commit 10fe6f78d1fafb87701270199cb9455f553242ce Author: montaghanmy Date: Thu Mar 23 11:03:16 2023 +0100 feat: init diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..eb1b3534 --- /dev/null +++ b/.gitignore @@ -0,0 +1,147 @@ +### PhpStorm ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +*.DS_Store + +# User-specific stuff: +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries + +# Sensitive or high-churn files: +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml + +# Gradle: +.idea/**/gradle.xml +.idea/**/libraries + +.idea/ + +# CMake +cmake-build-debug/ + +# Mongo Explorer plugin: +.idea/**/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Ruby plugin and RubyMine +/.rakeTasks + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +### PhpStorm Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/sonarlint + +### Symfony ### +# Cache and logs (Symfony2) +/app/cache/* +/app/logs/* +!app/cache/.gitkeep +!app/logs/.gitkeep + +# Email spool folder +/app/spool/* + +# Cache, session files and logs (Symfony3) +/var/cache/* +/var/logs/* +/var/sessions/* +!var/cache/.gitkeep +!var/logs/.gitkeep +!var/sessions/.gitkeep + +# Parameters +/app/config/parameters.yml +/app/config/parameters.ini + +# Managed by Composer +/app/bootstrap.php.cache +/var/bootstrap.php.cache +/bin/* +!bin/console +!bin/symfony_requirements + +# Assets and user uploads +/web/bundles/ +/web/uploads/ +/web/upload/ +/web/public/ + +# PHPUnit +/app/phpunit.xml +/phpunit.xml + +# Build data +/build/ +/builds/ + +# Backup entities generated with doctrine:generate:entities command +**/Entity/*~ + +### Symfony Patch ### +/web/css/ +/web/js/ +docker-compose.yml + +### Dev ### +/docker-data/* +/docker/data/* +/twake/docker-data/* +/twake/docker-data +/twake/backend/websockets_server/false + +### Twake specific ### +/build/ +/vendor/ +/app/Ressources/DatabaseEncryption/.HaliteEncryptor.key +/app/Ressources/DatabaseEncryption/.Halite.key +/backend/websockets_server/false/ + +### AWS ### +/app/config/aws_config.yml + +### Test ### +/tests/code_coverage/ +/web/detached/* +/drive/* +userreport.sh + +private + +log-workforce.sh +.dccache diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..b30f36d1 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,74 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch & Debug on Chrome", + "port": 9222, + "request": "launch", + "type": "chrome", + "url": "http://localhost:3000", + "webRoot": "${workspaceFolder}/twake/frontend/src" + }, + { + "name": "Launch & Debug on Canay", + "port": 9222, + "request": "launch", + "type": "chrome", + "url": "http://localhost:3000", + "webRoot": "${workspaceFolder}/twake/frontend/src", + "runtimeExecutable": "canary" + }, + { + "name": "Launch & Debug on Firefox", + "type": "firefox", + "request": "launch", + "reAttach": true, + "url": "http://localhost:3000", + "webRoot": "${workspaceFolder}/twake/frontend/src", + }, + { + "name": "Debug Node Backend", + "request": "launch", + "cwd": "${workspaceFolder}/twake/backend/node/", + "runtimeArgs": [ + "run", + "dev:debug" + ], + "runtimeExecutable": "npm", + "port": 9229, + "outputCapture": "std", + "skipFiles": [ + "/**" + ], + "type": "node" + }, + { + "name": "Debug Node Backend in Docker", + "port": 9229, + "address": "localhost", + "protocol": "inspector", + "request": "attach", + "type": "node", + "localRoot": "${workspaceFolder}/twake/backend/node/dist", + "remoteRoot": "/usr/src/app/dist", + "outFiles": [ + "${workspaceFolder}/twake/backend/node/dist/**/**.js" + ], + "skipFiles": [ + "/**/*.js" + ], + "sourceMapPathOverrides": { + "file:///usr/src/app/node_modules/*": "${workspaceRoot}/twake/backend/node/node_modules/*", + "file:///usr/src/app/node_modules/": "${workspaceRoot}/twake/backend/node/node_modules/", + "file:///usr/src/app/*": "${workspaceRoot}/twake/backend/node/dist/*", + "file:///usr/src/app/": "${workspaceRoot}/twake/backend/node/dist/", + "/usr/src/app/node_modules/*": "${workspaceRoot}/twake/backend/node/node_modules/*", + "/usr/src/app/node_modules/": "${workspaceRoot}/twake/backend/node/node_modules/", + "/usr/src/app/*": "${workspaceRoot}/twake/backend/node/dist/*", + "/usr/src/app/": "${workspaceRoot}/twake/backend/node/dist/" + }, + "sourceMaps": true + } + ], + "compounds": [] +} \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..b940e0c7 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# LINAGORA OPEN-SOURCE CODE OF CONDUCT + + + +## Our Pledge + +In Linagora, we foster an open and welcoming environment to build Good Tech - ethical and open-source software. We build this Good Tech to have a maximum positive impact on people, society, and the planet. We call this #GoodTech4Good. This is made possible by the support, hard work and enthusiasm of thousands of people, including those who create and use Linagora products. + +We as contributors and maintainers pledge to making participation in our project and in our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. + + + +## Our Standards + +This code of conduct outlines expectations for participants in Linagora managed open-source communities, as well as for reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all. + +Examples of behavior that contributes to creating a positive environment include: + +- **Using welcoming and inclusive language**: Our communities welcome and support people of all backgrounds and identities. Remember you might not be communicating in someone else's primary spoken or programming language, and others may not have your level of understanding. + +- **Being respectful of differing viewpoints and experiences**: In order for the Linagora community to thrive, its members must feel comfortable and accepted. Treating one another with respect is absolutely necessary for this. In a disagreement, in the first instance assume that people mean well. Respecting other people, their work, their contributions and assuming well-meaning motivation will make community members feel comfortable and safe and will result in motivation and productivity. + +- **Gracefully accepting constructive criticism**: Disagreements, both political and technical, happen all the time. The goal is not to avoid disagreements or criticisms but to resolve them constructively. You should turn to the community to seek advice and to resolve disagreements and where possible consult the team most directly involved. Think deeply before taking a criticism personally and turning it into a public dispute. If you do feel that you or your work is being attacked, take your time to breathe through before writing heated replies. + +- **Focusing on what is best for the community**: The success and quality of open-source software depends on collaboration. As a contributor, you should aim to collaborate with other community members, as well as with other communities that are interested in or depend on the work you do. Your work should be transparent and be fed back into the community when available. Please ensure that you keep the other community members informed of your work, and publish it in a way that allows them to test, discuss and contribute to your efforts. + + As a user, your feedback is important, as is its form. Poorly thought out comments can cause pain and demotivation of other community members, but considerate discussion of problems can bring positive results. + +- **Showing empathy towards other community members**: Our community is made strong by mutual respect, collaboration and empathy. Sometimes there are situations where this has to be defended and other community members need help. If you witness others being attacked, think first about how you can offer them personal support. If you feel that the situation is beyond your ability to help individually, go privately to the victim and ask if some form of official intervention is needed. Similarly, you should support anyone who appears to be in danger of burning out, either through work-related stress or personal problems. + +Examples of unacceptable behavior by participants include: + +- **The use of sexualized language or imagery and unwelcome sexual attention or advances.** +- **Trolling, insulting/derogatory comments, and personal or political attacks.** +- **Public or private harassments** +- **Publishing others' private information, such as physical or electronic address, without explicit permission.** +- **Other conduct which could reasonably be considered inappropriate in a professional setting.** + +This code is neither exhaustive nor complete. It serves to capture our common understanding of a productive, collaborative environment. We expect the code to be followed in spirit as much as in the letter. + + + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + + + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + + + +## Reporting Code of Conduct Issues + +We encourage all community members to resolve issues on their own whenever possible. This builds a broader and deeper understanding and ultimately a healthier interaction. In the event that an issue cannot be resolved locally, please feel free to report your concerns by contacting schauhan@linagora.com. Your report will be handled in accordance with the issue resolution process described in the Code of Conduct FAQ on our website(https://linagora.com). + +In your report please include: + +- Your contact information. +- Names (real, usernames or pseudonyms) of any individuals involved. If there are additional witnesses, please include them as well. +- Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public chat log), please include a link or attachment. +- Any additional information that may be helpful. + +All reports will be reviewed by a multi-person team and will result in a response that is deemed necessary and appropriate to the circumstances. Where additional perspectives are needed, the team may seek insight from others with relevant expertise or experience. The confidentiality of the person reporting the incident will be kept at all times. Involved parties are never a part of the review team. + +Anyone asked to stop unacceptable behavior is expected to comply immediately. If an individual engages in unacceptable behavior, the review team may take an action they deem appropriate, including a permanent ban from the community. + + + +## Attribution + +This Code of Conduct is adapted from both the [Contributor Covenant](https://www.contributor-covenant.org/), version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html and the template established by the [TODO Group](https://todogroup.org/). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..0b93ade2 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,126 @@ +# Contributing to Twake + +Hey! Thank you for your interest in contributing to Twake, we really appreciate it. + +Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open source project. In return, they should reciprocate that respect in addressing your issue, assessing changes, and helping you finalize your pull requests. + +We are an open-source project and we love to receive contributions from our community! There are many ways to contribute - writing tutorials or blog posts, improving the documentation, submitting bug reports and feature requests, fixing bugs, submitting pull requests for enhancements, or reviewing other's pull requests. + +## In a nutshell + +- Notify us that you will work on something using the issues of github. +- Fork this repository to start working and create a new working branch on top of the develop branch preferably. +- To propose your changes, open a PR from your fork and target the **develop** branch. + +Get more information here about how to start writing code: https://linagora.github.io/Twake/onprem/installation.html + +## Ground Rules + +Please adhere to the following responsibilities: + +- Ensure cross-platform compatibility for every change that's accepted. For example, Windows, Mac, Debian & Ubuntu Linux. +- Any change must be done using **Pull Requests** incoming from a fork of original Twake repository. +- Create issues for any major changes and enhancements that you wish to make. Discuss things transparently and get community feedback. +- Don't add any classes to the codebase unless absolutely needed. Err on the side of using functions. +- Keep feature versions as small as possible, preferably one new feature per version. +- Be welcoming to newcomers and encourage diverse new contributions from all backgrounds. See the [Code of Conduct](https://github.com/linagora/Twake/blob/main/CODE_OF_CONDUCT.md) + +#### What does the Code of Conduct mean for You? + +Our [Code of Conduct](https://github.com/linagora/Twake/blob/main/CODE_OF_CONDUCT.md) means that you are responsible for treating everyone on the project with respect and courtesy regardless of their identity. If you are the victim of any inappropriate behavior or comments as described in our [Code of Conduct](https://github.com/linagora/Twake/blob/main/CODE_OF_CONDUCT.md), we are here for you. Please follow the guidelines on our [website](https://linagora.com/en/) to report the issue and we will do the best to ensure that the abuser is reprimanded appropriately per our code. + +## Your First Contribution? + +Unsure where to begin contributing to Twake? You can start by looking at these [good first issues](https://github.com/linagora/Twake/labels/good%20first%20issue) and [help wanted issues](https://github.com/linagora/Twake/labels/help%20wanted). Good first issues - issues which should require only a few lines of code, and a test or two. Help wanted issues - issues which should be a bit more involved than beginner issues. While not perfect, number of comments is a reasonable proxy for impact a given change will have. + +Working on your first Pull Request? You can learn how from these free resources: [Course - How to Contribute to an Open Source Project on GitHub from @kentcdodds on @eggheadio](https://app.egghead.io/playlists/how-to-contribute-to-an-open-source-project-on-github) and [Make a Pull Request](https://makeapullrequest.com/). + +At this point, you are ready to make your changes! Feel free to ask for help; everyone is a beginner at first. πŸ˜ƒ + +If a maintainer asks you to "rebase" your PR, they are saying that a lot of code has changed, and that you need to update your branch so it's easier to merge. + +## How to Contribute? + +When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change. + +#### Pull Requests + +**It's important to break your feature down into small pieces first,** each piece should become it's own pull request. Once you know, what the first small piece of your feature will be, follow this general process while working: + +1. Create your own fork of the code and do changes in your own fork. + +2. Make your first commit: any will do even if empty or trivial, but we need something in order to create the initial pull request. Create the pull request and use the [pull request naming convention](https://github.com/linagora/Twake/blob/main/Contribute/Commit%20%26%20Pull%20Request%20Title%20Format.md). + + - Make sure that the titles of your pull requests and commits respect this format - [Commit & Pull Request Format](https://github.com/linagora/Twake/blob/main/Contribute/Commit%20%26%20Pull%20Request%20Title%20Format.md) + + - Write a detailed description of the problem you are solving, the part of Twake it affects, and how you plan on fixing it. + - If you have write access, add the **[Status] In Progress** label or wait until somebody adds it. This indicates that the pull request is not ready for a review and may still be incomplete. On the other hand, it welcomes early feedback and encourages collaboration during the development process. + +3. Start developing and pushing out commits to your new branch. + + - Push your changes out frequently and try to avoid getting stuck in a long-running branch or a merge nightmare. Smaller changes are much easier to review and to deal with potential conflicts. + - Note that you can automate some of these tasks by setting up githooks and they will run whenever you `git commit`. + - Please feel free to change, [squash](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html), and rearrange commits or to force push. Keep in mind, however, that if other people are committing on the same branch then you can mess up their history. You are perfectly safe if you are the only one pushing commits to that branch. + - Squash minor commits such as typo fixes or fixes to previous commits in the pull request. + +4. If you end up needing more than a few commits, consider splitting the pull request into separate components. Discuss in the new pull request and in the comments why the branch was broken apart and any changes that may have taken place that necessitated the split. Our goal is to catch early in the review process those pull requests that attempt to do too much. + +5. When you feel that you are ready for a formal review or for merging into `trunk` make sure you check this list. + + - Make sure your branch merges cleanly and consider rebasing against `trunk` to keep the branch history short and clean. You must target the **develop** branch for your changes. + - If there are visual changes, add before and after screenshots in the pull request comments. + - Add unit tests, or at a minimum, provide helpful instructions for the reviewer so they can test your changes. This will help speed up the review process. + - Ensure that your commit messages are [meaningful](https://thoughtbot.com/blog/5-useful-tips-for-a-better-commit-message). + - Mention that the PR is ready for review or if you have write access remove the **[Status] In Progress** label from the pull request and add the **[Status] Needs Review** label - someone will provide feedback on the latest unreviewed changes. The reviewer will also mark the pull request as **[Status] Needs Author Reply** if they think you need to change anything. + +6. If you get a :thumbsup: and the status has been changed to **[Status] Ready to Merge** - this is great - the pull request is ready to be merged. + +If you feel yourself waiting for someone to review a PR, don't hesitate to personally ask for someone to review it or to mention them on Github. Remember, the PR author is responsible for pushing the change through. + +#### Sign your work + +We use the Developer Certificate of Origin (DCO) as an additional safeguard for the Linagora/Twake projects. This is a well established and widely used mechanism to assure contributors have confirmed their right to license their contributions under the project's license. Please read [Developer Certificate of Origin](https://github.com/linagora/Twake/blob/main/Contribute/Linagora%20Developer's%20Certificate%20of%20Origin.md). If you can certify it, then just add a line to every git commit message: + +`Signed-Off by: Unicorn John ` + +Use your real name (sorry, no pseudonyms or anonymous contributions). If you set your `user.name` and `user.email` git configs, you can sign your commit automatically with `git commit-s`. + +#### Code Reviews + +Code Reviews are an important part of the Twake workflow. They help to keep code quality consistent, and they help every person working on Twake learn and improve over time. We want to make you the best Twake contributor you can be. + +Every PR should be reviewed and approved by someone other than the author, even if the author has write access. Fresh eyes can find problems that can hide in the open if you have been working on the code for a while. + +The recommended way of finding an appropriate person to review your code is by [blaming](https://docs.github.com/en/github/managing-files-in-a-repository/tracking-changes-in-a-file) one of the files you are updating and looking at who was responsible for previous commits on that file. + +Then, you may ask that person to review your code by mentioning their Github username on the PR comments like this: + +`cc @username` + +_Everyone_ is encouraged to review PRs and add feedback and ask questions. Reading other people's code is a great way to learn new techniques, and seeing code outside of your own feature helps you to see patterns across the project. It's also helpful to see the feedback other contributors are getting on their PRs. + +#### Apply a license + +In case you are not sure about how to apply our license correctly, please have a look at [How to Apply Licence](https://github.com/linagora/Twake/blob/main/Contribute/HowtoApplyOurLicense.md). + +#### How to report a bug? + +If you find a security vulnerability, do NOT open an issue. Email schauhan@linagora.com instead. + +In order to determine whether you are dealing with a security issue, ask yourself these two questions: + +- Can I access something that's not mine, or something I should not have access to? + +- Can I disable something for other people? + + If the answer to either of those two questions are "yes", then you are probably dealing with a security issue. Note that even if you answer "no" to both questions, you may still be dealing with a security issue, so if you're unsure, just email us at schauhan@linagora.com. + +For reporting any other bug, just file [a Github issue.](https://github.com/linagora/Twake/issues/new/choose) + +#### How to suggest a feature or enhancement? + +If you find yourself wishing for a feature that doesn't exist in Twake, you are probably not alone. There are bound to be others out there with similar needs. Many of the features that Twake has today have been added because our users saw the need. Open an issues on our issues list on Github which describes the feature you would like to see, why you need it. + +## Community + +You can chat with the core team at [- Gitter](https://gitter.im/linagora/Twake) and we will try our best to reply to you as soon as possible. diff --git a/Contribute/Commit & Pull Request Title Format.md b/Contribute/Commit & Pull Request Title Format.md new file mode 100644 index 00000000..9119bd8f --- /dev/null +++ b/Contribute/Commit & Pull Request Title Format.md @@ -0,0 +1,24 @@ +# Commit and Pull Request Format + +Your pull request and commits titles must respect this format: + +`[Emoji] [Verb] [Details]` + +The description of the commit must contain the issues fixed by your proposition. +Example: +`Fixes #43` + +List of commit emojis: + +- πŸ›  Fixing broken code. +- ♻️ Refactoring code and making it work better. +- πŸ” Writing or fixing tests. +- 🌈 Making your code or your app beautiful with style +- 🐳 Deployment / docker +- πŸ“š Documentation +- 🌟 New feature + +Examples of commits: + +`πŸ›  Fix broken login page` +`🌟 Implement SpaceX Crew Dragon plugin` diff --git a/Contribute/HowtoApplyOurLicense.md b/Contribute/HowtoApplyOurLicense.md new file mode 100644 index 00000000..10efd19e --- /dev/null +++ b/Contribute/HowtoApplyOurLicense.md @@ -0,0 +1,19 @@ +# How to apply our license? + +In order to distribute a program under the GNU Affero General Public License version 3 with the additional terms for TWAKE software, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. + +`` + +`Copyright (c) ` + +`This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the license, or (at your option) any later version, provided you comply with the Additional Terms applicable for TWAKE software by Linagora pursuant to Section 7 of the GNU Affero General Public License, subsections (b), (c), and (e), pursuant to which you most notably (i) retain the "TWAKE is powered by LINAGORA" notice appended to any type of outbound messages (e.g. e-mail and meeting requests) as well as in the TWAKE user interface, (ii) retain all hypertext links between TWAKE and https://twake.app, as well as between LINAGORA and https://linagora.com, and (iii) refrain from infringing LINAGORA intellectual property rights over its trademark and commercial brands. Other Additional Terms apply, see for more details.` + +`This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.` + +`You should have received a copy of the GNU Affero General Public License and its applicable Additional Terms for TWAKE along with this program. If not, see for the GNU Affero Public License version 3 and for the Additional Terms applicable to the TWAKE software.` + +Also add information on how to contact you by electronic and paper mail. + +If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. + +You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . diff --git a/Contribute/Linagora Developer's Certificate of Origin.md b/Contribute/Linagora Developer's Certificate of Origin.md new file mode 100644 index 00000000..6768eb92 --- /dev/null +++ b/Contribute/Linagora Developer's Certificate of Origin.md @@ -0,0 +1,35 @@ +# Developer Certificate of Origin + +[^Copyright (C) 2021 Linagora]: + + + +If you are reading this, then you're considering contributing to one or several LINAGORA project(s). That's great! We are enthusiastic about welcoming you as a LINAGORA project contributor, and working with you to make **#GoodTech4Good!** + +However, we have to ensure that anything you contribute to our projects: + +β€’ is really your own creation, developed with your bare brain and fingers (or whatever organs you favor to type with your preferred input device), or that you’re allowed to contribute it; + +β€’ is not β€œlicense locked”, i.e. that we can publish it under any other open source license in order to help our projects remain open source; + +β€’ can remain in our projects and not suddenly become unusable because you change your mind and demand that we either use your code differently or not at all. + +To achieve this, we first need you to agree to this Developer Certificate of Origin before we can accept merging your contributions to our projects. Once you've done so, you can create your pull requests right away! + +By submitting a contribution to a LINAGORA project, you certify: + +a) that this contribution is provided under the terms and conditions of the Creative Commons Zero (CC0) license (https://creativecommons.org/publicdomain/zero/1.0/legalcode); + +b) being the rightful copyright owner of the contribution, and/or being fully and lawfully authorized to provide the contribution under the CC0 license on behalf of all entities which participated in the creation of the contribution (for example your employer); + +c) if the contribution is based upon a previous work, that this previous work is covered by an open source license which enables you to lawfully redistribute your contribution and this previous work both under the LINAGORA project license (Just reach out to us if you have any doubts, and we will help you); + +d) if your contribution is a derivative of one of our projects under a different license than the CC0 license, LINAGORA grants you a special authorization to provide this contribution to LINAGORA under the CC0 license regardless of the project license; + +d) if moral rights apply to your contribution, to the extent permitted by applicable law, that you will not try to assert your moral rights in a manner which would, directly or indirectly, interfere with the use of your contribution either by LINAGORA or by any project user (though, of course, you will always be credited as a contributor to the project); + +e) either that there are no patents applicable to your contribution, or if there are, that you then grant (and are allowed to lawfully grant) any users of your contribution a non-exclusive, perpetual, worldwide, no-charge, royalty-free, transferable and irrevocable patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the contribution in any form and any combination; + +f) understanding and acknowledging that the LINAGORA project, your contribution, and any record pertaining thereto are and might remain indefinitely public, and might also be re-distributed to third-parties under the terms of the LINAGORA project license and/or the CC0 license; + +And that’s it! Let’s code now! diff --git a/Documentation/.gitignore b/Documentation/.gitignore new file mode 100644 index 00000000..76add878 --- /dev/null +++ b/Documentation/.gitignore @@ -0,0 +1,2 @@ +node_modules +dist \ No newline at end of file diff --git a/Documentation/docs/.vitepress/config.js b/Documentation/docs/.vitepress/config.js new file mode 100644 index 00000000..eca207a5 --- /dev/null +++ b/Documentation/docs/.vitepress/config.js @@ -0,0 +1,176 @@ +export default { + base: "/Twake/", + title: "Documentation", + description: "Public API documentation", + themeConfig: { + logo: "https://twake.app/images/logo-twake.svg", + sidebar: [ + { + text: "Getting started", + items: [ + { + text: "β˜€οΈ Welcome to Twake", + link: "index", + }, + { + text: "⬇️ Desktop and mobile apps", + link: "download", + }, + ], + }, + { + text: "On-premise", + items: [ + { + text: "πŸ— Run On-Premise", + link: "/onprem/installation", + }, + { + text: "βš™οΈ Server configuration", + link: "/onprem/configuration/README.md", + }, + ], + }, + { + text: "How to use Twake", + items: [ + { + text: "πŸ‘‹ Welcome to Twake !", + link: "/how-to-use-it/welcome", + }, + { + text: "πŸ–₯ Desktop and mobile app", + link: "/how-to-use-it/desktop-and-mobile-app", + }, + { + text: "πŸ”’ Privacy and security", + link: "/how-to-use-it/privacy-security", + }, + { + text: "Console", + link: "/how-to-use-it/console/README.md", + items: [ + { + text: "Users", + link: "/how-to-use-it/console/users", + }, + ], + }, + { + text: "Company & workspace", + link: "/how-to-use-it/company-and-workspace/README.md", + items: [ + { + text: "Invite user", + link: "/how-to-use-it/company-and-workspace/invite-user-from-chat", + }, + { + text: "Rights", + link: "/how-to-use-it/company-and-workspace/rights", + }, + ], + }, + { + text: "Chat", + link: "/how-to-use-it/applications/how-to-use-chat/README.md", + items: [ + { + text: "Channels", + link: "/how-to-use-it/applications/how-to-use-chat/channels", + }, + { + text: "Message", + link: "/how-to-use-it/applications/how-to-use-chat/message", + }, + ], + }, + { + text: "Drive", + link: "/how-to-use-it/applications/drive/README.md", + items: [ + { + text: "File and folder", + link: "/how-to-use-it/applications/drive/file-and-folder", + }, + { + text: "Share file with public link", + link: "/how-to-use-it/applications/drive/share-file-with-public-link", + }, + ], + }, + { + text: "Connectors", + link: "/how-to-use-it/applications/connectors/README.md", + items: [ + { + text: "n8n", + link: "/how-to-use-it/applications/connectors/n8n", + }, + ], + }, + ], + }, + { + text: "Internal documentation", + items: [ + { + text: "Our stack", + link: "/internal-documentation/our-stack", + }, + { + text: "Translation", + link: "/internal-documentation/translation", + }, + { + text: "Backend services", + items: [ + { + text: "Get started", + link: "/internal-documentation/backend-services/intro/README.md", + }, + { + text: "Applications", + link: "/internal-documentation/backend-services/applications/README.md", + }, + { + text: "Channels", + link: "/internal-documentation/backend-services/channels/README.md", + }, + { + text: "Documents", + link: "/internal-documentation/backend-services/documents/README.md", + }, + { + text: "Files", + link: "/internal-documentation/backend-services/files/README.md", + }, + { + text: "Tags", + link: "/internal-documentation/backend-services/tags/README.md", + }, + { + text: "Knowledge graph", + link: "/internal-documentation/backend-services/knowledge-graph/README.md", + }, + { + text: "Notifications", + link: "/internal-documentation/backend-services/notifications/README.md", + }, + ], + }, + + { + text: "Frontend components", + items: [ + { + text: "Get started", + link: "/internal-documentation/frontend-components/intro/README.md", + }, + ], + }, + ], + }, + ], + }, + head: [], +}; diff --git a/Documentation/docs/.vitepress/theme/custom.css b/Documentation/docs/.vitepress/theme/custom.css new file mode 100644 index 00000000..7bac8848 --- /dev/null +++ b/Documentation/docs/.vitepress/theme/custom.css @@ -0,0 +1,93 @@ +#docsearch { + margin-right: 16px; +} + +#docsearch .DocSearch-Button { + justify-content: flex-start; + border: 1px solid transparent; + border-radius: 8px; + padding: 0 10px 0 12px; + width: 100%; + height: 40px; + background-color: var(--vp-c-bg-alt); +} + +#docsearch .DocSearch-Button:hover { + border-color: var(--vp-c-brand); + background: var(--vp-c-bg-alt); +} + +#docsearch .DocSearch-Button-Placeholder { + transition: color 0.2s; +} + +#docsearch .DocSearch-Button-Keys { + display: flex; + align-items: center; + min-width: auto; + pointer-events: auto; +} + +#docsearch .DocSearch-Button .DocSearch-Button-Key+.DocSearch-Button-Key { + border-right: 1px solid var(--vp-c-divider); + border-left: none; + border-radius: 0 4px 4px 0; + padding-left: 2px; + padding-right: 6px; +} + +#docsearch .DocSearch-Button .DocSearch-Button-Key { + display: block; + margin: 2px 0 0; + border: 1px solid var(--vp-c-divider); + border-right: none; + border-radius: 4px 0 0 4px; + padding-left: 6px; + min-width: 0; + width: auto; + height: 22px; + line-height: 22px; + font-family: var(--vp-font-family-base); + font-size: 12px; + font-weight: 500; + transition: color .5s,border-color .5s; +} + +/* Modal */ + +.DocSearch-Modal, .modal { + border-radius: 6px; + flex-direction: column; + margin: 60px auto auto; + max-width: 600px; + position: relative; +} + +.modal .flex-logo { + width: 56px; + margin-left: calc(100% - 74px); +} + +.DocSearch-Input { + margin-left: 0px; + margin-right: 14px; + font-size: 16px; + padding: 12px; +} + +.modal .search-item { + border-radius: 4px; + display: flex; + padding-bottom: 4px; + position: relative; + + align-items: center; + display: flex; + flex-direction: row; + height: 56px; + padding: 0 16px 0 16px; +} + +.modal .search-item-icon { + display: none; +} \ No newline at end of file diff --git a/Documentation/docs/.vitepress/theme/index.js b/Documentation/docs/.vitepress/theme/index.js new file mode 100644 index 00000000..c495bc1b --- /dev/null +++ b/Documentation/docs/.vitepress/theme/index.js @@ -0,0 +1,4 @@ +import DefaultTheme from "vitepress/theme"; +import "./custom.css"; + +export default DefaultTheme; diff --git a/Documentation/docs/SUMMARY.md b/Documentation/docs/SUMMARY.md new file mode 100644 index 00000000..6f6bd16f --- /dev/null +++ b/Documentation/docs/SUMMARY.md @@ -0,0 +1,86 @@ +# Table of contents + +- [β˜€οΈ Twake](index.md) + +## Getting started + +- [β–Ά Use Twake on twake.app](gettingstarted/use-twake-on-twake.app.md) +- [πŸ— Install on your server](onprem/installation.md) +- [βš™ Configuration](onprem/configuration/index.md) + - [πŸ”’ Security](onprem/configuration/security.md) + - [πŸ”— Custom domain + HTTPS](onprem/configuration/custom-domain-and-https/README.md) + - [Apache2 configuration](onprem/configuration/custom-domain-and-https/apache2-configuration.md) + - [πŸ’Œ Configure mail server](onprem/configuration/configure-mail-server.md) + - [🎨 Customisation](onprem/configuration/customisation.md) + - [πŸ”Œ Connectors and plugins](onprem/configuration/connectors-and-plugins.md) + - [πŸ‘¨β€πŸ’» Authentication modes](onprem/configuration/authentication-modes/README.md) + - [Using Keycloak (LDAP, OpenID and more)](onprem/configuration/authentication-modes/using-keycloak-ldap-openid-and-more.md) + - [Installing Twake with LemonLDAP (LDAP, OpenID and more)](onprem/configuration/authentication-modes/installing-twake-with-lemonldap-ldap-openid-and-more.md) + +## How to use it + +- [πŸ‘‹ Welcome to Twake !](how-to-use-it/welcome.md) +- [🧰 Console](how-to-use-it/console/README.md) + - [Users](how-to-use-it/console/users.md) +- [🏒 Company & workspace](how-to-use-it/company-and-workspace/README.md) + - [Invite user from Chat](how-to-use-it/company-and-workspace/invite-user-from-chat.md) + - [Rights](how-to-use-it/company-and-workspace/rights.md) +- [πŸ’  Applications](how-to-use-it/applications/README.md) + - [πŸ’¬ Chat](how-to-use-it/applications/how-to-use-chat/README.md) + - [Channels](how-to-use-it/applications/how-to-use-chat/channels.md) + - [Message](how-to-use-it/applications/how-to-use-chat/message.md) + - [πŸ“‚ Drive](how-to-use-it/applications/drive/README.md) + - [File and folder](how-to-use-it/applications/drive/file-and-folder.md) + - [Share file with public link](how-to-use-it/applications/drive/share-file-with-public-link.md) + - [πŸ“† Calendar](how-to-use-it/applications/calendar.md) + - [βœ… Tasks](how-to-use-it/applications/tasks.md) + - [πŸ”ƒ Connectors](how-to-use-it/applications/connectors/README.md) + - [n8n](how-to-use-it/applications/connectors/n8n.md) +- [πŸ–₯ Desktop and mobile app](how-to-use-it/desktop-and-mobile-app.md) +- [πŸ”’ Privacy and security](how-to-use-it/privacy-security.md) + +## Developers API + +- [🏠 Home](developers-api/home.md) +- [πŸ₯‡ Getting started](developers-api/get-started/README.md) + - [Create your first application](developers-api/get-started/create-your-first-application.md) + - [Authenticate with Postman](developers-api/get-started/authenticate-postman.md) + - [Send a message with your application](developers-api/get-started/send-a-message-for-twake.md) + - [Trigger action from command](developers-api/get-started/trigger-action-from-command.md) +- [βš™ Application settings](developers-api/application-settings/README.md) + - [Api](developers-api/application-settings/api.md) + - [Display](developers-api/application-settings/application-visibility-example.md) + - [Privileges](developers-api/application-settings/privileges.md) + - [Identity](developers-api/application-settings/identity.md) +- [πŸ“– API Reference](developers-api/api-reference/README.md) + - [Webhook](developers-api/api-reference/wehbook.md) + - [Drive](developers-api/api-reference/drive.md) + - [Message](developers-api/api-reference/message/README.md) + - [Authentication](developers-api/api-reference/auth.md) +- [🧱 Blocks](developers-api/blocks.md) + +## Internal Documentation + +- [πŸ₯‡ Get started](developers-api/run-twake-as-developer.md) +- [🎨 Twake Ecosystem Guidelines](internal-documentation/twake-ecosystem-guidelines.md) +- [πŸ“š Our stack](internal-documentation/our-stack.md) +- [🧱 Backend and APIs](internal-documentation/backend-services/README.md) + - [πŸ‘₯ Users, workspaces and companies](internal-documentation/backend-services/users/README.md) + - [🍎 Applications](internal-documentation/backend-services/applications/README.md) + - [Database models](internal-documentation/backend-services/applications/database-models.md) + - [REST APIs](internal-documentation/backend-services/applications/rest-apis.md) + - [🎩 Channels and tabs](internal-documentation/backend-services/channels/README.md) + - [Database models](internal-documentation/backend-services/channels/database-models.md) + - [πŸ’¬ Messages](internal-documentation/backend-services/messages/README.md) + - [Database models](internal-documentation/backend-services/messages/database-model.md) + - [πŸ“„ Files](internal-documentation/backend-services/files/README.md) + - [Database models](internal-documentation/backend-services/files/database-models.md) + - [Resumable.js](internal-documentation/backend-services/files/resumablejs.md) + - [πŸ“² Notifications](internal-documentation/backend-services/notifications/README.md) + - [Database models](internal-documentation/backend-services/notifications/database-models.md) + - [πŸ›  Twake service development](internal-documentation/backend-services/intro/README.md) + - [What is a service in Twake ?](internal-documentation/backend-services/intro/start-working-into-a-service.md) + - [Create a new service](internal-documentation/backend-services/intro/create-a-new-twake-service.md) + - [Platform/Technical services](internal-documentation/backend-services/intro/platform/README.md) + - [Database ORM platform service](internal-documentation/backend-services/intro/platform/database-orm-platform-service.md) +- [🎭 Translation](internal-documentation/translation.md) diff --git a/Documentation/docs/assets/capture-decran-de-2020-07-17-17-05-36.png b/Documentation/docs/assets/capture-decran-de-2020-07-17-17-05-36.png new file mode 100644 index 00000000..49c4eb11 Binary files /dev/null and b/Documentation/docs/assets/capture-decran-de-2020-07-17-17-05-36.png differ diff --git a/Documentation/docs/assets/capture-decran-de-2020-07-17-17-48-56.png b/Documentation/docs/assets/capture-decran-de-2020-07-17-17-48-56.png new file mode 100644 index 00000000..42a10f9e Binary files /dev/null and b/Documentation/docs/assets/capture-decran-de-2020-07-17-17-48-56.png differ diff --git a/Documentation/docs/assets/capture-decran-de-2020-07-17-17-58-03.png b/Documentation/docs/assets/capture-decran-de-2020-07-17-17-58-03.png new file mode 100644 index 00000000..34932e0f Binary files /dev/null and b/Documentation/docs/assets/capture-decran-de-2020-07-17-17-58-03.png differ diff --git a/Documentation/docs/assets/changecomp.gif b/Documentation/docs/assets/changecomp.gif new file mode 100644 index 00000000..4503d0ce Binary files /dev/null and b/Documentation/docs/assets/changecomp.gif differ diff --git a/Documentation/docs/assets/channel-move.gif b/Documentation/docs/assets/channel-move.gif new file mode 100644 index 00000000..4ee3b3dd Binary files /dev/null and b/Documentation/docs/assets/channel-move.gif differ diff --git a/Documentation/docs/assets/createuser.gif b/Documentation/docs/assets/createuser.gif new file mode 100644 index 00000000..7f75d132 Binary files /dev/null and b/Documentation/docs/assets/createuser.gif differ diff --git a/Documentation/docs/assets/d-and-dmessage.gif b/Documentation/docs/assets/d-and-dmessage.gif new file mode 100644 index 00000000..273f1267 Binary files /dev/null and b/Documentation/docs/assets/d-and-dmessage.gif differ diff --git a/Documentation/docs/assets/externalmember.gif b/Documentation/docs/assets/externalmember.gif new file mode 100644 index 00000000..308be50f Binary files /dev/null and b/Documentation/docs/assets/externalmember.gif differ diff --git a/Documentation/docs/assets/gif-(1).gif b/Documentation/docs/assets/gif-(1).gif new file mode 100644 index 00000000..c3ddeb74 Binary files /dev/null and b/Documentation/docs/assets/gif-(1).gif differ diff --git a/Documentation/docs/assets/gif.gif b/Documentation/docs/assets/gif.gif new file mode 100644 index 00000000..ec569064 Binary files /dev/null and b/Documentation/docs/assets/gif.gif differ diff --git a/Documentation/docs/assets/how-to-install-n8n.gif b/Documentation/docs/assets/how-to-install-n8n.gif new file mode 100644 index 00000000..6ad2c8bc Binary files /dev/null and b/Documentation/docs/assets/how-to-install-n8n.gif differ diff --git a/Documentation/docs/assets/image-(2)-(1).png b/Documentation/docs/assets/image-(2)-(1).png new file mode 100644 index 00000000..21c737fe Binary files /dev/null and b/Documentation/docs/assets/image-(2)-(1).png differ diff --git a/Documentation/docs/assets/image-(3)-(1).png b/Documentation/docs/assets/image-(3)-(1).png new file mode 100644 index 00000000..5dd85adc Binary files /dev/null and b/Documentation/docs/assets/image-(3)-(1).png differ diff --git a/Documentation/docs/assets/image-(3).png b/Documentation/docs/assets/image-(3).png new file mode 100644 index 00000000..5dd85adc Binary files /dev/null and b/Documentation/docs/assets/image-(3).png differ diff --git a/Documentation/docs/assets/image-(4).png b/Documentation/docs/assets/image-(4).png new file mode 100644 index 00000000..f362e562 Binary files /dev/null and b/Documentation/docs/assets/image-(4).png differ diff --git a/Documentation/docs/assets/image-(5).png b/Documentation/docs/assets/image-(5).png new file mode 100644 index 00000000..56ab1042 Binary files /dev/null and b/Documentation/docs/assets/image-(5).png differ diff --git a/Documentation/docs/assets/image-(6).png b/Documentation/docs/assets/image-(6).png new file mode 100644 index 00000000..868c84a1 Binary files /dev/null and b/Documentation/docs/assets/image-(6).png differ diff --git a/Documentation/docs/assets/image-2.png b/Documentation/docs/assets/image-2.png new file mode 100644 index 00000000..21c737fe Binary files /dev/null and b/Documentation/docs/assets/image-2.png differ diff --git a/Documentation/docs/assets/image.png b/Documentation/docs/assets/image.png new file mode 100644 index 00000000..8c7b4aa6 Binary files /dev/null and b/Documentation/docs/assets/image.png differ diff --git a/Documentation/docs/assets/invitefromtwake.gif b/Documentation/docs/assets/invitefromtwake.gif new file mode 100644 index 00000000..32d42527 Binary files /dev/null and b/Documentation/docs/assets/invitefromtwake.gif differ diff --git a/Documentation/docs/assets/invitefromtwake.mov b/Documentation/docs/assets/invitefromtwake.mov new file mode 100644 index 00000000..b41c9c40 Binary files /dev/null and b/Documentation/docs/assets/invitefromtwake.mov differ diff --git a/Documentation/docs/assets/inviteuser.gif b/Documentation/docs/assets/inviteuser.gif new file mode 100644 index 00000000..7b82f4d5 Binary files /dev/null and b/Documentation/docs/assets/inviteuser.gif differ diff --git a/Documentation/docs/assets/logo_shape.svg b/Documentation/docs/assets/logo_shape.svg new file mode 100644 index 00000000..3730edc9 --- /dev/null +++ b/Documentation/docs/assets/logo_shape.svg @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/Documentation/docs/assets/message-reaction.gif b/Documentation/docs/assets/message-reaction.gif new file mode 100644 index 00000000..98860b57 Binary files /dev/null and b/Documentation/docs/assets/message-reaction.gif differ diff --git a/Documentation/docs/assets/n8n-implement (1).gif b/Documentation/docs/assets/n8n-implement (1).gif new file mode 100644 index 00000000..ed579f84 Binary files /dev/null and b/Documentation/docs/assets/n8n-implement (1).gif differ diff --git a/Documentation/docs/assets/n8n-implement.gif b/Documentation/docs/assets/n8n-implement.gif new file mode 100644 index 00000000..4aee1795 Binary files /dev/null and b/Documentation/docs/assets/n8n-implement.gif differ diff --git a/Documentation/docs/assets/pinmessage.gif b/Documentation/docs/assets/pinmessage.gif new file mode 100644 index 00000000..04b7b41b Binary files /dev/null and b/Documentation/docs/assets/pinmessage.gif differ diff --git a/Documentation/docs/assets/private-channel-member.gif b/Documentation/docs/assets/private-channel-member.gif new file mode 100644 index 00000000..caadf722 Binary files /dev/null and b/Documentation/docs/assets/private-channel-member.gif differ diff --git a/Documentation/docs/assets/responsemessage.gif b/Documentation/docs/assets/responsemessage.gif new file mode 100644 index 00000000..c7952392 Binary files /dev/null and b/Documentation/docs/assets/responsemessage.gif differ diff --git a/Documentation/docs/assets/sans-titre-2-1.gif b/Documentation/docs/assets/sans-titre-2-1.gif new file mode 100644 index 00000000..58927719 Binary files /dev/null and b/Documentation/docs/assets/sans-titre-2-1.gif differ diff --git a/Documentation/docs/assets/sans-titre-2.gif b/Documentation/docs/assets/sans-titre-2.gif new file mode 100644 index 00000000..a68cbf3c Binary files /dev/null and b/Documentation/docs/assets/sans-titre-2.gif differ diff --git a/Documentation/docs/assets/screenshot-2020-07-15-at-17.00.48.png b/Documentation/docs/assets/screenshot-2020-07-15-at-17.00.48.png new file mode 100644 index 00000000..3820e475 Binary files /dev/null and b/Documentation/docs/assets/screenshot-2020-07-15-at-17.00.48.png differ diff --git a/Documentation/docs/assets/screenshot-2021-03-31-at-14.51.23.png b/Documentation/docs/assets/screenshot-2021-03-31-at-14.51.23.png new file mode 100644 index 00000000..51aade1c Binary files /dev/null and b/Documentation/docs/assets/screenshot-2021-03-31-at-14.51.23.png differ diff --git a/Documentation/docs/assets/sendmessage.gif b/Documentation/docs/assets/sendmessage.gif new file mode 100644 index 00000000..a58c34d5 Binary files /dev/null and b/Documentation/docs/assets/sendmessage.gif differ diff --git a/Documentation/docs/assets/setadmin.gif b/Documentation/docs/assets/setadmin.gif new file mode 100644 index 00000000..3d0a5c7c Binary files /dev/null and b/Documentation/docs/assets/setadmin.gif differ diff --git a/Documentation/docs/assets/setguest.gif b/Documentation/docs/assets/setguest.gif new file mode 100644 index 00000000..8a8abb95 Binary files /dev/null and b/Documentation/docs/assets/setguest.gif differ diff --git a/Documentation/docs/assets/setwsadmin.gif b/Documentation/docs/assets/setwsadmin.gif new file mode 100644 index 00000000..91c9c60e Binary files /dev/null and b/Documentation/docs/assets/setwsadmin.gif differ diff --git a/Documentation/docs/assets/tab2.gif b/Documentation/docs/assets/tab2.gif new file mode 100644 index 00000000..59fc1d59 Binary files /dev/null and b/Documentation/docs/assets/tab2.gif differ diff --git a/Documentation/docs/assets/twake-api-settings.gif b/Documentation/docs/assets/twake-api-settings.gif new file mode 100644 index 00000000..404c80d2 Binary files /dev/null and b/Documentation/docs/assets/twake-api-settings.gif differ diff --git a/Documentation/docs/assets/twake-application-privileges.gif b/Documentation/docs/assets/twake-application-privileges.gif new file mode 100644 index 00000000..ea3adcc7 Binary files /dev/null and b/Documentation/docs/assets/twake-application-privileges.gif differ diff --git a/Documentation/docs/assets/twake-create-a-twake-app (1).gif b/Documentation/docs/assets/twake-create-a-twake-app (1).gif new file mode 100644 index 00000000..34ece352 Binary files /dev/null and b/Documentation/docs/assets/twake-create-a-twake-app (1).gif differ diff --git a/Documentation/docs/assets/twake-create-a-twake-app.gif b/Documentation/docs/assets/twake-create-a-twake-app.gif new file mode 100644 index 00000000..26bff123 Binary files /dev/null and b/Documentation/docs/assets/twake-create-a-twake-app.gif differ diff --git a/Documentation/docs/assets/twake-display-settings.png b/Documentation/docs/assets/twake-display-settings.png new file mode 100644 index 00000000..e0c14c5d Binary files /dev/null and b/Documentation/docs/assets/twake-display-settings.png differ diff --git a/Documentation/docs/assets/twake-identity-of-the-application.gif b/Documentation/docs/assets/twake-identity-of-the-application.gif new file mode 100644 index 00000000..323225fe Binary files /dev/null and b/Documentation/docs/assets/twake-identity-of-the-application.gif differ diff --git a/Documentation/docs/assets/twake-install-application.gif b/Documentation/docs/assets/twake-install-application.gif new file mode 100644 index 00000000..934e5424 Binary files /dev/null and b/Documentation/docs/assets/twake-install-application.gif differ diff --git a/Documentation/docs/assets/web-app-reference-architecture-2-.png b/Documentation/docs/assets/web-app-reference-architecture-2-.png new file mode 100644 index 00000000..1791d741 Binary files /dev/null and b/Documentation/docs/assets/web-app-reference-architecture-2-.png differ diff --git a/Documentation/docs/developers-api/api-reference/README.md b/Documentation/docs/developers-api/api-reference/README.md new file mode 100644 index 00000000..19c660b0 --- /dev/null +++ b/Documentation/docs/developers-api/api-reference/README.md @@ -0,0 +1,6 @@ +--- +description: Discover our wonderful API +--- + +# πŸ“– API Reference + diff --git a/Documentation/docs/developers-api/api-reference/auth.md b/Documentation/docs/developers-api/api-reference/auth.md new file mode 100644 index 00000000..9fc1ec8e --- /dev/null +++ b/Documentation/docs/developers-api/api-reference/auth.md @@ -0,0 +1,24 @@ +--- +description: How to manage authentification on API call +--- + +# Authentication + +## Authencate your app in Twake + +**All your connections** should respect the Basic access authentication protocol, which must be used via HTTPS, except in development mode. In order to make an API call with this method, you must add an HTTP header: + +```text +Authorization: Basic base64(public_id:private_api_key) +``` + +**You must concatenate** your [public_id and private_api_key](../get-started/README.md#identity-and-api-settings) , **then convert** the whole **to base64**. Your HTTP header will therefore look like: + +```text +# For the keys 'public_id' and 'private_key' +Authorization: Basic cHVibGljX2lkOnByaXZhdGVfYXBpX2tleQ== +``` + +## Authencate your app in a company + +**All your requests should have at least a "group_id" key with the company id you** diff --git a/Documentation/docs/developers-api/api-reference/drive.md b/Documentation/docs/developers-api/api-reference/drive.md new file mode 100644 index 00000000..a13d6291 --- /dev/null +++ b/Documentation/docs/developers-api/api-reference/drive.md @@ -0,0 +1,6 @@ +--- +description: How to manage Drive through API +--- + +# Drive + diff --git a/Documentation/docs/developers-api/api-reference/message/README.md b/Documentation/docs/developers-api/api-reference/message/README.md new file mode 100644 index 00000000..b9e62c25 --- /dev/null +++ b/Documentation/docs/developers-api/api-reference/message/README.md @@ -0,0 +1,21 @@ +--- +description: How to manage messages through API +--- + +# Message + +_While users have the ability to create message complexes using the built-in formatting system, applications can go even further and offer many types of messages such as system messages for notifications or interactive messages for your most popular applications._ + +## Group_id and channel_id: + +1. Get the current front id: + + `channel_service.currentChannelFrontId` + +2. With the channel front id, you will be able to get the channel id by doing this: + + `collections.collections.channels.manager.findByFrontId("My-Front-Id")` + +3. Get the current group id: + + `workspaceService.currentGroupId` diff --git a/Documentation/docs/developers-api/api-reference/wehbook.md b/Documentation/docs/developers-api/api-reference/wehbook.md new file mode 100644 index 00000000..49b65765 --- /dev/null +++ b/Documentation/docs/developers-api/api-reference/wehbook.md @@ -0,0 +1,6 @@ +--- +description: How to use webhook with Twake +--- + +# Webhook + diff --git a/Documentation/docs/developers-api/application-settings/README.md b/Documentation/docs/developers-api/application-settings/README.md new file mode 100644 index 00000000..5a1258f8 --- /dev/null +++ b/Documentation/docs/developers-api/application-settings/README.md @@ -0,0 +1,6 @@ +--- +description: Set your application +--- + +# βš™ Application settings + diff --git a/Documentation/docs/developers-api/application-settings/api.md b/Documentation/docs/developers-api/application-settings/api.md new file mode 100644 index 00000000..0bf67092 --- /dev/null +++ b/Documentation/docs/developers-api/application-settings/api.md @@ -0,0 +1,6 @@ +--- +description: There you will find some important pieces of information +--- + +# Api + diff --git a/Documentation/docs/developers-api/application-settings/application-visibility-example.md b/Documentation/docs/developers-api/application-settings/application-visibility-example.md new file mode 100644 index 00000000..3e1e0831 --- /dev/null +++ b/Documentation/docs/developers-api/application-settings/application-visibility-example.md @@ -0,0 +1,152 @@ +--- +description: This is a JSON parameter to define where your app should appear +--- + +# Display + +#### Latest version + +```typescript +{ + twake: { + version: 1; + + files?: { + preview?: { + url: string; //Url to preview file (full screen or inline) + inline?: boolean; + main_ext?: string[]; //Main extensions app can read + other_ext?: string[]; //Secondary extensions app can read + }; + actions?: //List of action that can apply on a file + { + name: string; + id: string; + }[]; + }; + + //Chat plugin + chat: { + input?: + | true + | { + icon?: string; //If defined replace original icon url of your app + type?: "file" | "call"; //To add in existing apps folder / default icon + }; + commands?: { + command: string; // my_app mycommand + description: string; + }[]; + actions?: //List of action that can apply on a message + { + name: string; + id: string; + }[]; + }; + + //Allow app to appear as a bot user in direct chat + direct?: + | true + | { + name?: string; + icon?: string; //If defined replace original icon url of your app + }; + + //Display app as a standalone application in a tab + tab?: { + url: string; + }; + + //Display app as a standalone application on the left bar + standalone?: { + url: string; + }; + + //Define where the app can be configured from + configuration: ("global" | "channel")[]; + }; +}; + +``` + +#### Legacy format + +```javascript +type ApplicationDisplay = { + twake: + { + "version": 0, //Legacy + "tasks_module" : { + "can_connect_to_tasks": true + }, + "calendar_module" : { + "can_connect_to_calendar": true + } + "drive_module" : { + "can_connect_to_directory": true, + "can_open_files": { + "url": "", //Une url Γ  appeler pour Γ©diter le fichier (ouvert dans un onglet) + "preview_url": "", //Une url Γ  appeler pour prΓ©visualiser un fichier (iframe) + "main_ext": ["docx", "xlsx"], //Extensions principales + "other_ext": ["txt", "html"] //Extensions secondaires + }, + "can_create_files": [ + { + "url": "https://[...]/empty.docx", + "filename": "Untitled.docx", + "name": "Word Document" + }, + { + "url": "https://[...]/empty.xlsx", + "filename": "Untitled.xlsx", + "name": "Excel Document" + } + ] + }, + "member_app": true, // Si dΓ©fini, votre application gΓ©nΓ¨rera un membre + // virtuel dans l'espace de travail avec lequel les + // utilisateurs pourront discuter. + "messages_module": { + "in_plus": { + "should_wait_for_popup": true + }, + "right_icon": { + "icon_url": "", //If defined replace original icon url of your app + "should_wait_for_popup": true, + "type": "file" //"file" | "call" + }, + "action": { + "should_wait_for_popup": true, + "description": "fdsqfds" //Description de l'action, sinon remplacΓ© par le nom de l'app + }, + "commands": [ + { + "command": "mycommand", // my_app mycommand + "description": "fdsqfds" + } + ] + }, + "channel": { + "can_connect_to_channel": "" + }, + "channel_tab": { + "iframe": "" + }, + "app": { + "iframe": "", + "plus_btn": { + "should_wait_for_popup": true + } + }, + "configuration": { + "can_configure_in_workspace": true, + "can_configure_in_channel": true, + "can_configure_in_calendar": true, + "can_configure_in_tasks": true, + //"can_configure_in_directory": true + } + } + } +} +``` + diff --git a/Documentation/docs/developers-api/application-settings/identity.md b/Documentation/docs/developers-api/application-settings/identity.md new file mode 100644 index 00000000..503e12cc --- /dev/null +++ b/Documentation/docs/developers-api/application-settings/identity.md @@ -0,0 +1,6 @@ +--- +description: How Identity are managed +--- + +# Identity + diff --git a/Documentation/docs/developers-api/application-settings/privileges.md b/Documentation/docs/developers-api/application-settings/privileges.md new file mode 100644 index 00000000..5841bc77 --- /dev/null +++ b/Documentation/docs/developers-api/application-settings/privileges.md @@ -0,0 +1,6 @@ +--- +description: Which privileges you need for your app +--- + +# Privileges + diff --git a/Documentation/docs/developers-api/blocks.md b/Documentation/docs/developers-api/blocks.md new file mode 100644 index 00000000..0dde4f11 --- /dev/null +++ b/Documentation/docs/developers-api/blocks.md @@ -0,0 +1,160 @@ +# 🧱 Blocks + +## Introduction: + +This guide will introduce you to use blocks to custom Twake messages. Twake allows application to send customs messages. This customs messages offer the possibility for an application to easily format the text your application wants to send and/or display UI components like button, input or iframe. + +## Write your first block: + +### 1. Take a look at slack block kit documentation + +* Go to this page: [Slack Block kit](https://api.slack.com/block-kit) +* Understand basic layers of block: + * Block + + First layer object, defining the use case of the current block (Actions, Context, Header, Files...). It can contain block elements and Composition object. + * Block elements + + Second layer object, defining complex element that will be display in a block (Button, Menus, Input...). It can contain composition object + * Composition object + + Third layer object, formatting the data to display in both block and/or block elements + +### 2. Try your first block + +* Go to this page: [Block Kit Builder](https://app.slack.com/block-kit-builder) +* Try to add/remove block +* Start writing block and check your result + +### 3. Twake block + +Twake have some blocks that are not implemented in slack block kit (iframes, progress bar and copiable). To use them please follow this: + +#### iframe + +An iframe is **Block** allowing you to display an html page in twake. + +How to use it: + +* Iframe type: + +``` +type BlockIframe = { + type: "iframe"; + iframe_url: string; + width: number; + height: number; + }; +``` + +* type: always "iframe" +* iframe\_url: the URL of the web page you want to display +* width: the with that you iframe will take +* height: the height that you iframe will take + +Example: + +``` +{ + "blocks": [ + { + "type": "iframe", + "iframe_url": " + https://twake.app + ", + width: "40vh", + height: "40vh" + } + ] +} +``` + +#### Copiable + +A copiable is **Block element** is a readable only input allowing you to copy string with a button. + +How to use it: + +* Copiable type: it is a plain text input block element with readonly and copiable set to true + +``` +type BlockElementPlaintextInput = { + type: "plain_text_input"; + action_id: string; + placeholder?: CompositionPlainTextObject; + initial_value?: string; + multiline?: boolean; + min_length?: number; + max_length?: number; + dispatch_action_config?: DispatchActionConfiguration; + readonly?: boolean; + copiable?: boolean; +}; +``` + +* type: always `"plain_text_input"` +* readonly: always `true` +* copiable: always `true` + +Example : + +``` +{ + "blocks": [ + { + "type": "input", + "element": { + "type": "plain_text_input", + "action_id": "plain_text_input-action", + "initial_value": "https://twake.app" + "readonly": true, + "copiable": true, + }, + } + ] +} +``` + +#### Progress bar + +A Progess bar is **Block element** that display a progress bar. + +How to use it: + +* Progress bar type: + +``` +export type BlockElementProgressBar = { + type: "progress_bar"; + value: number; + title: string; +}; +``` + +* type: always `"progress_bar"` +* value: the value of your progress between 0 and 100 +* title: the title associate to your progress bar + +Example : + +``` +{ + "blocks": [ + { + "type": "progress_bar", + "value": 50, + "title": "Chargement" + + } + ] +} +``` + + + + + + + + + diff --git a/Documentation/docs/developers-api/get-started/README.md b/Documentation/docs/developers-api/get-started/README.md new file mode 100644 index 00000000..f7b094da --- /dev/null +++ b/Documentation/docs/developers-api/get-started/README.md @@ -0,0 +1,19 @@ +--- +description: 'Welcome to the developers API of Twake, let''s begin together' +--- + +# πŸ₯‡ Getting started + +## Introduction: + +_While users have the ability to create message complexes using the built-in formatting system, applications can go even further and offer many types of messages such as system messages for notifications or interactive messages for your most popular applications._ + +## Basics: + +* [Create your first application](create-your-first-application.md) +* [Authenticate with Postman](authenticate-postman.md) +* [Send a message with your application](send-a-message-for-twake.md) +* [Trigger action from command](trigger-action-from-command.md) + + + diff --git a/Documentation/docs/developers-api/get-started/authenticate-postman.md b/Documentation/docs/developers-api/get-started/authenticate-postman.md new file mode 100644 index 00000000..5229ecb9 --- /dev/null +++ b/Documentation/docs/developers-api/get-started/authenticate-postman.md @@ -0,0 +1,39 @@ +--- +description: Postman example +--- + +# Authenticate with Postman + +## Introduction: + +This guide will introduce you to authenticate with [Postman](https://www.getpostman.com). + +## Prerequisites: + +* _You are a **manager** of the company._ +* You have already [created a Twake application](create-your-first-application.md). +* _You have previously installed_ [_Postman_](https://www.getpostman.com)_._ + +## Steps: + +### 1. Log your Application + +* Open Postman +* Find the app's credentials according to [#3.-api-settings](create-your-first-application.md#3.-api-settings "mention") +* Send POST request with : + * Url: https://web.twake.app/api/console/v1/login + * Headers: `{ "Content-Type": "application/json", }` + * Body: `{ id: $APP_`_`ID, secret: $APP_SECRET`_` ``}` +* This POST request will return a JWT token, this token will allow your application to send events in Twake + +### 2. Optional: Verify your token + +If you're not sure that the procedure to generate a token goes well : + +* Send GET request with : + * Url: https://web.twake.app/api/console/v1/me + * Headers: `{ "Content-Type": "application/json",` Authorization: "`Bearer " + $APP_TOKEN }` + + + +### diff --git a/Documentation/docs/developers-api/get-started/create-your-first-application.md b/Documentation/docs/developers-api/get-started/create-your-first-application.md new file mode 100644 index 00000000..a108c2f4 --- /dev/null +++ b/Documentation/docs/developers-api/get-started/create-your-first-application.md @@ -0,0 +1,78 @@ +--- +description: >- + You want to create an application for Twake? It's easy, just follow the steps + in this documentation! πŸ˜€ +--- + +# Create your first application + +## Introduction: + +This guide will walk you through creating, setting up and installing a Twake application. + +## Prerequisites: + +- _You are a **manager** of the company._ + +## Steps: + +### 1. Create a Twake application + +![ Fastest way to create an app](../../assets/twake-create-a-twake-app.gif) + +1. _Start by opening your `Workspace settings`_ +2. _Go to `Applications and connectors`, you should see an **Installed applications area** and **Applications developed by the company**,_ +3. _Click on `Access your applications and connectors` then `Create an application`,_ +4. _Enter your application name and application group._ + +**Application group** is used to group your application with other applications of the same type. **Be careful, the application group will not be modifiable later.** + +### **2. Identity of the application (Optional)** + +![](../../assets/twake-identity-of-the-application.gif) + +Let's add a description and an icon for our application. \ +it will be much prettier! πŸ˜‡ + +### 3. API settings + +There you will find some important pieces of information: + +![](../../assets/twake-api-settings.gif) + +- _Your API private key,_ +- _Your public application identifier,_ +- _URL that will be used to receive events for your application,_ +- _List of IP addresses that have the right to call the Twake API with your credentials. (You can use `*`during the development of your application.)_ + +**Private key** and **Public application identifier** ​​relate to **calls to the Twake API**. + +### 4. Display settings (Optional) + +![You can fill your JSON object here](../../assets/twake-display-settings.png) + +To configure where your application should display, you need to fill a `JSON` object in `Display Settings` field. + +[Here](../application-settings/application-visibility-example.md) is a quick example, each field is optional and his presence determines the positioning of your application in Twake. + +### 5. Application privileges + +![](../../assets/twake-application-privileges.gif) + +Your application can access and modify data, only according to your needs you don't need to access all the data present in Twake. \ +\ +This is why you must specify the accesses for the proper functioning of your application. These accesses will be public and indicated to the user before the installation of your application. + +In our example, we will only add `message_save` and `message_remove` in `Write privileges`.\ +\ +If you want to know more about capabilities and privileges, take a look at the list [here](../application-settings/privileges.md). + +### 6. Install application + +Once you've configured your application, you need to install it on Twake. + +![](../../assets/twake-install-application.gif) + +Go to `Applications and connectors`, search and display your application then install it. + +Your application is now ready, check the [Authenticate with Postman](authenticate-postman.md) documentation for starting using it ! diff --git a/Documentation/docs/developers-api/get-started/send-a-message-for-twake.md b/Documentation/docs/developers-api/get-started/send-a-message-for-twake.md new file mode 100644 index 00000000..df8e45a7 --- /dev/null +++ b/Documentation/docs/developers-api/get-started/send-a-message-for-twake.md @@ -0,0 +1,66 @@ +--- +description: Send a message through API +--- + +# Send a message with your application + +\ +Introduction: + +--- + +This guide will introduce you to send message with your application in Twake. + +## Prerequisites: + +- You have already created a Twake application. +- _Your application is installed and saved in your company._ + +## Steps: + +### 1. Send message as a new Thread + +- Find the app's token according to [1. Log your Application](authenticate-postman.md#1.-log-your-application) +- Find the identifiers to target a channel: + - Company's _id: $COMPANY_ID_ + - Workspace's \_id: $WOKSPACE\_\_ID + - Channel's _id: $CHANNEL_ID_ +- _Set the message you want to send:_ + + - _Minimal:_ + + _$MESSAGE = { "text": "Hello world !" }_ + + - _To take full advantage of the messages capability in Twake see the_ [_MessageObject_](../../internal-documentation/backend-services/messages/database-model.md)\_\_ + +- Send POST request with : + - Url: https://web.twake.app/api/messages/v1/companies/$COMPANY\_ID/threads + - Headers: `{ "Content-Type": "application/json",` Authorization: "`Bearer " + $APP_TOKEN }` + - Body: `{ resource: { participants: [ { type: "channel", id: $CHANNEL_ID, company_id: $COMPANY_ID, workspace_id: $WORKSPACE_ID, }, ], }, options: { $MESSAGE }, }` +- This POST request will return a [ThreadObject](../../internal-documentation/backend-services/messages/database-model.md) + +### 2. Send message as a Thread answer + +- Find the app's token according to [1. Log your Application](authenticate-postman.md#1.-log-your-application) +- Find the identifiers to target a channel: + - Company's _id: $COMPANY_ID_ + - Workspace's \_id: $WOKSPACE\_\_ID + - Channel's _id: $CHANNEL_ID_ + - _Thread's id: $THREAD_Id_ +- _Set the message you want to send:_ + + - _Minimal:_ + + _$MESSAGE = { "text": "Hello world !" }_ + + - _To take full advantage of the messages capability in Twake see the_ [_MessageObject_](../../internal-documentation/backend-services/messages/database-model.md)\_\_ + +- Send POST request with : + - Url: https://web.twake.app/api/messages/v1/companies/$COMPANY_ID/threads/$THREAD\__ID + - Headers: `{ "Content-Type": "application/json",` Authorization: "`Bearer " + $APP_TOKEN }` + - Body: `{ resource: { $MESSAGE } }` +- This POST request will return a [MessageObject](../../internal-documentation/backend-services/messages/database-model.md) + +### 3. Applications can send customized messages + +The [MessageObject](../../internal-documentation/backend-services/messages/database-model.md) object have a property called "block" that allow your application to send messages which contains more than a simple string. For example in an application message you can display an iFrame, buttons, menu selector, etc... Combining all this options you can create everything you want up to the limit of your imagination. To understand how to create powerful message using the block property see [blocks](../blocks.md). diff --git a/Documentation/docs/developers-api/get-started/trigger-action-from-command.md b/Documentation/docs/developers-api/get-started/trigger-action-from-command.md new file mode 100644 index 00000000..12be7559 --- /dev/null +++ b/Documentation/docs/developers-api/get-started/trigger-action-from-command.md @@ -0,0 +1,41 @@ +--- +description: Trigger action from command +--- + +# Trigger action from command + +## Introduction: + +This guide will introduce you to trigger action from your application using command + +## Prerequisites: + +* You have already created a Twake application. +* Your application is installed and saved in your company. + +## Steps: + +### 1. Let your application listen to command + +* Go in your app developer's setting: + * Click on your username in the top left corner + * Go to workspace settings + * Go to integrations + * Click on the three-dot next to your application + * Open developper setting +* Click on display +* You will find and editable object containing a twake object +* Add a new property commands in this object like this: + + * `"commands" : [{"command": string, "descritpion": string }]` + * The first property of commands is command that let you define a name for your command, by default the command name is the name of your application. + * The second property of command is description that let you describe the way to use the command you want to define. + + + +### 2. Use your command in a channel + +* In the message editor write /command +* A popup displaying the description on how to use the command related to your application should open. + +__ diff --git a/Documentation/docs/developers-api/home.md b/Documentation/docs/developers-api/home.md new file mode 100644 index 00000000..8f537fda --- /dev/null +++ b/Documentation/docs/developers-api/home.md @@ -0,0 +1,36 @@ +--- +description: >- + Welcome to the developers API home, here you can create apps, plugins and + connectors for Twake. +--- + +# 🏠 Home + +## Introduction: + +Twake offer the possibility to uses a lot of application to increase the quality of your team workflow. You can now easily send a Gif to add conviviality into your channels, start Jitsi calls in one click, create polls or even get notified in your channels using webhooks or automation as powerful as n8n allows. + + + +## Ready to use integration: + +Twake have some integrations ready to use that are just waiting for you to be installed in your workspaces. You can find in the list below these integrations: + +* Jitsi: [https://github.com/linagora/Twake-Plugins-Jitsi](https://github.com/linagora/Twake-Plugins-Jitsi) +* Giphy: [https://github.com/linagora/Twake-Plugins-Giphy](https://github.com/linagora/Twake-Plugins-Giphy) +* SimplePoll: [https://github.com/linagora/Twake-Plugins-SimplePoll](https://github.com/linagora/Twake-Plugins-SimplePoll) +* Webhoocks: [https://github.com/linagora/Twake-Plugins-Webhooks](https://github.com/linagora/Twake-Plugins-Webhooks) +* N8n: [https://github.com/linagora/Twake-Plugins-n8n](https://github.com/linagora/Twake-Plugins-n8n) + +## Imagination is your limit + +By installing webhooks or n8n in your workspace, you can now imagine infinite uses cases to increase the quality of your team workflow. Connect your channels to get notify of new code changes when pushing on github or to get notify in a n8n workflow. + +If you think that you can't do something with integration, as Twake is open source, feel free to contribute to an existing Twake's integration or even more create the new integration that answer to your need. + + + +> Please do not work on this list of plugins as we already made them (their are just not yet open-sourced)\ +> Zapier, IFTTT, OnlyOffice, RSS feed, Github, Gitlab and Reminder. + +πŸ€— We are not yet ready for this documentation, up this issue to have it sooner : [https://github.com/TwakeApp/Twake/issues/116](https://github.com/TwakeApp/Twake/issues/116) diff --git a/Documentation/docs/developers-api/run-twake-as-developer.md b/Documentation/docs/developers-api/run-twake-as-developer.md new file mode 100644 index 00000000..72f2747f --- /dev/null +++ b/Documentation/docs/developers-api/run-twake-as-developer.md @@ -0,0 +1,70 @@ +--- +description: >- + Welcome to the internal documentation section. This chapter is for developers + working in Twake team or wanting to participate in the project. +--- + +# πŸ₯‡ Get started + +> If you are looking for the Developers API of Twake to make plugins, apps or connectors, go here : [Developers API](../developers-api/home.md) + +## Before to start + +- Fork our repo [https://github.com/TwakeApp/Twake](https://github.com/TwakeApp/Twake) and checkout the **develop** branch + +::: info +You want to fix a translation issue? We use Weblate: [https://hosted.weblate.org/projects/linagora/twake-chat-web/](https://hosted.weblate.org/projects/linagora/twake-chat-web/) +::: + +## Run the backend (+ database) + +1. Go to "twake/" +2. `docker-compose -f docker-compose.dev.mongo.yml up -d` +3. The backend will be running on port 3000 + +## Run the frontend + +1. Go to "twake/frontend" +2. Run `yarn install` (better to use **yarn** than **npm**), our developers uses node 14 and 16, it should work with any upper version. +3. Prepare the **environment.ts** file like this: `cp environment/environment.ts.dist.dev environment/environment.ts` + +``` +export default { + env_dev: true, + front_root_url: 'http://localhost:3001', + api_root_url: 'http://localhost:3000', + websocket_url: 'ws://localhost:3000' +}; +``` + +5\. Run `yarn start` + +6\. It will propose to run on another port, say "yes" to run it on port 3001. + +## Test and start develop + +You should be able to go on localhost port 3001 just click on "create an account" and you'll be able to access Twake after a few steps. + +\-> Logs from backend can be accessed from `docker-compose -f docker-compose.dev.mongo.yml logs -f --tail 100` + +\-> Logs from frontend are visible in the output of `yarn start` + +You can start writing code πŸŽ‰ ! It will reload the backend / frontend automatically each time you save. + +::: danger +Before to start implementing a new feature or bug fix, please find or create an issue on our repository (here [https://github.com/linagora/Twake/issues](https://github.com/linagora/Twake/issues)) and put a comment to inform that you will work yourself on the issue. To avoid two same people doing the same work ;) +::: + +::: info +If you have any issue, please come and join us on [https://community.twake.app/](https://community.twake.app) +::: + +## Propose an improvement to be merged + +For this you need to create a merge request on Github from your fork to our develop branch. Goes there: [https://github.com/linagora/Twake/compare](https://github.com/linagora/Twake/compare) and click "compare across forks". + +Tests will be ran automatically and should pass before to merge the code. + +::: info +We are hiring! Apply now on [https://job.linagora.com/en/join-us/](https://job.linagora.com/en/join-us/) +::: diff --git a/Documentation/docs/download.md b/Documentation/docs/download.md new file mode 100644 index 00000000..f1462939 --- /dev/null +++ b/Documentation/docs/download.md @@ -0,0 +1,15 @@ +--- +description: How to download Twake +--- + +# ⬇️ Download desktop and mobile apps + +## Desktop + +You can download Twake for Mac, Windows, Linux here: [https://twake.app/download](https://twake.app/download) + +Click on the version according your OS, and click on "download" to get the desktop application. + +## Mobile + +iOS, Android is also available from Google Play Store and the App Store. diff --git a/Documentation/docs/get-started.md b/Documentation/docs/get-started.md new file mode 100644 index 00000000..59db8707 --- /dev/null +++ b/Documentation/docs/get-started.md @@ -0,0 +1 @@ +# Get started diff --git a/Documentation/docs/how-to-use-it/applications/README.md b/Documentation/docs/how-to-use-it/applications/README.md new file mode 100644 index 00000000..7afdee77 --- /dev/null +++ b/Documentation/docs/how-to-use-it/applications/README.md @@ -0,0 +1,6 @@ +--- +description: Discover Twake application +--- + +# πŸ’  Applications + diff --git a/Documentation/docs/how-to-use-it/applications/calendar.md b/Documentation/docs/how-to-use-it/applications/calendar.md new file mode 100644 index 00000000..1da2997b --- /dev/null +++ b/Documentation/docs/how-to-use-it/applications/calendar.md @@ -0,0 +1,6 @@ +--- +description: How to use Twake calendar +--- + +# πŸ“† Calendar + diff --git a/Documentation/docs/how-to-use-it/applications/connectors/README.md b/Documentation/docs/how-to-use-it/applications/connectors/README.md new file mode 100644 index 00000000..c24c6ecd --- /dev/null +++ b/Documentation/docs/how-to-use-it/applications/connectors/README.md @@ -0,0 +1,6 @@ +--- +description: How to add connector on Twake +--- + +# πŸ”ƒ Connectors + diff --git a/Documentation/docs/how-to-use-it/applications/connectors/n8n.md b/Documentation/docs/how-to-use-it/applications/connectors/n8n.md new file mode 100644 index 00000000..fc11cf70 --- /dev/null +++ b/Documentation/docs/how-to-use-it/applications/connectors/n8n.md @@ -0,0 +1,21 @@ +--- +description: Did you ever dreamed to use Twake and n8n together ? +--- + +# n8n + +## How to connect Twake with n8n + +n8n is a powerful workflow automation tool wich can be self hosted : [n8n.io](https://n8n.io) + +![n8n interface](../../../assets/image.png) + +### Install n8n in Twake + +Install your n8n application in your workspace and get your key : + +![](../../../assets/how-to-install-n8n.gif) + +### Create your credential on n8n + +![](../../../assets/n8n-implement.gif) diff --git a/Documentation/docs/how-to-use-it/applications/drive/README.md b/Documentation/docs/how-to-use-it/applications/drive/README.md new file mode 100644 index 00000000..5b051542 --- /dev/null +++ b/Documentation/docs/how-to-use-it/applications/drive/README.md @@ -0,0 +1,6 @@ +--- +description: How you can use the drive on Twake +--- + +# πŸ“‚ Drive + diff --git a/Documentation/docs/how-to-use-it/applications/drive/file-and-folder.md b/Documentation/docs/how-to-use-it/applications/drive/file-and-folder.md new file mode 100644 index 00000000..9296adf8 --- /dev/null +++ b/Documentation/docs/how-to-use-it/applications/drive/file-and-folder.md @@ -0,0 +1,8 @@ +--- +description: How you can create file & folder on Twake +--- + +# File and folder + +## + diff --git a/Documentation/docs/how-to-use-it/applications/drive/share-file-with-public-link.md b/Documentation/docs/how-to-use-it/applications/drive/share-file-with-public-link.md new file mode 100644 index 00000000..1a02bf4f --- /dev/null +++ b/Documentation/docs/how-to-use-it/applications/drive/share-file-with-public-link.md @@ -0,0 +1,21 @@ +--- +description: How you can share your files with a public link +--- + +# Share file with public link + +In Twake, you can share your folders or files to external user. You juste have to create a public link on what you want to share and send the link. Your partner will access to these elements without creating a Twake account. + +### Create a public link + +Click on "public access" of what you want to share and "create an access link". + +![](../../../assets/sans-titre-2-1.gif) + +### + +### Remove a public link + +If you want to remove the public link, select folder you want to unlink, then, "Public access" and "Suppress the link" + +![](../../../assets/sans-titre-2.gif) diff --git a/Documentation/docs/how-to-use-it/applications/how-to-use-chat/README.md b/Documentation/docs/how-to-use-it/applications/how-to-use-chat/README.md new file mode 100644 index 00000000..ef2f3e57 --- /dev/null +++ b/Documentation/docs/how-to-use-it/applications/how-to-use-chat/README.md @@ -0,0 +1,11 @@ +--- +description: How Twake chat is working +--- + +# πŸ’¬ Chat + +The discussion application are Twake's entry points. This is where you communicate with your team. + +[channels](channels.md) + +[message](message.md) diff --git a/Documentation/docs/how-to-use-it/applications/how-to-use-chat/channels.md b/Documentation/docs/how-to-use-it/applications/how-to-use-chat/channels.md new file mode 100644 index 00000000..40ecdbd7 --- /dev/null +++ b/Documentation/docs/how-to-use-it/applications/how-to-use-chat/channels.md @@ -0,0 +1,51 @@ +--- +description: Discover how channels are used on Twake +--- + +# Channels + +## Create a channel + +To create a channel, you must have `Administrator` rights for the workspace in question. + +[rights](../../company-and-workspace/rights.md) + +To create your channel, click on the `+` button right to the "Channel" inscription. Fill a name for your channel, select a wonderful emoji and select if it is a public or private channel \(by default, channels are private\). + +## Channel sections + +You can organize your channel by grouping them. If you are `Administrator`, you can drag a channel and drop in the section you want `Add here` or in `New group`. + +To edit section name, you just have to click on it, change the name and press `Enter` + +![](../../../assets/channel-move.gif) + +## Public channel + +Public channels are visible to all members of the workspace. + +## Private channel + +Private channels are channels accessible only to a limited number of users. Members not present in these channels cannot see them. + +### Modify the members of a private channel + +You can choose the members of a private channel when creating it. To modify the members of a private channel once created, place your mouse on the channel, click on the `...` then on `Edit channel`, in the `Participants` box, you can add or remove the members of the channel. + +![](../../../assets/private-channel-member.gif) + +## External member + +You have the possibility to invite external members to your channel. External members are members who are not in the workspace and who are added to one, or more, specific channel\(s\). + +This feature is useful for inviting users who are not in your company. Freelancers, for example, can be added to a specific channel to collaborate on a project. They will only have access to this channel, they will not see public channels. + +![](../../../assets/externalmember.gif) + +## Mute a channel + +You can mute a channel so that you do not receive notification of it. You will not receive a new notification from that channel unless you are mentioned \(with @username\). To do it, click on `...` and `Mute`a barred bell icon will appear. + +## Star a channel + +If a channel is very important for you, you can star it. Stared channels are gathered at the top of your channel. It is only for your view, not for everyone. To star a channel click on `...` and `Star this channel`. Your channel will be move to the stared channel section \(at the top\). diff --git a/Documentation/docs/how-to-use-it/applications/how-to-use-chat/message.md b/Documentation/docs/how-to-use-it/applications/how-to-use-chat/message.md new file mode 100644 index 00000000..407cc69b --- /dev/null +++ b/Documentation/docs/how-to-use-it/applications/how-to-use-chat/message.md @@ -0,0 +1,59 @@ +--- +description: Send message on Twake +--- + +# Message + +## Send a message + +To send a message, select the channel where you want to post. In the input message, write what you want to send. Press `enter` to send the message. + +If you want to add a new line to your message, press `Shift + Enter`. + +![](../../../assets/sendmessage.gif) + +#### Pin + +If one of the message is important for the team, you can pin it \(or unpin\) + +![](../../../assets/pinmessage.gif) + +#### Reaction + +You can react to a message with emoji. Click on the `Emoji button` in message to show emoji picker. + +### Response to a message + +Someone ask you a question ? You can answer it by clicking `Answer` below the message. + +![](../../../assets/responsemessage.gif) + +### Reorganize your chat + +You can reorganize your chat by dragging and dropping your messages. + +![](../../../assets/d-and-dmessage.gif) + +### + +### See thread message + +You can see a thread in a specific view. Hover over in one, the button `Show on the right` . A side panel opens. + +## Integration + +### Gif + +You can send gif in your channel. Just clic gif icon to open a gif selector. + +![](<../../../assets/gif-(1).gif>) + +### Call + +If you need to call your team, there is native integration with Jitsi. Just click on the green button with the phone and a menu opens on the left to create a Jitsi call. Once the information is filled in, the call link is sent to your team. + +## Send document + +If you want to send a document through the chat, drag it from your computer and drop it into the chat. It will be uploaded and shared with your teammates. + +You can also send a document from Twake drive: click on the `+` button, to the left of the input. You can select a file from Twake and share it in the chat room. diff --git a/Documentation/docs/how-to-use-it/applications/tasks.md b/Documentation/docs/how-to-use-it/applications/tasks.md new file mode 100644 index 00000000..9127ae4c --- /dev/null +++ b/Documentation/docs/how-to-use-it/applications/tasks.md @@ -0,0 +1,6 @@ +--- +description: How to use Twake task +--- + +# βœ… Tasks + diff --git a/Documentation/docs/how-to-use-it/company-and-workspace/README.md b/Documentation/docs/how-to-use-it/company-and-workspace/README.md new file mode 100644 index 00000000..0ad7fa5e --- /dev/null +++ b/Documentation/docs/how-to-use-it/company-and-workspace/README.md @@ -0,0 +1,17 @@ +--- +description: How company and workspace work on Twake +--- + +# 🏒 Company & workspace + +## Company + +Companies are the largest entities on Twake. They represent your virtual business. You will find all your employees and connectors that you have developed internally. Inside your company is your workspaces. + +You can switch from one company to an other by clicking on the left bottom button : + +![](../../assets/changecomp.gif) + +## Workspace + +Workspaces represent the teams or departments in your company. Each workspace has its members, discussions, files, tasks, and calendar. It's your team's sharing space. diff --git a/Documentation/docs/how-to-use-it/company-and-workspace/invite-user-from-chat.md b/Documentation/docs/how-to-use-it/company-and-workspace/invite-user-from-chat.md new file mode 100644 index 00000000..8d4b659a --- /dev/null +++ b/Documentation/docs/how-to-use-it/company-and-workspace/invite-user-from-chat.md @@ -0,0 +1,15 @@ +--- +description: Invite user from Twake +--- + +# Invite user from Chat + +You can invite user in your workspace. + +Open the menu, and click on `Collaborators` > `Add colleagues`. Enter emails of your colleagues \(separated with coma\) and validate. + +![](../../assets/invitefromtwake.gif) + +You can also invite users from the console : + +[users](../console/users.md) diff --git a/Documentation/docs/how-to-use-it/company-and-workspace/rights.md b/Documentation/docs/how-to-use-it/company-and-workspace/rights.md new file mode 100644 index 00000000..ec303134 --- /dev/null +++ b/Documentation/docs/how-to-use-it/company-and-workspace/rights.md @@ -0,0 +1,70 @@ +--- +description: How rights are managed on Twake +--- + +# Rights + +Twake has several levels of rights. Users belong to one or more workspaces within the company. They can have different statuses inherent to their membership to the company or workspace + +## Owner + +He's the main administrator of the whole company. He can: + +- Allow connectors and applications to be installed in workspaces +- Change the corporate identity +- Giving/withdrawing the right "Owner of the company" to a member of the company + +The creator of the company is the only owner. You can not change this role. Only the creator can be owner of the company. + +## Admin + +An admin has the same right than the owner. He can: + +- Allow connectors and applications to be installed in workspaces +- Change the corporate identity +- Giving/withdrawing the right "Owner of the company" to a member of the company + +The creator of the company is the only owner. You can not change this role. Only the creator can be owner of the company. + +To grant the admin right, open the console \([https://console.twake.app](https://console.twake.app)\). Open `Users` section and `Edit` the member you want to set admin. Update the Role with `Admin` and save. + +![](../../assets/setadmin.gif) + +## Workspace administrator + +He's the team administrator. He has the same rights as a user. In addition, he can: + +- Add/remove connectors and applications in the workspace +- Changing the identity of the workspace +- Adding members to the workspace +- Delete workspace + +By default, the creator of the workspace is the administrator. This right can be cumulated with that of a company administrator. + +To grant the workspace level, open your workspace collaborators page, and select `Administrator` + +![](../../assets/setwsadmin.gif) + +## User + +The "user" right is the default right of a member in a workspace. It can : + +- Read and send messages to public and private chat channels \(to which he has been invited\) +- Create, modify, delete documents from the drive +- Create, edit, delete events and calendars +- Create, modify, delete tables and tasks Invite users to the workspace +- Create a workspace within the company + +It's a default right. If the collaborator is not Company or Workspace administrator and he is not a Guest user, he is a simple User + +## Guest + +This status is intended for external partners working on a specific topic with the team. Guest user can : + +- Talk in the channel where they are invited + +They can not join by themself any channel \(even public\). They need to be invited by a normal user. + +To set the Guest level, open the console \([https://console.twake.app](https://console.twake.app)\) and the users page. Set the user's role to "Guest". + +![](../../assets/setguest.gif) diff --git a/Documentation/docs/how-to-use-it/console/README.md b/Documentation/docs/how-to-use-it/console/README.md new file mode 100644 index 00000000..c49d0eb8 --- /dev/null +++ b/Documentation/docs/how-to-use-it/console/README.md @@ -0,0 +1,12 @@ +--- +description: How to use the Twake console +--- + +# 🧰 Console + +The console is where you can manage your company and all information shared on Twake, LinShare and more. + + + + + diff --git a/Documentation/docs/how-to-use-it/console/users.md b/Documentation/docs/how-to-use-it/console/users.md new file mode 100644 index 00000000..66c0a735 --- /dev/null +++ b/Documentation/docs/how-to-use-it/console/users.md @@ -0,0 +1,36 @@ +--- +description: How users are managed in the Twake console +--- + +# Users + +As user admin, you have access to the user management page. + +Open the console : [https://console.twake.app/](https://console.twake.app/) and open the page "Users". + +![User management page](../../assets/image-2.png) + +## Add a user + +To work with your colleagues in your company, you have 2 choices : + +- Create user account +- Invite them by email + +You can also invite users from the chat : + +[invite-user-from-chat](../company-and-workspace/invite-user-from-chat.md) + +### Send email invitation + +To send an invitation, you can click on `Add user` > `Invite users`.Enter emails you want to invite separated with coma. After validation, an email is sent to this address. Your colleagues will have a link to signup and join your company. + +![Invite user](../../assets/inviteuser.gif) + +### Create user account + +You can create directly accounts for your colleagues. For that, click on `Add user` > `Create account`. After giving email, name and Role, you can specify a password \(or generate a random one\). You just have to send credentials to your teammate. + +![](../../assets/createuser.gif) + +## Manage user diff --git a/Documentation/docs/how-to-use-it/desktop-and-mobile-app.md b/Documentation/docs/how-to-use-it/desktop-and-mobile-app.md new file mode 100644 index 00000000..9bd15007 --- /dev/null +++ b/Documentation/docs/how-to-use-it/desktop-and-mobile-app.md @@ -0,0 +1,32 @@ +--- +description: "Yes, we have desktop and mobile apps !" +--- + +# πŸ–₯ Desktop and mobile app + +## Desktop + +You can download Twake for Mac, Windows, Linux here: [https://github.com/linagora/Twake-Desktop/tree/master/download](https://github.com/linagora/Twake-Desktop/tree/master/download) + +Click on the version according your OS, and click on "download" to get the desktop application. + +![](<../assets/image-(3)-(1).png>) + +### Switch to on-premise servers + +On the desktop app, you can use the following options to change your server: + +β€’ On MacOS, click on Help > Change Twake Server +β€’ On Windows, MacOS and Linux, use the shortcut CTRL+ALT+SHIFT+S or CMD+ALT+SHIFT+S + +## Mobile App + +The mobile app is available on iOS App Store and Android Play Store. + +### Switch to on-premise servers + +On the mobile app, just log out and you should be able to change the server from the bottom left login page link "Change Server". + +#### Push notifications on the on-premise mobile app + +This feature is not yet available, say you want this feature using a "thumbs up" emoji here: [https://github.com/TwakeApp/Twake/issues/130](https://github.com/TwakeApp/Twake/issues/130) diff --git a/Documentation/docs/how-to-use-it/privacy-security.md b/Documentation/docs/how-to-use-it/privacy-security.md new file mode 100644 index 00000000..f5fd7926 --- /dev/null +++ b/Documentation/docs/how-to-use-it/privacy-security.md @@ -0,0 +1,102 @@ +# πŸ”’ Privacy + +You will find everything related to privacy in this document [https://twake.app/en/privacy/](https://twake.app/en/privacy/). + +At Twake we are committed to protecting your privacy. We implemented specific security features to ensure that your data is safe and secure. + +## General presentation of Twake + +Twake is available in two main versions : + +- SaaS : Twake as a service (SaaS available on twake.app) +- On-Premise : Twake on-premise (on private servers or on dedicated servers managed by + Twake) + +The Twake SaaS version is hosted in France by a French infrastructure provider. All servers are located in Paris (UE). + +The Twake On-Premise version can be deployed on any local server and can work fully disconnected from the Internet or with an unique and unidirectional connection to twake.app for licencing management, mailing and iOS and Android push notifications (that are not available without additional configuration in fully disconnected mode). + +On SaaS version, Twake provide two main tiers softwares : + +- ONLYOFFICE spreadsheet, ONLYOFFICE document and ONLYOFFICE presentation, https:// + onlyoffice.com +- Jitsi video-conferencing, https://jitsi.org/ + +On the On-Premise version those softwares are optionals. + +## Quick FAQ about Twake security + +#### Where are your servers ? + +Twake servers are all in France, in Paris. + +#### Are you GRPD compliant ? + +Yes ! As you can see in this document, we do everything we can do to protect your personal and professional data. Concerning your password and personal data specifically, passwords are hashed using PBKDF2, your data is encrypted before to be sent to the database (encryption at rest on the application layer) and we use TLS.0 for communications (encryption on transit). Moreover, we do not require any personal data in order for you to use our software, you can use Twake without disclosing personal information. + +#### What protocol do you use ? + +We use HTTPS for unidirectional traffic encryption and WSS for bidirectional realtime traffic encryption. Passwords are hashed with PBKDF2. Files are encrypted with OpenSSL AES-256-CBC with a key composed of three parts stored in database, in code and in the server configuration. Finally our database data is encrypted with OpenSSL AES-256-CBC. In order to always improve our security, next version of Twake will include full end-to-end encryption for direct and private channels using the Matrix protocol. + +#### How do you manage backups ? + +We backup our encrypted database and your encrypted documents in a replicated Object Storage. We keep a backup of each month and a backup of each of the last seven days. + +#### What if I want to export all my data ? + +We do not provide an export feature on the software itself. But we have the ability to export your data on-demand, please contact us for more information. + +#### Can I delete my account and erase my data ? + +Yes, you can delete your account and erase your data. To proceed, open your account from the "console" and click on "Delete my account". You will be asked to confirm your choice. Once your account is deleted, you will not be able to access it anymore. + +#### How do you manage security with tiers applications and modules ? + +We cannot guarantee the security of the data you send to tiers applications and modules. If you work with an external app like Zapier or Giphy, they will have access to some of your information. You can see the access scope of an application before to add it to your company. + +## High availability + +Twake is built on scalable technologies and allow us to scale to million users but also to be fault tolerant. We define two kind of replication, hardware replication and software replication: + +Hardware replication in case of hard disk crash or network issue is managed by our infrastructure provider, you will find more details on how they manage this following these links: + +- Servers: https://www.ovhcloud.com/en/public-cloud/ +- Object storage and backups: https://www.ovhcloud.com/en/public-cloud/object-storage/ + +Software replication is done by ourself. Each middleware and nodes used by Twake are replicated at least three time. In the rare case of node failure, our system automatically alerts us and start using the remaining available node until we operate and fix the broken one. + +## Application encryption + +Data are stored encrypted in ScyllaDB and searchable entities will be stored in Elastic Search. + +#### ScyllaDB + +Any data (except non-sensible data like identifiers, dates and counters) stored in ScyllaDB is encrypted using OpenSSL AES-256-CBC before being sent to the database. + +#### Indexed search storage + +We provide advanced search features to our product Twake using Elastic Search to index our entities. Entities are not stored in Elastic Search and only indexes will be available if Twake Elastic Search servers are compromised. + +## Other + +#### Random token generation + +For random generation we use the PHP built-in random_bytes function with bin2hex if needed on PHP side and the crypto library with randomBytes from NodeJS and frontend side. + +#### Passwords storage and authentication + +Passwords are not stored in clear, only a hash of it is stored in database. We use the hash_pbkdf2 method with a randomly generated salt for each user. + +#### SQL Injection + +Each database access use Doctrine ORM sanitisation before write or reads, we never use custom access to the database to reduce risks of injection. We developed a middleware to use ScyllaDB databases but this middleware works after Doctrine ORM sanitisation. +On NodeJS, we also implemented an ORM for all database access in order to keep this level of security. + +#### XSS + +We use React as front-end framework and we never execute tiers Javascript. External apps are loaded in webviews or iframes and use a bridge designed like a router for data exchange between frames. + +## Continuous security checks + +- We use Snyk to ensure that our dependencies are up to date and secure. +- We are active on huntr.dev to ensure that we fix all security issues reported by the community. diff --git a/Documentation/docs/how-to-use-it/welcome.md b/Documentation/docs/how-to-use-it/welcome.md new file mode 100644 index 00000000..e0d03768 --- /dev/null +++ b/Documentation/docs/how-to-use-it/welcome.md @@ -0,0 +1,10 @@ +--- +description: Discover how to use Twake +--- + +# πŸ‘‹ Welcome to Twake ! + +Twake is an open source collaborative workspace. It can be self-hosted, used is saas and easily integrated into your teams. Twake offers all the features for collaboration : team chat, file storage, team calendar, tasks manager. + +In this chapter, you'll find how to use Twake. + diff --git a/Documentation/docs/index.md b/Documentation/docs/index.md new file mode 100644 index 00000000..e03a23ce --- /dev/null +++ b/Documentation/docs/index.md @@ -0,0 +1,45 @@ +# β˜€οΈ Welcome to Twake + +Twake is an open source collaborative workspace. It can be self-hosted, used is saas and easily integrated into your teams. Twake offers all the features for collaboration : team chat, file storage, team calendar, tasks manager. + +This **documentation** assists developers and users in having the best Twake experience as possible. We’ve developed Twake to have a better teamwork. + +--- + +# 🌎 Use Twake on twake.app + +#### Start using Twake now + +To use Twake online it is simple, just go on [twake.app](https://twake.app) and click "Sign up". + +> Want to install it on your own server ? [It is here](onprem/installation.md)). + +#### Now, you can learn how to become a Twake super-user + +> Learn how to become a power user of Twake: [welcome.md](./how-to-use-it/welcome.md) + +> If you want to see the latest updates you can go here: [https://github.com/linagora/Twake/blob/main/changelog.md](https://github.com/linagora/Twake/blob/canary/changelog.md) + +## Use the canary version to try out new features + +You want to try the latest features from Twake before they come out to production? You can! + +We have a server called Canary that will give you access to new features 1 month before their official releases. This server is compatible with the classic server so it means you can still discuss with your team even if you are the only one using the canary server. + +The goal of the canary server it to do additional testing with a larger set of users, so if you encounter any issue, please notify us to help us fix the version before to ship it on production. + +When using the canary server, the best is to set it up on all your devices like so: + +#### How to use it on my browser + +Just go to [canary.twake.app](https://canary.twake.app) instead of web.twake.app. + +#### How to use it on the desktop app + +Press Shift+Alt+Command or Shift+Ctrl+Alt to open the "Change server url" popup then enters [https://canary.twake.app](https://canary.twake.app) in the input then press OK. + +#### How to use it on the mobile app + +Logout from the mobile app, click on Change server and put [https://canary.twake.app](https://canary.twake.app) then login. + +> If you want to see the latest updates on the **canary** server you can go here: [https://github.com/linagora/Twake/blob/canary/changelog.md](https://github.com/linagora/Twake/blob/canary/changelog.md) diff --git a/Documentation/docs/internal-documentation/backend-services/README.md b/Documentation/docs/internal-documentation/backend-services/README.md new file mode 100644 index 00000000..6256b7fb --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/README.md @@ -0,0 +1,36 @@ +--- +description: >- + This page will document all the services implemented in the new NodeJS + backend. For all the PHP services not yet migrated, please ask us directly on + https://community.twake.app/ +--- + +# 🧱 Backend and APIs + +## Twake Services + +As a frontend developer / connector developer to read our APIs, or to understand our data models or just for fun, here is all the details over Twake backend services. + +If document are empty, check out our Notion documentation: [https://www.notion.so/twake/Backend-documentation-e219323593d2401c9887d0e11b2a597b](https://www.notion.so/twake/Backend-documentation-e219323593d2401c9887d0e11b2a597b) + +### Services + +[users/](users/README.md) + +[applications/](applications/README.md)) + +[channels/](channels/README.md)) + +[messages/](messages/README.md)) + +[notifications/](notifications/README.md)) + +## Get started to code in Twake + +Want to edit Twake code ? Congratulation ! You participate in the development of a great product πŸ˜ƒ + +[start-working-into-a-service](intro/start-working-into-a-service.md) + +[create-a-new-twake-service](intro/create-a-new-twake-service.md) + +[intro/platform/](intro/platform/README.md)) diff --git a/Documentation/docs/internal-documentation/backend-services/applications/README.md b/Documentation/docs/internal-documentation/backend-services/applications/README.md new file mode 100644 index 00000000..945ca4d9 --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/applications/README.md @@ -0,0 +1,22 @@ +--- +description: How applications are managed in Twake backend +--- + +# 🍎 Applications + +#### Description + +**Applications** is everything related to connectors in Twake. + +An application is described by an identity sheet containing this information: + +- **Identity** \(name, description, logo\) +- **API** **preferences** \(Twakeβ†’Connector events endpoint, API id and secret, and Connectorβ†’Twake allowed IPs\) +- **Privileges and capabilities** \(List of things the connector can read and can write\) +- **Display information** \(Where the connector is visible, button in chat, configuration in application list etc\) + +This is all we need to define a connector. + +[database-models](database-models.md) + +[rest-apis](rest-apis.md) diff --git a/Documentation/docs/internal-documentation/backend-services/applications/database-models.md b/Documentation/docs/internal-documentation/backend-services/applications/database-models.md new file mode 100644 index 00000000..785817f8 --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/applications/database-models.md @@ -0,0 +1,130 @@ +--- +description: Application models for backend +--- + +# Database models + +**applications**\ +****Represent an application in the database + +```javascript +{ + //PK + "company_id": uuid; + "id": uuid; + + "identity": ApplicationIdentity; + "api": ApplicationApi; + "access": ApplicationAccess; + "display": ApplicationDisplay; + "publication": ApplicationPublication; + "stats": ApplicationStatistics; +} + +type ApplicationIdentity = { + name: string; + iconUrl: string; + description: string; + website: string; + categories: string[]; + compatibility: "twake"[]; +}; + +type ApplicationPublication = { + published: boolean; +}; + +type ApplicationStatistics = { + createdAt: number; + updatedAt: number; + version: number; +}; + +type ApplicationApi = { + hooksUrl: string; + allowedIps: string; + privateKey: string; +}; + +type ApplicationAccess = { + privileges: string[]; + capabilities: string[]; + hooks: string[]; +}; + +type ApplicationDisplay = { + twake: { + "version": 1, + + "files" : { + "preview": { + "url": "", //Url to preview file (full screen or inline) + "inline": true, + "main_ext": ["docx", "xlsx"], //Main extensions app can read + "other_ext": ["txt", "html"] //Secondary extensions app can read + }, + "actions": [ //List of action that can apply on a file + { + "name": "string", + "id": "string" + } + ] + }, + + //Chat plugin + "chat": { + "input": { + "icon": "", //If defined replace original icon url of your app + "type": "file" | "call" //To add in existing apps folder / default icon + }, + "commands": [ + { + "command": "mycommand", // my_app mycommand + "description": "fdsqfds" + } + ], + "actions": [ //List of action that can apply on a message + { + "name": "string", + "id": "string" + } + ] + }, + + //Allow app to appear as a bot user in direct chat + "direct": { + "name": "My app Bot", + "icon": "", //If defined replace original icon url of your app + }, + + //Display app as a standalone application in a tab + "tab": { + "url": "" + }, + + //Display app as a standalone application on the left bar + "standalone": { + "url": "" + }, + + //Define where the app can be configured from + "configuration": ["global", "channel"] + }; +}; +``` + + + +**company\_application**\ +****Represent an application in a company + +```javascript +{ + "company_id": uuid; + "application_id": uuid; + "id": uuid; + + "created_at": number; + "created_by": string; //Will be the default delegated user when doing actions on Twake +} +``` diff --git a/Documentation/docs/internal-documentation/backend-services/applications/rest-apis.md b/Documentation/docs/internal-documentation/backend-services/applications/rest-apis.md new file mode 100644 index 00000000..69eda420 --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/applications/rest-apis.md @@ -0,0 +1,6 @@ +--- +description: Rest API for application +--- + +# REST APIs + diff --git a/Documentation/docs/internal-documentation/backend-services/channels/README.md b/Documentation/docs/internal-documentation/backend-services/channels/README.md new file mode 100644 index 00000000..125aa06a --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/channels/README.md @@ -0,0 +1,40 @@ +--- +description: >- + Channels are topics in Twake, users can subscribe to them, can make them + private or can create them. +--- + +# 🎩 Channels and tabs + +### Wording + +**Member:** member in company without the tag "guest" +**Guest:** company member with the tag "guest" +**Channel member:** member in the channel +**Channels types: +β†’ Private:** Relative to a workspace but restricted to a defined group of members +**β†’ Public:** Relative to a workspace anyone can find the channel and join +**β†’ Direct:** Relative to a company, a discussion between a set of members but without defined topic + +**To understand the routing** please read **"**Collections based rest api:" in "Wording and formating" + +TODO [Wording and formatting](https://www.notion.so/Wording-and-formatting-24ef27e094a042aea4899ac6a8039dee) + +### What it does + +Channel component is **not** responsible of the red badge counter \(notification service is\). + +Channel component **is** responsible of keeping track of the message from where the user need to start reading but can be override by notification service if there is a mention to start reading from. + +TODO [Some process details and constant s](https://www.notion.so/Some-process-details-and-constant-s-fb5b2d4974da490aa87bb87082af8454) + +### Models an APIs + +[Database models](database-models.md) + +TODO [REST Api / Websockets Api](https://www.notion.so/REST-Api-Websockets-Api-458b153a6a6e46c2925dfc1db3859d3b) + +TODO [In/Out microservice](https://www.notion.so/In-Out-microservice-e721e72e542244a69ca3a913e0b405ad) + +TODO [Activity models](https://www.notion.so/Activity-models-0fa3acb0a13f41fd98bc98709908eedf) + diff --git a/Documentation/docs/internal-documentation/backend-services/channels/database-models.md b/Documentation/docs/internal-documentation/backend-services/channels/database-models.md new file mode 100644 index 00000000..a295fa5d --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/channels/database-models.md @@ -0,0 +1,152 @@ +--- +description: Database models of channel +--- + +# Database models + +## Channels + +#### **channels** + +The main channel table, this table should only be used when changing things on the channel \(not frequently\) so we don't add counters or last\_activity or anything like that. + +```javascript +{ + //Primary key + "company_id": "uuid-v4", + "workspace_id": "string" // ("uuid-v4" | "direct") + "id": "uuid-v4", + + //Content + "owner": "uuid-v4", //User-id of the channel owner (invisible but used on some access restriction- + "icon": "String", + "name": "String", + "description": "String", + "channel_group": "String", + "visibility": "private" | "public" | "direct" + "default": true | false, //The new members join by default this channel + "archived": false | true, + "archivation_date": 0, //Timestamp +} +``` + +#### **channel\_defaults** + +Contain the default channels + +```javascript +{ + //Primary key + "company_id": "uuid-v4", + "workspace_id": "uuid-v4" + + "id": "uuid-v4" //Channel id +} +``` + +#### **channel\_counters** + +We use a separated table to manage counters for this channel. Currently this is not used to do statistics but can be used to this goal in the future. + +```javascript +{ + //Primary key + "company_id": "uuid-v4", + "workspace_id": "string", // "uuid-v4" | "direct" + "channel_id": "uuid-v4", + "type": "members" | "guests" | "messages", + + "value": 0, +} +``` + +#### **channel\_last\_activity** + +Store last channel activity for bold/not bold management + +```javascript +{ + //Primary key + "company_id": "uuid-v4", + "channel_id": "uuid-v4", + + "last_activity": 0, //Timestamp in seconds +} +``` + +#### **direct\_channel\_identifiers** + +This table is used to find an existing discussion with a group of members. The "identifier" is generated from the group of members. + +```javascript +{ + //Primary key + "company_id": "uuid-v4", + "identifier": "string", // ordered CSV list of user ids + "channel_id": "uuid-v4" //A way to find it in the channel table +} +``` + +## **Channels tabs** + +#### **channel\_tabs** + +Channels can have tabs that are connexion to other apps or different views. + +```javascript +{ + //Primary key + "company_id": "uuid-v4", + "workspace_id": "string", // "uuid-v4" | "direct" + "channel_id": "uuid-v4", + "tab_id": "uuid-v4", + + "name": "String", + "configuration": JSON, + "application_id": "uuid-v4", + "owner": "uuid-v4", + "order": "string" +} +``` + +## **Channels members** + +#### **channel\_members** + +List of channels for an user + +```javascript +{ + //Primary key + "company_id": "uuid-v4", //Partition Key + "workspace_id": "string", // "uuid-v4" | "direct", //Clustering key + "user_id": "uuid-v4", + "channel_id": "uuid-v4", + + "type": "member" | "guest" | "bot", + + "last_access": 0, //Timestamp in seconds + "last_increment": 0, //Number + "favorite": false | true, //Did the user add this channel to its favorites + "notification_level": "all" | "none" | "group_mentions" | "user_mentions", + "expiration": false | Timestamp, //Member expiration in channel (only for guests) +} +``` + +#### **channel\_members\_reversed** + +List of users in channel + +**Not implemented:** We need to ensure this replication regularly \(on each user open channel\) ? + +```javascript +{ + //Primary key + "company_id": "uuid-v4", + "workspace_id": "string", // "uuid-v4" | "direct", + "channel_id": "uuid-v4", + "type": "guest" | "bot" | "member", + "user_id": "uuid-v4", +} +``` + diff --git a/Documentation/docs/internal-documentation/backend-services/documents/README.md b/Documentation/docs/internal-documentation/backend-services/documents/README.md new file mode 100644 index 00000000..26a1db00 --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/documents/README.md @@ -0,0 +1,26 @@ +--- +description: Drive on Twake +--- + +# πŸ“ Drive + +## description + +**Drive** or **Documents** is the Nodejs drive implementation for twake, it contains drive items. + +A **Drive item** can be: + +- a file +- a directory +- the root folder +- the trash + +## wording + +**version** each file in the drive has a version associated to each update. + +## Models and APIs + +[database-models](database-models.md) + +[rest-api](rest-apis.md) diff --git a/Documentation/docs/internal-documentation/backend-services/documents/database-models.md b/Documentation/docs/internal-documentation/backend-services/documents/database-models.md new file mode 100644 index 00000000..23537040 --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/documents/database-models.md @@ -0,0 +1,86 @@ +--- +description: Documents database models +--- + +# Database models + +**DriveFile** + +```javascript +{ + // Primary Key + "company_id": uuid; + "id": uuid; + + "parent_id": string; + "is_in_trash": boolean; + "is_directory": boolean; + "name": string; + "extension": string; + "description": string; + "tags": string[]; + "added": string; + "last_modified": string; + "access_info": AccessInformation; + "content_keywords": string; + "hidden_data": unknown; + "last_version_cache": Partial; +} + +type AccessInformation = { + public: { + token: string; + level: publicAccessLevel; + }; + entities: AuthEntity[]; +}; + +type AuthEntity = { + type: "user" | "channel" | "company" | "folder"; + id: string | "parent"; + level: publicAccessLevel | DriveFileAccessLevel; +}; +``` + +**FileVersion** + +```javascript +{ + "id": string; + "provider": "internal" | "drive" | string; + "file_id": string; + "file_metadata": DriveFileMetadata; + "date_added": number; + "creator_id": string; + "application_id": string; + "realname": string; + "key": string; + "mode": string | "OpenSSL-2"; + "file_size": number; + "filename": string; + "data": unknown; +} + +type DriveFileMetadata = { + source: "internal" | "drive" | string; + external_id: string; + + name?: string; + mime?: string; + size?: number; + thumbnails?: DriveFileThumbnail; +}; + +type DriveFileThumbnail = { + index: number; + id: string; + + type: string; + size: number; + width: number; + height: number; + + url: string; + full_url?: string; +}; +``` diff --git a/Documentation/docs/internal-documentation/backend-services/documents/rest-apis.md b/Documentation/docs/internal-documentation/backend-services/documents/rest-apis.md new file mode 100644 index 00000000..975ab485 --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/documents/rest-apis.md @@ -0,0 +1,360 @@ +--- +description: Documents API +--- + +# Authentication + +All the following routes require the usual authentication header. But you can also use other ways of authentication: + +- For the download routes, you can use a token generated by the `/internal/services/documents/v1/companies/:company_id/download/token` route (see bellow). +- All the routes can use a query string `?public_token=token` to authenticate the user. +- All the routes can use a query string `?twake_tab_token=token` to authenticate the user in the context of a channel tab for instance. + +# Navigation and drive capabilities + +## Fetch a drive item + +Used to fetch a drive item + +**URL** : `/internal/services/documents/v1/companies/:company_id/item/:id` + +**Method** : `GET` + +**Auth required** : Yes + +### Success Response + +**Code** : `200 OK` + +**Content example** + +```javascript +{ + item: { + id: string; + company_id: string; + + parent_id: string; + in_trash: boolean; + is_directory: string; + name: string; + extension: string; + description: string; + tags: []; + + added: string; + last_modified: string; + last_version_cache: DriveItemVersion; + + access_info: DriveItemAccessInfo; + } + versions: { + id: string; + + provider: string | "drive" | "internal"; + file_id: string; + file_metadata: FileMetadata; + + date_added: number; + creator_id: string; + application_id: string; + } + []; + children: { + id: string; + company_id: string; + + parent_id: string; + in_trash: boolean; + is_directory: string; + name: string; + extension: string; + description: string; + tags: []; + + added: string; + last_modified: string; + last_version_cache: DriveItemVersion; + + access_info: DriveItemAccessInfo; + } + []; +} +``` + +### Error Responses + +If the item cannot be fetched the server will return an error with one of the following status codes: + +- 401 Unauthorized - The user is not authorized. +- 500 Internal Server Error - An error occurred while performing the operation. + +## Create a drive item + +Used to create a drive item + +**URL** : `/internal/services/documents/v1/companies/:company_id/item` + +**Method** : `POST` + +**Headers**: `Content-Type: application/json` OR `Content-Type: multipart/form-data` + +**Auth required** : Yes + +**Data constraints** + +```javascript +{ + item: { + id: string; + company_id: string; + + parent_id: string; + in_trash: boolean; + is_directory: string; + name: string; + extension: string; + description: string; + tags: []; + + added: string; + last_modified: string; + last_version_cache: DriveItemVersion; + + access_info: DriveItemAccessInfo; + }, + version: { + id: string; + + provider: string | 'drive' | 'internal'; + file_id: string; + file_metadata: FileMetadata; + + date_added: number; + creator_id: string; + application_id: string; + }, + file?: File // The multipart/form-data file to be uploaded ( optional ) +} +``` + +### Success Response + +**Code** : `200 OK` + +### Error Responses + +If the request is missing required fields or the item cannot be created, the server will return an error with one of the following status codes: + +- 400 Bad Request - The request is missing required fields. +- 401 Unauthorized - The user is not authorized. +- 500 Internal Server Error - An error occurred while performing the operation. + +## Update a drive item + +Used to update a drive item + +**URL** : `/internal/services/documents/v1/companies/:company_id/item/:id` + +**Method** : `POST` + +**Auth required** : Yes + +**Data constraints** + +```javascript +{ + id: string; + company_id: string; + + parent_id: string; + in_trash: boolean; + is_directory: string; + name: string; + extension: string; + description: string; + tags: []; + + added: string; + last_modified: string; + last_version_cache: DriveItemVersion; + + access_info: DriveItemAccessInfo; +} +``` + +### Success Response + +**Code** : `200 OK` + +### Error Responses + +If the request is missing required fields or the item cannot be updated, the server will return an error with one of the following status codes: + +- 400 Bad Request - The request is missing required fields. +- 401 Unauthorized - The user is not authorized. +- 500 Internal Server Error - An error occurred while performing the operation. + +## Delete a drive item + +Used to delete a drive item + +**URL** : `/internal/services/documents/v1/companies/:company_id/item/:id` + +**Method** : `DELETE` + +**Auth required** : Yes + +### Success Response + +**Code** : `200 OK` + +## Create a drive item version + +Used to create a drive item version + +**URL** : `/internal/services/documents/v1/companies/:company_id/item/:id/version` + +**Method** : `POST` + +**Auth required** : Yes + +**Data constraints** + +```javascript +{ + id: string; + + provider: string | 'drive' | 'internal'; + file_id: string; + file_metadata: { + source: 'internal' | 'drive' | string; + external_id: string | any; + + name?: string; + mime?: string; + size?: number; + thumbnails?: { + index: number; + id: string; + + type: string; + size: number; + width: number; + height: number; + + url: string; + full_url?: string; + }[]; + }; + + date_added: number; + creator_id: string; + application_id: string; +} +``` + +### Success Response + +**Code** : `200 OK` + +# Download + +## Get a download token + +Before to download, if you can't pass an authorisation token (for example in the browser context) you can generate a token that you will pass in the query string to download the file using the next routes. + +**URL** : `/internal/services/documents/v1/companies/:company_id/item/download/token?items=id1,id2,id3&version_id:optional_id` + +**Method** : `GET` + +**Auth required** : Yes + +### Success Response + +``` +{ + "token": string +} +``` + +## Download + +Shortcut to download a file (you can also use the file-service directly). +If the item is a folder, a zip will be automatically generated. + +**URL** : `/internal/services/documents/v1/companies/:company_id/item/:id/download?version_id=:optional_id` + +**Method** : `GET` + +**Auth required** : Yes + +## Zip download + +Used to create a zip archive containing the requested drive items ( files and folders ). + +**URL** : `/internal/services/documents/v1/companies/:company_id/item/download/zip?items=id1,id2,id3` + +**Method** : `GET` + +**Auth required** : Yes + +# Tabs (for Twake) + +If you want to use the Twake tabs, you must store the configuration of the tabs in the database. + +## Get tab configuration + +Get a tab configuration to get the attached folder/document id. + +**URL** : `/internal/services/documents/v1/companies/:company_id/tabs/:id` + +**Method** : `GET` + +**Auth required** : Yes + +### Success Response + +``` +{ + "company_id": string; + "tab_id": string; + "channel_id": string; + "item_id": string; + "level": "read" | "write"; +} +``` + +## Set tab configuration + +Get a tab configuration to get the attached folder/document id. + +**URL** : `/internal/services/documents/v1/companies/:company_id/tabs/:id` + +**Method** : `POST` + +**Auth required** : Yes + +**Data constraints** : + +``` +{ + "company_id": string; + "tab_id": string; + "channel_id": string; + "item_id": string; + "level": "read" | "write"; +} +``` + +### Success Response + +``` +{ + "company_id": string; + "tab_id": string; + "channel_id": string; + "item_id": string; + "level": "read" | "write"; +} +``` diff --git a/Documentation/docs/internal-documentation/backend-services/files/README.md b/Documentation/docs/internal-documentation/backend-services/files/README.md new file mode 100644 index 00000000..d358b5c7 --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/files/README.md @@ -0,0 +1,34 @@ +--- +description: File on Twake +--- + +# πŸ“„ Files + +## description + +**Files** is everything related to file upload in Twake after the migration to Node.js. Note that the Twake Drive isn't part of this migration because it will be replaced by Linshare. + +Twake Files upload support chunk upload and file encryption. + +## Wording + +**File:** document to upload, no constraint on the type of document \(image, text, pdf ..\) + +**Chunk:** Large file are split in multiple chunk for the upload process + +## Encryption + +Files and Storage services in Twake feature encryption at rest in **aes-256-cbc**. + +Each file is encrypted with two layers: + +- A file encryption key and iv stored in database and different for each file. +- A global encryption key and iv used in addition to the previous one and equal for each file. + +## Models and APIs + +[database-models](database-models.md) + +## Miscellaneous + +[resumablejs](resumablejs.md) diff --git a/Documentation/docs/internal-documentation/backend-services/files/database-models.md b/Documentation/docs/internal-documentation/backend-services/files/database-models.md new file mode 100644 index 00000000..e6c98c5d --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/files/database-models.md @@ -0,0 +1,40 @@ +--- +description: File database models +--- + +# Database models + +* **files** The main file object in database + + ```javascript + + javascript + { + + //Primary key: [["company_id"], "id"] + "company_id": "uuid-v4", + "id": "uuid-v4", + "user_id": "string", + "application_id": "string", + "updated_at": "number", + "created_at":"number + + "upload_data": (json){ + "size": number, //Total file size + "chunks": number, //Number of chunks + } + "metadata": (json){ + "name": "string", //File name + "mime": "type/subtype", + } + "thumbnails": (json) { //Url to thumbnail (or set it to undefined if no relevant) + "index": "string", + "id": "uuid-v4", + "type": "string", + "size": "number, + "width": number, //Thumbnail width (for images only) + "height": number, //Thumbnail height (for images only) + } + } + + ``` diff --git a/Documentation/docs/internal-documentation/backend-services/files/resumablejs.md b/Documentation/docs/internal-documentation/backend-services/files/resumablejs.md new file mode 100644 index 00000000..9b48c57b --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/files/resumablejs.md @@ -0,0 +1,25 @@ +--- +description: How we use resumable on Twake +--- + +# Resumable.js + +**Link to the official documentation:** [http://resumablejs.com](http://resumablejs.com/) + +## What is Resumable.js + +::: info +Using Resumable is not mandatory to upload a file to Twake. You can do it manually, see REST APIs page. +::: + +It’s a JavaScript library providing multiple simultaneous, stable and resumable uploads via the HTML5 File API. + +The library is designed to introduce fault-tolerance into the upload of large files through HTTP. This is done by splitting each files into small chunks; whenever the upload of a chunk fails, uploading is retried until the procedure completes. This allows uploads to automatically resume uploading after a network connection is lost either locally or to the server. Additionally, it allows for users to pause, resume and even recover uploads without losing state. + +Resumable.js does not have any external dependencies other the `HTML5 File API`. This is relied on for the ability to chunk files into smaller pieces. Currently, this means that support is limited to Firefox 4+ and Chrome 11+. + +## What Resumable.js does + +In Frontend side resumable split the file in multiple small chunks. For the upload process resumable ask the server with an HTTP GET request to know if the chunk requested is saved on the server side. If yes, resumable ask for the next chunk. If not, resumable send an HTTP POST request with the chunk to the server. + +With POST request from resumable, there is multiple information fields contains for exemple the number of chunk, the chunk size, the total size of the file, an unique identifier for the file, and the name of the file. diff --git a/Documentation/docs/internal-documentation/backend-services/intro/README.md b/Documentation/docs/internal-documentation/backend-services/intro/README.md new file mode 100644 index 00000000..1cc074cc --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/intro/README.md @@ -0,0 +1,11 @@ +--- +description: Get started with Twake service development +--- + +# πŸ›  Twake service development + +[start-working-into-a-service](start-working-into-a-service.md) + +[create-a-new-twake-service](create-a-new-twake-service.md) + +[platform/](platform/README.md)) diff --git a/Documentation/docs/internal-documentation/backend-services/intro/create-a-new-twake-service.md b/Documentation/docs/internal-documentation/backend-services/intro/create-a-new-twake-service.md new file mode 100644 index 00000000..e2480c07 --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/intro/create-a-new-twake-service.md @@ -0,0 +1,173 @@ +--- +description: >- + If you are here, you probably have a very great idea for Twake, like adding a + brand new feature into Twake, maybe a coffee maker service ? β˜•οΈ +--- + +# Create a new service + +::: info +Please ensure you read the [Start working into a service](start-working-into-a-service.md) before +::: + +To create a new component, a new folder must be created under the `src/services` one and an `index.ts` file must export the a class. This class will be instantiated by the platform and will be linked to the required services automatically. + +In order to illustrate how to create a component, let's create a fake Notification service. + +1. Create the folder `src/services/notification` +2. Create an `index.ts` file which exports a `NotificationService` class + +```javascript +// File src/services/notification/index.ts +import { TwakeService } from "../../core/platform/framework"; +import NotificationServiceAPI from "./api.ts"; + +export default class NotificationService extends TwakeService { + version = "1"; + name = "notification"; + service: NotificationServiceAPI; + + api(): NotificationServiceAPI { + return this.service; + } +} +``` + +1. Our `NotificationService` class extends the generic `TwakeService` class and we defined the `NotificationServiceAPI` as its generic type parameter. It means that in the platform, the other components will be able to retrieve the component from its name and then consume the API defined in the `NotificationServiceAPI` interface and exposed by the `api` method. + + We need to create this `NotificationServiceAPI` interface which must extend the `TwakeServiceProvider` from the platform like: + +```javascript +// File src/services/notification/api.ts +import { TwakeServiceProvider } from "../../core/platform/framework/api"; + +export default interface NotificationServiceAPI extends TwakeServiceProvider { + + /** + * Send a message to a list of recipients + */ + send(message: string, recipients: string[]): Promise; +} +``` + +1. Now that the interfaces are defined, we need to create the `NotificationServiceAPI` implementation \(this is a dummy implementation which does nothing but illustrates the process\): + +```javascript +// File src/services/notification/services/api.ts +import NotificationServiceAPI from "../api"; + +export class NotificationServiceImpl implements NotificationServiceAPI { + version = "1"; + + async send(message: string, recipients: string[]): Promise { + return Promise.resolve(`${message} sent`); + } +} +``` + +1. `NotificationServiceImpl` now needs to be instanciated from the `NotificationService` class since this is where we choose to keep its reference and expose it. There are several places which can be used to instanciate it, in the constructor itself, or in one of the `TwakeService` lifecycle hooks. The `TwakeService` abstract class has several lifecycle hooks which can be extended by the service implementation for customization pusposes: +2. `public async doInit(): Promise;` Customize the `init` step of the component. This is generally the place where services are instanciated. From this step, you can retrieve services consumed by the current component which have been already initialized by the platform. +3. `public async doStart(): Promise;` Customize the `start` step of the component. You have access to all other services which are already started. + +```javascript +// File src/services/notification/index.ts +import { TwakeService } from "../../core/platform/framework"; +import NotificationServiceAPI from "./api.ts"; +import NotificationServiceImpl from "./services/api.ts"; + +export default class NotificationService extends TwakeService { + version = "1"; + name = "notification"; + service: NotificationServiceAPI; + + api(): NotificationServiceAPI { + return this.service; + } + + public async doInit(): Promise { + this.service = new NotificationServiceImpl(); + + return this; + } +} +``` + +1. Now that the service is fully created, we can consume it from any other service in the platform. To do this, we rely on Typescript decorators to define the links between components. For example, let's say that the a `MessageService` needs to call the `NotificationServiceAPI`, we can create the link with the help of the `@Consumes` decorator and get a reference to the `NotificationServiceAPI` by calling the `getProvider` on the component context like: + +```javascript +import { TwakeService, Consumes } from "../../core/platform/framework"; +import MessageServiceAPI from "./providapier"; +import NotificationServiceAPI from "../notification/api"; + +@Consumes(["notification"]) +export default class MessageService extends TwakeService { + + public async doInit(): Promise { + const notificationService = this.context.getProvider("notification"); + + // You can not call anything defined in the NotificationServiceAPI interface from here or from inner services by passing down the reference to notificationService. + } +} +``` + +**Configuration** + +The platform and services configuration is defined in the `config/default.json` file. It uses [node-config](https://github.com/lorenwest/node-config) under the hood and to configuration file inheritence is supported in the platform. + +The list of services to start is defined in the `services` array like: + +```javascript +{ + "services": ["auth", "user", "channels", "webserver", "websocket", "database", "realtime"] +} +``` + +Then each service can have its own configuration block which is accessible from its service name i.e. `websocket` service configuration is defined in the `websocket` element like: + +```javascript +{ + "services": ["auth", "user", "channels", "webserver", "websocket", "orm"], + "websocket": { + "path": "/socket", + "adapters": { + "types": [], + "redis": { + "host": "redis", + "port": 6379 + } + } + } +} +``` + +On the component class side, the configuration object is directly accessible from the `configuration` property like: + +```javascript +export default class WebSocket extends TwakeService { + async doInit(): Promise { + // get the "path" value, defaults to "/socket" if not defined + const path = this.configuration.get < string > ("path", "/socket"); + + // The "get" method is generic and can accept custom types like + const adapters = + this.configuration.get < AdaptersConfiguration > "adapters"; + } +} + +interface AdaptersConfiguration { + types: Array; + redis: SocketIORedis.SocketIORedisOptions; +} +``` + +::: info +After creating a new service, you can add controllers, business services and entities, go back to the [What is a service section](start-working-into-a-service.md) +::: + +## Create a new technical service + +Now you are bringing things a step further, you are going to add new core services in Twake, like for instance a new database connector or encryption system. + +Creating a new core service is as easy as creating a functional service. But it must be in `src/core/platform/services` . + +You can read the [complete list of existing technical services here](platform/README.md)) . diff --git a/Documentation/docs/internal-documentation/backend-services/intro/platform.md b/Documentation/docs/internal-documentation/backend-services/intro/platform.md new file mode 100644 index 00000000..e526ae55 --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/intro/platform.md @@ -0,0 +1,247 @@ +--- +description: >- + List of core shared components in Twake backend, available in + src/core/platform/services +--- + +# Platform/Technical services + +## **Database Technical Service** + +Twake uses a custom ORM to work with both MongoDB and CassandraDB/ScyllaDB. + +::: info +This paragraph is not ready yet, you can contribute to this documentation on our Github! +::: + +## **Realtime Technical Service** + +The framework provides simple way to create CRUD Services which will notify clients using Websockets by following some conventions: + +1. The service must implement the `CRUDService` generic interface +2. In order to push notification to clients, Typescript decorators must be added on methods \(Create, Update, Delete methods\) + +For example, let's say that we want to implement a CRUD Service for `messages`: + +```javascript +import { + CRUDService, + CreateResult, + DeleteResult, + UpdateResult, + EntityId, +} from "@/core/platform/framework/api/crud-service"; + +class Message { + text: string; + createdAt: Date; + author: string; +} + +class MessageService implements CRUDService { + async create(item: Message): Promise> { + // save the message then return a CreateResult instance + } + + async get(id: EntityId): Promise { + // get the message from its ID and return it + } + + async update(id: EntityId, item: Message): Promise> { + // update the message with the given id, patch it with `item` values + // then return an instance of UpdateResult + } + + async delete(id: EntityId): Promise> { + // delete the message from its id then return a DeleteResult instance + } + + async list(): Promise { + // get a list of messages + } +} +``` + +By implementing the CRUD service following the API, we can now add realtime message to clients connected to Websocket on a selected collection of CRUD operations. For example, if we want to just notify when a `message` is created, we just have to add the right decorator on the `create` method like: + +```javascript +import { RealtimeCreated } from "@/core/platform/framework/decorators"; + +// top and bottom code removed for clarity +class MessageService implements CRUDService { + + @RealtimeCreated({ + room: "/messages", + path: message => `/messages/${message.id}` + }) + async create(item: Message): Promise> { + // save the message then return a CreateResult instance + const created: Message = new Message(/* */); + + return new CreateResult("message", created) + } + // ... +} +``` + +The `RealtimeCreated` decorator will intercept the `create` call and will publish an event in an internal event bus with the creation result, the input data and the `"/messages"` path. On the other side of the event bus, an event listener will be in charge of delivering the event to the right Websocket clients as described next. + +The Realtime\* decorators to add on methods to intercept calls and publish data are all following the same API. A decorator takes two parameters as input: + +- First one is the room name to publish the notification to \(`/messages` in the example above\) +- Second one is the full path of the resource linked to the action \(`message => /messages/${message.id}` in the example above\) + +Both parameters can take a string or an arrow function as parameter. If arrow function is used, the input parameter will be the result element. By doing this, the paths can be generated dynamically at runtime. + +## **Websocket Technical Service** + +Services annotated as described above automatically publish events to WebSockets. Under the hood, it uses Socket.IO rooms to send events to the right clients. + +**Authentication** + +- Client have to provide a valid JWT token to be able to connect and be authenticated by providing it as string in the `authenticate` event like `{ token: "the jwt token value" }` +- If the JWT token is valid, the client will receive a `authenticated` event +- If the JWT token is not valid or empty, the client will receive a `unauthorized` event + +**Example** + +```javascript +const io = require("socket.io-client"); + +// Get a JWT token from the Twake API first +const token = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOjEsImlhdCI6MTYwMzE5ODkzMn0.NvQoV9KeWuTNzRvzqbJ5uZCQ8Nmi2rCYQzcKk-WsJJ8"; +const socket = io.connect("http://localhost:3000", { path: "/socket" }); + +socket.on("connect", () => { + socket + .emit("authenticate", { token }) + .on("authenticated", () => { + console.log("User Authenticated"); + }) + .on("unauthorized", (err) => { + console.log("User is not authorized", err); + }); +}); + +socket.on("disconnected", () => console.log("Disconnected")); +``` + +**Joining rooms** + +CRUD operations on resources are pushing events in Socket.io rooms. In order to receive events, clients must subscribe to rooms by sending an `realtime:join` on an authenticated socket with the name of the room to join and with a valid JWT token like `{ name: "room name", token: "the jwt token for this room" }`: Users can not subscribe to arbitratry rooms, they have to be authorized to. + +As a result, the client will receive events: + +- `realtime:join:success` when join is succesful with data containing the name of the linked room like `{ name: "room" }`. +- `realtime:join:error` when join failed with data containing the name of the linked room and the error details like `{ name: "room", error: "some error message" }`. + +**Example** + +```javascript +const io = require("socket.io-client"); + +const token = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOjEsImlhdCI6MTYwMzE5ODkzMn0.NvQoV9KeWuTNzRvzqbJ5uZCQ8Nmi2rCYQzcKk-WsJJ8"; +const socket = io.connect("http://localhost:3000", { path: "/socket" }); + +socket.on("connect", () => { + socket + .emit("authenticate", { token }) + .on("authenticated", () => { + // join the /channels room + socket.emit("realtime:join", { name: "/channels", token: "twake" }); + socket.on("realtime:join:error", (message) => { + // will fire when join does not provide a valid token + console.log("Error on join", message); + }); + + // will be fired on each successful join. + // As event based, this event is not linked only to the join above + // but to all joins. So you have to dig into the message to know which one + // is successful. + socket.on("realtime:join:success", (message) => { + console.log("Successfully joined room", message.name); + }); + }) + .on("unauthorized", (err) => { + console.log("Unauthorized", err); + }); +}); + +socket.on("disconnected", () => console.log("Disconnected")); +``` + +**Leaving rooms** + +The client can leave the room by emitting a `realtime:leave` event with the name of the room given as `{ name: "the room to leave" }`. + +As a result, the client will receive events: + +- `realtime:leave:success` when leave is succesful with data containing the name of the linked room like `{ name: "room" }`. +- `realtime:leave:error` when leave failed with data containing the name of the linked room and the error details like `{ name: "room", error: "some error message" }`. + +Note: Asking to leave a room which has not been joined will not fire any error. + +**Example** + +```javascript +socket.on("connect", () => { + socket.emit("authenticate", { token }).on("authenticated", () => { + // leave the "/channels" room + socket.emit("realtime:leave", { name: "/channels" }); + + socket.on("realtime:leave:error", (message) => { + // will fire when join does not provide a valid token + console.log("Error on leave", message); + }); + + // will be fired on each successful leave. + // As event based, this event is not linked only to the leave above + // but to all leaves. So you have to dig into the message to know which one + // is successful. + socket.on("realtime:leave:success", (message) => { + console.log("Successfully left room", message.name); + }); + }); +}); +``` + +**Subscribe to resource events** + +Once the given room has been joined, the client will receive `realtime:resource` events with the resource linked to the event as data: + +```javascript +{ + "action": "created", + "room": "/channels", + "type": "channel", + "path": "/channels/5f905327e3e1626399aaad79", + "resource": { + "name": "My channel", + "id": "5f905327e3e1626399aaad79" + } +``` + +**Example:** + +```javascript +socket.on("connect", () => { + socket + .emit("authenticate", { token }) + .on("authenticated", () => { + // join the "/channels" room + socket.emit("realtime:join", { name: "/channels", token: "twake" }); + + // will only occur when an action occured on a resource + // and if and only if the client joined the room + // in which the resource is linked + socket.on("realtime:resource", (event) => { + console.log("Resource has been ${event.action}", event.resource); + }); + }) + .on("unauthorized", (err) => { + console.log("Unauthorized", err); + }); +}); +``` diff --git a/Documentation/docs/internal-documentation/backend-services/intro/platform/README.md b/Documentation/docs/internal-documentation/backend-services/intro/platform/README.md new file mode 100644 index 00000000..603be721 --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/intro/platform/README.md @@ -0,0 +1,245 @@ +--- +description: >- + List of core shared components in Twake backend, available in + src/core/platform/services +--- + +# Platform/Technical services + +## **Database Technical Service** + +Twake uses a custom ORM to work with both MongoDB and CassandraDB/ScyllaDB. + +[database-orm-platform-service](database-orm-platform-service.md) + +## **Realtime Technical Service** + +The framework provides simple way to create CRUD Services which will notify clients using Websockets by following some conventions: + +1. The service must implement the `CRUDService` generic interface +2. In order to push notification to clients, Typescript decorators must be added on methods \(Create, Update, Delete methods\) + +For example, let's say that we want to implement a CRUD Service for `messages`: + +```javascript +import { + CRUDService, + CreateResult, + DeleteResult, + UpdateResult, + EntityId, +} from "@/core/platform/framework/api/crud-service"; + +class Message { + text: string; + createdAt: Date; + author: string; +} + +class MessageService implements CRUDService { + async create(item: Message): Promise> { + // save the message then return a CreateResult instance + } + + async get(id: EntityId): Promise { + // get the message from its ID and return it + } + + async update(id: EntityId, item: Message): Promise> { + // update the message with the given id, patch it with `item` values + // then return an instance of UpdateResult + } + + async delete(id: EntityId): Promise> { + // delete the message from its id then return a DeleteResult instance + } + + async list(): Promise { + // get a list of messages + } +} +``` + +By implementing the CRUD service following the API, we can now add realtime message to clients connected to Websocket on a selected collection of CRUD operations. For example, if we want to just notify when a `message` is created, we just have to add the right decorator on the `create` method like: + +```javascript +import { RealtimeCreated } from "@/core/platform/framework/decorators"; + +// top and bottom code removed for clarity +class MessageService implements CRUDService { + + @RealtimeCreated({ + room: "/messages", + path: message => `/messages/${message.id}` + }) + async create(item: Message): Promise> { + // save the message then return a CreateResult instance + const created: Message = new Message(/* */); + + return new CreateResult("message", created) + } + // ... +} +``` + +The `RealtimeCreated` decorator will intercept the `create` call and will publish an event in an internal event bus with the creation result, the input data and the `"/messages"` path. On the other side of the event bus, an event listener will be in charge of delivering the event to the right Websocket clients as described next. + +The Realtime\* decorators to add on methods to intercept calls and publish data are all following the same API. A decorator takes two parameters as input: + +- First one is the room name to publish the notification to \(`/messages` in the example above\) +- Second one is the full path of the resource linked to the action \(`message => /messages/${message.id}` in the example above\) + +Both parameters can take a string or an arrow function as parameter. If arrow function is used, the input parameter will be the result element. By doing this, the paths can be generated dynamically at runtime. + +## **Websocket Technical Service** + +Services annotated as described above automatically publish events to WebSockets. Under the hood, it uses Socket.IO rooms to send events to the right clients. + +**Authentication** + +- Client have to provide a valid JWT token to be able to connect and be authenticated by providing it as string in the `authenticate` event like `{ token: "the jwt token value" }` +- If the JWT token is valid, the client will receive a `authenticated` event +- If the JWT token is not valid or empty, the client will receive a `unauthorized` event + +**Example** + +```javascript +const io = require("socket.io-client"); + +// Get a JWT token from the Twake API first +const token = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOjEsImlhdCI6MTYwMzE5ODkzMn0.NvQoV9KeWuTNzRvzqbJ5uZCQ8Nmi2rCYQzcKk-WsJJ8"; +const socket = io.connect("http://localhost:3000", { path: "/socket" }); + +socket.on("connect", () => { + socket + .emit("authenticate", { token }) + .on("authenticated", () => { + console.log("User Authenticated"); + }) + .on("unauthorized", (err) => { + console.log("User is not authorized", err); + }); +}); + +socket.on("disconnected", () => console.log("Disconnected")); +``` + +**Joining rooms** + +CRUD operations on resources are pushing events in Socket.io rooms. In order to receive events, clients must subscribe to rooms by sending an `realtime:join` on an authenticated socket with the name of the room to join and with a valid JWT token like `{ name: "room name", token: "the jwt token for this room" }`: Users can not subscribe to arbitratry rooms, they have to be authorized to. + +As a result, the client will receive events: + +- `realtime:join:success` when join is succesful with data containing the name of the linked room like `{ name: "room" }`. +- `realtime:join:error` when join failed with data containing the name of the linked room and the error details like `{ name: "room", error: "some error message" }`. + +**Example** + +```javascript +const io = require("socket.io-client"); + +const token = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOjEsImlhdCI6MTYwMzE5ODkzMn0.NvQoV9KeWuTNzRvzqbJ5uZCQ8Nmi2rCYQzcKk-WsJJ8"; +const socket = io.connect("http://localhost:3000", { path: "/socket" }); + +socket.on("connect", () => { + socket + .emit("authenticate", { token }) + .on("authenticated", () => { + // join the /channels room + socket.emit("realtime:join", { name: "/channels", token: "twake" }); + socket.on("realtime:join:error", (message) => { + // will fire when join does not provide a valid token + console.log("Error on join", message); + }); + + // will be fired on each successful join. + // As event based, this event is not linked only to the join above + // but to all joins. So you have to dig into the message to know which one + // is successful. + socket.on("realtime:join:success", (message) => { + console.log("Successfully joined room", message.name); + }); + }) + .on("unauthorized", (err) => { + console.log("Unauthorized", err); + }); +}); + +socket.on("disconnected", () => console.log("Disconnected")); +``` + +**Leaving rooms** + +The client can leave the room by emitting a `realtime:leave` event with the name of the room given as `{ name: "the room to leave" }`. + +As a result, the client will receive events: + +- `realtime:leave:success` when leave is succesful with data containing the name of the linked room like `{ name: "room" }`. +- `realtime:leave:error` when leave failed with data containing the name of the linked room and the error details like `{ name: "room", error: "some error message" }`. + +Note: Asking to leave a room which has not been joined will not fire any error. + +**Example** + +```javascript +socket.on("connect", () => { + socket.emit("authenticate", { token }).on("authenticated", () => { + // leave the "/channels" room + socket.emit("realtime:leave", { name: "/channels" }); + + socket.on("realtime:leave:error", (message) => { + // will fire when join does not provide a valid token + console.log("Error on leave", message); + }); + + // will be fired on each successful leave. + // As event based, this event is not linked only to the leave above + // but to all leaves. So you have to dig into the message to know which one + // is successful. + socket.on("realtime:leave:success", (message) => { + console.log("Successfully left room", message.name); + }); + }); +}); +``` + +**Subscribe to resource events** + +Once the given room has been joined, the client will receive `realtime:resource` events with the resource linked to the event as data: + +```javascript +{ + "action": "created", + "room": "/channels", + "type": "channel", + "path": "/channels/5f905327e3e1626399aaad79", + "resource": { + "name": "My channel", + "id": "5f905327e3e1626399aaad79" + } +``` + +**Example:** + +```javascript +socket.on("connect", () => { + socket + .emit("authenticate", { token }) + .on("authenticated", () => { + // join the "/channels" room + socket.emit("realtime:join", { name: "/channels", token: "twake" }); + + // will only occur when an action occured on a resource + // and if and only if the client joined the room + // in which the resource is linked + socket.on("realtime:resource", (event) => { + console.log("Resource has been ${event.action}", event.resource); + }); + }) + .on("unauthorized", (err) => { + console.log("Unauthorized", err); + }); +}); +``` diff --git a/Documentation/docs/internal-documentation/backend-services/intro/platform/database-orm-platform-service.md b/Documentation/docs/internal-documentation/backend-services/intro/platform/database-orm-platform-service.md new file mode 100644 index 00000000..dd264b31 --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/intro/platform/database-orm-platform-service.md @@ -0,0 +1,69 @@ +# Database ORM platform service + +## How to use it ? + +A. Create an entity and put it anywhere in the code + +```typescript +import { Entity, Column } from "../../../core/platform/services/database/services/orm/decorators"; + +@Entity("my_entity", { + primaryKey: [["company_id"], "id"], //Primary key, see Cassandra documentation for more details + type: "my_entity", +}) +export class MyEntity { + @Type(() => String) + @Column("company_id", "uuid", { generator: "uuid" }) + company_id: string; + + @Column("workspace_id", { generator: "uuid" }) + id: string; + + @Column("text", "encoded") + text: string; +} +``` + +B. Create a repository to manage entities + +```typescript +const database: DatabaseServiceAPI = ...; +const repository = await database.getRepository("my_entity", MyEntity); + +const newEntity = new MyEntity(); +newEntity.company_id = ""; +newEntity.text = ""; +await repository.save(newEntity); + +const entities = await repository.find({company_id: "", id: ""}); +const entity = await repository.findOne({company_id: "", id: ""}); + +await repository.remove({company_id: "", id: ""}); +``` + +## FAQ + +#### I set a column to a type but I get an other type on code. Why for two identical definitions it created fields of different types? + +It depends on what database you use \(mongo or scylladb\) for development. Here is the process for each: + +Scylla: + +* on startup it creates the tables with the requested types, in this case twake\_boolean => tinyint on scylla side +* on save entity it will convert the node type \(boolean\) to the good cql request: "{bool: false}" => "SET bool = 0", it happens in the transformValueToDbString method +* on find entity it will convert the database raw value \(a tinyint\) to the nodejs type \(boolean\): 1 => true, 0 => false. + +Mongo: + +* on startup it does nothing \(mongo don't need to initialise columns +* on save entity it will create a document, it means in mongo we just store json for each entity, there is no really a column concept. +* on find entity we just get back the saved json and map it to the entity in node. + + Even if mongo just store json directly from mongo, we sometime do some changes to the data before to save in mongo, it will also be in the typeTransforms.ts file. + +So what could have happened in you case ? + +* \(1\) if you use mongodb and we did not enforce the type before to save to mongo, then maybe you used a string instead of a boolean at some point in time while working and mongo just saved it as it was \(without checking the requested type on entity\) +* \(2\) other possibility is that we incorrectly get the information from the database on the typeTransforms.ts file, from cassandra for instance I think we don't convert tinyint back to clean boolean, so you could get 0 and 1 instead of false and true. And maybe instead of 0 and 1 sometime undefined values can convert to ''. +* To fix all this just enforce the types in typeTransforms.ts for the twake\_boolean type. + diff --git a/Documentation/docs/internal-documentation/backend-services/intro/start-working-into-a-service.md b/Documentation/docs/internal-documentation/backend-services/intro/start-working-into-a-service.md new file mode 100644 index 00000000..b01bfa7f --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/intro/start-working-into-a-service.md @@ -0,0 +1,48 @@ +--- +description: >- + You want to add new routes in an existing service, for instance add a feature + to our channel service ? You are in the right place ! +--- + +# What is a service in Twake ? + +The backend is developed using a **software component approach** in order to compose and adapt the platform based on needs and constraints. The current section describes this approach, and how to extend it by creating new components. + +The platform has the following properties: + +- A platform is composed of multiple components +- A component has an unique name in the platform +- A component can provide a `service` +- A component can consume `services` from other components +- A component has a lifecycle composed of several states: `ready`, `initialized`, `started`, `stopped` +- A component lifecycle changes when a lifecycle event is triggered by the platform: `init`, `start`, `stop` +- By creating links between components \(service producers and consumers\), components lifecycles **are also linked together**: A component going from `ready` to `initialized` will wait for all its dependencies to be in `initialized` state. This is automatically handled by the platform. + +The platform currently have some limitations: + +- Components can not have cyclic dependencies: if `component X` requires a component which requires `component X` directly or in one of its dependencies, the platform will not start +- Components can only have local dependencies. + +## Discover what is in a service + +To unfold the internal ways of services in Twake, we will follow a simple request journey into our framework. + +1. The requests starts from Twake Frontend or Postman for instance, +2. it then goes to a controller which validate the request parameters and extract them for the services, +3. the services uses the given parameters to get/set entities in database and returns a proper reply. + +### /web/controllers : where everything starts + +This is where you declare the routing you want to use. + +### /services : where the magic happen + +This is where you work for real, calling databases, sending websockets events, using tasks pushers etc. + +### /entities : where we keep the data + +If you store data, you must define its data model and how it is stored in our database middleware. + +::: danger +This document is not finished, you can contribute to it on our Github. +::: diff --git a/Documentation/docs/internal-documentation/backend-services/knowledge-graph/README.md b/Documentation/docs/internal-documentation/backend-services/knowledge-graph/README.md new file mode 100644 index 00000000..0134712f --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/knowledge-graph/README.md @@ -0,0 +1,49 @@ +# Knowledge-graph + +## Twake to Knowledge-graph events + +Twake can send events to the knowledge graph following this documentation: + +[Events from Twake](./pushed-from-twake.md) + +## Knowledge-graph to Twake REST + +The knowledge graph can send us event at the following endpoint: +`POST https://api.twake.app/internal/services/knowledge-graph/v1/push` + +Authorized by a Token authorization header: +`Authorization: Token {some token defined together}` + +And with the following data in JSON: + +``` +{ + events: [KnowledgeGraphCallbackEvent, KnowledgeGraphCallbackEvent, KnowledgeGraphCallbackEvent, ...] +} + +type KnowledgeGraphCallbackEvent = { + recipients: { + type: "user"; + id: string; // KG user id which is a md5 of the email + }[]; + event: { + type: "user_tags"; //More events will be added later + data: { + //For user_tags event only + tags?: { + value: string; + weight: number; + }[]; + }; + }; +}; + +``` + +The reply will be if everything was alright: + +``` +{ + "status": "success" +} +``` diff --git a/Documentation/docs/internal-documentation/backend-services/knowledge-graph/pushed-from-twake.md b/Documentation/docs/internal-documentation/backend-services/knowledge-graph/pushed-from-twake.md new file mode 100644 index 00000000..943feaa3 --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/knowledge-graph/pushed-from-twake.md @@ -0,0 +1,172 @@ +# Knowledge-graph + +## Knowledge-graph to Twake events + +[Send events to Twake](./README.md) + +## Events sent by twake to the knowledge graph + +### User created / updated + +```typescript +{ + records: [ + { + key: "null", + value: { + id: "User", + properties: { + _kg_user_id: string; //Console wide user id (based on the console id), prefer to use this one + _kg_email_id: string; //Console wide user id (based on the email md5) + _kg_company_all_id: string[]; //All console wide companies_ids for this user + + user_id: string; //Twake internal user id + company_id: string; //Company internal id + user_created_at: number; + user_last_activity: string; + email: string; + first_name: string; + last_name: string; + }, + }, + }, + ] +} +``` + +### Channel created / updated + +```typescript +{ + records: [ + { + key: "null", + value: { + id: "Channel", + properties: { + _kg_user_id: string; //Console wide user id (based on the console id), prefer to use this one + _kg_email_id: string; //Console wide user id (based on the email md5) + _kg_company_id: string; //Console wide company id + channel_id: string; + channel_name: string; + channel_owner: string; + workspace_id: string; + company_id: string; + }, + }, + }, + ], +} +``` + +### Message created / updated + +```typescript +{ + records: [ + { + key: "null", + value: { + id: "Message", + properties: { + _kg_user_id: string; //Console wide user id (based on the console id), prefer to use this one + _kg_email_id: string; //Console wide user id (based on the email md5) + _kg_company_id: string; //Console wide company id + message_thread_id: message.thread_id, + message_content: string; //Empty if user requested not to share data to KG + message_created_at: number; + message_updated_at: number; + type_message: string; + company_id: string; //Internal to Twake company id + workspace_id: string; + channel_id: string; + user_id: string; //Internal to Twake user id + }, + }, + }, + ], +} +``` + +### Company created / updated + +```typescript +{ + records: [ + { + key: "null", + value: { + id: "Company", + properties: { + _kg_company_id: string; //Console wide company id + company_id: string; //Internal to Twake company id + company_name: string; + }, + }, + }, + ], +} +``` + +### Workspace created / updated + +```typescript +{ + records: [ + { + key: "null", + value: { + id: "Workspace", + properties: { + _kg_company_id: string; //Console wide company id + company_id: string; //Internal to Twake company id + workspace_id: string; //Internal to Twake workspace id + workspace_name: string; + }, + }, + }, + ], +} +``` + +## Sending events to Twake from the KG + +Twake listen at at: +`POST https://domain/internal/services/knowledge-graph/v1/push` + +Authorised by a Token authorization header: +`Authorization: Token {some token defined together}` + +And with the following data in JSON: + +```typescript +{ + events: [KnowledgeGraphCallbackEvent, KnowledgeGraphCallbackEvent, KnowledgeGraphCallbackEvent, ...] +} + +type KnowledgeGraphCallbackEvent = { + recipients: { + type: "user"; + id: string; // KG user id which is a md5 of the email + }[]; + event: { + type: "user_tags"; //More events will be added later + data: { + //For user_tags event only + tags?: { + value: string; + weight: number; + }[]; + }; + }; +}; + +``` + +The reply will be if everything was alright: + +```typescript +{ + "status": "success" +} +``` diff --git a/Documentation/docs/internal-documentation/backend-services/messages/README.md b/Documentation/docs/internal-documentation/backend-services/messages/README.md new file mode 100644 index 00000000..564df982 --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/messages/README.md @@ -0,0 +1,8 @@ +--- +description: Message api +--- + +# πŸ’¬ Messages + +Document still on Notion: [https://www.notion.so/twake/Backend-documentation-e219323593d2401c9887d0e11b2a597b](https://www.notion.so/twake/Backend-documentation-e219323593d2401c9887d0e11b2a597b) + diff --git a/Documentation/docs/internal-documentation/backend-services/messages/database-model.md b/Documentation/docs/internal-documentation/backend-services/messages/database-model.md new file mode 100644 index 00000000..0790d63d --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/messages/database-model.md @@ -0,0 +1,6 @@ +--- +description: Message database models +--- + +# Database models + diff --git a/Documentation/docs/internal-documentation/backend-services/notifications/README.md b/Documentation/docs/internal-documentation/backend-services/notifications/README.md new file mode 100644 index 00000000..0ec60978 --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/notifications/README.md @@ -0,0 +1,6 @@ +--- +description: Notifications on Twake +--- + +# πŸ“² Notifications + diff --git a/Documentation/docs/internal-documentation/backend-services/notifications/database-models.md b/Documentation/docs/internal-documentation/backend-services/notifications/database-models.md new file mode 100644 index 00000000..a3a2880b --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/notifications/database-models.md @@ -0,0 +1,59 @@ +--- +description: Notification database model +--- + +# Database models + +#### **channel\_members\_notification\_preferences** + +```javascript +{ + //Primary key + "company_id": "uuid-v4", + "channel_id": "uuid-v4", + "user_id": "uuid-v4", + + "preferences": "all" | "mentions" | "me" | "none", + "last_read": 16000000, //Timestamp in seconds +} +``` + +#### **channel\_thread\_users** + +```javascript +{ + //Primary key + "company_id": "uuid-v4", + "channel_id": "uuid-v4", + "thread_id": "uuid-v4", + + "user_id": "uuid-v4" +} +``` + +#### **user\_notifications\_badges \(this is not a counter like scylladb counters here, just classic table\)** + +```javascript +{ + //Primary key + "company_id": "uuid-v4", (partition key) + "user_id": "uuid-v4", (clustering key) + "workspace_id": "uuid-v4", (clustering key) + "channel_id": "uuid-v4", (clustering key) + "thread_id": "uuid-v4", (clustering key) +} +``` + +#### **user\_notifications\_general\_preferences** + +```javascript +{ + //Primary key + "company_id": "uuid-v4", + "user_id": "uuid-v4", + "workspace_id": "uuid-v4", + + "preferences": PreferencesObject +} +``` + diff --git a/Documentation/docs/internal-documentation/backend-services/tags/README.md b/Documentation/docs/internal-documentation/backend-services/tags/README.md new file mode 100644 index 00000000..d3f72300 --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/tags/README.md @@ -0,0 +1,14 @@ +--- +description: Tags on Twake +--- + +# πŸ“ Tags + +## description + +**Tags** is everything related to tafs in Twake after the migration to Node.js. + +## Models and APIs + +[database-models](database-models.md) +[rest-api](rest-apis.md) diff --git a/Documentation/docs/internal-documentation/backend-services/tags/database-models.md b/Documentation/docs/internal-documentation/backend-services/tags/database-models.md new file mode 100644 index 00000000..34c67bd5 --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/tags/database-models.md @@ -0,0 +1,18 @@ +--- +description: Documents database models +--- + +# Database models + +**DriveFile** + +```javascript +{ + // Primary Key + "company_id": uuid; + "tag_id": string; + + "name": string; + "colour": string; +} +``` diff --git a/Documentation/docs/internal-documentation/backend-services/tags/rest-apis.md b/Documentation/docs/internal-documentation/backend-services/tags/rest-apis.md new file mode 100644 index 00000000..dd8294e8 --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/tags/rest-apis.md @@ -0,0 +1,123 @@ +--- +description: Tags API +--- + +## GET a tag + +Used to get a tag + +**URL** : `/internal/services/tags/v1/companies/:company_id/tags/:tag_id` + +**Method** : `GET` + +**Auth required** : Yes + +### Success Response + +**Code** : `200 OK` + +**Content example** + +```javascript +{ + { + company_id: string, + tag_id: string, + name: string, + colour: string, + }; +} +``` + +## LIST a tags + +Used to get a tag + +**URL** : `/internal/services/tags/v1/companies/:company_id/tags` + +**Method** : `LIST` + +**Auth required** : Yes + +### Success Response + +**Code** : `200 OK` + +**Content example** + +```javascript +{ + { + company_id: string, + tag_id: string, + name: string, + colour: string, + }[]; +} +``` + +## Create a tag + +Used to create a tag + +**URL** : `/internal/services/tags/v1/companies/:company_id/tags` + +**Method** : `POST` + +**Auth required** : Yes + +**Owner/admin right required** : Yes + +**Data constraints** + +```javascript +{ + name: string, + colour: string, +} +``` + +### Success Response + +**Code** : `201 CREATED` + +## Update a tag + +Used to update a tag + +**URL** : `/internal/services/tags/v1/companies/:company_id/tag/:tag_id` + +**Method** : `POST` + +**Auth required** : Yes + +**Owner/admin right required** : Yes + +**Data constraints** + +```javascript +{ + name: string, + colour: string, +} +``` + +### Success Response + +**Code** : `201 OK` + +## Delete a tag + +Used to delete a tag + +**URL** : `/internal/services/tags/v1/companies/:company_id/tags/:tag_id` + +**Method** : `DELETE` + +**Auth required** : Yes + +**Owner/admin right required** : Yes + +### Success Response + +**Code** : `200 OK` diff --git a/Documentation/docs/internal-documentation/backend-services/users/README.md b/Documentation/docs/internal-documentation/backend-services/users/README.md new file mode 100644 index 00000000..f4b29e3b --- /dev/null +++ b/Documentation/docs/internal-documentation/backend-services/users/README.md @@ -0,0 +1,8 @@ +--- +description: How users and workspaces are managed in backend +--- + +# πŸ‘₯ Users and workspaces + +Document still on notion: [https://www.notion.so/twake/Backend-documentation-e219323593d2401c9887d0e11b2a597b](https://www.notion.so/twake/Backend-documentation-e219323593d2401c9887d0e11b2a597b) + diff --git a/Documentation/docs/internal-documentation/frontend-components/intro/README.md b/Documentation/docs/internal-documentation/frontend-components/intro/README.md new file mode 100644 index 00000000..6ba486dd --- /dev/null +++ b/Documentation/docs/internal-documentation/frontend-components/intro/README.md @@ -0,0 +1,9 @@ +--- +description: Get started with Twake frontend. +--- + +# Storybook + +Twake components are available through our Storybook. You can find it here: + +[https://web.twake.app/storybook/index.html](https://web.twake.app/storybook/index.html) diff --git a/Documentation/docs/internal-documentation/frontend-components/mediumpopupmanager.md b/Documentation/docs/internal-documentation/frontend-components/mediumpopupmanager.md new file mode 100644 index 00000000..39772f10 --- /dev/null +++ b/Documentation/docs/internal-documentation/frontend-components/mediumpopupmanager.md @@ -0,0 +1,6 @@ +--- +description: Not documented yet. +--- + +# MediumPopupManager + diff --git a/Documentation/docs/internal-documentation/frontend-components/menumanager.md b/Documentation/docs/internal-documentation/frontend-components/menumanager.md new file mode 100644 index 00000000..0bb7f720 --- /dev/null +++ b/Documentation/docs/internal-documentation/frontend-components/menumanager.md @@ -0,0 +1,6 @@ +--- +description: Not documented yet. +--- + +# MenuManager + diff --git a/Documentation/docs/internal-documentation/frontend-components/objectmodal/README.md b/Documentation/docs/internal-documentation/frontend-components/objectmodal/README.md new file mode 100644 index 00000000..9d13bd9e --- /dev/null +++ b/Documentation/docs/internal-documentation/frontend-components/objectmodal/README.md @@ -0,0 +1,44 @@ +--- +description: >- + A beautiful, centered, medium modal with all you need to structure its + content. +--- + +# ObjectModal + +#### Usage + +```jsx +import ObjectModal from "components/ObjectModal/ObjectModal.js"; +``` + +```jsx +My awesome title !} + onClose={() => myComponent.closeSomething()} + disabled + footer={} +> + + Some text + +``` + +#### + +#### Props + +| **name** | **Description** | **Type** | **Default** | +| ------------ | -------------------------------------------------------------- | --------- | ----------- | +| **disabled** | Disable scrollbar X axis (need to rename for a better clarity) | Boolean | false | +| **footer** | Define a footer component | ReactNode | null | +| **onClose** | Add close icon in the component, waiting for a function | Function | null | +| **title** | _Define a title component_ | ReactNode | null | + +#### + +#### Preview + +![Modal example with task editor](../../../assets/screenshot-2020-07-15-at-17.00.48.png) + +--- diff --git a/Documentation/docs/internal-documentation/frontend-components/objectmodal/objectmodalformtitle.md b/Documentation/docs/internal-documentation/frontend-components/objectmodal/objectmodalformtitle.md new file mode 100644 index 00000000..4fcaeb9e --- /dev/null +++ b/Documentation/docs/internal-documentation/frontend-components/objectmodal/objectmodalformtitle.md @@ -0,0 +1,32 @@ +--- +description: Icon with sub heading for ObjectModal component. Perfect before a form field. +--- + +# ObjectModalFormTitle + +#### Usage + +```jsx +import ObjectModalFormTitle from 'components/ObjectModal/ObjectModal.js'; +``` + +```jsx + +``` + +#### + +#### Props + +| **name** | **Description** | **Type** | **Default** | +| :--- | :--- | :--- | :--- | +| **className** | Use predefined classes for the title | string | null | +| **icon** | Define icon for the title | string | null | +| **name** | Define the title name | string | null | +| **style** | Define a custom style for the title | object | null | + + + diff --git a/Documentation/docs/internal-documentation/frontend-components/objectmodal/objectmodalsectiontitle.md b/Documentation/docs/internal-documentation/frontend-components/objectmodal/objectmodalsectiontitle.md new file mode 100644 index 00000000..e54c95fd --- /dev/null +++ b/Documentation/docs/internal-documentation/frontend-components/objectmodal/objectmodalsectiontitle.md @@ -0,0 +1,34 @@ +--- +description: Section title, perfect after a separator. +--- + +# ObjectModalSectionTitle + +#### Usage + +```jsx +import ObjectModalFormTitle from "components/ObjectModal/ObjectModal.js"; +``` + +```jsx + +``` + +#### + +#### Props + +| **name** | **Description** | **Type** | **Default** | +| ------------- | ------------------------------------ | -------- | ----------- | +| **className** | Use predefined classes for the title | string | null | +| **icon** | Define icon for the title | string | null | +| **name** | Define the title name | string | null | +| **style** | Define a custom style for the title | object | null | + +#### + +#### Preview + +![](../../../assets/capture-decran-de-2020-07-17-17-58-03.png) + +--- diff --git a/Documentation/docs/internal-documentation/frontend-components/objectmodal/objectmodalseparator.md b/Documentation/docs/internal-documentation/frontend-components/objectmodal/objectmodalseparator.md new file mode 100644 index 00000000..b05164f3 --- /dev/null +++ b/Documentation/docs/internal-documentation/frontend-components/objectmodal/objectmodalseparator.md @@ -0,0 +1,29 @@ +--- +description: Separate your component sections with a simple line. +--- + +# ObjectModalSeparator + +#### Usage + +```jsx +import ObjectModalSeparator from "components/ObjectModal/ObjectModal.js"; +``` + +```jsx + +``` + +#### + +#### Props + +| Name | **Description** | **Type** | **Default** | +| :--: | :----------------------------: | :------: | :---------: | +| | no property for this component | | | + +#### + +#### Preview + +![ObjectModalSeparator example in the ChannelWorkspaceEditor](../../../assets/capture-decran-de-2020-07-17-17-05-36.png) diff --git a/Documentation/docs/internal-documentation/frontend-components/objectmodal/objectmodaltitle.md b/Documentation/docs/internal-documentation/frontend-components/objectmodal/objectmodaltitle.md new file mode 100644 index 00000000..8950f25e --- /dev/null +++ b/Documentation/docs/internal-documentation/frontend-components/objectmodal/objectmodaltitle.md @@ -0,0 +1,34 @@ +--- +description: Main title for the ObjectModal component. +--- + +# ObjectModalTitle + +#### Usage + +```jsx +import ObjectModalTitle from "components/ObjectModal/ObjectModal.js"; +``` + +```jsx + + My awesome title ! + +``` + +#### + +#### Props + +| **name** | **Description** | **Type** | **Default** | +| ------------- | ------------------------------------ | -------- | ----------- | +| **className** | Use predefined classes for the title | string | null | +| **style** | Define a custom style for the title | object | null | + +#### + +#### Preview + +![](../../../assets/capture-decran-de-2020-07-17-17-48-56.png) + +--- diff --git a/Documentation/docs/internal-documentation/frontend-components/table.md b/Documentation/docs/internal-documentation/frontend-components/table.md new file mode 100644 index 00000000..eff72a4a --- /dev/null +++ b/Documentation/docs/internal-documentation/frontend-components/table.md @@ -0,0 +1,43 @@ +--- +description: Create a table +--- + +# Table + +#### Usage + +```jsx +import Table from 'components/Table/Table.js'; +``` + +```jsx + +``` + +#### + +#### Props + +| **name** | **Description** | **Type** | **Default** | +| :--- | :--- | :--- | :--- | +| **columns** | | ReactNode | null | +| **onAdd** | If defined a add button appear and clicking on it call this callback. | Function | null | +| **addText** | Button content | ReactNode | null | +| **onSearch** | Called when search bar is changed. Return a Promise that resolve with a list of users. Argument is \(query: string, maxResult: number\)=>{return new Promise\(...\)} | Function | null | +| **onRequestNextPage, onRequestPreviousPage** | \(token: string, maxResult: number\)=>{return new Promise\(...\)} | Function | null | +| **rowKey** | \(row\)=>return row.id | Function | null | + +**Functions \(callable on the component from parent\)** + +| **name** | **Description** | **Type** | +| :--- | :--- | :--- | +| **newElements\(elements\)** | Add new rows at the beginning of the table. | Function | + +**Internal implementation** + +* If no data in table, set loading to true, call onRequestNextPage without offset token. +* If next page button is clicked, get last row token, set Table to loading, and requestNextPage. +* When recieve result in requestNextPage, set loading to false and update data. +* Table must memorize already loaded pages to be faster +* Table must detect when request a page and no result is returned in this case disable corresponding button. + diff --git a/Documentation/docs/internal-documentation/frontend-components/userlistmanager.md b/Documentation/docs/internal-documentation/frontend-components/userlistmanager.md new file mode 100644 index 00000000..2a130cee --- /dev/null +++ b/Documentation/docs/internal-documentation/frontend-components/userlistmanager.md @@ -0,0 +1,6 @@ +--- +description: Not documented yet? +--- + +# UserListManager + diff --git a/Documentation/docs/internal-documentation/our-stack.md b/Documentation/docs/internal-documentation/our-stack.md new file mode 100644 index 00000000..67625ec3 --- /dev/null +++ b/Documentation/docs/internal-documentation/our-stack.md @@ -0,0 +1,34 @@ +--- +description: Here is the list of our middlewares and their usages. +--- + +# πŸ“š Our stack + +Write an article describing our stack at Twake composed of: + +- In full mode a docker containing: node, react behind nginx, elasticsearch, scylladb, redis, rabbitmq +- In simple mode a docker containing: node, react and mongodb for db and search + +### Simple mode + +The simple mode of Twake messaging app is designed for quick setup and development purposes. It is a more straightforward mode that uses a single container to deploy the components. The technical stack of this mode includes the following components: + +- Node: A JavaScript runtime environment used to develop server-side applications. +- React: A JavaScript library used to build user interfaces. +- MongoDB: A cross-platform document-oriented database used to store and retrieve data. + +The simple mode is great for companies that want a quick and easy setup for their messaging app. It requires less technical expertise and is ideal for small to medium-sized businesses. + +### Full mode + +The full mode of Twake messaging app is designed to handle large-scale production loads with more than 1000 active users. It uses a container-based approach to deploy the components and ensure scalability. The technical stack of this mode includes the following components: + +- Node: A JavaScript runtime environment used to develop server-side applications. +- React: A JavaScript library used to build user interfaces. +- Nginx: A web server used as a reverse proxy to distribute incoming requests to the appropriate backend service. +- Elasticsearch: A distributed search and analytics engine used to perform advanced search operations. +- Scylladb: A NoSQL database used to store large amounts of structured and unstructured data. +- Redis: An in-memory data structure store used to implement caching, messaging, and pub/sub functionalities. +- Rabbitmq: An open-source message broker used to transmit messages between applications. + +The full mode is ideal for companies with large-scale deployment requirements but requires more technical expertise to install and maintain the infrastructure. diff --git a/Documentation/docs/internal-documentation/translation.md b/Documentation/docs/internal-documentation/translation.md new file mode 100644 index 00000000..daeb5793 --- /dev/null +++ b/Documentation/docs/internal-documentation/translation.md @@ -0,0 +1,25 @@ +--- +description: Want to translate Twake ? +--- + +# 🎭 Translation + +## Translation process + +Twake is built for everyone. That means we support languages that user want. If we do not already support your language, or you find a mistake in the translation, you have a simply way to do that. + +Send us a mail to this address saying that you want to help us on the translation : [sales@twake.app](mailto:sales@twake.app). After, you'll have to follow the bellow steps. + +## Join weblate server + +At Twake, we use [weblate](https://hosted.weblate.org/), a tool that allow you to translate Twake without working on the code. After you sent an email, we'll invite you to the project. Inside the Twake project you can find [twake-web-frontend](https://hosted.weblate.org/projects/twake/twake-web-frontend/) that contains all translation for the web version. + +## Start to translate + +After choosing the language you want to contribute, you can click on categories that need some work \(like `Not translated strings` . Now you can start to translate : you have to fulfill the input You can see `Other languages` tab to give you more context about the string. After, just click on save and it is done ! + +![](<../assets/image-(6).png>) + +## Thank you! + +Twake is build by and for the community. Your commitment is highly appreciate! In reward, we can offer you a year on our SaaS version. You just have to contact us through this email : [sales@twake.app](mailto:sales@twake.app) diff --git a/Documentation/docs/internal-documentation/twake-ecosystem-guidelines.md b/Documentation/docs/internal-documentation/twake-ecosystem-guidelines.md new file mode 100644 index 00000000..d9f54b54 --- /dev/null +++ b/Documentation/docs/internal-documentation/twake-ecosystem-guidelines.md @@ -0,0 +1,85 @@ +--- +description: >- + Global guidelines for any new projects around Twake, Frontend and Backend + guidelines are discussed here. +--- + +# 🎨 Twake Ecosystem Guidelines + +## Frontend guidelines + +### Logo, UI and UX guidelines + +#### Logos + +{% file src="../assets/logo\_shape.svg" caption="Logo shape in SVG format" %} + +#### Colors and fonts + +The fonts and colors to use are defined in the document bellow, scroll down for the hexadecimal codes of each color. + +![](../assets/screenshot-2021-03-31-at-14.51.23.png) + +Colors code extracted from the Twake theme [https://github.com/linagora/Twake/blob/main/twake/frontend/src/app/theme.less](https://github.com/linagora/Twake/blob/main/twake/frontend/src/app/theme.less) + +```css +// Circular Std = France +// Helvetica Neue = Vietnam +// TT Norms = Russia + +// --- Twake fonts --- // +@main-font: "Circular Std", -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", + "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol"; + +// --- Twake colors --- // +@primary: #3840f7; +@primary-background: #3842f723; +@primary-hover: #3850f7; +@secondary: #0d0f38; + +@black: #000000; +@black-alpha-50: #18295288; +@black-alpha-70: #18295255; +@grey-background: #f5f5f7; +@grey-light: #eeeeee; +@grey-dark: #6a6a6a; + +@error: #ff5154; +@success: #04aa11; +@warning: #ff8607; +@white: #fff; +``` + +#### Icons and emojis \(⚠️ not validated by UX designer yet\) + +Twake is currently using feather icons [https://feathericons.com/](https://feathericons.com/) and can fallback to Material Icons or FontAwesome. + +Emojis on web must use the Apple emojis set preferably. On device, prefer to use the device emoji set. + +### Frameworks and component system + +#### Languages and frameworks + +We recommend **TypeScript** and **VueJS** for any new projects around Twake. \(But Twake itself currently uses ReactJS with typescript.\) + +#### **Components system** + +We strongly recommend using Antd design system: [https://ant.design/](https://ant.design/) for 3 reasons: + +1. We want to **differ from Material** UI that is too recognisable +2. Antd is very customisable, and **we provide a Twake theme here:** [**https://github.com/linagora/Twake/blob/main/twake/frontend/src/app/theme.less**](https://github.com/linagora/Twake/blob/main/twake/frontend/src/app/theme.less)\*\*\*\* +3. Antd contain more components than Material UI + +### Libraries for common use cases + +Feel free to add any library in this table. + +| Use case | used by | prefered library | +| :-------------- | :----------------- | :------------------------------------------------------- | +| Infinite scroll | Twake message feed | [https://virtuoso.dev/](https://virtuoso.dev/) \(React\) | + +## Backend guidelines + +### Programmation languages + +### Databases and middlewares diff --git a/Documentation/docs/onprem/configuration/authentication-modes/README.md b/Documentation/docs/onprem/configuration/authentication-modes/README.md new file mode 100644 index 00000000..5d315610 --- /dev/null +++ b/Documentation/docs/onprem/configuration/authentication-modes/README.md @@ -0,0 +1,10 @@ +--- +description: Twake let you authenticate using CAS or OpenID. +--- + +# πŸ‘¨β€πŸ’» Authentication modes + +Twake works with OpenID, CAS and in standalone. + +See child pages to configure with [KeyCloak](using-keycloak-ldap-openid-and-more.md) or [LemonLDAP](installing-twake-with-lemonldap-ldap-openid-and-more.md). + diff --git a/Documentation/docs/onprem/configuration/authentication-modes/installing-twake-with-lemonldap-ldap-openid-and-more.md b/Documentation/docs/onprem/configuration/authentication-modes/installing-twake-with-lemonldap-ldap-openid-and-more.md new file mode 100644 index 00000000..ac843781 --- /dev/null +++ b/Documentation/docs/onprem/configuration/authentication-modes/installing-twake-with-lemonldap-ldap-openid-and-more.md @@ -0,0 +1,52 @@ +--- +description: 'Harder than KeyCloak but has other features, see official LemonLDAP site.' +--- + +# Installing Twake with LemonLDAP \(LDAP, OpenID and more\) + +#### 1. Twake configuration + +Edit Twake PHP config `twake/backend/core/app/Configuration/Parameters.php`, in defaults.auth.openid + +```text +"openid" => [ + "use" => true, + "provider_uri" => 'http://auth.open-paas.org.local', + "client_id" => 'twake', + "client_secret" => 'secret', + "ignore_mail_verified" => true, + "ignore_id_token_verification" => true, + "provider_config" => [ + "token_endpoint"=> "http://auth.open-paas.org.local/oauth2/token", //token_endpoint + "userinfo_endpoint" => "http://auth.open-paas.org.local/oauth2/userinfo",//userinfo_endpoint + "end_session_endpoint" => "http://auth.open-paas.org.local/oauth2/logout",//end_session_endpoint + "authorization_endpoint" => "http://auth.open-paas.org.local/oauth2/authorize",//authorization_endpoint + ] + +], +``` + +Add line to /etc/hosts if needed : + +`sudo docker-compose exec php bash -c "echo '51.210.124.92 manager.open-paas.org.local auth.open-paas.org.local reload.open-paas.org.local' >> /etc/hosts"` + +#### 2. Lemon LDAP configuration + +Dans ClientOpenIDConnect > twake > Options > Basique > Adresse connexion : [http://15.236.209.74/ajax/users/openid](http://15.236.209.74/ajax/users/openid) + +Dans ClientOpenIDConnect > twake > Attributs exportΓ©s : + +```text +{ + email_verified: email_verified, + picture: picture, + name: cn, + given_name: givenName, + family_name: sn, + email: mail, + sub: uid +} +``` + +\[Ne marche pas pour le moment\] Dans ClientOpenIDConnect > twake > Options > DΓ©connexion > Adresse : [http://15.236.209.74/ajax/users/openid/logout\_success](http://15.236.209.74/ajax/users/openid/logout_success) + diff --git a/Documentation/docs/onprem/configuration/authentication-modes/using-keycloak-ldap-openid-and-more.md b/Documentation/docs/onprem/configuration/authentication-modes/using-keycloak-ldap-openid-and-more.md new file mode 100644 index 00000000..385dcb2e --- /dev/null +++ b/Documentation/docs/onprem/configuration/authentication-modes/using-keycloak-ldap-openid-and-more.md @@ -0,0 +1,47 @@ +--- +description: Use Keycloak with Twake +--- + +# Using Keycloak \(LDAP, OpenID and more\) + +#### Run keycloak and persist data + +```text +cd twake +docker run -p 8080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin -v $(pwd)/docker-data/keycloak-db:/opt/jboss/keycloak/standalone/data jboss/keycloak +``` + +#### Configure keycloak with twake for the first time + +**On Keycloak** + +Go to `http://localhost:8080/auth/` + +Login with admin:admin + +Go to client > account > Credentials tab and save the `Secret` + +Go to Settings tab and add a Valid Redirect uri to `http://localhost:8000/*` and save + +Then create an user in User / Add User + +⚠️ Users must have an email and the email must be marked as verified ! + +Then create a password for this user. + +**On Twake** + +Go to your \[docker-compose file location\]/configuration/backend/Parameters.php \(see [Configuration](../)\) + +Change defaults.auth.openid to: + +```text + "use" => true, + "provider_uri" => 'http://[machine_ip]:8080/auth/realms/master', + "client_id" => 'account', + "client_secret" => '[keycloak_secret]', + "logout_suffix" => "/protocol/openid-connect/logout" //Specific to keycloak +``` + +ℹ️ \[machine\_ip\] Because Twake is accessing keycloak for inside a docker container, do not use localhost or 127.0.0.1 to access keycloak. + diff --git a/Documentation/docs/onprem/configuration/configure-mail-server.md b/Documentation/docs/onprem/configuration/configure-mail-server.md new file mode 100644 index 00000000..cd84a312 --- /dev/null +++ b/Documentation/docs/onprem/configuration/configure-mail-server.md @@ -0,0 +1,34 @@ +--- +description: To configure your mail serveur with Twake. +--- + +# πŸ’Œ Configure mail server + +Here is the default mail block in the configuration file to edit \(from Parameters.php, see "[Configuration page](./)"\): + +```text +"mail" => [ + "sender" => [ + "host" => "", //smtp server + "port" => "", + "username" => "", + "password" => "", + "auth_mode" => "plain" //plain, login, cram-md5, or null + ], + "from" => "noreply@twakeapp.com", + "dkim" => [ //Optional, to avoid lost emails, configure your dns with dkim + "private_key" => "", + "domain_name" => '', + "selector" => '' + ], + "twake_domain_url" => "https://twakeapp.com/", + "from_name" => "Twake", //Server owner name + "twake_address" => "Twake, 54000 Nancy, France", //Server owner address + "template_dir" => "/src/Twake/Core/Resources/views/", //Must not be modified +], +``` + +⚠️ Once edited, don't forget to restart docker. + +You can test the good behaviour of emails going into your account parameters, emails, add a secondary email. Or simply try to invite a user using its email. + diff --git a/Documentation/docs/onprem/configuration/connectors-and-plugins.md b/Documentation/docs/onprem/configuration/connectors-and-plugins.md new file mode 100644 index 00000000..3b0252da --- /dev/null +++ b/Documentation/docs/onprem/configuration/connectors-and-plugins.md @@ -0,0 +1,12 @@ +--- +description: 'You can connect anything you want on Twake, read this to know how.' +--- + +# πŸ”Œ Connectors and plugins + +### Install connectors and plugins on SaaS version + +Work in progress. + +Ask us to be faster on [https://community.twake.app](https://community.twake.app) ! + diff --git a/Documentation/docs/onprem/configuration/custom-domain-and-https/README.md b/Documentation/docs/onprem/configuration/custom-domain-and-https/README.md new file mode 100644 index 00000000..048d12b9 --- /dev/null +++ b/Documentation/docs/onprem/configuration/custom-domain-and-https/README.md @@ -0,0 +1,70 @@ +--- +description: Use a custom domain with Twake +--- + +# πŸ”— Custom domain + HTTPS + +::: info +We do not offer the possibility to edit the nginx configuration present in the docker-compose containers yet. To enable https you first need to install nginx and configure on your machine. + +Your nginx installation will be used to forward the requests from https to the docker-compose http port. + +The last step is to tell Twake that the frontend is accessed from a different domain and protocol to handle the redirections. +::: + +#### Use port 80 or 443 over https + +To use 443 create a new nginx install and attach a proxy to port 8000 + certauto. +If you use Apache2 go on the [Apache2 configuration page](apache2-configuration.md). + +> Follow this thread if you have issues with websockets and reverse proxy: [https://community.twake.app/t/twake-on-docker-behind-apache-proxy/78](https://community.twake.app/t/twake-on-docker-behind-apache-proxy/78) + +```text +# /etc/nginx/site-enabled/default +location / { + proxy_pass http://127.0.0.1:8000; +} + +location /socketcluster/ { + proxy_pass http://127.0.0.1:8000/socketcluster/; + # this magic is needed for WebSocket + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_connect_timeout 7d; + proxy_send_timeout 7d; + proxy_read_timeout 7d; +} +``` + +#### Configure domain name + +You must edit the configuration in both `configuration/frontend/environment.ts` and `configuration/backend/Parameters.php` + +```text +//Exemple of environment.ts +export default { + env_dev: false, + mixpanel_enabled: false, + sentry_dsn: false, + mixpanel_id: false, + front_root_url: 'https://twake.acme.com', + api_root_url: 'https://twake.acme.com', + websocket_url: 'wss://twake.acme.com' +}; +``` + +```text +//To change in Parameters.php +... +"env" => [ + ... + "server_name" => "https://twake.acme.com/", +], +... +``` + +> Dont forget to restart your docker-compose πŸ˜‰ and rebuild the frontend: +> `docker-compose exec nginx yarn build` diff --git a/Documentation/docs/onprem/configuration/custom-domain-and-https/apache2-configuration.md b/Documentation/docs/onprem/configuration/custom-domain-and-https/apache2-configuration.md new file mode 100644 index 00000000..f9218e9b --- /dev/null +++ b/Documentation/docs/onprem/configuration/custom-domain-and-https/apache2-configuration.md @@ -0,0 +1,77 @@ +--- +description: "\U0001F64F From Dahpril (community) https://github.com/TwakeApp/Twake/issues/76" +--- + +# Apache2 configuration + +#### Apache vhost + +You need to create a vhost listening on port 443. + +_For exemple with certbot :_ + +_1. Create a vhost listening on port 80 with ServerName equals to your custom domain. Don't define any document root. 2. Then, use certbot to get a certificate and automatically create your vhost listening on port 443_ + +```text +sudo certbot --apache --email your_email -d your_domain --agree-tos --redirect --noninteractive +``` + +#### Reverse proxy + +You have now to configure your reverse proxy directive. Head up to your 443 vhost configuration file and paste those directives \(place them after server and ssl directives\) : + +```text +RewriteEngine on +RewriteCond ${HTTP:Upgrade} websocket [NC] +RewriteCond ${HTTP:Connection} upgrade [NC] +RewriteRule .* "wss://127.0.0.1:8000/$1" [P,L] + +ProxyRequests off + + + ProxyPass http://127.0.0.1:8000/ + ProxyPassReverse http://127.0.0.1:8000/ + ProxyPreserveHost On + + + ProxyPass ws://127.0.0.1:8000/socketcluster + ProxyPassReverse ws://127.0.0.1:8000/socketcluster + ProxyPreserveHost On + + + + AllowOverride All + Order allow,deny + Allow from All + + +RequestHeader set X-Forwarded-port "80" +``` + +Be careful to NOT type trailing slash for ws location \(it won't work\). + +I'm not sure that all directives are needed, but this configuration works for me. + +#### Configuring remoteip + +You also need to configure remoteip mod from apache with this command : + +```text +a2enmod remoteip +``` + +Then, edit /etc/apache2/conf-available/remoteip.conf to fit with this content : + +```text +RemoteIPHeader X-Real-IP +RemoteIPTrustedProxy 127.0.0.1 ::1 +``` + +You can now enable the configuration of remoteip and restart Apache : + +```text +a2enconf remoteip +service apache2 restart +``` + +Return to the section "Configure domain name" of [Custom domain + HTTPS](./README.md#configure-domain-name) page to continue the configuration. diff --git a/Documentation/docs/onprem/configuration/customisation.md b/Documentation/docs/onprem/configuration/customisation.md new file mode 100644 index 00000000..1727eb7c --- /dev/null +++ b/Documentation/docs/onprem/configuration/customisation.md @@ -0,0 +1,64 @@ +--- +description: How to make Twake feel better in your company. +--- + +# 🎨 Customisation + +> Customising Twake on SaaS \(web.twake.app\) is not available yet, contact sales to install an on-premise Twake version. + +### Customise style and logos + +You can customise Twake for your brand using the `configuration/backend/Parameters.php` file. + +```text +"defaults" => [ + "branding" => [ + "header" => [ + "logo" => '', //Some logo used on header coloured background + "apps" => [ //A list of apps accessible from header + [ + "name"=> '', //App name + "url"=> '', //Url to your app + "icon"=> '', //App icon as image + ], + ], + ], + "style" => [ + "color" => '#2196F3', //Change default main color + "default_border_radius" => '2', //Change default main border-radius + ], + "name" => "", //Brand name + "enable_newsletter" => false, //Disable newsletter checkbox on subscribe + "link" => "", //Link to your website (showed on login page) + "logo" => "" //Coloured logo (white background) + ] +] +``` + +### Customize apps + +You can disable default apps with this command \(apps will not be installed on future new companies or workspaces\) + +```text +"defaults" => [ + "applications" => [ + "twake_calendar" => false, //Not available + "twake_tasks" => [ "default" => false ], //Available but not by default + "twake_drive" => [ "default" => true ], //Available and by default in every new workspaces + "connectors" => [ + "jitsi" => [ "default" => true ], + "linshare" => false + ] + ] +] +``` + +After editing this configuration, **restart docker-compose** \(to import new configuration\) and type the following command: + +```text +#docker-compose restart #To import new configuration +docker-compose exec php php bin/console twake:init +``` + + + diff --git a/Documentation/docs/onprem/configuration/index.md b/Documentation/docs/onprem/configuration/index.md new file mode 100644 index 00000000..36dd3afe --- /dev/null +++ b/Documentation/docs/onprem/configuration/index.md @@ -0,0 +1,52 @@ +--- +description: More details about Twake configuration. +--- + +# βš™οΈ Server configuration + +### Detach the configuration and start using your own + +Each configuration file is optional, if not given, Twake will fallback to default configuration. + +#### Backend configuration + +You can find an example of Twake configuration (default configuration) here: [https://github.com/TwakeApp/Twake/blob/main/twake/backend/node/config/default.json](https://github.com/TwakeApp/Twake/blob/main/twake/backend/node/config/default.json) + +Copy the content of this file and put it in `[docker-compose.yml location]/configuration/backend-node/production.json` + +> **Tip:** you can put a 'cert' directory with apns.cert keys (mobile push notifications) beside the backend-node/production.json file. + +#### Backend configuration, PHP (only for scalable mode) + +An example is available here: [https://github.com/TwakeApp/Twake/blob/main/twake/backend/core/app/Configuration/Parameters.php.dist](https://github.com/TwakeApp/Twake/blob/main/twake/backend/core/app/Configuration/Parameters.php.dist) + +Copy the content of this file and put it in `[docker-compose.yml location]/configuration/backend/Parameters.php` + +> **Tip:** you can also put a 'cert' directory with apns.cert keys (mobile push notifications) beside the Parameters.php file. + +#### Frontend configuration (only for scalable mode) + +You can find an example of Twake configuration (default configuration) here: [https://github.com/TwakeApp/Twake/blob/main/twake/frontend/src/app/environment/environment.ts.dist](https://github.com/TwakeApp/Twake/blob/main/twake/frontend/src/app/environment/environment.ts.dist) + +Copy the content of this file and put it in `[docker-compose.yml location]/configuration/frontend/environment.ts` + +#### After a configuration change + +Each time you change the configuration, restart your docker container like this: + +``` +# In mongodb mode +docker-compose restart node + +# In full scalable mode +docker-compose restart nginx node +docker-compose exec nginx yarn build #If you have custom frontend configuration +``` + +::: warning +If you are using ScyllaDB (mandatory for any version before 2022) you must make sure ScyllaDB is started before to start the node container. + +If your server is completely stoped you can use this command to make sure everything starts well: + + `docker-compose up -d scylladb; sleep 120; docker-compose up -d` +::: diff --git a/Documentation/docs/onprem/configuration/security.md b/Documentation/docs/onprem/configuration/security.md new file mode 100644 index 00000000..b1fe9115 --- /dev/null +++ b/Documentation/docs/onprem/configuration/security.md @@ -0,0 +1,60 @@ +--- +description: You should update this security keys to ship Twake in production. +--- + +# πŸ”’ Security + +> See how to [Detach Configuration](./) first. + +The following keys must be updated to increase Twake security in [docker-compose.yml location]/configuration/backend-node/production.json: + +```json +{ + "phpnode": { + "secret": "xxx" // Secret for PHP<->Node communication, deprecated like PHP + }, + "websocket": { + "auth": { + "jwt": { + "secret": "xxx" // JWT secret for websockets + } + } + }, + "auth": { + "jwt": { + "secret": "xxx" // JWT secret + } + }, + "database": { + "secret": "xxx" // Db app layer encryption key + }, + "storage": { + "secret": "xxx", // Storage app layer encryption key + "iv": "xxx" // Storage app layer encryption iv + } +} +``` + +The following keys must be updated to increase Twake security in /configuration/backend/Parameters.php: + +```text +"env" => [ + "secret" => "somesecret", //Any string +], +... +"websocket" => [ + ... + "pusher_public" //Generate public and private key + "pusher_private" //Put private key here +], +"db" => [ + ... + "encryption_key" //Any string +] +... +"storage" => [ + ... + "drive_salt" => "SecretPassword", //Any string +], +... +``` diff --git a/Documentation/docs/onprem/installation.md b/Documentation/docs/onprem/installation.md new file mode 100644 index 00000000..ba2aa875 --- /dev/null +++ b/Documentation/docs/onprem/installation.md @@ -0,0 +1,78 @@ +# πŸ— Install on your server + +## Use Twake in SaaS + +You can test or use Twake in our SaaS : [chat.twake.app](https://chat.twake.app) + +## Run Twake in your server + +1. First you'll need to [install docker and docker-compose](https://docs.docker.com/compose/install/). + +2. Then you can install Twake on your server with this command + +``` +git clone https://github.com/TwakeApp/Twake.git +cd Twake/twake +docker-compose -f docker-compose.onpremise.mongo.yml up -d +``` + +Twake will be running on port 3000 + +### What's next ? + +If you kept the default configuration, you can simply follow the signup steps, no email verification is required by default so you will get into Twake right after the signup steps. + +## Ship Twake in production + +See how to [manage configuration](./configuration/index.md)). And then how to [update security keys](./configuration/security.md), and finally how to use your [custom domain](./configuration/custom-domain-and-https/README.md)). + +### Update Twake + +``` +docker-compose stop +docker-compose rm #Remove images (not volumes so your data is safe) +docker-compose pull #Get new images +docker-compose up -d +docker-compose exec nginx yarn build #If you have custom frontend configuration +``` + +## Requirements and scalability + +Currently you'll need at least a **2 cpu + 4 gb of ram** machine for **20-50 users** depending on their usage and with ElasticSearch disabled. + +If you enable ElasticSearch, use two machines, or limit the cpu/ram dedicated to it and use a larger machine (at least 2gb of ram and 1 cpu dedicated to ES for 20-50 users). + +If you need to deploy Twake for more users, you can use only one big machine up to 500 users (Will need something like **12 cpu and 32go of ram**), then you'll need to use multiple nodes. + +--- + +# 🎑 Scale with Twake + +> We deployed Twake on production for companies of 10 to 50 users in a single node. We also deployed Twake in a scalable mode and we support currently thousands of concurrent users. +> If you deploy Twake in your own company we would love to have your feedback here [https://github.com/TwakeApp/Twake/issues/289](https://github.com/TwakeApp/Twake/issues/289) to improve our requirements documentation. +> Now if you want to scale with Twake and support thousand of users, continue reading. + +Scaling with Twake is possible if you install Twake with **RabbitMQ, Redis, ElasticSearch and ScyllaDB**. + +``` +git clone https://github.com/TwakeApp/Twake.git +cd Twake/twake + +cp -n docker-compose.yml.dist.onpremise docker-compose.yml +cp -nR default-configuration/ configuration/ + +docker-compose pull + +docker-compose up -d scylladb +sleep 5m #Wait scylladb to startup +docker-compose up -d php rabbitmq +sleep 10m #Wait php to create tables in scylladb + +docker-compose up -d +``` + +> To run ElasticSearch (optional, but enabled by default in the Twake docker-compose) you must increase the max_map_count of your system: [https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#\_set_vm_max_map_count_to_at_least_262144](https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#_set_vm_max_map_count_to_at_least_262144) +> +> To fix an other bug with ElasticSearch container, you must also run this command: `chmod 777 ./docker-data/es_twake` (create the folder if it doesn't exists in your docker-compose.yml folder) + +Twake will be running on port 8000 πŸŽ‰ diff --git a/Documentation/docs/vite.config.js b/Documentation/docs/vite.config.js new file mode 100644 index 00000000..b293d10d --- /dev/null +++ b/Documentation/docs/vite.config.js @@ -0,0 +1,6 @@ +import { SearchPlugin } from "vitepress-plugin-search"; +import { defineConfig } from "vite"; + +export default defineConfig({ + plugins: [SearchPlugin()], +}); diff --git a/Documentation/package.json b/Documentation/package.json new file mode 100644 index 00000000..10bd00ef --- /dev/null +++ b/Documentation/package.json @@ -0,0 +1,18 @@ +{ + "name": "Documentation", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "scripts": { + "docs:dev": "vitepress dev docs", + "docs:build": "vitepress build docs", + "docs:serve": "vitepress serve docs" + }, + "devDependencies": { + "flexsearch": "^0.7.31", + "markdown-it": "^13.0.1", + "vitepress": "1.0.0-alpha.13", + "vitepress-plugin-search": "^1.0.4-alpha.15", + "vue": "^3.2.45" + } +} diff --git a/Documentation/yarn.lock b/Documentation/yarn.lock new file mode 100644 index 00000000..ef28fd7e --- /dev/null +++ b/Documentation/yarn.lock @@ -0,0 +1,692 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@algolia/autocomplete-core@1.7.2": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.7.2.tgz#8abbed88082f611997538760dffcb43b33b1fd1d" + integrity sha512-eclwUDC6qfApNnEfu1uWcL/rudQsn59tjEoUYZYE2JSXZrHLRjBUGMxiCoknobU2Pva8ejb0eRxpIYDtVVqdsw== + dependencies: + "@algolia/autocomplete-shared" "1.7.2" + +"@algolia/autocomplete-preset-algolia@1.7.2": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.2.tgz#9cd4f64b3d64399657ee2dc2b7e0a939e0713a26" + integrity sha512-+RYEG6B0QiGGfRb2G3MtPfyrl0dALF3cQNTWBzBX6p5o01vCCGTTinAm2UKG3tfc2CnOMAtnPLkzNZyJUpnVJw== + dependencies: + "@algolia/autocomplete-shared" "1.7.2" + +"@algolia/autocomplete-shared@1.7.2": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.2.tgz#daa23280e78d3b42ae9564d12470ae034db51a89" + integrity sha512-QCckjiC7xXHIUaIL3ektBtjJ0w7tTA3iqKcAE/Hjn1lZ5omp7i3Y4e09rAr9ZybqirL7AbxCLLq0Ra5DDPKeug== + +"@algolia/cache-browser-local-storage@4.14.2": + version "4.14.2" + resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.14.2.tgz#d5b1b90130ca87c6321de876e167df9ec6524936" + integrity sha512-FRweBkK/ywO+GKYfAWbrepewQsPTIEirhi1BdykX9mxvBPtGNKccYAxvGdDCumU1jL4r3cayio4psfzKMejBlA== + dependencies: + "@algolia/cache-common" "4.14.2" + +"@algolia/cache-common@4.14.2": + version "4.14.2" + resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.14.2.tgz#b946b6103c922f0c06006fb6929163ed2c67d598" + integrity sha512-SbvAlG9VqNanCErr44q6lEKD2qoK4XtFNx9Qn8FK26ePCI8I9yU7pYB+eM/cZdS9SzQCRJBbHUumVr4bsQ4uxg== + +"@algolia/cache-in-memory@4.14.2": + version "4.14.2" + resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.14.2.tgz#88e4a21474f9ac05331c2fa3ceb929684a395a24" + integrity sha512-HrOukWoop9XB/VFojPv1R5SVXowgI56T9pmezd/djh2JnVN/vXswhXV51RKy4nCpqxyHt/aGFSq2qkDvj6KiuQ== + dependencies: + "@algolia/cache-common" "4.14.2" + +"@algolia/client-account@4.14.2": + version "4.14.2" + resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.14.2.tgz#b76ac1ba9ea71e8c3f77a1805b48350dc0728a16" + integrity sha512-WHtriQqGyibbb/Rx71YY43T0cXqyelEU0lB2QMBRXvD2X0iyeGl4qMxocgEIcbHyK7uqE7hKgjT8aBrHqhgc1w== + dependencies: + "@algolia/client-common" "4.14.2" + "@algolia/client-search" "4.14.2" + "@algolia/transporter" "4.14.2" + +"@algolia/client-analytics@4.14.2": + version "4.14.2" + resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.14.2.tgz#ca04dcaf9a78ee5c92c5cb5e9c74cf031eb2f1fb" + integrity sha512-yBvBv2mw+HX5a+aeR0dkvUbFZsiC4FKSnfqk9rrfX+QrlNOKEhCG0tJzjiOggRW4EcNqRmaTULIYvIzQVL2KYQ== + dependencies: + "@algolia/client-common" "4.14.2" + "@algolia/client-search" "4.14.2" + "@algolia/requester-common" "4.14.2" + "@algolia/transporter" "4.14.2" + +"@algolia/client-common@4.14.2": + version "4.14.2" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.14.2.tgz#e1324e167ffa8af60f3e8bcd122110fd0bfd1300" + integrity sha512-43o4fslNLcktgtDMVaT5XwlzsDPzlqvqesRi4MjQz2x4/Sxm7zYg5LRYFol1BIhG6EwxKvSUq8HcC/KxJu3J0Q== + dependencies: + "@algolia/requester-common" "4.14.2" + "@algolia/transporter" "4.14.2" + +"@algolia/client-personalization@4.14.2": + version "4.14.2" + resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.14.2.tgz#656bbb6157a3dd1a4be7de65e457fda136c404ec" + integrity sha512-ACCoLi0cL8CBZ1W/2juehSltrw2iqsQBnfiu/Rbl9W2yE6o2ZUb97+sqN/jBqYNQBS+o0ekTMKNkQjHHAcEXNw== + dependencies: + "@algolia/client-common" "4.14.2" + "@algolia/requester-common" "4.14.2" + "@algolia/transporter" "4.14.2" + +"@algolia/client-search@4.14.2": + version "4.14.2" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.14.2.tgz#357bdb7e640163f0e33bad231dfcc21f67dc2e92" + integrity sha512-L5zScdOmcZ6NGiVbLKTvP02UbxZ0njd5Vq9nJAmPFtjffUSOGEp11BmD2oMJ5QvARgx2XbX4KzTTNS5ECYIMWw== + dependencies: + "@algolia/client-common" "4.14.2" + "@algolia/requester-common" "4.14.2" + "@algolia/transporter" "4.14.2" + +"@algolia/logger-common@4.14.2": + version "4.14.2" + resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.14.2.tgz#b74b3a92431f92665519d95942c246793ec390ee" + integrity sha512-/JGlYvdV++IcMHBnVFsqEisTiOeEr6cUJtpjz8zc0A9c31JrtLm318Njc72p14Pnkw3A/5lHHh+QxpJ6WFTmsA== + +"@algolia/logger-console@4.14.2": + version "4.14.2" + resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.14.2.tgz#ec49cb47408f5811d4792598683923a800abce7b" + integrity sha512-8S2PlpdshbkwlLCSAB5f8c91xyc84VM9Ar9EdfE9UmX+NrKNYnWR1maXXVDQQoto07G1Ol/tYFnFVhUZq0xV/g== + dependencies: + "@algolia/logger-common" "4.14.2" + +"@algolia/requester-browser-xhr@4.14.2": + version "4.14.2" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.14.2.tgz#a2cd4d9d8d90d53109cc7f3682dc6ebf20f798f2" + integrity sha512-CEh//xYz/WfxHFh7pcMjQNWgpl4wFB85lUMRyVwaDPibNzQRVcV33YS+63fShFWc2+42YEipFGH2iPzlpszmDw== + dependencies: + "@algolia/requester-common" "4.14.2" + +"@algolia/requester-common@4.14.2": + version "4.14.2" + resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.14.2.tgz#bc4e9e5ee16c953c0ecacbfb334a33c30c28b1a1" + integrity sha512-73YQsBOKa5fvVV3My7iZHu1sUqmjjfs9TteFWwPwDmnad7T0VTCopttcsM3OjLxZFtBnX61Xxl2T2gmG2O4ehg== + +"@algolia/requester-node-http@4.14.2": + version "4.14.2" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.14.2.tgz#7c1223a1785decaab1def64c83dade6bea45e115" + integrity sha512-oDbb02kd1o5GTEld4pETlPZLY0e+gOSWjWMJHWTgDXbv9rm/o2cF7japO6Vj1ENnrqWvLBmW1OzV9g6FUFhFXg== + dependencies: + "@algolia/requester-common" "4.14.2" + +"@algolia/transporter@4.14.2": + version "4.14.2" + resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.14.2.tgz#77c069047fb1a4359ee6a51f51829508e44a1e3d" + integrity sha512-t89dfQb2T9MFQHidjHcfhh6iGMNwvuKUvojAj+JsrHAGbuSy7yE4BylhLX6R0Q1xYRoC4Vvv+O5qIw/LdnQfsQ== + dependencies: + "@algolia/cache-common" "4.14.2" + "@algolia/logger-common" "4.14.2" + "@algolia/requester-common" "4.14.2" + +"@babel/parser@^7.16.4": + version "7.20.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.3.tgz#5358cf62e380cf69efcb87a7bb922ff88bfac6e2" + integrity sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg== + +"@docsearch/css@3.3.0", "@docsearch/css@^3.2.1": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-3.3.0.tgz#d698e48302d12240d7c2f7452ccb2d2239a8cd80" + integrity sha512-rODCdDtGyudLj+Va8b6w6Y85KE85bXRsps/R4Yjwt5vueXKXZQKYw0aA9knxLBT6a/bI/GMrAcmCR75KYOM6hg== + +"@docsearch/js@^3.2.1": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@docsearch/js/-/js-3.3.0.tgz#c8f614b722cc8a6375e83f9c27557e9398d6a4d4" + integrity sha512-oFXWRPNvPxAzBhnFJ9UCFIYZiQNc3Yrv6912nZHw/UIGxsyzKpNRZgHq8HDk1niYmOSoLKtVFcxkccpQmYGFyg== + dependencies: + "@docsearch/react" "3.3.0" + preact "^10.0.0" + +"@docsearch/react@3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-3.3.0.tgz#b8ac8e7f49b9bf2f96d34c24bc1cfd097ec0eead" + integrity sha512-fhS5adZkae2SSdMYEMVg6pxI5a/cE+tW16ki1V0/ur4Fdok3hBRkmN/H8VvlXnxzggkQIIRIVvYPn00JPjen3A== + dependencies: + "@algolia/autocomplete-core" "1.7.2" + "@algolia/autocomplete-preset-algolia" "1.7.2" + "@docsearch/css" "3.3.0" + algoliasearch "^4.0.0" + +"@esbuild/android-arm@0.15.13": + version "0.15.13" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.15.13.tgz#ce11237a13ee76d5eae3908e47ba4ddd380af86a" + integrity sha512-RY2fVI8O0iFUNvZirXaQ1vMvK0xhCcl0gqRj74Z6yEiO1zAUa7hbsdwZM1kzqbxHK7LFyMizipfXT3JME+12Hw== + +"@esbuild/linux-loong64@0.15.13": + version "0.15.13" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.13.tgz#64e8825bf0ce769dac94ee39d92ebe6272020dfc" + integrity sha512-+BoyIm4I8uJmH/QDIH0fu7MG0AEx9OXEDXnqptXCwKOlOqZiS4iraH1Nr7/ObLMokW3sOCeBNyD68ATcV9b9Ag== + +"@types/flexsearch@^0.7.3": + version "0.7.3" + resolved "https://registry.yarnpkg.com/@types/flexsearch/-/flexsearch-0.7.3.tgz#ee79b1618035c82284278e05652e91116765b634" + integrity sha512-HXwADeHEP4exXkCIwy2n1+i0f1ilP1ETQOH5KDOugjkTFZPntWo0Gr8stZOaebkxsdx+k0X/K6obU/+it07ocg== + +"@types/linkify-it@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.2.tgz#fd2cd2edbaa7eaac7e7f3c1748b52a19143846c9" + integrity sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA== + +"@types/markdown-it@^12.2.3": + version "12.2.3" + resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-12.2.3.tgz#0d6f6e5e413f8daaa26522904597be3d6cd93b51" + integrity sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ== + dependencies: + "@types/linkify-it" "*" + "@types/mdurl" "*" + +"@types/mdurl@*": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9" + integrity sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA== + +"@types/web-bluetooth@^0.0.16": + version "0.0.16" + resolved "https://registry.yarnpkg.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz#1d12873a8e49567371f2a75fe3e7f7edca6662d8" + integrity sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ== + +"@vitejs/plugin-vue@^3.0.3": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-3.2.0.tgz#a1484089dd85d6528f435743f84cdd0d215bbb54" + integrity sha512-E0tnaL4fr+qkdCNxJ+Xd0yM31UwMkQje76fsDVBBUCoGOUPexu2VDUYHL8P4CwV+zMvWw6nlRw19OnRKmYAJpw== + +"@vue/compiler-core@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.45.tgz#d9311207d96f6ebd5f4660be129fb99f01ddb41b" + integrity sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A== + dependencies: + "@babel/parser" "^7.16.4" + "@vue/shared" "3.2.45" + estree-walker "^2.0.2" + source-map "^0.6.1" + +"@vue/compiler-dom@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz#c43cc15e50da62ecc16a42f2622d25dc5fd97dce" + integrity sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw== + dependencies: + "@vue/compiler-core" "3.2.45" + "@vue/shared" "3.2.45" + +"@vue/compiler-sfc@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz#7f7989cc04ec9e7c55acd406827a2c4e96872c70" + integrity sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q== + dependencies: + "@babel/parser" "^7.16.4" + "@vue/compiler-core" "3.2.45" + "@vue/compiler-dom" "3.2.45" + "@vue/compiler-ssr" "3.2.45" + "@vue/reactivity-transform" "3.2.45" + "@vue/shared" "3.2.45" + estree-walker "^2.0.2" + magic-string "^0.25.7" + postcss "^8.1.10" + source-map "^0.6.1" + +"@vue/compiler-ssr@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz#bd20604b6e64ea15344d5b6278c4141191c983b2" + integrity sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ== + dependencies: + "@vue/compiler-dom" "3.2.45" + "@vue/shared" "3.2.45" + +"@vue/devtools-api@^6.2.1": + version "6.4.5" + resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.4.5.tgz#d54e844c1adbb1e677c81c665ecef1a2b4bb8380" + integrity sha512-JD5fcdIuFxU4fQyXUu3w2KpAJHzTVdN+p4iOX2lMWSHMOoQdMAcpFLZzm9Z/2nmsoZ1a96QEhZ26e50xLBsgOQ== + +"@vue/reactivity-transform@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz#07ac83b8138550c83dfb50db43cde1e0e5e8124d" + integrity sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ== + dependencies: + "@babel/parser" "^7.16.4" + "@vue/compiler-core" "3.2.45" + "@vue/shared" "3.2.45" + estree-walker "^2.0.2" + magic-string "^0.25.7" + +"@vue/reactivity@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.2.45.tgz#412a45b574de601be5a4a5d9a8cbd4dee4662ff0" + integrity sha512-PRvhCcQcyEVohW0P8iQ7HDcIOXRjZfAsOds3N99X/Dzewy8TVhTCT4uXpAHfoKjVTJRA0O0K+6QNkDIZAxNi3A== + dependencies: + "@vue/shared" "3.2.45" + +"@vue/runtime-core@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.2.45.tgz#7ad7ef9b2519d41062a30c6fa001ec43ac549c7f" + integrity sha512-gzJiTA3f74cgARptqzYswmoQx0fIA+gGYBfokYVhF8YSXjWTUA2SngRzZRku2HbGbjzB6LBYSbKGIaK8IW+s0A== + dependencies: + "@vue/reactivity" "3.2.45" + "@vue/shared" "3.2.45" + +"@vue/runtime-dom@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz#1a2ef6ee2ad876206fbbe2a884554bba2d0faf59" + integrity sha512-cy88YpfP5Ue2bDBbj75Cb4bIEZUMM/mAkDMfqDTpUYVgTf/kuQ2VQ8LebuZ8k6EudgH8pYhsGWHlY0lcxlvTwA== + dependencies: + "@vue/runtime-core" "3.2.45" + "@vue/shared" "3.2.45" + csstype "^2.6.8" + +"@vue/server-renderer@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.2.45.tgz#ca9306a0c12b0530a1a250e44f4a0abac6b81f3f" + integrity sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g== + dependencies: + "@vue/compiler-ssr" "3.2.45" + "@vue/shared" "3.2.45" + +"@vue/shared@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.45.tgz#a3fffa7489eafff38d984e23d0236e230c818bc2" + integrity sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg== + +"@vueuse/core@^9.1.0": + version "9.5.0" + resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-9.5.0.tgz#6726e952e8f92b465457d3bc95deb385aacd9a41" + integrity sha512-6GsWBsJHEb3sYw15mbLrcbslAVY45pkzjJYTKYKCXv88z7srAF0VEW0q+oXKsl58tCbqooplInahXFg8Yo1m4w== + dependencies: + "@types/web-bluetooth" "^0.0.16" + "@vueuse/metadata" "9.5.0" + "@vueuse/shared" "9.5.0" + vue-demi "*" + +"@vueuse/metadata@9.5.0": + version "9.5.0" + resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-9.5.0.tgz#b01c84230261ddee4d439ae5d9c21343dc5ae565" + integrity sha512-4M1AyPZmIv41pym+K5+4wup3bKuYebbH8w8BROY1hmT7rIwcyS4tEL+UsGz0Hiu1FCOxcoBrwtAizc0YmBJjyQ== + +"@vueuse/shared@9.5.0": + version "9.5.0" + resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-9.5.0.tgz#f5306548af0dc9f2b3a0d4da74e62bfdd6211241" + integrity sha512-HnnCWU1Vg9CVWRCcI8ohDKDRB2Sc4bTgT1XAIaoLSfVHHn+TKbrox6pd3klCSw4UDxkhDfOk8cAdcK+Z5KleCA== + dependencies: + vue-demi "*" + +algoliasearch@^4.0.0: + version "4.14.2" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.14.2.tgz#63f142583bfc3a9bd3cd4a1b098bf6fe58e56f6c" + integrity sha512-ngbEQonGEmf8dyEh5f+uOIihv4176dgbuOZspiuhmTTBRBuzWu3KCGHre6uHj5YyuC7pNvQGzB6ZNJyZi0z+Sg== + dependencies: + "@algolia/cache-browser-local-storage" "4.14.2" + "@algolia/cache-common" "4.14.2" + "@algolia/cache-in-memory" "4.14.2" + "@algolia/client-account" "4.14.2" + "@algolia/client-analytics" "4.14.2" + "@algolia/client-common" "4.14.2" + "@algolia/client-personalization" "4.14.2" + "@algolia/client-search" "4.14.2" + "@algolia/logger-common" "4.14.2" + "@algolia/logger-console" "4.14.2" + "@algolia/requester-browser-xhr" "4.14.2" + "@algolia/requester-common" "4.14.2" + "@algolia/requester-node-http" "4.14.2" + "@algolia/transporter" "4.14.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +body-scroll-lock@^4.0.0-beta.0: + version "4.0.0-beta.0" + resolved "https://registry.yarnpkg.com/body-scroll-lock/-/body-scroll-lock-4.0.0-beta.0.tgz#4f78789d10e6388115c0460cd6d7d4dd2bbc4f7e" + integrity sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ== + +csstype@^2.6.8: + version "2.6.21" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.21.tgz#2efb85b7cc55c80017c66a5ad7cbd931fda3a90e" + integrity sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w== + +entities@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4" + integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q== + +esbuild-android-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.15.13.tgz#5f25864055dbd62e250f360b38b4c382224063af" + integrity sha512-yRorukXBlokwTip+Sy4MYskLhJsO0Kn0/Fj43s1krVblfwP+hMD37a4Wmg139GEsMLl+vh8WXp2mq/cTA9J97g== + +esbuild-android-arm64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.15.13.tgz#d8820f999314efbe8e0f050653a99ff2da632b0f" + integrity sha512-TKzyymLD6PiVeyYa4c5wdPw87BeAiTXNtK6amWUcXZxkV51gOk5u5qzmDaYSwiWeecSNHamFsaFjLoi32QR5/w== + +esbuild-darwin-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.15.13.tgz#99ae7fdaa43947b06cd9d1a1c3c2c9f245d81fd0" + integrity sha512-WAx7c2DaOS6CrRcoYCgXgkXDliLnFv3pQLV6GeW1YcGEZq2Gnl8s9Pg7ahValZkpOa0iE/ojRVQ87sbUhF1Cbg== + +esbuild-darwin-arm64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.13.tgz#bafa1814354ad1a47adcad73de416130ef7f55e3" + integrity sha512-U6jFsPfSSxC3V1CLiQqwvDuj3GGrtQNB3P3nNC3+q99EKf94UGpsG9l4CQ83zBs1NHrk1rtCSYT0+KfK5LsD8A== + +esbuild-freebsd-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.13.tgz#84ef85535c5cc38b627d1c5115623b088d1de161" + integrity sha512-whItJgDiOXaDG/idy75qqevIpZjnReZkMGCgQaBWZuKHoElDJC1rh7MpoUgupMcdfOd+PgdEwNQW9DAE6i8wyA== + +esbuild-freebsd-arm64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.13.tgz#033f21de434ec8e0c478054b119af8056763c2d8" + integrity sha512-6pCSWt8mLUbPtygv7cufV0sZLeylaMwS5Fznj6Rsx9G2AJJsAjQ9ifA+0rQEIg7DwJmi9it+WjzNTEAzzdoM3Q== + +esbuild-linux-32@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.15.13.tgz#54290ea8035cba0faf1791ce9ae6693005512535" + integrity sha512-VbZdWOEdrJiYApm2kkxoTOgsoCO1krBZ3quHdYk3g3ivWaMwNIVPIfEE0f0XQQ0u5pJtBsnk2/7OPiCFIPOe/w== + +esbuild-linux-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.15.13.tgz#4264249281ea388ead948614b57fb1ddf7779a2c" + integrity sha512-rXmnArVNio6yANSqDQlIO4WiP+Cv7+9EuAHNnag7rByAqFVuRusLbGi2697A5dFPNXoO//IiogVwi3AdcfPC6A== + +esbuild-linux-arm64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.13.tgz#9323c333924f97a02bdd2ae8912b36298acb312d" + integrity sha512-alEMGU4Z+d17U7KQQw2IV8tQycO6T+rOrgW8OS22Ua25x6kHxoG6Ngry6Aq6uranC+pNWNMB6aHFPh7aTQdORQ== + +esbuild-linux-arm@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.15.13.tgz#b407f47b3ae721fe4e00e19e9f19289bef87a111" + integrity sha512-Ac6LpfmJO8WhCMQmO253xX2IU2B3wPDbl4IvR0hnqcPrdfCaUa2j/lLMGTjmQ4W5JsJIdHEdW12dG8lFS0MbxQ== + +esbuild-linux-mips64le@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.13.tgz#bdf905aae5c0bcaa8f83567fe4c4c1bdc1f14447" + integrity sha512-47PgmyYEu+yN5rD/MbwS6DxP2FSGPo4Uxg5LwIdxTiyGC2XKwHhHyW7YYEDlSuXLQXEdTO7mYe8zQ74czP7W8A== + +esbuild-linux-ppc64le@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.13.tgz#2911eae1c90ff58a3bd3259cb557235df25aa3b4" + integrity sha512-z6n28h2+PC1Ayle9DjKoBRcx/4cxHoOa2e689e2aDJSaKug3jXcQw7mM+GLg+9ydYoNzj8QxNL8ihOv/OnezhA== + +esbuild-linux-riscv64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.13.tgz#1837c660be12b1d20d2a29c7189ea703f93e9265" + integrity sha512-+Lu4zuuXuQhgLUGyZloWCqTslcCAjMZH1k3Xc9MSEJEpEFdpsSU0sRDXAnk18FKOfEjhu4YMGaykx9xjtpA6ow== + +esbuild-linux-s390x@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.13.tgz#d52880ece229d1bd10b2d936b792914ffb07c7fc" + integrity sha512-BMeXRljruf7J0TMxD5CIXS65y7puiZkAh+s4XFV9qy16SxOuMhxhVIXYLnbdfLrsYGFzx7U9mcdpFWkkvy/Uag== + +esbuild-netbsd-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.13.tgz#de14da46f1d20352b43e15d97a80a8788275e6ed" + integrity sha512-EHj9QZOTel581JPj7UO3xYbltFTYnHy+SIqJVq6yd3KkCrsHRbapiPb0Lx3EOOtybBEE9EyqbmfW1NlSDsSzvQ== + +esbuild-openbsd-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.13.tgz#45e8a5fd74d92ad8f732c43582369c7990f5a0ac" + integrity sha512-nkuDlIjF/sfUhfx8SKq0+U+Fgx5K9JcPq1mUodnxI0x4kBdCv46rOGWbuJ6eof2n3wdoCLccOoJAbg9ba/bT2w== + +esbuild-sunos-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.15.13.tgz#f646ac3da7aac521ee0fdbc192750c87da697806" + integrity sha512-jVeu2GfxZQ++6lRdY43CS0Tm/r4WuQQ0Pdsrxbw+aOrHQPHV0+LNOLnvbN28M7BSUGnJnHkHm2HozGgNGyeIRw== + +esbuild-windows-32@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.15.13.tgz#fb4fe77c7591418880b3c9b5900adc4c094f2401" + integrity sha512-XoF2iBf0wnqo16SDq+aDGi/+QbaLFpkiRarPVssMh9KYbFNCqPLlGAWwDvxEVz+ywX6Si37J2AKm+AXq1kC0JA== + +esbuild-windows-64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.15.13.tgz#1fca8c654392c0c31bdaaed168becfea80e20660" + integrity sha512-Et6htEfGycjDrtqb2ng6nT+baesZPYQIW+HUEHK4D1ncggNrDNk3yoboYQ5KtiVrw/JaDMNttz8rrPubV/fvPQ== + +esbuild-windows-arm64@0.15.13: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.13.tgz#4ffd01b6b2888603f1584a2fe96b1f6a6f2b3dd8" + integrity sha512-3bv7tqntThQC9SWLRouMDmZnlOukBhOCTlkzNqzGCmrkCJI7io5LLjwJBOVY6kOUlIvdxbooNZwjtBvj+7uuVg== + +esbuild@^0.15.9: + version "0.15.13" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.15.13.tgz#7293480038feb2bafa91d3f6a20edab3ba6c108a" + integrity sha512-Cu3SC84oyzzhrK/YyN4iEVy2jZu5t2fz66HEOShHURcjSkOSAVL8C/gfUT+lDJxkVHpg8GZ10DD0rMHRPqMFaQ== + optionalDependencies: + "@esbuild/android-arm" "0.15.13" + "@esbuild/linux-loong64" "0.15.13" + esbuild-android-64 "0.15.13" + esbuild-android-arm64 "0.15.13" + esbuild-darwin-64 "0.15.13" + esbuild-darwin-arm64 "0.15.13" + esbuild-freebsd-64 "0.15.13" + esbuild-freebsd-arm64 "0.15.13" + esbuild-linux-32 "0.15.13" + esbuild-linux-64 "0.15.13" + esbuild-linux-arm "0.15.13" + esbuild-linux-arm64 "0.15.13" + esbuild-linux-mips64le "0.15.13" + esbuild-linux-ppc64le "0.15.13" + esbuild-linux-riscv64 "0.15.13" + esbuild-linux-s390x "0.15.13" + esbuild-netbsd-64 "0.15.13" + esbuild-openbsd-64 "0.15.13" + esbuild-sunos-64 "0.15.13" + esbuild-windows-32 "0.15.13" + esbuild-windows-64 "0.15.13" + esbuild-windows-arm64 "0.15.13" + +estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +flexsearch@^0.7.31: + version "0.7.31" + resolved "https://registry.yarnpkg.com/flexsearch/-/flexsearch-0.7.31.tgz#065d4110b95083110b9b6c762a71a77cc52e4702" + integrity sha512-XGozTsMPYkm+6b5QL3Z9wQcJjNYxp0CYn3U1gO7dwD6PAqU1SVWZxI9CCg3z+ml3YfqdPnrBehaBrnH2AGKbNA== + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +is-core-module@^2.9.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" + integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== + dependencies: + has "^1.0.3" + +jsonc-parser@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" + integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== + +linkify-it@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-4.0.1.tgz#01f1d5e508190d06669982ba31a7d9f56a5751ec" + integrity sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw== + dependencies: + uc.micro "^1.0.1" + +magic-string@^0.25.7: + version "0.25.9" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" + integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== + dependencies: + sourcemap-codec "^1.4.8" + +markdown-it@^13.0.1: + version "13.0.1" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-13.0.1.tgz#c6ecc431cacf1a5da531423fc6a42807814af430" + integrity sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q== + dependencies: + argparse "^2.0.1" + entities "~3.0.1" + linkify-it "^4.0.1" + mdurl "^1.0.1" + uc.micro "^1.0.5" + +mdurl@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g== + +nanoid@^3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" + integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +postcss@^8.1.10, postcss@^8.4.18: + version "8.4.19" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.19.tgz#61178e2add236b17351897c8bcc0b4c8ecab56fc" + integrity sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA== + dependencies: + nanoid "^3.3.4" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +preact@^10.0.0: + version "10.11.2" + resolved "https://registry.yarnpkg.com/preact/-/preact-10.11.2.tgz#e43f2a2f2985dedb426bb4c765b7bb037734f8a8" + integrity sha512-skAwGDFmgxhq1DCBHke/9e12ewkhc7WYwjuhHB8HHS8zkdtITXLRmUMTeol2ldxvLwYtwbFeifZ9uDDWuyL4Iw== + +resolve@^1.22.1: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +rollup@^2.79.1: + version "2.79.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7" + integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw== + optionalDependencies: + fsevents "~2.3.2" + +shiki@^0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.11.1.tgz#df0f719e7ab592c484d8b73ec10e215a503ab8cc" + integrity sha512-EugY9VASFuDqOexOgXR18ZV+TbFrQHeCpEYaXamO+SZlsnT/2LxuLBX25GGtIrwaEVFXUAbUQ601SWE2rMwWHA== + dependencies: + jsonc-parser "^3.0.0" + vscode-oniguruma "^1.6.1" + vscode-textmate "^6.0.0" + +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sourcemap-codec@^1.4.8: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +uc.micro@^1.0.1, uc.micro@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" + integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== + +vite@^3.0.8: + version "3.2.3" + resolved "https://registry.yarnpkg.com/vite/-/vite-3.2.3.tgz#7a68d9ef73eff7ee6dc0718ad3507adfc86944a7" + integrity sha512-h8jl1TZ76eGs3o2dIBSsvXDLb1m/Ec1iej8ZMdz+PsaFUsftZeWe2CZOI3qogEsMNaywc17gu0q6cQDzh/weCQ== + dependencies: + esbuild "^0.15.9" + postcss "^8.4.18" + resolve "^1.22.1" + rollup "^2.79.1" + optionalDependencies: + fsevents "~2.3.2" + +vitepress-plugin-search@^1.0.4-alpha.15: + version "1.0.4-alpha.15" + resolved "https://registry.yarnpkg.com/vitepress-plugin-search/-/vitepress-plugin-search-1.0.4-alpha.15.tgz#c26575a7b5f1eaa087835e702a9b93902a2d7948" + integrity sha512-Ef/VkhTVYlECVI0H9Ck6745UNPfYFppAqnlxVSMJXdxP2vjOZ5TYNczlTTQ2p9dh16MFw/IurbL1/GrG4nXdNw== + dependencies: + "@types/flexsearch" "^0.7.3" + "@types/markdown-it" "^12.2.3" + markdown-it "^13.0.1" + +vitepress@1.0.0-alpha.13: + version "1.0.0-alpha.13" + resolved "https://registry.yarnpkg.com/vitepress/-/vitepress-1.0.0-alpha.13.tgz#dfc0af0c624fbb81496ced9095b3f5ecb7a3a8ce" + integrity sha512-gCbKb+6o0g5wHt2yyqBPk7FcvrB+MfwGtg1JMS5p99GTQR87l3b7symCl8o1ecv7MDXwJ2mPB8ZrYNLnQAJxLQ== + dependencies: + "@docsearch/css" "^3.2.1" + "@docsearch/js" "^3.2.1" + "@vitejs/plugin-vue" "^3.0.3" + "@vue/devtools-api" "^6.2.1" + "@vueuse/core" "^9.1.0" + body-scroll-lock "^4.0.0-beta.0" + shiki "^0.11.1" + vite "^3.0.8" + vue "^3.2.37" + +vscode-oniguruma@^1.6.1: + version "1.6.2" + resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz#aeb9771a2f1dbfc9083c8a7fdd9cccaa3f386607" + integrity sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA== + +vscode-textmate@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-6.0.0.tgz#a3777197235036814ac9a92451492f2748589210" + integrity sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ== + +vue-demi@*: + version "0.13.11" + resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.13.11.tgz#7d90369bdae8974d87b1973564ad390182410d99" + integrity sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A== + +vue@^3.2.37, vue@^3.2.45: + version "3.2.45" + resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.45.tgz#94a116784447eb7dbd892167784619fef379b3c8" + integrity sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA== + dependencies: + "@vue/compiler-dom" "3.2.45" + "@vue/compiler-sfc" "3.2.45" + "@vue/runtime-dom" "3.2.45" + "@vue/server-renderer" "3.2.45" + "@vue/shared" "3.2.45" diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..162676cb --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + + Preamble + +The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + +The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + +Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + +A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + +The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + +An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + +The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + +0. Definitions. + +"This License" refers to version 3 of the GNU Affero General Public License. + +"Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + +"The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + +To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + +A "covered work" means either the unmodified Program or a work based +on the Program. + +To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + +To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + +An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +1. Source Code. + +The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + +A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + +The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + +The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + +The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + +The Corresponding Source for a work in source code form is that +same work. + +2. Basic Permissions. + +All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + +3. Protecting Users' Legal Rights From Anti-Circumvention Law. + +No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + +When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + +4. Conveying Verbatim Copies. + +You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + +5. Conveying Modified Source Versions. + +You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + +A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + +6. Conveying Non-Source Forms. + +You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + +A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + +"Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + +If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + +The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + +7. Additional Terms. + +"Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + +All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + +8. Termination. + +You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + +However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + +9. Acceptance Not Required for Having Copies. + +You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + +10. Automatic Licensing of Downstream Recipients. + +Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + +An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + +11. Patents. + +A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + +A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + +In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + +If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + +A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + +12. No Surrender of Others' Freedom. + +If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + +13. Remote Network Interaction; Use with the GNU General Public License. + +Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + +Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + +14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + +If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + +Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + +15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + +17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + +You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/README.md b/README.md new file mode 100644 index 00000000..8b2af4f2 --- /dev/null +++ b/README.md @@ -0,0 +1,72 @@ +![](https://twake.app/medias/Twake-long.png) + +# Twake - The Open Digital Workplace + +![update-saas-backend](https://github.com/TwakeApp/Twake/workflows/update-saas-backend/badge.svg?branch=main&style=flat) +![update-saas-frontend](https://github.com/TwakeApp/Twake/workflows/update-saas-frontend/badge.svg?branch=main&style=flat) +![backend-build](https://github.com/TwakeApp/Twake/workflows/backend-build/badge.svg?branch=main&style=flat) +[![docker-build](https://github.com/Twake/Twake/actions/workflows/docker.yml/badge.svg)](https://github.com/Twake/Twake/actions/workflows/docker.yml) + +![Docker](https://img.shields.io/docker/pulls/twaketech/twake-node?style=flat) +[![Docs](https://img.shields.io/badge/docs-up--to--date-blueviolet?style=flat)](https://doc.twake.app) +[![Community](https://img.shields.io/badge/community-awesome-brightgreen?style=flat)](https://community.twake.app) +[![Twitter](https://img.shields.io/badge/twitter-%40twake-blue?style=flat)](https://twitter.com/twake) [![Join the chat at https://gitter.im/linagora/Twake](https://badges.gitter.im/linagora/Twake.svg)](https://gitter.im/linagora/Twake?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +Twake is a secure open source collaboration platform to improve organizational productivity. +Twake offers all the features for collaboration : + +- Team chat +- File Storage +- Team Calendar +- Task Management +- Video call and conferencing +- Real time document collaboration + + + +## Demo + +You can try Twake in SaaS. + +Or run your own local Twake instance with : + +```bash +cd twake +export COMPOSE_FILE=docker-compose.onpremise.yml +docker compose up -d +``` + +Twake will be running on http//localhost and by default redirect to https and uses a self-signed certificate. If you want to run http only then set SSL_CERTS=none at docker-compose.yml + +## Documentation + +Twake's documentation can be found at [doc.twake.app](https://doc.twake.app) + +More information at twake.app : [twake.app](https://twake.app) + +## Community + +The Twake community is gathered on the forum: [community.twake.app](https://community.twake.app). + +If you have any questions or suggestions, we will be happy to answer them. + +### Translations + +We use [Weblate](https://hosted.weblate.org/projects/twake/) for translation management. Create an account on weblate to improve our Twake internationalisation. + +## How to contribute + +Everyone can contribute at their own level, even if they only give a few minutes of their time. Whatever you do, your help is very valuable. Only thanks to you Twake can be a powerful software. Check out how you can help [twake.app/en/how-to-contribute/](https://twake.app/en/how-to-contribute/) + +## Manual install of Twake + +Install Twake on your machine with docker-compose using the install documentation here : +[linagora.github.io/Twake/onprem/installation.html](https://linagora.github.io/Twake/onprem/installation.html) + +`cd twake; docker-compose -f docker-compose.onpremise.mongo.yml up -d` + +Twake will be available on port 3000. + +## License + +Twake is licensed under [Affero GPL v3 with additional terms](https://github.com/TwakeApp/Twake/blob/main/LICENSE.md) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..d1dac476 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,13 @@ +# Security Policy + +## Supported Versions + +Only the latest version is supported with security updates as of today (September, 2021). + +## Reporting a Vulnerability + +Please contact us at romaric@twakeapp.com . + +## Tools + +Twake uses Snyk to ensure we have the latests and most secure library and docker images. diff --git a/changelog.md b/changelog.md new file mode 100644 index 00000000..6b3f2fdf --- /dev/null +++ b/changelog.md @@ -0,0 +1,649 @@ +# Twake 2023.Q1.1223 + +- New Drive is here and migrared to Node! πŸ“πŸŽ‰ +- Drive now support advanced right management πŸŽ› +- OnlyOffice plugins is also now ready for Twake new Drive +- Minor fixes + +# Twake 2022.Q4.1143 + +- Ability to invite automatically any user with same business email βœ‰οΈ +- Workspace invitation improved 🎨 +- Channel menu improved 🎨 +- Fixes on Documents (for SaaS) πŸ“ +- Forward messages to another channel ‴️ +- Set a channel as read-only πŸ‘€ + +# Twake 2022.Q4.1120 + +- Message delivery status 🟒 +- New quote-reply feature ‴️ +- Notification when someone react to your message πŸ‘ +- New file preview and medias gallery with navigation, caption, and message context πŸ•Ά +- New badge notification system (mention, unread, etc) +- Digest notifications by email βœ‰οΈ +- Ability to customize notification sound +- Improved user live status indicator +- See when user was last active on Twake ⏰ +- Big simplification of backend πŸ‘©β€πŸ’» + +# Twake 2022.Q3.1065 + +- File and medias channel gallery view 🎞 +- New channel members invitation and management modal βš™οΈ +- Fixed connection status of users 🟒 +- New messages search feature on mobile πŸ”Ž +- Fixed bugs and translation #2425 #2424 #2420 #2442 #2436 #2435 + +# Twake 2022.Q3.1050 + +- Open desktop app if present in the system +- Preview public channels before to join them +- Updated [Search anything on Twake](https://github.com/linagora/Twake/issues/1710) +- Started using Tailwindcss for future new design +- Started using Storybooks + +# Twake 2022.Q2.975 + +### Backend + +- [Implemented the list of uploaded in our backend](https://github.com/linagora/Twake/issues/2127) +- [Jump to a message](https://github.com/linagora/Twake/issues/1926) +- [Search for messages](https://github.com/linagora/Twake/issues/1710) +- Generate links previews +- Multiple bug fixes + +### Bug fixed + +- [Fixed thumbnail rotatation when uploaded from mobile](https://github.com/linagora/Twake/issues/2111) +- [Scrolling message feed isn't smooth](https://github.com/linagora/Twake/issues/2039) +- [Position of Close (x) buttons are not consistent](https://github.com/linagora/Twake/issues/2031) +- [Mention user by any namu or identifier](https://github.com/linagora/Twake/issues/2042) +- [Update workspace name reset the logo](https://github.com/linagora/Twake/issues/1950) +- [Empty channel isn't working](https://github.com/linagora/Twake/issues/2146) +- [On Twake desktop I have notifications only inside Twake window and when it's collapsed I don't see them](https://github.com/linagora/Twake/issues/2043) +- [Windows notification has no redirection](https://github.com/linagora/Twake/issues/125) +- [Clicking on push notification does not open the right message](https://github.com/linagora/Twake/issues/396) + +# Twake 2022.Q2.930 + +### Backend + +- Refactoring of how we get services in our backend + +### Bug fixed + +- https://github.com/linagora/Twake/pull/2092 + +# Twake 2022.Q2.910 + +### Messages + +- Copy paste images to message editor fixed +- Large files preview is now available +- Mentions are back in messages +- Giphy, n8n and Jitsi are back + +### General + +- New workspaces parameters page view +- Ability to create and manage plugins from Twake + +### Backend + +- New backend routes to get files and pinned messages of a channel +- New search messages routes + +### Bug fixed + +- Fixed thumbnail generation +- https://github.com/linagora/Twake/issues/2083 +- https://github.com/linagora/Twake/issues/2091 +- https://github.com/linagora/Twake/issues/2095 +- https://github.com/linagora/Twake/issues/2037 +- https://github.com/linagora/Twake/issues/2036 +- https://github.com/linagora/Twake/issues/1918 +- https://github.com/linagora/Twake/issues/2102 + +# Twake 2022.Q1.890 + +### Messages + +- Shows that the last message was deleted on mobile channel list view +- Now we can cancel failed file uploads +- Add spell check to message editor + +### General + +- Save the user last visited companies to open them again after logout +- Fixed magic links +- Show a popup to decide to continue on web or open the mobile app +- Notice users that the company reached the maximum number of users +- Fixed some issues with workspace invitation +- Minor bugs fixed + +# Twake 2022.Q1.874 + +### Messages + +- Faster loading of message feed +- Fix message input issues + +### General + +- Reduce magic links invite urls +- Fix guest popup not visible on paid plans +- Fix company owners and admins not able to manage workspaces +- Fix channels members counters +- Migrate channels to recoil state management for more stable channels (favorite, rename, create, join etc) + +# Twake 2021.Q4.860 + +### Messages + +- Improved message top right menu +- Fixed message sending / edition / reaction / pinned etc, now instant ⚑️ +- User availability indicator 🟒 +- User is writing indicator + +### Workspace parameters + +- Improved integrations management page 🧹 +- Improved workspace users management page 🧹 +- Improved workspace preferences management page 🧹 + +### General + +- A lot of bug fixed, more to come on the 22 of January 🐞 +- Improved Twake loading time (still in progress) ⏰ +- New state management ( recoiljs.org ) on everything except channels and channels members +- Everything except Drive Tasks and Calendar was migrated to node backend 🧹 +- Twake is now working with a simplified docker-compose with only node + mongodb. Note that this works only with messages (no Drive, Calendar or Tasks yet) πŸš€ + +# Twake 2021.Q3.640 + +### Messages + +- New message WYSIWYG editor 🎨 +- Added limit to message size and to number of attached files +- Deleted messages are now showed as "Deleted" but don't disappear +- Limit number of users in the same direct channel +- You can now set multiple reactions to a single message πŸŒŸπŸ‘πŸ”₯ + +### General + +- Twake is now on [Weblate](https://hosted.weblate.org/projects/twake/) 🌎 +- Multiple bugs fixes + +# Twake 2021.Q2.550 + +### Messages + +- Fix missing notification when a first direct channel message is sent +- Now using the new nodejs backend (need to run `sudo docker-compose run node node bin/twake-cli migration message` after update). PHP endpoints (`/ajax/discussion/...`) are still working but are depreciated. + +### General + +- Update oidc login workflow for Console connectivity + +### Technical changes + +- Migrated users, companies, workspaces endpoints to nodejs (frontend not yet using theses endpoints) +- Migrated file service to nodejs (frontend not yet using theses endpoints) +- Migrated messages service to nodejs (frontend not yet using theses endpoints) +- Created Search, Storage and PushNotification internal services + +# Twake 2021.Q2.505 + +### Messages + +- Performance improvement and bug fixing +- Ability to invite external users as guest directly in channel + +# Twake 2021.Q2.481 + +### Messages + +- Fix a bug making too many desktop notifications at the same time. +- Fix a bug when sending a message using the send button, message now disapear as expected. +- Fix the "hidden notification" button that can be stuck on top or bottom of the channel list. + +### Console + +- Now if you change your language on Console it will affect Twake accordingly. +- Better onboarding of new users: automatic channel selection, add collaborators button, invite collaborators from Twake using console management app and more. +- Polishing console migration script, previous Twake users will soon uses the Console. + +# Twake 2021.Q1.434 + +### Messages + +- Default channels now available 🌟 You can set a channel as default, new users invited in workspace will be automatically added to this channel. + +### General + +- Console onboarding update (soon open source!) +- Multiple bug fixes + +# Twake 2021.Q1.401 + +### General + +- First elements of Twake new design, welcome to blue #3840f7 +- Cmd+K / Ctrl+K now working on all channels types (direct and workspace channels) +- Multiple bug fixes + +# Twake 2021.Q1.385 + +### General + +- Twake is on OVH! OVH is a french infrastructure provider, it is a big step for us. Good bye Amazon πŸ‘‹ +- Started migration to NodeJS from PHP (30%) for faster and lighter server, compatibility with MongoDB and more! +- Move to socket.io from socketcluster for more robust websockets. +- We are now compatible with the Twake Console. Twake account and group management will be soon fully replaced by the Console. +- Big performances upgrades, we fixed a lot of memory leaks in the last weeks. + +### Channels + +- Ability to join and leave channels. +- Channel activity messages. +- Access and rights for channel creation updated (now everyone can create channels). +- Favorite direct channels, now you can put your direct channels in favorites too. +- Channel groups are back! Yes, you can again create groups of channels to organize your workspace. +- Channel members list: see who is in a channel and manage members + +### Notifications + +- Now you only receive badge notification for threads you follow and when you are mentionned. +- Other messages in channel will update the channel text to bold. + +### Drive + +- Ability to preview coding files and markdown files + +# Twake 2020.Q4.137 + +### General + +- Twake is on OVH! OVH is a french infrastructure provider, it is a big step for us. Good bye Amazon πŸ‘‹ +- Started migration to NodeJS from PHP (30%) for faster and lighter server, compatibility with MongoDB and more! +- Move to socket.io from socketcluster for more robust websockets. +- We are now compatible with the Twake Console. Twake account and group management will be soon fully replaced by the Console. +- Big performances upgrades, we fixed a lot of memory leaks in the last weeks. + +### Channels + +- Ability to join and leave channels. +- Channel activity messages. +- Access and rights for channel creation updated (now everyone can create channels). +- Favorite direct channels, now you can put your direct channels in favorites too. +- Channel groups are back! Yes, you can again create groups of channels to organize your workspace. +- Channel members list: see who is in a channel and manage members + +### Notifications + +- Now you only receive badge notification for threads you follow and when you are mentionned. +- Other messages in channel will update the channel text to bold. + +### Drive + +- Ability to preview coding files and markdown files + +# Twake 2020.Q3.107 + +## Changelogs + +### General + +- New apple emoji set +- Fix unwanted deconnections and missing notifications +- Fix autocompletion glitches + +### Messages + +- New message feed design +- Improve performance in messages list and when getting previous messages +- Ability to prepare files before sending them with a message +- Ability to add files in a thread +- Allow ctrl-v documents in messages +- Ability to get a link to a specific thread +- Change formatting rules to be markdown compatible + +# Twake 2020.Q3.70 + +## Changelogs + +### General + +- Workspace members search and list improvement + +### Messages + +- New notifications parameters per channels (@mention, @all or nothing) +- Channel description header + +# Twake v1.2.2 + +## Changelogs + +### General + +- Added Russian translations +- Improve missing translations +- Improve design with smaller components +- Simplier installation procedure +- OIDC auth mode for On-Premise installations +- Brand global style and logos customization +- New emoji style on Apple devices + +### Messages + +- Side view for threads +- Shortcuts for last message edition +- Show only relevant private channels + +### Connectors + +- Built-in connectors, no second server required +- LinShare document selection connector for messages +- Jitsi select meeting name + +# Twake v1.2.1 + +## Changelogs + +### General + +- Full new design +- External users +- Task advanced search +- Event advanced search +- Files advanced search +- Message advanced search +- Export your company +- Quick search and chanel change +- Tabs system + +### Tasks + +- Improved Tasks + +### Dive + +- Upload for files over 100mo +- Link-files +- Files as tab +- Public directory/file link +- Files versioning + +### Calendar + +- Improved calendar + +### Mobile + +- Drive on native mobile app +- Tabs on mobile +- Tasks on mobile (v1) +- Messages on native mobile app + +### Connectors + +- New public API and connectors manager +- Google Drive Sync +- Zapier integration enabled +- Gitlab (notifications in messages) +- Github (notifications in messages) +- Webhooks +- Reminder (reminder bot) +- Simple Poll (for messages) +- Giphy +- RSS (notifications for messages) +- Jitsi (video conferencing) +- ONLYOFFICE (integrated with drive) + +## Changelogs + +### General + +- Ability to link objects of type event, task, call or file +- Apps open faster +- Ability to app any link by choosing an application manual mode +- New message modal for private messages +- Objects fields synchronisation + +### On-premise + +- Obfuscator code +- Integrate Onlyoffice in Twake core code + +# Twake v1.1.110 + +## Changelogs + +### General + +- Ability to link objects of type event, task, call or file +- Apps open faster +- Ability to app any link by choosing an application manual mode +- New message modal for private messages +- Objects fields synchronisation + +### On-premise + +- Obfuscator code +- Integrate Onlyoffice in Twake core code + +# Twake v1.1.100 + +## Changelogs + +### Messages + +- Highlight new messages + +### Tasks + +- Add Tasks app to manage tasks and projects + +### Calendar + +- Ability to auto import ics each 15 minutes +- Team members calendars + +### General + +- Team activity + +# Twake v1.1.001 + +## Changelogs + +### Calendar + +- Add export link + +### Drive + +- Add files versions + +### General + +- Change private workspace conception +- Add navigation buttons for external apps + +# Twake v1.1 + +## Changelogs + +### Messages + +- New app with better performances +- Remove temporarly subjects +- New respond button + +### Apps + +- Ability to integrate external apps + +### Calendar + +- Ability to import and export ics +- Ability to subscribe to calendar +- Mini google map for event location + +### Drive + +- Ability to subscribe to directory +- Async preview generation + +### General + +- Remove bootstrap and use ant.design +- New workspace start page +- New left bar with last messages and last notification +- New icons +- New subscribe popups +- Ability to hide workspaces, make workspaces favorite +- Ability to search in all workspaces +- Show who is with you on the same page +- New responsive UI for all apps +- New activity center for all apps + +# Twake-react v1.0.310 + +## Changelogs + +### Messages + +- Fix remove and add streams +- Fix update stream badge + +### Apps + +- Calendar backend + +### General + +- Managers system +- Group workspace unique name and identifier + +# Twake v1.0.300 + +## Changelogs + +### Messages + +- Repear notification system +- New push notification separated server +- Fix error creating subjects + +### Apps + +- Messages modules apps +- Marketplace of apps +- Group apps management +- Add Giphy app + +### General + +- Right and levels system and management + +# Twake v1.0.200 + +## Changelogs + +### Messages + +- Highlight new messages +- Add badge icon for subject tab +- Fix autocomplete click, fix message link parsing + +### Apps + +- Better images preview on mobile +- PDF viewer for all devices + +### General + +- Ability to enable disable app in workspace +- New app system implemented in backend (messages modules, capables apps, defaults apps...) +- Modify UX for groups and workspaces +- Better presentation for disconnected state +- Reduce animations + +# Twake v1.0.12 + +## Changelogs + +### Messages + +- Fix auto scroll +- Fix bugs + +### Drive + +- Directory zip download + +### Administration + +- New backend for entity listing and view + +# Twake v1.0.1 + +## Changelogs + +### Messages + +- Channels groups +- Drag-n-drop anything now +- New notification system more accurate +- New hold on mobile with text selection disabled +- Mute channels + +### Workspace management + +- Fix group unique name errors + +# Twake v1.0.0 + +## Features + +### General + +- Account setup +- Multiple emails +- Notification parameters +- Private workspace +- Contacts management +- Subscribe / Login +- Password recovery +- Translated to French and English + +### Drive + +- Drag and drop multiple files to upload +- Drag and drop to move files in Drive +- Click to see preview and details +- Details include : description, name, labels +- Search file, get files by date, manage trash +- Download, open, duplicate, move in trash +- List or block views + +### Messages + +- Create, modify and remove channels +- Private and public channels +- drag and dr + +### Other apps + +- Integration of ONLYOFFICE Slides, Spreadsheet, Document +- Integration of Wekan + +### Workspace management + +- Manage wallpaper, name and logo +- Manage members +- Manage other workspaces from same group +- Create, remove, groups and workspaces diff --git a/pull_request_template.md b/pull_request_template.md new file mode 100644 index 00000000..8ed57abc --- /dev/null +++ b/pull_request_template.md @@ -0,0 +1,35 @@ + + +## Description + + +## Related Issue + + + + + +## Motivation and Context + + +## How Has This Been Tested? + + + + +## Screenshots (if appropriate): + +## Types of changes + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to change) + +## Checklist: + + +- [ ] My code follows the code style of this project. +- [ ] My change requires a change to the documentation. +- [ ] I have updated the documentation accordingly. +- [ ] I have read the **CONTRIBUTING** document. +- [ ] I have added the Signed-off-by statement at the end of my commit message. diff --git a/twake.png b/twake.png new file mode 100644 index 00000000..b3dd0ab5 Binary files /dev/null and b/twake.png differ diff --git a/twake/.dockerignore b/twake/.dockerignore new file mode 100644 index 00000000..c7beb229 --- /dev/null +++ b/twake/.dockerignore @@ -0,0 +1,4 @@ +docker-data/ +frontend/node_modules/ +frontend/build/ +docker/data/ diff --git a/twake/.gitignore b/twake/.gitignore new file mode 100644 index 00000000..0ad1d088 --- /dev/null +++ b/twake/.gitignore @@ -0,0 +1,142 @@ +### PhpStorm ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +*.DS_Store +*.dccache +.dccache + +# User-specific stuff: +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries + +# Sensitive or high-churn files: +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml + +# Gradle: +.idea/**/gradle.xml +.idea/**/libraries + +.idea/ + +# CMake +cmake-build-debug/ + +# Mongo Explorer plugin: +.idea/**/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Ruby plugin and RubyMine +/.rakeTasks + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +### PhpStorm Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/sonarlint + +### Symfony ### +# Cache and logs (Symfony2) +/app/cache/* +/app/logs/* +!app/cache/.gitkeep +!app/logs/.gitkeep + +# Email spool folder +/app/spool/* + +# Cache, session files and logs (Symfony3) +/var/cache/* +/var/logs/* +/var/sessions/* +!var/cache/.gitkeep +!var/logs/.gitkeep +!var/sessions/.gitkeep + +# Parameters +/app/config/parameters.yml +/app/config/parameters.ini + +# Managed by Composer +/app/bootstrap.php.cache +/var/bootstrap.php.cache +/bin/* +!bin/console +!bin/symfony_requirements + +# Assets and user uploads +/web/bundles/ +/web/uploads/ +/web/upload/ +/web/public/ + +# PHPUnit +/app/phpunit.xml +/phpunit.xml + +# Build data +/build/ +/builds/ + +# Backup entities generated with doctrine:generate:entities command +**/Entity/*~ + +### Symfony Patch ### +/web/css/ +/web/js/ +docker-compose.yml + +### Dev ### +/docker-data +/docker-data/* +/docker/data/* + +### Twake specific ### +/build/ +/vendor/ +/app/Ressources/DatabaseEncryption/.HaliteEncryptor.key +/app/Ressources/DatabaseEncryption/.Halite.key +/backend/websockets_server/false/ + +### AWS ### +/app/config/aws_config.yml + +### Test ### +/tests/code_coverage/ +/web/detached/* +/drive/* +/configuration diff --git a/twake/backend/core/.gitignore b/twake/backend/core/.gitignore new file mode 100755 index 00000000..086e1239 --- /dev/null +++ b/twake/backend/core/.gitignore @@ -0,0 +1,138 @@ +### PhpStorm ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +*.DS_Store + +# User-specific stuff: +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries + +# Sensitive or high-churn files: +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml + +# Gradle: +.idea/**/gradle.xml +.idea/**/libraries + +.idea/ + +# CMake +cmake-build-debug/ + +# Mongo Explorer plugin: +.idea/**/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Ruby plugin and RubyMine +/.rakeTasks + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +### PhpStorm Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/sonarlint + +### Symfony ### +# Cache and logs (Symfony2) +/app/cache/* +/app/logs/* +!app/cache/.gitkeep +!app/logs/.gitkeep + +# Email spool folder +/app/spool/* + +# Cache, session files and logs (Symfony3) +/var/cache/* +/var/logs/* +/var/sessions/* +!var/cache/.gitkeep +!var/logs/.gitkeep +!var/sessions/.gitkeep + +# Parameters +/app/config/parameters.yml +/app/config/parameters.ini + +# Managed by Composer +/app/bootstrap.php.cache +/var/bootstrap.php.cache +/bin/* +!bin/console +!bin/symfony_requirements + +# Assets and user uploads +/web/bundles/ +/web/uploads/ +/web/upload/ +/web/public/ + +# PHPUnit +/app/phpunit.xml +/phpunit.xml + +# Build data +/build/ + +# Backup entities generated with doctrine:generate:entities command +**/Entity/*~ + +### Symfony Patch ### +/web/css/ +/web/js/ +docker-compose.yml + +### Twake specific ### +/build/ +/vendor/ + +### AWS ### +/app/config/aws_config.yml + +### Test ### +/tests/code_coverage/ +/web/detached/* +/drive/* +/web/medias/public/uploads/* +/app/Configuration/Parameters.php +/app/Configuration/certs/apns_prod.pem +/app/Configuration/certs/apns_dev.pem +/cache/ +/backend/core/vendor/ + +cassandra.log diff --git a/twake/backend/core/app.php b/twake/backend/core/app.php new file mode 100755 index 00000000..397c6bff --- /dev/null +++ b/twake/backend/core/app.php @@ -0,0 +1,148 @@ +getBundles(); + $bundles_instances = []; + + $this->app_root_dir = realpath(__DIR__ . "/../"); + $this->routing_service = new Routing($this); + $this->container_service = new Container($this); + $this->services_service = new Services($this); + $this->providers_service = new Providers($this, new \Configuration\Providers()); + + // Import configuration + $this->container_service->import(new Configuration($this), "configuration"); + $this->container_service->import(new Parameters($this), "parameters"); + + $this->counter = new Counter($this); + + // Require and instanciate all defined bundles + foreach ($bundles as $bundle) { + + if (file_exists(__DIR__ . "/../src/" . $bundle . "/Bundle.php")) { + require_once __DIR__ . "/../src/" . $bundle . "/Bundle.php"; + $class_name = str_replace("/", "\\", $bundle) . "\\Bundle"; + $bundles_instances[] = new $class_name($this); + } else { + error_log("No such bundle " . $bundle); + } + + } + + // Init routing for all bundles + foreach ($bundles_instances as $bundle_instance) { + $bundle_instance->init(); + } + + } + + public function getRouting() + { + return $this->routing_service; + } + + public function getContainer() + { + return $this->container_service; + } + + public function getServices() + { + return $this->services_service; + } + + public function getProviders() + { + return $this->providers_service; + } + + public function getAppRootDir() + { + return $this->app_root_dir; + } + + public function getCommands() + { + return $this->commands; + } + + public function getCounter() + { + return $this->counter; + } + + public function runCli() + { + if (php_sapi_name() == "cli") { + $this->commands = new CommandsManager($this, (new Commands())->commands); + ($this->commands)->run(); + } + } + + public function run() + { + try{ + SimpleRouter::start(); + }catch(\Exception $err){ + error_log($err); + http_response_code(500); + echo '{"error": "'.$err->getMessage().'"}'; + } + } +} diff --git a/twake/backend/core/app/App.php b/twake/backend/core/app/App.php new file mode 100755 index 00000000..398f79d9 --- /dev/null +++ b/twake/backend/core/app/App.php @@ -0,0 +1,160 @@ +getBundles(); + $bundles_instances = []; + + $this->app_root_dir = realpath(__DIR__ . "/../"); + $this->routing_service = new Routing($this); + $this->container_service = new Container($this); + $this->services_service = new Services($this); + $this->providers_service = new Providers($this, new \Configuration\Providers()); + + // Import configuration + $this->container_service->import(new Configuration($this), "configuration"); + $this->container_service->import(new Parameters($this), "parameters"); + + $dsn = $this->getContainer()->getParameter("env.sentry"); + if($dsn){ + \Sentry\init(['dsn' => $dsn, 'error_types' => (E_ERROR | E_WARNING | E_PARSE)]); + } + + $segment = $this->getContainer()->getParameter("env.segment"); + $GLOBALS["segment_enabled"] = false; + if($segment){ + $GLOBALS["segment_enabled"] = true; + \Segment::init($segment); + } + + $this->counter = new Counter($this); + + // Require and instanciate all defined bundles + foreach ($bundles as $bundle) { + + if (file_exists(__DIR__ . "/../src/" . $bundle . "/Bundle.php")) { + require_once __DIR__ . "/../src/" . $bundle . "/Bundle.php"; + $class_name = str_replace("/", "\\", $bundle) . "\\Bundle"; + $bundles_instances[] = new $class_name($this); + } else { + error_log("No such bundle " . $bundle); + } + + } + + // Init routing for all bundles + foreach ($bundles_instances as $bundle_instance) { + $bundle_instance->init(); + } + + } + + public function getRouting() + { + return $this->routing_service; + } + + public function getContainer() + { + return $this->container_service; + } + + public function getServices() + { + return $this->services_service; + } + + public function getProviders() + { + return $this->providers_service; + } + + public function getAppRootDir() + { + return $this->app_root_dir; + } + + public function getCommands() + { + return $this->commands; + } + + public function getCounter() + { + return $this->counter; + } + + public function runCli() + { + if (php_sapi_name() == "cli") { + $this->commands = new CommandsManager($this, (new Commands())->commands); + ($this->commands)->run(); + } + } + + public function run() + { + try{ + SimpleRouter::start(); + }catch(\Exception $err){ + error_log($err); + http_response_code(500); + echo '{"error": "'.$err->getMessage().'"}'; + } + } +} diff --git a/twake/backend/core/app/Common/BaseBundle.php b/twake/backend/core/app/Common/BaseBundle.php new file mode 100755 index 00000000..0810f9e8 --- /dev/null +++ b/twake/backend/core/app/Common/BaseBundle.php @@ -0,0 +1,132 @@ +app = $app; + } + + public function init() + { + } + + /** + * Load routes from Bundle php configuration + */ + protected function initRoutes() + { + + // For all defined route, create routing + connect lasy controller loader + $routing_service = $this->app->getRouting(); + foreach ($this->routes as $route => $data) { + + $final_route = preg_replace("/\\/+/", "/", $this->routing_prefix . "/" . $route); + $handler = null; + $methods = ["POST"]; + + if (is_string($data)) { + $handler = $data; + } else { + $handler = $data["handler"]; + if (isset($data["methods"])) $methods = $data["methods"]; + } + + $security = []; + if (isset($data["security"])) $security = $data["security"]; + + $controller = explode(":", $handler); + $handler = $controller[1]; + $controller = $controller[0]; + + foreach ($methods as $method) { + + $method = strtolower($method); + if (!in_array($method, ["get", "post", "delete", "put"])) { + continue; + } + + $that = $this; + $routing_service->addRoute($method, $final_route, function (Request $request = null) use ($that, $controller, $handler, $security) { + + if (count($security) > 0) { + foreach ($security as $security_service) { + $service = $this->app->getServices()->get($security_service); + if ($service) { + $response = $service->applySecurity($request); + if ($response && $response !== true) { + return $response; + } + } else { + error_log("Missing security service " . $service); + } + } + } + + $controller = $that->loadController($controller); + if (!$controller) { + return new Response("No controller " . $handler . " found", 500); + } + if (!method_exists($controller, $handler)) { + return new Response("No controller handler " . $handler . "->" . $handler . " found", 500); + } + return $controller->$handler($request ?: new Request()); + }); + } + } + + } + + /** + * Lasy load controller to handle request + * $controller : string + **/ + private function loadController($controller) + { + $controller_file = $this->bundle_root . "/Controller/" . $controller . ".php"; + if (file_exists($controller_file)) { + require_once $controller_file; + $class_name = $this->bundle_namespace . "\\Controller\\" . str_replace("/", "\\", $controller); + return new $class_name($this->app); + } else { + return null; + } + } + + /** + * Load services to service manager + */ + protected function initServices() + { + $services_service = $this->app->getServices(); + foreach ($this->services as $service_name => $service_relative_path) { + $service_path = preg_replace("/\\/+/", "/", $this->bundle_root . "/Services/" . $service_relative_path . ".php"); + $service_class_name = preg_replace("/\\\\+/", "\\", $this->bundle_namespace . "\\Services\\" . str_replace("/", "\\", $service_relative_path)); + + $services_service->set($service_name, $service_path, $service_class_name); + } + + } + +} \ No newline at end of file diff --git a/twake/backend/core/app/Common/BaseBundles.php b/twake/backend/core/app/Common/BaseBundles.php new file mode 100755 index 00000000..7388808f --- /dev/null +++ b/twake/backend/core/app/Common/BaseBundles.php @@ -0,0 +1,18 @@ +bundles; + } + +} \ No newline at end of file diff --git a/twake/backend/core/app/Common/BaseController.php b/twake/backend/core/app/Common/BaseController.php new file mode 100755 index 00000000..dd349e5b --- /dev/null +++ b/twake/backend/core/app/Common/BaseController.php @@ -0,0 +1,59 @@ +app = $app; + $this->container = $app->getContainer(); + } + + /* Get service */ + public function get($key) + { + return $this->app->getServices()->get($key); + } + + public function isConnected() + { + return $this->getUser() && !is_string($this->getUser()); + } + + public function getUser() + { + + $request = $this->app->getRouting()->getCurrentRequest(); + $user = $this->app->getServices()->get("app.session_handler")->getUser($request); + + return $user ?: "anonymous"; //null is reserved to user == system + } + + public function getParameter($key, $fallback = null) + { + return $this->app->getContainer()->getParameter($key) ?: $fallback; + } + + public function redirect($url) + { + $response = new Response(""); + $response->setHeader("Location: " . $url, true); + $response->sendHeaders(); + exit(); + } + +} diff --git a/twake/backend/core/app/Common/BaseRouting.php b/twake/backend/core/app/Common/BaseRouting.php new file mode 100755 index 00000000..43f49be5 --- /dev/null +++ b/twake/backend/core/app/Common/BaseRouting.php @@ -0,0 +1,22 @@ +routes; + } + + public function getRoutesPrefix() + { + return $this->routing_prefix; + } + +} \ No newline at end of file diff --git a/twake/backend/core/app/Common/BaseServices.php b/twake/backend/core/app/Common/BaseServices.php new file mode 100755 index 00000000..e99bceba --- /dev/null +++ b/twake/backend/core/app/Common/BaseServices.php @@ -0,0 +1,15 @@ +services; + } + +} \ No newline at end of file diff --git a/twake/backend/core/app/Common/Commands/ContainerAwareCommand.php b/twake/backend/core/app/Common/Commands/ContainerAwareCommand.php new file mode 100755 index 00000000..651dab34 --- /dev/null +++ b/twake/backend/core/app/Common/Commands/ContainerAwareCommand.php @@ -0,0 +1,63 @@ +configure(); + $this->app = $app; + } + + public function executeFromManager() + { + return $this->execute(); + } + + protected function getApp() + { + return $this->app; + } + + protected function getContainer() + { + + } + + protected function setName() + { + return $this; + } + + protected function setDescription() + { + return $this; + } + + protected function addOption() + { + return $this; + } + + protected function configure() + { + } + + protected function execute() + { + } + +} \ No newline at end of file diff --git a/twake/backend/core/app/Common/CommandsManager.php b/twake/backend/core/app/Common/CommandsManager.php new file mode 100755 index 00000000..1afcd4cb --- /dev/null +++ b/twake/backend/core/app/Common/CommandsManager.php @@ -0,0 +1,61 @@ +app = $app; + $this->commands = $commands; + } + + public function run() + { + array_shift($_SERVER["argv"]); + $command = array_shift($_SERVER["argv"]); + $arguments = $_SERVER["argv"]; + + if ($command && $this->commands[$command]) { + + $this->execute($command, $arguments); + + } else { + if ($command) { + error_log("Command \e[0;31;42m'" . $command . "'\e[0m was not found."); + } + $this->help(); + } + + } + + public function execute($command, $arguments) + { + if (!isset($this->commands[$command])) { + return; + } + + $command = new $this->commands[$command]($this->app); + + $command->executeFromManager(); + + } + + private function help() + { + + error_log("\nAll commands:"); + foreach ($this->commands as $name => $command) { + error_log("\e[0;31;42m" . $name . "\e[0m"); + } + error_log("\n"); + + } + +} diff --git a/twake/backend/core/app/Common/Configuration.php b/twake/backend/core/app/Common/Configuration.php new file mode 100755 index 00000000..c7baff50 --- /dev/null +++ b/twake/backend/core/app/Common/Configuration.php @@ -0,0 +1,11 @@ +app = $app; + } + + public function import(Configuration $configuration, $name) + { + $this->configuration[$name] = $configuration->configuration; + } + + public function getParameter($key) + { + return $this->get("parameters", $key); + } + + public function hasParameter($key) + { + return !!$this->get("parameters", $key); + } + + public function get($namespace, $key) + { + $key = explode(".", $key); + $obj = $this->configuration[$namespace]; + $i = 0; + while (is_array($obj) && $i < count($key)) { + $obj = @$obj[$key[$i]]; + + if (is_object($obj) && is_subclass_of($obj, "Common\Configuration") && isset($obj->configuration)) { + $obj = $obj->configuration; + } + + $i++; + } + return $obj; + } + +} diff --git a/twake/backend/core/app/Common/Counter.php b/twake/backend/core/app/Common/Counter.php new file mode 100755 index 00000000..01b9293c --- /dev/null +++ b/twake/backend/core/app/Common/Counter.php @@ -0,0 +1,60 @@ +dev_mode = $app->getContainer()->getParameter("env.timer") == true; + } + + public function incrementCounter($key) + { + if (!isset($this->counters["counter_" . $key])) { + $this->counters["counter_" . $key] = 0; + } + $this->counters["counter_" . $key]++; + } + + public function readCounter($key) + { + return isset($this->counters["counter_" . $key]) ? $this->counters["counter_" . $key] : 0; + } + + public function startTimer($key) + { + $this->timers_started[$key] = microtime(true); + } + + public function stopTimer($key) + { + if (!isset($this->timers_values[$key])) { + $this->timers_values[$key] = 0; + } + $this->timers_values[$key] += microtime(true) - $this->timers_started[$key]; + $this->counters["timer_" . $key] = $this->timers_values[$key]; + } + + public function readTimer($key) + { + return isset($this->counters["timer_" . $key]) ? $this->counters["timer_" . $key] : -1; + } + + public function showResults() + { + if ($this->dev_mode) { + error_log(json_encode($this->counters, JSON_PRETTY_PRINT)); + } + } + +} diff --git a/twake/backend/core/app/Common/Http/Cookie.php b/twake/backend/core/app/Common/Http/Cookie.php new file mode 100755 index 00000000..fdc2483b --- /dev/null +++ b/twake/backend/core/app/Common/Http/Cookie.php @@ -0,0 +1,70 @@ +name = $name; + $this->value = $value; + $this->expire = 0 < $expire ? (int)$expire : 0; + $this->path = empty($path) ? '/' : $path; + } + + + public function __toString() + { + $str = str_replace(self::$reservedCharsFrom, self::$reservedCharsTo, $this->name); + $str .= '='; + + if ('' === (string)$this->value) { + $str .= 'deleted; expires=' . gmdate('D, d-M-Y H:i:s T', time() - 31536001) . '; Max-Age=0; SameSite=Lax; Secure'; + } else { + $str .= rawurlencode($this->value); + + if (0 !== $this->expire) { + $str .= '; expires=' . gmdate('D, d-M-Y H:i:s T', $this->expire) . '; Max-Age=' . $this->getMaxAge() . "; SameSite=Lax; Secure"; + } + } + + if ($this->path) { + $str .= '; path=' . $this->path; + } + + return $str; + } + + public function asArray() + { + return [str_replace(self::$reservedCharsFrom, self::$reservedCharsTo, $this->name), (string)$this->value, $this->expire]; + } + + public function getMaxAge() + { + $maxAge = $this->expire - time(); + + return 0 >= $maxAge ? 0 : $maxAge; + } + + public function getName() + { + return $this->name; + } + + public function getValue() + { + return $this->value; + } + +} diff --git a/twake/backend/core/app/Common/Http/ParamBag.php b/twake/backend/core/app/Common/Http/ParamBag.php new file mode 100755 index 00000000..59b34cf5 --- /dev/null +++ b/twake/backend/core/app/Common/Http/ParamBag.php @@ -0,0 +1,44 @@ +array = $array; + } + + public function all() + { + return $this->array; + } + + public function get($key, $default = null) + { + return isset($this->array[$key]) ? $this->array[$key] : $default; + } + + public function has($key) + { + return isset($this->array[$key]); + } + + public function getBoolean($key, $default = false) + { + return isset($this->array[$key]) ? !!$this->array[$key] : $default; + } + + public function getInt($key, $default = false) + { + return isset($this->array[$key]) ? intval($this->array[$key]) : $default; + } + + public function reset($array) + { + $this->array = $array; + } +} diff --git a/twake/backend/core/app/Common/Http/Request.php b/twake/backend/core/app/Common/Http/Request.php new file mode 100755 index 00000000..b4c2f2ca --- /dev/null +++ b/twake/backend/core/app/Common/Http/Request.php @@ -0,0 +1,58 @@ +headers = new ParamBag(getallheaders()); + $this->content = file_get_contents('php://input'); + $this->query = new ParamBag($_GET); + $this->request = new ParamBag($_POST); + $this->files = new ParamBag($_FILES); + + //Get all cookies + $cookies = $_COOKIE; + $header_cookies = []; + try { + $all_cookies = isset(getallheaders()["All-Cookies"]) ? getallheaders()["All-Cookies"] : "[]"; + $header_cookies = json_decode($all_cookies, 1); + } catch (\Exception $err) { + $header_cookies = []; + } + foreach ($header_cookies as $cookie) { + $cookies[$cookie[0]] = $cookie[1]; + } + $this->cookies = new ParamBag($cookies); + + if (count($this->request->all()) === 0 || 0 === strpos($this->headers->get('Content-Type'), 'application/json')) { + try{ + $data = json_decode($this->getContent(), true); + $this->request = new ParamBag(is_array($data) ? $data : array()); + }catch(\Exception $err){ + //Nop + } + } + + } + + public function getContent() + { + return $this->content; + } +} diff --git a/twake/backend/core/app/Common/Http/Response.php b/twake/backend/core/app/Common/Http/Response.php new file mode 100755 index 00000000..4886e2c7 --- /dev/null +++ b/twake/backend/core/app/Common/Http/Response.php @@ -0,0 +1,106 @@ +setContent($content); + $this->httpStatus($status); + $this->headers = new ParamBag([]); + } + + public function setHeader($header, $replace = true) + { + $headers = $this->headers->all(); + $header = explode(":", $header); + $header_name = array_shift($header); + $header_value = join(":", $header); + $headers[$header_name] = $header_value; + $this->headers->reset($headers); + } + + public function setCookie(Cookie $cookie) + { + $this->cookies[$cookie->getName()] = $cookie; + } + + public function getCookiesValues() + { + $key_value = []; + foreach ($this->cookies as $name => $cookie) { + $key_value[$name] = $cookie->getValue(); + } + return $key_value; + } + + public function clearCookie($name) + { + $this->cookies[$name] = new Cookie($name, null, 1, "/"); + } + + public function getContent() + { + if (is_array($this->content)) { + $this->content["_cookies"] = $this->getCookiesValues(); + return json_encode($this->content); + } + return $this->content; + } + + public function setContent($content) + { + $this->content = $content; + } + + public function httpStatus($code) + { + $this->status = $code; + } + + public function getHttpStatus() + { + return $this->status; + } + + public function sendHeaders() + { + if(headers_sent()){ + return; + } + if (defined("TESTENV") && TESTENV) { + return; + } + $all_cookies = []; + foreach ($this->cookies as $cookie) { + header("Set-Cookie: " . $cookie, false); + $all_cookies[] = $cookie->asArray(); + } + header("All-Cookies: " . json_encode($all_cookies), true); + foreach ($this->headers->all() as $name => $value) { + header($name . ": " . $value, true); + } + header("Access-Control-Expose-Headers: All-Cookies"); + } + + public function send() + { + $this->sendHeaders(); + http_response_code($this->status); + if (is_array($this->content) && !headers_sent()) { + header('Content-Type: application/json; charset=utf-8'); + } + echo $this->getContent(); + } + +} diff --git a/twake/backend/core/app/Common/Providers.php b/twake/backend/core/app/Common/Providers.php new file mode 100755 index 00000000..500429d8 --- /dev/null +++ b/twake/backend/core/app/Common/Providers.php @@ -0,0 +1,95 @@ +app = $app; + $this->configuration = $configuration; + + foreach ($configuration->providers as $name => $provider_config) { + + //Each provider expose multiple services + foreach ($provider_config["services"] as $service) { + $this->services[$service] = $provider_config; + } + + } + + $this->provider_config = new \Pimple\Container(); + + } + + public function get($key) + { + + if (isset($this->service_instances[$key])) { + return $this->service_instances[$key]; + } + + if (!isset($this->services[$key])) { + error_log($key . " service was not found"); + return null; + } + + $service_register_name = $this->services[$key]["register"]; + if (empty($this->registered_services[$service_register_name])) { + + if (isset($services[$key]["parameters"])) { + $parameters_key = $services[$key]["parameters"]; + $parameters = $this->app->getContainer()->get("parameters", $parameters_key); + foreach ($parameters as $key => $parameter) { + $this->providers_options[$key] = $parameter; + } + } + + if (isset($services[$key]["configuration"])) { + $parameters_key = $services[$key]["configuration"]; + $parameters = $this->app->getContainer()->get("configuration", $parameters_key); + foreach ($parameters as $key => $parameter) { + $this->providers_options[$key] = $parameter; + } + } + + $service = new $service_register_name(); + $service->register($this->provider_config); + $this->registered_services[$service_register_name] = $service; + + } + + try { + $this->service_instances[$key] = $this->provider_config[$key]; + } catch (\Exception $e) { + error_log($e); + } + + return $this->service_instances[$key]; + + } + + public function getContainer() + { + return $this->provider_config; + } + + +} diff --git a/twake/backend/core/app/Common/Routing.php b/twake/backend/core/app/Common/Routing.php new file mode 100755 index 00000000..81b4f1dc --- /dev/null +++ b/twake/backend/core/app/Common/Routing.php @@ -0,0 +1,146 @@ +app = $app; + $this->request = new Request(); + } + + public function addRoute($method, $route, $callback) + { + $route = preg_replace("/^\//", "", $route); + $route = preg_replace("/\/$/", "", $route); + + if (isset($this->routes[$route . ":" . $method])) { + error_log("Route " . $route . " was already defined."); + return; + } + $this->routes[$route . ":" . $method] = true; + $this->routesToController[$route . ":" . $method] = $callback; + + if ($method == "get") { + $this->get($route, $callback); + } else if ($method == "post") { + $this->post($route, $callback); + } else if ($method == "put") { + $this->put($route, $callback); + } else if ($method == "delete") { + $this->delete($route, $callback); + } else { + error_log("Unable to register route " . $route . ": method " . $method . " is not implemented."); + } + } + + public function get($route, $callback) + { + SimpleRouter::get($route, function () use ($callback) { + error_log("[Router] - GET " . $_SERVER["REQUEST_URI"]); + try { + $response = $this->beforeRender($callback($this->request)); + $response->send(); + } catch (\Exception $e) { + error_log($e); + } + }); + } + + public function post($route, $callback) + { + SimpleRouter::post($route, function () use ($callback) { + error_log("[Router] - POST " . $_SERVER["REQUEST_URI"]); + try { + $response = $this->beforeRender($callback($this->request)); + $response->send(); + } catch (\Exception $e) { + error_log($e); + } + }); + } + + public function put($route, $callback) + { + SimpleRouter::put($route, function () use ($callback) { + error_log("[Router] - PUT " . $_SERVER["REQUEST_URI"]); + try { + $response = $this->beforeRender($callback($this->request)); + $response->send(); + } catch (\Exception $e) { + error_log($e); + } + }); + } + + public function delete($route, $callback) + { + SimpleRouter::delete($route, function () use ($callback) { + error_log("[Router] - DELETE " . $_SERVER["REQUEST_URI"]); + try { + $response = $this->beforeRender($callback($this->request)); + $response->send(); + } catch (\Exception $e) { + error_log($e); + } + }); + } + + //Allow any origin + private function beforeRender(Response $response) + { + if (isset($_SERVER['HTTP_ORIGIN']) && strpos("http://localhost", $_SERVER['HTTP_ORIGIN']) == 0) { + $response->setHeader('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN'], true); + } + $response->setHeader('Access-Control-Allow-Headers: ' . 'authorization, Content-Type, *', true); + $response->setHeader('Access-Control-Allow-Credentials: ' . 'true', true); + $response->setHeader('Access-Control-Allow-Methods: ' . 'GET, POST', true); + $response->setHeader('Access-Control-Max-Age: ' . '600', true); + $length = strlen($response->getContent()); + $response->setHeader('x-decompressed-content-length: ' . $length, true); + + $content = $response->getContent(); + + return $response; + } + + public function execute($method, $route, Request $request) + { + $this->request = $request; + + $route = preg_replace("/^\//", "", $route); + $route = preg_replace("/\/$/", "", $route); + + if (isset($this->routesToController[$route . ":" . strtolower($method)])) { + $response = $this->routesToController[$route . ":" . strtolower($method)]($request); + } else { + error_log(json_encode($route . ":" . strtolower($method)) . " does not exists."); + $response = new Response(); + } + return $this->beforeRender($response); + } + + public function getRoutes() + { + return array_keys($this->routes); + } + + public function getCurrentRequest() + { + return $this->request; + } + +} diff --git a/twake/backend/core/app/Common/Services.php b/twake/backend/core/app/Common/Services.php new file mode 100755 index 00000000..43068985 --- /dev/null +++ b/twake/backend/core/app/Common/Services.php @@ -0,0 +1,58 @@ +app = $app; + } + + public function set($key, $class_src_path, $class_name) + { + if (isset($this->services[$key])) { + error_log("The service " . $key . " is already defined."); + return; + } + $this->services[$key] = [ + "src_path" => $class_src_path, + "name" => $class_name + ]; + } + + /** Lasy instanciate service */ + public function get($key) + { + + if (!isset($this->services[$key])) { + error_log("The requested service " . $key . " is not defined."); + return null; + } + + if (isset($this->services_instances[$key])) { + return $this->services_instances[$key]; + } + + require_once $this->services[$key]["src_path"]; + $name = $this->services[$key]["name"]; + $this->services_instances[$key] = new $name($this->app); + + return $this->services_instances[$key]; + } + + public function isLoaded($key) + { + return isset($this->services[$key]); + } + +} diff --git a/twake/backend/core/app/Configuration/Bundles.php b/twake/backend/core/app/Configuration/Bundles.php new file mode 100755 index 00000000..783ddf87 --- /dev/null +++ b/twake/backend/core/app/Configuration/Bundles.php @@ -0,0 +1,43 @@ + "Twake\Core\Command\TwakeSchemaUpdateCommand", + "twake:init" => "Twake\Core\Command\InitCommand", + "twake:init_connector" => "BuiltInConnectors\Common\Command\InitConnector", + "twake:update_services_status" => "Twake\Core\Command\UpdateServicesStatusCommand", + "twake:routes" => "Twake\Core\Command\GetRoutesCommand", + "twake:tasks_check_reminders" => "Twake\Tasks\Command\TaskReminderCheckerCommand", + "twake:reindex" => "Twake\Core\Command\ReindexCommand", + "twake:mapping" => "Twake\Core\Command\MappingCommand", + "twake:calendar_check" => "Twake\Calendar\Command\ReminderCheckerCommand", + "twake:mails_queue" => "Twake\Core\Command\MailsQueueCommand", + "twake:notifications_mail" => "Twake\Notifications\Command\NotificationMailCommand", + "twake:preview_worker" => "Twake\Drive\Command\DrivePreviewCommand", + "twake:scheduled_notifications_consume_timetable" => "Twake\Core\Command\ScheduledNotificationsConsumeTimetable", + "twake:scheduled_notifications_consume_shard" => "Twake\Core\Command\ScheduledNotificationsConsumeShard", + ]; + +} diff --git a/twake/backend/core/app/Configuration/Configuration.php b/twake/backend/core/app/Configuration/Configuration.php new file mode 100755 index 00000000..ed30019f --- /dev/null +++ b/twake/backend/core/app/Configuration/Configuration.php @@ -0,0 +1,22 @@ +configuration = [ + "twig" => [ + 'cache' => '/cache/twig' + ] + ]; + } + +} \ No newline at end of file diff --git a/twake/backend/core/app/Configuration/Parameters.php.dist b/twake/backend/core/app/Configuration/Parameters.php.dist new file mode 100755 index 00000000..165886d3 --- /dev/null +++ b/twake/backend/core/app/Configuration/Parameters.php.dist @@ -0,0 +1,221 @@ +configuration = [ + "env" => [ + "type" => "prod", + "timer" => false, + "admin_api_token" => "", + "licence_key" => "", + "standalone" => true, + //"frontend_server_name" => "http://localhost:8000/", // define only if needed + "server_name" => "http://localhost:8000/", + "internal_server_name" => "http://nginx/" + ], + "jwt" => [ + "secret" => "supersecret", + "expiration" => 60*60, //1 hour + "refresh_expiration" => 60*60*24*31 //1 month + ], + "node" => [ + "api" => "http://node:3000/private/", + "secret" => "api_supersecret" + ], + "db" => [ + "driver" => "pdo_cassandra", + "host" => "scylladb", + "port" => 9042, + "dbname" => "twake", + "user" => "root", + "password" => "root", + "encryption_key" => "ab63bb3e90c0271c9a1c06651a7c0967eab8851a7a897766", + "replication" => "{'class': 'SimpleStrategy', 'replication_factor': '1'}", + "is_cassandra" => false + ], + "es" => [ + "host" => "elasticsearch:9200" + ], + "queues" => [ + "rabbitmq" => [ + "use" => true, + "host" => "rabbitmq", + "port" => 5672, + "username" => "admin", + "password" => "admin", + "vhost" => false + ] + ], + "storage" => [ + "drive_previews_tmp_folder" => "/tmp/", + "drive_tmp_folder" => "/tmp/", + "drive_salt" => "SecretPassword", + "providers" => [ + [ + "label" => "someOpenStack", + "type" => "openstack", + "use" => false, + "project_id" => "", + "auth_url" => "https//auth.cloud.ovh.net/v3", + "buckets_prefix" => "", + "disable_encryption" => false, + "buckets" => [ + "fr" => [ + "public" => "", + "private" => "", + "region" => "SBG5" + ] + ], + "user" => [ + "id" => "", + "password" => "", + "domain_name" => "default" + ] + ], + [ + "label" => "someS3", + "type" => "S3", + "base_url" => "http://127.0.0.1:9000", + "use" => false, + "version" => "latest", + "disable_encryption" => false, + "buckets_prefix" => "dev.", + "buckets" => [ + "fr" => "eu-west-3" + ], + "credentials" => [ + "key" => "", + "secret" => "" + ] + ], + [ + "label" => "someLocal", + "type" => "local", + "use" => true, + "disable_encryption" => false, + "location" => "../drive/", + "preview_location" => "../web/medias/", + "preview_public_path" => "/medias/" + ], + ], + ], + "mail" => [ + "sender" => [ + "host" => "", + "port" => "", + "username" => "", + "password" => "", + "auth_mode" => "plain" + ], + "template_dir" => "/src/Twake/Core/Resources/views/", + "twake_domain_url" => "https://twakeapp.com/", + "from" => "noreply@twakeapp.com", + "from_name" => "Twake", + "twake_address" => "Twake, 54000 Nancy, France", + "dkim" => [ + "private_key" => "", + "domain_name" => '', + "selector" => '' + ], + "mailjet"=> [ + "contact_list_subscribe"=> false, + "contact_list_newsletter"=> false + ] + ], + "push_notifications" => [ + "apns_certificate" => __DIR__ . "/certs/apns_prod.pem", + "firebase_api_key" => "KEY", + ], + + //Defaults values for all clients but editable in database + "defaults" => [ + "applications" => [ + "twake_drive" => [ "default" => true ], //False to not install + "twake_calendar" => [ "default" => true ], + "twake_tasks" => [ "default" => true ], + "connectors" => [ + "jitsi" => [ "default" => true ], + ] + ], + "connectors" => [ + ], + "branding" => [ + "name" => "Twake", + "enable_newsletter" => false, + /* + "header" => [ + "logo" => 'https://openpaas.linagora.com/images/white-logo.svg', + "apps" => [ + [ + "name"=> 'Accueil', + "url"=> 'https://openpaas.linagora.com/', + "icon"=> 'https://openpaas.linagora.com/images/application-menu/home-icon.svg', + ], + [ + "name"=> 'Inbox', + "url"=> 'https://openpaas.linagora.com/#/unifiedinbox/inbox', + "icon"=> 'https://openpaas.linagora.com/unifiedinbox/images/inbox-icon.svg', + ], + [ + "name"=> 'Calendrier', + "url"=> 'https://openpaas.linagora.com/#/calendar', + "icon"=> 'https://openpaas.linagora.com/calendar/images/calendar-icon.svg', + ], + [ + "name"=> 'Contacts', + "url"=> 'https://openpaas.linagora.com/#/contact/addressbooks/', + "icon"=> 'https://openpaas.linagora.com/contact/images/contacts-icon.svg', + ], + ], + ], + "style" => [ + "color" => '#2196F3', + "default_border_radius" => '2', + ], + "link" => "https://open-paas.org/", + "logo" => "https://open-paas.org/wp-content/uploads/2019/10/openpaas.png" + */ + ], + "auth" => [ + "internal" => [ + "use" => true, + "disable_account_creation" => false, + "disable_email_verification" => true + ], + "openid" => [ + "use" => false, + "provider_uri" => 'https://auth0.com', + "client_id" => '', + "client_secret" => '', + //"disable_logout_redirect" => false + "provider_config" => [ + //token_endpoint + //token_endpoint_auth_methods_supported + //userinfo_endpoint + //end_session_endpoint + //authorization_endpoint + ] + ], + "cas" => [ + "use" => false, + "base_url" => '', + "email_key" => '', + "lastname_key" => '', + "firstname_key" => '' + ], + "console" => [ + "use" => false + ] + ] + ], + ]; + } + +} diff --git a/twake/backend/core/app/Configuration/Providers.php b/twake/backend/core/app/Configuration/Providers.php new file mode 100755 index 00000000..f39ebfd0 --- /dev/null +++ b/twake/backend/core/app/Configuration/Providers.php @@ -0,0 +1,16 @@ + [ + "services" => [ + "db" + ], + "register" => "Twake\Core\Services\DoctrineAdapter\DoctrineServiceProvider", + ] + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/app/Configuration/certs/apns_dev.pem.dist b/twake/backend/core/app/Configuration/certs/apns_dev.pem.dist new file mode 100755 index 00000000..e69de29b diff --git a/twake/backend/core/app/Configuration/certs/apns_prod.pem.dist b/twake/backend/core/app/Configuration/certs/apns_prod.pem.dist new file mode 100755 index 00000000..e69de29b diff --git a/twake/backend/core/bin/console b/twake/backend/core/bin/console new file mode 100755 index 00000000..479df64b --- /dev/null +++ b/twake/backend/core/bin/console @@ -0,0 +1,9 @@ +#!/usr/bin/env php +runCli(); \ No newline at end of file diff --git a/twake/backend/core/composer.json b/twake/backend/core/composer.json new file mode 100755 index 00000000..5dda9081 --- /dev/null +++ b/twake/backend/core/composer.json @@ -0,0 +1,47 @@ +{ + "name": "twake/twake-core", + "authors": [ + { + "name": "Romaric Mourgues", + "email": "romaric.mourgues@twakeapp.com" + } + ], + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/Twake/Pusher" + } + ], + "require": { + "php": ">=7.1", + "doctrine/orm": "^2.5", + "doctrine/doctrine-bundle": "^1.6", + "doctrine/doctrine-cache-bundle": "^1.2", + "phpunit/phpunit": "5.7", + "aws/aws-sdk-php-symfony": "~2.0", + "php-opencloud/openstack": "^3.0", + "emojione/emojione": "3.1", + "swiftmailer/swiftmailer": "^6.0", + "twig/twig": "^2.12", + "doctrine/dbal": "~2.2", + "ramsey/uuid-doctrine": "^1.5", + "spatie/pdf-to-text": "*", + "soleon/sc-php": "^1.0", + "pecee/simple-router": "4.2.0.6", + "pimple/pimple": "~3.0", + "mxp100/pusher": "dev-twake-1.0 as 1.0", + "eluceo/ical": "^0.16.0", + "php-amqplib/php-amqplib": "^2.11", + "phpseclib/phpseclib": "^2.0", + "sentry/sdk": "^2.1", + "firebase/php-jwt": "^5.2", + "segmentio/analytics-php": "^1.5" + }, + "autoload": { + "psr-4": { + "": "src/", + "Common\\": "app/Common", + "App\\": "app/" + } + } +} diff --git a/twake/backend/core/composer.lock b/twake/backend/core/composer.lock new file mode 100755 index 00000000..f9cfa613 --- /dev/null +++ b/twake/backend/core/composer.lock @@ -0,0 +1,7547 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "57aa0be7eecf4be955a1e5863f35d700", + "packages": [ + { + "name": "aws/aws-sdk-php", + "version": "3.133.45", + "source": { + "type": "git", + "url": "https://github.com/aws/aws-sdk-php.git", + "reference": "928a23e2ee7e195a66f93d0758895e26958c3b7d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/928a23e2ee7e195a66f93d0758895e26958c3b7d", + "reference": "928a23e2ee7e195a66f93d0758895e26958c3b7d", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^5.3.3|^6.2.1|^7.0", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4.1", + "mtdowling/jmespath.php": "^2.5", + "php": ">=5.5" + }, + "require-dev": { + "andrewsville/php-token-reflection": "^1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "behat/behat": "~3.0", + "doctrine/cache": "~1.4", + "ext-dom": "*", + "ext-openssl": "*", + "ext-pcntl": "*", + "ext-sockets": "*", + "nette/neon": "^2.3", + "phpunit/phpunit": "^4.8.35|^5.4.3", + "psr/cache": "^1.0", + "psr/simple-cache": "^1.0", + "sebastian/comparator": "^1.2.3" + }, + "suggest": { + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "ext-curl": "To send requests using cURL", + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Aws\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Amazon Web Services", + "homepage": "http://aws.amazon.com" + } + ], + "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", + "homepage": "http://aws.amazon.com/sdkforphp", + "keywords": [ + "amazon", + "aws", + "cloud", + "dynamodb", + "ec2", + "glacier", + "s3", + "sdk" + ], + "time": "2020-03-26T18:12:15+00:00" + }, + { + "name": "aws/aws-sdk-php-symfony", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/aws/aws-sdk-php-symfony.git", + "reference": "238f399aaade616bb025e6f62fc309660aa3b087" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aws/aws-sdk-php-symfony/zipball/238f399aaade616bb025e6f62fc309660aa3b087", + "reference": "238f399aaade616bb025e6f62fc309660aa3b087", + "shasum": "" + }, + "require": { + "aws/aws-sdk-php": "^3.2.6", + "php": ">=5.5", + "symfony/config": "~2.3|~3.0|~4.0|~5.0", + "symfony/dependency-injection": "~2.3|~3.0|~4.0|~5.0", + "symfony/http-kernel": "~2.3|~3.0|~4.0|~5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|^5.4.0|^6.0.0", + "symfony/framework-bundle": "~2.3|~3.0|~4.0|~5.0", + "symfony/yaml": "~2.3|~3.0|~4.0|~5.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Aws\\Symfony\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Amazon Web Services", + "homepage": "http://aws.amazon.com" + } + ], + "description": "A Symfony bundle for v3 of the AWS SDK for PHP", + "keywords": [ + "Symfony2", + "amazon", + "aws", + "sdk", + "symfony", + "symfony3" + ], + "time": "2020-03-05T21:48:37+00:00" + }, + { + "name": "clue/stream-filter", + "version": "v1.4.1", + "source": { + "type": "git", + "url": "https://github.com/clue/stream-filter.git", + "reference": "5a58cc30a8bd6a4eb8f856adf61dd3e013f53f71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/clue/stream-filter/zipball/5a58cc30a8bd6a4eb8f856adf61dd3e013f53f71", + "reference": "5a58cc30a8bd6a4eb8f856adf61dd3e013f53f71", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "phpunit/phpunit": "^5.0 || ^4.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Clue\\StreamFilter\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian LΓΌck", + "email": "christian@lueck.tv" + } + ], + "description": "A simple and modern approach to stream filtering in PHP", + "homepage": "https://github.com/clue/php-stream-filter", + "keywords": [ + "bucket brigade", + "callback", + "filter", + "php_user_filter", + "stream", + "stream_filter_append", + "stream_filter_register" + ], + "time": "2019-04-09T12:31:48+00:00" + }, + { + "name": "doctrine/annotations", + "version": "v1.8.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/904dca4eb10715b92569fbcd79e201d5c349b6bc", + "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "php": "^7.1" + }, + "require-dev": { + "doctrine/cache": "1.*", + "phpunit/phpunit": "^7.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "time": "2019-10-01T18:55:10+00:00" + }, + { + "name": "doctrine/cache", + "version": "1.10.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "382e7f4db9a12dc6c19431743a2b096041bcdd62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/382e7f4db9a12dc6c19431743a2b096041bcdd62", + "reference": "382e7f4db9a12dc6c19431743a2b096041bcdd62", + "shasum": "" + }, + "require": { + "php": "~7.1" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "require-dev": { + "alcaeus/mongo-php-adapter": "^1.1", + "doctrine/coding-standard": "^6.0", + "mongodb/mongodb": "^1.1", + "phpunit/phpunit": "^7.0", + "predis/predis": "~1.0" + }, + "suggest": { + "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", + "homepage": "https://www.doctrine-project.org/projects/cache.html", + "keywords": [ + "abstraction", + "apcu", + "cache", + "caching", + "couchdb", + "memcached", + "php", + "redis", + "xcache" + ], + "time": "2019-11-29T15:36:20+00:00" + }, + { + "name": "doctrine/collections", + "version": "1.6.4", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "6b1e4b2b66f6d6e49983cebfe23a21b7ccc5b0d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/6b1e4b2b66f6d6e49983cebfe23a21b7ccc5b0d7", + "reference": "6b1e4b2b66f6d6e49983cebfe23a21b7ccc5b0d7", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan-shim": "^0.9.2", + "phpunit/phpunit": "^7.0", + "vimeo/psalm": "^3.2.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Collections\\": "lib/Doctrine/Common/Collections" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.", + "homepage": "https://www.doctrine-project.org/projects/collections.html", + "keywords": [ + "array", + "collections", + "iterators", + "php" + ], + "time": "2019-11-13T13:07:11+00:00" + }, + { + "name": "doctrine/common", + "version": "2.12.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/common.git", + "reference": "2053eafdf60c2172ee1373d1b9289ba1db7f1fc6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/common/zipball/2053eafdf60c2172ee1373d1b9289ba1db7f1fc6", + "reference": "2053eafdf60c2172ee1373d1b9289ba1db7f1fc6", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.0", + "doctrine/cache": "^1.0", + "doctrine/collections": "^1.0", + "doctrine/event-manager": "^1.0", + "doctrine/inflector": "^1.0", + "doctrine/lexer": "^1.0", + "doctrine/persistence": "^1.1", + "doctrine/reflection": "^1.0", + "php": "^7.1" + }, + "require-dev": { + "doctrine/coding-standard": "^1.0", + "phpstan/phpstan": "^0.11", + "phpstan/phpstan-phpunit": "^0.11", + "phpunit/phpunit": "^7.0", + "squizlabs/php_codesniffer": "^3.0", + "symfony/phpunit-bridge": "^4.0.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.11.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "PHP Doctrine Common project is a library that provides additional functionality that other Doctrine projects depend on such as better reflection support, persistence interfaces, proxies, event system and much more.", + "homepage": "https://www.doctrine-project.org/projects/common.html", + "keywords": [ + "common", + "doctrine", + "php" + ], + "time": "2020-01-10T15:49:25+00:00" + }, + { + "name": "doctrine/dbal", + "version": "v2.9.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/dbal.git", + "reference": "7345cd59edfa2036eb0fa4264b77ae2576842035" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/7345cd59edfa2036eb0fa4264b77ae2576842035", + "reference": "7345cd59edfa2036eb0fa4264b77ae2576842035", + "shasum": "" + }, + "require": { + "doctrine/cache": "^1.0", + "doctrine/event-manager": "^1.0", + "ext-pdo": "*", + "php": "^7.1" + }, + "require-dev": { + "doctrine/coding-standard": "^5.0", + "jetbrains/phpstorm-stubs": "^2018.1.2", + "phpstan/phpstan": "^0.10.1", + "phpunit/phpunit": "^7.4", + "symfony/console": "^2.0.5|^3.0|^4.0", + "symfony/phpunit-bridge": "^3.4.5|^4.0.5" + }, + "suggest": { + "symfony/console": "For helpful console commands such as SQL execution and import of files." + }, + "bin": [ + "bin/doctrine-dbal" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.9.x-dev", + "dev-develop": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\DBAL\\": "lib/Doctrine/DBAL" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.", + "homepage": "https://www.doctrine-project.org/projects/dbal.html", + "keywords": [ + "abstraction", + "database", + "dbal", + "mysql", + "persistence", + "pgsql", + "php", + "queryobject" + ], + "time": "2019-11-02T22:19:34+00:00" + }, + { + "name": "doctrine/doctrine-bundle", + "version": "1.12.7", + "source": { + "type": "git", + "url": "https://github.com/doctrine/DoctrineBundle.git", + "reference": "18fb7d271676dcb8e882adb0157ac1445c8fe89c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/18fb7d271676dcb8e882adb0157ac1445c8fe89c", + "reference": "18fb7d271676dcb8e882adb0157ac1445c8fe89c", + "shasum": "" + }, + "require": { + "doctrine/dbal": "^2.5.12", + "doctrine/doctrine-cache-bundle": "~1.2", + "doctrine/persistence": "^1.3.3", + "jdorn/sql-formatter": "^1.2.16", + "php": "^7.1", + "symfony/cache": "^3.4.30|^4.3.3", + "symfony/config": "^3.4.30|^4.3.3", + "symfony/console": "^3.4.30|^4.3.3", + "symfony/dependency-injection": "^3.4.30|^4.3.3", + "symfony/doctrine-bridge": "^3.4.30|^4.3.3", + "symfony/framework-bundle": "^3.4.30|^4.3.3", + "symfony/service-contracts": "^1.1.1|^2.0" + }, + "conflict": { + "doctrine/orm": "<2.6", + "twig/twig": "<1.34|>=2.0,<2.4" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "doctrine/orm": "^2.6", + "ocramius/proxy-manager": "^2.1", + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^7.5", + "symfony/phpunit-bridge": "^4.2", + "symfony/property-info": "^3.4.30|^4.3.3", + "symfony/proxy-manager-bridge": "^3.4|^4|^5", + "symfony/twig-bridge": "^3.4|^4.1", + "symfony/validator": "^3.4.30|^4.3.3", + "symfony/web-profiler-bundle": "^3.4.30|^4.3.3", + "symfony/yaml": "^3.4.30|^4.3.3", + "twig/twig": "^1.34|^2.12" + }, + "suggest": { + "doctrine/orm": "The Doctrine ORM integration is optional in the bundle.", + "symfony/web-profiler-bundle": "To use the data collector." + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "1.12.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Bundle\\DoctrineBundle\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Doctrine Project", + "homepage": "http://www.doctrine-project.org/" + } + ], + "description": "Symfony DoctrineBundle", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database", + "dbal", + "orm", + "persistence" + ], + "time": "2020-01-10T12:25:22+00:00" + }, + { + "name": "doctrine/doctrine-cache-bundle", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/DoctrineCacheBundle.git", + "reference": "6bee2f9b339847e8a984427353670bad4e7bdccb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/DoctrineCacheBundle/zipball/6bee2f9b339847e8a984427353670bad4e7bdccb", + "reference": "6bee2f9b339847e8a984427353670bad4e7bdccb", + "shasum": "" + }, + "require": { + "doctrine/cache": "^1.4.2", + "doctrine/inflector": "^1.0", + "php": "^7.1", + "symfony/doctrine-bridge": "^3.4|^4.0" + }, + "require-dev": { + "instaclick/coding-standard": "~1.1", + "instaclick/object-calisthenics-sniffs": "dev-master", + "instaclick/symfony2-coding-standard": "dev-remaster", + "phpunit/phpunit": "^7.0", + "predis/predis": "~0.8", + "satooshi/php-coveralls": "^1.0", + "squizlabs/php_codesniffer": "~1.5", + "symfony/console": "^3.4|^4.0", + "symfony/finder": "^3.4|^4.0", + "symfony/framework-bundle": "^3.4|^4.0", + "symfony/phpunit-bridge": "^3.4|^4.0", + "symfony/security-acl": "^2.8", + "symfony/validator": "^3.4|^4.0", + "symfony/yaml": "^3.4|^4.0" + }, + "suggest": { + "symfony/security-acl": "For using this bundle to cache ACLs" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Bundle\\DoctrineCacheBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Fabio B. Silva", + "email": "fabio.bat.silva@gmail.com" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@hotmail.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Doctrine Project", + "homepage": "http://www.doctrine-project.org/" + } + ], + "description": "Symfony Bundle for Doctrine Cache", + "homepage": "https://www.doctrine-project.org", + "keywords": [ + "cache", + "caching" + ], + "abandoned": true, + "time": "2019-11-29T11:22:01+00:00" + }, + { + "name": "doctrine/event-manager", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/event-manager.git", + "reference": "629572819973f13486371cb611386eb17851e85c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/629572819973f13486371cb611386eb17851e85c", + "reference": "629572819973f13486371cb611386eb17851e85c", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "conflict": { + "doctrine/common": "<2.9@dev" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.", + "homepage": "https://www.doctrine-project.org/projects/event-manager.html", + "keywords": [ + "event", + "event dispatcher", + "event manager", + "event system", + "events" + ], + "time": "2019-11-10T09:48:07+00:00" + }, + { + "name": "doctrine/inflector", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "ec3a55242203ffa6a4b27c58176da97ff0a7aec1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/ec3a55242203ffa6a4b27c58176da97ff0a7aec1", + "reference": "ec3a55242203ffa6a4b27c58176da97ff0a7aec1", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^6.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Common String Manipulations with regard to casing and singular/plural rules.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string" + ], + "time": "2019-10-30T19:59:35+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.13", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-shim": "^0.11", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2019-10-21T16:45:58+00:00" + }, + { + "name": "doctrine/lexer", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/1febd6c3ef84253d7c815bed85fc622ad207a9f8", + "reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "^4.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "time": "2019-06-08T11:03:04+00:00" + }, + { + "name": "doctrine/orm", + "version": "v2.7.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/orm.git", + "reference": "dafe298ce5d0b995ebe1746670704c0a35868a6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/orm/zipball/dafe298ce5d0b995ebe1746670704c0a35868a6a", + "reference": "dafe298ce5d0b995ebe1746670704c0a35868a6a", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.8", + "doctrine/cache": "^1.9.1", + "doctrine/collections": "^1.5", + "doctrine/common": "^2.11", + "doctrine/dbal": "^2.9.3", + "doctrine/event-manager": "^1.1", + "doctrine/instantiator": "^1.3", + "doctrine/persistence": "^1.2", + "ext-pdo": "*", + "ocramius/package-versions": "^1.2", + "php": "^7.1", + "symfony/console": "^3.0|^4.0|^5.0" + }, + "require-dev": { + "doctrine/coding-standard": "^5.0", + "phpunit/phpunit": "^7.5", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" + }, + "bin": [ + "bin/doctrine" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\ORM\\": "lib/Doctrine/ORM" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "Object-Relational-Mapper for PHP", + "homepage": "https://www.doctrine-project.org/projects/orm.html", + "keywords": [ + "database", + "orm" + ], + "time": "2020-03-19T06:41:02+00:00" + }, + { + "name": "doctrine/persistence", + "version": "1.3.7", + "source": { + "type": "git", + "url": "https://github.com/doctrine/persistence.git", + "reference": "0af483f91bada1c9ded6c2cfd26ab7d5ab2094e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/0af483f91bada1c9ded6c2cfd26ab7d5ab2094e0", + "reference": "0af483f91bada1c9ded6c2cfd26ab7d5ab2094e0", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.0", + "doctrine/cache": "^1.0", + "doctrine/collections": "^1.0", + "doctrine/event-manager": "^1.0", + "doctrine/reflection": "^1.2", + "php": "^7.1" + }, + "conflict": { + "doctrine/common": "<2.10@dev" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan": "^0.11", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common", + "Doctrine\\Persistence\\": "lib/Doctrine/Persistence" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "The Doctrine Persistence project is a set of shared interfaces and functionality that the different Doctrine object mappers share.", + "homepage": "https://doctrine-project.org/projects/persistence.html", + "keywords": [ + "mapper", + "object", + "odm", + "orm", + "persistence" + ], + "time": "2020-03-21T15:13:52+00:00" + }, + { + "name": "doctrine/reflection", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/reflection.git", + "reference": "55e71912dfcd824b2fdd16f2d9afe15684cfce79" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/reflection/zipball/55e71912dfcd824b2fdd16f2d9afe15684cfce79", + "reference": "55e71912dfcd824b2fdd16f2d9afe15684cfce79", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.0", + "ext-tokenizer": "*", + "php": "^7.1" + }, + "conflict": { + "doctrine/common": "<2.9" + }, + "require-dev": { + "doctrine/coding-standard": "^5.0", + "doctrine/common": "^2.10", + "phpstan/phpstan": "^0.11.0", + "phpstan/phpstan-phpunit": "^0.11.0", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "The Doctrine Reflection project is a simple library used by the various Doctrine projects which adds some additional functionality on top of the reflection functionality that comes with PHP. It allows you to get the reflection information about classes, methods and properties statically.", + "homepage": "https://www.doctrine-project.org/projects/reflection.html", + "keywords": [ + "reflection", + "static" + ], + "abandoned": "roave/better-reflection", + "time": "2020-03-27T11:06:43+00:00" + }, + { + "name": "egulias/email-validator", + "version": "2.1.17", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "ade6887fd9bd74177769645ab5c474824f8a418a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ade6887fd9bd74177769645ab5c474824f8a418a", + "reference": "ade6887fd9bd74177769645ab5c474824f8a418a", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^1.0.1", + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.10" + }, + "require-dev": { + "dominicsayers/isemail": "^3.0.7", + "phpunit/phpunit": "^4.8.36|^7.5.15", + "satooshi/php-coveralls": "^1.0.1" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "EmailValidator" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "time": "2020-02-13T22:36:52+00:00" + }, + { + "name": "eluceo/ical", + "version": "0.16.0", + "source": { + "type": "git", + "url": "https://github.com/markuspoerschke/iCal.git", + "reference": "97da0d94c9716e65c141066a2d96aa098379721b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/markuspoerschke/iCal/zipball/97da0d94c9716e65c141066a2d96aa098379721b", + "reference": "97da0d94c9716e65c141066a2d96aa098379721b", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "suggest": { + "ext-mbstring": "Massive performance enhancement of line folding" + }, + "type": "library", + "autoload": { + "psr-4": { + "Eluceo\\iCal\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Markus Poerschke", + "email": "markus@eluceo.de", + "role": "Developer" + } + ], + "description": "The eluceo/iCal package offers a abstraction layer for creating iCalendars. You can easily create iCal files by using PHP object instead of typing your *.ics file by hand. The output will follow RFC 5545 as best as possible.", + "homepage": "https://github.com/markuspoerschke/iCal", + "keywords": [ + "calendar", + "iCalendar", + "ical", + "ics", + "php calendar" + ], + "time": "2019-12-29T22:08:56+00:00" + }, + { + "name": "emojione/emojione", + "version": "v3.1.0", + "source": { + "type": "git", + "url": "https://github.com/emojione/emojione.git", + "reference": "4a166f9334809b5044ecf493f7decf47d50e0a8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/emojione/emojione/zipball/4a166f9334809b5044ecf493f7decf47d50e0a8a", + "reference": "4a166f9334809b5044ecf493f7decf47d50e0a8a", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.6 || ~5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Emojione\\": "lib/php/src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "(CC-BY-4.0 and MIT)" + ], + "description": "EmojiOne is a complete set of emojis designed for the web. It includes libraries to easily convert unicode characters to shortnames (:smile:) and shortnames to our custom emoji images. PNG format provided for the emoji images.", + "homepage": "http://www.emojione.com", + "keywords": [ + "emoji", + "emojione", + "emojis", + "emoticons", + "smileys", + "smilies", + "unicode" + ], + "abandoned": true, + "time": "2017-06-30T17:09:19+00:00" + }, + { + "name": "firebase/php-jwt", + "version": "v5.2.0", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "feb0e820b8436873675fd3aca04f3728eb2185cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/feb0e820b8436873675fd3aca04f3728eb2185cb", + "reference": "feb0e820b8436873675fd3aca04f3728eb2185cb", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": ">=4.8 <=9" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "time": "2020-03-25T18:49:23+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.5.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "43ece0e75098b7ecd8d13918293029e555a50f82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/43ece0e75098b7ecd8d13918293029e555a50f82", + "reference": "43ece0e75098b7ecd8d13918293029e555a50f82", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.6.1", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.1" + }, + "suggest": { + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.5-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2019-12-23T11:57:10+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-12-20T10:07:11+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "239400de7a173fe9901b9ac7c06497751f00727a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", + "reference": "239400de7a173fe9901b9ac7c06497751f00727a", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" + }, + "suggest": { + "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2019-07-01T23:21:34+00:00" + }, + { + "name": "http-interop/http-factory-guzzle", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/http-interop/http-factory-guzzle.git", + "reference": "34861658efb9899a6618cef03de46e2a52c80fc0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/http-interop/http-factory-guzzle/zipball/34861658efb9899a6618cef03de46e2a52c80fc0", + "reference": "34861658efb9899a6618cef03de46e2a52c80fc0", + "shasum": "" + }, + "require": { + "guzzlehttp/psr7": "^1.4.2", + "psr/http-factory": "^1.0" + }, + "provide": { + "psr/http-factory-implementation": "^1.0" + }, + "require-dev": { + "http-interop/http-factory-tests": "^0.5", + "phpunit/phpunit": "^6.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Http\\Factory\\Guzzle\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "An HTTP Factory using Guzzle PSR7", + "keywords": [ + "factory", + "http", + "psr-17", + "psr-7" + ], + "time": "2018-07-31T19:32:56+00:00" + }, + { + "name": "jdorn/sql-formatter", + "version": "v1.2.17", + "source": { + "type": "git", + "url": "https://github.com/jdorn/sql-formatter.git", + "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jdorn/sql-formatter/zipball/64990d96e0959dff8e059dfcdc1af130728d92bc", + "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc", + "shasum": "" + }, + "require": { + "php": ">=5.2.4" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "lib" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeremy Dorn", + "email": "jeremy@jeremydorn.com", + "homepage": "http://jeremydorn.com/" + } + ], + "description": "a PHP SQL highlighting library", + "homepage": "https://github.com/jdorn/sql-formatter/", + "keywords": [ + "highlight", + "sql" + ], + "time": "2014-01-12T16:20:24+00:00" + }, + { + "name": "jean85/pretty-package-versions", + "version": "1.2", + "source": { + "type": "git", + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/75c7effcf3f77501d0e0caa75111aff4daa0dd48", + "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48", + "shasum": "" + }, + "require": { + "ocramius/package-versions": "^1.2.0", + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A wrapper for ocramius/package-versions to get pretty versions strings", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "time": "2018-06-13T13:22:40+00:00" + }, + { + "name": "jeremeamia/superclosure", + "version": "2.4.0", + "source": { + "type": "git", + "url": "https://github.com/jeremeamia/super_closure.git", + "reference": "5707d5821b30b9a07acfb4d76949784aaa0e9ce9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jeremeamia/super_closure/zipball/5707d5821b30b9a07acfb4d76949784aaa0e9ce9", + "reference": "5707d5821b30b9a07acfb4d76949784aaa0e9ce9", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^1.2|^2.0|^3.0|^4.0", + "php": ">=5.4", + "symfony/polyfill-php56": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "psr-4": { + "SuperClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia", + "role": "Developer" + } + ], + "description": "Serialize Closure objects, including their context and binding", + "homepage": "https://github.com/jeremeamia/super_closure", + "keywords": [ + "closure", + "function", + "lambda", + "parser", + "serializable", + "serialize", + "tokenizer" + ], + "abandoned": "opis/closure", + "time": "2018-03-21T22:21:57+00:00" + }, + { + "name": "justinrainbow/json-schema", + "version": "5.2.9", + "source": { + "type": "git", + "url": "https://github.com/justinrainbow/json-schema.git", + "reference": "44c6787311242a979fa15c704327c20e7221a0e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/44c6787311242a979fa15c704327c20e7221a0e4", + "reference": "44c6787311242a979fa15c704327c20e7221a0e4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", + "json-schema/json-schema-test-suite": "1.2.0", + "phpunit/phpunit": "^4.8.35" + }, + "bin": [ + "bin/validate-json" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "JsonSchema\\": "src/JsonSchema/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bruno Prieto Reis", + "email": "bruno.p.reis@gmail.com" + }, + { + "name": "Justin Rainbow", + "email": "justin.rainbow@gmail.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Robert SchΓΆnthal", + "email": "seroscho@googlemail.com" + } + ], + "description": "A library to validate a json schema.", + "homepage": "https://github.com/justinrainbow/json-schema", + "keywords": [ + "json", + "schema" + ], + "time": "2019-09-25T14:49:45+00:00" + }, + { + "name": "mtdowling/jmespath.php", + "version": "2.5.0", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "52168cb9472de06979613d365c7f1ab8798be895" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/52168cb9472de06979613d365c7f1ab8798be895", + "reference": "52168cb9472de06979613d365c7f1ab8798be895", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "symfony/polyfill-mbstring": "^1.4" + }, + "require-dev": { + "composer/xdebug-handler": "^1.2", + "phpunit/phpunit": "^4.8.36|^7.5.15" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev" + } + }, + "autoload": { + "psr-4": { + "JmesPath\\": "src/" + }, + "files": [ + "src/JmesPath.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "time": "2019-12-30T18:03:34+00:00" + }, + { + "name": "mxp100/pusher", + "version": "dev-twake-1.0", + "source": { + "type": "git", + "url": "https://github.com/Twake/Pusher.git", + "reference": "7c410b3b0ec491a7e70f57fd4a81f56af30dc7b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Twake/Pusher/zipball/7c410b3b0ec491a7e70f57fd4a81f56af30dc7b3", + "reference": "7c410b3b0ec491a7e70f57fd4a81f56af30dc7b3", + "shasum": "" + }, + "require": { + "ext-json": ">=1.3.7", + "php": "^7.0" + }, + "suggest": { + "ext-curl": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "Pusher\\": "src/Pusher/" + } + }, + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Yuriy Potemkin" + } + ], + "description": "PHP push notifications to APNS, FCM", + "keywords": [ + "apns", + "fcm", + "notifications", + "push" + ], + "support": { + "source": "https://github.com/TwakeApp/Pusher/tree/master" + }, + "time": "2020-03-21T13:52:43+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.9.5", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/b2c28789e80a97badd14145fda39b545d83ca3ef", + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2020-01-17T21:11:47+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.3.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "9a9981c347c5c49d6dfe5cf826bb882b824080dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/9a9981c347c5c49d6dfe5cf826bb882b824080dc", + "reference": "9a9981c347c5c49d6dfe5cf826bb882b824080dc", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "0.0.5", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "time": "2019-11-08T13:50:10+00:00" + }, + { + "name": "ocramius/package-versions", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/Ocramius/PackageVersions.git", + "reference": "44af6f3a2e2e04f2af46bcb302ad9600cba41c7d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/44af6f3a2e2e04f2af46bcb302ad9600cba41c7d", + "reference": "44af6f3a2e2e04f2af46bcb302ad9600cba41c7d", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0.0", + "php": "^7.1.0" + }, + "require-dev": { + "composer/composer": "^1.6.3", + "doctrine/coding-standard": "^5.0.1", + "ext-zip": "*", + "infection/infection": "^0.7.1", + "phpunit/phpunit": "^7.5.17" + }, + "type": "composer-plugin", + "extra": { + "class": "PackageVersions\\Installer", + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "PackageVersions\\": "src/PackageVersions" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", + "time": "2019-11-15T16:17:10+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.99", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", + "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", + "shasum": "" + }, + "require": { + "php": "^7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "time": "2018-07-02T15:55:56+00:00" + }, + { + "name": "pecee/simple-router", + "version": "4.2.0.6", + "source": { + "type": "git", + "url": "https://github.com/skipperbent/simple-php-router.git", + "reference": "b715c48415d5e3660df668350152bba8798a6e33" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/skipperbent/simple-php-router/zipball/b715c48415d5e3660df668350152bba8798a6e33", + "reference": "b715c48415d5e3660df668350152bba8798a6e33", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=7.1", + "php-di/php-di": "^6.0" + }, + "require-dev": { + "mockery/mockery": "^1", + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Pecee\\": "src/Pecee/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Simon SessingΓΈ", + "email": "simon.sessingoe@gmail.com" + } + ], + "description": "Simple, fast PHP router that is easy to get integrated and in almost any project. Heavily inspired by the Laravel router.", + "keywords": [ + "framework", + "input-handler", + "laravel", + "pecee", + "php", + "request-handler", + "route", + "router", + "routing", + "routing-engine", + "simple-php-router", + "url-handling" + ], + "time": "2018-11-24T23:47:02+00:00" + }, + { + "name": "php-amqplib/php-amqplib", + "version": "v2.11.3", + "source": { + "type": "git", + "url": "https://github.com/php-amqplib/php-amqplib.git", + "reference": "6353c5d2d3021a301914bc6566e695c99cfeb742" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-amqplib/php-amqplib/zipball/6353c5d2d3021a301914bc6566e695c99cfeb742", + "reference": "6353c5d2d3021a301914bc6566e695c99cfeb742", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-sockets": "*", + "php": ">=5.6.3", + "phpseclib/phpseclib": "^2.0.0" + }, + "conflict": { + "php": "7.4.0 - 7.4.1" + }, + "replace": { + "videlalvaro/php-amqplib": "self.version" + }, + "require-dev": { + "ext-curl": "*", + "nategood/httpful": "^0.2.20", + "phpunit/phpunit": "^5.7|^6.5|^7.0", + "squizlabs/php_codesniffer": "^2.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.11-dev" + } + }, + "autoload": { + "psr-4": { + "PhpAmqpLib\\": "PhpAmqpLib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Alvaro Videla", + "role": "Original Maintainer" + }, + { + "name": "RaΓΊl Araya", + "email": "nubeiro@gmail.com", + "role": "Maintainer" + }, + { + "name": "Luke Bakken", + "email": "luke@bakken.io", + "role": "Maintainer" + }, + { + "name": "RamΕ«nas Dronga", + "email": "github@ramuno.lt", + "role": "Maintainer" + } + ], + "description": "Formerly videlalvaro/php-amqplib. This library is a pure PHP implementation of the AMQP protocol. It's been tested against RabbitMQ.", + "homepage": "https://github.com/php-amqplib/php-amqplib/", + "keywords": [ + "message", + "queue", + "rabbitmq" + ], + "time": "2020-05-13T13:56:11+00:00" + }, + { + "name": "php-di/invoker", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/Invoker.git", + "reference": "540c27c86f663e20fe39a24cd72fa76cdb21d41a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/540c27c86f663e20fe39a24cd72fa76cdb21d41a", + "reference": "540c27c86f663e20fe39a24cd72fa76cdb21d41a", + "shasum": "" + }, + "require": { + "psr/container": "~1.0" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "phpunit/phpunit": "~4.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Invoker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Generic and extensible callable invoker", + "homepage": "https://github.com/PHP-DI/Invoker", + "keywords": [ + "callable", + "dependency", + "dependency-injection", + "injection", + "invoke", + "invoker" + ], + "time": "2017-03-20T19:28:22+00:00" + }, + { + "name": "php-di/php-di", + "version": "6.0.11", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PHP-DI.git", + "reference": "9bdcc2f41f5fb700ddd01bc4fa8d5bd7b3f94620" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/9bdcc2f41f5fb700ddd01bc4fa8d5bd7b3f94620", + "reference": "9bdcc2f41f5fb700ddd01bc4fa8d5bd7b3f94620", + "shasum": "" + }, + "require": { + "jeremeamia/superclosure": "^2.0", + "nikic/php-parser": "^2.0|^3.0|^4.0", + "php": ">=7.0.0", + "php-di/invoker": "^2.0", + "php-di/phpdoc-reader": "^2.0.1", + "psr/container": "^1.0" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "require-dev": { + "doctrine/annotations": "~1.2", + "friendsofphp/php-cs-fixer": "^2.4", + "mnapoli/phpunit-easymock": "~1.0", + "ocramius/proxy-manager": "~2.0.2", + "phpstan/phpstan": "^0.9.2", + "phpunit/phpunit": "~6.4" + }, + "suggest": { + "doctrine/annotations": "Install it if you want to use annotations (version ~1.2)", + "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ~2.0)" + }, + "type": "library", + "autoload": { + "psr-4": { + "DI\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The dependency injection container for humans", + "homepage": "http://php-di.org/", + "keywords": [ + "PSR-11", + "container", + "container-interop", + "dependency injection", + "di", + "ioc", + "psr11" + ], + "time": "2019-12-12T07:58:02+00:00" + }, + { + "name": "php-di/phpdoc-reader", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PhpDocReader.git", + "reference": "15678f7451c020226807f520efb867ad26fbbfcf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PhpDocReader/zipball/15678f7451c020226807f520efb867ad26fbbfcf", + "reference": "15678f7451c020226807f520efb867ad26fbbfcf", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpDocReader\\": "src/PhpDocReader" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PhpDocReader parses @var and @param values in PHP docblocks (supports namespaced class names with the same resolution rules as PHP)", + "keywords": [ + "phpdoc", + "reflection" + ], + "time": "2019-09-26T11:24:58+00:00" + }, + { + "name": "php-http/client-common", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/client-common.git", + "reference": "e37e46c610c87519753135fb893111798c69076a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/client-common/zipball/e37e46c610c87519753135fb893111798c69076a", + "reference": "e37e46c610c87519753135fb893111798c69076a", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "php-http/httplug": "^2.0", + "php-http/message": "^1.6", + "php-http/message-factory": "^1.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "symfony/options-resolver": "^2.6 || ^3.4.20 || ~4.0.15 || ~4.1.9 || ^4.2.1 || ^5.0", + "symfony/polyfill-php80": "^1.17" + }, + "require-dev": { + "doctrine/instantiator": "^1.1", + "guzzlehttp/psr7": "^1.4", + "nyholm/psr7": "^1.2", + "phpspec/phpspec": "^5.1 || ^6.0", + "phpspec/prophecy": "^1.10.2", + "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.3" + }, + "suggest": { + "ext-json": "To detect JSON responses with the ContentTypePlugin", + "ext-libxml": "To detect XML responses with the ContentTypePlugin", + "php-http/cache-plugin": "PSR-6 Cache plugin", + "php-http/logger-plugin": "PSR-3 Logger plugin", + "php-http/stopwatch-plugin": "Symfony Stopwatch plugin" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Client\\Common\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "MΓ‘rk SΓ‘gi-KazΓ‘r", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Common HTTP Client implementations and tools for HTTPlug", + "homepage": "http://httplug.io", + "keywords": [ + "client", + "common", + "http", + "httplug" + ], + "time": "2020-07-21T10:04:13+00:00" + }, + { + "name": "php-http/discovery", + "version": "1.9.1", + "source": { + "type": "git", + "url": "https://github.com/php-http/discovery.git", + "reference": "64a18cc891957e05d91910b3c717d6bd11fbede9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/discovery/zipball/64a18cc891957e05d91910b3c717d6bd11fbede9", + "reference": "64a18cc891957e05d91910b3c717d6bd11fbede9", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "nyholm/psr7": "<1.0" + }, + "require-dev": { + "graham-campbell/phpspec-skip-example-extension": "^5.0", + "php-http/httplug": "^1.0 || ^2.0", + "php-http/message-factory": "^1.0", + "phpspec/phpspec": "^5.1 || ^6.1", + "puli/composer-plugin": "1.0.0-beta10" + }, + "suggest": { + "php-http/message": "Allow to use Guzzle, Diactoros or Slim Framework factories", + "puli/composer-plugin": "Sets up Puli which is recommended for Discovery to work. Check http://docs.php-http.org/en/latest/discovery.html for more details." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Discovery\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "MΓ‘rk SΓ‘gi-KazΓ‘r", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Finds installed HTTPlug implementations and PSR-7 message factories", + "homepage": "http://php-http.org", + "keywords": [ + "adapter", + "client", + "discovery", + "factory", + "http", + "message", + "psr7" + ], + "time": "2020-07-13T15:44:45+00:00" + }, + { + "name": "php-http/guzzle6-adapter", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-http/guzzle6-adapter.git", + "reference": "6074a4b1f4d5c21061b70bab3b8ad484282fe31f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/guzzle6-adapter/zipball/6074a4b1f4d5c21061b70bab3b8ad484282fe31f", + "reference": "6074a4b1f4d5c21061b70bab3b8ad484282fe31f", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^6.0", + "php": "^7.1", + "php-http/httplug": "^2.0", + "psr/http-client": "^1.0" + }, + "provide": { + "php-http/async-client-implementation": "1.0", + "php-http/client-implementation": "1.0", + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "ext-curl": "*", + "php-http/client-integration-tests": "^2.0", + "phpunit/phpunit": "^7.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Adapter\\Guzzle6\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "MΓ‘rk SΓ‘gi-KazΓ‘r", + "email": "mark.sagikazar@gmail.com" + }, + { + "name": "David de Boer", + "email": "david@ddeboer.nl" + } + ], + "description": "Guzzle 6 HTTP Adapter", + "homepage": "http://httplug.io", + "keywords": [ + "Guzzle", + "http" + ], + "time": "2018-12-16T14:44:03+00:00" + }, + { + "name": "php-http/httplug", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/httplug.git", + "reference": "191a0a1b41ed026b717421931f8d3bd2514ffbf9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/httplug/zipball/191a0a1b41ed026b717421931f8d3bd2514ffbf9", + "reference": "191a0a1b41ed026b717421931f8d3bd2514ffbf9", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "php-http/promise": "^1.1", + "psr/http-client": "^1.0", + "psr/http-message": "^1.0" + }, + "require-dev": { + "friends-of-phpspec/phpspec-code-coverage": "^4.1", + "phpspec/phpspec": "^5.1 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eric GELOEN", + "email": "geloen.eric@gmail.com" + }, + { + "name": "MΓ‘rk SΓ‘gi-KazΓ‘r", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "HTTPlug, the HTTP client abstraction for PHP", + "homepage": "http://httplug.io", + "keywords": [ + "client", + "http" + ], + "time": "2020-07-13T15:43:23+00:00" + }, + { + "name": "php-http/message", + "version": "1.9.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/message.git", + "reference": "2c7256e3c1aba0bfca70f099810f1c7712e00945" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/message/zipball/2c7256e3c1aba0bfca70f099810f1c7712e00945", + "reference": "2c7256e3c1aba0bfca70f099810f1c7712e00945", + "shasum": "" + }, + "require": { + "clue/stream-filter": "^1.4.1", + "php": "^7.1", + "php-http/message-factory": "^1.0.2", + "psr/http-message": "^1.0" + }, + "provide": { + "php-http/message-factory-implementation": "1.0" + }, + "require-dev": { + "akeneo/phpspec-skip-example-extension": "^1.0", + "coduo/phpspec-data-provider-extension": "^1.0", + "ergebnis/composer-normalize": "^2.1", + "ext-zlib": "*", + "guzzlehttp/psr7": "^1.0", + "henrikbjorn/phpspec-code-coverage": "^1.0", + "phpspec/phpspec": "^2.4", + "slim/slim": "^3.0", + "zendframework/zend-diactoros": "^1.0" + }, + "suggest": { + "ext-zlib": "Used with compressor/decompressor streams", + "guzzlehttp/psr7": "Used with Guzzle PSR-7 Factories", + "slim/slim": "Used with Slim Framework PSR-7 implementation", + "zendframework/zend-diactoros": "Used with Diactoros Factories" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Message\\": "src/" + }, + "files": [ + "src/filters.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "MΓ‘rk SΓ‘gi-KazΓ‘r", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "HTTP Message related tools", + "homepage": "http://php-http.org", + "keywords": [ + "http", + "message", + "psr-7" + ], + "time": "2020-08-17T06:33:14+00:00" + }, + { + "name": "php-http/message-factory", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-http/message-factory.git", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/message-factory/zipball/a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "MΓ‘rk SΓ‘gi-KazΓ‘r", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Factory interfaces for PSR-7 HTTP Message", + "homepage": "http://php-http.org", + "keywords": [ + "factory", + "http", + "message", + "stream", + "uri" + ], + "time": "2015-12-19T14:08:53+00:00" + }, + { + "name": "php-http/promise", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/promise.git", + "reference": "4c4c1f9b7289a2ec57cde7f1e9762a5789506f88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/promise/zipball/4c4c1f9b7289a2ec57cde7f1e9762a5789506f88", + "reference": "4c4c1f9b7289a2ec57cde7f1e9762a5789506f88", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "friends-of-phpspec/phpspec-code-coverage": "^4.3.2", + "phpspec/phpspec": "^5.1.2 || ^6.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Joel Wurtz", + "email": "joel.wurtz@gmail.com" + }, + { + "name": "MΓ‘rk SΓ‘gi-KazΓ‘r", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Promise used for asynchronous HTTP requests", + "homepage": "http://httplug.io", + "keywords": [ + "promise" + ], + "time": "2020-07-07T09:29:14+00:00" + }, + { + "name": "php-opencloud/openstack", + "version": "v3.0.7", + "source": { + "type": "git", + "url": "https://github.com/php-opencloud/openstack.git", + "reference": "5d73ff577731fc473448c489acfca9730aa39c88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-opencloud/openstack/zipball/5d73ff577731fc473448c489acfca9730aa39c88", + "reference": "5d73ff577731fc473448c489acfca9730aa39c88", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^6.1", + "justinrainbow/json-schema": "^5.2", + "php": "~7.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.13", + "jakub-onderka/php-parallel-lint": "^1.0", + "php-coveralls/php-coveralls": "^2.0", + "phpunit/phpunit": "^6.5", + "psr/log": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "OpenStack\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Jamie Hannaford", + "email": "jamie.hannaford@rackspace.com", + "homepage": "https://github.com/jamiehannaford" + }, + { + "name": "Ha Phan", + "email": "thanhha.work@gmail.com", + "homepage": "https://github.com/haphan" + } + ], + "description": "PHP SDK for OpenStack APIs. Supports BlockStorage, Compute, Identity, Images, Networking and Metric Gnocchi", + "homepage": "https://github.com/php-opencloud/openstack", + "keywords": [ + "Openstack", + "api", + "php", + "sdk" + ], + "time": "2020-01-07T08:46:53+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "~6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2018-08-07T13:53:10+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "4.3.4", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/da3fd972d6bafd628114f7e7e036f45944b62e9c", + "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c", + "shasum": "" + }, + "require": { + "php": "^7.0", + "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", + "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "doctrine/instantiator": "^1.0.5", + "mockery/mockery": "^1.0", + "phpdocumentor/type-resolver": "0.4.*", + "phpunit/phpunit": "^6.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2019-12-28T18:55:12+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "shasum": "" + }, + "require": { + "php": "^7.1", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "^7.1", + "mockery/mockery": "~1", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "time": "2019-08-22T18:11:29+00:00" + }, + { + "name": "phpseclib/phpseclib", + "version": "2.0.27", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "34620af4df7d1988d8f0d7e91f6c8a3bf931d8dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/34620af4df7d1988d8f0d7e91f6c8a3bf931d8dc", + "reference": "34620af4df7d1988d8f0d7e91f6c8a3bf931d8dc", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phing/phing": "~2.7", + "phpunit/phpunit": "^4.8.35|^5.7|^6.0", + "sami/sami": "~2.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "suggest": { + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + }, + "type": "library", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-JΓΌrgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "time": "2020-04-04T23:17:33+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.10.3", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "451c3cd1418cf640de218914901e51b064abb093" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093", + "reference": "451c3cd1418cf640de218914901e51b064abb093", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", + "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5 || ^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2020-03-05T15:02:03+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d", + "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^5.6 || ^7.0", + "phpunit/php-file-iterator": "^1.3", + "phpunit/php-text-template": "^1.2", + "phpunit/php-token-stream": "^1.4.2 || ^2.0", + "sebastian/code-unit-reverse-lookup": "^1.0", + "sebastian/environment": "^1.3.2 || ^2.0", + "sebastian/version": "^1.0 || ^2.0" + }, + "require-dev": { + "ext-xdebug": "^2.1.4", + "phpunit/phpunit": "^5.7" + }, + "suggest": { + "ext-xdebug": "^2.5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2017-04-02T07:44:40+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2017-11-27T13:52:08+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2017-02-26T11:10:40+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "791198a2c6254db10131eecfe8c06670700904db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", + "reference": "791198a2c6254db10131eecfe8c06670700904db", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.2.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "abandoned": true, + "time": "2017-11-27T05:48:46+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "5.7.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "00d72b8dbd2bb7d6f02a820e6db5cb70df6ac55c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/00d72b8dbd2bb7d6f02a820e6db5cb70df6ac55c", + "reference": "00d72b8dbd2bb7d6f02a820e6db5cb70df6ac55c", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "~1.3", + "php": "^5.6 || ^7.0", + "phpspec/prophecy": "^1.3.1", + "phpunit/php-code-coverage": "^4.0.3", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "^3.2", + "sebastian/comparator": "~1.2.2", + "sebastian/diff": "~1.2", + "sebastian/environment": "^1.3.4 || ^2.0", + "sebastian/exporter": "~2.0", + "sebastian/global-state": "~1.0", + "sebastian/object-enumerator": "~2.0", + "sebastian/resource-operations": "~1.0", + "sebastian/version": "~1.0|~2.0", + "symfony/yaml": "~2.1|~3.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "3.0.2" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-xdebug": "*", + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.7.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2016-12-01T17:04:00+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "3.4.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "a23b761686d50a560cc56233b9ecf49597cc9118" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118", + "reference": "a23b761686d50a560cc56233b9ecf49597cc9118", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.6 || ^7.0", + "phpunit/php-text-template": "^1.2", + "sebastian/exporter": "^1.2 || ^2.0" + }, + "conflict": { + "phpunit/phpunit": "<5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "abandoned": true, + "time": "2017-06-30T09:13:00+00:00" + }, + { + "name": "pimple/pimple", + "version": "v3.2.3", + "source": { + "type": "git", + "url": "https://github.com/silexphp/Pimple.git", + "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/9e403941ef9d65d20cba7d54e29fe906db42cf32", + "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/container": "^1.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2.x-dev" + } + }, + "autoload": { + "psr-0": { + "Pimple": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Pimple, a simple Dependency Injection Container", + "homepage": "http://pimple.sensiolabs.org", + "keywords": [ + "container", + "dependency injection" + ], + "time": "2018-01-21T07:42:36+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "time": "2016-08-06T20:24:11+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "time": "2020-06-29T06:28:15+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "time": "2019-04-30T12:38:16+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2020-03-23T09:12:05+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "ramsey/uuid", + "version": "3.9.3", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/7e1633a6964b48589b142d60542f9ed31bd37a92", + "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92", + "shasum": "" + }, + "require": { + "ext-json": "*", + "paragonie/random_compat": "^1 | ^2 | 9.99.99", + "php": "^5.4 | ^7 | ^8", + "symfony/polyfill-ctype": "^1.8" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "codeception/aspect-mock": "^1 | ^2", + "doctrine/annotations": "^1.2", + "goaop/framework": "1.0.0-alpha.2 | ^1 | ^2.1", + "jakub-onderka/php-parallel-lint": "^1", + "mockery/mockery": "^0.9.11 | ^1", + "moontoast/math": "^1.1", + "paragonie/random-lib": "^2", + "php-mock/php-mock-phpunit": "^0.3 | ^1.1", + "phpunit/phpunit": "^4.8 | ^5.4 | ^6.5", + "squizlabs/php_codesniffer": "^3.5" + }, + "suggest": { + "ext-ctype": "Provides support for PHP Ctype functions", + "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", + "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator", + "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", + "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Ramsey\\Uuid\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + }, + { + "name": "Marijn Huizendveld", + "email": "marijn.huizendveld@gmail.com" + }, + { + "name": "Thibaud Fabre", + "email": "thibaud@aztech.io" + } + ], + "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", + "homepage": "https://github.com/ramsey/uuid", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "time": "2020-02-21T04:36:14+00:00" + }, + { + "name": "ramsey/uuid-doctrine", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid-doctrine.git", + "reference": "9facc4689547e72e03c1e18df4a0ee162b2778b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid-doctrine/zipball/9facc4689547e72e03c1e18df4a0ee162b2778b0", + "reference": "9facc4689547e72e03c1e18df4a0ee162b2778b0", + "shasum": "" + }, + "require": { + "doctrine/orm": "^2.5", + "php": "^5.4 | ^7 | ^8", + "ramsey/uuid": "^3.5 | ^4" + }, + "require-dev": { + "jakub-onderka/php-parallel-lint": "^1", + "mockery/mockery": "^0.9 | ^1", + "phpunit/phpunit": "^4.8.36 | ^5.7 | ^6.5 | ^7", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Ramsey\\Uuid\\Doctrine\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Allow the use of ramsey/uuid as a Doctrine field type.", + "homepage": "https://github.com/ramsey/uuid-doctrine", + "keywords": [ + "database", + "doctrine", + "guid", + "identifier", + "uuid" + ], + "time": "2020-01-27T05:09:17+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2017-03-04T06:30:41+00:00" + }, + { + "name": "sebastian/comparator", + "version": "1.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2 || ~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2017-01-29T09:50:25+00:00" + }, + { + "name": "sebastian/diff", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2017-05-22T07:24:03+00:00" + }, + { + "name": "sebastian/environment", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2016-11-26T07:53:53+00:00" + }, + { + "name": "sebastian/exporter", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~2.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2016-11-19T08:54:04+00:00" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-10-12T03:26:01+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7", + "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7", + "shasum": "" + }, + "require": { + "php": ">=5.6", + "sebastian/recursion-context": "~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2017-02-18T15:18:39+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2016-11-19T07:33:16+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28T20:34:47+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "segmentio/analytics-php", + "version": "1.5.2", + "source": { + "type": "git", + "url": "https://github.com/segmentio/analytics-php.git", + "reference": "9513e3762ab24c9abd00078b0fb9e185aec10e07" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/segmentio/analytics-php/zipball/9513e3762ab24c9abd00078b0fb9e185aec10e07", + "reference": "9513e3762ab24c9abd00078b0fb9e185aec10e07", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "bin": [ + "bin/analytics" + ], + "type": "library", + "autoload": { + "files": [ + "lib/Segment.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Segment.io ", + "homepage": "https://segment.com/" + } + ], + "description": "Segment Analytics PHP Library", + "homepage": "https://segment.com/libraries/php", + "keywords": [ + "analytics", + "analytics.js", + "segment", + "segmentio" + ], + "time": "2017-08-18T22:13:00+00:00" + }, + { + "name": "sentry/sdk", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/getsentry/sentry-php-sdk.git", + "reference": "18921af9c2777517ef9fb480845c22a98554d6af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/getsentry/sentry-php-sdk/zipball/18921af9c2777517ef9fb480845c22a98554d6af", + "reference": "18921af9c2777517ef9fb480845c22a98554d6af", + "shasum": "" + }, + "require": { + "http-interop/http-factory-guzzle": "^1.0", + "php-http/guzzle6-adapter": "^1.1|^2.0", + "sentry/sentry": "^2.3" + }, + "type": "metapackage", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sentry", + "email": "accounts@sentry.io" + } + ], + "description": "This is a metapackage shipping sentry/sentry with a recommended http client.", + "time": "2020-01-08T19:16:29+00:00" + }, + { + "name": "sentry/sentry", + "version": "2.4.3", + "source": { + "type": "git", + "url": "https://github.com/getsentry/sentry-php.git", + "reference": "89fd1f91657b33ec9139f33f8a201eb086276103" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/89fd1f91657b33ec9139f33f8a201eb086276103", + "reference": "89fd1f91657b33ec9139f33f8a201eb086276103", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "guzzlehttp/promises": "^1.3", + "guzzlehttp/psr7": "^1.6", + "jean85/pretty-package-versions": "^1.2", + "php": "^7.1", + "php-http/async-client-implementation": "^1.0", + "php-http/client-common": "^1.5|^2.0", + "php-http/discovery": "^1.6.1", + "php-http/httplug": "^1.1|^2.0", + "php-http/message": "^1.5", + "psr/http-factory": "^1.0", + "psr/http-message-implementation": "^1.0", + "psr/log": "^1.0", + "symfony/options-resolver": "^2.7|^3.0|^4.0|^5.0", + "symfony/polyfill-uuid": "^1.13.1" + }, + "conflict": { + "php-http/client-common": "1.8.0", + "raven/raven": "*" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.16", + "monolog/monolog": "^1.3|^2.0", + "php-http/mock-client": "^1.3", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpunit/phpunit": "^7.5.18", + "symfony/phpunit-bridge": "^4.3|^5.0", + "vimeo/psalm": "^3.4" + }, + "suggest": { + "monolog/monolog": "Allow sending log messages to Sentry by using the included Monolog handler." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Sentry\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sentry", + "email": "accounts@sentry.io" + } + ], + "description": "A PHP SDK for Sentry (http://sentry.io)", + "homepage": "http://sentry.io", + "keywords": [ + "crash-reporting", + "crash-reports", + "error-handler", + "error-monitoring", + "log", + "logging", + "sentry" + ], + "time": "2020-08-13T10:54:32+00:00" + }, + { + "name": "soleon/sc-php", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/soleon-leiloes/sc-php.git", + "reference": "7c8f9169be5cefbe87d87adf2f2dcf59132706b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/soleon-leiloes/sc-php/zipball/7c8f9169be5cefbe87d87adf2f2dcf59132706b2", + "reference": "7c8f9169be5cefbe87d87adf2f2dcf59132706b2", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "textalk/websocket": "1.0.*" + }, + "require-dev": { + "illuminate/broadcasting": "5.2.*", + "mockery/mockery": "0.9.*", + "phpunit/phpunit": "~4.0", + "pimple/pimple": "~3.0" + }, + "suggest": { + "laravel/framework": "Framework Laravel (5.2.*)" + }, + "type": "library", + "autoload": { + "psr-4": { + "SocketCluster\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Renato Moura", + "email": "renato@soleon.com.br" + } + ], + "description": "SocketCluster - PHP library for interacting with the SocketCluster.io", + "homepage": "https://github.com/soleon-leiloes/sc-php", + "keywords": [ + "Broadcasting", + "laravel", + "php", + "realtime", + "socketcluster" + ], + "time": "2016-07-27T15:19:21+00:00" + }, + { + "name": "spatie/pdf-to-text", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/pdf-to-text.git", + "reference": "53b43c592c0a3f2df7bc0ceb48c6ce8bd51bb7e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/pdf-to-text/zipball/53b43c592c0a3f2df7bc0ceb48c6ce8bd51bb7e5", + "reference": "53b43c592c0a3f2df7bc0ceb48c6ce8bd51bb7e5", + "shasum": "" + }, + "require": { + "php": "^7.0", + "symfony/process": "^3.3|^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\PdfToText\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Extract text from a pdf", + "homepage": "https://github.com/spatie/pdf-to-text", + "keywords": [ + "pdf-to-text", + "spatie" + ], + "time": "2019-05-15T06:12:04+00:00" + }, + { + "name": "swiftmailer/swiftmailer", + "version": "v6.2.3", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "149cfdf118b169f7840bbe3ef0d4bc795d1780c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/149cfdf118b169f7840bbe3ef0d4bc795d1780c9", + "reference": "149cfdf118b169f7840bbe3ef0d4bc795d1780c9", + "shasum": "" + }, + "require": { + "egulias/email-validator": "~2.0", + "php": ">=7.0.0", + "symfony/polyfill-iconv": "^1.0", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "require-dev": { + "mockery/mockery": "~0.9.1", + "symfony/phpunit-bridge": "^3.4.19|^4.1.8" + }, + "suggest": { + "ext-intl": "Needed to support internationalized email addresses", + "true/punycode": "Needed to support internationalized email addresses, if ext-intl is not installed" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.2-dev" + } + }, + "autoload": { + "files": [ + "lib/swift_required.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Corbyn" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Swiftmailer, free feature-rich PHP mailer", + "homepage": "https://swiftmailer.symfony.com", + "keywords": [ + "email", + "mail", + "mailer" + ], + "time": "2019-11-12T09:31:26+00:00" + }, + { + "name": "symfony/cache", + "version": "v4.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "f20dcf48ecee66ab5ad7ccf4b3b55392b660c3d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/f20dcf48ecee66ab5ad7ccf4b3b55392b660c3d9", + "reference": "f20dcf48ecee66ab5ad7ccf4b3b55392b660c3d9", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "psr/cache": "~1.0", + "psr/log": "~1.0", + "symfony/cache-contracts": "^1.1.7|^2", + "symfony/service-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.2|^5.0" + }, + "conflict": { + "doctrine/dbal": "<2.5", + "symfony/dependency-injection": "<3.4", + "symfony/http-kernel": "<4.4", + "symfony/var-dumper": "<4.4" + }, + "provide": { + "psr/cache-implementation": "1.0", + "psr/simple-cache-implementation": "1.0", + "symfony/cache-implementation": "1.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/cache": "~1.6", + "doctrine/dbal": "~2.5", + "predis/predis": "~1.1", + "psr/simple-cache": "^1.0", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.1|^5.0", + "symfony/var-dumper": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Cache component with PSR-6, PSR-16, and tags", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "time": "2020-03-17T19:51:46+00:00" + }, + { + "name": "symfony/cache-contracts", + "version": "v1.1.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "af50d14ada9e4e82cfabfabdc502d144f89be0a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/af50d14ada9e4e82cfabfabdc502d144f89be0a1", + "reference": "af50d14ada9e4e82cfabfabdc502d144f89be0a1", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "psr/cache": "^1.0" + }, + "suggest": { + "symfony/cache-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-10-04T21:43:27+00:00" + }, + { + "name": "symfony/config", + "version": "v4.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "235e5afffd3a1a1b0dd0221973cbf670bc3be1d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/235e5afffd3a1a1b0dd0221973cbf670bc3be1d4", + "reference": "235e5afffd3a1a1b0dd0221973cbf670bc3be1d4", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/finder": "<3.4" + }, + "require-dev": { + "symfony/event-dispatcher": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/messenger": "^4.1|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Config Component", + "homepage": "https://symfony.com", + "time": "2020-03-16T11:24:17+00:00" + }, + { + "name": "symfony/console", + "version": "v4.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "20bc0c1068565103075359f5ce9e0639b36f92d1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/20bc0c1068565103075359f5ce9e0639b36f92d1", + "reference": "20bc0c1068565103075359f5ce9e0639b36f92d1", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/dependency-injection": "<3.4", + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/lock": "<4.4", + "symfony/process": "<3.3" + }, + "provide": { + "psr/log-implementation": "1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/event-dispatcher": "^4.3", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^4.3|^5.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2020-03-16T08:56:54+00:00" + }, + { + "name": "symfony/debug", + "version": "v4.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "aeb73aca16a8f1fe958230fe44e6cf4c84cbb85e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/aeb73aca16a8f1fe958230fe44e6cf4c84cbb85e", + "reference": "aeb73aca16a8f1fe958230fe44e6cf4c84cbb85e", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "~1.0", + "symfony/polyfill-php80": "^1.15" + }, + "conflict": { + "symfony/http-kernel": "<3.4" + }, + "require-dev": { + "symfony/http-kernel": "^3.4|^4.0|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Debug Component", + "homepage": "https://symfony.com", + "time": "2020-08-10T07:47:39+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v4.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "b4242fc7f18c8bf5427f84d5afe2131c9b323a04" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/b4242fc7f18c8bf5427f84d5afe2131c9b323a04", + "reference": "b4242fc7f18c8bf5427f84d5afe2131c9b323a04", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "psr/container": "^1.0", + "symfony/service-contracts": "^1.1.6|^2" + }, + "conflict": { + "symfony/config": "<4.3|>=5.0", + "symfony/finder": "<3.4", + "symfony/proxy-manager-bridge": "<3.4", + "symfony/yaml": "<3.4" + }, + "provide": { + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0" + }, + "require-dev": { + "symfony/config": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/config": "", + "symfony/expression-language": "For using expressions in service container configuration", + "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony DependencyInjection Component", + "homepage": "https://symfony.com", + "time": "2020-03-18T07:51:32+00:00" + }, + { + "name": "symfony/doctrine-bridge", + "version": "v4.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/doctrine-bridge.git", + "reference": "57a825089b7a9851fe552b08ed83f7625352c9ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/57a825089b7a9851fe552b08ed83f7625352c9ab", + "reference": "57a825089b7a9851fe552b08ed83f7625352c9ab", + "shasum": "" + }, + "require": { + "doctrine/event-manager": "~1.0", + "doctrine/persistence": "^1.3", + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/dependency-injection": "<3.4", + "symfony/form": "<4.4", + "symfony/http-kernel": "<4.3.7", + "symfony/messenger": "<4.3", + "symfony/security-core": "<4.4", + "symfony/validator": "<4.4.2|<5.0.2,>=5.0" + }, + "require-dev": { + "doctrine/annotations": "~1.7", + "doctrine/cache": "~1.6", + "doctrine/collections": "~1.0", + "doctrine/data-fixtures": "1.0.*", + "doctrine/dbal": "~2.4", + "doctrine/orm": "^2.6.3", + "doctrine/reflection": "~1.0", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/form": "^4.4|^5.0", + "symfony/http-kernel": "^4.3.7", + "symfony/messenger": "^4.4|^5.0", + "symfony/property-access": "^3.4|^4.0|^5.0", + "symfony/property-info": "^3.4|^4.0|^5.0", + "symfony/proxy-manager-bridge": "^3.4|^4.0|^5.0", + "symfony/security-core": "^4.4|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/translation": "^3.4|^4.0|^5.0", + "symfony/validator": "^4.4.2|^5.0.2", + "symfony/var-dumper": "^3.4|^4.0|^5.0" + }, + "suggest": { + "doctrine/data-fixtures": "", + "doctrine/dbal": "", + "doctrine/orm": "", + "symfony/form": "", + "symfony/property-info": "", + "symfony/validator": "" + }, + "type": "symfony-bridge", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Doctrine\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Doctrine Bridge", + "homepage": "https://symfony.com", + "time": "2020-03-16T11:24:17+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v4.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "2434fb32851f252e4f27691eee0b77c16198db62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/2434fb32851f252e4f27691eee0b77c16198db62", + "reference": "2434fb32851f252e4f27691eee0b77c16198db62", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "~1.0", + "symfony/debug": "^4.4.5", + "symfony/polyfill-php80": "^1.15", + "symfony/var-dumper": "^4.4|^5.0" + }, + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony ErrorHandler Component", + "homepage": "https://symfony.com", + "time": "2020-08-17T09:56:45+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v4.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "3e8ea5ccddd00556b86d69d42f99f1061a704030" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/3e8ea5ccddd00556b86d69d42f99f1061a704030", + "reference": "3e8ea5ccddd00556b86d69d42f99f1061a704030", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1" + }, + "conflict": { + "symfony/dependency-injection": "<3.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2020-08-13T14:18:44+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "84e23fdcd2517bf37aecbd16967e83f0caee25a7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/84e23fdcd2517bf37aecbd16967e83f0caee25a7", + "reference": "84e23fdcd2517bf37aecbd16967e83f0caee25a7", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2020-07-06T13:19:58+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v4.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "6d4fdf28187250f671c1edc9cf921ebfb7fe3809" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/6d4fdf28187250f671c1edc9cf921ebfb7fe3809", + "reference": "6d4fdf28187250f671c1edc9cf921ebfb7fe3809", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "time": "2020-03-16T08:56:54+00:00" + }, + { + "name": "symfony/finder", + "version": "v4.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "ea69c129aed9fdeca781d4b77eb20b62cf5d5357" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/ea69c129aed9fdeca781d4b77eb20b62cf5d5357", + "reference": "ea69c129aed9fdeca781d4b77eb20b62cf5d5357", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "time": "2020-02-14T07:42:58+00:00" + }, + { + "name": "symfony/framework-bundle", + "version": "v4.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/framework-bundle.git", + "reference": "f0ef822516463bef83625e7d33f8e047093f310e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/f0ef822516463bef83625e7d33f8e047093f310e", + "reference": "f0ef822516463bef83625e7d33f8e047093f310e", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "php": "^7.1.3", + "symfony/cache": "^4.4|^5.0", + "symfony/config": "^4.3.4|^5.0", + "symfony/dependency-injection": "^4.4.1|^5.0.1", + "symfony/error-handler": "^4.4.1|^5.0.1", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-mbstring": "~1.0", + "symfony/routing": "^4.4|^5.0" + }, + "conflict": { + "doctrine/persistence": "<1.3", + "phpdocumentor/reflection-docblock": "<3.0", + "phpdocumentor/type-resolver": "<0.2.1", + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/asset": "<3.4", + "symfony/browser-kit": "<4.3", + "symfony/console": "<4.3", + "symfony/dom-crawler": "<4.3", + "symfony/dotenv": "<4.3.6", + "symfony/form": "<4.3.5", + "symfony/http-client": "<4.4", + "symfony/lock": "<4.4", + "symfony/mailer": "<4.4", + "symfony/messenger": "<4.4", + "symfony/mime": "<4.4", + "symfony/property-info": "<3.4", + "symfony/security-bundle": "<4.4", + "symfony/serializer": "<4.4", + "symfony/stopwatch": "<3.4", + "symfony/translation": "<4.4", + "symfony/twig-bridge": "<4.1.1", + "symfony/twig-bundle": "<4.4", + "symfony/validator": "<4.4", + "symfony/web-profiler-bundle": "<4.4", + "symfony/workflow": "<4.3.6" + }, + "require-dev": { + "doctrine/annotations": "~1.7", + "doctrine/cache": "~1.0", + "paragonie/sodium_compat": "^1.8", + "phpdocumentor/reflection-docblock": "^3.0|^4.0", + "symfony/asset": "^3.4|^4.0|^5.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/console": "^4.3.4|^5.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dom-crawler": "^4.3|^5.0", + "symfony/dotenv": "^4.3.6|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/form": "^4.3.5|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/mailer": "^4.4|^5.0", + "symfony/messenger": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/property-info": "^3.4|^4.0|^5.0", + "symfony/security-csrf": "^3.4|^4.0|^5.0", + "symfony/security-http": "^3.4|^4.0|^5.0", + "symfony/serializer": "^4.4|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.4|^5.0", + "symfony/twig-bundle": "^4.4|^5.0", + "symfony/validator": "^4.4|^5.0", + "symfony/web-link": "^4.4|^5.0", + "symfony/workflow": "^4.3.6|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0", + "twig/twig": "^1.41|^2.10|^3.0" + }, + "suggest": { + "ext-apcu": "For best performance of the system caches", + "symfony/console": "For using the console commands", + "symfony/form": "For using forms", + "symfony/property-info": "For using the property_info service", + "symfony/serializer": "For using the serializer service", + "symfony/validator": "For using validation", + "symfony/web-link": "For using web links, features such as preloading, prefetching or prerendering", + "symfony/yaml": "For using the debug:config and lint:yaml commands" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\FrameworkBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony FrameworkBundle", + "homepage": "https://symfony.com", + "time": "2020-03-19T20:46:03+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v4.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "e3e5a62a6631a461954d471e7206e3750dbe8ee1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e3e5a62a6631a461954d471e7206e3750dbe8ee1", + "reference": "e3e5a62a6631a461954d471e7206e3750dbe8ee1", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/mime": "^4.3|^5.0", + "symfony/polyfill-mbstring": "~1.1" + }, + "require-dev": { + "predis/predis": "~1.0", + "symfony/expression-language": "^3.4|^4.0|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony HttpFoundation Component", + "homepage": "https://symfony.com", + "time": "2020-08-17T07:39:58+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v4.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "2bb7b90ecdc79813c0bf237b7ff20e79062b5188" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/2bb7b90ecdc79813c0bf237b7ff20e79062b5188", + "reference": "2bb7b90ecdc79813c0bf237b7ff20e79062b5188", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "~1.0", + "symfony/error-handler": "^4.4", + "symfony/event-dispatcher": "^4.4", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.15" + }, + "conflict": { + "symfony/browser-kit": "<4.3", + "symfony/config": "<3.4", + "symfony/console": ">=5", + "symfony/dependency-injection": "<4.3", + "symfony/translation": "<4.2", + "twig/twig": "<1.34|<2.4,>=2" + }, + "provide": { + "psr/log-implementation": "1.0" + }, + "require-dev": { + "psr/cache": "~1.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^1.34|^2.4|^3.0" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony HttpKernel Component", + "homepage": "https://symfony.com", + "time": "2020-09-02T08:09:29+00:00" + }, + { + "name": "symfony/mime", + "version": "v4.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "50ad671306d3d3ffb888d95b4fb1859496831e3a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/50ad671306d3d3ffb888d95b4fb1859496831e3a", + "reference": "50ad671306d3d3ffb888d95b4fb1859496831e3a", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10", + "symfony/dependency-injection": "^3.4|^4.1|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A library to manipulate MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "time": "2020-08-17T09:56:45+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v4.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "376bd3a02e7946dbf90b01563361b47dde425025" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/376bd3a02e7946dbf90b01563361b47dde425025", + "reference": "376bd3a02e7946dbf90b01563361b47dde425025", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony OptionsResolver Component", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "time": "2020-07-10T09:12:14+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "1c302646f6efc070cd46856e600e5e0684d6b454" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454", + "reference": "1c302646f6efc070cd46856e600e5e0684d6b454", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-iconv", + "version": "v1.15.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-iconv.git", + "reference": "ad6d62792bfbcfc385dd34b424d4fcf9712a32c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/ad6d62792bfbcfc385dd34b424d4fcf9712a32c8", + "reference": "ad6d62792bfbcfc385dd34b424d4fcf9712a32c8", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-iconv": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.15-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Iconv\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Iconv extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "iconv", + "polyfill", + "portable", + "shim" + ], + "time": "2020-03-09T19:04:49+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "5dcab1bc7146cf8c1beaa4502a3d9be344334251" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/5dcab1bc7146cf8c1beaa4502a3d9be344334251", + "reference": "5dcab1bc7146cf8c1beaa4502a3d9be344334251", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php70": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "time": "2020-08-04T06:02:08+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e", + "reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "time": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/a6977d63bf9a0ad4c65cd352709e230876f9904a", + "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-php56", + "version": "v1.15.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php56.git", + "reference": "d51ec491c8ddceae7dca8dd6c7e30428f543f37d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/d51ec491c8ddceae7dca8dd6c7e30428f543f37d", + "reference": "d51ec491c8ddceae7dca8dd6c7e30428f543f37d", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/polyfill-util": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.15-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php56\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2020-03-09T19:04:49+00:00" + }, + { + "name": "symfony/polyfill-php70", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php70.git", + "reference": "0dd93f2c578bdc9c72697eaa5f1dd25644e618d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/0dd93f2c578bdc9c72697eaa5f1dd25644e618d3", + "reference": "0dd93f2c578bdc9c72697eaa5f1dd25644e618d3", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "~1.0|~2.0|~9.99", + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php70\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "639447d008615574653fb3bc60d1986d7172eaae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/639447d008615574653fb3bc60d1986d7172eaae", + "reference": "639447d008615574653fb3bc60d1986d7172eaae", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fffa1a52a023e782cdcc221d781fe1ec8f87fcca", + "reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/d87d5766cbf48d72388a9f6b85f280c8ad51f981", + "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981", + "shasum": "" + }, + "require": { + "php": ">=7.0.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-util", + "version": "v1.15.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-util.git", + "reference": "d8e76c104127675d0ea3df3be0f2ae24a8619027" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/d8e76c104127675d0ea3df3be0f2ae24a8619027", + "reference": "d8e76c104127675d0ea3df3be0f2ae24a8619027", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.15-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Util\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony utilities for portability of PHP codes", + "homepage": "https://symfony.com", + "keywords": [ + "compat", + "compatibility", + "polyfill", + "shim" + ], + "time": "2020-03-02T11:55:35+00:00" + }, + { + "name": "symfony/polyfill-uuid", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-uuid.git", + "reference": "da48e2cccd323e48c16c26481bf5800f6ab1c49d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/da48e2cccd323e48c16c26481bf5800f6ab1c49d", + "reference": "da48e2cccd323e48c16c26481bf5800f6ab1c49d", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "~1.0|~2.0|~9.99", + "php": ">=5.3.3" + }, + "suggest": { + "ext-uuid": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Uuid\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "GrΓ©goire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for uuid functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "uuid" + ], + "time": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/process", + "version": "v4.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "b9863d0f7b684d7c4c13e665325b5ff047de0aee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/b9863d0f7b684d7c4c13e665325b5ff047de0aee", + "reference": "b9863d0f7b684d7c4c13e665325b5ff047de0aee", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "https://symfony.com", + "time": "2020-03-23T12:37:11+00:00" + }, + { + "name": "symfony/routing", + "version": "v4.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "bd92312650007d29bbabf00795c591b975a0b9a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/bd92312650007d29bbabf00795c591b975a0b9a6", + "reference": "bd92312650007d29bbabf00795c591b975a0b9a6", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "conflict": { + "symfony/config": "<4.2", + "symfony/dependency-injection": "<3.4", + "symfony/yaml": "<3.4" + }, + "require-dev": { + "doctrine/annotations": "~1.2", + "psr/log": "~1.0", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "doctrine/annotations": "For using the annotation loader", + "symfony/config": "For using the all-in-one router or any loader", + "symfony/expression-language": "For using expression matching", + "symfony/http-foundation": "For using a Symfony Request object", + "symfony/yaml": "For using the YAML loader" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Routing Component", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "time": "2020-03-16T11:24:17+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v1.1.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/ffc7f5692092df31515df2a5ecf3b7302b3ddacf", + "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-10-14T12:27:06+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "1bef32329f3166486ab7cb88599cae4875632b99" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1bef32329f3166486ab7cb88599cae4875632b99", + "reference": "1bef32329f3166486ab7cb88599cae4875632b99", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.15" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.34|^2.4|^3.0" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony mechanism for exploring and dumping PHP variables", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "time": "2020-08-17T07:31:35+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v4.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "982ddfd0d7aeb2be0227c242399c3f29e0403266" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/982ddfd0d7aeb2be0227c242399c3f29e0403266", + "reference": "982ddfd0d7aeb2be0227c242399c3f29e0403266", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "require-dev": { + "symfony/var-dumper": "^4.1.1|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A blend of var_export() + serialize() to turn any serializable data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "serialize" + ], + "time": "2020-03-16T11:24:17+00:00" + }, + { + "name": "symfony/yaml", + "version": "v3.4.38", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "bc63e15160866e8730a1f738541b194c401f72bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/bc63e15160866e8730a1f738541b194c401f72bf", + "reference": "bc63e15160866e8730a1f738541b194c401f72bf", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<3.4" + }, + "require-dev": { + "symfony/console": "~3.4|~4.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2020-01-16T19:04:26+00:00" + }, + { + "name": "textalk/websocket", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/Textalk/websocket-php.git", + "reference": "ba2e5f9ef7cf24d536d1c864ae74b2a9599b86eb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Textalk/websocket-php/zipball/ba2e5f9ef7cf24d536d1c864ae74b2a9599b86eb", + "reference": "ba2e5f9ef7cf24d536d1c864ae74b2a9599b86eb", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "4.1.*", + "phpunit/phpunit-selenium": "1.3.3", + "satooshi/php-coveralls": "dev-master" + }, + "type": "library", + "autoload": { + "psr-4": { + "WebSocket\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fredrik Liljegren", + "email": "fredrik.liljegren@textalk.se" + } + ], + "description": "WebSocket client and server", + "time": "2015-04-11T05:45:54+00:00" + }, + { + "name": "twig/twig", + "version": "v2.12.5", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "18772e0190734944277ee97a02a9a6c6555fcd94" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/18772e0190734944277ee97a02a9a6c6555fcd94", + "reference": "18772e0190734944277ee97a02a9a6c6555fcd94", + "shasum": "" + }, + "require": { + "php": "^7.0", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3" + }, + "require-dev": { + "psr/container": "^1.0", + "symfony/phpunit-bridge": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.12-dev" + } + }, + "autoload": { + "psr-0": { + "Twig_": "lib/" + }, + "psr-4": { + "Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Twig Team", + "role": "Contributors" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], + "time": "2020-02-11T15:31:23+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "aed98a490f9a8f78468232db345ab9cf606cf598" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/aed98a490f9a8f78468232db345ab9cf606cf598", + "reference": "aed98a490f9a8f78468232db345ab9cf606cf598", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "vimeo/psalm": "<3.6.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.36 || ^7.5.13" + }, + "type": "library", + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2020-02-14T12:15:55+00:00" + } + ], + "packages-dev": [], + "aliases": [ + { + "alias": "1.0", + "alias_normalized": "1.0.0.0", + "version": "dev-twake-1.0", + "package": "mxp100/pusher" + } + ], + "minimum-stability": "stable", + "stability-flags": { + "mxp100/pusher": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.1" + }, + "platform-dev": [] +} diff --git a/twake/backend/core/composer.phar b/twake/backend/core/composer.phar new file mode 100755 index 00000000..863dc9ad Binary files /dev/null and b/twake/backend/core/composer.phar differ diff --git a/twake/backend/core/generate_onpremise_version.php b/twake/backend/core/generate_onpremise_version.php new file mode 100755 index 00000000..209a1e80 --- /dev/null +++ b/twake/backend/core/generate_onpremise_version.php @@ -0,0 +1,198 @@ + $value){ + $path = realpath($dir.DIRECTORY_SEPARATOR.$value); + + if(strpos($path."/", "generate_onpremise_version.php") !== false + || strpos($path."/", "/drive/") !== false + || strpos($path."/", "/vendor/") !== false){ + continue; + } + + $removed = false; + foreach ($exludedPathContaining as $filter) { + if(strpos($path."/", $filter) !== false){ + remove($path); + $removed = true; + break; + } + } + + if(!$removed){ + + if(!is_dir($path)) { + + $extension = explode(".", $path); + $extension = end($extension); + + if($extension!="phar") { + + $content = file_get_contents($path); + + $lines = explode("\n", $content); + $exclude = array(); + $removing = false; + foreach ($lines as $line) { + $found = false; + foreach ($exludedLinesContaining as $contain) { + if (strpos($line, $contain) !== false) { + $found = true; + } + } + if (strpos($line, "[REMOVE_ONPREMISE]") !== false) { + $removing = true; + } + + if (!$found && !$removing) { + if ($extension == "php") { + $line = str_replace(", $", ",$", $line); + $line = str_replace(") {", "){", $line); + $line = str_replace("if (", "if(", $line); + $line = str_replace("else {", "else{", $line); + $line = str_replace(" =", "=", $line); + $line = str_replace("= ", "=", $line); + $line = str_replace(" ? ", "?", $line); + $line = str_replace(" : ", ":", $line); + + //Remove one line comments + $line = preg_replace_callback('/\/\/.*|\/\*[\s\S]*?\*\/|("(\\.|[^"])*")/m', + function ($matches) { + if (\is_array($matches) && (\count($matches) > 1)) { + return $matches[1]; + } else { + return ''; + } + }, $line); + + if (strpos($line, "if") !== false || strpos($line, "else") !== false) { + $line .= "[ONPREMISE_LINE_BREAK]"; + } + + if (trim($line) != '') { + $exclude[] = trim($line); + } + } elseif ($extension == "yml") { + $splited = explode("#", $line); + + if (count($splited) > 1 && trim($splited[0]) == "") { + array_pop($splited); + $line = implode("#", $splited); + } + + if (trim($line) != '') { + $exclude[] = $line; + } + } else { + if (trim($line) != '') { + $exclude[] = $line; + } + } + } + + if (strpos($line, "[/REMOVE_ONPREMISE]") !== false) { + $removing = false; + } + } + if ($extension == "php" && strpos($path . "/", "/src/") !== false) { + if (strpos($path . "/", "/Entity/") !== false) { + $content = implode("\n", $exclude); + } else { + $content = implode("", $exclude); + } + $content = str_replace("' . $variable . "([^a-zA-Z0-9_])/"; + $replaceB[] = '$this->v' . md5($variable) . "$1"; + } + } + } + $content = preg_replace($replaceA, $replaceB, $content); + + //Re replace class vars + preg_match_all("/var +\\$[a-zA-Z_][a-zA-Z_0-9]+/", $content, $variables); + $variables = array_unique($variables[0]); + + $replaceA = []; + $replaceB = []; + foreach ($variables as $variable) { + $variable = explode(" ", $variable); + $variable = $variable[1]; + $replaceA[] = '/\\$v' . md5($variable) . "([^a-zA-Z0-9_])/"; + $replaceB[] = $variable . "$1"; + } + $content = preg_replace($replaceA, $replaceB, $content); + + } + + if (strpos($path . "/", "/Entity/") === false) { + $content = preg_replace('!/\*.*?\*/!s', '', $content); + } + + } else { + $content = implode("\n", $exclude); + } + + $content = str_replace("[ONPREMISE_LINE_BREAK]", "\n", $content); + + file_put_contents($path, $content); + + } + + } else if($value != "." && $value != "..") { + getDirContents($path); + } + + } + + } + +} + +getDirContents('./') + +?> diff --git a/twake/backend/core/phpunit.xml.dist b/twake/backend/core/phpunit.xml.dist new file mode 100755 index 00000000..37399b66 --- /dev/null +++ b/twake/backend/core/phpunit.xml.dist @@ -0,0 +1,21 @@ + + + + + + + + + + + tests + + + diff --git a/twake/backend/core/src/AdministrationApi/Apps/Bundle.php b/twake/backend/core/src/AdministrationApi/Apps/Bundle.php new file mode 100755 index 00000000..f584c1e2 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Apps/Bundle.php @@ -0,0 +1,30 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Apps/Controller/Apps.php b/twake/backend/core/src/AdministrationApi/Apps/Controller/Apps.php new file mode 100755 index 00000000..7325b5bb --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Apps/Controller/Apps.php @@ -0,0 +1,107 @@ + Array(), + "errors" => Array() + ); + + $validation = $this->get("administration.validation"); + $token = $request->request->get("token"); + $validate_token = $validation->validateAuthentication($token); + + if ($validate_token) { + $offset = $request->request->get("offset"); + $limit = $request->request->get("limit"); + + $validate_struct = $validation->validateStructure(Array(), Array(), $limit, $offset); + + if ($validate_struct) { + $apps = $this->get("administration.apps")->getAllApps($limit, $offset); + + $data["data"] = $apps; + } else { + $data["errors"][] = "invalid_request_structure"; + } + } else { + $data["errors"][] = "invalid_authentication_token"; + } + + return new Response($data); + } + + public function getOneApp(Request $request) + { + + $data = Array( + "data" => Array(), + "errors" => Array() + ); + + $validation = $this->get("administration.validation"); + $token = $request->request->get("token"); + $validate_token = $validation->validateAuthentication($token); + + if ($validate_token) { + $app_id = $request->request->get("id"); + + $app_service = $this->get("administration.apps"); + + $app = $app_service->getOneApp($app_id); + + if ($app) { + $data["data"] = $app->getAsArray(); + } else { + $data["errors"][] = "app_not_found"; + } + } else { + $data["errors"][] = "invalid_authentication_token"; + } + + return new Response($data); + } + + public function toggleValidation(Request $request) + { + + $data = Array( + "data" => Array(), + "errors" => Array() + ); + + $validation = $this->get("administration.validation"); + $token = $request->request->get("token"); + $validate_token = $validation->validateAuthentication($token); + + if ($validate_token) { + $app_id = $request->request->get("id"); + + $app_service = $this->get("administration.apps"); + + $app = $app_service->toggleAppValidation($app_id); + + if ($app) { + $data["data"] = ""; + } else { + $data["errors"][] = "app_not_validated"; + } + } else { + $data["errors"][] = "invalid_authentication_token"; + } + + return new Response($data); + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Apps/Resources/Routing.php b/twake/backend/core/src/AdministrationApi/Apps/Resources/Routing.php new file mode 100755 index 00000000..694c1cc9 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Apps/Resources/Routing.php @@ -0,0 +1,18 @@ + ["handler" => "Apps:getAllApps", "methods" => ["POST"]], + "getOneApp" => ["handler" => "Apps:getOneApp", "methods" => ["POST"]], + "toggleValidation" => ["handler" => "Apps:toggleValidation", "methods" => ["POST"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Apps/Resources/Services.php b/twake/backend/core/src/AdministrationApi/Apps/Resources/Services.php new file mode 100755 index 00000000..1e7ec1f1 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Apps/Resources/Services.php @@ -0,0 +1,14 @@ + "AdministrationApps", +// arguments: [ "@app.twake_doctrine" ] + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Apps/Services/AdministrationApps.php b/twake/backend/core/src/AdministrationApi/Apps/Services/AdministrationApps.php new file mode 100755 index 00000000..081aaed4 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Apps/Services/AdministrationApps.php @@ -0,0 +1,72 @@ +em = $app->getServices()->get("app.twake_doctrine"); + } + + public function getAllApps($limit, $offset) + { + + $appsRepository = $this->em->getRepository("Twake\Market:Application"); + + $apps_entities = $appsRepository->findBy(array(), array(), $limit, $offset/*, "__TOKEN__id"*/); + + $apps = array(); + + foreach ($apps_entities as $app) { + $apps[] = $app->getAsArray(); + } + + return $apps; + + } + + public function getOneApp($id) + { + $appsRepository = $this->em->getRepository("Twake\Market:Application"); + + $app_tab = $appsRepository->findBy(array("id" => $id)); + + $app = false; + + if (count($app_tab) == 1) { + $app = $app_tab[0]; + } + + return $app; + } + + public function toggleAppValidation($id) + { + $appsRepository = $this->em->getRepository("Twake\Market:Application"); + + $app_tab = $appsRepository->findBy(array("id" => $id)); + + $rep = false; + + if (count($app_tab) == 1) { + if ($app_tab[0]->getPublic()) { + $app_tab[0]->setIsAvailableToPublic(!$app_tab[0]->getIsAvailableToPublic()); + $this->em->persist($app_tab[0]); + $rep = true; + } + } + + $this->em->flush(); + + return $rep; + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Core/Bundle.php b/twake/backend/core/src/AdministrationApi/Core/Bundle.php new file mode 100755 index 00000000..4356aa68 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Core/Bundle.php @@ -0,0 +1,24 @@ +services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Core/Controller/Base.php b/twake/backend/core/src/AdministrationApi/Core/Controller/Base.php new file mode 100755 index 00000000..d68e1b15 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Core/Controller/Base.php @@ -0,0 +1,12 @@ + "ValidationService", +// arguments: [ %administration_token% ] + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Core/Services/ValidationService.php b/twake/backend/core/src/AdministrationApi/Core/Services/ValidationService.php new file mode 100755 index 00000000..5cc51c89 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Core/Services/ValidationService.php @@ -0,0 +1,52 @@ +token = $app->getContainer()->getParameter('env.admin_api_token'); + } + + /** + * @param $token + * @return bool + */ + public function validateAuthentication($token) + { + return $token == $this->token; + } + + /** + * @return bool + */ + public function validateStructure($filter, $sort, $limit, $page) + { + if ($limit <= 0) { + return false; + } + if ($page < 0) { + return false; + } + return true; + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Counter/Bundle.php b/twake/backend/core/src/AdministrationApi/Counter/Bundle.php new file mode 100755 index 00000000..3e1f3d7e --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Counter/Bundle.php @@ -0,0 +1,30 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Counter/Controller/Counter.php b/twake/backend/core/src/AdministrationApi/Counter/Controller/Counter.php new file mode 100755 index 00000000..648cfd71 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Counter/Controller/Counter.php @@ -0,0 +1,67 @@ + Array(), + "errors" => Array() + ); + + $validation = $this->get("administration.validation"); + $token = $request->request->get("token"); + $validate_token = $validation->validateAuthentication($token); + + if ($validate_token) { + + $keys = $request->request->get("key"); + + $begin_date = $request->request->get("begin"); + + $end_date = $request->request->get("end"); + + $counter_service = $this->get("administration.counter"); + + $counter_data = array(); + + if (is_array($keys)) { + foreach ($keys as $key) { + $counter_tab = $counter_service->getCounter($key, $begin_date, $end_date); + if ($counter_tab) { + $counter_data[$key] = $counter_tab; + } + } + if (count($counter_data) == 0) { + $data['errors'][] = "key_not_found"; + } + } elseif ($keys) { + $counter_tab = $counter_service->getCounter($keys, $begin_date, $end_date); + if ($counter_tab) { + $counter_data[$keys] = $counter_tab; + } else { + $data['errors'][] = "counter_not_found"; + } + } else { + $data['errors'][] = "key_not_found"; + } + + $data['data'] = $counter_data; + + } else { + $data["errors"][] = "invalid_authentication_token"; + } + + return new Response($data); + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Counter/Entity/StatsCounter.php b/twake/backend/core/src/AdministrationApi/Counter/Entity/StatsCounter.php new file mode 100755 index 00000000..872dc4fb --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Counter/Entity/StatsCounter.php @@ -0,0 +1,84 @@ +counter_key = $counter_key; + $this->date = $date; + $this->value = 0; + } + + /** + * @return mixed + */ + public function getCounterKey() + { + return $this->counter_key; + } + + /** + * @return mixed + */ + public function getDate() + { + return $this->date; + } + + /** + * @return mixed + */ + public function getValue() + { + return $this->value; + } + + /** + * @param mixed $value BE CAREFUL THIS IS A COUNTER ! SO IT WILL BE AN ADD NOT A SET + */ + public function setIncrementValue($value) + { + $this->value = $value; + } + + public function getAsArray() + { + $date = \DateTime::createFromFormat("d-m-Y", "01-01-" . intdiv($this->getDate(), 1000)); + $days = $this->getDate() % 1000; + $date->add(new \DateInterval("P" . $days . "D")); + $date_string = date("d/m/Y", $date->getTimestamp()); + return array( + "date" => $date_string, + "value" => $this->getValue() + ); + } + +} diff --git a/twake/backend/core/src/AdministrationApi/Counter/Resources/Routing.php b/twake/backend/core/src/AdministrationApi/Counter/Resources/Routing.php new file mode 100755 index 00000000..8057b2af --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Counter/Resources/Routing.php @@ -0,0 +1,16 @@ + ["handler" => "Counter:getCounter", "methods" => ["POST"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Counter/Resources/Services.php b/twake/backend/core/src/AdministrationApi/Counter/Resources/Services.php new file mode 100755 index 00000000..3927a541 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Counter/Resources/Services.php @@ -0,0 +1,14 @@ + "CounterService", +// arguments: [ "@app.twake_doctrine" ] + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Counter/Services/CounterService.php b/twake/backend/core/src/AdministrationApi/Counter/Services/CounterService.php new file mode 100755 index 00000000..f7398671 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Counter/Services/CounterService.php @@ -0,0 +1,79 @@ +em = $app->getServices()->get("app.twake_doctrine"); + } + + public function incrementCounter($key, $increment = 1) + { + $counter_repository = $this->em->getRepository("AdministrationApi\Counter:StatsCounter"); + + $counter_tab = $counter_repository->findBy(Array('counter_key' => $key), array(), 1, null, 'date', 'DESC'); + $last_counter = $counter_tab[0]; + + $date_int = intval(date("Y")) * 1000 + intval(date("z")); + + if (!$counter_tab || $last_counter->getDate() != $date_int) { + $counter = new StatsCounter($key, $date_int); + if ($last_counter) { + $increment = $increment + $last_counter->getValue(); + } + } else { + $counter = $last_counter; + } + + if (!$increment) { + return; + } + + $counter->setIncrementValue($increment); + + $this->em->merge($counter); + $this->em->flush(); + } + + public function getCounter($key, $beginDate = null, $endDate = null) + { + $counter_repository = $this->em->getRepository("AdministrationApi\Counter:StatsCounter"); + + $counter_tab = $counter_repository->findBy(Array('counter_key' => $key), array(), 20, null, 'date', 'DESC'); + + $rep = false; + + if ($beginDate) { + $beginValue = strtotime($beginDate); + $begin = intval(date('Y', $beginValue)) * 1000 + intval(date('z', $beginValue)); + } + + if ($endDate) { + $endValue = strtotime($endDate); + $end = intval(date('Y', $endValue)) * 1000 + intval(date('z', $endValue)); + } + + if ($counter_tab) { + $rep = array(); + foreach ($counter_tab as $counter_entity) { + $afterBegin = !isset($begin) || $counter_entity->getDate() >= $begin; + $beforeEnd = !isset($end) || $counter_entity->getDate() <= $end; + if ($afterBegin && $beforeEnd) { + $rep[] = $counter_entity->getAsArray(); + } + } + } + + return $rep; + } + +} diff --git a/twake/backend/core/src/AdministrationApi/Group/Bundle.php b/twake/backend/core/src/AdministrationApi/Group/Bundle.php new file mode 100755 index 00000000..02d112f9 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Group/Bundle.php @@ -0,0 +1,30 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Group/Controller/Group.php b/twake/backend/core/src/AdministrationApi/Group/Controller/Group.php new file mode 100755 index 00000000..8ff0f4e0 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Group/Controller/Group.php @@ -0,0 +1,248 @@ + Array(), +// "errors" => Array() +// ); +// +// $validation = $this->get("administration.validation"); +// $token = $request->request->get("token"); +// $validate_token = $validation->validateAuthentication($token); +// +// if ($validate_token) { +// +// $offset = $request->request->get("offset"); +// $limit = $request->request->get("limit"); +// +// $validate_struct = $validation->validateStructure(Array(), Array(), $limit, $offset); +// +// if ($validate_struct) { +// $users = $this->get("administration.users")->getAllUsers($limit, $offset); +// +// $data["data"] = $users; +// } else { +// $data["errors"][] = "invalid_request_structure"; +// } +// } else { +// $data["errors"][] = "invalid_authentication_token"; +// } +// +// return new Response($data); + + $scroll_id = $request->request->get("scroll_id"); +// $scroll_id = "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAezFnhWeWdRZE9FUnF1eFVRczFoclljUVEAAAAAAAAHtBZ4VnlnUWRPRVJxdXhVUXMxaHJZY1FRAAAAAAAAB7UWeFZ5Z1FkT0VScXV4VVFzMWhyWWNRUQAAAAAAAAe2FnhWeWdRZE9FUnF1eFVRczFoclljUVEAAAAAAAAHtxZ4VnlnUWRPRVJxdXhVUXMxaHJZY1FR"; +// $repository = "Twake\Workspaces:Group"; + + if (isset($scroll_id) && isset($repository)) { + $globalresult = $this->get('globalsearch.pagination')->getnextelement($scroll_id, $repository); + } else { + + $globalresult = $this->get('administration.group')->getAllGroups(); + } + + $data = Array("data" => $globalresult); + //return new Response("Hello !"); + return new Response($data); + } + + public function getAllWorkspace(Request $request) + { + + $scroll_id = $request->request->get("scroll_id"); +// $scroll_id = "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAezFnhWeWdRZE9FUnF1eFVRczFoclljUVEAAAAAAAAHtBZ4VnlnUWRPRVJxdXhVUXMxaHJZY1FRAAAAAAAAB7UWeFZ5Z1FkT0VScXV4VVFzMWhyWWNRUQAAAAAAAAe2FnhWeWdRZE9FUnF1eFVRczFoclljUVEAAAAAAAAHtxZ4VnlnUWRPRVJxdXhVUXMxaHJZY1FR"; +// $repository = "Twake\Workspaces:Group"; + + if (isset($scroll_id) && isset($repository)) { + $globalresult = $this->get('globalsearch.pagination')->getnextelement($scroll_id, $repository); + } else { + + $globalresult = $this->get('administration.group')->getAllWorkspace(); + } + + $data = Array("data" => $globalresult); + //return new Response("Hello !"); + return new Response($data); + + } + + public function getGroupbyname(Request $request) + { + + $scroll_id = $request->request->get("scroll_id"); +// $scroll_id = "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAezFnhWeWdRZE9FUnF1eFVRczFoclljUVEAAAAAAAAHtBZ4VnlnUWRPRVJxdXhVUXMxaHJZY1FRAAAAAAAAB7UWeFZ5Z1FkT0VScXV4VVFzMWhyWWNRUQAAAAAAAAe2FnhWeWdRZE9FUnF1eFVRczFoclljUVEAAAAAAAAHtxZ4VnlnUWRPRVJxdXhVUXMxaHJZY1FR"; +// $repository = "Twake\Workspaces:Group"; + + if (isset($scroll_id) && isset($repository)) { + $globalresult = $this->get('globalsearch.pagination')->getnextelement($scroll_id, $repository); + } else { + $options = Array( + "name" => "test" + ); + $globalresult = $this->get('administration.group')->getGroupbyName($options); + } + + $data = Array("data" => $globalresult); + //return new Response("Hello !"); + return new Response($data); + + } + + public function getWpbyname(Request $request) + { + + + $scroll_id = $request->request->get("scroll_id"); +// $scroll_id = "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAezFnhWeWdRZE9FUnF1eFVRczFoclljUVEAAAAAAAAHtBZ4VnlnUWRPRVJxdXhVUXMxaHJZY1FRAAAAAAAAB7UWeFZ5Z1FkT0VScXV4VVFzMWhyWWNRUQAAAAAAAAe2FnhWeWdRZE9FUnF1eFVRczFoclljUVEAAAAAAAAHtxZ4VnlnUWRPRVJxdXhVUXMxaHJZY1FR"; +// $repository = "Twake\Workspaces:Group"; + + if (isset($scroll_id) && isset($repository)) { + $globalresult = $this->get('globalsearch.pagination')->getnextelement($scroll_id, $repository); + } else { + $options = Array( + "name" => "test" + ); + $globalresult = $this->get('administration.group')->getWpbyName($options); + } + + $data = Array("data" => $globalresult); + //return new Response("Hello !"); + return new Response($data); + + } + + public function getUserbyMail(Request $request) + { + + + $scroll_id = $request->request->get("scroll_id"); +// $scroll_id = "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAezFnhWeWdRZE9FUnF1eFVRczFoclljUVEAAAAAAAAHtBZ4VnlnUWRPRVJxdXhVUXMxaHJZY1FRAAAAAAAAB7UWeFZ5Z1FkT0VScXV4VVFzMWhyWWNRUQAAAAAAAAe2FnhWeWdRZE9FUnF1eFVRczFoclljUVEAAAAAAAAHtxZ4VnlnUWRPRVJxdXhVUXMxaHJZY1FR"; +// $repository = "Twake\Workspaces:Group"; + + if (isset($scroll_id) && isset($repository)) { + $globalresult = $this->get('globalsearch.pagination')->getnextelement($scroll_id, $repository); + } else { + $options = Array( + "mail" => "romar" + ); + $globalresult = $this->get('administration.group')->getUserbyMail($options); + } + + $data = Array("data" => $globalresult); + //return new Response("Hello !"); + return new Response($data); + + } + + public function getOneGroup(Request $request) + { + +// $data = Array( +// "data" => Array(), +// "errors" => Array() +// ); +// +// $validation = $this->get("administration.validation"); +// $token = $request->request->get("token"); +// $validate_token = $validation->validateAuthentication($token); +// +// if ($validate_token) { +// +// $user_id = $request->request->get("id"); +// +// $user_service = $this->get("administration.users"); +// +// $user = $user_service->getOneUser($user_id); +// +// if ($user) { +// +// if ($user == "Error") { +// $data["errors"][] = "unknown_error"; +// } else { +// +// $devices = $user_service->getUserDevices($user); +// $mails = $user_service->getUserMails($user); +// $workspaces = $user_service->getUserWorkspaces($user); +// $groups = $user_service->getUserGroups($user); +// +// $data["data"]["user"] = $user->getAsArray(); +// $data["data"]["user"]["creation_date"] = $user->getCreationDate(); +// $data["data"]["user"]["last_login"] = $user->getLastLogin(); +// $data["data"]["devices"] = $devices; +// $data["data"]["mails"] = $mails; +// $data["data"]["workspaces"] = $workspaces; +// $data["data"]["groups"] = $groups; +// } +// } else { +// $data["errors"][] = "user_not_found"; +// } +// } else { +// $data["errors"][] = "invalid_authentication_token"; +// } +// +// return new Response($data); + } + + public function findGroup(Request $request) + { + +// $data = array( +// "data" => Array(), +// "errors" => Array() +// ); +// +// $validation = $this->get("administration.validation"); +// $token = $request->request->get("token"); +// $validate_token = $validation->validateAuthentication($token); +// +// if ($validate_token) { +// $search_string = $request->request->get("search"); +// +// $users_service = $this->get("administration.users"); +// +// $users = $users_service->findUserByUsername($search_string); +// +// if (!$users) { +// $users = $users_service->findUserByEmail($search_string); +// } +// +// if (!$users) { +// $users = $users_service->findUserById($search_string); +// } +// +// if (!$users) { +// +// $advanced_search = $this->get("app.users"); +// +// $search_words = explode(" ", $search_string); +// +// $users = $advanced_search->search($search_words, Array("allow_email" => true)); +// +// } +// +// if (count($users) == 0) { +// $data['errors'][] = "user_not_found"; +// } else { +// $data['data'] = $users; +// } +// +// } else { +// $data["errors"][] = "invalid_authentication_token"; +// } +// +// return new Response($data); + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Group/Resources/Routing.php b/twake/backend/core/src/AdministrationApi/Group/Resources/Routing.php new file mode 100755 index 00000000..0c08fc2a --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Group/Resources/Routing.php @@ -0,0 +1,21 @@ + ["handler" => "Group:getAllGroup", "methods" => ["POST"]], + "getwp" => ["handler" => "Group:getAllWorkspace", "methods" => ["POST"]], + "getgroupbyname" => ["handler" => "Group:getGroupbyname", "methods" => ["POST"]], + "getwpbyname" => ["handler" => "Group:getWpbyname", "methods" => ["POST"]], + "getuserbymail" => ["handler" => "Group:getUserbyMail", "methods" => ["POST"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Group/Resources/Services.php b/twake/backend/core/src/AdministrationApi/Group/Resources/Services.php new file mode 100755 index 00000000..ad7a6462 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Group/Resources/Services.php @@ -0,0 +1,14 @@ + "AdministrationGroup", +// arguments: [ "@app.twake_doctrine" ] + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Group/Services/AdministrationGroup.php b/twake/backend/core/src/AdministrationApi/Group/Services/AdministrationGroup.php new file mode 100755 index 00000000..aba2033b --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Group/Services/AdministrationGroup.php @@ -0,0 +1,307 @@ + Array(), "scroll_id" => ""); + + public function __construct(App $app) + { + $this->em = $app->getServices()->get("app.twake_doctrine"); + } + + public function getGroupbyName($options) + { + + if (isset($options["name"])) { + $name = $options["name"]; + + $options = Array( + "repository" => "Twake\Workspaces:Group", + "index" => "group", + "size" => 10, + "query" => Array( + "bool" => Array( + "should" => Array( + "bool" => Array( + "filter" => Array( + "regexp" => Array( + "name" => ".*" . $name . ".*" + ) + ) + ) + ) + ) + ), + "sort" => Array( + "creation_date" => Array( + "order" => "desc" + ) + ) + ); + } + // search in ES + $result = $this->em->es_search($options); + + //var_dump(json_encode($options,JSON_PRETTY_PRINT)); + + array_slice($result["result"], 0, 5); + + $scroll_id = $result["scroll_id"]; + + //on traite les donnΓ©es recu d'Elasticsearch + //var_dump(json_encode($options)); + foreach ($result["result"] as $group) { + if($group && $group[0]){ + $this->list_group["group"][] = Array($group[0]->getAsArray(), $group[1][0]); + } + } +// var_dump("nombre de resultat : " . count($this->list_files)); +// var_dump($this->list_group); + $this->list_group["scroll_id"] = $scroll_id; + + return $this->list_group ?: null; + } + + public function getAllUsers() + { + $options = Array( + "repository" => "Twake\Users:User", + "index" => "users", + "size" => 10, + "query" => Array( + "match_all" => (object)[] + ), + "sort" => Array( + "creation_date" => Array( + "order" => "desc" + ) + ) + ); + + // search in ES + $result = $this->em->es_search($options); + + array_slice($result["result"], 0, 5); + + $scroll_id = $result["scroll_id"]; + + //on traite les donnΓ©es recu d'Elasticsearch + //var_dump(json_encode($options)); + foreach ($result["result"] as $user) { + //var_dump($file->getAsArray()); + $this->list_group["users"][] = Array($user[0]->getAsArray(), $user[1][0]);; + } +// var_dump("nombre de resultat : " . count($this->list_files)); +// var_dump($this->list_group); + $this->list_group["scroll_id"] = $scroll_id; + + return $this->list_group ?: null; + } + + public function getWpbyName($options) + { + + if (isset($options["name"])) { + $name = $options["name"]; + + $options = Array( + "repository" => "Twake\Workspaces:Workspace", + "index" => "workspace", + "size" => 10, + "query" => Array( + "bool" => Array( + "should" => Array( + "bool" => Array( + "filter" => Array( + "regexp" => Array( + "name" => ".*" . $name . ".*" + ) + ) + ) + ) + ) + ), + "sort" => Array( + "creation_date" => Array( + "order" => "desc" + ) + ) + ); + } + // search in ES + $result = $this->em->es_search($options); + + + array_slice($result["result"], 0, 5); + + $scroll_id = $result["scroll_id"]; + + //on traite les donnΓ©es recu d'Elasticsearch + //var_dump(json_encode($options)); + foreach ($result["result"] as $group) { + //var_dump($file->getAsArray()); + $this->list_group["group"][] = Array($group[0]->getAsArray(), $group[1][0]);; + } +// var_dump("nombre de resultat : " . count($this->list_files)); +// var_dump($this->list_group); + $this->list_group["scroll_id"] = $scroll_id; + + return $this->list_group ?: null; + } + + public function getAllGroup() + { + +// $group = new Group("group_admin_test_2"); +// $this->em->persist($group); +// $this->em->flush(); + + $options = Array( + "repository" => "Twake\Workspaces:Group", + "index" => "group", + "size" => 10, + "query" => Array( + "match_all" => (object)[] + ), + "sort" => Array( + "creation_date" => Array( + "order" => "desc" + ) + ) + ); + + //var_dump(json_encode($options,JSON_PRETTY_PRINT)); + + // search in ES + $result = $this->em->es_search($options); + + + array_slice($result["result"], 0, 5); + + $scroll_id = $result["scroll_id"]; + + //on traite les donnΓ©es recu d'Elasticsearch + //var_dump(json_encode($options)); + foreach ($result["result"] as $group) { + //var_dump($file->getAsArray()); + $this->list_group["group"][] = Array($group[0]->getAsArray(), $group[1][0]);; + } +// var_dump("nombre de resultat : " . count($this->list_files)); +// var_dump($this->list_group); + $this->list_group["scroll_id"] = $scroll_id; + + return $this->list_group ?: null; + } + + public function getAllWorkspace() + { + +// $group = new Group("group_for_workspace_1"); +// $this->em->persist($group); +// $this->em->flush(); +// +// $wp = new Workspace("workspace_admin_test_1"); +// $wp->setGroup($group); +// $this->em->persist($wp); +// $this->em->flush(); + + $options = Array( + "repository" => "Twake\Workspaces:Workspace", + "index" => "workspace", + "size" => 10, + "query" => Array( + "match_all" => (object)[] + ), + "sort" => Array( + "creation_date" => Array( + "order" => "desc" + ) + ) + ); + + //var_dump(json_encode($options,JSON_PRETTY_PRINT)); + + // search in ES + $result = $this->em->es_search($options); + + + array_slice($result["result"], 0, 5); + + $scroll_id = $result["scroll_id"]; + + //on traite les donnΓ©es recu d'Elasticsearch + //var_dump(json_encode($options)); + foreach ($result["result"] as $wp) { + $this->list_group["group"][] = Array($wp[0]->getAsArray(), $wp[1][0]);; + } +// var_dump("nombre de resultat : " . count($this->list_files)); +// var_dump($this->list_group); + $this->list_group["scroll_id"] = $scroll_id; + + return $this->list_group ?: null; + } + + public function getUserbyMail($options) + { + + if (isset($options["mail"])) { + $mail = $options["mail"]; + + //var_dump("passage"); + + $options = Array( + "repository" => "Twake\Users:Mail", + "index" => "mail", + "size" => 10, + "query" => Array( + "bool" => Array( + "should" => Array( + "bool" => Array( + "filter" => Array( + "regexp" => Array( + "mail" => ".*" . $mail . ".*" + ) + ) + ) + ) + ) + ), + ); + } + +// $mail = new Mail(); +// $mail->setMail("romaric@twakemail.fr"); +// $this->em->persist($mail); +// $this->em->flush(); + + // search in ES + $result = $this->em->es_search($options); + + + array_slice($result["result"], 0, 5); + + $scroll_id = $result["scroll_id"]; + + //on traite les donnΓ©es recu d'Elasticsearch + //var_dump(json_encode($options)); + foreach ($result["result"] as $mail) { + //var_dump($file->getAsArray()); + $this->list_group["group"][] = $mail[0]->getUser() + ->getId() . ""; + } +// var_dump("nombre de resultat : " . count($this->list_files)); +// var_dump($this->list_group); + $this->list_group["scroll_id"] = $scroll_id; + + return $this->list_group ?: null; + } + +} diff --git a/twake/backend/core/src/AdministrationApi/Users/Bundle.php b/twake/backend/core/src/AdministrationApi/Users/Bundle.php new file mode 100755 index 00000000..cae77592 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Users/Bundle.php @@ -0,0 +1,30 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Users/Controller/Users.php b/twake/backend/core/src/AdministrationApi/Users/Controller/Users.php new file mode 100755 index 00000000..f3fbef30 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Users/Controller/Users.php @@ -0,0 +1,143 @@ + Array(), + "errors" => Array() + ); + + $validation = $this->get("administration.validation"); + $token = $request->request->get("token"); + $validate_token = $validation->validateAuthentication($token); + + if ($validate_token) { + + $repository = "Twake\Users:User"; + + $scroll_id = $request->request->get("scroll_id"); + + $options = Array(); + + if (isset($scroll_id) && isset($repository)) { + $options["scroll_id"] = $scroll_id; + } + + $users = $this->get("administration.users")->getAllUsers($options); + + $data["data"] = $users; + + } else { + $data["errors"][] = "invalid_authentication_token"; + } + + return new Response($data); + } + + public function getOneUser(Request $request) + { + + $data = Array( + "data" => Array(), + "errors" => Array() + ); + + $validation = $this->get("administration.validation"); + $token = $request->request->get("token"); + $validate_token = $validation->validateAuthentication($token); + + if ($validate_token) { + + $user_id = $request->request->get("id"); + + $user_service = $this->get("administration.users"); + + $user = $user_service->getOneUser($user_id); + + if ($user) { + + if ($user == "Error") { + $data["errors"][] = "unknown_error"; + } else { + + $devices = $user_service->getUserDevices($user); + $mails = $user_service->getUserMails($user); + $workspaces = $user_service->getUserWorkspaces($user); + $groups = $user_service->getUserGroups($user); + + $data["data"]["user"] = $user->getAsArray(); + $data["data"]["user"]["creation_date"] = $user->getCreationDate(); + $data["data"]["user"]["last_login"] = $user->getLastLogin(); + $data["data"]["devices"] = $devices; + $data["data"]["mails"] = $mails; + $data["data"]["workspaces"] = $workspaces; + $data["data"]["groups"] = $groups; + } + } else { + $data["errors"][] = "user_not_found"; + } + } else { + $data["errors"][] = "invalid_authentication_token"; + } + + return new Response($data); + } + + public function findUser(Request $request) + { + + $data = array( + "data" => Array(), + "errors" => Array() + ); + + $validation = $this->get("administration.validation"); + $token = $request->request->get("token"); + $validate_token = $validation->validateAuthentication($token); + + if ($validate_token) { + $search_string = $request->request->get("search"); + + $users_service = $this->get("administration.users"); + + $users = $users_service->findUserById($search_string); + + if (count($users["users"]) == 0) { + $options = Array( + "mail" => $search_string + ); + $users = $this->get('administration.users')->getUserbyMail($options); + } + + if (count($users["users"]) == 0) { + + $advanced_search = $this->get("app.users"); + + $options = array( + "name" => $search_string + ); + + $users = $advanced_search->search($options); + + } + + $data['data'] = $users; + } else { + $data["errors"][] = "invalid_authentication_token"; + } + + return new Response($data); + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Users/Resources/Routing.php b/twake/backend/core/src/AdministrationApi/Users/Resources/Routing.php new file mode 100755 index 00000000..fee2d6fc --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Users/Resources/Routing.php @@ -0,0 +1,18 @@ + ["handler" => "Users:getAllUsers", "methods" => ["POST"]], + "getOne" => ["handler" => "Users:getOneUser", "methods" => ["POST"]], + "findUser" => ["handler" => "Users:findUser", "methods" => ["POST"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Users/Resources/Services.php b/twake/backend/core/src/AdministrationApi/Users/Resources/Services.php new file mode 100755 index 00000000..79a0cd96 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Users/Resources/Services.php @@ -0,0 +1,14 @@ + "AdministrationUsers", +// arguments: [ "@app.twake_doctrine" ] + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Users/Services/AdministrationUsers.php b/twake/backend/core/src/AdministrationApi/Users/Services/AdministrationUsers.php new file mode 100755 index 00000000..af40564f --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Users/Services/AdministrationUsers.php @@ -0,0 +1,219 @@ + Array(), "scroll_id" => ""); + + public function __construct(App $app) + { + $this->em = $app->getServices()->get("app.twake_doctrine"); + } + + public function getAllUsers($options) + { + + $options = Array( + "repository" => "Twake\Users:User", + "index" => "users", + "scroll_id" => $options["scroll_id"], + "size" => 10, + "query" => Array( + "match_all" => (object)[] + ), + "sort" => Array( + "creation_date" => Array( + "order" => "desc" + ) + ) + ); + + // search in ES + $result = $this->em->es_search($options); + + array_slice($result["result"], 0, 5); + + $scroll_id = $result["scroll_id"]; + + //on traite les donnΓ©es recu d'Elasticsearch + foreach ($result["result"] as $user) { + if($user && $user[0]){ + $user_tab = $user[0]->getAsArray(); + $user_tab['mail'] = $this->getUserMails($user[0])[0]; + $user_tab['phone_number'] = $user[0]->getPhone(); + $user_tab['creation_date'] = $user[0]->getCreationDate(); + + $this->list_user["users"][] = Array($user_tab, $user[1][0]); + } + } + $this->list_user["scroll_id"] = $scroll_id; + + return $this->list_user ?: null; + } + + public function getUserMails($user) + { + if(is_string($user)){ + $usersRepository = $this->em->getRepository("Twake\Users:User"); + $user = $usersRepository->findBy(Array("user_id" => $user)); + } + + $mailsRepository = $this->em->getRepository("Twake\Users:Mail"); + $mails_tab = $mailsRepository->findBy(Array("user_id" => $user)); + + $mails = array(); + + foreach ($mails_tab as $mail) { + $mails[] = $mail->getMail(); + } + + $mails[] = $user->getEmail()." (not verified)"; + + return $mails; + } + + public function getOneUser($user_id) + { + try { + $usersRepository = $this->em->getRepository("Twake\Users:User"); + + $user = $usersRepository->find($user_id); + + return $user; + + } catch (\Exception $e) { + return "Error"; + } + } + + public function getUserDevices($user) + { + $devicesRepository = $this->em->getRepository("Twake\Users:Device"); + + $devices_tab = $devicesRepository->findBy(Array("user_id" => $user)); + + $devices = array(); + + foreach ($devices_tab as $device) { + $devices[] = $device->getAsArray(); + } + + return $devices; + } + + public function getUserWorkspaces($user) + { + $workspacesLinkRepository = $this->em->getRepository("Twake\Workspaces:WorkspaceUser"); + $workspacesRepository = $this->em->getRepository("Twake\Workspaces:Workspace"); + + $workspaces_tab = $workspacesLinkRepository->findBy(Array("user_id" => $user->getId())); + + $workspaces = array(); + + foreach ($workspaces_tab as $workspace) { + $ws = $workspacesRepository->findOneBy(["id"=>$workspace->getWorkspaceId()]); + if($ws){ + $workspaces[] = $ws->getAsArray($this->em); + } + } + + return $workspaces; + } + + public function getUserGroups($user) + { + $groupsRepository = $this->em->getRepository("Twake\Workspaces:GroupUser"); + + $groups_tab = $groupsRepository->findBy(Array("user_id" => $user->getId())); + + $groups = array(); + + foreach ($groups_tab as $group) { + $groups[] = $group->getGroup()->getAsArray(); + } + + return $groups; + } + + public function findUserById($id) + { + + $usersRepository = $this->em->getRepository("Twake\Users:User"); + + $users = $usersRepository->findBy(Array("id" => $id)); + + $rep = array("users" => array(), "scroll_id" => ""); + + if (count($users) >= 1) { + + foreach ($users as $user) { + $user_tab = $user->getAsArray(); + $user_tab['mail'] = $user->getEmail(); + $rep["users"][] = array($user_tab, null); + } + } + + return $rep; + + } + + public function getUserbyMail($options) + { + + if (isset($options["mail"])) { + $mail = $options["mail"]; + + //var_dump("passage"); + + $options = Array( + "repository" => "Twake\Users:Mail", + "index" => "mail", + "size" => 10, + "query" => Array( + "bool" => Array( + "should" => Array( + "bool" => Array( + "filter" => Array( + "regexp" => Array( + "mail" => ".*" . $mail . ".*" + ) + ) + ) + ) + ) + ), + ); + } + + // search in ES + $result = $this->em->es_search($options); + + array_slice($result["result"], 0, 5); + + $scroll_id = $result["scroll_id"]; + + //on traite les donnΓ©es recu d'Elasticsearch + foreach ($result["result"] as $mail) { + $mail = $mail[0]; + $user_id = $mail->getUserId(); + $user_tab = $user->getAsArray(); + $user_tab['mail'] = $this->getUserMails($user_id)[0]; + $user_tab['phone_number'] = $user->getPhone(); + $user_tab['creation_date'] = $user->getCreationDate(); + + $this->list_user["users"][] = array($user_tab, null); + } + $this->list_user["scroll_id"] = $scroll_id; + + return $this->list_user ?: null; + } + +} diff --git a/twake/backend/core/src/AdministrationApi/Workspaces/Bundle.php b/twake/backend/core/src/AdministrationApi/Workspaces/Bundle.php new file mode 100755 index 00000000..2640d68a --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Workspaces/Bundle.php @@ -0,0 +1,30 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Workspaces/Controller/Groups.php b/twake/backend/core/src/AdministrationApi/Workspaces/Controller/Groups.php new file mode 100755 index 00000000..17abfdc5 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Workspaces/Controller/Groups.php @@ -0,0 +1,190 @@ + Array(), + "errors" => Array() + ); + + $validation = $this->get("administration.validation"); + $token = $request->request->get("token"); + $validate_token = $validation->validateAuthentication($token); + + if ($validate_token) { +// $page = $request->request->get("page"); +// $limit = $request->request->get("limit"); +// $offset = $page * $limit; +// +// $validate_struct = $validation->validateStructure(Array(), Array(), $limit, $offset); +// +// if ($validate_struct) { +// $groups = $this->get("administration.groups")->getAllGroups($limit,$offset); +// +// $data["data"] = $groups; +// } else { +// $data["errors"][] = "invalid_request_structure"; +// } + $scroll_id = $request->request->get("scroll_id"); + $repository = "Twake\Workspaces:Group"; + + $options = Array(); + + if (isset($scroll_id) && isset($repository)) { + $options["scroll_id"] = $scroll_id; + } + + $globalresult = $this->get('administration.groups')->getAllGroups($options); + + $data["data"] = $globalresult; + + } else { + $data["errors"][] = "invalid_authentication_token"; + } + + return new Response($data); + } + + public function getOneGroup(Request $request) + { + $data = Array( + "data" => Array(), + "errors" => Array() + ); + + $validation = $this->get("administration.validation"); + $token = $request->request->get("token"); + $validate_token = $validation->validateAuthentication($token); + + if ($validate_token) { + $id = $request->request->get("id"); + + $group_service = $this->get("administration.groups"); + + $group = $group_service->getOneGroup($id); + + if ($group) { + + $workspaces = $group_service->getGroupWorkspaces($group); + $members = $group_service->getGroupMembers($group); + $apps = $group_service->getGroupApps($group); + + //TODO Get group Drive size + + $data["data"]["group"] = $group->getAsArray(); + $data["data"]["group"]["creation_data"] = $group->getOnCreationData(); + $data["data"]["workspaces"] = $workspaces; + $data["data"]["members"] = $members; + $data["data"]["apps"] = $apps; + + } else { + $data["errors"][] = "group_not_found"; + } + } else { + $data["errors"][] = "invalid_authentication_token"; + } + + return new Response($data); + } + + public function findGroups(Request $request) + { + $data = Array( + "data" => Array(), + "errors" => Array() + ); + + $validation = $this->get("administration.validation"); + $token = $request->request->get("token"); + $validate_token = $validation->validateAuthentication($token); + + if ($validate_token) { + + $group_scroll_id = $request->request->get("group_scroll_id"); + + $repository = "Twake\Workspaces:Group"; + + $search_string = $request->request->get("search"); + + $data['data']['group'] = array(); + $data['data']['workspaces'] = array(); + + $options = Array( + "name" => $search_string + ); + + if (isset($group_scroll_id) && isset($repository)) { + $options["scroll_id"] = $group_scroll_id; + } + + $globalresult = $this->get('administration.groups')->getGroupbyName($options); + + $group_service = $this->get("administration.groups"); + + foreach ($globalresult['group'] as $group) { + + $id = $group[0]['id']; + + $workspaces = $group_service->getGroupWorkspaces($id); + + $data['data']['group'][] = $group[0]; + $data['data']['workspaces'] = array_merge($data['data']['workspaces'], $workspaces); + } + + $data['data']['group_scroll_id'] = $globalresult['scroll_id']; + + $group = $group_service->getOneGroup($search_string); + + if ($group) { + $data['data']['group'][] = $group->getAsArray(); + } + + $workspace_scroll_id = $request->request->get("workspace_scroll_id"); + + $repository = "Twake\Workspaces:Group"; + + if (isset($workspace_scroll_id) && isset($repository)) { + $globalresult = $this->get('globalsearch.pagination')->getnextelement($workspace_scroll_id, $repository); + } else { + $options = Array( + "name" => $search_string + ); + $globalresult = $this->get('administration.workspaces')->getWpbyName($options); + } + + foreach ($globalresult['workspace'] as $workspace) { + + $data['data']['workspaces'][] = $workspace[0]; + + } + + $data['data']['workspaces_scroll_id'] = $globalresult['scroll_id']; + + $workspace_service = $this->get("administration.workspaces"); + + $workspace = $workspace_service->getOneWorkspace($search_string); + + if ($workspace) { + $data['data']['workspaces'][] = $workspace->getAsArray($this->get("app.twake_doctrine")); + } + + + } else { + $data["errors"][] = "invalid_authentication_token"; + } + + return new Response($data); + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Workspaces/Controller/Workspaces.php b/twake/backend/core/src/AdministrationApi/Workspaces/Controller/Workspaces.php new file mode 100755 index 00000000..33800271 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Workspaces/Controller/Workspaces.php @@ -0,0 +1,83 @@ + Array(), + "errors" => Array() + ); + + $validation = $this->get("administration.validation"); + $token = $request->request->get("token"); + $validate_token = $validation->validateAuthentication($token); + + if ($validate_token) { + $id = $request->request->get("id"); + + $workspace_service = $this->get("administration.workspaces"); + + $workspace = $workspace_service->getOneWorkspace($id); + + if ($workspace) { + $members = $workspace_service->getWorkspaceMembers($workspace); + $apps = $workspace_service->getWorkspaceApps($workspace); + $invited_mails = $workspace_service->getInvitedUsers($workspace); + + $data["data"]["workspace"] = $workspace->getAsArray($this->get("app.twake_doctrine")); + $data["data"]["members"] = $members; + $data["data"]["apps"] = $apps; + $data["data"]["invited"] = $invited_mails; + + //TODO Infos du workspace a recuperer : taille du Drive + } else { + $data["errors"][] = "workspace_not_found"; + } + } else { + $data["errors"][] = "invalid_authentication_token"; + } + + return new Response($data); + } + + public function getAllWorkspaces(Request $request) + { + $data = Array( + "data" => Array(), + "errors" => Array() + ); + + $validation = $this->get("administration.validation"); + $token = $request->request->get("token"); + $validate_token = $validation->validateAuthentication($token); + + if ($validate_token) { + $scroll_id = $request->request->get("scroll_id"); + $repository = "Twake\Workspaces:Group"; + + $options = Array(); + + if (isset($scroll_id) && isset($repository)) { + $options["scroll_id"] = $scroll_id; + } + + $globalresult = $this->get('administration.workspaces')->getAllWorkspace($options); + + $data = Array("data" => $globalresult); + } else { + $data["errors"][] = "invalid_authentication_token"; + } + + return new Response($data); + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Workspaces/Resources/Routing.php b/twake/backend/core/src/AdministrationApi/Workspaces/Resources/Routing.php new file mode 100755 index 00000000..7c5576cf --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Workspaces/Resources/Routing.php @@ -0,0 +1,20 @@ + ["handler" => "Groups:getAllGroups", "methods" => ["POST"]], + "getOneGroup" => ["handler" => "Groups:getOneGroup", "methods" => ["POST"]], + "getAllWorkspaces" => ["handler" => "Workspaces:getAllWorkspaces", "methods" => ["POST"]], + "getWorkspace" => ["handler" => "Workspaces:getOneWorkspace", "methods" => ["POST"]], + "searchGroups" => ["handler" => "Groups:findGroups", "methods" => ["POST"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Workspaces/Resources/Services.php b/twake/backend/core/src/AdministrationApi/Workspaces/Resources/Services.php new file mode 100755 index 00000000..a0f09265 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Workspaces/Resources/Services.php @@ -0,0 +1,16 @@ + "AdministrationGroups", +// arguments: [ "@app.twake_doctrine" ] + "administration.workspaces" => "AdministrationWorkspaces", +// arguments: [ "@app.twake_doctrine" ] + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/AdministrationApi/Workspaces/Services/AdministrationGroups.php b/twake/backend/core/src/AdministrationApi/Workspaces/Services/AdministrationGroups.php new file mode 100755 index 00000000..31b7055e --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Workspaces/Services/AdministrationGroups.php @@ -0,0 +1,194 @@ + Array(), "scroll_id" => ""); + + public function __construct(App $app) + { + $this->em = $app->getServices()->get("app.twake_doctrine"); + } + + public function getAllGroups($options) + { + + $options = Array( + "repository" => "Twake\Workspaces:Group", + "index" => "group", + "size" => 10, + "scroll_id" => $options["scroll_id"], + "query" => Array( + "match_all" => (object)[] + ), + "sort" => Array( + "creation_date" => Array( + "order" => "desc" + ) + ) + ); + + //var_dump(json_encode($options,JSON_PRETTY_PRINT)); + + // search in ES + $result = $this->em->es_search($options); + + + array_slice($result["result"], 0, 5); + + $scroll_id = $result["scroll_id"]; + + //on traite les donnΓ©es recu d'Elasticsearch + //var_dump(json_encode($options)); + foreach ($result["result"] as $group) { + //var_dump($file->getAsArray()); + $group_tab = $group[0]->getAsArray(); + $group_tab["nb_workspaces"] = count($group[0]->getWorkspaces()); + $group_tab["nb_members"] = count($this->getGroupMembers($group[0])); + $group_tab["creation_data"] = $group[0]->getOnCreationData(); + $this->list_group["group"][] = Array($group_tab, $group[1][0]); + } + //var_dump("nombre de resultat : " . count($this->list_files)); + //var_dump($this->list_group); + $this->list_group["scroll_id"] = $scroll_id; + + return $this->list_group ?: null; + } + + public function getGroupMembers($group) + { + $membersRepository = $this->em->getRepository("Twake\Workspaces:GroupUser"); + + $members_tab = $membersRepository->findBy(Array("group" => $group)); + + $members = Array(); + + foreach ($members_tab as $member) { + try{ + $members[] = $member->getUser()->getAsArray(); + }catch(\Exception $err){ + + } + } + + return $members; + } + + public function getOneGroup($group_id) + { + + $groupsRepository = $this->em->getRepository("Twake\Workspaces:Group"); + + $group = $groupsRepository->find($group_id); + + return $group; + } + + public function getGroupWorkspaces($group_id) + { + $groupsRepository = $this->em->getRepository("Twake\Workspaces:Group"); + + $group = $groupsRepository->find($group_id); + + $rep = false; + + if ($group) { + $rep = array(); + + $workspaces_tab = $group->getWorkspaces(); + + foreach ($workspaces_tab as $workspace) { + $rep[] = $workspace->getAsArray($this->em); + } + } + return $rep; + } + + public function getGroupApps($group) + { + $groupAppRepository = $this->em->getRepository("Twake\Workspaces:GroupApp"); + + $apps_tab = $groupAppRepository->findBy(array("group" => $group)); + + $apps = array(); + + $appsRepository = $this->em->getRepository("Twake\Market:Application"); + + foreach ($apps_tab as $grpApp) { + $app_id = $grpApp->getAppId(); + + $app = $appsRepository->findby(array('id' => $app_id)); + + if (count($app) == 1) { + $apps[] = $app[0]->getAsArray(); + } + + } + + return $apps; + } + + public function getGroupbyName($options) + { + + if (isset($options["name"])) { + $name = $options["name"]; + + $options = Array( + "repository" => "Twake\Workspaces:Group", + "index" => "group", + "size" => 10, + "query" => Array( + "bool" => Array( + "should" => Array( + "bool" => Array( + "filter" => Array( + "regexp" => Array( + "name" => ".*" . strtolower($name) . ".*" + ) + ) + ) + ) + ) + ), + "sort" => Array( + "creation_date" => Array( + "order" => "desc" + ) + ) + ); + } + // search in ES + $result = $this->em->es_search($options); + + //var_dump(json_encode($options,JSON_PRETTY_PRINT)); + + array_slice($result["result"], 0, 5); + + $scroll_id = $result["scroll_id"]; + + //on traite les donnΓ©es recu d'Elasticsearch + //var_dump(json_encode($options)); + foreach ($result["result"] as $group) { + //var_dump($file->getAsArray()); + $group_tab = $group[0]->getAsArray(); + $group_tab["nb_workspaces"] = count($group[0]->getWorkspaces()); + $group_tab["nb_members"] = count($this->getGroupMembers($group[0])); + $group_tab["creation_data"] = $group[0]->getOnCreationData(); + $this->list_group["group"][] = Array($group_tab, $group[1][0]); + } +// var_dump("nombre de resultat : " . count($this->list_files)); +// var_dump($this->list_group); + $this->list_group["scroll_id"] = $scroll_id; + + return $this->list_group ?: null; + } + +} diff --git a/twake/backend/core/src/AdministrationApi/Workspaces/Services/AdministrationWorkspaces.php b/twake/backend/core/src/AdministrationApi/Workspaces/Services/AdministrationWorkspaces.php new file mode 100755 index 00000000..7276bc11 --- /dev/null +++ b/twake/backend/core/src/AdministrationApi/Workspaces/Services/AdministrationWorkspaces.php @@ -0,0 +1,180 @@ + Array(), "scroll_id" => ""); + + public function __construct(App $app) + { + $this->em = $app->getServices()->get("app.twake_doctrine"); + } + + public function getOneWorkspace($workspace_id) + { + $workspacesRepository = $this->em->getRepository("Twake\Workspaces:Workspace"); + + $workspace = $workspacesRepository->findOneBy(["id"=>$workspace_id]); + + return $workspace; + } + + public function getWorkspaceMembers($workspace) + { + $membersRepository = $this->em->getRepository("Twake\Workspaces:WorkspaceUser"); + + $members_tab = $membersRepository->findBy(array("workspace_id" => $workspace->getId())); + + $members = array(); + + foreach ($members_tab as $member) { + $members[] = $member->getUser($this->em)->getAsArray(); + } + + return $members; + } + + public function getWorkspaceApps($workspace) + { + $workspaceAppsRepository = $this->em->getrepository("Twake\Workspaces:WorkspaceApp"); + + $apps_tab = $workspaceAppsRepository->findBy(array("workspace_id" => $workspace)); + + $apps = array(); + + $appsRepository = $this->em->getRepository("Twake\Market:Application"); + + foreach ($apps_tab as $appWksp) { + $app_id = $appWksp->getAppId(); + + $app = $appsRepository->findBy(array('id' => $app_id)); + + if (count($app) == 1) { + $apps[] = $app[0]->getAsArray(); + } + } + + return $apps; + } + + public function getInvitedUsers($workspace) + { + $workspaceMailRepository = $this->em->getrepository("Twake\Workspaces:WorkspaceUserByMail"); + + $mails_tab = $workspaceMailRepository->findBy(array('workspace' => $workspace)); + + $mails = array(); + + foreach ($mails_tab as $ws_mail) { + $mails[] = $ws_mail->getMail(); + } + + return $mails; + } + + public function getWpbyName($options) + { + + if (isset($options["name"])) { + $name = $options["name"]; + + $options = Array( + "repository" => "Twake\Workspaces:Workspace", + "index" => "workspace", + "size" => 10, + "query" => Array( + "bool" => Array( + "should" => Array( + "bool" => Array( + "filter" => Array( + "regexp" => Array( + "name" => ".*" . strtolower($name) . ".*" + ) + ) + ) + ) + ) + ), + "sort" => Array( + "creation_date" => Array( + "order" => "desc" + ) + ) + ); + } + // search in ES + $result = $this->em->es_search($options); + + + array_slice($result["result"], 0, 5); + + $scroll_id = $result["scroll_id"]; + + //on traite les donnΓ©es recu d'Elasticsearch + //var_dump(json_encode($options)); + foreach ($result["result"] as $workspace) { + //var_dump($file->getAsArray()); + $this->list_workspace["workspace"][] = Array($workspace[0]->getAsArray(), $workspace[1][0]);; + } +// var_dump("nombre de resultat : " . count($this->list_files)); +// var_dump($this->list_group); + $this->list_workspace["scroll_id"] = $scroll_id; + + return $this->list_workspace ?: null; + } + + public function getAllWorkspace($options) + { + +// $group = new Group("group_for_workspace_1"); +// $this->em->persist($group); +// $this->em->flush(); +// +// $wp = new Workspace("workspace_admin_test_1"); +// $wp->setGroup($group); +// $this->em->persist($wp); +// $this->em->flush(); + $options = Array( + "repository" => "Twake\Workspaces:Workspace", + "index" => "workspace", + "scroll_id" => $options["scroll_id"], + "size" => 10, + "query" => Array( + "match_all" => (object)[] + ), + "sort" => Array( + "creation_date" => Array( + "order" => "desc" + ) + ) + ); + + //var_dump(json_encode($options,JSON_PRETTY_PRINT)); + + // search in ES + $result = $this->em->es_search($options); + + + array_slice($result["result"], 0, 5); + + $scroll_id = $result["scroll_id"]; + + //on traite les donnΓ©es recu d'Elasticsearch + //var_dump(json_encode($options)); + foreach ($result["result"] as $wp) { + $this->list_group["group"][] = Array($wp[0]->getAsArray(), $wp[1][0]);; + } +// var_dump("nombre de resultat : " . count($this->list_files)); +// var_dump($this->list_group); + $this->list_group["scroll_id"] = $scroll_id; + + return $this->list_group ?: null; + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/BuiltInConnectors/Common/Bundle.php b/twake/backend/core/src/BuiltInConnectors/Common/Bundle.php new file mode 100755 index 00000000..5fba0724 --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Common/Bundle.php @@ -0,0 +1,58 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + + $path = __DIR__ . "/../Connectors/"; + $dir = new \DirectoryIterator($path); + $connectors_bundles_instances = []; + // Require and instanciate all defined connectors + foreach ($dir as $fileinfo) { + if ($fileinfo->isDir() && !$fileinfo->isDot()) { + try{ + $bundle = "BuiltInConnectors/Connectors/" . $fileinfo->getFilename(); + if (file_exists(__DIR__ . "/../../" . $bundle . "/Bundle.php")) { + require_once __DIR__ . "/../../" . $bundle . "/Bundle.php"; + $class_name = str_replace("/", "\\", $bundle) . "\\Bundle"; + $connectors_bundles_instances[] = new $class_name($this->app); + } else { + error_log("No such connector bundle " . $bundle); + } + }catch(\Exception $err){ + error_log("No such connector bundle " . $fileinfo->getFilename()); + error_log($err->getMessage()); + } + } + } + + // Init routing for all bundles + foreach ($connectors_bundles_instances as $bundle_instance) { + $bundle_instance->init(); + } + + } +} diff --git a/twake/backend/core/src/BuiltInConnectors/Common/Command/InitConnector.php b/twake/backend/core/src/BuiltInConnectors/Common/Command/InitConnector.php new file mode 100755 index 00000000..a21bf4b4 --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Common/Command/InitConnector.php @@ -0,0 +1,143 @@ +setName("twake:init_connector"); + } + + protected function execute() + { + + $arg_list = $_SERVER['argv']; + + $connector_name = isset($arg_list[0]) ? $arg_list[0] : false; + if(!$connector_name){ + + error_log("βš™οΈ Installing default connectors defined in configuration"); + + $connectors = $this->getApp()->getContainer()->getParameter("defaults.applications.connectors"); + if($connectors){ + foreach($connectors as $name => $configuration){ + $this->toggleConnector($name, !!$configuration, isset($configuration["default"]) && $configuration["default"]); + } + } + + die; + } + $action_name = isset($arg_list[1]) ? $arg_list[1] : "enable"; + $enable = $action_name != "disable"; + + $second_action_name = isset($arg_list[2]) ? $arg_list[2] : ""; + $is_default = $second_action_name == "default"; + + $this->toggleConnector($connector_name, $enable, $is_default); + + } + + public function toggleConnector($connector_name, $enable, $is_default){ + + error_log(($enable?"Enabling" : "Disabling") . " " . $connector_name. ($is_default?" and default for future workspaces":"") . "!"); + + $path = __DIR__ . "/../../Connectors/"; + $dir = new \DirectoryIterator($path); + $connectors_bundles_instances = []; + // Require and instanciate all defined connectors + foreach ($dir as $fileinfo) { + if ($fileinfo->isDir() && !$fileinfo->isDot()) { + try{ + $bundle = "BuiltInConnectors/Connectors/" . $fileinfo->getFilename(); + if (file_exists(__DIR__ . "/../../../" . $bundle . "/Bundle.php")) { + $class_name = str_replace("/", "\\", $bundle) . "\\Bundle"; + $connectors_bundles_instances[] = new $class_name($this->app); + } else { + error_log("No such connector bundle " . $bundle); + } + }catch(\Exception $err){ + error_log("No such connector bundle " . $fileinfo->getFilename()); + error_log($err->getMessage()); + } + } + } + + $found = false; + // Init routing for all bundles + foreach ($connectors_bundles_instances as $bundle_instance) { + if(method_exists($bundle_instance, "getDefinition")){ + $definition = $bundle_instance->getDefinition(); + + if($definition["simple_name"] == $connector_name){ + $found = true; + + $server_route = rtrim($this->app->getContainer()->getParameter("env.internal_server_name")?:$this->app->getContainer()->getParameter("env.server_name"), "/"); + + $simple_name = $definition["simple_name"]; + $icon = $definition['icon_url']; + if(!(strpos("http://", $icon) === 0 || strpos("https://", $icon) === 0)){ + $icon = rtrim($this->app->getContainer()->getParameter("env.server_name"), "/") . "/bundle/connectors/" . $definition["simple_name"] . "/icon"; + } + + $app_exists = $this->app->getServices()->get("app.applications")->findAppBySimpleName($simple_name, true); + + $application = [ + 'simple_name' => $simple_name, + 'name' => $definition['name'], + 'description' => $definition['description'], + 'icon_url' => $icon, + 'website' => $definition['website'], + 'categories' => $definition['categories'], + 'privileges' => $definition['privileges'], + 'capabilities' => $definition['capabilities'], + 'hooks' => $definition['hooks'], + 'display' => $definition['display'], + 'api_allowed_ips' => $definition['api_allowed_ips'], + 'api_event_url' => $server_route . "/bundle/connectors/" . $definition["simple_name"] . "/" . ltrim($definition['api_event_url'], "/"), + 'public' => true + ]; + + if($enable){ + //Update database with this app + if(!$app_exists){ + $new_app = $this->app->getServices()->get("app.applications")->createApp(null, $definition["name"], $simple_name, $definition["app_group_name"], null); + $application["id"] = $new_app["id"]; + }else{ + $application["id"] = $app_exists["id"]; + } + + $this->app->getServices()->get("app.applications")->update($application, null); + $this->app->getServices()->get("app.applications")->toggleAppValidation($application["id"], true); + + if($is_default){ + $this->app->getServices()->get("app.applications")->toggleAppDefault($application["id"], true); + } + + error_log("The connector is now available to the public."); + }else{ + //If in database, set to non public + if($app_exists){ + $application["public"] = false; + $application["id"] = $app_exists["id"]; + $this->app->getServices()->get("app.applications")->toggleAppValidation($application["id"], false); + $this->app->getServices()->get("app.applications")->toggleAppDefault($application["id"], false); + } + + error_log("The connector is now unavailable to the public."); + } + + } + + } + } + + if(!$found){ + error_log("This connector was not found."); + } + } + +} diff --git a/twake/backend/core/src/BuiltInConnectors/Common/Controller/Index.php b/twake/backend/core/src/BuiltInConnectors/Common/Controller/Index.php new file mode 100755 index 00000000..cd9dd70e --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Common/Controller/Index.php @@ -0,0 +1,12 @@ +connector_id = $connector_id; + $this->document_id = $document_id; + } + + + /** + * @return mixed + */ + public function getConnectorId() + { + return $this->connector_id; + } + + /** + * @return mixed + */ + public function getDocumentId() + { + return $this->document_id; + } + + /** + * @return mixed + */ + public function getValue() + { + return json_decode($this->value, 1); + } + + /** + * @param mixed $value + */ + public function setValue($value): void + { + $this->value = json_encode($value); + } + +} diff --git a/twake/backend/core/src/BuiltInConnectors/Common/Resources/Routing.php b/twake/backend/core/src/BuiltInConnectors/Common/Resources/Routing.php new file mode 100755 index 00000000..7784d458 --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Common/Resources/Routing.php @@ -0,0 +1,16 @@ + "MainConnectorService" + ]; + +} diff --git a/twake/backend/core/src/BuiltInConnectors/Common/Services/MainConnectorService.php b/twake/backend/core/src/BuiltInConnectors/Common/Services/MainConnectorService.php new file mode 100755 index 00000000..b854ea05 --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Common/Services/MainConnectorService.php @@ -0,0 +1,167 @@ +market_service = $app->getServices()->get("app.applications"); + $this->rest_client = $app->getServices()->get("app.restclient"); + $this->api_url = rtrim($app->getContainer()->getParameter("env.internal_server_name")?:$app->getContainer()->getParameter("env.server_name"), "/") . "/api/v1/"; + $this->server_url = rtrim($app->getContainer()->getParameter("env.server_name"), "/") . "/bundle/connectors/"; + $this->emojione_client = new Client(new Ruleset()); + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + } + + public function setConnector($simple_name){ + $this->app_simple_name = $simple_name; + } + + private function getConnectorKeys(){ + $simple_name = $this->app_simple_name; + if(!isset($this->credentials[$simple_name])){ + $this->credentials[$simple_name] = $this->market_service->getCredentials($simple_name); + } + return $this->credentials[$simple_name]; + } + + public function postApi($route, $data, $timeout = 3, $raw = false){ + + $cred = $this->getConnectorKeys(); + + $custom = array( + CURLOPT_HTTPHEADER => Array( + "Authorization: Basic ".base64_encode($cred["api_id"].":".$cred["api_key"]), + "Content-Type: application/json" + ), + ); + + return $this->post(rtrim($this->api_url, "/") . "/" . ltrim($route, "/"), $data, $raw, $custom, $timeout); + } + + + public function post($route, $data, $raw = false, $custom_options = Array(), $timeout = 1){ + $data_string = json_encode($data); + $restClient = $this->rest_client; + + $custom = array( + CURLOPT_CONNECTTIMEOUT => $timeout, + CURLOPT_SSL_VERIFYPEER => false + ); + + foreach ($custom_options as $key=>$value){ + $custom[$key] = $value; + } + + $resp = $restClient->post($route, $data_string, $custom); + + try { + if(!$raw) { + $data = json_decode($resp->getContent(), 1); + }else{ + $data = $resp->getContent(); + } + return $data; + } catch (\Exception $e) { + return false; + } + } + + + public function get($route, $raw = false, $custom_options = Array(), $timeout = 1){ + $restClient = $this->rest_client; + + $custom = array( + CURLOPT_CONNECTTIMEOUT => $timeout, + CURLOPT_SSL_VERIFYPEER => false + ); + + foreach ($custom_options as $key=>$value){ + $custom[$key] = $value; + } + + $resp = $restClient->get($route, $custom); + + + try { + if(!$raw) { + $data = json_decode($resp->getContent(), 1); + }else{ + $data = $resp->getContent(); + } + return $data; + } catch (\Exception $e) { + return false; + } + } + + public function getServerBaseUrl(){ + return $this->server_url; + } + + public function generateToken($length = 10){ + try { + return bin2hex(random_bytes(intval($length / 2))); + }catch(\Exception $e){ + $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $charactersLength = strlen($characters); + $randomString = ''; + for ($i = 0; $i < $length; $i++) { + $randomString .= $characters[rand(0, $charactersLength - 1)]; + } + return $randomString; + } + } + + + /** + * @return string + */ + public function getAppName() + { + return $this->app_simple_name; + } + + /** Save connector document to db */ + public function saveDocument($id, $content){ + $cred = $this->getConnectorKeys(); + if(!$cred["api_id"]){ + return false; + } + $document = new BuiltInConnectorsEntity($cred["api_id"], $id); + if($content === null){ + $this->doctrine->remove($document); + }else{ + $document->setValue($content); + $this->doctrine->persist($document); + } + $this->doctrine->flush(); + return true; + } + + /** Remove connector document from db */ + public function removeDocument($id){ + return $this->saveDocument($id, null); + } + + /** Get connector document from db */ + public function getDocument($id){ + $cred = $this->getConnectorKeys(); + if(!$cred["api_id"]){ + return false; + } + $documentsRepo = $this->doctrine->getRepository("BuiltInConnectors\Common:BuiltInConnectorsEntity"); + $document = $documentsRepo->findOneBy(["connector_id" => $cred["api_id"], "document_id" => $id]); + return $document?$document->getValue():null; + } +} diff --git a/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Bundle.php b/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Bundle.php new file mode 100755 index 00000000..fd7bfa83 --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Bundle.php @@ -0,0 +1,42 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = "bundle/connectors/" . (new ConnectorDefinition())->definition["simple_name"] . $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + + } + + public function getDefinition(){ + return (new ConnectorDefinition())->definition; + } + + public function getConfiguration(){ + return (new ConnectorDefinition())->configuration; + } + +} diff --git a/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/ConnectorDefinition.php b/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/ConnectorDefinition.php new file mode 100755 index 00000000..b822d95e --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/ConnectorDefinition.php @@ -0,0 +1,43 @@ + 'meet.jit.si' + ]; + + public $definition = [ + 'app_group_name' => 'twake', + 'categories' => [ 'voice_video' ], + 'name' => 'Jitsi', + 'simple_name' => 'jitsi', + 'description' => 'Jitsi allows you to create and join video calls directly from Twake.', + 'icon_url' => 'jitsi.png', + 'website' => 'https://twake.app', + 'privileges' => [], + 'capabilities' => + [ + 'messages_send', + 'display_modal', + 'messages_save', + ], + 'hooks' => [], + 'display' => + [ + 'messages_module' => + [ + 'right_icon' => true, + 'commands' => + [ + [ + 'command' => 'Meeting name', + 'description' => 'Create a Jisti call', + ] + ] + ] + ], + 'api_allowed_ips' => '*', + 'api_event_url' => '/event' + ]; +} diff --git a/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Controller/Index.php b/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Controller/Index.php new file mode 100755 index 00000000..5516bb51 --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Controller/Index.php @@ -0,0 +1,71 @@ +definition; + $route = realpath(__DIR__."/../Resources/medias/".$configuration["icon_url"]); + + $filename = basename($route); + $file_extension = strtolower(substr(strrchr($filename,"."),1)); + + switch( $file_extension ) { + case "gif": $ctype="image/gif"; break; + case "png": $ctype="image/png"; break; + case "jpeg": + case "jpg": $ctype="image/jpeg"; break; + case "svg": $ctype="image/svg+xml"; break; + default: + } + + header('Content-type: ' . $ctype); + + return new Response(file_get_contents($route)); + } + + public function event(Request $request) + { + $data = $request->request->get("data"); + $event = $request->request->get("event"); + $type = $request->request->get("type"); + + $this->get('connectors.jitsi.event')->proceedEvent($type, $event, $data); + + return new Response([]); + } + + public function call(Request $request){ + $user_id = $request->query->get("twake_user", false); + + $id = explode("__", explode("twake_", array_pop(explode("/", $_SERVER['REQUEST_URI'])))[1]); + + $group_id = str_replace("_", "-", $id[0]); + $id = str_replace("_", "", $id[1]); + $user = $this->get('connectors.jitsi.event')->getUserFromId(str_replace("twake-", "", str_replace("_", "-", $id)), $user_id, $group_id); + + $loader = new \Twig\Loader\FilesystemLoader(realpath(__DIR__.'/../Views/')); + $twig = new \Twig\Environment($loader, [ + 'cache' => $this->app->getAppRootDir() . "/" . $this->app->getContainer()->get("configuration", "twig.cache"), + ]); + $template = $twig->load("Templates/call.html.twig"); + + $configuration = (new ConnectorDefinition())->configuration; + + return new Response($template->render( + Array( + "id" => $id, + "user" => $user, + "jitsi_domain" => $this->getParameter("defaults.connectors.jitsi.jitsi_domain", $configuration["jitsi_domain"]) + ) + )); + } + +} diff --git a/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Resources/Routing.php b/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Resources/Routing.php new file mode 100755 index 00000000..d695ece8 --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Resources/Routing.php @@ -0,0 +1,18 @@ + ["handler" => "Index:icon", "methods" => ["GET"]], + "event" => ["handler" => "Index:event", "methods" => ["POST"]], + "call/{id}" => ["handler" => "Index:call", "methods" => ["GET"]], + ]; + +} diff --git a/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Resources/Services.php b/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Resources/Services.php new file mode 100755 index 00000000..2da62d6b --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Resources/Services.php @@ -0,0 +1,13 @@ + "Event" + ]; + +} diff --git a/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Resources/medias/jitsi.png b/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Resources/medias/jitsi.png new file mode 100755 index 00000000..44df6908 Binary files /dev/null and b/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Resources/medias/jitsi.png differ diff --git a/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Services/Event.php b/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Services/Event.php new file mode 100755 index 00000000..ca65ee84 --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Services/Event.php @@ -0,0 +1,137 @@ +main_service = $app->getServices()->get("connectors.common.main"); + } + + public function getUserFromId($room_id, $user_id, $group_id = null){ + $this->main_service->setConnector("jitsi"); + + $user_object = $this->main_service->postApi("users/get", Array("user_id" => $user_id, "group_id" => $group_id)); + return $user_object["object"]; + } + + public function proceedEvent($type, $event, $data) + { + $this->main_service->setConnector("jitsi"); + + $group = $data["group"]; + $user = $data["user"]; + $message = $data["message"]; + $channel = $data["channel"]; + $parent_message = $data["parent_message"]; + $creator = $data["user"]; + + if ($type == "action" && ($event == "command" || $event == "open")) { + + $message = [ + "channel_id" => $channel["id"], + "content" => Array( + Array("type"=>"system", "content"=>"Choose a subject for your call"), + Array("type"=>"br"), + Array("type"=>"input", "content" => $data["command"], "placeholder" => "Meeting about ...", "passive_id" => "meeting_name"), + Array("type"=>"br"), + Array("type"=>"button", "style"=>"default", "action_id"=>"cancel", "content"=>"Cancel"), + Array("type"=>"button", "style"=>"primary", "action_id"=>"create", "content"=>"Create") + ), + "hidden_data" => Array( + ), + "parent_message_id" => isset($parent_message["id"])?$parent_message["id"]:"", + "ephemeral_message_recipients" => [$user["id"]], + "_once_ephemeral_message" => true + ]; + + $data_string = Array( + "group_id" => $group["id"], + "workspace_id" => $channel["workspace_id"], + "message" => $message + ); + $message = $this->main_service->postApi("messages/save", $data_string); + + } + + if ($type == "interactive_message_action" && $event == "cancel") { + + $data_string = Array( + "group_id" => $group["id"], + "workspace_id" => $channel["workspace_id"], + "message" => $data["message"] + ); + + $this->main_service->postApi("messages/remove", $data_string); + + } + + if ($type == "interactive_message_action" && $event == "create") { + + $original_message = $message; + + $room_id = $group["id"]."__".$original_message["channel_id"]; + + $url = rtrim($this->main_service->getServerBaseUrl(), "/") . "/jitsi/call/twake_" . str_replace("-", "_", $room_id); + + $message = []; + $message["channel_id"] = $original_message["channel_id"]; + $message["sender"] = $user["id"]; + $message["parent_message_id"] = isset($original_message["parent_message_id"])?$original_message["parent_message_id"]:""; + $message["content"] = Array( + ["type" => "system", "content" => ["@" . $creator["username"] . " invite you to join the call ", ["type" => "bold", "content" => $data["form"]["meeting_name"]],". "]], + ["type" => "system", "content" => ["type" => "button", "inline" => "true", "style"=>"primary", "action_id"=>"show_link", "content" => "Show call link"]], + ["type" => "br"], + ["type" => "url", "user_identifier" => true, "url" => $url, "content" => ["type" => "button", "content" => ["Join call ", ["type" => "bold", "content" => $data["form"]["meeting_name"]]]]]); + $message["hidden_data"] = Array( + "allow_delete" => "everyone", + "room_id" => $room_id + ); + + $data_string = Array( + "group_id" => $group["id"], + "workspace_id" => $channel["workspace_id"], + "message" => $data["message"] + ); + $this->main_service->postApi("messages/remove", $data_string); + + $data_string = Array( + "group_id" => $group["id"], + "workspace_id" => $channel["workspace_id"], + "message" => $message + ); + + $message = $this->main_service->postApi("messages/save", $data_string); + + $message_id = $message["object"]["id"]; + + } + + if ($type == "interactive_message_action" && $event == "show_link") { + + $room_id = $message["hidden_data"]["room_id"]; + + $url = rtrim($this->main_service->getServerBaseUrl(), "/") . "/jitsi/call/twake_" . str_replace("-", "_", $room_id); + + $display = Array( + "type" => "system", "content" => [ + "Partagez ce lien avec les participants de l'appel.", + Array("type" => "br"), + Array("type" => "copiable", "content" => $url) + ] + ); + + $data_string = Array( + "group_id" => $group["id"], + "user_id" => $data["user"]["id"], + "connection_id" => $data["connection_id"], + "form" => $display + ); + $this->main_service->postApi("general/configure", $data_string); + + } + + } + +} diff --git a/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Views/Templates/call.html.twig b/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Views/Templates/call.html.twig new file mode 100755 index 00000000..0fa3d94f --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Connectors/Jitsi/Views/Templates/call.html.twig @@ -0,0 +1,59 @@ + + + + + + + + + + +
+ +
+ + + + + diff --git a/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Bundle.php b/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Bundle.php new file mode 100755 index 00000000..ae7f00c5 --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Bundle.php @@ -0,0 +1,42 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = "bundle/connectors/" . (new ConnectorDefinition())->definition["simple_name"] . $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + + } + + public function getDefinition(){ + return (new ConnectorDefinition())->definition; + } + + public function getConfiguration(){ + return (new ConnectorDefinition())->configuration; + } + +} diff --git a/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/ConnectorDefinition.php b/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/ConnectorDefinition.php new file mode 100755 index 00000000..6b208434 --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/ConnectorDefinition.php @@ -0,0 +1,62 @@ + '', + 'key' => [ + "issuer" => "Twake", + "private" => "-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgHpJ/MAWh52lMCOt4btMb06LHAXn3BrrQoKrZ5IEPPLKqGwl7MVn +X6r+wEtMX5MmTQ68JHb4ohVVjKiJyySql/GXNcwGmx8jhTpFBzOTRDJBm60Z8wz3 +G4Uy0IPWt1TRz4oiS9V5cC69ZpvxOQd/yaeN9BDkI/Tda4fDOa3PRINRAgMBAAEC +gYA1+uzf2dIZS26ZgUrQQ6gqcot3K+bj1w9v4LuCH+7LeZuoyYDfjocTUwqM8nSJ +3vFK3M/32D6rziydxN1wHQGench+cfR8yun8V9EV7Y5bTIX8DwMvLGvBkZT0u5Ai +J3g6JkWZTQHdthbOyADCgv7OxCjLrq9egE6py2R5cqk4NQJBALayivwy3WizoKNl +hpTdnIngyUbQnRd/3Enx50qaM3qGjyIpENOsNBhJQDtfQf82MRjAhrrsPSDmGvjL +HXFpqNsCQQCrWrIoGx68e//A5GR8dK7XfxBYaTPsXEXQD3uvegFxYxJJj26Qw8lx +i6XKA2lZKuAiyISrk1UWezG/gCzkF5ZDAkBCyDjtv1oXr7GEiNQNDoTuEXEBpbgG +owJPNVGqf3tZyl3/yqsP9N6GEiCck1F4jMKdnaKiKUCfCf3J+9UjY9AJAkA14SPJ +xpVIkPjfLzGFjK75ZaO/GP1RocX14Rh0GbngbFVwud/7NwTdZhqwRZhXiErHxSMq +S/5iPkRrQaNb6Sq/AkEAqQIOghY6T0SPrKfj+utFJMe0YchSU/bjApyE6U3pj1Vf +JZ7e+kO+wtORxj1bDh9nE6YEvW/fOY6/Sw+HoyYW9w== +-----END RSA PRIVATE KEY-----", + "public" => "-----BEGIN PUBLIC KEY----- +MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHpJ/MAWh52lMCOt4btMb06LHAXn +3BrrQoKrZ5IEPPLKqGwl7MVnX6r+wEtMX5MmTQ68JHb4ohVVjKiJyySql/GXNcwG +mx8jhTpFBzOTRDJBm60Z8wz3G4Uy0IPWt1TRz4oiS9V5cC69ZpvxOQd/yaeN9BDk +I/Tda4fDOa3PRINRAgMBAAE= +-----END PUBLIC KEY-----" + ] + ]; + + public $definition = [ + 'app_group_name' => 'linshare', + 'categories' => [ 'files' ], + 'name' => 'Linshare', + 'simple_name' => 'linshare', + 'description' => 'Linshare allows you to send Linshare documents into Twake messages.', + 'icon_url' => 'linshare.jpg', + 'website' => 'https://www.linshare.org/', + 'privileges' => [], + 'capabilities' => + [ + "messages_save", + 'display_modal', + ], + 'hooks' => [], + 'display' => [ + "messages_module" => [ + "in_plus" => [ + "should_wait_for_popup" => true + ] + ], + "configuration" => [ + "can_configure_in_workspace" => true + ] + ], + 'api_allowed_ips' => '*', + 'api_event_url' => '/event' + ]; +} diff --git a/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Controller/Index.php b/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Controller/Index.php new file mode 100755 index 00000000..cc973947 --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Controller/Index.php @@ -0,0 +1,61 @@ +definition; + $route = realpath(__DIR__."/../Resources/medias/".$configuration["icon_url"]); + + $filename = basename($route); + $file_extension = strtolower(substr(strrchr($filename,"."),1)); + + switch( $file_extension ) { + case "gif": $ctype="image/gif"; break; + case "png": $ctype="image/png"; break; + case "jpeg": + case "jpg": $ctype="image/jpeg"; break; + case "svg": $ctype="image/svg+xml"; break; + default: + } + + header('Content-type: ' . $ctype); + + return new Response(file_get_contents($route)); + } + + public function event(Request $request) + { + $data = $request->request->get("data"); + $event = $request->request->get("event"); + $type = $request->request->get("type"); + + if($event == "workspace" && $type == "configuration" || $event == "save_configuration_domain"){ + $this->get('connectors.linshare.configure')->proceedEvent($type, $event, $data); + }else{ + $this->get('connectors.linshare.event')->proceedEvent($type, $event, $data); + } + + return new Response([]); + } + + public function download(Request $request) + { + $file_uuid = $request->query->get("file_uuid"); + $group_id = $request->query->get("group_id"); + $owner_id = $request->query->get("owner_id"); + $sign = $request->query->get("sign"); + $twake_user = $request->query->get("twake_user"); + + $this->get('connectors.linshare.event')->download($twake_user, $file_uuid, $group_id, $owner_id, $sign); + return new Response([]); + } + +} diff --git a/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Resources/Routing.php b/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Resources/Routing.php new file mode 100755 index 00000000..a1366409 --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Resources/Routing.php @@ -0,0 +1,18 @@ + ["handler" => "Index:icon", "methods" => ["GET"]], + "event" => ["handler" => "Index:event", "methods" => ["POST"]], + "download" => ["handler" => "Index:download", "methods" => ["GET"]], + ]; + +} diff --git a/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Resources/Services.php b/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Resources/Services.php new file mode 100755 index 00000000..ebb47698 --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Resources/Services.php @@ -0,0 +1,14 @@ + "Configure", + "connectors.linshare.event" => "Event" + ]; + +} diff --git a/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Resources/medias/linshare.jpg b/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Resources/medias/linshare.jpg new file mode 100755 index 00000000..f407500f Binary files /dev/null and b/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Resources/medias/linshare.jpg differ diff --git a/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Services/Configure.php b/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Services/Configure.php new file mode 100755 index 00000000..4509e88f --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Services/Configure.php @@ -0,0 +1,77 @@ +app = $app; + $this->main_service = $app->getServices()->get("connectors.common.main"); + } + + public function proceedEvent($type, $event, $data) { + $this->main_service->setConnector("linshare"); + $configuration = (new ConnectorDefinition())->configuration; + $linshare_domain = $this->app->getContainer()->getParameter("defaults.connectors.linshare.domain", $configuration["domain"]); + + $group = $data["group"]; + $entity = null; + $user = $data["user"]; + $workspace = $data["workspace"]; + + if($event == "save_configuration_domain"){ + + $document_id = $group["id"]."_domain_conf"; + $document_value = $data["form"]["domain_url"]; + $this->main_service->saveDocument($document_id, $document_value); + + $type = "configuration"; //Reopen/Update configuration + } + + if ($type == "configuration") { + + $document_id = $group["id"]."_domain_conf"; + $document_value = $this->main_service->getDocument($document_id); + if($document_value){ + $linshare_domain = $document_value; + } + + $linshare_publickey = $this->app->getContainer()->getParameter("defaults.connectors.linshare.key.public", $configuration["key"]["public"]); + + $form = Array("type" => "nop", "content" => [ + Array("type" => "nop" , "content" => "β€’ To configure your company with LinShare you must enter your LinShare domain URL first."), + Array("type" => "br"), + Array("type" => "br"), + Array("type" => "bold" , "content" => "Domain url"), + Array("type" => "br"), + Array("type" => "input", "placeholder" => "https://linshare.org", "content" => $linshare_domain, "passive_id" => "domain_url"), + Array("type" => "button", "content" => "Save domain", "action_id" => "save_configuration_domain", "style" => "primary"), + Array("type" => "br"), + Array("type" => "system" , "content" => ["Current domain is ", Array("type" => "bold" , "content" => $linshare_domain)]), + Array("type" => "br"), + Array("type" => "br"), + Array("type" => "nop" , "content" => "β€’ To authorize Twake in LinShare, add this public key to LinShare adminitration."), + Array("type" => "br"), + Array("type" => "br"), + Array("type" => "bold" , "content" => "Public key"), + Array("type" => "br"), + Array("type" => "mcode", "content" => $linshare_publickey) + ]); + + $data_string = Array( + "group_id" => $group["id"], + "user_id" => $user["id"], + "connection_id" => $data["connection_id"], + "form" => $form + ); + + $res = $this->main_service->postApi("general/configure", $data_string); + + } + + } + +} diff --git a/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Services/Event.php b/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Services/Event.php new file mode 100755 index 00000000..99e0ce1d --- /dev/null +++ b/twake/backend/core/src/BuiltInConnectors/Connectors/Linshare/Services/Event.php @@ -0,0 +1,245 @@ +app = $app; + $this->main_service = $app->getServices()->get("connectors.common.main"); + } + + public function getJWT($user_email){ + $configuration = (new ConnectorDefinition())->configuration; + + $data = []; + $data["sub"] = $user_email; + + $linshare_privatekey = $this->app->getContainer()->getParameter("defaults.connectors.linshare.key.private", $configuration["key"]["private"]); + $data["iss"] = $this->app->getContainer()->getParameter("defaults.connectors.linshare.key.issuer", $configuration["key"]["issuer"]) ?: "Twake"; + + // Create JWT + $header = json_encode(['alg' => 'RS512']); + $data["iat"] = date("U"); + $data["exp"] = date("U") + 5 * 60; + $payload = json_encode($data); + $base64UrlHeader = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header)); + $base64UrlPayload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload)); + openssl_sign( $base64UrlHeader . "." . $base64UrlPayload, $signature, $linshare_privatekey, OPENSSL_ALGO_SHA512); + $base64UrlSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature)); + $jwt = $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature; + + return $jwt; + } + + public function proceedEvent($type, $event, $data) { + $this->main_service->setConnector("linshare"); + $definition = (new ConnectorDefinition())->definition; + + $group = $data["group"]; + $entity = null; + $user = $data["user"]; + $workspace = $data["workspace"]; + $channel = $data["channel"]; + $parent_message = $data["parent_message"]; + $interactive_context = $data["interactive_context"]; + + if ($type == "action") { + + $linshare_domain = $this->app->getContainer()->getParameter("defaults.connectors.linshare.domain", $configuration["domain"]); + $document_id = $group["id"]."_domain_conf"; + $document_value = $this->main_service->getDocument($document_id); + if($document_value){ + $linshare_domain = $document_value; + } + + // GET Documents from LinShare + $token = $this->getJWT($user["email"]); + $documents = $this->main_service->get(rtrim($linshare_domain, "/") . "/linshare/webservice/rest/user/documents/", false, [ + CURLOPT_HTTPHEADER => [ + "Accept: application/json", + "Authorization: Bearer " . $token + ] + ]); + + $values = []; + foreach($documents as $document){ + $uuid = $document["uuid"]; + $values[] = [ + "name" => $document["name"], + "value" => json_encode(["uuid"=>$uuid, "name"=>$document["name"]]) + ]; + } + $select = [ + "type" => "select", + "title"=>"Choose file", + "values" => $values, + "passive_id" => "file_select" + ]; + + $form = Array("type" => "nop", "content" => [ + "Choose a file to send from your space", + Array("type" => "br"), + $select, + Array("type" => "br"), + Array("type" => "button", "action_id" => "send_file", "content" => "Envoyer", "interactive_context" => [ + "channel_id" => $channel["id"] + ]), + ]); + + $data_string = Array( + "group_id" => $group["id"], + "user_id" => $user["id"], + "connection_id" => $data["connection_id"], + "form" => $form + ); + + $res = $this->main_service->postApi("general/configure", $data_string); + + } + + if($type == "interactive_configuration_action" && $event == "send_file"){ + + $data_string = Array( + "group_id" => $group["id"], + "user_id" => $user["id"], + "connection_id" =>$data["connection_id"] + ); + $this->main_service->postApi("general/configure_close", $data_string); + + $file = json_decode($data["form"]["file_select"], 1); + $server_route = rtrim($this->app->getContainer()->getParameter("env.server_name"), "/"); + + if(!$file || !$file["name"]){ + return; + } + + $download_parameters = [ + "file_uuid=" . $file["uuid"], + "group_id=" . $group["id"], + "owner_id=" . $user["id"] + ]; + $download_route = $server_route . "/bundle/connectors/" . $definition["simple_name"] . "/download"; + $download_route = $download_route . "?" . join("&", $download_parameters); + $linshare_privatekey = $this->app->getContainer()->getParameter("defaults.connectors.linshare.key.private", $configuration["key"]["private"]); + openssl_sign($file["uuid"] . $user["id"], $signature, $linshare_privatekey, OPENSSL_ALGO_SHA512); + $download_route .= "&sign=" . str_replace(str_split('+/='), str_split('._-'), base64_encode($signature)); + + $message["channel_id"] = $interactive_context["channel_id"]; + $message["sender"] = $user["id"]; + $message["parent_message_id"] = isset($parent_message["id"])?$parent_message["id"]:""; + + $message["content"] = Array( + ["type" => "url", "user_identifier" => true, "url" => $download_route, "content" => ["type" => "button", "content" => "Download " . $file["name"]]] + ); + $message["hidden_data"] = Array( + "allow_delete" => "everyone" + ); + + $data_string = Array( + "group_id" => $group["id"], + "message" => $message + ); + + $message = $this->main_service->postApi("messages/save", $data_string); + + } + + } + + public function download($twake_user, $file_uuid, $group_id, $owner_id, $sign){ + + $this->main_service->setConnector("linshare"); + + $linshare_publickey = $this->app->getContainer()->getParameter("defaults.connectors.linshare.key.public", $configuration["key"]["public"]); + $r = openssl_verify($file_uuid . $owner_id, base64_decode(str_replace(str_split('._-'), str_split('+/='), $sign)), $linshare_publickey, OPENSSL_ALGO_SHA512); + if(!$r){ + echo "This document isn't available."; + die(); + } + + + $linshare_domain = $this->app->getContainer()->getParameter("defaults.connectors.linshare.domain", $configuration["domain"]); + $document_id = $group_id."_domain_conf"; + $document_value = $this->main_service->getDocument($document_id); + if($document_value){ + $linshare_domain = $document_value; + } + + //Get user email + $user_object = $this->main_service->postApi("users/get", Array("user_id" => $twake_user, "group_id" => $group_id)); + $requester_email = $user_object["object"]["email"]; + + //Get owner email + $owner_email = $requester_email; + if($twake_user != $owner_id){ + $user_object = $this->main_service->postApi("users/get", Array("user_id" => $owner_id, "group_id" => $group_id)); + $owner_email = $user_object["object"]["email"]; + } + + //TODO download as the requester and not as the owner + + //Test if user has access to this file + $token = $this->getJWT($owner_email); + $document = $this->main_service->get(rtrim($linshare_domain, "/") . "/linshare/webservice/rest/user/documents/".$file_uuid, false, [ + CURLOPT_HTTPHEADER => [ + "Accept: application/json", + "Authorization: Bearer " . $token + ] + ]); + + if(!$document){ + echo "This document isn't available."; + die(); + } + + $size = $document["size"]; + $quoted = $document["name"]; + + header('Content-Description: File Transfer'); + header('Content-Type: application/octet-stream'); + header('Content-Disposition: attachment; filename=' . $quoted); + header('Content-Transfer-Encoding: binary'); + header('Connection: Keep-Alive'); + header('Expires: 0'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Pragma: public'); + if($size) header('Content-Length: ' . $size); + + $url = rtrim($linshare_domain, "/") . "/linshare/webservice/rest/user/documents/".$file_uuid."/download"; + + $options = [ + CURLOPT_HTTPHEADER => [ + "Accept: application/json", + "Authorization: Bearer " . $token + ] + ]; + + $options[CURLOPT_RETURNTRANSFER] = true; + $options[CURLOPT_HEADER] = false; + $options[CURLOPT_URL] = $url; + $options[CURLOPT_CUSTOMREQUEST] = "GET"; + + $curl_write_flush = function ($curl_handle, $chunk) + { + echo $chunk; + ob_flush(); // flush output buffer (Output Control configuration specific) + flush(); // flush output body (SAPI specific) + return strlen($chunk); // tell Curl there was output (if any). + }; + + $curl = curl_init(); + curl_setopt_array($curl, $options); + curl_setopt($curl, CURLOPT_BINARYTRANSFER, 1); + curl_setopt($curl, CURLOPT_WRITEFUNCTION, $curl_write_flush); + curl_exec($curl); + curl_close($curl); + + die(); + + } + +} diff --git a/twake/backend/core/src/DevelopersApiV1/Calendar/Bundle.php b/twake/backend/core/src/DevelopersApiV1/Calendar/Bundle.php new file mode 100755 index 00000000..aa5cf98a --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Calendar/Bundle.php @@ -0,0 +1,26 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Calendar/Controller/Calendar.php b/twake/backend/core/src/DevelopersApiV1/Calendar/Controller/Calendar.php new file mode 100755 index 00000000..577535ba --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Calendar/Controller/Calendar.php @@ -0,0 +1,122 @@ +get("app.applications_api")->getAppFromRequest($request, $capabilities); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + + $object = $request->request->get("object", null); + $user = null; + $object = $this->get("app.calendar.event")->remove($object, Array(), $user); + + $event = Array( + "client_id" => "system", + "action" => "remove", + "object_type" => "", + "front_id" => $object["front_id"] + ); + $workspace_calendars = $object["workspaces_calendars"] ? $object["workspaces_calendars"] : []; + $workspace_ids = []; + foreach ($workspace_calendars as $wc) { + if (!in_array($wc["workspace_id"], $workspace_ids)) { + $workspace_ids[] = $wc["workspace_id"]; + $this->get("app.websockets")->push("calendar_events/" . $wc["workspace_id"], $event); + } + } + + $this->get("administration.counter")->incrementCounter("total_api_calendar_operation", 1); + + return new Response(Array("result" => $object)); + } + + public function saveEvent(Request $request) + { + $capabilities = ["calendar_event_save"]; + $application = $this->get("app.applications_api")->getAppFromRequest($request, $capabilities); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + + $object = $request->request->get("object", null); + $user = null; + try { + $object = $this->get("app.calendar.event")->save($object, Array(), $user); + } catch (\Exception $e) { + $object = false; + } + if (!$object) { + return new Response(Array("error" => "unknown error or malformed query.")); + } + + if ($object) { + + $event = Array( + "client_id" => "system", + "action" => "save", + "object_type" => "", + "object" => $object + ); + $workspace_calendars = $object["workspaces_calendars"] ? $object["workspaces_calendars"] : []; + $workspace_ids = []; + foreach ($workspace_calendars as $wc) { + if (!in_array($wc["workspace_id"], $workspace_ids)) { + $workspace_ids[] = $wc["workspace_id"]; + $this->get("app.websockets")->push("calendar_events/" . $wc["workspace_id"], $event); + } + } + + } + + $this->get("administration.counter")->incrementCounter("total_api_calendar_operation", 1); + + return new Response(Array("object" => $object)); + + } + + public function getCalendarList(Request $request) + { + $privileges = ["workspace_calendar"]; + + $application = $this->get("app.applications_api")->getAppFromRequest($request, [], $privileges); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + $objects = false; + $user_id = $request->request->get("user_id", ""); + $workspace_id = $request->request->get("workspace_id", ""); + if ($workspace_id) { + if ($user_id) { + $user_entity = $this->get("app.users")->getById($user_id, true); + } + if ($user_entity) { + $objects = $this->get("app.calendar.calendar")->get(Array("workspace_id" => $workspace_id), $user_entity); + } + } + + if ($objects === false) { + return new Response(Array("error" => "payload_error")); + } + + $res = []; + foreach ($objects as $object) { + $res[] = $object; + } + + $this->get("administration.counter")->incrementCounter("total_api_calendar_operation", 1); + + return new Response(Array("data" => $res)); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Calendar/Resources/Routing.php b/twake/backend/core/src/DevelopersApiV1/Calendar/Resources/Routing.php new file mode 100755 index 00000000..ef70cfa3 --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Calendar/Resources/Routing.php @@ -0,0 +1,19 @@ + ["handler" => "Calendar:removeEvent", "methods" => ["POST"]], + "event/save" => ["handler" => "Calendar:saveEvent", "methods" => ["POST"]], + "get_calendars" => ["handler" => "Calendar:getCalendarList", "methods" => ["POST"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Channels/Bundle.php b/twake/backend/core/src/DevelopersApiV1/Channels/Bundle.php new file mode 100755 index 00000000..947a29ab --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Channels/Bundle.php @@ -0,0 +1,26 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Channels/Controller/Channel.php b/twake/backend/core/src/DevelopersApiV1/Channels/Controller/Channel.php new file mode 100755 index 00000000..2b88b24d --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Channels/Controller/Channel.php @@ -0,0 +1,80 @@ +get("app.applications_api")->getAppFromRequest($request, $capabilities); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + + $user_id = $request->request->get("user_id", ""); + + if ($user_id) { + $user_entity = $this->get("app.users")->getById($user_id, true); + if ($user_entity) { + $object = $this->get("app.channels.direct_messages_system")->save(Array("app_id" => $application->getId(), "group_id" => $request->request->get("group_id", null)), Array(), $user_entity); + } + } + + $this->get("administration.counter")->incrementCounter("total_api_messages_operation", 1); + + return new Response(Array("object" => $object)); + + } + + public function getChannelsByWorkspace(Request $request) + { + $privileges = ["channels"]; + + $application = $this->get("app.applications_api")->getAppFromRequest($request, [], $privileges); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + $objects = false; + $user_id = $request->request->get("user_id", ""); + $workspace_id = $request->request->get("workspace_id", ""); + if ($workspace_id) { + if ($user_id) { + $user_entity = $this->get("app.users")->getById($user_id, true); + } + if ($user_entity) { + $objects = $this->get("app.channels.channels_system")->get(Array("workspace_id" => $workspace_id), $user_entity); + } + } + + if ($objects === false) { + return new Response(Array("error" => "payload_error")); + } + + $res = []; + foreach ($objects as $object) { + if (!$object["direct"] && !$object["application"]) { + $res[] = $object; + } + } + + $this->get("administration.counter")->incrementCounter("total_api_messages_operation", 1); + + return new Response(Array("data" => $res)); + } + +} diff --git a/twake/backend/core/src/DevelopersApiV1/Channels/Resources/Routing.php b/twake/backend/core/src/DevelopersApiV1/Channels/Resources/Routing.php new file mode 100755 index 00000000..8e1e7a92 --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Channels/Resources/Routing.php @@ -0,0 +1,18 @@ + ["handler" => "Channel:getDirectChannel", "methods" => ["POST"]], + "get_by_workspace" => ["handler" => "Channel:getChannelsByWorkspace", "methods" => ["POST"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Core/Bundle.php b/twake/backend/core/src/DevelopersApiV1/Core/Bundle.php new file mode 100755 index 00000000..bc6f683b --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Core/Bundle.php @@ -0,0 +1,30 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Core/Controller/Base.php b/twake/backend/core/src/DevelopersApiV1/Core/Controller/Base.php new file mode 100755 index 00000000..dff4fa95 --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Core/Controller/Base.php @@ -0,0 +1,32 @@ +get("api.v1.check_user_data")->getInfo($request->request->get("token", null)); + if ($info) + return new Response($info->getAsArray()); + else + return new Response(array("error" => "invalid_token")); + } + + public function BadRequest() + { + return new Response(Array("errors" => "0000", "description" => "Bad request")); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Core/Entity/AccessLog.php b/twake/backend/core/src/DevelopersApiV1/Core/Entity/AccessLog.php new file mode 100755 index 00000000..8c5ac1d1 --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Core/Entity/AccessLog.php @@ -0,0 +1,178 @@ +id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getAppId() + { + return $this->appid; + } + + /** + * @param mixed $appid + */ + public function setAppId($appid) + { + $this->appid = $appid; + } + + /** + * @return mixed + */ + public function getMinutes() + { + return $this->minutes; + } + + /** + * @param mixed $minutes + */ + public function setMinutes($minutes) + { + $this->minutes = $minutes; + } + + /** + * @return mixed + */ + public function getReadAccessCount() + { + return $this->readaccesscount; + } + + /** + */ + public function readAccessIncrease() + { + $this->readAccessCount++; + } + + /** + * @return mixed + */ + public function getWriteAccessCount() + { + return $this->writeaccesscount; + } + + /** + */ + public function writeAccessIncrease() + { + $this->writeAccessCount++; + } + + /** + * @return mixed + */ + public function getManageAccessCount() + { + return $this->manageaccesscount; + } + + /** + */ + public function manageAccessIncrease() + { + $this->manageAccessCount++; + } + + /** + * @param mixed $readaccesscount + */ + public function setReadAccessCount($readaccesscount) + { + $this->readaccesscount = $readaccesscount; + } + + + /** + * @param mixed $writeaccesscount + */ + public function setWriteAccessCount($writeaccesscount) + { + $this->writeaccesscount = $writeaccesscount; + } + + /** + * @param mixed $manageaccesscount + */ + public function setManageAccessCount($manageaccesscount) + { + $this->manageaccesscount = $manageaccesscount; + } + + public function clear($minutes) + { + $this->setMinutes($minutes); + $this->setReadAccessCount(0); + $this->setWriteAccessCount(0); + $this->setManageAccessCount(0); + } + + public function __construct() + { + $this->setId(0); + $this->setAppId(0); + $this->setMinutes(0); + $this->setReadAccessCount(0); + $this->setWriteAccessCount(0); + $this->setManageAccessCount(0); + } +} diff --git a/twake/backend/core/src/DevelopersApiV1/Core/Resources/Routing.php b/twake/backend/core/src/DevelopersApiV1/Core/Resources/Routing.php new file mode 100755 index 00000000..297b66c0 --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Core/Resources/Routing.php @@ -0,0 +1,16 @@ + ["handler" => "Base:getInfoFromToken", "methods" => ["POST"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Core/Resources/Services.php b/twake/backend/core/src/DevelopersApiV1/Core/Resources/Services.php new file mode 100755 index 00000000..b2321b21 --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Core/Resources/Services.php @@ -0,0 +1,20 @@ + "CheckService", +// arguments: ["@app.twake_doctrine", "@api.v1.access_log"] + "api.v1.api_status" => "ApiStatus", +// arguments: ["@app.twake_doctrine"] + "api.v1.access_log" => "AccessLogSystem", +// arguments: ["@app.twake_doctrine"] + "api.v1.check_user_data" => "CheckUserInfo", +// arguments: ["@app.twake_doctrine"] + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Core/Services/AccessLogSystem.php b/twake/backend/core/src/DevelopersApiV1/Core/Services/AccessLogSystem.php new file mode 100755 index 00000000..a91010f1 --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Core/Services/AccessLogSystem.php @@ -0,0 +1,51 @@ +doctrine = $app->getServices()->get("app.twake_doctrine"); + + } + + public function record($applicationId, $rightLevel) + { + $accessLogger = $this->doctrine->getRepository("DevelopersApiV1\Core:AccessLog")->findOneBy(Array("appid" => $applicationId)); + + if ($accessLogger == null) { + $accessLogger = new AccessLog(); + $accessLogger->setAppId($applicationId); + } + + $minutes = $accessLogger->getMinutes(); + + if ($minutes != date("i")) + $accessLogger->clear(date("i")); + + if ($rightLevel == 1) //read + $accessLogger->readAccessIncrease(); + elseif ($rightLevel == 2) //write + $accessLogger->writeAccessIncrease(); + elseif ($rightLevel == 3) //manage + $accessLogger->manageAccessIncrease(); + + $this->doctrine->persist($accessLogger); + $this->doctrine->flush(); + + return true; + } +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Core/Services/ApiStatus.php b/twake/backend/core/src/DevelopersApiV1/Core/Services/ApiStatus.php new file mode 100755 index 00000000..1d0b2a7f --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Core/Services/ApiStatus.php @@ -0,0 +1,108 @@ +map[1] = "Incorrect authentification"; + $this->map[2] = "You have not the rights to perform this action"; + $this->map[3] = "Token not found"; + + //999 < errors from Workspace < 2000 + $this->map[1000] = "The workspace does not exist or is incorrect"; + $this->map[1001] = "Array empty. The workspace is incorrect"; + $this->map[1002] = "No level found"; + + //1999 < errors from Drive < 3000 + $this->map[2000] = "The file have not been created"; + $this->map[2001] = "The file does not exist in this workspace or is not accessible"; + $this->map[2002] = "The file or the folder was not deleted"; + $this->map[2003] = "The file or the folder has not been thrown away"; + $this->map[2004] = "The file or the folder has not been restored"; + $this->map[2005] = "The content of the trash has not been restored"; + $this->map[2006] = "The trash has not been emptied"; + $this->map[2007] = "Failed to get informations"; + $this->map[2008] = "No content and no url has been given"; + $this->map[2009] = "The folder has not been shared"; + $this->map[2010] = "The folder has not been unshared"; + $this->map[2011] = "The file has not been renamed"; + $this->map[2012] = "The array is empty"; + $this->map[2013] = "The search is impossible"; + $this->map[2014] = "Impossible to return the list of files contained into the folder"; + $this->map[2015] = "The file has not been moved"; + $this->map[2016] = "The content of the file has not been set"; + + //2999 < errors from Messages < 4000 + $this->map[3000] = "Stream not found"; + $this->map[3001] = "Message not found"; + $this->map[3002] = "Failed to post message"; + $this->map[3003] = "Failed to get message"; + $this->map[3004] = "Failed to get message children"; + $this->map[3005] = "Failed to edit a message"; + $this->map[3006] = "Failed to delete a message"; + $this->map[3007] = "Failed to get stream content"; + $this->map[3008] = ""; + $this->map[3009] = "Failed to get stream list"; + $this->map[3010] = "Failed to change message in subject"; + $this->map[3011] = "Failed to move a message in a message"; + $this->map[3012] = ""; + $this->map[3013] = "Failed to close a subject"; + $this->map[3014] = "Failed to move message in subject"; + $this->map[3015] = "Failed to delete a stream"; + $this->map[3016] = "Failed to create a stream"; + $this->map[3017] = "Failed to edit a stream"; + $this->map[3018] = ""; + $this->map[3019] = "Failed to add a member"; + $this->map[3020] = "Failed to remove a member"; + $this->map[3021] = "Failed to edit a subject"; + $this->map[3022] = "Failed to get all subjects from a stream"; + + //3999 < errors from Calendar < 5000 + $this->map[4000] = " No content in the request "; + $this->map[4001] = " Fail to create a calendar"; + $this->map[4002] = " Fail to delete a calendar"; + $this->map[4003] = " Fail to edit a calendar"; + $this->map[4004] = " Fail to get a calendar"; + $this->map[4005] = " Fail to share a calendar"; + $this->map[4006] = " Fail to unshare a calendar "; + $this->map[4007] = " Fail to create an event "; + $this->map[4008] = " Fail to delete an event "; + $this->map[4009] = " Fail to edit an event "; + $this->map[4009] = " Fail to get an event "; + $this->map[4011] = " Fail to share an event "; + $this->map[4012] = " Fail to unshare an event "; + $this->map[4013] = " Fail to get all events "; + $this->map[4014] = " Fail to get all calendars "; + $this->map[4015] = " Fail to generate calenda "; + } + + public function getError($code) + { + $message = $this->map[$code]; + $response = Array("status" => "error", "code" => $code, "message" => $message); + return $response; + } + + public function getSuccess() + { + $response = Array("status" => "success"); + return $response; + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Core/Services/CheckService.php b/twake/backend/core/src/DevelopersApiV1/Core/Services/CheckService.php new file mode 100755 index 00000000..168e1d41 --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Core/Services/CheckService.php @@ -0,0 +1,102 @@ +doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->accessLogService = $app->getServices()->get("api.v1.access_log"); + + } + + public function check(Request $request) + { + + $application = false; + $header = $request->headers->get("Authorization"); + $explode1 = explode(" ", $header); + + if (count($explode1) == 2 && $explode1[0] == "Basic") { + + $exploser2 = explode(":", base64_decode($explode1[1])); + + if (count($exploser2) == 2) { + $publickey = $exploser2[0]; + $privateKey = $exploser2[1]; + + $application = $this->doctrine->getRepository("Twake\Market:Application")->findOneBy(Array("simple_name" => $publickey)); + + if ($application != null) { + $key = $application->getPrivateKey(); + + if ($key == $privateKey) { + return $application; + } + } + } + } + return false; + } + + public function get(Request $request) + { + $request = @json_decode($request->getContent(), true); + if (json_last_error() !== JSON_ERROR_NONE) { + $request = Array(); + } + return $request; + } + + + public function isAllowedTo($application, $action, $workspaceId) + { + + $rights = $application->getApplicationRights(); + + //Compare with action asked + $actions = explode(":", $action); + $object = $actions[0]; + $value = intval(str_replace(Array("none", "read", "write", "manage"), Array(0, 1, 2, 3), $actions[1])); + + $this->accessLogService->record($application->getId(), $value); + + if (!isset($rights[$object]) || intval(str_replace(Array("none", "read", "write", "manage"), Array(0, 1, 2, 3), $rights[$object])) < $value) { + return false; + } + + return $this->containsApp($workspaceId, $application); + } + + + public function containsApp($workspaceId, $application) + { + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + if ($workspace == null) { + return false; + } + + $workspaceapp = null; + + $workspaceappsRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupApp"); + $groupApp = $workspaceappsRepository->findOneBy(Array("group" => $workspace->getGroup(), "app" => $application->getId())); + + if ($groupApp) { + //Group apps + $workspaceappsRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceApp"); + $workspaceapp = $workspaceappsRepository->findOneBy(Array("workspace_id" => $workspace, "groupapp" => $groupApp)); + } + + return $workspaceapp != null; + } + +} diff --git a/twake/backend/core/src/DevelopersApiV1/Core/Services/CheckUserInfo.php b/twake/backend/core/src/DevelopersApiV1/Core/Services/CheckUserInfo.php new file mode 100755 index 00000000..ec3d73f6 --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Core/Services/CheckUserInfo.php @@ -0,0 +1,25 @@ +doctrine = $app->getServices()->get("app.twake_doctrine"); + + } + + public function getInfo($token) + { + return $this->doctrine->getRepository("Twake\Market:AccessToken")->findOneBy(Array("atoken" => $token)); + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Drive/Bundle.php b/twake/backend/core/src/DevelopersApiV1/Drive/Bundle.php new file mode 100755 index 00000000..2e61f616 --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Drive/Bundle.php @@ -0,0 +1,26 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Drive/Controller/Drive.php b/twake/backend/core/src/DevelopersApiV1/Drive/Controller/Drive.php new file mode 100755 index 00000000..f3af4154 --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Drive/Controller/Drive.php @@ -0,0 +1,181 @@ +get("app.applications_api")->getAppFromRequest($request, $capabilities); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + + $object = $request->request->get("object", null); + $file_uploaded = $request->request->get("file_url", null); + + if (!$file_uploaded) { + $file_uploaded = $_FILES["file"]; + } + + $user = null; + if (isset($object["sender"])) { + $user = $this->get("app.users")->getById($object["sender"], true)->getId(); + } + + try { + $options = Array("application_id" => $application->getId()); + if ($file_uploaded) { + //If object[_once_new_version] is set a new version is added + $object = $this->get('driveupload.upload')->uploadDirectly($file_uploaded, $object, $options, $user); + } else { + $object = $this->get("app.drive")->save($object, $options, $user, $upload_data); + } + } catch (\Exception $e) { + $object = false; + } + + if (!$object) { + return new Response(Array("error" => "unknown error or malformed query.")); + } + + if ($object) { + + $event = Array( + "client_id" => "system", + "action" => "save", + "object_type" => "", + "object" => $object + ); + $this->get("app.websockets")->push("drive/" . $object["workspace_id"] . "/" . $object["parent_id"], $event); + + } + + $this->get("administration.counter")->incrementCounter("total_api_drive_operation", 1); + + return new Response(Array("object" => $object)); + + + } + + public function remove(Request $request) + { + $capabilities = ["drive_remove"]; + $application = $this->get("app.applications_api")->getAppFromRequest($request, $capabilities); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + + $options = Array("application_id" => $application->getId()); + $object = $request->request->get("object", null); + + $res = $this->get("app.drive")->remove($object, $options, null); + if (!$res) { + return new Response(Array("error" => "unknown error or malformed query.")); + } else { + + $event = Array( + "client_id" => "system", + "action" => "remove", + "object_type" => "", + "front_id" => $res["front_id"] + ); + $this->get("app.websockets")->push("drive/" . $res["workspace_id"] . "/" . $res["parent_id"], $event); + + } + + $this->get("administration.counter")->incrementCounter("total_api_drive_operation", 1); + + return new Response(Array("object" => $res)); + + + } + + public function find(Request $request) + { + $privileges = ["workspace_drive"]; + $application = $this->get("app.applications_api")->getAppFromRequest($request, [], $privileges); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + + $workspace_id = $request->request->get("workspace_id", null); + $element_id = $request->request->get("element_id", null); + + $user = null; + if (isset($object["user_id"])) { + $user = $this->get("app.users")->getById($object["user_id"], true); + if (!$user) { + return null; + } + } + + if ($workspace_id && $element_id) { + $object = $this->get("app.drive")->find( + Array("workspace_id" => $workspace_id, "element_id" => $element_id), $user); + } else { + return new Response(Array("error" => "unknown error or malformed query.")); + } + + $this->get("administration.counter")->incrementCounter("total_api_drive_operation", 1); + + return new Response(Array("object" => $object)); + } + + public function getList(Request $request) + { + $privileges = ["drive_list"]; + $application = $this->get("app.applications_api")->getAppFromRequest($request, [], $privileges); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + + $user_id = null; + $workspace_id = $request->request->get("workspace_id", null); + $directory_id = $request->request->get("directory_id", null); + + if ($workspace_id && $directory_id) { + $objects = $this->get("app.drive")->get( + Array("workspace_id" => $workspace_id, "directory_id" => $directory_id, "trash" => false), null); + } else { + return new Response(Array("error" => "unknown error or malformed query.")); + } + + $res = []; + foreach ($objects as $object) { + $res[] = $object; + } + + $this->get("administration.counter")->incrementCounter("total_api_drive_operation", 1); + + return new Response(Array("data" => $res)); + } + + public function download(Request $request) + { + + $privileges = ["workspace_drive"]; + $application = $this->get("app.applications_api")->getAppFromRequest($request, [], $privileges); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + + $workspace_id = $request->request->get("workspace_id", null); + $fileId = $request->request->get("file_id", null); + + @$response = $this->get('driveupload.download')->download($workspace_id, $fileId, true, null); + + $this->get("administration.counter")->incrementCounter("total_api_drive_operation", 1); + + return $response; + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Drive/Resources/Routing.php b/twake/backend/core/src/DevelopersApiV1/Drive/Resources/Routing.php new file mode 100755 index 00000000..671732fb --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Drive/Resources/Routing.php @@ -0,0 +1,21 @@ + ["handler" => "Drive:remove", "methods" => ["POST"]], + "save" => ["handler" => "Drive:save", "methods" => ["POST"]], + "list" => ["handler" => "Drive:getList", "methods" => ["POST"]], + "find" => ["handler" => "Drive:find", "methods" => ["POST"]], + "download" => ["handler" => "Drive:download", "methods" => ["POST"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/General/Bundle.php b/twake/backend/core/src/DevelopersApiV1/General/Bundle.php new file mode 100755 index 00000000..0c35dd6c --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/General/Bundle.php @@ -0,0 +1,26 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/General/Controller/General.php b/twake/backend/core/src/DevelopersApiV1/General/Controller/General.php new file mode 100755 index 00000000..8c2aaf9d --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/General/Controller/General.php @@ -0,0 +1,88 @@ +get("app.applications_api")->getAppFromRequest($request, $capabilities); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + + $user_id = $request->request->get("user_id", null); + if (!$user_id) { + return new Response(Array("error" => "missing_user_id")); + } + + $connection_id = $request->request->get("connection_id", false); + if (!$connection_id) { + return new Response(Array("error" => "missing_connection_id")); + } + + $event = Array( + "connection_id" => $connection_id, + "action" => "close_configure", + "application" => $application->getAsArray() + ); + $this->get("app.websockets")->push("updates/" . $user_id, $event); + + return new Response(Array("result" => "success")); + + } + + public function configure(Request $request) + { + + $capabilities = ["display_modal"]; + + $application = $this->get("app.applications_api")->getAppFromRequest($request, $capabilities); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + + //TODO Verify targeted user in in app requested group + + $user_id = $request->request->get("user_id", null); + if (!$user_id) { + return new Response(Array("error" => "missing_user_id")); + } + + $connection_id = $request->request->get("connection_id", false); + if (!$connection_id) { + return new Response(Array("error" => "missing_connection_id")); + } + + $form = $request->request->get("form", Array()); + $hidden_data = $request->request->get("hidden_data", Array()); + + $event = Array( + "connection_id" => $connection_id, + "action" => "configure", + "application" => $application->getAsArray(), + "form" => $form, + "hidden_data" => $hidden_data + ); + $this->get("app.websockets")->push("updates/" . $user_id, $event); + + return new Response(Array("result" => "success")); + + } + +} diff --git a/twake/backend/core/src/DevelopersApiV1/General/Resources/Routing.php b/twake/backend/core/src/DevelopersApiV1/General/Resources/Routing.php new file mode 100755 index 00000000..e7b671a7 --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/General/Resources/Routing.php @@ -0,0 +1,17 @@ + ["handler" => "General:configure", "methods" => ["POST"]], + "configure_close" => ["handler" => "General:closeConfigure", "methods" => ["POST"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Messages/Bundle.php b/twake/backend/core/src/DevelopersApiV1/Messages/Bundle.php new file mode 100755 index 00000000..19968d16 --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Messages/Bundle.php @@ -0,0 +1,26 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Messages/Controller/Message.php b/twake/backend/core/src/DevelopersApiV1/Messages/Controller/Message.php new file mode 100755 index 00000000..e60f0b35 --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Messages/Controller/Message.php @@ -0,0 +1,98 @@ +request->get("group_id", null); + $workspace_id = $request->request->get("workspace_id", null); + + $application = $this->get("app.applications_api")->getAppFromRequest($request, $capabilities); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + + $options = Array( + "application_id" => $application->getId() + ); + + $object = $request->request->get("message", null); + $chan_id = $object["channel_id"]; + + $object["company_id"] = $group_id; + $object["worskpace_id"] = $workspace_id; + $result = $this->get("app.messages")->remove($object, $options); + $front_id = $result["front_id"]; + + $this->get("administration.counter")->incrementCounter("total_api_messages_operation", 1); + + return new Response(Array("result" => $object)); + + } + + public function saveMessage(Request $request) + { + + $capabilities = ["messages_save"]; + + $group_id = $request->request->get("group_id", null); + $workspace_id = $request->request->get("workspace_id", null); + + $application = $this->get("app.applications_api")->getAppFromRequest($request, $capabilities); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + + $object = $request->request->get("message", null); + $chan_id = $object["channel_id"]; + + $user = null; + if (isset($object["sender"])) { + $user = $this->get("app.users")->getById($object["sender"], true); + } + + try { + $object["company_id"] = $group_id; + $object["worskpace_id"] = $workspace_id; + $object = $this->get("app.messages")->save($object, Array(), $user, $application); + } catch (\Exception $e) { + $object = false; + } + + if (!$object) { + return new Response(Array("error" => "unknown error or malformed query.")); + } + + if (isset($object["message"])) { + if (isset($object["message"]["formatted"])) { + $object["content"]["last_change"] = date("U"); + } else { + $object["content"]["formatted"] = $object["content"]; + $object["content"]["last_change"] = date("U"); + } + } + + $this->get("administration.counter")->incrementCounter("total_api_messages_operation", 1); + + return new Response(Array("object" => $object)); + + } + +} diff --git a/twake/backend/core/src/DevelopersApiV1/Messages/Resources/Routing.php b/twake/backend/core/src/DevelopersApiV1/Messages/Resources/Routing.php new file mode 100755 index 00000000..5e0f317a --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Messages/Resources/Routing.php @@ -0,0 +1,18 @@ + ["handler" => "Message:removeMessage", "methods" => ["POST"]], + "save" => ["handler" => "Message:saveMessage", "methods" => ["POST"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Tasks/Bundle.php b/twake/backend/core/src/DevelopersApiV1/Tasks/Bundle.php new file mode 100755 index 00000000..d1f13340 --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Tasks/Bundle.php @@ -0,0 +1,26 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Tasks/Controller/Tasks.php b/twake/backend/core/src/DevelopersApiV1/Tasks/Controller/Tasks.php new file mode 100755 index 00000000..7d47d1eb --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Tasks/Controller/Tasks.php @@ -0,0 +1,184 @@ +get("app.applications_api")->getAppFromRequest($request, $capabilities); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + + $object = $request->request->get("object", null); + $user = null; + $object = $this->get("app.tasks.task")->remove($object, Array(), $user); + + $event = Array( + "client_id" => "system", + "action" => "remove", + "object_type" => "", + "front_id" => $object["front_id"] + ); + $this->get("app.websockets")->push("board_tasks/" . $object["board_id"], $event); + + $this->get("administration.counter")->incrementCounter("total_api_tasks_operation", 1); + + return new Response(Array("result" => $object)); + } + + public function saveTask(Request $request) + { + + $capabilities = ["tasks_task_save"]; + + $application = $this->get("app.applications_api")->getAppFromRequest($request, $capabilities); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + + $object = $request->request->get("object", null); + $user = null; + try { + $object = $this->get("app.tasks.task")->save($object, Array(), $user); + } catch (\Exception $e) { + $object = false; + } + if (!$object) { + return new Response(Array("error" => "unknown error or malformed query.")); + } + + if ($object) { + + $event = Array( + "client_id" => "system", + "action" => "save", + "object_type" => "", + "object" => $object + ); + $this->get("app.websockets")->push("board_tasks/" . $object["board_id"], $event); + + } + + $this->get("administration.counter")->incrementCounter("total_api_tasks_operation", 1); + + return new Response(Array("object" => $object)); + + } + + public function getBoardList(Request $request) + { + $privileges = ["workspace_tasks"]; + + $application = $this->get("app.applications_api")->getAppFromRequest($request, [], $privileges); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + $objects = false; + $user_id = $request->request->get("user_id", ""); + $workspace_id = $request->request->get("workspace_id", ""); + if ($workspace_id) { + $user_entity = null; + if ($user_id) { + $user_entity = $this->get("app.users")->getById($user_id, true); + } + if ($user_entity) { + $objects = $this->get("app.tasks.board")->get(Array("workspace_id" => $workspace_id), $user_entity); + } + } + + if ($objects === false) { + return new Response(Array("error" => "payload_error")); + } + + $res = []; + foreach ($objects as $object) { + $res[] = $object; + } + + $this->get("administration.counter")->incrementCounter("total_api_tasks_operation", 1); + + return new Response(Array("data" => $res)); + } + + public function getListsInBoard(Request $request) + { + $privileges = ["workspace_tasks"]; + + $application = $this->get("app.applications_api")->getAppFromRequest($request, [], $privileges); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + $objects = false; + $user_id = $request->request->get("user_id", ""); + $board_id = $request->request->get("board_id", ""); + $workspace_id = $request->request->get("workspace_id", ""); + if ($workspace_id) { + $user_entity = null; + if ($user_id) { + $user_entity = $this->get("app.users")->getById($user_id, true); + } + if ($user_entity) { + $objects = $this->get("app.tasks.list")->get(Array("board_id" => $board_id, "workspace_id" => $workspace_id), $user_entity); + } + } + + if ($objects === false) { + return new Response(Array("error" => "payload_error")); + } + + $res = []; + foreach ($objects as $object) { + $res[] = $object; + } + + $this->get("administration.counter")->incrementCounter("total_api_tasks_operation", 1); + + return new Response(Array("data" => $res)); + } + + public function getTasksInBoard(Request $request) + { + $privileges = ["workspace_tasks"]; + + $application = $this->get("app.applications_api")->getAppFromRequest($request, [], $privileges); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + $objects = false; + $user_id = $request->request->get("user_id", ""); + $board_id = $request->request->get("board_id", ""); + $workspace_id = $request->request->get("workspace_id", ""); + if ($workspace_id) { + $user_entity = null; + if ($user_id) { + $user_entity = $this->get("app.users")->getById($user_id, true); + } + if ($user_entity) { + $objects = $this->get("app.tasks.task")->get(Array("board_id" => $board_id, "workspace_id" => $workspace_id), $user_entity); + } + } + + if ($objects === false) { + return new Response(Array("error" => "payload_error")); + } + + $res = []; + foreach ($objects as $object) { + $res[] = $object; + } + + $this->get("administration.counter")->incrementCounter("total_api_tasks_operation", 1); + + return new Response(Array("data" => $res)); + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Tasks/Resources/Routing.php b/twake/backend/core/src/DevelopersApiV1/Tasks/Resources/Routing.php new file mode 100755 index 00000000..c31e5728 --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Tasks/Resources/Routing.php @@ -0,0 +1,21 @@ + ["handler" => "Tasks:removeTask", "methods" => ["POST"]], + "task/save" => ["handler" => "Tasks:saveTask", "methods" => ["POST"]], + "get_boards" => ["handler" => "Tasks:getBoardList", "methods" => ["POST"]], + "task/get" => ["handler" => "Tasks:getTasksInBoard", "methods" => ["POST"]], + "task/get_lists" => ["handler" => "Tasks:getListsInBoard", "methods" => ["POST"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Users/Bundle.php b/twake/backend/core/src/DevelopersApiV1/Users/Bundle.php new file mode 100755 index 00000000..ac01b1c1 --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Users/Bundle.php @@ -0,0 +1,26 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/DevelopersApiV1/Users/Controller/Users.php b/twake/backend/core/src/DevelopersApiV1/Users/Controller/Users.php new file mode 100755 index 00000000..c4e39caf --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Users/Controller/Users.php @@ -0,0 +1,128 @@ +get("app.applications_api")->getAppFromRequest($request, $capabilities); + if (is_array($application) && $application["error"]) { + return new Response($application); + } + + $user_id = $request->request->get("user_id", false); + + if ($user_id) { + $object_orm = $this->get("app.users")->getById($user_id, true); + $object = $object_orm->getAsArray(); + $object["email"] = $object_orm->getEmail(); + } + + return new Response(Array("object" => $object)); + + } + + public function getNotifications(Request $request) + { + $result = Array("unread" => 0, "notifications" => Array()); + + try{ + $user_id = $request->request->get("user_id"); + $user = null; + if($user_id){ + $user = $this->get("app.users")->getById($user_id, true); + }else{ + $user_email = $request->request->get("user_email"); + $user = $this->get("app.users")->getByEmail($user_email, true); + } + $limit = $request->request->get("limit", 30); + + $notifications = []; + + if($user){ + $workspaces_obj = $this->get("app.workspace_members")->getWorkspaces($user->getId() . ""); + if($workspaces_obj){ + $workspaces = Array(); + foreach ($workspaces_obj as $workspace_obj) { + if($workspace_obj["hasnotifications"]){ + //Add notifications in notification list + $workspace_infos = $workspace_obj["workspace"]->getAsArray(); + + $channels = $this->get("app.channels.channels_system")->get(["workspace_id"=>$workspace_infos["id"]], $user); + + foreach ($channels as $channel) { + $unread = max(0, $channel["messages_increment"] - $channel["_user_last_message_increment"]); + if($unread > 0){ + $notifications[] = [ + "title" => $workspace_infos["name"] . " β€’ " . $channel["name"], + "content" => $unread . " unread message(s)", + "date" => $channel["_user_last_access"] ?: $channel["last_activity"], + "url" => "/notification/-".$workspace_infos["id"]."-".$channel["id"] + ]; + } + } + } + } + }else{ + $notifications = []; + } + + $channels = $this->get("app.channels.direct_messages_system")->get([], $user); + foreach ($channels as $channel) { + $unread = max(0, $channel["messages_increment"] - $channel["_user_last_message_increment"]); + if($unread > 0){ + + $name = []; + foreach($channel["members"] as $member){ + if($member != $user->getId()){ + $member_user = $this->get("app.users")->getById($member, true); + if($member_user){ + $name[] = $member_user->getFullName(); + } + } + } + $name = join(", ", $name); + + $notifications[] = [ + "title" => $name, + "content" => $unread . " unread message(s)", + "date" => $channel["_user_last_access"] ?: $channel["last_activity"], + "url" => "/notification/-".$channel["id"] //For private channels + ]; + } + } + + } + + usort($notifications, function ($a, $b) { + return $b['date'] - $a['date']; + }); + + $result["unread"] = count($notifications); + $result["notifications"] = array_slice($notifications, 0, $limit); + + }catch(\Exception $err){ + $result["unread"] = 0; + $result["notifications"] = []; + $result["error"] = $err->getMessage(); + } + return new Response($result); + } + +} diff --git a/twake/backend/core/src/DevelopersApiV1/Users/Resources/Routing.php b/twake/backend/core/src/DevelopersApiV1/Users/Resources/Routing.php new file mode 100755 index 00000000..f28d800b --- /dev/null +++ b/twake/backend/core/src/DevelopersApiV1/Users/Resources/Routing.php @@ -0,0 +1,18 @@ + ["handler" => "Users:getAction", "methods" => ["POST"]], + "notifications" => ["handler" => "Users:getNotifications", "methods" => ["POST"]], + ]; + +} diff --git a/twake/backend/core/src/Twake/Calendar/Bundle.php b/twake/backend/core/src/Twake/Calendar/Bundle.php new file mode 100755 index 00000000..d30dd1a4 --- /dev/null +++ b/twake/backend/core/src/Twake/Calendar/Bundle.php @@ -0,0 +1,30 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Calendar/Command/ReminderCheckerCommand.php b/twake/backend/core/src/Twake/Calendar/Command/ReminderCheckerCommand.php new file mode 100755 index 00000000..c0075ef4 --- /dev/null +++ b/twake/backend/core/src/Twake/Calendar/Command/ReminderCheckerCommand.php @@ -0,0 +1,32 @@ +setName("twake:calendar_check_reminders"); + } + + + protected function execute() + { + $services = $this->getApp()->getServices(); + + $limit = date("U", date("U") + 60); + + while (date("U") < $limit) { + $sent = $services->get("app.calendar.event")->checkReminders(); + if ($sent == 0) { + sleep(30); + } + } + } + + +} diff --git a/twake/backend/core/src/Twake/Calendar/Controller/Calendar.php b/twake/backend/core/src/Twake/Calendar/Controller/Calendar.php new file mode 100755 index 00000000..0e1f969b --- /dev/null +++ b/twake/backend/core/src/Twake/Calendar/Controller/Calendar.php @@ -0,0 +1,56 @@ +request->get("options"); + $object = $request->request->get("object"); + $res = $this->get("app.calendar.calendar")->remove($object, $options, $this->getUser()); + if (!$res) { + return new Response(Array("status" => "error")); + } + return new Response(Array("data" => Array("object" => $res))); + } + + public function save(Request $request) + { + $options = $request->request->get("options"); + $object = $request->request->get("object"); + $res = $this->get("app.calendar.calendar")->save($object, $options, $this->getUser()); + if (!$res) { + return new Response(Array("status" => "error")); + }else{ + if($GLOBALS["segment_enabled"]) \Segment::track([ + "event" => "calendar:".($object["id"] ? "edit" : "create"), + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() + ]); + } + return new Response(Array("data" => Array("object" => $res))); + } + + public function getAction(Request $request) + { + $options = $request->request->get("options"); + $objects = $this->get("app.calendar.calendar")->get($options, $this->getUser()); + if ($objects === false) { + return new Response(Array("status" => "error")); + }else{ + if($GLOBALS["segment_enabled"]) \Segment::track([ + "event" => "calendar:open", + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() + ]); + } + + return new Response(Array("data" => $objects)); + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Calendar/Controller/Event.php b/twake/backend/core/src/Twake/Calendar/Controller/Event.php new file mode 100755 index 00000000..ab207fcc --- /dev/null +++ b/twake/backend/core/src/Twake/Calendar/Controller/Event.php @@ -0,0 +1,57 @@ +request->get("options"); + $object = $request->request->get("object"); + $res = $this->get("app.calendar.event")->remove($object, $options, $this->getUser()); + if (!$res) { + return new Response(Array("status" => "error")); + } + if($GLOBALS["segment_enabled"]) \Segment::track([ + "event" => "calendar:event:remove", + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() + ]); + return new Response(Array("data" => Array("object" => $res))); + } + + public function save(Request $request) + { + $options = $request->request->get("options"); + $object = $request->request->get("object"); + $res = $this->get("app.calendar.event")->save($object, $options, $this->getUser()); + if (!$res) { + return new Response(Array("status" => "error")); + } else { + if (!$object["id"]) { + $this->get("administration.counter")->incrementCounter("total_events", 1); + } + if($GLOBALS["segment_enabled"]) \Segment::track([ + "event" => "calendar:event:".($object["id"] ? "edit" : "create"), + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() + ]); + } + return new Response(Array("data" => Array("object" => $res))); + } + + public function getAction(Request $request) + { + $options = $request->request->get("options"); + $objects = $this->get("app.calendar.event")->get($options, $this->getUser()); + if ($objects === false) { + return new Response(Array("status" => "error")); + } + return new Response(Array("data" => $objects)); + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Calendar/Controller/Export.php b/twake/backend/core/src/Twake/Calendar/Controller/Export.php new file mode 100755 index 00000000..53fa79fd --- /dev/null +++ b/twake/backend/core/src/Twake/Calendar/Controller/Export.php @@ -0,0 +1,27 @@ +query->get("token"); + if ($token) { + return $this->get("app.calendar.export")->exportCalendar($token, $this->get("app.calendar.event")); + } else + return new Response("Errors : Token not found"); + } + + + public function generateToken(Request $request) + { + $user = $this->getUser(); + return new Response(Array("token" => $this->get("app.calendar.export")->generateToken($request, $user))); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Calendar/Entity/Calendar.php b/twake/backend/core/src/Twake/Calendar/Entity/Calendar.php new file mode 100755 index 00000000..2cce7639 --- /dev/null +++ b/twake/backend/core/src/Twake/Calendar/Entity/Calendar.php @@ -0,0 +1,170 @@ +setWorkspaceId($workspace_id); + $this->setTitle($title); + $this->setColor($color); + $this->setAutoParticipants(Array()); + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getWorkspaceId() + { + return $this->workspace_id; + } + + /** + * @param mixed $workspace_id + */ + public function setWorkspaceId($workspace_id) + { + $this->workspace_id = $workspace_id; + } + + /** + * @return mixed + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param mixed $title + */ + public function setTitle($title) + { + $this->title = $title; + } + + /** + * @return mixed + */ + public function getColor() + { + return $this->color; + } + + /** + * @param mixed $color + */ + public function setColor($color) + { + $this->color = $color; + } + + /** + * @return mixed + */ + public function getAutoParticipants() + { + return json_decode($this->auto_participants, 1); + } + + /** + * @param mixed $auto_participants + */ + public function setAutoParticipants($auto_participants) + { + $this->auto_participants = json_encode($auto_participants); + } + + /** + * @return mixed + */ + public function getConnectors() + { + return json_decode($this->connectors, 1); + } + + /** + * @param mixed $tabs + */ + public function setConnectors($connectors) + { + $this->connectors = json_encode($connectors); + } + + public function getAsArray() + { + return Array( + "id" => $this->getId(), + "front_id" => $this->getFrontId(), + "title" => $this->getTitle(), + "color" => $this->getColor(), + "connectors" => $this->getConnectors(), + "workspace_id" => $this->getWorkspaceId(), + "auto_participants" => $this->getAutoParticipants() + ); + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Calendar/Entity/Event.php b/twake/backend/core/src/Twake/Calendar/Entity/Event.php new file mode 100755 index 00000000..ca9cf5db --- /dev/null +++ b/twake/backend/core/src/Twake/Calendar/Entity/Event.php @@ -0,0 +1,509 @@ +setTitle($title); + $this->setFrom($from); + $this->setTo($to); + $this->setEventLastModified(); + } + + public function getIndexationArray() + { + $participants = []; + foreach ($this->getParticipants() as $p) { + $participants[] = $p["user_id_or_mail"]; + } + + return Array( + "id" => $this->getId() . "", + "title" => $this->getTitle(), + "description" => $this->getDescription(), + "owner" => $this->getOwner(), + "tags" => $this->getTags(), + 'date_from' => ($this->getFrom() ? date('Y-m-d', $this->getFrom()) : null), + 'date_to' => ($this->getTo() ? date('Y-m-d', $this->getTo()) : null), + "date_last_modified" => ($this->getEventLastModified() ? date('Y-m-d', $this->getEventLastModified()) : null), + "workspace_id" => $this->getWorkspaceId(), + "participants" => $participants, + "attachments" => $this->getAttachements() + ); + + } + + /** + * @return mixed + */ + public function getWorkspaceId() + { + $workspace_id = $this->workspace_id; + if (!$workspace_id) { + $list = $this->getWorkspacesCalendars(); + if (count($list) > 0) { + $workspace_id = $list[0]["workspace_id"]; + } + } + return $workspace_id; + } + + /** + * @param mixed $workspace_id + */ + public function setWorkspaceId($workspace_id) + { + $this->workspace_id = $workspace_id; + } + + + /** + * @return string + */ + public function getEsType() + { + return $this->es_type; + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getFrom() + { + return $this->from; + } + + /** + * @param mixed $from + */ + public function setFrom($from) + { + $this->from = $from; + } + + /** + * @return mixed + */ + public function getTo() + { + return $this->to; + } + + /** + * @param mixed $to + */ + public function setTo($to) + { + $this->to = $to; + } + + /** + * @return mixed + */ + public function getAllDay() + { + return $this->all_day; + } + + /** + * @param mixed $all_day + */ + public function setAllDay($all_day) + { + $this->all_day = $all_day; + } + + /** + * @return mixed + */ + public function getType() + { + return $this->type; + } + + /** + * @param mixed $type + */ + public function setType($type) + { + $this->type = $type; + } + + /** + * @return mixed + */ + public function getRepetitionDefinition() + { + return json_decode($this->repetition_definition, true); + } + + /** + * @param mixed $repetition_definition + */ + public function setRepetitionDefinition($repetition_definition) + { + $this->repetition_definition = json_encode($repetition_definition); + } + + /** + * @return mixed + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param mixed $title + */ + public function setTitle($title) + { + $this->title = $title; + } + + /** + * @return mixed + */ + public function getDescription() + { + return $this->description; + } + + /** + * @param mixed $description + */ + public function setDescription($description) + { + $this->description = $description; + } + + /** + * @return mixed + */ + public function getLocation() + { + return $this->location; + } + + /** + * @param mixed $location + */ + public function setLocation($location) + { + $this->location = $location; + } + + /** + * @return mixed + */ + public function getPrivate() + { + return $this->private; + } + + /** + * @param mixed $private + */ + public function setPrivate($private) + { + $this->private = $private; + } + + /** + * @return mixed + */ + public function getAvailable() + { + return $this->available; + } + + /** + * @param mixed $available + */ + public function setAvailable($available) + { + $this->available = $available; + } + + /** + * @return mixed + */ + public function getOwner() + { + return $this->owner; + } + + /** + * @param mixed $owner + */ + public function setOwner($owner) + { + $this->owner = $owner; + } + + /** + * @return mixed + */ + public function getParticipants() + { + return json_decode($this->participants, true); + } + + /** + * @param mixed $participants + */ + public function setParticipants($participants) + { + $this->participants = json_encode($participants); + } + + /** + * @return mixed + */ + public function getWorkspacesCalendars() + { + return json_decode($this->workspaces_calendars, true); + } + + /** + * @param mixed $workspaces_calendars + */ + public function setWorkspacesCalendars($workspaces_calendars) + { + $this->workspaces_calendars = json_encode($workspaces_calendars); + } + + /** + * @return mixed + */ + public function getNotifications() + { + return json_decode($this->notifications, true); + } + + /** + * @param mixed $notifications + */ + public function setNotifications($notifications) + { + $this->notifications = json_encode($notifications); + } + + /** + * @return mixed + */ + public function getTags() + { + return json_decode($this->tags, true); + } + + /** + * @param mixed $tags + */ + public function setTags($tags) + { + $this->tags = json_encode($tags); + } + + /** + * @return mixed + */ + public function getAttachements() + { + return json_decode($this->attachements, true); + } + + /** + * @param mixed $tags + */ + public function setAttachements($attachements) + { + $this->attachements = json_encode($attachements); + } + + public function getSortKey() + { + $after_sort_date = floor($this->getFrom() / (60 * 60 * 24 * 7)); + $before_sort_date = floor($this->getTo() / (60 * 60 * 24 * 7)); + $sort_key = [$after_sort_date]; + if ($after_sort_date != $before_sort_date) { + $sort_key = [$after_sort_date, $before_sort_date]; + } + return $sort_key; + } + + /** + * @return mixed + */ + public function getEventLastModified() + { + return $this->event_last_modified; + } + + /** + * @param mixed $event_last_modified + */ + public function setEventLastModified() + { + $this->event_last_modified = date("U"); + } + + + public function getAsArray() + { + return Array( + "id" => $this->getId(), + "front_id" => $this->getFrontId(), + "from" => $this->getFrom(), + "to" => $this->getTo(), + "all_day" => $this->getAllDay(), + "repetition_definition" => $this->getRepetitionDefinition(), + "type" => $this->getType(), + "title" => $this->getTitle(), + "description" => $this->getDescription(), + "location" => $this->getLocation(), + "private" => $this->getPrivate(), + "available" => $this->getAvailable(), + "owner" => $this->getOwner(), + "participants" => $this->getParticipants(), + "workspaces_calendars" => $this->getWorkspacesCalendars(), + "notifications" => $this->getNotifications(), + "tags" => $this->getTags(), + "event_last_modified" => $this->getEventLastModified(), + "attachments" => $this->getAttachements() + ); + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Calendar/Entity/EventCalendar.php b/twake/backend/core/src/Twake/Calendar/Entity/EventCalendar.php new file mode 100755 index 00000000..6fe19f24 --- /dev/null +++ b/twake/backend/core/src/Twake/Calendar/Entity/EventCalendar.php @@ -0,0 +1,105 @@ +workspace_id = $workspace_id; + $this->calendar_id = $calendar_id; + $this->event_id = $event_id; + $this->sort_date = $sort_date; + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getWorkspaceId() + { + return $this->workspace_id; + } + + /** + * @return mixed + */ + public function getCalendarId() + { + return $this->calendar_id; + } + + /** + * @return mixed + */ + public function getSortDate() + { + return $this->sort_date; + } + + /** + * @return mixed + */ + public function getEventId() + { + return $this->event_id; + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Calendar/Entity/EventUser.php b/twake/backend/core/src/Twake/Calendar/Entity/EventUser.php new file mode 100755 index 00000000..af8b235d --- /dev/null +++ b/twake/backend/core/src/Twake/Calendar/Entity/EventUser.php @@ -0,0 +1,133 @@ +user_id_or_mail = $user_id_or_mail; + $this->event_id = $event_id; + $this->sort_date = $sort_date; + $this->accept_status = $accept_status; + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getUserIdOrMail() + { + return $this->user_id_or_mail; + } + + /** + * @return mixed + */ + public function getSortDate() + { + return $this->sort_date; + } + + /** + * @return mixed + */ + public function getEventId() + { + return $this->event_id; + } + + /** + * @return mixed + */ + public function getAcceptStatus() + { + return $this->accept_status; + } + + /** + * @param mixed $accept_status + */ + public function setAcceptStatus($accept_status) + { + $this->accept_status = $accept_status; + } + + /** + * @return mixed + */ + public function getEmail() + { + return $this->email; + } + + /** + * @param mixed $email + */ + public function setEmail($email) + { + $this->email = $email; + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Calendar/Entity/ExportToken.php b/twake/backend/core/src/Twake/Calendar/Entity/ExportToken.php new file mode 100755 index 00000000..3f66bf57 --- /dev/null +++ b/twake/backend/core/src/Twake/Calendar/Entity/ExportToken.php @@ -0,0 +1,140 @@ +user_id = $user_id; + $this->workspaceid = $workspaceid; + $this->setCalendars($calendars); + $this->user_token = $user_token; + } + + /** + * @return mixed + */ + public function getUserId() + { + return $this->user_id; + } + + /** + * @param mixed $user_id + */ + public function setUserId($user_id) + { + $this->user_id = $user_id; + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getWorkspaceid() + { + return $this->workspaceid; + } + + /** + * @param mixed $workspaceid + */ + public function setWorkspaceid($workspaceid) + { + $this->workspaceid = $workspaceid; + } + + /** + * @return mixed + */ + public function getCalendars() + { + return json_decode($this->calendars, true); + } + + /** + * @param mixed $calendars + */ + public function setCalendars($calendars) + { + $this->calendars = json_encode($calendars); + } + + /** + * @return mixed + */ + public function getToken() + { + return $this->user_token; + } + + /** + * @param mixed $user_token + */ + public function setToken($token) + { + $this->user_token = $token; + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Calendar/Resources/Routing.php b/twake/backend/core/src/Twake/Calendar/Resources/Routing.php new file mode 100755 index 00000000..cbf025fa --- /dev/null +++ b/twake/backend/core/src/Twake/Calendar/Resources/Routing.php @@ -0,0 +1,26 @@ + ["handler" => "Event:getAction", "methods" => ["POST"], "security" => ["user_connected_security"]], + "event/save" => ["handler" => "Event:save", "methods" => ["POST"], "security" => ["user_connected_security"]], + "event/remove" => ["handler" => "Event:remove", "methods" => ["POST"], "security" => ["user_connected_security"]], +#Calendars + "calendar/get" => ["handler" => "Calendar:getAction", "methods" => ["POST"], "security" => ["user_connected_security"]], + "calendar/save" => ["handler" => "Calendar:save", "methods" => ["POST"], "security" => ["user_connected_security"]], + "calendar/remove" => ["handler" => "Calendar:remove", "methods" => ["POST"], "security" => ["user_connected_security"]], +#Export + "export" => ["handler" => "Export:export", "methods" => ["POST", "GET"]], + "token_export" => ["handler" => "Export:generateToken", "methods" => ["POST"], "security" => ["user_connected_security"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Calendar/Resources/Services.php b/twake/backend/core/src/Twake/Calendar/Resources/Services.php new file mode 100755 index 00000000..e4d5dc32 --- /dev/null +++ b/twake/backend/core/src/Twake/Calendar/Resources/Services.php @@ -0,0 +1,18 @@ + "CalendarEvent", +// arguments: ["@app.twake_doctrine", "@app.websockets", "@app.applications_api", "@app.notifications", "@app.calendar.export"] + "app.calendar.calendar" => "CalendarCalendar", +// arguments: ["@app.twake_doctrine", "@app.applications_api"] + "app.calendar.export" => "CalendarExport", +// arguments: ["@app.twake_doctrine"] + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Calendar/Services/CalendarCalendar.php b/twake/backend/core/src/Twake/Calendar/Services/CalendarCalendar.php new file mode 100755 index 00000000..2772790a --- /dev/null +++ b/twake/backend/core/src/Twake/Calendar/Services/CalendarCalendar.php @@ -0,0 +1,167 @@ +doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->applications_api = $app->getServices()->get("app.applications_api"); + } + + /** Called from Collections manager to verify user has access to websockets room, registered in Core/Services/Websockets.php */ + public function init($route, $data, $current_user = null) + { + return $this->hasAccess($data, $current_user); + } + + public function hasAccess($data, $current_user = null) + { + //TODO + return true; + } + + public function get($options, $current_user) + { + $workspace_id = $options["workspace_id"]; + $calendars = $this->doctrine->getRepository("Twake\Calendar:Calendar")->findBy(Array("workspace_id" => $workspace_id)); + + if (!$this->hasAccess($options, $current_user)) { + return false; + } + + if (count($calendars) == 0) { + $cal = $this->save(Array( + "workspace_id" => $workspace_id, + "title" => "General", + "color" => "#33b679", + "auto_participants" => Array() + ), Array(), null); + if ($cal) { + return [$cal]; + } + } + + $ret = []; + foreach ($calendars as $calendar) { + $ret[] = $calendar->getAsArray(); + } + + return $ret; + } + + public function save($object, $options, $current_user) + { + + if (!$this->hasAccess($object, $current_user)) { + return false; + } + + $did_create = false; + if (isset($object["id"])) { + $calendar = $this->doctrine->getRepository("Twake\Calendar:Calendar")->findOneBy(Array("id" => $object["id"])); + if (!$calendar) { + return false; + } + } else { + $did_create = true; + $calendar = new Calendar($object["workspace_id"], "", ""); + $calendar->setFrontId($object["front_id"]); + } + + $calendar->setTitle($object["title"]); + $calendar->setColor($object["color"]); + $calendar->setAutoParticipants($object["auto_participants"]); + $this->doctrine->persist($calendar); + $this->doctrine->flush(); + + $this->updateConnectors($calendar, $object["connectors"], $current_user ? $current_user->getId() : null); + + //Notify connectors + $workspace_id = $calendar->getWorkspaceId(); + $resources = $this->applications_api->getResources($workspace_id, "workspace_calendar", $workspace_id); + $apps_ids = []; + foreach ($resources as $resource) { + if (in_array("calendar", $resource->getApplicationHooks())) { + $apps_ids[] = $resource->getApplicationId(); + } + } + if (count($apps_ids) > 0) { + foreach ($apps_ids as $app_id) { + if ($app_id) { + $data = Array( + "calendar" => $calendar->getAsArray() + ); + if ($did_create) { + $this->applications_api->notifyApp($app_id, "hook", "new_calendar", $data); + } else { + $this->applications_api->notifyApp($app_id, "hook", "edit_calendar", $data); + } + } + } + } + + return $calendar->getAsArray(); + + } + + private function updateConnectors($calendar_entity, $connectors_ids, $current_user_id = null) + { + + if (!$connectors_ids) { + $connectors_ids = []; + } + + $current_connectors = $calendar_entity->getConnectors(); + $current_connectors = $current_connectors ? $current_connectors : []; + + $did_something = false; + + foreach ($connectors_ids as $connector_id) { + if (!in_array($connector_id, $current_connectors)) { + $this->applications_api->addResource($connector_id, $calendar_entity->getWorkspaceId(), "calendar", $calendar_entity->getId(), $current_user_id); + $did_something = true; + } + } + + foreach ($current_connectors as $current_connector_id) { + if (!in_array($current_connector_id, $connectors_ids)) { + $this->applications_api->removeResource($connector_id, $calendar_entity->getWorkspaceId(), "calendar", $calendar_entity->getId(), $current_user_id); + $did_something = true; + } + } + + if ($did_something) { + $calendar_entity->setConnectors($connectors_ids); + $this->doctrine->persist($calendar_entity); + $this->doctrine->flush(); + } + + } + + public function remove($object, $options, $current_user = null) + { + $id = $object["id"]; + + if (!$this->hasAccess($object, $current_user)) { + return false; + } + + $calendar = $this->doctrine->getRepository("Twake\Calendar:Calendar")->findOneBy(Array("id" => $id)); + if (!$calendar) { + return false; + } + + $this->doctrine->remove($calendar); + $this->doctrine->flush(); + + $this->doctrine->getRepository("Twake\Calendar:EventCalendar")->removeBy(Array("workspace_id" => $calendar->getWorkspaceId(), "calendar_id" => $id)); + + return $object; + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Calendar/Services/CalendarEvent.php b/twake/backend/core/src/Twake/Calendar/Services/CalendarEvent.php new file mode 100755 index 00000000..f784d59c --- /dev/null +++ b/twake/backend/core/src/Twake/Calendar/Services/CalendarEvent.php @@ -0,0 +1,762 @@ +doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->calendarExport = $app->getServices()->get("app.calendar.export"); + $this->enc_pusher = $app->getServices()->get("app.websockets"); + $this->applications_api = $app->getServices()->get("app.applications_api"); + $this->notifications = $app->getServices()->get("app.notifications"); + $this->queues_scheduled = $app->getServices()->get("app.queues_scheduled"); + $this->attachementManager = new AttachementManager($this->doctrine, $this->enc_pusher); + } + + /** Called from Collections manager to verify user has access to websockets room, registered in Core/Services/Websockets.php */ + public function init($route, $data, $current_user = null) + { + return $this->hasAccess($data, $current_user); + } + + public function hasAccess($data, $current_user = null) + { + //TODO + + if ($data["entity"]) { + //Test we have access to this event + } + + return true; + } + + public function get($options, $current_user) + { + + $after_ts = floor(($options["after_ts"] ? $options["after_ts"] : 0) / (60 * 60 * 24 * 7)); + $before_ts = floor(($options["before_ts"] ? $options["before_ts"] : 0) / (60 * 60 * 24 * 7)); + $mode = $options["mode"]; //User or workspace + + if (!$this->hasAccess($options, $current_user)) { + return false; + } + + $events_ids = []; + if ($mode == "workspace" || $mode == "both") { + + + $events_links = []; + foreach (($options["calendar_list"] ? $options["calendar_list"] : []) as $object) { + $workspace_id = $object["workspace_id"]; + $calendar_id = $object["calendar_id"]; + if ($calendar_id && $workspace_id) { + $events_links = array_merge($events_links, $this->doctrine->getRepository("Twake\Calendar:EventCalendar")->findRange(Array("workspace_id" => $workspace_id, "calendar_id" => $calendar_id), false, "sort_date", $after_ts, $before_ts)); + } + } + + foreach ($events_links as $event_link) { + $events_ids[] = $event_link->getEventId(); + } + + } + if ($mode == "mine" || $mode == "both") { + + if (!isset($options["users_ids_or_mails"]) && $current_user) { + $options["users_ids_or_mails"] = [$current_user->getId()]; + } + + $events_links = []; + foreach (($options["users_ids_or_mails"] ? $options["users_ids_or_mails"] : []) as $user_id_or_mail) { + $events_links = array_merge($events_links, $this->doctrine->getRepository("Twake\Calendar:EventUser")->findRange(Array("user_id_or_mail" => $user_id_or_mail), false, "sort_date", $after_ts, $before_ts)); + } + + foreach ($events_links as $event_link) { + $events_ids[] = $event_link->getEventId(); + } + + } + + $events_ids = array_unique($events_ids); + + $ret = []; + foreach ($events_ids as $id) { + $event = $this->doctrine->getRepository("Twake\Calendar:Event")->find($id); + if ($event) { + $ret[] = $event->getAsArray(); + } else { + //Remove innexistant event + $this->removeEventDependancesById($id); + } + } + + return $ret; + } + + private function removeEventDependancesById($id) + { + $event = $this->doctrine->getRepository("Twake\Calendar:Event")->findOneBy(Array("id" => $id)); + if ($event) { + $this->attachementManager->removeAttachementsFromEntity($event); + } + + $entities = $this->doctrine->getRepository("Twake\Calendar:EventCalendar")->findBy(Array("event_id" => $id)); + $entities = array_merge($entities, $this->doctrine->getRepository("Twake\Calendar:EventUser")->findBy(Array("event_id" => $id))); + foreach ($entities as $entity) { + $this->doctrine->remove($entity); + + } + $this->doctrine->flush(); + } + + public function remove($object, $options, $current_user = null) + { + $id = $object["id"]; + + if (!$this->hasAccess($object, $current_user)) { + return false; + } + + $event = $this->doctrine->getRepository("Twake\Calendar:Event")->find($id); + if (!$event) { + return false; + } + + $participants = $event->getParticipants(); + + //Quit event + if ($event->getOwner() && $event->getOwner() != $current_user->getId()) { + $list = []; + foreach ($event->getParticipants() as $part) { + if ($part["user_id_or_mail"] != $current_user->getId()) { + $list[] = $part; + } + } + $this->updateParticipants($event, $list, false); + + $evt = Array( + "client_id" => "system", + "action" => "save", + "object_type" => "", + "object" => $event->getAsArray() + ); + + } //Or delete event + else { + $this->doctrine->remove($event); + $this->doctrine->flush(); + + $this->removeEventDependancesById($id); + + //Notify connectors + $resources = []; + $done = []; + foreach ($event->getWorkspacesCalendars() as $calendar) { + $workspace_id = $calendar["workspace_id"]; + if (!in_array($workspace_id, $done)) { + $done[] = $workspace_id; + $resources = array_merge($resources, $this->applications_api->getResources($workspace_id, "workspace_calendar", $workspace_id)); + } + } + $apps_ids = []; + foreach ($resources as $resource) { + if (in_array("event", $resource->getApplicationHooks())) { + $apps_ids[] = $resource->getApplicationId(); + } + } + if (count($apps_ids) > 0) { + foreach ($apps_ids as $app_id) { + if ($app_id) { + $data = Array( + "event" => $event->getAsArray() + ); + $this->applications_api->notifyApp($app_id, "hook", "remove_event", $data); + } + } + } + + $evt = Array( + "client_id" => "system", + "action" => "remove", + "object_type" => "", + "front_id" => $event->getFrontId() + ); + } + + //Notify modification for participant users + foreach ($participants as $participant) { + if (preg_match('/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/', $participant["user_id_or_mail"])) { + $this->enc_pusher->push("calendar_events/user/" . $participant["user_id_or_mail"], $evt); + } + } + + return $event->getAsArray(); + } + + public function updateParticipants(Event $event, $participants = Array(), $replace_all = false) + { + $sort_key = $event->getSortKey(); + + $participants = $participants ? $participants : []; + + $updated_participants = $this->formatArrayInput($participants, ["user_id_or_mail"]); + $current_participants = $event->getParticipants(); + $updated_participants_fixed = $current_participants; + + $get_diff = $this->getArrayDiffUsingKeys($updated_participants, $current_participants, ["user_id_or_mail"]); + error_log("get diff" . json_encode($get_diff)); + if (count($get_diff["del"]) > 0 || $replace_all) { + $users_in_event = $this->doctrine->getRepository("Twake\Calendar:EventUser")->findBy(Array("event_id" => $event->getId())); + foreach ($users_in_event as $user) { + if ($this->inArrayUsingKeys($get_diff["del"], Array("user_id_or_mail" => $user->getUserIdOrMail()), ["user_id_or_mail"]) || $replace_all) { + //Remove old participants + $this->doctrine->remove($user); + + //Remove from array fixed + foreach ($updated_participants_fixed as $i => $v) { + if ($v["user_id_or_mail"] == $user->getUserIdOrMail()) { + unset($updated_participants_fixed[$i]); + } + } + + } + } + } + + foreach (($replace_all ? $updated_participants : $get_diff["add"]) as $participant) { + foreach ($sort_key as $sort_date) { + + $fixed_participant = $participant; + + //Remove from array fixed + if (filter_var($participant["user_id_or_mail"], FILTER_VALIDATE_EMAIL)) { + //Mail given + $mail = trim(strtolower($participant["user_id_or_mail"])); + $mail_entity = $this->doctrine->getRepository("Twake\Users:Mail")->findOneBy(Array("mail" => $mail)); + if ($mail_entity) { + $fixed_participant["user_id_or_mail"] = $mail_entity->getUser()->getId(); + } + } else if (preg_match('/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/', $participant["user_id_or_mail"])) { + //User id given + $user = $this->doctrine->getRepository("Twake\Users:User")->findOneBy(Array("id" => $participant["user_id_or_mail"])); + if (!$user) { + continue; + } + $mail = $user->getEmail(); + } else { + continue; + } + + $fixed_participant["email"] = $mail; + $participant = $fixed_participant; + + $user = new EventUser($participant["user_id_or_mail"], $event->getId(), $sort_date); + $user->setEmail($mail); + $this->doctrine->persist($user); + + $updated_participants_fixed[] = $participant; + + } + } + + $_updated_participants_fixed = []; + foreach ($updated_participants_fixed as $v) { + $_updated_participants_fixed[] = $v; + } + $updated_participants_fixed = $_updated_participants_fixed; + $event->setParticipants($updated_participants_fixed); + $this->doctrine->persist($event); + + $this->doctrine->flush(); + } + + //TODO Not the best to send update email every time, change it to a worker waiting 30 minutes at least + + public function formatArrayInput($array, $id_keys = []) + { + $updated_array = []; + $unicity = []; + foreach ($array as $element) { + + $tmp = false; + + if (is_array($element)) { + $all_ok = true; + foreach ($id_keys as $id_key) { + if (!isset($element[$id_key])) { + $all_ok = false; + } + } + if ($all_ok) { + $tmp = $element; + } + } else { + $tmp = Array(); + $tmp[$id_key] = $element; + } + + if ($tmp !== false) { + $uniq_key = ""; + foreach ($id_keys as $id_key) { + $uniq_key .= "_" . $tmp[$id_key]; + } + if (!in_array($uniq_key, $unicity)) { + $unicity[] = $uniq_key; + $updated_array[] = $tmp; + } + } + + } + return $updated_array; + } + + public function getArrayDiffUsingKeys($new_array, $old_array, $keys) + { + $remove = []; + $add = []; + foreach ($new_array as $new_el) { + if (!$this->inArrayUsingKeys($old_array, $new_el, $keys)) { + $add[] = $new_el; + } + } + foreach ($old_array as $old_el) { + if (!$this->inArrayUsingKeys($new_array, $old_el, $keys)) { + $remove[] = $old_el; + } + } + return Array("del" => $remove, "add" => $add); + } + + public function inArrayUsingKeys($array, $element, $keys) + { + $in = false; + foreach ($array as $el) { + $same = true; + foreach ($keys as $key) { + if ($el[$key] != $element[$key]) { + $same = false; + break; + } + } + if ($same) { + $in = true; + break; + } + } + return $in; + } + + public function save($object, $options, $current_user) + { + + if (!$this->hasAccess($object, $current_user)) { + return false; + } + + if (isset($object["id"]) && $object["id"]) { + $event = $this->doctrine->getRepository("Twake\Calendar:Event")->find($object["id"]); + if (!$event) { + return false; + } + $did_create = false; + } else { + $event = new Event($object["title"], intval($object["from"]), intval($object["to"])); + $event->setFrontId($object["front_id"]); + if (isset($object["workspaces_calendars"]) && is_array($object["workspaces_calendars"])) { + $event->setWorkspaceId($object["workspaces_calendars"][0]["workspace_id"]); + } + $did_create = true; + } + + //Manage infos + $old_event = $event->getAsArray(); + $event->setTitle($object["title"]); + $event->setDescription($object["description"]); + $event->setLocation($object["location"]); + $event->setPrivate($object["private"]); + $event->setAvailable($object["available"]); + + //Manage dates + $object["type"] = in_array($object["type"], ["event", "remind", "move", "deadline"]) ? $object["type"] : "event"; + if (!isset($object["from"]) || !$object["from"]) { + if (isset($object["to"])) { + $object["from"] = $object["to"] - 60 * 60; + } else { + $object["from"] = intval(date("U") / (15 * 60)) * 15 * 60; + } + } + if (!isset($object["to"]) || !$object["to"]) { + $object["to"] = $object["from"] + 60 * 60; + } + $tmp_sort_key = json_encode($event->getSortKey()); + $from_changed = ($object["from"] != $event->getFrom()); + $event->setFrom(intval($object["from"])); + $event->setTo(intval($object["to"])); + $event->setAllDay($object["all_day"]); + $event->setType($object["type"]); + $event->setRepetitionDefinition($object["repetition_definition"]); + $sort_key = json_encode($event->getSortKey()); + if ($sort_key != $tmp_sort_key) { + $sort_key_has_changed = true; + } + + $event->setEventLastModified(); + + if (isset($object["tags"])) { + $event->setTags($object["tags"]); + } + + + $this->doctrine->persist($event); + $this->doctrine->flush(); + + if (isset($object["attachments"]) || $did_create) { + $this->attachementManager->updateAttachements($event, $object["attachments"] ? $object["attachments"] : Array()); + } + + $old_participants = $event->getParticipants(); + if (isset($object["participants"]) || $did_create || $sort_key_has_changed) { + + if (!isset($object["participants"])) { + $object["participants"] = $event->getParticipants(); + } + + if (count($object["workspaces_calendars"]) == 0 && count($object["participants"]) == 0 && !$current_user) { + return false; + } + if (count($object["workspaces_calendars"]) == 0 && $current_user) { + if (!is_array($object["participants"])) { + $object["participants"] = []; + } + $object["participants"] = array_merge([Array("user_id_or_mail" => $current_user->getId())], $object["participants"]); + } + if (count($object["participants"]) > 0 && count($object["workspaces_calendars"]) == 0) { + if (preg_match('/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/', $object["participants"][0]["user_id_or_mail"])) { + $event->setOwner($current_user ? $current_user->getId() : $object["participants"][0]["user_id_or_mail"]); + } else { + //No user (except mails) and no workspaces + $this->doctrine->remove($event); + $this->doctrine->flush(); + return false; + } + } + + + $this->updateParticipants($event, $object["participants"] ? $object["participants"] : Array(), $sort_key_has_changed || $did_create); + } + if (isset($object["workspaces_calendars"]) || $sort_key_has_changed) { + + if (!isset($object["workspaces_calendars"])) { + $object["workspaces_calendars"] = $event->getWorkspacesCalendars(); + } + + if (count($object["workspaces_calendars"]) > 0) { + $event->setOwner(""); + } + + $this->updateCalendars($event, $object["workspaces_calendars"] ? $object["workspaces_calendars"] : Array(), $sort_key_has_changed || $did_create); + } + + + //After checking user id or mails, we verify event is somewere + if (count($event->getParticipants()) == 0 && count($event->getWorkspacesCalendars()) == 0) { + $this->doctrine->remove($event); + $this->doctrine->flush(); + return false; + } + + if (isset($object["notifications"]) || $sort_key_has_changed || $from_changed) { + + if (!isset($object["notifications"])) { + $object["notifications"] = $event->getNotifications(); + } + + $this->updateNotifications($event, $object["notifications"] ? $object["notifications"] : Array(), ($sort_key_has_changed || $did_create || $from_changed)); + } + + + //Notify modification for participant users + $evt = Array( + "client_id" => "system", + "action" => "save", + "object_type" => "", + "object" => $event->getAsArray() + ); + $done = []; + foreach (array_merge($event->getParticipants(), $old_participants) as $participant) { + if (!in_array($participant["user_id_or_mail"], $done) && preg_match('/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/', $participant["user_id_or_mail"])) { + $done[] = $participant["user_id_or_mail"]; + $this->enc_pusher->push("calendar_events/user/" . $participant["user_id_or_mail"], $evt); + } + } + + //Send invitation or update mails + foreach ($event->getParticipants() as $participant) { + if (filter_var($participant["user_id_or_mail"], FILTER_VALIDATE_EMAIL)) { + $mail = $participant["user_id_or_mail"]; + } else if (preg_match('/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/', $participant["user_id_or_mail"])) { + $user = $this->doctrine->getRepository("Twake\Users:User")->findOneBy(Array("id" => $participant["user_id_or_mail"])); + if (!$user || ($current_user && $user->getId() == $current_user->getId())) { + continue; + } + $mail = $user->getEmail(); + } else { + continue; + } + $not_in_previous_participants = true; + foreach ($old_participants as $old_participant) { + if ($old_participant["user_id_or_mail"] == $mail) { + $not_in_previous_participants = false; + break; + } + } + if ($did_create || $not_in_previous_participants) { + $this->notifications->sendCustomMail( + $mail, "event_invitation", Array( + "_language" => $current_user ? $current_user->getLanguage() : "en", + "event" => $event->getAsArray(), + "user_timezone_delay" => $current_user ? (intval($current_user->getTimezone())) : null, + "user_timezone_text" => str_replace("+-", "-", $current_user ? ("GMT+" . ($current_user->getTimezone() / 60)) : "GMT+0"), + "sender_fullname" => $current_user ? ("@" . $current_user->getUsername()) : null, + "sender_email" => $current_user ? $current_user->getEmail() : null + ), + [Array("type" => "raw", "data" => $this->calendarExport->generateIcs([$event->getAsArray()]), "filename" => "event.ics", "mimetype" => "text/calendar")] + ); + } else if ($this->hasRealChange($old_event, $event->getAsArray())) { + $this->notifications->sendCustomMail( + $mail, "event_invitation_updated", Array( + "_language" => $current_user ? $current_user->getLanguage() : "en", + "event" => $event->getAsArray(), + "user_timezone_delay" => $current_user ? (intval($current_user->getTimezone())) : null, + "user_timezone_text" => str_replace("+-", "-", $current_user ? ("GMT+" . ($current_user->getTimezone() / 60)) : "GMT+0"), + "sender_fullname" => $current_user ? ("@" . $current_user->getUsername()) : null, + "sender_email" => $current_user ? $current_user->getEmail() : null + ), + [Array("type" => "raw", "data" => $this->calendarExport->generateIcs([$event->getAsArray()]), "filename" => "event.ics", "mimetype" => "text/calendar")] + + + ); + } + + } + + + //Notify connectors + $resources = []; + $done = []; + foreach ($event->getWorkspacesCalendars() as $calendar) { + $workspace_id = $calendar["workspace_id"]; + if (!in_array($workspace_id, $done)) { + $done[] = $workspace_id; + $resources = array_merge($resources, $this->applications_api->getResources($workspace_id, "workspace_calendar", $workspace_id)); + } + } + $apps_ids = []; + foreach ($resources as $resource) { + if (in_array("event", $resource->getApplicationHooks())) { + $apps_ids[] = $resource->getApplicationId(); + } + } + if (count($apps_ids) > 0) { + foreach ($apps_ids as $app_id) { + if ($app_id) { + $data = Array( + "event" => $event->getAsArray() + ); + if ($did_create) { + $this->applications_api->notifyApp($app_id, "hook", "new_event", $data); + } else { + $this->applications_api->notifyApp($app_id, "hook", "edit_event", $data); + } + } + } + } + + + return $event->getAsArray(); + } + + public function updateCalendars(Event $event, $calendars = Array(), $replace_all = false) + { + $sort_key = $event->getSortKey(); + + $calendars = $calendars ? $calendars : []; + + $updated_calendars = $this->formatArrayInput($calendars, ["calendar_id", "workspace_id"]); + $current_calendars = $event->getWorkspacesCalendars(); + $event->setWorkspacesCalendars($updated_calendars); + $this->doctrine->persist($event); + + $get_diff = $this->getArrayDiffUsingKeys($updated_calendars, $current_calendars, ["calendar_id", "workspace_id"]); + + if (count($get_diff["del"]) > 0 || $replace_all) { + $calendars_in_event = $this->doctrine->getRepository("Twake\Calendar:EventCalendar")->findBy(Array("event_id" => $event->getId())); + foreach ($calendars_in_event as $calendar) { + if (!$this->inArrayUsingKeys($get_diff["del"], ["calendar_id" => $calendar->getCalendarId(), "workspace_id" => $calendar->getWorkspaceId()], ["calendar_id", "workspace_id"]) || $replace_all) { + //Remove old participants + $this->doctrine->remove($calendar); + } + } + } + + foreach (($replace_all ? $updated_calendars : $get_diff["add"]) as $calendar) { + foreach ($sort_key as $sort_date) { + $user = new EventCalendar($calendar["workspace_id"], $calendar["calendar_id"], $event->getId(), $sort_date); + $this->doctrine->persist($user); + } + } + + $this->doctrine->flush(); + + } + + public function updateNotifications(Event $event, $notifications = Array(), $replace_all = false) + { + + $notifications = $notifications ? $notifications : []; + $token = base64_encode(bin2hex(random_bytes(32))); + + foreach ($notifications as $index => $notification) { + $notifications[$index]["token"] = $token; + } + + $updated_notifications = $this->formatArrayInput($notifications, ["delay", "mode"]); + $event->setNotifications($updated_notifications); + $this->doctrine->persist($event); + $this->doctrine->flush(); + + foreach ($updated_notifications as $notification) { + if ($event->getFrom() - $notification["delay"] < date("U")) { + continue; + } + + $this->queues_scheduled->schedule("calendar_events", $event->getFrom() - $notification["delay"], [ + "token" => $token, + "event_id" => $event->getId(), + "delay" => $notification["delay"], + "mode" => $notification["mode"] + ]); + } + + } + + public function hasRealChange($old_event, $new_event) + { + return ($old_event["from"] != $new_event["from"] || $old_event["to"] != $new_event["to"] + || strlen(str_replace(" ", "", $old_event["title"] . "")) - strlen(trim($new_event["title"] . "")) > 10 + || strlen(str_replace(" ", "", $old_event["location"] . "")) - strlen(trim($new_event["location"] . "")) > 10 + || strlen(str_replace(" ", "", $old_event["description"] . "")) - strlen(trim($new_event["description"] . "")) > 10); + } + + public function checkReminders() + { + + $sent = 0; + + $notifications = $this->queues_scheduled->consume("calendar_events", true); + + foreach ($notifications ?: [] as $notification_original) { + + $notification = $this->queues_scheduled->getMessage($notification_original); + + //Send notification + /** @var EventCalendar $event */ + $event = $this->doctrine->getRepository("Twake\Calendar:Event")->findOneBy(Array("id" => $notification["event_id"])); + + if ($event) { + + $existing_notifications = $event->getNotifications(); + $valid_notification = false; + foreach ($existing_notifications as $existing_notification) { + //Verify this received notification exists in calendar event + if ($existing_notification["token"] == $notification["token"]) { + $valid_notification = true; + } + } + + if ($valid_notification) { + + $delay = floor($notification["delay"] / 60) . "min"; + if ($notification["delay"] > 60 * 60) { + $delay = floor($notification["delay"] / (60 * 60)) . "h"; + } + if ($notification["delay"] > 60 * 60 * 24) { + $delay = floor($notification["delay"] / (60 * 60 * 24)) . "j"; + } + if ($notification["delay"] > 60 * 60 * 24 * 7 * 2) { + $delay = floor($notification["delay"] / (60 * 60 * 24 * 7)) . "w"; + } + + $title = "Untitled"; + if ($event->getTitle()) { + $title = $event->getTitle(); + } + $text = $title . " in " . $delay; + + $participants = $event->getParticipants(); + + foreach ($participants as $participant) { + if ($notification["mode"] == "mail" || !$notification["mode"]) { + $mail = $participant["user_id_or_mail"]; + $language = false; + if (preg_match('/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/', $participant["user_id_or_mail"])) { + $mail = $this->doctrine->getRepository("Twake\Users:User")->findOneBy(Array("id" => $participant["user_id_or_mail"])); + if ($mail) { + $language = $mail->getLanguage(); + $mail = $mail->getEMail(); + } else { + $mail = null; + } + } + //Mail + if ($mail) { + $this->notifications->sendCustomMail( + $mail, "event_notification", Array( + "_language" => $language ? $language : "en", + "text" => $text, + "delay" => $delay, + "event" => $event->getAsArray() + ) + ); + } + } + if ($notification["mode"] == "push" || !$notification["mode"]) { + //Push notification + if (preg_match('/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/', $participant["user_id_or_mail"])) { + $user = $this->doctrine->getRepository("Twake\Users:User")->findOneBy(Array("id" => $participant["user_id_or_mail"])); + if ($user) { + $this->notifications->pushDevice( + $user, $text, "πŸ“… Calendar notification", null + ); + } + } + } + } + + } + + } + + $sent++; + $this->queues_scheduled->ack("calendar_events", $notification_original); + + } + + return $sent; + + } + +} diff --git a/twake/backend/core/src/Twake/Calendar/Services/CalendarExport.php b/twake/backend/core/src/Twake/Calendar/Services/CalendarExport.php new file mode 100755 index 00000000..1fe8f5c5 --- /dev/null +++ b/twake/backend/core/src/Twake/Calendar/Services/CalendarExport.php @@ -0,0 +1,234 @@ +doctrine = $app->getServices()->get("app.twake_doctrine"); + } + + public function generateToken($request, $current_user = null) + { + + $user_id = $current_user->getId(); + $workspace_id = $request->request->get('workspace_id'); + $calendars = $request->request->get('calendars'); + + if ($workspace_id && ($calendars["mode"] == "both" || $calendars["mode"] == "workspace")) { + if (!isset($calendars["calendar_list"]) || !$calendars["calendar_list"] || count($calendars["calendar_list"]) == 0) { + $calendars["calendar_list"] = []; + $calendars_entities = $this->doctrine->getRepository("Twake\Calendar:Calendar")->findBy(Array("workspace_id" => $workspace_id)); + foreach ($calendars_entities as $calendar_entity) { + $calendars["calendar_list"][] = ["workspace_id" => $workspace_id, "calendar_id" => $calendar_entity->getId()]; + } + } + } + + $token = bin2hex(random_bytes(64)); + + $entity = new ExportToken($user_id, $workspace_id, $calendars, $token); + $this->doctrine->persist($entity); + $this->doctrine->flush(); + + return $token; + + } + + + public function exportCalendar($token, $calendarEventService) + { + $entity = $this->doctrine->getRepository("Twake\Calendar:ExportToken")->findOneBy(Array("user_token" => $token)); + if ($entity) { + $calendars = $entity->getCalendars(); + $mode = $calendars["mode"]; + $options = Array("mode" => $mode, + "calendar_list" => isset($calendars["calendar_list"]) ? $calendars["calendar_list"] : "", + "after_ts" => date("U", strtotime("-2 months")), + "before_ts" => date("U", strtotime("+10 months"))); + $user_entity = $this->doctrine->getRepository("Twake\Users:User")->findOneBy(Array("id" => $entity->getUserId())); + + + $events = $calendarEventService->get($options, $user_entity); + + if (is_array($events)) { + $vCalendar = $this->generateIcs($events); + + return new Response( + $vCalendar, 200, array( + 'Content-Type' => 'application/octet-stream', + 'Content-Description' => 'File Transfer', + + 'Content-Disposition' => 'attachment; filename="cal.ics"', + + 'Expires' => '0', + 'Cache-Control' => 'must-revalidate', + 'Pragma' => 'public', + ) + ); + } else { + return new Response("Errors : Events not found in data-base"); + } + } else + return new Response("Errors : Token not found in data-base"); + + + } + + public function generateIcs($events) + { + $time_zone = new \DateTimeZone("Etc/UTC"); + date_default_timezone_set("Etc/UTC"); + + + $vCalendar = new Component\Calendar('twakeapp.com'); + foreach ($events as $evt) { + + if (isset($evt["from"]) && $evt["from"]) { + $dateStart = new \DateTime(date("c", (int)$evt["from"]), $time_zone); + } else { + continue; + } + if (isset($evt["to"]) && $evt["to"]) { + //If allday we need to remove one day because we dont use the normal format + $dateEnd = new \DateTime(date("c", (int)$evt["to"]), $time_zone); + } else { + continue; + } + + $vEvent = new Component\Event(); + + if ($evt["repetition_definition"]) { + try { + $rrule = $evt["repetition_definition"]["rrule"]; + $rrule = explode("nRRULE", $rrule)[1]; + + foreach (explode(";", $rrule) as $parameter) { + $data = explode("=", $parameter); + $properties["key"][] = $data[0]; + $properties["value"][] = $data[1]; + } + + foreach ($properties as $p) { + foreach ($p as $key => $value) { + switch ($value) { + case ":FREQ" : + $freq = $key; + break; + case ":INTERVAL" : + $interval = $key; + break; + case "UNTIL" : + $until = $key; + break; + case "COUNT" : + $count = $key; + break; + Default: + } + + } + } + $freq = $properties["value"][$freq]; + $interval = $properties["value"][$interval]; + $until = $properties["value"][$until]; + if ($count) + $count = $properties["value"][$count]; + $stdRecurrenceRule = new \Eluceo\iCal\Property\Event\RecurrenceRule(); + + switch ($freq) { + case "WEEKLY" : + $stdRecurrenceRule->setFreq(\Eluceo\iCal\Property\Event\RecurrenceRule::FREQ_WEEKLY); + break; + case "YEARLY" : + $stdRecurrenceRule->setFreq(\Eluceo\iCal\Property\Event\RecurrenceRule::FREQ_YEARLY); + break; + case "MONTHLY" : + $stdRecurrenceRule->setFreq(\Eluceo\iCal\Property\Event\RecurrenceRule::FREQ_MONTHLY); + break; + case "DAILY" : + $stdRecurrenceRule->setFreq(\Eluceo\iCal\Property\Event\RecurrenceRule::FREQ_DAILY); + break; + case "HOURLY" : + $stdRecurrenceRule->setFreq(\Eluceo\iCal\Property\Event\RecurrenceRule::FREQ_HOURLY); + break; + case "MINUETELY" : + $stdRecurrenceRule->setFreq(\Eluceo\iCal\Property\Event\RecurrenceRule::FREQ_MINUETELY); + break; + case "SECONDLY" : + $stdRecurrenceRule->setFreq(\Eluceo\iCal\Property\Event\RecurrenceRule::FREQ_SECONDLY); + break; + Default: + } + + + $stdRecurrenceRule->setFreq(\Eluceo\iCal\Property\Event\RecurrenceRule::FREQ_WEEKLY); + $stdRecurrenceRule->setUntil(\DateTime::createFromFormat("Ymd\THis\Z", $until)); + $stdRecurrenceRule->setInterval($interval); + + switch ($properties["key"][3]) { + case "BYDAY" : + $stdRecurrenceRule->setByDay($properties["value"][3]); + break; + case "BYMONTH" : + $stdRecurrenceRule->setByMonth($properties["value"][3]); + break; + case "BYYEARDAY" : + $stdRecurrenceRule->setByYearDay($properties["value"][3]); + break; + case "BYWEEKNO" : + $stdRecurrenceRule->setByWeekNo($properties["value"][3]); + break; + case "BYMONTHDAY" : + $stdRecurrenceRule->setByMonthDay($properties["value"][3]); + break; + case "BYHOUR" : + $stdRecurrenceRule->setByHour($properties["value"][3]); + break; + case "BYMINUTE" : + $stdRecurrenceRule->setByMinute($properties["value"][3]); + break; + case "BYSECOND" : + $stdRecurrenceRule->setBySecond($properties["value"][3]); + break; + default: + } + + $vEvent->setRecurrenceRule($stdRecurrenceRule); + $vEvent->setDuration(isset($evt["repetition_definition"]["duration"]) ? $evt["repetition_definition"]["duration"] : 0); + + } catch (\Exception $e) { + //No recurence ! + } + } + + $vEvent + ->setNoTime(isset($evt["all_day"]) ? $evt["all_day"] : false) + ->setUseUtc(true) + ->setDtStart($dateStart) + ->setDtEnd($dateEnd) + ->setSummary(isset($evt["title"]) ? $evt["title"] : "") + ->setDescription(isset($evt["description"]) ? $evt["description"] : "") + ->setLocation(isset($evt["location"]) ? $evt["location"] : ""); + + if (isset($evt["id"])) { + $vEvent->setUniqueId($evt["id"] . ""); + } + + $vCalendar->addComponent($vEvent); + + } + + return $vCalendar->render(); + } + + +} diff --git a/twake/backend/core/src/Twake/Channels/Bundle.php b/twake/backend/core/src/Twake/Channels/Bundle.php new file mode 100755 index 00000000..52d1a433 --- /dev/null +++ b/twake/backend/core/src/Twake/Channels/Bundle.php @@ -0,0 +1,30 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Channels/Controller/Channels.php b/twake/backend/core/src/Twake/Channels/Controller/Channels.php new file mode 100755 index 00000000..6a0d50c3 --- /dev/null +++ b/twake/backend/core/src/Twake/Channels/Controller/Channels.php @@ -0,0 +1,53 @@ +request->get("options"); + + //This is only used now to get old "applications as channels" feature + //$objects = $this->get("app.channels.channels_system")->get($options, $this->getUser()); + $workspace = $this->get("app.workspaces")->get($options["workspace_id"]); + $apps = $this->get("app.group_apps")->getApps($workspace->getGroup()); + + $objects = []; + foreach($apps as $app){ + $objects[] = [ + "app_bot_identifier" =>"", + "app_group_id" =>"", + "app_id" => $app["app_id"], + "application" =>true, + "channel_group_name" =>"", + "connectors" =>[], + "description" =>"", + "direct" =>false, + "ext_members" =>[], + "front_id" => $app["app_id"], + "icon" =>"", + "id" => $app["app_id"], + "last_activity" =>1626706970, + "members" =>[$this->getUser()->getId()], + "members_count" => null, + "messages_increment" =>0, + "name" =>"", + "original_group" => $workspace->getGroup(), + "original_workspace" => $options["workspace_id"], + "private" =>false, + "tabs" =>[] + ]; + } + + if ($objects === false) { + return new Response(Array("status" => "error")); + } + return new Response(Array("data" => $objects)); + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Channels/Entity/Channel.php b/twake/backend/core/src/Twake/Channels/Entity/Channel.php new file mode 100755 index 00000000..d7a48ea1 --- /dev/null +++ b/twake/backend/core/src/Twake/Channels/Entity/Channel.php @@ -0,0 +1,626 @@ +front_id = sha1(random_bytes(40)); + $this->last_activity = new \DateTime(); + } + + public function getIndexationArray() + { + $return = Array( + "id" => $this->getId() . "", + "workspace_id" => $this->getOriginalWorkspaceId(), + "group_id" => ($this->getOriginalGroupId()) ? $this->getOriginalGroupId() : null, + "name" => $this->getName(), + "last_activity" => $this->getLastActivity() ? $this->getLastActivity()->getTimestamp() : null, + "members" => $this->getMembers(), + "ext_members" => $this->getExtMembers() + ); + + return $return; + } + + public function getAsArray() + { + return Array( + "id" => $this->getId(), + "front_id" => $this->getFrontId(), + "icon" => $this->getIcon(), + "name" => $this->getName(), + "description" => $this->getDescription(), + "channel_group_name" => $this->getChannelGroupName(), + "private" => $this->getPrivate(), + "direct" => $this->getDirect(), + "application" => $this->getApplication(), + "app_id" => $this->getAppId(), + "app_group_id" => $this->getAppGroupId(), + "app_bot_identifier" => $this->getAppBotIdentifier(), + "original_workspace" => ($this->getOriginalWorkspaceId()) ? $this->getOriginalWorkspaceId() : null, + "original_group" => ($this->getOriginalGroupId()) ? $this->getOriginalGroupId() : null, + "members_count" => $this->getMembersCount(), + "last_activity" => $this->getLastActivity() ? $this->getLastActivity()->getTimestamp() : null, + "members" => $this->getMembers(), + "ext_members" => $this->getExtMembers(), + "connectors" => $this->getConnectors(), + "tabs" => $this->getTabs(), + "messages_increment" => $this->getMessagesIncrement() + ); + } + + public function getTotalMembers() + { + return array_merge($this->getMembers(), $this->getExtMembers()); + } + + + /** + * @return mixed + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getFrontId() + { + return $this->front_id; + } + + /** + * @param mixed $front_id + */ + public function setFrontId($front_id) + { + if ($front_id) { + $this->front_id = $front_id; + } + } + + /** + * @return mixed + */ + public function getIcon() + { + return $this->icon; + } + + /** + * @param mixed $icon + */ + public function setIcon($icon) + { + $this->icon = $icon; + } + + /** + * @return mixed + */ + public function getName() + { + return $this->name; + } + + /** + * @param mixed $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @return mixed + */ + public function getChannelGroupName() + { + return $this->channel_group_name; + } + + /** + * @param mixed $channel_group_name + */ + public function setChannelGroupName($channel_group_name) + { + $this->channel_group_name = $channel_group_name; + } + + /** + * @return mixed + */ + public function getDescription() + { + return $this->description; + } + + /** + * @param mixed $description + */ + public function setDescription($description) + { + $this->description = $description; + } + + /** + * @return mixed + */ + public function getExternalAccessToken() + { + return $this->external_access_token; + } + + /** + * @param mixed $external_access_token + */ + public function setExternalAccessToken($external_access_token) + { + $this->external_access_token = $external_access_token; + } + + /** + * @return mixed + */ + public function getPrivate() + { + return $this->private; + } + + /** + * @param mixed $private + */ + public function setPrivate($private) + { + $this->private = ($private == true); + } + + /** + * @return mixed + */ + public function getDirect() + { + return $this->direct; + } + + /** + * @param mixed $direct + */ + public function setDirect($direct) + { + $this->direct = ($direct == true); + } + + /** + * @return Boolean (application channel or not) + */ + public function getApplication() + { + return $this->application; + } + + /** + * @return string + */ + public function getEsType() + { + return $this->es_type; + } + + + /** + * @param mixed $direct + */ + public function setApplication($application) + { + $this->application = ($application == true); + } + + /** + * @return mixed + */ + public function getAppId() + { + return $this->app_id; + } + + /** + * @return mixed + */ + public function getAppBotIdentifier() + { + return $this->app_bot_identifier; + } + + /** + * @param mixed $app_bot_identifier + */ + public function setAppBotIdentifier($app_bot_identifier) + { + $this->app_bot_identifier = $app_bot_identifier; + } + + /** + * @param mixed $direct + */ + public function setAppId($app_id) + { + $this->app_id = $app_id; + } + + /** + * @return mixed + */ + public function getAppGroupId() + { + return $this->app_group_id; + } + + /** + * @param mixed $app_group_id + */ + public function setAppGroupId($app_group_id) + { + $this->app_group_id = $app_group_id; + } + + /** + * @return mixed + */ + public function getOriginalWorkspaceId() + { + return $this->original_workspace_id; + } + + /** + * @param mixed $original_workspace + */ + public function setOriginalWorkspaceId($original_workspace_id) + { + $this->original_workspace_id = $original_workspace_id; + } + + /** + * @return mixed + */ + public function getOriginalGroupId() + { + return $this->original_group_id; + } + + /** + * @param mixed $original_group + */ + public function setOriginalGroupId($original_group) + { + $this->original_group_id = $original_group; + } + + /** + * @return mixed + */ + public function getMembersCount() + { + return $this->members_count; + } + + /** + * @param mixed $members_count + */ + public function setMembersCount($members_count) + { + $this->members_count = $members_count; + } + + /** + * @return mixed + */ + public function getLastActivity() + { + return $this->last_activity; + } + + /** + * @param mixed $last_activity + */ + public function setLastActivity($last_activity) + { + $this->last_activity = $last_activity; + } + + /** + * @return mixed + */ + public function getIdentifier() + { + return $this->identifier; + } + + /** + * @param mixed $identifier + */ + public function setIdentifier($identifier) + { + $this->identifier = $identifier; + } + + /** + * @return mixed + */ + public function getMembers() + { + $m = json_decode($this->members, 1); + if ($m) { + return array_values($m); + } + return $m; + } + + /** + * @param mixed $members + */ + public function setMembers($members) + { + $this->members = json_encode($members); + } + + /** + * @return mixed + */ + public function getExtMembers() + { + $m = json_decode($this->ext_members, 1); + if ($m) { + return array_values($m); + } + return $m; + } + + /** + * @param mixed $ext_members + */ + public function setExtMembers($ext_members) + { + $this->ext_members = json_encode($ext_members); + } + + /** + * @return mixed + */ + public function getTabs() + { + $m = json_decode($this->tabs, 1); + if ($m) { + return array_values($m); + } + return $m; + } + + /** + * @param mixed $tabs + */ + public function setTabs($tabs) + { + $this->tabs = json_encode($tabs); + } + + /** + * @return mixed + */ + public function getConnectors() + { + $m = json_decode($this->connectors, 1); + if ($m) { + return array_values($m); + } + return $m; + } + + /** + * @param mixed $tabs + */ + public function setConnectors($connectors) + { + $this->connectors = json_encode($connectors); + } + + + /** + * @return mixed + */ + public function getMessagesCount() + { + return $this->messages_count; + } + + /** + * @param mixed $messages_count + */ + public function setMessagesCount($messages_count) + { + $this->messages_count = $messages_count; + } + + /** + * @return mixed + */ + public function getMessagesIncrement() + { + return $this->messages_increment ? $this->messages_increment : 0; + } + + /** + * @param mixed $messages_increment + */ + public function setMessagesIncrement($messages_increment) + { + $this->messages_increment = $messages_increment; + } + + /** + * @return mixed + */ + public function getAutoMute() + { + return $this->auto_mute; + } + + /** + * @param mixed $auto_mute + */ + public function setAutoMute($auto_mute) + { + $this->auto_mute = $auto_mute; + } + + +} diff --git a/twake/backend/core/src/Twake/Channels/Entity/ChannelMember.php b/twake/backend/core/src/Twake/Channels/Entity/ChannelMember.php new file mode 100755 index 00000000..579dbfd7 --- /dev/null +++ b/twake/backend/core/src/Twake/Channels/Entity/ChannelMember.php @@ -0,0 +1,241 @@ +user_id = $user_id; + $this->channel_id = $channel->getId(); + $this->last_activity_least_updated = new \DateTime(); + $this->last_activity = new \DateTime(); + $this->last_access = new \DateTime(); + $this->direct = $channel->getDirect(); + $this->last_messages_increment = $channel->getMessagesIncrement(); + } + + /** + * @return mixed + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getUserId() + { + return $this->user_id; + } + + /** + * @return mixed + */ + public function getChannelId() + { + return $this->channel_id; + } + + /** + * @return mixed + */ + public function getLastActivity() + { + return $this->last_activity; + } + + /** + * @param mixed $last_activity + */ + public function setLastActivity($last_activity) + { + $this->last_activity = $last_activity; + if ($this->last_activity_least_updated->getTimestamp() < $last_activity->getTimestamp() - 60 * 60 * 24) { + $this->last_activity_least_updated = $last_activity; + } + } + + /** + * @return mixed + */ + public function getLastAccess() + { + return $this->last_access; + } + + /** + * @param mixed $last_access + */ + public function setLastAccess($last_access) + { + $this->last_access = $last_access; + } + + /** + * @return mixed + */ + public function getDirect() + { + return $this->direct; + } + + /** + * @param mixed $direct + */ + public function setDirect($direct) + { + $this->direct = $direct; + } + + /** + * @return mixed + */ + public function getExterne() + { + return $this->externe; + } + + /** + * @param mixed $direct + */ + public function setExterne($externe) + { + $this->externe = $externe; + } + + /** + * @return mixed + */ + public function getMuted() + { + return $this->muted; + } + + /** + * @param mixed $muted 0: no, 1: mute default (except @all, @[user]), 2: mute all except user mension, 3: mute everything + */ + public function setMuted($muted) + { + $this->muted = $muted; + } + + /** + * @return mixed + */ + public function getLastMessagesIncrement() + { + return $this->last_messages_increment; + } + + /** + * @param mixed $last_messages_increment + */ + public function setLastMessagesIncrement($last_messages_increment) + { + $this->last_messages_increment = $last_messages_increment; + } + + /** + * @return mixed + */ + public function getLastQuotedMessageId() + { + return $this->last_quoted_message_id; + } + + /** + * @param mixed $last_quoted_message_id + */ + public function setLastQuotedMessageId($last_quoted_message_id) + { + $this->last_quoted_message_id = $last_quoted_message_id; + } + +} diff --git a/twake/backend/core/src/Twake/Channels/Entity/ChannelTab.php b/twake/backend/core/src/Twake/Channels/Entity/ChannelTab.php new file mode 100755 index 00000000..5615f0eb --- /dev/null +++ b/twake/backend/core/src/Twake/Channels/Entity/ChannelTab.php @@ -0,0 +1,143 @@ + $this->getId(), + "front_id" => $this->getFrontId(), + "app_id" => $this->getAppId(), + "channel_id" => $this->getChannelId(), + "name" => $this->getName(), + "configuration" => $this->getConfiguration() + ); + } + + /** + * @return mixed + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getName() + { + return $this->name; + } + + /** + * @param mixed $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @return mixed + */ + public function getAppId() + { + return $this->app_id; + } + + /** + * @param mixed $app_id + */ + public function setAppId($app_id) + { + $this->app_id = $app_id; + } + + /** + * @return mixed + */ + public function getChannelId() + { + return $this->channel_id; + } + + /** + * @param mixed $channel_id + */ + public function setChannelId($channel_id) + { + $this->channel_id = $channel_id; + } + + /** + * @return mixed + */ + public function getConfiguration() + { + return json_decode($this->configuration, true); + } + + /** + * @param mixed $configuration + */ + public function setConfiguration($configuration) + { + $this->configuration = json_encode($configuration); + } + + +} diff --git a/twake/backend/core/src/Twake/Channels/Resources/Routing.php b/twake/backend/core/src/Twake/Channels/Resources/Routing.php new file mode 100755 index 00000000..811c7588 --- /dev/null +++ b/twake/backend/core/src/Twake/Channels/Resources/Routing.php @@ -0,0 +1,16 @@ + ["handler" => "Channels:getAction", "methods" => ["POST"], "security" => ["user_connected_security"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Channels/Resources/Services.php b/twake/backend/core/src/Twake/Channels/Resources/Services.php new file mode 100755 index 00000000..aa9e8140 --- /dev/null +++ b/twake/backend/core/src/Twake/Channels/Resources/Services.php @@ -0,0 +1,14 @@ + "DirectMessagesSystem", + "app.channels.channels_system" => "ChannelsSystem" + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Channels/Services/ChannelSystemAbstract.php b/twake/backend/core/src/Twake/Channels/Services/ChannelSystemAbstract.php new file mode 100755 index 00000000..74cf0a5f --- /dev/null +++ b/twake/backend/core/src/Twake/Channels/Services/ChannelSystemAbstract.php @@ -0,0 +1,387 @@ +entity_manager = $app->getServices()->get("app.twake_doctrine"); + $this->applicationsApi = $app->getServices()->get("app.applications_api"); + $this->workspaceUser = $app->getServices()->get("app.workspace_members"); + } + + public function removeGeneralChannel($object) + { + + $object = $this->entity_manager->getRepository("Twake\Channels:Channel")->find(Array("id" => $object["id"], "direct" => $object["direct"], "original_workspace_id" => $object["original_workspace"])); + if ($object) { + $this->entity_manager->remove($object); + + $members = $this->entity_manager->getRepository("Twake\Channels:ChannelMember")->findBy(Array("channel_id" => $object->getId())); + foreach ($members as $member) { + $this->entity_manager->remove($member); + $linkWorkspaceUser = $this->entity_manager->getRepository("Twake\Workspaces:WorkspaceUser")->findOneBy(Array("workspace_id" => $object->getOriginalWorkspaceId(), "user_id" => $member->getUserId())); + if ($linkWorkspaceUser && $linkWorkspaceUser->getExterne() && !$linkWorkspaceUser->getAutoAddExterne()) { + $this->removeExterneIfNotAnymoreInChannel($object->getOriginalWorkspaceId(), $object->getId(), $member->getUserId()); + } + } + + + $this->entity_manager->flush(); + } + + return $object; + + } + + public function removeExterneIfNotAnymoreInChannel($workspaceId, $channelId, $userId) + { + $channel_in_current_workspace = $this->entity_manager->getRepository("Twake\Channels:Channel")->findBy(Array("direct" => false, "original_workspace_id" => $workspaceId)); + $isInChannel = false; + foreach ($channel_in_current_workspace as $chan) { + $link_user_channel = $this->entity_manager->getRepository("Twake\Channels:ChannelMember")->findOneBy(Array("direct" => 0, "user_id" => $userId, "channel_id" => $chan->getId())); + if ($link_user_channel && $link_user_channel->getChannelId() != $channelId) { + $isInChannel = true; + break; + } + } + if (!$isInChannel) { + $linkUserWorkspace = $this->entity_manager->getRepository("Twake\Workspaces:WorkspaceUser")->findOneBy(Array("workspace_id" => $workspaceId, "user_id" => $userId)); + if ($linkUserWorkspace) { + $this->workspaceUser->removeMember($workspaceId, $userId); + } + } + + } + + public function updateConnectors($channel_entity, $connectors_ids, $current_user_id = null) + { + + + $current_connectors = $channel_entity->getConnectors(); + $current_connectors = $current_connectors ? $current_connectors : []; + + $did_something = false; + + foreach ($connectors_ids as $connector_id) { + if (!in_array($connector_id, $current_connectors)) { + $this->applicationsApi->addResource($connector_id, $channel_entity->getOriginalWorkspaceId(), "channel", $channel_entity->getId(), $current_user_id); + $did_something = true; + } + } + + foreach ($current_connectors as $current_connector_id) { + if (!in_array($current_connector_id, $connectors_ids)) { + $this->applicationsApi->removeResource($connector_id, $channel_entity->getOriginalWorkspaceId(), "channel", $channel_entity->getId(), $current_user_id); + $did_something = true; + } + } + + if ($did_something) { + $channel_entity->setConnectors($connectors_ids); + $this->entity_manager->persist($channel_entity); + $this->entity_manager->flush(); + } + + } + + public function updateTabConfiguration($channel_id, $application_id, $tab_id, $configuration) + { + + $tab = $this->entity_manager->getRepository("Twake\Channels:ChannelTab")->findOneBy(Array("channel_id" => $channel_id, "app_id" => $application_id, "id" => $tab_id)); + if (!$tab) { + return; + } + $tab->setConfiguration($configuration); + $this->entity_manager->persist($tab); + $this->entity_manager->flush(); + + $channel = $this->entity_manager->getRepository("Twake\Channels:Channel")->findOneBy(Array("id" => $channel_id)); + $cached_tabs = $channel->getTabs(); + foreach ($cached_tabs as $k => $cached_tab) { + if ($cached_tab["id"] == $tab_id) { + $cached_tabs[$k] = $tab->getAsArray(); + } + } + $channel->setTabs($cached_tabs); + + $this->entity_manager->persist($channel); + $this->entity_manager->flush(); + + } + + public function renameTab($channel_id, $application_id, $tab_id, $name) + { + + $tab = $this->entity_manager->getRepository("Twake\Channels:ChannelTab")->findOneBy(Array("channel_id" => $channel_id, "app_id" => $application_id, "id" => $tab_id)); + if (!$tab) { + return; + } + $tab->setName($name); + $this->entity_manager->persist($tab); + $this->entity_manager->flush(); + + $channel = $this->entity_manager->getRepository("Twake\Channels:Channel")->findOneBy(Array("id" => $channel_id)); + $cached_tabs = $channel->getTabs(); + foreach ($cached_tabs as $k => $cached_tab) { + if ($cached_tab["id"] == $tab_id) { + $cached_tabs[$k] = $tab->getAsArray(); + } + } + $channel->setTabs($cached_tabs); + + $this->entity_manager->persist($channel); + $this->entity_manager->flush(); + + } + + public function removeTab($channel_id, $application_id, $tab_id) + { + + $tab = $this->entity_manager->getRepository("Twake\Channels:ChannelTab")->findOneBy(Array("channel_id" => $channel_id, "app_id" => $application_id, "id" => $tab_id)); + if (!$tab) { + return; + } + $this->entity_manager->remove($tab); + $this->entity_manager->flush(); + + $channel = $this->entity_manager->getRepository("Twake\Channels:Channel")->findOneBy(Array("id" => $channel_id)); + $cached_tabs = $channel->getTabs(); + $cached_tabs_new = []; + foreach ($cached_tabs as $cached_tab) { + if ($cached_tab["id"] != $tab_id) { + $cached_tabs_new[] = $cached_tab; + } + } + $channel->setTabs($cached_tabs_new); + + $this->entity_manager->persist($channel); + $this->entity_manager->flush(); + + } + + public function addTab($channel_id, $application_id, $name) + { + + $tab = new ChannelTab(); + $tab->setAppId($application_id); + $tab->setChannelId($channel_id); + $tab->setName($name); + + $this->entity_manager->persist($tab); + $this->entity_manager->flush(); + + $channel = $this->entity_manager->getRepository("Twake\Channels:Channel")->findOneBy(Array("id" => $channel_id)); + $cached_tabs = $channel->getTabs(); + $cached_tabs[] = $tab->getAsArray(); + $channel->setTabs($cached_tabs); + + $this->entity_manager->persist($channel); + $this->entity_manager->flush(); + + return $tab; + + } + + public function addAllWorkspaceMember($workspace, $channel) + { + if ($workspace && $channel) { + + $wuRepo = $this->entity_manager->getRepository("Twake\Workspaces:WorkspaceUser"); + $members = $wuRepo->findBy(Array("workspace_id" => $workspace->getId())); + $idsMembers = Array(); + $idsExt = Array(); + foreach ($members as $member) { + if($member->getUser($this->entity_manager)){ + if (!$member->getExterne()) { + $idsMembers[] = $member->getUser($this->entity_manager)->getId(); + } elseif ($member->getAutoAddExterne()) { + $idsExt[] = $member->getUser($this->entity_manager)->getId(); + } + } + } + $this->updateChannelMembers($channel, $idsMembers); + $this->updateExtChannelMembers($channel, $idsExt); + + } + } + + public function updateChannelMembers($channel_entity, $members_ids, $current_user_id = null) + { + + if ($current_user_id && !in_array($current_user_id, $members_ids)) { + $members_ids[] = $current_user_id; + } + + $members_ids = array_unique($members_ids); + $final_members_ids = []; + + $current_members = $channel_entity->getMembers(); + + $membersRepo = $this->entity_manager->getRepository("Twake\Channels:ChannelMember"); + $usersRepo = $this->entity_manager->getRepository("Twake\Users:User"); + + foreach ($members_ids as $member_id) { + if (!in_array($member_id, $current_members)) { + //Check if user is in workspace + $canBeAdded = true; + if(!$channel_entity->getDirect()){ + $wuRepo = $this->entity_manager->getRepository("Twake\Workspaces:WorkspaceUser"); + $canBeAdded = !!$wuRepo->findBy(Array("workspace_id" => $channel_entity->getOriginalWorkspaceId()."", "user_id" => $member_id."")); + } + if($canBeAdded){ + $member = new \Twake\Channels\Entity\ChannelMember($member_id . "", $channel_entity); + $member->setLastMessagesIncrement($channel_entity->getMessagesIncrement()); + $this->entity_manager->persist($member); + $final_members_ids[] = $member_id; + } + }else{ + $final_members_ids[] = $member_id; + } + } + + foreach ($current_members as $member_id) { + if (!in_array($member_id, $members_ids)) { + $members = $membersRepo->findBy(Array("direct" => $channel_entity->getDirect(), "channel_id" => $channel_entity->getId(), "user_id" => $usersRepo->find($member_id))); + foreach ($members as $member) { + $this->entity_manager->remove($member); + } + } + } + + $channel_entity->setMembers($final_members_ids); + $this->entity_manager->persist($channel_entity); + $this->entity_manager->flush(); + + } + + public function updateExtChannelMembers($channel_entity, $ext_members, $current_user_id = null) + { + $_ext_members = []; + $members = $channel_entity->getMembers(); + + foreach ($ext_members as $ext_member) { + if (!in_array($ext_member, $members)) { + $_ext_members[] = $ext_member; + } + } + if (!$channel_entity->getPrivate()) { + // si le channel n'est pas privΓ©, on rajoute tous les autoadd + $membersWorkspace = $this->entity_manager->getRepository("Twake\Workspaces:WorkspaceUser")->findBy(Array("workspace_id" => $channel_entity->getOriginalWorkspaceId())); + foreach ($membersWorkspace as $members) { + try{ + if ($members->getAutoAddExterne() && !in_array($members->getUserId(), $_ext_members)) { + $_ext_members[] = $members->getUserId(); + } + }catch(\Exception $err){ + //No user + } + } + + } + + + $current_ext = $channel_entity->getExtMembers(); + $current_ext = $current_ext ? $current_ext : []; + + $membersRepo = $this->entity_manager->getRepository("Twake\Channels:ChannelMember"); + $usersRepo = $this->entity_manager->getRepository("Twake\Users:User"); + + $did_something = false; + + foreach ($_ext_members as $member) { + // dans le cas oΓΉ c'est un id + if (strrpos($member, "@") <= 0) { + if (!in_array($member, $current_ext)) { + $member_id = $member; + $user = $usersRepo->findOneBy(Array("id" => $member_id)); + if ($user) { + $this->addUserToChannel($user, $channel_entity); + $did_something = true; + } + } + } else { + // dans le cas oΓΉ c'est une adresse mail + $mail = $member; + if (!in_array($mail, $current_ext)) { + $user = $this->entity_manager->getRepository("Twake\Users:User")->findOneBy(Array("emailcanonical" => $mail)); + if ($user && !in_array($user->getId(), $current_ext)) { + $_ext_members[array_search($mail, $_ext_members)] = $user->getId(); + $this->addUserToChannel($user, $channel_entity); + $did_something = true; + } else { + $secondMail = $this->entity_manager->getRepository("Twake\Users:Mail")->findOneBy(Array("mail" => $mail)); + if ($secondMail && !in_array($secondMail->getUserId(), $current_ext)) { + // c'est un email secondaire + $user_id = $secondMail->getUserId(); + $_ext_members[array_search($mail, $_ext_members)] = $user_id; + $this->addUserToChannel($user, $channel_entity); + $did_something = true; + } else { + $member = new \Twake\Channels\Entity\ChannelMember($mail, $channel_entity); + $member->setLastMessagesIncrement($channel_entity->getMessagesIncrement()); + $member->setExterne(true); + $this->entity_manager->persist($member); + $this->workspaceUser->addMemberByMail($channel_entity->getOriginalWorkspaceId(), $mail, true, $current_user_id); + $did_something = true; + } + } + + } + + } + } + + foreach ($current_ext as $member_id) { + if (!in_array($member_id, $_ext_members)) { + $members = $membersRepo->findBy(Array("direct" => $channel_entity->getDirect(), "channel_id" => $channel_entity->getId(), "user_id" => $member_id)); + foreach ($members as $member) { + $this->entity_manager->remove($member); + $this->removeExterneIfNotAnymoreInChannel($channel_entity->getOriginalWorkspaceId(), $channel_entity->getId(), $member_id); + // vΓ©rifier si l'utilisateur est dans un autre channel + } + $did_something = true; + + //TODO Si utilisateur invitΓ© dans aucun channel, supprimer des invitΓ©s + } + } + + if ($did_something) { + $channel_entity->setExtMembers($_ext_members); + + $this->entity_manager->persist($channel_entity); + $this->entity_manager->flush(); + } + } + + public function addUserToChannel($user, $channel) + { + if(!$user || is_string($user) === 'string'){ + return false; + } + $link = $this->entity_manager->getRepository("Twake\Channels:ChannelMember")->findOneBy(Array("direct" => false, "user_id" => $user->getId(), "channel_id" => $channel->getId())); + if (!$link) { + $member = new \Twake\Channels\Entity\ChannelMember($user->getId(), $channel); + $member->setLastMessagesIncrement($channel->getMessagesIncrement()); + $member->setExterne(true); + $this->entity_manager->persist($member); + + $workspace_id = $channel->getOriginalWorkspaceId(); + $link = $this->entity_manager->getRepository("Twake\Workspaces:WorkspaceUser")->findBy(Array("workspace_id" => $workspace_id, "user_id" => $user->getId())); + if (!$link) { + $this->workspaceUser->addMember($workspace_id, $user->getId(), true); + } + } + return true; + } + + +} diff --git a/twake/backend/core/src/Twake/Channels/Services/ChannelsSystem.php b/twake/backend/core/src/Twake/Channels/Services/ChannelsSystem.php new file mode 100755 index 00000000..58ef50c5 --- /dev/null +++ b/twake/backend/core/src/Twake/Channels/Services/ChannelsSystem.php @@ -0,0 +1,423 @@ +access_manager = $app->getServices()->get("app.accessmanager"); + $this->messages_service = $app->getServices()->get("app.messages"); + $this->websockets_service = $app->getServices()->get("app.websockets"); + parent::__construct($app); + } + + /** Called from Collections manager to verify user has access to websockets room, registered in Core/Services/Websockets.php */ + public function init($route, $data, $current_user = null) + { + $route = explode("/", $route); + $workspace_id = isset($route[2]) ? $route[2] : null; + + return $this->hasAccess([ + "workspace_id" => $workspace_id + ], $current_user); + } + + public function hasAccess($data, $current_user = null) + { + if ($current_user === null) { + return true; + } + if (!is_string($current_user)) { + $current_user = $current_user->getId(); + } + + if (empty($data["id"])) { + return $this->access_manager->has_access($current_user, [ + "type" => "Workspace", + "edition" => false, + "object_id" => $data["workspace_id"] ?: $data["original_workspace"] + ]); + } + + return $this->access_manager->has_access($current_user, [ + "type" => "Channel", + "edition" => true, + "object_id" => $data["id"] + ]); + } + + public function get($options, $current_user) + { + if (!$this->hasAccess($options, $current_user)) { + return false; + } + + $workspace_id = $options["workspace_id"]; + + $channels = $this->entity_manager->getRepository("Twake\Channels:Channel")->findBy( + Array("original_workspace_id" => $workspace_id, "direct" => false) + ); + + $result = []; + foreach ($channels as $channel) { + if (!$current_user || !$channel) { + continue; + } + $res = $this->entity_manager->getRepository("Twake\Channels:ChannelMember")->findOneBy(Array("direct" => false, "user_id" => $current_user->getId(), "channel_id" => $channel->getId())); + if ($res) { + $tmp = $channel->getAsArray(); + $tmp["_user_last_message_increment"] = $res->getLastMessagesIncrement(); + $tmp["_user_last_quoted_message_id"] = $res->getLastQuotedMessageId(); + $tmp["_user_last_access"] = $res->getLastAccess() ? $res->getLastAccess()->getTimestamp() : null; + $tmp["_user_muted"] = $res->getMuted(); + $result[] = $tmp; + } + }; + + return $result; + } + + public function remove($object, $options, $current_user = null) + { + if (!$this->hasAccess($object, $current_user)) { + return false; + } + + + return $this->removeGeneralChannel($object); + } + + public function save($object, $options, $current_user) + { + if (!$this->hasAccess($object, $current_user)) { + error_log("no access " . $object["id"]); + return false; + } + + $did_create = false; + + $members = isset($object["members"]) ? $object["members"] : []; + $members = array_unique($members); + sort($members); + + + //Create or find channel + if (!isset($object["id"])) { + + if (!$object["original_group"] || !$object["original_workspace"]) { + return false; + } + + $group = $this->entity_manager->getRepository("Twake\Workspaces:Group")->find($object["original_group"]); + $workspace = $this->entity_manager->getRepository("Twake\Workspaces:Workspace")->find($object["original_workspace"]); + + $channel = new \Twake\Channels\Entity\Channel(); + $channel->setDirect(false); + $channel->setFrontId($object["front_id"]); + + $channel->setOriginalGroupId($group->getId()); + $channel->setOriginalWorkspaceId($workspace->getId()); + + $did_create = true; + + } else { + $channel = $this->entity_manager->getRepository("Twake\Channels:Channel")->find(Array("id" => $object["id"], "direct" => $object["direct"], "original_workspace_id" => $object["original_workspace"])); + if (!$channel) { + return false; + } + } + + //It should not be a direct channel + if ($channel->getDirect()) { + return false; + } + + + //Modifiy channel details + $channel->setMembersCount(count($members)); + $channel->setName($object["name"]); + $channel->setIcon($object["icon"]); + $channel->setDescription($object["description"]); + $channel->setChannelGroupName($object["channel_group_name"]); + + + //Manage private or not private status + $add_everybody = false; + if ($channel->getPrivate() && !$object["private"]) { + $add_everybody = true; + } + + $channel->setPrivate($object["private"]); + + $this->entity_manager->persist($channel); + $this->entity_manager->flush($channel); + + + //Private and non private users management + if ($channel->getPrivate()) { + $this->updateChannelMembers($channel, $members, $current_user->getId()); + } + if (($did_create || $add_everybody) && !$channel->getPrivate()) { + if (!$workspace) { + $workspace = $this->entity_manager->getRepository("Twake\Workspaces:Workspace")->find($object["original_workspace"]); + } + $this->addAllWorkspaceMember($workspace, $channel); + } + + + //Add external members + if (isset($object["ext_members"])) { + $ext_members = $object["ext_members"]; + $this->updateExtChannelMembers($channel, $ext_members, $current_user->getId()); + } + + + //Manage connectors + if (!$channel->getAppId() && isset($object["connectors"])) { + $connectors = $object["connectors"]; + $this->updateConnectors($channel, $connectors, $current_user ? $current_user->getId() : null); + } + + + //Tabs + $tab = null; + if (isset($object["_once_save_tab"])) { + if (isset($object["_once_save_tab"]["id"]) && $object["_once_save_tab"]["id"]) { + $this->renameTab($channel->getId(), $object["_once_save_tab"]["app_id"], $object["_once_save_tab"]["id"], $object["_once_save_tab"]["name"]); + } else { + $tab = $this->addTab($channel->getId(), $object["_once_save_tab"]["app_id"], $object["_once_save_tab"]["name"]); + } + } + if (isset($object["_once_remove_tab"])) { + $this->removeTab($channel->getId(), $object["_once_remove_tab"]["app_id"], $object["_once_remove_tab"]["id"]); + } + if (isset($object["_once_save_tab_config"])) { + $tab_id = $object["_once_save_tab_config"]["id"]; + if($tab && !$tab_id){ + $tab_id = $tab->getId(); + } + $this->updateTabConfiguration($channel->getId(), $object["_once_save_tab_config"]["app_id"], $tab_id, $object["_once_save_tab_config"]["configuration"]); + } + + //Send first message if created channel + if ($did_create) { + //Init channel with a first message + $init_message = Array( + "channel_id" => $channel->getId(), + "hidden_data" => Array("type" => "init_channel"), + "content" => "[]" + ); + $this->messages_service->save($init_message, Array()); + } + + return $channel->getAsArray(); + + } + + public function getApplicationChannel($application, $workspace) + { + + $identifier = "app_" . $application->getId() . "+ws_" . $workspace->getId(); + + $channel = $this->entity_manager->getRepository("Twake\Channels:Channel")->findOneBy( + Array("identifier" => $identifier) + ); + + if (!$channel) { + + $channel = new \Twake\Channels\Entity\Channel(); + $channel->setDirect(false); + $channel->setApplication(true); + + $channel->setOriginalGroupId($workspace->getGroup()); + $channel->setOriginalWorkspaceId($workspace->getId()); + + $channel->setAppId($application->getId()); + $channel->setIdentifier($identifier); + + $did_create = true; + + $this->entity_manager->persist($channel); + $this->entity_manager->flush(); + + } + + if ($channel->getPrivate()) { + $this->updateChannelMembers($channel, $members); + } + + if ($did_create && !$channel->getPrivate()) { + $this->addAllWorkspaceMember($workspace, $channel); + } + + $event = Array( + "client_id" => "system", + "action" => "save", + "object_type" => "", + "object" => $channel->getAsArray() + ); + $this->websockets_service->push("channels/workspace/" . $workspace->getId(), $event); + + return $channel; + + } + + public function removeApplicationChannel($application, $workspace) + { + $identifier = "app_" . $application->getId() . "+ws_" . $workspace->getId(); + + $channel = $this->entity_manager->getRepository("Twake\Channels:Channel")->findOneBy( + Array("identifier" => $identifier) + ); + + if ($channel) { + + $event = Array( + "client_id" => "system", + "action" => "remove", + "object_type" => "", + "front_id" => $channel->getFrontId() + ); + $this->websockets_service->push("channels/workspace/" . $workspace->getId(), $event); + + $this->entity_manager->remove($channel); + $this->entity_manager->flush(); + + return true; + } + + return false; + } + + public function search($words, $workspaces, $current_user_id) + { + + $terms = Array(); + $should_workspaces = Array(); + foreach ($words as $word) { + $st = new StringCleaner(); + $word = $st->simplifyInArray($word); + $terms[] = Array( + "bool" => Array( + "filter" => Array( + "regexp" => Array( + "name" => ".*" . $word . ".*" + ) + ) + ) + ); + } + + foreach ($workspaces as $workspace) { + $should_workspaces[] = Array( + "match_phrase" => Array( + "workspace_id" => $workspace["id"] + ) + ); + } + + $options = Array( + "repository" => "Twake\Channels:Channel", + "index" => "channel", + "query" => Array( + "bool" => Array( + "must" => Array( + "bool" => Array( + "filter" => Array( + "match_phrase" => Array( + "members" => $current_user_id + ) + ), + "should" => Array( + $should_workspaces + ), + "minimum_should_match" => 1, + "must" => Array( + "bool" => Array( + "should" => Array( + $terms + ), + "minimum_should_match" => 1 + ) + ) + ) + ) + ) + ), + "sort" => Array( + "last_activity" => Array( + "order" => "desc" + ) + ) + ); + + $channels = $this->entity_manager->es_search($options); + + $result = []; + foreach ($channels["result"] as $channel) { + $result[] = Array($channel[0]->getAsArray(), $channel[1][0]); + } + + return $result; + + } + + public function searchprivate($words, $current_user_id) + { + + $terms = Array(); + foreach ($words as $word) { + $st = new StringCleaner(); + $word = $st->simplifyInArray($word); + $terms[] = Array( + "bool" => Array( + "filter" => Array( + "regexp" => Array( + "name" => ".*" . $word . ".*" + ) + ) + ) + ); + } + + $options = Array( + "repository" => "Twake\Channels:Channel", + "index" => "channel", + "query" => Array( + "bool" => Array( + "filter" => Array( + "match_phrase" => Array( + "members" => $current_user_id + ) + ), + "should" => Array( + $terms + ), + "minimum_should_match" => 2 + ) + ), + "sort" => Array( + "last_activity" => Array( + "order" => "desc" + ) + ) + ); + + $channels = $this->entity_manager->es_search($options); + + $result = []; + foreach ($channels["result"] as $channel) { + $result[] = Array($channel[0]->getAsArray(), $channel[1][0]); + } + + return $result; + + } +} diff --git a/twake/backend/core/src/Twake/Channels/Services/DirectMessagesSystem.php b/twake/backend/core/src/Twake/Channels/Services/DirectMessagesSystem.php new file mode 100755 index 00000000..9860d0b2 --- /dev/null +++ b/twake/backend/core/src/Twake/Channels/Services/DirectMessagesSystem.php @@ -0,0 +1,181 @@ +messages_service = $app->getServices()->get("app.messages"); + parent::__construct($app); + } + + /** Called from Collections manager to verify user has access to websockets room, registered in Core/Services/Websockets.php */ + public function init($route, $data, $current_user = null) + { + if(!$current_user || is_string($current_user)){ + return false; + } + if (str_replace("channels/direct_messages/", "", $route) == $current_user->getId()) { + return $this->hasAccess($data, $current_user); + } else { + return false; + } + } + + public function hasAccess($data, $current_user = null) + { + if ($current_user) { + return true; + } else { + return false; + } + } + + public function get($options, $current_user) + { + if (!$this->hasAccess($options, $current_user)) { + return false; + } + + $channelRepo = $this->entity_manager->getRepository("Twake\Channels:Channel"); + + $member = $this->entity_manager->getRepository("Twake\Channels:ChannelMember")->findBy( + Array("user_id" => $current_user->getId(), "direct" => true), + Array(), + isset($options["max"]) ? $options["max"] : 40, + isset($options["offset"]) ? $options["offset"] : 0, + "last_activity_least_updated", + 0, + "last_modified_channels" + ); + + $result = []; + foreach ($member as $link) { + if ($link->getChannelId()) { + $channel = $channelRepo->find(Array("direct" => 1, "original_workspace_id" => "", "id" => $link->getChannelId())); + if ($channel) { + $tmp = $channel->getAsArray(); + $tmp["_user_last_message_increment"] = $link->getLastMessagesIncrement(); + $tmp["_user_last_quoted_message_id"] = $link->getLastQuotedMessageId(); + $tmp["_user_last_access"] = $link->getLastAccess() ? $link->getLastAccess()->getTimestamp() : null; + $tmp["_user_muted"] = $link->getMuted(); + $result[] = $tmp; + } + } + } + + return $result; + } + + public function remove($object, $options, $current_user) + { + //TODO verify this channel is ours + if (!$this->hasAccess($options, $current_user)) { + return false; + } + + return $this->removeGeneralChannel($object); + } + + public function save($object, $options, $current_user) + { + if (!$this->hasAccess($options, $current_user)) { + return false; + } + + if (isset($object["app_id"]) && $object["app_id"]) { + + $object["front_id"] = $object["group_id"] . "_app_" . $object["app_id"] . "_" . $current_user->getId(); + + $members = [$current_user->getId()]; + + if (isset($object["group_id"])) { + $app_bot_identifier = $object["group_id"] . "_app_" . $object["app_id"]; + } else if (isset($object["app_bot_identifier"])) { + $app_bot_identifier = $object["app_bot_identifi er"]; + } else { + return false; + } + $direct_identifier = $app_bot_identifier . "+" . $current_user->getId(); + + } else { + + $members = []; + foreach ($object["members"] as $member) { + if (strlen($member) > 0) { + $members[] = $member; + } + } + $members = array_unique($members); + sort($members); + $direct_identifier = join("+", $members); + + } + + + //No members in direct messages + if (!$direct_identifier) { + return false; + } + + $did_create = false; + if (!isset($object["id"])) { + //Search if channel exists for this group of users + $channel = $this->entity_manager->getRepository("Twake\Channels:Channel")->findOneBy(Array("identifier" => $direct_identifier)); + if (!$channel) { + $did_create = true; + $channel = new \Twake\Channels\Entity\Channel(); + $channel->setDirect(true); + $channel->setFrontId($object["front_id"]); + + if (isset($object["app_id"])) { + $channel->setAppId($object["app_id"]); + $channel->setAppBotIdentifier($app_bot_identifier); + $channel->setAppGroupId($object["group_id"]); + } + } + } else { + $channel = $this->entity_manager->getRepository("Twake\Channels:Channel")->find(Array("id" => $object["id"], "direct" => $object["direct"], "original_workspace_id" => $object["original_workspace"] ? $object["original_workspace"] : "")); + if (!$channel) { + return false; + } + } + + //Not a direct channel + if (!($channel->getDirect() && !$channel->getPrivate())) { + return false; + } + + //Modifiy $channel + $channel->setIdentifier($direct_identifier); + + if (!isset($object["app_id"])) { + $channel->setMembersCount(count($members)); + } + + $this->entity_manager->persist($channel); + $this->entity_manager->flush($channel); + + if ($did_create) { + //Init channel with a first message + $init_message = Array( + "channel_id" => $channel->getId(), + "hidden_data" => Array("type" => "init_channel"), + "content" => "[]" + ); + $this->messages_service->save($init_message, Array()); + } + + $this->updateChannelMembers($channel, $members, $current_user->getId()); + + + return $channel->getAsArray(); + } + +} diff --git a/twake/backend/core/src/Twake/Core/Bundle.php b/twake/backend/core/src/Twake/Core/Bundle.php new file mode 100755 index 00000000..d0880caa --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Bundle.php @@ -0,0 +1,33 @@ +routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Command/ExportCommand.php b/twake/backend/core/src/Twake/Core/Command/ExportCommand.php new file mode 100755 index 00000000..18da4a7d --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Command/ExportCommand.php @@ -0,0 +1,385 @@ + Array(), 'notall' => Array()); + + protected function configure() + { + $this + ->setName("twake:export_group") + ->setDescription("Command to export a group from Twake") + ->addArgument('name', InputArgument::REQUIRED, 'What group do you want to export?'); + } + + protected function execute() + { + + + $services = $this->getApp()->getServices(); + $doctrine = $this->getApp()->getServices()->get('doctrine'); + $manager = $doctrine->getManager(); + $group_name = $input->getArgument('name'); + $export_user = true; + +// ================================================================================================================================================= +// ================================================================================================================================================= + + //PARTIE CONCERNANT LE GROUP + $upper_path = getcwd(); + + $group = $manager->getRepository("Twake\Workspaces:Group")->findOneBy(Array("name" => $group_name)); + $group_id = $group->getId(); + + //ON CREER LES DIFFERENTS DOSSIER A LA RACINE DU DOSSIER D EXPORTATION + mkdir("Export_Folder"); + chdir("Export_Folder"); + mkdir($group_id . ""); + chdir($group_id . ""); + chmod(getcwd(), 0777); + mkdir("workspaces"); + $workspaces = $group->getWorkspaces(); + + //ON RECUPERE LES DONNEES DU GROUPE + $group_admin = $group->getManagers(); + + $group_members_file = "group_members.json"; + $handle_group_members = fopen($group_members_file, 'w') or die('Cannot open file: ' . $group_members_file); + $group_members = Array(); + foreach ($group_admin as $ga) { + $group_members[] = Array( + "user_id" => $ga->getUser()->getId(), + "level" => $ga->getLevel(), + "externe" => $ga->getExterne() + ); + } + fwrite($handle_group_members, json_encode($group_members, JSON_PRETTY_PRINT)); + fclose($handle_group_members); + $url = $group->getLogo(); + $group = $group->getAsArray(); + if ($group["logo"] != "") { + if (strpos($group["logo"], "://")) { + $group["logo"]; + } else { + $path = $upper_path . $group["logo"]; + } + $type = pathinfo($path, PATHINFO_EXTENSION); + $data = file_get_contents($path); + + $logo64 = Array( + "logo_type" => $type, + "base64_data" => base64_encode($data), + "url" => $url + ); + } else { + $logo64 = ""; + } + + $data = Array( + "name" => $group["unique_name"], + "display_name" => $group["name"], + "logo" => json_encode($logo64, JSON_PRETTY_PRINT) + ); + + //ON MET LES INFO DU GROUP DANS LE FICHIER GROUP.JSON + $group_file = "group.json"; + $handle_group_file = fopen($group_file, 'w') or die('Cannot open file: ' . $group_file); + fwrite($handle_group_file, json_encode($data, JSON_PRETTY_PRINT)); + fclose($handle_group_file); + +// ================================================================================================================================================= +// ================================================================================================================================================= + + //on regarde les user qu'on va devoir creer + if ($export_user) { + mkdir("users"); + chdir("users"); + foreach ($group_admin as $ga) { + if (!$ga->getUser()->getIsRobot()) { + $user = $ga->getUser(); + $url = $user->getThumbnail()->getName(); + $user_array = $user->getAsArray(); + //si le membre du workspace n'est pas rΓ©fΓ©rencΓ© comme user on doit le crΓ©er + $path = ""; + $data = ""; + $type = ""; + if ($user_array["thumbnail"] != "") { + if (strpos($user_array["thumbnail"], "://")) { + $path = $user_array["thumbnail"]; + } else { + $path = $upper_path . $user_array["thumbnail"]; + } + $type = pathinfo($path, PATHINFO_EXTENSION); + $data = file_get_contents($path); + + $logo64 = Array( + "logo_type" => $type, + "base64_data" => base64_encode($data), + "url" => $url + ); + } else { + $logo64 = ""; + } + + $mails = $manager->getRepository("Twake\Users:Mail")->findBy(Array("user_id" => $user_array["id"])); + $secondarymail = Array(); + foreach ($mails as $mail) { + $secondarymail[] = $mail->getMail(); + } + if (($key = array_search($user->getemailCanonical(), $secondarymail)) !== false) { + unset($secondarymail[$key]); + } + + $users = Array( + "firstname" => $user_array["firstname"], + "lastname" => $user_array["lastname"], + "language" => $user_array["language"], + "username" => $user_array["username"], + "emailcanonical" => $user->getemailCanonical(), + "logo" => json_encode($logo64, JSON_PRETTY_PRINT), + "password" => $user->getPassword(), + "salt" => $user->getSalt(), + "secondary_email" => $secondarymail, + ); + $user_file = "user_" . $user_array["id"] . ".json"; + $handle_user = fopen($user_file, 'w') or die('Cannot open file: ' . $user_file); + fwrite($handle_user, json_encode($users, JSON_PRETTY_PRINT)); + fclose($handle_user); + } + } + chdir(".."); + } + +// ================================================================================================================================================= +// ================================================================================================================================================= + + + chdir("workspaces"); + foreach ($workspaces as $wp) { + //ON CREE LE DOSSIER POUR LE WORKSPACE EN QUESTION ET ON MET LES DONNES DANS UN FICHIER WORKSPACE.JSON + mkdir("ws_" . $wp->getId() . ""); + $workspace_file = "workspace.json"; + $handle_workspace_file = fopen($workspace_file, 'w') or die('Cannot open file: ' . $workspace_file); + $workspaces_user = $wp->getMembers(); + $url = $wp->getLogo()->getName(); + $wp = $wp->getAsArray(); + $path = ""; + $data = ""; + $type = ""; + if ($wp["logo"] != "") { + if (strpos($wp["logo"], "://")) { + $path = $wp["logo"]; + } else { + $path = $upper_path . $wp["logo"]; + } + $type = pathinfo($path, PATHINFO_EXTENSION); + $data = file_get_contents($path); + $logo64 = Array( + "logo_type" => $type, + "base64_data" => base64_encode($data), + "url" => $url + ); + } else { + $logo64 = ""; + } + + $data_ws = Array( + "name" => $wp["name"], + "uniquename" => $wp["uniqueName"], + "color" => $wp["color"], + "logo" => json_encode($logo64, JSON_PRETTY_PRINT) + ); + fwrite($handle_workspace_file, json_encode($data_ws, JSON_PRETTY_PRINT)); + fclose($handle_workspace_file); + rename('workspace.json', "ws_" . $wp["id"] . "" . DIRECTORY_SEPARATOR . "workspace.json"); + +// ================================================================================================================================================= +// ================================================================================================================================================= + + //PARTIE SUR LES MEMBRES D UN WORKSPACE DANS LE FICHIER MEMBERS.JSON + $members = Array(); + foreach ($workspaces_user as $wp_user) { + //on cree la liste des membres du workspace + if (!$wp_user->getUser($this->doctrine)->getIsRobot()) { + $members[] = Array( + "user_id" => $wp_user->getUser($this->doctrine)->getId(), + "level" => $wp_user->getLevelId(), + "externe" => $wp_user->getExterne() + ); + } + } + + //ON ECRIT LES MEMBRES DU WORKSPACE DANS LE FICHIER ET ON DEPLACE LE FICHIER + $workspace_members_file = "members.json"; + $handle_workspace_members = fopen($workspace_members_file, 'w') or die('Cannot open file: ' . $workspace_members_file); + fwrite($handle_workspace_members, json_encode($members, JSON_PRETTY_PRINT)); + fclose($handle_workspace_members); + rename('members.json', "ws_" . $wp["id"] . "" . DIRECTORY_SEPARATOR . "members.json"); + +// ================================================================================================================================================= +// ================================================================================================================================================= + + //PARTIE SUR LES CHANNELS ET LES MESSAGES D UN WORKSPACE DANS LES SOUS DOSSIER CHANNEL ET MESSAGE + $channels = $$manager->getRepository("Twake\Channels:Channel")->findBy(Array("direct" => false, "original_workspace_id" => $wp["id"])); + chdir("ws_" . $wp["id"] . ""); + mkdir("channels"); + chdir("channels"); + foreach ($channels as $channel) { + //ON RECUPERE LES INFORMATIONS DU CHANNEL + $channel = $channel->getAsArray(); + if ($channel["name"] != "") { + if (!file_exists($channel["name"])) { + mkdir(str_replace("/", "_", $channel["name"])); + chdir(str_replace("/", "_", $channel["name"])); + $channel_file = "channel.json"; + $handle_channel_file = fopen($channel_file, 'w') or die('Cannot open file: ' . $channel_file); + + $data_ch = Array( + "name" => $channel["name"], + "description" => $channel["description"], + "members" => $channel["members"], + "ext_members" => $channel["ext_members"], + ); + fwrite($handle_channel_file, json_encode($data_ch, JSON_PRETTY_PRINT)); + fclose($handle_channel_file); + + //ON RECUPERE LES MESSAGES DU CHANNEL + $messages_tmp = $this->doctrine->getRepository("Twake\Discussion:Message")->findBy(Array("channel_id" => $channel["id"])); + $messages = Array(); + foreach ($messages_tmp as $message) { + + //ON RECUPERE LES INFORMATIONS DU MESSAGE + $message = $message->getAsArray(); + + $message_file = "messages.json"; + $handle_message_file = fopen($message_file, 'w') or die('Cannot open file: ' . $message_file); + $messages[] = Array( + "parent_message_id" => $message["parent_message_id"], + "reactions" => $message["reactions"], + "content" => $message["content"], + "hidden_data" => $message["hidden_data"], + "message_type" => $message["message_type"], + "sender" => $message["sender"], + "creation_date" => $message["creation_date"] + ); + } + fwrite($handle_message_file, json_encode($messages, JSON_PRETTY_PRINT)); + fclose($handle_message_file); + chdir(".."); //on remonte dans channels + } + } + } + + +// ================================================================================================================================================= +// ================================================================================================================================================= + + //PARTIE SUR LES DRIVE FILES ET LES CALENDARS + chdir(".."); + mkdir("calendars"); + chdir("calendars"); + $calendars = $manager->getRepository("Twake\Calendar:Calendar")->findBy(Array("workspace_id" => $wp["id"])); + $calendar = Array(); + foreach ($calendars as $c) { + $c = $c->getAsArray(); + $calendar_file = "calendar_" . $c["id"] . ".json"; + $handle_calendar_file = fopen($calendar_file, 'w') or die('Cannot open file: ' . $calendar_file); + $events = Array(); + $eventcalendar = $manager->getRepository("Twake\Calendar:EventCalendar")->findBy(Array("calendar_id" => $c["id"])); + foreach ($eventcalendar as $ec) { + $event = $manager->getRepository("Twake\Calendar:Event")->findOneBy(Array("id" => $ec->getEventId())); + $events[] = Array( + "date" => $ec->getSortDate(), + "event" => Array( + "from" => $event->getFrom(), + "to" => $event->getTo(), + "all_day" => $event->getAllDay(), + "type" => $event->getType(), + "title" => $event->getTitle(), + "description" => $event->getDescription(), + "location" => $event->getLocation(), + "private" => $event->getPrivate(), + "available" => $event->getAvailable(), + "owner" => $event->getOwner()(), + "participants" => $event->getParticipants(), + "notification" => $event->getNotifications(), + ) + ); + $calendar[] = Array( + "color" => $c["color"], + "title" => $c["title"], + "auto_participant" => $c["auto_participant"], + "connectors" => $c["connectors"], + "events" => $events + ); + fwrite($handle_calendar_file, json_encode($calendar, JSON_PRETTY_PRINT)); + fclose($handle_calendar_file); + } + } + + chdir(".."); + mkdir("drive_files"); + chdir("drive_files"); + $files = $manager->getRepository("Twake\Drive:DriveFile")->findBy(Array("workspace_id" => $wp["id"])); + foreach ($files as $file) { + $path = $file->getPath(); + $version_array = Array(); + $file = $file->getAsArray(); + $version = $manager->getRepository("Twake\Drive:DriveFileVersion")->findBy(Array("file_id" => $file["id"])); + foreach ($version as $v) { + $v = $v->getAsArray(); + //ar_dump("file id in version: " . $file["id"]); + $version_array[] = Array( + "creator" => $v["creator"], + "name" => $v["name"], + "date_added" => $v["added"], + "data" => json_encode($v["data"], JSON_PRETTY_PRINT), + ); + + } + $drive_file = "drive_" . $file["id"] . ".json"; + + $handle_drive_file = fopen($drive_file, 'w') or die('Cannot open file: ' . $drive_file); + $drivefile = Array( + "parent_id" => $file["parent_id"], + "detached" => $file["detached"], + "trash" => $file["trash"], + "is_directory" => $file["is_directory"], + "name" => $file["name"], + "description" => $file["description"], + "size" => $file["size"], + "extension" => $file["extension"], + "acces_info" => $file["acces_info"], + "url" => $file["url"], + "path" => $path, + "version" => $version_array + ); + fwrite($handle_drive_file, json_encode($drivefile, JSON_PRETTY_PRINT)); + fclose($handle_drive_file); + } + chdir("../.."); // on remonte dans le workspace en cours de construction + } + +// ================================================================================================================================================= +// ================================================================================================================================================= + + // ON CREE LE FICHIER CONTENANT TOUS LES USER EN DETAIL ET UN QUI REFERENCE CEUX DU GROUP +// chdir(".."); + + } +} diff --git a/twake/backend/core/src/Twake/Core/Command/GetRoutesCommand.php b/twake/backend/core/src/Twake/Core/Command/GetRoutesCommand.php new file mode 100755 index 00000000..9d047ee0 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Command/GetRoutesCommand.php @@ -0,0 +1,33 @@ +setName("twake:routes"); + } + + + protected function execute() + { + foreach ($this->app->getRouting()->getRoutes() as $route) { + error_log($route); + } + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Command/ImportCommand.php b/twake/backend/core/src/Twake/Core/Command/ImportCommand.php new file mode 100755 index 00000000..9f057cb3 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Command/ImportCommand.php @@ -0,0 +1,926 @@ + Array(), 'notall' => Array()); + + public static function cmpMessage($a, $b) + { + return $a["creation_date"] - $b["creation_date"]; + } + + protected function configure() + { + $this + ->setName("twake:import_group") + ->setDescription("Command to import a group from old Twake"); + //->addArgument('tarname', InputArgument::REQUIRED, 'Which tar do you want to import'); + } + + protected function execute() + { + +// ================================================================================================================================================= +// ================================================================================================================================================= + + error_log("========================================================================================"); + error_log("========================================================================================"); + error_log("\n"); + error_log("DO NO STOP THIS PROCESS IT COULD TAKE A REALLY LONG TIME !!"); + error_log("\n"); + error_log("========================================================================================"); + error_log("========================================================================================"); + + + $services = $this->getApp()->getServices(); + $manager = $services->get('app.twake_doctrine'); + //$group_name = $input->getArgument('tarname'); + $export_user = true; + chdir('web'); + chmod(getcwd(), 0777); + mkdir("Export"); + $phar = new \PharData('Export.tar'); + $phar->extractTo('Export'); + chdir("Export"); + chdir("Export"); + + $dir = '.'; + + $this->match_file = Array(); + $this->match_table = Array( + "user" => Array(), + "message" => Array(), + "message_bdd" => Array() + ); + + $dh = opendir($dir); + $roor_tar = getcwd(); + + + while (false !== ($filename = readdir($dh))) { + if ($filename[0] == ".") { + continue; + } + + chdir($roor_tar); + + error_log("\n\n -------- NEW GROUP --------\n" . $filename . "\n"); + if (is_dir($filename)) { + chdir($filename); + + //Import this group + $this->importGroup(); + + } else { + error_log(getcwd()); + error_log("error reading folder " . $filename); + } + + } + chdir($roor_tar); + + + error_log("\n\n -------- PRIVATE CHANS --------\n"); + + $dh = opendir($dir); + while (false !== ($filename = readdir($dh))) { + if ($filename[0] == ".") { + continue; + } + chdir($filename); + + //Import this group + $this->importGroupPrivateChannels(); + + chdir(".."); + + } + + } + + private function importGroup() + { + + $services = $this->getApp()->getServices(); + $manager = $services->get('app.twake_doctrine'); + +// ================================================================================================================================================= +// ================================================================================================================================================= + + //PARTIE CONCERNANT LE GROUPE + $group_file = "group.json"; + if (filesize($group_file) > 0) { + $handle_group = fopen($group_file, 'r') or die('Cannot open file: ' . $group_file); + $group_members = Array(); + $contents = json_decode(fread($handle_group, filesize($group_file)), true); + fclose($handle_group); + + $group = $manager->getRepository("Twake\Workspaces:Group")->findOneBy(Array("name" => $contents["name"] . "_itw")); + + if (!$group) { + + $group = new Group($contents["name"] . "_itw"); + $group->setDisplayName($contents["display_name"]); + + $logo = $contents["logo"]; + if ($logo !== '') { + $group->setLogo($contents["logo"]); + } + + $manager->persist($group); + $manager->flush(); + + } + + $group_id = $group->getId(); + + } + + $appRepository = $manager->getRepository("Twake\Market:Application"); + $list_default_apps = $appRepository->findBy(Array("is_default" => true)); + $groupapp_apps = []; + foreach ($list_default_apps as $app) { + $groupapp = new GroupApp($group, $app->getId()); + $groupapp->setWorkspaceDefault(true); + $manager->persist($groupapp); + + $groupapp_apps[] = $groupapp; + } + $manager->flush(); + +// ================================================================================================================================================= +// ================================================================================================================================================= + + //CREATION DES COMPTES UTILISATEURS QU IL FAUT CREER AVANT DE LES AJOUTER A L ENTREPRISE + + chdir('users'); + $user_file = "users.json"; + $handle_user = fopen($user_file, 'r') or die('Cannot open file: ' . $user_file); + $contents = json_decode(fread($handle_user, filesize($user_file)), true); + foreach ($contents as $user) { + $old_id = $user["id"]; + $mail = strtolower(trim($user["emailcanonical"])); + $username = trim($user["username"]); + + // on regarde si le compte du user existe dΓ©jΓ  avec son mail + $new_user = $manager->getRepository("Twake\Users:User")->findOneBy(Array("emailcanonical" => $mail)); + if (!$new_user) { + $other_new_users_mails = $manager->getRepository("Twake\Users:Mail")->findOneBy(Array("mail" => $mail)); + if ($other_new_users_mails) { + $new_user = $other_new_users_mails->getUser(); + } + } + if (!$new_user) { + $new_user = $manager->getRepository("Twake\Users:User")->findOneBy(Array("usernamecanonical" => $username)); + } + + if (!isset($new_user)) { + //si le compte de n'existe pas on ne le crΓ©e pas a nouveau + $new_user = new User(); + $new_user->setFirstName($user["firstname"]); + $new_user->setLastName($user["lastname"]); + $new_user->setLanguage($user["language"]); + $new_user->setUsername($user["username"]); + $new_user->setPassword($user["password"]); + $new_user->setemailCanonical($mail); + $new_user->setSalt($user["salt"]); + $new_user->setNotificationPreference($user["notification_preference"]); + $logo = $user["logo"]; + if ($logo !== '') { + $logo = new File(); + $logo->setPublicLink($user["logo"]); + $manager->persist($logo); + $manager->flush(); + $new_user->setThumbnail($logo); + } + $manager->persist($new_user); + + //creation des emails secondaire + foreach ($user["secondary_email"] as $mail) { + $mail_to_find = $manager->getRepository("Twake\Users:Mail")->findOneBy(Array("mail" => $mail)); + if (!isset($mail_to_find)) { + $mail_bdd = new Mail(); + $mail_bdd->setMail($mail); + $mail_bdd->setUserId($new_user->getId()); + $manager->persist($mail_bdd); + } + } + $manager->flush(); + } + $this->match_table["user"][$old_id] = $new_user->getId() . ""; + } + fclose($handle_user); + +// chdir(".."); +// return; + +// ================================================================================================================================================= +// ================================================================================================================================================= + + //AJOUT DES MEMBRES DU GROUP DANS LE GROUP AVEC LE LEVEL ET LE IS EXTERNE + + chdir('..'); + $group_members_file = "group_members.json"; + if (filesize($group_members_file) > 0) { + $handle_group_members = fopen($group_members_file, 'r') or die('Cannot open file: ' . $group_members_file); + $group_members = Array(); + $contents = json_decode(fread($handle_group_members, filesize($group_members_file)), true); + if (isset($contents)) { + foreach ($contents as $user) { + if (array_key_exists($user["user_id"], $this->match_table["user"])) { + $new_id = $this->match_table["user"][$user["user_id"]]; + $user_bdd = $manager->getRepository("Twake\Users:User")->findOneBy(Array("id" => $new_id)); + $groupuser = new GroupUser($group, $user_bdd); + $groupuser->setExterne($user["externe"]); + $groupuser->setLevel($user["level"]); + $manager->persist($groupuser); + $manager->flush(); + } + } + } + fclose($handle_group_members); + } + + // PARTIE SUR LA CREATION DES WORKSPACES ET DES WORKSPACES MEMBERS + if (file_exists("workspaces")) { + chdir("workspaces"); + $allworkspace = scandir("./"); + $workspaces = array_values(array_diff($allworkspace, array('.', '..'))); + foreach ($workspaces as $workspace) { + + if ($workspace[0] == ".") { + continue; + } + + chdir($workspace); + $workspace_file = "workspace.json"; + if (filesize($workspace_file) > 0) { + $handle_workspace_file = fopen($workspace_file, 'r') or die('Cannot open file: ' . $workspace_file); + $contents = json_decode(fread($handle_workspace_file, filesize($workspace_file)), true); + if (isset($contents)) { + $old_wp_id = $contents["id"]; + error_log(print_r("DEBUT WP : " . $contents["name"] . " ID : " . $old_wp_id)); + $workspace_bdd = new Workspace($contents["name"]); + $workspace_bdd->setUniqueName($contents["uniquename"]); + $workspace_bdd->setColor($contents["color"]); + $logo = $contents["logo"]; + if ($logo !== '') { + $workspace_bdd->setLogo($contents["logo"]); + } + $workspace_bdd->setGroup($group->getId()); + $manager->persist($workspace_bdd); + $workspace_id = $workspace_bdd->getId(); + $manager->flush(); + } + } + + $workspace_members_file = "members.json"; + if (filesize($workspace_members_file) > 0) { + + $handle_workspace_members = fopen($workspace_members_file, 'r') or die('Cannot open file: ' . $workspace_members_file); + $contents = json_decode(fread($handle_workspace_members, filesize($workspace_members_file)), true); + $level_admin_bdd = new WorkspaceLevel(); + $level_admin_bdd->setIsAdmin(true); + $level_admin_bdd->setWorkspace($workspace_bdd->getId()); + $level_admin_bdd->setLabel("Administrator"); + $manager->persist($level_admin_bdd); + $manager->flush(); + $level_admin_id = $level_admin_bdd->getId(); + + $level_none_bdd = new WorkspaceLevel(); + $level_none_bdd->setWorkspace($workspace_bdd->getId()); + $level_none_bdd->setLabel("Basic user"); + $manager->persist($level_none_bdd); + $manager->flush(); + $level_none_id = $level_none_bdd->getId(); + + if (isset($contents)) { + foreach ($contents as $user) { + if (array_key_exists($user["user_id"], $this->match_table["user"])) { + $new_id = $this->match_table["user"][$user["user_id"]]; + $user_bdd = $manager->getRepository("Twake\Users:User")->findOneBy(Array("id" => $new_id)); + $workspaceuser = new WorkspaceUser($workspace_bdd, $user_bdd, $level_none_id); + if ($user["admin"]) { + $workspaceuser->setLevelId($level_admin_id); + } + $manager->persist($workspaceuser); + } + } + $workspace_bdd->setMemberCount(count($contents)); + $manager->persist($workspace_bdd); + $manager->flush(); + } + } + + + foreach ($groupapp_apps as $groupapp_app) { + $services->get("app.workspaces_apps")->enableApp($workspace_id, $groupapp_app->getAppId()); + } + +// ================================================================================================================================================= +// ================================================================================================================================================= + error_log(">DRIVE"); + //PARTIE SUR LA CREATION DE TOUT LES DRIVE FILES + if (file_exists("drive_files")) { + + $root_directory = $manager->getRepository("Twake\Drive:DriveFile") + ->findOneBy(Array("workspace_id" => $workspace_id . "", "isintrash" => false, "parent_id" => "")); + if (!$root_directory) { + $root_directory = new DriveFile($workspace_id . "", "", true); + $manager->persist($root_directory); + $manager->flush(); + } + + chdir("drive_files"); + $file = "drive_file.json"; + $handle_drive_file = fopen($file, 'r') or die('Cannot open file: ' . $file); + if (filesize($file) > 0) { + $contents = json_decode(fread($handle_drive_file, filesize($file)), true); + if (isset($contents) && $contents != Array()) { + + $all_files_to_sort = $contents; + $all_files_sorted = []; + $known_parents = []; + $i_while = 0; + while (count($all_files_to_sort) > 0 && $i_while < 1000) { + $next_all_files_to_sort = Array(); + foreach ($all_files_to_sort as $file) { + if ($file["parent_id"] > 0) { + if (in_array($file["parent_id"], $known_parents)) { + $all_files_sorted[] = $file; + $known_parents[] = $file["id"]; + } else { + $next_all_files_to_sort[] = $file; + } + } else { + $all_files_sorted[] = $file; + $known_parents[] = $file["id"]; + } + } + $all_files_to_sort = $next_all_files_to_sort; + $i_while++; + } + + + foreach ($all_files_sorted as $file) { + error_log(print_r("NEW DRIVE FILE : " . $file["name"] . " ID : " . $file["id"], true)); + + $drive_file_bdd = new DriveFile($workspace_id . "", "", $file["is_directory"]); + $drive_file_bdd->setDetachedFile($file["detached"]); + //$drive_file_bdd->setIsInTrash($file["trash"]); + $drive_file_bdd->setName($file["name"]); + $drive_file_bdd->setDescription($file["description"]); + $drive_file_bdd->setPreviewLink("https://s3.eu-west-3.amazonaws.com/twake.eu-west-3/public/uploads/previews/" . $file["path"] . ".png"); + $drive_file_bdd->setPreviewHasBeenGenerated(true); + $drive_file_bdd->setHasPreview(true); + $drive_file_bdd->setSize($file["size"]); + $drive_file_bdd->setExtension($file["extension"]); + $drive_file_bdd->setWorkspaceId($workspace_id . ""); + //$drive_file_bdd->setAccesInfo($file["acces_info"]); + $drive_file_bdd->setUrl($file["url"]); + + if ($file["parent_id"] != 0 && array_key_exists($file["parent_id"], $this->match_file)) { + $drive_file_bdd->setParentId($this->match_file[$file["parent_id"]] . ""); + } else { + $drive_file_bdd->setParentId($root_directory->getId() . ""); + } + $manager->persist($drive_file_bdd); + + error_log($drive_file_bdd->getId()); + $this->match_file[$file["id"]] = $drive_file_bdd->getId(); + + $manager->flush(); + + if ($file["version"] != Array() && !$file["is_directory"]) { + $version_bdd = new DriveFileVersion($drive_file_bdd, $file["version"][0]["creator"] ? $file["version"][0]["creator"]["id"] : ""); + $version_bdd->setFileName($file["version"][0]["name"]); + $version_bdd->setDateAdded(new \DateTime("@" . intval($file["version"][0]["date_added"]))); + + $version_bdd->setKey($file["key"]); + $version_bdd->setMode($file["mode"]); + + $manager->persist($version_bdd); + $manager->flush(); + $drive_file_bdd->setLastVersionId($version_bdd->getId()); + $manager->persist($drive_file_bdd); + $manager->flush(); + } + } + } + fclose($handle_drive_file); + } + chdir(".."); + } + +// ================================================================================================================================================= +// ================================================================================================================================================= + error_log(">CHANNELS"); + // PARTIE SUR LA CREATION DE TOUT LES CHANNELS + if (file_exists("channels")) { + chdir("channels"); + $allchannel = scandir("./"); + $channels = array_values(array_diff($allchannel, array('.', '..'))); + + foreach ($channels as $channel) { + + if ($channel[0] == ".") { + continue; + } + + $this->match_table["message"] = Array(); + + $name = $channel; + chdir($channel); + $channel_bdd = new Channel(); + + $name = explode(":", $name); + + if (count($name) > 1) { + $channel_bdd->setName($name[1]); + if (trim($name[0])) { + $channel_bdd->setChannelGroupName($name[0]); + } + } else { + $channel_bdd->setName($name[0]); + } + $name = join($name); + + if (strpos(strtolower($channel_bdd->getName()), "general") !== false || strpos(strtolower($channel_bdd->getName()), "gΓ©nΓ©ral") !== false) { + $channel_bdd->setIcon(":mailbox:"); + } else if (strpos(strtolower($channel_bdd->getName()), "random") !== false || strpos(strtolower($channel_bdd->getName()), "divers") !== false) { + $channel_bdd->setIcon(":beach_umbrella:"); + } else { + $channel_bdd->setIcon(":small_blue_diamond:"); + } + + $channel_file = "channel.json"; + $handle_channel_file = fopen($channel_file, 'r') or die('Cannot open file: ' . $channel_file); + if (filesize($channel_file) > 0) { + $contents = json_decode(fread($handle_channel_file, filesize($channel_file)), true); + if (isset($contents)) { + error_log(print_r("NEW CHANNEL : " . $name . " ID : " . $contents["id"], true)); + $channel_bdd->setPrivate($contents["is_private"]); + $channel_bdd->setDirect(false); + $channel_bdd->setDescription($contents["description"]); + $channel_bdd->setOriginalWorkspaceId($workspace_id); + $channel_bdd->setOriginalGroupId($group->getId()); + $member_list = Array(); + foreach ($contents["members"] as $channel_member) { + if (array_key_exists($channel_member["id"], $this->match_table["user"])) { + array_push($member_list, $this->match_table["user"][$channel_member["id"]]); + } + } + $channel_bdd->setMembers($member_list); + } + fclose($handle_channel_file); + $manager->persist($channel_bdd); + $manager->flush(); + + $channel_bdd_id = $channel_bdd->getId(); + + + foreach ($member_list as $id) { + $ch_member = new ChannelMember($id . "", $channel_bdd); + $manager->persist($ch_member); + } + $manager->flush(); + + } + + $message_file = "messages.json"; + $handle_message_file = fopen($message_file, 'r') or die('Cannot open file: ' . $message_file); + + $contents = json_decode(fread($handle_message_file, filesize($message_file)), true); + if (isset($contents) && $contents != Array()) { + usort($contents, "self::cmpMessage"); + $no_parent_yet = Array(); + + $messages_to_sort = $contents; + $messages = []; + $known_parents = []; + $i_while = 0; + while (count($messages_to_sort) > 0 && $i_while < 1000) { + $next_messages_to_sort = Array(); + foreach ($messages_to_sort as $message) { + if ($message["parent_message_id"] > 0) { + if (in_array($message["parent_message_id"], $known_parents)) { + $messages[] = $message; + $known_parents[] = $message["id"]; + } else { + $next_messages_to_sort[] = $message; + } + } else { + $messages[] = $message; + $known_parents[] = $message["id"]; + } + } + $messages_to_sort = $next_messages_to_sort; + $i_while++; + } + + foreach ($messages as $message) { + + if (!$message["creation_date"]) { + continue; + } + + $message_bdd = new Message($channel_bdd_id, ""); + $manager->persist($message_bdd); + $message_bdd->setContent(Array("type" => "compile", "content" => $message["content"])); + $res = $this->setMessageContent($message_bdd, $message); + + if (!$res) { + continue; + } + + $this->match_table["message"][$message["id"]] = $message_bdd->getId() . ""; + $this->match_table["message_bdd"][$message["id"]] = $message_bdd; + + if ($message["parent_message_id"] != null) { + if (array_key_exists($message["parent_message_id"], $this->match_table["message"])) { + error_log("add message to parent " . $this->match_table["message"][$message["parent_message_id"]]); + $message_bdd->setParentMessageId($this->match_table["message"][$message["parent_message_id"]]); + + $parent = $this->match_table["message_bdd"][$message["parent_message_id"]]; + $parent->setResponsesCount($parent->getResponsesCount() + 1); + + } else { + // le parent n'existe pas encore on doit creer le message plus tard + $no_parent_yet[$message_bdd->getId() . ""] = Array( + "bdd" => $message_bdd, + "pid" => $message["parent_message_id"] + ); + } + } + if ($message["sender"] != null) { + if (array_key_exists($message["sender"], $this->match_table["user"])) { + $user = $manager->getRepository("Twake\Users:User")->findOneBy(Array("id" => $this->match_table["user"][$message["sender"]])); + $message_bdd->setSender($user); + } + } + $message_bdd->setCreationDate(new DateTime("@" . intval($message["creation_date"] / 1000))); + + $manager->persist($message_bdd); + } + foreach ($no_parent_yet as $key => $message) { + error_log("add message to parent (after) " . $this->match_table["message"][$message["pid"]]); + + $message["bdd"]->setParentMessageId($this->match_table["message"][$message["pid"]]); + $manager->persist($message["bdd"]); + } + } + $manager->flush(); + chdir("..");//on sort du channel en question + + } + chdir(".."); //on sort des channels + } + +// ================================================================================================================================================= +// ================================================================================================================================================= + error_log(">CALENDAR"); + // PARTIE SUR LA CREATION DE TOUT DES CALENDARS + if (file_exists("calendars")) { + chdir("calendars"); + $allcalendar = scandir("./"); + $calendars = array_values(array_diff($allcalendar, array('.', '..'))); + foreach ($calendars as $calendar) { + + if ($calendar[0] == ".") { + continue; + } + + $handle_calendar_file = fopen($calendar, 'r') or die('Cannot open file: ' . $calendar); + if (filesize($calendar) > 0) { + $contents = json_decode(fread($handle_calendar_file, filesize($calendar)), true); + error_log(print_r("NEW CALENDAR : " . $contents[0]["title"] . " ID : " . $contents[0]["id"], true)); + + $color = $contents[0]["color"]; + if ($color[0] != "#") { + $color = "#444444"; + } + + $calendar_bdd = new Calendar($workspace_id, $contents[0]["title"], $color); + if (isset($contents[0]["auto_participant"]) && $contents[0]["auto_participant"] != Array()) { + $participants = Array(); + foreach ($contents[0]["auto_participant"] as $p) { + $participants[] = $this->match_table["user"][$p]; + } + $calendar_bdd->setAutoParticipants($participants); + } + + $manager->persist($calendar_bdd); + $manager->flush(); + $calendar_id = $calendar_bdd->getId(); + //TODO CREER LES EVENTS AVEC LES BONNES INFO ET LES EVENT CALENDAR POUR LIER LES DEUX + + $events = $contents[0]["events"]; + if (isset($events)) { + foreach ($events as $event) { + + $title = ""; + if (isset($event["event"]["event"]["title"]) && is_string(($event["event"]["event"]["title"]))) { + $title = $event["event"]["event"]["title"]; + } + $event_bdd = new Event($title, $event["event"]["from"], $event["event"]["to"]); + + $event_bdd->setType("event"); + if (isset($event["event"]["event"])) { + $event_bdd->setAllDay($event["event"]["event"]["allDay"]); + $event_bdd->setDescription($event["event"]["event"]["description"]); + } + $manager->persist($event_bdd); + $event_id = $event_bdd->getId(); + + $manager->flush(); + + $services->get("app.calendar.event")->updateCalendars($event_bdd, Array(Array("calendar_id" => $calendar_id, "workspace_id" => $workspace_id)), true); + + $participants = Array(); + if (isset($event["event"]["participants"]) && is_array($event["event"]["participants"])) { + foreach ($event["event"]["participants"] as $p) { + if (is_int($p)) { + $participants[] = $this->match_table["user"][$p]; + } else { + $participants[] = $this->match_table["user"][$p["id"]]; + } + } + $services->get("app.calendar.event")->updateParticipants($event_bdd, $participants, true); + + $services->get("app.calendar.event")->updateNotifications($event_bdd, Array(Array("delay" => 30 * 60, "mode" => "")), true); + } + + $manager->flush(); + + } + } + } + } + chdir(".."); + } + +// ================================================================================================================================================= +// ================================================================================================================================================= + + error_log(">TASKS"); + // PARTIE SUR LA CREATION DES TACHES + if (file_exists("tasks")) { + chdir("tasks"); + $allboard = scandir("./"); + $boards = array_values(array_diff($allboard, array('.', '..'))); + foreach ($boards as $board) { + + if ($board[0] == ".") { + continue; + } + + $handle_board_file = fopen($board, 'r') or die('Cannot open file: ' . $board); + if (filesize($board) > 0) { + $contents = json_decode(fread($handle_board_file, filesize($board)), true); + error_log(print_r("NEW TASK : " . $contents["title"] . " ID : " . $contents["id"], true)); + if (isset($contents)) { + $board_bdd = new Board($workspace_id, str_replace(":", " ", $contents["title"])); + $board_bdd->setGroupName($group->getName()); + $manager->persist($board_bdd); + $manager->flush(); + $board_id = $board_bdd->getId(); + $lists = $contents["lists"]; + if (isset($contents["lists"]) && $contents["lists"] != Array()) { + foreach ($lists as $list) { + $board_list = new BoardList($board_id, $list["title"], $list["color"]); + $manager->persist($board_list); + $manager->flush(); + $list_id = $board_list->getId(); + $tasks = $list["tasks"]; + if (isset($list["tasks"]) && $list["tasks"] != Array()) { + foreach ($tasks as $task) { + $task_bdd = new Task($board_id, $list_id, $task["name"]); + $task_bdd->setDescription($task["description"]); + $task_bdd->setOrder($task["order"]); + $task_bdd->setOwner($this->match_table["user"][$task["user"]]); + $task_bdd->setCheckList($task["checklist"]); + if (isset($task["participant"]) && $task["participant"] != Array()) { + $participants = Array(); + foreach ($task["participant"] as $p) { + $participants[] = $this->match_table["user"][$p]; + } + $task_bdd->setParticipants($participants); + } + $manager->persist($task_bdd); + $manager->flush(); + } + } + } + } + } + fclose($handle_board_file); + } + } + chdir(".."); + } + chdir(".."); // on sort du workspace + } +// ================================================================================================================================================= +// ================================================================================================================================================= + + } + + chdir(".."); // on sort du workspace + } + + private function setMessageContent($m_bdd, $m_arr) + { + + if ($m_arr["is_application_message"] && $m_arr["hidden_data"] && $m_arr["hidden_data"]["file"]) { + $file_id = $m_arr["hidden_data"]["file"]; + if ($this->match_file[$file_id]) { + $m_bdd->setContent(Array( + Array( + "type" => "system", + "content" => "This message contain a file." + ), + Array( + "type" => "br" + ), + Array( + "type" => "file", + "content" => $this->match_file[$file_id] + ) + ) + ); + return true; + } + } + + if ($m_arr["is_application_message"] && $m_arr["hidden_data"] && $m_arr["hidden_data"]["iframe"]) { + $url = explode("giphy/view.php?url=", $m_arr["hidden_data"]["iframe"]); + if (count($url) == 2 && trim($url[1])) { + $m_bdd->setContent(Array( + Array("type" => "system", "content" => ["New GIF"]), + Array("type" => "br"), + Array( + "type" => "image", + "src" => urldecode($url[1]) + ) + )); + return true; + } + } + + if (trim($m_arr["content"]) == "") { + return false; + } + + return true; + + } + + + private function importGroupPrivateChannels() + { + $services = $this->getApp()->getServices(); + $manager = $services->get('app.twake_doctrine'); + + //PARTIE SUR LES CHANNEL PRIVES + + //chdir(".."); + if (file_exists("private_channel")) { + chdir("private_channel"); + $channel_file = "channel_private.json"; + $handle_channel_file = fopen($channel_file, 'r') or die('Cannot open file: ' . $channel_file); + if (filesize($channel_file) > 0) { + $contents = json_decode(fread($handle_channel_file, filesize($channel_file)), true); + if (isset($contents)) { + foreach ($contents as $channel) { + error_log(print_r("NEW PRIVATE CHANNEL : " . $channel["id"], true)); + $name = ""; + $member_list_id = Array(); + foreach ($channel["members"] as $channel_member) { + if (array_key_exists($channel_member["id"], $this->match_table["user"])) { + array_push($member_list_id, $this->match_table["user"][$channel_member["id"]]); + $name = $name . $channel_member["username"] . " "; + } + } + error_log(join(", ", $member_list_id)); + if (count($member_list_id) != 2) { + continue; + } + + $false_current_user = new User(); + $false_current_user->setId($member_list_id[0]); + + $res = $services->get("app.channels.direct_messages_system")->save(Array("members" => $member_list_id), Array(), $false_current_user); + $channel_bdd = $manager->getRepository("Twake\Channels:Channel")->findOneBy(Array("id" => $res["id"])); + $channel_bdd_id = $channel_bdd->getId(); + + usort($channel["message"], "self::cmpMessage"); + $no_parent_yet = Array(); + + $messages_to_sort = $channel["message"]; + $messages = []; + $known_parents = []; + $i_while = 0; + while (count($messages_to_sort) > 0 && $i_while < 1000) { + $next_messages_to_sort = Array(); + foreach ($messages_to_sort as $message) { + if ($message["parent_message_id"] > 0) { + if (in_array($message["parent_message_id"], $known_parents)) { + $messages[] = $message; + $known_parents[] = $message["id"]; + } else { + $next_messages_to_sort[] = $message; + } + } else { + $messages[] = $message; + $known_parents[] = $message["id"]; + } + } + $messages_to_sort = $next_messages_to_sort; + $i_while++; + } + + foreach ($messages as $message) { + + if (!$message["creation_date"]) { + continue; + } + + $message_bdd = new Message($channel_bdd_id, ""); + $manager->persist($message_bdd); + $message_bdd->setContent(Array("type" => "compile", "content" => $message["content"])); + $res = $this->setMessageContent($message_bdd, $message); + + if (!$res) { + continue; + } + + $this->match_table["message"][$message["id"]] = $message_bdd->getId() . ""; + $this->match_table["message_bdd"][$message["id"]] = $message_bdd; + + if ($message["parent_message_id"] != null) { + if (array_key_exists($message["parent_message_id"], $this->match_table["message"])) { + error_log("add message to parent " . $this->match_table["message"][$message["parent_message_id"]]); + $message_bdd->setParentMessageId($this->match_table["message"][$message["parent_message_id"]]); + $parent = $this->match_table["message_bdd"][$message["parent_message_id"]]; + $parent->setResponsesCount($parent->getResponsesCount() + 1); + } else { + // le parent n'existe pas encore on doit creer le message plus tard + $no_parent_yet[$message_bdd->getId() . ""] = Array( + "bdd" => $message_bdd, + "pid" => $message["parent_message_id"] + ); + } + } + if ($message["sender"] != null) { + if (array_key_exists($message["sender"], $this->match_table["user"])) { + $user = $manager->getRepository("Twake\Users:User")->findOneBy(Array("id" => $this->match_table["user"][$message["sender"]])); + $message_bdd->setSender($user); + } + } + + + $message_bdd->setCreationDate(new DateTime("@" . intval($message["creation_date"] / 1000))); + + $manager->persist($message_bdd); + } + + } + } + fclose($handle_channel_file); + chdir(".."); + } + } + } +} diff --git a/twake/backend/core/src/Twake/Core/Command/InitCommand.php b/twake/backend/core/src/Twake/Core/Command/InitCommand.php new file mode 100755 index 00000000..ed824c80 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Command/InitCommand.php @@ -0,0 +1,118 @@ + Array(), 'notall' => Array()); + + protected function configure() + { + $this + ->setName("twake:init") + ->setDescription("Command to initialize the server, notably filling the database with crucial data"); + } + + + protected function execute() + { + + @file_put_contents("/twake.status.init", "0"); + + $manager = $this->getApp()->getServices()->get('app.twake_doctrine'); + + /** + * RΓ©cupΓ©ration des repository, de Twake et des applis de base + */ + + $services = $this->getApp()->getServices(); + + // CrΓ©ation des applications de base + error_log("> Creating basic apps"); + + $configuration = $this->getApp()->getContainer()->getParameter("defaults.applications.twake_drive"); + $app = null; + $app = $manager->getRepository("Twake\Market:Application")->findOneBy(Array("simple_name" => "twake_drive")); + if (!$app) { + $app = new Application(new FakeCassandraTimeuuid(), "Documents"); + $app->setApiPrivateKey($app->generatePrivateApiKey()); + } + $app->setEsIndexed(false); + $app->setIconUrl("/public/img/twake-emoji/twake-drive.png"); + $app->setWebsite("https://twakeapp.com"); + $app->setDescription("Twake file storage application."); + $app->setSimpleName("twake_drive"); + $app->setAppGroupName("twake"); + $app->setPublic(!!$configuration); + $app->setIsAvailableToPublic(!!$configuration); + $app->setTwakeTeamValidation(!!$configuration); + $app->setDisplayConfiguration(json_decode('{"messages_module":{"in_plus":true},"channel_tab":true,"app":true}', true)); + $app->setDefault(isset($configuration["default"]) && $configuration["default"]); + $manager->persist($app); + $manager->flush(); + + $configuration = $this->getApp()->getContainer()->getParameter("defaults.applications.twake_calendar"); + $app = null; + $app = $manager->getRepository("Twake\Market:Application")->findOneBy(Array("simple_name" => "twake_calendar")); + if (!$app) { + $app = new Application(new FakeCassandraTimeuuid(), "Calendar"); + $app->setApiPrivateKey($app->generatePrivateApiKey()); + } + $app->setEsIndexed(false); + $app->setIconUrl("/public/img/twake-emoji/twake-calendar.png"); + $app->setWebsite("https://twakeapp.com"); + $app->setDescription("Twake's shared calendar app."); + $app->setSimpleName("twake_calendar"); + $app->setAppGroupName("twake"); + $app->setPublic(!!$configuration); + $app->setIsAvailableToPublic(!!$configuration); + $app->setTwakeTeamValidation(!!$configuration); + $app->setDisplayConfiguration(json_decode(/*'{"messages_module":{"in_plus":true},*/ + '{"app":true, "channel_tab": true}', true)); + $app->setDefault(isset($configuration["default"]) && $configuration["default"]); + $manager->persist($app); + $manager->flush(); + + $configuration = $this->getApp()->getContainer()->getParameter("defaults.applications.twake_tasks"); + $app = null; + $app = $manager->getRepository("Twake\Market:Application")->findOneBy(Array("simple_name" => "twake_tasks")); + if (!$app) { + $app = new Application(new FakeCassandraTimeuuid(), "Tasks"); + $app->setApiPrivateKey($app->generatePrivateApiKey()); + } + $app->setEsIndexed(false); + $app->setIconUrl("/public/img/twake-emoji/twake-tasks.png"); + $app->setWebsite("https://twakeapp.com"); + $app->setDescription("Twake task management application."); + $app->setSimpleName("twake_tasks"); + $app->setAppGroupName("twake"); + $app->setPublic(!!$configuration); + $app->setIsAvailableToPublic(!!$configuration); + $app->setTwakeTeamValidation(!!$configuration); + $app->setDisplayConfiguration(json_decode(/*'{"messages_module":{"in_plus":true},*/ + '{"channel_tab":true, "app":true}', true)); + $app->setDefault(isset($configuration["default"]) && $configuration["default"]); + $manager->persist($app); + $manager->flush(); + + @file_put_contents("/twake.status.init", "1"); + + } + +} diff --git a/twake/backend/core/src/Twake/Core/Command/MailsQueueCommand.php b/twake/backend/core/src/Twake/Core/Command/MailsQueueCommand.php new file mode 100755 index 00000000..1a3e92e4 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Command/MailsQueueCommand.php @@ -0,0 +1,87 @@ +setName("twake:mails_queue"); + } + + protected function execute() + { + + $services = $this->getApp()->getServices(); + $em = $services->get('app.twake_doctrine'); + $repo = $em->getRepository("Twake\Core:MailTask"); + /** @var QueueManager $queues */ + $queues = $services->get('app.queues')->getAdapter(); + $mailer = $services->get("app.twake_mailer"); + + $limit = date("U", date("U") + 60); + + while (date("U") < $limit) { + + $messages = $queues->oldConsume("mails", true); + + if (count($messages) == 0) { + sleep(1); + } else { + + + foreach ($messages as $queue_message) { + $push_message = $queues->getMessage($queue_message); + + $data = $push_message; + + if ($data) { + + $id = $data["task_id"]; + + /** @var MailTask $task */ + $task = $repo->find($id); + + //Ack anyway, we do not retry email sending + $queues->ack("mails", $queue_message); + + if ($task) { + $task_data = $task->getData(); + $mailer->sendInternal($task_data["mail"], $task_data["template"], $task_data["data"], $task_data["attachments"], $task_data["templateDirectory"]); + $em->remove($task); + } + + } + + + } + + $em->flush($task); + + } + + } + + + } + +} diff --git a/twake/backend/core/src/Twake/Core/Command/MappingCommand.php b/twake/backend/core/src/Twake/Core/Command/MappingCommand.php new file mode 100755 index 00000000..5949f22b --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Command/MappingCommand.php @@ -0,0 +1,291 @@ +setName("twake:mapping") + ->setDescription("Command add mapping in all index in Elasticsearch"); + } + + protected function execute() + { + @file_put_contents("/twake.status.es_mapping", "0"); + @file_put_contents("/twake.status.no_es", "0"); + + $es_host = $this->getApp()->getContainer()->getParameter('es.host'); + $es_disabled = $es_host === "false" || !$es_host; + + if ($es_disabled) { + error_log("\nℹ️ ElasticSearch is disabled"); + @file_put_contents("/twake.status.no_es", "1"); + return; + } else { + //Wait for es connection + error_log("\n⏳Waiting for ElasticSearch connection"); + $connected = false; + $iteration = 0; + while(!$connected && $iteration < 15){ + try{ + $test = $this->getApp()->getServices()->get("app.restclient")->get("http://" . $es_host); + $connected = $test->getContent(); + }catch(\Exception $e){ + $connected = false; + } + if(!$connected){ + error_log("... not found, retry in 5 seconds (timeout 180s)"); + sleep(5); + } + $iteration++; + } + if(!$connected){ + @file_put_contents("/twake.status.no_es", "1"); + error_log("\nπŸ’₯ Unable to join ElasticSearch !\n"); + return; + } + } + + $mapping_workspace = Array( + "_source" => Array( + "includes" => Array("id"), + "excludes" => Array( + "name", "group_id", "creation_date" + ) + ), + "properties" => Array( + "id" => Array("type" => "keyword"), + "group_id" => Array("type" => "keyword"), + "name" => Array("type" => "text"), + "creation_date" => Array("type" => "date") + ) + ); + + $mapping_group = Array( + "_source" => Array( + "includes" => Array("id"), + "excludes" => Array( + "name", "creation_date" + ) + ), + "properties" => Array( + "id" => Array("type" => "keyword"), + "name" => Array("type" => "text"), + "creation_date" => Array("type" => "date") + ) + ); + + $mapping_mail = Array( + "_source" => Array( + "includes" => Array("id"), + "excludes" => Array( + "mail" + ) + ), + "properties" => Array( + "id" => Array("type" => "keyword"), + "mail" => Array("type" => "keyword") + ) + ); + + $mapping_message_bloc = Array( + "_source" => Array( + "includes" => Array("id"), + "excludes" => Array( + "workspace_id", "channel_id", "messages" + ) + ), + "properties" => Array( + "id" => Array("type" => "keyword"), + "workspace_id" => Array("type" => "keyword"), + "channel_id" => Array("type" => "keyword"), + "messages" => Array( + "type" => "nested", + "properties" => Array( + "content" => Array("type" => "text"), + "sender" => Array("type" => "keyword"), + "application_id" => Array("type" => "keyword"), + "mentions" => Array("type" => "text"), + "date" => Array("type" => "date"), + "tags" => Array("type" => "keyword"), + "pinned" => Array("type" => "boolean"), + "reactions" => Array("type" => "keyword") + ) + ) + ) + ); + + $mapping_task = Array( + "_source" => Array( + "includes" => Array("id"), + "excludes" => Array( + "title", "description", "owner", "before", "start", "date_created", "tags", "participants", "workspace_id", "date_last_modified" + ) + ), + "properties" => Array( + "id" => Array("type" => "keyword"), + "title" => Array("type" => "text"), + "description" => Array("type" => "text"), + "owner" => Array("type" => "keyword"), + "tags" => Array("type" => "keyword"), + "before" => Array("type" => "date"), + "start" => Array("type" => "date"), + "date_created" => Array("type" => "date"), + "date_last_modified" => Array("type" => "date"), + "workspace_id" => Array("type" => "keyword"), + "participants" => Array("type" => "keyword") + ) + ); + + $mapping_event = Array( + "_source" => Array( + "includes" => Array("id"), + "excludes" => Array( + "title", "description", "owner", "date_from", "date_to", "tags", "participants", "workspace_id", "date_last_modified" + ) + ), + "properties" => Array( + "id" => Array("type" => "keyword"), + "title" => Array("type" => "text"), + "description" => Array("type" => "text"), + "owner" => Array("type" => "keyword"), + "tags" => Array("type" => "keyword"), + "date_from" => Array("type" => "date"), + "date_to" => Array("type" => "date"), + "date_last_modified" => Array("type" => "date"), + "participants" => Array("type" => "keyword"), + "workspace_id" => Array("type" => "keyword") + ) + ); + + + $mapping_channel = Array( + "_source" => Array( + "includes" => Array("id"), + "excludes" => Array( + "workspace_id", "name", "group_id", "last_activity" + ) + ), + "properties" => Array( + "id" => Array("type" => "keyword"), + "workspace_id" => Array("type" => "keyword"), + "group_id" => Array("type" => "keyword"), + "name" => Array("type" => "text"), + "last_activity" => Array("type" => "integer") + ) + ); + + $mapping_file = Array( + "_source" => Array( + "includes" => Array("id"), + "excludes" => Array( + "name", "type", "creation_date", "workspace_id", "keywords", "creator", "date_last_modified", "tags", "size") + ), + "properties" => Array( + "id" => Array("type" => "keyword"), + "name" => Array("type" => "text"), + "type" => Array("type" => "keyword"), + "creation_date" => Array("type" => "date"), + "creator" => Array("type" => "keyword"), + "date_last_modified" => Array("type" => "date"), + "workspace_id" => Array("type" => "keyword"), + "tags" => Array("type" => "keyword"), + "size" => Array("type" => "integer"), + "keywords" => Array( + "type" => "nested", + "properties" => Array( + "keyword" => Array("type" => "text"), + "score" => Array("type" => "float") + ) + ) + ) + ); + + $mapping_users = Array( + "_source" => Array( + "includes" => Array("id"), + "excludes" => Array( + "firstname", "lastname", "username", "email", "language", "creation_date", "groups_id", "workspaces_id" + ) + ), + "properties" => Array( + "id" => Array("type" => "keyword"), + "firstname" => Array("type" => "text"), + "lastname" => Array("type" => "text"), + "username" => Array("type" => "text"), + "email" => Array("type" => "text"), + "language" => Array("type" => "keyword"), + "creation_date" => Array("type" => "date"), + "workspaces_id" => Array("type" => "keyword"), + "groups_id" => Array("type" => "keyword"), + ) + ); + + + $url = $this->getApp()->getContainer()->getParameter('es.host') . "/task"; + $this->updateMapping($url, $mapping_task, "/_mapping/_doc"); + + $url = $this->getApp()->getContainer()->getParameter('es.host') . "/event"; + $this->updateMapping($url, $mapping_event, "/_mapping/_doc"); + + $url = $this->getApp()->getContainer()->getParameter('es.host') . "/channel"; + $this->updateMapping($url, $mapping_channel, "/_mapping/_doc"); + + $url = $this->getApp()->getContainer()->getParameter('es.host') . "/group"; + $this->updateMapping($url, $mapping_group, "/_mapping/_doc"); + + $url = $this->getApp()->getContainer()->getParameter('es.host') . "/mail"; + $this->updateMapping($url, $mapping_mail, "/_mapping/_doc"); + + $url = $this->getApp()->getContainer()->getParameter('es.host') . "/workspace"; + $this->updateMapping($url, $mapping_workspace, "/_mapping/_doc"); + + $url = $this->getApp()->getContainer()->getParameter('es.host') . "/users"; + $this->updateMapping($url, $mapping_users, "/_mapping/_doc"); + + $url = $this->getApp()->getContainer()->getParameter('es.host') . "/drive_file"; + $this->updateMapping($url, $mapping_file, "/_mapping/_doc"); + + $url = $this->getApp()->getContainer()->getParameter('es.host') . "/message_bloc"; + $this->updateMapping($url, $mapping_message_bloc, "/_mapping/_doc"); + + @file_put_contents("/twake.status.es_mapping", "1"); + + } + + private function updateMapping($url, $mapping, $mapping_suffix) + { + + error_log($url . $mapping_suffix); + + try { + $this->getApp()->getServices()->get("app.restclient")->put("http://" . $url, ""); + } catch (\Exception $e) { + error_log("no es"); + error_log($e); + } + + $mapping = json_encode($mapping); + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, "http://" . $url . $mapping_suffix); + curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Content-Length: ' . strlen($mapping))); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); + curl_setopt($ch, CURLOPT_POSTFIELDS, $mapping); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_VERBOSE, 0); + $result = curl_exec($ch); + curl_close($ch); + + error_log($result); + error_log("---------------"); + } +} diff --git a/twake/backend/core/src/Twake/Core/Command/ReindexCommand.php b/twake/backend/core/src/Twake/Core/Command/ReindexCommand.php new file mode 100755 index 00000000..86dbbcad --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Command/ReindexCommand.php @@ -0,0 +1,108 @@ +setName("twake:reindex") + ->setDescription("Command to reindex scylladb date in all index in Elasticsearch"); + } + + protected function execute() + { + $manager = $this->getApp()->getServices()->get('app.twake_doctrine'); + + $arg_list = $_SERVER['argv']; + $arg = isset($arg_list[0]) ? $arg_list[0] : false; + + error_log("REINDEX ".$arg); + + if($arg == "channel"){ + $channels = $manager->getRepository("Twake\Channels:Channel")->findBy(Array("direct" => false)); + foreach ($channels as $i => $channel) { + $c = $this->indexChannel($channel, $manager); + error_log("index " . "Workspaces Channels " . $i . "/" . count($channels) . " " . $c . " messsages"); + } + } + + if($arg == "workspace"){ + $this->indexRepository("Twake\Workspaces:Workspace"); + } + + if($arg == "group"){ + $this->indexRepository("Twake\Workspaces:Group"); + } + + if($arg == "file"){ + $workspaces = $manager->getRepository("Twake\Workspaces:Workspace")->findBy(Array()); + error_log("index " . "Files"); + foreach ($workspaces as $workspace) { + $this->indexRepository("Twake\Drive:DriveFile", Array("workspace_id" => $workspace->getId())); + } + } + + if($arg == "application"){ + $this->indexRepository("Twake\Market:Application"); + } + + if($arg == "message"){ + $this->indexRepository("Twake\GlobalSearch:Bloc"); + } + + if($arg == "mail"){ + $this->indexRepository("Twake\Users:Mail"); + } + + if($arg == "user"){ + $this->indexRepository("Twake\Users:User"); + } + + if($arg == "task"){ + $this->indexRepository("Twake\Tasks:Task"); + } + + if($arg == "event"){ + $this->indexRepository("Twake\Calendar:Event"); + } + + + } + + private function indexChannel($channel, $manager) + { + + $messages = $manager->getRepository("Twake\Discussion:Message")->findBy(Array("channel_id" => $channel->getId())); + foreach ($messages as $message) { + $this->getApp()->getServices()->get('app.messages')->indexMessage($message, $channel->getOriginalWorkspaceId(), $channel->getId()); + } + + return count($messages); + + } + + private function indexRepository($repository, $options = Array()) + { + $manager = $this->getApp()->getServices()->get('app.twake_doctrine'); + + error_log("index " . $repository); + + $items = $manager->getRepository($repository)->findBy($options); + error_log(" -> " . count($items)); + $i = 0; + foreach ($items as $item) { + if(($i++) % 100 == 0) error_log($i); + $manager->es_put($item, $item->getEsType()); + } + + } +} diff --git a/twake/backend/core/src/Twake/Core/Command/ScheduledNotificationsConsumeShard.php b/twake/backend/core/src/Twake/Core/Command/ScheduledNotificationsConsumeShard.php new file mode 100755 index 00000000..6a5219f7 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Command/ScheduledNotificationsConsumeShard.php @@ -0,0 +1,33 @@ +setName("twake:scheduled_notifications_consume_shard"); + } + + + protected function execute() + { + /** @var Scheduled $service */ + $service = $this->app->getServices()->get("app.queues_scheduled"); + + $limit = date("U", date("U") + 60); + + while (date("U") < $limit) { + $done = $service->consumeShardsFromRabbitMQ(); + if ($done == 0) { + break; + } + } + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Command/ScheduledNotificationsConsumeTimetable.php b/twake/backend/core/src/Twake/Core/Command/ScheduledNotificationsConsumeTimetable.php new file mode 100755 index 00000000..008f00fe --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Command/ScheduledNotificationsConsumeTimetable.php @@ -0,0 +1,31 @@ +setName("twake:scheduled_notifications_consume_timetable"); + } + + + protected function execute() + { + /** @var Scheduled $service */ + $service = $this->app->getServices()->get("app.queues_scheduled"); + + $limit = date("U", date("U") + 60); + + while (date("U") < $limit) { + $service->consumeShards(60); + usleep(100000); + } + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Command/TestQueue.php b/twake/backend/core/src/Twake/Core/Command/TestQueue.php new file mode 100755 index 00000000..96856673 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Command/TestQueue.php @@ -0,0 +1,45 @@ +setName("twake:queue:test"); + } + + + protected function execute() + { + + error_log("test queue"); + + /** @var QueueManager $queues */ + $queues = $this->getApp()->getServices()->get('app.queues')->getAdapter(); + + $queues->push("test", Array("message" => "coucou")); + + sleep(10); + + error_log(json_encode($queues->oldConsume("test"))); + + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Command/TwakeSchemaUpdateCommand.php b/twake/backend/core/src/Twake/Core/Command/TwakeSchemaUpdateCommand.php new file mode 100755 index 00000000..c235ec9c --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Command/TwakeSchemaUpdateCommand.php @@ -0,0 +1,410 @@ +setName("twake:schema:update") + ->setDescription("Update table schemas using configured database system (cassandra or mysql") + ->addOption('complete', null, InputOption::VALUE_NONE, 'If defined, all assets of the database which are not relevant to the current metadata will be dropped.') + ->addOption('dump-sql', null, InputOption::VALUE_NONE, 'Dumps the generated SQL statements to the screen (does not execute them).') + ->addOption('force', 'f', InputOption::VALUE_NONE, 'Causes the generated SQL statements to be physically executed against your database.'); + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * @return int|null|void + */ + protected function execute() + { + + @file_put_contents("/twake.status.db_init", "0"); + + //Wait for scylladb connection + error_log("\n⏳Waiting for ScyllaDB/Cassandra connection"); + $connected = false; + $iteration = 0; + while(!$connected && $iteration < 12 * 6){ + try{ + $doctrine = $this->getApp()->getServices()->get('app.twake_doctrine'); + $em = $doctrine->getManager(); + $connection = $em->getConnection(); + $connection = $connection->getWrappedConnection(); + $connected = true; + }catch(\Exception $e){ + $connected = false; + } + if(!$connected){ + error_log("... not found, retry in 5 seconds (timeout 360s)"); + sleep(5); + } + $iteration++; + } + if(!$connected){ + error_log("\nπŸ’₯ Unable to join ScyllaDB/Cassandra !\n"); + return; + } + + $doctrine = $this->getApp()->getServices()->get('app.twake_doctrine'); + $em = $doctrine->getManager(); + $connection = $em->getConnection(); + $connection = $connection->getWrappedConnection(); + + $entities = array(); + + $meta = $em->getMetadataFactory()->getAllMetadata(); + foreach ($meta as $m) { + $entities[] = $m; + } + + $schema = $connection->getSchema(); + $keyspace = $schema->keyspace(strtolower($connection->getKeyspace())); + $is_cassandra = $this->getApp()->getContainer()->getParameter("db.is_cassandra", false); + + $ignored_cols = 0; + $viable_indexes = []; + + foreach ($entities as $entity) { + + $table_name = $entity->getTableName(); + error_log($table_name); + $fields = Array(); + $indexed_fields = Array(); + + $custom_keys_names = false; + $custom_keys = false; + $custom_keys_order = false; + $custom_keys_where = false; + if (isset($entity->table["options"]) && isset($entity->table["options"]["scylladb_keys"])) { + if (isset($entity->table["options"]["scylladb_keys"][0]) && count($entity->table["options"]["scylladb_keys"][0]) > 0) { + $_custom_keys = $entity->table["options"]["scylladb_keys"]; + + $custom_keys = Array(); + $custom_keys_names = Array(); + $custom_keys_order = Array(); + $custom_keys_where = Array(); + + $j = 0; + foreach ($_custom_keys as $_custom_key) { + $keys = []; + $i = 0; + $custom_keys_order_tmp = Array(); + $custom_keys_where_tmp = Array(); + $custom_name = null; + foreach ($_custom_key as $key => $order) { + + if ($key == "__name") { + $custom_name = $order; + continue; + } + + $value = false; + if ($order != "ASC" and $order != "DESC") { + $value = $order; + $order = "ASC"; + } + + if (is_array($key)) { + $keys[] = "(" . join(", ", $key) . ")"; + } else { + $keys[] = $key; + } + + $custom_keys_where_tmp[] = $key . (($value === false) ? " IS NOT NULL" : " = " . $value); + if ($i > 0) { + $custom_keys_order_tmp[] = $key . " " . $order; + } + $i++; + + } + $custom_keys[] = join(", ", $keys); + $custom_keys_order[] = join(", ", $custom_keys_order_tmp); + $custom_keys_where[] = join(" AND ", $custom_keys_where_tmp); + $custom_keys_names[] = $custom_name; + } + + } + } + + foreach ($entity->getFieldNames() as $_fieldname) { + + $mapping = Array(); + if (!$entity->hasAssociation($_fieldname)) { + $mapping = $entity->getFieldMapping($_fieldname); + } else { + $mapping["type"] = "timeuuid"; + } + + if (isset($mapping["columnName"])) { + $fieldname = $mapping["columnName"]; + } + + if (isset($mapping["options"]) && isset($mapping["options"]["index"]) && $mapping["options"]["index"]) { + $indexed_fields[$fieldname] = true; + } + + if (strtolower($fieldname) != $fieldname) { + $ignored_cols++; + error_log("INFO (IGNORING COLUMN) ! Column names MUST be snakecase and lowercase ! (" . $fieldname . " in " . $entity->getName() . ")"); + continue; + } + + $type = $this->convertType($mapping["type"]); + if ($type == "ERROR") { + error_log("INFO (IGNORING COLUMN) ! Type " . $mapping["type"] . " is not allowed with Cassandra implementation (in " . $entity->getName() . ")"); + continue; + } + + $fields[$fieldname] = $type; + } + + foreach ($entity->getAssociationNames() as $_fieldname) { + + $fieldname = $_fieldname; + + $mapping = $entity->getAssociationMapping($fieldname); + + if (isset($mapping["columnName"])) { + $fieldname = $mapping["columnName"]; + } + + $fieldname = $fieldname . "_id"; + + if(isset($mapping["joinColumns"][0]["name"])){ + $fieldname = $mapping["joinColumns"][0]["name"]; + } + + if (strtolower($fieldname) != $fieldname) { + $ignored_cols++; + error_log("INFO (IGNORING COLUMN) ! Column names MUST be snakecase and lowercase ! (" . $fieldname . " in " . $entity->getName() . ")"); + continue; + } + + if (!(isset($mapping["id"]) && $mapping["id"])) { //isset($mapping["options"]) && isset($mapping["options"]["index"]) && $mapping["options"]["index"]) { + $indexed_fields[$fieldname] = true; + } + + $fields[$fieldname] = "timeuuid"; + } + + if (strtolower($table_name) != $table_name) { + error_log("INFO (IGNORING TABLE) ! Tables names MUST be snakecase and lowercase ! (" . $entity->getName() . ")"); + continue; + } + + if (!$keyspace->table($table_name)) { + //Create table + $create_table = "CREATE TABLE " . strtolower($connection->getKeyspace()) . ".\"" . $table_name . "\" "; + + //Add Primary key + $identifiers = $entity->getIdentifier(); + if (!$custom_keys && count($identifiers) != 1) { + error_log("INFO (IGNORING TABLE) ! Tables MUST have exactly one identifier for this implementation with Cassandra ! (in " . $entity->getName() . " " . json_encode($identifiers) . ")"); + continue; + } + $identifier = $identifiers[0]; + + $mapping = Array(); + if (!$entity->hasAssociation($identifier)) { + $mapping = $entity->getFieldMapping($identifier); + if (!in_array($mapping["type"], Array("twake_timeuuid", "twake_uuid", "string", "blob", "twake_string", "twake_bigint"))) { + error_log("INFO (IGNORING TABLE) ! Tables index MUST be of type twake_timeuuid or string, or twake_string or blob or twake_bigint ! (in " . $entity->getName() . ")"); + continue; + } + } else { + $mapping["columnName"] = $identifier . "_id"; + $mapping["type"] = "twake_timeuuid"; + } + + $identifier = $mapping["columnName"]; + + $create_table .= "("; + $columns = Array(); + + $columns[] = "\"" . $identifier . "\" " . $this->convertType($mapping["type"]) . ($custom_keys ? "" : " PRIMARY KEY"); + foreach ($fields as $fieldname => $type) { + if ($fieldname != $identifier) { + $columns[] = "\"" . $fieldname . "\" " . $type . ""; + } + } + $columns = join(", ", $columns); + + $create_table .= $columns; + + if ($custom_keys) { + $create_table .= ", PRIMARY KEY (" . $custom_keys[0] . ")"; + } + + $create_table .= ")"; + + if ($custom_keys_order && $custom_keys_order[0]) { + $create_table .= " WITH CLUSTERING ORDER BY (" . $custom_keys_order[0] . ")"; + } + + $connection->exec($create_table); + + $schema = $connection->getSchema(); + $keyspace = $schema->keyspace(strtolower($connection->getKeyspace())); + } + + $cassandra_table = $keyspace->table($table_name); + if (!$cassandra_table) { + continue; + } + + //Add columns + $columns_to_add = Array(); + $alter_command = "ALTER TABLE " . strtolower($connection->getKeyspace()) . ".\"" . $table_name . "\" "; + foreach ($fields as $fieldname => $type) { + + $existing_col = $cassandra_table->column($fieldname); + + if ($existing_col) { + if ($existing_col->type() != $type) { + $command = $alter_command . " ALTER \"" . $fieldname . "\" TYPE " . $type; + $connection->exec($command); + } + } else { + /* MULTIPLE ADD COLUMN NOT SUPORTED FOR CURRENT SCYLLADB VERSION*/ + $add = "\"" . $fieldname . "\" " . $type . ""; + $connection->exec($alter_command . " ADD " . $add); + $columns_to_add[] = $add; + } + + } + + if ($custom_keys) { + + //Cannot update main primary key + array_shift($custom_keys); + array_shift($custom_keys_order); + array_shift($custom_keys_where); + array_shift($custom_keys_names); + + if (count($custom_keys) > 0) { + + foreach ($custom_keys as $i => $key) { + + $index_name = $table_name . "_index_" . str_replace([",", " "], ["_", ""], $key); + + if (strpos($key, ",") !== false) { + if ($custom_keys_names[$i]) { + $index_name = $custom_keys_names[$i] . "_custom_index"; + } else { + $index_name .= "_composite"; + } + + if($is_cassandra){ + $index_name = "index_".md5($index_name); + } + + $command = "CREATE MATERIALIZED VIEW IF NOT EXISTS " . strtolower($connection->getKeyspace()) . ".\""; + $command .= $index_name . "\" AS "; + $command .= " SELECT " . $key; + $command .= " FROM " . strtolower($connection->getKeyspace()) . ".\"" . $table_name . "\" "; + $command .= " WHERE " . $custom_keys_where[$i]; + $command .= " PRIMARY KEY (" . $key . ")"; + $command .= " WITH CLUSTERING ORDER BY (" . $custom_keys_order[$i] . ")"; + } else { + + if ($custom_keys_names[$i]) { + $index_name = $custom_keys_names[$i] . "_custom_index"; + } else { + $index_name .= "_simple"; + } + + if($is_cassandra){ + $index_name = "index_".md5($index_name); + } + + $command = "CREATE INDEX IF NOT EXISTS \""; + $command .= $index_name . "\" ON " . strtolower($connection->getKeyspace()) . ".\"" . $table_name . "\" "; + $command .= "(\"" . $key . "\")"; + } + $connection->exec($command); + $viable_indexes[] = $index_name; + } + + } + + } else { + + if (isset($entity->table["options"]["indexes"])) { + foreach ($entity->table["options"]["indexes"] as $index_name => $data) { + $columns = $data->columns; + if (count($columns) == 1) { + $indexed_fields[$columns[0]] = true; + } + } + } + + foreach ($indexed_fields as $indexed_field => $dummy) { + + $index_name = $table_name . "_index_" . str_replace([",", " "], ["_", ""], $indexed_field) . "_simple_2"; + + $index_base_command = "CREATE INDEX IF NOT EXISTS \"" . $index_name . "\" ON " . strtolower($connection->getKeyspace()) . ".\"" . $table_name . "\" "; + + $command = $index_base_command . "(\"" . $indexed_field . "\")"; + $connection->exec($command); + + $viable_indexes[] = $index_name; + } + + } + + } + + error_log("Indexes = " . count($viable_indexes)); + error_log("Ignored cols = " . $ignored_cols); + + @file_put_contents("/twake.status.db_init", "1"); + + } + + private function convertType($type) + { + $conversionFor = Array( + "string" => "text", + "twake_text" => "text", + "twake_no_salt_text" => "text", + "twake_string" => "text", + "twake_timeuuid" => "timeuuid", + "twake_uuid" => "timeuuid", + "array" => "text", + "twake_boolean" => "tinyint", + "tinyint" => "tinyint", + "boolean" => "tinyint", + "text" => "text", + "twake_float" => "float", + "integer" => "int", + "bigint" => "bigint", + "twake_bigint" => "bigint", + "twake_counter" => "counter", + "decimal" => "decimal", + "twake_datetime" => "timestamp", + "blob" => "blob" + ); + return isset($conversionFor[$type]) ? $conversionFor[$type] : "ERROR"; + } + +} diff --git a/twake/backend/core/src/Twake/Core/CommonObjects/AttachementManager.php b/twake/backend/core/src/Twake/Core/CommonObjects/AttachementManager.php new file mode 100755 index 00000000..39ae5fcd --- /dev/null +++ b/twake/backend/core/src/Twake/Core/CommonObjects/AttachementManager.php @@ -0,0 +1,183 @@ +doctrine = $doctrine; + $this->ws = $ws; + } + + public function updateAttachements($object, $attachements = Array()) + { + $type = $this->getTypeFromClass($object); + $oldAttachements = $object->getAttachements() ? $object->getAttachements() : Array(); + $newAttachement = $oldAttachements; + $get_diff = $this->getArrayDiffUsingKeys($attachements, $oldAttachements, ["id"]); + foreach ($get_diff["del"] as $att) { + foreach ($newAttachement as $index => $attac) { + if ($attac["id"] == $att["id"] && $attac["type"] == $att["type"]) { + $this->removeAttachementFromEntity($object, $attac); + unset($newAttachement[$index]); + } + } + } + foreach ($get_diff["add"] as $att) { + $att["isAttached"] = false; + $newAttachement[] = $att; + $attachedRepo = $this->getAttachementRepository($att["type"]); + if ($attachedRepo) { + $entityAttached = $attachedRepo->findOneBy(Array("id" => $att["id"])); + if ($entityAttached) { + $attachmentInEntityAttached = $entityAttached->getAttachements(); + $attachmentOfAttached = Array( + "type" => $type, + "id" => $object->getId(), + "name" => $this->getAttachmentName($object), + "isAttached" => true + ); + $attachmentInEntityAttached[] = $attachmentOfAttached; + $entityAttached->setAttachements($attachmentInEntityAttached); + $this->doctrine->persist($entityAttached); + $data = Array( + "client_id" => "system", + "action" => "save", + "object_type" => "", + "object" => $entityAttached->getAsArray() + ); + error_log("pushing on " . $this->getRoutePush($entityAttached) . ", " . json_encode($data)); + $this->ws->push($this->getRoutePush($entityAttached), $data); + } + } + } + $object->setAttachements($newAttachement); + $this->doctrine->persist($object); + $this->doctrine->flush(); + } + + private function getTypeFromClass($entity) + { + if (get_class($entity) == "Twake\Tasks\Entity\Task") { + return "task"; + } elseif (get_class($entity) == "Twake\Drive\Entity\DriveFile") { + return "file"; + } elseif (get_class($entity) == "Twake\Calendar\Entity\Event") { + return "event"; + } + return ""; + } + + private function getArrayDiffUsingKeys($new_array, $old_array, $keys) + { + $remove = []; + $add = []; + foreach ($new_array as $new_el) { + if (!$this->inArrayUsingKeys($old_array, $new_el, $keys)) { + $add[] = $new_el; + } + } + foreach ($old_array as $old_el) { + if (!$this->inArrayUsingKeys($new_array, $old_el, $keys)) { + $remove[] = $old_el; + } + } + return Array("del" => $remove, "add" => $add); + } + + private function inArrayUsingKeys($array, $element, $keys) + { + $in = false; + foreach ($array as $el) { + $same = true; + foreach ($keys as $key) { + if ($el[$key] != $element[$key]) { + $same = false; + break; + } + } + if ($same) { + $in = true; + break; + } + } + return $in; + } + + private function removeAttachementFromEntity($object, $attachement) + { + $type = $this->getTypeFromClass($object); + $attachedRepo = $this->getAttachementRepository($attachement["type"]); + $entityAttached = $attachedRepo->findOneBy(Array("id" => $attachement["id"])); + $attachmentInEntityAttached = $entityAttached->getAttachements(); + foreach ($attachmentInEntityAttached as $index => $attac) { + error_log("try " . $attac["id"] . " == " . $object->getId() . ", " . $attac["type"] . " == " . $type); + if ($attac["id"] == $object->getId() && $attac["type"] == $type) { + error_log("remove passive" . json_encode($attac)); + unset($attachmentInEntityAttached[$index]); + $entityAttached->setAttachements($attachmentInEntityAttached); + $this->doctrine->persist($entityAttached); + $data = Array( + "client_id" => "system", + "action" => "save", + "object_type" => "", + "object" => $entityAttached->getAsArray() + ); + $this->ws->push($this->getRoutePush($entityAttached), $data); + break; + } + } + } + + private function getAttachementRepository($type) + { + if ($type == "file") { + return $this->doctrine->getRepository("Twake\Drive:DriveFile"); + } elseif ($type == "task") { + return $this->doctrine->getRepository("Twake\Tasks:Task"); + } elseif ($type == "event") { + return $this->doctrine->getRepository("Twake\Calendar:Event"); + } + return false; + } + + private function getRoutePush($entity) + { + if (get_class($entity) == "Twake\Tasks\Entity\Task") { + return "board_tasks/" . $entity->getBoardId(); + } elseif (get_class($entity) == "Twake\Drive\Entity\DriveFile") { + return "drive/" . $entity->getWorkspaceId() . "/" . $entity->getParentId(); + } elseif (get_class($entity) == "Twake\Calendar\Entity\Event") { + return "calendar_events/" . $entity->getWorkspaceId(); + } + return ""; + } + + private function getAttachmentName($entity) + { + if (get_class($entity) == "Twake\Tasks\Entity\Task") { + return $entity->getTitle(); + } elseif (get_class($entity) == "Twake\Drive\Entity\DriveFile" || get_class($entity) == "Twake\Calendar\Entity\Event") { + return $entity->getName(); + } + return ""; + } + + public function removeAttachementsFromEntity($object) + { + $attachementsToRemove = $object->getAttachements(); + foreach ($attachementsToRemove as $attachement) { + error_log("remove attachement" . json_encode($attachement)); + $this->removeAttachementFromEntity($object, $attachement); + } + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Controller/Access.php b/twake/backend/core/src/Twake/Core/Controller/Access.php new file mode 100755 index 00000000..24e4ddbc --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Controller/Access.php @@ -0,0 +1,37 @@ +getUser(); + $data = $request->request->get("data"); + $options = $request->request->get("options"); + $current_user_id = $current_user->getId(); + + $acces = $this->get('app.accessmanager')->has_access($current_user_id, $data, $options); + $data = Array("data" => $acces); + + return new Response($data); + } + + public function user_has_workspace_access(Request $request) + { + $workspace_id = $request->request->get("workspace_id"); + $current_user = $this->getUser(); + $current_user_id = $current_user->getId(); + + $publicaccess = $this->get('app.accessmanager')->user_has_workspace_access($current_user_id, $workspace_id); + $data = Array("data" => $publicaccess); + + return new Response($data); + } +} diff --git a/twake/backend/core/src/Twake/Core/Controller/GroupedQuery.php b/twake/backend/core/src/Twake/Core/Controller/GroupedQuery.php new file mode 100755 index 00000000..64a0d7c6 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Controller/GroupedQuery.php @@ -0,0 +1,64 @@ +request->get("request"); + $response = []; + + foreach ($requests as $_request) { + $route = $_request["route"]; + $data = $_request["data"]; + $request->request->replace($data); + + $controller = $this->routeToControllerName($route); + + if ($controller) { + + $tmp = $this->forward($controller, array('request' => $request)); + $response[] = Array( + "route" => $route, + "data" => json_decode($tmp->getContent(), true) + ); + + } else { + $response[] = Array( + "route" => $route, + "data" => Array("error" => "controller_was_not_found") + ); + } + } + + return new Response(Array("data" => $response)); + + } + + private function routeToControllerName($routename) + { + if ($routename == "/ajax/core/collections/init") { + return "Twake\Core:Websockets:init"; + } + if ($routename == "/ajax/notifications/get") { + return "Twake\Notifications:Default:get"; + } + if ($routename == "/ajax/channels/get") { + return "Twake\Channels:Channels:get"; + } + if ($routename == "/ajax/channels/direct_messages/get") { + return "Twake\Channels:DirectMessages:get"; + } + if ($routename == "/ajax/discussion/get") { + return "Twake\Discussion:Discussion:get"; + } + } + +} diff --git a/twake/backend/core/src/Twake/Core/Controller/Remote.php b/twake/backend/core/src/Twake/Core/Controller/Remote.php new file mode 100755 index 00000000..f0e3d5d2 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Controller/Remote.php @@ -0,0 +1,98 @@ +container->getParameter('env.standalone')) { + + $remoteLicenceKey = $request->request->get("licenceKey", ""); + $remoteIp = $request->getClientIp(); + + $licenceServer = "https://licences.twakeapp.com/api"; + $licenceKey = $this->container->getParameter('env.licence_key'); + $data = Array( + "licenceKey" => $licenceKey, + "remoteLicenceKey" => $remoteLicenceKey, + "remoteIp" => $remoteIp + ); + $result = $this->get("app.restclient")->post($licenceServer . "/verifyRemote", json_encode($data), array(CURLOPT_CONNECTTIMEOUT => 60)); + $result = json_decode($result->getContent(), true); + + if (!isset($result["status"]) || $result["status"] != "valid") { + return new Response(Array("status" => "error", "error" => $result)); + } + + $mail = $request->request->get("mail", ""); + $html = $request->request->get("html", ""); + $attachments = $request->request->get("attachments", Array()); + $this->get("app.twake_mailer")->sendHTML($mail, $html, $attachments); + + return new Response(Array("status" => "success")); + + } + //[/REMOVE_ONPREMISE] + return new Response(Array("status" => "error")); + + } + + public function push(Request $request) + { + //[REMOVE_ONPREMISE] + + if ($this->container->getParameter('env.standalone')) { + + $remoteLicenceKey = $request->request->get("licenceKey", ""); + $remoteIp = $request->getClientIp(); + + $licenceServer = "https://licences.twakeapp.com/api"; + $licenceKey = $this->container->getParameter('env.licence_key'); + $data = Array( + "licenceKey" => $licenceKey, + "remoteLicenceKey" => $remoteLicenceKey, + "remoteIp" => $remoteIp + ); + $result = $this->get("app.restclient")->post($licenceServer . "/verifyRemote", json_encode($data), array(CURLOPT_CONNECTTIMEOUT => 60)); + $result = json_decode($result->getContent(), true); + + if (!isset($result["status"]) || $result["status"] != "valid") { + return new Response(Array("status" => "error", "error" => $result)); + } + + $data_array = $request->request->get("data", Array()); + + if (isset($data_array["type"])) { + $data_array = Array($data_array); + } + + foreach ($data_array as $data) { + + $type = $data["type"]; + $deviceId = $data["device_id"]; + $message = $data["message"]; + $title = $data["title"]; + $badge = $data["badge"]; + $more_data = $data["data"]; + + $this->get("app.notifications")->pushDeviceInternal($type, $deviceId, $message, $title, $badge, $more_data); + + } + + return new Response(Array("status" => "success")); + + } + //[/REMOVE_ONPREMISE] + return new Response(Array("status" => "error")); + + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Controller/Version.php b/twake/backend/core/src/Twake/Core/Controller/Version.php new file mode 100755 index 00000000..3fe4c477 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Controller/Version.php @@ -0,0 +1,76 @@ +get("app.update_services_status")->execute(); + + $auth = []; + if ($this->getParameter("defaults.auth.internal.use")) { + $auth["internal"] = [ + "disable_account_creation" => $this->getParameter("defaults.auth.internal.disable_account_creation"), + "disable_email_verification" => $this->getParameter("defaults.auth.internal.disable_email_verification"), + "use" => true, + ]; + } + if ($this->getParameter("defaults.auth.cas.use")) { + $auth["cas"] = [ + "use" => true, + ]; + } + if ($this->getParameter("defaults.auth.openid.use")) { + $auth["openid"] = [ + "use" => true, + ]; + } + if ($this->getParameter("defaults.auth.console.use")) { + $auth["console"] = [ + "use" => true, + "max_unverified_days" => intval($this->getParameter("defaults.auth.console.configuration.max_unverified_days", "7")), + "account_management_url" => $this->getParameter("defaults.auth.console.redirections.account_management_url"), + "company_management_url" => $this->getParameter("defaults.auth.console.redirections.company_management_url"), + "collaborators_management_url" => $this->getParameter("defaults.auth.console.redirections.collaborators_management_url"), + ]; + } + + $data = Array( + "ready" => $ready, + "auth_mode" => array_keys($auth), + "auth" => $auth, + "version" => [ + "current" => /* @VERSION_DETAIL */ "2023.Q1.1223", + "minimal" => [ + "web" => /* @MIN_VERSION_WEB */ "2022.Q2.975", + "mobile" => /* @MIN_VERSION_MOBILE */ "2022.Q2.975", + ] + ], + "elastic_search_available" => !!$this->container->getParameter("es.host"), + "help_url" => "https://go.crisp.chat/chat/embed/?website_id=9ef1628b-1730-4044-b779-72ca48893161" + ); + + if ($this->container->hasParameter("defaults.branding")) { + $branding = $this->container->getParameter("defaults.branding"); + if ($branding && $branding["name"]) { + $data["branding"] = $branding; + } + } + + return new Response(Array("data" => + $data + )); + + + } + +} diff --git a/twake/backend/core/src/Twake/Core/Controller/Websockets.php b/twake/backend/core/src/Twake/Core/Controller/Websockets.php new file mode 100755 index 00000000..0b9abaf0 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Controller/Websockets.php @@ -0,0 +1,63 @@ +request->get("multiple", false); + $multiple = $multiple_request; + if (!$multiple_request) { + $multiple = [Array( + "collection_id" => $request->request->get("collection_id", ""), + "options" => $request->request->get("options", "") + )]; + } + + $final_result = []; + + $wss = $this->get("app.websockets"); + + foreach ($multiple as $item) { + $route = $item["collection_id"]; + $data = $item["options"]; + + try { + $result = $wss->init($route, $data, $this); + if ($result) { + $final_result[] = Array( + "data" => Array( + "room_id" => $result["route_id"], + "key" => $result["key"], + "key_version" => $result["key_version"], + "get" => $result["get"] + ) + ); + } else { + $final_result[] = Array("status" => "error_service_not_found_or_not_allowed"); + } + } catch (\Exception $e) { + log_exception($e); + $final_result[] = Array("status" => "error_service_not_found_or_not_allowed"); + } + + } + + if (!$multiple_request) { + $final_result = $final_result[0]; + } else { + $final_result = Array("data" => $final_result); + } + + return new Response($final_result); + + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Entity/CachedFromNode.php b/twake/backend/core/src/Twake/Core/Entity/CachedFromNode.php new file mode 100755 index 00000000..568fd68a --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Entity/CachedFromNode.php @@ -0,0 +1,56 @@ +company_id = $company; + $this->type = $type; + $this->key = $key; + $this->data = json_encode($data); + } + + public function getData() + { + return json_decode($this->data, 1); + } + +} diff --git a/twake/backend/core/src/Twake/Core/Entity/FrontObject.php b/twake/backend/core/src/Twake/Core/Entity/FrontObject.php new file mode 100755 index 00000000..4bb2080a --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Entity/FrontObject.php @@ -0,0 +1,47 @@ +front_id = date("U") . bin2hex(random_bytes(20)); + } + + public function getId() + { + return ""; + } + + /** + * @return mixed + */ + public function getFrontId() + { + return $this->front_id ? $this->front_id : $this->getId(); + } + + /** + * @param mixed $front_id + */ + public function setFrontId($front_id) + { + if ($front_id) { + $this->front_id = $front_id; + } + } + +} diff --git a/twake/backend/core/src/Twake/Core/Entity/MailTask.php b/twake/backend/core/src/Twake/Core/Entity/MailTask.php new file mode 100755 index 00000000..b2641b77 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Entity/MailTask.php @@ -0,0 +1,73 @@ +setData($data); + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id): void + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getData() + { + return json_decode($this->data, 1); + } + + /** + * @param mixed $data + */ + public function setData($data): void + { + $this->data = json_encode($data); + } + + +} diff --git a/twake/backend/core/src/Twake/Core/Entity/ScheduledCounter.php b/twake/backend/core/src/Twake/Core/Entity/ScheduledCounter.php new file mode 100755 index 00000000..fff6be63 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Entity/ScheduledCounter.php @@ -0,0 +1,71 @@ +type = $type; + $this->time = floor(($timestamp / $time_interval)) * $time_interval; + } + + /** + * @return mixed + */ + public function getValue() + { + return $this->value || 0; + } + + /** + * @param mixed $value BE CAREFUL THIS IS A COUNTER ! SO IT WILL BE AN ADD NOT A SET + */ + public function setIncrementValue($value) + { + $this->value = $value; + } + + /** + * @return float|int + */ + public function getTime() + { + return $this->time; + } + + /** + * @return mixed + */ + public function getType() + { + return $this->type; + } + +} diff --git a/twake/backend/core/src/Twake/Core/Entity/ScheduledTask.php b/twake/backend/core/src/Twake/Core/Entity/ScheduledTask.php new file mode 100755 index 00000000..ecf859f5 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Entity/ScheduledTask.php @@ -0,0 +1,115 @@ +route = $route; + $this->time = floor(($timestamp / $time_interval)) * $time_interval; + $this->timestamp = $timestamp; + $this->shard = $shard . ""; + $this->setData($data); + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id): void + { + $this->id = $id . ""; + } + + /** + * @return mixed + */ + public function getData() + { + return json_decode($this->data, 1); + } + + /** + * @param mixed $data + */ + public function setData($data): void + { + $this->data = json_encode($data); + } + + /** + * @return mixed + */ + public function getTimestamp() + { + return $this->timestamp; + } + + /** + * @return mixed + */ + public function getRoute() + { + return $this->route; + } + + +} diff --git a/twake/backend/core/src/Twake/Core/Entity/SearchableObject.php b/twake/backend/core/src/Twake/Core/Entity/SearchableObject.php new file mode 100755 index 00000000..5ca5cf96 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Entity/SearchableObject.php @@ -0,0 +1,100 @@ +setEsIndexed(false); + } + + /** + * @return mixed + */ + public function getEsIndexed() + { + return $this->es_indexed; + } + + /** + * @param mixed $es_indexed + */ + public function setEsIndexed($es_indexed) + { + $this->es_indexed = $es_indexed; + } + + /** + * @return mixed + */ + public function getEsType() + { + return $this->es_type; + } + + /** + * @param mixed $es_type + */ + public function setEsType($es_type) + { + $this->es_type = $es_type; + } + + /** + * @return mixed + */ + public function getEsIndex() + { + return $this->es_index; + } + + /** + * @param mixed $es_index + */ + public function setEsIndex($es_index) + { + if (!$es_index) { + $this->on_construct_indexation_array = ""; + } + $this->es_index = $es_index; + } + + public function getIndexationArray() + { + return Array(); + } + + public function updatePreviousIndexationArray() + { + $this->on_construct_indexation_array = json_encode($this->getIndexationArray()); + } + + public function changesInIndexationArray() + { + if (json_encode($this->getIndexationArray()) != $this->on_construct_indexation_array) { + return true; + } + return false; + } + +} diff --git a/twake/backend/core/src/Twake/Core/Entity/Sessions.php b/twake/backend/core/src/Twake/Core/Entity/Sessions.php new file mode 100755 index 00000000..17216635 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Entity/Sessions.php @@ -0,0 +1,111 @@ +sess_id; + } + + /** + * @return mixed + */ + public function getSessData() + { + return $this->sess_data; + } + + /** + * @return mixed + */ + public function getSessTime() + { + return $this->sess_time; + } + + /** + * @return mixed + */ + public function getSessLifetime() + { + return $this->sess_lifetime; + } + + /** + * @param mixed $sess_id + */ + public function setSessId($sess_id) + { + $this->sess_id = $sess_id; + } + + /** + * @param mixed $sess_data + */ + public function setSessData($sess_data) + { + $this->sess_data = $sess_data; + } + + /** + * @param mixed $sess_time + */ + public function setSessTime($sess_time) + { + $this->sess_time = $sess_time; + } + + /** + * @param mixed $sess_lifetime + */ + public function setSessLifetime($sess_lifetime) + { + $this->sess_lifetime = $sess_lifetime; + } + + +} diff --git a/twake/backend/core/src/Twake/Core/Entity/WebsocketsRoute.php b/twake/backend/core/src/Twake/Core/Entity/WebsocketsRoute.php new file mode 100755 index 00000000..904e3105 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Entity/WebsocketsRoute.php @@ -0,0 +1,161 @@ +route_random_endpoint = date("U") . "-" . bin2hex(random_bytes(30)); + } + + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getRoute() + { + return $this->route; + } + + /** + * @param mixed $route + */ + public function setRoute($route) + { + $this->route = $route; + } + + /** + * @return mixed + */ + public function getRouteRandomEndpoint() + { + return $this->route_random_endpoint; + } + + /** + * @return mixed + */ + public function getData() + { + return json_decode($this->data, 1); + } + + /** + * @param mixed $data + */ + public function setData($data) + { + $this->data = json_encode($data); + } + + /** + * @return mixed + */ + public function getLastModifiedDate() + { + return $this->last_modified_date; + } + + /** + * @param mixed $last_modified_date + */ + public function setLastModifiedDate() + { + $this->last_modified_date = new \DateTime(); + } + + /** + * @return mixed + */ + public function getKey() + { + return $this->key; + } + + /** + * @param mixed $key + */ + public function setKey($key) + { + $this->key = $key; + } + + /** + * @return mixed + */ + public function getKeyVersion() + { + return $this->key_version; + } + + /** + * @param mixed $key_version + */ + public function setKeyVersion($key_version) + { + $this->key_version = $key_version; + } + + +} diff --git a/twake/backend/core/src/Twake/Core/Resources/Routing.php b/twake/backend/core/src/Twake/Core/Resources/Routing.php new file mode 100755 index 00000000..9988020c --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/Routing.php @@ -0,0 +1,26 @@ + ["handler" => "Version:getVersion", "methods" => ["GET"]], + "ajax/core/grouped_query" => ["handler" => "GroupedQuery:query", "methods" => ["POST"]], + "ajax/core/collections/init" => ["handler" => "Websockets:init", "methods" => ["POST"]], + "ajax/core/access" => ["handler" => "Access:has_access", "methods" => ["POST"]], + "ajax/core/workspaceaccess" => ["handler" => "Access:user_has_workspace_access", "methods" => ["POST"]], + + //Remote routes + "api/remote/mail" => ["handler" => "Remote:mail", "methods" => ["POST"]], + "api/remote/push" => ["handler" => "Remote:push", "methods" => ["POST"]], + "api/remote/recaptcha" => ["handler" => "Remote:verifyReCaptcha", "methods" => ["POST"]] + + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/Services.php b/twake/backend/core/src/Twake/Core/Resources/Services.php new file mode 100755 index 00000000..970a8bbc --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/Services.php @@ -0,0 +1,27 @@ + "UserConnectedSecurity", + "app.websockets" => "Websockets", + "app.twake_mailer" => "TwakeMailer", + "app.restclient" => "TwakeRestClient", + "app.pusher" => "Pusher", + "app.translate" => "Translate", + "app.twake_doctrine" => "DoctrineAdapter/ManagerAdapter", + "app.queues" => "Queues/Queues", + "app.queues_scheduled" => "Queues/Scheduled", + "app.accessmanager" => "AccessManager", + "app.exportversion" => "ExportManager", + "app.string_cleaner" => "StringCleaner", + "app.session_handler" => "DoctrineAdapter/SessionHandler", + "app.update_services_status" => "UpdateServicesStatus" + ]; + +} diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/all_style.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/all_style.html.twig new file mode 100755 index 00000000..6b030e61 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/all_style.html.twig @@ -0,0 +1,124 @@ + + + + + + {% block title %}Twake{% endblock %} + + + +
+ + + + + +
+ +
+ +
+ + {% block content %}{% endblock %} + +
+
+ + \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/addMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/addMail.html.twig new file mode 100755 index 00000000..b7acaed6 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/addMail.html.twig @@ -0,0 +1,20 @@ +{% extends "Mail/de/all.html.twig" %} + +{% block title %}Neue E-Mail-Adresse bestΓ€tigen{% endblock %} + +{% block secondtitle %}Neue E-Mail-Adresse bestΓ€tigen{% endblock %} + +{% block body %} + + Guten Tag {{ username|capitalize }}, +
+ Um diese E-Mail-Adresse zu Ihrem Konto hinzuzufΓΌgen, verwenden Sie bitte folgenden Code: +
+
+
+
+ {{ code }} +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/addedToGroupManagersMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/addedToGroupManagersMail.html.twig new file mode 100755 index 00000000..61d4d81e --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/addedToGroupManagersMail.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/de/all.html.twig" %} + +{% block title %}Sie wurden zu den Managern der Gruppe {{ group }} hinzugefΓΌgt{% endblock %} + +{% block secondtitle %}Sie wurden zu den Managern der Gruppe {{ group }} hinzugefΓΌgt{% endblock %} + +{% block body %} + + Guten Tag {{ username|capitalize }}, +
+ Sie wurden zum Verwalter der Gruppe {{ group }} ernannt. +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/addedToWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/addedToWorkspaceMail.html.twig new file mode 100755 index 00000000..920e031e --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/addedToWorkspaceMail.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/de/all.html.twig" %} + +{% block title %}Sie wurden zum Arbeitsbereich {{ workspace }} hinzugefΓΌgt!{% endblock %} + +{% block secondtitle %}Sie wurden zum Arbeitsbereich {{ workspace }} hinzugefΓΌgt!{% endblock %} + +{% block body %} + + Guten Tag {{ username|capitalize }}, +
+ Sie wurden zum Arbeitsbereich {{ workspace }} in der Gruppe {{ group }} hinzugefΓΌgt. +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/all.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/all.html.twig new file mode 100755 index 00000000..0e10cdb5 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/all.html.twig @@ -0,0 +1,53 @@ +{% extends "Mail/all_style.html.twig" %} + +{% block content %} + + + + + + + +
+ +
{% block secondtitle %}Guten Tag!{% endblock %}
+ + {% block body %}{% endblock %} + +

+ Bis bald auf Twake, +
+ Ihr Twake-Team +
+ {{ twakeurl }} + +
+ + + +{% endblock %} diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/changeLevelWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/changeLevelWorkspaceMail.html.twig new file mode 100755 index 00000000..c8868d96 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/changeLevelWorkspaceMail.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/de/all.html.twig" %} + +{% block title %}Ihr Status in {{ workspace }} hat sich geΓ€ndert{% endblock %} + +{% block secondtitle %}Ihr Status in {{ workspace }} hat sich geΓ€ndert{% endblock %} + +{% block body %} + + Guten Tag {{ username|capitalize }}, +
+ Ihr Status in {{ workspace }} (Gruppe {{ group }}) wurde geΓ€ndert. Sie sind jetzt {{ level }} +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/event_notification.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/event_notification.html.twig new file mode 100755 index 00000000..b2c2625e --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/event_notification.html.twig @@ -0,0 +1,30 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}πŸ“… Twake, {{ text }}{% endblock %} + +{% block secondtitle %}Twake, {{ text }}{% endblock %} + +{% block body %} + + Guten Tag πŸ‘‹, + sie haben bald eine Veranstaltung! +
+
+
+ + {% if event.title %} + {{ event.title }}

+ {% else %} + Untitled

+ {% endif %} + + {% if event.location %} + Where: {{ event.location }}

+ {% endif %} + + + When: in {{ delay }}

+ +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/inviteToWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/inviteToWorkspaceMail.html.twig new file mode 100755 index 00000000..b43fd46d --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/inviteToWorkspaceMail.html.twig @@ -0,0 +1,34 @@ +{% extends "Mail/de/all.html.twig" %} + +{% block title %}Sie wurden in den Arbeitsbereich {{ workspace }}{% endblock %} + +{% block secondtitle %}Sie wurden in den Arbeitsbereich {{ workspace }} der Gruppe {{ group }} eingeladen{% endblock %} + +{% block body %} + + Guten Tag, +
+ Sie wurden von {{ sender_user|capitalize }} ({{ sender_user_mail }}) in den Arbeitsbereich + {{ workspace }} der Gruppe {{ group }} eingeladen. +

+ +
+
+ + Dem Arbeitsbereich beitreten + +
+
{{ twakeappurl|trim('/') }}/login?subscribe&mail={{ mail }} +
+
+
+
+ + Richten Sie bitte ein neues Konto ein, denn wir kennen diese E-Mail-Adresse nicht. +
+
+ Wenn Sie bereits ein Twake-Konto besitzen, fΓΌgen Sie + {{ mail }} in der Liste Ihrer E-Mail-Adressen hinzu; Sie werden dann automtisch zu diesem Arbeitsbereich hinzugefΓΌgt. + +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/messages_notifications.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/messages_notifications.html.twig new file mode 100755 index 00000000..ff38131a --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/messages_notifications.html.twig @@ -0,0 +1,30 @@ +{% extends "Mail/de/all.html.twig" %} + +{% block title %}Sie haben {{ total_notifications }} ungelesene Nachricht(en) auf Twake{% endblock %} + +{% block secondtitle %}πŸ”” Sie haben {{ total_notifications }} ungelesene Nachricht(en) auf Twake{% endblock %} + +{% block body %} + + Guten Tag {{ username|capitalize }}, +
+ Sie haben {{ total_notifications }} ungelesene Nachricht(en) auf Twake. +

+ Letzte Nachricht(en): + + {% for notification in notifications %} +
+ Vor {{ notification.delay }} + Stund(en) + {{ notification.title }}
+ {{ notification.text }} +
+ {% endfor %} + +
+ Γ–ffne Twake +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/newMember.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/newMember.html.twig new file mode 100755 index 00000000..9a8fa073 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/newMember.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/de/all.html.twig" %} + +{% block title %}Herzlich willkommen auf Twake!{% endblock %} + +{% block secondtitle %}Herzlich willkommen auf Twake!{% endblock %} + +{% block body %} + + Guten Tag {{ username|capitalize }}, +
+ Herzlich willkommen auf Twake. Sollten Sie Hilfe benΓΆtigen, kontaktieren Sie uns bitte auf contact@twakeapp.com . +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/notification.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/notification.html.twig new file mode 100755 index 00000000..398d593c --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/notification.html.twig @@ -0,0 +1,17 @@ +{% extends "Mail/de/all.html.twig" %} + +{% block title %}Twake, neue Benachrichtigung von {{ application_name }} in {{ workspace_name }}{% endblock %} + +{% block secondtitle %}Twake, neue Benachrichtigung {{ application_name }} in {{ workspace_name }}{% endblock %} + +{% block body %} + + Guten Tag {{ username|capitalize }}, +
+ Sie haben eine neue Benachrichtigung der Anwendung {{ application_name }} im Arbeitsbereich + {{ workspace_name }} +

+ {{ text }} +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/removedFromWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/removedFromWorkspaceMail.html.twig new file mode 100755 index 00000000..2ffa3e8c --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/removedFromWorkspaceMail.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/de/all.html.twig" %} + +{% block title %}Sie wurden aus dem Arbeitsbereich {{ workspace }} entfernt.{% endblock %} + +{% block secondtitle %}Sie wurden aus dem Arbeitsbereich {{ workspace }} entfernt.{% endblock %} + +{% block body %} + + Guten Tag {{ username|capitalize }}, +
+ Sie wurden aus dem Arbeitsbereich {{ workspace }} in der Gruppe {{ group }} gelΓΆscht. +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/requestPassword.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/requestPassword.html.twig new file mode 100755 index 00000000..f1fa0328 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/requestPassword.html.twig @@ -0,0 +1,20 @@ +{% extends "Mail/de/all.html.twig" %} + +{% block title %} Ihre Anforderung eines neuen Passwortes {% endblock %} + +{% block secondtitle %} Ihre Anforderung eines neuen Passwortes {% endblock %} + +{% block body %} + + Guten Tag {{ username|capitalize }}, +
+ Sie haben ein neues Passwort angefordert; hier ist der erforderliche Aktivierungscode: +
+
+
+
+ {{ code }} +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/subscribeMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/subscribeMail.html.twig new file mode 100755 index 00000000..e7600697 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/subscribeMail.html.twig @@ -0,0 +1,22 @@ +{% extends "Mail/de/all.html.twig" %} + +{% block title %}E-Mail BestΓ€tigung{% endblock %} + +{% block secondtitle %}E-Mail BestΓ€tigung{% endblock %} + +{% block body %} + + Herzlich willkommen auf Twake! +
+ Um Ihr Konto einzurichten, sie kΓΆnnen auf diesen Link klicken : +
+ {{ twakeappurl|trim('/') }}{{ magic_link }} +
+
+ Durch Klicken auf diesen Link erklΓ€ren Sie sich mit den Twake-Nutzungsbedingungen + einverstanden. +

+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/task_notification.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/task_notification.html.twig new file mode 100755 index 00000000..84d9eec8 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/task_notification.html.twig @@ -0,0 +1,26 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}πŸ“‹ Twake, {{ text }}{% endblock %} + +{% block secondtitle %}Twake, {{ text }}{% endblock %} + +{% block body %} + + Guten Tag πŸ‘‹, + Sie haben eine Aufgabe zu erinnern! +
+
+
+ + {% if task.title %} + {{ task.title }}

+ {% else %} + Untitled

+ {% endif %} + + + When: in {{ delay }}

+ +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/unread_notifications.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/unread_notifications.html.twig new file mode 100755 index 00000000..ff4a8135 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/unread_notifications.html.twig @@ -0,0 +1,35 @@ +{% extends "Mail/de/all.html.twig" %} + +{% block title %}Sie haben ungelesene Benachrichtigung(en) auf Twake{% endblock %} + +{% block secondtitle %}Sie haben ungelesene Benachrichtigung(en) auf Twake{% endblock %} + +{% block body %} + + Guten Tag {{ username|capitalize }}, +
+ Sie haben ungelesene Benachrichtigung(en) auf Twake. +

+ Letzte Benachrichtigung(en): + + + {% for notification in notifications %} +
+ Vor {{ notification.delay }} + Stund(en) + {{ notification.title }}
+ {{ notification.text }} +
+ {% endfor %} + +
+
+ + Γ–ffne Twake + +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/addMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/addMail.html.twig new file mode 100755 index 00000000..26fa242d --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/addMail.html.twig @@ -0,0 +1,20 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}Confirm new e-mail{% endblock %} + +{% block secondtitle %}Confirm new e-mail{% endblock %} + +{% block body %} + + Hello {{ username|capitalize }}, +
+ To add this e-mail to your account, use this code : +
+
+
+
+ {{ code }} +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/addedToGroupManagersMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/addedToGroupManagersMail.html.twig new file mode 100755 index 00000000..b048ad2b --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/addedToGroupManagersMail.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}You have been added to the managers of the group {{ group }}{% endblock %} + +{% block secondtitle %}You have been added to the managers of the group {{ group }}{% endblock %} + +{% block body %} + + Hello {{ username|capitalize }}, +
+ You have been granted manager of the group {{ group }}. +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/addedToWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/addedToWorkspaceMail.html.twig new file mode 100755 index 00000000..48ea760f --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/addedToWorkspaceMail.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}You have been added to the workspace {{ workspace }} !{% endblock %} + +{% block secondtitle %}You have been added to the workspace {{ workspace }} !{% endblock %} + +{% block body %} + + Hello {{ username|capitalize }}, +
+ You have been added to the workspace {{ workspace }} in the group {{ group }}. +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/all.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/all.html.twig new file mode 100755 index 00000000..55632bdd --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/all.html.twig @@ -0,0 +1,53 @@ +{% extends "Mail/all_style.html.twig" %} + +{% block content %} + + + + + + + +
+ +
{% block secondtitle %}Hello !{% endblock %}
+ + {% block body %}{% endblock %} + +

+ See you soon on Twake, +
+ the Twake team +
+ {{ twakeurl }} + +
+ + + +{% endblock %} + diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/changeLevelWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/changeLevelWorkspaceMail.html.twig new file mode 100755 index 00000000..53bc3ae6 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/changeLevelWorkspaceMail.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}Your status in {{ workspace }} changed{% endblock %} + +{% block secondtitle %}Your status in {{ workspace }} changed{% endblock %} + +{% block body %} + + Hello {{ username|capitalize }}, +
+ Your status in {{ workspace }} (group {{ group }}) was changed to {{ level }} +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/event_invitation.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/event_invitation.html.twig new file mode 100755 index 00000000..e838c098 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/event_invitation.html.twig @@ -0,0 +1,33 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}πŸ“… Twake, you have been invited to the following event.{% endblock %} + +{% block secondtitle %}Twake, you have been invited to the following event.{% endblock %} + +{% block body %} + + You have been invited to the following event. +
+
+
+ + {% if event.title %} + {{ event.title }}

+ {% else %} + Untitled

+ {% endif %} + + {% if event.location %} + Where: {{ event.location }}

+ {% endif %} + + + When: {{ (event.from - (user_timezone_delay*60)) | date('F j, Y, g:i a') }} + - {{ (event.to - (user_timezone_delay*60)) | date('F j, Y, g:i a') }} ({{ user_timezone_text }})

+ + Invited by: {{ sender_fullname }} {{ sender_email }}

+ +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/event_invitation_updated.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/event_invitation_updated.html.twig new file mode 100755 index 00000000..68e67a9b --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/event_invitation_updated.html.twig @@ -0,0 +1,33 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}πŸ“… Twake, an event has been updated.{% endblock %} + +{% block secondtitle %}Twake, an event has been updated.{% endblock %} + +{% block body %} + + An event you participate in has been updated. +
+
+
+ + {% if event.title %} + {{ event.title }}

+ {% else %} + Untitled

+ {% endif %} + + {% if event.location %} + Where: {{ event.location }}

+ {% endif %} + + + When: {{ (event.from - (user_timezone_delay*60)) | date('F j, Y, g:i a') }} + - {{ (event.to - (user_timezone_delay*60)) | date('F j, Y, g:i a') }} ({{ user_timezone_text }})

+ + Invited by: {{ sender_fullname }} {{ sender_email }}

+ +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/event_notification.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/event_notification.html.twig new file mode 100755 index 00000000..b9165267 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/event_notification.html.twig @@ -0,0 +1,30 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}πŸ“… Twake, {{ text }}{% endblock %} + +{% block secondtitle %}Twake, {{ text }}{% endblock %} + +{% block body %} + + Hello from Twake πŸ‘‹,
+ you have an event soon ! +
+
+
+ + {% if event.title %} + {{ event.title }}

+ {% else %} + Untitled

+ {% endif %} + + {% if event.location %} + Where: {{ event.location }}

+ {% endif %} + + + When: in {{ delay }}

+ +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/inviteToWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/inviteToWorkspaceMail.html.twig new file mode 100755 index 00000000..6c4e9a63 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/inviteToWorkspaceMail.html.twig @@ -0,0 +1,35 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}You have been invited in the workspace {{ workspace }} {% endblock %} + +{% block secondtitle %}You have been invited in the workspace {{ workspace }} of the group {{ group }}{% endblock %} + +{% block body %} + + Hello, +
+ {{ sender_user|capitalize }} ({{ sender_user_mail }}) just invited you in the workspace + {{ workspace }} from the group {{ group }}. +

+ +
+
+ + Join workspace now ! + +
+
{{ twakeappurl|trim('/') }}/login?subscribe&mail={{ mail }} +
+
+
+
+ + We invite you to create a new account because we do not know this e-mail address. +
+
+ If you already have a Twake account, add + {{ mail }} in the list of your e-mail addresses, you will be automatically added to this workspace. + + +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/messages_notifications.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/messages_notifications.html.twig new file mode 100755 index 00000000..97dc3c96 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/messages_notifications.html.twig @@ -0,0 +1,34 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}You have {{ total_notifications }} unread message(s) on Twake{% endblock %} + +{% block secondtitle %}πŸ”” You have {{ total_notifications }} unread message(s) on Twake{% endblock %} + +{% block body %} + + Hello {{ username|capitalize }}, +
+ You have {{ total_notifications }} unread message(s) on Twake. +

+ Last messages : + + {% for notification in notifications %} +
+ {{ notification.delay }} hour(s) ago + {{ notification.title }}
+ {{ notification.text }} +
+ {% endfor %} + +
+
+ + Ouvrir Twake + +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/newMember.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/newMember.html.twig new file mode 100755 index 00000000..c29243db --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/newMember.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}Welcome on Twake !{% endblock %} + +{% block secondtitle %}Welcome on Twake !{% endblock %} + +{% block body %} + + Hello {{ username|capitalize }}, +
+ Welcome on Twake, if you need any help, please contact support at contact@twakeapp.com . +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/notification.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/notification.html.twig new file mode 100755 index 00000000..f9e7abb9 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/notification.html.twig @@ -0,0 +1,16 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}Twake, new notification from {{ application_name }} in {{ workspace_name }}{% endblock %} + +{% block secondtitle %}Twake, new notification from {{ application_name }} in {{ workspace_name }}{% endblock %} + +{% block body %} + + Hello {{ username|capitalize }}, +
+ You have a new notification from {{ application_name }} in the workspace {{ workspace_name }} +

+ {{ text }} +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/removedFromWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/removedFromWorkspaceMail.html.twig new file mode 100755 index 00000000..3152377d --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/removedFromWorkspaceMail.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}You have been removed from the workspace {{ workspace }}.{% endblock %} + +{% block secondtitle %}You have been removed from the workspace {{ workspace }}.{% endblock %} + +{% block body %} + + Hello {{ username|capitalize }}, +
+ You have been removed from the workspace {{ workspace }} in the group {{ group }}. +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/requestPassword.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/requestPassword.html.twig new file mode 100755 index 00000000..227054d4 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/requestPassword.html.twig @@ -0,0 +1,20 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %} Your request for a new password {% endblock %} + +{% block secondtitle %} Your request for a new password {% endblock %} + +{% block body %} + + Hello {{ username|capitalize }}, +
+ You requested a new password, there is the activation code you need : +
+
+
+
+ {{ code }} +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/subscribeMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/subscribeMail.html.twig new file mode 100755 index 00000000..0e958607 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/subscribeMail.html.twig @@ -0,0 +1,21 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}E-mail confirmation{% endblock %} + +{% block secondtitle %}E-mail confirmation{% endblock %} + +{% block body %} + + Welcome to Twake ! +
+ In order to create your account, you can click on this link : +
+ {{ twakeappurl|trim('/') }}{{ magic_link }} +
+
+ By clicking on this link you agree to the terms + of use of twake. +

+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/task_notification.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/task_notification.html.twig new file mode 100755 index 00000000..5ab0ce4f --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/task_notification.html.twig @@ -0,0 +1,26 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}πŸ“‹ Twake, {{ text }}{% endblock %} + +{% block secondtitle %}Twake, {{ text }}{% endblock %} + +{% block body %} + + Hello from Twake πŸ‘‹,
+ you have a task remind ! +
+
+
+ + {% if task.title %} + {{ task.title }}

+ {% else %} + Untitled

+ {% endif %} + + + When: in {{ delay }}

+ +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/unread_notifications.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/unread_notifications.html.twig new file mode 100755 index 00000000..2c4924da --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/unread_notifications.html.twig @@ -0,0 +1,33 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}You have unread notifications on Twake{% endblock %} + +{% block secondtitle %}You have unread notifications on Twake{% endblock %} + +{% block body %} + + Hello {{ username|capitalize }}, +
+ You have unread notifications waiting for you on Twake. +

+ Last notifications : + + {% for notification in notifications %} +
+ {{ notification.delay }} hour(s) ago + {{ notification.title }}
+ {{ notification.text }} +
+ {% endfor %} + +
+
+ + Open Twake + +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/addMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/addMail.html.twig new file mode 100755 index 00000000..b43d74ff --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/addMail.html.twig @@ -0,0 +1,20 @@ +{% extends "Mail/fr/all.html.twig" %} + +{% block title %}Confirmer votre nouvelle adresse e-mail{% endblock %} + +{% block secondtitle %}Confirmer votre nouvelle adresse e-mail{% endblock %} + +{% block body %} + + Bonjour {{ username|capitalize }}, +
+ Pour ajouter cet e-mail Γ  votre compte, utilisez ce code : +
+
+
+
+ {{ code }} +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/addedToGroupManagersMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/addedToGroupManagersMail.html.twig new file mode 100755 index 00000000..eec12667 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/addedToGroupManagersMail.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/fr/all.html.twig" %} + +{% block title %}Vous avez Γ©tΓ© ajoutΓ© aux managers du groupe {{ group }}{% endblock %} + +{% block secondtitle %}Vous avez Γ©tΓ© ajoutΓ© aux managers du groupe {{ group }}{% endblock %} + +{% block body %} + + Bonjour {{ username|capitalize }}, +
+ Vous avez Γ©tΓ© nommΓ© gΓ©rant du groupe {{ group }}. +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/addedToWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/addedToWorkspaceMail.html.twig new file mode 100755 index 00000000..fcae1c12 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/addedToWorkspaceMail.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/fr/all.html.twig" %} + +{% block title %}Vous avez Γ©tΓ© ajoutΓ© Γ  l'espace de travail {{ workspace }} !{% endblock %} + +{% block secondtitle %}Vous avez Γ©tΓ© ajoutΓ© Γ  l'espace de travail {{ workspace }} !{% endblock %} + +{% block body %} + + Bonjour {{ username|capitalize }}, +
+ Vous avez Γ©tΓ© ajoutΓ© Γ  l'espace de travail {{ workspace }} dans le groupe {{ group }}. +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/all.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/all.html.twig new file mode 100755 index 00000000..e1e839bd --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/all.html.twig @@ -0,0 +1,52 @@ +{% extends "Mail/all_style.html.twig" %} + +{% block content %} + + + + + + + +
+ +
{% block secondtitle %}Bonjour !{% endblock %}
+ + {% block body %}{% endblock %} + +

+ A très bientôt sur Twake, +
+ L'Γ©quipe Twake +
+ {{ twakeurl }} + +
+ + + +{% endblock %} diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/changeLevelWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/changeLevelWorkspaceMail.html.twig new file mode 100755 index 00000000..77fad844 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/changeLevelWorkspaceMail.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/fr/all.html.twig" %} + +{% block title %}Votre statut dans {{ workspace }} a changΓ©{% endblock %} + +{% block secondtitle %}Votre statut dans {{ workspace }} a changΓ©{% endblock %} + +{% block body %} + + Bonjour {{ username|capitalize }}, +
+ Votre statut dans {{ workspace }} (groupe {{ group }}) a Γ©tΓ© modifiΓ© en {{ level }} +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/event_notification.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/event_notification.html.twig new file mode 100755 index 00000000..9c528af9 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/event_notification.html.twig @@ -0,0 +1,30 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}πŸ“… Twake, {{ text }}{% endblock %} + +{% block secondtitle %}Twake, {{ text }}{% endblock %} + +{% block body %} + + Bonjour depuis Twake πŸ‘‹, + vous avez bientΓ΄t un Γ©vΓ©nement ! +
+
+
+ + {% if event.title %} + {{ event.title }}

+ {% else %} + Untitled

+ {% endif %} + + {% if event.location %} + OΓΉ: {{ event.location }}

+ {% endif %} + + + Quand: in {{ delay }}

+ +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/inviteToWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/inviteToWorkspaceMail.html.twig new file mode 100755 index 00000000..84b776f6 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/inviteToWorkspaceMail.html.twig @@ -0,0 +1,34 @@ +{% extends "Mail/fr/all.html.twig" %} + +{% block title %}Vous avez Γ©tΓ© invitΓ© dans l'espace de travail {{ workspace }} {% endblock %} + +{% block secondtitle %}Vous avez Γ©tΓ© invitΓ© dans l'espace de travail {{ workspace }} du groupe {{ group }}{% endblock %} + +{% block body %} + + Bonjour, +
+ Vous avez Γ©tΓ© invitΓ© par {{ sender_user|capitalize }} ({{ sender_user_mail }}) dans l'espace de travail + {{ workspace }} du groupe {{ group }}. +

+ +
+
+ + Rejoindre l'espace de travail + +
+
{{ twakeappurl|trim('/') }}/login?subscribe&mail={{ mail }} +
+
+
+
+ + Nous vous invitons Γ  crΓ©er un nouveau compte car nous ne connaissons pas cette adresse e-mail. +
+
+ Si vous avez dΓ©jΓ  un compte Twake, ajoutez + {{ mail }} dans la liste de vos adresse mails, vous serez alors automatiquement ajoutΓ© Γ  cet espace de travail. + +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/messages_notifications.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/messages_notifications.html.twig new file mode 100755 index 00000000..60ca99ff --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/messages_notifications.html.twig @@ -0,0 +1,35 @@ +{% extends "Mail/fr/all.html.twig" %} + +{% block title %}Vous avez {{ total_notifications }} message(s) non lue(s) sur Twake{% endblock %} + +{% block secondtitle %}πŸ”” Vous avez {{ total_notifications }} message(s) non lue(s) sur Twake{% endblock %} + +{% block body %} + + Bonjour {{ username|capitalize }}, +
+ Vous avez reΓ§u {{ total_notifications }} message(s) sur Twake. +

+ Vos messages : + + {% for notification in notifications %} +
+ il y a {{ notification.delay }} + heure(s) + {{ notification.title }}
+ {{ notification.text }} +
+ {% endfor %} + +
+
+ + Ouvrir Twake + +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/newMember.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/newMember.html.twig new file mode 100755 index 00000000..6784938b --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/newMember.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/fr/all.html.twig" %} + +{% block title %}Bienvenue sur Twake !{% endblock %} + +{% block secondtitle %}Bienvenue sur Twake !{% endblock %} + +{% block body %} + + Bonjour {{ username|capitalize }}, +
+ Bienvenue sur Twake, si vous avez besoin d'aide, n'hΓ©sitez pas Γ  contacter le support Γ  contact@twakeapp.com . +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/notification.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/notification.html.twig new file mode 100755 index 00000000..9c1988b3 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/notification.html.twig @@ -0,0 +1,17 @@ +{% extends "Mail/fr/all.html.twig" %} + +{% block title %}Twake, nouvelle notification de {{ application_name }} dans {{ workspace_name }}{% endblock %} + +{% block secondtitle %}Twake, nouvelle notification {{ application_name }} dans {{ workspace_name }}{% endblock %} + +{% block body %} + + Bonjour {{ username|capitalize }}, +
+ Vous avez une nouvelle notification de l'application {{ application_name }} dans l'espace de travail + {{ workspace_name }} +

+ {{ text }} +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/removedFromWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/removedFromWorkspaceMail.html.twig new file mode 100755 index 00000000..f327afc5 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/removedFromWorkspaceMail.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/fr/all.html.twig" %} + +{% block title %}Vous avez Γ©tΓ© retirΓ© de l'espace de travail {{ workspace }}.{% endblock %} + +{% block secondtitle %}Vous avez Γ©tΓ© retirΓ© de l'espace de travail {{ workspace }}.{% endblock %} + +{% block body %} + + Bonjour {{ username|capitalize }}, +
+ Vous avez Γ©tΓ© supprimΓ© de l'espace de travail {{ workspace }} dans le groupe {{ group }}. +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/requestPassword.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/requestPassword.html.twig new file mode 100755 index 00000000..962a85b2 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/requestPassword.html.twig @@ -0,0 +1,20 @@ +{% extends "Mail/fr/all.html.twig" %} + +{% block title %} Votre demande de nouveau mot de passe {% endblock %} + +{% block secondtitle %} Votre demande de nouveau mot de passe {% endblock %} + +{% block body %} + + Bonjour {{ username|capitalize }}, +
+ Vous avez demandΓ© un nouveau mot de passe, voici le code d'activation dont vous avez besoin : +
+
+
+
+ {{ code }} +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/subscribeMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/subscribeMail.html.twig new file mode 100755 index 00000000..81cedb3f --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/subscribeMail.html.twig @@ -0,0 +1,20 @@ +{% extends "Mail/fr/all.html.twig" %} + +{% block title %}E-mail confirmation{% endblock %} + +{% block secondtitle %}E-mail confirmation{% endblock %} + +{% block body %} + + Bienvenue sur Twake ! +
+ Pour terminer votre inscription, cliquez sur ce lien : +
+ {{ twakeappurl|trim('/') }}{{ magic_link }} +

+ En cliquant sur ce lien, vous acceptez les + condition d'utilisation de Twake. +

+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/task_notification.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/task_notification.html.twig new file mode 100755 index 00000000..bc0a186b --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/task_notification.html.twig @@ -0,0 +1,26 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}πŸ“‹ Twake, {{ text }}{% endblock %} + +{% block secondtitle %}Twake, {{ text }}{% endblock %} + +{% block body %} + + Bonjour depuis Twake πŸ‘‹, + vous avez un rappel de tΓ’che ! +
+
+
+ + {% if task.title %} + {{ task.title }}

+ {% else %} + Untitled

+ {% endif %} + + + Quand: in {{ delay }}

+ +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/unread_notifications.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/unread_notifications.html.twig new file mode 100755 index 00000000..86f89db0 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/unread_notifications.html.twig @@ -0,0 +1,34 @@ +{% extends "Mail/fr/all.html.twig" %} + +{% block title %}Vous avez des notifications non lues sur Twake{% endblock %} + +{% block secondtitle %}Vous avez des notifications non lues sur Twake{% endblock %} + +{% block body %} + + Bonjour {{ username|capitalize }}, +
+ Vous avez des notifications qui vous attendent sur Twake. +

+ Dernières notifications : + + {% for notification in notifications %} +
+ il y a {{ notification.delay }} + heure(s) + {{ notification.title }}
+ {{ notification.text }} +
+ {% endfor %} + +
+
+ + Ouvrir Twake + +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/addMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/addMail.html.twig new file mode 100755 index 00000000..d3f5b9ed --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/addMail.html.twig @@ -0,0 +1,20 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ ΡΠ»Π΅ΠΊΡ‚Ρ€ΠΎΠ½Π½ΡƒΡŽ ΠΏΠΎΡ‡Ρ‚Ρƒ{% endblock %} + +{% block secondtitle %}ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ ΡΠ»Π΅ΠΊΡ‚Ρ€ΠΎΠ½Π½ΡƒΡŽ ΠΏΠΎΡ‡Ρ‚Ρƒ{% endblock %} + +{% block body %} + + ЗдравствуйтС {{ username|capitalize }}, +
+ Π§Ρ‚ΠΎΠ±Ρ‹ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ эту ΡΠ»Π΅ΠΊΡ‚Ρ€ΠΎΠ½Π½ΡƒΡŽ ΠΏΠΎΡ‡Ρ‚Ρƒ Π² свой Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ этот ΠΊΠΎΠ΄. : +
+
+
+
+ {{ code }} +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/addedToGroupManagersMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/addedToGroupManagersMail.html.twig new file mode 100755 index 00000000..e2a8e443 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/addedToGroupManagersMail.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}Π’Ρ‹ Π±Ρ‹Π»ΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Ρ‹ ΠΊ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€Π°ΠΌ Π³Ρ€ΡƒΠΏΠΏΡ‹ {{ group }}{% endblock %} + +{% block secondtitle %}Π’Ρ‹ Π±Ρ‹Π»ΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Ρ‹ ΠΊ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€Π°ΠΌ Π³Ρ€ΡƒΠΏΠΏΡ‹ {{ group }}{% endblock %} + +{% block body %} + + ЗдравствуйтС {{ username|capitalize }}, +
+ Π’Ρ‹ Π±Ρ‹Π»ΠΈ Π½Π°Π·Π½Π°Ρ‡Π΅Π½Ρ‹ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€ΠΎΠΌ Π³Ρ€ΡƒΠΏΠΏΡ‹ {{ group }}. +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/addedToWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/addedToWorkspaceMail.html.twig new file mode 100755 index 00000000..046e7814 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/addedToWorkspaceMail.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}Π’Ρ‹ Π±Ρ‹Π»ΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Ρ‹ Π² Ρ€Π°Π±ΠΎΡ‡Π΅Π΅ пространство {{ workspace }} !{% endblock %} + +{% block secondtitle %}Π’Ρ‹ Π±Ρ‹Π»ΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Ρ‹ Π² Ρ€Π°Π±ΠΎΡ‡Π΅Π΅ пространство {{ workspace }} !{% endblock %} + +{% block body %} + + ЗдравствуйтС {{ username|capitalize }}, +
+ Π’Ρ‹ Π±Ρ‹Π»ΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Ρ‹ Π² Ρ€Π°Π±ΠΎΡ‡Π΅Π΅ пространство {{ workspace }} Π² Π³Ρ€ΡƒΠΏΠΏΠ΅ {{ group }}. +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/all.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/all.html.twig new file mode 100755 index 00000000..7e47f1b2 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/all.html.twig @@ -0,0 +1,53 @@ +{% extends "Mail/all_style.html.twig" %} + +{% block content %} + + + + + + + +
+ +
{% block secondtitle %}Hello !{% endblock %}
+ + {% block body %}{% endblock %} + +

+ Π”ΠΎ встрСчи Π² Twake, +
+ ΠΊΠΎΠΌΠ°Π½Π΄Π° Twake +
+ {{ twakeurl }} + +
+ + + +{% endblock %} + diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/changeLevelWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/changeLevelWorkspaceMail.html.twig new file mode 100755 index 00000000..a5930ec9 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/changeLevelWorkspaceMail.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}Π’Π°Ρˆ статус Π² {{ workspace }} измСнился{% endblock %} + +{% block secondtitle %}Π’Π°Ρˆ статус Π² {{ workspace }} измСнился{% endblock %} + +{% block body %} + + ЗдравствуйтС {{ username|capitalize }}, +
+ Π’Π°Ρˆ статус Π² {{ workspace }} (group {{ group }}) Π±Ρ‹Π» ΠΈΠ·ΠΌΠ΅Π½Ρ‘Π½ Π½Π° {{ level }} +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/event_invitation.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/event_invitation.html.twig new file mode 100755 index 00000000..28433c1d --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/event_invitation.html.twig @@ -0,0 +1,33 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}πŸ“… Twake, вас пригласили Π½Π° ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅ мСроприятиС.{% endblock %} + +{% block secondtitle %}Twake, вас пригласили Π½Π° ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅ мСроприятиС.{% endblock %} + +{% block body %} + + Π’Ρ‹ Π±Ρ‹Π»ΠΈ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½Ρ‹ Π½Π° ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅ мСроприятиС. +
+
+
+ + {% if event.title %} + {{ event.title }}

+ {% else %} + Π‘Π΅Π· названия

+ {% endif %} + + {% if event.location %} + Π“Π΄Π΅: {{ event.location }}

+ {% endif %} + + + Когда: {{ (event.from - (user_timezone_delay*60)) | date('F j, Y, g:i a') }} + - {{ (event.to - (user_timezone_delay*60)) | date('F j, Y, g:i a') }} ({{ user_timezone_text }})

+ + ΠŸΡ€ΠΈΠ³Π»Π°ΡˆΡ‘Π½Π½Ρ‹ΠΉ: {{ sender_fullname }} {{ sender_email }}

+ +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/event_invitation_updated.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/event_invitation_updated.html.twig new file mode 100755 index 00000000..b7ddf439 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/event_invitation_updated.html.twig @@ -0,0 +1,33 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}πŸ“… Twake, мСроприятиС Π±Ρ‹Π»ΠΎ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΎ.{% endblock %} + +{% block secondtitle %}Twake, мСроприятиС Π±Ρ‹Π»ΠΎ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΎ.{% endblock %} + +{% block body %} + + ΠœΠ΅Ρ€ΠΎΠΏΡ€ΠΈΡΡ‚ΠΈΠ΅, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π²Ρ‹ участвуСтС, Π±Ρ‹Π»ΠΎ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΎ. +
+
+
+ + {% if event.title %} + {{ event.title }}

+ {% else %} + Π‘Π΅Π· названия

+ {% endif %} + + {% if event.location %} + Π“Π΄Π΅: {{ event.location }}

+ {% endif %} + + + Когда: {{ (event.from - (user_timezone_delay*60)) | date('F j, Y, g:i a') }} + - {{ (event.to - (user_timezone_delay*60)) | date('F j, Y, g:i a') }} ({{ user_timezone_text }})

+ + ΠŸΡ€ΠΈΠ³Π»Π°ΡˆΡ‘Π½Π½Ρ‹ΠΉ: {{ sender_fullname }} {{ sender_email }}

+ +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/event_notification.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/event_notification.html.twig new file mode 100755 index 00000000..6056edb4 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/event_notification.html.twig @@ -0,0 +1,30 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}πŸ“… Twake, {{ text }}{% endblock %} + +{% block secondtitle %}Twake, {{ text }}{% endblock %} + +{% block body %} + + ЗдравствуйтС ΠΎΡ‚ Twake πŸ‘‹,
+ Ρƒ вас скоро мСроприятиС ! +
+
+
+ + {% if event.title %} + {{ event.title }}

+ {% else %} + Π‘Π΅Π· названия

+ {% endif %} + + {% if event.location %} + Π“Π΄Π΅: {{ event.location }}

+ {% endif %} + + + Когда: in {{ delay }}

+ +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/inviteToWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/inviteToWorkspaceMail.html.twig new file mode 100755 index 00000000..ca169e1e --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/inviteToWorkspaceMail.html.twig @@ -0,0 +1,35 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}You have been invited in the workspace {{ workspace }} {% endblock %} + +{% block secondtitle %}You have been invited in the workspace {{ workspace }} of the group {{ group }}{% endblock %} + +{% block body %} + + ЗдравствуйтС, +
+ {{ sender_user|capitalize }} ({{ sender_user_mail }}) Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‡Ρ‚ΠΎ пригласил вас Π½Π° Ρ€Π°Π±ΠΎΡ‡Π΅Π΅ пространство + {{ workspace }} Π² Π³Ρ€ΡƒΠΏΠΏΠ΅ {{ group }}. +

+ +
+
+ + ΠŸΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒΡΡ ΠΊ Ρ€Π°Π±ΠΎΡ‡Π΅ΠΌΡƒ пространству сСйчас ! + +
+
{{ twakeappurl|trim('/') }}/login?subscribe&mail={{ mail }} +
+
+
+
+ + ΠŸΡ€ΠΈΠ³Π»Π°ΡˆΠ°Π΅ΠΌ Вас ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²Ρ‹ΠΉ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΌΡ‹ Π½Π΅ Π·Π½Π°Π΅ΠΌ этого адрСса элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹. +
+
+ Если Ρƒ вас ΡƒΠΆΠ΅ Π΅ΡΡ‚ΡŒ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ Twake, Π΄ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ + {{ mail }} Π² спискС Π²Π°ΡˆΠΈΡ… адрСсов элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹, Π²Ρ‹ Π±ΡƒΠ΄Π΅Ρ‚Π΅ автоматичСски Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Ρ‹ Π² это Ρ€Π°Π±ΠΎΡ‡Π΅Π΅ пространство. + + +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/messages_notifications.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/messages_notifications.html.twig new file mode 100755 index 00000000..6379e998 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/messages_notifications.html.twig @@ -0,0 +1,34 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}Π£ вас {{ total_notifications }} Π½Π΅ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π½Π½Ρ‹ΠΉ(Ρ…) сообщСниС(я) Π² Twake{% endblock %} + +{% block secondtitle %}πŸ”” Π£ вас {{ total_notifications }} Π½Π΅ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π½Π½Ρ‹ΠΉ(Ρ…) сообщСниС(я) Π² Twake{% endblock %} + +{% block body %} + + ЗдравствуйтС {{ username|capitalize }}, +
+ Π£ вас {{ total_notifications }} Π½Π΅ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π½Π½Ρ‹ΠΉ(Ρ…) сообщСниС(я) Π² Twake. +

+ ПослСдниС сообщСния : + + {% for notification in notifications %} +
+ {{ notification.delay }} hour(s) ago + {{ notification.title }}
+ {{ notification.text }} +
+ {% endfor %} + +
+
+ + ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ Twake + +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/newMember.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/newMember.html.twig new file mode 100755 index 00000000..fbf2cd05 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/newMember.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}Π”ΠΎΠ±Ρ€ΠΎ ΠΏΠΎΠΆΠ°Π»ΠΎΠ²Π°Ρ‚ΡŒ Π² Twake !{% endblock %} + +{% block secondtitle %}Π”ΠΎΠ±Ρ€ΠΎ ΠΏΠΎΠΆΠ°Π»ΠΎΠ²Π°Ρ‚ΡŒ Π² Twake !{% endblock %} + +{% block body %} + + ЗдравствуйтС {{ username|capitalize }}, +
+ Π”ΠΎΠ±Ρ€ΠΎ ΠΏΠΎΠΆΠ°Π»ΠΎΠ²Π°Ρ‚ΡŒ Π² Twake, Ссли Π²Π°ΠΌ Π½ΡƒΠΆΠ½Π° ΠΏΠΎΠΌΠΎΡ‰ΡŒ, поТалуйста, ΡΠ²ΡΠΆΠΈΡ‚Π΅ΡΡŒ со слуТбой ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ ΠΏΠΎ адрСсу contact@twakeapp.com . +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/notification.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/notification.html.twig new file mode 100755 index 00000000..0320fa4e --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/notification.html.twig @@ -0,0 +1,16 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}Twake, Π½ΠΎΠ²ΠΎΠ΅ ΡƒΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠ΅ ΠΎΡ‚ {{ application_name }} Π² {{ workspace_name }}{% endblock %} + +{% block secondtitle %}Twake, Π½ΠΎΠ²ΠΎΠ΅ ΡƒΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠ΅ ΠΎΡ‚ {{ application_name }} Π² {{ workspace_name }}{% endblock %} + +{% block body %} + + ЗдравствуйтС {{ username|capitalize }}, +
+ Π£ вас Π΅ΡΡ‚ΡŒ Π½ΠΎΠ²ΠΎΠ΅ ΡƒΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠ΅ ΠΎΡ‚ {{ application_name }} Π² Ρ€Π°Π±ΠΎΡ‡Π΅ΠΌ пространствС {{ workspace_name }} +

+ {{ text }} +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/removedFromWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/removedFromWorkspaceMail.html.twig new file mode 100755 index 00000000..998b4e31 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/removedFromWorkspaceMail.html.twig @@ -0,0 +1,14 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}Π’Ρ‹ Π±Ρ‹Π»ΠΈ ΡƒΠ΄Π°Π»Π΅Π½Ρ‹ ΠΈΠ· Ρ€Π°Π±ΠΎΡ‡Π΅Π³ΠΎ пространства {{ workspace }}.{% endblock %} + +{% block secondtitle %}Π’Ρ‹ Π±Ρ‹Π»ΠΈ ΡƒΠ΄Π°Π»Π΅Π½Ρ‹ ΠΈΠ· Ρ€Π°Π±ΠΎΡ‡Π΅Π³ΠΎ пространства {{ workspace }}.{% endblock %} + +{% block body %} + + ЗдравствуйтС {{ username|capitalize }}, +
+ Π’Ρ‹ Π±Ρ‹Π»ΠΈ ΡƒΠ΄Π°Π»Π΅Π½Ρ‹ ΠΈΠ· Ρ€Π°Π±ΠΎΡ‡Π΅Π³ΠΎ пространства {{ workspace }} Π² Π³Ρ€ΡƒΠΏΠΏΠ΅ {{ group }}. +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/requestPassword.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/requestPassword.html.twig new file mode 100755 index 00000000..55afe1a4 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/requestPassword.html.twig @@ -0,0 +1,20 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %} Π’Π°Ρˆ запрос Π½ΠΎΠ²ΠΎΠ³ΠΎ пароля {% endblock %} + +{% block secondtitle %} Π’Π°Ρˆ запрос Π½ΠΎΠ²ΠΎΠ³ΠΎ пароля {% endblock %} + +{% block body %} + + ЗдравствуйтС {{ username|capitalize }}, +
+ Π’Ρ‹ запросили Π½ΠΎΠ²Ρ‹ΠΉ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ, Π²ΠΎΡ‚ ΠΊΠΎΠ΄ Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π²Π°ΠΌ Π½ΡƒΠΆΠ΅Π½ : +
+
+
+
+ {{ code }} +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/subscribeMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/subscribeMail.html.twig new file mode 100755 index 00000000..7a1792b9 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/subscribeMail.html.twig @@ -0,0 +1,21 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΏΠΎ элСктронной ΠΏΠΎΡ‡Ρ‚Π΅{% endblock %} + +{% block secondtitle %}ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΏΠΎ элСктронной ΠΏΠΎΡ‡Ρ‚Π΅{% endblock %} + +{% block body %} + + Π”ΠΎΠ±Ρ€ΠΎ ΠΏΠΎΠΆΠ°Π»ΠΎΠ²Π°Ρ‚ΡŒ Π² Twake ! +
+ Для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ свой Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚, Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π½Π°ΠΆΠ°Ρ‚ΡŒ Π½Π° эту ссылку: +
+ {{ twakeappurl|trim('/') }}{{ magic_link }} +
+
+ ΠŸΠ΅Ρ€Π΅ΠΉΠ΄Ρ ΠΏΠΎ этой ссылкС, Π²Ρ‹ ΡΠΎΠ³Π»Π°ΡˆΠ°Π΅Ρ‚Π΅ΡΡŒ с условиями + использования twake. +

+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/task_notification.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/task_notification.html.twig new file mode 100755 index 00000000..007bdb8f --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/task_notification.html.twig @@ -0,0 +1,26 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}πŸ“‹ Twake, {{ text }}{% endblock %} + +{% block secondtitle %}Twake, {{ text }}{% endblock %} + +{% block body %} + + ЗдравствуйтС ΠΎΡ‚ Twake πŸ‘‹,
+ Π½Π°ΠΏΠΎΠΌΠΈΠ½Π°Π½ΠΈΠ΅ ΠΎ Π·Π°Π΄Π°Ρ‡Π΅! +
+
+
+ + {% if task.title %} + {{ task.title }}

+ {% else %} + Π‘Π΅Π· названия

+ {% endif %} + + + Когда: in {{ delay }}

+ +
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/unread_notifications.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/unread_notifications.html.twig new file mode 100755 index 00000000..acb7cc34 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/unread_notifications.html.twig @@ -0,0 +1,33 @@ +{% extends "Mail/en/all.html.twig" %} + +{% block title %}Π£ вас Π΅ΡΡ‚ΡŒ Π½Π΅ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π½Π½Ρ‹Π΅ увСдомлСния Π² Twake{% endblock %} + +{% block secondtitle %}Π£ вас Π΅ΡΡ‚ΡŒ Π½Π΅ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π½Π½Ρ‹Π΅ увСдомлСния Π² Twake{% endblock %} + +{% block body %} + + ЗдравствуйтС {{ username|capitalize }}, +
+ Π£ вас Π΅ΡΡ‚ΡŒ Π½Π΅ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π½Π½Ρ‹Π΅ увСдомлСния, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΆΠ΄ΡƒΡ‚ вас Π² Twake.. +

+ ПослСдниС увСдомлСния : + + {% for notification in notifications %} +
+ {{ notification.delay }} hour(s) ago + {{ notification.title }}
+ {{ notification.text }} +
+ {% endfor %} + +
+
+ + ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ Twake + +
+
+ +{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Services/AccessManager.php b/twake/backend/core/src/Twake/Core/Services/AccessManager.php new file mode 100755 index 00000000..1077bc09 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/AccessManager.php @@ -0,0 +1,267 @@ +app = $app; + $this->rest = $app->getServices()->get("app.restclient"); + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->memberservice = $app->getServices()->get("app.workspace_members"); + $this->emojione_client = new Client(new Ruleset()); + } + + public function has_access($current_user_id, $data, $options = null) + { + if ($current_user_id && !is_string($current_user_id)) { + $current_user_id = $current_user_id->getId(); + } + + $type = @$data["type"]; + $edition = @$data["edition"]; //TODO test if we have edition access (everybodyhas edition acess for now) + $id = @$data["object_id"]; + + + //FONCTION POUR SAVOIR SI UN UTILISATEUR A ACCES A QUELQUE CHOSE + + + if ($type == "Workspace") { + if (!$this->user_has_workspace_access($current_user_id, $id)) { + return false; + } + } else if ($type == "Channel") { + + //Use new node backend for this and cache result + $userId = $current_user_id; + $channelId = $id; + + $getChannelCache = false; + $channelDetails = $this->doctrine->getRepository("Twake\Core:CachedFromNode")->findOneBy(Array("company_id" => "unused", "type" => "channel", "key"=>$channelId)); + if($channelDetails){ + $companyId = $channelDetails->getData()["company_id"]; + $workspaceId = $channelDetails->getData()["workspace_id"]; + if($channelDetails->getData()["last_update"] < date("U") - 0 * 60 * 60){ + $getChannelCache = true; + } + }else{ + $getChannelCache = true; + } + $getChannelCache = true; + + if($options["company_id"] && $options["workspace_id"]){ + $companyId = $options["company_id"]; + $workspaceId = $options["workspace_id"]; + } + + $cacheKey = $userId."_".$channelId; + $data = $this->doctrine->getRepository("Twake\Core:CachedFromNode")->findOneBy(Array("company_id" => "unused", "type" => "access_channel", "key"=>$cacheKey)); + if(!$data || !$data->getData()["has_access"]){ + + try{ + + $res = $this->callNode( + "companies/".$companyId."/workspaces/".$workspaceId."/". + "channels/".$channelId."/members/".$userId."/exists" + ); + + try{ + + if($res && isset($res["has_access"])){ + + $hasAccess = $res["has_access"] == true; + + if($getChannelCache){ + $this->getChannelCache($companyId, $workspaceId, $channelId); + } + + } + + }catch(\Exception $err){ + error_log($err); + } + + $cache = new CachedFromNode("unknown", "access_channel", $cacheKey, [ + "has_access" => $hasAccess + ]); + $this->doctrine->persist($cache); + $this->doctrine->flush(); + + return $hasAccess; + + + }catch(\Exception $err){ + error_log($err); + } + + return false; + } + + return true; + + } else if ($type == "Message") { + $message = $this->doctrine->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $id)); + if (isset($message)) { + $message = $message->getAsArray(); + $channel_id = $message["channel_id"]; + $data = Array("type" => "Channel", "object_id" => $channel_id); + if (!$this->has_access($current_user_id, $data)) { + return false; + } + } else { + return false; + } + } else if ($type == "DriveFile") { //Read parent id and detached from file to get access + + if ($id == "root" || $id == "trash" || $id == "") { + if (!$data["workspace_id"]) { + return false; + } + return $this->has_access($current_user_id, Array("type" => "Workspace", "object_id" => $data["workspace_id"])); + } + + if (!$id) { + return false; + } + $df = $this->doctrine->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $id)); + + if ($df) { + + $df = $df->getAsArray(); + $workspace_id = $df["workspace_id"]; + + // Public access token + if (!empty($df["acces_info"]["token"]) && !empty($options["token"]) && $df["acces_info"]["token"] != $options["token"]) { + return false; + } + if (isset($df["acces_info"]["token"]) && $df["acces_info"]["token"] == "" && isset($options["token"]) && $options["token"] == "") { + return false; + } + if (isset($df["acces_info"]["token"]) && isset($options["token"]) && $df["acces_info"]["token"] == $options["token"]) { + return true; + } + + //In this case only members authorized can see the directory + if (isset($df["acces_info"]["authorized_members"]) && is_array($df["acces_info"]["authorized_members"])) { + if (in_array($current_user_id, $df["acces_info"]["authorized_members"])) { + return true; + } else { + return false; + } + } + + //In this case defined has special access authorization + if (isset($df["acces_info"]["authorized_channels"]) && is_array($df["acces_info"]["authorized_channels"])) { + $channels = $df["acces_info"]["authorized_channels"]; + $access = false; + foreach ($channels as $channel) { + $data = Array("type" => "Channel", "object_id" => $channel); + if ($this->has_access($current_user_id, $data)) { + $access = true; + } + } + if ($access) { + return true; + } + } + + //Access to workspace + if (!$workspace_id) { + return true; + } else { + if ($this->user_has_workspace_access($current_user_id, $data["workspace_id"] ?: $workspace_id)) { + return true; + } + } + + } + + return false; + + } else if ($type == "Calendar") { //pensez au parent id tous ca tous ca et a detached + $calendar = $this->doctrine->getRepository("Twake\Calendar:Calendar")->findOneBy(Array("id" => $id)); + if (isset($calendar)) { + $calendar = $calendar->getAsArray(); + $workspace_id = $calendar["workspace_id"]; + if (!$this->user_has_workspace_access($current_user_id, $workspace_id)) { + return false; + } + } else { + return false; + } + } + + + return true; + } + + public function user_has_workspace_access($current_user_id, $workspace_id) + { + return $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser")->findOneBy(Array("workspace_id" => $workspace_id, "user_id" => $current_user_id)); + } + + private function callNode($route){ + $secret = $this->app->getContainer()->getParameter("node.secret"); + $uri = $this->app->getContainer()->getParameter("node.api") . + $route; + + $res = $this->rest->get($uri, [ + CURLOPT_HTTPHEADER => Array( + "Authorization: Token ".$secret, + "Content-Type: application/json" + ), + CURLOPT_CONNECTTIMEOUT => 1, + CURLOPT_TIMEOUT => 1 + ]); + $res = $res->getContent(); + $res = json_decode($res, 1); + return $res; + } + + public function getChannelCache($companyId, $workspaceId, $channelId){ + $path = "companies/".$companyId + ."/workspaces/".$workspaceId."/" + ."channels/".$channelId; + + if(!$workspaceId){ + $path = "companies/".$companyId + ."/channels/".$channelId; + } + + $resChannel = $this->callNode($path); + + $name = $resChannel["icon"] . " " . $resChannel["name"]; + if($resChannel["workspace_id"] === "direct"){ + $name = ""; + } + + $name = html_entity_decode($this->emojione_client->shortnameToUnicode($name), ENT_NOQUOTES, 'UTF-8'); + + $workspaceId = $workspaceId ?: $resChannel["workspace_id"]; + + $workspace = $this->doctrine->getRepository("Twake\Workspaces:Workspace")->findOneBy(Array("id" => $workspaceId)); + $group = $this->doctrine->getRepository("Twake\Workspaces:Group")->findOneBy(Array("id" => $companyId)); + $workspaceName = $workspace ? $workspace->getName() : ""; + $companyName = $group ? $group->getDisplayName() : ""; + + $cacheChannel = new CachedFromNode("unused", "channel", $resChannel["id"], [ + "company_id" => $resChannel["company_id"], + "workspace_id" => $resChannel["workspace_id"], + "channel_id" => $resChannel["id"], + "is_direct" => $resChannel["workspace_id"] === "direct", + "name" => $name, + "workspace_name" => $workspaceName, + "company_name" => $companyName, + "last_update" => date("U") + ]); + $this->doctrine->persist($cacheChannel); + $this->doctrine->flush(); + } + +} diff --git a/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Driver/PDOCassandra/CassandraConnection.php b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Driver/PDOCassandra/CassandraConnection.php new file mode 100755 index 00000000..6a256876 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Driver/PDOCassandra/CassandraConnection.php @@ -0,0 +1,540 @@ +list = $list; + $this->pointer = 0; + } + + public function next() + { + $this->pointer++; + } + + public function rewind() + { + $this->pointer = 0; + } + + public function current() + { + if (!$this->list || !isset($this->list[$this->pointer])) { + return null; + } + return $this->list[$this->pointer]; + } + + public function count() + { + return count($this->list); + } + + public function isLastPage() + { + return true; + } + +} + +class PDOStatementAdapter +{ + + public function __construct() + { + $this->values = Array(); + $this->data = null; + } + + public function setQuery($query, $executor) + { + $this->executor = $executor; + $this->query = $query; + } + + public function setData($data) + { + $this->data = $data; + } + + public function setFetchMode($mode) + { + } + + public function fetchColumn($position) + { + $res = $this->data->current(); + $this->data->next(); + $res = $res[array_keys($res)[$position]]; + return $this->stripslashesCell($res); + } + + protected function stripslashesCell($obj = "") + { + if (is_string($obj)) { + $obj = stripslashes($obj); + } + return $obj; + } + + public function fetchAll($fetch_style, $fetch_argument = null, $ctor_args = array()) + { + $res = Array(); + + while ($row) { + $row = $this->fetch(); + if ($row) { + $res[] = $row; + } + } + + return $res; + } + + public function fetch() + { + if (!$this->data) { + return null; + } + $res = $this->data->current(); + $this->data->next(); + + if (!$this->data->current() && !$this->data->isLastPage()) { + $this->data = $this->data->nextPage(); + } + + return $this->stripslashesRow($res); + } + + protected function stripslashesRow($obj = Array()) + { + if (!is_array($obj)) { + return $obj; + } + foreach ($obj as $key => $value) { + $obj[$key] = $this->stripslashesCell($value); + } + return $obj; + } + + public function rowCount() + { + if (!$this->data) { + return 0; + } + $res = $this->data->count(); + return $res; + } + + public function bindValue($parameter, $value, $type) + { + $this->types[$parameter] = $type; + $this->values[$parameter] = $value; + } + + public function execute($parameters = Array()) + { + $query = $this->query; + + //lowercase columns + $query = preg_replace_callback('/ ([a-zA-Z0-9_]+ +)AS /', function ($match) { + return ' ' . strtolower($match[1]) . ' AS '; + }, $query); + $query = preg_replace_callback('/ ([a-zA-Z0-9_]+ +)([^a-zA-Z0-9_]{1,2}) *\?/', function ($match) { + return ' ' . strtolower($match[1]) . ' ' . $match[2] . ' ?'; + }, $query); + + $query_explode = explode("?", $query); + $query = ""; + + $there_is_a_counter = false; + + foreach ($query_explode as $position => $query_part) { + + if ($position == count($query_explode) - 1) { + + $query .= $query_explode[count($query_explode) - 1]; + + } else { + + $value = $this->values[$position + 1]; + + if ($this->types[$position + 1] == "twake_boolean") { + $value = (!$value) ? "0" : "1"; //Cassandra booleans are tiny ints + } else if ($this->types[$position + 1] == "twake_bigint") { + $value = intval($value); + } else if ($this->types[$position + 1] == "twake_counter") { + $there_is_a_counter = $position; + preg_match("/([a-z_]+) *= *$/", $query_part, $matches); + if (isset($matches[1])) { + $column_name = $matches[1]; + if ($value > 0) { + $value = $column_name . " + " . $value; + } else { + $value = $column_name . " - " . $value; + } + } else { + $value = $value; + } + } else if ($value == NULL && !is_string($value)) { + $value = "NULL"; + } else if ($this->types[$position + 1] == \PDO::PARAM_INT || $this->types[$position + 1] == "twake_timeuuid" || $this->types[$position + 1] == "twake_uuid" || $this->types[$position + 1] == "twake_bigint") { + if ($value . "" != "" && preg_replace("/[0-9]/", "", $value) == "") { + $value = $value; + } else if (preg_match('/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/', $value)) { + $value = $value; + } else { + $value = "00000000-0000-1000-0000-000000000000"; + } + } else if (is_string($value) || (is_object($value) && method_exists($value, 'toCqlString')) || $this->types[$position + 1] == "twake_string") { + $value = addslashes($value); + $value = str_replace("'", "''", $value); + $value = "'" . $value . "'"; + } + + $query .= $query_part . "" . $value; + + } + } + + $query = preg_replace("/ +IS +NULL( |$)/", " = NULL ", $query); + + + if ($there_is_a_counter !== false && preg_match("/^INSERT/", $query)) { + + //Change INSERTS to UPDATES + $pos = $there_is_a_counter; + preg_match("/^ *INSERT +INTO +([a-z_]+) +\(([a-z_ ,]+)\) +values +\((.*)\) *$/", $query, $matches); + $table = $matches[1]; + $parameters = explode(",", $matches[2]); + $values = explode(",", $matches[3]); + $increment_value = $values[$pos]; + if ($increment_value >= 0) { + $increment_value = " + " . intval($increment_value); + } + $new_query = "UPDATE " . $table . " SET " . $parameters[$pos] . " = " . $parameters[$pos] . " " . $increment_value . " WHERE "; + + $first = true; + foreach ($parameters as $k => $parameter) { + if ($k != $pos) { + if (!$first) $new_query .= " AND "; + $new_query .= $parameter . " = " . $values[$k]; + $first = false; + } + } + + $query = $new_query; + + } + + try { + $this->executor->exec($query, $this); + } catch (\Exception $e) { + $message = "SCYLLADB > AN ERROR OCCURED WITH THIS QUERY : " . preg_replace("/AS .* FROM/", "AS [...] FROM", $query); + error_log($message); + error_log($e); + } + + } + + public function closeCursor() + { + + } + +} + +class CassandraConnection +{ + + private $use_ttl = null; + /** @var App */ + private $app = null; + + public function __construct($keyspace, $username, $password, $driverOptions) + { + + $this->cluster = Cassandra::cluster() + ->withContactPoints($driverOptions["host"]); + + if ($driverOptions["ssl"]) { + $ssl = Cassandra::ssl() + ->withTrustedCerts($driverOptions["ssl"]["node_certificate"]) + ->withVerifyFlags(Cassandra::VERIFY_PEER_CERT) + ->build(); + $this->cluster = $this->cluster + ->withSSL($ssl); + } + + if ($driverOptions["port"]) { + $this->cluster = $this->cluster + ->withPort($driverOptions["port"]); + } + + if ($driverOptions["user"]) { + $this->cluster = $this->cluster + ->withCredentials($driverOptions["user"], $driverOptions["password"]); + } + + $this->cluster = $this->cluster + ->build(); + + try { + $this->session = $this->cluster->connect(strtolower($keyspace)); + } catch (\Exception $e) { + $this->session = $this->cluster->connect(); + + error_log("Prepare keyspace creation"); + + $statement = new Cassandra\SimpleStatement( + "CREATE KEYSPACE IF NOT EXISTS " . strtolower($keyspace) . " WITH replication = " . ($driverOptions["replication"] ?: "{'class': 'SimpleStrategy', 'replication_factor': '1'}") + ); + $future = $this->session->executeAsync($statement); + $future->get(); + + error_log("Did create keyspace"); + + $this->session = $this->cluster->connect(strtolower($keyspace)); + } + + $this->keyspace = $keyspace; + $this->view_to_use = null; + } + + public function setApp(App $app) + { + $this->app = $app; + } + + public function changeTableToView($view_to_use) + { + $this->view_to_use = $view_to_use; + } + + public function useTTLOnFirstInsert($ttl) + { + $this->use_ttl = $ttl; + } + + public function getSchema() + { + return $this->session->schema(); + } + + public function getKeyspace() + { + return $this->keyspace; + } + + public function beginTransaction() + { + return true; + } + + public function commit() + { + return true; + } + + public function rollBack() + { + return true; + } + + function prepare($prepareString) + { + $prepareString = $this->removeTableAlias($prepareString); + $prepareString_cql = $this->normalizeCount($prepareString); + $prepareString = new PDOStatementAdapter(); + $prepareString->setQuery($prepareString_cql, $this); + return $prepareString; + } + + /** + * Cassandra does not support table alias. Let's remove them + */ + private function removeTableAlias($sql) + { + //clean up extra space + $sql = trim(preg_replace('/\s+/', ' ', $sql)); + $arrSplitByFROM = explode('FROM ', $sql, 2); + if (count($arrSplitByFROM) >= 2) { + $arrSplit4TableAlias = explode(' ', trim($arrSplitByFROM[1]), 3); + if (count($arrSplit4TableAlias) >= 2 + && strtoupper($arrSplit4TableAlias[1]) != 'WHERE') { + //replace table alias and merge stuff + $alias = $arrSplit4TableAlias[1]; + $arrSplit4TableAlias[1] = ''; + $arrSplitByFROM[0] = str_replace($alias . '.', '', $arrSplitByFROM[0]); + $arrSplitByFROM[1] = implode(' ', $arrSplit4TableAlias); + $arrSplitByFROM[1] = str_replace($alias . '.', '', $arrSplitByFROM[1]); + return implode('FROM ', $arrSplitByFROM); + } + + } + return $sql; + } + + /** + * For COUNT(), Cassandra only allows two formats: COUNT(1) and COUNT(*) + */ + private function normalizeCount($sql) + { + $sql = trim(preg_replace('/COUNT\(.*\)/i', 'COUNT(1)', $sql)); + return $sql; + } + + public function exec($cql, $pdoStatement = null) + { + return $this->query($cql, $pdoStatement); + } + + /** + * {@inheritdoc}non-PHPdoc) + */ + public function query($cql = null, $pdoStatement = null) + { + if ($this->app) $this->app->getCounter()->startTimer("cql_time"); + if ($this->app) $is_cassandra = $this->app->getContainer()->getParameter("db.is_cassandra", false); + + $view_to_use = false; + if ($this->view_to_use) { + $view_to_use = $this->view_to_use . "_custom_index"; + if($is_cassandra){ + $view_to_use = "index_".md5($view_to_use); + } + } + $this->view_to_use = null; + + if ($view_to_use) { + $_cql = preg_replace("/ FROM [a-z_\-0-9]+ /", " FROM " . $view_to_use . " ", $cql); + $_cql = preg_replace("/ *SELECT .* FROM /", "SELECT * FROM ", $_cql); + + $results = $this->query($_cql, $pdoStatement); + $row = true; + $ids = []; + $list = []; + while ($row) { + $row = $results->fetch(\PDO::FETCH_ASSOC); + if ($row && isset($row["id"])) { + $ids[] = $row["id"]->uuid(); + } + } + foreach ($ids as $id) { + $__cql = preg_replace("/ WHERE .*$/", " WHERE id = " . $id, $cql); + $result = $this->query($__cql, $pdoStatement)->fetch(\PDO::FETCH_ASSOC); + $list[] = $result; + } + + if (!$pdoStatement) { + $pdo = new PDOStatementAdapter(); + } else { + $pdo = $pdoStatement; + } + + + $pdo->setData(new FakeCassandraRows($list)); + if ($this->app) $this->app->getCounter()->stopTimer("cql_time"); + + return $pdo; + + } else { + + $sql = $this->removeTableAlias($cql); + $sql = $this->normalizeCount($sql); + $sql = $this->removeCQLUnallowedKeys($sql); + if ($this->use_ttl && $this->use_ttl > 0) { + $sql = $this->addTTL($sql, $this->use_ttl); + } + $this->use_ttl = null; + + if ($sql == "SELECT uuid()") { + $sql = "select now() from system.local"; + } + + if ($this->app) $this->app->getCounter()->incrementCounter("cql_requests"); + + $future = $this->session->executeAsync($sql); + if (!$pdoStatement) { + $pdo = new PDOStatementAdapter(); + } else { + $pdo = $pdoStatement; + } + + + $rows = $future->get(); + $pdo->setData($rows); + + if ($this->app) $this->app->getCounter()->stopTimer("cql_time"); + + return $pdo; + + } + } + + private function removeCQLUnallowedKeys($sql) + { + + $keys = Array( + "token", + "from", + "to", + "default" + ); + + $sql = explode('FROM ', $sql, 2); + if (isset($sql[1])) { //There is a FROM + foreach ($keys as $key) { + $sql[0] = preg_replace('/([^a-z_-])' . preg_quote($key, '/') . '([^a-z_-])/', '$1"' . $key . '"$2', $sql[0]); + } + } + $sql = join("FROM ", $sql); + + $sql = explode(') VALUES ', $sql, 2); + if (isset($sql[1])) { //There is a FROM + foreach ($keys as $key) { + $sql[0] = preg_replace('/([^a-z_-])' . preg_quote($key, '/') . '([^a-z_-])/', '$1"' . $key . '"$2', $sql[0]); + } + } + $sql = join(") VALUES ", $sql); + + $sql = explode('WHERE ', $sql, 2); + if (isset($sql[1])) { //There is a WHERE + $sql[1] = " " . $sql[1]; + foreach ($keys as $key) { + $sql[1] = preg_replace('/([^a-z_-])' . preg_quote($key, '/') . ' *=/', '$1"' . $key . '" =', $sql[1]); + } + } + $sql = join("WHERE ", $sql); + + + foreach ($keys as $key) { + $sql = preg_replace('/\(' . preg_quote($key, '/') . '\)/', '("' . $key . '")', $sql); + } + + + return $sql; + } + + private function addTTL($sql, $ttl) + { + if (!$ttl || intval($ttl) < 1) { + return; + } + if (strpos($sql, "INSERT ") === 0) { + $sql = preg_replace("/; *$/", "", $sql); + $sql = $sql . " USING TTL " . intval($ttl) . " "; + $sql = $sql . ";"; + } + return $sql; + } + + +} diff --git a/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Driver/PDOCassandra/Driver.php b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Driver/PDOCassandra/Driver.php new file mode 100755 index 00000000..07fbae70 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Driver/PDOCassandra/Driver.php @@ -0,0 +1,80 @@ +cassandra_connection = $conn; + return $conn; + } + + public function getConnection() + { + return $this->cassandra_connection; + } + + public function getDatabasePlatform() + { + return new CassandraPlatform(); + } + + public function getSchemaManager(\Doctrine\DBAL\Connection $conn) + { + return new CassandraSchemaManager($conn); + } + + public function getName() + { + return 'pdo_cassandra'; + } + + public function getDatabase(\Doctrine\DBAL\Connection $conn) + { + $params = $conn->getParams(); + + if (isset($params['dbname'])) { + return $params['dbname']; + } + return null; + } + + private function _constructPdoDsn(array $params) + { + $dsn = 'cassandra:'; + $arrHosts = array(); + $arrPorts = array(); + if (isset($params['host']) && $params['host'] != '') { + $arrHosts = explode(',', $params['host']); + } + if (isset($params['port'])) { + $arrPorts = explode(',', $params['port']); + } + for ($i = 0; $i < count($arrHosts); $i++) { + $dsn .= 'host=' . $arrHosts[$i] . ';'; + $dsn .= 'port=' . $arrPorts[$i]; + $dsn .= ($i == count($arrHosts) - 1) ? ';' : ','; + } + if (isset($params['cqlversion'])) { + $dsn .= 'cqlversion=' . $params['cqlversion'] . ';'; + } + return $dsn; + } +} diff --git a/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/DriverManager.php b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/DriverManager.php new file mode 100755 index 00000000..c360fb63 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/DriverManager.php @@ -0,0 +1,143 @@ + 'Twake\Core\Services\DoctrineAdapter\DBAL\Driver\PDOCassandra\Driver', + ); + + public static function getConnection( + array $params, + Configuration $config = null, + EventManager $eventManager = null) + { + // create default config and event manager, if not set + if (!$config) { + $config = new Configuration(); + } + if (!$eventManager) { + $eventManager = new EventManager(); + } + + $params = self::parseDatabaseUrl($params); + + // check for existing pdo object + if (isset($params['pdo']) && !$params['pdo'] instanceof \PDO) { + throw DBALException::invalidPdoInstance(); + } else if (isset($params['pdo'])) { + $params['pdo']->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + $params['driver'] = 'pdo_' . $params['pdo']->getAttribute(\PDO::ATTR_DRIVER_NAME); + } else { + self::_checkParams($params); + } + if (isset($params['driverClass'])) { + $className = $params['driverClass']; + } else { + $className = self::$_driverMap[$params['driver']]; + } + + $driver = new $className(); + + $wrapperClass = 'Doctrine\DBAL\Connection'; + if (isset($params['wrapperClass'])) { + if (is_subclass_of($params['wrapperClass'], $wrapperClass)) { + $wrapperClass = $params['wrapperClass']; + } else { + throw DBALException::invalidWrapperClass($params['wrapperClass']); + } + } + if (self::$instance === null) { + self::$instance = 1; + //add new types + foreach ($params["twake_types"] as $name => $class) { + Type::addType($name, $class); + } + } + + return new $wrapperClass($params, $driver, $config, $eventManager); + } + + private static function parseDatabaseUrl(array $params) + { + if (!isset($params['url'])) { + return $params; + } + + // (pdo_)?sqlite3?:///... => (pdo_)?sqlite3?://localhost/... or else the URL will be invalid + $url = preg_replace('#^((?:pdo_)?sqlite3?):/' . '/' . '/#', '$1:/' . '/localhost/', $params['url']); + + $url = parse_url($url); + + if ($url === false) { + throw new DBALException('Malformed parameter "url".'); + } + + if (isset($url['scheme'])) { + $params['driver'] = str_replace('-', '_', $url['scheme']); // URL schemes must not contain underscores, but dashes are ok + } + + if (isset($url['host'])) { + $params['host'] = $url['host']; + } + if (isset($url['port'])) { + $params['port'] = $url['port']; + } + if (isset($url['user'])) { + $params['user'] = $url['user']; + } + if (isset($url['pass'])) { + $params['password'] = $url['pass']; + } + + if (isset($url['path'])) { + if (!isset($url['scheme']) || (strpos($url['scheme'], 'sqlite') !== false && $url['path'] == ':memory:')) { + $params['dbname'] = $url['path']; // if the URL was just "sqlite::memory:", which parses to scheme and path only + } else { + $params['dbname'] = substr($url['path'], 1); // strip the leading slash from the URL + } + } + + if (isset($url['query'])) { + $query = array(); + parse_str($url['query'], $query); // simply ingest query as extra params, e.g. charset or sslmode + $params = array_merge($params, $query); // parse_str wipes existing array elements + } + + return $params; + } + + private static function _checkParams(array $params) + { + // check existence of mandatory parameters + + // driver + if (!isset($params['driver']) && !isset($params['driverClass'])) { + throw DBALException::driverRequired(); + } + + // check validity of parameters + + // driver + if (isset($params['driver']) && !isset(self::$_driverMap[$params['driver']])) { + throw DBALException::unknownDriver($params['driver'], array_keys(self::$_driverMap)); + } + + if (isset($params['driverClass']) && !in_array('Doctrine\DBAL\Driver', class_implements($params['driverClass'], true))) { + throw DBALException::invalidDriverClass($params['driverClass']); + } + } + + public static function getAvailableDrivers() + { + return array_keys(self::$_driverMap); + } +} diff --git a/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Platforms/CassandraPlatform.php b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Platforms/CassandraPlatform.php new file mode 100755 index 00000000..8ad3fa46 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Platforms/CassandraPlatform.php @@ -0,0 +1,242 @@ +_getCommonIntegerTypeDeclarationSQL($field); + } + + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) + { + return ''; + } + + public function getBigIntTypeDeclarationSQL(array $field) + { + return 'bigint' . $this->_getCommonIntegerTypeDeclarationSQL($field); + } + + public function getSmallIntTypeDeclarationSQL(array $field) + { + return 'int' . $this->_getCommonIntegerTypeDeclarationSQL($field); + } + + public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) + { + return ''; + } + + public function getName() + { + return 'cassandra'; + } + + public function getReadLockSQL() + { + return ''; + } + + public function supportsTransactions() + { + return false; + } + + public function getColumnDeclarationSQL($name, array $field) + { + if (isset($field['columnDefinition'])) { + $columnDef = $this->getCustomTypeDeclarationSQL($field); + } else { + $default = $this->getDefaultValueDeclarationSQL($field); + $check = (isset($field['check']) && $field['check']) ? + ' ' . $field['check'] : ''; + + /** @var \Doctrine\DBAL\Types\Type $type */ + $type = $field['type']; + $typeDecl = $type->getSqlDeclaration($field, $this); + $columnDef = $typeDecl; + } + + return $name . ' ' . $columnDef; + } + + public function getVarcharMaxLength() + { + return 65535; + } + + protected function doModifyLimitQuery($query, $limit, $offset) + { + if ($limit !== null) { + $query .= ' LIMIT ' . $limit; + } + return $query; + } + + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + return 'varchar'; + } + + protected function getReservedKeywordsClass() + { + return 'Twake\Core\Services\DoctrineAdapter\DBAL\Platforms\Keywords\CassandraKeywords'; + } + + protected function _getCreateTableSQL($tableName, array $columns, array $options = array()) + { + $queryFields = $this->getColumnDeclarationListSQL($columns); + + // attach all primary keys + if (isset($options['primary']) && !empty($options['primary'])) { + $keyColumns = array_unique(array_values($options['primary'])); + $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')'; + } + + $query = 'CREATE TABLE ' . $tableName . ' (' . $queryFields . ') '; + $sql[] = $query; + return $sql; + } + + /** + * http://doctrine-orm.readthedocs.org/en/latest/reference/basic-mapping.html + */ + protected function initializeDoctrineTypeMappings() + { + $this->doctrineTypeMapping = array( + 'ascii' => 'string', + 'bigint' => 'bigint', + 'blob' => 'blob', + 'boolean' => 'boolean', + 'counter' => 'bigint', + 'decimal' => 'decimal', + 'double' => 'twake_float', + 'float' => 'twake_float', + 'inet' => 'string', + 'int' => 'integer', + 'list' => 'object', + 'map' => 'string', + 'set' => 'string', + 'text' => 'string', + 'timestamp' => 'twake_datetime', + 'timeuuid' => 'guid', + 'tuple' => 'object', + 'uuid' => 'guid', + 'varchar' => 'string', + 'varint' => 'bigint' + ); + } + +} diff --git a/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Platforms/Keywords/CassandraKeywords.php b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Platforms/Keywords/CassandraKeywords.php new file mode 100755 index 00000000..b8e30f98 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Platforms/Keywords/CassandraKeywords.php @@ -0,0 +1,83 @@ +_platform->getDoctrineTypeMapping($dbType); + $options = array(); + return new Column($tableColumn['field'], Type::getType($type), $options); + } +} diff --git a/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Types/CassandraBigIntType.php b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Types/CassandraBigIntType.php new file mode 100755 index 00000000..dd85d7b5 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Types/CassandraBigIntType.php @@ -0,0 +1,16 @@ +value(); + } + + $res = false; + try { + $res = ((!$value) ? false : true); + } catch (\Exception $e) { + } + + return $res; + } + + /** + * It's best to let PDO driver guess the binding type rather than forcing to string + */ + public function getBindingType() + { + return "twake_boolean"; + } +} diff --git a/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Types/CassandraCounterType.php b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Types/CassandraCounterType.php new file mode 100755 index 00000000..df292649 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Types/CassandraCounterType.php @@ -0,0 +1,25 @@ +getDateTimeFormatString(), $value); + if (!$val) { + $value = $this->getDateStringFromHex($value); + $val = \DateTime::createFromFormat($platform->getDateTimeFormatString(), $value); + } + if (!$val) { + throw ConversionException::conversionFailedFormat($value, $this->getName(), $platform->getDateTimeFormatString()); + } + + return $val; + } + + /** + * @param $str + * @return bool|string + */ + public function getDateStringFromHex($str) + { + if (is_numeric("" . $str)) { + $time = intval("" . $str) / 1000; + return date('Y-m-d H:i:s', $time); + } else { + $date = unpack('H*', $str); + $time = hexdec($date[1]) / 1000; + return date('Y-m-d H:i:s', $time); + } + } + + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + + if ($value === null || is_string($value)) { + return $value; + } + + $val = null; + + if ($value instanceof \DateTime) { + $val = $value->format($platform->getDateTimeFormatStringToDatabase()); + } + + if (!$val) { + throw ConversionException::conversionFailedFormat( + $value, + $this->getName(), + $platform->getDateTimeFormatStringToDatabase() + ); + } + + return $val; + } + + +} diff --git a/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Types/CassandraFloatType.php b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Types/CassandraFloatType.php new file mode 100755 index 00000000..fcf7895c --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Types/CassandraFloatType.php @@ -0,0 +1,17 @@ +getVarcharTypeDeclarationSQL( + array( + 'length' => '42' + ) + ); + } + + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if (empty($value)) { + return null; + } + + if ($value instanceof UuidInterface) { + return $value; + } + + try { + return parent::convertToPHPValue(hex2bin(str_replace("-", "", $value)), $platform); + } catch (InvalidArgumentException $e) { + throw ConversionException::conversionFailed($value, self::NAME); + } + } + + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + if (empty($value)) { + return null; + } + + try { + if (is_string($value) || method_exists($value, '__toString') || $value instanceof UuidInterface) { + $value = bin2hex(parent::convertToDatabaseValue($value, $platform)); + if(!preg_match("/[^a-f0-9-]/", $value)){ + return $value; + }else{ + return null; + } + } + } catch (InvalidArgumentException $e) { + // Ignore the exception and pass through. + } + + throw ConversionException::conversionFailed($value, self::NAME); + } + +} + + + diff --git a/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Types/MysqlUUIDType.php b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Types/MysqlUUIDType.php new file mode 100755 index 00000000..046f7437 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DBAL/Types/MysqlUUIDType.php @@ -0,0 +1,37 @@ +secretKey = $key; + $this->iv = "twake_constantiv"; + } + + public function convertToPHPValue($original_data, AbstractPlatform $platform) + { + $data = $this->v2Decrypt($original_data); + if(!$data["done"]){ + $data = $this->v1Decrypt($original_data); + } + if(!$data["done"]){ + $data = ["data" => $this->legacyDecrypt($original_data)]; + } + return $data["data"]; + } + + public function convertToDatabaseValue($data, AbstractPlatform $platform) + { + if (!$data) { + return $data; + } + + if ($this->searchable) { + $iv = $this->iv; + $salt = ""; + } else { + $iv = openssl_random_pseudo_bytes(16); + $salt = bin2hex(openssl_random_pseudo_bytes(16)); + } + + $encoded = "encrypted_" . trim( + base64_encode( + openssl_encrypt( + $data, + "AES-256-CBC", + $this->secretKey . $salt, + true, + $iv + ) + ) + ); + + if (!$this->searchable) { + $encoded .= "_" . $salt . "_" . base64_encode($iv); + } + + return $encoded; + + } + + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return "TEXT"; + } + + public function v2Decrypt($data){ + $key = substr(hash("sha256", unpack("H*", $this->secretKey)[1]), 0, 32); + $encryptedArray = explode(":", $data); + + if (!count($encryptedArray) || count($encryptedArray) !== 3) { + return [ + "data" => $data, + "done" => false, + ]; + } + + $iv = base64_decode($encryptedArray[0]); + if ($encryptedArray[0] === "0000000000000000") { + $iv = "0000000000000000"; + } + + try { + $tag = base64_decode($encryptedArray[1]); + $str = openssl_decrypt(base64_decode($encryptedArray[2]), 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag); + $decrypt = json_decode($str); + + return [ + "data" => $decrypt, + "done" => true, + ]; + } catch (Error $err) { + return [ + "data" => $data, + "done" => false, + ]; + } + } + + public function v1Decrypt($data){ + $key = substr(base64_encode(hash("sha256", unpack("H*", $this->secretKey)[1], true)), 0, 32); + $encryptedArray = explode(":", $data); + + if (!count($encryptedArray) || count($encryptedArray) !== 2) { + return [ + "data" => $data, + "done" => false, + ]; + } + + try { + + $iv = @hex2bin($encryptedArray[0]); + if ($encryptedArray[0] === "0000000000000000") { + $iv = "0000000000000000"; + } + + $str = openssl_decrypt(@hex2bin($encryptedArray[1]), 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); + $decrypt = json_decode($str); + + return [ + "data" => $decrypt, + "done" => true, + ]; + } catch (Error $err) { + return [ + "data" => $data, + "done" => false, + ]; + } + } + + public function legacyDecrypt($original_data){ + if (substr($original_data, 0, 10) == "encrypted_") { + $data = substr($original_data, 10); + $data = explode("_", $data); + $salt = isset($data[1]) ? $data[1] : ""; + $iv = isset($data[2]) ? base64_decode($data[2]) : $this->iv; + $data = base64_decode($data[0]); + try { + $data = openssl_decrypt( + $data, + "AES-256-CBC", + $this->secretKey . $salt, + true, + $iv + ); + } catch (\Exception $e) { + $data = $original_data; + } + } else { + $data = $original_data; + } + + return $data; + } + +} diff --git a/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DoctrineServiceProvider.php b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DoctrineServiceProvider.php new file mode 100755 index 00000000..47ddc3f2 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/DoctrineServiceProvider.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Twake\Core\Services\DoctrineAdapter; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; +use Doctrine\DBAL\DriverManager; +use Doctrine\DBAL\Configuration; +use Doctrine\Common\EventManager; + +class DoctrineServiceProvider implements ServiceProviderInterface +{ + public function register(Container $app) + { + $app['db.default_options'] = [ + 'driver' => 'pdo_mysql', + 'dbname' => null, + 'host' => 'localhost', + 'user' => 'root', + 'password' => null, + ]; + + $app['dbs.options.initializer'] = $app->protect(function () use ($app) { + static $initialized = false; + + if ($initialized) { + return; + } + + $initialized = true; + + if (!isset($app['dbs.options'])) { + $app['dbs.options'] = ['default' => isset($app['db.options']) ? $app['db.options'] : []]; + } + + $tmp = $app['dbs.options']; + foreach ($tmp as $name => &$options) { + $options = array_replace($app['db.default_options'], $options); + + if (!isset($app['dbs.default'])) { + $app['dbs.default'] = $name; + } + } + $app['dbs.options'] = $tmp; + }); + + $app['dbs'] = function ($app) { + $app['dbs.options.initializer'](); + + $dbs = new Container(); + foreach ($app['dbs.options'] as $name => $options) { + if ($app['dbs.default'] === $name) { + // we use shortcuts here in case the default has been overridden + $config = $app['db.config']; + $manager = $app['db.event_manager']; + } else { + $config = $app['dbs.config'][$name]; + $manager = $app['dbs.event_manager'][$name]; + } + + $dbs[$name] = function ($dbs) use ($options, $config, $manager) { + return DriverManager::getConnection($options, $config, $manager); + }; + } + + return $dbs; + }; + + $app['dbs.config'] = function ($app) { + $app['dbs.options.initializer'](); + + $configs = new Container(); + foreach ($app['dbs.options'] as $name => $options) { + $configs[$name] = new Configuration(); + } + + return $configs; + }; + + $app['dbs.event_manager'] = function ($app) { + $app['dbs.options.initializer'](); + + $managers = new Container(); + foreach ($app['dbs.options'] as $name => $options) { + $managers[$name] = new EventManager(); + } + + return $managers; + }; + + // shortcuts for the "first" DB + $app['db'] = function ($app) { + $dbs = $app['dbs']; + + return $dbs[$app['dbs.default']]; + }; + + $app['db.config'] = function ($app) { + $dbs = $app['dbs.config']; + + return $dbs[$app['dbs.default']]; + }; + + $app['db.event_manager'] = function ($app) { + $dbs = $app['dbs.event_manager']; + + return $dbs[$app['dbs.default']]; + }; + } +} diff --git a/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/FakeCassandraTimeuuid.php b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/FakeCassandraTimeuuid.php new file mode 100755 index 00000000..c6dd07e3 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/FakeCassandraTimeuuid.php @@ -0,0 +1,21 @@ +timeuuid = $timeuuid; + } + + public function __toString() + { + return $this->timeuuid; + } + + public function isNull() + { + return $this->timeuuid == "00000000-0000-1000-0000-000000000000"; + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/ManagerAdapter.php b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/ManagerAdapter.php new file mode 100755 index 00000000..7f25bc6f --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/ManagerAdapter.php @@ -0,0 +1,474 @@ +app = $app; + $this->doctrine_manager = $app->getProviders()->get("db"); + $this->database_configuration = Array( + "driver" => $app->getContainer()->getParameter("db.driver"), + "host" => $app->getContainer()->getParameter("db.host"), + "port" => $app->getContainer()->getParameter("db.port"), + "user" => $app->getContainer()->getParameter("db.user"), + "password" => $app->getContainer()->getParameter("db.password"), + "dbname" => $app->getContainer()->getParameter("db.dbname"), + "ssl" => $app->getContainer()->getParameter("db.ssl"), + "encryption_key" => $app->getContainer()->getParameter("db.encryption_key"), + "replication" => $app->getContainer()->getParameter("db.replication"), + ); + $this->dev_mode = true; // If false no entity generation + $this->manager = null; + + $this->circle = $app->getServices()->get("app.restclient"); + $this->es_server = $app->getContainer()->getParameter("es.host"); + $this->es_updates = Array(); + $this->es_removes = Array(); + $this->generator = null; + + if (!$this->es_server && !defined("ELASTICSEARCH_INSTALL_MESSAGE_SHOWED") && php_sapi_name() === 'cli') { + define("ELASTICSEARCH_INSTALL_MESSAGE_SHOWED", true); + error_log("INFO: Installation configured without elastic search"); + } + } + + public function clear() + { + return $this->getEntityManager()->clear(); + } + + public function getEntityManager() + { + + if ($this->manager) { + return $this->manager; + } + + if ($this->database_configuration["driver"] == "pdo_mysql") { + $driver_type = "Mysql"; + } else { + $driver_type = "Cassandra"; + } + + $paths = array($this->app->getAppRootDir() . "/src/"); + $isDevMode = $this->dev_mode; + $config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode, null, null, false); + + $config->setProxyDir($this->app->getAppRootDir() . '/cache/Doctrine/Proxies'); + + if ($isDevMode) { + $cache = new \Doctrine\Common\Cache\ArrayCache; + $config->setAutoGenerateProxyClasses(true); + } else { + $cache = new \Doctrine\Common\Cache\ApcuCache; + $config->setAutoGenerateProxyClasses(false); + } + + $config->setMetadataCacheImpl($cache); + $config->setQueryCacheImpl($cache); + + $conn = DriverManager::getConnection(Array( + 'driver' => $this->database_configuration["driver"], + 'host' => $this->database_configuration["host"], + 'port' => $this->database_configuration["port"], + 'dbname' => $this->database_configuration["dbname"], + 'user' => $this->database_configuration["user"], + 'password' => $this->database_configuration["password"], + 'ssl' => $this->database_configuration["ssl"], + 'twake_types' => Array( + 'twake_float' => 'Twake\Core\Services\DoctrineAdapter\DBAL\Types\\' . $driver_type . 'FloatType', + 'twake_datetime' => 'Twake\Core\Services\DoctrineAdapter\DBAL\Types\\' . $driver_type . 'DateTimeType', + 'twake_uuid' => 'Twake\Core\Services\DoctrineAdapter\DBAL\Types\\' . $driver_type . 'UUIDType', + 'twake_timeuuid' => 'Twake\Core\Services\DoctrineAdapter\DBAL\Types\\' . $driver_type . 'TimeUUIDType', + 'twake_boolean' => 'Twake\Core\Services\DoctrineAdapter\DBAL\Types\\' . $driver_type . 'BooleanType', + 'tinyint' => 'Twake\Core\Services\DoctrineAdapter\DBAL\Types\\TinyintType', + 'twake_no_salt_text' => 'Twake\Core\Services\DoctrineAdapter\DBAL\Types\\' . $driver_type . 'SearchableTextType', + 'twake_text' => 'Twake\Core\Services\DoctrineAdapter\DBAL\Types\\' . $driver_type . 'TextType', + 'twake_string' => 'Twake\Core\Services\DoctrineAdapter\DBAL\Types\\' . $driver_type . 'StringType', + 'twake_bigint' => 'Twake\Core\Services\DoctrineAdapter\DBAL\Types\\' . $driver_type . 'BigIntType', + 'twake_counter' => 'Twake\Core\Services\DoctrineAdapter\DBAL\Types\\' . $driver_type . 'CounterType' + ) + ), $config); + + $encryptedStringType = Type::getType('twake_text'); + $encryptedStringType->setEncryptionKey(pack("H*", $this->database_configuration["encryption_key"])); + + $searchableEncryptedStringType = Type::getType('twake_no_salt_text'); + $searchableEncryptedStringType->setEncryptionKey(pack("H*", $this->database_configuration["encryption_key"])); + + $entityManager = EntityManager::create($conn, $config); + + $this->manager = $entityManager; + + /** @var CassandraConnection */ + $cassandraConnection = $this->manager->getConnection()->getWrappedConnection(); + $cassandraConnection->setApp($this->app); + + return $this->manager; + } + + /** !Caution! : thin ttl will be used on the first insert in the next flush ! */ + public function useTTLOnFirstInsert($ttl) + { + $this->getManager()->getConnection()->getWrappedConnection()->useTTLOnFirstInsert($ttl); + } + + public function getManager() + { + return $this->getEntityManager(); + } + + public function flush() + { + //ElasticSearch + foreach ($this->es_removes as $es_remove) { + $this->es_remove($es_remove, $es_remove->getEsType(), $es_remove->getEsIndex()); + } + + $this->es_removes = Array(); + foreach ($this->es_updates as $id => $es_update) { + $this->es_put($es_update, $es_update->getEsType(), $es_update->getEsIndex()); + $es_update->updatePreviousIndexationArray(); + + } + + $this->es_updates = Array(); + + try { + $a = $this->manager->flush(); + } catch (\Exception $e) { + error_log($e); + error_log("ERROR FLUSH"); + die("ERROR with flush"); + } + + return $a; + } + + public function es_remove($entity, $index, $server = "twake") + { + + if (!$this->es_server) { + return; + } + + if (is_array($entity)) { + $id = $entity["id"]; + } else { + $id = $entity->getId(); + } + + $route = "http://" . $this->es_server . "/" . $index . "/_doc/" . $id; + + try { + $this->circle->delete($route, array(CURLOPT_CONNECTTIMEOUT => 1)); + } catch (\Exception $e) { + error_log("Unable to delete on ElasticSearch."); + } + } + + public function es_put($entity, $index, $server = "twake") + { + + if (!$this->es_server) { + return; + } + + if (is_array($entity)) { + $id = $entity["id"]; + $data = $entity["data"]; + if (!is_array($data)) { + $data = Array("content" => $data); + } + } else { + $id = $entity->getId() . ""; + if (method_exists($entity, "getIndexationArray")) { + $data = $entity->getIndexationArray(); + } + if (method_exists($entity, "getContentKeywords") && is_array($entity->getContentKeywords())) { + $keywords = $entity->getContentKeywords(); + //partie sur la verification du format des mots clΓ©s + $keywords_verif = Array(); + foreach ($keywords as $keyword_score) { + $keys = array_keys($keyword_score); + if (count($keys) != 2 || $keys[0] != "keyword" || $keys[1] != "score" || + gettype($keyword_score["keyword"]) != "string" || gettype($keyword_score["keyword"]) != "string") { + error_log("Wrong format for keyword data"); + } else { + $keywords_verif[] = $keyword_score; + } + } + + $name = $entity->getName(); + $keywords = $this->update_ES_keyword($keywords_verif, $name); + $data["keywords"] = $keywords; + + } + } + + $st = new StringCleaner(); + $data = $st->simplifyInArray($data); + $route = "http://" . $this->es_server . "/" . $index . "/_doc/" . $id; + + + try { + $this->circle->put($route, json_encode($data), array(CURLOPT_CONNECTTIMEOUT => 1, CURLOPT_TIMEOUT => 1, CURLOPT_HTTPHEADER => ['Content-Type: application/json'])); + } catch (\Exception $e) { + error_log("Unable to put on ElasticSearch."); + } + + } + + public function update_ES_keyword($keywords, $word) + { + + + $keywords[] = Array( + "keyword" => $word, + "score" => 1.1 + ); + return $keywords; + } + + public function remove($object) + { + if (!$object) { + return; + } + if (method_exists($object, "getEsIndexed")) { + //This is a searchable object + $this->es_removes[$object->getId() . ""] = $object; + unset($this->es_updates[$object->getId() . ""]); + } + return $this->getEntityManager()->remove($object); + } + + public function getReference($ent, $id) + { + $res = null; + try { + $res = $this->getEntityManager()->getReference($ent, $id); + } catch (\Exception $e) { + error_log($e); + die("ERROR with persist"); + } + + return $res; + } + + public function merge($object) + { + $res = null; + try { + $res = $this->getEntityManager()->merge($object); + } catch (\Exception $e) { + error_log($e); + die("ERROR with persist"); + } + + return $res; + } + + + /* Elastic Search */ + + //update for important keywords from title or extension of a file only in ES to not repeat info in scyllaDB + + public function persist($object) + { + + if (!$this->generator) { + $this->generator = new UuidOrderedTimeGenerator(); + } + if (method_exists($object, "getId") && (!$object->getId() || (is_object($object->getId()) && method_exists($object->getId(), "isNull") && $object->getId()->isNull()))) { + $object->setId($this->generator->generate($this->getEntityManager(), $object)); + } + + + if (method_exists($object, "getEsIndexed")) { + //This is a searchable object + if (method_exists($object, "getLock()")) { + if ($object->getLock() == true) { + $this->es_updates[$object->getId() . ""] = $object; + unset($this->es_removes[$object->getId() . ""]); + $object->setEsIndexed(true); + } + } else { + if (!$object->getEsIndexed() || $object->changesInIndexationArray()) { + $this->es_updates[$object->getId() . ""] = $object; + unset($this->es_removes[$object->getId() . ""]); + $object->setEsIndexed(true); + } + } + } + + $res = null; + try { + $res = $this->getEntityManager()->persist($object); + } catch (\Exception $e) { + error_log($e); + die("ERROR with persist"); + } + + return $res; + + } + + public function createQueryBuilder($qb = null) + { + return $this->getEntityManager()->createQueryBuilder($qb); + } + + function validateDate($date, $format = 'Y-m-d') + { + $d = DateTime::createFromFormat($format, $date); + // The Y ( 4 digits year ) returns TRUE for any integer with any number of digits so changing the comparison from == to === fixes the issue. + return $d && $d->format($format) === $date; + } + + public function es_search($options = Array(), $index = null, $server = "twake") + { + + if (isset($options["scroll_id"])) { + $route = "http://" . $this->es_server . "/_search/scroll"; + $res = $this->circle->post($route, json_encode(Array("scroll" => "5m", "scroll_id" => $options["scroll_id"])), array(CURLOPT_CONNECTTIMEOUT => 1, CURLOPT_TIMEOUT => 1, CURLOPT_HTTPHEADER => ['Content-Type: application/json'])); + } else { + if (!$this->es_server) { + + if (isset($options["repository"]) && isset($options["fallback_keys"])) { + $repository = $this->getRepository($options["repository"]); + + $filter = isset($options["fallback_filter"]) ? $options["fallback_filter"] : Array(); + $results = $repository->findBy($filter, Array(), 500); + + $entities = []; + + foreach ($results as $result) { + $match = false; + foreach ($options["fallback_keys"] as $key => $query) { + if (strtolower(trim($query)) && strpos(strtolower($result->getAsArray()[$key]), strtolower(trim($query))) !== false) { + $match = true; + } + } + if ($match && $result) { + $entities[] = [$result, 0]; + } + } + + return Array("result" => $entities); + } + return ["result" => []]; + } + if (isset($options["index"]) && !$type) { + $index = $options["index"]; + } + + + $route = "http://" . $this->es_server . "/" . $index . "/_doc/"; + $route .= "_search"; + $route .= "?scroll=5m"; //on spΓ©cifie un temps ou la recherche est active + + if (!isset($options["size"])) { + $options["size"] = 10; + } + + try { + if (isset($options["sort"])) { + $res = $this->circle->post($route, json_encode(Array("size" => $options["size"], "query" => $options["query"], "sort" => $options["sort"])), array(CURLOPT_CONNECTTIMEOUT => 1, CURLOPT_TIMEOUT => 1, CURLOPT_HTTPHEADER => ['Content-Type: application/json'])); + } else { + $res = $this->circle->post($route, json_encode(Array("size" => $options["size"], "query" => $options["query"])), array(CURLOPT_CONNECTTIMEOUT => 1, CURLOPT_TIMEOUT => 1, CURLOPT_HTTPHEADER => ['Content-Type: application/json'])); + } + + } catch (\Exception $e) { + error_log("Unable to post on ElasticSearch."); + } + } + + + $repository = null; + if (isset($options["repository"])) { + $repository = $this->getRepository($options["repository"]); + } + + if (!$res) { + return ["result" => []]; + } + + $res = $res->getContent(); + + $result = ["result" => []]; + $scroll_id = ""; + + if ($res) { + $res = json_decode($res, 1); + if ($res["hits"]["total"] > $options["size"] && isset($res["_scroll_id"])) { + //on a plus de 10 resultat et un ID il faut paginer + $scroll_id = $res["_scroll_id"]; + } + + $result = []; + if (isset($res["hits"]) && isset($res["hits"]["hits"])) { + $res = $res["hits"]["hits"]; + + foreach ($res as $object_json) { + if ($repository) { + $obj = $repository->findOneBy(Array("id" => $object_json["_id"])); + } else { + $obj = $object_json["_id"]; + } + + if ($obj) { + $result[] = Array($obj, isset($object_json["sort"]) ? $object_json["sort"] : 0); + } + } + } + $result = Array("repository" => $repository, "scroll_id" => $scroll_id, "result" => $result); + + } + return $result; + + } + + private function registerEntity($name) + { + $name = explode(":", $name); + $entity_bundle_name_space = $name[0]; + $real_name_space = $entity_bundle_name_space . "\\Entity"; + $this->getEntityManager()->getConfiguration()->addEntityNamespace($entity_bundle_name_space, $real_name_space); + } + + public function getRepository($name) + { + + $this->registerEntity($name); + + try { + $metadata = $this->getEntityManager()->getClassMetadata($name); + } catch (\Exception $e) { + error_log($e); + return; + } + + $em = $this->getEntityManager(); + return new RepositoryAdapter($em, $metadata); + } + + +} diff --git a/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/RepositoryAdapter.php b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/RepositoryAdapter.php new file mode 100755 index 00000000..09ddf5ff --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/RepositoryAdapter.php @@ -0,0 +1,351 @@ +updatePreviousIndexationArray(); + } + } + + } catch (\Exception $e) { + error_log($e); + error_log("ERROR with find"); + $a = null; + } + return $a; + } + + public function findOneBy(Array $filter, array $sort = null) + { + try { + $a = parent::findOneBy($filter, $sort); + + if ($a) { + if (method_exists($a, "getEsIndexed")) { + $a->updatePreviousIndexationArray(); + } + } + + } catch (\Exception $e) { + error_log($e); + error_log("ERROR with findOneBy"); + $a = null; + } + return $a; + } + + public function findRange(Array $filters, $limit = false, $order_field = null, $min = null, $max = null, $view_to_use = null) + { + + try { + + $mapping = Array(); + if (isset($this->getClassMetadata()->associationMappings)) { + foreach ($this->getClassMetadata()->associationMappings as $field => $data) { + $mapping[] = $field; + } + } + if (isset($this->getClassMetadata()->fieldMappings)) { + foreach ($this->getClassMetadata()->fieldMappings as $field => $data) { + if ($data["type"] == "twake_timeuuid" || $data["type"] == "twake_uuid") { + $mapping[] = $field; + } + } + } + + //Cassandra + $qb = $this->createQueryBuilder('e'); + + foreach ($filters as $filter => $value) { + $qb = $qb->andWhere($qb->expr()->eq('e.' . $filter, ":" . $filter . "_param")); + if (in_array($filter, $mapping)) { + if (is_object($value)) { + $qb = $qb->setParameter($filter . "_param", new FakeCassandraTimeuuid($value->getId())); + } else { + $qb = $qb->setParameter($filter . "_param", new FakeCassandraTimeuuid($value)); + } + } else { + $qb = $qb->setParameter($filter . "_param", $value); + } + } + + if ($min) { + if (is_string($min)) { + new FakeCassandraTimeuuid($min); + } + $qb = $qb->andWhere($qb->expr()->gte('e.' . $order_field, ":offset_min")); + $qb = $qb->setParameter("offset_min", $min); + } + if ($max) { + if (is_string($max)) { + new FakeCassandraTimeuuid($max); + } + $qb = $qb->andWhere($qb->expr()->lte('e.' . $order_field, ":offset_max")); + $qb = $qb->setParameter("offset_max", $max); + } + + if ($view_to_use) { + $this->_em->getConnection()->getWrappedConnection()->changeTableToView($view_to_use); + } + + if ($limit) { + $qb = $qb->setMaxResults(abs($limit)); + } + + $qb = $qb->getQuery(); + $a = $qb->execute(); + + + foreach ($a as $e) { + if (method_exists($e, "getEsIndexed")) { + $e->updatePreviousIndexationArray(); + } + } + + } catch (\Exception $e) { + error_log($e); + error_log("ERROR with findRange"); + $a = []; + } + return $a; + } + + public function findBy(Array $filters, ?array $sort = null, $limit = null, $offset = null, $order_fields = null, $order_directions = "ASC", $view_to_use = null) + { + + if (is_array($order_directions)) { + $order_direction = $order_directions[count($order_directions) - 1]; + $order_field = $order_fields[count($order_fields) - 1]; + } else { + $order_direction = $order_directions; + $order_field = $order_fields; + } + + $cassandra = strpos(get_class($this->_em->getConnection()->getDriver()), "PDOCassandra") >= 0; + + $offset_field = null; + if ($offset && is_array($offset)) { + if ($cassandra) { + $sort = Array(); + $offset_field = $order_fields[1]; + $offset = $offset[1]; + } else { + $offset_field = $order_fields[0]; + $offset = $offset[0]; + } + } + + try { + + if (($view_to_use || $offset && $order_field) && $cassandra) { + + + $mapping_timeuuid = Array(); + $mapping_uuid = Array(); + $mapping_twake_text = Array(); + if (isset($this->getClassMetadata()->associationMappings)) { + foreach ($this->getClassMetadata()->associationMappings as $field => $data) { + $mapping_timeuuid[] = $field; + } + } + if (isset($this->getClassMetadata()->fieldMappings)) { + foreach ($this->getClassMetadata()->fieldMappings as $field => $data) { + if ($data["type"] == "twake_no_salt_text") { + $mapping_twake_text[] = $field; + } + if ($data["type"] == "twake_timeuuid") { + $mapping_timeuuid[] = $field; + } + if ($data["type"] == "twake_uuid") { + $mapping_uuid[] = $field; + } + } + } + + //Cassandra + $qb = $this->createQueryBuilder('e'); + + foreach ($filters as $filter => $value) { + $qb = $qb->andWhere($qb->expr()->eq('e.' . $filter, ":" . $filter . "_param")); + if (in_array($filter, $mapping_timeuuid)) { + if (is_object($value)) { + $qb = $qb->setParameter($filter . "_param", new FakeCassandraTimeuuid($value->getId())); + } else { + $qb = $qb->setParameter($filter . "_param", new FakeCassandraTimeuuid($value)); + } + } else if (in_array($filter, $mapping_uuid)) { + $uuidType = Type::getType('twake_uuid'); + if (is_object($value)) { + $value = $value->getId(); + } + $value = $uuidType->convertToDatabaseValue($value, $this->_em->getConnection()->getDatabasePlatform()); + $qb = $qb->setParameter($filter . "_param", new FakeCassandraTimeuuid($value)); + } else if (in_array($filter, $mapping_twake_text)) { + /** \Doctrine\DBAL\Types\Type @var $encryptedStringType */ + $encryptedStringType = Type::getType('twake_no_salt_text'); + $encrypted = $encryptedStringType->convertToDatabaseValue($value, $this->_em->getConnection()->getDatabasePlatform()); + $qb = $qb->setParameter($filter . "_param", $encrypted); + } else { + $qb = $qb->setParameter($filter . "_param", $value); + } + } + + if ($offset) { + if (is_array($order_fields)) { + foreach ($order_fields as $i => $of) { + if ($limit > 0) { + $qb = $qb->addOrderBy('e.' . $of, $order_directions[$i]); + } else { + if ($order_directions[$i] == "ASC") { + $qb = $qb->addOrderBy('e.' . $of, "DESC"); + } else { + $qb = $qb->addOrderBy('e.' . $of, "ASC"); + } + } + } + } + if ($limit > 0) { + $qb = $qb->andWhere($qb->expr()->lte('e.' . $order_field, ":offset")); + } else { + $qb = $qb->andWhere($qb->expr()->gte('e.' . $order_field, ":offset")); + } + if (is_object($offset)) { + $offset = $offset->getId(); + } + + if (is_string($offset) && in_array($order_field, $mapping_timeuuid)) { + $offset = new FakeCassandraTimeuuid($offset); + if (strpos($order_field, "__TOKEN__") === 0) { + $offset = "__TOKEN__" . $offset . ""; + } + } + + $qb = $qb->setParameter("offset", $offset); + } + + if ($limit) { + $qb = $qb->setMaxResults(abs($limit) + ($offset?1:0)); + } + + if ($view_to_use) { + $this->_em->getConnection()->getWrappedConnection()->changeTableToView($view_to_use); + } + + $qb = $qb->getQuery(); + $a = $qb->execute(); + + } else { + $a = parent::findBy($filters, $sort, $limit, $offset); + } + + foreach ($a as $e) { + if (method_exists($e, "getEsIndexed")) { + $e->updatePreviousIndexationArray(); + } + } + + } catch (\Exception $e) { + error_log($e); + foreach (explode("\n", $e->getTraceAsString()) as $line) { + error_log($line); + } + error_log("ERROR with findBy"); + $a = []; + } + return $a; + } + + public function removeBy($filters) + { + + $qb = $this->createQueryBuilder("e"); + + $qb = $qb->delete(); + + $mapping = Array(); + if (isset($this->getClassMetadata()->associationMappings)) { + foreach ($this->getClassMetadata()->associationMappings as $field => $data) { + $mapping[] = $field; + } + } + if (isset($this->getClassMetadata()->fieldMappings)) { + foreach ($this->getClassMetadata()->fieldMappings as $field => $data) { + if ($data["type"] == "twake_timeuuid" || $data["type"] == "twake_uuid") { + $mapping[] = $field; + } + } + } + + foreach ($filters as $filter => $value) { + $qb = $qb->andWhere($qb->expr()->eq('e.' . $filter, ":" . $filter . "_param")); + if (in_array($filter, $mapping)) { + if (is_object($value)) { + $qb = $qb->setParameter($filter . "_param", new FakeCassandraTimeuuid($value->getId())); + } else { + $qb = $qb->setParameter($filter . "_param", new FakeCassandraTimeuuid($value)); + } + } else { + $qb = $qb->setParameter($filter . "_param", $value); + } + } + + $qb = $qb->getQuery(); + $qb->execute(); + + } + + public function queryBuilderUuid($list) + { + + $not_array = false; + if (!is_array($list)) { + if ($list === null) { + return null; + } + $not_array = true; + $list = [$list]; + } + + $return = Array(); + foreach ($list as $el) { + if (is_object($el) && method_exists($el, "getId")) { + $el = $el->getId(); + } + if (is_string($el) || get_class($el) == "Ramsey\Uuid\Uuid") { + $hex = str_replace("-", "", $el); + $value = substr($hex, 12, 4) . substr($hex, 8, 4) . substr($hex, 0, 8) . substr($hex, 16, 4) . substr($hex, 20); + $return[] = $value; + } else { + $return[] = $el; + } + } + + if ($not_array) { + $return = $return[0]; + } + + return $return; + + } + +} diff --git a/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/SessionHandler.php b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/SessionHandler.php new file mode 100755 index 00000000..32cf9086 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/DoctrineAdapter/SessionHandler.php @@ -0,0 +1,167 @@ +app = $app; + $this->doctrineAdapter = $app->getServices()->get("app.twake_doctrine"); + $this->didInit = false; + $this->lifetime = 3600; + $this->rememberMeLifetime = 60 * 60 * 24 * 360; + $this->cookiesToSet = []; + } + + public function getUser(Request $request) + { + if ($this->user) { + return $this->user; + } + $this->user = $this->checkRequest($request); + return $this->user; + } + + public function setUser(User $user) + { + $this->user = $user; + } + + public function getDidUseRememberMe(){ + return $this->did_use_remember_me; + } + + public function checkRequest(Request $request, Response $response = null) + { + + $authorization = $request->headers->get("Authorization"); + $authorization = explode(" ", $authorization); + + if($authorization[0] === "Bearer"){ + $jwt = $authorization[1]; + if($jwt){ + try{ + $key = $this->app->getContainer()->getParameter("jwt.secret"); + $jwt = JWT::decode($jwt, $key, array('HS256')); + + if(!$jwt->sub){ + return false; + } + + if($jwt->exp < date("U") && $jwt->type !== "refresh"){ + return false; + } + + if($jwt->exp < date("U") && $jwt->type === "refresh"){ + return false; + } + + $user = $this->doctrineAdapter->getRepository("Twake\Users:User")->find($jwt->sub); + + if(!$user){ + return false; + } + + return $user; + + }catch(\Exception $err){ + error_log($err); + return false; + } + } + } + + return false; + + } + + public function destroySession(Request $request) + { + + $cookie = $request->cookies->get('SESSID'); + $cookie = json_decode(base64_decode($cookie), 1); + $session_id = $cookie["sessid"]; + + $this->destroy($session_id); + $this->destroyRememberMe($request); + + } + + public function destroyRememberMe(Request $request) + { + + $cookie = $request->cookies->get('SESSID'); + $cookie = json_decode(base64_decode($cookie), 1); + $session_id = $cookie["sessid"]; + $user_id = $cookie["userid"]; + + $this->destroy($session_id); + + $user = $this->doctrineAdapter->getRepository("Twake\Users:User")->find($user_id); + if ($user && $user->getRememberMeSecret()) { + $user->setRememberMeSecret(false); + $this->doctrineAdapter->persist($user); + $this->doctrineAdapter->flush(); + } + + } + + public function destroy($sessionId) + { + $repo = $this->doctrineAdapter->getRepository("Twake\Core:Sessions"); + $result = $repo->find($sessionId); + + if ($result) { + $this->doctrineAdapter->remove($result); + $this->doctrineAdapter->flush(); + } + return true; + } + + public function write($sessionId, $data) + { + $session = $this->doctrineAdapter->getRepository("Twake\Core:Sessions")->find($sessionId); + if (!$session) { + $session = new Sessions(); + } + $session->setSessId($sessionId); + $session->setSessData(json_encode($data)); + $session->setSessLifetime($this->lifetime); + $session->setSessTime(date("U")); + $this->doctrineAdapter->persist($session); + $this->doctrineAdapter->flush(); + + return true; + } + + public function read($sessionId) + { + if (!$sessionId) { + return null; + } + $repo = $this->doctrineAdapter->getRepository("Twake\Core:Sessions"); + $result = $repo->find($sessionId); + + if ($result) { + $data = json_decode($result->getSessData(), 1); + return $data; + } + return null; + } + +} diff --git a/twake/backend/core/src/Twake/Core/Services/Languages/de.php b/twake/backend/core/src/Twake/Core/Services/Languages/de.php new file mode 100755 index 00000000..60e18fb6 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/Languages/de.php @@ -0,0 +1,82 @@ + "Allgemeine Aufgabenverteilung", + "project.discover_twake" => "Twake entdecken", + "project.project" => "Mein Projekt", + "project.createTwakeWorkspace" => "Richten Sie Ihren ersten Arbeitsbereich ein", + "project.createTwakeWorkspaceDescription" => "Um einen Arbeitsbereich einzurichten, klicken Sie auf \"+\" in der Liste Ihrer Arbeitsbereiche", + "project.discoverTwake" => "Twake entdecken", + "project.discoverTwakeDescription" => "Γ–ffnen Sie jede Anwendung, um zu entdecken, wie Twake Ihnen Zeit ersparen kann", + "project.signin" => "Auf Twake anmelden", + "project.invitePartner" => "Laden Sie Ihre Partner ein", + "project.invitePartnerDescription" => "Wechseln Sie in Ihrem Arbeitsbereich zu den Registerkarten \"Mitglieder\" und fΓΌgen Sie Ihre Partner mit ihren Benutzernamen oder E-Mail-Adressen hinzu", + "drive.society" => "Firma", + "drive.comminucation" => "Kommunikation", + "drive.financial" => "Finanzen", + "drive.hr" => "Personal", + "drive.rules" => "Regeln.docx", + "drive.accounting" => "Buchhaltung.xlsx", + "drive.twake" => "Twake", + "drive.rules" => "Regeln.docx", + "drive.ruleText" => "HΓΆren Sie die Musik nicht vollstΓ€ndig im Open Space.", + "drive.welcome" => "Herzlich willkommen.docx", + "drive.welcomeText" => "Herzlich willkommen auf Twake! \nWir freuen uns, Sie auf unserer Plattform begrüßen zu dΓΌrfen. :D", + "calendar.communication" => "Kommunikation", + "calendar.customer" => "Kunde", + "calendar.generalMeeting" => "Teambesprechung", + "calendar.meetingDurant" => "Treffen mit Herrn Durant", + "calendar.meetingNextAds" => "Vorbereitung der Fernsehwerbung", + "calendar.meetingXu" => "Treffen mit Herrn Xu", + "calendar.interview" => "Fernsehwerbung", + "message.hello1" => "Hallo $1, herzlich willkommen auf Twake!:tada:", + "message.hello2" => "Ich bin Twake_bot, ich bin hier, um Ihnen zu helfen", + "message.hello3" => "Bereit fΓΌr Twake? :grinning:", + + "quote.update_policy" => "Wir haben unsere DatenschutzerklΓ€rung nicht aktualisiert.", + "subquote.update_policy" => "Haben wir's gemacht? Ich weiß es nicht, sehen Sie in Ihren E-Mails nach.", + "quote.dont_worry" => "Keine Sorge, alles unter Kontrolle.", + "quote.read_text" => "Lesen Sie diesen Text nicht.", + "subquote.read_text" => "Sie haben soeben verloren", + "quote.love_the_live" => "Liebe das Leben, das du lebst, und lebe das Leben, das du liebst.", + + "general" => "Allgemein", + + "drive.move_file" => "Datei verschoben", + "drive.new_file" => "Neue Datei", + "drive.has_been_added" => "$1 wurde zu $2 hinzugefΓΌgt", + "drive.has_been_moved" => "$1 wurde in $2 verschoben", + "drive.file_updated" => "Aktualisierte Datei", + "drive.has_been_update" => "$1 wurde aktualisiert", + + "workspace.activity.task.update" => "$1 hat $2 Aufgabe(n) aktualisiert", + "workspace.activity.task.remove" => "$1 hat $2 Aufgabe(n) entfernt", + "workspace.activity.task.create" => "$1 hat $2 Aufgabe(n) angelegt", + "workspace.activity.task.done" => "$1 hat $2 Aufgabe(n) beendet", + + "workspace.activity.event.update" => "$1 hat $2 Ereignis(se) aktualisiert", + "workspace.activity.event.remove" => "$1 hat $2 Ereignis(se) entfernt", + "workspace.activity.event.create" => "$1 hat $2 Ereignis(se) angelegt", + + "workspace.activity.file.move" => "$1 hat $2 Datei(en) verschoben", + "workspace.activity.file.rename" => "$1 hat $2 Datei(en) umbenannt", + "workspace.activity.file.create" => "$1 hat $2 Datei(en) angelegt", + "workspace.activity.file.move_detached_file_to_drive" => "$1 hat $2 abgetrennte Datei(en) in den Drive verschoben", + "workspace.activity.file.trash" => "$1 hat $2 Datei(en) entfernt", + "workspace.activity.file.restore" => "$1 hat $2 Datei(en) wiederhergestellt", + "workspace.activity.file.upload_new_version" => "$1 hat $2 neue Dateiversionen hochgeladen", + + "workspace.activity.workspace.change_logo" => "$1 hat das Logo des Arbeitsbereichs geΓ€ndert", + "workspace.activity.workspace.rename" => "$1 hat den Arbeitsbereich umbenannt", + "workspace.activity.workspace.change_wallpaper" => "$1 hat das Hintergrundbild des Arbeitsbereichs geΓ€ndert", + "workspace.activity.workspace.archive" => "$1 hat den Arbeitsbereich archiviert", + "workspace.activity.workspace.unarchive" => "$1 hat den Arbeitsbereich dearchiviert", + "workspace.activity.workspace.add_member" => "$1 wurde zu diesem Arbeitsbereich hinzugefΓΌgt", +); \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Services/Languages/en.php b/twake/backend/core/src/Twake/Core/Services/Languages/en.php new file mode 100755 index 00000000..dbdd121e --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/Languages/en.php @@ -0,0 +1,83 @@ + "General", + + "drive.move_file" => "Move file", + "drive.new_file" => "New file", + "drive.has_been_added" => "$1 has been added to $2", + "drive.has_been_moved" => "$1 has been moved into $2", + "drive.file_updated" => "Updated file", + "drive.has_been_update" => "$1 has been updated", + + "project.generalBoardDescription" => "General board of tasks", + "project.discover_twake" => "Discover Twake", + "project.project" => "My project", + "project.createTwakeWorkspace" => "Create your first workspace", + "project.createTwakeWorkspaceDescription" => "To create a workspace, you have to click on the \"+\" in your workspace list", + "project.discoverTwake" => "Discover Twake", + "project.discoverTwakeDescription" => "Open each application to see what Twake can do for you", + "project.signin" => "Sign in", + "project.invitePartner" => "Invite your partners", + "project.invitePartnerDescription" => "Go to your workspace, in the \"members\" tabs, add your partners with their username or email address if they are not already registered", + + + "drive.twake" => "Twake", + "drive.rules" => "Rules.docx", + "drive.ruleText" => "Do not listen to the music fully in the openspace", + "drive.welcome" => "Welcome.docx", + "drive.welcomeText" => "Welcome on Twake ! \nWe are very happy to welcome you on our plateforme :D", + + + "calendar.communication" => "Communication", + "calendar.customer" => "Customer", + "calendar.generalMeeting" => "Team meeting", + "calendar.meetingDurant" => "Meeting with Mr Durant", + "calendar.meetingNextAds" => "Preparation to TV advertising", + "calendar.meetingXu" => "Meeting with Mr Xu", + "calendar.interview" => "TV advertising", + + "message.hello1" => "Hello $1, welcome on board !:tada:", + "message.hello2" => "I am Twake_bot, I am here to help you", + "message.hello3" => "Ready to use Twake ? :grinning:", + + + "mail.request_new_password" => "Your request for a new password", + "mail.hello" => "Hello", + "mail.request_new_password_body" => "You requested a new password, there is the activation code you need", + + + "quote.update_policy" => "We did not update our privacy policy.", + "subquote.update_policy" => "Did we? I don't know, check your e-mails.", + "quote.dont_worry" => "Don't worry, everything is under control.", + "quote.read_text" => "Don't read that text.", + "subquote.read_text" => "You just lost", + "quote.love_the_live" => "Love the life you live, and live the life you love.", + + "workspace.activity.task.update" => "$1 has updated $2 task(s)", + "workspace.activity.task.remove" => "$1 has removed $2 task(s)", + "workspace.activity.task.create" => "$1 has created $2 task(s)", + "workspace.activity.task.done" => "$1 achieved $2 task(s)", + "workspace.activity.event.update" => "$1 has updated $2 event(s)", + "workspace.activity.event.remove" => "$1 has removed $2 event(s)", + "workspace.activity.event.create" => "$1 has created $2 event(s)", + "workspace.activity.file.move" => "$1 has moved $2 file(s)", + "workspace.activity.file.rename" => "$1 has renamed $2 file(s)", + "workspace.activity.file.create" => "$1 has created $2 file(s)", + "workspace.activity.file.move_detached_file_to_drive" => "$1 has moved $2 detached files to drive", + "workspace.activity.file.trash" => "$1 has trashed $2 file(s)", + "workspace.activity.file.restore" => "$1 has restored $2 file(s)", + "workspace.activity.file.upload_new_version" => "$1 has uploaded $2 new file(s) version(s)", + "workspace.activity.workspace.change_logo" => "$1 has changed the workspace logo", + "workspace.activity.workspace.rename" => "$1 has renamed the workspace", + "workspace.activity.workspace.change_wallpaper" => "$1 has changed the workspace wallpaper", + "workspace.activity.workspace.archive" => "$1 has archived the workspace", + "workspace.activity.workspace.unarchive" => "$1 has unarchived the workspace", + "workspace.activity.workspace.add_member" => "$1 was added to this workspace", +); \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Services/Languages/fr.php b/twake/backend/core/src/Twake/Core/Services/Languages/fr.php new file mode 100755 index 00000000..508e9f6c --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/Languages/fr.php @@ -0,0 +1,88 @@ + "GΓ©nΓ©ral", + + "drive.move_file" => "Fichier dΓ©placΓ©", + "drive.new_file" => "Nouveau fichier", + "drive.has_been_added" => "$1 a Γ©tΓ© ajoutΓ© dans $2", + "drive.has_been_moved" => "$1 a Γ©tΓ© dΓ©placΓ© dans $2", + "drive.file_updated" => "Fichier mis Γ  jour", + "drive.has_been_update" => "$1 a Γ©tΓ© mis Γ  jour", + + "project.generalBoardDescription" => "Tableau gΓ©nΓ©ral de tΓ’ches", + "project.discover_twake" => "DΓ©couvrir Twake", + "project.project" => "Mon projet", + "project.createTwakeWorkspace" => "CrΓ©ez votre premier espace de travail", + "project.createTwakeWorkspaceDescription" => "Pour crΓ©er un espace de travail, cliquez sur le bouton \"+\" dans ta liste d\'espaces de travail", + "project.discoverTwake" => "DΓ©couvrir Twake", + "project.discoverTwakeDescription" => "Ouvrez chaque application pour dΓ©couvrir en quoi Twake peut vous faire gagner du temps", + "project.signin" => "S'inscrire sur Twake", + "project.invitePartner" => "Invitez vos partenaires", + "project.invitePartnerDescription" => "Allez dans votre espace de travail, dans les onglets \"membres\", ajoutez vos partenaires avec leur nom d'utilisateur ou leur adresse mail", + + + "drive.society" => "SociΓ©tΓ©", + "drive.comminucation" => "Communication", + "drive.financial" => "Finances", + "drive.hr" => "Ressources humaines", + "drive.rules" => "RΓ¨gles.docx", + "drive.ruleSmoke" => "", + "drive.accounting" => "ComptabilitΓ©.xlsx", + + "drive.twake" => "Twake", + "drive.rules" => "RΓ¨gles.docx", + "drive.ruleText" => "Ne pas Γ©couter la musique Γ  fond dans l'openspace", + "drive.welcome" => "Bienvenue.docx", + "drive.welcomeText" => "Bienvenue sur Twake ! \nNous sommes trΓ¨s heureux de vous accueillir sur notre plateforme. :D", + + "calendar.communication" => "Communication", + "calendar.customer" => "Client", + "calendar.generalMeeting" => "RΓ©union d'Γ©quipe", + "calendar.meetingDurant" => "RDV avec M. Durant", + "calendar.meetingNextAds" => "PrΓ©paration de la pub TV", + "calendar.meetingXu" => "RDV avec M. Xu", + "calendar.interview" => "PublicitΓ© TV", + + "message.hello1" => "Bonjour $1, bienvenue sur Twake !:tada:", + "message.hello2" => "Je suis Twake_bot, je suis ici pour vous aider", + "message.hello3" => "PrΓͺt Γ  utiliser Twake ? :grinning:", + + + "mail.request_new_password" => "Votre demande d'un nouveau mot de passe", + "mail.hello" => "Bonjour", + "mail.request_new_password_body" => "Vous avez demandΓ© un nouveau mot de passe, voici le code d'activation dont vous avez besoin", + "quote.update_policy" => "Nous n'avons pas mis Γ  jour notre politique de confidentialitΓ©.", + "subquote.update_policy" => "L'avons-nous fait ? Je ne sais pas, vΓ©rifiez vos mails.", + "quote.dont_worry" => "Ne vous inquiΓ©tez pas, tout est sous contrΓ΄le.", + "quote.read_text" => "Ne lisez pas ce texte.", + "subquote.read_text" => "Vous venez de perdre", + "quote.love_the_live" => "Aimez la vie que vous vivez et vivez la vie que vous aimez.", + + "workspace.activity.task.update" => "$1 a mis Γ  jour $2 tΓ’che(s)", + "workspace.activity.task.remove" => "$1 a supprimΓ© $2 tΓ’che(s)", + "workspace.activity.task.create" => "$1 a créé $2 tΓ’che(s)", + "workspace.activity.task.done" => "$1 a terminΓ© $2 tΓ’che(s)", + "workspace.activity.event.update" => "$1 a mis Γ  jour $2 Γ©vΓ©nement(s)", + "workspace.activity.event.remove" => "$1 a supprimΓ© $2 Γ©vΓ©nement(s)", + "workspace.activity.event.create" => "$1 a créé $2 Γ©vΓ©nement(s)", + "workspace.activity.file.move" => "$1 a dΓ©placΓ© $2 fichier(s)", + "workspace.activity.file.rename" => "$1 a renommΓ© $2 fichier(s)", + "workspace.activity.file.create" => "$1 a créé $2 fichier(s)", + "workspace.activity.file.move_detached_file_to_drive" => "$1 a dΓ©placΓ© $2 fichier(s) dΓ©tachΓ©(s) dans le Drive", + "workspace.activity.file.trash" => "$1 a supprimΓ© $2 fichier(s)", + "workspace.activity.file.restore" => "$1 a restaurΓ© $2 fichier(s)", + "workspace.activity.file.upload_new_version" => "$1 a tΓ©lΓ©chargΓ© $2 nouvelles versions de fichiers", + "workspace.activity.workspace.change_logo" => "$1 a modifiΓ© le logo de l'espace de travail", + "workspace.activity.workspace.rename" => "$1 a renommΓ© l'espace de travail", + "workspace.activity.workspace.change_wallpaper" => "$1 a changΓ© l'image de fond de l'espace de travail", + "workspace.activity.workspace.archive" => "$1 a archivΓ© l'espace de travail", + "workspace.activity.workspace.unarchive" => "$1 a dΓ©sarchivΓ© the l'espace de travail", + "workspace.activity.workspace.add_member" => "$1 a Γ©tΓ© ajoutΓ© Γ  l'espace de travail", +); \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Services/Monitoring/AbstractCollector.php b/twake/backend/core/src/Twake/Core/Services/Monitoring/AbstractCollector.php new file mode 100755 index 00000000..4b43330f --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/Monitoring/AbstractCollector.php @@ -0,0 +1,72 @@ +set($this->getData(), $labelValues); + } + + /** + * Return the collected data + * + * @return mixed + */ + public function getData() + { + return $this->data; + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Services/Monitoring/CollectorRegistry.php b/twake/backend/core/src/Twake/Core/Services/Monitoring/CollectorRegistry.php new file mode 100755 index 00000000..edf7ea06 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/Monitoring/CollectorRegistry.php @@ -0,0 +1,128 @@ +appCode = $appCode; + $this->registry = $registry; + } + + public function init() + { + $this->addCollector(new MemoryCollector()); + $this->addCollector(new ResponseCodeCollector()); + $this->addCollector(new ResponseSizeCollector()); + $this->addCollector(new ResponseTimeCollector()); + } + + /** + * Add a collector to the registry + * + * @param AbstractCollector $collector + */ + public function addCollector(AbstractCollector $collector) + { + $this->collectors[] = $collector; + } + + public function setAppCode($code) + { + $this->appCode = $code; + } + + /** + * Trigger data collection on all collectors + * + * @param Request $request + * @param Response $response + */ + public function collect(Request $request, Response $response) + { + foreach ($this->collectors as $collector) { + $collector->collect($request, $response); + } + } + + /** + * Set the current route name + * + * @param string $routeName + */ + public function setCurrentRoute($routeName) + { + $this->routeName = $routeName; + } + + /** + * Save the collected metrics to the backend in Prometheus format + * + * @throws \TweedeGolf\PrometheusClient\PrometheusException + */ + public function save() + { + if (!function_exists('apcu_add')) { + return; + } + + foreach ($this->collectors as $collector) { + if ($this->routeName) { + $collector->save( + $this->registry->get($collector->getCollectorName()), + [$this->appCode, $this->routeName] + ); + } + } + + if ($this->routeName) { + $this->registry->getCounter('app_collectors_call_count')->inc( + 1, + [$this->appCode, $this->routeName] + ); + } + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Services/Monitoring/MemoryCollector.php b/twake/backend/core/src/Twake/Core/Services/Monitoring/MemoryCollector.php new file mode 100755 index 00000000..d74492de --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/Monitoring/MemoryCollector.php @@ -0,0 +1,32 @@ +data = memory_get_peak_usage(true); + } + + /** + * {@inheritdoc} + */ + public function getCollectorName(): string + { + return 'app_collectors_memory_usage'; + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Services/Monitoring/MonitoringCollectionSubscriber.php b/twake/backend/core/src/Twake/Core/Services/Monitoring/MonitoringCollectionSubscriber.php new file mode 100755 index 00000000..a07d5ce7 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/Monitoring/MonitoringCollectionSubscriber.php @@ -0,0 +1,101 @@ +dataRegistry = $dataRegistry; + + $this->dataRegistry->setAppCode("twake-core"); + $this->dataRegistry->init(); + + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return array( + KernelEvents::RESPONSE => array('onKernelResponse', -100), + KernelEvents::TERMINATE => array('onKernelTerminate', -1024), + ); + } + + /** + * Handles the onKernelResponse event. + * + * Collect the metrics on this event + * + * @param $event FilterResponseEvent + */ + public function onKernelResponse(FilterResponseEvent $event) + { + $master = $event->isMasterRequest(); + if (!$master) { + return; + } + + $request = $event->getRequest(); + + $route = $request->get('_route'); + + $app_code = "twake-core"; + if (strpos($request->attributes->get('_controller'), "DevelopersApi") === 0) { + $app_code = "twake-api"; + } + + $this->dataRegistry->setAppCode($app_code); + + if ($route != "tweede_golf_prometheus_metrics") { + + $this->dataRegistry->setCurrentRoute($route); + $this->dataRegistry->collect($request, $event->getResponse()); + + } + } + + /** + * Handles the onKernelTerminate event. + * + * Save the collected metrics to the backend + * + * @param PostResponseEvent $event + */ + public function onKernelTerminate(PostResponseEvent $event) + { + try { + $this->dataRegistry->save(); + } catch (PrometheusException $e) { + error_log('Save prometheus metrics error'); + error_log((string)$e); + } + } +} diff --git a/twake/backend/core/src/Twake/Core/Services/Monitoring/ResponseCodeCollector.php b/twake/backend/core/src/Twake/Core/Services/Monitoring/ResponseCodeCollector.php new file mode 100755 index 00000000..b2f0f330 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/Monitoring/ResponseCodeCollector.php @@ -0,0 +1,55 @@ +responseCode = $response->getStatusCode(); + } + + /** + * {@inheritdoc} + */ + public function getCollectorName(): string + { + return 'app_collectors_response_code'; + } + + /** + * {@inheritdoc} + * + * Note : overriden because suez_sf_app_response_code is a counter + * + * @throws PrometheusException + */ + public function save(CollectorInterface $collector, array $labelValues) + { + /** @var $collector Counter */ + $collector->inc(1, array_merge($labelValues, [(string)$this->responseCode])); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Services/Monitoring/ResponseSizeCollector.php b/twake/backend/core/src/Twake/Core/Services/Monitoring/ResponseSizeCollector.php new file mode 100755 index 00000000..5b6adf5e --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/Monitoring/ResponseSizeCollector.php @@ -0,0 +1,32 @@ +data = strlen($response->getContent()); + } + + /** + * {@inheritdoc} + */ + public function getCollectorName(): string + { + return 'app_collectors_response_size'; + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Services/Monitoring/ResponseTimeCollector.php b/twake/backend/core/src/Twake/Core/Services/Monitoring/ResponseTimeCollector.php new file mode 100755 index 00000000..d29683b1 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/Monitoring/ResponseTimeCollector.php @@ -0,0 +1,58 @@ +start_time = $start_time; + } + + /** + * {@inheritdoc} + */ + public function collect(Request $request, Response $response) + { + $startTime = null; + + if (null !== $this->kernel) { + $startTime = $this->start_time; + } + + if (is_null($startTime) || $startTime === -INF) { + $startTime = $request->server->get('REQUEST_TIME_FLOAT'); + } + + $this->data = (microtime(true) - $startTime) * 1000; + } + + /** + * {@inheritdoc} + */ + public function getCollectorName(): string + { + return 'app_collectors_response_time'; + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Services/Pusher.php b/twake/backend/core/src/Twake/Core/Services/Pusher.php new file mode 100755 index 00000000..468dd3d4 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/Pusher.php @@ -0,0 +1,57 @@ +secret = $app->getContainer()->getParameter("node.secret"); + $this->pusher = $app->getContainer()->getParameter("node.api") . "pusher"; + $this->rest = $app->getServices()->get("app.restclient"); + } + + public function push($data, $route) + { + $data = Array( + "topic" => $route, + "data" => $data + ); + + $this->pushForReal($data, $route); + } + + public function pushForReal($data, $route) + { + $signin_key = $this->pusher_private_key; + $sent_data = $data["data"]; + if ($signin_key) { + openssl_sign((string)@json_encode($sent_data), $signed, $signin_key); + $sent_data["_sign"] = base64_encode($signed); + } + + $pubData = [ + 'room' => "previous::".$data["topic"], + 'data' => $sent_data, + ]; + + $data = (string)@json_encode($pubData); + $this->rest->post($this->pusher, $data, [ + CURLOPT_HTTPHEADER => Array( + "Authorization: Token ".$this->secret, + "Content-Type: application/json" + ), + CURLOPT_CONNECTTIMEOUT => 1, + CURLOPT_TIMEOUT => 1 + ]); + } + +} diff --git a/twake/backend/core/src/Twake/Core/Services/Queues/Adapters/EmptyManager.php b/twake/backend/core/src/Twake/Core/Services/Queues/Adapters/EmptyManager.php new file mode 100755 index 00000000..dd5b89ec --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/Queues/Adapters/EmptyManager.php @@ -0,0 +1,47 @@ +parameters = $parameters; + } + + public function getChannel($options = []) + { + if (!$this->connection) { + $this->connection = new AMQPStreamConnection($this->parameters["host"], $this->parameters["port"] ?: 5672, $this->parameters["username"], $this->parameters["password"], $this->parameters["vhost"] ?: '/'); + } + if (!$this->channel) { + $this->channel = $this->connection->channel(); + } + return $this->channel; + } + + public function push($route, $message, $options = []) + { + $amqp_options = []; + if (isset($options["delay"])) { + $amqp_options = [ + 'delivery_mode' => 2, # make message persistent + 'application_headers' => new AMQPTable([ + 'x-delay' => max(0, $options["delay"] * 1000) + ]) + ]; + $data["DelaySeconds"] = $options["delay"]; + } + + $message = json_encode($message); + + if(!$message){ + error_log("[RabbitMQ] - Unable to encode message to JSON"); + return; + } + + $msg = new AMQPMessage($message, $amqp_options); + + $channel = $this->getChannel(); + if($options["exchange_type"]){ + $channel->queue_declare($route, false, true, false, false); + $channel->exchange_declare($route, $options["exchange_type"], false, true, false); + $channel->basic_publish($msg, $route, $route); + }else{ + $channel->queue_declare($route, false, true, false, false, [ + "x-message-ttl" => 24 * 60 * 60 * 1000 + ]); + $channel->basic_publish($msg, '', $route); + } + } + + public function consume($route, $callback, $options) + { + $incallback = function ($msg) use ($max_messages, &$list, $callback) { + $callback($msg); + if (count($list) >= $options["max_messages"]) { + $this->stop_consume = true; + } + return true; + }; + $this->stop_consume = false; + + if($this->channel){ + $this->channel->close(); + $this->channel = null; + } + $channel = $this->getChannel(); + + if($options["exchange_type"]){ + $channel->queue_declare($route, false, true, false, false); + $channel->exchange_declare($route, $options["exchange_type"], false, true, false); + $channel->queue_bind($route, $route); + $channel->basic_qos(null, $options["max_messages"], null); + $channel->basic_consume($route, "", false, !$options["should_ack"], false, false, $incallback); + }else{ + $channel->queue_declare($route, false, true, false, false, [ + "x-message-ttl" => 24 * 60 * 60 * 1000 + ]); + $channel->basic_qos(null, $options["max_messages"], null); + $channel->basic_consume($route, '', false, !$options["should_ack"], false, false, $incallback); + } + + try { + while ($channel->is_consuming() && !$this->stop_consume) { + $channel->wait(null, false, 1); + } + } catch (\Exception $err) { + error_log($err->getMessage()); + } + return true; + } + + public function oldConsume($route, $should_ack = false, $max_messages = 10, $message_processing = 60, $options = []) + { + $list = []; + $callback = function ($msg) use ($max_messages, &$list) { + $list[] = $msg; + if (count($list) >= $max_messages) { + $this->stop_consume = true; + } + return true; + }; + $this->stop_consume = false; + + if($this->channel){ + $this->channel->close(); + $this->channel = null; + } + $channel = $this->getChannel(); + + if($options["exchange_type"]){ + $channel->queue_declare($route, false, true, false, false); + $channel->exchange_declare($route, $options["exchange_type"], false, true, false); + $channel->queue_bind($route, $route); + $channel->basic_qos(null, $max_messages, null); + $channel->basic_consume($route, "", false, !$should_ack, false, false, $callback); + }else{ + $channel->queue_declare($route, false, true, false, false, [ + "x-message-ttl" => 24 * 60 * 60 * 1000 + ]); + $channel->basic_qos(null, $max_messages, null); + $channel->basic_consume($route, '', false, !$should_ack, false, false, $callback); + } + + try { + while ($channel->is_consuming() && !$this->stop_consume) { + $channel->wait(null, false, 1); + } + } catch (\Exception $err) { + error_log($err->getMessage()); + } + return $list; + } + + public function getMessage($message) + { + return json_decode($message->body, true); + } + + public function ack($route, $message, $options = []) + { + $channel = $this->getChannel(); + + if($options["exchange_type"]){ + $channel->queue_declare($route, false, true, false, false); + $channel->exchange_declare($route, $options["exchange_type"], false, true, false); + }else{ + $channel->queue_declare($route, false, true, false, false, [ + "x-message-ttl" => 24 * 60 * 60 * 1000 + ]); + } + $message->delivery_info['channel']->basic_ack($message->delivery_info['delivery_tag']); + } + + public function close() + { + if ($this->channel) { + $this->channel->close(); + } + if ($this->connection) { + $this->connection->close(); + } + } + +} diff --git a/twake/backend/core/src/Twake/Core/Services/Queues/Queues.php b/twake/backend/core/src/Twake/Core/Services/Queues/Queues.php new file mode 100755 index 00000000..f28bcb7c --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/Queues/Queues.php @@ -0,0 +1,33 @@ +adapter = new EmptyManager(); + if ($app->getContainer()->getParameter("queues.rabbitmq.use")) { + $this->adapter = new RabbitMQ($app->getContainer()->getParameter("queues.rabbitmq")); + } + } + + /** + * @return QueueManager + */ + public function getAdapter() + { + return $this->adapter; + } + +} diff --git a/twake/backend/core/src/Twake/Core/Services/Queues/Scheduled.php b/twake/backend/core/src/Twake/Core/Services/Queues/Scheduled.php new file mode 100755 index 00000000..3f2d05cd --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/Queues/Scheduled.php @@ -0,0 +1,253 @@ +doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->queues = $app->getServices()->get("app.queues")->getAdapter(); + } + + private function timeKeyFromTimestamp($timestamp) + { + return floor(($timestamp / $this->time_interval)) * $this->time_interval; + } + + /** Schedule a task, called once by one node */ + public function schedule($route, $timestamp, $message) + { + if ($timestamp < date("U")) { + return; + } + + if ($timestamp < date("U") + 15 * 60) { + $this->queues->push("scheduled_notifications_" . $route, [ + "message" => $message, + "timestamp" => $timestamp + ], [ + "delay" => $timestamp - date("U") + ]); + return true; + } + + //Get current counter state (if exists) + $counter_repository = $this->doctrine->getRepository("Twake\Core:ScheduledCounter"); + $counter = $counter_repository->findOneBy(Array('time' => $this->timeKeyFromTimestamp($timestamp), 'type' => 'total')); + if (!$counter) { + $counter = new ScheduledCounter($timestamp, "total", $this->time_interval); + $counter_done = new ScheduledCounter($timestamp, "done", $this->time_interval); + $this->doctrine->persist($counter_done); + } + + //Get shard to place notification + $shard = floor(($counter->getValue() + 1) / $this->bulk_size); + + $notification = new ScheduledTask($timestamp, $shard, $route, $message, $this->time_interval); + $counter->setIncrementValue(1); + + //Save counter and notification + $this->doctrine->useTTLOnFirstInsert(min(date("U") - $timestamp + $this->time_interval * 2, $this->max_ttl)); + $this->doctrine->persist($notification); + $this->doctrine->persist($counter); + $this->doctrine->flush(); + + return true; + } + + /** Get all notifications in 15 minutes interval (all nodes are calling this each minutes) */ + public function consumeShards($timeout = 60) + { + + if ($already_sent_shard[$timekey . "_all"]) { + return; + } + + $start = date("U"); + + $timestamp = date("U"); + $timekey = $this->timeKeyFromTimestamp($timestamp); + + //Get current counter state (if exists) + $counter_repository = $this->doctrine->getRepository("Twake\Core:ScheduledCounter"); + $counter_total = $counter_repository->findOneBy(Array('time' => $timekey, 'type' => 'total')); + $counter_done = $counter_repository->findOneBy(Array('time' => $timekey, 'type' => 'done')); + //Nothing to do, no notifications + if (!$counter_total || $counter_total->getValue() == 0 + || ($counter_done && $counter_total->getValue() <= $counter_done->getValue())) { + return true; + } + + $shards = []; //Get number of shards ex. shards 0, 1 and 2 for 235 notifications and 100 as bulk size + for ($i = 0; $i <= floor($counter_total->getValue() / $this->bulk_size); $i++) { + $shards[] = $i; + } + shuffle($shards); + + foreach ($shards as $shard) { + + if (date("U") - $start > $timeout) { + return; + } + + if ($already_sent_shard[$timekey . "_" . $shard]) { + continue; + } + + $tasks_repository = $this->doctrine->getRepository("Twake\Core:ScheduledTask"); + $tokenbdd = $tasks_repository->findOneBy(Array('time' => $timekey, 'shard' => $shard . '', 'id' => "token")); + + if (!$tokenbdd) { + + $token = base64_encode(bin2hex(random_bytes(32))); + + $tokenbdd = new ScheduledTask($timestamp, $shard, "", "", $this->time_interval); + $tokenbdd->setId("token"); + $tokenbdd->setData($token); + $this->doctrine->useTTLOnFirstInsert(60 * 60); //1 hour + $this->doctrine->persist($tokenbdd); + + $this->queues->push("scheduled_notifications", [ + "timekey" => $timekey, + "shard" => $shard, + "token" => $token + ], [ + "delay" => 2 //2 seconds time to update table + ]); + + $this->doctrine->flush(); + + } else { + $already_sent_shard[$timekey . "_" . $shard] = true; + } + + } + + $already_sent_shard[$timekey . "_all"] = true; + + } + + /** Consume shard task and ack once finished sent from consumeShards method and ignore duplicatas using token (sent on scheduled_notifications) */ + public function consumeShardsFromRabbitMQ() + { + + $done = 0; + + $shards = $this->queues->oldConsume("scheduled_notifications", true, 1); + + foreach ($shards ?: [] as $shard) { + + $shard_message = $this->queues->getMessage($shard); + + $token = $shard_message["token"]; + $shard_number = $shard_message["shard"]; + $timekey = $shard_message["timekey"]; + + $tasks_repository = $this->doctrine->getRepository("Twake\Core:ScheduledTask"); + /** @var ScheduledTask $tokenbdd */ + $tokenbdd = $tasks_repository->findOneBy(Array('time' => $timekey, 'shard' => $shard_number . "", 'id' => "token")); + if ($tokenbdd && $tokenbdd->getData() === $token) { + + /** @var ScheduledTask[] $notifications */ + $notifications = $tasks_repository->findBy(Array('time' => $timekey, 'shard' => $shard_number . "")); + foreach ($notifications as $notification) { + if ($notification->getId() == "token") { + continue; + } + + $timestamp = $notification->getTimestamp(); + + $this->queues->push("scheduled_notifications_" . $notification->getRoute(), [ + "message" => $notification->getData(), + "timestamp" => $timestamp + ], [ + "delay" => $timestamp - date("U") + ]); + + } + + // Remove counters if task finished + $counter_repository = $this->doctrine->getRepository("Twake\Core:ScheduledCounter"); + /** @var ScheduledCounter $counter_total */ + $counter_total = $counter_repository->findOneBy(Array('time' => $timekey, 'type' => 'total')); + + if ($counter_total) { + /** @var ScheduledCounter $counter_done */ + $counter_done = $counter_repository->findOneBy(Array('time' => $timekey, 'type' => 'done')); + $final_value = $counter_total->getValue(); + if ($counter_done) { + $final_value = $counter_done->getValue() + $this->bulk_size; + $counter_done->setIncrementValue($this->bulk_size); + $this->doctrine->persist($counter_done); + $this->doctrine->flush(); + } + + if ($final_value >= $counter_total->getValue()) { + $this->doctrine->remove($counter_total); + $this->doctrine->remove($counter_done); + $this->doctrine->flush(); + } + } + + // Remove shard + $tasks_repository->removeBy(Array('time' => $timekey, 'shard' => $shard_number . "")); + $this->doctrine->flush(); + + } + + if ($tokenbdd) { + $this->queues->ack("scheduled_notifications", $shard); + } + + $done++; + + } + + return $done; + + } + + /** Get RabbitMQ notifications received at exact wanted time (sent on scheduled_notifications_[route]) */ + public function consume($route, $should_ack = false, $max_messages = 10, $message_processing = 60) + { + $list = $this->queues->oldConsume("scheduled_notifications_" . $route, $should_ack, $max_messages, $message_processing); + return $list; + } + + /** Ack a scheduled notification from any scheduled_notifications_[route] */ + public function ack($route, $message) + { + $this->queues->ack("scheduled_notifications_" . $route, $message); + } + + public function getMessage($message) + { + return ($this->queues->getMessage($message) ?: [])["message"] ?: null; + } + +} diff --git a/twake/backend/core/src/Twake/Core/Services/StringCleaner.php b/twake/backend/core/src/Twake/Core/Services/StringCleaner.php new file mode 100755 index 00000000..8366ce2f --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/StringCleaner.php @@ -0,0 +1,136 @@ +removeSpecialChars(strtolower($data))); + } + if (is_array($data)) { + foreach ($data as $key => $value) { + $data[$key] = $this->simplifyInArray($value); + } + } + return $data; + } + + public function removeSpecialChars($str) + { + + $regex = <<<'END' +/ +( + (?: [\x00-\x7F] #:00d2f4aa-605b-11e9-b23e-0242ac120005 single-byte sequences 0xxxxxxx + | [\xC0-\xDF][\x80-\xBF] #:00d2f4aa-605b-11e9-b23e-0242ac120005 double-byte sequences 110xxxxx 10xxxxxx + | [\xE0-\xEF][\x80-\xBF]{2} #:00d2f4aa-605b-11e9-b23e-0242ac120005 triple-byte sequences 1110xxxx 10xxxxxx * 2 + | [\xF0-\xF7][\x80-\xBF]{3} #:00d2f4aa-605b-11e9-b23e-0242ac120005 quadruple-byte sequence 11110xxx 10xxxxxx * 3 + ){1,100} #:00d2f4aa-605b-11e9-b23e-0242ac120005 ...one or more times +) +| . #:00d2f4aa-605b-11e9-b23e-0242ac120005 anything else +/x +END; + return preg_replace($regex, '$1', $this->removeAccents($str)); + + } + + public function removeAccents($str) + { + $str = preg_replace('#Γ‡#', 'C', $str); + $str = preg_replace('#Γ§#', 'c', $str); + $str = preg_replace('#Γ¨|Γ©|Γͺ|Γ«#', 'e', $str); + $str = preg_replace('#È|Γ‰|Ê|Γ‹#', 'E', $str); + $str = preg_replace('#Γ |Γ‘|Γ’|Γ£|Γ€|Γ₯#', 'a', $str); + $str = preg_replace('#Γ€|Á|Γ‚|Γƒ|Γ„|Γ…#', 'A', $str); + $str = preg_replace('#Γ¬|Γ­|Γ|Γ―#', 'i', $str); + $str = preg_replace('#Ì|Í|Î|Ï#', 'I', $str); + $str = preg_replace('#Γ°|Γ²|Γ³|Γ΄|Γ΅|ΓΆ#', 'o', $str); + $str = preg_replace('#Γ’|Γ“|Γ”|Γ•|Γ–#', 'O', $str); + $str = preg_replace('#ΓΉ|ΓΊ|Γ»|ΓΌ#', 'u', $str); + $str = preg_replace('#Γ™|Ú|Γ›|Ü#', 'U', $str); + $str = preg_replace('#Γ½|ΓΏ#', 'y', $str); + $str = preg_replace('#Ý#', 'Y', $str); + + return $str; + } + + public function simplify($str) + { + return preg_replace("/[^a-z0-9_-]/", "", strtolower($this->removeAccents($str))); + } + + public function simplifyWithoutRemovingUpperCase($str) + { + return preg_replace("/[^a-z0-9A-Z]/", "", $this->removeAccents($str)); + } + + public function simplifyWithoutRemovingSpaces($str) + { + return preg_replace("/[^a-z0-9 ]/", "", strtolower($this->removeAccents($str))); + } + + public function simplifyWithoutRemovingSpacesOrUpperCase($str) + { + return preg_replace("/[^a-z0-9A-Z ]/", "", $this->removeAccents($str)); + } + + public function simplifyMail($str) + { + return preg_replace("/[^a-z0-9@\.\-\_\:]/", "", strtolower($this->removeAccents($str))); + } + + public function simplifyUsername($str) + { + return preg_replace("/[^a-z0-9_.-]/", "", strtolower($this->removeAccents($str))); + } + + public function simplifyURL($str) + { + return preg_replace("/[^a-z0-9@\.\-\_\/\:]/", "", strtolower($this->removeAccents($str))); + } + + public function verifyMail($mail) + { + return preg_match("/^[A-Za-z0-9.\-_]{1,250}@[A-Za-z0-9.\-_]{2,250}\.[A-Za-z0-9]{2,16}$/", $mail); + } + + public function verifyPassword($password) + { + //At least 8 chars + return strlen($password) >= 8; + //At least 8 characters, one lower and one uppercase, at least one number + //return preg_match("/^\S*(?=\S{8,})(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[\d])\S*$/",$password); + } + + public function verifyUsername($username) + { + if (strlen($username) < 4 or strlen($username) > 30) { + return false; + } + return true; + } + + public function getElapsedTime($ts) + { + + $diff = (date("U") - $ts); + + if ($diff < 60 * 60) { + $r = floor($diff / 60); + $date = "Il y a " . $r . " minute" . (($r > 1) ? 's' : ''); + } elseif ($diff < 60 * 60 * 24) { + $r = floor(($diff) / (60 * 60)); + $date = "Il y a " . $r . " heure" . (($r > 1) ? 's' : ''); + } elseif ($diff < 60 * 60 * 24 * 10) { + $r = floor(($diff) / (60 * 60 * 24)); + $date = "Il y a " . $r . " jour" . (($r > 1) ? 's' : ''); + } else { + $date = "Le " . date("d/m/Y", $ts); + } + + return $date; + } + +} diff --git a/twake/backend/core/src/Twake/Core/Services/Translate.php b/twake/backend/core/src/Twake/Core/Services/Translate.php new file mode 100755 index 00000000..2d4ae171 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/Translate.php @@ -0,0 +1,53 @@ +defaultLanguage; + } + + public function setDefaultLanguage($lang) + { + $this->defaultLanguage = $lang; + } + + public function translate($key, $lang) + { + if ($key instanceof TranslationObject) + return $key->toString($lang); + + $availableLanguages = Array("fr", "en", "de"); + + if (in_array($lang, $availableLanguages)) { + $translation = Array(); + include dirname(__FILE__) . "/Languages/$lang.php"; + + if (isset(($translation)[$key])) { + return ($translation)[$key]; + } + } + + if ($lang == 'en') + return $key; + return $this->translate($key, "en"); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Services/TwakeMailer.php b/twake/backend/core/src/Twake/Core/Services/TwakeMailer.php new file mode 100755 index 00000000..7886247e --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/TwakeMailer.php @@ -0,0 +1,217 @@ +app = $app; + $this->mail_parameters = $app->getContainer()->getParameter("mail"); + $this->licenceKey = $app->getContainer()->getParameter("env.licence_key"); + $this->standalone = $app->getContainer()->getParameter("env.standalone"); + $this->circle = $app->getServices()->get("app.restclient"); + $this->string_cleaner = $app->getServices()->get("app.string_cleaner"); + } + + public function send($mail, $template, $data = Array(), $attachments = Array(), $templateDirectory = "Mail") + { + $task = new MailTask(Array( + "mail" => $mail, + "data" => $data, + "template" => $template, + "attachments" => $attachments, + "template_directory" => $templateDirectory + )); + + /** @var ManagerAdapter $em */ + $em = $this->app->getServices()->get("app.twake_doctrine"); + $em->useTTLOnFirstInsert(60 * 60 * 24); //Kept 1 day + $em->persist($task); + $em->flush(); + + /** @var QueueManager $queues */ + $queues = $this->app->getServices()->get("app.queues")->getAdapter(); + $queues->push("mails", Array( + "task_id" => $task->getId() + )); + } + + public function sendInternal($mail, $template, $data = Array(), $attachments = Array(), $templateDirectory = "Mail") + { + + if(!$mail || !$this->string_cleaner->verifyMail($mail)){ + return false; + } + + $templateDirectory = "Mail"; + + $path = $this->app->getAppRootDir() . "/" . $this->mail_parameters["template_dir"]; + $loader = new FilesystemLoader($path); + + $twig = new \Twig\Environment($loader, [ + 'cache' => $this->app->getAppRootDir() . "/" . $this->app->getContainer()->get("configuration", "twig.cache"), + ]); + + $data["mail"] = $mail; + $data["twakeaddress"] = $this->mail_parameters["twake_address"]; + $data["twakeurl"] = $this->mail_parameters["twake_domain_url"]; + + $data["twakeappurl"] = $this->app->getContainer()->getParameter("env.frontend_server_name", $this->app->getContainer()->getParameter("env.server_name", $data["twakeurl"])); + + $language = "en"; + if (isset($data["_language"])) { + $language = $data["_language"]; + $templateName = $templateDirectory . "/" . $language . "/" . $template . '.html.twig'; + if (!file_exists($path . $templateName)) { + $language = "en"; + } + } + + $templateName = $templateDirectory . "/" . $language . "/" . $template . '.html.twig'; + + $template = $twig->load($templateName); + + $html = $template->render( + $data + ); + + + if ($this->standalone) { + return $this->sendHtml($mail, $html, $attachments); + } else { + return $this->sendHtmlViaRemote($mail, $html, $attachments); + } + + } + + public function sendHtml($mail, $html, $attachments = Array()) + { + //[REMOVE_ONPREMISE] + + if (defined("TESTENV") && TESTENV) { + return false; + } + + if (!$this->mailer) { + $transport = (new \Swift_SmtpTransport($this->mail_parameters["sender"]["host"], $this->mail_parameters["sender"]["port"])) + ->setUsername($this->mail_parameters["sender"]["username"]) + ->setPassword($this->mail_parameters["sender"]["password"]) + ->setAuthMode($this->mail_parameters["sender"]["auth_mode"]); + $this->mailer = new \Swift_Mailer($transport); + } + + if(isset($this->mail_parameters["dkim"]) && + isset($this->mail_parameters["dkim"]["private_key"]) && $this->mail_parameters["dkim"]["private_key"] !== "" && + isset($this->mail_parameters["dkim"]["domain_name"]) && $this->mail_parameters["dkim"]["domain_name"] !== "" && + isset($this->mail_parameters["dkim"]["selector"]) && $this->mail_parameters["dkim"]["selector"] !== ""){ + $is_DKIM = true; + }else{ + $is_DKIM = false; + } + + if($is_DKIM){ + $privateKey = $this->mail_parameters["dkim"]["private_key"]; + $domainName = $this->mail_parameters["dkim"]["domain_name"]; + $selector = $this->mail_parameters["dkim"]["selector"]; + $signer = new Swift_Signers_DKIMSigner($privateKey, $domainName, $selector); + } + + $this->app->getProviders()->getContainer()['swiftmailer.options'] = $this->mail_parameters["sender"]; + + //Sending verification mail + $message = (new \Swift_Message("")) + ->setSubject($this->html2title($html)) + ->setFrom($this->mail_parameters["from"], $this->mail_parameters["from_name"]) + ->setTo($mail) + ->setBody( + $html, + 'text/html' + ) + ->addPart( + $this->html2txt($html), + 'text/plain' + ); + + foreach ($attachments as $attachment) { + if ($attachment["type"] == "path") { + $message->attach(\Swift_Attachment::fromPath($attachment["path"])); + } + if ($attachment["type"] == "raw") { + $message->attach(new \Swift_Attachment($attachment["data"], $attachment["filename"], $attachment["mimetype"])); + } + } + + if($is_DKIM){ + $message->attachSigner($signer); + } + + $this->mailer->send($message); + + return true; + + //[/REMOVE_ONPREMISE] + + } + + private function html2title($html) + { + $a = explode("", $html, 2)[1]; + $a = explode("<", $a, 2)[0]; + return $a; + } + + private function html2txt($html) + { + $html = explode("</head>", $html); + $html = preg_replace("/<br *\/>/", "\n\n", $html[1]); + $html = strip_tags($html); + $html = preg_replace("/(\r?\n){2,}/m", "\n\n", $html); + $html = preg_replace("/^\s+/m", "", $html); + $html = preg_replace("/\s+$/m", "", $html); + return $html; + } + + public function sendHtmlViaRemote($mail, $html, $attachments = Array()) + { + $final_attachments = []; + foreach ($attachments as $attachment) { + if ($attachment["type"] == "raw") { + $final_attachments[] = $attachment; + } + } + + $masterServer = "https://app.twakeapp.com/api/remote"; + $data = Array( + "licenceKey" => $this->licenceKey, + "mail" => $mail, + "html" => $html, + "attachments" => $final_attachments + ); + $this->circle->post($masterServer . "/mail", json_encode($data), array(CURLOPT_CONNECTTIMEOUT => 60, CURLOPT_HTTPHEADER => ['Content-Type: application/json'])); + + return true; + } + +} diff --git a/twake/backend/core/src/Twake/Core/Services/TwakeRestClient.php b/twake/backend/core/src/Twake/Core/Services/TwakeRestClient.php new file mode 100755 index 00000000..1b0a50bf --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/TwakeRestClient.php @@ -0,0 +1,109 @@ +<?php + +namespace Twake\Core\Services; + +use App\App; +use Common\Http\Response; + +if (!function_exists('http_parse_headers')) { + function http_parse_headers($raw_headers) + { + $headers = array(); + $key = ''; + + foreach (explode("\n", $raw_headers) as $i => $h) { + $h = explode(':', $h, 2); + + if (isset($h[1])) { + if (!isset($headers[$h[0]])) + $headers[$h[0]] = trim($h[1]); + elseif (is_array($headers[$h[0]])) { + $headers[$h[0]] = array_merge($headers[$h[0]], array(trim($h[1]))); + } else { + $headers[$h[0]] = array_merge(array($headers[$h[0]]), array(trim($h[1]))); + } + + $key = $h[0]; + } else { + if (substr($h[0], 0, 1) == "\t") + $headers[$key] .= "\r\n\t" . trim($h[0]); + elseif (!$key) + $headers[0] = trim($h[0]); + } + } + + return $headers; + } +} + +class TwakeRestClient +{ + private $app = null; + + public function __construct(App $app) + { + $this->app = $app; + } + + public function get($url, $curl_options = []) + { + return $this->request("GET", $url, [], $curl_options); + } + + public function post($url, $data, $curl_options = []) + { + return $this->request("POST", $url, $data, $curl_options); + } + + public function put($url, $data, $curl_options = []) + { + return $this->request("PUT", $url, $data, $curl_options); + } + + public function delete($url, $curl_options = []) + { + return $this->request("DELETE", $url, [], $curl_options); + } + + public function request($method, $url, $data, $curl_options = []) + { + + if ($this->app) $this->app->getCounter()->startTimer("external_requests"); + + $options = []; + foreach ($curl_options as $key => $opt) { + $options[$key] = $opt; + } + + $options[CURLOPT_RETURNTRANSFER] = true; + $options[CURLOPT_HEADER] = true; + + $options[CURLOPT_URL] = $url; + $options[CURLOPT_CUSTOMREQUEST] = strtoupper($method); + $options[CURLOPT_POSTFIELDS] = $data; + + $curl = curl_init(); + curl_setopt_array($curl, $options); + + $response = curl_exec($curl); + $obj_response = new Response(); + + $headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE); + + $content = substr($response, $headerSize); + $content = empty($content) ? '' : $content; + $obj_response->setContent($content); + + $headers = substr($response, 0, $headerSize); + $headers = http_parse_headers($headers); + $obj_response->headers->reset($headers); + + $curl_data = (object)curl_getinfo($curl); + $obj_response->httpStatus($curl_data->http_code); + + if ($this->app) $this->app->getCounter()->stopTimer("external_requests"); + + return $obj_response; + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Services/UpdateServicesStatus.php b/twake/backend/core/src/Twake/Core/Services/UpdateServicesStatus.php new file mode 100755 index 00000000..9372c0a8 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/UpdateServicesStatus.php @@ -0,0 +1,97 @@ +<?php + +namespace Twake\Core\Services; +use App\App; + +class UpdateServicesStatus +{ + + public function __construct(App $app){ + $this->app = $app; + } + + public function execute($update_status = true) + { + + $status_content = ""; + try{ + $status_content = @file_get_contents("/tmp/twake.status"); + }catch(\Exception $err){ + error_log($err->getMessage()); + } + + $ready = [ //Array or "true" + "elasticsearch_connection" => false, + "elasticsearch_mapping" => false, + "db_connection" => false, + "db_mapping" => false, + "init" => false + ]; + $has_false = false; + foreach ($ready as $key => $_) { + $ready[$key] = (strpos($status_content, ";".$key.";") !== false); + if(!$ready[$key]){ + $has_false = true; + } + } + if($has_false){ + + if($update_status){ + + $status = ";"; + + //Check ES + $es_not_found = @file_get_contents("/twake.status.no_es") === "1"; + if($es_not_found || !$this->app->getContainer()->getParameter("es.host")){ + $status .= "elasticsearch_connection;elasticsearch_mapping;"; + }else{ + $test = $this->app->getServices()->get("app.restclient")->get("http://" . $this->app->getContainer()->getParameter('es.host')); + if($test){ + $status .= "elasticsearch_connection;"; + + $service_status = @file_get_contents("/twake.status.es_mapping") === "1"; + if($service_status){ + $status .= "elasticsearch_mapping;"; + } + } + } + + //Check scyllaDB + try{ + $doctrine = $this->app->getServices()->get('app.twake_doctrine'); + $em = $doctrine->getManager(); + $connection = $em->getConnection(); + $connection = $connection->getWrappedConnection(); + $connected = true; + }catch(\Exception $e){ + $connected = false; + } + if($connected){ + $status .= "db_connection;"; + + $service_status = @file_get_contents("/twake.status.db_init") === "1"; + if($service_status){ + $status .= "db_mapping;"; + } + + } + + $service_status = @file_get_contents("/twake.status.init") === "1"; + if($service_status){ + $status .= "init;"; + } + + @file_put_contents("/tmp/twake.status", $status); + + return $this->execute(false); + } + + }else{ + $ready = true; + } + + return $ready; + + } + +} diff --git a/twake/backend/core/src/Twake/Core/Services/UserConnectedSecurity.php b/twake/backend/core/src/Twake/Core/Services/UserConnectedSecurity.php new file mode 100755 index 00000000..3ff2f249 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/UserConnectedSecurity.php @@ -0,0 +1,31 @@ +<?php + +namespace Twake\Core\Services; + +use App\App; +use Common\Http\Request; +use Common\Http\Response; + +class UserConnectedSecurity +{ + + /** @var App */ + private $app; + + public function __construct(App $app) + { + $this->app = $app; + } + + public function applySecurity(Request $request) + { + $user = $this->app->getServices()->get("app.session_handler")->getUser($request); + if (!$user || is_string($user)) { + $response = new Response(); + $response->setContent(Array("errors" => ["user_not_connected"])); + return $response; + } + return true; + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Services/Websockets.php b/twake/backend/core/src/Twake/Core/Services/Websockets.php new file mode 100755 index 00000000..79b38cf5 --- /dev/null +++ b/twake/backend/core/src/Twake/Core/Services/Websockets.php @@ -0,0 +1,180 @@ +<?php + +namespace Twake\Core\Services; + +use App\App; +use Twake\Core\Entity\WebsocketsRoute; + +/** + * Class TwakeMailer + * @package Twake\Core\Services + * + * This class send mail with twake default template + */ +class Websockets +{ + + /** @var App */ + private $app; + private $doctrine; + private $pusher; + + public function __construct(App $app) + { + $this->app = $app; + + //Register services to call for init websocekts and verify user has access + $this->services_for_type = Array( + "notifications" => "app.notifications", + "messages" => "app.messages", + "drive" => "app.drive", + "event" => "app.calendar.event", + "calendar" => "app.calendar.calendar", + "board" => "app.tasks.board", + "list" => "app.tasks.list", + "task" => "app.tasks.task", + "tags" => "globalsearch.tag", + "updates" => "app.user_updates" + ); + + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->pusher = $app->getServices()->get("app.pusher"); + } + + public function init($route, $data, $controller = null) + { + + $routes = $this->doctrine->getRepository("Twake\Core:WebsocketsRoute"); + $route_entity = $routes->findOneBy(Array("route" => $route)); + + $new = false; + if (!$route_entity) { + $route_entity = new WebsocketsRoute(); + $route_entity->setRoute($route); + $route_entity->setData($data); + $new = true; + } + + $last_modified_date = $route_entity->getLastModifiedDate(); + $route_entity->setLastModifiedDate(); + //Be fast here (add lock ?) + $this->doctrine->persist($route_entity); + $this->doctrine->flush(); + + $route_endpoint = $route_entity->getRouteRandomEndpoint(); + + if ($new || (new \DateTime())->getTimestamp() - $last_modified_date->getTimestamp() > 60*60*24) { + + $new_key_part = bin2hex(random_bytes(30)); + $new_key = hash('sha256', $route_entity->getKey() . $new_key_part); + + $tmp = explode("-", $route_entity->getKeyVersion()); + $key_version = ((intval($tmp[0]) + 1) % 1000) . "-" . date("U") . "-" . random_int(0, 10000); + + $this->push($route_endpoint, Array( + "new_key" => $new_key_part, + "key_version" => $key_version + ), $route_entity); + + + $route_entity->setKey($new_key); + $route_entity->setKeyVersion($key_version); + $this->doctrine->persist($route_entity); + $this->doctrine->flush(); + + } else { + $new_key = $route_entity->getKey(); + $key_version = $route_entity->getKeyVersion(); + } + + //Verify user has access + $get_result = false; + if ($controller) { + $type = $data["type"]; + if (isset($this->services_for_type[$type])) { + + + $service = $this->app->getServices()->get($this->services_for_type[$type]); + $has_access = $service->init($route, $data, $controller->getUser()); + if (!$has_access) { + return Array(); + } else if (isset($data["get_options"]) && method_exists($service, "get")) { + $_get_result = $service->get($data["get_options"], $controller->getUser()); + if ($_get_result) { + $get_result = []; + foreach ($_get_result as $result) { + if (is_array($result)) { + $get_result[] = $result; + } else { + $get_result[] = $result->getAsArray(); + } + } + } + } + } else { + return Array(); + } + } + + return Array( + "route_id" => $route_endpoint, + "key" => $new_key, + "key_version" => $key_version, + "get" => $get_result + ); + + } + + public function push($route, $event, $route_entity = null) + { + + if (is_array($event) && !array_diff_key($event, array_keys(array_keys($event)))) { + $event = ["multiple" => $event]; + } + + if (!$route_entity) { + $routes = $this->doctrine->getRepository("Twake\Core:WebsocketsRoute"); + $route_entity = $routes->findOneBy(Array("route" => $route)); + } + + if (!$route_entity) { + //Nobody never init this collection so nobody will receive this event + return false; + } + + $route_endpoint = $route_entity->getRouteRandomEndpoint(); + $key_version = $route_entity->getKeyVersion(); + $key = $route_entity->getKey(); + + //Encrypt event + $salt = openssl_random_pseudo_bytes(256); + $iv = openssl_random_pseudo_bytes(16); + $iterations = 9; + $prepared_key = hash_pbkdf2("sha512", $key, $salt, $iterations, 64); + $string = json_encode($event); + $encrypted = trim( + base64_encode( + openssl_encrypt( + $string, + 'aes-256-cbc', + hex2bin($prepared_key), + OPENSSL_RAW_DATA, + $iv + ) + ) + ); + + $this->pusher->push(Array( + "route" => $route, + "public" => $event, + "encrypted" => $encrypted, + "iv" => bin2hex($iv), + "salt" => bin2hex($salt), + "key_version" => $key_version + ), "collections/" . $route_endpoint); + + return true; + + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Discussion/Bundle.php b/twake/backend/core/src/Twake/Discussion/Bundle.php new file mode 100755 index 00000000..299925b8 --- /dev/null +++ b/twake/backend/core/src/Twake/Discussion/Bundle.php @@ -0,0 +1,30 @@ +<?php + +namespace Twake\Discussion; + +require_once __DIR__ . "/Resources/Routing.php"; +require_once __DIR__ . "/Resources/Services.php"; + +use Twake\Discussion\Resources\Routing; +use Twake\Discussion\Resources\Services; +use Common\BaseBundle; + +class Bundle extends BaseBundle +{ + + protected $bundle_root = __DIR__; + protected $bundle_namespace = __NAMESPACE__; + protected $routes = []; + protected $services = []; + + public function init() + { + $routing = new Routing(); + $this->routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Discussion/Controller/Discussion.php b/twake/backend/core/src/Twake/Discussion/Controller/Discussion.php new file mode 100755 index 00000000..efc85ba5 --- /dev/null +++ b/twake/backend/core/src/Twake/Discussion/Controller/Discussion.php @@ -0,0 +1,114 @@ +<?php + +namespace Twake\Discussion\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + + +class Discussion extends BaseController +{ + + public function remove(Request $request) + { + $options = $request->request->get("options"); + $object = $request->request->get("object"); + + if ($object["ephemeral_id"]) { + return new Response(Array("status" => "cancelled")); + } + + $res = $this->get("app.messages")->remove($object, $options, $this->getUser()); + if (!$res) { + return new Response(Array("status" => "error")); + } + + return new Response(Array("data" => Array("object" => $res))); + } + + public function save(Request $request) + { + $options = $request->request->get("options"); + $object = $request->request->get("object"); + $res = $this->get("app.messages")->save($object, $options, $this->getUser()); + if (!$res) { + return new Response(Array("status" => "error")); + } else { + if (!$object["id"]) { + $this->get("administration.counter")->incrementCounter("total_messages", 1); + if($GLOBALS["segment_enabled"]) \Segment::track([ + "event" => "message:send", + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() + ]); + } + } + + return new Response(Array("data" => Array("object" => $res))); + } + + public function getAction(Request $request) + { + $options = $request->request->get("options"); + $objects = $this->get("app.messages")->get($options, $this->getUser()); + if ($objects === false) { + return new Response(Array("status" => "error")); + } + return new Response(Array("data" => $objects)); + } + + public function nodeRealTime(Request $request) + { + $token = explode(" ", getallheaders()["Authorization"])[1]; + $secret = $this->app->getContainer()->getParameter("node.secret"); + if($token != $secret){ + error_log("got node realtime request unauthorized"); + return new Response(Array("error" => "unauthorized")); + } + + $context = $request->request->get("context"); + $entity = $request->request->get("entity"); + $participant = $request->request->get("participant"); + + $channel_id = $participant["id"]; + $parent_message_id = $entity["thread_id"] === $entity["id"] ? "" : $entity["thread_id"]; + $removed = $entity["subtype"] == "deleted"; + + $array = $this->get("app.messages")->convertFromNode($entity, [ + "channel_id" => $channel_id + ]); + + if($removed){ + + $event = Array( + "client_id" => "system", + "action" => "remove", + "message_id" => $entity["id"], + "thread_id" => $parent_message_id + ); + $this->app->getServices()->get("app.pusher")->push($event, "channels/" . $channel_id . "/messages/updates"); + + } else { + + $event = Array( + "client_id" => "system", + "action" => "update", + "message_id" => $entity["id"], + "thread_id" => $parent_message_id + ); + $this->app->getServices()->get("app.pusher")->push($event, "channels/" . $channel_id . "/messages/updates"); + } + + $event = Array( + "client_id" => "bot", + "action" => "save", + "object_type" => "", + "object" => $array + ); + $this->app->getServices()->get("app.websockets")->push("messages/" . $channel_id, $event); + + return new Response(Array("data" => "ok")); + } + + +} diff --git a/twake/backend/core/src/Twake/Discussion/Entity/Message.php b/twake/backend/core/src/Twake/Discussion/Entity/Message.php new file mode 100755 index 00000000..3ef1db86 --- /dev/null +++ b/twake/backend/core/src/Twake/Discussion/Entity/Message.php @@ -0,0 +1,634 @@ +<?php + +namespace Twake\Discussion\Entity; + +use Doctrine\ORM\Mapping as ORM; + + +use Twake\Core\Entity\FrontObject; + +/** + * Message + * + * @ORM\Table(name="message",options={"engine":"MyISAM", "scylladb_keys": {{"channel_id":"ASC", "parent_message_id":"ASC", "id":"DESC"}, {"id":"ASC"}} }) + * @ORM\Entity() + */ +class Message extends FrontObject +{ + + /** + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="channel_id", type="twake_uuid") + * @ORM\Id + */ + private $channel_id; + + /** + * @ORM\Column(name="parent_message_id", type="twake_no_salt_text") + * @ORM\Id + */ + private $parent_message_id = ""; + + /** + * @ORM\Column(name="responses_count", type="integer") + */ + private $responses_count = 0; + + /** + * @ORM\Column(name="message_type", type="integer") + */ + private $message_type = 0; //0 from user, 1 from application, 2 from system + + /** + * @ORM\ManyToOne(targetEntity="Twake\Users\Entity\User",cascade={"persist"}) + * @ORM\JoinColumn(nullable=true) + */ + private $sender = null; + + /** + * @ORM\Column(name="application_id", type="twake_no_salt_text", nullable=true) + */ + private $application_id = null; + + + /** + * @ORM\Column(name="creation_date", type="twake_datetime", nullable=true) + */ + private $creation_date; + + /** + * @ORM\Column(name="modification_date", type="twake_datetime", nullable=true) + */ + private $modification_date; + + /** + * @ORM\Column(type="twake_boolean") + */ + private $edited = false; + + /** + * @ORM\Column(type="twake_boolean") + */ + private $pinned = false; + + /** + * @ORM\Column(name="hidden_data", type="twake_text") + */ + private $hidden_data = "{}"; + + /** + * @ORM\Column(name="reactions", type="twake_text") + */ + private $reactions = "{}"; + + /** + * @ORM\Column(name="content", type="twake_text") + */ + private $content = "[]"; + + /** + * @ORM\Column(name="user_specific_content", type="twake_text") + */ + private $user_specific_content = "[]"; + + /** + * @ORM\Column(name="tags", type="twake_text", nullable=true) + */ + private $tags; + + /** + * @ORM\Column(name="block_id", type="twake_timeuuid", nullable=true) + */ + private $block_id = null; + + /** + * @ORM\Column(name="increment_at_time", type="twake_bigint", nullable=true) + */ + private $increment_at_time = null; + + /** + * Message constructor. + */ + + public function __construct($channel_id, $parent_message_id, $increment_at_time = 0) + { + parent::__construct(); + $this->channel_id = $channel_id; + $this->parent_message_id = $parent_message_id; + $this->creation_date = new \DateTime(); + $this->modification_date = new \DateTime(); + $this->increment_at_time = $increment_at_time; + } + + + /** + * @return mixed + */ + public function getTags() + { + return json_decode($this->tags); + } + + /** + * @param mixed $tags + */ + public function setTags($tags) + { + $this->tags = json_encode($tags); + } + + /** + * Get the value of Id + * + * @return mixed + */ + + public function getId() + { + return $this->id; + } + + /** + * Set the value of Id + * + * @param mixed id + * + * @return self + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * Get the value of Channel Id + * + * @return mixed + */ + public function getChannelId() + { + return $this->channel_id; + } + + /** + * Get the value of Parent Message Id + * + * @return mixed + */ + public function getParentMessageId() + { + return $this->parent_message_id; + } + + public function setParentMessageId($id) + { + $this->parent_message_id = $id; + } + + /** + * Get the value of Responses Count + * + * @return mixed + */ + public function getResponsesCount() + { + return $this->responses_count; + } + + /** + * Set the value of Responses Count + * + * @param mixed responses_count + * + * @return self + */ + public function setResponsesCount($responses_count) + { + $this->responses_count = max(0, $responses_count); + + return $this; + } + + /** + * Get the value of Message Type + * + * @return mixed + */ + public function getMessageType() + { + return $this->message_type; + } + + /** + * Set the value of Message Type + * + * @param mixed message_type + * + * @return self + */ + public function setMessageType($message_type) + { + $this->message_type = $message_type; + + return $this; + } + + /** + * Get the value of Sender + * + * @return mixed + */ + public function getSender() + { + return $this->sender; + } + + /** + * Set the value of Sender + * + * @param mixed sender + * + * @return self + */ + public function setSender($sender) + { + $this->sender = $sender; + + return $this; + } + + /** + * Get the value of Application + * + * @return mixed + */ + public function getApplicationId() + { + return $this->application_id; + } + + /** + * Set the value of Application + * + * @param mixed application + * + * @return self + */ + public function setApplicationId($application_id) + { + $this->application_id = $application_id; + + return $this; + } + + /** + * Get the value of Creation Date + * + * @return mixed + */ + public function getCreationDate() + { + return $this->creation_date; + } + + /** + * Set the value of Creation Date + * + * @param mixed creation_date + * + * @return self + */ + public function setCreationDate($creation_date) + { + $this->creation_date = $creation_date; + + return $this; + } + + /** + * Get the value of Modification Date + * + * @return mixed + */ + public function getModificationDate() + { + return $this->modification_date; + } + + /** + * Set the value of Modification Date + * + * @param mixed modification_date + * + * @return self + */ + public function setModificationDate($modification_date) + { + $this->modification_date = $modification_date; + + return $this; + } + + /** + * Get the value of Edited + * + * @return mixed + */ + public function getEdited() + { + return $this->edited; + } + + /** + * Set the value of Edited + * + * @param mixed edited + * + * @return self + */ + public function setEdited($edited) + { + $this->edited = $edited; + + return $this; + } + + /** + * Get the value of Pinned + * + * @return mixed + */ + public function getPinned() + { + return $this->pinned; + } + + /** + * Set the value of Pinned + * + * @param mixed pinned + * + * @return self + */ + public function setPinned($pinned) + { + $this->pinned = $pinned; + + return $this; + } + + /** + * Get the value of Hidden Data + * + * @return mixed + */ + public function getHiddenData() + { + if (!$this->hidden_data) { + return Array(); + } + return json_decode($this->hidden_data, 1); + } + + /** + * Set the value of Hidden Data + * + * @param mixed hidden_data + * + * @return self + */ + public function setHiddenData($hidden_data) + { + $this->hidden_data = json_encode($hidden_data); + + return $this; + } + + /** + * Get the value of Hidden Data + * + * @return mixed + */ + public function getReactions() + { + if (!$this->reactions) { + return Array(); + } + return json_decode($this->reactions, 1); + } + + /** + * Set the value of Hidden Data + * + * @param mixed hidden_data + * + * @return self + */ + public function setReactions($reactions) + { + $this->reactions = json_encode($reactions); + + return $this; + } + + public function getContent() + { + return json_decode($this->content, true); + } + + public function setContent($content) + { + $this->content = json_encode($content); + } + + public function getUserSpecificContent() + { + return json_decode($this->user_specific_content, true); + } + + public function setUserSpecificContent($user_specific_content) + { + $this->user_specific_content = json_encode($user_specific_content); + } + + public function getBlockId() + { + return $this->block_id; + } + + public function setBlockId($block_id) + { + $this->block_id = $block_id; + } + + public function getIncrementAtTime() + { + return $this->increment_at_time; + } + + public function setIncrementAtTime($increment_at_time) + { + $this->increment_at_time = $increment_at_time; + } + + public function getMessageTypeObject() { + switch($this->getMessageType()) { + case 1: return Array( + "type" => "message", + "subtype" => "application", + ); + case 2: return Array( + "type" => "message", + "subtype" => "system", + ); + case 0: + default: + return Array( + "type" => "message", + "subtype" => null, + ); + } + } + + public function getNewApiObjectReactions($messageEntity) { + $reactions = Array(); + + if($messageEntity->getReactions() == null) return $reactions; + + $orignal_reactions_array = $messageEntity->getReactions(); + + foreach($orignal_reactions_array as $key => $value){ + $new_reaction_object = Array( + "name" => $value["name"] ?: $key + ); + $new_reaction_object = array_merge($new_reaction_object, $value); + $new_reaction_object["users"] = array_values($new_reaction_object["users"]); + + array_push($reactions, $new_reaction_object); + } + + return $reactions; + } + + /** + * Set files for new api object + */ + public function setFiles($messageEntity) { + $files = Array(); + + if(!isset($messageEntity->getContent()['files'])) return $files; + + $orignal_files = $messageEntity->getContent()['files']; + + foreach($orignal_files as $file){ + if($file["type"] == "file") { + $new_file_format = Array( + "company_id" => "", + "message_id" => $messageEntity->getId(), + "id" => $file["content"], + "metadata" => Array( + "source" => "drive", + "external_id" => $file["content"] + ), + ); + array_push($files, $new_file_format); + } + } + + return $files; + } + + /** + * Set blocks for new api object + */ + public function setBlocks($messageEntity) { + $blocks = Array(); + $content = $messageEntity->getContent(); + + if(!isset($content)) return $blocks; + + $markdown_element = Array( + "type" => "mrkdwn", + "text" => isset($content['original_str']) ? $content['original_str'] : "" + ); + + $new_block_format = Array( + "type" => "section", + "text" => $markdown_element + ); + + array_push($blocks, $new_block_format); + + return $blocks; + } + + /** + * Generate new api object + */ + public function generateNewApiObject($messageEntity, $array) { + + $message_type_object = $messageEntity->getMessageTypeObject(); + $api_object = Array( + "id" => $messageEntity->getId(), + "channel_id" => $messageEntity->getChannelId(), + "thread_id" => $messageEntity->getParentMessageId(), + "created_at" => ($messageEntity->getCreationDate() ? $messageEntity->getCreationDate()->getTimestamp() : null), + "application_id" => $messageEntity->getApplicationId(), + "user_id" => is_string($messageEntity->getSender()) ? $messageEntity->getSender() : ($messageEntity->getSender() ? $messageEntity->getSender()->getId() : null), + "edited" => $messageEntity->getEdited(), + "text" => isset($messageEntity->getContent()['original_str']) ? $messageEntity->getContent()['original_str'] : "", + "blocks" => $messageEntity->setBlocks($messageEntity), + "files" => $messageEntity->setFiles($messageEntity), + "context" => $messageEntity->getHiddenData(), + "title" => $messageEntity->getHiddenData()['custom_title'] ?: null, + "picture" => $messageEntity->getHiddenData()['custom_icon'] ?: null, + "stats" => Array( + "last_activity" => ($this->getModificationDate() ? $this->getModificationDate()->getTimestamp() : null), + "replies" => $messageEntity->getResponsesCount() + ), + "pinned_info" => Array( + "pinned_by" => is_string($messageEntity->getSender()) ? $messageEntity->getSender() : ($messageEntity->getSender() ? $messageEntity->getSender()->getId() : null), + "pinned_at" => 0, + ), + "reactions" => $messageEntity->getNewApiObjectReactions($messageEntity), + ); + + return $array = array_merge($api_object, $message_type_object); + } + + + public function getAsArray() + { + $api_object = $this->generateNewApiObject($this, $api_object); + + $old_message_object = Array( + "id" => $this->getId(), + "front_id" => $this->getFrontId(), + "channel_id" => $this->getChannelId(), + "parent_message_id" => $this->getParentMessageId(), + "responses_count" => $this->getResponsesCount(), + "message_type" => $this->getMessageType(), + "sender" => is_string($this->getSender()) ? $this->getSender() : ($this->getSender() ? $this->getSender()->getId() : null), + "application_id" => $this->getApplicationId(), + "edited" => $this->getEdited(), + "pinned" => $this->getPinned(), + "hidden_data" => $this->getHiddenData(), + "_reactions" => $this->getReactions(), + "modification_date" => ($this->getModificationDate() ? $this->getModificationDate()->getTimestamp() : null), + "creation_date" => ($this->getCreationDate() ? $this->getCreationDate()->getTimestamp() : null), + "content" => $this->getContent(), + "user_specific_content" => $this->getUserSpecificContent(), + "increment_at_time" => $this->getIncrementAtTime(), + ); + + return array_merge($old_message_object, $api_object); + } + +} diff --git a/twake/backend/core/src/Twake/Discussion/Entity/MessageReaction.php b/twake/backend/core/src/Twake/Discussion/Entity/MessageReaction.php new file mode 100755 index 00000000..dfe86b5c --- /dev/null +++ b/twake/backend/core/src/Twake/Discussion/Entity/MessageReaction.php @@ -0,0 +1,70 @@ +<?php + +namespace Twake\Discussion\Entity; + +use Doctrine\ORM\Mapping as ORM; + + +use Twake\Core\Entity\FrontObject; + +/** + * Message + * + * @ORM\Table(name="message_reaction",options={"engine":"MyISAM", "scylladb_keys": {{"message_id":"ASC", "user_id":"ASC"}} }) + * @ORM\Entity() + */ +class MessageReaction +{ + + /** + * @ORM\Column(name="message_id", type="twake_timeuuid") + * @ORM\Id + */ + private $message_id; + + /** + * @ORM\Column(name="user_id", type="twake_timeuuid") + * @ORM\Id + */ + private $user_id; + + /** + * @ORM\Column(name="reaction", type="twake_text") + */ + private $reaction = ""; + + /** + * Message constructor. + */ + public function __construct($message_id, $user_id) + { + $this->message_id = $message_id; + $this->user_id = $user_id; + } + + /** + * @return mixed + */ + public function getReaction() + { + return $this->reaction; + } + + /** + * @param mixed $reaction + */ + public function setReaction($reaction) + { + $this->reaction = $reaction; + } + + /** + * @return mixed + */ + public function getUserId() + { + return $this->user_id; + } + + +} diff --git a/twake/backend/core/src/Twake/Discussion/Resources/Routing.php b/twake/backend/core/src/Twake/Discussion/Resources/Routing.php new file mode 100755 index 00000000..7e9bd3f9 --- /dev/null +++ b/twake/backend/core/src/Twake/Discussion/Resources/Routing.php @@ -0,0 +1,19 @@ +<?php + +namespace Twake\Discussion\Resources; + +use Common\BaseRouting; + +class Routing extends BaseRouting +{ + + protected $routing_prefix = "ajax/discussion/"; + + protected $routes = [ + "get" => ["handler" => "Discussion:getAction", "methods" => ["POST"], "security" => ["user_connected_security"]], + "save" => ["handler" => "Discussion:save", "methods" => ["POST"], "security" => ["user_connected_security"]], + "remove" => ["handler" => "Discussion:remove", "methods" => ["POST"], "security" => ["user_connected_security"]], + "noderealtime" => ["handler" => "Discussion:nodeRealTime", "methods" => ["POST"]] + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Discussion/Resources/Services.php b/twake/backend/core/src/Twake/Discussion/Resources/Services.php new file mode 100755 index 00000000..6209d8b6 --- /dev/null +++ b/twake/backend/core/src/Twake/Discussion/Resources/Services.php @@ -0,0 +1,14 @@ +<?php + +namespace Twake\Discussion\Resources; + +use Common\BaseServices; + +class Services extends BaseServices +{ + protected $services = [ + "app.messages" => "MessageSystem", + "app.messages.depreciated" => "MessageSystemDepreciated" + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Discussion/Services/MessageSystem.php b/twake/backend/core/src/Twake/Discussion/Services/MessageSystem.php new file mode 100755 index 00000000..48e75bb3 --- /dev/null +++ b/twake/backend/core/src/Twake/Discussion/Services/MessageSystem.php @@ -0,0 +1,345 @@ +<?php + + +namespace Twake\Discussion\Services; + +use App\App; +use Twake\Discussion\Entity\Message; +use \Firebase\JWT\JWT; + +class MessageSystem +{ + + public function __construct(App $app) + { + $this->app = $app; + $this->rest = $app->getServices()->get("app.restclient"); + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->depreciated = $app->getServices()->get("app.messages.depreciated"); + $this->access_manager = $app->getServices()->get("app.accessmanager"); + } + + public function init($route, $data, $current_user = null) + { + return $this->depreciated->init($route, $data, $current_user); + } + + public function hasAccess($data, $current_user = null, $message = null) + { + return $this->depreciated->hasAccess($data, $current_user, $message); + } + + public function get($options, $current_user) + { + $offset = isset($options["offset"]) ? $options["offset"] : null; + $limit = isset($options["limit"]) ? $options["limit"] : 20; + $message_id = isset($options["id"]) ? $options["id"] : ""; + $parent_message_id = isset($options["parent_message_id"]) ? $options["parent_message_id"] : ($message_id ?: ""); + + if($options["company_id"] && $options["workspace_id"]){ + $channel = [ + "company_id" => $options["company_id"], + "workspace_id" => $options["workspace_id"], + "channel_id" => $options["channel_id"], + ]; + }else{ + $channel = $this->getInfosFromChannel($options["company_id"], $options["workspace_id"], $options["channel_id"]); + if(!$channel){ + return; + } + } + + if($message_id){ + $uri = "/companies/".$channel["company_id"]."/threads/".$parent_message_id."/messages/".$message_id; + $singleResponse = $this->forwardToNode("GET", $uri, [], $current_user); + $response = []; + $response["resources"] = [ $singleResponse["resource"] ]; + }else{ + if(!$parent_message_id){ + $uri = "/companies/".$channel["company_id"]."/workspaces/".$channel["workspace_id"]."/channels/".$channel["channel_id"]."/feed?replies_per_thread=5&limit=".abs($limit)."&page_token=".$offset."&direction=".($limit > 0?"history":"future"); + }else{ + $uri = "/companies/".$channel["company_id"]."/threads/".$parent_message_id."/messages?replies_per_thread=5&limit=".abs($limit)."&page_token=".$offset."&direction=".($limit > 0?"history":"future"); + } + $response = $this->forwardToNode("GET", $uri, [], $current_user); + } + + if(!is_array($response["resources"])){ + return []; + } + + $messages = []; + foreach($response["resources"] as $message){ + if($message["id"]){ + $messages[] = $this->convertFromNode($message, $channel); + if($message["last_replies"]){ + foreach($message["last_replies"] as $reply){ + if($reply["id"] !== $message["id"]) + $messages[] = $this->convertFromNode($reply, $channel); + } + } + } + } + + return $messages; + } + + public function remove($object, $options, $current_user = null) + { + $channel = $this->getInfosFromChannel($object["company_id"], $object["workspace_id"], $object["channel_id"]); + $channel["company_id"] = $channel["company_id"] ?? $object["company_id"]; + $channel["workspace_id"] = $channel["workspace_id"] ?? $object["workspace_id"]; + + if(!$channel){ + return; + } + + if($object["id"]){ + $response = $this->forwardToNode("POST", "/companies/".$channel["company_id"]."/threads/".($object["parent_message_id"] ?: $object["id"])."/messages/".$object["id"]."/delete", null, $current_user, $application ? $application->getId() : null); + return $this->convertFromNode($response["resource"], $channel); + } + return null; + } + + public function save($object, $options, $current_user = null, $application = null) + { + $channel = $this->getInfosFromChannel($object["company_id"], $object["workspace_id"], $object["channel_id"]); + $channel["company_id"] = $channel["company_id"] ?? $object["company_id"]; + $channel["workspace_id"] = $channel["workspace_id"] ?? $object["workspace_id"]; + + if(!$channel){ + return; + } + + $response = null; + + if($object["id"]){ + //Manage message pin + $response = $this->forwardToNode("POST", "/companies/".$channel["company_id"]."/threads/".($object["parent_message_id"] ?: $object["id"])."/messages/".$object["id"]."/pin", ["pin" => $object["pinned"]], $current_user, $application ? $application->getId() : null); + } + + if(isset($object["_user_reaction"])){ + //Manage user reaction + $response = $this->forwardToNode( + "POST", + "/companies/".$channel["company_id"]."/threads/".($object["parent_message_id"] ?: $object["id"])."/messages/".$object["id"]."/reaction", + [ + "reactions" => $object["_user_reaction"] ? + (is_array($object["_user_reaction"]) ? $object["_user_reaction"] : [$object["_user_reaction"]]) + : [] + ], + $current_user, $application ? $application->getId() : null); + }else{ + //Manage message edition + + $newMessage = !$object["id"]; + + $message = $this->convertToNode($object); + if(!$current_user){ + $message["subtype"] = "system"; + } + if($application){ + $message["subtype"] = "application"; + } + $message["context"]["_front_id"] = $object["front_id"]; + + //New thread + if(!$object["parent_message_id"] && $newMessage){ + + $data = [ + "resource" => [ + "participants" => [ + [ + "type" => "channel", + "id" => $channel["channel_id"], + "workspace_id" => $channel["workspace_id"], + "company_id" => $channel["company_id"], + ] + ] + ], + "options" => [] + ]; + + $response = $this->forwardToNode("POST", "/companies/".$channel["company_id"]."/threads", $data, $current_user, $application ? $application->getId() : null); + $object["parent_message_id"] = $response["resource"]["id"]; + $message["thread_id"] = $response["resource"]["id"]; + $message["id"] = $response["resource"]["id"]; + } + + $options = []; + if(isset($object["_once_replace_message_parent_message"])){ + $options["previous_thread"] = $object["_once_replace_message_parent_message"] ?: $object["_once_replace_message"] ?: $object["id"]; + } + + //New message in thread (also called for new threads because we set the parent_message_id automatically) + if($object["parent_message_id"] && $newMessage){ + + $data = [ + "resource" => $message, + "options" => $options + ]; + + $response = $this->forwardToNode("POST", "/companies/".$channel["company_id"]."/threads/".($object["parent_message_id"] ?: $object["id"])."/messages", $data, $current_user, $application ? $application->getId() : null); + + }else + + //Edited message + if(!$newMessage){ + + $data = [ + "resource" => $message, + "options" => $options + ]; + + $response = $this->forwardToNode("POST", "/companies/".$channel["company_id"]."/threads/".($object["parent_message_id"] ?: $object["id"])."/messages/".$object["id"], $data, $current_user, $application ? $application->getId() : null); + + }else { + + error_log("Unknown operation"); + + } + + } + + error_log(json_encode($response)); + + return $this->convertFromNode($response["resource"], $channel); + } + + private function convertToNode($object){ + + //TODO convert to new block if this is user 'simple' message + + $blocks = [[ + "type" => "twacode", + "elements" => $object["content"]["formatted"] ?: $object["content"]["prepared"] ?: $object["content"] + ]]; + + $files = []; + + $ephemeral = (isset($object["_once_ephemeral_message"]) && $object["_once_ephemeral_message"] || isset($object["ephemeral_id"]) && $object["ephemeral_id"]); + + return [ + "ephemeral" => $ephemeral ? [ + "id" => $object["ephemeral_id"] ?: $object["front_id"] ?: $object["id"] ?: $object["ephemeral_message_recipients"][0], + "version" => date("U"), + "recipient" => $object["ephemeral_message_recipients"][0], + "recipient_context_id" => "", + ] : null, + "text" => $object["content"]["original_str"] ?: $object["content"]["fallback_string"], + "blocks" => $blocks, + "files" => $object["files"], + "context" => $object["hidden_data"] + ]; + } + + public function convertFromNode($message, $channel){ + + if($message["last_replies"] || $message["thread_id"] === $message["id"]){ + $message["thread_id"] = ""; + } + + $phpMessage = new Message($channel["channel_id"], $message["thread_id"]); + + $phpMessage->setId($message["id"] ?: $message["ephemeral"]["id"]); + $phpMessage->setFrontId($message["context"]["_front_id"] ?: $message["id"] ?: $message["ephemeral"]["id"]); + $phpMessage->setSender($message["user_id"]); + $phpMessage->setApplicationId($message["application_id"]); + $phpMessage->setMessageType($message["subtype"] == "application" ? 1 : ($message["subtype"] == "system" ? 2 : 0)); + $phpMessage->setHiddenData($message["context"]); + + $phpMessage->setPinned(!!$message["pinned_info"]); + $phpMessage->setEdited(false); //!!$message["edited"]); + $phpMessage->setReactions($message["reactions"]); + + $phpMessage->setCreationDate(new \DateTime("@" . intval($message["created_at"] / 1000))); + $phpMessage->setModificationDate(new \DateTime("@" . intval(($message["edited_at"] ?: $message["created_at"]) / 1000))); + + $phpMessage->setResponsesCount(max(0, $message["stats"]["replies"] - 1)); + + // Find the twacode block if exists or get the fallback string + $prepared = []; + if($message["blocks"]) + foreach( $message["blocks"] as $block ){ + if($block["type"] === "twacode"){ + $prepared = $block["elements"]; + } + if($block["type"] === "section" && count($prepared) === 0){ + $prepared = [["type" => "twacode", "content" => $block["text"]["text"] || ""]]; + } + } + + + $phpMessage->setContent([ + "fallback_string" => $message["text"], + "original_str" => $message["text"], + "prepared" => $prepared + ]); + + $array = $phpMessage->getAsArray(); + + if($message["subtype"] === "deleted"){ + $array["subtype"] = "deleted"; + } + + if($message["ephemeral"]){ + $array["front_id"] = $message["id"]; + $array["ephemeral_id"] = $message["id"] ?: $message["ephemeral"]["id"]; + $array["ephemeral_message_recipients"] =[ $message["ephemeral"]["recipient"]]; + $array["_user_ephemeral"] = true; + } + + $array["files"] = $message["files"]; + + return $array; + } + + private function getInfosFromChannel($companyId, $workspaceId, $channelId){ + + $this->access_manager->getChannelCache($companyId, $workspaceId, $channelId); + + $channelDetails = $this->doctrine->getRepository("Twake\Core:CachedFromNode")->findOneBy(Array("company_id" => "unused", "type" => "channel", "key"=>$channelId)); + if($channelDetails){ + return $channelDetails->getData(); + } + return null; + } + + private function forwardToNode($method, $route, $data = [], $user = null, $applicationId = null){ + + $uri = str_replace("/private", "/internal/services/messages/v1", $this->app->getContainer()->getParameter("node.api")) . + ltrim($route, "/"); + + error_log($user); + + $key = $this->app->getContainer()->getParameter("jwt.secret"); + $payload = [ + "exp" => date("U") + 60, + "type" => "access", + "iat" => intval(date("U")) - 60*10, + "nbf" => intval(date("U")) - 60*10, + "sub" => $user ? $user->getId() : null, + "email" => $user ? $user->getEmail() : null, + "application_id" => $applicationId, + "server_request" => true, + "provider_id" => $user ? $user->getIdentityProviderId() : null, + "track" => $user ? $user->getTrack() : true + ]; + $jwt = JWT::encode($payload, $key); + + $opt = [ + CURLOPT_HTTPHEADER => Array( + "Authorization: Bearer " . $jwt, + "Content-Type: application/json" + ), + CURLOPT_CONNECTTIMEOUT => 1, + CURLOPT_TIMEOUT => 1 + ]; + + $res = $this->rest->request($method, $uri, json_encode($data), $opt); + + $res = $res->getContent(); + $res = json_decode($res, 1); + return $res; + } + +} diff --git a/twake/backend/core/src/Twake/Discussion/Services/MessageSystemDepreciated.php b/twake/backend/core/src/Twake/Discussion/Services/MessageSystemDepreciated.php new file mode 100755 index 00000000..39819612 --- /dev/null +++ b/twake/backend/core/src/Twake/Discussion/Services/MessageSystemDepreciated.php @@ -0,0 +1,832 @@ +<?php + + +namespace Twake\Discussion\Services; + +use App\App; +use Twake\Discussion\Entity\Call; +use Twake\Discussion\Entity\Channel; +use Twake\Discussion\Entity\Message; +use Twake\Discussion\Entity\MessageLike; +use Twake\Discussion\Entity\MessageReaction; +use Twake\Discussion\Model\MessagesSystemInterface; +use Twake\GlobalSearch\Entity\Bloc; +use Twake\Core\Entity\CachedFromNode; +use Emojione\Client; +use Emojione\Ruleset; + +class MessageSystemDepreciated +{ + + public function __construct(App $app) + { + $this->em = $app->getServices()->get("app.twake_doctrine"); + $this->applications_api = $app->getServices()->get("app.applications_api"); + $this->websockets_service = $app->getServices()->get("app.websockets"); + $this->access_manager = $app->getServices()->get("app.accessmanager"); + $this->queues = $app->getServices()->get('app.queues')->getAdapter(); + $this->emojione_client = new Client(new Ruleset()); + $this->app = $app; + } + + /** Called from Collections manager to verify user has access to websockets room, registered in Core/Services/Websockets.php */ + public function init($route, $data, $current_user = null) + { + + $route = explode("/", $route); + $channel_id = isset($route[1]) ? $route[1] : null; + + if (!$channel_id) { + return false; + } + + if($data["get_options"]){ + $data = $data["get_options"]; + } + + return $this->hasAccess([ + "channel_id" => $channel_id, + "company_id" => $data["company_id"], + "workspace_id" => $data["workspace_id"], + ], $current_user); + } + + public function hasAccess($data, $current_user = null, $message = null) + { + + if ($current_user === null) { + return true; + } + if (!is_string($current_user)) { + $current_user = $current_user->getId(); + } + + //Verify message access + if ($message) { + if ($current_user && $message->getSender() && $message->getSender()->getId() != $current_user) { + return false; //Not my message + } + } + + $channel_id = $data["channel_id"]; + + return $this->access_manager->has_access($current_user, [ + "type" => "Channel", + "edition" => false, + "object_id" => $channel_id + ], [ + "company_id" => $data["company_id"], + "workspace_id" => $data["workspace_id"] + ]); + } + + public function get($options, $current_user) + { + $channel_id = $options["channel_id"]; + if (!$channel_id) { + return false; + } + + if (!$this->hasAccess($options, $current_user)) { + return false; + } + + $message_repo = $this->em->getRepository("Twake\Discussion:Message"); + + + $offset = isset($options["offset"]) ? $options["offset"] : null; + $limit = isset($options["limit"]) ? $options["limit"] : 60; + $parent_message_id = isset($options["parent_message_id"]) ? $options["parent_message_id"] : ""; + + if($options["id"]){ + $messages_ent = $message_repo->findBy(Array("channel_id" => $channel_id, "parent_message_id" => $parent_message_id, "id" => $options["id"])); + }else{ + $messages_ent = $message_repo->findBy(Array("channel_id" => $channel_id, "parent_message_id" => $parent_message_id), Array(), $limit, $offset, ["parent_message_id", "id"], ["ASC", "DESC"]); + } + + $messages_ent = array_reverse($messages_ent); + + $messages = []; + foreach ($messages_ent as $message) { + if ($parent_message_id == "" && $message->getResponsesCount() > 0 && !$options["id"]) { + $messages_responses_ent = $message_repo->findBy(Array("channel_id" => $channel_id, "parent_message_id" => $message->getId()), Array(), 10, null, "id", "DESC"); + if (count($messages_responses_ent) == 0) { + $message->setResponsesCount(0); + $this->em->persist($message); + $this->em->flush(); + } + foreach ($messages_responses_ent as $message_response) { + $messages[] = $message_response->getAsArray(); + } + } + + $messages[] = $message->getAsArray(); + } + + //Add my reaction if necessary + foreach ($messages as $id => $message) { + + //If possible, show only current user content ! + if ($current_user && isset($message["user_specific_content"][$current_user->getId()])) { + $tmp = Array(); + $tmp[$current_user->getId()] = $message["user_specific_content"][$current_user->getId()]; + $message["user_specific_content"] = $tmp; + } + + if ($current_user && count($message["reactions"]) > 0) { + $message_reaction_repo = $this->em->getRepository("Twake\Discussion:MessageReaction"); + $message_reaction = $message_reaction_repo->findOneBy(Array("user_id" => $current_user->getId(), "message_id" => $message["id"])); + if ($message_reaction) { + $messages[$id]["_user_reaction"] = $message_reaction->getReaction(); + } + } + + } + + if(count($messages) === 0 + && !$options["id"] + && !$offset + && $limit > 0 + && !$parent_message_id ){ + + $init_message = Array( + "channel_id" => $options["channel_id"], + "hidden_data" => Array("type" => "init_channel"), + "content" => "[]" + ); + return [$this->save($init_message, Array())]; + } + + return $messages; + } + + public function remove($object, $options, $current_user = null) + { + $channel_id = $object["channel_id"]; + if (!$channel_id) { + return false; + } + + if (!$object["parent_message_id"]) { + $object["parent_message_id"] = ""; + } + + if(!$object["ephemeral_id"]){ + $message_repo = $this->em->getRepository("Twake\Discussion:Message"); + $message = $message_repo->findOneBy(Array("channel_id" => $object["channel_id"], "parent_message_id" => $object["parent_message_id"], "id" => $object["id"])); + + if (!$message) { + return false; + } + + //TODO for allow_delete == "administrators" implement user access verification + if (!($this->hasAccess($message->getAsArray(), $current_user, $message) || $message->getAsArray()["hidden_data"]["allow_delete"] == "everyone" || $message->getAsArray()["hidden_data"]["allow_delete"] == "administrators")) { + return false; + } + + if ($message->getResponsesCount() > 0) { + return false; + } + + if ($message->getParentMessageId()) { + $parent_message = $message_repo->findOneBy(Array("channel_id" => $object["channel_id"], "parent_message_id" => "", "id" => $message->getParentMessageId())); + $parent_message->setResponsesCount($parent_message->getResponsesCount() - 1); + $this->em->persist($parent_message); + } + + $array_before_delete = $message->getAsArray(); + + $this->em->remove($message); + $this->em->flush(); + + $this->deleteInBloc($message); + }else{ + $array_before_delete = $object; + } + + $event = Array( + "client_id" => "system", + "action" => "remove", + "message_id" => $array_before_delete["id"], + "thread_id" => $array_before_delete["parent_message_id"] + ); + $this->app->getServices()->get("app.pusher")->push($event, "channels/" . $array_before_delete["channel_id"] . "/messages/updates"); + + $event = Array( + "client_id" => "system", + "action" => "remove", + "object_type" => "", + "front_id" => $array_before_delete["front_id"] + ); + $this->app->getServices()->get("app.websockets")->push("messages/" . $array_before_delete["channel_id"], $event); + + return $array_before_delete; + + } + + public function deleteInBloc($message) + { + + if($message->getBlockId()){ + + $bloc = $this->em->getRepository("Twake\GlobalSearch:Bloc")->findOneBy(Array("id" => $message->getBlockId())); + + if (!$bloc) { + return false; + } + + try { + $bloc->removeMessage($message->getId()); + + $this->em->persist($bloc); + $this->em->flush(); + + if ($bloc->getLock() == true) { + $this->em->es_put($bloc, $bloc->getEsType()); + } + + } catch (\Exception $e) { + error_log($e->getMessage()); + } + + } + + } + + /** + * @param $object + * @param $options + * @param null $user + * @param null $application + * @return array + */ + public function save($object, $options, $user = null, $application = null) + { + + $channel_id = $object["channel_id"]; + if (!$channel_id) { + return false; + } + + if (!$object["parent_message_id"]) { + $object["parent_message_id"] = ""; + } + + $ephemeral = (isset($object["_once_ephemeral_message"]) && $object["_once_ephemeral_message"] || isset($object["ephemeral_id"]) && $object["ephemeral_id"]); + if ($ephemeral) { + unset($object["id"]); + } + + $message_repo = $this->em->getRepository("Twake\Discussion:Message"); + + $did_create = false; + + $message = null; + + if (isset($object["id"])) { + $message = $message_repo->findOneBy(Array("channel_id" => $object["channel_id"], "parent_message_id" => isset($object["_once_replace_message_parent_message"]) ? $object["_once_replace_message_parent_message"] : $object["parent_message_id"], "id" => $object["id"])); + + if (!$message) { + $message = $message_repo->findOneBy(Array("id" => $object["id"])); + if ($message) { + if (isset($object["channel_id"]) && $object["channel_id"] != $message->getChannelId()) { + return false; + } + if (isset($object["_once_replace_message_parent_message"]) && $object["_once_replace_message_parent_message"] != $message->getParentMessageId()) { + return false; + } else if (isset($object["parent_message_id"]) && $object["parent_message_id"] != $message->getParentMessageId()) { + return false; + } + } else { + return false; + } + } + + //Verify can modify this message + if ($message && !$this->hasAccess($object, $current_user, $message)) { + return false; + } + + if (!$message) { + return false; + } + + foreach ($message->getAsArray() as $key => $value) { + if (!isset($object[$key])) { + $object[$key] = $value; + } + } + + } + + if ($message == null) { + + //Verify can create in channel + if (!$this->hasAccess($object, $current_user)) { + + return false; + } + + + if (!$ephemeral && $object["parent_message_id"]) { + //Increment parent + $new_parent = $message_repo->findOneBy(Array("channel_id" => $object["channel_id"], "parent_message_id" => "", "id" => $object["parent_message_id"])); + if (!$new_parent) { + $object["parent_message_id"] = ""; + } else { + $new_parent->setResponsesCount($new_parent->getResponsesCount() + 1); + $this->em->persist($new_parent); + $this->share($new_parent); + } + } + + //Create a new message + $message = new Message($object["channel_id"], $object["parent_message_id"]); + + $message->setModificationDate(new \DateTime()); + if ($object["front_id"]) { + $message->setFrontId($object["front_id"]); + } + + if ($object["ephemeral_id"]) { + $message->setId($object["ephemeral_id"]); + $message->setFrontId($object["ephemeral_id"]); + } + + $did_create = true; + + } else if ($message->getContent() != $object["content"]) { + $message->setEdited(true); + $message->setModificationDate(new \DateTime()); + } + + //Move message + if (!$ephemeral && isset($object["_once_replace_message_parent_message"])) { + $new_parent = null; + if ($object["parent_message_id"]) { + $new_parent = $message_repo->findOneBy(Array("channel_id" => $object["channel_id"], "parent_message_id" => "", "id" => $object["parent_message_id"])); + } + $this->moveMessageToNewParent($message, $new_parent); + } + + if ($did_create) { + //Set message type + if ($application) { + $message->setMessageType(1); + $message->setApplicationId($application->getId()); + if ($user) { + $message->setSender($user); + } + } else if (!$user && !$application) { + $message->setMessageType(2); + } else if ($user && !$application) { + $message->setMessageType(0); + } + } + + //If no sender set, update sender (can be modified after) + if (!$message->getSender() && $message->getMessageType() == 0) { + $message->setSender($user); + } + + + //Update message values + if ($application && isset($object["_once_user_specific_update"])) { + $specific_data = $message->getUserSpecificContent(); + if (!$specific_data) { + $specific_data = Array(); + } + $updates = $object["_once_user_specific_update"]; + if ($updates["user_id"]) { + $updates = Array($updates); + } + foreach ($updates as $update) { + $user_id = $update["user_id"]; + $modifiers = $update["modifiers"]; + $replace_all_keys = $update["replace_all"]; + if ($replace_all_keys) { + $specific_data[$user_id] = $modifiers; + } else { + foreach ($modifiers as $key => $data) { + $specific_data[$user_id][$key] = $data; + } + } + } + $message->setUserSpecificContent($specific_data); + } + + $message->setHiddenData($object["hidden_data"]); + $message->setContent($object["content"]); + $message->setPinned($object["pinned"]); + + + //Update reactions + if (isset($object["_user_reaction"]) && $user && $message->getId()) { + $message_reaction_repo = $this->em->getRepository("Twake\Discussion:MessageReaction"); + $message_reaction = $message_reaction_repo->findOneBy(Array("user_id" => $user->getId(), "message_id" => $message->getId())); + $current_reactions = []; + + foreach($message->getAsArray()["reactions"] as $key => $reaction){ + $current_reactions[$reaction["name"] ?: $key] = $reaction; + } + + $user_reaction = $object["_user_reaction"]; + $reaction = Array(); + + if ($message_reaction) { + if ($user_reaction == $message_reaction->getReaction()) { + //Noop + } else if (!$user_reaction) { + $this->em->remove($message_reaction); + $reaction["remove"] = Array($message_reaction->getReaction() => Array("user" => $user->getId())); + } else { + $reaction["remove"] = Array($message_reaction->getReaction() => Array("user" => $user->getId())); + $reaction["add"] = Array($user_reaction => $user->getId()); + + $message_reaction->setReaction($user_reaction); + $this->em->persist($message_reaction); + } + + } else if ($user_reaction) { + $message_reaction = new MessageReaction($message->getId(), $user->getId()); + $reaction["add"] = Array($user_reaction => Array("user" => $user->getId())); + $message_reaction->setReaction($user_reaction); + $this->em->persist($message_reaction); + } + + if (isset($reaction["add"])) { + $key_first = array_keys($reaction["add"])[0]; + if (array_key_exists($key_first, $current_reactions)) { + $current_reactions[$key_first]["users"][] = $user->getId(); + } else { + $current_reactions[$key_first]["users"] = Array($user->getId()); + } + $current_reactions[$key_first]["count"]++; + } + if (isset($reaction["remove"])) { + $key_first = array_keys($reaction["remove"])[0]; + if (array_key_exists($key_first, $current_reactions)) { + $keytoremove = array_search($user->getId(), $current_reactions[$key_first]["users"]); + unset($current_reactions[$key_first]["users"][$keytoremove]); + $current_reactions[$key_first]["count"]--; + if ($current_reactions[$key_first]["count"] == 0) { + unset($current_reactions[$key_first]); + } + } + } + + $message->setReactions($current_reactions); + } + + if (isset($object["tags"])) { + $message->setTags($object["tags"]); + } + + //Generate an ID + $this->em->persist($message); + + if ($ephemeral) { + $this->em->remove($message); + } else { + + $channel = $this->em->getRepository("Twake\Core:CachedFromNode")->findOneBy(Array("company_id" => "unused", "type" => "channel", "key"=>$channel_id)); + if($channel){ + + $this->sendToNode($channel, $message, $did_create); + + try { + $this->indexMessage($message, $channel->getData()["workspace_id"], $channel_id); + } catch (\Exception $e) { + error_log("ERROR WITH MESSAGE SAVE INSIDE A BLOC"); + } + + $this->em->flush(); + + } + + if($channel){ + //Notify connectors + if ($channel->getData()["workspace_id"]) { + if (false && $channel->getAppId()) { + $apps_ids = [$channel->getAppId()]; + } else { + $resources = $this->applications_api->getResources($channel->getData()["workspace_id"], "channel", $channel_id); + $resources = array_merge($resources, $this->applications_api->getResources($channel->getData()["workspace_id"], "workspace", $channel->getData()["workspace_id"])); + $apps_ids = []; + foreach ($resources as $resource) { + if ($resource->getResourceId() == $channel->getData()["workspace_id"] && !in_array("message_in_workspace", $resource->getApplicationHooks())) { + continue; //Si resource sur tout le workspace et qu'on a pas le hook new_message_in_workspace on a pas le droit + } + if (in_array("message", $resource->getApplicationHooks()) || in_array("message_in_workspace", $resource->getApplicationHooks())) { + $apps_ids[] = $resource->getApplicationId(); + } + } + } + if (count($apps_ids) > 0) { + foreach ($apps_ids as $app_id) { + if ($app_id) { + $data = Array( + "message" => $message->getAsArray(), + "channel" => $channel->getData() + ); + if ($did_create) { + $this->applications_api->notifyApp($app_id, "hook", "new_message", $data); + } else if (false && $channel->getAppId()) { //Only private channels with app can receive edit hook + $this->applications_api->notifyApp($app_id, "hook", "edit_message", $data); + } + } + } + } + } + } + + + + } + + $array = $message->getAsArray(); + + if ($ephemeral) { + $array["ephemeral_id"] = $message->getId(); + $array["_user_ephemeral"] = true; + if (isset($object["ephemeral_message_recipients"])) { + $array["ephemeral_message_recipients"] = $object["ephemeral_message_recipients"]; + } + } + + $event = Array( + "client_id" => "system", + "action" => "update", + "message_id" => $array["id"], + "thread_id" => $array["parent_message_id"] + ); + $this->app->getServices()->get("app.pusher")->push($event, "channels/" . $array["channel_id"] . "/messages/updates"); + + $event = Array( + "client_id" => "bot", + "action" => "save", + "object_type" => "", + "object" => $array + ); + $this->app->getServices()->get("app.websockets")->push("messages/" . $array["channel_id"], $event); + + return $array; + } + + public function sendToNode($channel, $message, $did_create){ + $messageArray = $message->getAsArray(); + + $senderName = ""; + if($messageArray["sender"]){ + $sender_user = $this->em->getRepository("Twake\Users:User")->findOneBy(Array("id" => $messageArray["sender"])); + $senderName = $sender_user ? $sender_user->getFullName() : ""; + } + + $title = ""; + $text = $this->buildShortText($message); + $body = $text; // we need original body just in case text gets updated further on + if ($channel->getData()["is_direct"]) { + $title = $senderName . " in " . $channel->getData()["company_name"]; + }else{ + $title = $channel->getData()["name"]; + $title .= " in " . $channel->getData()["company_name"] . " β€’ " . $channel->getData()["workspace_name"]; + $text = $senderName . ": " . $text; + } + + if($channel){ + + $md2text_options = Array("keep_mentions" => true); + $text_content = $this->mdToText($message->getContent(), $md2text_options); + preg_match_all("/@[^: ]+:([0-f-]{36})/m", $text_content, $users_output); + preg_match_all("/(^| )@(all|here|channel|everyone)[^a-z]/m", $text_content, $global_output); + $mentions = [ + "users" => $users_output[1], + "specials" => $global_output[2] + ]; + $rabbitData = [ + "company_id" => $channel->getData()["company_id"], + "workspace_id" => $channel->getData()["workspace_id"] ?: "direct", + "channel_id" => $messageArray["channel_id"], + "thread_id" => $messageArray["parent_message_id"], + "id" => $messageArray["id"], + "sender" => $messageArray["sender"], + "creation_date" => $messageArray["creation_date"] * 1000, + "mentions" => $mentions, + + "sender_name" => $senderName, + "channel_name" => $channel->getData()["name"], + "company_name" => $channel->getData()["workspace_name"], + "workspace_name" => $channel->getData()["company_name"], + + "title" => $title, + "text" => $text + ]; + $rabbitChannelData = [ + "company_id" => $channel->getData()["company_id"], + "workspace_id" => $channel->getData()["workspace_id"] ?: "direct", + "channel_id" => $messageArray["channel_id"], + "date" => $messageArray["creation_date"] * 1000, + "sender" => $messageArray["sender"], + "sender_name" => $senderName, // username, because it's not convenient to make request to find out username by id + "title" => $title, + "text" => $text, + "body" => $body // original body of the message without sender + ]; + + if($messageArray["message_type"] != 2){ //Ignore system messages + if($did_create){ + $this->queues->push("channel:activity", $rabbitChannelData, ["exchange_type" => "fanout"]); + $this->queues->push("message:created", $rabbitData, ["exchange_type" => "fanout"]); + }else{ + $this->queues->push("message:updated", $rabbitData, ["exchange_type" => "fanout"]); + } + } + } + } + + private function buildShortText($message){ + $text = $this->mdToText($message->getContent()) ?: "No text content."; + $text = preg_replace("/ +/", " ", trim(html_entity_decode($this->emojione_client->shortnameToUnicode($text), ENT_NOQUOTES, 'UTF-8'))); + if(strlen($text) > 180){ + $text = substr($text, 0, 180) . "..."; + } + return $text; + } + + private function share($message) + { + + if (!$message) { + return; + } + + $event = Array( + "client_id" => "system", + "action" => "save", + "object_type" => "", + "object" => $message->getAsArray() + ); + $this->websockets_service->push("messages/" . $message->getChannelId(), $event); + + } + + private function moveMessageToNewParent(Message $messageA, $messageB, $flush = true) + { + + if (!$messageA->getParentMessageId() && !$messageB || $messageB && $messageA->getParentMessageId() == $messageB->getId()) { + return; + } + + $this->em->remove($messageA); + $this->em->flush(); + + $new_parent_message_id = $messageB ? $messageB->getId() : ""; + + $messageA->setParentMessageId($new_parent_message_id); + + if ($messageA->getResponsesCount() > 0) { + $message_repo = $this->em->getRepository("Twake\Discussion:Message"); + + //Move all children to the same parent message id + $others = $message_repo->findBy(Array("channel_id" => $messageA->getChannelId(), "parent_message_id" => $messageA->getId())); + + foreach ($others as $message) { + $this->moveMessageToNewParent($message, $messageB, false); + } + + } + + if ($messageB) { + $messageB->setResponsesCount($messageB->getResponsesCount() + 1); + } + + $messageA->setResponsesCount(0); + $this->em->persist($messageA); + + $this->share($messageA); + + if ($flush) { + $this->share($messageB); + $this->em->flush(); + } + + return $messageA; + + } + + public function indexMessage($message, $workspace_id, $channel_id) + { + if (!$workspace_id) { + $workspace_id = "00000000-0000-1000-0000-000000000000"; + } + + $blocbdd = null; + if ($message->getBlockId()) { + $blocbdd = $this->em->getRepository("Twake\GlobalSearch:Bloc")->findOneBy(Array("id" => $message->getBlockId())); + } + + if (!$blocbdd) { + + $lastbloc = $this->em->getRepository("Twake\GlobalSearch:Bloc")->findOneBy(Array("workspace_id" => $workspace_id, "channel_id" => $channel_id)); + + if (isset($lastbloc) == false || $lastbloc->getLock() == true) { + + $messages = Array(); + $id_messages = Array(); + $blocbdd = new Bloc($workspace_id, $channel_id, $messages, $id_messages); + + } else { + + $blocbdd = $lastbloc; + + } + + } + + if (!$blocbdd) { + return false; + } + + try { + + $options = Array("keep_mentions" => true); + $content_id = $this->mdToText($message->getContent(), $options); + $content = $this->mdToText($message->getContent()); + + $blocbdd->addOrUpdateMessage($message, $content, $content_id); + + if ($blocbdd->getNbMessage() >= 10) { + $blocbdd->setLock(true); + } + + $this->em->persist($blocbdd); + $message->setBlockId($blocbdd->getId() . ""); + + $this->em->persist($message); + $this->em->flush(); + + if ($blocbdd->getLock()) { + $this->em->es_put($blocbdd, $blocbdd->getEsType()); + } + + } catch (\Exception $e) { + error_log($e->getMessage()); + } + + } + + private function mdToText($array, $options = null) + { + + if (!$array) { + return ""; + } + + if (is_string($array)) { + $array = [$array]; + } + + if (isset($array["fallback_string"])) { + $result = $array["fallback_string"]; + } else if (isset($array["original_str"])) { + $result = $array["original_str"]; + } else { + + if (isset($array["type"]) || isset($array["start"])) { + $array = [$array]; + } + + $result = ""; + + try { + foreach ($array as $item) { + if (is_string($item)) { + $result .= $item; + } else if (isset($item["type"])) { + if (in_array($item["type"], Array("underline", "strikethrough", "bold", "italic", "mquote", "quote", "email", "url", "", "nop", "br", "system"))) { + if ($item["type"] == "br") { + $result .= " "; + } + $result .= $this->mdToText($item["content"]); + } + } else { + $result .= $this->mdToText($item["content"]); + } + } + + } catch (\Exception $e) { + return "Open Twake to see this message."; + } + + } + if (!(isset($options["keep_mentions"]) && $options["keep_mentions"] == true)) { + $result = preg_replace("/@(.*?):.*?(( |$))/", "@$1$2", $result); + $result = preg_replace("/#(.*?):.*?(( |$))/", "#$1$2", $result); + } + + return $result; + + } + + +} diff --git a/twake/backend/core/src/Twake/Drive/Bundle.php b/twake/backend/core/src/Twake/Drive/Bundle.php new file mode 100755 index 00000000..60e06b85 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Bundle.php @@ -0,0 +1,30 @@ +<?php + +namespace Twake\Drive; + +require_once __DIR__ . "/Resources/Routing.php"; +require_once __DIR__ . "/Resources/Services.php"; + +use Twake\Drive\Resources\Routing; +use Twake\Drive\Resources\Services; +use Common\BaseBundle; + +class Bundle extends BaseBundle +{ + + protected $bundle_root = __DIR__; + protected $bundle_namespace = __NAMESPACE__; + protected $routes = []; + protected $services = []; + + public function init() + { + $routing = new Routing(); + $this->routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Command/DrivePreviewCommand.php b/twake/backend/core/src/Twake/Drive/Command/DrivePreviewCommand.php new file mode 100755 index 00000000..ccb31a5b --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Command/DrivePreviewCommand.php @@ -0,0 +1,100 @@ +<?php + +namespace Twake\Drive\Command; + +use Common\Commands\ContainerAwareCommand; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Twake\Drive\Services\DriveFileSystemOld; + + +class DrivePreviewCommand extends ContainerAwareCommand +{ + var $leveladmin; + var $output; + var $force; + var $twake; + + protected function configure() + { + $this + ->setName("twake:preview_worker"); + } + + protected function execute() + { + $services = $this->getApp()->getServices(); + + $this->queues = $services->get("app.queues")->getAdapter(); + $this->em = $services->get("app.twake_doctrine"); + $this->pusher = $services->get("app.pusher"); + $this->preview = $services->get("app.drive.preview"); + $this->root = $this->getApp()->getContainer()->getParameter('kernel.root_dir'); + $this->drive_previews_tmp_folder = $this->getApp()->getContainer()->getParameter("drive_previews_tmp_folder"); + $this->storagemanager = $services->get("driveupload.storemanager"); + + $limit = date("U", date("U") + 60); + + while (date("U") < $limit) { + + $todos = $this->queues->oldConsume("drive_preview_to_generate", true); + if (count($todos ?: []) == 0) { + sleep(1); + } + foreach ($todos ?: [] as $todo_original) { + $todo = $this->queues->getMessage($todo_original); + $this->autoGenPreview($todo["file_id"]); + $this->queues->ack("drive_preview_to_generate", $todo_original); + } + + } + + } + + public function autoGenPreview($file_id) + { + /* @var DriveFile $file */ + $file = $this->em->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $file_id)); + if ($file->getSize() > 10 && $file->getSize() < 50000000) { + + $file->setPreviewHasBeenGenerated(true); + + if (in_array(strtolower($file->getExtension()), $this->preview->previewableExt)) { + + $tmppath = $this->checkLocalFileForPreview($file); + + if (!$tmppath || !file_exists($tmppath)) { + //TODO Unimplemented $tmppath = $this->oldFileSystem->decode($path, $file->getLastVersion($this->em)->getKey(), $file->getLastVersion($this->em)->getMode()); + } + + $res = $this->storagemanager->getAdapter()->genPreview($file, $tmppath); + if ($res) { + $file->setHasPreview(true); + } + + } + + $this->em->persist($file); + $this->em->flush(); + + $this->pusher->push(Array("action" => "update_file", "file" => $file->getAsArray()), "drive/file/" . $file->getWorkspaceId() . "/" . $file->getParentId()); + + } + + return true; + } + + public function checkLocalFileForPreview($file) + { + $tmppath = null; + $version = $this->em->getRepository("Twake\Drive:DriveFileVersion")->findOneBy(Array("id" => $file->getLastVersionId())); + if ($version && isset($version->getData()["identifier"]) && isset($version->getData()["upload_mode"]) && $version->getData()["upload_mode"] == "chunk") { + $uploadstate = $this->em->getRepository("Twake\Drive:UploadState")->findOneBy(Array("identifier" => $version->getData()["identifier"])); + if ($uploadstate && $uploadstate->getHasPreview()) { + $tmppath = $this->drive_previews_tmp_folder . "/preview_" . $uploadstate->getIdentifier() . ".chunk_1"; + } + } + return $tmppath; + } + +} diff --git a/twake/backend/core/src/Twake/Drive/Controller/Download.php b/twake/backend/core/src/Twake/Drive/Controller/Download.php new file mode 100755 index 00000000..53e73b3e --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Controller/Download.php @@ -0,0 +1,54 @@ +<?php + + +namespace Twake\Drive\Controller; + +use PHPUnit\Util\Json; +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class Download extends BaseController +{ + + public function downloadfile(Request $request) + { + $data = Array( + "errors" => Array() + ); + + if ($request->query->has("workspace_id")) { + $data = $request->query; + } else { + $data = $request->request; + } + + $workspace_id = $data->get("workspace_id", 0); + $files_ids = $data->get("element_id", 0); + $download = $data->get("download", 1); + $versionId = $data->get("version_id", 0); + $public_access_key = $data->get("public_access_key", false); + + if ($data->has("elements_id")) { + $files_ids = explode(",", $data->get("elements_id", "")); + } + + //TODO check access to this file or set of files + + $this->get("administration.counter")->incrementCounter("total_files_downloaded", 1); + + if($GLOBALS["segment_enabled"]) \Segment::track([ + "event" => "drive:download", + "userId" => $this->isConnected() ? ($this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId()) : "anonymous" + ]); + + @$response = $this->get('driveupload.download')->download($workspace_id, $files_ids, $download, $versionId); + if ($response === true) { + return; + } + + return new Response($data); + + } + +} diff --git a/twake/backend/core/src/Twake/Drive/Controller/DriveFile.php b/twake/backend/core/src/Twake/Drive/Controller/DriveFile.php new file mode 100755 index 00000000..cfcba190 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Controller/DriveFile.php @@ -0,0 +1,164 @@ +<?php + +namespace Twake\Drive\Controller; + +use PHPUnit\Util\Json; +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class DriveFile extends BaseController +{ + + public function remove(Request $request) + { + $options = $request->request->get("options"); + $object = $request->request->get("object"); + + $res = $this->get("app.drive")->remove($object, $options, $this->getUser()); + if (!$res) { + return new Response(Array("status" => "error")); + } + return new Response(Array("data" => Array("object" => $res))); + } + + public function save(Request $request) + { + $options = $request->request->get("options"); + $object = $request->request->get("object"); + + $file_uploaded = null; + if (isset($_FILES["file"])) { + $options = json_decode($options, true); + $object = json_decode($object, true); + $file_uploaded = $_FILES["file"]; + } else { + $file_uploaded = isset($object["file_url"]) ? $object["file_url"] : $request->request->get("file_url"); + } + + $current_user = $this->getUser(); + $current_user_id = $current_user->getId(); + + if ($file_uploaded) { + //If object[_once_new_version] is set a new version is added + $res = $this->get('driveupload.upload')->uploadDirectly($file_uploaded, $object, $options, $current_user_id); + } else { + $res = $this->get("app.drive")->save($object, $options, $current_user_id, Array()); + } + + if($GLOBALS["segment_enabled"]) \Segment::track([ + "event" => "drive:".($object["is_directory"] ? "directory" : "file") . ":" . ($object["id"] ? "edit" : "create"), + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() + ]); + + if (!empty($object["_once_set_access"]) && !empty($object["id"])) { + + $is_editable = $object["acces_info"]["is_editable"]; + $publicaccess = $object["acces_info"]["public_access"]; + $authorized_members = $object["acces_info"]["authorized_members"]; + $authorized_channels = $object["acces_info"]["authorized_channels"]; + + $res = $this->get('app.drive')->set_file_access($object["id"], $publicaccess, $is_editable, $authorized_members, $authorized_channels, $this->getUser()); + + } + + if (!$res) { + return new Response(Array("status" => "error")); + } else { + if (empty($object["id"])) { + $this->get("administration.counter")->incrementCounter("total_files", 1); + $this->get("administration.counter")->incrementCounter("total_files_size", intval($res["size"] / 1000)); + } + } + return new Response(Array("data" => Array("object" => $res))); + } + + public function getAction(Request $request) + { + $options = $request->request->get("options"); + + $objects = $this->get("app.drive")->get($options, $this->getUser()); + + if ($objects === false) { + return new Response(Array("status" => "error")); + } + return new Response(Array("data" => $objects)); + } + + public function find(Request $request) + { + $options = $request->request->get("options"); + + $object = $this->get("app.drive")->find($options, $this->getUser()); + + if ($object === false) { + return new Response(Array("status" => "error")); + } + return new Response(Array("data" => $object)); + } + + + public function set_file_access(Request $request) + { + + $file_id = $request->request->get("file_id"); + + $is_editable = $request->request->get("is_editable"); + $publicaccess = $request->request->get("public_access"); + $authorized_members = $request->request->get("authorized_members"); + $authorized_channels = $request->request->get("authorized_channels"); + + $publicaccess = $this->get('app.drive')->set_file_access($file_id, $publicaccess, $is_editable, $authorized_members, $authorized_channels, $this->getUser()); + $data = Array("data" => $publicaccess); + + return new Response($data); + } + + public function reset_file_access(Request $request) + { + $file_id = $request->request->get("file_id"); + + $publicaccess = $this->get('app.drive')->reset_file_access($file_id, $this->getUser()); + $data = Array("data" => $publicaccess); + + return new Response($data); + } + + public function emptyTrash(Request $request) + { + $data = Array( + "errors" => Array() + ); + + $groupId = $request->request->get("workspace_id", 0); + + $can = $this->get('app.workspace_levels')->can($groupId, $this->getUser(), "drive:write"); + + if ($can || true) { + $data["data"] = $this->get('app.drive')->emptyTrash($groupId, $this->getUser()); + } + + return new Response($data); + } + + public function open(Request $request) + { + $data = Array( + "data" => Array(), + "errors" => Array() + ); + $file_id = $request->request->get("id", null); + + $bool = $this->get("app.drive")->open($file_id); + + if ($bool) { + $data["data"][] = "success"; + } else { + $data["data"][] = "error"; + } + + return new Response($data); + } + + +} diff --git a/twake/backend/core/src/Twake/Drive/Controller/Upload.php b/twake/backend/core/src/Twake/Drive/Controller/Upload.php new file mode 100755 index 00000000..15c30289 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Controller/Upload.php @@ -0,0 +1,51 @@ +<?php + + +namespace Twake\Drive\Controller; + +use PHPUnit\Util\Json; +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class Upload extends BaseController +{ + + public function Preprocess(Request $request) + { + $identifier = $this->get('driveupload.upload')->preprocess($request, $this->getUser()->getId()); + + if($GLOBALS["segment_enabled"]) \Segment::track([ + "event" => "drive:file:create", + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() + ]); + + return new Response(Array("identifier" => $identifier)); + } + + public function uploadFile(Request $request) + { + $current_user_id = $this->getUser()->getId(); + $res = $this->get('driveupload.upload')->upload($request, $response, $current_user_id); + + $this->get("administration.counter")->incrementCounter("total_files", 1); + $this->get("administration.counter")->incrementCounter("total_files_size", intval($res["size"] / 1000)); + + return new Response(Array("data" => Array("object" => $res))); + } + + + public function Preview(Request $request) + { + $response = new Response(); + + if($GLOBALS["segment_enabled"]) \Segment::track([ + "event" => "drive:preview", + "userId" => $this->isConnected() ? ($this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId()) : "anonymous" + ]); + + $this->get('driveupload.previewmanager')->generatePreviewFromFolder($request); + return $response; + } + +} diff --git a/twake/backend/core/src/Twake/Drive/Entity/DriveFile.php b/twake/backend/core/src/Twake/Drive/Entity/DriveFile.php new file mode 100755 index 00000000..020a6643 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Entity/DriveFile.php @@ -0,0 +1,971 @@ +<?php + +namespace Twake\Drive\Entity; + +use Doctrine\ORM\Mapping as ORM; + +use Twake\Core\Entity\FrontObject; +use Twake\Core\Entity\SearchableObject; + +/** + * DriveFile + * + * @ORM\Table(name="drive_file",options={"engine":"MyISAM", "scylladb_keys": {{"workspace_id":"ASC", "parent_id":"ASC", "isintrash": "ASC", "id":"DESC"}, {"id": "DESC"}} }) + * @ORM\Entity() + */ +class DriveFile extends SearchableObject +{ + /** + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="workspace_id", type="text") + * @ORM\Id + */ + private $workspace_id; + + /** + * @ORM\Column(name="parent_id", type="text") + * @ORM\Id + */ + private $parent_id; + + /** + * @ORM\Column(type="twake_boolean") + * @ORM\Id + */ + private $isintrash = false; + + /** + * @ORM\Column(name="root_group_folder_id", type="twake_timeuuid", nullable=true) + */ + private $root_group_folder = NULL; + + /** + * @ORM\Column(type="string", length=512) + */ + private $public_access_key = ""; + + /** + * @ORM\Column(type="twake_text") + */ + private $name; + + /** + * @ORM\Column(type="string", length=16) + */ + private $extension; + + /** + * @ORM\Column(type="twake_text") + */ + private $description; + + /** + * @ORM\Column(type="twake_boolean") + */ + private $isdirectory; + + /** + * @ORM\Column(name="old_parent", type="text") + */ + private $old_parent; + + /** + * @ORM\OneToMany(targetEntity="Twake\Drive\Entity\DriveFile", mappedBy="parent") + */ + private $children; + + /** + * @ORM\Column(type="twake_datetime") + */ + private $added; + + /** + * @ORM\Column(type="twake_datetime") + */ + private $last_modified; + + /** + * @ORM\Column(name="last_version_id", type="text") + */ + private $last_version_id; + + /** + * @ORM\Column(name="last_modification_token", type="text") + */ + private $last_modification_token; + + /** + * @ORM\Column(name="creator", type="text") + */ + private $creator; + + + /** + * @ORM\Column(type="twake_bigint") + */ + private $size; + + /** + * @ORM\Column(type="twake_text") + */ + private $cache; + + /** + * @ORM\Column(type="twake_boolean") + */ + private $detached_file = false; + + /** + * @ORM\Column(type="twake_boolean") + */ + private $previewhasbeengenerated = false; + + /** + * @ORM\Column(type="twake_boolean") + */ + private $has_preview = false; + + /** + * @ORM\ManyToOne(targetEntity="Twake\Drive\Entity\DriveFile") + */ + private $copyof; + + + /** + * @ORM\Column(type="twake_boolean") + */ + private $shared = false; + + /** + * @ORM\Column(type="twake_text", nullable = true) + */ + private $url; + + /** + * @ORM\Column(type="decimal") + */ + private $opening_rate; + + /** + * @ORM\ManyToOne(targetEntity="Twake\Market\Entity\Application") + * @ORM\JoinColumn(nullable=true) + */ + private $default_web_app; + + /** + * @ORM\Column(type="twake_text", nullable = true) + */ + private $preview_link = ""; + + /** + * @ORM\Column(type="twake_text", nullable=true) + */ + private $object_link_cache; + + /** + * @ORM\Column(name ="content_keywords", type="twake_text", nullable=true) + */ + private $content_keywords; + + /** + * @ORM\Column(name ="access_info", type="twake_text", nullable=true) + */ + private $acces_info; + + /** + * @ORM\Column(name="application_id", type="twake_no_salt_text", nullable=true) + */ + private $application_id = null; + + /** + * @ORM\Column(type="twake_boolean") + */ + private $external_storage = false; + + /** + * @ORM\Column(name="hidden_data", type="twake_text") + */ + private $hidden_data = "{}"; + + /** + * @ORM\Column(name="last_user", type="twake_no_salt_text", nullable=true) + */ + private $last_user; + + /** + * @ORM\Column(name="tags", type="twake_text", nullable=true) + */ + private $tags; + + /** + * @ORM\Column(name="attachements", type="twake_text") + */ + private $attachements = "[]"; + + + protected $es_type = "drive_file"; + + public function __construct($workspace_id, $parent_id, $isdirectory = false) + { + parent::__construct(); + $this->workspace_id = $workspace_id; + $this->setParentId($parent_id); + $this->isdirectory = $isdirectory; + $this->setContentKeywords(Array()); + $this->setName(""); + $this->setDescription(""); + $this->setSize(0); + $this->setIsInTrash(false); + $this->added = new \DateTime(); + $this->cache = "{}"; + $this->setLastModified(); + $this->opening_rate = 0; + $this->default_web_app = null; + $this->setPreviewHasBeenGenerated(false); + } + + /** + * @return mixed + */ + public function getAccesInfo() + { + return json_decode($this->acces_info, true); + } + + /** + * @param mixed $acces_info + */ + public function setAccesInfo($acces_info) + { + $this->acces_info = json_encode($acces_info); + } + + /** + * @return string + */ + public function getEsType() + { + return $this->es_type; + } + + + public function getIndexationArray() + { + return Array( + "id" => $this->getId() . "", + "type" => $this->getExtension(), + "name" => $this->getName(), + "creation_date" => ($this->getAdded() ? $this->getAdded()->format('Y-m-d') : null), + "creator" => $this->getCreator(), + "size" => $this->getSize(), + "date_last_modified" => ($this->getLastModified() ? $this->getLastModified()->format('Y-m-d') : null), + "workspace_id" => $this->getWorkspaceId(), + "keywords" => $this->getContentKeywords(), + "tags" => $this->getTags() + ); + } + + /** + * @return mixed + */ + public function getTags() + { + return json_decode($this->tags); + } + + /** + * @param mixed $tags + */ + public function setTags($tags) + { + $this->tags = json_encode($tags); + } + + + /** + * @return mixed + */ + public function getCreator() + { + return $this->creator; + } + + /** + * @param mixed $creator + */ + public function setCreator($creator) + { + $this->creator = $creator; + } + + + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getLastUser() + { + return $this->last_user; + } + + /** + * @param mixed $last_user + */ + public function setLastUser($last_user) + { + $this->last_user = $last_user; + } + + /** + * @return mixed + */ + public function getContentKeywords() + { + return json_decode($this->content_keywords, true); + } + + /** + * @param mixed $content_keywords + */ + public function setContentKeywords($content_keywords) + { + $this->content_keywords = json_encode($content_keywords); + } + + /** + * @return mixed + */ + public function getWorkspaceId() + { + return $this->workspace_id; + } + + /** + * @return mixed + */ + public function setWorkspaceId($wid) + { + $this->workspace_id = $wid; + } + + /** + * @return mixed + */ + public function getParentId() + { + return $this->parent_id; + } + + /** + * @param mixed $parent + */ + public function setParentId($parent_id) + { + $this->parent_id = $parent_id . ""; + if ($parent_id) { + $this->root_group_folder = NULL; + } else { + $this->root_group_folder = $this->getWorkspaceId() . ""; + } + } + + /** + * @return mixed + */ + public function getName() + { + return $this->name; + } + + /** + * @param mixed $name + */ + public function setName($name) + { + $this->name = $name; + $array = explode(".", $name); + $ext = ""; + if (count($array) > 1) { + $ext = array_pop($array); + } + $this->setExtension($ext); + } + + /** + * @return mixed + */ + public function getPublicAccessKey() + { + return $this->public_access_key; + } + + /** + * @param mixed $public_access_key + */ + public function setPublicAccessKey($public_access_key) + { + $this->public_access_key = $public_access_key; + } + + /** + * @return mixed + */ + public function getIsDirectory() + { + return $this->isdirectory; + } + + /** + * @return mixed + */ + public function getIsInTrash() + { + return $this->isintrash; + } + + /** + * @param mixed $isintrash + */ + public function setIsInTrash($isintrash) + { + $this->isintrash = $isintrash; + } + + /** + * @return mixed + */ + public function getOldParent() + { + return $this->old_parent; + } + + /** + * @param mixed $old_parent + */ + public function setOldParent($old_parent) + { + $this->old_parent = $old_parent; + } + + /** + * @return mixed + */ + public function getChildren() + { + return $this->children; + } + + /** + * Generate path from group id and realName + */ + public function getPath() + { + if ($this->getLastVersionId() == null) { + return null; + } + + if ($this->getDetachedFile()) { + return "" . $this->workspace_id . "/" . $this->getLastVersionId(); + } + return $this->workspace_id . "/" . $this->getLastVersionId(); + } + + /** + * Generate preview path from group id and realName + */ + public function getPreviewPath() + { + if ($this->getLastVersionId() == null) { + return null; + } + if ($this->getDetachedFile()) { + return "" . $this->workspace_id . "/preview/" . $this->getLastVersionId() . ".png"; + } + return $this->workspace_id . "/preview/" . $this->getLastVersionId() . ".png"; + } + + /** + * @return mixed + */ + public function getDescription() + { + return $this->description; + } + + /** + * @param mixed $description + */ + public function setDescription($description) + { + $this->description = $description; + } + + /** + * @return mixed + */ + public function getAdded() + { + return $this->added; + } + + /** + * @param mixed $added + */ + public function setAdded($added) + { + $this->added = $added; + } + + /** + * @return mixed + */ + public function getLastModified() + { + return $this->last_modified; + } + + /** + * @param mixed $last_modified + */ + public function setLastModified() + { + $this->last_modified = new \DateTime(); + } + + /** + * @return mixed + */ + public function getLastModificationToken() + { + return $this->last_modification_token; + } + + /** + * @param mixed $last_modification_token + */ + public function setLastModificationToken($last_modification_token) + { + $this->last_modification_token = $last_modification_token; + } + + /** + * @return mixed + */ + public function getLastVersionId() + { + return $this->last_version_id; + } + + /** + * @param mixed $last_version + */ + public function setLastVersionId($last_version_id) + { + $this->last_version_id = $last_version_id . ""; + } + + //TODO Very very bad to pass doctrine as parameter here... + public function getLastVersion($doctrine) + { + $repo = $doctrine->getRepository("Twake\Drive:DriveFileVersion"); + return $repo->find($this->getLastVersionId()); + } + + /** + * @return mixed + */ + public function getSize() + { + return $this->size; + } + + /** + * @param mixed $size + */ + public function setSize($size) + { + $this->size = $size; + if ($this->size < 10) { + $this->size = 0; + } + } + + /** + * @return mixed + */ + public function getExtension() + { + return strtolower($this->extension); + } + + /** + * @param mixed $extension + */ + public function setExtension($extension) + { + if (!$this->getIsDirectory()) { + $this->extension = $extension; + } else { + $this->extension = ""; + } + } + + /** + * @return mixed + */ + public function getCache() + { + $cache = json_decode($this->cache, 1); + return ($cache) ? $cache : Array(); + } + + /** + * @param mixed $cache + */ + public function setCache($key, $cache) + { + $val = $this->getCache(); + $val[$key] = $cache; + $this->cache = json_encode($val); + } + + /** + * @return mixed + */ + public function getDetachedFile() + { + return $this->detached_file; + } + + /** + * @param mixed $detached_file + */ + public function setDetachedFile($detached_file) + { + $this->detached_file = $detached_file; + } + + /** + * @return mixed + */ + public function getCopyOf() + { + return $this->copyof; + } + + /** + * @param mixed $copyof + */ + public function setCopyOf($copyof) + { + $this->copyof = $copyof; + } + + /** + * @return mixed + */ + public function getShared() + { + return $this->shared; + } + + /** + * @param mixed $shared + */ + public function setShared($shared) + { + $this->shared = $shared; + } + + /** + * @return mixed + */ + public function getUrl() + { + return $this->url; + } + + /** + * @param $url + */ + public function setUrl($url) + { + $this->url = $url; + } + + /** + * @return mixed + */ + public function getOpeningRate() + { + return $this->opening_rate; + } + + /** + * @param $opening_rate + */ + public function setOpeningRate($opening_rate) + { + $this->opening_rate = $opening_rate; + } + + /** + * @return mixed + */ + public function getDefaultWebApp() + { + return $this->default_web_app; + } + + /** + * @param $default_web_app + */ + public function setDefaultWebApp($default_web_app) + { + $this->default_web_app = $default_web_app; + } + + public function getAsArray() + { + return Array( + 'id' => $this->getId(), + 'front_id' => $this->getFrontId(), + "workspace_id" => $this->getWorkspaceId(), + 'parent_id' => $this->getParentId(), + "detached" => $this->getDetachedFile(), + "trash" => $this->getIsInTrash() ? true : false, + + 'is_directory' => $this->getIsDirectory(), + "creator" => $this->getCreator(), + 'name' => $this->getName(), + 'description' => $this->getDescription(), + "last_user" => $this->getLastUser(), + 'size' => $this->getSize() ? $this->getSize() : 0, + 'added' => $this->getAdded() ? $this->getAdded()->getTimestamp() : null, + 'modified' => (($this->getLastModified()) ? $this->getLastModified()->getTimestamp() : 0), + "last_modification_token" => $this->getLastModificationToken(), + "extension" => $this->getExtension(), + "cache" => $this->getCache(), + "preview_link" => $this->getPreviewLink(), + "copy_of" => ($this->getCopyOf() ? $this->getCopyOf()->getId() : null), + "shared" => $this->getShared(), + "url" => $this->getUrl(), + "opening_rate" => $this->getOpeningRate(), + "has_preview" => $this->getHasPreview(), + "preview_has_been_generated" => $this->getPreviewHasBeenGenerated(), + "default_web_app_id" => $this->getDefaultWebApp() ? $this->getDefaultWebApp()->getId() : null, + //"keywords" => $this->getContentKeywords() + "acces_info" => $this->getAccesInfo(), + "application_id" => $this->getApplicationId(), + "external_storage" => $this->getExternalStorage(), + "hidden_data" => $this->getHiddenData(), + "tags" => $this->getTags(), + "attachments" => $this->getAttachements(), + + ); + } + + /** + * @return mixed + */ + public function getExternalStorage() + { + return $this->external_storage; + } + + /** + * @param mixed $external_storage + */ + public function setExternalStorage($external_storage) + { + $this->external_storage = $external_storage; + } + + /** + * @return mixed + */ + public function getPreviewHasBeenGenerated() + { + return $this->previewhasbeengenerated; + } + + /** + * @param mixed $previewhasbeengenerated + */ + public function setPreviewHasBeenGenerated($previewhasbeengenerated) + { + $this->previewhasbeengenerated = $previewhasbeengenerated; + } + + + public function getRepository() + { + return "Twake\Drive:DriveFile"; + } + + public function getAsArrayFormated() + { + return Array( + "id" => $this->getId(), + "title" => "File", + "object_name" => $this->getName(), + "object_data" => Array( + "preview_link" => $this->getPreviewLink(), + "extension" => $this->getExtension(), + "groupId" => ($this->getGroup()) ? $this->getGroup()->getId() : "", + 'parent' => (($this->getParent()) ? $this->getParent()->getId() : 0), + "default_web_app_id" => $this->getDefaultWebApp() ? $this->getDefaultWebApp()->getId() : null + ), + "key" => "drive", + "type" => "file", + "code" => "twake/" . ($this->getParent() ? $this->getParent()->getId() : 0) . "/" . $this->getId(), + "attachments" => $this->getAttachements(), + ); + } + + public function synchroniseField($fieldname, $value) + { + if (!property_exists($this, $fieldname)) + return false; + + $setter = "set" . ucfirst($fieldname); + $this->$setter($value); + return true; + } + + public function get($fieldname) + { + if (!property_exists($this, $fieldname)) + return false; + + $getter = "get" . ucfirst($fieldname); + + return $this->$getter(); + } + + public function getPushRoute() + { + return "drive/" . $this->getId(); + } + + /** + * @param mixed $group + */ + public function setGroup($group) + { + $this->group = $group; + } + + public function hasPreviewLink() + { + return !!$this->preview_link; + } + + /** + * @return mixed + */ + public function getPreviewLink() + { + if (!$this->preview_link) { + return "/ajax/drive/preview?f=" . $this->getLastVersionId() . "&w=" . $this->getWorkspaceId() . "&d=" . $this->getParentId() . "&t=" . $this->getIsInTrash(); + } + return $this->preview_link; + } + + /** + * @param mixed $preview_link + */ + public function setPreviewLink($preview_link) + { + $this->preview_link = $preview_link; + } + + + public function finishSynchroniseField($data) + { + // TODO: Implement finishSynchroniseField($data) method. + } + + /** + * @return mixed + */ + public function getHasPreview() + { + return $this->has_preview; + } + + /** + * @param mixed $haspreview + */ + public function setHasPreview($has_preview) + { + $this->has_preview = $has_preview; + } + + /** + * @return mixed + */ + public function getApplicationId() + { + return $this->application_id; + } + + /** + * @param mixed $application_id + */ + public function setApplicationId($application_id) + { + $this->application_id = $application_id; + } + + /** + * @return mixed + */ + public function getHiddenData() + { + if (!$this->hidden_data) { + return Array(); + } + return json_decode($this->hidden_data, 1); + } + + /** + * @param mixed $hidden_data + */ + public function setHiddenData($hidden_data) + { + $this->hidden_data = json_encode($hidden_data); + } + + + /** + * @return mixed + */ + public function getAttachements() + { + return json_decode($this->attachements, true); + } + + /** + * @param mixed $tags + */ + public function setAttachements($attachements) + { + $this->attachements = json_encode($attachements); + } + +} diff --git a/twake/backend/core/src/Twake/Drive/Entity/DriveFileVersion.php b/twake/backend/core/src/Twake/Drive/Entity/DriveFileVersion.php new file mode 100755 index 00000000..d22d9d8c --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Entity/DriveFileVersion.php @@ -0,0 +1,272 @@ +<?php + +namespace Twake\Drive\Entity; + +use Doctrine\ORM\Mapping as ORM; + + +use Twake\Users\Entity\User; + +/** + * DriveFileVersion + * + * @ORM\Table(name="drive_file_version",options={"engine":"MyISAM" , "scylladb_keys": { {"id": "DESC"}, {"file_id": "DESC"} } }) + * @ORM\Entity() + */ +class DriveFileVersion +{ + /** + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="file_id", type="twake_timeuuid") + */ + private $file_id; + + /** + * @ORM\Column(name="creator_id", type="twake_no_salt_text") + */ + private $creator_id; + + /** + * @ORM\Column(type="twake_no_salt_text") + */ + private $realname; + + /** + * @ORM\Column(name="aes_key", type="twake_text") + */ + private $key; + + /** + * @ORM\Column(type="twake_no_salt_text") + */ + private $mode = "OpenSSL-2"; + + /** + * @ORM\Column(type="integer") + */ + private $size; + + /** + * @ORM\Column(type="twake_bigint") + */ + private $file_size; + + /** + * @ORM\Column(type="twake_datetime") + */ + private $date_added; + + /** + * @ORM\Column(type="twake_text") + */ + private $filename; + + /** + * @ORM\Column(type="twake_text") + */ + private $data; + + /** + * @ORM\Column(name="provider", type="string") + */ + private $provider; + + public function __construct(DriveFile $file, $user_id) + { + $this->file_id = $file->getId(); + $this->setKey(base64_encode(random_bytes(256))); + $this->setSize(0); + $this->resetRealName(); + $this->date_added = new \DateTime(); + $this->setFileName($file->getName()); + $this->setUserId($user_id); + } + + /** + * @return mixed + */ + public function getData() + { + return json_decode($this->data, true); + } + + /** + * @param mixed $data + */ + public function setData($data) + { + $this->data = json_encode($data); + } + + /** + * @return mixed + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + public function setProvider($provider) + { + $this->provider = $provider; + } + + public function getProvider() + { + return $this->provider; + } + + /** + * @return mixed + */ + public function getKey() + { + return $this->key; + } + + /** + * @param mixed $key + */ + public function setKey($key) + { + $this->key = $key; + } + + /** + * @return mixed + */ + public function getRealName() + { + return $this->realname; + } + + /** + * @param mixed $realname + */ + public function resetRealName() + { + $this->realname = sha1(microtime() . rand(0, 10000)) . ".tw"; + } + + /** + * @return mixed + */ + public function getSize() + { + return $this->file_size ?: $this->size; //Size is the old 32bit integer... + } + + /** + * @param mixed $size + */ + public function setSize($size) + { + $this->file_size = $size; + } + + /** + * @return mixed + */ + public function getMode() + { + if (!$this->mode) { + return "AES"; + } + return $this->mode; + } + + public function setMode($mode) + { + $this->mode = $mode; + } + + public function getAsArray() + { + return Array( + "id" => $this->id, + "name" => $this->getFileName(), + "file_id" => $this->getFileId(), + "added" => $this->date_added->getTimestamp(), + "size" => $this->getSize(), + //"user" => $this->user!=null ? $this->user->getId() != 0 ? $this->user->getAsArray() : "" : "", + "creator" => $this->getUserId(), + "data" => $this->getData() + ); + } + + /** + * @return mixed + */ + public function getFileName() + { + return $this->filename; + } + + /** + * @param mixed $filename + */ + public function setFileName($filename) + { + $this->filename = $filename; + } + + /** + * @return mixed + */ + public function getUserId() + { + return $this->creator_id; + } + + /** + * @param mixed $user + */ + public function setUserId($user) + { + $this->creator_id = $user; + } + + /** + * @return mixed + */ + public function getDateAdded() + { + return $this->date_added; + } + + /** + * @param mixed $date_added + */ + public function setDateAdded($date_added) + { + $this->date_added = $date_added; + } + + /** + * @return mixed + */ + public function getFileId() + { + return $this->file_id; + } + + /** + * @param mixed $file_id + */ + public function setFileId($file_id) + { + $this->file_id = $file_id; + } + + +} diff --git a/twake/backend/core/src/Twake/Drive/Entity/UploadState.php b/twake/backend/core/src/Twake/Drive/Entity/UploadState.php new file mode 100755 index 00000000..fd46a7c4 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Entity/UploadState.php @@ -0,0 +1,343 @@ +<?php + + +namespace Twake\Drive\Entity; + +use Doctrine\ORM\Mapping as ORM; + + +/** + * UploadState + * + * @ORM\Table(name="uploadstate",options={"engine":"MyISAM", "scylladb_keys": {{"id": "ASC"}, {"identifier": "ASC"}} }) + * @ORM\Entity() + */ +class UploadState +{ + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + protected $id; + + /** + * @ORM\Column(name ="identifier", type="twake_no_salt_text") + */ + protected $identifier; + + /** + * @ORM\Column(name ="user_id", type="twake_no_salt_text") + */ + protected $user_id; + + /** + * @ORM\Column(name ="workspace_id", type="twake_no_salt_text") + */ + protected $workspace_id; + + /** + * @ORM\Column(name ="filename", type="twake_text") + */ + protected $filename; + + /** + * @ORM\Column(name ="extension", type="twake_no_salt_text") + */ + protected $extension; + + /** + * @ORM\Column(name ="chunk", type="integer") + */ + protected $chunk; + + /** + * @ORM\Column(name ="success", type="twake_boolean") + */ + protected $success; + + /** + * @ORM\Column(name ="chunklist", type="twake_text", nullable=true) + */ + protected $chunklist; + + /** + * @ORM\Column(name ="has_preview", type="twake_boolean") + */ + protected $has_preview; + + /** + * @ORM\Column(name ="encryption_key", type="twake_text", nullable=true) + */ + protected $encryption_key; + + /** + * @ORM\Column(name ="encryption_mode", type="twake_text", nullable=true) + */ + protected $encryption_mode; + + /** + * @ORM\Column(name ="encryption_salt", type="twake_text", nullable=true) + */ + protected $encryption_salt; + + /** + * @ORM\Column(name ="storage_provider", type="string", nullable=true) + */ + protected $storage_provider; + + public function __construct($storage_provider, $workspace_id, $identifier, $filename, $extension, $chunklist) + { + $this->workspace_id = $workspace_id; + $this->identifier = $identifier; + $this->filename = $filename; + $this->extension = $extension; + $this->chunk = 1; + $this->chunklist = json_encode($chunklist); + $this->success = false; + $this->encryption_key = "testkey"; + $this->storage_provider = $storage_provider; + } + + /** + * @return mixed + */ + public function getStorageProvider() + { + return $this->storage_provider; + } + + /** + * @return mixed + */ + public function getChunklist() + { + return json_decode($this->chunklist); + } + + /** + * @param mixed $chunklist + */ + public function setChunklist($chunklist) + { + $this->chunklist = json_encode($chunklist); + } + + public function addChunk($chunk) + { + + $chunklist = $this->getChunklist(); + array_push($chunklist, $chunk); + $this->setChunklist($chunklist); + + $this->setChunk(count($this->getChunklist())); + } + + public function getAsArray() + { + $return = Array( + "id" => $this->getId(), + "filename" => $this->getFilename(), + "identifier" => $this->getIdentifier(), + "extension" => $this->getExtension(), + "chunk" => $this->getChunk(), + "chunklist" => $this->getChunklist(), + "succes" => $this->getSuccess() + ); + return $return; + } + + /** + * @return mixed + */ + public function getChunk() + { + return $this->chunk; + } + + /** + * @param mixed $chunk + */ + public function setChunk($chunk) + { + $this->chunk = $chunk; + } + + /** + * @return mixed + */ + public function getEncryptionKey() + { + return $this->encryption_key; + } + + /** + * @param mixed $encryption_key + */ + public function setEncryptionKey($encryption_key) + { + $this->encryption_key = $encryption_key; + } + + /** + * @return mixed + */ + public function getEncryptionMode() + { + return $this->encryption_mode; + } + + /** + * @param mixed $encryption_mode + */ + public function setEncryptionMode($encryption_mode): void + { + $this->encryption_mode = $encryption_mode; + } + + /** + * @return mixed + */ + public function getEncryptionSalt() + { + return $this->encryption_salt; + } + + /** + * @param mixed $encryption_salt + */ + public function setEncryptionSalt($encryption_salt): void + { + $this->encryption_salt = $encryption_salt; + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @param int $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getIdentifier() + { + return $this->identifier; + } + + /** + * @param mixed $identifier + */ + public function setIdentifier($identifier) + { + $this->identifier = $identifier; + } + + /** + * @return mixed + */ + public function getFilename() + { + return $this->filename; + } + + /** + * @param mixed $filename + */ + public function setFilename($filename) + { + $this->filename = $filename; + } + + /** + * @return mixed + */ + public function getExtension() + { + return $this->extension; + } + + /** + * @param mixed $extension + */ + public function setExtension($extension) + { + $this->extension = $extension; + } + + /** + * @return mixed + */ + public function getSuccess() + { + return $this->success; + } + + /** + * @param mixed $success + */ + public function setSuccess($success) + { + $this->success = $success; + } + + /** + * @return mixed + */ + public function getWorkspaceId() + { + return $this->workspace_id; + } + + /** + * @param mixed $workspace_id + */ + public function setWorkspaceId($workspace_id) + { + $this->workspace_id = $workspace_id; + } + + /** + * @return mixed + */ + public function getHasPreview() + { + return $this->has_preview; + } + + /** + * @param mixed $has_preview + */ + public function setHasPreview($has_preview) + { + $this->has_preview = $has_preview; + } + + /** + * @return mixed + */ + public function getUserId() + { + return $this->user_id; + } + + /** + * @param mixed $user_id + */ + public function setUserId($user_id) + { + $this->user_id = $user_id; + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Resources/Routing.php b/twake/backend/core/src/Twake/Drive/Resources/Routing.php new file mode 100755 index 00000000..3bd5897b --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Resources/Routing.php @@ -0,0 +1,35 @@ +<?php + +namespace Twake\Drive\Resources; + +use Common\BaseRouting; + +class Routing extends BaseRouting +{ + + protected $routing_prefix = "ajax/"; + + protected $routes = [ +# Drive base + +#Old mobile versions + "drive/get" => ["handler" => "DriveFile:getAction", "methods" => ["POST"]], + "drive/save" => ["handler" => "DriveFile:save", "methods" => ["POST"]], + "drive/find" => ["handler" => "DriveFile:find", "methods" => ["POST"]], + "drive/remove" => ["handler" => "DriveFile:remove", "methods" => ["POST"]], +#Drive v1.2 + "drive/v2/get" => ["handler" => "DriveFile:getAction", "methods" => ["POST"]], + "drive/v2/save" => ["handler" => "DriveFile:save", "methods" => ["POST"]], + "drive/v2/remove" => ["handler" => "DriveFile:remove", "methods" => ["POST"]], + "drive/v2/find" => ["handler" => "DriveFile:find", "methods" => ["POST"]], + "drive/access/set" => ["handler" => "DriveFile:set_file_access", "methods" => ["POST"]], + "drive/access/reset" => ["handler" => "DriveFile:reset_file_access", "methods" => ["POST"]], + "drive/trash/empty" => ["handler" => "DriveFile:emptyTrash", "methods" => ["POST"]], + "drive/open" => ["handler" => "DriveFile:open", "methods" => ["POST"]], + "driveupload/upload" => ["handler" => "Upload:uploadFile", "methods" => ["POST"]], + "drive/download" => ["handler" => "Download:downloadfile", "methods" => ["POST", "GET"]], + "driveupload/download" => ["handler" => "Download:downloadfile", "methods" => ["POST", "GET"]], + "driveupload/preprocess" => ["handler" => "Upload:Preprocess", "methods" => ["POST"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Resources/Services.php b/twake/backend/core/src/Twake/Drive/Resources/Services.php new file mode 100755 index 00000000..f6b4d853 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Resources/Services.php @@ -0,0 +1,32 @@ +<?php + +namespace Twake\Drive\Resources; + +use Common\BaseServices; + +class Services extends BaseServices +{ + protected $services = [ + "app.drive.preview" => "DrivePreview", +// arguments: ["@app.twake_doctrine"] + "app.drive" => "DriveFileSystem", +// arguments: ["@app.twake_doctrine", "@app.applications_api", "@app.websockets", "@app.accessmanager"] + "driveupload.storemanager" => "Storage/StorageManager", +// arguments: [%local%, %aws%, %openstack%, %kernel.root_dir%, "@app.drive.preview","@app.twake_doctrine"] + "driveupload.download" => "DownloadFile", +// arguments: ["@driveupload.resumable", "@app.twake_doctrine","@driveupload.storemanager", %DRIVE_SALT%, "@app.drive.old.adapter_selector"] + "driveupload.resumable" => "Resumable/Resumable", +// arguments: ["@app.twake_doctrine","@driveupload.storemanager", "@app.drive", %drive_previews_tmp_folder%, %drive_tmp_folder%, %DRIVE_SALT%] + "driveupload.upload" => "UploadFile", +// arguments: ["@driveupload.resumable"] + + ### OLD + "app.drive.old.adapter_selector" => "OldFileSystem/DriveAdapterSelector", +// arguments: [%aws%, %openstack%, "@app.drive.old.AWS_FileSystem", "@app.drive.old.OpenStack_FileSystem"] + "app.drive.old.OpenStack_FileSystem" => "OldFileSystem/Adapter_OpenStack_DriveFileSystem", +// arguments: [%openstack%, %kernel.root_dir%, %DRIVE_SALT%] + "app.drive.old.AWS_FileSystem" => "OldFileSystem/Adapter_AWS_DriveFileSystem", +// arguments: [%aws%, %kernel.root_dir%, %DRIVE_SALT%] + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Services/DownloadFile.php b/twake/backend/core/src/Twake/Drive/Services/DownloadFile.php new file mode 100755 index 00000000..cb1451f7 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/DownloadFile.php @@ -0,0 +1,311 @@ +<?php + +namespace Twake\Drive\Services; + +use http\Client\Response; +use Twake\Drive\Services\Storage\EncryptionBag; +use Twake\Drive\Services\ZipStream\Option\Archive; +use Twake\Drive\Services\ZipStream\TwakeFileStream; +use Twake\Drive\Services\ZipStream\ZipStream; +use App\App; + +class DownloadFile +{ + private $resumable; + private $doctrine; + private $download; + private $versionId; + private $oldFileSystem; + private $workspace_id; + private $storagemanager; + private $parameter_drive_salt; + + public function __construct(App $app) + { + $this->resumable = $app->getServices()->get("driveupload.resumable"); + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->storagemanager = $app->getServices()->get("driveupload.storemanager"); + $this->parameter_drive_salt = $app->getContainer()->getParameter("storage.drive_salt"); + $this->oldFileSystem = $app->getServices()->get("app.drive.old.adapter_selector"); + } + + public function download($workspace_id, $files_ids, $download, $versionId) + { + + //TODO verify access to this file + + if (!is_array($files_ids)) { + $files_ids = [$files_ids]; + } + + $zip_archive = null; + $zip = false; + + $this->download = $download; + $this->versionId = $versionId; + $this->workspace_id = $workspace_id; + $name = null; + + if (count($files_ids) > 1) { + $zip = true; + $name = "Document.zip"; + } elseif (count($files_ids) == 1) { + $file = $this->doctrine->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $files_ids[0])); + if($file){ + if ($file->getIsDirectory()) { + $name = $file->getName() . ".zip"; + $zip = true; + $files_ids = Array(); + $files_son = $this->doctrine->getRepository("Twake\Drive:DriveFile")->findBy(Array("workspace_id" => $file->getWorkspaceId(), "parent_id" => $file->getId())); + foreach ($files_son as $son) { + $files_ids[] = $son->getId() . ""; + } + } + } + } + + if (isset($zip) && $zip) { + //plusieurs fichiers ou un dossier, on fait un zip + # enable output of HTTP headers + $options = new Archive(); + $options->setSendHttpHeaders(true); + $options->setZeroHeader(true); + $options->setEnableZip64(false); + + # create a new zipstream object + $zip_archive = new ZipStream($name, $options); + //error_log(print_r($files_ids,true)); + $this->downloadList($files_ids, $zip_archive, "/"); + + } else { + //tΓ©lΓ©chargement classique + $this->downloadList($files_ids); + } + + + if (isset($zip) && $zip) { + //on ajoute un fichier url dans le zip + + # finish the zip stream + $zip_archive->finish(); + } + + die(); + return true; + + } + + public function downloadList($files, &$zip = null, $zip_prefix = null) + { + $download = $this->download; + $versionId = $this->versionId; + $workspace_id = $this->workspace_id; + $first_element = true; + + foreach ($files as $file) { + + if (!$file) { + return false; + } + + if (is_string($file)) { + $file = $this->doctrine->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $file)); + } + + if ($file->getWorkspaceId() != $workspace_id && !$file->getDetachedFile()) { + continue; + } + + if ($file) { + $download_name = $file->getName(); + $ext = $file->getExtension(); + + $version = null; + + if ($file->getUrl()) { + + $version = null; + + } else if (isset($versionId) && $versionId && strlen($versionId) > 10 && $versionId != $file->getLastVersionId()) { + + $version = $this->doctrine->getRepository("Twake\Drive:DriveFileVersion")->find($versionId); + + if (!$version || $version->getFileId() != $file->getId()) { + continue; + } + + $download_name = date("Y-m-d_h:i", $version->getDateAdded()->getTimestamp()) . "_" . $version->getFileName(); + } else { + + $version = $this->doctrine->getRepository("Twake\Drive:DriveFileVersion")->find($file->getLastVersionId()); + } + + if ($first_element) { + + $first_element = false; + + if (!isset($zip) || !isset($zip_prefix)) { + + $final_download_name = $download_name; + if ($version) { + $final_download_size = $version->getSize(); + } else { + $final_download_size = 0; + } + + header('Content-Description: File Transfer'); + if ($download) { + + if (in_array($ext, ["gif", "svg", "jpeg", "jpg", "tiff", "png"])) { + header('Content-Type: image; filename="' . $final_download_name . '"'); + }else + if ($ext == "pdf") { + header("Content-type: application/pdf"); + }else{ + header('Content-Type: application/octet-stream'); + header("Content-type: application/force-download"); + } + + header('Content-Disposition: attachment; filename="' . $final_download_name . '"'); + } else { + header('Content-Disposition: inline; filename="' . $final_download_name . '"'); + + if (in_array($ext, ["gif", "svg", "jpeg", "jpg", "tiff", "png"])) { + header('Content-Type: image; filename="' . $final_download_name . '"'); + } + if ($ext == "pdf") { + header("Content-type: application/pdf"); + } + + } + + header('Expires: 0'); + header('Cache-Control: must-revalidate'); + header('Pragma: public'); + header('Content-Length: ' . $final_download_size); + + if (isset($_SERVER['HTTP_ORIGIN'])) { + header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']); + } + header('Access-Control-Allow-Credentials: true'); + + } + } + + if (isset($zip_prefix)) { + if ($file->getIsDirectory()) { + if ($zip_prefix == "/") { + $next_zip_prefix = $zip_prefix . $file->getName(); + } else { + $next_zip_prefix = $zip_prefix . DIRECTORY_SEPARATOR . $file->getName(); + } + + $files_son = $this->doctrine->getRepository("Twake\Drive:DriveFile")->findBy(Array("workspace_id" => $file->getWorkspaceId(), "parent_id" => $file->getId())); + foreach ($files_son as $son) { + + $this->downloadList(Array($son->getId() . ""), $zip, $next_zip_prefix); + } + } else { + $this->addOneFile($file, $version, $zip, $zip_prefix); + } + } else { + $this->addOneFile($file, $version); + } + } + } + } + + public function addOneFile($file, $version, &$zip = null, $zip_prefix = null) + { + if (!$version && !$file->getUrl()) { + error_log("no version found"); + return false; + } + if (!$version && $file->getUrl()) { + $url = $file->getUrl(); + if (isset($url)) { + //on ajoute un fichier url dans le zip + $zip->addFile($zip_prefix . DIRECTORY_SEPARATOR . $file->getName() . ".url", "[InternetShortcut]" . "\n" . "URL=" . $url); + } + return true; + } + if (isset($version->getData()["identifier"]) && isset($version->getData()["upload_mode"]) && $version->getData()["upload_mode"] == "chunk") { + $this->downloadFile($version, $version->getData()["identifier"], $file->getName(), $zip, $zip_prefix); + return true; + } else { + if ($this->oldFileSystem) { + + $provider = $version->getProvider(); + //Prod retro-compatibility + if($this->storagemanager->getProviderConfiguration("")["label"] === ""){ + $provider = $provider ?: ""; + } + $oldFileSystem = $this->oldFileSystem->getFileSystem($provider); + + $completePath = $oldFileSystem->getRoot() . $file->getPath(); + + //START - Woodpecker files import ! + $test_old_version = explode("/previews/", $file->getPreviewLink()); + if (count($test_old_version) == 2) { + $test_old_version = explode("/", $test_old_version[1]); + if ($test_old_version[0] == "detached") { + $test_old_version[0] = $test_old_version[1]; + } + if (intval($test_old_version[0]) . "" == $test_old_version[0]) { + $completePath = $oldFileSystem->getRoot() . str_replace(Array("https://s3.eu-west-3.amazonaws.com/twake.eu-west-3/public/uploads/previews/", ".png"), "", $file->getPreviewLink()); + } + } + //END - Woodpecker files import ! + + $completePath = $oldFileSystem->decode($completePath, $version->getKey(), $version->getMode()); + $fp = fopen($completePath, "r"); + ob_clean(); + flush(); + while (!feof($fp)) { + $buff = fread($fp, 1024); + if(!$zip){ + print $buff; + } + } + + if($zip){ + $zip->addFileFromPath($zip_prefix . DIRECTORY_SEPARATOR . $file->getName(), $completePath); + } + + //Delete decoded file + @unlink($completePath); + return true; + } + } + return false; + } + + public function downloadFile($version, $identifier, $name, &$zip = null, $zip_prefix = null) + { + + $uploadstate = $this->doctrine->getRepository("Twake\Drive:UploadState")->findOneBy(Array("identifier" => $identifier)); + if ($uploadstate->getEncryptionMode() == "OpenSSL-2") { + $param_bag = new EncryptionBag($uploadstate->getEncryptionKey(), $uploadstate->getEncryptionSalt(), $uploadstate->getEncryptionMode()); + } else { + //Old resumable with drive salt + $param_bag = new EncryptionBag($uploadstate->getEncryptionKey(), $this->parameter_drive_salt, "OpenSSL-2"); + } + if (isset($uploadstate)) { + if (isset($zip_prefix) && isset($zip)) { + $stream_zip = new TwakeFileStream($this->storagemanager->getAdapter($version->getProvider()), $param_bag, $uploadstate); + $zip->addFileFromPsr7Stream($zip_prefix . DIRECTORY_SEPARATOR . $name, $stream_zip); + } else { + for ($i = 1; $i <= $uploadstate->getChunk(); $i++) { + $this->storagemanager->getAdapter($version->getProvider())->read("stream", $i, $param_bag, $uploadstate); + } + } + } else { + $file = $this->doctrine->getRepository("Twake\Drive:DriveFile")->findBy(Array("id" => $identifier)); + $url = $file->getUrl(); + if (isset($url)) { + //on ajoute un fichier url dans le zip + $zip->addFile($zip_prefix . DIRECTORY_SEPARATOR . "google.url", "[InternetShortcut]" . "\r\n" . "URL=" . $url); + } + } + } +} diff --git a/twake/backend/core/src/Twake/Drive/Services/DriveFileSystem.php b/twake/backend/core/src/Twake/Drive/Services/DriveFileSystem.php new file mode 100755 index 00000000..0c32e14c --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/DriveFileSystem.php @@ -0,0 +1,852 @@ +<?php + + +namespace Twake\Drive\Services; + +use App\App; +use Twake\Core\CommonObjects\AttachementManager; +use Twake\Drive\Entity\DriveFile; +use Twake\Drive\Entity\DriveFileVersion; + +class DriveFileSystem +{ + + public function __construct(App $app) + { + $this->em = $app->getServices()->get("app.twake_doctrine"); + $this->applications_api = $app->getServices()->get("app.applications_api"); + $this->drive_resumable = false; + $this->ws = $app->getServices()->get("app.websockets"); + $this->access_manager = $app->getServices()->get("app.accessmanager"); + $this->attachementManager = new AttachementManager($this->em, $this->ws); + $this->storagemanager = $app->getServices()->get("driveupload.storemanager"); + } + + function setDriveResumable($drive_resumable) + { + $this->drive_resumable = $drive_resumable; + } + + /** Called from Collections manager to verify user has access to websockets room, registered in Core/Services/Websockets.php */ + public function init($route, $data, $current_user = null) + { + $route = explode("/", $route); + + if (count($route) < 3) { + return false; + } + + $workspace_id = $route[1]; + $document_id = $route[2]; + + if (!$workspace_id || (!empty($data["get_options"]["workspace_id"]) && $workspace_id != $data["get_options"]["workspace_id"])) { + return false; + } + + if (!$document_id || $document_id == "undefined") { + $document_id = $this->getRootEntity($workspace_id)->getId(); + } + + return $this->hasAccess([ + "id" => $document_id, + "workspace_id" => $workspace_id, + "public_access_token" => $data["get_options"]["public_access_token"] + ], $current_user); + + } + + public function hasAccess($data, $current_user = null) + { + if ($current_user === null) { + return true; + } + if (!is_string($current_user)) { + $current_user = $current_user->getId(); + } + return $this->access_manager->has_access($current_user, Array( + "type" => "DriveFile", + "edition" => true, + "object_id" => empty($data["id"]) ? (isset($data["parent_id"]) ? $data["parent_id"] : null) : $data["id"], + "workspace_id" => isset($data["workspace_id"]) ? $data["workspace_id"] : null + ), ["token" => @$data["public_access_token"]]); + } + + public function get($options, $current_user) + { + $options["id"] = $options["directory_id"]; + if (!$this->hasAccess($options, $current_user)) { + return false; + } + + $directory_id = $options["directory_id"]; + $workspace_id = $options["workspace_id"]; + $trash = $options["trash"]; + + if (!$directory_id) { + $directory_id = "root"; + } + + $elements = $this->listDirectory($workspace_id, $directory_id, $trash); + $path = $this->getPath($workspace_id, $directory_id); + + + $list = Array(); + foreach ($elements as $element) { + $array = $element->getAsArray(); + $array["path"] = $path; + $array["versions"] = $this->getFileVersion($element, true); + + $list[] = $array; + } + return $list; + + } + + public function listDirectory($workspaceId, $directoryId, $trash = false) + { + + if (!$workspaceId) { + return false; + } + + $repo = $this->em->getRepository("Twake\Drive:DriveFile"); + $root = $this->getRootEntity($workspaceId); + + if (!$directoryId || $directoryId == "root") { + $directoryId = $root->getId(); + } + + if ($directoryId == $root->getId()) { + if ($trash) { + $list = $repo->findBy(Array("workspace_id" => $workspaceId, "parent_id" => $this->getTrashEntity($workspaceId)->getId() . "")); + } else { + $list = $repo->findBy(Array("workspace_id" => $workspaceId, "parent_id" => $root->getId())); + } + } else { + $list = $repo->findBy(Array("workspace_id" => $workspaceId, "parent_id" => $directoryId)); + } + + return $list; + } + + public function getRootEntity($workspace_id) + { + $root = $this->em->getRepository("Twake\Drive:DriveFile") + ->findOneBy(Array("workspace_id" => $workspace_id . "", "isintrash" => false, "parent_id" => "")); + if (!$root) { + $root = new DriveFile($workspace_id, "", true); + $this->em->persist($root); + $this->em->flush(); + } + return $root; + } + + public function getTrashEntity($workspace_id) + { + $trash = $this->em->getRepository("Twake\Drive:DriveFile") + ->findOneBy(Array("workspace_id" => $workspace_id . "", "parent_id" => "trash")); + + if (!$trash) { + $trash = new DriveFile($workspace_id, "trash", true); + $trash->setParentId("trash"); + $this->em->persist($trash); + $this->em->flush(); + } + + return $trash; + } + + public function getPath($workspace_id, $directory_id) + { + + $repo = $this->em->getRepository("Twake\Drive:DriveFile"); + + if ($directory_id == "root" || $directory_id == "trash") { + $child = $this->getRootEntity($workspace_id); + return [$child->getAsArray()]; + } else { + $child = $repo->findOneBy(Array("id" => $directory_id)); + } + + if (!$child) { + return []; + } + + $list = [$child->getAsArray()]; + + $iter = 0; + while ($child && $child->getParentId() && $child->getParentId() != "root" && $child->getParentId() != "trash" && $iter < 100) { + $iter++; + $parent = $repo->findOneBy(Array("id" => $child->getParentId())); + if ($parent) { + $list[] = $parent->getAsArray(); + $child = $parent; + } else { + $child = null; + } + } + + $list = array_reverse($list); + + return $list; + } + + public function getFileVersion($fileOrFileId, $asArray = false) + { + if (!is_object($fileOrFileId)) { + $file = $this->em->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $fileOrFileId)); + } else { + $file = $fileOrFileId; + } + if (!$file || $file->getIsDirectory()) { + return false; + } + $versionsEntity = $this->em->getRepository("Twake\Drive:DriveFileVersion")->findBy(Array("file_id" => $file->getId())); + if ($asArray) { + $versions = Array(); + foreach ($versionsEntity as $version) { + $versions[] = $version->getAsArray(); + } + return $versions; + } + return $versionsEntity; + } + + public function find($options, $current_user) + { + $element_id = $options["element_id"]; + $workspace_id = $options["workspace_id"]; + + if (!$element_id) { + $element_id = "root"; + } + + $options["id"] = $element_id; + if (!$this->hasAccess($options, $current_user)) { + return false; + } + + if ($element_id == "root") { + $element = $this->getRootEntity($workspace_id); + } else if ($element_id == "trash") { + $element = $this->getTrashEntity($workspace_id); + } else { + $element = $this->em->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $element_id)); + } + + $data = $element; + + if (!$data) { + return null; + } + + if (!$data->getDetachedFile() && $element->getParentId() && $element->getParentId() != "trash") { + $path = $this->getPath($workspace_id, $element_id); + } else { + $path = [$data->getAsArray()]; + } + + $versions = $this->em->getRepository("Twake\Drive:DriveFileVersion")->findBy(Array("file_id" => $element->getId())); + $file_version = []; + foreach ($versions as $version) { + $file_version[] = $version->getAsArray(); + } + $data = $data->getAsArray(); + $data["path"] = $path; + $data["versions"] = $file_version; + + return $data; + + } + + public function remove($object, $options, $current_user = null, $return_entity = false) + { + if (!$this->hasAccess($object, $current_user)) { + return false; + } + if (isset($object["id"])) { // on recoit un identifiant donc on supprime un drive file + $fileordirectory = $this->em->getRepository("Twake\Drive:DriveFile") + ->findOneBy(Array("id" => $object["id"])); + if ($fileordirectory && $fileordirectory->getParentId() && $fileordirectory->getParentId() != "trash") { + //on change la taille de tous les dossiers parent a celui ci + if ($fileordirectory->getIsInTrash()) { + //on delete definitevement de la corbeille donc on modifie pas la racine + $this->updateSize($fileordirectory->getParentId(), -$fileordirectory->getSize(), 2); + } else { + $this->updateSize($fileordirectory->getParentId(), -$fileordirectory->getSize(), 0); + } + + if ($fileordirectory->getIsDirectory()) { + $fileson = $this->em->getRepository("Twake\Drive:DriveFile") + ->findBy(Array("workspace_id" => $fileordirectory->getWorkspaceId() . "", "parent_id" => $object["id"] . "")); + if (isset($fileson)) { + foreach ($fileson as $file) { + $this->recursedelete($file); + } + } + } + $this->em->remove($fileordirectory); + $this->em->flush(); + + $this->notifyConnectors($fileordirectory, "remove", $current_user); + + } else { + return false; + } + } + + if ($return_entity) { + return $fileordirectory; + } + return $fileordirectory->getAsArray(); + } + + protected function updateSize($directory, $delta, $to_or_out_trash) // on passe l'id du directory + { + + $workspace_id = null; + + $iter = 0; + + while ($directory != null && $iter < 100) { + + $iter++; + + if ($directory == "root" || $directory == "trash" || $directory == "removed_trashes") { + if (!$workspace_id) { + return; + } + $directory = $this->getRootEntity($workspace_id); + } + if (is_string($directory)) { + $directory = $this->em->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $directory . "")); + + if (!$workspace_id && $directory) { + $workspace_id = $directory->getWorkspaceId(); + } + + } + if (!$directory) { + $directory = null; + } + + if ($directory != null) { + if (!($directory->getParentId() == "" && (($to_or_out_trash === 1 && $delta > 0) || ($to_or_out_trash === 2 && $delta < 0)))) { + $currentSize = $directory->getSize(); + $directory->setSize($currentSize + $delta); + $this->em->persist($directory); + $this->em->flush(); + } + + $directory = $this->em->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $directory->getId() . "")); + $directory = $directory->getParentId(); + } + } + } + + public function recursedelete($directoryOrFile) + { + if ($directoryOrFile->getIsDirectory()) { + $fileson = $this->em->getRepository("Twake\Drive:DriveFile")->findBy(Array("workspace_id" => $directoryOrFile->getWorkspaceId() . "", "parent_id" => $directoryOrFile->getId() . "")); + if (isset($fileson)) { + foreach ($fileson as $file) { + $this->recursedelete($file); + } + } + }else{ + try{ + //Remove file from storage + $version = $directoryOrFile->getLastVersion($this->em); + $adapter = $this->storagemanager->getAdapter($version->getProvider()); + $identifier = $version->getData()["identifier"]; + $uploadstate = $this->em->getRepository("Twake\Drive:UploadState")->findOneBy(Array("identifier" => $identifier)); + for ($i = 1; $i <= $uploadstate->getChunk(); $i++) { + $adapter->remove($uploadstate, $i); + } + }catch(\Exception $err){ + error_log($err); + } + } + $this->em->remove($directoryOrFile); + $this->em->flush(); + } + + private function notifyConnectors(DriveFile $file, $did_create = true, $current_user = null) + { + + if ($file->getDetachedFile()) { + return; + } + + $workspace_id = $file->getWorkspaceId(); + $workspace = $this->em->getRepository("Twake\Workspaces:Workspace")->findOneBy(Array("id" => $workspace_id)); + $group = $this->em->getRepository("Twake\Workspaces:Group")->findOneBy(["id" => $workspace->getGroup()]); + + $notification_data = Array( + "group" => $group->getAsArray(), + "workspace" => $workspace->getAsArray($this->em), + "file" => $file->getAsArray(), + "user" => $current_user + ); + + if ($did_create === "remove") { + $hook_name = "remove_file"; + } else if ($did_create) { + $hook_name = "new_file"; + } else { + $hook_name = "edit_file"; + } + + $application_notified = []; + + //Look if this file is in application directory + $child = $file; + $repo = $this->em->getRepository("Twake\Drive:DriveFile"); + $iter = 0; + while ($child && $child->getParentId() && $child->getParentId() != "root" && $child->getParentId() != "trash" && $iter < 100) { + $iter++; + + $parent_id = null; + if ($child->getIsInTrash()) { + $parent_id = $child->getOldParent(); + } + + if (!$parent_id) { + $parent_id = $child->getParentId(); + } + + $parent = $repo->findOneBy(Array("id" => $parent_id)); + if ($parent) { + + if ($parent->getApplicationId() && $parent->getExternalStorage()) { + + $notification_data["external_storage_root"] = $parent->getAsArray(); + + if (!in_array($parent->getApplicationId(), $application_notified)) { + $application_notified[] = $parent->getApplicationId(); + $this->applications_api->notifyApp($parent->getApplicationId(), "hook", $hook_name, $notification_data); + } + + //Do not continue while because we found our app container + break; + } + + $child = $parent; + } else { + $child = null; + } + } + + //Notify all connectors with access to drive + $resources = []; + $resources = array_merge($resources, $this->applications_api->getResources($workspace_id, "workspace_drive", $workspace_id)); + $apps_ids = []; + foreach ($resources as $resource) { + if (in_array("file", $resource->getApplicationHooks())) { + $apps_ids[] = $resource->getApplicationId(); + } + } + if (count($apps_ids) > 0) { + foreach ($apps_ids as $app_id) { + if ($app_id) { + if (!in_array($app_id, $application_notified)) { + $application_notified[] = $app_id; + $this->applications_api->notifyApp($app_id, "hook", $hook_name, $notification_data); + } + } + } + } + + } + + public function save($object, $options, $current_user = null, $upload_data = Array(), $return_entity = false) + { + + if (!$this->hasAccess($object, $current_user)) { + return false; + } + + $application = isset($options["application_id"]) ? $options["application_id"] : false; + + $did_create = false; + $fileordirectory = null; + if (isset($object["id"]) && $object["id"]) { // on recoit un identifiant donc c'est un modification + + + + $fileordirectory = $this->em->getRepository("Twake\Drive:DriveFile") + ->findOneBy(Array("id" => $object["id"] . "")); + if (!$fileordirectory) { + return false; + } + + $fileordirectory->setLastModified(); + + } else { // pas d'identifiant on veut donc crΓ©er un fichier + + if (!isset($object["workspace_id"])) { + return false; + } + $front_id = $object["front_id"]; + $workspace_id = $object["workspace_id"]; + $fileordirectory = new DriveFile($workspace_id, "defined_later", $object["is_directory"]); + $fileordirectory->setFrontId($front_id); + $fileordirectory->setCreator($current_user); + $fileordirectory->setPreviewHasBeenGenerated(false); + $fileordirectory->setHasPreview(false); + if (isset($object["detached"]) && $object["detached"]) { + $fileordirectory->setDetachedFile(true); + $parent_id = "detached"; + } + + $did_create = true; + } + + //Trying to modify trash or root folders + if ($fileordirectory->getParentId() == "trash" || (!$fileordirectory->getParentId() && !$fileordirectory->getDetachedFile())) { + return false; + } + + $did_move = false; + if (isset($object["parent_id"]) && $object["parent_id"] != "" && $object["parent_id"] != $fileordirectory->getParentId() . "") { + $parent_id = $object["parent_id"] . ""; + $did_move = true; + + if ($did_create) { // on set le fichier avec le bon parent + $file_parent = $this->em->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $object["parent_id"] . "")); + if ($file_parent == null) { + return false; + } + } else { // on a un parent ce n'est pas une creation c'est un dΓ©placement + $fileordirectory_parent_id = $fileordirectory->getParentId() . ""; + if ($fileordirectory_parent_id != $parent_id) { //changement de parent id donc le fichier a Γ©tΓ© dΓ©placΓ©. + $this->move($fileordirectory, $fileordirectory_parent_id, $parent_id, $current_user); + } + } + } else { + if (!isset($object["detached"]) && $did_create) { + $parent_id = $this->getRootEntity($workspace_id)->getId(); + } + } + if (isset($parent_id)) { + $fileordirectory->setParentId($parent_id); + } + + if (isset($object["trash"]) && $object["trash"] && !$did_create && !$fileordirectory->getIsInTrash()) { // on veut mettre un fichier a la corbeille + $oldparent = $fileordirectory->getParentId() . ""; + $newparent = $this->getTrashEntity($fileordirectory->getWorkspaceId() . "")->getId() . ""; + $this->move($fileordirectory, $oldparent, $newparent, 1, $current_user); + + $fileordirectory->setOldParent($oldparent); + + + $this->recursetrash($fileordirectory); + + + } elseif (isset($object["trash"]) && !$object["trash"] && !$did_create && $fileordirectory->getIsInTrash()) { //on veut restaurer un fichier de la corbeille sur son ancien parent + $oldparent = $fileordirectory->getParentId() . ""; + $newparent = $fileordirectory->getOldParent() . ""; + $parenttrash = $this->em->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $oldparent)); + if ($parenttrash->getIsInTrash() && $newparent === "") { // Si le parent est a la corbeille Γ©galement on va le mettre a la racine du workspace + $newparent = $this->getRootEntity($fileordirectory->getWorkspaceId() . "")->getId() . ""; + } + $this->move($fileordirectory, $oldparent, $newparent, 2, $current_user); + + $fileordirectory->setOldParent(""); + $this->recursetrash($fileordirectory); + + } + + + $name_changed = false; + if (isset($object["name"]) && $object["name"] != $fileordirectory->getName()) { + $name_changed = true; + $fileordirectory->setName($object["name"]); + } + + if (($name_changed || $did_create || $did_move) && !$fileordirectory->getIsInTrash()) { + + $repo = $this->em->getRepository("Twake\Drive:DriveFile"); + $list = $repo->findBy(Array("workspace_id" => $fileordirectory->getWorkspaceId(), "parent_id" => $fileordirectory->getParentId(), "isintrash" => false)); + + $present = true; + $iter = 0; + while ($present == true && $iter < 100) { + $iter++; + + $second_present = false; + foreach ($list as $el) { + if ($el->getName() == $fileordirectory->getName() && $el->getId() != $fileordirectory->getId()) { + $second_present = true; + } + } + if (!$second_present) { + $present = false; + } else { + $present = true; + + preg_match("/(.*)(\.[a-zA-Z0-9]+)+$/i", $fileordirectory->getName(), $matches); + $name = isset($matches[1]) ? $matches[1] : ""; + $ext = isset($matches[2]) ? $matches[2] : ""; + if (!$ext) { + $name = $fileordirectory->getName(); + $ext = ""; + } + preg_match("/-([0-9]+)$/i", $name, $matches); + $cur_val = intval(isset($matches[1]) ? $matches[1] : 0); + $cur_val_to_replace = isset($matches[0]) ? $matches[0] : ""; + + if ($iter >= 100) { + $new_name = substr($name, 0, strlen($name) - strlen($cur_val_to_replace)) . "-" . date("U") . $ext; + } else { + $new_name = substr($name, 0, strlen($name) - strlen($cur_val_to_replace)) . "-" . ($cur_val + 1) . $ext; + } + + $fileordirectory->setName($new_name); + + } + } + + } + + if ($application && $object["preview_link"]) { + $fileordirectory->setHasPreview(true); + $fileordirectory->setPreviewHasBeenGenerated(true); + $fileordirectory->setPreviewLink($object["preview_link"]); + } + + if (isset($object["hidden_data"])) { + $fileordirectory->setHiddenData($object["hidden_data"]); + } + + if ($application && isset($object["last_modification_token"])) { + $fileordirectory->setLastModificationToken($object["last_modification_token"]); + } else { + $fileordirectory->setLastModificationToken(date("U") . "-" . md5(random_bytes(20))); + } + + if (isset($object["application_id"])) { + $fileordirectory->setApplicationId($object["application_id"]); + if (isset($object["external_storage"])) { + $fileordirectory->setExternalStorage($object["external_storage"]); + } + } + + if (isset($object["url"])) { + $fileordirectory->setUrl($object["url"]); + } + + if (isset($object["tags"])) { + $fileordirectory->setTags($object["tags"]); + } + if (isset($object["attachments"]) || $did_create) { + $this->attachementManager->updateAttachements($fileordirectory, isset($object["attachments"]) ? $object["attachments"] : Array()); + } + + + $fileordirectory->setLastUser($current_user); + + + if (isset($fileordirectory)) { + $fileordirectory->setEsIndex(false); + $this->em->persist($fileordirectory); + $this->em->flush(); + } + + + if (isset($object["_once_new_version"])) { + $new = $object["_once_new_version"]; + } else { + $new = false; + } + //Update size if file was created AFTER versionning + if (!$fileordirectory->getIsDirectory() && $upload_data) { + $size_before = $fileordirectory->getSize(); + + $this->versionning($fileordirectory, $current_user, $upload_data, $new); + $size_after = $upload_data["size"]; + + if ($size_after - $size_before != 0) { + if ($fileordirectory->getDetachedFile()) { + $fileordirectory->setSize($size_after); + } else { + $this->updateSize($fileordirectory->getId() . "", $size_after - $size_before, false); + } + } + } + + $this->notifyConnectors($fileordirectory, $did_create, $current_user); + + if ($return_entity) { + return $fileordirectory; + } + return $fileordirectory->getAsArray(); + } + + public function move($fileordirectory, $oldparent, $newparent, $to_or_out_trash = 0, $current_user = null) + { + $this->em->remove($fileordirectory); + $this->em->flush(); + $fileordirectory->setParentId($newparent); + $size = $fileordirectory->getSize(); + if ($fileordirectory->getDetachedFile() == false) { + //on doit modifer la taille recursivement de l'ancien dossier parent + $this->updateSize($oldparent, -$size, $to_or_out_trash); + $trashcheck = $this->em->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $newparent . "")); + if (isset($trashcheck) && $trashcheck->getIsInTrash()) { // si on deplace un fichier sur un autre qui est prΓ©sent a la corbeille mais sans passer par la mise a la corbeille + $to_or_out_trash = 1; + $fileordirectory->setOldParent($oldparent); + //$fileordirectory->setIsInTrash(true); + $this->recursetrash($fileordirectory); + } + } else { + $fileordirectory->setDetachedFile(false); + } + $this->updateSize($newparent, $size, $to_or_out_trash); + + } + + public function recursetrash($directory) + { // permet de changer tous les in trash d'une arborescence + + $fileson = $this->em->getRepository("Twake\Drive:DriveFile")->findBy(Array("workspace_id" => $directory->getWorkspaceId() . "", "parent_id" => $directory->getId() . "")); + if (isset($fileson)) { + foreach ($fileson as $file) { + $this->recursetrash($file); + } + } + $file = $this->em->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $directory->getId())); + if (isset($file)) { + $this->em->remove($file); + $this->em->flush(); + } + $directory->setIsInTrash(!($directory->getIsInTrash())); + $this->em->persist($directory); + $this->em->flush(); + } + + public function versionning($fileordirectory, $current_user, $upload_data = null, $create_new_version = false) + { + + //on recupere la derniere version pour le fichier en cours + $last_version = null; + if ($fileordirectory->getLastVersionId()) { + $last_version = $this->em->getRepository("Twake\Drive:DriveFileVersion")->findOneBy(Array("id" => $fileordirectory->getLastVersionId())); + } + + if ($last_version && !$create_new_version && count($last_version->getData()) > 0 && $this->drive_resumable) { + //In this case we must remove what we have on storage ! + $this->drive_resumable->removeFromStorage($last_version->getData()); + } + + if (!$last_version || $create_new_version) { // on crΓ©e une nouvelle version pour le fichier en question + $last_version = new DriveFileVersion($fileordirectory, $current_user); + $last_version->setProvider($upload_data["provider"] ?: $this->storagemanager->getOneProvider()); + } + + if($last_version && $upload_data["provider"]){ + $last_version->setProvider($upload_data["provider"]); + } + + $last_version->setData(isset($upload_data["data"]) ? $upload_data["data"] : Array()); + $last_version->setSize(isset($upload_data["size"]) ? $upload_data["size"] : 0); + + $this->em->persist($last_version); + $this->em->flush(); + + $fileordirectory->setLastVersionId($last_version->getId()); + $this->em->persist($fileordirectory); + $this->em->flush(); + + } + + public function set_file_access($file_id, $has_public_acess = false, $is_editable = false, $authorized_members = Array(), $authorized_channels = Array(), $current_user = null) + { + if ($current_user) { + + $df = $this->em->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $file_id)); + //on cree la liste des personnes autorizΓ©; + if (strlen($df->getPublicAccessKey()) > 10) { + $token = $df->getPublicAccessKey(); + } else { + $token = sha1(bin2hex(random_bytes(120))); + $df->setPublicAccessKey($token); + } + + if (!$has_public_acess) { + $df->setPublicAccessKey(""); + } + + $jsondata = Array( + "token" => $has_public_acess ? $token : "", + "authorized_members" => $authorized_members, + "authorized_channels" => $authorized_channels, + "is_editable" => $is_editable); + $df->setAccesInfo($jsondata); + $this->em->persist($df); + $this->em->flush(); + + return $df->getAsArray(); + + } + } + + public function reset_file_access($file_id, $current_user = null) + { + if ($current_user) { + + $df = $this->em->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $file_id)); + $df->setPublicAccessKey(""); + $jsondata = Array( + "token" => "", + "authorized_members" => Array(), + "authorized_channels" => Array(), + "is_editable" => false + ); + $df->setAccesInfo($jsondata); + $this->em->persist($df); + $this->em->flush(); + + return $df; + + } + } + + public function emptyTrash($workspace_id, $current_user) + { + + $trash = $this->getTrashEntity($workspace_id); + $this->updateSize($this->getRootEntity($workspace_id), -$trash->getSize(), 2); + + //We have just to rename the trash, we are not really deleting it + $this->em->remove($trash); + $this->em->flush(); + + $trash->setParentId("removed_trashes"); + $trash->setName("removed_trash_" . date("U")); + $this->em->persist($trash); + $this->em->flush(); + + $this->recursedelete($trash); + + //Regenerate new trash + $new_trash = $this->getTrashEntity($workspace_id); + + return $new_trash->getAsArray(); + + } + + public function open($file_id) + { + $file = $this->em->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $file_id)); + if ($file != null) { + $file->setOpeningRate($file->getOpeningRate() + 1); + $this->em->persist($file); + $this->em->flush(); + return true; + } + + return false; + } + +} diff --git a/twake/backend/core/src/Twake/Drive/Services/DrivePreview.php b/twake/backend/core/src/Twake/Drive/Services/DrivePreview.php new file mode 100755 index 00000000..71130048 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/DrivePreview.php @@ -0,0 +1,328 @@ +<?php +/** + * Created by PhpStorm. + * User: vaati + * Date: 07/05/18 + * Time: 11:32 + */ + +namespace Twake\Drive\Services; + +use App\App; +use Dompdf\Exception; + +class DrivePreview +{ + var $doctrine; + var $img_height; + var $img_width; + var $previewableExt = []; + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->img_height = 300; + $this->img_width = 300; + $this->previewableExt = Array("png", "jpeg", "jpg", "gif", "tiff", "ai", "svg", "pdf", "txt", "rtf", "csv", "docx", "doc", "odt", "xls", "xlsx", "ods", "ppt", "pptx", "odp"); + } + + public function generatePreview($filename, $file, $path, $ext, $entity = null) + { + try { + + if (!is_dir($path)) { + mkdir($path, 0777, true); + } + + if (filesize($file) > 50000000) { //50Mo (protection) + return false; + } + + $finfo = finfo_open(FILEINFO_MIME_TYPE); + $filetype = finfo_file($finfo, $file); + + if ($filetype === 'image/png' || + $filetype === 'image/gif' || + $filetype === 'image/x-icon' || + $filetype === 'image/jpeg' || + $filetype === 'image/tiff' || + $filetype === 'image/webp' || + $this->isImage($ext)) { + return $this->generateImagePreview($filename, $file, $path, $entity); + } + + if ($filetype === 'application/pdf') { + return $this->generateImagePreview($filename, $file, $path, $entity, true); + } + if ($filetype === 'application/msword' || + $filetype === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' || + $filetype === 'text/css' || + $filetype === 'text/csv' || + $filetype === 'text/plain' || + $filetype === 'application/vnd.oasis.opendocument.presentation' || + $filetype === 'application/vnd.oasis.opendocument.spreadsheet' || + $filetype === 'application/vnd.oasis.opendocument.text' || + $filetype === 'application/vnd.ms-powerpoint' || + $filetype === 'application/vnd.ms-excel' || + $filetype === 'application/vnd.ms-office' || + $filetype === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || + $filetype === 'application/vnd.openxmlformats-officedocument.presentationml.presentation' || + $filetype === 'application/vnd.oasis.opendocument.text' || + $filetype === 'application/vnd.oasis.opendocument.presentation' || + $filetype === 'application/vnd.oasis.opendocument.spreadsheet' || + $filetype === 'application/vnd.oasis.opendocument.chart' || + $filetype === 'application/xml' || + $filetype === 'text/html' || + $ext === 'doc' || + $ext === 'docx ' || + $ext === 'xls' || + $ext === 'xlsx' || + $ext === 'pps' || + $ext === 'ppt' || + $ext === 'pptx' || + $ext === 'bmp' || + $ext === 'ico' || + $ext === 'odt' || + $ext === 'odg' || + $ext === 'odp' || + $ext === 'ods' || + $ext === 'odc' || + $ext === 'xml' || + $ext === 'webp' || + $ext === 'txt' || + $ext === 'svg' + ) { + return $this->generateImagePreview($filename, $file, $path, $entity, false, true); + } + + + finfo_close($finfo); + + } catch (\Exception $e) { + error_log("Error during preview generation : " . $e); + } + + return false; + } + + /* Do not generate preview for files larger than 50Mo */ + + public function isImage($ext) + { + return ( + $ext === 'png' || + $ext === 'jpg' || + $ext === 'jpeg' || + $ext === 'gif' || + $ext === 'svg' || + $ext === 'tiff' + ); + } + + public function generateImagePreview($filename, $file, $path, $entity = null, $isText = false, $isOffice = false) + { + $filepath = $path . "/" . $filename; + $width = $this->img_width; + $height = $this->img_height; + $im = new \Imagick(); + + + if ($isText) { + $im->readimage($file . "[0]"); + $this->set_keyword($file, $entity); + } elseif ($isOffice) { + $file = $this->convertToPDF($file, $entity); + if ($file) { + $im->readimage($file . "[0]"); + $this->set_keyword($file, $entity); + } + } else { + $im->readimage($file); + } + + + $im = $this->autorotate($im); + $im->setBackgroundColor(new \ImagickPixel('transparent')); + $geo = $im->getImageGeometry(); + + $min_size = min((int)($geo['width']), (int)($geo['height'])); + + if ($min_size > $this->img_width) { + $ox = 0; + $oy = (int)(($geo['height'] - $min_size) / 2); + if ($min_size == (int)($geo['height'])) { + $ox = (int)(($geo['width'] - $min_size) / 2); + $oy = 0; + } + $im->cropImage($min_size, $min_size, $ox, $oy); + } + + // get the current image dimensions + $im->ThumbnailImage($width, $height, true); + + /* + $canvas = new \Imagick(); + $canvas->newImage($width, $height, 'white', 'png'); + $canvas->setBackgroundColor(new \ImagickPixel('transparent')); + $offsetX = (int)($width / 2) - (int)($geo['width'] / 2); + $offsetY = (int)($height / 2) - (int)($geo['height'] / 2); + $canvas->compositeImage($im, \Imagick::COMPOSITE_OVER, $offsetX, $offsetY); + + $im = $canvas; + */ + + // thumbnail the image + + + $im->setImageFormat('png'); + $im->writeImage($filepath . '.png'); + $im->clear(); + $im->destroy(); + + if ($isOffice) { + unlink($file); + } + + } + + public function set_keyword($file, $entity) + { + + try { + $content = (new \Spatie\PdfToText\Pdf()) + ->setPdf($file) + ->text(); + $content = str_replace(array("\\'", "'"), " ", $content); + $size = substr_count($content, ' '); + + $words = str_word_count(strtolower($content), 1, 'Γ€Γ‚Γ„Γ‡Γ‰ΓˆΓŠΓ‹ΓŽΓΓ”Γ–Γ™Γ›ΓœΕΈΓ†Ε’Γ Γ’Γ€Γ§Γ©Γ¨ΓͺΓ«Γïôâùûüÿæœ'); + $totalwords = 1; + + $keywords = Array(); + + $regex = <<<'END' +/ +( + (?: [\x00-\x7F] #:00d2f4aa-605b-11e9-b23e-0242ac120005 single-byte sequences 0xxxxxxx + | [\xC0-\xDF][\x80-\xBF] #:00d2f4aa-605b-11e9-b23e-0242ac120005 double-byte sequences 110xxxxx 10xxxxxx + | [\xE0-\xEF][\x80-\xBF]{2} #:00d2f4aa-605b-11e9-b23e-0242ac120005 triple-byte sequences 1110xxxx 10xxxxxx * 2 + | [\xF0-\xF7][\x80-\xBF]{3} #:00d2f4aa-605b-11e9-b23e-0242ac120005 quadruple-byte sequence 11110xxx 10xxxxxx * 3 + ){1,100} #:00d2f4aa-605b-11e9-b23e-0242ac120005 ...one or more times +) +| . #:00d2f4aa-605b-11e9-b23e-0242ac120005 anything else +/x +END; + foreach ($words as $value) { + $value = preg_replace($regex, '$1', $value); + $value = strtolower($value); + if (strlen($value) > 3 && is_numeric($value) == false) { + if ($totalwords < floor($size * 0.20)) //we define the weight of word trough the text + $weight = 20; + elseif ($totalwords > floor($size * 80)) + $weight = 20; + else + $weight = 3; + if (!isset($keywords[$value])) { + $keywords[$value] = 0; + } + if (!($keywords[$value]) || substr($value, -1) == "s") { //if the word is not in our table + if (substr($value, -1) == "s") { //we check if it's a plural + $maybesinglar = substr($value, 0, strlen($value) - 1); + if (isset($keywords[$maybesinglar])) { // we check if their is already a singular for this word + $keywords[$maybesinglar] += $weight + max(strlen($maybesinglar) - 4, 0) * 2; //if we find a singular we add the singular version of the word instead of the plural + } else { // if not we add the new words or it's the first time we saw the word so we need to add it + $keywords[$value] = $weight + max(strlen($value) - 4, 0) * 2; + } + } else { + $keywords[$value] = $weight + max(strlen($value) - 4, 0) * 2; // we add the new word which is not a plural or it the first time we saw it + } + } else { //if the word is in the table + $keywords[$value] += $weight + max(strlen($value) - 4, 0) * 2; // we adjust his weight in the table + } + } + $totalwords++; //we add our total of word to alter the weight of futur word. + } + + arsort($keywords); // Sort based on frequency + + + $keywords_raw = array_slice($keywords, 0, 100); + $max = array_values(array_slice($keywords, 0, 1))[0]; + + foreach ($keywords_raw as $key => $score) { + $keywords_raw[$key] = ($score / $max); + } + + $keywords_score = Array(); + foreach ($keywords_raw as $key => $score) { + $keywords_score[] = Array( + "keyword" => $key, + "score" => $keywords_raw[$key] + ); + } + + $entity->setContentKeywords($keywords_score); + + } catch (\Exception $e) { + + } + + } + + public function convertToPDF($filepath, $entity) + { + putenv("PATH=/sbin:/bin:/usr/sbin:/usr/bin"); + error_log($filepath); + shell_exec("timeout 5s unoconv -T 5 -vvvv -f pdf -e PageRange=1-1 " . $filepath); + $a = explode(".", $filepath); + array_pop($a); + $filepath = join(".", $a) . ".pdf"; + if (!file_exists($filepath)) { + + $name = "Unknown name"; + if ($entity) { + $name = $entity->getName(); + } + + return false; + } + return $filepath; + } + + private function autorotate(\Imagick $image) + { + switch ($image->getImageOrientation()) { + case \Imagick::ORIENTATION_TOPLEFT: + break; + case \Imagick::ORIENTATION_TOPRIGHT: + $image->flopImage(); + break; + case \Imagick::ORIENTATION_BOTTOMRIGHT: + $image->rotateImage("#000", 180); + break; + case \Imagick::ORIENTATION_BOTTOMLEFT: + $image->flopImage(); + $image->rotateImage("#000", 180); + break; + case \Imagick::ORIENTATION_LEFTTOP: + $image->flopImage(); + $image->rotateImage("#000", -90); + break; + case \Imagick::ORIENTATION_RIGHTTOP: + $image->rotateImage("#000", 90); + break; + case \Imagick::ORIENTATION_RIGHTBOTTOM: + $image->flopImage(); + $image->rotateImage("#000", 90); + break; + case \Imagick::ORIENTATION_LEFTBOTTOM: + $image->rotateImage("#000", -90); + break; + default: // Invalid orientation + break; + } + $image->setImageOrientation(\Imagick::ORIENTATION_TOPLEFT); + return $image; + } + +} diff --git a/twake/backend/core/src/Twake/Drive/Services/OldFileSystem/Adapter_AWS_DriveFileSystem.php b/twake/backend/core/src/Twake/Drive/Services/OldFileSystem/Adapter_AWS_DriveFileSystem.php new file mode 100755 index 00000000..499c4b0b --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/OldFileSystem/Adapter_AWS_DriveFileSystem.php @@ -0,0 +1,108 @@ +<?php + + +namespace Twake\Drive\Services\OldFileSystem; + +use App\App; +use Aws\S3\Exception\S3Exception; +use Aws\S3\S3Client; + +class Adapter_AWS_DriveFileSystem +{ + + public function __construct(App $app) + { + $configuration = $app->getContainer()->getParameter("storage.openstack"); + foreach($app->getContainer()->getParameter("storage.providers") as $providerConfiguration){ + if($providerConfiguration["type"] == "S3"){ + $configuration = $providerConfiguration; + } + } + $this->configure($app, $configuration); + } + + public function configure(App $app, $config){ + $aws_config = $config; + $s3_config = $aws_config; + + $this->root = $this->local = $app->getAppRootDir(); + $this->parameter_drive_salt = $s3_config["override_drive_salt"] ?: $app->getContainer()->getParameter("storage.drive_salt"); + + $this->aws_version = $s3_config["version"]; + $this->aws_buckets = $s3_config["buckets"]; + $this->aws_buckets_prefix = isset($s3_config["buckets_prefix"]) ? $s3_config["buckets_prefix"] : ""; + $this->aws_credentials_key = $s3_config["credentials"]["key"]; + $this->aws_credentials_secret = $s3_config["credentials"]["secret"]; + + $region = false; + foreach ($this->aws_buckets as $region_code => $aws_region) { + if ($region_code == "fr" || !$region) { + $region = $aws_region; + } + } + $this->aws_bucket_name = isset($s3_config["bucket_name"]) ? $s3_config["bucket_name"] : ($this->aws_buckets_prefix . 'twake.' . $region); + $this->aws_bucket_region = $region; + + $options = [ + 'version' => $this->aws_version, + 'region' => $this->aws_bucket_region, + 'use_path_style_endpoint' => isset($s3_config["use_path_style_endpoint"]) ? $s3_config["use_path_style_endpoint"] : false, + 'credentials' => [ + 'key' => $this->aws_credentials_key, + 'secret' => $this->aws_credentials_secret + ] + ]; + if (isset($s3_config["base_url"]) && $s3_config["base_url"]) { + $options["endpoint"] = $s3_config["base_url"]; + } + + $this->aws_s3_client = new S3Client($options); + } + + public function decode($path, $key, $mode = null) + { + + $key = "AWS" . $this->parameter_drive_salt . $key; + $key = md5($key); + + $key_path = str_replace($this->getRoot() . "/", "", $path); + $key_path = str_replace($this->getRoot(), "", $key_path); + + try { + + $object = $this->aws_s3_client->getObject([ + 'Bucket' => $this->aws_bucket_name, + 'Key' => "drive/" . $key_path, + 'SSECustomerAlgorithm' => 'AES256', + 'SSECustomerKey' => $key, + 'SSECustomerKeyMD5' => md5($key, true) + ]); + + $tmpPath = "/tmp/" . bin2hex(random_bytes(16)); + $this->verifyPath($tmpPath); + file_put_contents($tmpPath, $object["Body"]); + + return $tmpPath; + + } catch (S3Exception $e) { + error_log("Error accessing aws file."); + } + + return false; + } + + public function getRoot() + { + return dirname($this->root) . "/" . "drive" . "/"; + } + + public function verifyPath($path) + { + if (strpos($path, "/tmp") !== false) { + $path = dirname($path); + if (!file_exists($path, null)) { + mkdir($path, 0777, true); + } + } + } +} diff --git a/twake/backend/core/src/Twake/Drive/Services/OldFileSystem/Adapter_OpenStack_DriveFileSystem.php b/twake/backend/core/src/Twake/Drive/Services/OldFileSystem/Adapter_OpenStack_DriveFileSystem.php new file mode 100755 index 00000000..b75a48f5 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/OldFileSystem/Adapter_OpenStack_DriveFileSystem.php @@ -0,0 +1,118 @@ +<?php + + +namespace Twake\Drive\Services\OldFileSystem; + +use App\App; +use GuzzleHttp\Client; +use GuzzleHttp\HandlerStack; +use OpenStack\Common\Transport\Utils as TransportUtils; +use OpenStack\Identity\v2\Service; +use OpenStack\OpenStack; + +class Adapter_OpenStack_DriveFileSystem +{ + + public function __construct(App $app) + { + $configuration = $app->getContainer()->getParameter("storage.openstack"); + foreach($app->getContainer()->getParameter("storage.providers") as $providerConfiguration){ + if($providerConfiguration["type"] == "openstack"){ + $configuration = $providerConfiguration; + } + } + $this->configure($app, $configuration); + } + + public function configure(App $app, $config){ + $openstack_config = $config; + $this->root = $this->local = $app->getAppRootDir(); + $this->parameter_drive_salt = $openstack_config["override_drive_salt"] ?: $app->getContainer()->getParameter("storage.drive_salt"); + + $this->openstack_buckets = $openstack_config["buckets"]; + $this->openstack_buckets_prefix = isset($openstack_config["buckets_prefix"]) ? $openstack_config["buckets_prefix"] : ""; + $this->openstack_credentials_key = $openstack_config["user"]["id"]; + $this->openstack_credentials_secret = $openstack_config["user"]["password"]; + $this->openstack_project_id = $openstack_config["project_id"]; + $this->openstack_auth_url = $openstack_config["auth_url"]; + + $httpClient = new Client([ + 'base_uri' => TransportUtils::normalizeUrl($this->openstack_auth_url), + 'handler' => HandlerStack::create(), + ]); + + $region = false; + foreach ($this->openstack_buckets as $region_code => $openstack_region) { + if ($region_code == "fr" || !$region) { + if (isset($openstack_region["private"])) { + $region = $openstack_region["private"]; + $public_region = $openstack_region["public"]; + } else { + $region = $openstack_region["public"]; + } + $region_id = $openstack_region["region"]; + } + } + $this->openstack_bucket_name = $this->openstack_buckets_prefix . $region; + $this->openstack_public_bucket_name = $this->openstack_buckets_prefix . $public_region; + $this->openstack_bucket_region = $region; + $this->openstack_region_id = $region_id; + + $this->openstack = new OpenStack([ + 'authUrl' => $this->openstack_auth_url, + 'region' => $this->openstack_region_id, + 'tenantId' => $this->openstack_project_id, + 'username' => $this->openstack_credentials_key, + 'password' => $this->openstack_credentials_secret, + 'identityService' => Service::factory($httpClient) + ]); + + } + + public function decode($path, $key, $mode = null) + { + + $key = "OpenStack" . $this->parameter_drive_salt . $key; + $key = md5($key); + + $key_path = str_replace($this->getRoot() . "/", "", $path); + $key_path = str_replace($this->getRoot(), "", $key_path); + + try { + + $stream = $this->openstack->objectStoreV1() + ->getContainer($this->openstack_bucket_name) + ->getObject("drive/" . $key_path) + ->download(); + + $tmpPath = $this->getRoot() . "/tmp/" . bin2hex(random_bytes(16)); + $this->verifyPath($tmpPath); + file_put_contents($tmpPath, $stream->getContents()); + + $decodedPath = parent::decode($tmpPath, $key, $mode); + rename($decodedPath, $tmpPath); + + return $tmpPath; + + } catch (\Exception $e) { + error_log("Error accessing aws file."); + } + + return false; + } + + public function getRoot() + { + return dirname($this->root) . "/" . "drive" . "/"; + } + + public function verifyPath($path) + { + if (strpos($path, "/tmp") !== false) { + $path = dirname($path); + if (!file_exists($path, null)) { + mkdir($path, 0777, true); + } + } + } +} diff --git a/twake/backend/core/src/Twake/Drive/Services/OldFileSystem/DriveAdapterSelector.php b/twake/backend/core/src/Twake/Drive/Services/OldFileSystem/DriveAdapterSelector.php new file mode 100755 index 00000000..ebb190b5 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/OldFileSystem/DriveAdapterSelector.php @@ -0,0 +1,39 @@ +<?php + +namespace Twake\Drive\Services\OldFileSystem; + +use App\App; + +class DriveAdapterSelector +{ + + public function __construct(App $app) + { + $services = $app->getServices(); + $this->app = $app; + $this->aws = $app->getContainer()->getParameter("storage.S3"); + $this->openstack = $app->getContainer()->getParameter("storage.openstack"); + $this->storagemanager = $services->get("driveupload.storemanager"); + } + + public function getFileSystem($provider = null) + { + if($provider === null || $provider === false){ + $provider = $this->storagemanager->getOneProvider(); + } + $configuration = $this->storagemanager->getProviderConfiguration($provider); + + if ($configuration["type"] === "S3") { + $this->aws_file_system = $this->app->getServices()->get("app.drive.old.AWS_FileSystem"); + $this->aws_file_system->configure($this->app, $configuration); + return $this->aws_file_system; + } + if ($configuration["type"] === "openstack") { + $this->openstack_file_system = $this->app->getServices()->get("app.drive.old.OpenStack_FileSystem"); + $this->openstack_file_system->configure($this->app, $configuration); + return $this->openstack_file_system; + } + + } + +} diff --git a/twake/backend/core/src/Twake/Drive/Services/Resumable/Network/SimpleRequest.php b/twake/backend/core/src/Twake/Drive/Services/Resumable/Network/SimpleRequest.php new file mode 100755 index 00000000..e96c7fa9 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/Resumable/Network/SimpleRequest.php @@ -0,0 +1,60 @@ +<?php + +namespace Twake\Drive\Services\Resumable\Network; + +class SimpleRequest +{ + public $apprequest; + + public function __construct($request) + { + $this->apprequest = $request; + } + + /** + * @param $type get/post + * @return boolean + */ + public function is($type) + { + switch (strtolower($type)) { + case 'post': + return isset($_POST) && !empty($_POST); + break; + case 'get': + return isset($_GET) && !empty($_GET); + break; + } + return false; + } + + /** + * @param $requestType GET/POST + * @return mixed + */ + public function data($requestType) + { + switch (strtolower($requestType)) { + case 'post': + return isset($_POST) ? $_POST : array(); + break; + case 'get': + return isset($_GET) ? $_GET : array(); + break; + } + return array(); + } + + /** + * @return FILES data + */ + public function file() + { + + if (!isset($_FILES) || empty($_FILES)) { + return array(); + } + $files = array_values($_FILES); + return array_shift($files); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Services/Resumable/Network/SimpleResponse.php b/twake/backend/core/src/Twake/Drive/Services/Resumable/Network/SimpleResponse.php new file mode 100755 index 00000000..3ff8ef36 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/Resumable/Network/SimpleResponse.php @@ -0,0 +1,30 @@ +<?php + +namespace Twake\Drive\Services\Resumable\Network; + +use Common\Http\Response; + +class SimpleResponse +{ + + private $appresponse; + + public function __construct($response) + { + $this->appresponse = $response; + } + + /** + * @param $statusCode + * @return mixed + */ + public function header($statusCode) + { + if (200 == $statusCode) { + return $this->appresponse->setStatusCode(Response::HTTP_OK); + } else if (404 == $statusCode) { + return $this->appresponse->setStatusCode(Response::HTTP_NOT_FOUND); + } + return $this->appresponse->setStatusCode(Response::HTTP_NO_CONTENT); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Services/Resumable/Resumable.php b/twake/backend/core/src/Twake/Drive/Services/Resumable/Resumable.php new file mode 100755 index 00000000..7bd5bf6d --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/Resumable/Resumable.php @@ -0,0 +1,447 @@ +<?php + +namespace Twake\Drive\Services\Resumable; + +use Twake\Core\Services\Queues\Adapters\QueueManager; +use Twake\Drive\Entity\UploadState; +use Twake\Drive\Services\DriveFile; +use Twake\Drive\Services\Storage\EncryptionBag; +use App\App; + +class Resumable +{ + const WITHOUT_EXTENSION = true; + public $debug = false; + public $tempFolder = 'tmp'; + // for testing + public $uploadFolder = 'test/files/uploads'; + public $deleteTmpFolder = true; + protected $request; + protected $response; + protected $params; + protected $chunkFile; + protected $filename; + protected $filepath; + protected $extension; + protected $originalFilename; + protected $isUploadComplete = false; + protected $resumableOption = [ + 'identifier' => 'identifier', + 'filename' => 'filename', + 'chunkNumber' => 'chunkNumber', + 'chunkSize' => 'chunkSize', + 'totalSize' => 'totalSize', + 'query' => 'query', + 'parent_id' => 'parent_id' + ]; + protected $storagemanager; + protected $doctrine; + protected $driverefacto; + protected $current_user; + protected $previews; + protected $parameter_drive_salt; + /** @var QueueManager */ + protected $queues; + + public function __construct(App $app) + { + $this->queues = $app->getServices()->get("app.queues")->getAdapter(); + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->storagemanager = $app->getServices()->get("driveupload.storemanager"); + $this->driverefacto = $app->getServices()->get("app.drive"); + $this->previews = $app->getContainer()->getParameter("storage.drive_previews_tmp_folder"); + $this->tempFolder = $app->getContainer()->getParameter("storage.drive_tmp_folder"); + $this->parameter_drive_salt = $app->getContainer()->getParameter("storage.drive_salt"); + } + + public function setResumableOption(array $resumableOption) + { + $this->resumableOption = array_merge($this->resumableOption, $resumableOption); + } + + // sets original filename and extenstion etc + public function process($current_user) + { + + if (!empty($this->resumableParams())) { + if (!empty($this->request->file())) { + $this->current_user_id = $current_user; + return $this->handleChunk(); + } else { + $this->handleTestChunk(); + } + } + } + + public function resumableParams() + { + if ($this->request->is('get')) { + return $this->request->data('get'); + } + if ($this->request->is('post')) { + return $this->request->data('post'); + } + } + + public function handleChunk($file_or_url = null, $filename = null, $totalSize = null, $identifier = null, $chunkNumber = null, $numOfChunks = null, $object_from_caller = null, $options_from_caller = null) + { + + // VERIFIER IDENTIFIER QU ON A BIEN QUE DES CHIFFRES ET DES LETTRES ET PAS UN REQUETE OU AUTRES. + $file = $file_or_url !== null ? $file_or_url : $this->request->file(); + $identifier = $identifier ? $identifier : $this->resumableParam($this->resumableOption['identifier']); + $filename = $filename !== null ? $filename : $this->resumableParam($this->resumableOption['filename']); + $chunkNumber = $chunkNumber ? $chunkNumber : $this->resumableParam($this->resumableOption['chunkNumber']); + $totalSize = $totalSize !== null ? $totalSize : intval($_POST["resumableTotalSize"]); + $numOfChunks = $numOfChunks ? $numOfChunks : intval($_POST["resumableTotalChunks"]); + + + $finalname = $identifier . ".chunk_" . $chunkNumber; + + if (!$this->isChunkUploaded($identifier, $finalname, $chunkNumber)) { + + $uploadstate = $this->doctrine->getRepository("Twake\Drive:UploadState")->findOneBy(Array("identifier" => $identifier)); + $param_bag = new EncryptionBag($uploadstate->getEncryptionKey(), $uploadstate->getEncryptionSalt(), $uploadstate->getEncryptionMode()); + + if ($this->current_user_id != $uploadstate->getUserId()) { + return false; + } + + $chunkFile = $this->tmpChunkDir() . DIRECTORY_SEPARATOR . $finalname; + + $do_preview = ($numOfChunks == 1 && $chunkNumber == 1 && $totalSize < 50000000); + + if (!$this->storagemanager->getAdapter($uploadstate->getStorageProvider())->streamModeIsAvailable() || $do_preview) { + + if (is_string($file)) { + if (strpos($file, "http://") === 0 || strpos($file, "https://") === 0) { + try{ + $newContent = fopen($file, 'r', false, stream_context_create(array( + "ssl"=>array( + "verify_peer"=>false, + "verify_peer_name"=>false, + ), + ))); + }catch(\Exception $e){ + error_log("Error while downloading file from url : " . $file); + return; + } + file_put_contents($chunkFile, $newContent); + } + } else { + $this->moveUploadedFile($file['tmp_name'], $chunkFile); + } + + if ($file_or_url && $numOfChunks == 1) { + $totalSize = filesize($chunkFile); + } + + //Preview if only one chunk + if ($do_preview) { + $previewDestination = $this->previews . DIRECTORY_SEPARATOR . "preview_" . $finalname; + $this->copy($chunkFile, $previewDestination); + $uploadstate->setHasPreview(true); + $this->doctrine->persist($uploadstate); + $this->doctrine->flush(); + } + + } else { + $chunkFile = $file['tmp_name']; + } + + + $this->storagemanager->getAdapter($uploadstate->getStorageProvider())->write($chunkFile, $chunkNumber, $param_bag, $uploadstate); + $this->doctrine->clear(); + + $chunktoadd = "chunk_" . $chunkNumber; + $uploadstate = $this->doctrine->getRepository("Twake\Drive:UploadState")->findOneBy(Array("identifier" => $identifier)); + $uploadstate->addChunk($chunktoadd); + $this->doctrine->persist($uploadstate); + $this->doctrine->flush(); + + } + + if (isset($uploadstate) && $uploadstate->getChunk() == $numOfChunks && count($uploadstate->getChunklist()) == $numOfChunks) { + + $this->isUploadComplete = true; + $uploadstate->setSuccess(true); + $uploadstate->setChunk($chunkNumber); + $this->doctrine->persist($uploadstate); + $this->doctrine->flush(); + + $object = Array(); + if ($object_from_caller) { + $object = $object_from_caller; + } else { + $object = json_decode($_POST['object'], 1); + + } + + $data = Array("upload_mode" => "chunk", "identifier" => $identifier, "nb_chunk" => $chunkNumber); + + //TODO What if we uploaded to an existing object (object[id] is set) TODO->REMOVE OLD VERSION IF WE ARE NOT CREATING A NEW ONE (or each time onlyoffice write we add a new copy on S3) + + $this->driverefacto->setDriveResumable($this); + $fileordirectory = $this->driverefacto->save($object, $options_from_caller, $current_user, Array("provider" => $uploadstate->getStorageProvider(), "data" => $data, "size" => $totalSize), true); + + if ($uploadstate->getHasPreview() && $totalSize < 20000000) { + $this->storagemanager->getAdapter($uploadstate->getStorageProvider())->genPreview($fileordirectory, $previewDestination); + } else { + $this->queues->push("drive_preview_to_generate", [ + "file_id" => $fileordirectory->getId() + ]); + } + $fileToReturn = $fileordirectory->getAsArray(); + if (!$fileordirectory->getIsDirectory()) { + $versions = $this->driverefacto->getFileVersion($fileordirectory, true); + $fileToReturn["versions"] = $versions; + return $fileToReturn; + } + return $fileordirectory->getAsArray(); + + } + return true; + } + + private function resumableParam($shortName) + { + $resumableParams = $this->resumableParams(); + if (!isset($resumableParams['resumable' . ucfirst($shortName)])) { + return null; + } + return $resumableParams['resumable' . ucfirst($shortName)]; + } + + public function isChunkUploaded($identifier, $filename, $chunkNumber) + { + $part = explode("_", $filename)[0]; + $chemin = $this->tmpChunkDir($identifier) . DIRECTORY_SEPARATOR . $part . "_" . $chunkNumber; + + return file_exists($chemin); + } + + public function tmpChunkDir() + { + //$tmpChunkDir = $this->tempFolder . DIRECTORY_SEPARATOR . $identifier; + $tmpChunkDir = $this->tempFolder; + //error_log($tmpChunkDir); + if (!file_exists($tmpChunkDir)) { + mkdir($tmpChunkDir); + } + return $tmpChunkDir; + } + + public function moveUploadedFile($file, $destFile) + { + if (file_exists($file)) { + return copy($file, $destFile); + } + return false; + } + + public function copy($file, $destFile) + { + if (file_exists($file)) { + return copy($file, $destFile); + } + return false; + } + + public function handleTestChunk() + { + + $identifier = $this->resumableParam($this->resumableOption['identifier']); + $filename = $this->resumableParam($this->resumableOption['filename']); + $chunkNumber = $this->resumableParam($this->resumableOption['chunkNumber']); + + + if (!$this->isChunkUploaded($identifier, $filename, $chunkNumber)) { + return $this->response->header(204); + } else { + return $this->response->header(200); + } + } + + /** + * Get isUploadComplete + * + * @return boolean + */ + public function isUploadComplete() + { + return $this->isUploadComplete; + } + + /** + * Get final filename. + * + * @return string Final filename + */ + public function getFilename() + { + return $this->filename; + } + + /** + * Set final filename. + * + * @param string Final filename + */ + public function setFilename($filename) + { + $this->filename = $filename; + return $this; + } + + /** + * Get final filename. + * + * @return string Final filename + */ + public function getOriginalFilename($withoutExtension = false) + { + if ($withoutExtension === static::WITHOUT_EXTENSION) { + return $this->removeExtension($this->originalFilename); + } + return $this->originalFilename; + } + + private function removeExtension($filename) + { + $parts = explode('.', basename($filename)); + $ext = end($parts); // get extension + // remove extension from filename if any + return str_replace(sprintf('.%s', $ext), '', $filename); + } + + /** + * Get final filapath. + * + * @return string Final filename + */ + public function getFilepath() + { + return $this->filepath; + } + + /** + * Get final extension. + * + * @return string Final extension name + */ + public function getExtension() + { + return $this->extension; + } + + public function createObject($workspace_id, $filename, $extension, $user_id) + { + + $identifier = $workspace_id . date("U") . bin2hex(random_bytes(20)); + + $this->current_user_id = $user_id; + + $storage_provider = $this->storagemanager->getOneProvider(); + + $chunklist = Array(); + $uploadstate = new UploadState($storage_provider, $workspace_id, $identifier, $filename, $extension, $chunklist); + $new_key = bin2hex(random_bytes(20)); + $uploadstate->setEncryptionKey($new_key); + $uploadstate->setEncryptionSalt(""); + $uploadstate->setEncryptionMode("OpenSSL-2"); + $uploadstate->setUserId($user_id); + $this->doctrine->persist($uploadstate); + $this->doctrine->flush(); + + sleep(1); + + return $identifier; + } + + /** + * Makes sure the orginal extension never gets overriden by user defined filename. + * + * @param string User defined filename + * @param string Original filename + * @return string Filename that always has an extension from the original file + */ +// private function createSafeFilename($filename, $originalFilename) +// { +// $filename = $this->removeExtension($filename); +// $extension = $this->findExtension($originalFilename); +// return sprintf('%s.%s', $filename, $extension); +// } + public function tmpChunkFilename($filename, $chunkNumber) + { + return $filename . '.' . str_pad($chunkNumber, 4, 0, STR_PAD_LEFT); + } + + public function updateParam($request, $response) + { + $this->setRequest($request); + $this->setResponse($response); + $this->preProcess(); + } + + public function setRequest($request) + { + $this->request = $request; + } + + public function setResponse($response) + { + $this->response = $response; + } + + public function preProcess() + { + if (!empty($this->resumableParams())) { + if (!empty($this->request->file())) { + $this->extension = $this->findExtension($this->resumableParam('filename')); + $this->originalFilename = $this->resumableParam('filename'); + } + } + } + + private function findExtension($filename) + { + $parts = explode('.', basename($filename)); + return end($parts); + } + + + public function getExclusiveFileHandle($name) + { + // if the file exists, fopen() will raise a warning + $previous_error_level = error_reporting(); + error_reporting(E_ERROR); + $handle = fopen($name, 'a'); + error_reporting($previous_error_level); + return $handle; + } + + public function removeFromStorage($data) + { + + if ($data["upload_mode"] == "chunk") { + + $identifier = $data["identifier"]; + $chunkNumber = $data["nb_chunk"]; + + $uploadstate = $this->doctrine->getRepository("Twake\Drive:UploadState")->findOneBy(Array("identifier" => $identifier)); + + for ($i = 1; $i <= $chunkNumber; $i++) { + $this->storagemanager->getAdapter($uploadstate->getStorageProvider())->remove($uploadstate, $i); + } + + $this->doctrine->remove($uploadstate); + $this->doctrine->flush(); + + return true; + + } + + return false; + } + + +} diff --git a/twake/backend/core/src/Twake/Drive/Services/Storage/AdapterInterface.php b/twake/backend/core/src/Twake/Drive/Services/Storage/AdapterInterface.php new file mode 100755 index 00000000..ab7454be --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/Storage/AdapterInterface.php @@ -0,0 +1,16 @@ +<?php + +namespace Twake\Drive\Services\Storage; + +use Twake\Drive\Entity\UploadState; + +interface AdapterInterface +{ + + public function read($destination, $chunkNo, $param_bag, UploadState $uploadState, &$zip, $zip_prefixe); + + public function write($chunkFile, $chunkNo, $param_bag, UploadState $uploadState); + + public function streamModeIsAvailable(); + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Services/Storage/Adapter_AWS.php b/twake/backend/core/src/Twake/Drive/Services/Storage/Adapter_AWS.php new file mode 100755 index 00000000..ac40af5b --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/Storage/Adapter_AWS.php @@ -0,0 +1,248 @@ +<?php + +namespace Twake\Drive\Services\Storage; + +use Aws\S3\Exception\S3Exception; +use Aws\S3\S3Client; +use Twake\Drive\Entity\DriveFile; +use Twake\Drive\Entity\UploadState; + +class Adapter_AWS implements AdapterInterface +{ + + public function __construct($aws_config, $preview, $doctrine) + { + + $s3_config = $aws_config; + $this->aws_version = $s3_config["version"]; + $this->aws_buckets = $s3_config["buckets"]; + $this->aws_buckets_prefix = isset($s3_config["buckets_prefix"]) ? $s3_config["buckets_prefix"] : ""; + $this->aws_credentials_key = $s3_config["credentials"]["key"]; + $this->aws_credentials_secret = $s3_config["credentials"]["secret"]; + $this->disable_encryption = $s3_config["disable_encryption"] ?: false; + $this->parameter_drive_salt = $s3_config["override_drive_salt"] ?: $s3_config["default_drive_salt"]; + $this->default_parameter_drive_salt = $s3_config["default_drive_salt"]; + + $region = false; + foreach ($this->aws_buckets ? $this->aws_buckets : [] as $region_code => $aws_region) { + if ($region_code == "fr" || !$region) { + $region = $aws_region; + } + } + $this->aws_bucket_name = isset($s3_config["bucket_name"]) ? $s3_config["bucket_name"] : ($this->aws_buckets_prefix . 'twake.' . $region); + $this->aws_bucket_region = $region; + + $options = [ + 'version' => $this->aws_version, + 'region' => $this->aws_bucket_region, + 'use_path_style_endpoint' => isset($s3_config["use_path_style_endpoint"]) ? $s3_config["use_path_style_endpoint"] : false, + 'credentials' => [ + 'key' => $this->aws_credentials_key, + 'secret' => $this->aws_credentials_secret + ] + ]; + if (isset($s3_config["base_url"]) && $s3_config["base_url"]) { + $options["endpoint"] = $s3_config["base_url"]; + } + + $this->aws_s3_client = new S3Client($options); + + $this->preview = $preview; + $this->doctrine = $doctrine; + } + + + public function genPreview(DriveFile $file, $tmppath) + { + + $res = false; + if (!$file->getIsDirectory() && $file->getLastVersion($this->doctrine)) { + + $ext = $file->getExtension(); + + + if ($tmppath) { + + rename($tmppath, $tmppath . ".tw"); + $tmppath = $tmppath . ".tw"; + + try { + + //Remove old preview + if ($file->getPreviewLink()) { + try { + $this->aws_s3_client->deleteObject([ + 'Bucket' => $this->aws_bucket_name, + 'Key' => "public/uploads/previews/" . $file->getPath() . ".png", + ]); + } catch (S3Exception $e) { + error_log($e->getMessage()); + } + } + + try { + $this->preview->generatePreview(basename($file->getPath()), $tmppath, dirname($tmppath), $ext, $file); + } catch (\Exception $e) { + //error_log($e->getMessage()); + } + $previewpath = dirname($tmppath) . "/" . basename($file->getPath()); + + if (file_exists($previewpath . ".png")) { + + try { + // Upload data. + $result = $this->aws_s3_client->putObject([ + 'Bucket' => $this->aws_bucket_name, + 'Key' => "public/uploads/previews/" . $file->getId() . ".png", + 'Body' => fopen($previewpath . ".png", "rb"), + 'ACL' => 'public-read' + ]); + + $file->setPreviewLink($result['ObjectURL'] . ""); + $file->setPreviewHasBeenGenerated(true); + $file->setHasPreview(true); + $this->doctrine->persist($file); + $this->doctrine->flush(); + $res = true; + + } catch (S3Exception $e) { + $res = false; + $e->getMessage(); + } + + @unlink($previewpath . ".png"); + //error_log("PREVIEW GENERATED !"); + + } else { + $res = false; + error_log("FILE NOT GENERATED !"); + } + + } catch (\Exception $e) { + + } + + @unlink($tmppath); + + } + + } + return $res; + + } + + public function read($destination, $chunkNo, $param_bag, UploadState $uploadState, &$zip = null, $zip_prefix = null) + { + + $key = "AWS" . $param_bag->getSalt() . $param_bag->getKey(); + if($param_bag->getSalt() == $this->default_parameter_drive_salt){ + $key = "AWS" . $this->parameter_drive_salt . $param_bag->getKey(); + } + $key = md5($key); + + $file_path = "drive/" . $uploadState->getWorkspaceId() . "/" . $uploadState->getIdentifier() . "/" . $chunkNo; + + try { + + $options = [ + 'Bucket' => $this->aws_bucket_name, + 'Key' => $file_path + ]; + + if(!$this->disable_encryption){ + $options = array_merge($options, [ + 'SSECustomerAlgorithm' => 'AES256', + 'SSECustomerKey' => $key, + 'SSECustomerKeyMD5' => md5($key, true) + ]); + } + + $object = $this->aws_s3_client->getObject($options); + + if ($destination == "stream") { + echo $object["Body"]; + return true; + } elseif ($destination == "original_stream") { + $fp = tmpfile(); + fwrite($fp, $object["Body"]); + rewind($fp); + return $fp; + } + + file_put_contents($destination, $object["Body"]); + return $destination; + + } catch (S3Exception $e) { + error_log("Error accessing aws file." . $e); + } + + return false; + } + + public function write($chunkFile, $chunkNo, $param_bag, UploadState $uploadState) + { + + $key = "AWS" . $param_bag->getSalt() . $param_bag->getKey(); + $key = md5($key); + + $file_path = "drive/" . $uploadState->getWorkspaceId() . "/" . $uploadState->getIdentifier() . "/" . $chunkNo; + + try { + + $data = [ + 'Bucket' => $this->aws_bucket_name, + 'Key' => $file_path, + 'Body' => fopen($chunkFile, 'r'), + 'ACL' => 'private' + ]; + + if(!$this->disable_encryption){ + $data = array_merge($data, [ + 'SSECustomerAlgorithm' => 'AES256', + 'SSECustomerKey' => $key, + 'SSECustomerKeyMD5' => md5($key, true) + ]); + } + + // Upload data. + $result = $this->aws_s3_client->putObject($data); + + @unlink($chunkFile); + + } catch (S3Exception $e) { + error_log($e->getMessage() . PHP_EOL); + } + + return $result; + + } + + public function remove(UploadState $uploadState, $chunkNo = 1) + { + + $file_path = "drive/" . $uploadState->getWorkspaceId() . "/" . $uploadState->getIdentifier() . "/" . $chunkNo; + + try { + + $data = [ + 'Bucket' => $this->aws_bucket_name, + 'Key' => $file_path + ]; + + // Upload data. + $result = $this->aws_s3_client->deleteObject($data); + + } catch (S3Exception $e) { + error_log($e->getMessage() . PHP_EOL); + } + + return $result; + + } + + public function streamModeIsAvailable() + { + return false; + } + +} diff --git a/twake/backend/core/src/Twake/Drive/Services/Storage/Adapter_Local.php b/twake/backend/core/src/Twake/Drive/Services/Storage/Adapter_Local.php new file mode 100755 index 00000000..b97720a7 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/Storage/Adapter_Local.php @@ -0,0 +1,259 @@ +<?php + +namespace Twake\Drive\Services\Storage; + +use Twake\Drive\Entity\DriveFile; +use Twake\Drive\Entity\UploadState; +use Twake\Drive\Services\Storage\Encryption\AESCryptFileLib; +use Twake\Drive\Services\Storage\Encryption\MCryptAES256Implementation; +use Twake\Drive\Services\Storage\Encryption\OpenSSLCryptLib; +use Twake\Drive\Services\ZipStream\Exception; + +class Adapter_Local implements AdapterInterface +{ + + protected $root; + protected $preview; + protected $doctrine; + + public function __construct($local_config, $preview, $doctrine) + { + $this->root = $local_config["location"]; + $this->preview_root = $local_config["preview_location"]; + $this->pre_public_path = $local_config["preview_public_path"]; + $this->disable_encryption = $local_config["disable_encryption"]; + $this->preview = $preview; + $this->doctrine = $doctrine; + } + + public function genPreview(Drivefile $file, $tmppath) + { + $res = false; + + try { + + if (!$file->getIsDirectory() && $file->getLastVersion($this->doctrine)) { + + $ext = $file->getExtension(); + + if ($tmppath) { + rename($tmppath, $tmppath . ".tw"); + $tmppath = $tmppath . ".tw"; + + try { + + //Remove old preview + if ($file->hasPreviewLink()) { + try { + $pre_path = $this->preview_root . "/" . "public/uploads/previews/" . $file->getPath() . ".png"; + @unlink($pre_path); + } catch (\Exception $e) { + //error_log($e->getMessage()); + } + } + + try { + $this->preview->generatePreview(basename($file->getPath()), $tmppath, dirname($tmppath), $ext, $file); + } catch (\Exception $e) { + //error_log($e->getMessage()); + } + $previewpath = dirname($tmppath) . "/" . basename($file->getPath()); + if ($previewpath && file_exists($previewpath . ".png")) { + + try { + // Upload data. + $pre_path = $this->preview_root . "/" . "public/uploads/previews/" . $file->getPath() . ".png"; + $this->verifyPath($pre_path); + rename($previewpath . ".png", $pre_path); + + $pre_public_path = $this->pre_public_path . "/" . "public/uploads/previews/" . $file->getPath() . ".png"; + $file->setPreviewLink($pre_public_path . ""); + $file->setPreviewHasBeenGenerated(true); + $file->setHasPreview(true); + $this->doctrine->persist($file); + $this->doctrine->flush(); + $res = true; + + } catch (\Exception $e) { + $res = false; + //error_log($e->getMessage()); + } + @unlink($previewpath . ".png"); + //error_log("PREVIEW GENERATED !"); + + } else { + $res = false; + error_log("FILE NOT GENERATED !"); + } + + } catch (\Exception $e) { + //error_log($e->getMessage()); + } + + @unlink($tmppath); + + } + } + + } catch (\Exception $e) { + //error_log($e->getMessage()); + $res = false; + } + return $res; + + } + + public function verifyPath($path) + { + $path = dirname($path); + error_log($path); + if (!is_dir($path)) { + mkdir($path, 0777, true); + } + } + + public function write($chunkFile, $chunkNo, $param_bag, UploadState $uploadState) + { + $this->encode($chunkFile, $param_bag); + + $chunkFile = $chunkFile . ".encrypt"; + + try { + + $file_path = $this->root . "/" . "drive/" . $uploadState->getWorkspaceId() . "/" . $uploadState->getIdentifier() . "/" . $chunkNo; + $this->verifyPath($file_path); + error_log($chunkFile); + if (file_exists($chunkFile)) { + rename($chunkFile, $file_path); + } else { + return false; + } + + } catch (\Exception $e) { + error_log($e->getMessage() . PHP_EOL); + } + } + + private function encode($chunkFile, $param_bag) + { + + if($this->disable_encryption){ + $pathTemp = $chunkFile . ".encrypt"; + copy($chunkFile, $pathTemp); + return $pathTemp; + } + //error_log(print_r($chunkFile,true)); + + $key = $param_bag->getKey(); + if ($param_bag->getMode() == "AES") { + $mcrypt = new MCryptAES256Implementation(); + $lib = new AESCryptFileLib($mcrypt); + } + if ($param_bag->getMode() == "OpenSSL") { + $lib = new OpenSSLCryptLib(); + } + if ($param_bag->getMode() == "OpenSSL-2") { + $lib = new OpenSSLCryptLib(); + $key = $param_bag->getMode() . $this->parameter_drive_salt . $param_bag->getKey(); + } + + $pathTemp = $chunkFile . ".encrypt"; + + + //rename($path, $pathTemp); + + $finalpath = $lib->encryptFile($chunkFile, $key, $pathTemp); + //error_log(print_r($finalpath,true)); + @unlink($chunkFile); + + return $finalpath; + } + + public function read($destination, $chunkNo, $param_bag, UploadState $uploadState, &$zip = null, $zip_prefix = null) + { + try { + + $file_path = $this->root . "/" . "drive/" . $uploadState->getWorkspaceId() . "/" . $uploadState->getIdentifier() . "/" . $chunkNo; + + $decodedPath = $this->decode($file_path, $param_bag); + + if ($destination == "stream") { + if ($stream = fopen($decodedPath, 'r')) { + // While the stream is still open + while (!feof($stream)) { + // Read 1,024 bytes from the stream + echo fread($stream, 1024); + } + // Be sure to close the stream resource when you're done with it + fclose($stream); + unlink($decodedPath); + } + return true; + } + + if ($destination == "original_stream") { + if ($stream = fopen($decodedPath, 'r')) { + return $stream; + } + } + + return $decodedPath; + + } catch (\Exception $e) { + error_log("Error accessing openstack file."); + } + + return false; + } + + protected function decode($chunkFile, $param_bag) + { + if($this->disable_encryption){ + $pathTemp = $chunkFile . ".decrypt"; + copy($chunkFile, $pathTemp); + return $pathTemp; + } + + $key = $param_bag->getKey(); + if ($param_bag->getMode() == "AES") { + $mcrypt = new MCryptAES256Implementation(); + $lib = new AESCryptFileLib($mcrypt); + } + if ($param_bag->getMode() == "OpenSSL") { + $lib = new OpenSSLCryptLib(); + } + if ($param_bag->getMode() == "OpenSSL-2") { + $lib = new OpenSSLCryptLib(); + $key = $param_bag->getMode() . $this->parameter_drive_salt . $param_bag->getKey(); + } + $pathTemp = $chunkFile . ".decrypt"; + + $finalpath = $lib->decryptFile($chunkFile, $key, $pathTemp); + return $pathTemp; + + } + + public function remove(UploadState $uploadState, $chunkNo = 1) + { + + $file_path = $this->root . "/" . "drive/" . $uploadState->getWorkspaceId() . "/" . $uploadState->getIdentifier() . "/" . $chunkNo; + + try { + + @unlink($file_path); + + } catch (\Exception $e) { + error_log($e->getMessage() . PHP_EOL); + } + + return true; + + } + + public function streamModeIsAvailable() + { + return false; + } + + +} diff --git a/twake/backend/core/src/Twake/Drive/Services/Storage/Adapter_OpenStack.php b/twake/backend/core/src/Twake/Drive/Services/Storage/Adapter_OpenStack.php new file mode 100755 index 00000000..7ab695b2 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/Storage/Adapter_OpenStack.php @@ -0,0 +1,326 @@ +<?php + +namespace Twake\Drive\Services\Storage; + +use GuzzleHttp\Client; +use GuzzleHttp\HandlerStack; +use GuzzleHttp\Psr7\Stream; +use OpenStack\Common\Transport\Utils as TransportUtils; +use OpenStack\Identity\v3\Service; +use OpenStack\OpenStack; +use Twake\Drive\Entity\DriveFile; +use Twake\Drive\Entity\UploadState; +use Twake\Drive\Services\Storage\Encryption\AESCryptFileLib; +use Twake\Drive\Services\Storage\Encryption\MCryptAES256Implementation; +use Twake\Drive\Services\Storage\Encryption\OpenSSLCryptLib; +use Twake\Drive\Services\ZipStream\Exception; + +class Adapter_OpenStack implements AdapterInterface +{ + + protected $openstack; + protected $openstack_buckets; + protected $openstack_buckets_prefix; + protected $openstack_credentials_key; + protected $openstack_credentials_secret; + protected $openstack_project_id; + protected $openstack_auth_url; + protected $openstack_bucket_name; + protected $openstack_public_bucket_name; + protected $openstack_bucket_region; + protected $openstack_region_id; + protected $preview; + protected $doctrine; + + public function __construct($openstack, $preview, $doctrine) + { + + $this->openstack_buckets = $openstack["buckets"]; + $this->openstack_buckets_prefix = $openstack["buckets_prefix"]; + $this->openstack_credentials_key = $openstack["user"]["id"]; + $this->openstack_credentials_secret = $openstack["user"]["password"]; + $this->openstack_domain_name = $openstack["user"]["domain_name"]; + $this->openstack_project_id = $openstack["project_id"]; + $this->openstack_auth_url = $openstack["auth_url"]; + $this->disable_encryption = $openstack["disable_encryption"]; + + $httpClient = new Client([ + 'base_uri' => TransportUtils::normalizeUrl($this->openstack_auth_url ? $this->openstack_auth_url : ""), + 'handler' => HandlerStack::create(), + ]); + + $region = false; + foreach ($this->openstack_buckets as $region_code => $openstack_region) { + if ($region_code == "fr" || !$region) { + if (isset($openstack_region["private"])) { + $region = $openstack_region["private"]; + $public_region = $openstack_region["public"]; + } else { + $region = $openstack_region["public"]; + } + $region_id = $openstack_region["region"]; + } + } + $this->openstack_bucket_name = $this->openstack_buckets_prefix . $region; + $this->openstack_public_bucket_name = $this->openstack_buckets_prefix . $public_region; + $this->openstack_bucket_region = $region; + $this->openstack_region_id = $region_id; + + $this->openstack = new OpenStack([ + 'authUrl' => $this->openstack_auth_url, + 'region' => $this->openstack_region_id, + 'user' => [ + 'name' => $this->openstack_credentials_key, + 'password' => $this->openstack_credentials_secret, + 'domain' => [ 'id' => $this->openstack_domain_name ] + ], + 'scope' => [ + 'project' => [ + 'id' => $this->openstack_project_id + ] + ], + 'identityService' => Service::factory($httpClient) + ]); + + $this->preview = $preview; + $this->doctrine = $doctrine; + + } + + public function genPreview(Drivefile $file, $tmppath) + { + $res = false; + + try { + + if (!$file->getIsDirectory() && $file->getLastVersion($this->doctrine)) { + + $ext = $file->getExtension(); + + if ($tmppath) { + rename($tmppath, $tmppath . ".tw"); + $tmppath = $tmppath . ".tw"; + + try { + + //Remove old preview + if ($file->hasPreviewLink()) { + try { + $this->openstack->objectStoreV1() + ->getContainer($this->openstack_public_bucket_name) + ->getObject("public/uploads/previews/" . $file->getPath() . ".png") + ->delete(); + } catch (\Exception $e) { + //error_log($e->getMessage()); + } + } + + try { + $this->preview->generatePreview(basename($file->getPath()), $tmppath, dirname($tmppath), $ext, $file); + } catch (\Exception $e) { + //error_log($e->getMessage()); + } + $previewpath = dirname($tmppath) . "/" . basename($file->getPath()); + if ($previewpath && file_exists($previewpath . ".png")) { + + try { + // Upload data. + $options = [ + 'name' => "public/uploads/previews/" . $file->getPath() . ".png", + 'stream' => new Stream(fopen($previewpath . ".png", "rb")), + ]; + $result = $this->openstack->objectStoreV1() + ->getContainer($this->openstack_public_bucket_name) + ->createObject($options); + + $file->setPreviewLink($result->getPublicUri() . ""); + $file->setPreviewHasBeenGenerated(true); + $file->setHasPreview(true); + $this->doctrine->persist($file); + $this->doctrine->flush(); + $res = true; + + } catch (\Exception $e) { + $res = false; + //error_log($e->getMessage()); + } + @unlink($previewpath . ".png"); + //error_log("PREVIEW GENERATED !"); + + } else { + $res = false; + error_log("PREVIEW NOT GENERATED !"); + } + + } catch (\Exception $e) { + //error_log($e->getMessage()); + } + + @unlink($tmppath); + + } + } + + } catch (\Exception $e) { + //error_log($e->getMessage()); + $res = false; + } + return $res; + + } + + + public function write($chunkFile, $chunkNo, $param_bag, UploadState $uploadState) + { + $this->encode($chunkFile, $param_bag); + + $chunkFile = $chunkFile . ".encrypt"; + + try { + + $options = [ + 'name' => "drive/" . $uploadState->getWorkspaceId() . "/" . $uploadState->getIdentifier() . "/" . $chunkNo, + 'stream' => new Stream(fopen($chunkFile, 'rb')), + ]; + + $this->openstack->objectStoreV1() + ->getContainer($this->openstack_bucket_name) + ->createObject($options); + + @unlink($chunkFile); + + } catch (\Exception $e) { + error_log($e->getMessage() . PHP_EOL); + } + } + + private function encode($chunkFile, $param_bag) + { + + if($this->disable_encryption){ + $pathTemp = $chunkFile . ".encrypt"; + copy($chunkFile, $pathTemp); + return $pathTemp; + } + + $key = $param_bag->getKey(); + if ($param_bag->getMode() == "AES") { + $mcrypt = new MCryptAES256Implementation(); + $lib = new AESCryptFileLib($mcrypt); + } + if ($param_bag->getMode() == "OpenSSL") { + $lib = new OpenSSLCryptLib(); + } + if ($param_bag->getMode() == "OpenSSL-2") { + $lib = new OpenSSLCryptLib(); + $key = $param_bag->getMode() . $this->parameter_drive_salt . $param_bag->getKey(); + } + + $pathTemp = $chunkFile . ".encrypt"; + + + //rename($path, $pathTemp); + + $finalpath = $lib->encryptFile($chunkFile, $key, $pathTemp); + //error_log(print_r($finalpath,true)); + @unlink($chunkFile); + + return $finalpath; + } + + public function read($destination, $chunkNo, $param_bag, UploadState $uploadState, &$zip = null, $zip_prefix = null) + { + try { + $stream = $this->openstack->objectStoreV1() + ->getContainer($this->openstack_bucket_name) + ->getObject("drive/" . $uploadState->getWorkspaceId() . "/" . $uploadState->getIdentifier() . "/" . $chunkNo) + ->download(); + + $tmp_upload = "/tmp/" . date("U") . $uploadState->getWorkspaceId() . $uploadState->getIdentifier(); + file_put_contents($tmp_upload, $stream->getContents()); + $decodedPath = $this->decode($tmp_upload, $param_bag); + + if ($destination == "stream") { + if ($stream = fopen($decodedPath, 'r')) { + // While the stream is still open + while (!feof($stream)) { + // Read 1,024 bytes from the stream + echo fread($stream, 1024); + } + // Be sure to close the stream resource when you're done with it + fclose($stream); + unlink($decodedPath); + } + return true; + } + + if ($destination == "original_stream") { + if ($stream = fopen($decodedPath, 'r')) { + return $stream; + } + } + + return $decodedPath; + + } catch (\Exception $e) { + error_log("Error accessing openstack file."); + } + + return false; + } + + protected function decode($chunkFile, $param_bag) + { + if($this->disable_encryption){ + $pathTemp = $chunkFile . ".decrypt"; + copy($chunkFile, $pathTemp); + return $pathTemp; + } + + $key = $param_bag->getKey(); + if ($param_bag->getMode() == "AES") { + $mcrypt = new MCryptAES256Implementation(); + $lib = new AESCryptFileLib($mcrypt); + } + if ($param_bag->getMode() == "OpenSSL") { + $lib = new OpenSSLCryptLib(); + } + if ($param_bag->getMode() == "OpenSSL-2") { + $lib = new OpenSSLCryptLib(); + $key = $param_bag->getMode() . $this->parameter_drive_salt . $param_bag->getKey(); + } + $pathTemp = $chunkFile . ".decrypt"; + + $finalpath = $lib->decryptFile($chunkFile, $key, $pathTemp); + @unlink($chunkFile); + return $pathTemp; + + } + + public function remove(UploadState $uploadState, $chunkNo = 1) + { + + $file_path = "drive/" . $uploadState->getWorkspaceId() . "/" . $uploadState->getIdentifier() . "/" . $chunkNo; + + try { + + $this->openstack->objectStoreV1() + ->getContainer($this->openstack_bucket_name) + ->getObject($file_path) + ->delete(); + + } catch (\Exception $e) { + error_log($e->getMessage() . PHP_EOL); + } + + return $result; + + } + + public function streamModeIsAvailable() + { + return false; + } + + +} diff --git a/twake/backend/core/src/Twake/Drive/Services/Storage/Encryption/AES256Implementation.php b/twake/backend/core/src/Twake/Drive/Services/Storage/Encryption/AES256Implementation.php new file mode 100755 index 00000000..ce0e2961 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/Storage/Encryption/AES256Implementation.php @@ -0,0 +1,16 @@ +<?php + +namespace Twake\Drive\Services\Storage\Encryption; + +interface AES256Implementation +{ + public function checkDependencies(); + + public function createIV(); + + public function createRandomKey(); + + public function encryptData($the_data, $iv, $enc_key); + + public function decryptData($the_data, $iv, $enc_key); +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Services/Storage/Encryption/AESCryptFileLib.php b/twake/backend/core/src/Twake/Drive/Services/Storage/Encryption/AESCryptFileLib.php new file mode 100755 index 00000000..94e0b9a0 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/Storage/Encryption/AESCryptFileLib.php @@ -0,0 +1,660 @@ +<?php + +namespace Twake\Drive\Services\Storage\Encryption; + +use Exception; + +/** + * Please see https://www.aescrypt.com/aes_file_format.html + * for the file format used. + * + */ +class AESCryptFileLib +{ + const ENCRYPTED_FILE_EXTENSION = "aes"; + + //http://www.leaseweblabs.com/2014/02/aes-php-mcrypt-key-padding/ + //Only "Rijndael-128" in "Cipher-block chaining" (CBC) mode is defined as the Advanced Encryption Standard (AES). + //The file format specifies IV length of 128 bits (the block length) and key length of 256 bits + //These are assumed to be implemented properly in all AES256 interfaces + private $aes_impl; + + private $use_dynamic_filenaming; + + private $debugging = false; + + public function __construct(AES256Implementation $aes_impl, $use_dynamic_filenaming = true) + { + $this->aes_impl = $aes_impl; + $this->use_dynamic_filenaming = $use_dynamic_filenaming; + + try { + $this->aes_impl->checkDependencies(); + } catch (\Exception $e) { + throw new AESCryptMissingDependencyException($e->getMessage()); + } + } + + public function enableDebugging() + { + $this->debugging = true; + } + + public function encryptFile($source_file, $passphrase, $dest_file = NULL, $ext_data = NULL) + { + //Check we can read the source file + $this->checkSourceExistsAndReadable($source_file); + + //Check any ext_data is formatted correctly + $this->checkExtensionData($ext_data); + + //Check that the password is a string (it cannot be NULL) + $this->checkPassphraseIsValid($passphrase); + + //Actually do the encryption here + $dest_fh = $this->doEncryptFile($source_file, $passphrase, $dest_file, $ext_data); +// error_log(print_r($dest_fh,true)); + + //Return encrypted file location + $meta_data = stream_get_meta_data($dest_fh); +// error_log(print_r($meta_data,true)); + fclose($dest_fh); + $filename = realpath($meta_data["uri"]); + return $filename; + } + + private function checkSourceExistsAndReadable($source_file) + { + //Source file must exist + if (!file_exists($source_file)) { + throw new AESCryptFileMissingException($source_file); + } + + //Source file must be readable + if (!is_readable($source_file)) { + throw new AESCryptFileAccessException("Cannot read: " . $source_file); + } + } + + private function checkExtensionData($ext_data) + { + if ($ext_data === NULL) { + return; + } + if (!is_array($ext_data)) { + throw new AESCryptInvalidExtensionException("Must be NULL or an array (containing 'extension block' arrays)"); + } + + //Ignore associative arrays + $ext_data = array_values($ext_data); + + $unique_identifiers = array(); + foreach ($ext_data as $index => $eb) { + if (!is_array($eb)) { + throw new AESCryptInvalidExtensionException("Extension block at index {$index} must be an array"); + } + //Each block must contain the array keys 'identifier' and 'contents' + if (!array_key_exists("identifier", $eb)) { + throw new AESCryptInvalidExtensionException("Extension block at index {$index} must contain the key 'identifier'"); + } + if (!array_key_exists("contents", $eb)) { + throw new AESCryptInvalidExtensionException("Extension block at index {$index} must contain the key 'contents'"); + } + + $identifier = $eb['identifier']; + $contents = $eb['contents']; + if (!is_string($identifier)) { + throw new AESCryptInvalidExtensionException("Extension block at index {$index} has a bad 'identifier' value. It must be a string."); + } + if (!is_string($contents)) { + throw new AESCryptInvalidExtensionException("Extension block at index {$index} has a bad 'contents' value. It must be a string."); + } + + if (in_array($identifier, $unique_identifiers)) { + throw new AESCryptInvalidExtensionException("Extension block at index {$index} contains an 'identifier' which has already been used. Make sure they are unique."); + } else { + $unique_identifiers[] = $identifier; + } + } + } + + private function checkPassphraseIsValid($passphrase) + { + if ($passphrase === NULL) { + throw new AESCryptInvalidPassphraseException("NULL passphrase not allowed"); + } + } + + private function doEncryptFile($source_file, $passphrase, $dest_file, $ext_data) + { + $this->debug("ENCRYPTION", "Started"); + + $header = "AES"; + $header .= pack("H*", "02"); //Version + $header .= pack("H*", "00"); //Reserved + + //Generate the extension data + $extdat_binary = $this->getBinaryExtensionData($ext_data); + + //Create a random IV using the aes implementation + //IV is based on the block size which is 128 bits (16 bytes) for AES + $iv_1 = $this->aes_impl->createIV(); + if (self::bin_strlen($iv_1) != 16) { + throw new AESCryptImplementationException("Returned an IV which is not 16 bytes long: " . bin2hex($iv_1)); + } + $this->debug("IV1", bin2hex($iv_1)); + + //Use this IV and password to generate the first encryption key + //We dont need to use AES for this as its just lots of sha hashing + $passphrase = iconv(mb_internal_encoding(), 'UTF-16LE', $passphrase); + $this->debug("PASSPHRASE", $passphrase); + $enc_key_1 = $this->createKeyUsingIVAndPassphrase($iv_1, $passphrase); + if (self::bin_strlen($enc_key_1) != 32) { + throw new \Exception("Returned a passphrase which is not 32 bytes long: " . bin2hex($enc_key_1)); + } + $this->debug("KEY1", bin2hex($enc_key_1)); + + //Create another set of keys to do the actual file encryption + $iv_2 = $this->aes_impl->createIV(); + if (self::bin_strlen($iv_2) != 16) { + throw new AESCryptImplementationException("Returned an IV which is not 16 bytes long: " . bin2hex($iv_2)); + } + $this->debug("IV2", bin2hex($iv_2)); + + //The file format uses AES 256 (which is the key length) + $enc_key_2 = $this->aes_impl->createRandomKey(); + if (self::bin_strlen($enc_key_2) != 32) { + throw new AESCryptImplementationException("Returned a random key which is not 32 bytes long: " . bin2hex($enc_key_2)); + } + $this->debug("KEY2", bin2hex($enc_key_2)); + + //Encrypt the second set of keys using the first keys + $file_encryption_keys = $iv_2 . $enc_key_2; + + $encrypted_keys = $this->aes_impl->encryptData($file_encryption_keys, $iv_1, $enc_key_1); + if (self::bin_strlen($encrypted_keys) != 48) { + throw new \Exception("Assertion 1 failed"); + } + $this->debug("ENCRYPTED KEYS", bin2hex($encrypted_keys)); + //$this->assertLength($encrypted_keys, 48); + + //Calculate HMAC1 using the first enc key + $hmac_1 = hash_hmac("sha256", $encrypted_keys, $enc_key_1, true); + if (self::bin_strlen($hmac_1) != 32) { + throw new \Exception("Assertion 2 failed"); + } + $this->debug("HMAC 1", bin2hex($hmac_1)); + //$this->assertLength($hmac_1, 32); + + //Now do file encryption + $source_contents = file_get_contents($source_file); + $encrypted_file_data = $this->aes_impl->encryptData($source_contents, $iv_2, $enc_key_2); + + $file_size_modulo = pack("C", self::bin_strlen($source_contents) % 16); + + $this->debug("FS MODULO", bin2hex($file_size_modulo)); + + //HMAC the encrypted data too + $this->debug("MD5 of ENC DATA", md5($encrypted_file_data)); + $hmac_2 = hash_hmac("sha256", $encrypted_file_data, $enc_key_2, true); + + $this->debug("HMAC2", bin2hex($hmac_2)); + + //Actaully write it to the dest fh + $enc_data = $header . $extdat_binary . $iv_1 . $encrypted_keys . $hmac_1 . $encrypted_file_data . $file_size_modulo . $hmac_2; + + //Open destination file for writing + $dest_fh = $this->openDestinationFile($source_file, $dest_file, true); + $written = fwrite($dest_fh, $enc_data); + if ($written === false) { + throw new AESCryptFileAccessException("Could not write encrypted data to file. Tried to write " . self::bin_strlen($enc_data) . " bytes"); + } + $this->debug("ENCRYPTION", "Complete"); + + return $dest_fh; + } + + private function debug($name, $msg) + { + if ($this->debugging) { + echo "<br/>"; + echo $name . " - " . $msg; + echo "<br/>"; + } + } + + private function getBinaryExtensionData($ext_data) + { + $this->checkExtensionData($ext_data); + + if ($ext_data === NULL) { + $ext_data = array(); + } + + $output = ""; + foreach ($ext_data as $ext) { + $ident = $ext['identifier']; + $contents = $ext['contents']; + $data = $ident . pack("C", 0) . $contents; + $output .= pack("n", self::bin_strlen($data)); + $output .= $data; + } + + //Also insert a 128 byte container + $data = str_repeat(pack("C", 0), 128); + $output .= pack("n", self::bin_strlen($data)); + $output .= $data; + + //2 finishing NULL bytes to signify end of extensions + $output .= pack("C", 0); + $output .= pack("C", 0); + return $output; + } + + public static function bin_strlen($string) + { + if (function_exists('mb_strlen')) { + return mb_strlen($string, '8bit'); + } else { + return strlen($string); + } + } + + private function createKeyUsingIVAndPassphrase($iv, $passphrase) + { + //Start with the IV padded to 32 bytes + $aes_key = str_pad($iv, 32, hex2bin("00")); + $iterations = 8192; + for ($i = 0; $i < $iterations; $i++) { + $hash = hash_init("sha256"); + hash_update($hash, $aes_key); + hash_update($hash, $passphrase); + $aes_key = hash_final($hash, true); + } + return $aes_key; + } + + private function openDestinationFile($source_file, $dest_file, $encrypting = true) + { + + //Please use checkSourceExistsAndReadable on the source before running this function as we assume it exists here + $source_info = pathinfo($source_file); + + if ($dest_file === NULL) { + if (!$encrypting) { + //We are decrypting without a known destination file + //We should check for a double extension in the file name e.g. (filename.docx.aes) + //Actually, we just check it ends with .aes and strip off the rest + if (preg_match("/^(.+)\." . self::ENCRYPTED_FILE_EXTENSION . "$/i", $source_info['basename'], $matches)) { + //Yes, source is an .aes file + //We remove the .aes part and use a destination file in the same source directory + $dest_file = $source_info['dirname'] . DIRECTORY_SEPARATOR . $matches[1]; + } else { + throw new AESCryptCannotInferDestinationException($source_file); + } + + } else { + //We are encrypting, use .aes as destination file extension + $dest_file = $source_file . "." . self::ENCRYPTED_FILE_EXTENSION; + } + } + + if ($this->use_dynamic_filenaming) { + //Try others until it doesnt exist + $dest_info = pathinfo($dest_file); + + $duplicate_id = 1; + while (file_exists($dest_file)) { + //Check the destination file doesn't exist (We never overwrite) + $dest_file = $dest_info['dirname'] . DIRECTORY_SEPARATOR . $dest_info['filename'] . "({$duplicate_id})." . $dest_info['extension']; + $duplicate_id++; + } + } else { + if (file_exists($dest_file)) { + throw new AESCryptFileExistsException($dest_file); + } + } + + //Now that we found a non existing file, attempt to open it for writing + $dest_fh = fopen($dest_file, "xb"); + if ($dest_fh === false) { + throw new AESCryptFileAccessException("Cannot create for writing:" . $dest_file); + } + + return $dest_fh; + } + + //Converts the given extension data in to binary data + + public function readExtensionBlocks($source_file) + { + //Check we can read the source file + $this->checkSourceExistsAndReadable($source_file); + + //Attempt to parse and return the extension blocks only + //Open the file + $source_fh = fopen($source_file, "rb"); + if ($source_fh === false) { + throw new AESCryptFileAccessException("Cannot open file for reading: " . $source_file); + } + + $this->readChunk($source_fh, 3, "file header", NULL, "AES"); + $version_chunk = $this->readChunk($source_fh, 1, "version byte", "C"); + $extension_blocks = array(); + if (bin2hex($version_chunk) === dechex(ord("0"))) { + //This file uses version 0 of the standard + //Extension blocks dont exist in this versions spec + $extension_blocks = NULL; + } else if (bin2hex($version_chunk) === dechex(ord("1"))) { + //This file uses version 1 of the standard + //Extension blocks dont exist in this versions spec + $extension_blocks = NULL; + } else if (bin2hex($version_chunk) === dechex(ord("2"))) { + + //This file uses version 2 of the standard (The latest standard at the time of writing) + $this->readChunk($source_fh, 1, "reserved byte", "C", 0); + $eb_index = 0; + while (true) { + //Read ext length + $ext_length = $this->readChunk($source_fh, 2, "extension length", "n"); + if ($ext_length == 0) { + break; + } else { + $ext_content = $this->readChunk($source_fh, $ext_length, "extension content"); + + //Find the first NULL splitter character + $null_index = self::bin_strpos($ext_content, "\x00"); + if ($null_index === false) { + throw new AESCryptCorruptedFileException("Extension block data at index {$eb_index} has no null splitter byte: " . $source_file); + } + + $identifier = self::bin_substr($ext_content, 0, $null_index); + $contents = self::bin_substr($ext_content, $null_index + 1); + + if ($identifier != "") { + $extension_blocks[$eb_index] = array( + "identifier" => $identifier, + "contents" => $contents + ); + $eb_index++; + } + } + } + } else { + throw new AESCryptCorruptedFileException("Unknown version: " . bin2hex($version_chunk)); + } + return $extension_blocks; + } + + //This is sha256 by standard and should always returns 256bits (32 bytes) of hash data + //Looking at the java implementation, it seems we should iterate the hasing 8192 times + + private function readChunk($source_fh, $num_bytes, $chunk_name, $unpack_format = NULL, $expected_value = NULL) + { + $read_data = fread($source_fh, $num_bytes); + if ($read_data === false) { + throw new AESCryptFileAccessException("Could not read chunk " . $chunk_name . " of " . $num_bytes . " bytes"); + } + + if (self::bin_strlen($read_data) != $num_bytes) { + throw new AESCryptCorruptedFileException("Could not read chunk " . $chunk_name . " of " . $num_bytes . " bytes, only found " . self::bin_strlen($read_data) . " bytes"); + } + + if ($unpack_format !== NULL) { + $read_data = unpack($unpack_format, $read_data); + if (is_array($read_data)) { + $read_data = $read_data[1]; + } + } + + + if ($expected_value !== NULL) { + if ($read_data !== $expected_value) { + throw new AESCryptCorruptedFileException("The chunk " . $chunk_name . " was expected to be " . bin2hex($expected_value) . " but found " . bin2hex($read_data)); + } + } + return $read_data; + } + + public static function bin_strpos($haystack, $needle, $offset = 0) + { + if (function_exists('mb_strpos')) { + return mb_strpos($haystack, $needle, $offset, '8bit'); + } else { + return strpos($haystack, $needle, $offset); + } + } + + public static function bin_substr($string, $start, $length = NULL) + { + if (function_exists('mb_substr')) { + return mb_substr($string, $start, $length, '8bit'); + } else { + return substr($string, $start, $length); + } + } + + //http://php.net/manual/en/mbstring.overload.php + //String functions which may be overloaded are: mail, strlen, strpos, strrpos, substr, + //strtolower, strtoupper, stripos, strripos, strstr, stristr, strrchr, + //substr_count, ereg, eregi, ereg_replace, eregi_replace, split + // + //Since we use some of these str_ php functions to manipulate binary data, + //to prevent accidental multibyte string functions thinking binary data is a + //multibyte string and breaking the engine, we use the 8bit mode + //with the mb_ equivalents if they exist. + + //Functions we use and so must wrap: strlen, strpos, substr + + public function decryptFile($source_file, $passphrase, $dest_file = NULL) + { + //Check we can read the source file + $this->checkSourceExistsAndReadable($source_file); + + //Check whether the passphrase is correct before decrypting the keys and validating with HMAC1 + //If it is, attempt to decrypt the file using these keys and write to destination file + $dest_fh = $this->doDecryptFile($source_file, $passphrase, $dest_file); + + //Return encrypted file location + $meta_data = stream_get_meta_data($dest_fh); + fclose($dest_fh); + $filename = realpath($meta_data["uri"]); + return $filename; + } + + private function doDecryptFile($source_file, $passphrase, $dest_file) + { + $this->debug("DECRYPTION", "Started"); + + //Check we can read the source file + $this->checkSourceExistsAndReadable($source_file); + + //Attempt to parse and return the extension blocks only + //Open the file + $source_fh = fopen($source_file, "rb"); + if ($source_fh === false) { + throw new AESCryptFileAccessException("Cannot open file for reading: " . $source_file); + } + + $this->readChunk($source_fh, 3, "file header", NULL, "AES"); + $version_chunk = $this->readChunk($source_fh, 1, "version byte", "C"); + $extension_blocks = array(); + if ($version_chunk === 0) { + //This file uses version 0 of the standard + $file_size_modulos = $this->readChunk($source_fh, 1, "file size modulo", "C", 0); + if ($file_size_modulos === false) { + throw new \Exception("Could not decode file size modulos"); + } + if ($file_size_modulos < 0 || $file_size_modulos >= 16) { + throw new \Exception("Invalid file size modulos: " . $file_size_modulos); + } + + $iv = $this->readChunk($source_fh, 16, "IV"); + + $rest_of_data = ""; + while (!feof($source_fh)) { + $rest_of_data .= fread($source_fh, 8192); //Read in 8K chunks + } + $encrypted_data = self::bin_substr($rest_of_data, 0, -32); + $hmac = self::bin_substr($rest_of_data, -32, 32); + + //Convert the passphrase to UTF-16LE + $passphrase = iconv(mb_internal_encoding(), 'UTF-16LE', $passphrase); + $this->debug("PASSPHRASE", bin2hex($passphrase)); + $enc_key = $this->createKeyUsingIVAndPassphrase($iv, $passphrase); + $this->debug("ENCKEYFROMPASSWORD", bin2hex($enc_key)); + + //We simply use this enc key to decode the payload + //We do not know if it is correct yet until we finish decrypting the data + + $decrypted_data = $this->aes_impl->decryptData($encrypted_data, $iv, $enc_key); + if ($file_size_modulos > 0) { + $decrypted_data = self::bin_substr($decrypted_data, 0, ((16 - $file_size_modulos) * -1)); + } + + //Here the HMAC is (probably) used to verify the decrypted data + $this->validateHMAC($enc_key, $decrypted_data, $hmac, "HMAC"); + + //Open destination file for writing + $dest_fh = $this->openDestinationFile($source_file, $dest_file, false); + + $result = fwrite($dest_fh, $decrypted_data); + if ($result === false) { + throw new \Exception("Could not write back file"); + } + if ($result != self::bin_strlen($decrypted_data)) { + throw new \Exception("Could not write back file"); + } + $this->debug("DECRYPTION", "Completed"); + return $dest_fh; + + } else if ($version_chunk === 1 || $version_chunk === 2) { + if ($version_chunk === 1) { + //This file uses version 1 of the standard + $this->readChunk($source_fh, 1, "reserved byte", "C", 0); + } else if ($version_chunk === 2) { + //This file uses version 2 of the standard (The latest standard at the time of writing) + $this->readChunk($source_fh, 1, "reserved byte", "C", 0); + while (true) { + //Read ext length + $ext_length = $this->readChunk($source_fh, 2, "extension length", "n"); + if ($ext_length == 0) { + break; + } else { + $this->readChunk($source_fh, $ext_length, "extension content"); + } + } + } + + $iv_1 = $this->readChunk($source_fh, 16, "IV 1"); + $this->debug("IV1", bin2hex($iv_1)); + $enc_keys = $this->readChunk($source_fh, 48, "Encrypted Keys"); + $this->debug("ENCRYPTED KEYS", bin2hex($enc_keys)); + $hmac_1 = $this->readChunk($source_fh, 32, "HMAC 1"); + $this->debug("HMAC1", bin2hex($hmac_1)); + + //Convert the passphrase to UTF-16LE + $passphrase = iconv(mb_internal_encoding(), 'UTF-16LE', $passphrase); + $this->debug("PASSPHRASE", bin2hex($passphrase)); + $enc_key_1 = $this->createKeyUsingIVAndPassphrase($iv_1, $passphrase); + $this->debug("ENCKEY1FROMPASSWORD", bin2hex($enc_key_1)); + + $this->validateHMAC($enc_key_1, $enc_keys, $hmac_1, "HMAC 1"); + + + $rest_of_data = ""; + while (!feof($source_fh)) { + $rest_of_data .= fread($source_fh, 8192); //Read in 8K chunks + } + + $encrypted_data = self::bin_substr($rest_of_data, 0, -33); + $file_size_modulos = unpack("C", self::bin_substr($rest_of_data, -33, 1)); + $file_size_modulos = $file_size_modulos[1]; + if ($file_size_modulos === false) { + throw new \Exception("Could not decode file size modulos"); + } + if ($file_size_modulos < 0 || $file_size_modulos >= 16) { + throw new \Exception("Invalid file size modulos: " . $file_size_modulos); + } + + $hmac_2 = self::bin_substr($rest_of_data, -32); + $this->debug("HMAC2", bin2hex($hmac_2)); + + $decrypted_keys = $this->aes_impl->decryptData($enc_keys, $iv_1, $enc_key_1); + $this->debug("DECRYPTED_KEYS", bin2hex($decrypted_keys)); + + $iv_2 = self::bin_substr($decrypted_keys, 0, 16); + $enc_key_2 = self::bin_substr($decrypted_keys, 16); + + $this->debug("MD5 of ENC DATA", md5($encrypted_data)); + + $this->validateHMAC($enc_key_2, $encrypted_data, $hmac_2, "HMAC 2"); + //All keys were correct, we can be sure that the decrypted data will be correct + $decrypted_data = $this->aes_impl->decryptData($encrypted_data, $iv_2, $enc_key_2); + //Modulos tells us how many bytes to trim from the end + if ($file_size_modulos > 0) { + $decrypted_data = self::bin_substr($decrypted_data, 0, ((16 - $file_size_modulos) * -1)); + } + + //Open destination file for writing + $dest_fh = $this->openDestinationFile($source_file, $dest_file, false); + + $result = fwrite($dest_fh, $decrypted_data); + if ($result === false) { + throw new \Exception("Could not write back file"); + } + if ($result != self::bin_strlen($decrypted_data)) { + throw new \Exception("Could not write back file"); + } + $this->debug("DECRYPTION", "Completed"); + return $dest_fh; + } else { + throw new \Exception("Invalid version chunk: " . $version_chunk); + } + throw new \Exception("Not implemented"); + } + + private function validateHMAC($key, $data, $hash, $name) + { + $calculated = hash_hmac("sha256", $data, $key, true); + $actual = $hash; + if ($calculated != $actual) { + $this->debug("CALCULATED", bin2hex($calculated)); + $this->debug("ACTUAL", bin2hex($actual)); + if ($name == "HMAC 1") { + throw new AESCryptInvalidPassphraseException("{$name} failed to validate integrity of encryption keys. Incorrect password or file corrupted."); + } else { + throw new AESCryptCorruptedFileException("{$name} failed to validate integrity of encrypted data. The file is corrupted and should not be trusted."); + } + } + } + +} + +class AESCryptMissingDependencyException extends \Exception +{ +} //E.g. missing mcrypt +class AESCryptCorruptedFileException extends \Exception +{ +} //E.g. when file looks corrupted or wont parse +class AESCryptFileMissingException extends \Exception +{ +} //E.g. cant read file to encrypt +class AESCryptFileAccessException extends \Exception +{ +} //E.g. read/write error on files +class AESCryptFileExistsException extends \Exception +{ +} //E.g. when a destination file exists (we never overwrite) +class AESCryptInvalidExtensionException extends \Exception +{ +} //E.g. when an extension array is invalid +class AESCryptInvalidPassphraseException extends \Exception +{ +} //E.g. when the password is wrong +class AESCryptCannotInferDestinationException extends \Exception +{ +} //E.g. when we try to decrypt a 3rd party written file which doesnt have the standard file name convention +class AESCryptImplementationException extends \Exception +{ +} //For generic \Exceptions by the aes implementation used \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Services/Storage/Encryption/MCryptAES256Implementation.php b/twake/backend/core/src/Twake/Drive/Services/Storage/Encryption/MCryptAES256Implementation.php new file mode 100755 index 00000000..70cfdafd --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/Storage/Encryption/MCryptAES256Implementation.php @@ -0,0 +1,45 @@ +<?php + +namespace Twake\Drive\Services\Storage\Encryption; + +class MCryptAES256Implementation implements AES256Implementation +{ + const BLOCK_SIZE = 16; // 128 bits + const KEY_SIZE = 32; // 256 bits + const MY_MCRYPT_CIPHER = MCRYPT_RIJNDAEL_128; //AES + const MY_MCRYPT_MODE = MCRYPT_MODE_CBC; //AES + + public function checkDependencies() + { + $function_list = array( + "mcrypt_create_iv", + "mcrypt_encrypt", + "mcrypt_decrypt", + ); + foreach ($function_list as $func) { + if (!function_exists($func)) { + throw new \Exception("Missing function dependency: " . $func); + } + } + } + + public function createIV() + { + return mcrypt_create_iv(self::BLOCK_SIZE, MCRYPT_RAND); + } + + public function createRandomKey() + { + return mcrypt_create_iv(self::KEY_SIZE, MCRYPT_RAND); + } + + public function encryptData($the_data, $iv, $enc_key) + { + return mcrypt_encrypt(self::MY_MCRYPT_CIPHER, $enc_key, $the_data, self::MY_MCRYPT_MODE, $iv); + } + + public function decryptData($the_data, $iv, $enc_key) + { + return mcrypt_decrypt(self::MY_MCRYPT_CIPHER, $enc_key, $the_data, self::MY_MCRYPT_MODE, $iv); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Services/Storage/Encryption/OpenSSLCryptLib.php b/twake/backend/core/src/Twake/Drive/Services/Storage/Encryption/OpenSSLCryptLib.php new file mode 100755 index 00000000..359a76e0 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/Storage/Encryption/OpenSSLCryptLib.php @@ -0,0 +1,48 @@ +<?php + +namespace Twake\Drive\Services\Storage\Encryption; + +class OpenSSLCryptLib +{ + public function decryptFile($in, $key, $out) + { + + $key = md5($key); + + if ($out != $in) { + $temp = $out; + } else { + $temp = $in . ".tmp"; + } + + $iv = bin2hex(substr($key, 0, openssl_cipher_iv_length('aes-256-cbc') / 2)); + + shell_exec('openssl enc -aes-256-cbc -base64 -d -A -p -K ' . $key . ' -iv ' . $iv . ' -in ' . $in . ' -out ' . $temp); + + if ($out == $in) { + rename($in . ".tmp", $out); + } + + } + + public function encryptFile($in, $key, $out) + { + + $key = md5($key); + + if ($out != $in) { + $temp = $out; + } else { + $temp = $in . ".tmp"; + } + + $iv = bin2hex(substr($key, 0, openssl_cipher_iv_length('aes-256-cbc') / 2)); + + shell_exec('openssl enc -aes-256-cbc -base64 -e -A -p -K ' . $key . ' -iv ' . $iv . ' -in ' . $in . ' -out ' . $temp); + + if ($out == $in) { + rename($in . ".tmp", $out); + } + + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Services/Storage/EncryptionBag.php b/twake/backend/core/src/Twake/Drive/Services/Storage/EncryptionBag.php new file mode 100755 index 00000000..a9e071c6 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/Storage/EncryptionBag.php @@ -0,0 +1,68 @@ +<?php + +namespace Twake\Drive\Services\Storage; + +class EncryptionBag +{ + + private $salt; + private $key; + private $mode; + + public function __construct($key, $salt = "", $mode = "OpenSSL-2") + { + $this->salt = $salt; + $this->key = $key; + $this->mode = $mode; + } + + /** + * @return mixed + */ + public function getSalt() + { + return $this->salt; + } + + /** + * @param mixed $salt + */ + public function setSalt($salt) + { + $this->salt = $salt; + } + + /** + * @return mixed + */ + public function getKey() + { + return $this->key; + } + + /** + * @param mixed $key + */ + public function setKey($key) + { + $this->key = $key; + } + + /** + * @return mixed + */ + public function getMode() + { + return $this->mode; + } + + /** + * @param mixed $mode + */ + public function setMode($mode) + { + $this->mode = $mode; + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Services/Storage/StorageManager.php b/twake/backend/core/src/Twake/Drive/Services/Storage/StorageManager.php new file mode 100755 index 00000000..1c8c90bd --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/Storage/StorageManager.php @@ -0,0 +1,74 @@ +<?php + +namespace Twake\Drive\Services\Storage; + +use App\App; + +class StorageManager +{ + + private $storage; + private $root; + private $doctrine; + + public function __construct(App $app) + { + $this->storage = $app->getContainer()->getParameter("storage"); + $this->root = $app->getAppRootDir(); + $this->preview = $app->getServices()->get("app.drive.preview"); + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->app = $app; + } + + /** + * @return mixed + */ + public function getAdapter($provider = false) + { + //Prod retro-compatibility + if($this->getProviderConfiguration("")["label"] === ""){ + $provider = $provider ?: ""; + } + + $configuration = $this->getProviderConfiguration($provider); + $configuration["default_drive_salt"] = $this->app->getContainer()->getParameter("storage.drive_salt"); + + if ($configuration["type"] === "S3") { + return new Adapter_AWS($configuration, $this->preview, $this->doctrine); + } elseif ($configuration["type"] === "openstack") { + return new Adapter_OpenStack($configuration, $this->preview, $this->doctrine); + } + return new Adapter_Local($configuration, $this->preview, $this->doctrine); + } + + public function getProviderConfiguration($provider = false){ + $defaultProvider = $this->getOneProvider(); + $provider = $provider === false ? $defaultProvider : $provider; + $configuration = ""; + foreach($this->storage["providers"] as $providerConfiguration){ + if((!$configuration && $providerConfiguration["label"] == $defaultProvider) + || ($providerConfiguration["label"] == $provider)){ + $configuration = $providerConfiguration; + } + } + return $configuration; + } + + /** + * Choose a provider in the available providers + */ + public function getOneProvider(){ + $candidates = []; + + foreach($this->storage["providers"] as $provider){ + if($provider["use"]){ + $candidates[] = $provider["label"]; + } + } + + shuffle($candidates); + + return $candidates[0] ?: null; + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Services/UploadFile.php b/twake/backend/core/src/Twake/Drive/Services/UploadFile.php new file mode 100755 index 00000000..ff67f030 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/UploadFile.php @@ -0,0 +1,63 @@ +<?php + +namespace Twake\Drive\Services; + +use App\App; +use http\Client\Response; +use Twake\Drive\Services\Resumable\Network\SimpleRequest; +use Twake\Drive\Services\Resumable\Network\SimpleResponse; + +class UploadFile +{ + private $resumable; + + public function __construct(App $app) + { + $this->resumable = $app->getServices()->get("driveupload.resumable"); + } + + public function preprocess($request, $current_user_id) + { + $workspace_id = $request->request->get("workspace_id", ""); + $name = $request->request->all()["name"]; + $extension = $request->request->all()["extension"]; + return $this->resumable->createObject($workspace_id, $name, $extension, $current_user_id); + } + + public function upload($request, $response, $current_user_id) + { + $request = new SimpleRequest($request); + $response = new SimpleResponse($response); + $this->resumable->updateParam($request, $response); + $res = $this->resumable->process($current_user_id); + if (is_array($res)) { + return $res; + } + } + + public function uploadDirectly($file_or_url, $object, $options, $current_user_id) + { + $workspace_id = $object["workspace_id"]; + $name = $object["name"]; + if (!isset($object["extension"]) || !$object["extension"]) { + preg_match("/(.*)(\.[a-zA-Z0-9]+)+$/i", $name, $matches); + $extension = isset($matches[2]) ? $matches[2] : ""; + } else { + $extension = $object["extension"]; + } + + $identifier = $this->resumable->createObject($workspace_id, $name, $extension, $current_user_id); + + if ($identifier) { + $res = $this->resumable->handleChunk($file_or_url, $object["name"], 0, $identifier, 1, 1, $object, $options); + if (is_array($res)) { + return $res; + } + } + + return null; + + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/Bigint.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Bigint.php new file mode 100755 index 00000000..6989c576 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Bigint.php @@ -0,0 +1,172 @@ +<?php +declare(strict_types=1); + +namespace Twake\Drive\Services\ZipStream; + +use OverflowException; + +class Bigint +{ + /** + * @var int[] + */ + private $bytes = [0, 0, 0, 0, 0, 0, 0, 0]; + + /** + * Initialize the bytes array + * + * @param int $value + */ + public function __construct(int $value = 0) + { + $this->fillBytes($value, 0, 8); + } + + /** + * Fill the bytes field with int + * + * @param int $value + * @param int $start + * @param int $count + * @return void + */ + protected function fillBytes(int $value, int $start, int $count): void + { + for ($i = 0; $i < $count; $i++) { + $this->bytes[$start + $i] = $i >= PHP_INT_SIZE ? 0 : $value & 0xFF; + $value >>= 8; + } + } + + /** + * Get an instance + * + * @param int $value + * @return Bigint + */ + public static function init(int $value = 0): self + { + return new self($value); + } + + /** + * Fill bytes from low to high + * + * @param int $low + * @param int $high + * @return Bigint + */ + public static function fromLowHigh(int $low, int $high): self + { + $bigint = new Bigint(); + $bigint->fillBytes($low, 0, 4); + $bigint->fillBytes($high, 4, 4); + return $bigint; + } + + /** + * Get high 32 + * + * @return int + */ + public function getHigh32(): int + { + return $this->getValue(4, 4); + } + + /** + * Get value from bytes array + * + * @param int $end + * @param int $length + * @return int + */ + public function getValue(int $end = 0, int $length = 8): int + { + $result = 0; + for ($i = $end + $length - 1; $i >= $end; $i--) { + $result <<= 8; + $result |= $this->bytes[$i]; + } + return $result; + } + + /** + * Get low FF + * + * @param bool $force + * @return int + */ + public function getLowFF(bool $force = false): int + { + if ($force || $this->isOver32()) { + return 0xFFFFFFFF; + } + return $this->getLow32(); + } + + /** + * Check if is over 32 + * + * @param bool $force + * @return bool + */ + public function isOver32(bool $force = false): bool + { + // value 0xFFFFFFFF already needs a Zip64 header + return $force || + max(array_slice($this->bytes, 4, 4)) > 0 || + min(array_slice($this->bytes, 0, 4)) === 0xFF; + } + + /** + * Get low 32 + * + * @return int + */ + public function getLow32(): int + { + return $this->getValue(0, 4); + } + + /** + * Get hexadecimal + * + * @return string + */ + public function getHex64(): string + { + $result = '0x'; + for ($i = 7; $i >= 0; $i--) { + $result .= sprintf('%02X', $this->bytes[$i]); + } + return $result; + } + + /** + * Add + * + * @param Bigint $other + * @return Bigint + */ + public function add(Bigint $other): Bigint + { + $result = clone $this; + $overflow = false; + for ($i = 0; $i < 8; $i++) { + $result->bytes[$i] += $other->bytes[$i]; + if ($overflow) { + $result->bytes[$i]++; + $overflow = false; + } + if ($result->bytes[$i] & 0x100) { + $overflow = true; + $result->bytes[$i] &= 0xFF; + } + } + if ($overflow) { + throw new OverflowException; + } + return $result; + } +} diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/DeflateStream.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/DeflateStream.php new file mode 100755 index 00000000..11bf5600 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/DeflateStream.php @@ -0,0 +1,70 @@ +<?php +declare(strict_types=1); + +namespace Twake\Drive\Services\ZipStream; + +class DeflateStream extends Stream +{ + protected $filter; + + /** + * @var Option\File + */ + protected $options; + + /** + * Rewind stream + * + * @return void + */ + public function rewind(): void + { + // deflate filter needs to be removed before rewind + if ($this->filter) { + $this->removeDeflateFilter(); + $this->seek(0); + $this->addDeflateFilter($this->options); + } else { + rewind($this->stream); + } + } + + /** + * Remove the deflate filter + * + * @return void + */ + public function removeDeflateFilter(): void + { + if (!$this->filter) { + return; + } + stream_filter_remove($this->filter); + $this->filter = null; + } + + /** + * Add a deflate filter + * + * @param Option\File $options + * @return void + */ + public function addDeflateFilter(Option\File $options): void + { + $this->options = $options; + // parameter 4 for stream_filter_append expects array + // so we convert the option object in an array + $optionsArr = [ + 'comment' => $options->getComment(), + 'method' => $options->getMethod(), + 'deflateLevel' => $options->getDeflateLevel(), + 'time' => $options->getTime() + ]; + $this->filter = stream_filter_append( + $this->stream, + 'zlib.deflate', + STREAM_FILTER_READ, + $optionsArr + ); + } +} diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception.php new file mode 100755 index 00000000..26efd725 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception.php @@ -0,0 +1,11 @@ +<?php +declare(strict_types=1); + +namespace Twake\Drive\Services\ZipStream; + +/** + * This class is only for inheriting + */ +abstract class Exception extends \Exception +{ +} diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/EncodingException.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/EncodingException.php new file mode 100755 index 00000000..c687dfba --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/EncodingException.php @@ -0,0 +1,13 @@ +<?php +declare(strict_types=1); + +namespace Twake\Drive\Services\ZipStream\Exception; + +use Twake\Drive\Services\ZipStream\Exception; + +/** + * This Exception gets invoked if file or comment encoding is incorrect + */ +class EncodingException extends Exception +{ +} diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/FileNotFoundException.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/FileNotFoundException.php new file mode 100755 index 00000000..824d2c2d --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/FileNotFoundException.php @@ -0,0 +1,22 @@ +<?php +declare(strict_types=1); + +namespace Twake\Drive\Services\ZipStream\Exception; + +use Twake\Drive\Services\ZipStream\Exception; + +/** + * This Exception gets invoked if a file wasn't found + */ +class FileNotFoundException extends Exception +{ + /** + * Constructor of the Exception + * + * @param String $path - The path which wasn't found + */ + public function __construct(string $path) + { + parent::__construct("The file with the path $path wasn't found."); + } +} diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/FileNotReadableException.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/FileNotReadableException.php new file mode 100755 index 00000000..9c9f6433 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/FileNotReadableException.php @@ -0,0 +1,22 @@ +<?php +declare(strict_types=1); + +namespace Twake\Drive\Services\ZipStream\Exception; + +use Twake\Drive\Services\ZipStream\Exception; + +/** + * This Exception gets invoked if a file wasn't found + */ +class FileNotReadableException extends Exception +{ + /** + * Constructor of the Exception + * + * @param String $path - The path which wasn't found + */ + public function __construct(string $path) + { + parent::__construct("The file with the path $path isn't readable."); + } +} diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/IncompatibleOptionsException.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/IncompatibleOptionsException.php new file mode 100755 index 00000000..dbbe5746 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/IncompatibleOptionsException.php @@ -0,0 +1,13 @@ +<?php +declare(strict_types=1); + +namespace Twake\Drive\Services\ZipStream\Exception; + +use Twake\Drive\Services\ZipStream\Exception; + +/** + * This Exception gets invoked if options are incompatible + */ +class IncompatibleOptionsException extends Exception +{ +} diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/OverflowException.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/OverflowException.php new file mode 100755 index 00000000..ec4a49ba --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/OverflowException.php @@ -0,0 +1,17 @@ +<?php +declare(strict_types=1); + +namespace Twake\Drive\Services\ZipStream\Exception; + +use Twake\Drive\Services\ZipStream\Exception; + +/** + * This Exception gets invoked if a counter value exceeds storage size + */ +class OverflowException extends Exception +{ + public function __construct() + { + parent::__construct('File size exceeds limit of 32 bit integer. Please enable "zip64" option.'); + } +} diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/StreamNotReadableException.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/StreamNotReadableException.php new file mode 100755 index 00000000..42e1716e --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Exception/StreamNotReadableException.php @@ -0,0 +1,22 @@ +<?php +declare(strict_types=1); + +namespace Twake\Drive\Services\ZipStream\Exception; + +use Twake\Drive\Services\ZipStream\Exception; + +/** + * This Exception gets invoked if `fread` fails on a stream. + */ +class StreamNotReadableException extends Exception +{ + /** + * Constructor of the Exception + * + * @param string $fileName - The name of the file which the stream belongs to. + */ + public function __construct(string $fileName) + { + parent::__construct("The stream for $fileName could not be read."); + } +} diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/File.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/File.php new file mode 100755 index 00000000..95c337eb --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/File.php @@ -0,0 +1,483 @@ +<?php +declare(strict_types=1); + +namespace Twake\Drive\Services\ZipStream; + +use Twake\Drive\Services\ZipStream\Exception\EncodingException; +use Twake\Drive\Services\ZipStream\Exception\FileNotFoundException; +use Twake\Drive\Services\ZipStream\Exception\FileNotReadableException; +use Twake\Drive\Services\ZipStream\Exception\OverflowException; +use Twake\Drive\Services\ZipStream\Option\File as FileOptions; +use Twake\Drive\Services\ZipStream\Option\Method; +use Twake\Drive\Services\ZipStream\Option\Version; + +class File +{ + const HASH_ALGORITHM = 'crc32b'; + + const BIT_ZERO_HEADER = 0x0008; + const BIT_EFS_UTF8 = 0x0800; + + const COMPUTE = 1; + const SEND = 2; + + private const CHUNKED_READ_BLOCK_SIZE = 1048576; + + /** + * @var string + */ + public $name; + + /** + * @var FileOptions + */ + public $opt; + + /** + * @var Bigint + */ + public $len; + /** + * @var Bigint + */ + public $zlen; + + /** @var int */ + public $crc; + + /** + * @var Bigint + */ + public $hlen; + + /** + * @var Bigint + */ + public $ofs; + + /** + * @var int + */ + public $bits; + + /** + * @var Version + */ + public $version; + + /** + * @var ZipStream + */ + public $zip; + + /** + * @var resource + */ + private $deflate; + /** + * @var resource + */ + private $hash; + + /** + * @var Method + */ + private $method; + + /** + * @var Bigint + */ + private $totalLength; + + public function __construct(ZipStream $zip, string $name, ?FileOptions $opt = null) + { + $this->zip = $zip; + + $this->name = $name; + $this->opt = $opt ?: new FileOptions(); + $this->method = $this->opt->getMethod(); + $this->version = Version::STORE(); + $this->ofs = new Bigint(); + } + + public function processPath(string $path): void + { + if (!is_readable($path)) { + if (!file_exists($path)) { + throw new FileNotFoundException($path); + } + throw new FileNotReadableException($path); + } + if ($this->zip->isLargeFile($path) === false) { + $data = file_get_contents($path); + $this->processData($data); + } else { + $this->method = $this->zip->opt->getLargeFileMethod(); + + $stream = new DeflateStream(fopen($path, 'rb')); + $this->processStream($stream); + } + } + + public function processData(string $data): void + { + $this->len = new Bigint(strlen($data)); + $this->crc = crc32($data); + + // compress data if needed + if ($this->method->equals(Method::DEFLATE())) { + $data = gzdeflate($data); + } + + $this->zlen = new Bigint(strlen($data)); + $this->addFileHeader(); + $this->zip->send($data); + $this->addFileFooter(); + } + + + /** + * Create and send zip header for this file. + * + * @return void + * @throws \ZipStream\Exception\EncodingException + */ + public function addFileHeader(): void + { + $name = static::filterFilename($this->name); + + // calculate name length + $nameLength = strlen($name); + + // create dos timestamp + $time = static::dosTime($this->opt->getTime()->getTimestamp()); + + $comment = $this->opt->getComment(); + + if (!mb_check_encoding($name, 'ASCII') || + !mb_check_encoding($comment, 'ASCII')) { + // Sets Bit 11: Language encoding flag (EFS). If this bit is set, + // the filename and comment fields for this file + // MUST be encoded using UTF-8. (see APPENDIX D) + if (!mb_check_encoding($name, 'UTF-8') || + !mb_check_encoding($comment, 'UTF-8')) { + throw new EncodingException( + 'File name and comment should use UTF-8 ' . + 'if one of them does not fit into ASCII range.' + ); + } + $this->bits |= self::BIT_EFS_UTF8; + } + + if ($this->method->equals(Method::DEFLATE())) { + $this->version = Version::DEFLATE(); + } + + $force = (boolean)($this->bits & self::BIT_ZERO_HEADER) && + $this->zip->opt->isEnableZip64(); + + $footer = $this->buildZip64ExtraBlock($force); + + // If this file will start over 4GB limit in ZIP file, + // CDR record will have to use Zip64 extension to describe offset + // to keep consistency we use the same value here + if ($this->zip->ofs->isOver32()) { + $this->version = Version::ZIP64(); + } + + $fields = [ + ['V', ZipStream::FILE_HEADER_SIGNATURE], + ['v', $this->version->getValue()], // Version needed to Extract + ['v', $this->bits], // General purpose bit flags - data descriptor flag set + ['v', $this->method->getValue()], // Compression method + ['V', $time], // Timestamp (DOS Format) + ['V', $this->crc], // CRC32 of data (0 -> moved to data descriptor footer) + ['V', $this->zlen->getLowFF($force)], // Length of compressed data (forced to 0xFFFFFFFF for zero header) + ['V', $this->len->getLowFF($force)], // Length of original data (forced to 0xFFFFFFFF for zero header) + ['v', $nameLength], // Length of filename + ['v', strlen($footer)], // Extra data (see above) + ]; + + // pack fields and calculate "total" length + $header = ZipStream::packFields($fields); + + // print header and filename + $data = $header . $name . $footer; + $this->zip->send($data); + + // save header length + $this->hlen = Bigint::init(strlen($data)); + } + + /** + * Strip characters that are not legal in Windows filenames + * to prevent compatibility issues + * + * @param string $filename Unprocessed filename + * @return string + */ + public static function filterFilename(string $filename): string + { + // strip leading slashes from file name + // (fixes bug in windows archive viewer) + $filename = preg_replace('/^\\/+/', '', $filename); + + return str_replace(['\\', ':', '*', '?', '"', '<', '>', '|'], '_', $filename); + } + + /** + * Convert a UNIX timestamp to a DOS timestamp. + * + * @param int $when + * @return int DOS Timestamp + */ + final protected static function dosTime(int $when): int + { + // get date array for timestamp + $d = getdate($when); + + // set lower-bound on dates + if ($d['year'] < 1980) { + $d = array( + 'year' => 1980, + 'mon' => 1, + 'mday' => 1, + 'hours' => 0, + 'minutes' => 0, + 'seconds' => 0 + ); + } + + // remove extra years from 1980 + $d['year'] -= 1980; + + // return date string + return + ($d['year'] << 25) | + ($d['mon'] << 21) | + ($d['mday'] << 16) | + ($d['hours'] << 11) | + ($d['minutes'] << 5) | + ($d['seconds'] >> 1); + } + + protected function buildZip64ExtraBlock(bool $force = false): string + { + + $fields = []; + if ($this->len->isOver32($force)) { + $fields[] = ['P', $this->len]; // Length of original data + } + + if ($this->len->isOver32($force)) { + $fields[] = ['P', $this->zlen]; // Length of compressed data + } + + if ($this->ofs->isOver32()) { + $fields[] = ['P', $this->ofs]; // Offset of local header record + } + + if (!empty($fields)) { + if (!$this->zip->opt->isEnableZip64()) { + throw new OverflowException(); + } + + array_unshift( + $fields, + ['v', 0x0001], // 64 bit extension + ['v', count($fields) * 8] // Length of data block + ); + $this->version = Version::ZIP64(); + } + + return ZipStream::packFields($fields); + } + + /** + * Create and send data descriptor footer for this file. + * + * @return void + */ + + public function addFileFooter(): void + { + + if ($this->bits & self::BIT_ZERO_HEADER) { + $fields = [ + ['V', ZipStream::DATA_DESCRIPTOR_SIGNATURE], + ['V', $this->crc], // CRC32 + ['V', $this->zlen], // Length of compressed data + ['V', $this->len], // Length of original data + ]; + + if ($this->zip->opt->isEnableZip64()) { + $fields = [ + ['V', ZipStream::DATA_DESCRIPTOR_SIGNATURE], + ['V', $this->crc], // CRC32 + ['P', $this->zlen], // Length of compressed data + ['P', $this->len], // Length of original data + ]; + } + + $footer = ZipStream::packFields($fields); + $this->zip->send($footer); + } else { + $footer = ''; + } + $this->totalLength = $this->hlen->add($this->zlen)->add(Bigint::init(strlen($footer))); + $this->zip->addToCdr($this); + } + + public function processStream(StreamInterface $stream): void + { + + $this->zlen = new Bigint(); + $this->len = new Bigint(); + + if ($this->zip->opt->isZeroHeader()) { + $this->processStreamWithZeroHeader($stream); + } else { + $this->processStreamWithComputedHeader($stream); + } + } + + protected function processStreamWithZeroHeader(StreamInterface $stream): void + { + + $this->bits |= self::BIT_ZERO_HEADER; + $this->addFileHeader(); + $this->readStream($stream, self::COMPUTE | self::SEND); + $this->addFileFooter(); + } + + protected function readStream(StreamInterface $stream, ?int $options = null): void + { + $this->deflateInit(); + $total = 0; + $size = $this->opt->getSize(); + while (!$stream->eof() && ($size === 0 || $total < $size)) { + + $data = $stream->read(self::CHUNKED_READ_BLOCK_SIZE); + $total += strlen($data); + if ($size > 0 && $total > $size) { + $data = substr($data, 0, strlen($data) - ($total - $size)); + } + $this->deflateData($stream, $data, $options); + if ($options & self::SEND) { + $this->zip->send($data); + } + } + $this->deflateFinish($options); + } + + protected function deflateInit(): void + { + $this->hash = hash_init(self::HASH_ALGORITHM); + if ($this->method->equals(Method::DEFLATE())) { + $this->deflate = deflate_init( + ZLIB_ENCODING_RAW, + ['level' => $this->opt->getDeflateLevel()] + ); + } + } + + protected function deflateData(StreamInterface $stream, string &$data, ?int $options = null): void + { + if ($options & self::COMPUTE) { + $this->len = $this->len->add(Bigint::init(strlen($data))); + hash_update($this->hash, $data); + } + if ($this->deflate) { + $data = deflate_add( + $this->deflate, + $data, + $stream->eof() + ? ZLIB_FINISH + : ZLIB_NO_FLUSH + ); + } + if ($options & self::COMPUTE) { + $this->zlen = $this->zlen->add(Bigint::init(strlen($data))); + } + } + + protected function deflateFinish(?int $options = null): void + { + if ($options & self::COMPUTE) { + $this->crc = hexdec(hash_final($this->hash)); + } + } + + protected function processStreamWithComputedHeader(StreamInterface $stream): void + { + + $this->readStream($stream, self::COMPUTE); + $stream->rewind(); + // incremental compression with deflate_add + // makes this second read unnecessary + // but it is only available from PHP 7.0 + if (!$this->deflate && $stream instanceof DeflateStream && $this->method->equals(Method::DEFLATE())) { + $stream->addDeflateFilter($this->opt); + $this->zlen = new Bigint(); + while (!$stream->eof()) { + $data = $stream->read(self::CHUNKED_READ_BLOCK_SIZE); + $this->zlen = $this->zlen->add(Bigint::init(strlen($data))); + } + $stream->rewind(); + } + + $this->addFileHeader(); + $this->readStream($stream, self::SEND); + $this->addFileFooter(); + } + + /** + * Send CDR record for specified file. + * + * @return string + */ + public function getCdrFile(): string + { + $name = static::filterFilename($this->name); + + // get attributes + $comment = $this->opt->getComment(); + + // get dos timestamp + $time = static::dosTime($this->opt->getTime()->getTimestamp()); + + $footer = $this->buildZip64ExtraBlock(); + + $fields = [ + ['V', ZipStream::CDR_FILE_SIGNATURE], // Central file header signature + ['v', ZipStream::ZIP_VERSION_MADE_BY], // Made by version + ['v', $this->version->getValue()], // Extract by version + ['v', $this->bits], // General purpose bit flags - data descriptor flag set + ['v', $this->method->getValue()], // Compression method + ['V', $time], // Timestamp (DOS Format) + ['V', $this->crc], // CRC32 + ['V', $this->zlen->getLowFF()], // Compressed Data Length + ['V', $this->len->getLowFF()], // Original Data Length + ['v', strlen($name)], // Length of filename + ['v', strlen($footer)], // Extra data len (see above) + ['v', strlen($comment)], // Length of comment + ['v', 0], // Disk number + ['v', 0], // Internal File Attributes + ['V', 32], // External File Attributes + ['V', $this->ofs->getLowFF()] // Relative offset of local header + ]; + + // pack fields, then append name and comment + $header = ZipStream::packFields($fields); + + return $header . $name . $footer . $comment; + } + + /** + * @return Bigint + */ + public function getTotalLength(): Bigint + { + return $this->totalLength; + } +} diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/Option/Archive.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Option/Archive.php new file mode 100755 index 00000000..950fdc78 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Option/Archive.php @@ -0,0 +1,261 @@ +<?php +declare(strict_types=1); + +namespace Twake\Drive\Services\ZipStream\Option; + +final class Archive +{ + const DEFAULT_DEFLATE_LEVEL = 6; + /** + * @var string + */ + private $comment = ''; + /** + * Size, in bytes, of the largest file to try + * and load into memory (used by + * addFileFromPath()). Large files may also + * be compressed differently; see the + * 'largeFileMethod' option. Default is ~20 Mb. + * + * @var int + */ + private $largeFileSize = 20 * 1024 * 1024; + /** + * How to handle large files. Legal values are + * Method::STORE() (the default), or + * Method::DEFLATE(). STORE sends the file + * raw and is significantly + * faster, while DEFLATE compresses the file + * and is much, much slower. Note that DEFLATE + * must compress the file twice and is extremely slow. + * + * @var Method + */ + private $largeFileMethod; + /** + * Boolean indicating whether or not to send + * the HTTP headers for this file. + * + * @var bool + */ + private $sendHttpHeaders = false; + /** + * The method called to send headers + * + * @var Callable + */ + private $httpHeaderCallback = 'header'; + /** + * Enable Zip64 extension, supporting very large + * archives (any size > 4 GB or file count > 64k) + * + * @var bool + */ + private $enableZip64 = true; + /** + * Enable streaming files with single read where + * general purpose bit 3 indicates local file header + * contain zero values in crc and size fields, + * these appear only after file contents + * in data descriptor block. + * + * @var bool + */ + private $zeroHeader = false; + /** + * Enable reading file stat for determining file size. + * When a 32-bit system reads file size that is + * over 2 GB, invalid value appears in file size + * due to integer overflow. Should be disabled on + * 32-bit systems with method addFileFromPath + * if any file may exceed 2 GB. In this case file + * will be read in blocks and correct size will be + * determined from content. + * + * @var bool + */ + private $statFiles = true; + /** + * Enable flush after every write to output stream. + * @var bool + */ + private $flushOutput = false; + /** + * HTTP Content-Disposition. Defaults to + * 'attachment', where + * FILENAME is the specified filename. + * + * Note that this does nothing if you are + * not sending HTTP headers. + * + * @var string + */ + private $contentDisposition = 'attachment'; + /** + * Note that this does nothing if you are + * not sending HTTP headers. + * + * @var string + */ + private $contentType = 'application/x-zip'; + /** + * @var int + */ + private $deflateLevel = 6; + + /** + * @var resource + */ + private $outputStream; + + /** + * Options constructor. + */ + public function __construct() + { + $this->largeFileMethod = Method::STORE(); + $this->outputStream = fopen('php://output', 'wb'); + } + + public function getComment(): string + { + return $this->comment; + } + + public function setComment(string $comment): void + { + $this->comment = $comment; + } + + public function getLargeFileSize(): int + { + return $this->largeFileSize; + } + + public function setLargeFileSize(int $largeFileSize): void + { + $this->largeFileSize = $largeFileSize; + } + + public function getLargeFileMethod(): Method + { + return $this->largeFileMethod; + } + + public function setLargeFileMethod(Method $largeFileMethod): void + { + $this->largeFileMethod = $largeFileMethod; + } + + public function isSendHttpHeaders(): bool + { + return $this->sendHttpHeaders; + } + + public function setSendHttpHeaders(bool $sendHttpHeaders): void + { + $this->sendHttpHeaders = $sendHttpHeaders; + } + + public function getHttpHeaderCallback(): Callable + { + return $this->httpHeaderCallback; + } + + public function setHttpHeaderCallback(Callable $httpHeaderCallback): void + { + $this->httpHeaderCallback = $httpHeaderCallback; + } + + public function isEnableZip64(): bool + { + return $this->enableZip64; + } + + public function setEnableZip64(bool $enableZip64): void + { + $this->enableZip64 = $enableZip64; + } + + public function isZeroHeader(): bool + { + return $this->zeroHeader; + } + + public function setZeroHeader(bool $zeroHeader): void + { + $this->zeroHeader = $zeroHeader; + } + + public function isFlushOutput(): bool + { + return $this->flushOutput; + } + + public function setFlushOutput(bool $flushOutput): void + { + $this->flushOutput = $flushOutput; + } + + public function isStatFiles(): bool + { + return $this->statFiles; + } + + public function setStatFiles(bool $statFiles): void + { + $this->statFiles = $statFiles; + } + + public function getContentDisposition(): string + { + return $this->contentDisposition; + } + + public function setContentDisposition(string $contentDisposition): void + { + $this->contentDisposition = $contentDisposition; + } + + public function getContentType(): string + { + return $this->contentType; + } + + public function setContentType(string $contentType): void + { + $this->contentType = $contentType; + } + + /** + * @return resource + */ + public function getOutputStream() + { + return $this->outputStream; + } + + /** + * @param resource $outputStream + */ + public function setOutputStream($outputStream): void + { + $this->outputStream = $outputStream; + } + + /** + * @return int + */ + public function getDeflateLevel(): int + { + return $this->deflateLevel; + } + + /** + * @param int $deflateLevel + */ + public function setDeflateLevel(int $deflateLevel): void + { + $this->deflateLevel = $deflateLevel; + } +} diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/Option/Enum.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Option/Enum.php new file mode 100755 index 00000000..f45580ea --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Option/Enum.php @@ -0,0 +1,196 @@ +<?php +/** + * @link http://github.com/myclabs/php-enum + * @license http://www.opensource.org/licenses/mit-license.php MIT (see the LICENSE file) + */ + +namespace Twake\Drive\Services\ZipStream\Option; +/** + * Base Enum class + * + * Create an enum by implementing this class and adding class constants. + * + * @author Matthieu Napoli <matthieu@mnapoli.fr> + * @author Daniel Costa <danielcosta@gmail.com> + * @author MirosΕ‚aw Filip <mirfilip@gmail.com> + */ +abstract class Enum implements \JsonSerializable +{ + /** + * Store existing constants in a static cache per object. + * + * @var array + */ + protected static $cache = []; + /** + * Enum value + * + * @var mixed + */ + protected $value; + + /** + * Creates a new value of some type + * + * @param mixed $value + * + * @throws \UnexpectedValueException if incompatible type is given. + */ + public function __construct($value) + { + if ($value instanceof static) { + $value = $value->getValue(); + } + if (!$this->isValid($value)) { + throw new \UnexpectedValueException("Value '$value' is not part of the enum " . \get_called_class()); + } + $this->value = $value; + } + + /** + * @return mixed + */ + public function getValue() + { + return $this->value; + } + + /** + * Check if is valid enum value + * + * @param $value + * + * @return bool + */ + public static function isValid($value) + { + return \in_array($value, static::toArray(), true); + } + + /** + * Returns all possible values as an array + * + * @return array Constant name in key, constant value in value + */ + public static function toArray() + { + $class = \get_called_class(); + if (!isset(static::$cache[$class])) { + $reflection = new \ReflectionClass($class); + static::$cache[$class] = $reflection->getConstants(); + } + return static::$cache[$class]; + } + + /** + * Returns the names (keys) of all constants in the Enum class + * + * @return array + */ + public static function keys() + { + return \array_keys(static::toArray()); + } + + /** + * Returns instances of the Enum class of all Enum constants + * + * @return static[] Constant name in key, Enum instance in value + */ + public static function values() + { + $values = array(); + foreach (static::toArray() as $key => $value) { + $values[$key] = new static($value); + } + return $values; + } + + /** + * Check if is valid enum key + * + * @param $key + * + * @return bool + */ + public static function isValidKey($key) + { + $array = static::toArray(); + return isset($array[$key]) || \array_key_exists($key, $array); + } + + /** + * Returns a value when called statically like so: MyEnum::SOME_VALUE() given SOME_VALUE is a class constant + * + * @param string $name + * @param array $arguments + * + * @return static + * @throws \BadMethodCallException + */ + public static function __callStatic($name, $arguments) + { + $array = static::toArray(); + if (isset($array[$name]) || \array_key_exists($name, $array)) { + return new static($array[$name]); + } + throw new \BadMethodCallException("No static method or enum constant '$name' in class " . \get_called_class()); + } + + /** + * Returns the enum key (i.e. the constant name). + * + * @return mixed + */ + public function getKey() + { + return static::search($this->value); + } + + /** + * Return key for value + * + * @param $value + * + * @return mixed + */ + public static function search($value) + { + return \array_search($value, static::toArray(), true); + } + + /** + * @return string + */ + public function __toString() + { + return (string)$this->value; + } + + /** + * Determines if Enum should be considered equal with the variable passed as a parameter. + * Returns false if an argument is an object of different class or not an object. + * + * This method is final, for more information read https://github.com/myclabs/php-enum/issues/4 + * + * @return bool + */ + final public function equals($variable = null): bool + { + return $variable instanceof self + && $this->getValue() === $variable->getValue() + && \get_called_class() === \get_class($variable); + } + + /** + * Specify data which should be serialized to JSON. This method returns data that can be serialized by json_encode() + * natively. + * + * @return mixed + * @link http://php.net/manual/en/jsonserializable.jsonserialize.php + */ + public function jsonSerialize() + { + return $this->getValue(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/Option/File.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Option/File.php new file mode 100755 index 00000000..5ef40798 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Option/File.php @@ -0,0 +1,116 @@ +<?php +declare(strict_types=1); + +namespace Twake\Drive\Services\ZipStream\Option; + +use DateTime; + +final class File +{ + /** + * @var string + */ + private $comment = ''; + /** + * @var Method + */ + private $method; + /** + * @var int + */ + private $deflateLevel; + /** + * @var DateTime + */ + private $time; + /** + * @var int + */ + private $size = 0; + + public function defaultTo(Archive $archiveOptions): void + { + $this->deflateLevel = $this->deflateLevel ?: $archiveOptions->getDeflateLevel(); + $this->time = $this->time ?: new DateTime(); + } + + /** + * @return string + */ + public function getComment(): string + { + return $this->comment; + } + + /** + * @param string $comment + */ + public function setComment(string $comment): void + { + $this->comment = $comment; + } + + /** + * @return Method + */ + public function getMethod(): Method + { + return $this->method ?: Method::DEFLATE(); + } + + /** + * @param Method $method + */ + public function setMethod(Method $method): void + { + $this->method = $method; + } + + /** + * @return int + */ + public function getDeflateLevel(): int + { + return $this->deflateLevel ?: Archive::DEFAULT_DEFLATE_LEVEL; + } + + /** + * @param int $deflateLevel + */ + public function setDeflateLevel(int $deflateLevel): void + { + $this->deflateLevel = $deflateLevel; + } + + /** + * @return DateTime + */ + public function getTime(): DateTime + { + return $this->time; + } + + /** + * @param DateTime $time + */ + public function setTime(DateTime $time): void + { + $this->time = $time; + } + + /** + * @return int + */ + public function getSize(): int + { + return $this->size; + } + + /** + * @param int $size + */ + public function setSize(int $size): void + { + $this->size = $size; + } +} diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/Option/Method.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Option/Method.php new file mode 100755 index 00000000..5c058bc1 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Option/Method.php @@ -0,0 +1,16 @@ +<?php +declare(strict_types=1); + +namespace Twake\Drive\Services\ZipStream\Option; + +/** + * Methods enum + * + * @method static STORE(): Method + * @method static DEFLATE(): Method + */ +class Method extends Enum +{ + const STORE = 0x00; + const DEFLATE = 0x08; +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/Option/Version.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Option/Version.php new file mode 100755 index 00000000..428013f9 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Option/Version.php @@ -0,0 +1,19 @@ +<?php +declare(strict_types=1); + +namespace Twake\Drive\Services\ZipStream\Option; + +/** + * Class Version + * @package ZipStream\Option + * + * @method static STORE(): Version + * @method static DEFLATE(): Version + * @method static ZIP64(): Version + */ +class Version extends Enum +{ + const STORE = 0x000A; // 1.00 + const DEFLATE = 0x0014; // 2.00 + const ZIP64 = 0x002D; // 4.50 +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/Stream.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Stream.php new file mode 100755 index 00000000..74622212 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/Stream.php @@ -0,0 +1,258 @@ +<?php +declare(strict_types=1); + +namespace Twake\Drive\Services\ZipStream; + +use RuntimeException; + +/** + * Describes a data stream. + * + * Typically, an instance will wrap a PHP stream; this interface provides + * a wrapper around the most common operations, including serialization of + * the entire stream to a string. + */ +class Stream implements StreamInterface +{ + protected $stream; + + public function __construct($stream) + { + $this->stream = $stream; + } + + public function __destruct() + { + $this->close(); + } + + /** + * Closes the stream and any underlying resources. + * + * @return void + */ + public function close(): void + { + if (is_resource($this->stream)) { + fclose($this->stream); + } + $this->detach(); + } + + /** + * Separates any underlying resources from the stream. + * + * After the stream has been detached, the stream is in an unusable state. + * + * @return resource|null Underlying PHP stream, if any + */ + public function detach() + { + $result = $this->stream; + $this->stream = null; + return $result; + } + + /** + * Reads all data from the stream into a string, from the beginning to end. + * + * This method MUST attempt to seek to the beginning of the stream before + * reading data and read the stream until the end is reached. + * + * Warning: This could attempt to load a large amount of data into memory. + * + * This method MUST NOT raise an exception in order to conform with PHP's + * string casting operations. + * + * @see http://php.net/manual/en/language.oop5.magic.php#object.tostring + * @return string + */ + public function __toString(): string + { + try { + $this->seek(0); + } catch (\RuntimeException $e) { + } + return (string)stream_get_contents($this->stream); + } + + /** + * Seek to a position in the stream. + * + * @link http://www.php.net/manual/en/function.fseek.php + * @param int $offset Stream offset + * @param int $whence Specifies how the cursor position will be calculated + * based on the seek offset. Valid values are identical to the built-in + * PHP $whence values for `fseek()`. SEEK_SET: Set position equal to + * offset bytes SEEK_CUR: Set position to current location plus offset + * SEEK_END: Set position to end-of-stream plus offset. + * @throws \RuntimeException on failure. + */ + public function seek($offset, $whence = SEEK_SET): void + { + if (!$this->isSeekable()) { + throw new RuntimeException; + } + if (fseek($this->stream, $offset, $whence) !== 0) { + throw new RuntimeException; + } + } + + /** + * Returns whether or not the stream is seekable. + * + * @return bool + */ + public function isSeekable(): bool + { + return (bool)$this->getMetadata('seekable'); + } + + /** + * Get stream metadata as an associative array or retrieve a specific key. + * + * The keys returned are identical to the keys returned from PHP's + * stream_get_meta_data() function. + * + * @link http://php.net/manual/en/function.stream-get-meta-data.php + * @param string $key Specific metadata to retrieve. + * @return array|mixed|null Returns an associative array if no key is + * provided. Returns a specific key value if a key is provided and the + * value is found, or null if the key is not found. + */ + public function getMetadata($key = null) + { + $metadata = stream_get_meta_data($this->stream); + return $key !== null ? @$metadata[$key] : $metadata; + } + + /** + * Get the size of the stream if known. + * + * @return int|null Returns the size in bytes if known, or null if unknown. + */ + public function getSize(): ?int + { + $stats = fstat($this->stream); + return $stats['size']; + } + + /** + * Returns the current position of the file read/write pointer + * + * @return int Position of the file pointer + * @throws \RuntimeException on error. + */ + public function tell(): int + { + $position = ftell($this->stream); + if ($position === false) { + throw new RuntimeException; + } + return $position; + } + + /** + * Returns true if the stream is at the end of the stream. + * + * @return bool + */ + public function eof(): bool + { + return feof($this->stream); + } + + /** + * Seek to the beginning of the stream. + * + * If the stream is not seekable, this method will raise an exception; + * otherwise, it will perform a seek(0). + * + * @see seek() + * @link http://www.php.net/manual/en/function.fseek.php + * @throws \RuntimeException on failure. + */ + public function rewind(): void + { + $this->seek(0); + } + + /** + * Write data to the stream. + * + * @param string $string The string that is to be written. + * @return int Returns the number of bytes written to the stream. + * @throws \RuntimeException on failure. + */ + public function write($string): int + { + if (!$this->isWritable()) { + throw new RuntimeException; + } + if (fwrite($this->stream, $string) === false) { + throw new RuntimeException; + } + return \mb_strlen($string); + } + + /** + * Returns whether or not the stream is writable. + * + * @return bool + */ + public function isWritable(): bool + { + return preg_match('/[waxc+]/', $this->getMetadata('mode')) === 1; + } + + /** + * Read data from the stream. + * + * @param int $length Read up to $length bytes from the object and return + * them. Fewer than $length bytes may be returned if underlying stream + * call returns fewer bytes. + * @return string Returns the data read from the stream, or an empty string + * if no bytes are available. + * @throws \RuntimeException if an error occurs. + */ + public function read($length): string + { + if (!$this->isReadable()) { + throw new RuntimeException; + } + $result = fread($this->stream, $length); + if ($result === false) { + throw new RuntimeException; + } + return $result; + } + + /** + * Returns whether or not the stream is readable. + * + * @return bool + */ + public function isReadable(): bool + { + return preg_match('/[r+]/', $this->getMetadata('mode')) === 1; + } + + /** + * Returns the remaining contents in a string + * + * @return string + * @throws \RuntimeException if unable to read or an error occurs while + * reading. + */ + public function getContents(): string + { + if (!$this->isReadable()) { + throw new RuntimeException; + } + $result = stream_get_contents($this->stream); + if ($result === false) { + throw new RuntimeException; + } + return $result; + } +} diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/StreamInterface.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/StreamInterface.php new file mode 100755 index 00000000..f3d962d9 --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/StreamInterface.php @@ -0,0 +1,157 @@ +<?php + +namespace Twake\Drive\Services\ZipStream; +/** + * Describes a data stream. + * + * Typically, an instance will wrap a PHP stream; this interface provides + * a wrapper around the most common operations, including serialization of + * the entire stream to a string. + */ +interface StreamInterface +{ + /** + * Reads all data from the stream into a string, from the beginning to end. + * + * This method MUST attempt to seek to the beginning of the stream before + * reading data and read the stream until the end is reached. + * + * Warning: This could attempt to load a large amount of data into memory. + * + * This method MUST NOT raise an exception in order to conform with PHP's + * string casting operations. + * + * @see http://php.net/manual/en/language.oop5.magic.php#object.tostring + * @return string + */ + public function __toString(); + + /** + * Closes the stream and any underlying resources. + * + * @return void + */ + public function close(); + + /** + * Separates any underlying resources from the stream. + * + * After the stream has been detached, the stream is in an unusable state. + * + * @return resource|null Underlying PHP stream, if any + */ + public function detach(); + + /** + * Get the size of the stream if known. + * + * @return int|null Returns the size in bytes if known, or null if unknown. + */ + public function getSize(); + + /** + * Returns the current position of the file read/write pointer + * + * @return int Position of the file pointer + * @throws \RuntimeException on error. + */ + public function tell(); + + /** + * Returns true if the stream is at the end of the stream. + * + * @return bool + */ + public function eof(); + + /** + * Returns whether or not the stream is seekable. + * + * @return bool + */ + public function isSeekable(); + + /** + * Seek to a position in the stream. + * + * @link http://www.php.net/manual/en/function.fseek.php + * @param int $offset Stream offset + * @param int $whence Specifies how the cursor position will be calculated + * based on the seek offset. Valid values are identical to the built-in + * PHP $whence values for `fseek()`. SEEK_SET: Set position equal to + * offset bytes SEEK_CUR: Set position to current location plus offset + * SEEK_END: Set position to end-of-stream plus offset. + * @throws \RuntimeException on failure. + */ + public function seek($offset, $whence = SEEK_SET); + + /** + * Seek to the beginning of the stream. + * + * If the stream is not seekable, this method will raise an exception; + * otherwise, it will perform a seek(0). + * + * @see seek() + * @link http://www.php.net/manual/en/function.fseek.php + * @throws \RuntimeException on failure. + */ + public function rewind(); + + /** + * Returns whether or not the stream is writable. + * + * @return bool + */ + public function isWritable(); + + /** + * Write data to the stream. + * + * @param string $string The string that is to be written. + * @return int Returns the number of bytes written to the stream. + * @throws \RuntimeException on failure. + */ + public function write($string); + + /** + * Returns whether or not the stream is readable. + * + * @return bool + */ + public function isReadable(); + + /** + * Read data from the stream. + * + * @param int $length Read up to $length bytes from the object and return + * them. Fewer than $length bytes may be returned if underlying stream + * call returns fewer bytes. + * @return string Returns the data read from the stream, or an empty string + * if no bytes are available. + * @throws \RuntimeException if an error occurs. + */ + public function read($length); + + /** + * Returns the remaining contents in a string + * + * @return string + * @throws \RuntimeException if unable to read or an error occurs while + * reading. + */ + public function getContents(); + + /** + * Get stream metadata as an associative array or retrieve a specific key. + * + * The keys returned are identical to the keys returned from PHP's + * stream_get_meta_data() function. + * + * @link http://php.net/manual/en/function.stream-get-meta-data.php + * @param string $key Specific metadata to retrieve. + * @return array|mixed|null Returns an associative array if no key is + * provided. Returns a specific key value if a key is provided and the + * value is found, or null if the key is not found. + */ + public function getMetadata($key = null); +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/TwakeFileStream.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/TwakeFileStream.php new file mode 100755 index 00000000..a37c340f --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/TwakeFileStream.php @@ -0,0 +1,214 @@ +<?php +declare(strict_types=1); + +namespace Twake\Drive\Services\ZipStream; + +use RuntimeException; + +//class TwakeFileStream extends Stream +class TwakeFileStream implements StreamInterface +{ + + private $manager; + private $param_bag; + private $uploadstate; + + private $totalchunk; + private $current_chunk; + private $stream; + + public function __construct($manager, $param_bag, $uploadstate) + { + $this->manager = $manager; + $this->param_bag = $param_bag; + $this->uploadstate = $uploadstate; + $this->current_chunk = 1; + $this->totalchunk = $this->uploadstate->getChunk(); + $this->stream = $this->manager->read("original_stream", $this->current_chunk, $this->param_bag, $this->uploadstate); + + } + + public function __destruct() + { + $this->close(); + } + + public function close() + { + if (is_resource($this->stream)) { + fclose($this->stream); + } + $this->detach(); + + } + + public function detach() + { + $result = $this->stream; + $this->stream = null; + return $result; + } + + public function __toString() + { + + if (!$this->stream) { + return ""; + } + + try { + $this->seek(0); + } catch (\RuntimeException $e) { + } + return (string)stream_get_contents($this->stream); + + } + + public function seek($offset, $whence = SEEK_SET) + { + if (!$this->stream) { + return; + } + if (!$this->isSeekable()) { + throw new RuntimeException; + } + if (fseek($this->stream, $offset, $whence) !== 0) { + throw new RuntimeException; + } + + } + + public function isSeekable() + { + return (bool)$this->getMetadata('seekable'); + + } + + public function getMetadata($key = null) + { + if (!$this->stream) { + return Array(); + } + $metadata = stream_get_meta_data($this->stream); + return $key !== null ? @$metadata[$key] : $metadata; + } + + public function getSize() + { + if (!$this->stream) { + return 0; + } + $stats = fstat($this->stream); + return $stats['size'] + 1; + } + + public function tell() + { + if (!$this->stream) { + return 0; + } + + $position = ftell($this->stream); + if ($position === false) { + throw new RuntimeException; + } + return $position; + + } + + public function rewind() + { + if (!$this->stream) { + return; + } + $this->seek(0); + $this->current_chunk = 1; + $this->manager->read("original_stream", $this->current_chunk, $this->param_bag, $this->uploadstate); + + } + + public function isWritable() + { + return false; + } + + public function write($string) + { + return false; + } + + public function getContents() + { + if (!$this->stream) { + return ""; + } + if (!$this->isReadable()) { + throw new RuntimeException; + } + $result = stream_get_contents($this->stream); + if ($result === false) { + throw new RuntimeException; + } + return $result; + } + + public function isReadable() + { + return true; + } + + public function read($length) + { + if (!$this->stream) { + return ""; + } + + //error_log(print_r(stream_get_meta_data($this->stream),true)); + $retour = fread($this->stream, $length); + if ($retour === false) { + throw new RuntimeException; + } + if ($this->eof()) { + if ($this->current_chunk < $this->totalchunk) { + //todo : probleme avec les close des stream des differents chunk +// try{ +// fclose($this->stream); +// }catch (\Exception $e) { +// error_log($e->getTraceAsString()); +// error_log($e->getMessage()); +// die("ERROR with fclose"); +// } + $path = realpath(stream_get_meta_data($this->stream)["uri"]); + $valid = preg_match("/\/tmp\/.*/", $path); + if (file_exists($path) && !is_dir($path) && $valid) { + error_log(print_r($path, true)); + @unlink($path); + } + + $this->current_chunk = $this->current_chunk + 1; + $this->stream = $this->manager->read("original_stream", $this->current_chunk, $this->param_bag, $this->uploadstate); + + if ($length - strlen($retour) > 0) { + $retour = $retour . $this->read($length - strlen($retour)); + } + } else { + $path = stream_get_meta_data($this->stream)["uri"]; + $valid = preg_match("/\/tmp\/.*/", $path); + if (file_exists($path) && !is_dir($path) && $valid) { + error_log(print_r($path, true)); + @unlink($path); + } + //fclose($this->stream); + } + } + return $retour; + } + + public function eof() + { + if (!$this->stream) { + return true; + } + return feof($this->stream); + } +} diff --git a/twake/backend/core/src/Twake/Drive/Services/ZipStream/ZipStream.php b/twake/backend/core/src/Twake/Drive/Services/ZipStream/ZipStream.php new file mode 100755 index 00000000..b1abc5ec --- /dev/null +++ b/twake/backend/core/src/Twake/Drive/Services/ZipStream/ZipStream.php @@ -0,0 +1,595 @@ +<?php +declare(strict_types=1); + +namespace Twake\Drive\Services\ZipStream; + +use Twake\Drive\Services\ZipStream\Exception\OverflowException; +use Twake\Drive\Services\ZipStream\Option\Archive as ArchiveOptions; +use Twake\Drive\Services\ZipStream\Option\File as FileOptions; +use Twake\Drive\Services\ZipStream\Option\Version; + +/** + * ZipStream + * + * Streamed, dynamically generated zip archives. + * + * Usage: + * + * Streaming zip archives is a simple, three-step process: + * + * 1. Create the zip stream: + * + * $zip = new ZipStream('example.zip'); + * + * 2. Add one or more files to the archive: + * + * * add first file + * $data = file_get_contents('some_file.gif'); + * $zip->addFile('some_file.gif', $data); + * + * * add second file + * $data = file_get_contents('some_file.gif'); + * $zip->addFile('another_file.png', $data); + * + * 3. Finish the zip stream: + * + * $zip->finish(); + * + * You can also add an archive comment, add comments to individual files, + * and adjust the timestamp of files. See the API documentation for each + * method below for additional information. + * + * Example: + * + * // create a new zip stream object + * $zip = new ZipStream('some_files.zip'); + * + * // list of local files + * $files = array('foo.txt', 'bar.jpg'); + * + * // read and add each file to the archive + * foreach ($files as $path) + * $zip->addFile($path, file_get_contents($path)); + * + * // write archive footer to stream + * $zip->finish(); + */ +class ZipStream +{ + /** + * This number corresponds to the ZIP version/OS used (2 bytes) + * From: https://www.iana.org/assignments/media-types/application/zip + * The upper byte (leftmost one) indicates the host system (OS) for the + * file. Software can use this information to determine + * the line record format for text files etc. The current + * mappings are: + * + * 0 - MS-DOS and OS/2 (F.A.T. file systems) + * 1 - Amiga 2 - VAX/VMS + * 3 - *nix 4 - VM/CMS + * 5 - Atari ST 6 - OS/2 H.P.F.S. + * 7 - Macintosh 8 - Z-System + * 9 - CP/M 10 thru 255 - unused + * + * The lower byte (rightmost one) indicates the version number of the + * software used to encode the file. The value/10 + * indicates the major version number, and the value + * mod 10 is the minor version number. + * Here we are using 6 for the OS, indicating OS/2 H.P.F.S. + * to prevent file permissions issues upon extract (see #84) + * 0x603 is 00000110 00000011 in binary, so 6 and 3 + */ + const ZIP_VERSION_MADE_BY = 0x603; + + /** + * The following signatures end with 0x4b50, which in ASCII isΒ PK, + * the initials of the inventor Phil Katz. + * See https://en.wikipedia.org/wiki/Zip_(file_format)#File_headers + */ + const FILE_HEADER_SIGNATURE = 0x04034b50; + const CDR_FILE_SIGNATURE = 0x02014b50; + const CDR_EOF_SIGNATURE = 0x06054b50; + const DATA_DESCRIPTOR_SIGNATURE = 0x08074b50; + const ZIP64_CDR_EOF_SIGNATURE = 0x06064b50; + const ZIP64_CDR_LOCATOR_SIGNATURE = 0x07064b50; + + /** + * Global Options + * + * @var ArchiveOptions + */ + public $opt; + + /** + * @var array + */ + public $files = []; + + /** + * @var Bigint + */ + public $cdr_ofs; + + /** + * @var Bigint + */ + public $ofs; + + /** + * @var bool + */ + protected $need_headers; + + /** + * @var null|String + */ + protected $output_name; + + /** + * Create a new ZipStream object. + * + * Parameters: + * + * @param String $name - Name of output file (optional). + * @param ArchiveOptions $opt - Archive Options + * + * Large File Support: + * + * By default, the method addFileFromPath() will send send files + * larger than 20 megabytes along raw rather than attempting to + * compress them. You can change both the maximum size and the + * compression behavior using the largeFile* options above, with the + * following caveats: + * + * * For "small" files (e.g. files smaller than largeFileSize), the + * memory use can be up to twice that of the actual file. In other + * words, adding a 10 megabyte file to the archive could potentially + * occupy 20 megabytes of memory. + * + * * Enabling compression on large files (e.g. files larger than + * large_file_size) is extremely slow, because ZipStream has to pass + * over the large file once to calculate header information, and then + * again to compress and send the actual data. + * + * Examples: + * + * // create a new zip file named 'foo.zip' + * $zip = new ZipStream('foo.zip'); + * + * // create a new zip file named 'bar.zip' with a comment + * $opt->setComment = 'this is a comment for the zip file.'; + * $zip = new ZipStream('bar.zip', $opt); + * + * Notes: + * + * In order to let this library send HTTP headers, a filename must be given + * _and_ the option `sendHttpHeaders` must be `true`. This behavior is to + * allow software to send its own headers (including the filename), and + * still use this library. + */ + public function __construct(?string $name = null, $opt = null) + { + $this->opt = $opt ?: new ArchiveOptions(); + + $this->output_name = $name; + $this->need_headers = $name && $this->opt->isSendHttpHeaders(); + + $this->cdr_ofs = new Bigint(); + $this->ofs = new Bigint(); + } + + /** + * addFile + * + * Add a file to the archive. + * + * @param String $name - path of file in archive (including directory). + * @param String $data - contents of file + * @param FileOptions $options + * + * File Options: + * time - Last-modified timestamp (seconds since the epoch) of + * this file. Defaults to the current time. + * comment - Comment related to this file. + * method - Storage method for file ("store" or "deflate") + * + * Examples: + * + * // add a file named 'foo.txt' + * $data = file_get_contents('foo.txt'); + * $zip->addFile('foo.txt', $data); + * + * // add a file named 'bar.jpg' with a comment and a last-modified + * // time of two hours ago + * $data = file_get_contents('bar.jpg'); + * $opt->setTime = time() - 2 * 3600; + * $opt->setComment = 'this is a comment about bar.jpg'; + * $zip->addFile('bar.jpg', $data, $opt); + */ + public function addFile(string $name, string $data, ?FileOptions $options = null): void + { + $options = $options ?: new FileOptions(); + $options->defaultTo($this->opt); + + $file = new File($this, $name, $options); + $file->processData($data); + } + + /** + * addFileFromPath + * + * Add a file at path to the archive. + * + * Note that large files may be compressed differently than smaller + * files; see the "Large File Support" section above for more + * information. + * + * @param String $name - name of file in archive (including directory path). + * @param String $path - path to file on disk (note: paths should be encoded using + * UNIX-style forward slashes -- e.g '/path/to/some/file'). + * @param FileOptions $options + * + * File Options: + * time - Last-modified timestamp (seconds since the epoch) of + * this file. Defaults to the current time. + * comment - Comment related to this file. + * method - Storage method for file ("store" or "deflate") + * + * Examples: + * + * // add a file named 'foo.txt' from the local file '/tmp/foo.txt' + * $zip->addFileFromPath('foo.txt', '/tmp/foo.txt'); + * + * // add a file named 'bigfile.rar' from the local file + * // '/usr/share/bigfile.rar' with a comment and a last-modified + * // time of two hours ago + * $path = '/usr/share/bigfile.rar'; + * $opt->setTime = time() - 2 * 3600; + * $opt->setComment = 'this is a comment about bar.jpg'; + * $zip->addFileFromPath('bigfile.rar', $path, $opt); + * + * @return void + * @throws \ZipStream\Exception\FileNotFoundException + * @throws \ZipStream\Exception\FileNotReadableException + */ + public function addFileFromPath(string $name, string $path, ?FileOptions $options = null): void + { + $options = $options ?: new FileOptions(); + $options->defaultTo($this->opt); + + $file = new File($this, $name, $options); + $file->processPath($path); + } + + /** + * addFileFromStream + * + * Add an open stream to the archive. + * + * @param String $name - path of file in archive (including directory). + * @param Resource $stream - contents of file as a stream resource + * @param FileOptions $options + * + * File Options: + * time - Last-modified timestamp (seconds since the epoch) of + * this file. Defaults to the current time. + * comment - Comment related to this file. + * + * Examples: + * + * // create a temporary file stream and write text to it + * $fp = tmpfile(); + * fwrite($fp, 'The quick brown fox jumped over the lazy dog.'); + * + * // add a file named 'streamfile.txt' from the content of the stream + * $x->addFileFromStream('streamfile.txt', $fp); + * + * @return void + */ + public function addFileFromStream(string $name, $stream, $options = null): void + { + $options = $options ?: new FileOptions(); + $options->defaultTo($this->opt); + + $file = new File($this, $name, $options); + + $file->processStream(new DeflateStream($stream)); + } + + /** + * addFileFromPsr7Stream + * + * Add an open stream to the archive. + * + * @param String $name - path of file in archive (including directory). + * @param StreamInterface $stream - contents of file as a stream resource + * @param FileOptions $options + * + * File Options: + * time - Last-modified timestamp (seconds since the epoch) of + * this file. Defaults to the current time. + * comment - Comment related to this file. + * + * Examples: + * + * // create a temporary file stream and write text to it + * $fp = tmpfile(); + * fwrite($fp, 'The quick brown fox jumped over the lazy dog.'); + * + * // add a file named 'streamfile.txt' from the content of the stream + * $x->addFileFromPsr7Stream('streamfile.txt', $fp); + * + * @return void + */ + + public function addFileFromPsr7Stream( + string $name, + StreamInterface $stream, + ?FileOptions $options = null + ): void + { + $options = $options ?: new FileOptions(); + $options->defaultTo($this->opt); + + $file = new File($this, $name, $options); + $file->processStream($stream); + } + + /** + * finish + * + * Write zip footer to stream. + * + * Example: + * + * // add a list of files to the archive + * $files = array('foo.txt', 'bar.jpg'); + * foreach ($files as $path) + * $zip->addFile($path, file_get_contents($path)); + * + * // write footer to stream + * $zip->finish(); + * @return void + * + * @throws OverflowException + */ + public function finish(): void + { + // add trailing cdr file records + foreach ($this->files as $cdrFile) { + $this->send($cdrFile); + $this->cdr_ofs = $this->cdr_ofs->add(Bigint::init(strlen($cdrFile))); + } + + // Add 64bit headers (if applicable) + if (count($this->files) >= 0xFFFF || + $this->cdr_ofs->isOver32() || + $this->ofs->isOver32()) { + if (!$this->opt->isEnableZip64()) { + throw new OverflowException(); + } + + $this->addCdr64Eof(); + $this->addCdr64Locator(); + } + + // add trailing cdr eof record + $this->addCdrEof(); + + // The End + $this->clear(); + } + + /** + * Send string, sending HTTP headers if necessary. + * Flush output after write if configure option is set. + * + * @param String $str + * @return void + */ + public function send(string $str): void + { + if ($this->need_headers) { + $this->sendHttpHeaders(); + } + $this->need_headers = false; + + fwrite($this->opt->getOutputStream(), $str); + + if ($this->opt->isFlushOutput()) { + flush(); + ob_flush(); + } + } + + /** + * Send HTTP headers for this stream. + * + * @return void + */ + protected function sendHttpHeaders(): void + { + // grab content disposition + $disposition = $this->opt->getContentDisposition(); + + if ($this->output_name) { + // Various different browsers dislike various characters here. Strip them all for safety. + $safe_output = trim(str_replace(['"', "'", '\\', ';', "\n", "\r"], '', $this->output_name)); + + // Check if we need to UTF-8 encode the filename + $urlencoded = rawurlencode($safe_output); + $disposition .= "; filename*=UTF-8''{$urlencoded}"; + } + + $headers = array( + 'Content-Type' => $this->opt->getContentType(), + 'Content-Disposition' => $disposition, + 'Pragma' => 'public', + 'Cache-Control' => 'public, must-revalidate', + 'Content-Transfer-Encoding' => 'binary' + ); + + $call = $this->opt->getHttpHeaderCallback(); + foreach ($headers as $key => $val) { + $call("$key: $val"); + } + } + + /** + * Send ZIP64 CDR EOF (Central Directory Record End-of-File) record. + * + * @return void + */ + protected function addCdr64Eof(): void + { + $num_files = count($this->files); + $cdr_length = $this->cdr_ofs; + $cdr_offset = $this->ofs; + + $fields = [ + ['V', static::ZIP64_CDR_EOF_SIGNATURE], // ZIP64 end of central file header signature + ['P', 44], // Length of data below this header (length of block - 12) = 44 + ['v', static::ZIP_VERSION_MADE_BY], // Made by version + ['v', Version::ZIP64], // Extract by version + ['V', 0x00], // disk number + ['V', 0x00], // no of disks + ['P', $num_files], // no of entries on disk + ['P', $num_files], // no of entries in cdr + ['P', $cdr_length], // CDR size + ['P', $cdr_offset], // CDR offset + ]; + + $ret = static::packFields($fields); + $this->send($ret); + } + + /** + * Create a format string and argument list for pack(), then call + * pack() and return the result. + * + * @param array $fields + * @return string + */ + public static function packFields(array $fields): string + { + $fmt = ''; + $args = []; + + // populate format string and argument list + foreach ($fields as [$format, $value]) { + if ($format === 'P') { + $fmt .= 'VV'; + if ($value instanceof Bigint) { + $args[] = $value->getLow32(); + $args[] = $value->getHigh32(); + } else { + $args[] = $value; + $args[] = 0; + } + } else { + if ($value instanceof Bigint) { + $value = $value->getLow32(); + } + $fmt .= $format; + $args[] = $value; + } + } + + // prepend format string to argument list + array_unshift($args, $fmt); + + // build output string from header and compressed data + return pack(...$args); + } + + /** + * Send ZIP64 CDR Locator (Central Directory Record Locator) record. + * + * @return void + */ + protected function addCdr64Locator(): void + { + $cdr_offset = $this->ofs->add($this->cdr_ofs); + + $fields = [ + ['V', static::ZIP64_CDR_LOCATOR_SIGNATURE], // ZIP64 end of central file header signature + ['V', 0x00], // Disc number containing CDR64EOF + ['P', $cdr_offset], // CDR offset + ['V', 1], // Total number of disks + ]; + + $ret = static::packFields($fields); + $this->send($ret); + } + + /** + * Send CDR EOF (Central Directory Record End-of-File) record. + * + * @return void + */ + protected function addCdrEof(): void + { + $num_files = count($this->files); + $cdr_length = $this->cdr_ofs; + $cdr_offset = $this->ofs; + + // grab comment (if specified) + $comment = $this->opt->getComment(); + + $fields = [ + ['V', static::CDR_EOF_SIGNATURE], // end of central file header signature + ['v', 0x00], // disk number + ['v', 0x00], // no of disks + ['v', min($num_files, 0xFFFF)], // no of entries on disk + ['v', min($num_files, 0xFFFF)], // no of entries in cdr + ['V', $cdr_length->getLowFF()], // CDR size + ['V', $cdr_offset->getLowFF()], // CDR offset + ['v', strlen($comment)], // Zip Comment size + ]; + + $ret = static::packFields($fields) . $comment; + $this->send($ret); + } + + /** + * Clear all internal variables. Note that the stream object is not + * usable after this. + * + * @return void + */ + protected function clear(): void + { + $this->files = []; + $this->ofs = new Bigint(); + $this->cdr_ofs = new Bigint(); + $this->opt = new ArchiveOptions(); + } + + /** + * Is this file larger than large_file_size? + * + * @param string $path + * @return bool + */ + public function isLargeFile(string $path): bool + { + if (!$this->opt->isStatFiles()) { + return false; + } + $stat = stat($path); + return $stat['size'] > $this->opt->getLargeFileSize(); + } + + /** + * Save file attributes for trailing CDR record. + * + * @param File $file + * @return void + */ + public function addToCdr(File $file): void + { + $file->ofs = $this->ofs; + $this->ofs = $this->ofs->add($file->getTotalLength()); + $this->files[] = $file->getCdrFile(); + } +} diff --git a/twake/backend/core/src/Twake/GlobalSearch/Bundle.php b/twake/backend/core/src/Twake/GlobalSearch/Bundle.php new file mode 100755 index 00000000..7691b8c6 --- /dev/null +++ b/twake/backend/core/src/Twake/GlobalSearch/Bundle.php @@ -0,0 +1,30 @@ +<?php + +namespace Twake\GlobalSearch; + +require_once __DIR__ . "/Resources/Routing.php"; +require_once __DIR__ . "/Resources/Services.php"; + +use Twake\GlobalSearch\Resources\Routing; +use Twake\GlobalSearch\Resources\Services; +use Common\BaseBundle; + +class Bundle extends BaseBundle +{ + + protected $bundle_root = __DIR__; + protected $bundle_namespace = __NAMESPACE__; + protected $routes = []; + protected $services = []; + + public function init() + { + $routing = new Routing(); + $this->routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/GlobalSearch/Controller/GlobalSearch.php b/twake/backend/core/src/Twake/GlobalSearch/Controller/GlobalSearch.php new file mode 100755 index 00000000..e2c7e2a3 --- /dev/null +++ b/twake/backend/core/src/Twake/GlobalSearch/Controller/GlobalSearch.php @@ -0,0 +1,131 @@ +<?php + + +namespace Twake\GlobalSearch\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class GlobalSearch extends BaseController +{ + + public function QuickSearch(Request $request) + { + + $current_user = $this->getUser(); + $words = $identifier = $request->request->get("words"); + $group_id = $request->request->get("group_id"); + $workspace_id = $request->request->get("workspace_id"); + $current_user_id = $current_user->getId(); + + $globalresult = $this->get('globalsearch.quicksearch')->QuickSearch($current_user_id, $words, $group_id, $workspace_id); + + $this->get("administration.counter")->incrementCounter("total_quicksearch", 1); + + $data = Array("data" => $globalresult); + return new Response($data); + + } + + public function AdvancedBloc(Request $request) + { + + $scroll_id = $request->request->get("scroll_id"); + $repository = "Twake\GlobalSearch:Bloc"; + + $options = $request->request->get("options"); + $channels = $options["channel_id"] ?: $request->request->get("channel_id"); + + if (isset($scroll_id) && isset($repository)) { + $options["scroll_id"] = $scroll_id; + } + + $current_user = $this->getUser(); + $current_user_id = $current_user->getId(); + + $options["words"] = $options["words"] ? $options["words"] : $request->request->get("words"); + + $globalresult = $this->get('globalsearch.advancedbloc')->AdvancedBloc($current_user_id, $options, $channels); + + $this->get("administration.counter")->incrementCounter("total_search", 1); + + $data = Array("data" => $globalresult); + return new Response($data); + } + + public function AdvancedFile(Request $request) + { + + $scroll_id = $request->request->get("scroll_id"); + $repository = "Twake\GlobalSearch:Bloc"; + + + $options = $request->request->get("options"); + $workspaces = $request->request->get("workspace_id"); + + if (isset($scroll_id) && isset($repository)) { + $options["scroll_id"] = $scroll_id; + } + + $current_user = $this->getUser(); + $current_user_id = $current_user->getId(); + + $options["name"] = $options["name"] ? $options["name"] : join(" ", $request->request->get("words")); + + $globalresult = $this->get('globalsearch.advancedfile')->AdvancedFile($current_user_id, $options, $workspaces); + + $data = Array("data" => $globalresult); + return new Response($data); + } + + public function AdvancedTask(Request $request) + { + + $scroll_id = $request->request->get("scroll_id"); + $repository = "Twake\Tasks:Task"; + + + $options = $request->request->get("options"); + $workspaces = $request->request->get("workspace_id"); + + if (isset($scroll_id) && isset($repository)) { + $options["scroll_id"] = $scroll_id; + } + + $current_user = $this->getUser(); + $current_user_id = $current_user->getId(); + + $options["name"] = $options["name"] ? $options["name"] : join(" ", $request->request->get("words")); + + $globalresult = $this->get('globalsearch.advancedtask')->AdvancedTask($current_user_id, $options, $workspaces); + + $data = Array("data" => $globalresult); + return new Response($data); + } + + public function AdvancedEvent(Request $request) + { + + $scroll_id = $request->request->get("scroll_id"); + $repository = "Twake\Calendar:Event"; + + $options = $request->request->get("options"); + $workspaces = $request->request->get("workspace_id"); + + if (isset($scroll_id) && isset($repository)) { + $options["scroll_id"] = $scroll_id; + } + + $current_user = $this->getUser(); + $current_user_id = $current_user->getId(); + + $options["name"] = $options["name"] ? $options["name"] : join(" ", $request->request->get("words")); + + $globalresult = $this->get('globalsearch.advancedevent')->AdvancedEvent($current_user_id, $options, $workspaces); + + $data = Array("data" => $globalresult); + return new Response($data); + } + +} diff --git a/twake/backend/core/src/Twake/GlobalSearch/Controller/Tag.php b/twake/backend/core/src/Twake/GlobalSearch/Controller/Tag.php new file mode 100755 index 00000000..359756f9 --- /dev/null +++ b/twake/backend/core/src/Twake/GlobalSearch/Controller/Tag.php @@ -0,0 +1,51 @@ +<?php + +namespace Twake\GlobalSearch\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class Tag extends BaseController +{ + + public function remove(Request $request) + { + $options = $request->request->get("options"); + $object = $request->request->get("object"); + + $res = $this->get("globalsearch.tag")->remove($object, $options, $this->getUser()); + if (!$res) { + return new Response(Array("status" => "error")); + } + return new Response(Array("data" => Array("object" => $res))); + } + + public function save(Request $request) + { + $options = $request->request->get("options"); + $object = $request->request->get("object"); + + $res = $this->get("globalsearch.tag")->save($object, $options, $this->getUser(), Array()); + + if (!$res) { + return new Response(Array("status" => "error")); + } + return new Response(Array("data" => Array("object" => $res))); + + + } + + public function getAction(Request $request) + { + $options = $request->request->get("options"); + $objects = $this->get("globalsearch.tag")->get($options, $this->getUser()); + + if ($objects === false) { + return new Response(Array("status" => "error")); + } + return new Response(Array("data" => $objects)); + } + +} + diff --git a/twake/backend/core/src/Twake/GlobalSearch/Entity/Bloc.php b/twake/backend/core/src/Twake/GlobalSearch/Entity/Bloc.php new file mode 100755 index 00000000..f5af8241 --- /dev/null +++ b/twake/backend/core/src/Twake/GlobalSearch/Entity/Bloc.php @@ -0,0 +1,308 @@ +<?php + + +namespace Twake\GlobalSearch\Entity; + +use Doctrine\ORM\Mapping as ORM; + +use Twake\Core\Entity\SearchableObject; + +/** + * Bloc + * + * @ORM\Table(name="bloc",options={"engine":"MyISAM", "scylladb_keys": {{"workspace_id": "ASC", "channel_id": "ASC", "id": "DESC"}, {"channel_id": "ASC"} , {"id": "ASC"} } }) + * @ORM\Entity() + */ +class Bloc extends SearchableObject +{ + + protected $es_type = "message_bloc"; + + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + protected $id; + /** + * @ORM\Column(name="workspace_id", type="twake_timeuuid") + * @ORM\Id + */ + protected $workspace_id; + /** + * @ORM\Column(name="channel_id", type="twake_uuid") + * @ORM\Id + */ + protected $channel_id; + + /** + * @ORM\Column(name ="nb_message", type="integer", nullable=true) + */ + protected $nb_message = 0; + + /** + * @ORM\Column(name ="messages", type="twake_text", nullable=true) + */ + protected $messages; + + /** + * @ORM\Column(name ="id_messages", type="twake_text", nullable=true) + */ + protected $id_messages; + + /** + * @ORM\Column(name ="lock", type="twake_boolean") + */ + protected $lock = false; + + + /** + * Bloc constructor. + * @param string $workspace_id + * @param string $channel_id + * @param int $nb_message + * @param $content_keywords + */ + public function __construct($workspace_id, $channel_id, $messages, $id_messages) + { + $this->workspace_id = $workspace_id; + $this->channel_id = $channel_id; + $this->messages = json_encode($messages); + $this->id_messages = json_encode($id_messages); + } + + + public function getAsArray() + { + $return = Array( + "id" => $this->getId(), + "channel_id" => $this->getChannelId(), + "workspace_id" => $this->getWorkspaceId(), + "nb_message" => $this->getNbMessage(), + "messages" => $this->getMessages(), + "id_messages" => $this->getIdMessages() + + ); + return $return; + } + + public function getIndexationArray() + { + if ($this->getLock() == true) { + $return = Array( + "id" => $this->getId() . "", + "channel_id" => $this->getChannelId(), + "workspace_id" => $this->getWorkspaceId(), + "messages" => $this->getMessages() + ); + } else + $return = Array(); + return $return; + } + + /** + * @return mixed + */ + public function getIdMessages() + { + return json_decode($this->id_messages, true); + } + + + /** + * @param mixed $id_messages + */ + public function setIdMessages($id_messages) + { + $this->id_messages = json_encode($id_messages); + } + + /** + * @return string + */ + public function getEsType() + { + return $this->es_type; + } + + /** + * @return mixed + */ + public function getMessages() + { + return json_decode($this->messages, true); + } + + /** + * @param mixed $messages + */ + public function setMessages($messages) + { + $this->messages = json_encode($messages); + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @param int $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getLock() + { + return $this->lock; + } + + /** + * @param mixed $lock + */ + public function setLock($lock) + { + $this->lock = $lock; + } + + /** + * @return mixed + */ + public function getWorkspaceId() + { + return $this->workspace_id; + } + + /** + * @param mixed $workspace_id + */ + public function setWorkspaceId($workspace_id) + { + $this->workspace_id = $workspace_id; + } + + /** + * @return mixed + */ + public function getChannelId() + { + return $this->channel_id; + } + + /** + * @param mixed $channel_id + */ + public function setChannelId($channel_id) + { + $this->channel_id = $channel_id; + } + + /** + * @return mixed + */ + public function getNbMessage() + { + return $this->nb_message; + } + + /** + * @param mixed $nb_message + */ + public function setNbMessage($nb_message) + { + $this->nb_message = $nb_message; + } + + public function removeMessage($message_id) + { + $messages = $this->getMessages(); + if (!$messages) { + $messages = Array(); + } + + $id_messages = Array(); + $new_messages = Array(); + foreach ($messages as $index => $message) { + if ($message) { + if ($message["id"] != $message_id) { + $new_messages[] = $message; + $id_messages[] = $message["id"]; + } + } + } + + $this->setNbMessage(count($messages)); + $this->setMessages($messages); + $this->setIdMessages($id_messages); + + } + + public function addOrUpdateMessage($message, $content, $content_id) + { + + if (!$message) { + return false; + } + + $messages = $this->getMessages(); + if (!$messages) { + $messages = Array(); + } + + $id_messages = Array(); + $message_exists = -1; + foreach ($messages as $index => $m) { + if ($m) { + $id_messages[] = $m["id"]; + if ($m["id"] == $message->getId()) { + $message_exists = $index; + } + } + } + + $reactions_tmp = $message->getReactions(); + $reactions = Array(); + foreach ($reactions_tmp as $reaction => $count) { + $reactions[] = $reaction; + } + + preg_match_all("/\w*-\w*-\w*-\w*-\w*/i", $content_id, $mentions_matches); + $mentions_matches = $mentions_matches[0]; + $mentions_matches = array_unique($mentions_matches); + + $formatted_message = Array( + "id" => $message->getId(), + "mentions" => $mentions_matches, + "reactions" => $reactions, + "content" => $content, + "sender" => $message->getSender() ? $message->getSender()->getId() . "" : null, + "application_id" => $message->getApplicationId(), + "date" => $message->getCreationDate()->format('Y-m-d'), + "tags" => $message->getTags(), + "pinned" => $message->getPinned() + ); + + if ($message_exists >= 0) { + $messages[$index] = $formatted_message; + } else { + $messages[] = $formatted_message; + $id_messages[] = $message->getId(); + $this->setNbMessage($this->getNbMessage() + 1); + } + + $this->setNbMessage(count($messages)); + $this->setMessages($messages); + $this->setIdMessages($id_messages); + + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/GlobalSearch/Entity/SearchHistory.php b/twake/backend/core/src/Twake/GlobalSearch/Entity/SearchHistory.php new file mode 100755 index 00000000..0f0e8da3 --- /dev/null +++ b/twake/backend/core/src/Twake/GlobalSearch/Entity/SearchHistory.php @@ -0,0 +1,110 @@ +<?php + + +namespace Twake\GlobalSearch\Entity; + +use Doctrine\ORM\Mapping as ORM; + +use Twake\Core\Entity\SearchableObject; + +/** + * Bloc + * + * @ORM\Table(name="searchhistory",options={"engine":"MyISAM", "scylladb_keys": { {"user_id": "ASC"}, {"id": "ASC"} } }) + * @ORM\Entity() + */ +class SearchHistory +{ + + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + protected $id; + /** + * @ORM\Column(name="user_id", type="twake_timeuuid") + * @ORM\Id + */ + protected $user_id; + + /** + * @ORM\Column(name ="search", type="twake_text", nullable=true) + */ + protected $search; + + + public function __construct($user_id, $search) + { + $this->user_id = $user_id; + $this->search = $search; + } + + public function getAsArray() + { + $return = Array( + "id" => $this->getId(), + "user_id" => $this->getUserId(), + "search" => $this->getSearch() + ); + return $return; + } + + public function addSearch($temp) + { + $this->search[] = $temp; + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @param int $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getUserId() + { + return $this->user_id; + } + + /** + * @param mixed $user_id + */ + public function setUserId($user_id) + { + $this->user_id = $user_id; + } + + /** + * @return mixed + */ + public function getSearch() + { + return $this->search; + } + + /** + * @param mixed $search + */ + public function setSearch($search) + { + $this->search = $search; + } + + +} + + diff --git a/twake/backend/core/src/Twake/GlobalSearch/Entity/WorkspaceTag.php b/twake/backend/core/src/Twake/GlobalSearch/Entity/WorkspaceTag.php new file mode 100755 index 00000000..13a1d494 --- /dev/null +++ b/twake/backend/core/src/Twake/GlobalSearch/Entity/WorkspaceTag.php @@ -0,0 +1,127 @@ +<?php + +namespace Twake\GlobalSearch\Entity; + +use Doctrine\ORM\Mapping as ORM; + +use Twake\Core\Entity\FrontObject; + +/** + * Tag + * + * @ORM\Table(name="workspacetag",options={"engine":"MyISAM", "scylladb_keys": {{"workspace_id": "ASC", "id": "DESC"}, {"id": "ASC"} } }) + * @ORM\Entity() + */ +class WorkspaceTag extends FrontObject +{ + + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="workspace_id", type="twake_timeuuid") + * @ORM\Id + */ + protected $workspace_id; + + /** + * @ORM\Column(name ="name", type="twake_text", nullable=true) + */ + protected $name; + + /** + * @ORM\Column(name ="color", type="twake_text", nullable=true) + */ + protected $color; + + public function __construct($workspace_id, $name) + { + $this->workspace_id = $workspace_id; + $this->name = $name; + + } + + public function getAsArray() + { + $return = Array( + "id" => $this->getId(), + "front_id" => $this->getFrontId(), + "workspace_id" => $this->getWorkspaceId(), + "name" => $this->getName(), + "color" => $this->getColor() + ); + return $return; + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @param int $id + */ + public function setId($id) + { + $this->id = $id; + } + + + /** + * @return mixed + */ + public function getWorkspaceId() + { + return $this->workspace_id; + } + + /** + * @param mixed $workspace_id + */ + public function setWorkspaceId($workspace_id) + { + $this->workspace_id = $workspace_id; + } + + /** + * @return mixed + */ + public function getName() + { + return $this->name; + } + + /** + * @param mixed $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @return mixed + */ + public function getColor() + { + return $this->color; + } + + /** + * @param mixed $color + */ + public function setColor($color) + { + $this->color = $color; + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/GlobalSearch/Resources/Routing.php b/twake/backend/core/src/Twake/GlobalSearch/Resources/Routing.php new file mode 100755 index 00000000..dee4821b --- /dev/null +++ b/twake/backend/core/src/Twake/GlobalSearch/Resources/Routing.php @@ -0,0 +1,23 @@ +<?php + +namespace Twake\GlobalSearch\Resources; + +use Common\BaseRouting; + +class Routing extends BaseRouting +{ + + protected $routing_prefix = "ajax/globalsearch/"; + + protected $routes = [ + "quicksearch" => ["handler" => "GlobalSearch:QuickSearch", "methods" => ["POST"], "security" => ["user_connected_security"]], + "advancedbloc" => ["handler" => "GlobalSearch:AdvancedBloc", "methods" => ["POST"], "security" => ["user_connected_security"]], + "advancedfile" => ["handler" => "GlobalSearch:AdvancedFile", "methods" => ["POST"], "security" => ["user_connected_security"]], + "advancedtask" => ["handler" => "GlobalSearch:AdvancedTask", "methods" => ["POST"], "security" => ["user_connected_security"]], + "advancedevent" => ["handler" => "GlobalSearch:AdvancedEvent", "methods" => ["POST"], "security" => ["user_connected_security"]], + "tags/get" => ["handler" => "Tag:getAction", "methods" => ["POST"], "security" => ["user_connected_security"]], + "tags/save" => ["handler" => "Tag:save", "methods" => ["POST"], "security" => ["user_connected_security"]], + "tags/remove" => ["handler" => "Tag:remove", "methods" => ["POST"], "security" => ["user_connected_security"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/GlobalSearch/Resources/Services.php b/twake/backend/core/src/Twake/GlobalSearch/Resources/Services.php new file mode 100755 index 00000000..525491c0 --- /dev/null +++ b/twake/backend/core/src/Twake/GlobalSearch/Resources/Services.php @@ -0,0 +1,31 @@ +<?php + +namespace Twake\GlobalSearch\Resources; + +use Common\BaseServices; + +class Services extends BaseServices +{ + protected $services = [ + "globalsearch.quicksearch" => "QuickSearch", +// arguments: ["@app.twake_doctrine", "@app.users", "@app.workspaces", "@app.channels.channels_system", "@globalsearch.advancedfile", "@app.workspace_members", "@globalsearch.messagebloc"] + "globalsearch.advancedbloc" => "AdvancedBloc", +// arguments: ["@app.twake_doctrine", "@globalsearch.messagebloc", "@app.workspaces"] + "globalsearch.advancedfile" => "AdvancedFile", +// arguments: ["@app.twake_doctrine","@app.workspaces"] + "globalsearch.advancedtask" => "AdvancedTask", +// arguments: ["@app.twake_doctrine", "@app.workspaces"] + "globalsearch.advancedevent" => "AdvancedEvent", +// arguments: ["@app.twake_doctrine", "@app.workspaces"] + "globalsearch.messagebloc" => "Blocmessage", +// arguments: ["@app.twake_doctrine"] + "globalsearch.reindex" => "Reindex", +// arguments: ["@app.twake_doctrine"] + "globalsearch.mapping" => "Mapping", + "globalsearch.pagination" => "Pagination", +// arguments: ["@app.twake_doctrine"] + "globalsearch.tag" => "Tag", +// arguments: ["@app.twake_doctrine", "@app.accessmanager"] + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/GlobalSearch/Services/AdvancedBloc.php b/twake/backend/core/src/Twake/GlobalSearch/Services/AdvancedBloc.php new file mode 100755 index 00000000..f688a2c9 --- /dev/null +++ b/twake/backend/core/src/Twake/GlobalSearch/Services/AdvancedBloc.php @@ -0,0 +1,67 @@ +<?php + + +namespace Twake\GlobalSearch\Services; + +use App\App; + +class AdvancedBloc +{ + private $doctrine; + private $blocservice; + private $workspaceservice; + private $globalresult; + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->blocservice = $app->getServices()->get("globalsearch.messagebloc"); + $this->workspaceservice = $app->getServices()->get("app.workspaces"); + } + + public function AdvancedBloc($current_user_id, $options, $channels) + { + $this->globalresult = Array(); + $this->SearchInBloc($current_user_id, $options, $channels); + return $this->globalresult; + } + + public function SearchInBloc($current_user_id, $options, $channels) + { + + $channel_acces = Array(); + if (!$channels && !is_array($channels)) { + $channels_member = $this->doctrine->getRepository("Twake\Channels:ChannelMember")->findBy(Array("direct" => false, "user_id" => $current_user_id)); + foreach ($channels_member as $cm) { + $channel = $this->doctrine->getRepository("Twake\Channels:Channel")->findOneBy(Array("id" => $cm->getChannelId())); + if ($channel) { + $channel_acces[] = $channel; + } + } + $channels_member = $this->doctrine->getRepository("Twake\Channels:ChannelMember")->findBy(Array("direct" => true, "user_id" => $current_user_id)); + foreach ($channels_member as $cm) { + $channel = $this->doctrine->getRepository("Twake\Channels:Channel")->findOneBy(Array("id" => $cm->getChannelId())); + if ($channel) { + $channel_acces[] = $channel; + } + } + } else { + foreach ($channels as $channel) { + $member = $this->doctrine->getRepository("Twake\Channels:ChannelMember")->findOneBy(Array("direct" => false, "user_id" => $current_user_id, "channel_id" => $channel)); + if (!$member) { + $member = $this->doctrine->getRepository("Twake\Channels:ChannelMember")->findOneBy(Array("direct" => true, "user_id" => $current_user_id, "channel_id" => $channel)); + } + if ($member) { + $channel_acces[] = $channel; + } + } + } + + if (isset($channel_acces) && $channel_acces != Array()) { + $messages = $this->blocservice->search($options, $channel_acces); + $this->globalresult = $messages; + } + + } + +} diff --git a/twake/backend/core/src/Twake/GlobalSearch/Services/AdvancedEvent.php b/twake/backend/core/src/Twake/GlobalSearch/Services/AdvancedEvent.php new file mode 100755 index 00000000..c4f9c452 --- /dev/null +++ b/twake/backend/core/src/Twake/GlobalSearch/Services/AdvancedEvent.php @@ -0,0 +1,169 @@ +<?php + + +namespace Twake\GlobalSearch\Services; + +use App\App; + +class AdvancedEvent +{ + private $doctrine; + private $workspaceservice; + private $list_events = Array("results" => Array(), "scroll_id" => ""); + + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->workspaceservice = $app->getServices()->get("app.workspaces"); + + } + + + public function AdvancedEvent($current_user_id, $options, $workspaces) + { + $known_workspaces_by_id = Array(); + + //Prepare parameters + if (!$options["title"]) { + $options["title"] = $options["name"]; + } + + $workspace_access = []; + if (!$workspaces && !is_array($workspaces)) { + $workspace_access_tmp = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser")->findBy(Array("user_id" => $current_user_id)); + foreach ($workspace_access_tmp as $wp) { + $workspace_access[] = $wp->getWorkspace($this->doctrine); + } + } else { + foreach ($workspaces as $wp) { + if (!is_string($wp)) { + if (is_array($wp)) { + $known_workspaces_by_id[$wp["id"]] = $wp; + $wp = $wp["id"]; + } else { + $known_workspaces_by_id[$wp->getId()] = $wp->getAsArray(); + $wp = $wp->getId(); + } + } + $wp_entity = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser")->findOneBy(Array("workspace_id" => $wp, "user_id" => $current_user_id)); + if ($wp_entity) { + $workspace_access[] = $wp; + } + } + } + $workspaces = $workspace_access; + + $workspaces_ids = []; + foreach ($workspaces as $wp) { + if (!is_string($wp)) { + if (is_array($wp)) { + $known_workspaces_by_id[$wp["id"]] = $wp; + $wp = $wp["id"]; + } else { + $known_workspaces_by_id[$wp->getId()] = $wp->getAsArray(); + $wp = $wp->getId(); + } + } + $workspaces_ids[] = $wp; + } + $workspaces = $workspaces_ids; + + //on regarde avant l'acces pour ne faire qu'une requete sur ES et pour pouvoir profitier de l'ordonnocement par pertinence + if (isset($workspace_access) && $workspace_access != Array()) { + + $must = Array(); + + $visible_match = ESUtils::createShouldMatch($workspaces, "workspace_id", 1); + $visible_match["bool"]["should"][] = Array( + "match_phrase" => Array( + "participants" => $current_user_id + ) + ); + $must[] = $visible_match; + + $title = isset($options["title"]) ? preg_filter('/($|^)/', '.*', explode(" ", $options["title"])) : false; + ESUtils::createRegexShouldMatch($title, "title", "all", $must); + + $description = isset($options["description"]) ? preg_filter('/($|^)/', '.*', explode(" ", $options["description"])) : false; + ESUtils::createRegexShouldMatch($description, "description", "all", $must); + + $participants = isset($options["participants"]) ? $options["participants"] : false; + ESUtils::createShouldMatch($participants, "participants", "all", $must); + + $tags = isset($options["tags"]) ? $options["tags"] : false; + ESUtils::createShouldMatch($tags, "tags", "all", $must); + + $owner = isset($options["owner"]) ? $options["owner"] : false; + ESUtils::createMatchPhrase($owner, "owner", $must); + + + $date_from = isset($options["date_from"]) ? $options["date_from"] : false; + $date_to = isset($options["date_to"]) ? $options["date_to"] : false; + ESUtils::createRange($date_from, $date_to, "date_from", $must); + + $modified_before = isset($options["date_modified_before"]) ? $options["date_modified_before"] : false; + $modified_after = isset($options["date_modified_after"]) ? $options["date_modified_after"] : false; + ESUtils::createRange($modified_after, $modified_before, "date_last_modified", $must); + + $options = Array( + "repository" => "Twake\Calendar:Event", + "index" => "event", + "size" => 10, + "query" => Array( + "bool" => Array( + "must" => $must + ) + ), + "sort" => Array( + "date_from" => Array( + "order" => "desc", + ) + ) + ); + + if (isset($options["scroll_id"])) { + $options["scroll_id"] = $options["scroll_id"]; + } + + $result = $this->doctrine->es_search($options); + + //On traite les donnΓ©es recu d'Elasticsearch + foreach ($result["result"] as $event) { + + $workspaces_calendars = $event[0]->getWorkspacesCalendars(); + $workspace_id = null; + if ($workspaces_calendars) { + foreach ($workspaces_calendars as $workspace_calendar) { + $workspace_id = $workspace_calendar["workspace_id"]; + break; + } + } + + if ($workspace_id) { + if (!isset($known_workspaces_by_id[$workspace_id])) { + $workspace_entity = $this->doctrine->getRepository("Twake\Workspaces:Workspace")->findOneBy(Array("id" => $workspace_id)); + $known_workspaces_by_id[$workspace_id] = $workspace_entity->getAsArray(); + } + $workspace_array = $known_workspaces_by_id[$workspace_id]; + } + + $this->list_events["results"][] = Array( + "event" => $event[0]->getAsArray(), + "type" => "event", + "score" => $event[1][0], + "workspace" => $workspace_array + ); + } + + $scroll_id = $result["scroll_id"]; + $this->list_events["scroll_id"] = $scroll_id; + + $this->list_events["es"] = $options; + + return $this->list_events; + } + + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/GlobalSearch/Services/AdvancedFile.php b/twake/backend/core/src/Twake/GlobalSearch/Services/AdvancedFile.php new file mode 100755 index 00000000..60e34fb5 --- /dev/null +++ b/twake/backend/core/src/Twake/GlobalSearch/Services/AdvancedFile.php @@ -0,0 +1,154 @@ +<?php + + +namespace Twake\GlobalSearch\Services; + +use App\App; + +class AdvancedFile +{ + private $doctrine; + private $workspaceservice; + private $globalresult; + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->workspaceservice = $app->getServices()->get("app.workspaces"); + + } + + + public function AdvancedFile($current_user_id, $options, $workspaces) + { + $known_workspaces_by_id = Array(); + + //Prepare parameters + if (!$options["name"]) { + $options["name"] = $options["title"]; + } + + $workspace_access = []; + if (!$workspaces && !is_array($workspaces)) { + $workspace_access_tmp = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser")->findBy(Array("user_id" => $current_user_id)); + foreach ($workspace_access_tmp as $wp) { + $workspace_access[] = $wp->getWorkspace($this->doctrine); + } + } else { + foreach ($workspaces as $wp) { + if (!is_string($wp)) { + if (is_array($wp)) { + $known_workspaces_by_id[$wp["id"]] = $wp; + $wp = $wp["id"]; + } else { + $known_workspaces_by_id[$wp->getId()] = $wp->getAsArray(); + $wp = $wp->getId(); + } + } + $wp_entity = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser")->findOneBy(Array("workspace_id" => $wp, "user_id" => $current_user_id)); + if ($wp_entity) { + $workspace_access[] = $wp; + } + } + } + $workspaces = $workspace_access; + + $workspaces_ids = []; + foreach ($workspaces as $wp) { + if (!is_string($wp)) { + if (is_array($wp)) { + $known_workspaces_by_id[$wp["id"]] = $wp; + $wp = $wp["id"]; + } else { + $known_workspaces_by_id[$wp->getId()] = $wp->getAsArray(); + $wp = $wp->getId(); + } + } + $workspaces_ids[] = $wp; + } + $workspaces = $workspaces_ids; + + //on regarde avant l'acces pour ne faire qu'une requete sur ES et pour pouvoir profitier de l'ordonnocement par pertinence + if (isset($workspace_access) && $workspace_access != Array()) { + + $must = Array(); + + ESUtils::createShouldMatch($workspaces, "workspace_id", 1, $must); + + $name = isset($options["name"]) ? preg_filter('/($|^)/', '.*', explode(" ", $options["name"])) : false; + ESUtils::createNestedRegexShouldMatch($name, "keywords.keyword", "all", $must); + + $tags = isset($options["tags"]) ? $options["tags"] : false; + ESUtils::createShouldMatch($tags, "tags", "all", $must); + + $size_lte = isset($options["size_lte"]) ? $options["size_lte"] : false; + $size_gte = isset($options["size_gte"]) ? $options["size_gte"] : false; + ESUtils::createRange($size_gte, $size_lte, "size", $must); + + $create_before = (isset($options["date_create_before"]) && $options["date_create_before"]) ? date('Y-m-d', intval($options["date_create_before"])) : false; + $create_after = (isset($options["date_create_after"]) && $options["date_create_after"]) ? date('Y-m-d', intval($options["date_create_after"])) : false; + ESUtils::createRange($create_after, $create_before, "creation_date", $must); + + $modified_before = (isset($options["date_modified_before"]) && $options["date_modified_before"]) ? date('Y-m-d', intval($options["date_modified_before"])) : false; + $modified_after = (isset($options["date_modified_after"]) && $options["date_modified_before"]) ? date('Y-m-d', intval($options["date_modified_after"])) : false; + ESUtils::createRange($modified_after, $modified_before, "date_last_modified", $must); + + + $creator = isset($options["creator"]) ? $options["creator"] : false; + ESUtils::createMatchPhrase($creator, "creator", $must); + + $type = isset($options["type"]) ? (is_array($options["type"]) ? $options["type"] : [$type]) : false; + ESUtils::createShouldMatch($type, "type", 1, $must); + + $options = Array( + "repository" => "Twake\Drive:DriveFile", + "index" => "drive_file", + "size" => 10, + "query" => Array( + "bool" => Array( + "must" => $must + ) + ) + ); + + if (isset($options["scroll_id"])) { + $options["scroll_id"] = $options["scroll_id"]; + } + + $result = $this->doctrine->es_search($options); + + $this->list_files["results"] = []; + + //On traite les donnΓ©es recu d'Elasticsearch + foreach ($result["result"] as $file) { + + if ($file[0] && ($file[0]->getParentId() == "removed_trashes" || $file[0]->getIsInTrash())) { + $this->doctrine->es_remove($file[0], $file[0]->getEsType(), $file[0]->getEsIndex()); + continue; + } + + if (!isset($known_workspaces_by_id[$file[0]->getAsArray()["workspace_id"]])) { + $workspace_entity = $this->doctrine->getRepository("Twake\Workspaces:Workspace")->findOneBy(Array("id" => $file[0]->getAsArray()["workspace_id"])); + $known_workspaces_by_id[$file[0]->getAsArray()["workspace_id"]] = $workspace_entity->getAsArray(); + } + $workspace_array = $known_workspaces_by_id[$file[0]->getAsArray()["workspace_id"]]; + + $this->list_files["results"][] = Array( + "file" => $file[0]->getAsArray(), + "type" => "file", + "score" => $file[1][0], + "workspace" => $workspace_array + ); + + } + + $scroll_id = $result["scroll_id"]; + $this->list_files["scroll_id"] = $scroll_id; + + $this->list_files["es"] = $options; + + return $this->list_files; + } + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/GlobalSearch/Services/AdvancedTask.php b/twake/backend/core/src/Twake/GlobalSearch/Services/AdvancedTask.php new file mode 100755 index 00000000..dd6a9e08 --- /dev/null +++ b/twake/backend/core/src/Twake/GlobalSearch/Services/AdvancedTask.php @@ -0,0 +1,180 @@ +<?php + + +namespace Twake\GlobalSearch\Services; + +use App\App; + +class AdvancedTask +{ + private $doctrine; + private $workspaceservice; + private $list_tasks = Array("results" => Array(), "scroll_id" => ""); + + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->workspaceservice = $app->getServices()->get("app.workspaces"); + + } + + + public function AdvancedTask($current_user_id, $options, $workspaces) + { + $known_workspaces_by_id = Array(); + $known_boards_by_id = Array(); + $known_lists_by_id = Array(); + + //Prepare parameters + if (!$options["title"]) { + $options["title"] = $options["name"]; + } + + $workspace_access = []; + if (!$workspaces && !is_array($workspaces)) { + $workspace_access_tmp = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser")->findBy(Array("user_id" => $current_user_id)); + foreach ($workspace_access_tmp as $wp) { + $workspace_access[] = $wp->getWorkspace($this->doctrine); + } + } else { + foreach ($workspaces as $wp) { + if (!is_string($wp)) { + if (is_array($wp)) { + $known_workspaces_by_id[$wp["id"]] = $wp; + $wp = $wp["id"]; + } else { + $known_workspaces_by_id[$wp->getId()] = $wp->getAsArray(); + $wp = $wp->getId(); + } + } + $wp_entity = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser")->findOneBy(Array("workspace_id" => $wp, "user_id" => $current_user_id)); + if ($wp_entity) { + $workspace_access[] = $wp; + } + } + } + $workspaces = $workspace_access; + + $workspaces_ids = []; + foreach ($workspaces as $wp) { + if (!is_string($wp)) { + if (is_array($wp)) { + $known_workspaces_by_id[$wp["id"]] = $wp; + $wp = $wp["id"]; + } else { + $known_workspaces_by_id[$wp->getId()] = $wp->getAsArray(); + $wp = $wp->getId(); + } + } + $workspaces_ids[] = $wp; + } + $workspaces = $workspaces_ids; + + + //On commence le travail de crΓ©ation de la query + if (isset($workspace_access) && $workspace_access != Array()) { + + $must = Array(); + + ESUtils::createShouldMatch($workspaces, "workspace_id", 1, $must); + + $title = isset($options["title"]) ? preg_filter('/($|^)/', '.*', explode(" ", $options["title"])) : false; + ESUtils::createRegexShouldMatch($title, "title", "all", $must); + + $description = isset($options["description"]) ? preg_filter('/($|^)/', '.*', explode(" ", $options["description"])) : false; + ESUtils::createRegexShouldMatch($description, "description", "all", $must); + + $participants = isset($options["participants"]) ? $options["participants"] : false; + ESUtils::createShouldMatch($participants, "participants", "all", $must); + + $tags = isset($options["tags"]) ? $options["tags"] : false; + ESUtils::createShouldMatch($tags, "tags", "all", $must); + + $owner = isset($options["owner"]) ? $options["owner"] : false; + ESUtils::createMatchPhrase($owner, "owner", $must); + + $date_created_after = isset($options["date_created_after"]) ? $options["date_created_after"] : false; + $date_created_before = isset($options["date_created_before"]) ? $options["date_created_before"] : false; + ESUtils::createRange($date_created_after, $date_created_before, "date_created", $must); + + $modified_before = isset($options["date_modified_before"]) ? $options["date_modified_before"] : false; + $modified_after = isset($options["date_modified_after"]) ? $options["date_modified_after"] : false; + ESUtils::createRange($modified_after, $modified_before, "date_last_modified", $must); + + $before_before = isset($options["before_before"]) ? $options["before_before"] : false; + $before_after = isset($options["before_after"]) ? $options["before_after"] : false; + ESUtils::createRange($before_after, $before_before, "before", $must); + + $start_time_before = isset($options["start_time_before"]) ? $options["start_time_before"] : false; + $start_time_after = isset($options["start_time_after"]) ? $options["start_time_after"] : false; + ESUtils::createRange($start_time_after, $start_time_before, "start", $must); + + $options = Array( + "repository" => "Twake\Tasks:Task", + "index" => "task", + "size" => 10, + "query" => Array( + "bool" => Array( + "must" => $must + ) + ), + "sort" => Array( + "date_last_modified" => Array( + "order" => "desc", + ) + ) + ); + + if (isset($options["scroll_id"])) { + $options["scroll_id"] = $options["scroll_id"]; + } + + $result = $this->doctrine->es_search($options); + + //On traite les donnΓ©es recu d'Elasticsearch + foreach ($result["result"] as $task) { + + $list_id = $task[0]->getAsArray()["list_id"]; + $board_id = $task[0]->getAsArray()["board_id"]; + $workspace_id = $task[0]->getAsArray()["workspace_id"]; + + if (!isset($known_workspaces_by_id[$workspace_id])) { + $workspace_entity = $this->doctrine->getRepository("Twake\Workspaces:Workspace")->findOneBy(Array("id" => $workspace_id)); + $known_workspaces_by_id[$workspace_id] = $workspace_entity->getAsArray(); + } + $workspace_array = $known_workspaces_by_id[$workspace_id]; + + if (!isset($known_lists_by_id[$list_id])) { + $list_entity = $this->doctrine->getRepository("Twake\Tasks:BoardList")->findOneBy(Array("id" => $list_id)); + $known_lists_by_id[$list_id] = $list_entity->getAsArray(); + } + $list_array = $known_lists_by_id[$list_id]; + + if (!isset($known_boards_by_id[$board_id])) { + $board_entity = $this->doctrine->getRepository("Twake\Tasks:Board")->findOneBy(Array("id" => $board_id)); + $known_boards_by_id[$board_id] = $board_entity->getAsArray(); + } + $board_array = $known_boards_by_id[$board_id]; + + $this->list_tasks["results"][] = Array( + "task" => $task[0]->getAsArray(), + "type" => "task", + "score" => $task[1][0], + "workspace" => $workspace_array, + "board" => $board_array, + "list" => $list_array + ); + } + + $scroll_id = $result["scroll_id"]; + $this->list_tasks["scroll_id"] = $scroll_id; + + $this->list_tasks["es"] = $options; + + return $this->list_tasks; + } + + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/GlobalSearch/Services/Blocmessage.php b/twake/backend/core/src/Twake/GlobalSearch/Services/Blocmessage.php new file mode 100755 index 00000000..d8d64969 --- /dev/null +++ b/twake/backend/core/src/Twake/GlobalSearch/Services/Blocmessage.php @@ -0,0 +1,315 @@ +<?php + +namespace Twake\GlobalSearch\Services; + +use App\App; + +class Blocmessage + +{ + private $doctrine; + + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + } + + public function search($options, $channels) + { + + $known_channels_by_id = Array(); + $known_workspaces_by_id = Array(); + + $doublon_id = Array(); + $list_messages = Array("results" => Array(), "scroll_id" => ""); + + $final_words = Array(); + if (isset($options["words"])) { + foreach ($options["words"] as $word) { + if (strlen($word) >= 2) { + $final_words[] = strtolower($word); + } + } + } + + $channels_ids = []; + foreach ($channels as $channel) { + if (is_object($channel)) { + $known_channels_by_id[$channel->getId()] = $channel->getAsArray(); + $channel = $channel->getId(); + } + if (is_array($channel)) { + $known_channels_by_id[$channel["id"]] = $channel; + $channel = $channel["id"]; + } + $channels_ids[] = $channel; + } + $channels = $channels_ids; + + $must = Array(); + + + $words = count($final_words) > 0 ? preg_filter('/($|^)/', '.*', $final_words) : false; + ESUtils::createRegexShouldMatch($words, "messages.content", "all", $must); + + $reactions = isset($options["reactions"]) ? $options["reactions"] : false; + ESUtils::createShouldMatch($reactions, "messages.reactions", "all", $must); + + + $mentions = isset($options["mentions"]) ? $options["mentions"] : false; + ESUtils::createShouldMatch($mentions, "messages.mentions", "all", $must); + + $tags = isset($options["tags"]) ? $options["tags"] : false; + ESUtils::createShouldMatch($tags, "messages.tags", "all", $must); + + $pinned = (isset($options["pinned"]) && $options["pinned"]) ? $options["pinned"] : false; + ESUtils::createMatchPhrase($pinned, "messages.pinned", $must); + + $created_before = isset($options["date_before"]) ? date("Y-m-d", intval($options["date_before"])) : false; + $created_after = isset($options["date_after"]) ? date("Y-m-d", intval($options["date_after"])) : false; + ESUtils::createRange($created_after, $created_before, "messages.date", $must); + + $sender = isset($options["sender"]) ? $options["sender"] : false; + ESUtils::createMatchPhrase($sender, "messages.sender", $must); + + $application_id = isset($options["application_id"]) ? $options["application_id"] : false; + ESUtils::createMatchPhrase($application_id, "messages.application_id", $must); + + $should_channels = Array(); + foreach ($channels as $channel) { + $should_channels[] = Array( + "match_phrase" => Array( + "channel_id" => $channel + ) + ); + } + + $search_data = Array( + "repository" => "Twake\GlobalSearch:Bloc", + "index" => "message_bloc", + "size" => 10, + "query" => Array( + "bool" => Array( + "must" => Array( + Array( + "bool" => Array( + "should" => Array( + $should_channels + ), + "minimum_should_match" => 1 + ) + ), + Array( + "nested" => Array( + "path" => "messages", + "score_mode" => "avg", + "query" => Array( + "bool" => Array( + "must" => $must + ) + ) + ) + ) + ) + ) + ) + ); + + + // search in ES + $result = $this->doctrine->es_search($search_data); + $list_messages["scroll_id"] = $result["scroll_id"]; + + $list_messages["es_res"] = count($result["result"]); + + $blocs = []; + foreach ($result["result"] as $bloc) { + $blocs[] = $bloc[0]; + } + + // on cherche dans le bloc en cours de construction de tout les channels demandΓ©s + foreach ($channels as $channel) { + $lastbloc = $this->doctrine->getRepository("Twake\GlobalSearch:Bloc")->findOneBy(Array("channel_id" => $channel)); + if (isset($lastbloc) && $lastbloc->getLock() == false) { + $blocs[] = $lastbloc; + } + } + + foreach ($blocs as $bloc) { + $messages = $bloc->getMessages(); + foreach ($messages as $message) { + + if (!is_array($message)) { + continue; + } + + $message_id_in_bloc = $message["id"]; + + if ($message_id_in_bloc) { + + $valid = $this->verif_valid(null, $message, $options); + + if ($valid && !in_array($message_id_in_bloc, $doublon_id)) { + + $message_bdd = $this->doctrine->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $message["id"])); + + if(!$message_bdd){ + continue; + } + + $doublon_id[] = $message_id_in_bloc; + + if (!isset($known_channels_by_id[$message_bdd->getChannelId()])) { + $channel_entity = $this->doctrine->getRepository("Twake\Channels:Channel")->findOneBy(Array("id" => $message_bdd->getChannelId())); + $known_channels_by_id[$message_bdd->getChannelId()] = $channel_entity->getAsArray(); + } + + $workspace_array = null; + if ($channel_array["original_workspace"]) { + if (!isset($known_workspaces_by_id[$channel_array["original_workspace"]])) { + $workspace_entity = $this->doctrine->getRepository("Twake\Workspaces:Workspace")->findOneBy(Array("id" => $channel_array["original_workspace"])); + $known_workspaces_by_id[$channel_array["original_workspace"]] = $workspace_entity->getAsArray(); + } + $workspace_array = $known_workspaces_by_id[$channel_array["original_workspace"]]; + } + + $channel_array = $known_channels_by_id[$message_bdd->getChannelId()]; + + $list_messages["results"][] = Array( + "score" => 1, + "type" => "message", + "message" => $message_bdd->getAsArray(), + "channel" => $channel_array, + "workspace" => $workspace_array + ); + } + + } + + } + } + + + return $list_messages; + + } + + public function verif_valid($message_bdd, $message_array, $options) + { + + $final_words = Array(); + if (isset($options["words"])) { + foreach ($options["words"] as $word) { + $final_words[] = strtolower($word); + } + } + + $valid = true; + + foreach ($final_words as $word) { + if ($word) { + if ($valid && isset($message_array["content"]) && strpos(strtolower($message_array["content"]), strtolower($word)) !== false) { + } else { + $valid = false; + } + } + } + + if ($valid && isset($options["sender"])) { + if ($message_array["sender"] . "" != $options["sender"]) { + $valid = false; + } + } + if ($valid && isset($options["date_before"]) && ( + (\DateTime::createFromFormat("Y-m-d", $message_array["date"]))->getTimestamp() > + intval($options["date_before"]) + ) + ) { + $valid = false; + } + if ($valid && isset($options["date_after"]) && ( + (\DateTime::createFromFormat("Y-m-d", $message_array["date"]))->getTimestamp() < + intval($options["date_after"]) + )) { + $valid = false; + } + + if ($valid && isset($options["pinned"]) && $message_array["pinned"] != $options["pinned"]) { + $valid = false; + } + + if ($valid && isset($options["application_id"]) && ($message_array["application_id"] != $options["application_id"])) { + $valid = false; + } + + if ($valid && isset($options["tags"])) { + $tags = $message_array["tags"]; + if (!$message_array["tags"]) { + $message_array["tags"] = Array(); + } + $tags_search = true; + $i = 0; + if (isset($tags)) { + while ($tags_search && $i < count($options["tags"])) { + $trouve = false; + foreach ($message_array["tags"] as $tag) { + if ($tag == $options["tags"][$i]) { + $trouve = true; + break; + } + } + if ($trouve == false) { + $tags_search = false; + } + $i++; + } + } else { + $valid = false; + } + if (!$tags_search) { + $valid = false; + } + } + + if ($valid && isset($options["mentions"])) { + if (!array_intersect($options["mentions"], $message_array["mentions"]) == $options["mentions"]) { + $valid = false; + } + } + + if ($valid && isset($options["reactions"])) { + $react_search = true; + $i = 0; + // on parcours toute les reactions saisites + $reaction = $message_array["reactions"]; + if (!$reaction) { + $reaction = Array(); + } + if (isset($reaction)) { + while ($react_search && $i < count($options["reactions"])) { + $trouve = false; + foreach (array_keys($message_array["reactions"]) as $reaction) { + if (strpos(strtolower($reaction), strtolower($options["reactions"][$i])) !== false) { + $trouve = true; + break; + } + } + if ($trouve == false) { + $react_search = false; + } + $i++; + } + } else { + $valid = false; + } + if (!$react_search) { + $valid = false; + } + } + + return $valid; + + } + +} diff --git a/twake/backend/core/src/Twake/GlobalSearch/Services/ESUtils.php b/twake/backend/core/src/Twake/GlobalSearch/Services/ESUtils.php new file mode 100755 index 00000000..15b17dfe --- /dev/null +++ b/twake/backend/core/src/Twake/GlobalSearch/Services/ESUtils.php @@ -0,0 +1,274 @@ +<?php +/** + * Created by PhpStorm. + * User: romaricmourgues + * Date: 08/10/2019 + * Time: 09:33 + */ + +namespace Twake\GlobalSearch\Services; + + +use Twake\Core\Services\StringCleaner; + +class ESUtils +{ + static function createRange($from, $to, $parameter_name, &$must_list = NULL) + { + if (!$to && !$from) { + return; + } + + $tmp = Array( + "range" => Array( + "$parameter_name" => Array() + ) + ); + + if ($to) { + $tmp["range"][$parameter_name]["lte"] = ESUtils::simplifyInArray($to); + } + + if ($from) { + $tmp["range"][$parameter_name]["gte"] = ESUtils::simplifyInArray($from); + } + + if ($must_list !== NULL) { + $must_list[] = $tmp; + } + + return $tmp; + } + + static function simplifyInArray($data) + { + + $sc = new StringCleaner(); + return $sc->simplifyInArray($data); + + } + + static function createMatchPhrase($value, $parameter_name, &$must_list = NULL) + { + + if (!$value) { + return; + } + + $tmp = Array( + "match_phrase" => Array( + "$parameter_name" => ESUtils::simplifyInArray($value) + ) + ); + + if ($must_list !== NULL) { + $must_list[] = $tmp; + } + + return $tmp; + + } + + static function createShouldMatch($terms, $parameter_name, $minimum_should_match = "all", &$must_list = NULL) + { + + if ($terms && !is_array($terms)) { + $terms = [$terms]; + } + + if ($minimum_should_match == "all") { + $minimum_should_match = count($terms); + } + + if (!$terms || count($terms) == 0) { + return; + } + + $array = Array(); + foreach ($terms as $term) { + if ($term) { + $array[] = Array( + "match_phrase" => Array( + "$parameter_name" => ESUtils::simplifyInArray($term) + ) + ); + } + } + + $tmp = Array( + "bool" => Array( + "should" => $array, + "minimum_should_match" => $minimum_should_match + ) + ); + + if ($must_list !== NULL) { + $must_list[] = $tmp; + } + + return $tmp; + + + } + + static function createRegexShouldMatch($terms, $parameter_name, $minimum_should_match = "all", &$must_list = NULL) + { + + if ($terms && !is_array($terms)) { + $terms = [$terms]; + } + + if ($minimum_should_match == "all") { + $minimum_should_match = count($terms); + } + + if (!$terms || count($terms) == 0) { + return; + } + + $array = Array(); + foreach ($terms as $term) { + if ($term) { + $array[] = Array( + "bool" => Array( + "filter" => Array( + "regexp" => Array( + "$parameter_name" => ESUtils::simplifyInArray($term) + ) + ) + ) + ); + } + } + + $tmp = Array( + "bool" => Array( + "should" => $array, + "minimum_should_match" => $minimum_should_match + ) + ); + + if ($must_list !== NULL) { + $must_list[] = $tmp; + } + + return $tmp; + } + + static function createNestedShouldMatch($terms, $parameter_name, $minimum_should_match = "all", &$must_list = NULL) + { + + if ($terms && !is_array($terms)) { + $terms = [$terms]; + } + + if ($minimum_should_match == "all") { + $minimum_should_match = count($terms); + } + + if (!$terms || count($terms) == 0) { + return; + } + + $parameter_name_root = explode(".", $parameter_name)[0]; + + $array = Array(); + foreach ($terms as $term) { + + $array[] = Array( + "nested" => Array( + "path" => $parameter_name_root, + "score_mode" => "avg", + "query" => Array( + "bool" => Array( + "should" => Array( + Array( + "bool" => Array( + "must" => Array( + "match_phrase" => Array( + "$parameter_name" => ESUtils::simplifyInArray($term) + ) + ) + ) + ) + ), + "minimum_should_match" => 1 + ) + ) + ) + ); + } + + $tmp = Array( + "bool" => Array( + "should" => $array, + "minimum_should_match" => $minimum_should_match + ) + ); + + if ($must_list !== NULL) { + $must_list[] = $tmp; + } + + return $tmp; + } + + static function createNestedRegexShouldMatch($terms, $parameter_name, $minimum_should_match = "all", &$must_list = NULL) + { + + if ($terms && !is_array($terms)) { + $terms = [$terms]; + } + + if ($minimum_should_match == "all") { + $minimum_should_match = count($terms); + } + + if (!$terms || count($terms) == 0) { + return; + } + + $parameter_name_root = explode(".", $parameter_name)[0]; + + $array = Array(); + foreach ($terms as $term) { + + $array[] = Array( + "nested" => Array( + "path" => $parameter_name_root, + "score_mode" => "avg", + "query" => Array( + "bool" => Array( + "should" => Array( + Array( + "bool" => Array( + "filter" => Array( + "regexp" => Array( + "$parameter_name" => ESUtils::simplifyInArray($term) + ) + ) + ) + ) + ), + "minimum_should_match" => 1 + ) + ) + ) + ); + } + + $tmp = Array( + "bool" => Array( + "should" => $array, + "minimum_should_match" => $minimum_should_match + ) + ); + + if ($must_list !== NULL) { + $must_list[] = $tmp; + } + + return $tmp; + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/GlobalSearch/Services/Pagination.php b/twake/backend/core/src/Twake/GlobalSearch/Services/Pagination.php new file mode 100755 index 00000000..9a9109f9 --- /dev/null +++ b/twake/backend/core/src/Twake/GlobalSearch/Services/Pagination.php @@ -0,0 +1,28 @@ +<?php + +namespace Twake\GlobalSearch\Services; + +use App\App; + +class Pagination + +{ + private $doctrine; + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + } + + public function getnextelement($scroll_id, $repository) + { + + $option = Array( + "scroll_id" => $scroll_id, + "repository" => $repository + ); + $result = $this->doctrine->es_search($option); + return $result; + + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/GlobalSearch/Services/QuickSearch.php b/twake/backend/core/src/Twake/GlobalSearch/Services/QuickSearch.php new file mode 100755 index 00000000..5965960b --- /dev/null +++ b/twake/backend/core/src/Twake/GlobalSearch/Services/QuickSearch.php @@ -0,0 +1,202 @@ +<?php + +namespace Twake\GlobalSearch\Services; + +use App\App; + +use Twake\Core\Services\StringCleaner; + +class QuickSearch +{ + private $doctrine; + private $userservice; + private $workspaceservice; + private $channelservice; + private $fileservice; + private $memberservice; + + //liste final de rΓ©sultats + private $globalresult; + + //va stocker les rΓ©sultat non prioritaire sΓ©parΓ© par type + private $fileresult; + private $channelresult; + + //va stocker les rΓ©sultat prioritaire sΓ©parΓ© par type + private $priofileresult; + private $priochannelresult; + + private $history; + + private $workspace_prio; + + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->userservice = $app->getServices()->get("app.users"); + $this->workspaceservice = $app->getServices()->get("app.workspaces"); + $this->channelservice = $app->getServices()->get("app.channels.channels_system"); + $this->fileservice = $app->getServices()->get("globalsearch.advancedfile"); + $this->memberservice = $app->getServices()->get("app.workspace_members"); + } + + private static function cmpfile($file1, $file2) + { //permet d'obtenir la list des fichier par liste de pertinence + if ($file1["score"] == $file2["score"]) { + return 0; + } + return ($file1["score"] > $file2["score"]) ? -1 : 1; + } + + private static function cmpchannel($channel1, $channel2) + { //permet d'obtenir la list des fichier par liste de pertinence + if ($channel1["channel"]["last_activity"] == $channel2["channel"]["last_activity"]) { + return 0; + } + return ($channel1["channel"]["last_activity"] > $channel2["channel"]["last_activity"]) ? -1 : 1; + } + + public function AddAllChannels($workspace) + { + + $channels = $this->doctrine->getRepository("Twake\Channels:Channel")->findBy(Array("direct" => false, "original_workspace_id" => $workspace["id"])); + foreach ($channels as $channel) { + if ($channel->getAsArray()["application"] == false && $channel->getAsArray()["direct"] == false) { + $channel = $channel->getAsArray(); + if (isset($this->workspace_prio) && $this->workspace_prio == $workspace["id"]) { + $this->priochannelresult[] = Array("type" => "channel", "channel" => $channel, "workspace" => $workspace); + } else { + $this->channelresult[] = Array("type" => "channel", "channel" => $channel, "workspace" => $workspace); + } + //$this->history->addSearch(Array("id" => $channel["id"],"type"=> "file", "compteur" => 0)); + } + } + } + + public function QuickSearch($current_user_id, $words, $group_id = null, $workspace_prio = null) + { + + $this->workspace_prio = $workspace_prio; + //$this->workspace_prio = "d975075e-6028-11e9-b206-0242ac120005"; + //$words = Array("Romaric",'justin'); + $st = new StringCleaner(); + $words = $st->simplifyInArray($words); + $this->globalresult = Array(); + + $this->fileresult = Array(); + $this->priofileresult = Array(); + $this->channelresult = Array(); + $this->priochannelresult = Array(); + +// $this->history = $this->doctrine->getRepository("Twake\GlobalSearch:SearchHistory")->findOneBy(Array("user_id" => $current_user_id)); +// if(!isset($this->history)){ +// $this->history = new SearchHistory($current_user_id,Array()); +// } + + $workspaces_acces = $this->memberservice->getWorkspaces($current_user_id); + $workspaces = Array(); //liste des workspace dont on a accces; + foreach ($workspaces_acces as $workspace_obj) { + $value = $workspace_obj["workspace"]->getAsArray(); + if (isset($group_id) && !(in_array($value, $workspaces)) && $value["group"]["id"] == $group_id) { + $workspaces[$value["id"]] = $value; + } elseif (!isset($group_id) && !(in_array($value, $workspaces))) { + $workspaces[$value["id"]] = $value; + } + } + + $user = $this->doctrine->getRepository("Twake\Users:User")->findOneBy(Array("id" => $current_user_id)); + + + $this->SearchFile($current_user_id, $words, $workspaces); + $this->SearchInWorkspace($words, $workspaces, $current_user_id); + $this->SearchPrivateChannel($words, $user->getUsername(), $current_user_id); + + +// usort($this->fileresult,array($this,'cmpfile')); //on a meme plus besoin de trier ES le fait pour nous normalement +// usort($this->priofileresult,array($this,'cmpfile')); +// usort($this->priochannelresult,array($this,'cmpchannel')); + usort($this->channelresult, array($this, 'cmpchannel')); + + +// une fois toutes les donnΓ©es rΓ©cupΓ©rΓ© on construit le tableau de rΓ©sltat final comme suit: +// - resultat prio +// - fichier prio +// - channel +// - fichier + + $this->globalresult = array_merge($this->globalresult, $this->priochannelresult); + $this->globalresult = array_merge($this->globalresult, $this->priofileresult); + $this->globalresult = array_merge($this->globalresult, $this->channelresult); + $this->globalresult = array_merge($this->globalresult, $this->fileresult); + + +// $this->history = $this->doctrine->getRepository("Twake\GlobalSearch:SearchHistory")->findOneBy(Array("user_id" => $current_user_id)); +// $this->doctrine->persist($this->history); //rajouter if isset history +// $this->doctrine->flush(); + +// $channels= $this->doctrine->getRepository("Twake\Channels:Channel")->findBy(Array()); +// foreach ($channels as $channel){ +// if($channel->getAsArray()["application"] == false && $channel->getAsArray()["direct"] == true) { +// } +// } + +// +// $workspaces = $this->doctrine->getRepository("Twake\Workspaces:Workspace")->findBy(Array("id" => "0f34eff8-48af-11e9-9dd1-0242ac120005")); +// foreach ($workspaces as $workspace) { +// } + +// $files = $this->doctrine->getRepository("Twake\Drive:DriveFile")->findBy(Array()); +// foreach ($files as $file){ +// $this->doctrine->remove($file); +// } +// $this->doctrine->flush(); + + return $this->globalresult; + } + + public function SearchFile($current_user_id, $words, $workspaces) + { + + $options = Array(); + $options["title"] = join(" ", $words); + + $files = $this->fileservice->AdvancedFile($current_user_id, $options, $workspaces); + error_log(json_encode($files)); + foreach ($files["results"] as $file) { + if (isset($this->workspace_prio) && $this->workspace_prio == $file["file"]["workspace_id"]) { + $this->priofileresult[] = $file; + } else { + $this->fileresult[] = $file; + } + //$this->history->addSearch(Array("id" => $file[0]["id"],"type"=> "file", "compteur" => 0)); + } + } + + public function SearchInWorkspace($words, $workspaces, $current_user_id) + { + $channels = $this->channelservice->search($words, $workspaces, $current_user_id); // search channel in a workspace + foreach ($channels as $channel) { + if (in_array($current_user_id, $channel[0]["members"]) || in_array($current_user_id, $channel[0]["ext_members"])) { + if (isset($this->workspace_prio) && $this->workspace_prio == $channel[0]["original_workspace"]) { + $this->priochannelresult[] = Array("type" => "channel", "channel" => $channel[0], "last_activity" => $channel[1], "workspace" => $workspaces[$channel[0]["original_workspace"]]); + } else { + $this->channelresult[] = Array("type" => "channel", "channel" => $channel[0], "last_activity" => $channel[1], "workspace" => $workspaces[$channel[0]["original_workspace"]]); + } + //$this->history->addSearch(Array("id" => $channel["id"],"type"=> "file", "compteur" => 0)); + } + } + } + + public function SearchPrivateChannel($words, $name, $current_user_id) + { + $words[] = $name; + $channels = $this->channelservice->searchprivate($words, $current_user_id); // search channel in a workspace + foreach ($channels as $channel) { + $this->channelresult[] = Array("type" => "channel", "channel" => $channel[0], "last_activity" => $channel[1]); + //$this->history->addSearch(Array("id" => $channel["id"],"type"=> "file", "compteur" => 0)); + } + + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/GlobalSearch/Services/Tag.php b/twake/backend/core/src/Twake/GlobalSearch/Services/Tag.php new file mode 100755 index 00000000..823b3290 --- /dev/null +++ b/twake/backend/core/src/Twake/GlobalSearch/Services/Tag.php @@ -0,0 +1,179 @@ +<?php + +namespace Twake\GlobalSearch\Services; + +use Twake\GlobalSearch\Entity\WorkspaceTag; +use App\App; + +Class Tag +{ + + private $em; + + public function __construct(App $app) + { + $this->em = $app->getServices()->get("app.twake_doctrine"); + $this->access_manager = $app->getServices()->get("app.accessmanager"); + } + + /** Called from Collections manager to verify user has access to websockets room, registered in Core/Services/Websockets.php */ + public function init($route, $data, $current_user = null) + { + $route = explode("/", $route); + $workspace_id = $route[1]; + + if (!$workspace_id) { + return false; + } + + return $this->hasAccess([ + "workspace_id" => $workspace_id + ], $current_user); + } + + public function hasAccess($data, $current_user = null) + { + if ($current_user === null) { + return true; + } + if (!is_string($current_user)) { + $current_user = $current_user->getId(); + } + return $this->access_manager->has_access($current_user, [ + "type" => "Workspace", + "edition" => false, + "object_id" => $data["workspace_id"] + ]); + } + + public function get($options, $current_user) + { + + if (!$this->hasAccess($options, $current_user)) { + return false; + } + + + $list = Array(); + if (isset($options["workspace_id"])) { + $workspace_id = $options["workspace_id"]; + if (isset($options["id"])) { + $tag = $this->em->getRepository("Twake\GlobalSearch:WorkspaceTag")->findOneBy(Array("workspace_id" => $workspace_id, "id" => $options["id"])); + if (isset($tag)) { + $list[] = $tag->getAsArray(); + } + + } else { + $tags = $this->em->getRepository("Twake\GlobalSearch:WorkspaceTag")->findBy(Array("workspace_id" => $workspace_id)); + foreach ($tags as $tag) { + $list[] = $tag->getAsArray(); + } + } + } + + return $list; + + } + + public function remove($object, $options, $current_user = null, $return_entity = false) + { + if (!$this->hasAccess($object, $current_user)) { + return false; + } + + if (isset($object["id"])) { // on recoit un identifiant donc on supprime un tag + $tag = $this->em->getRepository("Twake\GlobalSearch:WorkspaceTag")->findOneBy(Array("id" => $object["id"])); + + $this->em->remove($tag); + $this->em->flush(); + + } else { + return false; + } + + if ($return_entity) { + return $tag; + } + return $tag->getAsArray(); + + } + + public function save($object, $options, $current_user = null, $return_entity = false) + { + if (!$this->hasAccess($object, $current_user)) { + return false; + } + + $tag = null; + if (isset($object["id"]) && $object["id"]) { // on recoit un identifiant donc c'est un modification + $tag = $this->em->getRepository("Twake\GlobalSearch:WorkspaceTag")->findOneBy(Array("id" => $object["id"])); + if (!$tag) { + return false; + } + } else { // pas d'identifiant on veut donc crΓ©er un tag + $name = $object["name"]; + $workspace_id = $object["workspace_id"]; + if ($this->checkname($workspace_id, $name)) { + $tag = new WorkspaceTag($workspace_id, $name); + if ($object["front_id"]) { + $tag->setFrontId($object["front_id"]); + } + }else{ + return false; + } + $did_create = true; + } + + if (isset($object["color"])) { + $tag->setColor($object["color"]); + } + + if (!$did_create && isset($object["name"])) { + if ($this->checkname($tag->getWorkspaceId(), $object["name"])) { + $tag->setName($object["name"]); + } + } + + + if (isset($tag)) { + $this->em->persist($tag); + $this->em->flush(); + } + + if ($return_entity) { + return $tag; + } + if (isset($tag)) { + return $tag->getAsArray(); + } + + } + + public function checkname($workspace_id, $name) + { + $tags = $this->em->getRepository("Twake\GlobalSearch:WorkspaceTag")->findBy(Array("workspace_id" => $workspace_id)); + $valid = true; + foreach ($tags as $tag) { + if ($tag->getName() == $name) { + $valid = false; + } + } + + return $valid; + } + +// public function addTags($object,$tags){ +// $actual_tags = $object->gettags(); +// +// $object->setTags($tags); +// $this->em->persist($object); +// $this->em->flush(); +// +// $diff = array_merge(array_diff($tags, $actual_tags), array_diff($actual_tags, $tags)); +// +// foreach ($diff as $d){ +// //mettre a jour les compteurs +// } +// +// } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Market/Bundle.php b/twake/backend/core/src/Twake/Market/Bundle.php new file mode 100755 index 00000000..4813a571 --- /dev/null +++ b/twake/backend/core/src/Twake/Market/Bundle.php @@ -0,0 +1,30 @@ +<?php + +namespace Twake\Market; + +require_once __DIR__ . "/Resources/Routing.php"; +require_once __DIR__ . "/Resources/Services.php"; + +use Twake\Market\Resources\Routing; +use Twake\Market\Resources\Services; +use Common\BaseBundle; + +class Bundle extends BaseBundle +{ + + protected $bundle_root = __DIR__; + protected $bundle_namespace = __NAMESPACE__; + protected $routes = []; + protected $services = []; + + public function init() + { + $routing = new Routing(); + $this->routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Market/Controller/Application.php b/twake/backend/core/src/Twake/Market/Controller/Application.php new file mode 100755 index 00000000..67a9cd09 --- /dev/null +++ b/twake/backend/core/src/Twake/Market/Controller/Application.php @@ -0,0 +1,105 @@ +<?php + +/** + * Created by PhpStorm. + * User: Romaric Mourgues + * Date: 19/06/2017 + * Time: 11:56 + */ + +namespace Twake\Market\Controller; + +use DevelopersApi\Users\Entity\Token; +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class Application extends BaseController +{ + + public function search(Request $request) + { + + $data = array( + "data" => Array(), + "errors" => Array() + ); + + $group_id = $request->request->get("group_id"); + $query = $request->request->get("query"); + + $res = $this->get("app.applications")->search($group_id, $query, $this->getUser()->getId()); + $data["data"] = $res; + + return new Response($data); + + } + + public function find(Request $request) + { + + $data = array( + "data" => Array(), + "errors" => Array() + ); + + $id = $request->request->get("id"); + + $res = $this->get("app.applications")->find($id); + $data["data"] = $res; + + return new Response($data); + + } + + public function getUserToken(Request $request) + { + + $manager = $this->get("app.twake_doctrine"); + + $data = array( + "data" => Array(), + 'errors' => Array() + ); + + + $appid = $request->request->get("appid", 0); + $wId = $request->request->get("workspaceId", 0); + + $app = $manager->getRepository("Twake\Market:Application") + ->find($appid); + + if (!$this->get('app.workspace_levels')->can($wId, $this->getUser()->getId(), "")) { + $data['errors'][] = "notallowed"; + } else { + + $useringroup = $manager->getRepository("Twake\Workspaces:WorkspaceUser") + ->findOneBy(Array("user_id" => $this->getUser()->getId(), "workspace_id" => $wId)); + + //Delete old tokens (1 minutes) + $qb = $manager->createQueryBuilder(); + $qb->delete('DevelopersApiUsers:Token', 't'); + $qb->where('t.date < :mindate'); + $qb->setParameter('mindate', (new \DateTime())->modify('-1 minute')); + + //Ok + $tokenE = new Token(); + $tokenE->setUser($this->getUser()); + $tokenE->setWorkspace($useringroup->getWorkspace($manager)->getId()); + $tokenE->setApplication($app); + + $manager->persist($tokenE); + $manager->flush(); + + $token = $tokenE->getToken(); + + $data["data"]["token"] = $token; + + } + + return new Response($data); + + } + + +} diff --git a/twake/backend/core/src/Twake/Market/Controller/ApplicationApi.php b/twake/backend/core/src/Twake/Market/Controller/ApplicationApi.php new file mode 100755 index 00000000..43bf2daf --- /dev/null +++ b/twake/backend/core/src/Twake/Market/Controller/ApplicationApi.php @@ -0,0 +1,77 @@ +<?php + +/** + * Created by PhpStorm. + * User: Romaric Mourgues + * Date: 19/06/2017 + * Time: 11:56 + */ + +namespace Twake\Market\Controller; + +use DevelopersApi\Users\Entity\Token; +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class ApplicationApi extends BaseController +{ + + public function getToken(Request $request) + { + $user = $this->getUser(); + $app_id = $request->request->get("application_id", null); + $workspace_id = $request->request->get("workspace_id", null); + $group_id = $request->request->get("group_id", null); + + if ($user != null) { + $data = array("token" => $this->get("app.applications_api")->generatedToken($app_id, $workspace_id, $group_id, $user->getId())); + } else { + $data = array("error" => "unknown_error"); + } + + return new Response($data); + + } + + public function event(Request $request) + { + + $data = array( + "data" => Array(), + "errors" => Array() + ); + + $workspace_id = $request->request->get("workspace_id"); + $group_id = $request->request->get("group_id"); + $app_id = $request->request->get("app_id"); + $type = $request->request->get("type"); + $event = $request->request->get("event"); + $evt_data = $request->request->get("data"); + + + $workspace = $this->get("app.workspaces")->get($workspace_id, $this->getUser()->getId()); + if ($workspace && $workspace->getGroup() == $group_id) { + $can = $this->get("app.applications_api")->hasCapability($app_id, $group_id); + if ($can) { + + $evt_data["workspace"] = $workspace->getAsArray($this->get("app.twake_doctrine")); + $evt_data["group"] = $evt_data["workspace"]["group"]; + $evt_data["user"] = $this->getUser()->getAsArray(); + $evt_data["user"]["email"] = $this->getUser()->getEmail(); + + $res = $this->get("app.applications_api")->notifyApp($app_id, $type, $event, $evt_data); + if ($res) { + return new Response($data); + } + + } + + } + + $data["errors"][] = "error"; + return new Response($data); + + } + +} diff --git a/twake/backend/core/src/Twake/Market/Controller/ApplicationDevelopment.php b/twake/backend/core/src/Twake/Market/Controller/ApplicationDevelopment.php new file mode 100755 index 00000000..3e0b6fbf --- /dev/null +++ b/twake/backend/core/src/Twake/Market/Controller/ApplicationDevelopment.php @@ -0,0 +1,129 @@ +<?php + +namespace Twake\Market\Controller; + +use DevelopersApi\Users\Entity\Token; +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class ApplicationDevelopment extends BaseController +{ + + public function create(Request $request) + { + + $data = array( + "data" => Array(), + "errors" => Array() + ); + + $workspace_id = $request->request->get("workspace_id"); + $name = $request->request->get("name"); + $simple_name = $request->request->get("simple_name"); + $app_group_name = $request->request->get("app_group_name", ""); + + $app_exists = $this->get("app.applications")->findAppBySimpleName($simple_name, true); + + if ($app_exists) { + + $data["errors"][] = "simple_name_used"; + + } else { + + $res = $this->get("app.applications")->createApp($workspace_id, $name, $simple_name, $app_group_name, $this->getUser()->getId()); + + if (!$res) { + $data["errors"][] = "error"; + } else { + + $this->get("administration.counter")->incrementCounter("total_apps", 1); + + $data["data"] = $res; + } + + } + + return new Response($data); + + } + + public function getGroupDevelopedApps(Request $request) + { + + $data = array( + "data" => Array(), + "errors" => Array() + ); + + $workspace_id = $request->request->get("workspace_id"); + $res = $this->get("app.applications")->getGroupDevelopedApps($workspace_id, $this->getUser()->getId()); + + if (!is_array($res)) { + $data["errors"][] = "error"; + } else { + $data["data"] = $res; + } + + return new Response($data); + + } + + public function update(Request $request) + { + + $data = array( + "data" => Array(), + "errors" => Array() + ); + + $application = $request->request->get("application"); + + $app_exists = $this->get("app.applications")->findAppBySimpleName($application["simple_name"], true); + + if ($app_exists && $app_exists["id"] != $application["id"]) { + + $data["errors"][] = "simple_name_used"; + + } else { + + $res = $this->get("app.applications")->update($application, $this->getUser()->getId()); + + if (!is_array($res)) { + $data["errors"][] = "error"; + } else { + $data["data"] = $res; + } + + } + + return new Response($data); + + } + + public function remove(Request $request) + { + + $data = array( + "data" => Array(), + "errors" => Array() + ); + + $application_id = $request->request->get("application_id"); + + $res = $this->get("app.applications")->remove($application_id, $this->getUser()->getId()); + + if (!$res) { + $data["errors"][] = "error"; + } else { + + $this->get("administration.counter")->incrementCounter("total_apps", -1); + + $data["data"] = Array("success" => true); + } + + return new Response($data); + + } + +} diff --git a/twake/backend/core/src/Twake/Market/Entity/AccessToken.php b/twake/backend/core/src/Twake/Market/Entity/AccessToken.php new file mode 100755 index 00000000..624203ec --- /dev/null +++ b/twake/backend/core/src/Twake/Market/Entity/AccessToken.php @@ -0,0 +1,177 @@ +<?php + + +namespace Twake\Market\Entity; + +use Doctrine\ORM\Mapping as ORM; + +use Twake\Workspaces\Entity\Workspace; + +/** + * Message + * + * @ORM\Table(name="access_token",options={"engine":"MyISAM", "scylladb_keys": {{"atoken": "ASC", "id": "ASC"}}} ) + * @ORM\Entity() + */ +class AccessToken +{ + /** + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="atoken", type="twake_no_salt_text") + */ + private $atoken; + + /** + * @ORM\Column(name="application_id", type="twake_timeuuid") + */ + private $application_id; + + /** + * @ORM\Column(name="group_id", type="twake_timeuuid") + */ + private $group_id; + + /** + * @ORM\Column(name="workspace_id", type="twake_timeuuid") + */ + private $workspace_id; + + /** + * @ORM\Column(name="user_id", type="twake_timeuuid") + */ + private $user_id; + + + /** + * @param mixed $tokenaL21 + * + */ + public function resetToken() + { + $this->atoken = bin2hex(random_bytes(64)); + } + + + public function __construct($application_id, $workspace_id, $group_id, $user_id) + { + $this->resetToken(); + $this->setApplicationId($application_id); + $this->setWorkspaceId($workspace_id); + $this->setGroupId($group_id); + $this->setUserId($user_id); + + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getToken() + { + return $this->atoken; + } + + /** + * @param mixed $token + */ + public function setToken($atoken) + { + $this->atoken = $atoken; + } + + /** + * @return mixed + */ + public function getApplicationId() + { + return $this->application_id; + } + + /** + * @param mixed $application_id + */ + public function setApplicationId($application_id) + { + $this->application_id = $application_id; + } + + /** + * @return mixed + */ + public function getGroupId() + { + return $this->group_id; + } + + /** + * @param mixed $group_id + */ + public function setGroupId($group_id) + { + $this->group_id = $group_id; + } + + /** + * @return mixed + */ + public function getWorkspaceId() + { + return $this->workspace_id; + } + + /** + * @param mixed $workspace_id + */ + public function setWorkspaceId($workspace_id) + { + $this->workspace_id = $workspace_id; + } + + /** + * @return mixed + */ + public function getUserId() + { + return $this->user_id; + } + + /** + * @param mixed $user_id + */ + public function setUserId($user_id) + { + $this->user_id = $user_id; + } + + public function getAsArray() + { + return Array( + "user_id" => $this->getUserId(), + "workspace_id" => $this->getWorkspaceId(), + "group_id" => $this->getGroupId(), + "app_id" => $this->getApplicationId() + ); + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Market/Entity/Application.php b/twake/backend/core/src/Twake/Market/Entity/Application.php new file mode 100755 index 00000000..02ad5a9b --- /dev/null +++ b/twake/backend/core/src/Twake/Market/Entity/Application.php @@ -0,0 +1,695 @@ +<?php + + +namespace Twake\Market\Entity; + +use Doctrine\ORM\Mapping as ORM; + +use Twake\Workspaces\Entity\Workspace; +use Twake\Core\Entity\SearchableObject; + +/** + * Application + * + * @ORM\Table(name="application",options={"engine":"MyISAM", "scylladb_keys": {{"group_id": "ASC", "app_group_name": "ASC", "id": "ASC"}, {"id": "ASC"}, {"simple_name": "ASC"}, {"is_default": "ASC"}}}) + * @ORM\Entity() + */ +class Application extends SearchableObject +{ + + protected $es_type = "applications"; + + // General + + /** + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + protected $id; + + /** + * @ORM\Column(name="group_id", type="twake_timeuuid") + * @ORM\Id + */ + protected $group_id; + + /** + * @ORM\Column(name="is_default", type="twake_boolean") + */ + protected $is_default; + + /** + * @ORM\Column(name="app_group_name", type="twake_no_salt_text") + * @ORM\Id + */ + protected $app_group_name; + + /** + * @ORM\Column(name="name", type="twake_text") + */ + protected $name; + + /** + * @ORM\Column(name="simple_name", type="twake_no_salt_text") + */ + protected $simple_name; + + /** + * @ORM\Column(name="description", type="twake_text") + */ + protected $description; + + /** + * @ORM\Column(name="website", type="twake_text") + */ + protected $website; + + /** + * @ORM\Column(name="categories", type="twake_text") + */ + protected $categories; + + /** + * @ORM\Column(name="icon_url", type="twake_text") + */ + protected $icon_url; //Doit finir par un format obligatoirement + + /** + * @ORM\Column(name="public", type="twake_boolean") + */ + protected $public; + + /** + * @ORM\Column(name="twake_team_validation", type="twake_boolean") + */ + protected $twake_team_validation; + + /** + * @ORM\Column(name="is_available_to_public", type="twake_boolean") + */ + protected $is_available_to_public; //Vrai si $public ET $twake_team_validation + + + // Statistiques + + /** + * @ORM\Column(name="install_count", type="integer") + */ + protected $install_count = 0; + + /** + * @ORM\Column(name="creation_date", type="twake_datetime") + */ + protected $creation_date; + + + // API configuration + + /** + * @ORM\Column(name="api_events_url", type="twake_text") + */ + protected $api_events_url; + + /** + * @ORM\Column(name="api_allowed_ip", type="twake_text") + */ + protected $api_allowed_ip; + + /** + * @ORM\Column(name="api_private_key", type="twake_text") + */ + protected $api_private_key; + + + // Access configuration + + /** + * @ORM\Column(name="privileges_capabilities_last_update", type="twake_datetime") + */ + protected $privileges_capabilities_last_update; + + /** + * @ORM\Column(name="privileges", type="twake_text") + */ + protected $privileges = "[]"; + + /** + * @ORM\Column(name="capabilities", type="twake_text") + */ + protected $capabilities = "[]"; + + /** + * @ORM\Column(name="hooks", type="twake_text") + */ + protected $hooks = "[]"; + + + // Display configuration + + /** + * @ORM\Column(name="display_configuration", type="twake_text") + */ + protected $display_configuration = "{}"; + + /** + * Application constructor. + * @param $group_id + * @param $name + */ + public function __construct($group_id, $name) + { + parent::__construct(); + $this->group_id = $group_id; + $this->name = $name; + $this->creation_date = new \DateTime(); + } + + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getGroupId() + { + return $this->group_id; + } + + /** + * @param mixed $group_id + */ + public function setGroupId($group_id) + { + $this->group_id = $group_id; + } + + /** + * @return mixed + */ + public function getDefault() + { + return $this->is_default; + } + + /** + * @param mixed $is_default + */ + public function setDefault($is_default) + { + $this->is_default = $is_default; + } + + /** + * @return mixed + */ + public function getApiPrivateKey() + { + return $this->api_private_key; + } + + /** + * @param mixed $api_private_key + */ + public function setApiPrivateKey($api_private_key) + { + $this->api_private_key = $api_private_key; + } + + /** + * @return mixed + */ + public function getAppGroupName() + { + return $this->app_group_name; + } + + /** + * @param mixed $app_group_name + */ + public function setAppGroupName($app_group_name) + { + $this->app_group_name = $app_group_name; + } + + /** + * @return mixed + */ + public function getName() + { + return $this->name; + } + + /** + * @param mixed $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @return mixed + */ + public function getSimpleName() + { + return $this->simple_name; + } + + /** + * @param mixed $simple_name + */ + public function setSimpleName($simple_name) + { + $this->simple_name = $simple_name; + } + + /** + * @return mixed + */ + public function getDescription() + { + return $this->description; + } + + /** + * @param mixed $description + */ + public function setDescription($description) + { + $this->description = $description; + } + + /** + * @return mixed + */ + public function getWebsite() + { + return $this->website; + } + + /** + * @param mixed $website + */ + public function setWebsite($website) + { + $this->website = $website; + } + + /** + * @return mixed + */ + public function getIconUrl() + { + return $this->icon_url; + } + + /** + * @param mixed $icon_url + */ + public function setIconUrl($icon_url) + { + $this->icon_url = $icon_url; + } + + /** + * @return mixed + */ + public function getCategories() + { + return json_decode($this->categories, true); + } + + /** + * @param mixed $categories + */ + public function setCategories($categories) + { + $this->categories = json_encode($categories); + } + + /** + * @return mixed + */ + public function getPublic() + { + return $this->public; + } + + /** + * @param mixed $public + */ + public function setPublic($public) + { + $this->public = $public; + } + + /** + * @return mixed + */ + public function getTwakeTeamValidation() + { + return $this->twake_team_validation; + } + + /** + * @param mixed $twake_team_validation + */ + public function setTwakeTeamValidation($twake_team_validation) + { + $this->twake_team_validation = $twake_team_validation; + } + + /** + * @return mixed + */ + public function getisAvailableToPublic() + { + return $this->is_available_to_public; + } + + /** + * @param mixed $is_available_to_public + */ + public function setIsAvailableToPublic($is_available_to_public) + { + $this->is_available_to_public = $is_available_to_public; + } + + /** + * @return mixed + */ + public function getInstallCount() + { + return $this->install_count; + } + + /** + * @param mixed $install_count + */ + public function setInstallCount($install_count) + { + $this->install_count = max(0, $install_count); + } + + /** + * @return mixed + */ + public function getCreationDate() + { + return $this->creation_date; + } + + /** + * @param mixed $creation_date + */ + public function setCreationDate($creation_date) + { + $this->creation_date = $creation_date; + } + + /** + * @return mixed + */ + public function getApiEventsUrl() + { + return $this->api_events_url; + } + + /** + * @param mixed $api_events_url + */ + public function setApiEventsUrl($api_events_url) + { + $this->api_events_url = $api_events_url; + } + + /** + * @return mixed + */ + public function getApiAllowedIp() + { + return json_decode($this->api_allowed_ip, true); + } + + /** + * @param mixed $api_allowed_ip + */ + public function setApiAllowedIp($api_allowed_ip) + { + $this->api_allowed_ip = json_encode($api_allowed_ip); + } + + /** + * @return mixed + */ + public function getPrivilegesCapabilitiesLastUpdate() + { + return $this->privileges_capabilities_last_update; + } + + /** + * @param mixed $privileges_capabilities_last_update + */ + public function setPrivilegesCapabilitiesLastUpdate($privileges_capabilities_last_update) + { + $this->privileges_capabilities_last_update = $privileges_capabilities_last_update; + } + + /** + * @return mixed + */ + public function getPrivileges() + { + if (!$this->privileges) { + return Array(); + } + return json_decode($this->privileges, true); + } + + /** + * @param mixed $privileges + */ + public function setPrivileges($privileges) + { + $this->privileges = json_encode($privileges); + } + + /** + * @return mixed + */ + public function getCapabilities() + { + if (!$this->capabilities) { + return Array(); + } + return json_decode($this->capabilities, true); + } + + /** + * @param mixed $capabilities + */ + public function setCapabilities($capabilities) + { + $this->capabilities = json_encode($capabilities); + } + + /** + * @return mixed + */ + public function getHooks() + { + if (!$this->hooks) { + return Array(); + } + return json_decode($this->hooks, true); + } + + /** + * @param mixed $hooks + */ + public function setHooks($hooks) + { + $this->hooks = json_encode($hooks); + } + + /** + * @return mixed + */ + public function getDisplayConfiguration() + { + return json_decode($this->display_configuration, true); + } + + /** + * @param mixed $display_configuration + */ + public function setDisplayConfiguration($display_configuration) + { + if (is_string($display_configuration)) { + try { + $_display_configuration = json_decode($display_configuration, true); + } catch (\Exception $e) { + $_display_configuration = $display_configuration; + } + $display_configuration = $_display_configuration; + } + $this->display_configuration = json_encode($display_configuration); + } + + + static public function generatePrivateApiKey() + { + $letters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + return str_replace(Array("+", "/", "="), Array($letters[random_int(0, 61)], $letters[random_int(0, 61)], $letters[random_int(0, 61)]), + base64_encode(random_bytes(100))); + } + + public function getAsCredentialArray() + { + $return = []; + $return["api_id"] = $this->getId(); + $return["api_key"] = $this->getApiPrivateKey(); + return $return; + } + + public function getAsArrayForDevelopers() + { + $return = $this->getAsArray(); + + $return["id"] = $this->getId(); + + $return["api_id"] = $this->getId(); + $return["api_key"] = $this->getApiPrivateKey(); + $return["api_event_url"] = $this->getApiEventsUrl(); + $return["api_allowed_ips"] = $this->getApiAllowedIp(); + + $return["privileges"] = $this->getPrivileges(); + $return["capabilities"] = $this->getCapabilities(); + + $return["available_privileges"] = Array( + "channels", //Lister les channels et leur configuration (tabulations etc) + "workspace", //Information sur l’espace de travail + "workspace_calendar", //Information sur le calendrier de l’espace de travail + "workspace_tasks", //Information sur les taches de l’espace de travail + "workspace_drive", //Information sur le drive de l’espace de travail + "drive_list", //Lister documents dans le Drive + "tasks_task_save", + "tasks_task_remove", + //"drive_tree", //Liste des fichiers, noms et autres metadatas + //"drive_files_content", //TΓ©lΓ©chargement des fichiers et preview des fichiers + //"messages_history", //RΓ©cupΓ©rer ou rechercher des messages + //"members", //Lister les membres d’un espace de travail + //"group_members", //Lister les membres d’un groupe entier + //"applications", //Liste des applications dΓ©ployΓ©es sur l’espace de travail (sans le dΓ©tail de leur configuration) + //"group" //Information sur le groupe + ); + $return["available_capabilities"] = Array( + "display_modal", //Afficher une modal (comme une modal de configuration) + "messages_save", //Envoyer des messages + "messages_remove", + "drive_save", + "drive_remove", + "calendar_event_save", + "calendar_event_remove", + "tasks_task_save", + "tasks_task_remove", + //"drive_add", //Ajouter un fichiers + //"drive_remove", //Supprimer un fichier existant + //"drive_modify", //Modifier un fichier existant + //"drive_add_version", //Ajouter une version Γ  un fichier existant + //"messages_remove", //Supprimer des messages autre que ceux de l’application + //"messages_modify", //Modifier des messages autre que ceux de l’application + //"members_add", //Ajouter un membre + //"members_remove", //Supprimer un membre + //"workspace_add", //Ajouter un espace de travail + //"workspace_remove" //Supprimer un espace de travail + ); + $return["available_hooks"] = Array( + "message", //Nouveau message hook dans un channel particulier (si Γ©coutΓ©) + "message_in_workspace", //Nouveau message hook dans tous le workspace + "calendar", + "event", + "task", + "file" + ); + $return["available_categories"] = Array( + "bots", + "data_analysis", + "communication", + "customer_support", + "graphism", + "developers", + "files", + "events", + "health", + "human_resources", + "corporate_culture", + "marketing", + "office", + "finances", + "productivity", + "project_management", + "sales", + "security_compliance", + "entertainment", + "trip", + "voice_video", + "medias_news" + ); + + return $return; + } + + public function getAsArray() + { + $return = Array( + "id" => $this->getId(), + "group_id" => $this->getGroupId(), + "app_group_name" => $this->getAppGroupName(), + "categories" => $this->getCategories(), + "name" => $this->getName(), + "simple_name" => $this->getSimpleName(), + "description" => $this->getDescription(), + "icon_url" => $this->getIconUrl(), + "website" => $this->getWebsite(), + "install_count" => $this->getInstallCount(), + "creation_date" => $this->getCreationDate() ? $this->getCreationDate()->getTimestamp() : new \DateTime(), + "privileges" => $this->getPrivileges(), + "capabilities" => $this->getCapabilities(), + "hooks" => $this->getHooks(), + "display" => $this->getDisplayConfiguration(), + "public" => $this->getPublic(), + "is_available_to_public" => $this->getisAvailableToPublic() + ); + return $return; + } + + public function getIndexationArray() + { + $return = Array( + "app_group_name" => $this->getAppGroupName(), + "name" => $this->getName(), + "simple_name" => $this->getSimpleName(), + "description" => $this->getDescription(), + "categories" => $this->getCategories(), + "group_id" => $this->getGroupId(), + "public" => $this->getisAvailableToPublic() + ); + return $return; + } + +} diff --git a/twake/backend/core/src/Twake/Market/Entity/ApplicationResource.php b/twake/backend/core/src/Twake/Market/Entity/ApplicationResource.php new file mode 100755 index 00000000..fb6b93f6 --- /dev/null +++ b/twake/backend/core/src/Twake/Market/Entity/ApplicationResource.php @@ -0,0 +1,169 @@ +<?php + + +namespace Twake\Market\Entity; + +use Doctrine\ORM\Mapping as ORM; + +use Twake\Workspaces\Entity\Workspace; +use Twake\Core\Entity\SearchableObject; + +/** + * ApplicationResource + * + * @ORM\Table(name="application_resource",options={"engine":"MyISAM", "scylladb_keys": {{"application_id": "ASC", "workspace_id": "ASC", "id": "ASC"}, {"id": "ASC"}, {"resource_id": "ASC"}}}) + * @ORM\Entity() + */ +class ApplicationResource +{ + + /** + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + protected $id; + + /** + * @ORM\Column(name="workspace_id", type="twake_timeuuid") + * @ORM\Id + */ + protected $workspace_id; + + /** + * @ORM\Column(name="application_id", type="twake_timeuuid") + * @ORM\Id + */ + protected $application_id; + + /** + * @ORM\Column(name="resource_type", type="twake_no_salt_text") + */ + protected $resource_type; //directory, channel, workspace, group + + /** + * @ORM\Column(name="resource_id", type="twake_timeuuid") + */ + protected $resource_id; + + /** + * @ORM\Column(name="application_hooks", type="twake_text") + */ + protected $application_hooks; + + /** + * ApplicationResource constructor. + * @param $id + * @param $workspace_id + * @param $application_id + * @param $resource_type + * @param $resource_id + */ + public function __construct($workspace_id, $application_id, $resource_type, $resource_id) + { + $this->workspace_id = $workspace_id; + $this->application_id = $application_id; + $this->resource_type = $resource_type; + $this->resource_id = $resource_id; + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getWorkspaceId() + { + return $this->workspace_id; + } + + /** + * @param mixed $workspace_id + */ + public function setWorkspaceId($workspace_id) + { + $this->workspace_id = $workspace_id; + } + + /** + * @return mixed + */ + public function getApplicationId() + { + return $this->application_id; + } + + /** + * @param mixed $application_id + */ + public function setApplicationId($application_id) + { + $this->application_id = $application_id; + } + + /** + * @return mixed + */ + public function getResourceType() + { + return $this->resource_type; + } + + /** + * @param mixed $resource_type + */ + public function setResourceType($resource_type) + { + $this->resource_type = $resource_type; + } + + /** + * @return mixed + */ + public function getResourceId() + { + return $this->resource_id; + } + + /** + * @param mixed $resource_id + */ + public function setResourceId($resource_id) + { + $this->resource_id = $resource_id; + } + + /** + * @return mixed + */ + public function getApplicationHooks() + { + if (!$this->application_hooks) { + return Array(); + } + return json_decode($this->application_hooks, true); + } + + /** + * @param mixed $application_hooks + */ + public function setApplicationHooks($application_hooks) + { + $this->application_hooks = json_encode($application_hooks); + } + + +} diff --git a/twake/backend/core/src/Twake/Market/Entity/ApplicationResourceNode.php b/twake/backend/core/src/Twake/Market/Entity/ApplicationResourceNode.php new file mode 100755 index 00000000..ecd199cf --- /dev/null +++ b/twake/backend/core/src/Twake/Market/Entity/ApplicationResourceNode.php @@ -0,0 +1,169 @@ +<?php + + +namespace Twake\Market\Entity; + +use Doctrine\ORM\Mapping as ORM; + +use Twake\Workspaces\Entity\Workspace; +use Twake\Core\Entity\SearchableObject; + +/** + * ApplicationResourceNode + * + * @ORM\Table(name="application_resource_node",options={"engine":"MyISAM", "scylladb_keys": {{"application_id": "ASC", "workspace_id": "ASC", "id": "ASC"}, {"id": "ASC"}, {"resource_id": "ASC"}}}) + * @ORM\Entity() + */ +class ApplicationResourceNode +{ + + /** + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + protected $id; + + /** + * @ORM\Column(name="workspace_id", type="twake_text") + * @ORM\Id + */ + protected $workspace_id; + + /** + * @ORM\Column(name="application_id", type="twake_text") + * @ORM\Id + */ + protected $application_id; + + /** + * @ORM\Column(name="resource_type", type="twake_no_salt_text") + */ + protected $resource_type; //directory, channel, workspace, group + + /** + * @ORM\Column(name="resource_id", type="twake_text") + */ + protected $resource_id; + + /** + * @ORM\Column(name="application_hooks", type="twake_text") + */ + protected $application_hooks; + + /** + * ApplicationResourceNode constructor. + * @param $id + * @param $workspace_id + * @param $application_id + * @param $resource_type + * @param $resource_id + */ + public function __construct($workspace_id, $application_id, $resource_type, $resource_id) + { + $this->workspace_id = $workspace_id; + $this->application_id = $application_id; + $this->resource_type = $resource_type; + $this->resource_id = $resource_id; + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getWorkspaceId() + { + return $this->workspace_id; + } + + /** + * @param mixed $workspace_id + */ + public function setWorkspaceId($workspace_id) + { + $this->workspace_id = $workspace_id; + } + + /** + * @return mixed + */ + public function getApplicationId() + { + return $this->application_id; + } + + /** + * @param mixed $application_id + */ + public function setApplicationId($application_id) + { + $this->application_id = $application_id; + } + + /** + * @return mixed + */ + public function getResourceType() + { + return $this->resource_type; + } + + /** + * @param mixed $resource_type + */ + public function setResourceType($resource_type) + { + $this->resource_type = $resource_type; + } + + /** + * @return mixed + */ + public function getResourceId() + { + return $this->resource_id; + } + + /** + * @param mixed $resource_id + */ + public function setResourceId($resource_id) + { + $this->resource_id = $resource_id; + } + + /** + * @return mixed + */ + public function getApplicationHooks() + { + if (!$this->application_hooks) { + return Array(); + } + return json_decode($this->application_hooks, true); + } + + /** + * @param mixed $application_hooks + */ + public function setApplicationHooks($application_hooks) + { + $this->application_hooks = json_encode($application_hooks); + } + + +} diff --git a/twake/backend/core/src/Twake/Market/Resources/Routing.php b/twake/backend/core/src/Twake/Market/Resources/Routing.php new file mode 100755 index 00000000..594a6a05 --- /dev/null +++ b/twake/backend/core/src/Twake/Market/Resources/Routing.php @@ -0,0 +1,29 @@ +<?php + +namespace Twake\Market\Resources; + +use Common\BaseRouting; + +class Routing extends BaseRouting +{ + + protected $routing_prefix = "ajax/market/"; + + protected $routes = [ +# Apps management + + "app/search" => ["handler" => "Application:search", "methods" => ["POST"], "security" => ["user_connected_security"]], + "app/find" => ["handler" => "Application:find", "methods" => ["POST"], "security" => ["user_connected_security"]], +# Apps API + + "app/api/event" => ["handler" => "ApplicationApi:event", "methods" => ["POST"], "security" => ["user_connected_security"]], + "app/api/getToken" => ["handler" => "ApplicationApi:getToken", "methods" => ["POST"], "security" => ["user_connected_security"]], +# Apps Developers + + "app/create" => ["handler" => "ApplicationDevelopment:create", "methods" => ["POST"], "security" => ["user_connected_security"]], + "app/remove" => ["handler" => "ApplicationDevelopment:remove", "methods" => ["POST"], "security" => ["user_connected_security"]], + "app/update" => ["handler" => "ApplicationDevelopment:update", "methods" => ["POST"], "security" => ["user_connected_security"]], + "app/get_developed" => ["handler" => "ApplicationDevelopment:getGroupDevelopedApps", "methods" => ["POST"], "security" => ["user_connected_security"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Market/Resources/Services.php b/twake/backend/core/src/Twake/Market/Resources/Services.php new file mode 100755 index 00000000..754a8f61 --- /dev/null +++ b/twake/backend/core/src/Twake/Market/Resources/Services.php @@ -0,0 +1,16 @@ +<?php + +namespace Twake\Market\Resources; + +use Common\BaseServices; + +class Services extends BaseServices +{ + + protected $services = [ + "app.applications" => "MarketApplication", + "app.applications_api" => "ApplicationApi", + "website_api_market.data_token" => "DataTokenSystem", + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Market/Services/ApplicationApi.php b/twake/backend/core/src/Twake/Market/Services/ApplicationApi.php new file mode 100755 index 00000000..a6dc6d9e --- /dev/null +++ b/twake/backend/core/src/Twake/Market/Services/ApplicationApi.php @@ -0,0 +1,420 @@ +<?php + +namespace Twake\Market\Services; + +use Twake\Market\Entity\AccessToken; +use Twake\Market\Entity\Application; +use Twake\Market\Entity\ApplicationResourceNode; +use App\App; + +class ApplicationApi +{ + private $app; + private $doctrine; + private $rest_client; + + public function __construct(App $app) + { + $this->app = $app; + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->rest_client = $app->getServices()->get("app.restclient"); + } + + + public function generatedToken($app_id, $workspace_id, $group_id, $user_id) + { + + $entity = new AccessToken($app_id, $workspace_id, $group_id, $user_id); + $this->doctrine->useTTLOnFirstInsert(60 * 60); + $this->doctrine->persist($entity); + $this->doctrine->flush(); + + return $entity->getToken(); + + } + + /** + * @param $request + * @param array $capabilities + * @param array $privileges + * @return array|Application + */ + public function getAppFromRequest($request, $capabilities = [], $privileges = []) + { + + $header = $request->headers->get("Authorization"); + $explode1 = explode(" ", $header); + + if (count($explode1) == 2 && $explode1[0] == "Basic") { + + $exploser2 = explode(":", base64_decode($explode1[1])); + + if (count($exploser2) == 2) { + $id = $exploser2[0]; + $privateKey = $exploser2[1]; + + $application = $this->get($id); + + if ($application != null) { + $key = $application->getApiPrivateKey(); + + if ($key == $privateKey) { + + $group_id = $request->request->get("group_id", null); + + $group_app = $this->doctrine->getRepository("Twake\Workspaces:GroupApp")->findOneBy(Array("app_id" => $application->getId(), "group" => $group_id)); + + if($group_app->getPrivileges() === null){ + return $application; + } + + if ((!$group_id || !$group_app) && (count($capabilities) > 0 || count($privileges) > 0)) { + return Array("error" => "you_need_to_provide_a_valid_group_id_field_in_any_api_request", "group_id" => $group_id); + } + + $can_do_it = false; + if ($group_id) { + $can_do_it = $this->hasCapability($application->getId(), $group_id, $capabilities, $group_app); + } + if (!$can_do_it) { + return Array("error" => "you_do_not_have_this_set_of_required_capabilities", "capabilities" => $capabilities); + } + + if ($group_id) { + $can_do_it = $this->hasPrivilege($application->getId(), $group_id, $privileges, $group_app); + } + if (!$can_do_it) { + return Array("error" => "you_do_not_have_this_set_of_required_privileges", "privileges" => $privileges); + } + + return $application; + } + + } + } + + } + + return Array("error" => "unknown_application_or_bad_private_key"); + + } + + /** + * @param $app_id + * @return Application + */ + public function get($app_id) + { + return $this->doctrine->getRepository("Twake\Market:Application")->findOneBy(Array("id" => $app_id)); + } + + public function hasCapability($app_id, $group_id, $capabilities = [], $group_app = null) + { + $app = $this->get($app_id); + $group_app = $group_app ? $group_app : $this->doctrine->getRepository("Twake\Workspaces:GroupApp")->findOneBy(Array("app_id" => $app_id, "group" => $group_id)); + + if (!$group_app || !$app) { + return false; + } + + if (count($capabilities) == 0) { + return true; + } + + $accepted_capabilities = $group_app->getCapabilities(); + + $ok = true; + foreach ($capabilities as $capability) { + if ($accepted_capabilities && !in_array($capability, $accepted_capabilities)) { + $ok = false; + } + } + if ($ok) { + return true; + } + + $app_capabilities = $app->getCapabilities(); + + $ok = true; + foreach ($capabilities as $capability) { + if (!in_array($capability, $app_capabilities)) { + $ok = false; + } + } + if (!$ok) { + return false; + } + + //This app is developed by the group + if ($group_id == $app->getGroupId()) { + return true; + } + + //TODO send an email to the group managers to update the app because it was not updated with latest capabilities + + return false; + } + + public function hasPrivilege($app_id, $group_id, $privileges = [], $group_app = null) + { + $app = $this->get($app_id); + $group_app = $group_app ? $group_app : $this->doctrine->getRepository("Twake\Workspaces:GroupApp")->findOneBy(Array("app_id" => $app_id, "group" => $group_id)); + + if (!$group_app || !$app) { + return false; + } + + if (count($privileges) == 0) { + return true; + } + + $accepted_privileges = $group_app->getPrivileges(); + + $ok = true; + foreach ($privileges as $privilege) { + if (!in_array($privilege, $accepted_privileges)) { + $ok = false; + } + } + if ($ok) { + return true; + } + + $app_privileges = $app->getPrivileges(); + + $ok = true; + foreach ($privileges as $privilege) { + if (!in_array($privilege, $app_privileges)) { + $ok = false; + } + } + if (!$ok) { + return false; + } + + //This app is developed by the group + if ($group_id == $app->getGroupId()) { + return true; + } + + //TODO send an email to the group managers to update the app because it was not updated with latest privileges + + return false; + } + + public function hasResource($app_id, $workspace_id, $resource_type, $resource_id) + { + } + + public function setAsync() + { + $this->async = true; + } + + public function unsetAsyncAndFlush() + { + $this->async = false; + if ($this->curl_rcx) { + $this->curl_rcx->execute(); + } + } + + public function getResources($workspace_id, $resource_type, $resource_id) + { + $repo = $this->doctrine->getRepository("Twake\Market:ApplicationResourceNode"); + $list = $repo->findBy(Array("resource_id" => $resource_id)); + $final_list = []; + foreach ($list as $el) { + if ($el->getWorkspaceId() == $workspace_id) { + $final_list[] = $el; + } + } + return $final_list; + } + + public function addResource($app_id, $workspace_id, $resource_type, $resource_id, $current_user_id = null) + { + $repo = $this->doctrine->getRepository("Twake\Market:Application"); + $app = $repo->findOneBy(Array("id" => $app_id)); + + if (!$app) { + return false; + } + + $repo = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $repo->findOneBy(Array("id" => $workspace_id)); + + if (!$workspace) { + return false; + } + + $current_user = null; + if ($current_user_id) { + $repo = $this->doctrine->getRepository("Twake\Users:User"); + $current_user = $repo->findOneBy(Array("id" => $current_user_id)); + } + + //Verify we do not have this resource + $repo = $this->doctrine->getRepository("Twake\Market:ApplicationResourceNode"); + $candidates = $repo->findBy(Array("application_id" => $app_id, "workspace_id" => $workspace_id)); + + foreach ($candidates as $candidate) { + if ($candidate->getResourceId() == $resource_id) { //No necessity to verufy type as uuid are universaly unique + return true; + } + } + + $resource = new ApplicationResourceNode($workspace_id, $app_id, $resource_type, $resource_id); + $resource->setApplicationHooks($app->getHooks()); + $this->doctrine->persist($resource); + $this->doctrine->flush(); + + $this->notifyApp($app_id, "resource", "add", Array( + "workspace" => $workspace, + "resource" => Array( + "id" => $resource_id, + "type" => $resource_type + ), + "user" => $current_user + )); + + return true; + + } + + public function notifyApp($app_id, $type, $event, $data) + { + + $event = Array( + "type" => $type, + "event" => $event, + "data" => $data + ); + + if(isset($event["data"]["message"])){ + $event["data"]["message"]["channel_id"] = $event["data"]["message"]["cache"]["channel_id"]; + $event["data"]["message"]["workspace_id"] = $event["data"]["message"]["cache"]["workspace_id"]; + } + + if (!$this->curl_rcx) { + $this->curl_rcx = new RollingCurlX(10); + $this->curl_rcx->setOptions([ + CURLOPT_SSL_VERIFYPEER => false + ]); + $this->curl_rcx->setTimeout(3000); + $this->curl_rcx->setHeaders(['Content-Type: application/json']); + } + + $repo = $this->doctrine->getRepository("Twake\Market:Application"); + $app = $repo->findOneBy(Array("id" => $app_id)); + + if (!$app) { + return false; + } + + $event_route = $app->getApiEventsUrl(); + + //Check route is correct + if (!parse_url($event_route, PHP_URL_HOST)) { + return false; + } + $event_route = preg_replace("/^\/+/", "", $event_route); + + //Hack for having same set of apps in beta and web + $betaHack = explode("/bundle/connectors/", $event_route); + if(count($betaHack) > 1){ + $server_route = rtrim($this->app->getContainer()->getParameter("env.internal_server_name")?:$this->app->getContainer()->getParameter("env.server_name"), "/"); + $event_route = $server_route . "/bundle/connectors/" . $betaHack[1]; + } + //Hack to send to connectors wich server to respond + $event["_origin"] = $this->app->getContainer()->getParameter("env.server_name"); + + $use_https = false; + if (strpos($event_route, "https") === 0) { + $use_https = true; + } + + $event_route = preg_replace("/^https?+:\/\//", "", $event_route); + $event_route = preg_replace("/\/+/", "/", $event_route); + $parts = explode("/", $event_route); + if (count($parts) == 1 || $parts[1] == "" || $parts[0] == "") { + return false; //No domain or no route + } + + if ($use_https) { + $event_route = "https://" . $event_route; + } else { + $event_route = "http://" . $event_route; + } + + + $data = json_encode($event); + + try { + + $this->curl_rcx->addRequest($event_route, $data); + + if (!$this->async) { + $this->curl_rcx->execute(); + } + + } catch (\Exception $e) { + //Timeout exceeded maybe + } + + return true; + + } + + public function removeResource($app_id, $workspace_id, $resource_type, $resource_id, $current_user_id = null) + { + $repo = $this->doctrine->getRepository("Twake\Market:Application"); + $app = $repo->findOneBy(Array("id" => $app_id)); + + if (!$app) { + return false; + } + + $repo = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $repo->findOneBy(Array("id" => $workspace_id)); + + if (!$workspace) { + return false; + } + + $current_user = null; + if ($current_user_id) { + $repo = $this->doctrine->getRepository("Twake\Users:User"); + $current_user = $repo->findOneBy(Array("id" => $current_user_id)); + } + + //Verify we have this resource + $repo = $this->doctrine->getRepository("Twake\Market:ApplicationResourceNode"); + $candidates = $repo->findBy(Array("application_id" => $app_id, "workspace_id" => $workspace_id)); + + $choosen = null; + foreach ($candidates as $candidate) { + if ($candidate->getResourceId() == $resource_id) { //No necessity to verufy type as uuid are universaly unique + $choosen = $candidate; + } + } + + if ($choosen) { + $this->doctrine->remove($choosen); + $this->doctrine->flush(); + } + + $this->notifyApp($app_id, "resource", "remove", Array( + "workspace" => $workspace, + "resource" => Array( + "id" => $resource_id, + "type" => $resource_type + ), + "user" => $current_user + )); + + return true; + + } + +} diff --git a/twake/backend/core/src/Twake/Market/Services/DataTokenSystem.php b/twake/backend/core/src/Twake/Market/Services/DataTokenSystem.php new file mode 100755 index 00000000..105eeb54 --- /dev/null +++ b/twake/backend/core/src/Twake/Market/Services/DataTokenSystem.php @@ -0,0 +1,54 @@ +<?php +/** + * Created by PhpStorm. + * User: ehlnofey + * Date: 08/06/18 + * Time: 11:53 + */ + +namespace Twake\Market\Services; + +use App\App; +use Twake\Market\Entity\DataToken; + +class DataTokenSystem +{ + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + } + + public function makeToken($workspaceId, $userId) + { + $dataToken = new DataToken($workspaceId, $userId); + + $this->doctrine->persist($dataToken); + $this->doctrine->flush(); + + return $dataToken; + } + + public function getDataToken($token) + { + $dataTokenRepository = $this->doctrine->getRepository("Twake\Market:DataToken"); + $dataToken = $dataTokenRepository->findOneBy(Array("token" => $token)); + if ($dataToken == null) + return false; + + $data["workspaceId"] = $dataToken->getWorkspaceId(); + $data["userId"] = $dataToken->getUserId(); + + $dataTokenRepository->removeToken($dataToken->getToken()); + + return $data; + } + + public function checkWorkspaceUser($workspaceId, $userId) + { + $workspaceUserRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + + $workspaceUser = $workspaceUserRepository->findOneBy(Array("workspace_id" => $workspaceId, "user_id" => $userId)); + + return $workspaceUser != null; + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Market/Services/MarketApplication.php b/twake/backend/core/src/Twake/Market/Services/MarketApplication.php new file mode 100755 index 00000000..b7d1e899 --- /dev/null +++ b/twake/backend/core/src/Twake/Market/Services/MarketApplication.php @@ -0,0 +1,353 @@ +<?php + +namespace Twake\Market\Services; + +use Twake\Market\Entity\Application; +use Twake\Market\Model\MarketApplicationInterface; +use App\App; + +class MarketApplication +{ + private $doctrine; + private $gms; + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->gms = $app->getServices()->get("app.group_managers"); + } + + public function findBySimpleName($name, $entity = false) + { + $repo = $this->doctrine->getRepository("Twake\Market:Application"); + $app = $repo->findOneBy(Array("simple_name" => $name)); + return ($app && !$entity) ? $app->getAsArray() : $app; + } + + public function getCredentials($simple_name){ + $repo = $this->doctrine->getRepository("Twake\Market:Application"); + $app = $repo->findOneBy(Array("simple_name" => $simple_name)); + return ($app) ? $app->getAsCredentialArray() : false; + } + + public function find($id, $entity = false) + { + $repo = $this->doctrine->getRepository("Twake\Market:Application"); + $app = $repo->findOneBy(Array("id" => $id)); + return ($app && !$entity) ? $app->getAsArray() : $app; + } + + public function createApp($workspace_id, $name, $simple_name, $app_group_name, $current_user_id) + { + + $group_id = "00000000-0000-1000-0000-000000000000"; + if($workspace_id || $current_user_id != null){ + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $groupRepository->findOneBy(Array("id" => $workspace_id)); + $group_id = $workspace->getGroup(); + } + + if ($current_user_id == null + || $this->gms->hasPrivileges( + $this->gms->getLevel($group_id, $current_user_id), + "MANAGE_APPS" + ) + ) { + + if (!$name || !$simple_name || (!$workspace_id && $current_user_id != null)) { + return false; + } + + $application = new Application($group_id, $name); + $application->setCreationDate(new \DateTime()); + $application->setAppGroupName($app_group_name); + + $application->setSimpleName($simple_name); + + $application->setApiPrivateKey(Application::generatePrivateApiKey()); + + $this->doctrine->persist($application); + $this->doctrine->flush(); + + return $application->getAsArrayForDevelopers(); + + } + return false; + } + + public function getGroupDevelopedApps($workspace_id, $current_user_id) + { + + $group_id = "00000000-0000-1000-0000-000000000000"; + if($workspace_id || $current_user_id != null){ + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $groupRepository->findOneBy(Array("id" => $workspace_id)); + $group_id = $workspace->getGroup(); + } + + if ($current_user_id == null + || $this->gms->hasPrivileges( + $this->gms->getLevel($group_id, $current_user_id), + "MANAGE_APPS" + ) + ) { + + $repo = $this->doctrine->getRepository("Twake\Market:Application"); + $apps = $repo->findBy(Array("group_id" => $group_id)); + + $list = []; + + foreach ($apps as $app) { + $list[] = $app->getAsArrayForDevelopers(); + } + + return $list; + + } + return []; + } + + public function findAppBySimpleName($simple_name, $include_private_apps = false) + { + + $repo = $this->doctrine->getRepository("Twake\Market:Application"); + + $app = $repo->findOneBy(Array("simple_name" => $simple_name)); + + if (!$app) { + return false; + } + + if (!$include_private_apps && !$app->getisAvailableToPublic()) { + return false; + } + + return $app->getAsArray(); + } + + public function update($application, $current_user_id) + { + + $applicationRepository = $this->doctrine->getRepository("Twake\Market:Application"); + /** + * @var Application $application_original + */ + $application_original = $applicationRepository->findOneBy(Array('id' => $application["id"])); + + if ($application_original) { + + $group_id = $application_original->getGroupId(); + if ($current_user_id == null + || $this->gms->hasPrivileges( + $this->gms->getLevel($group_id, $current_user_id), + "MANAGE_APPS" + ) + ) { + + if (!$application_original->getPublic()) { + + $application_original->setSimpleName($application["simple_name"]); + $application_original->setName($application["name"]); + $application_original->setDescription($application["description"]); + $application_original->setIconUrl($application["icon_url"]); + $application_original->setWebsite($application["website"]); + $application_original->setCategories($application["categories"]); + + $old_privileges = $application_original->getPrivileges(); + $old_capabilities = $application_original->getCapabilities(); + $changed = false; + foreach ($application["privileges"] as $pr) { + if (!in_array($pr, $old_privileges)) { + $changed = true; + } + } + foreach ($application["capabilities"] as $pr) { + if (!in_array($pr, $old_capabilities)) { + $changed = true; + } + } + + if ($changed) { + $application_original->setPrivilegesCapabilitiesLastUpdate(new \DateTime()); + $application_original->setTwakeTeamValidation(false); + $application_original->setIsAvailableToPublic(false); + } + + $application_original->setPrivileges($application["privileges"]); + $application_original->setCapabilities($application["capabilities"]); + $application_original->setHooks($application["hooks"]); + + $application_original->setDisplayConfiguration($application["display"]); + } + + $application_original->setApiAllowedIp($application["api_allowed_ips"]); + + if (strpos($application["api_event_url"], "https") === 0 || !$application_original->getisAvailableToPublic()) { + $application_original->setApiEventsUrl($application["api_event_url"]); + } + + $application_original->setPublic($application["public"]); + if (!$application["public"]) { + $application_original->setTwakeTeamValidation(false); + $application_original->setIsAvailableToPublic(false); + } + + $this->doctrine->persist($application_original); + $this->doctrine->flush(); + + return $application_original->getAsArrayForDevelopers(); + + } + + } + + return false; + + } + + public function toggleAppDefault($application_id, $status = null){ + $appsRepository = $this->doctrine->getRepository("Twake\Market:Application"); + $app = $appsRepository->findOneBy(array("id" => $application_id)); + + $rep = false; + + if ($app) { + + $app->setEsIndexed(false); + + if($status === null){ + $status = !$app->getDefault(); + } + + $app->setDefault($status); + $this->doctrine->persist($app); + } + + $this->doctrine->flush(); + } + + public function toggleAppValidation($application_id, $status = null){ + $appsRepository = $this->doctrine->getRepository("Twake\Market:Application"); + $app = $appsRepository->findOneBy(array("id" => $application_id)); + + $rep = false; + + if ($app) { + + $app->setEsIndexed(false); + + if ($app->getPublic()) { + + if($status === null){ + $status = !$app->getIsAvailableToPublic(); + } + + $app->setIsAvailableToPublic($status); + if(!$status){ + $app->setPublic(false); + } + $this->doctrine->persist($app); + } + } + + $this->doctrine->flush(); + } + + public function remove($application_id, $current_user_id) + { + + $applicationRepository = $this->doctrine->getRepository("Twake\Market:Application"); + $application = $applicationRepository->findOneBy(Array('id' => $application_id)); + + if ($application) { + + $group_id = $application->getGroupId(); + if ($current_user_id == null + || $this->gms->hasPrivileges( + $this->gms->getLevel($group_id, $current_user_id), + "MANAGE_APPS" + ) + ) { + + if (!$application->getisAvailableToPublic()) { + + $this->doctrine->getRepository("Twake\Market:ApplicationResourceNode")->removeBy(Array("application_id" => $application->getId())); + //TODO REMOVE EVERYWHERE + + $this->doctrine->remove($application); + $this->doctrine->flush(); + + return true; + + } + + } + + } + + return false; + + } + + + public function search($group_id, $query, $current_user_id = null) + { + + $allows_unpublished_apps_from_group_id = "null"; + if ($current_user_id == null + || $this->gms->hasPrivileges( + $this->gms->getLevel($group_id, $current_user_id), + "MANAGE_APPS" + ) + ) { + $allows_unpublished_apps_from_group_id = $group_id; + } + + $options = Array( + "repository" => "Twake\Market:Application", + "index" => "applications", + "fallback_keys" => Array( + "name" => $query + ), + "query" => Array( + "bool" => Array( + "filter" => Array( + "query_string" => Array( + "query" => "group_id:" . $allows_unpublished_apps_from_group_id . " OR public:true" + ) + ), + "must" => Array( + "query_string" => Array( + "query" => "*" . $query . "*" + ) + ) + ) + ) + ); + + $applications = $this->doctrine->es_search($options); + + $result = []; + foreach ($applications["result"] as $application) { + $application = $application[0]; + if ($allows_unpublished_apps_from_group_id == $application->getGroupId() || $application->getPublic()) { + $result[] = $application->getAsArray(); + } + } + + if(count($result) === 0){ + $app = $this->findAppBySimpleName($query); + if($app){ + $result[] = $app; + }else{ + $app = $this->findAppBySimpleName("twake.".$query); + if($app){ + $result[] = $app; + } + } + } + + return $result; + } + +} diff --git a/twake/backend/core/src/Twake/Market/Services/RollingCurlX.php b/twake/backend/core/src/Twake/Market/Services/RollingCurlX.php new file mode 100755 index 00000000..44077a68 --- /dev/null +++ b/twake/backend/core/src/Twake/Market/Services/RollingCurlX.php @@ -0,0 +1,263 @@ +<?php + +namespace Twake\Market\Services; + +/* + ---------- RollingCurlX 3.0.2 ----------- + an easy to use curl_multi wrapper for php + Copyright (c) 2015-2017 Marcus Leath + License: MIT + https://github.com/marcushat/RollingCurlX +*/ + +class RollingCurlX +{ + public $requests = []; + private $_curl_version; //max. number of simultaneous connections allowed + private $_maxConcurrent = 0; //shared cURL options + private $_options = []; //shared cURL request headers + private $_headers = []; //default callback + private $_callback = NULL; //all requests must be completed by this time + private $_timeout = 5000; //request_queue + private $curle_msgs = [CURLE_OK => 'OK', CURLE_UNSUPPORTED_PROTOCOL => 'UNSUPPORTED_PROTOCOL', CURLE_FAILED_INIT => 'FAILED_INIT', CURLE_URL_MALFORMAT => 'URL_MALFORMAT', CURLE_URL_MALFORMAT_USER => 'URL_MALFORMAT_USER', CURLE_COULDNT_RESOLVE_PROXY => 'COULDNT_RESOLVE_PROXY', CURLE_COULDNT_RESOLVE_HOST => 'COULDNT_RESOLVE_HOST', CURLE_COULDNT_CONNECT => 'COULDNT_CONNECT', CURLE_FTP_WEIRD_SERVER_REPLY => 'FTP_WEIRD_SERVER_REPLY', CURLE_FTP_ACCESS_DENIED => 'FTP_ACCESS_DENIED', CURLE_FTP_USER_PASSWORD_INCORRECT => 'FTP_USER_PASSWORD_INCORRECT', CURLE_FTP_WEIRD_PASS_REPLY => 'FTP_WEIRD_PASS_REPLY', CURLE_FTP_WEIRD_USER_REPLY => 'FTP_WEIRD_USER_REPLY', CURLE_FTP_WEIRD_PASV_REPLY => 'FTP_WEIRD_PASV_REPLY', CURLE_FTP_WEIRD_227_FORMAT => 'FTP_WEIRD_227_FORMAT', CURLE_FTP_CANT_GET_HOST => 'FTP_CANT_GET_HOST', CURLE_FTP_CANT_RECONNECT => 'FTP_CANT_RECONNECT', CURLE_FTP_COULDNT_SET_BINARY => 'FTP_COULDNT_SET_BINARY', CURLE_PARTIAL_FILE => 'PARTIAL_FILE', CURLE_FTP_COULDNT_RETR_FILE => 'FTP_COULDNT_RETR_FILE', CURLE_FTP_WRITE_ERROR => 'FTP_WRITE_ERROR', CURLE_FTP_QUOTE_ERROR => 'FTP_QUOTE_ERROR', CURLE_HTTP_NOT_FOUND => 'HTTP_NOT_FOUND', CURLE_WRITE_ERROR => 'WRITE_ERROR', CURLE_MALFORMAT_USER => 'MALFORMAT_USER', CURLE_FTP_COULDNT_STOR_FILE => 'FTP_COULDNT_STOR_FILE', CURLE_READ_ERROR => 'READ_ERROR', CURLE_OUT_OF_MEMORY => 'OUT_OF_MEMORY', CURLE_OPERATION_TIMEOUTED => 'OPERATION_TIMEOUTED', CURLE_FTP_COULDNT_SET_ASCII => 'FTP_COULDNT_SET_ASCII', CURLE_FTP_PORT_FAILED => 'FTP_PORT_FAILED', CURLE_FTP_COULDNT_USE_REST => 'FTP_COULDNT_USE_REST', CURLE_FTP_COULDNT_GET_SIZE => 'FTP_COULDNT_GET_SIZE', CURLE_HTTP_RANGE_ERROR => 'HTTP_RANGE_ERROR', CURLE_HTTP_POST_ERROR => 'HTTP_POST_ERROR', CURLE_SSL_CONNECT_ERROR => 'SSL_CONNECT_ERROR', CURLE_FTP_BAD_DOWNLOAD_RESUME => 'FTP_BAD_DOWNLOAD_RESUME', CURLE_FILE_COULDNT_READ_FILE => 'FILE_COULDNT_READ_FILE', CURLE_LDAP_CANNOT_BIND => 'LDAP_CANNOT_BIND', CURLE_LDAP_SEARCH_FAILED => 'LDAP_SEARCH_FAILED', CURLE_LIBRARY_NOT_FOUND => 'LIBRARY_NOT_FOUND', CURLE_FUNCTION_NOT_FOUND => 'FUNCTION_NOT_FOUND', CURLE_ABORTED_BY_CALLBACK => 'ABORTED_BY_CALLBACK', CURLE_BAD_FUNCTION_ARGUMENT => 'BAD_FUNCTION_ARGUMENT', CURLE_BAD_CALLING_ORDER => 'BAD_CALLING_ORDER', CURLE_HTTP_PORT_FAILED => 'HTTP_PORT_FAILED', CURLE_BAD_PASSWORD_ENTERED => 'BAD_PASSWORD_ENTERED', CURLE_TOO_MANY_REDIRECTS => 'TOO_MANY_REDIRECTS', CURLE_UNKNOWN_TELNET_OPTION => 'UNKNOWN_TELNET_OPTION', CURLE_TELNET_OPTION_SYNTAX => 'TELNET_OPTION_SYNTAX', CURLE_OBSOLETE => 'OBSOLETE', CURLE_SSL_PEER_CERTIFICATE => 'SSL_PEER_CERTIFICATE', CURLE_GOT_NOTHING => 'GOT_NOTHING', CURLE_SSL_ENGINE_NOTFOUND => 'SSL_ENGINE_NOTFOUND', CURLE_SSL_ENGINE_SETFAILED => 'SSL_ENGINE_SETFAILED', CURLE_SEND_ERROR => 'SEND_ERROR', CURLE_RECV_ERROR => 'RECV_ERROR', CURLE_SHARE_IN_USE => 'SHARE_IN_USE', CURLE_SSL_CERTPROBLEM => 'SSL_CERTPROBLEM', CURLE_SSL_CIPHER => 'SSL_CIPHER', CURLE_SSL_CACERT => 'SSL_CACERT', CURLE_BAD_CONTENT_ENCODING => 'BAD_CONTENT_ENCODING', CURLE_LDAP_INVALID_URL => 'LDAP_INVALID_URL', CURLE_FILESIZE_EXCEEDED => 'FILESIZE_EXCEEDED', CURLE_FTP_SSL_FAILED => 'FTP_SSL_FAILED', CURLE_SSH => 'SSH' + ]; + + function __construct($max_concurrent = 10) + { + $this->setMaxConcurrent($max_concurrent); + $this->_curl_version = curl_version()['version']; + } + + public function setMaxConcurrent($max_requests) + { + if ($max_requests > 0) { + $this->_maxConcurrent = $max_requests; + } + } + + public function setOptions(array $options) + { + $this->_options = $options; + } + + public function setHeaders(array $headers) + { + if (is_array($headers) && count($headers)) { + $this->_headers = $headers; + } + } + + public function setCallback(callable $callback) + { + $this->_callback = $callback; + } + + //Add a request to the request queue + + public function setTimeout($timeout) + { //in milliseconds + if ($timeout > 0) { + $this->_timeout = $timeout; + } + } + + //Reset request queue + + public function addRequest( + $url, + $post_data = NULL, + callable $callback = NULL, //individual callback + $user_data = NULL, + array $options = NULL, //individual cURL options + array $headers = NULL //individual cURL request headers + ) + { //Add to request queue + $this->requests[] = [ + 'url' => $url, + 'post_data' => ($post_data) ? $post_data : NULL, + 'callback' => ($callback) ? $callback : $this->_callback, + 'user_data' => ($user_data) ? $user_data : NULL, + 'options' => ($options) ? $options : NULL, + 'headers' => ($headers) ? $headers : NULL + ]; + return count($this->requests) - 1; //return request number/index + } + + public function execute() + { + //the request map that maps the request queue to request curl handles + $requests_map = []; + $multi_handle = curl_multi_init(); + $num_outstanding = 0; + //start processing the initial request queue + $num_initial_requests = min($this->_maxConcurrent, count($this->requests)); + for ($i = 0; $i < $num_initial_requests; $i++) { + $this->init_request($i, $multi_handle, $requests_map); + $num_outstanding++; + } + do { + do { + $mh_status = curl_multi_exec($multi_handle, $active); + } while ($mh_status == CURLM_CALL_MULTI_PERFORM); + if ($mh_status != CURLM_OK) { + break; + } + //a request is just completed, find out which one + while ($completed = curl_multi_info_read($multi_handle)) { + $this->process_request($completed, $multi_handle, $requests_map); + $num_outstanding--; + //try to add/start a new requests to the request queue + while ( + $num_outstanding < $this->_maxConcurrent && //under the limit + $i < count($this->requests) && isset($this->requests[$i]) // requests left + ) { + $this->init_request($i, $multi_handle, $requests_map); + $num_outstanding++; + $i++; + } + } + usleep(15); //save CPU cycles, prevent continuous checking + } while ($active || count($requests_map)); //End do-while + $this->reset(); + curl_multi_close($multi_handle); + } + + //Execute the request queue + + private function init_request($request_num, $multi_handle, &$requests_map) + { + $request =& $this->requests[$request_num]; + $this->addTimer($request); + $ch = curl_init(); + $options = $this->buildOptions($request); + $request['options_set'] = $options; //merged options + $opts_set = curl_setopt_array($ch, $options); + if (!$opts_set) { + echo 'options not set'; + exit; + } + curl_multi_add_handle($multi_handle, $ch); + //add curl handle of a new request to the request map + $ch_hash = (string)$ch; + $requests_map[$ch_hash] = $request_num; + } + + //Build individual cURL options for a request + + private function addTimer(array &$request) + { //adds timer object to request + $request['timer'] = microtime(true); //start time + $request['time'] = false; //default if not overridden by time later + } + + private function buildOptions(array $request) + { + $url = $request['url']; + $post_data = $request['post_data']; + $individual_opts = $request['options']; + $individual_headers = $request['headers']; + $options = ($individual_opts) ? $individual_opts + $this->_options : $this->_options; //merge shared and individual request options + $headers = ($individual_headers) ? $individual_headers + $this->_headers : $this->_headers; //merge shared and individual request headers + //the below will overide the corresponding default or individual options + $options[CURLOPT_RETURNTRANSFER] = true; + $options[CURLOPT_NOSIGNAL] = 1; + if (version_compare($this->_curl_version, '7.16.2') >= 0) { + $options[CURLOPT_CONNECTTIMEOUT_MS] = $this->_timeout; + $options[CURLOPT_TIMEOUT_MS] = $this->_timeout; + unset($options[CURLOPT_CONNECTTIMEOUT]); + unset($options[CURLOPT_TIMEOUT]); + } else { + $options[CURLOPT_CONNECTTIMEOUT] = round($this->_timeout / 1000); + $options[CURLOPT_TIMEOUT] = round($this->_timeout / 1000); + unset($options[CURLOPT_CONNECTTIMEOUT_MS]); + unset($options[CURLOPT_TIMEOUT_MS]); + } + if ($url) { + $options[CURLOPT_URL] = $url; + } + if ($headers) { + $options[CURLOPT_HTTPHEADER] = $headers; + } + // enable POST method and set POST parameters + if ($post_data !== null) { + $options[CURLOPT_POST] = 1; + $options[CURLOPT_POSTFIELDS] = is_array($post_data) ? http_build_query($post_data) : $post_data; + } + return $options; + } + + private function process_request($completed, $multi_handle, array &$requests_map) + { + $ch = $completed['handle']; + $ch_hash = (string)$ch; + $request =& $this->requests[$requests_map[$ch_hash]]; //map handler to request index to get request info + $request_info = curl_getinfo($ch); + $request_info['curle'] = $completed['result']; + $request_info['curle_msg'] = isset($this->curle_msgs[$completed['result']]) ? $this->curle_msgs[$completed['result']] : curl_strerror($completed['result']); + $request_info['handle'] = $ch; + $request_info['time'] = $time = $this->stopTimer($request); //record request time + $request_info['url_raw'] = $url = $request['url']; + $request_info['user_data'] = $user_data = $request['user_data']; + if (curl_errno($ch) !== 0 || intval($request_info['http_code']) !== 200) { //if server responded with http error + $response = false; + } else { //sucessful response + $response = curl_multi_getcontent($ch); + } + //get request info + $callback = $request['callback']; + $options = $request['options_set']; + if ($response && !empty($options[CURLOPT_HEADER])) { + $k = intval($request_info['header_size']); + $request_info['response_header'] = substr($response, 0, $k); + $response = substr($response, $k); + } + //remove completed request and its curl handle + unset($requests_map[$ch_hash]); + curl_multi_remove_handle($multi_handle, $ch); + //call the callback function and pass request info and user data to it + if ($callback) { + call_user_func($callback, $response, $url, $request_info, $user_data, $time); + } + $request = NULL; //free up memory now just incase response was large + } + + private function stopTimer(array &$request) + { + $elapsed = microtime(true) - $request['timer']; + $request['time'] = $elapsed; + unset($request['timer']); + return $elapsed; + } + + public function reset() + { + $this->requests = []; + } + + private function normalize_headers(array $headers) + { + $normalized = []; + foreach ($headers as $key => $header) { + if (is_string($key)) { + $normal = "$key: $header"; + } else { + $header; + } + $normalized = []; + } + } + + private function check_for_timeouts($mh) + { //DO NOT USE!!! Not implemented yet. + $now = microtime(true); + $requests = $this->_requests; + foreach ($requests as $request) { + $timeout = $request->timeout; + $start_time = $request->start_time; + $ch = $request->handle; + if ($now >= $start_time + $timeout) { + curl_multi_remove_handle($mh, $ch); + } + } + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Notifications/Bundle.php b/twake/backend/core/src/Twake/Notifications/Bundle.php new file mode 100755 index 00000000..4e1c2200 --- /dev/null +++ b/twake/backend/core/src/Twake/Notifications/Bundle.php @@ -0,0 +1,30 @@ +<?php + +namespace Twake\Notifications; + +require_once __DIR__ . "/Resources/Routing.php"; +require_once __DIR__ . "/Resources/Services.php"; + +use Twake\Notifications\Resources\Routing; +use Twake\Notifications\Resources\Services; +use Common\BaseBundle; + +class Bundle extends BaseBundle +{ + + protected $bundle_root = __DIR__; + protected $bundle_namespace = __NAMESPACE__; + protected $routes = []; + protected $services = []; + + public function init() + { + $routing = new Routing(); + $this->routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Notifications/Command/NotificationMailCommand.php b/twake/backend/core/src/Twake/Notifications/Command/NotificationMailCommand.php new file mode 100755 index 00000000..51c89813 --- /dev/null +++ b/twake/backend/core/src/Twake/Notifications/Command/NotificationMailCommand.php @@ -0,0 +1,134 @@ +<?php + +namespace Twake\Notifications\Command; + +use Emojione\Client; +use Emojione\Ruleset; +use Common\Commands\ContainerAwareCommand; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Twake\Core\Services\DoctrineAdapter\ManagerAdapter; +use Twake\Core\Services\Queues\Scheduled; +use Twake\Notifications\Entity\MailNotificationQueue; +use Twake\Notifications\Entity\UserNotificationStatus; +use Twake\Users\Entity\User; + + +class NotificationMailCommand extends ContainerAwareCommand +{ + + protected function configure() + { + $this->setName("twake:notifications_mail"); + } + + protected function execute() + { + + $services = $this->getApp()->getServices(); + $em = $services->get('app.twake_doctrine'); + /** @var Scheduled $scheduled */ + $scheduled = $services->get("app.queues_scheduled"); + + $repo = $em->getRepository("Twake\Notifications:MailNotificationQueue"); + + $limit = date("U", date("U") + 60); + + while (date("U") < $limit) { + + $reminders = $scheduled->consume("mail_reminder", true); + + if (count($reminders ?: []) == 0) { + break; + } + + //Get users to notify + foreach ($reminders ?: [] as $reminder_original) { + + $reminder = $scheduled->getMessage($reminder_original); + + /** @var ManagerAdapter $entry */ + $entry = $repo->findOneBy(Array("id" => $reminder["id"], "user_id" => $reminder["user_id"])); + + if ($entry && $entry->getToken() === $reminder["token"]) { + + $user_notification_status = $em->getRepository("Twake\Notifications:UserNotificationStatus")->findOneBy(Array("user_id" => $entry->getUserId())); + if (!$user_notification_status) { + $user_notification_status = new UserNotificationStatus($entry->getUserId()); + } + + if ($user_notification_status->getMailStatus() == 0) { + $user_notification_status->setMailStatus(1); + + $users = []; + $users[] = Array("user" => $entry->getUserId(), "date" => $entry->getDate()->getTimestamp()); + $em->remove($entry); + + $em->persist($user_notification_status); + $this->sendMail($users, "messages_notifications"); + $em->flush(); + } + + } + + $scheduled->ack("mail_reminder", $reminder_original); + + } + + } + + } + + /** + * @param $users_id_count + * @param string $template + * @param null $app + * @param bool $all_and_delete + */ + protected function sendMail($users_ids, $template = "unread_notifications") + { + + $services = $this->getApp()->getServices(); + $em = $services->get('app.twake_doctrine'); + + $emojione_client = new Client(new Ruleset()); + + foreach ($users_ids as $user) { + + $user_id = $user["user"]; + $date = $user["date"]; + + /** @var $user User */ + $user = $em->getRepository("Twake\Users:User")->find($user_id); + + $preferences = $user->getNotificationPreference(); + $mail_preferences = isset($preferences["mail_notifications"]) ? $preferences["mail_notifications"] : 2; + + if ($mail_preferences == 0) { + continue; + } + + $count = max(0, $user->getNotificationWriteIncrement() - $user->getNotificationReadIncrement()); + $notifications = $em->getRepository("Twake\Notifications:Notification")->findBy(Array("user" => $user_id), Array(), $count); + + $data = Array( + "username" => $user->getFullName(), + "total_notifications" => $count, + "notifications" => Array() + ); + + foreach ($notifications as $notification) { + $data["notifications"][] = Array( + "title" => html_entity_decode($emojione_client->shortnameToUnicode($notification->getTitle()), ENT_NOQUOTES, 'UTF-8'), + "delay" => (new \DateTime())->diff($notification->getDate())->format("%h"), + "text" => html_entity_decode($emojione_client->shortnameToUnicode($notification->getText()), ENT_NOQUOTES, 'UTF-8') + ); + } + + $services->get("app.twake_mailer")->send($user->getEmail(), $template, $data); + + } + + } + +} diff --git a/twake/backend/core/src/Twake/Notifications/Controller/Base.php b/twake/backend/core/src/Twake/Notifications/Controller/Base.php new file mode 100755 index 00000000..f4479a98 --- /dev/null +++ b/twake/backend/core/src/Twake/Notifications/Controller/Base.php @@ -0,0 +1,110 @@ +<?php + +namespace Twake\Notifications\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class Base extends BaseController +{ + + public function getAction() + { + + $messages = $this->get("app.twake_doctrine")->getRepository("Twake\Market:Application")->findOneBy(Array("simple_name" => "messages")); + + $notifs = $this->get("app.notifications")->getAll($this->getUser()); + $data = Array(); + foreach ($notifs as $notif) { + $obj = $notif->getAsArray(); + $data[] = $obj; + } + return new Response(Array("data" => $data)); + + } + + public function remove(Request $request) + { + $data = Array( + 'errors' => Array(), + 'data' => Array() + ); + + $application_tmp = $request->request->get("application"); + $workspace_id_tmp = $request->request->get("workspace_id"); + + $application_id = isset($application_tmp["id"]) ? $application_tmp["id"] : $application_tmp; + + $workspace_id = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:Workspace")->findOneBy(Array("id" => $workspace_id_tmp)); + $application = $this->get("app.twake_doctrine")->getRepository("Twake\Market:Application")->findOneBy(Array("id" => $application_id)); + + $user = $this->getUser(); + $delete = $this->get('app.notifications')->deleteAll($application, $workspace_id, $user, null, false); + if (!$delete) { + $data["errors"][] = "no removal made"; + } else { + $data["data"][] = "success"; + } + + return new Response($data); + } + + public function deleteAllExceptMessages(Request $request) + { + $data = Array( + 'errors' => Array(), + 'data' => Array() + ); + + $user = $this->getUser(); + $delete = $this->get('app.notifications')->deleteAllExceptMessages($user); + + if (!$delete) { + $data["errors"][] = "no removal made"; + } else { + $data["data"][] = "success"; + } + + return new Response($data); + } + + public function readAllExceptMessages(Request $request) + { + $data = Array( + 'errors' => Array(), + 'data' => Array() + ); + + $user = $this->getUser(); + $delete = $this->get('app.notifications')->readAllExceptMessages($user); + + if (!$delete) { + $data["errors"][] = "no read made"; + } else { + $data["data"][] = "success"; + } + + return new Response($data); + } + + + public function readAll(Request $request) + { + $data = Array( + 'errors' => Array(), + 'data' => Array() + ); + + $user = $this->getUser(); + $delete = $this->get('app.notifications')->readAll($user); + if (!$delete) { + $data["errors"][] = "no read made"; + } else { + $data["data"][] = "success"; + } + + return new Response($data); + } + +} diff --git a/twake/backend/core/src/Twake/Notifications/Entity/MailNotificationQueue.php b/twake/backend/core/src/Twake/Notifications/Entity/MailNotificationQueue.php new file mode 100755 index 00000000..c7b1a52d --- /dev/null +++ b/twake/backend/core/src/Twake/Notifications/Entity/MailNotificationQueue.php @@ -0,0 +1,100 @@ +<?php + +namespace Twake\Notifications\Entity; + +use Doctrine\ORM\Mapping as ORM; + + +/** + * Mail + * + * @ORM\Table(name="mail_push_queue",options={"engine":"MyISAM", "scylladb_keys":{{"id":"ASC"}, {"user_id":"ASC"} }}) + * @ORM\Entity() + */ +class MailNotificationQueue +{ + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(type="twake_no_salt_text") + */ + private $user_id; + + /** + * @ORM\Column(type="twake_datetime") + */ + private $date; + + /** + * @ORM\Column(type="twake_text") + */ + private $atoken; + + + public function __construct($user_id) + { + $this->date = new \DateTime(); + $this->user_id = $user_id; + } + + /** + * @return int + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return \DateTime + */ + public function setDate($date) + { + $this->date = $date; + } + + /** + * @return \DateTime + */ + public function getDate() + { + return $this->date; + } + + /** + * @return \DateTime + */ + public function getUserId() + { + return $this->user_id; + } + + /** + * @return mixed + */ + public function getToken() + { + return $this->atoken; + } + + /** + * @param mixed $token + */ + public function setToken($token): void + { + $this->atoken = $token; + } + + +} diff --git a/twake/backend/core/src/Twake/Notifications/Entity/Notification.php b/twake/backend/core/src/Twake/Notifications/Entity/Notification.php new file mode 100755 index 00000000..1bba4c4a --- /dev/null +++ b/twake/backend/core/src/Twake/Notifications/Entity/Notification.php @@ -0,0 +1,305 @@ +<?php + +namespace Twake\Notifications\Entity; + +use Doctrine\ORM\Mapping as ORM; + + +/** + * Mail + * + * @ORM\Table(name="notification",options={"engine":"MyISAM", "scylladb_keys":{ {"user_id":"ASC", "id":"DESC"}, {"id":"DESC"} }}) + * @ORM\Entity() + */ +class Notification +{ + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(type="twake_no_salt_text") + * @ORM\Id + */ + private $application_id; + + /** + * @ORM\Column(type="twake_no_salt_text") + */ + private $channel_id; + + /** + * @ORM\Column(type="twake_no_salt_text") + * @ORM\Id + */ + private $workspace_id; + + /** + * @ORM\ManyToOne(targetEntity="Twake\Users\Entity\User") + * @ORM\Id + */ + private $user; + + /** + * @ORM\Column(type="twake_no_salt_text", nullable=true) + */ + private $code; + + /** + * @ORM\Column(type="twake_no_salt_text", nullable=true) + */ + private $shortcut; + + /** + * @ORM\Column(type="twake_text", nullable=true) + */ + private $title; + + /** + * @ORM\Column(type="twake_text", nullable=true) + */ + private $text; + + /** + * @ORM\Column(type="twake_text") + */ + private $data = "{}"; + + /** + * @ORM\Column(type="twake_datetime") + */ + private $date; + + /** + * @ORM\Column(type="integer", nullable=false) + */ + private $mail_sent = 0; + + /** + * @ORM\Column(type="twake_datetime", nullable=true) + */ + private $last_mail = null; + + /** + * @ORM\Column(type="twake_boolean" , options={"default" : true}) + */ + private $isread; + + public function __construct($application_id, $workspace_id, $channel_id, $user) + { + $this->date = new \DateTime(); + $this->application_id = $application_id; + $this->workspace_id = $workspace_id; + $this->channel_id = $channel_id; + $this->user = $user; + $this->setIsRead(false); + } + + /** + * @return int + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getApplicationId() + { + return $this->application_id; + } + + /** + * @return mixed + */ + public function getWorkspaceId() + { + return $this->workspace_id; + } + + /** + * @return \DateTime + */ + public function getDate() + { + return $this->date; + } + + /** + * @return mixed + */ + public function getUser() + { + return $this->user; + } + + /** + * @return mixed + */ + public function getCode() + { + return $this->code; + } + + /** + * @param mixed $code + */ + public function setCode($code) + { + $this->code = $code; + } + + /** + * @return mixed + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param mixed $title + */ + public function setTitle($title) + { + $this->title = $title; + } + + /** + * @return mixed + */ + public function getText() + { + return $this->text; + } + + /** + * @param mixed $text + */ + public function setText($text) + { + $this->text = $text; + } + + /** + * @return mixed + */ + public function getData() + { + if (!$this->data) { + return null; + } + return json_decode($this->data, 1); + } + + /** + * @param mixed $data + */ + public function setData($data) + { + $this->data = json_encode($data); + } + + /** + * @return mixed + */ + public function getMailSent() + { + return $this->mail_sent; + } + + /** + * @param mixed $mail_sent + */ + public function setMailSent($mail_sent) + { + $this->mail_sent = $mail_sent; + } + + /** + * @return mixed + */ + public function getLastMail() + { + return $this->last_mail; + } + + /** + * @param mixed $last_mail + */ + public function setLastMail($last_mail) + { + $this->last_mail = $last_mail; + } + + /** + * @return mixed + */ + public function getChannelId() + { + return $this->channel_id; + } + + + public function getAsArray() + { + return Array( + "id" => $this->getId(), + "date" => $this->getDate()->getTimestamp(), + "code" => $this->getCode(), + "workspace_id" => ($this->getWorkspaceId() ? $this->getWorkspaceId() : null), + "application_id" => ($this->getApplicationId() ? $this->getApplication() : null), + "channel_id" => ($this->getChannelId() ? $this->getChannelId() : null), + "title" => $this->getTitle(), + "text" => $this->getText(), + "is_read" => $this->getisRead(), + "data" => $this->getData() + ); + } + + /** + * @return mixed + */ + public function getisRead() + { + return $this->isread; + } + + /** + * @param mixed $isread + */ + public function setIsRead($isread) + { + $this->isread = $isread; + } + + /** + * @return mixed + */ + public function getShortcut() + { + return $this->shortcut; + } + + /** + * @param mixed $shortcut + */ + public function setShortcut($shortcut) + { + $this->shortcut = $shortcut; + } + + +} + diff --git a/twake/backend/core/src/Twake/Notifications/Entity/PushNotificationQueue.php b/twake/backend/core/src/Twake/Notifications/Entity/PushNotificationQueue.php new file mode 100755 index 00000000..d9edac04 --- /dev/null +++ b/twake/backend/core/src/Twake/Notifications/Entity/PushNotificationQueue.php @@ -0,0 +1,89 @@ +<?php + +namespace Twake\Notifications\Entity; + +use Doctrine\ORM\Mapping as ORM; + + +/** + * Mail + * + * @ORM\Table(name="push_queue",options={"engine":"MyISAM"}) + * @ORM\Entity() + */ +class PushNotificationQueue +{ + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(type="twake_text", nullable=true) + */ + private $text; + + /** + * @ORM\Column(type="twake_datetime") + */ + private $date; + + + public function __construct($text) + { + $this->date = new \DateTime(); + $this->text = json_encode($text); + } + + /** + * @return int + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return \DateTime + */ + public function getDate() + { + return $this->date; + } + + /** + * @return mixed + */ + public function getText() + { + return json_decode($this->text); + } + + /** + * @param mixed $text + */ + public function setText($text) + { + $this->text = json_encode($text); + } + + + public function getAsArray() + { + return Array( + "id" => $this->getId(), + "date" => $this->getDate()->getTimestamp(), + "text" => $this->getText() + ); + } + +} + diff --git a/twake/backend/core/src/Twake/Notifications/Entity/UserNotificationStatus.php b/twake/backend/core/src/Twake/Notifications/Entity/UserNotificationStatus.php new file mode 100755 index 00000000..424bba75 --- /dev/null +++ b/twake/backend/core/src/Twake/Notifications/Entity/UserNotificationStatus.php @@ -0,0 +1,78 @@ +<?php + +namespace Twake\Notifications\Entity; + +use Doctrine\ORM\Mapping as ORM; + + +/** + * Mail + * + * @ORM\Table(name="user_notification_status",options={"engine":"MyISAM", "scylladb_keys":{ {"user_id":"ASC", "id":"DESC"} }}) + * @ORM\Entity() + */ +class UserNotificationStatus +{ + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="user_id", type="twake_timeuuid") + * @ORM\Id + */ + private $user_id; + + /** + * @ORM\Column(type="integer") + */ + private $mail_status; + + /** + * UserNotificationStatus constructor. + * @param $user + */ + public function __construct($user_id) + { + $this->user_id = $user_id; + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @param int $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getMailStatus() + { + return $this->mail_status; + } + + /** + * @param mixed $mail_status + */ + public function setMailStatus($mail_status) + { + $this->mail_status = $mail_status; + } + + +} + diff --git a/twake/backend/core/src/Twake/Notifications/Resources/Routing.php b/twake/backend/core/src/Twake/Notifications/Resources/Routing.php new file mode 100755 index 00000000..6aaba6d2 --- /dev/null +++ b/twake/backend/core/src/Twake/Notifications/Resources/Routing.php @@ -0,0 +1,20 @@ +<?php + +namespace Twake\Notifications\Resources; + +use Common\BaseRouting; + +class Routing extends BaseRouting +{ + + protected $routing_prefix = "ajax/notifications/"; + + protected $routes = [ + #Collections + //"get" => ["handler" => "Base:getAction", "methods" => ["POST"], "security" => ["user_connected_security"]], + //"remove" => ["handler" => "Base:remove", "methods" => ["POST"], "security" => ["user_connected_security"]], + //"deleteAll" => ["handler" => "Base:deleteAllExceptMessages", "methods" => ["POST"], "security" => ["user_connected_security"]], + //"readAll" => ["handler" => "Base:readAll", "methods" => ["POST"], "security" => ["user_connected_security"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Notifications/Resources/Services.php b/twake/backend/core/src/Twake/Notifications/Resources/Services.php new file mode 100755 index 00000000..b1077392 --- /dev/null +++ b/twake/backend/core/src/Twake/Notifications/Resources/Services.php @@ -0,0 +1,16 @@ +<?php + +namespace Twake\Notifications\Resources; + +use Common\BaseServices; + +class Services extends BaseServices +{ + + protected $services = [ + "app.notifications" => "Notifications", +// arguments: ["@app.twake_doctrine","@app.websockets", "@app.twake_mailer", "@app.restclient", "%PUSH_NOTIFICATION_SERVER%", "%STANDALONE%", "%LICENCE_KEY%"] +// public: true + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Notifications/Services/Notifications.php b/twake/backend/core/src/Twake/Notifications/Services/Notifications.php new file mode 100755 index 00000000..55314e45 --- /dev/null +++ b/twake/backend/core/src/Twake/Notifications/Services/Notifications.php @@ -0,0 +1,645 @@ +<?php + + +namespace Twake\Notifications\Services; + +use App\App; +use Emojione\Client; +use Emojione\Ruleset; +use Twake\Core\Services\DoctrineAdapter\ManagerAdapter; +use Twake\Core\Services\Queues\Adapters\QueueManager; +use Twake\Core\Services\Queues\Scheduled; +use Twake\Notifications\Entity\MailNotificationQueue; +use Twake\Notifications\Entity\Notification; +use Twake\Notifications\Entity\PushNotificationQueue; +use Twake\Notifications\Model\NotificationsInterface; +use Twake\Users\Entity\User; + +/** + * Class Notifications + * @package Twake\Users\Services + * + * Gestion des notifications + */ +class Notifications +{ + + /** @var ManagerAdapter */ + var $doctrine; + var $circle; + var $pushNotificationServer; + var $standalone; + var $licenceKey; + /** @var QueueManager */ + var $queues; + /** @var Scheduled */ + var $scheduled_queues; + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->queues = $app->getServices()->get("app.queues")->getAdapter(); + $this->scheduled_queues = $app->getServices()->get("app.queues_scheduled"); + $this->pusher = $app->getServices()->get("app.websockets"); + $this->mailer = $app->getServices()->get("app.twake_mailer"); + $this->circle = $app->getServices()->get("app.restclient"); + $this->pushNotificationServer = $app->getContainer()->getParameter("PUSH_NOTIFICATION_SERVER"); + $this->standalone = $app->getContainer()->getParameter("env.standalone"); + $this->licenceKey = $app->getContainer()->getParameter("env.licence_key"); + $this->emojione_client = new Client(new Ruleset()); + } + + // Collections part + public function init($route, $data, $current_user = null) + { + if (!is_string($current_user) && $current_user && explode("/", $route)[1] == $current_user->getId()) { + return true; + } + return false; + } + + /** + * @param null $application Application where the notification is from "null" = messaging service + * @param null $sender_application Application generating the notification + * @param null $sender_user User generating the notification + * @param null $workspace Workspace where the notification can be found + * @param null $channel Channel where the notification can be found + * @param null $users List of users which receive the notification + * @param null $code Identifier for the notification (mass deletion) + * @param null $text Text for the notification + * @param null $message Message + * @param null $additionnal_data + * @param array $type Types of notification : "push" and "mail" + * @param bool $save_notification Add notification to log or not (default true) + */ + public function pushNotification( + $application = null, + $sender_application = null, + $sender_user = null, + $workspace = null, + $channel = null, + $users = null, + $code = null, + $text = null, + $message = null, + $additionnal_data = Array(), + $type = Array(), + $save_notification = true + ) + { + + $text = trim($text); + $text = preg_replace("/ +/", " ", $text); + + //Construct title and text according with metadata + if ($sender_user) { + $title = $sender_user->getFullName(); + } else if ($sender_application) { + $title = $sender_application->getName(); + } else if ($application) { + $title = $application->getName(); + } else { + $title = "Notification"; + } + if ($channel && !$channel->getDirect()) { + $title .= " to "; + if ($channel->getIcon()) { + $title .= $channel->getIcon() . " "; + } + $title .= $channel->getName(); + } + if ($workspace) { + $group = $this->doctrine->getRepository("Twake\Workspaces:Group")->findOneBy(["id" => $workspace->getGroup()]); + $title .= " in " . $workspace->getName() . " (" . $group->getName() . ")"; + } + + if (($application || $sender_application) && $sender_user) { + if ($application) { + $text = $application->getName() . " : " . $text; + } else { + $text = $sender_application->getName() . " : " . $text; + } + } + //End title and text construction + + $data = Array( + "type" => "add", + + "company_id" => ($workspace != null ? $workspace->getGroup() : null), + "workspace_id" => ($workspace != null ? $workspace->getId() : null), + "channel_id" => ($channel != null ? $channel->getId() : null), + "message_id" => $message->getId(), + "thread_id" => $message->getParentMessageId(), + + "application_id" => ($application != null ? $application->getId() : null), + "sender_application_id" => ($sender_application != null ? $sender_application->getId() : null), + "sender_user_id" => ($sender_user != null ? $sender_user->getId() : null), + + "title" => $title, + "original_text" => $text, + "text" => $text, + "code" => $code, + "type" => $type, + "additionnal_data" => $additionnal_data, + ); + + $device_minimal_data = Array( + "company_id" => ($workspace != null ? $workspace->getGroup() : null), + "workspace_id" => ($workspace != null ? $workspace->getId() : null), + "channel_id" => ($channel != null ? $channel->getId() : null), + "message_id" => $message->getId(), + "thread_id" => $message ? $message->getParentMessageId() : "", + "click_action" => "FLUTTER_NOTIFICATION_CLICK", + ); + + $toPush = true; + + $count = count($users); + for ($i = 0; $i < $count; $i++) { + + $data["text"] = $data["original_text"]; + + $user = $this->doctrine->getRepository("Twake\Users:User")->find($users[$i]); + + if (!$user) { + continue; + } + + //Verify that user want this notification + + $notificationPreference = $user->getNotificationPreference(); + + $notification_disabled = false; + if ($notificationPreference["disable_until"] > 0) { + $delta = $notificationPreference["disable_until"] - time(); + if ($delta > 0) { + $notification_disabled = true; + } + } + + $mail_preferences = isset($notificationPreference["mail_notifications"]) ? $notificationPreference["mail_notifications"] : 2; + + $useDevices = false; + if ($data["workspace_id"] != null) { + $workspace_id = $data["workspace_id"]; + $disabled_workspaces = $notificationPreference["disabled_workspaces"]; + if (in_array($workspace_id . "", $disabled_workspaces)) { + return false; + } + if ($application != null) { + if (isset($notificationPreference["workspace"][$workspace_id . ""])) { + if (isset($notificationPreference["workspace"][$workspace_id . ""][$application->getId() . ""])) { + $toPush = false; + } + } + } + } + if ($notificationPreference["devices"] == 0) { + $useDevices = true; + } + if ($notificationPreference["devices"] == 1 && !$user->isConnected()) { + $useDevices = true; + } + if ($useDevices) { + $currentDate = gmdate("H") + floor(gmdate("i") / 30) / 2; + if ($notificationPreference["dont_disturb_between"] != null && $notificationPreference["dont_disturb_and"] != null) { + + if ($notificationPreference["dont_disturb_between"] < $notificationPreference["dont_disturb_and"] + && $currentDate >= $notificationPreference["dont_disturb_between"] + && $currentDate < $notificationPreference["dont_disturb_and"] + ) { + $useDevices = false; + } + if ($notificationPreference["dont_disturb_between"] > $notificationPreference["dont_disturb_and"] + && ($currentDate >= $notificationPreference["dont_disturb_between"] + || $currentDate < $notificationPreference["dont_disturb_and"]) + ) { + $useDevices = false; + } + + } + } + if (!$notificationPreference["dont_use_keywords"]) { + $keywords = explode(",", $notificationPreference["keywords"]); + $keywords[] = $user->getUsername(); + $present = false; + foreach ($keywords as $keyword) { + $keyword = trim($keyword); + $keyword = " " . $keyword . " "; + if (mb_strrpos(mb_strtolower($title . " " . $text . " "), mb_strtolower($keyword)) >= 0) { + $present = true; + } + } + if (!$present) { + continue; + } + } + if ($notificationPreference["privacy"]) { + $data["text"] = "[Private]"; + } + + $n = new Notification($application ? $application->getId() : "", $workspace ? $workspace->getId() : "", $channel ? $channel->getId() : "", $user); + if ($additionnal_data) { + $n->setData($additionnal_data); + } + if ($code) { + $n->setCode($code); + } + if ($text) { + $n->setText($text); + } + if ($title) { + $n->setTitle($title); + } + + if ($save_notification) { + $this->doctrine->persist($n); + + if ($mail_preferences == 2 || $mail_preferences == 1) { + $this->addMailReminder($user); + } + + } + + if (in_array("push", $type) && $toPush && !$notification_disabled) { + + $totalNotifications = 1; + if ($useDevices) { + @$this->pushDevice($user, $data["text"], $title, $totalNotifications, $device_minimal_data, false); + } else { + @$this->updateDeviceBadge($user, $totalNotifications, Array(), false); + } + + } + if (in_array("mail", $type)) { + @$this->sendMail($application, $workspace, $user, $text); + } + + if ($toPush && !$notification_disabled) { + $ws_data = Array( + "client_id" => "system", + "action" => "save", + "object_type" => "", + "object" => $n->getAsArray() + ); + $this->pusher->push("notifications/" . $user->getId(), $ws_data); + } + + } + + $this->doctrine->flush(); + + } + + public function pushDevice($user, $text, $title, $badge = null, $data = null, $doPush = true) + { + + $devicesRepo = $this->doctrine->getRepository("Twake\Users:Device"); + $devices = $devicesRepo->findBy(Array("user_id" => $user->getId())); + + $title = html_entity_decode($this->emojione_client->shortnameToUnicode($title), ENT_NOQUOTES, 'UTF-8'); + $text = html_entity_decode($this->emojione_client->shortnameToUnicode($text), ENT_NOQUOTES, 'UTF-8'); + + $count = count($devices); + for ($i = 0; $i < $count; $i++) { + $device = $devices[$i]; + + $token = $device->getValue(); + + $this->pushDeviceInternal($device->getType(), $token, + mb_substr($text, 0, 100) . (mb_strlen($title) > 100 ? "..." : ""), + mb_substr($title, 0, 50) . (mb_strlen($title) > 50 ? "..." : ""), + $badge, + $data, + $doPush + ); + + + } + } + + public function pushDeviceInternal($type, $deviceId, $message, $title, $badge, $_data, $doPush = true) + { + + if (mb_strlen($deviceId) < 32) { //False device + return; + } + + $data = Array( + "message" => $message, + "title" => $title, + "data" => json_encode($_data), + "badge" => $badge, + "device_id" => $deviceId, + "type" => $type + ); + + $this->queues->push("push_notification", $data); + } + + public function updateDeviceBadge($user, $badge = 0, $data = null, $doPush = true) + { + + $devicesRepo = $this->doctrine->getRepository("Twake\Users:Device"); + $devices = $devicesRepo->findBy(Array("user_id" => $user)); + + $count = count($devices); + for ($i = 0; $i < $count; $i++) { + $device = $devices[$i]; + + $token = $device->getValue(); + + $this->pushDeviceInternal($device->getType(), $token, + null, + null, + $badge, + $data, + $doPush + ); + + + } + } + + + /* Private */ + + public function sendMail($application, $workspace, $user, $text) + { + + $text = html_entity_decode($this->emojione_client->shortnameToUnicode($text), ENT_NOQUOTES, 'UTF-8'); + + $this->mailer->send($user->getEmail(), "notification", Array( + "_language" => $user ? $user->getLanguage() : "en", + "application_name" => ($application) ? $application->getName() : "Twake", + "workspace_name" => ($workspace) ? $workspace->getName() : "Account", + "username" => $user->getUsername(), + "text" => $text + )); + } + + public function deleteAll($application, $workspace, $user, $code = null, $force = false) + { + + //TODO + /* + $nRepo = $this->doctrine->getRepository("Twake\Notifications:Notification"); + + $search = Array( + "user" => $user + ); + + if ($code) { + $search["code"] = $code; + } + + if ($application) { + $search["application"] = $application; + } + + if ($workspace) { + $search["workspace"] = $workspace; + } + + $notif = $nRepo->findBy($search); + + $count = count($notif); + for($i = 0; $i < $count; $i++) { + $this->doctrine->remove($notif[$i]); + } + + if ($count == 0){ + return false; + } + + if($count>0 || $force) { + $this->doctrine->flush(); + + $totalNotifications = $this->countAll($user); + + $data = Array( + "action"=>"remove", + "workspace_id"=>($workspace)?$workspace->getId():null, + "app_id"=>($application)?$application->getId():null + ); + $this->pusher->push($data, "notifications/".$user->getId()); + + $this->updateDeviceBadge($user, $totalNotifications); + return true; + } + */ + + return true; + + + } + + public function readAll($user) + { + + $this->removeMailReminder($user); + + $has_notification_group = false; + $has_notification_workspace = false; + + $group_members = $this->doctrine->getRepository("Twake\Workspaces:GroupUser")->findBy(Array("user" => $user)); + foreach ($group_members as $group_member) { + if ($group_member->getHasNotifications()) { + $has_notification_group = true; + $group_member->setHasNotifications(false); + $this->doctrine->persist($group_member); + } + } + $this->doctrine->flush(); + + if ($has_notification_group) { + + $workspace_members = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser")->findBy(Array("user_id" => $user->getId())); + foreach ($workspace_members as $workspace_member) { + if ($workspace_member->getHasNotifications()) { + $has_notification_workspace = true; + $workspace_member->setHasNotifications(false); + $this->doctrine->persist($workspace_member); + } + } + $this->doctrine->flush(); + + } + + $channel_members = $this->doctrine->getRepository("Twake\Channels:ChannelMember")->findBy(Array("direct" => true, "user_id" => $user->getId())); + if ($has_notification_workspace) { + $channel_members = array_merge($channel_members, $this->doctrine->getRepository("Twake\Channels:ChannelMember")->findBy(Array("direct" => false, "user_id" => $user->getId()))); + } + foreach ($channel_members as $channel_member) { + + $channel = $this->doctrine->getRepository("Twake\Channels:Channel")->findOneBy(Array("id" => $channel_member->getChannelId())); + if (!$channel) { + $this->doctrine->remove($channel_member); + } + if ($channel && $channel->getMessagesIncrement() != $channel_member->getLastMessagesIncrement()) { + $channel_member->setLastMessagesIncrement($channel->getMessagesIncrement()); + $this->doctrine->persist($channel_member); + } + } + $this->doctrine->flush(); + + } + + /** + * @param $user User + */ + public function removeMailReminder($user) + { + if (!$user) { + return; + } + + $user_notification_status = $this->doctrine->getRepository("Twake\Notifications:UserNotificationStatus")->findOneBy(Array("user_id" => $user->getId())); + if ($user_notification_status) { + $user_notification_status->setMailStatus(0); + $this->doctrine->persist($user_notification_status); + } + + $user->setNotificationReadIncrement($user->getNotificationWriteIncrement()); + $this->doctrine->persist($user); + + $repo = $this->doctrine->getRepository("Twake\Notifications:MailNotificationQueue"); + $reminder = $repo->findOneBy(Array("user_id" => $user->getId())); + if ($reminder) { + $this->doctrine->remove($reminder); + $this->doctrine->flush(); + } + + } + + /** + * @param $user User + */ + private function addMailReminder($user) + { + + $user->setNotificationWriteIncrement($user->getNotificationWriteIncrement() + 1); + $this->doctrine->persist($user); + + $repo = $this->doctrine->getRepository("Twake\Notifications:MailNotificationQueue"); + $reminder = $repo->findOneBy(Array("user_id" => $user->getId())); + if (!$reminder) { + $token = base64_encode(bin2hex(random_bytes(32))); + + $reminder = new MailNotificationQueue($user->getId()); + $reminder->setToken($token); + $this->doctrine->useTTLOnFirstInsert(60 * 60 * 24); + $this->doctrine->persist($reminder); + + $this->scheduled_queues->schedule("mail_reminder", date("U") + 60 * 60 * 12, [ + "token" => $token, + "user_id" => $user->getId(), + "id" => $reminder->getId() + ]); + + } + + $this->doctrine->flush(); + + } + + public function get($options, $current_user) + { + return $this->getAll($current_user); + } + + public function getAll($user) + { + $nRepo = $this->doctrine->getRepository("Twake\Notifications:Notification"); + $notifs = $nRepo->findBy(Array("user" => $user), Array(), 30); //Limit number of results + + return $notifs; + } + + public function sendCustomMail($mail, $template, $data = Array(), $files = Array()) + { + $this->mailer->send($mail, $template, $data, $files); + } + + public function deleteAllExceptMessages($user, $force = false) + { + + return true; + + //TODO + /* + $app = $this->doctrine->getRepository("Twake\Market:Application")->findOneBy(array("simple_name" => "messages")); + + $nRepo = $this->doctrine->getRepository("Twake\Notifications:Notification"); + $notif = $nRepo->getAppNoMessages($app); + $count = count($notif); + + + if ($count == 0){ + return false; + } + for($i = 0; $i < $count; $i++) { + $this->doctrine->remove($notif[$i]); + } + + if($count>0 || $force) { + $this->doctrine->flush(); + + $data = Array( + "action" => "remove_all_non_messages" + ); + //convert + $this->pusher->push($data, "notifications/".$user->getId()); + + $totalNotifications = $this->countAll($user); + $this->updateDeviceBadge($user, $totalNotifications); + return true; + } + + return true;*/ + } + + public function readAllExceptMessages($user, $force = false) + { + + return true; + + //TODO + /* + + $app = $this->doctrine->getRepository("Twake\Market:Application")->findOneBy(array("simple_name" => "messages")); + + $nRepo = $this->doctrine->getRepository("Twake\Notifications:Notification"); + $notif = $nRepo->getAppNoMessages($app); + $count = count($notif); + + + if ($count == 0){ + return false; + } + for($i = 0; $i < $count; $i++) { + $notif[$i]->setIsRead(true); + $this->doctrine->persist($notif[$i]); + + } + + if($count>0 || $force) { + $this->doctrine->flush(); + + $totalNotifications = $this->countAll($user); + + $data = Array( + "action" => "remove_all_non_messages" + ); + //convert + $this->pusher->push($data, "notifications/".$user->getId()); + + $this->updateDeviceBadge($user, $totalNotifications); + return true; + } + + return true; + */ + } + +} diff --git a/twake/backend/core/src/Twake/Tasks/Bundle.php b/twake/backend/core/src/Twake/Tasks/Bundle.php new file mode 100755 index 00000000..4027f422 --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Bundle.php @@ -0,0 +1,30 @@ +<?php + +namespace Twake\Tasks; + +require_once __DIR__ . "/Resources/Routing.php"; +require_once __DIR__ . "/Resources/Services.php"; + +use Twake\Tasks\Resources\Routing; +use Twake\Tasks\Resources\Services; +use Common\BaseBundle; + +class Bundle extends BaseBundle +{ + + protected $bundle_root = __DIR__; + protected $bundle_namespace = __NAMESPACE__; + protected $routes = []; + protected $services = []; + + public function init() + { + $routing = new Routing(); + $this->routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Tasks/Command/TaskReminderCheckerCommand.php b/twake/backend/core/src/Twake/Tasks/Command/TaskReminderCheckerCommand.php new file mode 100755 index 00000000..1a5bc46a --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Command/TaskReminderCheckerCommand.php @@ -0,0 +1,40 @@ +<?php + +namespace Twake\Tasks\Command; + +use Common\Commands\ContainerAwareCommand; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + + +class TaskReminderCheckerCommand extends ContainerAwareCommand +{ + var $leveladmin; + var $output; + var $force; + var $twake; + + protected function configure() + { + $this + ->setName("twake:tasks_check_reminders"); + } + + + protected function execute() + { + $services = $this->getApp()->getServices(); + + $limit = date("U", date("U") + 60); + + while (date("U") < $limit) { + $sent = $services->get("app.tasks.task")->checkReminders(); + if ($sent == 0) { + sleep(30); + } + } + + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Tasks/Controller/Board.php b/twake/backend/core/src/Twake/Tasks/Controller/Board.php new file mode 100755 index 00000000..58fe1027 --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Controller/Board.php @@ -0,0 +1,53 @@ +<?php + +namespace Twake\Tasks\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class Board extends BaseController +{ + + + public function remove(Request $request) + { + $options = $request->request->get("options"); + $object = $request->request->get("object"); + $res = $this->get("app.tasks.board")->remove($object, $options, $this->getUser()); + if (!$res) { + return new Response(Array("status" => "error")); + } + if($GLOBALS["segment_enabled"]) \Segment::track([ + "event" => "tasks:board:remove", + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() + ]); + return new Response(Array("data" => Array("object" => $res))); + } + + public function save(Request $request) + { + $options = $request->request->get("options"); + $object = $request->request->get("object"); + $res = $this->get("app.tasks.board")->save($object, $options, $this->getUser()); + if (!$res) { + return new Response(Array("status" => "error")); + } + if($GLOBALS["segment_enabled"]) \Segment::track([ + "event" => "tasks:board:".($object["id"] ? "edit" : "create"), + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() + ]); + return new Response(Array("data" => Array("object" => $res))); + } + + public function getAction(Request $request) + { + $options = $request->request->get("options"); + $objects = $this->get("app.tasks.board")->get($options, $this->getUser()); + if ($objects === false) { + return new Response(Array("status" => "error")); + } + return new Response(Array("data" => $objects)); + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Tasks/Controller/BoardList.php b/twake/backend/core/src/Twake/Tasks/Controller/BoardList.php new file mode 100755 index 00000000..aa169f09 --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Controller/BoardList.php @@ -0,0 +1,67 @@ +<?php + +namespace Twake\Tasks\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class BoardList extends BaseController +{ + + + public function remove(Request $request) + { + $options = $request->request->get("options"); + $object = $request->request->get("object"); + $res = $this->get("app.tasks.list")->remove($object, $options, $this->getUser()); + if (!$res) { + return new Response(Array("status" => "error")); + } + return new Response(Array("data" => Array("object" => $res))); + } + + public function archiveAll(Request $request) + { + $options = $request->request->get("options"); + $object = $request->request->get("object"); + $res = $this->get("app.tasks.list")->archiveAllTasks($object, $options, $this->getUser()); + if ($res === false) { + return new Response(Array("status" => "error")); + } + return new Response(Array("status" => "ok")); + } + + public function removeAll(Request $request) + { + $options = $request->request->get("options"); + $object = $request->request->get("object"); + $res = $this->get("app.tasks.list")->removeAllTasks($object, $options, $this->getUser()); + if ($res === false) { + return new Response(Array("status" => "error")); + } + return new Response(Array("status" => "ok")); + } + + public function save(Request $request) + { + $options = $request->request->get("options"); + $object = $request->request->get("object"); + $res = $this->get("app.tasks.list")->save($object, $options, $this->getUser()); + if (!$res) { + return new Response(Array("status" => "error")); + } + return new Response(Array("data" => Array("object" => $res))); + } + + public function getAction(Request $request) + { + $options = $request->request->get("options"); + $objects = $this->get("app.tasks.list")->get($options, $this->getUser()); + if ($objects === false) { + return new Response(Array("status" => "error")); + } + return new Response(Array("data" => $objects)); + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Tasks/Controller/Export.php b/twake/backend/core/src/Twake/Tasks/Controller/Export.php new file mode 100755 index 00000000..20ba4f23 --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Controller/Export.php @@ -0,0 +1,27 @@ +<?php + + +namespace Twake\Tasks\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class Export extends BaseController +{ + public function export(Request $request) + { + $token = $request->query->get("token"); + if ($token) { + return $this->get("app.tasks.export")->exportBoard($token, $this->get("app.tasks.task")); + } else + return new Response("Errors : Token not found"); + } + + + public function generateToken(Request $request) + { + $user = $this->getUser(); + return new Response(Array("token" => $this->get("app.tasks.export")->generateToken($request, $user))); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Tasks/Controller/Task.php b/twake/backend/core/src/Twake/Tasks/Controller/Task.php new file mode 100755 index 00000000..fa5f505f --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Controller/Task.php @@ -0,0 +1,64 @@ +<?php + +namespace Twake\Tasks\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class Task extends BaseController +{ + + + public function remove(Request $request) + { + $options = $request->request->get("options"); + $object = $request->request->get("object"); + $res = $this->get("app.tasks.task")->remove($object, $options, $this->getUser()); + if (!$res) { + return new Response(Array("status" => "error")); + }else{ + if($GLOBALS["segment_enabled"]) \Segment::track([ + "event" => "tasks:task:remove", + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() + ]); + } + return new Response(Array("data" => Array("object" => $res))); + } + + public function save(Request $request) + { + $options = $request->request->get("options"); + $object = $request->request->get("object"); + $res = $this->get("app.tasks.task")->save($object, $options, $this->getUser()); + + if (!$object["id"]) { + $this->get("administration.counter")->incrementCounter("total_tasks", 1); + } + if($GLOBALS["segment_enabled"]) \Segment::track([ + "event" => "tasks:task:".($object["id"] ? "edit" : "create"), + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() + ]); + + if (!$res) { + return new Response(Array("status" => "error")); + } + return new Response(Array("data" => Array("object" => $res))); + } + + public function getAction(Request $request) + { + $options = $request->request->get("options"); + $objects = $this->get("app.tasks.task")->get($options, $this->getUser()); + if ($objects === false) { + return new Response(Array("status" => "error")); + }else{ + if($GLOBALS["segment_enabled"]) \Segment::track([ + "event" => "tasks:task:get", + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() + ]); + } + return new Response(Array("data" => $objects)); + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Tasks/Entity/Board.php b/twake/backend/core/src/Twake/Tasks/Entity/Board.php new file mode 100755 index 00000000..e71dca82 --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Entity/Board.php @@ -0,0 +1,227 @@ +<?php + +namespace Twake\Tasks\Entity; + +use DateTime; +use Doctrine\ORM\Mapping as ORM; + +use Twake\Core\Entity\FrontObject; + +/** + * Board + * + * @ORM\Table(name="board",options={"engine":"MyISAM", "scylladb_keys": {{"workspace_id":"ASC", "id":"ASC"}, {"id":"ASC"}} }) + * @ORM\Entity() + */ +class Board extends FrontObject +{ + + /** + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="workspace_id", type="twake_timeuuid") + * @ORM\Id + */ + private $workspace_id; + + /** + * @ORM\Column(name="title", type="twake_text", nullable=true) + */ + private $title; + + /** + * @ORM\Column(name="emoji", type="string", nullable=true) + */ + private $emoji; + + /** + * @ORM\Column(name="group_name", type="twake_no_salt_text", nullable=true) + */ + private $group_name; + + /** + * @ORM\Column(name="active_tasks", type="integer", nullable=true) + */ + private $active_tasks; + + /** + * @ORM\Column(name="view_mode", type="twake_text", nullable=true) + */ + private $view_mode = "grid"; + + /** + * @ORM\Column(name="connectors", type="twake_text", nullable=true) + */ + private $connectors = "[]"; + + /** + * @ORM\Column(name="deleted", type="twake_boolean") + */ + private $deleted = false; + + + public function __construct($workspace_id, $title) + { + $this->setWorkspaceId($workspace_id); + $this->setTitle($title); + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getWorkspaceId() + { + return $this->workspace_id; + } + + /** + * @param mixed $workspace_id + */ + public function setWorkspaceId($workspace_id) + { + $this->workspace_id = $workspace_id; + } + + /** + * @return mixed + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param mixed $title + */ + public function setTitle($title) + { + $this->title = $title; + } + + /** + * @return mixed + */ + public function getConnectors() + { + return json_decode($this->connectors, 1); + } + + /** + * @param mixed $tabs + */ + public function setConnectors($connectors) + { + $this->connectors = json_encode($connectors); + } + + /** + * @return mixed + */ + public function getEmoji() + { + return $this->emoji; + } + + /** + * @param mixed $emoji + */ + public function setEmoji($emoji) + { + $this->emoji = $emoji; + } + + /** + * @return mixed + */ + public function getActiveTasks() + { + return $this->active_tasks ? $this->active_tasks : 0; + } + + /** + * @param mixed $active_tasks + */ + public function setActiveTasks($active_tasks) + { + $this->active_tasks = $active_tasks; + } + + /** + * @return mixed + */ + public function getGroupName() + { + return $this->group_name; + } + + /** + * @param mixed $group_name + */ + public function setGroupName($group_name) + { + $this->group_name = $group_name; + } + + /** + * @return mixed + */ + public function getViewMode() + { + return $this->view_mode; + } + + /** + * @param mixed $view_mode + */ + public function setViewMode($view_mode) + { + $this->view_mode = $view_mode; + } + + public function getDeleted() + { + return $this->deleted; + } + + public function setDeleted($deleted) + { + $this->deleted = $deleted; + } + + public function getAsArray() + { + return Array( + "id" => $this->getId(), + "front_id" => $this->getFrontId(), + "title" => $this->getTitle(), + "emoji" => $this->getEmoji(), + "group_name" => $this->getGroupName(), + "view_mode" => $this->getViewMode(), + "active_tasks" => $this->getActiveTasks(), + "connectors" => $this->getConnectors(), + "workspace_id" => $this->getWorkspaceId() + ); + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Tasks/Entity/BoardList.php b/twake/backend/core/src/Twake/Tasks/Entity/BoardList.php new file mode 100755 index 00000000..70f6b138 --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Entity/BoardList.php @@ -0,0 +1,192 @@ +<?php + +namespace Twake\Tasks\Entity; + +use DateTime; +use Doctrine\ORM\Mapping as ORM; + +use Twake\Core\Entity\FrontObject; + +/** + * Board + * + * @ORM\Table(name="tasks_list",options={"engine":"MyISAM", "scylladb_keys": {{"board_id":"ASC", "id":"ASC"}, {"id":"ASC"}} }) + * @ORM\Entity() + */ +class BoardList extends FrontObject +{ + + /** + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="board_id", type="twake_timeuuid") + * @ORM\Id + */ + private $board_id; + + /** + * @ORM\Column(name="title", type="twake_text", nullable=true) + */ + private $title; + + /** + * @ORM\Column(name="color", type="string", nullable=true) + */ + private $color; + + /** + * @ORM\Column(name="emoji", type="string", nullable=true) + */ + private $emoji; + + /** + * @ORM\Column(name="order_pos", type="twake_text", nullable=true) + */ + private $order; + + /** + * @ORM\Column(name="auto_participants", type="twake_text", nullable=false) + */ + private $auto_participants = "[]"; + + + public function __construct($board_id, $title, $color) + { + $this->setBoardId($board_id); + $this->setTitle($title); + $this->setColor($color); + $this->setAutoParticipants(Array()); + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getBoardId() + { + return $this->board_id; + } + + /** + * @param mixed $workspace_id + */ + public function setBoardId($board_id) + { + $this->board_id = $board_id; + } + + /** + * @return mixed + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param mixed $title + */ + public function setTitle($title) + { + $this->title = $title; + } + + /** + * @return mixed + */ + public function getColor() + { + return $this->color; + } + + /** + * @param mixed $color + */ + public function setColor($color) + { + $this->color = $color; + } + + /** + * @return mixed + */ + public function getAutoParticipants() + { + return json_decode($this->auto_participants, 1); + } + + /** + * @param mixed $auto_participants + */ + public function setAutoParticipants($auto_participants) + { + $this->auto_participants = json_encode($auto_participants); + } + + /** + * @return mixed + */ + public function getEmoji() + { + return $this->emoji; + } + + /** + * @param mixed $emoji + */ + public function setEmoji($emoji) + { + $this->emoji = $emoji; + } + + /** + * @return mixed + */ + public function getOrder() + { + return $this->order; + } + + /** + * @param mixed $order + */ + public function setOrder($order) + { + $this->order = $order; + } + + public function getAsArray() + { + return Array( + "id" => $this->getId(), + "front_id" => $this->getFrontId(), + "title" => $this->getTitle(), + "color" => $this->getColor(), + "emoji" => $this->getEmoji(), + "order" => $this->getOrder(), + "board_id" => $this->getBoardId(), + "auto_participants" => $this->getAutoParticipants() + ); + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Tasks/Entity/Task.php b/twake/backend/core/src/Twake/Tasks/Entity/Task.php new file mode 100755 index 00000000..58651919 --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Entity/Task.php @@ -0,0 +1,477 @@ +<?php + +namespace Twake\Tasks\Entity; + +use DateTime; +use Doctrine\ORM\Mapping as ORM; + +use Twake\Core\Entity\FrontObject; +use Twake\Core\Entity\SearchableObject; + +/** + * Task + * + * @ORM\Table(name="tasks_task",options={"engine":"MyISAM", "scylladb_keys": {{"board_id":"ASC", "id":"ASC"}, {"id":"ASC"}, {"list_id":"ASC"}} }) + * @ORM\Entity() + */ +class Task extends SearchableObject +{ + protected $es_type = "task"; + + /** + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + + /** + * @ORM\Column(name="board_id", type="twake_timeuuid") + * @ORM\Id + */ + private $board_id; + + /** + * @ORM\Column(name="list_id", type="twake_timeuuid") + */ + private $list_id; + + /** + * @ORM\Column(name="order_pos", type="twake_text", nullable=true) + */ + private $order; + + /** + * @ORM\Column(name="before", type="twake_bigint") + */ + private $before = 0; + + /** + * @ORM\Column(name="start_time", type="twake_bigint") + */ + private $start_time = 0; + + /** + * @ORM\Column(name="title", type="twake_text") + */ + private $title = ""; + + /** + * @ORM\Column(name="description", type="twake_text", nullable=true) + */ + private $description = ""; + + /** + * @ORM\Column(name="owner", type="twake_no_salt_text") + */ + private $owner; + + /** + * @ORM\Column(name="task_created_at", type="twake_bigint") + */ + private $task_created_at; + + /** + * @ORM\Column(name="check_list", type="twake_text") + */ + private $check_list = "{}"; + + /** + * @ORM\Column(name="participants", type="twake_text") + */ + private $participants = "{}"; + + /** + * @ORM\Column(name="notifications", type="twake_text") + */ + private $notifications = "{}"; + + /** + * @ORM\Column(name="tags", type="twake_text") + */ + private $tags = "{}"; + + /** + * @ORM\Column(name="task_last_modified", type="twake_bigint") + */ + private $task_last_modified; + + /** + * @ORM\Column(name="archived", type="twake_boolean") + */ + private $archived; + + /** + * @ORM\Column(name="workspace_id", type="twake_timeuuid") + */ + protected $workspace_id; + + + /** + * @ORM\Column(name="attachements", type="twake_text") + */ + private $attachements = "[]"; + + + public function __construct($board_id, $list_id, $title) + { + $this->setTitle($title); + $this->setBoardId($board_id); + $this->setListId($list_id); + $this->setTaskLastModified(); + $this->setTaskCreatedAt(date("U")); + } + + public function getIndexationArray() + { + $participants = []; + foreach ($this->getParticipants() as $p) { + $participants[] = $p["user_id_or_mail"]; + } + + return Array( + "id" => $this->getId() . "", + "title" => $this->getTitle(), + "description" => $this->getDescription(), + "owner" => $this->getOwner(), + "tags" => $this->getTags(), + 'before' => ($this->getBefore() ? date('Y-m-d', $this->getBefore()) : null), + 'start' => ($this->getStartTime() ? date('Y-m-d', $this->getStartTime()) : null), + 'date_created' => ($this->getTaskCreatedAt() ? date('Y-m-d', $this->getTaskCreatedAt()) : null), + "date_last_modified" => ($this->getTaskLastModified() ? date('Y-m-d', $this->getTaskLastModified()) : null), + "workspace_id" => $this->getWorkspaceId(), + "participants" => $participants + ); + + } + + + /** + * @return mixed + */ + public function getWorkspaceId() + { + return $this->workspace_id; + } + + /** + * @param mixed $workspace_id + */ + public function setWorkspaceId($workspace_id) + { + $this->workspace_id = $workspace_id; + } + + + /** + * @return string + */ + public function getEsType() + { + return $this->es_type; + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param mixed $title + */ + public function setTitle($title) + { + $this->title = $title; + } + + /** + * @return mixed + */ + public function getDescription() + { + try { + return json_decode($this->description, 1); + } catch (\Exception $e) { + + } + return $this->description; + } + + /** + * @param mixed $description + */ + public function setDescription($description) + { + $this->description = json_encode($description); + } + + /** + * @return mixed + */ + public function getOwner() + { + return $this->owner; + } + + /** + * @param mixed $owner + */ + public function setOwner($owner) + { + $this->owner = $owner; + } + + /** + * @return mixed + */ + public function getParticipants() + { + return json_decode($this->participants, true); + } + + /** + * @param mixed $participants + */ + public function setParticipants($participants) + { + $this->participants = json_encode($participants); + } + + /** + * @return mixed + */ + public function getNotifications() + { + return json_decode($this->notifications, true); + } + + /** + * @param mixed $notifications + */ + public function setNotifications($notifications) + { + $this->notifications = json_encode($notifications); + } + + /** + * @return mixed + */ + public function getTags() + { + return json_decode($this->tags, true); + } + + /** + * @param mixed $tags + */ + public function setTags($tags) + { + $this->tags = json_encode($tags); + } + + /** + * @return mixed + */ + public function getTaskLastModified() + { + return $this->task_last_modified; + } + + /** + * @param mixed $task_last_modified + */ + public function setTaskLastModified() + { + $this->task_last_modified = date("U"); + } + + /** + * @return mixed + */ + public function getBoardId() + { + return $this->board_id; + } + + /** + * @param mixed $board_id + */ + public function setBoardId($board_id) + { + $this->board_id = $board_id; + } + + /** + * @return mixed + */ + public function getListId() + { + return $this->list_id; + } + + /** + * @param mixed $list_id + */ + public function setListId($list_id) + { + $this->list_id = $list_id; + } + + /** + * @return mixed + */ + public function getOrder() + { + return $this->order; + } + + /** + * @param mixed $order + */ + public function setOrder($order) + { + $this->order = $order; + } + + /** + * @return mixed + */ + public function getBefore() + { + return $this->before; + } + + /** + * @param mixed $before + */ + public function setBefore($before) + { + $this->before = $before; + } + + /** + * @return mixed + */ + public function getStartTime() + { + return $this->start_time; + } + + /** + * @param mixed $before + */ + public function setStartTime($start_time) + { + $this->start_time = $start_time; + } + + /** + * @return mixed + */ + public function getTaskCreatedAt() + { + return $this->task_created_at; + } + + /** + * @param mixed $task_created_at + */ + public function setTaskCreatedAt($task_created_at) + { + $this->task_created_at = $task_created_at; + } + + /** + * @return mixed + */ + public function getCheckList() + { + return json_decode($this->check_list, 1); + } + + /** + * @param mixed $check_list + */ + public function setCheckList($check_list) + { + $this->check_list = json_encode($check_list); + } + + /** + * @return mixed + */ + public function getArchived() + { + return $this->archived; + } + + /** + * @param mixed $archived + */ + public function setArchived($archived) + { + $this->archived = $archived; + } + + /** + * @return mixed + */ + public function getAttachements() + { + return json_decode($this->attachements, true); + } + + /** + * @param mixed $tags + */ + public function setAttachements($attachements) + { + $this->attachements = json_encode($attachements); + } + + public function getAsArray() + { + return Array( + "id" => $this->getId(), + "front_id" => $this->getFrontId(), + "board_id" => $this->getBoardId(), + "list_id" => $this->getListId(), + "owner" => $this->getOwner(), + "task_created_at" => $this->getTaskCreatedAt(), + "task_last_modified" => $this->getTaskLastModified(), + "archived" => !!$this->getArchived(), + "before" => $this->getBefore(), + "start" => $this->getStartTime(), + "title" => $this->getTitle(), + "description" => $this->getDescription(), + "checklist" => $this->getCheckList(), + "order" => $this->getOrder(), + "participants" => $this->getParticipants(), + "notifications" => $this->getNotifications(), + "tags" => $this->getTags(), + "workspace_id" => $this->getWorkspaceId(), + "attachments" => $this->getAttachements() + ); + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Tasks/Entity/TaskExportToken.php b/twake/backend/core/src/Twake/Tasks/Entity/TaskExportToken.php new file mode 100755 index 00000000..bf2a4b05 --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Entity/TaskExportToken.php @@ -0,0 +1,140 @@ +<?php + + +namespace Twake\Tasks\Entity; + +use Doctrine\ORM\Mapping as ORM; + +/** + * TaskExportToken + * + * @ORM\Table(name="task_export_token",options={"engine":"MyISAM", "scylladb_keys": {{"user_id": "ASC", "id": "ASC"},{"user_token": "ASC"}} }) + * @ORM\Entity() + */ +class TaskExportToken +{ + /** + * @ORM\Column(name="user_id", type="twake_timeuuid") + * @ORM\Id + */ + private $user_id; + + /** + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="workspaceid", type="twake_timeuuid") + */ + private $workspaceid; + + + /** + * @ORM\Column(name="boards",type="twake_text") + */ + private $boards; + + /** + * @ORM\Column(name="user_token", type="twake_no_salt_text") + */ + private $user_token; + + /** + * ExportToken constructor. + * @param $user_id + * @param $workspaceid + * @param $boards + * @param $user_token + */ + public function __construct($user_id, $workspaceid, $boards, $user_token) + { + $this->user_id = $user_id; + $this->workspaceid = $workspaceid; + $this->setBoards($boards); + $this->user_token = $user_token; + } + + /** + * @return mixed + */ + public function getUserId() + { + return $this->user_id; + } + + /** + * @param mixed $user_id + */ + public function setUserId($user_id) + { + $this->user_id = $user_id; + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getWorkspaceid() + { + return $this->workspaceid; + } + + /** + * @param mixed $workspaceid + */ + public function setWorkspaceid($workspaceid) + { + $this->workspaceid = $workspaceid; + } + + /** + * @return mixed + */ + public function getBoards() + { + return json_decode($this->boards, true); + } + + /** + * @param mixed $boards + */ + public function setBoards($boards) + { + $this->boards = json_encode($boards); + } + + /** + * @return mixed + */ + public function getToken() + { + return $this->user_token; + } + + /** + * @param mixed $user_token + */ + public function setToken($token) + { + $this->user_token = $token; + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Tasks/Entity/TaskNotification.php b/twake/backend/core/src/Twake/Tasks/Entity/TaskNotification.php new file mode 100755 index 00000000..3ab55e51 --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Entity/TaskNotification.php @@ -0,0 +1,134 @@ +<?php + +namespace Twake\Tasks\Entity; + +use DateTime; +use Doctrine\ORM\Mapping as ORM; + + +/** + * TaskNotification + * + * @ORM\Table(name="tasks_task_notification",options={"engine":"MyISAM", "scylladb_keys": {{"when_ts_week":"ASC", "when_ts": "ASC", "id": "ASC"}, {"task_id":"ASC"}} }) + * @ORM\Entity() + */ +class TaskNotification +{ + + /** + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="when_ts_week", type="twake_bigint") + * @ORM\Id + */ + private $when_ts_week; + + /** + * @ORM\Column(name="when_ts", type="twake_bigint") + * @ORM\Id + */ + private $when_ts; + + /** + * @ORM\Column(name="delay", type="twake_bigint") + */ + private $delay; + + /** + * @ORM\Column(name="mode", type="twake_no_salt_text") + */ + private $mode; + + /** + * @ORM\Column(name="task_id", type="twake_timeuuid") + */ + private $task_id; + + + public function __construct($task_id, $delay, $ts, $mode = "push") + { + $this->task_id = $task_id; + $this->when_ts = $ts; + $this->when_ts_week = floor($ts / (60 * 60 * 24)); //Timestamp rounded by day + $this->setDelay($delay); + $this->setMode($mode); + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getWhenTsWeek() + { + return $this->when_ts_week; + } + + /** + * @return mixed + */ + public function getWhenTs() + { + return $this->when_ts; + } + + /** + * @return mixed + */ + public function getTaskId() + { + return $this->task_id; + } + + /** + * @return mixed + */ + public function getDelay() + { + return $this->delay; + } + + /** + * @param mixed $delay + */ + public function setDelay($delay) + { + $this->delay = $delay; + } + + /** + * @return mixed + */ + public function getMode() + { + return $this->mode; + } + + /** + * @param mixed $mode + */ + public function setMode($mode) + { + $this->mode = $mode; + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Tasks/Entity/TaskUser.php b/twake/backend/core/src/Twake/Tasks/Entity/TaskUser.php new file mode 100755 index 00000000..2b499129 --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Entity/TaskUser.php @@ -0,0 +1,96 @@ +<?php + +namespace Twake\Tasks\Entity; + +use DateTime; +use Doctrine\ORM\Mapping as ORM; + + +/** + * TaskUser + * + * @ORM\Table(name="task_user",options={"engine":"MyISAM", "scylladb_keys": {{"user_id_or_mail": "ASC", "id": "ASC"}, {"task_id":"ASC"}} }) + * @ORM\Entity() + */ +class TaskUser +{ + + /** + * @ORM\Column(name="user_id_or_mail", type="twake_string") + * @ORM\Id + */ + private $user_id_or_mail; + + /** + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="task_id", type="twake_timeuuid") + */ + private $task_id; + + /** + * @ORM\Column(name="email", type="twake_no_salt_text") + */ + private $email = ""; + + + public function __construct($user_id_or_mail, $task_id) + { + $this->user_id_or_mail = $user_id_or_mail; + $this->task_id = $task_id; + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return mixed + */ + public function getUserIdOrMail() + { + return $this->user_id_or_mail; + } + + /** + * @return mixed + */ + public function getTaskId() + { + return $this->task_id; + } + + /** + * @return mixed + */ + public function getEmail() + { + return $this->email; + } + + /** + * @param mixed $email + */ + public function setEmail($email) + { + $this->email = $email; + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Tasks/Resources/Routing.php b/twake/backend/core/src/Twake/Tasks/Resources/Routing.php new file mode 100755 index 00000000..b0bb40c7 --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Resources/Routing.php @@ -0,0 +1,32 @@ +<?php + +namespace Twake\Tasks\Resources; + +use Common\BaseRouting; + +class Routing extends BaseRouting +{ + + protected $routing_prefix = "ajax/tasks/"; + + protected $routes = [ +#Tasks + "task/get" => ["handler" => "Task:getAction", "methods" => ["POST"], "security" => ["user_connected_security"]], + "task/save" => ["handler" => "Task:save", "methods" => ["POST"], "security" => ["user_connected_security"]], + "task/remove" => ["handler" => "Task:remove", "methods" => ["POST"], "security" => ["user_connected_security"]], +#Lists + "list/get" => ["handler" => "BoardList:getAction", "methods" => ["POST"], "security" => ["user_connected_security"]], + "list/save" => ["handler" => "BoardList:save", "methods" => ["POST"], "security" => ["user_connected_security"]], + "list/remove" => ["handler" => "BoardList:remove", "methods" => ["POST"], "security" => ["user_connected_security"]], + "list/tasks/remove" => ["handler" => "BoardList:removeAll", "methods" => ["POST"], "security" => ["user_connected_security"]], + "list/tasks/archive" => ["handler" => "BoardList:archiveAll", "methods" => ["POST"], "security" => ["user_connected_security"]], +#Boards + "board/get" => ["handler" => "Board:getAction", "methods" => ["POST"], "security" => ["user_connected_security"]], + "board/save" => ["handler" => "Board:save", "methods" => ["POST"], "security" => ["user_connected_security"]], + "board/remove" => ["handler" => "Board:remove", "methods" => ["POST"], "security" => ["user_connected_security"]], +#Export + "export" => ["handler" => "Export:export", "methods" => ["POST", "GET"]], + "token_export" => ["handler" => "Export:generateToken", "methods" => ["POST"], "security" => ["user_connected_security"]], + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Tasks/Resources/Services.php b/twake/backend/core/src/Twake/Tasks/Resources/Services.php new file mode 100755 index 00000000..136590d0 --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Resources/Services.php @@ -0,0 +1,21 @@ +<?php + +namespace Twake\Tasks\Resources; + +use Common\BaseServices; + +class Services extends BaseServices +{ + + protected $services = [ + "app.tasks.task" => "BoardTask", +// arguments: ["@app.twake_doctrine", "@app.websockets", "@app.applications_api", "@app.notifications", "@app.tasks.export"] + "app.tasks.list" => "BoardList", +// arguments: ["@app.twake_doctrine", "@app.websockets", "@app.applications_api", "@app.notifications", "@app.tasks.export"] + "app.tasks.board" => "BoardBoard", +// arguments: ["@app.twake_doctrine", "@app.applications_api", "@app.tasks.list", "@app.tasks.task"] + "app.tasks.export" => "BoardExport", +// arguments: ["@app.twake_doctrine"] + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Tasks/Services/BoardBoard.php b/twake/backend/core/src/Twake/Tasks/Services/BoardBoard.php new file mode 100755 index 00000000..d8a13d01 --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Services/BoardBoard.php @@ -0,0 +1,216 @@ +<?php + +namespace Twake\Tasks\Services; + + +use Twake\Tasks\Entity\Board; +use App\App; + +class BoardBoard +{ + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->applications_api = $app->getServices()->get("app.applications_api"); + $this->list_service = $app->getServices()->get("app.tasks.list"); + $this->task_service = $app->getServices()->get("app.tasks.task"); + } + + /** Called from Collections manager to verify user has access to websockets room, registered in Core/Services/Websockets.php */ + public function init($route, $data, $current_user = null) + { + return $this->hasAccess($data, $current_user); + } + + public function hasAccess($data, $current_user = null) + { + //TODO + return true; + } + + public function get($options, $current_user) + { + $workspace_id = $options["workspace_id"]; + $boards = $this->doctrine->getRepository("Twake\Tasks:Board")->findBy(Array("workspace_id" => $workspace_id)); + + if (!$this->hasAccess($options, $current_user)) { + return false; + } + + if (count($boards) == 0) { + $board = $this->save(Array( + "workspace_id" => $workspace_id, + "title" => "First Board", + "emoji" => ":clipboard:", + ), Array(), null); + + $list_todo = $this->list_service->save(Array( + "board_id" => $board["id"], + "title" => "Not done", + "emoji" => ":vertical_traffic_light:", + "color" => "#f4511e", + "order" => "a" + ), Array(), null); + + $list_done = $this->list_service->save(Array( + "board_id" => $board["id"], + "title" => "Done", + "emoji" => ":white_check_mark:", + "color" => "#0b8043", + "order" => "b" + ), Array(), null); + + $this->task_service->save(Array( + "board_id" => $board["id"], + "list_id" => $list_todo["id"], + "title" => "Invite collaborators", + "order" => "a" + ), Array(), null); + + $this->task_service->save(Array( + "board_id" => $board["id"], + "list_id" => $list_todo["id"], + "title" => "Customize my workspace", + "order" => "b" + ), Array(), null); + + $this->task_service->save(Array( + "board_id" => $board["id"], + "list_id" => $list_done["id"], + "title" => "Create my Twake workspace", + "order" => "a" + ), Array(), null); + + $board["active_tasks"] = 3; + + if ($board) { + return [$board]; + } + + } + + $ret = []; + foreach ($boards as $board) { + if(!$board->getDeleted()){ + $ret[] = $board->getAsArray(); + } + } + + return $ret; + } + + public function save($object, $options, $current_user) + { + + //TODO add access restriction option like for directories + + if (!$this->hasAccess($object, $current_user)) { + return false; + } + + $did_create = false; + if (isset($object["id"])) { + $board = $this->doctrine->getRepository("Twake\Tasks:Board")->findOneBy(Array("id" => $object["id"])); + if (!$board) { + return false; + } + } else { + $did_create = true; + $board = new Board($object["workspace_id"], ""); + $board->setFrontId($object["front_id"]); + } + + if (isset($object["title"])) $board->setTitle($object["title"]); + if (isset($object["emoji"])) $board->setEmoji($object["emoji"]); + if (isset($object["group_name"])) $board->setGroupName($object["group_name"]); + if (isset($object["view_mode"])) $board->setViewMode($object["view_mode"]); + + $this->doctrine->persist($board); + $this->doctrine->flush(); + + $this->updateConnectors($board, $object["connectors"], $current_user ? $current_user->getId() : null); + + //Notify connectors + $workspace_id = $board->getWorkspaceId(); + $resources = $this->applications_api->getResources($workspace_id, "workspace_tasks", $workspace_id); + $apps_ids = []; + foreach ($resources as $resource) { + if (in_array("board", $resource->getApplicationHooks())) { + $apps_ids[] = $resource->getApplicationId(); + } + } + if (count($apps_ids) > 0) { + foreach ($apps_ids as $app_id) { + if ($app_id) { + $data = Array( + "board" => $board->getAsArray() + ); + if ($did_create) { + $this->applications_api->notifyApp($app_id, "hook", "new_board", $data); + } else { + $this->applications_api->notifyApp($app_id, "hook", "edit_board", $data); + } + } + } + } + + return $board->getAsArray(); + + } + + private function updateConnectors($board_entity, $connectors_ids, $current_user_id = null) + { + + if (!$connectors_ids) { + $connectors_ids = []; + } + + $current_connectors = $board_entity->getConnectors(); + $current_connectors = $current_connectors ? $current_connectors : []; + + $did_something = false; + + foreach ($connectors_ids as $connector_id) { + if (!in_array($connector_id, $current_connectors)) { + $this->applications_api->addResource($connector_id, $board_entity->getWorkspaceId(), "board", $board_entity->getId(), $current_user_id); + $did_something = true; + } + } + + foreach ($current_connectors as $current_connector_id) { + if (!in_array($current_connector_id, $connectors_ids)) { + $this->applications_api->removeResource($connector_id, $board_entity->getWorkspaceId(), "board", $board_entity->getId(), $current_user_id); + $did_something = true; + } + } + + if ($did_something) { + $board_entity->setConnectors($connectors_ids); + $this->doctrine->persist($board_entity); + $this->doctrine->flush(); + } + + } + + public function remove($object, $options, $current_user = null) + { + $id = $object["id"]; + + if (!$this->hasAccess($object, $current_user)) { + return false; + } + + $board = $this->doctrine->getRepository("Twake\Tasks:Board")->findOneBy(Array("id" => $id)); + if (!$board) { + return false; + } + $board->setDeleted(true); + + $this->doctrine->save($board); + $this->doctrine->flush(); + + return $object; + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Tasks/Services/BoardExport.php b/twake/backend/core/src/Twake/Tasks/Services/BoardExport.php new file mode 100755 index 00000000..ec287f4b --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Services/BoardExport.php @@ -0,0 +1,46 @@ +<?php + + +namespace Twake\Tasks\Services; + +use Twake\Tasks\Entity\ExportToken; +use App\App; + +class BoardExport +{ + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + } + + public function generateToken($request, $current_user = null) + { + + $user_id = $current_user->getId(); + + $workspace_id = $request->request->get('workspace_id'); + $boards = $request->request->get('boards'); + + $token = bin2hex(random_bytes(64)); + + //Insert to export_token table + $entity = new ExportToken($user_id, $workspace_id, $boards, $token); + $this->doctrine->persist($entity); + $this->doctrine->flush(); + + return $token; + + } + + + public function exportBoard($token, $boardTaskService) + { + } + + + public function importBoard($token, $boardTaskService) + { + } + +} diff --git a/twake/backend/core/src/Twake/Tasks/Services/BoardList.php b/twake/backend/core/src/Twake/Tasks/Services/BoardList.php new file mode 100755 index 00000000..8ab5e3ef --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Services/BoardList.php @@ -0,0 +1,228 @@ +<?php + +namespace Twake\Tasks\Services; + +use App\App; + +class BoardList +{ + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->boardExport = $app->getServices()->get("app.tasks.export"); + $this->enc_pusher = $app->getServices()->get("app.websockets"); + $this->applications_api = $app->getServices()->get("app.applications_api"); + $this->notifications = $app->getServices()->get("app.notifications"); + } + + /** Called from Collections manager to verify user has access to websockets room, registered in Core/Services/Websockets.php */ + public function init($route, $data, $current_user = null) + { + return $this->hasAccess($data, $current_user); + } + + public function hasAccess($data, $current_user = null) + { + //TODO + return true; + } + + public function get($options, $current_user) + { + $board_list_id = $options["board_id"]; + + if (!$this->hasAccess($options, $current_user)) { + return false; + } + + $lists = $this->doctrine->getRepository("Twake\Tasks:BoardList")->findBy(Array("board_id" => $board_list_id)); + + $ret = []; + foreach ($lists as $list) { + $ret[] = $list->getAsArray(); + } + + return $ret; + } + + public function remove($object, $options, $current_user = null) + { + $id = $object["id"]; + + if (!$this->hasAccess($object, $current_user)) { + return false; + } + + $board_list = $this->doctrine->getRepository("Twake\Tasks:BoardList")->findOneBy(Array("id" => $id)); + if (!$board_list) { + return false; + } + + $this->removeAllTasks($object, $options, $current_user = null); + + $this->doctrine->remove($board_list); + $this->doctrine->flush(); + + return $object; + } + + public function removeAllTasks($object, $options, $current_user = null) + { + + $id = $object["id"]; + + if (!$this->hasAccess($object, $current_user)) { + return false; + } + + $only_archived = $options["only_archived_tasks"]; + + $board_list = $this->doctrine->getRepository("Twake\Tasks:BoardList")->findOneBy(Array("id" => $id)); + if (!$board_list) { + return false; + } + + $ws_events = []; + $ws_task_users = []; + + //Remove all tasks and update count in board + $tasks = $this->doctrine->getRepository("Twake\Tasks:Task")->findBy(Array("list_id" => $id)); + $count = 0; + foreach ($tasks as $task) { + if (!$only_archived || $task->getArchived()) { + + if (!$task->getArchived()) { + $count++; + } + + $this->doctrine->remove($task); + + //Send websocket notification + $ws_events[] = Array( + "client_id" => "system", + "action" => "remove", + "object_type" => "", + "front_id" => $task->getFrontId() + ); + foreach ($task->getParticipants() as $participant) { + if (!is_string($participant)) { + $participant = $participant["user_id_or_mail"]; + } + $ws_task_users[] = $participant; + } + + } + } + $board = $this->doctrine->getRepository("Twake\Tasks:Board")->findOneBy(Array("id" => $board_list->getBoardId())); + $board->setActiveTasks($board->getActiveTasks() - $count); + $this->doctrine->persist($board); + + $this->doctrine->flush(); + + if (count($ws_events) > 0) { + $this->enc_pusher->push("board_tasks/" . $board_list->getBoardId(), $ws_events); + $ws_task_users = array_unique($ws_task_users); + foreach ($ws_task_users as $ws_task_user) { + $this->enc_pusher->push("board_tasks/user_" . $ws_task_user, $ws_events); + } + } + + } + + public function archiveAllTasks($object, $options, $current_user = null) + { + + $id = $object["id"]; + + if (!$this->hasAccess($object, $current_user)) { + return false; + } + + $board_list = $this->doctrine->getRepository("Twake\Tasks:BoardList")->findOneBy(Array("id" => $id)); + if (!$board_list) { + return false; + } + + //Remove all tasks and update count in board + $tasks = $this->doctrine->getRepository("Twake\Tasks:Task")->findBy(Array("list_id" => $id)); + $count = 0; + + $ws_events = []; + $ws_task_users = []; + + foreach ($tasks as $task) { + if (!$task->getArchived()) { + + $task->setArchived(true); + $this->doctrine->persist($task); + $count++; + + //Send websocket notification + $ws_events[] = Array( + "client_id" => "system", + "action" => "save", + "object_type" => "", + "object" => $task->getAsArray() + ); + foreach ($task->getParticipants() as $participant) { + if (!is_string($participant)) { + $participant = $participant["user_id_or_mail"]; + } + $ws_task_users[] = $participant; + } + + } + } + + $board = $this->doctrine->getRepository("Twake\Tasks:Board")->findOneBy(Array("id" => $board_list->getBoardId())); + $board->setActiveTasks($board->getActiveTasks() - $count); + $this->doctrine->persist($board); + + $this->doctrine->flush(); + + if (count($ws_events) > 0) { + $this->enc_pusher->push("board_tasks/" . $board_list->getBoardId(), $ws_events); + $ws_task_users = array_unique($ws_task_users); + foreach ($ws_task_users as $ws_task_user) { + $this->enc_pusher->push("board_tasks/user_" . $ws_task_user, $ws_events); + } + } + + } + + public function save($object, $options, $current_user) + { + + if (!$this->hasAccess($object, $current_user)) { + return false; + } + + $did_create = false; + if (isset($object["id"])) { + $board_list = $this->doctrine->getRepository("Twake\Tasks:BoardList")->findOneBy(Array("id" => $object["id"])); + if (!$board_list) { + return false; + } + } else { + $did_create = true; + $board_list = new \Twake\Tasks\Entity\BoardList($object["board_id"], "", ""); + $board_list->setFrontId($object["front_id"]); + } + + if (isset($object["title"])) $board_list->setTitle($object["title"]); + if (isset($object["color"])) $board_list->setColor($object["color"]); + if (isset($object["emoji"])) $board_list->setEmoji($object["emoji"]); + + if (isset($object["order"])) $board_list->setOrder($object["order"]); + + if (isset($object["auto_participants"])) $board_list->setAutoParticipants($object["auto_participants"]); + + $this->doctrine->persist($board_list); + $this->doctrine->flush(); + + return $board_list->getAsArray(); + + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Tasks/Services/BoardTask.php b/twake/backend/core/src/Twake/Tasks/Services/BoardTask.php new file mode 100755 index 00000000..43578b9b --- /dev/null +++ b/twake/backend/core/src/Twake/Tasks/Services/BoardTask.php @@ -0,0 +1,651 @@ +<?php + +namespace Twake\Tasks\Services; + + +use Twake\Core\CommonObjects\AttachementManager; +use Twake\Notifications\Entity\Notification; +use Twake\Tasks\Entity\Board; +use Twake\Tasks\Entity\Task; +use Twake\Tasks\Entity\TaskBoard; +use Twake\Tasks\Entity\TaskNotification; +use Twake\Tasks\Entity\TaskUser; +use App\App; + +class BoardTask +{ + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->boardExport = $app->getServices()->get("app.tasks.export"); + $this->enc_pusher = $app->getServices()->get("app.websockets"); + $this->applications_api = $app->getServices()->get("app.applications_api"); + $this->notifications = $app->getServices()->get("app.notifications"); + $this->attachementManager = new AttachementManager($this->doctrine, $this->enc_pusher); + $this->queues_scheduled = $app->getServices()->get("app.queues_scheduled"); + } + + /** Called from Collections manager to verify user has access to websockets room, registered in Core/Services/Websockets.php */ + public function init($route, $data, $current_user = null) + { + return $this->hasAccess($data, $current_user); + } + + public function hasAccess($data, $current_user = null) + { + //TODO + + if ($data["entity"]) { + //Test we have access to this task + } + + return true; + } + + public function get($options, $current_user) + { + $board_id = $options["board_id"]; + + if (!$this->hasAccess($options, $current_user)) { + return false; + } + + if (explode("_", $board_id)[0] == "user") { + $tasks = []; + $user_id = explode("_", $board_id)[1]; + $workspaces = Array(); + if ($user_id != $current_user->getId() . "") { + //Get available workspaces + $workspaceUsers = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser")->findBy(Array("user_id" => $user_id)); + foreach ($workspaceUsers as $wu) { + $available = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser")->findBy(Array("user_id" => $current_user->getId(), "workspace_id" => $wu->getWorkspace($this->doctrine)->getId())); + if ($available) { + $workspaces[] = $wu->getWorkspaceId(); + } + } + } + $tasks_user = $this->doctrine->getRepository("Twake\Tasks:TaskUser")->findBy(Array("user_id_or_mail" => $user_id)); + $boardIsDeleted = []; + foreach ($tasks_user as $taskuser) { + $t = $this->doctrine->getRepository("Twake\Tasks:Task")->findOneBy(Array("id" => $taskuser->getTaskId())); + if ($t) { + + if(!isset($boardIsDeleted[$t->getBoardId()])){ + $board = $this->doctrine->getRepository("Twake\Tasks:Board")->findOneBy(Array("id" => $t->getBoardId())); + $boardIsDeleted[$t->getBoardId()] = $board->getDeleted(); + } + + if(!$boardIsDeleted[$t->getBoardId()]){ + + if ($user_id != $current_user->getId() . "") { + $ok = false; + foreach ($workspaces as $workspace_id) { + if ($workspace_id == $t->getWorkspaceId()) { + $ok = true; + break; + } + } + } else { + $ok = true; + } + if ($ok) $tasks[] = $t; + + } + } else { + $this->doctrine->remove($taskuser); + $this->doctrine->flush(); + } + } + } else { + $tasks = $this->doctrine->getRepository("Twake\Tasks:Task")->findBy(Array("board_id" => $board_id)); + } + + $ret = []; + foreach ($tasks as $task) { + $ret[] = $task->getAsArray(); + } + + return $ret; + } + + public function remove($object, $options, $current_user = null) + { + $id = $object["id"]; + + if (!$this->hasAccess($object, $current_user)) { + return false; + } + + $board_task = $this->doctrine->getRepository("Twake\Tasks:Task")->findOneBy(Array("id" => $id)); + if (!$board_task) { + return false; + } + + $board = $this->doctrine->getRepository("Twake\Tasks:Board")->findOneBy(Array("id" => $board_task->getBoardId())); + + if (!$board_task->getArchived()) { + $board->setActiveTasks($board->getActiveTasks() - 1); + } + $this->attachementManager->removeAttachementsFromEntity($board_task); + $this->doctrine->persist($board); + $this->doctrine->remove($board_task); + $this->doctrine->flush(); + + return $object; + } + + public function save($object, $options, $current_user) + { + + if (!$this->hasAccess($object, $current_user)) { + return false; + } + + if (isset($object["id"]) && $object["id"]) { + $task = $this->doctrine->getRepository("Twake\Tasks:Task")->findOneBy(Array("id" => $object["id"])); + if (!$task) { + return false; + } + $did_create = false; + } else { + $task = new Task($object["board_id"], $object["list_id"], $object["title"]); + $task->setFrontId($object["front_id"]); + $task->setOwner($current_user ? $current_user->getId() : null); + $workspace_id = $this->doctrine->getRepository("Twake\Tasks:Board")->findOneBy(Array("id" => $object["board_id"]))->getWorkspaceId(); + $task->setWorkspaceId($workspace_id); + $did_create = true; + } + + /* @var Board $board */ + $board = $this->doctrine->getRepository("Twake\Tasks:Board")->findOneBy(Array("id" => $task->getBoardId())); + + /* @var \Twake\Tasks\Entity\BoardList $list */ + $list = $this->doctrine->getRepository("Twake\Tasks:BoardList")->findOneBy(Array("id" => $task->getListId())); + + if ($did_create) { + if (!isset($object["participants"]) || !$object["participants"]) { + $object["participants"] = []; + } + foreach ($list->getAutoParticipants() as $participant) { + if (is_string($participant)) { + $participant = Array( + "user_id_or_mail" => $participant + ); + } + $object["participants"][] = $participant; + } + } + + //Manage infos + if (isset($object["title"])) $task->setTitle($object["title"]); + if (isset($object["description"])) $task->setDescription($object["description"]); + if (isset($object["checklist"])) $task->setCheckList($object["checklist"]); + + if (isset($object["list_id"])) $task->setListId($object["list_id"]); + if (isset($object["order"])) $task->setOrder($object["order"]); + + //Change active task count on board + if (isset($object["archived"]) && !!$object["archived"] != $task->getArchived()) { + //Changed archived status + $task->setArchived($object["archived"]); + if (!!$object["archived"]) { + $board->setActiveTasks($board->getActiveTasks() - 1); + } else { + $board->setActiveTasks($board->getActiveTasks() + 1); + } + $this->doctrine->persist($board); + $this->doctrine->flush(); + } + if ($did_create) { + $board->setActiveTasks($board->getActiveTasks() + 1); + $this->doctrine->persist($board); + $this->doctrine->flush(); + } + + $task->setTaskLastModified(); + + if (isset($object["tags"])) { + $task->setTags($object["tags"]); + } + + $this->doctrine->persist($task); + $this->doctrine->flush(); + + if ($did_create || $task->getNotifications() != $object["notifications"] || $task->getBefore() != $object["before"] || $task->getStartTime() != $object["start"]) { + $change_dates = $did_create || $task->getBefore() != $object["before"] || $task->getStartTime() != $object["start"]; + if (isset($object["before"])) $task->setBefore(intval($object["before"])); + if (isset($object["start"])) $task->setStartTime(intval($object["start"])); + $this->updateNotifications($task, $object["notifications"], $change_dates); + } + + if (isset($object["participants"]) || $did_create) { + $this->updateParticipants($task, $object["participants"] ? $object["participants"] : Array()); + } + + if (isset($object["attachments"]) || $did_create) { + $this->attachementManager->updateAttachements($task, $object["attachments"] ? $object["attachments"] : Array()); + } + + foreach ($task->getParticipants() as $participant) { + if (!is_string($participant)) { + $participant = $participant["user_id_or_mail"]; + } + $ws_events = Array( + "client_id" => "system", + "action" => "save", + "object_type" => "", + "object" => $task->getAsArray() + ); + $this->enc_pusher->push("board_tasks/user_" . $participant, $ws_events); + } + + + //Notify connectors + $resources = []; + $workspace_id = $board->getWorkspaceId(); + $resources = array_merge($resources, $this->applications_api->getResources($workspace_id, "workspace_tasks", $workspace_id)); + $apps_ids = []; + foreach ($resources as $resource) { + if (in_array("task", $resource->getApplicationHooks())) { + $apps_ids[] = $resource->getApplicationId(); + } + } + if (count($apps_ids) > 0) { + foreach ($apps_ids as $app_id) { + if ($app_id) { + $data = Array( + "task" => $task->getAsArray() + ); + if ($did_create) { + $this->applications_api->notifyApp($app_id, "hook", "new_task", $data); + } else { + $this->applications_api->notifyApp($app_id, "hook", "edit_task", $data); + } + } + } + } + + + return $task->getAsArray(); + } + + private function updateNotifications(Task $task, $notifications = Array(), $replace_all = false) + { + + $notifications = $notifications ? $notifications : []; + $token = base64_encode(bin2hex(random_bytes(32))); + + foreach ($notifications as $index => $notification) { + $notifications[$index]["token"] = $token; + } + + $has_before = true; + if (!$task->getBefore() || $task->getBefore() < date("U")) { + $has_before = false; + $notifications = Array(); + } + + $updated_notifications = $this->formatArrayInput($notifications, ["delay", "mode"]); + $task->setNotifications($updated_notifications); + $this->doctrine->persist($task); + + if ($task->getBefore() > 0 && $replace_all) { + //Add deadline + $updated_notifications[] = Array( + "delay" => 0, + "mode" => "push", + "token" => $token + ); + } + + if ($task->getStartTime() > 0 && $task->getStartTime() > date("U") && $replace_all) { + //Add start time as notification + $updated_notifications[] = Array( + "delay" => $has_before ? ($task->getBefore() - $task->getStartTime()) : ($task->getStartTime()), + "mode" => "push", + "token" => $token + ); + } + + $this->doctrine->flush(); + + foreach ($updated_notifications as $notification) { + if ($has_before) { + $notification_date = $task->getBefore() - $notification["delay"]; + $delay = $notification["delay"]; + } else { + $notification_date = $notification["delay"]; + $delay = "0"; + } + + if ($notification_date < date("U")) { + continue; + } + + $this->queues_scheduled->schedule("tasks_task", $notification_date, [ + "token" => $token, + "task_id" => $task->getId(), + "delay" => $delay, + "mode" => $notification["mode"] + ]); + } + + } + + private function formatArrayInput($array, $id_keys = []) + { + $updated_array = []; + $unicity = []; + foreach ($array as $element) { + + $tmp = false; + + if (is_array($element)) { + $all_ok = true; + foreach ($id_keys as $id_key) { + if (!isset($element[$id_key])) { + $all_ok = false; + } + } + if ($all_ok) { + $tmp = $element; + } + } else { + $tmp = Array(); + $tmp[$id_key] = $element; + } + + if ($tmp !== false) { + $uniq_key = ""; + foreach ($id_keys as $id_key) { + $uniq_key .= "_" . $tmp[$id_key]; + } + if (!in_array($uniq_key, $unicity)) { + $unicity[] = $uniq_key; + $updated_array[] = $tmp; + } + } + + } + return $updated_array; + } + + private function getArrayDiffUsingKeys($new_array, $old_array, $keys) + { + $remove = []; + $add = []; + foreach ($new_array as $new_el) { + if (!$this->inArrayUsingKeys($old_array, $new_el, $keys)) { + $add[] = $new_el; + } + } + foreach ($old_array as $old_el) { + if (!$this->inArrayUsingKeys($new_array, $old_el, $keys)) { + $remove[] = $old_el; + } + } + return Array("del" => $remove, "add" => $add); + } + + private function inArrayUsingKeys($array, $element, $keys) + { + $in = false; + foreach ($array as $el) { + $same = true; + foreach ($keys as $key) { + if ($el[$key] != $element[$key]) { + $same = false; + break; + } + } + if ($same) { + $in = true; + break; + } + } + return $in; + } + + private function updateParticipants(Task $task, $participants = Array()) + { + + $participants = $participants ? $participants : []; + + $updated_participants = $this->formatArrayInput($participants, ["user_id_or_mail"]); + $current_participants = $task->getParticipants(); + $updated_participants_fixed = $current_participants; + + $get_diff = $this->getArrayDiffUsingKeys($updated_participants, $current_participants, ["user_id_or_mail"]); + + if (count($get_diff["del"]) > 0) { + $users_in_task = $this->doctrine->getRepository("Twake\Tasks:TaskUser")->findBy(Array("task_id" => $task->getId())); + foreach ($users_in_task as $user) { + if ($this->inArrayUsingKeys($get_diff["del"], Array("user_id_or_mail" => $user->getUserIdOrMail()), ["user_id_or_mail"]) || $replace_all) { + //Remove old participants + $this->doctrine->remove($user); + + //Remove from array fixed + foreach ($updated_participants_fixed as $i => $v) { + if ($v["user_id_or_mail"] == $user->getUserIdOrMail()) { + unset($updated_participants_fixed[$i]); + } + } + + } + } + } + + foreach (($replace_all ? $updated_participants : $get_diff["add"]) as $participant) { + + $fixed_participant = $participant; + + //Remove from array fixed + if (filter_var($participant["user_id_or_mail"], FILTER_VALIDATE_EMAIL)) { + //Mail given + $mail = trim(strtolower($participant["user_id_or_mail"])); + $mail_entity = $this->doctrine->getRepository("Twake\Users:Mail")->findOneBy(Array("mail" => $mail)); + if ($mail_entity) { + $fixed_participant["user_id_or_mail"] = $mail_entity->getUser()->getId(); + } + } else if (preg_match('/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/', $participant["user_id_or_mail"])) { + //User id given + $user = $this->doctrine->getRepository("Twake\Users:User")->findOneBy(Array("id" => $participant["user_id_or_mail"])); + if (!$user) { + continue; + } + $mail = $user->getEmail(); + } else { + continue; + } + + $fixed_participant["email"] = $mail; + $participant = $fixed_participant; + + $user = new TaskUser($participant["user_id_or_mail"], $task->getId()); + $user->setEmail($mail); + $this->doctrine->persist($user); + + $updated_participants_fixed[] = $participant; + + } + + $_updated_participants_fixed = []; + foreach ($updated_participants_fixed as $v) { + $_updated_participants_fixed[] = $v; + } + $updated_participants_fixed = $_updated_participants_fixed; + + $task->setParticipants($updated_participants_fixed); + $this->doctrine->persist($task); + + $this->doctrine->flush(); + } + + public function updateAttachements(Task $task, $attachements = Array()) + { + $oldAttachements = $task->getAttachements() ? $task->getAttachements() : Array(); + $newAttachement = $oldAttachements; + $get_diff = $this->getArrayDiffUsingKeys($attachements, $oldAttachements, ["id"]); + foreach ($get_diff["del"] as $att) { + foreach ($newAttachement as $index => $attac) { + if ($attac["id"] == $att["id"] && $attac["type"] == $att["type"]) { + $attachedRepo = $this->getAttachementRepository($att["type"]); + if ($attachedRepo) { + $entityAttached = $attachedRepo->findOneBy(Array("id" => $att["id"])); + $attachmentInEntityAttached = $entityAttached->getAttachements(); + foreach ($attachmentInEntityAttached as $index1 => $attac1) { + if ($attac1["id"] == $task->getId() && $attac1["type"] == "task" && $attac1["isAtttached"]) { + unset($attachmentInEntityAttached[$index1]); + $entityAttached->setAttachements($attachmentInEntityAttached); + $this->doctrine->persist($entityAttached); + break; + } + } + } + unset($newAttachement[$index]); + } + } + } + foreach ($get_diff["add"] as $att) { + $att["isAttached"] = false; + $newAttachement[] = $att; + $attachedRepo = $this->getAttachementRepository($att["type"]); + if ($attachedRepo) { + $entityAttached = $attachedRepo->findOneBy(Array("id" => $att["id"])); + if ($entityAttached) { + $attachmentInEntityAttached = $entityAttached->getAttachements(); + $attachmentOfAttached = Array( + "type" => "task", + "id" => $task->getId(), + "name" => $task->getTitle(), + "isAttached" => true + ); + $attachmentInEntityAttached[] = $attachmentOfAttached; + $entityAttached->setAttachements($attachmentInEntityAttached); + $this->doctrine->persist($entityAttached); + } + } + } + $task->setAttachements($newAttachement); + $this->doctrine->persist($task); + $this->doctrine->flush(); + } + + public function getAttachementRepository($type) + { + if ($type == "file") { + return $this->doctrine->getRepository("Twake\Drive:DriveFile"); + } elseif ($type == "task") { + return $this->doctrine->getRepository("Twake\Tasks:Task"); + } elseif ($type == "event") { + return $this->doctrine->getRepository("Twake\Calendar:Event"); + } + return false; + } + + public function checkReminders() + { + $sent = 0; + + $notifications = $this->queues_scheduled->consume("tasks_task", true); + + foreach ($notifications ?: [] as $notification_original) { + + $notification = $this->queues_scheduled->getMessage($notification_original); + + //Send notification + $task = $this->doctrine->getRepository("Twake\Tasks:Task")->findOneBy(Array("id" => $notification["task_id"])); + + if ($task) { + + $existing_notifications = $task->getNotifications(); + $valid_notification = false; + foreach ($existing_notifications as $existing_notification) { + //Verify this received notification exists in calendar event + if ($existing_notification["token"] == $notification["token"]) { + $valid_notification = true; + } + } + + if ($valid_notification) { + + $is_deadline = false; + if ($task->getBefore() && abs($task->getBefore() - (date("U") + $notification["delay"])) < 60) { + $is_deadline = true; + } + + if (!$task->getArchived()) { + + $delay = floor($notification["delay"] / 60) . "min"; + if ($notification["delay"] > 60 * 60) { + $delay = floor($notification["delay"] / (60 * 60)) . "h"; + } + if ($notification["delay"] > 60 * 60 * 24) { + $delay = floor($notification["delay"] / (60 * 60 * 24)) . "j"; + } + if ($notification["delay"] > 60 * 60 * 24 * 7 * 2) { + $delay = floor($notification["delay"] / (60 * 60 * 24 * 7)) . "w"; + } + + $title = "Untitled"; + if ($task->getTitle()) { + $title = $task->getTitle(); + } + $text = $title . ($is_deadline ? " (deadline)" : "") . ($delay > 0 ? (" in " . $delay) : ""); + + $participants = $task->getParticipants(); + + foreach ($participants as $participant) { + if ($notification["mode"] == "mail" || !$notification["mode"]) { + $mail = $participant["user_id_or_mail"]; + $language = false; + if (preg_match('/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/', $participant["user_id_or_mail"])) { + $mail = $this->doctrine->getRepository("Twake\Users:User")->findOneBy(Array("id" => $participant["user_id_or_mail"])); + if ($mail) { + $language = $mail->getLanguage(); + $mail = $mail->getEMail(); + } else { + $mail = null; + } + } + //Mail + if ($mail) { + $this->notifications->sendCustomMail( + $mail, "task_notification", Array( + "_language" => $language ? $language : "en", + "text" => $text, + "delay" => $delay, + "task" => $task->getAsArray() + ) + ); + } + } + if ($notification["mode"] == "push" || !$notification["mode"]) { + //Push notification + if (preg_match('/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/', $participant["user_id_or_mail"])) { + $user = $this->doctrine->getRepository("Twake\Users:User")->findOneBy(Array("id" => $participant["user_id_or_mail"])); + if ($user) { + $this->notifications->pushDevice( + $user, $text, "πŸ“‹ Tasks notification", null, Array( + ) + ); + } + } + } + } + } + } + } + + + $sent++; + $this->queues_scheduled->ack("tasks_task", $notification_original); + + } + + return $sent; + + } + +} diff --git a/twake/backend/core/src/Twake/Upload/Bundle.php b/twake/backend/core/src/Twake/Upload/Bundle.php new file mode 100755 index 00000000..a8aacda2 --- /dev/null +++ b/twake/backend/core/src/Twake/Upload/Bundle.php @@ -0,0 +1,24 @@ +<?php + +namespace Twake\Upload; + +require_once __DIR__ . "/Resources/Services.php"; + +use Twake\Upload\Resources\Services; +use Common\BaseBundle; + +class Bundle extends BaseBundle +{ + + protected $bundle_root = __DIR__; + protected $bundle_namespace = __NAMESPACE__; + protected $routes = []; + protected $services = []; + + public function init() + { + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Upload/Entity/File.php b/twake/backend/core/src/Twake/Upload/Entity/File.php new file mode 100755 index 00000000..47769cc3 --- /dev/null +++ b/twake/backend/core/src/Twake/Upload/Entity/File.php @@ -0,0 +1,274 @@ +<?php + +namespace Twake\Upload\Entity; + +use Doctrine\ORM\Mapping as ORM; + + +/** + * File + * + * Fichiers uploadΓ© /!\ sauf drive ! + * + * @ORM\Table(name="file",options={"engine":"MyISAM"}) + * @ORM\Entity() + */ +class File +{ + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @var string + * + * @ORM\Column(name="type", type="string", length=8) + */ + private $type; //Define where this file is used + + /** + * @var string + * + * @ORM\Column(name="name", type="string", length=255) + */ + private $name; //Name of the file in server (md5) + + /** + * @var string + * + * @ORM\Column(name="real_name", type="string", length=255) + */ + private $realname; //Original name of the files on user computer + + /** + * @var int + * + * @ORM\Column(name="sizes", type="integer") + */ + private $sizes; //Size (binary position) : 0 = original + // 1 = 512 + // 2 = 256 + // 3 = 128 + // 4 = 64 + // Example : 00001 = 1 = only original + // 10111 = 23 = original, 512, 256 and 64 sizes + + /** + * @var int + * + * @ORM\Column(name="date", type="twake_bigint") + */ + private $date; //Creation date + + /** + * @var int + * + * @ORM\Column(name="weight", type="integer") + */ + private $weight; + + /** + * @ORM\Column(name="provider", type="string") + */ + private $provider; + + /** + * + * @ORM\Column(name="aws_public_link", type="twake_text") + */ + private $aws_public_link = false; + + + public function __construct() + { + $this->name = "<null>"; + $this->sizes = 31; //All sizes + $this->date = date("U"); + $this->weight = 0; + } + + + /** + * Get id + * + * @return int + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + public function setProvider($provider) + { + $this->provider = $provider; + } + + public function getProvider() + { + return $this->provider; + } + + /** + * Return the url to get the file (public url) + * @param int $size + * @return string + */ + public function getPublicURL($size = 0) + { + if ($this->aws_public_link) { + return $this->aws_public_link . ""; + } + if (!$this->size_exists($size)) { + return ""; + } + return "/upload/" . $this->type . "/" . $size . "/" . $this->name; + } + + /** + * Return the url to get the file (local url) + * @param int $size + * @return string + */ + public function getLocalServerURL($size = 0) + { + if ($this->aws_public_link) { + return false; + } + return "../web/" . $this->getPublicURL($size); + } + + + /** + * @ORM\PostRemove() + */ + public function deleteFromDisk() + { //Delete files from disk + for ($i = 0; $i <= 4; $i++) { + if ($this->size_exists($i)) { + @unlink($this->getLocalServerURL($i)); + } + } + } + + /** + * Return true if this size is available + * @param $size + * @return bool + */ + private function size_exists($size) + { + $sizes = decbin($this->sizes); + if ($sizes[strlen($sizes) - $size - 1] != 1) { + return false; + } + return true; + } + + /** + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * @param string $type + */ + public function setType($type) + { + $this->type = $type; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @param string $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @return int + */ + public function getSizes() + { + return $this->sizes; + } + + /** + * @param int $sizes + */ + public function setSizes($sizes) + { + $this->sizes = $sizes; + } + + + /** + * @return int + */ + public function getWeight() + { + return $this->weight; + } + + /** + * @param int $weight + */ + public function setWeight($weight) + { + $this->weight = $weight; + } + + /** + * @return string + */ + public function getRealName() + { + return $this->realname; + } + + /** + * @param string $realname + */ + public function setRealName($realname) + { + $this->realname = $realname; + } + + /** + * @return mixed + */ + public function getPublicLink() + { + return $this->aws_public_link; + } + + /** + * @param mixed $aws_public_link + */ + public function setPublicLink($aws_public_link) + { + $this->aws_public_link = $aws_public_link; + } + + +} diff --git a/twake/backend/core/src/Twake/Upload/Resources/Services.php b/twake/backend/core/src/Twake/Upload/Resources/Services.php new file mode 100755 index 00000000..ba475c93 --- /dev/null +++ b/twake/backend/core/src/Twake/Upload/Resources/Services.php @@ -0,0 +1,20 @@ +<?php + +namespace Twake\Upload\Resources; + +use Common\BaseServices; + +class Services extends BaseServices +{ + + protected $services = [ + "app.images_modifiers" => "ImagesModifiers", + "app.upload" => "Upload", + "app.uploader" => "Uploader", + #AWS + "app.aws_uploader" => "AWS_Uploader", + #OpenStack + "app.openstack_uploader" => "OpenStack_Uploader", + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Upload/Services/AWS_Uploader.php b/twake/backend/core/src/Twake/Upload/Services/AWS_Uploader.php new file mode 100755 index 00000000..e2852835 --- /dev/null +++ b/twake/backend/core/src/Twake/Upload/Services/AWS_Uploader.php @@ -0,0 +1,113 @@ +<?php + + +namespace Twake\Upload\Services; + +use App\App; +use Aws\S3\Exception\S3Exception; +use Aws\S3\S3Client; + +class AWS_Uploader extends Uploader +{ + + public function __construct(App $app) + { + parent::__construct($app); + } + + public function configure($config){ + $s3_config = $config; + + $this->aws_version = $s3_config["version"]; + $this->aws_buckets = $s3_config["buckets"]; + $this->aws_buckets_prefix = $s3_config["buckets_prefix"]; + $this->aws_credentials_key = $s3_config["credentials"]["key"]; + $this->aws_credentials_secret = $s3_config["credentials"]["secret"]; + + $region = false; + foreach ($this->aws_buckets as $region_code => $aws_region) { + if ($region_code == "fr" || !$region) { + $region = $aws_region; + } + } + $this->aws_bucket_name = isset($s3_config["bucket_name"]) ? $s3_config["bucket_name"] : ($this->aws_buckets_prefix . 'twake.' . $region); + $this->aws_bucket_region = $region; + + $options = [ + 'version' => $this->aws_version, + 'region' => $this->aws_bucket_region, + 'use_path_style_endpoint' => isset($s3_config["use_path_style_endpoint"]) ? $s3_config["use_path_style_endpoint"] : false, + 'credentials' => [ + 'key' => $this->aws_credentials_key, + 'secret' => $this->aws_credentials_secret + ] + ]; + if (isset($s3_config["base_url"]) && $s3_config["base_url"]) { + $options["endpoint"] = $s3_config["base_url"]; + } + + $this->aws_s3_client = new S3Client($options); + + } + + public function upload($realfile, $file, $context) + { + $contexts = $this->getContexts(); + + $file_size = filesize($realfile); + + $upload_status = []; + + $error = "unknown"; + if ($upload_status["status"] != "error") { + + try { + // Upload data. + $result = $this->aws_s3_client->putObject([ + 'Bucket' => $this->aws_bucket_name, + 'Key' => "public/uploads/" . $file->getType() . "/" . $file->getName(), + 'Body' => fopen($realfile, "rb"), + 'ACL' => 'public-read' + ]); + + $file->setPublicLink($result['ObjectURL']); + + return Array( + "errors" => [], + "status" => "success", + "filesize" => $file_size + ); + + } catch (S3Exception $e) { + $error = $e->getMessage(); + } + + } + + return Array( + "errors" => [$error], + "status" => "error" + ); + } + + public function removeFile($file, $flush = true) + { + + try { + + $this->aws_s3_client->deleteObject([ + 'Bucket' => $this->aws_bucket_name, + 'Key' => "public/uploads/" . $file->getType() . "/" . $file->getName(), + ]); + + } catch (S3Exception $e) { + $error = $e->getMessage(); + } + + $this->doctrine->remove($file); + if ($flush) { + $this->doctrine->flush(); + } + } + +} diff --git a/twake/backend/core/src/Twake/Upload/Services/ImagesModifiers.php b/twake/backend/core/src/Twake/Upload/Services/ImagesModifiers.php new file mode 100755 index 00000000..7ff5e2ce --- /dev/null +++ b/twake/backend/core/src/Twake/Upload/Services/ImagesModifiers.php @@ -0,0 +1,276 @@ +<?php + +namespace Twake\Upload\Services; + +use App\App; + +class ImagesModifiers +{ + + /** + * THUMBNAILS + */ + + /** + * Supported image types + * + * @staticvar array + */ + public static $__image_types = array( + 0x1 => 'gif', + 0x2 => 'jpeg', + 0x3 => 'png', + 0x6 => 'bmp' + ); + + /** + * Allowed image types/file extensions (separate multiple values with pipe '|') + * + * @var string + */ + public $allowed_image_types = 'bmp|gif|jpg|jpeg|png'; + + /** + * JPEG compression level (0-100, 0 is the most compression) + * + * @var int + */ + public $compression_jpeg = 50; + + /** + * PNG compresssion level (0-8, 8 is the most compression, 0 is none) + * + * @var int + */ + public $compression_png = 8; + + /** + * Max dimesion (this can control both width and height) + * + * @var int + */ + public $max_dimension = 200; + + /** + * Max height dimension (this will override max_dimension property) + * + * @var int + */ + public $max_height = 0; + + /** + * Max width dimension (this will override max_dimension property) + * + * @var int + */ + public $max_width = 0; + + /** + * Use true color flag + * + * @var bool + */ + public $use_true_color = true; + + /** + * Init + */ + public function __construct(App $app) + { + if (!function_exists('getimagesize')) { // check for GD library + trigger_error(__CLASS__ . ' requires the GD library', E_USER_ERROR); + } + } + + public function setMax_dimension($md) + { + $this->max_dimension = $md; + } + + /** + * Draw/create thumbnail image + * + * @param string $image_path (source image path) + * @param string $target_path (optional, will save image instead of output if set) + * @return void + */ + public function draw($image_path, $target_path = null) + { + + if (!file_exists($image_path)) // check if image exists + { + trigger_error('Image "' . $image_path . '" does not exist', E_USER_ERROR); + } + + if (!preg_match('/\.(' . $this->allowed_image_types . ')$/i', $image_path)) // check valid image type + { + trigger_error('Invalid image type for image "' . $image_path . '"', E_USER_ERROR); + } + + $img_info = getimagesize($image_path); // set image info + list($img_w, $img_h, $img_type) = $img_info; + $img_mine = null; + + if ($img_type > 0 && !isset(self::$__image_types[$img_type])) // check valid image type code + { + trigger_error('Invalid image type for image "' . $image_path . '" (image type code: ' . $img_type . ')'); + } + + if (isset($img_info['mime'])) { + $img_mine = $img_info['mime']; + } else { + trigger_error('Invalid iamge MIME type for image "' . $image_path . '"', E_USER_ERROR); + } + + // override max dimesion + $this->max_dimension = $this->max_height > 0 ? $this->max_height : $this->max_dimension; + $this->max_dimension = $this->max_width > 0 ? $this->max_width : $this->max_dimension; + + // set new dimensions + $img_new_w = $img_new_h = 0; + if ($this->max_width > 0 && $img_w > $this->max_width) // resize on width + { + $img_new_w = $this->max_width; + $img_new_h = round($img_h * ($img_new_w / $img_w)); + } else if ($this->max_height > 0 && $img_h > $this->max_height) // resize on height + { + $img_new_h = $this->max_height; + $img_new_w = round($img_w * ($img_new_h / $img_h)); + } else if ($img_w > $this->max_dimension || $img_h > $this->max_dimension) // resize on max dim + { + $img_new_w = $this->max_dimension; + $img_new_h = $this->max_dimension; + if ($img_w > $img_h) { + $img_new_h = round($img_h * ($img_new_w / $img_w)); + } else { + $img_new_w = round($img_w * ($img_new_h / $img_h)); + } + } + + $fc = $this->use_true_color ? 'imagecreatetruecolor' : 'imagecreate'; // use truecolor for jpeg + if ($img_new_w > 0 && $img_new_h > 0) // check if resize needed + { + $img_new = $fc($img_new_w, $img_new_h); + $f = 'imagecreatefrom' . self::$__image_types[$img_type]; + + $img = new \Imagick($image_path); + $img = $this->autorotate($img); + $img->writeImage(); + + $img = $f($image_path); + imagealphablending($img_new, true); + imagesavealpha($img_new, true); + $whiteBackground = imagecolorallocatealpha($img_new, 255, 255, 255, 0); + imagefill($img_new,0,0,$whiteBackground); // fill the background with white + imagecopyresampled($img_new, $img, 0, 0, 0, 0, $img_new_w, $img_new_h, $img_w, $img_h); + imagedestroy($img); + } else { + $img_new = $fc($img_w, $img_h); + $f = 'imagecreatefrom' . self::$__image_types[$img_type]; + $img_new = $f($image_path); + } + + $f = 'image' . self::$__image_types[$img_type]; + if (strlen($target_path) < 1) // output image + { + header('Content-type: ' . $img_mine); + } + switch ($img_type) { + case 0x2: + $f($img_new, $target_path, $this->compression_jpeg); + break; + + case 0x3: + $f($img_new, $target_path, $this->compression_png); + break; + + default: + $f($img_new, $target_path); + break; + } + + imagedestroy($img_new); + } + + private function autorotate(\Imagick $image) + { + switch ($image->getImageOrientation()) { + case \Imagick::ORIENTATION_TOPLEFT: + break; + case \Imagick::ORIENTATION_TOPRIGHT: + $image->flopImage(); + break; + case \Imagick::ORIENTATION_BOTTOMRIGHT: + $image->rotateImage("#FFF", 180); + break; + case \Imagick::ORIENTATION_BOTTOMLEFT: + $image->flopImage(); + $image->rotateImage("#FFF", 180); + break; + case \Imagick::ORIENTATION_LEFTTOP: + $image->flopImage(); + $image->rotateImage("#FFF", -90); + break; + case \Imagick::ORIENTATION_RIGHTTOP: + $image->rotateImage("#FFF", 90); + break; + case \Imagick::ORIENTATION_RIGHTBOTTOM: + $image->flopImage(); + $image->rotateImage("#FFF", 90); + break; + case \Imagick::ORIENTATION_LEFTBOTTOM: + $image->rotateImage("#FFF", -90); + break; + default: // Invalid orientation + break; + } + $image->setImageOrientation(\Imagick::ORIENTATION_TOPLEFT); + return $image; + } + + function improve($path) + { + + if (mime_content_type($path) != "image/jpeg" + or mime_content_type($path) != "image/tiff") { + return; + } + + $exif = exif_read_data($path); + + if (isset($exif['Orientation'])) { + switch ($exif['Orientation']) { + case 3: + $this->rotate($path, 180); + break; + + case 6: + $this->rotate($path, -90); + break; + + case 8: + $this->rotate($path, 90); + break; + } + } + + + } + + /*** + * ROTATIONS (IOS) + * @param $path + * @param $deg + */ + + + function rotate($path, $deg) + { + if (exif_imagetype($path) == IMAGETYPE_JPEG) { + $source = imagecreatefromjpeg($path); + $rotate = imagerotate($source, $deg, 0); + imagejpeg($rotate, $path); + } + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Upload/Services/OpenStack_Uploader.php b/twake/backend/core/src/Twake/Upload/Services/OpenStack_Uploader.php new file mode 100755 index 00000000..4cc52c8e --- /dev/null +++ b/twake/backend/core/src/Twake/Upload/Services/OpenStack_Uploader.php @@ -0,0 +1,135 @@ +<?php + + +namespace Twake\Upload\Services; + +use GuzzleHttp\Client; +use GuzzleHttp\HandlerStack; +use GuzzleHttp\Psr7\Stream; +use OpenStack\Common\Transport\Utils as TransportUtils; +use OpenStack\Identity\v3\Service; +use OpenStack\OpenStack; +use App\App; + +class OpenStack_Uploader extends Uploader +{ + + public function __construct(App $app) + { + parent::__construct($app); + } + + public function configure($openstack){ + + $this->openstack_buckets = $openstack["buckets"]; + $this->openstack_buckets_prefix = $openstack["buckets_prefix"]; + $this->openstack_credentials_key = $openstack["user"]["id"]; + $this->openstack_credentials_secret = $openstack["user"]["password"]; + $this->openstack_domain_name = $openstack["user"]["domain_name"]; + $this->openstack_project_id = $openstack["project_id"]; + $this->openstack_auth_url = $openstack["auth_url"]; + $this->disable_encryption = $openstack["disable_encryption"]; + + $httpClient = new Client([ + 'base_uri' => TransportUtils::normalizeUrl($this->openstack_auth_url ? $this->openstack_auth_url : ""), + 'handler' => HandlerStack::create(), + ]); + + $region = false; + foreach ($this->openstack_buckets as $region_code => $openstack_region) { + if ($region_code == "fr" || !$region) { + if (isset($openstack_region["private"])) { + $region = $openstack_region["private"]; + $public_region = $openstack_region["public"]; + } else { + $region = $openstack_region["public"]; + } + $region_id = $openstack_region["region"]; + } + } + $this->openstack_bucket_name = $this->openstack_buckets_prefix . $region; + $this->openstack_public_bucket_name = $this->openstack_buckets_prefix . $public_region; + $this->openstack_bucket_region = $region; + $this->openstack_region_id = $region_id; + + $this->openstack = new OpenStack([ + 'authUrl' => $this->openstack_auth_url, + 'region' => $this->openstack_region_id, + 'user' => [ + 'name' => $this->openstack_credentials_key, + 'password' => $this->openstack_credentials_secret, + 'domain' => [ 'id' => $this->openstack_domain_name ] + ], + 'scope' => [ + 'project' => [ + 'id' => $this->openstack_project_id + ] + ], + 'identityService' => Service::factory($httpClient) + ]); + + + } + + public function upload($realfile, $file, $context) + { + $contexts = $this->getContexts(); + + $file_size = filesize($realfile); + + $upload_status = []; + + $error = "unknown"; + if ($upload_status["status"] != "error") { + + try { + // Upload data. + $options = [ + 'name' => "public/uploads/" . $file->getType() . "/" . $file->getName(), + 'stream' => new Stream(fopen($realfile, "rb")), + ]; + $result = $this->openstack->objectStoreV1() + ->getContainer($this->openstack_public_bucket_name) + ->createObject($options); + + $file->setPublicLink($result->getPublicUri()); + + return Array( + "errors" => [], + "status" => "success", + "filesize" => $file_size + ); + + } catch (\Exception $e) { + $error = $e->getMessage(); + } + + } + + return Array( + "errors" => [$error], + "status" => "error" + ); + } + + public function removeFile($file, $flush = true) + { + + try { + + $this->openstack->objectStoreV1() + ->getContainer($this->openstack_public_bucket_name) + ->getObject("public/uploads/" . $file->getType() . "/" . $file->getName()) + ->delete(); + + } catch (\Exception $e) { + $error = $e->getMessage(); + } + + $this->doctrine->remove($file); + if ($flush) { + $this->doctrine->flush(); + } + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Upload/Services/Upload.php b/twake/backend/core/src/Twake/Upload/Services/Upload.php new file mode 100755 index 00000000..72bdcef9 --- /dev/null +++ b/twake/backend/core/src/Twake/Upload/Services/Upload.php @@ -0,0 +1,162 @@ +<?php + + +namespace Twake\Upload\Services; + +use App\App; + +class Upload +{ + + var $imagesModifiers; + var $default_context; + + function __construct(App $app) + { + + $this->default_context = Array( + "is_img" => 1, + "max_size" => 1000000, //1mo + "sizes" => 3 //512 && original + ); + + } + + function setImageModifiers($imagesModifiers) + { + $this->imagesModifiers = $imagesModifiers; + } + + public function upload($file, $path, $context) + { + + + error_log(json_encode($file)); + + $upload_status = Array(); + $upload_status["status"] = ""; + $upload_status["errors"] = Array(); + + //Forcer la crΓ©ation du dossier + if (!file_exists(dirname($path))) { + mkdir(dirname($path), 0755, true); + } + + $upload_status["file"] = $file; + + $upload_status["filesize"] = filesize($file); + + //Create directory if doesnt exists + if (!file_exists(dirname($path))) { + mkdir(dirname($path), 0777, true); + } + + //MOVE THE FILE + $moved = false; + if ($upload_status["status"] != "error") { + set_time_limit(600); + $moved = rename($file, $path); + } + + if ($moved) { + + //Verify that is it an image if wanted + if (isset($context["is_img"]) && $context["is_img"] == 1) { + $image_info = getimagesize($path); + if ($image_info === false) { + $upload_status["status"] = "error"; + $upload_status["errors"][] = "not_image"; + } + + $width = $image_info[0]; + $height = $image_info[1]; + + if (isset($context["min_width"]) && $context["min_width"] > $width) { + $upload_status["status"] = "error"; + $upload_status["errors"][] = "width_too_small"; + } + if (isset($context["max_width"]) && $context["max_width"] < $width) { + $upload_status["status"] = "error"; + $upload_status["errors"][] = "width_too_large"; + } + if (isset($context["min_height"]) && $context["min_height"] > $height) { + $upload_status["status"] = "error"; + $upload_status["errors"][] = "height_too_small"; + } + if (isset($context["max_height"]) && $context["max_height"] < $height) { + $upload_status["status"] = "error"; + $upload_status["errors"][] = "height_too_large"; + } + + } + + } + + if ($moved && $upload_status["status"] != "error") { + + if (isset($context["is_img"]) && $context["is_img"] == 1) {//Rectifie l'orientation des images prises avec l'appareil photo ios + $this->imagesModifiers->improve($path); + } + + $upload_status["status"] = "success"; + + } else { + + if ($moved) { + unlink($path); + $upload_status["errors"][] = "unknown_error_moved"; + } else { + $upload_status["errors"][] = "unknown_error_on_move"; + } + + $upload_status["status"] = "error"; + + } + + return $upload_status; + + } + + public function verifyContext(&$upload_status, $file, $context) + { + if (filesize($file['tmp_name']) > $context['max_size']) { + $upload_status["status"] = "error"; + $upload_status["errors"][] = "max_size_exeeded"; + } + + $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); + if (isset($context["allowed_ext"]) && !in_array($ext, $context["allowed_ext"])) { + $upload_status["status"] = "error"; + $upload_status["errors"][] = "ext_not_allowed_" . $ext; + } + + } + + public function addThumbnail($original, $size, $path) + { + + //Forcer la crΓ©ation du dossier + if (!file_exists(dirname($path))) { + mkdir(dirname($path), 0755, true); + } + + $this->imagesModifiers->setMax_dimension($size); + $this->imagesModifiers->draw($original, $path); + + } + + private function getAsArraySizes($sizes) + { + $res = Array(); + + $reallimit_sizes = Array(64, 128, 256, 512, 1000000000000); + foreach (str_split(decbin($sizes)) as $i => $s) { + if ($s == 1) { + $res[] = $reallimit_sizes[$s]; + } + } + + return $res; + } + +} diff --git a/twake/backend/core/src/Twake/Upload/Services/Uploader.php b/twake/backend/core/src/Twake/Upload/Services/Uploader.php new file mode 100755 index 00000000..476d4c03 --- /dev/null +++ b/twake/backend/core/src/Twake/Upload/Services/Uploader.php @@ -0,0 +1,217 @@ +<?php + +namespace Twake\Upload\Services; + +use App\App; +use Twake\Upload\Entity\File; + +class Uploader +{ + + var $doctrine; + var $uploadService; + var $modifiersService; + var $tempFolder; + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->uploadService = $app->getServices()->get("app.upload"); + $this->modifiersService = $app->getServices()->get("app.images_modifiers"); + $this->tempFolder = $app->getContainer()->getParameter("storage.drive_tmp_folder"); + } + + public function configure($configuration){ + return; + } + + /** + * Upload a file + * $file = $_FILE["aa"]; + * $context = "prfl"/"covr" + * + * returns : + * Array of results + */ + public function uploadFiles($currentUser, $file, $context) + { + + $res = Array(); + + if (!is_array($file["tmp_name"])) { + $res[] = $this->uploadTheFile($currentUser, $file, $context); + } else { + + foreach ($file["tmp_name"] as $key => $null) { + $file = Array(); + $file["tmp_name"] = $file["tmp_name"][$key]; + $file["name"] = $file["name"][$key]; + $file["size"] = $file["size"][$key]; + $res[] = $this->uploadTheFile($currentUser, $file, $context); + } + } + + return $res; + + } + + /** + * Upload file into disk and add it to bdd (using context != drive) + * @param $file + * @return File + */ + private function uploadTheFile($currentUser, $realfile, $context) + { + + if ($currentUser == null || !$currentUser->getId()) { + return Array("errors" => Array("error_not_connected"), "file" => null, "realfile" => $realfile); + } + + /** + * Allowed context + */ + + $contexts = $this->getContexts(); + + if (!isset($contexts[$context])) { + return Array("errors" => Array("error_not_such_context"), "file" => null, "realfile" => $realfile); + } + + + $orm = $this->doctrine; + + + $this->uploadService->verifyContext($upload_status, $realfile, $contexts[$context]); + if ($upload_status["status"] != "error") { + + $file = new File(); + + $file->setType($context); + + + $newfilename = md5(date("U") . $realfile["tmp_name"] . $realfile["name"]) . "." . $this->getExtension($realfile["name"]); + $file->setName($newfilename); + $file->setRealName($realfile["name"]); + $file->setSizes($contexts[$context]['sizes']); + + $this->uploadService->setImageModifiers($this->modifiersService); + + $tmpFile = $this->tempFolder . "thumb-" . date("U") . "-" . $currentUser->getId() . "-" . $realfile["name"]; + move_uploaded_file($realfile["tmp_name"], $tmpFile); + + $this->modifiersService->setMax_dimension(192); + $this->modifiersService->draw($tmpFile, $tmpFile); + + $upload_status = $this->upload($tmpFile, $file, $context); //Upload thumbnail + + @unlink($tmpFile); + + $file->setWeight($upload_status['filesize']); + + } + + if ($upload_status["status"] == "success") { + + $orm->persist($file); + $orm->flush(); + + $upload_status["fileEntity"] = $file; + + return Array("errors" => $upload_status["errors"], "file" => $upload_status["fileEntity"], "realfile" => $realfile); + + } else { + + return Array("errors" => $upload_status["errors"], "file" => null, "realfile" => $realfile); + + } + + } + + public function getContexts() + { + return Array( + "prfl" => Array( + "is_img" => 1, + "max_size" => 2000000, //2mo + "sizes" => 31, //All ! + "allowed_ext" => Array("png", "jpg", "jpeg", "gif", "tiff") + ), + "covr" => Array( + "is_img" => 1, + "max_size" => 3000000, //3mo + "min_width" => 900, + "min_height" => 230, + "sizes" => 31, //All ! + "allowed_ext" => Array("png", "jpg", "jpeg", "gif", "tiff") + ), + "wslogo" => Array( + "is_img" => 1, + "max_size" => 2000000, //2mo + "min_width" => 100, + "min_height" => 100, + "sizes" => 31, //All ! + "allowed_ext" => Array("png", "jpg", "jpeg", "gif", "tiff") + ), + "grouplogo" => Array( + "is_img" => 1, + "max_size" => 2000000, //2mo + "min_width" => 100, + "min_height" => 100, + "sizes" => 31, //All ! + "allowed_ext" => Array("png", "jpg", "jpeg", "gif", "tiff") + ), + "wswall" => Array( + "is_img" => 1, + "max_size" => 4000000, //2mo + "min_width" => 0, + "min_height" => 0, + "sizes" => 31, //All ! + "allowed_ext" => Array("png", "jpg", "jpeg", "gif", "tiff") + ), + "msg" => Array( + "is_img" => 0, + "max_size" => 10000000, //10mo + "sizes" => 31 + ), + "status" => Array( + "is_img" => 0, + "max_size" => 3000000, //3mo + ) + ); + } + + private function getExtension($filename) + { + return pathinfo($filename, PATHINFO_EXTENSION); + } + + public function upload($realfile, $file, $context) + { + $contexts = $this->getContexts(); + $upload_status = $this->uploadService->upload($realfile, $file->getLocalServerURL(0), $contexts[$context]); + + if ($upload_status["status"] == "success") { + //Ajouter les thumbnails ! + if ($contexts[$context]['is_img']) { + $sizes = Array(0, 512, 256, 128, 64); + for ($size = 1; $size <= 4; $size++) { + if (decbin($file->getSizes())[$size] == 1) { + $this->uploadService->addThumbnail($file->getLocalServerURL(0), $sizes[$size], $file->getLocalServerURL($size)); //Upload thumbnails + } + } + } + } + + return $upload_status; + } + + public function removeFile($file, $flush = true) + { + $file->deleteFromDisk(); + $this->doctrine->remove($file); + if ($flush) { + $this->doctrine->flush(); + } + } + +} diff --git a/twake/backend/core/src/Twake/Users/Bundle.php b/twake/backend/core/src/Twake/Users/Bundle.php new file mode 100755 index 00000000..fb117c2a --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Bundle.php @@ -0,0 +1,30 @@ +<?php + +namespace Twake\Users; + +require_once __DIR__ . "/Resources/Routing.php"; +require_once __DIR__ . "/Resources/Services.php"; + +use Twake\Users\Resources\Routing; +use Twake\Users\Resources\Services; +use Common\BaseBundle; + +class Bundle extends BaseBundle +{ + + protected $bundle_root = __DIR__; + protected $bundle_namespace = __NAMESPACE__; + protected $routes = []; + protected $services = []; + + public function init() + { + $routing = new Routing(); + $this->routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Users/Controller/Adapters/CAS.php b/twake/backend/core/src/Twake/Users/Controller/Adapters/CAS.php new file mode 100755 index 00000000..1d6eb77f --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Controller/Adapters/CAS.php @@ -0,0 +1,118 @@ +<?php + + +namespace Twake\Users\Controller\Adapters; + +use Common\BaseController; +use Common\Http\Request; +use Common\Http\Response; + +class CAS extends BaseController +{ + + function logoutSuccess(Request $request) + { + return $this->closeIframe("success"); + } + + // Redirect user to CAS connection page + public function login() + { + $cas_login_page_url = $this->getParameter("defaults.auth.cas.base_url"); + $cas_login_page_url .= "/login?"; + $cas_login_page_url .= "service="; + $cas_login_page_url .= urlencode($this->getParameter("env.server_name") . "ajax/users/cas/verify"); + return $this->redirect($cas_login_page_url); + } + + // Verify CAS token and search for user in database (or create it) + public function verify(Request $request) + { + $ticket = $request->query->get("ticket"); + $cas_ticket_verification_url = $this->getParameter("defaults.auth.cas.base_url"); + + $cas_ticket_verification_url .= "/serviceValidate?"; + $cas_ticket_verification_url .= "service="; + $cas_ticket_verification_url .= urlencode($this->getParameter("env.server_name") . "ajax/users/cas/verify"); + $cas_ticket_verification_url .= "&ticket=" . $ticket; + $cas_ticket_verification_url .= "&format=JSON"; + + //var_dump($cas_ticket_verification_url); + //die(); + + $response = $this->get("app.restclient")->get($cas_ticket_verification_url); + $response = $response->getContent(); + if (strpos($response, "<cas:") !== false) { + $result = Array(); + if (strpos($response, "cas:authenticationSuccess") !== false) { + $username = explode("<cas:user>", $response); + $username = explode("</cas:user>", $username[1]); + $username = $username[0]; + if ($username) { + $result = Array( + "serviceResponse" => Array( + "authenticationSuccess" => Array( + "user" => $username + ) + ) + ); + } + } + } else { + $result = json_decode($response, true); + } + + if (isset($result["serviceResponse"]) && isset($result["serviceResponse"]["authenticationSuccess"])) { + $details = $result["serviceResponse"]["authenticationSuccess"]; + + $username = $details["user"]; + $mail = $username . "@" . str_replace(Array("http", "https", ":", "/"), "", $this->getParameter("defaults.auth.cas.base_url")); + $firstname = ""; + $lastname = ""; + + if (isset($details["attributes"])) { + + $mailKey = $this->getParameter("defaults.auth.cas.email_key") ? $this->getParameter("defaults.auth.cas.email_key") : "email"; + if (isset($details["attributes"][$mailKey])) { + $mail = $details["attributes"][$mailKey]; + } + + $lastnameKey = $this->getParameter("defaults.auth.cas.lastname_key") ? $this->getParameter("defaults.auth.cas.lastname_key") : "lastname"; + if (isset($details["attributes"][$lastnameKey])) { + $lastname = $details["attributes"][$lastnameKey]; + } + + $firstnameKey = $this->getParameter("defaults.auth.cas.firstname_key") ? $this->getParameter("defaults.auth.cas.firstname_key") : "firstname"; + if (isset($details["attributes"][$firstnameKey])) { + $firstname = $details["attributes"][$firstnameKey]; + } + + } + + //Search user with this username + $res = $this->get("app.user")->loginFromServiceWithToken("cas", $mail, $mail, $username, $firstname . " " . $lastname, ""); + + if ($res) { + return $this->closeIframe("success", $res); + } + + } + return new Response("An error occured, please contact CAS service administrator."); + + } + + // Redirect user to CAS logout page + public function logout(Request $request) + { + $this->get("app.user")->logout($request); + + $cas_login_page_url = $this->getParameter("defaults.auth.cas.base_url") . "/logout"; + return $this->redirect($cas_login_page_url); + } + + private function closeIframe($message, $userTokens=null) + { + $this->redirect(rtrim($this->getParameter("env.frontend_server_name", $this->getParameter("env.server_name")), "/") . "?external_login=".str_replace('+', '%20', urlencode(json_encode(["provider"=>"openid", "message" => $message, "token" => json_encode($userTokens)])))); + } + +} diff --git a/twake/backend/core/src/Twake/Users/Controller/Adapters/Console.php b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console.php new file mode 100755 index 00000000..70a7cf15 --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console.php @@ -0,0 +1,263 @@ +<?php + +namespace Twake\Users\Controller\Adapters; + +use Common\BaseController; +use Common\Http\Request; +use Common\Http\Response; +use Twake\Users\Entity\User; +use Twake\Users\Controller\Adapters\OpenID\OpenIDConnectClient; +use Twake\Users\Controller\Adapters\Console\Hooks; +use Twake\Users\Controller\Adapters\Console\ApplyUpdates; +class Console extends BaseController +{ + + /* + function hook(Request $request) + { + if(!$this->isServiceEnabled()){ + return new Response(["error" => "unauthorized"], 401); + } + + $handler = new Hooks($this->app); + $res = $handler->handle($request); + error_log(json_encode($res->getContent())); + return $res; + } + */ + + //Redirect hook to node + function hook(Request $request) + { + if(!$this->isServiceEnabled()){ + return new Response(["error" => "unauthorized"], 401); + } + + $api = $this->app->getServices()->get("app.restclient"); + + $secret = $request->query->get("secret_key"); + $uri = str_replace("/private", "/internal/services/console/v1", $this->app->getContainer()->getParameter("node.api")) . + ltrim("/hook?secret_key=".$secret, "/"); + + $opt = [ + CURLOPT_HTTPHEADER => Array( + "Authorization: Bearer " . $jwt, + "Content-Type: application/json" + ), + CURLOPT_CONNECTTIMEOUT => 1, + CURLOPT_TIMEOUT => 1 + ]; + + $data = [ + "content" => $request->request->get("content"), + "type" => $request->request->get("type"), + "secret_key" => $request->request->get("secret_key") + ]; + + error_log("Request to node:"); + error_log($uri); + error_log(json_encode($data)); + + $res = $api->request("POST", $uri, json_encode($data), $opt); + + error_log("Reply from node:"); + error_log($res->getContent()); + + return new Response([], 200); + + $handler = new Hooks($this->app); + $res = $handler->handle($request); + error_log(json_encode($res->getContent())); + return $res; + } + + + function logoutSuccess(Request $request) + { + if(!$this->isServiceEnabled()){ + return new Response(["error" => "unauthorized"], 401); + } + try{ + $message = json_decode(urldecode($request->query->get("error_code"))); + }catch(\Exception $err){ + $message = false; + } + + return $this->redirect(rtrim($this->getParameter("env.frontend_server_name", $this->getParameter("env.server_name")), "/") . "/login" . ($message ? ("?error_code=".str_replace('+', '%20', urlencode(json_encode($message)))) : "?auto")); + } + + function logout(Request $request, $message = null) + { + error_log(json_encode($message)); + + if(!$this->isServiceEnabled()){ + return new Response(["error" => "unauthorized"], 401); + } + error_reporting(E_ERROR | E_PARSE); + + $this->get("app.user")->logout($request); + + $logout_parameter = $this->getParameter("defaults.auth.console.openid.logout_query_parameter_key") ?: "post_logout_redirect_uri"; + $logout_url_suffix = $this->getParameter("defaults.auth.console.openid.logout_suffix") ?: "/oauth2/logout"; + + $logout_redirect_url = rtrim($this->getParameter("env.server_name"), "/") . "/ajax/users/console/openid/logout_success"; + + if($message){ + $logout_redirect_url .= "?error_code=".str_replace('+', '%20', urlencode(json_encode($message))); + } + + $redirect = ""; + if(!$this->getParameter("defaults.auth.console.openid.disable_logout_redirect")){ + $redirect = "?" . $logout_parameter . "=" . urlencode($logout_redirect_url); + } + + $this->redirect($this->getParameter("defaults.auth.console.openid.provider_uri") . $logout_url_suffix . $redirect); + } + + function index(Request $request) + { + if(!$this->isServiceEnabled()){ + return new Response(["error" => "unauthorized"], 401); + } + + error_reporting(E_ERROR | E_PARSE); + + $this->get("app.user")->logout($request); + + //We store the mobile session + if (!isset($_SESSION)) { + @session_start(); + } + + if($request->query->get("mobile", "")){ + $_SESSION["mobile"] = true; + } + + if($request->query->get("localhost", "")){ + $_SESSION["localhost"] = true; + $_SESSION["localhost_port"] = $request->query->get("port", "3000"); + } + + try { + $oidc = new OpenIDConnectClient( + $this->getParameter("defaults.auth.console.openid.provider_uri"), + $this->getParameter("defaults.auth.console.openid.client_id"), + $this->getParameter("defaults.auth.console.openid.client_secret") + ); + $oidc->setServerKey($this->app->getContainer()->getParameter("jwt.secret")); + + $oidc->setCodeChallengeMethod($this->getParameter("defaults.auth.console.openid.provider_config.code_challenge_methods_supported", [""])[0]); + $oidc->providerConfigParam($this->getParameter("defaults.auth.console.openid.provider_config", [])); + + $oidc->setRedirectURL(rtrim($this->getParameter("env.server_name"), "/") . "/ajax/users/console/openid"); + + $oidc->addScope(array('openid', 'email', 'profile', 'address', 'phone', 'offline_access')); + try { + $authentificated = $oidc->authenticate([ + "ignore_id_token" => true, + "ignore_nonce" => true + ]); + }catch(\Exception $err){ + error_log("Error with Authenticated: ".$err); + $authentificated = false; + } + if ($authentificated) { + return $this->generateReplyForLoginFromOIDCAccessToken($oidc->getAccessToken()); + }else{ + return $this->logout($request, ["error" => "OIDC auth error"]); + } + + } catch (\Exception $e) { + error_log($e); + $this->logout($request, ["error" => "Unknown error while processing OIDC login"]); + } + + return $this->logout($request, ["error" => "An unknown error occurred"]); + + } + + function loginFromOIDCAccessToken(Request $request){ + return new Response($this->generateReplyForLoginFromOIDCAccessToken($request->request->get("access_token"), false), 200); + } + + + function generateReplyForLoginFromOIDCAccessToken($access_token = null, $redirect = true){ + + $accessToken = $access_token; + + $url = rtrim($this->getParameter("defaults.auth.console.provider"), "/") . "/users/profile"; + $header = "Authorization: Bearer " . $accessToken; + $response = $this->app->getServices()->get("app.restclient")->get($url, array(CURLOPT_HTTPHEADER => [$header])); + $response = json_decode($response->getContent(), 1); + + error_log($header); + error_log(json_encode($response)); + + try { + + /** @var User $user */ + $user = (new ApplyUpdates($this->app))->updateUser($response); + + $userTokens = null; + if($user){ + $userTokens = $this->get("app.user")->loginWithIdOnlyWithToken($user->getId()); + } + + } catch (\Exception $e) { + error_log($e); + + if(!$redirect){ + return ["error" => "Unknown error while creating/getting your account"]; + } + + $this->logout($request, ["error" => "Unknown error while creating/getting account"]); + } + + if ($userTokens) { + + if(!$redirect){ + return ["access_token" => $this->get("app.user")->generateJWT($user)]; + } + + return $this->redirect(rtrim($this->getParameter("env.server_name"), "/") + . "/ajax/users/console/redirect_to_app?token=" . urlencode($userTokens["token"]) . "&username=" . urlencode($userTokens["username"]) ); + }else{ + + if(!$redirect){ + return ["error" => "No user profile created."]; + } + + return $this->logout($request, ["error" => "No user profile created: is your email already used in Twake?"]); + } + } + + function redirectToApp(Request $request){ + if (!isset($_SESSION)) { + @session_start(); + } + if($_SESSION["mobile"]){ + return new Response("", 200); + }else{ + return $this->closeIframe("success", [ + "token" => $request->query->get("token"), + "username" => $request->query->get("username") + ]); + } + } + + private function closeIframe($message, $userTokens=null) + { + $server = rtrim($this->getParameter("env.frontend_server_name", $this->getParameter("env.server_name")), "/"); + if($_SESSION["localhost"]){ + $server = "http://localhost:" . $_SESSION["localhost_port"]; + $_SESSION["localhost"] = false; + } + $this->redirect($server + . "/?external_login=".str_replace('+', '%20', urlencode(json_encode(["provider"=>"console", "message" => $message, "token" => json_encode($userTokens)])))); + } + + private function isServiceEnabled(){ + return $this->app->getContainer()->getParameter("defaults.auth.console.use"); + } + +} diff --git a/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/Api.php b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/Api.php new file mode 100755 index 00000000..00bc7c65 --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/Api.php @@ -0,0 +1,117 @@ +<?php + +namespace Twake\Users\Controller\Adapters\Console; + +use App\App; +use Common\BaseController; +use Common\Http\Request; +use Common\Http\Response; + +class Api extends BaseController +{ + + + /** @var TwakeRestClient */ + protected $api = null; + + /** @var String */ + protected $endpoint = null; + + /** @var String */ + private $authB64 = ""; + + public function __construct(App $app) + { + parent::__construct($app); + $this->api = $app->getServices()->get("app.restclient"); + $this->endpoint = $this->getParameter("defaults.auth.console.provider"); + $this->authB64 = base64_encode( + $this->getParameter("defaults.auth.console.credentials.key") + . ":" + . $this->getParameter("defaults.auth.console.credentials.secret")); + } + + /** + * Send again the verification email for an user + */ + public function verifyMail(Request $request) + { + if(!$this->getUser()){ + return new Response(["error" => "disconnected"]); + } + + $data = [ + "email" => $this->getUser()->getEmail() + ]; + $header = "Authorization: Basic " . $this->authB64; + $response = $this->api->post(rtrim($this->endpoint, "/") . "/users/resend-verification-email", json_encode($data), array(CURLOPT_HTTPHEADER => [$header, "Content-Type: application/json"])); + $result = json_decode($response->getContent(), 1); + + return new Response(["data" => $result]); + } + + /** + * Invite a list of emails to a workspace + */ + public function invite(Request $request) + { + $companyId = $request->request->get("company_id", ""); + $workspaceId = $request->request->get("workspace_id", ""); + $asExterne = false; + $emails = $request->request->get("emails", []); + $role = $request->request->get("role", "member"); + + // Get company code + $doctrine = $this->get("app.twake_doctrine"); + $groupRepository = $doctrine->getRepository("Twake\Workspaces:Group"); + $company = $groupRepository->find($companyId); + + if(!$company || $company->getIdentityProvider() !== "console"){ + return new Response(["error" => "not a console company"]); + } + + // Check user is connected and part of the requested company + $groupUserRepository = $doctrine->getRepository("Twake\Workspaces:GroupUser"); + $workspaceUserRepository = $doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + $companyUser = $groupUserRepository->findOneBy(Array("group" => $companyId, "user" => $this->getUser()->getId())); + $workspaceUser = $workspaceUserRepository->findOneBy(Array("workspace_id" => $workspaceId, "user_id" => $this->getUser()->getId())); + if(!$companyUser || !$workspaceUser){ + return new Response(["error" => "user not in company or workspace"]); + } + + // Also add the emails as pending on Twake side + $workspaceUserByMailRepository = $doctrine->getRepository("Twake\Workspaces:WorkspaceUserByMail"); + foreach($emails as $mail){ + $this->get("app.workspace_members")->addMemberByMail($workspaceId, $mail, $asExterne, $this->getUser()->getId(), false); + } + + $companyCode = $company->getIdentityProviderId(); + + $header = "Authorization: Basic " . $this->authB64; + + if($role === "member") { + $data = [ + "emails" => $emails, + "inviter" => [ + "name" => $this->getUser()->getFullName(), + "email" => $this->getUser()->getEmail() + ] + ]; + $response = $this->api->post(rtrim($this->endpoint, "/") . "/companies/" . $companyCode . "/users/invitation", json_encode($data), array(CURLOPT_HTTPHEADER => [$header, "Content-Type: application/json"])); + } + else { + $data = [ + "name" => $emails[0], + "email" => $emails[0], + "password" => base64_encode(random_bytes(6)), + "role" => $role + ]; + $response = $this->api->post(rtrim($this->endpoint, "/") . "/companies/" . $companyCode . "/users", json_encode($data), array(CURLOPT_HTTPHEADER => [$header, "Content-Type: application/json"])); + } + + $result = json_decode($response->getContent(), 1); + + return new Response(["data" => $result]); + } + +} diff --git a/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/ApplyUpdates.php b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/ApplyUpdates.php new file mode 100755 index 00000000..9b36b7b2 --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/ApplyUpdates.php @@ -0,0 +1,275 @@ +<?php + +namespace Twake\Users\Controller\Adapters\Console; + +use App\App; +use Twake\Users\Services\PasswordEncoder; +use Twake\Workspaces\Entity\Group; +use Twake\Workspaces\Entity\GroupUser; +use Twake\Workspaces\Entity\ExternalGroupRepository; +use Twake\Upload\Entity\File; + +/** + * This class will do updates in Twake from Twake console + */ +class ApplyUpdates +{ + /** @var App */ + protected $app = null; + + /** @var String */ + protected $endpoint = null; + + public function __construct(App $app) + { + $this->app = $app; + $this->em = $app->getServices()->get("app.twake_doctrine"); + $this->endpoint = $app->getContainer()->getParameter("defaults.auth.console.provider"); + $this->string_cleaner = $app->getServices()->get("app.string_cleaner"); + $this->user_service = $app->getServices()->get("app.user"); + } + + function updateCompany($companyDTO){ + error_log("apply:updateCompany with params: ". json_encode([$companyDTO])); + + $companyConsoleCode = $companyDTO["company"]["details"]["code"]; + + $extRepository = $this->em->getRepository("Twake\Workspaces:ExternalGroupRepository"); + $company_link = $extRepository->findOneBy(Array("service_id" => "console", "external_id" => $companyConsoleCode)); + + $company = null; + if ($company_link) { + $twakeCompanyId = $company_link->getGroupId(); + $companyRepository = $this->em->getRepository("Twake\Workspaces:Group"); + $company = $companyRepository->find($twakeCompanyId); + } + if(!$company) { + //Create company + $company = new Group($companyDTO["company"]["details"]["name"]); + + $this->em->persist($company); + $this->em->flush(); + + $company_link = new ExternalGroupRepository("console", $companyConsoleCode, $company->getId()); + $this->em->persist($company_link); + } + + $company->setName($companyDTO["company"]["details"]["name"]); + $company->setDisplayName($companyDTO["company"]["details"]["name"]); + $company->setIdentityProvider("console"); + $company->setIdentityProviderId($companyConsoleCode); + + $avatar = $userDTO["company"]["details"]["avatar"]; + $picture = $companyDTO["value"] ?: ""; + if($avatar["type"] && $avatar["type"] !== "url"){ + $picture = rtrim($this->endpoint, "/") . "/avatars/" . $avatar["value"]; + } + $company->setLogo($picture); + + // Format is {name: "string", limits: {}} + $company->setPlan($companyDTO["company"]["plan"]); + + // Format is {} + $company->setStats($companyDTO["company"]["stats"]); + + $logo = $companyDTO["company"]["details"]["logo"]; + if ($logo) { + $company->setLogo($logo); + } + + $this->em->persist($company); + $this->em->flush(); + + $this->app->getServices()->get("app.groups")->init($company); + + return $company; + + } + + function removeCompany($companyConsoleCode){ + //Not implemented + error_log("not implemented"); + return false; + } + + /** + * Take a user from api and save it into PHP + */ + function updateUser($userDTO){ + error_log("apply:updateUser with params: ". json_encode([$userDTO])); + + $roles = $userDTO["roles"]; + + $userConsoleId = $userDTO["_id"]; + + $email = $userDTO["email"]; + $username = preg_replace("/ +/", "_", + preg_replace("/[^a-zA-Z0-9]/", "", + trim( + strtolower( + explode("@", $userDTO["email"])[0] + ) + ) + ) + ); + + // Create user if needed + $user = $this->user_service->getUserFromExternalRepository("console", $userConsoleId); + if (!$user) { + //Create user on our side + + //Find allowed username / email + $counter = 1; + $original_username = $username; + $ok = false; + $mailUsedError = false; + $usernameUsedError = false; + do { + $res = $this->user_service->getAvaibleMailPseudo($email, $username); + if ($res !== true) { + if (in_array(-1, $res)) { + //Mail used + $mailUsedError = true; + break; + } + if (in_array(-2, $res)) { + //Username used + $username = $original_username . $counter; + $usernameUsedError = true; + }else{ + $usernameUsedError = false; + $ok = true; + } + }else{ + $usernameUsedError = false; + $ok = true; + } + $counter++; + } while (!$ok && $counter < 1000); + if($mailUsedError || $usernameUsedError){ + error_log("Console user not created because mail exists or username exists:"); + error_log("Username used " . $username . ": " . ( $usernameUsedError ? "true" : "false" ) ); + error_log("Email used " . $email . ": " . ( $mailUsedError ? "true" : "false" ) ); + return false; + } + + $user = new \Twake\Users\Entity\User(); + $user->setSalt(bin2hex(random_bytes(40))); + $encoder = new PasswordEncoder(); + $user->setPassword($encoder->encodePassword(bin2hex(random_bytes(40)), $user->getSalt())); + $user->setUsername($username); + $user->setMailVerified(true); + $user->setEmail($email); + $user->setIdentityProvider("console"); + $user->setIdentityProviderId($userConsoleId); + + $this->em->persist($user); + $this->em->flush(); + + $this->user_service->setUserFromExternalRepository("console", $userConsoleId, $user->getId()); + } + + // Update user names + $user->setEmail($email); + $user->setPhone(""); + $user->setFirstName($userDTO["firstName"] ?: ($userDTO["name"] ?: "")); + $user->setLastName($userDTO["lastName"] ?: ""); + $user->setMailVerified(!!$userDTO["isVerified"]); + $user->setIdentityProvider("console"); + $user->setIdentityProviderId($userConsoleId); + + $user->setLanguage(@$userDTO["preference"]["locale"] ?: "en"); + $user->setTimezone(@$userDTO["preference"]["timeZone"] ?: ""); + + // Update user picture + $avatar = $userDTO["avatar"]; + $picture = $avatar["value"] ?: ""; + if($avatar["type"] && $avatar["type"] !== "url"){ + $picture = rtrim($this->endpoint, "/") . "/avatars/" . $avatar["value"]; + } + $user->setPicture($picture); + + $this->em->persist($user); + $this->em->flush(); + + foreach($roles as $role){ + $companyConsoleCode = $role["targetCode"]; + $level = $role["roleCode"]; + //Double check we created this user in external users repo + if($companyConsoleCode && $this->user_service->getUserFromExternalRepository("console", $userConsoleId)){ + (new PrepareUpdates($this->app))->addUser($userConsoleId, $companyConsoleCode, $userDTO); + } + } + + error_log("Created console user in Twake with success, id: " . $user->getId()); + + return $user; + + } + + /** + * Add or update user in a company, the role has the following format: + * roleCode: "owner" | 'admin' | 'member' | 'guest', + * status: "active", + */ + function addUser($userTwakeEntity, $companyTwakeEntity, $roleDTO){ + error_log("addUser with params: ". json_encode([$userTwakeEntity, $companyTwakeEntity, $roleDTO])); + + if($roleDTO["status"] !== "active"){ + return $this->removeUser($userTwakeEntity, $companyTwakeEntity); + } + + // Add user into the company + + $companyUserRepository = $this->em->getRepository("Twake\Workspaces:GroupUser"); + $companyUserEntity = $companyUserRepository->findOneBy(Array("group" => $companyTwakeEntity, "user" => $userTwakeEntity)); + + if(!$companyUserEntity){ + $companyUserEntity = new GroupUser($companyTwakeEntity, $userTwakeEntity); + } + + $companyUserEntity->setExterne($roleDTO["roleCode"] === "guest"); + $companyUserEntity->setLevel(($roleDTO["roleCode"] === "admin" || $roleDTO["roleCode"] === "owner") ? 3 : 0); + $role = $roleDTO["roleCode"]; + if($role == "owner") $role = "admin"; + $companyUserEntity->setRole($role); + + $this->em->persist($companyUserEntity); + $this->em->flush(); + + // Check if company has any workspace, if not, create a workspace and invite user in it + + $workspacesRepository = $this->em->getRepository("Twake\Workspaces:Workspace"); + $existingWorkspace = $workspacesRepository->findBy(Array("group" => $companyTwakeEntity)); + + if(count($existingWorkspace) < 1){ + $this->app->getServices()->get("app.workspaces")->create($companyTwakeEntity->getDisplayName(), $companyTwakeEntity->getId(), $userTwakeEntity->getId(), true); + }else{ + foreach($existingWorkspace as $workspace){ + if($workspace->getIsDefault() || count($existingWorkspace) == 1){ + //Add user in this workspace + $this->app->getServices()->get("app.workspace_members")->addMember($workspace->getId(), $userTwakeEntity->getId(), false, null); + } + } + } + + $this->app->getServices()->get("app.workspace_members")->autoAddMemberByNewMail($userTwakeEntity->getEmail(), $userTwakeEntity->getId()); + + return true; + + } + + function removeUser($userTwakeEntity, $companyTwakeEntity){ + error_log("removeUser with params: ". json_encode([$userTwakeEntity, $companyTwakeEntity])); + $companyUserRepository = $this->em->getRepository("Twake\Workspaces:GroupUser"); + $companyUserEntity = $companyUserRepository->findOneBy(Array("group" => $companyTwakeEntity, "user" => $userTwakeEntity)); + + if($companyUserEntity){ + $this->em->remove($companyUserEntity); + $this->em->flush(); + } + + return true; + } + +} diff --git a/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/Hooks.php b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/Hooks.php new file mode 100755 index 00000000..69238d83 --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/Hooks.php @@ -0,0 +1,100 @@ +<?php + +namespace Twake\Users\Controller\Adapters\Console; + +use App\App; +use Common\Http\Response; +use Common\Http\Request; + +class Hooks +{ + /** @var App */ + protected $app = null; + + public function __construct(App $app) + { + $this->app = $app; + } + + function handle(Request $request) + { + $sign = $request->request->get("signature"); + $event = [ + "content" => $request->request->get("content"), + "type" => $request->request->get("type"), + "secret_key" => $request->request->get("secret_key") + ]; + + // Check secret + $secret = $this->app->getContainer()->getParameter("defaults.auth.console.secret"); + if ($secret && $secret != $request->query->get("secret_key")) { + return new Response(["error" => "unauthorized"], 401); + } + + // Check signature to ensure request origin + $publicKey = $this->app->getContainer()->getParameter("defaults.auth.console.public_key"); + if ($publicKey) { + $r = openssl_verify(json_encode($event), base64_decode(str_replace(str_split('._-'), str_split('+/='), $sign)), $publicKey, OPENSSL_ALGO_SHA512); + if(!$r){ + return new Response(["error" => "unauthorized"], 401); + } + }else{ + error_log("WARNING: no public key set for console hook!"); + } + + error_log(json_encode($event)); + + switch($event["type"]){ + case "company_user_added": + case "company_user_activated": + case "company_user_updated": + return $this->userAdded($event["content"]); + case "company_user_deactivated": + return $this->userRemoved($event["content"]); + case "user_updated": + return $this->userUpdated($event["content"]); + case "plan_updated": + return $this->planUpdated($event["content"]); + case "company_deleted": + return $this->companyRemoved($event["content"]); + case "company_created": + case "company_updated": + return $this->companyUpdated($event["content"]); + default: + return new Response(["error" => "unimplemented"], 501); + } + } + + function userAdded($data){ + $service = new PrepareUpdates($this->app); + if($data["company"]["code"]) $service->updateCompany($data["company"]["code"]); + return new Response($service->addUser($data["user"]["_id"], $data["company"]["code"] ?: null, $data["user"]) ?: ""); + } + + function userRemoved($data){ + $service = new PrepareUpdates($this->app); + if($data["company"]["code"]) $service->updateCompany($data["company"]["code"]); + return new Response($service->removeUser($data["user"]["_id"], $data["company"]["code"] ?: null) ?: ""); + } + + function userUpdated($data){ + $service = new PrepareUpdates($this->app); + return new Response($service->updateUser($data["user"]["_id"], $data["company"]["code"] ?: null, $data["user"]) ?: ""); + } + + function companyRemoved($data){ + $service = new PrepareUpdates($this->app); + return new Response($service->removeCompany($data["company"]["code"]) ?: ""); + } + + function companyUpdated($data){ + $service = new PrepareUpdates($this->app); + return new Response($service->updateCompany($data["company"]["code"]) ?: ""); + } + + function planUpdated($data){ + $service = new PrepareUpdates($this->app); + return new Response($service->updateCompany($data["company"]["code"]) ?: ""); + } + +} diff --git a/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/PrepareUpdates.php b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/PrepareUpdates.php new file mode 100755 index 00000000..573af3d7 --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/PrepareUpdates.php @@ -0,0 +1,125 @@ +<?php + +namespace Twake\Users\Controller\Adapters\Console; + +use App\App; + +/** + * This class will do updates in Twake from Twake console + */ +class PrepareUpdates +{ + /** @var App */ + protected $app = null; + + /** @var TwakeRestClient */ + protected $api = null; + + /** @var String */ + protected $endpoint = null; + + /** @var String */ + private $authB64 = ""; + + public function __construct(App $app) + { + $this->app = $app; + $this->api = $app->getServices()->get("app.restclient"); + $this->endpoint = $this->app->getContainer()->getParameter("defaults.auth.console.provider"); + $this->authB64 = base64_encode( + $this->app->getContainer()->getParameter("defaults.auth.console.credentials.key") + . ":" + . $this->app->getContainer()->getParameter("defaults.auth.console.credentials.secret")); + } + + function updateCompany($companyCode){ + error_log("updateCompany with params: " . json_encode([$companyCode])); + $header = "Authorization: Basic " . $this->authB64; + $response = $this->api->get(rtrim($this->endpoint, "/") . "/companies/" . $companyCode, array(CURLOPT_HTTPHEADER => [$header])); + $companyDTO = json_decode($response->getContent(), 1); + $result = (new ApplyUpdates($this->app))->updateCompany($companyDTO); + return [ + "success" => !!$result + ]; + } + + function removeCompany($companyCode){ + error_log("removeCompany with params: " . json_encode([$companyCode])); + $result = (new ApplyUpdates($this->app))->removeCompany($companyCode); + return [ + "success" => !!$result + ]; + } + + function updateUser($userId, $companyCode = null, $userDTO = null){ + error_log("updateUser with params: " . json_encode([$userId, $companyCode, $userDTO])); + if(!$userDTO){ + return [ + "success" => false + ]; + } + $result = (new ApplyUpdates($this->app))->updateUser($userDTO); + return [ + "success" => !!$result + ]; + } + + function addUser($userId, $companyCode, $userDTO = null){ + error_log("addUser with params: " . json_encode([$userId, $companyCode, $userDTO])); + + $user = (new Utils($this->app))->getUser($userId); + $company = (new Utils($this->app))->getCompany($companyCode); + + if(!$user){ + $this->updateUser($userId, $companyCode, $userDTO); + $user = (new Utils($this->app))->getUser($userId); + } + if(!$company){ + $this->updateCompany($companyCode); + $company = (new Utils($this->app))->getCompany($companyCode); + } + + if(!$user || !$company){ + return [ + "success" => false + ]; + } + + //Fixme, in the future there should be a better endpoint to get user role in a given company + if(!$userDTO){ + $header = "Authorization: Basic " . $this->authB64; + $response = $this->api->get(rtrim($this->endpoint, "/") . "/users/" . $userId, array(CURLOPT_HTTPHEADER => [$header])); + $userDTO = json_decode($response->getContent(), 1); + } + $companyRole = null; + foreach($userDTO["roles"] as $role){ + if($role["targetCode"] === $companyCode){ + $companyRole = $role; + } + } + + $result = (new ApplyUpdates($this->app))->addUser($user, $company, $companyRole); + return [ + "success" => !!$result + ]; + } + + function removeUser($userId, $companyCode){ + error_log("removeUser with params: " . json_encode([$userId, $companyCode])); + + $user = (new Utils($this->app))->getUser($userId); + $company = (new Utils($this->app))->getCompany($companyCode); + + if(!$user || !$company){ + return [ + "success" => true + ]; + } + + $result = (new ApplyUpdates($this->app))->removeUser($user, $company); + return [ + "success" => !!$result + ]; + } + +} diff --git a/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/Utils.php b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/Utils.php new file mode 100755 index 00000000..290ae457 --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/Utils.php @@ -0,0 +1,49 @@ +<?php + +namespace Twake\Users\Controller\Adapters\Console; + +use App\App; + +/** + * This class will do updates in Twake from Twake console + */ +class Utils +{ + /** @var App */ + protected $app = null; + + public function __construct(App $app) + { + $this->app = $app; + $this->em = $app->getServices()->get("app.twake_doctrine"); + $this->string_cleaner = $app->getServices()->get("app.string_cleaner"); + $this->user_service = $app->getServices()->get("app.user"); + } + + function getCompany($companyConsoleId){ + $extRepository = $this->em->getRepository("Twake\Workspaces:ExternalGroupRepository"); + $company_link = $extRepository->findOneBy(Array("service_id" => "console", "external_id" => $companyConsoleId)); + + $company = null; + if ($company_link) { + $twakeCompanyId = $company_link->getGroupId(); + $companyRepository = $this->em->getRepository("Twake\Workspaces:Group"); + $company = $companyRepository->find($twakeCompanyId); + } + return $company; + } + + function getUser($userConsoleId){ + $extRepository = $this->em->getRepository("Twake\Users:ExternalUserRepository"); + $user_link = $extRepository->findOneBy(Array("service_id" => "console", "external_id" => $userConsoleId)); + + $user = null; + if ($user_link) { + $twakeUserId = $user_link->getUserId(); + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->find($twakeUserId); + } + return $user; + } + +} diff --git a/twake/backend/core/src/Twake/Users/Controller/Adapters/OpenID.php b/twake/backend/core/src/Twake/Users/Controller/Adapters/OpenID.php new file mode 100755 index 00000000..fd1ee589 --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Controller/Adapters/OpenID.php @@ -0,0 +1,143 @@ +<?php + +namespace Twake\Users\Controller\Adapters; + +use Common\BaseController; +use Common\Http\Request; +use Common\Http\Response; +use Twake\Users\Controller\Adapters\OpenID\OpenIDConnectClient; +use Twake\Users\Entity\User; + +class OpenID extends BaseController +{ + + function logoutSuccess(Request $request) + { + try{ + $message = json_decode(urldecode($request->query->get("error_code"))); + }catch(\Exception $err){ + $message = "success"; + } + return $this->closeIframe($message); + } + + function logout(Request $request, $message = null) + { + error_reporting(E_ERROR | E_PARSE); + + $this->get("app.user")->logout($request); + + $logout_parameter = $this->getParameter("defaults.auth.openid.logout_query_parameter_key") ?: "post_logout_redirect_uri"; + $logout_url_suffix = $this->getParameter("defaults.auth.openid.logout_suffix") ?: "/logout"; + + $logout_redirect_url = rtrim($this->getParameter("env.server_name"), "/") . "/ajax/users/openid/logout_success"; + + if($message){ + $logout_redirect_url .= "?error_code=".str_replace('+', '%20', urlencode(json_encode($message))); + } + + $redirect = ""; + if(!$this->getParameter("defaults.auth.openid.disable_logout_redirect")){ + $redirect = "?" . $logout_parameter . "=" . urlencode($logout_redirect_url); + } + + $this->redirect($this->getParameter("defaults.auth.openid.provider_uri") . $logout_url_suffix . $redirect); + } + + function index(Request $request) + { + + if (!$this->getParameter("defaults.auth.openid.use")) { + return new Response(["error" => "OpenID is not enabled on this instance"]); + } + + error_reporting(E_ERROR | E_PARSE); + + $this->get("app.user")->logout($request); + + try { + $oidc = new OpenIDConnectClient( + $this->getParameter("defaults.auth.openid.provider_uri"), + $this->getParameter("defaults.auth.openid.client_id"), + $this->getParameter("defaults.auth.openid.client_secret") + ); + $oidc->setServerKey($this->app->getContainer()->getParameter("jwt.secret")); + + $oidc->providerConfigParam($this->getParameter("defaults.auth.openid.provider_config", [])); + + $oidc->setRedirectURL(rtrim($this->getParameter("env.server_name"), "/") . "/ajax/users/openid"); + + $oidc->addScope(array('openid', 'email', 'profile')); + + try { + $authentificated = $oidc->authenticate([ + "ignore_id_token" => true + ]); + }catch(\Exception $err){ + error_log("Error with Authenticated: ".$err); + $authentificated = false; + } + if ($authentificated) { + + $data = []; + $data["user_id"] = $oidc->requestUserInfo('sub'); //User unique id + $data["nickname"] = $oidc->requestUserInfo('nickname'); //Prefered first name / username + $data["given_name"] = $oidc->requestUserInfo('given_name'); //First name + $data["family_name"] = $oidc->requestUserInfo('family_name'); //Second name + $data["name"] = $oidc->requestUserInfo('name'); //Full name + $data["email"] = $oidc->requestUserInfo('email'); + $data["email_verified"] = $oidc->requestUserInfo('email_verified'); + $data["picture"] = $oidc->requestUserInfo('picture'); //Thumbnail + + if ((empty($data["email_verified"]) || !$data["email_verified"] || empty($data["email"])) && !$this->getParameter("defaults.auth.openid.ignore_mail_verified")) { + return $this->logout($request, ["error" => "Your mail is not verified"]); + } + + if (empty($data["user_id"])) { + return $this->logout($request, ["error" => "An error occurred (no unique id found)"]); + } + + //Generate username, fullname, email, picture from recovered data + $external_id = $data["user_id"]; + $email = $data["email"]; + $picture = $data["picture"]; + $fullname = $data["name"] ?: (($data["given_name"] . " " . $data["family_name"]) ?: $data["nickname"]); + $fullname = explode("@", $fullname)[0]; + $username = preg_replace("/ '/", "_", + preg_replace("/[^a-zA-Z0-9]/", "", + trim( + strtolower( + $data["nickname"] ?: ($fullname ?: explode("@", $data["email"])[0]) + ) + ) + ) + ); + + /** @var User $user */ + $userTokens = $this->get("app.user")->loginFromServiceWithToken("openid", $external_id, $email, $username, $fullname, $picture); + + if ($userTokens) { + return $this->closeIframe("success", $userTokens); + }else{ + return $this->logout($request, ["error" => "No user profile created"]); + } + + }else{ + return $this->logout($request, ["error" => "OIDC auth error"]); + } + + } catch (\Exception $e) { + error_log($e); + $this->logout($request); + } + + return $this->logout($request, ["error" => "An unknown error occurred"]); + + } + + private function closeIframe($message, $userTokens=null) + { + $this->redirect(rtrim($this->getParameter("env.frontend_server_name", $this->getParameter("env.server_name")), "/") . "?external_login=".str_replace('+', '%20', urlencode(json_encode(["provider"=>"openid", "message" => $message, "token" => json_encode($userTokens)])))); + } + +} diff --git a/twake/backend/core/src/Twake/Users/Controller/Adapters/OpenID/OpenIDConnectClient.php b/twake/backend/core/src/Twake/Users/Controller/Adapters/OpenID/OpenIDConnectClient.php new file mode 100755 index 00000000..3e514cd5 --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Controller/Adapters/OpenID/OpenIDConnectClient.php @@ -0,0 +1,1828 @@ +<?php +namespace Twake\Users\Controller\Adapters\OpenID; + +use \Firebase\JWT\JWT; + +/** + * + * JWT signature verification support by Jonathan Reed <jdreed@mit.edu> + * Edited by Romaric Mourgues to make it stateless and compatible with LemonLDAP + * Licensed under the same license as the rest of this file. + * + * phpseclib is required to validate the signatures of some tokens. + * It can be downloaded from: http://phpseclib.sourceforge.net/ + */ + +if (!class_exists('\phpseclib\Crypt\RSA') && !class_exists('Crypt_RSA')) { + user_error('Unable to find phpseclib Crypt/RSA.php. Ensure phpseclib is installed and in include_path before you include this file'); +} + +/** + * A wrapper around base64_decode which decodes Base64URL-encoded data, + * which is not the same alphabet as base64. + * @param string $base64url + * @return bool|string + */ +function base64url_decode($base64url) { + return base64_decode(b64url2b64($base64url)); +} + +/** + * Per RFC4648, "base64 encoding with URL-safe and filename-safe + * alphabet". This just replaces characters 62 and 63. None of the + * reference implementations seem to restore the padding if necessary, + * but we'll do it anyway. + * @param string $base64url + * @return string + */ +function b64url2b64($base64url) { + // "Shouldn't" be necessary, but why not + $padding = strlen($base64url) % 4; + if ($padding > 0) { + $base64url .= str_repeat('=', 4 - $padding); + } + return strtr($base64url, '-_', '+/'); +} + + +/** + * OpenIDConnect Exception Class + */ +class OpenIDConnectClientException extends \Exception +{ + +} + +/** + * Require the CURL and JSON PHP extensions to be installed + */ +if (!function_exists('curl_init')) { + throw new OpenIDConnectClientException('OpenIDConnect needs the CURL PHP extension.'); +} +if (!function_exists('json_decode')) { + throw new OpenIDConnectClientException('OpenIDConnect needs the JSON PHP extension.'); +} + +/** + * + * Please note this class stores nonces by default in $_SESSION['openid_connect_nonce'] + * + */ +class OpenIDConnectClient +{ + + /** + * @var string arbitrary id value + */ + private $clientID; + + /** + * @var string arbitrary name value + */ + private $clientName; + + /** + * @var string arbitrary secret value + */ + private $clientSecret; + + /** + * @var array holds the provider configuration + */ + private $providerConfig = array(); + + /** + * @var string http proxy if necessary + */ + private $httpProxy; + + /** + * @var string full system path to the SSL certificate + */ + private $certPath; + + /** + * @var bool Verify SSL peer on transactions + */ + private $verifyPeer = true; + + /** + * @var bool Verify peer hostname on transactions + */ + private $verifyHost = true; + + /** + * @var string if we acquire an access token it will be stored here + */ + protected $accessToken; + + /** + * @var string if we acquire a refresh token it will be stored here + */ + private $refreshToken; + + /** + * @var string if we acquire an id token it will be stored here + */ + protected $idToken; + + /** + * @var string stores the token response + */ + private $tokenResponse; + + /** + * @var array holds scopes + */ + private $scopes = array(); + + /** + * @var int|null Response code from the server + */ + private $responseCode; + + /** + * @var array holds response types + */ + private $responseTypes = array(); + + /** + * @var array holds a cache of info returned from the user info endpoint + */ + private $userInfo = array(); + + /** + * @var array holds authentication parameters + */ + private $authParams = array(); + + /** + * @var array holds additional registration parameters for example post_logout_redirect_uris + */ + private $registrationParams = array(); + + /** + * @var mixed holds well-known openid server properties + */ + private $wellKnown = false; + + /** + * @var mixed holds well-known opendid configuration parameters, like policy for MS Azure AD B2C User Flow + * @see https://docs.microsoft.com/en-us/azure/active-directory-b2c/user-flow-overview + */ + private $wellKnownConfigParameters = array(); + + /** + * @var int timeout (seconds) + */ + protected $timeOut = 60; + + /** + * @var int leeway (seconds) + */ + private $leeway = 300; + + /** + * @var array holds response types + */ + private $additionalJwks = array(); + + /** + * @var array holds verified jwt claims + */ + protected $verifiedClaims = array(); + + /** + * @var callable validator function for issuer claim + */ + private $issuerValidator; + + /** + * @var bool Allow OAuth 2 implicit flow; see http://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth + */ + private $allowImplicitFlow = false; + /** + * @var string + */ + private $redirectURL; + + protected $enc_type = PHP_QUERY_RFC1738; + + /** + * @var string holds code challenge method for PKCE mode + * @see https://tools.ietf.org/html/rfc7636 + */ + private $codeChallengeMethod = false; + + /** + * @var array holds PKCE supported algorithms + */ + private $pkceAlgs = array('S256' => 'sha256', 'plain' => false); + + /** + * Server key, used to generate stateless OIDC state + */ + private $serverKey = ""; + + public function setServerKey($key){ + $this->serverKey = $key; + } + + private function getServerKey(){ + return $this->serverKey; + } + + /** + * @param $provider_url string optional + * + * @param $client_id string optional + * @param $client_secret string optional + * @param null $issuer + */ + public function __construct($provider_url = null, $client_id = null, $client_secret = null, $issuer = null) { + $this->setProviderURL($provider_url); + if ($issuer === null) { + $this->setIssuer($provider_url); + } else { + $this->setIssuer($issuer); + } + + $this->clientID = $client_id; + $this->clientSecret = $client_secret; + + $this->issuerValidator = function($iss){ + return ($iss === $this->getIssuer() || $iss === $this->getWellKnownIssuer() || $iss === $this->getWellKnownIssuer(true)); + }; + } + + /** + * @param $provider_url + */ + public function setProviderURL($provider_url) { + $this->providerConfig['providerUrl'] = $provider_url; + } + + /** + * @param $issuer + */ + public function setIssuer($issuer) { + $this->providerConfig['issuer'] = $issuer; + } + + /** + * @param $response_types + */ + public function setResponseTypes($response_types) { + $this->responseTypes = array_merge($this->responseTypes, (array)$response_types); + } + + /** + * @return bool + * @throws OpenIDConnectClientException + */ + public function authenticate($options = []) { + + // Do a preemptive check to see if the provider has thrown an error from a previous redirect + if (isset($_REQUEST['error'])) { + $desc = isset($_REQUEST['error_description']) ? ' Description: ' . $_REQUEST['error_description'] : ''; + throw new OpenIDConnectClientException('Error: ' . $_REQUEST['error'] .$desc); + } + + // If we have an authorization code then proceed to request a token + if (isset($_REQUEST['code'])) { + + $code = $_REQUEST['code']; + $token_json = $this->requestTokens($code); + + // Throw an error if the server returns one + if (isset($token_json->error)) { + if (isset($token_json->error_description)) { + throw new OpenIDConnectClientException($token_json->error_description); + } + throw new OpenIDConnectClientException('Got response: ' . $token_json->error); + } + + // Do an OpenID Connect session check + if (!$this->checkState($_REQUEST['state']) && !$options["ignore_state"]) { + throw new OpenIDConnectClientException('Unable to determine state'); + } + + if (!property_exists($token_json, 'id_token')) { + throw new OpenIDConnectClientException('User did not authorize openid scope.'); + } + + $claims = $this->decodeJWT($token_json->id_token, 1); + + // Verify the signature + if ($this->canVerifySignatures()) { + if (!$this->getProviderConfigValue('jwks_uri')) { + throw new OpenIDConnectClientException ('Unable to verify signature due to no jwks_uri being defined'); + } + if (!$this->verifyJWTsignature($token_json->id_token)) { + throw new OpenIDConnectClientException ('Unable to verify signature'); + } + } else { + user_error('Warning: JWT signature verification unavailable.'); + } + + // Save the id token + $this->idToken = $token_json->id_token; + + // Save the access token + $this->accessToken = $token_json->access_token; + + // If this is a valid claim + if ($this->verifyJWTclaims($claims, $token_json->access_token, $options)) { + + // Clean up the session a little + $this->unsetNonce(); + + // Save the full response + $this->tokenResponse = $token_json; + + // Save the verified claims + $this->verifiedClaims = $claims; + + // Save the refresh token, if we got one + if (isset($token_json->refresh_token)) { + $this->refreshToken = $token_json->refresh_token; + } + + // Success! + return true; + + } + + throw new OpenIDConnectClientException ('Unable to verify JWT claims'); + } + + if ($this->allowImplicitFlow && isset($_REQUEST['id_token'])) { + // if we have no code but an id_token use that + $id_token = $_REQUEST['id_token']; + + $accessToken = null; + if (isset($_REQUEST['access_token'])) { + $accessToken = $_REQUEST['access_token']; + } + + // Do an OpenID Connect session check + if ($_REQUEST['state'] !== $this->checkState($_REQUEST['state'])) { + throw new OpenIDConnectClientException('Unable to determine state'); + } + + $claims = $this->decodeJWT($id_token, 1); + + // Verify the signature + if ($this->canVerifySignatures()) { + if (!$this->getProviderConfigValue('jwks_uri')) { + throw new OpenIDConnectClientException ('Unable to verify signature due to no jwks_uri being defined'); + } + if (!$this->verifyJWTsignature($id_token)) { + throw new OpenIDConnectClientException ('Unable to verify signature'); + } + } else { + user_error('Warning: JWT signature verification unavailable.'); + } + + // Save the id token + $this->idToken = $id_token; + + // If this is a valid claim + if ($this->verifyJWTclaims($claims, $accessToken, $options)) { + + // Clean up the session a little + $this->unsetNonce(); + + // Save the verified claims + $this->verifiedClaims = $claims; + + // Save the access token + if ($accessToken) { + $this->accessToken = $accessToken; + } + + // Success! + return true; + + } + + throw new OpenIDConnectClientException ('Unable to verify JWT claims'); + } + + $this->requestAuthorization(); + return false; + + } + + /** + * It calls the end-session endpoint of the OpenID Connect provider to notify the OpenID + * Connect provider that the end-user has logged out of the relying party site + * (the client application). + * + * @param string $accessToken ID token (obtained at login) + * @param string|null $redirect URL to which the RP is requesting that the End-User's User Agent + * be redirected after a logout has been performed. The value MUST have been previously + * registered with the OP. Value can be null. + * + * @throws OpenIDConnectClientException + */ + public function signOut($accessToken, $redirect) { + $signout_endpoint = $this->getProviderConfigValue('end_session_endpoint'); + + $signout_params = null; + if($redirect === null){ + $signout_params = array('id_token_hint' => $accessToken); + } + else { + $signout_params = array( + 'id_token_hint' => $accessToken, + 'post_logout_redirect_uri' => $redirect); + } + + $signout_endpoint .= (strpos($signout_endpoint, '?') === false ? '?' : '&') . http_build_query( $signout_params, null, '&', $this->enc_type); + error_log("redirect user to (signout): ".$signout_endpoint); + + $this->redirect($signout_endpoint); + } + + /** + * @param array $scope - example: openid, given_name, etc... + */ + public function addScope($scope) { + $this->scopes = array_merge($this->scopes, (array)$scope); + } + + /** + * @param array $param - example: prompt=login + */ + public function addAuthParam($param) { + $this->authParams = array_merge($this->authParams, (array)$param); + } + + /** + * @param array $param - example: post_logout_redirect_uris=[http://example.com/successful-logout] + */ + public function addRegistrationParam($param) { + $this->registrationParams = array_merge($this->registrationParams, (array)$param); + } + + /** + * @param $jwk object - example: (object) array('kid' => ..., 'nbf' => ..., 'use' => 'sig', 'kty' => "RSA", 'e' => "", 'n' => "") + */ + protected function addAdditionalJwk($jwk) { + $this->additionalJwks[] = $jwk; + } + + /** + * Get's anything that we need configuration wise including endpoints, and other values + * + * @param string $param + * @param string $default optional + * @throws OpenIDConnectClientException + * @return string + * + */ + protected function getProviderConfigValue($param, $default = null) { + + // If the configuration value is not available, attempt to fetch it from a well known config endpoint + // This is also known as auto "discovery" + if (!isset($this->providerConfig[$param])) { + $this->providerConfig[$param] = $this->getWellKnownConfigValue($param, $default); + } + + return $this->providerConfig[$param]; + } + + /** + * Get's anything that we need configuration wise including endpoints, and other values + * + * @param string $param + * @param string $default optional + * @throws OpenIDConnectClientException + * @return string + * + */ + private function getWellKnownConfigValue($param, $default = null) { + + // If the configuration value is not available, attempt to fetch it from a well known config endpoint + // This is also known as auto "discovery" + if(!$this->wellKnown) { + $well_known_config_url = rtrim($this->getProviderURL(), '/') . '/.well-known/openid-configuration'; + if (count($this->wellKnownConfigParameters) > 0){ + $well_known_config_url .= '?' . http_build_query($this->wellKnownConfigParameters) ; + } + $this->wellKnown = json_decode($this->fetchURL($well_known_config_url)); + } + + $value = false; + if(isset($this->wellKnown->{$param})){ + $value = $this->wellKnown->{$param}; + } + + if ($value) { + return $value; + } + + if (isset($default)) { + // Uses default value if provided + return $default; + } + + throw new OpenIDConnectClientException("The provider {$param} could not be fetched. Make sure your provider has a well known configuration available."); + } + + /** + * Set optionnal parameters for .well-known/openid-configuration + * + * @param string $param + * + */ + public function setWellKnownConfigParameters(array $params = []){ + $this->wellKnownConfigParameters=$params; + } + + + /** + * @param string $url Sets redirect URL for auth flow + */ + public function setRedirectURL ($url) { + if (parse_url($url,PHP_URL_HOST) !== false) { + $this->redirectURL = $url; + } + } + + /** + * Gets the URL of the current page we are on, encodes, and returns it + * + * @return string + */ + public function getRedirectURL() { + + // If the redirect URL has been set then return it. + if (property_exists($this, 'redirectURL') && $this->redirectURL) { + return $this->redirectURL; + } + + // Other-wise return the URL of the current page + + /** + * Thank you + * http://stackoverflow.com/questions/189113/how-do-i-get-current-page-full-url-in-php-on-a-windows-iis-server + */ + + /* + * Compatibility with multiple host headers. + * The problem with SSL over port 80 is resolved and non-SSL over port 443. + * Support of 'ProxyReverse' configurations. + */ + + if (isset($_SERVER['HTTP_UPGRADE_INSECURE_REQUESTS']) && ($_SERVER['HTTP_UPGRADE_INSECURE_REQUESTS'] === '1')) { + $protocol = 'https'; + } else { + $protocol = @$_SERVER['HTTP_X_FORWARDED_PROTO'] + ?: @$_SERVER['REQUEST_SCHEME'] + ?: ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ? 'https' : 'http'); + } + + $port = @intval($_SERVER['HTTP_X_FORWARDED_PORT']) + ?: @intval($_SERVER['SERVER_PORT']) + ?: (($protocol === 'https') ? 443 : 80); + + $host = @explode(':', $_SERVER['HTTP_HOST'])[0] + ?: @$_SERVER['SERVER_NAME'] + ?: @$_SERVER['SERVER_ADDR']; + + $port = (443 === $port) || (80 === $port) ? '' : ':' . $port; + + return sprintf('%s://%s%s/%s', $protocol, $host, $port, @trim(reset(explode('?', $_SERVER['REQUEST_URI'])), '/')); + } + + /** + * Used for arbitrary value generation for nonces and state + * + * @return string + * @throws OpenIDConnectClientException + */ + protected function generateRandString() { + // Error and Exception need to be catched in this order, see https://github.com/paragonie/random_compat/blob/master/README.md + // random_compat polyfill library should be removed if support for PHP versions < 7 is dropped + try { + $a = \bin2hex(\random_bytes(16)); + error_log("random string: ".$a); + return $a; + } catch (Error $e) { + throw new OpenIDConnectClientException('Random token generation failed.'); + } catch (\Exception $e) { + throw new OpenIDConnectClientException('Random token generation failed.'); + }; + } + + /** + * Start Here + * @return void + * @throws OpenIDConnectClientException + */ + private function requestAuthorization() { + + $auth_endpoint = $this->getProviderConfigValue('authorization_endpoint'); + $response_type = 'code'; + + // Generate and store a nonce in the session + // The nonce is an arbitrary value + $nonce = $this->setNonce($this->generateRandString()); + + // State essentially acts as a session key for OIDC + $state = $this->genState(); + + $auth_params = array_merge($this->authParams, array( + 'response_type' => $response_type, + 'redirect_uri' => $this->getRedirectURL(), + 'client_id' => $this->clientID, + 'nonce' => $nonce, + 'state' => $state, + 'scope' => 'openid' + )); + + // If the client has been registered with additional scopes + if (count($this->scopes) > 0) { + $auth_params = array_merge($auth_params, array('scope' => implode(' ', array_merge($this->scopes, array('openid'))))); + } + + // If the client has been registered with additional response types + if (count($this->responseTypes) > 0) { + $auth_params = array_merge($auth_params, array('response_type' => implode(' ', $this->responseTypes))); + } + + // If the client supports Proof Key for Code Exchange (PKCE) + if (!empty($this->getCodeChallengeMethod()) && in_array($this->getCodeChallengeMethod(), $this->getProviderConfigValue('code_challenge_methods_supported'))) { + $codeVerifier = bin2hex(random_bytes(64)); + $this->setCodeVerifier($codeVerifier); + if (!empty($this->pkceAlgs[$this->getCodeChallengeMethod()])) { + $codeChallenge = rtrim(strtr(base64_encode(hash($this->pkceAlgs[$this->getCodeChallengeMethod()], $codeVerifier, true)), '+/', '-_'), '='); + } else { + $codeChallenge = $codeVerifier; + } + $auth_params = array_merge($auth_params, array( + 'code_challenge' => $codeChallenge, + 'code_challenge_method' => $this->getCodeChallengeMethod() + )); + } + + $auth_endpoint .= (strpos($auth_endpoint, '?') === false ? '?' : '&') . http_build_query($auth_params, null, '&', $this->enc_type); + error_log("redirect user to: ".$auth_endpoint); + + $this->commitSession(); + $this->redirect($auth_endpoint); + } + + /** + * Requests a client credentials token + * + * @throws OpenIDConnectClientException + */ + public function requestClientCredentialsToken() { + $token_endpoint = $this->getProviderConfigValue('token_endpoint'); + + $headers = []; + + $grant_type = 'client_credentials'; + + $post_data = array( + 'grant_type' => $grant_type, + 'client_id' => $this->clientID, + 'client_secret' => $this->clientSecret, + 'scope' => implode(' ', $this->scopes) + ); + + // Convert token params to string format + $post_params = http_build_query($post_data, null, '&', $this->enc_type); + + return json_decode($this->fetchURL($token_endpoint, $post_params, $headers)); + } + + + /** + * Requests a resource owner token + * (Defined in https://tools.ietf.org/html/rfc6749#section-4.3) + * + * @param boolean $bClientAuth Indicates that the Client ID and Secret be used for client authentication + * @return mixed + * @throws OpenIDConnectClientException + */ + public function requestResourceOwnerToken($bClientAuth = FALSE) { + $token_endpoint = $this->getProviderConfigValue('token_endpoint'); + + $headers = []; + + $grant_type = 'password'; + + $post_data = array( + 'grant_type' => $grant_type, + 'username' => $this->authParams['username'], + 'password' => $this->authParams['password'], + 'scope' => implode(' ', $this->scopes) + ); + + //For client authentication include the client values + if($bClientAuth) { + $post_data['client_id'] = $this->clientID; + $post_data['client_secret'] = $this->clientSecret; + } + + // Convert token params to string format + $post_params = http_build_query($post_data, null, '&', $this->enc_type); + + return json_decode($this->fetchURL($token_endpoint, $post_params, $headers)); + } + + + /** + * Requests ID and Access tokens + * + * @param string $code + * @return mixed + * @throws OpenIDConnectClientException + */ + protected function requestTokens($code) { + $token_endpoint = $this->getProviderConfigValue('token_endpoint'); + $token_endpoint_auth_methods_supported = $this->getProviderConfigValue('token_endpoint_auth_methods_supported', ['client_secret_basic']); + + $headers = []; + + $grant_type = 'authorization_code'; + + $token_params = array( + 'grant_type' => $grant_type, + 'code' => $code, + 'redirect_uri' => $this->getRedirectURL(), + 'client_id' => $this->clientID, + 'client_secret' => $this->clientSecret + ); + + # Consider Basic authentication if provider config is set this way + if (in_array('client_secret_basic', $token_endpoint_auth_methods_supported, true)) { + $headers = ['Authorization: Basic ' . base64_encode(urlencode($this->clientID) . ':' . urlencode($this->clientSecret))]; + unset($token_params['client_secret']); + unset($token_params['client_id']); + } + + if (!empty($this->getCodeChallengeMethod()) && !empty($this->getCodeVerifier())) { + $headers = []; + unset($token_params['client_secret']); + $token_params = array_merge($token_params, array( + 'client_id' => $this->clientID, + 'code_verifier' => $this->getCodeVerifier() + )); + } + + // Convert token params to string format + $token_params = http_build_query($token_params, null, '&', $this->enc_type); + + $this->tokenResponse = json_decode($this->fetchURL($token_endpoint, $token_params, $headers)); + + return $this->tokenResponse; + } + + /** + * Requests Access token with refresh token + * + * @param string $refresh_token + * @return mixed + * @throws OpenIDConnectClientException + */ + public function refreshToken($refresh_token) { + $token_endpoint = $this->getProviderConfigValue('token_endpoint'); + + $grant_type = 'refresh_token'; + + $token_params = array( + 'grant_type' => $grant_type, + 'refresh_token' => $refresh_token, + 'client_id' => $this->clientID, + 'client_secret' => $this->clientSecret, + ); + + // Convert token params to string format + $token_params = http_build_query($token_params, null, '&', $this->enc_type); + + $json = json_decode($this->fetchURL($token_endpoint, $token_params)); + + if (isset($json->access_token)) { + $this->accessToken = $json->access_token; + } + + if (isset($json->refresh_token)) { + $this->refreshToken = $json->refresh_token; + } + + return $json; + } + + /** + * @param array $keys + * @param array $header + * @throws OpenIDConnectClientException + * @return object + */ + private function get_key_for_header($keys, $header) { + foreach ($keys as $key) { + if ($key->kty === 'RSA') { + if (!isset($header->kid) || $key->kid === $header->kid) { + return $key; + } + } else { + if (isset($key->alg) && $key->alg === $header->alg && $key->kid === $header->kid) { + return $key; + } + } + } + if ($this->additionalJwks) { + foreach ($this->additionalJwks as $key) { + if ($key->kty === 'RSA') { + if (!isset($header->kid) || $key->kid === $header->kid) { + return $key; + } + } else { + if (isset($key->alg) && $key->alg === $header->alg && $key->kid === $header->kid) { + return $key; + } + } + } + } + if (isset($header->kid)) { + throw new OpenIDConnectClientException('Unable to find a key for (algorithm, kid):' . $header->alg . ', ' . $header->kid . ')'); + } + + throw new OpenIDConnectClientException('Unable to find a key for RSA'); + } + + + /** + * @param string $hashtype + * @param object $key + * @param $payload + * @param $signature + * @param $signatureType + * @return bool + * @throws OpenIDConnectClientException + */ + private function verifyRSAJWTsignature($hashtype, $key, $payload, $signature, $signatureType) { + if (!class_exists('\phpseclib\Crypt\RSA') && !class_exists('Crypt_RSA')) { + throw new OpenIDConnectClientException('Crypt_RSA support unavailable.'); + } + if (!(property_exists($key, 'n') && property_exists($key, 'e'))) { + throw new OpenIDConnectClientException('Malformed key object'); + } + + /* We already have base64url-encoded data, so re-encode it as + regular base64 and use the XML key format for simplicity. + */ + $public_key_xml = "<RSAKeyValue>\r\n". + ' <Modulus>' . b64url2b64($key->n) . "</Modulus>\r\n" . + ' <Exponent>' . b64url2b64($key->e) . "</Exponent>\r\n" . + '</RSAKeyValue>'; + if(class_exists('Crypt_RSA', false)) { + $rsa = new Crypt_RSA(); + $rsa->setHash($hashtype); + if ($signatureType === 'PSS') { + $rsa->setMGFHash($hashtype); + } + $rsa->loadKey($public_key_xml, Crypt_RSA::PUBLIC_FORMAT_XML); + $rsa->signatureMode = $signatureType === 'PSS' ? Crypt_RSA::SIGNATURE_PSS : Crypt_RSA::SIGNATURE_PKCS1; + } else { + $rsa = new \phpseclib\Crypt\RSA(); + $rsa->setHash($hashtype); + if ($signatureType === 'PSS') { + $rsa->setMGFHash($hashtype); + } + $rsa->loadKey($public_key_xml, \phpseclib\Crypt\RSA::PUBLIC_FORMAT_XML); + $rsa->signatureMode = $signatureType === 'PSS' ? \phpseclib\Crypt\RSA::SIGNATURE_PSS : \phpseclib\Crypt\RSA::SIGNATURE_PKCS1; + } + return $rsa->verify($payload, $signature); + } + + /** + * @param string $hashtype + * @param object $key + * @param $payload + * @param $signature + * @return bool + * @throws OpenIDConnectClientException + */ + private function verifyHMACJWTsignature($hashtype, $key, $payload, $signature) + { + if (!function_exists('hash_hmac')) { + throw new OpenIDConnectClientException('hash_hmac support unavailable.'); + } + + $expected=hash_hmac($hashtype, $payload, $key, true); + + if (function_exists('hash_equals')) { + return hash_equals($signature, $expected); + } + + return self::hashEquals($signature, $expected); + } + + /** + * @param string $jwt encoded JWT + * @throws OpenIDConnectClientException + * @return bool + */ + public function verifyJWTsignature($jwt) { + if (!\is_string($jwt)) { + throw new OpenIDConnectClientException('Error token is not a string'); + } + $parts = explode('.', $jwt); + if (!isset($parts[0])) { + throw new OpenIDConnectClientException('Error missing part 0 in token'); + } + $signature = base64url_decode(array_pop($parts)); + if (false === $signature || '' === $signature) { + throw new OpenIDConnectClientException('Error decoding signature from token'); + } + $header = json_decode(base64url_decode($parts[0])); + if (null === $header || !\is_object($header)) { + throw new OpenIDConnectClientException('Error decoding JSON from token header'); + } + $payload = implode('.', $parts); + $jwks = json_decode($this->fetchURL($this->getProviderConfigValue('jwks_uri'))); + if ($jwks === NULL) { + throw new OpenIDConnectClientException('Error decoding JSON from jwks_uri'); + } + if (!isset($header->alg)) { + throw new OpenIDConnectClientException('Error missing signature type in token header'); + } + switch ($header->alg) { + case 'RS256': + case 'PS256': + case 'RS384': + case 'RS512': + $hashtype = 'sha' . substr($header->alg, 2); + $signatureType = $header->alg === 'PS256' ? 'PSS' : ''; + + $verified = $this->verifyRSAJWTsignature($hashtype, + $this->get_key_for_header($jwks->keys, $header), + $payload, $signature, $signatureType); + break; + case 'HS256': + case 'HS512': + case 'HS384': + $hashtype = 'SHA' . substr($header->alg, 2); + $verified = $this->verifyHMACJWTsignature($hashtype, $this->getClientSecret(), $payload, $signature); + break; + case 'none': + $verified = true; + break; + default: + throw new OpenIDConnectClientException('No support for signature type: ' . $header->alg); + } + return $verified; + } + + /** + * @param object $claims + * @param string|null $accessToken + * @return bool + */ + protected function verifyJWTclaims($claims, $accessToken = null, $options = []) { + if(isset($claims->at_hash) && isset($accessToken)){ + if(isset($this->getIdTokenHeader()->alg) && $this->getIdTokenHeader()->alg !== 'none'){ + $bit = substr($this->getIdTokenHeader()->alg, 2, 3); + }else{ + // TODO: Error case. throw exception??? + $bit = '256'; + } + $len = ((int)$bit)/16; + $expected_at_hash = $this->urlEncode(substr(hash('sha'.$bit, $accessToken, true), 0, $len)); + } + return (($this->issuerValidator->__invoke($claims->iss)) + && (($claims->aud === $this->clientID) || in_array($this->clientID, $claims->aud, true)) + && ($claims->nonce === $this->getNonce() || $options["ignore_nonce"]) + && ( !isset($claims->exp) || ((gettype($claims->exp) === 'integer') && ($claims->exp >= time() - $this->leeway))) + && ( !isset($claims->nbf) || ((gettype($claims->nbf) === 'integer') && ($claims->nbf <= time() + $this->leeway))) + && ( !isset($claims->at_hash) || $claims->at_hash === $expected_at_hash ) + ); + } + + /** + * @param string $str + * @return string + */ + protected function urlEncode($str) { + $enc = base64_encode($str); + $enc = rtrim($enc, '='); + $enc = strtr($enc, '+/', '-_'); + return $enc; + } + + /** + * @param string $jwt encoded JWT + * @param int $section the section we would like to decode + * @return object + */ + protected function decodeJWT($jwt, $section = 0) { + + $parts = explode('.', $jwt); + return json_decode(base64url_decode($parts[$section])); + } + + /** + * + * @param string|null $attribute optional + * + * Attribute Type Description + * user_id string REQUIRED Identifier for the End-User at the Issuer. + * name string End-User's full name in displayable form including all name parts, ordered according to End-User's locale and preferences. + * given_name string Given name or first name of the End-User. + * family_name string Surname or last name of the End-User. + * middle_name string Middle name of the End-User. + * nickname string Casual name of the End-User that may or may not be the same as the given_name. For instance, a nickname value of Mike might be returned alongside a given_name value of Michael. + * profile string URL of End-User's profile page. + * picture string URL of the End-User's profile picture. + * website string URL of End-User's web page or blog. + * email string The End-User's preferred e-mail address. + * verified boolean True if the End-User's e-mail address has been verified; otherwise false. + * gender string The End-User's gender: Values defined by this specification are female and male. Other values MAY be used when neither of the defined values are applicable. + * birthday string The End-User's birthday, represented as a date string in MM/DD/YYYY format. The year MAY be 0000, indicating that it is omitted. + * zoneinfo string String from zoneinfo [zoneinfo] time zone database. For example, Europe/Paris or America/Los_Angeles. + * locale string The End-User's locale, represented as a BCP47 [RFC5646] language tag. This is typically an ISO 639-1 Alpha-2 [ISO639‑1] language code in lowercase and an ISO 3166-1 Alpha-2 [ISO3166‑1] country code in uppercase, separated by a dash. For example, en-US or fr-CA. As a compatibility note, some implementations have used an underscore as the separator rather than a dash, for example, en_US; Implementations MAY choose to accept this locale syntax as well. + * phone_number string The End-User's preferred telephone number. E.164 [E.164] is RECOMMENDED as the format of this Claim. For example, +1 (425) 555-1212 or +56 (2) 687 2400. + * address JSON object The End-User's preferred address. The value of the address member is a JSON [RFC4627] structure containing some or all of the members defined in Section 2.4.2.1. + * updated_time string Time the End-User's information was last updated, represented as a RFC 3339 [RFC3339] datetime. For example, 2011-01-03T23:58:42+0000. + * + * @return mixed + * + * @throws OpenIDConnectClientException + */ + public function requestUserInfo($attribute = null) { + + $user_info_endpoint = $this->getProviderConfigValue('userinfo_endpoint'); + $schema = 'openid'; + + $user_info_endpoint .= '?schema=' . $schema; + + //The accessToken has to be sent in the Authorization header. + // Accept json to indicate response type + $headers = ["Authorization: Bearer {$this->accessToken}", + 'Accept: application/json']; + + $user_json = json_decode($this->fetchURL($user_info_endpoint,null,$headers)); + if ($this->getResponseCode() <> 200) { + throw new OpenIDConnectClientException('The communication to retrieve user data has failed with status code '.$this->getResponseCode()); + } + $this->userInfo = $user_json; + + if($attribute === null) { + return $this->userInfo; + } + + if (property_exists($this->userInfo, $attribute)) { + return $this->userInfo->$attribute; + } + + return null; + } + + /** + * + * @param string|null $attribute optional + * + * Attribute Type Description + * exp int Expires at + * nbf int Not before + * ver string Version + * iss string Issuer + * sub string Subject + * aud string Audience + * nonce string nonce + * iat int Issued At + * auth_time int Authenatication time + * oid string Object id + * + * @return mixed + * + */ + public function getVerifiedClaims($attribute = null) { + + if($attribute === null) { + return $this->verifiedClaims; + } + + if (property_exists($this->verifiedClaims, $attribute)) { + return $this->verifiedClaims->$attribute; + } + + return null; + } + + /** + * @param string $url + * @param string | null $post_body string If this is set the post type will be POST + * @param array $headers Extra headers to be send with the request. Format as 'NameHeader: ValueHeader' + * @throws OpenIDConnectClientException + * @return mixed + */ + protected function fetchURL($url, $post_body = null, $headers = array()) { + + // OK cool - then let's create a new cURL resource handle + $ch = curl_init(); + + // Determine whether this is a GET or POST + if ($post_body !== null) { + // curl_setopt($ch, CURLOPT_POST, 1); + // Alows to keep the POST method even after redirect + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); + curl_setopt($ch, CURLOPT_POSTFIELDS, $post_body); + + // Default content type is form encoded + $content_type = 'application/x-www-form-urlencoded'; + + // Determine if this is a JSON payload and add the appropriate content type + if (is_object(json_decode($post_body))) { + $content_type = 'application/json'; + } + + // Add POST-specific headers + $headers[] = "Content-Type: {$content_type}"; + + } + + // If we set some headers include them + if(count($headers) > 0) { + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + } + + // Set URL to download + curl_setopt($ch, CURLOPT_URL, $url); + + if (isset($this->httpProxy)) { + curl_setopt($ch, CURLOPT_PROXY, $this->httpProxy); + } + + // Include header in result? (0 = yes, 1 = no) + curl_setopt($ch, CURLOPT_HEADER, 0); + + // Allows to follow redirect + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + + /** + * Set cert + * Otherwise ignore SSL peer verification + */ + if (isset($this->certPath)) { + curl_setopt($ch, CURLOPT_CAINFO, $this->certPath); + } + + if($this->verifyHost) { + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); + } else { + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + } + + if($this->verifyPeer) { + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); + } else { + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + } + + // Should cURL return or print out the data? (true = return, false = print) + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + // Timeout in seconds + curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeOut); + + // Download the given URL, and return output + $output = curl_exec($ch); + + // HTTP Response code from server may be required from subclass + $info = curl_getinfo($ch); + $this->responseCode = $info['http_code']; + + if ($output === false) { + throw new OpenIDConnectClientException('Curl error: (' . curl_errno($ch) . ') ' . curl_error($ch)); + } + + // Close the cURL resource, and free system resources + curl_close($ch); + + return $output; + } + + /** + * @param bool $appendSlash + * @return string + * @throws OpenIDConnectClientException + */ + public function getWellKnownIssuer($appendSlash = false) { + + return $this->getWellKnownConfigValue('issuer') . ($appendSlash ? '/' : ''); + } + + /** + * @return string + * @throws OpenIDConnectClientException + */ + public function getIssuer() { + + if (!isset($this->providerConfig['issuer'])) { + throw new OpenIDConnectClientException('The issuer has not been set'); + } + + return $this->providerConfig['issuer']; + } + + /** + * @return mixed + * @throws OpenIDConnectClientException + */ + public function getProviderURL() { + if (!isset($this->providerConfig['providerUrl'])) { + throw new OpenIDConnectClientException('The provider URL has not been set'); + } + + return $this->providerConfig['providerUrl']; + } + + /** + * @param string $url + */ + public function redirect($url) { + header('Location: ' . $url); + exit; + } + + /** + * @param string $httpProxy + */ + public function setHttpProxy($httpProxy) { + $this->httpProxy = $httpProxy; + } + + /** + * @param string $certPath + */ + public function setCertPath($certPath) { + $this->certPath = $certPath; + } + + /** + * @return string|null + */ + public function getCertPath() + { + return $this->certPath; + } + + /** + * @param bool $verifyPeer + */ + public function setVerifyPeer($verifyPeer) { + $this->verifyPeer = $verifyPeer; + } + + /** + * @param bool $verifyHost + */ + public function setVerifyHost($verifyHost) { + $this->verifyHost = $verifyHost; + } + + /** + * @return bool + */ + public function getVerifyHost() + { + return $this->verifyHost; + } + + /** + * @return bool + */ + public function getVerifyPeer() + { + return $this->verifyPeer; + } + + /** + * Use this for custom issuer validation + * The given function should accept the issuer string from the JWT claim as the only argument + * and return true if the issuer is valid, otherwise return false + * + * @param callable $issuerValidator + */ + public function setIssuerValidator($issuerValidator){ + $this->issuerValidator = $issuerValidator; + } + + /** + * @param bool $allowImplicitFlow + */ + public function setAllowImplicitFlow($allowImplicitFlow) { + $this->allowImplicitFlow = $allowImplicitFlow; + } + + /** + * @return bool + */ + public function getAllowImplicitFlow() + { + return $this->allowImplicitFlow; + } + + /** + * + * Use this to alter a provider's endpoints and other attributes + * + * @param array $array + * simple key => value + */ + public function providerConfigParam($array) { + $this->providerConfig = array_merge($this->providerConfig, $array); + } + + /** + * @param string $clientSecret + */ + public function setClientSecret($clientSecret) { + $this->clientSecret = $clientSecret; + } + + /** + * @param string $clientID + */ + public function setClientID($clientID) { + $this->clientID = $clientID; + } + + + /** + * Dynamic registration + * + * @throws OpenIDConnectClientException + */ + public function register() { + + $registration_endpoint = $this->getProviderConfigValue('registration_endpoint'); + + $send_object = (object ) array_merge($this->registrationParams, array( + 'redirect_uris' => array($this->getRedirectURL()), + 'client_name' => $this->getClientName() + )); + + $response = $this->fetchURL($registration_endpoint, json_encode($send_object)); + + $json_response = json_decode($response); + + // Throw some errors if we encounter them + if ($json_response === false) { + throw new OpenIDConnectClientException('Error registering: JSON response received from the server was invalid.'); + } + + if (isset($json_response->{'error_description'})) { + throw new OpenIDConnectClientException($json_response->{'error_description'}); + } + + $this->setClientID($json_response->{'client_id'}); + + // The OpenID Connect Dynamic registration protocol makes the client secret optional + // and provides a registration access token and URI endpoint if it is not present + if (isset($json_response->{'client_secret'})) { + $this->setClientSecret($json_response->{'client_secret'}); + } else { + throw new OpenIDConnectClientException('Error registering: + Please contact the OpenID Connect provider and obtain a Client ID and Secret directly from them'); + } + + } + + /** + * Introspect a given token - either access token or refresh token. + * @see https://tools.ietf.org/html/rfc7662 + * + * @param string $token + * @param string $token_type_hint + * @param string|null $clientId + * @param string|null $clientSecret + * @return mixed + * @throws OpenIDConnectClientException + */ + public function introspectToken($token, $token_type_hint = '', $clientId = null, $clientSecret = null) { + $introspection_endpoint = $this->getProviderConfigValue('introspection_endpoint'); + + $post_data = array( + 'token' => $token, + ); + if ($token_type_hint) { + $post_data['token_type_hint'] = $token_type_hint; + } + $clientId = $clientId !== null ? $clientId : $this->clientID; + $clientSecret = $clientSecret !== null ? $clientSecret : $this->clientSecret; + + // Convert token params to string format + $post_params = http_build_query($post_data, null, '&'); + $headers = ['Authorization: Basic ' . base64_encode(urlencode($clientId) . ':' . urlencode($clientSecret)), + 'Accept: application/json']; + + return json_decode($this->fetchURL($introspection_endpoint, $post_params, $headers)); + } + + /** + * Revoke a given token - either access token or refresh token. + * @see https://tools.ietf.org/html/rfc7009 + * + * @param string $token + * @param string $token_type_hint + * @param string|null $clientId + * @param string|null $clientSecret + * @return mixed + * @throws OpenIDConnectClientException + */ + public function revokeToken($token, $token_type_hint = '', $clientId = null, $clientSecret = null) { + $revocation_endpoint = $this->getProviderConfigValue('revocation_endpoint'); + + $post_data = array( + 'token' => $token, + ); + if ($token_type_hint) { + $post_data['token_type_hint'] = $token_type_hint; + } + $clientId = $clientId !== null ? $clientId : $this->clientID; + $clientSecret = $clientSecret !== null ? $clientSecret : $this->clientSecret; + + // Convert token params to string format + $post_params = http_build_query($post_data, null, '&'); + $headers = ['Authorization: Basic ' . base64_encode(urlencode($clientId) . ':' . urlencode($clientSecret)), + 'Accept: application/json']; + + return json_decode($this->fetchURL($revocation_endpoint, $post_params, $headers)); + } + + /** + * @return string + */ + public function getClientName() { + return $this->clientName; + } + + /** + * @param string $clientName + */ + public function setClientName($clientName) { + $this->clientName = $clientName; + } + + /** + * @return string + */ + public function getClientID() { + return $this->clientID; + } + + /** + * @return string + */ + public function getClientSecret() { + return $this->clientSecret; + } + + /** + * @return bool + */ + public function canVerifySignatures() { + return class_exists('\phpseclib\Crypt\RSA') || class_exists('Crypt_RSA'); + } + + /** + * Set the access token. + * + * May be required for subclasses of this Client. + * + * @param string $accessToken + * @return void + */ + public function setAccessToken($accessToken) { + $this->accessToken = $accessToken; + } + + /** + * @return string + */ + public function getAccessToken() { + return $this->accessToken; + } + + /** + * @return string + */ + public function getRefreshToken() { + return $this->refreshToken; + } + + /** + * @return string + */ + public function getIdToken() { + return $this->idToken; + } + + /** + * @return object + */ + public function getAccessTokenHeader() { + return $this->decodeJWT($this->accessToken); + } + + /** + * @return object + */ + public function getAccessTokenPayload() { + return $this->decodeJWT($this->accessToken, 1); + } + + /** + * @return object + */ + public function getIdTokenHeader() { + return $this->decodeJWT($this->idToken); + } + + /** + * @return object + */ + public function getIdTokenPayload() { + return $this->decodeJWT($this->idToken, 1); + } + + /** + * @return string + */ + public function getTokenResponse() { + return $this->tokenResponse; + } + + /** + * Stores nonce + * + * @param string $nonce + * @return string + */ + protected function setNonce($nonce) { + $this->setSessionKey('openid_connect_nonce', $nonce); + return $nonce; + } + + /** + * Get stored nonce + * + * @return string + */ + protected function getNonce() { + return $this->getSessionKey('openid_connect_nonce'); + } + + /** + * Cleanup nonce + * + * @return void + */ + protected function unsetNonce() { + $this->unsetSessionKey('openid_connect_nonce'); + } + + /** + * Stores $state + * + * @param string $state + * @return string + */ + protected function genState() { + //Generate a state using jwt + $payload = [ + "token" => $this->generateRandString(), + "exp" => date("U") + 5 * 60 + ]; + + $key = $this->getServerKey(); + $jwt = JWT::encode($payload, $key); + + return $jwt; + } + + /** + * Get stored state + * + * @return string + */ + protected function checkState($state = "") { + $key = $this->getServerKey(); + + try{ + //Check state is valid and non expired + $jwt = JWT::decode($state, $key, array('HS256')); + + if($jwt->exp > date("U")){ + return true; + } + }catch(\Exception $e){} + + return false; + } + + /** + * Stores $codeVerifier + * + * @param string $codeVerifier + * @return string + */ + protected function setCodeVerifier($codeVerifier) { + $this->setSessionKey('openid_connect_code_verifier', $codeVerifier); + return $codeVerifier; + } + + /** + * Get stored codeVerifier + * + * @return string + */ + protected function getCodeVerifier() { + return $this->getSessionKey('openid_connect_code_verifier'); + } + + /** + * Cleanup state + * + * @return void + */ + protected function unsetCodeVerifier() { + $this->unsetSessionKey('openid_connect_code_verifier'); + } + + /** + * Get the response code from last action/curl request. + * + * @return int + */ + public function getResponseCode() + { + return $this->responseCode; + } + + /** + * Set timeout (seconds) + * + * @param int $timeout + */ + public function setTimeout($timeout) + { + $this->timeOut = $timeout; + } + + /** + * @return int + */ + public function getTimeout() + { + return $this->timeOut; + } + + /** + * Safely calculate length of binary string + * @param string $str + * @return int + */ + private static function safeLength($str) + { + if (function_exists('mb_strlen')) { + return mb_strlen($str, '8bit'); + } + return strlen($str); + } + + /** + * Where has_equals is not available, this provides a timing-attack safe string comparison + * @param string $str1 + * @param string $str2 + * @return bool + */ + private static function hashEquals($str1, $str2) + { + $len1=static::safeLength($str1); + $len2=static::safeLength($str2); + + //compare strings without any early abort... + $len = min($len1, $len2); + $status = 0; + for ($i = 0; $i < $len; $i++) { + $status |= (ord($str1[$i]) ^ ord($str2[$i])); + } + //if strings were different lengths, we fail + $status |= ($len1 ^ $len2); + return ($status === 0); + } + + /** + * Use session to manage a nonce + */ + protected function startSession() { + if (!isset($_SESSION)) { + @session_start(); + } + } + + protected function commitSession() { + $this->startSession(); + + session_write_close(); + } + + protected function getSessionKey($key) { + $this->startSession(); + + return $_SESSION[$key]; + } + + protected function setSessionKey($key, $value) { + $this->startSession(); + + $_SESSION[$key] = $value; + } + + protected function unsetSessionKey($key) { + $this->startSession(); + + unset($_SESSION[$key]); + } + + public function setUrlEncoding($curEncoding) + { + switch ($curEncoding) + { + case PHP_QUERY_RFC1738: + $this->enc_type = PHP_QUERY_RFC1738; + break; + + case PHP_QUERY_RFC3986: + $this->enc_type = PHP_QUERY_RFC3986; + break; + + default: + break; + } + + } + + /** + * @return array + */ + public function getScopes() + { + return $this->scopes; + } + + /** + * @return array + */ + public function getResponseTypes() + { + return $this->responseTypes; + } + + /** + * @return array + */ + public function getAuthParams() + { + return $this->authParams; + } + + /** + * @return callable + */ + public function getIssuerValidator() + { + return $this->issuerValidator; + } + + /** + * @return int + */ + public function getLeeway() + { + return $this->leeway; + } + + /** + * @return string + */ + public function getCodeChallengeMethod() { + return $this->codeChallengeMethod; + } + + /** + * @param string $codeChallengeMethod + */ + public function setCodeChallengeMethod($codeChallengeMethod) { + $this->codeChallengeMethod = $codeChallengeMethod; + } +} diff --git a/twake/backend/core/src/Twake/Users/Controller/Users.php b/twake/backend/core/src/Twake/Users/Controller/Users.php new file mode 100755 index 00000000..e3323015 --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Controller/Users.php @@ -0,0 +1,68 @@ +<?php + + +namespace Twake\Users\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class Users extends BaseController +{ + + public function search(Request $request) + { + + $options = $request->request->get("query", $request->request->get("options", Array())); + + if (is_string($options)) { + $options = Array("name" => $options); + } + + $globalresult = $this->get("app.users")->search($options); + + $users = []; + foreach($globalresult["users"] as $obj){ + $users[] = $this->get("app.users")->completeUserWithCompanies($obj, $this->getUser()); + } + $globalresult["users"] = $users; + + $data = Array("data" => $globalresult); + + return new Response($data); + + } + + public function getById(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + $id = $request->request->get("id"); + if(!\is_array($id)){ + $user = $this->get("app.users")->getById($id); + }else{ + $user = []; + foreach($id as $singleId){ + $obj = $this->get("app.users")->getById($singleId); + if($obj){ + $obj = $this->get("app.users")->completeUserWithCompanies($obj, $this->getUser()); + } + $user[] = $obj; + } + } + + if ($user) { + $data["data"] = $user; + } else { + $data["errors"][] = "user_was_not_found"; + } + + return new Response($data); + + } + +} diff --git a/twake/backend/core/src/Twake/Users/Controller/UsersAccount.php b/twake/backend/core/src/Twake/Users/Controller/UsersAccount.php new file mode 100755 index 00000000..bec249db --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Controller/UsersAccount.php @@ -0,0 +1,400 @@ +<?php + + +namespace Twake\Users\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class UsersAccount extends BaseController +{ + + public function setLanguage(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + if ($this->getUser() && !is_string($this->getUser())) { + + $language = $request->request->get("language", ""); + $this->get("app.user")->updateLanguage($this->getUser()->getId(), $language); + + } else { + $data["errors"][] = "unknown"; + } + + return new Response($data); + + } + + public function getNotificationPreferences(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + if ($this->getUser() && !is_string($this->getUser())) { + + $data["data"] = $this->get("app.user")->getNotificationPreferences($this->getUser()->getId()); + + } else { + $data["errors"][] = "unknown"; + } + + return new Response($data); + + } + + public function setNotificationPreferences(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + if ($this->getUser() && !is_string($this->getUser())) { + + $notification = $request->request->get("preferences", Array()); + $this->get("app.user")->setNotificationPreferences($this->getUser()->getId(), $notification); + + } else { + $data["errors"][] = "unknown"; + } + + return new Response($data); + + } + + public function setTutorialStatus(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + if ($this->getUser() && !is_string($this->getUser())) { + + $status = $request->request->get("status", Array()); + $this->get("app.user")->setTutorialStatus($this->getUser()->getId(), $status); + + } else { + $data["errors"][] = "unknown"; + } + + return new Response($data); + + } + + public function updateNotificationPreferenceByWorkspace(Request $request) + { + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + $workspaceId = $request->request->get("workspaceId", 0); + $appNotif = $request->request->get("appNotification", Array()); + + $res = $this->get("app.user")->updateNotificationPreferenceByWorkspace($workspaceId, $appNotif, $this->getUser()); + + if ($res) { + $data["data"] = "success"; + } else { + $data["error"][] = "error"; + } + + return new Response($data); + } + + public function setWorkspacesPreferences(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + if ($this->getUser() && !is_string($this->getUser())) { + + $preferences = $request->request->get("preferences", Array()); + $this->get("app.user")->setWorkspacesPreferences($this->getUser()->getId(), $preferences); + + } else { + $data["errors"][] = "unknown"; + } + + return new Response($data); + + } + + public function updateStatus(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + if ($this->getUser() && !is_string($this->getUser())) { + + $status = $request->request->get("status", Array()); + $this->get("app.user")->updateStatus($this->getUser()->getId(), $status); + + } else { + $data["errors"][] = "unknown"; + } + + return new Response($data); + + } + + public function setIdentity(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + if ($this->getUser() && !is_string($this->getUser())) { + + $firstname = $request->request->get("firstname", ""); + $lastname = $request->request->get("lastname", ""); + $thumbnail = $request->request->get("thumbnail", null); + + $user = null; + + if (isset($_FILES["thumbnail"])) { + $thumbnail = $this->getUploader()->uploadFiles($this->getUser(), $_FILES["thumbnail"], "prfl"); + $thumbnail = $thumbnail[0]; + + if (count($thumbnail["errors"]) > 0) { + $data["errors"][] = "badimage"; + } else { + $user = $this->get("app.user")->updateUserBasicData($this->getUser()->getId(), $firstname, $lastname, $thumbnail["file"], $this->getUploader()); + } + } else { + $user = $this->get("app.user")->updateUserBasicData($this->getUser()->getId(), $firstname, $lastname, $thumbnail, $this->getUploader()); + } + + if ($user) { + $data["data"] = $user->getAsArray(); + } + + } else { + $data["errors"][] = "unknown"; + } + + return new Response($data); + + } + + public function getUploader() + { + $storagemanager = $this->get("driveupload.storemanager"); + if(!$provider){ + $provider = $storagemanager->getOneProvider(); + } + $configuration = $storagemanager->getProviderConfiguration($provider); + + if ($configuration["type"] === "S3") { + $uploader = $this->get("app.aws_uploader"); + }else if ($configuration["type"] === "openstack") { + $uploader =$this->get("app.openstack_uploader"); + }else{ + $uploader = $this->get("app.uploader"); + } + $uploader->configure($configuration); + return $uploader; + } + + public function setUsername(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + if ($this->getUser() && !is_string($this->getUser())) { + + $username = $request->request->get("username", ""); + + if (!$this->get("app.user")->changePseudo($this->getUser()->getId(), $username)) { + $data["errors"][] = "alreadyused"; + } + + } else { + $data["errors"][] = "unknown"; + } + + return new Response($data); + + } + + public function setPassword(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + if ($this->getUser() && !is_string($this->getUser())) { + + $oldPassword = $request->request->get("old_password", ""); + $password = $request->request->get("password", ""); + + if (!$this->get("app.user")->changePassword($this->getUser()->getId(), $oldPassword, $password)) { + $data["errors"][] = "badpassword"; + } + + } else { + $data["errors"][] = "unknown"; + } + + return new Response($data); + + } + + public function setMainMail(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + if ($this->getUser() && !is_string($this->getUser())) { + + $mail = $request->request->get("mail", ""); + + if (!$this->get("app.user")->changeMainMail($this->getUser()->getId(), $mail)) { + $data["errors"][] = "nosuchid"; + } + + } else { + $data["errors"][] = "unknown"; + } + + return new Response($data); + + } + + public function removeMail(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + if ($this->getUser() && !is_string($this->getUser())) { + + $mail = $request->request->get("mail", ""); + $result = $this->get("app.user")->removeSecondaryMail($this->getUser()->getId(), $mail); + if (!$result) { + $data["errors"][] = "badmail"; + } + $data["statuts"] = $result; + + } else { + $data["errors"][] = "unknown"; + } + + return new Response($data); + + } + + public function addMail(Request $request) + { + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + if ($this->getUser() && !is_string($this->getUser())) { + $mail = $request->request->get("mail", ""); + + $token = $this->get("app.user")->addNewMail($this->getUser()->getId(), $mail); + if ($token) { + $data["data"]["token"] = $token; + } else { + $data["errors"][] = "badmail"; + } + + } else { + $data["errors"][] = "unknown"; + } + + return new Response($data); + + } + + public function addMailVerify(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + if ($this->getUser() && !is_string($this->getUser())) { + + $token = $request->request->get("token", ""); + $number = $request->request->get("code", ""); + + $idMail = $this->get("app.user")->checkNumberForAddNewMail($this->getUser()->getId(), $token, $number); + + if ($idMail) { + $data["data"]["status"] = "success"; + $data["data"]["idMail"] = $idMail; + + } else { + $data["errors"][] = "badcode"; + } + + } else { + $data["errors"][] = "unknown"; + } + + return new Response($data); + + } + + public function getMails(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + if ($this->getUser() && !is_string($this->getUser())) { + + $mails = $this->get("app.user")->getSecondaryMails($this->getUser()->getId()); + foreach ($mails as $mail) { + $data["data"][] = Array( + "id" => $mail->getId(), + "main" => $mail->getMail() == $this->getUser()->getEmail(), + "email" => $mail->getMail() + ); + } + + } else { + $data["errors"][] = "unknown"; + } + + return new Response($data); + + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Users/Controller/UsersConnections.php b/twake/backend/core/src/Twake/Users/Controller/UsersConnections.php new file mode 100755 index 00000000..1b82a8fa --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Controller/UsersConnections.php @@ -0,0 +1,306 @@ +<?php + + +namespace Twake\Users\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; +use Twake\Market\Entity\LinkAppWorkspace; + +class UsersConnections extends BaseController +{ + + public function alive(Request $request) + { + $time = microtime(true); + $focus = $request->request->get("focus", true); + if ($this->getUser() && !is_string($this->getUser()) && $focus) { + $this->get("app.user")->alive($this->getUser()->getId()); + } + return new Response(Array("data" => "ok")); + + } + + public function autoLogin(Request $request) + { + $this->login($request); + return $this->redirect($this->getParameter("env.server_name")); + } + + public function login(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + $usernameOrMail = $request->request->get("username", ""); + $password = $request->request->get("token", $request->request->get("password", "")); + $rememberMe = $request->request->get("remember_me", true); + + //Retro compatibility + if(!$usernameOrMail && !$password){ + $usernameOrMail = $request->request->get("_username", ""); + $password = $request->request->get("_token", $request->request->get("_password", "")); + $rememberMe = $request->request->get("_remember_me", true); + } + + $response = new Response(); + $logged = $this->getUser() && !is_string($this->getUser()); + if(!$logged || ($usernameOrMail && $password)){ + $loginResult = $this->get("app.user")->login($usernameOrMail, $password, $rememberMe, $request, $response); + } + + if ($loginResult || $logged) { + + $device = $request->request->get("device", false); + if ($device && isset($device["type"]) && isset($device["value"])) { + $this->get("app.user")->addDevice($this->getUser()->getId(), $device["type"], $device["value"], isset($device["version"]) ? $device["version"] : null); + $this->get("administration.counter")->incrementCounter("total_devices_linked", 1); + } + + $workspaces_obj = $this->get("app.workspace_members")->getWorkspaces($this->getUser()->getId() . ""); + $workspaces = Array(); + foreach ($workspaces_obj as $workspace_obj) { + $value = $workspace_obj["workspace"]->getAsArray(); + $value["_user_last_access"] = $workspace_obj["last_access"] ? $workspace_obj["last_access"]->getTimestamp() : null; + $value["_user_hasnotifications"] = $workspace_obj["hasnotifications"]; + $value["_user_is_guest"] = $workspace_obj["_user_is_guest"]; + $value["_user_is_organization_administrator"] = $workspace_obj["_user_is_organization_administrator"]; + $value["_user_is_admin"] = $workspace_obj["_user_is_admin"]; + $value["role"] = ($value["_user_is_admin"] || $value["_user_is_organization_administrator"]) ? "moderator" : $value["role"]; + $workspaces[] = $value; + } + + $data["access_token"] = $this->get("app.user")->generateJWT($this->getUser()); + + $data["data"]["status"] = "connected"; + + } else { + + $data["data"]["status"] = "disconnected"; + + } + + $response->setContent(json_encode($data)); + + return $response; + + } + + public function mobileRedirect(Request $request) + { + $response = new Response(); + $response->setContent("<script>document.location='" . base64_decode($request->query->get("redirect")) . "'</script>"); + return $response; + } + + public function isLogged(Request $request) + { + $ok = $this->getUser() && !is_string($this->getUser()); + + if (!$ok) { + $origin = $request->query->get("origin", ""); + $name = $request->query->get("name", ""); + $forename = $request->query->get("forename", ""); + $mail = $request->query->get("mail", ""); + $username = $request->query->get("username", ""); + $url = "https://app.twakeapp.com/login?subscribe&origin=" . $origin; + if ($username && $username != "") { + $url = $url . "&username=" . $username; + } + if ($mail && $mail != "") { + $url = $url . "&mail=" . $mail; + } + if ($name && $name != "") { + $url = $url . "&name=" . $name; + } + if ($forename && $forename != "") { + $url = $url . "&forename=" . $forename; + } + return $this->redirect($url); + } + return $this->redirect($this->getParameter("env.server_name")); + } + + public function logout(Request $request) + { + if(!$this->getUser() || \is_string($this->getUser())){ + return new Response(Array("error" => "user disconnected")); + } + + $device = $request->request->get("device", false); + if ($device && isset($device["type"])) { + $this->get("app.user")->removeDevice($this->getUser()->getId(), $device["type"], $device["value"]); + $this->get("administration.counter")->incrementCounter("total_devices_linked", -1); + } + $this->get("app.user")->logout($request); + return new Response(Array()); + + } + + + public function currentUser(Request $request) + { + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + $ok = $this->getUser() && !is_string($this->getUser()); + if (!$ok) { + $data["errors"][] = "disconnected"; + } else { + + if( $this->get("app.session_handler")->getDidUseRememberMe() && $this->getUser()->getIdentityProvider()){ + $data["errors"][] = "redirect_to_" . $this->getUser()->getIdentityProvider(); + return new Response($data); + } + + $device = $request->request->get("device", false); + + if ($device && isset($device["type"]) && isset($device["value"]) && $device["value"]) { + $this->get("app.user")->addDevice($this->getUser()->getId(), $device["type"], $device["value"], $device["version"]); + $this->get("administration.counter")->incrementCounter("total_devices_linked", 1); + } + + $this->get("app.user")->updateTimezone($this->getUser(), $request->request->get("timezone", false)); + + $data["data"] = $this->getUser()->getAsArray(); + $data["data"]["notifications_preferences"] = $this->getUser()->getNotificationPreference(); + $data["data"]["tutorial_status"] = $this->getUser()->getTutorialStatus(); + + $workspaces_obj = $this->get("app.workspace_members")->getWorkspaces($this->getUser()->getId() . ""); + + //This is needed because node do some stuff when loading workspaces list + $api = $this->app->getServices()->get("app.restclient"); + $groupManagerRepository = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:GroupUser"); + $groupLinks = $groupManagerRepository->findBy(Array("user" => $this->getUser())); + $groups_ids = Array(); + $empty_groups_ids = Array(); + foreach($groupLinks as $group){ + $gid = $group->getGroup()->getId(); + $groups_ids[] = $gid; + $foundWorkspace = false; + foreach($workspaces_obj as $workspace_obj){ + if($workspace_obj["workspace"]->getGroup() === $gid){ + $foundWorkspace = true; + } + } + if(!$foundWorkspace){ + $empty_groups_ids[] = $group->getGroup()->getId(); + } + } + $groups_ids = array_values(array_unique($groups_ids)); + $empty_groups_ids = array_values(array_unique($empty_groups_ids)); + foreach($empty_groups_ids as $gid){ + $url = str_replace("/private", "/internal/services/workspaces/v1", $this->app->getContainer()->getParameter("node.api")); + $url = $url . "companies/".$gid."/workspaces"; + $opt = [ + CURLOPT_HTTPHEADER => Array( + "Authorization: " . $request->headers->get("Authorization"), + "Content-Type: application/json" + ), + CURLOPT_CONNECTTIMEOUT => 1, + CURLOPT_TIMEOUT => 1 + ]; + $res = $api->request("GET", $url, null, $opt); + } + //End of temp stuff + + $workspaces_obj = $this->get("app.workspace_members")->getWorkspaces($this->getUser()->getId() . ""); + + $workspaces = Array(); + $workspaces_ids = Array(); + foreach ($workspaces_obj as $workspace_obj) { + $value = $workspace_obj["workspace"]->getAsArray($this->get("app.twake_doctrine")); + $value["_user_last_access"] = $workspace_obj["last_access"] ? $workspace_obj["last_access"]->getTimestamp() : null; + $value["_user_hasnotifications"] = $workspace_obj["hasnotifications"]; + $value["_user_is_guest"] = $workspace_obj["_user_is_guest"]; + $value["_user_is_organization_administrator"] = $workspace_obj["_user_is_organization_administrator"]; + $value["_user_is_admin"] = $workspace_obj["_user_is_admin"]; + $value["role"] = ($value["_user_is_admin"] || $value["_user_is_organization_administrator"]) ? "moderator" : $value["role"]; + + if($value["group"]){ + $workspaces[] = $value; + $workspaces_ids[] = $value["id"]; + } + } + + $workspaces_ids = array_values(array_unique($workspaces_ids)); + + $this->get("app.workspace_members")->updateUser($this->getUser(), $workspaces_ids, $groups_ids); + + $mails = $this->get("app.user")->getSecondaryMails($this->getUser()->getId()); + + $data["data"]["mails"] = Array(); + foreach ($mails as $mail) { + $data["data"]["mails"][] = Array( + "id" => $mail->getId(), + "main" => ($this->getUser()->getEmail() == $mail->getMail()), + "email" => $mail->getMail() + ); + } + + $data["access_token"] = $this->get("app.user")->generateJWT($this->getUser()); + + $data["data"]["workspaces"] = $workspaces; + + //Start - Compatibility with new model + $data["data"]["preferences"] = [ + "language" => $data["data"]["language"], + "timezone" => $data["data"]["timezone_offset"] + ]; + + $data["data"]["companies"] = []; + $registeredCompanies = []; + foreach($data["data"]["workspaces"] as $workspace){ + $companyId = $workspace["group"]["id"]; + if(!in_array($companyId, $registeredCompanies)){ + $registeredCompanies[] = $companyId; + $data["data"]["companies"][] = [ + "company" => [ + "id" => $companyId, + "name" => $workspace["group"]["name"], + "logo" => $workspace["group"]["logo"], + ], + "status" => "", // Console implementation TODO + "role" => $workspace["_user_is_organization_administrator"] ? "admin" : ($workspace["_user_is_guest"] ? "guest" : "member"), + ]; + } + } + //End - Compatibility with new model + + } + + + return new Response($data); + + } + + public function setIsNew(Request $request) + { + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + $value = $request->request->get("value"); + + $ok = $this->getUser() && !is_string($this->getUser()); + if (!$ok) { + $data["errors"][] = "disconnected"; + } else { + + $user = $this->getUser()->getId(); + $this->get("app.user")->setIsNew($value, $user); + + } + + return new Response($data); + + } + +} diff --git a/twake/backend/core/src/Twake/Users/Controller/UsersRecover.php b/twake/backend/core/src/Twake/Users/Controller/UsersRecover.php new file mode 100755 index 00000000..14531884 --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Controller/UsersRecover.php @@ -0,0 +1,96 @@ +<?php + + +namespace Twake\Users\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class UsersRecover extends BaseController +{ + + + public function mail(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + $email = $request->request->get("email", ""); + + $res = $this->get("app.user")->requestNewPassword($email); + if ($res) { + + $data["data"]["token"] = $res; + + } else { + + $data["errors"][] = "nosuchmail"; + + } + + return new Response($data); + + } + + + public function codeVerification(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + $code = $request->request->get("code", ""); + $token = $request->request->get("token", ""); + + $res = $this->get("app.user")->checkNumberForNewPasswordRequest($token, $code); + + if ($res) { + + $data["data"]["status"] = "success"; + + } else { + + $data["errors"][] = "badcodeortoken"; + + } + + return new Response($data); + + } + + + public function newPassword(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + $code = $request->request->get("code", ""); + $token = $request->request->get("token", ""); + $password = $request->request->get("password", ""); + + $res = $this->get("app.user")->setNewPasswordAfterNewPasswordRequest($token, $code, $password); + + if ($res) { + + $data["data"]["status"] = "success"; + + } else { + + $data["errors"][] = "badcodeortoken"; + + } + + return new Response($data); + + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Users/Controller/UsersSubscribe.php b/twake/backend/core/src/Twake/Users/Controller/UsersSubscribe.php new file mode 100755 index 00000000..b98ab42d --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Controller/UsersSubscribe.php @@ -0,0 +1,154 @@ +<?php + + +namespace Twake\Users\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class UsersSubscribe extends BaseController +{ + + + public function mail(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + + $email = $request->request->get("email", ""); + $username = $request->request->get("username", ""); + $password = $request->request->get("password", ""); + $name = $request->request->get("name", ""); + $firstname = $request->request->get("firstname", ""); + $phone = $request->request->get("phone", ""); + $language = $request->request->get("language", ""); + $newsletter = $request->request->get("newsletter", ""); + + $res = $this->get("app.user")->subscribeMail($email, $username, $password, $name, $firstname, $phone, $language, $newsletter); + + if ($res && (!is_array($res) || !isset($res["error"]))) { + + $data["data"]["token"] = $res; + + } else { + + $data["errors"][] = $res["error"]; + + } + + return new Response($data); + + } + + public function doVerifyMail(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + $code = $request->request->get("code", ""); + $token = $request->request->get("token", ""); + $mail = $request->request->get("mail", ""); + + $mail = trim(strtolower($mail)); + + $response = new Response(Array()); + + $res = $this->get("app.user")->verifyMail($mail, $token, $code, false, $response); + + if ($res) { + + $data["data"]["status"] = "success"; + + $device = $request->request->get("device", false); + if ($device && isset($device["type"]) && isset($device["value"])) { + $this->get("app.user")->addDevice($this->getUser()->getId(), $device["type"], $device["value"], isset($device["version"]) ? $device["version"] : null); + $this->get("administration.counter")->incrementCounter("total_devices_linked", 1); + } + + $this->get("administration.counter")->incrementCounter("total_users", 1); + + if($this->isConnected()){ + $data["access_token"] = $this->get("app.user")->generateJWT($this->getUser()); + } + + } else { + + $data["errors"][] = "error"; + + } + + $response->setContent(json_encode($data)); + + return $response; + } + + public function getAvaible(Request $request) + { + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + $mail = $request->request->get("mail", ""); + $username = $request->request->get("username", ""); + + + $res = $this->get("app.user")->getAvaibleMailPseudo($mail, $username); + + if (is_bool($res) && $res == true) { + $data["data"]["status"] = "success"; + } elseif (is_array($res)) { + if (in_array(-1, $res)) { + + $data["errors"][] = "mailalreadytaken"; + + } + if (in_array(-2, $res)) { + + $data["errors"][] = "usernamealreadytaken"; + + } + } + + return new Response($data); + } + + public function createCompanyUser(Request $request) + { + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + $mail = $request->request->get("mail", ""); + $fullname = $request->request->get("fullname", ""); + $password = $request->request->get("password", ""); + $language = $request->request->get("language", ""); + $workspace_id = $request->request->get("workspace_id", ""); + $current_user_id = $this->getUser()->getId(); + + $can = $this->get('app.workspace_levels')->can($workspace_id, $this->getUser(), "external_accounts:write"); + $res = ["not_allowed"]; + if ($can) { + $res = $this->get("app.user")->createCompanyUser($mail, $fullname, $password, $language, $workspace_id, $current_user_id); + } + + if ($res === true) { + $data["data"] = "success"; + } else { + $data["errors"] = $res; + } + + return new Response($data); + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Users/Entity/Device.php b/twake/backend/core/src/Twake/Users/Entity/Device.php new file mode 100755 index 00000000..a78d680f --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Entity/Device.php @@ -0,0 +1,148 @@ +<?php + +namespace Twake\Users\Entity; + +use Doctrine\ORM\Mapping as ORM; + + +/** + * Mail + * + * @ORM\Table(name="device",options={"engine":"MyISAM", "scylladb_keys": {{"id": "ASC"}, {"value": "ASC"}, {"user_id":"ASC"}}}) + * @ORM\Entity() + */ +class Device +{ + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="user_id", type="twake_timeuuid") + */ + private $user_id; + + /** + * @var string + * + * @ORM\Column(name="type", type="string", length=16) + */ + private $type; + + /** + * @var string + * + * @ORM\Column(name="version", type="string", length=16) + */ + private $version; + + /** + * @var string + * + * @ORM\Column(name="value", type="twake_no_salt_text", nullable=true) + */ + private $value = ""; + + public function __construct($user_id, $type, $value, $version) + { + $this->user_id = $user_id; + $this->setType($type); + $this->setValue($value); + $this->setVersion($version); + } + + /** + * @return int + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getUserId() + { + return $this->user_id; + } + + /** + * @param mixed $user + */ + public function setUserId($user_id) + { + $this->user_id = $user_id; + } + + /** + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * @param string $type + */ + public function setType($type) + { + $this->type = isset($type) ? $type : ""; + } + + /** + * @return string + */ + public function getValue() + { + return $this->value; + } + + /** + * @param string $value + */ + public function setValue($value) + { + $this->value = isset($value) ? $value : ""; + } + + /** + * @return string + */ + public function getVersion() + { + return $this->version; + } + + /** + * @param string $version + */ + public function setVersion($version) + { + $this->version = isset($version) ? $version : "unknown"; + } + + public function getAsArray() + { + return Array( + "user_id" => $this->getUserId(), + "type" => $this->getType(), + "value" => $this->getValue(), + "version" => $this->getVersion() + + ); + } + + +} + diff --git a/twake/backend/core/src/Twake/Users/Entity/ExternalUserRepository.php b/twake/backend/core/src/Twake/Users/Entity/ExternalUserRepository.php new file mode 100755 index 00000000..115f2530 --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Entity/ExternalUserRepository.php @@ -0,0 +1,83 @@ +<?php + +namespace Twake\Users\Entity; + +use Symfony\Component\Security\Core\User\UserInterface; +use Twake\Core\Entity\SearchableObject; +use Twake\Workspaces\Entity\LinkWorkspaceParent; +use Symfony\Component\Security\Core\User\UserInterface as BaseUserInterface; +use Doctrine\ORM\Mapping as ORM; + + +/** + * ExternalUserRepository + * + * @ORM\Table(name="external_user_repository",options={"engine":"MyISAM", "scylladb_keys": {{"service_id":"ASC", "external_id":"ASC", "user_id": "ASC"}, {"service_id":"ASC", "user_id":"ASC", "external_id":"ASC"}} }) + * @ORM\Entity() + */ +class ExternalUserRepository +{ + + /** + * @ORM\Column(name="service_id", type="string") + * @ORM\Id + */ + protected $service_id; + + /** + * @ORM\Column(name="external_id", type="string") + * @ORM\Id + */ + protected $external_id; + + /** + * @ORM\Column(type="twake_timeuuid") + */ + protected $user_id; + + /** + * ExternalUserRepository constructor. + * @param int $service_id + * @param int $external_id + * @param $user_id + */ + public function __construct($service_id, $external_id, $user_id) + { + $this->service_id = $service_id . ""; + $this->external_id = $external_id . ""; + $this->user_id = $user_id . ""; + } + + /** + * @return string + */ + public function getServiceId() + { + return $this->service_id; + } + + /** + * @return string + */ + public function getExternalId() + { + return $this->external_id; + } + + /** + * @return mixed + */ + public function getUserId() + { + return $this->user_id; + } + + /** + * @return mixed + */ + public function setUserId($user_id) + { + $this->user_id = $user_id . ""; + } + +} diff --git a/twake/backend/core/src/Twake/Users/Entity/Mail.php b/twake/backend/core/src/Twake/Users/Entity/Mail.php new file mode 100755 index 00000000..0a4fe8fd --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Entity/Mail.php @@ -0,0 +1,124 @@ +<?php + +namespace Twake\Users\Entity; + +use Doctrine\ORM\Mapping as ORM; + +use Twake\Core\Entity\SearchableObject; + +/** + * Mail + * + * @ORM\Table(name="mail",options={"engine":"MyISAM", + * + * "scylladb_keys": {{"id":"ASC"}, {"user_id":"ASC"},{"mail":"ASC"}} + * }) + * @ORM\Entity() + */ +class Mail extends SearchableObject +{ + + protected $es_type = "mail"; + + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="user_id", type="twake_timeuuid") + */ + private $user_id; + + /** + * @var string + * + * @ORM\Column(name="mail", type="string", length=350) + */ + private $mail; + + + /** + * Get id + * + * @return int + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return string + */ + public function getEsType() + { + return $this->es_type; + } + + + /** + * Set user + * + * @param integer $user + * + * @return Mail + */ + public function setUserId($user_id) + { + $this->user_id = $user_id; + } + + /** + * Get user + * + * @return int + */ + public function getUserId() + { + return $this->user_id; + } + + /** + * Set mail + * + * @param string $mail + * + * @return Mail + */ + public function setMail($mail) + { + $this->mail = $mail; + + return $this; + } + + /** + * Get mail + * + * @return string + */ + public function getMail() + { + return $this->mail; + } + + public function getIndexationArray() + { + $return = Array( + "id" => $this->getId() . "", + "mail" => $this->getMail() + ); + return $return; + } + +} + diff --git a/twake/backend/core/src/Twake/Users/Entity/User.php b/twake/backend/core/src/Twake/Users/Entity/User.php new file mode 100755 index 00000000..3929a6f1 --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Entity/User.php @@ -0,0 +1,1270 @@ +<?php + +namespace Twake\Users\Entity; + +use Symfony\Component\Security\Core\User\UserInterface; +use Twake\Core\Entity\SearchableObject; +use Twake\Workspaces\Entity\LinkWorkspaceParent; +use Symfony\Component\Security\Core\User\UserInterface as BaseUserInterface; +use Doctrine\ORM\Mapping as ORM; + + +/** + * User + * + * @ORM\Table(name="user",options={"engine":"MyISAM"}) + * @ORM\Entity() + */ +class User extends SearchableObject +{ + + protected $es_type = "users"; + + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + protected $id; + + /** + * Used for cassandra session handler because timeuuid cannot be unserialized + */ + public $id_as_string_for_session_handler; + + /** + * @ORM\Column(name="banned", type="twake_boolean") + */ + protected $banned = false; + + /** + * @ORM\Column(name="is_robot", type="twake_boolean", options={"default" : false } ) + */ + protected $isrobot; + + /** + * @ORM\Column(name="first_name", type="twake_text") + */ + protected $firstname = ""; + + /** + * @ORM\Column(name="last_name", type="twake_text") + */ + protected $lastname = ""; + + /** + * @ORM\ManyToOne(targetEntity="Twake\Upload\Entity\File") + */ + protected $thumbnail; //Old format depreciated (now with console) + + /** + * @ORM\Column(name="picture", type="twake_text") + */ + protected $picture; + + /** + * @ORM\Column(name="workspaces", type="twake_text") + */ + protected $workspaces; + + /** + * @ORM\Column(name="groups", type="twake_text") + */ + protected $groups; + + /** + * @var int + * @ORM\Column(name="connections", type="integer") + */ + protected $connections; + + /** + * @var int + * @ORM\Column(name="connected", type="twake_boolean") + */ + protected $connected; + + /** + * @var int + * @ORM\Column(name="status_icon", type="string", length=64) + */ + protected $status_icon = '["", ""]'; + + /** + * @var int + * @ORM\Column(name="last_activity", type="twake_bigint") + */ + protected $lastactivity = 0; + + /** + * @var int + * @ORM\Column(name="creation_date", type="twake_datetime",nullable=true, options={"default" : "1970-01-02"}) + */ + protected $creationdate; + + /** + * @ORM\Column(name="language", type="string", length=64) + */ + protected $language = "en"; + + /** + * @ORM\Column(name="notification_preference", type="twake_text") + */ + protected $notification_preference = "{}"; + + /** + * @ORM\Column(name="notification_read_increment", type="twake_bigint") + */ + protected $notification_read_increment = 0; + + /** + * @ORM\Column(name="notification_write_increment", type="twake_bigint") + */ + protected $notification_write_increment = 0; + + /** + * @ORM\Column(name="workspaces_preference", type="twake_text") + */ + protected $workspaces_preference = "{}"; + + /** + * @ORM\Column(name="preferences", type="twake_text") + */ + protected $preferences = "{}"; + + /** + * @ORM\Column(name="tutorial_status", type="twake_text") + */ + protected $tutorial_status = "{}"; + + /** + * @ORM\Column(name="phone", type="twake_text") + */ + protected $phone = ""; + + /** + * @ORM\Column(name="identity_provider", type="twake_text") + */ + protected $identity_provider = ""; + + /** + * @ORM\Column(name="identity_provider_id", type="twake_text") + */ + protected $identity_provider_id = ""; + + /** + * @ORM\Column(name="token_login", type="twake_text") + */ + protected $token_login = ""; + + /** + * @ORM\Column(name="origin", type="string", length=64) + */ + protected $origin = ""; + + /** + * @ORM\Column(name="is_new", type="twake_boolean") + */ + protected $isnew = true; + + /** + * @ORM\Column(name="mail_verified", type="twake_boolean") + */ + protected $mail_verified = false; + + /** + * @ORM\Column(name="mail_verification_override", type="string") + */ + protected $mail_verification_override = ""; + + + protected $username; + + /** + * @ORM\Column(name="username_canonical", type="string", length=64, options={"index": true}) + */ + protected $usernamecanonical; + + protected $email; + + /** + * @ORM\Column(name="email_canonical", type="string", length=512, options={"index": true}) + */ + protected $emailcanonical; + + /** + * @ORM\Column(name="remember_me_secret", type="twake_text") + */ + protected $remember_me_secret; + + + /** + * @ORM\Column(type="twake_boolean") + */ + protected $enabled; + + /** + * @ORM\Column(type="string", length=512, nullable=true) + */ + protected $salt; + + /** + * @ORM\Column(type="string", length=512) + */ + protected $password; + + /** + * @ORM\Column(type="string", length=16) + */ + protected $timezone; + + /** + * @ORM\Column(name="last_login", type="twake_datetime") + */ + protected $lastlogin; + + /** + * @ORM\Column(name="confirmation_token", type="string", nullable = true) + */ + protected $confirmationtoken; + + /** + * @ORM\Column(name="password_requested_at", type="twake_datetime") + */ + protected $passwordrequestedat; + + /** + * @ORM\Column(type="array") + */ + protected $roles; + + /** + * @ORM\Column(name="deleted", type="twake_boolean") + */ + protected $deleted = false; + + public function __construct() + { + parent::__construct(); + $this->enabled = true; + $this->connections = 0; + $this->connected = 1; + $this->isrobot = false; + $this->roles = array(); + $this->lastlogin = new \DateTime(); + $this->passwordrequestedat = new \DateTime(); + + $this->setCreationDate(new \DateTime()); + } + + /** + * @return int + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id . ""; + } + + public function setIdAsString() + { + if ($this->id && str_replace(Array("0", "-"), "", $this->id . "")) { + $this->id_as_string_for_session_handler = $this->id . ""; + } + } + + /** + * @return mixed + */ + public function getBanned() + { + return $this->banned; + } + + /** + * @param mixed $banned + */ + public function setBanned($banned) + { + $this->banned = $banned; + } + + /** + * @return mixed + */ + public function getFirstName() + { + return $this->firstname; + } + + /** + * @param mixed $firstname + */ + public function setFirstName($firstname) + { + $this->firstname = $firstname; + } + + /** + * @return dateTime + */ + public function getCreationDate() + { + return $this->creationdate; + } + + /** + * @param datetime $creationdate + */ + public function setCreationDate($creationdate) + { + $this->creationdate = $creationdate; + } + + /** + * @return mixed + */ + public function getLastName() + { + return $this->lastname; + } + + /** + * @param mixed $lastname + */ + public function setLastName($lastname) + { + $this->lastname = $lastname; + } + + /** + * @return mixed + */ + public function getThumbnail() + { + return $this->thumbnail; + } + + /** + * @param mixed $thumbnail + */ + public function setThumbnail($thumbnail) + { + $this->thumbnail = $thumbnail; + } + + /** + * @return mixed + */ + public function getPicture() + { + if(!$this->picture){ + $this->setPicture($this->getThumbnail() ? $this->getThumbnail()->getPublicURL(2) : ""); + } + return $this->picture ?: ""; + } + + /** + * @param mixed $logo + */ + public function setPicture($picture) + { + $this->picture = $picture; + } + + public function isActive() + { + $this->lastactivity = date("U"); + $this->connected = true; + } + + public function isConnected() + { + if (date("U") - $this->lastactivity > 60 * 5) { + $this->connected = false; + return false; + } + return $this->connected; + } + + /** + * @return mixed + */ + public function getLanguage() + { + try{ + $this->language = json_decode($this->preferences, 1)["language"] ?: $this->language; + }catch(Error $err){} + return $this->language; + } + + /** + * @param mixed $language + */ + public function setLanguage($language) + { + $this->language = $language; + } + + /** + * @return mixed + */ + public function getPhone() + { + return $this->phone; + } + + /** + * @param mixed $phone + */ + public function setPhone($phone) + { + $this->phone = $phone; + } + + /** + * @return mixed + */ + public function getisNew() + { + return $this->isnew; + } + + /** + * @param mixed $isnew + */ + public function setIsNew($isnew) + { + $this->isnew = $isnew; + } + + public function getIdentityProvider() + { + return $this->identity_provider; + } + + public function setIdentityProvider($identity_provider) + { + if (!$identity_provider) { + $this->identity_provider = ""; + } + $this->identity_provider = $identity_provider; + } + + public function getIdentityProviderId() + { + return $this->identity_provider_id; + } + + public function getTrack() + { + $allow = true; + try{ + $allow = json_decode($this->preferences, 1)["allow_tracking"]; + }catch(Error $err){} + return $allow; + } + + public function setIdentityProviderId($identity_provider_id) + { + if (!$identity_provider_id) { + $this->identity_provider_id = ""; + } + $this->identity_provider_id = $identity_provider_id; + } + + public function getTokenLogin() + { + return json_decode(empty($this->token_login)?"{}":$this->token_login, 1); + } + + public function setTokenLogin($token_login) + { + $this->token_login = json_encode($token_login); + } + + /** + * @return mixed + */ + public function getOrigin() + { + return $this->origin; + } + + /** + * @param mixed $origin + */ + public function setOrigin($origin) + { + if (!$origin) { + $origin = ""; + } + $this->origin = $origin; + } + + /** + * @return mixed + */ + public function getNotificationPreference() + { + $preferences = json_decode($this->notification_preference, 1); + $preferences["devices"] = (isset($preferences["devices"])) ? $preferences["devices"] : 0; + $preferences["dont_disturb_between"] = (isset($preferences["dont_disturb_between"])) ? $preferences["dont_disturb_between"] : null; + $preferences["dont_disturb_and"] = (isset($preferences["dont_disturb_and"])) ? $preferences["dont_disturb_and"] : null; + $preferences["privacy"] = (isset($preferences["privacy"])) ? $preferences["privacy"] : 0; + $preferences["dont_use_keywords"] = (isset($preferences["dont_use_keywords"])) ? $preferences["dont_use_keywords"] : 1; + $preferences["keywords"] = (isset($preferences["keywords"])) ? $preferences["keywords"] : ""; + $preferences["disabled_workspaces"] = (isset($preferences["disabled_workspaces"])) ? $preferences["disabled_workspaces"] : []; + $preferences["workspace"] = (isset($preferences["workspace"])) ? $preferences["workspace"] : []; + $preferences["mail_notifications"] = (isset($preferences["mail_notifications"])) ? $preferences["mail_notifications"] : 2; + $preferences["disable_until"] = (isset($preferences["disable_until"])) ? $preferences["disable_until"] : 0; + + return $preferences; + } + + /** + * @param mixed $notification_preference + */ + public function setNotificationPreference($notification_preference) + { + $preferences = Array(); + @$preferences["devices"] = intval($notification_preference["devices"]); + @$preferences["dont_disturb_between"] = intval($notification_preference["disturb_before"]); + @$preferences["dont_disturb_and"] = intval($notification_preference["disturb_after"]); + @$preferences["privacy"] = intval($notification_preference["privacy"]); + @$preferences["dont_use_keywords"] = intval($notification_preference["use_keywords"]); + @$preferences["keywords"] = substr($notification_preference["keywords"], 0, 512); + @$preferences["mail_notifications"] = intval($notification_preference["mail_notifications"]); + @$preferences["disable_until"] = (isset($notification_preference["disable_until"])) ? $notification_preference["disable_until"] : 0; + + foreach ($notification_preference["disabled_workspaces"] as $item) { + @$preferences["disabled_workspaces"][] = intval($item); + } + + $this->notification_preference = json_encode($notification_preference); + } + + + public function getTutorialStatus() + { + return json_decode($this->tutorial_status, true); + } + + public function setTutorialStatus($tutorial_status) + { + @$this->tutorial_status = json_encode($tutorial_status); + } + + public function getFullName() + { + $name = "@" . $this->getUsername(); + if ($this->getFirstName() && $this->getFirstName() != "") { + $name = $this->getFirstName(); + } + if ($this->getFirstName() && $this->getFirstName() != "" && $this->getLastName() && $this->getLastName() != "") { + $name .= " " . $this->getLastName(); + } + return ucwords($name); + } + + public function getAsArray() + { + $return = Array( + "id" => $this->getId(), + "username" => $this->getUsername(), + "firstname" => $this->getFirstName(), + "lastname" => $this->getLastName(), + "thumbnail" => $this->getPicture(), + "identity_provider" => $this->getIdentityProvider(), + "connected" => $this->isConnected(), + "language" => $this->getLanguage(), + "isNew" => $this->getisNew(), + "isRobot" => $this->getisRobot(), + "status_icon" => $this->getStatusIcon(), + "front_id" => $this->getFrontId(), + "timezone_offset" => $this->timezone, + "email" => $this->getEmail(), + "mail_hash" => md5(trim(strtolower($this->getEmail()))), + "mail_verification_override" => $this->getMailVerified() ? null : $this->getMailVerificationOverride(), + "mail_verification_override_mail" => $this->getMailVerified() ? null : $this->getEmail(), + "groups_id" => $this->getGroups(), + "workspaces_id" => $this->getWorkspaces(), + "deleted" => $this->getDeleted(), + ); + + //Start - Compatibility with new model + $return["id"] = $return["id"]; + $return["provider"] = $return["identity_provider"] ?: "internal"; + $return["provider_id"] = $this->getIdentityProviderId(); + + $return["email"] = $return["email"]; + $return["is_verified"] = $this->getMailVerified(); + $return["picture"] = $this->getPicture(); + $return["first_name"] = $return["firstname"]; + $return["last_name"] = $return["lastname"]; + $return["created_at"] = ($this->getCreationDate() ? ($this->getCreationDate()->format('U') * 1000) : null); + + $return["preference"] = [ + "locale" => $this->getLanguage(), + "timezone" => $this->timezone, + ]; + + $return["status"] = trim(join(" ", $return["status_icon"])); + $return["last_activity"] = $this->getLastActivity() * 1000; + $return["deleted"] = $return["deleted"]; + //End - Compatibility with new model + + return $return; + } + + public function getIndexationArray() + { + $return = Array( + "email" => $this->getEmail(), + "username" => $this->getUsername(), + "firstname" => $this->getFirstName(), + "lastname" => $this->getLastName(), + "language" => $this->getLanguage(), + "creation_date" => ($this->getCreationDate() ? $this->getCreationDate()->format('Y-m-d') : null), + "groups_id" => $this->getGroups(), + "workspaces_id" => $this->getWorkspaces() + ); + return $return; + } + + public function setGroups($ids) + { + $this->groups = json_encode($ids); + } + + public function setWorkspaces($ids) + { + $this->workspaces = json_encode($ids); + } + + public function getGroups() + { + return json_decode($this->groups, 1); + } + + public function getWorkspaces() + { + return json_decode($this->workspaces, 1); + } + + /** + * @return mixed + */ + public function getisRobot() + { + return $this->isrobot; + } + + /** + * @param mixed $isrobot + */ + public function setIsRobot($isrobot) + { + $this->isrobot = $isrobot; + } + + /** + * @return int + */ + public function getLastActivity() + { + return $this->lastactivity; + } + + /** + * @return \DateTime|null + */ + public function getLastLogin() + { + return $this->lastlogin; + } + + + /** + * @return string + */ + public function __toString() + { + return (string)$this->getUsername(); + } + + /** + * {@inheritdoc} + */ + public function addRole($role) + { + $role = strtoupper($role); + if ($role === static::ROLE_DEFAULT) { + return $this; + } + + if (!in_array($role, $this->roles, true)) { + $this->roles[] = $role; + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function serialize() + { + return serialize(array( + $this->password, + $this->salt, + $this->usernamecanonical, + $this->username, + $this->enabled, + $this->id, + $this->email, + $this->emailcanonical, + )); + } + + /** + * {@inheritdoc} + */ + public function unserialize($serialized) + { + $data = unserialize($serialized); + + if (13 === count($data)) { + // Unserializing a User object from 1.3.x + unset($data[4], $data[5], $data[6], $data[9], $data[10]); + $data = array_values($data); + } elseif (11 === count($data)) { + // Unserializing a User from a dev version somewhere between 2.0-alpha3 and 2.0-beta1 + unset($data[4], $data[7], $data[8]); + $data = array_values($data); + } + + list( + $this->password, + $this->salt, + $this->usernamecanonical, + $this->username, + $this->enabled, + $this->id, + $this->email, + $this->emailcanonical + ) = $data; + } + + /** + * {@inheritdoc} + */ + public function eraseCredentials() + { + $this->plainpassword = null; + } + + /** + * {@inheritdoc} + */ + public function getUsername() + { + return $this->getusernameCanonical(); + } + + /** + * {@inheritdoc} + */ + public function getusernameCanonical() + { + return $this->usernamecanonical; + } + + /** + * {@inheritdoc} + */ + public function getSalt() + { + return $this->salt; + } + + /** + * @return string + */ + public function getEsType() + { + return $this->es_type; + } + + + /** + * {@inheritdoc} + */ + public function getEmail() + { + return $this->getemailCanonical(); + } + + /** + * {@inheritdoc} + */ + public function getemailCanonical() + { + return $this->emailcanonical; + } + + /** + * {@inheritdoc} + */ + public function getPassword() + { + return $this->password; + } + + /** + * {@inheritdoc} + */ + public function getConfirmationToken() + { + return $this->confirmationtoken; + } + + /** + * {@inheritdoc} + */ + public function getRoles() + { + $roles = $this->roles; + + // we need to make sure to have at least one role + $roles[] = 'ROLE_USER'; + + return array_unique($roles); + } + + /** + * {@inheritdoc} + */ + public function hasRole($role) + { + return in_array(strtoupper($role), $this->getRoles(), true); + } + + /** + * {@inheritdoc} + */ + public function isAccountNonExpired() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function isAccountNonLocked() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function isCredentialsNonExpired() + { + return true; + } + + public function isEnabled() + { + return $this->enabled; + } + + /** + * {@inheritdoc} + */ + public function isSuperAdmin() + { + return $this->hasRole(static::ROLE_SUPER_ADMIN); + } + + /** + * {@inheritdoc} + */ + public function removeRole($role) + { + if (false !== $key = array_search(strtoupper($role), $this->roles, true)) { + unset($this->roles[$key]); + $this->roles = array_values($this->roles); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function setUsername($username) + { + $this->username = $username; + $this->usernamecanonical = $username; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function setusernameCanonical($usernamecanonical) + { + $this->usernamecanonical = $usernamecanonical; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function setSalt($salt) + { + $this->salt = $salt; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function setEmail($email) + { + $this->email = trim(strtolower($email)); + $this->emailcanonical = trim(strtolower($email)); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function setemailCanonical($emailcanonical) + { + $this->emailcanonical = $emailcanonical; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function setEnabled($boolean) + { + $this->enabled = (bool)$boolean; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function setPassword($password) + { + $this->password = $password; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function setSuperAdmin($boolean) + { + if (true === $boolean) { + $this->addRole(static::ROLE_SUPER_ADMIN); + } else { + $this->removeRole(static::ROLE_SUPER_ADMIN); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function setPlainPassword($password) + { + $this->plainpassword = $password; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function setLastLogin(\DateTime $time = null) + { + $this->lastlogin = $time; + + return $this; + } + + /** + * @return mixed + */ + public function getMailVerified() + { + return $this->mail_verified; + } + + /** + * @param mixed $mail_verified + */ + public function setMailVerified($mail_verified) + { + $this->mail_verified = $mail_verified; + } + + public function getMailVerifiedExtended($mail = null, $pseudo = null) + { + //Dans tous les cas si le mail est vΓ©rifiΓ© cet utilisateur est bloquΓ© + if ($this->getMailVerified()) { + return true; + } + + $override = (strlen($this->getMailVerificationOverride()) > 2); + + if ($override && $mail != null && $pseudo != null) { + if (trim(strtolower($mail)) == trim(strtolower($this->getemailCanonical()))) { + return false; //Cas spΓ©cial ou on authorise l'inscription et l'Γ©crasement de l'utilisateur + } + } + + return $this->getMailVerified() || $override; + } + + /** + * @return mixed + */ + public function getMailVerificationOverride() + { + return $this->mail_verification_override; + } + + /** + * @param mixed $mail_verification_override + */ + public function setMailVerificationOverride($mail_verification_override): void + { + $this->mail_verification_override = $mail_verification_override; + } + + /** + * {@inheritdoc} + */ + public function setConfirmationToken($confirmationtoken) + { + $this->confirmationtoken = $confirmationtoken; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function setPasswordRequestedAt(\DateTime $date = null) + { + $this->passwordrequestedat = $date; + + return $this; + } + + /** + * Gets the timestamp that the user requested a password reset. + * + * @return null|\DateTime + */ + public function getPasswordRequestedAt() + { + return $this->passwordrequestedat; + } + + /** + * {@inheritdoc} + */ + public function isPasswordRequestNonExpired($ttl) + { + return $this->getPasswordRequestedAt() instanceof \DateTime && + $this->getPasswordRequestedAt()->getTimestamp() + $ttl > time(); + } + + /** + * {@inheritdoc} + */ + public function setRoles(array $roles) + { + $this->roles = array(); + + foreach ($roles as $role) { + $this->addRole($role); + } + + return $this; + } + + + public function isEqualTo(User $user) + { + if (!$user instanceof self) { + return false; + } + + if ($this->password !== $user->getPassword()) { + return false; + } + + if ($this->salt !== $user->getSalt()) { + return false; + } + + if ($this->username !== $user->getUsername()) { + return false; + } + + return true; + } + + /** + * @return int + */ + public function getStatusIcon() + { + try { + $status_icon = json_decode($this->status_icon, 1); + } catch (\Exception $e) { + $status_icon = Array("", ""); + } + if (!$status_icon) { + $status_icon = Array("", ""); + } + return $status_icon; + } + + /** + * @param int $status_icon + */ + public function setStatusIcon($status_icon) + { + try { + $this->status_icon = json_encode($status_icon); + } catch (\Exception $e) { + $this->status_icon = '["", ""]'; + } + } + + /** + * @return mixed + */ + public function getWorkspacesPreference() + { + try { + $preferences = json_decode($this->workspaces_preference, 1); + } catch (\Exception $e) { + $preferences = Array(); + } + if (!$preferences) { + $preferences = Array(); + } + return $preferences; + } + + /** + * @param mixed $workspaces_preference + */ + public function setWorkspacesPreference($workspaces_preference) + { + try { + $this->workspaces_preference = json_encode($workspaces_preference); + } catch (\Exception $e) { + $this->workspaces_preference = "{}"; + } + } + + /** + * @return mixed + */ + public function getNotificationReadIncrement() + { + return $this->notification_read_increment; + } + + /** + * @param mixed $notification_read_increment + */ + public function setNotificationReadIncrement($notification_read_increment) + { + $this->notification_read_increment = $notification_read_increment; + } + + /** + * @return mixed + */ + public function getNotificationWriteIncrement() + { + return $this->notification_write_increment; + } + + /** + * @param mixed $notification_write_increment + */ + public function setNotificationWriteIncrement($notification_write_increment) + { + $this->notification_write_increment = $notification_write_increment; + } + + /** + * @return mixed + */ + public function getTimezone() + { + try{ + $this->timezone = json_decode($this->preferences, 1)["timezone"] ?: $this->timezone; + }catch(Error $err){} + return $this->timezone; + } + + /** + * @param mixed $timezone + */ + public function setTimezone($timezone) + { + $this->timezone = $timezone; + } + + /** + * @return mixed + */ + public function getRememberMeSecret() + { + return $this->remember_me_secret; + } + + /** + * @param mixed $remember_me_secret + */ + public function setRememberMeSecret($remember_me_secret) + { + $this->remember_me_secret = $remember_me_secret; + } + + /** + * {@inheritdoc} + */ + public function getDeleted() + { + return $this->deleted; + } + +} diff --git a/twake/backend/core/src/Twake/Users/Entity/VerificationNumberMail.php b/twake/backend/core/src/Twake/Users/Entity/VerificationNumberMail.php new file mode 100755 index 00000000..8d6e1ea6 --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Entity/VerificationNumberMail.php @@ -0,0 +1,163 @@ +<?php + +namespace Twake\Users\Entity; + +use Doctrine\ORM\Mapping as ORM; + + +/** + * Mail + * + * @ORM\Table(name="verification_number_mail",options={"engine":"MyISAM"}) + * @ORM\Entity() + */ +class VerificationNumberMail +{ + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") //TO ADD FOR CASSANDRA + * @ORM\Id + * + */ + private $id; + + /** + * @var string + * + * @ORM\Column(name="mail", type="twake_no_salt_text") + */ + private $mail; + + /** + * @ORM\Column(name="verified", type="twake_boolean") + */ + private $verified = false; + + /** + * @var string + * + * @ORM\Column(name="hash_code", type="twake_text") + */ + private $hashcode; + + /** + * @var string + * + * @ORM\Column(name="token_column", type="string", length=256, options={"index": true}) + */ + private $token = ""; + + /** + * @var \DateTime + * + * @ORM\Column(name="date", type="twake_datetime") //TO ADD FOR CASSANDRA (replace datetime) + */ + private $date = ""; + + /** + * @ORM\Column(name="validity_time", type="integer") + */ + private $validitytime; + + + /** + * @ORM\Column(name="clean_code", type="twake_text") + */ + private $clean_code; + + + public function __construct($mail, $validitytime = 3600) + { + $this->mail = $mail; + $this->token = bin2hex(random_bytes(40)); + $this->hashcode = bin2hex(random_bytes(128)); + $this->date = new \DateTime(); + $this->validitytime = max(3600, $validitytime); + } + + public function getCode() + { + $code = substr(bin2hex(random_bytes(5)), 0, 9); + $this->clean_code = $code; + $this->hashcode = $this->hash($code); + //Prettify + $code = str_split($code, 3); + $code = join("-", $code); + return $code; + } + + public function verifyCode($code) + { + if ($this->date->format('U') < (new \DateTime())->format('U') - $this->validitytime) { + return false; + } + $code = preg_replace("/[^a-z0-9]/", "", strtolower($code)); + return $this->hash($code) == $this->hashcode; + } + + private function hash($str) + { + return hash("sha512", $str); + } + + /** + * @return string + */ + public function getToken() + { + return $this->token; + } + + public function getMail() + { + return $this->mail; + } + + /** + * @return int + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return \DateTime + */ + public function getDate() + { + return $this->date; + } + + /** + * @return mixed + */ + public function getCleanCode() + { + return $this->clean_code; + } + + /** + * @return mixed + */ + public function getVerified() + { + return $this->verified; + } + + /** + * @param mixed $verified + */ + public function setVerified($verified) + { + $this->verified = $verified; + } + +} + diff --git a/twake/backend/core/src/Twake/Users/Resources/Routing.php b/twake/backend/core/src/Twake/Users/Resources/Routing.php new file mode 100755 index 00000000..ae911721 --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Resources/Routing.php @@ -0,0 +1,73 @@ +<?php + +namespace Twake\Users\Resources; + +use Common\BaseRouting; + +class Routing extends BaseRouting +{ + + protected $routing_prefix = "ajax/users/"; + + protected $routes = [ + "login" => ["handler" => "UsersConnections:login", "methods" => ["POST"]], + "autoLogin" => ["handler" => "UsersConnections:autoLogin", "methods" => ["POST"]], + "logout" => ["handler" => "UsersConnections:logout", "methods" => ["POST"]], + "current/isLogged" => ["handler" => "UsersConnections:isLogged", "methods" => ["POST"]], + "current/get" => ["handler" => "UsersConnections:currentUser", "methods" => ["POST"], "security" => ["user_connected_security"]], + "mobile_redirect" => ["handler" => "UsersConnections:mobileRedirect", "methods" => ["GET"]], + "alive" => ["handler" => "UsersConnections:alive", "methods" => ["POST"], "security" => ["user_connected_security"]], + "set/isNew" => ["handler" => "UsersConnections:setIsNew", "methods" => ["POST"], "security" => ["user_connected_security"]], + // Account + "account/identity" => ["handler" => "UsersAccount:setIdentity", "methods" => ["POST"], "security" => ["user_connected_security"]], + "account/username" => ["handler" => "UsersAccount:setUsername", "methods" => ["POST"], "security" => ["user_connected_security"]], + "account/password" => ["handler" => "UsersAccount:setPassword", "methods" => ["POST"], "security" => ["user_connected_security"]], + "account/mainmail" => ["handler" => "UsersAccount:setMainMail", "methods" => ["POST"], "security" => ["user_connected_security"]], + "account/removemail" => ["handler" => "UsersAccount:removeMail", "methods" => ["POST"], "security" => ["user_connected_security"]], + "account/addmail" => ["handler" => "UsersAccount:addMail", "methods" => ["POST"], "security" => ["user_connected_security"]], + "account/mails" => ["handler" => "UsersAccount:getMails", "methods" => ["POST"], "security" => ["user_connected_security"]], + "account/addmailverify" => ["handler" => "UsersAccount:addMailVerify", "methods" => ["POST"], "security" => ["user_connected_security"]], + "account/language" => ["handler" => "UsersAccount:setLanguage", "methods" => ["POST"], "security" => ["user_connected_security"]], + "account/get_notifications" => ["handler" => "UsersAccount:getNotificationPreferences", "methods" => ["POST"], "security" => ["user_connected_security"]], + "account/set_notifications" => ["handler" => "UsersAccount:setNotificationPreferences", "methods" => ["POST"], "security" => ["user_connected_security"]], + "account/update_notifications" => ["handler" => "UsersAccount:updateNotificationPreferenceByWorkspace", "methods" => ["POST"], "security" => ["user_connected_security"]], + "account/set_tutorial_status" => ["handler" => "UsersAccount:setTutorialStatus", "methods" => ["POST"], "security" => ["user_connected_security"]], + "account/update_status" => ["handler" => "UsersAccount:updateStatus", "methods" => ["POST"], "security" => ["user_connected_security"]], + // Subscribe + "subscribe/mail" => ["handler" => "UsersSubscribe:mail", "methods" => ["POST"]], + "subscribe/doverifymail" => ["handler" => "UsersSubscribe:doVerifyMail", "methods" => ["POST"]], + "subscribe/availability" => ["handler" => "UsersSubscribe:getAvaible", "methods" => ["POST"]], + "subscribe/company_subscribe" => ["handler" => "UsersSubscribe:createCompanyUser", "methods" => ["POST"]], + // Recover + "recover/mail" => ["handler" => "UsersRecover:mail", "methods" => ["POST"]], + "recover/verify" => ["handler" => "UsersRecover:codeVerification", "methods" => ["POST"]], + "recover/password" => ["handler" => "UsersRecover:newPassword", "methods" => ["POST"]], + // Get and search + "all/get" => ["handler" => "Users:getById", "methods" => ["POST"], "security" => ["user_connected_security"]], + "all/search" => ["handler" => "Users:search", "methods" => ["POST"], "security" => ["user_connected_security"]], + + // CAS + "cas/login" => ["handler" => "Adapters/CAS:login", "methods" => ["GET"]], + "cas/verify" => ["handler" => "Adapters/CAS:verify", "methods" => ["GET"]], + "cas/logout" => ["handler" => "Adapters/CAS:logout", "methods" => ["GET"]], + "cas/logout_success" => ["handler" => "Adapters/CAS:logoutSuccess", "methods" => ["GET"]], + + // OpenID + "openid/logout" => ["handler" => "Adapters/OpenID:logout", "methods" => ["GET"]], + "openid/logout_success" => ["handler" => "Adapters/OpenID:logoutSuccess", "methods" => ["GET"]], + "openid/{method?}" => ["handler" => "Adapters/OpenID:index", "methods" => ["GET", "POST"]], + "openid" => ["handler" => "Adapters/OpenID:index", "methods" => ["GET", "POST"]], + + // Console + "console/hook" => ["handler" => "Adapters/Console:hook", "methods" => ["POST"]], + "console/token" => ["handler" => "Adapters/Console:loginFromOIDCAccessToken", "methods" => ["POST"]], + "console/redirect_to_app" => ["handler" => "Adapters/Console:redirectToApp", "methods" => ["GET"]], + "console/openid/logout" => ["handler" => "Adapters/Console:logout", "methods" => ["GET"]], + "console/openid/logout_success" => ["handler" => "Adapters/Console:logoutSuccess", "methods" => ["GET"]], + "console/openid/{method?}" => ["handler" => "Adapters/Console:index", "methods" => ["GET", "POST"]], + "console/openid" => ["handler" => "Adapters/Console:index", "methods" => ["GET", "POST"]], + "console/api/verify_mail" => ["handler" => "Adapters/Console/Api:verifyMail", "methods" => ["POST"]], + "console/api/invite" => ["handler" => "Adapters/Console/Api:invite", "methods" => ["POST"]], + ]; + +} diff --git a/twake/backend/core/src/Twake/Users/Resources/Services.php b/twake/backend/core/src/Twake/Users/Resources/Services.php new file mode 100755 index 00000000..c74f3b45 --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Resources/Services.php @@ -0,0 +1,17 @@ +<?php + +namespace Twake\Users\Resources; + +use Common\BaseServices; + +class Services extends BaseServices +{ + + protected $services = [ + "app.users" => "Users", + "app.user" => "User", + "app.user_updates" => "Updates", + "app.user_provider" => "UserProvider" + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Users/Services/PasswordEncoder.php b/twake/backend/core/src/Twake/Users/Services/PasswordEncoder.php new file mode 100755 index 00000000..24dbff23 --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Services/PasswordEncoder.php @@ -0,0 +1,56 @@ +<?php + +namespace Twake\Users\Services; + + +class PasswordEncoder +{ + private $algorithm = "sha512"; + private $encodeHashAsBase64 = true; + private $iterations = 5000; + private $encodedLength = -1; + + public function __construct() + { + $this->encodedLength = \strlen($this->encodePassword('', 'salt')); + } + + protected function mergePasswordAndSalt(string $password, ?string $salt) + { + if (empty($salt)) { + return $password; + } + + return $password . '{' . $salt . '}'; + } + + protected function isPasswordTooLong(string $password) + { + return \strlen($password) > 4096; + } + + public function encodePassword(string $raw, ?string $salt) + { + if ($this->isPasswordTooLong($raw)) { + throw new BadCredentialsException('Invalid password.'); + } + + $salted = $this->mergePasswordAndSalt($raw, $salt); + $digest = hash($this->algorithm, $salted, true); + + for ($i = 1; $i < $this->iterations; ++$i) { + $digest = hash($this->algorithm, $digest . $salted, true); + } + + return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest); + } + + public function isPasswordValid(string $encoded, string $raw, ?string $salt) + { + if (\strlen($encoded) !== $this->encodedLength || false !== strpos($encoded, '$')) { + return false; + } + + return !$this->isPasswordTooLong($raw) && hash_equals($encoded, $this->encodePassword($raw, $salt)); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Users/Services/Updates.php b/twake/backend/core/src/Twake/Users/Services/Updates.php new file mode 100755 index 00000000..a04e67ff --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Services/Updates.php @@ -0,0 +1,17 @@ +<?php + +namespace Twake\Users\Services; + +use Twake\Users\Model\ContactsInterface; +use App\App; + +class Updates +{ + + /* Used for websocket init */ + public function init($route, $data, $user) + { + return true; + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Users/Services/User.php b/twake/backend/core/src/Twake/Users/Services/User.php new file mode 100755 index 00000000..411aa12e --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Services/User.php @@ -0,0 +1,1210 @@ +<?php + +namespace Twake\Users\Services; + +use App\App; +use Common\Http\Request; +use Common\Http\Response; +use Twake\Core\Services\DoctrineAdapter\ManagerAdapter; +use Twake\Core\Services\Translate; +use Twake\Upload\Entity\File; +use Twake\Users\Entity\Device; +use Twake\Users\Entity\ExternalUserRepository; +use Twake\Users\Entity\Mail; +use Twake\Users\Entity\VerificationNumberMail; +use \Firebase\JWT\JWT; + +/** + * This service is responsible for subscribtions, unsubscribtions, request for new password + */ +class User +{ + + /** @var App */ + private $app; + + /* @var Translate $translate */ + var $translate; + /** @var ManagerAdapter */ + private $em; + private $pusher; + private $twake_mailer; + private $string_cleaner; + private $workspace_members_service; + private $group_service; + private $workspace_service; + private $restClient; + private $standalone; + private $licenceKey; + private $encoder; + + + public function __construct(App $app) + { + $this->app = $app; + $this->em = $app->getServices()->get("app.twake_doctrine"); + $this->pusher = $app->getServices()->get("app.pusher"); + $this->twake_mailer = $app->getServices()->get("app.twake_mailer"); + $this->string_cleaner = $app->getServices()->get("app.string_cleaner"); + $this->workspace_members_service = $app->getServices()->get("app.workspace_members"); + $this->group_service = $app->getServices()->get("app.groups"); + $this->workspace_service = $app->getServices()->get("app.workspaces"); + $this->restClient = $app->getServices()->get("app.restclient"); + $this->translate = $app->getServices()->get("app.translate"); + $this->standalone = $app->getContainer()->getParameter("env.standalone"); + $this->licenceKey = $app->getContainer()->getParameter("env.licence_key"); + $this->encoder = new PasswordEncoder(); + } + + public function alive($userId) + { + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->find($userId); + + if ($user != null) { + $user->isActive(); + $this->em->persist($user); + $this->em->flush(); + } + } + + /** + * @param $service_id + * @param $external_id + * @return null|\Twake\Users\Entity\User + */ + public function getUserFromExternalRepository($service_id, $external_id) + { + + $extRepository = $this->em->getRepository("Twake\Users:ExternalUserRepository"); + /** @var ExternalUserRepository $user_link */ + $user_link = $extRepository->findOneBy(Array("service_id" => $service_id, "external_id" => $external_id)); + + if (!$user_link) { + return null; + } else { + $user_id = $user_link->getUserId(); + $userRepository = $this->em->getRepository("Twake\Users:User"); + /** @var \Twake\Users\Entity\User $user */ + $user = $userRepository->find($user_id); + return $user; + } + + } + public function setUserFromExternalRepository($service_id, $external_id, $user_id) + { + + $extRepository = $this->em->getRepository("Twake\Users:ExternalUserRepository"); + /** @var ExternalUserRepository $user_link */ + $user_link = $extRepository->findOneBy(Array("service_id" => $service_id, "external_id" => $external_id)); + + if (!$user_link) { + $user_link = new ExternalUserRepository($service_id, $external_id, $user_id); + $this->em->persist($user_link); + } else { + $user_link->setUserId($user_id); + } + + $this->em->flush(); + return $user_link; + + } + + public function loginFromServiceWithToken($service_id, $external_id, $email, $username, $fullname, $picture) + { + $user = $this->getUserFromExternalRepository($service_id, $external_id); + + if (!$user) { + //Subscribe user + + //Find allowed username / email + $counter = 1; + $original_username = $username; + $ok = false; + $mailUsedError = false; + do { + $res = $this->getAvaibleMailPseudo($email, $username); + if ($res !== true) { + if (in_array(-1, $res)) { + //Mail used + $mailUsedError = true; + break; + } + if (in_array(-2, $res)) { + //Username used + $username = $original_username . $counter; + }else{ + $ok = true; + } + }else{ + $ok = true; + } + $counter++; + } while (!$ok && $counter < 1000); + if($mailUsedError){ + return false; + } + + $user = new \Twake\Users\Entity\User(); + $user->setSalt(bin2hex(random_bytes(40))); + $encoder = $this->encoder; + $user->setPassword($encoder->encodePassword(bin2hex(random_bytes(40)), $user->getSalt())); + $user->setUsername($username); + $user->setMailVerified(true); + $user->setEmail($email); + $user->setLanguage("en"); + $user->setPhone(""); + $user->setIdentityProvider($service_id); + + $this->em->persist($user); + $this->em->flush(); + + $this->setUserFromExternalRepository($service_id, $external_id, $user->getId()); + + $this->workspace_members_service->autoAddMemberByNewMail($email, $user->getId()); + + } + + $user->setFirstName(@explode(" ", $fullname)[0] ?: ""); + $user->setLastName(@explode(" ", $fullname)[1] ?: ""); + + if (($picture && (!$user->getThumbnail() || $user->getThumbnail()->getPublicLink() != $picture)) || ($user->getThumbnail() && !$picture)) { + if ($user->getThumbnail()) { + $this->em->remove($user->getThumbnail()); + } + if($picture){ + $thumbnail = new File(); + $thumbnail->setPublicLink($picture); + $user->setThumbnail($thumbnail); + $user->setPicture($thumbnail->getPublicURL(2)); + $this->em->persist($thumbnail); + }else{ + $user->setThumbnail(null); + $user->setPicture(""); + } + } + + $this->em->persist($user); + $this->em->flush(); + + return $this->loginWithUsernameOnlyWithToken($user->getusernameCanonical()); + } + + public function loginWithIdOnlyWithToken($userId, Response $response = null) + { + + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->findOneBy(Array("id" => $userId)); + + if ($user == null) { + return false; + } + + if ($user->getBanned()) { + return false; + } + + $token = bin2hex(random_bytes(64)); + + $user->setTokenLogin( + [ + "expiration" => date("U") + 120, + "token" => $token + ] + ); + + $this->em->persist($user); + $this->em->flush(); + + return ["token" => $token, "username" => $user->getEmail()]; + + } + + public function loginWithUsernameOnlyWithToken($usernameOrMail, Response $response = null) + { + + $usernameOrMail = trim(strtolower($usernameOrMail)); + + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->findOneBy(Array("usernamecanonical" => $this->string_cleaner->simplifyUsername($usernameOrMail))); + if ($user == null) { + $user = $userRepository->findOneBy(Array("emailcanonical" => $this->string_cleaner->simplifyMail($usernameOrMail))); + } + + if ($user == null) { + return false; + } + + if ($user->getBanned()) { + return false; + } + + $token = bin2hex(random_bytes(64)); + + $user->setTokenLogin( + [ + "expiration" => date("U") + 120, + "token" => $token + ] + ); + + $this->em->persist($user); + $this->em->flush(); + + return ["token" => $token, "username" => $user->getEmail()]; + + } + + public function login($usernameOrMail, $passwordOrToken, $rememberMe = false, $request = null, $response = null) + { + + $usernameOrMail = trim(strtolower($usernameOrMail)); + + $userRepository = $this->em->getRepository("Twake\Users:User"); + + $user = $userRepository->findOneBy(Array("usernamecanonical" => $this->string_cleaner->simplifyUsername($usernameOrMail))); + + if ($user == null) { + $user = $userRepository->findOneBy(Array("emailcanonical" => $this->string_cleaner->simplifyMail($usernameOrMail))); + } + + if ($user == null) { + return false; + } + + $tokenLogin = $user->getTokenLogin(); + + if(isset($tokenLogin["expiration"]) && $tokenLogin["expiration"] > date("U")){ + if(isset($tokenLogin["token"]) && $tokenLogin["token"] == $passwordOrToken){ + $this->app->getServices()->get("app.session_handler")->setUser($user); + return $user; + } + } + + $encoder = $this->encoder; + $passwordValid = $encoder->isPasswordValid($user->getPassword(), $passwordOrToken, $user->getSalt()); + + if ($passwordValid && !$user->getBanned() && $user->getMailVerifiedExtended()) { + + $this->app->getServices()->get("app.session_handler")->setUser($user); + return $user; + + } + + return false; + + } + + public function generateJWT($user){ + + $key = $this->app->getContainer()->getParameter("jwt.secret"); + + $expiration = date("U") + $this->app->getContainer()->getParameter("jwt.expiration"); + $payload = [ + "exp" => $expiration, + "type" => "access", + "iat" => intval(date("U")) - 60*10, + "nbf" => intval(date("U")) - 60*10, + "sub" => $user->getId(), + "email" => $user->getEmail(), + "provider_id" => $user ? $user->getIdentityProviderId() : null, + "track" => $user ? $user->getTrack() : true + ]; + $jwt = JWT::encode($payload, $key); + + $refreshExpiration = date("U") + $this->app->getContainer()->getParameter("jwt.refresh_expiration"); + $payload = [ + "exp" => $refreshExpiration, + "type" => "refresh", + "iat" => intval(date("U")) - 60*10, + "nbf" => intval(date("U")) - 60*10, + "sub" => $user->getId(), + "provider_id" => $user ? $user->getIdentityProviderId() : null, + "track" => $user ? $user->getTrack() : true + ]; + $jwt_refresh = JWT::encode($payload, $key); + + return [ + "time" => date("U"), + "expiration" => $expiration, + "refresh_expiration" => $refreshExpiration, + "value" => $jwt, + "refresh" => $jwt_refresh, + "type" => "Bearer" + ]; + + } + + public function logout(Request $request) + { + $response = new Response(); + $response->clearCookie('REMEMBERME'); + $response->sendHeaders(); + + $this->app->getServices()->get("app.session_handler")->destroySession($request); + + return true; + } + + public function ban($userId) + { + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->find($userId); + $user->setBanned(true); + $this->em->persist($user); + $this->em->flush(); + } + + public function unban($userId) + { + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->find($userId); + $user->setBanned(false); + $this->em->persist($user); + $this->em->flush(); + } + + public function requestNewPassword($mail) + { + + $mail = $this->string_cleaner->simplifyMail($mail); + + $userRepository = $this->em->getRepository("Twake\Users:User"); + /* @var \Twake\Users\Entity\User $user */ + $user = $userRepository->findOneBy(Array("emailcanonical" => $mail)); + if ($user != null) { + $verificationNumberMail = new VerificationNumberMail($mail); + + $code = $verificationNumberMail->getCode(); + + if (!defined("TESTENV")) { + error_log("recover code: " . $code); + } + + $this->twake_mailer->send($mail, "requestPassword", Array( + "_language" => $user ? $user->getLanguage() : "en", + "code" => $code, + "username" => $user->getUsername() + )); + + $this->em->persist($verificationNumberMail); + $this->em->flush(); + return $verificationNumberMail->getToken(); + } + + return false; + } + + public function checkNumberForNewPasswordRequest($token, $code) + { + $verificationRepository = $this->em->getRepository("Twake\Users:VerificationNumberMail"); + $ticket = $verificationRepository->findOneBy(Array("token" => $token)); + + if ($ticket != null) { + return $ticket->verifyCode($code); + } + + return false; + } + + public function setNewPasswordAfterNewPasswordRequest($token, $code, $password) + { + + $verificationRepository = $this->em->getRepository("Twake\Users:VerificationNumberMail"); + $userRepository = $this->em->getRepository("Twake\Users:User"); + $ticket = $verificationRepository->findOneBy(Array("token" => $token)); + $encoder = $this->encoder; + + if ($ticket != null) { + if ($ticket->verifyCode($code)) { + $user = $userRepository->findOneBy(Array("emailcanonical" => $ticket->getMail())); + if ($user != null) { + + $user->setPassword($encoder->encodePassword($password, $user->getSalt())); + $user->setMailVerified(true); + + $this->em->remove($ticket); + $this->em->persist($user); + $this->em->flush(); + + return true; + } + } + } + + return false; + } + + /** + * @param $mail + * @param $pseudo + * @return [-1, -2] | true (-1 is bad mail, -2 is bad username) + */ + public function getAvaibleMailPseudo($mail, $pseudo) + { + $mail = $this->string_cleaner->simplifyMail($mail); + $pseudo = $this->string_cleaner->simplifyUsername($pseudo); + $retour = Array(); + + if (!$this->string_cleaner->verifyMail($mail)) { + $retour[] = -1; + } else { + + if(in_array($pseudo, ["all", "here", "null", "undefined"]) || strlen($pseudo) <= 4){ + $retour[] = -2; + } + + //Check user doesn't exists + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->findOneBy(Array("emailcanonical" => $mail)); + //Check mail doesn't exists + $mailsRepository = $this->em->getRepository("Twake\Users:Mail"); + $mailExists = $mailsRepository->findOneBy(Array("mail" => $mail)); + + if (($user != null && $user->getMailVerifiedExtended($mail, $pseudo)) || $mailExists != null) { + $retour[] = -1; + } + + //Check pseudo doesn't exists + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->findOneBy(Array("usernamecanonical" => $pseudo)); + if ($user != null && $user->getMailVerifiedExtended($mail, $pseudo)) { + $retour[] = -2; + } + } + + if (count($retour) <= 0) { + return true; + } + return $retour; + } + + public function subscribeMail($mail, $pseudo, $password, $name, $firstname, $phone, $language, $newsletter = false, $sendEmail = true) + { + + $pseudo = $this->string_cleaner->simplifyUsername($pseudo); + + //Check pseudo doesn't exists + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->findOneBy(Array("usernamecanonical" => $pseudo)); + if ($user != null && $user->getMailVerifiedExtended($mail, $pseudo)) { + return ["error" => "usernamealreadytaken"]; + } + + $mail = $this->string_cleaner->simplifyMail($mail); + + if (!$this->string_cleaner->verifyMail($mail)) { + return ["error" => "mailalreadytaken"]; + } + + //Check mail doesn't exists + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->findOneBy(Array("emailcanonical" => $mail)); + if ($user != null && $user->getMailVerifiedExtended($mail, $pseudo)) { + return ["error" => "mailalreadytaken"]; + } + $mailsRepository = $this->em->getRepository("Twake\Users:Mail"); + $mailExists = $mailsRepository->findOneBy(Array("mail" => $mail)); + if ($mailExists != null) { + return ["error" => "mailalreadytaken"]; + } + + $complete_existing_user = null; + if ($user && !$user->getMailVerifiedExtended($mail, $pseudo) && $user->getisNew()) { //This user never verified his email, so we remove it. + if (strlen($user->getMailVerificationOverride()) > 2) { + $complete_existing_user = $user; + } else { + $this->em->remove($user); + $this->em->flush(); + } + } + + $auto_validate_mail = $this->app->getContainer()->getParameter("defaults.auth.internal.disable_email_verification"); + + $verificationNumberMail = new VerificationNumberMail($mail); + $code = $verificationNumberMail->getCode(); + $this->em->persist($verificationNumberMail); + + if(!$auto_validate_mail){ + + $magic_link = "/login?verifyMail&m=" . $mail . "&c=" . $code . "&token=" . $verificationNumberMail->getToken(); + + if (!defined("TESTENV")) { + error_log("sign in code: " . $magic_link); + } + + if ($sendEmail) { + $this->twake_mailer->send($mail, "subscribeMail", Array("_language" => $user ? $user->getLanguage() : "en", "code" => $code, "magic_link" => $magic_link)); + } + + } + + //Create the temporary user + $user = new \Twake\Users\Entity\User(); + $user->setSalt(bin2hex(random_bytes(40))); + $encoder = $this->encoder; + $user->setPassword($encoder->encodePassword($password, $user->getSalt())); + if (!$complete_existing_user) { + $user->setUsername($pseudo); + $user->setEmail($mail); + } else { + $user->setUsername("to_replace/" . $pseudo); + $user->setEmail("to_replace/" . $mail); + } + $user->setFirstName($firstname); + $user->setLastName($name); + $user->setPhone($phone); + $user->setLanguage($language ? $language : "en"); + $this->em->persist($user); + + $this->em->flush(); + + if ($sendEmail) { + try { + $contact_list_subscribe = $this->app->getContainer()->getParameter("mail.mailjet.contact_list_subscribe"); + if($contact_list_subscribe){ + $data = Array( + "Email" => $mail, + "Properties" => Array( + "first_name" => $firstname, + "last_name" => $name, + "language" => $language, + ), + "Action" => "addforce" + ); + $this->restClient->post($contact_list_subscribe["url"], json_encode($data), array(CURLOPT_CONNECTTIMEOUT => 60, CURLOPT_USERPWD => $contact_list_subscribe["token"], CURLOPT_HTTPHEADER => ['Content-Type: application/json'])); + } + } catch (\Exception $exception) { + error_log($exception->getMessage()); + } + } + if ($newsletter) { + try { + $contact_list_newsletter = $this->app->getContainer()->getParameter("mail.mailjet.contact_list_newsletter"); + if($contact_list_newsletter){ + $data = Array( + "Email" => $mail, + "Properties" => Array( + "first_name" => $firstname, + "last_name" => $name, + "language" => $language, + ), + "Action" => "addforce" + ); + $this->restClient->post($contact_list_newsletter["url"], json_encode($data), array(CURLOPT_CONNECTTIMEOUT => 60, CURLOPT_USERPWD => $contact_list_newsletter["token"], CURLOPT_HTTPHEADER => ['Content-Type: application/json'])); + } + } catch (\Exception $exception) { + error_log($exception->getMessage()); + } + } + + if($auto_validate_mail){ + $this->verifyMail($mail, $verificationNumberMail->getToken(), $code, true); + } + + return $verificationNumberMail->getToken(); + } + + public function verifyMail($mail, $token, $code, $force = false, $response = null, $login = true) + { + + $mail = trim(strtolower($mail)); + + $verificationRepository = $this->em->getRepository("Twake\Users:VerificationNumberMail"); + $ticket = $verificationRepository->findOneBy(Array("token" => $token)); + if (($ticket != null && $ticket->verifyCode($code) && $ticket->getMail($mail)) || $force) { + + if ($ticket) { + $ticket->setVerified(true); + $this->em->persist($ticket); + $this->em->flush(); + } + + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->findOneBy(Array("emailcanonical" => $mail)); + if ($user) { + + $user_to_replace = $userRepository->findOneBy(Array("emailcanonical" => "to_replace/" . $mail)); + if ($user_to_replace) { + + $username = explode("/", $user_to_replace->getUsername()); + $username = $username[1]; + + $user->setUsername($username); + + $user->setSalt($user_to_replace->getSalt()); + $user->setPassword($user_to_replace->getPassword()); + + $user->setFirstName($user_to_replace->getFirstName()); + $user->setLastName($user_to_replace->getLastName()); + $user->setPhone($user_to_replace->getPhone()); + + $this->em->remove($user_to_replace); + $this->em->flush(); + + } + + $user->setMailVerified(true); + $this->em->persist($user); + + $mailObj = new Mail(); + $mailObj->setMail($user->getEmail()); + $mailObj->setUserId($user->getId()); + + $this->em->persist($mailObj); + + $this->em->flush(); + + $this->workspace_members_service->autoAddMemberByNewMail($mail, $user->getId()); + + + // User auto log in + if($login) $this->app->getServices()->get("app.session_handler")->setUser($user); + + } + + return true; + } + return false; + } + + public function createCompanyUser($mail, $fullname, $password, $language, $workspace_id, $current_user_id) + { + + $pseudo = explode("@", $mail)[0] . "_" . date("U"); + $firstname = explode(" ", $fullname)[0]; + $lastname = explode(" ", $fullname . " ")[1]; + $override_key = $workspace_id . "_" . $current_user_id; + + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->findOneBy(Array("emailcanonical" => $mail)); + if ($user != null) { + if ($user->getMailVerified() || $user->getMailVerificationOverride() != $override_key) { + return ["error" => "mailalreadytaken"]; + } else if (!$user->getMailVerified() && $user->getMailVerificationOverride() == $override_key) { + + $user->setSalt(bin2hex(random_bytes(40))); + $encoder = $this->encoder; + $user->setPassword($encoder->encodePassword($password, $user->getSalt())); + $user->setUsername($pseudo); + + $this->em->persist($user); + $this->em->flush(); + + $this->verifyMail($mail, "", "", true); + + $user->setMailVerified(false); + $this->em->persist($user); + $this->em->flush(); + + return true; + + } else { + return ["error" => "mailalreadytaken"]; + } + } + $mailsRepository = $this->em->getRepository("Twake\Users:Mail"); + $mailExists = $mailsRepository->findOneBy(Array("mail" => $mail)); + if ($mailExists != null) { + return ["error" => "mailalreadytaken"]; + } + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->findOneBy(Array("usernamecanonical" => $pseudo)); + if ($user != null && $user->getMailVerified()) { + return ["error" => "usernamealreadytaken"]; + } + + $user = new \Twake\Users\Entity\User(); + $user->setSalt(bin2hex(random_bytes(40))); + $encoder = $this->encoder; + $user->setPassword($encoder->encodePassword($password, $user->getSalt())); + $user->setUsername($pseudo); + $user->setEmail($mail); + $user->setFirstName($firstname); + $user->setLastName($lastname); + $user->setPhone(""); + $user->setLanguage($language ? $language : "en"); + $user->setMailVerificationOverride($override_key); + $this->em->persist($user); + $this->em->flush(); + + $this->verifyMail($mail, "", "", true, null, false); + + $user->setMailVerified(false); + $this->em->persist($user); + $this->em->flush(); + + return true; + + } + + public function checkPassword($userId, $password) + { + $userRepository = $this->em->getRepository("Twake\Users:User"); + + $user = $userRepository->find($userId); + + if ($user == null) { + return false; + } + + $encoder = $this->encoder; + $passwordValid = $encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt()); + + $res = false; + if ($passwordValid) { + $res = true; + } + return $res; + } + + public function addDevice($userId, $type, $value, $version = "?") + { + $devicesRepository = $this->em->getRepository("Twake\Users:Device"); + + $devices = $devicesRepository->findBy(Array("value" => $value)); + $devices = array_merge($devices, $devicesRepository->findBy(Array("user_id" => $userId))); + foreach($devices as $device){ + $this->em->remove($device); + } + + $newDevice = new Device($userId, $type, $value, $version); + $this->em->persist($newDevice); + $this->em->flush(); + + return true; + + } + + public function removeDevice($userId, $type, $value) + { + $devicesRepository = $this->em->getRepository("Twake\Users:Device"); + $devices = $devicesRepository->findBy(Array("user_id" => $userId)); + foreach($devices as $device){ + if($device->getValue() === $value){ + $this->em->remove($device); + } + } + + return true; + } + + public function getSecondaryMails($userId) + { + + $mailRepository = $this->em->getRepository("Twake\Users:Mail"); + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->find($userId); + + return $mailRepository->findBy(Array("user_id" => $user)); + + } + + public function addNewMail($userId, $mail) + { + + $mail = $this->string_cleaner->simplifyMail($mail); + + $userRepository = $this->em->getRepository("Twake\Users:User"); + $mailRepository = $this->em->getRepository("Twake\Users:Mail"); + $user = $userRepository->find($userId); + + $userWithThisMailAsMainMail = $userRepository->findOneBy(Array("emailcanonical" => $mail)); + + $res = false; + + if ($user != null && $userWithThisMailAsMainMail == null) { + $mailExists = $mailRepository->findOneBy(Array("mail" => $mail)); + + if ($mailExists == null) { + + $verificationNumberMail = new VerificationNumberMail($mail); + + $code = $verificationNumberMail->getCode(); + + $this->twake_mailer->send($mail, "addMail", + Array("_language" => $user ? $user->getLanguage() : "en", "code" => $code, "username" => $user->getUsername())); + + $this->em->persist($verificationNumberMail); + $this->em->flush(); + $res = $verificationNumberMail->getToken(); + + } + + } + + return $res; + } + + public function removeSecondaryMail($userId, $mailId) + { + + + $userRepository = $this->em->getRepository("Twake\Users:User"); + $mailRepository = $this->em->getRepository("Twake\Users:Mail"); + $user = $userRepository->find($userId); + + $res = false; + + if ($user != null) { + $mail = $mailRepository->findOneBy(Array("id" => $mailId)); + if ($mail && $mail->getUserId() == $userId) { + $this->em->remove($mail); + $this->em->flush(); + $res = true; + } + + } + + return $res; + } + + public function checkNumberForAddNewMail($userId, $token, $code) + { + + $verificationRepository = $this->em->getRepository("Twake\Users:VerificationNumberMail"); + $userRepository = $this->em->getRepository("Twake\Users:User"); + $mailRepository = $this->em->getRepository("Twake\Users:Mail"); + $ticket = $verificationRepository->findOneBy(Array("token" => $token)); + $user = $userRepository->find($userId); + + if ($ticket != null && $user != null) { + if ($ticket->verifyCode($code)) { + $userWithMail = $userRepository->findOneBy(Array("emailcanonical" => $ticket->getMail())); + if ($userWithMail == null || $userWithMail->getId() != $userId) { + $mailExists = $mailRepository->findOneBy(Array("mail" => $ticket->getMail())); + + if ($mailExists == null) { + $mail = new Mail(); + $mail->setMail($ticket->getMail()); + $mail->setUserId($user->getId()); + + $this->em->remove($ticket); + $this->em->persist($mail); + $this->em->flush(); + + $this->workspace_members_service->autoAddMemberByNewMail($ticket->getMail(), $user->getId()); + + return $mail->getId(); + + } + } + } + } + + return false; + } + + public function changePassword($userId, $oldPassword, $password) + { + + if (!$password) { + return false; + } + + if (!$this->string_cleaner->verifyPassword($password)) { + return false; + } + + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->find($userId); + $encoder = $this->encoder; + if ($user != null) { + + $passwordValid = $encoder->isPasswordValid($user->getPassword(), $oldPassword, $user->getSalt()); + + if ($passwordValid) { + + $user->setPassword($encoder->encodePassword($password, $user->getSalt())); + + $this->em->persist($user); + $this->em->flush(); + + return true; + } + + } + + return false; + } + + public function changePseudo($userId, $pseudo) + { + + $pseudo = $this->string_cleaner->simplifyUsername($pseudo); + + if (!$pseudo) { + return false; + } + + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->find($userId); + + $otherUser = $userRepository->findOneBy(Array("usernamecanonical" => $pseudo)); + if ($otherUser != null && $otherUser->getId() != $userId) { + return false; + } + + if ($user != null) { + + $user->setUsername($pseudo); + + $this->em->persist($user); + $this->em->flush(); + + $datatopush = Array( + "type" => "USER", + "action" => "changeUser" + ); + $this->pusher->push($datatopush, "notifications/" . $user->getId()); + + return true; + + } + + return false; + } + + /** + * @param $userId + * @param $mail + * @return bool + */ + public function changeMainMail($userId, $mailId) + { + + + $userRepository = $this->em->getRepository("Twake\Users:User"); + $mailRepository = $this->em->getRepository("Twake\Users:Mail"); + + $user = $userRepository->find($userId); + + if ($user != null) { + $mailObj = $mailRepository->findOneBy(Array("id" => $mailId)); + + + if ($mailObj != null) { + + $user->setEmail($mailObj->getMail()); + + $this->em->persist($user); + $this->em->persist($mailObj); + $this->em->flush(); + + return true; + + } + + } + + return false; + } + + public function updateUserBasicData($userId, $firstName, $lastName, $thumbnail = null, $uploader = null) + { + $userRepository = $this->em->getRepository("Twake\Users:User"); + + $user = $userRepository->find($userId); + + if ($user != null) { + + $user->setFirstName($firstName); + $user->setLastName($lastName); + if ($thumbnail == 'false' || $thumbnail == 'null') { + $user->setThumbnail(null); + $user->setPicture(""); + } else if ($thumbnail != null && !is_string($thumbnail)) { + if ($user->getThumbnail()) { + if ($uploader) { + $uploader->removeFile($user->getThumbnail(), false); + } else { + $user->getThumbnail()->deleteFromDisk(); + } + $this->em->remove($user->getThumbnail()); + } + $user->setThumbnail($thumbnail); + $user->setPicture($thumbnail->getPublicURL(2)); + } + $this->em->persist($user); + $this->em->flush(); + + $datatopush = Array( + "type" => "USER", + "action" => "changeUser" + ); + $this->pusher->push($datatopush, "notifications/" . $user->getId()); + + return $user; + + } + + } + + public function setNotificationPreferences($userId, $notification) + { + $userRepository = $this->em->getRepository("Twake\Users:User"); + + $user = $userRepository->find($userId); + + if ($user != null) { + + $all_notification = $user->getNotificationPreference(); + + foreach ($notification as $key => $value) { + $all_notification[$key] = $value; + } + + $user->setNotificationPreference($all_notification); + $this->em->persist($user); + $this->em->flush(); + + } + } + + public function getNotificationPreferences($userId) + { + $userRepository = $this->em->getRepository("Twake\Users:User"); + + $user = $userRepository->find($userId); + + if ($user != null) { + return $user->getNotificationPreference(); + } + + return false; + + } + + public function setWorkspacesPreferences($userId, $preferences) + { + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->find($userId); + if ($user != null) { + $user->setWorkspacesPreference($preferences); + $this->em->persist($user); + $this->em->flush(); + } + } + + public function updateStatus($userId, $status) + { + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->find($userId); + if ($user != null) { + $user->setStatusIcon($status); + $this->em->persist($user); + $this->em->flush(); + } + } + + public function updateLanguage($userId, $language) + { + $userRepository = $this->em->getRepository("Twake\Users:User"); + + $user = $userRepository->find($userId); + + if ($user != null) { + + $user->setLanguage($language); + $this->em->persist($user); + $this->em->flush(); + + if ($userId) { + $datatopush = Array( + "type" => "LANGUAGE" + ); + $this->pusher->push($datatopush, "notifications/" . $userId); + } + + } + } + + public function setIsNew($value, $userId) + { + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->find($userId); + + if ($user != null) { + + $user->setisNew($value); + $this->em->persist($user); + $this->em->flush(); + + } + } + + public function updateNotificationPreferenceByWorkspace($workspaceId, $appNotif, $user) + { + /* @var \Twake\Users\Entity\User $user */ + $pref = $user->getNotificationPreference(); + + $pref["workspace"][$workspaceId . ""] = $appNotif; + + $user->setNotificationPreference($pref); + + $this->em->persist($user); + $this->em->flush(); + + return true; + } + + public function setTutorialStatus($userId, $status) + { + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->find($userId); + + if ($user != null) { + $user->setTutorialStatus($status); + $this->em->persist($user); + $this->em->flush(); + } + + return true; + } + + public function updateTimezone($user, $timezone = false) + { + if ($user && $timezone !== false) { + if ($user->getTimezone() != intval($timezone)) { + $user->setTimezone(intval($timezone) . ""); + $this->em->persist($user); + $this->em->flush(); + } + } + } + + public function removeUserByUsername($username) + { + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->findOneBy(Array("usernamecanonical" => $username)); + + if (!$user) { + return false; + } + + $this->removeLinkedToUserRows("Twake\Users:Device", $user, "user_id"); + $this->removeLinkedToUserRows("Twake\Users:Mail", $user, "user_id"); + + $this->removeLinkedToUserRows("Twake\Workspaces:WorkspaceUser", $user, "user"); + $this->removeLinkedToUserRows("Twake\Workspaces:GroupUser", $user, "user"); + $this->removeLinkedToUserRows("Twake\Workspaces:Workspace", $user, "user"); + + $this->em->remove($user); + $this->em->flush(); + + return true; + + } + + private function removeLinkedToUserRows($entity, $user, $col = "user") + { + $repo = $this->em->getRepository($entity); + $toRemove = $repo->findBy(Array($col => $user)); + foreach ($toRemove as $r) { + $this->em->remove($r); + } + } + + + +} diff --git a/twake/backend/core/src/Twake/Users/Services/UserProvider.php b/twake/backend/core/src/Twake/Users/Services/UserProvider.php new file mode 100755 index 00000000..ae3c994a --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Services/UserProvider.php @@ -0,0 +1,93 @@ +<?php + +namespace Twake\Users\Services; + +use App\App; +use Doctrine\ORM\NoResultException; + +class UserProvider +{ + + private $repository; + + public function __construct(App $app) + { + $this->repository = $app->getServices()->get("app.twake_doctrine")->getRepository("Twake\Core:User"); + } + + public function loadUserByUsername($username) + { + + $q = $this->repository->createQueryBuilder('u') + ->select('u') + ->where('u.usernamecanonical = :username') + ->setParameter('username', $username) + ->getQuery(); + + try { + $user = $q->getSingleResult(); + } catch (NoResultException $e) { + $message = sprintf('Unable to find active admin identified by %s', $username); + throw new \Exception($message, 0, $e); + } + + if ($user) { + $user->setIdAsString(); + } + + return $user; + } + + + public function refreshUser($user) + { + + $class = get_class($user); + if (!$this->repository->supportsClass($user)) { + $message = sprintf('Unsupported class type : %s', $class); + throw new \Exception($message); + } + + if ($user->id_as_string_for_session_handler) { + $res = $this->repository->find($user->id_as_string_for_session_handler); + } else { + $res = $this->repository->find($user->getId() . ""); + } + + if (!$res || !gettype($res) || gettype($res) == "NULL") { + error_log("refresh pass" . gettype($res) . " - " . $user->id_as_string_for_session_handler); + error_log($user->getId()); + } + + return $res; + } + + + public function supportsClass($class) + { + return true; + } + + public function find($id) + { + $res = parent::find($id); + + if ($res) { + $res->setIdAsString(); + } + + return $res; + } + + public function findOneBy(Array $arr) + { + $res = parent::findOneBy($arr); + + if ($res) { + $res->setIdAsString(); + } + + return $res; + } + +} diff --git a/twake/backend/core/src/Twake/Users/Services/Users.php b/twake/backend/core/src/Twake/Users/Services/Users.php new file mode 100755 index 00000000..b39788e6 --- /dev/null +++ b/twake/backend/core/src/Twake/Users/Services/Users.php @@ -0,0 +1,281 @@ +<?php + +namespace Twake\Users\Services; + +use App\App; + +/** + * This service is responsible for subscribtions, unsubscribtions, request for new password + */ +class Users +{ + + private $em; + private $list_users = Array("users" => Array(), "scroll_id" => ""); + + + public function __construct(App $app) + { + $this->em = $app->getServices()->get("app.twake_doctrine"); + $this->string_cleaner = $app->getServices()->get("app.string_cleaner"); + } + + public function search($options = Array(), $entity = false){ + $res = $this->searchWithES($options, $entity); + if(!isset($res["users"]) || count($res["users"]) === 0){ + $res = $this->searchWithDB($options, $entity); + } + return $res; + } + + public function searchWithDB($options = Array(), $entity = false) + { + $name = $options["name"]; + + $scope = $options["scope"] ?: "all"; + if($scope !== "group" || $scope !== "workspace") $scope = "group"; + + $usersArray = []; + $usersEntities = []; + + $offset = null; + $limit = 100; + $iteration = 0; + + while(count($usersArray) < 5 && $iteration < 10){ + $iteration++; + + $users = []; + if($scope == "workspace"){ + $workspace_id = $options["workspace_id"]; + + $repo = $this->em->getRepository("Twake\Workspaces:WorkspaceUser"); + $links = $repo->findBy(["workspace_id" => $workspace_id], null, $limit, $offset); + + foreach($links as $link){ + $users[] = $link->getUser($this->em); + $offset = $link->getUserId(); + } + + }elseif($scope == "group"){ + $group_id = $options["group_id"]; + + $repo = $this->em->getRepository("Twake\Workspaces:GroupUser"); + $links = $repo->findBy(["group" => $group_id], null, $limit, $offset); + + foreach($links as $link){ + $users[] = $link->getUser(); + $offset = $link->getUser()->getId(); + } + + } + + foreach($users as $user){ + if($user){ + + $match = false; + foreach($user->getAsArray() as $key => $value){ + if(in_array($key, ["username", "firstname", "lastname", "email"])){ + foreach(explode(" ", $name) as $word){ + if(strpos(strtolower($value), strtolower($word)) !== false){ + $match = true; + } + } + } + } + + if($match){ + $usersArray[] = [$user->getAsArray(), 0]; + $usersEntities[] = [$user, 0]; + } + } + } + + if(count($users) < $limit){ + break; + } + + } + + return ["users" => $entity ? $usersEntities : $usersArray, "scroll_id" => ""]; + + } + + public function searchWithES($options = Array(), $entity = false) + { + + $name = $options["name"]; + + $scope = $options["scope"] === "workspace" ? "workspace" : "group"; + $workspace_id = $options["workspace_id"]; + $group_id = $options["group_id"]; + + $should = Array(); + + if (isset($name)) { + $should[] = Array( + "bool" => Array( + "filter" => Array( + "regexp" => Array( + "firstname" => ".*" . $name . ".*" + ) + ) + ) + ); + + $should[] = Array( + "bool" => Array( + "filter" => Array( + "regexp" => Array( + "email" => $name . ".*" + ) + ) + ) + ); + + $should[] = Array( + "bool" => Array( + "filter" => Array( + "regexp" => Array( + "lastname" => ".*" . $name . ".*" + ) + ) + ) + ); + + $should[] = Array( + "bool" => Array( + "filter" => Array( + "regexp" => Array( + "username" => ".*" . $name . ".*" + ) + ) + ) + ); + } + + $match = Array( + "groups_id" => $group_id + ); + + $search_bool = Array( + "should" => $should, + "minimum_should_match" => 1 + ); + + if($match){ + $search_bool["filter"] = [ + "match" => $match + ]; + } + + $options = Array( + "repository" => "Twake\Users:User", + "index" => "users", + "size" => 10, + "query" => Array( + "bool" => Array( + "must" => Array( + "bool" => $search_bool + ) + ) + ), + "sort" => Array( + "creation_date" => Array( + "order" => "desc" + ) + ) + ); + + + // search in ES + $result = $this->em->es_search($options); + + array_slice($result["result"], 0, 5); + + $scroll_id = $result["scroll_id"]; + + if($scope === "all"){ + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->findOneBy(Array("usernamecanonical" => strtolower($name))); + + if ($user) { + $this->list_users["users"][] = Array($entity ? $user : $user->getAsArray(), 0); + } + } + + //on traite les donnΓ©es recu d'Elasticsearch + foreach ($result["result"] as $user) { + + if($scope == "workspace"){ + $repo = $this->em->getRepository("Twake\Workspaces:WorkspaceUser"); + $link = $repo->findOneBy(["workspace_id" => $workspace_id, "user_id" => $user[0]->getId()]); + if(!$link){ + continue; + } + } + + if($scope == "group"){ + $repo = $this->em->getRepository("Twake\Workspaces:GroupUser"); + $link = $repo->findOneBy(["group" => $group_id, "user" => $user[0]->getId()]); + if(!$link){ + continue; + } + } + + if($user[0]){ + $this->list_users["users"][] = Array($entity ? $user[0] : $user[0]->getAsArray(), $user[1][0]); + } + } + + $this->list_users["scroll_id"] = $scroll_id; + + return $this->list_users ?: null; + } + + public function completeUserWithCompanies($user, $requester = null) + { + if(is_string($requester)){ + return $user; + } + + $membersRepository = $this->em->getRepository("Twake\Workspaces:GroupUser"); + $companies = $membersRepository->findBy(Array("user" => $user["id"])); + $user["companies"] = []; + + foreach($companies as $companyMember){ + if($requester && !$membersRepository->findBy(Array("user" => $requester, "group" => $companyMember->getGroup())) ){ + continue; + } + $user["companies"][] = [ + "role" => $companyMember->getRole() === null ? "member" : $companyMember->getRole(), + "status" => "active", + "company" => [ + "id" => $companyMember->getGroup() + ] + ]; + } + + return $user; + } + + public function getById($id, $entity = false) + { + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->find($id); + if ($user) { + return $entity ? $user : $user->getAsArray(); + } + return false; + } + + public function getByEmail($email, $entity = false) + { + $userRepository = $this->em->getRepository("Twake\Users:User"); + $user = $userRepository->findOneBy(Array("emailcanonical" => $this->string_cleaner->simplifyMail($email))); + if ($user) { + return $entity ? $user : $user->getAsArray(); + } + return false; + } +} diff --git a/twake/backend/core/src/Twake/Workspaces/Bundle.php b/twake/backend/core/src/Twake/Workspaces/Bundle.php new file mode 100755 index 00000000..c4d68f97 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Bundle.php @@ -0,0 +1,30 @@ +<?php + +namespace Twake\Workspaces; + +require_once __DIR__ . "/Resources/Routing.php"; +require_once __DIR__ . "/Resources/Services.php"; + +use Twake\Workspaces\Resources\Routing; +use Twake\Workspaces\Resources\Services; +use Common\BaseBundle; + +class Bundle extends BaseBundle +{ + + protected $bundle_root = __DIR__; + protected $bundle_namespace = __NAMESPACE__; + protected $routes = []; + protected $services = []; + + public function init() + { + $routing = new Routing(); + $this->routes = $routing->getRoutes(); + $this->routing_prefix = $routing->getRoutesPrefix(); + $this->initRoutes(); + + $this->services = (new Services())->getServices(); + $this->initServices(); + } +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Workspaces/Controller/Group.php b/twake/backend/core/src/Twake/Workspaces/Controller/Group.php new file mode 100755 index 00000000..e5784504 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Controller/Group.php @@ -0,0 +1,187 @@ +<?php +/** + * Created by PhpStorm. + * User: yoanf + * Date: 24/04/2018 + * Time: 16:54 + */ + +namespace Twake\Workspaces\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + +class Group extends BaseController +{ + + + public function changeName(Request $request) + { + $response = Array("errors" => Array(), "data" => Array()); + + $groupId = $request->request->get("groupId"); + $name = $request->request->get("name"); + + $res = $this->get("app.groups")->changeData($groupId, $name, $this->getUser()->getId()); + + if (!$res) { + $response["errors"][] = "notallowed"; + } else { + $response["data"][] = true; + } + + return new Response($response); + } + + public function setLogo(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + $groupId = $request->request->get("groupId"); + + if (isset($_FILES["logo"])) { + error_log("logo "); + $thumbnail = $this->getUploader()->uploadFiles($this->getUser(), $_FILES["logo"], "grouplogo"); + $thumbnail = $thumbnail[0]; + + if (count($thumbnail["errors"]) > 0) { + $data["errors"][] = "badimage"; + } else { + + $group = $this->get("app.groups")->changeLogo($groupId, $thumbnail["file"]->getPublicURL(2), $this->getUser()->getId(), $this->getUploader()); + } + } else { + $group = $this->get("app.groups")->changeLogo($groupId, null, $this->getUser()->getId(), $this->getUploader()); + } + + if ($group) { + $data["data"] = $group->getAsArray(); + } + + return new Response($data); + + } + + public function getUploader() + { + $storagemanager = $this->get("driveupload.storemanager"); + if(!$provider){ + $provider = $storagemanager->getOneProvider(); + } + $configuration = $storagemanager->getProviderConfiguration($provider); + + if ($configuration["type"] === "S3") { + $uploader = $this->get("app.aws_uploader"); + }else if ($configuration["type"] === "openstack") { + $uploader =$this->get("app.openstack_uploader"); + }else{ + $uploader = $this->get("app.uploader"); + } + $uploader->configure($configuration); + return $uploader; + } + + public function getUsers(Request $request) + { + $response = Array("errors" => Array(), "data" => Array()); + + $groupId = $request->request->get("groupId"); + $limit = $request->request->get("limit"); + $offset = $request->request->get("offset"); + $onlyExterne = $request->request->getBoolean("onlyExterne"); + + $nb = $this->get("app.groups")->countUsersGroup($groupId); + $users = $this->get("app.groups")->getUsersGroup($groupId, $onlyExterne, $limit, $offset, $this->getUser()->getId()); + + if (!is_array($users)) { + $response["errors"][] = "notallowed"; + } else { + $list = Array(); + foreach ($users as $user) { + $temp = Array(); + $temp["user"] = $user["user"]->getAsArray(); + $temp["externe"] = $user["externe"]; + $temp["groupLevel"] = $user["level"]; + $temp["nbWorkspace"] = $user["nbWorkspace"]; + $list[] = $temp; + } + $response["data"] = Array("users" => $list); + $response["data"]["nbuser"] = max($nb, count($list)); + } + + return new Response($response); + } + + public function removeUser(Request $request) + { + $response = Array("errors" => Array(), "data" => Array()); + + $groupId = $request->request->get("groupId"); + $userId = $request->request->get("userId"); + + $users = $this->get("app.groups")->removeUserFromGroup($groupId, $userId, $this->getUser()->getId()); + + if (!$users) { + $response["errors"][] = "notallowed"; + } else { + $response["data"][] = "success"; + } + + return new Response($response); + } + + public function editUser(Request $request) + { + $response = Array("errors" => Array(), "data" => Array()); + + $groupId = $request->request->get("groupId"); + $userId = $request->request->get("userId"); + $externe = $request->request->getBoolean("editExterne"); + + $users = $this->get("app.groups")->editUserFromGroup($groupId, $userId, $externe, $this->getUser()->getId()); + + if (!$users) { + $response["errors"][] = "notallowed"; + } else { + $response["data"][] = "success"; + } + + return new Response($response); + } + + public function getWorkspaces(Request $request) + { + $response = Array( + "errors" => Array(), + "data" => Array() + ); + + $groupId = $request->request->get("groupId"); + + $workspaces = $this->get("app.groups")->getWorkspaces($groupId, $this->getUser()->getId()); + + foreach ($workspaces as $workspace) { + $is_deleted = $workspace->getIsDeleted(); + + if (!$is_deleted) { + $response["data"][] = Array( + "workspace" => $workspace->getAsArray($this->get("app.twake_doctrine")) + ); + } + } + + if (count($workspaces) == 0) { + $response["errors"][] = "empty list"; + } + + + return new Response($response); + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Workspaces/Controller/GroupApps.php b/twake/backend/core/src/Twake/Workspaces/Controller/GroupApps.php new file mode 100755 index 00000000..d87867c3 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Controller/GroupApps.php @@ -0,0 +1,117 @@ +<?php +/** + * Created by PhpStorm. + * User: Elliot + * Date: 11/04/2018 + * Time: 13:36 + */ + +namespace Twake\Workspaces\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + + +class GroupApps extends BaseController +{ + /** + * RΓ©cupΓ¨re les applications d'un group + */ + public function getApps(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $groupId = $request->request->get("group_id"); + + $apps = $this->get("app.group_apps")->getApps($groupId); + + if (!is_array($apps)) { + $response["errors"][] = "notallowed"; + } else { + $response["data"] = $apps; + } + + return new Response($response); + } + + public function setWorkspaceDefault(Request $request) + { + $response = Array("errors" => Array(), "data" => Array()); + + $groupId = $request->request->get("group_id"); + $appid = $request->request->get("app_id"); + $boolean = $request->request->getInt("state"); + + $res = $this->get("app.group_apps")->setWorkspaceDefault($groupId, $appid, $boolean, $this->getUser()->getId()); + + if (!$res) { + $response["errors"][] = "notallowed"; + } else { + $response["data"][] = true; + } + + return new Response($response); + } + + public function removeApplication(Request $request) + { + $response = Array("errors" => Array(), "data" => Array()); + + $groupId = $request->request->get("group_id"); + $appid = $request->request->get("app_id"); + + $res = $this->get("app.group_apps")->removeApplication($groupId, $appid, $this->getUser()->getId()); + + if (!$res) { + $response["errors"][] = "notallowed"; + } else { + $response["data"][] = true; + } + + return new Response($response); + } + + public function forceApplication(Request $request) + { + $response = Array("errors" => Array(), "data" => Array()); + + $groupId = $request->request->get("group_id"); + $appid = $request->request->get("app_id"); + + $res = $this->get("app.workspaces_apps")->forceApplication($groupId, $appid, $this->getUser()->getId()); + + if (!$res) { + $response["errors"][] = "notallowed"; + } else { + $response["data"][] = true; + } + + return new Response($response); + } + + /** + * Inscrit l'utilisation d'une application pour un groupe + pour un user + */ + public function useApp(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $groupId = $request->request->get("groupId"); + $workspaceId = $request->request->get("workspaceId"); + $appid = $request->request->get("appid"); + + $res = $this->get("app.group_apps")->useApp($groupId, $workspaceId, $this->getUser()->getId(), $appid); + + if (!$res) { + $response["errors"][] = "notallowed"; + } else { + $response["data"][] = "success"; + } + + return new Response($response); + } + +} diff --git a/twake/backend/core/src/Twake/Workspaces/Controller/GroupManager.php b/twake/backend/core/src/Twake/Workspaces/Controller/GroupManager.php new file mode 100755 index 00000000..60dfcc89 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Controller/GroupManager.php @@ -0,0 +1,147 @@ +<?php +/** + * Created by PhpStorm. + * User: Elliot + * Date: 23/04/2018 + * Time: 10:57 + */ + +namespace Twake\Workspaces\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + + +class GroupManager extends BaseController +{ + /** + * RΓ©cupΓ¨re les managers d'un group + */ + public function getManagers(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $groupId = $request->request->get("groupId"); + + $managers = $this->get("app.group_managers")->getManagers($groupId, $this->getUser()->getId()); + + if (!is_array($managers)) { + $response["errors"][] = "notallowed"; + } else { + $list = Array(); + foreach ($managers as $manager) { + $list[] = Array( + "user" => $manager["user"]->getAsArray(), + "level" => $manager["level"], + ); + } + + $response["data"] = Array( + "managers" => $list + ); + } + + return new Response($response); + } + + /** + * toggle status d'un utilisateur (manager ou non) + */ + public function toggleManager(Request $request) + { + $response = Array("errors" => Array(), "data" => Array()); + + $groupId = $request->request->get("groupId"); + $userId = $request->request->get("userId"); + $isManager = $request->request->get("isManager", null); + $result = $this->get("app.group_managers")->toggleManager($groupId, $userId, $isManager, $this->getUser()->getId()); + + + if (!$result) { + $response["errors"][] = "notallowed"; + } else { + $response["data"] = "success"; + } + + return new Response($response); + } + + + /** + * Ajoute un manager au groupe + */ + public function addManagers(Request $request) + { + $response = Array("errors" => Array(), "data" => Array()); + + $groupId = $request->request->get("groupId"); + $username = $request->request->get("username"); + + $username = str_replace(Array("@", " "), "", $username); + + $userRepository = $this->get("app.twake_doctrine")->getRepository("Twake\Users:User"); + $user = $userRepository->findOneBy(Array("usernamecanonical" => $username)); + + if (!$user) { + $response["errors"][] = "usernotfound"; + return new Response($response); + } + + $result = $this->get("app.group_managers")->addManager($groupId, $user->getId(), 1, false, $this->getUser()->getId()); + + + if (!$result) { + $response["errors"][] = "notallowed"; + } else { + $response["data"] = "success"; + } + + return new Response($response); + } + + /** + * Retire un managers d'un group + */ + public function removeManagers(Request $request) + { + $response = Array("errors" => Array(), "data" => Array()); + + $groupId = $request->request->get("groupId"); + $userId = $request->request->get("userId"); + + $result = $this->get("app.group_managers")->removeManager($groupId, $userId, $this->getUser()->getId()); + + if (!$result) { + $response["errors"][] = "notallowed"; + } else { + $response["data"] = "success"; + } + + return new Response($response); + } + + /** + * edite le managers d'un group + */ + public function editManagers(Request $request) + { + $response = Array("errors" => Array(), "data" => Array()); + + $groupId = $request->request->get("groupId"); + $userId = $request->request->get("userId"); + $level = $request->request->get("level"); + + $result = $this->get("app.group_managers")->changeLevel($groupId, $userId, $level, $this->getUser()->getId()); + + if (!$result) { + $response["errors"][] = "notallowed"; + } else { + $response["data"] = "success"; + } + + return new Response($response); + } + +} diff --git a/twake/backend/core/src/Twake/Workspaces/Controller/Workspace.php b/twake/backend/core/src/Twake/Workspaces/Controller/Workspace.php new file mode 100755 index 00000000..470732f2 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Controller/Workspace.php @@ -0,0 +1,440 @@ +<?php +/** + * Created by PhpStorm. + * User: Romaric Mourgues + * Date: 19/01/2017 + * Time: 10:38 + */ + +namespace Twake\Workspaces\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + + +class Workspace extends BaseController +{ + /** + * RΓ©cupΓ¨re les informations de base d'un workspace + */ + public function getAction(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $workspaceId = $request->request->get("workspaceId"); + + $ws = $this->get("app.workspaces")->get($workspaceId, $this->getUser()->getId()); + if (!$ws) { + $response["errors"][] = "notallowed"; + } else { + + $response["data"] = $ws->getAsArray($this->get("app.twake_doctrine")); + + $level = $this->get("app.workspace_levels")->getLevel($workspaceId, $this->getUser()->getId()); + $response["data"]["user_level"] = $level ? $level->getAsArray() : null; + + $levels = $this->get("app.workspace_levels")->getLevels($workspaceId, $this->getUser()->getId()); + $response["data"]["levels"] = Array(); + foreach ($levels as $level) { + $response["data"]["levels"][] = $level->getAsArray(); + } + + $groupRepository = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:Group"); + $workspaceRepository = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:Workspace"); + $groupUserRepository = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:GroupUser"); + + $wp = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + if ($wp->getGroup() != null) { + $group = $groupRepository->find($wp->getGroup()); + + $level = $this->get("app.group_managers")->getLevel($group, $this->getUser()->getId()); + + $privileges = $this->get("app.group_managers")->getPrivileges($level); + $response["data"]["group"]["level"] = $privileges; + + $response["data"]["apps"] = $this->get("app.group_apps")->getApps($group->getId()); + + $this->get("app.workspace_members")->updateCountersIfEmpty($workspaceId); + if($wp->getMemberCount() < 50){ + $response["data"]["members"] = $this->get("app.workspace_members")->getMembersAndPending($workspaceId, $this->getUser()->getId()); + }else{ + $response["data"]["members"] = []; + } + + $response["data"]["maxWorkspace"] = $limit; + } + } + return new Response($response); + } + + public function getPublicData(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $workspaceId = $request->request->get("workspace_id"); + $groupRepository = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:Group"); + + $ws = $this->get("app.workspaces")->get($workspaceId); + if (!$ws) { + $response["errors"][] = "no_such_workspace"; + } else { + + $response["data"]["workspace_name"] = $ws->getName(); + + if ($ws->getGroup() != null) { + + $group = $groupRepository->findOneBy(["id" => $ws->getGroup()]); + + $response["data"]["group_name"] = $group->getAsArray()["name"]; + $response["data"]["group_logo"] = $group->getAsArray()["logo"]; + + } + } + return new Response($response); + + } + + /** + * RΓ©cupΓ¨re les informations de base d'un groupe + */ + public function create(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $name = $request->request->get("name", ""); + + if (strlen($name) == 0) { + $name = "Untitled"; + } + + $groupId = $request->request->get("groupId", 0); + + if (!$groupId) { + $group_name = $request->request->get("group_name", ""); + $group_creation_data = $request->request->get("group_creation_data", ""); + + if (!is_array($group_creation_data)) { + $group_creation_data = Array(); + } + + //Auto create group + if (!$group_name) { + $group_name = $name; + } + + $uniquename = $this->get("app.string_cleaner")->simplify($group_name); + + $group = $this->get("app.groups")->create($this->getUser()->getId(), $group_name, $uniquename, null, $group_creation_data); + $groupId = $group->getId(); + + $this->get("administration.counter")->incrementCounter("total_groups", 1); + + } + + $ws = $this->get("app.workspaces")->create($name, $groupId, $this->getUser()->getId()); + + if (!$ws || is_string($ws)) { + $response["errors"][] = "notallowed"; + $response["errors"]["max"] = $ws; + } else { + + $ws_id = $ws->getId(); + + $channels = $request->request->get("channels", false); + if ($channels && is_array($channels)) { + foreach ($channels as $channel) { + error_log("TODO automatic channel creation"); + } + } + + $response["data"]["status"] = "success"; + //$response["data"]["workspace_id"] = $ws_id; + $response["data"]["workspace"] = $ws->getAsArray($this->get("app.twake_doctrine")); + + $this->get("administration.counter")->incrementCounter("total_workspaces", 1); + + } + + return new Response($response); + } + + /** + * RΓ©cupΓ¨re les informations de base d'un groupe + */ + public function duplicate(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $original_workspace_id = $request->request->get("original_workspace_id", 0); + $name = $request->request->get("config_name", ""); + + $config = Array(); + + $config["users"] = $request->request->get("config_users", "me"); + + $config["calendars"] = $request->request->get("config_calendars", 1); + $config["streams"] = $request->request->get("config_streams", 1); + $config["drive_labels"] = $request->request->get("config_drive_labels", 1); + $config["boards"] = $request->request->get("config_boards", 1); + $config["rights"] = $request->request->get("config_rights", 1); + + $ws = $this->get("app.workspaces")->duplicate($original_workspace_id, $name, $config, $this->getUser()->getId()); + + if (!$ws || is_string($ws)) { + $response["errors"][] = "notallowed"; + $response["errors"]["max"] = $ws; + } else { + $ws_id = $ws->getId(); + $response["data"]["status"] = "success"; + $response["data"]["workspace_id"] = $ws_id; + } + + return new Response($response); + } + + public function delete(Request $request) + { + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + if ($this->getUser() && !is_string($this->getUser())) { + $workspaceId = $request->request->get("workspaceId"); + $ok = $this->get("app.workspaces")->remove(0, $workspaceId); + if ($ok) { + $data["data"] = "success"; + } + } else { + $data["errors"][] = "unknown"; + } + + return new Response($data); + } + + /** + * RΓ©cupΓ¨re les applications d'un workspace + */ + public function getApps(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $workspaceId = $request->request->get("workspace_id"); + + $ws = $this->get("app.workspaces")->get($workspaceId, $this->getUser()->getId()); + if (!$ws) { + $response["errors"][] = "notallowed"; + } else { + $apps = $this->get("app.group_apps")->getApps($ws["group"]["id"]); + $response["data"] = $apps; + } + + return new Response($response); + } + + /** + * desactive une application d'un workspace + */ + public function disableApp(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $workspaceId = $request->request->get("workspace_id"); + $appid = $request->request->get("app_id"); + + $res = $this->get("app.workspaces_apps")->disableApp($workspaceId, $appid); + if (!$res) { + $response["errors"][] = "notauthorized"; + } else { + $response["data"][] = "success"; + } + + return new Response($response); + } + + /** + * Active une application d'un workspace + */ + public function enableApp(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $workspaceId = $request->request->get("workspace_id"); + $appid = $request->request->get("app_id"); + + $res = $this->get("app.workspaces_apps")->enableApp($workspaceId, $appid); + if (!$res) { + $response["errors"][] = "notauthorized"; + } else { + $response["data"][] = "success"; + } + + return new Response($response); + } + + public function getWorkspaceByName(Request $request) + { + $response = Array("errors" => Array(), "data" => Array()); + + $name = $request->request->get("name"); + + $res = $this->get("app.workspaces")->getWorkspaceByName($name); + if (!$res) { + $response["errors"][] = "notallowed"; + } else { + $response["data"]["workspace"] = $res; + } + + + return new Response($response); + } + + /** + * Archiver archiver un workspace + */ + public function archiveWorkspace(Request $request) + { + $response = Array( + "errors" => Array(), + "data" => Array() + ); + + $workspaceId = $request->request->get("workspaceId"); + $groupId = $request->request->get("groupId"); + + $res = $this->get("app.workspaces")->archive($groupId, $workspaceId, $this->getUser()->getId()); + + if ($res == true) { + $response["data"] = "success"; + } else { + $response["errors"] = "impossible to archive"; + } + + return new Response($response); + } + + /** + * DΓ©sarchiver archiver un workspace + */ + public function unarchiveWorkspace(Request $request) + { + $response = Array( + "errors" => Array(), + "data" => Array() + ); + + $workspaceId = $request->request->get("workspaceId"); + $groupId = $request->request->get("groupId"); + + $res = $this->get("app.workspaces")->unarchive($groupId, $workspaceId, $this->getUser()->getId()); + + if ($res == true) { + $response["data"] = "success"; + } else { + $response["errors"] = "impossible to archive"; + } + + return new Response($response); + } + + /** + * Cacher ou non un workspace + */ + public function hideOrUnhideWorkspace(Request $request) + { + $response = Array( + "errors" => Array(), + "data" => Array() + ); + + $workspaceId = $request->request->get("workspaceId"); + $wantedValue = $request->request->get("wantedValue"); + + $res = $this->get("app.workspaces")->hideOrUnhideWorkspace($workspaceId, $this->getUser()->getId(), $wantedValue); + + if ($res == true) { + $response["data"] = "success"; + } else { + $response["errors"] = "impossible to hide a workspace"; + } + + return new Response($response); + } + + /** + * Mettre un workspace en favori + */ + public function favoriteOrUnfavoriteWorkspace(Request $request) + { + $response = Array( + "errors" => Array(), + "data" => Array() + ); + + $workspaceId = $request->request->get("workspaceId"); + + $res = $this->get("app.workspaces")->favoriteOrUnfavoriteWorkspace($workspaceId, $this->getUser()->getId()); + + if ($res["answer"]) { + $response["data"] = $res["isfavorite"]; + } else { + $response["errors"] = "impossible to put as favorite a workspace"; + } + + return new Response($response); + } + + /** + * Recevoir ou non les notifications d'un workspace + */ + public function haveNotificationsOrNotWorkspace(Request $request) + { + $response = Array( + "errors" => Array(), + "data" => Array() + ); + + $workspaceId = $request->request->get("workspaceId"); + $wantedValue = $request->request->get("wantedValue"); + + $res = $this->get("app.workspaces")->haveNotificationsOrNotWorkspace($workspaceId, $this->getUser()->getId(), $wantedValue); + + if ($res == true) { + $response["data"] = "success"; + } else { + $response["errors"] = "impossible to receive notifications"; + } + + return new Response($response); + } + + + public function setIsNew(Request $request) + { + $response = Array( + "errors" => Array(), + "data" => Array() + ); + + $workspaceId = $request->request->get("workspaceId"); + $value = $request->request->get("value"); + + $res = $this->get("app.workspaces")->setIsNew($value, $workspaceId, $this->getUser()->getId()); + if ($res) { + $response["data"] = "success"; + } else { + $response["data"] = "Set has not been done"; + } + return new Response($response); + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Workspaces/Controller/WorkspaceData.php b/twake/backend/core/src/Twake/Workspaces/Controller/WorkspaceData.php new file mode 100755 index 00000000..37305ae0 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Controller/WorkspaceData.php @@ -0,0 +1,137 @@ +<?php +/** + * Created by PhpStorm. + * User: Romaric Mourgues + * Date: 19/01/2017 + * Time: 10:38 + */ + +namespace Twake\Workspaces\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + + +class WorkspaceData extends BaseController +{ + + public function setName(Request $request) + { + + $response = Array( + "errors" => Array(), + "data" => Array() + ); + + $workspaceId = $request->request->get("workspaceId"); + $name = $request->request->get("name", null); + + $ok = false; + if ($name != null) { + $ok = $this->get("app.workspaces")->changeName($workspaceId, $name, $this->getUser()->getId()); + } + + if (!$ok) { + $response["errors"][] = "error"; + } else { + $response["data"] = "success"; + } + + return new Response($response); + + } + + public function setLogo(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + $workspaceId = $request->request->get("workspaceId"); + + if (!$this->get("app.workspace_levels")->can($workspaceId, $this->getUser()->getId(), "workspace:write")) { + $data["errors"][] = "notallowed"; + } else { + + if (isset($_FILES["logo"])) { + $thumbnail = $this->getUploader()->uploadFiles($this->getUser(), $_FILES["logo"], "wslogo"); + $thumbnail = $thumbnail[0]; + + if (count($thumbnail["errors"]) > 0) { + $data["errors"][] = "badimage"; + } else { + + $workspace = $this->get("app.workspaces")->changeLogo($workspaceId, $thumbnail["file"]->getPublicURL(2), $this->getUser()->getId(), $this->getUploader()); + } + } else { + $workspace = $this->get("app.workspaces")->changeLogo($workspaceId, null, $this->getUser()->getId(), $this->getUploader()); + } + + } + + if ($workspace) { + $data["data"] = $workspace->getAsArray($this->get("app.twake_doctrine")); + } + + return new Response($data); + + } + + public function getUploader() + { + $storagemanager = $this->get("driveupload.storemanager"); + if(!$provider){ + $provider = $storagemanager->getOneProvider(); + } + $configuration = $storagemanager->getProviderConfiguration($provider); + + if ($configuration["type"] === "S3") { + $uploader = $this->get("app.aws_uploader"); + }else if ($configuration["type"] === "openstack") { + $uploader =$this->get("app.openstack_uploader"); + }else{ + $uploader = $this->get("app.uploader"); + } + $uploader->configure($configuration); + return $uploader; + } + + public function setWallpaper(Request $request) + { + + $data = Array( + "errors" => Array(), + "data" => Array() + ); + + $workspaceId = $request->request->get("workspaceId"); + + if (!$this->get("app.workspace_levels")->can($workspaceId, $this->getUser()->getId(), "workspace:write")) { + $data["errors"][] = "notallowed"; + } else { + + if (isset($_FILES["wallpaper"])) { + $thumbnail = $this->getUploader()->uploadFiles($this->getUser(), $_FILES["wallpaper"], "wswall"); + + $thumbnail = $thumbnail[0]; + + if (count($thumbnail["errors"]) > 0) { + $data["errors"][] = "badimage"; + } else { + $color = null; + $this->get("app.workspaces")->changeWallpaper($workspaceId, $thumbnail["file"], $color, $this->getUser()->getId(), $this->getUploader()); + } + } else { + $this->get("app.workspaces")->changeWallpaper($workspaceId, null, null, $this->getUser()->getId(), $this->getUploader()); + } + + } + + return new Response($data); + + } + +} diff --git a/twake/backend/core/src/Twake/Workspaces/Controller/WorkspaceLevels.php b/twake/backend/core/src/Twake/Workspaces/Controller/WorkspaceLevels.php new file mode 100755 index 00000000..27f21efb --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Controller/WorkspaceLevels.php @@ -0,0 +1,170 @@ +<?php +/** + * Created by PhpStorm. + * User: Romaric Mourgues + * Date: 19/01/2017 + * Time: 10:38 + */ + +namespace Twake\Workspaces\Controller; + +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; +use Twake\Workspaces\Model\WorkspaceLevelsInterface; + + +class WorkspaceLevels extends BaseController +{ + /** + * Get list of workspace levels + */ + public function getLevels(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $workspaceId = $request->request->get("workspaceId"); + + $levels = $this->get("app.workspace_levels")->getLevels($workspaceId, $this->getUser()->getId()); + $workspaceApps = $this->get("app.group_apps")->getApps($workspaceId, $this->getUser()->getId(), false, true); + + if ($levels == null) { + $response["errors"] = "notauthorized"; + return new Response($response); + } + + $list = $this->get("app.workspace_levels")->fixLevels($levels, $workspaceApps); + + $list["apps"] = Array(); + $list["apps"]["workspace"] = "Workspace"; + if ($workspaceApps != null) { + foreach ($workspaceApps as $workspaceApp) { + $list["apps"][$workspaceApp->getPublicKey()] = $workspaceApp->getName(); + } + } + + $response["data"] = $list; + + return new Response($response); + } + + /** + * Create a workspace level + */ + public function createLevel(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $workspaceId = $request->request->get("workspaceId"); + $label = $request->request->get("label", ""); + if ($label == null) { + $response["errors"] = "emptylabel"; + return new Response($response); + } + + $rights = $this->get("app.workspace_levels")->getDefaultLevel($workspaceId)->getRights(); + + $res = $this->get("app.workspace_levels")->addLevel($workspaceId, $label, $rights, $this->getUser()->getId()); + + if ($res) { + $response["data"] = "success"; + } else { + $response["errors"] = "notauthorized"; + } + + return new Response($response); + } + + /** + * Delete a workspace level + */ + public function deleteLevel(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $workspaceId = $request->request->get("workspaceId"); + $levelId = $request->request->get("levelId"); + + $res = $this->get("app.workspace_levels")->removeLevel($workspaceId, $levelId, $this->getUser()->getId()); + + if ($res) { + $response["data"] = "success"; + } else { + $response["errors"] = "notauthorized"; + } + + return new Response($response); + } + + /** + * Make a workspace levels default + */ + public function makeDefaulLevel(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $workspaceId = $request->request->get("workspaceId"); + $levelId = $request->request->get("levelId"); + + $res = $this->get("app.workspace_levels")->setDefaultLevel($workspaceId, $levelId, $this->getUser()->getId()); + + if ($res) { + $response["data"] = "success"; + } else { + $response["errors"] = "notauthorized"; + } + + return new Response($response); + } + + /** + * Edit a level (name and or rights) + */ + public function editLevel(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $workspaceId = $request->request->get("workspaceId"); + $levelId = $request->request->get("levelId"); + $rights = $request->request->get("rights"); + $label = $request->request->get("label", ""); + + $res = $this->get("app.workspace_levels")->updateLevel($workspaceId, $levelId, $label, $rights, $this->getUser()->getId()); + + if ($res) { + $response["data"] = "success"; + } else { + $response["errors"] = "notauthorized"; + } + + return new Response($response); + } + + public function getByLabel(Request $request) + { + $response = Array("errors" => Array(), "data" => Array()); + + $workspaceId = $request->request->get("workspaceId"); + $label = $request->request->get("label", ""); + + $res = $this->get("app.workspace_levels")->getByLabel($workspaceId, $label); + $labels = []; + if (!$res) { + $response["errors"] = "notauthorized"; + } else { + foreach ($res as $label) { + $labels[] = $label->getAsArray(); + } + $response["data"] = $labels; + } + + return new Response($response); + } + + +} diff --git a/twake/backend/core/src/Twake/Workspaces/Controller/WorkspaceMembers.php b/twake/backend/core/src/Twake/Workspaces/Controller/WorkspaceMembers.php new file mode 100755 index 00000000..5cdce4c2 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Controller/WorkspaceMembers.php @@ -0,0 +1,227 @@ +<?php +/** + * Created by PhpStorm. + * User: Romaric Mourgues + * Date: 19/01/2017 + * Time: 10:38 + */ + +namespace Twake\Workspaces\Controller; + +use PHPUnit\Util\Json; +use Common\BaseController; +use Common\Http\Response; +use Common\Http\Request; + + +class WorkspaceMembers extends BaseController +{ + + public function getMembers(Request $request) + { + $response = Array("errors" => Array(), "data" => Array( + "nextPageToken" => null, + "list" => [], + )); + + $workspaceId = $request->request->get("workspaceId"); + $order = $request->request->get("order", null); + $max = $request->request->get("max", null); + $offset = $request->request->get("offset", null); + $query = $request->request->get("query", null); + + if($query){ + $all_info = $this->get("app.workspace_members")->searchMembers($workspaceId, $this->getUser()->getId(), $query); + }else{ + $all_info = $this->get("app.workspace_members")->getMembers($workspaceId, $this->getUser()->getId(), $order, $max, $offset); + } + $response["data"] = []; + + foreach($all_info as $user){ + $user["user"] = $user["user"]->getAsArray(); + $response["data"]["list"][$user["user"]["id"]] = $user; + $response["data"]["nextPageToken"] = $user["user"]["id"]; + } + + return new Response($response); + } + + public function getPending(Request $request) + { + $response = Array("errors" => Array(), "data" => Array( + "nextPageToken" => null, + "list" => [], + )); + + $workspaceId = $request->request->get("workspaceId"); + $order = $request->request->get("order", null); + $max = $request->request->get("max", null); + $offset = $request->request->get("offset", null); + + $all_info = $this->get("app.workspace_members")->getPendingMembers($workspaceId, $this->getUser()->getId(), $max, $offset); + $response["data"] = []; + + foreach($all_info as $mail){ + $object = Array( + "mail" => $mail->getMail(), + "id" => $mail->getId(), + "externe" => $mail->getExterne() + ); + $response["data"]["list"][$mail->getMail()] = $object; + $response["data"]["nextPageToken"] = $mail->getMail(); + } + + return new Response($response); + } + + /** + * Add list of usernames or mails + */ + public function addList(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $workspaceId = $request->request->get("workspaceId"); + $list = $request->request->get("list", ""); + + $list = str_replace(Array(",", ";"), " ", $list); + $list = preg_replace('!\s+!', ' ', $list); + $list = explode(" ", $list); + + $added = Array("user" => Array(), "pending" => Array()); + $not_added = Array(); + foreach ($list as $element) { + $element = trim($element); + $element = explode("|", $element); + if (!isset($element[1])) { + $element[1] = "0"; + } + $asExterne = $element[1] == "1" ? true : false; + $element = $element[0]; + if (strlen($element) > 0) { + if (strrpos($element, "@") <= 0) { //No mail or "@username" + $res = $this->get("app.workspace_members")->addMemberByUsername($workspaceId, $element, $asExterne, $this->getUser()->getId()); + if ($res) { + $added["user"][] = $element; + } else { + $not_added[] = $element; + } + } else { + $res = $this->get("app.workspace_members")->addMemberByMail($workspaceId, $element, $asExterne, $this->getUser()->getId()); + if ($res == "user") { + $added["user"][] = $element; + } elseif ($res == "mail") { + $added["pending"][] = $element; + } else { + $not_added[] = $element; + } + } + } + } + + $response["data"]["added"] = $added; + $response["data"]["not_added"] = $not_added; + + return new Response($response); + } + + /** + * Remove e-mail wainting for add + */ + public function removeMail(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $workspaceId = $request->request->get("workspaceId"); + $mail = $request->request->get("mail", ""); + + $res = $this->get("app.workspace_members") + ->removeMemberByMail($workspaceId, $mail, $this->getUser()->getId()); + + $response["data"] = $res; + + return new Response($response); + } + + /** + * Remove list of members by ids + */ + public function removeMembers(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $workspaceId = $request->request->get("workspaceId"); + $ids = $request->request->get("ids", Array()); + + $removed = 0; + foreach ($ids as $id) { + $res = $this->get("app.workspace_members") + ->removeMember($workspaceId, $id, $this->getUser()->getId()); + if ($res) { + $removed++; + } + } + + $response["data"]["removed"] = $removed; + + return new Response($response); + } + + /** + * Change level of members + */ + public function changeMembersLevel(Request $request) + { + + $response = Array("errors" => Array(), "data" => Array()); + + $workspaceId = $request->request->get("workspaceId"); + $ids = $request->request->get("usersId", Array()); + $levelId = $request->request->get("levelId"); + + $updated = 0; + foreach ($ids as $id) { + $res = $this->get("app.workspace_members") + ->changeLevel($workspaceId, $id, $levelId, $this->getUser()->getId()); + if ($res) { + $updated++; + } + } + + $response["data"]["updated"] = $updated; + + return new Response($response); + } + + + public function getWorkspaces(Request $request) + { + $response = Array( + "errors" => Array(), + "data" => Array() + ); + + $workspaces = $this->get("app.workspace_members")->getWorkspaces($this->getUser()->getId()); + + foreach ($workspaces as $workspace) { + $response["data"][] = Array( + "workspace" => $workspace["workspace"]->getAsArray(), + "last_access" => $workspace["last_access"], + "ishidden" => $workspace["ishidden"], + "isfavorite" => $workspace["isfavorite"], + "hasnotifications" => $workspace["hasnotifications"], + "isArchived" => $workspace["isArchived"]); + } + + if (count($workspaces) == 0) { + $response["errors"][] = "empty list"; + } + + + return new Response($response); + } + +} diff --git a/twake/backend/core/src/Twake/Workspaces/Entity/AppPricingInstance.php b/twake/backend/core/src/Twake/Workspaces/Entity/AppPricingInstance.php new file mode 100755 index 00000000..6544bbfb --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Entity/AppPricingInstance.php @@ -0,0 +1,153 @@ +<?php + +namespace Twake\Workspaces\Entity; + +use Doctrine\ORM\Mapping as ORM; + + +/** + * AppPricingInstance + * + * @ORM\Table(name="app_pricing",options={"engine":"MyISAM"}) + * @ORM\Entity() + */ +class AppPricingInstance +{ + + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\ManyToOne(targetEntity="Twake\Workspaces\Entity\Group") + */ + private $group; + + /** + * @ORM\ManyToOne(targetEntity="Twake\Workspaces\Entity\GroupApp") + */ + private $groupapp; + + /** + * @ORM\Column(name="cost_monthly", type="integer") + */ + protected $costmonthly; + + /** + * @ORM\Column(name="cost_per_user", type="integer") + */ + protected $costuser; + + /** + * @ORM\Column(type="twake_datetime") + */ + private $startedat; + + + public function __construct($groupapp) + { + $this->group = $groupapp->getGroup(); + $this->groupapp = $groupapp; + $this->costmonthly = $groupapp->getApp()->getPriceMonthly(); + $this->costuser = $groupapp->getApp()->getPriceUser(); + $this->startedat = new \DateTime(); + } + + /** + * @return mixed + */ + public function getGroupapp() + { + return $this->groupapp; + } + + /** + * @param mixed $groupapp + */ + public function setGroupapp($groupapp) + { + $this->groupapp = $groupapp; + } + + /** + * @return int + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getCostMonthly() + { + return $this->costmonthly; + } + + /** + * @param mixed $costmonthly + */ + public function setCostMonthly($costmonthly) + { + $this->costmonthly = $costmonthly; + } + + /** + * @return mixed + */ + public function getCostUser() + { + return $this->costuser; + } + + /** + * @param mixed $costuser + */ + public function setCostUser($costuser) + { + $this->costuser = $costuser; + } + + /** + * @return mixed + */ + public function getStartedAt() + { + return $this->startedat; + } + + /** + * @param mixed $startedat + */ + public function setStartedAt($startedat) + { + $this->startedat = $startedat; + } + + /** + * @return mixed + */ + public function getGroup() + { + return $this->group; + } + + /** + * @param mixed $group + */ + public function setGroup($group) + { + $this->group = $group; + } + +} diff --git a/twake/backend/core/src/Twake/Workspaces/Entity/ExternalGroupRepository.php b/twake/backend/core/src/Twake/Workspaces/Entity/ExternalGroupRepository.php new file mode 100755 index 00000000..2eb0e1e3 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Entity/ExternalGroupRepository.php @@ -0,0 +1,79 @@ +<?php + +namespace Twake\Workspaces\Entity; + +use Doctrine\ORM\Mapping as ORM; + + +/** + * ExternalGroupRepository + * + * @ORM\Table(name="external_group_repository",options={"engine":"MyISAM", "scylladb_keys": {{"service_id":"ASC", "external_id":"ASC", "company_id":"ASC"}, {"service_id":"ASC", "company_id":"ASC", "external_id":"ASC"}} }) + * @ORM\Entity() + */ +class ExternalGroupRepository +{ + + /** + * @ORM\Column(name="service_id", type="string") + * @ORM\Id + */ + protected $service_id; + + /** + * @ORM\Column(name="external_id", type="string") + * @ORM\Id + */ + protected $external_id; + + /** + * @ORM\Column(type="string") + */ + protected $company_id; + + /** + * ExternalGroupRepository constructor. + * @param int $service_id + * @param int $external_id + * @param $company_id + */ + public function __construct($service_id, $external_id, $company_id) + { + $this->service_id = $service_id . ""; + $this->external_id = $external_id . ""; + $this->company_id = $company_id . ""; + } + + /** + * @return string + */ + public function getServiceId() + { + return $this->service_id; + } + + /** + * @return string + */ + public function getExternalId() + { + return $this->external_id; + } + + /** + * @return mixed + */ + public function getGroupId() + { + return $this->company_id; + } + + /** + * @return mixed + */ + public function setGroupId($company_id) + { + $this->company_id = $company_id . ""; + } + +} diff --git a/twake/backend/core/src/Twake/Workspaces/Entity/Group.php b/twake/backend/core/src/Twake/Workspaces/Entity/Group.php new file mode 100755 index 00000000..386b4752 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Entity/Group.php @@ -0,0 +1,407 @@ +<?php + +namespace Twake\Workspaces\Entity; + +use Doctrine\ORM\Mapping as ORM; + +use Ramsey\Uuid\Doctrine\UuidOrderedTimeGenerator; +use Twake\Core\Entity\SearchableObject; + + +/** + * Group + * + * @ORM\Table(name="group_entity",options={"engine":"MyISAM"}) + * @ORM\Entity() + */ +class Group extends SearchableObject +{ + + protected $es_type = "group"; + + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + protected $id; + + /** + * @ORM\Column(name="name", type="string", length=255, options={"index"=true}) + */ + protected $name; + + /** + * @ORM\Column(name="plan", type="twake_text") + */ + protected $plan; + + /** + * @ORM\Column(name="stats", type="twake_text") + */ + protected $stats; + + /** + * @ORM\Column(name="logo", type="twake_text") + */ + protected $logo; + + /** + * @ORM\Column(name="identity_provider", type="twake_text") + */ + protected $identity_provider = ""; + + /** + * @ORM\Column(name="identity_provider_id", type="twake_text") + */ + protected $identity_provider_id = ""; + + + // Twake without console fields below + + /** + * @ORM\ManyToOne(targetEntity="Twake\Upload\Entity\File") + * @ORM\JoinColumn(name="logo_id") + */ + protected $logofile; + + /** + * @ORM\Column(name="display_name", type="twake_text") + */ + protected $displayname; + + /** + * @ORM\OneToMany(targetEntity="Twake\Workspaces\Entity\Workspace", mappedBy="group") + */ + private $workspaces; + + /** + * @ORM\OneToMany(targetEntity="Twake\Workspaces\Entity\GroupUser", mappedBy="group") + */ + private $managers; + + /** + * @ORM\Column(type="twake_datetime") + */ + private $date_added; + + /** + * @ORM\Column(name="on_creation_data", type="twake_text") + */ + protected $on_creation_data = "{}"; + + /** + * @ORM\Column(name="isblocked", type="twake_boolean") + */ + private $isblocked = false; + + /** + * @ORM\Column(name="isprivate", type="twake_boolean") + */ + private $isprivate = false; + + /** + * @ORM\Column(name="member_count", type="twake_bigint") + */ + private $member_count = false; + + + public function __construct($name) + { + $this->name = $name; + $this->date_added = new \DateTime(); + } + + /** + * @return string + */ + public function getEsType() + { + return $this->es_type; + } + + + public function getIndexationArray() + { + $return = Array( + "id" => $this->getId() . "", + "name" => $this->getName(), + "creation_date" => ($this->getDateAdded() ? ($this->getDateAdded()->format('U') * 1000) : null), + ); + return $return; + } + + + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getName() + { + return $this->name; + } + + /** + * @param mixed $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @return mixed + */ + public function getDisplayName() + { + return $this->displayname; + } + + /** + * @param mixed $displayname + */ + public function setDisplayName($displayname) + { + $this->displayname = $displayname; + } + + /** + * @return mixed + */ + public function getStats() + { + $stats = []; + if ($this->stats) { + $stats = json_decode($this->stats, 1); + } + + $stats["created_at"] = ($this->getDateAdded() ? ($this->getDateAdded()->format('U') * 1000) : 0); + + return $stats; + } + + /** + * @param mixed $data + */ + public function setStats($stats) + { + $this->stats = json_encode($stats); + } + + public function getIdentityProvider() + { + return $this->identity_provider; + } + + public function setIdentityProvider($identity_provider) + { + if (!$identity_provider) { + $this->identity_provider = ""; + } + $this->identity_provider = $identity_provider; + } + + public function getIdentityProviderId() + { + return $this->identity_provider_id; + } + + public function setIdentityProviderId($identity_provider_id) + { + if (!$identity_provider_id) { + $this->identity_provider_id = ""; + } + $this->identity_provider_id = $identity_provider_id; + } + + /** + * @return mixed + */ + public function getLogoFile() + { + return $this->logofile; + } + + /** + * @return mixed + */ + public function getLogo() + { + if(!$this->logo){ + $this->setLogo($this->getLogoFile() ? $this->getLogoFile()->getPublicURL(2) : ""); + } + return $this->logo ?: ""; + } + + /** + * @param mixed $logo + */ + public function setLogo($logo) + { + $this->logo = $logo; + } + + /** + * @return mixed + */ + public function getPlan() + { + return json_decode($this->plan, 1); + } + + /** + * @param mixed $pricing_plan + */ + public function setPlan($plan) + { + $this->plan = json_encode($plan); + } + + /** + * @return mixed + */ + public function getWorkspaces() + { + return $this->workspaces; + } + + /** + * @param mixed $workspaces + */ + public function setWorkspaces($workspaces) + { + $this->workspaces = $workspaces; + } + + /** + * @return mixed + */ + public function getManagers() + { + return $this->managers; + } + + /** + * @param mixed $managers + */ + public function setManagers($managers) + { + $this->managers = $managers; + } + + /** + * @return mixed + */ + public function getDateAdded() + { + return $this->date_added; + } + + /** + * @param mixed $date_added + */ + public function setDateAdded($date_added) + { + $this->date_added = $date_added; + } + + /** + * @return mixed + */ + public function getisPrivate() + { + return $this->isprivate; + } + + /** + * @param mixed $isprivate + */ + public function setIsPrivate($isprivate) + { + $this->isprivate = $isprivate; + } + + /** + * @return mixed + */ + public function getIsBlocked() + { + return $this->isblocked; + } + + /** + * @param mixed $isblocked + */ + public function setIsBlocked($isblocked) + { + $this->isblocked = $isblocked; + } + + /** + * @return mixed + */ + public function getOnCreationData() + { + @$v = json_decode($this->on_creation_data, 1); + if (!$v) { + $v = Array(); + } + return $v; + } + + public function getOnCreationDataAsText() + { + return $this->on_creation_data; + } + + /** + * @param mixed $on_creation_data + */ + public function setOnCreationData($on_creation_data) + { + $this->on_creation_data = json_encode($on_creation_data); + } + + /** + * @return mixed + */ + public function getMemberCount() + { + if (!$this->member_count || $this->member_count < 0) { + return 0; + } + return $this->member_count; + } + + /** + * @param mixed $member_count + */ + public function setMemberCount($member_count) + { + $this->member_count = $member_count; + } + + public function getAsArray() + { + return Array( + "id" => $this->getId(), + "name" => $this->getDisplayName(), + "logo" => $this->getLogo(), + "plan" => $this->getPlan(), + "stats" => $this->getStats(), + "identity_provider" => $this->getIdentityProvider(), + "identity_provider_id" => $this->getIdentityProviderId(), + ); + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Workspaces/Entity/GroupApp.php b/twake/backend/core/src/Twake/Workspaces/Entity/GroupApp.php new file mode 100755 index 00000000..68ae9cbc --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Entity/GroupApp.php @@ -0,0 +1,242 @@ +<?php + +namespace Twake\Workspaces\Entity; + +use Doctrine\ORM\Mapping as ORM; + + +/** + * GroupApp + * + * @ORM\Table(name="group_app",options={"engine":"MyISAM", "scylladb_keys": {{"group_id": "ASC", "app_id": "ASC", "id": "ASC"}, {"id":"ASC"}}}) + * @ORM\Entity() + */ +class GroupApp +{ + + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\ManyToOne(targetEntity="Twake\Workspaces\Entity\Group") + * @ORM\Id + */ + private $group; + + /** + * @ORM\Column(name="app_id", type="twake_timeuuid") + * @ORM\Id + */ + private $app_id; + + /** + * @ORM\Column(type="twake_datetime") + */ + private $date_added; + + /** + * @ORM\Column(type="twake_boolean") + */ + private $workspacedefault; + + /** + * @ORM\Column(type="integer") + */ + private $workspaces_count; + + /** + * @ORM\Column(name="privileges_capabilities_last_update", type="twake_datetime") + */ + protected $privileges_capabilities_last_update; + + /** + * @ORM\Column(name="privileges", type="twake_text") + */ + protected $privileges = "[]"; + + /** + * @ORM\Column(name="capabilities", type="twake_text") + */ + protected $capabilities = "[]"; + + /** + * @ORM\Column(name="hooks", type="twake_text") + */ + protected $hooks = "[]"; + + + public function __construct($group, $app_id) + { + $this->group = $group; + $this->app_id = $app_id; + + $this->date_added = new \DateTime(); + $this->workspacedefault = false; + + $this->setPrivilegesCapabilitiesLastRead(new \DateTime()); + } + + + public function getAsArray() + { + return Array( + "id" => $this->getId(), + "group_id" => $this->getGroup()->getId(), + "app_id" => $this->getAppId(), + "date_added" => $this->getDateAdded() ? $this->getDateAdded()->getTimestamp() : null, + "workspace_default" => $this->getWorkspaceDefault(), + "workspace_count" => $this->getWorkspacesCount() + ); + } + + /** + * @return int + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getGroup() + { + return $this->group; + } + + /** + * @return mixed + */ + public function getDateAdded() + { + return $this->date_added; + } + + /** + * @return mixed + */ + public function getWorkspaceDefault() + { + return $this->workspacedefault; + } + + /** + * @param mixed $workspacedefault + */ + public function setWorkspaceDefault($workspacedefault) + { + $this->workspacedefault = $workspacedefault; + } + + /** + * @return mixed + */ + public function getAppId() + { + return $this->app_id; + } + + /** + * @param mixed $app_id + */ + public function setAppId($app_id) + { + $this->app_id = $app_id; + } + + /** + * @return mixed + */ + public function getWorkspacesCount() + { + return $this->workspaces_count; + } + + /** + * @param mixed $workspaces_count + */ + public function setWorkspacesCount($workspaces_count) + { + $this->workspaces_count = $workspaces_count; + } + + /** + * @return mixed + */ + public function getPrivilegesCapabilitiesLastRead() + { + return $this->privileges_capabilities_last_update; + } + + /** + * @param mixed $privileges_capabilities_last_update + */ + public function setPrivilegesCapabilitiesLastRead($privileges_capabilities_last_update) + { + $this->privileges_capabilities_last_update = $privileges_capabilities_last_update; + } + + /** + * @return mixed + */ + public function getPrivileges() + { + return json_decode($this->privileges, true); + } + + /** + * @param mixed $privileges + */ + public function setPrivileges($privileges) + { + $this->privileges = json_encode($privileges); + } + + /** + * @return mixed + */ + public function getCapabilities() + { + return json_decode($this->capabilities, true); + } + + /** + * @param mixed $capabilities + */ + public function setCapabilities($capabilities) + { + $this->capabilities = json_encode($capabilities); + } + + /** + * @return mixed + */ + public function getHooks() + { + if (!$this->hooks) { + return Array(); + } + return json_decode($this->hooks, true); + } + + /** + * @param mixed $hooks + */ + public function setHooks($hooks) + { + $this->hooks = json_encode($hooks); + } + + +} diff --git a/twake/backend/core/src/Twake/Workspaces/Entity/GroupUser.php b/twake/backend/core/src/Twake/Workspaces/Entity/GroupUser.php new file mode 100755 index 00000000..323251a1 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Entity/GroupUser.php @@ -0,0 +1,346 @@ +<?php + +namespace Twake\Workspaces\Entity; + +use Doctrine\ORM\Mapping as ORM; + + +/** + * GroupUser + * + * @ORM\Table(name="group_user",options={"engine":"MyISAM", "scylladb_keys": {{"group_id":"ASC", "user_id":"DESC", "id":"ASC"} , {"user_id":"DESC"}}}) + * @ORM\Entity() + */ +class GroupUser +{ + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + protected $id; + + /** + * @ORM\ManyToOne(targetEntity="Twake\Users\Entity\User") + * @ORM\Id + */ + protected $user; + + /** + * @ORM\ManyToOne(targetEntity="Twake\Workspaces\Entity\Group") + * @ORM\Id + */ + protected $group; + + /** + * @ORM\Column(name="level", type="integer") + */ + protected $level; + + /** + * @ORM\Column(name="did_connect_today", type="twake_boolean") + */ + private $didconnecttoday; + + /** + * @ORM\Column(name="is_externe", type="twake_boolean") + */ + private $externe; + + /** + * @ORM\Column(name="role", type="string", length=10) + */ + private $role = "member"; //"guest" | "admin" | "member" + + /** + * @ORM\Column(name="app_used_today", type="string", length=100000) + */ + protected $usedappstoday; + + /** + * @ORM\Column(name="nb_workspace", type="integer") + */ + protected $nbworkspace; + + /** + * @ORM\Column(type="twake_datetime") + */ + private $date_added; + + /** + * @ORM\Column(name="last_update_day", type="integer") + */ + protected $lastdayofupdate; + + /** + * @ORM\Column(name="nb_connections_period", type="integer") + */ + protected $connectionsperiod; + + /** + * @ORM\Column(name="app_used_period", type="string", length=100000) + */ + protected $appsusage_period; + + /** + * @ORM\Column(type="twake_boolean") + */ + private $hasnotifications = false; + + public function __construct($group, $user) + { + $this->group = $group; + $this->user = $user; + + $this->level = 0; + $this->date_added = new \DateTime(); + $this->nbworkspace = 0; + $this->didconnecttoday = false; + $this->usedappstoday = "[]"; + $this->lastdayofupdate = date('z') + 1; + $this->connectionsperiod = 0; + $this->appsusage_period = "[]"; + $this->externe = false; + } + + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getUser() + { + return $this->user; + } + + /** + * @return mixed + */ + public function getGroup() + { + return $this->group; + } + + /** + * @return mixed + */ + public function getLevel() + { + if($this->getRole() == "admin" || $this->getRole() == "owner"){ + return 2; + } + if($this->getRole() == "member"){ + return 1; + } + if($this->getRole() == "guest"){ + return 0; + } + return $this->level; + } + + /** + * @param mixed $level + */ + public function setLevel($level) + { + if($level > 1){ + $this->setRole("admin"); + }else if($this->getRole() !== "guest"){ + $this->setRole("member"); + } + $this->level = $level; + } + + /** + * @return mixed + */ + public function getRole() + { + return $this->role; + } + + /** + * @param mixed $level + */ + public function setRole($role) + { + $this->role = $role; + } + + /** + * @return mixed + */ + public function getNbWorkspace() + { + return $this->nbworkspace; + } + + /** + * @return mixed + */ + public function getConnectionsPeriod() + { + return $this->connectionsperiod; + } + + /** + * @param mixed $connectionsperiod + */ + public function setConnectionsPeriod($connectionsperiod) + { + $this->connectionsperiod = $connectionsperiod; + } + + /** + * @return mixed $connectionPeriod+1 + */ + public function increaseConnectionsPeriod() + { + return $this->connectionsperiod = $this->connectionsperiod + 1; + } + + + /** + * @param mixed $nbworkspace + */ + public function setNbWorkspace($nbworkspace) + { + $this->nbworkspace = $nbworkspace; + } + + public function increaseNbWorkspace() + { + return $this->nbworkspace = $this->nbworkspace + 1; + } + + public function decreaseNbWorkspace() + { + if ($this->nbworkspace == 0) { + return $this->nbworkspace; + } else { + return $this->nbworkspace = $this->nbworkspace - 1; + } + } + + /** + * @return mixed + */ + public function getLastDayOfUpdate() + { + if ($this->lastdayofupdate == 0) { + return date('z') + 1; + } + return $this->lastdayofupdate; + } + + /** + * @param mixed $lastdayofupdate + */ + public function setLastDayOfUpdate($lastdayofupdate) + { + $this->lastdayofupdate = $lastdayofupdate; + } + + /** + * @return mixed + */ + public function getAppsUsagePeriod() + { + if ($this->appsusage_period == null) { + return Array(); + } + return json_decode($this->appsusage_period, true); + } + + /** + * @param mixed $appsusage_period + */ + public function setAppsUsagePeriod($appsusage_period) + { + $this->appsusage_period = json_encode($appsusage_period); + } + + /** + * @return mixed + */ + public function getUsedAppsToday() + { + if ($this->usedappstoday == null) { + return Array(); + } + return json_decode($this->usedappstoday, true); + } + + /** + * @param mixed $usedapps + */ + public function setUsedAppsToday($usedapps) + { + $this->usedappstoday = json_encode($usedapps); + } + + /** + * @return mixed + */ + public function getDidConnectToday() + { + if ($this->didconnecttoday == null) { + return false; + } + return $this->didconnecttoday; + } + + /** + * @param mixed $didconnecttoday + */ + public function setDidConnectToday($didconnecttoday) + { + $this->didconnecttoday = $didconnecttoday; + } + + /** + * @return mixed + */ + public function getExterne() + { + return $this->externe; + } + + /** + * @param mixed $isclient + */ + public function setExterne($externe) + { + if($externe){ + $this->setRole("guest"); + } + $this->externe = $externe; + } + + /** + * @return mixed + */ + public function getHasNotifications() + { + return $this->hasnotifications; + } + + /** + * @param mixed $hasnotifications + */ + public function setHasNotifications($hasnotifications) + { + $this->hasnotifications = $hasnotifications; + } + + +} diff --git a/twake/backend/core/src/Twake/Workspaces/Entity/Workspace.php b/twake/backend/core/src/Twake/Workspaces/Entity/Workspace.php new file mode 100755 index 00000000..904b20f4 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Entity/Workspace.php @@ -0,0 +1,374 @@ +<?php + +namespace Twake\Workspaces\Entity; + +use Doctrine\ORM\Mapping as ORM; + +use Twake\Core\Entity\SearchableObject; + + +/** + * Workspace + * + * @ORM\Table(name="workspaces",options={"engine":"MyISAM", "scylladb_keys": {{"company_id":"ASC", "id":"ASC"}, {"id":"ASC"}}}) + * @ORM\Entity() + */ +class Workspace extends SearchableObject +{ + + protected $es_type = "workspace"; + + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="company_id", type="twake_timeuuid") + * @ORM\Id + */ + private $group; + + /** + * @ORM\Column(name="name", type="twake_no_salt_text", nullable=true) + */ + private $name; + + /** + * @ORM\Column(name="logo", type="twake_text") + */ + private $logo; + + /** + * @ORM\Column(name="stats", type="twake_text") + */ + protected $stats; + + + // Twake without console fields below + + + /** + * @ORM\Column(name="isdeleted", type="twake_boolean") + */ + private $isdeleted = false; + + /** + * @ORM\Column(name="isarchived", type="twake_boolean") + */ + private $isarchived = false; + + /** + * @ORM\Column(name="isdefault", type="twake_boolean") + */ + private $isdefault = false; + + /** + * @ORM\ManyToOne(targetEntity="Twake\Upload\Entity\File") + * @ORM\JoinColumn(name="logo_id") + */ + private $logofile; + + /** + * @ORM\Column(name="uniquename", type="twake_no_salt_text", nullable=true) + */ + private $uniquename; + + /** + * @ORM\Column(name="member_count", type="integer") + */ + private $member_count = 0; + + /** + * @ORM\Column(name="guest_count", type="integer") + */ + private $guest_count = 0; + + /** + * @ORM\Column(name="pending_count", type="integer") + */ + private $pending_count = 0; + + /** + * @ORM\Column(type="twake_datetime") + */ + private $date_added; + + /** + * @ORM\OneToMany(targetEntity="Twake\Workspaces\Entity\WorkspaceUser", mappedBy="workspace") + */ + private $members; + + /** + * Workspace constructor. + * @param $name + */ + public function __construct($name) + { + $this->name = $name; + $this->date_added = new \DateTime(); + } + + public function getIndexationArray() + { + $return = Array( + "id" => $this->getId() . "", + "name" => $this->getName(), + "company_id" => $this->getGroup(), + "creation_date" => ($this->getDateAdded() ? $this->getDateAdded()->format('Y-m-d') : null), + ); + return $return; + } + + /** + * @return string + */ + public function getEsType() + { + return $this->es_type; + } + + /** + * @param string $es_type + */ + public function setEsType($es_type) + { + $this->es_type = $es_type; + } + + + /** + * @return int + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getDateAdded() + { + return $this->date_added; + } + + /** + * @return mixed + */ + public function getName() + { + return $this->name; + } + + /** + * @param mixed $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @return mixed + */ + public function getUniqueName() + { + return $this->uniquename; + } + + /** + * @param mixed $name + */ + public function setUniqueName($name) + { + $this->uniquename = $name; + } + + /** + * @return mixed + */ + public function getLogoFile() + { + return $this->logofile; + } + + /** + * @return mixed + */ + public function getLogo() + { + if(!$this->logo){ + $this->setLogo($this->getLogoFile() ? $this->getLogoFile()->getPublicURL(2) : ""); + } + return $this->logo ?: ""; + } + + /** + * @param mixed $logo + */ + public function setLogo($logo) + { + $this->logo = $logo; + } + + /** + * @return mixed + */ + public function getGroup() + { + return $this->group; + } + + public function getGroupEntity($em) + { + $groupRepository = $em->getRepository("Twake\Workspaces:Group"); + return $groupRepository->findOneBy(Array("id" => $this->getGroup())); + } + + /** + * @param mixed $group + */ + public function setGroup($group) + { + $this->group = $group; + } + + /** + * @return mixed + */ + public function getIsDeleted() + { + return $this->isdeleted; + } + + /** + * @param mixed $isdeleted + */ + public function setIsDeleted($isdeleted) + { + $this->isdeleted = $isdeleted; + } + + /** + * @return mixed + */ + public function getMembers() + { + return $this->members; + } + + /** + * @return mixed + */ + public function getMemberCount() + { + if (!$this->member_count || $this->member_count < 0) { + return 0; + } + return $this->member_count; + } + + /** + * @param mixed $member_count + */ + public function setMemberCount($member_count) + { + $this->member_count = $member_count; + } + + public function getGuestCount() + { + if (!$this->guest_count || $this->guest_count < 0) { + return 0; + } + return $this->guest_count; + } + + public function setGuestCount($guest_count) + { + $this->guest_count = $guest_count; + } + + public function getPendingCount() + { + if (!$this->pending_count || $this->pending_count < 0) { + return 0; + } + return $this->pending_count; + } + + public function setPendingCount($pending_count) + { + $this->pending_count = $pending_count; + } + + /** + * @return mixed + */ + public function getIsArchived() + { + return $this->isarchived; + } + + /** + * @param mixed $isarchived + */ + public function setIsArchived($isarchived) + { + $this->isarchived = $isarchived; + } + + /** + * @return mixed + */ + public function getIsDefault() + { + return $this->isdefault; + } + + /** + * @param mixed $isnew + */ + public function setIsDefault($default) + { + $this->isdefault = $default; + } + + + public function getAsArray($em = null) + { + + if($em){ + $group = $em->getRepository("Twake\Workspaces:Group")->findOneBy(["id" => $this->getGroup()]); + } + + return Array( + "id" => $this->getId(), + "company_id" => $this->getGroup(), + "name" => $this->getName(), + "logo" => $this->getLogo(), + + "default" => $this->getIsDefault(), + "archived" => $this->getIsArchived(), + + "stats" => [ + "created_at" => $this->date_added ? ($this->date_added->getTimestamp() * 1000) : 0, + "total_members" => $this->getMemberCount(), + "total_guests" => $this->getGuestCount(), + "total_pending" => $this->getPendingCount(), + ], + + "group" => ($group ? $group->getAsArray() : null), + ); + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Workspaces/Entity/WorkspaceActivity.php b/twake/backend/core/src/Twake/Workspaces/Entity/WorkspaceActivity.php new file mode 100755 index 00000000..8cff1a28 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Entity/WorkspaceActivity.php @@ -0,0 +1,174 @@ +<?php + +namespace Twake\Workspaces\Entity; + + +use Doctrine\ORM\Mapping as ORM; + + +/** + * WorkspacesActivities + * + * @ORM\Table(name="workspace_activity",options={"engine":"MyISAM"}) + * @ORM\Entity() + */ +class WorkspaceActivity +{ + + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="workspace_id", type="twake_timeuuid") + */ + private $workspace; + + /** + * @ORM\ManyToOne(targetEntity="Twake\Users\Entity\User") + */ + private $user; + + /** + * @ORM\ManyToOne(targetEntity="Twake\Market\Entity\Application") + */ + private $app; + + /** + * @ORM\Column(type="twake_datetime") + */ + private $date_added; + + /** + * @ORM\Column(type="string") + */ + private $title; + + /** + * @ORM\Column(type="string", nullable=true) + */ + private $objectrepository; + + /** + * @ORM\Column(type="twake_timeuuid", nullable=true) + */ + private $objectid = 0; + + public function __construct($workspace, $user, $app, $title, $objectrepository, $objectid) + { + $this->workspace = $workspace; + $this->date_added = new \DateTime(); + $this->user = $user; + $this->app = $app; + $this->title = $title; + $this->objectrepository = $objectrepository; + $this->objectid = $objectid; + } + + /** + * @return int + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getWorkspace() + { + return $this->workspace; + } + + /** + * @return mixed + */ + public function getDateAdded() + { + return $this->date_added; + } + + /** + * @return mixed + */ + public function getApp() + { + return $this->app; + } + + /** + * @param mixed $app + */ + public function setApp($app) + { + $this->app = $app; + } + + /** + * @return mixed + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param mixed $title + */ + public function setTitle($title) + { + $this->title = $title; + } + + /** + * @return mixed + */ + public function getUser() + { + return $this->user; + } + + /** + * @param mixed $user + */ + public function setUser($user) + { + $this->user = $user; + } + + + /** + * @return mixed + */ + public function getObjectId() + { + return $this->objectid; + } + + /** + * @param mixed $objectid + */ + public function setObjectId($objectid) + { + $this->objectid = $objectid; + } + + /** + * @return mixed + */ + public function getObjectRepository() + { + return $this->objectrepository; + } + +} diff --git a/twake/backend/core/src/Twake/Workspaces/Entity/WorkspaceApp.php b/twake/backend/core/src/Twake/Workspaces/Entity/WorkspaceApp.php new file mode 100755 index 00000000..baf5a1a4 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Entity/WorkspaceApp.php @@ -0,0 +1,110 @@ +<?php + +namespace Twake\Workspaces\Entity; + + +use Doctrine\ORM\Mapping as ORM; + + +/** + * WorkspaceApp + * + * @ORM\Table(name="workspace_app",options={"engine":"MyISAM", "scylladb_keys": {{"workspace_id": "ASC", "groupapp_id": "ASC", "app_id": "ASC", "id":"ASC"}, {"groupapp_id": "ASC"}, {"id":"ASC"}}}) + * @ORM\Entity() + */ +class WorkspaceApp +{ + + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="workspace_id", type="twake_timeuuid") + * @ORM\Id + */ + private $workspace_id; + + /** + * @ORM\Column(name="groupapp_id", type="twake_timeuuid") + * @ORM\Id + */ + private $groupapp_id; + + /** + * @ORM\Column(name="app_id", type="twake_timeuuid") + * @ORM\Id + */ + private $app_id; + + /** + * @ORM\Column(type="twake_datetime") + */ + private $date_added; + + public function __construct($workspace_id, $groupapp_id, $app_id) + { + $this->workspace_id = $workspace_id; + $this->groupapp_id = $groupapp_id; + $this->app_id = $app_id; + $this->date_added = new \DateTime(); + } + + /** + * @return int + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getWorkspace() + { + return $this->workspace_id; + } + + /** + * @return mixed + */ + public function getGroupApp() + { + return $this->groupapp; + } + + /** + * @return mixed + */ + public function getDateAdded() + { + return $this->date_added; + } + + /** + * @return mixed + */ + public function getAppId() + { + return $this->app_id; + } + + /** + * @param mixed $app_id + */ + public function setAppId($app_id) + { + $this->app_id = $app_id; + } + +} diff --git a/twake/backend/core/src/Twake/Workspaces/Entity/WorkspaceLevel.php b/twake/backend/core/src/Twake/Workspaces/Entity/WorkspaceLevel.php new file mode 100755 index 00000000..8642d75c --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Entity/WorkspaceLevel.php @@ -0,0 +1,159 @@ +<?php +namespace Twake\Workspaces\Entity; + + +use Doctrine\ORM\Mapping as ORM; + + +/** + * WorkspaceLevel + * + * @ORM\Table(name="workspace_level",options={"engine":"MyISAM", "scylladb_keys": {{"workspace_id":"ASC","id":"ASC"}} } ) + * @ORM\Entity() + */ +class WorkspaceLevel +{ + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + protected $id; + + /** + * @ORM\Column(name="label", type="twake_no_salt_text") + */ + protected $label; + + /** + * @ORM\Column(name="workspace_id", type="twake_timeuuid") + * @ORM\Id + */ + protected $workspace_id; + + /** + * @ORM\Column(name="rights", type="string", length=100000) + */ + protected $rights; + + /** + * @ORM\Column(name="is_default", type="twake_boolean", length=1) + */ + protected $isdefault = false; + + /** + * @ORM\Column(name="is_admin", type="twake_boolean", length=1) + */ + protected $isadmin = false; + + + function __construct() + { + $this->rights = "{}"; + } + + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getLabel() + { + return $this->label; + } + + /** + * @param mixed $label + */ + public function setLabel($label) + { + $this->label = $label; + } + + /** + * @return mixed + */ + public function getWorkspace() + { + return $this->workspace_id; + } + + /** + * @param mixed $workspace_id + */ + public function setWorkspace($workspace_id) + { + $this->workspace_id = $workspace_id; + } + + /** + * @return mixed + */ + public function getRights() + { + return json_decode($this->rights, true); + } + + /** + * @param mixed $rights + */ + public function setRights($rights) + { + $this->rights = json_encode($rights); + } + + /** + * @return mixed + */ + public function getIsDefault() + { + return $this->isdefault; + } + + /** + * @param mixed $isdefault + */ + public function setIsDefault($isdefault) + { + $this->isdefault = $isdefault; + } + + /** + * @return mixed + */ + public function getIsAdmin() + { + return $this->isadmin; + } + + /** + * @param mixed $isadmin + */ + public function setIsAdmin($isadmin) + { + $this->isadmin = $isadmin; + } + + + public function getAsArray() + { + return Array( + "id" => $this->getId(), + "name" => $this->getLabel(), + "admin" => $this->getIsAdmin(), + "default" => $this->getIsDefault(), + "rights" => $this->getRights() + ); + } +} + +?> diff --git a/twake/backend/core/src/Twake/Workspaces/Entity/WorkspaceUser.php b/twake/backend/core/src/Twake/Workspaces/Entity/WorkspaceUser.php new file mode 100755 index 00000000..5384c43b --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Entity/WorkspaceUser.php @@ -0,0 +1,284 @@ +<?php + +namespace Twake\Workspaces\Entity; + + +use Doctrine\ORM\Mapping as ORM; + + +/** + * WorkspaceUser + * + * @ORM\Table(name="workspace_user",options={"engine":"MyISAM", "scylladb_keys": {{"workspace_id":"ASC", "user_id": "DESC", "id":"ASC"}, {"level_id":"ASC"}, {"user_id": "DESC"}} }) + * @ORM\Entity() + */ +class WorkspaceUser +{ + + /** + * @var int + * + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="workspace_id", type="twake_timeuuid") + * @ORM\Id + */ + private $workspace_id; + + /** + * @ORM\Column(name="user_id", type="twake_timeuuid") + * @ORM\Id + */ + private $user_id; + + /** + * @ORM\Column(name="role", type="string") + */ + private $role = "member"; // "member" | "moderator" + + /** + * @ORM\Column(name="level_id", type="twake_timeuuid") + */ + private $level_id; //Depreciated + + /** + * @ORM\Column(type="twake_datetime") + */ + private $date_added; + + /** + * @ORM\Column(type="twake_datetime", options={"default" : "1970-01-02"}) + */ + private $last_access; + + /** + * @ORM\Column(type="twake_boolean") + */ + private $hasnotifications = false; + + /** + * @ORM\Column(name="is_externe", type="twake_boolean") + */ + private $externe; + + /** + * @ORM\Column(name="is_auto_add_externe", type="twake_boolean") + */ + private $auto_add_externe; + + public function __construct($workspace, $user, $level_id) + { + $this->workspace_id = $workspace->getId(); + $this->user_id = $user->getId(); + + $this->level_id = $level_id; + $this->date_added = new \DateTime(); + $this->last_access = new \DateTime(); + } + + /** + * @return int + */ + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getWorkspace($em) + { + $workspacesRepository = $em->getRepository("Twake\Workspaces:Workspace"); + return $workspacesRepository->findOneBy(["id"=>$this->workspace_id]); + } + + /** + * @return mixed + */ + public function getWorkspaceId() + { + return $this->workspace_id; + } + + /** + * @return mixed + */ + public function getUser($em) + { + $repo = $em->getRepository("Twake\Users:User"); + return $repo->find($this->user_id); + } + + /** + * @return mixed + */ + public function getUserId() + { + return $this->user_id; + } + + /** + * @return mixed + */ + public function getRole() + { + return $this->role ?: "member"; + } + + /** + * @param mixed $level + */ + public function setRole($role) + { + $this->role = $role; + } + + /** + * @return mixed + */ + public function getLevelId() + { + return $this->level_id; + } + + /** + * @param mixed $level + */ + public function setLevelId($level) + { + $this->level_id = $level; + } + + /** + * @return mixed + */ + public function getDateAdded() + { + return $this->date_added; + } + + /** + * @return mixed + */ + public function getLastAccess() + { + return $this->last_access; + } + + /** + * @param mixed $last_access + */ + public function setLastAccess() + { + $this->last_access = new \DateTime(); + } + + /** + * @return mixed + */ + public function getisHidden() + { + //return $this->ishidden; + } + + /** + * @param mixed $ishidden + */ + public function setIsHidden($ishidden) + { + //$this->ishidden = $ishidden; + } + + /** + * @return mixed + */ + public function getisFavorite() + { + //return $this->isfavorite; + } + + /** + * @param mixed $isfavorite + */ + public function setIsFavorite($isfavorite) + { + //$this->isfavorite = $isfavorite; + } + + /** + * @return mixed + */ + public function getHasNotifications() + { + return $this->hasnotifications; + } + + /** + * @param mixed $hasnotifications + */ + public function setHasNotifications($hasnotifications) + { + $this->hasnotifications = $hasnotifications; + } + + /** + * @return mixed + */ + public function getExterne() + { + return $this->externe; + } + + /** + * @param mixed $isclient + */ + public function setExterne($externe) + { + $this->externe = $externe; + } + + /** + * @return mixed + */ + public function getAutoAddExterne() + { + return $this->auto_add_externe; + } + + /** + * @param mixed $isclient + */ + public function setAutoAddExterne($auto_add_externe) + { + $this->auto_add_externe = $auto_add_externe; + } + + public function getAsArray($em) + { + return Array( + "id" => $this->getId(), + "user" => $this->getUser($em), + "user_id" => $this->getUserId(), + "workspace_id" => $this->getWorkspaceId(), + "workspace" => $this->getWorkspace($em), + "role" => $this->getRole(), + "level_id" => $this->getLevelId(), + "date_added" => $this->getDateAdded(), + "last_access" => $this->getLastAccess(), + "hasnotifications" => $this->getHasNotifications(), + "externe" => $this->getExterne(), + "auto_add_externe" => $this->getAutoAddExterne() + ); + } + +} diff --git a/twake/backend/core/src/Twake/Workspaces/Entity/WorkspaceUserByMail.php b/twake/backend/core/src/Twake/Workspaces/Entity/WorkspaceUserByMail.php new file mode 100755 index 00000000..c600433e --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Entity/WorkspaceUserByMail.php @@ -0,0 +1,123 @@ +<?php +namespace Twake\Workspaces\Entity; + + +use Doctrine\ORM\Mapping as ORM; + + +/** + * WorkspaceUserByMail + * + * @ORM\Table(name="workspace_user_by_mail",options={"engine":"MyISAM", "scylladb_keys": {{"workspace_id":"ASC", "mail": "DESC", "id":"ASC"}, {"id":"ASC"}, {"mail":"ASC"}}}) + * @ORM\Entity() + */ +class WorkspaceUserByMail +{ + /** + * @ORM\Column(name="id", type="twake_timeuuid") + * @ORM\Id + */ + private $id; + + /** + * @ORM\Column(name="workspace_id", type="twake_timeuuid") + * @ORM\Id + */ + private $workspace_id; + + /** + * @ORM\Column(name="mail", type="string", length=255) + * @ORM\Id + */ + private $mail; + + /** + * @ORM\Column(name="is_externe", type="twake_boolean") + */ + private $externe; + + /** + * @ORM\Column(name="is_auto_add_externe", type="twake_boolean") + */ + private $is_auto_add_externe; + + + function __construct($workspace, $mail) + { + $this->workspace_id = $workspace->getId(); + $this->mail = $mail; + $this->externe = false; + $this->is_auto_add_externe = false; + } + + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getWorkspace($em) + { + $workspacesRepository = $em->getRepository("Twake\Workspaces:Workspace"); + return $workspacesRepository->findOneBy(["id"=>$this->workspace_id]); + } + + /** + * @return mixed + */ + public function getWorkspaceId() + { + return $this->workspace_id; + } + + /** + * @return mixed + */ + public function getMail() + { + return $this->mail; + } + + /** + * @return mixed + */ + public function getExterne() + { + return $this->externe; + } + + /** + * @param mixed $isclient + */ + public function setExterne($externe) + { + $this->externe = $externe; + } + + /** + * @return mixed + */ + public function getAutoAddExterne() + { + return $this->is_auto_add_externe; + } + + /** + * @param mixed $isclient + */ + public function setAutoAddExterne($externe) + { + $this->is_auto_add_externe = $externe; + } + + +} + +?> diff --git a/twake/backend/core/src/Twake/Workspaces/Resources/Routing.php b/twake/backend/core/src/Twake/Workspaces/Resources/Routing.php new file mode 100755 index 00000000..d0b94f55 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Resources/Routing.php @@ -0,0 +1,72 @@ +<?php + +namespace Twake\Workspaces\Resources; + +use Common\BaseRouting; + +class Routing extends BaseRouting +{ + + protected $routing_prefix = "ajax/workspace/"; + + protected $routes = [ + "get" => ["handler" => "Workspace:getAction", "methods" => ["POST"], "security" => ["user_connected_security"]], + "get_public_data" => ["handler" => "Workspace:getPublicData", "methods" => ["POST"]], + "create" => ["handler" => "Workspace:create", "methods" => ["POST"], "security" => ["user_connected_security"]], + "duplicate" => ["handler" => "Workspace:duplicate", "methods" => ["POST"], "security" => ["user_connected_security"]], + "delete" => ["handler" => "Workspace:delete", "methods" => ["POST"], "security" => ["user_connected_security"]], + "archive" => ["handler" => "Workspace:archiveWorkspace", "methods" => ["POST"], "security" => ["user_connected_security"]], + "unarchive" => ["handler" => "Workspace:unarchiveWorkspace", "methods" => ["POST"], "security" => ["user_connected_security"]], + "hideOrNot" => ["handler" => "Workspace:hideOrUnhideWorkspace", "methods" => ["POST"], "security" => ["user_connected_security"]], + "favorite" => ["handler" => "Workspace:favoriteOrUnfavoriteWorkspace", "methods" => ["POST"], "security" => ["user_connected_security"]], + "notifications" => ["handler" => "Workspace:haveNotificationsOrNotWorkspace", "methods" => ["POST"], "security" => ["user_connected_security"]], + "set/isNew" => ["handler" => "Workspace:setIsNew", "methods" => ["POST"], "security" => ["user_connected_security"]], +# Edit workspace data + + "data/name" => ["handler" => "WorkspaceData:setName", "methods" => ["POST"], "security" => ["user_connected_security"]], + "data/logo" => ["handler" => "WorkspaceData:setLogo", "methods" => ["POST"], "security" => ["user_connected_security"]], + "data/wallpaper" => ["handler" => "WorkspaceData:setWallpaper", "methods" => ["POST"], "security" => ["user_connected_security"]], + "getByName" => ["handler" => "Workspace:getWorkspaceByName", "methods" => ["POST"], "security" => ["user_connected_security"]], +# Apps + + "apps/getModuleApps" => ["handler" => "Workspace:getModuleApps", "methods" => ["POST"], "security" => ["user_connected_security"]], + "apps/get" => ["handler" => "Workspace:getApps", "methods" => ["POST"], "security" => ["user_connected_security"]], + "apps/enable" => ["handler" => "Workspace:enableApp", "methods" => ["POST"], "security" => ["user_connected_security"]], + "apps/disable" => ["handler" => "Workspace:disableApp", "methods" => ["POST"], "security" => ["user_connected_security"]], +# Groups + "group/getUsers" => ["handler" => "Group:getUsers", "methods" => ["POST"], "security" => ["user_connected_security"]], + "group/edit" => ["handler" => "Group:editUser", "methods" => ["POST"], "security" => ["user_connected_security"]], + "group/removeUser" => ["handler" => "Group:removeUser", "methods" => ["POST"], "security" => ["user_connected_security"]], + "group/data/name" => ["handler" => "Group:changeName", "methods" => ["POST"], "security" => ["user_connected_security"]], + "group/data/logo" => ["handler" => "Group:setLogo", "methods" => ["POST"], "security" => ["user_connected_security"]], + "group/getWorkspaces" => ["handler" => "Group:getWorkspaces", "methods" => ["POST"], "security" => ["user_connected_security"]], + "group/app/use" => ["handler" => "GroupApps:useApp", "methods" => ["POST"], "security" => ["user_connected_security"]], + "group/apps/get" => ["handler" => "GroupApps:getApps", "methods" => ["POST"], "security" => ["user_connected_security"]], + "group/workspacedefault/set" => ["handler" => "GroupApps:setWorkspaceDefault", "methods" => ["POST"], "security" => ["user_connected_security"]], + "group/application/force" => ["handler" => "GroupApps:forceApplication", "methods" => ["POST"], "security" => ["user_connected_security"]], + "group/application/remove" => ["handler" => "GroupApps:removeApplication", "methods" => ["POST"], "security" => ["user_connected_security"]], + "group/manager/get" => ["handler" => "GroupManager:getManagers", "methods" => ["POST"], "security" => ["user_connected_security"]], + "group/manager/add" => ["handler" => "GroupManager:addManagers", "methods" => ["POST"], "security" => ["user_connected_security"]], + "group/manager/remove" => ["handler" => "GroupManager:removeManagers", "methods" => ["POST"], "security" => ["user_connected_security"]], + "group/manager/edit" => ["handler" => "GroupManager:editManagers", "methods" => ["POST"], "security" => ["user_connected_security"]], + "group/manager/toggleManager" => ["handler" => "GroupManager:toggleManager", "methods" => ["POST"], "security" => ["user_connected_security"]], +# Edit members + + "members/list" => ["handler" => "WorkspaceMembers:getMembers", "methods" => ["POST"], "security" => ["user_connected_security"]], + "members/pending" => ["handler" => "WorkspaceMembers:getPending", "methods" => ["POST"], "security" => ["user_connected_security"]], + "members/addlist" => ["handler" => "WorkspaceMembers:addList", "methods" => ["POST"], "security" => ["user_connected_security"]], + "members/removemail" => ["handler" => "WorkspaceMembers:removeMail", "methods" => ["POST"], "security" => ["user_connected_security"]], + "members/remove" => ["handler" => "WorkspaceMembers:removeMembers", "methods" => ["POST"], "security" => ["user_connected_security"]], + "members/changelevel" => ["handler" => "WorkspaceMembers:changeMembersLevel", "methods" => ["POST"], "security" => ["user_connected_security"]], +#Levels + + "levels/list" => ["handler" => "WorkspaceLevels:getLevels", "methods" => ["POST"], "security" => ["user_connected_security"]], + "levels/create" => ["handler" => "WorkspaceLevels:createLevel", "methods" => ["POST"], "security" => ["user_connected_security"]], + "levels/delete" => ["handler" => "WorkspaceLevels:deleteLevel", "methods" => ["POST"], "security" => ["user_connected_security"]], + "levels/edit" => ["handler" => "WorkspaceLevels:editLevel", "methods" => ["POST"], "security" => ["user_connected_security"]], + "levels/default" => ["handler" => "WorkspaceLevels:makeDefaulLevel", "methods" => ["POST"], "security" => ["user_connected_security"]], + "levels/getByLabel" => ["handler" => "WorkspaceLevels:getByLabel", "methods" => ["POST"], "security" => ["user_connected_security"]], + "members/getWorkspaces" => ["handler" => "WorkspaceMembers:getWorkspaces", "methods" => ["POST"], "security" => ["user_connected_security"]], + ]; + +} diff --git a/twake/backend/core/src/Twake/Workspaces/Resources/Services.php b/twake/backend/core/src/Twake/Workspaces/Resources/Services.php new file mode 100755 index 00000000..26b59cac --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Resources/Services.php @@ -0,0 +1,21 @@ +<?php + +namespace Twake\Workspaces\Resources; + +use Common\BaseServices; + +class Services extends BaseServices +{ + + protected $services = [ + "app.group_managers" => "GroupManagers", + "app.groups" => "Groups", + "app.group_apps" => "GroupApps", + "app.workspace_levels" => "WorkspaceLevels", + "app.workspace_members" => "WorkspaceMembers", + "app.workspaces" => "Workspaces", + "app.workspaces_activities" => "WorkspacesActivities", + "app.workspaces_apps" => "WorkspacesApps", + ]; + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Workspaces/Services/GroupApps.php b/twake/backend/core/src/Twake/Workspaces/Services/GroupApps.php new file mode 100755 index 00000000..5dc80923 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Services/GroupApps.php @@ -0,0 +1,178 @@ +<?php + +namespace Twake\Workspaces\Services; + +use App\App; +use Twake\Workspaces\Model\GroupAppsInterface; + +class GroupApps +{ + private $doctrine; + private $gms; + private $was; + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->gms = $app->getServices()->get("app.group_managers"); + $this->was = $app->getServices()->get("app.workspaces_apps"); + } + + public function getApps($groupId, $currentUserId = null) + { + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $group = $groupRepository->find($groupId); + + if ($group == null) { + return false; + } + + if ($currentUserId == null + || $this->gms->hasPrivileges( + $this->gms->getLevel($groupId, $currentUserId), + "MANAGE_APPS" + ) + ) { + //Group apps + $groupappsRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupApp"); + $groupapps = $groupappsRepository->findBy(Array("group" => $group)); + + $applicationRepository = $this->doctrine->getRepository("Twake\Market:Application"); + + $apps = array(); + foreach ($groupapps as $ga) { + + $app = $applicationRepository->findOneBy(Array("id" => $ga->getAppId())); + + if (!$app) { + + $this->removeApplication($group->getId(), $ga->getAppId()); + + } else { + + $workspace_app = $ga->getAsArray(); + $workspace_app["app"] = $app->getAsArray(); + + $apps[] = $workspace_app; + + } + } + + return $apps; + } + + return false; + } + + public function removeApplication($groupId, $appid, $currentUserId = null) + { + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $group = $groupRepository->find($groupId); + + $applicationRepository = $this->doctrine->getRepository("Twake\Market:Application"); + $application = $applicationRepository->findOneBy(Array("id" => $appid)); + + if ($group == null || $application == null) { + return false; + } + + if ($currentUserId == null + || $this->gms->hasPrivileges( + $this->gms->getLevel($groupId, $currentUserId), + "MANAGE_APPS" + ) + ) { + + //Group apps + $groupappsRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupApp"); + $groupapp = $groupappsRepository->findOneBy(Array("group" => $group, "app_id" => $application->getId())); + + if (!$groupapp) { + return true; + } + + $workspaceAppsRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceApp"); + $workspace_apps = $workspaceAppsRepository->findBy(Array("groupapp_id" => $groupapp->getId())); + + foreach ($workspace_apps as $workspace_app) { + $this->was->disableApp($workspace_app->getWorkspace(), $application->getId()); + } + + return true; + } + + return false; + } + + public function setWorkspaceDefault($groupId, $appid, $boolean, $currentUserId = null) + { + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $group = $groupRepository->find($groupId); + + if ($group == null) { + return false; + } + + if ($currentUserId == null + || $this->gms->hasPrivileges( + $this->gms->getLevel($groupId, $currentUserId), + "MANAGE_APPS" + ) + ) { + //Group apps + $groupappsRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupApp"); + $groupapp = $groupappsRepository->findOneBy(Array("group" => $group, "app_id" => $appid)); + + $groupapp->setWorkspaceDefault($boolean); + $this->doctrine->persist($groupapp); + $this->doctrine->flush(); + + return true; + } + return false; + } + + //OLD CODE ? + + public function useApp($groupId, $workspaceId, $userId, $appid) + { + $groupUserRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + $groupuser = $groupUserRepository->findOneBy(Array("user" => $userId, "group" => $groupId)); + + $groupAppRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupApp"); + $groupApp = $groupAppRepository->findOneBy(Array("group" => $groupId, "app" => $appid)); + + if ($groupuser == null || $groupApp == null || $groupId == null) {//if no user or app not in group app's list or private workspace + return false; + } else { + + $appUsed = $groupuser->getUsedAppsToday(); + if (in_array($appid . "", $appUsed)) { + return true; + } else { + + if ($workspaceId) { + $workspaceUserRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + $workspaceUser = $workspaceUserRepository->findOneBy(Array("workspace_id" => $workspaceId, "user_id" => $userId)); + $workspaceUser->setLastAccess(); + $this->doctrine->persist($workspaceUser); + } + + if (!$groupuser->getDidConnectToday()) { + $groupuser->setDidConnectToday(true); + } + + $appUsed[] = $appid; + $groupuser->setUsedAppsToday($appUsed); + + $this->doctrine->persist($groupuser); + $this->doctrine->flush(); + return true; + } + } + + return false; + } + + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Workspaces/Services/GroupManagers.php b/twake/backend/core/src/Twake/Workspaces/Services/GroupManagers.php new file mode 100755 index 00000000..3f60f2bf --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Services/GroupManagers.php @@ -0,0 +1,356 @@ +<?php + +namespace Twake\Workspaces\Services; + +use App\App; +use Twake\Workspaces\Entity\GroupUser; +use Twake\Workspaces\Model\GroupManagersInterface; + + +class GroupManagers +{ + + var $doctrine; + var $privileges = Array( + 0 => Array("VIEW_USERS"), + 1 => Array("VIEW_USERS", + "VIEW_WORKSPACES", + "VIEW_MANAGERS", + "VIEW_APPS", + "VIEW_PRICINGS"), + 2 => Array("VIEW_USERS", + "VIEW_WORKSPACES", + "VIEW_MANAGERS", + "VIEW_APPS", + "VIEW_PRICINGS", + "MANAGE_USERS", + "MANAGE_WORKSPACES"), + 3 => Array("VIEW_USERS", + "VIEW_WORKSPACES", + "VIEW_MANAGERS", + "VIEW_APPS", + "VIEW_PRICINGS", + "MANAGE_USERS", + "MANAGE_WORKSPACES", + "MANAGE_MANAGERS", + "MANAGE_PRICINGS", + "MANAGE_APPS", + "MANAGE_DATA") + ); + private $twake_mailer; + private $pusher; + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->twake_mailer = $app->getServices()->get("app.twake_mailer"); + $this->pusher = $app->getServices()->get("app.pusher"); + } + + public function changeLevel($groupId, $userId, $level, $currentUserId = null) + { + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $groupManagerRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + + if ($currentUserId == null + || $this->hasPrivileges( + $this->getLevel($groupId, $currentUserId), + "MANAGE_MANAGERS" + ) + ) { + + $user = $userRepository->find($userId); + $group = $groupRepository->find($groupId); + $manager = $groupManagerRepository->findOneBy(Array("user" => $user, "group" => $group)); + + if ($manager) { + $manager->setLevel($level); + $this->doctrine->persist($manager); + $this->doctrine->flush(); + return true; + } + + } + + return false; + + } + + public function hasPrivileges($level, $privilege) + { + $privileges = $this->getPrivileges($level); + if ($privileges == null) { + return false; + } + return in_array($privilege, $privileges); + } + + public function getPrivileges($level) + { + if ($level === null) { + return null; + } + return $this->privileges[$level]; + } + + public function getLevel($groupId, $userId, $currentUserId = null) + { + + if ($userId == null) { + return 3; // If userId == null this is the system (all rights) + } + + /* + * If currentUserId == null then we are root (system) + * If we are the current user we can access our data + * Else we verify that we can look rights + */ + + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $groupManagerRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + + $user = $userRepository->find($userId); + $group = $groupRepository->find($groupId); + $manager = $groupManagerRepository->findOneBy(Array("user" => $user, "group" => $group)); + + if (!$manager || $manager->getExterne()) { + return null; //No rights + } + + return $manager->getLevel(); + + + } + + public function toggleManager($groupId, $userId, $isManager = null, $currentUserId = null) + { + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $groupManagerRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + + if ($currentUserId == null + || $this->hasPrivileges( + $this->getLevel($groupId, $currentUserId), + "MANAGE_MANAGERS" + ) + ) { + + $user = $userRepository->find($userId); + $group = $groupRepository->find($groupId); + $manager = $groupManagerRepository->findOneBy(Array("group" => $groupId, "user" => $userId)); + if (!$manager) { // not in group + return false; + } + if ($manager->getLevel() != null && $manager->getLevel() == 3 && $isManager != null && $isManager == true) { + // is already manager; + return true; + } + if ($manager->getLevel() == null && $isManager != null && $isManager == false) { + // is already not manager; + return true; + } + if ($manager->getLevel() == null) { // si l'utilisateur n'est pas manager + $manager->setLevel(3); + + $this->doctrine->persist($manager); + $this->doctrine->flush(); + + } else { + $groupUserRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + $otherPotentialGroupAdmin = $groupUserRepository->findBy(Array("group" => $groupId)); + $hasOtherAdmin = false; + foreach ($otherPotentialGroupAdmin as $potentialAdmin) { + if ($potentialAdmin->getLevel() == 3 && $potentialAdmin->getUser()->getId() != $userId) { + $hasOtherAdmin = true; + } + } + if (!$hasOtherAdmin) { + header("twake-debug: no other group admins"); + return false; + } + $manager->setLevel(null); + $this->doctrine->persist($manager); + $this->doctrine->flush(); + } + $dataToPush = Array( + "type" => "update_group_privileges", + "group_id" => $groupId, + "privileges" => $this->getPrivileges($this->getLevel($groupId, $userId)) + ); + $this->pusher->push($dataToPush, "workspaces_of_user/" . $userId); + + return true; + + } + return false; + } + + public function addManager($groupId, $userId, $level, $createdWorkspace, $currentUserId = null) + { + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $groupManagerRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + + if ($currentUserId == null + || $this->hasPrivileges( + $this->getLevel($groupId, $currentUserId), + "MANAGE_MANAGERS" + ) + ) { + + $user = $userRepository->find($userId); + $group = $groupRepository->find($groupId); + $manager = $groupManagerRepository->findOneBy(Array("user" => $user, "group" => $group)); + + + if (!$manager) { // si on a crΓ©e un workspace et qu'on s'y ajoute soi mΓͺme en admin + if ($createdWorkspace) { + $manager = new GroupUser($group, $user); + $manager->setLevel($level); + + $this->doctrine->persist($manager); + $this->doctrine->flush(); + + return true; + } else { + return false; + } + } else { + $manager->setLevel($level); + + $this->twake_mailer->send($user->getEmail(), "addedToGroupManagersMail", Array("_language" => $user ? $user->getLanguage() : "en", "group" => $group->getDisplayName(), "username" => $user->getUsername())); + + $this->doctrine->persist($manager); + $this->doctrine->flush(); + + return true; + } + + } + + return false; + } + + public function removeManager($groupId, $userId, $currentUserId = null) + { + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $groupManagerRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + + if ($currentUserId == $userId) { + return false; //Cant remove myself + } + + if ($currentUserId == null + || $this->hasPrivileges( + $this->getLevel($groupId, $currentUserId), + "MANAGE_MANAGERS" + ) + ) { + + $user = $userRepository->find($userId); + $group = $groupRepository->find($groupId); + $manager = $groupManagerRepository->findOneBy(Array("user" => $user, "group" => $group)); + + if (!$manager) { + return true; + } + + $manager->setLevel(0); + $this->doctrine->persist($manager); + $this->doctrine->flush(); + + return true; + + } + + return false; + } + + public function getManagers($groupId, $currentUserId = null) + { + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $groupManagerRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + + if ($currentUserId == null + || $this->hasPrivileges( + $this->getLevel($groupId, $currentUserId), + "VIEW_MANAGERS" + ) + ) { + + $group = $groupRepository->find($groupId); + $managerLinks = $groupManagerRepository->findBy(Array("group" => $group, "level" => 0)); + + $users = Array(); + foreach ($managerLinks as $managerLink) { + $users[] = Array( + "user" => $managerLink->getUser(), + "level" => $managerLink->getLevel() + ); + } + + return $users; + + } + + return false; + } + + public function getGroups($userId) + { + + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $groupManagerRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + + $user = $userRepository->find($userId); + $groupsLinks = $groupManagerRepository->findBy(Array("user" => $user)); + + $groups = Array(); + foreach ($groupsLinks as $groupLink) { + $groups[] = Array( + "group" => $groupLink->getGroup(), + "level" => $groupLink->getLevel() + ); + } + + return $groups; + } + + public function init($group) + { + $workspaces = $group->getWorkspaces(); + $groupManagerRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + $workspaceUserRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + + foreach ($workspaces as $workspace) { + $workspace = $workspace["workspace"]; + $members = $workspace->getMembers(); + + foreach ($members as $member) { + $userEntity = $member->getUser($this->doctrine); + $manager = $groupManagerRepository->findBy(Array("user" => $userEntity, "group" => $group)); + + if ($manager == null) { //si user n'est pas repertoriΓ© on l'ajoute au rang super-admin + + $wss = $workspaceUserRepository->findBy(Array("user_id" => $userEntity->getId())); + $nbWs = 0; + foreach ($wss as $ws) { + if ($ws->getWorkspace($this->doctrine)->getGroup() && $ws->getWorkspace($this->doctrine)->getGroup() == $group->getId()) { + $nbWs++; + } + } + + $newManager = new GroupUser($group, $userEntity); + $newManager->setLevel(3); + $newManager->setNbWorkspace($nbWs); + $this->doctrine->persist($newManager); + $this->doctrine->flush(); + } + } + } + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Workspaces/Services/Groups.php b/twake/backend/core/src/Twake/Workspaces/Services/Groups.php new file mode 100755 index 00000000..adf171fc --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Services/Groups.php @@ -0,0 +1,348 @@ +<?php + +namespace Twake\Workspaces\Services; + +use Twake\Workspaces\Entity\Group; +use Twake\Workspaces\Entity\GroupApp; +use Twake\Workspaces\Entity\GroupManager; +use Twake\Workspaces\Model\GroupsInterface; +use App\App; + +class Groups +{ + + private $doctrine; + private $gms; + private $market; + private $string_cleaner; + private $wms; + private $pusher; + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->gms = $app->getServices()->get("app.group_managers"); + $this->market = $app->getServices()->get("app.applications"); + $this->string_cleaner = $app->getServices()->get("app.string_cleaner"); + $this->wms = $app->getServices()->get("app.workspace_members"); + $this->pusher = $app->getServices()->get("app.pusher"); + } + + public function create($userId, $name, $uniquename, $planId, $group_data_on_create = Array()) + { + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + + $user = $userRepository->find($userId); + + //Find a name + $groupUsingThisName = $groupRepository->findOneBy(Array("name" => $uniquename)); + $increment = 0; + $uniquenameIncremented = $uniquename; + while ($groupUsingThisName != null) { + $groupUsingThisName = $groupRepository->findOneBy(Array("name" => $uniquenameIncremented)); + $increment += 1; + if ($groupUsingThisName != null) { + $uniquenameIncremented = $uniquename . "-" . $increment; + } + } + + + $group = new Group($uniquenameIncremented); + $group->setDisplayName($name); + $group->setOnCreationData($group_data_on_create); + + $this->doctrine->persist($group); + $this->doctrine->flush(); + + $this->gms->addManager($group->getId(), $userId, 3, true); + + $this->init($group); + + return $group; + + } + + public function init($group) + { + $appRepository = $this->doctrine->getRepository("Twake\Market:Application"); + $groupAppRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupApp"); + + $groupApps = $groupAppRepository->findBy(Array("group" => $group)); + + $listApps = $appRepository->findBy(Array("is_default" => true)); + + if (count($groupApps) != 0) { + return false; + } else { + foreach ($listApps as $app) { + $groupapp = new GroupApp($group, $app->getId()); + $groupapp->setWorkspaceDefault(true); + $this->doctrine->persist($groupapp); + } + $this->doctrine->flush(); + return true; + } + return true; + } + + public function changeData($groupId, $name, $currentUserId = null) + { + if ($currentUserId != null || $this->gms->hasPrivileges($this->gms->getLevel($groupId, $currentUserId), "MANAGE_DATA")) { + + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $group = $groupRepository->find($groupId); + + $group->setDisplayName($name); + + //Find a name + $groupUsingThisName = $groupRepository->findOneBy(Array("name" => $name)); + $increment = 0; + $uniquenameIncremented = $this->string_cleaner->simplify($name); + + while ($groupUsingThisName != null) { + $groupUsingThisName = $groupRepository->findOneBy(Array("name" => $uniquenameIncremented)); + $increment += 1; + if ($groupUsingThisName != null) { + $uniquenameIncremented = $name . "-" . $increment; + } + } + + $group->setName($uniquenameIncremented); + + $this->doctrine->persist($group); + $this->doctrine->flush(); + + return true; + } else { + error_log("NOT ALLOWED"); + } + + return false; + } + + public function removeUserFromGroup($groupId, $userId, $currentUserId = null) + { + if ($currentUserId == null || $this->gms->hasPrivileges($this->gms->getLevel($groupId, $currentUserId), "MANAGE_USERS")) { + + $ws = $this->getWorkspaces($groupId); + + foreach ($ws as $workspace) { + $this->wms->removeMember($workspace->getId(), $userId, $currentUserId); + } + + return true; + } + + return false; + } + + public function getWorkspaces($groupId, $currentUserId = null) + { + if ($currentUserId != null || $this->gms->hasPrivileges($this->gms->getLevel($groupId, $currentUserId), "VIEW_WORKSPACES")) { + + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $group = $groupRepository->findBy(Array("id" => $groupId)); + + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + + return $workspaceRepository->findBy(Array("group" => $group)); + } + + return false; + } + + public function getUsers($groupId, $currentUserId = null) + { + if ($currentUserId == null || $this->gms->hasPrivileges($this->gms->getLevel($groupId, $currentUserId), "VIEW_WORKSPACES")) { + + $ws = $this->getWorkspaces($groupId);//TODO remove users from all workspaces + + $workspace_ids = Array(); + foreach ($ws as $workspace) { + $workspace = $workspace["workspace"]; + $workspace_ids[] = $workspace->getId(); + } + + $userLinks = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser")->getUsersFromGroup($workspace_ids); + + $users = Array(); + foreach ($userLinks as $userLink) { + $users[] = $userLink->getUser(); + } + + return $users; + } + + return false; + } + + public function changeLogo($groupId, $logo, $currentUserId = null, $uploader = null) + { + if ($currentUserId != null || $this->gms->hasPrivileges($this->gms->getLevel($groupId, $currentUserId), "MANAGE_DATA")) { + + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $group = $groupRepository->find($groupId); + + $group->setLogo($logo); + + $this->doctrine->persist($group); + $this->doctrine->flush(); + + return $group; + } + + return false; + } + + public function remove($group) + { + + //TODO REMOVE USERS FROM WORKSPACE + if ($group != null) { + $groupappsRepository = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:GroupApp"); + $groupapps = $groupappsRepository->findBy(Array("group" => $group)); + + $workspaceRepository = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(Array("name" => "phpunit")); + + $workspaceUserRepository = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:WorkspaceUser"); + $workspaceUsers = $workspaceUserRepository->findBy(Array("workspace_id" => $workspace->getId())); + + $workspaceappsRepository = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:WorkspaceApp"); + $workspaceapps = $workspaceappsRepository->findBy(Array("workspace_id" => $workspace)); + + $workspacelevelRepository = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:WorkspaceLevel"); + $workspacelevels = $workspacelevelRepository->findBy(Array("workspace_id" => $workspace)); + + $workspacestatsRepository = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:WorkspaceStats"); + $workspacestats = $workspacestatsRepository->findOneBy(Array("workspace" => $workspace)); + + $streamRepository = $this->get("app.twake_doctrine")->getRepository("Twake\Discussion:Stream"); + $streams = $streamRepository->findBy(Array("workspace" => $workspace)); + + $groupUserdRepository = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:GroupUser"); + $groupUsers = $groupUserdRepository->findBy(Array("group" => $group)); + + $groupPricingRepository = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:GroupPricingInstance"); + $groupPricing = $groupPricingRepository->findOneBy(Array("group" => $group)); + } + + //TODO DOCTRINE REMOVE USERS FROM WORKSPACE + + if ($group != null) { + if ($groupapps != null) { + if (is_array($groupapps)) { + foreach ($groupapps as $groupapp) { + $this->get("app.twake_doctrine")->remove($groupapp); + } + } + } + if ($workspaceapps != null) { + if (is_array($workspaceapps)) { + foreach ($workspaceapps as $workspaceapp) { + $this->get("app.twake_doctrine")->remove($workspaceapp); + } + } + } + if ($workspaceUsers != null) { + if (is_array($workspaceUsers)) { + foreach ($workspaceUsers as $workspaceUser) { + $this->get("app.twake_doctrine")->remove($workspaceUser); + } + } + } + if ($groupPricing != null) { + $this->get("app.twake_doctrine")->remove($groupPricing); + } + if ($workspacelevels != null) { + if (is_array($workspacelevels)) { + foreach ($workspacelevels as $workspacelevel) { + $this->get("app.twake_doctrine")->remove($workspacelevel); + } + } + } + if ($streams != null) { + if (is_array($streams)) { + foreach ($streams as $stream) { + $this->get("app.twake_doctrine")->remove($stream); + } + } + } + if ($workspacestats != null) { + $this->get("app.twake_doctrine")->remove($workspacestats); + } + if ($workspace != null) { + $this->get("app.twake_doctrine")->remove($workspace); + } + if (is_array($groupUsers)) { + foreach ($groupUsers as $groupuser) { + $this->get("app.twake_doctrine")->remove($groupuser); + } + } + if ($groupPeriod != null) { + $this->get("app.twake_doctrine")->remove($groupPeriod); + } + } + + if ($group != null) { + $this->get("app.twake_doctrine")->remove($group); + } + + $this->get("app.twake_doctrine")->flush(); + } + + public function countUsersGroup($groupId) + { + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $group = $groupRepository->find($groupId); + return $group->getMemberCount(); + } + + public function getUsersGroup($groupId, $onlyExterne, $limit = 100, $offset = 0, $currentUserId = null) + { + if ($currentUserId == null || $this->gms->hasPrivileges($this->gms->getLevel($groupId, $currentUserId), "VIEW_USERS")) { + + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $groupManagerRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + + $group = $groupRepository->find($groupId); + $groupLinks = $groupManagerRepository->findBy(Array("group" => $group), null, $max, $offset); + $users = Array(); + foreach ($groupLinks as $link) { + if (!$onlyExterne || $link->getExterne()) { + $users[] = Array( + "user" => $link->getUser(), + "externe" => $link->getExterne(), + "level" => $link->getLevel(), + "nbWorkspace" => $link->getNbWorkspace() + ); + } + } + return $users; + } + return false; + + + } + + public function editUserFromGroup($groupId, $userId, $externe, $currentUserId = null) + { + if ($currentUserId == null || $this->gms->hasPrivileges($this->gms->getLevel($groupId, $currentUserId), "MANAGE_USERS")) { + + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $groupManagerRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + + $group = $groupRepository->find($groupId); + $user = $groupManagerRepository->findOneBy(Array("user" => $user->getId(), "group" => $groupId)); + + $user->setExterne($externe); + $this->doctrine->persist($user); + $this->doctrine->flush(); + return true; + } + + return false; + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Workspaces/Services/WorkspaceLevels.php b/twake/backend/core/src/Twake/Workspaces/Services/WorkspaceLevels.php new file mode 100755 index 00000000..040fa0c4 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Services/WorkspaceLevels.php @@ -0,0 +1,398 @@ +<?php + +namespace Twake\Workspaces\Services; + + +use Twake\Workspaces\Entity\WorkspaceLevel; +use Twake\Workspaces\Model\WorkspaceLevelsInterface; +use App\App; + +class WorkspaceLevels +{ + + private $doctrine; + private $pusher; + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->pusher = $app->getServices()->get("app.pusher"); + } + + public function getLevel($workspaceId, $userId, $currentUserId = null) + { + if ($currentUserId == null + || $currentUserId == $userId + || $this->can($workspaceId, $currentUserId, "") + ) { + + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspaceUserRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + + $user = $userRepository->find($userId); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + $link = $workspaceUserRepository->findOneBy(Array("workspace_id" => $workspace->getId(), "user_id" => $user->getId())); + + if (!$link) { + return null; //No level because no member + } + $level = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceLevel")->findOneBy(Array("workspace_id" => $workspace->getId(), "id" => $link->getLevelId())); + + return $level; + + } + + return null; //Cant look this info + } + + public function can($workspaceId, $userId, $action) + { + + if (!$userId) { + return false; + } + + //Load rights for this users + + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspaceUserRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + $companyUserRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + + $user = $this->convertToEntity($userId, "Twake\Users:User"); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + if (!$user || !$workspace) { + error_log("no user / ws "); + return false; + } + + $companyLink = $companyUserRepository->findOneBy(Array("group" => $workspace->getGroup(), "user" => $user->getId())); + $link = $workspaceUserRepository->findOneBy(Array("workspace_id" => $workspace->getId(), "user_id" => $user->getId())); + if ($link) { + + if($link->getRole() === "moderator" || $companyLink->getRole() === "admin" || $companyLink->getRole() === "owner"){ + return true; //Admin can do everything + } + + $level = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceLevel")->findOneBy(Array("workspace_id" => $workspace->getId(), "id" => $link->getLevelId())); + if ($level && $level->getIsAdmin()) { + return true; //Admin can do everything + } + + if($action === "admin"){ + return false; + } + + if ($action == "" || $action == null) { + return true; + } + + return false; + } + + return false; + + } + + private function convertToEntity($var, $repository) + { + if (is_string($var)) { + $var = $var; // Cassandra id do nothing + } + + if (is_int($var) || is_string($var) || get_class($var) == "Ramsey\Uuid\Uuid") { + return $this->doctrine->getRepository($repository)->find($var); + } else if (is_object($var)) { + return $var; + } else { + return null; + } + + } + + public function updateLevel($workspaceId, $levelId, $label, $rights, $currentUserId = null) + { + if ($currentUserId == null + || $this->can($workspaceId, $currentUserId, "workspace:write") + ) { + + $levelRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceLevel"); + + $level = $levelRepository->findBy(Array("workspace_id" => $workspaceId, "level" => $levelId)); + if (!$level) { + return false; + } + + if ($level->getWorkspace()->getId() != $workspaceId) { + return false; + } + + $level->setRights($rights); + $level->setLabel($label); + + $this->doctrine->persist($level); + $this->doctrine->flush(); + + $datatopush = Array( + "type" => "CHANGE_LEVEL", + "data" => Array( + "workspaceId" => $workspaceId, + ) + ); + $this->pusher->push($datatopush, "group/" . $workspaceId); + + return true; + + } + + return false; + } + + public function getDefaultLevel($workspaceId) + { + + $choosen = null; + + $levelRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceLevel"); + + $levels = $levelRepository->findBy(Array("workspace_id" => $workspaceId)); + + + foreach ($levels as $level) { + if ($level->getIsDefault()) { + $choosen = $level; + } + } + + //No default level ! + if (!$choosen) { + + $levelD = new WorkspaceLevel(); + $levelD->setWorkspace($workspaceId); + $levelD->setLabel("Default"); + $levelD->setIsAdmin(false); + $levelD->setIsDefault(true); + $this->doctrine->persist($levelD); + $this->doctrine->flush(); + + $choosen = $levelD; + + } + + return $choosen; + + } + + public function setDefaultLevel($workspaceId, $levelId, $currentUserId = null) + { + if ($currentUserId == null + || $this->can($workspaceId, $currentUserId, "workspace:write") + ) { + + $levelRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceLevel"); + + $oldLevelDefault = $levelRepository->findOneBy(Array("workspace_id" => $workspaceId, "isdefault" => true)); + + if ($oldLevelDefault) { + $oldLevelDefault->setisDefault(false); + $this->doctrine->persist($oldLevelDefault); + } + + $levelDefault = $levelRepository->find($levelId); + if (!$levelDefault) { + return false; + } + if ($levelDefault->getWorkspace()->getId() != $workspaceId) { + return false; + } + $levelDefault->setisDefault(true); + + + $this->doctrine->persist($levelDefault); + $this->doctrine->flush(); + + return true; + + } + + return false; + } + + public function addLevel($workspaceId, $label, $rights, $currentUserId = null) + { + if ($currentUserId == null + || $this->can($workspaceId, $currentUserId, "workspace:write") + ) { + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + $level = new WorkspaceLevel(); + + $level->setWorkspace($workspaceId); + $level->setRights($rights); + $level->setLabel($label); + + $this->doctrine->persist($level); + $this->doctrine->flush(); + + return true; + + } + + return false; + } + + public function removeLevel($workspaceId, $levelId, $currentUserId = null) + { + if ($currentUserId == null + || $this->can($workspaceId, $currentUserId, "workspace:write") + ) { + + $levelRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceLevel"); + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspaceUserRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + + $level = $levelRepository->findBy(Array("workspace_id" => $workspaceId, "level" => $levelId)); + if ($level->getWorkspace()->getId() != $workspaceId) { + return false; + } + + if ($level->getIsDefault()) { + return false; //Can't remove default level + } + + if ($level->getIsAdmin()) { + return false; //Can't remove admin level + } + + $levelDefault = $levelRepository->findOneBy(Array("workspace_id" => $workspaceId, "isdefault" => true)); + + if (!$levelDefault) { + return false; + } + + $affectedUsers = $workspaceUserRepository->findBy(Array("workspace_id" => $workspaceId, "level" => $level)); + foreach ($affectedUsers as $affectedUser) { + $affectedUser->setLevel($levelDefault); + $this->doctrine->persist($affectedUser); + } + + $this->doctrine->remove($level); + $this->doctrine->flush(); + + $datatopush = Array( + "type" => "CHANGE_LEVEL", + "data" => Array( + "workspaceId" => $workspaceId(), + ) + ); + $this->pusher->push($datatopush, "group/" . $workspaceId()); + + return true; + + } + + return false; + } + + public function getUsers($workspaceId, $levelId, $currentUserId = null) + { + if ($currentUserId == null + || $this->can($workspaceId, $currentUserId, "workspace:read") + ) { + + $levelRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceLevel"); + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspaceUserRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + + $level = $levelRepository->findBy(Array("workspace_id" => $workspaceId, "level" => $levelId)); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + if (!$level || !$workspace) { + return false; + } + + $link = $workspaceUserRepository->findBy(Array("level" => $level, "workspace_id" => $workspaceId)); + + $users = Array(); + foreach ($link as $user) { + $users[] = $user->getUser($this->doctrine); + } + + return $users; + } + + return false; + } + + public function getLevels($workspaceId, $currentUserId = null) + { + $levelRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceLevel"); + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + if (!$workspace) { + return false; + } + + $levels = $levelRepository->findBy(Array("workspace_id" => $workspaceId)); + + return $levels; + } + + public function getByLabel($workspaceId, $label, $currentUserId = null) + { + if ($currentUserId == null + || $this->can($workspaceId, $currentUserId, "workspace:read") + ) { + + $levelRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceLevel"); + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + if (!$workspace) { + return false; + } + + $levels = $levelRepository->findBy(["label" => $label, "workspace_id" => $workspaceId]); + + return $levels; + } + + return false; + } + + + // @Depreciated + public function hasRight($userId, $workspaceId, $rightAsked) + { + $userId = $this->convertToEntity($userId, "Twake\Users:User"); + $userId = $userId->getId(); + + $workspaceId = $this->convertToEntity($workspaceId, "Twake\Workspaces:Workspace"); + $workspaceId = $workspaceId->getId(); + + return $this->can($workspaceId, $userId, $rightAsked); + } + + // @Depreciated + public function errorsAccess($userId, $workspaceId, $right) + { + $userId = $this->convertToEntity($userId, "Twake\Users:User"); + $userId = $userId->getId(); + + $workspaceId = $this->convertToEntity($workspaceId, "Twake\Workspaces:Workspace"); + $workspaceId = $workspaceId->getId(); + + if ($this->can($workspaceId, $userId, $right)) { + return []; + } + return ["notallowed"]; + } + +} + +?> diff --git a/twake/backend/core/src/Twake/Workspaces/Services/WorkspaceMembers.php b/twake/backend/core/src/Twake/Workspaces/Services/WorkspaceMembers.php new file mode 100755 index 00000000..a27dbfea --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Services/WorkspaceMembers.php @@ -0,0 +1,764 @@ +<?php + +namespace Twake\Workspaces\Services; + +use Twake\Users\Entity\User; +use Twake\Workspaces\Entity\GroupUser; +use Twake\Workspaces\Entity\WorkspaceUser; +use Twake\Workspaces\Entity\WorkspaceUserByMail; +use Twake\Workspaces\Model\WorkspaceMembersInterface; +use App\App; + +class WorkspaceMembers +{ + + /* @var WorkspacesActivities $workspacesActivities */ + var $workspacesActivities; + var $groupManager; + private $app; + private $wls; + private $string_cleaner; + private $doctrine; + private $pusher; + private $calendar; + private $queues; + + public function __construct(App $app) + { + $this->app = $app; + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->wls = $app->getServices()->get("app.workspace_levels"); + $this->string_cleaner = $app->getServices()->get("app.string_cleaner"); + $this->pusher = $app->getServices()->get("app.pusher"); + $this->calendar = $app->getServices()->get("app.calendar.calendar"); + $this->workspacesActivities = $app->getServices()->get("app.workspaces_activities"); + $this->groupManager = $app->getServices()->get("app.group_managers"); + $this->queues = $app->getServices()->get('app.queues')->getAdapter(); + } + + public function changeLevel($workspaceId, $userId, $levelId, $currentUserId = null) + { + if ($currentUserId == null + || $this->wls->can($workspaceId, $currentUserId, "workspace:write") + ) { + + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $levelRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceLevel"); + + $level = $levelRepository->findOneBy(Array("workspace_id" => $workspaceId, "id" => $levelId)); + $user = $userRepository->find($userId); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + $workspaceUserRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + $member = $workspaceUserRepository->findOneBy(Array("workspace_id" => $workspace->getId(), "user_id" => $user->getId())); + + $member->setLevelId($level->getId()); + if($level->getIsAdmin()){ + $member->setRole("moderator"); + }else{ + $member->setRole("member"); + } + + $this->doctrine->persist($member); + $this->doctrine->flush(); + + $workspaceUser = $member->getAsArray($this->doctrine); + $workspaceUser["groupLevel"] = $this->groupManager->getLevel($workspace->getGroup(), $userId, $currentUserId); + $dataToPush = Array( + "type" => "update_workspace_level", + "workspace_user" => $workspaceUser + ); + $this->pusher->push($dataToPush, "workspace_users/" . $workspace->getId()); + + $dataToPush = Array( + "type" => "update_workspace_level", + "level" => $level->getAsArray() + ); + $this->pusher->push($dataToPush, "workspaces_of_user/" . $userId); + + return true; + } + return false; + } + + public function addMemberByUsername($workspaceId, $username, $asExterne, $currentUserId = null) + { + if ($currentUserId == null + || $this->wls->can($workspaceId, $currentUserId, "workspace:write") + ) { + $username = $this->string_cleaner->simplifyUsername($username); + + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $user = $userRepository->findOneBy(Array("usernamecanonical" => $username)); + if ($user) { + return $this->addMember($workspaceId, $user->getId(), $asExterne); + } + + } + return false; + } + + // return false if error, user if user already have an account, mail if invitation mail sent + + public function addMember($workspaceId, $userId, $asExterne = false, $levelId = null, $currentUserId = null) + { + if ($currentUserId == null || $this->wls->can($workspaceId, $currentUserId, "workspace:write")) { + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + + $user = $userRepository->find($userId); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + if ($workspace->getGroup() != null) { + $groupUserRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + $nbuserGroup = $groupUserRepository->findBy(Array("group" => $workspace->getGroup())); + } + $workspaceUserRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + $member = $workspaceUserRepository->findOneBy(Array("workspace_id" => $workspace->getId(), "user_id" => $user->getId())); + + + if ($member != null) { + return false; //Already added + } + + if (!$levelId || $levelId == null) { + $level = $this->wls->getDefaultLevel($workspaceId); + } else { + $levelRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceLevel"); + $level = $levelRepository->findOneBy(Array("workspace_id" => $workspaceId, "id" => $levelId)); + } + $member = new WorkspaceUser($workspace, $user, $level->getId()); + $member->setExterne($asExterne); + + if($asExterne){ + $workspace->setGuestCount($workspace->getGuestCount() + 1); + }else{ + $workspace->setMemberCount($workspace->getMemberCount() + 1); + } + + $groupUserRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + $groupmember = $groupUserRepository->findOneBy(Array("group" => $workspace->getGroup(), "user" => $user)); + $group = $groupRepository->findOneBy(["id" => $workspace->getGroup()]); + + if (!$groupmember) { + $groupmember = new GroupUser($workspace->getGroup(), $user); + $groupmember->increaseNbWorkspace(); + $groupmember->setLevel(0); + $group->setMemberCount($group->getMemberCount() + 1); + } else { + $groupmember->increaseNbWorkspace(); + } + $groupmember->setExterne(false); + + $this->doctrine->persist($workspace); + $this->doctrine->persist($member); + $this->doctrine->persist($groupmember); + $this->doctrine->persist($group); + $this->doctrine->flush(); + + + $dataToPush = Array( + "type" => "add", + "workspace_user" => $member->getAsArray($this->doctrine) + ); + $this->pusher->push($dataToPush, "workspace_users/" . $workspace->getId()); + + $dataToPush = Array( + "type" => "add", + "workspace" => $workspace->getAsArray($this->doctrine) + ); + $this->pusher->push($dataToPush, "workspaces_of_user/" . $userId); + + $this->queues->push("workspace:member:added", [ + "company_id" => $workspace->getGroup(), + "workspace_id" => $workspaceId, + "user_id" => $userId + ], ["exchange_type" => "fanout"]); + + $this->updateChannelAfterAddWorkspaceMember($workspace, $user); + + $this->updateUser($user); + + return true; + } + + return false; + } + + public function updateChannelAfterAddWorkspaceMember($workspace, $user) + { + $workspaceMember = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser")->findOneBy(Array("workspace_id" => $workspace->getId(), "user_id" => $user->getId())); + if ($workspaceMember) { + $channels = $this->doctrine->getRepository("Twake\Channels:Channel")->findBy( + Array("original_workspace_id" => $workspace->getId(), "direct" => false) + ); + + foreach ($channels as $channel_entity) { + + $isInChannel = false; + $mails = $this->doctrine->getRepository("Twake\Users:Mail")->findBy(Array("user_id" => $user)); + $channelExt = $channel_entity->getExtMembers(); + if (!$channelExt) { + $channelExt = Array(); + } + foreach ($mails as $mail) { + if (in_array($mail->getMail(), $channelExt)) { + $isInChannel = true; + } + } + if (!$channel_entity->getPrivate() && (!$workspaceMember->getExterne() || $workspaceMember->getExterne() && $workspaceMember->getAutoAddExterne() || $workspaceMember->getExterne() && (in_array($user->getId(), $channel_entity->getExtMembers()) || $isInChannel))) { + $member = new \Twake\Channels\Entity\ChannelMember($user->getId() . "", $channel_entity); + $member->setLastMessagesIncrement($channel_entity->getMessagesIncrement()); + $this->doctrine->persist($member); + if (!$workspaceMember->getExterne()) { + //membre du ws + $channel_entity->setMembers(array_merge($channel_entity->getMembers(), [$user->getId()])); + } else { + // externe + if (array_search($user->getId(), $channelExt) === false) { + $channel_entity->setExtMembers(array_merge($channel_entity->getExtMembers(), [$user->getId()])); + } + if (!$workspaceMember->getAutoAddExterne()) { + // c'est un chaviter d'espace + $mails = $this->doctrine->getRepository("Twake\Users:Mail")->findBy(Array("user_id" => $user->getId())); + $channelExt = $channel_entity->getExtMembers(); + foreach ($mails as $mail) { + if (($index = array_search($mail->getMail(), $channelExt)) !== false) { + array_splice($channelExt, $index, 1); + } + } + $channel_entity->setExtMembers($channelExt); + } + } + $this->doctrine->persist($channel_entity); + } + } + $this->doctrine->flush(); + } + } + + public function addMemberByMail($workspaceId, $mail, $asExterne, $currentUserId = null, $sendEmail = true) + { + if ($currentUserId == null + || $this->wls->can($workspaceId, $currentUserId, "workspace:write") + ) { + + $mail = $this->string_cleaner->simplifyMail($mail); + + if (!$this->string_cleaner->verifyMail($mail)) { + return false; + } + + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $currentUser = null; + if ($currentUserId) { + $currentUser = $userRepository->find($currentUserId); + } + $user = $userRepository->findOneBy(Array("emailcanonical" => $mail)); + + if ($user) { + $uOk = $this->addMember($workspaceId, $user->getId(), $asExterne); + if ($uOk) { + return "user"; + } + return false; + } + + $mailsRepository = $this->doctrine->getRepository("Twake\Users:Mail"); + $userMail = $mailsRepository->findOneBy(Array("mail" => $mail)); + + if ($userMail) { + $user_id = $userMail->getUserId(); + $user = $userRepository->find($user_id); + $mOk = $this->addMember($workspaceId, $user, $asExterne); + if ($mOk) { + return "user"; + } + return false; + } + + $retour = false; + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + $workspaceUserByMailRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUserByMail"); + $mailObj = $workspaceUserByMailRepository->findOneBy(Array("workspace_id" => $workspaceId, "mail" => $mail)); + + if ($mailObj == null) { + //Mail not in tables + $userByMail = new WorkspaceUserByMail($workspace, $mail); + $userByMail->setExterne($asExterne); + $userByMail->setAutoAddExterne(false); + $workspace->setPendingCount($workspace->getPendingCount()+1); + $this->doctrine->persist($workspace); + $this->doctrine->persist($userByMail); + $this->doctrine->flush(); + $retour = "mail"; + } + return $retour; + } + + return false; + } + + public function removeMemberByMail($workspaceId, $mail, $currentUserId = null) + { + if ($currentUserId == null + || $this->wls->can($workspaceId, $currentUserId, "workspace:write") + ) { + $mail = $this->string_cleaner->simplifyMail($mail); + + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + $workspaceUserByMailRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUserByMail"); + $mails = $workspaceUserByMailRepository->findBy(Array("workspace_id" => $workspaceId, "mail" => $mail)); + foreach($mails as $mailguest){ + $this->doctrine->remove($mailguest); + $workspace->setPendingCount($workspace->getPendingCount() - 1); + } + + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $user = $userRepository->findOneBy(Array("emailcanonical" => $mail)); + + if ($user) { + return "user " . $this->removeMember($workspaceId, $user->getId()); + } + + $mailsRepository = $this->doctrine->getRepository("Twake\Users:Mail"); + $userMail = $mailsRepository->findOneBy(Array("mail" => $mail)); + + if ($userMail) { + $user_id = $userMail->getUserId(); + $user = $userRepository->find($user_id); + return "mail " . $this->removeMember($workspaceId, $user); + } + + $this->doctrine->flush(); + + return "ok"; + + } + + return "not allowed"; + } + + public function removeMember($workspaceId, $userId, $currentUserId = null) + { + if ($currentUserId == null + || $userId == $currentUserId + || $this->wls->can($workspaceId, $currentUserId, "workspace:write") + ) { + + $total_membres = $this->doctrine->getRepository("Twake\Workspaces:Workspace")->findOneBy(Array("id" => $workspaceId))->getMemberCount(); + + if ($userId == $currentUserId) { + if ($total_membres == 1) { + return false; // can't remove myself if I'm the last + } + } + + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + + $user = $userRepository->find($userId); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + $workspaceUserRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + $member = $workspaceUserRepository->findOneBy(Array("workspace_id" => $workspace->getId(), "user_id" => $user->getId())); + + if (!$member) { + return false; + } + + $groupUserRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + $groupmember = $groupUserRepository->findOneBy(Array("group" => $workspace->getGroup(), "user" => $user)); + $groupmember->decreaseNbWorkspace(); + $this->doctrine->persist($groupmember); + + //If multiple users + if ($total_membres > 1) { + + //Test if other workspace administrators are present + $level = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceLevel")->findOneBy(Array("workspace_id" => $workspace->getId(), "id" => $member->getLevelId())); + + if ($currentUserId != null && $level->getIsAdmin()) { + $other_workspace_admins = $workspaceUserRepository->findBy(Array("level_id" => $member->getLevelId())); + if (count($other_workspace_admins) <= 1) { + header("twake-debug: no other workspace admins"); + return false; + } + } + } + + //Test if other group administrators are present in case this is the last workspace of the user + if ($groupmember->getNbWorkspace() <= 0) { + if ($currentUserId != null && $groupmember->getLevel() == 3) { + $otherGroupAdmin = $groupUserRepository->findBy(Array("group" => $workspace->getGroup(), "level" => 3)); + if (count($otherGroupAdmin) == 1) { + header("twake-debug: no other group admins"); + return false; + } + } + if ($groupmember) { + $this->doctrine->remove($groupmember); + } + $groupmember = null; + } + + + $workspace_user = $member->getAsArray($this->doctrine); + $workspace_user["nbWorkspace"] = $groupmember != null ? $groupmember->getNbWorkspace() : 0; + + $dataToPush = Array( + "type" => "remove", + "workspace_user" => $workspace_user, + ); + $this->pusher->push($dataToPush, "workspace_users/" . $workspace->getId()); + $dataToPush = Array( + "type" => "remove", + "workspace" => $workspace->getAsArray($this->doctrine), + ); + $this->pusher->push($dataToPush, "workspaces_of_user/" . $userId); + + $this->queues->push("workspace:member:removed", [ + "company_id" => $workspace->getGroup(), + "workspace_id" => $workspaceId, + "user_id" => $userId + ], ["exchange_type" => "fanout"]); + + if ($member) { + if($member->getExterne()){ + $workspace->setGuestCount($workspace->getGuestCount() - 1); + }else{ + $workspace->setMemberCount($workspace->getMemberCount() - 1); + } + $this->doctrine->persist($workspace); + $this->doctrine->remove($member); + } + $this->doctrine->flush(); + + $this->delWorkspaceMember_temp($workspace, $user); + + $this->updateUser($user); + + return true; + } + + return false; + } + + public function delWorkspaceMember_temp($workspace, $user) + { + $membersRepo = $this->doctrine->getRepository("Twake\Channels:ChannelMember"); + $channels = $this->doctrine->getRepository("Twake\Channels:Channel")->findBy( + Array("original_workspace_id" => $workspace->getId(), "direct" => false) + ); + + foreach ($channels as $channel_entity) { + + $member = $membersRepo->findOneBy(Array("direct" => $channel_entity->getDirect(), "channel_id" => $channel_entity->getId() . "", "user_id" => $user->getId())); + if ($member) { + $this->doctrine->remove($member); + $channel_entity->setMembers(array_diff($channel_entity->getMembers(), [$user->getId()])); + $channel_entity->setExtMembers(array_diff($channel_entity->getExtMembers(), [$user->getId()])); + } + $this->doctrine->persist($channel_entity); + } + $this->doctrine->flush(); + } + + public function autoAddMemberByNewMail($mail, $userId) + { + $mail = $this->string_cleaner->simplifyMail($mail); + $workspaceUerByMailRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUserByMail"); + $invitations = $workspaceUerByMailRepository->findBy(Array("mail" => $mail)); + + foreach ($invitations as $userByMail) { + $this->doctrine->remove($userByMail); + $this->doctrine->flush(); + $this->addMember($userByMail->getWorkspaceId(), $userId, $userByMail->getExterne()); + } + + return true; + } + + public function removeAllMember($workspaceId) + { + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + if (!$workspace) { + return false; //Private workspace, only one user + } + + $workspaceUserRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + $members = $workspaceUserRepository->findBy(Array("workspace_id" => $workspace->getId())); + + foreach ($members as $member) { + $this->removeMember($workspaceId, $member->getUserId()); + } + + $this->doctrine->flush(); + return true; + + } + + public function getMembersAndPending($workspaceId, $currentUserId, $order = Array("user" => "DESC"), $max = 100, $offset = 0) + { + + $members = $this->getMembers($workspaceId, $currentUserId, $order, $max, $offset); + $list = Array(); + foreach ($members as $member) { + $user = $member["user"]->getAsArray(); + $list[] = Array( + "user" => $user, + "last_access" => $member["last_access"], + "level" => $member["level"], + "externe" => $member["externe"], + "groupLevel" => $member["groupLevel"] + ); + } + + $pendingMails = $this->getPendingMembers($workspaceId, $currentUserId); + + $listMails = Array(); + foreach ($pendingMails as $mail) { + $listMails[] = Array( + "mail" => $mail->getMail(), + "externe" => $mail->getExterne() + ); + } + + return Array( + "mails" => $listMails, + "members" => $list + ); + + } + + public function searchMembers($workspaceId, $currentUserId = null, $query) + { + if ($currentUserId == null + || $this->wls->can($workspaceId, $currentUserId, "") + ) { + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspaceUserRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + if (!$workspace) { + return false; + } + + $usersService = $this->app->getServices()->get("app.users"); + + $results = $usersService->search([ + "name" => $query, + "workspace_id" => $workspaceId, + "scope" => "workspace" + ], true); + + if($results){ + $results = $results["users"]; + }else{ + $results = []; + } + + $members = []; + foreach($results as $user){ + if($user[0]){ + $link = $workspaceUserRepository->findOneBy(Array("workspace_id" => $workspace->getId(), "user_id" => $user[0]->getId())); + $v = $this->memberFromLink($workspace, $currentUserId, $user[0], $link); + if($v){ + $members[] = $v; + } + } + } + + return $members; + + } + + return false; + + } + + public function getMembers($workspaceId, $currentUserId = null, $order = Array("user" => "DESC"), $max = 100, $offset = 0) + { + if ($currentUserId == null + || $this->wls->can($workspaceId, $currentUserId, "") + ) { + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspaceUserRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + $groupUserRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + if (!$workspace) { + return false; + } + + $links = $workspaceUserRepository->findBy(Array("workspace_id" => $workspace->getId()), Array(), $max, $offset, "user_id", "ASC"); + $users = Array(); + foreach ($links as $link) { + $userEntity = $link->getUser($this->doctrine); + if($userEntity){ + $v = $this->memberFromLink($workspace, $currentUserId, $userEntity, $link); + if($v){ + $users[] = $v; + } + } + + } + + return $users; + } + + return false; + } + + private function memberFromLink($workspace, $currentUserId, $userEntity, $link){ + $groupUserRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + $group_user = $groupUserRepository->findOneBy(Array("user" => $link->getUserId(), "group" => $workspace->getGroup())); + $groupId = $workspace->getGroup(); + + $value = null; + if ($group_user) { + $value = Array( + "user" => $userEntity, + "last_access" => $link->getLastAccess() ? $link->getLastAccess()->getTimestamp() : null, + "level" => $link->getLevelId(), + "externe" => $link->getExterne(), + "workspace_member_id" => $link->getId(), + "groupLevel" => $this->groupManager->getLevel($groupId, $link->getUserId(), $currentUserId) + ); + + } else { + error_log("error group user, " . $link->getUserId() . "," . $workspace->getGroup()); + } + return $value; + } + + public function getPendingMembers($workspaceId, $currentUserId = null, $max = 100, $offset = 0) + { + if ($currentUserId == null + || $this->wls->can($workspaceId, $currentUserId, "") + ) { + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspaceUserByMailRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUserByMail"); + + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + if (!$workspace) { + return false; + } + + $mails = $workspaceUserByMailRepository->findBy(Array("workspace_id" => $workspace->getId()), Array(), $max, $offset, "mail", "ASC"); + + return $mails; + } + + return false; + } + + public function getWorkspaces($userId) + { + $groupUserRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + $workspaceUserRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $user = $userRepository->find($userId); + if (!$user) { + return false; + } + $link = $workspaceUserRepository->findBy(Array("user_id" => $user->getId())); + $workspaces = Array(); + foreach ($link as $workspaceMember) { + $workspace = $workspaceMember->getWorkspace($this->doctrine); + if ($workspace && !$workspace->getIsDeleted() && $workspace->getGroup()) { + + $levels = $this->wls->getLevels($workspace->getId(), $userId); + $isAdmin = false; + foreach ($levels as $level) { + if($level->getId() === $workspaceMember->getLevelId() && $level->getIsAdmin()){ + $isAdmin = true; + } + } + + if($isAdmin){ + $workspaceMember->setRole("moderator"); + $this->doctrine->persist($workspaceMember); + } + + $groupUser = $groupUserRepository->findOneBy(Array("user" => $user->getId(), "group" => $workspace->getGroup())); + + $companyAdmin = $groupUser ?( $groupUser->getLevel() === 3 || $groupUser->getRole() === "admin" || $groupUser->getRole() === "owner"): false; + + $workspaces[] = Array( + "last_access" => $workspaceMember->getLastAccess(), + "workspace" => $workspace, + "ishidden" => $workspaceMember->getisHidden(), + "isfavorite" => $workspaceMember->getisFavorite(), + "role" => $companyAdmin ? "moderator" : $workspaceMember->getRole(), + "_user_is_admin" => $isAdmin || $companyAdmin || ($workspaceMember->getRole() === "moderator"), + "_user_is_guest" => $groupUser ? $groupUser->getExterne() : $workspaceMember->getExterne(), + "_user_is_organization_administrator" => $companyAdmin, + "hasnotifications" => $workspaceMember->getHasNotifications(), + "isArchived" => $workspaceMember->getWorkspace($this->doctrine)->getIsArchived() + ); + } + } + + return $workspaces; + } + + public function updateCountersIfEmpty($workspaceId){ + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + $update = false; + + if($workspace->getMemberCount() === 0){ + $workspace->setMemberCount(count($this->getMembers($workspaceId))); + $update = true; + } + + if($workspace->getPendingCount() === 0){ + $count = count($this->getPendingMembers($workspaceId)); + $workspace->setPendingCount($count); + $update = $update || ($count > 0); + } + + if($update){ + $this->doctrine->persist($workspace); + $this->doctrine->flush(); + } + + } + + public function updateUser(User $user, $workspaces_ids = null, $groups_ids = null){ + + if(!$workspaces_ids){ + $workspaces_obj = $this->getWorkspaces($user->getId() . ""); + $workspaces_ids = Array(); + $groups_ids = Array(); + foreach ($workspaces_obj as $value) { + if($value && $value["workspace"] && $value["workspace"]->getGroup()){ + $workspaces_ids[] = $value["workspace"]->getId(); + $groups_ids[] = $value["workspace"]->getGroup(); + } + } + $workspaces_ids = array_values(array_unique($workspaces_ids)); + $groups_ids = array_values(array_unique($groups_ids)); + } + + $user->setWorkspaces($workspaces_ids); + $user->setGroups($groups_ids); + $user->setEsIndexed(false); + $this->doctrine->persist($user); + $this->doctrine->flush(); + } + +} diff --git a/twake/backend/core/src/Twake/Workspaces/Services/Workspaces.php b/twake/backend/core/src/Twake/Workspaces/Services/Workspaces.php new file mode 100755 index 00000000..3db1c322 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Services/Workspaces.php @@ -0,0 +1,793 @@ +<?php + +namespace Twake\Workspaces\Services; + + +use Twake\_old_Calendar\Entity\Calendar; +use Twake\_old_Calendar\Entity\LinkCalendarWorkspace; +use Twake\Channels\Entity\Channel; +use Twake\Drive\Entity\DriveLabel; +use Twake\Workspaces\Entity\Workspace; +use Twake\Workspaces\Entity\WorkspaceApp; +use Twake\Workspaces\Entity\WorkspaceLevel; +use Twake\Workspaces\Model\WorkspacesInterface; +use App\App; + +class Workspaces +{ + + /* @var WorkspacesActivities $workspacesActivities */ + var $workspacesActivities; + var $calendarEventService; + var $calendarService; + var $workspaces_service; + private $wls; + private $wms; + private $app; + private $gms; + private $gas; + private $rest; + private $gs; + private $doctrine; + private $string_cleaner; + private $pusher; + private $translate; + + public function __construct(App $app) + { + $this->app = $app; + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->wls = $app->getServices()->get("app.workspace_levels"); + $this->wms = $app->getServices()->get("app.workspace_members"); + $this->gms = $app->getServices()->get("app.group_managers"); + $this->gas = $app->getServices()->get("app.group_apps"); + $this->gs = $app->getServices()->get("app.groups"); + $this->string_cleaner = $app->getServices()->get("app.string_cleaner"); + $this->pusher = $app->getServices()->get("app.pusher"); + $this->workspacesActivities = $app->getServices()->get("app.workspaces_activities"); + $this->translate = $app->getServices()->get("app.translate"); + $this->calendarService = $app->getServices()->get("app.calendar.calendar"); + $this->calendarEventService = $app->getServices()->get("app.calendar.event"); + $this->workspaces_service = $app->getServices()->get("app.workspaces_apps"); + $this->rest = $app->getServices()->get("app.restclient"); + } + + public function create($name, $groupId = null, $userId = null, $default = false) + { + + if ($groupId == null && $userId == null) { + return false; + } + + if ($name == "") { + return false; + } + + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + + $workspace = new Workspace($name); + + $uniquename = $this->string_cleaner->simplify($name); + $uniquenameIncremented = $uniquename . "-" . substr(md5(date("U") . rand()), 0, 10); + + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $user = $userRepository->find($userId); + + if ($groupId != null) { + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $group = $groupRepository->find($groupId); + + + $groupUserdRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupUser"); + $group_user = $groupUserdRepository->findOneBy(Array("group" => $group, "user" => $user)); + + if (!$group_user || $group_user->getExterne()) { + return false; + } + + } + + $workspace->setUniqueName($uniquenameIncremented); + + $workspace->setIsDefault($default); + + if ($groupId != null) { + $workspace->setGroup($groupId); + } + + $this->doctrine->persist($workspace); + $this->doctrine->flush(); + + + $this->translate->setDefaultLanguage($user->getLanguage()); + + $this->doctrine->flush(); + + + //Create admin level + $levelAdmin = new WorkspaceLevel(); + $levelAdmin->setWorkspace($workspace->getId()); + $levelAdmin->setLabel("Administrator"); + $levelAdmin->setIsAdmin(true); + $levelAdmin->setIsDefault(false); + + $levelUser = new WorkspaceLevel(); + $levelUser->setWorkspace($workspace->getId()); + $levelUser->setLabel("User"); + $levelUser->setIsAdmin(false); + $levelUser->setIsDefault(true); + + $this->doctrine->persist($levelAdmin); + $this->doctrine->persist($levelUser); + $this->doctrine->flush(); + + //init default apps + $this->init($workspace); + + //Add user in workspace + if ($userId != null) { + $this->wms->addMember($workspace->getId(), $userId, false, $levelAdmin->getId()); + } + + //Create default channels + $secret = $this->app->getContainer()->getParameter("node.secret"); + $uri = $this->app->getContainer()->getParameter("node.api") . + "companies/".$groupId."/workspaces/".$workspace->getId()."/". + "channels/defaultchannel"; + + $data = [ + "resource" => [ + "icon" => "πŸ’¬", + "name" => "General", + "description" => "", + "visibility" => "public", + "is_default" => true + ], + "options" => [], + "user_id" => $userId + ]; + + $res = $this->rest->post($uri, json_encode($data), [ + CURLOPT_HTTPHEADER => Array( + "Authorization: Token ".$secret, + "Content-Type: application/json" + ), + CURLOPT_CONNECTTIMEOUT => 1, + CURLOPT_TIMEOUT => 1 + ]); + + return $workspace; + + } + + public function init(Workspace $workspace) + { + $groupappsRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupApp"); + $grouppaceapps = $groupappsRepository->findBy(Array("group" => $workspace->getGroup())); + + $workspaceappRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceApp"); + $workspaceapps = $workspaceappRepository->findBy(Array("workspace" => $workspace)); + + if (count($grouppaceapps) != 0 && count($workspaceapps) == 0) { + + foreach ($grouppaceapps as $ga) { + if ($ga->getWorkspaceDefault()) { + + $this->workspaces_service->enableApp($workspace->getId(), $ga->getAppId()); + + } + } + + $this->doctrine->flush(); + } + + if ($workspace->getMemberCount() == 0) { + + $members = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser")->findBy(Array("workspace_id" => $workspace->getId())); + $workspace->setMemberCount(count($members)); + $this->doctrine->persist($workspace); + + $this->doctrine->flush(); + } + + //DΓ©jΓ  initialisΓ© + return false; + } + + public function duplicate($original_workspace_id, $name, $config, $currentUserId = null) + { + + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $original_workspace = $workspaceRepository->findOneBy(["id"=>$original_workspace_id]); + + if (!$original_workspace) { + return false; + } + + //Verify we have right to access this workspace + if ($currentUserId == null + || $this->wls->can($original_workspace_id, $currentUserId, "workspace:manage") + ) { + + $groupId = $original_workspace->getGroup(); + + $workspace = $this->create($name, $groupId, $currentUserId); + $this->doctrine->persist($workspace); + + if ($workspace && $workspace->getGroup() && !$workspace->getIsArchived() && !$workspace->getisDeleted()) { + + $workspacelevelRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceLevel"); + $original_workspacelevels = $workspacelevelRepository->findBy(Array("workspace_id" => $original_workspace)); + $adminLevelId = 0; + foreach ($original_workspacelevels as $level) { + if ($level->getIsAdmin()) { + $adminLevelId = $level->getId(); + } + } + + //Duplicate Rights + $old_levels_id_to_new_levels = Array(); + $workspacelevels = $workspacelevelRepository->findBy(Array("workspace" => $workspace)); + foreach ($workspacelevels as $level) { + if ($level->getIsAdmin()) { + $old_levels_id_to_new_levels[$adminLevelId . ""] = $level; + } + } + if ($config["users"] == "all" || $config["rights"]) { + foreach ($original_workspacelevels as $level) { + if (!$level->getIsAdmin()) { + $level = new WorkspaceLevel(); + $level->setWorkspace($workspace); + $level->setLabel($level->getLabel()); + $level->setIsAdmin($level->getIsAdmin()); + $level->setIsDefault($level->getIsDefault()); + $this->doctrine->persist($level); + $old_levels_id_to_new_levels[$level->getId() . ""] = $level; + } + } + $this->doctrine->flush(); + } + + //Duplicate users + if ($config["users"] == "all" || $config["users"] == "admins") { + $members = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser")->findBy(Array("workspace_id" => $original_workspace->getId())); + foreach ($members as $member) { + if ($member->getUserId() != $currentUserId && ($config["users"] == "all" || ($config["users"] == "admins" && $member->getLevelId() == $adminLevelId))) { + + //Add user with good level + if (isset($old_levels_id_to_new_levels[$member->getLevelId() . ""])) { + $level_id = $old_levels_id_to_new_levels[$member->getLevelId() . ""]->getId(); + $this->wms->addMember($workspace->getId(), $member->getUserId(), false, $level_id); + } + + } + } + } + + //Duplicate applications + $old_applications = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceApp")->findBy(Array("workspace" => $original_workspace)); + $new_applications = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceApp")->findBy(Array("workspace" => $workspace)); + foreach ($old_applications as $old_application) { + $found = false; + foreach ($new_applications as $new_application) { + if ($new_application->getGroupApp()->getId() == $old_application->getGroupApp()->getId()) { + $found = true; + break; + } + } + if (!$found) { + $app = new WorkspaceApp($workspace->getId(), $old_application->getGroupApp()->getId(), $old_application->getAppId()); + $this->doctrine->persist($app); + } + } + foreach ($new_applications as $new_application) { + $found = false; + foreach ($old_applications as $old_application) { + if ($new_application->getGroupApp()->getId() == $old_application->getGroupApp()->getId()) { + $found = true; + break; + } + } + if (!$found) { + $this->doctrine->remove($new_application); + } + } + $this->doctrine->flush(); + + + //Duplicate calendars + if ($config["calendars"]) { + $old_calendarLinks = $this->doctrine->getRepository("Twake\Calendar:LinkCalendarWorkspace")->findBy(Array("workspace" => $original_workspace)); + foreach ($old_calendarLinks as $calendarLink) { + $calendar = $calendarLink->getCalendar(); + if ($calendarLink->getOwner()) { + $new_calendar = new Calendar($calendar->getTitle(), $calendar->getColor(), $calendar->getIcsLink()); + $this->doctrine->persist($new_calendar); + $new_link = new LinkCalendarWorkspace($workspace, $new_calendar, true); + $new_link->setApplication($calendarLink->getApplication()); + } else { + $new_link = new LinkCalendarWorkspace($workspace, $calendar, false, $calendarLink->getCalendarRight()); + } + $this->doctrine->persist($new_link); + } + $this->doctrine->flush(); + } + + + //Duplicate channels + if ($config["streams"]) { + $current_streams = $this->doctrine->getRepository("Twake\Discussion:Stream")->findBy(Array("workspace" => $workspace)); + foreach ($current_streams as $stream) { + $this->doctrine->remove($stream); + } + $old_streams = $this->doctrine->getRepository("Twake\Discussion:Stream")->findBy(Array("workspace" => $original_workspace)); + foreach ($old_streams as $stream) { + $new_stream = new Channel($workspace, $stream->getName(), $stream->getIsPrivate(), $stream->getDescription()); + $new_stream->setType("stream"); + $this->doctrine->persist($new_stream); + + foreach ($stream->getMembers() as $member) { + $new_link = $new_stream->addMember($member); + $this->doctrine->persist($new_link); + } + } + $this->doctrine->flush(); + } + + //Duplicate labels + if ($config["drive_labels"]) { + $old_labels = $this->doctrine->getRepository("Twake\Drive:DriveLabel")->findBy(Array("workspace" => $original_workspace)); + foreach ($old_labels as $label) { + $new_label = new DriveLabel($workspace, $label->getName(), $label->getColor()); + $this->doctrine->persist($new_label); + } + $this->doctrine->flush(); + } + + //Duplicate boards + /*if ($config["boards"]) { + $old_boardLinks = $this->doctrine->getRepository("Twake\Project:LinkBoardWorkspace")->findBy(Array("workspace" => $original_workspace)); + foreach ($old_boardLinks as $boardLink) { + $board = $boardLink->getBoard(); + if ($boardLink->getOwner()) { + $new_board = new Board($board->getTitle(), $board->getDescription(), $board->getisPrivate()); + $new_board->setParticipants($board->getParticipants()); + $this->doctrine->persist($new_board); + + //Add lists + $listOfTasks = $this->doctrine->getRepository("Twake\Project:ListOfTasks")->findBy(Array("board" => $board)); + foreach ($listOfTasks as $listOfTask) { + $new_listOfTask = new ListOfTasks($new_board, $listOfTask->getTitle(), $listOfTask->getColor(), $listOfTask->getUserIdToNotify()); + $this->doctrine->persist($new_listOfTask); + } + + $new_link = new LinkBoardWorkspace($workspace, $new_board, true); + } else { + $new_link = new LinkBoardWorkspace($workspace, $board, false, $boardLink->getBoardRight()); + } + $this->doctrine->persist($new_link); + } + $this->doctrine->flush(); + }*/ + + } + + return $workspace; + + } + + return false; + + } + + public function remove($groupId, $workspaceId, $currentUserId = null) + { + if ($currentUserId == null + || ($this->wls->can($workspaceId, $currentUserId, "workspace:write") + && count($this->wms->getMembers($workspaceId)) <= 1 + ) + || $this->gms->hasPrivileges($this->gms->getLevel($groupId, $currentUserId), "MANAGE_WORKSPACES") + ) { + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + $this->wms->removeAllMember($workspaceId); + + if(!$workspace){ + return true; + } + + $workspace->setIsDeleted(true); + + $this->doctrine->persist($workspace); + $this->doctrine->flush(); + + return true; + } + return false; + } + + public function changeName($workspaceId, $name, $currentUserId = null) + { + if ($currentUserId == null + || $this->wls->can($workspaceId, $currentUserId, "workspace:write") + ) { + + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + $workspace->setName($name); + + $uniquename = $this->string_cleaner->simplify($name); + $uniquenameIncremented = $uniquename . "-" . substr(md5(date("U") . rand()), 0, 10); + + $workspace->setUniqueName($uniquenameIncremented); + $this->doctrine->persist($workspace); + $this->doctrine->flush(); + + return true; + } + + return false; + } + + public function changeLogo($workspaceId, $logo, $currentUserId = null, $uploader = null) + { + if ($currentUserId == null + || $this->wls->can($workspaceId, $currentUserId, "workspace:write") + ) { + + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + $workspace->setLogo($logo); + + $this->doctrine->persist($workspace); + $this->doctrine->flush(); + + return $workspace; + } + + return false; + } + + public function changeWallpaper($workspaceId, $wallpaper, $color = null, $currentUserId = null, $uploader = null) + { + + if ($color == null) { + $color = "#7E7A6D"; + } + + if ($currentUserId == null + || $this->wls->can($workspaceId, $currentUserId, "workspace:write") + ) { + + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + if ($workspace->getWallpaper()) { + if ($uploader) { + $uploader->removeFile($workspace->getWallpaper(), false); + } else { + $workspace->getWallpaper()->deleteFromDisk(); + } + $this->doctrine->remove($workspace->getWallpaper()); + } + $workspace->setWallpaper($wallpaper); + $workspace->setColor($color); + + $this->doctrine->persist($workspace); + $this->doctrine->flush(); + + $datatopush = Array( + "type" => "CHANGE_WORKSPACE", + "data" => Array( + "workspaceId" => $workspace->getId(), + ) + ); + $this->workspacesActivities->recordActivity($workspace, $currentUserId, "workspace", "workspace.activity.workspace.change_wallpaper", "Twake\Workspaces:Workspace", $workspaceId); + $this->pusher->push($datatopush, "group/" . $workspace->getId()); + + return true; + } + + return false; + } + + public function get($workspaceId, $currentUserId = null) + { + + if ($currentUserId == null + || $this->wls->can($workspaceId, $currentUserId, "") + ) { + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + return $workspace; + } + + return false; + } + + public function getWorkspaceByName($string, $currentUserId = null) + { + + $arr = explode("@", $string, 2); + + if (count($arr) != 2) { + return false; + } + + $groupName = $arr[0]; + $workspaceName = $arr[1]; + + + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $group = $groupRepository->findOneBy(Array("name" => $groupName)); + + if ($group == null) { + return false; + } + + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(Array("uniquename" => $workspaceName, "group" => $group, "is_deleted" => 0)); + + if ($workspace != null) { + return $workspace->getAsArray($this->doctrine); + } else { + return false; + } + + } + + public function archive($groupId, $workspaceId, $currentUserId = null) + { + + if ($currentUserId == null + || ($this->wls->can($workspaceId, $currentUserId, "workspace:write") + && count($this->wms->getMembers($workspaceId)) <= 1 + ) + || $this->gms->hasPrivileges($this->gms->getLevel($groupId, $currentUserId), "MANAGE_WORKSPACES") + ) { + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + $isArchived = $workspace->getIsArchived(); + $is_deleted = $workspace->getIsDeleted(); + + if ($is_deleted == false && $isArchived == false) { + $workspace->setIsArchived(true); + $this->workspacesActivities->recordActivity($workspace, $currentUserId, "workspace", "workspace.activity.workspace.archive", "Twake\Workspaces:Workspace", $workspaceId); + } + + $this->doctrine->persist($workspace); + $this->doctrine->flush(); + + $datatopush = Array( + "type" => "CHANGE_WORKSPACE", + "data" => Array( + "workspaceId" => $workspace->getId(), + ) + ); + $this->pusher->push($datatopush, "group/" . $workspace->getId()); + + return true; + } + return false; + + } + + public function unarchive($groupId, $workspaceId, $currentUserId = null) + { + + if ($currentUserId == null + || ($this->wls->can($workspaceId, $currentUserId, "workspace:write") + && count($this->wms->getMembers($workspaceId)) <= 1 + ) + || $this->gms->hasPrivileges($this->gms->getLevel($groupId, $currentUserId), "MANAGE_WORKSPACES") + ) { + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + $isArchived = $workspace->getIsArchived(); + $is_deleted = $workspace->getIsDeleted(); + + if ($is_deleted == false && $isArchived == true) { + $workspace->setIsArchived(false); + $this->workspacesActivities->recordActivity($workspace, $currentUserId, "workspace", "workspace.activity.workspace.unarchive", "Twake\Workspaces:Workspace", $workspaceId); + } + + $this->doctrine->persist($workspace); + $this->doctrine->flush(); + + $datatopush = Array( + "type" => "CHANGE_WORKSPACE", + "data" => Array( + "workspaceId" => $workspace->getId(), + ) + ); + $this->pusher->push($datatopush, "group/" . $workspace->getId()); + + return true; + } + return false; + + } + + + public function hideOrUnhideWorkspace($workspaceId, $currentUserId = null, $wanted_value = null) + { + if ($currentUserId != null) { + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(Array("id" => $workspaceId)); + + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $currentUser = $userRepository->findOneBy(Array("id" => $currentUserId)); + + $workspaceUserRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + $workspaceUser = $workspaceUserRepository->findOneBy(Array("workspace_id" => $workspace->getId(), "user_id" => $currentUser->getId())); + + if ($wanted_value === null) { + $ishidden = $workspaceUser->getisHidden(); + $workspaceUser->setisHidden(!$ishidden); + } + $workspaceUser->setisHidden($wanted_value); + + $this->doctrine->persist($workspaceUser); + $this->doctrine->flush(); + + if ($currentUserId) { + $datatopush = Array( + "type" => "USER_WORKSPACES", + "data" => Array( + "workspaceId" => $workspace->getId(), + ) + ); + $this->pusher->push($datatopush, "notifications/" . $currentUserId); + } + + return true; + } + return false; + } + + public function haveNotificationsOrNotWorkspace($workspaceId, $currentUserId = null, $wanted_value = null) + { + if ($currentUserId != null) { + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(Array("id" => $workspaceId)); + + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $currentUser = $userRepository->findOneBy(Array("id" => $currentUserId)); + + $workspaceUserRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + $workspaceUser = $workspaceUserRepository->findOneBy(Array("workspace_id" => $workspace->getId(), "user_id" => $currentUser->getId())); + + if ($wanted_value === null) { + $hasnotifications = $workspaceUser->getHasNotifications(); + $workspaceUser->setHasNotifications(!$hasnotifications); + } + $workspaceUser->setHasNotifications($wanted_value); + + $notificationPreference = $currentUser->getNotificationPreference(); + $disabled_ws = $notificationPreference["disabled_workspaces"]; + if (in_array($workspaceId . "", $disabled_ws) && $workspaceUser->getHasNotifications()) { + $position = array_search($workspaceId, $disabled_ws); + unset($disabled_ws[$position]); + } + + if (!in_array($workspaceId . "", $disabled_ws) && !$workspaceUser->getHasNotifications()) { + array_push($disabled_ws, $workspaceId); + } + + $this->doctrine->persist($workspaceUser); + $this->doctrine->flush(); + return true; + } + return false; + } + + public function favoriteOrUnfavoriteWorkspace($workspaceId, $currentUserId = null) + { + $result = Array(); + + if ($currentUserId != null) { + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(Array("id" => $workspaceId)); + + $userRepository = $this->doctrine->getRepository("Twake\Users:User"); + $currentUser = $userRepository->findOneBy(Array("id" => $currentUserId)); + + $workspaceUserRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceUser"); + $workspaceUser = $workspaceUserRepository->findOneBy(Array("workspace_id" => $workspace->getId(), "user_id" => $currentUser->getId())); + + $isfavorite = $workspaceUser->getisFavorite(); + $workspaceUser->setisFavorite(!$isfavorite); + $this->doctrine->persist($workspaceUser); + + $this->doctrine->flush(); + + + if ($currentUserId) { + $datatopush = Array( + "type" => "USER_WORKSPACES", + "data" => Array( + "workspaceId" => $workspace->getId(), + ) + ); + $this->pusher->push($datatopush, "notifications/" . $currentUserId); + } + + $result["answer"] = true; + $result["isfavorite"] = $workspaceUser->getisFavorite(); + + return $result; + } + $result["answer"] = false; + return $result; + } + + public function setIsNew($value, $workspaceId, $currentUserId = null) + { + if ($currentUserId != null) { + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(Array("id" => $workspaceId)); + + if ($workspace != null) { + + $workspace->setisNew($value); + $this->doctrine->persist($workspace); + $this->doctrine->flush(); + + return true; + } + return false; + } + return false; + } + + public function search($group_id) + { + +// $terms = Array(); +// foreach ($words as $word){ +// $terms[] = Array( +// "bool" => Array( +// "filter" => Array( +// "regexp" => Array( +// "name" => ".*".$word.".*" +// ) +// ) +// ) +// ); +// } + + $options = Array( + "repository" => "Twake\Workspaces:Workspace", + "index" => "workspace", + "query" => Array( + "bool" => Array( + "must" => Array( + "match_phrase" => Array( + "company_id" => $group_id + ) + ) +// "should" => $terms, +// "minimum_should_match" => 1 + ) + ) + ); + + + $workspaces = $this->doctrine->es_search($options); + $result = []; + + foreach ($workspaces["result"] as $workspace) { + $result[] = $workspace[0]->getAsArray(); + } + + return $result; + + } + +} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Workspaces/Services/WorkspacesActivities.php b/twake/backend/core/src/Twake/Workspaces/Services/WorkspacesActivities.php new file mode 100755 index 00000000..d1f0aaf9 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Services/WorkspacesActivities.php @@ -0,0 +1,159 @@ +<?php +/** + * Created by PhpStorm. + * User: ehlnofey + * Date: 31/07/18 + * Time: 14:45 + */ + +namespace Twake\Workspaces\Services; + + +use Doctrine\ORM\ORMException; +use Dompdf\Exception; +use Twake\Market\Services\MarketApplication; +use Twake\Workspaces\Entity\WorkspaceActivity; +use App\App; + +class WorkspacesActivities +{ + /* @var MarketApplication $applicationManager */ + var $applicationManager; + private $doctrine; + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->applicationManager = $app->getServices()->get("app.applications"); + } + + public static function cmpResumed($a, $b) + { + return $b["date"] - $a["date"]; + } + + public function recordActivity($workspace, $user, $appPublicKey, $title, $objectrepository = null, $objectid = null) + { + $workspace = $this->convertToEntity($workspace, "Twake\Workspaces:Workspace"); + $user = $this->convertToEntity($user, "Twake\Users:User"); + $app = $this->applicationManager->getAppByPublicKey($appPublicKey); + + $workspaceActivity = new WorkspaceActivity($workspace->getId(), $user, $app, $title, $objectrepository, $objectid); + + $this->doctrine->persist($workspaceActivity); + $this->doctrine->flush(); + } + + private function convertToEntity($var, $repository) + { + if (is_string($var)) { + $var = $var; // Cassandra id do nothing + } + + if (is_int($var) || is_string($var) || get_class($var) == "Ramsey\Uuid\Uuid") { + try { + $r = $this->doctrine->getRepository($repository)->find($var); + } catch (ORMException $e) { + $r = null; + } + } else if (is_object($var)) { + $r = $var; + } else { + $r = null; + } + return $r; + + } + + public function getRecordByWorkspace($workspace) + { + $workspace = $this->convertToEntity($workspace, "Twake\Workspaces:Workspace"); + return $this->doctrine->getRepository("Twake\Workspaces:WorkspaceActivity")->findBy(Array("workspace" => $workspace)); + } + + public function getWorkspaceActivityResumed($workspace, $userIdsList, $limit = 100, $offset = 0) + { + $workspace = $this->convertToEntity($workspace, "Twake\Workspaces:Workspace"); + $users = []; + + foreach ($userIdsList as $user) { + $users[] = $this->convertToEntity($user["user"], "Twake\Users:User"); + } + + /* @var WorkspaceActivity[] $activities */ + $activities = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceActivity")->findBy(Array("workspace" => $workspace), Array("id" => "desc"), $limit, $offset); + + // Get activity by unique user/app id + $activities_by_user_app = Array(); + $last_date_by_user_app = Array(); + foreach ($activities as $activity) { + + $key = ($activity->getApp() ? $activity->getApp()->getId() : "") . "_" . ($activity->getUser() ? $activity->getUser()->getId() : ""); + + if (!isset($activities_by_user_app[$key])) { + $activities_by_user_app[$key] = Array(); + } + $addToPrevious = false; + if (isset($last_date_by_user_app[$key]) && abs($activity->getDateAdded()->getTimestamp() - $last_date_by_user_app[$key]) < 60) { + $addToPrevious = true; + } + if ($addToPrevious) { + end($activities_by_user_app[$key]); + $end_pos = key($activities_by_user_app[$key]); + if ($activity->getObjectRepository()) { + try { + $obj = $this->convertToEntity($activity->getObjectId(), $activity->getObjectRepository()); + if ($obj && isset($activities_by_user_app[$key][$end_pos]["objects"])) { + $found = false; + foreach ($activities_by_user_app[$key][$end_pos]["objects"] as $o) { + if ($o["id"] == $obj->getId()) { + $found = true; + break; + } + } + if (!$found && method_exists($obj, "getAsArrayFormated")) { + $activities_by_user_app[$key][$end_pos]["objects"][] = $obj->getAsArrayFormated(); + } + } + } catch (\Exception $e) { + error_log($e); + } + } + } else { + $objects = Array(); + if ($activity->getObjectRepository()) { + try { + $obj = $this->convertToEntity($activity->getObjectId(), $activity->getObjectRepository()); + if ($obj && method_exists($obj, "getAsArrayFormated")) { + $objects[] = $obj->getAsArrayFormated(); + } + } catch (\Exception $e) { + error_log($e); + } + } + if (count($objects) > 0) { + $activities_by_user_app[$key][] = Array( + "user" => ($activity->getUser() ? $activity->getUser()->getAsArray() : null), + "app" => ($activity->getApp() ? $activity->getApp()->getAsSimpleArray() : null), + "date" => $activity->getDateAdded()->getTimestamp(), + "title" => $activity->getTitle(), + "objects" => $objects + ); + } + } + + $last_date_by_user_app[$key] = $activity->getDateAdded()->getTimestamp(); + + } + + + $resumed = Array(); + foreach ($activities_by_user_app as $grouped_activity) { + $resumed = array_merge($resumed, $grouped_activity); + } + + usort($resumed, "self::cmpResumed"); + + return $resumed; + } +} diff --git a/twake/backend/core/src/Twake/Workspaces/Services/WorkspacesApps.php b/twake/backend/core/src/Twake/Workspaces/Services/WorkspacesApps.php new file mode 100755 index 00000000..6f129a57 --- /dev/null +++ b/twake/backend/core/src/Twake/Workspaces/Services/WorkspacesApps.php @@ -0,0 +1,259 @@ +<?php + +namespace Twake\Workspaces\Services; + +use Twake\Discussion\Entity\Channel; +use Twake\Workspaces\Entity\GroupApp; +use Twake\Workspaces\Entity\WorkspaceApp; +use Twake\Workspaces\Model\WorkspacesAppsInterface; +use Twake\Workspaces\Model\WorkspacesInterface; +use App\App; + +class WorkspacesApps +{ + + private $wls; + private $doctrine; + private $gms; + private $pusher; + private $channel_system; + private $application_api; + + public function __construct(App $app) + { + $this->doctrine = $app->getServices()->get("app.twake_doctrine"); + $this->wls = $app->getServices()->get("app.workspace_levels"); + $this->gms = $app->getServices()->get("app.group_managers"); + $this->pusher = $app->getServices()->get("app.pusher"); + $this->channel_system = $app->getServices()->get("app.channels.channels_system"); + $this->application_api = $app->getServices()->get("app.applications_api"); + } + + public function getApps($workspaceId, $currentUserId = null, $onlymessageModule = false, $onlyEditableRights = false) + { + + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(["id"=>$workspaceId]); + + if ($workspace == null) { + return false; + } + + if ($currentUserId == null + || $this->wls->can($workspaceId, $currentUserId, "")) { + + //Group apps + $workspaceappsRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceApp"); + $workspaceapps = $workspaceappsRepository->findBy(Array("workspace_id" => $workspace)); + + $applicationRepository = $this->doctrine->getRepository("Twake\Market:Application"); + $groupappsRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupApp"); + + $apps = array(); + foreach ($workspaceapps as $wa) { + + $app = $applicationRepository->findOneBy(Array("id" => $wa->getAppId())); + + if (!$app) { + + $this->disableApp($workspace->getId(), $wa->getAppId()); + + } else { + + + $groupapp = $groupappsRepository->findOneBy(Array("group" => $workspace->getGroupEntity($this->doctrine), "app_id" => $app->getId())); + + if($groupapp){ + + $workspace_app = $groupapp->getAsArray(); + $workspace_app["workspace_id"] = $workspace->getId(); + $workspace_app["app"] = $app->getAsArray(); + + $apps[] = $workspace_app; + + } + + } + } + return $apps; + } + + return false; + + } + + public function disableApp($workspaceId, $applicationId, $currentUserId = null) + { + $current_user_id = $currentUserId; + + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(Array("id" => $workspaceId)); + + $appRepository = $this->doctrine->getRepository("Twake\Market:Application"); + $app = $appRepository->findOneBy(Array("id" => $applicationId)); + + if ($workspace == null || $app == null) { + return false; + } + + if ($currentUserId == null + || $this->wls->can($workspaceId, $currentUserId, "workspace:write")) { + + //Search WorkspaceApp targeting the app + $groupappsRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupApp"); + $groupapp = $groupappsRepository->findOneBy(Array("group" => $workspace->getGroupEntity($this->doctrine), "app_id" => $app->getId())); + + + $groupapp->setWorkspacesCount($groupapp->getWorkspacesCount() - 1); + + $app->setInstallCount($app->getInstallCount() - 1); + $this->doctrine->persist($app); + + $workspaceappsRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceApp"); + $workspaceapp = $workspaceappsRepository->findOneBy(Array("workspace_id" => $workspace, "groupapp_id" => $groupapp->getId())); + + if ($groupapp->getWorkspacesCount() <= 0) { + $this->doctrine->remove($groupapp); + } + + $this->doctrine->remove($workspaceapp); + $this->doctrine->flush(); + + //Remove resource access to workspace + $this->application_api->removeResource($app->getId(), $workspace->getId(), "workspace", $workspace->getId(), $current_user_id); + + $workspace_app = $groupapp->getAsArray(); + $workspace_app["workspace_id"] = $workspace->getId(); + $workspace_app["app"] = $app->getAsArray(); + + $datatopush = Array( + "type" => "remove", + "workspace_app" => $workspace_app + ); + $this->pusher->push($datatopush, "workspace_apps/" . $workspace->getId()); + + $this->channel_system->removeApplicationChannel($app, $workspace); + + return true; + } + + return false; + } + + public function forceApplication($groupId, $appid, $currentUserId = null) + { + $groupRepository = $this->doctrine->getRepository("Twake\Workspaces:Group"); + $group = $groupRepository->find($groupId); + + $applicationRepository = $this->doctrine->getRepository("Twake\Market:Application"); + $application = $applicationRepository->findOneBy(Array("id" => $appid)); + + if ($group == null || $application == null) { + return false; + } + + if ($currentUserId == null + || $this->gms->hasPrivileges( + $this->gms->getLevel($groupId, $currentUserId), + "MANAGE_APPS" + ) + ) { + $workspaces = $group->getWorkspaces(); + foreach ($workspaces as $workspace) { + + $this->enableApp($workspace->getId(), $appid, null); + + } + + return true; + } + return false; + } + + public function enableApp($workspaceId, $applicationId, $currentUserId = null) + { + + + + $current_user_id = $currentUserId; + + $workspaceRepository = $this->doctrine->getRepository("Twake\Workspaces:Workspace"); + $workspace = $workspaceRepository->findOneBy(Array("id" => $workspaceId)); + + $appRepository = $this->doctrine->getRepository("Twake\Market:Application"); + $app = $appRepository->findOneBy(Array("id" => $applicationId)); + + if ($workspace == null || $app == null) { + error_log("hello 2"); + error_log($applicationId); + return false; + } + + if ($currentUserId == null + || $this->wls->can($workspaceId, $currentUserId, "workspace:write")) { + + //Search in GroupApp if the targeted app exists + $groupappsRepository = $this->doctrine->getRepository("Twake\Workspaces:GroupApp"); + $groupapp = $groupappsRepository->findOneBy(Array("group" => $workspace->getGroupEntity($this->doctrine), "app_id" => $app->getId())); + + if ($groupapp == null) { + $groupapp = new GroupApp($workspace->getGroupEntity($this->doctrine), $app->getId()); + $this->doctrine->persist($groupapp); + } + + $groupapp->setPrivilegesCapabilitiesLastRead(new \DateTime()); + $groupapp->setCapabilities($app->getCapabilities()); + $groupapp->setPrivileges($app->getPrivileges()); + $groupapp->setHooks($app->getHooks()); + + //Search if the App is already enabled + $workspaceappsRepository = $this->doctrine->getRepository("Twake\Workspaces:WorkspaceApp"); + $workspaceapp = $workspaceappsRepository->findOneBy(Array("workspace_id" => $workspace, "groupapp_id" => $groupapp->getId())); + + if ($workspaceapp) { + $this->doctrine->persist($groupapp); + $this->doctrine->flush(); + return true; + } + + $groupapp->setWorkspacesCount($groupapp->getWorkspacesCount() + 1); + $this->doctrine->persist($groupapp); + + $app->setInstallCount($app->getInstallCount() + 1); + $this->doctrine->persist($app); + + $workspaceapp = new WorkspaceApp($workspace->getId(), $groupapp->getId(), $groupapp->getAppId()); + $this->doctrine->persist($workspaceapp); + $this->doctrine->flush(); + + //Add resource access to workspace if workspace privilege is requested + if (in_array("workspace", $app->getPrivileges())) { + $this->application_api->addResource($app->getId(), $workspace->getId(), "workspace", $workspace->getId(), $current_user_id); + } + if (in_array("workspace_calendar", $app->getPrivileges())) { + $this->application_api->addResource($app->getId(), $workspace->getId(), "workspace_calendar", $workspace->getId(), $current_user_id); + } + if (in_array("workspace_drive", $app->getPrivileges())) { + $this->application_api->addResource($app->getId(), $workspace->getId(), "workspace_drive", $workspace->getId(), $current_user_id); + } + + $workspace_app = $groupapp->getAsArray(); + $workspace_app["workspace_id"] = $workspace->getId(); + $workspace_app["app"] = $app->getAsArray(); + + $datatopush = Array( + "type" => "add", + "workspace_app" => $workspace_app + ); + $this->pusher->push($datatopush, "workspace_apps/" . $workspace->getId()); + + $this->channel_system->getApplicationChannel($app, $workspace); + + return true; + } + + return false; + } + + +} \ No newline at end of file diff --git a/twake/backend/core/tests/AccessBundle/AccessTest.php b/twake/backend/core/tests/AccessBundle/AccessTest.php new file mode 100755 index 00000000..6e3f0737 --- /dev/null +++ b/twake/backend/core/tests/AccessBundle/AccessTest.php @@ -0,0 +1,821 @@ +<?php + +namespace Tests\AccessBundle; + + +require_once __DIR__ . "/../WebTestCaseExtended.php"; + +use Tests\WebTestCaseExtended; +use Twake\Calendar\Entity\Calendar; +use Twake\Channels\Entity\Channel; +use Twake\Discussion\Entity\Message; +use Twake\Users\Entity\User; +use Twake\Workspaces\Entity\WorkspaceUser; +use Twake\Workspaces\Entity\Workspace; +use Twake\Workspaces\Entity\Group; + +class AccessTest extends WebTestCaseExtended +{ + public function testAccess() + { + + +//// ================================================================================================================================================= +//// ================================================================================================================================================= + + // ON CREE UN GROUP POUR CREER NOS DEUX WORKSPACES + $group = new Group("group_for_test"); + $this->get("app.twake_doctrine")->persist($group); + $this->get("app.twake_doctrine")->flush(); + + // ON CREE NOS DEUX WORKSPACES POUR FAIRE NOS TESTS + + //creation du premier workspace + $workspace1 = new Workspace("workspace1_for_test"); + $workspace1->setGroup($group); + $this->get("app.twake_doctrine")->persist($workspace1); + $this->get("app.twake_doctrine")->flush(); + $workspace1_id = $workspace1->getId() . ""; + + //creation du deuxieme workspace + $workspace2 = new Workspace("workspace2_for_test"); + $workspace2->setGroup($group); + $this->get("app.twake_doctrine")->persist($workspace2); + $this->get("app.twake_doctrine")->flush(); + $workspace2_id = $workspace2->getId() . ""; + +//// ================================================================================================================================================= +//// ================================================================================================================================================= + + //ON CREE LES USERS + + $this->removeUserByName("usertest003"); + $this->newUserByName("usertest003"); + + $this->doPost("/ajax/users/login", Array( + "_username" => "usertest003", + "_password" => "usertest003" + )); + $result = $this->doPost("/ajax/users/current/get", Array()); + $user3_id = $result["data"]["id"]; + + + $result = $this->doPost("/ajax/users/logout", Array()); + $this->clearClient(); + + $this->removeUserByName("usertest002"); + $this->newUserByName("usertest002"); + + $this->doPost("/ajax/users/login", Array( + "_username" => "usertest002", + "_password" => "usertest002" + )); + $result = $this->doPost("/ajax/users/current/get", Array()); + $user2_id = $result["data"]["id"]; + + $result = $this->doPost("/ajax/users/logout", Array()); + $this->clearClient(); + + $this->removeUserByName("usertest001"); + $this->newUserByName("usertest001"); + + $this->doPost("/ajax/users/login", Array( + "_username" => "usertest001", + "_password" => "usertest001" + )); + $result = $this->doPost("/ajax/users/current/get", Array()); + $user1_id = $result["data"]["id"]; + + $user1 = $this->get("app.twake_doctrine")->getRepository("Twake\Users:User")->findOneBy(Array("id" => $user1_id)); + $user2 = $this->get("app.twake_doctrine")->getRepository("Twake\Users:User")->findOneBy(Array("id" => $user2_id)); + $user3 = $this->get("app.twake_doctrine")->getRepository("Twake\Users:User")->findOneBy(Array("id" => $user3_id)); + +//// ================================================================================================================================================= +//// ================================================================================================================================================= + + // POUR FAIRE LE LIEN ENTRE LE USER1 ET LE WORKSPACE 1 (RESPECTIVEMENT USER2 WORKSPACE2) -> ON CREE DEUX WORKSPACEUSERS + $workspace1 = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:Workspace")->findOneBy(Array("id" => $workspace1_id)); + $workspace2 = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:Workspace")->findOneBy(Array("id" => $workspace2_id)); + +// //creation workspaceUser1 + $workspaceUser1 = new WorkspaceUser($workspace1, $user1, null); + $this->get("app.twake_doctrine")->persist($workspaceUser1); + $this->get("app.twake_doctrine")->flush(); + + //creation workspaceUser2 + $workspaceUser2 = new WorkspaceUser($workspace2, $user2, null); + $this->get("app.twake_doctrine")->persist($workspaceUser2); + $this->get("app.twake_doctrine")->flush(); + + //creation workspaceUser3 + $workspaceUser3 = new WorkspaceUser($workspace1, $user3, null); + $this->get("app.twake_doctrine")->persist($workspaceUser3); + $this->get("app.twake_doctrine")->flush(); + +//// ================================================================================================================================================= +//// ================================================================================================================================================= + + //POUR CHAQUE WORKSPACE, ON CREE DEUX CHANNELS + + //pour le workspace1 + $channel1 = new Channel(); + $channel1->setOriginalWorkspaceId($workspace1_id); + $channel1->setMembers(Array($user1_id)); // pour donner acces a user1 au channel1 + $channel1->setExtMembers(Array($user3_id)); + $this->get("app.twake_doctrine")->persist($channel1); + $this->get("app.twake_doctrine")->flush(); + $channel1_ID = $channel1->getId(); + + $channel2 = new Channel(); + $channel2->setOriginalWorkspaceId($workspace1_id); + $channel2->setMembers(Array($user1_id)); // pour donner acces a user1 au channel2 + + $this->get("app.twake_doctrine")->persist($channel2); + $this->get("app.twake_doctrine")->flush(); + $channel2_ID = $channel2->getId(); + + //pour le workspace2 + $channel3 = new Channel(); + $channel3->setOriginalWorkspaceId($workspace2_id); + $channel3->setMembers(Array($user2_id)); // pour donner acces a user2 au channel3 + $this->get("app.twake_doctrine")->persist($channel3); + $this->get("app.twake_doctrine")->flush(); + $channel3_ID = $channel3->getId(); + + $channel4 = new Channel(); + $channel4->setOriginalWorkspaceId($workspace2_id); + $channel4->setMembers(Array($user2_id)); // pour donner acces a user2 au channel4 + $this->get("app.twake_doctrine")->persist($channel4); + $this->get("app.twake_doctrine")->flush(); + $channel4_ID = $channel4->getId(); + +//// ================================================================================================================================================= +//// ================================================================================================================================================= + + // ON CREE DEUX MESSAGES PAR CHANNEL + + //pour le channel 1 + $message1 = new Message($channel1_ID, "null"); + $this->get("app.twake_doctrine")->persist($message1); + $this->get("app.twake_doctrine")->flush(); + $message1_ID = $message1->getId(); + + $message2 = new Message($channel1_ID, "null"); + $this->get("app.twake_doctrine")->persist($message2); + $this->get("app.twake_doctrine")->flush(); + $message2_ID = $message2->getId(); + + //pour le channel 2 + $message3 = new Message($channel2_ID, "null"); + $this->get("app.twake_doctrine")->persist($message3); + $this->get("app.twake_doctrine")->flush(); + $message3_ID = $message3->getId(); + + $message4 = new Message($channel2_ID, "null"); + $this->get("app.twake_doctrine")->persist($message4); + $this->get("app.twake_doctrine")->flush(); + $message4_ID = $message4->getId(); + + //pour le channel 3 + $message5 = new Message($channel3_ID, "null"); + $this->get("app.twake_doctrine")->persist($message5); + $this->get("app.twake_doctrine")->flush(); + $message5_ID = $message5->getId(); + + $message6 = new Message($channel3_ID, "null"); + $this->get("app.twake_doctrine")->persist($message6); + $this->get("app.twake_doctrine")->flush(); + $message6_ID = $message6->getId(); + + //pour le channel 4 + $message7 = new Message($channel4_ID, "null"); + $this->get("app.twake_doctrine")->persist($message7); + $this->get("app.twake_doctrine")->flush(); + $message7_ID = $message7->getId(); + + $message8 = new Message($channel4_ID, "null"); + $this->get("app.twake_doctrine")->persist($message8); + $this->get("app.twake_doctrine")->flush(); + $message8_ID = $message8->getId(); + +//// ================================================================================================================================================= +//// ================================================================================================================================================= + + // ON RECUPERE LA RACINE DE CE NOUVEAU WORKSPACE ET ON CREE DEUX FICHIER + $root = $this->get("app.drive")->getRootEntity($workspace1_id); + $root_id = $root->getId() . ""; + + $object = Array("parent_id" => $root_id, "workspace_id" => $workspace1_id . "", "front_id" => "14005200-48b1-11e9-a0b4-0242ac120005", "name" => "filefortest", "is_directory" => false); + $data = Array("upload_mode" => "chunk", "identifier" => "identifier", "nb_chunk" => 1); + $options = Array("new" => true, "data" => $data, "version" => true); + $result = $this->doPost("/ajax/drive/v2/save", Array( + "object" => $object, + "options" => $options + )); + $idtofind_parent = $result["data"]["object"]["id"]; + + $object = Array("workspace_id" => $workspace1_id, "front_id" => "14005200-48b1-11e9-a0b4-0242ac120005", "name" => "filefortest", "detached" => true, "is_directory" => false); + $options = Array("new" => true, "data" => $data, "version" => true); + $result = $this->doPost("/ajax/drive/v2/save", Array( + "object" => $object, + "options" => $options + )); + $idtofind_detached = $result["data"]["object"]["id"]; + + $object = Array("parent_id" => $root_id, "workspace_id" => $workspace1_id, "front_id" => "14005200-48b1-11e9-a0b4-0242ac120005", "name" => "filefortest", "is_directory" => false); + $data = Array("upload_mode" => "chunk", "identifier" => "identifier", "nb_chunk" => 1); + $options = Array("new" => true, "data" => $data, "version" => true); + $result = $this->doPost("/ajax/drive/v2/save", Array( + "object" => $object, + "options" => $options + )); + $idtofind_shared = $result["data"]["object"]["id"]; + //error_log(print_r($idtofind_shared,true)); + + //$file = $this->get("app.twake_doctrine")->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_shared)); +// $file->setShared(true); +// $this->get("app.twake_doctrine")->persist($file); +// $this->get("app.twake_doctrine")->flush(); + + /* + $result = $this->doPost("/ajax/drive/publicaccess", Array( + "file_id" => $idtofind_shared, + "is_editable" => false, + "authorized_members" => Array($user3_id), + "authorized_channels" => Array() + )); + + $file = $this->get("app.twake_doctrine")->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_shared)); + $publicdata = $file->getAccesInfo(); + // error_log(print_r($publicdata, true)); + + $this->assertEquals(true, in_array($user3_id, $publicdata["authorized_members"]), "User 3 id is not inside the public data of file shared"); + */ + +//// ================================================================================================================================================= +//// ================================================================================================================================================= + + $calendar = new Calendar($workspace1_id, "calendarfortest", "red"); + $this->get("app.twake_doctrine")->persist($calendar); + $this->get("app.twake_doctrine")->flush(); + + $id_calendar = $calendar->getId(); + +//// ================================================================================================================================================= +//// ================================================================================================================================================= + + //ON VERIFIE ... + + //test que le user1 a acces au workspace1 + $data = Array("type" => "Workspace", "object_id" => $workspace1_id); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(true, $result["data"], "User 1 don't have acces to the workspace 1 , he should"); + + //test que le user1 n'a pas acces au workspace2 + $data = Array("type" => "Workspace", "object_id" => $workspace2_id); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(false, $result["data"], "User 1 have acces to the workspace 2 , he shouldn't"); + + + //test que le user1 a acces au channel 1 et 2 du workspace 1 + + $data = Array("type" => "Channel", "object_id" => $channel1_ID); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(true, $result["data"], "User 1 don't have acces to the channel 1 , he should"); + + + $data = Array("type" => "Channel", "object_id" => $channel2_ID); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(true, $result["data"], "User 1 don't have acces to the channel 2 , he should"); + + + // test que le user1 n'a pas acces au channel 2 et 3 du workspace 2 + $data = Array("type" => "Channel", "object_id" => $channel3_ID); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(false, $result["data"], "User 1 have acces to the channel 3 , he shouldn't"); + + + $data = Array("type" => "Channel", "object_id" => $channel4_ID); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(false, $result["data"], "User 1 have acces to the channel 4 , he shouldn't"); + + //test que le user1 a acces au message 1 par exemple (doit aussi fonctionner avec les messages 2, 3 et 4) + $data = Array("type" => "Message", "object_id" => $message1_ID); + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + $this->assertEquals(true, $result["data"], "User 1 don't have acces to the message 1 , he should"); + + //test que le user 1 n'a pas acces au message 5 par exemple (doit aussi fonctionner aves les messages 6, 7 et 8) + $data = Array("type" => "Message", "object_id" => $message5_ID); + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + $this->assertEquals(false, $result["data"], "User 1 have acces to the message 1 , he shouldn't"); + + $data = Array("type" => "DriveFile", "object_id" => $idtofind_parent); + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + $this->assertEquals(true, $result["data"], "User 1 don't have access to filefortest , he should"); + + $data = Array("type" => "DriveFile", "object_id" => $idtofind_detached); + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + $this->assertEquals(true, $result["data"], "User 1 doesnt have access to detached file , he should"); + + $result = $this->doPost("/ajax/core/workspaceaccess", Array( + "workspace_id" => $workspace1_id, + )); + + $this->assertEquals(true, $result["data"], "User 1 have access to workspace 1 with special function , he shouldn't"); + + $data = Array("type" => "Calendar", "object_id" => $id_calendar); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(true, $result["data"], "User 1 don't have access to calendar , he should"); + +//// ================================================================================================================================================= +//// ================================================================================================================================================= + + //FOR USER 2testSaveFiletestSaveFile + + $result = $this->doPost("/ajax/users/logout", Array()); + $this->clearClient(); + + $this->doPost("/ajax/users/login", Array( + "_username" => "usertest002", + "_password" => "usertest002" + )); + + $result = $this->doPost("/ajax/users/current/get", Array()); + $user2_id = $result["data"]["id"]; + + + //test que le user2 a acces au workspace2 + $data = Array("type" => "Workspace", "object_id" => $workspace2_id); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(true, $result["data"], "User 2 don't have acces to the workspace 2 , he should"); + + //test que le user2 n'a pas acces au workspace1 + $data = Array("type" => "Workspace", "object_id" => $workspace1_id); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(false, $result["data"], "User 2 have acces to the workspace 1 , he shouldn't"); + + + // test que le user2 a acces au channel 3 et 4 du workspace 2 + + + $data = Array("type" => "Channel", "object_id" => $channel3_ID); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(true, $result["data"], "User 2 don't have acces to the channel 3 , he should"); + + + $data = Array("type" => "Channel", "object_id" => $channel4_ID); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(true, $result["data"], "User 2 don't have acces to the channel 4 , he should"); + + + // test que le user2 n'a pas acces au channel 1 et 2 du workspace 1 + $data = Array("type" => "Channel", "object_id" => $channel1_ID); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(false, $result["data"], "User 2 have acces to the channel 1 , he shouldn't"); + + + $data = Array("type" => "Channel", "object_id" => $channel2_ID); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(false, $result["data"], "User 2 have acces to the channel 2 , he shouldn't"); + + //test que le user2 a acces au message 5 par exemple (doit aussi fonctionner avec les messages 6, 7 et 8) + $data = Array("type" => "Message", "object_id" => $message5_ID); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(true, $result["data"], "User 2 don't have acces to the message 5 , he should"); + + //test que le user 2 n'a pas acces au message 1 par exemple (doit aussi fonctionner aves les messages 1, 2 et 3) + $data = Array("type" => "Message", "object_id" => $message1_ID); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(false, $result["data"], "User 2 have acces to the message 1 , he shouldn't"); + + $data = Array("type" => "DriveFile", "object_id" => $idtofind_parent); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(false, $result["data"], "User 2 have access to filefortest , he should not"); + + + $data = Array("type" => "Calendar", "object_id" => $id_calendar); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(false, $result["data"], "User 2 have access to calendar , he should not"); + +//// ================================================================================================================================================= +//// ================================================================================================================================================= + + //FOR USER 3 + + $result = $this->doPost("/ajax/users/logout", Array()); + $this->clearClient(); + + $this->doPost("/ajax/users/login", Array( + "_username" => "usertest003", + "_password" => "usertest003" + )); + + $result = $this->doPost("/ajax/users/current/get", Array()); + $user3_id = $result["data"]["id"]; + + //test que le user1 a acces au workspace1 + $data = Array("type" => "Workspace", "object_id" => $workspace1_id); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(true, $result["data"], "User 3 don't have acces to the workspace 1 , he should"); + + //test que le user1 n'a pas acces au workspace2 + $data = Array("type" => "Workspace", "object_id" => $workspace2_id); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(false, $result["data"], "User 3 have acces to the workspace 2 , he shouldn't"); + + + //test que le user1 a acces au channel 1 et 2 du workspace 1 + + $data = Array("type" => "Channel", "object_id" => $channel1_ID); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(true, $result["data"], "User 3 don't have acces to the channel 1 , he should"); + + + $data = Array("type" => "Channel", "object_id" => $channel2_ID); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(false, $result["data"], "User 3 have acces to the channel 2 , he should not"); + + + // test que le user1 n'a pas acces au channel 2 et 3 du workspace 2 + $data = Array("type" => "Channel", "object_id" => $channel3_ID); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(false, $result["data"], "User 3 have acces to the channel 3 , he shouldn't"); + + + $data = Array("type" => "Channel", "object_id" => $channel4_ID); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(false, $result["data"], "User 3 have acces to the channel 4 , he shouldn't"); + + //test que le user1 a acces au message 1 par exemple (doit aussi fonctionner avec les messages 2, 3 et 4) + $data = Array("type" => "Message", "object_id" => $message1_ID); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(true, $result["data"], "User 3 don't have acces to the message 1 , he should"); + + $data = Array("type" => "Message", "object_id" => $message3_ID); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(false, $result["data"], "User 3 have acces to the message 3 , he shouldn't"); + + $data = Array("type" => "Message", "object_id" => $message5_ID); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(false, $result["data"], "User 3 have acces to the message 5 , he shouldn't"); + + $data = Array("type" => "DriveFile", "object_id" => $idtofind_parent); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(true, $result["data"], "User 3 don't have access to filefortest , he should"); + + $data = Array("type" => "DriveFile", "object_id" => $idtofind_detached); + + $result = $this->doPost("/ajax/core/access", Array( + "data" => $data + )); + + $this->assertEquals(true, $result["data"], "User 3 doesnt have access to detached file , he should"); + + +//// ================================================================================================================================================= +//// ================================================================================================================================================= + + // ON SUPPRIME TOUT CE QU ON A CREE ET ON VERIFIE QUE LES ENTITES SUPPRIMEES N EXISTENT PLUS + + // pour les messages + $message1 = $this->get("app.twake_doctrine")->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $message1->getId() . "")); + $this->get("app.twake_doctrine")->remove($message1); + $this->get("app.twake_doctrine")->flush(); + + $message1 = $this->get("app.twake_doctrine")->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $message1->getId() . "")); + $this->assertEquals(null, $message1); + + $message2 = $this->get("app.twake_doctrine")->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $message2->getId() . "")); + $this->get("app.twake_doctrine")->remove($message2); + $this->get("app.twake_doctrine")->flush(); + + $message2 = $this->get("app.twake_doctrine")->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $message2->getId() . "")); + $this->assertEquals(null, $message2); + + $message3 = $this->get("app.twake_doctrine")->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $message3->getId() . "")); + $this->get("app.twake_doctrine")->remove($message3); + $this->get("app.twake_doctrine")->flush(); + + $message3 = $this->get("app.twake_doctrine")->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $message3->getId() . "")); + $this->assertEquals(null, $message3); + + $message4 = $this->get("app.twake_doctrine")->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $message4->getId() . "")); + $this->get("app.twake_doctrine")->remove($message4); + $this->get("app.twake_doctrine")->flush(); + + $message4 = $this->get("app.twake_doctrine")->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $message4->getId() . "")); + $this->assertEquals(null, $message4); + + $message5 = $this->get("app.twake_doctrine")->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $message5->getId() . "")); + $this->get("app.twake_doctrine")->remove($message5); + $this->get("app.twake_doctrine")->flush(); + + $message5 = $this->get("app.twake_doctrine")->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $message5->getId() . "")); + $this->assertEquals(null, $message5); + + $message6 = $this->get("app.twake_doctrine")->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $message6->getId() . "")); + $this->get("app.twake_doctrine")->remove($message6); + $this->get("app.twake_doctrine")->flush(); + + $message6 = $this->get("app.twake_doctrine")->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $message6->getId() . "")); + $this->assertEquals(null, $message6); + + $message7 = $this->get("app.twake_doctrine")->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $message7->getId() . "")); + $this->get("app.twake_doctrine")->remove($message7); + $this->get("app.twake_doctrine")->flush(); + + $message7 = $this->get("app.twake_doctrine")->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $message7->getId() . "")); + $this->assertEquals(null, $message7); + + $message8 = $this->get("app.twake_doctrine")->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $message8->getId() . "")); + $this->get("app.twake_doctrine")->remove($message8); + $this->get("app.twake_doctrine")->flush(); + + $message8 = $this->get("app.twake_doctrine")->getRepository("Twake\Discussion:Message")->findOneBy(Array("id" => $message8->getId() . "")); + $this->assertEquals(null, $message8); + + + // pour les channels + $channel1 = $this->get("app.twake_doctrine")->getRepository("Twake\Channels:Channel")->findOneBy(Array("id" => $channel1->getId() . "")); + $this->get("app.twake_doctrine")->remove($channel1); + $this->get("app.twake_doctrine")->flush(); + + $channel1 = $this->get("app.twake_doctrine")->getRepository("Twake\Channels:Channel")->findOneBy(Array("id" => $channel1->getId() . "")); + $this->assertEquals(null, $channel1); + + $channel2 = $this->get("app.twake_doctrine")->getRepository("Twake\Channels:Channel")->findOneBy(Array("id" => $channel2->getId() . "")); + $this->get("app.twake_doctrine")->remove($channel2); + $this->get("app.twake_doctrine")->flush(); + + $channel2 = $this->get("app.twake_doctrine")->getRepository("Twake\Channels:Channel")->findOneBy(Array("id" => $channel2->getId() . "")); + $this->assertEquals(null, $channel2); + + $channel3 = $this->get("app.twake_doctrine")->getRepository("Twake\Channels:Channel")->findOneBy(Array("id" => $channel3->getId() . "")); + $this->get("app.twake_doctrine")->remove($channel3); + $this->get("app.twake_doctrine")->flush(); + + $channel3 = $this->get("app.twake_doctrine")->getRepository("Twake\Channels:Channel")->findOneBy(Array("id" => $channel3->getId() . "")); + $this->assertEquals(null, $channel3); + + $channel4 = $this->get("app.twake_doctrine")->getRepository("Twake\Channels:Channel")->findOneBy(Array("id" => $channel4->getId() . "")); + $this->get("app.twake_doctrine")->remove($channel4); + $this->get("app.twake_doctrine")->flush(); + + $channel4 = $this->get("app.twake_doctrine")->getRepository("Twake\Channels:Channel")->findOneBy(Array("id" => $channel4->getId() . "")); + $this->assertEquals(null, $channel4); + + // pour les worskspaceUser + $workspaceUser1 = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:WorkspaceUser")->findBy(Array("workspace_id" => $workspace1_id)); + foreach ($workspaceUser1 as $wp) { + $this->get("app.twake_doctrine")->remove($wp); + $this->get("app.twake_doctrine")->flush(); + } + + $workspaceUser1 = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:WorkspaceUser")->findOneBy(Array("workspace_id" => $workspace1_id)); + $this->assertEquals(null, $workspaceUser1); + + $workspaceUser2 = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:WorkspaceUser")->findOneBy(Array("workspace_id" => $workspace2_id)); + $this->get("app.twake_doctrine")->remove($workspaceUser2); + $this->get("app.twake_doctrine")->flush(); + + $workspaceUser2 = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:WorkspaceUSer")->findOneBy(Array("workspace_id" => $workspace2_id)); + $this->assertEquals(null, $workspaceUser2); + + //pour les fichiers + + $version = $this->get("app.twake_doctrine")->getRepository("Twake\Drive:DriveFileVersion")->findBy(Array("file_id" => $idtofind_parent)); + foreach ($version as $v) { + $this->get("app.twake_doctrine")->remove($v); + $this->get("app.twake_doctrine")->flush(); + } + $version = $this->get("app.twake_doctrine")->getRepository("Twake\Drive:DriveFileVersion")->findBy(Array("file_id" => $idtofind_parent)); + $this->assertEquals(Array(), $version); + + $version = $this->get("app.twake_doctrine")->getRepository("Twake\Drive:DriveFileVersion")->findBy(Array("file_id" => $idtofind_shared)); + foreach ($version as $v) { + $this->get("app.twake_doctrine")->remove($v); + $this->get("app.twake_doctrine")->flush(); + } + $version = $this->get("app.twake_doctrine")->getRepository("Twake\Drive:DriveFileVersion")->findBy(Array("file_id" => $idtofind_shared)); + $this->assertEquals(Array(), $version); + + $version = $this->get("app.twake_doctrine")->getRepository("Twake\Drive:DriveFileVersion")->findBy(Array("file_id" => $idtofind_detached)); + foreach ($version as $v) { + $this->get("app.twake_doctrine")->remove($v); + $this->get("app.twake_doctrine")->flush(); + } + $version = $this->get("app.twake_doctrine")->getRepository("Twake\Drive:DriveFileVersion")->findBy(Array("file_id" => $idtofind_detached)); + $this->assertEquals(Array(), $version); + + $file = $this->get("app.twake_doctrine")->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_parent)); + $this->get("app.twake_doctrine")->remove($file); + $this->get("app.twake_doctrine")->flush(); + + $file = $this->get("app.twake_doctrine")->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_parent)); + $this->assertEquals(null, $file); + + $file = $this->get("app.twake_doctrine")->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_detached)); + $this->get("app.twake_doctrine")->remove($file); + $this->get("app.twake_doctrine")->flush(); + + $file = $this->get("app.twake_doctrine")->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_detached)); + $this->assertEquals(null, $file); + + $file = $this->get("app.twake_doctrine")->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_shared)); + $this->get("app.twake_doctrine")->remove($file); + $this->get("app.twake_doctrine")->flush(); + + $file = $this->get("app.twake_doctrine")->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_shared)); + $this->assertEquals(null, $file); + + //pour calendar + + $calendar = $this->get("app.twake_doctrine")->getRepository("Twake\Calendar:Calendar")->findOneBy(Array("id" => $id_calendar)); + $this->get("app.twake_doctrine")->remove($calendar); + $this->get("app.twake_doctrine")->flush(); + + $calendar = $this->get("app.twake_doctrine")->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $id_calendar)); + $this->assertEquals(null, $calendar); + + // pour les users + $mail1 = $this->get("app.twake_doctrine")->getRepository("Twake\Users:Mail")->findOneBy(Array("user_id" => $user1_id)); + $this->get("app.twake_doctrine")->remove($mail1); + $this->get("app.twake_doctrine")->flush(); + + $mail2 = $this->get("app.twake_doctrine")->getRepository("Twake\Users:Mail")->findOneBy(Array("user_id" => $user2_id)); + $this->get("app.twake_doctrine")->remove($mail2); + $this->get("app.twake_doctrine")->flush(); + + $mail3 = $this->get("app.twake_doctrine")->getRepository("Twake\Users:Mail")->findOneBy(Array("user_id" => $user3_id)); + $this->get("app.twake_doctrine")->remove($mail3); + $this->get("app.twake_doctrine")->flush(); + + $mail1 = $this->get("app.twake_doctrine")->getRepository("Twake\Users:Mail")->findOneBy(Array("user_id" => $user1_id)); + $this->assertEquals(null, $mail1); + + $mail2 = $this->get("app.twake_doctrine")->getRepository("Twake\Users:Mail")->findOneBy(Array("user_id" => $user2_id)); + $this->assertEquals(null, $mail2); + + $mail3 = $this->get("app.twake_doctrine")->getRepository("Twake\Users:Mail")->findOneBy(Array("user_id" => $user3_id)); + $this->assertEquals(null, $mail3); + + $user1 = $this->get("app.twake_doctrine")->getRepository("Twake\Users:User")->findOneBy(Array("id" => $user1_id)); + $this->get("app.twake_doctrine")->remove($user1); + $this->get("app.twake_doctrine")->flush(); + + $user1 = $this->get("app.twake_doctrine")->getRepository("Twake\Users:User")->findOneBy(Array("id" => $user1_id)); + $this->assertEquals(null, $user1); + + $user2 = $this->get("app.twake_doctrine")->getRepository("Twake\Users:User")->findOneBy(Array("id" => $user2_id)); + $this->get("app.twake_doctrine")->remove($user2); + $this->get("app.twake_doctrine")->flush(); + + $user2 = $this->get("app.twake_doctrine")->getRepository("Twake\Users:User")->findOneBy(Array("id" => $user2_id)); + $this->assertEquals(null, $user2); + + $user3 = $this->get("app.twake_doctrine")->getRepository("Twake\Users:User")->findOneBy(Array("id" => $user3_id)); + $this->get("app.twake_doctrine")->remove($user3); + $this->get("app.twake_doctrine")->flush(); + + $user3 = $this->get("app.twake_doctrine")->getRepository("Twake\Users:User")->findOneBy(Array("id" => $user3_id)); + $this->assertEquals(null, $user3); + + // pour les worskspaces + $workspace1 = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:Workspace")->findOneBy(Array("id" => $workspace1->getId() . "")); + $this->get("app.twake_doctrine")->remove($workspace1); + + $workspace2 = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:Workspace")->findOneBy(Array("id" => $workspace2->getId() . "")); + $this->get("app.twake_doctrine")->remove($workspace2); + + // pour le groupe + $group = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:Group")->findOneBy(Array("id" => $group->getId() . "")); + $this->get("app.twake_doctrine")->remove($group); + $this->get("app.twake_doctrine")->flush(); + + $group = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:Group")->findOneBy(Array("id" => $group->getId() . "")); + $this->assertEquals(null, $group); + + $workspace1 = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:Workspace")->findOneBy(Array("id" => $workspace1->getId() . "")); + $this->assertEquals(null, $workspace1); + + $workspace2 = $this->get("app.twake_doctrine")->getRepository("Twake\Workspaces:Workspace")->findOneBy(Array("id" => $workspace2->getId() . "")); + $this->assertEquals(null, $workspace2); + + } +} \ No newline at end of file diff --git a/twake/backend/core/tests/DriveBundle/DriveCollectionTest.php b/twake/backend/core/tests/DriveBundle/DriveCollectionTest.php new file mode 100755 index 00000000..983f14a3 --- /dev/null +++ b/twake/backend/core/tests/DriveBundle/DriveCollectionTest.php @@ -0,0 +1,506 @@ +<?php + +namespace Tests\DriveBundle; + +require_once __DIR__ . "/../WebTestCaseExtended.php"; + +use Tests\WebTestCaseExtended; +use Twake\Workspaces\Entity\Workspace; +use Twake\Workspaces\Entity\Group; +use Twake\Workspaces\Entity\WorkspaceUser; +use Twake\Workspaces\Entity\GroupUser; + +class DriveCollectionTest extends WebTestCaseExtended +{ + public function testSaveFile() + { + + // ON CREE UN GROUP POUR CREER NOTRE WORKSPACE + $group = new Group("group_for_test"); + $this->getDoctrine()->persist($group); + + // ON CREE UN WORKSPACE POUR FAIRE NOS TESTS SUR LES FICHIERS + $workspace = new Workspace("workspace_for_test"); + $workspace->setGroup($group); + $this->getDoctrine()->persist($workspace); + $this->getDoctrine()->persist($group); + $this->getDoctrine()->flush(); + $workspace_id = $workspace->getId() . ""; + + // ON RECUPERE LA RACINE DE CE NOUVEAU WORKSPACE + $root = $this->get("app.drive")->getRootEntity($workspace_id); + $root_id = $root->getId() . ""; + //error_log(print_r("root id: " . $root_id,true)); + + + //ON RECUPERE LA CORBEILLE DE CE NOUVEAU WORKSPACE + $trash = $this->get("app.drive")->getTrashEntity($workspace_id); + $trash_id = $trash->getId() . ""; + //error_log(print_r("trash id: " .$trash_id,true)); + + //ON CREEE UN USER POUR FAIRE NOS TEST ET ON LE CONNECTE + + $this->removeUserByName("usertest001"); + $user1 = $this->newUserByName("usertest001"); + + $this->login($user1->getUsernameCanonical()); + $result = $this->doPost("/ajax/users/current/get", Array()); + $user1_id = $result["data"]["id"]; + $current_date = new \DateTime(); + $current_date = $current_date->getTimestamp(); + + $workspaceUser1 = new WorkspaceUser($workspace, $user1, null); + $groupUser1 = new GroupUser($group, $user1); + $this->getDoctrine()->persist($workspaceUser1); + $this->getDoctrine()->persist($workspace); + $this->getDoctrine()->persist($user1); + $this->getDoctrine()->persist($groupUser1); + $this->getDoctrine()->persist($group); + $this->getDoctrine()->flush(); + + +// ================================================================================================================================================= +// ================================================================================================================================================= + + //ON CREE UN FICHIER QUI VA SE TROUVER A LA RACINE DU WORKSPACE EN SPECIFIANT UN PARENT + + $object = Array("parent_id" => $root_id, "trash" => false, "workspace_id" => $workspace_id, "front_id" => "14005200-48b1-11e9-a0b4-0242ac120005", "name" => "filefortest", "is_directory" => false); + $data = Array("upload_mode" => "chunk", "identifier" => "identifier", "nb_chunk" => 1); + $options = Array(); + $result = $this->doPost("/ajax/drive/save", Array( + "object" => $object, + "options" => $options, + )); + $idtofind_parent = $result["data"]["object"]["id"]; + + $this->assertEquals($workspace_id, $result["data"]["object"]["workspace_id"], "Wrong workspace id for file create with a parent " . json_encode($result)); + $this->assertEquals($root_id, $result["data"]["object"]["parent_id"], "Wrong parent id for file create with a parent"); + $this->assertEquals("14005200-48b1-11e9-a0b4-0242ac120005", $result["data"]["object"]["front_id"], "Wrong front id for file create with a parent"); + $this->assertEquals("filefortest", $result["data"]["object"]["name"], "Wrong name for file create with a parent"); + $this->assertEquals(false, $result["data"]["object"]["trash"], "Wrong is in trash attribut for file create with a parent"); + $this->assertEquals($user1_id, $result["data"]["object"]["last_user"], "Wrong last user for file create with a parent"); + + $added_parent = $result["data"]["object"]["added"]; + $modified_parent = $result["data"]["object"]["modified"]; + $this->assertLessThan(60, $modified_parent - $current_date, "Problem with date modified of filed create with a parent"); + $this->assertLessThan(60, $added_parent - $current_date, "Problem with date added of filed create with a parent"); + $this->assertEquals($modified_parent, $added_parent, "Added date and modified date should be the same"); + + + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_parent)); + $this->assertEquals($workspace_id, $fileordirectory->getWorkspaceId() . "", "Wrong workspace id for file create with a parent in database"); + $this->assertEquals($root_id, $fileordirectory->getParentId() . "", "Wrong parent id for file create with a parent in database"); + $this->assertEquals("14005200-48b1-11e9-a0b4-0242ac120005", $fileordirectory->getFrontId() . "", "Wrong front id for file create with a parent in database"); + $this->assertEquals("filefortest", $fileordirectory->getName(), "Wrong name for file create with a parent in database"); + $this->assertEquals(false, $fileordirectory->getIsInTrash(), "Wrong is in trash attribut for file create with a parent in database"); + + +// ================================================================================================================================================= +// ================================================================================================================================================= + + // ON CREE UN FICHIER QUI VA SE TROUVER A LA RACINE DU WORKSPACE SANS SPECIFIER UN PARENT + + $object = Array("parent_id" => $root_id, "trash" => false, "workspace_id" => $workspace_id, "front_id" => "14005200-48b1-11e9-a0b4-0242ac120005", "name" => "filefortest-randomothername", "is_directory" => false); + $options = Array(); + $result = $this->doPost("/ajax/drive/save", Array( + "object" => $object, + "options" => $options + )); + $idtofind_root = $result["data"]["object"]["id"]; + + $this->assertEquals($workspace_id, $result["data"]["object"]["workspace_id"], "Wrong workspace id for file create without a parent"); + $this->assertEquals($root_id, $result["data"]["object"]["parent_id"], "Wrong parent id for file create without a parent"); + $this->assertEquals("14005200-48b1-11e9-a0b4-0242ac120005", $result["data"]["object"]["front_id"], "Wrong front id for file create without a parent"); + $this->assertEquals("filefortest-randomothername", $result["data"]["object"]["name"], "Wrong name for file create without a parent"); + $this->assertEquals(false, $result["data"]["object"]["trash"], "Wrong is in trash attribut for file create without a parent"); + $this->assertEquals($user1_id, $result["data"]["object"]["last_user"], "Wrong last user for file create without a parent"); + + $added = $result["data"]["object"]["added"]; + $modified = $result["data"]["object"]["modified"]; + $this->assertLessThan(60, $modified - $current_date, "Problem with date modified of filed create with a parent"); + $this->assertLessThan(60, $added - $current_date, "Problem with date added of filed create with a parent"); + $this->assertEquals($modified, $added, "Added date and modified date should be the same"); + + + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_root)); + $this->assertEquals($workspace_id, $fileordirectory->getWorkspaceId() . "", "Wrong workspace id for file create without a parent in database"); + $this->assertEquals($root_id, $fileordirectory->getParentId() . "", "Wrong parent id for file create without a parent in database"); + $this->assertEquals("14005200-48b1-11e9-a0b4-0242ac120005", $fileordirectory->getFrontId() . "", "Wrong front id for file create without a parent in database"); + $this->assertEquals(false, $fileordirectory->getIsInTrash(), "Wrong is in trash attribut for file create with a parent in database"); + + +// ================================================================================================================================================= +// ================================================================================================================================================= + // ON CREE UN FICHIER DETACHED + + $object = Array("workspace_id" => $workspace_id, "trash" => false, "front_id" => "14005200-48b1-11e9-a0b4-0242ac120005", "name" => "filefortest-randomothername2", "detached" => true, "is_directory" => false); + $options = Array("new" => true, "data" => $data, "version" => true); + $result = $this->doPost("/ajax/drive/save", Array( + "object" => $object, + "options" => $options + + )); + $idtofind_detached = $result["data"]["object"]["id"]; + + $this->assertEquals($workspace_id, $result["data"]["object"]["workspace_id"], "Wrong workspace id for file create detached"); + $this->assertEquals("detached", $result["data"]["object"]["parent_id"], "Wrong parent id for file create detached"); + $this->assertEquals("14005200-48b1-11e9-a0b4-0242ac120005", $result["data"]["object"]["front_id"], "Wrong front id for file create detached"); + $this->assertEquals(true, $result["data"]["object"]["detached"], "Wrong detached bool for file create without a parent detached"); + $this->assertEquals("filefortest-randomothername2", $result["data"]["object"]["name"], "Wrong name for file create detached"); + $this->assertEquals(false, $result["data"]["object"]["trash"], "Wrong is in trash attribut for file create detached"); + $this->assertEquals($user1_id, $result["data"]["object"]["last_user"], "Wrong last user for file create detached"); + + /*$fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $root_id)); + $this->assertEquals(200000, $fileordirectory->getAsArray()["size"], "Wrong size for the file root"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $trash_id)); + $this->assertEquals(0, $fileordirectory->getAsArray()["size"], "Wrong size for the file in trash"); +*/ + + $added = $result["data"]["object"]["added"]; + $modified = $result["data"]["object"]["modified"]; + $this->assertLessThan(60, $modified - $current_date, "Problem with date modified of filed create with a parent"); + $this->assertLessThan(60, $added - $current_date, "Problem with date added of filed create with a parent"); + $this->assertEquals($modified, $added, "Added date and modified date should be the same"); + + + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_detached)); + $this->assertEquals($workspace_id, $fileordirectory->getWorkspaceId() . "", "Wrong workspace id for file create without a parent in database"); + $this->assertEquals("detached", $fileordirectory->getParentId() . "", "Wrong parent id for file create without a parent in database"); + $this->assertEquals("14005200-48b1-11e9-a0b4-0242ac120005", $fileordirectory->getFrontId() . "", "Wrong front id for file create without a parent in database"); + $this->assertEquals(true, $fileordirectory->getDetachedFile(), "Wrong detached bool for file create without a parent detached in database"); + $this->assertEquals(false, $fileordirectory->getIsInTrash(), "Wrong is in trash attribut for file create with a parent in database"); + +// ================================================================================================================================================= +// ================================================================================================================================================= + + //ON VA ATTACHER LE FICHIER DETACHED CREE PRECEDEMENT A LA RACINE + + $object = Array("id" => $idtofind_detached, "parent_id" => $root_id); + $options = Array(); + $result = $this->doPost("/ajax/drive/save", Array( + "object" => $object, + "options" => $options + )); + + $this->assertEquals($workspace_id, $result["data"]["object"]["workspace_id"], "Wrong workspace id for file reatached"); + $this->assertEquals($root_id, $result["data"]["object"]["parent_id"], "Wrong parent id for file reatached"); + $this->assertEquals("14005200-48b1-11e9-a0b4-0242ac120005", $result["data"]["object"]["front_id"], "Wrong front id for file reatached"); + $this->assertEquals(false, $result["data"]["object"]["detached"], "Wrong detached bool for file reatached"); + $this->assertEquals(false, $result["data"]["object"]["trash"], "Wrong is in trash attribut for file create with a parent"); + + //error_log(print_r(json_decode($result->getContent(),true),true)); + /*$this->assertEquals(100000,$result["data"]["object"]["size"], "Wrong size for file create without a parent"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $root_id)); + $this->assertEquals(300000, $fileordirectory->getAsArray()["size"], "Wrong size for the file root"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $trash_id)); + $this->assertEquals(0, $fileordirectory->getAsArray()["size"], "Wrong size for the file in trash");*/ + + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_detached)); + $this->assertEquals($workspace_id, $fileordirectory->getWorkspaceId() . "", "Wrong workspace id for file reatached"); + $this->assertEquals($root_id, $fileordirectory->getParentId() . "", "Wrong parent id for file reatached"); + $this->assertEquals("14005200-48b1-11e9-a0b4-0242ac120005", $fileordirectory->getFrontId() . "", "Wrong front id for file reatached"); + $this->assertEquals(false, $fileordirectory->getDetachedFile(), "Wrong detached bool for file reatached"); + $this->assertEquals(false, $fileordirectory->getIsInTrash(), "Wrong is in trash attribut for file create with a parent in database"); + +// ================================================================================================================================================= +// ================================================================================================================================================= + //ON VA METTRE LE FICHIER PARENT A LA CORBEILLE ET REGARDER SI LES TAILLES SONT CORRECTES + + $object = Array("id" => $idtofind_parent, "trash" => true); + $options = Array(); + $result = $this->doPost("/ajax/drive/save", Array( + "object" => $object, + "options" => $options + )); + + //error_log(print_r($result->getContent(),true)); + $this->assertEquals(true, $result["data"]["object"]["trash"], "File should be in trash he is not"); + + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_parent)); + $this->assertEquals($trash_id, $fileordirectory->getParentId(), "File has nottrash as parent"); + $this->assertEquals($root_id, $fileordirectory->getOldParent(), "File has nottrash as parent"); + + /*$this->assertEquals(100000,$result["data"]["object"]["size"], "Wrong size for the file"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_parent)); + $this->assertEquals(100000, $fileordirectory->getAsArray()["size"], "Wrong size for the file in database"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $root_id)); + $this->assertEquals(200000, $fileordirectory->getAsArray()["size"], "Wrong size for the file root"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $trash_id)); + $this->assertEquals(100000, $fileordirectory->getAsArray()["size"], "Wrong size for the file in trash");*/ + + +// ================================================================================================================================================= +// ================================================================================================================================================= + //ON VA RESTAURER LE FICHIER DEPLACE SUR SON PARENT ET REGARDER SI LES TAILLES SONT CORRECTES + + $object = Array("id" => $idtofind_parent, "trash" => false); + $options = Array(); + $result = $this->doPost("/ajax/drive/save", Array( + "object" => $object, + "options" => $options + )); + + $this->assertEquals(false, $result["data"]["object"]["trash"], "File should not be in trash he is "); + + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_parent)); + $this->assertEquals($root_id, $fileordirectory->getParentId(), "File has notroot as parent"); + $this->assertEquals("", $fileordirectory->getOldParent(), "File got old parent he should not"); + + /*$this->assertEquals(100000,$result["data"]["object"]["size"], "Wrong size for the file"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_parent)); + $this->assertEquals(100000, $fileordirectory->getAsArray()["size"], "Wrong size for the file in database"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $root_id)); + $this->assertEquals(300000, $fileordirectory->getAsArray()["size"], "Wrong size for the file root"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $trash_id)); + $this->assertEquals(0, $fileordirectory->getAsArray()["size"], "Wrong size for the file trash");*/ + + +// ================================================================================================================================================= +// ================================================================================================================================================= + // ON CREE UN DOSSIER A LA RACINE + + $object = Array("workspace_id" => $workspace_id, "front_id" => "14005200-48b1-11e9-a0b4-0242ac120005", "name" => "folderfortest", "is_directory" => true); + $options = Array("new" => true, "data" => $data, "version" => true); + $result = $this->doPost("/ajax/drive/save", Array( + "object" => $object, + "options" => $options, + )); + $idtofind_folder = $result["data"]["object"]["id"]; + + $this->assertEquals($workspace_id, $result["data"]["object"]["workspace_id"], "Wrong workspace id for the folder "); + $this->assertEquals($root_id, $result["data"]["object"]["parent_id"], "Wrong parent id for the folder"); + $this->assertEquals("14005200-48b1-11e9-a0b4-0242ac120005", $result["data"]["object"]["front_id"], "Wrong front id for the folder"); + $this->assertEquals("folderfortest", $result["data"]["object"]["name"], "Wrong name for the folder"); + $this->assertEquals(false, $result["data"]["object"]["trash"], "Wrong is in trash attribut for the folder"); + $this->assertEquals($user1_id, $result["data"]["object"]["last_user"], "Wrong last user for the folder"); + $this->assertEquals(0, $result["data"]["object"]["size"], "Wrong size for the folder"); + + /*$this->assertEquals(0,$result["data"]["object"]["size"], "Wrong size for the folder"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_parent)); + $this->assertEquals(100000, $fileordirectory->getAsArray()["size"], "Wrong size for the file in database"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $root_id)); + $this->assertEquals(300000, $fileordirectory->getAsArray()["size"], "Wrong size for the file root"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $trash_id)); + $this->assertEquals(0, $fileordirectory->getAsArray()["size"], "Wrong size for the file trash");*/ + +// ================================================================================================================================================= +// ================================================================================================================================================= + + //ON VA ATTACHER LE FICHIER DETACHED CREE PRECEDEMENT AU DOSSIER QU ON VIENT DE CREER + + $object = Array("id" => $idtofind_detached, "parent_id" => $idtofind_folder); + $options = Array(); + $result = $this->doPost("/ajax/drive/save", Array( + "object" => $object, + "options" => $options + )); + + $this->assertEquals($workspace_id, $result["data"]["object"]["workspace_id"], "Wrong workspace id for file reatached"); + $this->assertEquals($idtofind_folder, $result["data"]["object"]["parent_id"], "Wrong parent id for file reatached"); + $this->assertEquals("14005200-48b1-11e9-a0b4-0242ac120005", $result["data"]["object"]["front_id"], "Wrong front id for file reatached"); + $this->assertEquals(false, $result["data"]["object"]["detached"], "Wrong detached bool for file reatached"); + $this->assertEquals(false, $result["data"]["object"]["trash"], "Wrong is in trash attribut for file create with a parent"); + + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_detached)); + $this->assertEquals($idtofind_folder, $fileordirectory->getParentId() . "", "Wrong parent for the file which should be in folder"); + + //error_log(print_r($result,true)); + /*$this->assertEquals(100000,$result["data"]["object"]["size"], "Wrong size for file detached"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $root_id)); + $this->assertEquals(300000, $fileordirectory->getAsArray()["size"], "Wrong size for the file root"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $trash_id)); + $this->assertEquals(0, $fileordirectory->getAsArray()["size"], "Wrong size for the file in trash"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_folder)); + $this->assertEquals(100000, $fileordirectory->getAsArray()["size"], "Wrong size for the folder");*/ + +// ================================================================================================================================================= +// ================================================================================================================================================= + + //ON MET LE DOSSIER CREE A LA CORBEILLE ET DONC LE FICHIER DETACHED EN MEME TEMPS + + $object = Array("id" => $idtofind_folder, "trash" => true); + $options = Array(); + $result = $this->doPost("/ajax/drive/save", Array( + "object" => $object, + "options" => $options + )); + + $this->assertEquals(true, $result["data"]["object"]["trash"], "Folder should be in trash he is not"); + + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_folder)); + $this->assertEquals($trash_id, $fileordirectory->getParentId(), "Folder as not trash as parent"); + $this->assertEquals($root_id, $fileordirectory->getOldParent(), "Folder as not trash as parent"); + $this->assertEquals(true, $fileordirectory->getIsInTrash(), "Folder as not trash as parent"); + + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_detached)); + $this->assertEquals($idtofind_folder, $fileordirectory->getParentId(), "Folder as not trash as parent"); + $this->assertEquals("", $fileordirectory->getOldParent(), "Folder as not trash as parent"); + $this->assertEquals(true, $fileordirectory->getIsInTrash(), "Folder as not trash as parent"); + + /*$this->assertEquals(100000,$result["data"]["object"]["size"], "Wrong size for the folder"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_detached)); + $this->assertEquals(100000, $fileordirectory->getAsArray()["size"], "Wrong size for the file in database"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $root_id)); + $this->assertEquals(200000, $fileordirectory->getAsArray()["size"], "Wrong size for the file root"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $trash_id)); + $this->assertEquals(100000, $fileordirectory->getAsArray()["size"], "Wrong size for the file in trash");*/ + +// ================================================================================================================================================= +// ================================================================================================================================================= + + //ON VA RESTAURER LE FICHIER DETACHED QUI SE TROUVE DANS LE DOSSIER LUI MEME A LA CORBEILLE ET VOIR SI IL SE RESTAURE A LA RACINE + + $object = Array("id" => $idtofind_detached, "trash" => false); + $options = Array(); + $result = $this->doPost("/ajax/drive/save", Array( + "object" => $object, + "options" => $options + )); + + $fileson = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findBy(Array("workspace_id" => $workspace_id, "parent_id" => $idtofind_detached)); + + $this->assertEquals(false, $result["data"]["object"]["trash"], "Detached file should not be in trash he is "); + + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_detached)); + $this->assertEquals($root_id, $fileordirectory->getParentId(), "Detached file as not trash as parent"); + $this->assertEquals("", $fileordirectory->getOldParent(), "Detached file as not trash as parent"); + $this->assertEquals(false, $fileordirectory->getIsInTrash(), "Detached file as not trash as parent"); + + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_folder)); + $this->assertEquals($trash_id, $fileordirectory->getParentId(), "Folder as not trash as parent"); + $this->assertEquals($root_id, $fileordirectory->getOldParent(), "Folder as not trash as parent"); + $this->assertEquals(true, $fileordirectory->getIsInTrash(), "Folder as not trash as parent"); + + /*$this->assertEquals(100000,$result["data"]["object"]["size"], "Wrong size for the file"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_detached)); + $this->assertEquals(100000, $fileordirectory->getAsArray()["size"], "Wrong size for the file in database"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $root_id)); + $this->assertEquals(300000, $fileordirectory->getAsArray()["size"], "Wrong size for the file root"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $trash_id)); + $this->assertEquals(0, $fileordirectory->getAsArray()["size"], "Wrong size for the file in trash"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_folder)); + $this->assertEquals(0, $fileordirectory->getAsArray()["size"], "Wrong size for the file in trash");*/ + +// ================================================================================================================================================= +// ================================================================================================================================================= + + //ON SUPPRIME LE FICHIER DETACHED + + $object = Array("id" => $idtofind_detached); + $options = Array(); + $result = $this->doPost("/ajax/drive/remove", Array( + "object" => $object, + "options" => $options + )); + + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_detached)); + $this->assertEquals(null, $fileordirectory, "The deleted file still exist"); + + /*$fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $root_id)); + $this->assertEquals(200000, $fileordirectory->getAsArray()["size"], "Wrong size for the file root"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $trash_id)); + $this->assertEquals(0, $fileordirectory->getAsArray()["size"], "Wrong size for the file trash");*/ + +// ================================================================================================================================================= +// ================================================================================================================================================= + + // ON DEPLACE LE FICHIER PARENT EN LE RATACHANT A UN FICHIER DE LA CORBEILLE + + $object = Array("id" => $idtofind_parent, "parent_id" => $idtofind_folder); + $options = Array(); + $result = $this->doPost("/ajax/drive/save", Array( + "object" => $object, + "options" => $options + )); + + + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_parent)); + $this->assertEquals($idtofind_folder, $fileordirectory->getParentId(), "File has nottrash as parent"); + $this->assertEquals($root_id, $fileordirectory->getOldParent(), "File has notroot as old parent"); + $this->assertEquals(true, $fileordirectory->getIsInTrash(), "File is not in trash"); + + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_folder)); + $this->assertEquals($trash_id, $fileordirectory->getParentId(), "Folder is not trash as parent"); + $this->assertEquals(true, $fileordirectory->getIsInTrash(), "Folder is not in trash"); + + $this->assertEquals(true, $result["data"]["object"]["trash"], "Folder should be in trash he is not"); + + /*$fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_folder)); + $this->assertEquals(100000, $fileordirectory->getAsArray()["size"], "Wrong size for the file in trash"); + $this->assertEquals(100000,$result["data"]["object"]["size"], "Wrong size for the folder"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_parent)); + $this->assertEquals(100000, $fileordirectory->getAsArray()["size"], "Wrong size for the file in database"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $root_id)); + $this->assertEquals(100000, $fileordirectory->getAsArray()["size"], "Wrong size for the file root"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $trash_id)); + $this->assertEquals(100000, $fileordirectory->getAsArray()["size"], "Wrong size for the file in trash");*/ + + //ET ON LE SUPPRIME + + $object = Array("id" => $idtofind_parent); + $options = Array(); + $result = $this->doPost("/ajax/drive/remove", Array( + "object" => $object, + "options" => $options + )); + + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $idtofind_parent)); + $this->assertEquals(null, $fileordirectory, "The deleted file still exist"); + + /*$fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $trash_id)); + $this->assertEquals(0, $fileordirectory->getAsArray()["size"], "Wrong size for the file trash"); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("id" => $root_id)); + $this->assertEquals(100000, $fileordirectory->getAsArray()["size"], "Wrong size for the file root");*/ + +// ================================================================================================================================================= +// ================================================================================================================================================= + + // ON SUPPRIME TOUS LES FICHIERS DU WORKSPACE, LE WORKSPACE EN LUI MEME AINSI QUE LE GROUPE + + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findBy(Array("workspace_id" => $workspace_id)); + foreach ($fileordirectory as $item) { + $this->getDoctrine()->remove($item); + } + $workspace = $this->getDoctrine()->getRepository("Twake\Workspaces:Workspace")->findOneBy(Array("id" => $workspace_id)); + $this->getDoctrine()->remove($workspace); + $group = $this->getDoctrine()->getRepository("Twake\Workspaces:Group")->findOneBy(Array("id" => $group->getId() . "")); + $this->getDoctrine()->remove($group); + $this->getDoctrine()->flush(); + + + $group = $this->getDoctrine()->getRepository("Twake\Workspaces:Group")->findOneBy(Array("id" => $group->getId() . "")); + $this->assertEquals(null, $group); + $workspace = $this->getDoctrine()->getRepository("Twake\Workspaces:Workspace")->findOneBy(Array("id" => $workspace_id)); + $this->assertEquals(null, $workspace); + $fileordirectory = $this->getDoctrine()->getRepository("Twake\Drive:DriveFile")->findOneBy(Array("workspace_id" => $workspace_id)); + $this->assertEquals(null, $fileordirectory); + + + //ON SUPPRIME TOUTE LES VERSIONS QUI ONT ETE CREE + $version = $this->getDoctrine()->getRepository("Twake\Drive:DriveFileVersion")->findBy(Array("file_id" => $idtofind_parent)); + foreach ($version as $v) { + $this->getDoctrine()->remove($v); + $this->getDoctrine()->flush(); + } + $version = $this->getDoctrine()->getRepository("Twake\Drive:DriveFileVersion")->findBy(Array("file_id" => $idtofind_parent)); + $this->assertEquals(Array(), $version); + + + $version = $this->getDoctrine()->getRepository("Twake\Drive:DriveFileVersion")->findBy(Array("file_id" => $idtofind_root)); + foreach ($version as $v) { + $this->getDoctrine()->remove($v); + $this->getDoctrine()->flush(); + } + $version = $this->getDoctrine()->getRepository("Twake\Drive:DriveFileVersion")->findBy(Array("file_id" => $idtofind_root)); + $this->assertEquals(Array(), $version); + + $version = $this->getDoctrine()->getRepository("Twake\Drive:DriveFileVersion")->findBy(Array("file_id" => $idtofind_detached)); + foreach ($version as $v) { + $this->getDoctrine()->remove($v); + $this->getDoctrine()->flush(); + } + $version = $this->getDoctrine()->getRepository("Twake\Drive:DriveFileVersion")->findBy(Array("file_id" => $idtofind_detached)); + $this->assertEquals(Array(), $version); + + } +} \ No newline at end of file diff --git a/twake/backend/core/tests/UsersBundle/Error200Test.php b/twake/backend/core/tests/UsersBundle/Error200Test.php new file mode 100755 index 00000000..be45346b --- /dev/null +++ b/twake/backend/core/tests/UsersBundle/Error200Test.php @@ -0,0 +1,53 @@ +<?php + +namespace Tests\UsersBundle; + +require_once __DIR__ . "/../WebTestCaseExtended.php"; + +use Tests\WebTestCaseExtended; + +class Error200Test extends WebTestCaseExtended + +{ + public function testErrorRemoveSecondaryMail() + { + + $this->removeUserByName("usertest001"); + $user = $this->newUserByName("usertest001"); + + + $result = $this->login($user->getUsernameCanonical()); + + $result = $this->doPost("/ajax/users/account/removemail", Array( + "mail" => "14005200-48b1-11e9-a0b4-0242ac120005" + )); + + $this->assertEquals(Array("badmail"), $result["errors"]); + } + + + public function testCheckNumberForAddNewMail() + { + + $this->removeUserByName("usertest001"); + $user = $this->newUserByName("usertest001", "usertest001@twake_phpunit.fr"); + $this->login($user->getUsernameCanonical()); + + $result = $this->doPost("/ajax/users/account/addmail", Array( + "mail" => "usertest0021@twake_phpunit.fr" + )); + + $token = $result["data"]["token"]; + + $verif = $this->get("app.twake_doctrine")->getRepository("Twake\Users:VerificationNumberMail")->findOneBy(Array("token" => $token)); + $code = $verif->getCleanCode(); + + $result = $this->doPost("/ajax/users/account/addmailverify", Array( + "token" => $token, + "code" => $code + )); + $this->assertEquals(Array(), $result["errors"]); + + } + +} \ No newline at end of file diff --git a/twake/backend/core/tests/UsersBundle/ExterneUserTest.php b/twake/backend/core/tests/UsersBundle/ExterneUserTest.php new file mode 100755 index 00000000..4e6d597b --- /dev/null +++ b/twake/backend/core/tests/UsersBundle/ExterneUserTest.php @@ -0,0 +1,238 @@ +<?php + +namespace Tests\AccessBundle; + +require_once __DIR__ . "/../WebTestCaseExtended.php"; + +use Tests\WebTestCaseExtended; +use Twake\Channels\Entity\Channel; +use Twake\Channels\Entity\ChannelMember; +use Twake\Users\Entity\User; +use Twake\Workspaces\Entity\WorkspaceUser; +use Twake\Workspaces\Entity\Workspace; +use Twake\Workspaces\Entity\Group; +use Twake\Workspaces\Entity\WorkspaceLevel; + +class ExterneUserTest extends WebTestCaseExtended +{ + public function testWexterne() + { + list($g1, $w1, $c1, $u1) = $this->getStuff(); + $u2 = $this->newUserByName("usertest002"); + $this->login($u1->getUsernameCanonical()); + $result = $this->doPost("/ajax/workspace/members/addlist", Array("list" => $u2->getUsernameCanonical() . "|1", "workspaceId" => $w1->getId())); + $this->assertEquals(Array($u2->getUsernameCanonical()), $result["data"]["added"]["user"], "User2 not invited"); + // on se connecte Γ  u2 pour voir ce qu'il en est + $this->assertEquals(true, $this->verifyIfUserIsInChannel($u2, $w1, $c1, true), "u2 is not invited as wexterne"); + } + + public function testChainvite() + { + list($g1, $w1, $c1, $u1) = $this->getStuff(); + $u3 = $this->newUserByName("usertest003"); + $this->login($u1->getUsernameCanonical()); + $result = $this->updateChainviteFromFront($w1, $c1, $u1, [$u3->getId()], []); + $this->assertEquals(true, $this->verifyIfUserIsInChannel($u3, $w1, $c1, true), "u3 is not invited as chanvitΓ©"); + $this->updateChainviteFromFront($w1, $c1, $u1, [], [$u3->getId()]); + $this->assertEquals(false, $this->verifyIfUserIsInChannel($u3, $w1, $c1, true), "u3 is still invited as chanvitΓ©"); + } + + public function testChainviteMail() + { + list($g1, $w1, $c1, $u1) = $this->getStuff(); + $mail1 = "mail1@benoit.best"; + $mailEntity = $this->getDoctrine()->getRepository("Twake\Users:Mail")->findOneBy(Array("mail" => $mail1)); + if ($mailEntity) { + if ($mailEntity->getUserId()) { + $groupUsers = $this->getDoctrine()->getRepository("Twake\Workspaces:GroupUser")->findBy(Array("user" => $mailEntity->getUserId())); + foreach ($groupUsers as $groupUser) { + $this->getDoctrine()->remove($groupUser); + } + $user = $this->getDoctrine()->getRepository("Twake\Users:User")->find($mailEntity->getUserId()); + $this->getDoctrine()->remove($user); + } + $this->getDoctrine()->remove($mailEntity); + } + $this->getDoctrine()->flush(); + $this->updateChainviteFromFront($w1, $c1, $u1, [$mail1], []); + $u4 = $this->newUserByName("usertest004", $mail1); + $this->assertEquals(true, $this->verifyIfUserIsInChannel($u4, $w1, $c1, true), "u4 is not invited as chanvitΓ©"); + // on vΓ©rifi que $mail1 n'est plus dans la liste + $this->assertEquals(false, $this->verifyIfUserIsInChannel($u4, $w1, $c1, true, $mail1), "mail1 is still invited as chanvitΓ©"); + } + + public function testRemoveAutoAddFromChannel() + { + list($g1, $w1, $c1, $u1) = $this->getStuff(); + $u2 = $this->newUserByName("usertest002"); + $this->login($u1->getUsernameCanonical()); + $result = $this->doPost("/ajax/workspace/members/addlist", Array("list" => $u2->getUsernameCanonical() . "|1", "workspaceId" => $w1->getId())); + $this->updateChainviteFromFront($w1, $c1, $u1, [], [$u2->getId()]); + $this->assertEquals(true, $this->verifyIfUserIsInChannel($u2, $w1, $c1, true), "User can be remove from channel as wexterne"); + } + + public function testRemoveAutoAddFromPrivateChannel() + { + list($g1, $w1, $c1, $u1) = $this->getStuff(); + $c1->setPrivate(true); + $this->getDoctrine()->persist($c1); + $this->getDoctrine()->flush(); + $u2 = $this->newUserByName("usertest002"); + $this->login($u1->getUsernameCanonical()); + $result = $this->doPost("/ajax/workspace/members/addlist", Array("list" => $u2->getUsernameCanonical() . "|1", "workspaceId" => $w1->getId())); + $this->assertEquals(false, $this->verifyIfUserIsInChannel($u2, $w1, $c1, true), "Wexterne is auto add in private channel"); + $this->updateChainviteFromFront($w1, $c1, $u1, [$u2->getId()], []); + $this->assertEquals(true, $this->verifyIfUserIsInChannel($u2, $w1, $c1, true), "Wexterne can't be add in private channel"); + $this->updateChainviteFromFront($w1, $c1, $u1, [], [$u2->getId()]); + $this->assertEquals(false, $this->verifyIfUserIsInChannel($u2, $w1, $c1, true), "Wexterne can't be remove from private channel"); + } + + public function testRemoveUserWexterne() + { + list($g1, $w1, $c1, $u1) = $this->getStuff(); + $this->login($u1->getUsernameCanonical()); + + $u2 = $this->newUserByName("usertest002"); + $result = $this->doPost("/ajax/workspace/members/addlist", Array("list" => $u2->getUsernameCanonical() . "|1", "workspaceId" => $w1->getId())); + + $this->assertEquals(true, $this->verifyIfUserIsInChannel($u2, $w1, $c1, true), "Wexterne was not added in private channel"); + + $this->login($u1->getUsernameCanonical()); + $result = $this->doPost("/ajax/workspace/members/remove", Array("ids" => Array($u2->getId()), "workspaceId" => $w1->getId())); + + + $this->assertEquals(Array("removed" => 1), $result["data"]); + $linkChannel = $this->getDoctrine()->getRepository("Twake\Channels:ChannelMember")->findOneBy(Array("direct" => false, "user_id" => $u2->getId() . "", "channel_id" => $c1->getId())); + $this->assertNull($linkChannel, "Wexterne is still in channel (entity) on remove from workspace"); + $this->assertEquals(false, $this->verifyIfUserIsInChannel($u1, $w1, $c1, true, $u2->getUsernameCanonical()), "Wexterne is still in channel (front) on remove from workspace"); + $this->logout(); + } + + + private function getStuff() + { + $u1 = $this->newUserByName("usertest001"); + $g1 = $this->newGroup($u1->getId(), "grptest1"); + $w1 = $this->newWorkspace("workspace1", $g1); + $w1->setMemberCount(1); + $this->getDoctrine()->persist($w1); + $rightAdmin = new WorkspaceLevel(); + $rightAdmin->setIsAdmin(true); + $rightAdmin->setWorkspace($w1); + $this->getDoctrine()->persist($rightAdmin); + $linkWorkspaceUser = new WorkspaceUser($w1, $u1, $rightAdmin->getId()); + $this->getDoctrine()->persist($linkWorkspaceUser); + + $c1 = $this->newChannel($g1, $w1, $u1); + + return Array($g1, $w1, $c1, $u1); + } + + private function getChannelsFromFront($workspace, $channel, $user) + { + $this->login($user->getUsernameCanonical()); + $result = $this->doPost("/ajax/core/collections/init", Array( + "collection_id" => "channels/workspace/" . $workspace->getId(), + "options" => Array( + "type" => "channels/workspace", + "get_options" => Array( + "workspace_id" => $workspace->getId(), + ), + "_grouped" => true, + ) + )); + if (!isset($result["data"])) { + return []; + } + $channels = $result["data"]["get"]; + return $channels; + } + + private function updateChainviteFromFront($workspace, $channel, $user, $toAdd = [], $toRemove = []) + { + $channels = $this->getChannelsFromFront($workspace, $channel, $user); + $frontChan = $this->getChannelById($channels, $channel->getId()); + if ($frontChan) { + $members = $frontChan["ext_members"]; + foreach ($toAdd as $adding) { + if (!in_array($adding, $members)) { + $members[] = $adding; + } + } + foreach ($toRemove as $removing) { + if (($index = array_search($removing . "", $members)) !== false) { + array_splice($members, $index, 1); + } + } + $frontChan["ext_members"] = $members; + $result = $this->doPost("/ajax/channels/save", Array( + "collection_id" => "", + "object" => $frontChan, + )); + return true; + } + return false; + } + + private function verifyIfUserIsInChannel($user, $workspace, $channel, $hasToBeExterne, $mailOrUsername = null) + { + $this->login($user->getUsernameCanonical()); + $result = $this->doPost("/ajax/core/collections/init", Array( + "collection_id" => "channels/workspace/" . $workspace->getId(), + "options" => Array( + "type" => "channels/workspace", + "get_options" => Array( + "workspace_id" => $workspace->getId(), + ), + "_grouped" => true, + ) + )); + if (isset($result["data"]["get"])) { + $channels = $result["data"]["get"]; + } else { + $channels = []; + } + $isOk = $this->isInChannel($channels, $user, $channel, $hasToBeExterne, $mailOrUsername); + $this->logout(); + return $isOk; + } + + private function isInChannel($channelInWorkspace, $user, $channel, $hasToBeExterne, $mailOrUsername = null) + { + $chan = $this->getChannelById($channelInWorkspace, $channel->getId()); + if ($chan) { + if ($hasToBeExterne) { + $externeMembers = $chan["ext_members"]; + foreach ($externeMembers as $ext) { + if ($mailOrUsername) { + if ($ext == $mailOrUsername) { + return true; + } + } elseif ($ext == $user->getId()) { + return true; + } + } + } else { + $members = $chan["members"]; + foreach ($members as $memb) { + if ($memb == $user->getId()) { + return true; + } + } + } + } + return false; + } + + private function getChannelById($channelList, $channelId) + { + if (is_array($channelList)) { + foreach ($channelList as $chan) { + if ($chan["id"] == $channelId) { + return $chan; + } + } + } + return false; + } +} \ No newline at end of file diff --git a/twake/backend/core/tests/UsersBundle/UserAccountTest.php b/twake/backend/core/tests/UsersBundle/UserAccountTest.php new file mode 100755 index 00000000..010ebc22 --- /dev/null +++ b/twake/backend/core/tests/UsersBundle/UserAccountTest.php @@ -0,0 +1,420 @@ +<?php + +namespace Tests\UsersBundle; + +require_once __DIR__ . "/../WebTestCaseExtended.php"; + +use Tests\WebTestCaseExtended; +use Twake\Users\Entity\Mail; + +class UserAccountTest extends WebTestCaseExtended + +//Tests when the user is already connected + +{ + + public function testAlive() + { + + $this->removeUserByName("usertest001"); + $user = $this->newUserByName("usertest001"); + + $alive = $this->get("app.user")->Alive($user->getId()); + + + $lastActivityUser = $user->getLastActivity(); + $currentDate = date("U"); + + $difference = $currentDate - $lastActivityUser; + + $this->assertLessThanOrEqual(10, $difference); + + } + + public function testChangePassword() + + { + + $this->removeUserByName("usertest001"); + $user = $this->newUserByName("usertest001"); + + $result = $this->get("app.user")->changePassword($user->getId(), "usertest001", "newPassword"); + $this->assertEquals(true, $result); + + $result = $this->get("app.user")->checkPassword($user->getId(), "newPassword"); + $this->assertEquals(true, $result); + + $result = $this->get("app.user")->changePassword($user->getId(), "usertest001", "3"); + $this->assertEquals(false, $result); + + $result = $this->get("app.user")->checkPassword($user->getId(), "newPassword"); + $this->assertEquals(true, $result); + + $result = $this->get("app.user")->changePassword($user->getId(), "usertest001", null); + $this->assertEquals(false, $result); + + $result = $this->get("app.user")->checkPassword($user->getId(), "newPassword"); + $this->assertEquals(true, $result); + + $result = $this->get("app.user")->changePassword("14005200-48b1-11e9-a0b4-0242ac120005", "usertest001", "newpasswordbis"); + $this->assertEquals(false, $result); + + $result = $this->get("app.user")->checkPassword($user->getId(), "newPassword"); + $this->assertEquals(true, $result); + + + } + + public function testChangePseudo() + + { + $this->removeUserByName("usertest001"); + $user = $this->newUserByName("usertest001"); + + $result = $this->get("app.user")->changePseudo($user->getId(), "newpseudo"); + $this->assertEquals(true, $result); + $this->assertEquals("newpseudo", $user->getUsername()); + + $this->removeUserByName("newpseudo"); + + + $user2 = $this->newUserByName("usertest002"); + $user = $this->newUserByName("usertest001"); + $result = $this->get("app.user")->changePseudo($user->getId(), "usertest002"); + $this->assertEquals(false, $result); + $this->removeUserByName("usertest002"); + + $result = $this->get("app.user")->changePseudo($user->getId(), null); + $this->assertEquals(false, $result); + + + $result = $this->get("app.user")->changePseudo("14005200-48b1-11e9-a0b4-0242ac120005", "newPseudoBis"); + $this->assertEquals(false, $result); + + + } + + public function testChangeMainMail() + { + + $user = $this->newUserByName("usertest001"); + + $mail = new Mail(); + $mail->setMail("emailforphpunittest@twake_phpunit.fr"); + $mail->setUserId($user->getId()); + $this->getDoctrine()->persist($mail); + $this->getDoctrine()->flush(); + + $id = $mail->getId() . ""; + + $result = $this->get("app.user")->changeMainMail($user->getId(), $id); + + $this->assertEquals(true, $result); + + $this->assertEquals("emailforphpunittest@twake_phpunit.fr", $user->getEmail()); + + $this->getDoctrine()->remove($mail); + $this->removeUserByName("usertest001"); + $this->getDoctrine()->flush(); + + $result = $this->get("app.user")->changeMainMail("14005200-48b1-11e9-a0b4-0242ac120005", $id); + $this->assertEquals(false, $result); + + $user = $this->newUserByName("usertest001"); + $user = $this->getDoctrine()->getRepository("Twake\Users:User")->findOneBy(Array("usernamecanonical" => "usertest001")); + $result = $this->get("app.user")->changeMainMail($user->getId(), "14005200-48b1-11e9-a0b4-0242ac120005"); + $this->assertEquals(false, $result); + + + } + + public function testSetNotificationPreferences() + { + $user = $this->newUserByName("usertest001"); + $notif = Array( + "key1" => "notif1", + "key2" => "notif2" + ); + $result = $this->get("app.user")->setNotificationPreferences($user->getId(), $notif); + $i = 1; + foreach ($notif as $key => $value) { + + $this->assertArrayHasKey($key, $user->getNotificationPreference()); + $this->assertEquals("notif" . $i, $user->getNotificationPreference()[$key]); + $i++; + } + } + + public function testGetNotificationPreferences() + { + $user = $this->newUserByName("usertest001"); + + $result = $this->get("app.user")->getNotificationPreferences($user->getId()); + + $bool = is_array($result); + $this->assertEquals(true, $bool); + + $result = $this->get("app.user")->getNotificationPreferences("14005200-48b1-11e9-a0b4-0242ac120005"); + $this->assertEquals(false, $result); + } + + public function testSetWorkspacesPreferences() + { + $user = $this->newUserByName("usertest001"); + + $preferences = Array( + "key1" => "pref1", + "key2" => "pref2" + ); + + $result = $this->get("app.user")->setWorkspacesPreferences($user->getId(), $preferences); + + $i = 1; + foreach ($preferences as $key => $value) { + + $this->assertArrayHasKey($key, $user->getWorkspacesPreference()); + $this->assertEquals("pref" . $i, $user->getWorkspacesPreference()[$key]); + $i++; + } + + } + + public function testUpdateTutorialStatus() + { + $user = $this->newUserByName("usertest001"); + + $status = Array( + "key1" => "status1", + "key2" => "status2" + ); + + $result = $this->get("app.user")->setTutorialStatus($user->getId(), $status); + $i = 1; + foreach ($status as $key => $value) { + + $this->assertArrayHasKey($key, $user->getTutorialStatus()); + $this->assertEquals("status" . $i, $user->getTutorialStatus()[$key]); + $i++; + } + } + + public function testUpdateLanguage() + { + + $user = $this->newUserByName("usertest001"); + + $result = $this->get("app.user")->updateLanguage($user->getId(), "langage"); + $this->assertEquals("langage", $user->getLanguage()); + + } + + public function testSetIsNew() + { + $user = $this->newUserByName("usertest001"); + $this->assertEquals(true, $user->getisNew()); + + + $result = $this->get("app.user")->setIsNew(false, $user->getId()); + $this->assertEquals(false, $user->getisNew()); + } + + /*public function testUpdateNotificationPreferenceByWorkspace() + { + $user = $this->newUserByName("usertest001"); + $result = $this->login($user->getUsernameCanonical()); + + $result = $this->doPost("/ajax/users/account/update_notifications", Array( + "workspaceId" => "14005200-48b1-11e9-a0b4-0242ac120005", + "appNotification" => Array() + )); + $this->assertEquals("success", $result["data"]); + $this->assertArrayHasKey("14005200-48b1-11e9-a0b4-0242ac120005", $user->getNotificationPreference()["workspace"]); + $this->assertEquals(Array(), $user->getNotificationPreference()["workspace"]["14005200-48b1-11e9-a0b4-0242ac120005"]); + + }*/ + + public function testRemoveUserByUsername() + { + + $user = $this->newUserByName("usertest001"); + + $result = $this->get("app.user")->removeUserByUsername($user->getUsername()); + + $result = $this->doPost("/ajax/users/current/get", Array()); + + $this->assertEquals("disconnected", $result["errors"]["0"]); + + $this->assertEquals(false, $this->get("app.user")->removeUserByUsername($user->getUsername())); + + + } + + public function testThreeNewPassword() + { + + $user = $this->newUserByName("usertest001"); + $result = $this->doPost("/ajax/users/recover/mail", Array( + "email" => "usertest001@twake_phpunit.fr" + )); + $token = $result["data"]["token"]; + $boolean = false; + if (is_string($token) && strlen($result["data"]["token"]) > 5) { + $boolean = true; + } + $this->assertEquals(true, $boolean); + +//--------------------------------------------------------------------------- + + $result = $this->doPost("/ajax/users/recover/mail", Array( + "email" => "emai1fortest@twake_phpunit.fr" + )); + $this->assertEquals("nosuchmail", $result["errors"][0]); + + $verif = $this->getDoctrine()->getRepository("Twake\Users:VerificationNumberMail")->findOneBy(Array("token" => $token)); + $code = $verif->getcode(); + $this->getDoctrine()->persist($verif); + $this->getDoctrine()->flush(); + + + $result = $this->doPost("/ajax/users/recover/verify", Array( + "code" => $code, + "token" => $token + )); + + $res = $result["data"]["status"]; + $this->assertEquals("success", $res); + + $result = $this->doPost("/ajax/users/recover/verify", Array( + "code" => $code, + "token" => "tokenfortest" + )); + + $res = $result["errors"][0]; + $this->assertEquals("badcodeortoken", $res); + + +//------------------------------------------------------------------------------- + + $result = $this->doPost("/ajax/users/recover/password", Array( + "code" => $code, + "token" => $token, + "password" => "usertest001" + )); + + $res = $result["data"]["status"]; + $this->assertEquals("success", $res); + + $result = $this->doPost("/ajax/users/recover/password", Array( + "code" => $code, + "token" => "tokenfortest", + "password" => "usertest001" + )); + + $res = $result["errors"][0]; + $this->assertEquals("badcodeortoken", $res); + + } + + public function testSubscribeMail() + { + + $user = $this->newUserByName("usertest001"); + $user->setMailVerified(false); + $user->setisNew(true); + $this->getDoctrine()->persist($user); + $mail = $this->getDoctrine()->getRepository("Twake\Users:Mail")->findOneBy(Array("mail" => "usertest001@twake_phpunit.fr")); + $this->getDoctrine()->remove($mail); + $this->getDoctrine()->flush(); + + + $result = $this->doPost("/ajax/users/subscribe/mail", Array( + "email" => "usertest001@twake_phpunit.fr", + "username" => "usertestfortest", + "password" => "usertest001", + "name" => "namefortest", + "firstname" => "firstnamefortest", + "phone" => "phonefortest" + )); + + $result = $this->doPost("/ajax/users/current/get", Array()); + $this->assertEquals("disconnected", $result["errors"]["0"]); + $this->assertEquals(Array(), $result["data"]); + + + $this->removeUserByName("usertest001"); + $result = $this->doPost("/ajax/users/subscribe/mail", Array( + "email" => "usertest001@twake_phpunit.fr", + "username" => "usertest001", + "password" => "usertest001", + "name" => "namefortest", + "firstname" => "firstnamefortest", + "phone" => "phonefortest" + )); + + $token = $result["data"]["token"]; + + $boolean = false; + if (is_string($token) && strlen($result["data"]["token"]) > 5) { + $boolean = true; + } + $this->assertEquals(true, $boolean); + + $user = $this->newUserByName("usertest001"); + $user = $this->getDoctrine()->getRepository("Twake\Users:User")->findOneBy(Array("usernamecanonical" => "usertest001")); + + $result = $this->doPost("/ajax/users/subscribe/mail", Array( + "email" => "usertest001_notused@twake_phpunit.fr", + "username" => "usertest001", + "password" => "usertest001", + "name" => "namefortest", + "firstname" => "firstnamefortest", + "phone" => "phonefortest" + )); + + $result = $result["errors"][0]; + $this->assertEquals("usernamealreadytaken", $result, "testing username available"); + + $result = $this->doPost("/ajax/users/subscribe/mail", Array( + "email" => "12345678", + "username" => "usertestfortest", + "password" => "usertest00D222", + "name" => "namefortest", + "firstname" => "firstnamefortest", + "phone" => "phonefortest" + )); + $result = $result["errors"][0]; + $this->assertEquals("mailalreadytaken", $result, "Testing wrong mail format"); + + + $result = $this->doPost("/ajax/users/subscribe/mail", Array( + "email" => "usertest001@twake_phpunit.fr", + "username" => "usertestfortest", + "password" => "usertest001", + "name" => "namefortest", + "firstname" => "firstnamefortest", + "phone" => "phonefortest" + )); + $result = $result["errors"][0]; + $this->assertEquals("mailalreadytaken", $result, "testing mail available"); + + + $mailfortest = new Mail(); + $mailfortest->setMail("emailforphpunittest@twake_phpunit.fr"); + $this->getDoctrine()->persist($mailfortest); + $this->getDoctrine()->flush(); + + $result = $this->doPost("/ajax/users/subscribe/mail", Array( + "email" => "emailforphpunittest@twake_phpunit.fr", + "username" => "usertestfortest", + "password" => "usertest001", + "name" => "namefortest", + "firstname" => "firstnamefortest", + "phone" => "phonefortest" + )); + + $this->removeUserByName("usertest001"); + + + } + +} \ No newline at end of file diff --git a/twake/backend/core/tests/UsersBundle/UserLoginTest.php b/twake/backend/core/tests/UsersBundle/UserLoginTest.php new file mode 100755 index 00000000..a06d581e --- /dev/null +++ b/twake/backend/core/tests/UsersBundle/UserLoginTest.php @@ -0,0 +1,355 @@ +<?php + +namespace Tests\UsersBundle; + +require_once __DIR__ . "/../WebTestCaseExtended.php"; + +use Tests\WebTestCaseExtended; +use Twake\Users\Entity\Device; + +class UserLoginTest extends WebTestCaseExtended + +//Tests when the user is not connected yet + +{ + + public function testLoginCorrect() + + { + $user = $this->newUserByName("usertest001"); + + + $this->login("usertest001"); + $result = $this->doPost("/ajax/users/current/get", Array()); + + $name = $result["data"]["username"]; + $this->assertEquals("usertest001", $name); + + + } + + public function testLoginIncorrect() + { + $user = $this->newUserByName("usertest001"); + $result = $this->doPost("/ajax/users/login", Array( + "_username" => "wrong email", + + )); + + $result = $this->doPost("/ajax/users/current/get", Array()); + + $this->assertEquals("disconnected", $result["errors"]["0"]); + $this->assertEquals(Array(), $result["data"]); + + } + + public function testEmailCorrect() + { + $user = $this->newUserByName("usertest001"); + + $result = $this->doPost("/ajax/users/login", Array( + "_username" => "usertest001@twake_phpunit.fr", + "_password" => "usertest001" + )); + + + $result = $this->doPost("/ajax/users/current/get", Array()); + $email = $result["data"]["mails"][0]["email"]; + $this->assertEquals("usertest001@twake_phpunit.fr", $email); + } + + public function testPasswordIncorrect() + { + $user = $this->newUserByName("usertest001"); + + + $result = $this->doPost("/ajax/users/login", Array( + "_username" => "usertest001", + "_password" => "wrong password" + )); + + $result = $this->doPost("/ajax/users/current/get", Array()); + $this->assertEquals("disconnected", $result["errors"]["0"]); + $this->assertEquals(Array(), $result["data"]);; + + } + + public function testBanuser() + { + + $user = $this->newUserByName("usertest001"); + + $user = $this->getDoctrine()->getRepository("Twake\Users:User")->findOneBy(Array("usernamecanonical" => "usertest001")); + + $this->assertEquals(false, $user->getBanned()); + + $ban = $this->get("app.user")->ban($user->getId()); + + $user = $this->getDoctrine()->getRepository("Twake\Users:User")->findOneBy(Array("usernamecanonical" => "usertest001")); + + $this->assertEquals(true, $user->getBanned()); + + $result = $this->doPost("/ajax/users/login", Array( + "_username" => "usertest001", + "_password" => "usertest001" + )); + $this->assertEquals("disconnected", $result["data"]["status"]); + + + //test for unban + + $unban = $this->get("app.user")->unban($user->getId()); + + $result = $this->doPost("/ajax/users/login", Array( + "_username" => "usertest001", + "_password" => "usertest001" + )); + $this->assertEquals("connected", $result["data"]["status"]); + + } + + public function testPassword() + { + $user = $this->newUserByName("usertest001"); + + $user = $this->getDoctrine()->getRepository("Twake\Users:User")->findOneBy(Array("usernamecanonical" => "usertest001")); + + $checkPass = $this->get("app.user")->checkPassword($user->getId(), "usertest001"); + + + $user = $this->getDoctrine()->getRepository("Twake\Users:User")->findOneBy(Array("usernamecanonical" => "usertest001")); + $this->assertEquals(true, $checkPass); + + $checkPass = $this->get("app.user")->checkPassword($user->getId(), "wrong password"); + $this->assertEquals(false, $checkPass); + + + } + + public function testPasswordNoExistingUser() + { + + $this->removeUserByName("usertest001"); + + $user = $this->getDoctrine()->getRepository("Twake\Users:User")->findOneBy(Array("usernamecanonical" => "usertest001")); + $checkPass = $this->get("app.user")->checkPassword("14005200-48b1-11e9-a0b4-0242ac120005", "usertest001"); + $user = $this->getDoctrine()->getRepository("Twake\Users:User")->findOneBy(Array("usernamecanonical" => "usertest001")); + $this->assertEquals(false, $checkPass); + + } + + public function testAvailableMail() + { + + $this->removeUserByName("usertest001"); + $result = $this->get("app.user")->getAvaibleMailPseudo("usertest001@twake_phpunit.fr", "usertest001"); + $this->assertEquals(true, $result); + + $user = $this->newUserByName("usertest001"); + $result = $this->get("app.user")->getAvaibleMailPseudo("usertest001@twake_phpunit.fr", "usertest001"); + $this->assertGreaterThan(0, count($result)); + + $result = $this->get("app.user")->getAvaibleMailPseudo("wrong email", "usertest001"); + $this->assertGreaterThan(0, count($result)); + } + + public function testLogoutCorrect() + + { + $this->removeUserByName("usertest001"); + $user = $this->newUserByName("usertest001"); + + + $result = $this->doPost("/ajax/users/login", Array( + "_username" => "usertest001", + "_password" => "usertest001" + )); + + $result = $this->doPost("/ajax/users/current/get", Array()); + + $name = $result["data"]["username"]; + $this->assertEquals("usertest001", $name); + + $result = $this->doPost("/ajax/users/logout", Array()); + $this->clearClient(); + + $result = $this->doPost("/ajax/users/current/get", Array()); + $this->assertEquals(Array(), $result["data"]); + } + + public function testVerifyMail() + { + + $this->removeUserByName("usertest001"); + $user = $this->newUserByName("usertest001"); + $user = $this->getDoctrine()->getRepository("Twake\Users:User")->findOneBy(Array("usernamecanonical" => "usertest001")); + + $result = $this->doPost("/ajax/users/recover/mail", Array( + "email" => "usertest001@twake_phpunit.fr" + )); + $token = $result["data"]["token"]; + + $verif = $this->getDoctrine()->getRepository("Twake\Users:VerificationNumberMail")->findOneBy(Array("token" => $token)); + $code = $verif->getcode(); + $this->getDoctrine()->persist($verif); + $this->getDoctrine()->flush(); + + + $res = $this->doPost("/ajax/users/subscribe/doverifymail", Array( + "code" => $code, + "token" => $token, + "mail" => "usertest001@twake_phpunit.fr" + )); + + + $verificationRepository = $this->getDoctrine()->getRepository("Twake\Users:VerificationNumberMail"); + + $ticket = $verificationRepository->findOneBy(Array("token" => $token)); + $mail = trim(strtolower("usertest001@twake_phpunit.fr")); + + $this->assertEquals(true, $ticket->getVerified()); + + + $this->assertEquals(true, $user->getMailVerifiedExtended()); + + $email = $this->getDoctrine()->getRepository("Twake\Users:Mail")->findOneBy(Array("mail" => "usertest001@twake_phpunit.fr")); + $email = $email->getMail(); + $this->assertEquals("usertest001@twake_phpunit.fr", $email); + + + $workspaceUerByMailRepository = $this->getDoctrine()->getRepository("Twake\Workspaces:WorkspaceUserByMail")->findOneBy(Array("mail" => "usertest001@twake_phpunit.fr")); + $this->assertEquals(null, $workspaceUerByMailRepository); + + + $res = $this->doPost("/ajax/users/subscribe/doverifymail", Array( + "code" => "ftvg", + "token" => "bgfsdngfn", + "mail" => "usertest001@twake_phpunit.fr" + )); + } + + public function testAddDevice() + { + + + $this->removeUserByName("usertest001"); + $user = $this->newUserByName("usertest001"); + $user = $this->getDoctrine()->getRepository("Twake\Users:User")->findOneBy(Array("usernamecanonical" => "usertest001")); + + $result = $this->doPost("/ajax/users/login", Array( + "_username" => "usertest001", + "_password" => "usertest001" + )); + + $device = Array( + "type" => "APNS", + "value" => "AZERTYUIOPQSDFGHJKLMWXCVBN134567890", + "version" => "1.2.0" + + ); + + + $existedDevice = $this->getDoctrine()->getRepository("Twake\Users:Device")->findOneBy(Array("value" => "AZERTYUIOPQSDFGHJKLMWXCVBN134567890")); + if (isset($existedDevice)) { + $this->getDoctrine()->remove($existedDevice); + $this->getDoctrine()->flush(); + } + + + $res = $this->doPost("/ajax/users/current/get", Array( + "device" => $device + )); + + + $existedDevice = $this->getDoctrine()->getRepository("Twake\Users:Device")->findOneBy(Array("value" => "AZERTYUIOPQSDFGHJKLMWXCVBN134567890")); + $existedDeviceValue = $existedDevice->getValue(); + $this->assertEquals("AZERTYUIOPQSDFGHJKLMWXCVBN134567890", $existedDeviceValue); + + + $device = Array( + "type" => "APNS", + "value" => "AZERTYUIOPQSDFGHJKLMWXCVBN134567890", + "version" => "1.3.0" + + ); + + $res = $this->doPost("/ajax/users/current/get", Array( + "device" => $device + )); + + $existedDevice = $this->getDoctrine()->getRepository("Twake\Users:Device")->findOneBy(Array("value" => "AZERTYUIOPQSDFGHJKLMWXCVBN134567890")); + $existedDeviceValue = $existedDevice->getValue(); + $this->assertEquals("1.3.0", $existedDevice->getVersion()); + + + $this->removeUserByName("usertest002"); + $user = $this->newUserByName("usertest002"); + $user = $this->getDoctrine()->getRepository("Twake\Users:User")->findOneBy(Array("usernamecanonical" => "usertest002")); + + $result = $this->doPost("/ajax/users/login", Array( + "_username" => "usertest002", + "_password" => "usertest002" + )); + + $res = $this->doPost("/ajax/users/current/get", Array( + "device" => $device + )); + + $existedDevice = $this->getDoctrine()->getRepository("Twake\Users:Device")->findOneBy(Array("value" => "AZERTYUIOPQSDFGHJKLMWXCVBN134567890")); + + $this->assertEquals($user->getId(), $existedDevice->getUserId()); + + } + + public function testRemoveDevice() + { + + $this->removeUserByName("usertest001"); + $user = $this->newUserByName("usertest001"); + $user = $this->getDoctrine()->getRepository("Twake\Users:User")->findOneBy(Array("usernamecanonical" => "usertest001")); + + $result = $this->doPost("/ajax/users/login", Array( + "_username" => "usertest002", + "_password" => "usertest002" + )); + + $device_array = Array( + "type" => "APNS", + "value" => "AZERTYUIOPQSDFGHJKLMWXCVBN134567890", + "version" => "1.2.0" + ); + + + $device = $this->getDoctrine()->getRepository("Twake\Users:Device")->findOneBy(Array("value" => "AZERTYUIOPQSDFGHJKLMWXCVBN134567890")); + $deviceValue = $device->getValue(); + $this->assertEquals("AZERTYUIOPQSDFGHJKLMWXCVBN134567890", $deviceValue); + + $res = $this->doPost("/ajax/users/logout", Array( + "device" => $device_array + )); + + $device = $this->getDoctrine()->getRepository("Twake\Users:Device")->findOneBy(Array("value" => "AZERTYUIOPQSDFGHJKLMWXCVBN134567890")); + $this->assertEquals(null, $device); + + } + + public function testAddNewMail() + { + + $this->removeUserByName("usertest001"); + $user = $this->newUserByName("usertest001"); + $user = $this->getDoctrine()->getRepository("Twake\Users:User")->findOneBy(Array("usernamecanonical" => "usertest001")); + + $result = $this->doPost("/ajax/users/login", Array( + "_username" => "usertest001", + "_password" => "usertest001" + )); + + $result = $this->doPost("/ajax/users/account/addmail", Array( + "mail" => "usertest001secondmail@twake_phpunit.fr" + )); + + + } + +} \ No newline at end of file diff --git a/twake/backend/core/tests/WebTestCaseExtended.php b/twake/backend/core/tests/WebTestCaseExtended.php new file mode 100755 index 00000000..193a30a7 --- /dev/null +++ b/twake/backend/core/tests/WebTestCaseExtended.php @@ -0,0 +1,209 @@ +<?php + +namespace Tests; + +use App\App; +use Common\Http\Request; +use Twake\Workspaces\Entity\Group; +use Twake\Workspaces\Entity\Workspace; +use Twake\Channels\Entity\Channel; +use Twake\Channels\Entity\ChannelMember; +use Twake\Users\Entity\User; +use Twake\Workspaces\Entity\WorkspaceUser; +use Twake\Workspaces\Entity\WorkspaceLevel; + +class WebTestCaseExtended extends \PHPUnit\Framework\TestCase +{ + + var $client; + + /** @var App */ + public $app; + + public $cookies = []; + + + public function __construct() + { + error_reporting(E_ERROR | E_PARSE); + # Warning: + \PHPUnit_Framework_Error_Warning::$enabled = FALSE; + # notice, strict: + \PHPUnit_Framework_Error_Notice::$enabled = FALSE; + define("TESTENV", true); + } + + protected function getDoctrine() + { + return $this->get("app.twake_doctrine"); + } + + protected function get($service) + { + return $this->getClient()->getServices()->get($service); + } + + protected function clearApp() + { + $this->app = null; + } + + protected function clearClient() + { + $this->cookies = []; + } + + protected function getClient(): App + { + if (!isset($this->app) || !$this->app) { + $this->app = new App(); + } + return $this->app; + } + + protected function doPost($route, $data = Array()) + { + $this->clearApp(); + $request = new Request(); + $query_data = $this->getQueryFromUrl($route); + $request->cookies->reset($this->cookies); + $request->request->reset($data); + $request->query->reset($query_data["query"]); + $response = $this->getClient()->getRouting()->execute("post", $query_data["route"], $request); + $this->cookies = array_merge($this->cookies, $response->getCookiesValues()); + return json_decode($response->getContent(), 1); + } + + protected function doGet($route) + { + $this->clearApp(); + $request = new Request(); + $request->cookies->reset($this->cookies); + $query_data = $this->getQueryFromUrl($route); + $request->query->reset($query_data["query"]); + $response = $this->getClient()->getRouting()->execute("get", $query_data["route"], $request); + $this->cookies = array_merge($this->cookies, $response->getCookiesValues()); + return json_decode($response->getContent(), 1); + } + + private function getQueryFromUrl($route) + { + $route = explode("?", $route); + if (count($route) == 1) { + return ["route" => $route[0], "query" => []]; + } + $parts = $route[1]; + parse_str($parts, $query); + + return ["route" => $route[0], "query" => $query]; + } + + + public function newUserByName($name, $mail = null) + { + + $user = $this->get("app.twake_doctrine")->getRepository("Twake\Users:User")->findOneBy(Array("usernamecanonical" => $name)); + + if ($user) { + $this->removeUserByName($name); + } + + if (!$mail) { + $mail = $name . "@twake_phpunit.fr"; + } + + $userWithMail = $this->get("app.twake_doctrine")->getRepository("Twake\Users:User")->findOneBy(Array("emailcanonical" => $mail)); + if ($userWithMail) { + $this->removeUserByName($userWithMail->getUsername()); + } + + $mails = $this->get("app.twake_doctrine")->getRepository("Twake\Users:Mail")->findBy(Array("mail" => $mail)); + foreach ($mails as $mail) { + $this->get("app.twake_doctrine")->remove($mail); + $this->get("app.twake_doctrine")->flush(); + } + $token = $this->get("app.user")->subscribeMail($mail, $name, $name, "", "", "", "en", false); + $this->get("app.user")->verifyMail($mail, $token, "", true); + + $user = $this->get("app.twake_doctrine")->getRepository("Twake\Users:User")->findOneBy(Array("usernamecanonical" => $name)); + + return $user; + } + + public function removeUserByName($name) + { + $user = $this->get("app.twake_doctrine")->getRepository("Twake\Users:User")->findOneBy(Array("usernamecanonical" => $name)); + + if (isset($user)) { + + $mails = $this->get("app.twake_doctrine")->getRepository("Twake\Users:Mail")->findBy(Array("user_id" => $user)); + + foreach ($mails as $mail) { + $this->get("app.twake_doctrine")->remove($mail); + } + + $this->get("app.twake_doctrine")->remove($user); + $this->get("app.twake_doctrine")->flush(); + } + } + + public function newGroup($userId, $name) + { + $group = new Group($name); + $this->get("app.twake_doctrine")->persist($group); + $this->get("app.twake_doctrine")->flush(); + return $group; + } + + public function newWorkspace($name, $group) + { + $work = new Workspace($name); + $work->setGroup($group); + $this->get("app.twake_doctrine")->persist($work); + $this->get("app.twake_doctrine")->flush(); + + return $work; + } + + public function newChannel($group, $workspace, $user) + { + $channel = new Channel(); + $channel->setDirect(false); + $channel->setOriginalWorkspaceId($workspace->getId()); + $channel->setOriginalGroupId($group->getId()); + + $this->getDoctrine()->persist($channel); + $this->getDoctrine()->flush(); + + $linkUserChannel = new ChannelMember($user->getId() . "", $channel); + $this->getDoctrine()->persist($linkUserChannel); + $this->getDoctrine()->flush(); + return $channel; + } + + public function newSubscription($group, $pricing_plan, $balanceInit, $start_date, $end_date, $autowithdraw, $autorenew) + { + + $sub = $this->get("app.subscription_system")->create($group, $pricing_plan, $balanceInit, $start_date, $end_date, $autowithdraw, $autorenew); + + return $sub; + } + + public function login($username, $password = null) + { + if (!$password) { + $password = $username; + } + $result = $this->doPost("/ajax/users/login", Array( + "_username" => $username, + "_password" => $password + )); + return $result; + } + + public function logout() + { + $this->clearClient(); + $this->doPost("/ajax/users/logout", Array()); + } +} diff --git a/twake/backend/core/tests/autoload.php b/twake/backend/core/tests/autoload.php new file mode 100755 index 00000000..6d4cdd8b --- /dev/null +++ b/twake/backend/core/tests/autoload.php @@ -0,0 +1,3 @@ +<?php + +include_once __DIR__ . '/../vendor/autoload.php'; \ No newline at end of file diff --git a/twake/backend/core/web/app.php b/twake/backend/core/web/app.php new file mode 100755 index 00000000..413df3b7 --- /dev/null +++ b/twake/backend/core/web/app.php @@ -0,0 +1,49 @@ +<?php + +use App\App; +function getDefaultHeaders() +{ + if(headers_sent()){ + return; + } + if (isset($_SERVER['HTTP_ORIGIN']) && strpos("http://localhost", $_SERVER['HTTP_ORIGIN']) == 0) { + @header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN'], true); + } + @header('Access-Control-Allow-Headers: ' . 'authorization, Content-Type, *', true); + @header('Access-Control-Allow-Credentials: true', true); + @header('Access-Control-Allow-Methods: GET, POST', true); + @header('Access-Control-Max-Age: 600', true); +} + +if ($_SERVER['REQUEST_METHOD'] !== 'OPTIONS') { + + try { + + require_once __DIR__ . '/../vendor/autoload.php'; + require_once __DIR__ . '/../app/App.php'; + + if(!headers_sent()){ + @header('X-Frame-Options: SAMEORIGIN'); + } + + $app = new App(); + + $app->getCounter()->startTimer("main_run"); + if (php_sapi_name() != "cli") { + $app->run(); + } + $app->getCounter()->stopTimer("main_run"); + + $app->getCounter()->showResults(); + + return $app; + + } catch (\Exception $e) { + getDefaultHeaders(); + } + +} else { + + getDefaultHeaders(); + +} diff --git a/twake/backend/node/.eslintignore b/twake/backend/node/.eslintignore new file mode 100644 index 00000000..987411c1 --- /dev/null +++ b/twake/backend/node/.eslintignore @@ -0,0 +1,10 @@ +# /node_modules/* in the project root is ignored by default +# build artefacts +dist/* +coverage/* +# data definition files +**/*.d.ts +# custom definition files +/src/types/ +# tests +test/* diff --git a/twake/backend/node/.eslintrc b/twake/backend/node/.eslintrc new file mode 100644 index 00000000..70793cdd --- /dev/null +++ b/twake/backend/node/.eslintrc @@ -0,0 +1,36 @@ +{ + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint", "prettier", "unused-imports"], + "extends": ["plugin:@typescript-eslint/recommended", "prettier"], + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module" + }, + "rules": { + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { + "vars": "all", + "args": "after-used", + "ignoreRestSiblings": false, + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^_" + } + ], + "semi": ["off"], + "@typescript-eslint/semi": ["error"], + "quotes": ["error", "double", { "avoidEscape": true }], + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-explicit-any": 1, + "@typescript-eslint/no-inferrable-types": [ + "warn", + { + "ignoreParameters": true + } + ], + "unused-imports/no-unused-imports": "error", + "@typescript-eslint/no-extra-semi": ["error"], + "prettier/prettier": 2 + } +} diff --git a/twake/backend/node/.gitignore b/twake/backend/node/.gitignore new file mode 100644 index 00000000..b2d2affe --- /dev/null +++ b/twake/backend/node/.gitignore @@ -0,0 +1,41 @@ +# compiled output +/dist +/node_modules + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# OS +.DS_Store + +# Tests +/coverage +/.nyc_output + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +.env.development +config/local.json +config/production.json +config/development.json +jest.config.js +/config/test-local.json diff --git a/twake/backend/node/.nvmrc b/twake/backend/node/.nvmrc new file mode 100644 index 00000000..48082f72 --- /dev/null +++ b/twake/backend/node/.nvmrc @@ -0,0 +1 @@ +12 diff --git a/twake/backend/node/.prettierignore b/twake/backend/node/.prettierignore new file mode 100644 index 00000000..41b07685 --- /dev/null +++ b/twake/backend/node/.prettierignore @@ -0,0 +1,11 @@ +dist +vendor +node_modules +src/client/public +src/client/images +public +build +.idea +.storybook +.git +utils/scaffolds diff --git a/twake/backend/node/.prettierrc b/twake/backend/node/.prettierrc new file mode 100644 index 00000000..a5d7d44f --- /dev/null +++ b/twake/backend/node/.prettierrc @@ -0,0 +1,10 @@ +{ + "printWidth": 100, + "tabWidth": 2, + "useTabs": false, + "semi": true, + "singleQuote": false, + "trailingComma": "all", + "bracketSpacing": true, + "arrowParens": "avoid" +} diff --git a/twake/backend/node/README.md b/twake/backend/node/README.md new file mode 100644 index 00000000..fe33933d --- /dev/null +++ b/twake/backend/node/README.md @@ -0,0 +1,530 @@ +# Twake backend + +## Developer guide + +### Getting started + +1. Clone and install dependencies (assumes that you have Node.js 12 and npm installed. If not, we suggest to use [nvm](https://github.com/nvm-sh/nvm/)): + +```sh +git clone git@github.com:Twake/Twake.git +cd Twake/Twake/backend/node +npm install +``` + +2. Run in developer mode (will restart on each change) + +```sh +npm run dev +``` + +3. Backend is now running and available on [http://localhost:3000](http://localhost:3000) + +### Docker + +Run all tests + +```sh +docker-compose -f ./docker-compose.test.yml up +``` + +Run specific tests + +```sh +docker-compose -f ./docker-compose.test.yml run node npm run test:unit +``` + +will run unit tests only (`test:unit`). For possible tests to run, check the `package.json` scripts. + +### Command Line Interface (CLI) + +The Twake backend CLI provides a set of commands to manage/use/develop Twake from the `twake-cli` binary. +Before to use the CLI, you must `compile` Twake with `npm run build`. Once done, you can get help on on any command with the `--help` flag like `./bin/twake-cli console --help`. + +#### The 'console merge' command + +This command allows to connect to the database configured in the `./config/default.json` file and to "merge" the Twake users and companies into the "Twake Console". + +```sh +./bin/twake-cli console merge --url http://console.twake.app --client twake-app --secret supersecret +``` + +The simplified console workflow is like (some parts are done in parallel): + +1. Get all the companies +2. Iterate over companies and create them in the console side +3. For each company, get all the users +4. Iterate over all the users and create them in the console (if the user is in several companies, create once, add it to all the companies) +5. For each company, get all the admins and choose the oldest one which will be 'marked' as the owner on the console side + +At the end of the 'merge', a report will be displayed. + +### Component Framework + +The backend is developed using a software component approach in order to compose and adapt the platform based on needs and constraints. +The current section describes this approach, and how to extend it by creating new components. + +The platform has the following properties: + +- A platform is composed of multiple components +- A component has an unique name in the platform +- A component can provide a `service` +- A component can consume `services` from other components +- A component has a lifecycle composed of several states: `ready`, `initialized`, `started`, `stopped` +- A component lifecycle changes when a lifecycle event is triggered by the platform: `init`, `start`, `stop` +- By creating links between components (service producers and consumers), components lifecycles **are also linked together**: A component going from `ready` to `initialized` will wait for all its dependencies to be in `initialized` state. This is automatically handled by the platform. + +The platform currently have some limitations: + +- Components can not have cyclic dependencies: if `component X` requires a component which requires `component X` directly or in one of its dependencies, the platform will not start +- Components can only have local dependencies. + +#### Creating a new component + +To create a new component, a new folder must be created under the `src/services` one and an `index.ts` file must export the a class. This class will be instantiated by the platform and will be linked to the required services automatically. + +In order to illustrate how to create a component, let's create a fake Notification service. + +1. Create the folder `src/services/notification` +2. Create an `index.ts` file which exports a `NotificationService` class + +```js +// File src/services/notification/index.ts +import { TwakeService } from "../../core/platform/framework"; +import NotificationServiceAPI from "./api.ts"; + +export default class NotificationService extends TwakeService<NotificationServiceAPI> { + version = "1"; + name = "notification"; + service: NotificationServiceAPI; + + api(): NotificationServiceAPI { + return this.service; + } +} +``` + +3. Our `NotificationService` class extends the generic `TwakeService` class and we defined the `NotificationServiceAPI` as its generic type parameter. It means that in the platform, the other components will be able to retrieve the component from its name and then consume the API defined in the `NotificationServiceAPI` interface and exposed by the `api` method. + We need to create this `NotificationServiceAPI` interface which must extend the `TwakeServiceProvider` from the platform like: + +```js +// File src/services/notification/api.ts +import { TwakeServiceProvider } from "../../core/platform/framework/api"; + +export default interface NotificationServiceAPI extends TwakeServiceProvider { + + /** + * Send a message to a list of recipients + */ + send(message: string, recipients: string[]): Promise<string>; +} +``` + +4. Now that the interfaces are defined, we need to create the `NotificationServiceAPI` implementation (this is a dummy implementation which does nothing but illustrates the process): + +```js +// File src/services/notification/services/api.ts +import NotificationServiceAPI from "../api"; + +export class NotificationServiceImpl implements NotificationServiceAPI { + version = "1"; + + async send(message: string, recipients: string[]): Promise<string> { + return Promise.resolve(`${message} sent`); + } +} +``` + +5. `NotificationServiceImpl` now needs to be instanciated from the `NotificationService` class since this is where we choose to keep its reference and expose it. There are several places which can be used to instanciate it, in the constructor itself, or in one of the `TwakeService` lifecycle hooks. The `TwakeService` abstract class has several lifecycle hooks which can be extended by the service implementation for customization pusposes: + +- `public async doInit(): Promise<this>;` Customize the `init` step of the component. This is generally the place where services are instanciated. From this step, you can retrieve services consumed by the current component which have been already initialized by the platform. +- `public async doStart(): Promise<this>;` Customize the `start` step of the component. You have access to all other services which are already started. + +```js +// File src/services/notification/index.ts +import { TwakeService } from "../../core/platform/framework"; +import NotificationServiceAPI from "./api.ts"; +import NotificationServiceImpl from "./services/api.ts"; + +export default class NotificationService extends TwakeService<NotificationServiceAPI> { + version = "1"; + name = "notification"; + service: NotificationServiceAPI; + + api(): NotificationServiceAPI { + return this.service; + } + + public async doInit(): Promise<this> { + this.service = new NotificationServiceImpl(); + + return this; + } +} +``` + +6. Now that the service is fully created, we can consume it from any other service in the platform. To do this, we rely on Typescript decorators to define the links between components. For example, let's say that the a `MessageService` needs to call the `NotificationServiceAPI`, we can create the link with the help of the `@Consumes` decorator and get a reference to the `NotificationServiceAPI` by calling the `getProvider` on the component context like: + +```js +import { TwakeService, Consumes } from "../../core/platform/framework"; +import MessageServiceAPI from "./providapier"; +import NotificationServiceAPI from "../notification/api"; + +@Consumes(["notification"]) +export default class MessageService extends TwakeService<MessageServiceAPI> { + + public async doInit(): Promise<this> { + const notificationService = this.context.getProvider<NotificationServiceAPI>("notification"); + + // You can not call anything defined in the NotificationServiceAPI interface from here or from inner services by passing down the reference to notificationService. + } +} +``` + +#### Configuration + +The platform and services configuration is defined in the `config/default.json` file. It uses [node-config](https://github.com/lorenwest/node-config) under the hood and to configuration file inheritence is supported in the platform. + +The list of services to start is defined in the `services` array like: + +```json +{ + "services": ["auth", "user", "channels", "webserver", "websocket", "database", "realtime"] +} +``` + +Then each service can have its own configuration block which is accessible from its service name i.e. `websocket` service configuration is defined in the `websocket` element like: + +```json +{ + "services": ["auth", "user", "channels", "webserver", "websocket", "orm"], + "websocket": { + "path": "/socket", + "adapters": { + "types": [], + "redis": { + "host": "redis", + "port": 6379 + } + } + } +} +``` + +On the component class side, the configuration object is directly accessible from the `configuration` property like: + +```js +export default class WebSocket extends TwakeService<WebSocketAPI> { + async doInit(): Promise<this> { + // get the "path" value, defaults to "/socket" if not defined + const path = this.configuration.get < string > ("path", "/socket"); + + // The "get" method is generic and can accept custom types like + const adapters = this.configuration.get < AdaptersConfiguration > "adapters"; + } +} + +interface AdaptersConfiguration { + types: Array<string>; + redis: SocketIORedis.SocketIORedisOptions; +} +``` + +### Platform + +The Twake Platform is built using the component framework described just before and so, is composed of several technical services on which business services can rely on to provide a micro-services based platform. + +The current chapter describes the technical services of the plaform, how to use them, how to build business services on top of them... + +Current technical services are located in `src/core/platform/services`: + +- `auth`: To manage authentication +- `database`: To manage database connections +- `realtime`: To provide realtime notification on platform resources +- `webserver`: To expose services as REST ones +- `websocket`: To communicate between client and server using websockets + +#### Database Technical Service + +Database technical service provides an abstraction layer over several databases to get a connection through the help of drivers and to use them in any other services. + +Supported databases are currently [MongoDB](https://www.mongodb.com/) and [Cassandra](https://cassandra.apache.org/). Switching from one to other one is achieved from the database configuration document by switching the `database.type` flag: + +```json +{ + "database": { + "type": "cassandra", + "mongodb": { + "uri": "mongodb://localhost:27017", + "database": "twake" + }, + "cassandra": { + "contactPoints": ["localhost:9042"], + "localDataCenter": "datacenter1", + "keyspace": "twake" + } + } +} +``` + +In the example above, the `type` is set to `cassandra`, so the `database.cassandra` document will be used to connect to cassandra. + +##### Cassandra + +In order to use Cassandra, we will have to: + +1. Create a keyspace. From the configuration above, the keyspace is `twake` +2. Create all the required tables + +To achieve these steps, you have to use [cqlsh](https://cassandra.apache.org/doc/latest/tools/cqlsh.html) from a terminal then: + +1. Create the keyspace: + +```sh +CREATE KEYSPACE twake WITH replication = {'class': 'NetworkTopologyStrategy', 'datacenter1': '2'} AND durable_writes = true; +``` + +2. Create the required tables + +```sh +USE twake; + +CREATE TABLE channels(company_id uuid, workspace_id uuid, id uuid, archivation_date date, archived boolean, channel_group text, description text, icon text, is_default boolean, name text, owner uuid, visibility text, PRIMARY KEY ((company_id, workspace_id), id)); +``` + +##### MongoDB + +There are no special steps to achieve to use MongoDB. + +#### Realtime Technical Service + +The framework provides simple way to create CRUD Services which will notify clients using Websockets by following some conventions: + +1. The service must implement the `CRUDService` generic interface +2. In order to push notification to clients, Typescript decorators must be added on methods (Create, Update, Delete methods) + +For example, let's say that we want to implement a CRUD Service for `messages`: + +```js +import { + CRUDService, + CreateResult, + DeleteResult, + UpdateResult, + EntityId, +} from "@/core/platform/framework/api/crud-service"; + +class Message { + text: string; + createdAt: Date; + author: string; +} + +class MessageService implements CRUDService<Message> { + async create(item: Message): Promise<CreateResult<Message>> { + // save the message then return a CreateResult instance + } + + async get(id: EntityId): Promise<Message> { + // get the message from its ID and return it + } + + async update(id: EntityId, item: Message): Promise<UpdateResult<Message>> { + // update the message with the given id, patch it with `item` values + // then return an instance of UpdateResult + } + + async delete(id: EntityId): Promise<DeleteResult<Message>> { + // delete the message from its id then return a DeleteResult instance + } + + async list(): Promise<Message[]> { + // get a list of messages + } +} +``` + +By implementing the CRUD service following the API, we can now add realtime message to clients connected to Websocket on a selected collection of CRUD operations. For example, if we want to just notify when a `message` is created, we just have to add the right decorator on the `create` method like: + +```js +import { RealtimeCreated } from "@/core/platform/framework/decorators"; + +// top and bottom code removed for clarity +class MessageService implements CRUDService<Message> { + + @RealtimeCreated<Message>({ + room: "/messages", + path: message => `/messages/${message.id}` + }) + async create(item: Message): Promise<CreateResult<Message>> { + // save the message then return a CreateResult instance + const created: Message = new Message(/* */); + + return new CreateResult<Message>("message", created) + } + // ... +} +``` + +The `RealtimeCreated` decorator will intercept the `create` call and will publish an event in an internal event bus with the creation result, the input data and the `"/messages"` path. On the other side of the event bus, an event listener will be in charge of delivering the event to the right Websocket clients as described next. + +The Realtime\* decorators to add on methods to intercept calls and publish data are all following the same API. +A decorator takes two parameters as input: + +- First one is the room name to publish the notification to (`/messages` in the example above) +- Second one is the full path of the resource linked to the action (`message => /messages/${message.id}` in the example above) + +Both parameters can take a string or an arrow function as parameter. If arrow function is used, the input parameter will be the result element. By doing this, the paths can be generated dynamically at runtime. + +#### Websocket Technical Service + +Services annotated as described above automatically publish events to WebSockets. Under the hood, it uses Socket.IO rooms to send events to the right clients. + +##### Authentication + +- Client have to provide a valid JWT token to be able to connect and be authenticated by providing it as string in the `authenticate` event like `{ token: "the jwt token value" }` +- If the JWT token is valid, the client will receive a `authenticated` event +- If the JWT token is not valid or empty, the client will receive a `unauthorized` event + +**Example** + +```js +const io = require("socket.io-client"); + +// Get a JWT token from the Twake API first +const token = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOjEsImlhdCI6MTYwMzE5ODkzMn0.NvQoV9KeWuTNzRvzqbJ5uZCQ8Nmi2rCYQzcKk-WsJJ8"; +const socket = io.connect("http://localhost:3000", { path: "/socket" }); + +socket.on("connect", () => { + socket + .emit("authenticate", { token }) + .on("authenticated", () => { + console.log("User Authenticated"); + }) + .on("unauthorized", err => { + console.log("User is not authorized", err); + }); +}); + +socket.on("disconnected", () => console.log("Disconnected")); +``` + +##### Joining rooms + +CRUD operations on resources are pushing events in Socket.io rooms. In order to receive events, clients must subscribe to rooms by sending an `realtime:join` on an authenticated socket with the name of the room to join and with a valid JWT token like `{ name: "room name", token: "the jwt token for this room" }`: Users can not subscribe to arbitratry rooms, they have to be authorized to. + +As a result, the client will receive events: + +- `realtime:join:success` when join is succesful with data containing the name of the linked room like `{ name: "room" }`. +- `realtime:join:error` when join failed with data containing the name of the linked room and the error details like `{ name: "room", error: "some error message" }`. + +**Example** + +```js +const io = require("socket.io-client"); + +const token = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOjEsImlhdCI6MTYwMzE5ODkzMn0.NvQoV9KeWuTNzRvzqbJ5uZCQ8Nmi2rCYQzcKk-WsJJ8"; +const socket = io.connect("http://localhost:3000", { path: "/socket" }); + +socket.on("connect", () => { + socket + .emit("authenticate", { token }) + .on("authenticated", () => { + // join the /channels room + socket.emit("realtime:join", { name: "/channels", token: "twake" }); + socket.on("realtime:join:error", message => { + // will fire when join does not provide a valid token + console.log("Error on join", message); + }); + + // will be fired on each successful join. + // As event based, this event is not linked only to the join above + // but to all joins. So you have to dig into the message to know which one + // is successful. + socket.on("realtime:join:success", message => { + console.log("Successfully joined room", message.name); + }); + }) + .on("unauthorized", err => { + console.log("Unauthorized", err); + }); +}); + +socket.on("disconnected", () => console.log("Disconnected")); +``` + +##### Leaving rooms + +The client can leave the room by emitting a `realtime:leave` event with the name of the room given as `{ name: "the room to leave" }`. + +As a result, the client will receive events: + +- `realtime:leave:success` when leave is succesful with data containing the name of the linked room like `{ name: "room" }`. +- `realtime:leave:error` when leave failed with data containing the name of the linked room and the error details like `{ name: "room", error: "some error message" }`. + +Note: Asking to leave a room which has not been joined will not fire any error. + +**Example** + +```js +socket.on("connect", () => { + socket.emit("authenticate", { token }).on("authenticated", () => { + // leave the "/channels" room + socket.emit("realtime:leave", { name: "/channels" }); + + socket.on("realtime:leave:error", message => { + // will fire when join does not provide a valid token + console.log("Error on leave", message); + }); + + // will be fired on each successful leave. + // As event based, this event is not linked only to the leave above + // but to all leaves. So you have to dig into the message to know which one + // is successful. + socket.on("realtime:leave:success", message => { + console.log("Successfully left room", message.name); + }); + }); +}); +``` + +##### Subscribe to resource events + +Once the given room has been joined, the client will receive `realtime:resource` events with the resource linked to the event as data: + +```json +{ + "action": "created", + "room": "/channels", + "type": "channel", + "path": "/channels/5f905327e3e1626399aaad79", + "resource": { + "name": "My channel", + "id": "5f905327e3e1626399aaad79" + } +``` + +**Example:** + +```js +socket.on("connect", () => { + socket + .emit("authenticate", { token }) + .on("authenticated", () => { + // join the "/channels" room + socket.emit("realtime:join", { name: "/channels", token: "twake" }); + + // will only occur when an action occured on a resource + // and if and only if the client joined the room + // in which the resource is linked + socket.on("realtime:resource", event => { + console.log("Resource has been ${event.action}", event.resource); + }); + }) + .on("unauthorized", err => { + console.log("Unauthorized", err); + }); +}); +``` diff --git a/twake/backend/node/babel.config.js b/twake/backend/node/babel.config.js new file mode 100644 index 00000000..0c2628c0 --- /dev/null +++ b/twake/backend/node/babel.config.js @@ -0,0 +1,9 @@ +module.exports = { + presets: [["@babel/preset-env", { targets: { node: "current" } }], "@babel/preset-typescript"], + plugins: [ + ["@babel/plugin-proposal-decorators", { legacy: true }], + ["@babel/plugin-proposal-class-properties", { loose: true }], + ["@babel/plugin-proposal-private-property-in-object", { loose: true }], + "babel-plugin-parameter-decorator", + ], +}; diff --git a/twake/backend/node/bin/twake-cli b/twake/backend/node/bin/twake-cli new file mode 100755 index 00000000..a1fc424f --- /dev/null +++ b/twake/backend/node/bin/twake-cli @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +require("../dist/cli/index"); diff --git a/twake/backend/node/config/cli.json b/twake/backend/node/config/cli.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/twake/backend/node/config/cli.json @@ -0,0 +1 @@ +{} diff --git a/twake/backend/node/config/custom-environment-variables.json b/twake/backend/node/config/custom-environment-variables.json new file mode 100644 index 00000000..57896348 --- /dev/null +++ b/twake/backend/node/config/custom-environment-variables.json @@ -0,0 +1,81 @@ +{ + "sentry": { + "dsn": "SENTRY_DSN" + }, + "logger": { + "level": "LOG_LEVEL" + }, + "webserver": { + "logger": { + "level": "LOG_LEVEL" + }, + "static": { + "root": "STATIC_ROOT" + } + }, + "phpnode": { + "secret": "PHP_NODE_API_SECRET" + }, + "websocket": { + "auth": { + "jwt": { + "secret": "AUTH_JWT_SECRET" + } + } + }, + "tracker": { + "segment": { + "key": "SEGMENT_SECRET_KEY" + } + }, + "auth": { + "jwt": { + "secret": "AUTH_JWT_SECRET" + } + }, + "notifications": { + "push": { + "type": "PUSH_DRIVER", + "fcm": { + "endpoint": "PUSH_FCM_ENDPOINT", + "key": "PUSH_FCM_KEY" + } + } + }, + "database": { + "secret": "DB_SECRET", + "type": "DB_DRIVER", + "mongodb": { + "uri": "DB_MONGO_URI", + "database": "DB_MONGO_DATABASE" + }, + "cassandra": { + "contactPoints": "DB_CASSANDRA_URI", + "localDataCenter": "DB_CASSANDRA_LOCALDATACENTER", + "keyspace": "DB_CASSANDRA_KEYSPACE" + } + }, + "search": { + "type": "SEARCH_DRIVER", + "elasticsearch": { + "endpoint": "SEARCH_ES_ENDPOINT", + "flushInterval": "SEARCH_ES_FLUSHINTERVAL" + } + }, + "message-queue": { + "type": "PUBSUB_TYPE", + "amqp": { + "urls": "PUBSUB_URLS" + } + }, + "pusbub": { + "//": "//deprecated", + "type": "PUBSUB_TYPE", + "amqp": { + "urls": "PUBSUB_URLS" + } + }, + "plugins": { + "server": "PLUGINS_SERVER" + } +} diff --git a/twake/backend/node/config/default.json b/twake/backend/node/config/default.json new file mode 100644 index 00000000..8e7c5a1c --- /dev/null +++ b/twake/backend/node/config/default.json @@ -0,0 +1,191 @@ +{ + "general": { + "help_url": false, + "pricing_plan_url": "", + "app_download_url": "https://twake.app/download", + "mobile": { + "mobile_redirect": "mobile.twake.app", + "mobile_appstore": "https://apps.apple.com/fr/app/twake/id1588764852?l=en", + "mobile_googleplay": "https://play.google.com/store/apps/details?id=com.twake.twake&gl=FR" + }, + "accounts": { + "_type": "console", + "type": "internal", + "internal": { + "disable_account_creation": false + }, + "console": { + "account_management_url": "http://web.twake-console.local/profile?company-code={company_id}", + "authority": "http://auth.example.com/", + "client_id": "twakeweb", + "collaborators_management_url": "http://web.twake-console.local/compaies/{company_id}/users?company-code={company_id}", + "company_management_url": "http://web.twake-console.local/companies?company-code={company_id}" + } + } + }, + "console": { + "_type": "remote", + "type": "internal", + "remote": { + "new_console": false, + "username": "", + "password": "12345678", + "url": "https://some-remote-console-url/", + "hook": { + "token": "12345678" + } + }, + "internal": { + "disable_account_creation": false + } + }, + "sentry": { + "dsn": "" + }, + "logger": { + "level": "debug" + }, + "tracker": { + "type": "segment", + "segment": { + "key": "" + } + }, + "webserver": { + "port": 3000, + "logger": { + "level": "info" + }, + "cors": { + "origin": "*" + }, + "static": { + "root": "./public" + } + }, + "phpnode": { + "secret": "api_supersecret", + "php_endpoint": "http://nginx:80" + }, + "websocket": { + "path": "/socket/", + "adapters": { + "types": [], + "redis": { + "host": "redis", + "port": 6379 + } + }, + "auth": { + "jwt": { + "secret": "supersecret" + } + } + }, + "auth": { + "jwt": { + "secret": "supersecret", + "expiration": 3600, + "refresh_expiration": 2592000 + } + }, + "database": { + "secret": "ab63bb3e90c0271c9a1c06651a7c0967eab8851a7a897766", + "type": "cassandra", + "mongodb": { + "uri": "mongodb://mongo:27017", + "database": "twake" + }, + "cassandra": { + "contactPoints": ["scylladb:9042"], + "localDataCenter": "datacenter1", + "keyspace": "twake", + "wait": false, + "retries": 10, + "delay": 200 + } + }, + "message-queue": { + "// possible 'type' values are": "'amqp' or 'local'", + "type": "amqp", + "amqp": { + "urls": ["amqp://guest:guest@rabbitmq:5672"] + } + }, + "search": { + "type": "elasticsearch", + "elasticsearch": { + "endpoint": "http://elasticsearch:9200" + } + }, + "push": { + "type": false, + "fcm": { + "endpoint": "https://fcm.googleapis.com/fcm/send", + "key": "" + } + }, + "storage": { + "secret": "0ea28a329df23220fa814e005bfb671c", + "iv": "1234abcd00000000", + "type": "local", + "S3": { + "endPoint": "play.min.io", + "port": 9000, + "useSSL": false, + "accessKey": "ABCD", + "secretKey": "x1yz" + }, + "local": { + "path": "/storage/" + } + }, + "plugins": { + "server": "plugins:3100" + }, + "knowledge-graph": { + "endpoint": "http://host-gateway:8888", + "callback_token": "secret", + "use": false, + "forwarded_companies": [] + }, + "email-pusher": { + "endpoint": "https://api.smtp2go.com/v3/email/send", + "api_key": "secret", + "sender": "noreply@twake.app" + }, + "services": [ + "auth", + "push", + "storage", + "webserver", + "websocket", + "database", + "cron", + "search", + "message-queue", + "realtime", + "phpnode", + "tracker", + "general", + "user", + "applications-api", + "applications", + "channels", + "notifications", + "messages", + "files", + "workspaces", + "console", + "previews", + "counter", + "statistics", + "cron", + "online", + "knowledge-graph", + "knowledge-graph-web", + "email-pusher", + "documents", + "tags" + ] +} diff --git a/twake/backend/node/config/test.json b/twake/backend/node/config/test.json new file mode 100644 index 00000000..65aadc6f --- /dev/null +++ b/twake/backend/node/config/test.json @@ -0,0 +1,26 @@ +{ + "database": { + "secret": "ab63bb3e90c0271c9a1c06651a7c0967eab8851a7a897766", + "mongodb": { + "uri": "mongodb://mongo:27017" + }, + "cassandra": { + "contactPoints": ["scylladb:9042"], + "wait": true, + "retries": 50, + "delay": 500, + "queryOptions": { + "consistency": 1 + } + } + }, + "message-queue": { + "type": "amqp", + "amqp": { + "urls": ["amqp://guest:guest@rabbitmq:5672"] + } + }, + "phpnode": { + "php_endpoint": false + } +} diff --git a/twake/backend/node/package-lock.json b/twake/backend/node/package-lock.json new file mode 100644 index 00000000..7bc522c7 --- /dev/null +++ b/twake/backend/node/package-lock.json @@ -0,0 +1,12195 @@ +{ + "name": "@twake/twake-backend", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "requires": { + "@babel/highlight": "^7.14.5" + } + }, + "@babel/compat-data": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", + "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", + "dev": true + }, + "@babel/core": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.0.tgz", + "integrity": "sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.15.0", + "@babel/helper-compilation-targets": "^7.15.0", + "@babel/helper-module-transforms": "^7.15.0", + "@babel/helpers": "^7.14.8", + "@babel/parser": "^7.15.0", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.15.0", + "@babel/types": "^7.15.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", + "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", + "dev": true, + "requires": { + "@babel/types": "^7.15.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz", + "integrity": "sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.14.5.tgz", + "integrity": "sha512-YTA/Twn0vBXDVGJuAX6PwW7x5zQei1luDDo2Pl6q1qZ7hVNl0RZrhHCQG/ArGpR29Vl7ETiB8eJyrvpuRp300w==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz", + "integrity": "sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.15.0", + "@babel/helper-validator-option": "^7.14.5", + "browserslist": "^4.16.6", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.0.tgz", + "integrity": "sha512-MdmDXgvTIi4heDVX/e9EFfeGpugqm9fobBVg/iioE8kueXrOHdRDe36FAY7SnE9xXLVeYCoJR/gdrBEIHRC83Q==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-member-expression-to-functions": "^7.15.0", + "@babel/helper-optimise-call-expression": "^7.14.5", + "@babel/helper-replace-supers": "^7.15.0", + "@babel/helper-split-export-declaration": "^7.14.5" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz", + "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "regexpu-core": "^4.7.1" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz", + "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.14.5.tgz", + "integrity": "sha512-Htb24gnGJdIGT4vnRKMdoXiOIlqOLmdiUYpAQ0mYfgVT/GDm8GOYhgi4GL+hMKrkiPRohO4ts34ELFsGAPQLDQ==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-function-name": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", + "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", + "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", + "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz", + "integrity": "sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==", + "dev": true, + "requires": { + "@babel/types": "^7.15.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", + "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-module-transforms": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz", + "integrity": "sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-replace-supers": "^7.15.0", + "@babel/helper-simple-access": "^7.14.8", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.9", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.15.0", + "@babel/types": "^7.15.0" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", + "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", + "dev": true + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.14.5.tgz", + "integrity": "sha512-rLQKdQU+HYlxBwQIj8dk4/0ENOUEhA/Z0l4hN8BexpvmSMN9oA9EagjnhnDpNsRdWCfjwa4mn/HyBXO9yhQP6A==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-wrap-function": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-replace-supers": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz", + "integrity": "sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.15.0", + "@babel/helper-optimise-call-expression": "^7.14.5", + "@babel/traverse": "^7.15.0", + "@babel/types": "^7.15.0" + } + }, + "@babel/helper-simple-access": { + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz", + "integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==", + "dev": true, + "requires": { + "@babel/types": "^7.14.8" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.14.5.tgz", + "integrity": "sha512-dmqZB7mrb94PZSAOYtr+ZN5qt5owZIAgqtoTuqiFbHFtxgEcmQlRJVI+bO++fciBunXtB6MK7HrzrfcAzIz2NQ==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", + "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", + "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==" + }, + "@babel/helper-validator-option": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", + "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.14.5.tgz", + "integrity": "sha512-YEdjTCq+LNuNS1WfxsDCNpgXkJaIyqco6DAelTUjT4f2KIWC1nBcaCaSdHTBqQVLnTBexBcVcFhLSU1KnYuePQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helpers": { + "version": "7.15.3", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.3.tgz", + "integrity": "sha512-HwJiz52XaS96lX+28Tnbu31VeFSQJGOeKHJeaEPQlTl7PnlhFElWPj8tUXtqFIzeN86XxXoBr+WFAyK2PPVz6g==", + "dev": true, + "requires": { + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.15.0", + "@babel/types": "^7.15.0" + } + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.15.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.3.tgz", + "integrity": "sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA==", + "dev": true + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.14.5.tgz", + "integrity": "sha512-ZoJS2XCKPBfTmL122iP6NM9dOg+d4lc9fFk3zxc8iDjvt8Pk4+TlsHSKhIPf6X+L5ORCdBzqMZDjL/WHj7WknQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5", + "@babel/plugin-proposal-optional-chaining": "^7.14.5" + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.9.tgz", + "integrity": "sha512-d1lnh+ZnKrFKwtTYdw320+sQWCTwgkB9fmUhNXRADA4akR6wLjaruSGnIEUjpt9HCOwTr4ynFTKu19b7rFRpmw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-remap-async-to-generator": "^7.14.5", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz", + "integrity": "sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.14.5.tgz", + "integrity": "sha512-KBAH5ksEnYHCegqseI5N9skTdxgJdmDoAOc0uXa+4QMYKeZD0w5IARh4FMlTNtaHhbB8v+KzMdTgxMMzsIy6Yg==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@babel/plugin-proposal-decorators": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.14.5.tgz", + "integrity": "sha512-LYz5nvQcvYeRVjui1Ykn28i+3aUiXwQ/3MGoEy0InTaz1pJo/lAzmIDXX+BQny/oufgHzJ6vnEEiXQ8KZjEVFg==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-decorators": "^7.14.5" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz", + "integrity": "sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.5.tgz", + "integrity": "sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz", + "integrity": "sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz", + "integrity": "sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz", + "integrity": "sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.5.tgz", + "integrity": "sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz", + "integrity": "sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.14.7", + "@babel/helper-compilation-targets": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.14.5" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz", + "integrity": "sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz", + "integrity": "sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.14.5.tgz", + "integrity": "sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-62EyfyA3WA0mZiF2e2IV9mc9Ghwxcg8YTu8BS4Wss4Y3PY725OmS9M0qLORbJwLqFtGh+jiE4wAmocK2CTUK2Q==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-create-class-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz", + "integrity": "sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-decorators": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.14.5.tgz", + "integrity": "sha512-c4sZMRWL4GSvP1EXy0woIP7m4jkVcEuG8R1TOZxPBPtp4FSM/kiPZub9UIs/Jrb5ZAOzvTUSGYrWsrSu1JvoPw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz", + "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz", + "integrity": "sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz", + "integrity": "sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-remap-async-to-generator": "^7.14.5" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz", + "integrity": "sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.15.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.15.3.tgz", + "integrity": "sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.9.tgz", + "integrity": "sha512-NfZpTcxU3foGWbl4wxmZ35mTsYJy8oQocbeIMoDAGGFarAmSQlL+LWMkDx/tj6pNotpbX3rltIA4dprgAPOq5A==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-optimise-call-expression": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz", + "integrity": "sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz", + "integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz", + "integrity": "sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz", + "integrity": "sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz", + "integrity": "sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.14.5.tgz", + "integrity": "sha512-CfmqxSUZzBl0rSjpoQSFoR9UEj3HzbGuGNL21/iFTmjb5gFggJp3ph0xR1YBhexmLoKRHzgxuFvty2xdSt6gTA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz", + "integrity": "sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz", + "integrity": "sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz", + "integrity": "sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz", + "integrity": "sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.0.tgz", + "integrity": "sha512-3H/R9s8cXcOGE8kgMlmjYYC9nqr5ELiPkJn4q0mypBrjhYQoc+5/Maq69vV4xRPWnkzZuwJPf5rArxpB/35Cig==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.15.0", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-simple-access": "^7.14.8", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.14.5.tgz", + "integrity": "sha512-mNMQdvBEE5DcMQaL5LbzXFMANrQjd2W7FPzg34Y4yEz7dBgdaC+9B84dSO+/1Wba98zoDbInctCDo4JGxz1VYA==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.14.5", + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.5", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.5.tgz", + "integrity": "sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.9.tgz", + "integrity": "sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.14.5" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz", + "integrity": "sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz", + "integrity": "sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.5.tgz", + "integrity": "sha512-Tl7LWdr6HUxTmzQtzuU14SqbgrSKmaR77M0OKyq4njZLQTPfOvzblNKyNkGwOfEFCEx7KeYHQHDI0P3F02IVkA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz", + "integrity": "sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz", + "integrity": "sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz", + "integrity": "sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz", + "integrity": "sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz", + "integrity": "sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz", + "integrity": "sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz", + "integrity": "sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz", + "integrity": "sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.15.0.tgz", + "integrity": "sha512-WIIEazmngMEEHDaPTx0IZY48SaAmjVWe3TRSX7cmJXn0bEv9midFzAjxiruOWYIVf5iQ10vFx7ASDpgEO08L5w==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.15.0", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-typescript": "^7.14.5" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz", + "integrity": "sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz", + "integrity": "sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/preset-env": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.15.0.tgz", + "integrity": "sha512-FhEpCNFCcWW3iZLg0L2NPE9UerdtsCR6ZcsGHUX6Om6kbCQeL5QZDqFDmeNHC6/fy6UH3jEge7K4qG5uC9In0Q==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.15.0", + "@babel/helper-compilation-targets": "^7.15.0", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-validator-option": "^7.14.5", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.14.5", + "@babel/plugin-proposal-async-generator-functions": "^7.14.9", + "@babel/plugin-proposal-class-properties": "^7.14.5", + "@babel/plugin-proposal-class-static-block": "^7.14.5", + "@babel/plugin-proposal-dynamic-import": "^7.14.5", + "@babel/plugin-proposal-export-namespace-from": "^7.14.5", + "@babel/plugin-proposal-json-strings": "^7.14.5", + "@babel/plugin-proposal-logical-assignment-operators": "^7.14.5", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5", + "@babel/plugin-proposal-numeric-separator": "^7.14.5", + "@babel/plugin-proposal-object-rest-spread": "^7.14.7", + "@babel/plugin-proposal-optional-catch-binding": "^7.14.5", + "@babel/plugin-proposal-optional-chaining": "^7.14.5", + "@babel/plugin-proposal-private-methods": "^7.14.5", + "@babel/plugin-proposal-private-property-in-object": "^7.14.5", + "@babel/plugin-proposal-unicode-property-regex": "^7.14.5", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.14.5", + "@babel/plugin-transform-async-to-generator": "^7.14.5", + "@babel/plugin-transform-block-scoped-functions": "^7.14.5", + "@babel/plugin-transform-block-scoping": "^7.14.5", + "@babel/plugin-transform-classes": "^7.14.9", + "@babel/plugin-transform-computed-properties": "^7.14.5", + "@babel/plugin-transform-destructuring": "^7.14.7", + "@babel/plugin-transform-dotall-regex": "^7.14.5", + "@babel/plugin-transform-duplicate-keys": "^7.14.5", + "@babel/plugin-transform-exponentiation-operator": "^7.14.5", + "@babel/plugin-transform-for-of": "^7.14.5", + "@babel/plugin-transform-function-name": "^7.14.5", + "@babel/plugin-transform-literals": "^7.14.5", + "@babel/plugin-transform-member-expression-literals": "^7.14.5", + "@babel/plugin-transform-modules-amd": "^7.14.5", + "@babel/plugin-transform-modules-commonjs": "^7.15.0", + "@babel/plugin-transform-modules-systemjs": "^7.14.5", + "@babel/plugin-transform-modules-umd": "^7.14.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.14.9", + "@babel/plugin-transform-new-target": "^7.14.5", + "@babel/plugin-transform-object-super": "^7.14.5", + "@babel/plugin-transform-parameters": "^7.14.5", + "@babel/plugin-transform-property-literals": "^7.14.5", + "@babel/plugin-transform-regenerator": "^7.14.5", + "@babel/plugin-transform-reserved-words": "^7.14.5", + "@babel/plugin-transform-shorthand-properties": "^7.14.5", + "@babel/plugin-transform-spread": "^7.14.6", + "@babel/plugin-transform-sticky-regex": "^7.14.5", + "@babel/plugin-transform-template-literals": "^7.14.5", + "@babel/plugin-transform-typeof-symbol": "^7.14.5", + "@babel/plugin-transform-unicode-escapes": "^7.14.5", + "@babel/plugin-transform-unicode-regex": "^7.14.5", + "@babel/preset-modules": "^0.1.4", + "@babel/types": "^7.15.0", + "babel-plugin-polyfill-corejs2": "^0.2.2", + "babel-plugin-polyfill-corejs3": "^0.2.2", + "babel-plugin-polyfill-regenerator": "^0.2.2", + "core-js-compat": "^3.16.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/preset-modules": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", + "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/preset-typescript": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.15.0.tgz", + "integrity": "sha512-lt0Y/8V3y06Wq/8H/u0WakrqciZ7Fz7mwPDHWUJAXlABL5hiUG42BNlRXiELNjeWjO5rWmnNKlx+yzJvxezHow==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-validator-option": "^7.14.5", + "@babel/plugin-transform-typescript": "^7.15.0" + } + }, + "@babel/runtime": { + "version": "7.15.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.3.tgz", + "integrity": "sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", + "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/traverse": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz", + "integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.15.0", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-hoist-variables": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/parser": "^7.15.0", + "@babel/types": "^7.15.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz", + "integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.9", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "@cnakazawa/watch": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", + "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", + "dev": true, + "requires": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + } + }, + "@elastic/elasticsearch": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@elastic/elasticsearch/-/elasticsearch-7.14.0.tgz", + "integrity": "sha512-BlxqykcNtdBxo0mF7UQ1OsUxoVOOnEaeF70u2N4jpePih9paCOOotTWfFSDrtEw0TWv1CZlzCGD3TD5+8ASx8A==", + "requires": { + "debug": "^4.3.1", + "hpagent": "^0.1.1", + "ms": "^2.1.3", + "secure-json-parse": "^2.4.0" + } + }, + "@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "13.12.1", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", + "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "@fastify/ajv-compiler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-1.1.0.tgz", + "integrity": "sha512-gvCOUNpXsWrIQ3A4aXCLIdblL0tDq42BG/2Xw7oxbil9h11uow10ztS2GuFazNBfjbrsZ5nl+nPl5jDSjj5TSg==", + "requires": { + "ajv": "^6.12.6" + } + }, + "@fastify/busboy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-1.0.0.tgz", + "integrity": "sha512-tzTXX1TFEjWCseEsNdIlXXkD+48uJoN+zpqIojUX4pSoMscsbhO/UuVEB5SzJucexqDWOo2ma0ECwdD7hZdrzg==", + "requires": { + "text-decoding": "^1.0.0" + } + }, + "@fastify/caching": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@fastify/caching/-/caching-7.0.0.tgz", + "integrity": "sha512-zMZzUmtByWKeqW8WMt0PILgGIUHLopSGjVPK2pDSPhcrdf9/B/gA4FiW4ylJVY0fhkW18awqI3z+tgUiY6mPsw==", + "requires": { + "abstract-cache": "^1.0.1", + "fastify-plugin": "^3.0.1", + "uid-safe": "^2.1.5" + }, + "dependencies": { + "fastify-plugin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.1.tgz", + "integrity": "sha512-qKcDXmuZadJqdTm6vlCqioEbyewF60b/0LOFCcYN1B6BIZGlYJumWWOYs70SFYLDAH4YqdE1cxH/RKMG7rFxgA==" + } + } + }, + "@fastify/error": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@fastify/error/-/error-2.0.0.tgz", + "integrity": "sha512-wI3fpfDT0t7p8E6dA2eTECzzOd+bZsZCJ2Hcv+Onn2b7ZwK3RwD27uW2QDaMtQhAfWQQP+WNK7nKf0twLsBf9w==" + }, + "@fastify/formbody": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@fastify/formbody/-/formbody-6.0.0.tgz", + "integrity": "sha512-YzPTXJbB3CzDMqU5K9YGSBt/nc/RDFZSxSWZ4SoqA3T2VRJzCPd7sZFpggdmlBRWhEBlvl0EWW7EX33kfbbFlg==", + "requires": { + "fastify-plugin": "^3.0.0" + }, + "dependencies": { + "fastify-plugin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.1.tgz", + "integrity": "sha512-qKcDXmuZadJqdTm6vlCqioEbyewF60b/0LOFCcYN1B6BIZGlYJumWWOYs70SFYLDAH4YqdE1cxH/RKMG7rFxgA==" + } + } + }, + "@fastify/static": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@fastify/static/-/static-5.0.1.tgz", + "integrity": "sha512-0lReUKWVOt2i5i1KoBLYsbcMBthq5eiEoUQrFceoXJkCv+OyA0iLl6hGxcmnMRxLsl/Netrzt1NNOpg4muCcuw==", + "requires": { + "content-disposition": "^0.5.3", + "encoding-negotiator": "^2.0.1", + "fastify-plugin": "^3.0.0", + "glob": "^7.1.4", + "p-limit": "^3.1.0", + "readable-stream": "^3.4.0", + "send": "^0.17.1" + }, + "dependencies": { + "fastify-plugin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.1.tgz", + "integrity": "sha512-qKcDXmuZadJqdTm6vlCqioEbyewF60b/0LOFCcYN1B6BIZGlYJumWWOYs70SFYLDAH4YqdE1cxH/RKMG7rFxgA==" + } + } + }, + "@ffprobe-installer/darwin-arm64": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/darwin-arm64/-/darwin-arm64-5.0.1.tgz", + "integrity": "sha512-vwNCNjokH8hfkbl6m95zICHwkSzhEvDC3GVBcUp5HX8+4wsX10SP3B+bGur7XUzTIZ4cQpgJmEIAx6TUwRepMg==", + "optional": true + }, + "@ffprobe-installer/darwin-x64": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/darwin-x64/-/darwin-x64-5.0.0.tgz", + "integrity": "sha512-Zl0UkZ+wW/eyMKBPLTUCcNQch2VDnZz/cBn1DXv3YtCBVbYd9aYzGj4MImdxgWcoE0+GpbfbO6mKGwMq5HCm6A==", + "optional": true + }, + "@ffprobe-installer/ffprobe": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/ffprobe/-/ffprobe-1.4.1.tgz", + "integrity": "sha512-3WJvxU0f4d7IOZdzoVCAj9fYtiQNC6E0521FJFe9iP5Ej8auTXU7TsrUzIAG1CydeQI+BnM3vGog92SCcF9KtA==", + "requires": { + "@ffprobe-installer/darwin-arm64": "5.0.1", + "@ffprobe-installer/darwin-x64": "5.0.0", + "@ffprobe-installer/linux-arm": "5.0.0", + "@ffprobe-installer/linux-arm64": "5.0.0", + "@ffprobe-installer/linux-ia32": "5.0.0", + "@ffprobe-installer/linux-x64": "5.0.0", + "@ffprobe-installer/win32-ia32": "5.0.0", + "@ffprobe-installer/win32-x64": "5.0.0" + } + }, + "@ffprobe-installer/linux-arm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/linux-arm/-/linux-arm-5.0.0.tgz", + "integrity": "sha512-mM1PPxP2UX5SUvhy0urcj5U8UolwbYgmnXA/eBWbW78k6N2Wk1COvcHYzOPs6c5yXXL6oshS2rZHU1kowigw7g==", + "optional": true + }, + "@ffprobe-installer/linux-arm64": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/linux-arm64/-/linux-arm64-5.0.0.tgz", + "integrity": "sha512-IwFbzhe1UydR849YXLPP0RMpHgHXSuPO1kznaCHcU5FscFBV5gOZLkdD8e/xrcC8g/nhKqy0xMjn5kv6KkFQlQ==", + "optional": true + }, + "@ffprobe-installer/linux-ia32": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/linux-ia32/-/linux-ia32-5.0.0.tgz", + "integrity": "sha512-c3bWlWEDMST59SAZycVh0oyc2eNS/CxxeRjoNryGRgqcZX3EJWJJQL1rAXbpQOMLMi8to1RqnmMuwPJgLLjjUA==", + "optional": true + }, + "@ffprobe-installer/linux-x64": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/linux-x64/-/linux-x64-5.0.0.tgz", + "integrity": "sha512-zgLnWJFvMGCaw1txGtz84sMEQt6mQUzdw86ih9S/kZOWnp06Gj/ams/EXxEkAxgAACCVM6/O0mkDe/6biY5tgA==", + "optional": true + }, + "@ffprobe-installer/win32-ia32": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/win32-ia32/-/win32-ia32-5.0.0.tgz", + "integrity": "sha512-NnDdAZD6ShFXzJeCkAFl2ZjAv7GcJWYudLA+0T/vjZwvskBop+sq1PGfdmVltfFDcdQiomoThRhn9Xiy9ZC71g==", + "optional": true + }, + "@ffprobe-installer/win32-x64": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/win32-x64/-/win32-x64-5.0.0.tgz", + "integrity": "sha512-P4ZMRFxVMnfMsOyTfBM/+nkTodLeOUfXNPo+X1bKEWBiZxRErqX/IHS5sLA0yAH8XmtKZcL7Cu6M26ztGcQYxw==", + "optional": true + }, + "@hapi/bourne": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.0.0.tgz", + "integrity": "sha512-WEezM1FWztfbzqIUbsDzFRVMxSoLy3HugVcux6KDDtTqzPsLE8NDRHfXvev66aH1i2oOKKar3/XDjbvh/OUBdg==", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "dev": true + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jest/console": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", + "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^26.6.2", + "jest-util": "^26.6.2", + "slash": "^3.0.0" + } + }, + "@jest/core": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", + "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", + "dev": true, + "requires": { + "@jest/console": "^26.6.2", + "@jest/reporters": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-changed-files": "^26.6.2", + "jest-config": "^26.6.3", + "jest-haste-map": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-resolve-dependencies": "^26.6.3", + "jest-runner": "^26.6.3", + "jest-runtime": "^26.6.3", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "jest-watcher": "^26.6.2", + "micromatch": "^4.0.2", + "p-each-series": "^2.1.0", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "@jest/environment": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", + "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", + "dev": true, + "requires": { + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2" + } + }, + "@jest/fake-timers": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", + "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "@sinonjs/fake-timers": "^6.0.1", + "@types/node": "*", + "jest-message-util": "^26.6.2", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2" + } + }, + "@jest/globals": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", + "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", + "dev": true, + "requires": { + "@jest/environment": "^26.6.2", + "@jest/types": "^26.6.2", + "expect": "^26.6.2" + } + }, + "@jest/reporters": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", + "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.4", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^26.6.2", + "jest-resolve": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "node-notifier": "^8.0.0", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^7.0.0" + } + }, + "@jest/source-map": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", + "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" + } + }, + "@jest/test-result": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", + "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", + "dev": true, + "requires": { + "@jest/console": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", + "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", + "dev": true, + "requires": { + "@jest/test-result": "^26.6.2", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-runner": "^26.6.3", + "jest-runtime": "^26.6.3" + } + }, + "@jest/transform": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", + "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^26.6.2", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-util": "^26.6.2", + "micromatch": "^4.0.2", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + } + }, + "@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + } + }, + "@mapbox/node-pre-gyp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz", + "integrity": "sha512-4srsKPXWlIxp5Vbqz5uLfBN+du2fJChBoYn/f2h991WLdk7jUvcSk/McVLSv/X+xQIPI8eGD5GjrnygdyHnhPA==", + "requires": { + "detect-libc": "^1.0.3", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.1", + "nopt": "^5.0.0", + "npmlog": "^4.1.2", + "rimraf": "^3.0.2", + "semver": "^7.3.4", + "tar": "^6.1.0" + }, + "dependencies": { + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + } + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@segment/loosely-validate-event": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz", + "integrity": "sha512-ZMCSfztDBqwotkl848ODgVcAmN4OItEWDCkshcKz0/W6gGSQayuuCtWV/MlodFivAZD793d6UgANd6wCXUfrIw==", + "requires": { + "component-type": "^1.2.1", + "join-component": "^1.1.0" + } + }, + "@selderee/plugin-htmlparser2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.6.0.tgz", + "integrity": "sha512-J3jpy002TyBjd4N/p6s+s90eX42H2eRhK3SbsZuvTDv977/E8p2U3zikdiehyJja66do7FlxLomZLPlvl2/xaA==", + "requires": { + "domhandler": "^4.2.0", + "selderee": "^0.6.0" + }, + "dependencies": { + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "requires": { + "domelementtype": "^2.2.0" + } + } + } + }, + "@sentry/core": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.19.7.tgz", + "integrity": "sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw==", + "requires": { + "@sentry/hub": "6.19.7", + "@sentry/minimal": "6.19.7", + "@sentry/types": "6.19.7", + "@sentry/utils": "6.19.7", + "tslib": "^1.9.3" + } + }, + "@sentry/hub": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.19.7.tgz", + "integrity": "sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA==", + "requires": { + "@sentry/types": "6.19.7", + "@sentry/utils": "6.19.7", + "tslib": "^1.9.3" + } + }, + "@sentry/minimal": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.19.7.tgz", + "integrity": "sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ==", + "requires": { + "@sentry/hub": "6.19.7", + "@sentry/types": "6.19.7", + "tslib": "^1.9.3" + } + }, + "@sentry/node": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-6.19.7.tgz", + "integrity": "sha512-gtmRC4dAXKODMpHXKfrkfvyBL3cI8y64vEi3fDD046uqYcrWdgoQsffuBbxMAizc6Ez1ia+f0Flue6p15Qaltg==", + "requires": { + "@sentry/core": "6.19.7", + "@sentry/hub": "6.19.7", + "@sentry/types": "6.19.7", + "@sentry/utils": "6.19.7", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + } + }, + "@sentry/tracing": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.19.7.tgz", + "integrity": "sha512-ol4TupNnv9Zd+bZei7B6Ygnr9N3Gp1PUrNI761QSlHtPC25xXC5ssSD3GMhBgyQrcvpuRcCFHVNNM97tN5cZiA==", + "requires": { + "@sentry/hub": "6.19.7", + "@sentry/minimal": "6.19.7", + "@sentry/types": "6.19.7", + "@sentry/utils": "6.19.7", + "tslib": "^1.9.3" + } + }, + "@sentry/types": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.19.7.tgz", + "integrity": "sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==" + }, + "@sentry/utils": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.19.7.tgz", + "integrity": "sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA==", + "requires": { + "@sentry/types": "6.19.7", + "tslib": "^1.9.3" + } + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@socket.io/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==" + }, + "@socket.io/redis-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/redis-adapter/-/redis-adapter-7.1.0.tgz", + "integrity": "sha512-vbsNJKUQgtVHcOqNL2ac8kSemTVNKHRzYPldqQJt0eFKvlAtAviuAMzBP0WmOp5OoRLQMjhVsVvgMzzMsVsK5g==", + "requires": { + "debug": "~4.3.1", + "notepack.io": "~2.2.0", + "socket.io-adapter": "~2.3.0", + "uid2": "0.0.3" + } + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "@types/amqp-connection-manager": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@types/amqp-connection-manager/-/amqp-connection-manager-2.0.12.tgz", + "integrity": "sha512-2GX1jG6ECpEXQF0X68gTTZc8MQ8GA0dM2mAd1irTpWlKzGKlGzCBtb1YnqLHozNNsoLtGI6UXSp0q06jU1LA6g==", + "dev": true, + "requires": { + "@types/amqplib": "*" + } + }, + "@types/amqplib": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@types/amqplib/-/amqplib-0.8.2.tgz", + "integrity": "sha512-p+TFLzo52f8UanB+Nq6gyUi65yecAcRY3nYowU6MPGFtaJvEDxcnFWrxssSTkF+ts1W3zyQDvgVICLQem5WxRA==", + "dev": true, + "requires": { + "@types/bluebird": "*", + "@types/node": "*" + } + }, + "@types/analytics-node": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@types/analytics-node/-/analytics-node-3.1.5.tgz", + "integrity": "sha512-zSqNpyzF3hcweslf7ttqB03iZvxtymUh820SAXaFhox5Y5Qa7bYmrdOi4IW050OHrKmtq4SE4kE1XeE1mK+zrQ==", + "dev": true + }, + "@types/babel__core": { + "version": "7.1.15", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.15.tgz", + "integrity": "sha512-bxlMKPDbY8x5h6HBwVzEOk2C8fb6SLfYQ5Jw3uBYuYF1lfWk/kbLd81la82vrIkBb0l+JdmrZaDikPrNxpS/Ew==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", + "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", + "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/bcrypt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.0.tgz", + "integrity": "sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/bluebird": { + "version": "3.5.36", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.36.tgz", + "integrity": "sha512-HBNx4lhkxN7bx6P0++W8E289foSu8kO8GCk2unhuVggO+cE7rh9DhZUyPhUxNRG9m+5B5BTKxZQ5ZP92x/mx9Q==", + "dev": true + }, + "@types/busboy": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@types/busboy/-/busboy-0.2.4.tgz", + "integrity": "sha512-f+ZCVjlcN8JW/zf3iR0GqO4gjOUlltMTtZjn+YR1mlK+MVu6esTiIecO0/GQlmYQPQLdBnc7+5vG3Xb+SkvFLw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "@types/chai": { + "version": "4.2.21", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.21.tgz", + "integrity": "sha512-yd+9qKmJxm496BOV9CMNaey8TWsikaZOwMRwPHQIjcOJM9oV+fi9ZMNw3JsVnbEEbo2gRTDnGEBv8pjyn67hNg==", + "dev": true + }, + "@types/cli-table": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@types/cli-table/-/cli-table-0.3.0.tgz", + "integrity": "sha512-QnZUISJJXyhyD6L1e5QwXDV/A5i2W1/gl6D6YMc8u0ncPepbv/B4w3S+izVvtAg60m6h+JP09+Y/0zF2mojlFQ==", + "dev": true + }, + "@types/component-emitter": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz", + "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==" + }, + "@types/config": { + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@types/config/-/config-0.0.36.tgz", + "integrity": "sha512-EoAeT1MyFWh2BJvBDEFInY714bQBbHOAucqxqqhprhbBFqr+B7fuN5T9CJqUIGDzvwubnKKRqmSo6yPo0aSpNw==", + "dev": true + }, + "@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "@types/cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", + "dev": true + }, + "@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==" + }, + "@types/eslint": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.0.tgz", + "integrity": "sha512-07XlgzX0YJUn4iG1ocY4IX9DzKSmMGUs6ESKlxWhZRaa0fatIWaHWUVapcuGa8r5HFnTqzj+4OCjd5f7EZ/i/A==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/estree": { + "version": "0.0.50", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", + "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", + "dev": true + }, + "@types/fastify-multipart": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@types/fastify-multipart/-/fastify-multipart-0.7.0.tgz", + "integrity": "sha512-dKK9S8nBesXhSfUlgyGE7mNJ5a1TxiBeIalJFdPbUj5bJywgjo3ixpm+LcIpTK2UwQ10OWptny/Kjc3GprREtg==", + "dev": true, + "requires": { + "fastify-multipart": "*" + } + }, + "@types/fastify-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@types/fastify-static/-/fastify-static-2.2.1.tgz", + "integrity": "sha512-jDE4J3nkhmBbDwopkaEmJzbGnCc1YWlkCeKPtdh9B6SuPH3RJv8SMf1Tv3nGel/RL2GUWN3tkhhFVJogqrmtMw==", + "dev": true, + "requires": { + "fastify-static": "*" + } + }, + "@types/fluent-ffmpeg": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/@types/fluent-ffmpeg/-/fluent-ffmpeg-2.1.20.tgz", + "integrity": "sha512-B+OvhCdJ3LgEq2PhvWNOiB/EfwnXLElfMCgc4Z1K5zXgSfo9I6uGKwR/lqmNPFQuebNnes7re3gqkV77SyypLg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/html-to-text": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@types/html-to-text/-/html-to-text-8.1.1.tgz", + "integrity": "sha512-QFcqfc7TiVbvIX8Fc2kWUxakruI1Ay6uitaGCYHzI5M0WHQROV5D2XeSaVrK0FmvssivXum4yERVnJsiuH61Ww==", + "dev": true + }, + "@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "26.0.24", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz", + "integrity": "sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==", + "dev": true, + "requires": { + "jest-diff": "^26.0.0", + "pretty-format": "^26.0.0" + } + }, + "@types/json-schema": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "dev": true + }, + "@types/jsonwebtoken": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.5.tgz", + "integrity": "sha512-OGqtHQ7N5/Ap/TUwO6IgHDuLiAoTmHhGpNvgkCm/F4N6pKzx/RBSfr2OXZSwC6vkfnsEdb6+7DNZVtiXiwdwFw==", + "requires": { + "@types/node": "*" + } + }, + "@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "requires": { + "@types/node": "*" + } + }, + "@types/lodash": { + "version": "4.14.172", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.172.tgz", + "integrity": "sha512-/BHF5HAx3em7/KkzVKm3LrsD6HZAXuXO1AJZQ3cRRBZj4oHZDviWPYu0aEplAqDFNHZPW6d3G7KN+ONcCCC7pw==", + "dev": true + }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, + "@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, + "@types/minio": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/minio/-/minio-7.0.9.tgz", + "integrity": "sha512-aMalbSDDB+TV9m3fVMD4E2vJR3XVAtOcf9t5Iq+PHnc5D0ti3LMXjaxGKXmllicliaBrh0gzURLrs44n/Jl43g==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/mongodb": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-4.0.7.tgz", + "integrity": "sha512-lPUYPpzA43baXqnd36cZ9xxorprybxXDzteVKCPAdp14ppHtFJHnXYvNpmBvtMUTb5fKXVv6sVbzo1LHkWhJlw==", + "dev": true, + "requires": { + "mongodb": "*" + } + }, + "@types/needle": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@types/needle/-/needle-2.5.3.tgz", + "integrity": "sha512-RwgTwMRaedfyCBe5SSWMpm1Yqzc5UPZEMw0eAd09OSyV93nLRj9/evMGZmgFeHKzUOd4xxtHvgtc+rjcBjI1Qg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "14.17.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.11.tgz", + "integrity": "sha512-n2OQ+0Bz6WEsUjrvcHD1xZ8K+Kgo4cn9/w94s1bJS690QMUWfJPW/m7CCb7gPkA1fcYwL2UpjXP/rq/Eo41m6w==" + }, + "@types/node-cron": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/node-cron/-/node-cron-3.0.0.tgz", + "integrity": "sha512-RNBIyVwa/1v2r8/SqK8tadH2sJlFRAo5Ghac/cOcCv4Kp94m0I03UmAh9WVhCqS9ZdB84dF3x47p9aTw8E4c4A==", + "dev": true + }, + "@types/node-fetch": { + "version": "2.5.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.12.tgz", + "integrity": "sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==", + "dev": true, + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "@types/node-uuid": { + "version": "0.0.28", + "resolved": "https://registry.npmjs.org/@types/node-uuid/-/node-uuid-0.0.28.tgz", + "integrity": "sha512-FOZsQldDy39ox+grtoZfGC43zLz88fBZo+YbH+ROXqrHw2stPSnOL5nMTrq4I2q+Kd8rBU2PEXMN/HO9nIrvQQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "@types/pdf-image": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/pdf-image/-/pdf-image-2.0.1.tgz", + "integrity": "sha512-WSG+F90yd53I2iA3/MiRolRmP0hT0GLkfdq2CYg1sW1AmsWK9bitc9v0EaakkMvFebESzoU/P4vsUhYnDz/OYw==", + "dev": true + }, + "@types/pino": { + "version": "6.3.11", + "resolved": "https://registry.npmjs.org/@types/pino/-/pino-6.3.11.tgz", + "integrity": "sha512-S7+fLONqSpHeW9d7TApUqO6VN47KYgOXhCNKwGBVLHObq8HhaAYlVqUNdfnvoXjCMiwE5xcPm/5R2ZUh8bgaXQ==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/pino-pretty": "*", + "@types/pino-std-serializers": "*", + "sonic-boom": "^2.1.0" + }, + "dependencies": { + "sonic-boom": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.1.0.tgz", + "integrity": "sha512-x2j9LXx27EDlyZEC32gBM+scNVMdPutU7FIKV2BOTKCnPrp7bY5BsplCMQ4shYYR3IhDSIrEXoqb6GlS+z7KyQ==", + "dev": true, + "requires": { + "atomic-sleep": "^1.0.0" + } + } + } + }, + "@types/pino-pretty": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/@types/pino-pretty/-/pino-pretty-4.7.1.tgz", + "integrity": "sha512-l1ntNXdpVWsnPYUk5HyO5Lxfr38zLCgxVfEn/9Zhhm+nGF04/BiIou/m8XPwvoVZLV+livUo79VdHXMJPfUYxA==", + "dev": true, + "requires": { + "@types/pino": "*" + } + }, + "@types/pino-std-serializers": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/pino-std-serializers/-/pino-std-serializers-2.4.1.tgz", + "integrity": "sha512-17XcksO47M24IVTVKPeAByWUd3Oez7EbIjXpSbzMPhXVzgjGtrOa49gKBwxH9hb8dKv58OelsWQ+A1G1l9S3wQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/prettier": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog==", + "dev": true + }, + "@types/probe-image-size": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/probe-image-size/-/probe-image-size-7.2.0.tgz", + "integrity": "sha512-R5H3vw62gHNHrn+JGZbKejb+Z2D/6E5UNVlhCzIaBBLroMQMOFqy5Pap2gM+ZZHdqBtVU0/cx/M6to+mOJcoew==", + "dev": true, + "requires": { + "@types/needle": "*", + "@types/node": "*" + } + }, + "@types/pump": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/pump/-/pump-1.1.1.tgz", + "integrity": "sha512-wpRerjHDxFBQ4r8XNv3xHJZeuqrBBoeQ/fhgkooV2F7KsPIYRROb/+f9ODgZfOEyO5/w2ej4YQdpPPXipT8DAA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/random-useragent": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@types/random-useragent/-/random-useragent-0.3.1.tgz", + "integrity": "sha512-yVz7897JjjwS6V+lmxlu8pktzNnNWgtF9MGxfaRfI8o+hQageO9K+0hfwr8PspdFJIIRE9KkLqp4o5tlQqv/0w==", + "dev": true + }, + "@types/redis": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@types/redis/-/redis-4.0.11.tgz", + "integrity": "sha512-bI+gth8La8Wg/QCR1+V1fhrL9+LZUSWfcqpOj2Kc80ZQ4ffbdL173vQd5wovmoV9i071FU9oP2g6etLuEwb6Rg==", + "requires": { + "redis": "*" + } + }, + "@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "requires": { + "@types/node": "*" + } + }, + "@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "@types/sharp": { + "version": "0.29.5", + "resolved": "https://registry.npmjs.org/@types/sharp/-/sharp-0.29.5.tgz", + "integrity": "sha512-3TC+S3H5RwnJmLYMHrcdfNjz/CaApKmujjY9b6PU/pE6n0qfooi99YqXGWoW8frU9EWYj/XTI35Pzxa+ThAZ5Q==", + "requires": { + "@types/node": "*" + } + }, + "@types/socket.io-client": { + "version": "1.4.36", + "resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.36.tgz", + "integrity": "sha512-ZJWjtFBeBy1kRSYpVbeGYTElf6BqPQUkXDlHHD4k/42byCN5Rh027f4yARHCink9sKAkbtGZXEAmR0ZCnc2/Ag==", + "dev": true + }, + "@types/socket.io-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/socket.io-parser/-/socket.io-parser-3.0.0.tgz", + "integrity": "sha512-Ry/rbTE6HQNL9eu3LpL1Ocup5VexXu1bSSGlSho/IR5LuRc8YvxwSNJ3JxqTltVJEATLbZkMQETSbxfKNgp4Ew==", + "requires": { + "socket.io-parser": "*" + } + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", + "dev": true + }, + "@types/strip-json-comments": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", + "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", + "dev": true + }, + "@types/superagent": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.12.tgz", + "integrity": "sha512-1GQvD6sySQPD6p9EopDFI3f5OogdICl1sU/2ij3Esobz/RtL9fWZZDPmsuv7eiy5ya+XNiPAxUcI3HIUTJa+3A==", + "dev": true, + "requires": { + "@types/cookiejar": "*", + "@types/node": "*" + } + }, + "@types/supertest": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.4.tgz", + "integrity": "sha512-0TvOJ+6XVMSImgqc2ClNllfVffCxHQhFbsbwOGzGTjdFydoaG052LPqnP8SnmSlnokOcQiPPcbz+Yi30LxWPyA==", + "dev": true, + "requires": { + "@types/superagent": "*" + } + }, + "@types/uuid": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.1.tgz", + "integrity": "sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg==", + "dev": true + }, + "@types/webidl-conversions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz", + "integrity": "sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q==" + }, + "@types/whatwg-url": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.1.tgz", + "integrity": "sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==", + "requires": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, + "@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/yargs": { + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", + "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.1.tgz", + "integrity": "sha512-cOizjPlKEh0bXdFrBLTrI/J6B/QMlhwE9auOov53tgB+qMukH6/h8YAK/qw+QJGct/PTbdh2lytGyipxCcEtAw==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.45.1", + "@typescript-eslint/type-utils": "5.45.1", + "@typescript-eslint/utils": "5.45.1", + "debug": "^4.3.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "@typescript-eslint/scope-manager": { + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.45.1.tgz", + "integrity": "sha512-D6fCileR6Iai7E35Eb4Kp+k0iW7F1wxXYrOhX/3dywsOJpJAQ20Fwgcf+P/TDtvQ7zcsWsrJaglaQWDhOMsspQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.45.1", + "@typescript-eslint/visitor-keys": "5.45.1" + } + }, + "@typescript-eslint/types": { + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.45.1.tgz", + "integrity": "sha512-HEW3U0E5dLjUT+nk7b4lLbOherS1U4ap+b9pfu2oGsW3oPu7genRaY9dDv3nMczC1rbnRY2W/D7SN05wYoGImg==", + "dev": true + }, + "@typescript-eslint/visitor-keys": { + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.45.1.tgz", + "integrity": "sha512-cy9ln+6rmthYWjH9fmx+5FU/JDpjQb586++x2FZlveq7GdGuLLW9a2Jcst2TGekH82bXpfmRNSwP9tyEs6RjvQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.45.1", + "eslint-visitor-keys": "^3.3.0" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "ignore": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/parser": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.29.3.tgz", + "integrity": "sha512-jrHOV5g2u8ROghmspKoW7pN8T/qUzk0+DITun0MELptvngtMrwUJ1tv5zMI04CYVEUsSrN4jV7AKSv+I0y0EfQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "4.29.3", + "@typescript-eslint/types": "4.29.3", + "@typescript-eslint/typescript-estree": "4.29.3", + "debug": "^4.3.1" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.29.3.tgz", + "integrity": "sha512-x+w8BLXO7iWPkG5mEy9bA1iFRnk36p/goVlYobVWHyDw69YmaH9q6eA+Fgl7kYHmFvWlebUTUfhtIg4zbbl8PA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.29.3", + "@typescript-eslint/visitor-keys": "4.29.3" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.45.1.tgz", + "integrity": "sha512-aosxFa+0CoYgYEl3aptLe1svP910DJq68nwEJzyQcrtRhC4BN0tJAvZGAe+D0tzjJmFXe+h4leSsiZhwBa2vrA==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "5.45.1", + "@typescript-eslint/utils": "5.45.1", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "dependencies": { + "@typescript-eslint/types": { + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.45.1.tgz", + "integrity": "sha512-HEW3U0E5dLjUT+nk7b4lLbOherS1U4ap+b9pfu2oGsW3oPu7genRaY9dDv3nMczC1rbnRY2W/D7SN05wYoGImg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.45.1.tgz", + "integrity": "sha512-76NZpmpCzWVrrb0XmYEpbwOz/FENBi+5W7ipVXAsG3OoFrQKJMiaqsBMbvGRyLtPotGqUfcY7Ur8j0dksDJDng==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.45.1", + "@typescript-eslint/visitor-keys": "5.45.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.45.1.tgz", + "integrity": "sha512-cy9ln+6rmthYWjH9fmx+5FU/JDpjQb586++x2FZlveq7GdGuLLW9a2Jcst2TGekH82bXpfmRNSwP9tyEs6RjvQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.45.1", + "eslint-visitor-keys": "^3.3.0" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/types": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.29.3.tgz", + "integrity": "sha512-s1eV1lKNgoIYLAl1JUba8NhULmf+jOmmeFO1G5MN/RBCyyzg4TIOfIOICVNC06lor+Xmy4FypIIhFiJXOknhIg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.3.tgz", + "integrity": "sha512-45oQJA0bxna4O5TMwz55/TpgjX1YrAPOI/rb6kPgmdnemRZx/dB0rsx+Ku8jpDvqTxcE1C/qEbVHbS3h0hflag==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.29.3", + "@typescript-eslint/visitor-keys": "4.29.3", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/utils": { + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.45.1.tgz", + "integrity": "sha512-rlbC5VZz68+yjAzQBc4I7KDYVzWG2X/OrqoZrMahYq3u8FFtmQYc+9rovo/7wlJH5kugJ+jQXV5pJMnofGmPRw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.45.1", + "@typescript-eslint/types": "5.45.1", + "@typescript-eslint/typescript-estree": "5.45.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "dependencies": { + "@typescript-eslint/scope-manager": { + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.45.1.tgz", + "integrity": "sha512-D6fCileR6Iai7E35Eb4Kp+k0iW7F1wxXYrOhX/3dywsOJpJAQ20Fwgcf+P/TDtvQ7zcsWsrJaglaQWDhOMsspQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.45.1", + "@typescript-eslint/visitor-keys": "5.45.1" + } + }, + "@typescript-eslint/types": { + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.45.1.tgz", + "integrity": "sha512-HEW3U0E5dLjUT+nk7b4lLbOherS1U4ap+b9pfu2oGsW3oPu7genRaY9dDv3nMczC1rbnRY2W/D7SN05wYoGImg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.45.1.tgz", + "integrity": "sha512-76NZpmpCzWVrrb0XmYEpbwOz/FENBi+5W7ipVXAsG3OoFrQKJMiaqsBMbvGRyLtPotGqUfcY7Ur8j0dksDJDng==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.45.1", + "@typescript-eslint/visitor-keys": "5.45.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.45.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.45.1.tgz", + "integrity": "sha512-cy9ln+6rmthYWjH9fmx+5FU/JDpjQb586++x2FZlveq7GdGuLLW9a2Jcst2TGekH82bXpfmRNSwP9tyEs6RjvQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.45.1", + "eslint-visitor-keys": "^3.3.0" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.3.tgz", + "integrity": "sha512-MGGfJvXT4asUTeVs0Q2m+sY63UsfnA+C/FDgBKV3itLBmM9H0u+URcneePtkd0at1YELmZK6HSolCqM4Fzs6yA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.29.3", + "eslint-visitor-keys": "^2.0.0" + } + }, + "@zxing/text-encoding": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", + "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", + "optional": true + }, + "abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "abstract-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/abstract-cache/-/abstract-cache-1.0.1.tgz", + "integrity": "sha512-EfUeMhRUbG5bVVbrSY/ogLlFXoyfMAPxMlSP7wrEqH53d+59r2foVy9a5KjmprLKFLOfPQCNKEfpBN/nQ76chw==", + "requires": { + "clone": "^2.1.1", + "lru_map": "^0.3.3", + "merge-options": "^1.0.0" + } + }, + "abstract-logging": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", + "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==" + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + }, + "adm-zip": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.5.tgz", + "integrity": "sha512-IWwXKnCbirdbyXSfUDvCCrmYrOHANRZcc8NcRrvTlIApdl7PwE9oGcsYvNeJPAVY1M+70b4PxXGKIf8AEuiQ6w==" + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, + "aggregate-error": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", + "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", + "dev": true, + "requires": { + "clean-stack": "^4.0.0", + "indent-string": "^5.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "amqp-connection-manager": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/amqp-connection-manager/-/amqp-connection-manager-3.7.0.tgz", + "integrity": "sha512-pWlrXVQNnSV9Jsewq6wnZjddzlHI/gZroDdmMEYfsqaAUa2V2ENCXbDdoi0r/GVesxueY/Yb8nBO024lfdtdPQ==", + "requires": { + "promise-breaker": "^5.0.0" + } + }, + "amqplib": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.8.0.tgz", + "integrity": "sha512-icU+a4kkq4Y1PS4NNi+YPDMwdlbFcZ1EZTQT2nigW3fvOb6AOgUQ9+Mk4ue0Zu5cBg/XpDzB40oH10ysrk2dmA==", + "requires": { + "bitsyntax": "~0.1.0", + "bluebird": "^3.7.2", + "buffer-more-ints": "~1.0.0", + "readable-stream": "1.x >=1.1.9", + "safe-buffer": "~5.2.1", + "url-parse": "~1.5.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" + } + } + }, + "analytics-node": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/analytics-node/-/analytics-node-5.0.0.tgz", + "integrity": "sha512-eU/lPK6V3hmmv7hnJ8762zExL7WvcpVeBL6RgGZ8yQZQewk08VbbHk0M5GAlhruyh0ZT+/IBPW3Q/SYVhjexNQ==", + "requires": { + "@segment/loosely-validate-event": "^2.0.0", + "axios": "^0.21.1", + "axios-retry": "^3.0.2", + "lodash.isstring": "^4.0.1", + "md5": "^2.2.1", + "ms": "^2.0.0", + "remove-trailing-slash": "^0.1.0", + "uuid": "^8.3.2" + } + }, + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "requires": { + "string-width": "^4.1.0" + }, + "dependencies": { + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==" + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "args": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/args/-/args-5.0.1.tgz", + "integrity": "sha512-1kqmFCFsPffavQFGt8OxJdIcETti99kySRUPMpOhaGjL6mRJn8HFU1OxKY5bMqfZKUwTQc1mZkAjmGYaVOHFtQ==", + "dev": true, + "requires": { + "camelcase": "5.0.0", + "chalk": "2.4.2", + "leven": "2.1.0", + "mri": "1.1.4" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "camelcase": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "args-js": { + "version": "0.10.12", + "resolved": "https://registry.npmjs.org/args-js/-/args-js-0.10.12.tgz", + "integrity": "sha512-tR5vYVPA1lIqK4xr8F9ysseHuqgpqHhYe7i1iCW0Vh3zGjrqL9Fti/y5McZkRga2pWOC9Z9rnLIKW1l6I6AVgw==" + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true + }, + "array-parallel": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz", + "integrity": "sha512-TDPTwSWW5E4oiFiKmz6RGJ/a80Y91GuLgUYuLd49+XBS75tYo8PNgaT2K/OxuQYqkoI852MDGBorg9OcUSTQ8w==" + }, + "array-series": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz", + "integrity": "sha512-L0XlBwfx9QetHOsbLDrE/vh2t018w9462HM3iaFfxRiK83aJjAt/Ja3NMkOW7FICwWTlQBa3ZbL5FKhuQWkDrg==" + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "dev": true + }, + "arrify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-3.0.0.tgz", + "integrity": "sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" + }, + "available-typed-arrays": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.4.tgz", + "integrity": "sha512-SA5mXJWrId1TaQjfxUYghbqQ/hYioKmLJvPJyDuYRtXXenFNMjj4hSSt1Cf1xsuXSXrtxrVC5Ot4eU6cOtBDdA==" + }, + "avvio": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/avvio/-/avvio-7.2.5.tgz", + "integrity": "sha512-AOhBxyLVdpOad3TujtC9kL/9r3HnTkxwQ5ggOsYrvvZP1cCFvzHWJd5XxZDFuTn+IN8vkKSG5SEJrd27vCSbeA==", + "requires": { + "archy": "^1.0.0", + "debug": "^4.0.0", + "fastq": "^1.6.1", + "queue-microtask": "^1.1.2" + } + }, + "axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "requires": { + "follow-redirects": "^1.14.0" + } + }, + "axios-retry": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.1.9.tgz", + "integrity": "sha512-NFCoNIHq8lYkJa6ku4m+V1837TP6lCa7n79Iuf8/AqATAHYB0ISaAS1eyIenDOfHOLtym34W65Sjke2xjg2fsA==", + "requires": { + "is-retry-allowed": "^1.1.0" + } + }, + "babel-jest": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", + "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", + "dev": true, + "requires": { + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/babel__core": "^7.1.7", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", + "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^4.0.0", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", + "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-plugin-parameter-decorator": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/babel-plugin-parameter-decorator/-/babel-plugin-parameter-decorator-1.0.16.tgz", + "integrity": "sha512-yUT2WPTUg1JaPmRGRSF557m1HJ9vdFQInRWOkiOyO5a9HhqlXffJu+fQ2xd5+qU/35ICMrrk9eWKsHCairKA9w==", + "dev": true + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz", + "integrity": "sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.2.2", + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.4.tgz", + "integrity": "sha512-z3HnJE5TY/j4EFEa/qpQMSbcUJZ5JQi+3UFjXzn6pQCmIKc5Ug5j98SuYyH+m4xQnvKlMDIW4plLfgyVnd0IcQ==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.2.2", + "core-js-compat": "^3.14.0" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz", + "integrity": "sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.2.2" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", + "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^26.6.2", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + } + } + }, + "base64-arraybuffer": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", + "integrity": "sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" + }, + "bcrypt": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz", + "integrity": "sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw==", + "requires": { + "@mapbox/node-pre-gyp": "^1.0.0", + "node-addon-api": "^3.1.0" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "bitsyntax": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bitsyntax/-/bitsyntax-0.1.0.tgz", + "integrity": "sha512-ikAdCnrloKmFOugAfxWws89/fPc+nw0OOG1IzIE72uSOg/A3cYptKCjSUhDTuj7fhsJtzkzlv7l3b8PzRHLN0Q==", + "requires": { + "buffer-more-ints": "~1.0.0", + "debug": "~2.6.9", + "safe-buffer": "~5.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "block-stream2": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/block-stream2/-/block-stream2-2.1.0.tgz", + "integrity": "sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg==", + "requires": { + "readable-stream": "^3.4.0" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "browserslist": { + "version": "4.16.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.8.tgz", + "integrity": "sha512-sc2m9ohR/49sWEbPj14ZSSZqp+kbi16aLao42Hmn3Z8FpjuMaq2xCA2l4zl9ITfyzvnvyE0hcg62YkIGKxgaNQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001251", + "colorette": "^1.3.0", + "electron-to-chromium": "^1.3.811", + "escalade": "^3.1.1", + "node-releases": "^1.1.75" + } + }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "bson": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.5.0.tgz", + "integrity": "sha512-WoSOKryfrKx0aqhPz/DJsUlrMlOL+hkW+469Q5z5E/EQWF2xilOH7h/s5HH4j9iLRzVDwKFwVNQ3Mba16srmlw==", + "requires": { + "buffer": "^5.6.0" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "buffer-more-ints": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz", + "integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==" + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==" + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", + "dev": true + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "camelcase-keys": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz", + "integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==", + "dev": true, + "requires": { + "camelcase": "^6.3.0", + "map-obj": "^4.1.0", + "quick-lru": "^5.1.1", + "type-fest": "^1.2.1" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true + } + } + }, + "caniuse-lite": { + "version": "1.0.30001327", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001327.tgz", + "integrity": "sha512-1/Cg4jlD9qjZzhbzkzEaAC2JHsP0WrOc8Rd/3a3LuajGzGWR/hD7TVyvq99VqmTy99eVh8Zkmdq213OgvgXx7w==", + "dev": true + }, + "capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "dev": true, + "requires": { + "rsvp": "^4.8.4" + } + }, + "cassandra-driver": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/cassandra-driver/-/cassandra-driver-4.6.3.tgz", + "integrity": "sha512-npW670TXjTHrdb15LUFN01wssb9vvz6SuNYcppesoKcUXx3Q29nXVhRtnvsnkG0BaSnDGvCCR4udrzYLsbh+sg==", + "requires": { + "@types/long": "^4.0.0", + "@types/node": ">=8", + "adm-zip": "^0.5.3", + "long": "^2.2.0" + } + }, + "cb2promise": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cb2promise/-/cb2promise-1.1.1.tgz", + "integrity": "sha512-ShCxBARPFJlSO+Y4pxSpbXh6y+tW54Dmy4jKf0gB1C7qUslRqWqFi80+W9416zSoj6RsqMsnKUcpkt3bOrZmDg==", + "requires": { + "mimic-fn": "~2.0.0", + "sliced": "~1.0.1" + }, + "dependencies": { + "mimic-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.0.0.tgz", + "integrity": "sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA==" + } + } + }, + "chai": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==" + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==" + }, + "cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "requires": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "dependencies": { + "parse5": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz", + "integrity": "sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==", + "requires": { + "entities": "^4.3.0" + } + } + } + }, + "cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "requires": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + } + }, + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cjs-module-lexer": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", + "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", + "dev": true + }, + "class-transformer": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.3.1.tgz", + "integrity": "sha512-cKFwohpJbuMovS8xVLmn8N2AUbAuc8pVo4zEfsUVo8qgECOogns1WVk/FkOZoxhOPTyTYFckuoH+13FO+MQ8GA==" + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + } + }, + "clean-stack": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", + "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", + "dev": true, + "requires": { + "escape-string-regexp": "5.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true + } + } + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.0.tgz", + "integrity": "sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q==" + }, + "cli-table": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.6.tgz", + "integrity": "sha512-ZkNZbnZjKERTY5NwC2SeMeLeifSPq/pubeRoTpdr3WchLlnZg6hEgvHkK5zL7KNFdd9PmHN8lxrENUwI3cE8vQ==", + "requires": { + "colors": "1.0.3" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==" + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "requires": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + }, + "dependencies": { + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorette": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.3.0.tgz", + "integrity": "sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w==", + "dev": true + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "component-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.2.1.tgz", + "integrity": "sha512-Kgy+2+Uwr75vAi6ChWXgHuLvd+QLD7ssgpaRq2zCvt80ptvAfMc/hijcJxXkBa2wMlEZcJvC2H8Ubo+A9ATHIg==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "config": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/config/-/config-3.3.6.tgz", + "integrity": "sha512-Hj5916C5HFawjYJat1epbyY2PlAgLpBtDUlr0MxGLgo3p5+7kylyvnRY18PqJHgnNWXcdd0eWDemT7eYWuFgwg==", + "requires": { + "json5": "^2.1.1" + } + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", + "dev": true + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", + "dev": true + }, + "core-js-compat": { + "version": "3.16.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.16.2.tgz", + "integrity": "sha512-4lUshXtBXsdmp8cDWh6KKiHUg40AjiuPD3bOWkNVsr1xkAhpUqCjaZ8lB1bKx9Gb5fXcbRbFJ4f4qpRIRTuJqQ==", + "dev": true, + "requires": { + "browserslist": "^4.16.7", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "cp-file": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-9.1.0.tgz", + "integrity": "sha512-3scnzFj/94eb7y4wyXRWwvzLFaQp87yyfTnChIjlfYrVqp5lVO3E2hIJMeQIltUT0K2ZAB3An1qXcBmwGyvuwA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "nested-error-stacks": "^2.0.0", + "p-event": "^4.1.0" + } + }, + "cpy": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cpy/-/cpy-9.0.1.tgz", + "integrity": "sha512-D9U0DR5FjTCN3oMTcFGktanHnAG5l020yvOCR1zKILmAyPP7I/9pl6NFgRbDcmSENtbK1sQLBz1p9HIOlroiNg==", + "dev": true, + "requires": { + "arrify": "^3.0.0", + "cp-file": "^9.1.0", + "globby": "^13.1.1", + "junk": "^4.0.0", + "micromatch": "^4.0.4", + "nested-error-stacks": "^2.1.0", + "p-filter": "^3.0.0", + "p-map": "^5.3.0" + }, + "dependencies": { + "globby": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", + "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", + "dev": true, + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "ignore": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", + "dev": true + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true + } + } + }, + "cpy-cli": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/cpy-cli/-/cpy-cli-4.2.0.tgz", + "integrity": "sha512-b04b+cbdr29CdpREPKw/itrfjO43Ty0Aj7wRM6M6LoE4GJxZJCk9Xp+Eu1IqztkKh3LxIBt1tDplENsa6KYprg==", + "dev": true, + "requires": { + "cpy": "^9.0.0", + "meow": "^10.1.2" + } + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==" + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, + "css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" + }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + } + } + }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, + "dateformat": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.5.1.tgz", + "integrity": "sha512-OD0TZ+B7yP7ZgpJf5K2DIbj3FZvFvxgFUuaqA/V5zTjAtAAXZ1E8bktHxmAGs4x5b7PflqA9LeQ84Og7wYtF7Q==", + "dev": true + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true + } + } + }, + "decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==", + "dev": true + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "requires": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + } + } + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "deep-object-diff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.0.tgz", + "integrity": "sha512-b+QLs5vHgS+IoSNcUE4n9HP2NwcHj7aqnJWsjPtuG75Rh5TOaGt0OjAYInh77d5T16V5cRDC+Pw/6ZZZiETBGw==" + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "requires": { + "clone": "^1.0.2" + }, + "dependencies": { + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + } + } + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==" + }, + "detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==" + }, + "detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==" + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "diff-sequences": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "discontinuous-range": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", + "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==" + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } + } + }, + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "requires": { + "domelementtype": "^2.3.0" + } + }, + "domutils": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", + "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "requires": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.1" + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "dynamic-dedupe": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", + "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", + "dev": true, + "requires": { + "xtend": "^4.0.0" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "electron-to-chromium": { + "version": "1.3.816", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.816.tgz", + "integrity": "sha512-/AvJPIJldO0NkwkfpUD7u1e4YEGRFBQpFuvl9oGCcVgWOObsZB1loxVGeVUJB9kmvfsBUUChPYdgRzx6+AKNyg==", + "dev": true + }, + "emittery": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", + "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", + "dev": true + }, + "emoji-name-map": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/emoji-name-map/-/emoji-name-map-1.2.9.tgz", + "integrity": "sha512-MSM8y6koSqh/2uEMI2VoKA+Ac0qL5RkgFGP/pzL6n5FOrOJ7FOZFxgs7+uNpqA+AT+WmdbMPXkd3HnFXXdz4AA==", + "requires": { + "emojilib": "^2.0.2", + "iterate-object": "^1.3.1", + "map-o": "^2.0.1" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "encoding-negotiator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/encoding-negotiator/-/encoding-negotiator-2.0.1.tgz", + "integrity": "sha512-GSK7qphNR4iPcejfAlZxKDoz3xMhnspwImK+Af5WhePS9jUpK/Oh7rUdyENWu+9rgDflOCTmAojBsgsvM8neAQ==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "engine.io": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.3.tgz", + "integrity": "sha512-rqs60YwkvWTLLnfazqgZqLa/aKo+9cueVfEi/dZ8PyGyaf8TLOxj++4QMIgeG3Gn0AhrWiFXvghsoY9L9h25GA==", + "requires": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.2.3" + }, + "dependencies": { + "engine.io-parser": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.3.tgz", + "integrity": "sha512-BtQxwF27XUNnSafQLvDi0dQ8s3i6VgzSoQMJacpIcGNrlUdfHSKbgm3jmjCVvQluGzqwujQMPAoMai3oYSTurg==", + "requires": { + "@socket.io/base64-arraybuffer": "~1.0.2" + } + }, + "ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==" + } + } + }, + "engine.io-client": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-4.1.4.tgz", + "integrity": "sha512-843fqAdKeUMFqKi1sSjnR11tJ4wi8sIefu6+JC1OzkkJBmjtc/gM/rZ53tJfu5Iae/3gApm5veoS+v+gtT0+Fg==", + "requires": { + "base64-arraybuffer": "0.1.4", + "component-emitter": "~1.3.0", + "debug": "~4.3.1", + "engine.io-parser": "~4.0.1", + "has-cors": "1.1.0", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "ws": "~7.4.2", + "xmlhttprequest-ssl": "~1.6.2", + "yeast": "0.1.2" + }, + "dependencies": { + "ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" + } + } + }, + "engine.io-parser": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-4.0.3.tgz", + "integrity": "sha512-xEAAY0msNnESNPc00e19y5heTPX4y/TJ36gr8t1voOaNmTojP9b3oK3BbJLFufW2XFPQaaijpFewm2g2Um3uqA==", + "requires": { + "base64-arraybuffer": "0.1.4" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "entities": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.3.1.tgz", + "integrity": "sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + } + } + }, + "es-abstract": { + "version": "1.18.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz", + "integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==", + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + } + } + }, + "eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "globals": { + "version": "13.12.1", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", + "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "eslint-config-prettier": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz", + "integrity": "sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + } + }, + "eslint-plugin-prettier": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz", + "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-plugin-unused-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-2.0.0.tgz", + "integrity": "sha512-3APeS/tQlTrFa167ThtP0Zm0vctjr4M44HMpeg1P4bK6wItarumq0Ma82xorMKdFsWpphQBlRPzw/pxiVELX1A==", + "dev": true, + "requires": { + "eslint-rule-composer": "^0.3.0" + } + }, + "eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "eta": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/eta/-/eta-1.12.3.tgz", + "integrity": "sha512-qHixwbDLtekO/d51Yr4glcaUJCIjGVJyTzuqV4GPlgZo1YpgOKG+avQynErZIYrfM6JIJdtiG2Kox8tbb+DoGg==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "event-stream": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==", + "dev": true, + "requires": { + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", + "pause-stream": "0.0.11", + "split": "0.3", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" + } + }, + "exec-sh": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", + "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", + "dev": true + }, + "execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + }, + "expect": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", + "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "ansi-styles": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + } + } + }, + "fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-json-stringify": { + "version": "2.7.13", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-2.7.13.tgz", + "integrity": "sha512-ar+hQ4+OIurUGjSJD1anvYSDcUflywhKjfxnsW4TBTD7+u0tJufv6DKRWoQk3vI6YBOWMoz0TQtfbe7dxbQmvA==", + "requires": { + "ajv": "^6.11.0", + "deepmerge": "^4.2.2", + "rfdc": "^1.2.0", + "string-similarity": "^4.0.1" + } + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fast-proxy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-proxy/-/fast-proxy-2.1.0.tgz", + "integrity": "sha512-ihCPWH8j4pfSIULx6evT39RzZjCkGScCVn2BRyJElDu3v96NCWjPJPX8Olnzxv30mMQUEEijonTKroqCVpXjUQ==", + "requires": { + "end-of-stream": "^1.4.4", + "pump": "^3.0.0", + "semver": "^7.3.5", + "tiny-lru": "^7.0.6", + "undici": "^3.3.6" + } + }, + "fast-redact": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.0.1.tgz", + "integrity": "sha512-kYpn4Y/valC9MdrISg47tZOpYBNoTXKgT9GYXFpHN/jYFs+lFkPoisY+LcBODdKVMY96ATzvzsWv+ES/4Kmufw==" + }, + "fast-safe-stringify": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz", + "integrity": "sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag==" + }, + "fast-xml-parser": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-3.19.0.tgz", + "integrity": "sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg==" + }, + "fastfall": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/fastfall/-/fastfall-1.5.1.tgz", + "integrity": "sha512-KH6p+Z8AKPXnmA7+Iz2Lh8ARCMr+8WNPVludm1LGkZoD2MjY6LVnRMtTKhkdzI+jr0RzQWXKzKyBJm1zoHEL4Q==", + "requires": { + "reusify": "^1.0.0" + } + }, + "fastify": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/fastify/-/fastify-3.29.4.tgz", + "integrity": "sha512-BEyKidZQvscNaiF1BLh+YLE7AzHH03NexhPzrwZP6KBQ+jG2czdgq72X+RFB5rK9hbqdaafVb5yiWN+hCvHfYg==", + "requires": { + "@fastify/ajv-compiler": "^1.0.0", + "@fastify/error": "^2.0.0", + "abstract-logging": "^2.0.0", + "avvio": "^7.1.2", + "content-type": "^1.0.4", + "fast-json-stringify": "^2.5.2", + "find-my-way": "^4.5.0", + "flatstr": "^1.0.12", + "light-my-request": "^4.2.0", + "pino": "^6.13.0", + "process-warning": "^1.0.0", + "proxy-addr": "^2.0.7", + "rfdc": "^1.1.4", + "secure-json-parse": "^2.0.0", + "semver": "^7.3.2", + "tiny-lru": "^8.0.1" + }, + "dependencies": { + "find-my-way": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-4.5.1.tgz", + "integrity": "sha512-kE0u7sGoUFbMXcOG/xpkmz4sRLCklERnBcg7Ftuu1iAxsfEt2S46RLJ3Sq7vshsEy2wJT2hZxE58XZK27qa8kg==", + "requires": { + "fast-decode-uri-component": "^1.0.1", + "fast-deep-equal": "^3.1.3", + "safe-regex2": "^2.0.0", + "semver-store": "^0.3.0" + } + }, + "tiny-lru": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-8.0.2.tgz", + "integrity": "sha512-ApGvZ6vVvTNdsmt676grvCkUCGwzG9IqXma5Z07xJgiC5L7akUMof5U8G2JTI9Rz/ovtVhJBlY6mNhEvtjzOIg==" + } + } + }, + "fastify-cors": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/fastify-cors/-/fastify-cors-4.1.0.tgz", + "integrity": "sha512-Vr4AgypDkRwG16cs1ORnYItZx6FMN+gCpHvP3/nzNZL1HFzf7U/NaSgmC784VqtK8yiqSXZEoTGCsmzeSp8JVw==", + "requires": { + "fastify-plugin": "^2.0.0", + "vary": "^1.1.2" + } + }, + "fastify-error": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/fastify-error/-/fastify-error-0.3.1.tgz", + "integrity": "sha512-oCfpcsDndgnDVgiI7bwFKAun2dO+4h84vBlkWsWnz/OUK9Reff5UFoFl241xTiLeHWX/vU9zkDVXqYUxjOwHcQ==" + }, + "fastify-formbody": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/fastify-formbody/-/fastify-formbody-5.1.0.tgz", + "integrity": "sha512-dLFQ8gMQeLuV45J72svDbrp6CZ3hxsaiK2dd3vzoiCs9wEmCSbbJV+/afQl1cfvf19+NfCIzYVQIg1r4yO4Epw==", + "requires": { + "fastify-plugin": "^3.0.0" + }, + "dependencies": { + "fastify-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.0.tgz", + "integrity": "sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w==" + } + } + }, + "fastify-jwt": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/fastify-jwt/-/fastify-jwt-2.5.0.tgz", + "integrity": "sha512-QXOSfo65OxSk30TTecLh8J0LEmuQJwRPqXMDvPA9HfLdsX/xPdq/QSvQFvR5Aj1kwrFFjsyb1SNAOQmbkmpj4w==", + "requires": { + "@types/jsonwebtoken": "^8.5.0", + "fastify-plugin": "^3.0.0", + "http-errors": "^1.8.0", + "jsonwebtoken": "^8.5.1", + "steed": "^1.1.3" + }, + "dependencies": { + "fastify-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.0.tgz", + "integrity": "sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w==" + } + } + }, + "fastify-multipart": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/fastify-multipart/-/fastify-multipart-5.3.1.tgz", + "integrity": "sha512-c2pnGfkJmiNpYqzFYT2QfBg/06AxG531O+n1elqc8YUbWPRzufdqn3yfGAIV3RA7J4Vnf7Pfvgx0iaWqaRTOVA==", + "requires": { + "@fastify/busboy": "^1.0.0", + "deepmerge": "^4.2.2", + "end-of-stream": "^1.4.4", + "fastify-error": "^0.3.0", + "fastify-plugin": "^3.0.0", + "hexoid": "^1.0.0", + "secure-json-parse": "^2.4.0", + "stream-wormhole": "^1.1.0" + }, + "dependencies": { + "fastify-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.0.tgz", + "integrity": "sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w==" + } + } + }, + "fastify-plugin": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-2.3.4.tgz", + "integrity": "sha512-I+Oaj6p9oiRozbam30sh39BiuiqBda7yK2nmSPVwDCfIBlKnT8YB3MY+pRQc2Fcd07bf6KPGklHJaQ2Qu81TYQ==", + "requires": { + "semver": "^7.3.2" + } + }, + "fastify-sensible": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fastify-sensible/-/fastify-sensible-3.0.1.tgz", + "integrity": "sha512-XVgrQySnpNq6FTUEhLLyA0i6eB7DKF6OJV05gxCDQ008cEgzOs97L/TOd1tT3fgRf3Z6tyA2zb/wMdFX5o1C2Q==", + "requires": { + "@types/node": "^14.0.1", + "fast-deep-equal": "^3.1.1", + "fastify-plugin": "^2.0.0", + "forwarded": "^0.1.2", + "http-errors": "^1.7.3", + "type-is": "^1.6.18", + "vary": "^1.1.2" + }, + "dependencies": { + "@types/node": { + "version": "14.18.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.16.tgz", + "integrity": "sha512-X3bUMdK/VmvrWdoTkz+VCn6nwKwrKCFTHtqwBIaQJNx4RUIBBUFXM00bqPz/DsDd+Icjmzm6/tyYZzeGVqb6/Q==" + } + } + }, + "fastify-socket.io": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fastify-socket.io/-/fastify-socket.io-3.0.0.tgz", + "integrity": "sha512-rVNs6NPY6ZoUQFMxZCRQreQpNyNkyKXrTbzXXzw55/grEegTW0meKBI02JAyWd2/T+k7nKB+d/7aNhYlB/Q5Bg==", + "requires": { + "fastify-plugin": "^3.0.0" + }, + "dependencies": { + "fastify-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.0.tgz", + "integrity": "sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w==" + } + } + }, + "fastify-static": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/fastify-static/-/fastify-static-4.7.0.tgz", + "integrity": "sha512-zZhCfJv/hkmud2qhWqpU3K9XVAuy3+IV8Tp9BC5J5U+GyA2XwoB6h8lh9GqpEIqdXOw01WyWQllV7dOWVyAlXg==", + "requires": { + "fastify-static-deprecated": "npm:fastify-static@4.6.1", + "process-warning": "^1.0.0" + }, + "dependencies": { + "fastify-plugin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.1.tgz", + "integrity": "sha512-qKcDXmuZadJqdTm6vlCqioEbyewF60b/0LOFCcYN1B6BIZGlYJumWWOYs70SFYLDAH4YqdE1cxH/RKMG7rFxgA==" + }, + "fastify-static-deprecated": { + "version": "npm:fastify-static@4.6.1", + "resolved": "https://registry.npmjs.org/fastify-static/-/fastify-static-4.6.1.tgz", + "integrity": "sha512-vy7N28U4AMhuOim12ZZWHulEE6OQKtzZbHgiB8Zj4llUuUQXPka0WHAQI3njm1jTCx4W6fixUHfpITxweMtAIA==", + "requires": { + "content-disposition": "^0.5.3", + "encoding-negotiator": "^2.0.1", + "fastify-plugin": "^3.0.0", + "glob": "^7.1.4", + "p-limit": "^3.1.0", + "readable-stream": "^3.4.0", + "send": "^0.17.1" + } + } + } + }, + "fastify-swagger": { + "version": "4.12.6", + "resolved": "https://registry.npmjs.org/fastify-swagger/-/fastify-swagger-4.12.6.tgz", + "integrity": "sha512-XuHyi+aPQETMsB5oOw5m8j8hror/08MSa/7Gpxon3Mu2ZtlulG8q8/XmBGB1UM0WDRifGw456IgO7kVQVPLU8A==", + "requires": { + "fastify-plugin": "^3.0.0", + "fastify-static": "^4.0.0", + "js-yaml": "^4.0.0", + "json-schema-resolver": "^1.3.0", + "openapi-types": "^9.1.0" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "fastify-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.0.tgz", + "integrity": "sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + } + } + }, + "fastify-warning": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/fastify-warning/-/fastify-warning-0.2.0.tgz", + "integrity": "sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw==" + }, + "fastify-websocket": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fastify-websocket/-/fastify-websocket-2.1.0.tgz", + "integrity": "sha512-u5zClCarOHctvzKq76Gc0rDwtWfU7pw+JGYETfSu77YzZ/uzXLDX4jB70vLliUc3nqK0zXFRDK2/KnEnfdF9Kw==", + "requires": { + "fastify-plugin": "^3.0.0", + "find-my-way": "^3.0.5", + "ws": "^7.4.2" + }, + "dependencies": { + "fastify-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.0.tgz", + "integrity": "sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w==" + }, + "find-my-way": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-3.0.5.tgz", + "integrity": "sha512-FweGg0cv1sBX8z7WhvBX5B5AECW4Zdh/NiB38Oa0qwSNIyPgRBCl/YjxuZn/rz38E/MMBHeVKJ22i7W3c626Gg==", + "requires": { + "fast-decode-uri-component": "^1.0.1", + "safe-regex2": "^2.0.0", + "semver-store": "^0.3.0" + } + } + } + }, + "fastparallel": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/fastparallel/-/fastparallel-2.4.1.tgz", + "integrity": "sha512-qUmhxPgNHmvRjZKBFUNI0oZuuH9OlSIOXmJ98lhKPxMZZ7zS/Fi0wRHOihDSz0R1YiIOjxzOY4bq65YTcdBi2Q==", + "requires": { + "reusify": "^1.0.4", + "xtend": "^4.0.2" + } + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "requires": { + "reusify": "^1.0.4" + } + }, + "fastseries": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/fastseries/-/fastseries-1.7.2.tgz", + "integrity": "sha512-dTPFrPGS8SNSzAt7u/CbMKCJ3s01N04s4JFbORHcmyvVfVKmbhMD1VtRbh5enGHxkaQDqWyLefiKOGGmohGDDQ==", + "requires": { + "reusify": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "file-type": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-7.7.1.tgz", + "integrity": "sha512-bTrKkzzZI6wH+NXhyD3SOXtb2zXTw2SbwI2RxUlRcXVsnN7jNL5hJzVQLYv7FOQhxFkK4XWdAflEaWFpaLLWpQ==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-my-way": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-5.2.0.tgz", + "integrity": "sha512-YLocRSSJJ1PCnrupBmaw2pUcFkU125QTWfFfpdLq11h7bQ+r+Ke4D1/4v7UkERlw0037VkYMd+1RMGTbhFCbPw==", + "requires": { + "fast-decode-uri-component": "^1.0.1", + "fast-deep-equal": "^3.1.3", + "safe-regex2": "^2.0.0", + "semver-store": "^0.3.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatstr": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz", + "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==" + }, + "flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "fluent-ffmpeg": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz", + "integrity": "sha512-IZTB4kq5GK0DPp7sGQ0q/BWurGHffRtQQwVkiqDgeO6wYJLLV5ZhgNOQ65loZxxuPMKZKZcICCUnaGtlxBiR0Q==", + "requires": { + "async": ">=0.2.9", + "which": "^1.1.1" + } + }, + "fold-to-ascii": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/fold-to-ascii/-/fold-to-ascii-5.0.0.tgz", + "integrity": "sha512-HjtRWXC9aVit47DOEqvorgaQDiIyeX+frV3tM22RlllposIxnPXRM/vYoE6y6pwW57RdgahSe32Cu0vf4/UX1Q==" + }, + "follow-redirects": { + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", + "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, + "form-auto-content": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/form-auto-content/-/form-auto-content-2.2.0.tgz", + "integrity": "sha512-OT4qi6hNGc+fJJGieTjy+WmV1nDhg4ULATNR0Fx92YUIy9gPw8odX3z8c+IiivWITzTg8j4TcKKbsAku8l2dwQ==", + "dev": true, + "requires": { + "form-data": "^3.0.0" + } + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "formidable": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz", + "integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==", + "dev": true + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "free-email-domains": { + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/free-email-domains/-/free-email-domains-1.0.26.tgz", + "integrity": "sha512-nEMSDa99ccSIb78AZr7OIzFk0Np/wsN/wZuXSVi1jzutDJ250tLy6ZU0hCf5wuCT03B7K+Gi+pxCkUwGfpnP/w==", + "requires": { + "got": "~11.8.5", + "json-future": "~2.2.13" + }, + "dependencies": { + "@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==" + }, + "@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "requires": { + "defer-to-connect": "^2.0.0" + } + }, + "cacheable-request": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", + "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + } + }, + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "got": { + "version": "11.8.5", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", + "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", + "requires": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + }, + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==" + }, + "p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==" + }, + "responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "requires": { + "lowercase-keys": "^2.0.0" + } + } + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", + "dev": true + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "generate-password": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/generate-password/-/generate-password-1.7.0.tgz", + "integrity": "sha512-WPCtlfy0jexf7W5IbwxGUgpIDvsZIohbI2DAq2Q6TSlKKis+G4GT9sxvPxrZUGL8kP6WUXMWNqYnxY6DDKAdFA==" + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==" + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "dev": true + }, + "get-website-favicon": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/get-website-favicon/-/get-website-favicon-0.0.7.tgz", + "integrity": "sha512-FD452CzghMhdMytp09Ax5R/IAi6835DcFsbF/kXNDa5Aep+aVN+c2kmy5wDTLPtY2Tnlh4eq1j6GgXtUGK3gYQ==", + "requires": { + "axios": "^0.18.0", + "cheerio": "^1.0.0-rc.2", + "file-type": "^7.6.0" + }, + "dependencies": { + "axios": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", + "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", + "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "dev": true, + "requires": { + "ini": "1.3.7" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "dependencies": { + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + } + } + }, + "gm": { + "version": "1.23.1", + "resolved": "https://registry.npmjs.org/gm/-/gm-1.23.1.tgz", + "integrity": "sha1-Lt7rlYCE0PjqeYjl2ZWxx9/BR3c=", + "requires": { + "array-parallel": "~0.1.3", + "array-series": "~0.1.5", + "cross-spawn": "^4.0.0", + "debug": "^3.1.0" + }, + "dependencies": { + "cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + } + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "dependencies": { + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + } + } + }, + "graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==", + "dev": true, + "optional": true + }, + "hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==" + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "hpagent": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-0.1.2.tgz", + "integrity": "sha512-ePqFXHtSQWAFXYmj+JtOTHr84iNrII4/QRlAAPPE+zqnKy4xJo7Ie1Y4kC7AdB+LxLxSTTzBMASsEcy0q8YyvQ==" + }, + "html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "html-metadata-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/html-metadata-parser/-/html-metadata-parser-2.0.4.tgz", + "integrity": "sha512-pBjST/bbe3nuy/fNmvyY4G+ypukQ/QHiGc+YnS4up2OVnT4vI0CZA4x2J0Ri77sQkQGH2IMAAug0fE78FfDrLw==", + "requires": { + "axios": "^0.24.0", + "node-html-parser": "^5.2.0" + }, + "dependencies": { + "axios": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", + "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "requires": { + "follow-redirects": "^1.14.4" + } + } + } + }, + "html-to-text": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-8.2.1.tgz", + "integrity": "sha512-aN/3JvAk8qFsWVeE9InWAWueLXrbkoVZy0TkzaGhoRBC2gCFEeRLDDJN3/ijIGHohy6H+SZzUQWN/hcYtaPK8w==", + "requires": { + "@selderee/plugin-htmlparser2": "^0.6.0", + "deepmerge": "^4.2.2", + "he": "^1.2.0", + "htmlparser2": "^6.1.0", + "minimist": "^1.2.6", + "selderee": "^0.6.0" + }, + "dependencies": { + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + } + } + }, + "htmlparser2": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", + "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "entities": "^4.3.0" + } + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "dependencies": { + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + } + } + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", + "dev": true + }, + "import-local": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" + }, + "indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==" + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + }, + "dependencies": { + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", + "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + }, + "dependencies": { + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "optional": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "dev": true, + "requires": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + } + }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==" + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" + }, + "is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-number-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==" + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "is-promise": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz", + "integrity": "sha512-mjWH5XxnhMA8cFnDchr6qRP9S/kLntKuEfIYku+PaN1CnS8v+OG9O/BKpRCVRJvpIkgAZm0Pf5Is3iSSOILlcg==" + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-retry-allowed": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.7.tgz", + "integrity": "sha512-VxlpTBGknhQ3o7YiVjIhdLU6+oD8dPz/79vvvH4F+S/c8608UCVa9fgDpa1kZgFoUST2DCgacc70UszKgzKuvA==", + "requires": { + "available-typed-arrays": "^1.0.4", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.5", + "foreach": "^2.0.5", + "has-tostringtag": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "optional": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + } + }, + "istanbul-reports": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "iterate-object": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/iterate-object/-/iterate-object-1.3.4.tgz", + "integrity": "sha512-4dG1D1x/7g8PwHS9aK6QV5V94+ZvyP4+d19qDv43EzImmrndysIl4prmJ1hWWIGCqrZHyaHBm6BSEWHOLnpoNw==" + }, + "jest": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz", + "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", + "dev": true, + "requires": { + "@jest/core": "^26.6.3", + "import-local": "^3.0.2", + "jest-cli": "^26.6.3" + } + }, + "jest-changed-files": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", + "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "execa": "^4.0.0", + "throat": "^5.0.0" + } + }, + "jest-cli": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", + "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", + "dev": true, + "requires": { + "@jest/core": "^26.6.3", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "import-local": "^3.0.2", + "is-ci": "^2.0.0", + "jest-config": "^26.6.3", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "prompts": "^2.0.1", + "yargs": "^15.4.1" + }, + "dependencies": { + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "jest-config": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", + "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^26.6.3", + "@jest/types": "^26.6.2", + "babel-jest": "^26.6.3", + "chalk": "^4.0.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "jest-environment-jsdom": "^26.6.2", + "jest-environment-node": "^26.6.2", + "jest-get-type": "^26.3.0", + "jest-jasmine2": "^26.6.3", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2" + } + }, + "jest-diff": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", + "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + } + }, + "jest-docblock": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", + "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", + "dev": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", + "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-util": "^26.6.2", + "pretty-format": "^26.6.2" + } + }, + "jest-environment-jsdom": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz", + "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", + "dev": true, + "requires": { + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2", + "jsdom": "^16.4.0" + } + }, + "jest-environment-node": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", + "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", + "dev": true, + "requires": { + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2" + } + }, + "jest-get-type": { + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", + "dev": true + }, + "jest-haste-map": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", + "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.1.2", + "graceful-fs": "^4.2.4", + "jest-regex-util": "^26.0.0", + "jest-serializer": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "micromatch": "^4.0.2", + "sane": "^4.0.3", + "walker": "^1.0.7" + } + }, + "jest-jasmine2": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", + "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^26.6.2", + "@jest/source-map": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^26.6.2", + "is-generator-fn": "^2.0.0", + "jest-each": "^26.6.2", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-runtime": "^26.6.3", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "pretty-format": "^26.6.2", + "throat": "^5.0.0" + } + }, + "jest-leak-detector": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", + "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", + "dev": true, + "requires": { + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + } + }, + "jest-matcher-utils": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", + "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + } + }, + "jest-message-util": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", + "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/types": "^26.6.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.2" + } + }, + "jest-mock": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", + "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "@types/node": "*" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true + }, + "jest-regex-util": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", + "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "dev": true + }, + "jest-resolve": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.2", + "read-pkg-up": "^7.0.1", + "resolve": "^1.18.1", + "slash": "^3.0.0" + } + }, + "jest-resolve-dependencies": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", + "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-snapshot": "^26.6.2" + } + }, + "jest-runner": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", + "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", + "dev": true, + "requires": { + "@jest/console": "^26.6.2", + "@jest/environment": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.7.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-config": "^26.6.3", + "jest-docblock": "^26.0.0", + "jest-haste-map": "^26.6.2", + "jest-leak-detector": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-resolve": "^26.6.2", + "jest-runtime": "^26.6.3", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "source-map-support": "^0.5.6", + "throat": "^5.0.0" + } + }, + "jest-runtime": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", + "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", + "dev": true, + "requires": { + "@jest/console": "^26.6.2", + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/globals": "^26.6.2", + "@jest/source-map": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0", + "cjs-module-lexer": "^0.6.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.4", + "jest-config": "^26.6.3", + "jest-haste-map": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-mock": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "slash": "^3.0.0", + "strip-bom": "^4.0.0", + "yargs": "^15.4.1" + }, + "dependencies": { + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "jest-serializer": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", + "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", + "dev": true, + "requires": { + "@types/node": "*", + "graceful-fs": "^4.2.4" + } + }, + "jest-snapshot": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", + "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0", + "@jest/types": "^26.6.2", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.0.0", + "chalk": "^4.0.0", + "expect": "^26.6.2", + "graceful-fs": "^4.2.4", + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "jest-haste-map": "^26.6.2", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-resolve": "^26.6.2", + "natural-compare": "^1.4.0", + "pretty-format": "^26.6.2", + "semver": "^7.3.2" + } + }, + "jest-util": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", + "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^2.0.0", + "micromatch": "^4.0.2" + } + }, + "jest-validate": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", + "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "camelcase": "^6.0.0", + "chalk": "^4.0.0", + "jest-get-type": "^26.3.0", + "leven": "^3.1.0", + "pretty-format": "^26.6.2" + }, + "dependencies": { + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + } + } + }, + "jest-watcher": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", + "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", + "dev": true, + "requires": { + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^26.6.2", + "string-length": "^4.0.1" + } + }, + "jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + } + }, + "jmespath": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", + "integrity": "sha512-+kHj8HXArPfpPEKGLZ+kB5ONRTCiGQXo8RQYL0hH8t6pWXUBBK5KkkQmTNOwKK4LEsd0yTsgtjJVm4UBSZea4w==", + "dev": true + }, + "join-component": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/join-component/-/join-component-1.1.0.tgz", + "integrity": "sha512-bF7vcQxbODoGK1imE2P9GS9aw4zD0Sd+Hni68IMZLj7zRnquH7dXUmMw9hDI5S/Jzt7q+IyTXN0rSg2GI0IKhQ==" + }, + "joycon": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-2.2.5.tgz", + "integrity": "sha512-YqvUxoOcVPnCp0VU1/56f+iKSdvIRJYPznH22BdXV3xMk75SFXhWeJkZ8C9XxUWt1b5x2X1SxuFygW1U0FmkEQ==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "requires": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz", + "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==", + "dev": true + } + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "json-future": { + "version": "2.2.18", + "resolved": "https://registry.npmjs.org/json-future/-/json-future-2.2.18.tgz", + "integrity": "sha512-o0tlS8WYaiUq65480fv7Rn4inT+KN+cmnXXFMa8NGvyY2drgQGcuQY08bPym1ms+mWT7fZ41F5zFW2LNRD5DAw==", + "requires": { + "args-js": "~0.10.12", + "async": "~3.2.0", + "cb2promise": "~1.1.1", + "fast-safe-stringify": "~2.1.0", + "load-json-file": "~6.2.0", + "nodeify": "~1.0.1", + "parse-json": "~5.2.0", + "sliced": "~1.0.1", + "write-json-file": "~4.3.0" + }, + "dependencies": { + "fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" + } + } + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "json-schema-resolver": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/json-schema-resolver/-/json-schema-resolver-1.3.0.tgz", + "integrity": "sha512-EX7W1r8aZ/T3j8GbbBxPXi60bnsELfT90OiA1QrbGMvwzVSbyMNOAzvMFcFb8m7gKCXZLJpGe+cJOvWgoFl29A==", + "requires": { + "debug": "^4.1.1", + "rfdc": "^1.1.4", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-stream/-/json-stream-1.0.0.tgz", + "integrity": "sha512-H/ZGY0nIAg3QcOwE1QN/rK/Fa7gJn7Ii5obwp6zyPO4xiPNwpIMjqy2gwjBEGqzkF/vSWEIBQCBuN19hYiL6Qg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "requires": { + "minimist": "^1.2.5" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "junk": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/junk/-/junk-4.0.0.tgz", + "integrity": "sha512-ojtSU++zLJ3jQG9bAYjg94w+/DOJtRyD7nPaerMFrBhmdVmiV5/exYH5t4uHga4G/95nT6hr1OJoKIFbYbrW5w==", + "dev": true + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "keyv": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", + "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", + "requires": { + "json-buffer": "3.0.1" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "requires": { + "package-json": "^6.3.0" + } + }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "dependencies": { + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + } + } + }, + "light-my-request": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-4.12.0.tgz", + "integrity": "sha512-0y+9VIfJEsPVzK5ArSIJ8Dkxp8QMP7/aCuxCUtG/tr9a2NoOf/snATE/OUc05XUplJCEnRh6gTkH7xh9POt1DQ==", + "requires": { + "ajv": "^8.1.0", + "cookie": "^0.5.0", + "process-warning": "^1.0.0", + "set-cookie-parser": "^2.4.1" + }, + "dependencies": { + "ajv": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + } + } + }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" + }, + "load-json-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz", + "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", + "requires": { + "graceful-fs": "^4.1.15", + "parse-json": "^5.0.0", + "strip-bom": "^4.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==" + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "long": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/long/-/long-2.4.0.tgz", + "integrity": "sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ==" + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==" + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "requires": { + "tmpl": "1.0.x" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true + }, + "map-o": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/map-o/-/map-o-2.0.10.tgz", + "integrity": "sha512-BxazE81fVByHWasyXhqKeo2m7bFKYu+ZbEfiuexMOnklXW+tzDvnlTi/JaklEeuuwqcqJzPaf9q+TWptSGXeLg==", + "requires": { + "iterate-object": "^1.3.0" + } + }, + "map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true + }, + "map-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "match-all": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/match-all/-/match-all-1.2.6.tgz", + "integrity": "sha512-0EESkXiTkWzrQQntBu2uzKvLu6vVkUGz40nGPbSZuegcfE5UuSzNjLaIu76zJWuaT/2I3Z/8M06OlUOZLGwLlQ==" + }, + "md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "requires": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "meow": { + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/meow/-/meow-10.1.5.tgz", + "integrity": "sha512-/d+PQ4GKmGvM9Bee/DPa8z3mXs/pkvJE2KEThngVNOqtmljC6K7NMPxtc2JeZYTmpWb9k/TmxjeL18ez3h7vCw==", + "dev": true, + "requires": { + "@types/minimist": "^1.2.2", + "camelcase-keys": "^7.0.0", + "decamelize": "^5.0.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.2", + "read-pkg-up": "^8.0.0", + "redent": "^4.0.0", + "trim-newlines": "^4.0.2", + "type-fest": "^1.2.2", + "yargs-parser": "^20.2.9" + }, + "dependencies": { + "decamelize": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz", + "integrity": "sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "requires": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "read-pkg": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-6.0.0.tgz", + "integrity": "sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^3.0.2", + "parse-json": "^5.2.0", + "type-fest": "^1.0.1" + } + }, + "read-pkg-up": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-8.0.0.tgz", + "integrity": "sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ==", + "dev": true, + "requires": { + "find-up": "^5.0.0", + "read-pkg": "^6.0.0", + "type-fest": "^1.0.1" + } + }, + "type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true + } + } + }, + "merge-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-1.0.1.tgz", + "integrity": "sha512-iuPV41VWKWBIOpBsjoxjDZw8/GbSfZ2mk7N1453bwMrfzdrIk7EzBd+8UVR6rkw67th7xnk9Dytl3J+lHPdxvg==", + "requires": { + "is-plain-obj": "^1.1" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", + "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==" + }, + "mime-types": { + "version": "2.1.32", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", + "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", + "requires": { + "mime-db": "1.49.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "dependencies": { + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "minio": { + "version": "7.0.19", + "resolved": "https://registry.npmjs.org/minio/-/minio-7.0.19.tgz", + "integrity": "sha512-DOGKauWLdmj0/y2QKXdnrhqyzRFEnUteHi6q382uujg9TjSDrA84BiQVppS2Ew6V8Rcg+2IaRkF4GR34zw9sIA==", + "requires": { + "async": "^3.1.0", + "block-stream2": "^2.0.0", + "es6-error": "^4.1.1", + "fast-xml-parser": "^3.17.5", + "json-stream": "^1.0.0", + "lodash": "^4.17.21", + "mime-types": "^2.1.14", + "mkdirp": "^0.5.1", + "querystring": "0.2.0", + "through2": "^3.0.1", + "web-encoding": "^1.1.5", + "xml": "^1.0.0", + "xml2js": "^0.4.15" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + } + } + }, + "minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "requires": { + "yallist": "^4.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, + "moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" + }, + "moment-timezone": { + "version": "0.5.33", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.33.tgz", + "integrity": "sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==", + "requires": { + "moment": ">= 2.9.0" + } + }, + "mongodb": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.1.0.tgz", + "integrity": "sha512-Gx9U9MsFWgJ3E0v4oHAdWvYTGBznNYPCkhmD/3i/kPTY/URnPfHD5/6VoKUFrdgQTK3icFiM9976hVbqCRBO9Q==", + "requires": { + "bson": "^4.4.0", + "denque": "^1.5.0", + "mongodb-connection-string-url": "^1.0.1", + "saslprep": "^1.0.0" + } + }, + "mongodb-connection-string-url": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-1.1.2.tgz", + "integrity": "sha512-mp5lv4guWuykOpkwNNqQ0tKKytuJUjL/aC/bu/DqoJVWL5NSh4j/u+gJ+EiOdweLujHyq6JZZqcTVipHhL5xRg==", + "requires": { + "@types/whatwg-url": "^8.0.0", + "whatwg-url": "^8.4.0" + } + }, + "moo": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz", + "integrity": "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==" + }, + "mri": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz", + "integrity": "sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "multistream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", + "integrity": "sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==", + "requires": { + "once": "^1.4.0", + "readable-stream": "^3.6.0" + } + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "nearley": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz", + "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==", + "requires": { + "commander": "^2.19.0", + "moo": "^0.5.0", + "railroad-diagrams": "^1.0.0", + "randexp": "0.4.6" + } + }, + "needle": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz", + "integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==", + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "nested-error-stacks": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", + "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-abi": { + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.24.0.tgz", + "integrity": "sha512-YPG3Co0luSu6GwOBsmIdGW6Wx0NyNDLg/hriIyDllVsNwnI6UeqaWShxC3lbH4LtEQUgoLP3XR1ndXiDAWvmRw==", + "requires": { + "semver": "^7.3.5" + } + }, + "node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" + }, + "node-cache": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", + "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", + "requires": { + "clone": "2.x" + } + }, + "node-cleanup": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz", + "integrity": "sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw==", + "dev": true + }, + "node-cron": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.0.tgz", + "integrity": "sha512-DDwIvvuCwrNiaU7HEivFDULcaQualDv7KoNlB/UU1wPW0n1tDEmBJKhEIE6DlF2FuoOHcNbLJ8ITL2Iv/3AWmA==", + "requires": { + "moment-timezone": "^0.5.31" + } + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, + "node-html-parser": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-5.3.3.tgz", + "integrity": "sha512-ncg1033CaX9UexbyA7e1N0aAoAYRDiV8jkTvzEnfd1GDvzFdrsXLzR4p4ik8mwLgnaKP/jyUFWDy9q3jvRT2Jw==", + "requires": { + "css-select": "^4.2.1", + "he": "1.2.0" + }, + "dependencies": { + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + } + } + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, + "node-notifier": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", + "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", + "dev": true, + "optional": true, + "requires": { + "growly": "^1.3.0", + "is-wsl": "^2.2.0", + "semver": "^7.3.2", + "shellwords": "^0.1.1", + "uuid": "^8.3.0", + "which": "^2.0.2" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "optional": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "node-releases": { + "version": "1.1.75", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz", + "integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==", + "dev": true + }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha512-TkCET/3rr9mUuRp+CpO7qfgT++aAxfDRaalQhwPFzI9BY/2rCDn6OfpZOVggi1AXfTPpfkTrg5f5WQx5G1uLxA==" + }, + "nodeify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nodeify/-/nodeify-1.0.1.tgz", + "integrity": "sha512-n7C2NyEze8GCo/z73KdbjRsBiLbv6eBn1FxwYKQ23IqGo7pQY3mhQan61Sv7eEDJCiyUjTVrVkXTzJCo1dW7Aw==", + "requires": { + "is-promise": "~1.0.0", + "promise": "~1.3.0" + } + }, + "nodemon": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz", + "integrity": "sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ==", + "dev": true, + "requires": { + "chokidar": "^3.2.2", + "debug": "^3.2.6", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.7", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.2", + "update-notifier": "^4.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "dev": true + }, + "notepack.io": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/notepack.io/-/notepack.io-2.2.0.tgz", + "integrity": "sha512-9b5w3t5VSH6ZPosoYnyDONnUTF8o0UkBw7JLA6eBlYJWyGT1Q3vQa8Hmuj1/X6RYvHjjygBDgw6fJhe0JEojfw==" + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + }, + "dependencies": { + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + } + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "requires": { + "boolbase": "^1.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + } + }, + "object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "openapi-types": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-9.2.0.tgz", + "integrity": "sha512-3x0gg8DxhpZ5MVki7AK6jmMdVIZASmVGo9CoUtD+nksLdkqz7EzWKdfS9Oxxq1J7idnZV0b3LjqcvizfKFySpQ==" + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "dependencies": { + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + } + } + }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + } + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, + "p-each-series": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", + "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", + "dev": true + }, + "p-event": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", + "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "dev": true, + "requires": { + "p-timeout": "^3.1.0" + } + }, + "p-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-3.0.0.tgz", + "integrity": "sha512-QtoWLjXAW++uTX67HZQz1dbTpqBfiidsB6VtQUC9iR85S120+s0T5sO6s+B5MLzFcZkrEd/DGMmCjR+f2Qpxwg==", + "dev": true, + "requires": { + "p-map": "^5.1.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + }, + "dependencies": { + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + } + } + }, + "p-map": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz", + "integrity": "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==", + "dev": true, + "requires": { + "aggregate-error": "^4.0.0" + } + }, + "p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "requires": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "dependencies": { + "parse5": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz", + "integrity": "sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==", + "requires": { + "entities": "^4.3.0" + } + } + } + }, + "parseley": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.7.0.tgz", + "integrity": "sha512-xyOytsdDu077M3/46Am+2cGXEKM9U9QclBDv7fimY7e+BBlxh2JcBp2mgNsmkyA9uvgyTjVzDi7cP1v4hcFxbw==", + "requires": { + "moo": "^0.5.1", + "nearley": "^2.20.1" + } + }, + "parseqs": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", + "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" + }, + "parseuri": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", + "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==" + }, + "pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", + "dev": true, + "requires": { + "through": "~2.3" + } + }, + "pdf2pic": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/pdf2pic/-/pdf2pic-2.1.4.tgz", + "integrity": "sha512-8QOCvxZlYs7wsmBQbqpIApSWD/eqgXMQU+4VM0vWrXifLgXS+Ns3484sUa1Q7ddr+gwnruq/xKHzu7x1scqX6w==", + "requires": { + "fs-extra": "^9.1.0", + "gm": "^1.23.1" + } + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "pino": { + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-6.13.1.tgz", + "integrity": "sha512-QQf67BU+cANnc/2U+wzUV20UjO5oBryWpnNyKshdLfT9BdeiXlh9wxLGmOjAuBWMYITdMs+BtJSQQNlGRNbWpA==", + "requires": { + "fast-redact": "^3.0.0", + "fast-safe-stringify": "^2.0.8", + "fastify-warning": "^0.2.0", + "flatstr": "^1.0.12", + "pino-std-serializers": "^3.1.0", + "quick-format-unescaped": "^4.0.3", + "sonic-boom": "^1.0.2" + } + }, + "pino-pretty": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-4.8.0.tgz", + "integrity": "sha512-mhQfHG4rw5ZFpWL44m0Utjo4GC2+HMfdNvxyA8lLw0sIqn6fCf7uQe6dPckUcW/obly+OQHD7B/MTso6LNizYw==", + "dev": true, + "requires": { + "@hapi/bourne": "^2.0.0", + "args": "^5.0.1", + "chalk": "^4.0.0", + "dateformat": "^4.5.1", + "fast-safe-stringify": "^2.0.7", + "jmespath": "^0.15.0", + "joycon": "^2.2.5", + "pump": "^3.0.0", + "readable-stream": "^3.6.0", + "rfdc": "^1.3.0", + "split2": "^3.1.1", + "strip-json-comments": "^3.1.1" + } + }, + "pino-std-serializers": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz", + "integrity": "sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg==" + }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", + "dev": true + }, + "prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "requires": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", + "dev": true + }, + "prettier": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + } + }, + "probe-image-size": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/probe-image-size/-/probe-image-size-7.2.3.tgz", + "integrity": "sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w==", + "requires": { + "lodash.merge": "^4.6.2", + "needle": "^2.5.2", + "stream-parser": "~0.3.1" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "process-warning": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz", + "integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-1.3.0.tgz", + "integrity": "sha512-R9WrbTF3EPkVtWjp7B7umQGVndpsi+rsDAfrR4xAALQpFLa/+2OriecLhawxzvii2gd9+DZFwROWDuUUaqS5yA==", + "requires": { + "is-promise": "~1" + } + }, + "promise-breaker": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/promise-breaker/-/promise-breaker-5.0.0.tgz", + "integrity": "sha512-mgsWQuG4kJ1dtO6e/QlNDLFtMkMzzecsC69aI5hlLEjGHFNpHrvGhFi4LiK5jg2SMQj74/diH+wZliL9LpGsyA==" + }, + "prompts": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", + "integrity": "sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "dependencies": { + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + } + } + }, + "ps-tree": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz", + "integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==", + "dev": true, + "requires": { + "event-stream": "=3.3.4" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "requires": { + "escape-goat": "^2.0.0" + } + }, + "qs": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", + "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "quick-format-unescaped": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.3.tgz", + "integrity": "sha512-MaL/oqh02mhEo5m5J2rwsVL23Iw2PEaGVHgT2vFt8AAsr0lfvQA5dpXo9TPu0rz7tSBdUPgkbam0j/fj5ZM8yg==" + }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==" + }, + "railroad-diagrams": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", + "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==" + }, + "randexp": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", + "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", + "requires": { + "discontinuous-range": "1.0.0", + "ret": "~0.1.10" + }, + "dependencies": { + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + } + } + }, + "random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==" + }, + "random-seed": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/random-seed/-/random-seed-0.3.0.tgz", + "integrity": "sha512-y13xtn3kcTlLub3HKWXxJNeC2qK4mB59evwZ5EkeRlolx+Bp2ztF7LbcZmyCnOqlHQrLnfuNbi1sVmm9lPDlDA==", + "requires": { + "json-stringify-safe": "^5.0.1" + } + }, + "random-useragent": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/random-useragent/-/random-useragent-0.5.0.tgz", + "integrity": "sha512-FUMkqVdZeoSff5tErNL3FFGYXElDWZ1bEuedhm5u9MdCFwANriJWbHvDRYrLTOzp/fBsBGu5J1cWtDgifa97aQ==", + "requires": { + "random-seed": "^0.3.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + } + } + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "redent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-4.0.0.tgz", + "integrity": "sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==", + "dev": true, + "requires": { + "indent-string": "^5.0.0", + "strip-indent": "^4.0.0" + } + }, + "redis": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/redis/-/redis-3.1.2.tgz", + "integrity": "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==", + "requires": { + "denque": "^1.5.0", + "redis-commands": "^1.7.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0" + } + }, + "redis-commands": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", + "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==" + }, + "redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==" + }, + "redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "requires": { + "redis-errors": "^1.0.0" + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "regenerator-transform": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "regexpu-core": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", + "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + } + }, + "registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "dev": true + }, + "regjsparser": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.9.tgz", + "integrity": "sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "dev": true + }, + "remove-trailing-slash": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz", + "integrity": "sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA==" + }, + "repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", + "dev": true + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", + "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "dev": true, + "requires": { + "ret": "~0.1.10" + }, + "dependencies": { + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + } + } + }, + "safe-regex2": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz", + "integrity": "sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==", + "requires": { + "ret": "~0.2.0" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "dev": true, + "requires": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + } + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + } + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, + "secure-json-parse": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.4.0.tgz", + "integrity": "sha512-Q5Z/97nbON5t/L/sH6mY2EacfjVGwrCcSi5D3btRO2GZ8pf1K1UN7Z9H5J57hjVU2Qzxr1xO+FmBhOvEkzCMmg==" + }, + "selderee": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.6.0.tgz", + "integrity": "sha512-ibqWGV5aChDvfVdqNYuaJP/HnVBhlRGSRrlbttmlMpHcLuTqqbMH36QkSs9GEgj5M88JDYLI8eyP94JaQ8xRlg==", + "requires": { + "parseley": "^0.7.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "semver-store": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/semver-store/-/semver-store-0.3.0.tgz", + "integrity": "sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg==" + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + } + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "set-cookie-parser": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz", + "integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==" + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "sharp": { + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.30.7.tgz", + "integrity": "sha512-G+MY2YW33jgflKPTXXptVO28HvNOo9G3j0MybYAHeEmby+QuD2U98dT6ueht9cv/XDqZspSpIhoSW+BAKJ7Hig==", + "requires": { + "color": "^4.2.3", + "detect-libc": "^2.0.1", + "node-addon-api": "^5.0.0", + "prebuild-install": "^7.1.1", + "semver": "^7.3.7", + "simple-get": "^4.0.1", + "tar-fs": "^2.1.1", + "tunnel-agent": "^0.6.0" + }, + "dependencies": { + "node-addon-api": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", + "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true, + "optional": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, + "simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "requires": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "requires": { + "is-arrayish": "^0.3.1" + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "sliced": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", + "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==" + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + } + }, + "socket.io": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", + "integrity": "sha512-s04vrBswdQBUmuWJuuNTmXUVJhP0cVky8bBDhdkf8y0Ptsu7fKU2LuLbts9g+pdmAdyMMn8F/9Mf1/wbtUN0fg==", + "requires": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.1.0", + "socket.io-adapter": "~2.3.3", + "socket.io-parser": "~4.0.4" + } + }, + "socket.io-adapter": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz", + "integrity": "sha512-Qd/iwn3VskrpNO60BeRyCyr8ZWw9CPZyitW4AQwmRZ8zCiyDiL+znRnWX6tDHXnWn1sJrM1+b6Mn6wEDJJ4aYQ==" + }, + "socket.io-client": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-3.1.3.tgz", + "integrity": "sha512-4sIGOGOmCg3AOgGi7EEr6ZkTZRkrXwub70bBB/F0JSkMOUFpA77WsL87o34DffQQ31PkbMUIadGOk+3tx1KGbw==", + "requires": { + "@types/component-emitter": "^1.2.10", + "backo2": "~1.0.2", + "component-emitter": "~1.3.0", + "debug": "~4.3.1", + "engine.io-client": "~4.1.0", + "parseuri": "0.0.6", + "socket.io-parser": "~4.0.4" + } + }, + "socket.io-parser": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz", + "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==", + "requires": { + "@types/component-emitter": "^1.2.10", + "component-emitter": "~1.3.0", + "debug": "~4.3.1" + } + }, + "sonic-boom": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz", + "integrity": "sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==", + "requires": { + "atomic-sleep": "^1.0.0", + "flatstr": "^1.0.12" + } + }, + "sort-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-4.2.0.tgz", + "integrity": "sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==", + "requires": { + "is-plain-obj": "^2.0.0" + }, + "dependencies": { + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "dev": true + }, + "sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "optional": true, + "requires": { + "memory-pager": "^1.0.2" + } + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz", + "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==", + "dev": true + }, + "split": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==", + "dev": true, + "requires": { + "through": "2" + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "requires": { + "readable-stream": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" + }, + "steed": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/steed/-/steed-1.1.3.tgz", + "integrity": "sha512-EUkci0FAUiE4IvGTSKcDJIQ/eRUP2JJb56+fvZ4sdnguLTqIdKjSxUe138poW8mkvKWXW2sFPrgTsxqoISnmoA==", + "requires": { + "fastfall": "^1.5.0", + "fastparallel": "^2.2.0", + "fastq": "^1.3.0", + "fastseries": "^1.7.0", + "reusify": "^1.0.0" + } + }, + "stream-combiner": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==", + "dev": true, + "requires": { + "duplexer": "~0.1.1" + } + }, + "stream-parser": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz", + "integrity": "sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==", + "requires": { + "debug": "2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "stream-wormhole": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stream-wormhole/-/stream-wormhole-1.1.0.tgz", + "integrity": "sha512-gHFfL3px0Kctd6Po0M8TzEvt3De/xu6cnRrjlfYNhwbhLPLwigI2t1nc6jrzNuaYg5C4YF78PPFuQPzRiqn9ew==" + }, + "string-argv": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.1.2.tgz", + "integrity": "sha512-mBqPGEOMNJKXRo7z0keX0wlAhbBAjilUdPW13nN0PecVryZxdHIeM7TqbsSUA7VYuS00HGC6mojP7DlQzfa9ZA==", + "dev": true + }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "string-similarity": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/string-similarity/-/string-similarity-4.0.4.tgz", + "integrity": "sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ==" + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", + "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", + "dev": true, + "requires": { + "min-indent": "^1.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "superagent": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", + "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", + "dev": true, + "requires": { + "component-emitter": "^1.2.0", + "cookiejar": "^2.1.0", + "debug": "^3.1.0", + "extend": "^3.0.0", + "form-data": "^2.3.1", + "formidable": "^1.2.0", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.3.5" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "supertest": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-4.0.2.tgz", + "integrity": "sha512-1BAbvrOZsGA3YTCWqbmh14L0YEq0EGICX/nBnfkfVJn7SrxQV1I3pMYjSzG9y/7ZU2V9dWqyqk2POwxlb09duQ==", + "dev": true, + "requires": { + "methods": "^1.1.2", + "superagent": "^3.8.3" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "table": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", + "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "tar": { + "version": "6.1.10", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.10.tgz", + "integrity": "sha512-kvvfiVvjGMxeUNB6MyYv5z7vhfFRwbwCXJAeL0/lnbrttBVqcMOnpHUf0X42LrPMR8mMpgapkJMchFH4FSHzNA==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + } + } + }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, + "term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true + }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "text-decoding": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-decoding/-/text-decoding-1.0.0.tgz", + "integrity": "sha512-/0TJD42KDnVwKmDK6jj3xP7E2MG7SHAOG4tyTgyUCRPdHwvkquYNLEQltmdMa3owq3TkddCVcTsoctJI8VQNKA==" + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } + }, + "tiny-lru": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-7.0.6.tgz", + "integrity": "sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow==" + }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "dependencies": { + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + }, + "dependencies": { + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + } + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + }, + "dependencies": { + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "requires": { + "abbrev": "1" + } + } + } + }, + "tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dev": true, + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + }, + "dependencies": { + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + } + } + }, + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "requires": { + "punycode": "^2.1.1" + } + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, + "trim-newlines": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-4.0.2.tgz", + "integrity": "sha512-GJtWyq9InR/2HRiLZgpIKv+ufIKrVrvjQWEj7PxAXNc5dwbNJkqhAUoAGgzRmULAnoOM5EIpveYd3J2VeSAIew==", + "dev": true + }, + "ts-jest": { + "version": "26.5.6", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz", + "integrity": "sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "buffer-from": "1.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^26.1.0", + "json5": "2.x", + "lodash": "4.x", + "make-error": "1.x", + "mkdirp": "1.x", + "semver": "7.x", + "yargs-parser": "20.x" + } + }, + "ts-node": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + } + }, + "ts-node-dev": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-1.1.8.tgz", + "integrity": "sha512-Q/m3vEwzYwLZKmV6/0VlFxcZzVV/xcgOt+Tx/VjaaRHyiBcFlV0541yrT09QjzzCxlDZ34OzKjrFAynlmtflEg==", + "dev": true, + "requires": { + "chokidar": "^3.5.1", + "dynamic-dedupe": "^0.3.0", + "minimist": "^1.2.5", + "mkdirp": "^1.0.4", + "resolve": "^1.0.0", + "rimraf": "^2.6.1", + "source-map-support": "^0.5.12", + "tree-kill": "^1.2.2", + "ts-node": "^9.0.0", + "tsconfig": "^7.0.0" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "tsc-watch": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/tsc-watch/-/tsc-watch-4.5.0.tgz", + "integrity": "sha512-aXhN4jY+1YEcn/NwCQ/+fHqU43EqOpW+pS+933EPsVEsrKhvyrodPDIjQsk1a1niFrabAK3RIBrRbAslVefEbQ==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "node-cleanup": "^2.1.2", + "ps-tree": "^1.2.0", + "string-argv": "^0.1.1", + "strip-ansi": "^6.0.0" + } + }, + "tsconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", + "dev": true, + "requires": { + "@types/strip-bom": "^3.0.0", + "@types/strip-json-comments": "0.0.30", + "strip-bom": "^3.0.0", + "strip-json-comments": "^2.0.0" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + } + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", + "dev": true + }, + "uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "requires": { + "random-bytes": "~1.0.0" + } + }, + "uid2": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz", + "integrity": "sha512-5gSP1liv10Gjp8cMEnFd6shzkL/D6W1uhXSFNCxDC+YI8+L8wkCYCbJ7n77Ezb4wE/xzMogecE+DtamEe9PZjg==" + }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, + "undefsafe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", + "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", + "dev": true, + "requires": { + "debug": "^2.2.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "undici": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/undici/-/undici-3.3.6.tgz", + "integrity": "sha512-/j3YTZ5AobMB4ZrTY72mzM54uFUX32v0R/JRW9G2vOyF1uSKYAx+WT8dMsAcRS13TOFISv094TxIyWYk+WEPsA==" + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, + "unoconv-promise": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/unoconv-promise/-/unoconv-promise-1.0.8.tgz", + "integrity": "sha512-YBVskYpnYj5KQS5aCnE+a+n7jFOmL9dOKzfymw5mKsZhO2K6LrBLAGzReXpOU3x77tTEeJzZYTgrhqIbtF9Acw==", + "requires": { + "chai": "^4.2.0", + "debug": "^4.1.1", + "mime": "^2.4.0" + }, + "dependencies": { + "mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==" + } + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", + "dev": true + } + } + }, + "update-notifier": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", + "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", + "dev": true, + "requires": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", + "dev": true + }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", + "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "uuid-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/uuid-time/-/uuid-time-1.0.0.tgz", + "integrity": "sha512-F0EzKK+aqt41uDutE+qukIta0CkMJ212qkIWT7uUCy0DjbyMEGpNkiLQfdByBveEt28Z/ywZU7u4CQ/a03oCaA==" + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "v8-to-istanbul": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", + "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "requires": { + "xml-name-validator": "^3.0.0" + } + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.x" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "requires": { + "defaults": "^1.0.3" + } + }, + "web-encoding": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", + "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==", + "requires": { + "@zxing/text-encoding": "0.9.0", + "util": "^0.12.3" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==" + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==", + "dev": true + }, + "which-typed-array": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.6.tgz", + "integrity": "sha512-DdY984dGD5sQ7Tf+x1CkXzdg85b9uEel6nr4UkFg1LoE9OXv3uRuZhe5CoWdawhGACeFpEZXH8fFLQnDhbpm/Q==", + "requires": { + "available-typed-arrays": "^1.0.4", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.5", + "foreach": "^2.0.5", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.6" + } + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "write-json-file": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-4.3.0.tgz", + "integrity": "sha512-PxiShnxf0IlnQuMYOPPhPkhExoCQuTUNPOa/2JWCYTmBquU9njyyDuwRKN26IZBlp4yn1nt+Agh2HOOBl+55HQ==", + "requires": { + "detect-indent": "^6.0.0", + "graceful-fs": "^4.1.15", + "is-plain-obj": "^2.0.0", + "make-dir": "^3.0.0", + "sort-keys": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" + } + } + }, + "ws": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz", + "integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==" + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true + }, + "xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==" + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "xmlhttprequest-ssl": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz", + "integrity": "sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==" + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + } + } +} \ No newline at end of file diff --git a/twake/backend/node/package.json b/twake/backend/node/package.json new file mode 100644 index 00000000..9728281f --- /dev/null +++ b/twake/backend/node/package.json @@ -0,0 +1,193 @@ +{ + "name": "@twake/twake-backend", + "version": "1.0.0", + "description": "Twake backend", + "scripts": { + "build": "npm run build:clean && npm run build:ts && npm run build:copy-assets", + "build:ts": "tsc", + "build:clean": "rimraf ./dist", + "build:copy-assets": "npm run build:copy-config && npm run build:copy-templates", + "build:copy-config": "cp -R config dist", + "build:copy-templates": "cpy src/**/*.eta dist/", + "dev": "tsc-watch --project . --noClear --outDir ./dist --onSuccess \"nodemon ./dist/server.js\" | pino-pretty", + "dev:cli": "tsc-watch --project . --noClear --outDir ./dist --onSuccess \"nodemon ./dist/cli/index.js workspace user\" | pino-pretty", + "dev:cli-dry": "tsc-watch --project . --noClear --outDir ./dist --onSuccess \"nodemon ./dist/cli/index.js console merge --dry\" | pino-pretty", + "dev:debug": "tsc-watch --project . --noClear --outDir ./dist --onSuccess \"nodemon --inspect=0.0.0.0 ./dist/server.js\" | pino-pretty", + "lint": "eslint . --ext .ts --quiet --fix", + "lint:no-fix": "eslint . --ext .ts", + "lint:prettier": "prettier --check --config .prettierrc 'src/**/*.ts'", + "serve": "node --unhandled-rejections=warn --max-http-header-size=30000 dist/server.js", + "serve:watch": "nodemon dist/server.js | pino-pretty", + "serve:debug": "nodemon --inspect dist/server.js | pino-pretty", + "start": "npm run serve", + "test": "jest --forceExit --coverage --detectOpenHandles --runInBand --verbose false | pino-pretty", + "test:local": "jest --forceExit --detectOpenHandles --runInBand mock.spec.ts", + "test:watch": "npm run test -- --watchAll --verbose false | pino-pretty", + "test:e2e": "node ./test/e2e/run-all.js", + "test:unit": "jest test/unit --forceExit --coverage --detectOpenHandles --maxWorkers=1 --testTimeout=30000 --verbose false > coverage/coverage-report.txt", + "test:unit:watch": "npm run test:unit -- --watchAll --verbose false | pino-pretty", + "test:merge:json": "npx istanbul report --dir coverage/merged --include 'coverage/**/coverage-final.json' json-summary", + "test:merge:text": "npx istanbul report --dir coverage/merged --include 'coverage/**/coverage-final.json' text > coverage/merged/coverage-report.txt", + "kill": "kill $(lsof -t -i:3000) | exit 0" + }, + "jest": { + "collectCoverage": true, + "coverageReporters": [ + "json", + "html", + "clover", + "json-summary", + "text" + ], + "verbose": true, + "testEnvironment": "node" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Twake/twake-backend.git" + }, + "author": "Twake", + "license": "ISC", + "bugs": { + "url": "https://github.com/Twake/twake-backend/issues" + }, + "homepage": "https://github.com/Twake/twake-backend#readme", + "bin": { + "twake-cli": "bin/twake-cli" + }, + "devDependencies": { + "@babel/core": "^7.11.6", + "@babel/plugin-proposal-class-properties": "^7.10.4", + "@babel/plugin-proposal-decorators": "^7.10.5", + "@babel/preset-env": "^7.11.5", + "@babel/preset-typescript": "^7.10.4", + "@types/amqp-connection-manager": "^2.0.10", + "@types/analytics-node": "^3.1.5", + "@types/archiver": "^5.3.1", + "@types/bcrypt": "^5.0.0", + "@types/busboy": "^0.2.3", + "@types/chai": "^4.2.12", + "@types/cli-table": "^0.3.0", + "@types/config": "0.0.36", + "@types/eslint": "^7.2.3", + "@types/fastify-multipart": "^0.7.0", + "@types/fastify-static": "^2.2.1", + "@types/fluent-ffmpeg": "^2.1.20", + "@types/html-to-text": "^8.1.1", + "@types/jest": "^26.0.14", + "@types/lodash": "^4.14.165", + "@types/minio": "^7.0.7", + "@types/mongodb": "^4.0.7", + "@types/node": "^14.11.2", + "@types/node-cron": "^3.0.0", + "@types/node-fetch": "^2.5.12", + "@types/node-uuid": "^0.0.28", + "@types/pdf-image": "^2.0.1", + "@types/pino": "^6.3.2", + "@types/probe-image-size": "^7.0.1", + "@types/pump": "^1.1.1", + "@types/random-useragent": "^0.3.1", + "@types/socket.io-client": "^1.4.34", + "@types/supertest": "2.0.4", + "@types/uuid": "^8.3.0", + "@types/ws": "^7.2.7", + "@typescript-eslint/eslint-plugin": "^5.0.0", + "@typescript-eslint/parser": "^4.2.0", + "babel-jest": "^26.5.2", + "babel-plugin-parameter-decorator": "^1.0.16", + "chai": "^4.2.0", + "cpy-cli": "^4.2.0", + "eslint": "^7.10.0", + "eslint-config-prettier": "^6.15.0", + "eslint-plugin-prettier": "^3.1.4", + "eslint-plugin-unused-imports": "^2.0.0", + "form-auto-content": "^2.2.0", + "jest": "^26.6.3", + "nodemon": "2.0.4", + "pino-pretty": "^4.7.1", + "prettier": "^2.1.2", + "rimraf": "^3.0.2", + "supertest": "4.0.2", + "ts-jest": "^26.4.0", + "ts-node": "^9.0.0", + "ts-node-dev": "^1.1.8", + "tsc-watch": "^4.2.9", + "typescript": "^4.0.3" + }, + "dependencies": { + "@elastic/elasticsearch": "7", + "@fastify/caching": "^7.0.0", + "@fastify/formbody": "^6.0.0", + "@fastify/static": "^5.0.1", + "@ffprobe-installer/ffprobe": "^1.4.1", + "@sentry/node": "^6.19.7", + "@sentry/tracing": "^6.19.7", + "@socket.io/redis-adapter": "^7.1.0", + "@types/pdf-parse": "^1.1.1", + "@types/redis": "^4.0.11", + "@types/sharp": "^0.29.5", + "@types/socket.io-parser": "^3.0.0", + "amqp-connection-manager": "^3.7.0", + "amqplib": "^0.8.0", + "analytics-node": "^5.0.0", + "archiver": "^5.3.1", + "axios": "^0.21.3", + "bcrypt": "^5.0.1", + "cassandra-driver": "^4.6.0", + "class-transformer": "^0.3.1", + "cli-table": "^0.3.6", + "config": "^3.3.2", + "deep-object-diff": "^1.1.0", + "emoji-name-map": "^1.2.9", + "eta": "^1.12.3", + "fast-proxy": "^2.1.0", + "fastify": "^3.29.4", + "fastify-cors": "^4.1.0", + "fastify-formbody": "^5.0.0", + "fastify-jwt": "^2.2.0", + "fastify-multipart": "5.3.1", + "fastify-plugin": "^2.3.4", + "fastify-sensible": "=3.0.1", + "fastify-socket.io": "^3.0.0", + "fastify-static": "^4.7.0", + "fastify-swagger": "^4.12.6", + "fastify-websocket": "^2.0.11", + "find-my-way": "^5.2.0", + "fluent-ffmpeg": "^2.1.2", + "fold-to-ascii": "^5.0.0", + "free-email-domains": "1.0.26", + "generate-password": "^1.6.0", + "get-website-favicon": "^0.0.7", + "html-metadata-parser": "^2.0.4", + "html-to-text": "^8.2.1", + "jsonwebtoken": "^8.5.1", + "keyv": "^4.5.0", + "lodash": "^4.17.21", + "match-all": "^1.2.6", + "minio": "^7.0.18", + "moment": "^2.29.4", + "mongodb": "^4.1.0", + "multistream": "^4.1.0", + "node-cache": "^5.1.2", + "node-cron": "^3.0.0", + "node-fetch": "^2.6.7", + "node-uuid": "^1.4.8", + "ora": "^5.4.0", + "pdf-parse": "^1.1.1", + "pdf2pic": "^2.1.4", + "pino": "^6.8.0", + "probe-image-size": "^7.2.3", + "pump": "^3.0.0", + "random-useragent": "^0.5.0", + "redis": "3", + "reflect-metadata": "^0.1.13", + "rxjs": "^6.6.3", + "sharp": "^0.30.5", + "socket.io": "4", + "socket.io-client": "^3.0.0", + "unoconv-promise": "^1.0.8", + "uuid": "^8.3.2", + "uuid-time": "^1.0.0", + "yargs": "^16.2.0" + } +} diff --git a/twake/backend/node/public/index.html b/twake/backend/node/public/index.html new file mode 100644 index 00000000..f2d2dbd4 --- /dev/null +++ b/twake/backend/node/public/index.html @@ -0,0 +1,4 @@ +Twake frontend is not here, please do one of the following:<br/> +- use the nginx container as a separate process<br/> +- attach the built frontend to this container and use the STATIC_ROOT env variable<br/> +- use the production container \ No newline at end of file diff --git a/twake/backend/node/src/@types/emoji-name-map.ts b/twake/backend/node/src/@types/emoji-name-map.ts new file mode 100644 index 00000000..163b9707 --- /dev/null +++ b/twake/backend/node/src/@types/emoji-name-map.ts @@ -0,0 +1 @@ +declare module "emoji-name-map"; diff --git a/twake/backend/node/src/@types/fastify.ts b/twake/backend/node/src/@types/fastify.ts new file mode 100644 index 00000000..f30ed5f0 --- /dev/null +++ b/twake/backend/node/src/@types/fastify.ts @@ -0,0 +1,21 @@ +import { FastifyReply, FastifyRequest } from "fastify"; +import SocketIO from "socket.io"; +import { User } from "../utils/types"; + +export interface authenticateDecorator { + (request: FastifyRequest): FastifyRequest; + (reply: FastifyReply): FastifyReply; +} + +declare module "fastify" { + interface FastifyInstance { + phpnodeAuthenticate(): void; + authenticate(): void; + authenticateOptional(): void; + io: SocketIO.Server; + } + + interface FastifyRequest { + currentUser: User; + } +} diff --git a/twake/backend/node/src/@types/free-email-domains.ts b/twake/backend/node/src/@types/free-email-domains.ts new file mode 100644 index 00000000..a25d0bf4 --- /dev/null +++ b/twake/backend/node/src/@types/free-email-domains.ts @@ -0,0 +1 @@ +declare module "free-email-domains"; diff --git a/twake/backend/node/src/@types/get-website-favicon.ts b/twake/backend/node/src/@types/get-website-favicon.ts new file mode 100644 index 00000000..0e02735f --- /dev/null +++ b/twake/backend/node/src/@types/get-website-favicon.ts @@ -0,0 +1 @@ +declare module "get-website-favicon"; diff --git a/twake/backend/node/src/@types/multistream.ts b/twake/backend/node/src/@types/multistream.ts new file mode 100644 index 00000000..2951c3c7 --- /dev/null +++ b/twake/backend/node/src/@types/multistream.ts @@ -0,0 +1 @@ +declare module "multistream"; diff --git a/twake/backend/node/src/@types/unoconv.ts b/twake/backend/node/src/@types/unoconv.ts new file mode 100644 index 00000000..a997b12b --- /dev/null +++ b/twake/backend/node/src/@types/unoconv.ts @@ -0,0 +1 @@ +declare module "unoconv-promise"; diff --git a/twake/backend/node/src/@types/uuid-time.ts b/twake/backend/node/src/@types/uuid-time.ts new file mode 100644 index 00000000..88eb050d --- /dev/null +++ b/twake/backend/node/src/@types/uuid-time.ts @@ -0,0 +1 @@ +declare module "uuid-time"; diff --git a/twake/backend/node/src/cli/cmds/applications.ts b/twake/backend/node/src/cli/cmds/applications.ts new file mode 100644 index 00000000..e7acd332 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/applications.ts @@ -0,0 +1,14 @@ +import { CommandModule } from "yargs"; + +const command: CommandModule = { + describe: "Manage Twake Applications", + command: "applications <command>", + builder: yargs => + yargs.commandDir("applications_cmds", { + visit: commandModule => commandModule.default, + }), + // eslint-disable-next-line @typescript-eslint/no-empty-function + handler: () => {}, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/applications_cmds/ls.ts b/twake/backend/node/src/cli/cmds/applications_cmds/ls.ts new file mode 100644 index 00000000..25341c51 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/applications_cmds/ls.ts @@ -0,0 +1,54 @@ +import yargs from "yargs"; +import ora from "ora"; +import twake from "../../../twake"; +import Table from "cli-table"; +import * as process from "process"; +import gr from "../../../services/global-resolver"; + +/** + * Merge command parameters. Check the builder definition below for more details. + */ +type CLIArgs = Record<string, unknown>; + +const services = [ + "storage", + "counter", + "message-queue", + "platform-services", + "applications", + "auth", + "realtime", + "websocket", + // "user", + "search", + "database", + "webserver", + // "statistics", +]; + +const command: yargs.CommandModule<unknown, CLIArgs> = { + command: "ls", + describe: "command that allow you to list applications (unpublished only)", + + handler: async _argv => { + const spinner = ora({ text: "Retrieving applications" }).start(); + const platform = await twake.run(services); + await gr.doInit(platform); + // + const unpublished = await gr.services.applications.marketplaceApps.listUnpublished(undefined); + // + const table = new Table({ + head: ["ID", "Name", "Description"], + colWidths: [40, 20, 40], + }); + unpublished.forEach((app: any) => { + table.push([app.id, app.identity.name, app.identity.description]); + }); + spinner.stop(); + console.log(table.toString()); + await platform.stop(); + process.exit(0); + }, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/applications_cmds/publish.ts b/twake/backend/node/src/cli/cmds/applications_cmds/publish.ts new file mode 100644 index 00000000..18d88fc3 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/applications_cmds/publish.ts @@ -0,0 +1,89 @@ +import yargs from "yargs"; +import ora from "ora"; +import twake from "../../../twake"; +import Table from "cli-table"; +import * as process from "process"; +import gr from "../../../services/global-resolver"; +/** + * Merge command parameters. Check the builder definition below for more details. + */ +type CLIArgs = { + id: string; +}; + +const services = [ + "storage", + "counter", + "message-queue", + "platform-services", + "applications", + "auth", + "realtime", + "websocket", + "user", + "search", + "database", + "webserver", + "statistics", +]; + +const command: yargs.CommandModule<unknown, CLIArgs> = { + command: "publish <id>", + describe: + "command that allow you to validate an application and make it available on the marketplace", + builder: { + force: { + default: false, + type: "boolean", + description: "Force update unrequested application", + }, + }, + handler: async argv => { + if (argv.id) { + let spinner = ora({ text: "Retrieving application" }).start(); + const platform = await twake.run(services); + await gr.doInit(platform); + let app = await gr.services.applications.marketplaceApps.get({ id: argv.id }, undefined); + spinner.stop(); + if (!app) { + console.error(`Application ${argv.id} not found`); + process.exit(1); + } + let table = new Table(); + table.push(app); + table.push({ name: app.identity.name }); + table.push({ description: app.identity.description }); + table.push({ website: app.identity.website }); + table.push({ requested: app.publication.requested }); + table.push({ published: app.publication.published }); + console.log(table.toString()); + + if (app.publication.published) { + console.error("Application already published"); + process.exit(1); + } + + if (!app.publication.requested && !argv.force) { + console.error( + "Application is not requested to be published. Use --force if you want to publish it anyway", + ); + process.exit(1); + } + + spinner = ora({ text: "Publishing application" }).start(); + await gr.services.applications.marketplaceApps.publish({ id: argv.id }, undefined); + app = await gr.services.applications.marketplaceApps.get({ id: argv.id }, undefined); + + spinner.stop(); + console.log("Application published"); + + table = new Table(); + table.push(app); + table.push({ published: app.publication.published }); + console.log(table.toString()); + } + process.exit(0); + }, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/applications_cmds/unpublish.ts b/twake/backend/node/src/cli/cmds/applications_cmds/unpublish.ts new file mode 100644 index 00000000..2e8b927c --- /dev/null +++ b/twake/backend/node/src/cli/cmds/applications_cmds/unpublish.ts @@ -0,0 +1,73 @@ +import yargs from "yargs"; +import ora from "ora"; +import twake from "../../../twake"; +import Table from "cli-table"; +import * as process from "process"; +import gr from "../../../services/global-resolver"; +/** + * Merge command parameters. Check the builder definition below for more details. + */ +type CLIArgs = { + id: string; +}; + +const services = [ + "storage", + "counter", + "message-queue", + "platform-services", + "applications", + "auth", + "realtime", + "websocket", + "user", + "search", + "database", + "webserver", + "statistics", +]; + +const command: yargs.CommandModule<unknown, CLIArgs> = { + command: "unpublish <id>", + describe: "command that allow you to make application unavailable on the marketplace", + handler: async argv => { + if (argv.id) { + let spinner = ora({ text: "Retrieving application" }).start(); + const platform = await twake.run(services); + await gr.doInit(platform); + let app = await gr.services.applications.marketplaceApps.get({ id: argv.id }, undefined); + spinner.stop(); + if (!app) { + console.error(`Application ${argv.id} not found`); + process.exit(1); + } + let table = new Table(); + table.push(app); + table.push({ name: app.identity.name }); + table.push({ description: app.identity.description }); + table.push({ website: app.identity.website }); + table.push({ requested: app.publication.requested }); + table.push({ published: app.publication.published }); + console.log(table.toString()); + + if (!app.publication.published) { + console.error("Application is not published"); + process.exit(1); + } + + spinner = ora({ text: "Unpublishing application" }).start(); + await gr.services.applications.marketplaceApps.unpublish({ id: argv.id }, undefined); + app = await gr.services.applications.marketplaceApps.get({ id: argv.id }, undefined); + spinner.stop(); + console.log("Application unpublished"); + + table = new Table(); + table.push(app); + table.push({ published: app.publication.published }); + console.log(table.toString()); + } + process.exit(0); + }, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/console.ts b/twake/backend/node/src/cli/cmds/console.ts new file mode 100644 index 00000000..a1d1eee4 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/console.ts @@ -0,0 +1,14 @@ +import { CommandModule } from "yargs"; + +const command: CommandModule = { + describe: "Manage Twake Console", + command: "console <command>", + builder: yargs => + yargs.commandDir("console_cmds", { + visit: commandModule => commandModule.default, + }), + // eslint-disable-next-line @typescript-eslint/no-empty-function + handler: () => {}, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/console_cmds/merge.ts b/twake/backend/node/src/cli/cmds/console_cmds/merge.ts new file mode 100644 index 00000000..c6e093e5 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/console_cmds/merge.ts @@ -0,0 +1,257 @@ +import yargs from "yargs"; +import ora from "ora"; +import twake from "../../../twake"; +import { CompanyReport, UserReport } from "../../../services/console/types"; +import Company from "../../../services/user/entities/company"; +import gr from "../../../services/global-resolver"; +import { ConsoleServiceImpl } from "../../../services/console/service"; + +/** + * Merge command parameters. Check the builder definition below for more details. + */ +type MergeParams = { + url: string; + concurrent: number; + dry: boolean; + console: string; + link: boolean; + csv: boolean; + client: string; + secret: string; +}; + +const services = [ + "platform-services", + "user", + "channels", + "notifications", + "database", + "webserver", + "message-queue", + "console", +]; + +const command: yargs.CommandModule<MergeParams, MergeParams> = { + command: "merge", + describe: "Merge Twake Chat users in the Twake Console", + builder: { + url: { + default: "http://localhost:8080", + type: "string", + description: "URL of the Twake console", + }, + concurrent: { + default: 1, + type: "number", + description: "Number of concurrent imports", + }, + dry: { + default: false, + type: "boolean", + description: "Make a dry run without creating anything on the Twake console", + }, + csv: { + default: false, + type: "boolean", + description: "Generate result as CSV", + }, + console: { + default: "console", + type: "string", + description: "The console service identifier to user to link user and companies", + }, + link: { + default: true, + type: "boolean", + description: + "Link the companies/users to external companies/user. Works with the --console parameter", + implies: "console", + }, + client: { + default: "twake", + type: "string", + description: "Client identifier to be used to authenticate calls to the Console", + }, + secret: { + default: "secret", + type: "string", + description: "Client secret to be used to authenticate calls to the Console", + }, + }, + handler: async argv => { + const spinner = ora({ text: `Importing Twake data on ${argv.url}` }).start(); + const platform = await twake.run(services); + await gr.doInit(platform); + const consoleService = platform.getProvider<ConsoleServiceImpl>("console"); + const merge = consoleService.merge( + argv.url, + argv.concurrent, + argv.dry, + argv.console, + argv.link, + argv.client, + argv.secret, + ); + const start = Date.now(); + let stop: number = start; + const userReports: UserReport[] = []; + const companyReports: CompanyReport[] = []; + const ownerReports: UserReport[] = []; + let companiesWithoutAdmin: Company[] = []; + + const process = merge.subscribe({ + next: report => { + if (report.type === "company:created") { + const companyReport = report.data as CompanyReport; + companyReports.push(companyReport); + + if (companyReport.status === "success") { + spinner.succeed( + `Company created: ${companyReport.company.source.id} ${companyReport.company.source.displayName}`, + ); + } else { + spinner.fail( + `Creation error for company ${companyReport.company.source.id} (${companyReport.company.source.displayName}): ${companyReport?.error?.message}`, + ); + } + } + + if (report.type === "user:created") { + const userReport = report.data as UserReport; + userReports.push(userReport); + + if (userReport.status === "success") { + spinner.succeed( + `Company ${userReport.user.source.company.id}: User created ${userReport.user.destination.id}`, + ); + } else { + spinner.fail( + `Company ${userReport.user.source.company.id}: User creation error ${userReport.user.destination.id}: ${userReport?.error?.message}`, + ); + } + } + + if (report.type === "user:updated") { + const userReport = report.data as UserReport; + ownerReports.push(userReport); + if (userReport.status === "success") { + spinner.succeed( + `Company ${userReport.destinationCompanyCode} owner updated to user ${userReport.destinationId}`, + ); + } else { + spinner.fail( + `Company ${userReport.destinationCompanyCode}: Owner update error for user ${userReport.destinationId}: ${userReport?.error?.message}`, + ); + } + } + + if (report.type === "processing:owner") { + spinner.start("Computing company owners, please wait..."); + } + + if (report.type === "user:updating") { + //spinner.succeed(`Updating owner for company ${report?.company?.sourceId}`); + } + + if (report.type === "log") { + report.message && (spinner.text = report.message); + } + + if (report.type === "company:withoutadmin") { + report.message && (spinner.text = report.message); + const companies = (report.data || []) as Company[]; + + if (companies.length) { + companiesWithoutAdmin = companies; + } + } + }, + error: () => { + spinner.fail("Fatal error"); + }, + complete: async () => { + stop = Date.now(); + spinner.succeed("Merge is complete"); + displayStats(); + await tearDown(); + }, + }); + + async function tearDown() { + await platform.stop(); + process.unsubscribe(); + } + + function reportAsCSV() { + const users = userReports.map( + user => + `${user.sourceId},${user.destinationId},${user.destinationCompanyCode},${user.status}`, + ); + const userCSV = [...["sourceId,destinationId,destinationCompanyCode,status"], ...users].join( + "\n", + ); + + const companies = companyReports.map( + company => `${company.sourceId},${company.destinationCode},${company.status}`, + ); + const companyCSV = [...["sourceId,destinationCode,status"], ...companies].join("\n"); + + console.log(userCSV); + console.log(companyCSV); + } + + function displayStats() { + const userFailures = userReports.filter(user => user.error); + const companyFailures = companyReports.filter(company => company.error); + const ownerFailures = ownerReports.filter(report => report.error); + + console.log("# Import report"); + console.log(`Data imported in ${(stop - start) / 1000} seconds`); + console.log("## Company"); + console.log("- Companies success:", companyReports.filter(company => !company.error).length); + console.log("- Companies failure:", companyFailures.length); + if (companyFailures.length) { + console.log("### Failures"); + companyFailures.forEach(failure => + console.log( + `- Company ${failure.company.source.id} error: ${failure.company.error?.message}`, + ), + ); + } + + console.log("## User"); + console.log("- Users success:", userReports.filter(user => !user.error).length); + console.log("- Users failure:", userFailures.length); + if (userFailures.length) { + console.log("### Failures"); + userFailures.forEach(failure => + console.log( + `- User ${failure.user.source.user.user_id} error: ${failure.user.error?.message}`, + ), + ); + } + + console.log("## Owner"); + console.log("- Owners success:", ownerReports.filter(report => !report.error).length); + console.log("- Owners failure:", ownerFailures.length); + if (ownerFailures.length) { + console.log("### Failures"); + ownerFailures.forEach(report => + console.log(`- User ${report.destinationId} error: ${report?.error?.message}`), + ); + } + + console.log("## Warnings"); + console.log("### Companies witout admins"); + companiesWithoutAdmin.forEach(company => { + console.log(`- ${company.id} - ${company.displayName}`); + }); + + if (argv.csv) { + reportAsCSV(); + } + } + }, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/export.ts b/twake/backend/node/src/cli/cmds/export.ts new file mode 100644 index 00000000..97f88aa6 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/export.ts @@ -0,0 +1,14 @@ +import { CommandModule } from "yargs"; + +const command: CommandModule = { + describe: "Export Twake data", + command: "export <command>", + builder: yargs => + yargs.commandDir("export_cmds", { + visit: commandModule => commandModule.default, + }), + // eslint-disable-next-line @typescript-eslint/no-empty-function + handler: () => {}, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/export_cmds/export_company.ts b/twake/backend/node/src/cli/cmds/export_cmds/export_company.ts new file mode 100644 index 00000000..6d68b863 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/export_cmds/export_company.ts @@ -0,0 +1,266 @@ +import yargs from "yargs"; +import twake from "../../../twake"; +import { mkdirSync, writeFileSync } from "fs"; +import { Pagination } from "../../../core/platform/framework/api/crud-service"; +import WorkspaceUser from "../../../services/workspaces/entities/workspace_user"; +import { ChannelVisibility } from "../../../services/channels/types"; +import { Channel, ChannelMember } from "../../../services/channels/entities"; +import { Message } from "../../../services/messages/entities/messages"; +import { MessageWithReplies } from "../../../services/messages/types"; +import { formatCompany } from "../../../services/user/utils"; +import gr from "../../../services/global-resolver"; +import { formatUser } from "../../../utils/users"; + +/** + * Merge command parameters. Check the builder definition below for more details. + */ +type CLIArgs = { + id: string; +}; + +const services = [ + "auth", + "storage", + "counter", + "message-queue", + "user", + "files", + "messages", + "workspaces", + "platform-services", + "console", + "applications", + "search", + "database", + "webserver", + "channels", + "statistics", +]; + +const command: yargs.CommandModule<unknown, CLIArgs> = { + command: "company", + describe: + "command to export everything inside a company (publicly data only available to a new member)", + builder: { + id: { + default: "", + type: "string", + description: "Company ID", + }, + output: { + default: "", + type: "string", + description: "Folder containing the exported data", + }, + }, + handler: async argv => { + const platform = await twake.run(services); + await gr.doInit(platform); + + const company = await gr.services.companies.getCompany({ id: argv.id }); + + if (!company) { + return "No such company"; + } + + console.log(`Start export for company ${company.id}`); + + const output = (argv.output as string) || `export-${company.id}`; + mkdirSync(output, { recursive: true }); + + //Company + console.log("- Create company json file"); + writeFileSync(`${output}/company.json`, JSON.stringify(formatCompany(company))); + + //Workspaces + console.log("- Create workspaces json file"); + const workspaces = await gr.services.workspaces.getAllForCompany(company.id); + writeFileSync(`${output}/workspaces.json`, JSON.stringify(workspaces)); + + //Users + console.log("- Create users json file"); + const users = []; + for (const workspace of workspaces) { + const workspace_users = []; + let workspaceUsers: WorkspaceUser[] = []; + let pagination = new Pagination(); + do { + const res = await gr.services.workspaces.getUsers( + { workspaceId: workspace.id }, + pagination, + ); + workspaceUsers = [...workspaceUsers, ...res.getEntities()]; + pagination = res.nextPage as Pagination; + } while (pagination.page_token); + for (const workspaceUser of workspaceUsers) { + const user = await gr.services.users.get({ id: workspaceUser.userId }); + if (user) { + users.push(await formatUser(user)); + workspace_users.push({ ...workspaceUser, user }); + } + } + mkdirSync(`${output}/workspaces/${workspace.id}`, { recursive: true }); + writeFileSync( + `${output}/workspaces/${workspace.id}/users.json`, + JSON.stringify(workspace_users), + ); + } + writeFileSync(`${output}/users.json`, JSON.stringify(users)); + + //Applications + console.log("- Create applications json file"); + const applications = await gr.services.applications.companyApps.list( + new Pagination(), + {}, + { company: { id: company.id }, user: { id: "", server_request: true } }, + ); + writeFileSync(`${output}/applications.json`, JSON.stringify(applications)); + + //Channels + console.log("- Create channels json file"); + const directChannels: Channel[] = []; + let allPublicChannels: Channel[] = []; + + let pagination = new Pagination(); + do { + const page = await gr.services.channels.channels.getDirectChannelsInCompany( + pagination, + company.id, + undefined, + ); + for (const channel of page.getEntities()) { + const channelDetail = await gr.services.channels.channels.get( + { + company_id: channel.company_id, + workspace_id: "direct", + id: channel.id, + }, + undefined, + ); + directChannels.push(channelDetail); + } + pagination = page.nextPage as Pagination; + } while (pagination.page_token); + + for (const workspace of workspaces) { + let pagination = new Pagination(); + + let publicChannels: Channel[] = []; + pagination = new Pagination(); + do { + const page = await gr.services.channels.channels.list( + pagination, + {}, + { + user: { id: "", server_request: true }, + workspace: { workspace_id: workspace.id, company_id: company.id }, + }, + ); + const chans = page.getEntities().filter(c => c.visibility == ChannelVisibility.PUBLIC); + allPublicChannels = [...allPublicChannels, ...chans]; + publicChannels = [...publicChannels, ...chans]; + pagination = page.nextPage as Pagination; + } while (pagination.page_token); + + mkdirSync(`${output}/workspaces/${workspace.id}`, { recursive: true }); + writeFileSync( + `${output}/workspaces/${workspace.id}/channels.json`, + JSON.stringify(publicChannels), + ); + } + writeFileSync(`${output}/direct_channels.json`, JSON.stringify(directChannels)); + + //Channels users + console.log("- Create channels users json file"); + for (const channel of [...allPublicChannels /*, ...directChannels*/]) { + let members: ChannelMember[] = []; + let pagination = new Pagination(); + do { + const page = await gr.services.channels.members.list( + pagination, + {}, + { + user: { id: "", server_request: true }, + channel: { + company_id: channel.company_id, + workspace_id: channel.workspace_id, + id: channel.id, + }, + }, + ); + members = [...members, ...page.getEntities()] as ChannelMember[]; + pagination = page.nextPage as Pagination; + } while (pagination.page_token); + + mkdirSync(`${output}/workspaces/${channel.workspace_id}/channels/${channel.id}`, { + recursive: true, + }); + writeFileSync( + `${output}/workspaces/${channel.workspace_id}/channels/${channel.id}/members.json`, + JSON.stringify(members), + ); + } + + //Messages + console.log("- Create messages json file"); + //Note: direct channels content is private and not needed for R&D + for (const channel of [...allPublicChannels /*, ...directChannels*/]) { + let threads: MessageWithReplies[] = []; + let messages: Message[] = []; + let pagination = new Pagination(); + try { + do { + const page = await gr.services.messages.views.listChannel( + pagination, + { + include_users: false, + replies_per_thread: 10000, + emojis: false, + }, + { + user: { id: "", server_request: true }, + channel: { + company_id: channel.company_id, + workspace_id: channel.workspace_id, + id: channel.id, + }, + }, + ); + + for (const thread of page.getEntities()) { + messages = [...messages, ...thread.last_replies]; + } + + threads = [ + ...threads, + ...page.getEntities().map(thread => { + thread.last_replies = undefined; + return thread; + }), + ]; + + pagination = page.nextPage as Pagination; + } while (pagination.page_token); + } catch (err) { + console.log(`-- Error on the channel ${channel.id}`); + console.log(err); + } + + mkdirSync(`${output}/workspaces/${channel.workspace_id}/channels/${channel.id}`, { + recursive: true, + }); + writeFileSync( + `${output}/workspaces/${channel.workspace_id}/channels/${channel.id}/threads.json`, + JSON.stringify(threads), + ); + writeFileSync( + `${output}/workspaces/${channel.workspace_id}/channels/${channel.id}/messages.json`, + JSON.stringify(messages), + ); + } + + await platform.stop(); + }, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/generate.ts b/twake/backend/node/src/cli/cmds/generate.ts new file mode 100644 index 00000000..c71ca84d --- /dev/null +++ b/twake/backend/node/src/cli/cmds/generate.ts @@ -0,0 +1,14 @@ +import { CommandModule } from "yargs"; + +const command: CommandModule = { + describe: "Generate Twake data", + command: "generate <command>", + builder: yargs => + yargs.commandDir("generate_cmds", { + visit: commandModule => commandModule.default, + }), + // eslint-disable-next-line @typescript-eslint/no-empty-function + handler: () => {}, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/generate_cmds/users-and-companies.ts b/twake/backend/node/src/cli/cmds/generate_cmds/users-and-companies.ts new file mode 100644 index 00000000..a4d1e77c --- /dev/null +++ b/twake/backend/node/src/cli/cmds/generate_cmds/users-and-companies.ts @@ -0,0 +1,147 @@ +import passwordGenerator from "generate-password"; +import { from, pipe } from "rxjs"; +import { bufferCount, first, map, mergeMap, switchMap, tap } from "rxjs/operators"; +import { v1 as uuid } from "uuid"; +import yargs from "yargs"; + +import Company, { + getInstance as getCompanyInstance, +} from "../../../services/user/entities/company"; +import CompanyUser from "../../../services/user/entities/company_user"; +import twake from "../../../twake"; +import User, { getInstance as getUserInstance } from "../../../services/user/entities/user"; +import gr from "../../../services/global-resolver"; + +type CLIArgs = { + company: number; + user: number; + concurrent: number; +}; + +const services = [ + "storage", + "counter", + "applications", + "statistics", + "auth", + "realtime", + "push", + "platform-services", + "user", + "search", + "channels", + "notifications", + "database", + "webserver", + "message-queue", +]; + +// eslint-disable-next-line @typescript-eslint/ban-types +const command: yargs.CommandModule<{}, CLIArgs> = { + command: "users", + describe: "Generate users and companies", + builder: { + company: { + alias: "c", + default: 3, + type: "number", + description: "Number of companies to generate", + }, + user: { + alias: "u", + default: 5, + type: "number", + description: "Number of users to generate in the company", + }, + concurrent: { + default: 1, + type: "number", + description: "Number of concurrent creation tasks", + }, + }, + handler: async argv => { + const concurrentTasks = argv.concurrent; + const nbUsersPerCompany = argv.user; + const nbCompanies = argv.company; + const platform = await twake.run(services); + await gr.doInit(platform); + const companies = getCompanies(nbCompanies); + const createUser = async (userInCompany: { + user: User; + company: Company; + }): Promise<CompanyUser> => { + console.log("Creating user", userInCompany); + const created = await gr.services.users.create(getUserInstance(userInCompany.user)); + + return (await gr.services.companies.setUserRole(userInCompany.company.id, created.entity.id)) + ?.entity; + }; + const createCompany = (company: Company) => { + console.log("Creating company", company); + return gr.services.companies.createCompany(company); + }; + + const obsv$ = from(companies).pipe( + // Create companies sequentially + mergeMap(company => createCompany(company), concurrentTasks), + // until we create enough companies + bufferCount(companies.length), + tap(companies => console.log("Created companies", companies.length)), + // for each created company + switchMap(companies => from(companies)), + // generate a set of user for each company + map(company => getUsersForCompany(company, nbUsersPerCompany)), + // Create users sequentially + pipe( + switchMap(userCompanies => from(userCompanies)), + mergeMap(userCompany => createUser(userCompany), concurrentTasks), + // until we reach the number of users in the company + bufferCount(nbUsersPerCompany), + ), + // until we reach the number of companies + bufferCount(companies.length), + first(), + ); + + return obsv$ + .toPromise() + .then(() => platform.stop()) + .finally(() => console.log("βœ… Company users are now created")); + }, +}; + +const getCompanies = (size: number = 10): Company[] => { + return [...Array(size).keys()].map(i => + getCompanyInstance({ + id: uuid(), + name: `twake${i}.app`, + displayName: `My Twake Company #${i}`, + }), + ); +}; + +const getUsersForCompany = (company: Company, size: number = 10) => { + return getUsers(company, size).map(user => ({ + user, + company, + })); +}; + +const getUsers = (company: Company, size: number = 100): User[] => { + return [...Array(size).keys()].map(i => getUser(company, i)); +}; + +const getUser = (company: Company, id: number): User => { + return getUserInstance({ + id: uuid(), + first_name: "John", + last_name: `Doe${id}`, + email_canonical: `user${id}@${company.name}`, + password: passwordGenerator.generate({ + length: 10, + numbers: true, + }), + }); +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/migration.ts b/twake/backend/node/src/cli/cmds/migration.ts new file mode 100644 index 00000000..99c0884c --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration.ts @@ -0,0 +1,14 @@ +import { CommandModule } from "yargs"; + +const command: CommandModule = { + describe: "Migrate your php message to node", + command: "migration <command>", + builder: yargs => + yargs.commandDir("migration_cmds", { + visit: commandModule => commandModule.default, + }), + // eslint-disable-next-line @typescript-eslint/no-empty-function + handler: () => {}, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/application.ts b/twake/backend/node/src/cli/cmds/migration_cmds/application.ts new file mode 100644 index 00000000..63c88264 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/application.ts @@ -0,0 +1,264 @@ +import yargs from "yargs"; +import twake from "../../../twake"; +import ora from "ora"; +import { TwakePlatform } from "../../../core/platform/platform"; +import { DatabaseServiceAPI } from "../../../core/platform/services/database/api"; +import PhpApplication, { + DepreciatedDisplayConfiguration, + TYPE as phpTYPE, +} from "./php-application/php-application-entity"; +import { Pagination } from "../../../core/platform/framework/api/crud-service"; +import Application, { TYPE } from "../../../services/applications/entities/application"; +import gr from "../../../services/global-resolver"; + +type Options = { + onlyApplication?: string; + replaceExisting?: boolean; +}; + +class ApplicationMigrator { + database: DatabaseServiceAPI; + + constructor(readonly platform: TwakePlatform) { + this.database = this.platform.getProvider<DatabaseServiceAPI>("database"); + } + + public async run(options: Options = {}): Promise<void> { + const phpRepository = await this.database.getRepository(phpTYPE, PhpApplication); + const repository = await this.database.getRepository(TYPE, Application); + + let page: Pagination = { limitStr: "100" }; + do { + const applicationListResult = await phpRepository.find({}, { pagination: page }, undefined); + page = applicationListResult.nextPage as Pagination; + + for (const application of applicationListResult.getEntities()) { + if ( + !(await repository.findOne( + { + id: application.id, + }, + {}, + undefined, + )) || + options.replaceExisting + ) { + const newApplication = importDepreciatedFields(application); + await repository.save(newApplication, undefined); + } + } + } while (page.page_token); + } +} + +const services = [ + "storage", + "counter", + "platform-services", + "user", + "search", + "channels", + "database", + "webserver", + "message-queue", + "applications", + "console", + "auth", + "statistics", + "realtime", +]; + +const command: yargs.CommandModule<unknown, unknown> = { + command: "application", + describe: "command that allow you to migrate php applications to node", + builder: { + onlyApplication: { + default: null, + type: "string", + description: "Migrate only this application ID", + }, + replaceExisting: { + default: false, + type: "boolean", + description: "Replace already migrated applications", + }, + }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + handler: async argv => { + const spinner = ora({ text: "Migrating php applications - " }).start(); + const platform = await twake.run(services); + await gr.doInit(platform); + const migrator = new ApplicationMigrator(platform); + + const onlyApplication = argv.onlyApplication as string | null; + const replaceExisting = (argv.replaceExisting || false) as boolean; + + await migrator.run({ + onlyApplication, + replaceExisting, + }); + + return spinner.stop(); + }, +}; + +export default command; + +export const importDepreciatedFields = (application: PhpApplication): Application => { + const newApplication = new Application(); + + newApplication.id = application.id; + newApplication.company_id = application.group_id; + newApplication.is_default = application.is_default; + + if (!newApplication.identity?.name) { + newApplication.identity = { + code: + application.depreciated_simple_name || + (application.depreciated_name || "").toLocaleLowerCase(), + name: application.depreciated_name, + icon: application.depreciated_icon_url, + description: application.depreciated_description, + website: "http://twake.app/", + categories: [], + compatibility: ["twake"], + }; + } + + if (newApplication.publication?.published === undefined) { + newApplication.publication = newApplication.publication || { + published: false, + requested: false, + }; + newApplication.publication.published = application.depreciated_is_available_to_public; + newApplication.publication.requested = + application.depreciated_public && !application.depreciated_twake_team_validation; + } + + if (!newApplication.stats?.version) { + newApplication.stats = newApplication.stats || { + created_at: null, + updated_at: null, + version: null, + }; + newApplication.stats.version = 1; + newApplication.stats.created_at = Date.now(); + newApplication.stats.updated_at = Date.now(); + } + + if (!newApplication.api?.private_key) { + newApplication.api = newApplication.api || { + hooks_url: null, + allowed_ips: null, + private_key: null, + }; + newApplication.api.hooks_url = application.depreciated_api_events_url; + newApplication.api.allowed_ips = application.depreciated_api_allowed_ip; + newApplication.api.private_key = application.depreciated_api_private_key; + } + + if (newApplication.access?.write === undefined) { + newApplication.access = newApplication.access || { + read: null, + write: null, + delete: null, + hooks: null, + }; + try { + newApplication.access.write = JSON.parse(application.depreciated_capabilities || "[]") || []; + newApplication.access.delete = JSON.parse(application.depreciated_capabilities || "[]") || []; + } catch (e) { + newApplication.access.write = []; + newApplication.access.delete = []; + } + try { + newApplication.access.read = JSON.parse(application.depreciated_privileges || "[]") || []; + } catch (e) { + newApplication.access.read = []; + } + try { + newApplication.access.hooks = JSON.parse(application.depreciated_hooks || "[]") || []; + } catch (e) { + newApplication.access.hooks = []; + } + } + + newApplication.display = importDepreciatedDisplayFields( + newApplication, + JSON.parse(application.depreciated_display_configuration), + ); + + return newApplication; +}; + +export const importDepreciatedDisplayFields = ( + application: Application, + depreciatedDisplay: DepreciatedDisplayConfiguration, +): Application["display"] => { + let display = application.display; + + if (!display?.twake) { + display = display || { twake: {} }; + display.twake = display.twake || {}; + } + + display.twake.tab = depreciatedDisplay?.channel_tab + ? { url: depreciatedDisplay?.channel_tab?.iframe } || true + : undefined; + + display.twake.standalone = depreciatedDisplay?.app + ? { url: depreciatedDisplay?.app?.iframe } || true + : undefined; + + display.twake.configuration = []; + if (depreciatedDisplay?.configuration?.can_configure_in_workspace) + display.twake.configuration.push("global"); + if (depreciatedDisplay?.configuration?.can_configure_in_channel) + display.twake.configuration.push("channel"); + + display.twake.direct = depreciatedDisplay?.member_app + ? { name: application.identity.name, icon: application.identity.icon } || true + : undefined; + + if (depreciatedDisplay?.drive_module) { + display.twake.files = { + editor: undefined, + actions: [], + }; + + display.twake.files.editor = { + preview_url: depreciatedDisplay?.drive_module?.can_open_files?.preview_url, + edition_url: depreciatedDisplay?.drive_module?.can_open_files?.url, + extensions: [ + ...(depreciatedDisplay?.drive_module?.can_open_files?.main_ext || []), + ...(depreciatedDisplay?.drive_module?.can_open_files?.other_ext || []), + ], + empty_files: (depreciatedDisplay?.drive_module?.can_create_files as any) || [], + }; + } + + if (depreciatedDisplay?.messages_module) { + display.twake.chat = { + input: + depreciatedDisplay?.messages_module?.in_plus || + depreciatedDisplay?.messages_module?.right_icon + ? { + icon: application.identity.icon, + } + : undefined, + commands: + (depreciatedDisplay?.messages_module + ?.commands as Application["display"]["twake"]["chat"]["commands"]) || undefined, + actions: depreciatedDisplay?.messages_module?.action + ? [ + { + name: depreciatedDisplay?.messages_module?.action.description, + id: "default", + }, + ] + : undefined, + }; + } + + return display; +}; diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/channel-member-read-cursors.ts b/twake/backend/node/src/cli/cmds/migration_cmds/channel-member-read-cursors.ts new file mode 100644 index 00000000..aec9c6a7 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/channel-member-read-cursors.ts @@ -0,0 +1,173 @@ +import { DatabaseServiceAPI } from "../../../core/platform/services/database/api"; +import { TwakePlatform } from "../../../core/platform/platform"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import { ChannelMember, ChannelMemberReadCursors } from "../../../services/channels/entities"; +import { + ExecutionContext, + Paginable, + Pagination, +} from "../../../core/platform/framework/api/crud-service"; +import gr from "../../../services/global-resolver"; +import yargs from "yargs"; +import ora from "ora"; +import twake from "../../../twake"; + +class ChannelMemberReadCursorsMigrator { + readSectionRepository: Repository<ChannelMemberReadCursors>; + database: DatabaseServiceAPI; + + constructor(readonly _platform: TwakePlatform) { + this.database = this._platform.getProvider<DatabaseServiceAPI>("database"); + } + + public async run(_options = {}, context?: ExecutionContext): Promise<void> { + const companyPagination: Paginable = new Pagination(null, "100"); + const companies = await gr.services.companies.getCompanies(companyPagination); + + context.user.server_request = true; + + for (const company of companies.getEntities()) { + const { id: CompanyId } = company; + + const workspaces = await gr.services.workspaces.getAllForCompany(CompanyId); + const workspaceIds = [...workspaces.map(({ id }) => id), "direct"]; + + for (const workspaceId of workspaceIds) { + const channels = await gr.services.channels.channels.getAllChannelsInWorkspace( + CompanyId, + workspaceId, + ); + + for (const channel of channels) { + const { id: channelId } = channel; + const membersPagination: Pagination = new Pagination(null, "100"); + const threadsPagination: Pagination = new Pagination(null, "1"); + let members: ChannelMember[]; + + try { + const membersList = await gr.services.channels.members.list( + membersPagination, + {}, + { + ...context, + channel: { + company_id: CompanyId, + id: channelId, + workspace_id: workspaceId, + }, + }, + ); + members = membersList.getEntities(); + } catch (error) { + continue; + } + + let lastMessage = await gr.services.messages.views.listChannel( + threadsPagination, + {}, + { + ...context, + channel: { + company_id: CompanyId, + id: channelId, + workspace_id: workspaceId, + }, + user: { + id: null, + }, + }, + ); + + const firstMessage = await gr.services.messages.views.listChannel( + { + ...threadsPagination, + reversed: true, + }, + {}, + { + ...context, + channel: { + company_id: CompanyId, + id: channelId, + workspace_id: workspaceId, + }, + user: { + id: null, + }, + }, + ); + + if (!firstMessage.getEntities().length) { + continue; + } + + if (!lastMessage.getEntities().length) { + lastMessage = firstMessage; + } + + const firstMessageId = firstMessage.getEntities()[0].id; + const lastMessageId = lastMessage.getEntities()[0].id; + + if (!firstMessageId) { + continue; + } else { + for (const member of members) { + await gr.services.channels.members.setChannelMemberReadSections( + { + start: firstMessageId, + end: lastMessageId, + }, + { + ...context, + channel_id: channelId, + workspace_id: workspaceId, + company: { + id: CompanyId, + }, + user: { + id: member.user_id, + }, + }, + ); + } + } + } + } + } + } +} + +const services = [ + "search", + "database", + "webserver", + "auth", + "counter", + "cron", + "message-queue", + "push", + "realtime", + "storage", + "tracker", + "websocket", + "email-pusher", +]; + +const command: yargs.CommandModule<unknown, unknown> = { + command: "channel-member-read-cursor-repair", + describe: "fixes the channel members read cursors for old messages", + builder: {}, + + handler: async () => { + const spinner = ora({ text: "Fixing channel members read cursors" }).start(); + const platform = await twake.run(services); + await gr.doInit(platform); + const migrator = new ChannelMemberReadCursorsMigrator(platform); + + await migrator.run({}); + + return spinner.stop(); + }, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/devices.ts b/twake/backend/node/src/cli/cmds/migration_cmds/devices.ts new file mode 100644 index 00000000..8027d3d1 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/devices.ts @@ -0,0 +1,103 @@ +import yargs from "yargs"; +import twake from "../../../twake"; +import ora from "ora"; +import { TwakePlatform } from "../../../core/platform/platform"; +import { DatabaseServiceAPI } from "../../../core/platform/services/database/api"; +import { PhpDevice, TYPE as phpTYPE } from "./php-device/php-device-entity"; +import { Pagination } from "../../../core/platform/framework/api/crud-service"; +import Device, { TYPE } from "../../../services/user/entities/device"; +import User, { TYPE as userTYPE } from "../../../services/user/entities/user"; +import _ from "lodash"; +import gr from "../../../services/global-resolver"; + +type Options = { + replaceExisting?: boolean; +}; + +class DeviceMigrator { + database: DatabaseServiceAPI; + + constructor(readonly platform: TwakePlatform) { + this.database = this.platform.getProvider<DatabaseServiceAPI>("database"); + } + + public async run(options: Options = {}): Promise<void> { + const phpRepository = await this.database.getRepository(phpTYPE, PhpDevice); + const userRepository = await this.database.getRepository(userTYPE, User); + const repository = await this.database.getRepository(TYPE, Device); + + // Get all companies + let page: Pagination = { limitStr: "100" }; + // For each devices + do { + const deviceListResult = await phpRepository.find({}, { pagination: page }, undefined); + page = deviceListResult.nextPage as Pagination; + + for (const device of deviceListResult.getEntities()) { + if ( + !(await repository.findOne({ id: device.value }, {}, undefined)) || + options.replaceExisting + ) { + if (device.type === "FCM" || device.type === "fcm") { + const newDevice = new Device(); + newDevice.id = device.value; + newDevice.type = "FCM"; + newDevice.user_id = device.user_id; + newDevice.version = device.version; + await repository.save(newDevice, undefined); + + const user = await userRepository.findOne({ id: device.user_id }, {}, undefined); + if (user) { + user.devices = _.uniq([...(user.devices || []), newDevice.id]); + await userRepository.save(user, undefined); + } + } + } + } + } while (page.page_token); + } +} + +const services = [ + "storage", + "counter", + "platform-services", + "user", + "search", + "channels", + "database", + "webserver", + "message-queue", + "workspaces", + "console", + "auth", +]; + +const command: yargs.CommandModule<unknown, unknown> = { + command: "device", + describe: "command that allow you to migrate php devices to node", + builder: { + replaceExisting: { + default: false, + type: "boolean", + description: "Replace already migrated devices", + }, + }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + handler: async argv => { + const spinner = ora({ text: "Migrating php devices - " }).start(); + const platform = await twake.run(services); + await gr.doInit(platform); + const migrator = new DeviceMigrator(platform); + + const replaceExisting = (argv.replaceExisting || false) as boolean; + + await migrator.run({ + replaceExisting, + }); + + return spinner.stop(); + }, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/drive.ts b/twake/backend/node/src/cli/cmds/migration_cmds/drive.ts new file mode 100644 index 00000000..e5dba126 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/drive.ts @@ -0,0 +1,40 @@ +import ora from "ora"; +import globalResolver from "../../../services/global-resolver"; +import twake from "../../../twake"; +import yargs from "yargs"; +import DriveMigrator from "./php-drive-file/drive-migrator-service"; + +const services = [ + "search", + "database", + "webserver", + "auth", + "counter", + "cron", + "message-queue", + "push", + "realtime", + "storage", + "tracker", + "websocket", + "email-pusher", +]; + +const command: yargs.CommandModule<unknown, unknown> = { + command: "drive", + describe: "migrate php drive items to node", + builder: {}, + handler: async _argv => { + console.log("test"); + const spinner = ora({ text: "Migrating php drive - " }).start(); + const platform = await twake.run(services); + await globalResolver.doInit(platform); + const migrator = new DriveMigrator(platform); + + await migrator.run(); + + return spinner.stop(); + }, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/message-channel-repair.ts b/twake/backend/node/src/cli/cmds/migration_cmds/message-channel-repair.ts new file mode 100644 index 00000000..80f85fbe --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/message-channel-repair.ts @@ -0,0 +1,96 @@ +import yargs from "yargs"; +import twake from "../../../twake"; +import ora from "ora"; +import { DatabaseServiceAPI } from "../../../core/platform/services/database/api"; +import { TwakePlatform } from "../../../core/platform/platform"; +import gr from "../../../services/global-resolver"; + +type Options = { + from?: string; + onlyCompany?: string; + onlyWorkspace?: string; + onlyChannel?: string; + dryRun?: boolean; +}; + +class MessageReferenceRepair { + database: DatabaseServiceAPI; + + constructor(readonly platform: TwakePlatform) { + this.database = this.platform.getProvider<DatabaseServiceAPI>("database"); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public async run(_options: Options = {}): Promise<void> { + //TODO repair messages + } +} + +const services = [ + "storage", + "counter", + "platform-services", + "user", + "search", + "channels", + "database", + "webserver", + "message-queue", + "messages", +]; + +const command: yargs.CommandModule<unknown, unknown> = { + command: "message-channel-repair", + describe: "command that allow you to repair messages references in channels", + builder: { + from: { + default: null, + type: "string", + description: "Start migration from this company ID", + }, + onlyCompany: { + default: null, + type: "string", + description: "Migrate only this company ID", + }, + onlyWorkspace: { + default: null, + type: "string", + description: "Migrate only this workspace ID", + }, + onlyChannel: { + default: null, + type: "string", + description: "Migrate only this channel ID", + }, + dryRun: { + default: false, + type: "boolean", + description: "Do not save anything and show missing references", + }, + }, + handler: async argv => { + const spinner = ora({ text: "Fixing messages references - " }).start(); + const platform = await twake.run(services); + await gr.doInit(platform); + const migrator = new MessageReferenceRepair(platform); + + const from = argv.from as string | null; + const onlyCompany = argv.onlyCompany as string | null; + const onlyWorkspace = argv.onlyWorkspace as string | null; + const onlyChannel = argv.onlyChannel as string | null; + const dryRun = (argv.dryRun || false) as boolean; + + await migrator.run({ + from, + onlyCompany, + onlyWorkspace, + onlyChannel, + dryRun, + }); + + return spinner.stop(); + }, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/message-files-cache.ts b/twake/backend/node/src/cli/cmds/migration_cmds/message-files-cache.ts new file mode 100644 index 00000000..0e56413e --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/message-files-cache.ts @@ -0,0 +1,190 @@ +import yargs from "yargs"; +import twake from "../../../twake"; +import ora from "ora"; +import { TwakePlatform } from "../../../core/platform/platform"; +import { DatabaseServiceAPI } from "../../../core/platform/services/database/api"; +import { + ExecutionContext, + Paginable, + Pagination, +} from "../../../core/platform/framework/api/crud-service"; +import gr from "../../../services/global-resolver"; +import { getInstance, MessageFileRef } from "../../../services/messages/entities/message-file-refs"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import uuid from "node-uuid"; +import { MessageFile } from "../../../services/messages/entities/message-files"; +import { ThreadExecutionContext } from "../../../services/messages/types"; + +type Options = Record<string, unknown>; + +class MessageFilesCacheMigrator { + database: DatabaseServiceAPI; + repository: Repository<MessageFileRef>; + messageFileRepository: Repository<MessageFile>; + + constructor(readonly platform: TwakePlatform) { + this.database = this.platform.getProvider<DatabaseServiceAPI>("database"); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public async run(_options: Options = {}, context?: ExecutionContext): Promise<void> { + this.repository = await gr.database.getRepository<MessageFileRef>( + "message_file_refs", + MessageFileRef, + ); + this.messageFileRepository = await gr.database.getRepository<MessageFile>( + "message_files", + MessageFile, + ); + + let count = 0; + + let companyPagination: Paginable = new Pagination(null, "100"); + do { + const companyList = await gr.services.companies.getCompanies(companyPagination); + companyPagination = companyList.nextPage; + + for (const company of companyList.getEntities()) { + const companyId: string = company.id; + const workspaceList = await gr.services.workspaces.getAllForCompany(companyId); + + for (const workspaceId of [...workspaceList.map(w => w.id), "direct"]) { + const channelsList = await gr.services.channels.channels.getAllChannelsInWorkspace( + companyId, + workspaceId, + context, + ); + + for (const channel of channelsList) { + const channelId = channel.id; + + let threadPagination: Paginable = new Pagination(null, "100"); + do { + const threadList = await gr.services.messages.views.listChannel( + threadPagination, + {}, + { + channel: { + company_id: companyId, + workspace_id: workspaceId, + id: channelId, + }, + user: { id: null }, + }, + ); + + for (const thread of threadList.getEntities()) { + let messagesPagination: Paginable = new Pagination(null, "100"); + do { + const messagesList = await gr.services.messages.messages.list( + messagesPagination, + {}, + { + thread: { id: thread.id }, + company: { id: companyId }, + workspace: { id: workspaceId }, + channel: { id: channelId }, + user: { id: null }, + } as ThreadExecutionContext, + ); + messagesPagination = messagesList.nextPage; + messagesPagination.page_token = messagesList.getEntities()[0]?.id; + + for (const message of messagesList.getEntities()) { + if (message.files && message.files.length > 0) { + for (const _messageFile of message.files) { + count++; + try { + const messageFile = await this.messageFileRepository.findOne( + { + message_id: message.id, + id: _messageFile.id, + }, + {}, + undefined, + ); + + if (messageFile) { + console.log(messageFile.metadata.name); + + //Update user uploads + const fileRef = getInstance({ + target_type: "user_upload", + target_id: message.user_id, + id: uuid.v1({ msecs: message.created_at }), + created_at: message.created_at, + company_id: companyId, + workspace_id: workspaceId, + channel_id: channelId, + thread_id: message.thread_id, + message_id: message.id, + message_file_id: messageFile.id, + file_id: messageFile.metadata.external_id, + }); + await this.repository.save(fileRef, undefined); + + //Update messageFileRepository + + messageFile.cache = { + company_id: companyId, + workspace_id: workspaceId, + channel_id: channelId, + user_id: message.user_id, + }; + messageFile.thread_id = message.thread_id; + + await this.messageFileRepository.save(messageFile, undefined); + } + } catch (e) {} + } + } + } + } while (messagesPagination.page_token); + } + + threadPagination = threadList.nextPage; + threadPagination.page_token = + threadPagination.page_token && + threadList.getEntities()?.[threadList.getEntities().length - 1]?.thread_id; + } while (false); // && threadPagination.page_token && threadList.getEntities().length > 50); + } + } + } + console.log("updated messages: ", count); + } while (companyPagination.page_token); + } +} + +const services = [ + "search", + "database", + "webserver", + "auth", + "counter", + "cron", + "message-queue", + "push", + "realtime", + "storage", + "tracker", + "websocket", +]; + +const command: yargs.CommandModule<unknown, unknown> = { + command: "message-files-cache", + describe: "command that allow you to fix cache for each message-file refs", + builder: {}, + + handler: async () => { + const spinner = ora({ text: "Migrating messages - " }).start(); + const platform = await twake.run(services); + await gr.doInit(platform); + const migrator = new MessageFilesCacheMigrator(platform); + + await migrator.run({}); + + return spinner.stop(); + }, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/message.ts b/twake/backend/node/src/cli/cmds/migration_cmds/message.ts new file mode 100644 index 00000000..b2814cf9 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/message.ts @@ -0,0 +1,91 @@ +import yargs from "yargs"; +import twake from "../../../twake"; +import ora from "ora"; +import MessageMigrator from "./php-message/message-migrator-service"; +import gr from "../../../services/global-resolver"; + +const services = [ + "storage", + "counter", + "platform-services", + "user", + "search", + "channels", + "database", + "webserver", + "message-queue", + "messages", + "statistics", +]; + +const command: yargs.CommandModule<unknown, unknown> = { + command: "message", + describe: "command that allow you to migrate php messages to node", + builder: { + from: { + default: null, + type: "string", + description: "Start migration from this company ID", + }, + onlyCompany: { + default: null, + type: "string", + description: "Migrate only this company ID", + }, + onlyWorkspace: { + default: null, + type: "string", + description: "Migrate only this workspace ID", + }, + onlyChannel: { + default: null, + type: "string", + description: "Migrate only this channel ID", + }, + ignoreExisting: { + default: false, + type: "boolean", + description: "Skip existing message ids", + }, + backToPhp: { + default: false, + type: "boolean", + description: + "Run the migration back, put node messages into php table (only the one that are not already here)", + }, + dryRun: { + default: false, + type: "boolean", + description: "Do not save anything", + }, + }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + handler: async argv => { + const spinner = ora({ text: "Migrating php messages - " }).start(); + const platform = await twake.run(services); + await gr.doInit(platform); + const migrator = new MessageMigrator(platform); + + const from = argv.from as string | null; + const onlyCompany = argv.onlyCompany as string | null; + const onlyWorkspace = argv.onlyWorkspace as string | null; + const onlyChannel = argv.onlyChannel as string | null; + const ignoreExisting = (argv.ignoreExisting || false) as boolean; + const backToPhp = (argv.backToPhp || false) as boolean; + const dryRun = (argv.dryRun || false) as boolean; + + await migrator.run({ + from, + onlyCompany, + onlyWorkspace, + onlyChannel, + ignoreExisting, + backToPhp, + dryRun, + }); + + return spinner.stop(); + }, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/messages-files-medias-separation.ts b/twake/backend/node/src/cli/cmds/migration_cmds/messages-files-medias-separation.ts new file mode 100644 index 00000000..35b23c09 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/messages-files-medias-separation.ts @@ -0,0 +1,125 @@ +import yargs from "yargs"; +import twake from "../../../twake"; +import ora from "ora"; +import { DatabaseServiceAPI } from "../../../core/platform/services/database/api"; +import { TwakePlatform } from "../../../core/platform/platform"; +import gr from "../../../services/global-resolver"; +import { MessageFileRef } from "../../../services/messages/entities/message-file-refs"; +import { Paginable } from "../../../core/platform/framework/api/crud-service"; +import { Pagination } from "../../../core/platform/framework/api/crud-service"; +import { fileIsMedia } from "../../../services/files/utils"; +import { MessageFile } from "../../../services/messages/entities/message-files"; +import _ from "lodash"; + +type Options = Record<string, unknown>; + +class MessageReferenceRepair { + database: DatabaseServiceAPI; + + constructor(readonly platform: TwakePlatform) { + this.database = this.platform.getProvider<DatabaseServiceAPI>("database"); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public async run(_options: Options = {}): Promise<void> { + const repository = await gr.database.getRepository<MessageFileRef>( + "message_file_refs", + MessageFileRef, + ); + const repositoryMessageFile = await gr.database.getRepository<MessageFile>( + "message_files", + MessageFile, + ); + + let count = 0; + + let companyPagination: Paginable = new Pagination(null, "100"); + do { + const companyList = await gr.services.companies.getCompanies(companyPagination); + companyPagination = companyList.nextPage; + + for (const company of companyList.getEntities()) { + const companyId: string = company.id; + const workspaceList = await gr.services.workspaces.getAllForCompany(companyId); + + for (const workspaceId of [...workspaceList.map(w => w.id), "direct"]) { + const channelsList = await gr.services.channels.channels.getAllChannelsInWorkspace( + companyId, + workspaceId, + ); + + for (const channel of channelsList) { + const channelId = channel.id; + let filePagination: Pagination = new Pagination(null, "100"); + + do { + const items = await repository.find( + { + target_type: "channel", + target_id: channelId, + company_id: companyId, + }, + { pagination: filePagination }, + ); + + for (const item of items.getEntities()) { + try { + const msgFile = await repositoryMessageFile.findOne({ + message_id: item.message_id, + id: item.message_file_id, + }); + if (msgFile) { + count++; + const isMedia = fileIsMedia(msgFile); + const ref = _.cloneDeep(item); + ref.target_type = isMedia ? "channel_media" : "channel_file"; + await repository.save(ref); + } + } catch (e) { + console.log("Error", e); + } + } + + filePagination = new Pagination(items.nextPage.page_token, "100"); + } while (filePagination.page_token); + } + } + } + + console.log("updated files refs: ", count); + } while (companyPagination.page_token); + } +} + +const services = [ + "search", + "database", + "webserver", + "auth", + "counter", + "cron", + "message-queue", + "push", + "realtime", + "storage", + "tracker", + "websocket", +]; + +const command: yargs.CommandModule<unknown, unknown> = { + command: "messages-files-medias-separation", + describe: "command to separate medias and files in messages-files channels refs", + builder: {}, + handler: async () => { + const spinner = ora({ text: "Fixing messages references - " }).start(); + const platform = await twake.run(services); + await gr.doInit(platform); + const migrator = new MessageReferenceRepair(platform); + + await migrator.run({}); + + return spinner.stop(); + }, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/php-application/php-application-entity.ts b/twake/backend/node/src/cli/cmds/migration_cmds/php-application/php-application-entity.ts new file mode 100644 index 00000000..5df778ab --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/php-application/php-application-entity.ts @@ -0,0 +1,133 @@ +import { Type } from "class-transformer"; +import { + Column, + Entity, +} from "../../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "application"; + +@Entity(TYPE, { + primaryKey: [["group_id"], "app_group_name", "id"], + type: TYPE, +}) +export default class PhpApplication { + @Type(() => String) + @Column("id", "timeuuid", { generator: "timeuuid" }) + id: string; + + @Type(() => String) + @Column("group_id", "timeuuid") + group_id: string; + + @Type(() => String) + @Column("app_group_name", "string") + app_group_name = ""; + + @Column("name", "encoded_string") + depreciated_name: string; + + @Column("simple_name", "encoded_string") + depreciated_simple_name: string; + + @Column("description", "encoded_string") + depreciated_description: string; + + @Column("icon_url", "encoded_string") + depreciated_icon_url: string; + + @Column("is_default", "twake_boolean") + is_default: boolean; + + @Column("public", "twake_boolean") + depreciated_public: boolean; + + @Column("twake_team_validation", "twake_boolean") + depreciated_twake_team_validation: boolean; + + @Column("is_available_to_public", "twake_boolean") + depreciated_is_available_to_public: boolean; //Vrai si $public ET $twake_team_validation + + @Column("api_events_url", "encoded_string") + depreciated_api_events_url: string; + + @Column("api_allowed_ip", "encoded_string") + depreciated_api_allowed_ip: string; + + @Column("api_private_key", "encoded_string") + depreciated_api_private_key: string; + + @Column("privileges", "encoded_string") + depreciated_privileges = "[]"; + + @Column("capabilities", "encoded_string") + depreciated_capabilities = "[]"; + + @Column("hooks", "encoded_string") + depreciated_hooks = "[]"; + + @Column("display_configuration", "encoded_string") + depreciated_display_configuration = "{}"; +} + +export type DepreciatedDisplayConfiguration = { + version?: 0; //Legacy + tasks_module?: { + can_connect_to_tasks?: boolean; + }; + calendar_module?: { + can_connect_to_calendar?: boolean; + }; + drive_module?: { + can_connect_to_directory?: boolean; + can_open_files?: { + url?: string; //Une url Γ  appeler pour Γ©diter le fichier (ouvert dans un onglet) + preview_url?: string; //Une url Γ  appeler pour prΓ©visualiser un fichier (iframe) + main_ext?: string[]; //Extensions principales + other_ext?: string[]; //Extensions secondaires + }; + can_create_files?: { + url?: string; + filename?: string; + name?: string; + }[]; + }; + member_app?: boolean; // Si dΓ©fini, votre application gΓ©nΓ¨rera un membre + // virtuel dans l'espace de travail avec lequel les + // utilisateurs pourront discuter. + messages_module?: { + in_plus?: { + should_wait_for_popup: boolean; + }; + right_icon?: { + icon_url?: string; //If defined replace original icon url of your app + should_wait_for_popup?: boolean; + type?: string; //"file" | "call" + }; + action?: { + should_wait_for_popup?: boolean; + description?: string; //Description de l'action, sinon remplacΓ© par le nom de l'app + }; + commands?: { + command?: string; // my_app mycommand + description?: string; + }[]; + }; + channel?: { + can_connect_to_channel?: string; + }; + channel_tab?: { + iframe?: string; + }; + app?: { + iframe?: string; + plus_btn: { + should_wait_for_popup?: boolean; + }; + }; + configuration?: { + can_configure_in_workspace?: boolean; + can_configure_in_channel?: boolean; + can_configure_in_calendar?: boolean; + can_configure_in_tasks?: boolean; + }; +}; diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/php-device/php-device-entity.ts b/twake/backend/node/src/cli/cmds/migration_cmds/php-device/php-device-entity.ts new file mode 100644 index 00000000..9860b252 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/php-device/php-device-entity.ts @@ -0,0 +1,26 @@ +import { + Column, + Entity, +} from "../../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "device"; +@Entity(TYPE, { + primaryKey: [["id"]], + type: TYPE, +}) +export class PhpDevice { + @Column("id", "timeuuid") + id: string; + + @Column("user_id", "timeuuid") + user_id: string; + + @Column("type", "string") + type: string; + + @Column("version", "string") + version: string; + + @Column("value", "encoded_string") + value: string; +} diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/php-drive-file/drive-migrator-service.ts b/twake/backend/node/src/cli/cmds/migration_cmds/php-drive-file/drive-migrator-service.ts new file mode 100644 index 00000000..2c28b2a1 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/php-drive-file/drive-migrator-service.ts @@ -0,0 +1,535 @@ +import { logger } from "../../../../core/platform/framework"; +import { ExecutionContext, Pagination } from "../../../../core/platform/framework/api/crud-service"; +import { TwakePlatform } from "../../../../core/platform/platform"; +import Repository from "../../../../core/platform/services/database/services/orm/repository/repository"; +import { DriveFile, AccessInformation } from "../../../../services/documents/entities/drive-file"; +import { + generateAccessToken, + getDefaultDriveItem, + getDefaultDriveItemVersion, +} from "../../../../services/documents/utils"; +import globalResolver from "../../../../services/global-resolver"; +import Company from "../../../../services/user/entities/company"; +import Workspace from "../../../../services/workspaces/entities/workspace"; +import { PhpDriveFile } from "./php-drive-file-entity"; +import { PhpDriveFileService } from "./php-drive-service"; +import mimes from "../../../../utils/mime"; +import WorkspaceUser from "../../../../services/workspaces/entities/workspace_user"; +import CompanyUser from "src/services/user/entities/company_user"; + +interface CompanyExecutionContext extends ExecutionContext { + company: { + id: string; + }; +} + +interface WorkspaceExecutionContext extends CompanyExecutionContext { + workspace_id: string; +} + +class DriveMigrator { + private phpDriveService: PhpDriveFileService; + private nodeRepository: Repository<DriveFile>; + + constructor(readonly _platform: TwakePlatform) { + this.phpDriveService = new PhpDriveFileService(); + } + + /** + * Run + */ + public run = async (): Promise<void> => { + await globalResolver.doInit(this._platform); + await this.phpDriveService.init(); + + this.nodeRepository = await globalResolver.database.getRepository<DriveFile>( + "drive_files", + DriveFile, + ); + + let page: Pagination = { limitStr: "100" }; + const context: ExecutionContext = { + user: { + id: null, + server_request: true, + }, + }; + + do { + const companyListResult = await globalResolver.services.companies.getCompanies(page); + page = companyListResult.nextPage as Pagination; + + for (const company of companyListResult.getEntities()) { + await this.migrateCompany(company, { + ...context, + company: { id: company.id }, + }); + } + } while (page.page_token); + }; + + /** + * Migrate a company drive files. + * + * @param {Company} company - the company to migrate + */ + private migrateCompany = async ( + company: Company, + context: CompanyExecutionContext, + ): Promise<void> => { + logger.info(`Migrating company ${company.id}`); + + const companyAdminOrOwnerId = await this.getCompanyOwnerOrAdminId(company.id, context); + const workspaceList = await globalResolver.services.workspaces.getAllForCompany(company.id); + + for (const workspace of workspaceList) { + const wsContext = { + ...context, + workspace_id: workspace.id, + user: { id: companyAdminOrOwnerId, server_request: true }, + }; + const access = await this.getWorkspaceAccess(workspace, company, wsContext); + + await this.migrateWorkspace(workspace, access, wsContext); + } + }; + + /** + * Migrates a workspace drive files. + * + * @param {Workspace} workspace - the workspace to migrate + */ + private migrateWorkspace = async ( + workspace: Workspace, + access: AccessInformation, + context: WorkspaceExecutionContext, + ): Promise<void> => { + let page: Pagination = { limitStr: "100" }; + + console.debug(`Migrating workspace ${workspace.id} of company ${context.company.id}`); + logger.info(`Migrating workspace ${workspace.id} root folder`); + + const workspaceFolder = await this.createWorkspaceFolder(workspace, access, context); + // Migrate the root folder. + do { + const phpDriveFiles = await this.phpDriveService.listDirectory( + page, + "", + workspace.id, + context, + ); + page = phpDriveFiles.nextPage as Pagination; + + for (const phpDriveFile of phpDriveFiles.getEntities()) { + await this.migrateDriveFile(phpDriveFile, workspaceFolder.id, access, context); + } + } while (page.page_token); + + logger.info(`Migrating workspace ${workspace.id} trash`); + // Migrate the trash. + page = { limitStr: "100" }; + + do { + const phpDriveFiles = await this.phpDriveService.listDirectory(page, "trash", workspace.id); + page = phpDriveFiles.nextPage as Pagination; + + for (const phpDriveFile of phpDriveFiles.getEntities()) { + await this.migrateDriveFile(phpDriveFile, "trash", access, context); + } + } while (page.page_token); + }; + + /** + * Migrates a php drive item to a Node drive file + * + * @param {PhpDriveItem} item - the php drive file to migrate. + */ + private migrateDriveFile = async ( + item: PhpDriveFile, + parentId: string, + access: AccessInformation, + context: WorkspaceExecutionContext, + ): Promise<void> => { + logger.info(`Migrating php drive item ${item.id} - parent: ${parentId ?? "root"}`); + + try { + const migrationRecord = await this.phpDriveService.getMigrationRecord( + item.id, + context.company.id, + ); + + const newDriveItem = getDefaultDriveItem( + { + name: item.name || item.id, + extension: item.extension, + added: item.added.toString(), + content_keywords: + item.content_keywords && item.content_keywords.length + ? item.content_keywords.join(",") + : "", + creator: item.creator || context.user.id, + is_directory: item.isdirectory, + is_in_trash: item.isintrash, + description: item.description, + tags: item.tags || [], + parent_id: parentId, + company_id: context.company.id, + access_info: access, + }, + context, + ); + + if (migrationRecord && migrationRecord.company_id === context.company.id) { + console.debug(`${item.id} is already migrated`); + } else { + await this.nodeRepository.save(newDriveItem); + } + + if (item.isdirectory) { + const newParentId = + migrationRecord && migrationRecord.company_id === context.company.id + ? migrationRecord.new_id + : newDriveItem.id; + + let page: Pagination = { limitStr: "100" }; + + do { + const directoryChildren = await this.phpDriveService.listDirectory( + page, + item.id, + context.workspace_id, + ); + page = directoryChildren.nextPage as Pagination; + + for (const child of directoryChildren.getEntities()) { + try { + await this.migrateDriveFile(child, newParentId, access, context); + } catch (error) { + logger.error(`Failed to migrate drive item ${child.id}`); + console.error(`Failed to migrate drive item ${child.id}`); + } + } + } while (page.page_token); + } else { + let versionPage: Pagination = { limitStr: "100" }; + if ( + migrationRecord && + migrationRecord.item_id === item.id && + migrationRecord.company_id === context.company.id + ) { + logger.info(`item is already migrated - ${item.id} - skipping`); + console.log(`item is already migrated - ${item.id} - skipping`); + return; + } + + const mime = mimes[item.extension]; + + let createdVersions = 0; + + do { + const itemVersions = await this.phpDriveService.listItemVersions( + versionPage, + item.id, + context, + ); + versionPage = itemVersions.nextPage as Pagination; + + for (const version of itemVersions.getEntities()) { + try { + const newVersion = getDefaultDriveItemVersion( + { + creator_id: version.creator_id || context.user.id, + data: version.data, + date_added: +version.date_added, + drive_item_id: newDriveItem.id, + file_size: version.file_size, + filename: version.filename, + key: version.key, + provider: version.provider, + realname: version.realname, + mode: version.mode, + }, + context, + ); + + const file = await this.phpDriveService.migrate( + version.file_id, + item.workspace_id, + version.id, + { + filename: version.filename, + userId: version.creator_id || context.user.id, + totalSize: version.file_size, + waitForThumbnail: true, + chunkNumber: 1, + totalChunks: 1, + type: mime, + }, + context, + ); + + if (!file) { + throw Error("cannot download file version"); + } + + newVersion.file_metadata = { + external_id: file.id, + mime: file.metadata.mime, + name: file.metadata.name || version.filename, + size: file.upload_data.size || version.file_size, + }; + + await globalResolver.services.documents.documents.createVersion( + newDriveItem.id, + newVersion, + context, + ); + + createdVersions++; + } catch (error) { + logger.error(`Failed to migrate version ${version.id} for drive item ${item.id}`); + console.error(`Failed to migrate version ${version.id} for drive item ${item.id}`); + } + } + } while (versionPage.page_token); + + if (createdVersions === 0) { + await this.nodeRepository.remove(newDriveItem); + return; + } + } + + if (!migrationRecord) { + await this.phpDriveService.markAsMigrated(item.id, newDriveItem.id, context.company.id); + } + } catch (error) { + logger.error( + `Failed to migrate Drive item ${item.id} / workspace ${item.workspace_id} / company_id: ${context.company.id}`, + error, + ); + console.error(`Failed to migrate Drive item ${item.id}`, error); + } + }; + + /** + * Fetches the first found company owner or admin identifier. + * + * @param {string} companyId - the companyId + * @param {ExecutionContext} context - the execution context + * @returns {Promise<string>} + */ + private getCompanyOwnerOrAdminId = async ( + companyId: string, + context: ExecutionContext, + ): Promise<string> => { + let pagination: Pagination = { limitStr: "100" }; + let companyOwnerOrAdminId = null; + + do { + const companyUsers = await globalResolver.services.companies.companyUserRepository.find( + { group_id: companyId }, + { pagination }, + context, + ); + + pagination = companyUsers.nextPage as Pagination; + + const companyAdminOrOwner = companyUsers + .getEntities() + .find(({ role }) => ["admin", "owner"].includes(role)); + + if (companyAdminOrOwner) { + companyOwnerOrAdminId = companyAdminOrOwner.id; + } + } while (pagination && !companyOwnerOrAdminId); + + return companyOwnerOrAdminId; + }; + + /** + * Compute the Access Information for the workspace folder to be created. + * + * @param {Workspace} workspace - the target workspace + * @param {Company} company - the target company + * @param {WorkspaceExecutionContext} context - the execution context + * @returns {Promise<AccessInformation>} + */ + private getWorkspaceAccess = async ( + workspace: Workspace, + company: Company, + context: WorkspaceExecutionContext, + ): Promise<AccessInformation> => { + const companyUsersCount = await globalResolver.services.companies.getUsersCount(company.id); + const workspaceUsersCount = await globalResolver.services.workspaces.getUsersCount( + workspace.id, + ); + + if (companyUsersCount === workspaceUsersCount) { + return { + entities: [ + { + id: "parent", + type: "folder", + level: "manage", + }, + { + id: company.id, + type: "company", + level: "none", + }, + { + id: context.user?.id, + type: "user", + level: "manage", + }, + ], + public: { + level: "none", + token: generateAccessToken(), + }, + }; + } + + let workspaceUsers: WorkspaceUser[] = []; + let wsUsersPagination: Pagination = { limitStr: "100" }; + + do { + const wsUsersQuery = await globalResolver.services.workspaces.getUsers( + { workspaceId: workspace.id }, + wsUsersPagination, + context, + ); + wsUsersPagination = wsUsersQuery.nextPage as Pagination; + + workspaceUsers = [...workspaceUsers, ...wsUsersQuery.getEntities()]; + } while (wsUsersPagination.page_token); + + if (companyUsersCount < 30 || workspaceUsersCount < 30) { + return { + entities: [ + { + id: "parent", + type: "folder", + level: "none", + }, + { + id: company.id, + type: "company", + level: "none", + }, + { + id: context.user?.id, + type: "user", + level: "manage", + }, + ...workspaceUsers.reduce((acc, curr) => { + acc = [ + ...acc, + { + id: curr.userId, + type: "user", + level: "manage", + }, + ]; + + return acc; + }, []), + ], + public: { + level: "none", + token: generateAccessToken(), + }, + }; + } + + let companyUsers: CompanyUser[] = []; + let companyUsersPaginations: Pagination = { limitStr: "100" }; + do { + const companyUsersQuery = await globalResolver.services.companies.getUsers( + { group_id: company.id }, + companyUsersPaginations, + {}, + context, + ); + companyUsersPaginations = companyUsersQuery.nextPage as Pagination; + companyUsers = [...companyUsers, ...companyUsersQuery.getEntities()]; + } while (companyUsersPaginations.page_token); + return { + entities: [ + { + id: "parent", + type: "folder", + level: "none", + }, + { + id: company.id, + type: "company", + level: "manage", + }, + { + id: context.user?.id, + type: "user", + level: "manage", + }, + ...companyUsers.reduce((acc, curr) => { + if (workspaceUsers.find(({ userId }) => curr.user_id === userId)) { + return acc; + } + + acc = [ + ...acc, + { + id: curr.user_id, + type: "user", + level: "none", + }, + ]; + + return acc; + }, []), + ], + public: { + level: "none", + token: generateAccessToken(), + }, + }; + }; + + /** + * Creates a folder for the workspace to migrate. + * + * @param {Workspace} workspace - the workspace to migrate. + * @param {AccessInformation} access - the access information. + * @param {WorkspaceExecutionContext} context - the execution context + * @returns {Promise<DriveFile>} + */ + private createWorkspaceFolder = async ( + workspace: Workspace, + access: AccessInformation, + context: WorkspaceExecutionContext, + ): Promise<DriveFile> => { + const workspaceFolder = getDefaultDriveItem( + { + name: workspace.name || workspace.id, + extension: "", + content_keywords: "", + creator: context.user.id, + is_directory: true, + is_in_trash: false, + description: "", + tags: [], + parent_id: "root", + company_id: context.company.id, + access_info: access, + }, + context, + ); + + await this.nodeRepository.save(workspaceFolder); + await this.phpDriveService.markAsMigrated(workspace.id, workspaceFolder.id, context.company.id); + + return workspaceFolder; + }; +} + +export default DriveMigrator; diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/php-drive-file/php-drive-file-entity.ts b/twake/backend/node/src/cli/cmds/migration_cmds/php-drive-file/php-drive-file-entity.ts new file mode 100644 index 00000000..05b32680 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/php-drive-file/php-drive-file-entity.ts @@ -0,0 +1,64 @@ +import { Type } from "class-transformer"; +import { + Column, + Entity, +} from "../../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "drive_file"; + +@Entity(TYPE, { + primaryKey: [["workspace_id"], "parent_id", "id"], + type: TYPE, +}) +export class PhpDriveFile { + @Type(() => String) + @Column("workspace_id", "timeuuid") + workspace_id: string; + + @Type(() => String) + @Column("parent_id", "string") + parent_id: string | ""; + + @Type(() => String) + @Column("id", "timeuuid", { generator: "timeuuid" }) + id: string; + + @Column("isintrash", "boolean") + isintrash: boolean; + + @Column("added", "string") + added: string; + + @Column("attachements", "encoded_json") + attachements: unknown; + + @Column("content_keywords", "encoded_json") + content_keywords: string[] | null; + + @Column("creator", "string") + creator: string; + + @Column("description", "string") + description: string; + + @Column("extension", "string") + extension: string; + + @Column("hidden_data", "encoded_json") + hidden_data: unknown; + + @Column("isdirectory", "boolean") + isdirectory: boolean; + + @Column("last_modified", "string") + last_modified: string; + + @Column("name", "encoded_string") + name: string; + + @Column("size", "number") + size: number; + + @Column("tags", "encoded_json") + tags: string[] | null; +} diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/php-drive-file/php-drive-file-version-entity.ts b/twake/backend/node/src/cli/cmds/migration_cmds/php-drive-file/php-drive-file-version-entity.ts new file mode 100644 index 00000000..69ecdd05 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/php-drive-file/php-drive-file-version-entity.ts @@ -0,0 +1,58 @@ +import { Type } from "class-transformer"; +import { + Column, + Entity, +} from "../../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "drive_file_version"; + +@Entity(TYPE, { + primaryKey: [["file_id"], "id"], + type: TYPE, +}) +export class PhpDriveFileVersion { + @Type(() => String) + @Column("id", "timeuuid", { generator: "timeuuid" }) + id: string; + + @Type(() => String) + @Column("file_id", "string") + file_id: string; + + @Type(() => String) + @Column("creator_id", "string") + creator_id: string; + + @Type(() => String) + @Column("realname", "encoded_string") + realname: string; + + @Type(() => String) + @Column("key", "string") + key: string; + + @Type(() => String) + @Column("mode", "string") + mode: string; + + @Type(() => String) + @Column("file_size", "number") + file_size: number; + + @Type(() => String) + @Column("date_added", "string") + date_added: string; + + @Type(() => String) + @Column("filename", "encoded_string") + filename: string; + + @Type(() => String) + @Column("provider", "string") + provider: string; + + @Column("data", "encoded_json") + data: unknown; +} + +export type PhpDriveFileVersionPrimaryKey = Pick<PhpDriveFileVersion, "file_id" | "id">; diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/php-drive-file/php-drive-migration-record-entity.ts b/twake/backend/node/src/cli/cmds/migration_cmds/php-drive-file/php-drive-migration-record-entity.ts new file mode 100644 index 00000000..0461d6b0 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/php-drive-file/php-drive-migration-record-entity.ts @@ -0,0 +1,25 @@ +import { Type } from "class-transformer"; +import { + Column, + Entity, +} from "../../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "php_drive_migration_record"; + +@Entity(TYPE, { + primaryKey: [["company_id"], "item_id"], + type: TYPE, +}) +export class phpDriveMigrationRecord { + @Type(() => String) + @Column("item_id", "timeuuid") + item_id: string; + + @Type(() => String) + @Column("company_id", "uuid") + company_id: string; + + @Type(() => String) + @Column("new_id", "string") + new_id: string; +} diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/php-drive-file/php-drive-service.ts b/twake/backend/node/src/cli/cmds/migration_cmds/php-drive-file/php-drive-service.ts new file mode 100644 index 00000000..9397a031 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/php-drive-file/php-drive-service.ts @@ -0,0 +1,189 @@ +import { + ExecutionContext, + ListResult, + Pagination, +} from "../../../../core/platform/framework/api/crud-service"; +import Repository from "../../../../core/platform/services/database/services/orm/repository/repository"; +import globalResolver from "../../../../services/global-resolver"; +import { PhpDriveFile, TYPE as DRIVE_FILE_TABLE } from "./php-drive-file-entity"; +import { Initializable, logger, TwakeServiceProvider } from "../../../../core/platform/framework"; +import { + PhpDriveFileVersion, + TYPE as DRIVE_FILE_VERSION_TABLE, +} from "./php-drive-file-version-entity"; +import axios from "axios"; +import { Multipart } from "fastify-multipart"; +import { CompanyExecutionContext } from "../../../../services/files/web/types"; +import { File } from "../../../../services/files/entities/file"; +import { UploadOptions } from "../../../../services/files/types"; +import { + phpDriveMigrationRecord, + TYPE as MIGRATION_RECORD_TABLE, +} from "./php-drive-migration-record-entity"; + +export interface MigrateOptions extends UploadOptions { + userId: string; +} + +export interface PhpDriveServiceAPI extends TwakeServiceProvider, Initializable {} + +export class PhpDriveFileService implements PhpDriveServiceAPI { + version: "1"; + public repository: Repository<PhpDriveFile>; + public versionRepository: Repository<PhpDriveFileVersion>; + public migrationRepository: Repository<phpDriveMigrationRecord>; + + /** + * Init the service. + * + * @returns {PhpDriveFileService} + */ + async init(): Promise<this> { + this.repository = await globalResolver.database.getRepository<PhpDriveFile>( + DRIVE_FILE_TABLE, + PhpDriveFile, + ); + + this.versionRepository = await globalResolver.database.getRepository<PhpDriveFileVersion>( + DRIVE_FILE_VERSION_TABLE, + PhpDriveFileVersion, + ); + + this.migrationRepository = await globalResolver.database.getRepository<phpDriveMigrationRecord>( + MIGRATION_RECORD_TABLE, + phpDriveMigrationRecord, + ); + + return this; + } + + /** + * Lists the drive item directory children. + * + * @param {Pagination} pagination - the page. + * @param {string} directory - the drive item / directory id to search within. + * @param {string} workspaceId - the workspace id + * @param {ExecutionContext} context - the execution context. + * @returns {Promise<ListResult<PhpDriveFile>>} - the drive item children. + */ + listDirectory = async ( + pagination: Pagination, + directory: string | "" | "trash", + workspaceId: string, + context?: ExecutionContext, + ): Promise<ListResult<PhpDriveFile>> => + await this.repository.find( + { + workspace_id: workspaceId, + parent_id: directory, + }, + { pagination }, + context, + ); + + /** + * Lists the versions of a drive item. + * + * @param {Pagination} pagination - the page. + * @param {string} itemId - the drive item id. + * @param {ExecutionContext} context - the execution context. + * @returns {Promise<ListResult<PhpDriveFileVersion>>} - the list of the item versions. + */ + listItemVersions = async ( + pagination: Pagination, + itemId: string, + context?: ExecutionContext, + ): Promise<ListResult<PhpDriveFileVersion>> => + await this.versionRepository.find( + { + file_id: itemId, + }, + { pagination }, + context, + ); + + /** + * Downloads a file version from the old drive and uploads it to the new Drive. + * + * @param {string} fileId - the old file id + * @param {string} workspaceId - the workspace id + * @param {string} versionId - the version id + * @param {MigrateOptions} options - the file upload / migration options. + * @param {CompanyExecutionContext} context - the company execution context. + * @param {string} public_access_key - the file public access key. + * @returns {Promise<File>} - the uploaded file information. + */ + migrate = async ( + fileId: string, + workspaceId: string, + versionId: string, + options: MigrateOptions, + context: CompanyExecutionContext, + public_access_key?: string, + ): Promise<File> => { + try { + const url = `https://web.twake.app/ajax/drive/download?workspace_id=${workspaceId}&element_id=${fileId}&version_id=${versionId}&download=1${ + public_access_key ? `&public_access_key=${public_access_key}` : "" + }`; + + const response = await axios.get(url, { + responseType: "stream", + }); + + if (!response.data) { + throw Error("invalid download response"); + } + + const file = { + file: response.data, + }; + + return await globalResolver.services.files.save(null, file as Multipart, options, { + ...context, + user: { + id: options.userId, + }, + }); + } catch (error) { + logger.error(`Failed to migrate file ${fileId} on workspace ${workspaceId}`, error); + throw Error(error); + } + }; + + /** + * Saves a drive item. + * + * @param {PhpDriveFile} item - the php drive item. + * @returns {Promise<void>} + */ + save = async (item: PhpDriveFile): Promise<void> => await this.repository.save(item); + + /** + * Marks a drive item as migrated. + * + * @param {string} itemId - the drive item. + * @param {string} newId - the new drive item id. + * @param {string} companyId - the company id. + */ + markAsMigrated = async (itemId: string, newId: string, companyId: string): Promise<void> => { + const migrationRecord = new phpDriveMigrationRecord(); + migrationRecord.item_id = itemId; + migrationRecord.new_id = newId; + migrationRecord.company_id = companyId; + + await this.migrationRepository.save(migrationRecord); + }; + + /** + * Fetches the drive item migration record. + * + * @param {string} itemId - the drive item id. + * @param {string} companyId - the company id. + * @returns {Promise<boolean>} + */ + getMigrationRecord = async ( + itemId: string, + companyId: string, + ): Promise<phpDriveMigrationRecord> => + await this.migrationRepository.findOne({ item_id: itemId, company_id: companyId }); +} diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/php-message/message-migrator-service.ts b/twake/backend/node/src/cli/cmds/migration_cmds/php-message/message-migrator-service.ts new file mode 100644 index 00000000..fa4199a0 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/php-message/message-migrator-service.ts @@ -0,0 +1,560 @@ +import { PhpMessagesService } from "./php-message-service"; +import { convertUuidV4ToV1 } from "./utils"; +import Company from "../../../../services/user/entities/company"; +import { Pagination } from "../../../../core/platform/framework/api/crud-service"; +import { PhpMessage } from "./php-message-entity"; +import { TwakePlatform } from "../../../../core/platform/platform"; +import { + Message, + MessageEdited, + MessageOverride, + MessagePinnedInfo, + MessageReaction, +} from "../../../../services/messages/entities/messages"; +import { MessageChannelRef } from "../../../../services/messages/entities/message-channel-refs"; +import { ParticipantObject, Thread } from "../../../../services/messages/entities/threads"; +import { Block } from "../../../../services/messages/blocks-types"; +import { WorkspaceExecutionContext } from "../../../../services/workspaces/types"; +import gr from "../../../../services/global-resolver"; + +type MigratedChannel = { + id: string; + workspace_id: string; + company_id: string; + owner?: string; +}; + +type Options = { + from?: string; + onlyCompany?: string; + onlyWorkspace?: string; + onlyChannel?: string; + ignoreExisting?: boolean; + backToPhp?: boolean; + dryRun?: boolean; +}; +class MessageMigrator { + private phpMessageService: PhpMessagesService; + private migratedMessages = 0; + private options: Options = {}; + + constructor(readonly _platform: TwakePlatform) { + this.phpMessageService = new PhpMessagesService(); + } + + public async run(options: Options = {}): Promise<void> { + await gr.doInit(this._platform); + this.options = options; + + await this.phpMessageService.init(); + + if (this.options.onlyCompany) { + const company = await gr.services.companies.getCompany({ id: options.onlyCompany }); + await this.migrateCompanyMessages(company); + } else { + let waitForCompany = false; + if (this.options.from) { + waitForCompany = true; + } + + // Get all companies + let page: Pagination = { limitStr: "100" }; + // For each companies find workspaces + do { + const companyListResult = await gr.services.companies.getCompanies(page); + page = companyListResult.nextPage as Pagination; + + for (const company of companyListResult.getEntities()) { + if (waitForCompany && this.options.from == `${company.id}`) { + waitForCompany = false; + } + + if (!waitForCompany) { + await this.migrateCompanyMessages(company); + } + } + } while (page.page_token); + } + + console.log( + `Php Messages successfully migrated to node: (${this.migratedMessages} messages) !`, + ); + } + + private async migrateCompanyMessages(company: Company) { + console.log(`Start migration for ${company.id}...`); + + if (!this.options.onlyWorkspace || this.options.onlyWorkspace === "direct") { + await this.migrateCompanyDirectMessages(company); + console.log( + `${company.id} - (1/2) migrated direct messages (total: ${this.migratedMessages} messages) βœ…`, + ); + } + + if (!this.options.onlyWorkspace || this.options.onlyWorkspace !== "direct") { + await this.migrateCompanyChannelsMessages(company); + console.log(`${company.id} - (2/2) completed (total: ${this.migratedMessages} messages) βœ…`); + } + } + + /** + * Set all direct messages in company and set them to channelPhpMessages + */ + private async migrateCompanyDirectMessages(company: Company) { + await gr.doInit(this._platform); + let pageDirectChannels: Pagination = { limitStr: "100" }; + // For each directChannels find messages + do { + const directChannelsInCompanyResult = await gr.services.channels.channels.list( + pageDirectChannels, + {}, + { + workspace: { + workspace_id: "direct", + company_id: company.id, + }, + user: { id: null, server_request: true }, + }, + ); + + pageDirectChannels = directChannelsInCompanyResult.nextPage as Pagination; + + for (const directChannel of directChannelsInCompanyResult.getEntities()) { + await this.migrateChannelsMessages(company, { + id: directChannel.id, + workspace_id: "direct", + company_id: directChannel.company_id, + }); + } + } while (pageDirectChannels.page_token); + } + + /** + * Set all messages in company and set them to channelPhpMessages + */ + private async migrateCompanyChannelsMessages(company: Company) { + await gr.doInit(this._platform); + + // Get all workspaces in company + const workspacesInCompany = ( + await gr.services.workspaces.list({ limitStr: "" }, {}, { + user: { + id: null, + server_request: true, + }, + company_id: company.id, + } as WorkspaceExecutionContext) + ).getEntities(); + + // For each workspaces find channels + for (const workspace of workspacesInCompany) { + if (this.options.onlyWorkspace && `${workspace.id}` !== this.options.onlyWorkspace) { + continue; + } + + // Get all channels in workspace + let pageChannels: Pagination = { limitStr: "1" }; + do { + const channelsInWorkspace = await gr.services.channels.channels.list( + pageChannels, + {}, + { + workspace: { + workspace_id: workspace.id, + company_id: workspace.company_id, + }, + user: { id: null, server_request: true }, + }, + ); + pageChannels = channelsInWorkspace.nextPage as Pagination; + + // For each channels find messages + for (const channel of channelsInWorkspace.getEntities()) { + await this.migrateChannelsMessages(company, { + id: channel.id, + workspace_id: channel.workspace_id, + company_id: channel.company_id, + owner: channel.owner, + }); + } + } while (pageChannels.page_token); + } + } + + //Params: company, channel + private async migrateChannelsMessages(company: Company, channel: MigratedChannel) { + if (this.options.onlyChannel && `${channel.id}` !== this.options.onlyChannel) { + return; + } + + if (this.options.backToPhp) { + await this.migrateChannelsMessagesBackToPhp(company, channel); + return; + } + + //This function will migrate all messages in a channel + let pagePhpMessages: Pagination = { limitStr: "100" }; + do { + const messages = await this.phpMessageService.list( + pagePhpMessages, + {}, + { + channel_id: convertUuidV4ToV1(channel.id), + user: { id: null, server_request: true }, + }, + ); + + for (const message of messages.getEntities()) { + try { + await this.migrateMessage(company, channel, message); + } catch (err) { + console.log(err); + } + } + + pagePhpMessages = messages.nextPage as Pagination; + } while (pagePhpMessages.page_token); + } + + private migratedThreads: string[] = []; + + /** + * Migrate php message to node + * @param company + * @param channel + * @param message + */ + private async migrateMessage(company: Company, channel: MigratedChannel, message: PhpMessage) { + if (!message.id) { + return; + } + await gr.doInit(this._platform); + //Create thread first if not exists + const threadId = message.parent_message_id || message.id; + + if (this.options.ignoreExisting) { + const msg = await gr.services.messages.messages.get({ + thread_id: threadId, + id: message.id, + }); + if (msg) { + return; + } + } + + const threadDoesNotExists = !this.migratedThreads.includes(threadId); + if (threadDoesNotExists) { + await this.migratePhpMessageToNodeThread(message, channel, company); + this.migratedThreads.push(threadId); + } + + //Migrate message itself + await this.migratePhpMessageToNodeMessage(threadId, message, company); + + this.migratedMessages++; + + if (this.migratedMessages % 100 == 0) { + console.log(`${company.id} - ... (total: ${this.migratedMessages} messages)`); + } + + //Force delay between channels + await new Promise(r => { + setTimeout(r, 40); + }); + } + + private async migrateChannelsMessagesBackToPhp(company: Company, channel: MigratedChannel) { + await gr.doInit(this._platform); + const channelRefRepository = await gr.database.getRepository( + "message_channel_refs", + MessageChannelRef, + ); + const messageRepository = await gr.database.getRepository("messages", Message); + + //This function will migrate all messages in a channel + let pageMessages: Pagination = { limitStr: "100" }; + do { + const messages = await channelRefRepository.find( + { + company_id: company.id, + workspace_id: channel.workspace_id, + channel_id: channel.id, + }, + { pagination: pageMessages }, + undefined, + ); + + for (const messageRef of messages.getEntities()) { + const messages = await messageRepository.find( + { + thread_id: messageRef.thread_id, + }, + {}, + undefined, + ); + + for (const message of messages.getEntities()) { + const uuidv1_channel_id = + channel.id.substring(0, 14) + "1" + channel.id.substring(14 + 1); + + let phpMessage = await this.phpMessageService.get({ + id: message.id, + }); + + if (!phpMessage) { + phpMessage = await this.phpMessageService.get({ + channel_id: uuidv1_channel_id, + parent_message_id: message.thread_id, + id: message.id, + }); + } + + if (!phpMessage && message.subtype !== "deleted") { + //This message doesn't exists in php, move it to php + + const newPhpMessage = new PhpMessage(); + newPhpMessage.id = message.id; + newPhpMessage.channel_id = uuidv1_channel_id; + newPhpMessage.parent_message_id = message.thread_id; + newPhpMessage.application_id = message.application_id || null; + newPhpMessage.modification_date = Math.floor( + message.edited?.edited_at || message.created_at, + ); + newPhpMessage.creation_date = Math.floor(message.created_at); + newPhpMessage.sender = message.user_id; + newPhpMessage.pinned = !!message.pinned_info?.pinned_at; + newPhpMessage.edited = !!message.edited?.edited_at; + newPhpMessage.message_type = + message.subtype === "application" ? 1 : message.subtype === "system" ? 2 : 0; + newPhpMessage.hidden_data = message.context; + newPhpMessage.reactions = "{}"; + newPhpMessage.responses_count = 0; + + let prepared: any[] = []; + (message.blocks || []).map(block => { + if (block.type === "twacode") { + prepared = block["elements"]; + } + if (block.type === "section" && prepared.length > 0) { + prepared = [ + { + type: "twacode", + content: block?.text?.text || "", + }, + ]; + } + }); + newPhpMessage.content = { + fallback_string: message.text, + original_str: message.text, + files: (message.files || []).map(f => { + return { + content: f, + mode: "mini", + type: "file", + }; + }), + prepared: prepared, + }; + + if (!this.options.dryRun) { + await this.phpMessageService.repository.save(newPhpMessage, undefined); + } + + this.migratedMessages++; + if (this.migratedMessages % 100 == 0) { + console.log(`${company.id} - ... (total: ${this.migratedMessages} messages)`); + } + } + } + } + + pageMessages = messages.nextPage as Pagination; + } while (pageMessages.page_token); + } + + /** + * Migrate php message to node thread + * @param message PhpMessage + * @param channel MigratedChannel + */ + private async migratePhpMessageToNodeThread( + message: PhpMessage, + channel: MigratedChannel, + company: Company, + ) { + const thread = new Thread(); + + // Set nodeThread values + thread.id = message.parent_message_id || message.id; + thread.created_at = message.creation_date; + thread.last_activity = message.modification_date; + thread.answers = 0; + thread.participants = [ + { + type: "channel", + id: channel.id, + company_id: channel.company_id, + workspace_id: channel.workspace_id, + created_at: message.creation_date, + created_by: message.sender, + } as ParticipantObject, + ]; + + if (this.options.dryRun) { + return; + } + + // Create nodeThread + return await gr.services.messages.threads.save( + thread, + {}, + { user: { id: null, server_request: true }, company }, + ); + } + + /** + * Set message string type + * @param integer 0 = null | 1 = system | 2 = application + */ + private setMessageType(integer: number): { type: Message["type"]; subtype: Message["subtype"] } { + switch (integer) { + case 1: + return { + type: "message", + subtype: "application", + }; + case 2: + return { + type: "message", + subtype: "system", + }; + case 0: + default: + return { + type: "message", + subtype: null, + }; + } + } + + /** + * Set blocks array + * @param content { [key: string]: any } + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private setBlocks(content: { [key: string]: any }): Block[] { + const blocks: Block[] = []; + + if (!content) return blocks; + + const new_block_format: Block = { + type: "twacode", + elements: content.formatted || content.prepared || content || [], + }; + + blocks.push(new_block_format); + + return blocks; + } + + /** + * Set edited message Object + * @param modification_date timestamp + */ + private setMessageEditedObject(message: PhpMessage): MessageEdited { + return message.edited ? { edited_at: message.modification_date } : null; + } + + /** + * Set pinned message Object + * @param message PhpMessage + */ + private setMessagePinnedObject(message: PhpMessage): MessagePinnedInfo { + if (message.pinned) { + return { pinned_at: 0, pinned_by: message.sender }; + } + return null; + } + + /** + * Set reactions message object + * @param reactions JSON + */ + private setMessageReactionsObject(reactions: string): MessageReaction[] { + const parsed_reactions = JSON.parse(reactions); + + if (!parsed_reactions) return []; + + const new_reactions_array: MessageReaction[] = []; + + for (const reaction_name in parsed_reactions) { + const new_reaction_object: MessageReaction = { + name: reaction_name, + users: parsed_reactions[reaction_name].users, + count: parsed_reactions[reaction_name].count, + }; + + new_reactions_array.push(new_reaction_object); + } + + return new_reactions_array; + } + + /** + * Set override message Object + * @param message PhpMessage + */ + private setMessageOverrideObject(_message: PhpMessage): MessageOverride { + return null; + } + + /** + * Migrate php message to node message + * @param message PhpMessage + */ + private async migratePhpMessageToNodeMessage( + threadId: string, + message: PhpMessage, + company: Company, + ) { + const nodeMessage = new Message(); + + // Set nodeMessage values + nodeMessage.id = message.id; + nodeMessage.thread_id = threadId; + nodeMessage.type = this.setMessageType(message.message_type).type; + nodeMessage.subtype = this.setMessageType(message.message_type).subtype; + nodeMessage.created_at = message.creation_date; + nodeMessage.user_id = message.sender; + nodeMessage.application_id = message.application_id; + nodeMessage.text = message.content?.original_str || ""; + nodeMessage.blocks = this.setBlocks(message.content); + nodeMessage.context = message.hidden_data || {}; + nodeMessage.edited = this.setMessageEditedObject(message); + nodeMessage.pinned_info = this.setMessagePinnedObject(message); + nodeMessage.reactions = this.setMessageReactionsObject(message.reactions); + nodeMessage.override = this.setMessageOverrideObject(message); + + nodeMessage.context._front_id = message.id; + + if (this.options.dryRun) { + return; + } + + // Create nodeMessage then add it to thread + return await gr.services.messages.messages.save( + nodeMessage, + { + enforceViewPropagation: true, + }, + { + user: { id: null, server_request: true }, + thread: { id: threadId }, + company: { id: company.id }, + }, + ); + } +} + +export default MessageMigrator; diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/php-message/php-message-entity.ts b/twake/backend/node/src/cli/cmds/migration_cmds/php-message/php-message-entity.ts new file mode 100644 index 00000000..0623db4b --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/php-message/php-message-entity.ts @@ -0,0 +1,67 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { + Column, + Entity, +} from "../../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "message"; +@Entity(TYPE, { + primaryKey: [["channel_id"], "parent_message_id", "id"], + type: TYPE, +}) +export class PhpMessage { + @Type(() => String) + @Column("id", "timeuuid", { generator: "timeuuid" }) + id: string; + + @Type(() => String) + @Column("channel_id", "timeuuid") + channel_id: string; + + @Type(() => String) + @Column("parent_message_id", "encoded_string") + parent_message_id: string; + + @Type(() => String) + @Column("application_id", "encoded_string") + application_id: string | null; + + @Column("modification_date", "twake_datetime") + modification_date: number | null; + + @Column("creation_date", "twake_datetime") + creation_date: number; + + @Column("message_type", "number") + message_type: number; + + @Column("sender_id", "timeuuid") + sender: string; + + @Column("content", "encoded_json") + // eslint-disable-next-line @typescript-eslint/no-explicit-any + content: { [key: string]: any } | null; + + @Column("hidden_data", "encoded_json") + // eslint-disable-next-line @typescript-eslint/no-explicit-any + hidden_data: { [key: string]: any } | null; + + @Column("reactions", "encoded_string") + reactions: string | null; + + @Column("pinned", "twake_boolean") + pinned: boolean; + + @Column("edited", "twake_boolean") + edited: boolean; + + @Column("responses_count", "twake_int") + responses_count: number | null; +} + +export type PhpMessagePrimaryKey = Pick<PhpMessage, "parent_message_id" | "channel_id" | "id">; + +export function getInstance(message: PhpMessage): PhpMessage { + return merge(new PhpMessage(), message); +} diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/php-message/php-message-service.ts b/twake/backend/node/src/cli/cmds/migration_cmds/php-message/php-message-service.ts new file mode 100644 index 00000000..5995a24f --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/php-message/php-message-service.ts @@ -0,0 +1,59 @@ +import { + DeleteResult, + ExecutionContext, + ListResult, + Pagination, +} from "../../../../core/platform/framework/api/crud-service"; +import Repository, { + FindFilter, +} from "../../../../core/platform/services/database/services/orm/repository/repository"; +import { PhpMessagesServiceAPI } from "./types"; +import { PhpMessage, PhpMessagePrimaryKey } from "./php-message-entity"; +import gr from "../../../../services/global-resolver"; + +export interface PhpMessageExecutionContext extends ExecutionContext { + channel_id: string; + parent_message_id?: string; + id?: string; +} + +export class PhpMessagesService implements PhpMessagesServiceAPI { + version: "1"; + public repository: Repository<PhpMessage>; + + async init(): Promise<this> { + this.repository = await gr.database.getRepository<PhpMessage>("message", PhpMessage); + return this; + } + + get(pk: { parent_message_id?: string; channel_id?: string; id: string }): Promise<PhpMessage> { + if (pk.channel_id) { + pk.channel_id = `${pk.channel_id}`; + pk.channel_id.substring(0, 14) + "1" + pk.channel_id.substring(14 + 1); + } + return this.repository.findOne(pk, {}, undefined); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async delete(pk: PhpMessagePrimaryKey): Promise<DeleteResult<PhpMessage>> { + throw Error("not implemented"); + } + + async list<ListOptions>( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + pagination: Pagination, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + options?: ListOptions, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + context?: PhpMessageExecutionContext, + ): Promise<ListResult<PhpMessage>> { + const findFilter: FindFilter = { + channel_id: context.channel_id, + parent_message_id: context.parent_message_id, + //id: context.id, + }; + + const list = await this.repository.find(findFilter, { pagination }, undefined); + return list; + } +} diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/php-message/types.ts b/twake/backend/node/src/cli/cmds/migration_cmds/php-message/types.ts new file mode 100644 index 00000000..067e7abc --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/php-message/types.ts @@ -0,0 +1,3 @@ +import { Initializable, TwakeServiceProvider } from "../../../../core/platform/framework"; + +export interface PhpMessagesServiceAPI extends TwakeServiceProvider, Initializable {} diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/php-message/utils.ts b/twake/backend/node/src/cli/cmds/migration_cmds/php-message/utils.ts new file mode 100644 index 00000000..61334010 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/php-message/utils.ts @@ -0,0 +1,11 @@ +export const convertUuidV4ToV1 = (str: string): string => { + const uuid = [...str]; + uuid[14] = "1"; + return uuid.join(""); +}; + +export const convertUuidV1ToV4 = (str: string): string => { + const uuid = [...str]; + uuid[14] = "4"; + return uuid.join(""); +}; diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/php-workspace/php-workspace-entity.ts b/twake/backend/node/src/cli/cmds/migration_cmds/php-workspace/php-workspace-entity.ts new file mode 100644 index 00000000..9ad04b4f --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/php-workspace/php-workspace-entity.ts @@ -0,0 +1,45 @@ +import { merge } from "lodash"; +import { + Column, + Entity, +} from "../../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "workspace"; +@Entity(TYPE, { + primaryKey: [["id"]], + type: TYPE, +}) +export class PhpWorkspace { + @Column("id", "timeuuid") + id: string; + + @Column("group_id", "timeuuid") + group_id: string; + + @Column("name", "encoded_string") + name: string; + + @Column("logo", "encoded_string") + logo: string; + + @Column("stats", "encoded_string") + stats: string; + + @Column("is_deleted", "boolean") + isDeleted: boolean; + + @Column("is_archived", "boolean") + isArchived: boolean; + + @Column("is_default", "boolean") + isDefault: boolean; + + @Column("date_added", "number") + dateAdded: number; +} + +export type PhpMessagePrimaryKey = Pick<PhpWorkspace, "id">; + +export function getInstance(workspace: PhpWorkspace): PhpWorkspace { + return merge(new PhpWorkspace(), workspace); +} diff --git a/twake/backend/node/src/cli/cmds/migration_cmds/workspace.ts b/twake/backend/node/src/cli/cmds/migration_cmds/workspace.ts new file mode 100644 index 00000000..96a17ef7 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/migration_cmds/workspace.ts @@ -0,0 +1,148 @@ +import yargs from "yargs"; +import twake from "../../../twake"; +import ora from "ora"; +import { TwakePlatform } from "../../../core/platform/platform"; +import { DatabaseServiceAPI } from "../../../core/platform/services/database/api"; +import { PhpWorkspace, TYPE as phpTYPE } from "./php-workspace/php-workspace-entity"; +import { Pagination } from "../../../core/platform/framework/api/crud-service"; +import Workspace, { TYPE, getInstance } from "../../../services/workspaces/entities/workspace"; +import _ from "lodash"; +import gr from "../../../services/global-resolver"; + +type Options = { + from?: string; + onlyCompany?: string; + onlyWorkspace?: string; + replaceExisting?: boolean; +}; + +class WorkspaceMigrator { + database: DatabaseServiceAPI; + + constructor(readonly platform: TwakePlatform) { + this.database = this.platform.getProvider<DatabaseServiceAPI>("database"); + } + + public async run(options: Options = {}): Promise<void> { + const phpRepository = await this.database.getRepository(phpTYPE, PhpWorkspace); + const repository = await this.database.getRepository(TYPE, Workspace); + + let waitForCompany = false; + if (options.from) { + waitForCompany = true; + } + + // Get all companies + let page: Pagination = { limitStr: "100" }; + // For each companies find workspaces + do { + const workspaceListResult = await phpRepository.find({}, { pagination: page }, undefined); + page = workspaceListResult.nextPage as Pagination; + + for (const workspace of workspaceListResult.getEntities()) { + if (waitForCompany && options.from == `${workspace.group_id}`) { + waitForCompany = false; + } + + if (!waitForCompany) { + if ( + (!options.onlyCompany && !options.onlyWorkspace) || + options.onlyCompany == `${workspace.group_id}` + ) { + if ( + !(await repository.findOne( + { company_id: workspace.group_id, id: workspace.id }, + {}, + undefined, + )) || + options.replaceExisting + ) { + const newWorkspace = getInstance( + _.pick( + workspace, + "id", + "company_id", + "name", + "logo", + "stats", + "is_deleted", + "is_archived", + "is_default", + "date_added", + ), + ); + newWorkspace.company_id = workspace.group_id; + await repository.save(newWorkspace, undefined); + } + } + } + } + } while (page.page_token); + } +} + +const services = [ + "storage", + "counter", + "platform-services", + "applications", + "user", + "search", + "channels", + "database", + "webserver", + "message-queue", + "workspaces", + "console", + "auth", +]; + +const command: yargs.CommandModule<unknown, unknown> = { + command: "workspace", + describe: "command that allow you to migrate php workspaces to node", + builder: { + from: { + default: null, + type: "string", + description: "Start migration from this workspace ID", + }, + onlyCompany: { + default: null, + type: "string", + description: "Migrate only this workspace ID", + }, + onlyWorkspace: { + default: null, + type: "string", + description: "Migrate only this workspace ID", + }, + replaceExisting: { + default: false, + type: "boolean", + description: "Replace already migrated workspaces", + }, + }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + handler: async argv => { + const spinner = ora({ text: "Migrating php worskpaces - " }).start(); + const platform = await twake.run(services); + await gr.doInit(platform); + const migrator = new WorkspaceMigrator(platform); + + const from = argv.from as string | null; + const onlyCompany = argv.onlyCompany as string | null; + const onlyWorkspace = argv.onlyWorkspace as string | null; + const replaceExisting = (argv.replaceExisting || false) as boolean; + + await migrator.run({ + from, + onlyCompany, + onlyWorkspace, + replaceExisting, + }); + + return spinner.stop(); + }, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/search.ts b/twake/backend/node/src/cli/cmds/search.ts new file mode 100644 index 00000000..f566288a --- /dev/null +++ b/twake/backend/node/src/cli/cmds/search.ts @@ -0,0 +1,14 @@ +import { CommandModule } from "yargs"; + +const command: CommandModule = { + describe: "Work with search middleware", + command: "search <command>", + builder: yargs => + yargs.commandDir("search_cmds", { + visit: commandModule => commandModule.default, + }), + // eslint-disable-next-line @typescript-eslint/no-empty-function + handler: () => {}, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/search_cmds/index_all.ts b/twake/backend/node/src/cli/cmds/search_cmds/index_all.ts new file mode 100644 index 00000000..a6872830 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/search_cmds/index_all.ts @@ -0,0 +1,160 @@ +import yargs from "yargs"; +import twake from "../../../twake"; +import ora from "ora"; +import { TwakePlatform } from "../../../core/platform/platform"; +import { DatabaseServiceAPI } from "../../../core/platform/services/database/api"; +import { Pagination } from "../../../core/platform/framework/api/crud-service"; + +import User, { TYPE as UserTYPE } from "../../../services/user/entities/user"; +import { Channel } from "../../../services/channels/entities"; +import Application, { + TYPE as ApplicationTYPE, +} from "../../../services/applications/entities/application"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import { SearchServiceAPI } from "../../../core/platform/services/search/api"; +import CompanyUser, { TYPE as CompanyUserTYPE } from "../../../services/user/entities/company_user"; +import { Message, TYPE as MessageTYPE } from "../../../services/messages/entities/messages"; +import gr from "../../../services/global-resolver"; +import { + MessageFile, + TYPE as MessageFileTYPE, +} from "../../../services/messages/entities/message-files"; + +type Options = { + repository?: string; + repairEntities?: boolean; +}; + +class SearchIndexAll { + database: DatabaseServiceAPI; + search: SearchServiceAPI; + + constructor(readonly platform: TwakePlatform) { + this.database = this.platform.getProvider<DatabaseServiceAPI>("database"); + this.search = this.platform.getProvider<SearchServiceAPI>("search"); + } + + public async run(options: Options = {}): Promise<void> { + const repositories: Map<string, Repository<any>> = new Map(); + repositories.set("messages", await this.database.getRepository(MessageTYPE, Message)); + repositories.set( + "message_files", + await this.database.getRepository(MessageFileTYPE, MessageFile), + ); + repositories.set("users", await this.database.getRepository(UserTYPE, User)); + repositories.set("channels", await this.database.getRepository("channels", Channel)); + repositories.set( + "applications", + await this.database.getRepository(ApplicationTYPE, Application), + ); + + const repository = repositories.get(options.repository); + if (!repository) { + throw ( + "No such repository ready for indexation, available are: " + + Array.from(repositories.keys()).join(", ") + ); + } + + // Complete user with companies in cache + if (options.repository === "users" && options.repairEntities) { + console.log("Complete user with companies in cache"); + const companiesUsersRepository = await this.database.getRepository( + CompanyUserTYPE, + CompanyUser, + ); + const userRepository = await this.database.getRepository(UserTYPE, User); + let page: Pagination = { limitStr: "100" }; + // For each rows + do { + const list = await userRepository.find({}, { pagination: page }, undefined); + + for (const user of list.getEntities()) { + const companies = await companiesUsersRepository.find( + { user_id: user.id }, + {}, + undefined, + ); + + user.cache ||= { companies: [] }; + user.cache.companies = companies.getEntities().map(company => company.group_id); + await repositories.get("users").save(user, undefined); + } + + page = list.nextPage as Pagination; + await new Promise(r => setTimeout(r, 200)); + } while (page.page_token); + } + + console.log("Start indexing..."); + let count = 0; + // Get all items + let page: Pagination = { limitStr: "100" }; + do { + console.log("Indexed " + count + " items..."); + const list = await repository.find({}, { pagination: page }, undefined); + page = list.nextPage as Pagination; + await this.search.upsert(list.getEntities()); + count += list.getEntities().length; + await new Promise(r => setTimeout(r, 200)); + } while (page.page_token); + + console.log("Emptying flush (10s)..."); + await new Promise(r => setTimeout(r, 10000)); + + console.log("Done!"); + } +} + +const services = [ + "search", + "database", + "webserver", + "auth", + "counter", + "cron", + "message-queue", + "push", + "realtime", + "storage", + "tracker", + "websocket", +]; + +const command: yargs.CommandModule<unknown, unknown> = { + command: "index", + describe: "command to reindex search middleware from db entities", + builder: { + repository: { + default: "", + type: "string", + description: "Choose a repository to reindex", + }, + repairEntities: { + default: false, + type: "boolean", + description: "Choose to repair entities too when possible", + }, + }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + handler: async argv => { + const spinner = ora({ text: "Reindex repository - " }).start(); + const platform = await twake.run(services); + await gr.doInit(platform); + const migrator = new SearchIndexAll(platform); + + const repository = (argv.repository || "") as string; + + if (!repository) { + throw "No repository was set."; + } + + await migrator.run({ + repository, + }); + + return spinner.stop(); + }, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/users.ts b/twake/backend/node/src/cli/cmds/users.ts new file mode 100644 index 00000000..02fb151d --- /dev/null +++ b/twake/backend/node/src/cli/cmds/users.ts @@ -0,0 +1,14 @@ +import { CommandModule } from "yargs"; + +const command: CommandModule = { + describe: "Manage Twake Users", + command: "users <command>", + builder: yargs => + yargs.commandDir("users_cmds", { + visit: commandModule => commandModule.default, + }), + // eslint-disable-next-line @typescript-eslint/no-empty-function + handler: () => {}, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/users_cmds/remove.ts b/twake/backend/node/src/cli/cmds/users_cmds/remove.ts new file mode 100644 index 00000000..f9304309 --- /dev/null +++ b/twake/backend/node/src/cli/cmds/users_cmds/remove.ts @@ -0,0 +1,85 @@ +import yargs from "yargs"; +import ora from "ora"; +import twake from "../../../twake"; +import Table from "cli-table"; +import { exit } from "process"; +import gr from "../../../services/global-resolver"; + +/** + * Merge command parameters. Check the builder definition below for more details. + */ +type CLIArgs = { + id: string; +}; + +const services = [ + "storage", + "counter", + "message-queue", + "platform-services", + "user", + "search", + "database", + "webserver", + "statistics", + "applications", + "auth", + "realtime", + "websocket", +]; + +const command: yargs.CommandModule<unknown, CLIArgs> = { + command: "remove", + describe: "command that allow you to remove one user", + builder: { + id: { + default: "", + type: "string", + description: "User ID", + }, + }, + handler: async argv => { + const tableBefore = new Table({ + head: ["User ID", "Username", "Deleted"], + colWidths: [40, 40, 10], + }); + const tableAfter = new Table({ + head: ["User ID", "Username", "Deleted"], + colWidths: [40, 40, 10], + }); + const spinner = ora({ text: "Retrieving user" }).start(); + + const platform = await twake.run(services); + await gr.doInit(platform); + + const user = await gr.services.users.get({ id: argv.id }); + + if (!user) { + console.error("Error: You need to provide User ID"); + return spinner.stop(); + } + + if (user) { + // Table before + tableBefore.push([user.id, user.username_canonical, user.deleted]); + + await gr.services.users.anonymizeAndDelete( + { id: user.id }, + { + user: { id: user.id, server_request: true }, + }, + ); + + const finalUser = await gr.services.users.get({ id: argv.id }); + + // Table after + tableAfter.push([finalUser.id, finalUser.username_canonical, finalUser.deleted]); + + spinner.stop(); + } + + exit(); + }, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/workspace.ts b/twake/backend/node/src/cli/cmds/workspace.ts new file mode 100644 index 00000000..9eb9bd8b --- /dev/null +++ b/twake/backend/node/src/cli/cmds/workspace.ts @@ -0,0 +1,14 @@ +import { CommandModule } from "yargs"; + +const command: CommandModule = { + describe: "Manage Twake Workspaces", + command: "workspace <command>", + builder: yargs => + yargs.commandDir("workspace_cmds", { + visit: commandModule => commandModule.default, + }), + // eslint-disable-next-line @typescript-eslint/no-empty-function + handler: () => {}, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/workspace_cmds/list.ts b/twake/backend/node/src/cli/cmds/workspace_cmds/list.ts new file mode 100644 index 00000000..910f1f4c --- /dev/null +++ b/twake/backend/node/src/cli/cmds/workspace_cmds/list.ts @@ -0,0 +1,47 @@ +import yargs from "yargs"; +import ora from "ora"; +import Table from "cli-table"; +import twake from "../../../twake"; +import gr from "../../../services/global-resolver"; +/** + * Merge command parameters. Check the builder definition below for more details. + */ +type ListParams = { + size: string; +}; + +const services = [ + "platform-services", + "user", + "search", + "channels", + "notifications", + "database", + "webserver", + "message-queue", +]; + +const command: yargs.CommandModule<ListParams, ListParams> = { + command: "list", + describe: "List Twake workspaces", + builder: { + size: { + default: "50", + type: "string", + description: "Number of workspaces to fetch", + }, + }, + handler: async argv => { + const table = new Table({ head: ["ID", "Name"], colWidths: [40, 50] }); + const spinner = ora({ text: "List Twake workspaces" }).start(); + const platform = await twake.run(services); + await gr.doInit(platform); + const workspaces = await gr.services.workspaces.list({ limitStr: argv.size }); + + spinner.stop(); + workspaces.getEntities().forEach(ws => table.push([ws.id, ws.name])); + console.log(table.toString()); + }, +}; + +export default command; diff --git a/twake/backend/node/src/cli/cmds/workspace_cmds/user.ts b/twake/backend/node/src/cli/cmds/workspace_cmds/user.ts new file mode 100644 index 00000000..bc5b139b --- /dev/null +++ b/twake/backend/node/src/cli/cmds/workspace_cmds/user.ts @@ -0,0 +1,49 @@ +import yargs from "yargs"; +import ora from "ora"; +import Table from "cli-table"; +import twake from "../../../twake"; +import gr from "../../../services/global-resolver"; +/** + * Merge command parameters. Check the builder definition below for more details. + */ +type ListParams = { + id: string; +}; + +const services = [ + "platform-services", + "user", + "search", + "channels", + "notifications", + "database", + "webserver", + "message-queue", +]; + +const command: yargs.CommandModule<ListParams, ListParams> = { + command: "user", + describe: "List workspace ers", + builder: { + id: { + default: "f339d54a-e833-11ea-92c3-0242ac120004", + type: "string", + description: "Workspace ID", + }, + }, + handler: async argv => { + const table = new Table({ head: ["user ID", "Date Added"], colWidths: [40, 40] }); + const spinner = ora({ text: "Retrieving workspace users" }).start(); + const platform = await twake.run(services); + await gr.doInit(platform); + const users = await gr.services.workspaces.getUsers({ workspaceId: argv.id }); + + spinner.stop(); + users + .getEntities() + .forEach(u => table.push([u.id, new Date(u.dateAdded).toLocaleDateString()])); + console.log(table.toString()); + }, +}; + +export default command; diff --git a/twake/backend/node/src/cli/index.ts b/twake/backend/node/src/cli/index.ts new file mode 100644 index 00000000..c1350f05 --- /dev/null +++ b/twake/backend/node/src/cli/index.ts @@ -0,0 +1,28 @@ +import yargs from "yargs"; +import { logger } from "../core/platform/framework/logger"; + +process.env.NODE_ENV = "cli"; + +yargs + .strict() + .usage("Usage: $0 <command> [options]") + .middleware([ + argv => { + logger.level = argv.verbose ? "debug" : "fatal"; + }, + ]) + .commandDir("cmds", { + visit: commandModule => commandModule.default, + }) + .option("verbose", { + alias: "v", + default: false, + type: "boolean", + description: "Run with verbose logging", + }) + .demandCommand(1, "Please supply a valid command") + .alias("help", "h") + .help("help") + .version() + .epilogue("for more information, go to https://twake.app") + .example("$0 <command> --help", "show help of the issue command").argv; diff --git a/twake/backend/node/src/cli/utils/copy-cluster/.gitignore b/twake/backend/node/src/cli/utils/copy-cluster/.gitignore new file mode 100644 index 00000000..97008e5b --- /dev/null +++ b/twake/backend/node/src/cli/utils/copy-cluster/.gitignore @@ -0,0 +1,2 @@ +node_modules +yarn.lock \ No newline at end of file diff --git a/twake/backend/node/src/cli/utils/copy-cluster/README.md b/twake/backend/node/src/cli/utils/copy-cluster/README.md new file mode 100644 index 00000000..02fe7cc4 --- /dev/null +++ b/twake/backend/node/src/cli/utils/copy-cluster/README.md @@ -0,0 +1,4 @@ +Edit the file to your needs + +yarn install +node index.js diff --git a/twake/backend/node/src/cli/utils/copy-cluster/index.js b/twake/backend/node/src/cli/utils/copy-cluster/index.js new file mode 100644 index 00000000..e478433c --- /dev/null +++ b/twake/backend/node/src/cli/utils/copy-cluster/index.js @@ -0,0 +1,214 @@ +/* eslint-disable */ +var cassandra = require("cassandra-driver"); + +var fromAuthProvider = new cassandra.auth.PlainTextAuthProvider("", ""); +var fromContactPoints = [""]; +var fromKeyspace = "twake"; + +var toAuthProvider = new cassandra.auth.PlainTextAuthProvider("", ""); +var toContactPoints = [""]; +var toKeyspace = "twake"; + +var forceUpdateAll = false; +var ignoreTables = ["notification"]; +var countersTables = ["statistics", "stats_counter", "channel_counters", "scheduled_queue_counter"]; + +var specialConversions = { + "twake.group_user.date_added": value => { + return new Date(value).getTime(); + }, +}; + +// -- start process + +var fromClient = new cassandra.Client({ + localDataCenter: "datacenter1", + contactPoints: fromContactPoints, + authProvider: fromAuthProvider, + keyspace: fromKeyspace, +}); + +var toClient = new cassandra.Client({ + localDataCenter: "datacenter1", + contactPoints: toContactPoints, + authProvider: toAuthProvider, + keyspace: toKeyspace, + queryOptions: { + consistency: cassandra.types.consistencies.quorum, + }, +}); + +// -- Get all tables and copy schema + +async function client(origin, query, parameters, options) { + return await new Promise((resolve, reject) => { + origin.execute(query, [], {}, function (err, result) { + if (err) { + reject({ err, result }); + } else { + resolve(result); + } + }); + }); +} + +(async () => { + const result = await client( + fromClient, + "SELECT table_name from system_schema.tables WHERE keyspace_name = '" + fromKeyspace + "'", + [], + {}, + ); + for (row of result.rows) { + try { + const fromTable = fromKeyspace + "." + row.table_name; + const toTable = toKeyspace + "." + row.table_name; + + if (ignoreTables.includes(row.table_name)) { + console.log(fromTable.padEnd(50) + " | " + "ignored".padEnd(20) + " | ⏺"); + continue; + } + + let fromCount = 0; + + const destColumns = ( + await client( + toClient, + "SELECT column_name from system_schema.columns where keyspace_name = '" + + toKeyspace + + "' and table_name = '" + + row.table_name + + "'", + [], + {}, + ) + ).rows.map(r => r.column_name); + + try { + const fromResult = await client( + fromClient, + "SELECT count(*) from " + fromTable + "", + [], + {}, + ); + fromCount = parseInt(fromResult.rows[0].count); + } catch (err) { + fromCount = NaN; + } + + if (destColumns.length === 0) { + if (fromCount > 0) + console.log( + fromTable.padEnd(50) + " | " + ("not_in_dest" + "/" + fromCount).padEnd(20) + " | ⏺", + ); + continue; + } + + try { + const toResult = await client(toClient, "SELECT count(*) from " + toTable + "", [], {}); + const toCount = parseInt(toResult.rows[0].count); + + console.log( + fromTable.padEnd(50) + + " | " + + (toCount + "/" + fromCount).padEnd(20) + + " | " + + (toCount >= fromCount ? "βœ…" : "❌"), + ); + + if (row.table_name.indexOf("counter") >= 0 || countersTables.includes(row.table_name)) { + console.log( + fromTable.padEnd(50) + " | " + ("counter_table" + "/" + fromCount).padEnd(20) + " | πŸ§", + ); + if (fromCount > toCount || !fromCount || forceUpdateAll) { + await new Promise(r => { + fromClient.eachRow( + "SELECT JSON * from " + fromTable, + [], + { prepare: true, fetchSize: 1000 }, + async function (n, row) { + // + //TODO handle counters (it is special !) + }, + async function (err, result) { + if (result && result.nextPage) { + await new Promise(r => setTimeout(r, 1000)); + result.nextPage(); + } else { + r(); + } + }, + ); + }); + } + + continue; + } + + if (fromCount > toCount || !fromCount || forceUpdateAll) { + await new Promise(r => { + fromClient.eachRow( + "SELECT JSON * from " + fromTable, + [], + { prepare: true, fetchSize: 1000 }, + async function (n, row) { + try { + const json = JSON.parse(row["[json]"]); + + //The from table can have additional depreciated fields, we need to remove them + const filteredJson = {}; + for (const col of destColumns) { + if ( + typeof json[col] == "string" && + (json[col] || "").match( + /[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]+/, + ) + ) { + json[col] = json[col].split(".")[0]; + } + + if (specialConversions[fromTable + "." + col]) { + json[col] = specialConversions[fromTable + "." + col](json[col]); + } + + if (json[col] !== undefined) filteredJson[col] = json[col]; + } + + await client( + toClient, + "INSERT INTO " + + toTable + + " JSON '" + + JSON.stringify(filteredJson).replace(/'/g, "'$&") + + "'", + [], + {}, + ); + } catch (err) { + console.log(err); + } + }, + async function (err, result) { + if (result && result.nextPage) { + await new Promise(r => setTimeout(r, 1000)); + result.nextPage(); + } else { + r(); + } + }, + ); + }); + } + } catch (err) { + console.log( + fromTable.padEnd(50) + " | " + ("error" + "/" + fromCount).padEnd(20) + " | ❌", + ); + } + } catch (err) { + console.log(err); + continue; + } + + //TODO copy content + } +})(); diff --git a/twake/backend/node/src/cli/utils/copy-cluster/package.json b/twake/backend/node/src/cli/utils/copy-cluster/package.json new file mode 100644 index 00000000..4a306878 --- /dev/null +++ b/twake/backend/node/src/cli/utils/copy-cluster/package.json @@ -0,0 +1,9 @@ +{ + "name": "copy-cluster", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "dependencies": { + "cassandra-driver": "^4.6.3" + } +} diff --git a/twake/backend/node/src/cli/utils/copy-messages/.gitignore b/twake/backend/node/src/cli/utils/copy-messages/.gitignore new file mode 100644 index 00000000..97008e5b --- /dev/null +++ b/twake/backend/node/src/cli/utils/copy-messages/.gitignore @@ -0,0 +1,2 @@ +node_modules +yarn.lock \ No newline at end of file diff --git a/twake/backend/node/src/cli/utils/copy-messages/README.md b/twake/backend/node/src/cli/utils/copy-messages/README.md new file mode 100644 index 00000000..02fe7cc4 --- /dev/null +++ b/twake/backend/node/src/cli/utils/copy-messages/README.md @@ -0,0 +1,4 @@ +Edit the file to your needs + +yarn install +node index.js diff --git a/twake/backend/node/src/cli/utils/copy-messages/index.js b/twake/backend/node/src/cli/utils/copy-messages/index.js new file mode 100644 index 00000000..ddaf0d75 --- /dev/null +++ b/twake/backend/node/src/cli/utils/copy-messages/index.js @@ -0,0 +1,98 @@ +/* eslint-disable */ +var cassandra = require("cassandra-driver"); + +var fromAuthProvider = new cassandra.auth.PlainTextAuthProvider("", ""); +var fromContactPoints = [""]; + +var toAuthProvider = new cassandra.auth.PlainTextAuthProvider("", ""); +var toContactPoints = [""]; + +// -- start process + +var fromClient = new cassandra.Client({ + localDataCenter: "datacenter1", + contactPoints: fromContactPoints, + authProvider: fromAuthProvider, + keyspace: "twake", +}); + +var toClient = new cassandra.Client({ + localDataCenter: "datacenter1", + contactPoints: toContactPoints, + authProvider: toAuthProvider, + keyspace: "twake", + queryOptions: { + consistency: cassandra.types.consistencies.quorum, + }, +}); + +// -- Get all tables and copy schema + +async function client(origin, query, parameters, options) { + return await new Promise((resolve, reject) => { + origin.execute(query, [], {}, function (err, result) { + if (err) { + reject({ err, result }); + } else { + resolve(result); + } + }); + }); +} + +// Get all threads and then copy all messages in each threads + +let copiedMessages = 0; +let copiedThreads = 0; + +(async () => { + await new Promise(r => { + fromClient.eachRow( + "SELECT id from twake.threads", + [], + { prepare: true, fetchSize: 50 }, + async function (n, row) { + const threadId = row["id"]; + + console.log("Threads / Messages :", copiedThreads, "/", copiedMessages); + + copiedThreads++; + + await new Promise(r2 => { + fromClient.eachRow( + "SELECT JSON * from twake.messages where thread_id = ? order by id desc", + [threadId], + { prepare: true, fetchSize: 1000 }, + async function (n, row) { + const message = row["[json]"]; + + copiedMessages++; + + await toClient.execute( + "INSERT INTO twake.messages JSON '" + message.replace(/'/g, "'$&") + "'", + [], + { prepare: true }, + ); + }, + async function (err, result) { + if (result && result.nextPage) { + await new Promise(r => setTimeout(r, 100)); + result.nextPage(); + } else { + r2(); + } + }, + ); + }); + }, + async function (err, result) { + if (result && result.nextPage) { + await new Promise(r => setTimeout(r, 2000)); + result.nextPage(); + } else { + r(); + } + }, + ); + }); +})(); diff --git a/twake/backend/node/src/cli/utils/copy-messages/package.json b/twake/backend/node/src/cli/utils/copy-messages/package.json new file mode 100644 index 00000000..6aa7d488 --- /dev/null +++ b/twake/backend/node/src/cli/utils/copy-messages/package.json @@ -0,0 +1,9 @@ +{ + "name": "copy-messages", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "dependencies": { + "cassandra-driver": "^4.6.3" + } +} diff --git a/twake/backend/node/src/cli/utils/copy-table/README.md b/twake/backend/node/src/cli/utils/copy-table/README.md new file mode 100644 index 00000000..02fe7cc4 --- /dev/null +++ b/twake/backend/node/src/cli/utils/copy-table/README.md @@ -0,0 +1,4 @@ +Edit the file to your needs + +yarn install +node index.js diff --git a/twake/backend/node/src/cli/utils/copy-table/index.js b/twake/backend/node/src/cli/utils/copy-table/index.js new file mode 100644 index 00000000..112abdae --- /dev/null +++ b/twake/backend/node/src/cli/utils/copy-table/index.js @@ -0,0 +1,88 @@ +/* eslint-disable */ +var cassandra = require("cassandra-driver"); + +var authProvider = new cassandra.auth.PlainTextAuthProvider("", ""); +var contactPoints = [""]; +var from = "table_a"; +var to = "table_b"; + +var client = new cassandra.Client({ + localDataCenter: "datacenter1", + contactPoints: contactPoints, + authProvider: authProvider, + keyspace: "twake", +}); + +//Copy object to other table +(async () => { + const query = "SELECT * FROM " + from; + const parameters = []; + + let count = 0; + let max = 0; + let min = new Date().getTime(); + + let rows = []; + + const options = { prepare: true, fetchSize: 1000 }; + + await new Promise(r => { + client.eachRow( + query, + parameters, + options, + function (n, row) { + min = Math.min(parseInt(row.created_at.toString()), min); + max = Math.max(parseInt(row.created_at.toString()), max); + count++; + if (count % 100 == 0) { + console.log(count); + } + rows.push(row); + }, + function (err, result) { + if (result && result.nextPage) { + result.nextPage(); + } else { + r(); + } + }, + ); + }); + + console.log("Downloaded ", count, " rows of ", from, ". Starting copy..."); + + let copyCount = 0; + + for (let i = 0; i < count; i++) { + copyCount++; + if (copyCount % 100 == 0) { + console.log(copyCount, "of", count); + } + + const row = rows[i]; + + await new Promise(r => { + let query = + "UPDATE " + + to + + " SET answers=?, created_at=?, created_by=?, last_activity=?, participants=?, updated_at=? WHERE id=?"; + client.execute( + query, + [ + row.answers, + row.created_at, + row.created_by, + row.last_activity, + row.participants, + row.updated_at, + row.id, + ], + () => { + r(); + }, + ); + }); + } + console.log("Ended with ", count, "threads"); +})(); diff --git a/twake/backend/node/src/cli/utils/copy-table/package.json b/twake/backend/node/src/cli/utils/copy-table/package.json new file mode 100644 index 00000000..f3c1b49b --- /dev/null +++ b/twake/backend/node/src/cli/utils/copy-table/package.json @@ -0,0 +1,6 @@ +{ + "name": "copy-table", + "version": "1.0.0", + "main": "index.js", + "license": "MIT" +} diff --git a/twake/backend/node/src/cli/utils/repair-threads/README.md b/twake/backend/node/src/cli/utils/repair-threads/README.md new file mode 100644 index 00000000..02fe7cc4 --- /dev/null +++ b/twake/backend/node/src/cli/utils/repair-threads/README.md @@ -0,0 +1,4 @@ +Edit the file to your needs + +yarn install +node index.js diff --git a/twake/backend/node/src/cli/utils/repair-threads/index.js b/twake/backend/node/src/cli/utils/repair-threads/index.js new file mode 100644 index 00000000..87a00d5a --- /dev/null +++ b/twake/backend/node/src/cli/utils/repair-threads/index.js @@ -0,0 +1,96 @@ +/* eslint-disable */ +var cassandra = require("cassandra-driver"); + +var authProvider = new cassandra.auth.PlainTextAuthProvider("", ""); +var contactPoints = [""]; + +var client = new cassandra.Client({ + localDataCenter: "datacenter1", + contactPoints: contactPoints, + authProvider: authProvider, + keyspace: "twake", +}); + +var threadsTable = "threads"; +var messagesTable = "messages"; + +//Copy object to other table +(async () => { + const query = "SELECT * FROM " + threadsTable + " where answers>1000 allow filtering"; + const parameters = []; + const options = { prepare: true, fetchSize: 1000 }; + + let count = 0; + + let threads = {}; + + await new Promise(r => { + client.eachRow( + query, + parameters, + options, + function (n, row) { + threads[row.id] ||= { answers: 0, id: row.id }; + count++; + }, + function (err, result) { + if (result && result.nextPage) { + result.nextPage(); + } else { + r(); + } + }, + ); + }); + + console.log( + "Downloaded ", + Object.keys(threads).length, + " threads of ", + messagesTable, + ". Starting copy...", + ); + + for (var key of Object.keys(threads)) { + await new Promise(r => { + const query = "SELECT id FROM " + messagesTable + " where thread_id=" + key; + const parameters = []; + const options = { prepare: true, fetchSize: 1000 }; + client.eachRow( + query, + parameters, + options, + function (n, row) { + threads[key].answers++; + }, + function (err, result) { + if (result && result.nextPage) { + result.nextPage(); + } else { + r(); + } + }, + ); + r(); + }); + } + + var copyCount = 0; + for (var key of Object.keys(threads)) { + copyCount++; + if (copyCount % 100 == 0) { + console.log(copyCount, "of", Object.keys(threads)); + } + + const row = threads[key]; + + await new Promise(r => { + let query = "UPDATE " + threadsTable + " SET answers=? WHERE id=?"; + console.log(query, [row.answers, row.id + ""]); + //client.execute(query, [row.answers, row.id], () => { + // r(); + //}); + }); + } + console.log("Ended with ", Object.keys(threads), "threads"); +})(); diff --git a/twake/backend/node/src/cli/utils/repair-threads/package.json b/twake/backend/node/src/cli/utils/repair-threads/package.json new file mode 100644 index 00000000..dd45de8a --- /dev/null +++ b/twake/backend/node/src/cli/utils/repair-threads/package.json @@ -0,0 +1,9 @@ +{ + "name": "repair-threads", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "dependencies": { + "cassandra-driver": "^4.6.3" + } +} diff --git a/twake/backend/node/src/core/config/index.ts b/twake/backend/node/src/core/config/index.ts new file mode 100644 index 00000000..2f819dc2 --- /dev/null +++ b/twake/backend/node/src/core/config/index.ts @@ -0,0 +1,3 @@ +import config from "config"; + +export default config; diff --git a/twake/backend/node/src/core/crypto/index.ts b/twake/backend/node/src/core/crypto/index.ts new file mode 100644 index 00000000..417e7cad --- /dev/null +++ b/twake/backend/node/src/core/crypto/index.ts @@ -0,0 +1,50 @@ +import legacy from "./legacy"; +import v1 from "./v1"; +import v2 from "./v2"; +import { createHash } from "crypto"; + +export type CryptoResult = { + /** + * Encrypted | Decrypted data if done, original data if not done due to error or not encrypted data to decrypt + */ + data: any; + /** + * Is there an error while processing the input data? + */ + err?: Error; + /** + * Did we encrypted | decrypted the data? true if yes. + */ + done?: boolean; +}; + +export function decrypt(data: string, encryptionKey: string): CryptoResult { + let result = v2.decrypt(data, encryptionKey); + if (result.done) { + return result; + } + + result = v1.decrypt(data, encryptionKey); + if (result.done) { + return result; + } + + result = legacy.decrypt(data, encryptionKey); + if (result.done) { + return result; + } + + return result; +} + +export function md5(value: string): string { + return createHash("md5").update(value).digest("hex"); +} + +export function encrypt( + value: any, + encryptionKey: any, + options: { disableSalts?: boolean } = {}, +): CryptoResult { + return v2.encrypt(value, encryptionKey, options); +} diff --git a/twake/backend/node/src/core/crypto/legacy.ts b/twake/backend/node/src/core/crypto/legacy.ts new file mode 100644 index 00000000..f18479e0 --- /dev/null +++ b/twake/backend/node/src/core/crypto/legacy.ts @@ -0,0 +1,45 @@ +import { createDecipheriv } from "crypto"; +import { CryptoResult } from "."; + +const PREFIX = "encrypted_"; +const DEFAULT_IV = "twake_constantiv"; + +export default { + decrypt, + encrypt, +}; + +function decrypt(data: string, encryptionKey: string): CryptoResult { + if (!data || !data.startsWith(PREFIX)) { + return { + data, + done: false, + }; + } + + const toDecode = data.substr(PREFIX.length); + const encryptedArray = toDecode.split("_"); + + // If array length is 1, the value has not been salted and iv is the default one + const encrypted = Buffer.from(encryptedArray[0], "base64"); + const salt = encryptedArray[1] + ? Buffer.from(encryptedArray[1], "utf-8") + : Buffer.from("", "utf-8"); + const iv = encryptedArray[2] + ? Buffer.from(encryptedArray[2], "base64") + : Buffer.from(DEFAULT_IV, "utf-8"); + const password = Buffer.concat([Buffer.from(encryptionKey, "hex"), salt], 32); + const decipher = createDecipheriv("AES-256-CBC", password, iv); + + return { + data: Buffer.concat([decipher.update(encrypted), decipher.final()]).toString("utf-8"), + done: true, + }; +} + +function encrypt(data: any): CryptoResult { + return { + data, + done: false, + }; +} diff --git a/twake/backend/node/src/core/crypto/v1.ts b/twake/backend/node/src/core/crypto/v1.ts new file mode 100644 index 00000000..08f00ae5 --- /dev/null +++ b/twake/backend/node/src/core/crypto/v1.ts @@ -0,0 +1,67 @@ +import { createCipheriv, createDecipheriv, createHash, randomBytes } from "crypto"; +import { CryptoResult } from "."; + +export default { + encrypt, + decrypt, +}; + +function encrypt( + data: any, + encryptionKey: any, + options: { disableSalts?: boolean } = {}, +): CryptoResult { + const key = createHash("sha256").update(String(encryptionKey)).digest("base64").substr(0, 32); + try { + const iv = options.disableSalts ? "0000000000000000" : randomBytes(16); + const cipher = createCipheriv("aes-256-cbc", key, iv); + const encrypted = Buffer.concat([cipher.update(JSON.stringify(data)), cipher.final()]).toString( + "hex", + ); + return { + data: `${iv.toString("hex")}:${encrypted}`, + done: true, + }; + } catch (err) { + return { + err, + data, + done: false, + }; + } +} + +function decrypt(data: string, encryptionKey: any): CryptoResult { + const key = createHash("sha256").update(String(encryptionKey)).digest("base64").substr(0, 32); + + const encryptedArray = data.split(":"); + + if (!encryptedArray.length || encryptedArray.length !== 2) { + return { + data, + done: false, + }; + } + + let iv: Buffer | string = Buffer.from(encryptedArray[0], "hex"); + if (encryptedArray[0] === "0000000000000000") { + iv = "0000000000000000"; + } + + try { + const encrypted = Buffer.from(encryptedArray[1], "hex"); + const decipher = createDecipheriv("aes-256-cbc", key, iv); + const decrypt = JSON.parse( + Buffer.concat([decipher.update(encrypted), decipher.final()]).toString(), + ); + return { + data: decrypt, + done: true, + }; + } catch (err) { + return { + data, + done: false, + }; + } +} diff --git a/twake/backend/node/src/core/crypto/v2.ts b/twake/backend/node/src/core/crypto/v2.ts new file mode 100644 index 00000000..b1ff60e6 --- /dev/null +++ b/twake/backend/node/src/core/crypto/v2.ts @@ -0,0 +1,70 @@ +import { createCipheriv, createDecipheriv, createHash, randomBytes } from "crypto"; +import { CryptoResult } from "."; + +export default { + encrypt, + decrypt, +}; + +function encrypt( + data: any, + encryptionKey: any, + options: { disableSalts?: boolean } = {}, +): CryptoResult { + const key = createHash("sha256").update(String(encryptionKey)).digest("hex").substr(0, 32); + try { + const iv = options.disableSalts ? "0000000000000000" : randomBytes(16); + const cipher = createCipheriv("aes-256-gcm", key, iv); + const encrypted = + cipher.update(JSON.stringify(data), "utf8", "base64") + cipher.final("base64"); + + return { + data: `${iv.toString("base64")}:${cipher.getAuthTag().toString("base64")}:${encrypted}`, + done: true, + }; + } catch (err) { + return { + err, + data, + done: false, + }; + } +} + +function decrypt(data: string, encryptionKey: any): CryptoResult { + const key = createHash("sha256").update(String(encryptionKey)).digest("hex").substr(0, 32); + + const encryptedArray = data.split(":"); + + if (!encryptedArray.length || encryptedArray.length !== 3) { + return { + data, + done: false, + }; + } + + let iv: Buffer | string = Buffer.from(encryptedArray[0], "base64"); + if (encryptedArray[0] === "0000000000000000") { + iv = "0000000000000000"; + } + + try { + const decipher = createDecipheriv("aes-256-gcm", key, iv); + decipher.setAuthTag(Buffer.from(encryptedArray[1], "base64")); + + const encrypted = encryptedArray[2]; + let str = decipher.update(encrypted, "base64", "utf8"); + str += decipher.final("utf8"); + const decrypt = JSON.parse(str); + + return { + data: decrypt, + done: true, + }; + } catch (err) { + return { + data, + done: false, + }; + } +} diff --git a/twake/backend/node/src/core/platform/framework/api/application-configuration.ts b/twake/backend/node/src/core/platform/framework/api/application-configuration.ts new file mode 100644 index 00000000..ae678c5f --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/api/application-configuration.ts @@ -0,0 +1,7 @@ +import { TwakeServiceOptions } from "./service-options"; +import { TwakeServiceConfiguration } from "./service-configuration"; + +export class TwakeAppConfiguration extends TwakeServiceOptions<TwakeServiceConfiguration> { + services: Array<string>; + servicesPath: string; +} diff --git a/twake/backend/node/src/core/platform/framework/api/class.ts b/twake/backend/node/src/core/platform/framework/api/class.ts new file mode 100644 index 00000000..26303f61 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/api/class.ts @@ -0,0 +1,2 @@ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type Class = { new (...args: any[]): any }; diff --git a/twake/backend/node/src/core/platform/framework/api/component.ts b/twake/backend/node/src/core/platform/framework/api/component.ts new file mode 100644 index 00000000..7a982410 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/api/component.ts @@ -0,0 +1,67 @@ +import { BehaviorSubject } from "rxjs"; +import { TwakeService } from "./service"; +import { TwakeServiceProvider } from "./service-provider"; +import { ServiceDefinition } from "./service-definition"; +import { TwakeServiceState } from "./service-state"; +import { logger } from "../logger"; + +export class TwakeComponent { + instance: TwakeService<TwakeServiceProvider>; + components: Array<TwakeComponent> = new Array<TwakeComponent>(); + + constructor(public name: string, private serviceDefinition: ServiceDefinition) {} + + getServiceDefinition(): ServiceDefinition { + return this.serviceDefinition; + } + + setServiceInstance(instance: TwakeService<TwakeServiceProvider>): void { + this.instance = instance; + } + + getServiceInstance(): TwakeService<TwakeServiceProvider> { + return this.instance; + } + + addDependency(component: TwakeComponent): void { + this.components.push(component); + } + + getStateTree(): string { + return `${this.name}(${this.instance.state.value}) => {${this.components + .map(component => component.getStateTree()) + .join(",")}}`; + } + + async switchToState( + state: TwakeServiceState.Initialized | TwakeServiceState.Started | TwakeServiceState.Stopped, + recursionDepth?: number, + ): Promise<void> { + if (recursionDepth > 10) { + logger.error("Maximum recursion depth exceeded (will exit process)"); + process.exit(1); + } + + const states: BehaviorSubject<TwakeServiceState>[] = this.components.map( + component => component.instance.state, + ); + + if (states.length) { + for (const component of this.components) { + await component.switchToState(state, (recursionDepth || 0) + 1); + } + logger.info(`Children of ${this.name} are all in ${state} state`); + logger.info(this.getStateTree()); + } else { + logger.info(`${this.name} does not have children`); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + async function _switchServiceToState(service: TwakeService<any>) { + state === TwakeServiceState.Initialized && (await service.init()); + state === TwakeServiceState.Started && (await service.start()); + state === TwakeServiceState.Stopped && (await service.stop()); + } + await _switchServiceToState(this.instance); + } +} diff --git a/twake/backend/node/src/core/platform/framework/api/constants.ts b/twake/backend/node/src/core/platform/framework/api/constants.ts new file mode 100644 index 00000000..1a90f94d --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/api/constants.ts @@ -0,0 +1,3 @@ +export const PREFIX_METADATA = "service:prefix"; +export const CONSUMES_METADATA = "service:consumes"; +export const SERVICENAME_METADATA = "service:name"; diff --git a/twake/backend/node/src/core/platform/framework/api/container.ts b/twake/backend/node/src/core/platform/framework/api/container.ts new file mode 100644 index 00000000..c374a9ee --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/api/container.ts @@ -0,0 +1,73 @@ +import { TwakeAppConfiguration } from "./application-configuration"; +import { TwakeComponent } from "./component"; +import { TwakeContext } from "./context"; +import { TwakeServiceProvider } from "./service-provider"; +import { TwakeService } from "./service"; +import { TwakeServiceState } from "./service-state"; +import * as ComponentUtils from "../utils/component-utils"; + +/** + * A container contains components. It provides methods to manage and to retrieve them. + */ +export abstract class TwakeContainer + extends TwakeService<TwakeServiceProvider> + implements TwakeContext +{ + private components: Map<string, TwakeComponent>; + name = "TwakeContainer"; + + constructor(protected options?: TwakeAppConfiguration) { + super(options); + } + + abstract loadComponents(): Promise<Map<string, TwakeComponent>>; + + abstract loadComponent(name: string): Promise<TwakeComponent>; + + getProvider<T extends TwakeServiceProvider>(name: string): T { + const service = this.components.get(name)?.getServiceInstance(); + + if (!service) { + throw new Error(`Service "${name}" not found`); + } + + return service.api() as T; + } + + async doInit(): Promise<this> { + this.components = await this.loadComponents(); + await ComponentUtils.buildDependenciesTree(this.components, async (name: string) => { + const component = await this.loadComponent(name); + if (component) this.components.set(name, component); + return component; + }); + + await this.launchInit(); + + return this; + } + + protected async launchInit(): Promise<this> { + await this.switchToState(TwakeServiceState.Initialized); + + return this; + } + + async doStart(): Promise<this> { + await this.switchToState(TwakeServiceState.Started); + + return this; + } + + async doStop(): Promise<this> { + await this.switchToState(TwakeServiceState.Stopped); + + return this; + } + + protected async switchToState( + state: TwakeServiceState.Started | TwakeServiceState.Initialized | TwakeServiceState.Stopped, + ): Promise<void> { + await ComponentUtils.switchComponentsToState(this.components, state); + } +} diff --git a/twake/backend/node/src/core/platform/framework/api/context.ts b/twake/backend/node/src/core/platform/framework/api/context.ts new file mode 100644 index 00000000..f9ac36e4 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/api/context.ts @@ -0,0 +1,5 @@ +import { TwakeServiceProvider } from "./service-provider"; + +export interface TwakeContext { + getProvider<T extends TwakeServiceProvider>(name: string): T; +} diff --git a/twake/backend/node/src/core/platform/framework/api/crud-service.ts b/twake/backend/node/src/core/platform/framework/api/crud-service.ts new file mode 100644 index 00000000..e0ed0e40 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/api/crud-service.ts @@ -0,0 +1,233 @@ +import { User } from "../../../../utils/types"; + +export class ContextualizedTarget { + context?: ExecutionContext; + readonly operation: OperationType; +} + +export class EntityTarget<Entity> extends ContextualizedTarget { + /** + * + * @param type type of entity + * @param entity the entity itself + */ + constructor(readonly type: string, readonly entity: Entity) { + super(); + } +} + +export class UpdateResult<Entity> extends EntityTarget<Entity> { + readonly operation = OperationType.UPDATE; + + /** + * Result sent back by the underlying database + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + raw?: any; + + /** + * Number of rows affected by the update. + */ + affected?: number; +} + +export class CreateResult<Entity> extends EntityTarget<Entity> { + readonly operation = OperationType.CREATE; + + /** + * Result sent back by the underlying database + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + raw?: any; +} + +export class SaveResult<Entity> extends EntityTarget<Entity> { + /** + * Result sent back by the underlying database + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + raw?: any; + + /** + * + * @param type Type of entity + * @param entity The entity itself + * @param operation Save can be for a "create", an "update" or "exists" when resource already exists + */ + constructor( + readonly type: string, + readonly entity: Entity, + readonly operation: OperationType.UPDATE | OperationType.CREATE | OperationType.EXISTS, + ) { + super(type, entity); + } +} + +export class DeleteResult<Entity> extends EntityTarget<Entity> { + readonly operation = OperationType.DELETE; + + /** + * + * @param type type of entity + * @param entity the entity itself + * @param deleted the entity has been deleted or not + */ + constructor(readonly type: string, readonly entity: Entity, readonly deleted: boolean) { + super(type, entity); + } +} + +export class ListResult<Entity> extends ContextualizedTarget implements Paginable { + // next page token + page_token: string; + + constructor(readonly type: string, protected entities: Entity[], readonly nextPage?: Paginable) { + super(); + this.page_token = nextPage?.page_token; + } + + mapEntities(mapper: <T extends Entity>(entity: Entity) => T): void { + this.entities = this.entities.map(entity => mapper(entity)); + } + + filterEntities(filter: (entity: Entity) => boolean): void { + this.entities = this.entities.filter(entity => filter(entity)); + } + + getEntities(): Entity[] { + return this.entities || []; + } + + isEmpty(): boolean { + return this.getEntities().length === 0; + } +} + +export enum OperationType { + CREATE = "create", + UPDATE = "update", + SAVE = "save", + DELETE = "delete", + EXISTS = "exists", +} + +export declare type EntityOperationResult<Entity> = + | CreateResult<Entity> + | UpdateResult<Entity> + | SaveResult<Entity> + | DeleteResult<Entity>; + +export interface ExecutionContext { + user: User; + reqId?: string; + url?: string; + method?: string; + transport?: "http" | "ws"; +} + +export class CrudException extends Error { + constructor(readonly details: string, readonly status: number) { + super(); + this.message = details; + } + + static badRequest(details: string): CrudException { + return new CrudException(details, 400); + } + + static notFound(details: string): CrudException { + return new CrudException(details, 404); + } + static forbidden(details: string): CrudException { + return new CrudException(details, 403); + } + + static notImplemented(details: string): CrudException { + return new CrudException(details, 501); + } + + static badGateway(details: string): CrudException { + return new CrudException(details, 502); + } +} + +export interface Paginable { + page_token?: string; + limitStr?: string; + reversed?: boolean; +} + +export class Pagination implements Paginable { + reversed?: boolean; + constructor(readonly page_token?: string, readonly limitStr = "100", reversed = false) { + this.reversed = reversed; + } + + public static fromPaginable(p: Paginable) { + return new Pagination(p.page_token, p.limitStr, p.reversed); + } +} + +export interface CRUDService<Entity, PrimaryKey, Context extends ExecutionContext> { + /** + * Creates a resource + * + * @param item + * @param context + */ + create?(item: Entity, context?: Context): Promise<CreateResult<Entity>>; + + /** + * Get a resource + * + * @param pk + * @param context + */ + get(pk: PrimaryKey, context?: Context): Promise<Entity>; + + /** + * Update a resource + * + * @param pk + * @param item + * @param context + */ + update?( + pk: PrimaryKey, + item: Entity, + context?: Context /* TODO: Options */, + ): Promise<UpdateResult<Entity>>; + + /** + * Save a resource. + * If the resource exists, it is updated, if it does not exists, it is created. + * + * @param itemOrItems + * @param options + * @param context + */ + save?<SaveOptions>( + item: Entity, + options?: SaveOptions, + context?: Context, + ): Promise<SaveResult<Entity>>; + + /** + * Delete a resource + * + * @param pk + * @param context + */ + delete(pk: PrimaryKey, context?: Context): Promise<DeleteResult<Entity>>; + + /** + * List a resource + * + * @param context + */ + list<ListOptions>( + pagination: Paginable, + options?: ListOptions, + context?: Context /* TODO: Options */, + ): Promise<ListResult<Entity>>; +} diff --git a/twake/backend/node/src/core/platform/framework/api/index.ts b/twake/backend/node/src/core/platform/framework/api/index.ts new file mode 100644 index 00000000..461cf533 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/api/index.ts @@ -0,0 +1,14 @@ +export * from "./application-configuration"; +export * from "./class"; +export * from "./component"; +export * from "./constants"; +export * from "./context"; +export * from "./container"; +export * from "./lifecycle"; +export * from "./service-configuration"; +export * from "./service-definition"; +export * from "./service-interface"; +export * from "./service-options"; +export * from "./service-provider"; +export * from "./service-state"; +export * from "./service"; diff --git a/twake/backend/node/src/core/platform/framework/api/lifecycle.ts b/twake/backend/node/src/core/platform/framework/api/lifecycle.ts new file mode 100644 index 00000000..eb938efe --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/api/lifecycle.ts @@ -0,0 +1,6 @@ +import { TwakeContext } from "./context"; + +export interface Initializable { + // TODO: Flag to tell if a service which fails to initialize must break all + init?(context?: TwakeContext): Promise<this>; +} diff --git a/twake/backend/node/src/core/platform/framework/api/service-configuration.ts b/twake/backend/node/src/core/platform/framework/api/service-configuration.ts new file mode 100644 index 00000000..4cf6816b --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/api/service-configuration.ts @@ -0,0 +1,3 @@ +export interface TwakeServiceConfiguration { + get<T>(name?: string, defaultValue?: T): T; +} diff --git a/twake/backend/node/src/core/platform/framework/api/service-definition.ts b/twake/backend/node/src/core/platform/framework/api/service-definition.ts new file mode 100644 index 00000000..37628e58 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/api/service-definition.ts @@ -0,0 +1,6 @@ +import { Class } from "./class"; + +export interface ServiceDefinition { + name: string; + clazz: Class; +} diff --git a/twake/backend/node/src/core/platform/framework/api/service-interface.ts b/twake/backend/node/src/core/platform/framework/api/service-interface.ts new file mode 100644 index 00000000..4bec93b9 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/api/service-interface.ts @@ -0,0 +1,8 @@ +import { TwakeServiceProvider } from "./service-provider"; + +export interface TwakeServiceInterface<T extends TwakeServiceProvider> { + doInit(): Promise<this>; + doStart(): Promise<this>; + doStop(): Promise<this>; + api(): T; +} diff --git a/twake/backend/node/src/core/platform/framework/api/service-options.ts b/twake/backend/node/src/core/platform/framework/api/service-options.ts new file mode 100644 index 00000000..86bb44fd --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/api/service-options.ts @@ -0,0 +1,5 @@ +export class TwakeServiceOptions<TwakeServiceConfiguration> { + name?: string; + // TODO: configuration is abstract and comes from all others + configuration?: TwakeServiceConfiguration; +} diff --git a/twake/backend/node/src/core/platform/framework/api/service-provider.ts b/twake/backend/node/src/core/platform/framework/api/service-provider.ts new file mode 100644 index 00000000..5d247a91 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/api/service-provider.ts @@ -0,0 +1,3 @@ +export interface TwakeServiceProvider { + version: string; +} diff --git a/twake/backend/node/src/core/platform/framework/api/service-state.ts b/twake/backend/node/src/core/platform/framework/api/service-state.ts new file mode 100644 index 00000000..35b9e9c1 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/api/service-state.ts @@ -0,0 +1,10 @@ +export enum TwakeServiceState { + Ready = "READY", + Initializing = "INITIALIZING", + Initialized = "INITIALIZED", + Starting = "STARTING", + Started = "STARTED", + Stopping = "STOPPING", + Stopped = "STOPPED", + Errored = "ERRORED", +} diff --git a/twake/backend/node/src/core/platform/framework/api/service.ts b/twake/backend/node/src/core/platform/framework/api/service.ts new file mode 100644 index 00000000..9e9ab643 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/api/service.ts @@ -0,0 +1,133 @@ +import { BehaviorSubject } from "rxjs"; +import { TwakeServiceInterface } from "./service-interface"; +import { TwakeServiceProvider } from "./service-provider"; +import { TwakeServiceState } from "./service-state"; +import { TwakeServiceConfiguration } from "./service-configuration"; +import { TwakeContext } from "./context"; +import { TwakeServiceOptions } from "./service-options"; +import { CONSUMES_METADATA, PREFIX_METADATA } from "./constants"; +import { getLogger, logger } from "../logger"; +import { TwakeLogger } from ".."; + +const pendingServices: any = {}; + +export abstract class TwakeService<T extends TwakeServiceProvider> + implements TwakeServiceInterface<TwakeServiceProvider> +{ + state: BehaviorSubject<TwakeServiceState>; + readonly name: string; + protected readonly configuration: TwakeServiceConfiguration; + context: TwakeContext; + logger: TwakeLogger; + + constructor(protected options?: TwakeServiceOptions<TwakeServiceConfiguration>) { + this.state = new BehaviorSubject<TwakeServiceState>(TwakeServiceState.Ready); + // REMOVE ME, we should import config from framework folder instead + this.configuration = options?.configuration; + this.logger = getLogger(`core.platform.services.${this.name}Service`); + } + + abstract api(): T; + + public get prefix(): string { + return Reflect.getMetadata(PREFIX_METADATA, this) || "/"; + } + + getConsumes(): Array<string> { + return Reflect.getMetadata(CONSUMES_METADATA, this) || []; + } + + async init(): Promise<this> { + if (this.state.value !== TwakeServiceState.Ready) { + logger.info("Service %s is already initialized", this.name); + return this; + } + + try { + logger.info("Initializing service %s", this.name); + pendingServices[this.name] = true; + this.state.next(TwakeServiceState.Initializing); + await this.doInit(); + this.state.next(TwakeServiceState.Initialized); + logger.info("Service %s is initialized", this.name); + delete pendingServices[this.name]; + logger.info("Pending services: %s", JSON.stringify(Object.keys(pendingServices))); + return this; + } catch (err) { + logger.error("Error while initializing service %s", this.name); + logger.error(err); + this.state.error(new Error(`Error while initializing service ${this.name}`)); + + throw err; + } + } + + async doInit(): Promise<this> { + return this; + } + + async doStart(): Promise<this> { + return this; + } + + async start(): Promise<this> { + if ( + this.state.value === TwakeServiceState.Starting || + this.state.value === TwakeServiceState.Started + ) { + logger.info("Service %s is already started", this.name); + return this; + } + + try { + logger.info("Starting service %s", this.name); + this.state.next(TwakeServiceState.Starting); + await this.doStart(); + this.state.next(TwakeServiceState.Started); + logger.info("Service %s is started", this.name); + + return this; + } catch (err) { + logger.error("Error while starting service %s", this.name, err); + logger.error(err); + this.state.error(new Error(`Error while starting service ${this.name}`)); + + throw err; + } + } + + async stop(): Promise<this> { + if ( + this.state.value === TwakeServiceState.Stopping || + this.state.value === TwakeServiceState.Stopped + ) { + logger.info("Service %s is already stopped", this.name); + return this; + } + + if (this.state.value !== TwakeServiceState.Started) { + logger.info("Service %s can not be stopped until started", this.name); + return this; + } + + try { + logger.info("Stopping service %s", this.name); + this.state.next(TwakeServiceState.Stopping); + await this.doStop(); + this.state.next(TwakeServiceState.Stopped); + logger.info("Service %s is stopped", this.name); + + return this; + } catch (err) { + logger.error("Error while stopping service %s", this.name, err); + logger.error(err); + this.state.error(new Error(`Error while stopping service ${this.name}`)); + + throw err; + } + } + + async doStop(): Promise<this> { + return this; + } +} diff --git a/twake/backend/node/src/core/platform/framework/api/webservice.ts b/twake/backend/node/src/core/platform/framework/api/webservice.ts new file mode 100644 index 00000000..39417552 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/api/webservice.ts @@ -0,0 +1,21 @@ +import { PREFIX_METADATA } from "./constants"; +import { FastifyInstance, FastifyPluginCallback } from "fastify"; + +import gr from "../../../../services/global-resolver"; + +export abstract class AbstractWebService { + abstract routes(fastify: FastifyInstance): void; + + public get prefix(): string { + return Reflect.getMetadata(PREFIX_METADATA, this) || "/"; + } + + public process(): void { + const wrapper: FastifyPluginCallback = (fastify: FastifyInstance, options, next) => { + this.routes(fastify); + next(); + }; + + gr.fastify.register(wrapper, { prefix: this.prefix }); + } +} diff --git a/twake/backend/node/src/core/platform/framework/configuration.ts b/twake/backend/node/src/core/platform/framework/configuration.ts new file mode 100644 index 00000000..cf77e855 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/configuration.ts @@ -0,0 +1,32 @@ +import { IConfig } from "config"; +import configuration from "../../config"; +import { TwakeServiceConfiguration } from "./api"; +export class Configuration implements TwakeServiceConfiguration { + configuration: IConfig; + serviceConfiguration: IConfig; + + constructor(path: string) { + try { + this.serviceConfiguration = configuration.get(path); + } catch { + // NOP + } + } + + get<T>(name?: string, defaultValue?: T): T { + let value: T; + + try { + value = this.serviceConfiguration as unknown as T; + if (name) { + value = + this.serviceConfiguration && + (this.serviceConfiguration.get(name) || configuration.get(name)); + } + } catch { + value = defaultValue || null; + } finally { + return value; + } + } +} diff --git a/twake/backend/node/src/core/platform/framework/decorators/consumes.ts b/twake/backend/node/src/core/platform/framework/decorators/consumes.ts new file mode 100644 index 00000000..dfa3ef09 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/decorators/consumes.ts @@ -0,0 +1,8 @@ +import { CONSUMES_METADATA } from "../api"; + +export function Consumes(services: string[] = []): ClassDecorator { + // eslint-disable-next-line @typescript-eslint/ban-types + return function (target: Function): void { + Reflect.defineMetadata(CONSUMES_METADATA, services, target.prototype); + }; +} diff --git a/twake/backend/node/src/core/platform/framework/decorators/index.ts b/twake/backend/node/src/core/platform/framework/decorators/index.ts new file mode 100644 index 00000000..a78685f3 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/decorators/index.ts @@ -0,0 +1,4 @@ +export * from "./consumes"; +export * from "./prefix"; +export * from "./service-name"; +export * from "./realtime"; diff --git a/twake/backend/node/src/core/platform/framework/decorators/prefix.ts b/twake/backend/node/src/core/platform/framework/decorators/prefix.ts new file mode 100644 index 00000000..734dda7f --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/decorators/prefix.ts @@ -0,0 +1,8 @@ +import { PREFIX_METADATA } from "../api"; + +export function Prefix(prefix: string = "/"): ClassDecorator { + // eslint-disable-next-line @typescript-eslint/ban-types + return function (target: Function): void { + Reflect.defineMetadata(PREFIX_METADATA, prefix, target.prototype); + }; +} diff --git a/twake/backend/node/src/core/platform/framework/decorators/realtime/created.ts b/twake/backend/node/src/core/platform/framework/decorators/realtime/created.ts new file mode 100644 index 00000000..2f88fb9d --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/decorators/realtime/created.ts @@ -0,0 +1,41 @@ +import { CreateResult } from "../../api/crud-service"; +import { RealtimeEntityEvent, RealtimeEntityActionType } from "../../../services/realtime/types"; +import { websocketEventBus } from "../../../services/realtime/bus"; +import { getRealtimeRecipients, getRoom, RealtimeRecipients } from "."; + +/** + * + * @param path the path to push the notification to + * @param resourcePath the path of the resource itself + */ +export function RealtimeCreated<T>(recipients: RealtimeRecipients<T>): MethodDecorator { + // eslint-disable-next-line @typescript-eslint/ban-types + return function (target: Object, propertyKey: string, descriptor: PropertyDescriptor): void { + const originalMethod = descriptor.value; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + descriptor.value = async function (...args: any[]) { + const result: CreateResult<T> = await originalMethod.apply(this, args); + // context should always be the last arg + const context = args && args[args.length - 1]; + + if (!(result instanceof CreateResult)) { + return result; + } + + getRealtimeRecipients(recipients, result.entity, context).forEach( + ({ room, path, resource }) => { + websocketEventBus.publish<T>(RealtimeEntityActionType.Created, { + type: result.type, + room: getRoom(room, result, context), + resourcePath: path || "/", + entity: resource, + result, + } as RealtimeEntityEvent<T>); + }, + ); + + return result; + }; + }; +} diff --git a/twake/backend/node/src/core/platform/framework/decorators/realtime/deleted.ts b/twake/backend/node/src/core/platform/framework/decorators/realtime/deleted.ts new file mode 100644 index 00000000..92b655a9 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/decorators/realtime/deleted.ts @@ -0,0 +1,41 @@ +import { getRealtimeRecipients, getRoom, RealtimeRecipients } from ".."; +import { DeleteResult } from "../../api/crud-service"; +import { RealtimeEntityEvent, RealtimeEntityActionType } from "../../../services/realtime/types"; +import { websocketEventBus } from "../../../services/realtime/bus"; + +/** + * + * @param path the path to push the notification to + * @param resourcePath the path of the resource itself + */ +export function RealtimeDeleted<T>(recipients: RealtimeRecipients<T>): MethodDecorator { + // eslint-disable-next-line @typescript-eslint/ban-types + return function (target: Object, propertyKey: string, descriptor: PropertyDescriptor): void { + const originalMethod = descriptor.value; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + descriptor.value = async function (...args: any[]) { + const result: DeleteResult<T> = await originalMethod.apply(this, args); + const context = args && args[args.length - 1]; + + if (!(result instanceof DeleteResult)) { + return result; + } + + if (result.deleted) + getRealtimeRecipients(recipients, result.entity, context).forEach( + ({ room, path, resource }) => { + websocketEventBus.publish<T>(RealtimeEntityActionType.Deleted, { + type: result.type, + room: getRoom(room, result, context), + resourcePath: path, + entity: resource, + result, + } as RealtimeEntityEvent<T>); + }, + ); + + return result; + }; + }; +} diff --git a/twake/backend/node/src/core/platform/framework/decorators/realtime/index.ts b/twake/backend/node/src/core/platform/framework/decorators/realtime/index.ts new file mode 100644 index 00000000..4e84da93 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/decorators/realtime/index.ts @@ -0,0 +1,67 @@ +import { ResourcePath } from "../../../../../core/platform/services/realtime/types"; +import { EntityTarget, ExecutionContext } from "../../api/crud-service"; + +export * from "./created"; +export * from "./deleted"; +export * from "./updated"; +export * from "./saved"; + +export type RealtimeRecipients<T> = + | RealtimeRecipient<T> + | RealtimeRecipient<T>[] + | ((type: T, context?: ExecutionContext) => RealtimeRecipient<T>[] | RealtimeRecipient<T>); + +export type RealtimeRecipient<T> = { + room: RealtimePath<T>; + path?: string; + resource?: any | T; +}; + +export function getRealtimeRecipients<T>( + recipients: RealtimeRecipients<T>, + type: T, + context?: ExecutionContext, +): RealtimeRecipient<T>[] { + if (typeof recipients === "function") recipients = recipients(type, context); + if (!recipients) return []; + if (!(recipients as RealtimeRecipient<T>[]).length) + recipients = [recipients as RealtimeRecipient<T>]; + + return (recipients as RealtimeRecipient<T>[]).map(recipient => { + return { + resource: recipient.resource || type, + path: recipient.path || "/", + room: recipient.room, + }; + }); +} + +export type RealtimePath<T> = string | ResourcePath | ResourcePathResolver<T>; +export interface ResourcePathResolver<T> { + (type: T, context?: ExecutionContext): ResourcePath; +} +export interface PathResolver<T> { + (type: T, context?: ExecutionContext): string; +} + +export type RealtimeEntity<T> = null | ((type: T, context?: ExecutionContext) => T); + +export function getRoom<T>( + path: RealtimePath<T> = ResourcePath.default(), + entity: EntityTarget<T>, + context: ExecutionContext, +): ResourcePath { + if (typeof path === "string") { + return ResourcePath.get(path); + } + + return typeof path === "function" ? path(entity.entity, context) : path; +} + +export function getPath<T>( + path: string | PathResolver<T> = "/", + entity: EntityTarget<T>, + context: ExecutionContext, +): string { + return typeof path === "function" ? path(entity.entity, context) : path; +} diff --git a/twake/backend/node/src/core/platform/framework/decorators/realtime/saved.ts b/twake/backend/node/src/core/platform/framework/decorators/realtime/saved.ts new file mode 100644 index 00000000..ca197457 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/decorators/realtime/saved.ts @@ -0,0 +1,41 @@ +import { getRealtimeRecipients, getRoom, RealtimeRecipients } from ".."; +import { SaveResult } from "../../api/crud-service"; +import { RealtimeEntityEvent, RealtimeEntityActionType } from "../../../services/realtime/types"; +import { websocketEventBus } from "../../../services/realtime/bus"; + +/** + * + * @param path the path to push the notification to + * @param resourcePath the path of the resource itself + */ +export function RealtimeSaved<T>(recipients: RealtimeRecipients<T>): MethodDecorator { + // eslint-disable-next-line @typescript-eslint/ban-types + return function (target: Object, propertyKey: string, descriptor: PropertyDescriptor): void { + const originalMethod = descriptor.value; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + descriptor.value = async function (...args: any[]) { + const result: SaveResult<T> = await originalMethod.apply(this, args); + // context should always be the last arg + const context = args && args[args.length - 1]; + + if (!(result instanceof SaveResult)) { + return result; + } + + getRealtimeRecipients(recipients, result.entity, context).forEach( + ({ room, path, resource }) => { + websocketEventBus.publish<T>(RealtimeEntityActionType.Saved, { + type: result.type, + room: getRoom(room, result, context), + resourcePath: path, + entity: resource, + result, + } as RealtimeEntityEvent<T>); + }, + ); + + return result; + }; + }; +} diff --git a/twake/backend/node/src/core/platform/framework/decorators/realtime/updated.ts b/twake/backend/node/src/core/platform/framework/decorators/realtime/updated.ts new file mode 100644 index 00000000..53ace2c2 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/decorators/realtime/updated.ts @@ -0,0 +1,40 @@ +import { getRealtimeRecipients, getRoom, RealtimeRecipients } from ".."; +import { UpdateResult } from "../../api/crud-service"; +import { RealtimeEntityEvent, RealtimeEntityActionType } from "../../../services/realtime/types"; +import { websocketEventBus } from "../../../services/realtime/bus"; + +/** + * + * @param path the path to push the notification to + * @param resourcePath the path of the resource itself + */ +export function RealtimeUpdated<T>(recipients: RealtimeRecipients<T>): MethodDecorator { + // eslint-disable-next-line @typescript-eslint/ban-types + return function (target: Object, propertyKey: string, descriptor: PropertyDescriptor): void { + const originalMethod = descriptor.value; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + descriptor.value = async function (...args: any[]) { + const result: UpdateResult<T> = await originalMethod.apply(this, args); + const context = args && args[args.length - 1]; + + if (!(result instanceof UpdateResult)) { + return result; + } + + getRealtimeRecipients(recipients, result.entity, context).forEach( + ({ room, path, resource }) => { + websocketEventBus.publish<T>(RealtimeEntityActionType.Updated, { + type: result.type, + room: getRoom(room, result, context), + resourcePath: path, + entity: resource, + result, + } as RealtimeEntityEvent<T>); + }, + ); + + return result; + }; + }; +} diff --git a/twake/backend/node/src/core/platform/framework/decorators/service-name.ts b/twake/backend/node/src/core/platform/framework/decorators/service-name.ts new file mode 100644 index 00000000..6899192e --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/decorators/service-name.ts @@ -0,0 +1,10 @@ +import { SERVICENAME_METADATA } from "../api"; + +export function ServiceName(name: string): ClassDecorator { + // eslint-disable-next-line @typescript-eslint/ban-types + return function (target: Function): void { + if (name) { + Reflect.defineMetadata(SERVICENAME_METADATA, name, target.prototype); + } + }; +} diff --git a/twake/backend/node/src/core/platform/framework/decorators/skip.ts b/twake/backend/node/src/core/platform/framework/decorators/skip.ts new file mode 100644 index 00000000..63af50b3 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/decorators/skip.ts @@ -0,0 +1,35 @@ +import { getLogger } from "../logger"; + +const logger = getLogger("core.platform.framework.decorators.Skip"); + +type SkipCondition = () => Promise<boolean> | boolean; + +/** + * Skip a method call based on some condition + */ +export function Skip(condition: SkipCondition): MethodDecorator { + // eslint-disable-next-line @typescript-eslint/ban-types + return function (target: Object, _propertyKey: string, descriptor: PropertyDescriptor): void { + logger.trace("Skipping method call"); + + const originalMethod = descriptor.value; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + descriptor.value = async function (...args: any[]) { + const skipIt = await (condition && condition()); + + if (skipIt) { + return target; + } + + return await originalMethod.apply(this, args); + }; + }; +} + +/** + * Skip when process.env.NODE_ENV is set to "cli" + */ +export function SkipCLI(): MethodDecorator { + return Skip(() => process.env.NODE_ENV === "cli"); +} diff --git a/twake/backend/node/src/core/platform/framework/decorators/webservice.ts b/twake/backend/node/src/core/platform/framework/decorators/webservice.ts new file mode 100644 index 00000000..0dc1f5c7 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/decorators/webservice.ts @@ -0,0 +1,8 @@ +import { PREFIX_METADATA } from "../api"; + +export function WebService(prefix: string = "/"): ClassDecorator { + // eslint-disable-next-line @typescript-eslint/ban-types + return function (target: Function): void { + Reflect.defineMetadata(PREFIX_METADATA, prefix, target.prototype); + }; +} diff --git a/twake/backend/node/src/core/platform/framework/event-bus.ts b/twake/backend/node/src/core/platform/framework/event-bus.ts new file mode 100644 index 00000000..361ea4ce --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/event-bus.ts @@ -0,0 +1,47 @@ +import { Subject } from "rxjs"; +import { logger as rootLogger } from "./logger"; +import { ExecutionContext } from "./api/crud-service"; + +const logger = rootLogger.child({ + component: "twake.core.platform.framework.event-bus", +}); + +/** + * A local event bus in the platform. Used by platform components and services to communicate using publish subscribe. + */ +class EventBus { + private subjects: Map<string, Subject<any>>; + constructor() { + this.subjects = new Map<string, Subject<any>>(); + } + + subscribe<T>(name: string, listener: (_data: T) => void): this { + if (!this.subjects.has(name)) { + this.subjects.set(name, new Subject<T>()); + } + + this.subjects.get(name).subscribe({ + next: (value: T) => { + try { + listener(value); + } catch (err) { + logger.warn({ err }, "Error while calling listener"); + } + }, + }); + + return this; + } + + publish<T>(name: string, data: T, _context?: ExecutionContext): boolean { + if (!this.subjects.has(name)) { + return false; + } + + this.subjects.get(name)?.next(data); + + return true; + } +} + +export const localEventBus = new EventBus(); diff --git a/twake/backend/node/src/core/platform/framework/factory.ts b/twake/backend/node/src/core/platform/framework/factory.ts new file mode 100644 index 00000000..315c13f8 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/factory.ts @@ -0,0 +1,32 @@ +import { + TwakeContext, + TwakeService, + TwakeServiceConfiguration, + TwakeServiceOptions, + TwakeServiceProvider, +} from "./api"; +import { Configuration } from "./configuration"; + +class StaticTwakeServiceFactory { + public async create< + T extends TwakeService<TwakeServiceProvider> = TwakeService<TwakeServiceProvider>, + >( + module: { new (options?: TwakeServiceOptions<TwakeServiceConfiguration>): T }, + context: TwakeContext, + configuration?: string, + ): Promise<T> { + let config; + + if (configuration) { + config = new Configuration(configuration); + } + + const instance = new module({ configuration: config }); + + instance.context = context; + + return instance; + } +} + +export const TwakeServiceFactory = new StaticTwakeServiceFactory(); diff --git a/twake/backend/node/src/core/platform/framework/index.ts b/twake/backend/node/src/core/platform/framework/index.ts new file mode 100644 index 00000000..3fafc09f --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/index.ts @@ -0,0 +1,8 @@ +import "reflect-metadata"; + +export * from "./api"; +export * from "./decorators"; +export * from "./configuration"; +export * from "./factory"; +export * from "./logger"; +export * from "./utils/component-utils"; diff --git a/twake/backend/node/src/core/platform/framework/logger.ts b/twake/backend/node/src/core/platform/framework/logger.ts new file mode 100644 index 00000000..8c0aa335 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/logger.ts @@ -0,0 +1,21 @@ +import pino from "pino"; +import { Configuration } from "./configuration"; + +const config = new Configuration("logger"); + +export type TwakeLogger = pino.Logger; + +export const logger = pino({ + name: "TwakeApp", + level: config.get("level", "info") || "info", + prettyPrint: + process.env.NODE_ENV?.indexOf("test") > -1 + ? { + translateTime: "HH:MM:ss Z", + ignore: "pid,hostname,name", + } + : false, +}); + +export const getLogger = (name?: string): TwakeLogger => + logger.child({ name: `twake${name ? "." + name : ""}` }); diff --git a/twake/backend/node/src/core/platform/framework/utils/component-utils.ts b/twake/backend/node/src/core/platform/framework/utils/component-utils.ts new file mode 100644 index 00000000..f74697e6 --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/utils/component-utils.ts @@ -0,0 +1,108 @@ +/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types */ +import { + logger, + TwakeComponent, + TwakeContext, + TwakeServiceFactory, + TwakeServiceState, +} from "../index"; +import { Loader } from "./loader"; + +export async function buildDependenciesTree( + components: Map<string, TwakeComponent>, + loadComponent: (name: string) => any, +): Promise<void> { + for (const [name, component] of components) { + const dependencies: string[] = component.getServiceInstance().getConsumes() || []; + + for (const dependencyName of dependencies) { + if (name === dependencyName) { + throw new Error(`There is a circular dependency for component ${dependencyName}`); + } + let dependencyComponent = components.get(dependencyName); + + if (!dependencyComponent) { + //Except in the tests, we allow this to happen with a warning + if (process.env.NODE_ENV === "test") { + throw new Error( + `The component dependency ${dependencyName} has not been found for component ${name}`, + ); + } else { + console.warn( + `(warning) The component dependency ${dependencyName} has not been found for component ${name} it will be imported asynchronously`, + ); + + try { + dependencyComponent = await loadComponent(name); + if (dependencyComponent) components.set(name, dependencyComponent); + } catch (err) { + dependencyComponent = null; + } + + if (!dependencyComponent) { + throw new Error( + `The component dependency ${dependencyName} has not been found for component ${name} even with async load`, + ); + } + } + } + + component.addDependency(dependencyComponent); + } + } +} + +/** + * Load specified components from given list of paths + * + * @param paths Paths to search components in + * @param names Components to load + * @param context + */ +export async function loadComponents( + paths: string[], + names: string[] = [], + context: TwakeContext, +): Promise<Map<string, TwakeComponent>> { + const result = new Map<string, TwakeComponent>(); + const loader = new Loader(paths); + + const components: TwakeComponent[] = await Promise.all( + names.map(async name => { + const clazz = await loader.load(name); + const component = new TwakeComponent(name, { clazz, name }); + result.set(name, component); + + return component; + }), + ); + + await Promise.all( + components.map(async component => { + const service = await TwakeServiceFactory.create( + component.getServiceDefinition().clazz, + context, + component.getServiceDefinition().name, + ); + + component.setServiceInstance(service); + }), + ); + + return result; +} + +export async function switchComponentsToState( + components: Map<string, TwakeComponent>, + state: TwakeServiceState.Initialized | TwakeServiceState.Started | TwakeServiceState.Stopped, +): Promise<void> { + const states = []; + + for (const [name, component] of components) { + logger.info(`Asking for ${state} on ${name} dependencies`); + states.push(component.getServiceInstance().state); + await component.switchToState(state); + } + + logger.info(`All components are now in ${state} state`); +} diff --git a/twake/backend/node/src/core/platform/framework/utils/loader.ts b/twake/backend/node/src/core/platform/framework/utils/loader.ts new file mode 100644 index 00000000..40c1bcee --- /dev/null +++ b/twake/backend/node/src/core/platform/framework/utils/loader.ts @@ -0,0 +1,45 @@ +import { logger } from "../logger"; +import fs from "fs"; + +export class Loader { + constructor(readonly paths: string[]) {} + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + async load(componentName: string): Promise<any> { + const modulesPaths = this.paths.map(path => `${path}/${componentName}`); + + let classes = await Promise.all( + modulesPaths.map(async modulePath => { + if (fs.existsSync(modulePath)) { + try { + return await import(modulePath); + } catch (err) { + logger.debug( + { err }, + `${modulePath} can not be loaded (file was found but we were unable to import the module)`, + ); + } + } + }), + ); + + classes = classes.filter(Boolean); + + if (!classes || !classes.length) { + modulesPaths.map(modulePath => { + if (fs.existsSync(modulePath)) { + logger.debug(`${modulePath} content was: [${fs.readdirSync(modulePath).join(", ")}]`); + } + }); + throw new Error( + `Can not find or load ${componentName} in any given path [${modulesPaths.join( + " - ", + )}] see previous logs for more details.`, + ); + } + + logger.debug(`Loaded ${componentName}`); + + return classes[0].default; + } +} diff --git a/twake/backend/node/src/core/platform/platform.ts b/twake/backend/node/src/core/platform/platform.ts new file mode 100644 index 00000000..689703f1 --- /dev/null +++ b/twake/backend/node/src/core/platform/platform.ts @@ -0,0 +1,47 @@ +import { TwakeContainer, TwakeServiceProvider, TwakeComponent } from "./framework"; +import * as ComponentUtils from "./framework/utils/component-utils"; +import path from "path"; + +export class TwakePlatform extends TwakeContainer { + constructor(protected options: TwakePlatformConfiguration) { + super(); + } + + api(): TwakeServiceProvider { + return null; + } + + async loadComponents(): Promise<Map<string, TwakeComponent>> { + return await ComponentUtils.loadComponents( + [this.options.servicesPath, path.resolve(__dirname, "./services/")], + this.options.services, + { + getProvider: this.getProvider.bind(this), + }, + ); + } + + async loadComponent(name: string): Promise<TwakeComponent> { + return ( + await ComponentUtils.loadComponents( + [this.options.servicesPath, path.resolve(__dirname, "./services/")], + [name], + { + getProvider: this.getProvider.bind(this), + }, + ) + ).get(name); + } +} + +export class TwakePlatformConfiguration { + /** + * The services to load in the container + */ + services: string[]; + + /** + * The path to load services from + */ + servicesPath: string; +} diff --git a/twake/backend/node/src/core/platform/services/auth/index.ts b/twake/backend/node/src/core/platform/services/auth/index.ts new file mode 100644 index 00000000..a1f0c028 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/auth/index.ts @@ -0,0 +1,29 @@ +import { TwakeService, Consumes, Prefix, ServiceName } from "../../framework"; +import web from "./web/index"; +import AuthServiceAPI, { JwtConfiguration } from "./provider"; +import { AuthService as AuthServiceImpl } from "./service"; +import WebServerAPI from "../webserver/provider"; + +@Prefix("/api/auth") +@Consumes(["webserver"]) +@ServiceName("auth") +export default class AuthService extends TwakeService<AuthServiceAPI> { + name = "auth"; + service: AuthServiceAPI; + + api(): AuthServiceAPI { + return this.service; + } + + public async doInit(): Promise<this> { + this.service = new AuthServiceImpl(this.configuration.get<JwtConfiguration>("jwt")); + const fastify = this.context.getProvider<WebServerAPI>("webserver").getServer(); + + fastify.register((instance, _opts, next) => { + web(instance, { prefix: this.prefix }); + next(); + }); + + return this; + } +} diff --git a/twake/backend/node/src/core/platform/services/auth/provider.ts b/twake/backend/node/src/core/platform/services/auth/provider.ts new file mode 100644 index 00000000..264430d1 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/auth/provider.ts @@ -0,0 +1,39 @@ +import { TwakeServiceProvider } from "../../framework/api"; +import { AccessToken, JWTObject, uuid } from "../../../../utils/types"; + +export default interface AuthServiceAPI extends TwakeServiceProvider { + /** + * Get the authentication types + */ + getTypes(): Array<string>; + + /** + * Sign payload + */ + sign(payload: any): string; + + /** + * Verify token + * + * @param token + */ + verifyToken(token: string): JWTObject; + + verifyTokenObject<T>(token: string): T; + + generateJWT( + userId: uuid, + email: string, + options: { + track: boolean; + provider_id: string; + application_id?: string; + } & any, + ): AccessToken; +} + +export interface JwtConfiguration { + secret: string; + expiration: number; + refresh_expiration: number; +} diff --git a/twake/backend/node/src/core/platform/services/auth/service.ts b/twake/backend/node/src/core/platform/services/auth/service.ts new file mode 100644 index 00000000..1fb716fa --- /dev/null +++ b/twake/backend/node/src/core/platform/services/auth/service.ts @@ -0,0 +1,71 @@ +import { JwtConfiguration } from "./provider"; +import jwt from "jsonwebtoken"; +import { AccessToken, JWTObject, uuid } from "../../../../utils/types"; +import assert from "assert"; +import { JwtType } from "../types"; +import AuthServiceAPI from "./provider"; + +export class AuthService implements AuthServiceAPI { + version: "1"; + + constructor(private configuration: JwtConfiguration) {} + + getTypes(): string[] { + throw new Error("Method not implemented."); + } + + // eslint-disable-next-line @typescript-eslint/ban-types + sign(payload: string | object | Buffer): string { + return jwt.sign(payload, this.configuration.secret); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + verifyToken(token: string): JWTObject { + return jwt.verify(token, this.configuration.secret) as JWTObject; + } + + verifyTokenObject<T>(token: string): T { + return jwt.verify(token, this.configuration.secret) as T; + } + + generateJWT( + userId: uuid, + email: string, + options: { track: boolean; provider_id: string; application_id?: string }, + ): AccessToken { + const now = Math.round(new Date().getTime() / 1000); // Current time in UTC + assert(this.configuration.expiration, "jwt.expiration is missing"); + assert(this.configuration.refresh_expiration, "jwt.refresh_expiration is missing"); + + const jwtExpiration = now + this.configuration.expiration; + const jwtRefreshExpiration = now + this.configuration.refresh_expiration; + return { + time: now, + expiration: jwtExpiration, + refresh_expiration: jwtRefreshExpiration, + value: this.sign({ + exp: jwtExpiration, + type: "access", + iat: now - 60 * 10, + nbf: now - 60 * 10, + sub: userId, + email: email, + track: !!options.track, + provider_id: options.provider_id || "", + application_id: options.application_id, + } as JwtType), + refresh: this.sign({ + exp: jwtRefreshExpiration, + type: "refresh", + iat: now - 60 * 10, + nbf: now - 60 * 10, + sub: userId, + email: email, + track: !!options.track, + provider_id: options.provider_id || "", + application_id: options.application_id, + } as JwtType), + type: "Bearer", + }; + } +} diff --git a/twake/backend/node/src/core/platform/services/auth/web/index.ts b/twake/backend/node/src/core/platform/services/auth/web/index.ts new file mode 100644 index 00000000..bbae27fc --- /dev/null +++ b/twake/backend/node/src/core/platform/services/auth/web/index.ts @@ -0,0 +1,10 @@ +import { FastifyInstance, FastifyRegisterOptions } from "fastify"; +import routes from "./routes"; + +export default ( + fastify: FastifyInstance, + opts: FastifyRegisterOptions<{ prefix: string }>, +): void => { + fastify.log.debug("Configuring /auth"); + fastify.register(routes, opts); +}; diff --git a/twake/backend/node/src/core/platform/services/auth/web/jwt.ts b/twake/backend/node/src/core/platform/services/auth/web/jwt.ts new file mode 100644 index 00000000..ea29de27 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/auth/web/jwt.ts @@ -0,0 +1,47 @@ +import { FastifyPluginCallback, FastifyRequest } from "fastify"; +import fastifyJwt from "fastify-jwt"; +import fp from "fastify-plugin"; +import config from "../../../../config"; +import { JwtType } from "../../types"; + +const jwtPlugin: FastifyPluginCallback = (fastify, _opts, next) => { + fastify.register(fastifyJwt, { + secret: config.get("auth.jwt.secret"), + }); + + const authenticate = async (request: FastifyRequest) => { + const jwt: JwtType = await request.jwtVerify(); + if (jwt.type === "refresh") { + // TODO in the future we must invalidate the refresh token (because it should be single use) + } + request.currentUser = { + ...{ email: jwt.email }, + ...{ id: jwt.sub }, + ...{ identity_provider_id: jwt.provider_id }, + ...{ application_id: jwt.application_id || null }, + ...{ server_request: jwt.server_request || false }, + ...{ allow_tracking: jwt.track || false }, + }; + request.log.debug(`Authenticated as user ${request.currentUser.id}`); + }; + + fastify.decorate("authenticate", async (request: FastifyRequest) => { + try { + await authenticate(request); + } catch (err) { + throw fastify.httpErrors.unauthorized("Bad credentials"); + } + }); + + fastify.decorate("authenticateOptional", async (request: FastifyRequest) => { + try { + await authenticate(request); + } catch (err) {} + }); + + next(); +}; + +export default fp(jwtPlugin, { + name: "authenticate", +}); diff --git a/twake/backend/node/src/core/platform/services/auth/web/routes.ts b/twake/backend/node/src/core/platform/services/auth/web/routes.ts new file mode 100644 index 00000000..e4e43fd8 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/auth/web/routes.ts @@ -0,0 +1,18 @@ +import { FastifyInstance, FastifyPluginCallback } from "fastify"; +import { v4 as uuidv4 } from "uuid"; + +const routes: FastifyPluginCallback = (fastify: FastifyInstance, _opts, next) => { + fastify.get("/login", async (_request, reply) => { + const userId = uuidv4(); + reply.send({ + token: fastify.jwt.sign({ sub: userId }), + user: { + id: userId, + }, + }); + }); + + next(); +}; + +export default routes; diff --git a/twake/backend/node/src/core/platform/services/counter/index.ts b/twake/backend/node/src/core/platform/services/counter/index.ts new file mode 100644 index 00000000..3e14ec8d --- /dev/null +++ b/twake/backend/node/src/core/platform/services/counter/index.ts @@ -0,0 +1,21 @@ +import { TwakeService } from "../../framework"; +import { CounterProvider } from "./provider"; +import { CounterAPI } from "./types"; +import Repository from "../database/services/orm/repository/repository"; + +export default class CounterService extends TwakeService<CounterAPI> implements CounterAPI { + name = "counter"; + version = "1"; + + api(): CounterAPI { + return this; + } + + async doInit(): Promise<this> { + return Promise.resolve(this); + } + + getCounter<T>(repository: Repository<T>): CounterProvider<T> { + return new CounterProvider(repository); + } +} diff --git a/twake/backend/node/src/core/platform/services/counter/provider.ts b/twake/backend/node/src/core/platform/services/counter/provider.ts new file mode 100644 index 00000000..3fbb9f7a --- /dev/null +++ b/twake/backend/node/src/core/platform/services/counter/provider.ts @@ -0,0 +1,91 @@ +import Repository from "../database/services/orm/repository/repository"; +import { logger } from "../../framework"; +import { ExecutionContext } from "../../framework/api/crud-service"; + +type LastRevised = { + calls: number; + period: number; +}; + +export class CounterProvider<T> { + private name = "CounterProvider"; + + protected readonly repository: Repository<T>; + + private reviseHandler: (pk: Partial<T>) => Promise<number>; + private reviseMaxCalls = 0; + private reviseMaxPeriod = 0; + + private lastRevisedMap = new Map<string, LastRevised>(); + + constructor(repository: Repository<T>) { + this.repository = repository; + logger.debug(`${this.name} Created counter provider for ${this.repository.table}`); + } + + async increase(pk: Partial<T>, value: number, context?: ExecutionContext): Promise<void> { + return this.repository.save(this.repository.createEntityFromObject({ value, ...pk }), context); + } + + async get(pk: Partial<T>, context?: ExecutionContext): Promise<number> { + try { + const counter = await this.repository.findOne(pk, {}, context); + const val = counter ? (counter as any).value : 0; + return this.revise(pk, val); + } catch (e) { + throw e; + } + } + + setReviseCallback( + handler: (pk: Partial<T>) => Promise<number>, + maxCalls: number = 10, + maxPeriod: number = 24 * 60 * 60 * 1000, + ): void { + logger.debug(`${this.name} Set setReviseCallback for ${this.repository.table}`); + this.reviseHandler = handler; + this.reviseMaxCalls = maxCalls; + this.reviseMaxPeriod = maxPeriod; + } + + private async revise(pk: Partial<T>, currentValue: number): Promise<number> { + const now = new Date().getTime(); + const lastRevised: LastRevised = this.lastRevisedMap.get(JSON.stringify(pk)) || { + calls: -1, + period: now, + }; + + logger.debug( + `${this.name} revision status for ${JSON.stringify(pk)} is ${JSON.stringify(lastRevised)}`, + ); + + if ( + lastRevised.calls >= this.reviseMaxCalls || + now > lastRevised.period + this.reviseMaxPeriod || + Math.random() < 1 / Math.max(1, currentValue) //The slowest the number is, the more we update it + ) { + if (!this.reviseHandler) { + logger.debug( + `${this.name} No setReviseCallback handler found for ${this.repository.table}`, + ); + return currentValue; + } + + logger.debug(`${this.name} Execute setReviseCallback handler for ${this.repository.table}`); + + const actual = await this.reviseHandler(pk); + + if (actual !== undefined && actual != currentValue) { + await this.increase(pk, actual - currentValue); + currentValue = actual; + } + lastRevised.calls = 0; + lastRevised.period = now; + } else { + lastRevised.calls++; + } + + this.lastRevisedMap.set(JSON.stringify(pk), lastRevised); + return currentValue; + } +} diff --git a/twake/backend/node/src/core/platform/services/counter/types.ts b/twake/backend/node/src/core/platform/services/counter/types.ts new file mode 100644 index 00000000..c3b83ff6 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/counter/types.ts @@ -0,0 +1,7 @@ +import { TwakeServiceProvider } from "../../framework"; +import Repository from "../database/services/orm/repository/repository"; +import { CounterProvider } from "./provider"; + +export interface CounterAPI extends TwakeServiceProvider { + getCounter<T>(repository: Repository<T>): CounterProvider<T>; +} diff --git a/twake/backend/node/src/core/platform/services/cron/api.ts b/twake/backend/node/src/core/platform/services/cron/api.ts new file mode 100644 index 00000000..2d495b77 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/cron/api.ts @@ -0,0 +1,35 @@ +import { ScheduledTask } from "node-cron"; +import { TwakeServiceProvider } from "../../framework"; + +export type CronJob = () => void; + +export type CronExpression = string; + +export type CronTask = { + id: string; + description: string; + task: ScheduledTask; + startDate: number; + lastRun: number; + nbRuns: number; + nbErrors: number; + lastError?: Error; + start: () => void; + stop: () => void; +}; + +export interface CronAPI extends TwakeServiceProvider { + /** + * Schedule a Job + * + * @param expression + * @param job + * @param callback + */ + schedule(expression: CronExpression, job: CronJob, description?: string): CronTask; + + /** + * Get the list of current tasks + */ + getTasks(): CronTask[]; +} diff --git a/twake/backend/node/src/core/platform/services/cron/index.ts b/twake/backend/node/src/core/platform/services/cron/index.ts new file mode 100644 index 00000000..b2e09283 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/cron/index.ts @@ -0,0 +1,53 @@ +import * as cron from "node-cron"; +import uuid from "node-uuid"; + +import { TwakeService } from "../../framework"; +import { CronAPI, CronJob, CronExpression, CronTask } from "./api"; + +export default class CronService extends TwakeService<CronAPI> implements CronAPI { + name = "cron"; + version = "1"; + private tasks = new Array<CronTask>(); + + api(): CronAPI { + return this; + } + + schedule(expression: CronExpression, job: CronJob, description?: string): CronTask { + this.logger.debug(`Submit new job with name ${description}`); + const task: CronTask = { + id: uuid.v4(), + description: description || "", + startDate: Date.now(), + lastRun: 0, + nbErrors: 0, + nbRuns: 0, + task: cron.schedule(expression, () => { + task.lastRun = Date.now(); + task.nbRuns++; + this.logger.debug(`Running job ${description || "untitled"}`); + try { + job(); + } catch (err) { + this.logger.error("Error while running job", err); + task.nbErrors++; + task.lastError = err; + } + }), + stop: () => { + task.task.stop(); + }, + start: () => { + task.task.start(); + }, + }; + + this.tasks.push(task); + + return task; + } + + getTasks(): CronTask[] { + return this.tasks; + } +} diff --git a/twake/backend/node/src/core/platform/services/database/api.ts b/twake/backend/node/src/core/platform/services/database/api.ts new file mode 100644 index 00000000..b5312f70 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/api.ts @@ -0,0 +1,25 @@ +import { TwakeServiceProvider } from "../../framework"; +import { Connector } from "./services/orm/connectors"; +import Manager from "./services/orm/manager"; +import Repository from "./services/orm/repository/repository"; +import { EntityTarget } from "./services/orm/types"; + +export interface DatabaseServiceAPI extends TwakeServiceProvider { + /** + * Get the database connector + */ + getConnector(): Connector; + + /** + * Get entities manager (TODO: Find a better name...) + */ + getManager(): Manager<unknown>; + + /** + * Get repository for given entity + * + * @param table + * @param entity + */ + getRepository<Entity>(table: string, entity: EntityTarget<Entity>): Promise<Repository<Entity>>; +} diff --git a/twake/backend/node/src/core/platform/services/database/index.ts b/twake/backend/node/src/core/platform/services/database/index.ts new file mode 100644 index 00000000..a2ec8261 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/index.ts @@ -0,0 +1,42 @@ +import { TwakeService, logger, ServiceName } from "../../framework"; +import { DatabaseServiceAPI } from "./api"; +import DatabaseService from "./services"; +import { DatabaseType } from "./services"; +import { ConnectionOptions } from "./services/orm/connectors"; + +@ServiceName("database") +export default class Database extends TwakeService<DatabaseServiceAPI> { + version = "1"; + name = "database"; + service: DatabaseService; + + public async doInit(): Promise<this> { + const driver = this.configuration.get<DatabaseType>("type"); + const secret = this.configuration.get<string>("secret"); + + if (!driver) { + throw new Error("Database driver name must be specified in 'database.type' configuration"); + } + + const configuration: ConnectionOptions = this.configuration.get<ConnectionOptions>(driver); + + this.service = new DatabaseService(driver, configuration, secret); + const dbConnector = this.service.getConnector(); + + try { + logger.info("Connecting to database %o", configuration); + await dbConnector.connect(); + await dbConnector.init(); + logger.info("Connected to database"); + } catch (err) { + logger.error("Failed to connect to database", err); + throw new Error("Failed to connect to db"); + } + + return this; + } + + api(): DatabaseServiceAPI { + return this.service; + } +} diff --git a/twake/backend/node/src/core/platform/services/database/services/connector-factory.ts b/twake/backend/node/src/core/platform/services/database/services/connector-factory.ts new file mode 100644 index 00000000..9c12f1b9 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/connector-factory.ts @@ -0,0 +1,20 @@ +import { DatabaseType } from "."; +import { ConnectionOptions, Connector } from "./orm/connectors"; +import { + CassandraConnectionOptions, + CassandraConnector, +} from "./orm/connectors/cassandra/cassandra"; +import { MongoConnectionOptions, MongoConnector } from "./orm/connectors/mongodb/mongodb"; + +export class ConnectorFactory { + public create(type: DatabaseType, options: ConnectionOptions, secret: string): Connector { + switch (type) { + case "cassandra": + return new CassandraConnector(type, options as CassandraConnectionOptions, secret); + case "mongodb": + return new MongoConnector(type, options as MongoConnectionOptions, secret); + default: + throw new Error(`${type} is not supported`); + } + } +} diff --git a/twake/backend/node/src/core/platform/services/database/services/index.ts b/twake/backend/node/src/core/platform/services/database/services/index.ts new file mode 100644 index 00000000..fe3a0914 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/index.ts @@ -0,0 +1,45 @@ +import { DatabaseServiceAPI } from "../api"; +import { ConnectorFactory } from "./connector-factory"; +import { Connector } from "./orm/connectors"; +import Manager from "./orm/manager"; +import Repository from "./orm/repository/repository"; +import { CassandraConnectionOptions } from "./orm/connectors/cassandra/cassandra"; +import { MongoConnectionOptions } from "./orm/connectors/mongodb/mongodb"; +import { EntityTarget } from "./orm/types"; +import { RepositoryManager } from "./orm/repository/manager"; + +export default class DatabaseService implements DatabaseServiceAPI { + version = "1"; + private connector: Connector; + private entityManager: RepositoryManager; + + constructor( + readonly type: DatabaseType, + private options: ConnectionOptions, + readonly secret: string, + ) { + this.entityManager = new RepositoryManager(this); + } + + getConnector(): Connector { + if (this.connector) { + return this.connector; + } + + this.connector = new ConnectorFactory().create(this.type, this.options, this.secret); + + return this.connector; + } + + getManager(): Manager<unknown> { + return new Manager<unknown>(this.connector); + } + + getRepository<Entity>(table: string, entity: EntityTarget<Entity>): Promise<Repository<Entity>> { + return this.entityManager.getRepository(table, entity); + } +} + +export declare type ConnectionOptions = MongoConnectionOptions | CassandraConnectionOptions; + +export declare type DatabaseType = "mongodb" | "cassandra"; diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/connectors/abstract-connector.ts b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/abstract-connector.ts new file mode 100644 index 00000000..92b41c27 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/abstract-connector.ts @@ -0,0 +1,45 @@ +/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types */ +import { Connector } from "."; +import { ConnectionOptions, DatabaseType } from "../.."; +import { FindOptions } from "../repository/repository"; +import { ColumnDefinition, EntityDefinition } from "../types"; +import { ListResult } from "../../../../../framework/api/crud-service"; + +export abstract class AbstractConnector<T extends ConnectionOptions, DatabaseClient> + implements Connector +{ + constructor(protected type: DatabaseType, protected options: T, protected secret: string) {} + + abstract connect(): Promise<this>; + + abstract drop(): Promise<this>; + + abstract getClient(): DatabaseClient; + + abstract createTable( + entity: EntityDefinition, + columns: { [name: string]: ColumnDefinition }, + ): Promise<boolean>; + + abstract upsert(entities: any[]): Promise<boolean[]>; + + abstract remove(entities: any[]): Promise<boolean[]>; + + abstract find<EntityType>( + entityType: any, + filters: any, + options: FindOptions, + ): Promise<ListResult<EntityType>>; + + getOptions(): T { + return this.options; + } + + getType(): DatabaseType { + return this.type; + } + + getSecret(): string { + return this.secret; + } +} diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/connectors/cassandra/cassandra.ts b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/cassandra/cassandra.ts new file mode 100644 index 00000000..32bb6f1c --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/cassandra/cassandra.ts @@ -0,0 +1,578 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import cassandra, { types } from "cassandra-driver"; +import { md5 } from "../../../../../../../crypto"; +import { defer, Subject, throwError, timer } from "rxjs"; +import { concat, delayWhen, retryWhen, take, tap } from "rxjs/operators"; +import { UpsertOptions } from ".."; +import { logger } from "../../../../../../framework"; +import { getEntityDefinition, unwrapIndexes, unwrapPrimarykey } from "../../utils"; +import { EntityDefinition, ColumnDefinition, ObjectType } from "../../types"; +import { AbstractConnector } from "../abstract-connector"; +import { + transformValueToDbString, + cassandraType, + transformValueFromDbString, +} from "./typeTransforms"; +import { FindOptions } from "../../repository/repository"; +import { ListResult, Pagination } from "../../../../../../framework/api/crud-service"; +import { Paginable } from "../../../../../../framework/api/crud-service"; +import { buildSelectQuery } from "./query-builder"; + +export { CassandraPagination } from "./pagination"; + +export interface CassandraConnectionOptions { + contactPoints: string[]; + localDataCenter: string; + username: string; + password: string; + keyspace: string; + + /** + * Consistency level + */ + queryOptions: { consistency: number }; + + /** + * Wait for keyspace and tables to be created at init + */ + wait: boolean; + + /** + * When wait = true, retry to get the resources N times where N = retries + */ + retries?: number; + + /** + * Delay in ms between the retries. The delay is growing each time a retry fails like delay = retryCount * delay + */ + delay?: number; +} + +export class CassandraConnector extends AbstractConnector< + CassandraConnectionOptions, + cassandra.Client +> { + private client: cassandra.Client; + private keyspaceExists = false; + + getClient(): cassandra.Client { + return this.client; + } + + async init(): Promise<this> { + if (!this.client) { + await this.connect(); + } + + try { + await this.createKeyspace(); + } catch (err) { + logger.warn("services.database.orm.cassandra - Keyspace can not be created", err); + } + + if (this.options.wait) { + await this.waitForKeyspace(this.options.delay, this.options.retries); + } + + return this; + } + + createKeyspace(): Promise<cassandra.types.ResultSet> { + const query = `CREATE KEYSPACE IF NOT EXISTS ${this.options.keyspace} WITH replication = {'class': 'NetworkTopologyStrategy', 'datacenter1': '2'} AND durable_writes = true;`; + logger.info(query); + return this.client.execute(query); + } + + async isKeyspaceCreated(): Promise<boolean> { + let result; + + if (this.keyspaceExists) { + return true; + } + + try { + result = await this.client.execute( + `SELECT * FROM system_schema.keyspaces where keyspace_name = '${this.options.keyspace}'`, + ); + + if (!result) { + throw new Error("No result for keyspace query"); + } + } catch (err) { + throw new Error("Keyspace query error"); + } + + if (result) { + await new Promise(resolve => setTimeout(resolve, 2000)); + this.keyspaceExists = true; + logger.info(`Keyspace '${this.options.keyspace}' found.`); + } + + return result ? Promise.resolve(true) : Promise.reject(new Error("Keyspace not found")); + } + + waitForKeyspace(delay: number = 500, retries: number = 10): Promise<boolean> { + const subject = new Subject<boolean>(); + const obs$ = defer(() => this.isKeyspaceCreated()); + + obs$ + .pipe( + retryWhen(errors => + errors.pipe( + delayWhen((_, i) => timer(i * delay)), + //delay(1000), if we want fixed delay + tap(() => logger.debug("services.database.orm.cassandra - Retrying...")), + take(retries), + concat(throwError("Maximum number of retries reached")), + ), + ), + ) + .subscribe( + () => logger.debug("services.database.orm.cassandra - Keyspace has been found"), + err => { + logger.error( + { err }, + "services.database.orm.cassandra - Error while getting keyspace information", + ); + subject.error(new Error("Can not find keyspace information")); + }, + () => subject.complete(), + ); + + return subject.toPromise(); + } + + async drop(): Promise<this> { + logger.info("Drop database is not implemented for security reasons."); + return this; + } + + async connect(): Promise<this> { + if (this.client) { + return this; + } + + // Environment variable format is comma separated string + const contactPoints = + typeof this.options.contactPoints === "string" + ? (this.options.contactPoints as string).split(",") + : this.options.contactPoints; + + const cassandraOptions: cassandra.DseClientOptions = { + contactPoints: contactPoints, + localDataCenter: this.options.localDataCenter, + queryOptions: {}, + }; + + if (this.options.username && this.options.password) { + cassandraOptions.authProvider = new cassandra.auth.PlainTextAuthProvider( + this.options.username, + this.options.password, + ); + } + + //Set default consistency level to quorum + cassandraOptions.queryOptions.consistency = + this.options?.queryOptions?.consistency || types.consistencies.quorum; + + this.client = new cassandra.Client(cassandraOptions); + await this.client.connect(); + + return this; + } + + async getTableDefinition(name: string): Promise<string[]> { + let result: string[]; + + try { + const query = `SELECT column_name from system_schema.columns WHERE keyspace_name = '${this.options.keyspace}' AND table_name='${name}';`; + const dbResult = await this.client.execute(query); + result = dbResult.rows.map(row => row.values()[0]); + } catch (err) { + throw "Table query error"; + } + + return result ? Promise.resolve(result || []) : Promise.resolve([]); + } + + async createTable( + entity: EntityDefinition, + columns: { [name: string]: ColumnDefinition }, + ): Promise<boolean> { + await this.waitForKeyspace(this.options.delay, this.options.retries); + + let result = true; + + // --- Generate column and key definition --- // + const primaryKey = entity.options.primaryKey || []; + + if (primaryKey.length === 0) { + logger.error( + `services.database.orm.cassandra - Primary key was not defined for table ${entity.name}`, + ); + return false; + } + + const partitionKeyPart = primaryKey.shift(); + const partitionKey: string[] = + typeof partitionKeyPart === "string" ? [partitionKeyPart] : partitionKeyPart; + const clusteringKeys: string[] = primaryKey as string[]; + if ([...partitionKey, ...clusteringKeys].some(key => columns[key] === undefined)) { + logger.error( + `services.database.orm.cassandra - One primary key item doesn't exists in entity columns for table ${entity.name}`, + ); + return false; + } + + const clusteringOrderBy = clusteringKeys.map(key => { + const direction: "ASC" | "DESC" = columns[key].options.order || "ASC"; + return `${key} ${direction}`; + }); + const clusteringOrderByString = + clusteringOrderBy.length > 0 + ? `WITH CLUSTERING ORDER BY (${clusteringOrderBy.join(", ")})` + : ""; + + const allKeys = [`(${partitionKey.join(", ")})`, ...clusteringKeys]; + const primaryKeyString = `(${allKeys.join(", ")})`; + + const columnsString = Object.keys(columns) + .map(colName => { + const definition = columns[colName]; + return `${colName} ${cassandraType[definition.type]}`; + }) + .join(",\n"); + + // --- Generate final create table query --- // + let query = ` + CREATE TABLE IF NOT EXISTS ${this.options.keyspace}.${entity.name} + ( + ${columnsString}, + PRIMARY KEY ${primaryKeyString} + ) ${clusteringOrderByString};`; + + // --- Alter table if not up to date --- // + const existingColumns = await this.getTableDefinition(entity.name); + if (existingColumns.length > 0) { + logger.debug( + `services.database.orm.cassandra - Existing columns for table ${entity.name}, generating altertable queries`, + ); + const alterQueryColumns = Object.keys(columns) + .filter(colName => existingColumns.indexOf(colName) < 0) + .map(colName => `${colName} ${cassandraType[columns[colName].type]}`); + query = `ALTER TABLE ${this.options.keyspace}.${entity.name} ADD (${alterQueryColumns.join( + ", ", + )})`; + + if (alterQueryColumns.length === 0) { + return true; + } + } + + // --- Write table --- // + try { + logger.debug(`service.database.orm.createTable - Creating table ${entity.name} : ${query}`); + await this.client.execute(query); + } catch (err) { + logger.warn( + { err }, + `service.database.orm.createTable - creation error for table ${entity.name} : ${err.message}`, + ); + result = false; + } + + // --- Create indexes --- // + if (entity.options.globalIndexes) { + for (const globalIndex of entity.options.globalIndexes) { + const indexName = globalIndex.join("_"); + const indexDbName = `index_${md5(indexName)}`; + + const query = `CREATE INDEX IF NOT EXISTS ${indexDbName} ON ${this.options.keyspace}."${ + entity.name + }" (${ + globalIndex.length === 1 ? globalIndex[0] : `(${globalIndex[0]}), ${globalIndex[1]}` + })`; + + try { + logger.debug( + `service.database.orm.createTable - Creating index ${indexName} (${indexDbName}) : ${query}`, + ); + await this.client.execute(query); + } catch (err) { + logger.warn( + { err }, + `service.database.orm.createTable - creation error for index ${indexName} (${indexDbName}) : ${err.message}`, + ); + result = false; + } + } + } + + return result; + } + + async upsert(entities: any[], _options: UpsertOptions = {}): Promise<boolean[]> { + return new Promise(resolve => { + const promises: Promise<boolean>[] = []; + + entities.forEach(entity => { + const { columnsDefinition, entityDefinition } = getEntityDefinition(entity); + const primaryKey = unwrapPrimarykey(entityDefinition); + + //Set updated content + const set = Object.keys(columnsDefinition) + .filter(key => primaryKey.indexOf(key) === -1) + .filter(key => entity[columnsDefinition[key].nodename] !== undefined) + .map(key => [ + `${key}`, + `${transformValueToDbString( + entity[columnsDefinition[key].nodename], + columnsDefinition[key].type, + { + columns: columnsDefinition[key].options, + secret: this.secret, + column: { key }, + }, + )}`, + ]); + //Set primary key + const where = primaryKey.map(key => [ + `${key}`, + `${transformValueToDbString( + entity[columnsDefinition[key].nodename], + columnsDefinition[key].type, + { + columns: columnsDefinition[key].options, + secret: this.secret, + disableSalts: true, + column: { key }, + }, + )}`, + ]); + + // Add time-to-live options + let ttlOptions = ""; + if (entityDefinition.options.ttl && entityDefinition.options.ttl > 0) { + ttlOptions = `USING TTL ${entityDefinition.options.ttl}`; + } + + // Insert and update are equivalent for most of Cassandra + // Update is prefered because the only solution for counters + let query = `UPDATE ${this.options.keyspace}.${ + entityDefinition.name + } ${ttlOptions} SET ${set.map(e => `${e[0]} = ${e[1]}`).join(", ")} WHERE ${where + .map(e => `${e[0]} = ${e[1]}`) + .join(" AND ")}`; + + // If no "set" part, we cannot do an update, so insert + if (set.length === 0) { + query = `INSERT INTO ${this.options.keyspace}.${ + entityDefinition.name + } ${ttlOptions} (${where.map(e => e[0]).join(", ")}) VALUES (${where + .map(e => e[1]) + .join(", ")})`; + } + + logger.debug(`service.database.orm.upsert - Query: "${query}"`); + + promises.push( + new Promise(async resolve => { + try { + await this.getClient().execute(query); + resolve(true); + } catch (err) { + logger.error( + { err }, + `services.database.orm.cassandra - Error with CQL query: ${query}`, + ); + resolve(false); + } + }), + ); + }); + + Promise.all(promises).then(resolve); + }); + } + + async remove(entities: any[]): Promise<boolean[]> { + return new Promise(resolve => { + const promises: Promise<boolean>[] = []; + + entities.forEach(entity => { + const { columnsDefinition, entityDefinition } = getEntityDefinition(entity); + const primaryKey = unwrapPrimarykey(entityDefinition); + + //Set primary key + const where = primaryKey.map( + key => + `${key} = ${transformValueToDbString( + entity[columnsDefinition[key].nodename], + columnsDefinition[key].type, + { + columns: columnsDefinition[key].options, + secret: this.secret, + disableSalts: true, + column: { key }, + }, + )}`, + ); + + const query = `DELETE FROM ${this.options.keyspace}.${ + entityDefinition.name + } WHERE ${where.join(" AND ")}`; + logger.debug(`services.database.orm.cassandra.remove - Query: ${query}`); + + promises.push( + new Promise(async resolve => { + try { + await this.getClient().execute(query); + resolve(true); + } catch (err) { + logger.error( + { err }, + `services.database.orm.cassandra.remove - Error with CQL query: ${query}`, + ); + resolve(false); + } + }), + ); + }); + + Promise.all(promises).then(resolve); + }); + } + + async find<Table>( + entityType: Table, + filters: any, + options: FindOptions = {}, + ): Promise<ListResult<Table>> { + const instance = new (entityType as any)(); + const { columnsDefinition, entityDefinition } = getEntityDefinition(instance); + + const pk = unwrapPrimarykey(entityDefinition); + const indexes = unwrapIndexes(entityDefinition); + + if ( + Object.keys(filters).some(key => pk.indexOf(key) < 0) && + Object.keys(filters).some(key => indexes.indexOf(key) < 0) + ) { + //Filter not in primary key + throw new Error( + `All filter parameters must be defined in entity primary key, + got: ${JSON.stringify(Object.keys(filters))} + on table ${entityDefinition.name} but pk is ${JSON.stringify(pk)}, + instance was ${JSON.stringify(instance)}`, + ); + } + + const query = buildSelectQuery<Table>( + entityType as unknown as ObjectType<Table>, + filters, + options, + { + keyspace: this.options.keyspace, + secret: this.secret, + }, + ); + + logger.debug(`services.database.orm.cassandra.find - Query: ${query}`); + + const results = await this.getClient().execute(query, [], { + fetchSize: parseInt(options.pagination.limitStr) || 100, + pageState: options.pagination.page_token || undefined, + prepare: false, + }); + + const entities: Table[] = []; + results.rows.forEach(row => { + const entity = new (entityType as any)(); + Object.keys(row).forEach(key => { + if (columnsDefinition[key]) { + entity[columnsDefinition[key].nodename] = transformValueFromDbString( + row[key], + columnsDefinition[key].type, + { column: { key: key, ...columnsDefinition[key].options }, secret: this.secret }, + ); + } + }); + entities.push(entity); + }); + + const nextPage: Paginable = new Pagination( + results.pageState, + options.pagination.limitStr || "100", + ); + logger.debug( + `services.database.orm.cassandra.find - Query Result (items=${entities.length}): ${query}`, + ); + + return new ListResult<Table>(entityDefinition.type, entities, nextPage); + } +} + +export function waitForTable( + client: cassandra.Client, + keyspace: string, + table: string, + retries: number = 10, + delay: number = 500, +): Promise<boolean> { + const subject = new Subject<boolean>(); + const obs$ = defer(() => checkForTable(client, keyspace, table)); + + obs$ + .pipe( + retryWhen(errors => + errors.pipe( + delayWhen((_, i) => timer(i * delay)), + //delay(1000), + tap(() => + logger.debug("services.database.orm.cassandra - Retrying to get table metadata..."), + ), + take(retries), + concat(throwError("Maximum number of retries reached")), + ), + ), + ) + .subscribe( + () => logger.debug(`services.database.orm.cassandra - Table ${table} has been found`), + err => { + logger.debug({ err }, `services.database.orm.cassandra - Table ${table} error`); + subject.error(new Error("Can not find table")); + }, + () => subject.complete(), + ); + + return subject.toPromise(); +} + +async function checkForTable( + client: cassandra.Client, + keyspace: string, + table: string, +): Promise<void> { + try { + const result: cassandra.types.ResultSet = await client.execute( + `SELECT * FROM system_schema.tables WHERE keyspace_name='${keyspace}' AND table_name='${table}'`, + ); + + const tableMetadata = result.rows[0]; + + logger.debug( + "services.database.orm.cassandra.checkForTable - Table metadata %o", + tableMetadata, + ); + + if (!tableMetadata) { + throw new Error("Can not find table metadata"); + } + } catch (err) { + logger.error( + { err }, + "services.database.orm.cassandra.checkForTable - Error while getting table metadata", + ); + throw new Error("Error while getting table metadata"); + } +} diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/connectors/cassandra/pagination.ts b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/cassandra/pagination.ts new file mode 100644 index 00000000..5bce1de9 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/cassandra/pagination.ts @@ -0,0 +1,19 @@ +import { Paginable } from "../../../../../../framework/api/crud-service"; +import { Pagination } from "../../../../../../framework/api/crud-service"; + +export class CassandraPagination extends Pagination { + limit = 100; + + private constructor(readonly page_token: string, readonly limitStr = "100") { + super(page_token, limitStr); + this.limit = Number.parseInt(limitStr, 10); + } + + static from(pagination: Paginable): CassandraPagination { + return new CassandraPagination(pagination.page_token, pagination.limitStr); + } + + static next(current: Pagination, pageState: string): Paginable { + return new Pagination(pageState, current.limitStr); + } +} diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/connectors/cassandra/query-builder.ts b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/cassandra/query-builder.ts new file mode 100644 index 00000000..192c1573 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/cassandra/query-builder.ts @@ -0,0 +1,131 @@ +import { FindOptions } from "../../repository/repository"; +import { ObjectType } from "../../types"; +import { getEntityDefinition, secureOperators } from "../../utils"; +import { transformValueToDbString } from "./typeTransforms"; + +export function buildSelectQuery<Entity>( + entityType: ObjectType<Entity>, + filters: Record<string, unknown>, + findOptions: FindOptions, + options: { + secret?: string; + keyspace: string; + } = { + secret: "", + keyspace: "twake", + }, +): string { + const instance = new (entityType as any)(); + const { columnsDefinition, entityDefinition } = getEntityDefinition(instance); + + const where = Object.keys(filters) + .map(key => { + let result: string; + const filter = filters[key]; + + if (!filter) { + return; + } + + if (Array.isArray(filter)) { + if (!filter.length) { + return; + } + const inClause: string[] = filter.map( + value => + `${transformValueToDbString(value, columnsDefinition[key].type, { + columns: columnsDefinition[key].options, + secret: options.secret || "", + disableSalts: true, + })}`, + ); + + result = `${key} IN (${inClause.join(",")})`; + } else { + result = `${key} = ${transformValueToDbString(filter, columnsDefinition[key].type, { + columns: columnsDefinition[key].options, + secret: options.secret || "", + disableSalts: true, + })}`; + } + + return result; + }) + .filter(Boolean); + + secureOperators(transformValueToDbString, findOptions, entityType, options); + + const whereClause = `${[ + ...where, + ...(buildComparison(findOptions) || []), + ...(buildIn(findOptions) || []), + ...(buildLike(findOptions) || []), + ].join(" AND ")}`.trimEnd(); + + let orderByClause = ""; + if (findOptions.pagination?.reversed) { + orderByClause = `${entityDefinition.options.primaryKey + .slice(1) + .map( + (key: string) => + `${key} ${(columnsDefinition[key].options.order || "ASC") === "ASC" ? "DESC" : "ASC"}`, + ) + .join(", ")}`; + } + + const query = `SELECT * FROM ${options.keyspace}.${entityDefinition.name} ${ + whereClause.trim().length ? "WHERE " + whereClause : "" + } ${orderByClause.trim().length ? "ORDER BY " + orderByClause : ""}` + .trimEnd() + .concat(";"); + + return query; +} + +export function buildComparison(options: FindOptions = {}): string[] { + let lessClause; + let lessEqualClause; + let greaterClause; + let greaterEqualClause; + + if (options.$lt) { + lessClause = options.$lt.map(element => `${element[0]} < ${element[1]}`); + } + + if (options.$lte) { + lessEqualClause = options.$lte.map(element => `${element[0]} <= ${element[1]}`); + } + + if (options.$gt) { + greaterClause = options.$gt.map(element => `${element[0]} > ${element[1]}`); + } + + if (options.$gte) { + greaterEqualClause = options.$gte.map(element => `${element[0]} >= ${element[1]}`); + } + + return [ + ...(lessClause || []), + ...(lessEqualClause || []), + ...(greaterClause || []), + ...(greaterEqualClause || []), + ]; +} + +export function buildIn(options: FindOptions = {}): string[] { + let inClauses: string[]; + if (options.$in) { + inClauses = options.$in.map(element => `${element[0]} IN (${element[1].join(",")})`); + } + + return inClauses || []; +} + +export function buildLike(options: FindOptions = {}): string[] { + let likeClauses: string[]; + if (options.$like) { + likeClauses = options.$like.map(element => `${element[0]} LIKE '%${element[1]}%`); + } + + return likeClauses || []; +} diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/connectors/cassandra/typeTransforms.ts b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/cassandra/typeTransforms.ts new file mode 100644 index 00000000..230420c0 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/cassandra/typeTransforms.ts @@ -0,0 +1,174 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +import { isBoolean, isInteger, isNull, isUndefined } from "lodash"; +import { ColumnOptions, ColumnType } from "../../types"; +import { decrypt, encrypt } from "../../../../../../../crypto"; +import { logger } from "../../../../../../../../core/platform/framework"; + +export const cassandraType = { + encoded_string: "TEXT", + encoded_json: "TEXT", + string: "TEXT", + json: "TEXT", + number: "BIGINT", + timeuuid: "TIMEUUID", + uuid: "UUID", + counter: "COUNTER", + blob: "BLOB", + boolean: "BOOLEAN", + + // backward compatibility + twake_boolean: "TINYINT", + twake_int: "INT", //Depreciated + twake_datetime: "TIMESTAMP", //Depreciated +}; + +type TransformOptions = { + secret?: any; + disableSalts?: boolean; + columns?: ColumnOptions; + column?: any; +}; + +export const transformValueToDbString = ( + v: any, + type: ColumnType, + options: TransformOptions = {}, +): string => { + if (type === "twake_datetime") { + if (isNaN(v) || isNull(v)) { + return "null"; + } + return `${v}`; + } + + if (type === "number" || type === "twake_int") { + if (isNull(v)) { + return "null"; + } + if (isNaN(v)) { + return "null"; + } + return `${parseInt(v)}`; + } + if (type === "uuid" || type === "timeuuid") { + if (isNull(v)) { + return "null"; + } + + v = (v || "").toString().replace(/[^a-zA-Z0-9-]/g, ""); + return `${v}`; + } + if (type === "boolean") { + //Security to avoid string with "false" in it + if (!isInteger(v) && !isBoolean(v) && !isNull(v) && !isUndefined(v)) { + throw new Error(`'${v}' is not a ${type}`); + } + return `${!!v}`; + } + if (type === "twake_boolean") { + if (!isBoolean(v)) { + throw new Error(`'${v}' is not a ${type}`); + } + return v ? "1" : "0"; + } + if (type === "encoded_string" || type === "encoded_json") { + if (type === "encoded_json") { + try { + v = JSON.stringify(v); + } catch (err) { + v = null; + } + } + const encrypted = encrypt(v, options.secret, { disableSalts: options.disableSalts }); + return `'${(encrypted.data || "").toString().replace(/'/gm, "''")}'`; + } + if (type === "blob") { + return "''"; //Not implemented yet + } + if (type === "string" || type === "json") { + if (type === "json" && v !== null) { + try { + v = JSON.stringify(v); + } catch (err) { + v = null; + } + } + return `'${(v || "").toString().replace(/'/gm, "''")}'`; + } + if (type === "counter") { + if (isNaN(v)) throw new Error("Counter value should be a number"); + return `${options.column.key} + ${v}`; + } + return `'${(v || "").toString().replace(/'/gm, "''")}'`; +}; + +export const transformValueFromDbString = ( + v: any, + type: string, + options: TransformOptions = {}, +): any => { + logger.trace(`Transform value %o of type ${type}`, v); + + if (type === "twake_datetime") { + return new Date(`${v}`).getTime(); + } + + if (v !== null && (type === "encoded_string" || type === "encoded_json")) { + let decryptedValue: any; + + if (typeof v === "string" && v.trim() === "") { + return v; + } + + try { + decryptedValue = decrypt(v, options.secret).data; + } catch (err) { + logger.debug(`Can not decrypt data (${err.message}) %o of type ${type}`, v); + + decryptedValue = v; + } + + if (type === "encoded_json") { + try { + decryptedValue = JSON.parse(decryptedValue); + } catch (err) { + logger.debug( + { err }, + `Can not parse JSON from decrypted data %o of type ${type}`, + decryptedValue, + ); + decryptedValue = null; + } + } + + return decryptedValue; + } + + if (type === "twake_boolean" || type === "boolean") { + return Boolean(v).valueOf(); + } + + if (type === "json") { + try { + return JSON.parse(v); + } catch (err) { + return null; + } + } + + if (type === "uuid" || type === "timeuuid") { + return v ? String(v).valueOf() : null; + } + + if (type === "number") { + return new Number(v).valueOf(); + } + + if (type === "counter") { + return new Number(v).valueOf(); + } + + return v; +}; diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/connectors/index.ts b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/index.ts new file mode 100644 index 00000000..a0369ed0 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/index.ts @@ -0,0 +1,63 @@ +import { Initializable } from "../../../../../framework"; +import { DatabaseType } from "../.."; +import { CassandraConnectionOptions } from "./cassandra/cassandra"; +import { MongoConnectionOptions } from "./mongodb/mongodb"; +import { ColumnDefinition, EntityDefinition } from "../types"; +import { FindOptions } from "../repository/repository"; +import { ListResult } from "../../../../../framework/api/crud-service"; + +export * from "./mongodb/mongodb"; +export * from "./cassandra/cassandra"; + +export type UpsertOptions = any; + +export type RemoveOptions = any; + +export interface Connector extends Initializable { + /** + * Connect to the database + */ + connect(): Promise<this>; + + /** + * Get the type of connector + */ + getType(): DatabaseType; + + /** + * Drop data + */ + drop(): Promise<this>; + + /** + * Create table + */ + createTable( + entity: EntityDefinition, + columns: { [name: string]: ColumnDefinition }, + ): Promise<boolean>; + + /** + * Upsert + * returns true if the object was created/updated, false otherwise + */ + upsert(entities: any[]): Promise<boolean[]>; + + /** + * Remove + * returns true if the object was removed, false otherwise + */ + remove(entities: any[]): Promise<boolean[]>; + + /** + * Find items in database + * returns the list of entities matching the filters and options. + */ + find<EntityType>( + entityType: any, + filters: any, + options: FindOptions, + ): Promise<ListResult<EntityType>>; +} + +export declare type ConnectionOptions = MongoConnectionOptions | CassandraConnectionOptions; diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/connectors/mongodb/mongodb.ts b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/mongodb/mongodb.ts new file mode 100644 index 00000000..cb0a9333 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/mongodb/mongodb.ts @@ -0,0 +1,255 @@ +import * as mongo from "mongodb"; +import { UpsertOptions } from ".."; +import { ListResult, Paginable, Pagination } from "../../../../../../framework/api/crud-service"; +import { FindOptions } from "../../repository/repository"; +import { ColumnDefinition, EntityDefinition, ObjectType } from "../../types"; +import { getEntityDefinition, unwrapIndexes, unwrapPrimarykey } from "../../utils"; +import { AbstractConnector } from "../abstract-connector"; +import { buildSelectQuery } from "./query-builder"; +import { transformValueFromDbString, transformValueToDbString } from "./typeTransforms"; +import { logger } from "../../../../../../framework"; + +export { MongoPagination } from "./pagination"; + +export interface MongoConnectionOptions { + // TODO: More options + uri: string; + database: string; +} + +export class MongoConnector extends AbstractConnector<MongoConnectionOptions, mongo.MongoClient> { + private client: mongo.MongoClient; + + async init(): Promise<this> { + if (!this.client) { + await this.connect(); + } + return this; + } + + async connect(): Promise<this> { + if (this.client) { + return this; + } + + this.client = new mongo.MongoClient(this.options.uri); + await this.client.connect(); + + return this; + } + + getClient(): mongo.MongoClient { + return this.client; + } + + async getDatabase(): Promise<mongo.Db> { + await this.connect(); + + return this.client.db(this.options.database); + } + + async drop(): Promise<this> { + const db = await this.getDatabase(); + + db.dropDatabase(); + + return this; + } + + async createTable( + _entity: EntityDefinition, + _columns: { [name: string]: ColumnDefinition }, + ): Promise<boolean> { + const db = await this.getDatabase(); + const collection = db.collection(`${_entity.name}`); + + //Mongo only need to create an index if ttl defined for entity + if (_entity.options.ttl && _entity.options.ttl > 0) { + const primaryKey = unwrapPrimarykey(_entity); + const filter: any = {}; + primaryKey.forEach(key => { + filter[key] = 1; + }); + collection.createIndex(filter, { expireAfterSeconds: _entity.options.ttl }); + } + + return true; + } + async upsert(entities: any[], _options: UpsertOptions = {}): Promise<boolean[]> { + return new Promise(async resolve => { + const promises: Promise<mongo.UpdateResult>[] = []; + + const db = await this.getDatabase(); + + entities.forEach(entity => { + const { columnsDefinition, entityDefinition } = getEntityDefinition(entity); + const primaryKey = unwrapPrimarykey(entityDefinition); + + //Set updated content + const set: any = {}; + const inc: any = {}; + Object.keys(columnsDefinition) + .filter(key => primaryKey.indexOf(key) === -1) + .filter(key => columnsDefinition[key].nodename !== undefined) + .forEach(key => { + const value = transformValueToDbString( + entity[columnsDefinition[key].nodename], + columnsDefinition[key].type, + { + columns: columnsDefinition[key].options, + secret: this.secret, + column: { key }, + }, + ); + + if (columnsDefinition[key].type === "counter") { + inc[key] = value; + } else { + set[key] = value; + } + }); + + //Set primary key + const where: any = {}; + primaryKey.forEach(key => { + where[key] = transformValueToDbString( + entity[columnsDefinition[key].nodename], + columnsDefinition[key].type, + { + columns: columnsDefinition[key].options, + secret: this.secret, + disableSalts: true, + column: { key }, + }, + ); + }); + + const collection = db.collection(`${entityDefinition.name}`); + + const updateObject = { $set: { ...where, ...set } } as any; + + if (Object.keys(inc).length) { + updateObject.$inc = inc; + } + + promises.push( + collection.updateOne(where, updateObject, { + upsert: true, + }) as Promise<mongo.UpdateResult>, + ); + }); + + Promise.all(promises).then(results => { + resolve(results.map(result => result.acknowledged)); + }); + }); + } + + async remove(entities: any[]): Promise<boolean[]> { + return new Promise(async resolve => { + const promises: Promise<mongo.DeleteResult>[] = []; + const db = await this.getDatabase(); + + entities.forEach(entity => { + const { columnsDefinition, entityDefinition } = getEntityDefinition(entity); + const primaryKey = unwrapPrimarykey(entityDefinition); + + //Set primary key + const where: any = {}; + primaryKey.forEach(key => { + where[key] = transformValueToDbString( + entity[columnsDefinition[key].nodename], + columnsDefinition[key].type, + { + columns: columnsDefinition[key].options, + secret: this.secret, + disableSalts: true, + column: { key }, + }, + ); + }); + + const collection = db.collection(`${entityDefinition.name}`); + promises.push(collection.deleteOne(where)); + }); + + Promise.all(promises).then(results => { + resolve(results.map(result => result.acknowledged)); + }); + }); + } + + async find<Table>( + entityType: Table, + filters: any, + options: FindOptions = {}, + ): Promise<ListResult<Table>> { + const instance = new (entityType as any)(); + const { columnsDefinition, entityDefinition } = getEntityDefinition(instance); + + const pk = unwrapPrimarykey(entityDefinition); + + const indexes = unwrapIndexes(entityDefinition); + if ( + Object.keys(filters).some(key => pk.indexOf(key) < 0) && + Object.keys(filters).some(key => indexes.indexOf(key) < 0) + ) { + //Filter not in primary key + throw Error( + "All filter parameters must be defined in entity primary key, got: " + + JSON.stringify(Object.keys(filters)) + + " on table " + + entityDefinition.name + + " but pk is " + + JSON.stringify(pk), + ); + } + + const db = await this.getDatabase(); + const collection = db.collection(`${entityDefinition.name}`); + + const query = buildSelectQuery<Table>( + entityType as unknown as ObjectType<Table>, + filters, + options, + ); + + const sort: any = {}; + for (const key of entityDefinition.options.primaryKey.slice(1)) { + const defaultOrder = + (columnsDefinition[key as string].options.order || "ASC") === "ASC" ? 1 : -1; + sort[key as string] = (options?.pagination?.reversed ? -1 : 1) * defaultOrder; + } + + logger.debug(`services.database.orm.mongodb.find - Query: ${JSON.stringify(query)}`); + + const cursor = collection + .find(query) + .sort(sort) + .skip(Math.max(0, parseInt(options.pagination.page_token || "0"))) + .limit(Math.max(0, parseInt(options.pagination.limitStr || "100"))); + + const entities: Table[] = []; + while (await cursor.hasNext()) { + let row = await cursor.next(); + row = { ...row.set, ...row }; + const entity = new (entityType as any)(); + Object.keys(row) + .filter(key => columnsDefinition[key] !== undefined) + .forEach(key => { + entity[columnsDefinition[key].nodename] = transformValueFromDbString( + row[key], + columnsDefinition[key].type, + { columns: columnsDefinition[key].options, secret: this.secret }, + ); + }); + entities.push(entity); + } + + const nextPageToken = options.pagination.page_token || "0"; + const limit = parseInt(options.pagination.limitStr); + const nextToken = entities.length === limit && (parseInt(nextPageToken) + limit).toString(10); + const nextPage: Paginable = new Pagination(nextToken, options.pagination.limitStr || "100"); + return new ListResult<Table>(entityDefinition.type, entities, nextPage); + } +} diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/connectors/mongodb/pagination.ts b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/mongodb/pagination.ts new file mode 100644 index 00000000..ef6618a5 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/mongodb/pagination.ts @@ -0,0 +1,25 @@ +import { Paginable } from "../../../../../../framework/api/crud-service"; +import { Pagination } from "../../../../../../framework/api/crud-service"; + +export class MongoPagination extends Pagination { + limit = 100; + skip = 0; + page = 1; + + private constructor(readonly page_token = "1", readonly limitStr = "100") { + super(page_token, limitStr); + this.limit = Number.parseInt(limitStr, 10); + this.page = Number.parseInt(page_token, 10); + this.skip = (this.page - 1) * this.limit; + } + + static from(pagination: Paginable): MongoPagination { + return new MongoPagination(pagination.page_token, pagination.limitStr); + } + + static next(current: MongoPagination, items: Array<unknown> = []): Paginable { + const nextToken = items.length === current.limit && (current.page + 1).toString(10); + + return new Pagination(nextToken, current.limitStr); + } +} diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/connectors/mongodb/query-builder.ts b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/mongodb/query-builder.ts new file mode 100644 index 00000000..c99e103f --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/mongodb/query-builder.ts @@ -0,0 +1,69 @@ +import { FindOptions } from "../../repository/repository"; +import { ObjectType } from "../../types"; +import { getEntityDefinition, secureOperators } from "../../utils"; +import { transformValueToDbString } from "./typeTransforms"; + +export function buildSelectQuery<Entity>( + entityType: ObjectType<Entity>, + filters: any, + findOptions: FindOptions, + options: { + secret?: string; + keyspace: string; + } = { + secret: "", + keyspace: "twake", + }, +): any { + const instance = new (entityType as any)(); + const { columnsDefinition } = getEntityDefinition(instance); + + let where: any = {}; + Object.keys(filters).forEach((key: string) => { + if (Array.isArray(filters[key])) { + if (!filters[key] || !filters[key].length) { + return; + } + findOptions.$in = findOptions.$in || []; + findOptions.$in.push([key, filters[key]]); + } else if (columnsDefinition[key]) { + where[key] = transformValueToDbString(filters[key], columnsDefinition[key].type, { + columns: columnsDefinition[key].options, + secret: options.secret, + disableSalts: true, + }); + } else { + where[key] = filters[key]; + } + }); + + findOptions = secureOperators(transformValueToDbString, findOptions, entityType, options); + where = buildComparison(where, findOptions); + where = buildIn(where, findOptions); + + return where; +} + +export function buildComparison(where: any, options: FindOptions = {}): string[] { + Object.keys(options).forEach(operator => { + if (operator === "$gt" || operator === "$gte" || operator === "$lt" || operator === "$lte") { + (options[operator] || []).forEach(element => { + if (!where[element[0]]) where[element[0]] = {}; + where[element[0]][operator] = element[1]; + }); + } + }); + + return where; +} + +export function buildIn(where: any, options: FindOptions = {}): any { + if (options.$in) { + options.$in.forEach(element => { + if (!where[element[0]]) where[element[0]] = {}; + where[element[0]]["$in"] = element[1]; + }); + } + + return where; +} diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/connectors/mongodb/typeTransforms.ts b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/mongodb/typeTransforms.ts new file mode 100644 index 00000000..933039da --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/connectors/mongodb/typeTransforms.ts @@ -0,0 +1,106 @@ +import { ColumnOptions, ColumnType } from "../../types"; +import { decrypt, encrypt } from "../../../../../../../crypto"; +import { isNull } from "lodash"; +import { fromMongoDbOrderable, toMongoDbOrderable } from "../../utils"; + +type TransformOptions = { + secret?: any; + disableSalts?: boolean; + columns?: ColumnOptions; + column?: any; +}; + +export const transformValueToDbString = ( + v: any, + type: ColumnType, + options: TransformOptions = {}, +): any => { + if (type === "timeuuid") { + if (isNull(v) || !v) { + return null; + } + //Convert to orderable number on mongodb + return toMongoDbOrderable(v); + } + + if (type === "uuid") { + return `${v}`; + } + + if (type === "encoded_string" || type === "encoded_json") { + if (type === "encoded_json") { + try { + v = JSON.stringify(v); + } catch (err) { + v = null; + } + } + if (v !== undefined) { + v = encrypt(v, options.secret, { disableSalts: options.disableSalts }).data; + } + return v; + } + if (type === "blob") { + return ""; //Not implemented yet + } + if (type === "string" || type === "json") { + if (type === "json") { + try { + v = JSON.stringify(v); + } catch (err) { + v = null; + } + } + return v; + } + + if (type === "twake_boolean") { + return Boolean(v); + } + + if (type === "counter") { + if (isNaN(v)) throw new Error("Counter value should be a number"); + return +v; + } + + return v || ""; +}; + +export const transformValueFromDbString = (v: any, type: string, options: any = {}): any => { + if (type === "timeuuid") { + return fromMongoDbOrderable(v); + } + if (v !== null && (type === "encoded_string" || type === "encoded_json")) { + try { + v = decrypt(v, options.secret).data; + } catch (err) { + v = v; + } + if (type === "encoded_json") { + try { + return JSON.parse(v); + } catch (err) { + return null; + } + } + } + if (type === "json") { + try { + return JSON.parse(v); + } catch (err) { + return null; + } + } + if (type === "twake_boolean" || type === "boolean") { + return Boolean(v).valueOf(); + } + if (type === "number") { + return Number(v).valueOf(); + } + + if (type === "counter") { + return new Number(v).valueOf(); + } + + return v; +}; diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/decorators/column.ts b/twake/backend/node/src/core/platform/services/database/services/orm/decorators/column.ts new file mode 100644 index 00000000..82751bf8 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/decorators/column.ts @@ -0,0 +1,19 @@ +import { ColumnDefinition, ColumnType } from "../types"; + +export function Column( + name: string, + type: ColumnType, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + options: ColumnDefinition["options"] = { order: "ASC" }, +): PropertyDecorator { + // eslint-disable-next-line @typescript-eslint/ban-types + return function (target: Object, key: string | symbol) { + target.constructor.prototype._columns = target.constructor.prototype._columns || {}; + const colDefinition: ColumnDefinition = { + type: type, + options: options, + nodename: key.toString(), + }; + target.constructor.prototype._columns[name] = colDefinition; + }; +} diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/decorators/entity.ts b/twake/backend/node/src/core/platform/services/database/services/orm/decorators/entity.ts new file mode 100644 index 00000000..088146c1 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/decorators/entity.ts @@ -0,0 +1,28 @@ +/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types */ +import { EntityDefinition } from "../types"; + +type EntityOption = { + type?: string; + ttl?: number; + primaryKey: (string | string[])[]; + globalIndexes?: string[][]; + search?: { + source: (entity: any) => any; //Should return an object that will be indexed + shouldUpdate?: (entity: any) => any; //Should return an object that will be indexed + index?: string; //Index name + esMapping?: any; //Used for elasticsearch mappings + mongoMapping?: any; //Used for elasticsearch mappings + }; +}; + +export function Entity(name: string, options: EntityOption): ClassDecorator { + // eslint-disable-next-line @typescript-eslint/ban-types + return function (constructor: Function): void { + const entityDefinition: EntityDefinition = { + name, + type: options.type || name, + options, + }; + constructor.prototype._entity = entityDefinition; + }; +} diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/decorators/index.ts b/twake/backend/node/src/core/platform/services/database/services/orm/decorators/index.ts new file mode 100644 index 00000000..7ad3b652 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/decorators/index.ts @@ -0,0 +1,2 @@ +export * from "./column"; +export * from "./entity"; diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/manager.ts b/twake/backend/node/src/core/platform/services/database/services/orm/manager.ts new file mode 100644 index 00000000..42a5a40a --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/manager.ts @@ -0,0 +1,102 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +import _ from "lodash"; +import { Connector } from "./connectors"; +import { getEntityDefinition, unwrapPrimarykey } from "./utils"; +import { v4 as uuidv4, v1 as uuidv1 } from "uuid"; +import { logger } from "../../../../framework"; +import { DatabaseEntitiesRemovedEvent, DatabaseEntitiesSavedEvent } from "./types"; +import { localEventBus } from "../../../../framework/event-bus"; + +export default class EntityManager<EntityType extends Record<string, any>> { + private toPersist: EntityType[] = []; + private toRemove: EntityType[] = []; + + constructor(readonly connector: Connector) {} + + public persist(entity: any): this { + if (!entity.constructor.prototype._entity || !entity.constructor.prototype._columns) { + logger.error("Can not persist this object %o", entity); + throw Error("Cannot persist this object: it is not an entity."); + } + + // --- Generate ids on primary keys elements (if not defined) --- + const { columnsDefinition, entityDefinition } = getEntityDefinition(entity); + const primaryKey: string[] = unwrapPrimarykey(entityDefinition); + + primaryKey.forEach(pk => { + if (entity[pk] === undefined) { + const definition = columnsDefinition[pk]; + + if (!definition) { + throw Error(`There is no definition for primary key ${pk}`); + } + + //Create default value + switch (definition.options.generator || definition.type) { + case "uuid": + entity[pk] = uuidv4(); + break; + case "timeuuid": + entity[pk] = uuidv1(); + break; + case "number": + entity[pk] = 0; + break; + default: + entity[pk] = ""; + } + } + }); + + //Apply the onUpsert + for (const column in columnsDefinition) { + const definition = columnsDefinition[column]; + if (definition.options.onUpsert) { + entity[definition.nodename] = definition.options.onUpsert(entity[definition.nodename]); + } + } + + this.toPersist = this.toPersist.filter(e => e !== entity); + this.toPersist.push(_.cloneDeep(entity)); + + return this; + } + + public remove(entity: EntityType, entityType?: EntityType): this { + if (entityType) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + entity = _.merge(new (entityType as any)(), entity); + } + if (!entity.constructor.prototype._entity || !entity.constructor.prototype._columns) { + throw Error("Cannot remove this object: it is not an entity."); + } + this.toRemove = this.toRemove.filter(e => e !== entity); + this.toRemove.push(_.cloneDeep(entity)); + + return this; + } + + public async flush(): Promise<this> { + this.toPersist = _.uniqWith(this.toPersist, _.isEqual); + this.toRemove = _.uniqWith(this.toRemove, _.isEqual); + + localEventBus.publish("database:entities:saved", { + entities: this.toPersist.map(e => _.cloneDeep(e)), + } as DatabaseEntitiesSavedEvent); + + localEventBus.publish("database:entities:saved", { + entities: this.toRemove.map(e => _.cloneDeep(e)), + } as DatabaseEntitiesRemovedEvent); + + await this.connector.upsert(this.toPersist); + await this.connector.remove(this.toRemove); + + return this; + } + + public reset(): void { + this.toPersist = []; + this.toRemove = []; + } +} diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/repository/manager.ts b/twake/backend/node/src/core/platform/services/database/services/orm/repository/manager.ts new file mode 100644 index 00000000..d5ccde57 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/repository/manager.ts @@ -0,0 +1,31 @@ +import { logger } from "../../../../../../../core/platform/framework"; +import DatabaseService from "../.."; +import Repository from "./repository"; +import { EntityTarget } from "../types"; + +export class RepositoryManager { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private repositories: Map<string, Repository<any>> = new Map<string, Repository<any>>(); + + constructor(private databaseService: DatabaseService) {} + + async getRepository<Entity>( + table: string, + entity: EntityTarget<Entity>, + ): Promise<Repository<Entity>> { + if (!this.repositories.has(table)) { + const repository = new Repository<Entity>(this.databaseService.getConnector(), table, entity); + + try { + await repository.init(); + } catch (err) { + logger.error({ err }, "Error while initializing repository"); + throw new Error("Can not initialize repository"); + } + + this.repositories.set(table, repository); + } + + return this.repositories.get(table); + } +} diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/repository/repository.ts b/twake/backend/node/src/core/platform/services/database/services/orm/repository/repository.ts new file mode 100644 index 00000000..51b9cd96 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/repository/repository.ts @@ -0,0 +1,118 @@ +import { assign } from "lodash"; +import { logger } from "../../../../../../../core/platform/framework"; +import { + ExecutionContext, + ListResult, + Pagination, +} from "../../../../../framework/api/crud-service"; +import { Connector } from "../connectors"; +import Manager from "../manager"; +import { EntityTarget } from "../types"; +import { getEntityDefinition } from "../utils"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type FindFilter = { [key: string]: any }; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type RemoveFilter = { [key: string]: any }; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type comparisonType = [string, any]; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type inType = [string, Array<any>]; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type likeType = [string, any]; + +export type FindOptions = { + pagination?: Pagination; + $lt?: comparisonType[]; + $lte?: comparisonType[]; + $gt?: comparisonType[]; + $gte?: comparisonType[]; + /** + * The $in operator selects the documents where the value of a field equals any value in the specified array + */ + $in?: inType[]; + $like?: likeType[]; +}; + +/** + * Repository to work with entities. Each entity type has its own repository instance. + */ +export default class Repository<EntityType> { + manager: Manager<EntityType>; + + constructor( + readonly connector: Connector, + readonly table: string, + readonly entityType: EntityTarget<EntityType>, + ) { + this.manager = new Manager<EntityType>(this.connector); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + checkEntityDefinition(): boolean { + //TODO, check entity definition make sense from this.entityType + return true; + } + + async init(): Promise<this> { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const instance = new (this.entityType as any)() as EntityType; + + if (this.checkEntityDefinition()) { + const { columnsDefinition, entityDefinition } = getEntityDefinition(instance); + await this.connector.createTable(entityDefinition, columnsDefinition); + } + + return this; + } + + async find( + filters: FindFilter, + options: FindOptions = {}, + _context?: ExecutionContext, + ): Promise<ListResult<EntityType>> { + if (!this.entityType) { + throw Error(`Unable to find or findOne: EntityType ${this.table} not initialized`); + } + + if (!options.pagination) { + options.pagination = new Pagination("", "100"); + } + + return await this.connector.find(this.entityType, filters, options); + } + + async findOne( + filters: FindFilter, + options: FindOptions = {}, + context?: ExecutionContext, + ): Promise<EntityType> { + if (!options.pagination) { + options.pagination = new Pagination("", "1"); + } + + return (await this.find(filters, options, context)).getEntities()[0] || null; + } + + async save(entity: EntityType, _context?: ExecutionContext): Promise<void> { + (await this.manager.persist(entity).flush()).reset(); + } + + async saveAll(entities: EntityType[] = [], _context?: ExecutionContext): Promise<void> { + logger.debug("services.database.repository - Saving entities"); + + entities.forEach(entity => this.manager.persist(entity)); + await (await this.manager.flush()).reset(); + } + + async remove(entity: EntityType, _context?: ExecutionContext): Promise<void> { + await (await this.manager.remove(entity).flush()).reset(); + } + + //Avoid using this except when no choice + createEntityFromObject(object: any): EntityType { + const entity = new (this.entityType as any)() as EntityType; + return assign(entity, object); + } +} diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/types.ts b/twake/backend/node/src/core/platform/services/database/services/orm/types.ts new file mode 100644 index 00000000..6888dd8e --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/types.ts @@ -0,0 +1,59 @@ +export type EntityDefinition = { + name: string; + type: string; + options: { + primaryKey: (string | string[])[]; + globalIndexes?: string[][]; + ttl?: number; + search?: { + source: <Entity>(entity: Entity) => any; //Should return an object that will be indexed + shouldUpdate?: (entity: any) => any; //Should return an object that will be indexed + index?: string; //Index name + esMapping?: any; //Used for elasticsearch / mongodb mappings + mongoMapping?: any; //Used for elasticsearch / mongodb mappings + }; + }; +}; + +export type ColumnDefinition = { + type: ColumnType; + nodename: string; + options: ColumnOptions; +}; + +export type ColumnOptions = { + order?: "ASC" | "DESC"; + generator?: ColumnType; + onUpsert?: (value: any) => any; +}; + +export type ColumnType = + | "encoded_string" + | "encoded_json" + | "string" + | "json" + | "number" + | "timeuuid" + | "uuid" + | "counter" + | "blob" + | "boolean" + // backward compatibility + | "twake_boolean" + | "twake_int" + | "twake_datetime"; + +export type EntityTarget<Entity> = ObjectType<Entity>; + +// eslint-disable-next-line @typescript-eslint/ban-types +export type ObjectType<T> = { new (): T } | Function; + +/** Local Event bus */ + +export type DatabaseEntitiesSavedEvent = { + entities: any[]; +}; + +export type DatabaseEntitiesRemovedEvent = { + entities: any[]; +}; diff --git a/twake/backend/node/src/core/platform/services/database/services/orm/utils.ts b/twake/backend/node/src/core/platform/services/database/services/orm/utils.ts new file mode 100644 index 00000000..bf4db2ae --- /dev/null +++ b/twake/backend/node/src/core/platform/services/database/services/orm/utils.ts @@ -0,0 +1,108 @@ +import _, { flatten } from "lodash"; +import { FindOptions } from "./repository/repository"; +import { ColumnDefinition, EntityDefinition, ObjectType } from "./types"; + +export function getEntityDefinition(instance: any): { + entityDefinition: EntityDefinition; + columnsDefinition: { [name: string]: ColumnDefinition }; +} { + const entityConfituration = _.cloneDeep(instance.constructor.prototype._entity); + const entityColumns = _.cloneDeep(instance.constructor.prototype._columns); + return { + entityDefinition: entityConfituration, + columnsDefinition: entityColumns, + }; +} + +export function unwrapPrimarykey(entityDefinition: EntityDefinition): string[] { + const initial = [...entityDefinition.options.primaryKey]; + const partitionKey = initial.shift(); + const primaryKey: string[] = [ + ...(typeof partitionKey === "string" ? [partitionKey] : partitionKey), + ...(initial as string[]), + ]; + return primaryKey; +} + +export function unwrapIndexes(entityDefinition: EntityDefinition): string[] { + const indexes = entityDefinition.options.globalIndexes; + if (!indexes) return []; + + return flatten(entityDefinition.options.globalIndexes); +} + +export function secureOperators<Entity>( + // eslint-disable-next-line @typescript-eslint/ban-types + transformValueToDbString: Function, + findOptions: FindOptions = {}, + entityType: ObjectType<Entity>, + options: { + secret?: string; + keyspace: string; + } = { + secret: "", + keyspace: "twake", + }, +): FindOptions { + const instance = new (entityType as any)(); + const { columnsDefinition } = getEntityDefinition(instance); + + Object.keys(findOptions).forEach(key => { + if ( + key == "$in" || + key == "$lte" || + key == "$lt" || + key == "$gte" || + key == "$gt" || + key == "$like" + ) { + findOptions[key].forEach(element => { + if (columnsDefinition[element[0]]) { + if (_.isArray(element[1])) { + element[1] = element[1].map((e: any) => + transformValueToDbString(e, columnsDefinition[element[0]].type, { + columns: columnsDefinition[element[0]].options, + secret: options.secret || "", + }), + ); + } else { + element[1] = transformValueToDbString(element[1], columnsDefinition[element[0]].type, { + columns: columnsDefinition[element[0]].options, + secret: options.secret || "", + }); + } + } + }); + } + }); + + return findOptions; +} + +/** + * Build uuid from nanotime + * @param orderable + * @returns + */ +export function fromMongoDbOrderable(orderable: string): string { + if (!orderable) { + return null; + } + const uuid_arr = orderable.split("-"); + const timeuuid = [uuid_arr[2], uuid_arr[1], uuid_arr[0], uuid_arr[3], uuid_arr[4]].join("-"); + return timeuuid; +} + +/** + * Returns orderable string + * @param timeuuid + * @returns + */ +export function toMongoDbOrderable(timeuuid?: string): string { + if (!timeuuid) { + return null; + } + const uuid_arr = timeuuid.split("-"); + const time_str = [uuid_arr[2], uuid_arr[1], uuid_arr[0], uuid_arr[3], uuid_arr[4]].join("-"); + return time_str; +} diff --git a/twake/backend/node/src/core/platform/services/email-pusher/index.ts b/twake/backend/node/src/core/platform/services/email-pusher/index.ts new file mode 100644 index 00000000..d47a594d --- /dev/null +++ b/twake/backend/node/src/core/platform/services/email-pusher/index.ts @@ -0,0 +1,131 @@ +import { getLogger, TwakeLogger, TwakeService } from "../../framework"; +import EmailPusherAPI from "./provider"; +import { + EmailBuilderDataPayload, + EmailBuilderRenderedResult, + EmailBuilderTemplateName, + EmailPusherEmailType, + EmailPusherPayload, + EmailPusherResponseType, +} from "./types"; +import * as Eta from "eta"; +import { convert } from "html-to-text"; +import path from "path"; +import { existsSync } from "fs"; +import axios from "axios"; + +export default class EmailPusherClass + extends TwakeService<EmailPusherAPI> + implements EmailPusherAPI +{ + readonly name = "email-pusher"; + readonly version: "1.0.0"; + logger: TwakeLogger = getLogger("email-pusher-service"); + apiKey: string; + apiUrl: string; + sender: string; + + api(): EmailPusherAPI { + return this; + } + + async doInit(): Promise<this> { + Eta.configure({ + views: path.join(__dirname, "templates"), + }); + + this.apiUrl = this.configuration.get<string>("endpoint", ""); + this.apiKey = this.configuration.get<string>("api_key", ""); + this.sender = this.configuration.get<string>("sender", ""); + + return this; + } + + /** + * Generate a rendered HTML and text email + * + * @param {EmailBuilderTemplateName} template - the Eta template name + * @param {String} language - the template language + * @param {EmailBuilderDataPayload} data - the data + * @returns {EmailBuilderRenderedResult} - the rendered html and text version + */ + async build( + template: EmailBuilderTemplateName, + language: string, + data: EmailBuilderDataPayload, + ): Promise<EmailBuilderRenderedResult> { + try { + language = ["en", "fr"].find(l => language.toLocaleLowerCase().includes(l)) || "en"; + const templatePath = path.join(__dirname, "templates", language, `${template}.eta`); + const subjectPath = path.join(__dirname, "templates", language, `${template}.subject.eta`); + + if (!existsSync(templatePath)) { + throw Error(`template not found: ${templatePath}`); + } + + if (!existsSync(subjectPath)) { + throw Error(`subject template not found: ${subjectPath}`); + } + + const html = await Eta.renderFile(templatePath, data); + + if (!html || !html.length) { + throw Error("Failed to render template"); + } + + const text = convert(html); + + const subject = convert((await Eta.renderFile(subjectPath, data)) as string); + + return { html, text, subject }; + } catch (error) { + this.logger.error(`Failure when building email template: ${error}`); + } + } + + /** + * Send email + * + * @param {string} to - the recipient + * @param {EmailPusherPayload} email - the email object + * @returns {Promise<void>} + */ + async send( + to: string, + { subject, html: html_body, text: text_body }: EmailPusherPayload, + ): Promise<void> { + try { + if (!html_body || !text_body || !subject || !to) { + throw Error("invalid email"); + } + + const emailObject = { + api_key: this.apiKey, + to: [to], + subject, + text_body, + html_body, + sender: this.sender, + }; + + const { data } = await axios.post<EmailPusherEmailType, EmailPusherResponseType>( + `${this.apiUrl}`, + emailObject, + ); + + if (data.error && data.error.length) { + throw Error(data.error); + } + + if (data.failed === 1 && data.failures.length) { + throw Error(data.failures.join("")); + } + + if (data.succeeded) { + this.logger.info("email sent"); + } + } catch (error) { + this.logger.error("Failed to send email", error); + } + } +} diff --git a/twake/backend/node/src/core/platform/services/email-pusher/provider.ts b/twake/backend/node/src/core/platform/services/email-pusher/provider.ts new file mode 100644 index 00000000..fc6c5817 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/email-pusher/provider.ts @@ -0,0 +1,17 @@ +import { TwakeServiceProvider } from "../../framework"; +import { + EmailBuilderDataPayload, + EmailBuilderRenderedResult, + EmailBuilderTemplateName, + EmailPusherPayload, +} from "./types"; + +export default interface EmailPusherAPI extends TwakeServiceProvider { + build( + template: EmailBuilderTemplateName, + language: string, + data: EmailBuilderDataPayload, + ): Promise<EmailBuilderRenderedResult>; + + send(to: string, email: EmailPusherPayload): Promise<void>; +} diff --git a/twake/backend/node/src/core/platform/services/email-pusher/templates/common/_body.eta b/twake/backend/node/src/core/platform/services/email-pusher/templates/common/_body.eta new file mode 100644 index 00000000..e36e300a --- /dev/null +++ b/twake/backend/node/src/core/platform/services/email-pusher/templates/common/_body.eta @@ -0,0 +1,58 @@ +<!--[if mso | + IE]> +<table role="presentation" border="0" cellpadding="0" + cellspacing="0"> + <% it.paragraphs.forEach(function(paragraph){ %> + <tr> + <td class="" width="600px" > + <table + align="center" border="0" cellpadding="0" cellspacing="0" + class="" role="presentation" style="width:600px;" width="600" + > + <tr> + <td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"> + <![endif]--> + <div style="margin:0px auto;max-width:600px;"> + <table + align="center" border="0" cellpadding="0" cellspacing="0" + role="presentation" style="width:100%;" + > + <tbody> + <tr> + <td + style="direction:ltr;font-size:0px;padding:0;text-align:center;" + > + <!--[if mso | IE]> + <table + role="presentation" border="0" cellpadding="0" + cellspacing="0"> + <tr> + <td class="section-wrapper-outlook" + style="vertical-align:top;width:600px;" > + <![endif]--> + <div + class="mj-column-per-100 mj-outlook-group-fix + section-wrapper" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;" + > + <%~ paragraph %> + </div> + <!--[if mso | IE]> + </td> + </tr> + </table> + <! + [endif]--> + </td> + </tr> + </tbody> + </table> + </div> + <!--[if mso | IE]> + </td> + </tr> + </table> + </td> + </tr> + <% }) %> +</table> +<![endif]--> diff --git a/twake/backend/node/src/core/platform/services/email-pusher/templates/common/_structure.eta b/twake/backend/node/src/core/platform/services/email-pusher/templates/common/_structure.eta new file mode 100644 index 00000000..e04df4ff --- /dev/null +++ b/twake/backend/node/src/core/platform/services/email-pusher/templates/common/_structure.eta @@ -0,0 +1,929 @@ +<!doctype html> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft- + com:office:office"> + <head> + <title><%~ it.title %> + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + + + +
+ headerImage +
+
+
+ +
+
+ +
+ + + + + + +
+ <%~ it.body %> +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+
<%~ it.follow_us %>
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ +
+ + + + + + +
+ + + + + + +
+ + instagramIcon + +
+
+
+ +
+ + + + + + +
+ + + + + + +
+ + facebookIcon + +
+
+
+ +
+ + + + + + +
+ + + + + + +
+ + twitterIcon + +
+
+
+ +
+ + + + + + +
+ + + + + + +
+ + youtubeIcon + +
+
+
+ +
+ + + + + + +
+ + + + + + +
+ + githubIcon + +
+
+
+ +
+ +
+
+ +
+ + + + + + +
+ +
+ +
+ + + + + + +
+
Tel + : +33 1 46 96 63 63 β€’ info@linagora.com +
+
+
+ +
+ +
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+
<%~ it.sent_by %> +
+
+
+ +
+
+ +
+ + + + + + +
+ +
+ +
+ + + + + + +
+ +
+
+ +
+ + + + + + +
+ +
+
+ +
+ + + + + + +
+ +
+
+ +
+ +
+
+ +
+
+ +
+ + \ No newline at end of file diff --git a/twake/backend/node/src/core/platform/services/email-pusher/templates/common/_title.eta b/twake/backend/node/src/core/platform/services/email-pusher/templates/common/_title.eta new file mode 100644 index 00000000..d1797518 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/email-pusher/templates/common/_title.eta @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + +
+
You have been invited
+
+
Hi romaric.mollard@gmail + .com, +
+
+
romaric.mollard@gmail.com has invited you to use Twake + on + Crayon Company. +
+
+
Since you already have an account, please sign in and switch your + application as shown here. +
+
\ No newline at end of file diff --git a/twake/backend/node/src/core/platform/services/email-pusher/templates/en/_structure.eta b/twake/backend/node/src/core/platform/services/email-pusher/templates/en/_structure.eta new file mode 100644 index 00000000..0695e651 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/email-pusher/templates/en/_structure.eta @@ -0,0 +1,12 @@ +<%~ includeFile("../common/_structure.eta", Object.assign(it, { + follow_us: "Follow us on social media", + sent_by: "Sent by LINAGORA | 100 Terrasse Boieldieu Tour Franklin 92042 Paris La DΓ©fense", + help: "Help center", + privacy: "Privacy Policy", + terms: "Terms of Service", + links: { + help: "https://twake.app/", + privacy: "https://twake.app/en/privacy-policy/", + terms: "https://twake.app/en/terms-of-service/" + } +})) %> \ No newline at end of file diff --git a/twake/backend/node/src/core/platform/services/email-pusher/templates/en/notification-digest.eta b/twake/backend/node/src/core/platform/services/email-pusher/templates/en/notification-digest.eta new file mode 100644 index 00000000..db7f25d9 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/email-pusher/templates/en/notification-digest.eta @@ -0,0 +1,43 @@ +<% layout('./_structure') %> +<% it.title = 'Missed notifications from company ' + it.company.name %> + +<%~ includeFile("../common/_body.eta", { + paragraphs: [ + ` + + + + + + +
+
+ While you were away +
+
+ `, + ` + + + + + + +
+
+ You have received new messages! πŸ˜‰ +
+
+ `, + ...it.notifications.map(notification => + includeFile("./notification-digest/notification.eta", notification) + ), + ` + + ` + ] +}) %> \ No newline at end of file diff --git a/twake/backend/node/src/core/platform/services/email-pusher/templates/en/notification-digest.subject.eta b/twake/backend/node/src/core/platform/services/email-pusher/templates/en/notification-digest.subject.eta new file mode 100644 index 00000000..098a3d20 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/email-pusher/templates/en/notification-digest.subject.eta @@ -0,0 +1 @@ +Missed notifications in your company <%= it.company.name %> diff --git a/twake/backend/node/src/core/platform/services/email-pusher/templates/en/notification-digest/notification.eta b/twake/backend/node/src/core/platform/services/email-pusher/templates/en/notification-digest/notification.eta new file mode 100644 index 00000000..bee47338 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/email-pusher/templates/en/notification-digest/notification.eta @@ -0,0 +1,20 @@ +
+
+ <%= it.message.user.first_name %> +
+
+
+
+ <%= [it.message.user.first_name, it.message.user.last_name].join(" ") || it.message.user.username %> +
+
+ <%= it.message.text %> +
+
+
+ <%= it.workspace?.name || "Direct chat" %><%= it.workspace?.name ? (" β€’ " + it.channel.name) : "" %> + <%= (new Date(it.message.created_at)).toLocaleDateString("en-US") %> +
+
+
+
\ No newline at end of file diff --git a/twake/backend/node/src/core/platform/services/email-pusher/templates/fr/_structure.eta b/twake/backend/node/src/core/platform/services/email-pusher/templates/fr/_structure.eta new file mode 100644 index 00000000..d0fa48b4 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/email-pusher/templates/fr/_structure.eta @@ -0,0 +1,12 @@ +<%~ includeFile("../common/_structure.eta", Object.assign(it, { + follow_us: "Retrouvez nous sur les rΓ©seaux", + sent_by: "EnvoyΓ© par LINAGORA | 100 Terrasse Boieldieu Tour Franklin 92042 Paris La DΓ©fense", + help: "Centre d'aide", + privacy: "ConfidentialitΓ©", + terms: "CGU", + links: { + help: "https://twake.app/", + privacy: "https://twake.app/fr/privacy-policy/", + terms: "https://twake.app/fr/terms-of-service/" + } +})) %> \ No newline at end of file diff --git a/twake/backend/node/src/core/platform/services/email-pusher/templates/fr/notification-digest.eta b/twake/backend/node/src/core/platform/services/email-pusher/templates/fr/notification-digest.eta new file mode 100644 index 00000000..00c4aea7 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/email-pusher/templates/fr/notification-digest.eta @@ -0,0 +1,45 @@ +<% layout('./_structure') %> +<% it.title = 'Notifications manquΓ©es de l\'entreprise ' + it.company.name %> + + +<%~ includeFile("../common/_body.eta", { + paragraphs: [ + ` + + + + + + +
+
+ Pendant votre absense +
+
+ `, + ` + + + + + + +
+
+ Vous avez reΓ§u de nouveaux messages! πŸ˜‰ +
+
+ `, + ...it.notifications.map(notification => + includeFile("./notification-digest/notification.eta", notification) + ) + , + ` + + ` + ] +}) %> \ No newline at end of file diff --git a/twake/backend/node/src/core/platform/services/email-pusher/templates/fr/notification-digest.subject.eta b/twake/backend/node/src/core/platform/services/email-pusher/templates/fr/notification-digest.subject.eta new file mode 100644 index 00000000..a402f827 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/email-pusher/templates/fr/notification-digest.subject.eta @@ -0,0 +1 @@ +Notifications manquΓ©es dans votre entreprise <%= it.company.name %> diff --git a/twake/backend/node/src/core/platform/services/email-pusher/templates/fr/notification-digest/notification.eta b/twake/backend/node/src/core/platform/services/email-pusher/templates/fr/notification-digest/notification.eta new file mode 100644 index 00000000..bee47338 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/email-pusher/templates/fr/notification-digest/notification.eta @@ -0,0 +1,20 @@ +
+
+ <%= it.message.user.first_name %> +
+
+
+
+ <%= [it.message.user.first_name, it.message.user.last_name].join(" ") || it.message.user.username %> +
+
+ <%= it.message.text %> +
+
+
+ <%= it.workspace?.name || "Direct chat" %><%= it.workspace?.name ? (" β€’ " + it.channel.name) : "" %> + <%= (new Date(it.message.created_at)).toLocaleDateString("en-US") %> +
+
+
+
\ No newline at end of file diff --git a/twake/backend/node/src/core/platform/services/email-pusher/types.ts b/twake/backend/node/src/core/platform/services/email-pusher/types.ts new file mode 100644 index 00000000..16765ac1 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/email-pusher/types.ts @@ -0,0 +1,50 @@ +import { Channel } from "../../../../services/channels/entities/channel"; +import { Message } from "../../../../services/messages/entities/messages"; +import Company from "../../../../services/user/entities/company"; +import Workspace from "../../../../services/workspaces/entities/workspace"; +import User from "../../../../services/user/entities/user"; +import { UserObject } from "../../../../services/user/web/types"; + +export type EmailBuilderDataPayload = { + user: User; + company: Company; + notifications: { + channel: Channel; + workspace: Workspace; + message: Message & { user: UserObject }; + }[]; +}; + +export type EmailBuilderRenderedResult = { + html: string; + text: string; + subject: string; +}; + +export type EmailBuilderTemplateName = "notification-digest"; + +export type EmailPusherPayload = { + subject: string; + html: string; + text: string; +}; + +export type EmailPusherEmailType = { + sender: string; + html_body: string; + text_body: string; + to: string[]; + subject: string; +}; + +export type EmailPusherResponseType = { + data: { + succeeded: number; + failed: number; + failures: string[]; + error?: string; + error_code?: string; + }; +}; + +export type EmailLanguageType = "en" | "fr"; diff --git a/twake/backend/node/src/core/platform/services/knowledge-graph/api-client.ts b/twake/backend/node/src/core/platform/services/knowledge-graph/api-client.ts new file mode 100644 index 00000000..4da68de8 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/knowledge-graph/api-client.ts @@ -0,0 +1,187 @@ +import axios, { AxiosInstance } from "axios"; + +import { KnowledgeGraphCreateBodyRequest, KnowledgeGraphCreateMessageObjectData } from "./types"; + +import { md5 } from "../../../../core/crypto"; +import { Channel } from "../../../../services/channels/entities"; +import gr from "../../../../services/global-resolver"; +import { Message } from "../../../../services/messages/entities/messages"; +import Company from "../../../../services/user/entities/company"; +import User from "../../../../services/user/entities/user"; +import Workspace from "../../../../services/workspaces/entities/workspace"; +import { getLogger, TwakeLogger } from "../../framework"; + +export default class KnowledgeGraphAPIClient { + protected readonly version = "1.0.0"; + protected readonly axiosInstance: AxiosInstance = axios.create(); + readonly apiUrl: string; + readonly logger: TwakeLogger = getLogger("knowledge-graph-api-client"); + + constructor(apiUrl: string) { + this.apiUrl = apiUrl; + } + + private async getUserKGId(id: string, provider_id?: string) { + provider_id = provider_id || (await gr.services.users.get({ id }))?.identity_provider_id; + return provider_id; + } + + private async getUserKGMailId(id: string, email?: string) { + email = email || (await gr.services.users.get({ id }))?.email_canonical; + return md5(email.trim().toLocaleLowerCase()); + } + + private async getCompanyKGId(id: string, identity_provider_id?: string) { + identity_provider_id = + identity_provider_id || + (await gr.services.companies.getCompany({ id }))?.identity_provider_id || + id; + return identity_provider_id; + } + + public async onCompanyCreated(company: Partial): Promise { + this.send({ + records: [ + { + key: "null", + value: { + id: "Company", + properties: { + _kg_company_id: await this.getCompanyKGId(company.id, company.identity_provider_id), + company_id: company.id, + company_name: company.displayName || company.name, + }, + }, + }, + ], + }); + } + + public async onWorkspaceCreated(workspace: Partial): Promise { + const response = await this.send({ + records: [ + { + key: "null", + value: { + id: "Workspace", + properties: { + _kg_company_id: await this.getCompanyKGId(workspace.company_id), + company_id: workspace.company_id, + workspace_name: workspace.name, + workspace_id: workspace.id, + }, + }, + }, + ], + }); + + if (response.statusText === "OK") { + this.logger.info("onWorkspaceCreated %o", response.config.data); + } + } + + public async onUserCreated(companyId: string, user: Partial): Promise { + const response = await this.send({ + records: [ + { + key: "null", + value: { + id: "User", + properties: { + _kg_user_id: await this.getUserKGId(user.id, user.identity_provider_id), + _kg_email_id: await this.getUserKGMailId(user.id, user.email_canonical), + _kg_company_all_id: await Promise.all( + user.cache.companies.map(async c => await this.getCompanyKGId(c)), + ), + user_id: user.id, + email: user.email_canonical, + username: user.username_canonical, + user_last_activity: user.last_activity, + first_name: user.first_name, + user_created_at: user.creation_date, + last_name: user.last_name, + company_id: companyId, + }, + }, + }, + ], + }); + + if (response.statusText === "OK") { + this.logger.info("onUserCreated %o", response.config.data); + } + } + + public async onChannelCreated(channel: Partial): Promise { + const response = await this.send({ + records: [ + { + key: "null", + value: { + id: "Channel", + properties: { + _kg_user_id: await this.getUserKGId(channel.owner), + _kg_email_id: await this.getUserKGMailId(channel.owner), + _kg_company_id: await this.getCompanyKGId(channel.company_id), + channel_id: channel.id, + channel_name: channel.name, + channel_owner: channel.owner, + workspace_id: channel.workspace_id, + company_id: channel.company_id, + }, + }, + }, + ], + }); + + if (response.statusText === "OK") { + this.logger.info("onChannelCreated %o", response.config.data); + } + } + + public async onMessageUpsert( + channelId: string, + message: Partial, + sensitiveData: boolean, + ): Promise { + const response = await this.send({ + records: [ + { + key: "null", + value: { + id: "Message", + properties: { + _kg_user_id: await this.getUserKGId(message.user_id), + _kg_email_id: await this.getUserKGMailId(message.user_id), + _kg_company_id: await this.getCompanyKGId(message.cache?.company_id), + message_thread_id: message.thread_id, + message_content: sensitiveData ? message.text : "", + type_message: message.type, + message_created_at: message.created_at, + message_updated_at: message.updated_at, + user_id: message.user_id, + channel_id: message.cache?.channel_id || channelId, + workspace_id: message.cache?.workspace_id, + company_id: message.cache?.company_id, + }, + }, + }, + ], + }); + + if (response.statusText === "OK") { + this.logger.info("onMessageUpsert %o", response.config.data); + } + } + + private async send(data: any) { + return await this.axiosInstance.post< + KnowledgeGraphCreateBodyRequest + >(`${this.apiUrl}/topics/twake`, data, { + headers: { + "Content-Type": "application/vnd.kafka.json.v2+json", + Accept: "application/vnd.kafka.v2+json", + }, + }); + } +} diff --git a/twake/backend/node/src/core/platform/services/knowledge-graph/index.ts b/twake/backend/node/src/core/platform/services/knowledge-graph/index.ts new file mode 100644 index 00000000..4e4af125 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/knowledge-graph/index.ts @@ -0,0 +1,167 @@ +import { Configuration, Consumes, getLogger, TwakeLogger, TwakeService } from "../../framework"; +import { localEventBus } from "../../framework/event-bus"; +import KnowledgeGraphAPI from "./provider"; +import Workspace from "../../../../services/workspaces/entities/workspace"; +import Company from "../../../../services/user/entities/company"; +import User from "../../../../services/user/entities/user"; +import { Channel } from "../../../../services/channels/entities"; +import { Message } from "../../../../services/messages/entities/messages"; +import { + KnowledgeGraphGenericEventPayload, + KnowledgeGraphEvents, + KnowledgeGraphCallbackEvent, +} from "./types"; +import KnowledgeGraphAPIClient from "./api-client"; +import gr from "../../../../services/global-resolver"; + +@Consumes([]) +export default class KnowledgeGraphService + extends TwakeService + implements KnowledgeGraphAPI +{ + readonly name = "knowledge-graph"; + readonly version = "1.0.0"; + protected kgAPIClient: KnowledgeGraphAPIClient = this.getKnowledgeGraphApiClient(); + logger: TwakeLogger = getLogger("knowledge-graph-service"); + + async doInit(): Promise { + const use = this.getConfigurationEntry("use"); + + if (!use) { + this.logger.warn("Knowledge graph is not used"); + + return this; + } + + localEventBus.subscribe>( + KnowledgeGraphEvents.COMPANY_UPSERT, + this.onCompanyCreated.bind(this), + ); + + localEventBus.subscribe>( + KnowledgeGraphEvents.WORKSPACE_UPSERT, + this.onWorkspaceCreated.bind(this), + ); + + localEventBus.subscribe>( + KnowledgeGraphEvents.CHANNEL_UPSERT, + this.onChannelCreated.bind(this), + ); + + localEventBus.subscribe>( + KnowledgeGraphEvents.MESSAGE_UPSERT, + this.onMessageUpsert.bind(this), + ); + + localEventBus.subscribe>( + KnowledgeGraphEvents.USER_UPSERT, + this.onUserCreated.bind(this), + ); + + return this; + } + + /** When the KG service send us new events */ + async onCallbackEvent(token: string, data: KnowledgeGraphCallbackEvent): Promise { + if (token === this.getConfigurationEntry("callback_token")) { + this.logger.info("Unimplemented: KnowledgeGraph - Callback event", data); + } else { + throw new Error("Invalid token"); + } + } + + async onCompanyCreated(data: KnowledgeGraphGenericEventPayload): Promise { + this.logger.info(`${KnowledgeGraphEvents.COMPANY_UPSERT} %o`, data); + + if (this.kgAPIClient && (await this.shouldForwardEvent([data.resource.id]))) { + this.kgAPIClient.onCompanyCreated(data.resource); + } + } + + async onWorkspaceCreated(data: KnowledgeGraphGenericEventPayload): Promise { + this.logger.info(`${KnowledgeGraphEvents.WORKSPACE_UPSERT} %o`, data); + + if (this.kgAPIClient && (await this.shouldForwardEvent([data.resource.company_id]))) { + this.kgAPIClient.onWorkspaceCreated(data.resource); + } + } + + async onChannelCreated(data: KnowledgeGraphGenericEventPayload): Promise { + this.logger.info(`${KnowledgeGraphEvents.CHANNEL_UPSERT} %o`, data); + + if (this.kgAPIClient && (await this.shouldForwardEvent([data.resource.company_id]))) { + this.kgAPIClient.onChannelCreated(data.resource); + } + } + + async onMessageUpsert(data: KnowledgeGraphGenericEventPayload): Promise { + this.logger.debug(`${KnowledgeGraphEvents.MESSAGE_UPSERT} %o`, data); + + const allowedToShare = await this.shouldForwardEvent( + [data.resource.cache.company_id], + data.resource.user_id, + ); + + if (this.kgAPIClient && allowedToShare) { + this.kgAPIClient.onMessageUpsert( + data.resource.cache.company_id, + data.resource, + allowedToShare === "all", + ); + } + } + + async onUserCreated(data: KnowledgeGraphGenericEventPayload): Promise { + this.logger.info(`${KnowledgeGraphEvents.USER_UPSERT} %o`, data); + + if ( + this.kgAPIClient && + (await this.shouldForwardEvent(data.resource.cache?.companies || [], data.resource.id)) + ) { + for (const companyId of data.resource.cache?.companies || []) { + this.kgAPIClient.onUserCreated(companyId, data.resource); + } + } + } + + private getConfigurationEntry(key: string): T { + const configuration = new Configuration("knowledge-graph"); + return configuration.get(key); + } + + private getKnowledgeGraphApiClient(): KnowledgeGraphAPIClient { + const endpoint = this.getConfigurationEntry("endpoint"); + + if (endpoint && endpoint.length) { + this.kgAPIClient = new KnowledgeGraphAPIClient(endpoint); + } else { + this.logger.info("KnowledgeGraph - No endpoint defined in default.json"); + } + + return this.kgAPIClient; + } + + async shouldForwardEvent( + companyIds: string[] | null, + userId?: string, + ): Promise { + const user = userId ? await gr.services.users.get({ id: userId }) : null; + const forwardedCompanies = this.getConfigurationEntry("forwarded_companies"); + const isCompanyForwarded = !!(companyIds || []).find(v => forwardedCompanies.includes(v)); + if (user?.preferences && !user.preferences.knowledge_graph) + user.preferences.knowledge_graph = "metadata"; + return (!userId || (user && user.preferences?.knowledge_graph !== "nothing")) && + (!companyIds || + companyIds.length === 0 || + isCompanyForwarded || + forwardedCompanies.length === 0) + ? user + ? (user.preferences.knowledge_graph as "all" | "metadata") + : "all" + : false; + } + + api(): KnowledgeGraphAPI { + return this; + } +} diff --git a/twake/backend/node/src/core/platform/services/knowledge-graph/provider.ts b/twake/backend/node/src/core/platform/services/knowledge-graph/provider.ts new file mode 100644 index 00000000..fc5a1f59 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/knowledge-graph/provider.ts @@ -0,0 +1,15 @@ +import Company from "../../../../services/user/entities/company"; +import { Channel } from "../../../../services/channels/entities"; +import { TwakeServiceProvider } from "../../framework"; +import { KnowledgeGraphGenericEventPayload } from "./types"; +import Workspace from "../../../../services/workspaces/entities/workspace"; +import { Message } from "../../../../services/messages/entities/messages"; +import User from "../../../../services/user/entities/user"; + +export default interface KnowledgeGraphAPI extends TwakeServiceProvider { + onCompanyCreated(data: KnowledgeGraphGenericEventPayload): void; + onWorkspaceCreated(data: KnowledgeGraphGenericEventPayload): void; + onChannelCreated(data: KnowledgeGraphGenericEventPayload): void; + onMessageUpsert(data: KnowledgeGraphGenericEventPayload): void; + onUserCreated(data: KnowledgeGraphGenericEventPayload): void; +} diff --git a/twake/backend/node/src/core/platform/services/knowledge-graph/types.ts b/twake/backend/node/src/core/platform/services/knowledge-graph/types.ts new file mode 100644 index 00000000..a6d38a4d --- /dev/null +++ b/twake/backend/node/src/core/platform/services/knowledge-graph/types.ts @@ -0,0 +1,109 @@ +export type KnowledgeGraphCreateCompanyObjectData = { + key: string; + value: { + id: string; + properties: { + company_id: string; + company_name: string; + }; + }; +}; + +export type KnowledgeGraphCreateWorkspaceObjectData = { + key: string; + value: { + id: string; + properties: { + company_id: string; + workspace_name: string; + workspace_id: string; + }; + }; +}; + +export type KnowledgeGraphCreateUserObjectData = { + key: string; + value: { + id: string; + properties: { + user_id: string; + email: string; + username: string; + user_last_activity: string; + first_name: string; + user_created_at: string; + last_name: string; + company_id: string; + }; + }; +}; + +export type KnowledgeGraphCreateChannelObjectData = { + key: string; + value: { + id: string; + properties: { + channel_id: string; + channel_name: string; + channel_owner: string; + workspace_id: string; + }; + }; +}; + +export type KnowledgeGraphCreateMessageObjectData = { + key: string; + value: { + id: string; + properties: { + message_thread_id: string; + message_created_at: string; + message_content: string; + type_message: string; + message_updated_at: string; + user_id: string; + channel_id: string; + }; + }; +}; + +export type KnowledgeGraphCreateBodyRequest = { + records: T; +}; + +export type KnowledgeGraphRelationLinkObject = { + relation: "mention" | "sender" | "parent" | "children" | "owner"; + type: "user" | "channel" | "workspace" | "company" | "message"; + id: string; +}; + +export type KnowledgeGraphGenericEventPayload = { + id: string; + resource: Partial; + links: KnowledgeGraphRelationLinkObject[]; +}; + +export enum KnowledgeGraphEvents { + COMPANY_UPSERT = "kg:company:upsert", + WORKSPACE_UPSERT = "kg:workspace:upsert", + CHANNEL_UPSERT = "kg:channel:upsert", + MESSAGE_UPSERT = "kg:message:upsert", + USER_UPSERT = "kg:user:upsert", +} + +export type KnowledgeGraphCallbackEvent = { + recipients: { + type: "user"; + id: string; // KG user id which is a md5 of the email + }[]; + event: { + type: "user_tags"; //More events will be added later + data: { + //For user_tags event only + tags?: { + value: string; + weight: number; + }[]; + }; + }; +}; diff --git a/twake/backend/node/src/core/platform/services/message-queue/amqp/client.ts b/twake/backend/node/src/core/platform/services/message-queue/amqp/client.ts new file mode 100644 index 00000000..a6e5dc8d --- /dev/null +++ b/twake/backend/node/src/core/platform/services/message-queue/amqp/client.ts @@ -0,0 +1,143 @@ +import { logger } from "../../../framework/logger"; +import { constants as CONSTANTS } from "./constants"; +import { ConfirmChannel, Replies, Message, Options, ConsumeMessage } from "amqplib"; + +const LOG_PREFIX = "service.message-queue.amqp.AmqpClient -"; + +export type AmqpCallbackType = ( + err: Error, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + parsedMessage: any, + originalMessage: ConsumeMessage, +) => void; + +export type PublishOptions = { + /** + * Published message TTL in ms. + * Up to the underlying layer to deal with it (if supported) and so to not deliver the message if expired. + */ + ttl?: number | null; +}; + +export type SubscribeOptions = { + /** + * Message TTL in ms. + * This value is used (if supported) by the underlying layer to not deliver message to the local subscriber if message expired. + */ + ttl?: number | null; +}; + +/** + * Low level AMQP client using AMQP channel the right way. + * + * see http://www.squaremobius.net/amqp.node/ for the amqp documentation + */ +export class AmqpClient { + protected _subscribeCallbackToConsumerTags: Map; + protected _connected = false; + + constructor(protected channel: ConfirmChannel) { + this._subscribeCallbackToConsumerTags = new Map(); + } + + get connected(): boolean { + return this._connected; + } + + set connected(value: boolean) { + this._connected = value; + } + + async dispose(): Promise { + logger.info(`${LOG_PREFIX} Closing the connection`); + + try { + this.channel.close(); + } catch (err) { + logger.debug({ err }, `${LOG_PREFIX} Can not close the channel (probably already closed)`); + } + } + + assertExchange( + exchange: string, + type = CONSTANTS.EXCHANGE_TYPES.topic, + ): Promise { + logger.debug(`${LOG_PREFIX} Assert exchange ${exchange} of type ${type}`); + return new Promise((r, e) => this.channel.assertExchange(exchange, type).then(r).catch(e)); + } + + ack(message: Message, allUpTo = false): void { + logger.debug(`${LOG_PREFIX} Ack message`); + this.channel.ack(message, allUpTo); + } + + assertQueue(name: string, options: Options.AssertQueue): Promise { + logger.debug(`${LOG_PREFIX} Assert queue ${name} with options %o`, options); + return new Promise((r, e) => + this.channel + .assertQueue(name, options) + .then(result => { + logger.debug(`${LOG_PREFIX} Queue created %o`, result); + + return result; + }) + .then(r) + .catch(e), + ); + } + + assertBinding(queue: string, exchange: string, routingPattern?: string): Promise { + logger.debug( + `${LOG_PREFIX} Bind queue ${queue} on exchange ${exchange} with pattern ${routingPattern}`, + ); + return new Promise((r, e) => + this.channel.bindQueue(queue, exchange, routingPattern).then(r).catch(e), + ); + } + + send(exchange: string, data: unknown, routingKey = "", options?: Options.Publish): boolean { + logger.debug(`${LOG_PREFIX} Publish message to exchange ${exchange} with options %o`, options); + return this.channel.publish(exchange, routingKey, dataAsBuffer(data), options); + } + + consume(queue: string, options: Options.Consume, callback: AmqpCallbackType): Promise { + logger.debug(`${LOG_PREFIX} Consume queue ${queue} with options %o`, options); + return new Promise((r, e) => + this.channel + .consume(queue, onMessage, options) + .then(res => this._registerNewConsumerTag(callback, res.consumerTag, queue)) + .then(r) + .catch(e), + ); + + function onMessage(originalMessage: ConsumeMessage) { + try { + const message = JSON.parse(originalMessage.content.toString()); + callback(null, message, originalMessage); + } catch (err) { + logger.warn({ err }, `${LOG_PREFIX} Can not parse the incoming message`); + callback(err, null, originalMessage); + } + } + } + + _registerNewConsumerTag( + callback: AmqpCallbackType, + consumerTag: string, + queueName: string, + ): void { + const sameCallbackTags = this._subscribeCallbackToConsumerTags.get(callback) || []; + + sameCallbackTags.push(consumerTag); + this._subscribeCallbackToConsumerTags.set(callback, sameCallbackTags); + + logger.info( + `${LOG_PREFIX} A new consumer has been created for queue ${queueName}: ${consumerTag}`, + ); + } +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function dataAsBuffer(data: any): Buffer { + return Buffer.from(JSON.stringify(data)); +} diff --git a/twake/backend/node/src/core/platform/services/message-queue/amqp/constants.ts b/twake/backend/node/src/core/platform/services/message-queue/amqp/constants.ts new file mode 100644 index 00000000..8601b359 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/message-queue/amqp/constants.ts @@ -0,0 +1,33 @@ +export const constants = { + DEFAULT_AMQP_PROTOCOL: "amqp", + DEFAULT_AMQP_HOST: "localhost", + DEFAULT_AMQP_PORT: "5672", + DEFAULT_AMQP_USERNAME: "guest", + DEFAULT_AMQP_PASSWORD: "guest", + + EXCHANGE_TYPES: { + pubsub: "fanout", + topic: "topic", + }, + + PUBSUB_EXCHANGE: { + type: "fanout", + routingKey: "", // not considered for 'fanout' exchange + encoding: "utf8", + }, + + SUBSCRIBER: { + queueName: "", // This is the message-queue pattern with amqp, the server allocates a free queue name for us + queueOptions: { + exclusive: true, + durable: false, + autoDelete: true, + }, + durableQueueOptions: { + exclusive: false, + durable: true, + autoDelete: false, + }, + consumeOptions: { noAck: false }, + }, +}; diff --git a/twake/backend/node/src/core/platform/services/message-queue/amqp/index.ts b/twake/backend/node/src/core/platform/services/message-queue/amqp/index.ts new file mode 100644 index 00000000..4c14a20d --- /dev/null +++ b/twake/backend/node/src/core/platform/services/message-queue/amqp/index.ts @@ -0,0 +1,76 @@ +import { Subscription } from "rxjs"; +import { logger as rootLogger } from "../../../framework/logger"; +import { + MessageQueueAdapter, + MessageQueueClient, + MessageQueueListener, + MessageQueueMessage, + MessageQueueSubscriptionOptions, +} from "../api"; +import MessageQueueProxy from "../proxy"; +import { AMQPMessageQueueManager } from "./manager"; +import { SkipCLI } from "../../../framework/decorators/skip"; + +const logger = rootLogger.child({ + component: "twake.core.platform.services.message-queue.amqp", +}); + +export class AMQPMessageQueueService implements MessageQueueAdapter { + version: "1"; + clientProxy: MessageQueueProxy; + availableSubscription: Subscription; + unavailableSubscription: Subscription; + manager: AMQPMessageQueueManager; + type: "amqp"; + + constructor(private urls: string[]) { + this.manager = new AMQPMessageQueueManager(); + this.clientProxy = new MessageQueueProxy(); + } + + @SkipCLI() + async init(): Promise { + logger.info("Initializing message-queue service implementation with urls %o", this.urls); + await this.manager.createClient(this.urls); + + this.availableSubscription = this.manager.getClientAvailable().subscribe({ + next: (client: MessageQueueClient) => { + logger.info("A new message-queue client is available"); + this.clientProxy.setClient(client); + }, + error: () => { + logger.error("Error while listening to message-queue client availability"); + }, + }); + + this.unavailableSubscription = this.manager.getClientUnavailable().subscribe({ + next: (err: Error) => { + logger.warn({ err }, "Client is not available anymore"); + this.clientProxy.unsetClient(); + }, + error: () => { + logger.error("Error while listening to message-queue client unavailability"); + }, + }); + + return this; + } + + async stop(): Promise { + logger.info("Closing message-queue service"); + await this.clientProxy.close(); + return this; + } + + publish(topic: string, message: MessageQueueMessage): Promise { + return this.clientProxy.publish(topic, message); + } + + subscribe( + topic: string, + listener: MessageQueueListener, + options?: MessageQueueSubscriptionOptions, + ): Promise { + return this.clientProxy.subscribe(topic, listener, options); + } +} diff --git a/twake/backend/node/src/core/platform/services/message-queue/amqp/manager.ts b/twake/backend/node/src/core/platform/services/message-queue/amqp/manager.ts new file mode 100644 index 00000000..276671a8 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/message-queue/amqp/manager.ts @@ -0,0 +1,88 @@ +import { ConfirmChannel } from "amqplib"; +import { AmqpConnectionManager, connect } from "amqp-connection-manager"; +import { ReplaySubject, Subject } from "rxjs"; +import { logger } from "../../../framework/logger"; +import { AmqpMessageQueueClient } from "./pubsubclient"; +import { MessageQueueClientManager, MessageQueueClient } from "../api"; +import { AMQPPubSub } from "./pubsub"; + +const LOG_PREFIX = "service.pubsub.amqp.AMQPMessageQueueManager -"; + +export class AMQPMessageQueueManager implements MessageQueueClientManager { + // using ReplaySubjects will allow to get the data which has been published before the subscriptions + private clientAvailable: Subject = new ReplaySubject(1); + private clientUnavailable: Subject = new ReplaySubject(1); + private connected = false; + + getClientAvailable(): Subject { + return this.clientAvailable; + } + + getClientUnavailable(): Subject { + return this.clientUnavailable; + } + + async createClient(urls: string[]): Promise> { + logger.info(`${LOG_PREFIX} Creating AMQP client %o`, urls); + const connection = connect(urls); + + // disconnect is called when going from "connected" to "disconnected", + // and also at every unsuccessfull connection attempt + connection.on("disconnect", (err: Error) => { + logger.warn({ err }, `${LOG_PREFIX} RabbitMQ connection lost`); + this.connected = false; + this.clientUnavailable.next(err); + }); + + const client = await this.create(connection); + const pubsub = new AMQPPubSub(client); + + // For the first connection + this.clientAvailable.next(pubsub); + + // This event listener must be after the first connection occurs + // Connect event is not sent on first connection + // so we have to deal with the `connected` flag + connection.on("connect", ({ url }) => { + logger.info(`${LOG_PREFIX} Connected to RabbitMQ on ${url}`); + if (this.connected) { + return; + } + this.connected = true; + }); + + return this.clientAvailable; + } + + private create(connection: AmqpConnectionManager): Promise { + logger.info(`${LOG_PREFIX} Creating AMQP Channel`); + const channel = connection.createChannel({ name: "Twake" }); + + channel.on("close", () => { + logger.info(`${LOG_PREFIX} Channel is closed`); + }); + + channel.on("connect", () => { + logger.info(`${LOG_PREFIX} Channel is connected`); + }); + + channel.on("error", () => { + logger.info(`${LOG_PREFIX} Channel creation error`); + }); + + return new Promise(resolve => { + channel.addSetup((channel: ConfirmChannel) => { + logger.info(`${LOG_PREFIX} Channel setup is complete`); + const client = new AmqpMessageQueueClient(channel); + + // First attempt + if (!this.connected) { + this.connected = true; + resolve(client); + } else { + this.clientAvailable.next(new AMQPPubSub(client)); + } + }); + }); + } +} diff --git a/twake/backend/node/src/core/platform/services/message-queue/amqp/pubsub.ts b/twake/backend/node/src/core/platform/services/message-queue/amqp/pubsub.ts new file mode 100644 index 00000000..1c0dbd4e --- /dev/null +++ b/twake/backend/node/src/core/platform/services/message-queue/amqp/pubsub.ts @@ -0,0 +1,70 @@ +import { logger } from "../../../framework/logger"; +import { AmqpMessageQueueClient } from "./pubsubclient"; +import { + MessageQueueMessage, + MessageQueueListener, + MessageQueueClient, + MessageQueueSubscriptionOptions, +} from "../api"; +import { AmqpCallbackType, SubscribeOptions } from "./client"; + +const LOG_PREFIX = "service.message-queue.amqp.AMQPPubSub -"; + +/** + * Implementation of MessageQueueClient based on AMQP + */ +export class AMQPPubSub implements MessageQueueClient { + constructor(private client: AmqpMessageQueueClient) {} + + close(): Promise { + return this.client.dispose(); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + async publish(topic: string, message: MessageQueueMessage): Promise { + logger.debug(`${LOG_PREFIX} Publishing message to topic ${topic}`); + await this.client.publish(topic, message.data, { ttl: message.ttl }); + } + + subscribe( + topic: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + listener: MessageQueueListener, + options: MessageQueueSubscriptionOptions = { unique: false, queue: null, ttl: -1 }, + ): Promise { + const subscribeOptions: SubscribeOptions = {}; + logger.debug(`${LOG_PREFIX} Subscribing to topic ${topic} with options %o`, options); + + const callback: AmqpCallbackType = (err, message, originalMessage) => { + const data = err ? originalMessage : message; + + if (err) { + logger.error( + `${LOG_PREFIX} Received a message which can not be parsed on topic ${topic}: %o`, + originalMessage?.content.toString(), + ); + } + + listener({ + data, + ack: (): void => { + logger.debug(`${LOG_PREFIX} Ack message on topic ${topic}`); + this.client.ack(originalMessage); + }, + }); + }; + + if (options.ttl && options.ttl > 0) { + subscribeOptions.ttl = options.ttl; + } + + return options?.unique + ? this.client.subscribeToDurableQueue( + topic, + options?.queue || topic, + subscribeOptions, + callback, + ) + : this.client.subscribe(topic, subscribeOptions, callback); + } +} diff --git a/twake/backend/node/src/core/platform/services/message-queue/amqp/pubsubclient.ts b/twake/backend/node/src/core/platform/services/message-queue/amqp/pubsubclient.ts new file mode 100644 index 00000000..996bbef4 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/message-queue/amqp/pubsubclient.ts @@ -0,0 +1,88 @@ +import { logger } from "../../../framework/logger"; +import { constants as CONSTANTS } from "./constants"; +import { AmqpClient, AmqpCallbackType, PublishOptions, SubscribeOptions } from "./client"; +import { Options } from "amqplib"; +import _ from "lodash"; + +const LOG_PREFIX = "service.message-queue.amqp.AmqpMessageQueueClient -"; + +/** + * AMQP client abstracting low level channel methods to create a message-queue-like implementation + */ +export class AmqpMessageQueueClient extends AmqpClient { + publish(topic: string, data: unknown, options?: PublishOptions): Promise { + data = _.cloneDeep(data); + + let publishOptions: Options.Publish; + + logger.debug(`${LOG_PREFIX} Publishing message to topic "${topic}" with options %o`, options); + + if (options?.ttl) { + publishOptions = { + expiration: options.ttl, + }; + } + + return this.assertExchange(topic, CONSTANTS.PUBSUB_EXCHANGE.type).then(() => + this.send(topic, data, CONSTANTS.PUBSUB_EXCHANGE.routingKey, publishOptions), + ); + } + + subscribe(topic: string, options: SubscribeOptions, callback: AmqpCallbackType): Promise { + const queueOptions: Options.AssertQueue = { + ...CONSTANTS.SUBSCRIBER.queueOptions, + ...(options?.ttl ? { messageTtl: options.ttl } : {}), + }; + + return this.assertExchange(topic, CONSTANTS.PUBSUB_EXCHANGE.type) + .then(() => this.assertQueue(CONSTANTS.SUBSCRIBER.queueName, queueOptions)) + .then(res => this.assertBinding(res.queue, topic).then(() => res)) + .then(res => this.consume(res.queue, CONSTANTS.SUBSCRIBER.consumeOptions, callback)); + } + + /** + * Creates a new consumer which asserts that it will listen to messages in a durable queue. + * The durable queue goal is to be able to receive events 'from the past' ie events which has been push to the queue while subscribers were not bound. + * This is quite useful in case of restart to not miss anything between stop and start. + * Important: If multiple consumers are connected to the same durable queue, AMQP will deliver message to one and only one consumer with a Round-robin behavior by default. + * + * @param {String} exchangeName - The exchange name + * @param {String} queueName - The queue name + * @param {Function} callback - The callback to call once there is a message in the queue + */ + subscribeToDurableQueue( + exchangeName: string, + queueName: string, + options: SubscribeOptions, + callback: AmqpCallbackType, + ): Promise { + const durableQueueOptions: Options.AssertQueue = { + ...CONSTANTS.SUBSCRIBER.durableQueueOptions, + ...(options?.ttl ? { messageTtl: options.ttl } : {}), + }; + + logger.debug( + `${LOG_PREFIX} Subscribing to durable queue ${queueName} with options %o`, + durableQueueOptions, + ); + + return this.assertExchange(exchangeName, CONSTANTS.PUBSUB_EXCHANGE.type) + .then(() => this.assertQueue(queueName, durableQueueOptions)) + .then(() => this.assertBinding(queueName, exchangeName)) + .then(() => this.consume(queueName, CONSTANTS.SUBSCRIBER.consumeOptions, callback)); + } + + async unsubscribe(topic: string, callback: AmqpCallbackType): Promise { + const consumerTags = this._subscribeCallbackToConsumerTags.get(callback); + + if (Array.isArray(consumerTags)) { + logger.info(`${LOG_PREFIX} About to remove the consumer(s): ${consumerTags}`); + + await Promise.all(consumerTags.map(c => this.channel.cancel(c))); + + return; + } + + logger.warn(`${LOG_PREFIX} No consumerTag found to unsubscribe a consumer from: ${topic}`); + } +} diff --git a/twake/backend/node/src/core/platform/services/message-queue/api.ts b/twake/backend/node/src/core/platform/services/message-queue/api.ts new file mode 100644 index 00000000..3df4475c --- /dev/null +++ b/twake/backend/node/src/core/platform/services/message-queue/api.ts @@ -0,0 +1,338 @@ +import { Subject } from "rxjs"; +import { v4 as uuidv4 } from "uuid"; +import { Initializable, logger, TwakeServiceProvider } from "../../framework"; +import { Processor } from "./processor"; +import { ExecutionContext } from "../../framework/api/crud-service"; + +export type MessageQueueType = "local" | "amqp"; + +export interface MessageQueueMessage { + /** + * Optional message id, mainly used for logs + */ + id?: string; + + /** + * The message TTL period in milliseconds + */ + ttl?: number; + + /** + * The message payload to process + */ + data: T; +} + +export interface MessageQueueEventMessage extends MessageQueueMessage { + topic: string; +} + +export interface IncomingMessageQueueMessage extends MessageQueueMessage { + ack: () => void; +} + +export type MessageQueueSubscriptionOptions = { + /** + * A unique subscription guaranties that there will be only one listener consuming the message on the subscription topic even if many are subscribing to the same topic from several places (not only from the current instance/host). + * Also, it will guaranties that messages which were published before any subscriber subscribes will be consumed. + */ + unique?: boolean; + + /** + * Automatically acknowledge the incoming message when the processing is complete + */ + ack?: boolean; + + /** + * Use custom named queue instead of using same name as exchange. Can be useful when we have multiple subsciptions on the same topic. + */ + queue?: string | null; + + /** + * Configures the message TTL (in ms) in the underlying messaging system. + * Negative or undefined means no TTL. + * Notes: + * - If supported by the messaging system, messages will not be delivered to the application. + * - If not supported, this may be up to the subscriber itself to filter messages at the application level based on some timestamp if available. + */ + ttl?: number | null; +}; + +export type MessageQueueListener = (message: IncomingMessageQueueMessage) => void; + +export interface MessageQueueServiceAPI extends TwakeServiceProvider { + /** + * Publish a message to a given topic + * @param topic The topic to publish the message to + * @param message The message to publish to the topic + * @param context + */ + publish( + topic: string, + message: MessageQueueMessage, + context?: ExecutionContext, + ): Promise; + + /** + * Subscribe the a topic. The listener will be called when a new message is published in the topic (this may not be true based on the options parameters). + * @param topic The topic to subsribe to + * @param listener The function which will process the message published in the topic + * @param options The subscription options. If not defined, the subscriber will be called for all messages available in the topic. + */ + subscribe( + topic: string, + listener: MessageQueueListener, + options?: MessageQueueSubscriptionOptions, + ): Promise; + + /** + * The messages processor instance + */ + processor: Processor; + + stop(): Promise; + start(): Promise; +} + +export type MessageQueueAdapter = Pick & { + type: string; + init?(): Promise; + start?(): Promise; + stop?(): Promise; +}; + +export type MessageQueueClient = Pick & { + /** + * Close the client + */ + close?(): Promise; +}; + +/** + * The client manager allows to get notified when a client is available and then becomes unavailable. + */ +export interface MessageQueueClientManager { + /** + * Ask for a new client to be created + */ + createClient(config: string[]): Promise>; + + /** + * Subject when a client is available + */ + getClientAvailable(): Subject; + + /** + * Subject when a client becomes unavailable + */ + getClientUnavailable(): Subject; +} + +/** + * Manages the message-queue client adding mechanisms to cache subscriptions and messages to publish. + */ +export interface MessageQueueProxy extends MessageQueueClient { + /** + * Set a new client to use replacing any existing one. + * The new client will reuse all the subscriptions automatically. + * @param client + */ + setClient(client: MessageQueueClient): Promise; + + /** + * Remove the client. This will close any underlying connection but will not remove any subscription. + */ + unsetClient(): Promise; +} + +export interface MessageQueueEventBus { + /** + * Subscribes to events + */ + subscribe(listener: (message: MessageQueueEventMessage) => void): this; + + /** + * Publish message in event bus + */ + publish(message: MessageQueueEventMessage): boolean; +} + +export abstract class MessageQueueServiceSubscription { + protected messageQueue: MessageQueueServiceAPI; + + async subscribe(messageQueue: MessageQueueServiceAPI): Promise { + if (!messageQueue) { + throw new Error("message-queue service it not defined"); + } + this.messageQueue = messageQueue; + + return this.doSubscribe(); + } + + abstract doSubscribe(): Promise; +} + +export class MessageQueueServiceProcessor + extends MessageQueueServiceSubscription + implements Initializable +{ + constructor( + protected handler: MessageQueueHandler, + protected messageQueue: MessageQueueServiceAPI, + ) { + super(); + } + + async init(): Promise { + try { + await this.subscribe(this.messageQueue); + } catch (err) { + logger.warn( + { err }, + `MessageQueueServiceProcessor.handler.${this.handler.name} - Not able to start handler`, + ); + } + + return this; + } + + async stop(): Promise { + // TODO + return this; + } + + async process(message: IncomingMessageQueueMessage): Promise { + logger.info( + `MessageQueueServiceProcessor.handler.${this.handler.name}:${message.id} - Processing message`, + ); + return this.handler.process(message.data); + } + + async doSubscribe(): Promise { + //TODO this is where we do not receive the call + + if (this.handler.topics && this.handler.topics.in) { + logger.info( + `MessageQueueServiceProcessor.handler.${this.handler.name} - Subscribing to topic ${this.handler?.topics?.in} with options %o`, + this.handler.options, + ); + await this.messageQueue.subscribe( + this.handler.topics.in, + this.processMessage.bind(this), + this.handler.options, + ); + } + } + + private async processMessage(message: IncomingMessageQueueMessage): Promise { + if (!message.id) { + message.id = uuidv4(); + } + + if (this.handler.validate) { + const isValid = this.handler.validate(message.data); + + if (!isValid) { + logger.error( + `MessageQueueServiceProcessor.handler.${this.handler.name}:${message.id} - Message is invalid`, + ); + + //Validate rabbitmq message, we will not process it again + if (this.handler?.options?.ack && message?.ack) message?.ack(); + return; + } + } + + try { + const result = await this.process(message); + if (this.handler?.options?.ack && message?.ack) { + logger.debug( + `MessageQueueServiceProcessor.handler.${this.handler.name}:${message.id} - Acknowledging message %o`, + message, + ); + message?.ack(); + } + + if (result) { + await this.sendResult(message, result); + } + } catch (error) { + this.handleError(message, error); + + //Fixme Validate message because we don't have max retry handler + if (this.handler?.options?.ack && message?.ack) message?.ack(); + } + } + + private async sendResult(message: IncomingMessageQueueMessage, result: Out): Promise { + if (!this.handler.topics.out) { + logger.info( + `MessageQueueServiceProcessor.handler.${this.handler.name}:${message.id} - Message processing result is skipped`, + ); + return; + } + + logger.info( + `MessageQueueServiceProcessor.handler.${this.handler.name}:${message.id} - Sending processing result to ${this.handler.topics.out}`, + ); + + return this.messageQueue.publish(this.handler.topics.out, { + id: uuidv4(), + data: result, + }); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private async handleError(message: IncomingMessageQueueMessage, err: any) { + logger.error( + { err }, + `MessageQueueServiceProcessor.handler.${this.handler.name}:${message.id} - Error while processing message`, + ); + if (this.handler.topics.error) { + this.messageQueue.publish(this.handler.topics.error, { + data: { + type: "error", + id: message.id, + message: err instanceof Error ? (err as Error).message : String(err), + }, + }); + } + } +} + +/** + * A message-queue handler is in charge of processing message from a topic and publishing the processing result to another topic + */ +export interface MessageQueueHandler extends Initializable { + readonly topics: { + // The topic to subscribe to + in: string; + // The topic to push process result to if defined + out?: string; + // The topic to push error to. When topic is undefined, do not push the error + error?: string; + }; + + /** + * Options subscriber options + */ + readonly options?: MessageQueueSubscriptionOptions; + + /** + * The handler name + */ + readonly name: string; + + /** + * Validate the input message + * + * @param message message to validate + */ + validate?(message: InputMessage): boolean; + + /** + * Process the message and potentially produces result which will be published elsewhere + * @param message + */ + process(message: InputMessage): Promise; +} diff --git a/twake/backend/node/src/core/platform/services/message-queue/bus.ts b/twake/backend/node/src/core/platform/services/message-queue/bus.ts new file mode 100644 index 00000000..9d0ecff4 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/message-queue/bus.ts @@ -0,0 +1,36 @@ +import { EventEmitter } from "events"; +import { MessageQueueEventBus, MessageQueueEventMessage } from "./api"; +const EVENT = Symbol("event"); + +/** + * Event bus is used by the MessageQueue decorators to publish data to be send to message-queue service. + * The message-queue service is the only subscriber of the event bus. + * By decoupling decorator and service, events will not be published when the service is not enabled. + */ +class EventBus extends EventEmitter implements MessageQueueEventBus { + constructor() { + super(); + } + + /** + * Subscribe is MUST only be used by the message-queue service + * + * @param listener + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + subscribe(listener: (message: MessageQueueEventMessage) => void): this { + return this.on(EVENT, listener); + } + + /** + * Publish must only be used by the MessageQueue decorators + * + * @param message + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + publish(message: MessageQueueEventMessage): boolean { + return this.emit(EVENT, message); + } +} + +export const eventBus = new EventBus(); diff --git a/twake/backend/node/src/core/platform/services/message-queue/factory.ts b/twake/backend/node/src/core/platform/services/message-queue/factory.ts new file mode 100644 index 00000000..fbf39f9a --- /dev/null +++ b/twake/backend/node/src/core/platform/services/message-queue/factory.ts @@ -0,0 +1,38 @@ +import { MessageQueueAdapter, MessageQueueType } from "./api"; +import { AMQPMessageQueueService } from "./amqp"; +import { LocalMessageQueueService } from "./local"; +import { TwakeServiceConfiguration, logger as rootLogger } from "../../framework"; + +const logger = rootLogger.child({ + component: "twake.core.platform.services.message-queue.factory", +}); + +const DEFAULT_AMQP_URL = "amqp://guest:guest@localhost:5672"; +const DEFAULT_ADAPTER = "amqp"; + +export class MessageQueueAdapterFactory { + public create(configuration: TwakeServiceConfiguration): MessageQueueAdapter { + const type: MessageQueueType = configuration.get("type", DEFAULT_ADAPTER); + + logger.info("Building Adapter %o", type); + + switch (type) { + case "local": + return new LocalMessageQueueService(); + case "amqp": + let urls: string[] = configuration.get("amqp.urls", [DEFAULT_AMQP_URL]); + + //For environment variables + if (typeof urls === "string") { + urls = (urls as string).split(","); + } + + return new AMQPMessageQueueService(urls); + default: + logger.error("Adapter '%o' is not supported", type); + throw new Error(`${type} is not supported`); + } + } +} + +export default new MessageQueueAdapterFactory(); diff --git a/twake/backend/node/src/core/platform/services/message-queue/index.ts b/twake/backend/node/src/core/platform/services/message-queue/index.ts new file mode 100644 index 00000000..cb5393e3 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/message-queue/index.ts @@ -0,0 +1,101 @@ +import { TwakeService, ServiceName, logger as rootLogger } from "../../framework"; +import { + MessageQueueAdapter, + MessageQueueListener, + MessageQueueMessage, + MessageQueueServiceAPI, + MessageQueueSubscriptionOptions, +} from "./api"; +import { eventBus } from "./bus"; +import { Processor } from "./processor"; +import adapterFactory from "./factory"; +import { SkipCLI } from "../../framework/decorators/skip"; +import config from "../../../../core/config"; + +const logger = rootLogger.child({ + component: "twake.core.platform.services.message-queue", +}); +@ServiceName("message-queue") +export default class MessageQueue extends TwakeService { + version = "1"; + name = "message-queue"; + service: MessageQueueService; + + async doInit(): Promise { + this.service = new MessageQueueService( + //Old config name was "pubsub" + adapterFactory.create(this.configuration || config.get("pubsub")), + ); + await this.service.init(); + + eventBus.subscribe(message => { + logger.info(`Event bus publishing message to ${message.topic}`); + this.service.publish(message.topic, { data: message.data }); + }); + + return this; + } + + async doStart(): Promise { + await this.service.start(); + + return this; + } + + async doStop(): Promise { + await this.service.stop(); + + return this; + } + + api(): MessageQueueServiceAPI { + return this.service; + } +} + +export class MessageQueueService implements MessageQueueServiceAPI { + version: "1"; + processor: Processor; + + constructor(private adapter: MessageQueueAdapter) { + this.processor = new Processor(this); + } + + @SkipCLI() + async init(): Promise { + logger.info("Initializing message-queue adapter %o", this.adapter.type); + await this.adapter?.init?.(); + + return this; + } + + @SkipCLI() + async start(): Promise { + logger.info("Starting message-queue adapter %o", this.adapter.type); + await this.adapter?.start?.(); + await this.processor.start(); + + return this; + } + + @SkipCLI() + async stop(): Promise { + logger.info("Stopping message-queue adapter %o", this.adapter.type); + await this.adapter?.stop?.(); + await this.processor.stop(); + + return this; + } + + publish(topic: string, message: MessageQueueMessage): Promise { + return this.adapter.publish(topic, message); + } + + subscribe( + topic: string, + listener: MessageQueueListener, + options?: MessageQueueSubscriptionOptions, + ): Promise { + return this.adapter.subscribe(topic, listener, options); + } +} diff --git a/twake/backend/node/src/core/platform/services/message-queue/local/index.ts b/twake/backend/node/src/core/platform/services/message-queue/local/index.ts new file mode 100644 index 00000000..1eb4cdfd --- /dev/null +++ b/twake/backend/node/src/core/platform/services/message-queue/local/index.ts @@ -0,0 +1,97 @@ +import { Subject } from "rxjs"; +import { logger as rootLogger } from "../../../framework/logger"; +import { + IncomingMessageQueueMessage, + MessageQueueAdapter, + MessageQueueListener, + MessageQueueMessage, + MessageQueueSubscriptionOptions, +} from "../api"; +import MessageQueueProxy from "../proxy"; + +const logger = rootLogger.child({ + component: "twake.core.platform.services.message-queue.local", +}); + +/** + * A message-queue service implementation based on RXJS. + */ +export class LocalMessageQueueService implements MessageQueueAdapter { + private subjects: Map>>; + private clientProxy: MessageQueueProxy; + type: "local"; + + constructor() { + this.subjects = new Map>>(); + this.clientProxy = new MessageQueueProxy(); + } + + async init(): Promise { + this.clientProxy.setClient({ + publish: async (topic: string, message: MessageQueueMessage): Promise => { + return this.doPublish(topic, message); + }, + subscribe: async (topic: string, listener: MessageQueueListener): Promise => { + return this.doSubscribe(topic, listener); + }, + async close(): Promise { + logger.info("Closing the local message-queue"); + return this; + }, + }); + + return this; + } + + async stop(): Promise { + logger.info("Closing message-queue service"); + await this.clientProxy.close(); + return this; + } + + async subscribe(topic: string, listener: MessageQueueListener): Promise { + return this.clientProxy.subscribe(topic, listener); + } + + async publish(topic: string, message: MessageQueueMessage): Promise { + return this.clientProxy.publish(topic, message); + } + + private async doSubscribe( + topic: string, + listener: MessageQueueListener, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _options?: MessageQueueSubscriptionOptions, + ): Promise { + if (!this.subjects.has(topic)) { + this.subjects.set(topic, new Subject>()); + } + + this.subjects.get(topic).subscribe({ + next: (value: IncomingMessageQueueMessage) => { + logger.debug("Got a new value to dispatch to topic '%s': %o", topic, value); + try { + listener(value); + } catch (err) { + logger.warn({ err }, "Error while calling listener"); + } + }, + }); + } + + private async doPublish(topic: string, message: MessageQueueMessage): Promise { + if (!this.subjects.has(topic)) { + return; + } + + logger.debug("Publish new value to topic '%s': %o", topic, message); + this.subjects.get(topic)?.next({ + ...message, + ...{ + ack: () => { + logger.debug("ACK message %o", message); + }, + }, + }); + } +} diff --git a/twake/backend/node/src/core/platform/services/message-queue/processor.ts b/twake/backend/node/src/core/platform/services/message-queue/processor.ts new file mode 100644 index 00000000..3fbd55c7 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/message-queue/processor.ts @@ -0,0 +1,87 @@ +import { logger } from "../../framework"; +import { MessageQueueHandler, MessageQueueServiceAPI, MessageQueueServiceProcessor } from "./api"; + +const LOG_PREFIX = "service.message-queue.Processor"; + +export class Processor { + // TODO: Add state + private registry: ProcessorRegistry; + private started = false; + + constructor(private messageQueue: MessageQueueServiceAPI) { + this.registry = new ProcessorRegistry(this.messageQueue); + } + + async init(): Promise { + return this; + } + + async start(): Promise { + this.started = true; + await Promise.all( + Array.from(this.registry.processors.keys()).map(async name => { + logger.info(`${LOG_PREFIX} - Starting notification processor ${name}`); + await this.registry.processors.get(name)?.init(); + logger.info(`${LOG_PREFIX} - notification processor ${name} is started`); + }), + ); + } + + async stop(): Promise { + this.started = false; + await Promise.all( + Array.from(this.registry.processors.keys()).map(async name => { + this.removeHandler(name); + }), + ); + } + + addHandler(handler: MessageQueueHandler): void { + if (!handler) { + throw new Error(`${LOG_PREFIX} - Can not add null handler`); + } + + logger.info(`${LOG_PREFIX} - Adding message-queue handler ${handler.name}`); + this.registry.register(handler); + + if (this.started) { + this.startHandler(handler.name); + } + } + + async startHandler(name: string): Promise { + logger.info(`${LOG_PREFIX} - Starting message-queue handler ${name}`); + await this.registry.processors.get(name)?.init(); + } + + stopHandler(name: string): void { + logger.info(`${LOG_PREFIX} - Stopping message-queue handler ${name}`); + this.registry.processors.get(name)?.stop(); + } + + removeHandler(name: string): void { + logger.info(`${LOG_PREFIX} - Removing message-queue handler ${name}`); + this.stopHandler(name); + this.registry.processors.delete(name); + } +} + +class ProcessorRegistry { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + processors: Map>; + + constructor(private messageQueue: MessageQueueServiceAPI) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + this.processors = new Map>(); + } + + register(handler: MessageQueueHandler): void { + if (!handler) { + throw new Error("Can not add a null handler"); + } + this.processors.set( + handler.name, + new MessageQueueServiceProcessor(handler, this.messageQueue), + ); + } +} diff --git a/twake/backend/node/src/core/platform/services/message-queue/proxy.ts b/twake/backend/node/src/core/platform/services/message-queue/proxy.ts new file mode 100644 index 00000000..1b6ffe8f --- /dev/null +++ b/twake/backend/node/src/core/platform/services/message-queue/proxy.ts @@ -0,0 +1,172 @@ +import { isEqual } from "lodash"; +import { logger } from "../../framework"; +import { + MessageQueueClient, + MessageQueueListener, + MessageQueueMessage, + MessageQueueProxy, + MessageQueueSubscriptionOptions, +} from "./api"; + +const LOG_PREFIX = "service.message-queue.MessageQueueProxyService -"; + +type ListenerCache = { + listener: MessageQueueListener; + options?: MessageQueueSubscriptionOptions; +}; + +/** + * The message-queue implementation managing underlaying message-queue layer mainly used to cache messages and subscriptions when layer is not ready. + */ +export default class MessageQueueProxyService implements MessageQueueProxy { + version: "1"; + /** + * Cache messages to be published to topic when layer is not ready + * TODO: We may explode if we can not publish it accumulating messages, add a FIFO with limited size, or cache eviction system... + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + protected publicationsBuffer: Array<{ topic: string; message: MessageQueueMessage }> = []; + /** + * Cache subscriptions to be created until a new client is set + */ + protected subscriptionsCache: Map> = new Map< + string, + Set + >(); + + /** + * @param client optional initial client + */ + constructor(private client?: MessageQueueClient) {} + + async setClient(client: MessageQueueClient): Promise { + logger.info(`${LOG_PREFIX} Setting new message-queue client`); + // TODO: The client can be removed or replaced while we are looping here + // We may wait until things are done, or discard some... + if (!client) { + return; + } + + if (this.client) { + logger.info(`${LOG_PREFIX} MessageQueue client already set. Overriding`); + } + + this.client = client; + + await Promise.all( + Array.from(this.subscriptionsCache).map(entries => { + const topic = entries[0]; + const listeners = entries[1]; + + return Array.from(listeners).map(async listener => { + logger.debug(`${LOG_PREFIX} Subscribing to topic ${topic} from cache`); + try { + await this.subscribe(topic, listener.listener, listener.options); + } catch (err) { + logger.warn( + { err }, + `${LOG_PREFIX} Error while subscribing with cached subscription to topic ${topic}`, + ); + } + }); + }), + ); + + await Promise.all( + this.publicationsBuffer.map(async publication => { + try { + logger.debug(`${LOG_PREFIX} Publishing to topic ${publication.topic} from cache`); + await this.publish(publication.topic, publication.message); + } catch (err) { + logger.warn( + { err }, + `${LOG_PREFIX} Error while publishing cached data on topic ${publication.topic}`, + ); + } + }), + ); + + this.publicationsBuffer = []; + } + + async unsetClient(): Promise { + await this.close(); + this.client = undefined; + } + + /** + * Close never fails + */ + async close(): Promise { + try { + await this.client?.close?.(); + } catch (err) { + logger.debug({ err }, `${LOG_PREFIX} Error on closing the message-queue layer`); + } + } + + publish(topic: string, message: MessageQueueMessage): Promise { + if (!this.client) { + this.addPublishCache(topic, message); + + return; + } + + return this.client.publish(topic, message); + } + + subscribe( + topic: string, + listener: MessageQueueListener, + options?: MessageQueueSubscriptionOptions, + ): Promise { + this.addSubscriptionToCache(topic, listener, options); + + if (!this.client) { + return; + } + + return this.subscribeToClient(topic, listener, options); + } + + private addSubscriptionToCache( + topic: string, + listener: MessageQueueListener, + options: MessageQueueSubscriptionOptions, + ): void { + if (!this.subscriptionsCache.get(topic)) { + this.subscriptionsCache.set(topic, new Set()); + } + + const subscriptions = this.subscriptionsCache.get(topic); + logger.debug(`${LOG_PREFIX} Subscriptions for topic ${topic}: ${subscriptions.size}`); + + const values = [...subscriptions]; + const cachedListener = values.find( + entry => listener === entry.listener && isEqual(options, entry.options), + ); + + if (!cachedListener) { + logger.debug(`${LOG_PREFIX} Caching subscription to ${topic} topic: Yes`); + this.subscriptionsCache.get(topic).add({ listener, options }); + } else { + logger.debug(`${LOG_PREFIX} Caching subscription to ${topic} topic: No`); + } + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private addPublishCache(topic: string, message: any): void { + logger.debug(`${LOG_PREFIX} Caching publication to ${topic} topic`); + this.publicationsBuffer.push({ topic, message }); + } + + private subscribeToClient( + topic: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + listener: MessageQueueListener, + options?: MessageQueueSubscriptionOptions, + ): Promise { + logger.debug(`${LOG_PREFIX} Trying to subscribe to ${topic} topic with options %o`, options); + return this.client?.subscribe(topic, listener, options); + } +} diff --git a/twake/backend/node/src/core/platform/services/phpnode/index.ts b/twake/backend/node/src/core/platform/services/phpnode/index.ts new file mode 100644 index 00000000..ae5c098f --- /dev/null +++ b/twake/backend/node/src/core/platform/services/phpnode/index.ts @@ -0,0 +1,189 @@ +import { FastifyRequest, RouteHandlerMethod } from "fastify"; +import { FastifyInstance } from "fastify/types/instance"; +import { IncomingMessage, Server, ServerResponse } from "http"; +import { + ChannelCrudController, + ChannelMemberCrudController, +} from "../../../../services/channels/web/controllers"; +import { + ChannelMemberParameters, + ChannelParameters, + CreateChannelBody, +} from "../../../../services/channels/web/types"; +import { Consumes, TwakeService } from "../../framework"; +import WebServerAPI from "../webserver/provider"; +import WebSocketAPI from "../websocket/provider"; +import PhpNodeAPI from "./provider"; +import { RealtimeServiceAPI } from "../realtime/api"; +import gr from "../../../../services/global-resolver"; + +@Consumes(["webserver", "websocket", "user", "channels"]) +export default class PhpNodeService extends TwakeService implements PhpNodeAPI { + name = "phpnode"; + version = "1"; + private server: FastifyInstance; + private ws: WebSocketAPI; + private realtime: RealtimeServiceAPI; + + api(): PhpNodeAPI { + return this; + } + + async accessControl( + request: FastifyRequest, + server: FastifyInstance, + ) { + const token = (request.headers.authorization || "").trim().split("Token ").pop(); + const secret = this.configuration.get("secret", ""); + let authorized = false; + if (secret && token === secret) { + authorized = true; + } + + if (!authorized) { + throw server.httpErrors.badRequest("Internal Access Refused"); + } + } + + register(paremeters: { + method: "DELETE" | "GET" | "POST" | "PUT"; + url: string; + handler: RouteHandlerMethod; + }) { + this.server.register((instance, _opts, next) => { + instance.register( + (internalServer, _, next) => { + internalServer.route({ + method: paremeters.method, + url: paremeters.url, + preValidation: [request => this.accessControl(request, internalServer)], + handler: paremeters.handler, + }); + next(); + }, + { prefix: "/private" }, + ); + next(); + }); + } + + async doStart(): Promise { + return this; + } + + async doInit(): Promise { + this.server = this.context.getProvider("webserver").getServer(); + this.ws = this.context.getProvider("websocket"); + this.realtime = this.context.getProvider("realtime"); + + /** + * Register private calls from php for websockets + */ + this.register({ + method: "POST", + url: "/pusher", + handler: (request, reply) => { + const body = request.body as { room: string; data: any }; + const room = body.room; + const data = body.data; + this.ws.getIo().to(room).emit("realtime:event", { name: room, data: data }); + reply.send({}); + }, + }); + + /** + * Register private calls from php channels + */ + this.register({ + method: "GET", + url: "/companies/:company_id/workspaces/:workspace_id/channels/:id/members/:member_id/exists", + handler: (request: FastifyRequest<{ Params: ChannelMemberParameters }>, reply) => { + if (!gr.services) { + reply.code(500).send(); //Server is not ready + return; + } + const membersController = new ChannelMemberCrudController(); + membersController.exists(request, reply); + }, + }); + + /** + * Register private calls from php channels + */ + this.register({ + method: "GET", + url: "/companies/:company_id/workspaces/:workspace_id/channels/:id", + handler: (request: FastifyRequest<{ Params: ChannelParameters }>, reply) => { + if (!gr.services) { + reply.code(500).send(); //Server is not ready + return; + } + const channelsController = new ChannelCrudController(); + channelsController.getForPHP(request, reply); + }, + }); + + /** + * Register private calls from php channels + */ + this.register({ + method: "GET", + url: "/companies/:company_id/channels/:id", + handler: async ( + request: FastifyRequest<{ Params: { company_id: string; id: string } }>, + reply, + ) => { + if (!gr.services) { + reply.code(500).send(); //Server is not ready + return; + } + const workspaces = await gr.services.workspaces.getAllForCompany(request.params.company_id); + + for (const w of workspaces) { + const channel = await gr.services.channels.channels.get( + { + company_id: request.params.company_id, + workspace_id: w.id, + id: request.params.id, + }, + undefined, + ); + if (channel) { + reply.send(channel); + return; + } + } + + reply.code(404).send(); + }, + }); + + /** + * Register private calls from php channels + */ + this.register({ + method: "POST", + url: "/companies/:company_id/workspaces/:workspace_id/channels/defaultchannel", + handler: ( + request: FastifyRequest<{ + Body: CreateChannelBody; + Params: ChannelParameters; + Querystring: { include_users: boolean }; + }>, + reply, + ) => { + if (!gr.services) { + reply.code(500).send(); //Server is not ready + return; + } + const channelsController = new ChannelCrudController(); + request.currentUser = { + id: (request.body as any).user_id, + }; + channelsController.save(request, reply); + }, + }); + + return this; + } +} diff --git a/twake/backend/node/src/core/platform/services/phpnode/provider.ts b/twake/backend/node/src/core/platform/services/phpnode/provider.ts new file mode 100644 index 00000000..d9686c0a --- /dev/null +++ b/twake/backend/node/src/core/platform/services/phpnode/provider.ts @@ -0,0 +1,11 @@ +import { FastifyInstance, FastifyRequest, RouteHandlerMethod } from "fastify"; +import { IncomingMessage, ServerResponse, Server } from "http"; +import { TwakeServiceProvider } from "../../framework"; + +export default interface PhpNodeAPI extends TwakeServiceProvider { + accessControl( + request: FastifyRequest, + server: FastifyInstance, + ): Promise; + register(parameters: { method: string; url: string; handler: RouteHandlerMethod }): void; +} diff --git a/twake/backend/node/src/core/platform/services/push/api.ts b/twake/backend/node/src/core/platform/services/push/api.ts new file mode 100644 index 00000000..08d52134 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/push/api.ts @@ -0,0 +1,10 @@ +import { TwakeServiceProvider } from "../../framework"; +import { PushMessageNotification, PushMessageOptions } from "./types"; + +export interface PushServiceAPI extends TwakeServiceProvider { + push( + devices: string[], + notification: PushMessageNotification, + options?: PushMessageOptions, + ): Promise; +} diff --git a/twake/backend/node/src/core/platform/services/push/connectors/connector.ts b/twake/backend/node/src/core/platform/services/push/connectors/connector.ts new file mode 100644 index 00000000..d1898849 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/push/connectors/connector.ts @@ -0,0 +1,9 @@ +import { PushMessageNotification, PushMessageOptions } from "../types"; + +export interface PushConnector { + push( + devices: string[], + notification: PushMessageNotification, + options?: PushMessageOptions, + ): Promise; +} diff --git a/twake/backend/node/src/core/platform/services/push/connectors/fcm/service.ts b/twake/backend/node/src/core/platform/services/push/connectors/fcm/service.ts new file mode 100644 index 00000000..c4082a60 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/push/connectors/fcm/service.ts @@ -0,0 +1,52 @@ +import fetch from "node-fetch"; +import { logger } from "../../../../framework"; +import { PushConfiguration, PushMessageNotification, PushMessageOptions } from "../../types"; +import { PushConnector } from "../connector"; + +export default class FcmPushConnector implements PushConnector { + name = "FcmPushConnector"; + + constructor(readonly configuration: PushConfiguration["fcm"]) {} + + async push( + devices: string[], + notification: PushMessageNotification, + options: PushMessageOptions, + ): Promise { + logger.debug(`${this.name} - Push notification to devices ${JSON.stringify(devices)}`); + + const firebaseEndpoint = this.configuration.endpoint; + const firebaseApiKey = this.configuration.key; + + const pushMessage = { + data: { + notification_data: options.notification_data, + click_action: "FLUTTER_NOTIFICATION_CLICK", + }, + notification: { ...notification, click_action: "FLUTTER_NOTIFICATION_CLICK" }, + collapse_key: options.collapse_key, + registration_ids: [...devices], + }; + + //Push to fcm + try { + const response = await fetch(firebaseEndpoint, { + method: "post", + body: JSON.stringify(pushMessage), + headers: { + "Content-Type": "application/json", + Authorization: `key=${firebaseApiKey}`, + }, + }); + if (response.status !== 200) { + logger.error(`${this.name} - Reply from FCM status code : ${response.status}`); + logger.error( + `${this.name} - JSON reply from FCM: ${JSON.stringify(await response.json())}`, + ); + } + } catch (e) { + logger.error(`${this.name} - Error while sending message to FCM`); + logger.error(e); + } + } +} diff --git a/twake/backend/node/src/core/platform/services/push/index.ts b/twake/backend/node/src/core/platform/services/push/index.ts new file mode 100644 index 00000000..c0550bec --- /dev/null +++ b/twake/backend/node/src/core/platform/services/push/index.ts @@ -0,0 +1,41 @@ +import { TwakeService, logger, ServiceName } from "../../framework"; +import { PushServiceAPI } from "./api"; +import { PushConnector } from "./connectors/connector"; +import FcmPushConnector from "./connectors/fcm/service"; +import { PushConfiguration, PushMessageNotification, PushMessageOptions } from "./types"; + +@ServiceName("push") +export default class Push extends TwakeService { + version = "1"; + name = "push"; + service: PushConnector; + + public async doInit(): Promise { + const configuration = this.configuration.get(); + if (configuration.type === "fcm") { + logger.info(`${this.name} - Use fcm connector`); + this.service = new FcmPushConnector(configuration.fcm); + } else { + logger.info(`${this.name} - Disabled`); + } + return this; + } + + async push( + devices: string[], + notification: PushMessageNotification, + options: PushMessageOptions, + ): Promise { + if (!this.service) { + return; + } + if (!devices || devices.length === 0) { + return; + } + return this.service.push(devices, notification, options); + } + + api(): PushServiceAPI { + return this; + } +} diff --git a/twake/backend/node/src/core/platform/services/push/types.ts b/twake/backend/node/src/core/platform/services/push/types.ts new file mode 100644 index 00000000..7ee5216c --- /dev/null +++ b/twake/backend/node/src/core/platform/services/push/types.ts @@ -0,0 +1,20 @@ +export type PushConfiguration = { + type: "fcm" | null; + fcm: { + endpoint: string; + key: string; + }; +}; + +export type PushMessageOptions = { + notification_data?: any; + collapse_key?: string; +}; + +export type PushMessageNotification = { + title: string; + body: string; + sound?: string; + badge?: number; + click_action?: "FLUTTER_NOTIFICATION_CLICK"; +}; diff --git a/twake/backend/node/src/core/platform/services/realtime/api.ts b/twake/backend/node/src/core/platform/services/realtime/api.ts new file mode 100644 index 00000000..9b3c4a96 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/realtime/api.ts @@ -0,0 +1,78 @@ +import { TwakeServiceProvider } from "../../framework"; +import { WebSocketUser, WebSocket } from "../../services/websocket/types"; +import RealtimeEntityManager from "./services/entity-manager"; +import { RealtimeEntityEvent } from "./types"; + +export interface RealtimeServiceAPI extends TwakeServiceProvider { + /** + * Get the realtime event bus instance + */ + getBus(): RealtimeEventBus; + + /** + * Get the room manager + */ + getRoomManager(): RealtimeRoomManager; + + /** + * Get the entity manager + */ + getEntityManager(): RealtimeEntityManager; + + /** + * Create a token for a room + */ + sign(items: { room: string }[], userId: string): { room: string; token: string }[]; +} + +export interface RealtimeRoomManager { + /** + * Get the number of connected users in the given room + * @param room name of the room + */ + getConnectedUsers(room: string): number; + + /** + * Add the user to a room + * + * @param websocket + * @param room + * @param user + */ + join(websocket: WebSocket, room: string, user: WebSocketUser): void; + + /** + * Remove the user from a room + * + * @param websocket + * @param room + * @param user + */ + leave(websocket: WebSocket, room: string, user: WebSocketUser): void; + + /** + * Remove a user from all the room he joined + * + * @param websocket + * @param user + */ + leaveAll(websocket: WebSocket, user: WebSocketUser): void; +} + +export interface RealtimeEventBus { + /** + * Subscribes to a topic + * + * @param topic Topic to subscribe to + * @param listener Listener to call when event is published in the given topic + */ + subscribe(topic: string, listener: (event: RealtimeEntityEvent) => void): this; + + /** + * Publish event in a topic + * + * @param topic Topic to publish event to + * @param event Event to publish + */ + publish(topic: string, event: RealtimeEntityEvent): boolean; +} diff --git a/twake/backend/node/src/core/platform/services/realtime/bus.ts b/twake/backend/node/src/core/platform/services/realtime/bus.ts new file mode 100644 index 00000000..1ae54fbd --- /dev/null +++ b/twake/backend/node/src/core/platform/services/realtime/bus.ts @@ -0,0 +1,22 @@ +/** + * EventBus is used internally to exchange events between decorators and realtime manager + */ +import { EventEmitter } from "events"; +import { RealtimeEventBus } from "./api"; +import { RealtimeEntityEvent } from "./types"; + +class WebsocketEventBus extends EventEmitter implements RealtimeEventBus { + constructor() { + super(); + } + + subscribe(topic: string, listener: (event: RealtimeEntityEvent) => void): this { + return this.on(topic, listener); + } + + publish(topic: string, event: RealtimeEntityEvent): boolean { + return this.emit(topic, event); + } +} + +export const websocketEventBus = new WebsocketEventBus(); diff --git a/twake/backend/node/src/core/platform/services/realtime/index.ts b/twake/backend/node/src/core/platform/services/realtime/index.ts new file mode 100644 index 00000000..9cc94ee5 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/realtime/index.ts @@ -0,0 +1,76 @@ +import { Consumes, ServiceName, TwakeService } from "../../framework"; +import { SkipCLI } from "../../framework/decorators/skip"; +import { localEventBus } from "../../framework/event-bus"; +import WebSocketAPI from "../../services/websocket/provider"; +import AuthService from "../auth/provider"; +import { RealtimeEventBus, RealtimeRoomManager, RealtimeServiceAPI } from "./api"; +import { websocketEventBus } from "./bus"; +import RealtimeEntityManager from "./services/entity-manager"; +import RoomManagerImpl from "./services/room-manager"; +import { RealtimeBaseBusEvent, RealtimeLocalBusEvent } from "./types"; + +@Consumes(["websocket", "auth"]) +@ServiceName("realtime") +export default class RealtimeService + extends TwakeService + implements RealtimeServiceAPI +{ + private roomManager: RoomManagerImpl; + private entityManager: RealtimeEntityManager; + private auth: AuthService; + version = "1"; + + api(): RealtimeServiceAPI { + return this; + } + + @SkipCLI() + async doStart(): Promise { + const ws = this.context.getProvider("websocket"); + this.auth = this.context.getProvider("auth"); + + this.roomManager = new RoomManagerImpl(ws, this.auth); + this.roomManager.init(); + this.entityManager = new RealtimeEntityManager(ws); + this.entityManager.init(); + + localEventBus.subscribe("realtime:event", (event: RealtimeBaseBusEvent) => { + event.data._type = event.type; + ws.getIo().to(event.room).emit("realtime:event", { name: event.room, data: event.data }); + }); + + localEventBus.subscribe("realtime:publish", (data: RealtimeLocalBusEvent) => { + this.getBus().publish(data.topic, data.event); + }); + + return this; + } + + getBus(): RealtimeEventBus { + return websocketEventBus; + } + + getRoomManager(): RealtimeRoomManager { + return this.roomManager; + } + + getEntityManager(): RealtimeEntityManager { + return this.entityManager; + } + + sign(items: { room: string }[], sub: string) { + return items.map(item => { + const token = this.auth.sign({ + sub, + name: item.room, + //Fixme, reduce this number but also in frontend reload the websocket token after this ends + iat: Math.round(new Date().getTime() / 1000) + 60 * 60 * 24 * 31, + nbf: Math.round(new Date().getTime() / 1000) - 60, + }); + return { + ...item, + token, + }; + }); + } +} diff --git a/twake/backend/node/src/core/platform/services/realtime/services/entity-manager.ts b/twake/backend/node/src/core/platform/services/realtime/services/entity-manager.ts new file mode 100644 index 00000000..49c5a14b --- /dev/null +++ b/twake/backend/node/src/core/platform/services/realtime/services/entity-manager.ts @@ -0,0 +1,54 @@ +import { logger } from "../../../framework/logger"; +import { RealtimeEntityActionType, RealtimeEntityEvent } from "../types"; +import WebSocketAPI from "../../../services/websocket/provider"; +import { websocketEventBus } from "../bus"; + +const REALTIME_RESOURCE = "realtime:resource"; + +export default class RealtimeEntityManager { + constructor(private ws: WebSocketAPI) {} + + init(): void { + websocketEventBus.subscribe(RealtimeEntityActionType.Created, event => { + this.pushResourceEvent(event, RealtimeEntityActionType.Created); + }); + + websocketEventBus.subscribe(RealtimeEntityActionType.Updated, event => { + this.pushResourceEvent(event, RealtimeEntityActionType.Updated); + }); + + websocketEventBus.subscribe(RealtimeEntityActionType.Deleted, event => { + this.pushResourceEvent(event, RealtimeEntityActionType.Deleted); + }); + + websocketEventBus.subscribe(RealtimeEntityActionType.Saved, event => { + this.pushResourceEvent(event, RealtimeEntityActionType.Saved); + }); + + websocketEventBus.subscribe(RealtimeEntityActionType.Event, event => { + this.pushResourceEvent(event, RealtimeEntityActionType.Event); + }); + } + + private pushResourceEvent( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + event: RealtimeEntityEvent, + action: RealtimeEntityActionType, + ): void { + event.room.path.forEach(path => { + logger.info(`Pushing ${action} entity to room ${path}`); + const message: unknown = { + action, + room: path, + type: event.type, + path: event.resourcePath, + resource: event.entity, + }; + if (logger.isLevelEnabled("debug")) { + logger.debug(`Entity to push to room ${path}: %o`, message); + } + + this.ws.getIo().to(path).emit(REALTIME_RESOURCE, message); + }); + } +} diff --git a/twake/backend/node/src/core/platform/services/realtime/services/index.ts b/twake/backend/node/src/core/platform/services/realtime/services/index.ts new file mode 100644 index 00000000..28041086 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/realtime/services/index.ts @@ -0,0 +1,2 @@ +export * from "./entity-manager"; +export * from "./room-manager"; diff --git a/twake/backend/node/src/core/platform/services/realtime/services/room-manager.ts b/twake/backend/node/src/core/platform/services/realtime/services/room-manager.ts new file mode 100644 index 00000000..c8cdb0ed --- /dev/null +++ b/twake/backend/node/src/core/platform/services/realtime/services/room-manager.ts @@ -0,0 +1,165 @@ +import { logger } from "../../../framework/logger"; +import { + JoinLeaveRoomError, + JoinLeaveRoomSuccess, + JoinRoomEvent, + LeaveRoomEvent, + ClientEvent, + WebsocketRoomSignature, +} from "../types"; +import { RealtimeRoomManager } from "../api"; +import WebSocketAPI from "../../../services/websocket/provider"; +import { WebSocketUser, WebSocket } from "../../../services/websocket/types"; +import AuthService from "../../auth/provider"; + +export default class RoomManager implements RealtimeRoomManager { + constructor(private ws: WebSocketAPI, private auth: AuthService) {} + + init(): void { + this.ws.onUserConnected(event => { + logger.info(`User ${event.user.id} is connected`); + + event.socket.on("realtime:join", async (joinEvent: JoinRoomEvent) => { + const canJoin = + joinEvent.name.indexOf("previous::") === 0 || //Compatibility with old collections + (await this.userCanJoinRoom(event.user, joinEvent)); + + if (canJoin) { + this.join(event.socket, joinEvent.name, event.user); + } else { + this.sendError("join", event.socket, { + name: joinEvent.name, + message: "User is not authorized to join room", + }); + } + }); + + event.socket.on("realtime:leave", (leaveEvent: LeaveRoomEvent) => { + this.leave(event.socket, leaveEvent.name, event.user); + }); + + event.socket.on("realtime:event", async (clientEvent: ClientEvent) => { + const canEmit = + clientEvent.name.indexOf("previous::") === 0 || //Compatibility with old collections + (await this.userCanEmitInRoom(event.user, clientEvent)); + if (canEmit) { + this.sendEvent(clientEvent.name, clientEvent.data); + } else { + this.sendError("event", event.socket, { + name: clientEvent.name, + message: "User is not authorized to emit in this room", + }); + } + }); + }); + + this.ws.onUserDisconnected(event => { + logger.info(`User ${event.user.id} is disconnected`); + this.leaveAll(event.socket, event.user); + }); + } + + getConnectedUsers(room: string): number { + if (this.ws.getIo().sockets.adapter.rooms.has(room)) { + return this.ws.getIo().sockets.adapter.rooms.get(room).entries.length; + } + + return 0; + } + + /** + * Check of the user can join room + * + * @param user + * @param joinEvent + * @return Promise true if can join, false otherwise. Never rejects. + */ + async userCanJoinRoom(user: WebSocketUser, joinEvent: JoinRoomEvent): Promise { + logger.info(`Checking if user ${user.id} can join room ${joinEvent.name} with token`); + + try { + //Public rooms we just check the user is logged in + if ( + joinEvent.name.startsWith("/users/online") || //User online room + joinEvent.name.startsWith("/users/") || //User update room + joinEvent.name === "/ping" + ) { + return !!this.auth.verifyToken(joinEvent.token)?.sub; + } + + //Retro-compatibility for mobile up to february 2021 (to remove after this date) + if (joinEvent.token === "twake") return true; + + const signature = this.auth.verifyTokenObject(joinEvent.token); + + return ( + signature && + signature.name === joinEvent.name && + signature.sub === user.id && + signature.iat > Math.round(new Date().getTime() / 1000) + ); + } catch (err) { + console.log(err); + return false; + } + } + + userCanEmitInRoom = this.userCanJoinRoom; + + async join(websocket: WebSocket, room: string, user: WebSocketUser): Promise { + logger.info(`User ${user.id} is joining room ${room}`); + + try { + await websocket.join(room); + } catch (err) { + if (err) { + logger.error(`Error while joining room ${room}`, err); + this.sendError("join", websocket, { + name: room, + message: "Error while joining room", + }); + return; + } + } + + this.sendSuccess("join", websocket, { name: room }); + logger.info(`User ${user.id} joined room ${room}`); + } + + async leave(websocket: WebSocket, room: string, user: WebSocketUser): Promise { + logger.info(`User ${user.id} is leaving room ${room}`); + + try { + await websocket.leave(room); + } catch (err) { + if (err) { + logger.error(`Error while leaving room ${room}`, err); + this.sendError("leave", websocket, { + name: room, + message: "Error while leaving room", + }); + return; + } + } + + this.sendSuccess("leave", websocket, { name: room }); + logger.info(`User ${user.id} left room ${room}`); + } + + leaveAll(websocket: WebSocket, user: WebSocketUser): void { + logger.info(`Leaving rooms for user ${user.id}`); + websocket.rooms.forEach(room => websocket.leave(room)); + } + + sendError(event: string, websocket: WebSocket, error: JoinLeaveRoomError): void { + websocket.emit(`realtime:${event}:error`, error); + } + + sendSuccess(event: string, websocket: WebSocket, success: JoinLeaveRoomSuccess): void { + websocket.emit(`realtime:${event}:success`, success); + } + + sendEvent(path: string, data: any): void { + this.ws.getIo().to(path).emit("realtime:event", { name: path, data: data }); + } +} diff --git a/twake/backend/node/src/core/platform/services/realtime/types.ts b/twake/backend/node/src/core/platform/services/realtime/types.ts new file mode 100644 index 00000000..0c65b111 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/realtime/types.ts @@ -0,0 +1,83 @@ +import { EntityOperationResult } from "../../framework/api/crud-service"; + +export enum RealtimeEntityActionType { + Created = "created", + Saved = "saved", + Updated = "updated", + Deleted = "deleted", + Event = "event", +} + +export interface WebsocketRoomSignature { + name: string; //Ws room name + sub: string; //User id + iat: number; //Deadline +} + +export class ResourcePath { + constructor(readonly path: string[] = ["/"], readonly name: string = "default") {} + + static default(): ResourcePath { + return new ResourcePath(); + } + + static get(path: string | string[]): ResourcePath { + return new ResourcePath(typeof path === "string" ? [path] : path); + } +} +export class RealtimeEntityEvent { + // the type of the resource + type: string; + // the room to push the resource to + room: ResourcePath; + // the unique full path of the resource, ie where we can get it + resourcePath: string | null; + // the input resource + entity: Entity; + // the action result which fired this event + result: EntityOperationResult | null; +} + +export class RealtimeApplicationEvent { + action: "configure" | "close_configure"; + application: unknown; + form: unknown; + hidden_data: unknown; +} + +export class RealtimeBaseBusEvent { + room: string; + type: string; + data: T; +} + +export class RealtimeLocalBusEvent { + event: RealtimeEntityEvent; + topic: string; +} + +export class JoinRoomEvent { + name: string; + token?: string; +} + +export class LeaveRoomEvent { + name: string; +} + +export class ClientEvent { + name: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data: any; +} + +export interface JoinLeaveRoomError { + name: string; + message?: string; + type?: string; +} + +export interface JoinLeaveRoomSuccess { + name: string; + message?: string; +} diff --git a/twake/backend/node/src/core/platform/services/search/adapters/abstract.ts b/twake/backend/node/src/core/platform/services/search/adapters/abstract.ts new file mode 100644 index 00000000..1dd64b48 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/search/adapters/abstract.ts @@ -0,0 +1,47 @@ +/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-unused-vars */ +import { ListResult } from "../../../framework/api/crud-service"; +import { FindFilter } from "../../database/services/orm/repository/repository"; +import { + ColumnDefinition, + EntityDefinition, + EntityTarget, + FindOptions, + IndexedEntity, + SearchAdapterInterface, +} from "../api"; + +type indexColumns = { [name: string]: ColumnDefinition }; + +export class SearchAdapter implements SearchAdapterInterface { + private createdIndexes: string[] = []; + + protected async ensureIndex( + entityDefinition: EntityDefinition, + columns: indexColumns, + createIndex: (arg0: EntityDefinition, arg1: indexColumns) => any, + ) { + const index = entityDefinition.name; + if (!this.createdIndexes.includes(index)) { + this.createdIndexes.push(index); + await createIndex(entityDefinition, columns); + } + } + + connect(): Promise { + throw new Error("Method not implemented."); + } + upsert(entities: any[]): Promise { + throw new Error("Method not implemented."); + } + remove(entities: any[]): Promise { + throw new Error("Method not implemented."); + } + search( + table: string, + entityType: EntityTarget, + filters: FindFilter, + options: FindOptions, + ): Promise> { + throw new Error("Method not implemented."); + } +} diff --git a/twake/backend/node/src/core/platform/services/search/adapters/ascii-folder.ts b/twake/backend/node/src/core/platform/services/search/adapters/ascii-folder.ts new file mode 100644 index 00000000..b784b50e --- /dev/null +++ b/twake/backend/node/src/core/platform/services/search/adapters/ascii-folder.ts @@ -0,0 +1,1297 @@ +/** + * ascii-folder.js + * https://github.com/mplatt/fold-to-ascii-js + * + * This is a JavaScript port of the Apache Lucene ASCII Folding Filter. + * + * The Apache Lucene ASCII Folding Filter is licensed to the Apache Software + * Foundation (ASF) under one or more contributor license agreements. See the + * NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You 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. + */ +class ASCIIFolder { + static foldReplacing(str = "", replacement = ""): string { + return this._fold(str, () => replacement); + } + + static foldMaintaining(str = ""): string { + return this._fold(str, (char: string) => char); + } + + static _fold(str: string, fallback: (character: string) => string): string { + if (str === null) return ""; + + if (typeof str === "number") return "" + str; + + if (typeof str !== "string") throw new Error("Invalid input data type"); + + return str + .split("") + .map(character => { + if (character.charCodeAt(0) < 128) { + return character; + } else { + const replacement = this.mapping.get(character.charCodeAt(0)); + return replacement === undefined ? fallback(character) : replacement; + } + }) + .join(""); + } + + private static mapping = new Map([ + [0xc0, "A"], + [0xc1, "A"], + [0xc2, "A"], + [0xc3, "A"], + [0xc4, "A"], + [0xc5, "A"], + [0x100, "A"], + [0x102, "A"], + [0x104, "A"], + [0x18f, "A"], + [0x1cd, "A"], + [0x1de, "A"], + [0x1e0, "A"], + [0x1fa, "A"], + [0x200, "A"], + [0x202, "A"], + [0x226, "A"], + [0x23a, "A"], + [0x1d00, "A"], + [0x1e00, "A"], + [0x1ea0, "A"], + [0x1ea2, "A"], + [0x1ea4, "A"], + [0x1ea6, "A"], + [0x1ea8, "A"], + [0x1eaa, "A"], + [0x1eac, "A"], + [0x1eae, "A"], + [0x1eb0, "A"], + [0x1eb2, "A"], + [0x1eb4, "A"], + [0x1eb6, "A"], + [0x24b6, "A"], + [0xff21, "A"], + [0xe0, "a"], + [0xe1, "a"], + [0xe2, "a"], + [0xe3, "a"], + [0xe4, "a"], + [0xe5, "a"], + [0x101, "a"], + [0x103, "a"], + [0x105, "a"], + [0x1ce, "a"], + [0x1df, "a"], + [0x1e1, "a"], + [0x1fb, "a"], + [0x201, "a"], + [0x203, "a"], + [0x227, "a"], + [0x250, "a"], + [0x259, "a"], + [0x25a, "a"], + [0x1d8f, "a"], + [0x1d95, "a"], + [0x1e01, "a"], + [0x1e9a, "a"], + [0x1ea1, "a"], + [0x1ea3, "a"], + [0x1ea5, "a"], + [0x1ea7, "a"], + [0x1ea9, "a"], + [0x1eab, "a"], + [0x1ead, "a"], + [0x1eaf, "a"], + [0x1eb1, "a"], + [0x1eb3, "a"], + [0x1eb5, "a"], + [0x1eb7, "a"], + [0x2090, "a"], + [0x2094, "a"], + [0x24d0, "a"], + [0x2c65, "a"], + [0x2c6f, "a"], + [0xff41, "a"], + [0xa732, "AA"], + [0xc6, "AE"], + [0x1e2, "AE"], + [0x1fc, "AE"], + [0x1d01, "AE"], + [0xa734, "AO"], + [0xa736, "AU"], + [0xa738, "AV"], + [0xa73a, "AV"], + [0xa73c, "AY"], + [0x249c, "(a)"], + [0xa733, "aa"], + [0xe6, "ae"], + [0x1e3, "ae"], + [0x1fd, "ae"], + [0x1d02, "ae"], + [0xa735, "ao"], + [0xa737, "au"], + [0xa739, "av"], + [0xa73b, "av"], + [0xa73d, "ay"], + [0x181, "B"], + [0x182, "B"], + [0x243, "B"], + [0x299, "B"], + [0x1d03, "B"], + [0x1e02, "B"], + [0x1e04, "B"], + [0x1e06, "B"], + [0x24b7, "B"], + [0xff22, "B"], + [0x180, "b"], + [0x183, "b"], + [0x253, "b"], + [0x1d6c, "b"], + [0x1d80, "b"], + [0x1e03, "b"], + [0x1e05, "b"], + [0x1e07, "b"], + [0x24d1, "b"], + [0xff42, "b"], + [0x249d, "(b)"], + [0xc7, "C"], + [0x106, "C"], + [0x108, "C"], + [0x10a, "C"], + [0x10c, "C"], + [0x187, "C"], + [0x23b, "C"], + [0x297, "C"], + [0x1d04, "C"], + [0x1e08, "C"], + [0x24b8, "C"], + [0xff23, "C"], + [0xe7, "c"], + [0x107, "c"], + [0x109, "c"], + [0x10b, "c"], + [0x10d, "c"], + [0x188, "c"], + [0x23c, "c"], + [0x255, "c"], + [0x1e09, "c"], + [0x2184, "c"], + [0x24d2, "c"], + [0xa73e, "c"], + [0xa73f, "c"], + [0xff43, "c"], + [0x249e, "(c)"], + [0xd0, "D"], + [0x10e, "D"], + [0x110, "D"], + [0x189, "D"], + [0x18a, "D"], + [0x18b, "D"], + [0x1d05, "D"], + [0x1d06, "D"], + [0x1e0a, "D"], + [0x1e0c, "D"], + [0x1e0e, "D"], + [0x1e10, "D"], + [0x1e12, "D"], + [0x24b9, "D"], + [0xa779, "D"], + [0xff24, "D"], + [0xf0, "d"], + [0x10f, "d"], + [0x111, "d"], + [0x18c, "d"], + [0x221, "d"], + [0x256, "d"], + [0x257, "d"], + [0x1d6d, "d"], + [0x1d81, "d"], + [0x1d91, "d"], + [0x1e0b, "d"], + [0x1e0d, "d"], + [0x1e0f, "d"], + [0x1e11, "d"], + [0x1e13, "d"], + [0x24d3, "d"], + [0xa77a, "d"], + [0xff44, "d"], + [0x1c4, "DZ"], + [0x1f1, "DZ"], + [0x1c5, "Dz"], + [0x1f2, "Dz"], + [0x249f, "(d)"], + [0x238, "db"], + [0x1c6, "dz"], + [0x1f3, "dz"], + [0x2a3, "dz"], + [0x2a5, "dz"], + [0xc8, "E"], + [0xc9, "E"], + [0xca, "E"], + [0xcb, "E"], + [0x112, "E"], + [0x114, "E"], + [0x116, "E"], + [0x118, "E"], + [0x11a, "E"], + [0x18e, "E"], + [0x190, "E"], + [0x204, "E"], + [0x206, "E"], + [0x228, "E"], + [0x246, "E"], + [0x1d07, "E"], + [0x1e14, "E"], + [0x1e16, "E"], + [0x1e18, "E"], + [0x1e1a, "E"], + [0x1e1c, "E"], + [0x1eb8, "E"], + [0x1eba, "E"], + [0x1ebc, "E"], + [0x1ebe, "E"], + [0x1ec0, "E"], + [0x1ec2, "E"], + [0x1ec4, "E"], + [0x1ec6, "E"], + [0x24ba, "E"], + [0x2c7b, "E"], + [0xff25, "E"], + [0xe8, "e"], + [0xe9, "e"], + [0xea, "e"], + [0xeb, "e"], + [0x113, "e"], + [0x115, "e"], + [0x117, "e"], + [0x119, "e"], + [0x11b, "e"], + [0x1dd, "e"], + [0x205, "e"], + [0x207, "e"], + [0x229, "e"], + [0x247, "e"], + [0x258, "e"], + [0x25b, "e"], + [0x25c, "e"], + [0x25d, "e"], + [0x25e, "e"], + [0x29a, "e"], + [0x1d08, "e"], + [0x1d92, "e"], + [0x1d93, "e"], + [0x1d94, "e"], + [0x1e15, "e"], + [0x1e17, "e"], + [0x1e19, "e"], + [0x1e1b, "e"], + [0x1e1d, "e"], + [0x1eb9, "e"], + [0x1ebb, "e"], + [0x1ebd, "e"], + [0x1ebf, "e"], + [0x1ec1, "e"], + [0x1ec3, "e"], + [0x1ec5, "e"], + [0x1ec7, "e"], + [0x2091, "e"], + [0x24d4, "e"], + [0x2c78, "e"], + [0xff45, "e"], + [0x24a0, "(e)"], + [0x191, "F"], + [0x1e1e, "F"], + [0x24bb, "F"], + [0xa730, "F"], + [0xa77b, "F"], + [0xa7fb, "F"], + [0xff26, "F"], + [0x192, "f"], + [0x1d6e, "f"], + [0x1d82, "f"], + [0x1e1f, "f"], + [0x1e9b, "f"], + [0x24d5, "f"], + [0xa77c, "f"], + [0xff46, "f"], + [0x24a1, "(f)"], + [0xfb00, "ff"], + [0xfb03, "ffi"], + [0xfb04, "ffl"], + [0xfb01, "fi"], + [0xfb02, "fl"], + [0x11c, "G"], + [0x11e, "G"], + [0x120, "G"], + [0x122, "G"], + [0x193, "G"], + [0x1e4, "G"], + [0x1e5, "G"], + [0x1e6, "G"], + [0x1e7, "G"], + [0x1f4, "G"], + [0x262, "G"], + [0x29b, "G"], + [0x1e20, "G"], + [0x24bc, "G"], + [0xa77d, "G"], + [0xa77e, "G"], + [0xff27, "G"], + [0x11d, "g"], + [0x11f, "g"], + [0x121, "g"], + [0x123, "g"], + [0x1f5, "g"], + [0x260, "g"], + [0x261, "g"], + [0x1d77, "g"], + [0x1d79, "g"], + [0x1d83, "g"], + [0x1e21, "g"], + [0x24d6, "g"], + [0xa77f, "g"], + [0xff47, "g"], + [0x24a2, "(g)"], + [0x124, "H"], + [0x126, "H"], + [0x21e, "H"], + [0x29c, "H"], + [0x1e22, "H"], + [0x1e24, "H"], + [0x1e26, "H"], + [0x1e28, "H"], + [0x1e2a, "H"], + [0x24bd, "H"], + [0x2c67, "H"], + [0x2c75, "H"], + [0xff28, "H"], + [0x125, "h"], + [0x127, "h"], + [0x21f, "h"], + [0x265, "h"], + [0x266, "h"], + [0x2ae, "h"], + [0x2af, "h"], + [0x1e23, "h"], + [0x1e25, "h"], + [0x1e27, "h"], + [0x1e29, "h"], + [0x1e2b, "h"], + [0x1e96, "h"], + [0x24d7, "h"], + [0x2c68, "h"], + [0x2c76, "h"], + [0xff48, "h"], + [0x1f6, "HV"], + [0x24a3, "(h)"], + [0x195, "hv"], + [0xcc, "I"], + [0xcd, "I"], + [0xce, "I"], + [0xcf, "I"], + [0x128, "I"], + [0x12a, "I"], + [0x12c, "I"], + [0x12e, "I"], + [0x130, "I"], + [0x196, "I"], + [0x197, "I"], + [0x1cf, "I"], + [0x208, "I"], + [0x20a, "I"], + [0x26a, "I"], + [0x1d7b, "I"], + [0x1e2c, "I"], + [0x1e2e, "I"], + [0x1ec8, "I"], + [0x1eca, "I"], + [0x24be, "I"], + [0xa7fe, "I"], + [0xff29, "I"], + [0xec, "i"], + [0xed, "i"], + [0xee, "i"], + [0xef, "i"], + [0x129, "i"], + [0x12b, "i"], + [0x12d, "i"], + [0x12f, "i"], + [0x131, "i"], + [0x1d0, "i"], + [0x209, "i"], + [0x20b, "i"], + [0x268, "i"], + [0x1d09, "i"], + [0x1d62, "i"], + [0x1d7c, "i"], + [0x1d96, "i"], + [0x1e2d, "i"], + [0x1e2f, "i"], + [0x1ec9, "i"], + [0x1ecb, "i"], + [0x2071, "i"], + [0x24d8, "i"], + [0xff49, "i"], + [0x132, "IJ"], + [0x24a4, "(i)"], + [0x133, "ij"], + [0x134, "J"], + [0x248, "J"], + [0x1d0a, "J"], + [0x24bf, "J"], + [0xff2a, "J"], + [0x135, "j"], + [0x1f0, "j"], + [0x237, "j"], + [0x249, "j"], + [0x25f, "j"], + [0x284, "j"], + [0x29d, "j"], + [0x24d9, "j"], + [0x2c7c, "j"], + [0xff4a, "j"], + [0x24a5, "(j)"], + [0x136, "K"], + [0x198, "K"], + [0x1e8, "K"], + [0x1d0b, "K"], + [0x1e30, "K"], + [0x1e32, "K"], + [0x1e34, "K"], + [0x24c0, "K"], + [0x2c69, "K"], + [0xa740, "K"], + [0xa742, "K"], + [0xa744, "K"], + [0xff2b, "K"], + [0x137, "k"], + [0x199, "k"], + [0x1e9, "k"], + [0x29e, "k"], + [0x1d84, "k"], + [0x1e31, "k"], + [0x1e33, "k"], + [0x1e35, "k"], + [0x24da, "k"], + [0x2c6a, "k"], + [0xa741, "k"], + [0xa743, "k"], + [0xa745, "k"], + [0xff4b, "k"], + [0x24a6, "(k)"], + [0x139, "L"], + [0x13b, "L"], + [0x13d, "L"], + [0x13f, "L"], + [0x141, "L"], + [0x23d, "L"], + [0x29f, "L"], + [0x1d0c, "L"], + [0x1e36, "L"], + [0x1e38, "L"], + [0x1e3a, "L"], + [0x1e3c, "L"], + [0x24c1, "L"], + [0x2c60, "L"], + [0x2c62, "L"], + [0xa746, "L"], + [0xa748, "L"], + [0xa780, "L"], + [0xff2c, "L"], + [0x13a, "l"], + [0x13c, "l"], + [0x13e, "l"], + [0x140, "l"], + [0x142, "l"], + [0x19a, "l"], + [0x234, "l"], + [0x26b, "l"], + [0x26c, "l"], + [0x26d, "l"], + [0x1d85, "l"], + [0x1e37, "l"], + [0x1e39, "l"], + [0x1e3b, "l"], + [0x1e3d, "l"], + [0x24db, "l"], + [0x2c61, "l"], + [0xa747, "l"], + [0xa749, "l"], + [0xa781, "l"], + [0xff4c, "l"], + [0x1c7, "LJ"], + [0x1efa, "LL"], + [0x1c8, "Lj"], + [0x24a7, "(l)"], + [0x1c9, "lj"], + [0x1efb, "ll"], + [0x2aa, "ls"], + [0x2ab, "lz"], + [0x19c, "M"], + [0x1d0d, "M"], + [0x1e3e, "M"], + [0x1e40, "M"], + [0x1e42, "M"], + [0x24c2, "M"], + [0x2c6e, "M"], + [0xa7fd, "M"], + [0xa7ff, "M"], + [0xff2d, "M"], + [0x26f, "m"], + [0x270, "m"], + [0x271, "m"], + [0x1d6f, "m"], + [0x1d86, "m"], + [0x1e3f, "m"], + [0x1e41, "m"], + [0x1e43, "m"], + [0x24dc, "m"], + [0xff4d, "m"], + [0x24a8, "(m)"], + [0xd1, "N"], + [0x143, "N"], + [0x145, "N"], + [0x147, "N"], + [0x14a, "N"], + [0x19d, "N"], + [0x1f8, "N"], + [0x220, "N"], + [0x274, "N"], + [0x1d0e, "N"], + [0x1e44, "N"], + [0x1e46, "N"], + [0x1e48, "N"], + [0x1e4a, "N"], + [0x24c3, "N"], + [0xff2e, "N"], + [0xf1, "n"], + [0x144, "n"], + [0x146, "n"], + [0x148, "n"], + [0x149, "n"], + [0x14b, "n"], + [0x19e, "n"], + [0x1f9, "n"], + [0x235, "n"], + [0x272, "n"], + [0x273, "n"], + [0x1d70, "n"], + [0x1d87, "n"], + [0x1e45, "n"], + [0x1e47, "n"], + [0x1e49, "n"], + [0x1e4b, "n"], + [0x207f, "n"], + [0x24dd, "n"], + [0xff4e, "n"], + [0x1ca, "NJ"], + [0x1cb, "Nj"], + [0x24a9, "(n)"], + [0x1cc, "nj"], + [0xd2, "O"], + [0xd3, "O"], + [0xd4, "O"], + [0xd5, "O"], + [0xd6, "O"], + [0xd8, "O"], + [0x14c, "O"], + [0x14e, "O"], + [0x150, "O"], + [0x186, "O"], + [0x19f, "O"], + [0x1a0, "O"], + [0x1d1, "O"], + [0x1ea, "O"], + [0x1ec, "O"], + [0x1fe, "O"], + [0x20c, "O"], + [0x20e, "O"], + [0x22a, "O"], + [0x22c, "O"], + [0x22e, "O"], + [0x230, "O"], + [0x1d0f, "O"], + [0x1d10, "O"], + [0x1e4c, "O"], + [0x1e4e, "O"], + [0x1e50, "O"], + [0x1e52, "O"], + [0x1ecc, "O"], + [0x1ece, "O"], + [0x1ed0, "O"], + [0x1ed2, "O"], + [0x1ed4, "O"], + [0x1ed6, "O"], + [0x1ed8, "O"], + [0x1eda, "O"], + [0x1edc, "O"], + [0x1ede, "O"], + [0x1ee0, "O"], + [0x1ee2, "O"], + [0x24c4, "O"], + [0xa74a, "O"], + [0xa74c, "O"], + [0xff2f, "O"], + [0xf2, "o"], + [0xf3, "o"], + [0xf4, "o"], + [0xf5, "o"], + [0xf6, "o"], + [0xf8, "o"], + [0x14d, "o"], + [0x14f, "o"], + [0x151, "o"], + [0x1a1, "o"], + [0x1d2, "o"], + [0x1eb, "o"], + [0x1ed, "o"], + [0x1ff, "o"], + [0x20d, "o"], + [0x20f, "o"], + [0x22b, "o"], + [0x22d, "o"], + [0x22f, "o"], + [0x231, "o"], + [0x254, "o"], + [0x275, "o"], + [0x1d16, "o"], + [0x1d17, "o"], + [0x1d97, "o"], + [0x1e4d, "o"], + [0x1e4f, "o"], + [0x1e51, "o"], + [0x1e53, "o"], + [0x1ecd, "o"], + [0x1ecf, "o"], + [0x1ed1, "o"], + [0x1ed3, "o"], + [0x1ed5, "o"], + [0x1ed7, "o"], + [0x1ed9, "o"], + [0x1edb, "o"], + [0x1edd, "o"], + [0x1edf, "o"], + [0x1ee1, "o"], + [0x1ee3, "o"], + [0x2092, "o"], + [0x24de, "o"], + [0x2c7a, "o"], + [0xa74b, "o"], + [0xa74d, "o"], + [0xff4f, "o"], + [0x152, "OE"], + [0x276, "OE"], + [0xa74e, "OO"], + [0x222, "OU"], + [0x1d15, "OU"], + [0x24aa, "(o)"], + [0x153, "oe"], + [0x1d14, "oe"], + [0xa74f, "oo"], + [0x223, "ou"], + [0x1a4, "P"], + [0x1d18, "P"], + [0x1e54, "P"], + [0x1e56, "P"], + [0x24c5, "P"], + [0x2c63, "P"], + [0xa750, "P"], + [0xa752, "P"], + [0xa754, "P"], + [0xff30, "P"], + [0x1a5, "p"], + [0x1d71, "p"], + [0x1d7d, "p"], + [0x1d88, "p"], + [0x1e55, "p"], + [0x1e57, "p"], + [0x24df, "p"], + [0xa751, "p"], + [0xa753, "p"], + [0xa755, "p"], + [0xa7fc, "p"], + [0xff50, "p"], + [0x24ab, "(p)"], + [0x24a, "Q"], + [0x24c6, "Q"], + [0xa756, "Q"], + [0xa758, "Q"], + [0xff31, "Q"], + [0x138, "q"], + [0x24b, "q"], + [0x2a0, "q"], + [0x24e0, "q"], + [0xa757, "q"], + [0xa759, "q"], + [0xff51, "q"], + [0x24ac, "(q)"], + [0x239, "qp"], + [0x154, "R"], + [0x156, "R"], + [0x158, "R"], + [0x210, "R"], + [0x212, "R"], + [0x24c, "R"], + [0x280, "R"], + [0x281, "R"], + [0x1d19, "R"], + [0x1d1a, "R"], + [0x1e58, "R"], + [0x1e5a, "R"], + [0x1e5c, "R"], + [0x1e5e, "R"], + [0x24c7, "R"], + [0x2c64, "R"], + [0xa75a, "R"], + [0xa782, "R"], + [0xff32, "R"], + [0x155, "r"], + [0x157, "r"], + [0x159, "r"], + [0x211, "r"], + [0x213, "r"], + [0x24d, "r"], + [0x27c, "r"], + [0x27d, "r"], + [0x27e, "r"], + [0x27f, "r"], + [0x1d63, "r"], + [0x1d72, "r"], + [0x1d73, "r"], + [0x1d89, "r"], + [0x1e59, "r"], + [0x1e5b, "r"], + [0x1e5d, "r"], + [0x1e5f, "r"], + [0x24e1, "r"], + [0xa75b, "r"], + [0xa783, "r"], + [0xff52, "r"], + [0x24ad, "(r)"], + [0x15a, "S"], + [0x15c, "S"], + [0x15e, "S"], + [0x160, "S"], + [0x218, "S"], + [0x1e60, "S"], + [0x1e62, "S"], + [0x1e64, "S"], + [0x1e66, "S"], + [0x1e68, "S"], + [0x24c8, "S"], + [0xa731, "S"], + [0xa785, "S"], + [0xff33, "S"], + [0x15b, "s"], + [0x15d, "s"], + [0x15f, "s"], + [0x161, "s"], + [0x17f, "s"], + [0x219, "s"], + [0x23f, "s"], + [0x282, "s"], + [0x1d74, "s"], + [0x1d8a, "s"], + [0x1e61, "s"], + [0x1e63, "s"], + [0x1e65, "s"], + [0x1e67, "s"], + [0x1e69, "s"], + [0x1e9c, "s"], + [0x1e9d, "s"], + [0x24e2, "s"], + [0xa784, "s"], + [0xff53, "s"], + [0x1e9e, "SS"], + [0x24ae, "(s)"], + [0xdf, "ss"], + [0xfb06, "st"], + [0x162, "T"], + [0x164, "T"], + [0x166, "T"], + [0x1ac, "T"], + [0x1ae, "T"], + [0x21a, "T"], + [0x23e, "T"], + [0x1d1b, "T"], + [0x1e6a, "T"], + [0x1e6c, "T"], + [0x1e6e, "T"], + [0x1e70, "T"], + [0x24c9, "T"], + [0xa786, "T"], + [0xff34, "T"], + [0x163, "t"], + [0x165, "t"], + [0x167, "t"], + [0x1ab, "t"], + [0x1ad, "t"], + [0x21b, "t"], + [0x236, "t"], + [0x287, "t"], + [0x288, "t"], + [0x1d75, "t"], + [0x1e6b, "t"], + [0x1e6d, "t"], + [0x1e6f, "t"], + [0x1e71, "t"], + [0x1e97, "t"], + [0x24e3, "t"], + [0x2c66, "t"], + [0xff54, "t"], + [0xde, "TH"], + [0xa766, "TH"], + [0xa728, "TZ"], + [0x24af, "(t)"], + [0x2a8, "tc"], + [0xfe, "th"], + [0x1d7a, "th"], + [0xa767, "th"], + [0x2a6, "ts"], + [0xa729, "tz"], + [0xd9, "U"], + [0xda, "U"], + [0xdb, "U"], + [0xdc, "U"], + [0x168, "U"], + [0x16a, "U"], + [0x16c, "U"], + [0x16e, "U"], + [0x170, "U"], + [0x172, "U"], + [0x1af, "U"], + [0x1d3, "U"], + [0x1d5, "U"], + [0x1d7, "U"], + [0x1d9, "U"], + [0x1db, "U"], + [0x214, "U"], + [0x216, "U"], + [0x244, "U"], + [0x1d1c, "U"], + [0x1d7e, "U"], + [0x1e72, "U"], + [0x1e74, "U"], + [0x1e76, "U"], + [0x1e78, "U"], + [0x1e7a, "U"], + [0x1ee4, "U"], + [0x1ee6, "U"], + [0x1ee8, "U"], + [0x1eea, "U"], + [0x1eec, "U"], + [0x1eee, "U"], + [0x1ef0, "U"], + [0x24ca, "U"], + [0xff35, "U"], + [0xf9, "u"], + [0xfa, "u"], + [0xfb, "u"], + [0xfc, "u"], + [0x169, "u"], + [0x16b, "u"], + [0x16d, "u"], + [0x16f, "u"], + [0x171, "u"], + [0x173, "u"], + [0x1b0, "u"], + [0x1d4, "u"], + [0x1d6, "u"], + [0x1d8, "u"], + [0x1da, "u"], + [0x1dc, "u"], + [0x215, "u"], + [0x217, "u"], + [0x289, "u"], + [0x1d64, "u"], + [0x1d99, "u"], + [0x1e73, "u"], + [0x1e75, "u"], + [0x1e77, "u"], + [0x1e79, "u"], + [0x1e7b, "u"], + [0x1ee5, "u"], + [0x1ee7, "u"], + [0x1ee9, "u"], + [0x1eeb, "u"], + [0x1eed, "u"], + [0x1eef, "u"], + [0x1ef1, "u"], + [0x24e4, "u"], + [0xff55, "u"], + [0x24b0, "(u)"], + [0x1d6b, "ue"], + [0x1b2, "V"], + [0x245, "V"], + [0x1d20, "V"], + [0x1e7c, "V"], + [0x1e7e, "V"], + [0x1efc, "V"], + [0x24cb, "V"], + [0xa75e, "V"], + [0xa768, "V"], + [0xff36, "V"], + [0x28b, "v"], + [0x28c, "v"], + [0x1d65, "v"], + [0x1d8c, "v"], + [0x1e7d, "v"], + [0x1e7f, "v"], + [0x24e5, "v"], + [0x2c71, "v"], + [0x2c74, "v"], + [0xa75f, "v"], + [0xff56, "v"], + [0xa760, "VY"], + [0x24b1, "(v)"], + [0xa761, "vy"], + [0x174, "W"], + [0x1f7, "W"], + [0x1d21, "W"], + [0x1e80, "W"], + [0x1e82, "W"], + [0x1e84, "W"], + [0x1e86, "W"], + [0x1e88, "W"], + [0x24cc, "W"], + [0x2c72, "W"], + [0xff37, "W"], + [0x175, "w"], + [0x1bf, "w"], + [0x28d, "w"], + [0x1e81, "w"], + [0x1e83, "w"], + [0x1e85, "w"], + [0x1e87, "w"], + [0x1e89, "w"], + [0x1e98, "w"], + [0x24e6, "w"], + [0x2c73, "w"], + [0xff57, "w"], + [0x24b2, "(w)"], + [0x1e8a, "X"], + [0x1e8c, "X"], + [0x24cd, "X"], + [0xff38, "X"], + [0x1d8d, "x"], + [0x1e8b, "x"], + [0x1e8d, "x"], + [0x2093, "x"], + [0x24e7, "x"], + [0xff58, "x"], + [0x24b3, "(x)"], + [0xdd, "Y"], + [0x176, "Y"], + [0x178, "Y"], + [0x1b3, "Y"], + [0x232, "Y"], + [0x24e, "Y"], + [0x28f, "Y"], + [0x1e8e, "Y"], + [0x1ef2, "Y"], + [0x1ef4, "Y"], + [0x1ef6, "Y"], + [0x1ef8, "Y"], + [0x1efe, "Y"], + [0x24ce, "Y"], + [0xff39, "Y"], + [0xfd, "y"], + [0xff, "y"], + [0x177, "y"], + [0x1b4, "y"], + [0x233, "y"], + [0x24f, "y"], + [0x28e, "y"], + [0x1e8f, "y"], + [0x1e99, "y"], + [0x1ef3, "y"], + [0x1ef5, "y"], + [0x1ef7, "y"], + [0x1ef9, "y"], + [0x1eff, "y"], + [0x24e8, "y"], + [0xff59, "y"], + [0x24b4, "(y)"], + [0x179, "Z"], + [0x17b, "Z"], + [0x17d, "Z"], + [0x1b5, "Z"], + [0x21c, "Z"], + [0x224, "Z"], + [0x1d22, "Z"], + [0x1e90, "Z"], + [0x1e92, "Z"], + [0x1e94, "Z"], + [0x24cf, "Z"], + [0x2c6b, "Z"], + [0xa762, "Z"], + [0xff3a, "Z"], + [0x17a, "z"], + [0x17c, "z"], + [0x17e, "z"], + [0x1b6, "z"], + [0x21d, "z"], + [0x225, "z"], + [0x240, "z"], + [0x290, "z"], + [0x291, "z"], + [0x1d76, "z"], + [0x1d8e, "z"], + [0x1e91, "z"], + [0x1e93, "z"], + [0x1e95, "z"], + [0x24e9, "z"], + [0x2c6c, "z"], + [0xa763, "z"], + [0xff5a, "z"], + [0x24b5, "(z)"], + [0x2070, "0"], + [0x2080, "0"], + [0x24ea, "0"], + [0x24ff, "0"], + [0xff10, "0"], + [0xb9, "1"], + [0x2081, "1"], + [0x2460, "1"], + [0x24f5, "1"], + [0x2776, "1"], + [0x2780, "1"], + [0x278a, "1"], + [0xff11, "1"], + [0x2488, "1."], + [0x2474, "(1)"], + [0xb2, "2"], + [0x2082, "2"], + [0x2461, "2"], + [0x24f6, "2"], + [0x2777, "2"], + [0x2781, "2"], + [0x278b, "2"], + [0xff12, "2"], + [0x2489, "2."], + [0x2475, "(2)"], + [0xb3, "3"], + [0x2083, "3"], + [0x2462, "3"], + [0x24f7, "3"], + [0x2778, "3"], + [0x2782, "3"], + [0x278c, "3"], + [0xff13, "3"], + [0x248a, "3."], + [0x2476, "(3)"], + [0x2074, "4"], + [0x2084, "4"], + [0x2463, "4"], + [0x24f8, "4"], + [0x2779, "4"], + [0x2783, "4"], + [0x278d, "4"], + [0xff14, "4"], + [0x248b, "4."], + [0x2477, "(4)"], + [0x2075, "5"], + [0x2085, "5"], + [0x2464, "5"], + [0x24f9, "5"], + [0x277a, "5"], + [0x2784, "5"], + [0x278e, "5"], + [0xff15, "5"], + [0x248c, "5."], + [0x2478, "(5)"], + [0x2076, "6"], + [0x2086, "6"], + [0x2465, "6"], + [0x24fa, "6"], + [0x277b, "6"], + [0x2785, "6"], + [0x278f, "6"], + [0xff16, "6"], + [0x248d, "6."], + [0x2479, "(6)"], + [0x2077, "7"], + [0x2087, "7"], + [0x2466, "7"], + [0x24fb, "7"], + [0x277c, "7"], + [0x2786, "7"], + [0x2790, "7"], + [0xff17, "7"], + [0x248e, "7."], + [0x247a, "(7)"], + [0x2078, "8"], + [0x2088, "8"], + [0x2467, "8"], + [0x24fc, "8"], + [0x277d, "8"], + [0x2787, "8"], + [0x2791, "8"], + [0xff18, "8"], + [0x248f, "8."], + [0x247b, "(8)"], + [0x2079, "9"], + [0x2089, "9"], + [0x2468, "9"], + [0x24fd, "9"], + [0x277e, "9"], + [0x2788, "9"], + [0x2792, "9"], + [0xff19, "9"], + [0x2490, "9."], + [0x247c, "(9)"], + [0x2469, "10"], + [0x24fe, "10"], + [0x277f, "10"], + [0x2789, "10"], + [0x2793, "10"], + [0x2491, "10."], + [0x247d, "(10)"], + [0x246a, "11"], + [0x24eb, "11"], + [0x2492, "11."], + [0x247e, "(11)"], + [0x246b, "12"], + [0x24ec, "12"], + [0x2493, "12."], + [0x247f, "(12)"], + [0x246c, "13"], + [0x24ed, "13"], + [0x2494, "13."], + [0x2480, "(13)"], + [0x246d, "14"], + [0x24ee, "14"], + [0x2495, "14."], + [0x2481, "(14)"], + [0x246e, "15"], + [0x24ef, "15"], + [0x2496, "15."], + [0x2482, "(15)"], + [0x246f, "16"], + [0x24f0, "16"], + [0x2497, "16."], + [0x2483, "(16)"], + [0x2470, "17"], + [0x24f1, "17"], + [0x2498, "17."], + [0x2484, "(17)"], + [0x2471, "18"], + [0x24f2, "18"], + [0x2499, "18."], + [0x2485, "(18)"], + [0x2472, "19"], + [0x24f3, "19"], + [0x249a, "19."], + [0x2486, "(19)"], + [0x2473, "20"], + [0x24f4, "20"], + [0x249b, "20."], + [0x2487, "(20)"], + [0xab, '"'], + [0xbb, '"'], + [0x201c, '"'], + [0x201d, '"'], + [0x201e, '"'], + [0x2033, '"'], + [0x2036, '"'], + [0x275d, '"'], + [0x275e, '"'], + [0x276e, '"'], + [0x276f, '"'], + [0xff02, '"'], + [0x2018, "'"], + [0x2019, "'"], + [0x201a, "'"], + [0x201b, "'"], + [0x2032, "'"], + [0x2035, "'"], + [0x2039, "'"], + [0x203a, "'"], + [0x275b, "'"], + [0x275c, "'"], + [0xff07, "'"], + [0x2010, "-"], + [0x2011, "-"], + [0x2012, "-"], + [0x2013, "-"], + [0x2014, "-"], + [0x207b, "-"], + [0x208b, "-"], + [0xff0d, "-"], + [0x2045, "["], + [0x2772, "["], + [0xff3b, "["], + [0x2046, "]"], + [0x2773, "]"], + [0xff3d, "]"], + [0x207d, "("], + [0x208d, "("], + [0x2768, "("], + [0x276a, "("], + [0xff08, "("], + [0x2e28, "(("], + [0x207e, ")"], + [0x208e, ")"], + [0x2769, ")"], + [0x276b, ")"], + [0xff09, ")"], + [0x2e29, "))"], + [0x276c, "<"], + [0x2770, "<"], + [0xff1c, "<"], + [0x276d, ">"], + [0x2771, ">"], + [0xff1e, ">"], + [0x2774, "{"], + [0xff5b, "{"], + [0x2775, "}"], + [0xff5d, "}"], + [0x207a, "+"], + [0x208a, "+"], + [0xff0b, "+"], + [0x207c, "="], + [0x208c, "="], + [0xff1d, "="], + [0xff01, "!"], + [0x203c, "!!"], + [0x2049, "!?"], + [0xff03, "#"], + [0xff04, "$"], + [0x2052, "%"], + [0xff05, "%"], + [0xff06, "&"], + [0x204e, "*"], + [0xff0a, "*"], + [0xff0c, ","], + [0xff0e, "."], + [0x2044, "/"], + [0xff0f, "/"], + [0xff1a, ":"], + [0x204f, ";"], + [0xff1b, ";"], + [0xff1f, "?"], + [0x2047, "??"], + [0x2048, "?!"], + [0xff20, "@"], + [0xff3c, "\\"], + [0x2038, "^"], + [0xff3e, "^"], + [0xff3f, "_"], + [0x2053, "~"], + [0xff5e, "~"], + ]); +} + +export default ASCIIFolder; diff --git a/twake/backend/node/src/core/platform/services/search/adapters/elasticsearch/index.ts b/twake/backend/node/src/core/platform/services/search/adapters/elasticsearch/index.ts new file mode 100644 index 00000000..342ff301 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/search/adapters/elasticsearch/index.ts @@ -0,0 +1,304 @@ +import { Client } from "@elastic/elasticsearch"; +import { logger } from "../../../../framework"; +import _ from "lodash"; +import { + ColumnDefinition, + EntityDefinition, + EntityTarget, + FindFilter, + FindOptions, + IndexedEntity, + SearchAdapterInterface, + SearchConfiguration, +} from "../../api"; +import { SearchAdapter } from "../abstract"; +import { DatabaseServiceAPI } from "../../../database/api"; +import { getEntityDefinition, unwrapPrimarykey } from "../../api"; +import { ListResult, Paginable, Pagination } from "../../../../framework/api/crud-service"; +import { asciiFold, parsePrimaryKey, stringifyPrimaryKey } from "../utils"; +import { ApiResponse } from "@elastic/elasticsearch/lib/Transport"; +import { buildSearchQuery } from "./search"; + +type Operation = { + index?: { _index: string; _id: string }; + delete?: { _index: string; _id: string }; + [key: string]: any; +}; + +export default class ElasticSearch extends SearchAdapter implements SearchAdapterInterface { + private client: Client; + private bulkReaders = 0; + private buffer: Operation[] = []; + private name = "ElasticSearch"; + + constructor( + readonly database: DatabaseServiceAPI, + readonly configuration: SearchConfiguration["elasticsearch"], + ) { + super(); + } + + public async connect() { + try { + this.client = new Client({ + node: this.configuration.endpoint, + }); + } catch (e) { + logger.error(`Unable to connect to ElasticSearch at ${this.configuration.endpoint}`); + } + this.startBulkReader(); + } + + private async createIndex( + entity: EntityDefinition, + _columns: { [name: string]: ColumnDefinition }, + ) { + if (!entity.options?.search) { + return; + } + + const name = entity.options?.search?.index || entity.name; + const mapping = entity.options?.search?.esMapping; + + try { + await this.client.indices.get({ + index: name, + }); + logger.info(`Index "${name}" already created`); + } catch (e) { + logger.info(`Create index ${name} with mapping %o`, mapping); + + const indice = { + index: name, + body: { + settings: { + analysis: { + analyzer: { + folding: { + tokenizer: "standard", + filter: ["lowercase", "asciifolding"], + }, + }, + }, + }, + mappings: { ...mapping, _source: { enabled: false } }, + }, + }; + + const rep = await this.client.indices.create(indice, { ignore: [400] }); + + if (rep.statusCode !== 200) { + logger.error(`${this.name} - ${JSON.stringify(rep.body)}`); + } + } + } + + public async upsert(entities: any[]) { + for (const entity of entities) { + const { entityDefinition, columnsDefinition } = getEntityDefinition(entity); + const pkColumns = unwrapPrimarykey(entityDefinition); + + await this.ensureIndex(entityDefinition, columnsDefinition, this.createIndex.bind(this)); + + if (!entityDefinition.options?.search) { + return; + } + + if ( + entityDefinition.options.search.shouldUpdate && + !entityDefinition.options.search.shouldUpdate(entity) + ) { + return; + } + + if (!entityDefinition.options?.search?.source) { + logger.info(`Unable to do operation upsert to elasticsearch for doc ${entity}`); + return; + } + + const body = { + ..._.pick(entity, ...pkColumns), + ...entityDefinition.options.search.source(entity), + }; + + Object.keys(entityDefinition.options?.search.esMapping?.properties || []).forEach( + (key: string) => { + const mapping: any = entityDefinition.options?.search?.esMapping?.properties[key]; + if (mapping.type === "text") { + body[key] = asciiFold(body[key]).toLocaleLowerCase(); + } + }, + ); + + const index = entityDefinition.options?.search?.index || entityDefinition.name; + + const record: Operation = { + index: { + _index: index, + _id: stringifyPrimaryKey(entity), + }, + ...body, + }; + + logger.info(`Add operation upsert to elasticsearch for doc ${record.id}`); + + this.buffer.push(record); + } + + this.startBulkReader(); + } + + public async remove(entities: any[]) { + for (const entity of entities) { + const { entityDefinition, columnsDefinition } = getEntityDefinition(entity); + + await this.ensureIndex(entityDefinition, columnsDefinition, this.createIndex.bind(this)); + + if (!entityDefinition.options?.search) { + return; + } + + const index = entityDefinition.options?.search?.index || entityDefinition.name; + + const record: Operation = { + delete: { + _index: index, + _id: stringifyPrimaryKey(entity), + }, + }; + + logger.info(`Add operation remove from elasticsearch for doc ${record.id}`); + + this.buffer.push(record); + } + + this.startBulkReader(); + } + + private async startBulkReader() { + if (this.bulkReaders > 0) { + return; + } + + logger.info("Start new Elasticsearch bulk reader."); + this.bulkReaders += 1; + + let buffer; + do { + await new Promise(r => + setTimeout(r, parseInt(`${this.configuration.flushInterval}`) || 3000), + ); + buffer = this.buffer; + } while (buffer.length === 0); + this.buffer = []; + + try { + await this.client.helpers.bulk({ + flushInterval: 1, + datasource: buffer, + onDocument: (doc: Operation) => { + if (doc.delete) { + logger.info( + `Operation ${"DELETE"} pushed to elasticsearch index ${doc.delete._index} (doc.id: ${ + doc.delete._id + })`, + ); + return { + delete: doc.delete, + }; + } + if (doc.index) { + logger.info( + `Operation ${"INDEX"} pushed to elasticsearch index ${doc.index._index} (doc.id: ${ + doc.index._id + })`, + ); + return { + index: doc.index, + ...doc.index, + }; + } + return null; + }, + onDrop: res => { + const doc = res.document; + logger.error( + `Operation ${ + doc.action + } was droped while pushing to elasticsearch index ${JSON.stringify( + doc.index, + )} (doc.id: ${doc.id})`, + ); + logger.error(res.error); + }, + }); + } catch (err) { + logger.error(`${this.name} - An error occured with the bulk reader`); + logger.error(err); + } + + logger.info("Elasticsearch bulk flushed."); + this.bulkReaders += -1; + + this.startBulkReader(); + } + + public async search( + _table: string, + entityType: EntityTarget, + filters: FindFilter, + options: FindOptions = {}, + ) { + const instance = new (entityType as any)(); + const { entityDefinition } = getEntityDefinition(instance); + + const { esParams, esOptions } = buildSearchQuery(entityType, filters, options); + const esParamsWithScroll = { + ...esParams, + size: parseInt(options.pagination.limitStr || "100"), + scroll: "1m", + }; + + let esResponse: ApiResponse; + + if (options.pagination.page_token) { + esResponse = await this.client.scroll( + { + scroll_id: options.pagination.page_token, + }, + esOptions, + ); + } else { + esResponse = await this.client.search(esParamsWithScroll, esOptions); + } + + if (esResponse.statusCode !== 200) { + logger.error(`${this.name} - ${JSON.stringify(esResponse.body)}`); + } + + const nextToken = esResponse.body?._scroll_id || ""; + const hits = esResponse.body?.hits?.hits || []; + + logger.debug(`${this.name} got response: ${JSON.stringify(esResponse)}`); + + const entities: IndexedEntity[] = []; + for await (const hit of hits) { + try { + entities.push({ + primaryKey: parsePrimaryKey(entityDefinition, hit._id), + score: hit._score, + }); + } catch (err) { + logger.error( + `${this.name} failed to get entity from search result: ${JSON.stringify( + hit._id, + )}, ${JSON.stringify(err)}`, + ); + } + } + + const nextPage: Paginable = new Pagination(nextToken, options.pagination.limitStr || "100"); + + return new ListResult(entityDefinition.type, entities, nextPage); + } +} diff --git a/twake/backend/node/src/core/platform/services/search/adapters/elasticsearch/search.ts b/twake/backend/node/src/core/platform/services/search/adapters/elasticsearch/search.ts new file mode 100644 index 00000000..5446149d --- /dev/null +++ b/twake/backend/node/src/core/platform/services/search/adapters/elasticsearch/search.ts @@ -0,0 +1,102 @@ +import { RequestParams } from "@elastic/elasticsearch"; +import { TransportRequestOptions } from "@elastic/elasticsearch/lib/Transport"; +import { logger } from "../../../../../../core/platform/framework/logger"; +import { EntityTarget, FindFilter, FindOptions, getEntityDefinition } from "../../api"; +import { asciiFold } from "../utils"; + +export function buildSearchQuery( + entityType: EntityTarget, + filters: FindFilter, + options: FindOptions = {}, +): { esParams: RequestParams.Search; esOptions: TransportRequestOptions } { + const instance = new (entityType as any)(); + const { entityDefinition } = getEntityDefinition(instance); + const indexProperties = entityDefinition.options.search.esMapping.properties || {}; + + const esBody: any = { + query: { + bool: { + boost: 1.0, + }, + }, + }; + + if (Object.keys(filters || {}).length > 0) { + esBody.query.bool.must = esBody.query.bool.must || []; + for (const [key, value] of Object.entries(filters)) { + const match: any = {}; + match[key] = { query: value, operator: "AND" }; + esBody.query.bool.must.push({ match }); + } + } + + if (options.$in?.length) { + esBody.query.bool.must = esBody.query.bool.must || []; + for (const inOperation of options.$in) { + if (inOperation[1].length > 0) { + const bool: any = { bool: { should: [], minimum_should_match: 1 } }; + for (const value of inOperation[1]) { + const match: any = {}; + match[inOperation[0]] = { query: value, operator: "AND" }; + bool.bool.should.push({ match }); + } + esBody.query.bool.must.push(bool); + } + } + } + + //TODO implement $gte, $lt, etc + + if (options.$text) { + esBody.query.bool.minimum_should_match = 1; + esBody.query.bool.should = esBody.query.bool.should || []; + + if (options?.$text?.$search) + options.$text.$search = asciiFold(options.$text.$search || "").toLocaleLowerCase(); + + for (const [key, value] of Object.entries(indexProperties)) { + if ((value as any)["type"] === "text") { + const match: any = {}; + match[key] = { + query: (options.$text.$search || "").toLocaleLowerCase(), + }; + esBody.query.bool.should.push({ + match, + }); + + //Allow prefix search + if (indexProperties[key].index_prefixes !== undefined) { + esBody.query.bool.should.push({ + prefix: { [key]: { value: (options.$text.$search || "").toLocaleLowerCase() } }, + }); + } + } + } + } + + if (options.$sort) { + for (const [key, value] of Object.entries(options.$sort)) { + esBody.sort = esBody.sort || []; + esBody.sort.push({ [key]: value }); + } + } + + //TODO implement regex search + + logger.debug(`Elasticsearch query: ${JSON.stringify(esBody)}`); + + const esParams: RequestParams.Search = { + index: entityDefinition.options?.search?.index || entityDefinition.name, + body: esBody, + }; + + const esOptions: TransportRequestOptions = { + ignore: [404], + maxRetries: 3, + }; + + return { + esParams, + esOptions, + }; +} diff --git a/twake/backend/node/src/core/platform/services/search/adapters/mongosearch/index.ts b/twake/backend/node/src/core/platform/services/search/adapters/mongosearch/index.ts new file mode 100644 index 00000000..302cb0d5 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/search/adapters/mongosearch/index.ts @@ -0,0 +1,238 @@ +import _ from "lodash"; +import { Db } from "mongodb"; +import { logger } from "../../../../framework"; +import { DatabaseServiceAPI } from "../../../database/api"; +import { + getEntityDefinition, + unwrapPrimarykey, + ColumnDefinition, + EntityDefinition, + FindFilter, + FindOptions, + EntityTarget, + IndexedEntity, + SearchAdapterInterface, +} from "../../api"; +import { SearchAdapter } from "../abstract"; +import { ListResult, Paginable, Pagination } from "../../../../framework/api/crud-service"; +import { MongoConnector } from "../../../database/services/orm/connectors"; +import { asciiFold, parsePrimaryKey, stringifyPrimaryKey } from "../utils"; +import { buildSearchQuery } from "./search"; + +const searchPrefix = "search__"; + +const typeToIndex: { [key: string]: "text" } = { + encoded_string: "text", + string: "text", +}; + +type Operation = { + index: string; + id: string; + action: "remove" | "upsert"; + body?: any; +}; +export default class MongoSearch extends SearchAdapter implements SearchAdapterInterface { + mongodb: Db; + private name = "MongoSearch"; + + constructor(readonly database: DatabaseServiceAPI) { + super(); + } + + public async connect() { + const service = this.database.getConnector() as MongoConnector; + this.mongodb = await service.getDatabase(); + } + + private async createIndex( + entityDefinition: EntityDefinition, + columns: { [name: string]: ColumnDefinition }, + ) { + if (!entityDefinition.options?.search) { + return; + } + + logger.info(`${this.name} - Start compute index ${JSON.stringify(entityDefinition)}`); + + const index = this.getIndex(entityDefinition); + const collection = this.mongodb.collection(`${searchPrefix}${index}`); + + const primaryKey = unwrapPrimarykey(entityDefinition); + const indexedPk: any = {}; + primaryKey.forEach(key => { + indexedPk[key] = 1; + }); + + let indexedFields: any = entityDefinition.options.search.mongoMapping || {}; + if (!entityDefinition.options.search.mongoMapping) { + Object.keys(columns).forEach(c => { + const def = columns[c]; + if (typeToIndex[def.type]) { + indexedFields[typeToIndex[def.type]][c] = typeToIndex[def.type]; + } + }); + } + + indexedFields = _.pick(indexedFields, ["text"]); + + logger.info( + `${this.name} - Create indexes ${JSON.stringify(indexedFields)} for ${ + entityDefinition.name + } (${searchPrefix}${index})`, + ); + + //Create one index for each type of indexes ["text"] + Object.keys(indexedFields).forEach(k => { + collection.createIndex(indexedFields[k], { default_language: "none" }); + }); + } + + public async upsert(entities: any[]) { + for (const entity of entities) { + const { entityDefinition, columnsDefinition } = getEntityDefinition(entity); + const pkColumns = unwrapPrimarykey(entityDefinition); + + await this.ensureIndex(entityDefinition, columnsDefinition, this.createIndex.bind(this)); + + if (!entityDefinition.options?.search) { + return; + } + + if ( + entityDefinition.options.search.shouldUpdate && + !entityDefinition.options.search.shouldUpdate(entity) + ) { + return; + } + + if (!entityDefinition.options?.search?.source) { + logger.info(`Unable to do operation upsert to mongodb search for doc ${entity}`); + return; + } + + const body = { + ..._.pick(entity, ...pkColumns), + ...entityDefinition.options.search.source(entity), + }; + + Object.keys(entityDefinition.options?.search.mongoMapping?.text || []).forEach( + (key: string) => { + if (entityDefinition.options?.search.mongoMapping?.text[key] === "text") { + body[key] = asciiFold(body[key]).toLocaleLowerCase(); + } + }, + ); + + const record: Operation = { + index: this.getIndex(entityDefinition), + id: stringifyPrimaryKey(entity), + action: "upsert", + body, + }; + + logger.info(`Add operation upsert to to mongodb search for doc ${record.id}`); + + this.proceed(record); + } + } + + public async remove(entities: any[]) { + for (const entity of entities) { + const { entityDefinition, columnsDefinition } = getEntityDefinition(entity); + + await this.ensureIndex(entityDefinition, columnsDefinition, this.createIndex.bind(this)); + + if (!entityDefinition.options?.search) { + return; + } + + const record: Operation = { + index: this.getIndex(entityDefinition), + id: stringifyPrimaryKey(entity), + action: "remove", + }; + + logger.info(`Add operation remove from to mongodb search for doc ${record.id}`); + + this.proceed(record); + } + } + + private getIndex(entityDefinition: EntityDefinition) { + return entityDefinition.options?.search?.index || entityDefinition.name; + } + + private async proceed(operation: Operation) { + const collection = this.mongodb.collection(`${searchPrefix}${operation.index}`); + logger.info( + `Process all buffered operations on searchable entity ${searchPrefix}${operation.index}`, + ); + if (operation.action === "remove") { + await collection.deleteOne({ _docId: operation.id }); + } + if (operation.action === "upsert") { + await collection.updateOne( + { _docId: operation.id }, + { $set: { ...{ _docId: operation.id }, ...operation.body } }, + { upsert: true }, + ); + } + } + + public async search( + _table: string, + entityType: EntityTarget, + filters: FindFilter, + options: FindOptions = {}, + ) { + const instance = new (entityType as any)(); + const { entityDefinition, columnsDefinition } = getEntityDefinition(instance); + const index = this.getIndex(entityDefinition); + + logger.info(`Run search on entity ${searchPrefix}${index}`); + + await this.ensureIndex(entityDefinition, columnsDefinition, this.createIndex.bind(this)); + + const collection = this.mongodb.collection(`${searchPrefix}${index}`); + + const { query, sort, project } = buildSearchQuery(entityType, filters, options); + + console.log(query); + + let cursor = collection.find({ ...query }).sort(sort); + if (project) { + cursor = cursor.project(project); + } + cursor = cursor + .skip(Math.max(0, parseInt(options.pagination.page_token || "0"))) + .limit(Math.max(0, parseInt(options.pagination.limitStr || "100"))); + + const entities: IndexedEntity[] = []; + while (await cursor.hasNext()) { + let row = await cursor.next(); + row = { ...row.set, ...row }; + try { + entities.push({ + primaryKey: parsePrimaryKey(entityDefinition, row._docId), + score: row.score, + }); + } catch (err) { + logger.error( + `${this.name} failed to get entity from search result: ${JSON.stringify( + row._docId, + )}, ${JSON.stringify(err)}`, + ); + } + } + + const nextToken = + entities.length === parseInt(options.pagination.limitStr) && + (parseInt(options.pagination.page_token) + 1).toString(10); + const nextPage: Paginable = new Pagination(nextToken, options.pagination.limitStr || "100"); + + logger.info(`Found ${entities.length} results on entity ${searchPrefix}${index}`); + + return new ListResult(entityDefinition.type, entities, nextPage); + } +} diff --git a/twake/backend/node/src/core/platform/services/search/adapters/mongosearch/search.ts b/twake/backend/node/src/core/platform/services/search/adapters/mongosearch/search.ts new file mode 100644 index 00000000..fa9d68f0 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/search/adapters/mongosearch/search.ts @@ -0,0 +1,66 @@ +import { buildSelectQuery } from "../../../database/services/orm/connectors/mongodb/query-builder"; +import { EntityTarget, FindFilter, FindOptions, getEntityDefinition } from "../../api"; +import { asciiFold } from "../utils"; + +export function buildSearchQuery( + entityType: EntityTarget, + filters: FindFilter, + options: FindOptions = {}, +): { project: any; query: any; sort: any } { + const instance = new (entityType as any)(); + const { entityDefinition } = getEntityDefinition(instance); + + let project: any = false; + let query: any = {}; + try { + query = buildSelectQuery(entityType, filters, options); + } catch (e) { + console.log(e); + } + let sort: any = {}; + + //Build text searches + if (options.$text) { + const prefixMapping = entityDefinition?.options?.search?.mongoMapping?.prefix || {}; + const textMapping = entityDefinition?.options?.search?.mongoMapping?.text || {}; + //Try to detect when we need prefix search + if (Object.values(prefixMapping).length > 0 && options.$text.$search.indexOf(" ") < 0) { + query.$or = [...Object.keys(prefixMapping), ...Object.keys(textMapping)].map(k => { + if (prefixMapping[k] === "prefix") { + return { + [k]: new RegExp(`^${asciiFold(options.$text.$search || "")}`, "i"), + }; + } else { + return { + [k]: new RegExp(`${asciiFold(options.$text.$search || "")}`, "i"), + }; + } + }); + } else { + project = { score: { $meta: "textScore" } }; + sort = { score: -1 }; + if (options?.$text?.$search) + options.$text.$search = asciiFold(options.$text.$search || "").toLocaleLowerCase(); + query.$text = options.$text || undefined; + } + } + + //Build regexes + if (options.$regex) { + options.$regex.forEach(r => { + //r: [Field, regex, options] + if (r.length >= 2) { + const field = r[0]; + query[field] = query[field] || {}; + query[field].$regex = r[1]; + if (r[2]) query[field].$options = r[2]; + } + }); + } + + return { + project, + query, + sort, + }; +} diff --git a/twake/backend/node/src/core/platform/services/search/adapters/utils.ts b/twake/backend/node/src/core/platform/services/search/adapters/utils.ts new file mode 100644 index 00000000..507fb2f2 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/search/adapters/utils.ts @@ -0,0 +1,39 @@ +import _ from "lodash"; +import { getEntityDefinition, unwrapPrimarykey, EntityDefinition } from "../api"; +import ASCIIFolder from "./ascii-folder"; + +export function stringifyPrimaryKey(entity: any): string { + const { entityDefinition } = getEntityDefinition(entity); + const pkColumns = unwrapPrimarykey(entityDefinition).sort((a, b) => a.localeCompare(b)); + return JSON.stringify(pkColumns.map(c => entity[c])); +} + +export function parsePrimaryKey( + entityDefinition: EntityDefinition, + pkStr: string, +): { [key: string]: any } { + const pkColumns = unwrapPrimarykey(entityDefinition).sort((a, b) => a.localeCompare(b)); + const pkList = JSON.parse(pkStr); + const pk: { [key: string]: any } = {}; + pkColumns.forEach((c, index) => { + pk[c] = pkList[index]; + }); + return pk; +} + +export function expandStringForPrefix( + str: string, + minimalSize: number = 1, + maximalSize: number = 5, +) { + const expanded: string[] = []; + [...str.split(" "), ...str.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, " ").split(" ")].map(w => { + for (let i = minimalSize; i <= Math.min(maximalSize, w.length); i++) + expanded.push(w.slice(0, i)); + }); + return _.uniq(expanded).join(" "); +} + +export function asciiFold(str: string) { + return ASCIIFolder.foldMaintaining(str); +} diff --git a/twake/backend/node/src/core/platform/services/search/api.ts b/twake/backend/node/src/core/platform/services/search/api.ts new file mode 100644 index 00000000..87f03fde --- /dev/null +++ b/twake/backend/node/src/core/platform/services/search/api.ts @@ -0,0 +1,73 @@ +/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types */ +import { TwakeServiceProvider } from "../../framework"; +import { ListResult } from "../../framework/api/crud-service"; +import { + FindFilter as OrmFindFilter, + FindOptions as OrmFindOptions, +} from "../database/services/orm/repository/repository"; +import { EntityTarget } from "../database/services/orm/types"; +import SearchRepository from "./repository"; + +export { getEntityDefinition, unwrapPrimarykey } from "../database/services/orm/utils"; +export { + DatabaseEntitiesRemovedEvent, + DatabaseEntitiesSavedEvent, + EntityDefinition, + ColumnDefinition, + EntityTarget, +} from "../database/services/orm/types"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type FindFilter = OrmFindFilter; + +type TextType = { + $search: string; + $caseSensitive?: boolean; //Default false + $diacriticSensitive?: boolean; //Default false +}; + +type SortType = { + [key: string]: "asc" | "desc"; +}; + +//Field, regex, options +type RegexType = [string, string, string]; + +export type FindOptions = OrmFindOptions & { + $regex?: RegexType[]; + $text?: TextType; + $sort?: SortType; +}; + +export type IndexedEntity = { + primaryKey: { [key: string]: any }; + score: number; +}; + +export interface SearchAdapterInterface { + connect(): Promise; + upsert(entities: any[]): Promise; + remove(entities: any[]): Promise; + + search( + table: string, + entityType: EntityTarget, + filters: FindFilter, + options: FindOptions, + ): Promise>; +} + +export interface SearchServiceAPI extends TwakeServiceProvider { + getRepository(table: string, entityType: EntityTarget): SearchRepository; + upsert(entities: any[]): Promise; + remove(entities: any[]): Promise; + type: SearchConfiguration["type"]; +} + +export type SearchConfiguration = { + type?: false | "elasticsearch" | "mongodb"; + elasticsearch?: { + endpoint: string; + flushInterval: number; //In milliseconds + }; +}; diff --git a/twake/backend/node/src/core/platform/services/search/index.ts b/twake/backend/node/src/core/platform/services/search/index.ts new file mode 100644 index 00000000..c339b72a --- /dev/null +++ b/twake/backend/node/src/core/platform/services/search/index.ts @@ -0,0 +1,78 @@ +import { TwakeService, logger, ServiceName, Consumes } from "../../framework"; +import { + DatabaseEntitiesRemovedEvent, + DatabaseEntitiesSavedEvent, + EntityTarget, + SearchAdapterInterface, + SearchConfiguration, + SearchServiceAPI, +} from "./api"; +import ElasticsearchService from "./adapters/elasticsearch"; +import MongosearchService from "./adapters/mongosearch"; +import { localEventBus } from "../../framework/event-bus"; +import { DatabaseServiceAPI } from "../database/api"; +import SearchRepository from "./repository"; + +@ServiceName("search") +@Consumes(["database"]) +export default class Search extends TwakeService { + version = "1"; + name = "search"; + service: SearchAdapterInterface; + database: DatabaseServiceAPI; + type: SearchConfiguration["type"]; + + public async doInit(): Promise { + const type = this.configuration.get("type") as SearchConfiguration["type"]; + this.type = type; + this.database = this.context.getProvider("database"); + + if (type === "elasticsearch") { + logger.info("Loaded Elasticsearch adapter for search."); + this.service = new ElasticsearchService( + this.database, + this.configuration.get("elasticsearch") as SearchConfiguration["elasticsearch"], + ); + } else if (type === "mongodb") { + logger.info("Loaded Mongo adapter for search."); + this.service = new MongosearchService(this.database); + } else { + logger.warn("No adapter for search was loaded."); + this.service = null; + } + + if (this.service) this.service.connect(); + return this; + } + + //Subscribe to local event bus to get entities to store to es + public async doStart(): Promise { + if (!this.service) return this; + + localEventBus.subscribe("database:entities:saved", (event: DatabaseEntitiesSavedEvent) => { + this.service.upsert(event.entities); + }); + + localEventBus.subscribe("database:entities:removed", (event: DatabaseEntitiesRemovedEvent) => { + this.service.remove(event.entities); + }); + + return this; + } + + public async upsert(entities: any[]) { + return this.service.upsert(entities); + } + + public async remove(entities: any[]) { + return this.service.remove(entities); + } + + public getRepository(table: string, entityType: EntityTarget) { + return new SearchRepository(this, table, entityType); + } + + api(): SearchServiceAPI { + return this; + } +} diff --git a/twake/backend/node/src/core/platform/services/search/repository.ts b/twake/backend/node/src/core/platform/services/search/repository.ts new file mode 100644 index 00000000..359da83d --- /dev/null +++ b/twake/backend/node/src/core/platform/services/search/repository.ts @@ -0,0 +1,66 @@ +import Search from "."; +import { logger } from "../../framework"; +import { + ExecutionContext, + ListResult, + Paginable, + Pagination, +} from "../../framework/api/crud-service"; +import { EntityTarget, FindFilter, FindOptions, getEntityDefinition } from "./api"; + +export default class SearchRepository { + name = "searchRepository"; + + constructor( + readonly service: Search, + readonly table: string, + readonly entityType: EntityTarget, + ) {} + + /** Execute a search over defined search database (mongo or elastic search) */ + public async search(filters: FindFilter, options: FindOptions = {}, context?: ExecutionContext) { + logger.debug( + `${this.name} Run search for table ${this.table} with filter ${JSON.stringify( + filters, + )} and options ${JSON.stringify(options)}`, + ); + + const instance = new (this.entityType as any)(); + const { entityDefinition } = getEntityDefinition(instance); + const repository = await this.service.database.getRepository(this.table, this.entityType); + + const results: EntityType[] = []; + let nextPage: Paginable = new Pagination(); + try { + //1. Get objects primary keys from search connector + const searchResults = await this.service.service.search( + this.table, + this.entityType, + filters, + options, + ); + + //2. Get database original objects from theses primary keys + for (const searchEntity of searchResults.getEntities().sort((a, b) => b.score - a.score)) { + const sourceEntity = await repository.findOne(searchEntity.primaryKey, {}, context); + if (sourceEntity) { + results.push(sourceEntity); + } else { + logger.error( + `${this.name} Missing source entity for pk ${JSON.stringify( + searchEntity.primaryKey, + )} in table ${this.table}`, + ); + } + } + nextPage = searchResults.nextPage; + } catch (err) { + logger.error(`${this.name} An error occurred while searching, returning zero results:`); + logger.error(err); + } + + logger.debug(`${this.name} Found ${results.length} results for table ${this.table}`); + + return new ListResult(entityDefinition.type, results, nextPage); + } +} diff --git a/twake/backend/node/src/core/platform/services/storage/connectors/S3/service.ts b/twake/backend/node/src/core/platform/services/storage/connectors/S3/service.ts new file mode 100644 index 00000000..a5bac237 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/storage/connectors/S3/service.ts @@ -0,0 +1,66 @@ +import * as Minio from "minio"; +import { logger } from "../../../../../../core/platform/framework"; +import { Readable } from "stream"; +import { StorageConnectorAPI, WriteMetadata } from "../../provider"; + +export type S3Configuration = Minio.ClientOptions & { bucket: string }; + +export default class S3ConnectorService implements StorageConnectorAPI { + client: Minio.Client; + minioConfiguration: S3Configuration; + + constructor(S3Configuration: S3Configuration) { + this.client = new Minio.Client({ ...S3Configuration }); + this.minioConfiguration = S3Configuration; + } + + write(path: string, stream: Readable): Promise { + let totalSize = 0; + return new Promise(resolve => { + stream + .on("data", function (chunk) { + totalSize += chunk.length; + }) + .on("end", () => { + resolve({ + size: totalSize, + }); + }); + + this.client.putObject(this.minioConfiguration.bucket, path, stream); + }); + } + + async read(path: string): Promise { + // Test if file exists in S3 bucket 10 times until we find it + const tries = 10; + let err = null; + for (let i = 0; i <= tries; i++) { + try { + const stat = await this.client.statObject(this.minioConfiguration.bucket, path); + if (stat?.size > 0) { + break; + } + } catch (e) { + err = e; + } + + if (i === tries) { + logger.info(`Unable to get file after ${tries} tries:`); + throw err; + } + + await new Promise(r => setTimeout(r, 500)); + logger.info(`File ${path} not found in S3 bucket, retrying...`); + } + return this.client.getObject(this.minioConfiguration.bucket, path); + } + + async remove(path: string): Promise { + try { + await this.client.removeObject(this.minioConfiguration.bucket, path); + return true; + } catch (err) {} + return false; + } +} diff --git a/twake/backend/node/src/core/platform/services/storage/connectors/local/service.ts b/twake/backend/node/src/core/platform/services/storage/connectors/local/service.ts new file mode 100644 index 00000000..d7150234 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/storage/connectors/local/service.ts @@ -0,0 +1,65 @@ +import { Readable } from "stream"; +import { createWriteStream, createReadStream, existsSync, mkdirSync, statSync, rmSync } from "fs"; +import p from "path"; +import { rm } from "fs/promises"; // Do not change the import, this is not the same function import { rm } from "fs" +import { StorageConnectorAPI, WriteMetadata } from "../../provider"; + +export type LocalConfiguration = { + path: string; +}; + +export default class LocalConnectorService implements StorageConnectorAPI { + configuration: LocalConfiguration; + + constructor(localConfiguration: LocalConfiguration) { + this.configuration = localConfiguration; + } + + write(relativePath: string, stream: Readable): Promise { + const path = this.getFullPath(relativePath); + + const directory = p.dirname(path); + if (!existsSync(directory)) { + mkdirSync(directory, { + recursive: true, + }); + } + + return new Promise((resolve, reject) => { + const file = createWriteStream(path); + file + .on("error", function (err) { + reject(err); + }) + .on("finish", () => { + const stats = statSync(path); + resolve({ + size: stats.size, + }); + }); + stream.pipe(file); + }); + } + + async read(path: string): Promise { + return createReadStream(this.getFullPath(path)); + } + + async remove(path: string): Promise { + try { + if (existsSync(this.getFullPath(path))) { + rmSync(this.getFullPath(path)); + return true; + } + } catch (err) {} + return false; + } + + private getFullPath(path: string): string { + return `${this.configuration.path}/${path}`.replace(/\/{2,}/g, "/"); + } + + delete(path: string): Promise { + return rm(this.getFullPath(path), { recursive: false, force: true }); + } +} diff --git a/twake/backend/node/src/core/platform/services/storage/index.ts b/twake/backend/node/src/core/platform/services/storage/index.ts new file mode 100644 index 00000000..ffc96e47 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/storage/index.ts @@ -0,0 +1,162 @@ +import { createCipheriv, createDecipheriv, Decipher } from "crypto"; +import { Stream, Readable } from "stream"; +import Multistream from "multistream"; +import { Consumes, logger, TwakeService } from "../../framework"; +import LocalConnectorService, { LocalConfiguration } from "./connectors/local/service"; +import S3ConnectorService, { S3Configuration } from "./connectors/S3/service"; +import StorageAPI, { + DeleteOptions, + ReadOptions, + StorageConnectorAPI, + WriteMetadata, + WriteOptions, +} from "./provider"; + +type EncryptionConfiguration = { + secret: string | null; + iv: string | null; +}; +@Consumes([]) +export default class StorageService extends TwakeService implements StorageAPI { + name = "storage"; + version = "1"; + + private encryptionOptions: EncryptionConfiguration; + private algorithm = "aes-256-cbc"; + + api(): StorageAPI { + return this; + } + + getConnectorType(): string { + return this.configuration.get("type"); + } + + getConnector(): StorageConnectorAPI { + //Fixme do not reload connector everytime + const type = this.getConnectorType(); + if (type === "S3") { + logger.info("Using 'S3' connector for storage."); + return new S3ConnectorService(this.configuration.get("S3")); + } + logger.info( + `Using 'local' connector for storage${ + type === "local" ? "" : " (no other connector recognized from configuration type: '%s')" + }.`, + type, + ); + return new LocalConnectorService(this.configuration.get("local")); + } + + async write(path: string, stream: Stream, options?: WriteOptions): Promise { + try { + if (options?.encryptionKey) { + const [key, iv] = options.encryptionKey.split("."); + const cipher = createCipheriv(options.encryptionAlgo || this.algorithm, key, iv); + stream = stream.pipe(cipher); + } + if (options?.chunkNumber) path = `${path}/chunk${options.chunkNumber}`; + + if (this.encryptionOptions.secret) { + try { + const cipher = createCipheriv( + this.algorithm, + this.encryptionOptions.secret, + this.encryptionOptions.iv, + ); + stream = stream.pipe(cipher); + } catch (err) { + logger.error("Unable to createCipheriv: %s", err); + } + } + + return await this.getConnector().write(path, stream); + } catch (err) { + logger.error(err); + return null; + } + } + + async read(path: string, options?: ReadOptions): Promise { + try { + // eslint-disable-next-line @typescript-eslint/no-this-alias + const self = this; + + const chunks = options?.totalChunks || 1; + let count = 1; + let stream; + async function factory(callback: (err?: Error, stream?: Stream) => unknown) { + if (count > chunks) { + callback(); + return; + } + + let decipher: Decipher; + if (options?.encryptionKey) { + const [key, iv] = options.encryptionKey.split("."); + decipher = createDecipheriv(options.encryptionAlgo || this.algorithm, key, iv); + } + + const chunk = options?.totalChunks ? `${path}/chunk${count}` : path; + count += 1; + + try { + stream = await self._read(chunk); + if (decipher) { + stream = stream.pipe(decipher); + } + } catch (err) { + logger.error(err); + callback(); + return; + } + callback(null, stream); + return; + } + + return new Multistream(factory); + } catch (err) { + logger.error(err); + return null; + } + } + + async _read(path: string): Promise { + let stream = await this.getConnector().read(path); + if (this.encryptionOptions.secret) { + try { + const decipher = createDecipheriv( + this.algorithm, + this.encryptionOptions.secret, + this.encryptionOptions.iv, + ); + stream = stream.pipe(decipher); + } catch (err) { + logger.error("Unable to createDecipheriv: %s", err); + } + } + return stream; + } + + async remove(path: string, options?: DeleteOptions) { + try { + for (let count = 1; count <= (options?.totalChunks || 1); count++) { + const chunk = options?.totalChunks ? `${path}/chunk${count}` : path; + await this.getConnector().remove(chunk); + } + return true; + } catch (err) { + logger.error("Unable to remove file %s", err); + } + return false; + } + + async doInit(): Promise { + this.encryptionOptions = { + secret: this.configuration.get("secret", null), + iv: this.configuration.get("iv", null), + }; + + return this; + } +} diff --git a/twake/backend/node/src/core/platform/services/storage/provider.ts b/twake/backend/node/src/core/platform/services/storage/provider.ts new file mode 100644 index 00000000..f6149853 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/storage/provider.ts @@ -0,0 +1,57 @@ +import { Stream, Readable } from "stream"; +import { TwakeServiceProvider } from "../../framework"; +import { ExecutionContext } from "../../framework/api/crud-service"; + +export type WriteMetadata = { + size: number; +}; + +export type WriteOptions = { + chunkNumber?: number; + encryptionKey?: string; + encryptionAlgo?: string; +}; + +export type ReadOptions = { + totalChunks?: number; + encryptionKey?: string; + encryptionAlgo?: string; +}; + +export type DeleteOptions = { + totalChunks?: number; +}; + +export interface StorageConnectorAPI { + /** + * Write a stream to a path + * + * @param path + * @param stream + */ + write( + path: string, + stream: Stream, + options?: WriteOptions, + context?: ExecutionContext, + ): Promise; + + /** + * Read a path and returns its stream + * + * @param path + */ + read(path: string, options?: ReadOptions, context?: ExecutionContext): Promise; + + /** + * Remove a path + * + * @param path + */ + remove(path: string, options?: DeleteOptions, context?: ExecutionContext): Promise; +} + +export default interface StorageAPI extends TwakeServiceProvider, StorageConnectorAPI { + getConnector(): StorageConnectorAPI; + getConnectorType(): string; +} diff --git a/twake/backend/node/src/core/platform/services/tracker/adapters/segment.ts b/twake/backend/node/src/core/platform/services/tracker/adapters/segment.ts new file mode 100644 index 00000000..06f949e3 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/tracker/adapters/segment.ts @@ -0,0 +1,91 @@ +import Analytics from "analytics-node"; +import { Analytics as AnalyticsAbtract } from "./types"; +import axios, { AxiosInstance } from "axios"; + +export default class Segment implements AnalyticsAbtract { + protected version = "5.0.0"; //Segment analytics lib version + protected analytics: Analytics; + + protected axiosInstance: AxiosInstance; + protected host: string; + protected writeKey: string; + protected timeout: string | number; + + constructor(key: string) { + this.writeKey = key; + this.host = "https://api.segment.io"; + this.timeout = 60000; + this.axiosInstance = axios.create(); + this.analytics = new Analytics(this.writeKey, { + host: this.host, + timeout: this.timeout, + }); + } + + public identify( + message: ( + | { userId: string | number } + | { userId?: string | number; anonymousId: string | number } + ) & { traits?: any; timestamp?: Date; context?: any }, + callback?: (err: Error) => void, + ): void { + try { + this.analytics.identify(message, callback); + } catch (err) { + console.error(err); + } + } + + public track( + message: ( + | { userId: string | number } + | { userId?: string | number; anonymousId: string | number } + ) & { event: string; properties?: any; timestamp?: Date; context?: any }, + callback?: (err: Error) => void, + ): void { + try { + this.analytics.track(message, callback); + } catch (err) { + console.error(err); + } + } + + public remove(message: { userId: string }, callback: (err: Error) => void) { + (async () => { + const headers: any = {}; + if (typeof window === "undefined") { + headers["user-agent"] = `analytics-node/${this.version}`; + } + + const req: any = { + auth: { + username: this.writeKey, + }, + headers, + timeout: 5000, + }; + + this.axiosInstance + .post( + `${this.host}/v1beta/workspaces/myworkspace/regulations`, + { + regulation_type: "Suppress_With_Delete", + attributes: { + name: "userId", + values: [message.userId], + }, + }, + req, + ) + // eslint-disable-next-line @typescript-eslint/no-empty-function + .then(() => () => {}) + .catch(err => { + if (err.response) { + const error = new Error(err.response.statusText); + return callback(error); + } + callback(err); + }); + })(); + } +} diff --git a/twake/backend/node/src/core/platform/services/tracker/adapters/types.ts b/twake/backend/node/src/core/platform/services/tracker/adapters/types.ts new file mode 100644 index 00000000..e6afe4a8 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/tracker/adapters/types.ts @@ -0,0 +1,29 @@ +type Identity = + | { userId: string | number } + | { userId?: string | number | undefined; anonymousId: string | number }; + +export interface Analytics { + /* The identify method lets you tie a user to their actions and record + traits about them. */ + identify( + message: Identity & { + traits?: any; + timestamp?: Date | undefined; + context?: any; + }, + callback?: (err: Error) => void, + ): void; + + remove(identity: Identity, callback?: (err: Error) => void): void; + + /* The track method lets you record the actions your users perform. */ + track( + message: Identity & { + event: string; + properties?: any; + timestamp?: Date | undefined; + context?: any; + }, + callback?: (err: Error) => void, + ): void; +} diff --git a/twake/backend/node/src/core/platform/services/tracker/index.ts b/twake/backend/node/src/core/platform/services/tracker/index.ts new file mode 100644 index 00000000..c89c71d9 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/tracker/index.ts @@ -0,0 +1,184 @@ +import Segment from "./adapters/segment"; +import { Analytics } from "./adapters/types"; +import { Consumes, TwakeService, logger } from "../../framework"; +import TrackerAPI from "./provider"; +import { localEventBus } from "../../framework/event-bus"; +import { IdentifyObjectType, TrackedEventType, TrackerConfiguration } from "./types"; +import { ResourceEventsPayload } from "../../../../utils/types"; +import { md5 } from "../../../../core/crypto"; + +@Consumes([]) +export default class Tracker extends TwakeService implements TrackerAPI { + name = "tracker"; + version = "1"; + analytics: Analytics; + + async doInit(): Promise { + localEventBus.subscribe("user:deleted", data => { + this.remove({ user: data.user }); + }); + + const channelListEvent = "channel:list"; + localEventBus.subscribe(channelListEvent, data => { + logger.debug(`Tracker - New ${channelListEvent} event`); + this.identify({ + user: data.user, + traits: { + email: data.user.email || "", + company: { + id: data.company.id, + }, + companies: [data.company.id], + }, + }); + this.track( + { + user: data.user, + event: "open_client", + }, + (err: Error) => + err + ? logger.error({ err }, "Tracker - Error while tracking event", channelListEvent) + : false, + ); + }); + + const messageSentEvent = "channel:message_sent"; + localEventBus.subscribe(messageSentEvent, data => { + logger.debug(`Tracker - New ${messageSentEvent} event`); + this.track( + { + user: data.user, + event: messageSentEvent, + properties: { + is_direct: data.message.workspace_id === "direct" ? true : false, + is_thread_reply: data.message.thread_id ? true : false, + }, + }, + (err: Error) => + err ? logger.error({ err }, "Tracker - Error while tracking", messageSentEvent) : false, + ); + }); + + const channelCreatedEvent = "channel:created"; + localEventBus.subscribe(channelCreatedEvent, data => { + logger.debug(`Tracker - New ${channelCreatedEvent} event`); + this.track( + { + user: data.user, + event: channelCreatedEvent, + properties: this.getVisibilityObject(data.channel.visibility), + }, + (err: Error) => + err + ? logger.error({ err }, "Tracker - Error while tracking", channelCreatedEvent) + : false, + ); + }); + + const channelMemberCreatedEvent = "channel:member:created"; + localEventBus.subscribe(channelMemberCreatedEvent, data => { + logger.debug(`Tracker - New ${channelMemberCreatedEvent} event`); + this.track( + { + user: data.user, + event: data.user.id !== data.member.user_id ? "channel:invite" : "channel:join", + properties: this.getVisibilityObject(data.channel.visibility), + }, + (err: Error) => + err + ? logger.error({ err }, "Tracker - Error while tracking", channelMemberCreatedEvent) + : false, + ); + }); + + return this; + } + + private getVisibilityObject(visibility: string) { + return { + is_direct: visibility === "direct" ? true : false, + is_private: visibility === "private" ? true : false, + is_public: visibility === "public" ? true : false, + }; + } + + public async identify( + identity: IdentifyObjectType, + callback?: (err: Error) => void, + ): Promise { + const analiticsIdentity = { + userId: identity.user?.allow_tracking + ? identity.user.identity_provider_id + : `anonymous-${md5(identity.user.identity_provider_id || "")}`, + ...identity, //Fixme: right now we use this to send onboarding emails so user is not completely anonymous yet + }; + + const analytics = await this.getAnalytics(); + + if (analytics && identity) analytics.identify(analiticsIdentity, callback); + } + + public async remove( + identity: IdentifyObjectType, + callback?: (err: Error) => void, + ): Promise { + const userId = identity.user.identity_provider_id; + if (userId) { + const analytics = await this.getAnalytics(); + if (analytics && identity) analytics.identify({ userId }, callback); + } + } + + public async track(event: TrackedEventType, callback?: (err: Error) => void): Promise { + if (!event.user) { + logger.warn(`Tracker - Tried to track event without userId: ${event.event}`); + return; + } + + // Fixme: For now we have zero users allowing to track (value false by default and not asked during sign up) + // As soon as we clearly define a way for users to choose this option we will enable this code again. + // Right now we need stats to move forward with Twake. + // Note that the user that create the event will be anonymised here + // if (!event.user?.allow_tracking) return; + + const analytics = await this.getAnalytics(); + + if (analytics && event) { + event.event = `twake:${event.event}`; + analytics.track( + { + userId: event.user?.allow_tracking + ? event.user.identity_provider_id || "no_identity_provider_id" + : `anonymous-${md5(event.user.identity_provider_id || "")}`, + ...event, + }, + callback, + ); + } + } + + private async getAnalytics(): Promise { + const type = this.configuration.get("type"); + if (!type || !type.length) { + logger.info("Tracker - No tracker type specified"); + return; + } + + const config = this.configuration.get(type); + if (!config) { + logger.info("Tracker - No tracker configured for type", type); + return; + } + + if (!this.analytics && config.key) { + this.analytics = new Segment(config.key); + } + + return this.analytics; + } + + api(): TrackerAPI { + return this; + } +} diff --git a/twake/backend/node/src/core/platform/services/tracker/provider.ts b/twake/backend/node/src/core/platform/services/tracker/provider.ts new file mode 100644 index 00000000..b8a98765 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/tracker/provider.ts @@ -0,0 +1,8 @@ +import { TwakeServiceProvider } from "../../framework"; +import { IdentifyObjectType, TrackedEventType } from "./types"; + +export default interface TrackerAPI extends TwakeServiceProvider { + identify(identity: IdentifyObjectType, callback?: (err: Error) => void): Promise; + remove(identity: IdentifyObjectType, callback?: (err: Error) => void): Promise; + track(tracker: TrackedEventType, callback?: (err: Error) => void): Promise; +} diff --git a/twake/backend/node/src/core/platform/services/tracker/types.ts b/twake/backend/node/src/core/platform/services/tracker/types.ts new file mode 100644 index 00000000..7256ced3 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/tracker/types.ts @@ -0,0 +1,21 @@ +import { ExecutionContext } from "../../framework/api/crud-service"; + +export type IdentityType = { user: ExecutionContext["user"] }; + +export type IdentifyObjectType = IdentityType & { + traits?: { [key: string]: unknown }; + timestamp?: Date; + context?: { [key: string]: unknown }; +}; + +export type TrackedEventType = IdentityType & { + // event starts with prefix `twake:` + event: string; + properties?: { [key: string]: unknown }; + timestamp?: Date; + context?: { [key: string]: unknown }; +}; + +export type TrackerConfiguration = { + key: string; +}; diff --git a/twake/backend/node/src/core/platform/services/types/index.ts b/twake/backend/node/src/core/platform/services/types/index.ts new file mode 100644 index 00000000..c73670b9 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/types/index.ts @@ -0,0 +1,12 @@ +export type JwtType = { + type: "access" | "refresh"; + sub: string; + provider_id: string; //Console sub + email: string; + application_id?: string; + server_request?: boolean; + nbf: number; + refresh_nbf?: number; + iat: number; + track: boolean; +}; diff --git a/twake/backend/node/src/core/platform/services/webserver/error.ts b/twake/backend/node/src/core/platform/services/webserver/error.ts new file mode 100644 index 00000000..f3a03279 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/webserver/error.ts @@ -0,0 +1,20 @@ +import { FastifyInstance } from "fastify"; + +function serverErrorHandler(server: FastifyInstance): void { + server.setErrorHandler(async (err, request, reply) => { + console.error(`Got ${reply.statusCode} error on request ${request.id} : `, err); + server.log.debug(`Got ${reply.statusCode} error on request ${request.id} : ${err.toString()}`); + await reply.send( + reply.statusCode == 500 + ? { + statusCode: reply.statusCode, + error: "Internal Server Error", + message: "Something went wrong", + requestId: request.id, + } + : err, + ); + }); +} + +export { serverErrorHandler }; diff --git a/twake/backend/node/src/core/platform/services/webserver/index.ts b/twake/backend/node/src/core/platform/services/webserver/index.ts new file mode 100644 index 00000000..f639675a --- /dev/null +++ b/twake/backend/node/src/core/platform/services/webserver/index.ts @@ -0,0 +1,158 @@ +import { logger, TwakeService } from "../../framework"; +import { Server, IncomingMessage, ServerResponse } from "http"; +import { FastifyInstance, fastify } from "fastify"; +import sensible from "fastify-sensible"; +import multipart from "fastify-multipart"; +import formbody from "@fastify/formbody"; +import fastifyStatic from "@fastify/static"; +import corsPlugin, { FastifyCorsOptions } from "fastify-cors"; +import { serverErrorHandler } from "./error"; +import WebServerAPI from "./provider"; +import jwtPlugin from "../auth/web/jwt"; +import path from "path"; +import swaggerPlugin from "fastify-swagger"; +import { SkipCLI } from "../../framework/decorators/skip"; +import fs from "fs"; +// import { throws } from "assert"; +export default class WebServerService extends TwakeService implements WebServerAPI { + name = "webserver"; + version = "1"; + private server: FastifyInstance; + // eslint-disable-next-line @typescript-eslint/ban-types + private onReadyHandlers: Function[] = []; + + getServer(): FastifyInstance { + return this.server; + } + + // eslint-disable-next-line @typescript-eslint/ban-types + onReady(handler: Function): void { + this.onReadyHandlers.push(handler); + } + + api(): WebServerAPI { + return this; + } + + async doInit(): Promise { + // TODO: Get server config from options + this.server = fastify({ + maxParamLength: 300, //We have big urls with uuids and devices tokens + logger: false, + }); + + this.server.addHook("onResponse", (req, reply, done) => { + logger.info(`${reply.raw.statusCode} ${req.raw.method} ${req.raw.url}`); + done(); + }); + + this.server.addHook("onError", (request, reply, error, done) => { + logger.error(error); + done(); + }); + + this.server.addHook("preValidation", (request, reply, done) => { + if (reply.statusCode === 500) { + logger.error("An error occured with the preValidation of ", request.routerPath); + } + done(); + }); + + this.server.addHook("preHandler", (request, reply, done) => { + reply.header("Cache-Control", "no-cache"); + if (reply.statusCode === 500) { + logger.error("An error occured with the preHandler of ", request.routerPath); + } + done(); + }); + + serverErrorHandler(this.server); + // DIRTY HACK: THis needs to be registered here to avoid circular dep between auth and user. + // will have to create a core service for this, or another service which must be started first... + this.server.register(swaggerPlugin, { + routePrefix: "/internal/docs", + swagger: { + info: { + title: "Twake Swagger", + description: "Automatically generate Twake Swagger API", + version: "0.1.0", + }, + externalDocs: { + url: "http://linagora.github.io/Twake", + description: "Find more info here", + }, + host: "localhost", + schemes: ["http"], + consumes: ["application/json"], + produces: ["application/json"], + tags: [], + definitions: {}, + securityDefinitions: {}, + }, + uiConfig: { + docExpansion: "full", + deepLinking: false, + }, + staticCSP: false, + transformStaticCSP: header => header, + exposeRoute: true, + }); + this.server.register(jwtPlugin); + this.server.register(sensible, { errorHandler: false }); + this.server.register(multipart); + this.server.register(formbody); + this.server.register(corsPlugin, this.configuration.get("cors", {})); + + return this; + } + + @SkipCLI() + async doStart(): Promise { + try { + let root = this.configuration.get<{ root: string }>("static", { root: "./public" }).root; + root = root.indexOf("/") === 0 ? root : path.join(__dirname + "/../../../../../", root); + this.server.register(fastifyStatic, { + root, + }); + this.server.setNotFoundHandler((req, res) => { + if ( + req.raw.url && + (req.raw.url.startsWith("/internal") || + req.raw.url.startsWith("/api") || + req.raw.url.startsWith("/plugins") || + req.raw.url.startsWith("/admin")) + ) { + return res.status(404).send({ + error: "Not found", + }); + } + + const path = root.replace(/\/$/, "") + "/index.html"; + const stream = fs.createReadStream(path); + res.type("text/html").send(stream); + }); + + await this.server.listen(this.configuration.get("port", 3000), "0.0.0.0"); + + this.server.ready(err => { + if (err) throw err; + this.server.swagger(); + + this.onReadyHandlers.forEach(handler => { + handler(err); + }); + }); + + return this; + } catch (err) { + this.server.log.error(err); + throw err; + } + } + + async doStop(): Promise { + await this.server.close(); + + return this; + } +} diff --git a/twake/backend/node/src/core/platform/services/webserver/provider.ts b/twake/backend/node/src/core/platform/services/webserver/provider.ts new file mode 100644 index 00000000..aa7d8b4f --- /dev/null +++ b/twake/backend/node/src/core/platform/services/webserver/provider.ts @@ -0,0 +1,13 @@ +import { Server, IncomingMessage, ServerResponse } from "http"; +import { FastifyInstance } from "fastify"; +import { TwakeServiceProvider } from "../../framework/api"; + +export default interface WebServerAPI extends TwakeServiceProvider { + /** + * Get the fastify webserver instance + */ + getServer(): FastifyInstance; + + // eslint-disable-next-line @typescript-eslint/ban-types + onReady(handler: Function): void; +} diff --git a/twake/backend/node/src/core/platform/services/webserver/types.ts b/twake/backend/node/src/core/platform/services/webserver/types.ts new file mode 100644 index 00000000..c725c733 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/webserver/types.ts @@ -0,0 +1,17 @@ +import { FastifyReply, FastifyRequest } from "fastify"; + +export interface CrudHandler { + (request: FastifyRequest, reply?: FastifyReply): Promise; +} + +export interface CrudController< + GetResponseType, + SaveResponseType, + ListResponseType, + DeleteResponseType, +> { + get?: CrudHandler; + save?: CrudHandler; + list?: CrudHandler; + delete?: CrudHandler; +} diff --git a/twake/backend/node/src/core/platform/services/websocket/index.ts b/twake/backend/node/src/core/platform/services/websocket/index.ts new file mode 100644 index 00000000..d039796f --- /dev/null +++ b/twake/backend/node/src/core/platform/services/websocket/index.ts @@ -0,0 +1,47 @@ +import { Consumes, ServiceName, TwakeService } from "../../framework"; +import WebServerAPI from "../webserver/provider"; +import WebSocketAPI from "./provider"; +import { WebSocketService } from "./services"; +import { AdaptersConfiguration } from "./types"; +import FastifyIO from "fastify-socket.io"; + +@Consumes(["webserver"]) +@ServiceName("websocket") +export default class WebSocket extends TwakeService { + private service: WebSocketService; + name = "websocket"; + version = "1"; + + api(): WebSocketAPI { + return this.service; + } + + async doInit(): Promise { + const webserver = this.context.getProvider("webserver"); + const fastify = webserver.getServer(); + + const options = { + path: this.configuration.get("path", "/socket"), + }; + + fastify.register(FastifyIO, { + ...options, + allowEIO3: true, + cors: { + //Allow all origins + origin: (origin, callback) => callback(null, origin), + credentials: true, + }, + }); + + this.service = new WebSocketService({ + server: fastify, + options, + ready: webserver.onReady.bind(webserver), + adapters: this.configuration.get("adapters"), + auth: this.configuration.get<{ secret: string }>("auth.jwt"), + }); + + return this; + } +} diff --git a/twake/backend/node/src/core/platform/services/websocket/provider.ts b/twake/backend/node/src/core/platform/services/websocket/provider.ts new file mode 100644 index 00000000..1306c742 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/websocket/provider.ts @@ -0,0 +1,17 @@ +import { EventEmitter } from "events"; +import socketIO from "socket.io"; +import { TwakeServiceProvider } from "../../framework"; +import { User } from "../../../../utils/types"; +import { WebsocketUserEvent, WebSocket, WebSocketUser } from "./types"; + +export default interface WebSocketAPI extends TwakeServiceProvider, EventEmitter { + getIo(): socketIO.Server; + + isConnected(user: User): boolean; + + onUserConnected(listener: (event: WebsocketUserEvent) => void): this; + + onUserDisconnected(listener: (event: WebsocketUserEvent) => void): this; + + getUser(websocket: WebSocket): WebSocketUser; +} diff --git a/twake/backend/node/src/core/platform/services/websocket/services/index.ts b/twake/backend/node/src/core/platform/services/websocket/services/index.ts new file mode 100644 index 00000000..8df71288 --- /dev/null +++ b/twake/backend/node/src/core/platform/services/websocket/services/index.ts @@ -0,0 +1,105 @@ +import socketIO from "socket.io"; +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { createClient } = require("redis"); +import SocketIORedis from "@socket.io/redis-adapter"; +import jwt from "jsonwebtoken"; +import WebSocketAPI from "../provider"; +import { + WebSocket, + WebSocketServiceConfiguration, + WebSocketUser, + WebsocketUserEvent, +} from "../types"; +import { EventEmitter } from "events"; +import { User } from "../../../../../utils/types"; +import { JwtType } from "../../types"; + +export class WebSocketService extends EventEmitter implements WebSocketAPI { + version: "1"; + private io: socketIO.Server; + + constructor(serviceConfiguration: WebSocketServiceConfiguration) { + super(); + + serviceConfiguration.ready(() => { + this.io = serviceConfiguration.server.io; + + if (serviceConfiguration.adapters?.types?.includes("redis")) { + const pubClient = createClient(serviceConfiguration.adapters.redis); + const subClient = pubClient.duplicate(); + this.io.adapter(SocketIORedis.createAdapter(pubClient, subClient)); + } + + this.io.on("connection", socket => { + socket.on("authenticate", message => { + if (message.token) { + jwt.verify( + message.token as string, + serviceConfiguration.auth.secret as string, + (err, decoded) => { + if (err) { + socket.emit("unauthorized", { err }); + socket.disconnect(); + return; + } + (socket as unknown as WebSocket).decoded_token = decoded as JwtType; + const user = this.getUser(socket as WebSocket); + + socket.emit("authenticated"); + + socket.on("message", message => { + this.io.emit("message", message); + }); + + this.emit("user:connected", { + user, + socket, + event: "user:connected", + } as WebsocketUserEvent); + + socket.on("disconnect", () => + this.emit("user:disconnected", { + user, + socket, + event: "user:disconnected", + } as WebsocketUserEvent), + ); + }, + ); + } else { + socket.emit("unauthorized", { err: "No token provided" }); + socket.disconnect(); + return; + } + }); + }); + }); + } + + onUserConnected(listener: (event: WebsocketUserEvent) => void): this { + return this.on("user:connected", listener); + } + + onUserDisconnected(listener: (event: WebsocketUserEvent) => void): this { + return this.on("user:disconnected", listener); + } + + getUser(socket: WebSocket): WebSocketUser { + return { + id: socket.decoded_token.sub, + identity_provider_id: socket.decoded_token.provider_id, + email: socket.decoded_token.email, + token: socket.decoded_token, + allow_tracking: socket.decoded_token.track, + }; + } + + getIo(): socketIO.Server { + return this.io; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + isConnected(user: User): boolean { + return false; + } +} diff --git a/twake/backend/node/src/core/platform/services/websocket/types.ts b/twake/backend/node/src/core/platform/services/websocket/types.ts new file mode 100644 index 00000000..6df3dd3d --- /dev/null +++ b/twake/backend/node/src/core/platform/services/websocket/types.ts @@ -0,0 +1,39 @@ +import socketIO, { Socket } from "socket.io"; +import { RedisAdapterOptions } from "@socket.io/redis-adapter"; +import { User } from "../../../../utils/types"; +import { JwtType } from "../types"; +import { FastifyInstance } from "fastify"; + +export interface AdaptersConfiguration { + types: Array; + redis: RedisAdapterOptions; +} + +export interface WebSocketServiceConfiguration { + server: FastifyInstance; + // eslint-disable-next-line @typescript-eslint/ban-types + ready: Function; + options?: socketIO.ServerOptions | { path: string }; + adapters?: AdaptersConfiguration; + auth?: { secret: string }; +} + +export interface WebSocketUser extends User { + token?: DecodedToken; +} + +export interface WebSockets { + [index: string]: WebSocket[]; +} + +export interface WebSocket extends Socket { + decoded_token: DecodedToken; +} + +export interface WebsocketUserEvent { + event: string; + socket: WebSocket; + user: WebSocketUser; +} + +type DecodedToken = JwtType; diff --git a/twake/backend/node/src/server.ts b/twake/backend/node/src/server.ts new file mode 100644 index 00000000..ef38dee7 --- /dev/null +++ b/twake/backend/node/src/server.ts @@ -0,0 +1,16 @@ +import * as Sentry from "@sentry/node"; +import { TwakePlatform } from "./core/platform/platform"; +import config from "./core/config"; +import twake from "./twake"; + +if (config.get("sentry.dsn")) { + Sentry.init({ + dsn: config.get("sentry.dsn"), + tracesSampleRate: 1.0, + }); +} + +const launch = async (): Promise => twake.run(config.get("services")); + +// noinspection JSIgnoredPromiseFromCall +launch(); diff --git a/twake/backend/node/src/services/applications-api/index.ts b/twake/backend/node/src/services/applications-api/index.ts new file mode 100644 index 00000000..5343ad5a --- /dev/null +++ b/twake/backend/node/src/services/applications-api/index.ts @@ -0,0 +1,34 @@ +import { Prefix, TwakeService } from "../../core/platform/framework"; +import WebServerAPI from "../../core/platform/services/webserver/provider"; +import web from "./web/index"; +import FastProxy from "fast-proxy"; + +@Prefix("/api") +export default class ApplicationsApiService extends TwakeService { + version = "1"; + name = "applicationsapi"; + + public async doInit(): Promise { + const fastify = this.context.getProvider("webserver").getServer(); + fastify.register((instance, _opts, next) => { + web(instance, { prefix: this.prefix }); + next(); + }); + + //Redirect requests from /plugins/* to the plugin server (if installed) + const { proxy, close } = FastProxy({ + base: this.configuration.get("plugins.server"), + }); + fastify.addHook("onClose", close); + fastify.all("/plugins/*", (req, rep) => { + proxy(req.raw, rep.raw, req.url, {}); + }); + + return this; + } + + // TODO: remove + api(): undefined { + return undefined; + } +} diff --git a/twake/backend/node/src/services/applications-api/types.ts b/twake/backend/node/src/services/applications-api/types.ts new file mode 100644 index 00000000..9919e15d --- /dev/null +++ b/twake/backend/node/src/services/applications-api/types.ts @@ -0,0 +1,13 @@ +import { Channel } from "../channels/entities"; +import { Message } from "../messages/entities/messages"; +import { Thread } from "../messages/entities/threads"; + +export type HookType = { + type: "message"; + application_id: string; + company_id: string; + + channel?: Channel; + thread: Thread; + message: Message; +}; diff --git a/twake/backend/node/src/services/applications-api/web/controllers/index.ts b/twake/backend/node/src/services/applications-api/web/controllers/index.ts new file mode 100644 index 00000000..afbf0f85 --- /dev/null +++ b/twake/backend/node/src/services/applications-api/web/controllers/index.ts @@ -0,0 +1,181 @@ +import { FastifyInstance, FastifyReply, FastifyRequest, HTTPMethods } from "fastify"; +import { ApplicationObject } from "../../../applications/entities/application"; +import { + ApplicationApiExecutionContext, + ApplicationLoginRequest, + ApplicationLoginResponse, + ConfigureRequest, +} from "../types"; +import { ResourceGetResponse } from "../../../../utils/types"; +import { CrudException } from "../../../../core/platform/framework/api/crud-service"; +import { localEventBus } from "../../../../core/platform/framework/event-bus"; +import { + RealtimeApplicationEvent, + RealtimeBaseBusEvent, +} from "../../../../core/platform/services/realtime/types"; +import gr from "../../../global-resolver"; +import _ from "lodash"; +import { v4 } from "uuid"; + +export class ApplicationsApiController { + async token( + request: FastifyRequest<{ Body: ApplicationLoginRequest }>, + ): Promise> { + const context = getExecutionContext(request); + + if (!request.body.id || !request.body.secret) { + throw CrudException.forbidden("Application not found"); + } + + const app = await gr.services.applications.marketplaceApps.get( + { + id: request.body.id, + }, + context, + ); + + if (!app) { + throw CrudException.forbidden("Application not found"); + } + + if (!app.api.private_key || app.api.private_key !== request.body.secret) { + throw CrudException.forbidden("Secret key is not valid"); + } + + return { + resource: { + access_token: gr.platformServices.auth.generateJWT(request.body.id, null, { + track: false, + provider_id: "", + application_id: request.body.id, + }), + }, + }; + } + + async me( + request: FastifyRequest, + _reply: FastifyReply, + ): Promise> { + const context = getExecutionContext(request); + + const entity = await gr.services.applications.marketplaceApps.get( + { + id: context.application_id, + }, + context, + ); + if (!entity) { + throw CrudException.notFound("Application not found"); + } + + return { resource: entity.getApplicationObject() }; + } + + async configure( + request: FastifyRequest<{ Body: ConfigureRequest }>, + _reply: FastifyReply, + ): Promise> { + const app_id = request.currentUser.application_id; + const context = getExecutionContext(request); + const application = await gr.services.applications.marketplaceApps.get({ id: app_id }, context); + + if (!application) { + throw CrudException.forbidden("Application not found"); + } + + const body = request.body; + + const data = { + action: "configure", + application: { + id: app_id, + identity: application.identity, + }, + form: body.form, + connection_id: body.connection_id, + hidden_data: {}, + configurator_id: v4(), + }; + + localEventBus.publish("realtime:event", { + room: "/me/" + body.user_id, + type: "application", + data, + } as RealtimeBaseBusEvent); + + return { status: "ok" }; + } + + async proxy( + request: FastifyRequest<{ Params: { company_id: string; service: string; version: string } }>, + reply: FastifyReply, + fastify: FastifyInstance, + ): Promise { + // Check the application has access to this company + const company_id = request.params.company_id; + const companyApplication = gr.services.applications.companyApps.get({ + company_id, + application_id: request.currentUser.application_id, + id: undefined, + }); + if (!companyApplication) { + throw CrudException.forbidden("This application is not installed in the requested company"); + } + + const context = getExecutionContext(request); + const app = await gr.services.applications.marketplaceApps.get( + { + id: request.currentUser.application_id, + }, + context, + ); + + // Check call can be done from this IP + if ( + app.api.allowed_ips.trim() && + app.api.allowed_ips !== "*" && + !_.includes( + app.api.allowed_ips + .split(",") + .map(a => a.trim()) + .filter(a => a), + request.ip, + ) + ) { + throw CrudException.forbidden( + `This application is not allowed to access from this IP (${request.ip})`, + ); + } + + //TODO Check application access rights (write, read, remove for each micro services) + const _access = app.access; + + //TODO save some statistics about API usage for application and per companies + + const route = request.url.replace("/api/", "/internal/services/"); + + fastify.inject( + { + method: request.method as HTTPMethods, + url: route, + payload: request.body as any, + headers: _.pick(request.headers, "authorization"), + }, + (err, response) => { + reply.headers(response.headers); + reply.send(response.payload); + }, + ); + } +} + +function getExecutionContext(request: FastifyRequest): ApplicationApiExecutionContext { + return { + application_id: request.currentUser?.application_id, + user: request.currentUser, + url: request.url, + method: request.routerMethod, + transport: "http", + }; +} diff --git a/twake/backend/node/src/services/applications-api/web/index.ts b/twake/backend/node/src/services/applications-api/web/index.ts new file mode 100644 index 00000000..de7176c9 --- /dev/null +++ b/twake/backend/node/src/services/applications-api/web/index.ts @@ -0,0 +1,10 @@ +import { FastifyInstance, FastifyRegisterOptions } from "fastify"; +import routes from "./routes"; + +export default ( + fastify: FastifyInstance, + options: FastifyRegisterOptions<{ prefix: string }>, +): void => { + fastify.log.debug("Configuring /internal/services/applications/v1 routes"); + fastify.register(routes, options); +}; diff --git a/twake/backend/node/src/services/applications-api/web/routes.ts b/twake/backend/node/src/services/applications-api/web/routes.ts new file mode 100644 index 00000000..3af81dbb --- /dev/null +++ b/twake/backend/node/src/services/applications-api/web/routes.ts @@ -0,0 +1,54 @@ +import { FastifyInstance, FastifyPluginCallback, FastifyRequest } from "fastify"; + +import { ApplicationsApiController } from "./controllers"; +import { ApplicationApiBaseRequest } from "./types"; +import { logger as log } from "../../../core/platform/framework"; +import { configureRequestSchema } from "./schemas"; + +const routes: FastifyPluginCallback = (fastify: FastifyInstance, options, next) => { + const controller = new ApplicationsApiController(); + + const checkApplication = async (request: FastifyRequest<{ Body: ApplicationApiBaseRequest }>) => { + if (!request.currentUser.application_id) { + log.debug(request.currentUser); + throw fastify.httpErrors.forbidden("You should log in as application"); + } + }; + + //Authenticate the application + fastify.route({ + method: "POST", + url: "/console/v1/login", + handler: controller.token.bind(controller), + }); + + //Get myself as an application + fastify.route({ + method: "GET", + url: "/console/v1/me", + preValidation: [fastify.authenticate], + preHandler: [checkApplication], + handler: controller.me.bind(controller), + }); + + //Open a configuration popup on the client side + fastify.route({ + method: "POST", + url: "/console/v1/configure", + preValidation: [fastify.authenticate], + schema: configureRequestSchema, + handler: controller.configure.bind(controller), + }); + + //Get myself as an application + fastify.route({ + method: ["POST", "GET", "DELETE", "PUT"], + url: "/:service/:version/companies/:company_id/*", + preValidation: [fastify.authenticate], + handler: (request, reply) => controller.proxy.bind(controller)(request, reply, fastify), + }); + + next(); +}; + +export default routes; diff --git a/twake/backend/node/src/services/applications-api/web/schemas.ts b/twake/backend/node/src/services/applications-api/web/schemas.ts new file mode 100644 index 00000000..1ee1b370 --- /dev/null +++ b/twake/backend/node/src/services/applications-api/web/schemas.ts @@ -0,0 +1,16 @@ +export const applicationsSchema = { + type: "object", + properties: {}, +}; + +export const configureRequestSchema = { + body: { + type: "object", + properties: { + user_id: { type: "string" }, + connection_id: { type: "string" }, + form: {}, + }, + required: ["user_id", "connection_id"], + }, +}; diff --git a/twake/backend/node/src/services/applications-api/web/types.ts b/twake/backend/node/src/services/applications-api/web/types.ts new file mode 100644 index 00000000..04556d9e --- /dev/null +++ b/twake/backend/node/src/services/applications-api/web/types.ts @@ -0,0 +1,23 @@ +import { AccessToken } from "../../../utils/types"; +import { ExecutionContext } from "../../../core/platform/framework/api/crud-service"; + +export interface ApplicationApiBaseRequest { + id: string; + secret: string; +} + +export type ApplicationLoginRequest = ApplicationApiBaseRequest; + +export interface ApplicationLoginResponse { + access_token: AccessToken; +} + +export interface ApplicationApiExecutionContext extends ExecutionContext { + application_id: string; +} + +export interface ConfigureRequest { + user_id: string; + connection_id: string; + form?: any; +} diff --git a/twake/backend/node/src/services/applications/entities/application.search.ts b/twake/backend/node/src/services/applications/entities/application.search.ts new file mode 100644 index 00000000..669e0245 --- /dev/null +++ b/twake/backend/node/src/services/applications/entities/application.search.ts @@ -0,0 +1,33 @@ +import Application, { TYPE } from "./application"; + +export default { + index: TYPE, + source: (entity: Application) => { + return { + company_id: entity.company_id, + name: entity.identity.name, + description: entity.identity.description, + categories: entity.identity.categories, + compatibility: entity.identity.compatibility, + published: entity.publication.published, + created_at: entity.stats.created_at, + }; + }, + mongoMapping: { + text: { + name: "text", + description: "text", + }, + }, + esMapping: { + properties: { + company_id: { type: "keyword" }, + name: { type: "text", index_prefixes: { min_chars: 1 } }, + description: { type: "text" }, + categories: { type: "keyword" }, + compatibility: { type: "keyword" }, + published: { type: "boolean" }, + created_at: { type: "number" }, + }, + }, +}; diff --git a/twake/backend/node/src/services/applications/entities/application.ts b/twake/backend/node/src/services/applications/entities/application.ts new file mode 100644 index 00000000..17cf4f54 --- /dev/null +++ b/twake/backend/node/src/services/applications/entities/application.ts @@ -0,0 +1,211 @@ +import { Type } from "class-transformer"; +import _, { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import search from "./application.search"; + +export const TYPE = "applications"; + +@Entity(TYPE, { + primaryKey: ["id"], + type: TYPE, + search, +}) +export default class Application { + @Type(() => String) + @Column("id", "timeuuid", { generator: "timeuuid" }) + id: string; + + @Type(() => String) + @Column("group_id", "timeuuid") + company_id: string; + + @Column("is_default", "boolean") + is_default: boolean; + + @Column("identity", "json") + identity: ApplicationIdentity; + + //This information is private to the application, make sure not to disclose it + @Column("api", "encoded_json") + api: ApplicationApi; + + @Column("access", "json") + access: ApplicationAccess; + + @Column("display", "json") + display: ApplicationDisplay; + + @Column("publication", "json") + publication: ApplicationPublication; + + @Column("stats", "json") + stats: ApplicationStatistics; + + getPublicObject(): PublicApplicationObject { + const i = _.pick( + this, + "id", + "company_id", + "is_default", + "identity", + "access", + "display", + "publication", + "stats", + ); + + i.is_default = !!i.is_default; + return i; + } + + getApplicationObject(): ApplicationObject { + const i = _.pick( + this, + "id", + "company_id", + "is_default", + "identity", + "access", + "display", + "publication", + "stats", + "api", + ); + + i.is_default = !!i.is_default; + return i; + } +} + +export type PublicApplicationObject = Pick< + Application, + "id" | "company_id" | "is_default" | "identity" | "access" | "display" | "publication" | "stats" +>; + +export type ApplicationObject = Pick< + Application, + | "id" + | "company_id" + | "is_default" + | "identity" + | "access" + | "display" + | "publication" + | "stats" + | "api" +>; + +export type ApplicationPrimaryKey = { id: string }; + +export function getInstance(message: Application): Application { + return merge(new Application(), message); +} + +export type ApplicationIdentity = { + code: string; + name: string; + icon: string; + description: string; + website: string; + categories: string[]; + compatibility: "twake"[]; +}; + +export type ApplicationPublication = { + published: boolean; //Publication accepted // RO + requested: boolean; //Publication requested +}; + +export type ApplicationStatistics = { + created_at: number; // RO + updated_at: number; // RO + version: number; // RO +}; + +export type ApplicationApi = { + hooks_url: string; + allowed_ips: string; + private_key: string; // RO +}; + +type ApplicationScopes = + | "files" + | "applications" + | "workspaces" + | "users" + | "messages" + | "channels"; + +export type ApplicationAccess = { + read: ApplicationScopes[]; + write: ApplicationScopes[]; + delete: ApplicationScopes[]; + hooks: ApplicationScopes[]; +}; + +export type ApplicationDisplay = { + twake: { + files?: { + editor?: { + preview_url: string; //Open a preview inline (iframe) + edition_url: string; //Url to edit the file (full screen) + extensions?: string[]; //Main extensions app can read + // if file was created by the app, then the app is able to edit with or without extension + empty_files?: { + url: string; // "https://[...]/empty.docx"; + filename: string; // "Untitled.docx"; + name: string; // "Word Document"; + }[]; + }; + actions?: //List of action that can apply on a file + { + name: string; + id: string; + }[]; + }; + + //Chat plugin + chat?: { + input?: + | true + | { + icon?: string; //If defined replace original icon url of your app + type?: "file" | "call"; //To add in existing apps folder / default icon + }; + commands?: { + command: string; // my_app mycommand + description: string; + }[]; + actions?: //List of action that can apply on a message + { + name: string; + id: string; + }[]; + }; + + //Allow app to appear as a bot user in direct chat + direct?: + | true + | { + name?: string; + icon?: string; //If defined replace original icon url of your app + }; + + //Display app as a standalone application in a tab + tab?: + | { + url: string; + } + | true; + + //Display app as a standalone application on the left bar + standalone?: + | { + url: string; + } + | true; + + //Define where the app can be configured from + configuration?: ("global" | "channel")[]; + }; +}; diff --git a/twake/backend/node/src/services/applications/entities/company-application.ts b/twake/backend/node/src/services/applications/entities/company-application.ts new file mode 100644 index 00000000..7598e05f --- /dev/null +++ b/twake/backend/node/src/services/applications/entities/company-application.ts @@ -0,0 +1,40 @@ +import { Type } from "class-transformer"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import { PublicApplicationObject } from "./application"; + +export const TYPE = "group_app"; + +@Entity(TYPE, { + primaryKey: [["group_id"], "app_id", "id"], + type: TYPE, +}) +export default class CompanyApplication { + @Type(() => String) + @Column("group_id", "timeuuid") + company_id: string; + + @Type(() => String) + @Column("app_id", "timeuuid") + application_id: string; + + @Type(() => String) + @Column("id", "timeuuid", { generator: "timeuuid" }) + id: string; + + @Column("created_at", "number") + created_at: number; + + @Type(() => String) + @Column("created_by", "string") + created_by: string; //Will be the default delegated user when doing actions on Twake +} + +export type CompanyApplicationPrimaryKey = Pick< + CompanyApplication, + "company_id" | "application_id" | "id" +>; + +export class CompanyApplicationWithApplication extends CompanyApplication { + //Not in database but attached to this object + application?: PublicApplicationObject; +} diff --git a/twake/backend/node/src/services/applications/index.ts b/twake/backend/node/src/services/applications/index.ts new file mode 100644 index 00000000..7c73c6a8 --- /dev/null +++ b/twake/backend/node/src/services/applications/index.ts @@ -0,0 +1,24 @@ +import { Prefix, TwakeService } from "../../core/platform/framework"; +import WebServerAPI from "../../core/platform/services/webserver/provider"; +import web from "./web"; + +@Prefix("/internal/services/applications/v1") +export default class ApplicationsService extends TwakeService { + version = "1"; + name = "applications"; + + public async doInit(): Promise { + const fastify = this.context.getProvider("webserver").getServer(); + fastify.register((instance, _opts, next) => { + web(instance, { prefix: this.prefix }); + next(); + }); + + return this; + } + + // TODO: remove + api(): undefined { + return undefined; + } +} diff --git a/twake/backend/node/src/services/applications/realtime.ts b/twake/backend/node/src/services/applications/realtime.ts new file mode 100644 index 00000000..074f8a3e --- /dev/null +++ b/twake/backend/node/src/services/applications/realtime.ts @@ -0,0 +1,13 @@ +import { WebsocketMetadata } from "../../utils/types"; + +export function getCompanyApplicationRooms(companyId: string): WebsocketMetadata[] { + return [ + { + room: getCompanyApplicationRoom(companyId), + }, + ]; +} + +export function getCompanyApplicationRoom(companyApplicationId: string): string { + return `/company-application/${companyApplicationId}`; +} diff --git a/twake/backend/node/src/services/applications/services/applications.ts b/twake/backend/node/src/services/applications/services/applications.ts new file mode 100644 index 00000000..4eecdd8f --- /dev/null +++ b/twake/backend/node/src/services/applications/services/applications.ts @@ -0,0 +1,143 @@ +import Application, { + ApplicationPrimaryKey, + getInstance as getApplicationInstance, + PublicApplicationObject, + TYPE, +} from "../entities/application"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import { Initializable, logger, TwakeServiceProvider } from "../../../core/platform/framework"; +import { + DeleteResult, + ExecutionContext, + ListResult, + OperationType, + Pagination, + SaveResult, +} from "../../../core/platform/framework/api/crud-service"; +import SearchRepository from "../../../core/platform/services/search/repository"; +import assert from "assert"; + +import gr from "../../global-resolver"; +import { InternalToHooksProcessor } from "./internal-event-to-hooks"; + +export class ApplicationServiceImpl implements TwakeServiceProvider, Initializable { + version: "1"; + repository: Repository; + searchRepository: SearchRepository; + + async init(): Promise { + try { + this.searchRepository = gr.platformServices.search.getRepository( + TYPE, + Application, + ); + this.repository = await gr.database.getRepository(TYPE, Application); + } catch (err) { + console.log(err); + logger.error("Error while initializing applications service"); + } + + gr.platformServices.messageQueue.processor.addHandler(new InternalToHooksProcessor()); + + return this; + } + + async get(pk: ApplicationPrimaryKey, context: ExecutionContext): Promise { + return await this.repository.findOne(pk, {}, context); + } + + async list( + pagination: Pagination, + options?: { search?: string }, + context?: ExecutionContext, + ): Promise> { + let entities: ListResult; + if (options.search) { + entities = await this.searchRepository.search( + {}, + { + pagination, + $text: { + $search: options.search, + }, + }, + context, + ); + } else { + entities = await this.repository.find({}, { pagination }, context); + } + entities.filterEntities(app => app.publication.published); + + const applications = entities + .getEntities() + .filter(app => app) + .map(app => app.getPublicObject()); + return new ListResult(entities.type, applications, entities.nextPage); + } + + async listUnpublished(context: ExecutionContext): Promise { + const entities = await this.repository.find({}, {}, context); + entities.filterEntities(app => !app.publication.published); + return entities.getEntities(); + } + + async listDefaults(context: ExecutionContext): Promise> { + const entities = []; + + let page: Pagination = { limitStr: "100" }; + do { + const applicationListResult = await this.repository.find({}, { pagination: page }, context); + page = applicationListResult.nextPage as Pagination; + applicationListResult.filterEntities(app => app.publication.published && app.is_default); + + for (const application of applicationListResult.getEntities()) { + if (application) entities.push(application.getPublicObject()); + } + } while (page.page_token); + + return new ListResult(TYPE, entities); + } + + async save( + item: Application, + options?: SaveOptions, + context?: ExecutionContext, + ): Promise> { + assert(item.company_id, "company_id is not defined"); + + try { + const entity = getApplicationInstance(item); + await this.repository.save(entity, context); + return new SaveResult("application", entity, OperationType.UPDATE); + } catch (e) { + throw e; + } + } + + async delete( + pk: ApplicationPrimaryKey, + context?: ExecutionContext, + ): Promise> { + const entity = await this.get(pk, context); + await this.repository.remove(entity, context); + return new DeleteResult("application", entity, true); + } + + async publish(pk: ApplicationPrimaryKey, context: ExecutionContext): Promise { + const entity = await this.get(pk, context); + if (!entity) { + throw new Error("Entity not found"); + } + entity.publication.published = true; + await this.repository.save(entity, context); + } + + async unpublish(pk: ApplicationPrimaryKey, context: ExecutionContext): Promise { + const entity = await this.get(pk, context); + if (!entity) { + throw new Error("Entity not found"); + } + entity.publication.published = false; + await this.repository.save(entity, context); + } +} diff --git a/twake/backend/node/src/services/applications/services/company-applications.ts b/twake/backend/node/src/services/applications/services/company-applications.ts new file mode 100644 index 00000000..5ae82621 --- /dev/null +++ b/twake/backend/node/src/services/applications/services/company-applications.ts @@ -0,0 +1,188 @@ +import CompanyApplication, { + CompanyApplicationPrimaryKey, + CompanyApplicationWithApplication, + TYPE, +} from "../entities/company-application"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import { + Initializable, + logger, + RealtimeDeleted, + RealtimeSaved, + TwakeServiceProvider, +} from "../../../core/platform/framework"; +import { + DeleteResult, + ListResult, + OperationType, + Paginable, + Pagination, + SaveResult, +} from "../../../core/platform/framework/api/crud-service"; +import { CompanyExecutionContext } from "../web/types"; +import { getCompanyApplicationRoom } from "../realtime"; +import gr from "../../global-resolver"; + +export class CompanyApplicationServiceImpl implements TwakeServiceProvider, Initializable { + version: "1"; + repository: Repository; + + async init(): Promise { + try { + this.repository = await gr.database.getRepository( + TYPE, + CompanyApplication, + ); + } catch (err) { + console.log(err); + logger.error("Error while initializing applications service"); + } + return this; + } + + // TODO: remove logic from context + async get( + pk: Pick & { id?: string }, + context?: CompanyExecutionContext, + ): Promise { + const companyApplication = await this.repository.findOne( + { + group_id: context ? context.company.id : pk.company_id, + app_id: pk.application_id, + }, + {}, + context, + ); + + const application = await gr.services.applications.marketplaceApps.get( + { + id: pk.application_id, + }, + context, + ); + + return { + ...companyApplication, + application: application, + }; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + @RealtimeSaved((companyApplication, _context) => { + return [ + { + room: getCompanyApplicationRoom(companyApplication.id), + resource: companyApplication, + }, + ]; + }) + async save( + item: Pick, + _?: SaveOptions, + context?: CompanyExecutionContext, + ): Promise> { + if (!context?.user?.id && !context?.user?.server_request) { + throw new Error("Only an user of a company can add an application to a company."); + } + + let operation = OperationType.UPDATE; + let companyApplication = await this.repository.findOne( + { + group_id: context?.company.id, + app_id: item.application_id, + }, + {}, + context, + ); + if (!companyApplication) { + operation = OperationType.CREATE; + + companyApplication = new CompanyApplication(); + companyApplication.company_id = context.company.id; + companyApplication.application_id = item.application_id; + companyApplication.created_at = new Date().getTime(); + companyApplication.created_by = context?.user?.id || ""; + + await this.repository.save(companyApplication, context); + } + + return new SaveResult(TYPE, companyApplication, operation); + } + + async initWithDefaultApplications( + companyId: string, + context: CompanyExecutionContext, + ): Promise { + const defaultApps = await gr.services.applications.marketplaceApps.listDefaults(context); + for (const defaultApp of defaultApps.getEntities()) { + await this.save({ company_id: companyId, application_id: defaultApp.id }, {}, context); + } + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + @RealtimeDeleted((companyApplication, _context) => { + return [ + { + room: getCompanyApplicationRoom(companyApplication.id), + resource: companyApplication, + }, + ]; + }) + async delete( + pk: CompanyApplicationPrimaryKey, + context?: CompanyExecutionContext, + ): Promise> { + const companyApplication = await this.repository.findOne( + { + group_id: context.company.id, + app_id: pk.application_id, + }, + {}, + context, + ); + + let deleted = false; + if (companyApplication) { + this.repository.remove(companyApplication, context); + deleted = true; + } + + return new DeleteResult(TYPE, companyApplication, deleted); + } + + async list( + pagination: Paginable, + options?: ListOptions, + context?: CompanyExecutionContext, + ): Promise> { + const companyApplications = await this.repository.find( + { + group_id: context.company.id, + }, + { pagination: Pagination.fromPaginable(pagination) }, + context, + ); + + const applications = []; + + for (const companyApplication of companyApplications.getEntities()) { + const application = await gr.services.applications.marketplaceApps.get( + { + id: companyApplication.application_id, + }, + context, + ); + if (application) + applications.push({ + ...companyApplication, + application: application, + }); + } + + return new ListResult( + TYPE, + applications, + companyApplications.nextPage, + ); + } +} diff --git a/twake/backend/node/src/services/applications/services/hooks.ts b/twake/backend/node/src/services/applications/services/hooks.ts new file mode 100644 index 00000000..d34a5f15 --- /dev/null +++ b/twake/backend/node/src/services/applications/services/hooks.ts @@ -0,0 +1,96 @@ +import Application from "../entities/application"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import { + Initializable, + logger as log, + TwakeServiceProvider, +} from "../../../core/platform/framework"; +import { CrudException, ExecutionContext } from "../../../core/platform/framework/api/crud-service"; +import SearchRepository from "../../../core/platform/services/search/repository"; +import axios from "axios"; +import * as crypto from "crypto"; +import { isObject } from "lodash"; +import gr from "../../global-resolver"; + +export class ApplicationHooksService implements TwakeServiceProvider, Initializable { + version: "1"; + repository: Repository; + searchRepository: SearchRepository; + + async init() { + return this; + } + + async notifyApp( + application_id: string, + connection_id: string, + user_id: string, + type: string, + name: string, + content: any, + company_id: string, + workspace_id: string, + context: ExecutionContext, + ): Promise { + const app = await gr.services.applications.marketplaceApps.get({ id: application_id }, context); + if (!app) { + throw CrudException.notFound("Application not found"); + } + + if (!app.api.hooks_url) { + throw CrudException.badRequest("Application hooks_url is not defined"); + } + + const payload = { + type, + name, + content, + connection_id: connection_id, + user_id: user_id, + company_id, + workspace_id, + }; + + const signature = crypto + .createHmac("sha256", app.api.private_key) + .update(JSON.stringify(payload)) + .digest("hex"); + + return await axios + .post(app.api.hooks_url, payload, { + headers: { + "Content-Type": "application/json", + "X-Twake-Signature": signature, + }, + }) + + .then(({ data }) => data) + .catch(e => { + log.error(e.message); + const r = e.response; + + if (!r) { + throw CrudException.badGateway("Can't connect remote application"); + } + + let msg = r.data; + + if (isObject(msg)) { + // parse typical responses + if (r.data.message) { + msg = r.data.message; + } else if (r.data.error) { + msg = r.data.error; + } else { + msg = JSON.stringify(r.data); + } + } + + if (r.status == 403) { + throw CrudException.forbidden(msg); + } else { + throw CrudException.badRequest(msg); + } + }); + } +} diff --git a/twake/backend/node/src/services/applications/services/internal-event-to-hooks.ts b/twake/backend/node/src/services/applications/services/internal-event-to-hooks.ts new file mode 100644 index 00000000..77fe8d74 --- /dev/null +++ b/twake/backend/node/src/services/applications/services/internal-event-to-hooks.ts @@ -0,0 +1,64 @@ +import { logger } from "../../../core/platform/framework"; +import { HookType } from "../../applications-api/types"; +import { MessageQueueHandler } from "../../../core/platform/services/message-queue/api"; +import { MessageHook } from "../../messages/types"; +import gr from "../../global-resolver"; +import { ExecutionContext } from "../../../core/platform/framework/api/crud-service"; + +export class InternalToHooksProcessor implements MessageQueueHandler { + readonly topics = { + in: "application:hook:message", + }; + + readonly options = { + unique: true, + ack: true, + queue: "application:hook:message:consumer1", + }; + + readonly name = "Application::InternalToHooksProcessor"; + + validate(_: HookType): boolean { + return true; + } + + async process(message: HookType, context?: ExecutionContext): Promise { + logger.debug(`${this.name} - Receive hook of type ${message.type}`); + + const application = await gr.services.applications.marketplaceApps.get( + { + id: message.application_id, + }, + context, + ); + + //TODO Check application access rights (hooks) + const _access = application.access; + + // Check application still exists in the company + if ( + !(await gr.services.applications.companyApps.get({ + company_id: message.company_id, + application_id: message.application_id, + id: undefined, + })) + ) { + logger.error( + `${this.name} - Application ${message.application_id} not found in company ${message.company_id}`, + ); + return; + } + + await gr.services.applications.hooks.notifyApp( + message.application_id, + null, + null, + "hook", + null, + { message }, + null, + null, + context, + ); + } +} diff --git a/twake/backend/node/src/services/applications/web/controllers/applications.ts b/twake/backend/node/src/services/applications/web/controllers/applications.ts new file mode 100644 index 00000000..418e9a92 --- /dev/null +++ b/twake/backend/node/src/services/applications/web/controllers/applications.ts @@ -0,0 +1,265 @@ +import { FastifyReply, FastifyRequest } from "fastify"; +import { CrudController } from "../../../../core/platform/services/webserver/types"; +import { + PaginationQueryParameters, + ResourceCreateResponse, + ResourceDeleteResponse, + ResourceGetResponse, + ResourceListResponse, + ResourceUpdateResponse, +} from "../../../../utils/types"; +import Application, { + ApplicationObject, + PublicApplicationObject, +} from "../../entities/application"; +import { + CrudException, + ExecutionContext, + Pagination, +} from "../../../../core/platform/framework/api/crud-service"; +import _ from "lodash"; +import { randomBytes } from "crypto"; +import { ApplicationEventRequestBody } from "../types"; +import { logger as log } from "../../../../core/platform/framework"; +import { hasCompanyAdminLevel } from "../../../../utils/company"; +import gr from "../../../global-resolver"; + +export class ApplicationController + implements + CrudController< + ResourceGetResponse, + ResourceUpdateResponse, + ResourceListResponse, + ResourceDeleteResponse + > +{ + async get( + request: FastifyRequest<{ Params: { application_id: string } }>, + ): Promise> { + const context = getExecutionContext(request); + + const entity = await gr.services.applications.marketplaceApps.get( + { + id: request.params.application_id, + }, + context, + ); + + const companyUser = await gr.services.companies.getCompanyUser( + { id: entity.company_id }, + { id: context.user.id }, + ); + + const isAdmin = companyUser && companyUser.role == "admin"; + + return { + resource: isAdmin ? entity.getApplicationObject() : entity.getPublicObject(), + }; + } + + async list( + request: FastifyRequest<{ + Querystring: PaginationQueryParameters & { search: string }; + }>, + ): Promise> { + const entities = await gr.services.applications.marketplaceApps.list(new Pagination(), { + search: request.query.search, + }); + return { + resources: entities.getEntities(), + next_page_token: entities.nextPage.page_token, + }; + } + + async save( + request: FastifyRequest<{ + Params: { application_id: string }; + Body: { resource: Application }; + }>, + _reply: FastifyReply, + ): Promise> { + const context = getExecutionContext(request); + + try { + const app = request.body.resource; + const now = new Date().getTime(); + + let entity: Application; + + if (request.params.application_id) { + entity = await gr.services.applications.marketplaceApps.get( + { + id: request.params.application_id, + }, + context, + ); + + if (!entity) { + throw CrudException.notFound("Application not found"); + } + + entity.publication.requested = app.publication.requested; + if (app.publication.requested === false) { + entity.publication.published = false; + } + + if (entity.publication.published) { + if ( + !_.isEqual( + _.pick(entity, "identity", "api", "access", "display"), + _.pick(app, "identity", "api", "access", "display"), + ) + ) { + throw CrudException.badRequest( + "You can't update applications details while it published", + ); + } + } + + entity.identity = app.identity; + entity.api.hooks_url = app.api.hooks_url; + entity.api.allowed_ips = app.api.allowed_ips; + entity.access = app.access; + entity.display = app.display; + + entity.stats.updated_at = now; + entity.stats.version++; + + const res = await gr.services.applications.marketplaceApps.save(entity); + entity = res.entity; + } else { + // INSERT + + app.is_default = false; + app.publication.published = false; + app.api.private_key = randomBytes(32).toString("base64"); + + app.stats = { + created_at: now, + updated_at: now, + version: 0, + }; + + const res = await gr.services.applications.marketplaceApps.save(app); + entity = res.entity; + } + + return { + resource: entity.getApplicationObject(), + }; + } catch (e) { + log.error(e); + throw e; + } + } + + async delete( + request: FastifyRequest<{ Params: { application_id: string } }>, + reply: FastifyReply, + ): Promise { + const context = getExecutionContext(request); + + const application = await gr.services.applications.marketplaceApps.get( + { + id: request.params.application_id, + }, + context, + ); + + const compUser = await gr.services.companies.getCompanyUser( + { id: application.company_id }, + { id: context.user.id }, + ); + if (!compUser || !hasCompanyAdminLevel(compUser.role)) { + throw CrudException.forbidden("You don't have the rights to delete this application"); + } + + const deleteResult = await gr.services.applications.marketplaceApps.delete( + { + id: request.params.application_id, + }, + context, + ); + + if (deleteResult.deleted) { + reply.code(204); + + return { + status: "success", + }; + } + + return { + status: "error", + }; + } + + async event( + request: FastifyRequest<{ + Body: ApplicationEventRequestBody; + Params: { application_id: string }; + }>, + _reply: FastifyReply, + ): Promise> { + const context = getExecutionContext(request); + + const content = request.body.data; + + const applicationEntity = await gr.services.applications.marketplaceApps.get( + { + id: request.params.application_id, + }, + context, + ); + + if (!applicationEntity) { + throw CrudException.notFound("Application not found"); + } + + const companyUser = gr.services.companies.getCompanyUser( + { id: request.body.company_id }, + { id: context.user.id }, + ); + + if (!companyUser) { + throw CrudException.badRequest( + "You cannot send event to an application from another company", + ); + } + + const applicationInCompany = await gr.services.applications.companyApps.get({ + company_id: request.body.company_id, + application_id: request.params.application_id, + id: undefined, + }); + + if (!applicationInCompany) { + throw CrudException.badRequest("Application isn't installed in this company"); + } + + const hookResponse = await gr.services.applications.hooks.notifyApp( + request.params.application_id, + request.body.connection_id, + context.user.id, + request.body.type, + request.body.name, + content, + request.body.company_id, + request.body.workspace_id, + context, + ); + + return { + resource: hookResponse, + }; + } +} + +function getExecutionContext(request: FastifyRequest): ExecutionContext { + return { + user: request.currentUser, + url: request.url, + method: request.routerMethod, + transport: "http", + }; +} diff --git a/twake/backend/node/src/services/applications/web/controllers/company-applications.ts b/twake/backend/node/src/services/applications/web/controllers/company-applications.ts new file mode 100644 index 00000000..26542e39 --- /dev/null +++ b/twake/backend/node/src/services/applications/web/controllers/company-applications.ts @@ -0,0 +1,119 @@ +import { FastifyReply, FastifyRequest } from "fastify"; + +import { + PaginationQueryParameters, + ResourceDeleteResponse, + ResourceGetResponse, + ResourceListResponse, + ResourceUpdateResponse, +} from "../../../../utils/types"; +import { PublicApplicationObject } from "../../entities/application"; +import { CompanyExecutionContext } from "../types"; +import { CrudController } from "../../../../core/platform/services/webserver/types"; +import { getCompanyApplicationRooms } from "../../realtime"; +import gr from "../../../global-resolver"; + +export class CompanyApplicationController + implements + CrudController< + ResourceGetResponse, + ResourceUpdateResponse, + ResourceListResponse, + ResourceDeleteResponse + > +{ + async get( + request: FastifyRequest<{ Params: { company_id: string; application_id: string } }>, + ): Promise> { + const context = getCompanyExecutionContext(request); + const resource = await gr.services.applications.companyApps.get( + { + application_id: request.params.application_id, + company_id: context.company.id, + id: undefined, + }, + context, + ); + return { + resource: resource?.application, + }; + } + + async list( + request: FastifyRequest<{ + Params: { company_id: string }; + Querystring: PaginationQueryParameters & { search: string }; + }>, + ): Promise> { + const context = getCompanyExecutionContext(request); + const resources = await gr.services.applications.companyApps.list( + request.query, + { search: request.query.search }, + context, + ); + + return { + resources: resources.getEntities().map(ca => ca.application), + next_page_token: resources.nextPage.page_token, + websockets: + gr.platformServices.realtime.sign( + getCompanyApplicationRooms(request.params.company_id), + context.user.id, + ) || [], + }; + } + + async save( + request: FastifyRequest<{ + Params: { company_id: string; application_id: string }; + Body: PublicApplicationObject; + }>, + ): Promise> { + const context = getCompanyExecutionContext(request); + + const resource = await gr.services.applications.companyApps.save( + { application_id: request.params.application_id, company_id: context.company.id }, + {}, + context, + ); + + const app = await gr.services.applications.companyApps.get(resource.entity); + + return { + resource: app.application, + }; + } + + async delete( + request: FastifyRequest<{ Params: { company_id: string; application_id: string } }>, + _reply: FastifyReply, + ): Promise { + const context = getCompanyExecutionContext(request); + const resource = await gr.services.applications.companyApps.delete( + { + application_id: request.params.application_id, + company_id: context.company.id, + id: undefined, + }, + context, + ); + return { + status: resource.deleted ? "success" : "error", + }; + } +} + +function getCompanyExecutionContext( + request: FastifyRequest<{ + Params: { company_id: string }; + }>, +): CompanyExecutionContext { + return { + user: request.currentUser, + company: { id: request.params.company_id }, + url: request.url, + method: request.routerMethod, + reqId: request.id, + transport: "http", + }; +} diff --git a/twake/backend/node/src/services/applications/web/controllers/index.ts b/twake/backend/node/src/services/applications/web/controllers/index.ts new file mode 100644 index 00000000..ef52722d --- /dev/null +++ b/twake/backend/node/src/services/applications/web/controllers/index.ts @@ -0,0 +1 @@ +export * from "./applications"; diff --git a/twake/backend/node/src/services/applications/web/index.ts b/twake/backend/node/src/services/applications/web/index.ts new file mode 100644 index 00000000..3c2df979 --- /dev/null +++ b/twake/backend/node/src/services/applications/web/index.ts @@ -0,0 +1,12 @@ +import { FastifyInstance, FastifyRegisterOptions } from "fastify"; +import routes from "./routes"; + +export default ( + fastify: FastifyInstance, + options: FastifyRegisterOptions<{ + prefix: string; + }>, +): void => { + fastify.log.debug("Configuring /internal/services/applications/v1 routes"); + fastify.register(routes, options); +}; diff --git a/twake/backend/node/src/services/applications/web/routes.ts b/twake/backend/node/src/services/applications/web/routes.ts new file mode 100644 index 00000000..3d5835c7 --- /dev/null +++ b/twake/backend/node/src/services/applications/web/routes.ts @@ -0,0 +1,161 @@ +import { FastifyInstance, FastifyPluginCallback, FastifyRequest } from "fastify"; +import { ApplicationController } from "./controllers/applications"; +import { CompanyApplicationController } from "./controllers/company-applications"; + +import Application from "../entities/application"; +import { applicationEventHookSchema, applicationPostSchema } from "./schemas"; +import { logger as log } from "../../../core/platform/framework"; +import { checkUserBelongsToCompany, hasCompanyAdminLevel } from "../../../utils/company"; +import gr from "../../global-resolver"; + +const applicationsUrl = "/applications"; +const companyApplicationsUrl = "/companies/:company_id/applications"; + +const routes: FastifyPluginCallback = (fastify: FastifyInstance, options, next) => { + const applicationController = new ApplicationController(); + const companyApplicationController = new CompanyApplicationController(); + + const adminCheck = async ( + request: FastifyRequest<{ + Body: { resource: Application }; + Params: { application_id: string }; + }>, + ) => { + try { + let companyId: string = request.body?.resource?.company_id; + + if (request.params.application_id) { + const application = await gr.services.applications.marketplaceApps.get( + { + id: request.params.application_id, + }, + undefined, + ); + + if (!application) { + throw fastify.httpErrors.notFound("Application is not defined"); + } + + companyId = application.company_id; + } + + const userId = request.currentUser.id; + + if (!companyId) { + throw fastify.httpErrors.forbidden(`Company ${companyId} not found`); + } + + const companyUser = await checkUserBelongsToCompany(userId, companyId); + + if (!hasCompanyAdminLevel(companyUser.role)) { + throw fastify.httpErrors.forbidden("You must be an admin of this company"); + } + } catch (e) { + log.error(e); + throw e; + } + }; + + /** + * Applications collection + * Marketplace of applications + */ + + //Get and search list of applications in the marketplace + fastify.route({ + method: "GET", + url: `${applicationsUrl}`, + preValidation: [fastify.authenticate], + // schema: applicationGetSchema, + handler: applicationController.list.bind(applicationController), + }); + + //Get a single application in the marketplace + fastify.route({ + method: "GET", + url: `${applicationsUrl}/:application_id`, + preValidation: [fastify.authenticate], + // schema: applicationGetSchema, + handler: applicationController.get.bind(applicationController), + }); + + //Create application (must be my company application and I must be company admin) + fastify.route({ + method: "POST", + url: `${applicationsUrl}`, + preHandler: [adminCheck], + preValidation: [fastify.authenticate], + schema: applicationPostSchema, + handler: applicationController.save.bind(applicationController), + }); + + //Edit application (must be my company application and I must be company admin) + fastify.route({ + method: "POST", + url: `${applicationsUrl}/:application_id`, + preHandler: [adminCheck], + preValidation: [fastify.authenticate], + schema: applicationPostSchema, + handler: applicationController.save.bind(applicationController), + }); + + // Delete application (must be my company application and I must be company admin) + fastify.route({ + method: "DELETE", + url: `${applicationsUrl}/:application_id`, + preHandler: [adminCheck], + preValidation: [fastify.authenticate], + handler: applicationController.delete.bind(applicationController), + }); + + /** + * Company applications collection + * Company-wide available applications + * (must be my company application and I must be company admin) + */ + + //Get list of applications for a company + fastify.route({ + method: "GET", + url: `${companyApplicationsUrl}`, + preValidation: [fastify.authenticate], + handler: companyApplicationController.list.bind(companyApplicationController), + }); + + //Get one application of a company + fastify.route({ + method: "GET", + url: `${companyApplicationsUrl}/:application_id`, + preValidation: [fastify.authenticate], + handler: companyApplicationController.get.bind(companyApplicationController), + }); + + //Remove an application from a company + fastify.route({ + method: "DELETE", + url: `${companyApplicationsUrl}/:application_id`, + preValidation: [fastify.authenticate], + handler: companyApplicationController.delete.bind(companyApplicationController), + }); + + //Add an application to the company + fastify.route({ + method: "POST", + url: `${companyApplicationsUrl}/:application_id`, + preValidation: [fastify.authenticate], + handler: companyApplicationController.save.bind(companyApplicationController), + }); + + //Application event triggered by a user + fastify.route({ + method: "POST", + url: `${applicationsUrl}/:application_id/event`, + preValidation: [fastify.authenticate], + schema: applicationEventHookSchema, + handler: applicationController.event.bind(applicationController), + }); + + next(); +}; + +export default routes; diff --git a/twake/backend/node/src/services/applications/web/schemas.ts b/twake/backend/node/src/services/applications/web/schemas.ts new file mode 100644 index 00000000..996cea70 --- /dev/null +++ b/twake/backend/node/src/services/applications/web/schemas.ts @@ -0,0 +1,129 @@ +export const applicationsSchema = { + type: "object", + properties: {}, +}; + +const applicationIdentity = { + type: "object", + properties: { + code: { type: "string" }, + name: { type: "string" }, + icon: { type: "string" }, + description: { type: "string" }, + website: { type: "string" }, + categories: { type: "array", items: { type: "string" } }, + compatibility: { type: "array", items: { type: "string" } }, + }, + required: ["code", "name", "icon", "description", "website", "categories", "compatibility"], +}; + +const applicationAccess = { + type: "object", + properties: { + read: { type: "array", items: { type: "string" } }, + write: { type: "array", items: { type: "string" } }, + delete: { type: "array", items: { type: "string" } }, + hooks: { type: "array", items: { type: "string" } }, + }, + required: ["read", "write", "delete", "hooks"], +}; + +const requestApplicationPublication = { + type: "object", + properties: { + requested: { type: "boolean" }, + }, + required: ["requested"], +}; + +const responseApplicationPublication = { + type: "object", + properties: { + published: { type: "boolean" }, + requested: { type: "boolean" }, + }, + required: ["requested", "published"], +}; + +const applicationStats = { + type: "object", + properties: { + created_at: { type: "number" }, + updated_at: { type: "number" }, + version: { type: "number" }, + }, + required: ["created_at", "updated_at", "version"], +}; + +const apiObject = { + type: "object", + properties: { + hooks_url: { type: "string" }, + allowed_ips: { type: "string" }, + private_key: { type: "string" }, + }, + required: ["hooks_url", "allowed_ips"], +}; + +const requestApplicationObject = { + type: "object", + properties: { + company_id: { type: "string" }, + identity: applicationIdentity, + access: applicationAccess, + display: {}, + api: apiObject, + publication: requestApplicationPublication, + }, + required: ["company_id", "identity", "access", "display", "api", "publication"], + additionalProperties: false, +}; + +const responseApplicationObject = { + type: "object", + properties: { + id: { type: "string" }, + is_default: { type: "boolean" }, + company_id: { type: "string" }, + identity: applicationIdentity, + access: applicationAccess, + display: {}, + publication: responseApplicationPublication, + api: apiObject, + stats: applicationStats, + }, + required: [ + "id", + "is_default", + "company_id", + "identity", + "access", + "display", + "publication", + "stats", + ], + additionalProperties: false, +}; + +export const applicationPostSchema = { + body: { type: "object", properties: { resource: requestApplicationObject } }, + response: { + "2xx": { + resource: responseApplicationObject, + }, + }, +}; + +export const applicationEventHookSchema = { + body: { + type: "object", + properties: { + company_id: { type: "string" }, + workspace_id: { type: "string" }, + type: { type: "string" }, + name: { type: "string" }, + content: {}, + }, + required: ["company_id", "workspace_id", "type", "content"], + }, +}; diff --git a/twake/backend/node/src/services/applications/web/types.ts b/twake/backend/node/src/services/applications/web/types.ts new file mode 100644 index 00000000..5a60f3b3 --- /dev/null +++ b/twake/backend/node/src/services/applications/web/types.ts @@ -0,0 +1,15 @@ +import { ExecutionContext } from "../../../core/platform/framework/api/crud-service"; + +export interface CompanyExecutionContext extends ExecutionContext { + company: { id: string }; +} + +export interface ApplicationEventRequestBody { + company_id: string; + workspace_id: string; + connection_id: string; + type: string; + name?: string; + content: any; + data: any; +} diff --git a/twake/backend/node/src/services/channels/entities/channel-activity.ts b/twake/backend/node/src/services/channels/entities/channel-activity.ts new file mode 100644 index 00000000..a354c408 --- /dev/null +++ b/twake/backend/node/src/services/channels/entities/channel-activity.ts @@ -0,0 +1,59 @@ +import { Type } from "class-transformer"; +import { Channel } from "."; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import { ChannelStats } from "../services/channel/types"; +import { ChannelType } from "../types"; + +@Entity("channel_activity", { + primaryKey: [["company_id", "workspace_id"], "channel_id"], + type: "channel_activity", +}) +export class ChannelActivity { + // uuid-v4 + @Type(() => String) + @Column("company_id", "string", { generator: "uuid" }) + company_id: string; + + // "uuid-v4" | "direct" + @Type(() => String) + @Column("workspace_id", "string", { generator: "uuid" }) + workspace_id: string | ChannelType.DIRECT; + + // uuid-v4 + @Type(() => String) + @Column("channel_id", "string", { generator: "uuid" }) + channel_id: string; + + @Column("last_activity", "number") + last_activity: number; + + @Column("stats", "encoded_json") + stats: ChannelStats; + + @Column("last_message", "encoded_json") + last_message: + | null + | Record + | { + date: number; + sender: string; + sender_name: string; + title: string; + text: string; + }; + + /* Not stored in database */ + + channel: Channel; + + public getChannelPrimaryKey(): Channel { + if (this.channel) { + return this.channel; + } + const channel = new Channel(); + channel.id = this.channel_id; + channel.workspace_id = this.workspace_id; + channel.company_id = this.company_id; + return channel; + } +} diff --git a/twake/backend/node/src/services/channels/entities/channel-counters.ts b/twake/backend/node/src/services/channels/entities/channel-counters.ts new file mode 100644 index 00000000..3958848f --- /dev/null +++ b/twake/backend/node/src/services/channels/entities/channel-counters.ts @@ -0,0 +1,35 @@ +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "channel_counters"; + +@Entity(TYPE, { + primaryKey: [["id"], "counter_type", "company_id", "workspace_id"], + type: TYPE, +}) +export class ChannelCounterEntity { + @Column("id", "uuid") + id: string; + + @Column("counter_type", "string") + counter_type: string; + + @Column("company_id", "uuid") + company_id: string; + + @Column("workspace_id", "string") + workspace_id: string; + + @Column("value", "counter") + value: number; +} + +export type ChannelCounterPrimaryKey = Pick< + ChannelCounterEntity, + "id" | "counter_type" | "company_id" | "workspace_id" +>; + +export enum ChannelUserCounterType { + MEMBERS = "members", + MESSAGES = "messages", + GUESTS = "guests", +} diff --git a/twake/backend/node/src/services/channels/entities/channel-member-read-cursors.ts b/twake/backend/node/src/services/channels/entities/channel-member-read-cursors.ts new file mode 100644 index 00000000..1054ad4b --- /dev/null +++ b/twake/backend/node/src/services/channels/entities/channel-member-read-cursors.ts @@ -0,0 +1,34 @@ +import { Type } from "class-transformer"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +@Entity("channel_member_read_cursors", { + primaryKey: [["company_id"], "channel_id", "user_id"], + type: "channel_member_read_cursors", +}) +export class ChannelMemberReadCursors { + /** + * Primary key + */ + @Type(() => String) + @Column("company_id", "uuid", { generator: "uuid" }) + company_id: string; + + /** + * Primary key + */ + @Type(() => String) + @Column("user_id", "uuid") + user_id: string; + + /** + * Primary key + */ + @Type(() => String) + @Column("channel_id", "uuid") + channel_id: string; + + @Column("read_section", "encoded_json") + read_section: ReadSection; +} + +export type ReadSection = [string, string]; diff --git a/twake/backend/node/src/services/channels/entities/channel-member.ts b/twake/backend/node/src/services/channels/entities/channel-member.ts new file mode 100644 index 00000000..77089489 --- /dev/null +++ b/twake/backend/node/src/services/channels/entities/channel-member.ts @@ -0,0 +1,138 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import { ChannelMemberNotificationLevel, ChannelMemberType } from "../types"; +import { UserObject } from "../../../services/user/web/types"; + +/** + * Defines the member <-> channel link and member settings in channel + * Table name is `user_channels` + */ +@Entity("user_channels", { + primaryKey: [["company_id", "workspace_id"], "user_id", "channel_id"], + type: "user_channels", +}) +export class ChannelMember { + /** + * Primary key + */ + @Type(() => String) + @Column("company_id", "uuid", { generator: "uuid" }) + company_id: string; + + /** + * Primary key + * Null for direct channels + */ + @Type(() => String) + @Column("workspace_id", "string") + workspace_id: string; + + /** + * Primary key + */ + @Type(() => String) + @Column("user_id", "uuid") + user_id: string; + + /** + * Primary key + */ + @Type(() => String) + @Column("channel_id", "uuid") + channel_id: string; + + @Column("type", "string") + type: ChannelMemberType = ChannelMemberType.MEMBER; + + /** + * Timestamp in secconds + */ + @Column("last_access", "number") + last_access: number; + + /** + * When last updated + */ + @Column("last_increment", "number") + last_increment: number; + + /** + * Member marked this channel as favorite? + */ + @Column("favorite", "boolean") + favorite = false; + + /** + * Member defined the notification level for the channel + * Defaults to all + */ + @Column("notification_level", "string") + notification_level: ChannelMemberNotificationLevel = ChannelMemberNotificationLevel.ALL; + + /** + * Member expiration in channel (only for guests) + */ + @Column("expiration", "number") + expiration: boolean | number; + + /** + * Every collection entity must have an id, here it is the user_id + */ + @Type(() => String) + @Column("id", "string") + id: string; + + @Column("updated_at", "number", { onUpsert: _ => new Date().getTime() }) + updated_at: number; + + @Column("created_at", "number", { onUpsert: d => d || new Date().getTime() }) + created_at: number; +} + +export type ChannelMemberPrimaryKey = Pick< + ChannelMember, + "channel_id" | "company_id" | "user_id" | "workspace_id" +>; + +export function getChannelMemberInstance(member: Partial): ChannelMember { + return merge(new ChannelMember(), member); +} + +export type ChannelMemberWithUser = ChannelMember & { user: UserObject }; + +/** + * The channel_members table allows to get all the members of a channel. + * Table name is `channel_members` + */ +@Entity("channel_members", { + primaryKey: [["company_id", "workspace_id"], "channel_id", "user_id"], + type: "channel_members", +}) +export class MemberOfChannel { + /** + * Primary key + */ + @Type(() => String) + @Column("company_id", "uuid", { generator: "uuid" }) + company_id: string; + + @Type(() => String) + @Column("workspace_id", "string") + workspace_id: string; + + @Type(() => String) + @Column("user_id", "uuid") + user_id: string; + + @Type(() => String) + @Column("channel_id", "uuid") + channel_id: string; + + @Column("type", "string") + type: ChannelMemberType = ChannelMemberType.MEMBER; +} + +export function getMemberOfChannelInstance(member: Partial): MemberOfChannel { + return merge(new MemberOfChannel(), member); +} diff --git a/twake/backend/node/src/services/channels/entities/channel-pending-emails.ts b/twake/backend/node/src/services/channels/entities/channel-pending-emails.ts new file mode 100644 index 00000000..0baa6197 --- /dev/null +++ b/twake/backend/node/src/services/channels/entities/channel-pending-emails.ts @@ -0,0 +1,46 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +@Entity("channel_pending_emails", { + primaryKey: [["company_id", "workspace_id"], "channel_id", "email"], + type: "channel_pending_emails", +}) +export class ChannelPendingEmails { + /** + * Primary key + */ + @Type(() => String) + @Column("company_id", "uuid", { generator: "uuid" }) + company_id: string; + + /** + * Primary key + */ + @Type(() => String) + @Column("workspace_id", "uuid") + workspace_id: string; + + /** + * Primary key + */ + @Type(() => String) + @Column("channel_id", "uuid") + channel_id: string; + + /** + * Pending email + */ + @Type(() => String) + @Column("email", "string") + email: string; +} + +export type ChannelPendingEmailsPrimaryKey = Pick< + ChannelPendingEmails, + "channel_id" | "company_id" | "workspace_id" | "email" +>; + +export function getInstance(pendingEmail: ChannelPendingEmails): ChannelPendingEmails { + return merge(new ChannelPendingEmails(), pendingEmail); +} diff --git a/twake/backend/node/src/services/channels/entities/channel.search.ts b/twake/backend/node/src/services/channels/entities/channel.search.ts new file mode 100644 index 00000000..78a7d5be --- /dev/null +++ b/twake/backend/node/src/services/channels/entities/channel.search.ts @@ -0,0 +1,24 @@ +import { Channel } from "./channel"; + +export default { + index: "channels", + source: (entity: Channel) => { + return { + workspace_id: entity.workspace_id, + company_id: entity.company_id, + name: entity.channel_group + " " + entity.name, + }; + }, + mongoMapping: { + text: { + name: "text", + }, + }, + esMapping: { + properties: { + name: { type: "text", index_prefixes: { min_chars: 1 } }, + workspace_id: { type: "keyword" }, + company_id: { type: "keyword" }, + }, + }, +}; diff --git a/twake/backend/node/src/services/channels/entities/channel.ts b/twake/backend/node/src/services/channels/entities/channel.ts new file mode 100644 index 00000000..86c7bbcb --- /dev/null +++ b/twake/backend/node/src/services/channels/entities/channel.ts @@ -0,0 +1,108 @@ +import { Type } from "class-transformer"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import { ChannelType, ChannelVisibility } from "../types"; +import { ChannelMember } from "./channel-member"; +import { UserObject } from "../../user/web/types"; +import { merge } from "lodash"; +import search from "./channel.search"; +import { ChannelActivity } from "./channel-activity"; + +@Entity("channels", { + primaryKey: [["company_id", "workspace_id"], "id"], + type: "channels", + search, +}) +export class Channel { + // uuid-v4 + @Type(() => String) + @Column("company_id", "uuid", { generator: "uuid" }) + company_id: string; + + @Type(() => String) + @Column("workspace_id", "string", { generator: "uuid" }) + workspace_id: string | ChannelType.DIRECT; + + @Type(() => String) + @Column("id", "uuid", { generator: "uuid" }) + id: string; + + @Column("name", "encoded_string") + name: string; + + @Column("icon", "encoded_string") + icon: string; + + @Column("description", "encoded_string") + description: string; + + @Column("channel_group", "encoded_string") + channel_group: string; + + @Column("is_readonly", "boolean") + is_readonly = false; + + @Column("visibility", "encoded_string") + visibility: ChannelVisibility; + + @Column("is_default", "boolean") + is_default = false; + + @Column("archived", "boolean") + archived = false; + + @Column("archivation_date", "number") + archivation_date: number; + + // uuid + @Column("owner", "uuid") + @Type(() => String) + owner: string; + + //This is only used for direct channels + @Column("members", "encoded_json") + members: string[] = []; + + @Column("connectors", "encoded_json") + connectors: string[] = []; //list of app-ids + + @Column("updated_at", "number", { onUpsert: _ => new Date().getTime() }) + updated_at: number; + + @Column("created_at", "number", { onUpsert: d => d || new Date().getTime() }) + created_at: number; + + static isPrivateChannel(channel: Channel): boolean { + return channel.visibility === ChannelVisibility.PRIVATE; + } + + static isPublicChannel(channel: Channel): boolean { + return channel.visibility === ChannelVisibility.PUBLIC; + } + + static isDirectChannel(channel: Channel): boolean { + return ( + channel.visibility === ChannelVisibility.DIRECT || + channel.workspace_id === ChannelVisibility.DIRECT + ); + } + + static isDefaultChannel(channel: Channel): boolean { + return channel?.is_default; + } +} + +export class UserChannel extends Channel { + user_member: ChannelMember; + last_activity: ChannelActivity["last_activity"]; + last_message: ChannelActivity["last_message"]; +} + +export class UsersIncludedChannel extends Channel { + users: UserObject[]; +} + +export function getInstance(channel: Partial): Channel { + return merge(new Channel(), channel); +} + +export type ChannelPrimaryKey = Pick; diff --git a/twake/backend/node/src/services/channels/entities/default-channel.ts b/twake/backend/node/src/services/channels/entities/default-channel.ts new file mode 100644 index 00000000..64c7f60a --- /dev/null +++ b/twake/backend/node/src/services/channels/entities/default-channel.ts @@ -0,0 +1,34 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import { ChannelType } from "../types"; + +@Entity("default_channels", { + primaryKey: [["company_id", "workspace_id"], "channel_id"], + type: "default_channels", +}) +export class DefaultChannel { + // uuid-v4 + @Type(() => String) + @Column("company_id", "string", { generator: "uuid" }) + company_id: string; + + // "uuid-v4" | "direct" + @Type(() => String) + @Column("workspace_id", "string", { generator: "uuid" }) + workspace_id: string | ChannelType.DIRECT; + + // uuid-v4 + @Type(() => String) + @Column("channel_id", "string", { generator: "uuid" }) + channel_id: string; +} + +export type DefaultChannelPrimaryKey = Pick< + DefaultChannel, + "channel_id" | "company_id" | "workspace_id" +>; + +export function getInstance(channel: DefaultChannel): DefaultChannel { + return merge(new DefaultChannel(), channel); +} diff --git a/twake/backend/node/src/services/channels/entities/direct-channel.ts b/twake/backend/node/src/services/channels/entities/direct-channel.ts new file mode 100644 index 00000000..1dd92a35 --- /dev/null +++ b/twake/backend/node/src/services/channels/entities/direct-channel.ts @@ -0,0 +1,47 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +/** + * Direct Channel information. + * A direct channel is a channel in a company composed of a defined set of users. + */ +@Entity("direct_channels", { + primaryKey: [["company_id"], "users", "channel_id"], + type: "direct_channels", +}) +export class DirectChannel { + /** + * The company identifier of this channel + * uuid-v4 + */ + @Type(() => String) + @Column("company_id", "uuid", { generator: "uuid" }) + company_id: string; + + /** + * The link to Channel.id + * uuid-v4 + */ + @Type(() => String) + @Column("channel_id", "string") + channel_id: string; + + /** + * CSV list of ordered user ids + */ + @Column("users", "string") + users: string; + + static getUsersAsString(users: string[] = []): string { + return users.sort().join(","); + } + + static getUsersFromString(identifier: string = ""): string[] { + return identifier.split(","); + } +} + +export function getInstance(channel: DirectChannel): DirectChannel { + return merge(new DirectChannel(), channel); +} diff --git a/twake/backend/node/src/services/channels/entities/index.ts b/twake/backend/node/src/services/channels/entities/index.ts new file mode 100644 index 00000000..41979e79 --- /dev/null +++ b/twake/backend/node/src/services/channels/entities/index.ts @@ -0,0 +1,16 @@ +export * from "./channel"; +export * from "./member"; +export * from "./tab"; +export * from "./channel-member"; +export * from "./channel-member-read-cursors"; +export { + ChannelPendingEmails, + ChannelPendingEmailsPrimaryKey, + getInstance as getChannelPendingEmailsInstance, +} from "./channel-pending-emails"; + +export { + DefaultChannel, + DefaultChannelPrimaryKey, + getInstance as getDefaultChannelInstance, +} from "./default-channel"; diff --git a/twake/backend/node/src/services/channels/entities/member.ts b/twake/backend/node/src/services/channels/entities/member.ts new file mode 100644 index 00000000..74c52b2b --- /dev/null +++ b/twake/backend/node/src/services/channels/entities/member.ts @@ -0,0 +1,6 @@ +import { Type } from "class-transformer"; + +export class Member { + @Type(() => String) + id: string; +} diff --git a/twake/backend/node/src/services/channels/entities/tab.ts b/twake/backend/node/src/services/channels/entities/tab.ts new file mode 100644 index 00000000..01ce1b8c --- /dev/null +++ b/twake/backend/node/src/services/channels/entities/tab.ts @@ -0,0 +1,55 @@ +import { Type } from "class-transformer"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import { ChannelType } from "../types"; + +@Entity("channel_tabs", { + primaryKey: [["company_id", "workspace_id"], "channel_id", "id"], + type: "channel_tabs", +}) +export class ChannelTab { + // uuid-v4 + @Type(() => String) + @Column("company_id", "string", { generator: "uuid" }) + company_id: string; + + // "uuid-v4" | "direct" + @Type(() => String) + @Column("workspace_id", "string", { generator: "uuid" }) + workspace_id: string | ChannelType.DIRECT; + + // uuid-v4 + @Type(() => String) + @Column("channel_id", "string", { generator: "uuid" }) + channel_id: string; + + // uuid-v4 + @Type(() => String) + @Column("id", "string", { generator: "uuid" }) + id: string; + + @Column("name", "encoded_string") + name: string; + + @Column("configuration", "encoded_json") + configuration: string; + + @Column("application_id", "encoded_string") + application_id: string; + + @Column("owner", "encoded_string") + owner: string; + + @Column("col_order", "encoded_string") + order: string; + + @Column("updated_at", "number", { onUpsert: _ => new Date().getTime() }) + updated_at: number; + + @Column("created_at", "number", { onUpsert: d => d || new Date().getTime() }) + created_at: number; +} + +export type ChannelTabPrimaryKey = Pick< + ChannelTab, + "company_id" | "workspace_id" | "channel_id" | "id" +>; diff --git a/twake/backend/node/src/services/channels/index.ts b/twake/backend/node/src/services/channels/index.ts new file mode 100644 index 00000000..1aec35f8 --- /dev/null +++ b/twake/backend/node/src/services/channels/index.ts @@ -0,0 +1,23 @@ +import { Prefix, TwakeService } from "../../core/platform/framework"; +import WebServerAPI from "../../core/platform/services/webserver/provider"; +import web from "./web"; + +@Prefix("/internal/services/channels/v1") +export default class ChannelService extends TwakeService { + version = "1"; + name = "channels"; + + public async doInit(): Promise { + const fastify = this.context.getProvider("webserver").getServer(); + fastify.register((instance, _opts, next) => { + web(instance, { prefix: this.prefix }); + next(); + }); + return this; + } + + // TODO: remove + api(): undefined { + return undefined; + } +} diff --git a/twake/backend/node/src/services/channels/services/channel/activities/service.ts b/twake/backend/node/src/services/channels/services/channel/activities/service.ts new file mode 100644 index 00000000..0314e3af --- /dev/null +++ b/twake/backend/node/src/services/channels/services/channel/activities/service.ts @@ -0,0 +1,223 @@ +import { getLogger, Initializable } from "../../../../../core/platform/framework"; +import { localEventBus } from "../../../../../core/platform/framework/event-bus"; +import { Channel as ChannelEntity, ChannelMember } from "../../../entities/"; +import { ResourceEventsPayload } from "../../../../../utils/types"; +import { ActivityObjectType, ActivityPublishedType } from "./types"; +import _, { sortBy } from "lodash"; +import { MessageQueueServiceAPI } from "../../../../../core/platform/services/message-queue/api"; +import { ChannelParameters } from "../../../web/types"; +import { ChannelVisibility } from "../../../types"; + +const logger = getLogger("channel.activities"); +export default class Activities implements Initializable { + messageQueue: MessageQueueServiceAPI; + + async init(): Promise { + const channelConnectorCreatedEvent = "channel:connector:created"; + const channelConnectorDeletedEvent = "channel:connector:deleted"; + const channelMemberCreatedEvent = "channel:member:created"; + const channelMemberDeletedEvent = "channel:member:deleted"; + const channelTabCreatedEvent = "channel:tab:created"; + const channelTabDeletedEvent = "channel:tab:deleted"; + const channelUpdatedEvent = "channel:updated"; + + localEventBus.subscribe(channelMemberCreatedEvent, data => { + if (data.channel.visibility === ChannelVisibility.DIRECT) { + return; + } + //Fixme: We don't show activity from user himself, + // in the future when we aggregate activities then we could keep it, + // but for now it is polution in the channel + if ((data.resourcesAfter[0] as ChannelMember).user_id === data.actor.id) { + return; + } + this.notify( + channelMemberCreatedEvent, + { + type: "channel:activity:member:created", + actor: { + type: "user", + id: data.actor.id, + }, + context: { + type: "add", + array: [ + // data.actor.id !== data.member.user_id ? "invite" : "join" + { type: "member", resource: data.resourcesAfter[0] }, + ], + }, + }, + data.channel, + ); + }); + + localEventBus.subscribe(channelMemberDeletedEvent, data => { + if (data.channel.visibility === ChannelVisibility.DIRECT) { + return; + } + //Do not notify when user leave the channel by themselves + if (data.resourcesBefore[0].id === data.actor.id) { + return; + } + this.notify( + channelMemberDeletedEvent, + { + type: "channel:activity:member:deleted", + actor: { + type: "user", + id: data.actor.id, + }, + context: { + type: "remove", + array: [{ type: "member", resource: data.resourcesBefore[0] }], + }, + }, + data.channel, + ); + }); + + localEventBus.subscribe(channelUpdatedEvent, data => { + const interestedChanges = ["channel_group", "name", "description", "visibility", "icon"]; + const channelChanged = !_.isEqual( + _.pick(data.resourcesBefore[0], interestedChanges), + _.pick(data.resourcesAfter[0], interestedChanges), + ); + + const connectorsBefore: Partial = _.pick(data.resourcesBefore[0], [ + "connectors", + ]); + + const connectorsAfter: Partial = _.pick(data.resourcesAfter[0], [ + "connectors", + ]); + + const isConnectorCreated: boolean = + connectorsBefore?.connectors.length < connectorsAfter?.connectors.length; + + const channelConnectorsChanged = !_.isEqual( + { connectors: sortBy(connectorsBefore.connectors) }, + { connectors: sortBy(connectorsAfter.connectors) }, + ); + + if (channelConnectorsChanged) { + return localEventBus.publish( + isConnectorCreated ? "channel:connector:created" : "channel:connector:deleted", + data, + ); + } + + if (channelChanged) { + return this.notify( + channelUpdatedEvent, + { + type: "channel:activity:updated", + actor: { + type: "user", + id: data.actor.id, + }, + context: { + type: "diff", + previous: { type: "channel", resource: data.resourcesBefore[0] }, + next: { type: "channel", resource: data.resourcesAfter[0] }, + }, + }, + data.channel, + ); + } + }); + + localEventBus.subscribe(channelTabCreatedEvent, data => + this.notify( + channelTabCreatedEvent, + { + type: "channel:activity:tab:created", + actor: { + type: "user", + id: data.actor.id, + }, + context: { + type: "add", + array: [{ type: "tab", resource: data.resourcesAfter[0] }], + }, + }, + data.channelParameters, + ), + ); + + localEventBus.subscribe(channelTabDeletedEvent, data => + this.notify( + channelTabDeletedEvent, + { + type: "channel:activity:tab:deleted", + actor: { + type: "user", + id: data.actor.id, + }, + context: { + type: "remove", + array: [{ type: "tab", resource: data.resourcesAfter[0] }], + }, + }, + data.channelParameters, + ), + ); + + localEventBus.subscribe(channelConnectorCreatedEvent, data => { + return this.notify( + channelConnectorCreatedEvent, + { + type: "channel:activity:connector:created", + actor: { + type: "user", + id: data.actor.id, + }, + context: { + type: "add", + array: [{ type: "connector", resource: data.resourcesAfter[0] }], + }, + }, + data.channel, + ); + }); + + localEventBus.subscribe(channelConnectorDeletedEvent, data => { + this.notify( + channelConnectorDeletedEvent, + { + type: "channel:activity:connector:deleted", + actor: { + type: "user", + id: data.actor.id, + }, + context: { + type: "remove", + array: [{ type: "connector", resource: data.resourcesBefore[0] }], + }, + }, + data.channel, + ); + }); + + return this; + } + + async notify( + event: string, + data: ActivityObjectType, + channel: ChannelEntity | ChannelParameters, + ): Promise { + logger.debug(`Activities - New ${event} event %o`, data); + try { + await this.messageQueue.publish("channel:activity_message", { + data: { + channel_id: channel.id, + workspace_id: channel.workspace_id, + company_id: channel.company_id, + activity: data, + }, + }); + } catch (err) { + logger.warn({ err }, `Activities - Error while publishing to ${event}`); + } + } +} diff --git a/twake/backend/node/src/services/channels/services/channel/activities/types.ts b/twake/backend/node/src/services/channels/services/channel/activities/types.ts new file mode 100644 index 00000000..571fbb60 --- /dev/null +++ b/twake/backend/node/src/services/channels/services/channel/activities/types.ts @@ -0,0 +1,29 @@ +import { Channel, User } from "../../../../../utils/types"; +import { ChannelMember } from "../../../../../services/channels/entities"; + +export type ActorType = { type: string; id: User["id"] }; + +export type ResourceObjectType = { + type: string; + resource: Channel | User | ChannelMember | []; +}; + +export type ContextType = { + type: "add" | "remove" | "diff"; + array?: ResourceObjectType[]; + previous?: ResourceObjectType; + next?: ResourceObjectType; +}; + +export type ActivityObjectType = { + type: string; + actor: ActorType; + context: ContextType; +}; + +export type ActivityPublishedType = { + channel_id: Channel["id"]; + workspace_id: Channel["workspace_id"]; + company_id: Channel["company_id"]; + activity: ActivityObjectType; +}; diff --git a/twake/backend/node/src/services/channels/services/channel/default/listener.ts b/twake/backend/node/src/services/channels/services/channel/default/listener.ts new file mode 100644 index 00000000..9f599e1b --- /dev/null +++ b/twake/backend/node/src/services/channels/services/channel/default/listener.ts @@ -0,0 +1,113 @@ +import { Channel, getDefaultChannelInstance } from "../../../entities"; +import { getLogger, Initializable } from "../../../../../core/platform/framework"; +import { localEventBus } from "../../../../../core/platform/framework/event-bus"; +import { ResourceEventsPayload } from "../../../../../utils/types"; +import DefaultChannelServiceImpl from "./service"; + +const logger = getLogger("channel:default:listener"); + +export default class DefaultChannelListener implements Initializable { + constructor(private service: DefaultChannelServiceImpl) {} + + async init(): Promise { + localEventBus.subscribe( + "channel:created", + this.onChannelCreated.bind(this), + ); + localEventBus.subscribe( + "channel:updated", + this.onChannelUpdated.bind(this), + ); + localEventBus.subscribe( + "channel:deleted", + this.onChannelDeleted.bind(this), + ); + return this; + } + + onChannelDeleted(event: ResourceEventsPayload): void { + logger.debug("Channel has been deleted %o", event.channel); + if (!event.channel || !Channel.isDefaultChannel(event.channel)) { + return; + } + + this.service + .delete( + getDefaultChannelInstance({ + channel_id: event.channel.id, + company_id: event.channel.company_id, + workspace_id: event.channel.workspace_id, + }), + ) + .catch((err: Error) => { + logger.error({ err }, "Default channel %id can not be deleted", event.channel.id); + }); + } + + onChannelUpdated(event: ResourceEventsPayload): void { + logger.debug("Channel has been updated %o", event.channel); + + if (!event.channel || !event.resourcesBefore || !event.resourcesBefore.length) { + return; + } + + const channelUpdatedToDefault = + !Channel.isDefaultChannel(event.resourcesBefore[0] as Channel) && + Channel.isDefaultChannel(event.channel); + + const channelIsNotDefaultAnymore = + Channel.isDefaultChannel(event.resourcesBefore[0] as Channel) && + !Channel.isDefaultChannel(event.channel); + + if (channelUpdatedToDefault) { + logger.debug("Channel %s has been switched to 'default'", event.channel.id); + this.service + .create( + getDefaultChannelInstance({ + channel_id: event.channel.id, + company_id: event.channel.company_id, + workspace_id: event.channel.workspace_id, + }), + undefined, + ) + .catch((err: Error) => { + logger.error({ err }, "Default channel %id can not be updated", event.channel.id); + }); + } + + if (channelIsNotDefaultAnymore) { + logger.debug("Channel %s has been switched to !'default'", event.channel.id); + this.service + .delete( + getDefaultChannelInstance({ + channel_id: event.channel.id, + company_id: event.channel.company_id, + workspace_id: event.channel.workspace_id, + }), + ) + .catch((err: Error) => { + logger.error({ err }, "Default channel %id can not be removed", event.channel.id); + }); + } + } + + onChannelCreated(event: ResourceEventsPayload): void { + if (!event.channel || !Channel.isDefaultChannel(event.channel)) { + return; + } + + logger.debug("Channel %s has been created with 'default' attribute", event.channel.id); + this.service + .create( + getDefaultChannelInstance({ + channel_id: event.channel.id, + company_id: event.channel.company_id, + workspace_id: event.channel.workspace_id, + }), + undefined, + ) + .catch((err: Error) => { + logger.warn({ err }, "Default channel %id can not be created", event.channel.id); + }); + } +} diff --git a/twake/backend/node/src/services/channels/services/channel/default/service.ts b/twake/backend/node/src/services/channels/services/channel/default/service.ts new file mode 100644 index 00000000..64a65684 --- /dev/null +++ b/twake/backend/node/src/services/channels/services/channel/default/service.ts @@ -0,0 +1,260 @@ +import { concat, EMPTY, from, Observable } from "rxjs"; +import { filter, mergeMap, toArray } from "rxjs/operators"; +import Repository from "../../../../../core/platform/services/database/services/orm/repository/repository"; +import { + Channel, + ChannelMember, + DefaultChannel, + DefaultChannelPrimaryKey, +} from "../../../entities"; +import { + CreateResult, + CrudException, + DeleteResult, + ExecutionContext, + ListResult, + Paginable, + SaveResult, + UpdateResult, +} from "../../../../../core/platform/framework/api/crud-service"; +import { ChannelExecutionContext } from "../../../types"; +import DefaultChannelListener from "./listener"; +import { getLogger } from "../../../../../core/platform/framework"; + +import { User } from "../../../../../utils/types"; +import WorkspaceUser from "../../../../workspaces/entities/workspace_user"; +import gr from "../../../../global-resolver"; + +const logger = getLogger("channel.default"); + +export default class DefaultChannelServiceImpl { + version: "1"; + repository: Repository; + listener: DefaultChannelListener; + + async init(): Promise { + this.repository = await gr.database.getRepository("default_channels", DefaultChannel); + this.listener = new DefaultChannelListener(this); + await this.listener.init(); + return this; + } + + async create( + channel: DefaultChannel, + context: ExecutionContext, + ): Promise> { + await this.repository.save(channel, context); + + // Once a default channel has been successfully created, we have to add all the workspace users as member of the channel + // There are several ways to do it: Directly or using pubsub + // Since member service is a channel sub service we can do it directly + // Another good way to be sure that the user is in default channels is to have an endpoint which ensures this... + this.onCreated(channel); + return new CreateResult("default_channel", channel); + } + + get(pk: DefaultChannelPrimaryKey, context: ExecutionContext): Promise { + return this.repository.findOne(pk, {}, context); + } + + update( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + pk: DefaultChannelPrimaryKey, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + item: DefaultChannel, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + context?: ChannelExecutionContext, + ): Promise> { + throw new Error("Method not implemented."); + } + + save?( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + item: DefaultChannel, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + options?: SaveOptions, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + context?: ChannelExecutionContext, + ): Promise> { + throw new Error("Method not implemented."); + } + + async delete( + pk: DefaultChannelPrimaryKey, + context?: ExecutionContext, + ): Promise> { + const defaultChannel = await this.get(pk, context); + + if (!defaultChannel) { + throw CrudException.notFound("Default channel has not been found"); + } + + await this.repository.remove(defaultChannel, context); + + return new DeleteResult("default_channel", defaultChannel, true); + } + + list( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + pagination: Paginable, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + options?: ListOptions, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + context?: ChannelExecutionContext, + ): Promise> { + throw new Error("Method not implemented."); + } + + /** + * @param channel + */ + onCreated(channel: DefaultChannel): void { + logger.debug("Default channel %s: Adding workspace users as members", channel.channel_id); + const members: ChannelMember[] = []; + const subscription = this.addWorkspaceUsersToChannel(channel).subscribe({ + next: member => { + logger.debug( + "Default Channel %s: User %s has been added: %s", + channel.channel_id, + member.user.userId, + member.added, + ); + member.added && members.push(member.member); + }, + error: (err: Error) => { + logger.error({ err }, "Default Channel %s: Error while adding users", channel.channel_id); + }, + complete: () => { + logger.debug( + "Default Channel %s: Workspace users have been added: %o", + channel.channel_id, + members.map(m => m.user_id), + ); + subscription.unsubscribe(); + }, + }); + } + + addWorkspaceUsersToChannel( + channel: DefaultChannelPrimaryKey, + ): Observable<{ user?: WorkspaceUser; member?: ChannelMember; added: boolean; err?: Error }> { + const workspaceUsers$ = gr.services.workspaces.getAllUsers$({ + workspaceId: channel.workspace_id, + }); + + return workspaceUsers$.pipe( + // filter out external workspace users + filter(wsUser => !wsUser.isExternal), + mergeMap(wsUser => + from( + gr.services.channels.members + .addUserToChannels({ id: wsUser.userId }, [ + { + company_id: channel.company_id, + workspace_id: channel.workspace_id, + id: channel.channel_id, + } as Channel, + ]) + .then(result => ({ + user: wsUser, + member: result.getEntities()[0].member, + added: result.getEntities()[0].added, + err: result.getEntities()[0].err, + })) + .catch(err => { + return { user: wsUser, added: false, err }; + }), + ), + ), + ); + } + + async addUserToDefaultChannels( + user: User, + workspace: Required>, + ): Promise> { + if (!user || !workspace) { + throw new Error("Can not add user to default channel (user or workspaces are empty)"); + } + + try { + const companyUser = await gr.services.companies.getCompanyUser( + { id: workspace.company_id }, + user, + ); + + if (!companyUser) { + return []; + } + + // Do not add guest in default channels + if (companyUser.role === "guest") { + logger.debug( + "CompanyUser role is %s, not added in workspace %s", + companyUser.role, + workspace.workspace_id, + ); + return []; + } + + const channels = await this.getDefaultChannels({ + company_id: workspace.company_id, + workspace_id: workspace.workspace_id, + }); + + if (!channels || !channels.length) { + logger.debug("No default channels in workspace %s", workspace.workspace_id); + return []; + } + + logger.info("Adding user %s to channels %s", user, JSON.stringify(channels)); + + const regChannels = channels.map(c => ({ id: c.channel_id, ...c } as any as Channel)); + + return ( + await gr.services.channels.members.addUserToChannels(user, regChannels) + ).getEntities(); + } catch (err) { + logger.error({ err }, "Error while adding user for default channels"); + throw new Error("Error while adding user for default channels"); + } + } + + getDefaultChannels( + workspace: Pick, + pagination?: Paginable, + context?: ExecutionContext, + ): Promise { + return this.getDefaultChannels$(workspace, pagination, context).pipe(toArray()).toPromise(); + } + + getDefaultChannels$( + workspace: Pick, + pagination?: Paginable, + context?: ExecutionContext, + ): Observable { + const list = ( + workspace: Pick, + pagination: Paginable, + ) => { + return this.repository.find( + workspace, + { + pagination: { limitStr: pagination?.limitStr, page_token: pagination?.page_token }, + }, + context, + ); + }; + + return from(list(workspace, pagination)).pipe( + mergeMap(channels => { + const items$ = from(channels.getEntities()); + const next$ = channels?.nextPage?.page_token + ? this.getDefaultChannels$(workspace, channels.nextPage) + : EMPTY; + + return concat(items$, next$); + }), + ); + } +} diff --git a/twake/backend/node/src/services/channels/services/channel/pending-emails/service.ts b/twake/backend/node/src/services/channels/services/channel/pending-emails/service.ts new file mode 100644 index 00000000..d3959550 --- /dev/null +++ b/twake/backend/node/src/services/channels/services/channel/pending-emails/service.ts @@ -0,0 +1,180 @@ +import Repository from "../../../../../core/platform/services/database/services/orm/repository/repository"; +import { + CreateResult, + CrudException, + DeleteResult, + ExecutionContext, + ListResult, + Pagination, + SaveResult, + UpdateResult, +} from "../../../../../core/platform/framework/api/crud-service"; +import { ChannelExecutionContext } from "../../../types"; +import { getLogger } from "../../../../../core/platform/framework"; +import { + Channel, + ChannelPendingEmails, + ChannelPendingEmailsPrimaryKey, + ChannelPrimaryKey, + getChannelPendingEmailsInstance, +} from "../../../entities"; +import { ChannelPendingEmailsListQueryParameters } from "../../../web/types"; +import { plainToClass } from "class-transformer"; +import { NewUserInWorkspaceNotification } from "../types"; +import gr from "../../../../global-resolver"; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const logger = getLogger("channel.pending_emails"); + +export default class ChannelPendingEmailServiceImpl { + version: "1"; + repository: Repository; + + async init(): Promise { + this.repository = await gr.database.getRepository( + "channel_pending_emails", + ChannelPendingEmails, + ); + + return this; + } + + async create( + pendingEmail: ChannelPendingEmails, + context: ExecutionContext, + ): Promise> { + await this.repository.save(pendingEmail, context); + + // Once a channel pending email has been successfully created, we have to add him to all channels of the company that he was invited + //this.onCreated(pendingEmail); + return new CreateResult("channel_pending_emails", pendingEmail); + } + + get( + pk: ChannelPendingEmailsPrimaryKey, + context: ExecutionContext, + ): Promise { + return this.repository.findOne(pk, {}, context); + } + + update( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + pk: ChannelPendingEmailsPrimaryKey, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + item: ChannelPendingEmails, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + context?: ChannelExecutionContext, + ): Promise> { + throw new Error("Method not implemented."); + } + + save?( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + item: ChannelPendingEmails, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + options?: SaveOptions, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + context?: ChannelExecutionContext, + ): Promise> { + throw new Error("Method not implemented."); + } + + async delete( + pk: ChannelPendingEmailsPrimaryKey, + context?: ExecutionContext, + ): Promise> { + const pendingEmail = await this.get(pk, context); + + if (!pendingEmail) { + throw CrudException.notFound("Channel pendingEmail has not been found"); + } + + await this.repository.remove(pendingEmail, context); + + return new DeleteResult("channel_pending_emails", pendingEmail, true); + } + + async list( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + pagination: Pagination, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + options?: ListOptions, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + context?: ChannelExecutionContext, + ): Promise> { + const pk = { + company_id: context.channel.company_id, + workspace_id: context.channel.workspace_id, + channel_id: context.channel.id, + }; + + const result = await this.repository.find(pk, { pagination }, context); + + return new ListResult( + "channel_pending_emails", + result + .getEntities() + .map(pendingMember => + plainToClass(ChannelPendingEmails, { email: pendingMember.email, ...pendingMember }), + ), + result.nextPage, + ); + } + + findPendingEmails( + pk: ChannelPendingEmailsListQueryParameters, + context: ExecutionContext, + ): Promise> { + return this.repository.find(pk, {}, context); + } + + async proccessPendingEmails( + user: NewUserInWorkspaceNotification, + workspace: Required>, + context: ExecutionContext, + ): Promise { + // Get user object + const userObj = await gr.services.users.get({ + id: user.user_id, + }); + + // All pending emails in workspace + const allPendingEmailsInWorkspace = await this.repository.find(workspace, {}, context); + + // Filter pending emails in workspace with user object email + allPendingEmailsInWorkspace.filterEntities(({ email }) => email === userObj.email_canonical); + + // Add user to all channel that he is invited then delete pending email entity + allPendingEmailsInWorkspace + .getEntities() + .forEach(async ({ workspace_id, channel_id, company_id, email }) => { + // Add user to channel + const list = await gr.services.channels.members.addUserToChannels(userObj, [ + { + workspace_id, + company_id, + id: channel_id, + } as Channel, + ]); + + // If added to channel, delete pending email + const isAddedToChannel = list.getEntities()[0].added; + if (isAddedToChannel) { + await this.delete( + getChannelPendingEmailsInstance({ + workspace_id, + company_id, + email, + channel_id, + }), + ); + } + }); + } + + onCreated( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + pendingEmail: ChannelPendingEmails, + ): void { + throw new Error("Method not implemented."); + } +} diff --git a/twake/backend/node/src/services/channels/services/channel/realtime.ts b/twake/backend/node/src/services/channels/services/channel/realtime.ts new file mode 100644 index 00000000..745ebdd3 --- /dev/null +++ b/twake/backend/node/src/services/channels/services/channel/realtime.ts @@ -0,0 +1,52 @@ +import { User, WebsocketMetadata, Workspace } from "../../../../utils/types"; +import { Channel } from "../../entities"; +import { WorkspaceExecutionContext } from "../../types"; +import { isDirectChannel } from "../../utils"; + +export function getWebsocketInformation(channel: Channel): WebsocketMetadata { + return { + name: channel.name, + room: getChannelPath(channel), + }; +} + +export function getWorkspaceRooms(workspace: Workspace, user: User): WebsocketMetadata[] { + return isDirectChannel(workspace) + ? [{ room: getDirectChannelRoomName(workspace, user.id) }] + : [{ room: getPublicRoomName(workspace) }, { room: getPrivateRoomName(workspace, user) }]; +} + +export function getDirectChannelRoomName(workspace: Workspace, userId: string): string { + return `/companies/${workspace.company_id}/workspaces/direct/channels?type=direct&user=${userId}`; +} + +export function getDirectChannelRooms(workspace: Workspace, channel: Channel): string[] { + return (channel.members || []).map(member => getDirectChannelRoomName(workspace, member)); +} + +export function getPrivateRoomName(workspace: Workspace, user: User): string { + return `/companies/${workspace.company_id}/workspaces/${workspace.workspace_id}/channels?type=private&user=${user.id}`; +} + +export function getPublicRoomName(workspace: Workspace): string { + return `/companies/${workspace?.company_id}/workspaces/${workspace?.workspace_id}/channels?type=public`; +} + +export function getRoomName(channel: Channel, context?: WorkspaceExecutionContext): string[] { + return isDirectChannel(channel) + ? getDirectChannelRooms(context.workspace, channel) + : [getPublicRoomName(context.workspace)]; +} + +export function getChannelPath( + channel: Pick, + context?: WorkspaceExecutionContext, +): string { + return `${getChannelsPath(context?.workspace)}/${channel.id}`; +} + +export function getChannelsPath(workspace?: Workspace): string { + return workspace + ? `/companies/${workspace.company_id}/workspaces/${workspace.workspace_id}/channels` + : "/channels"; +} diff --git a/twake/backend/node/src/services/channels/services/channel/service.ts b/twake/backend/node/src/services/channels/services/channel/service.ts new file mode 100644 index 00000000..aeae4ed6 --- /dev/null +++ b/twake/backend/node/src/services/channels/services/channel/service.ts @@ -0,0 +1,987 @@ +import _, { cloneDeep, find } from "lodash"; +import { diff } from "deep-object-diff"; +import { + getLogger, + RealtimeDeleted, + RealtimeSaved, + RealtimeUpdated, +} from "../../../../core/platform/framework"; +import { + CrudException, + DeleteResult, + ExecutionContext, + ListResult, + OperationType, + Pagination, + SaveResult, + UpdateResult, +} from "../../../../core/platform/framework/api/crud-service"; +import { ChannelActivityMessage, ChannelObject, SearchChannelOptions } from "./types"; +import { + Channel, + ChannelMember, + ChannelPrimaryKey, + DefaultChannel, + UserChannel, + UsersIncludedChannel, +} from "../../entities"; +import { getChannelPath, getRoomName } from "./realtime"; +import { ChannelType, ChannelVisibility, WorkspaceExecutionContext } from "../../types"; +import { isWorkspaceAdmin as userIsWorkspaceAdmin } from "../../../../utils/workspace"; +import { ResourceEventsPayload, User } from "../../../../utils/types"; +import { pick } from "../../../../utils/pick"; +import { + DirectChannel, + getInstance as getDirectChannelInstance, +} from "../../entities/direct-channel"; +import { ChannelListOptions, ChannelSaveOptions } from "../../web/types"; +import { isDirectChannel } from "../../utils"; +import { ResourcePath } from "../../../../core/platform/services/realtime/types"; +import Repository, { + FindFilter, +} from "../../../../core/platform/services/database/services/orm/repository/repository"; +import { ChannelActivity } from "../../entities/channel-activity"; +import { localEventBus } from "../../../../core/platform/framework/event-bus"; +import DefaultChannelServiceImpl from "./default/service"; +import { formatUser } from "../../../../utils/users"; +import gr from "../../../global-resolver"; +import { + KnowledgeGraphEvents, + KnowledgeGraphGenericEventPayload, +} from "../../../../core/platform/services/knowledge-graph/types"; +import { ChannelUserCounterType } from "../../entities/channel-counters"; +import { Readable } from "stream"; +import sharp from "sharp"; + +const logger = getLogger("channel.service"); + +export class ChannelServiceImpl { + version: "1"; + activityRepository: Repository; + channelRepository: Repository; + directChannelRepository: Repository; + defaultChannelService: DefaultChannelServiceImpl; + + async init(): Promise { + this.defaultChannelService = new DefaultChannelServiceImpl(); + + try { + this.activityRepository = await gr.database.getRepository( + "channel_activity", + ChannelActivity, + ); + this.channelRepository = await gr.database.getRepository("channels", Channel); + this.directChannelRepository = await gr.database.getRepository( + "direct_channels", + DirectChannel, + ); + } catch (err) { + logger.error({ err }, "Can not initialize channel db service"); + } + + try { + await this.defaultChannelService.init(); + } catch (err) { + logger.warn("Can not initialize default channel service", err); + } + + localEventBus.subscribe("workspace:user:deleted", async data => { + if (data?.user?.id && data?.company?.id) + gr.services.channels.members.ensureUserNotInWorkspaceIsNotInChannel( + data.user, + data.workspace, + undefined, + ); + }); + + return this; + } + + async thumbnail(channelId: string, context?: ExecutionContext): Promise<{ file: Readable }> { + const logoInternalPath = `/channels/${channelId}/thumbnail.jpg`; + const file = await gr.platformServices.storage.read(logoInternalPath, {}, context); + return { file }; + } + + @RealtimeSaved((channel, context) => [ + { + room: ResourcePath.get(getRoomName(channel, context as WorkspaceExecutionContext)), + path: getChannelPath(channel, context as WorkspaceExecutionContext), + }, + ]) + async save( + channel: Channel, + options: ChannelSaveOptions, + context: WorkspaceExecutionContext, + ): Promise> { + let channelToUpdate: Channel; + let channelToSave: Channel; + const mode = channel.id ? OperationType.UPDATE : OperationType.CREATE; + const isDirectChannel = Channel.isDirectChannel(channel); + const isWorkspaceAdmin = + !isDirectChannel && (await userIsWorkspaceAdmin(context.user, context.workspace)); + const isPrivateChannel = Channel.isPrivateChannel(channel); + const isDefaultChannel = Channel.isDefaultChannel(channel); + + channel.workspace_id = context.workspace.workspace_id || channel.workspace_id; + channel.company_id = context.workspace.company_id || channel.company_id; + + if (isDirectChannel) { + channel.visibility = ChannelVisibility.DIRECT; + channel.workspace_id = ChannelVisibility.DIRECT; + } + + if (mode === OperationType.UPDATE) { + logger.debug("Updating channel"); + channelToUpdate = await this.get(this.getPrimaryKey(channel), context); + + if (!channelToUpdate) { + throw CrudException.notFound("Channel not found"); + } + + const isChannelOwner = this.isChannelOwner(channelToUpdate, context.user); + const updatableParameters: Partial> = { + name: true, + description: !isDirectChannel, + icon: !isDirectChannel, + channel_group: !isDirectChannel, + is_default: (isWorkspaceAdmin || isChannelOwner) && !isDirectChannel && !isPrivateChannel, + visibility: !isDirectChannel && (isWorkspaceAdmin || isChannelOwner), + archived: isWorkspaceAdmin || isChannelOwner, + connectors: !isDirectChannel, + is_readonly: isWorkspaceAdmin || isChannelOwner, + }; + + // Diff existing channel and input one, cleanup all the undefined fields for all objects + const channelDiff = diff(channelToUpdate, channel); + const fields = Object.keys(channelDiff) as Array>; + + if (!fields.length) { + throw CrudException.badRequest("Nothing to update"); + } + + const updatableFields = fields.filter(field => updatableParameters[field]); + + if (!updatableFields.length) { + throw CrudException.badRequest("Current user can not update requested fields"); + } + + channelToSave = cloneDeep(channelToUpdate); + + updatableFields.forEach(field => { + if (channel[field] !== undefined) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (channelToSave as any)[field] = channel[field]; + } + }); + + localEventBus.publish("channel:updated", { + actor: context.user, + resourcesBefore: [channelToUpdate], + resourcesAfter: [channel], + channel: channel, + user: context.user, + }); + } + + if (mode === OperationType.CREATE) { + if (isPrivateChannel && isDefaultChannel) { + throw CrudException.badRequest("Private channel can not be default"); + } + + if (isDirectChannel) { + options.members = Array.from(new Set(options?.members || []).add(context.user.id)); + channel.members = options.members; + + logger.info("Direct channel creation with members %o", options.members); + if (context.workspace.workspace_id !== ChannelVisibility.DIRECT) { + throw CrudException.badRequest("Direct Channel creation error: bad workspace"); + } + + const directChannel = await this.getDirectChannelInCompany( + context.workspace.company_id, + options.members, + context, + ); + + if (directChannel) { + logger.debug("Direct channel already exists %o", directChannel); + const existingChannel = await this.channelRepository.findOne( + { + company_id: context.workspace.company_id, + workspace_id: ChannelType.DIRECT, + id: directChannel.channel_id, + }, + {}, + context, + ); + if (existingChannel) { + const last_activity = await this.getChannelActivity(existingChannel, context); + + const saveResult = new SaveResult( + "channels", + ChannelObject.mapTo(existingChannel, { last_activity }), + OperationType.EXISTS, + ); + await this.addContextUserToChannel(context, saveResult); + + return saveResult; + } else { + //Fixme: remove directChannel instance + throw CrudException.badRequest("table inconsistency"); + } + } + } else { + if (!channel.name) { + throw CrudException.badRequest("'name' is required"); + } + } + + channelToSave = channel; + channelToSave.owner = context.user.id; + } + + if (channelToSave.icon && channelToSave.icon.startsWith("data:")) { + const logoInternalPath = `/channels/${channelToSave.id}/thumbnail.jpg`; + const logoPublicPath = `/internal/services/channels/v1/companies/${ + channelToSave.company_id + }/workspaces/${channelToSave.workspace_id}/channels/${ + channelToSave.id + }/thumbnail?t=${new Date().getTime()}`; + + const image = await sharp(Buffer.from(channel.icon.split(",").pop(), "base64")) + .resize(250, 250) + .toBuffer(); + + const s = new Readable(); + s.push(image); + s.push(null); + await gr.platformServices.storage.write(logoInternalPath, s); + + channelToSave.icon = logoPublicPath; + } + + const channelActivity = await this.activityRepository.findOne( + { + channel_id: channel.id, + }, + {}, + context, + ); + + logger.info("Saving channel %o", channelToSave); + await this.channelRepository.save(channelToSave, context); + + if (!isDirectChannel) { + channel.members = []; //Members is specific to direct channels + } + + const saveResult = new SaveResult( + "channel", + { + ...ChannelObject.mapTo(channelToSave), + last_activity: channelActivity?.last_activity || 0, + last_message: channelActivity?.last_message || {}, + }, + mode, + ); + + await this.addContextUserToChannel(context, saveResult); + await this.onSaved(channelToSave, options, context, saveResult, mode); + + // Shortcut to invite members to a channel + if (!isDirectChannel && options.members && options.members.length > 0) { + await gr.services.channels.members.addUsersToChannel( + options.members.map(id => { + return { id }; + }), + saveResult.entity, + context, + ); + } + + return saveResult; + } + + async get(pk: ChannelPrimaryKey, _context?: ExecutionContext): Promise { + const primaryKey = this.getPrimaryKey(pk); + let channel = await this.channelRepository.findOne(primaryKey); + if (!channel) { + channel = await this.channelRepository.findOne({ ...primaryKey, workspace_id: "direct" }); + } + if (!channel) return null; + + const last_activity = await this.getChannelActivity(channel); + + if (channel.visibility === ChannelVisibility.DIRECT) + channel = await this.includeUsersInDirectChannel(channel); + + return ChannelObject.mapTo(channel, { last_activity }); + } + + @RealtimeUpdated((channel, context) => [ + { + room: ResourcePath.get(getRoomName(channel, context as WorkspaceExecutionContext)), + path: getChannelPath(channel, context as WorkspaceExecutionContext), + }, + ]) + async update( + pk: ChannelPrimaryKey, + channel: Channel, + context: ExecutionContext, + ): Promise> { + // TODO: Do the update by hand then save + if (!pk.id) { + throw CrudException.badRequest("Channel id is required for update"); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const mergeChannel: any = { ...channel, ...pk }; + await this.channelRepository.save(mergeChannel as Channel, context); + + return new UpdateResult("channel", ChannelObject.mapTo(mergeChannel)); + } + + @RealtimeDeleted((channel, context) => [ + { + room: ResourcePath.get(getRoomName(channel, context as WorkspaceExecutionContext)), + path: getChannelPath(channel, context as WorkspaceExecutionContext), + }, + ]) + async delete( + pk: ChannelPrimaryKey, + context: WorkspaceExecutionContext, + ): Promise> { + const channelToDelete = await this.channelRepository.findOne( + this.getPrimaryKey(pk), + {}, + context, + ); + + if (!channelToDelete) { + throw new CrudException("Channel not found", 404); + } + + const directChannel = isDirectChannel(channelToDelete); + + if (directChannel) { + throw new CrudException("Direct channel can not be deleted", 400); + } + + const isWorkspaceAdmin = + !directChannel && (await userIsWorkspaceAdmin(context.user, context.workspace)); + const isChannelOwner = this.isChannelOwner(channelToDelete, context.user); + + if (!isWorkspaceAdmin && !isChannelOwner) { + throw new CrudException("Channel can not be deleted", 400); + } + + await this.channelRepository.remove(channelToDelete, context); + const result = new DeleteResult("channel", ChannelObject.mapTo(pk as Channel), true); + + this.onDeleted(channelToDelete, result); + + localEventBus.publish("channel:deleted", { + channel: channelToDelete, + user: context.user, + }); + + return result; + } + + @RealtimeUpdated((channelActivity, context) => { + return [ + { + room: ResourcePath.get( + getRoomName(channelActivity.getChannelPrimaryKey(), context as WorkspaceExecutionContext), + ), + path: getChannelPath( + channelActivity.getChannelPrimaryKey(), + context as WorkspaceExecutionContext, + ), + resource: { + company_id: channelActivity.company_id, + workspace_id: channelActivity.workspace_id, + id: channelActivity.channel_id, + last_activity: channelActivity.last_activity, + last_message: channelActivity.last_message, + }, + }, + ]; + }) + async updateLastActivity( + payload: { + date: number; + channel: ChannelPrimaryKey; + message: ChannelActivityMessage | null; + }, + context: WorkspaceExecutionContext, + ): Promise> { + const channelPK = payload.channel; + const channelActivityMessage = payload.message; + const channel = (await this.channelRepository.findOne( + _.pick(channelPK, "company_id", "workspace_id", "id"), + {}, + context, + )) as ChannelObject & { stats: ChannelObject["stats"] }; + await gr.services.channels.channels.completeWithStatistics([channel]); + + const entity = new ChannelActivity(); + entity.channel_id = channelPK.id; + entity.company_id = channelPK.company_id; + entity.workspace_id = channelPK.workspace_id; + entity.last_activity = payload.date; + entity.stats = channel.stats; + entity.last_message = channelActivityMessage + ? { + date: channelActivityMessage.date, + sender: channelActivityMessage.sender, + sender_name: channelActivityMessage.sender_name, + title: channelActivityMessage.title, + text: channelActivityMessage.text, + } + : null; + + entity.channel = channel; + + logger.info(`Update activity for channel ${entity.channel_id} to ${entity.last_activity}`); + + localEventBus.publish>( + KnowledgeGraphEvents.CHANNEL_UPSERT, + { + id: channel.id, + resource: channel, + links: [], + }, + ); + + await this.activityRepository.save(entity, context); + return new UpdateResult("channel_activity", entity); + } + + public async getChannelActivity(channel: Channel, context?: ExecutionContext): Promise { + let result = 0; + + if (!channel) { + return result; + } + + try { + const activity = await this.activityRepository.findOne( + { + company_id: channel.company_id, + workspace_id: channel.workspace_id, + channel_id: channel.id, + } as ChannelActivity, + {}, + context, + ); + + result = activity?.last_activity || 0; + } catch (error) { + logger.debug(`Can not get channel last activity for channel ${channel.id}`); + } + return result; + } + + public async fillChannelActivities( + channels: Channel[], + context: ExecutionContext, + ): Promise { + const filledChannels: ChannelObject[] = []; + for (const channel of channels) { + const activity = await this.getChannelActivity(channel, context); + const chObj = ChannelObject.mapTo(channel); + chObj.last_activity = activity; + filledChannels.push(chObj); + } + return filledChannels; + } + + async list( + pagination: Pagination, + options: ChannelListOptions, + context: WorkspaceExecutionContext, + ): Promise> { + const isDirectWorkspace = isDirectChannel(context.workspace); + const isWorkspaceAdmin = + !isDirectWorkspace && userIsWorkspaceAdmin(context.user, context.workspace); + const findFilters: FindFilter = { + company_id: context.workspace.company_id, + workspace_id: context.workspace.workspace_id, + }; + + let user_id = context.user.id; + if (context.user.application_id) { + user_id = user_id || options.user_id; + } + + if ((options?.mine || isDirectWorkspace) && user_id) { + if (!context.user.application_id && !context.user.server_request) { + localEventBus.publish("channel:list", { + user: context.user, + company: { + id: context.workspace.company_id, + }, + }); + } + + return this.getChannelsForUsersInWorkspace( + context.workspace.company_id, + context.workspace.workspace_id, + context.user.id, + pagination, + context, + ); + } + + const channels = await this.channelRepository.find(findFilters, { pagination }, context); + channels.filterEntities(channel => channel.visibility !== ChannelVisibility.DIRECT); + + if (!isWorkspaceAdmin && !context.user.server_request) { + channels.filterEntities(channel => channel.visibility === ChannelVisibility.PUBLIC); + } + + return channels; + } + + async getChannelsForUsersInWorkspace( + companyId: string, + workspaceId: string | "direct", + userId: string, + pagination?: Pagination, + context?: ExecutionContext, + ): Promise> { + const isDirectWorkspace = isDirectChannel({ workspace_id: workspaceId }); + const findFilters: FindFilter = { + company_id: companyId, + workspace_id: workspaceId, + }; + + const userChannels = await gr.services.channels.members.listUserChannels( + { id: userId }, + pagination, + { + user: { + id: userId, + }, + workspace: { + workspace_id: workspaceId, + company_id: companyId, + }, + }, + ); + + let activityPerChannel: Map; + const channels = await this.channelRepository.find( + findFilters, + { + $in: [["id", userChannels.getEntities().map(channelMember => channelMember.channel_id)]], + }, + context, + ); + + if (!channels.isEmpty()) { + const activities = await this.activityRepository.find( + findFilters, + { + $in: [["channel_id", channels.getEntities().map(channel => channel.id)]], + }, + context, + ); + + activityPerChannel = new Map( + activities.getEntities().map(activity => [activity.channel_id, activity]), + ); + } else { + activityPerChannel = new Map(); + } + + channels.mapEntities((channel: Channel) => { + const userChannel = find(userChannels.getEntities(), { channel_id: channel.id }); + + const channelActivity = activityPerChannel.get(channel.id); + + return { + ...channel, + ...{ user_member: userChannel }, + last_activity: channelActivity?.last_activity || 0, + last_message: channelActivity?.last_message || {}, + } as unknown as UserChannel; + }); + + if (isDirectWorkspace) { + channels.mapEntities((channel: UserChannel) => { + return { + ...channel, + ...{ + members: channel.members || [], + }, + } as unknown as UserDirectChannel; + }); + } + + return new ListResult( + channels.type, + channels.getEntities() as UserChannel[], + userChannels.nextPage, + ); + } + + async createDirectChannel( + directChannel: DirectChannel, + context: ExecutionContext, + ): Promise { + const instance = getDirectChannelInstance(directChannel); + await this.directChannelRepository.save(instance, context); + + return instance; + } + + getDirectChannel( + directChannel: DirectChannel, + context: ExecutionContext, + ): Promise { + return this.directChannelRepository.findOne(directChannel, {}, context); + } + + async getDirectChannelInCompany( + companyId: string, + users: string[], + context: ExecutionContext, + ): Promise { + const directChannel = await this.directChannelRepository.findOne( + { + company_id: companyId, + users: DirectChannel.getUsersAsString(users), + }, + {}, + context, + ); + + return directChannel; + } + + async getDirectChannelsInCompany( + pagination: Pagination, + company_id: string, + context: ExecutionContext, + ): Promise> { + return await this.channelRepository.find( + { company_id, workspace_id: "direct" }, + { pagination }, + context, + ); + } + + async getDirectChannelsForUsersInCompany( + companyId: string, + userId: string, + context: ExecutionContext, + ): Promise { + const list = await this.directChannelRepository.find( + { + company_id: companyId, + }, + { + $like: [["users", userId]], + }, + context, + ); + + return list.getEntities(); + } + + async markAsRead( + pk: ChannelPrimaryKey, + user: Pick, + context: ExecutionContext, + ): Promise { + const now = Date.now(); + const channel = await this.get(pk, context); + + if (!channel) { + throw CrudException.notFound("Channel not found"); + } + + await this.completeWithStatistics([channel]); + + const member = await gr.services.channels.members.getChannelMember( + user, + channel, + undefined, + context, + ); + + if (!member) { + throw CrudException.badRequest("User is not channel member"); + } + + // Updating the member will also publish a message in the message-queue channel + // This message will be handled in the notification service and will update the notification preferences for the member + // cf this.members.onUpdated + member.last_access = now; + member.last_increment = channel.stats.messages; + const updatedMember = ( + await gr.services.channels.members.save(member, { + channel, + user, + }) + ).entity; + + this.onRead(channel, updatedMember); + + return true; + } + + async markAsUnread( + pk: ChannelPrimaryKey, + user: User, + context: ExecutionContext, + ): Promise { + const channel = await this.get(pk, context); + + if (!channel) { + throw CrudException.notFound("Channel not found"); + } + + const member = await gr.services.channels.members.getChannelMember(user, channel); + + if (!member) { + throw CrudException.badRequest("User is not channel member"); + } + + // do nothing here but send a notification so that notification service is updated... + this.onUnread(channel, member); + + return true; + } + + getDefaultChannels( + workspace: Required>, + ): Promise { + return this.defaultChannelService.getDefaultChannels(workspace); + } + + async addUserToDefaultChannels( + user: User, + workspace: Required>, + ): Promise { + const result = await this.defaultChannelService.addUserToDefaultChannels(user, workspace); + + return result.filter(e => e.added).map(e => e.member); + } + + getPrimaryKey(channelOrPrimaryKey: Channel | ChannelPrimaryKey): ChannelPrimaryKey { + return pick(channelOrPrimaryKey, ...(["company_id", "workspace_id", "id"] as const)); + } + + isChannelOwner(channel: Channel, user: User): boolean { + return channel.owner && String(channel.owner) === user.id; + } + + async addContextUserToChannel( + context: WorkspaceExecutionContext, + result: SaveResult, + ): Promise { + const savedChannel = result.entity; + + //Add requester as member + if (context.user.id) { + try { + await gr.services.channels.members.addUserToChannels({ id: context.user.id }, [ + savedChannel, + ]); + } catch (err) { + logger.warn({ err }, "Can not add requester as channel member"); + } + } + } + + public async includeUsersInDirectChannel( + channel: Channel, + excludeUserId?: string, + ): Promise { + const channelWithUsers: UsersIncludedChannel = { users: [], ...channel }; + if (isDirectChannel(channel)) { + const users = []; + for (const user of channel.members) { + if (user) { + const e = await formatUser(await gr.services.users.getCached({ id: user })); + if (e) users.push(e); + } + } + channelWithUsers.users = users; + channelWithUsers.name = users + .filter(u => u.id != excludeUserId) + .map(u => u.full_name?.trim()) + .filter(a => a) + .join(", "); + } + return channelWithUsers; + } + + /** + * Called when channel update has been successfully called + * + * @param channel The channel before update has been processed + * @param result The channel update result + */ + async onSaved( + channel: Channel, + options: ChannelSaveOptions, + context: WorkspaceExecutionContext, + result: SaveResult, + mode: OperationType.CREATE | OperationType.UPDATE, + ): Promise { + const savedChannel = result.entity; + + if (mode === OperationType.CREATE) { + if (isDirectChannel(channel)) { + const directChannel = { + channel_id: savedChannel.id, + company_id: savedChannel.company_id, + users: DirectChannel.getUsersAsString(options.members), + } as DirectChannel; + + await this.createDirectChannel(directChannel, context); + } else { + if (options.addCreatorAsMember && savedChannel.owner) { + try { + await gr.services.channels.members.addUserToChannels({ id: savedChannel.owner }, [ + savedChannel, + ]); + } catch (err) { + logger.warn({ err }, "Can not add owner as channel member"); + } + } + } + + this.updateLastActivity( + { + date: new Date().getTime(), + channel: channel, + message: null, + }, + context, + ); + + localEventBus.publish("channel:created", { + channel, + user: context.user, + }); + } + } + + /** + * Called when channel delete has been successfully called + * + * @param channel The channel to delete + * @param result The delete result + */ + onDeleted(channel: Channel, result: DeleteResult): void { + if (result.deleted) { + logger.debug("Channel %s has been deleted", channel.id); + } + } + + /** + * Called when a channel as been marked as read. + * Will publish `channel:read` notification in the message-queue service + * + * @param channel + * @param member + */ + onRead(channel: Channel, member: ChannelMember): void { + logger.info(`Channel ${channel.id} as been marked as read for user ${member.id}`); + + gr.platformServices.messageQueue.publish("channel:read", { + data: { + channel, + member, + }, + }); + } + + /** + * Called when a channel as been marked as unread. + * Will publish `channel:unread` notification in the message-queue service + * + * @param channel + * @param member + */ + onUnread(channel: Channel, member: ChannelMember): void { + logger.info(`Channel ${channel.id} as been marked as unread for user ${member.id}`); + + gr.platformServices.messageQueue.publish("channel:unread", { + data: { + channel, + member, + }, + }); + } + + async search( + pagination: Pagination, + options: SearchChannelOptions, + context: ExecutionContext, + ): Promise> { + const rep = gr.platformServices.search.getRepository("channel", Channel); + return rep.search( + {}, + { + pagination, + ...(options.companyId ? { $in: [["company_id", [options.companyId]]] } : {}), + $text: { + $search: options.search, + }, + }, + context, + ); + } + + async getAllChannelsInWorkspace( + company_id: string, + workspace_id: string, + context?: ExecutionContext, + ): Promise { + let pagination = new Pagination(null, "100"); + + const channels: Channel[] = []; + do { + const res = await this.channelRepository.find( + { + company_id: company_id, + workspace_id: workspace_id, + }, + { + pagination, + }, + context, + ); + pagination = new Pagination(res.nextPage.page_token, res.nextPage.limitStr); + channels.push(...res.getEntities()); + } while (pagination.page_token); + + return channels; + } + + async completeWithStatistics( + channels: Pick[], + ) { + await Promise.all( + channels.map(async a => { + const members = await gr.services.channels.members.getUsersCount({ + ..._.pick(a, "id", "company_id", "workspace_id"), + counter_type: ChannelUserCounterType.MEMBERS, + }); + //Fixme: even if it works strange to use "getUsersCount" to get messages count + const messages = await gr.services.channels.members.getUsersCount({ + ..._.pick(a, "id", "company_id", "workspace_id"), + counter_type: ChannelUserCounterType.MESSAGES, + }); + a.stats = { members, messages }; + }), + ); + } +} diff --git a/twake/backend/node/src/services/channels/services/channel/types.ts b/twake/backend/node/src/services/channels/services/channel/types.ts new file mode 100644 index 00000000..76a47855 --- /dev/null +++ b/twake/backend/node/src/services/channels/services/channel/types.ts @@ -0,0 +1,86 @@ +import { merge } from "lodash"; +import { Channel } from "../../entities/channel"; +import { ChannelActivity } from "../../entities/channel-activity"; +import { ChannelMember } from "../../entities"; +import { UserObject } from "../../../user/web/types"; + +export type NewUserInWorkspaceNotification = { + user_id: string; + company_id: string; + workspace_id: string; +}; + +export type ChannelStats = { + members: number; + messages: number; +}; + +type ChannelType = "workspace" | "direct"; + +export class ChannelMemberObject extends ChannelMember { + id: string; + user_id: string; + // type: "member" | "guest" | "bot"; + last_access: number; //Timestamp in seconds + last_increment: number; + favorite: boolean; //Did the user add this channel to its favorites + // notification_level: "all" | "none" | "group_mentions" | "user_mentions"; + + static mapTo( + channelMember: ChannelMember, + channelMemberLikeObject: Partial = {}, + ): ChannelMemberObject { + if (!channelMember) { + return null; + } + + return merge(new ChannelMemberObject(), { + favorite: false, + last_increment: 0, + last_access: 0, + ...channelMember, + ...channelMemberLikeObject, + }); + } +} + +export class ChannelObject extends Channel { + last_activity?: ChannelActivity["last_activity"]; + last_message?: ChannelActivity["last_message"]; + default: boolean; + type: ChannelType; + user_member: ChannelMemberObject; + users: UserObject[]; + stats: ChannelStats; + + constructor() { + super(); + } + + static mapTo(channel: Channel, channelLikeObject: Partial = {}): ChannelObject { + if (!channel) { + return null; + } + + return merge(new ChannelObject(), { + ...{ last_activity: 0 }, + ...channel, + ...channelLikeObject, + ...{ members: channel?.members?.length ? channel.members : [] }, + default: channel.is_default, + }); + } +} + +export type SearchChannelOptions = { + search: string; + companyId?: string; +}; + +export type ChannelActivityMessage = { + date: number; + sender: string; + sender_name: string; + title: string; + text: string; +}; diff --git a/twake/backend/node/src/services/channels/services/member/realtime.ts b/twake/backend/node/src/services/channels/services/member/realtime.ts new file mode 100644 index 00000000..ea6f99eb --- /dev/null +++ b/twake/backend/node/src/services/channels/services/member/realtime.ts @@ -0,0 +1,41 @@ +import { Channel, User, WebsocketMetadata } from "../../../../utils/types"; +import { ChannelMember } from "../../entities"; +import { getChannelPath, getChannelsPath } from "../channel/realtime"; +import { ChannelExecutionContext } from "../../types"; + +export function getPrivateRoomName(channel: Channel, user: User): string { + return `/companies/${channel.company_id}/workspaces/${channel.workspace_id}/channels/${channel.id}?type=private&user=${user.id}`; +} + +export function getPublicRoomName(channel: Channel): string { + return `/companies/${channel.company_id}/workspaces/${channel.workspace_id}/channels/${channel.id}?type=public`; +} + +export function getRoomName(channelOrContext: Channel | ChannelExecutionContext): string { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const channel = (channelOrContext as any).channel + ? (channelOrContext as ChannelExecutionContext).channel + : (channelOrContext as Channel); + + return getPublicRoomName(channel); +} + +export function getMembersPath(channel: Channel): string { + return `${getChannelsPath(channel)}/members`; +} + +export function getMemberPath(member: ChannelMember, context?: ChannelExecutionContext): string { + const parentContext = { + workspace: { + company_id: context?.channel?.company_id, + workspace_id: context?.channel?.workspace_id, + }, + user: context?.user, + }; + + return `${getChannelPath(context.channel, parentContext)}/members/${member.user_id}`; +} + +export function getChannelRooms(channel: Channel, user: User): WebsocketMetadata[] { + return [{ room: getPublicRoomName(channel) }, { room: getPrivateRoomName(channel, user) }]; +} diff --git a/twake/backend/node/src/services/channels/services/member/service.ts b/twake/backend/node/src/services/channels/services/member/service.ts new file mode 100644 index 00000000..e344771d --- /dev/null +++ b/twake/backend/node/src/services/channels/services/member/service.ts @@ -0,0 +1,912 @@ +import { getLogger, RealtimeDeleted, RealtimeSaved } from "../../../../core/platform/framework"; +import { + CreateResult, + CrudException, + DeleteResult, + ExecutionContext, + ListResult, + OperationType, + Pagination, + SaveResult, + UpdateResult, +} from "../../../../core/platform/framework/api/crud-service"; + +import { + Channel as ChannelEntity, + ChannelMember, + ChannelMemberPrimaryKey, + ChannelMemberReadCursors, + getChannelMemberInstance, + getMemberOfChannelInstance, + MemberOfChannel, + ReadSection, +} from "../../entities"; +import { + ChannelExecutionContext, + ChannelMemberType, + ChannelVisibility, + WorkspaceExecutionContext, +} from "../../types"; +import { Channel, ResourceEventsPayload, User } from "../../../../utils/types"; +import { cloneDeep, isNil, omitBy } from "lodash"; +import { updatedDiff } from "deep-object-diff"; +import { pick } from "../../../../utils/pick"; +import { getMemberPath, getRoomName } from "./realtime"; +import { ChannelListOptions } from "../../web/types"; +import { ResourcePath } from "../../../../core/platform/services/realtime/types"; +import Repository from "../../../../core/platform/services/database/services/orm/repository/repository"; +import { localEventBus } from "../../../../core/platform/framework/event-bus"; +import { plainToClass } from "class-transformer"; +import { + ChannelCounterEntity, + ChannelCounterPrimaryKey, + ChannelUserCounterType, + TYPE as ChannelCounterEntityType, +} from "../../entities/channel-counters"; +import { CounterProvider } from "../../../../core/platform/services/counter/provider"; +import { countRepositoryItems } from "../../../../utils/counters"; +import NodeCache from "node-cache"; +import { UserPrimaryKey } from "../../../user/entities/user"; +import { WorkspacePrimaryKey } from "../../../workspaces/entities/workspace"; + +import gr from "../../../global-resolver"; +import uuidTime from "uuid-time"; +import { CompanyExecutionContext } from "../../../../services/messages/types"; +import { ChannelObject } from "../channel/types"; + +const USER_CHANNEL_KEYS = [ + "id", + "company_id", + "workspace_id", + "user_id", + "channel_id", + "type", + "last_access", + "last_increment", + "favorite", + "notification_level", + "expiration", +] as const; + +const CHANNEL_MEMBERS_KEYS = [ + "company_id", + "workspace_id", + "user_id", + "channel_id", + "type", +] as const; + +const logger = getLogger("channel.member"); + +export class MemberServiceImpl { + version: "1"; + userChannelsRepository: Repository; + channelMembersRepository: Repository; + channelMembersReadCursorRepository: Repository; + private channelCounter: CounterProvider; + private cache: NodeCache; + + async init(): Promise { + try { + this.userChannelsRepository = await gr.database.getRepository("user_channels", ChannelMember); + this.channelMembersRepository = await gr.database.getRepository( + "channel_members", + MemberOfChannel, + ); + this.channelMembersReadCursorRepository = await gr.database.getRepository( + "channel_members_read_cursors", + ChannelMemberReadCursors, + ); + } catch (err) { + logger.error({ err }, "Can not initialize channel member service"); + } + + const channelCountersRepository = await gr.database.getRepository( + ChannelCounterEntityType, + ChannelCounterEntity, + ); + + this.channelCounter = await gr.platformServices.counter.getCounter( + channelCountersRepository, + ); + + this.channelCounter.setReviseCallback(async (pk: ChannelCounterPrimaryKey) => { + if (pk.counter_type === ChannelUserCounterType.MESSAGES) { + return; + } + const type = + ChannelUserCounterType.MEMBERS === pk.counter_type + ? ChannelMemberType.MEMBER + : ChannelMemberType.GUEST; + return countRepositoryItems( + this.channelMembersRepository, + { channel_id: pk.id, company_id: pk.company_id, workspace_id: pk.workspace_id }, + { type }, + ); + }, 400); + + this.cache = new NodeCache({ stdTTL: 1, checkperiod: 120 }); + + return this; + } + + @RealtimeSaved((member, context) => { + return [ + //Send member preferences update to channels collections + { + room: `/companies/${member.company_id}/workspaces/${member.workspace_id}/channels?type=${ + member.workspace_id === ChannelVisibility.DIRECT ? "direct" : "private" + }&user=${member.user_id}`, + resource: { + company_id: member.company_id, + workspace_id: member.workspace_id, + id: member.channel_id, + user_member: member, + }, + }, + { + room: ResourcePath.get(getRoomName(context as ChannelExecutionContext)), + path: getMemberPath(member, context as ChannelExecutionContext), + }, + ]; + }) + async save( + member: ChannelMember, + context: ChannelExecutionContext, + ): Promise> { + let memberToSave: ChannelMember; + const channel = await gr.services.channels.channels.get(context.channel, context); + + if (!channel) { + throw CrudException.notFound("Channel does not exists"); + } + + const memberToUpdate = await this.userChannelsRepository.findOne( + this.getPrimaryKey(member), + {}, + context, + ); + const mode = memberToUpdate ? OperationType.UPDATE : OperationType.CREATE; + + logger.debug(`MemberService.save - ${mode} member %o`, memberToUpdate); + + if (mode === OperationType.UPDATE) { + const isCurrentUser = this.isCurrentUser(memberToUpdate, context.user); + + if (!isCurrentUser) { + throw CrudException.badRequest(`Channel member ${member.user_id} can not be updated`); + } + + const updatableParameters: Partial> = { + notification_level: isCurrentUser, + favorite: isCurrentUser, + last_access: isCurrentUser, + last_increment: isCurrentUser, + }; + + // Diff existing channel and input one, cleanup all the undefined fields for all objects + const memberDiff = omitBy(updatedDiff(memberToUpdate, member), isNil); + const fields = Object.keys(memberDiff) as Array>; + + if (!fields.length) { + return new SaveResult("channel_member", member, mode); + } + + const updatableFields = fields.filter(field => updatableParameters[field]); + + if (!updatableFields.length) { + throw CrudException.badRequest("Current user can not update requested fields"); + } + + memberToSave = cloneDeep(memberToUpdate); + + //Ensure it is a boolean + memberToSave.favorite = !!memberToSave.favorite; + + updatableFields.forEach(field => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (memberToSave as any)[field] = member[field]; + }); + + await this.saveChannelMember(memberToSave, context); + this.onUpdated( + context.channel, + memberToSave, + new UpdateResult("channel_member", memberToSave), + ); + } else { + const currentUserIsMember = !!(await this.getChannelMember( + context.user, + channel, + undefined, + context, + )); + const isPrivateChannel = ChannelEntity.isPrivateChannel(channel); + const isPublicChannel = ChannelEntity.isPublicChannel(channel); + const isDirectChannel = ChannelEntity.isDirectChannel(channel); + const userIsDefinedInChannelUserList = (channel.members || []).includes( + String(member.user_id), + ); + const isChannelCreator = context.user && String(channel.owner) === String(context.user.id); + + // 1. Private channel: user can not join private channel by themself when it is private + // only member can add other users in channel + // 2. The channel creator check is only here on channel creation + if ( + isChannelCreator || + isPublicChannel || + context.user.server_request || + (isPrivateChannel && currentUserIsMember) || + (isDirectChannel && userIsDefinedInChannelUserList) + ) { + const memberToSave = { ...member, ...context.channel }; + await this.saveChannelMember(memberToSave, context); + + await this.usersCounterIncrease(channel, member.user_id); + this.onCreated( + channel, + member, + context.user, + new CreateResult("channel_member", memberToSave), + ); + } else { + throw CrudException.badRequest( + `User ${member.user_id} is not allowed to join this channel`, + ); + } + } + + return new SaveResult("channel_member", member, mode); + } + + async get(pk: ChannelMemberPrimaryKey, context: ExecutionContext): Promise { + // FIXME: Who can fetch a single member? + return await this.userChannelsRepository.findOne(this.getPrimaryKey(pk), {}, context); + } + + @RealtimeDeleted((member, context) => [ + { + room: `/companies/${member.company_id}/workspaces/${member.workspace_id}/channels?type=${ + member.workspace_id === ChannelVisibility.DIRECT ? "direct" : "private" + }&user=${member.user_id}`, + resource: { + company_id: member.company_id, + workspace_id: member.workspace_id, + id: member.channel_id, + user_id: member.user_id, + user_member: null, + }, + }, + { + room: ResourcePath.get(getRoomName(context as ChannelExecutionContext)), + path: getMemberPath(member, context as ChannelExecutionContext), + }, + ]) + async delete( + pk: ChannelMemberPrimaryKey, + context: ChannelExecutionContext, + ): Promise> { + const memberToDelete = await this.userChannelsRepository.findOne(pk, {}, context); + const channel = await gr.services.channels.channels.get(context.channel, context); + + if (!channel) { + throw CrudException.notFound("Channel does not exists"); + } + + if (!memberToDelete) { + throw CrudException.notFound("Channel member not found"); + } + + if (ChannelEntity.isDirectChannel(channel)) { + if (!this.isCurrentUser(memberToDelete, context.user)) { + throw CrudException.badRequest("User can not remove other users from direct channel"); + } + } + + if (ChannelEntity.isPrivateChannel(channel)) { + const canLeave = await this.canLeavePrivateChannel(context.user, channel); + + if (!canLeave) { + throw CrudException.badRequest("User can not leave the private channel"); + } + } + + await this.userChannelsRepository.remove(getChannelMemberInstance(pk), context); + await this.channelMembersRepository.remove(getMemberOfChannelInstance(pk), context); + await this.usersCounterIncrease(channel, pk.user_id, -1); + + this.onDeleted(memberToDelete, context.user, channel); + + return new DeleteResult("channel_member", pk as ChannelMember, true); + } + + /** + * List given channel members + */ + async list( + pagination: Pagination, + options: ChannelListOptions, + context: ChannelExecutionContext, + ): Promise> { + const channel = await gr.services.channels.channels.get( + { + company_id: context.channel.company_id, + workspace_id: context.channel.workspace_id, + id: context.channel.id, + }, + context, + ); + + if (!channel) { + throw CrudException.notFound("Channel not found"); + } + + if (ChannelEntity.isDirectChannel(channel) || ChannelEntity.isPrivateChannel(channel)) { + const isMember = await this.getChannelMember(context.user, channel, undefined, context); + + if (!isMember && !context.user.application_id && !context.user.server_request) { + throw CrudException.badRequest("User does not have enough rights to get channels"); + } + } + + const result = await this.channelMembersRepository.find( + { + company_id: context.channel.company_id, + workspace_id: context.channel.workspace_id, + channel_id: context.channel.id, + }, + { pagination }, + context, + ); + + const companyUsers = await gr.services.companies.getUsers( + { + group_id: context.channel.company_id, + }, + new Pagination(), + { userIds: result.getEntities().map(member => member.user_id) }, + ); + + if (options.company_role) { + companyUsers.filterEntities(entity => entity.role === options.company_role); + } + + const companyUserIds = companyUsers.getEntities().map(entity => entity.user_id); + + result.filterEntities(cm => companyUserIds.includes(cm.user_id)); + + return new ListResult( + "channel_member", + result + .getEntities() + .map(member => plainToClass(ChannelMember, { id: member.user_id, ...member })), + result.nextPage, + ); + } + + async listAllUserChannelsIds( + user_id: string, + company_id: string, + workspace_id: string, + context: ExecutionContext, + ): Promise { + let pagination = new Pagination(null); + const channels: string[] = []; + let result: ListResult; + let hasMoreItems = true; + do { + result = await this.userChannelsRepository.find( + { + company_id, + workspace_id, + user_id, + }, + { pagination }, + context, + ); + if (result.isEmpty()) { + hasMoreItems = false; + } else { + result.getEntities().forEach(entity => { + channels.push(entity.channel_id); + }); + if (!result.nextPage.page_token) hasMoreItems = false; + else pagination = new Pagination(result.nextPage.page_token); + } + } while (hasMoreItems); + return channels; + } + + async listUserChannels( + user: User, + pagination: Pagination, + context: WorkspaceExecutionContext, + ): Promise> { + const result = await this.userChannelsRepository.find( + { + company_id: context.workspace.company_id, + workspace_id: context.workspace.workspace_id, + user_id: user.id, + }, + { pagination }, + context, + ); + + return new ListResult( + "channel_member", + result + .getEntities() + .map(member => plainToClass(ChannelMember, { id: member.user_id, ...member })), + result.nextPage, + ); + } + + /** + * Can leave only if the number of members is > 1 + * since counting rows in DB takes too much time + * we query a list for 2 members without offset and check the length + */ + async canLeavePrivateChannel(user: User, channel: ChannelEntity): Promise { + const list = this.list(new Pagination(undefined, "2"), {}, { channel, user }); + + return (await list).getEntities().length > 1; + } + + async addUsersToChannel( + users: Pick[] = [], + channel: ChannelEntity & { stats: ChannelObject["stats"] }, + context?: ExecutionContext, + ): Promise< + ListResult<{ channel: ChannelEntity; added: boolean; member?: ChannelMember; err?: Error }> + > { + if (!channel) { + throw CrudException.badRequest("Channel is required"); + } + logger.debug( + "Add users %o to channel %o", + users.map(u => u.id), + channel.id, + ); + + await gr.services.channels.channels.completeWithStatistics([channel]); + + const members: Array<{ + channel: ChannelEntity; + added: boolean; + member?: ChannelMember; + err?: Error; + }> = await Promise.all( + users.map(async user => { + const channelContext: ChannelExecutionContext = { + channel, + user: context?.user || user, + }; + + const member: ChannelMember = getChannelMemberInstance({ + channel_id: channel.id, + company_id: channel.company_id, + workspace_id: channel.workspace_id, + user_id: user.id, + last_increment: channel.stats.messages, + last_access: Date.now(), + } as ChannelMember); + + try { + const isAlreadyMember = await this.getChannelMember(user, channel, undefined, context); + if (isAlreadyMember) { + logger.debug("User %s is already member in channel %s", member.user_id, channel.id); + return { channel, added: false }; + } + + const result = await this.save(member, channelContext); + + return { + channel, + added: true, + member: result.entity, + }; + } catch (err) { + logger.warn({ err }, "Member has not been added %o", member); + return { + channel, + err, + added: false, + }; + } + }), + ); + + return new ListResult("channel_member", members); + } + + async addUserToChannels( + user: Pick, + channels: ChannelEntity[], + ): Promise< + ListResult<{ channel: ChannelEntity; added: boolean; member?: ChannelMember; err?: Error }> + > { + logger.debug( + "Add user %s to channels %o", + user.id, + channels.map(c => c.id), + ); + const members: Array<{ + channel: ChannelEntity; + added: boolean; + member?: ChannelMember; + err?: Error; + }> = await Promise.all( + channels.map(async channel => { + const context: ChannelExecutionContext = { + channel, + user, + }; + + const member = getChannelMemberInstance({ + channel_id: channel.id, + company_id: channel.company_id, + workspace_id: channel.workspace_id, + user_id: user.id, + }); + + try { + const isAlreadyMember = await this.getChannelMember(user, channel, undefined, context); + if (isAlreadyMember) { + logger.debug("User %s is already member in channel %s", member.user_id, channel.id); + return { channel, added: false }; + } + + const result = await this.save(member, context); + + return { channel, member: result.entity, added: true }; + } catch (err) { + logger.warn({ err }, "Member has not been added %o", member); + return { channel, added: false, err }; + } + }), + ); + + return new ListResult("channel_member", members); + } + + onUpdated( + channel: Channel, + member: ChannelMember, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + updateResult: UpdateResult, + ): void { + logger.debug("Member updated %o", member); + + gr.platformServices.messageQueue.publish("channel:member:updated", { + data: { + channel, + member, + }, + }); + } + + onCreated( + channel: ChannelEntity, + member: ChannelMember, + user: User, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + createResult: SaveResult, + ): void { + logger.debug("Member created %o", member); + + gr.platformServices.messageQueue.publish("channel:member:created", { + data: { + channel, + user, + member, + }, + }); + + localEventBus.publish("channel:member:created", { + channel, + user, + member, + actor: user, + resourcesAfter: [member], + }); + } + + onDeleted(member: ChannelMember, user: User, channel: ChannelEntity): void { + logger.debug("Member deleted %o", member); + + gr.platformServices.messageQueue.publish("channel:member:deleted", { + data: { + channel, + user, + member, + }, + }); + + localEventBus.publish("channel:member:deleted", { + actor: user, + resourcesBefore: [member], + channel, + user, + member, + }); + } + + isCurrentUser(member: ChannelMember | MemberOfChannel, user: User): boolean { + return String(member.user_id) === String(user.id); + } + + async getChannelMember( + user: User, + channel: Partial>, + cacheTtlSec?: number, + context?: ExecutionContext, + ): Promise { + if (!user) { + return; + } + + if (cacheTtlSec) { + const pk = JSON.stringify({ user, channel }); + if (this.cache.has(pk)) return this.cache.get(pk); + const entity = await this.getChannelMember(user, channel, undefined, context); + this.cache.set(pk, entity, cacheTtlSec); + return entity; + } + + return this.get( + { + channel_id: channel.id, + company_id: channel.company_id, + workspace_id: channel.workspace_id, + user_id: user.id, + }, + context, + ); + } + + getPrimaryKey( + memberOrPrimaryKey: ChannelMember | ChannelMemberPrimaryKey, + ): ChannelMemberPrimaryKey { + return pick( + memberOrPrimaryKey, + ...(["company_id", "workspace_id", "channel_id", "user_id"] as const), + ); + } + + private async usersCounterIncrease(channel: Channel, userId: string, increaseValue: number = 1) { + // const isMember = await this.isCompanyMember(channel.company_id, userId); + const isMember = true; // Since actually all users are now added to the channel as members, we are removing the guest counter for now. + const counter_type = isMember ? ChannelUserCounterType.MEMBERS : ChannelUserCounterType.GUESTS; + return this.channelCounter.increase( + { + id: channel.id, + company_id: channel.company_id, + workspace_id: channel.workspace_id, + counter_type, + }, + increaseValue, + ); + } + + getUsersCount(pk: ChannelCounterPrimaryKey): Promise { + return this.channelCounter.get(pk); + } + + async isCompanyMember(companyId: string, userId: string): Promise { + return (await gr.services.companies.getUserRole(companyId, userId)) != "guest"; + } + + private async saveChannelMember( + memberToSave: ChannelMember & Channel, + context: ExecutionContext, + ) { + const userChannel = getChannelMemberInstance(pick(memberToSave, ...USER_CHANNEL_KEYS)); + const channelMember = getMemberOfChannelInstance(pick(memberToSave, ...CHANNEL_MEMBERS_KEYS)); + await this.userChannelsRepository.save(userChannel, context); + await this.channelMembersRepository.save(channelMember, context); + } + + async ensureUserNotInWorkspaceIsNotInChannel( + userPk: UserPrimaryKey, + workspacePk: WorkspacePrimaryKey, + context: ExecutionContext, + ) { + const workspace = await gr.services.workspaces.get(workspacePk); + const member = await gr.services.workspaces.getUser({ + workspaceId: workspace.id, + userId: userPk.id, + }); + if (!member) { + const result = await this.userChannelsRepository.find( + { + company_id: workspace.company_id, + workspace_id: workspace.id, + user_id: userPk.id, + }, + {}, + context, + ); + for (const channel of result.getEntities()) { + logger.warn( + `User ${userPk.id} is not in workspace ${workspace.id} so it will be removed from channel ${channel.id}`, + ); + await this.delete(channel, { user: { id: userPk.id }, channel }); + } + } + } + + /** + * The list of members read sections of the channel. + * + * @param {ChannelExecutionContext} context - The context of the execution. + * @returns {Promise>} - The channel members read cursors. + */ + async getChannelMembersReadSections( + context: ChannelExecutionContext, + ): Promise> { + try { + const readCursors = await this.channelMembersReadCursorRepository.find( + { + company_id: context.channel.company_id, + channel_id: context.channel.id, + }, + { pagination: { limitStr: "100" } }, + context, + ); + + return new ListResult( + "channel_members_read_cursors", + readCursors.getEntities(), + ); + } catch (error) { + logger.error(error); + throw error; + } + } + + /** + * The channel member read section of the channel. + * + * @param {ChannelExecutionContext} context - The context of the execution. + * @returns {Promise} - The channel member read cursors. + */ + async getChannelMemberReadSections( + member: string, + context: ChannelExecutionContext, + ): Promise { + try { + const readCursors = await this.channelMembersReadCursorRepository.findOne( + { + company_id: context.channel.company_id, + channel_id: context.channel.id, + user_id: member, + }, + {}, + context, + ); + + return readCursors; + } catch (error) { + logger.error(error); + throw error; + } + } + + /** + * Updates the channel member read section. + * + * @param {{ start: string; end: string }} section - The section to save the cursor for. + * @param {CompanyExecutionContext & { channel_id: string }} context - The channel execution context. + * @returns {Promise>} - The result of the save operation. + */ + async setChannelMemberReadSections( + section: { start: string; end: string }, + context: CompanyExecutionContext & { channel_id: string; workspace_id: string }, + ): Promise> { + const member = await this.getChannelMember( + context.user, + { + id: context.channel_id, + company_id: context.company.id, + workspace_id: context.workspace_id, + }, + null, + context, + ); + + if (!member) { + throw CrudException.badRequest( + `User ${context.user.id} is not a member of channel ${context.channel_id}`, + ); + } + + const existingReadSection = await this.channelMembersReadCursorRepository.findOne( + { + company_id: context.company.id, + channel_id: context.channel_id, + user_id: context.user.id, + }, + {}, + context, + ); + + const { start, end } = section; + + if ( + !existingReadSection || + !existingReadSection.read_section || + !existingReadSection.read_section.length + ) { + const newMemberReadCursor = new ChannelMemberReadCursors(); + newMemberReadCursor.company_id = context.company.id; + newMemberReadCursor.channel_id = context.channel_id; + newMemberReadCursor.user_id = context.user.id; + newMemberReadCursor.read_section = [start, end] as ReadSection; + + await this.channelMembersReadCursorRepository.save(newMemberReadCursor, context); + + return new SaveResult( + "channel_members_read_cursors", + newMemberReadCursor, + OperationType.CREATE, + ); + } + + const updatedReadSection = { start, end }; + const [existingStart, existingEnd] = existingReadSection.read_section; + const existingStartTime = uuidTime.v1(existingStart); + const existingEndTime = uuidTime.v1(existingEnd); + const startTime = uuidTime.v1(start); + const endTime = uuidTime.v1(end); + + if (existingStartTime < startTime) { + updatedReadSection.start = existingStart; + } + + if (existingEndTime > endTime) { + updatedReadSection.end = existingEnd; + } + + if (existingStart === updatedReadSection.start && existingEnd === updatedReadSection.end) { + return new SaveResult( + "channel_members_read_cursors", + existingReadSection, + OperationType.EXISTS, + ); + } + + existingReadSection.read_section = [updatedReadSection.start, updatedReadSection.end]; + await this.channelMembersReadCursorRepository.save(existingReadSection, context); + + return new SaveResult( + "channel_members_read_cursors", + existingReadSection, + OperationType.UPDATE, + ); + } + + /** + * list users who have seen the message. + * + * @param {String} id - the message id + * @param {ChannelExecutionContext} context - the thread execution context + * @returns { Promise} - the promise containing the user id list + */ + async getChannelMessageSeenByUsers( + id: string, + context: ChannelExecutionContext, + ): Promise { + const channelReadSections = await this.getChannelMembersReadSections(context); + + return channelReadSections + .getEntities() + .filter(section => { + const sectionEnd = section.read_section[1]; + const sectionEndTime = uuidTime.v1(sectionEnd); + const messageTime = uuidTime.v1(id); + + return messageTime <= sectionEndTime; + }) + .map(section => section.user_id); + } +} diff --git a/twake/backend/node/src/services/channels/services/pubsub/index.ts b/twake/backend/node/src/services/channels/services/pubsub/index.ts new file mode 100644 index 00000000..e8d452e0 --- /dev/null +++ b/twake/backend/node/src/services/channels/services/pubsub/index.ts @@ -0,0 +1,24 @@ +import { Initializable } from "../../../../core/platform/framework"; +import { NewChannelActivityProcessor } from "./new-channel-activity"; +import { NewDirectChannelMessageProcessor } from "./new-direct-channel-message"; +import { NewUserInWorkspaceJoinDefaultChannelsProcessor } from "./new-user-in-workspace-join-default-channels"; +import { NewPendingEmailsInWorkspaceJoinChannelsProcessor } from "./new-pending-emails-in-workspace-join-channels"; +import { NewWorkspaceProcessor } from "./new-workspace"; +import gr from "../../../global-resolver"; + +export class ChannelsMessageQueueListener implements Initializable { + async init(): Promise { + const channelActivityProcessor = await new NewChannelActivityProcessor().init(); + gr.platformServices.messageQueue.processor.addHandler(channelActivityProcessor); + gr.platformServices.messageQueue.processor.addHandler(new NewDirectChannelMessageProcessor()); + gr.platformServices.messageQueue.processor.addHandler( + new NewUserInWorkspaceJoinDefaultChannelsProcessor(), + ); + gr.platformServices.messageQueue.processor.addHandler( + new NewPendingEmailsInWorkspaceJoinChannelsProcessor(), + ); + gr.platformServices.messageQueue.processor.addHandler(new NewWorkspaceProcessor()); + + return this; + } +} diff --git a/twake/backend/node/src/services/channels/services/pubsub/new-channel-activity.ts b/twake/backend/node/src/services/channels/services/pubsub/new-channel-activity.ts new file mode 100644 index 00000000..127b2bd4 --- /dev/null +++ b/twake/backend/node/src/services/channels/services/pubsub/new-channel-activity.ts @@ -0,0 +1,91 @@ +import { getLogger } from "../../../../core/platform/framework"; +import { MessageQueueHandler } from "../../../../core/platform/services/message-queue/api"; +import { ChannelActivityNotification } from "../../types"; +import { CounterProvider } from "../../../../core/platform/services/counter/provider"; +import { + ChannelCounterEntity, + ChannelUserCounterType, + TYPE as ChannelCounterEntityType, +} from "../../entities/channel-counters"; +import gr from "../../../global-resolver"; + +const logger = getLogger("channel.message-queue.new-channel-activity"); +export class NewChannelActivityProcessor + implements MessageQueueHandler +{ + private channelCounter: CounterProvider; + + async init() { + const channelCountersRepository = await gr.database.getRepository( + ChannelCounterEntityType, + ChannelCounterEntity, + ); + this.channelCounter = await gr.platformServices.counter.getCounter( + channelCountersRepository, + ); + return this; + } + + readonly topics = { + in: "channel:activity", + }; + + readonly options = { + unique: true, + ack: true, + }; + + readonly name = "NewChannelActivityProcessor"; + + validate(message: ChannelActivityNotification): boolean { + return !!(message && message.channel_id && message.company_id && message.workspace_id); + } + + async process(message: ChannelActivityNotification): Promise { + logger.info(`${this.name} - Processing new activity in channel ${message.channel_id}`); + + await this.channelCounter.increase( + { + id: message.channel_id, + company_id: message.company_id, + workspace_id: message.workspace_id, + counter_type: ChannelUserCounterType.MESSAGES, + }, + 1, + ); + + try { + await gr.services.channels.channels.updateLastActivity( + { + date: message.date, + channel: { + id: message.channel_id, + workspace_id: message.workspace_id, + company_id: message.company_id, + }, + message: { + date: message.date, + sender: message.sender, + sender_name: message.sender_name, + title: message.title, + text: message.body, + }, + }, + { + workspace: { + workspace_id: message.workspace_id, + company_id: message.company_id, + }, + user: { + id: message.sender, + }, + }, + ); + } catch (err) { + logger.error( + { err }, + `${this.name} - Error while applying channel new activity in channel ${message?.channel_id}`, + ); + } + } +} diff --git a/twake/backend/node/src/services/channels/services/pubsub/new-direct-channel-message.ts b/twake/backend/node/src/services/channels/services/pubsub/new-direct-channel-message.ts new file mode 100644 index 00000000..9aee6a36 --- /dev/null +++ b/twake/backend/node/src/services/channels/services/pubsub/new-direct-channel-message.ts @@ -0,0 +1,93 @@ +import { without } from "lodash"; +import { Channel, ChannelMember } from "../../entities"; +import { getLogger } from "../../../../core/platform/framework"; +import { MessageQueueHandler } from "../../../../core/platform/services/message-queue/api"; +import { MessageNotification } from "../../../messages/types"; +import gr from "../../../global-resolver"; +import { ExecutionContext } from "../../../../core/platform/framework/api/crud-service"; + +const logger = getLogger("channel.message-queue.new-direct-channel-message"); + +export class NewDirectChannelMessageProcessor + implements MessageQueueHandler +{ + readonly topics = { + in: "message:created", + }; + + readonly options = { + unique: true, + ack: true, + queue: "message:created:consumer1", + }; + + readonly name = "Channel::NewDirectChannelMessageProcessor"; + + validate(message: MessageNotification): boolean { + return !!(message && message.channel_id && message.company_id && message.workspace_id); + } + + async process(message: MessageNotification, context?: ExecutionContext): Promise { + logger.info( + `${this.name} - Processing notification for message ${message.thread_id}/${message.id} in channel ${message.channel_id}`, + ); + logger.debug(`${this.name} - Notification message ${JSON.stringify(message)}`); + + try { + const channel = await gr.services.channels.channels.get( + { + company_id: message.company_id, + id: message.channel_id, + workspace_id: message.workspace_id, + }, + context, + ); + + if (!channel || !Channel.isDirectChannel(channel)) { + logger.debug(`${this.name} - Not a direct channel`); + return; + } + + const memberIds = without(channel.members || [], String(message.sender)); + if (!memberIds.length) { + logger.debug(`${this.name} - No members to notify. Original array was %o`, channel.members); + } + + const members = memberIds.map(user_id => { + return { + user_id, + channel_id: channel.id, + workspace_id: channel.workspace_id, + company_id: channel.company_id, + } as ChannelMember; + }); + + await Promise.all( + members.map(async member => { + try { + logger.info(`${this.name} - Adding ${member.user_id} to channel ${message.channel_id}`); + const memberSaved = await gr.services.channels.members.save(member, { + channel, + user: { id: member.user_id }, + }); + logger.info( + `${this.name} - Member added to channel ${message.channel_id} - ${JSON.stringify( + memberSaved, + )}`, + ); + } catch (err) { + logger.info( + { err }, + `${this.name} - Error while adding user ${member.user_id} to direct channel ${member.channel_id}`, + ); + } + }), + ); + } catch (err) { + logger.error( + { err }, + `${this.name} - Error while processing direct channel members for message ${message.thread_id}/${message.id} in channel ${message.channel_id}`, + ); + } + } +} diff --git a/twake/backend/node/src/services/channels/services/pubsub/new-pending-emails-in-workspace-join-channels.ts b/twake/backend/node/src/services/channels/services/pubsub/new-pending-emails-in-workspace-join-channels.ts new file mode 100644 index 00000000..95c1a278 --- /dev/null +++ b/twake/backend/node/src/services/channels/services/pubsub/new-pending-emails-in-workspace-join-channels.ts @@ -0,0 +1,58 @@ +import { getLogger } from "../../../../core/platform/framework"; +import { MessageQueueHandler } from "../../../../core/platform/services/message-queue/api"; +import { NewUserInWorkspaceNotification } from "../channel/types"; +import gr from "../../../global-resolver"; +import { ExecutionContext } from "../../../../core/platform/framework/api/crud-service"; + +const NAME = "Channel::NewPendingEmailsInWorkspaceJoinChannelsProcessor"; +const logger = getLogger( + "channel.message-queue.new-pending-emails-in-workspace-join-channels-processor", +); + +/** + * When a new pending email is added in a workspace, a `workspace:email:added` event is published. + * In such case, the email must be added to all the channels that he is invited. + */ +export class NewPendingEmailsInWorkspaceJoinChannelsProcessor + implements MessageQueueHandler +{ + readonly topics = { + in: "workspace:member:added", + }; + + readonly options = { + unique: true, + ack: true, + queue: "workspace:user:added:consumer_channel_pending_emails", + }; + + readonly name = NAME; + + validate(message: NewUserInWorkspaceNotification): boolean { + return !!(message && message.company_id && message.workspace_id && message.user_id); + } + + async process( + message: NewUserInWorkspaceNotification, + context?: ExecutionContext, + ): Promise { + logger.debug("Processing notification for message %o", message); + + try { + await gr.services.channelPendingEmail.proccessPendingEmails( + message, + { + workspace_id: message.workspace_id, + company_id: message.company_id, + }, + context, + ); + } catch (err) { + logger.error( + { err }, + `${this.name} - Error while processing message for pending emails %o`, + message, + ); + } + } +} diff --git a/twake/backend/node/src/services/channels/services/pubsub/new-user-in-workspace-join-default-channels.ts b/twake/backend/node/src/services/channels/services/pubsub/new-user-in-workspace-join-default-channels.ts new file mode 100644 index 00000000..e3f682c2 --- /dev/null +++ b/twake/backend/node/src/services/channels/services/pubsub/new-user-in-workspace-join-default-channels.ts @@ -0,0 +1,59 @@ +import { getLogger } from "../../../../core/platform/framework"; +import { MessageQueueHandler } from "../../../../core/platform/services/message-queue/api"; +import { NewUserInWorkspaceNotification } from "../channel/types"; +import gr from "../../../global-resolver"; + +const NAME = "Channel::NewUserInWorkspaceJoinDefaultChannelsProcessor"; +const logger = getLogger( + "channel.message-queue.new-user-in-workspace-join-default-channels-processor", +); + +/** + * When a new user is added in a workspace, a `workspace:user:added` event is published. + * In such case, the user must be added to all the default channels of the workspace. + */ +export class NewUserInWorkspaceJoinDefaultChannelsProcessor + implements MessageQueueHandler +{ + readonly topics = { + in: "workspace:member:added", + }; + + readonly options = { + unique: true, + ack: true, + queue: "workspace:user:added:consumer_default_channels", + }; + + readonly name = NAME; + + validate(message: NewUserInWorkspaceNotification): boolean { + return !!(message && message.company_id && message.workspace_id && message.user_id); + } + + async process(message: NewUserInWorkspaceNotification): Promise { + logger.debug("Processing notification for message %o", message); + + try { + const channelMembers = await gr.services.channels.channels.addUserToDefaultChannels( + { id: message.user_id }, + { + company_id: message.company_id, + workspace_id: message.workspace_id, + }, + ); + + logger.debug( + "User %s has been added as member to default channels %o", + message.user_id, + (channelMembers || []).map(c => c.channel_id), + ); + } catch (err) { + logger.error( + { err }, + `${this.name} - Error while processing message for default channels %o`, + message, + ); + } + } +} diff --git a/twake/backend/node/src/services/channels/services/pubsub/new-workspace.ts b/twake/backend/node/src/services/channels/services/pubsub/new-workspace.ts new file mode 100644 index 00000000..2803d49b --- /dev/null +++ b/twake/backend/node/src/services/channels/services/pubsub/new-workspace.ts @@ -0,0 +1,57 @@ +import { getLogger } from "../../../../core/platform/framework"; +import { MessageQueueHandler } from "../../../../core/platform/services/message-queue/api"; +import { ChannelActivityNotification, ChannelVisibility } from "../../types"; +import { getInstance } from "../../../channels/entities/channel"; +import gr from "../../../global-resolver"; + +const logger = getLogger("channel.message-queue.new-channel-activity"); +export class NewWorkspaceProcessor + implements MessageQueueHandler +{ + readonly topics = { + in: "workspace:added", + queue: "workspace:added:consumer1", + }; + + readonly options = { + unique: true, + ack: true, + }; + + readonly name = "NewWorkspaceProcessor"; + + validate(message: ChannelActivityNotification): boolean { + return !!(message && message.company_id && message.workspace_id); + } + + async process(message: ChannelActivityNotification): Promise { + logger.info(`${this.name} - Processing new workspace created ${message.workspace_id}`); + + try { + await gr.services.channels.channels.save( + getInstance({ + icon: "πŸ’¬", + name: "General", + description: "", + visibility: ChannelVisibility.PUBLIC, + is_default: true, + }), + {}, + { + workspace: { + workspace_id: message.workspace_id, + company_id: message.company_id, + }, + user: { + id: message.sender, + }, + }, + ); + } catch (err) { + logger.error( + { err }, + `${this.name} - Error while generating default channels for workspace ${message?.workspace_id}`, + ); + } + } +} diff --git a/twake/backend/node/src/services/channels/services/tab.ts b/twake/backend/node/src/services/channels/services/tab.ts new file mode 100644 index 00000000..a6d124ee --- /dev/null +++ b/twake/backend/node/src/services/channels/services/tab.ts @@ -0,0 +1,136 @@ +import _ from "lodash"; +import { RealtimeDeleted, RealtimeSaved } from "../../../core/platform/framework"; +import { + DeleteResult, + ExecutionContext, + ListResult, + OperationType, + Pagination, + SaveResult, + UpdateResult, +} from "../../../core/platform/framework/api/crud-service"; +import { ChannelTab, ChannelTabPrimaryKey } from "../entities"; +import { ChannelExecutionContext } from "../types"; +import { Channel } from "../../../utils/types"; +import { ResourcePath } from "../../../core/platform/services/realtime/types"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import gr from "../../global-resolver"; + +export class TabServiceImpl { + version: "1"; + repository: Repository; + + async init(): Promise { + this.repository = await gr.database.getRepository("channel_tabs", ChannelTab); + return this; + } + + @RealtimeSaved((tab, context) => [ + { + room: ResourcePath.get(getTabsRealtimeRoom((context as ChannelExecutionContext).channel)), + path: getTabsRealtimeResourcePath(tab, (context as ChannelExecutionContext).channel), + }, + ]) + async save( + tab: ChannelTab, + options: SaveOptions, + context: ChannelExecutionContext, + ): Promise> { + const pk = { + company_id: context.channel.company_id, + workspace_id: context.channel.workspace_id, + channel_id: context.channel.id, + id: tab.id, + }; + + let tabEntity = await this.repository.findOne(pk, {}, context); + if (!tabEntity || !tab.id) { + tabEntity = new ChannelTab(); + tabEntity = _.merge(tabEntity, pk); + tabEntity.owner = context.user.id; + } + + tabEntity = _.merge( + tabEntity, + _.pick(tab, ["name", "configuration", "application_id", "order"]), + ); + + await this.repository.save(tabEntity, context); + + return new SaveResult("channel_tabs", tabEntity, OperationType.CREATE); + } + + async get(tabPk: ChannelTabPrimaryKey, context: ChannelExecutionContext): Promise { + const pk = { + company_id: context.channel.company_id, + workspace_id: context.channel.workspace_id, + channel_id: context.channel.id, + id: tabPk.id, + }; + return await this.repository.findOne(pk, {}, context); + } + + @RealtimeDeleted((tab, context) => [ + { + room: ResourcePath.get(getTabsRealtimeRoom((context as ChannelExecutionContext).channel)), + path: getTabsRealtimeResourcePath(tab, (context as ChannelExecutionContext).channel), + }, + ]) + async delete( + pk: ChannelTabPrimaryKey, + context?: ExecutionContext, + ): Promise> { + const tabEntity = await this.repository.findOne(pk, {}, context); + if (tabEntity) { + await this.repository.remove(tabEntity, context); + } + + return new DeleteResult("channel_tabs", tabEntity, true); + } + + async list( + pagination: Pagination, + options: ListOptions, + context: ChannelExecutionContext, + ): Promise> { + const pk = { + company_id: context.channel.company_id, + workspace_id: context.channel.workspace_id, + channel_id: context.channel.id, + }; + return await this.repository.find(pk, { pagination }, context); + } + + onUpdated( + channel: Channel, + tab: ChannelTab, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + updateResult: UpdateResult, + ): void { + console.log("Tab updated", tab); + } + + onCreated( + channel: Channel, + tab: ChannelTab, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + createResult: SaveResult, + ): void { + console.log("Tab created", tab); + } + + onDeleted(channel: Channel, tab: ChannelTab): void { + console.log("Tab deleted", tab); + } +} + +export function getTabsRealtimeRoom(channel: ChannelExecutionContext["channel"]): string { + return `/companies/${channel.company_id}/workspaces/${channel.workspace_id}/channels/${channel.id}/tabs`; +} + +export function getTabsRealtimeResourcePath( + tab: ChannelTab, + channel: ChannelExecutionContext["channel"], +): string { + return `/companies/${channel.company_id}/workspaces/${channel.workspace_id}/channels/${channel.id}/tabs/${tab.id}`; +} diff --git a/twake/backend/node/src/services/channels/types.ts b/twake/backend/node/src/services/channels/types.ts new file mode 100644 index 00000000..20894579 --- /dev/null +++ b/twake/backend/node/src/services/channels/types.ts @@ -0,0 +1,54 @@ +import { ExecutionContext } from "../../core/platform/framework/api/crud-service"; +import { Channel, uuid, Workspace } from "../../utils/types"; + +export interface WorkspaceExecutionContext extends ExecutionContext { + workspace: Workspace; +} + +export interface ChannelExecutionContext extends ExecutionContext { + channel: Channel; +} + +export interface ChannelSystemExecutionContext { + workspace: Workspace; + channel?: Channel; +} + +export enum ChannelVisibility { + PRIVATE = "private", + PUBLIC = "public", + DIRECT = "direct", +} + +export enum ChannelType { + DIRECT = "direct", +} + +export enum ChannelMemberType { + MEMBER = "member", + GUEST = "guest", + BOT = "bot", +} + +export enum ChannelMemberNotificationLevel { + // be notified on all messages + ALL = "all", + // Only be notified on @user, @all, @here, @everyone mentions + MENTIONS = "mentions", + // Only be notified on @user mention + ME = "me", + // do not be notified at all even when someone mention user, not on direct channels + NONE = "none", +} + +export type ChannelActivityNotification = { + company_id: uuid; + workspace_id: uuid | "direct"; + channel_id: uuid; + date: number; + sender: string; + title: string; + text: string; + sender_name: string; + body: string; +}; diff --git a/twake/backend/node/src/services/channels/utils.ts b/twake/backend/node/src/services/channels/utils.ts new file mode 100644 index 00000000..caafd8a2 --- /dev/null +++ b/twake/backend/node/src/services/channels/utils.ts @@ -0,0 +1,5 @@ +import { ChannelType } from "./types"; + +export function isDirectChannel(channel: { workspace_id: string }): boolean { + return channel?.workspace_id === ChannelType.DIRECT; +} diff --git a/twake/backend/node/src/services/channels/web/controllers/channel.ts b/twake/backend/node/src/services/channels/web/controllers/channel.ts new file mode 100644 index 00000000..43091f79 --- /dev/null +++ b/twake/backend/node/src/services/channels/web/controllers/channel.ts @@ -0,0 +1,623 @@ +import { plainToClass } from "class-transformer"; +import { FastifyReply, FastifyRequest } from "fastify"; +import { + CrudException, + ExecutionContext, + ListResult, + Pagination, +} from "../../../../core/platform/framework/api/crud-service"; +import { CrudController } from "../../../../core/platform/services/webserver/types"; +import { + Channel, + ChannelMember, + ChannelPendingEmails, + ChannelPendingEmailsPrimaryKey, + ChannelPrimaryKey, + getChannelPendingEmailsInstance, + UserChannel, + UsersIncludedChannel, +} from "../../entities"; +import { getWebsocketInformation, getWorkspaceRooms } from "../../services/channel/realtime"; +import { + BaseChannelsParameters, + ChannelListQueryParameters, + ChannelParameters, + ChannelPendingEmailsDeleteQueryParameters, + ChannelSaveOptions, + ChannelSearchQueryParameters, + CreateChannelBody, + ReadChannelBody, + UpdateChannelBody, +} from "../types"; +import { ChannelExecutionContext, ChannelVisibility, WorkspaceExecutionContext } from "../../types"; +import { handleError } from "../../../../utils/handleError"; +import { + ResourceCreateResponse, + ResourceDeleteResponse, + ResourceGetResponse, + ResourceListResponse, + ResourceUpdateResponse, +} from "../../../../utils/types"; +import { getLogger } from "../../../../core/platform/framework/logger"; +import _ from "lodash"; +import { ChannelMemberObject, ChannelObject } from "../../services/channel/types"; +import gr from "../../../global-resolver"; +import { checkUserBelongsToCompany } from "../../../../utils/company"; + +const logger = getLogger("channel.controller"); + +export class ChannelCrudController + implements + CrudController< + ResourceGetResponse, + ResourceCreateResponse, + ResourceListResponse, + ResourceDeleteResponse + > +{ + getPrimaryKey(request: FastifyRequest<{ Params: ChannelParameters }>): ChannelPrimaryKey { + return { + id: request.params.id, + company_id: request.params.company_id, + workspace_id: request.params.workspace_id, + }; + } + + async get( + request: FastifyRequest<{ Querystring: ChannelListQueryParameters; Params: ChannelParameters }>, + _reply: FastifyReply, + ): Promise> { + const context = getExecutionContext(request); + + let channel: Channel | UsersIncludedChannel = await gr.services.channels.channels.get( + this.getPrimaryKey(request), + context, + ); + + if (!channel) { + throw CrudException.notFound(`Channel ${request.params.id} not found`); + } + + if (Channel.isDirectChannel(channel) || Channel.isPrivateChannel(channel)) { + const isMember = await gr.services.channels.members.getChannelMember( + request.currentUser, + channel, + undefined, + context, + ); + + if (!isMember && !context.user.application_id && !context.user.server_request) { + throw CrudException.badRequest("User does not have enough rights to get channel"); + } + } + + if (request.query.include_users) + channel = await gr.services.channels.channels.includeUsersInDirectChannel(channel); + + const member = await gr.services.channels.members.get( + _.assign(new ChannelMember(), { + channel_id: channel.id, + workspace_id: channel.workspace_id, + company_id: channel.company_id, + user_id: context.user.id, + }), + context, + ); + + const channelObject = ChannelObject.mapTo(channel, { + user_member: ChannelMemberObject.mapTo(member), + }); + + await gr.services.channels.channels.completeWithStatistics([channelObject]); + + return { + websocket: gr.platformServices.realtime.sign( + [getWebsocketInformation(channel)], + context.user.id, + )[0], + resource: channelObject, + }; + } + + async search( + request: FastifyRequest<{ + Querystring: ChannelSearchQueryParameters; + Params: { company_id: string }; + }>, + _reply: FastifyReply, + ): Promise> { + if (request.query?.q?.length === 0) { + return this.recent(request); + } + + const context = getSimpleExecutionContext(request); + const userId = request.currentUser.id; + + await checkUserBelongsToCompany(request.currentUser.id, request.params.company_id); + + const limit = request.query.limit || 100; + + async function* getNextChannels(): AsyncIterableIterator { + let lastPageToken = null; + let channels: Channel[] = []; + let hasMore = true; + do { + channels = await gr.services.channels.channels + .search( + new Pagination(lastPageToken, limit.toString()), + { + search: request.query.q, + companyId: request.params.company_id, + }, + context, + ) + .then((a: ListResult) => { + lastPageToken = a.nextPage.page_token; + if (!lastPageToken) { + hasMore = false; + } + return a.getEntities(); + }); + + if (channels.length) { + for (const channel of channels) { + yield channel; + } + } else { + hasMore = false; + } + } while (hasMore); + } + + const channels = [] as (Channel & { user_member: ChannelMemberObject })[]; + + for await (const ch of getNextChannels()) { + const channelMember = await gr.services.channels.members.getChannelMember( + { id: request.currentUser.id }, + ch, + 50, + context, + ); + + //If not public channel and not member then ignore + if (!channelMember && ch.visibility !== "public") continue; + + //If public channel but not in the workspace then ignore + if ( + !channelMember && + !(await gr.services.workspaces.getUser({ workspaceId: ch.workspace_id, userId })) + ) + continue; + + const chWithUser = await gr.services.channels.channels.includeUsersInDirectChannel( + ch, + userId, + ); + + channels.push({ ...chWithUser, user_member: channelMember }); + if (channels.length == limit) { + break; + } + } + + await gr.services.channels.channels.completeWithStatistics(channels as ChannelObject[]); + + return { resources: channels }; + } + + async getForPHP( + request: FastifyRequest<{ Params: ChannelParameters }>, + reply: FastifyReply, + ): Promise { + const context = getExecutionContext(request); + const channel = await gr.services.channels.channels.get(this.getPrimaryKey(request), context); + + reply.send(channel); + } + + async thumbnail( + request: FastifyRequest<{ Params: ChannelParameters }>, + response: FastifyReply, + ): Promise { + const data = await gr.services.channels.channels.thumbnail(request.params.id); + const filename = "thumbnail.jpg"; + + response.header("Content-disposition", `inline; filename="${filename}"`); + response.type("image/jpeg"); + + response.send(data.file); + } + + async save( + request: FastifyRequest<{ + Body: CreateChannelBody; + Params: ChannelParameters; + Querystring: { include_users: boolean }; + }>, + reply: FastifyReply, + ): Promise> { + const entity = plainToClass(Channel, { + ...request.body.resource, + ...{ + company_id: request.params.company_id, + workspace_id: request.params.workspace_id, + }, + }); + logger.debug("reqId: %s - save - Channel input %o", request.id, entity); + + try { + const options = { + members: request.body.options ? request.body.options.members || [] : [], + addCreatorAsMember: true, + } as ChannelSaveOptions; + + const context = getExecutionContext(request); + const channelResult = await gr.services.channels.channels.save(entity, options, context); + + logger.debug("reqId: %s - save - Channel %s created", request.id, channelResult.entity.id); + + const member = await gr.services.channels.members.get( + _.assign(new ChannelMember(), { + channel_id: channelResult.entity.id, + workspace_id: channelResult.entity.workspace_id, + company_id: channelResult.entity.company_id, + user_id: context.user.id, + }), + context, + ); + + let entityWithUsers: Channel = channelResult.entity; + + if (request.query.include_users) + entityWithUsers = await gr.services.channels.channels.includeUsersInDirectChannel( + entityWithUsers, + context.user.id, + ); + + const resultEntity = { + ...entityWithUsers, + ...{ user_member: member }, + } as unknown as UserChannel; + + if (entity) { + reply.code(201); + } + + return { + websocket: gr.platformServices.realtime.sign( + [getWebsocketInformation(channelResult.entity)], + context.user.id, + )[0], + resource: ChannelObject.mapTo(resultEntity), + }; + } catch (err) { + handleError(reply, err); + } + } + + async update( + request: FastifyRequest<{ Body: UpdateChannelBody; Params: ChannelParameters }>, + reply: FastifyReply, + ): Promise> { + const entity = plainToClass(Channel, { + ...request.body.resource, + ...{ + company_id: request.params.company_id, + workspace_id: request.params.workspace_id, + id: request.params.id, + }, + }); + + try { + const context = getExecutionContext(request); + const result = await gr.services.channels.channels.save(entity, {}, context); + + if (result.entity) { + reply.code(201); + } + + return { + websocket: gr.platformServices.realtime.sign( + [getWebsocketInformation(result.entity)], + context.user.id, + )[0], + resource: ChannelObject.mapTo(result.entity), + }; + } catch (err) { + handleError(reply, err); + } + } + + async list( + request: FastifyRequest<{ + Querystring: ChannelListQueryParameters; + Params: BaseChannelsParameters; + }>, + ): Promise> { + const context = getExecutionContext(request); + + //Fixme: this slow down the channel get operation. Once we stabilize the workspace:member:added event we can remove this + if (context.workspace.workspace_id !== ChannelVisibility.DIRECT) { + await gr.services.channelPendingEmail.proccessPendingEmails( + { + user_id: context.user.id, + ...context.workspace, + }, + context.workspace, + context, + ); + } + + const list = await gr.services.channels.channels.list( + new Pagination(request.query.page_token, request.query.limit), + { ...request.query }, + context, + ); + + let entities = []; + if (request.query.include_users) { + entities = []; + for (const e of list.getEntities()) { + entities.push( + await gr.services.channels.channels.includeUsersInDirectChannel(e, context.user.id), + ); + } + } else { + entities = list.getEntities(); + } + + const resources = entities.map(a => ChannelObject.mapTo(a)); + + await gr.services.channels.channels.completeWithStatistics(resources); + + return { + ...{ + resources: resources, + }, + ...(request.query.websockets && { + websockets: gr.platformServices.realtime.sign( + getWorkspaceRooms(request.params, request.currentUser), + request.currentUser.id, + ), + }), + ...(list.page_token && { + next_page_token: list.page_token, + }), + }; + } + + async delete( + request: FastifyRequest<{ Params: ChannelParameters }>, + reply: FastifyReply, + ): Promise { + try { + const deleteResult = await gr.services.channels.channels.delete( + this.getPrimaryKey(request), + getExecutionContext(request), + ); + + if (deleteResult.deleted) { + reply.code(204); + + return { + status: "success", + }; + } + + return { + status: "error", + }; + } catch (err) { + handleError(reply, err); + } + } + + async updateRead( + request: FastifyRequest<{ Body: ReadChannelBody; Params: ChannelParameters }>, + reply: FastifyReply, + ): Promise { + const read = request.body.value; + const context = getExecutionContext(request); + try { + const result = read + ? await gr.services.channels.channels.markAsRead( + this.getPrimaryKey(request), + request.currentUser, + context, + ) + : await gr.services.channels.channels.markAsUnread( + this.getPrimaryKey(request), + request.currentUser, + context, + ); + return result; + } catch (err) { + handleError(reply, err); + } + } + + async findPendingEmails( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + request: FastifyRequest<{ + Querystring: ChannelListQueryParameters; + Params: ChannelPendingEmailsPrimaryKey; + }>, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + reply: FastifyReply, + ): Promise> { + const list = await gr.services.channelPendingEmail.list( + new Pagination(request.query.page_token, request.query.limit), + { ...request.query }, + getChannelPendingEmailsExecutionContext(request), + ); + + return { + resources: list.getEntities(), + ...(request.query.websockets && { + websockets: gr.platformServices.realtime.sign( + getWorkspaceRooms(request.params, request.currentUser), + request.currentUser.id, + ), + }), + ...(list.page_token && { + next_page_token: list.page_token, + }), + }; + } + + async savePendingEmails( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + request: FastifyRequest<{ + Body: { resource: ChannelPendingEmails }; + Params: ChannelPendingEmailsPrimaryKey; + }>, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + reply: FastifyReply, + ): Promise> { + const context = getSimpleExecutionContext(request); + const pendingEmail = await gr.services.channelPendingEmail.create( + getChannelPendingEmailsInstance(request.body.resource), + context, + ); + logger.debug("reqId: %s - save - PendingEmails input %o", request.id, pendingEmail.entity); + return { resource: pendingEmail.entity }; + } + + async deletePendingEmails( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + request: FastifyRequest<{ Params: ChannelPendingEmailsDeleteQueryParameters }>, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + reply: FastifyReply, + ): Promise { + const pendingEmail = await gr.services.channelPendingEmail.delete( + getChannelPendingEmailsInstance({ + channel_id: request.params.channel_id, + company_id: request.params.company_id, + workspace_id: request.params.workspace_id, + email: request.params.email, + }), + ); + + return { status: pendingEmail.deleted ? "success" : "error" }; + } + + async recent( + request: FastifyRequest<{ + Querystring: { limit?: string }; + Params: Pick; + }>, + ): Promise> { + const companyId = request.params.company_id; + const userId = request.currentUser.id; + + const context = getSimpleExecutionContext(request); + const limit = parseInt(request.query.limit) || 100; + + const workspaces = ( + await gr.services.workspaces.getAllForUser({ userId }, { id: companyId }) + ).map(a => a.workspaceId); + + let channels: UserChannel[] = await gr.services.channels.channels + .getChannelsForUsersInWorkspace(companyId, "direct", userId, undefined, context) + .then(list => list.getEntities()); + + for (const workspaceId of workspaces) { + const workspaceChannels = await gr.services.channels.channels + .getChannelsForUsersInWorkspace(companyId, workspaceId, userId, undefined, context) + .then(list => list.getEntities()); + channels = [...channels, ...workspaceChannels]; + } + + channels = channels.sort( + (a, b) => + (b.last_activity || 0) / 100 + + (b.user_member.last_access || 0) - + ((a.user_member.last_access || 0) + (a.last_activity || 0) / 100), + ); + channels = channels.slice(0, 100); + + if (channels.length < limit) { + let otherChannels: UserChannel[] = []; + for (const workspaceId of workspaces) { + //Include channels we could join in this result + otherChannels = [ + ...otherChannels, + ...( + await gr.services.channels.channels.getAllChannelsInWorkspace( + companyId, + workspaceId, + context, + ) + ).map(ch => { + return { + ...ch, + user_member: null, + } as UserChannel; + }), + ]; + } + + channels = _.unionBy(channels, otherChannels, "id"); + } + + const userIncludedChannels: UsersIncludedChannel[] = await Promise.all( + channels.map(channel => { + return gr.services.channels.channels.includeUsersInDirectChannel(channel, userId); + }), + ); + + const resources = userIncludedChannels.slice(0, limit).map(r => ChannelObject.mapTo(r, {})); + await gr.services.channels.channels.completeWithStatistics(resources); + + await new Promise(r => setTimeout(r, 2000)); + + return { + resources, + }; + } +} + +function getExecutionContext( + request: FastifyRequest<{ Params: BaseChannelsParameters }>, +): WorkspaceExecutionContext { + return { + user: request.currentUser, + url: request.url, + method: request.routerMethod, + reqId: request.id, + transport: "http", + workspace: { + company_id: request.params.company_id, + workspace_id: request.params.workspace_id, + }, + }; +} + +function getChannelPendingEmailsExecutionContext( + request: FastifyRequest<{ + Params: ChannelPendingEmailsPrimaryKey | ChannelPendingEmailsDeleteQueryParameters; + }>, +): ChannelExecutionContext { + return { + user: request.currentUser, + url: request.url, + method: request.routerMethod, + reqId: request.id, + transport: "http", + channel: { + id: request.params.channel_id, + company_id: request.params.company_id, + workspace_id: request.params.workspace_id, + }, + }; +} + +function getSimpleExecutionContext(request: FastifyRequest): ExecutionContext { + return { + user: request.currentUser, + url: request.url, + method: request.routerMethod, + reqId: request.id, + transport: "http", + }; +} diff --git a/twake/backend/node/src/services/channels/web/controllers/index.ts b/twake/backend/node/src/services/channels/web/controllers/index.ts new file mode 100644 index 00000000..37fb690c --- /dev/null +++ b/twake/backend/node/src/services/channels/web/controllers/index.ts @@ -0,0 +1,3 @@ +export * from "./channel"; +export * from "./member"; +export * from "./tab"; diff --git a/twake/backend/node/src/services/channels/web/controllers/member.ts b/twake/backend/node/src/services/channels/web/controllers/member.ts new file mode 100644 index 00000000..60e1cb02 --- /dev/null +++ b/twake/backend/node/src/services/channels/web/controllers/member.ts @@ -0,0 +1,319 @@ +import { CrudController } from "../../../../core/platform/services/webserver/types"; +import { CrudException, Pagination } from "../../../../core/platform/framework/api/crud-service"; +import { + ChannelMember, + ChannelMemberPrimaryKey, + ChannelMemberReadCursors, + ChannelMemberWithUser, +} from "../../entities"; +import { + ChannelMemberParameters, + ChannelParameters, + CreateChannelMemberBody, + PaginationQueryParameters, + UpdateChannelMemberBody, +} from "../types"; +import { FastifyReply, FastifyRequest } from "fastify"; +import { ChannelExecutionContext } from "../../types"; +import { plainToClass } from "class-transformer"; +import { handleError } from "../../../../utils/handleError"; +import { getChannelRooms } from "../../services/member/realtime"; +import { + ResourceCreateResponse, + ResourceDeleteResponse, + ResourceGetResponse, + ResourceListResponse, + ResourceUpdateResponse, + User, +} from "../../../../utils/types"; +import gr from "../../../global-resolver"; +import { formatUser } from "../../../../utils/users"; + +export class ChannelMemberCrudController + implements + CrudController< + ResourceGetResponse, + ResourceCreateResponse, + ResourceListResponse, + ResourceDeleteResponse + > +{ + getPrimaryKey( + request: FastifyRequest<{ Params: ChannelMemberParameters }>, + ): ChannelMemberPrimaryKey { + return { + user_id: request.params.member_id, + channel_id: request.params.id, + company_id: request.params.company_id, + workspace_id: request.params.workspace_id, + }; + } + + async get( + request: FastifyRequest<{ Params: ChannelMemberParameters }>, + _reply: FastifyReply, + ): Promise> { + if (!isCurrentUser(request.params.member_id, request.currentUser)) { + throw CrudException.badRequest("User does not have enough rights to get member"); + } + const context = getExecutionContext(request); + const resource = await gr.services.channels.members.get(this.getPrimaryKey(request), context); + + if (!resource) { + throw CrudException.notFound(`Channel member ${request.params.member_id} not found`); + } + + return { + resource, + }; + } + + async save( + request: FastifyRequest<{ Body: CreateChannelMemberBody; Params: ChannelMemberParameters }>, + reply: FastifyReply, + ): Promise> { + const entity = plainToClass(ChannelMember, { + ...request.body.resource, + ...{ + company_id: request.params.company_id, + workspace_id: request.params.workspace_id, + channel_id: request.params.id, + }, + }); + + try { + const result = await gr.services.channels.members.save(entity, getExecutionContext(request)); + + if (result.entity) { + reply.code(201); + } + + return { + resource: result.entity, + }; + } catch (err) { + handleError(reply, err); + } + } + + async update( + request: FastifyRequest<{ Body: UpdateChannelMemberBody; Params: ChannelMemberParameters }>, + reply: FastifyReply, + ): Promise> { + const entity = plainToClass(ChannelMember, { + ...request.body.resource, + ...this.getPrimaryKey(request), + }); + + if (!isCurrentUser(entity.user_id, request.currentUser)) { + throw CrudException.badRequest("Current user can not update this member"); + } + + try { + const result = await gr.services.channels.members.save(entity, getExecutionContext(request)); + + if (result.entity) { + reply.code(200); + } + + return { + resource: result.entity, + }; + } catch (err) { + handleError(reply, err); + } + } + + async delete( + request: FastifyRequest<{ Params: ChannelMemberParameters }>, + reply: FastifyReply, + ): Promise { + try { + const deleteResult = await gr.services.channels.members.delete( + this.getPrimaryKey(request), + getExecutionContext(request), + ); + + if (deleteResult.deleted) { + reply.code(204); + + return { + status: "success", + }; + } + + return { + status: "error", + }; + } catch (err) { + handleError(reply, err); + } + } + + /** + * List channel members + * + * @param request + */ + async list( + request: FastifyRequest<{ + Querystring: PaginationQueryParameters & { company_role?: string; search?: string }; + Params: ChannelParameters; + }>, + ): Promise> { + let list: ChannelMember[] = []; + let nextPageToken: string = null; + const resources = []; + const context = getExecutionContext(request); + + if (request.query.search) { + const users = await gr.services.users.search( + new Pagination(request.query.page_token, request.query.limit), + { + search: request.query.search, + companyId: request.params.company_id, + }, + context, + ); + + nextPageToken = users.nextPage?.page_token; + + for (const user of users.getEntities()) { + const channelMember = await gr.services.channels.members.getChannelMember( + user, + { + company_id: request.params.company_id, + workspace_id: request.params.workspace_id, + id: request.params.id, + }, + undefined, + context, + ); + + if (channelMember) { + list.push(channelMember); + } + } + } else { + const channelMembers = await gr.services.channels.members.list( + new Pagination(request.query.page_token, request.query.limit), + { company_role: request.query.company_role }, + context, + ); + + nextPageToken = channelMembers.nextPage?.page_token; + list = channelMembers.getEntities(); + } + + for (const member of list) { + if (member) { + const user = await formatUser(await gr.services.users.getCached({ id: member.user_id }), { + includeCompanies: true, + }); + resources.push({ ...member, user }); + } + } + + return { + ...{ + resources, + }, + ...(request.query.websockets && { + websockets: gr.platformServices.realtime.sign( + getChannelRooms(request.params, request.currentUser), + request.currentUser.id, + ), + }), + next_page_token: nextPageToken, + }; + } + + /** + * + * @param request Private exists + * @param reply + */ + async exists( + request: FastifyRequest<{ Params: ChannelMemberParameters }>, + reply: FastifyReply, + ): Promise { + const context = getExecutionContext(request); + const resource = await gr.services.channels.members.get(this.getPrimaryKey(request), context); + + if (!resource) { + return reply.status(200).send({ has_access: false }); + } + + return reply.status(200).send({ has_access: true }); + } + + /** + * Lists the channel read sections for all members. + * + * @param {FastifyRequest<{ Params: ChannelParameters }>} request - the request object + * @param {FastifyReply} reply - the reply object + * @returns {Promise>} - the response + */ + async getAllChannelMembersReadSections( + request: FastifyRequest<{ Params: ChannelParameters }>, + reply: FastifyReply, + ): Promise> { + try { + const context = getExecutionContext(request); + const channelMembersReadSections = + await gr.services.channels.members.getChannelMembersReadSections(context); + + return { + resources: channelMembersReadSections.getEntities(), + }; + } catch (err) { + handleError(reply, err); + } + } + + /** + * Get the channel member read section for a user. + * + * @param {FastifyRequest<{ Params: ChannelMemberParameters }>} request - the request object + * @param {FastifyReply} reply - the reply object + * @returns {Promise>} - the read section for the member + */ + async getChannelMemberReadSections( + request: FastifyRequest<{ Params: ChannelMemberParameters }>, + reply: FastifyReply, + ): Promise> { + try { + const { member_id } = request.params; + const context = getExecutionContext(request); + const channelMembersReadSections = + await gr.services.channels.members.getChannelMemberReadSections(member_id, context); + + return { + resource: channelMembersReadSections, + }; + } catch (err) { + handleError(reply, err); + } + } +} + +function getExecutionContext( + request: FastifyRequest<{ Params: ChannelParameters }>, +): ChannelExecutionContext { + return { + user: request.currentUser, + url: request.url, + method: request.routerMethod, + reqId: request.id, + transport: "http", + channel: { + id: request.params.id, + company_id: request.params.company_id, + workspace_id: request.params.workspace_id, + }, + }; +} + +function isCurrentUser(memberId: string, user: User): boolean { + return memberId && memberId === user.id; +} diff --git a/twake/backend/node/src/services/channels/web/controllers/tab.ts b/twake/backend/node/src/services/channels/web/controllers/tab.ts new file mode 100644 index 00000000..9383f6d6 --- /dev/null +++ b/twake/backend/node/src/services/channels/web/controllers/tab.ts @@ -0,0 +1,204 @@ +import { CrudController } from "../../../../core/platform/services/webserver/types"; +import { CrudException, Pagination } from "../../../../core/platform/framework/api/crud-service"; +import { ChannelTab, ChannelTabPrimaryKey } from "../../entities"; +import { + ChannelParameters, + ChannelTabParameters, + CreateChannelTabBody, + PaginationQueryParameters, + UpdateChannelTabBody, +} from "../types"; +import { FastifyReply, FastifyRequest } from "fastify"; +import { ChannelExecutionContext } from "../../types"; +import { plainToClass } from "class-transformer"; +import { handleError } from "../../../../utils/handleError"; +import { + ResourceCreateResponse, + ResourceDeleteResponse, + ResourceEventsPayload, + ResourceGetResponse, + ResourceListResponse, + ResourceUpdateResponse, +} from "../../../../utils/types"; +import { localEventBus } from "../../../../core/platform/framework/event-bus"; +import { getTabsRealtimeRoom } from "../../services/tab"; +import gr from "../../../global-resolver"; + +export class ChannelTabCrudController + implements + CrudController< + ResourceGetResponse, + ResourceCreateResponse, + ResourceListResponse, + ResourceDeleteResponse + > +{ + getPrimaryKey(request: FastifyRequest<{ Params: ChannelTabParameters }>): ChannelTabPrimaryKey { + return { + id: request.params.tab_id, + channel_id: request.params.id, + company_id: request.params.company_id, + workspace_id: request.params.workspace_id, + }; + } + + async get( + request: FastifyRequest<{ Params: ChannelTabParameters }>, + _reply: FastifyReply, + ): Promise> { + const resource = await gr.services.tab.get( + this.getPrimaryKey(request), + getExecutionContext(request), + ); + + if (!resource) { + throw CrudException.notFound(`Channel member ${request.params.tab_id} not found`); + } + + return { + resource, + }; + } + + async save( + request: FastifyRequest<{ Body: CreateChannelTabBody; Params: ChannelTabParameters }>, + reply: FastifyReply, + ): Promise> { + const entity = plainToClass(ChannelTab, { + ...request.body.resource, + ...{ + company_id: request.params.company_id, + workspace_id: request.params.workspace_id, + channel_id: request.params.id, + }, + }); + + try { + const context = getExecutionContext(request); + const result = await gr.services.tab.save(entity, {}, context); + + if (result.entity) { + localEventBus.publish("channel:tab:created", { + tab: result.entity, + actor: getExecutionContext(request).user, + resourcesAfter: [result.entity], + channelParameters: request.params, + user: context.user, + }); + reply.code(201); + } + + return { + resource: result.entity, + }; + } catch (err) { + handleError(reply, err); + } + } + + async update( + request: FastifyRequest<{ Body: UpdateChannelTabBody; Params: ChannelTabParameters }>, + reply: FastifyReply, + ): Promise> { + const entity = plainToClass(ChannelTab, { + ...request.body.resource, + ...this.getPrimaryKey(request), + }); + + try { + const result = await gr.services.tab.save(entity, {}, getExecutionContext(request)); + + if (result.entity) { + reply.code(200); + } + + return { + resource: result.entity, + }; + } catch (err) { + handleError(reply, err); + } + } + + async delete( + request: FastifyRequest<{ Params: ChannelTabParameters }>, + reply: FastifyReply, + ): Promise { + try { + const context = getExecutionContext(request); + const deleteResult = await gr.services.tab.delete(this.getPrimaryKey(request)); + + if (deleteResult.deleted) { + localEventBus.publish("channel:tab:deleted", { + tab: deleteResult.entity, + actor: getExecutionContext(request).user, + resourcesAfter: [deleteResult.entity], + channelParameters: request.params, + user: context.user, + }); + reply.code(204); + + return { + status: "success", + }; + } + + return { + status: "error", + }; + } catch (err) { + handleError(reply, err); + } + } + + /** + * List channel tabs + * + * @param request + */ + async list( + request: FastifyRequest<{ + Querystring: PaginationQueryParameters; + Params: ChannelParameters; + }>, + ): Promise> { + const context = getExecutionContext(request); + const list = await gr.services.tab.list( + new Pagination(request.query.page_token, request.query.limit), + {}, + context, + ); + + return { + ...{ + resources: list.getEntities(), + }, + ...(request.query.websockets && { + websockets: gr.platformServices.realtime.sign( + [{ room: getTabsRealtimeRoom(context.channel) }], + context.user.id, + ), + }), + ...(list.page_token && { + next_page_token: list.page_token, + }), + }; + } +} + +function getExecutionContext( + request: FastifyRequest<{ Params: ChannelParameters }>, +): ChannelExecutionContext { + return { + user: request.currentUser, + url: request.url, + method: request.routerMethod, + reqId: request.id, + transport: "http", + channel: { + id: request.params.id, + company_id: request.params.company_id, + workspace_id: request.params.workspace_id, + }, + }; +} diff --git a/twake/backend/node/src/services/channels/web/index.ts b/twake/backend/node/src/services/channels/web/index.ts new file mode 100644 index 00000000..2945a147 --- /dev/null +++ b/twake/backend/node/src/services/channels/web/index.ts @@ -0,0 +1,12 @@ +import { FastifyInstance, FastifyRegisterOptions } from "fastify"; +import routes from "./routes"; + +export default ( + fastify: FastifyInstance, + options: FastifyRegisterOptions<{ + prefix: string; + }>, +): void => { + fastify.log.debug("Configuring /internal/services/channels/v1 routes"); + fastify.register(routes, options); +}; diff --git a/twake/backend/node/src/services/channels/web/middleware.ts b/twake/backend/node/src/services/channels/web/middleware.ts new file mode 100644 index 00000000..c0e77242 --- /dev/null +++ b/twake/backend/node/src/services/channels/web/middleware.ts @@ -0,0 +1,12 @@ +import { validate as validateUuid } from "uuid"; +import { ChannelVisibility } from "../types"; + +export function checkCompanyAndWorkspaceForUser( + companyId: string, + workspaceId: string, +): Promise { + return Promise.resolve( + validateUuid(companyId) && + (validateUuid(workspaceId) || workspaceId === ChannelVisibility.DIRECT), + ); +} diff --git a/twake/backend/node/src/services/channels/web/routes.ts b/twake/backend/node/src/services/channels/web/routes.ts new file mode 100644 index 00000000..3e40beb7 --- /dev/null +++ b/twake/backend/node/src/services/channels/web/routes.ts @@ -0,0 +1,270 @@ +import { FastifyInstance, FastifyPluginCallback } from "fastify"; +import { + BaseChannelsParameters, + ChannelParameters, + PaginationQueryParameters, + RecentChannelsParameters, +} from "./types"; +import { + createChannelMemberSchema, + createChannelSchema, + getChannelMemberSchema, + getChannelSchema, + updateChannelMemberSchema, + updateChannelSchema, +} from "./schemas"; +import { + ChannelCrudController, + ChannelMemberCrudController, + ChannelTabCrudController, +} from "./controllers"; +import { checkCompanyAndWorkspaceForUser } from "./middleware"; +import { FastifyRequest } from "fastify/types/request"; +import { checkUserBelongsToCompany } from "../../../utils/company"; + +const channelsUrl = "/companies/:company_id/workspaces/:workspace_id/channels"; +const membersUrl = `${channelsUrl}/:id/members`; +const tabsUrl = `${channelsUrl}/:id/tabs`; +const pendingEmailsUrl = `${channelsUrl}/:channel_id/pending_emails`; + +const routes: FastifyPluginCallback = (fastify: FastifyInstance, options, next) => { + const channelsController = new ChannelCrudController(); + const membersController = new ChannelMemberCrudController(); + const tabsController = new ChannelTabCrudController(); + + const accessControlCompanyOnly = async ( + request: FastifyRequest<{ Params: RecentChannelsParameters }>, + ) => { + await checkUserBelongsToCompany(request.currentUser.id, request.params.company_id); + }; + + const accessControl = async (request: FastifyRequest<{ Params: BaseChannelsParameters }>) => { + const authorized = await checkCompanyAndWorkspaceForUser( + request.params.company_id, + request.params.workspace_id, + ); + + if (!authorized) { + throw fastify.httpErrors.badRequest("Invalid company/workspace"); + } + }; + + const validateQuery = async ( + request: FastifyRequest<{ + Params: BaseChannelsParameters; + Querystring: PaginationQueryParameters; + }>, + ) => { + if (isNaN(+request.query.limit)) { + request.query.limit = "100"; + } + }; + + // channels + fastify.route({ + method: "GET", + url: channelsUrl, + preHandler: [accessControl, validateQuery], + preValidation: [fastify.authenticate], + handler: channelsController.list.bind(channelsController), + }); + + fastify.route({ + method: "GET", + url: `${channelsUrl}/:id`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + schema: getChannelSchema, + handler: channelsController.get.bind(channelsController), + }); + + fastify.route({ + method: "GET", + url: `${channelsUrl}/:id/thumbnail`, + handler: channelsController.thumbnail.bind(channelsController), + }); + + fastify.route({ + method: "POST", + url: channelsUrl, + preHandler: accessControl, + preValidation: [fastify.authenticate], + schema: createChannelSchema, + handler: channelsController.save.bind(channelsController), + }); + + fastify.route({ + method: "POST", + url: `${channelsUrl}/:id`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + schema: updateChannelSchema, + handler: channelsController.update.bind(channelsController), + }); + + fastify.route<{ Params: ChannelParameters }>({ + method: "DELETE", + url: `${channelsUrl}/:id`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + handler: channelsController.delete.bind(channelsController), + }); + + fastify.route<{ Params: ChannelParameters }>({ + method: "POST", + url: `${channelsUrl}/:id/read`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + handler: channelsController.updateRead.bind(channelsController), + }); + + fastify.route({ + method: "GET", + url: "/companies/:company_id/search", + preValidation: [fastify.authenticate], + handler: channelsController.search.bind(channelsController), + }); + + fastify.route({ + method: "GET", + url: "/companies/:company_id/channels/recent", + preHandler: accessControlCompanyOnly, + preValidation: [fastify.authenticate], + handler: channelsController.recent.bind(channelsController), + }); + + // members + + fastify.route({ + method: "GET", + url: membersUrl, + preHandler: accessControl, + preValidation: [fastify.authenticate], + handler: membersController.list.bind(membersController), + }); + + fastify.route({ + method: "POST", + url: membersUrl, + preHandler: accessControl, + preValidation: [fastify.authenticate], + schema: createChannelMemberSchema, + handler: membersController.save.bind(membersController), + }); + + fastify.route({ + method: "GET", + url: `${membersUrl}/:member_id`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + schema: getChannelMemberSchema, + handler: membersController.get.bind(membersController), + }); + + fastify.route({ + method: "POST", + url: `${membersUrl}/:member_id`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + schema: updateChannelMemberSchema, + handler: membersController.update.bind(membersController), + }); + + fastify.route({ + method: "DELETE", + url: `${membersUrl}/:member_id`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + handler: membersController.delete.bind(membersController), + }); + + fastify.route({ + method: "GET", + url: `${membersUrl}/read_sections`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + handler: membersController.getAllChannelMembersReadSections.bind(membersController), + }); + + fastify.route({ + method: "GET", + url: `${membersUrl}/:member_id/read_sections`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + handler: membersController.getChannelMemberReadSections.bind(membersController), + }); + + // pending_emails + + fastify.route({ + method: "GET", + url: pendingEmailsUrl, + preHandler: [accessControl, validateQuery], + preValidation: [fastify.authenticate], + //schema: getChannelPendingEmailsSchema, + handler: channelsController.findPendingEmails.bind(channelsController), + }); + + fastify.route({ + method: "POST", + url: pendingEmailsUrl, + preHandler: accessControl, + preValidation: [fastify.authenticate], + //schema: createChannelPendingEmailsSchema, + handler: channelsController.savePendingEmails.bind(channelsController), + }); + + fastify.route({ + method: "DELETE", + url: `${pendingEmailsUrl}/:email`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + handler: channelsController.deletePendingEmails.bind(channelsController), + }); + + // tabs + + fastify.route({ + method: "GET", + url: tabsUrl, + preHandler: accessControl, + preValidation: [fastify.authenticate], + handler: tabsController.list.bind(tabsController), + }); + + fastify.route({ + method: "POST", + url: tabsUrl, + preHandler: accessControl, + preValidation: [fastify.authenticate], + handler: tabsController.save.bind(tabsController), + }); + + fastify.route({ + method: "GET", + url: `${tabsUrl}/:tab_id`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + handler: tabsController.get.bind(tabsController), + }); + + fastify.route({ + method: "POST", + url: `${tabsUrl}/:tab_id`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + handler: tabsController.update.bind(tabsController), + }); + + fastify.route({ + method: "DELETE", + url: `${tabsUrl}/:tab_id`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + handler: tabsController.delete.bind(tabsController), + }); + + next(); +}; + +export default routes; diff --git a/twake/backend/node/src/services/channels/web/schemas.ts b/twake/backend/node/src/services/channels/web/schemas.ts new file mode 100644 index 00000000..7fdc8961 --- /dev/null +++ b/twake/backend/node/src/services/channels/web/schemas.ts @@ -0,0 +1,301 @@ +import { webSocketSchema } from "../../../utils/types"; + +const channelMemberSchema = { + type: "object", + properties: { + id: { type: "string" }, + user_id: { type: "string" }, + channel_id: { type: "string" }, + company_id: { type: "string" }, + workspace_id: { type: "string" }, + type: { type: "string", enum: ["member", "guest", "bot"] }, + favorite: { type: "boolean" }, + last_access: { type: "number" }, + last_increment: { type: "number" }, + notification_level: { + type: "string", + enum: ["all", "none", "group_mentions", "user_mentions"], + }, + }, +}; + +const channelSchema = { + type: "object", + properties: { + id: { type: "string" }, + company_id: { type: "string" }, + workspace_id: { type: "string" }, + type: { type: "string", enum: ["workspace", "direct"] }, + name: { type: "string" }, + description: { type: "string" }, + archivation_date: { type: "number" }, + archived: { type: "boolean" }, + channel_group: { type: "string" }, + connectors: { type: ["array", "null"] }, + icon: { type: "string" }, + default: { type: "boolean" }, + members: { type: ["array", "null"] }, + users: { type: ["array", "null"] }, + owner: { type: "string" }, + visibility: { type: "string", enum: ["private", "public", "direct"] }, + last_activity: { type: "number" }, + user_member: {}, + direct_channel_members: { type: "array" }, + stats: {}, + is_readonly: { type: "boolean" }, + }, +}; + +const channelTabSchema = { + type: "object", + properties: { + company_id: { type: "string" }, + workspace_id: { type: "string" }, + channel_id: { type: "string" }, + id: { type: "string" }, + owner: { type: "string" }, + order: { type: "string" }, + configuration: { + type: "object", + properties: { + board_id: { type: "string" }, + directory_id: { type: "string" }, + }, + }, + application_id: { type: "string" }, + name: { type: "string" }, + }, +}; + +export const createChannelSchema = { + body: { + type: "object", + properties: { + options: { + type: "object", + properties: { + members: { type: "array" }, + }, + }, + resource: { + type: "object", + }, + }, + required: ["resource"], + }, + response: { + 201: { + type: "object", + properties: { + websocket: webSocketSchema, + resource: channelSchema, + }, + required: ["resource"], + }, + }, +}; + +export const updateChannelSchema = { + body: { + type: "object", + properties: { + resource: { + type: "object", + }, + }, + required: ["resource"], + }, + response: { + 200: { + type: "object", + properties: { + websocket: webSocketSchema, + resource: channelSchema, + }, + required: ["resource"], + }, + }, +}; + +export const getChannelSchema = { + request: { + properties: { + company_id: { type: "string" }, + workspace_id: { type: "string" }, + }, + required: ["company_id", "workspace_id"], + }, + response: { + 200: { + type: "object", + properties: { + websocket: webSocketSchema, + resource: channelSchema, + }, + }, + }, +}; + +export const getChannelMemberSchema = { + response: { + 200: { + type: "object", + properties: { + websocket: webSocketSchema, + resource: channelMemberSchema, + }, + required: ["resource"], + }, + }, +}; + +export const createChannelMemberSchema = { + body: { + type: "object", + properties: { + resource: channelMemberSchema, + }, + required: ["resource"], + }, + response: { + 201: { + type: "object", + properties: { + websocket: webSocketSchema, + resource: channelMemberSchema, + }, + required: ["resource"], + }, + }, +}; + +export const updateChannelMemberSchema = { + body: { + type: "object", + properties: { + resource: { + type: "object", + properties: { + favorite: { type: "boolean" }, + notification_level: { type: "string" }, + }, + }, + }, + required: ["resource"], + }, + response: { + 200: { + type: "object", + properties: { + websocket: webSocketSchema, + resource: channelMemberSchema, + }, + required: ["resource"], + }, + }, +}; + +export const getChannelTabSchema = { + response: { + 200: { + type: "object", + properties: { + websocket: webSocketSchema, + resource: channelTabSchema, + }, + required: ["resource"], + }, + }, +}; + +export const createChannelTabSchema = { + body: { + type: "object", + properties: { + resource: { + type: "object", + properties: {}, + }, + }, + required: ["resource"], + }, + response: { + 201: { + type: "object", + properties: { + websocket: webSocketSchema, + resource: channelTabSchema, + }, + required: ["resource"], + }, + }, +}; + +export const updateChannelTabSchema = { + body: { + type: "object", + properties: { + resource: { + type: "object", + properties: {}, + }, + }, + required: ["resource"], + }, + response: { + 200: { + type: "object", + properties: { + websocket: webSocketSchema, + resource: channelTabSchema, + }, + required: ["resource"], + }, + }, +}; + +const channelPendingEmailsSchema = { + type: "object", + properties: { + company_id: { type: "string" }, + workspace_id: { type: "string" }, + channel_id: { type: "string" }, + email: { type: "string" }, + }, +}; + +export const getChannelPendingEmailsSchema = { + response: { + 200: { + type: "object", + properties: { + websocket: webSocketSchema, + resource: channelPendingEmailsSchema, + }, + required: ["resource"], + }, + }, +}; + +export const createChannelPendingEmailsSchema = { + body: { + type: "object", + properties: { + resource: { + type: "object", + properties: {}, + }, + }, + required: ["resource"], + }, + response: { + 201: { + type: "object", + properties: { + websocket: webSocketSchema, + resource: channelPendingEmailsSchema, + }, + required: ["resource"], + }, + }, +}; diff --git a/twake/backend/node/src/services/channels/web/types.ts b/twake/backend/node/src/services/channels/web/types.ts new file mode 100644 index 00000000..dad0eabb --- /dev/null +++ b/twake/backend/node/src/services/channels/web/types.ts @@ -0,0 +1,117 @@ +import { Channel, ChannelMember, ChannelPendingEmails, ChannelTab } from "../entities"; + +export declare type DirectChannel = "direct"; + +export interface RecentChannelsParameters { + company_id: string; +} + +export interface BaseChannelsParameters { + company_id: string; + workspace_id: string | DirectChannel; +} + +export interface ChannelParameters extends BaseChannelsParameters { + /** the channel id */ + id: string; +} + +export interface ChannelMemberParameters extends ChannelParameters { + member_id: string; +} + +export interface PaginationQueryParameters { + page_token?: string; + limit?: string; + websockets?: boolean; +} + +export interface ChannelListQueryParameters extends PaginationQueryParameters { + include_users?: string; + search_query?: string; + mine?: boolean; +} + +export interface ChannelSearchQueryParameters extends PaginationQueryParameters { + q: string; +} + +export class CreateChannelBody { + options?: ChannelCreateOptions; + resource: ChannelCreateResource; +} + +export class ChannelCreateOptions { + /** + * Members to add to channel in case of direct channel + */ + members?: string[]; +} + +export type ChannelSaveOptions = ChannelCreateOptions & { + /** + * Add the channel creator as member. + */ + addCreatorAsMember?: boolean; +}; + +export class ChannelListOptions { + channels?: string[]; + mine?: boolean; + company_role?: string; + user_id?: string; +} + +export class UpdateChannelBody { + resource: ChannelUpdateResource; +} + +export class ReadChannelBody { + value: boolean; +} + +export type ChannelCreateResource = Pick; + +export type ChannelUpdateResource = Pick; + +// channel members + +export class CreateChannelMemberBody { + resource: Pick; +} + +export class UpdateChannelMemberBody { + resource: Pick; +} + +export type ChannelMemberSaveOptions = null; + +// channel tabs + +export interface ChannelTabParameters extends ChannelParameters { + tab_id: string; +} + +export class CreateChannelTabBody { + resource: ChannelTab; +} + +export class UpdateChannelTabBody { + resource: ChannelTab; +} + +export type ChannelTabSaveOptions = { + resource: ChannelTab; +}; + +export interface ChannelPendingEmailsParameters extends BaseChannelsParameters { + channel_id: string; +} + +export interface ChannelPendingEmailsDeleteQueryParameters extends ChannelPendingEmailsParameters { + email: ChannelPendingEmails["email"]; +} + +export interface ChannelPendingEmailsListQueryParameters extends BaseChannelsParameters { + channel_id: string; +} diff --git a/twake/backend/node/src/services/console/client-factory.ts b/twake/backend/node/src/services/console/client-factory.ts new file mode 100644 index 00000000..839a4d82 --- /dev/null +++ b/twake/backend/node/src/services/console/client-factory.ts @@ -0,0 +1,21 @@ +import { ConsoleRemoteClient } from "./clients/remote"; +import { ConsoleServiceClient } from "./client-interface"; +import { ConsoleType } from "./types"; +import { ConsoleInternalClient } from "./clients/internal"; +import { ConsoleServiceImpl } from "./service"; + +class StaticConsoleClientFactory { + create(consoleInstance: ConsoleServiceImpl): ConsoleServiceClient { + const type: ConsoleType = consoleInstance.consoleType; + switch (type) { + case "remote": + return new ConsoleRemoteClient(consoleInstance, false); + case "internal": + return new ConsoleInternalClient(consoleInstance); + default: + throw new Error(`${type} is not supported`); + } + } +} + +export const ConsoleClientFactory = new StaticConsoleClientFactory(); diff --git a/twake/backend/node/src/services/console/client-interface.ts b/twake/backend/node/src/services/console/client-interface.ts new file mode 100644 index 00000000..878b90ce --- /dev/null +++ b/twake/backend/node/src/services/console/client-interface.ts @@ -0,0 +1,66 @@ +import { + ConsoleCompany, + ConsoleHookCompany, + ConsoleHookUser, + CreateConsoleCompany, + CreateConsoleUser, + CreatedConsoleCompany, + CreatedConsoleUser, + CreateInternalUser, + UpdateConsoleUserRole, + UpdatedConsoleUserRole, +} from "./types"; +import User from "../user/entities/user"; +import Company, { CompanySearchKey } from "../user/entities/company"; + +export interface ConsoleServiceClient { + /** + * Create a company + * + * @param company + */ + createCompany(company: CreateConsoleCompany): Promise; + + /** + * Add user to company + * + * @param company + * @param user + * @param inviter + */ + addUserToCompany(company: ConsoleCompany, user: CreateConsoleUser): Promise; + + /** + * Add user to twake in general (for non-console version) + * + * @param user + */ + addUserToTwake(user: CreateInternalUser): Promise; + + /** + * Update user role + * + * @param company + * @param user + */ + updateUserRole( + company: ConsoleCompany, + user: UpdateConsoleUserRole, + ): Promise; + + updateLocalCompanyFromConsole(companyDTO: ConsoleHookCompany): Promise; + + updateLocalUserFromConsole(code: string): Promise; + + removeCompanyUser(consoleUserId: string, company: Company): Promise; + + removeUser(consoleUserId: string): Promise; + + removeCompany(companySearchKey: CompanySearchKey): Promise; + + fetchCompanyInfo(consoleCompanyCode: string): Promise; + + getUserByAccessToken(accessToken: string): Promise; + + resendVerificationEmail(email: string): Promise; +} diff --git a/twake/backend/node/src/services/console/clients/internal.ts b/twake/backend/node/src/services/console/clients/internal.ts new file mode 100644 index 00000000..59af4f0b --- /dev/null +++ b/twake/backend/node/src/services/console/clients/internal.ts @@ -0,0 +1,107 @@ +import { AxiosInstance } from "axios"; +import { merge } from "lodash"; + +import { ConsoleServiceClient } from "../client-interface"; +import { + ConsoleCompany, + ConsoleHookCompany, + ConsoleHookUser, + CreateConsoleCompany, + CreateConsoleUser, + CreatedConsoleCompany, + CreatedConsoleUser, + UpdateConsoleUserRole, + UpdatedConsoleUserRole, +} from "../types"; + +import { v1 as uuidv1 } from "uuid"; +import User, { getInstance as getUserInstance } from "../../user/entities/user"; +import Company, { CompanySearchKey } from "../../user/entities/company"; +import { logger } from "../../../core/platform/framework/logger"; +import gr from "../../global-resolver"; +import { ConsoleServiceImpl } from "../service"; + +export class ConsoleInternalClient implements ConsoleServiceClient { + version: "1"; + client: AxiosInstance; + + constructor(private consoleInstance: ConsoleServiceImpl) {} + + async addUserToCompany( + company: ConsoleCompany, + user: CreateConsoleUser, + ): Promise { + logger.info("Internal: addUserToCompany"); + await gr.services.companies.setUserRole(company.id, user.id, user.role); + return merge(user, { _id: user.id }); + } + + async updateUserRole( + _company: ConsoleCompany, + _user: UpdateConsoleUserRole, + ): Promise { + logger.info("Internal: updateUserRole"); + throw Error("ConsoleInternalClient.updateUserRole is not implemented"); + } + + async createCompany(_company: CreateConsoleCompany): Promise { + logger.info("Internal: "); + throw Error("ConsoleInternalClient.createCompany is not implemented"); + } + + async addUserToTwake(user: CreateConsoleUser): Promise { + logger.info("Internal: addUserToTwake"); + const userToCreate = getUserInstance({ + id: uuidv1(), + email_canonical: user.email, + first_name: user.firstName, + last_name: user.lastName, + }); + + const createdUser = await gr.services.users.save(userToCreate).then(result => result.entity); + if (user.password) { + await gr.services.users.setPassword({ id: createdUser.id }, user.password); + } + return createdUser; + } + + updateLocalCompanyFromConsole(_companyDTO: ConsoleHookCompany): Promise { + logger.info("Internal: updateLocalCompanyFromConsole"); + throw new Error("Method should not be implemented."); + } + + updateLocalUserFromConsole(_code: string): Promise { + logger.info("Internal: updateLocalUserFromConsole"); + throw new Error("Method should not be implemented."); + } + + removeCompany(_companySearchKey: CompanySearchKey): Promise { + logger.info("Internal: removeCompany"); + throw new Error("Method should not be implemented."); + } + + removeCompanyUser(_consoleUserId: string, _company: Company): Promise { + logger.info("Internal: removeCompanyUser"); + throw new Error("Method should not be implemented."); + } + + removeUser(_consoleUserId: string): Promise { + logger.info("Internal: removeUser"); + throw new Error("Method should not be implemented."); + } + + fetchCompanyInfo(_consoleCompanyCode: string): Promise { + logger.info("Internal: fetchCompanyInfo"); + throw new Error("Method should not be implemented."); + } + + getUserByAccessToken(_accessToken: string): Promise { + logger.info("Internal: getUserByAccessToken"); + throw new Error("Method should not be implemented."); + } + + resendVerificationEmail(_accessToken: string): Promise { + logger.info("Internal: resendVerificationEmail"); + throw new Error("Method should not be implemented."); + } +} diff --git a/twake/backend/node/src/services/console/clients/remote.ts b/twake/backend/node/src/services/console/clients/remote.ts new file mode 100644 index 00000000..14e8ab06 --- /dev/null +++ b/twake/backend/node/src/services/console/clients/remote.ts @@ -0,0 +1,499 @@ +import axios, { AxiosInstance } from "axios"; +import { v1 as uuidv1 } from "uuid"; +import { ConsoleServiceClient } from "../client-interface"; +import { + ConsoleCompany, + ConsoleHookCompany, + ConsoleHookUser, + ConsoleOptions, + CreateConsoleCompany, + CreateConsoleUser, + CreatedConsoleCompany, + CreatedConsoleUser, + UpdateConsoleUserRole, + UpdatedConsoleUserRole, +} from "../types"; + +import User, { getInstance } from "../../user/entities/user"; +import Company, { + CompanySearchKey, + getInstance as getCompanyInstance, +} from "../../user/entities/company"; +import { CrudException } from "../../../core/platform/framework/api/crud-service"; +import coalesce from "../../../utils/coalesce"; +import { logger } from "../../../core/platform/framework/logger"; +import { CompanyFeaturesEnum, CompanyLimitsEnum } from "../../user/web/types"; +import gr from "../../global-resolver"; +import { ConsoleServiceImpl } from "../service"; + +export class ConsoleRemoteClient implements ConsoleServiceClient { + version: "1"; + client: AxiosInstance; + + private infos: ConsoleOptions; + + constructor(consoleInstance: ConsoleServiceImpl, private dryRun: boolean) { + this.infos = consoleInstance.consoleOptions; + this.client = axios.create({ baseURL: this.infos.url }); + } + + private auth() { + return { username: this.infos.username, password: this.infos.password }; + } + + async addUserToCompany( + company: ConsoleCompany, + user: CreateConsoleUser, + ): Promise { + logger.info("Remote: addUserToCompany"); + + const isNewConsole = this.infos.new_console; + + if (this.dryRun) { + return { + _id: uuidv1(), + }; + } + + if (user.skipInvite && user.name && user.email && user.password) { + return this.client + .post(`/api/companies/${company.code}/users`, user, { + auth: this.auth(), + headers: { + "Content-Type": "application/json", + }, + params: { + skipInvite: user.skipInvite, + }, + }) + .then(({ data }) => data); + } else { + const invitationData = { + role: user.role, + emails: [ + { + email: user.email, + role: user.role, + }, + ], + inviter: { email: user.inviterEmail }, + ...(isNewConsole + ? { + applicationCodes: ["twake"], + } + : {}), + }; + + const result = await this.client + .post( + `/api/companies/${company.code}/${isNewConsole ? "invitations" : "users/invitation"}`, + invitationData, + { + auth: this.auth(), + headers: { + "Content-Type": "application/json", + }, + }, + ) + .then(async ({ data, status }) => { + //Fixme: When console solve https://gitlab.com/COMPANY_LINAGORA/software/saas/twake-console-account/-/issues/36 + // we can remove this fallback + if ([200, 201].indexOf(status) >= 0) { + return data; + } else { + return this.client + .post(`/api/companies/${company.code}/users`, user, { + auth: this.auth(), + headers: { + "Content-Type": "application/json", + }, + params: { + skipInvite: user.skipInvite, + }, + }) + .then(({ data }) => data); + } + }); + + return result; + } + } + + async updateUserRole( + company: ConsoleCompany, + user: UpdateConsoleUserRole, + ): Promise { + logger.info("Remote: updateUserRole"); + + if (this.dryRun) { + return { + id: user.id, + role: user.role, + }; + } + + const result = await this.client + .put( + `/api/companies/${company.code}/users/${user.id}`, + { role: user.role }, + { + auth: this.auth(), + headers: { + "Content-Type": "application/json", + }, + }, + ) + .then(({ data }) => data); + + return result; + } + + async createCompany(company: CreateConsoleCompany): Promise { + logger.info("Remote: createCompany"); + + if (this.dryRun) { + return company; + } + + const result = await this.client + .post("/api/companies", company, { + auth: this.auth(), + headers: { + "Content-Type": "application/json", + }, + }) + .then(({ data }) => data); + + return result; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + addUserToTwake(user: CreateConsoleUser): Promise { + logger.info("Remote: addUserToTwake"); + //should do noting for real console + return Promise.resolve(undefined); + } + + async updateLocalCompanyFromConsole(partialCompanyDTO: ConsoleHookCompany): Promise { + logger.info("Remote: updateLocalCompanyFromConsole"); + + const companyDTO = await this.fetchCompanyInfo(partialCompanyDTO.details.code); + + let company = await gr.services.companies.getCompany({ + identity_provider_id: companyDTO.details.code, + }); + + if (!company) { + const newCompany = getCompanyInstance({ + id: uuidv1(), + identity_provider: "console", + identity_provider_id: companyDTO.details.code, + }); + company = await gr.services.companies.createCompany(newCompany); + } + + const details = companyDTO.details; + + if (details) { + company.name = coalesce(details.name, company.name); + company.displayName = coalesce(details.name, company.displayName); + + const avatar = details.avatar; + + company.logo = + details.logo || + (avatar && avatar.type && avatar.type !== "url" + ? this.infos.url.replace(/\/$/, "") + "/api/avatars/" + avatar.value + : companyDTO.value || ""); + } + + if (!company.plan) { + company.plan = { name: "", limits: undefined, features: undefined }; + } + + const limits = companyDTO.limits.twake || companyDTO.limits; + + //FIXME this is a hack right now! + let planFeatures: any = { + [CompanyFeaturesEnum.CHAT_GUESTS]: true, + [CompanyFeaturesEnum.CHAT_MESSAGE_HISTORY]: true, + [CompanyFeaturesEnum.CHAT_MULTIPLE_WORKSPACES]: true, + [CompanyFeaturesEnum.CHAT_EDIT_FILES]: true, + [CompanyFeaturesEnum.CHAT_UNLIMITED_STORAGE]: true, + [CompanyFeaturesEnum.COMPANY_INVITE_MEMBER]: true, + }; + + if (limits.members < 0 && this.infos.type === "remote") { + //Hack to say this is free version + planFeatures = { + [CompanyFeaturesEnum.CHAT_GUESTS]: false, + [CompanyFeaturesEnum.CHAT_MESSAGE_HISTORY]: false, + [CompanyFeaturesEnum.CHAT_MULTIPLE_WORKSPACES]: false, + [CompanyFeaturesEnum.CHAT_EDIT_FILES]: false, + [CompanyFeaturesEnum.CHAT_UNLIMITED_STORAGE]: false, // Currently inactive + }; + company.plan.name = "free"; + } else { + company.plan.name = "standard"; + } + company.plan.features = { ...planFeatures }; + company.plan.limits = { + [CompanyLimitsEnum.CHAT_MESSAGE_HISTORY_LIMIT]: 10000, // To remove duplicata since we define this in formatCompany function + [CompanyLimitsEnum.COMPANY_MEMBERS_LIMIT]: limits["members"], + [CompanyLimitsEnum.COMPANY_GUESTS_LIMIT]: limits["guests"], + }; + + company.stats = coalesce(companyDTO.stats, company.stats); + + await gr.services.companies.updateCompany(company); + + return company; + } + + async updateLocalUserFromConsole(code: string): Promise { + logger.info("Remote: updateLocalUserFromConsole"); + + const userDTO = await this.fetchUserInfo(code); + + if (!userDTO) { + throw CrudException.badRequest("User not found on Console"); + } + + const roles = userDTO.roles.filter( + role => role.applications === undefined || role.applications.find(a => a.code === "twake"), + ); + + let user = await gr.services.users.getByConsoleId(userDTO._id); + + if (!user) { + if (!userDTO.email) { + throw CrudException.badRequest("Email is required"); + } + + let username = userDTO.email + .split("@")[0] + .toLocaleLowerCase() + .replace(/[^a-zA-Z0-9]/g, "") + .replace(/ +/g, "_"); + + if (await gr.services.users.isEmailAlreadyInUse(userDTO.email)) { + const user = await gr.services.users.getByEmail(userDTO.email); + + if (user.identity_provider === "console") { + let emailUserOnConsole = null; + try { + emailUserOnConsole = await this.fetchUserInfo(user.identity_provider_id); + } catch (err) {} + if (emailUserOnConsole?._id) { + throw CrudException.badRequest( + `Console user not created because email already exists on console with different id: ${emailUserOnConsole._id} while requested to provision user with id: ${userDTO._id}`, + ); + } + + //If not present on console, then anonymise this one and create a new one + await gr.services.users.anonymizeAndDelete( + { id: user.id }, + { + user: { id: user.id, server_request: true }, + }, + ); + + //Now we can create the new user + } + } + + username = await gr.services.users.getAvailableUsername(username); + if (!username) { + throw CrudException.badRequest("Console user not created because username already exists"); + } + + user = getInstance({}); + user.username_canonical = (username || "").toLocaleLowerCase(); + user.email_canonical = userDTO.email; + user.deleted = false; + } + + user.email_canonical = coalesce(userDTO.email, user.email_canonical); + user.phone = ""; + user.first_name = coalesce(userDTO.name, user.first_name); + user.last_name = coalesce(userDTO.surname, user.last_name); + user.identity_provider = "console"; + user.identity_provider_id = userDTO._id; + user.mail_verified = coalesce(userDTO.isVerified, user.mail_verified); + if (userDTO.preference) { + user.preferences = user.preferences || {}; + user.preferences.allow_tracking = coalesce( + userDTO.preference.allowTrackingPersonalInfo, + user.preferences?.allow_tracking, + ); + user.preferences.language = coalesce(userDTO.preference.locale, user.preferences?.language); + user.preferences.timezone = coalesce(userDTO.preference.timeZone, user.preferences?.timezone); + } + + const avatar = userDTO.avatar; + + user.picture = + avatar && avatar.type && avatar.type !== "url" + ? this.infos.url.replace(/\/$/, "") + "/api/avatars/" + avatar.value + : ""; + + await gr.services.users.save(user); + + const getCompanyByCode = async (companyCode: string) => { + let company = await gr.services.companies.getCompany({ + identity_provider_id: companyCode, + }); + if (!company) { + const companyDTO = await this.fetchCompanyInfo(companyCode); + await this.updateLocalCompanyFromConsole(companyDTO); + company = await gr.services.companies.getCompany({ + identity_provider_id: companyCode, + }); + } + return company; + }; + + const updatedListOfCompanies = []; + if (roles) { + for (const role of roles) { + const companyConsoleCode = role.targetCode; + const roleName = role.roleCode; + const company = await getCompanyByCode(companyConsoleCode); + if (!company) { + throw CrudException.notFound(`Company ${companyConsoleCode} not found`); + } + //Make sure user is active, if not we remove it + if (role.status !== "deactivated") { + updatedListOfCompanies.push(company); + const applications = (role.applications || []).map(a => a.code); + await gr.services.companies.setUserRole(company.id, user.id, roleName, applications); + } + } + } + + // Remove user from companies not in the console + const currentCompanies = await gr.services.companies.getAllForUser(user.id); + for (const company of currentCompanies) { + if (!updatedListOfCompanies.map(c => c.id).includes(company.group_id)) { + await gr.services.companies.removeUserFromCompany( + { id: company.group_id }, + { id: user.id }, + ); + } + } + + await gr.services.users.save(user, { user: { id: user.id, server_request: true } }); + + return user; + } + + async removeCompanyUser(consoleUserId: string, company: Company): Promise { + logger.info("Remote: removeCompanyUser"); + + const user = await gr.services.users.getByConsoleId(consoleUserId); + if (!user) { + throw CrudException.notFound(`User ${consoleUserId} doesn't exists`); + } + await gr.services.companies.removeUserFromCompany({ id: company.id }, { id: user.id }); + } + + async removeUser(consoleUserId: string): Promise { + logger.info("Remote: removeUser"); + + const user = await gr.services.users.getByConsoleId(consoleUserId); + + if (!user) { + throw new Error("User does not exists on Twake."); + } + + await gr.services.users.anonymizeAndDelete( + { id: user.id }, + { + user: { id: user.id, server_request: true }, + }, + ); + } + + async removeCompany(companySearchKey: CompanySearchKey): Promise { + logger.info("Remote: removeCompany"); + await gr.services.companies.removeCompany(companySearchKey); + } + + fetchCompanyInfo(consoleCompanyCode: string): Promise { + logger.info(`Remote: fetchCompanyInfo ${consoleCompanyCode}`); + return this.client + .get(`/api/companies/${consoleCompanyCode}`, { + auth: this.auth(), + headers: { + "Content-Type": "application/json", + }, + }) + .then(({ data }) => data.company) + .catch(e => { + if (e.response.status === 401) { + throw CrudException.forbidden("Bad console credentials"); + } + throw e; + }); + } + + fetchUserInfo(consoleUserId: string): Promise { + logger.info(`Remote: fetchUserInfo ${consoleUserId}`); + return this.client + .get(`/api/users/${consoleUserId}`, { + auth: this.auth(), + headers: { + "Content-Type": "application/json", + }, + }) + .then(({ data }) => data) + .catch(e => { + if (e.response.status === 401) { + throw CrudException.forbidden("Bad console credentials"); + } + throw e; + }); + } + + getUserByAccessToken(accessToken: string): Promise { + logger.info("Remote: getUserByAccessToken"); + return this.client + .get("/api/users/profile", { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${accessToken}`, + }, + }) + .then(({ data }) => data) + .catch(e => { + if (e.response?.status === 401) { + throw CrudException.forbidden("Bad access token credentials"); + } + throw e; + }); + } + + async resendVerificationEmail(email: string) { + logger.info("Remote: resendVerificationEmail"); + return this.client + .post( + "/api/users/resend-verification-email", + { + email, + }, + { + auth: this.auth(), + headers: { + "Content-Type": "application/json", + }, + }, + ) + .then(({ data }) => data) + .catch(e => { + if (e.response.status === 401) { + throw CrudException.forbidden("Bad credentials"); + } + throw e; + }); + } +} diff --git a/twake/backend/node/src/services/console/index.ts b/twake/backend/node/src/services/console/index.ts new file mode 100644 index 00000000..43eac0d2 --- /dev/null +++ b/twake/backend/node/src/services/console/index.ts @@ -0,0 +1,23 @@ +import { Prefix, TwakeService } from "../../core/platform/framework"; +import WebServerAPI from "../../core/platform/services/webserver/provider"; +import web from "./web"; + +@Prefix("/internal/services/console/v1") +export default class ConsoleService extends TwakeService { + version = "1"; + name = "console"; + + public async doInit(): Promise { + const fastify = this.context.getProvider("webserver").getServer(); + fastify.register((instance, _opts, next) => { + web(instance, { prefix: this.prefix }); + next(); + }); + return this; + } + + // TODO: remove + api(): undefined { + return undefined; + } +} diff --git a/twake/backend/node/src/services/console/processing/merge.ts b/twake/backend/node/src/services/console/processing/merge.ts new file mode 100644 index 00000000..62fe2316 --- /dev/null +++ b/twake/backend/node/src/services/console/processing/merge.ts @@ -0,0 +1,426 @@ +import passwordGenerator from "generate-password"; +import { concat, EMPTY, forkJoin, from, Observable, ReplaySubject } from "rxjs"; +import { + count, + distinct, + filter, + groupBy, + map, + mergeMap, + min, + share, + tap, + toArray, +} from "rxjs/operators"; +import { getLogger } from "../../../core/platform/framework"; +import { + ExecutionContext, + Paginable, + Pagination, +} from "../../../core/platform/framework/api/crud-service"; +import Company from "../../user/entities/company"; +import User from "../../user/entities/user"; +import { + CompanyCreatedStreamObject, + CompanyReport, + ConsoleOptions, + CreatedConsoleCompany, + CreatedConsoleUser, + MergeProgress, + ProcessReport, + UpdateConsoleUserRole, + UserCreatedStreamObject, + UserReport, +} from "../types"; +import { getInstance as getExternalUserInstance } from "../../user/entities/external_user"; +import { getInstance as getExternalGroupInstance } from "../../user/entities/external_company"; +import CompanyUser from "../../user/entities/company_user"; +import { ConsoleRemoteClient } from "../clients/remote"; +import { ConsoleServiceClient } from "../client-interface"; +import { DatabaseServiceAPI } from "../../../core/platform/services/database/api"; +import { CompanyUserRole } from "../../user/web/types"; +import gr from "../../global-resolver"; +import { ConsoleServiceImpl } from "../service"; + +const logger = getLogger("console.process.merge"); + +export class MergeProcess { + private client: ConsoleServiceClient; + + constructor( + private database: DatabaseServiceAPI, + private dryRun: boolean, + private consoleId: string = "console", + private linkExternal: boolean = true, + consoleClientOptions: ConsoleOptions, + ) { + const consoleService = new ConsoleServiceImpl(consoleClientOptions); + this.client = new ConsoleRemoteClient(consoleService, dryRun); + } + + merge(concurrent: number = 1): MergeProgress { + const progress$ = new ReplaySubject(); + const { users$, companies$ } = this.getStreams(concurrent); + + const owners$ = users$.pipe( + // get only the admins + filter(userInCompany => userInCompany.source.user.level.valueOf() === 3), + // group by company id + groupBy(userInCompany => userInCompany.source.company.id), + mergeMap(group => + group.pipe( + // get the admin with the smaller creation date, let's say that this is the first one in the company so it is the owner + min((a, b) => { + return (a.source?.user?.dateAdded || 0) <= (b.source?.user?.dateAdded || 0) ? -1 : 1; + }), + ), + ), + ); + + const numberOfAdmins$ = users$.pipe(count(user => user.source.user.level.valueOf() === 3)); + const companyWithoutAdmin$ = users$.pipe( + // group by company + groupBy(user => user.source.company.id), + mergeMap(group => + group.pipe( + // get users as array + // TODO: we may be able to do this without doing a toArray but just by playing with the group + toArray(), + // filter groups where there is no user with level === 3 + filter(users => !users.some(user => user.source.user.level.valueOf() === 3)), + // take first element to get the company + map(users => users[0].source.company), + ), + ), + toArray(), + ); + + const companiesSubscription = companies$.subscribe({ + next(company) { + progress$.next({ + type: "company:created", + data: { + sourceId: company.source.id, + destinationCode: company.destination.code, + status: company.error ? "failure" : "success", + company, + error: company.error, + } as CompanyReport, + }); + }, + }); + + const usersSubscription = users$.subscribe({ + next(user) { + progress$.next({ + type: "user:created", + data: { + sourceId: user.source.user.id, + destinationId: user.destination.id, + destinationCompanyCode: user.destination.companyCode, + status: user.error ? "failure" : "success", + user, + error: user.error, + } as UserReport, + }); + }, + error(err: Error) { + console.error(err); + }, + }); + + const updateOwners$ = owners$.pipe( + mergeMap(owner => this.updateUserRole(owner, "owner"), concurrent), + tap(user => + progress$.next({ + type: "user:updated", + data: { + sourceId: user.source.source.user.id, + destinationId: user.source.destination.id, + destinationCompanyCode: user.source.destination.companyCode, + status: user.result.error ? "failure" : "success", + user: user.source, + error: user.result.error, + } as UserReport, + }), + ), + ); + + const process$ = forkJoin([users$, companies$, numberOfAdmins$, companyWithoutAdmin$]).pipe( + tap(result => { + progress$.next({ type: "log", message: `There are ${result[2]} admins` }); + progress$.next({ + type: "company:withoutadmin", + message: `Companies without admins ${result[3].length}`, + data: result[3], + }); + progress$.next({ type: "processing:owner" }); + }), + mergeMap(() => from(updateOwners$), concurrent), + ); + + const process = process$.subscribe({ + complete() { + usersSubscription.unsubscribe(); + companiesSubscription.unsubscribe(); + process.unsubscribe(); + progress$.complete(); + }, + }); + + return progress$; + } + + private getStreams( + concurrent: number = 1, + context?: ExecutionContext, + ): { + // hot companies observable + companies$: Observable; + // hot users observable + users$: Observable; + } { + const companies$ = this.getCompanies().pipe( + mergeMap(company => this.createCompany(company), concurrent), + // make it hot + share(), + ); + + const users$ = companies$.pipe( + filter(company => !company.error), + mergeMap(company => + this.getUserIds(company.source).pipe( + map(user => ({ + user, + company, + })), + ), + ), + mergeMap( + userInCompany => this.createUser(userInCompany.company.source, userInCompany.user, context), + concurrent, + ), + // make it hot + share(), + ); + + return { + companies$, + users$, + }; + } + + private getUserIds(company: Company, paginable?: Paginable): Observable { + const pagination = new Pagination( + paginable?.page_token, + paginable?.limitStr, + paginable?.reversed, + ); + + return from(gr.services.companies.getUsers({ group_id: company.id }, pagination)).pipe( + mergeMap(companyUsers => { + const items$ = from(companyUsers.getEntities()); + const next$ = companyUsers?.nextPage?.page_token + ? this.getUserIds(company, companyUsers.nextPage) + : EMPTY; + return concat(items$, next$); + }), + distinct(user => user.user_id), + ); + } + + private getCompanies(paginable?: Paginable): Observable { + return from(gr.services.companies.getCompanies(paginable)).pipe( + mergeMap(companiesResult => { + const items$ = from(companiesResult.getEntities()); + const next$ = companiesResult?.nextPage?.page_token + ? this.getCompanies(companiesResult.nextPage) + : EMPTY; + + return concat(items$, next$); + }), + distinct((company: Company) => company.id), + ); + } + + private async createCompany(company: Company): Promise { + logger.debug("Creating company in the Console %s", company.displayName); + let createdCompany: CreatedConsoleCompany; + let error; + + try { + createdCompany = await this.client.createCompany({ + code: company.id, + displayName: company.displayName, + avatar: { + type: "url", + value: company.logo, + }, + status: "active", + }); + + if (this.linkExternal) { + await this.createCompanyLink(company, createdCompany, this.consoleId); + } + } catch (err) { + logger.warn("Error while creating company %s", company.displayName); + error = err; + } + + return { + source: company, + destination: { + code: createdCompany?.code, + }, + error, + }; + } + + private async createUser( + company: Company, + companyUser: CompanyUser, + context: ExecutionContext, + ): Promise { + logger.debug("Creating user in console %o", companyUser.user_id); + let error: Error; + let result: CreatedConsoleUser; + + try { + const user = await gr.services.users.get({ id: companyUser.user_id }); + + if (!user) { + throw new Error(`User ${companyUser.user_id} not found`); + } + + const firstName = + user.first_name && user.first_name.trim().length ? user.first_name : user.email_canonical; + const lastName = + user.last_name && user.last_name.trim().length ? user.last_name : user.email_canonical; + const name = (firstName + " " + lastName).trim(); + + let role: "admin" | "guest" | "member" = + companyUser.level.valueOf() === 3 ? "admin" : "member"; + if (role != "admin") { + if (companyUser.isExterne) { + role = "guest"; + } + const workspacesUsers = await gr.services.workspaces.getAllForUser( + { userId: companyUser.user_id }, + { id: company.id }, + ); + workspacesUsers.forEach(e => { + if (e.isExternal) { + role = "guest"; + } + }); + } + + result = await this.client.addUserToCompany( + { code: company.id }, + { + email: user.email_canonical, + // console requires that firstname/lastname are defined and at least 1 chat long + firstName, + lastName, + name, + avatar: { + type: "url", + value: user.picture, + }, + password: passwordGenerator.generate({ + length: 10, + numbers: true, + }), + skipInvite: true, + role, + inviterEmail: "", + }, + ); + + const companyUserRepository = await this.database.getRepository( + "group_user", + CompanyUser, + ); + companyUser.role = role; + await companyUserRepository.save(companyUser, context); + + if (this.linkExternal) { + await this.createUserLink(user, result, this.consoleId); + } + } catch (err) { + logger.warn("Error while creating the user %o", companyUser.user_id); + error = err; + } + + return { + source: { user: companyUser, company }, + destination: { + id: result?._id, + companyCode: company.id, + }, + error, + }; + } + + private async createUserLink( + localUser: User, + remoteUser: CreatedConsoleUser, + serviceId: string, + ): Promise { + logger.debug("Creating user link for user %s", localUser.id); + if (this.dryRun) { + return; + } + + await gr.services.externalUser.createExternalUser( + getExternalUserInstance({ + service_id: serviceId, + external_id: remoteUser._id, + user_id: localUser.id, + }), + ); + } + + private async createCompanyLink( + localCompany: Company, + remoteCompany: CreatedConsoleCompany, + serviceId: string, + ): Promise { + if (this.dryRun) { + return; + } + + await gr.services.externalUser.createExternalGroup( + getExternalGroupInstance({ + service_id: serviceId, + company_id: localCompany.id, + external_id: remoteCompany.code, + }), + ); + } + + private updateUserRole( + user: UserCreatedStreamObject, + role: CompanyUserRole, + ): Promise<{ + source: UserCreatedStreamObject; + result: UpdateConsoleUserRole & { error?: Error }; + }> { + logger.debug( + `Updating user role for user ${user.source.user.id} in company ${user.source.company.id}`, + ); + return this.client + .updateUserRole({ code: user.destination.companyCode }, { id: user.destination.id, role }) + .then(result => ({ source: user, result })) + .catch((err: Error) => { + return { + source: user, + result: { + id: user.destination.id, + role, + error: err, + }, + }; + }); + } +} diff --git a/twake/backend/node/src/services/console/service.ts b/twake/backend/node/src/services/console/service.ts new file mode 100644 index 00000000..34e27fb1 --- /dev/null +++ b/twake/backend/node/src/services/console/service.ts @@ -0,0 +1,78 @@ +import { DatabaseServiceAPI } from "../../core/platform/services/database/api"; +import { MergeProcess } from "./processing/merge"; +import { ConsoleOptions, ConsoleType, MergeProgress } from "./types"; +import { ConsoleServiceClient } from "./client-interface"; +import { ConsoleClientFactory } from "./client-factory"; +import User from "../user/entities/user"; +import gr from "../global-resolver"; +import { Configuration, TwakeServiceProvider } from "../../core/platform/framework"; +import assert from "assert"; +import { ExecutionContext } from "../../core/platform/framework/api/crud-service"; + +export class ConsoleServiceImpl implements TwakeServiceProvider { + version: "1"; + + consoleType: ConsoleType; + consoleOptions: ConsoleOptions; + services: { + database: DatabaseServiceAPI; + }; + private configuration: Configuration; + + constructor(options?: ConsoleOptions) { + this.consoleOptions = options; + } + + async init(): Promise { + this.configuration = new Configuration("console"); + assert(this.configuration, "console configuration is missing"); + const type = this.configuration.get("type") as ConsoleType; + assert(type, "console configuration type is not defined"); + + const s = this.configuration.get(type) as ConsoleOptions; + + this.consoleOptions = { + type: type, + new_console: s.new_console, + username: s.username, + password: s.password, + url: s.url, + hook: { + token: s.hook?.token, + public_key: s.hook?.public_key, + }, + disable_account_creation: s.disable_account_creation, + }; + + this.consoleOptions.type = type; + this.consoleType = type; + + return this; + } + + merge( + baseUrl: string, + concurrent: number = 1, + dryRun: boolean = false, + console: string = "console", + link: boolean = true, + client: string, + secret: string, + _context?: ExecutionContext, + ): MergeProgress { + return new MergeProcess(this.services.database, dryRun, console, link, { + type: "remote", + username: client, + password: secret, + url: baseUrl, + } as ConsoleOptions).merge(concurrent); + } + + getClient(): ConsoleServiceClient { + return ConsoleClientFactory.create(this); + } + + async processPendingUser(user: User, context?: ExecutionContext): Promise { + await gr.services.workspaces.processPendingUser(user, null, context); + } +} diff --git a/twake/backend/node/src/services/console/types.ts b/twake/backend/node/src/services/console/types.ts new file mode 100644 index 00000000..547f9e67 --- /dev/null +++ b/twake/backend/node/src/services/console/types.ts @@ -0,0 +1,240 @@ +import { Observable } from "rxjs"; +import Company from "../user/entities/company"; +import CompanyUser from "../user/entities/company_user"; +import { CompanyUserRole } from "../user/web/types"; +import { ExecutionContext } from "../../core/platform/framework/api/crud-service"; +import { AccessToken } from "../../utils/types"; + +export interface CreateConsoleCompany { + code: string; + displayName: string; + avatar: { + type: "url"; + value: string; + }; + country?: string; + address?: string; + logo?: string; + status: string; + domain?: string[]; + applications?: string[]; + planId?: string; + limits?: { + members?: number; //Old console version + guests?: number; //Old console version + twake: { + members: number; + guests: number; + storage: number; + }; + }; +} + +export type CreatedConsoleCompany = Partial; + +export interface CreateConsoleUser { + id?: string; + email: string; + firstName: string; + lastName: string; + name: string; + avatar: { + type: "url"; + value: string; + }; + password: string; + role: CompanyUserRole; + skipInvite: boolean; + inviterEmail: string; +} + +export interface CreateInternalUser { + email: string; + password: string; +} + +export type CreatedConsoleUser = Partial & { _id: string }; + +export type UpdateConsoleUserRole = Pick & { id: string }; + +export type UpdatedConsoleUserRole = UpdateConsoleUserRole; + +export type ConsoleUser = { + id: string; + companyCode: string; +}; + +export type ConsoleCompany = { + id?: string; + code: string; +}; + +export type CompanyCreatedStreamObject = { + source: Company; + destination: ConsoleCompany; + // Creation error + error?: Error; +}; + +export type UserCreatedStreamObject = { + source: { + user: CompanyUser; + company: Company; + }; + destination: ConsoleUser; + // Creation error + error?: Error; +}; + +type ReportStatus = "success" | "failure"; + +export type CompanyReport = { + sourceId: string; + destinationCode: string; + status: ReportStatus; + company: CompanyCreatedStreamObject; + error?: Error; +}; + +export type UserReport = { + sourceId: string; + destinationId: string; + destinationCompanyCode: string; + status: ReportStatus; + user: UserCreatedStreamObject; + error?: Error; +}; + +export type MergeProgress = Observable; + +export type ProcessReport = { + type: + | "user:updated" + | "user:updating" + | "user:created" + | "user:error" + | "company:created" + | "processing:owner" + | "log" + | "company:withoutadmin"; + //error?: Error; + message?: string; + data?: UserReport | CompanyReport | Error | Company[]; +}; + +export type ConsoleType = "remote" | "internal"; + +export type ConsoleOptions = { + type: ConsoleType; + new_console: boolean; + username: string; + password: string; + url: string; + hook: { + token: string; + public_key?: string; + }; + disable_account_creation: boolean; +}; + +export type ConsoleHookCompany = { + stats: string; + limits: { + members?: number; //Old console version + guests?: number; //Old console version + twake: { + members: number; + guests: number; + storage: number; + }; + }; + value: string; + details: { + code: string; + logo: string; + avatar: { + value: string; + type: string; + }; + name: string; + country: string; + address: string; + }; +}; + +export type ConsoleHookUser = { + _id: string; + roles: [ + { + targetCode: string; + roleCode: CompanyUserRole; + status: "active" | "deactivated"; + applications: { + code: "twake"; + }[]; + }, + ]; + email: string; + name: string; + surname: string; + isVerified: boolean; + preference: { + locale: string; + timeZone: number; + allowTrackingPersonalInfo: boolean; + }; + avatar: { + type: string; + value: string; + }; +}; + +export type ConsoleHookBodyContent = { + company: ConsoleHookCompany; + user: ConsoleHookUser; +}; + +export type ConsoleHookCompanyDeletedContent = { + companyCode: string; +}; + +export type ConsoleHookPreferenceContent = { + preference: { + targetCode: string; + }; +}; + +export type ConsoleHookBody = { + type: string; + content: + | ConsoleHookBodyContent + | ConsoleHookUser + | ConsoleHookCompany + | ConsoleHookCompanyDeletedContent; + signature: string; + secret_key?: string; +}; + +export class ConsoleHookQueryString { + secret_key: string; +} + +export class ConsoleHookResponse { + success?: boolean; + error?: string; +} + +export interface ConsoleExecutionContext extends ExecutionContext { + options: ConsoleOptions; +} + +export interface AuthRequest { + email?: string; + password?: string; + remote_access_token?: string; +} + +export interface AuthResponse { + access_token?: AccessToken; + error?: string; +} diff --git a/twake/backend/node/src/services/console/web/controller.ts b/twake/backend/node/src/services/console/web/controller.ts new file mode 100644 index 00000000..d794dc34 --- /dev/null +++ b/twake/backend/node/src/services/console/web/controller.ts @@ -0,0 +1,298 @@ +import { FastifyReply, FastifyRequest } from "fastify"; +import { + AuthRequest, + AuthResponse, + ConsoleHookBody, + ConsoleHookBodyContent, + ConsoleHookCompany, + ConsoleHookCompanyDeletedContent, + ConsoleHookPreferenceContent, + ConsoleHookResponse, + ConsoleHookUser, + ConsoleType, +} from "../types"; +import Company from "../../user/entities/company"; +import { CrudException } from "../../../core/platform/framework/api/crud-service"; +import PasswordEncoder from "../../../utils/password-encoder"; +import { AccessToken } from "../../../utils/types"; +import assert from "assert"; +import { logger } from "../../../core/platform/framework"; +import { getInstance } from "../../user/entities/user"; +import { getInstance as getCompanyInstance } from "../../../services/user/entities/company"; +import Workspace from "../../../services/workspaces/entities/workspace"; +import gr from "../../global-resolver"; +import { Configuration } from "../../../core/platform/framework"; + +export class ConsoleController { + private passwordEncoder: PasswordEncoder; + + constructor() { + this.passwordEncoder = new PasswordEncoder(); + } + + async auth(request: FastifyRequest<{ Body: AuthRequest }>): Promise { + if (request.body.remote_access_token) { + return { access_token: await this.authByToken(request.body.remote_access_token) }; + } else if (request.body.email && request.body.password) { + return { access_token: await this.authByPassword(request.body.email, request.body.password) }; + } else { + throw CrudException.badRequest("remote_access_token or email+password are required"); + } + } + + async signup( + request: FastifyRequest<{ + Body: { email: string; password: string; first_name: string; last_name: string }; + }>, + ): Promise { + const configuration = new Configuration("console"); + const type = configuration.get("type") as ConsoleType; + + try { + //Allow only if no console is set up in this case everyone will be in the same company + //Console is set up + if (type !== "internal") { + throw new Error("Unable to signup in console mode"); + } + + //Allow only if signup isn't disabled + if (configuration.get("disable_account_creation")) { + throw new Error("Account creation is disabled"); + } + + const email = request.body.email.trim().toLocaleLowerCase(); + if (await gr.services.users.getByEmail(email)) { + throw new Error("This email is already used"); + } + + try { + const newUser = getInstance({ + first_name: request.body.first_name, + last_name: request.body.last_name, + email_canonical: email, + username_canonical: (email.replace("@", ".") || "").toLocaleLowerCase(), + }); + const user = await gr.services.users.create(newUser); + await gr.services.users.setPassword({ id: user.entity.id }, request.body.password); + + //Create a global company for all users in local mode + const companies = await gr.services.companies.getCompanies(); + let company = companies.getEntities()?.[0]; + if (!company) { + const newCompany = getCompanyInstance({ + name: "Twake", + plan: { name: "Local", limits: undefined, features: undefined }, + }); + company = await gr.services.companies.createCompany(newCompany); + } + await gr.services.companies.setUserRole(company.id, user.entity.id, "admin"); + + //In case someone invited us to a workspace + await gr.services.workspaces.processPendingUser(user.entity); + + //If user is in no workspace, then we create one for they + const workspaces = await gr.services.workspaces.getAllForUser( + { userId: user.entity.id }, + { id: company.id }, + ); + if (workspaces.length === 0) { + gr.services.workspaces.create( + { + company_id: company.id, + name: `${ + newUser.first_name || newUser.last_name || newUser.username_canonical + }'s space`, + } as Workspace, + { user: { id: user.entity.id } }, + ); + } + + return { + access_token: await this.authByPassword(request.body.email, request.body.password), + }; + } catch (err) { + throw new Error("An unknown error occured"); + } + } catch (err) { + return { error: err.toString() }; + } + } + + async tokenRenewal(request: FastifyRequest): Promise { + return { + access_token: gr.platformServices.auth.generateJWT( + request.currentUser.id, + request.currentUser.email, + { + track: request.currentUser?.allow_tracking || false, + provider_id: request.currentUser.identity_provider_id, + }, + ), + }; + } + + async resendVerificationEmail( + request: FastifyRequest, + ): Promise<{ success: boolean; email: string }> { + const user = await gr.services.users.get({ id: request.currentUser.id }); + + await gr.services.console.getClient().resendVerificationEmail(user.email_canonical); + + return { + success: true, + email: user.email_canonical, + }; + } + + private async getCompanyDataFromConsole( + company: ConsoleHookCompany | ConsoleHookCompany["details"] | { code: string }, + ): Promise { + return gr.services.console + .getClient() + .fetchCompanyInfo( + (company as ConsoleHookCompany["details"])?.code || + (company as ConsoleHookCompany)?.details?.code, + ); + } + + private async updateCompany(company: ConsoleHookCompany): Promise { + const companyDTO = await this.getCompanyDataFromConsole(company); + return gr.services.console.getClient().updateLocalCompanyFromConsole(companyDTO); + } + + async hook( + request: FastifyRequest<{ Body: ConsoleHookBody }>, + reply: FastifyReply, + ): Promise { + try { + logger.info(`Received event ${request.body.type}`); + + switch (request.body.type) { + case "user_created": + case "company_user_added": + case "company_user_activated": + case "company_user_updated": + await this.userAdded(request.body.content as ConsoleHookBodyContent); + break; + case "company_user_deactivated": + case "company_user_deleted": + await this.userDisabled(request.body.content as ConsoleHookBodyContent); + break; + case "user_updated": + await this.userUpdated((request.body.content as ConsoleHookBodyContent).user._id); + break; + case "user_preference_updated": + await this.userUpdated( + (request.body.content as unknown as ConsoleHookPreferenceContent).preference.targetCode, + ); + break; + case "user_deleted": + await this.userRemoved(request.body.content as ConsoleHookUser); + break; + case "plan_updated": + await this.planUpdated(request.body.content as ConsoleHookBodyContent); + break; + case "company_deleted": + await this.companyRemoved(request.body.content as ConsoleHookCompanyDeletedContent); + break; + case "company_created": + await this.companyUpdated(request.body.content as ConsoleHookBodyContent); + if ((request.body.content as ConsoleHookBodyContent)?.user?._id) { + await this.userUpdated((request.body.content as ConsoleHookBodyContent).user._id); + } + break; + case "company_updated": + await this.companyUpdated(request.body.content as ConsoleHookBodyContent); + break; + default: + logger.info("Event not recognized"); + throw CrudException.notImplemented("Unimplemented"); + } + } catch (e) { + reply.status(400); + return { + error: e.message, + }; + } + + return { + success: true, + }; + } + + private async userAdded(content: ConsoleHookBodyContent): Promise { + const userDTO = content.user; + const user = await gr.services.console.getClient().updateLocalUserFromConsole(userDTO._id); + await this.updateCompany(content.company); + await gr.services.console.processPendingUser(user); + } + + private async userDisabled(content: ConsoleHookBodyContent): Promise { + const company = await this.updateCompany(content.company); + await gr.services.console.getClient().removeCompanyUser(content.user._id, company); + } + + private async userRemoved(content: ConsoleHookUser): Promise { + await gr.services.console.getClient().removeUser(content._id); + } + + private async userUpdated(code: string) { + const user = await gr.services.console.getClient().updateLocalUserFromConsole(code); + await gr.services.console.processPendingUser(user); + } + + private async companyRemoved(content: ConsoleHookCompanyDeletedContent) { + assert(content.companyCode, "content.companyCode is missing"); + + await gr.services.console.getClient().removeCompany({ + identity_provider: "console", + identity_provider_id: content.companyCode, + }); + } + + private async companyUpdated(content: ConsoleHookBodyContent) { + await this.updateCompany(content.company); + } + + private async planUpdated(content: ConsoleHookBodyContent) { + await this.updateCompany(content.company); + } + + private async authByPassword(email: string, password: string): Promise { + const user = await gr.services.users.getByEmail(email); + if (!user) { + throw CrudException.forbidden("User doesn't exists"); + } + + // allow to login in development mode with any password. This can be used to test without the console provider because the password is not stored locally... + if (process.env.NODE_ENV !== "development") { + const [storedPassword, salt] = await gr.services.users.getHashedPassword({ + id: user.id, + }); + + if (!(await this.passwordEncoder.isPasswordValid(storedPassword, password, salt))) { + throw CrudException.forbidden("Password doesn't match"); + } + } else if (process.env.NODE_ENV === "development") { + logger.warn("ERROR_NOTONPROD: YOU ARE RUNNING IN DEVELOPMENT MODE, AUTH IS DISABLED!!!"); + } + + return gr.platformServices.auth.generateJWT(user.id, user.email_canonical, { + track: user?.preferences?.allow_tracking || false, + provider_id: user.identity_provider_id, + }); + } + + private async authByToken(accessToken: string): Promise { + const client = gr.services.console.getClient(); + const userDTO = await client.getUserByAccessToken(accessToken); + const user = await client.updateLocalUserFromConsole(userDTO._id); + if (!user) { + throw CrudException.notFound(`User details not found for access token ${accessToken}`); + } + return gr.platformServices.auth.generateJWT(user.id, user.email_canonical, { + track: user?.preferences?.allow_tracking || false, + provider_id: user.identity_provider_id, + }); + } +} diff --git a/twake/backend/node/src/services/console/web/index.ts b/twake/backend/node/src/services/console/web/index.ts new file mode 100644 index 00000000..1fe80a8f --- /dev/null +++ b/twake/backend/node/src/services/console/web/index.ts @@ -0,0 +1,12 @@ +import { FastifyInstance, FastifyRegisterOptions } from "fastify"; +import routes from "./routes"; + +export default ( + fastify: FastifyInstance, + options: FastifyRegisterOptions<{ + prefix: string; + }>, +): void => { + fastify.log.debug("Configuring /console routes"); + fastify.register(routes, options); +}; diff --git a/twake/backend/node/src/services/console/web/routes.ts b/twake/backend/node/src/services/console/web/routes.ts new file mode 100644 index 00000000..a14a19a7 --- /dev/null +++ b/twake/backend/node/src/services/console/web/routes.ts @@ -0,0 +1,79 @@ +import { FastifyInstance, FastifyPluginCallback, FastifyRequest } from "fastify"; +import { authenticationSchema, consoleHookSchema, tokenRenewalSchema } from "./schemas"; +import crypto from "crypto"; +// import { WorkspaceBaseRequest, WorkspaceUsersBaseRequest, WorkspaceUsersRequest } from "./types"; +import { ConsoleController } from "./controller"; +import { ConsoleHookBody, ConsoleHookQueryString } from "../types"; +import gr from "../../global-resolver"; + +const hookUrl = "/hook"; + +const routes: FastifyPluginCallback = (fastify: FastifyInstance, options, next) => { + const controller = new ConsoleController(); + + const accessControl = async ( + request: FastifyRequest<{ Body: ConsoleHookBody; Querystring: ConsoleHookQueryString }>, + ) => { + if (gr.services.console.consoleType != "remote") { + throw fastify.httpErrors.notImplemented("Hook service is only for the remote console"); + } + + if ( + (request.body.secret_key || request.query.secret_key) !== + gr.services.console.consoleOptions.hook.token + ) { + throw fastify.httpErrors.forbidden("Wrong secret"); + } + + const publicKey = gr.services.console.consoleOptions.hook.public_key; + + if (publicKey) { + const input = JSON.stringify({ content: request.body.content, type: request.body.type }); + const signatureBase64 = request.body.signature; + const verifier = crypto.createVerify("RSA-SHA512").update(input); + if (!verifier.verify(publicKey, signatureBase64, "base64")) { + throw fastify.httpErrors.forbidden("Signature verification failed"); + } + } + }; + + fastify.route({ + method: "POST", + url: `${hookUrl}`, + preHandler: [accessControl], + schema: consoleHookSchema, + handler: controller.hook.bind(controller), + }); + + fastify.route({ + method: "POST", + url: "/login", + schema: authenticationSchema, + handler: controller.auth.bind(controller), + }); + + fastify.route({ + method: "POST", + url: "/signup", + handler: controller.signup.bind(controller), + }); + + fastify.route({ + method: "POST", + url: "/token", + preValidation: [fastify.authenticate], + schema: tokenRenewalSchema, + handler: controller.tokenRenewal.bind(controller), + }); + + fastify.route({ + method: "POST", + url: "/resend-verification-email", + preValidation: [fastify.authenticate], + handler: controller.resendVerificationEmail.bind(controller), + }); + + next(); +}; + +export default routes; diff --git a/twake/backend/node/src/services/console/web/schemas.ts b/twake/backend/node/src/services/console/web/schemas.ts new file mode 100644 index 00000000..34db9196 --- /dev/null +++ b/twake/backend/node/src/services/console/web/schemas.ts @@ -0,0 +1,77 @@ +export const consoleHookSchema = { + querystring: { + type: "object", + properties: { + secret_key: { type: "string" }, + }, + }, + body: { + type: "object", + properties: { + type: { type: "string" }, + content: { type: "object" }, + signature: { type: "string" }, + secret_key: { type: "string" }, + }, + required: ["type", "content"], + }, + response: { + "2xx": { + type: "object", + properties: { + success: { type: "boolean" }, + error: { type: "string" }, + }, + }, + }, +}; + +export const authenticationSchema = { + body: { + type: "object", + properties: { + email: { type: "string" }, + password: { type: "string" }, + remote_access_token: { type: "string" }, + }, + }, + response: { + "2xx": { + type: "object", + properties: { + access_token: { + type: "object", + properties: { + time: { type: "number" }, + expiration: { type: "number" }, + refresh_expiration: { type: "number" }, + value: { type: "string" }, + refresh: { type: "string" }, + type: { type: "string" }, + }, + }, + }, + }, + }, +}; + +export const tokenRenewalSchema = { + response: { + "2xx": { + type: "object", + properties: { + access_token: { + type: "object", + properties: { + time: { type: "number" }, + expiration: { type: "number" }, + refresh_expiration: { type: "number" }, + value: { type: "string" }, + refresh: { type: "string" }, + type: { type: "string" }, + }, + }, + }, + }, + }, +}; diff --git a/twake/backend/node/src/services/documents/const.ts b/twake/backend/node/src/services/documents/const.ts new file mode 100644 index 00000000..16abf384 --- /dev/null +++ b/twake/backend/node/src/services/documents/const.ts @@ -0,0 +1,171 @@ +export const stopWords = [ + "about", + "above", + "after", + "again", + "all", + "also", + "am", + "an", + "and", + "another", + "any", + "are", + "as", + "at", + "be", + "because", + "been", + "before", + "being", + "below", + "between", + "both", + "but", + "by", + "came", + "can", + "cannot", + "come", + "could", + "did", + "do", + "does", + "doing", + "during", + "each", + "few", + "for", + "from", + "further", + "get", + "got", + "has", + "had", + "he", + "have", + "her", + "here", + "him", + "himself", + "his", + "how", + "if", + "in", + "into", + "is", + "it", + "its", + "itself", + "like", + "make", + "many", + "me", + "might", + "more", + "most", + "much", + "must", + "my", + "myself", + "never", + "now", + "of", + "on", + "only", + "or", + "other", + "our", + "ours", + "ourselves", + "out", + "over", + "own", + "said", + "same", + "see", + "should", + "since", + "so", + "some", + "still", + "such", + "take", + "than", + "that", + "the", + "their", + "theirs", + "them", + "themselves", + "then", + "there", + "these", + "they", + "this", + "those", + "through", + "to", + "too", + "under", + "until", + "up", + "very", + "was", + "way", + "we", + "well", + "were", + "what", + "where", + "when", + "which", + "while", + "who", + "whom", + "with", + "would", + "why", + "you", + "your", + "yours", + "yourself", + "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", + "$", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "0", + "_", +]; diff --git a/twake/backend/node/src/services/documents/entities/drive-file.search.ts b/twake/backend/node/src/services/documents/entities/drive-file.search.ts new file mode 100644 index 00000000..d9db47b1 --- /dev/null +++ b/twake/backend/node/src/services/documents/entities/drive-file.search.ts @@ -0,0 +1,33 @@ +import { DriveFile, TYPE } from "./drive-file"; + +export default { + index: TYPE, + source: (entity: DriveFile) => ({ + content_keywords: entity.content_keywords, + tags: (entity.tags || []).join(" "), + creator: entity.creator, + added: entity.added, + name: entity.name, + company_id: entity.company_id, + }), + mongoMapping: { + text: { + content_keywords: "text", + tags: "text", + creator: "text", + added: "text", + name: "text", + company_id: "text", + }, + }, + esMapping: { + properties: { + name: { type: "text", index_prefixes: { min_chars: 1 } }, + content_keywords: { type: "text", index_prefixes: { min_chars: 1 } }, + tags: { type: "keyword" }, + creator: { type: "keyword" }, + added: { type: "keyword" }, + company_id: { type: "keyword" }, + }, + }, +}; diff --git a/twake/backend/node/src/services/documents/entities/drive-file.ts b/twake/backend/node/src/services/documents/entities/drive-file.ts new file mode 100644 index 00000000..10d50c4f --- /dev/null +++ b/twake/backend/node/src/services/documents/entities/drive-file.ts @@ -0,0 +1,90 @@ +import { Type } from "class-transformer"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import { DriveFileAccessLevel, publicAccessLevel } from "../types"; +import { FileVersion } from "./file-version"; +import search from "./drive-file.search"; + +export const TYPE = "drive_files"; + +@Entity(TYPE, { + globalIndexes: [["company_id", "parent_id"]], + primaryKey: [["company_id"], "id"], + type: TYPE, + search, +}) +export class DriveFile { + @Type(() => String) + @Column("company_id", "uuid") + company_id: string; + + @Type(() => String) + @Column("id", "uuid", { generator: "uuid" }) + id: string; + + @Type(() => String) + @Column("parent_id", "string") + parent_id: string; + + @Type(() => Boolean) + @Column("is_in_trash", "boolean") + is_in_trash: boolean; + + @Type(() => Boolean) + @Column("is_directory", "boolean") + is_directory: boolean; + + @Type(() => String) + @Column("name", "string") + name: string; + + @Type(() => String) + @Column("extension", "string") + extension: string; + + @Type(() => String) + @Column("description", "string") + description: string; + + @Column("tags", "encoded_json") + tags: string[]; + + @Type(() => String) + @Column("added", "string") + added: string; + + @Type(() => String) + @Column("last_modified", "string") + last_modified: string; + + @Column("access_info", "encoded_json") + access_info: AccessInformation; + + @Type(() => String) + @Column("content_keywords", "string") + content_keywords: string; + + @Type(() => String) + @Column("creator", "uuid") + creator: string; + + @Type(() => Number) + @Column("size", "number") + size: number; + + @Column("last_version_cache", "encoded_json") + last_version_cache: Partial; +} + +export type AccessInformation = { + public?: { + token: string; + level: publicAccessLevel; + }; + entities: AuthEntity[]; +}; + +type AuthEntity = { + type: "user" | "channel" | "company" | "folder"; + id: string | "parent"; + level: publicAccessLevel | DriveFileAccessLevel; +}; diff --git a/twake/backend/node/src/services/documents/entities/drive-twake-tab.ts b/twake/backend/node/src/services/documents/entities/drive-twake-tab.ts new file mode 100644 index 00000000..ca8fb6cb --- /dev/null +++ b/twake/backend/node/src/services/documents/entities/drive-twake-tab.ts @@ -0,0 +1,30 @@ +import { Type } from "class-transformer"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "drive_twake_tab"; + +@Entity(TYPE, { + primaryKey: [["company_id"], "tab_id"], + type: TYPE, +}) +export class DriveTwakeTab { + @Type(() => String) + @Column("company_id", "string") + company_id: string; + + @Type(() => String) + @Column("tab_id", "string") + tab_id: string; + + @Type(() => String) + @Column("channel__id", "string") + channel_id: string; + + @Type(() => String) + @Column("item_id", "string") + item_id: string; + + @Type(() => String) + @Column("level", "string") + level: "read" | "write"; +} diff --git a/twake/backend/node/src/services/documents/entities/file-version.ts b/twake/backend/node/src/services/documents/entities/file-version.ts new file mode 100644 index 00000000..d4b00947 --- /dev/null +++ b/twake/backend/node/src/services/documents/entities/file-version.ts @@ -0,0 +1,83 @@ +import { Type } from "class-transformer"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "drive_file_versions"; + +@Entity(TYPE, { + primaryKey: [["drive_item_id"], "id"], + type: TYPE, +}) +export class FileVersion { + @Type(() => String) + @Column("drive_item_id", "uuid") + drive_item_id: string; + + @Type(() => String) + @Column("id", "uuid", { generator: "uuid" }) + id: string; + + @Type(() => String) + @Column("provider", "string") + provider: "internal" | "drive" | string; + + @Column("file_metadata", "encoded_json") + file_metadata: DriveFileMetadata; + + @Type(() => Number) + @Column("date_added", "number") + date_added: number; + + @Type(() => String) + @Column("creator_id", "uuid") + creator_id: string; + + @Type(() => String) + @Column("application_id", "string") + application_id: string; + + @Type(() => String) + @Column("realname", "string") + realname: string; + + @Type(() => String) + @Column("key", "string") + key: string; + + @Type(() => String) + @Column("mode", "string") + mode: string | "OpenSSL-2"; + + @Type(() => Number) + @Column("file_size", "number") + file_size: number; + + @Type(() => String) + @Column("filename", "string") + filename: string; + + @Column("data", "encoded_json") + data: unknown; +} + +export type DriveFileMetadata = { + source?: "internal" | "drive" | string; + external_id: string; + + name?: string; + mime?: string; + size?: number; + thumbnails?: DriveFileThumbnail[]; +}; + +type DriveFileThumbnail = { + index: number; + id: string; + + type: string; + size: number; + width: number; + height: number; + + url: string; + full_url?: string; +}; diff --git a/twake/backend/node/src/services/documents/index.ts b/twake/backend/node/src/services/documents/index.ts new file mode 100644 index 00000000..0b93f379 --- /dev/null +++ b/twake/backend/node/src/services/documents/index.ts @@ -0,0 +1,23 @@ +import { Prefix, TwakeService } from "../../core/platform/framework"; +import WebServerAPI from "../../core/platform/services/webserver/provider"; +import web from "./web"; + +@Prefix("/internal/services/documents/v1") +export default class DocumentsService extends TwakeService { + version = "1"; + name = "documents"; + + public doInit: () => Promise = async () => { + const fastify = this.context.getProvider("webserver").getServer(); + fastify.register((instance, _options, next) => { + web(instance, { prefix: this.prefix }); + next(); + }); + + return this; + }; + + api = (): undefined => { + return undefined; + }; +} diff --git a/twake/backend/node/src/services/documents/services/engine/extract-keywords.ts b/twake/backend/node/src/services/documents/services/engine/extract-keywords.ts new file mode 100644 index 00000000..7a9fa87c --- /dev/null +++ b/twake/backend/node/src/services/documents/services/engine/extract-keywords.ts @@ -0,0 +1,79 @@ +import globalResolver from "../../../../services/global-resolver"; +import { logger } from "../../../../core/platform/framework"; +import { MessageQueueHandler } from "../../../../core/platform/services/message-queue/api"; +import { DocumentsMessageQueueCallback, DocumentsMessageQueueRequest } from "../../types"; +import { extractKeywords, officeFileToString, pdfFileToString } from "../../utils"; +import { isFileType } from "../../../../services/previews/utils"; +import { officeExtensions, textExtensions, pdfExtensions } from "../../../../utils/mime"; +import { readableToString } from "../../../../utils/files"; + +export class DocumentsProcessor + implements MessageQueueHandler +{ + readonly name = "DocumentsProcessor"; + + readonly topics = { + in: "services:documents:process", + out: "services:documents:process:callback", + }; + + readonly options = { + unique: true, + ack: true, + }; + + validate(message: DocumentsMessageQueueRequest): boolean { + return !!( + message && + message.context && + message.item && + message.item.id && + message.version && + message.version.file_metadata && + message.version.file_metadata.external_id && + !message.item.is_directory + ); + } + + async process(message: DocumentsMessageQueueRequest): Promise { + logger.info(`${this.name} - process document content keywords for ${message.item.id}`); + + return await this.generate(message); + } + + async generate(message: DocumentsMessageQueueRequest): Promise { + let content_keywords = ""; + let content_strings = ""; + + try { + const storedFile = await globalResolver.services.files.download( + message.version.file_metadata.external_id, + message.context, + ); + + const extension = storedFile.name.split(".").pop(); + + if (isFileType(storedFile.mime, storedFile.name, textExtensions)) { + logger.info("Processing text file"); + content_strings = await readableToString(storedFile.file); + } + + if (isFileType(storedFile.mime, storedFile.name, pdfExtensions)) { + logger.info("Processing PDF file"); + content_strings = await pdfFileToString(storedFile.file); + } + + if (isFileType(storedFile.mime, storedFile.name, officeExtensions)) { + logger.info("Processing office file"); + content_strings = await officeFileToString(storedFile.file, extension); + } + + content_keywords = extractKeywords(content_strings); + } catch (error) { + console.debug(error); + logger.error("Failed to generate content keywords", error); + } + + return { content_keywords, item: message.item }; + } +} diff --git a/twake/backend/node/src/services/documents/services/engine/index.ts b/twake/backend/node/src/services/documents/services/engine/index.ts new file mode 100644 index 00000000..ce31982d --- /dev/null +++ b/twake/backend/node/src/services/documents/services/engine/index.ts @@ -0,0 +1,18 @@ +import globalResolver from "../../../global-resolver"; +import { Initializable } from "../../../../core/platform/framework"; +import { DocumentsProcessor } from "./extract-keywords"; +import { DriveFile, TYPE } from "../../entities/drive-file"; +import { DocumentsFinishedProcess } from "./save-keywords"; + +export class DocumentsEngine implements Initializable { + async init(): Promise { + const repository = await globalResolver.database.getRepository(TYPE, DriveFile); + + globalResolver.platformServices.messageQueue.processor.addHandler(new DocumentsProcessor()); + globalResolver.platformServices.messageQueue.processor.addHandler( + new DocumentsFinishedProcess(repository), + ); + + return this; + } +} diff --git a/twake/backend/node/src/services/documents/services/engine/save-keywords.ts b/twake/backend/node/src/services/documents/services/engine/save-keywords.ts new file mode 100644 index 00000000..c9ed8a91 --- /dev/null +++ b/twake/backend/node/src/services/documents/services/engine/save-keywords.ts @@ -0,0 +1,65 @@ +import { logger } from "../../../../core/platform/framework"; +import { ExecutionContext } from "../../../../core/platform/framework/api/crud-service"; +import Repository from "../../../../core/platform/services/database/services/orm/repository/repository"; +import { MessageQueueHandler } from "../../../../core/platform/services/message-queue/api"; +import { DriveFile } from "../../entities/drive-file"; +import { DocumentsMessageQueueCallback } from "../../types"; + +export class DocumentsFinishedProcess + implements MessageQueueHandler +{ + constructor(private repository: Repository) {} + + readonly name = "DocumentsFinishedProcess"; + readonly topics = { + in: "services:documents:process:callback", + }; + + readonly options = { + unique: true, + ack: true, + }; + + init? = (): Promise => { + throw Error("Method not implemented."); + }; + + validate = (message: DocumentsMessageQueueCallback): boolean => { + return !!( + message && + message.content_keywords && + message.content_keywords.length && + message.item && + message.item.id + ); + }; + + process = async ( + message: DocumentsMessageQueueCallback, + context?: ExecutionContext, + ): Promise => { + logger.info(`${this.name} - updating drive item content keywords`); + + try { + const entity = await this.repository.findOne( + { + id: message.item.id, + company_id: message.item.company_id, + }, + {}, + context, + ); + + if (!entity) { + throw Error("Drive item not found"); + } + + entity.content_keywords = message.content_keywords; + + return await this.repository.save(entity, context); + } catch (error) { + logger.error(`${this.name} - Failed to set content keywords`, error); + return; + } + }; +} diff --git a/twake/backend/node/src/services/documents/services/index.ts b/twake/backend/node/src/services/documents/services/index.ts new file mode 100644 index 00000000..6dc760b8 --- /dev/null +++ b/twake/backend/node/src/services/documents/services/index.ts @@ -0,0 +1,840 @@ +import SearchRepository from "../../../core/platform/services/search/repository"; +import { getLogger, logger, TwakeLogger } from "../../../core/platform/framework"; +import { CrudException, ListResult } from "../../../core/platform/framework/api/crud-service"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import { PublicFile } from "../../../services/files/entities/file"; +import globalResolver from "../../../services/global-resolver"; +import { hasCompanyAdminLevel } from "../../../utils/company"; +import gr from "../../global-resolver"; +import { DriveFile, TYPE } from "../entities/drive-file"; +import { FileVersion, TYPE as FileVersionType } from "../entities/file-version"; +import { + DriveTwakeTab as DriveTwakeTabEntity, + TYPE as DriveTwakeTabRepoType, +} from "../entities/drive-twake-tab"; +import { + DriveExecutionContext, + DocumentsMessageQueueRequest, + DriveItemDetails, + RootType, + SearchDocumentsOptions, + TrashType, + CompanyExecutionContext, + DriveTwakeTab, +} from "../types"; +import { + addDriveItemToArchive, + calculateItemSize, + canMoveItem, + checkAccess, + getAccessLevel, + getDefaultDriveItem, + getDefaultDriveItemVersion, + getFileMetadata, + getItemName, + getPath, + hasAccessLevel, + makeStandaloneAccessLevel, + updateItemSize, +} from "../utils"; +import { websocketEventBus } from "../../../core/platform/services/realtime/bus"; + +import archiver from "archiver"; +import internal from "stream"; +import { + RealtimeEntityActionType, + ResourcePath, +} from "../../../core/platform/services/realtime/types"; + +export class DocumentsService { + version: "1"; + repository: Repository; + searchRepository: SearchRepository; + fileVersionRepository: Repository; + driveTwakeTabRepository: Repository; + ROOT: RootType = "root"; + TRASH: TrashType = "trash"; + logger: TwakeLogger = getLogger("Documents Service"); + + async init(): Promise { + try { + this.repository = await globalResolver.database.getRepository(TYPE, DriveFile); + this.searchRepository = globalResolver.platformServices.search.getRepository( + TYPE, + DriveFile, + ); + this.fileVersionRepository = await globalResolver.database.getRepository( + FileVersionType, + FileVersion, + ); + this.driveTwakeTabRepository = + await globalResolver.database.getRepository( + DriveTwakeTabRepoType, + DriveTwakeTabEntity, + ); + } catch (error) { + logger.error("Error while initializing Documents Service", error); + } + + return this; + } + + /** + * Fetches a drive element + * + * @param {string} id - the id of the DriveFile to fetch or "trash" or an empty string for root folder. + * @param {DriveExecutionContext} context + * @returns {Promise} + */ + get = async (id: string, context: DriveExecutionContext): Promise => { + if (!context) { + this.logger.error("invalid context"); + return null; + } + + id = id || this.ROOT; + + //Get requested entity + const entity = + id === this.ROOT || id === this.TRASH + ? null + : await this.repository.findOne( + { + company_id: context.company.id, + id, + }, + {}, + context, + ); + + if (!entity && !(id === this.ROOT || id === this.TRASH)) { + this.logger.error("Drive item not found"); + throw new CrudException("Item not found", 404); + } + + //Check access to entity + try { + const hasAccess = await checkAccess(id, entity, "read", this.repository, context); + if (!hasAccess) { + this.logger.error("user does not have access drive item ", id); + throw Error("user does not have access to this item"); + } + } catch (error) { + this.logger.error("Failed to grant access to the drive item", error); + throw new CrudException("User does not have access to this item or its children", 401); + } + + const isDirectory = entity ? entity.is_directory : true; + + //Get entity version in case of a file + const versions = isDirectory + ? [] + : ( + await this.fileVersionRepository.find( + { + drive_item_id: entity.id, + }, + {}, + context, + ) + ).getEntities(); + + //Get children if it is a directory + let children = isDirectory + ? ( + await this.repository.find( + { + company_id: context.company.id, + parent_id: id, + }, + {}, + context, + ) + ).getEntities() + : []; + + //Check each children for access + const accessMap: { [key: string]: boolean } = {}; + await Promise.all( + children.map(async child => { + accessMap[child.id] = await checkAccess(child.id, child, "read", this.repository, context); + }), + ); + children = children.filter(child => accessMap[child.id]); + + //Return complete object + return { + path: await getPath(id, this.repository, false, context), + item: + entity || + ({ + id, + parent_id: null, + name: id === this.ROOT ? "root" : id === this.TRASH ? "trash" : "unknown", + size: await calculateItemSize( + id === this.ROOT ? this.ROOT : "trash", + this.repository, + context, + ), + } as DriveFile), + versions: versions, + children: children, + access: await getAccessLevel(id, entity, this.repository, context), + }; + }; + + /** + * Creates a DriveFile item. + * + * @param {PublicFile} file - the multipart file + * @param {Partial} content - the DriveFile item to create + * @param {Partial} version - the DriveFile version. + * @param {DriveExecutionContext} context - the company execution context. + * @returns {Promise} - the created DriveFile + */ + create = async ( + file: PublicFile | null, + content: Partial, + version: Partial, + context: DriveExecutionContext, + ): Promise => { + try { + const driveItem = getDefaultDriveItem(content, context); + const driveItemVersion = getDefaultDriveItemVersion(version, context); + + const hasAccess = await checkAccess( + driveItem.parent_id, + null, + "write", + this.repository, + context, + ); + if (!hasAccess) { + this.logger.error("User does not have access to parent drive item", driveItem.parent_id); + throw Error("User does not have access to this item parent"); + } + + if (file || driveItem.is_directory === false) { + let fileToProcess; + + if (file) { + fileToProcess = file; + } else if (driveItemVersion.file_metadata.external_id) { + fileToProcess = await globalResolver.services.files.getFile( + { + id: driveItemVersion.file_metadata.external_id, + company_id: driveItem.company_id, + }, + context, + { waitForThumbnail: true }, + ); + } + + if (fileToProcess) { + driveItem.size = fileToProcess.upload_data.size; + driveItem.is_directory = false; + driveItem.extension = fileToProcess.metadata.name.split(".").pop(); + driveItemVersion.filename = driveItemVersion.filename || fileToProcess.metadata.name; + driveItemVersion.file_size = fileToProcess.upload_data.size; + driveItemVersion.file_metadata.external_id = fileToProcess.id; + driveItemVersion.file_metadata.mime = fileToProcess.metadata.mime; + driveItemVersion.file_metadata.size = fileToProcess.upload_data.size; + driveItemVersion.file_metadata.name = fileToProcess.metadata.name; + driveItemVersion.file_metadata.thumbnails = fileToProcess.thumbnails; + if (context.user.application_id) { + driveItemVersion.application_id = context.user.application_id; + } + } + } + + driveItem.name = await getItemName( + driveItem.parent_id, + driveItem.id, + driveItem.name, + driveItem.is_directory, + this.repository, + context, + ); + + await this.repository.save(driveItem); + driveItemVersion.drive_item_id = driveItem.id; + + await this.fileVersionRepository.save(driveItemVersion); + driveItem.last_version_cache = driveItemVersion; + + await this.repository.save(driveItem); + await updateItemSize(driveItem.parent_id, this.repository, context); + + this.notifyWebsocket(driveItem.parent_id, context); + + globalResolver.platformServices.messageQueue.publish( + "services:documents:process", + { + data: { + item: driveItem, + version: driveItemVersion, + context, + }, + }, + ); + + return driveItem; + } catch (error) { + this.logger.error("Failed to create drive item", error); + throw new CrudException("Failed to create item", 500); + } + }; + + /** + * Updates a DriveFile item + * + * @param {string} id - the id of the DriveFile to update. + * @param {Partial} content - the updated content + * @param {DriveExecutionContext} context - the company execution context + * @returns {Promise} - the updated DriveFile + */ + update = async ( + id: string, + content: Partial, + context: CompanyExecutionContext, + ): Promise => { + if (!context) { + this.logger.error("invalid execution context"); + return null; + } + + try { + let oldParent = null; + const level = await getAccessLevel(id, null, this.repository, context); + const hasAccess = hasAccessLevel("write", level); + + if (!hasAccess) { + this.logger.error("user does not have access drive item ", id); + throw Error("user does not have access to this item"); + } + + const item = await this.repository.findOne({ + company_id: context.company.id, + id, + }); + + if (!item) { + this.logger.error("Drive item not found"); + throw Error("Item not found"); + } + + if (content.id && content.id !== id) { + this.logger.error("content mismatch"); + throw Error("content mismatch"); + } + + const updatable = ["access_info", "name", "tags", "parent_id", "description"]; + + for (const key of updatable) { + if ((content as any)[key]) { + if ( + key === "parent_id" && + !(await canMoveItem(item.id, content.parent_id, this.repository, context)) + ) { + throw Error("Move operation not permitted"); + } else { + oldParent = item.parent_id; + } + + if (key === "name") { + item.name = await getItemName( + content.parent_id || item.parent_id, + item.id, + content.name, + item.is_directory, + this.repository, + context, + ); + } else { + (item as any)[key] = (content as any)[key]; + } + } + } + + //We cannot do a change that would make the item unreachable + if ( + level === "manage" && + !(await checkAccess(item.id, item, "manage", this.repository, context)) + ) { + throw new Error("Cannot change access level to make the item unreachable"); + } + + await this.repository.save(item); + await updateItemSize(item.parent_id, this.repository, context); + + if (oldParent) { + await updateItemSize(oldParent, this.repository, context); + this.notifyWebsocket(oldParent, context); + } + + this.notifyWebsocket(item.parent_id, context); + + if (item.parent_id === this.TRASH) { + //When moving to trash we recompute the access level to make them flat + item.access_info = await makeStandaloneAccessLevel( + item.company_id, + item.id, + item, + this.repository, + ); + } + + return item; + } catch (error) { + this.logger.error("Failed to update drive item", error); + throw new CrudException("Failed to update item", 500); + } + }; + + /** + * deletes or moves to Trash a Drive Document and its children + * + * @param {string} id - the item id + * @param {DriveExecutionContext} context - the execution context + * @returns {Promise} + */ + delete = async ( + id: string | RootType | TrashType, + item?: DriveFile, + context?: DriveExecutionContext, + ): Promise => { + if (!id) { + //We can't remove the root folder + return; + } + + //In the case of the trash we definitively delete the items + if (id === "trash") { + //Only administrators can execute this action + const role = await gr.services.companies.getUserRole(context.company.id, context.user?.id); + if (hasCompanyAdminLevel(role) === false) { + throw new CrudException("Only administrators can empty the trash", 403); + } + + try { + const itemsInTrash = await this.repository.find( + { + company_id: context.company.id, + parent_id: "trash", + }, + {}, + context, + ); + await Promise.all( + itemsInTrash.getEntities().map(async item => { + await this.delete(item.id, item, context); + }), + ); + } catch (error) { + this.logger.error("Failed to empty trash", error); + throw new CrudException("Failed to empty trash", 500); + } + + return; + } else { + item = + item || + (await this.repository.findOne({ + company_id: context.company.id, + id, + })); + + if (!item) { + this.logger.error("item to delete not found"); + throw new CrudException("Drive item not found", 404); + } + + try { + if (!(await checkAccess(item.id, item, "manage", this.repository, context))) { + this.logger.error("user does not have access drive item ", id); + throw Error("user does not have access to this item"); + } + } catch (error) { + this.logger.error("Failed to grant access to the drive item", error); + throw new CrudException("User does not have access to this item or its children", 401); + } + + const previousParentId = item.parent_id; + if ( + item.parent_id === this.TRASH || + (await getPath(item.parent_id, this.repository, true, context))[0].id === this.TRASH + ) { + //This item is already in trash, we can delete it definitively + + if (item.is_directory) { + //We delete the children + const children = await this.repository.find( + { + company_id: context.company.id, + parent_id: item.id, + }, + {}, + context, + ); + await Promise.all( + children.getEntities().map(async child => { + await this.delete(child.id, child, context); + }), + ); + } else { + //Delete the version and stored file + const itemVersions = await this.fileVersionRepository.find( + { + drive_item_id: item.id, + }, + {}, + context, + ); + await Promise.all( + itemVersions.getEntities().map(async version => { + await this.fileVersionRepository.remove(version); + await gr.services.files.delete(version.file_metadata.external_id, context); + }), + ); + } + await this.repository.remove(item); + } else { + //This item is not in trash, we move it to trash + item.parent_id = this.TRASH; + await this.update(item.id, item, context); + } + await updateItemSize(previousParentId, this.repository, context); + + this.notifyWebsocket(previousParentId, context); + } + + this.notifyWebsocket("trash", context); + }; + + /** + * Create a Drive item version + * + * @param {string} id - the Drive item id to create a version for. + * @param {Partial} version - the version item. + * @param {DriveExecutionContext} context - the company execution context + * @returns {Promise} - the created FileVersion + */ + createVersion = async ( + id: string, + version: Partial, + context: DriveExecutionContext, + ): Promise => { + if (!context) { + this.logger.error("invalid execution context"); + return null; + } + + try { + const hasAccess = await checkAccess(id, null, "write", this.repository, context); + if (!hasAccess) { + this.logger.error("user does not have access drive item ", id); + throw Error("user does not have access to this item"); + } + + const item = await this.repository.findOne( + { + id, + company_id: context.company.id, + }, + {}, + context, + ); + + if (!item) { + throw Error("Drive item not found"); + } + + if (item.is_directory) { + throw Error("cannot create version for a directory"); + } + + const driveItemVersion = getDefaultDriveItemVersion(version, context); + const metadata = await getFileMetadata(driveItemVersion.file_metadata.external_id, context); + + driveItemVersion.file_size = metadata.size; + driveItemVersion.file_metadata.size = metadata.size; + driveItemVersion.file_metadata.name = metadata.name; + driveItemVersion.file_metadata.mime = metadata.mime; + driveItemVersion.file_metadata.thumbnails = metadata.thumbnails; + driveItemVersion.drive_item_id = item.id; + if (context.user.application_id) { + driveItemVersion.application_id = context.user.application_id; + } + + await this.fileVersionRepository.save(driveItemVersion); + + item.last_version_cache = driveItemVersion; + item.size = driveItemVersion.file_size; + + await this.repository.save(item); + + this.notifyWebsocket(item.parent_id, context); + await updateItemSize(item.parent_id, this.repository, context); + + globalResolver.platformServices.messageQueue.publish( + "services:documents:process", + { + data: { + item, + version: driveItemVersion, + context, + }, + }, + ); + + return driveItemVersion; + } catch (error) { + this.logger.error("Failed to create Drive item version", error); + throw new CrudException("Failed to create Drive item version", 500); + } + }; + + downloadGetToken = async ( + ids: string[], + versionId: string | null, + context: DriveExecutionContext, + ): Promise => { + for (const id of ids) { + const item = await this.get(id, context); + if (!item) { + throw new CrudException("Drive item not found", 404); + } + } + + return globalResolver.platformServices.auth.sign({ + ids, + version_id: versionId, + company_id: context.company.id, + user_id: context.user?.id, + }); + }; + + applyDownloadTokenToContext = async ( + ids: string[], + versionId: string | null, + token: string, + context: DriveExecutionContext, + ): Promise => { + try { + const v = globalResolver.platformServices.auth.verifyTokenObject<{ + ids: string[]; + version_id: string; + company_id: string; + user_id: string; + }>(token); + if ( + ids.some(a => !(v?.ids || [])?.includes(a)) || + (v?.version_id && versionId && v?.version_id !== versionId) + ) { + return; + } + + context.company = { id: v.company_id }; + context.user = { id: v.user_id }; + } catch (e) { + if (token) throw new CrudException("Invalid token", 401); + } + }; + + download = async ( + id: string, + versionId: string | null, + context: DriveExecutionContext, + ): Promise<{ + archive?: archiver.Archiver; + file?: { + file: internal.Readable; + name: string; + mime: string; + size: number; + }; + }> => { + const item = await this.get(id, context); + + if (item.item.is_directory) { + return { archive: await this.createZip([id], context) }; + } + + let version = item.item.last_version_cache; + if (versionId) version = item.versions.find(version => version.id === versionId); + if (!version) { + throw new CrudException("Version not found", 404); + } + + const fileId = version.file_metadata.external_id; + const file = await globalResolver.services.files.download(fileId, context); + + return { file }; + }; + + /** + * Creates a zip archive containing the drive items. + * + * @param {string[]} ids - the drive item list + * @param {DriveExecutionContext} context - the execution context + * @returns {Promise} the created archive. + */ + createZip = async ( + ids: string[] = [], + context: DriveExecutionContext, + ): Promise => { + if (!context) { + this.logger.error("invalid execution context"); + return null; + } + + const archive = archiver("zip", { + zlib: { level: 9 }, + }); + + for (const id of ids) { + if (!(await checkAccess(id, null, "read", this.repository, context))) { + this.logger.warn(`not enough permissions to download ${id}, skipping`); + return; + } + + try { + await addDriveItemToArchive(id, null, archive, this.repository, context); + } catch (error) { + console.error(error); + this.logger.warn("failed to add item to archive", error); + } + } + + archive.finalize(); + + return archive; + }; + + notifyWebsocket = async (id: string, context: DriveExecutionContext) => { + websocketEventBus.publish(RealtimeEntityActionType.Event, { + type: "documents:updated", + room: ResourcePath.get(`/companies/${context.company.id}/documents/item/${id}`), + entity: { + companyId: context.company.id, + id: id, + }, + resourcePath: null, + result: null, + }); + }; + + /** + * Search for Drive items. + * + * @param {SearchDocumentsOptions} options - the search optins. + * @param {DriveExecutionContext} context - the execution context. + * @returns {Promise>} - the search result. + */ + search = async ( + options: SearchDocumentsOptions, + context?: DriveExecutionContext, + ): Promise> => { + const result = await this.searchRepository.search( + {}, + { + pagination: { + limitStr: "100", + }, + ...(options.company_id ? { $in: [["company_id", [options.company_id]]] } : {}), + ...(options.creator ? { $in: [["creator", [options.creator]]] } : {}), + ...(options.added ? { $in: [["added", [options.added]]] } : {}), + $text: { + $search: options.search, + }, + }, + context, + ); + + // Use Promise.all to check access on each item in parallel + const filteredResult = await Promise.all( + result.getEntities().filter(async item => { + try { + // Check access for each item + const hasAccess = await checkAccess(item.id, null, "read", this.repository, context); + // Return true if the user has access + return hasAccess; + } catch (error) { + this.logger.warn("failed to check item access", error); + return false; + } + }), + ); + + return new ListResult(result.type, filteredResult, result.nextPage); + }; + + getTab = async (tabId: string, context: CompanyExecutionContext): Promise => { + const tab = await this.driveTwakeTabRepository.findOne( + { company_id: context.company.id, tab_id: tabId }, + {}, + context, + ); + return tab; + }; + + setTab = async ( + tabId: string, + channelId: string, + itemId: string, + level: "read" | "write", + context: CompanyExecutionContext, + ): Promise => { + const hasAccess = await checkAccess(itemId, null, "manage", this.repository, context); + + if (!hasAccess) { + throw new CrudException("Not enough permissions", 403); + } + + const previousTabConfiguration = await this.getTab(tabId, context); + const item = await this.repository.findOne( + { + company_id: context.company.id, + id: itemId, + }, + {}, + context, + ); + + await this.driveTwakeTabRepository.save( + Object.assign(new DriveTwakeTabEntity(), { + company_id: context.company.id, + tab_id: tabId, + channel_id: channelId, + item_id: itemId, + level, + }), + context, + ); + + await this.update( + item.id, + { + ...item, + access_info: { + ...item.access_info, + entities: [ + ...(item.access_info?.entities || []).filter( + e => + !previousTabConfiguration || + !(e.type === "channel" && e.id !== previousTabConfiguration.channel_id), + ), + { + type: "channel", + id: channelId, + level: level === "write" ? "write" : "read", + }, + ], + }, + }, + context, + ); + + return await this.getTab(tabId, context); + }; +} diff --git a/twake/backend/node/src/services/documents/types.ts b/twake/backend/node/src/services/documents/types.ts new file mode 100644 index 00000000..79d5f360 --- /dev/null +++ b/twake/backend/node/src/services/documents/types.ts @@ -0,0 +1,75 @@ +import { ExecutionContext } from "../../core/platform/framework/api/crud-service"; +import { DriveFile } from "./entities/drive-file"; +import { FileVersion } from "./entities/file-version"; + +export interface CompanyExecutionContext extends ExecutionContext { + company: { id: string }; +} + +export type DriveExecutionContext = CompanyExecutionContext & { + public_token?: string; +}; + +export type RequestParams = { + company_id: string; +}; + +export type ItemRequestParams = RequestParams & { + id: string; +}; + +export type DriveItemDetails = { + path: DriveFile[]; + item?: DriveFile; + versions?: FileVersion[]; + children: DriveFile[]; + access: DriveFileAccessLevel | "none"; +}; + +export type DriveFileAccessLevel = "read" | "write" | "manage"; +export type publicAccessLevel = "write" | "read" | "none"; + +export type RootType = "root"; +export type TrashType = "trash"; + +export type DownloadZipBodyRequest = { + items: string[]; +}; + +export type SearchDocumentsOptions = { + search?: string; + company_id?: string; + creator?: string; + added?: string; +}; + +export type SearchDocumentsBody = { + search?: string; + company_id?: string; + creator?: string; + added?: string; +}; + +export type DocumentsMessageQueueRequest = { + item: DriveFile; + version: FileVersion; + context: CompanyExecutionContext; +}; + +export type DocumentsMessageQueueCallback = { + item: DriveFile; + content_keywords: string; +}; + +export type exportKeywordPayload = { + file_id: string; + company_id: string; +}; + +export type DriveTwakeTab = { + company_id: string; + tab_id: string; + channel_id: string; + item_id: string; + level: "read" | "write"; +}; diff --git a/twake/backend/node/src/services/documents/utils.ts b/twake/backend/node/src/services/documents/utils.ts new file mode 100644 index 00000000..c622606f --- /dev/null +++ b/twake/backend/node/src/services/documents/utils.ts @@ -0,0 +1,806 @@ +import { merge } from "lodash"; +import { DriveFile } from "./entities/drive-file"; +import { + CompanyExecutionContext, + DriveExecutionContext, + DriveFileAccessLevel, + RootType, + TrashType, +} from "./types"; +import crypto from "crypto"; +import { FileVersion, DriveFileMetadata } from "./entities/file-version"; +import globalResolver from "../global-resolver"; +import Repository from "../../core/platform/services/database/services/orm/repository/repository"; +import archiver from "archiver"; +import { Readable } from "stream"; +import { stopWords } from "./const"; +import unoconv from "unoconv-promise"; +import { + writeToTemporaryFile, + cleanFiles, + getTmpFile, + readFromTemporaryFile, + readableToBuffer, +} from "../../utils/files"; +import PdfParse from "pdf-parse"; +import _ from "lodash"; +import { logger } from "../../core/platform/framework"; + +/** + * Returns the default DriveFile object using existing data + * + * @param {Partial} item - the partial drive file item. + * @param {CompanyExecutionContext} context - the company execution context + * @returns {DriveFile} - the Default DriveFile + */ +export const getDefaultDriveItem = ( + item: Partial, + context: CompanyExecutionContext, +): DriveFile => { + const defaultDriveItem = merge>(new DriveFile(), { + company_id: context.company.id, + added: item.added || new Date().getTime().toString(), + creator: item.creator || context.user?.id, + is_directory: item.is_directory || false, + is_in_trash: item.is_in_trash || false, + last_modified: new Date().getTime().toString(), + parent_id: item.parent_id || "root", + content_keywords: item.content_keywords || "", + description: item.description || "", + access_info: item.access_info || { + entities: [ + { + id: "parent", + type: "folder", + level: "manage", + }, + { + id: item.company_id, + type: "company", + level: "none", + }, + { + id: context.user?.id, + type: "user", + level: "manage", + }, + ], + public: { + level: "none", + token: generateAccessToken(), + }, + }, + extension: item.extension || "", + last_version_cache: item.last_version_cache, + name: item.name || "", + size: item.size || 0, + tags: item.tags || [], + }); + + if (item.id) { + defaultDriveItem.id = item.id; + } + + return defaultDriveItem; +}; + +/** + * Returns the default FileVersion item. + * + * @param {Partial} version - the partial version item + * @param {CompanyExecutionContext} context - the execution context + * @returns + */ +export const getDefaultDriveItemVersion = ( + version: Partial, + context: CompanyExecutionContext, +): FileVersion => { + const defaultVersion = merge(new FileVersion(), { + application_id: version.application_id || "", + creator_id: version.creator_id || context.user?.id, + data: version.data || {}, + date_added: version.date_added || new Date().getTime(), + drive_item_id: version.drive_item_id || "", + file_metadata: version.file_metadata || {}, + file_size: version.file_size || 0, + filename: version.filename || "", + key: version.key || "", + mode: version.mode || "OpenSSL-2", + provider: version.provider, + realname: version.realname, + }); + + if (version.id) { + defaultVersion.id = version.id; + } + + return defaultVersion; +}; + +/** + * Generates a random sha1 access token + * + * @returns {String} - the random access token ( sha1 hex digest ). + */ +export const generateAccessToken = (): string => { + const randomBytes = crypto.randomBytes(64); + + return crypto.createHash("sha1").update(randomBytes).digest("hex"); +}; + +/** + * Checks if the level meets the required level. + * + * @param {publicAccessLevel | DriveFileAccessLevel} requiredLevel + * @param {publicAccessLevel} level + * @returns {boolean} + */ +export const hasAccessLevel = ( + requiredLevel: DriveFileAccessLevel | "none", + level: DriveFileAccessLevel | "none", +): boolean => { + if (requiredLevel === level) return true; + + if (requiredLevel === "write") { + return level === "manage"; + } + + if (requiredLevel === "read") { + return level === "manage" || level === "write"; + } + + return requiredLevel === "none"; +}; + +/** + * checks the current user is a guest + * + * @param {CompanyExecutionContext} context + * @returns {Promise} + */ +export const isCompanyGuest = async (context: CompanyExecutionContext): Promise => { + const userRole = await globalResolver.services.companies.getUserRole( + context.company.id, + context.user?.id, + ); + + return userRole === "guest" || !userRole; +}; + +/** + * checks the current user is a admin + * + * @param {CompanyExecutionContext} context + * @returns {Promise} + */ +export const isCompanyAdmin = async (context: CompanyExecutionContext): Promise => { + const userRole = await globalResolver.services.companies.getUserRole( + context.company.id, + context.user?.id, + ); + + return userRole === "admin"; +}; + +/** + * Calculates the size of the Drive Item + * + * @param {DriveFile} item - The file or directory + * @param {Repository} repository - the database repository + * @param {CompanyExecutionContext} context - the execution context + * @returns {Promise} - the size of the Drive Item + */ +export const calculateItemSize = async ( + item: DriveFile | TrashType | RootType, + repository: Repository, + context: CompanyExecutionContext, +): Promise => { + if (item === "trash") { + const trashedItems = await repository.find( + { company_id: context.company.id, parent_id: "trash" }, + {}, + context, + ); + + return trashedItems.getEntities().reduce((acc, curr) => acc + curr.size, 0); + } + + if (item === "root" || !item) { + const rootFolderItems = await repository.find( + { company_id: context.company.id, parent_id: "root" }, + {}, + context, + ); + + return rootFolderItems.getEntities().reduce((acc, curr) => acc + curr.size, 0); + } + + if (item.is_directory) { + const children = await repository.find( + { + company_id: context.company.id, + parent_id: item.id, + }, + {}, + context, + ); + + return children.getEntities().reduce((acc, curr) => acc + curr.size, 0); + } + + return item.size; +}; + +/** + * Recalculates and updates the Drive item size + * + * @param {string} id - the item id + * @param {Repository} repository + * @param {CompanyExecutionContext} context - the execution context + * @returns {Promise} + */ +export const updateItemSize = async ( + id: string, + repository: Repository, + context: CompanyExecutionContext, +): Promise => { + if (!id || id === "root" || id === "trash") return; + + const item = await repository.findOne({ id, company_id: context.company.id }); + + if (!item) { + throw Error("Drive item doesn't exist"); + } + + item.size = await calculateItemSize(item, repository, context); + + await repository.save(item); + + if (item.parent_id === "root" || item.parent_id === "trash") { + return; + } + + await updateItemSize(item.parent_id, repository, context); +}; + +/** + * gets the path for the driveitem + * + * @param {string} id + * @param {Repository} repository + * @param {boolean} ignoreAccess + * @param {CompanyExecutionContext} context + * @returns + */ +export const getPath = async ( + id: string, + repository: Repository, + ignoreAccess?: boolean, + context?: DriveExecutionContext, +): Promise => { + id = id || "root"; + if (id === "root" || id === "trash") + return !context.public_token || ignoreAccess + ? [ + { + id, + name: id === "root" ? "Home" : "Trash", + } as DriveFile, + ] + : []; + + const item = await repository.findOne({ + id, + company_id: context.company.id, + }); + + if (!item || (!(await checkAccess(id, item, "read", repository, context)) && !ignoreAccess)) { + return []; + } + + return [...(await getPath(item.parent_id, repository, ignoreAccess, context)), item]; +}; + +/** + * checks if access can be granted for the drive item + * + * @param {string} id + * @param {DriveFile | null} item + * @param {DriveFileAccessLevel} level + * @param {Repository} repository + * @param {CompanyExecutionContext} context + * @param {string} token + * @returns {Promise} + */ +export const checkAccess = async ( + id: string, + item: DriveFile | null, + level: DriveFileAccessLevel, + repository: Repository, + context: CompanyExecutionContext & { public_token?: string; twake_tab_token?: string }, +): Promise => { + if (context.user.server_request) { + return true; + } + + const grantedLevel = await getAccessLevel(id, item, repository, context); + const hasAccess = hasAccessLevel(level, grantedLevel); + logger.info( + `Got level ${grantedLevel} for drive item ${id} and required ${level} - returning ${hasAccess}`, + ); + return hasAccess; +}; + +/** + * get maximum level for the drive item + * + * @param {string} id + * @param {DriveFile | null} item + * @param {Repository} repository + * @param {CompanyExecutionContext} context + * @param {string} token + * @returns {Promise} + */ +export const getAccessLevel = async ( + id: string, + item: DriveFile | null, + repository: Repository, + context: CompanyExecutionContext & { public_token?: string; twake_tab_token?: string }, +): Promise => { + if ( + context.user?.application_id && + ( + await globalResolver.services.applications.companyApps.get({ + company_id: context.company.id, + application_id: context.user.application_id, + }) + )?.application?.access //TODO check precise access right for applications + ) { + return "manage"; + } + + if (!id || id === "root") + return !context?.user?.id ? "none" : (await isCompanyGuest(context)) ? "read" : "manage"; + if (id === "trash") + return (await isCompanyGuest(context)) || !context?.user?.id + ? "none" + : (await isCompanyAdmin(context)) + ? "manage" + : "write"; + + const publicToken = context.public_token; + + try { + item = + item || + (await repository.findOne({ + id, + company_id: context.company.id, + })); + + if (!item) { + throw Error("Drive item doesn't exist"); + } + + /* + * Specific user or channel rule is applied first. Then less restrictive level will be chosen + * between the parent folder and company accesses. + */ + + //Public access + if (publicToken) { + if (!item.access_info.public.token) return "none"; + const { token: itemToken, level: itemLevel } = item.access_info.public; + if (itemToken === publicToken) return itemLevel; + } + + const accessEntities = item.access_info.entities || []; + const otherLevels = []; + + //From there a user must be logged in + if (context?.user?.id) { + //Users + const matchingUser = accessEntities.find(a => a.type === "user" && a.id === context.user?.id); + if (matchingUser) return matchingUser.level; + + //Channels + if (context.twake_tab_token) { + try { + const [channelId] = context.twake_tab_token.split("+"); //First item will be the channel id + const matchingChannel = accessEntities.find( + a => a.type === "channel" && a.id === channelId, + ); + if (matchingChannel) return matchingChannel.level; + } catch (e) { + console.log(e); + } + } + + //Companies + const matchingCompany = accessEntities.find( + a => a.type === "company" && a.id === context.company.id, + ); + if (matchingCompany) otherLevels.push(matchingCompany.level); + } + + //Parent folder + const maxParentFolderLevel = + accessEntities.find(a => a.type === "folder" && a.id === "parent")?.level || "none"; + if (maxParentFolderLevel === "none") { + otherLevels.push(maxParentFolderLevel); + } else { + const parentFolderLevel = await getAccessLevel(item.parent_id, null, repository, context); + otherLevels.push(parentFolderLevel); + } + + //Return least restrictive level of otherLevels + return otherLevels.reduce( + (previousValue, b) => + hasAccessLevel(b as DriveFileAccessLevel, previousValue as DriveFileAccessLevel) + ? previousValue + : b, + "none", + ) as DriveFileAccessLevel | "none"; + } catch (error) { + throw Error(error); + } +}; + +/** + * Isolate access level information from parent folder logic + * Used when putting folder in the trash + * @param id + * @param item + * @param repository + */ +export const makeStandaloneAccessLevel = async ( + companyId: string, + id: string, + item: DriveFile | null, + repository: Repository, + options: { removePublicAccess?: boolean } = { removePublicAccess: true }, +): Promise => { + item = + item || + (await repository.findOne({ + id, + company_id: companyId, + })); + + if (!item) { + throw Error("Drive item doesn't exist"); + } + + const accessInfo = _.cloneDeep(item.access_info); + + if (options?.removePublicAccess && accessInfo?.public?.level) accessInfo.public.level = "none"; + + const parentFolderAccess = accessInfo.entities.find( + a => a.type === "folder" && a.id === "parent", + ); + + if (!parentFolderAccess || parentFolderAccess.level === "none") { + return accessInfo; + } else if (item.parent_id !== "root" && item.parent_id !== "trash") { + // Get limitations from parent folder + const accessEntitiesFromParent = await makeStandaloneAccessLevel( + companyId, + item.parent_id, + null, + repository, + options, + ); + + let mostRestrictiveFolderLevel = parentFolderAccess.level as DriveFileAccessLevel | "none"; + + const keptEntities = accessEntitiesFromParent.entities.filter(a => { + if (["user", "channel"].includes(a.type)) { + return !accessInfo.entities.find(b => b.type === a.type && b.id === a.id); + } else { + if (a.type === "folder" && a.id === "parent") { + mostRestrictiveFolderLevel = hasAccessLevel(a.level, mostRestrictiveFolderLevel) + ? a.level + : mostRestrictiveFolderLevel; + } + return false; + } + }); + + accessInfo.entities = accessInfo.entities.map(a => { + if (a.type === "folder" && a.id === "parent") { + a.level = mostRestrictiveFolderLevel; + } + return a; + }) as DriveFile["access_info"]["entities"]; + + accessInfo.entities = [...accessInfo.entities, ...keptEntities]; + } + + return accessInfo; +}; + +/** + * Adds drive items to an archive recursively + * + * @param {string} id - the drive item id + * @param {DriveFile | null } entity - the drive item entity + * @param {archiver.Archiver} archive - the archive + * @param {Repository} repository - the repository + * @param {CompanyExecutionContext} context - the execution context + * @param {string} prefix - folder prefix + * @returns {Promise} + */ +export const addDriveItemToArchive = async ( + id: string, + entity: DriveFile | null, + archive: archiver.Archiver, + repository: Repository, + context: CompanyExecutionContext, + prefix?: string, +): Promise => { + const item = entity || (await repository.findOne({ id, company_id: context.company.id })); + + if (!item) { + throw Error("item not found"); + } + + if (!item.is_directory) { + const file_id = item.last_version_cache.file_metadata.external_id; + const file = await globalResolver.services.files.download(file_id, context); + + if (!file) { + throw Error("file not found"); + } + + archive.append(file.file, { name: file.name, prefix: prefix ?? "" }); + return; + } else { + const items = await repository.find({ + parent_id: item.id, + company_id: context.company.id, + }); + + for (const child of items.getEntities()) { + await addDriveItemToArchive( + child.id, + child, + archive, + repository, + context, + `${prefix || ""}${item.name}/`, + ); + } + + return; + } +}; + +/** + * Extracts the most popular 250 keywords from a text. + * + * @param {string} data - file data string. + * @returns {string} + */ +export const extractKeywords = (data: string): string => { + const words = data.toLowerCase().split(/[^a-zA-Z']+/); + const filteredWords = words.filter(word => !stopWords.includes(word) && word.length > 3); + + const wordFrequency = filteredWords.reduce((acc: Record, word: string) => { + acc[word] = (acc[word] || 0) + 1; + + return acc; + }, {}); + + const sortedFrequency = Object.entries(wordFrequency) + .sort((a, b) => b[1] - a[1]) + .reduce((acc: Record, [key, val]) => { + acc[key] = val; + + return acc; + }, {}); + + return Object.keys(sortedFrequency).slice(0, 250).join(" "); +}; + +/** + * Converts an office file stream into a human readable string. + * + * @param {Readable} file - the input file stream. + * @param {string} extension - the file extension. + * @returns {Promise} + */ +export const officeFileToString = async (file: Readable, extension: string): Promise => { + const officeFilePath = await writeToTemporaryFile(file, extension); + const outputPath = getTmpFile(".pdf"); + + try { + await unoconv.run({ + file: officeFilePath, + output: outputPath, + }); + + cleanFiles([officeFilePath]); + + return await pdfFileToString(outputPath); + } catch (error) { + cleanFiles([officeFilePath]); + throw Error(error); + } +}; + +/** + * Converts a PDF file stream into a human readable string. + * + * @param {Readable | string} file - the input file stream or path. + * @returns {Promise} + */ +export const pdfFileToString = async (file: Readable | string): Promise => { + let inputBuffer: Buffer; + + try { + if (typeof file === "string") { + inputBuffer = await readFromTemporaryFile(file); + cleanFiles([file]); + } else { + inputBuffer = await readableToBuffer(file); + } + + const result = await PdfParse(inputBuffer); + + return result.text; + } catch (error) { + if (typeof file === "string") { + cleanFiles([file]); + } + + throw Error(error); + } +}; + +/** + * returns the file metadata. + * + * @param {string} fileId - the file id + * @param {CompanyExecutionContext} context - the execution context + * @returns {DriveFileMetadata} + */ +export const getFileMetadata = async ( + fileId: string, + context: CompanyExecutionContext, +): Promise => { + const file = await globalResolver.services.files.getFile( + { + id: fileId, + company_id: context.company.id, + }, + context, + { ...(context.user.server_request ? {} : { waitForThumbnail: true }) }, + ); + + if (!file) { + throw Error("File doesn't exist"); + } + + return { + source: "internal", + external_id: fileId, + mime: file.metadata.mime, + name: file.metadata.name, + size: file.upload_data.size, + thumbnails: file.thumbnails, + } as DriveFileMetadata; +}; + +/** + * Finds a suitable name for an item based on items inside the same folder. + * + * @param {string} parent_id - the parent id. + * @param {string} name - the item name. + * @param {Repository} repository - the drive repository. + * @param {CompanyExecutionContext} context - the execution context. + * @returns {Promise} - the drive item name. + */ +export const getItemName = async ( + parent_id: string, + id: string, + name: string, + is_directory: boolean, + repository: Repository, + context: CompanyExecutionContext, +): Promise => { + try { + let newName = name.substring(0, 255); + let exists = true; + const children = await repository.find( + { + parent_id, + company_id: context.company.id, + }, + {}, + context, + ); + + while (exists) { + exists = !!children + .getEntities() + .find( + child => child.name === newName && child.is_directory === is_directory && child.id !== id, + ); + + if (exists) { + const ext = newName.split(".").pop(); + newName = + ext && ext !== newName ? `${newName.slice(0, -ext.length - 1)}-2.${ext}` : `${newName}-2`; + } + } + + return newName; + } catch (error) { + throw Error("Failed to get item name"); + } +}; + +/** + * Checks if an item can be moved to its destination + * An item cannot be moved to itself or any of its derived chilren. + * + * @param {string} source - the to be moved item id. + * @param {string} target - the to be moved to item id. + * @param {string} repository - the Drive item repository. + * @param {CompanyExecutionContex} context - the execution context. + * @returns {Promise} - whether the move is possible or not. + */ +export const canMoveItem = async ( + source: string, + target: string, + repository: Repository, + context: CompanyExecutionContext, +): Promise => { + if (source === target) return false; + if (target === "root" || target === "trash") return true; + + const item = await repository.findOne({ + id: source, + company_id: context.company.id, + }); + + if (!item.is_directory) { + return true; + } + + const targetItem = await repository.findOne({ + id: target, + company_id: context.company.id, + }); + + if (!targetItem || !targetItem.is_directory) { + throw Error("target item doesn't exist or not a directory"); + } + + if (!(await checkAccess(target, targetItem, "write", repository, context))) { + return false; + } + + if (!item) { + throw Error("Item not found"); + } + + const children = ( + await repository.find({ + parent_id: source, + company_id: context.company.id, + }) + ).getEntities(); + + if (children.some(child => child.id === target)) { + return false; + } + + for (const child of children) { + if (child.is_directory && !(await canMoveItem(child.id, target, repository, context))) { + return false; + } + } + + return true; +}; diff --git a/twake/backend/node/src/services/documents/web/controllers/documents.ts b/twake/backend/node/src/services/documents/web/controllers/documents.ts new file mode 100644 index 00000000..c5e4cdfe --- /dev/null +++ b/twake/backend/node/src/services/documents/web/controllers/documents.ts @@ -0,0 +1,401 @@ +import { FastifyReply, FastifyRequest } from "fastify"; +import { logger } from "../../../../core/platform/framework"; +import { CrudException, ListResult } from "../../../../core/platform/framework/api/crud-service"; +import { File } from "../../../../services/files/entities/file"; +import { UploadOptions } from "../../../../services/files/types"; +import globalResolver from "../../../../services/global-resolver"; +import { PaginationQueryParameters, ResourceWebsocket } from "../../../../utils/types"; +import { DriveFile } from "../../entities/drive-file"; +import { FileVersion } from "../../entities/file-version"; +import { + CompanyExecutionContext, + DriveExecutionContext, + DriveItemDetails, + DriveTwakeTab, + ItemRequestParams, + RequestParams, + SearchDocumentsBody, + SearchDocumentsOptions, +} from "../../types"; + +export class DocumentsController { + /** + * Creates a DriveFile item + * + * @param {FastifyRequest} request + * @returns + */ + create = async ( + request: FastifyRequest<{ + Params: RequestParams; + Querystring: Record; + Body: { + item: Partial; + version: Partial; + }; + }>, + ): Promise => { + try { + const context = getDriveExecutionContext(request); + + let createdFile: File = null; + if (request.isMultipart()) { + const file = await request.file(); + const q = request.query; + const options: UploadOptions = { + totalChunks: parseInt(q.resumableTotalChunks || q.total_chunks) || 1, + totalSize: parseInt(q.resumableTotalSize || q.total_size) || 0, + chunkNumber: parseInt(q.resumableChunkNumber || q.chunk_number) || 1, + filename: q.resumableFilename || q.filename || file?.filename || undefined, + type: q.resumableType || q.type || file?.mimetype || undefined, + waitForThumbnail: !!q.thumbnail_sync, + }; + + createdFile = await globalResolver.services.files.save(null, file, options, context); + } + + const { item, version } = request.body; + + return await globalResolver.services.documents.documents.create( + createdFile, + item, + version, + context, + ); + } catch (error) { + logger.error("Failed to create Drive item", error); + throw new CrudException("Failed to create Drive item", 500); + } + }; + + /** + * Deletes a DriveFile item or empty the trash or delete root folder contents + * + * @param {FastifyRequest} request + * @returns {Promise} + */ + delete = async ( + request: FastifyRequest<{ Params: ItemRequestParams; Querystring: { public_token?: string } }>, + reply: FastifyReply, + ): Promise => { + try { + const context = getDriveExecutionContext(request); + + await globalResolver.services.documents.documents.delete(request.params.id, null, context); + + reply.status(200).send(); + } catch (error) { + logger.error("Failed to delete drive item", error); + throw new CrudException("Failed to delete drive item", 500); + } + }; + + /** + * Lists the drive root folder. + * + * @param {FastifyRequest} request + * @returns {Promise} + */ + listRootFolder = async ( + request: FastifyRequest<{ + Params: RequestParams; + Querystring: PaginationQueryParameters & { public_token?: string }; + }>, + ): Promise => { + const context = getDriveExecutionContext(request); + + return await globalResolver.services.documents.documents.get(null, context); + }; + + /** + * Fetches a DriveFile item. + * + * @param {FastifyRequest} request + * @returns {Promise} + */ + get = async ( + request: FastifyRequest<{ + Params: ItemRequestParams; + Querystring: PaginationQueryParameters & { public_token?: string }; + }>, + ): Promise => { + const context = getDriveExecutionContext(request); + const { id } = request.params; + + return { + ...(await globalResolver.services.documents.documents.get(id, context)), + websockets: request.currentUser?.id + ? globalResolver.platformServices.realtime.sign( + [{ room: `/companies/${context.company.id}/documents/item/${id}` }], + request.currentUser?.id, + ) + : [], + }; + }; + + /** + * Update drive item + * + * @param {FastifyRequest} request + * @returns {Promise} + */ + update = async ( + request: FastifyRequest<{ + Params: ItemRequestParams; + Body: Partial; + Querystring: { public_token?: string }; + }>, + ): Promise => { + const context = getDriveExecutionContext(request); + const { id } = request.params; + const update = request.body; + + if (!id) throw new CrudException("Missing id", 400); + + return await globalResolver.services.documents.documents.update(id, update, context); + }; + + /** + * Create a drive file version. + * + * @param {FastifyRequest} request + * @returns {Promise} + */ + createVersion = async ( + request: FastifyRequest<{ + Params: ItemRequestParams; + Body: Partial; + Querystring: { public_token?: string }; + }>, + ): Promise => { + const context = getDriveExecutionContext(request); + const { id } = request.params; + const version = request.body; + + if (!id) throw new CrudException("Missing id", 400); + + return await globalResolver.services.documents.documents.createVersion(id, version, context); + }; + + downloadGetToken = async ( + request: FastifyRequest<{ + Params: ItemRequestParams; + Querystring: { version_id?: string; items?: string; public_token?: string }; + }>, + ): Promise<{ token: string }> => { + const ids = (request.query.items || "").split(","); + const context = getDriveExecutionContext(request); + return { + token: await globalResolver.services.documents.documents.downloadGetToken( + ids, + request.query.version_id, + context, + ), + }; + }; + + /** + * Shortcut to download a file (you can also use the file-service directly). + * If the item is a folder, a zip will be automatically generated. + * + * @param {FastifyRequest} request + * @param {FastifyReply} reply + */ + download = async ( + request: FastifyRequest<{ + Params: ItemRequestParams; + Querystring: { version_id?: string; token?: string; public_token?: string }; + }>, + response: FastifyReply, + ): Promise => { + const context = getDriveExecutionContext(request); + const id = request.params.id || ""; + const versionId = request.query.version_id || null; + const token = request.query.token; + await globalResolver.services.documents.documents.applyDownloadTokenToContext( + [id], + versionId, + token, + context, + ); + + try { + const archiveOrFile = await globalResolver.services.documents.documents.download( + id, + versionId, + context, + ); + + if (archiveOrFile.archive) { + const archive = archiveOrFile.archive; + + archive.on("finish", () => { + response.status(200); + }); + + archive.on("error", () => { + response.internalServerError(); + }); + + archive.pipe(response.raw); + } else if (archiveOrFile.file) { + const data = archiveOrFile.file; + const filename = data.name.replace(/[^a-zA-Z0-9 -_.]/g, ""); + + response.header("Content-disposition", `attachment; filename="${filename}"`); + if (data.size) response.header("Content-Length", data.size); + response.type(data.mime); + response.send(data.file); + } + } catch (error) { + logger.error("failed to download file", error); + throw new CrudException("Failed to download file", 500); + } + }; + + /** + * Downloads a zip archive containing the drive items. + * + * @param {FastifyRequest} request + * @param {FastifyReply} reply + */ + downloadZip = async ( + request: FastifyRequest<{ + Params: RequestParams; + Querystring: { token?: string; items: string; public_token?: string }; + }>, + reply: FastifyReply, + ): Promise => { + const context = getDriveExecutionContext(request); + let ids = (request.query.items || "").split(","); + const token = request.query.token; + + await globalResolver.services.documents.documents.applyDownloadTokenToContext( + ids, + null, + token, + context, + ); + + if (ids[0] === "root") { + const items = await globalResolver.services.documents.documents.get(ids[0], context); + ids = items.children.map(item => item.id); + } + + try { + const archive = await globalResolver.services.documents.documents.createZip(ids, context); + + archive.on("finish", () => { + reply.status(200); + }); + + archive.on("error", () => { + reply.internalServerError(); + }); + + archive.pipe(reply.raw); + } catch (error) { + logger.error("failed to send zip file", error); + throw new CrudException("Failed to create zip file", 500); + } + }; + /** + * Search for documents. + * + * @param {FastifyRequest} request + * @returns {Promise>} + */ + search = async ( + request: FastifyRequest<{ + Params: RequestParams; + Body: SearchDocumentsBody; + Querystring: { public_token?: string }; + }>, + ): Promise> => { + try { + const context = getDriveExecutionContext(request); + const { search = "", added = "", company_id = "", creator = "" } = request.body; + + const options: SearchDocumentsOptions = { + company_id: company_id || context.company.id, + ...(search ? { search } : {}), + ...(added ? { added } : {}), + ...(creator ? { creator } : {}), + }; + + if (!Object.keys(options).length) { + throw Error("Search options are empty"); + } + + return await globalResolver.services.documents.documents.search(options, context); + } catch (error) { + logger.error("error while searching for document", error); + throw new CrudException("Failed to search for documents", 500); + } + }; + + getTab = async ( + request: FastifyRequest<{ + Params: { tab_id: string; company_id: string }; + }>, + ): Promise => { + const context = getCompanyExecutionContext(request); + const { tab_id } = request.params; + + return await globalResolver.services.documents.documents.getTab(tab_id, context); + }; + + setTab = async ( + request: FastifyRequest<{ + Params: { tab_id: string; company_id: string }; + Body: DriveTwakeTab; + }>, + ): Promise => { + const context = getCompanyExecutionContext(request); + const { tab_id } = request.params; + + if (!request.body.channel_id || !request.body.item_id) + throw new Error("Missing parameters (channel_id, item_id)"); + + return await globalResolver.services.documents.documents.setTab( + tab_id, + request.body.channel_id, + request.body.item_id, + request.body.level, + context, + ); + }; +} + +/** + * Gets the company execution context + * + * @param { FastifyRequest<{ Params: { company_id: string } }>} req + * @returns {CompanyExecutionContext} + */ +const getDriveExecutionContext = ( + req: FastifyRequest<{ Params: { company_id: string }; Querystring: { public_token?: string } }>, +): DriveExecutionContext => ({ + public_token: req.query.public_token, + user: req.currentUser, + company: { id: req.params.company_id }, + url: req.url, + method: req.routerMethod, + reqId: req.id, + transport: "http", +}); + +function getCompanyExecutionContext( + request: FastifyRequest<{ + Params: { company_id: string }; + }>, +): CompanyExecutionContext { + return { + user: request.currentUser, + company: { id: request.params.company_id }, + url: request.url, + method: request.routerMethod, + reqId: request.id, + transport: "http", + }; +} diff --git a/twake/backend/node/src/services/documents/web/controllers/index.ts b/twake/backend/node/src/services/documents/web/controllers/index.ts new file mode 100644 index 00000000..afd2285a --- /dev/null +++ b/twake/backend/node/src/services/documents/web/controllers/index.ts @@ -0,0 +1 @@ +export * from "./documents"; diff --git a/twake/backend/node/src/services/documents/web/index.ts b/twake/backend/node/src/services/documents/web/index.ts new file mode 100644 index 00000000..6a3ab74b --- /dev/null +++ b/twake/backend/node/src/services/documents/web/index.ts @@ -0,0 +1,12 @@ +import fastifyCaching from "@fastify/caching"; +import { FastifyInstance, FastifyRegisterOptions } from "fastify"; +import routes from "./routes"; + +export default ( + fastify: FastifyInstance, + options: FastifyRegisterOptions<{ prefix: string }>, +): void => { + fastify.log.debug("configuring /internal/services/documents/v1 routes"); + fastify.register(fastifyCaching, { expiresIn: 31536000, privacy: fastifyCaching.privacy.PUBLIC }); + fastify.register(routes, options); +}; diff --git a/twake/backend/node/src/services/documents/web/routes.ts b/twake/backend/node/src/services/documents/web/routes.ts new file mode 100644 index 00000000..0bcf1aff --- /dev/null +++ b/twake/backend/node/src/services/documents/web/routes.ts @@ -0,0 +1,100 @@ +import { FastifyInstance, FastifyPluginCallback } from "fastify"; +import { DocumentsController } from "./controllers"; +import { createDocumentSchema, createVersionSchema } from "./schemas"; + +const baseUrl = "/companies/:company_id"; +const serviceUrl = `${baseUrl}/item`; + +const routes: FastifyPluginCallback = (fastify: FastifyInstance, _options, next) => { + const documentsController = new DocumentsController(); + + fastify.route({ + method: "GET", + url: `${serviceUrl}`, + preValidation: [fastify.authenticateOptional], + handler: documentsController.listRootFolder.bind(documentsController), + }); + + fastify.route({ + method: "GET", + url: `${serviceUrl}/:id`, + preValidation: [fastify.authenticateOptional], + handler: documentsController.get.bind(documentsController), + }); + + fastify.route({ + method: "POST", + url: serviceUrl, + preValidation: [fastify.authenticateOptional], + schema: createDocumentSchema, + handler: documentsController.create.bind(documentsController), + }); + + fastify.route({ + method: "POST", + url: `${serviceUrl}/:id`, + preValidation: [fastify.authenticateOptional], + handler: documentsController.update.bind(documentsController), + }); + + fastify.route({ + method: "DELETE", + url: `${serviceUrl}/:id`, + preValidation: [fastify.authenticateOptional], + handler: documentsController.delete.bind(documentsController), + }); + + fastify.route({ + method: "POST", + url: `${serviceUrl}/:id/version`, + preValidation: [fastify.authenticateOptional], + schema: createVersionSchema, + handler: documentsController.createVersion.bind(documentsController), + }); + + fastify.route({ + method: "GET", + url: `${serviceUrl}/download/token`, + preValidation: [fastify.authenticateOptional], + handler: documentsController.downloadGetToken.bind(documentsController), + }); + + fastify.route({ + method: "GET", + url: `${serviceUrl}/:id/download`, + preValidation: [fastify.authenticateOptional], + handler: documentsController.download.bind(documentsController), + }); + + fastify.route({ + method: "GET", + url: `${serviceUrl}/download/zip`, + preValidation: [fastify.authenticateOptional], + handler: documentsController.downloadZip.bind(documentsController), + }); + + fastify.route({ + method: "POST", + url: `${baseUrl}/search`, + preValidation: [fastify.authenticate], + handler: documentsController.search.bind(documentsController), + }); + + fastify.route({ + method: "GET", + url: `${baseUrl}/tabs/:tab_id`, + preValidation: [fastify.authenticate], + handler: documentsController.getTab.bind(documentsController), + }); + + fastify.route({ + method: "POST", + url: `${baseUrl}/tabs/:tab_id`, + preValidation: [fastify.authenticate], + handler: documentsController.setTab.bind(documentsController), + }); + + return next(); +}; + +export default routes; diff --git a/twake/backend/node/src/services/documents/web/schemas.ts b/twake/backend/node/src/services/documents/web/schemas.ts new file mode 100644 index 00000000..f49aa3d5 --- /dev/null +++ b/twake/backend/node/src/services/documents/web/schemas.ts @@ -0,0 +1,108 @@ +const fileVersionSchema = { + type: "object", + properties: { + id: { type: "string" }, + provider: { type: "string" }, + drive_item_id: { type: "string" }, + file_metadata: { + type: "object", + properties: { + source: { type: "string" }, + external_id: { type: "string" }, + name: { type: "string" }, + mime: { type: "string" }, + size: { type: "string" }, + thumbnails: { + type: "object", + properties: { + index: { type: "number" }, + id: { type: "string" }, + type: { type: "string" }, + size: { type: "number" }, + width: { type: "number" }, + height: { type: "number" }, + url: { type: "string" }, + full_url: { type: "string" }, + }, + }, + }, + }, + date_added: { type: "string" }, + creator_id: { type: "string" }, + application_id: { type: "string" }, + realname: { type: "string" }, + key: { type: "string" }, + mode: { type: "string" }, + file_size: { type: "number" }, + filename: { type: "string" }, + data: {}, + }, +}; + +const documentSchema = { + type: "object", + properties: { + id: { type: "string" }, + company_id: { type: "string" }, + parent_id: { type: "string" }, + is_in_trash: { type: "boolean" }, + is_directory: { type: "boolean" }, + name: { type: "string" }, + extension: { type: "string" }, + description: { type: "string" }, + tags: { type: "array" }, + added: { type: "string" }, + last_modified: { type: "string" }, + access_info: { + type: "object", + properties: { + public: { + type: "object", + properties: { + token: { type: "string" }, + level: { type: "string" }, + }, + }, + entities: { type: "array" }, + }, + }, + content_keywords: { type: "string" }, + hidden_data: {}, + root_group_folder: { type: "string" }, + creator: { type: "string" }, + size: { type: "number" }, + detached_file: { type: "boolean" }, + has_preview: { type: "boolean" }, + shared: { type: "boolean" }, + url: { type: "string" }, + preview_link: { type: "string" }, + object_link_cache: { type: "string" }, + external_storage: { type: "boolean" }, + last_user: { type: "string" }, + attachements: { type: "array" }, + last_version_cache: fileVersionSchema, + }, +}; + +export const createDocumentSchema = { + body: { + type: "object", + properties: { + item: { type: "object" }, + version: { type: "object" }, + }, + required: ["item", "version"], + }, + response: { + "2xx": documentSchema, + }, +}; + +export const createVersionSchema = { + body: { + type: "object", + }, + response: { + "2xx": fileVersionSchema, + }, +}; diff --git a/twake/backend/node/src/services/files/entities/file.ts b/twake/backend/node/src/services/files/entities/file.ts new file mode 100644 index 00000000..af4541d8 --- /dev/null +++ b/twake/backend/node/src/services/files/entities/file.ts @@ -0,0 +1,90 @@ +import { Type } from "class-transformer"; +import _ from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +@Entity("files", { + primaryKey: [["company_id"], "id"], + type: "files", +}) +export class File { + @Type(() => String) + @Column("company_id", "uuid") + company_id: string; + + @Type(() => String) + @Column("id", "uuid", { generator: "uuid" }) + id: string; + + @Type(() => String) + @Column("user_id", "encoded_string") + user_id: string; + + @Column("application_id", "encoded_string") + application_id: null | string; + + @Column("encryption_key", "encoded_string") + encryption_key: string; + + @Column("updated_at", "number", { onUpsert: _ => new Date().getTime() }) + updated_at: number; + + @Column("created_at", "number", { onUpsert: d => d || new Date().getTime() }) + created_at: number; + + @Column("metadata", "encoded_json") + metadata: null | { + name?: string; + mime?: string; + thumbnails_status?: "done" | "error" | "waiting"; + }; + + @Column("thumbnails", "encoded_json") + thumbnails: Thumbnail[]; + + @Column("upload_data", "encoded_json") + upload_data: null | { + size: number; + chunks: number; + }; + + getPublicObject(): PublicFile { + return _.pick( + this, + "company_id", + "id", + "user_id", + "application_id", + "updated_at", + "created_at", + "metadata", + "thumbnails", + "upload_data", + ); + } +} + +export type PublicFile = Pick< + File, + | "company_id" + | "id" + | "user_id" + | "application_id" + | "updated_at" + | "created_at" + | "metadata" + | "thumbnails" + | "upload_data" +>; + +export type Thumbnail = { + index: number; + id: string; + + type: string; + size: number; + width: number; + height: number; + + url: string; + full_url?: string; +}; diff --git a/twake/backend/node/src/services/files/index.ts b/twake/backend/node/src/services/files/index.ts new file mode 100644 index 00000000..da5bab3d --- /dev/null +++ b/twake/backend/node/src/services/files/index.ts @@ -0,0 +1,23 @@ +import { Prefix, TwakeService } from "../../core/platform/framework"; +import WebServerAPI from "../../core/platform/services/webserver/provider"; +import web from "./web"; + +@Prefix("/internal/services/files/v1") +export default class FilesService extends TwakeService { + version = "1"; + name = "files"; + + public async doInit(): Promise { + const fastify = this.context.getProvider("webserver").getServer(); + fastify.register((instance, _opts, next) => { + web(instance, { prefix: this.prefix }); + next(); + }); + return this; + } + + // TODO: remove + api(): undefined { + return undefined; + } +} diff --git a/twake/backend/node/src/services/files/services/index.ts b/twake/backend/node/src/services/files/services/index.ts new file mode 100644 index 00000000..3cb1c354 --- /dev/null +++ b/twake/backend/node/src/services/files/services/index.ts @@ -0,0 +1,311 @@ +import { randomBytes } from "crypto"; +import { Readable } from "stream"; +import { Multipart } from "fastify-multipart"; +import { UploadOptions } from "../types"; +import { File } from "../entities/file"; +import Repository from "../../../../src/core/platform/services/database/services/orm/repository/repository"; +import { CompanyExecutionContext } from "../web/types"; +import { logger } from "../../../core/platform/framework"; +import { PreviewClearMessageQueueRequest, PreviewMessageQueueRequest } from "../../previews/types"; +import { PreviewFinishedProcessor } from "./preview"; +import _ from "lodash"; +import { getDownloadRoute, getThumbnailRoute } from "../web/routes"; +import { + CrudException, + DeleteResult, + ExecutionContext, +} from "../../../core/platform/framework/api/crud-service"; +import gr from "../../global-resolver"; + +export class FileServiceImpl { + version: "1"; + repository: Repository; + private algorithm = "aes-256-cbc"; + private max_preview_file_size = 50000000; + + async init(): Promise { + try { + await Promise.all([ + (this.repository = await gr.database.getRepository("files", File)), + gr.platformServices.messageQueue.processor.addHandler( + new PreviewFinishedProcessor(this, this.repository), + ), + ]); + } catch (err) { + logger.error("Error while initializing files service", err); + } + return this; + } + + async save( + id: string, + file: Multipart, + options: UploadOptions, + context: CompanyExecutionContext, + ): Promise { + const userId = context.user?.id; + const applicationId: string | null = context.user?.application_id || null; + + let entity: File = null; + if (id) { + entity = await this.repository.findOne( + { + company_id: context.company.id, + id: id, + }, + {}, + context, + ); + if (!entity) { + throw new Error(`This file ${id} does not exist`); + } + } + + if (!entity) { + entity = new File(); + entity.company_id = `${context.company.id}`; + entity.metadata = null; + entity.thumbnails = []; + + const iv = randomBytes(8).toString("hex"); + const secret_key = randomBytes(16).toString("hex"); + entity.encryption_key = `${secret_key}.${iv}`; + + entity.user_id = userId; + entity.application_id = applicationId; + entity.upload_data = null; + + this.repository.save(entity, context); + } + + if (file) { + // Detect a new file upload + // Only applications can overwrite a file. + // Users alone can only write an empty file. + if (applicationId || !entity.upload_data?.size || context.user.server_request) { + if ( + //If there was any change to the file + entity.upload_data?.size !== options.totalSize || + entity.metadata?.name !== options.filename + ) { + entity.metadata = { + name: options.filename, + mime: options.type, + thumbnails_status: "done", + }; + entity.upload_data = { + size: options.totalSize, + chunks: options.totalChunks || 1, + }; + this.repository.save(entity, context); + } + } + + let totalUploadedSize = 0; + file.file.on("data", function (chunk) { + totalUploadedSize += chunk.length; + }); + await gr.platformServices.storage.write(getFilePath(entity), file.file, { + chunkNumber: options.chunkNumber, + encryptionAlgo: this.algorithm, + encryptionKey: entity.encryption_key, + }); + + if (entity.upload_data.chunks === 1 && totalUploadedSize) { + entity.upload_data.size = totalUploadedSize; + await this.repository.save(entity, context); + } + + //Fixme: detect in multichunk when all chunks are uploaded to trigger this. For now we do only single chunks for preview + if (entity.upload_data.chunks === 1 && totalUploadedSize) { + /** Send preview generation task */ + if (entity.upload_data.size < this.max_preview_file_size) { + const document: PreviewMessageQueueRequest["document"] = { + id: JSON.stringify(_.pick(entity, "id", "company_id")), + provider: gr.platformServices.storage.getConnectorType(), + + path: getFilePath(entity), + encryption_algo: this.algorithm, + encryption_key: entity.encryption_key, + chunks: entity.upload_data.chunks, + + filename: entity.metadata.name, + mime: entity.metadata.mime, + }; + const output = { + provider: gr.platformServices.storage.getConnectorType(), + path: `${getFilePath(entity)}/thumbnails/`, + encryption_algo: this.algorithm, + encryption_key: entity.encryption_key, + pages: 10, + }; + + entity.metadata.thumbnails_status = "waiting"; + await this.repository.save(entity, context); + + try { + await gr.platformServices.messageQueue.publish( + "services:preview", + { + data: { document, output }, + }, + ); + + if (options.waitForThumbnail) { + entity = await gr.services.files.getFile( + { + id: entity.id, + company_id: context.company.id, + }, + context, + { waitForThumbnail: true }, + ); + } + } catch (err) { + entity.metadata.thumbnails_status = "error"; + await this.repository.save(entity, context); + + logger.warn({ err }, "Previewing - Error while sending "); + } + } + + /** End preview generation task generation */ + } + } + + return entity; + } + + async exists(id: string, companyId: string, context?: CompanyExecutionContext): Promise { + const entity = await this.getFile({ id, company_id: companyId }, context); + return !!entity; + } + + async download( + id: string, + context: CompanyExecutionContext, + ): Promise<{ file: Readable; name: string; mime: string; size: number }> { + const entity = await this.get(id, context); + if (!entity) { + throw "File not found"; + } + + const readable = await gr.platformServices.storage.read(getFilePath(entity), { + totalChunks: entity.upload_data.chunks, + encryptionAlgo: this.algorithm, + encryptionKey: entity.encryption_key, + }); + + return { + file: readable, + name: entity.metadata.name, + mime: entity.metadata.mime, + size: entity.upload_data.size, + }; + } + + async thumbnail( + id: string, + index: string, + context: CompanyExecutionContext, + ): Promise<{ file: Readable; type: string; size: number }> { + const entity = await this.get(id, context); + + if (!entity) { + throw "File not found"; + } + + const thumbnail = entity.thumbnails[parseInt(index)]; + if (!thumbnail) { + throw `Thumbnail ${parseInt(index)} not found`; + } + + const thumbnailPath = `${getFilePath(entity)}/thumbnails/${thumbnail.id}`; + + const readable = await gr.platformServices.storage.read(thumbnailPath, { + encryptionAlgo: this.algorithm, + encryptionKey: entity.encryption_key, + }); + + return { + file: readable, + type: thumbnail.type, + size: thumbnail.size, + }; + } + + get(id: string, context: CompanyExecutionContext): Promise { + if (!id || !context.company.id) { + return null; + } + return this.getFile({ id, company_id: context.company.id }, context); + } + + async getFile( + pk: Pick, + context?: ExecutionContext, + options?: { + waitForThumbnail?: boolean; + }, + ): Promise { + let entity = await this.repository.findOne(pk, {}, context); + + if (options?.waitForThumbnail) { + for (let i = 1; i < 100; i++) { + if (entity.metadata.thumbnails_status === "done") { + break; + } + await new Promise(r => setTimeout(r, i * 200)); + entity = await this.repository.findOne(pk, {}, context); + } + } + + return entity; + } + + getThumbnailRoute(file: File, index: string) { + return getThumbnailRoute(file, index); + } + + getDownloadRoute(file: File) { + return getDownloadRoute(file); + } + + async delete(id: string, context: CompanyExecutionContext): Promise> { + const fileToDelete = await this.get(id, context); + + if (!fileToDelete) { + throw new CrudException("File not found", 404); + } + + await this.repository.remove(fileToDelete, context); + + const path = getFilePath(fileToDelete); + + await gr.platformServices.storage.remove(path, { + totalChunks: fileToDelete.upload_data.chunks, + }); + + if (fileToDelete.thumbnails.length > 0) { + await gr.platformServices.messageQueue.publish( + "services:preview:clear", + { + data: { + document: { + id: JSON.stringify(_.pick(fileToDelete, "id", "company_id")), + provider: gr.platformServices.storage.getConnectorType(), + path: `${path}/thumbnails/`, + thumbnails_number: fileToDelete.thumbnails.length, + }, + }, + }, + ); + } + + return new DeleteResult("files", fileToDelete, true); + } +} + +function getFilePath(entity: File): string { + return `/twake/files/${entity.company_id}/${entity.user_id || "anonymous"}/${entity.id}`; +} diff --git a/twake/backend/node/src/services/files/services/preview.ts b/twake/backend/node/src/services/files/services/preview.ts new file mode 100644 index 00000000..ec808eae --- /dev/null +++ b/twake/backend/node/src/services/files/services/preview.ts @@ -0,0 +1,67 @@ +import { logger, TwakeContext } from "../../../core/platform/framework"; +import { PreviewMessageQueueCallback } from "../../../../src/services/previews/types"; +import Repository from "../../../../src/core/platform/services/database/services/orm/repository/repository"; +import { File } from "../entities/file"; +import { FileServiceImpl } from "./index"; +import { MessageQueueHandler } from "../../../core/platform/services/message-queue/api"; +import { ExecutionContext } from "../../../core/platform/framework/api/crud-service"; + +/** + * Update the file metadata and upload the thumbnails in storage + */ +export class PreviewFinishedProcessor + implements MessageQueueHandler +{ + constructor(readonly service: FileServiceImpl, private repository: Repository) {} + + async init(_context?: TwakeContext): Promise { + return this; + } + + readonly topics = { + in: "services:preview:callback", + }; + + readonly options = { + unique: true, + ack: true, + }; + + name = "FilePreviewProcessor"; + + validate(message: PreviewMessageQueueCallback): boolean { + return !!(message && message.document && message.thumbnails); + } + + async process(message: PreviewMessageQueueCallback, context?: ExecutionContext): Promise { + logger.info( + `${this.name} - Updating file metadata with preview generation ${message.thumbnails.length}`, + ); + + const pk: { company_id: string; id: string } = JSON.parse(message.document.id); + const entity = await this.repository.findOne(pk, {}, context); + + if (!entity) { + logger.info(`This file ${message.document.id} does not exists anymore.`); + return; + } + + entity.thumbnails = message.thumbnails.map((thumb, index) => { + return { + index, + id: thumb.path.split("/").pop(), + size: thumb.size, + type: thumb.type, + width: thumb.width, + height: thumb.height, + url: `/internal/services/files/v1/companies/${entity.company_id}/files/${entity.id}/thumbnails/${index}`, + }; + }); + + if (!entity.metadata) entity.metadata = {}; + entity.metadata.thumbnails_status = "done"; + + await this.repository.save(entity, context); + return "done"; + } +} diff --git a/twake/backend/node/src/services/files/types.ts b/twake/backend/node/src/services/files/types.ts new file mode 100644 index 00000000..b9190e13 --- /dev/null +++ b/twake/backend/node/src/services/files/types.ts @@ -0,0 +1,8 @@ +export type UploadOptions = { + filename: string; + type: string; + totalSize: number; + totalChunks: number; + chunkNumber: number; + waitForThumbnail: boolean; +}; diff --git a/twake/backend/node/src/services/files/utils.ts b/twake/backend/node/src/services/files/utils.ts new file mode 100644 index 00000000..946c53c6 --- /dev/null +++ b/twake/backend/node/src/services/files/utils.ts @@ -0,0 +1,25 @@ +import { MessageFile } from "../messages/entities/message-files"; +import { File, PublicFile } from "./entities/file"; + +export const formatPublicFile = (file: Partial): PublicFile => { + if ((file as Partial).getPublicObject) file = (file as Partial).getPublicObject(); + return { + ...file, + thumbnails: [ + ...file.thumbnails.map(thumbnail => ({ + ...thumbnail, + full_url: thumbnail.url.match(/https?:\/\//) + ? "/internal/services/files/v1/" + thumbnail.url.replace(/^\//, "") + : thumbnail.url, + })), + ], + } as PublicFile; +}; + +export const fileIsMedia = (file: Partial): boolean => { + return ( + file.metadata?.mime?.startsWith("video/") || + file.metadata?.mime?.startsWith("audio/") || + file.metadata?.mime?.startsWith("image/") + ); +}; diff --git a/twake/backend/node/src/services/files/web/controllers/files.ts b/twake/backend/node/src/services/files/web/controllers/files.ts new file mode 100644 index 00000000..35a20242 --- /dev/null +++ b/twake/backend/node/src/services/files/web/controllers/files.ts @@ -0,0 +1,113 @@ +import { FastifyReply, FastifyRequest } from "fastify"; +import { Multipart } from "fastify-multipart"; +import { ResourceDeleteResponse } from "../../../../utils/types"; +import { CompanyExecutionContext } from "../types"; +import { UploadOptions } from "../../types"; +import { PublicFile } from "../../entities/file"; +import gr from "../../../global-resolver"; + +export class FileController { + async save( + request: FastifyRequest<{ + Params: { company_id: string; id: string }; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + Querystring: any; + }>, + ): Promise<{ resource: PublicFile }> { + const context = getCompanyExecutionContext(request); + + let file: null | Multipart = null; + if (request.isMultipart()) { + file = await request.file(); + } + const q = request.query; + const options: UploadOptions = { + totalChunks: parseInt(q.resumableTotalChunks || q.total_chunks) || 1, + totalSize: parseInt(q.resumableTotalSize || q.total_size) || 0, + chunkNumber: parseInt(q.resumableChunkNumber || q.chunk_number) || 1, + filename: q.resumableFilename || q.filename || file?.filename || undefined, + type: q.resumableType || q.type || file?.mimetype || undefined, + waitForThumbnail: q.thumbnail_sync, + }; + + const id = request.params.id; + const result = await gr.services.files.save(id, file, options, context); + + return { + resource: result.getPublicObject(), + }; + } + + async download( + request: FastifyRequest<{ Params: { company_id: string; id: string } }>, + response: FastifyReply, + ): Promise { + const context = getCompanyExecutionContext(request); + const params = request.params; + const data = await gr.services.files.download(params.id, context); + const filename = data.name.replace(/[^a-zA-Z0-9 -_.]/g, ""); + + response.header("Content-disposition", `attachment; filename="${filename}"`); + if (data.size) response.header("Content-Length", data.size); + response.type(data.mime); + response.send(data.file); + } + + async thumbnail( + request: FastifyRequest<{ Params: { company_id: string; id: string; index: string } }>, + response: FastifyReply, + ): Promise { + const context = getCompanyExecutionContext(request); + const params = request.params; + try { + const data = await gr.services.files.thumbnail(params.id, params.index, context); + + response.header("Content-disposition", "inline"); + response.expires(new Date(new Date().getTime() + 1000 * 60 * 60 * 24 * 365)); + if (data.size) response.header("Content-Length", data.size); + response.type(data.type); + response.send(data.file); + } catch (err) { + console.log(err); + response.statusCode = 500; + response.send(""); + } + } + + async get( + request: FastifyRequest<{ Params: { company_id: string; id: string } }>, + ): Promise<{ resource: PublicFile }> { + const context = getCompanyExecutionContext(request); + const params = request.params; + const resource = await gr.services.files.get(params.id, context); + + return { resource: resource.getPublicObject() }; + } + + async delete( + request: FastifyRequest<{ Params: { company_id: string; id: string } }>, + ): Promise { + const params = request.params; + const context = getCompanyExecutionContext(request); + + const deleteResult = await gr.services.files.delete(params.id, context); + + return { status: deleteResult.deleted ? "success" : "error" }; + } +} + +function getCompanyExecutionContext( + request: FastifyRequest<{ + Params: { company_id: string }; + }>, +): CompanyExecutionContext { + return { + user: request.currentUser, + + company: { id: request.params.company_id }, + url: request.url, + method: request.routerMethod, + reqId: request.id, + transport: "http", + }; +} diff --git a/twake/backend/node/src/services/files/web/controllers/index.ts b/twake/backend/node/src/services/files/web/controllers/index.ts new file mode 100644 index 00000000..b2cba4b6 --- /dev/null +++ b/twake/backend/node/src/services/files/web/controllers/index.ts @@ -0,0 +1 @@ +export * from "./files"; diff --git a/twake/backend/node/src/services/files/web/index.ts b/twake/backend/node/src/services/files/web/index.ts new file mode 100644 index 00000000..cc806d3d --- /dev/null +++ b/twake/backend/node/src/services/files/web/index.ts @@ -0,0 +1,12 @@ +import { FastifyInstance, FastifyRegisterOptions } from "fastify"; +import fastifyCaching from "@fastify/caching"; +import routes from "./routes"; + +export default ( + fastify: FastifyInstance, + options: FastifyRegisterOptions<{ prefix: string }>, +): void => { + fastify.log.debug("Configuring /internal/services/files/v1 routes"); + fastify.register(fastifyCaching, { expiresIn: 31536000, privacy: fastifyCaching.privacy.PUBLIC }); + fastify.register(routes, options); +}; diff --git a/twake/backend/node/src/services/files/web/routes.ts b/twake/backend/node/src/services/files/web/routes.ts new file mode 100644 index 00000000..a9e04428 --- /dev/null +++ b/twake/backend/node/src/services/files/web/routes.ts @@ -0,0 +1,61 @@ +import { FastifyInstance, FastifyPluginCallback } from "fastify"; +import { FileController } from "./controllers"; +import { File } from "../entities/file"; + +const filesUrl = "/companies/:company_id/files"; + +const routes: FastifyPluginCallback = (fastify: FastifyInstance, options, next) => { + const fileController = new FileController(); + + fastify.route({ + method: "POST", + url: filesUrl, + preValidation: [fastify.authenticate], + handler: fileController.save.bind(fileController), + }); + + fastify.route({ + method: "POST", + url: `${filesUrl}/:id`, + preValidation: [fastify.authenticate], + handler: fileController.save.bind(fileController), + }); + + fastify.route({ + method: "GET", + url: `${filesUrl}/:id/download`, + handler: fileController.download.bind(fileController), + }); + + fastify.route({ + method: "GET", + url: `${filesUrl}/:id`, + preValidation: [fastify.authenticate], + handler: fileController.get.bind(fileController), + }); + + fastify.route({ + method: "GET", + url: `${filesUrl}/:id/thumbnails/:index`, + handler: fileController.thumbnail.bind(fileController), + }); + + fastify.route({ + method: "DELETE", + url: `${filesUrl}/:id`, + preValidation: [fastify.authenticate], + handler: fileController.delete.bind(fileController), + }); + + next(); +}; + +export const getDownloadRoute = (file: File) => { + return filesUrl.replace(":company_id", file.company_id) + `/${file.id}/download`; +}; + +export const getThumbnailRoute = (file: File, index: string) => { + return `/internal/services/files/v1/companies/${file.company_id}/files/${file.id}/thumbnails/${index}`; +}; + +export default routes; diff --git a/twake/backend/node/src/services/files/web/schemas.ts b/twake/backend/node/src/services/files/web/schemas.ts new file mode 100644 index 00000000..52e7cc47 --- /dev/null +++ b/twake/backend/node/src/services/files/web/schemas.ts @@ -0,0 +1,13 @@ +export const filesSchema = { + type: "object", + properties: { + preferences: { + type: "object", + }, + id: { type: "string" }, + name: { type: "string" }, + size: { type: "number" }, + width: { type: "number" }, + height: { type: "number" }, + }, +}; diff --git a/twake/backend/node/src/services/files/web/types.ts b/twake/backend/node/src/services/files/web/types.ts new file mode 100644 index 00000000..d340c9c5 --- /dev/null +++ b/twake/backend/node/src/services/files/web/types.ts @@ -0,0 +1,5 @@ +import { ExecutionContext } from "../../../core/platform/framework/api/crud-service"; + +export interface CompanyExecutionContext extends ExecutionContext { + company: { id: string }; +} diff --git a/twake/backend/node/src/services/general/api.ts b/twake/backend/node/src/services/general/api.ts new file mode 100644 index 00000000..00fc56fc --- /dev/null +++ b/twake/backend/node/src/services/general/api.ts @@ -0,0 +1,3 @@ +import { Initializable, TwakeServiceProvider } from "../../core/platform/framework/api"; + +export interface GeneralServiceAPI extends TwakeServiceProvider, Initializable {} diff --git a/twake/backend/node/src/services/general/index.ts b/twake/backend/node/src/services/general/index.ts new file mode 100644 index 00000000..e0396478 --- /dev/null +++ b/twake/backend/node/src/services/general/index.ts @@ -0,0 +1,30 @@ +import WebServerAPI from "../../core/platform/services/webserver/provider"; +import { Consumes, Prefix, TwakeService } from "../../core/platform/framework"; +import { GeneralServiceAPI } from "./api"; +import web from "./web/index"; +import { ServerConfiguration } from "./types"; + +@Prefix("/internal/services/general/v1") +@Consumes(["webserver"]) +export default class GeneralService extends TwakeService { + version = "1"; + name = "general"; + service: GeneralServiceAPI; + + api(): GeneralServiceAPI { + return this.service; + } + + public async doInit(): Promise { + const fastify = this.context.getProvider("webserver").getServer(); + + const configuration = this.configuration.get(); + + fastify.register((instance, _opts, next) => { + web(instance, { prefix: this.prefix, configuration: configuration }); + next(); + }); + + return this; + } +} diff --git a/twake/backend/node/src/services/general/languages.ts b/twake/backend/node/src/services/general/languages.ts new file mode 100644 index 00000000..491aa803 --- /dev/null +++ b/twake/backend/node/src/services/general/languages.ts @@ -0,0 +1,6 @@ +import { Languages } from "./types"; + +export const languages: Languages = { + default: "en", + availables: ["en", "fr", "es", "vn", "ru"], +}; diff --git a/twake/backend/node/src/services/general/types.ts b/twake/backend/node/src/services/general/types.ts new file mode 100644 index 00000000..67e96865 --- /dev/null +++ b/twake/backend/node/src/services/general/types.ts @@ -0,0 +1,40 @@ +export type Languages = { + default: string; + availables: string[]; +}; + +export type ServerConfiguration = { + status: "ready"; + version: { + current: string; + minimal: { + web: string; + mobile: string; + }; + }; + configuration: { + help_url: string | null; + pricing_plan_url: string | null; + app_download_url: string | null; + mobile: { + mobile_redirect: string; + mobile_appstore: string; + mobile_googleplay: string; + }; + accounts: { + type: "console" | "internal"; + console: null | { + authority: string; + client_id: string; + account_management_url: string; + company_management_url: string; + company_subscription_url: string; + collaborators_management_url: string; + }; + internal: null | { + disable_account_creation: boolean; + disable_email_verification: boolean; + }; + }; + }; +}; diff --git a/twake/backend/node/src/services/general/web/index.ts b/twake/backend/node/src/services/general/web/index.ts new file mode 100644 index 00000000..a78077fd --- /dev/null +++ b/twake/backend/node/src/services/general/web/index.ts @@ -0,0 +1,14 @@ +import { FastifyInstance, FastifyRegisterOptions } from "fastify"; +import { ServerConfiguration } from "../types"; +import routes from "./routes"; + +export default ( + fastify: FastifyInstance, + options: FastifyRegisterOptions<{ + prefix: string; + configuration: ServerConfiguration["configuration"]; + }>, +): void => { + fastify.log.debug("Configuring /internal/services/general/v1 routes"); + fastify.register(routes, options); +}; diff --git a/twake/backend/node/src/services/general/web/routes.ts b/twake/backend/node/src/services/general/web/routes.ts new file mode 100644 index 00000000..76fbd45b --- /dev/null +++ b/twake/backend/node/src/services/general/web/routes.ts @@ -0,0 +1,69 @@ +import { FastifyInstance, FastifyPluginCallback } from "fastify"; +import _ from "lodash"; +import { languages } from "../languages"; +import { Languages, ServerConfiguration } from "../types"; +import version from "../../../version"; + +const routes: FastifyPluginCallback<{ configuration: ServerConfiguration["configuration"] }> = ( + fastify: FastifyInstance, + options, + next, +) => { + fastify.route({ + method: "GET", + url: "/server", + handler: async (): Promise => { + const accounts = options.configuration.accounts; + return { + status: "ready", + version: version, + configuration: { + ..._.pick( + options.configuration, + "help_url", + "pricing_plan_url", + "mobile", + "app_download_url", + ), + accounts: { + type: accounts.type, + console: _.pick( + accounts.console, + "authority", + "client_id", + "account_management_url", + "company_subscription_url", + "company_management_url", + "collaborators_management_url", + ), + internal: _.pick( + accounts.internal, + "disable_account_creation", + "disable_email_verification", + ), + }, + }, + }; + }, + }); + + fastify.route({ + method: "GET", + url: "/locales", + handler: async (): Promise => { + return languages; + }, + }); + + fastify.route({ + method: "GET", + url: "/locales/:language", + handler: async (): Promise => { + return {}; + }, + }); + + next(); +}; + +export default routes; diff --git a/twake/backend/node/src/services/global-resolver.ts b/twake/backend/node/src/services/global-resolver.ts new file mode 100644 index 00000000..4d477f62 --- /dev/null +++ b/twake/backend/node/src/services/global-resolver.ts @@ -0,0 +1,229 @@ +import { FastifyInstance } from "fastify"; +import { IncomingMessage, Server, ServerResponse } from "http"; + +import { TwakePlatform } from "../core/platform/platform"; +import { RealtimeServiceAPI } from "../core/platform/services/realtime/api"; +import WebServerAPI from "../core/platform/services/webserver/provider"; +import { SearchServiceAPI } from "../core/platform/services/search/api"; +import StorageAPI from "../core/platform/services/storage/provider"; +import { MessageQueueServiceAPI } from "../core/platform/services/message-queue/api"; +import { CounterAPI } from "../core/platform/services/counter/types"; +import { DatabaseServiceAPI } from "../core/platform/services/database/api"; +import AuthServiceAPI from "../core/platform/services/auth/provider"; +import { PushServiceAPI } from "../core/platform/services/push/api"; +import { CronAPI } from "../core/platform/services/cron/api"; +import WebSocketAPI from "../core/platform/services/websocket/provider"; +import TrackerAPI from "../core/platform/services/tracker/provider"; +import KnowledgeGraphService from "../core/platform/services/knowledge-graph"; +import EmailPusherAPI from "../core/platform/services/email-pusher/provider"; + +import { logger } from "../core/platform/framework"; +import assert from "assert"; +import { CompanyServiceImpl } from "./user/services/companies"; +import { WorkspaceServiceImpl } from "./workspaces/services/workspace"; +import { UserExternalLinksServiceImpl } from "./user/services/external_links"; +import { UserNotificationBadgeService } from "./notifications/services/bages"; +import { NotificationPreferencesService } from "./notifications/services/preferences"; +import { ThreadMessagesService } from "./messages/services/messages"; +import { MessagesFilesService } from "./messages/services/messages-files"; +import { ThreadsService } from "./messages/services/threads"; +import { UserBookmarksService } from "./messages/services/user-bookmarks"; +import { UserServiceImpl } from "./user/services/users/service"; +import { CompanyApplicationServiceImpl } from "./applications/services/company-applications"; +import { ApplicationServiceImpl } from "./applications/services/applications"; +import { ViewsServiceImpl } from "./messages/services/views"; +import { MessagesEngine } from "./messages/services/engine"; +import { FileServiceImpl } from "./files/services"; +import { ChannelServiceImpl } from "./channels/services/channel/service"; +import { MemberServiceImpl } from "./channels/services/member/service"; +import ChannelPendingEmailServiceImpl from "./channels/services/channel/pending-emails/service"; +import { TabServiceImpl } from "./channels/services/tab"; +import { ConsoleServiceImpl } from "./console/service"; +import { StatisticsServiceImpl } from "./statistics/service"; +import { NotificationEngine } from "./notifications/services/engine"; +import { MobilePushService } from "./notifications/services/mobile-push"; +import { ChannelMemberPreferencesServiceImpl } from "./notifications/services/channel-preferences"; +import { ChannelThreadUsersServiceImpl } from "./notifications/services/channel-thread-users"; +import { PreviewProcessService } from "./previews/services/files/processing/service"; +import { ApplicationHooksService } from "./applications/services/hooks"; +import OnlineServiceImpl from "./online/service"; +import { PreviewEngine } from "./previews/services/files/engine"; +import { ChannelsMessageQueueListener } from "./channels/services/pubsub"; +import { LinkPreviewProcessService } from "./previews/services/links/processing/service"; +import { LinkPreviewEngine } from "./previews/services/links/engine"; +import { UserNotificationDigestService } from "./notifications/services/digest"; +import { DocumentsService } from "./documents/services"; +import { DocumentsEngine } from "./documents/services/engine"; +import { TagsService } from "./tags/services/tags"; + +type PlatformServices = { + auth: AuthServiceAPI; + counter: CounterAPI; + cron: CronAPI; + messageQueue: MessageQueueServiceAPI; + push: PushServiceAPI; + realtime: RealtimeServiceAPI; + search: SearchServiceAPI; + storage: StorageAPI; + tracker: TrackerAPI; + webserver: WebServerAPI; + websocket: WebSocketAPI; + knowledgeGraph: KnowledgeGraphService; + emailPusher: EmailPusherAPI; +}; + +type TwakeServices = { + workspaces: WorkspaceServiceImpl; + companies: CompanyServiceImpl; + users: UserServiceImpl; + console: ConsoleServiceImpl; + statistics: StatisticsServiceImpl; + externalUser: UserExternalLinksServiceImpl; + notifications: { + badges: UserNotificationBadgeService; + channelPreferences: ChannelMemberPreferencesServiceImpl; + channelThreads: ChannelThreadUsersServiceImpl; + engine: NotificationEngine; + preferences: NotificationPreferencesService; + mobilePush: MobilePushService; + digest: UserNotificationDigestService; + }; + preview: { + files: PreviewProcessService; + links: LinkPreviewProcessService; + }; + messages: { + messages: ThreadMessagesService; + messagesFiles: MessagesFilesService; + threads: ThreadsService; + userBookmarks: UserBookmarksService; + views: ViewsServiceImpl; + engine: MessagesEngine; + }; + applications: { + marketplaceApps: ApplicationServiceImpl; + companyApps: CompanyApplicationServiceImpl; + hooks: ApplicationHooksService; + }; + files: FileServiceImpl; + channels: { + channels: ChannelServiceImpl; + members: MemberServiceImpl; + pubsub: ChannelsMessageQueueListener; + }; + channelPendingEmail: ChannelPendingEmailServiceImpl; + tab: TabServiceImpl; + online: OnlineServiceImpl; + documents: { + documents: DocumentsService; + engine: DocumentsEngine; + }; + tags: TagsService; +}; + +class GlobalResolver { + public services: TwakeServices; + public platformServices: PlatformServices; + public database: DatabaseServiceAPI; + + public fastify: FastifyInstance; + + private alreadyInitialized = false; + + async doInit(platform: TwakePlatform) { + if (this.alreadyInitialized) { + return; + } + this.database = platform.getProvider("database"); + + this.platformServices = { + auth: platform.getProvider("auth"), + counter: platform.getProvider("counter"), + cron: platform.getProvider("cron"), + messageQueue: platform.getProvider("message-queue"), + push: platform.getProvider("push"), + realtime: platform.getProvider("realtime"), + search: platform.getProvider("search"), + storage: platform.getProvider("storage"), + tracker: platform.getProvider("tracker"), + webserver: platform.getProvider("webserver"), + websocket: platform.getProvider("websocket"), + knowledgeGraph: await new KnowledgeGraphService().init(), + emailPusher: platform.getProvider("email-pusher"), + }; + + this.fastify = this.platformServices.webserver.getServer(); + + Object.keys(this.platformServices).forEach((key: keyof PlatformServices) => { + const service = this.platformServices[key]; + assert(service, `Platform service ${key} was not initialized`); + }); + + await new PreviewEngine().init(); + await new LinkPreviewEngine().init(); + + this.services = { + workspaces: await new WorkspaceServiceImpl().init(), + companies: await new CompanyServiceImpl().init(), + users: await new UserServiceImpl().init(), + console: await new ConsoleServiceImpl().init(), + statistics: await new StatisticsServiceImpl().init(), + externalUser: await new UserExternalLinksServiceImpl().init(), + notifications: { + badges: await new UserNotificationBadgeService().init(platform), + channelPreferences: await new ChannelMemberPreferencesServiceImpl().init(), + channelThreads: await new ChannelThreadUsersServiceImpl().init(), + engine: await new NotificationEngine().init(), + preferences: await new NotificationPreferencesService().init(), + mobilePush: await new MobilePushService().init(), + digest: await new UserNotificationDigestService().init(), + }, + preview: { + files: await new PreviewProcessService().init(), + links: await new LinkPreviewProcessService().init(), + }, + messages: { + messages: await new ThreadMessagesService().init(platform), + messagesFiles: await new MessagesFilesService().init(), + threads: await new ThreadsService().init(), + userBookmarks: await new UserBookmarksService().init(), + views: await new ViewsServiceImpl().init(), + engine: await new MessagesEngine().init(), + }, + applications: { + marketplaceApps: await new ApplicationServiceImpl().init(), + companyApps: await new CompanyApplicationServiceImpl().init(), + hooks: await new ApplicationHooksService().init(), + }, + files: await new FileServiceImpl().init(), + channels: { + channels: await new ChannelServiceImpl().init(), + members: await new MemberServiceImpl().init(), + pubsub: await new ChannelsMessageQueueListener().init(), + }, + channelPendingEmail: await new ChannelPendingEmailServiceImpl().init(), + tab: await new TabServiceImpl().init(), + online: await new OnlineServiceImpl().init(), + documents: { + documents: await new DocumentsService().init(), + engine: await new DocumentsEngine().init(), + }, + tags: await new TagsService().init(), + }; + + Object.keys(this.services).forEach((key: keyof TwakeServices) => { + assert(this.services[key], `Service ${key} was not initialized`); + if (this.services[key].constructor.name == "Object") { + const subs = this.services[key] as any; + Object.keys(subs).forEach(sk => { + assert(subs[sk], `Service ${key}.${sk} was not initialized`); + }); + } + }); + + logger.info("Global resolver finished initializing services"); + this.alreadyInitialized = true; + } +} + +export default new GlobalResolver(); diff --git a/twake/backend/node/src/services/knowledge-graph-web/index.ts b/twake/backend/node/src/services/knowledge-graph-web/index.ts new file mode 100644 index 00000000..6a6d601b --- /dev/null +++ b/twake/backend/node/src/services/knowledge-graph-web/index.ts @@ -0,0 +1,25 @@ +import { Consumes, Prefix, TwakeService } from "../../core/platform/framework"; +import WebServerAPI from "../../core/platform/services/webserver/provider"; +import web from "./web/index"; + +@Prefix("/internal/services/knowledge-graph/v1") +@Consumes(["webserver"]) +export default class MessageService extends TwakeService { + version = "1"; + name = "knowledge-graph"; + + api(): undefined { + return undefined; + } + + public async doInit(): Promise { + const fastify = this.context.getProvider("webserver").getServer(); + + fastify.register((instance, _opts, next) => { + web(instance, { prefix: this.prefix }); + next(); + }); + + return this; + } +} diff --git a/twake/backend/node/src/services/knowledge-graph-web/web/index.ts b/twake/backend/node/src/services/knowledge-graph-web/web/index.ts new file mode 100644 index 00000000..60f69e05 --- /dev/null +++ b/twake/backend/node/src/services/knowledge-graph-web/web/index.ts @@ -0,0 +1,12 @@ +import { FastifyInstance, FastifyRegisterOptions } from "fastify"; +import routes from "./routes"; + +export default ( + fastify: FastifyInstance, + options: FastifyRegisterOptions<{ + prefix: string; + }>, +): void => { + fastify.log.debug("Configuring /internal/services/knowledge-graph/v1 routes"); + fastify.register(routes, options); +}; diff --git a/twake/backend/node/src/services/knowledge-graph-web/web/routes.ts b/twake/backend/node/src/services/knowledge-graph-web/web/routes.ts new file mode 100644 index 00000000..53b27bdd --- /dev/null +++ b/twake/backend/node/src/services/knowledge-graph-web/web/routes.ts @@ -0,0 +1,41 @@ +import { FastifyInstance, FastifyPluginCallback, FastifyReply, FastifyRequest } from "fastify"; +import { KnowledgeGraphCallbackEvent } from "../../../core/platform/services/knowledge-graph/types"; +import gr from "../../global-resolver"; + +const routes: FastifyPluginCallback = (fastify: FastifyInstance, _, next) => { + fastify.route({ + method: "POST", + url: "/push", + handler: async ( + request: FastifyRequest<{ + Body: { + events: KnowledgeGraphCallbackEvent[]; + }; + }>, + reply: FastifyReply, + ): Promise => { + try { + for (let i = 0; i < request.body.events.length; i++) { + await gr.platformServices.knowledgeGraph.onCallbackEvent( + request.headers.authorization.split(" ")[1], + request.body.events[i], + ); + } + } catch (e) { + reply.status(500).send({ + status: "error", + error: "Internal server error", + message: e.message || "Unknown error", + }); + } + + reply.status(200).send({ + status: "success", + }); + }, + }); + + next(); +}; + +export default routes; diff --git a/twake/backend/node/src/services/messages/blocks-types.ts b/twake/backend/node/src/services/messages/blocks-types.ts new file mode 100644 index 00000000..19b848ed --- /dev/null +++ b/twake/backend/node/src/services/messages/blocks-types.ts @@ -0,0 +1,208 @@ +import { MessageFileMetadata } from "./entities/message-files"; + +/* Blocks objects */ + +export type Block = { block_id?: string } & ( + | BlockFile + | BlockActions + | BlockContext + | BlockHeader + | BlockDivider + | BlockImage + | BlockInput + | BlockSection + | BlockIframe + | BlockTwacode +); + +export type BlockTwacode = { + type: "twacode"; + elements: any; +}; + +export type BlockActions = { + type: "actions"; + elements: BlockElement[]; +}; + +export type BlockContext = { + type: "context"; + elements: (BlockElementImage | CompositionTextObject | BlockElementProgressBar)[]; +}; + +export type BlockHeader = { + type: "header"; + text: CompositionPlainTextObject; +}; + +export type BlockDivider = { + type: "divider"; +}; + +export type BlockFile = { + type: "file"; + external_id: string; + source: string; + metadata?: MessageFileMetadata; +}; + +export type BlockImage = BlockElementImage & { + title?: CompositionPlainTextObject; +}; + +export type BlockInput = { + type: "input"; + label: string; + element: BlockElement; + dispatch_action?: boolean; + hint?: CompositionPlainTextObject; + optional?: boolean; +}; + +export type BlockSection = { + type: "section"; + text?: CompositionTextObject; + fields?: CompositionTextObject[]; + accessory?: BlockElement; +}; + +export type BlockIframe = { + type: "iframe"; + iframe_url: string; + width: number; + height: number; +}; + +/* Elements objects */ + +export type BlockElement = + | BlockElementImage + | BlockElementProgressBar + | BlockElementButton + | BlockElementCheckboxes + | BlockElementDatePicker + | BlockElementMultiselectMenu + | BlockElementPlaintextInput + | BlockElementRadioButtonInput + | BlockElementSelectMenus + | BlockElementOverflowMenus + | BlockElementTimePicker; + +export type BlockElementImage = { + type: "image"; + image_url: string; + alt_text: string; + title?: any; + metadata?: MessageFileMetadata; +}; + +export type BlockElementProgressBar = { + type: "progress_bar"; + value: number; //Between 0 and 100 + title: string; +}; + +export type BlockElementButton = { + type: "button"; + text: CompositionPlainTextObject; + action_id: string; + url?: string; + value?: string; + style?: "primary" | "danger" | "default"; + confirm?: CompositionConfirmationDialog; +}; + +export type BlockElementCheckboxes = { + type: "checkboxes"; + action_id: string; + options: CompositionOption[]; + initial_options?: CompositionOption[]; + confirm?: CompositionConfirmationDialog; +}; + +type BlockElementPlaintextInput = { + type: "plain_text_input"; + action_id: string; + placeholder?: CompositionPlainTextObject; + initial_value?: string; + multiline?: boolean; + min_length?: number; + max_length?: number; + dispatch_action_config?: DispatchActionConfiguration; + readonly?: boolean; + copiable?: boolean; +}; + +export type BlockElementRadioButtonInput = { + type: "radio_buttons"; + action_id: string; + options: CompositionOption[]; + initial_option?: CompositionOption; + confirm?: CompositionConfirmationDialog; +}; + +export type BlockElementDatePicker = { + type: "datepicker"; + action_id: string; + placeholder?: CompositionPlainTextObject; + initial_date?: string; + confirm?: CompositionConfirmationDialog; +}; + +export type BlockElementTimePicker = { + type: "timepicker"; + action_id: string; + placeholder?: CompositionPlainTextObject; + initial_time?: string; + confirm?: CompositionConfirmationDialog; +}; + +export type BlockElementOverflowMenus = { + type: "overflow"; + action_id: string; + options: CompositionOption[]; + confirm?: CompositionConfirmationDialog; +}; + +export type BlockElementSelectMenus = { + type: ""; +}; //TODO + +export type BlockElementMultiselectMenu = { + type: any; +}; //TODO + +/* Composition objects */ + +type CompositionTextObject = CompositionPlainTextObject | CompositionMarkdownTextObject; + +type CompositionPlainTextObject = { + type: "plain_text"; + text: string; + emoji?: boolean; + verbatim?: boolean; +}; + +type CompositionMarkdownTextObject = { + type: "mrkdwn"; + text: string; +}; + +type CompositionConfirmationDialog = { + title: CompositionPlainTextObject; + text: CompositionMarkdownTextObject; + confirm: CompositionPlainTextObject; + deny: CompositionPlainTextObject; + style: "confirm" | "danger" | "default"; +}; + +type CompositionOption = { + text: CompositionPlainTextObject; + value: string; + description?: CompositionPlainTextObject; + url?: string; +}; + +type DispatchActionConfiguration = { + trigger_actions_on: ("on_enter_pressed" | "on_character_entered")[]; +}; diff --git a/twake/backend/node/src/services/messages/entities/message-channel-marked-refs.ts b/twake/backend/node/src/services/messages/entities/message-channel-marked-refs.ts new file mode 100644 index 00000000..42dba32d --- /dev/null +++ b/twake/backend/node/src/services/messages/entities/message-channel-marked-refs.ts @@ -0,0 +1,51 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "message_channel_marked_refs"; +@Entity(TYPE, { + primaryKey: [["company_id", "workspace_id"], "type", "channel_id", "thread_id", "message_id"], + type: TYPE, +}) +export class MessageChannelMarkedRef { + @Type(() => String) + @Column("company_id", "uuid") + company_id: string; + + @Type(() => String) + @Column("workspace_id", "string") + workspace_id: string; + + @Type(() => String) + @Column("channel_id", "string") + channel_id: string; + + @Type(() => String) + @Column("type", "string") + type: "pinned"; + + @Type(() => String) + @Column("thread_id", "timeuuid", { order: "DESC" }) + thread_id: string; + + @Type(() => String) + @Column("message_id", "timeuuid", { order: "DESC" }) + message_id: string; + + @Type(() => Number) + @Column("created_at", "number") + created_at: number; + + @Type(() => String) + @Column("created_by", "string") + created_by: string; +} + +export type MessageChannelMarkedRefPrimaryKey = Pick< + MessageChannelMarkedRef, + "company_id" | "workspace_id" | "type" | "channel_id" | "thread_id" | "message_id" +>; + +export function getInstance(ref: MessageChannelMarkedRef): MessageChannelMarkedRef { + return merge(new MessageChannelMarkedRef(), ref); +} diff --git a/twake/backend/node/src/services/messages/entities/message-channel-refs-reversed.ts b/twake/backend/node/src/services/messages/entities/message-channel-refs-reversed.ts new file mode 100644 index 00000000..b54d10dc --- /dev/null +++ b/twake/backend/node/src/services/messages/entities/message-channel-refs-reversed.ts @@ -0,0 +1,39 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "message_channel_refs_reversed"; +@Entity(TYPE, { + primaryKey: [["company_id", "workspace_id"], "channel_id", "thread_id"], + type: TYPE, +}) +export class MessageChannelRefReversed { + @Type(() => String) + @Column("company_id", "uuid") + company_id: string; + + @Type(() => String) + @Column("workspace_id", "string") + workspace_id: string; + + @Type(() => String) + @Column("channel_id", "string") + channel_id: string; + + @Type(() => String) + @Column("thread_id", "timeuuid", { order: "DESC" }) + thread_id: string; + + @Type(() => String) + @Column("message_id", "timeuuid") + message_id: string; +} + +export type MessageChannelRefReversedPrimaryKey = Pick< + MessageChannelRefReversed, + "company_id" | "workspace_id" | "channel_id" | "thread_id" +>; + +export function getInstance(ref: MessageChannelRefReversed): MessageChannelRefReversed { + return merge(new MessageChannelRefReversed(), ref); +} diff --git a/twake/backend/node/src/services/messages/entities/message-channel-refs.ts b/twake/backend/node/src/services/messages/entities/message-channel-refs.ts new file mode 100644 index 00000000..de8d06c1 --- /dev/null +++ b/twake/backend/node/src/services/messages/entities/message-channel-refs.ts @@ -0,0 +1,39 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "message_channel_refs"; +@Entity(TYPE, { + primaryKey: [["company_id", "workspace_id"], "channel_id", "message_id"], + type: TYPE, +}) +export class MessageChannelRef { + @Type(() => String) + @Column("company_id", "uuid") + company_id: string; + + @Type(() => String) + @Column("workspace_id", "string") + workspace_id: string; + + @Type(() => String) + @Column("channel_id", "string") + channel_id: string; + + @Type(() => String) + @Column("message_id", "timeuuid", { order: "DESC" }) + message_id: string; + + @Type(() => String) + @Column("thread_id", "timeuuid") + thread_id: string; +} + +export type MessageChannelRefPrimaryKey = Pick< + MessageChannelRef, + "company_id" | "workspace_id" | "channel_id" | "message_id" +>; + +export function getInstance(ref: MessageChannelRef): MessageChannelRef { + return merge(new MessageChannelRef(), ref); +} diff --git a/twake/backend/node/src/services/messages/entities/message-file-refs.ts b/twake/backend/node/src/services/messages/entities/message-file-refs.ts new file mode 100644 index 00000000..07bed537 --- /dev/null +++ b/twake/backend/node/src/services/messages/entities/message-file-refs.ts @@ -0,0 +1,59 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "message_file_refs"; +@Entity(TYPE, { + primaryKey: [["target_type", "company_id", "target_id"], "id"], + type: TYPE, +}) +export class MessageFileRef { + @Type(() => String) + @Column("target_type", "string") + target_type: "channel" | "channel_media" | "channel_file" | "user_upload" | "user_download"; + + @Type(() => String) + @Column("target_id", "string") + target_id: string; + + @Type(() => String) + @Column("id", "timeuuid", { generator: "timeuuid", order: "DESC" }) + id: string; + + @Type(() => Number) + @Column("created_at", "number") + created_at: number; + + @Type(() => String) + @Column("workspace_id", "string") + workspace_id: string; + + @Type(() => String) + @Column("channel_id", "string") + channel_id: string; + + @Type(() => String) + @Column("thread_id", "timeuuid") + thread_id: string; + + @Type(() => String) + @Column("message_id", "timeuuid") + message_id: string; + + @Type(() => String) + @Column("message_file_id", "string") + message_file_id: string; + + @Type(() => String) + @Column("file_id", "json") + file_id: string; + + @Column("company_id", "timeuuid") + company_id: string; +} + +export type MessageFileRefPrimaryKey = Pick; + +export function getInstance(ref: MessageFileRef): MessageFileRef { + return merge(new MessageFileRef(), ref); +} diff --git a/twake/backend/node/src/services/messages/entities/message-files.search.ts b/twake/backend/node/src/services/messages/entities/message-files.search.ts new file mode 100644 index 00000000..16c9a4fc --- /dev/null +++ b/twake/backend/node/src/services/messages/entities/message-files.search.ts @@ -0,0 +1,54 @@ +import _ from "lodash"; +import { fileIsMedia } from "../../../services/files/utils"; +import { MessageFile } from "./message-files"; + +export const expandFileNameForSearch = (name: string) => { + return name + " " + _.snakeCase(name).replace(/[^a-zA-Z0-9]/gm, " "); +}; + +export default { + index: "message_files", + source: (entity: MessageFile) => { + const isMedia = fileIsMedia(entity); + + const source = { + name: expandFileNameForSearch(entity.metadata?.name || ""), + size: entity.metadata?.size || "", + source: entity.metadata?.source || "", + extension: (entity.metadata?.name || "").split(".").pop() || "", + is_media: isMedia, + is_file: !isMedia, + created_at: entity.created_at, + + cache_company_id: entity.cache?.company_id, + cache_workspace_id: entity.cache?.workspace_id, + cache_channel_id: entity.cache?.channel_id, + cache_user_id: entity.cache?.user_id, + }; + return source; + }, + mongoMapping: { + text: { + name: "text", + }, + prefix: { + name: "prefix", + }, + }, + esMapping: { + properties: { + name: { type: "text", index_prefixes: { min_chars: 1, max_chars: 20 } }, + size: { type: "number" }, + source: { type: "keyword" }, + extension: { type: "keyword" }, + is_media: { type: "boolean" }, + is_file: { type: "boolean" }, + created_at: { type: "number" }, + + cache_company_id: { type: "keyword" }, + cache_workspace_id: { type: "keyword" }, + cache_channel_id: { type: "keyword" }, + cache_user_id: { type: "keyword" }, + }, + }, +}; diff --git a/twake/backend/node/src/services/messages/entities/message-files.ts b/twake/backend/node/src/services/messages/entities/message-files.ts new file mode 100644 index 00000000..44b8f05a --- /dev/null +++ b/twake/backend/node/src/services/messages/entities/message-files.ts @@ -0,0 +1,54 @@ +import { Type } from "class-transformer"; +import { Thumbnail } from "../../files/entities/file"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import search from "./message-files.search"; + +export const TYPE = "message_files"; +@Entity(TYPE, { + primaryKey: [["message_id"], "id"], + type: TYPE, + search, +}) +export class MessageFile { + @Type(() => String) + @Column("message_id", "timeuuid", { order: "DESC" }) + message_id?: string; + + //Timeuuid is used please do not change to uuid + @Type(() => String) + @Column("id", "timeuuid", { order: "DESC" }) + id: string; + + @Type(() => String) + @Column("thread_id", "string") + thread_id?: string; + + @Column("company_id", "timeuuid") + company_id: string; + + @Column("created_at", "number") + created_at: number; + + @Column("metadata", "encoded_json") + metadata: MessageFileMetadata; + + @Column("cache", "encoded_json") + cache: null | { + company_id: string; + workspace_id: string; + channel_id: string; + user_id: string; + }; +} + +export type MessageFileMetadata = { + source: "internal" | "drive" | string; //Uuid of the corresponding connector + external_id: string | any; + + name?: string; //Original file name + mime?: string; //Original file mime + size?: number; //Original file weight + thumbnails?: Thumbnail[]; //Url to thumbnail (or set it to undefined if no relevant) +}; + +export type MessageFilePrimaryKey = Pick; diff --git a/twake/backend/node/src/services/messages/entities/message-user-inbox-refs-reversed.ts b/twake/backend/node/src/services/messages/entities/message-user-inbox-refs-reversed.ts new file mode 100644 index 00000000..b6389d63 --- /dev/null +++ b/twake/backend/node/src/services/messages/entities/message-user-inbox-refs-reversed.ts @@ -0,0 +1,35 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "message_user_inbox_refs_reversed"; +@Entity(TYPE, { + primaryKey: [["company_id"], "user_id", "thread_id"], + type: TYPE, +}) +export class MessageUserInboxRefReversed { + @Type(() => String) + @Column("company_id", "uuid") + company_id: string; + + @Type(() => String) + @Column("user_id", "string") + user_id: string; + + @Type(() => String) + @Column("thread_id", "timeuuid", { order: "DESC" }) + thread_id: string; + + @Type(() => Number) + @Column("last_activity", "number") + last_activity: number; +} + +export type MessageUserInboxRefReversedPrimaryKey = Pick< + MessageUserInboxRefReversed, + "company_id" | "user_id" | "thread_id" +>; + +export function getInstance(ref: MessageUserInboxRefReversed): MessageUserInboxRefReversed { + return merge(new MessageUserInboxRefReversed(), ref); +} diff --git a/twake/backend/node/src/services/messages/entities/message-user-inbox-refs.ts b/twake/backend/node/src/services/messages/entities/message-user-inbox-refs.ts new file mode 100644 index 00000000..343aafe0 --- /dev/null +++ b/twake/backend/node/src/services/messages/entities/message-user-inbox-refs.ts @@ -0,0 +1,43 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "message_user_inbox_refs"; +@Entity(TYPE, { + primaryKey: [["company_id"], "user_id", "last_activity", "thread_id"], + type: TYPE, +}) +export class MessageUserInboxRef { + @Type(() => String) + @Column("company_id", "uuid") + company_id: string; + + @Type(() => String) + @Column("user_id", "string") + user_id: string; + + @Type(() => Number) + @Column("last_activity", "number", { order: "DESC" }) + last_activity: number; + + @Type(() => String) + @Column("thread_id", "timeuuid", { order: "DESC" }) + thread_id: string; + + @Type(() => String) + @Column("workspace_id", "string") + workspace_id: string; + + @Type(() => String) + @Column("channel_id", "string") + channel_id: string; +} + +export type MessageUserInboxRefPrimaryKey = Pick< + MessageUserInboxRef, + "company_id" | "user_id" | "last_activity" | "thread_id" +>; + +export function getInstance(ref: MessageUserInboxRef): MessageUserInboxRef { + return merge(new MessageUserInboxRef(), ref); +} diff --git a/twake/backend/node/src/services/messages/entities/message-user-marked_refs.ts b/twake/backend/node/src/services/messages/entities/message-user-marked_refs.ts new file mode 100644 index 00000000..07ee752b --- /dev/null +++ b/twake/backend/node/src/services/messages/entities/message-user-marked_refs.ts @@ -0,0 +1,51 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "message_user_marked_refs"; +@Entity(TYPE, { + primaryKey: [["company_id"], "user_id", "bookmark_id", "id"], + type: TYPE, +}) +export class MessageUserMarkedRef { + @Type(() => String) + @Column("company_id", "uuid") + company_id: string; + + @Type(() => String) + @Column("user_id", "string") + user_id: string; + + @Type(() => String) + @Column("bookmark_id", "string") + bookmark_id: string; + + @Type(() => Number) + @Column("id", "timeuuid", { generator: "timeuuid", order: "DESC" }) + id: number; + + @Type(() => String) + @Column("workspace_id", "string") + workspace_id: string; + + @Type(() => String) + @Column("channel_id", "string") + channel_id: string; + + @Type(() => String) + @Column("thread_id", "timeuuid") + thread_id: string; + + @Type(() => String) + @Column("message_id", "timeuuid") + message_id: string; +} + +export type MessageUserMarkedRefPrimaryKey = Pick< + MessageUserMarkedRef, + "company_id" | "user_id" | "bookmark_id" | "id" +>; + +export function getInstance(ref: MessageUserMarkedRef): MessageUserMarkedRef { + return merge(new MessageUserMarkedRef(), ref); +} diff --git a/twake/backend/node/src/services/messages/entities/messages.search.ts b/twake/backend/node/src/services/messages/entities/messages.search.ts new file mode 100644 index 00000000..9b85f2e1 --- /dev/null +++ b/twake/backend/node/src/services/messages/entities/messages.search.ts @@ -0,0 +1,59 @@ +import { fileIsMedia } from "../../../services/files/utils"; +import { expandFileNameForSearch } from "./message-files.search"; +import { Message } from "./messages"; + +export default { + index: "messages", + source: (entity: Message) => { + const links = ( + (entity.text || "").match( + /(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/gi, + ) || [] + ).join(" "); + const source: any = { + created_at: entity.created_at, + text: entity.text || "", + has_files: (entity.files || []).length > 0, + has_medias: (entity.files || []).filter(f => fileIsMedia(f)).length > 0, + attachments_names: (entity.files || []) + .map(file => expandFileNameForSearch(file.metadata.name)) + .join(" "), + links: + links + + " " + + links.replace(/https?:\/\//gm, "") + + " " + + links.replace(/[^A-Z-a-z0-9]/gm, " "), + }; + if (entity.cache) { + return { + company_id: entity.cache?.company_id, + workspace_id: entity.cache?.workspace_id, + channel_id: entity.cache?.channel_id, + user_id: entity.user_id, + + ...source, + }; + } + return source; + }, + mongoMapping: { + text: { + text: "text", + }, + }, + esMapping: { + properties: { + text: { type: "text" }, + attachments_names: { type: "text", index_prefixes: { min_chars: 1 } }, + links: { type: "text", index_prefixes: { min_chars: 1 } }, + user_id: { type: "keyword" }, + company_id: { type: "keyword" }, + workspace_id: { type: "keyword" }, + channel_id: { type: "keyword" }, + has_files: { type: "boolean" }, + has_medias: { type: "boolean" }, + created_at: { type: "number" }, + }, + }, +}; diff --git a/twake/backend/node/src/services/messages/entities/messages.ts b/twake/backend/node/src/services/messages/entities/messages.ts new file mode 100644 index 00000000..c7f36f13 --- /dev/null +++ b/twake/backend/node/src/services/messages/entities/messages.ts @@ -0,0 +1,161 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import { Block } from "../blocks-types"; +import { UserObject } from "../../user/web/types"; +import { MessageFile } from "./message-files"; +import Application from "../../applications/entities/application"; +import search from "./messages.search"; + +export const TYPE = "messages"; +@Entity(TYPE, { + primaryKey: [["thread_id"], "id"], + type: TYPE, + search, +}) +export class Message { + @Type(() => String) + @Column("thread_id", "timeuuid", { order: "DESC" }) + thread_id: string; + + @Type(() => String) + @Column("id", "timeuuid", { generator: "timeuuid", order: "DESC" }) + id: string; + + @Type(() => String) //Not in database (obviousl y because it is ephemeral) + ephemeral: EphemeralMessage | null; //Used for non-persisted messages (like interractive messages) + + @Type(() => String) + @Column("type", "encoded_string") + type: + | "message" // Classic message + | "event"; // Hidden system events + + @Column("subtype", "encoded_string") + subtype: + | null + | "application" //Message from a connector + | "deleted" //Message deleted by user + | "system"; // Message from system (channel activity) + + @Type(() => Number) + @Column("created_at", "number") + created_at: number; + + @Column("updated_at", "number", { onUpsert: _ => new Date().getTime() }) + updated_at: number; + + @Type(() => String) + @Column("user_id", "uuid") + user_id: string; + + @Column("application_id", "encoded_string") + application_id: null | string; + + @Type(() => String) + @Column("text", "encoded_string") + text: string; + + @Column("blocks", "encoded_json") + blocks: Block[]; + + @Column("files", "encoded_json") + files: null | Partial[]; + + @Column("context", "encoded_json") + context: any; + + @Column("edited", "encoded_json") + edited: null | MessageEdited; + + @Column("pinned_info", "encoded_json") + pinned_info: null | MessagePinnedInfo; + + @Column("quote_message", "encoded_json") + quote_message: + | null + | (Partial & { + id: string; + thread_id: string; + channel_id: string | null; + workspace_id: string | null; + company_id: string | null; + }); + + @Column("reactions", "encoded_json") + reactions: null | MessageReaction[]; + + @Column("bookmarks", "encoded_json") + bookmarks: null | MessageBookmarks[]; + + @Column("override", "encoded_json") + override: null | MessageOverride; + + @Column("cache", "encoded_json") + cache: null | { + company_id: string; + workspace_id: string; + channel_id: string; + }; + + @Column("links", "encoded_json") + links: null | MessageLinks[]; + + @Column("status", "encoded_json") + status: null | MessageDeliveryStatus; +} + +export type MessageReaction = { count: number; name: string; users: string[] }; + +export type MessageOverride = { title?: string; picture?: string }; + +export type MessagePinnedInfo = { pinned_at: number; pinned_by: string }; + +export type MessageEdited = { edited_at: number }; + +export type EphemeralMessage = { + id: string; //Identifier of the ephemeral message + version: string; //Version of ephemeral message (to update the view) + recipient: string; //User that will see this ephemeral message + recipient_context_id: string; //Recipient current view/tab/window to send the message to +}; + +export type MessageBookmarks = { + user_id: string; + bookmark_id: string; + created_at: number; +}; + +export type MessagePrimaryKey = Pick; + +export function getInstance(message: Partial): Message { + return merge(new Message(), { + id: undefined, + ephemeral: null, + type: "message", + created_at: new Date().getTime(), + application_id: null, + text: "", + blocks: [], + + ...message, + }); +} + +export type MessageWithUsers = Message & { + users?: UserObject[]; + application?: Partial; +}; + +export type MessageLinks = { + title: string; + description: string | null; + domain: string; + img: string | null; + favicon: string | null; + img_width: number | null; + img_height: number | null; + url: string; +}; + +export type MessageDeliveryStatus = "sent" | "delivered" | "read"; diff --git a/twake/backend/node/src/services/messages/entities/threads.ts b/twake/backend/node/src/services/messages/entities/threads.ts new file mode 100644 index 00000000..21aa8ff0 --- /dev/null +++ b/twake/backend/node/src/services/messages/entities/threads.ts @@ -0,0 +1,51 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "threads"; +@Entity(TYPE, { + primaryKey: [["id"]], + type: TYPE, +}) +export class Thread { + @Type(() => String) + @Column("id", "timeuuid", { order: "DESC" }) + id: string; + + @Type(() => String) + @Column("created_by", "string") + created_by: string; + + @Type(() => Number) + @Column("created_at", "number") + created_at: number; + + @Column("updated_at", "number", { onUpsert: _ => new Date().getTime() }) + updated_at: number; + + @Type(() => Number) + @Column("last_activity", "number") + last_activity: number; + + @Type(() => Number) + @Column("answers", "number") + answers: number; + + @Column("participants", "encoded_json") + participants: ParticipantObject[]; +} + +export type ParticipantObject = { + type: "user" | "channel"; + created_at: number; + created_by: string; + id: string; + company_id: string; + workspace_id?: string; +}; + +export type ThreadPrimaryKey = Pick; + +export function getInstance(thread: Thread): Thread { + return merge(new Thread(), thread); +} diff --git a/twake/backend/node/src/services/messages/entities/user-message-bookmarks.ts b/twake/backend/node/src/services/messages/entities/user-message-bookmarks.ts new file mode 100644 index 00000000..a3a0117c --- /dev/null +++ b/twake/backend/node/src/services/messages/entities/user-message-bookmarks.ts @@ -0,0 +1,37 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "user_message_bookmarks"; +@Entity(TYPE, { + primaryKey: [["company_id"], "user_id", "id"], + type: TYPE, +}) +export class UserMessageBookmark { + @Type(() => String) + @Column("company_id", "uuid") + company_id: string; + + @Type(() => String) + @Column("user_id", "uuid") + user_id: string; + + @Type(() => String) + @Column("id", "uuid", { generator: "uuid" }) + id: string; + + @Type(() => String) + @Column("name", "encoded_string") + name = ""; +} + +export type UserMessageBookmarkPrimaryKey = Pick< + UserMessageBookmark, + "company_id" | "user_id" | "id" +>; + +export function getInstance( + bookmark: Pick, +): UserMessageBookmark { + return merge(new UserMessageBookmark(), bookmark); +} diff --git a/twake/backend/node/src/services/messages/index.ts b/twake/backend/node/src/services/messages/index.ts new file mode 100644 index 00000000..1e0ea84c --- /dev/null +++ b/twake/backend/node/src/services/messages/index.ts @@ -0,0 +1,23 @@ +import { Prefix, TwakeService } from "../../core/platform/framework"; +import WebServerAPI from "../../core/platform/services/webserver/provider"; +import web from "./web"; + +@Prefix("/internal/services/messages/v1") +export default class MessageService extends TwakeService { + version = "1"; + name = "messages"; + + public async doInit(): Promise { + const fastify = this.context.getProvider("webserver").getServer(); + fastify.register((instance, _opts, next) => { + web(instance, { prefix: this.prefix }); + next(); + }); + return this; + } + + // TODO: remove + api(): undefined { + return undefined; + } +} diff --git a/twake/backend/node/src/services/messages/services/engine/index.ts b/twake/backend/node/src/services/messages/services/engine/index.ts new file mode 100644 index 00000000..069415c1 --- /dev/null +++ b/twake/backend/node/src/services/messages/services/engine/index.ts @@ -0,0 +1,112 @@ +import { localEventBus } from "../../../../core/platform/framework/event-bus"; +import { Initializable } from "../../../../core/platform/framework"; +import { MessageFileDownloadEvent, MessageLocalEvent } from "../../types"; +import { ChannelViewProcessor } from "./processors/channel-view"; +import { ChannelMarkedViewProcessor } from "./processors/channel-marked"; +import { UserMarkedViewProcessor } from "./processors/user-marked"; +import { UserInboxViewProcessor } from "./processors/user-inbox"; +import { FilesViewProcessor } from "./processors/files"; +import Repository from "../../../../core/platform/services/database/services/orm/repository/repository"; +import { Thread } from "../../entities/threads"; +import { ChannelSystemActivityMessageProcessor } from "./processors/system-activity-message"; +import { MessageToNotificationsProcessor } from "./processors/message-to-notifications"; +import { ResourceEventsPayload } from "../../../../utils/types"; +import _ from "lodash"; +import { StatisticsMessageProcessor } from "../../../statistics/pubsub/messages"; +import { MessageToHooksProcessor } from "./processors/message-to-hooks"; +import gr from "../../../global-resolver"; +import { MessageLinksPreviewFinishedProcessor } from "./processors/links"; +import { Message } from "../../entities/messages"; +import { ExecutionContext } from "../../../../core/platform/framework/api/crud-service"; + +export class MessagesEngine implements Initializable { + private channelViewProcessor: ChannelViewProcessor; + private channelMarkedViewProcessor: ChannelMarkedViewProcessor; + private userMarkedViewProcessor: UserMarkedViewProcessor; + private userInboxViewProcessor: UserInboxViewProcessor; + private filesViewProcessor: FilesViewProcessor; + private messageToNotifications: MessageToNotificationsProcessor; + private messageToHooks: MessageToHooksProcessor; + + private threadRepository: Repository; + private messageRepository: Repository; + + constructor() { + this.channelViewProcessor = new ChannelViewProcessor(); + this.channelMarkedViewProcessor = new ChannelMarkedViewProcessor(); + this.userMarkedViewProcessor = new UserMarkedViewProcessor(); + this.userInboxViewProcessor = new UserInboxViewProcessor(); + this.filesViewProcessor = new FilesViewProcessor(); + this.messageToNotifications = new MessageToNotificationsProcessor(); + this.messageToHooks = new MessageToHooksProcessor(); + } + + async dispatchMessage(e: MessageLocalEvent, context?: ExecutionContext) { + const thread = await this.threadRepository.findOne( + { + id: e.resource.thread_id, + }, + {}, + context, + ); + + if (e.resource.ephemeral) { + await this.channelViewProcessor.process(thread || null, e); + return; + } + + await this.channelViewProcessor.process(thread, e); + await this.channelMarkedViewProcessor.process(thread, e); + await this.userInboxViewProcessor.process(thread, e); + await this.userMarkedViewProcessor.process(); + await this.filesViewProcessor.process(thread, e); + await this.messageToNotifications.process(thread, e); + await this.messageToHooks.process(thread, e); + + if (e.created) { + for (const workspaceId of _.uniq( + thread.participants.filter(p => p.type == "channel").map(p => p.workspace_id), + )) { + localEventBus.publish("channel:message_sent", { + message: { + thread_id: e.resource.thread_id, + sender: e.resource.user_id, + workspace_id: workspaceId, + }, + user: e.context.user, + }); + } + } + } + + async init(): Promise { + this.threadRepository = await gr.database.getRepository("threads", Thread); + this.messageRepository = await gr.database.getRepository("messages", Message); + + await this.channelViewProcessor.init(); + await this.channelMarkedViewProcessor.init(); + await this.userInboxViewProcessor.init(); + await this.userMarkedViewProcessor.init(); + await this.filesViewProcessor.init(); + + gr.platformServices.messageQueue.processor.addHandler( + new ChannelSystemActivityMessageProcessor(), + ); + gr.platformServices.messageQueue.processor.addHandler(new StatisticsMessageProcessor()); + gr.platformServices.messageQueue.processor.addHandler( + new MessageLinksPreviewFinishedProcessor(this.messageRepository, this.threadRepository), + ); + + localEventBus.subscribe("message:saved", async (e: MessageLocalEvent) => { + this.dispatchMessage(e); + }); + + localEventBus.subscribe("message:download", async (e: MessageFileDownloadEvent) => { + if (e.user?.id) { + await this.filesViewProcessor.processDownloaded(e.user?.id, e.operation); + } + }); + + return this; + } +} diff --git a/twake/backend/node/src/services/messages/services/engine/processors/channel-marked/index.ts b/twake/backend/node/src/services/messages/services/engine/processors/channel-marked/index.ts new file mode 100644 index 00000000..cf341fa3 --- /dev/null +++ b/twake/backend/node/src/services/messages/services/engine/processors/channel-marked/index.ts @@ -0,0 +1,47 @@ +import { MessageLocalEvent } from "../../../../types"; +import { Thread } from "../../../../entities/threads"; +import Repository from "../../../../../../core/platform/services/database/services/orm/repository/repository"; +import { + getInstance, + MessageChannelMarkedRef, +} from "../../../../entities/message-channel-marked-refs"; +import gr from "../../../../../global-resolver"; +import { ExecutionContext } from "../../../../../../core/platform/framework/api/crud-service"; + +export class ChannelMarkedViewProcessor { + repository: Repository; + + async init() { + this.repository = await gr.database.getRepository( + "message_channel_marked_refs", + MessageChannelMarkedRef, + ); + } + + async process( + thread: Thread, + message: MessageLocalEvent, + context?: ExecutionContext, + ): Promise { + for (const participant of thread.participants.filter(p => p.type === "channel")) { + //Pinned messages + const pinRef = getInstance({ + company_id: participant.company_id, + workspace_id: participant.workspace_id, + channel_id: participant.id, + thread_id: thread.id, + message_id: message.resource.id, + type: "pinned", + created_at: message.resource.pinned_info?.pinned_at || 0, + created_by: message.resource.pinned_info?.pinned_by || "", + }); + if (message.resource.pinned_info) { + this.repository.save(pinRef, context); + } else if (!message.created) { + this.repository.remove(pinRef, context); + } + + //TODO add realtime + } + } +} diff --git a/twake/backend/node/src/services/messages/services/engine/processors/channel-view/index.ts b/twake/backend/node/src/services/messages/services/engine/processors/channel-view/index.ts new file mode 100644 index 00000000..4271fd25 --- /dev/null +++ b/twake/backend/node/src/services/messages/services/engine/processors/channel-view/index.ts @@ -0,0 +1,143 @@ +import { MessageLocalEvent } from "../../../../types"; +import { ParticipantObject, Thread } from "../../../../entities/threads"; +import Repository from "../../../../../../core/platform/services/database/services/orm/repository/repository"; +import { getInstance, MessageChannelRef } from "../../../../entities/message-channel-refs"; +import { + getInstance as getInstanceReversed, + MessageChannelRefReversed, +} from "../../../../entities/message-channel-refs-reversed"; + +import { ExecutionContext } from "../../../../../../core/platform/framework/api/crud-service"; +import gr from "../../../../../global-resolver"; +import { publishMessageInRealtime } from "../../../utils"; + +export class ChannelViewProcessor { + repository: Repository; + repositoryReversed: Repository; + + async init() { + this.repository = await gr.database.getRepository( + "message_channel_refs", + MessageChannelRef, + ); + this.repositoryReversed = await gr.database.getRepository( + "message_channel_refs_reversed", + MessageChannelRefReversed, + ); + } + + async process( + thread: Thread, + message: MessageLocalEvent, + context?: ExecutionContext, + ): Promise { + let participants: ParticipantObject[] = thread?.participants || []; + + if (participants.length === 0) { + participants = message.context.channel + ? [ + { + type: "channel", + id: message.context.channel.id, + workspace_id: message.context.workspace.id, + company_id: message.context.company.id, + } as ParticipantObject, + ] + : []; + } + + for (const participant of (participants || []).filter(p => p.type === "channel")) { + if (!message.resource.ephemeral) { + //Publish message in corresponding channel + if (message.created) { + const pkPrefix = { + company_id: participant.company_id, + workspace_id: participant.workspace_id, + channel_id: participant.id, + }; + + //If a pointer exists it means the message already exists (it was probably moved and so we need to keep everything in place) + const existingPointer = await this.repository.findOne( + { + ...pkPrefix, + message_id: message.resource.id, + }, + {}, + context, + ); + + if (!existingPointer) { + await this.repository.save( + getInstance({ + ...pkPrefix, + thread_id: thread.id, + message_id: message.resource.id, + }), + context, + ); + + const reversed = await this.repositoryReversed.findOne( + { + ...pkPrefix, + thread_id: thread.id, + }, + {}, + context, + ); + + if (reversed) { + const existingThreadRef = await this.repository.findOne( + { + ...pkPrefix, + message_id: reversed.message_id, + }, + {}, + context, + ); + if ( + existingThreadRef && + `${existingThreadRef.thread_id}` === `${message.resource.thread_id}` + ) { + reversed.message_id = message.resource.id; + await this.repositoryReversed.save(reversed, context); + await this.repository.remove(existingThreadRef, context); + } + } else { + await this.repositoryReversed.save( + getInstanceReversed({ + ...pkPrefix, + thread_id: thread.id, + message_id: message.resource.id, + }), + context, + ); + } + } + + //Message moved to it own thread + if (existingPointer && message.resource.thread_id === message.resource.id) { + await this.repository.save( + getInstance({ + ...pkPrefix, + thread_id: thread.id, + message_id: message.resource.id, + }), + context, + ); + await this.repositoryReversed.save( + getInstanceReversed({ + ...pkPrefix, + thread_id: thread.id, + message_id: message.resource.id, + }), + context, + ); + } + } + } + + //Publish message in realtime + publishMessageInRealtime(message, participant); + } + } +} diff --git a/twake/backend/node/src/services/messages/services/engine/processors/files/index.ts b/twake/backend/node/src/services/messages/services/engine/processors/files/index.ts new file mode 100644 index 00000000..01920e69 --- /dev/null +++ b/twake/backend/node/src/services/messages/services/engine/processors/files/index.ts @@ -0,0 +1,144 @@ +import { MessageLocalEvent } from "../../../../types"; +import { Thread } from "../../../../entities/threads"; +import Repository from "../../../../../../core/platform/services/database/services/orm/repository/repository"; +import { getInstance, MessageFileRef } from "../../../../entities/message-file-refs"; +import gr from "../../../../../global-resolver"; +import uuid from "node-uuid"; +import { + ExecutionContext, + Pagination, +} from "../../../../../../core/platform/framework/api/crud-service"; +import { MessageFile } from "../../../../entities/message-files"; +import { fileIsMedia } from "../../../../../files/utils"; + +export class FilesViewProcessor { + repository: Repository; + messageFileRepository: Repository; + + async init() { + this.repository = await gr.database.getRepository( + "message_file_refs", + MessageFileRef, + ); + this.messageFileRepository = await gr.database.getRepository( + "message_files", + MessageFile, + ); + } + + async processDownloaded( + userId: string, + operation: { message_id: string; thread_id: string; message_file_id: string }, + context?: ExecutionContext, + ): Promise { + const messageFile = await this.messageFileRepository.findOne( + { + message_id: operation.message_id, + id: operation.message_file_id, + }, + {}, + context, + ); + + const thread = await gr.services.messages.threads.get( + { + id: operation.thread_id, + }, + context, + ); + + const refs = await this.repository.find( + { target_type: "user_download", target_id: userId, company_id: messageFile.company_id }, + { + pagination: new Pagination("", "100"), + }, + context, + ); + if (refs.getEntities().some(r => r.message_file_id === messageFile.id)) { + //File already in the recent list + return; + } + + //For the user we add it as downloaded by user + const fileRef = getInstance({ + target_type: "user_download", + target_id: userId, + id: uuid.v1(), + created_at: new Date().getTime(), + file_id: messageFile?.metadata?.external_id, + company_id: messageFile.company_id, + workspace_id: thread.participants?.find(p => p.type === "channel")?.workspace_id || "", + channel_id: thread.participants?.find(p => p.type === "channel")?.id || "", + thread_id: messageFile.thread_id, + message_id: messageFile.message_id, + message_file_id: messageFile.id, + }); + this.repository.save(fileRef, context); + } + + async process( + thread: Thread, + message: MessageLocalEvent, + context?: ExecutionContext, + ): Promise { + if (!message.resource.ephemeral) { + for (const file of message.resource.files || []) { + //For each channel, we add the media + for (const participant of (thread.participants || []).filter(p => p.type === "channel")) { + const fileRef = getInstance({ + target_type: "channel", + target_id: participant.id, + id: uuid.v1(), + created_at: message.resource.created_at, + workspace_id: participant.workspace_id, + channel_id: participant.id, + thread_id: thread.id, + message_id: message.resource.id, + message_file_id: file.id, + company_id: file.company_id, + file_id: file.metadata.external_id, + }); + this.repository.save(fileRef, context); + + const isMedia = fileIsMedia(file); + for (const type of [ + "channel", + isMedia ? "channel_media" : "channel_file", + ] as MessageFileRef["target_type"][]) { + const fileRef = getInstance({ + target_type: type, + target_id: participant.id, + id: uuid.v1(), + created_at: message.resource.created_at, + workspace_id: participant.workspace_id, + channel_id: participant.id, + thread_id: thread.id, + message_id: message.resource.id, + message_file_id: file.id, + company_id: file.company_id, + file_id: file.metadata.external_id, + }); + this.repository.save(fileRef); + } + } + + //For the user we add it as uploaded by user + const fileRef = getInstance({ + target_type: "user_upload", + target_id: message.resource.user_id, + id: uuid.v1(), + created_at: message.resource.created_at, + workspace_id: + (thread.participants || []).filter(p => p.type === "channel")[0]?.workspace_id || "", + channel_id: (thread.participants || []).filter(p => p.type === "channel")[0]?.id || "", + thread_id: thread.id, + message_id: message.resource.id, + message_file_id: file.id, + company_id: file.company_id, + file_id: file.metadata.external_id, + }); + this.repository.save(fileRef, context); + } + } + } +} diff --git a/twake/backend/node/src/services/messages/services/engine/processors/links/index.ts b/twake/backend/node/src/services/messages/services/engine/processors/links/index.ts new file mode 100644 index 00000000..7884ab52 --- /dev/null +++ b/twake/backend/node/src/services/messages/services/engine/processors/links/index.ts @@ -0,0 +1,85 @@ +import { logger } from "../../../../../../core/platform/framework"; +import { MessageQueueHandler } from "../../../../../../core/platform/services/message-queue/api"; +import { Message } from "../../../../entities/messages"; +import Repository from "../../../../../../core/platform/services/database/services/orm/repository/repository"; +import { LinkPreviewMessageQueueCallback } from "../../../../../previews/types"; +import { Thread } from "../../../../entities/threads"; +import { publishMessageInRealtime } from "../../../utils"; +import { ExecutionContext } from "../../../../../../core/platform/framework/api/crud-service"; + +export class MessageLinksPreviewFinishedProcessor + implements MessageQueueHandler +{ + constructor( + private MessageRepository: Repository, + private ThreadRepository: Repository, + ) {} + readonly name = "MessageLinksPreviewFinishedProcessor"; + readonly topics = { + in: "services:preview:links:callback", + }; + + readonly options = { + unique: true, + ack: true, + }; + + init?(): Promise { + throw new Error("Method not implemented."); + } + + validate(message: LinkPreviewMessageQueueCallback): boolean { + return !!(message && message.previews && message.previews.length); + } + + async process( + localMessage: LinkPreviewMessageQueueCallback, + context?: ExecutionContext, + ): Promise { + logger.info( + `${this.name} - updating message links with generated previews: ${localMessage.previews.length}`, + ); + + const entity = await this.MessageRepository.findOne( + { + thread_id: localMessage.message.resource.thread_id, + id: localMessage.message.resource.id, + }, + {}, + context, + ); + + if (!entity) { + logger.error(`${this.name} - message not found`); + return ""; + } + + entity.links = localMessage.previews; + + await this.MessageRepository.save(entity, context); + + const thread: Thread = await this.ThreadRepository.findOne( + { + id: localMessage.message.resource.thread_id, + }, + {}, + context, + ); + + if (!thread) { + logger.error(`${this.name} - thread not found`); + return ""; + } + + const updatedMessage = { + ...localMessage.message, + resource: entity, + }; + + for (const participant of thread.participants.filter(p => p.type === "channel")) { + publishMessageInRealtime(updatedMessage, participant); + } + + return "done"; + } +} diff --git a/twake/backend/node/src/services/messages/services/engine/processors/message-to-hooks/index.ts b/twake/backend/node/src/services/messages/services/engine/processors/message-to-hooks/index.ts new file mode 100644 index 00000000..12f92bf7 --- /dev/null +++ b/twake/backend/node/src/services/messages/services/engine/processors/message-to-hooks/index.ts @@ -0,0 +1,107 @@ +import { MessageHook, MessageLocalEvent } from "../../../../types"; +import { ParticipantObject, Thread } from "../../../../entities/threads"; +import { logger } from "../../../../../../core/platform/framework"; +import { Channel } from "../../../../../channels/entities"; +import { + ExecutionContext, + Pagination, +} from "../../../../../../core/platform/framework/api/crud-service"; +import { Message } from "../../../../entities/messages"; +import gr from "../../../../../global-resolver"; + +export class MessageToHooksProcessor { + private name = "MessageToHooksProcessor"; + + async init() { + return this; + } + + async process( + thread: Thread, + message: MessageLocalEvent, + context?: ExecutionContext, + ): Promise { + logger.debug(`${this.name} - Share message with channel microservice for hooks`); + + if (message.resource.ephemeral) { + logger.debug(`${this.name} - Cancel because message is ephemeral`); + return; + } + + try { + const messageResource = message.resource; + + for (const participant of thread.participants) { + if (participant.type !== "channel") { + continue; + } + + const channel: Channel = await gr.services.channels.channels.get( + { + id: participant.id, + company_id: participant.company_id, + workspace_id: participant.workspace_id, + }, + context, + ); + + if (!channel) { + continue; + } + + for (const appId of channel.connectors) { + if (message.resource.application_id !== appId) { + //Publish hook + await gr.platformServices.messageQueue.publish( + "application:hook:message", + { + data: { + type: "message", + application_id: appId, + company_id: participant.company_id, + channel: channel, + thread: thread, + message: messageResource, + }, + }, + ); + } + } + } + } catch (err) { + logger.warn({ err }, `${this.name} - Error while publishing`); + } + } + + async isLastActivityMessageDeleted( + participant: ParticipantObject, + messageResource: Message, + message: MessageLocalEvent, + ): Promise { + if (participant.company_id && participant.workspace_id && participant.id) { + const list = await gr.services.messages.views.listChannel( + new Pagination("", "1"), + { + include_users: false, + replies_per_thread: 1, + emojis: false, + }, + { + channel: { + company_id: participant.company_id, + workspace_id: participant.workspace_id, + id: participant.id, + }, + user: { + id: messageResource.user_id, + }, + }, + ); + + return ( + list.getEntities().pop()?.id === message.resource.id && + messageResource.subtype === "deleted" + ); + } + } +} diff --git a/twake/backend/node/src/services/messages/services/engine/processors/message-to-notifications/index.ts b/twake/backend/node/src/services/messages/services/engine/processors/message-to-notifications/index.ts new file mode 100644 index 00000000..54fc45c4 --- /dev/null +++ b/twake/backend/node/src/services/messages/services/engine/processors/message-to-notifications/index.ts @@ -0,0 +1,179 @@ +import { MessageLocalEvent, MessageNotification } from "../../../../types"; +import { ParticipantObject, Thread } from "../../../../entities/threads"; +import { logger } from "../../../../../../core/platform/framework"; +import { Channel } from "../../../../../channels/entities"; +import { isDirectChannel } from "../../../../../channels/utils"; +import { ChannelActivityNotification } from "../../../../../channels/types"; +import { getMentions } from "../../../utils"; +import { + ExecutionContext, + Pagination, +} from "../../../../../../core/platform/framework/api/crud-service"; +import { Message } from "../../../../../../services/messages/entities/messages"; +import gr from "../../../../../global-resolver"; + +export class MessageToNotificationsProcessor { + private name = "MessageToNotificationsProcessor"; + + async init() { + // + } + + async process( + thread: Thread, + message: MessageLocalEvent, + context?: ExecutionContext, + ): Promise { + logger.debug(`${this.name} - Share message with notification microservice`); + + if (message.resource.ephemeral) { + logger.debug(`${this.name} - Cancel because message is ephemeral`); + return; + } + + try { + const messageResource = message.resource; + + for (const participant of thread.participants) { + if (participant.type !== "channel") { + continue; + } + + const channel: Channel = await gr.services.channels.channels.get( + { + id: participant.id, + company_id: participant.company_id, + workspace_id: participant.workspace_id, + }, + context, + ); + + if (!channel) { + continue; + } + + const company = await gr.services.companies.getCompany({ id: participant.company_id }); + + const companyName = company?.name || ""; + let workspaceName = ""; + let senderName = "Twake"; + if (messageResource.user_id) { + const user = await gr.services.users.get({ id: messageResource.user_id }); + senderName = + `${user?.first_name || ""} ${user?.last_name || ""}`.trim() || + `@${user?.username_canonical}`; + } + + let title = ""; + let text = (messageResource.text || "").substr(0, 255); + const body = messageResource.text; // we need original body just in case text gets updated further on + if (isDirectChannel(channel)) { + title = `${senderName} in ${companyName}`; + } else { + const workspace = + (await gr.services.companies.getCompany({ id: participant.workspace_id })) || null; + workspaceName = workspace?.name || workspaceName; + title = `${channel.name} in ${companyName} β€’ ${workspaceName}`; + text = `${senderName}: ${text}`; + } + + const mentions = await getMentions(messageResource, async (username: string) => { + return await gr.services.users.getByUsername(username); + }); + + const messageEvent: MessageNotification = { + company_id: participant.company_id, + workspace_id: participant.workspace_id || "direct", + channel_id: participant.id, + thread_id: messageResource.thread_id, + id: messageResource.id, + sender: messageResource.user_id, + creation_date: messageResource.created_at, + + mentions, + + sender_name: senderName, + channel_name: channel.name, + company_name: companyName, + workspace_name: workspaceName, + + title: title, + text: text, + }; + + const channelEvent: ChannelActivityNotification = { + company_id: participant.company_id, + workspace_id: participant.workspace_id || "direct", + channel_id: participant.id, + date: messageResource.created_at, + sender: messageResource.user_id, + sender_name: senderName, + title: title, + text: text, + body: body, + }; + + if (messageResource.type === "message" && messageResource.subtype !== "system") { + logger.info( + `${this.name} - Forward message ${messageResource.id} to channel:activity and message:created / message:updated`, + ); + + if ( + message.created || + (await this.isLastActivityMessageDeleted(participant, messageResource, message)) + ) { + await gr.platformServices.messageQueue.publish( + "channel:activity", + { + data: channelEvent, + }, + ); + } + + await gr.platformServices.messageQueue.publish( + message.created ? "message:created" : "message:updated", + { + data: messageEvent, + }, + ); + } else { + logger.debug(`${this.name} - Cancel because this is system message`); + } + } + } catch (err) { + logger.warn({ err }, `${this.name} - Error while publishing`); + } + } + + async isLastActivityMessageDeleted( + participant: ParticipantObject, + messageResource: Message, + message: MessageLocalEvent, + ): Promise { + if (participant.company_id && participant.workspace_id && participant.id) { + const list = await gr.services.messages.views.listChannel( + new Pagination("", "1"), + { + include_users: false, + replies_per_thread: 1, + emojis: false, + }, + { + channel: { + company_id: participant.company_id, + workspace_id: participant.workspace_id, + id: participant.id, + }, + user: { + id: messageResource.user_id, + }, + }, + ); + + return ( + list.getEntities().pop()?.id === message.resource.id && + messageResource.subtype === "deleted" + ); + } + } +} diff --git a/twake/backend/node/src/services/messages/services/engine/processors/system-activity-message/index.ts b/twake/backend/node/src/services/messages/services/engine/processors/system-activity-message/index.ts new file mode 100644 index 00000000..1c44a3f0 --- /dev/null +++ b/twake/backend/node/src/services/messages/services/engine/processors/system-activity-message/index.ts @@ -0,0 +1,66 @@ +import { MessageQueueHandler } from "../../../../../../core/platform/services/message-queue/api"; +import { ActivityPublishedType } from "../../../../../channels/services/channel/activities/types"; +import { ParticipantObject } from "../../../../entities/threads"; +import { getInstance } from "../../../../entities/messages"; +import { logger } from "../../../../../../core/platform/framework"; +import gr from "../../../../../global-resolver"; + +export class ChannelSystemActivityMessageProcessor + implements MessageQueueHandler +{ + readonly topics = { + in: "channel:activity_message", + }; + + readonly options = { + unique: true, + ack: true, + }; + + readonly name = "Channel::ChannelSystemActivityMessageProcessor"; + + validate(message: ActivityPublishedType): boolean { + return !!(message && message.channel_id && message.company_id && message.workspace_id); + } + + async process(event: ActivityPublishedType): Promise { + logger.info( + `${this.name} Publish system message to message service in channel ${event.channel_id}`, + ); + + const message = getInstance({ + type: "message", + subtype: "system", + context: { + type: "activity", + activity: event.activity, + }, + }); + + const participants: Pick[] = [ + { + type: "channel", + id: event.channel_id, + workspace_id: event.workspace_id, + company_id: event.company_id, + }, + ]; + + gr.services.messages.threads.save( + { + id: undefined, + participants, + }, + { + message, + }, + { + user: { + id: null, + server_request: true, + }, + company: { id: event.company_id }, + }, + ); + } +} diff --git a/twake/backend/node/src/services/messages/services/engine/processors/user-inbox/index.ts b/twake/backend/node/src/services/messages/services/engine/processors/user-inbox/index.ts new file mode 100644 index 00000000..c9954a1a --- /dev/null +++ b/twake/backend/node/src/services/messages/services/engine/processors/user-inbox/index.ts @@ -0,0 +1,93 @@ +import { MessageLocalEvent } from "../../../../types"; +import { Thread } from "../../../../entities/threads"; +import Repository from "../../../../../../core/platform/services/database/services/orm/repository/repository"; +import { + getInstance as getInboxRefInstance, + MessageUserInboxRef, +} from "../../../../entities/message-user-inbox-refs"; +import { + getInstance as getInboxThreadInstance, + MessageUserInboxRefReversed, +} from "../../../../entities/message-user-inbox-refs-reversed"; + +import { ExecutionContext } from "../../../../../../core/platform/framework/api/crud-service"; +import gr from "../../../../../global-resolver"; +import { publishMessageInRealtime } from "../../../utils"; + +export class UserInboxViewProcessor { + repositoryRef: Repository; + repositoryReversed: Repository; + + async init() { + this.repositoryRef = await gr.database.getRepository( + "message_user_inbox_refs", + MessageUserInboxRef, + ); + this.repositoryReversed = await gr.database.getRepository( + "message_user_inbox_refs_reversed", + MessageUserInboxRefReversed, + ); + } + + async process( + thread: Thread, + message: MessageLocalEvent, + context?: ExecutionContext, + ): Promise { + for (const userParticipant of thread.participants.filter(p => p.type === "user")) { + for (const channelParticipant of thread.participants.filter(p => p.type === "channel")) { + //Publish message in corresponding channel + + if (!userParticipant.id) { + continue; + } + + if (message.created) { + const commonPk = { + company_id: channelParticipant.company_id, + user_id: userParticipant.id, + thread_id: thread.id, + }; + + let threadActivityReversed = await this.repositoryReversed.findOne(commonPk, {}, context); + + let currentRef: MessageUserInboxRef = null; + if (threadActivityReversed) { + currentRef = await this.repositoryRef.findOne( + { + ...commonPk, + last_activity: threadActivityReversed.last_activity, + }, + {}, + context, + ); + } else { + threadActivityReversed = getInboxThreadInstance({ + ...commonPk, + last_activity: 0, + }); + } + + const ref = getInboxRefInstance({ + ...commonPk, + workspace_id: channelParticipant.workspace_id, + channel_id: channelParticipant.id, + last_activity: message.resource.created_at, + }); + + if (currentRef) { + await this.repositoryReversed.remove(currentRef, context); + } + await this.repositoryRef.save(ref, context); + threadActivityReversed.last_activity = message.resource.created_at; + await this.repositoryReversed.save(threadActivityReversed, context); + } + + //Publish message in realtime + + //TODO send a thread object instead of a message object + publishMessageInRealtime(message, channelParticipant); + } + } + } +} diff --git a/twake/backend/node/src/services/messages/services/engine/processors/user-marked/index.ts b/twake/backend/node/src/services/messages/services/engine/processors/user-marked/index.ts new file mode 100644 index 00000000..da8308e7 --- /dev/null +++ b/twake/backend/node/src/services/messages/services/engine/processors/user-marked/index.ts @@ -0,0 +1,18 @@ +import Repository from "../../../../../../core/platform/services/database/services/orm/repository/repository"; +import { MessageUserMarkedRef } from "../../../../entities/message-user-marked_refs"; +import gr from "../../../../../global-resolver"; + +export class UserMarkedViewProcessor { + repository: Repository; + + async init(): Promise { + this.repository = await gr.database.getRepository( + "message_user_marked_refs", + MessageUserMarkedRef, + ); + } + + async process(): Promise { + // + } +} diff --git a/twake/backend/node/src/services/messages/services/messages-files.ts b/twake/backend/node/src/services/messages/services/messages-files.ts new file mode 100644 index 00000000..730d6914 --- /dev/null +++ b/twake/backend/node/src/services/messages/services/messages-files.ts @@ -0,0 +1,170 @@ +import { Channel } from "../../../services/channels/entities"; +import { fileIsMedia } from "../../../services/files/utils"; +import { UserObject } from "../../../services/user/web/types"; +import { formatUser } from "../../../utils/users"; +import { Initializable } from "../../../core/platform/framework"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import gr from "../../../services/global-resolver"; +import { MessageFileRef, TYPE as TYPERef } from "../entities/message-file-refs"; +import { MessageFile, TYPE } from "../entities/message-files"; +import { Message } from "../entities/messages"; + +export class MessagesFilesService implements Initializable { + version: "1"; + msgFilesRepository: Repository; + msgFilesRefRepository: Repository; + + async init(): Promise { + this.msgFilesRepository = await gr.database.getRepository(TYPE, MessageFile); + this.msgFilesRefRepository = await gr.database.getRepository(TYPERef, MessageFileRef); + return this; + } + + /** + * Delete a message file and test this files belongs to the right user + * @param message_id + * @param id + * @param user_id + * @returns + */ + async deleteMessageFile(message_id: string, id: string, user_id: string): Promise { + const msgFile = await this.getMessageFile(message_id, id); + if (!msgFile) return null; + + if (msgFile.message.user_id !== user_id) return null; + + await this.msgFilesRepository.remove(msgFile); + + for (const target_type of ["channel_media", "channel_file", "channel"]) { + const ref = await this.msgFilesRefRepository.findOne({ + target_type, + company_id: msgFile.channel.company_id, + target_id: msgFile.channel.id, + id: msgFile.id, + }); + if (ref) await this.msgFilesRefRepository.remove(ref); + } + + return msgFile; + } + + /** + * Get a message file and returns more contextual data + * @param message_id + * @param id + * @returns + */ + async getMessageFile( + message_id: string, + id: string, + ): Promise< + MessageFile & { + user: UserObject; + message: Message; + channel: Channel; + navigation: { next: Partial; previous: Partial }; + } + > { + const msgFile = await this.msgFilesRepository.findOne({ message_id, id }); + if (!msgFile) return null; + + const message = await gr.services.messages.messages.get({ + thread_id: msgFile.thread_id, + id: message_id, + }); + const channel = await gr.services.channels.channels.get({ + company_id: message.cache.company_id, + workspace_id: message.cache.workspace_id, + id: message.cache.channel_id, + }); + const user = await formatUser(await gr.services.users.get({ id: message.user_id })); + + const navigationPk = { + target_type: fileIsMedia(msgFile) ? "channel_media" : "channel_file", + company_id: channel.company_id, + target_id: channel.id, + }; + const { previous, next } = await this.getMessageFileNavigation(navigationPk, msgFile.id); + + return { + ...msgFile, + user, + message, + channel, + navigation: { + next: next + ? { + id: next.message_file_id, + message_id: next.message_id, + } + : null, + previous: previous + ? { + id: previous.message_file_id, + message_id: previous.message_id, + } + : null, + }, + }; + } + + /** + * Message file references are ordered with an id based on the time the file was uploaded + * We cannot get this specific ID directly from the message file right now + */ + private async getMessageFileNavigation( + navigationPk: { target_type: string; company_id: string; target_id: string }, + id: string, + ) { + const list = [ + ...( + await this.msgFilesRefRepository.find(navigationPk, { + pagination: { + page_token: null, + limitStr: "5", + reversed: false, + }, + $gte: [["id", id]], + }) + ).getEntities(), + ...( + await this.msgFilesRefRepository.find(navigationPk, { + pagination: { + page_token: null, + limitStr: "5", + reversed: true, + }, + $lte: [["id", id]], + }) + ).getEntities(), + ]; + const offsetRef = list.find(a => a.message_file_id === id) || null; + + const next = ( + await this.msgFilesRefRepository.find(navigationPk, { + pagination: { + page_token: null, + limitStr: "2", + reversed: true, + }, + $gte: [["id", offsetRef?.id || id]], + }) + ) + .getEntities() + .filter(a => a.message_file_id !== id)?.[0]; + const previous = ( + await this.msgFilesRefRepository.find(navigationPk, { + pagination: { + page_token: null, + limitStr: "2", + reversed: false, + }, + $lte: [["id", offsetRef?.id || id]], + }) + ) + .getEntities() + .filter(a => a.message_file_id !== id)?.[0]; + + return { previous, next }; + } +} diff --git a/twake/backend/node/src/services/messages/services/messages-operations.ts b/twake/backend/node/src/services/messages/services/messages-operations.ts new file mode 100644 index 00000000..f1f525db --- /dev/null +++ b/twake/backend/node/src/services/messages/services/messages-operations.ts @@ -0,0 +1,301 @@ +import { OperationType, SaveResult } from "../../../core/platform/framework/api/crud-service"; +import { logger, TwakeContext } from "../../../core/platform/framework"; +import { Message, TYPE as MessageTableName } from "../entities/messages"; +import { + BookmarkOperation, + DeleteLinkOperation, + MessageFileDownloadEvent, + PinOperation, + ReactionOperation, + ThreadExecutionContext, + UpdateDeliveryStatusOperation, +} from "../types"; +import emoji from "emoji-name-map"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import { ThreadMessagesService } from "./messages"; +import gr from "../../global-resolver"; +import { updateMessageReactions } from "../../../utils/messages"; +import { localEventBus } from "../../../core/platform/framework/event-bus"; +import { ReactionNotification } from "../../../services/notifications/types"; +export class ThreadMessagesOperationsService { + constructor(private threadMessagesService: ThreadMessagesService) {} + repository: Repository; + + async init(_context: TwakeContext): Promise { + this.repository = await gr.database.getRepository(MessageTableName, Message); + return this; + } + + async pin( + operation: PinOperation, + options: Record, + context: ThreadExecutionContext, + ): Promise> { + if ( + !context?.user?.server_request && + !gr.services.messages.threads.checkAccessToThread(context) + ) { + logger.error(`Unable to write in thread ${context.thread.id}`); + throw Error("Can't edit this message."); + } + + const message = await this.repository.findOne( + { + thread_id: context.thread.id, + id: operation.id, + }, + {}, + context, + ); + + if (!message) { + logger.error("This message doesn't exists"); + throw Error("Can't edit this message."); + } + + message.pinned_info = operation.pin + ? { + pinned_by: context.user.id, + pinned_at: new Date().getTime(), + } + : null; + + logger.info( + `Updated message ${operation.id} pin to ${JSON.stringify(message.pinned_info)} thread ${ + message.thread_id + }`, + ); + await this.repository.save(message, context); + this.threadMessagesService.onSaved(message, { created: false }, context); + return new SaveResult("message", message, OperationType.UPDATE); + } + + async reaction( + operation: ReactionOperation, + options: Record, + context: ThreadExecutionContext, + ): Promise> { + if ( + !context?.user?.server_request && + !gr.services.messages.threads.checkAccessToThread(context) + ) { + logger.error(`Unable to write in thread ${context.thread.id}`); + throw Error("Can't edit this message."); + } + + const message = await this.repository.findOne( + { + thread_id: context.thread.id, + id: operation.id, + }, + {}, + context, + ); + + if (!message) { + logger.error("This message doesn't exists"); + throw Error("Can't edit this message."); + } + + //Update message reactions + updateMessageReactions(message, operation.reactions || [], context.user.id); + + logger.info( + `Updated message ${operation.id} reactions to ${JSON.stringify(message.reactions)} thread ${ + message.thread_id + }`, + ); + await this.repository.save(message, context); + + if ((operation.reactions || []).length === 1 && context.user.id !== message.user_id) { + await gr.platformServices.messageQueue.publish( + "notification:reaction", + { + data: { + thread_id: context.thread.id, + company_id: message.cache?.company_id || context.company.id, + user_id: message.user_id, + message_id: message.id, + workspace_id: message.cache?.workspace_id, + channel_id: message.cache?.channel_id, + creation_date: new Date().getTime(), + reaction: emoji.get(operation.reactions[0]), + reaction_user_id: context.user.id, + }, + }, + ); + } + + this.threadMessagesService.onSaved(message, { created: false }, context); + return new SaveResult("message", message, OperationType.UPDATE); + } + + async bookmark( + operation: BookmarkOperation, + options: Record, + context: ThreadExecutionContext, + ): Promise> { + const message = await this.repository.findOne( + { + thread_id: context.thread.id, + id: operation.id, + }, + {}, + context, + ); + + if (!message) { + logger.error("This message doesn't exists"); + throw Error("Can't edit this message."); + } + + //TODO add message to user bookmarks + message.bookmarks = message.bookmarks.filter( + b => !(b.user_id === context.user.id && b.bookmark_id === operation.bookmark_id), + ); + if (operation.active) { + message.bookmarks.push({ + user_id: context.user.id, + bookmark_id: operation.bookmark_id, + created_at: new Date().getTime(), + }); + } + + logger.info( + `Added bookmark to message ${operation.id} => ${JSON.stringify( + message.bookmarks, + )} to thread ${message.thread_id}`, + ); + await this.repository.save(message, context); + this.threadMessagesService.onSaved(message, { created: false }, context); + + return new SaveResult("message", message, OperationType.UPDATE); + } + + async download( + operation: { id: string; thread_id: string; message_file_id: string }, + options: Record, + context: ThreadExecutionContext, + ) { + //Register download action for reference + localEventBus.publish("message:download", { + user: context.user, + operation: { + message_id: operation.id, + thread_id: operation.thread_id, + message_file_id: operation.message_file_id, + }, + } as MessageFileDownloadEvent); + } + + /** + * Delete a link preview from a message + * + * @param {DeleteLinkOperation} operation - params of the operation + * @param {ThreadExecutionContext} context - Thread execution context + * @returns {Promise>} - Result of the operation + */ + async deleteLinkPreview( + operation: DeleteLinkOperation, + context: ThreadExecutionContext, + ): Promise> { + if ( + !context?.user?.server_request && + !gr.services.messages.threads.checkAccessToThread(context) + ) { + logger.error(`no access ${context.thread.id}`); + throw Error("can't remove link preview from message."); + } + + const message = await this.repository.findOne( + { + thread_id: context.thread.id, + id: operation.message_id, + }, + {}, + context, + ); + + if (!message) { + logger.error("This message doesn't exists"); + throw Error("Can't edit message links previews."); + } + + if (context.user.id !== message.user_id) { + logger.error("You can't remove link preview from another user message."); + throw Error("Can't edit message links previews."); + } + + message.links = message.links.filter(({ url }: { url: string }) => url !== operation.link); + + await this.repository.save(message, context); + this.threadMessagesService.onSaved(message, { created: false }, context); + + return new SaveResult("message", message, OperationType.UPDATE); + } + + /** + * Update message delivery status operation + * + * @param {UpdateDeliveryStatusOperation} operation - the operation params + * @param {ThreadExecutionContext} context - Thread execution context + * @returns {Promise>} - Result of the operation + */ + async updateDeliveryStatus( + operation: UpdateDeliveryStatusOperation, + context: ThreadExecutionContext, + ): Promise> { + if ( + !context?.user?.server_request && + !gr.services.messages.threads.checkAccessToThread(context) + ) { + logger.error(`no access ${context.thread.id}`); + throw Error("can't update message delivery status."); + } + + if (!operation.message_id || !operation.status) { + logger.error("Invalid operation"); + throw Error("Invalid operation"); + } + + if (operation.status !== "delivered" && operation.status !== "read") { + logger.error("Invalid status"); + throw Error("Invalid status"); + } + + const message = await this.repository.findOne( + { + thread_id: context.thread.id, + id: operation.message_id, + }, + {}, + context, + ); + + if (!message) { + logger.error("This message doesn't exists"); + throw Error("Can't update message delivery status."); + } + + if (operation.status === "delivered" && message.status === "delivered") { + logger.error("Message already delivered"); + return; + } + + if (operation.status === "read" && message.status === "read") { + logger.error("Message already read"); + return; + } + + if (operation.status === "delivered" && message.status === "read" && !operation.self_message) { + logger.error("Invalid operation"); + return; + } + + message.status = operation.status; + await this.repository.save(message, context); + this.threadMessagesService.onSaved(message, { created: false }, context); + + return new SaveResult("message", message, OperationType.UPDATE); + } +} diff --git a/twake/backend/node/src/services/messages/services/messages.ts b/twake/backend/node/src/services/messages/services/messages.ts new file mode 100644 index 00000000..7e2f061b --- /dev/null +++ b/twake/backend/node/src/services/messages/services/messages.ts @@ -0,0 +1,1078 @@ +import { + DeleteResult, + ExecutionContext, + ListResult, + OperationType, + Paginable, + Pagination, + SaveResult, +} from "../../../core/platform/framework/api/crud-service"; +import { ResourcePath } from "../../../core/platform/services/realtime/types"; +import { + Initializable, + logger, + RealtimeSaved, + TwakeContext, + TwakeServiceProvider, +} from "../../../core/platform/framework"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import { + getInstance, + Message, + MessagePrimaryKey, + MessageWithUsers, + TYPE as MessageTableName, +} from "../entities/messages"; +import { MessageFile, TYPE as MsgFileTableName } from "../entities/message-files"; +import { + BookmarkOperation, + CompanyExecutionContext, + DeleteLinkOperation, + MessageIdentifier, + MessagesGetThreadOptions, + MessagesSaveOptions, + MessageWithReplies, + MessageWithRepliesWithUsers, + PinOperation, + ReactionOperation, + ThreadExecutionContext, + UpdateDeliveryStatusOperation, +} from "../types"; +import _ from "lodash"; +import { getThreadMessagePath, getThreadMessageWebsocketRoom } from "../web/realtime"; +import { ThreadMessagesOperationsService } from "./messages-operations"; +import { Thread } from "../entities/threads"; +import { UserObject } from "../../user/web/types"; +import { formatUser } from "../../../utils/users"; +import gr from "../../global-resolver"; +import { getDefaultMessageInstance } from "../../../utils/messages"; +import { + buildMessageListPagination, + getLinks, + getMentions, + publishMessageInRealtime, +} from "./utils"; +import { localEventBus } from "../../../core/platform/framework/event-bus"; +import { + KnowledgeGraphEvents, + KnowledgeGraphGenericEventPayload, +} from "../../../core/platform/services/knowledge-graph/types"; +import { MessageUserInboxRef } from "../entities/message-user-inbox-refs"; +import { MessageUserInboxRefReversed } from "../entities/message-user-inbox-refs-reversed"; +import { LinkPreviewMessageQueueRequest } from "../../../services/previews/types"; +import { Thumbnail } from "../../files/entities/file"; +import uuidTime from "uuid-time"; + +export class ThreadMessagesService implements TwakeServiceProvider, Initializable { + version: "1"; + repository: Repository; + msgFilesRepository: Repository; + operations: ThreadMessagesOperationsService; + private messageUserInboxRefsRepository: Repository; + private threadRepository: Repository; + + constructor() { + this.operations = new ThreadMessagesOperationsService(this); + } + + async init(context: TwakeContext): Promise { + this.repository = await gr.database.getRepository(MessageTableName, Message); + this.msgFilesRepository = await gr.database.getRepository( + MsgFileTableName, + MessageFile, + ); + this.messageUserInboxRefsRepository = await gr.database.getRepository( + "message_user_inbox_refs", + MessageUserInboxRef, + ); + + this.threadRepository = await gr.database.getRepository("threads", Thread); + await this.operations.init(context); + return this; + } + + /** + * Save a message + * The server / application / users can do different actions + * @param item + * @param options + * @param context + * @returns SaveResult + */ + async save( + item: Partial, + options?: MessagesSaveOptions, + context?: ThreadExecutionContext, + ): Promise> { + //This can come from: + // - Server want to change the message somehow (the message should already be formated) + // - Application change the message + // - User change its message + // - Pin / Reaction / Bookmark are *not* done here + + const serverRequest = context?.user?.server_request; + const applicationRequest = context?.user?.application_id; + let messageOwnerAndNotRemoved = true; + + item.thread_id = (serverRequest ? item.thread_id : null) || context.thread.id; + const pk = _.pick(item, "thread_id", "id"); + + let messageCreated = !pk.id; + + if (!item.ephemeral) { + if ( + !pk.thread_id || + (!serverRequest && !gr.services.messages.threads.checkAccessToThread(context)) + ) { + logger.error(`Unable to write in thread ${context.thread.id}`); + throw Error("Can't write this message."); + } + } else { + pk.id = undefined; + } + + let message = getDefaultMessageInstance(item, context); + if (pk.id) { + const existingMessage = await this.repository.findOne(pk, {}, context); + if (!existingMessage && !serverRequest) { + logger.error(`This message ${item.id} doesn't exists in thread ${item.thread_id}`); + throw Error("This message doesn't exists."); + } + if (existingMessage) { + message = existingMessage; + messageOwnerAndNotRemoved = + ((context.user?.id && message.user_id === context.user?.id) || + (context.user?.application_id && + message.application_id === context.user?.application_id)) && + message.subtype !== "deleted"; + + if (message.user_id === context.user?.id && context.user?.id) { + message.edited = { + edited_at: new Date().getTime(), + }; + } + } else { + messageCreated = true; + } + } + + const updatable: { [K in keyof Partial]: boolean } = { + ephemeral: serverRequest || messageOwnerAndNotRemoved, + subtype: serverRequest, + text: serverRequest || messageOwnerAndNotRemoved, + blocks: serverRequest || messageOwnerAndNotRemoved, + context: serverRequest || messageOwnerAndNotRemoved, + override: serverRequest || (messageOwnerAndNotRemoved && !!applicationRequest), + }; + Object.keys(updatable).forEach(k => { + if ((updatable as any)[k] && (item as any)[k] !== undefined) { + (message as any)[k] = (item as any)[k]; + } + }); + message = _.assign(message, pk); + + if (context.workspace && context.channel) { + message.cache = { + company_id: context.company.id, + workspace_id: context.workspace.id, + channel_id: context.channel.id, + }; + } + + if (!message.ephemeral) { + if (options.threadInitialMessage) { + message.id = message.thread_id; + } + + logger.info(`Saved message in thread ${message.thread_id}`); + await this.repository.save(message, context); + } else { + logger.info(`Did not save ephemeral message in thread ${message.thread_id}`); + } + + if (serverRequest || messageOwnerAndNotRemoved) { + message = await this.completeMessage( + message, + { files: item.files || message.files || [] }, + context, + ); + } + + await this.onSaved(message, { created: messageCreated }, context); + + if (context.channel) { + localEventBus.publish>( + KnowledgeGraphEvents.MESSAGE_UPSERT, + { + id: message.id, + resource: message, + links: [{ relation: "parent", type: "channel", id: context.channel.id }], + }, + ); + } + + return new SaveResult( + "message", + message, + messageCreated ? OperationType.CREATE : OperationType.UPDATE, + ); + } + + /** + * Move a message from a thread to another + * @param item + * @param options + * @param context + * @returns + */ + async move( + pk: Pick, + options: { previous_thread: string }, + context: ThreadExecutionContext, + ): Promise { + logger.debug( + `Try to move message ${pk.id} from thread ${options.previous_thread} to thread ${context.thread.id}`, + ); + + if (options.previous_thread === context.thread.id) { + return; + } + + //Move replies if it was a thread head message + if (pk.id === options.previous_thread) { + let nextPage: Pagination = { limitStr: "100" }; + do { + const replies = await this.list( + nextPage, + {}, + { + user: { id: null, server_request: true }, + thread: { id: pk.id }, + company: { id: context.company.id }, + }, + ); + + for (const reply of replies.getEntities()) { + //Do not create an infinite loop + if (reply.id !== options.previous_thread) { + logger.debug( + `Try to move reply ${reply.id} to message ${pk.id} from thread ${reply.thread_id} to thread ${context.thread.id}`, + ); + + await gr.services.messages.messages.move( + { id: reply.id || undefined }, + { + previous_thread: reply.thread_id, + }, + context, + ); + } + } + + nextPage = replies.nextPage as Pagination; + } while (nextPage.page_token); + } + + const messageInOldThread = await this.repository.findOne( + { + thread_id: options.previous_thread, + id: pk.id, + }, + {}, + context, + ); + + if (!messageInOldThread) { + logger.error(`Unable to find message ${pk.id} in old thread ${context.thread.id}`); + throw Error("Can't move this message."); + } + + //Check new thread exists + let thread = await gr.services.messages.threads.get({ id: context.thread.id }, context); + if (!thread && `${context.thread.id}` === `${pk.id}`) { + logger.info("Create empty thread for message moved out of thread"); + const oldThread = await gr.services.messages.threads.get( + { id: options.previous_thread }, + context, + ); + const upgradedContext = _.cloneDeep(context); + upgradedContext.user.server_request = true; + thread = ( + await gr.services.messages.threads.save( + { + id: messageInOldThread.id, + participants: oldThread.participants, + }, + {}, + upgradedContext, + ) + )?.entity; + } + if (!thread) { + throw Error("Can't move this message to inexistent thread."); + } + + const messageInNewThread = _.cloneDeep(messageInOldThread); + messageInNewThread.thread_id = context.thread.id; + + await this.repository.save(messageInNewThread, context); + + await this.onSaved(messageInNewThread, { created: true }, context); + + await this.repository.remove(messageInOldThread, context); + await gr.services.messages.threads.addReply(messageInOldThread.thread_id, -1, context); + + logger.info( + `Moved message ${pk.id} from thread ${options.previous_thread} to thread ${context.thread.id}`, + ); + + return; + } + + async forceDelete(pk: Message, context?: ThreadExecutionContext): Promise> { + return this.delete(pk, context, true); + } + + async delete( + pk: Message, + context?: ThreadExecutionContext, + forceDelete: boolean = false, + ): Promise> { + if ( + !context?.user?.server_request && + !gr.services.messages.threads.checkAccessToThread(context) + ) { + logger.error(`Unable to write in thread ${context.thread.id}`); + throw Error("Can't edit this message."); + } + + const message = await this.repository.findOne( + { + thread_id: context.thread.id, + id: pk.id, + }, + {}, + context, + ); + + if (!message) { + logger.error( + "This message does not exists, only remove it on websockets (ephemeral message)", + ); + + const msg = getInstance({ + subtype: "deleted", + ...pk, + }); + + msg.ephemeral = pk.ephemeral || { + id: pk.id, + version: "", + recipient: "", + recipient_context_id: "", + }; + + await this.onSaved(msg, { created: false }, context); + + return new DeleteResult("message", msg, true); + } + + if ( + !context?.user?.server_request && + message.user_id !== context.user.id && + message.application_id !== context?.user?.application_id + ) { + logger.error("You have no right to delete this message"); + throw Error("Can't delete this message."); + } + + message.subtype = "deleted"; + message.blocks = []; + message.reactions = []; + message.text = "Deleted message"; + message.files = []; + + logger.info(`Deleted message ${pk.id} from thread ${message.thread_id}`); + await this.repository.save(message, context); + await this.onSaved(message, { created: false }, context); + + //Only server and application can definively remove a message + if ( + (forceDelete && (context.user.server_request || context.user.application_id)) || + message.application_id + ) { + await this.repository.remove(message, context); + } + + return new DeleteResult("message", message, true); + } + + async get( + pk: Pick, + context?: ThreadExecutionContext, + options?: { includeQuoteInMessage?: boolean }, + ): Promise { + const thread = await gr.services.messages.threads.get({ id: pk.id }, context); + let message; + if (thread) { + message = await this.getThread(thread, options, context); + } else { + message = await this.getSingleMessage(pk, options, context); + } + return message; + } + + private async getSingleMessage( + pk: Pick, + options?: { includeQuoteInMessage?: boolean }, + context?: ExecutionContext, + ) { + let message = await this.repository.findOne(pk, {}, context); + if (message) { + message = await this.completeMessage( + message, + { + files: message.files || [], + includeQuoteInMessage: options?.includeQuoteInMessage, + }, + context, + ); + } + return message; + } + + async getThread( + thread: Thread, + options: MessagesGetThreadOptions = {}, + context?: ExecutionContext, + ): Promise { + const lastRepliesUncompleted = ( + await this.repository.find( + { + thread_id: thread.id, + }, + { + pagination: new Pagination("", `${options?.replies_per_thread || 3}`, false), + }, + context, + ) + ).getEntities(); + + const lastReplies: Message[] = []; + for (const lastReply of lastRepliesUncompleted) { + if (lastReply) + lastReplies.push( + await this.completeMessage(lastReply, { files: lastReply.files || [] }, context), + ); + } + + const firstMessage = await this.getSingleMessage( + { + thread_id: thread.id, + id: thread.id, + }, + {}, + context, + ); + + return { + ...firstMessage, + stats: { + replies: lastReplies.length === 1 ? 1 : thread.answers, //This line ensure the thread can be deleted by user if there is no replies + last_activity: thread.last_activity, + }, + last_replies: lastReplies.sort((a, b) => a.created_at - b.created_at), + }; + } + + async list( + pagination: Paginable, + options?: ListOption, + context?: ThreadExecutionContext, + ): Promise> { + const list = await this.repository.find( + { thread_id: context.thread.id }, + buildMessageListPagination(Pagination.fromPaginable(pagination), "id"), + context, + ); + + //Get complete details about initial message + if ( + list + .getEntities() + .map(m => `${m.id}`) + .includes(`${context.thread.id}`) + ) { + const initialMessage = await this.get( + { thread_id: context.thread.id, id: context.thread.id }, + context, + ); + list.mapEntities((m: any) => { + if (`${m.id}` === `${initialMessage.id}`) { + return initialMessage; + } + return m; + }); + } + + const extendedList = []; + for (const m of list.getEntities()) { + extendedList.push(await this.completeMessage(m, {}, context)); + } + + return new ListResult("messages", extendedList, list.nextPage); + } + + async includeUsersInMessage( + message: Message, + context?: ExecutionContext, + ): Promise { + let ids: string[] = []; + if (message.user_id) ids.push(message.user_id); + if (message.pinned_info?.pinned_by) ids.push(message.pinned_info?.pinned_by); + const mentions = await getMentions(message, async (username: string) => { + return await gr.services.users.getByUsername(username); + }); + for (const mentionedUser of mentions.users) { + ids.push(mentionedUser); + } + ids = _.uniq(ids); + + const users: UserObject[] = []; + for (const id of ids) { + const user = await gr.services.users.getCached({ id }); + if (user) users.push(await formatUser(user)); + } + + let application = null; + if (message.application_id) { + application = await gr.services.applications.marketplaceApps.get( + { + id: message.application_id, + }, + context, + ); + } + + const messageWithUsers: MessageWithUsers = { ...message, users, application }; + + if (message.quote_message && (message.quote_message as any).id) { + messageWithUsers.quote_message = { + ...(await this.includeUsersInMessage(message.quote_message as any, context)), + ...quoteMessageKeys(message), + }; + } + + return messageWithUsers; + } + + async includeUsersInMessageWithReplies( + message: MessageWithReplies, + context?: ExecutionContext, + ): Promise { + let last_replies = undefined; + for (const reply of message.last_replies || []) { + if (!last_replies) last_replies = []; + last_replies.push(await this.includeUsersInMessage(reply, context)); + } + + let highlighted_replies = undefined; + for (const reply of message.highlighted_replies || []) { + if (!highlighted_replies) highlighted_replies = []; + highlighted_replies.push(await this.includeUsersInMessage(reply, context)); + } + + let thread: MessageWithRepliesWithUsers = undefined; + if (message.thread) { + thread = await this.includeUsersInMessageWithReplies(message.thread, context); + } + + const messageWithUsers = { + ...message, + users: (await this.includeUsersInMessage(message, context)).users, + last_replies, + ...(highlighted_replies ? { highlighted_replies } : {}), + ...(thread ? { thread } : {}), + } as MessageWithRepliesWithUsers; + + return messageWithUsers; + } + + async onSaved(message: Message, options: { created?: boolean }, context: ThreadExecutionContext) { + if (options.created && !message.ephemeral) { + const messageLinks = getLinks(message); + + gr.platformServices.messageQueue.publish( + "services:preview:links", + { + data: { + links: messageLinks, + message: { + context, + resource: message, + created: options?.created, + }, + }, + }, + ); + + await gr.services.messages.threads.addReply(message.thread_id, 1, context); + try { + await gr.services.channels.members.setChannelMemberReadSections( + { + start: message.id, + end: message.id, + }, + { + ...context, + channel_id: message.cache.channel_id, + workspace_id: message.cache.workspace_id, + }, + ); + } catch (error) { + logger.error("failed to set read sections"); + } + } + + //Depreciated way of doing this was localEventBus.publish("message:saved") + await gr.services.messages.engine.dispatchMessage({ + resource: message, + context: context, + created: options.created, + }); + + return await this.shareMessageInRealtime(message, { message, ...options }, context); + } + + async shareMessageInRealtime( + pk: MessagePrimaryKey, + options: { message?: Message; created?: boolean }, + context: ThreadExecutionContext, + ): Promise> { + let message = + options?.message || + (await gr.services.messages.messages.get(pk, context, { + includeQuoteInMessage: true, + })); + + if (!message) return null; + message = await this.includeUsersInMessage(message, context); + + publishMessageInRealtime( + { resource: message, created: options.created, context }, + { + type: "channel", + id: message.cache?.channel_id || context?.channel?.id, + company_id: message.cache?.company_id || context?.company?.id, + workspace_id: message.cache?.workspace_id || context.workspace?.id, + }, + ); + } + + async pin( + operation: PinOperation, + options: Record, + context: ThreadExecutionContext, + ): Promise> { + return this.operations.pin(operation, options, context); + } + + async reaction( + operation: ReactionOperation, + options: Record, + context: ThreadExecutionContext, + ): Promise> { + return this.operations.reaction(operation, options, context); + } + + async bookmark( + operation: BookmarkOperation, + options: Record, + context: ThreadExecutionContext, + ): Promise> { + return this.operations.bookmark(operation, options, context); + } + + async download( + operation: { id: string; thread_id: string; message_file_id: string }, + options: Record, + context: ThreadExecutionContext, + ): Promise { + return this.operations.download(operation, options, context); + } + + //Complete message with all missing information and cache + async completeMessage( + message: Message, + options: { files?: Message["files"]; includeQuoteInMessage?: boolean } = {}, + context: ExecutionContext, + ) { + this.fixReactionsFormat(message, context); + try { + if (options.files) message = await this.completeMessageFiles(message, options.files || []); + } catch (err) { + console.log(err); + logger.warn("Error while completing message files"); + } + + //Mobile retro compatibility + if ((message.blocks?.length || 0) === 0) { + message.blocks = message.blocks || []; + message.blocks.push({ + type: "twacode", + elements: [message.text], + }); + } + + //Add quote message + if (options?.includeQuoteInMessage !== false) + message = await this.includeQuoteInMessage(message); + + return message; + } + + async includeQuoteInMessage(message: MessageWithUsers): Promise { + if (message.quote_message && (message.quote_message as Message["quote_message"]).id) { + message.quote_message = { + ...(await this.includeUsersInMessage( + await this.getSingleMessage( + { + thread_id: (message.quote_message as Message["quote_message"]).thread_id, + id: (message.quote_message as Message["quote_message"]).id, + }, + { includeQuoteInMessage: false }, + ), + )), + ...quoteMessageKeys(message), + }; + } + return message; + } + + //Fix https://github.com/linagora/Twake/issues/1559 + async fixReactionsFormat(message: Message, context: ExecutionContext) { + if (message.reactions?.length > 0) { + let foundError = false; + message.reactions.map(r => { + if (!(r.users?.length > 0)) { + foundError = true; + r.users = Object.values(r.users); + } + }); + if (foundError) await this.repository.save(message, context); + } + } + + async completeMessageFiles( + message: Message, + files: Message["files"], + context?: ExecutionContext, + ) { + if (files.length === 0 && (message.files || []).length === 0) { + return message; + } + + let didChange = false; + + files = files.map(f => { + f.message_id = message.id; + return f; + }); + + const sameFile = (a: MessageFile["metadata"], b: MessageFile["metadata"]) => { + return _.isEqual(a.external_id, b.external_id) && a.source === b.source; + }; + + //Delete all existing msg files not in the new files object + const existingMsgFiles = ( + await this.msgFilesRepository.find( + { + message_id: message.id, + }, + {}, + context, + ) + ).getEntities(); + for (const entity of existingMsgFiles) { + if (!files.some(f => sameFile(f.metadata, entity.metadata))) { + await this.msgFilesRepository.remove(entity, context); + } + } + + //Ensure all files in the file object are in the message + const previousMessageFiles = message.files; + message.files = []; + for (const file of files) { + let existing = existingMsgFiles.filter(e => sameFile(e.metadata, file.metadata))[0]; + const entity = existing || new MessageFile(); + entity.message_id = message.id; + entity.thread_id = message.thread_id; + entity.id = file.id || undefined; + entity.company_id = file.company_id || message.cache?.company_id; + entity.cache = { + company_id: message.cache?.company_id, + workspace_id: message.cache?.workspace_id, + channel_id: message.cache?.channel_id, + user_id: message.user_id, + }; + entity.created_at = file.created_at || new Date().getTime(); + + //If it is defined it should exists + let messageFileExistOnDb = false; + try { + messageFileExistOnDb = !!(await this.msgFilesRepository.findOne( + { + message_id: message.id, + id: entity.id, + }, + {}, + context, + )); + } catch (e) {} + if (entity.id && !messageFileExistOnDb) { + existing = null; + entity.id = undefined; + } + + //For internal files, we have a special additional sync + if (file.metadata?.source == "internal") { + //Test external id format + if ( + message.files.length === 0 && + (typeof file.metadata.external_id === "string" || + !file.metadata.external_id?.company_id || + !file.metadata.external_id?.id) + ) { + console.log("File external_id format is wrong for source internal"); + continue; + } + + const original = await gr.services.files.get(file.metadata.external_id?.id as string, { + user: { id: "", server_request: true }, + company: { id: file.metadata.external_id?.company_id as string }, + }); + if (original) { + file.metadata = { + ...file.metadata, + ..._.pick(original.metadata, "mime", "name"), + ..._.pick(original.upload_data, "size"), + source: "internal", + external_id: file.metadata.external_id, + }; + file.metadata.thumbnails = (file.metadata.thumbnails || original.thumbnails || []).map( + (t: Thumbnail, index: number) => { + t.url = gr.services.files.getThumbnailRoute(original, (t.index || index).toString()); + return t; + }, + ); + } + } + + entity.metadata = file.metadata; + + if (!existing || !_.isEqual(existing.metadata, entity.metadata)) { + didChange = true; + await this.msgFilesRepository.save(entity, context); + } + + message.files.push(entity); + } + + if (!_.isEqual(previousMessageFiles.map(a => a.id).sort(), message.files.map(a => a.id).sort())) + didChange = true; + + if (didChange) { + await this.repository.save(message, context); + } + + return message; + } + + async inbox( + userId: string, + context: CompanyExecutionContext, + pagination: Pagination, + ): Promise> { + let nextPage = null; + + async function* getNextThreads( + refRepo: Repository, + ): AsyncIterableIterator { + let lastPageToken = pagination.page_token; + let hasMore = true; + do { + const threadsIds = await refRepo + .find( + { + company_id: context.company.id, + user_id: userId, + }, + { pagination: new Pagination(lastPageToken, pagination.limitStr) }, + context, + ) + .then((a: ListResult) => { + lastPageToken = a.nextPage.page_token; + nextPage = a.nextPage; + if (!lastPageToken) { + hasMore = false; + } + return a.getEntities().map(a => a.thread_id); + }); + + if (threadsIds.length) { + for (const threadId of threadsIds) { + yield threadId; + } + } else { + hasMore = false; + } + } while (hasMore); + } + + const threadsIds = []; + const threadsIdsMap: { [key: string]: boolean } = {}; + + for await (const id of getNextThreads(this.messageUserInboxRefsRepository)) { + if (!threadsIdsMap[id]) { + threadsIdsMap[id] = true; + threadsIds.push(id); + } + if (threadsIds.length == +pagination.limitStr) { + break; + } + } + + const msgPromises = threadsIds.map(id => + this.repository.findOne({ thread_id: id, id }, {}, context), + ); + return new ListResult("message", await Promise.all(msgPromises), nextPage); + } + + /** + * Deletes a link preview from message operation + * + * @param {DeleteLinkOperation} operation - The delete link operation + * @param {ThreadExecutionContext} context - The thread execution context + * @returns + */ + async deleteLinkPreview( + operation: DeleteLinkOperation, + context: ThreadExecutionContext, + ): Promise> { + return this.operations.deleteLinkPreview(operation, context); + } + + /** + * Updates the message delivery status to delivered or read. + * + * @param {UpdateDeliveryStatusOperation} operation - The update delivery status operation + * @param {ThreadExecutionContext} context - The thread execution context + * @returns {Promise>} - The save result + */ + async updateDeliveryStatus( + operation: UpdateDeliveryStatusOperation, + context: ThreadExecutionContext, + ): Promise> { + return this.operations.updateDeliveryStatus(operation, context); + } + + /** + * Updates the messages delivery status to read. + * + * @param {MessageReadType} messages - The messages to mark as read + * @param {CompanyExecutionContext & { channel_id: string; workspace_id: string }} context - The company execution context + * @returns {Promise} - The promise result of the operation + */ + async read( + messages: MessageIdentifier[], + context: CompanyExecutionContext & { channel_id: string; workspace_id: string }, + ): Promise { + const timestamps = messages + .map(({ message_id }) => ({ + message_id, + timestamp: uuidTime.v1(message_id), + })) + .sort((a, b) => a.timestamp - b.timestamp); + + const read_section = { + start: timestamps[0].message_id, + end: timestamps[timestamps.length - 1].message_id, + }; + + await gr.services.channels.members.setChannelMemberReadSections(read_section, context); + + const updates = await Promise.all( + messages.map(async message => { + const readOperation: UpdateDeliveryStatusOperation = { + ...message, + status: "read", + }; + + return this.updateDeliveryStatus(readOperation, { + ...context, + thread: { id: message.thread_id }, + }); + }), + ); + + return updates.every(item => !!item); + } + + /** + * List users who've seen the specified message + * + * @param { String} id - the message id + * @param {ThreadExecutionContext} context - the thread execution context + * @returns {Promise} - the users list + */ + async listSeenBy(id: string, context: ThreadExecutionContext): Promise { + try { + const message = await this.repository.findOne( + { + thread_id: context.thread.id, + id, + }, + {}, + context, + ); + + if (!message) { + logger.error(`message ${id} doesn't exist`); + throw Error("failed to list seen by users: message doesn't exist"); + } + + const channelContext = { + ...context, + channel: { + id: message.cache.channel_id, + company_id: context.company.id, + workspace_id: context.workspace.id, + }, + }; + + return await gr.services.channels.members.getChannelMessageSeenByUsers(id, channelContext); + } catch (error) { + logger.error(error); + return []; + } + } +} + +const quoteMessageKeys = ( + message: Message, +): { channel_id: string; workspace_id: string; company_id: string } => { + return { + channel_id: + message.quote_message?.channel_id || + message.quote_message?.cache?.channel_id || + message.cache.channel_id, + workspace_id: + message.quote_message?.workspace_id || + message.quote_message?.cache?.workspace_id || + message.cache.workspace_id, + company_id: + message.quote_message?.company_id || + message.quote_message?.cache?.company_id || + message.cache.company_id, + }; +}; diff --git a/twake/backend/node/src/services/messages/services/threads.ts b/twake/backend/node/src/services/messages/services/threads.ts new file mode 100644 index 00000000..5f1b2471 --- /dev/null +++ b/twake/backend/node/src/services/messages/services/threads.ts @@ -0,0 +1,309 @@ +import { + DeleteResult, + ExecutionContext, + ListResult, + OperationType, + SaveResult, +} from "../../../core/platform/framework/api/crud-service"; +import { + Initializable, + logger, + RealtimeSaved, + TwakeServiceProvider, +} from "../../../core/platform/framework"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import { ParticipantObject, Thread } from "../entities/threads"; +import { CompanyExecutionContext, ThreadExecutionContext } from "../types"; +import { Message, MessageWithUsers } from "../entities/messages"; +import _ from "lodash"; +import { extendExecutionContentWithChannel } from "../web/controllers"; +import gr from "../../global-resolver"; +import { ResourcePath } from "../../../core/platform/services/realtime/types"; +import { getThreadMessagePath, getThreadMessageWebsocketRoom } from "../web/realtime"; + +export class ThreadsService implements TwakeServiceProvider, Initializable { + version: "1"; + name: "ThreadsService"; + repository: Repository; + + async init(): Promise { + this.repository = await gr.database.getRepository("threads", Thread); + return this; + } + + /** + * Create a thread with its first message in it + * @param item + * @param options + * @param context + * @returns + */ + async save( + item: Pick & { + participants: Pick[]; + }, + options: { participants?: ParticipantOperation; message?: Message } = {}, + context?: CompanyExecutionContext, + ): Promise> { + if (item.id) { + //Update + const participantsOperation: ParticipantOperation = options.participants || { + add: [], + remove: [], + }; + + const thread = await this.repository.findOne({ id: item.id }, {}, context); + + if (thread) { + // Add the created_by information + participantsOperation.add = (participantsOperation.add || []).map(p => { + return { + created_by: context.user.id, + created_at: new Date().getTime(), + ...p, + }; + }) as ParticipantObject[]; + + thread.participants = _.uniqBy( + _.differenceBy( + [...thread.participants, ...participantsOperation.add], + participantsOperation.remove || [], + p => p.id, + ), + p => p.id, + ) as ParticipantObject[]; + + await this.repository.save(thread, context); + + //TODO ensure the thread is in all participants views (and removed from deleted participants) + + return new SaveResult( + "thread", + await this.getWithMessage({ id: thread.id }), + OperationType.UPDATE, + ); + } else { + //Thread to edit does not exists + + if (!context.user?.server_request) { + throw new Error("ThreadService: Unable to edit inexistent thread"); + } + } + } + + //Creation of thread or server edition + if (!options.message) { + if (context.user?.server_request) { + logger.info(`${this.name} - Create empty thread by server itself`); + } else { + throw new Error("You must provide an initial message in the thread."); + } + } + + //Enforce current user in the participants list and add the created_by information + const participants: ParticipantObject[] = [ + context.user.application_id ? {} : { type: "user", id: context.user.id }, + ...item.participants, + ].map(p => { + return { + created_by: context.user.id, + created_at: new Date().getTime(), + ...p, + }; + }) as ParticipantObject[]; + + const message: Message | null = options.message || null; + + const thread = new Thread(); + thread.created_at = new Date().getTime(); + thread.last_activity = thread.created_at; + thread.answers = 0; + thread.created_by = context.user.id; + thread.participants = _.uniqBy(participants, p => p.id); + + //If server request, we allow more + if (context.user?.server_request) { + thread.id = item.id; + thread.created_at = (item as Thread)?.created_at || thread.created_at; + } + + if (message && message.ephemeral) { + //We should not save if this is an ephemeral message + } else { + await this.repository.save(thread, context); + } + + if (message) { + message.status = "sent"; + + const result = await gr.services.messages.messages.save( + message, + { + threadInitialMessage: true, + }, + extendExecutionContentWithChannel( + participants, + Object.assign(context, { thread: { id: thread.id, company_id: context.company.id } }), + ), + ); + try { + const channelMembersCount = await gr.services.channels.members.getUsersCount({ + id: result.entity.cache.channel_id, + company_id: result.entity.cache.company_id, + workspace_id: result.entity.cache.workspace_id, + counter_type: "members", + }); + + if (channelMembersCount === 1) { + await gr.services.messages.messages.updateDeliveryStatus( + { + message_id: result.entity.id, + self_message: true, + status: "read", + thread_id: result.entity.thread_id, + }, + { + ...context, + thread: { id: thread.id }, + }, + ); + + await gr.services.channels.members.setChannelMemberReadSections( + { + start: result.entity.id, + end: result.entity.id, + }, + { + ...context, + channel_id: result.entity.cache.channel_id, + workspace_id: result.entity.cache.workspace_id, + }, + ); + } + } catch (err) { + logger.error("failed to update message delivery status"); + } + } + + return new SaveResult( + "thread", + await this.getWithMessage({ id: thread.id }), + OperationType.CREATE, + ); + } + + /** + * Add reply to thread: increase last_activity time and number of answers + * @param threadId + * @param increment + * @param context + */ + async addReply(threadId: string, increment: number = 1, context: ThreadExecutionContext) { + const thread = await this.repository.findOne({ id: threadId }, {}, context); + if (thread) { + thread.answers = Math.max(0, (thread.answers || 0) + increment); + if (increment > 0) { + thread.last_activity = new Date().getTime(); + } + await this.repository.save(thread, context); + } else { + throw new Error("Try to add reply count to inexistent thread"); + } + + await gr.services.messages.messages.shareMessageInRealtime( + { + id: threadId, + thread_id: threadId, + }, + {}, + context, + ); + } + + /** + * Add reply to thread: increase last_activity time and number of answers + * @param threadId + */ + async setReplyCount(threadId: string, count: number, context: ExecutionContext) { + const thread = await this.repository.findOne({ id: threadId }, {}, context); + if (thread) { + thread.answers = count; + await this.repository.save(thread, context); + } else { + throw new Error("Try to add reply count to inexistent thread"); + } + } + + /** + * Check context is allowed to accesss a thread + * @param context + * @returns + */ + async checkAccessToThread(context: ThreadExecutionContext): Promise { + if (context?.user?.server_request) { + return true; + } + + logger.info( + `Check access to thread ${context.thread.id} in company ${context.company.id} for user ${context.user.id} and app ${context?.user?.application_id}`, + ); + + const thread = await this.repository.findOne( + { + id: context.thread.id, + }, + {}, + context, + ); + + if (!thread) { + logger.info("No such thread"); + return false; + } + + //User is participant of the thread directly + if (thread.participants.some(p => p.type === "user" && p.id === context.user.id)) { + return true; + } + + //Check user is in one of the participant channels + //TODO: get the channel_member from channel micro_service + + return false; + } + + get(pk: Pick, context: ExecutionContext): Promise { + return this.repository.findOne(pk, {}, context); + } + + async getWithMessage( + pk: Pick, + context?: ExecutionContext, + ): Promise { + const thread = await this.get(pk, context); + return { + ...thread, + message: await gr.services.messages.messages.get( + { id: pk.id, thread_id: pk.id }, + context as ThreadExecutionContext, + ), + }; + } + + async delete(pk: Pick, context?: ExecutionContext): Promise> { + const thread = await this.repository.findOne({ id: pk.id }, {}, context); + if (context.user.server_request) { + await this.repository.remove(thread, context); + } + return new DeleteResult("thread", thread, context.user.server_request && !!thread); + } + + list(): Promise> { + throw new Error("CRUD method not used."); + } +} + +type ParticipantOperation = { + add: Pick[]; + remove: Pick[]; +}; diff --git a/twake/backend/node/src/services/messages/services/user-bookmarks.ts b/twake/backend/node/src/services/messages/services/user-bookmarks.ts new file mode 100644 index 00000000..cba0fa88 --- /dev/null +++ b/twake/backend/node/src/services/messages/services/user-bookmarks.ts @@ -0,0 +1,110 @@ +import { + DeleteResult, + ExecutionContext, + ListResult, + OperationType, + Pagination, + SaveResult, +} from "../../../core/platform/framework/api/crud-service"; +import { + Initializable, + RealtimeDeleted, + RealtimeSaved, + TwakeServiceProvider, +} from "../../../core/platform/framework"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import { getInstance, UserMessageBookmark } from "../entities/user-message-bookmarks"; +import { CompanyExecutionContext } from "../types"; +import { ResourcePath } from "../../../core/platform/services/realtime/types"; +import { getUserBookmarksWebsocketRoom } from "../web/realtime"; +import gr from "../../global-resolver"; + +export class UserBookmarksService implements TwakeServiceProvider, Initializable { + version: "1"; + repository: Repository; + + async init(): Promise { + this.repository = await gr.database.getRepository( + "user_message_bookmarks", + UserMessageBookmark, + ); + return this; + } + + get( + pk: Pick, + context: CompanyExecutionContext, + ): Promise { + return this.repository.findOne(pk, {}, context); + } + + @RealtimeSaved((bookmark, context) => [ + { + room: ResourcePath.get(getUserBookmarksWebsocketRoom(context as CompanyExecutionContext)), + path: getUserBookmarksWebsocketRoom(context as CompanyExecutionContext) + "/" + bookmark.id, + }, + ]) + async save( + { company_id, user_id, id, name }: SaveParams, + context: CompanyExecutionContext, + ): Promise> { + //Disallow duplicates + const entities = (await this.list({ user_id, company_id }, context)).getEntities(); + + for (const entity of entities) { + if (name === entity.name) { + return new SaveResult( + "user_message_bookmark", + entity, + OperationType.EXISTS, + ); + } + } + + const instance = getInstance({ + company_id: company_id, + user_id: user_id, + name, + }); + if (id) { + instance.id = id; + } + await this.repository.save(instance, context); + + return new SaveResult( + "user_message_bookmark", + instance, + id ? OperationType.UPDATE : OperationType.CREATE, + ); + } + + @RealtimeDeleted((bookmark, context) => [ + { + room: ResourcePath.get(getUserBookmarksWebsocketRoom(context as CompanyExecutionContext)), + path: getUserBookmarksWebsocketRoom(context as CompanyExecutionContext) + "/" + bookmark.id, + }, + ]) + async delete( + pk: Pick, + context?: CompanyExecutionContext, + ): Promise> { + const instance = await this.repository.findOne(pk, {}, context); + if (instance) await this.repository.remove(instance, context); + return new DeleteResult("user_message_bookmark", instance, !!instance); + } + + async list( + { user_id, company_id, pagination }: ListParams, + context: ExecutionContext, + ): Promise> { + return this.repository.find({ user_id, company_id }, { pagination }, context); + } +} + +type SaveParams = { user_id: string; company_id: string; name: string; id: string; test?: string }; + +type ListParams = { + company_id: string; + user_id: string; + pagination?: Pagination; +}; diff --git a/twake/backend/node/src/services/messages/services/utils.ts b/twake/backend/node/src/services/messages/services/utils.ts new file mode 100644 index 00000000..48a97900 --- /dev/null +++ b/twake/backend/node/src/services/messages/services/utils.ts @@ -0,0 +1,104 @@ +import { FindOptions } from "../../../core/platform/services/database/services/orm/repository/repository"; +import { + CreateResult, + Pagination, + UpdateResult, +} from "../../../core/platform/framework/api/crud-service"; +import { Message } from "../entities/messages"; +import { MessageLocalEvent, SpecialMention, ThreadExecutionContext } from "../types"; +import User from "../../../services/user/entities/user"; +import { RealtimeEntityActionType } from "../../../core/platform/services/realtime/types"; +import { getThreadMessagePath } from "../web/realtime"; +import { ResourcePath } from "../../../core/platform/services/realtime/types"; +import { RealtimeLocalBusEvent } from "../../../core/platform/services/realtime/types"; +import { localEventBus } from "../../../core/platform/framework/event-bus"; +import { ParticipantObject } from "../entities/threads"; + +export const buildMessageListPagination = ( + pagination: Pagination, + messageIdKey: string, +): FindOptions => { + const offset = pagination.page_token; + pagination = { ...pagination, page_token: null }; + return { + pagination, + ...(!!offset && pagination.reversed && { $gte: [[messageIdKey, offset]] }), + ...(!!offset && !pagination.reversed && { $lte: [[messageIdKey, offset]] }), + }; +}; + +export const getMentions = async ( + messageResource: Message, + findByUsername: (username: string) => Promise, +) => { + const idsFromUsernames = []; + try { + const usersNoIdOutput = (messageResource.text || "").match(/( |^)@[a-zA-Z0-9-_.]+/gm); + const usernames = (usersNoIdOutput || []).map(u => (u || "").trim().split("@").pop()); + for (const username of usernames) { + if (!"all|here|channel|everyone".split("|").includes(username)) { + const user = await findByUsername(username); + if (user) idsFromUsernames.push(user.id); + } + } + } catch (err) { + console.log(err); + } + + const usersOutput = (messageResource.text || "").match(/@[^: ]+:([0-f-]{36})/gm); + const globalOutput = (messageResource.text || "").match( + /(^| )@(all|here|channel|everyone)([^a-z]|$)/gm, + ); + + return { + users: [ + ...(usersOutput || []).map(u => (u || "").trim().split(":").pop()), + ...idsFromUsernames, + ], + specials: (globalOutput || []).map(g => (g || "").trim().split("@").pop()) as SpecialMention[], + }; +}; + +/** + * extracts the links from a message + * + * @param {Message} messageResource - The message to be parsed + * @returns {String} - links found in the message + */ +export const getLinks = (messageResource: Message): string[] => { + const cleanText = messageResource.text.replace(/\n+/gm, " "); + const links = (cleanText || "").match(/https?:\/\/[^ ]+/gm); + + return links || []; +}; + +/** + * Publish a message to the realtime bus + * + * @param {MessageLocalEvent} message - The event to be published + * @param {ParticipantObject} participant - The participant + */ +export const publishMessageInRealtime = ( + message: MessageLocalEvent, + participant: Omit, +): void => { + if (participant.type !== "channel") return; + + const room = `/companies/${participant.company_id}/workspaces/${participant.workspace_id}/channels/${participant.id}/feed`; + const type = "message"; + const entity = message.resource; + const context = message.context; + + localEventBus.publish("realtime:publish", { + topic: message.created ? RealtimeEntityActionType.Created : RealtimeEntityActionType.Updated, + event: { + type, + room: ResourcePath.get(room), + resourcePath: getThreadMessagePath(context as ThreadExecutionContext) + "/" + entity.id, + entity, + result: message.created + ? new CreateResult(type, entity) + : new UpdateResult(type, entity), + }, + } as RealtimeLocalBusEvent); +}; diff --git a/twake/backend/node/src/services/messages/services/views.ts b/twake/backend/node/src/services/messages/services/views.ts new file mode 100644 index 00000000..22a0e415 --- /dev/null +++ b/twake/backend/node/src/services/messages/services/views.ts @@ -0,0 +1,456 @@ +import _, { uniqBy } from "lodash"; +import { Initializable, TwakeServiceProvider } from "../../../core/platform/framework"; +import { + ExecutionContext, + ListResult, + Paginable, + Pagination, +} from "../../../core/platform/framework/api/crud-service"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import SearchRepository from "../../../core/platform/services/search/repository"; +import { fileIsMedia } from "../../../services/files/utils"; +import { formatUser } from "../../../utils/users"; +import gr from "../../global-resolver"; +import { MessageChannelMarkedRef } from "../entities/message-channel-marked-refs"; +import { MessageChannelRef } from "../entities/message-channel-refs"; +import { MessageFileRef } from "../entities/message-file-refs"; +import { MessageFile } from "../entities/message-files"; +import { Message } from "../entities/messages"; +import { Thread } from "../entities/threads"; +import { + ChannelViewExecutionContext, + CompanyExecutionContext, + FlatFileFromMessage, + FlatPinnedFromMessage, + MessageViewListOptions, + MessageWithReplies, + SearchMessageFilesOptions, + SearchMessageOptions, +} from "../types"; +import { FileSearchResult } from "../web/controllers/views/search-files"; +import { buildMessageListPagination } from "./utils"; + +export class ViewsServiceImpl implements TwakeServiceProvider, Initializable { + version: "1"; + repositoryChannelRefs: Repository; + repositoryThreads: Repository; + repositoryFilesRef: Repository; + repositoryMessageFile: Repository; + repositoryMarkedRef: Repository; + searchRepository: SearchRepository; + searchFilesRepository: SearchRepository; + + async init(): Promise { + this.searchRepository = gr.platformServices.search.getRepository("messages", Message); + this.searchFilesRepository = gr.platformServices.search.getRepository( + "message_files", + MessageFile, + ); + this.repositoryThreads = await gr.database.getRepository("threads", Thread); + this.repositoryChannelRefs = await gr.database.getRepository( + "message_channel_refs", + MessageChannelRef, + ); + this.repositoryFilesRef = await gr.database.getRepository( + "message_file_refs", + MessageFileRef, + ); + this.repositoryMarkedRef = await gr.database.getRepository( + "message_channel_marked_refs", + MessageChannelMarkedRef, + ); + this.repositoryMessageFile = await gr.database.getRepository( + "message_files", + MessageFile, + ); + + return this; + } + + async listChannelFiles( + pagination: Pagination, + options?: MessageViewListOptions, + context?: ChannelViewExecutionContext, + ): Promise> { + const refs = await this.repositoryFilesRef.find( + { + target_type: options?.media_only + ? "channel_media" + : options?.file_only + ? "channel_file" + : "channel", + target_id: context.channel.id, + company_id: context.channel.company_id, + }, + buildMessageListPagination(pagination, "id"), + ); + + const threads: (MessageWithReplies & { context: MessageFileRef })[] = []; + for (const ref of refs.getEntities()) { + const thread = await this.repositoryThreads.findOne({ id: ref.thread_id }, {}); + const extendedThread = await gr.services.messages.messages.getThread( + thread, + { + replies_per_thread: options.replies_per_thread || 1, + }, + context, + ); + + const message = await gr.services.messages.messages.get({ + thread_id: ref.thread_id, + id: ref.message_id, + }); + if (message && extendedThread) { + extendedThread.highlighted_replies = [message]; + threads.push({ ...extendedThread, context: ref }); + } + } + + if (options.flat) { + let files: FlatFileFromMessage[] = []; + for (const thread of threads) { + for (const reply of thread.highlighted_replies) { + for (const file of reply.files || []) { + if (file.id === thread.context.message_file_id) { + files.push({ + file: file as MessageFile, + thread, + context: thread.context, + }); + } + } + } + } + files = _.uniqBy(files, f => f.file.id); + refs.nextPage.page_token = files.length > 0 ? files[files.length - 1].context?.id : null; + return new ListResult("file", files, refs.nextPage); + } + + return new ListResult("thread", threads, refs.nextPage); + } + + async listChannelPinned( + pagination: Pagination, + options?: MessageViewListOptions, + context?: ChannelViewExecutionContext, + ): Promise> { + const refs = await this.repositoryMarkedRef.find( + { + company_id: context.channel.company_id, + workspace_id: context.channel.workspace_id, + type: "pinned", + channel_id: context.channel.id, + }, + buildMessageListPagination(pagination, "thread_id"), + context, + ); + + const threads: MessageWithReplies[] = []; + for (const ref of uniqBy(refs.getEntities(), "thread_id")) { + const thread = await this.repositoryThreads.findOne({ id: ref.thread_id }, {}); + const extendedThread = await gr.services.messages.messages.getThread( + thread, + { + replies_per_thread: options.replies_per_thread || 1, + }, + context, + ); + if (extendedThread) { + threads.push(extendedThread); + } + } + + for (const ref of refs.getEntities()) { + const extendedThread = threads.find(th => th.id === ref.thread_id); + if (extendedThread) { + extendedThread.highlighted_replies = extendedThread.highlighted_replies || []; + const message = await gr.services.messages.messages.get({ + thread_id: ref.thread_id, + id: ref.message_id, + }); + extendedThread.highlighted_replies.push(message); + } + } + + if (options.flat) { + const messages: FlatPinnedFromMessage[] = []; + for (const thread of threads) { + for (const message of thread.highlighted_replies) { + messages.push({ + message, + thread, + }); + } + } + return new ListResult("message", messages, refs.nextPage); + } + + return new ListResult("thread", threads, null); + } + + async listChannelThreads( + pagination: Pagination, + options?: MessageViewListOptions, + context?: ChannelViewExecutionContext, + ): Promise> { + return this.listChannel(pagination, { ...options, replies_per_thread: 0 }, context); + } + + /** + * Get last threads in a channel. + * + * We can do great improvements in the number of calls we currently do: + - Get last threads refs (1req) + - For each ref get the corresponding thread (to get number of replies => can be cached in the thread ref itself) (threads x reqs) + - For each thread, get first message (=> first message id can be cached in thread ref too and so replace this request by a $in) (threads x reqs) + - For each thread get last N replies (threads x reqs) + + Total requests for "get last 20 threads with their last 3 replies": + + 1 + + 20 (can be cached in first req) + + 20 (can be replaced by a $in ) + + 20 + ---- + = 61 reqs + * @param pagination + * @param options + * @param context + * @returns + */ + async listChannel( + pagination: Paginable, + options?: MessageViewListOptions, + context?: ChannelViewExecutionContext, + ): Promise> { + const threadsRefs = await this.repositoryChannelRefs.find( + { + company_id: context.channel.company_id, + workspace_id: context.channel.workspace_id, + channel_id: context.channel.id, + }, + buildMessageListPagination(Pagination.fromPaginable(pagination), "message_id"), + context, + ); + + const threads = uniqBy( + ( + await this.repositoryThreads.find( + {}, + { + $in: [["id", threadsRefs.getEntities().map(ref => ref.thread_id)]], + }, + context, + ) + ).getEntities(), + thread => thread.id, + ); + + //Get first message for each thread and add last replies for each thread + let threadWithLastMessages: MessageWithReplies[] = []; + if (options.replies_per_thread !== 0) { + await Promise.all( + threads.map(async (thread: Thread) => { + const extendedThread = await gr.services.messages.messages.getThread( + thread, + { + replies_per_thread: options.replies_per_thread || 3, + }, + context, + ); + + if ( + extendedThread?.last_replies?.length === 0 && + extendedThread.created_at > new Date().getTime() - 1000 * 60 //This is important to avoid removing thread if people loads a channel at the same time people create a thread + ) { + await gr.services.messages.threads.delete( + { id: extendedThread.thread_id }, + { user: { id: null, server_request: true } }, + ); + } else if (extendedThread) { + threadWithLastMessages.push(extendedThread); + } + }), + ); + } + threadWithLastMessages = threadWithLastMessages + .filter(m => m.id) + .sort((a, b) => a.stats.last_activity - b.stats.last_activity); + + return new ListResult("thread", threadWithLastMessages, threadsRefs.nextPage); + } + + async search( + pagination: Pagination, + options: SearchMessageOptions, + context?: ExecutionContext, + ): Promise> { + return await this.searchRepository + .search( + { + ...(options.hasFiles ? { has_files: true } : {}), + ...(options.hasMedias ? { has_medias: true } : {}), + }, + { + pagination, + ...(options.companyId ? { $in: [["company_id", [options.companyId]]] } : {}), + ...(options.workspaceId ? { $in: [["workspace_id", [options.workspaceId]]] } : {}), + ...(options.channelId ? { $in: [["channel_id", [options.channelId]]] } : {}), + ...(options.sender ? { $in: [["user_id", [options.sender]]] } : {}), + $text: { + $search: options.search, + }, + $sort: { + created_at: "desc", + }, + }, + context, + ) + .then(a => { + return a; + }); + } + + async searchFiles( + pagination: Pagination, + options: SearchMessageFilesOptions, + context?: ExecutionContext, + ): Promise> { + const temp = await this.searchFilesRepository.search( + { + ...(options.isFile ? { is_file: true } : {}), + ...(options.isMedia ? { is_media: true } : {}), + }, + { + pagination, + ...(options.companyId ? { $in: [["cache_company_id", [options.companyId]]] } : {}), + ...(options.workspaceId ? { $in: [["cache_workspace_id", [options.workspaceId]]] } : {}), + ...(options.channelId ? { $in: [["cache_channel_id", [options.channelId]]] } : {}), + ...(options.sender ? { $in: [["cache_user_id", [options.sender]]] } : {}), + ...(options.extension ? { $in: [["extension", [options.extension]]] } : {}), + $text: { + $search: options.search, + }, + $sort: { + created_at: "desc", + }, + }, + context, + ); + + return new ListResult(temp.type, await this.checkFiles(temp.getEntities()), temp.nextPage); + } + + async listUserMarkedFiles( + userId: string, + type: "user_upload" | "user_download" | "both", + media: "file_only" | "media_only" | "both", + context: CompanyExecutionContext, + pagination: Pagination, + ): Promise> { + let files: (MessageFile & { context: MessageFileRef })[] = []; + let nextPageUploads: Paginable; + let nextPageDownloads: Paginable; + do { + const uploads = + type === "user_upload" || type === "both" + ? await this.repositoryFilesRef + .find( + { target_type: "user_upload", target_id: userId, company_id: context.company.id }, + { + pagination: { ...pagination, page_token: nextPageUploads?.page_token }, + }, + context, + ) + .then(a => { + nextPageUploads = a.nextPage; + return a.getEntities(); + }) + : []; + + const downloads = + type === "user_download" || type === "both" + ? await this.repositoryFilesRef + .find( + { target_type: "user_download", target_id: userId, company_id: context.company.id }, + { + pagination: { ...pagination, page_token: nextPageDownloads?.page_token }, + }, + context, + ) + .then(a => { + nextPageDownloads = a.nextPage; + return a.getEntities(); + }) + : []; + + const refs = [...uploads, ...downloads]; + + const messageFilePromises: Promise[] = refs.map( + async ref => { + try { + const res = { + ...(await this.repositoryMessageFile.findOne( + { + message_id: ref.message_id, + id: ref.message_file_id, + }, + {}, + context, + )), + context: ref, + }; + + return res; + } catch (e) { + return null; + } + }, + ); + + const messageFiles = _.uniqBy( + (await Promise.all(messageFilePromises)).filter(a => a), + a => a.metadata?.source + JSON.stringify(a.metadata?.external_id), + ); + + files = [...files, ...messageFiles.filter(a => a)].filter(ref => { + //Apply media filer + const isMedia = fileIsMedia(ref); + return !((media === "file_only" && isMedia) || (media === "media_only" && !isMedia)); + }); + files = files.sort((a, b) => b.created_at - a.created_at); + } while ( + files.length < (parseInt(pagination.limitStr) || 100) && + (nextPageDownloads?.page_token || nextPageUploads?.page_token) + ); + + const fileWithUserAndMessagePromise: Promise[] = files.map( + async file => + ({ + user: await formatUser(await gr.services.users.getCached({ id: file.cache?.user_id })), + message: await gr.services.messages.messages.get({ + id: file.message_id, + thread_id: file.thread_id, + }), + ...file, + } as FileSearchResult), + ); + const fileWithUserAndMessage = await Promise.all(fileWithUserAndMessagePromise); + + return new ListResult( + "file", + await this.checkFiles(fileWithUserAndMessage), + nextPageUploads || nextPageDownloads, + ); + } + + async checkFiles(files: T[]): Promise { + const results = await Promise.all( + files.map(async file => { + if (file.metadata.source !== "internal") return true; + const ei = file.metadata.external_id; + return await gr.services.files.exists(ei.id, ei.company_id); + }), + ); + return files.filter((_v, index) => results[index]); + } +} diff --git a/twake/backend/node/src/services/messages/types.ts b/twake/backend/node/src/services/messages/types.ts new file mode 100644 index 00000000..c65498ea --- /dev/null +++ b/twake/backend/node/src/services/messages/types.ts @@ -0,0 +1,188 @@ +import { ExecutionContext } from "../../core/platform/framework/api/crud-service"; +import { uuid } from "../../utils/types"; +import { HookType } from "../applications-api/types"; +import { Channel } from "../channels/entities"; +import { UserObject } from "../user/web/types"; +import { MessageFileRef } from "./entities/message-file-refs"; +import { MessageFile } from "./entities/message-files"; +import { Message, MessageWithUsers } from "./entities/messages"; +import { Thread } from "./entities/threads"; + +export type SpecialMention = "all" | "here" | "everyone" | "channel"; + +export type MessageNotification = { + company_id: uuid; + workspace_id: uuid | "direct"; + channel_id: uuid; + thread_id: uuid; + id: uuid; + sender: uuid; + creation_date: number; + mentions?: { + users?: uuid[]; + teams?: uuid[]; + specials?: SpecialMention[]; + }; + + sender_name?: string; + channel_name?: string; + company_name?: string; + workspace_name?: string; + + title: string; + text: string; +}; + +export type MessageHook = HookType & { + channel: Channel; + thread: Thread; + message: Message; +}; + +export type MessageWithReplies = Message & { + last_replies: Message[]; + thread?: MessageWithReplies; + highlighted_replies?: Message[]; + stats: { + last_activity: number; + replies: number; + }; +}; + +export type MessageWithRepliesWithUsers = MessageWithReplies & { + last_replies: MessageWithUsers[]; + thread?: MessageWithRepliesWithUsers; + highlighted_replies?: MessageWithUsers[]; + users: UserObject[]; +}; + +export interface CompanyExecutionContext extends ExecutionContext { + company: { id: string }; +} + +export interface ThreadExecutionContext extends CompanyExecutionContext { + thread: { id: string }; + company: { id: string }; + workspace?: { id: string }; + channel?: { id: string }; +} +export interface ChannelViewExecutionContext extends ExecutionContext { + channel: { + company_id: string; + workspace_id: string; + id: string; + }; +} +export interface MessageLocalEvent { + resource: Message; + context: ThreadExecutionContext; + created: boolean; +} + +export interface PaginationQueryParameters { + page_token?: string; + limit?: string; + websockets?: boolean; + direction?: "history" | "future"; +} +export interface MessageViewListOptions { + include_users?: boolean; + replies_per_thread?: number; + flat?: boolean; + emojis?: boolean; + media_only?: boolean; + file_only?: boolean; +} + +export interface MessageListQueryParameters extends PaginationQueryParameters { + include_users: boolean; +} + +export interface PinOperation { + id: string; + pin: boolean; +} + +export interface ReactionOperation { + id: string; + reactions: string[]; +} + +export interface BookmarkOperation { + id: string; + bookmark_id: string; + active: boolean; +} + +export type MessageFileDownloadEvent = { + user: { id: string }; + operation: { message_id: string; thread_id: string; message_file_id: string }; +}; + +export interface MessagesSaveOptions { + threadInitialMessage?: boolean; + enforceViewPropagation?: boolean; + message_moved?: boolean; + previous_thread?: string; //If message was in a previous thread before (moved) then this indicate when is it from +} +export interface MessagesGetThreadOptions { + replies_per_thread?: number; + includeQuoteInMessage?: boolean; +} + +export type SearchMessageOptions = { + search?: string; + companyId?: string; + workspaceId?: string; + channelId?: string; + hasFiles?: boolean; + hasMedias?: boolean; + sender?: string; +}; + +export type SearchMessageFilesOptions = { + search?: string; + companyId?: string; + workspaceId?: string; + channelId?: string; + sender?: string; + isFile?: boolean; + isMedia?: boolean; + extension?: string; +}; + +export type InboxOptions = { + companyId: string; +}; + +export type FlatFileFromMessage = { + file: MessageFile; + thread: MessageWithReplies; + context: MessageFileRef; +}; + +export type FlatPinnedFromMessage = { + message: any; + thread: any; +}; + +export interface DeleteLinkOperation { + message_id: string; + thread_id: string; + link: string; +} + +export type UpdateDeliveryStatusOperation = { + status: "delivered" | "read"; + self_message?: boolean; +} & MessageIdentifier; + +export type MessageReadType = { + messages: MessageIdentifier[]; + channel_id: string; +}; + +export type MessageIdentifier = { + message_id: string; + thread_id: string; +}; diff --git a/twake/backend/node/src/services/messages/utils.ts b/twake/backend/node/src/services/messages/utils.ts new file mode 100644 index 00000000..414bf1e4 --- /dev/null +++ b/twake/backend/node/src/services/messages/utils.ts @@ -0,0 +1,32 @@ +import { MessageFile } from "./entities/message-files"; +import { Message } from "./entities/messages"; +import { MessageWithReplies } from "./types"; + +export const formatMessageFile = (file: MessageFile): MessageFile => { + return { + ...file, + metadata: { + ...file.metadata, + thumbnails: [ + ...file.metadata.thumbnails.map(thumbnail => ({ + ...thumbnail, + full_url: thumbnail.url.match(/https?:\/\//) + ? "/internal/services/files/v1/" + thumbnail.url.replace(/^\//, "") + : thumbnail.url, + })), + ], + }, + }; +}; + +export const formatMessage = ( + message: MessageWithReplies | Message, +): MessageWithReplies | Message => { + return { + ...message, + files: message.files.map(formatMessageFile), + ...((message as MessageWithReplies).last_replies + ? { last_replies: (message as MessageWithReplies).last_replies.map(formatMessage) } + : {}), + }; +}; diff --git a/twake/backend/node/src/services/messages/web/controllers/index.ts b/twake/backend/node/src/services/messages/web/controllers/index.ts new file mode 100644 index 00000000..5255a64c --- /dev/null +++ b/twake/backend/node/src/services/messages/web/controllers/index.ts @@ -0,0 +1,22 @@ +import { ParticipantObject } from "../../entities/threads"; +import { ThreadExecutionContext } from "../../types"; + +export * from "./threads"; +export * from "./messages"; +export * from "./views"; +export * from "./user-bookmarks"; + +export const extendExecutionContentWithChannel = ( + participants: ParticipantObject[], + context: ThreadExecutionContext, +): ThreadExecutionContext => { + const channelInfo = participants.find(a => a.type === "channel"); + if (!channelInfo) { + return context; + } + return Object.assign(context, { + company: { id: channelInfo.company_id }, + workspace: { id: channelInfo.workspace_id }, + channel: { id: channelInfo.id }, + }); +}; diff --git a/twake/backend/node/src/services/messages/web/controllers/messages-files.ts b/twake/backend/node/src/services/messages/web/controllers/messages-files.ts new file mode 100644 index 00000000..cccd4c4a --- /dev/null +++ b/twake/backend/node/src/services/messages/web/controllers/messages-files.ts @@ -0,0 +1,52 @@ +import gr from "../../../global-resolver"; +import { FastifyRequest, FastifyReply } from "fastify"; + +export class MessagesFilesController { + async deleteMessageFile( + request: FastifyRequest<{ + Params: { + company_id: string; + message_id: string; + message_file_id: string; + }; + }>, + reply: FastifyReply, + ) { + const user = request.currentUser; + const resp = await gr.services.messages.messagesFiles.deleteMessageFile( + request.params.message_id, + request.params.message_file_id, + user.id, + ); + + if (!resp) reply.code(404).send(); + + reply.send({ resource: resp }); + } + + async getMessageFile( + request: FastifyRequest<{ + Params: { + company_id: string; + message_id: string; + message_file_id: string; + }; + }>, + reply: FastifyReply, + ) { + const user = request.currentUser; + const resp = await gr.services.messages.messagesFiles.getMessageFile( + request.params.message_id, + request.params.message_file_id, + ); + + if (!resp) reply.code(404).send(); + + //Check user has access to this file (check access to channel) + if (!(await gr.services.channels.members.getChannelMember(user, resp.channel))) { + reply.code(403).send(); + } + + reply.send({ resource: resp }); + } +} diff --git a/twake/backend/node/src/services/messages/web/controllers/messages.ts b/twake/backend/node/src/services/messages/web/controllers/messages.ts new file mode 100644 index 00000000..308d1747 --- /dev/null +++ b/twake/backend/node/src/services/messages/web/controllers/messages.ts @@ -0,0 +1,531 @@ +import { FastifyReply, FastifyRequest } from "fastify"; +import { CrudController } from "../../../../core/platform/services/webserver/types"; +import { + ResourceDeleteResponse, + ResourceGetResponse, + ResourceListResponse, + ResourceUpdateResponse, +} from "../../../../utils/types"; +import { getInstance as getMessageInstance, Message } from "../../entities/messages"; +import { + CompanyExecutionContext, + MessageListQueryParameters, + MessageReadType, + MessageWithReplies, + ThreadExecutionContext, +} from "../../types"; +import { handleError } from "../../../../utils/handleError"; +import { CrudException, Pagination } from "../../../../core/platform/framework/api/crud-service"; +import { getThreadMessageWebsocketRoom } from "../realtime"; +import { ThreadPrimaryKey } from "../../entities/threads"; +import { extendExecutionContentWithChannel } from "./index"; +import gr from "../../../global-resolver"; +import { formatUser } from "../../../../utils/users"; +import { UserObject } from "../../../../services/user/web/types"; + +export class MessagesController + implements + CrudController< + ResourceGetResponse, + ResourceUpdateResponse, + ResourceListResponse, + ResourceDeleteResponse + > +{ + async save( + request: FastifyRequest<{ + Querystring: { + include_users: boolean; + }; + Params: { + company_id: string; + thread_id: string; + message_id?: string; + }; + Body: { + resource: Message; + options: { + previous_thread: string; + }; + }; + }>, + reply: FastifyReply, + ): Promise> { + const context = getThreadExecutionContext(request); + try { + if (request.body.options?.previous_thread) { + //First move the message to another thread, then edit it + await gr.services.messages.messages.move( + { id: request.params.message_id || undefined }, + { + previous_thread: request.body.options?.previous_thread, + }, + context, + ); + } + + const thread = await gr.services.messages.threads.get( + { + id: context.thread.id, + } as ThreadPrimaryKey, + context, + ); + + if (!thread) { + throw "Message must be in a thread"; + } + + let hasOneMembership = false; + for (const participant of thread.participants) { + if (thread.created_by === context.user.id) { + hasOneMembership = true; + break; + } + if (participant.type === "channel") { + const isMember = await gr.services.channels.members.getChannelMember( + { id: context.user.id }, + { + company_id: participant.company_id, + workspace_id: participant.workspace_id, + id: participant.id, + }, + ); + if (isMember) { + hasOneMembership = true; + break; + } + } else if (participant.type === "user") { + if (participant.id === context.user.id) { + hasOneMembership = true; + break; + } + } + } + if (!hasOneMembership) { + throw CrudException.notFound("You can't post in this thread"); + } + + const result = await gr.services.messages.messages.save( + { + id: request.params.message_id || undefined, + ...request.body.resource, + }, + {}, + extendExecutionContentWithChannel(thread.participants, context), + ); + + let entity = result.entity; + + if (request.query.include_users) { + entity = await gr.services.messages.messages.includeUsersInMessage(entity, context); + } + + return { + resource: entity, + }; + } catch (err) { + handleError(reply, err); + } + } + + async forceDelete( + request: FastifyRequest<{ + Params: { + company_id: string; + thread_id: string; + message_id: string; + }; + }>, + reply: FastifyReply, + ) { + const context = getThreadExecutionContext(request); + try { + await gr.services.messages.messages.forceDelete( + getMessageInstance({ + thread_id: request.params.thread_id, + id: request.params.message_id, + }), + context, + ); + return { + status: "success", + }; + } catch (err) { + handleError(reply, err); + } + } + + async delete( + request: FastifyRequest<{ + Params: { + company_id: string; + thread_id: string; + message_id: string; + }; + }>, + reply: FastifyReply, + ): Promise { + const context = getThreadExecutionContext(request); + try { + await gr.services.messages.messages.delete( + getMessageInstance({ + thread_id: request.params.thread_id, + id: request.params.message_id, + }), + context, + ); + return { + status: "success", + }; + } catch (err) { + handleError(reply, err); + } + } + + async get( + request: FastifyRequest<{ + Querystring: MessageListQueryParameters; + Params: { + company_id: string; + thread_id: string; + message_id: string; + }; + }>, + reply: FastifyReply, + ): Promise> { + const context = getThreadExecutionContext(request); + try { + let resource = await gr.services.messages.messages.get( + { + thread_id: request.params.thread_id, + id: request.params.message_id, + }, + context, + ); + + if (request.query.include_users) { + if ((resource as MessageWithReplies).last_replies?.length) { + resource = await gr.services.messages.messages.includeUsersInMessageWithReplies( + resource as MessageWithReplies, + context, + ); + } else { + resource = await gr.services.messages.messages.includeUsersInMessage(resource, context); + } + } + + return { + resource: resource, + }; + } catch (err) { + handleError(reply, err); + } + } + + async list( + request: FastifyRequest<{ + Querystring: MessageListQueryParameters; + Params: { + company_id: string; + thread_id: string; + }; + }>, + reply: FastifyReply, + ): Promise> { + const context = getThreadExecutionContext(request); + try { + const resources = await gr.services.messages.messages.list( + new Pagination( + request.query.page_token, + request.query.limit, + request.query.direction !== "history", + ), + { ...request.query, include_users: request.query.include_users || false }, + context, + ); + + let entities = []; + if (request.query.include_users) { + for (const msg of resources.getEntities()) { + entities.push(await gr.services.messages.messages.includeUsersInMessage(msg, context)); + } + } else { + entities = resources.getEntities(); + } + + return { + resources: entities, + ...(request.query.websockets && { + websockets: gr.platformServices.realtime.sign( + [{ room: getThreadMessageWebsocketRoom(context) }], + context.user.id, + ), + }), + ...(resources.page_token && { + next_page_token: resources.page_token, + }), + }; + } catch (err) { + handleError(reply, err); + } + } + + async reaction( + request: FastifyRequest<{ + Params: { + company_id: string; + thread_id: string; + message_id: string; + }; + Body: { + reactions: string[]; + }; + }>, + reply: FastifyReply, + ): Promise> { + const context = getThreadExecutionContext(request); + try { + const result = await gr.services.messages.messages.reaction( + { + id: request.params.message_id, + reactions: request.body.reactions, + }, + {}, + context, + ); + return { + resource: result.entity, + }; + } catch (err) { + handleError(reply, err); + } + } + + async bookmark( + request: FastifyRequest<{ + Params: { + company_id: string; + thread_id: string; + message_id: string; + }; + Body: { + active: boolean; + bookmark_id: string; + }; + }>, + reply: FastifyReply, + ): Promise> { + const context = getThreadExecutionContext(request); + try { + const result = await gr.services.messages.messages.bookmark( + { + id: request.params.message_id, + bookmark_id: request.body.bookmark_id, + active: request.body.active, + }, + {}, + context, + ); + return { + resource: result.entity, + }; + } catch (err) { + handleError(reply, err); + } + } + + async pin( + request: FastifyRequest<{ + Params: { + company_id: string; + thread_id: string; + message_id: string; + }; + Body: { + pin: boolean; + }; + }>, + reply: FastifyReply, + ): Promise> { + const context = getThreadExecutionContext(request); + try { + const result = await gr.services.messages.messages.pin( + { + id: request.params.message_id, + pin: request.body.pin, + }, + {}, + context, + ); + return { + resource: result.entity, + }; + } catch (err) { + handleError(reply, err); + } + } + + async download( + request: FastifyRequest<{ + Params: { + company_id: string; + thread_id: string; + message_id: string; + message_file_id: string; + }; + }>, + reply: FastifyReply, + ): Promise<{ status: "ok" }> { + const context = getThreadExecutionContext(request); + try { + await gr.services.messages.messages.download( + { + id: request.params.message_id, + thread_id: request.params.thread_id, + message_file_id: request.params.message_file_id, + }, + {}, + context, + ); + return { + status: "ok", + }; + } catch (err) { + handleError(reply, err); + } + } + + /** + * Delete link preview handler + * + * @param {FastifyRequest} request - The request object + * @param {FastifyReply} reply - The reply object + * @returns {Promise>} - The response object + */ + async deleteLinkPreview( + request: FastifyRequest<{ + Params: { + company_id: string; + thread_id: string; + message_id: string; + encoded_url: string; + }; + Body: { + url: string; + }; + }>, + reply: FastifyReply, + ): Promise> { + const context = getThreadExecutionContext(request); + try { + const result = await gr.services.messages.messages.deleteLinkPreview( + { + message_id: request.params.message_id, + thread_id: request.params.thread_id, + link: request.body.url, + }, + context, + ); + + return { + resource: result.entity, + }; + } catch (err) { + handleError(reply, err); + } + } + + /** + * Mark messages as seen + * + * @param {FastifyRequest} request - The request object + * @param {FastifyReply} reply - The reply object + * @returns {Promise} - The response promise + */ + async read( + request: FastifyRequest<{ + Params: { + company_id: string; + workspace_id: string; + }; + Body: MessageReadType; + }>, + reply: FastifyReply, + ): Promise { + try { + const { messages, channel_id } = request.body; + const context: CompanyExecutionContext = { + company: { id: request.params.company_id }, + user: request.currentUser, + url: request.url, + method: request.routerMethod, + reqId: request.id, + transport: "http", + }; + + const result = await gr.services.messages.messages.read(messages, { + ...context, + channel_id, + workspace_id: request.params.workspace_id, + }); + return !!result; + } catch (err) { + handleError(reply, err); + return false; + } + } + + /** + * get users who've seen the message + * + * @param {FastifyRequest} request - the request object + * @param {FastifyReply} reply - the reply object + * @returns {Promise>} - the users list + */ + async seenBy( + request: FastifyRequest<{ + Params: { + company_id: string; + workspace_id: string; + thread_id: string; + message_id: string; + }; + }>, + reply: FastifyReply, + ): Promise> { + try { + const { message_id, workspace_id } = request.params; + const context = getThreadExecutionContext(request); + + const userIds = await gr.services.messages.messages.listSeenBy(message_id, { + ...context, + workspace: { id: workspace_id }, + }); + + const users = await Promise.all(userIds.map(id => gr.services.users.get({ id }, context))); + const resources = await Promise.all(users.map(user => formatUser(user))); + + return { + resources, + }; + } catch (error) { + handleError(reply, error); + } + } +} + +function getThreadExecutionContext( + request: FastifyRequest<{ + Params: { company_id: string; thread_id: string }; + }>, +): ThreadExecutionContext { + return { + user: request.currentUser, + thread: { id: request.params.thread_id }, + company: { id: request.params.company_id }, + url: request.url, + method: request.routerMethod, + reqId: request.id, + transport: "http", + }; +} diff --git a/twake/backend/node/src/services/messages/web/controllers/threads.ts b/twake/backend/node/src/services/messages/web/controllers/threads.ts new file mode 100644 index 00000000..4d44110a --- /dev/null +++ b/twake/backend/node/src/services/messages/web/controllers/threads.ts @@ -0,0 +1,98 @@ +import { FastifyReply, FastifyRequest } from "fastify"; +import { CrudController } from "../../../../core/platform/services/webserver/types"; +import { + ResourceCreateResponse, + ResourceDeleteResponse, + ResourceGetResponse, + ResourceListResponse, +} from "../../../../utils/types"; +import { handleError } from "../../../../utils/handleError"; +import { CompanyExecutionContext } from "../../types"; +import { ParticipantObject, Thread } from "../../entities/threads"; +import gr from "../../../global-resolver"; +import { CrudException } from "../../../../core/platform/framework/api/crud-service"; + +export class ThreadsController + implements + CrudController< + ResourceGetResponse, + ResourceCreateResponse, + ResourceListResponse, + ResourceDeleteResponse + > +{ + async save( + request: FastifyRequest<{ + Params: { + company_id: string; + thread_id: string; + }; + Body: { + resource: { + participants: ParticipantObject[]; + }; + options: { + message: any; + participants: { add: ParticipantObject[]; remove: ParticipantObject[] }; + }; + }; + }>, + reply: FastifyReply, + ): Promise> { + const context = getCompanyExecutionContext(request); + + const participants = + (request.body.resource.participants?.length + ? request.body.resource?.participants + : request.body.options?.participants?.add) || []; + for (const participant of participants) { + if (participant.type === "channel") { + const isMember = await gr.services.channels.members.getChannelMember( + { id: context.user.id }, + { + company_id: participant.company_id, + workspace_id: participant.workspace_id, + id: participant.id, + }, + ); + if (!isMember && !context.user.application_id && !context.user.server_request) { + throw CrudException.notFound("Channel not found"); + } + } + } + + try { + const result = await gr.services.messages.threads.save( + { + id: request.params.thread_id || undefined, + participants: request.body.resource.participants || undefined, + }, + { + message: request.body.options.message, + participants: request.body.options.participants, + }, + context, + ); + return { + resource: result.entity, + }; + } catch (err) { + handleError(reply, err); + } + } +} + +function getCompanyExecutionContext( + request: FastifyRequest<{ + Params: { company_id: string }; + }>, +): CompanyExecutionContext { + return { + user: request.currentUser, + company: { id: request.params.company_id }, + url: request.url, + method: request.routerMethod, + reqId: request.id, + transport: "http", + }; +} diff --git a/twake/backend/node/src/services/messages/web/controllers/user-bookmarks.ts b/twake/backend/node/src/services/messages/web/controllers/user-bookmarks.ts new file mode 100644 index 00000000..0e075305 --- /dev/null +++ b/twake/backend/node/src/services/messages/web/controllers/user-bookmarks.ts @@ -0,0 +1,130 @@ +import { FastifyReply, FastifyRequest } from "fastify"; +import { CrudController } from "../../../../core/platform/services/webserver/types"; +import { + ResourceDeleteResponse, + ResourceGetResponse, + ResourceListResponse, + ResourceUpdateResponse, +} from "../../../../utils/types"; +import { UserMessageBookmark } from "../../entities/user-message-bookmarks"; +import { handleError } from "../../../../utils/handleError"; +import { CompanyExecutionContext } from "../../types"; +import { getUserBookmarksWebsocketRoom } from "../realtime"; +import gr from "../../../global-resolver"; + +export class UserBookmarksController + implements + CrudController< + ResourceGetResponse, + ResourceUpdateResponse, + ResourceListResponse, + ResourceDeleteResponse + > +{ + async save( + request: FastifyRequest<{ + Params: { + company_id: string; + id: string; + }; + Body: { + resource: { + name: string; + }; + }; + }>, + reply: FastifyReply, + ): Promise> { + const context = getCompanyExecutionContext(request); + try { + const result = await gr.services.messages.userBookmarks.save( + { + user_id: context.user.id, + company_id: request.params.company_id, + name: request.body.resource.name, + id: request.params.id || undefined, + }, + context, + ); + return { + resource: result.entity, + }; + } catch (err) { + handleError(reply, err); + } + } + + async delete( + request: FastifyRequest<{ + Params: { + company_id: string; + id: string; + }; + }>, + reply: FastifyReply, + ): Promise { + const context = getCompanyExecutionContext(request); + try { + const result = await gr.services.messages.userBookmarks.delete( + { + user_id: context.user.id, + company_id: request.params.company_id, + id: request.params.id, + }, + context, + ); + return { + status: result.deleted ? "success" : "error", + }; + } catch (err) { + handleError(reply, err); + } + } + + async list( + request: FastifyRequest<{ + Params: { + company_id: string; + }; + }>, + reply: FastifyReply, + ): Promise> { + const context = getCompanyExecutionContext(request); + try { + const list = await gr.services.messages.userBookmarks.list( + { + user_id: context.user.id, + company_id: context.company.id, + }, + context, + ); + return { + websockets: gr.platformServices.realtime.sign( + [{ room: getUserBookmarksWebsocketRoom(context) }], + context.user.id, + ), + resources: list.getEntities(), + ...(list.page_token && { + next_page_token: list.page_token, + }), + }; + } catch (err) { + handleError(reply, err); + } + } +} + +function getCompanyExecutionContext( + request: FastifyRequest<{ + Params: { company_id: string }; + }>, +): CompanyExecutionContext { + return { + user: request.currentUser, + company: { id: request.params.company_id }, + url: request.url, + method: request.routerMethod, + reqId: request.id, + transport: "http", + }; +} diff --git a/twake/backend/node/src/services/messages/web/controllers/views.ts b/twake/backend/node/src/services/messages/web/controllers/views.ts new file mode 100644 index 00000000..dbb530ee --- /dev/null +++ b/twake/backend/node/src/services/messages/web/controllers/views.ts @@ -0,0 +1,317 @@ +import { FastifyReply, FastifyRequest } from "fastify"; +import { ResourceListResponse } from "../../../../utils/types"; +import { Message } from "../../entities/messages"; +import { handleError } from "../../../../utils/handleError"; +import { + CrudException, + ListResult, + Pagination, +} from "../../../../core/platform/framework/api/crud-service"; +import { + ChannelViewExecutionContext, + FlatFileFromMessage, + FlatPinnedFromMessage, + MessageViewListOptions, + MessageWithReplies, + PaginationQueryParameters, +} from "../../types"; +import gr from "../../../global-resolver"; +import { CompanyExecutionContext } from "../../../applications/web/types"; +import searchFiles from "./views/search-files"; +import recentFiles from "./views/recent-files"; + +export class ViewsController { + async feed( + request: FastifyRequest<{ + Querystring: MessageViewListQueryParameters; + Params: { + company_id: string; + workspace_id: string; + channel_id: string; + }; + }>, + reply: FastifyReply, + ): Promise< + ResourceListResponse + > { + const pagination = new Pagination( + request.query.page_token, + request.query.limit, + request.query.direction !== "history", + ); + const query = { ...request.query, include_users: request.query.include_users }; + const context = getChannelViewExecutionContext(request); + + const isMember = await gr.services.channels.members.getChannelMember( + { id: context.user.id }, + { + company_id: request.params.company_id, + workspace_id: request.params.workspace_id, + id: request.params.channel_id, + }, + ); + if (!isMember && !context.user.application_id && !context.user.server_request) { + throw CrudException.notFound("Channel not found"); + } + + let resources: ListResult; + + try { + if (request.query.filter === "files") { + resources = await gr.services.messages.views.listChannelFiles(pagination, query, context); + } else if (request.query.filter === "thread") { + resources = await gr.services.messages.views.listChannelThreads(pagination, query, context); + } else if (request.query.filter === "pinned") { + resources = await gr.services.messages.views.listChannelPinned(pagination, query, context); + } else { + resources = await gr.services.messages.views.listChannel(pagination, query, context); + } + + if (!resources) { + throw new Error("No list resources created"); + } + + let entities = []; + if (request.query.include_users) { + for (const msg of resources.getEntities()) { + if (request.query.flat) { + entities.push({ + ...msg, + ...((msg as any).message + ? { + message: await gr.services.messages.messages.includeUsersInMessageWithReplies( + (msg as any).message, + context, + ), + } + : {}), + ...((msg as any).thread + ? { + thread: await gr.services.messages.messages.includeUsersInMessageWithReplies( + (msg as any).thread, + context, + ), + } + : {}), + } as FlatFileFromMessage | FlatPinnedFromMessage); + } else { + entities.push( + await gr.services.messages.messages.includeUsersInMessageWithReplies( + msg as MessageWithReplies, + context, + ), + ); + } + } + } else { + entities = resources.getEntities(); + } + + return { + resources: entities, + ...(request.query.websockets && { + websockets: gr.platformServices.realtime.sign( + [ + { + room: `/companies/${context.channel.company_id}/workspaces/${context.channel.workspace_id}/channels/${context.channel.id}/feed`, + }, + ], + context.user.id, + ), + }), + ...(resources.page_token && { + next_page_token: resources.page_token, + }), + }; + } catch (err) { + handleError(reply, err); + } + } + + // Bookmarked messages of user from all over workspace + async bookmarks(): Promise> { + return { resources: [] }; + } + + // Uploaded and downloaded files of user from all over workspace + files = recentFiles; + + // Latest messages of user from all over workspace + async inbox( + request: FastifyRequest<{ + Querystring: MessageViewListQueryParameters; + Params: { + company_id: string; + }; + }>, + _reply: FastifyReply, + ): Promise> { + const context = getCompanyExecutionContext(request); + const messages = await gr.services.messages.messages.inbox( + request.currentUser.id, + context, + new Pagination(null, String(request.query.limit)), + ); + + return { + resources: messages.getEntities(), + }; + } + + async search( + request: FastifyRequest<{ + Querystring: MessageViewSearchQueryParameters & { page_token: string }; + Params: { + company_id: string; + }; + }>, + context: ChannelViewExecutionContext, + ): Promise> { + if (request.query.q.length < 1) { + return { resources: [] }; + } + + const limit = +request.query.limit || 100; + + async function* getNextMessages( + initialPageToken?: string, + ): AsyncIterableIterator<{ msg: Message; pageToken: string }> { + let lastPageToken = initialPageToken; + let messages: Message[] = []; + let hasMoreMessages = true; + do { + messages = await gr.services.messages.views + .search( + new Pagination(lastPageToken, limit.toString()), + { + search: request.query.q, + workspaceId: request.query.workspace_id, + channelId: request.query.channel_id, + companyId: request.params.company_id, + ...(request.query.has_files ? { hasFiles: true } : {}), + ...(request.query.has_medias ? { hasMedias: true } : {}), + ...(request.query.sender ? { sender: request.query.sender } : {}), + }, + context, + ) + .then((a: ListResult) => { + lastPageToken = a.nextPage.page_token; + if (!lastPageToken) { + hasMoreMessages = false; + } + return a.getEntities(); + }); + + if (messages.length) { + for (const message of messages) { + yield { msg: message, pageToken: lastPageToken }; + } + } else { + hasMoreMessages = false; + } + } while (hasMoreMessages); + } + + const messages = [] as Message[]; + let lastPageToken = null; + + for await (const { msg, pageToken } of getNextMessages(request.query.page_token)) { + lastPageToken = pageToken; + const getChannelMember = await gr.services.channels.members.getChannelMember( + { id: request.currentUser.id }, + { + company_id: msg.cache.company_id, + workspace_id: msg.cache.workspace_id, + id: msg.cache.channel_id, + }, + 50, + context, + ); + if (!getChannelMember) continue; + + messages.push(msg); + if (messages.length == limit) { + break; + } + } + + const extendedMessages = []; + for (const message of messages) { + const extended = { + ...(await gr.services.messages.messages.includeUsersInMessage(message, context)), + channel: await gr.services.channels.channels.get( + { + company_id: message.cache?.company_id, + workspace_id: message.cache?.workspace_id, + id: message.cache?.channel_id, + }, + context, + ), + }; + extendedMessages.push(extended); + } + + return { + resources: extendedMessages, + ...(lastPageToken && { + next_page_token: lastPageToken, + }), + }; + } + + searchFiles = searchFiles; +} + +export interface MessageViewListQueryParameters + extends PaginationQueryParameters, + MessageViewListOptions { + include_users: boolean; + filter?: "pinned" | "files" | "thread"; +} + +export interface MessageViewSearchQueryParameters extends PaginationQueryParameters { + q: string; + workspace_id: string; + channel_id: string; + sender: string; + has_files: boolean; + has_medias: boolean; +} + +function getChannelViewExecutionContext( + request: FastifyRequest<{ + Params: { + company_id: string; + workspace_id: string; + channel_id: string; + }; + }>, +): ChannelViewExecutionContext { + return { + user: request.currentUser, + url: request.url, + method: request.routerMethod, + reqId: request.id, + transport: "http", + channel: { + id: request.params.channel_id, + company_id: request.params.company_id, + workspace_id: request.params.workspace_id, + }, + }; +} + +export function getCompanyExecutionContext( + request: FastifyRequest<{ + Params: { company_id: string }; + }>, +): CompanyExecutionContext { + return { + user: request.currentUser, + company: { id: request.params.company_id }, + url: request.url, + method: request.routerMethod, + reqId: request.id, + transport: "http", + }; +} diff --git a/twake/backend/node/src/services/messages/web/controllers/views/recent-files.ts b/twake/backend/node/src/services/messages/web/controllers/views/recent-files.ts new file mode 100644 index 00000000..45ce1c98 --- /dev/null +++ b/twake/backend/node/src/services/messages/web/controllers/views/recent-files.ts @@ -0,0 +1,31 @@ +import { FastifyRequest } from "fastify"; +import { Pagination } from "../../../../../core/platform/framework/api/crud-service"; +import { ResourceListResponse } from "../../../../../utils/types"; +import gr from "../../../../global-resolver"; +import { getCompanyExecutionContext } from "../views"; +import { FileSearchResult } from "./search-files"; + +export default async ( + request: FastifyRequest<{ + Params: { company_id: string }; + Querystring: { + page_token: string; + limit?: string; + type?: "user_upload" | "user_download"; + media?: "media_only" | "file_only"; + }; + }>, +): Promise> => { + const userFiles = await gr.services.messages.views.listUserMarkedFiles( + request.currentUser.id, + request.query.type || "both", + request.query.media || "both", + getCompanyExecutionContext(request), + new Pagination(request.query.page_token, String(request.query.limit || 100)), + ); + + return { + resources: userFiles.getEntities().filter(a => a?.metadata?.external_id) as FileSearchResult[], + next_page_token: userFiles?.nextPage?.page_token, + }; +}; diff --git a/twake/backend/node/src/services/messages/web/controllers/views/search-files.ts b/twake/backend/node/src/services/messages/web/controllers/views/search-files.ts new file mode 100644 index 00000000..362062c5 --- /dev/null +++ b/twake/backend/node/src/services/messages/web/controllers/views/search-files.ts @@ -0,0 +1,216 @@ +import { FastifyRequest } from "fastify"; +import { ListResult, Pagination } from "../../../../../core/platform/framework/api/crud-service"; +import { MessageFile } from "../../../../../services/messages/entities/message-files"; +import { Message } from "../../../../../services/messages/entities/messages"; +import { + ChannelViewExecutionContext, + FlatFileFromMessage, +} from "../../../../../services/messages/types"; +import { UserObject } from "../../../../../services/user/web/types"; +import { PaginationQueryParameters, ResourceListResponse } from "../../../../../utils/types"; +import { formatUser } from "../../../../../utils/users"; +import gr from "../../../../global-resolver"; +import { MessageFileRef } from "../../../../../services/messages/entities/message-file-refs"; +import recentFiles from "./recent-files"; +import { isEmpty } from "lodash"; + +interface MessageViewSearchFilesQueryParameters extends PaginationQueryParameters { + q: string; + workspace_id: string; + channel_id: string; + sender: string; + is_file: boolean; + is_media: boolean; + extension: string; +} + +export type FileSearchResult = MessageFile & { + message: Message; + user: UserObject; + context?: MessageFileRef; +}; + +export default async ( + request: FastifyRequest<{ + Querystring: MessageViewSearchFilesQueryParameters & { + page_token: string; + }; + Params: { + company_id: string; + }; + }>, + context: ChannelViewExecutionContext, +): Promise> => { + const files = await searchFiles(request, context); + + //Include channel in reply everytime + await Promise.all( + files.resources.map((f, i) => { + return (async () => { + const channel = await gr.services.channels.channels.get( + { + id: f.cache.channel_id, + company_id: f.cache.company_id, + workspace_id: f.cache.workspace_id, + }, + context, + ); + files.resources[i] = { ...f, channel } as MessageFile; + })(); + }), + ); + + return files; +}; + +const searchFiles = async ( + request: FastifyRequest<{ + Querystring: MessageViewSearchFilesQueryParameters & { + page_token: string; + }; + Params: { + company_id: string; + }; + }>, + context: ChannelViewExecutionContext, +): Promise> => { + const limit = +request.query.limit || 100; + + if (isEmpty(request.query?.q)) { + if (request.query.channel_id) { + const tmp = await gr.services.messages.views.listChannelFiles( + new Pagination(request.query.page_token, limit.toString()), + { + flat: true, + ...(request.query.is_file ? { file_only: true } : {}), + ...(request.query.is_media ? { media_only: true } : {}), + }, + { + ...context, + channel: { + id: request.query.channel_id, + workspace_id: request.query.workspace_id || context.channel.workspace_id, + company_id: request.params.company_id, + }, + }, + ); + + const resources: FileSearchResult[] = []; + for (let flatFile of tmp.getEntities()) { + flatFile = flatFile as FlatFileFromMessage; + resources.push({ + ...flatFile.file, + message: flatFile.thread, + context: flatFile.context, + user: await formatUser( + await gr.services.users.getCached({ id: flatFile.thread.user_id }), + ), + }); + } + + return { + resources, + next_page_token: tmp.nextPage.page_token, + }; + } else { + return recentFiles({ + ...request, + query: { + ...request.query, + media: request.query.is_media + ? "media_only" + : request.query.is_file + ? "file_only" + : undefined, + }, + }); + } + } + + async function* getNextMessageFiles(initialPageToken?: string): AsyncIterableIterator<{ + msgFile: MessageFile; + pageToken: string; + }> { + let lastPageToken = initialPageToken; + let messageFiles: MessageFile[] = []; + let hasMoreMessageFiles = true; + do { + messageFiles = await gr.services.messages.views + .searchFiles( + new Pagination(lastPageToken, limit.toString()), + { + search: request.query.q, + companyId: request.params.company_id, + workspaceId: request.query.workspace_id, + channelId: request.query.channel_id, + ...(request.query.is_file ? { isFile: true } : {}), + ...(request.query.is_media ? { isMedia: true } : {}), + ...(request.query.sender ? { sender: request.query.sender } : {}), + ...(request.query.extension ? { extension: request.query.extension } : {}), + }, + context, + ) + .then((a: ListResult) => { + lastPageToken = a.nextPage.page_token; + if (!lastPageToken) { + hasMoreMessageFiles = false; + } + return a.getEntities(); + }); + + if (messageFiles.length) { + for (const messageFile of messageFiles) { + yield { msgFile: messageFile, pageToken: lastPageToken }; + } + } else { + hasMoreMessageFiles = false; + } + } while (hasMoreMessageFiles); + } + + let messageFiles = [] as FileSearchResult[]; + let nextPageToken = null; + + for await (const { msgFile, pageToken } of getNextMessageFiles(request.query.page_token)) { + nextPageToken = pageToken; + const getChannelMember = await gr.services.channels.members.getChannelMember( + { id: request.currentUser.id }, + { + company_id: msgFile.cache?.company_id, + workspace_id: msgFile.cache?.workspace_id, + id: msgFile.cache?.channel_id, + }, + 50, + context, + ); + if (!getChannelMember) continue; + + try { + const message = await gr.services.messages.messages.get({ + thread_id: msgFile.thread_id, + id: msgFile.message_id, + }); + const user = await formatUser( + await gr.services.users.getCached({ id: msgFile.cache?.user_id }), + ); + + messageFiles.push({ ...msgFile, user, message }); + if (messageFiles.length == limit) { + break; + } + } catch (e) { + continue; + } + } + + messageFiles = messageFiles + .filter(mf => mf.message.subtype !== "deleted") + .filter(a => a?.metadata?.external_id); + + return { + resources: messageFiles, + ...(nextPageToken && { + next_page_token: nextPageToken, + }), + }; +}; diff --git a/twake/backend/node/src/services/messages/web/index.ts b/twake/backend/node/src/services/messages/web/index.ts new file mode 100644 index 00000000..603b828f --- /dev/null +++ b/twake/backend/node/src/services/messages/web/index.ts @@ -0,0 +1,12 @@ +import { FastifyInstance, FastifyRegisterOptions } from "fastify"; +import routes from "./routes"; + +export default ( + fastify: FastifyInstance, + options: FastifyRegisterOptions<{ + prefix: string; + }>, +): void => { + fastify.log.debug("Configuring /internal/services/messages/v1 routes"); + fastify.register(routes, options); +}; diff --git a/twake/backend/node/src/services/messages/web/realtime.ts b/twake/backend/node/src/services/messages/web/realtime.ts new file mode 100644 index 00000000..1df492b6 --- /dev/null +++ b/twake/backend/node/src/services/messages/web/realtime.ts @@ -0,0 +1,13 @@ +import { CompanyExecutionContext, ThreadExecutionContext } from "../types"; + +export const getUserBookmarksWebsocketRoom = (context: CompanyExecutionContext): string => { + return "/companies/" + context.company.id + "/messages/bookmarks"; +}; + +export const getThreadMessageWebsocketRoom = (context: ThreadExecutionContext): string => { + return "/companies/" + context.company.id + "/threads/" + context.thread.id; +}; + +export const getThreadMessagePath = (context: ThreadExecutionContext): string => { + return "/companies/" + context.company.id + "/threads/" + context.thread.id; +}; diff --git a/twake/backend/node/src/services/messages/web/routes.ts b/twake/backend/node/src/services/messages/web/routes.ts new file mode 100644 index 00000000..0b595b0f --- /dev/null +++ b/twake/backend/node/src/services/messages/web/routes.ts @@ -0,0 +1,227 @@ +import { FastifyInstance, FastifyPluginCallback } from "fastify"; +import { + MessagesController, + ThreadsController, + UserBookmarksController, + ViewsController, +} from "./controllers"; +import { MessagesFilesController } from "./controllers/messages-files"; +import { listUserFiles } from "./schemas"; + +const routes: FastifyPluginCallback = (fastify: FastifyInstance, options, next) => { + const threadsController = new ThreadsController(); + const messagesController = new MessagesController(); + const userBookmarksController = new UserBookmarksController(); + const viewsController = new ViewsController(); + const messagesFilesController = new MessagesFilesController(); + + /** + * User bookmarks collection + */ + fastify.route({ + method: "GET", + url: "/companies/:company_id/preferences/bookmarks", + preValidation: [fastify.authenticate], + handler: userBookmarksController.list.bind(userBookmarksController), + }); + + fastify.route({ + method: "POST", + url: "/companies/:company_id/preferences/bookmarks/:id", + preValidation: [fastify.authenticate], + handler: userBookmarksController.save.bind(userBookmarksController), + }); + + fastify.route({ + method: "POST", + url: "/companies/:company_id/preferences/bookmarks", + preValidation: [fastify.authenticate], + handler: userBookmarksController.save.bind(userBookmarksController), + }); + + fastify.route({ + method: "DELETE", + url: "/companies/:company_id/preferences/bookmarks/:id", + preValidation: [fastify.authenticate], + handler: userBookmarksController.delete.bind(userBookmarksController), + }); + + /** + * Threads creation route + */ + fastify.route({ + method: "POST", + url: "/companies/:company_id/threads", + preValidation: [fastify.authenticate], + handler: threadsController.save.bind(threadsController), + }); + + fastify.route({ + method: "POST", + url: "/companies/:company_id/threads/:thread_id", + preValidation: [fastify.authenticate], + handler: threadsController.save.bind(threadsController), + }); + + /** + * In threads message collection + */ + fastify.route({ + method: "POST", + url: "/companies/:company_id/threads/:thread_id/messages", + preValidation: [fastify.authenticate], + handler: messagesController.save.bind(messagesController), + }); + + fastify.route({ + method: "POST", + url: "/companies/:company_id/threads/:thread_id/messages/:message_id", + preValidation: [fastify.authenticate], + handler: messagesController.save.bind(messagesController), + }); + + fastify.route({ + method: "GET", + url: "/companies/:company_id/threads/:thread_id/messages/:message_id", + preValidation: [fastify.authenticate], + handler: messagesController.get.bind(messagesController), + }); + + fastify.route({ + method: "GET", + url: "/companies/:company_id/threads/:thread_id/messages", + preValidation: [fastify.authenticate], + handler: messagesController.list.bind(messagesController), + }); + + fastify.route({ + method: "DELETE", + url: "/companies/:company_id/threads/:thread_id/messages/:message_id", + preValidation: [fastify.authenticate], + handler: messagesController.forceDelete.bind(messagesController), + }); + + fastify.route({ + method: "POST", + url: "/companies/:company_id/threads/:thread_id/messages/:message_id/reaction", + preValidation: [fastify.authenticate], + handler: messagesController.reaction.bind(messagesController), + }); + + fastify.route({ + method: "POST", + url: "/companies/:company_id/threads/:thread_id/messages/:message_id/bookmark", + preValidation: [fastify.authenticate], + handler: messagesController.bookmark.bind(messagesController), + }); + + fastify.route({ + method: "POST", + url: "/companies/:company_id/threads/:thread_id/messages/:message_id/pin", + preValidation: [fastify.authenticate], + handler: messagesController.pin.bind(messagesController), + }); + + fastify.route({ + method: "POST", + url: "/companies/:company_id/threads/:thread_id/messages/:message_id/download/:message_file_id", + preValidation: [fastify.authenticate], + handler: messagesController.download.bind(messagesController), + }); + + fastify.route({ + method: "POST", + url: "/companies/:company_id/threads/:thread_id/messages/:message_id/delete", + preValidation: [fastify.authenticate], + handler: messagesController.delete.bind(messagesController), + }); + + fastify.route({ + method: "POST", + url: "/companies/:company_id/threads/:thread_id/messages/:message_id/deletelink", + preValidation: [fastify.authenticate], + handler: messagesController.deleteLinkPreview.bind(messagesController), + }); + + fastify.route({ + method: "POST", + url: "/companies/:company_id/workspaces/:workspace_id/threads/read", + preValidation: [fastify.authenticate], + handler: messagesController.read.bind(messagesController), + }); + + fastify.route({ + method: "GET", + url: "/companies/:company_id/workspaces/:workspace_id/threads/:thread_id/messages/:message_id/seen", + preValidation: [fastify.authenticate], + handler: messagesController.seenBy.bind(messagesController), + }); + + /** + * Views routes + */ + fastify.route({ + method: "GET", + url: "/companies/:company_id/workspaces/:workspace_id/channels/:channel_id/feed", + preValidation: [fastify.authenticate], + handler: viewsController.feed.bind(viewsController), + }); + + fastify.route({ + method: "GET", + url: "/companies/:company_id/files", + preValidation: [fastify.authenticate], + schema: listUserFiles, + handler: viewsController.files.bind(viewsController), + }); + + fastify.route({ + method: "GET", + url: "/companies/:company_id/bookmarks", + preValidation: [fastify.authenticate], + handler: viewsController.bookmarks.bind(viewsController), + }); + + fastify.route({ + method: "GET", + url: "/companies/:company_id/inbox", + preValidation: [fastify.authenticate], + handler: viewsController.inbox.bind(viewsController), + }); + + fastify.route({ + method: "GET", + url: "/companies/:company_id/search", + preValidation: [fastify.authenticate], + handler: viewsController.search.bind(viewsController), + }); + + fastify.route({ + method: "GET", + url: "/companies/:company_id/files/search", + preValidation: [fastify.authenticate], + handler: viewsController.searchFiles.bind(viewsController), + }); + + /** + * Messages files routes + */ + + fastify.route({ + method: "GET", + url: "/companies/:company_id/messages/:message_id/files/:message_file_id", + preValidation: [fastify.authenticate], + handler: messagesFilesController.getMessageFile.bind(messagesFilesController), + }); + + fastify.route({ + method: "DELETE", + url: "/companies/:company_id/messages/:message_id/files/:message_file_id", + preValidation: [fastify.authenticate], + handler: messagesFilesController.deleteMessageFile.bind(messagesFilesController), + }); + + next(); +}; + +export default routes; diff --git a/twake/backend/node/src/services/messages/web/schemas.ts b/twake/backend/node/src/services/messages/web/schemas.ts new file mode 100644 index 00000000..db5db9b8 --- /dev/null +++ b/twake/backend/node/src/services/messages/web/schemas.ts @@ -0,0 +1,37 @@ +const publicFileSchema = { + type: "object", + properties: { + id: { type: "string" }, + user_id: { type: "string" }, + company_id: { type: "string" }, + application_id: { type: "string" }, + updated_at: { type: "number" }, + created_at: { type: "number" }, + metadata: { type: "object", additionalProperties: true }, + thumbnails: { type: "array" }, + upload_data: { type: "object", additionalProperties: true }, + user: { type: "object", additionalProperties: true, nullable: true }, + context: { type: "object", additionalProperties: true, nullable: true }, + }, +}; + +export const listUserFiles = { + request: { + properties: { + type: { type: "string", enum: ["user_upload", "user_download"] }, + page_token: { type: "string" }, + limit: { type: "number" }, + }, + required: ["type"], + }, + response: { + "2xx": { + type: "object", + properties: { + resources: { type: "array", items: publicFileSchema }, + next_page_token: { type: "string" }, + }, + required: ["resources"], + }, + }, +}; diff --git a/twake/backend/node/src/services/notifications/entities/channel-member-notification-preferences.ts b/twake/backend/node/src/services/notifications/entities/channel-member-notification-preferences.ts new file mode 100644 index 00000000..9b20051a --- /dev/null +++ b/twake/backend/node/src/services/notifications/entities/channel-member-notification-preferences.ts @@ -0,0 +1,50 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import { ChannelMemberNotificationLevel } from "../../../services/channels/types"; + +export const TYPE = "channel_members_notification_preferences"; +@Entity(TYPE, { + primaryKey: [["company_id", "channel_id"], "user_id"], + type: TYPE, +}) +export class ChannelMemberNotificationPreference { + /** + * Primary key / Partition key + */ + @Type(() => String) + @Column("user_id", "uuid") + user_id: string; + + /** + * Primary key + */ + @Type(() => String) + @Column("company_id", "uuid") + company_id: string; + + /** + * Primary key + */ + @Type(() => String) + @Column("channel_id", "uuid") + channel_id: string; + + @Type(() => String) + @Column("preferences", "string") + preferences: ChannelMemberNotificationLevel = ChannelMemberNotificationLevel.ALL; + + @Column("last_read", "number") + last_read = 0; +} + +export type ChannelMemberNotificationPreferencePrimaryKey = Pick< + ChannelMemberNotificationPreference, + "company_id" | "channel_id" | "user_id" +>; + +export function getInstance( + preference: ChannelMemberNotificationPreference, +): ChannelMemberNotificationPreference { + return merge(new ChannelMemberNotificationPreference(), preference); +} diff --git a/twake/backend/node/src/services/notifications/entities/channel-thread-users.ts b/twake/backend/node/src/services/notifications/entities/channel-thread-users.ts new file mode 100644 index 00000000..95db4501 --- /dev/null +++ b/twake/backend/node/src/services/notifications/entities/channel-thread-users.ts @@ -0,0 +1,50 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "channel_thread_users"; +@Entity(TYPE, { + primaryKey: [["company_id", "channel_id", "thread_id"], "user_id"], + type: TYPE, +}) +export class ChannelThreadUsers { + /** + * UUIDv4 + * Primary key / partition key + */ + @Type(() => String) + @Column("company_id", "uuid") + company_id: string; + + /** + * UUIDv4 + * Primary key / partition key + */ + @Type(() => String) + @Column("channel_id", "uuid") + channel_id: string; + + /** + * UUIDv4 + * Primary key / partition key + */ + @Type(() => String) + @Column("thread_id", "uuid") + thread_id: string; + + /** + * UUIDv4 + */ + @Type(() => String) + @Column("user_id", "uuid") + user_id: string; +} + +export type ChannelThreadUsersPrimaryKey = Pick< + ChannelThreadUsers, + "company_id" | "channel_id" | "thread_id" +>; + +export function getInstance(element: ChannelThreadUsers): ChannelThreadUsers { + return merge(new ChannelThreadUsers(), element); +} diff --git a/twake/backend/node/src/services/notifications/entities/index.ts b/twake/backend/node/src/services/notifications/entities/index.ts new file mode 100644 index 00000000..bb1e7ead --- /dev/null +++ b/twake/backend/node/src/services/notifications/entities/index.ts @@ -0,0 +1,20 @@ +export { + ChannelMemberNotificationPreference, + ChannelMemberNotificationPreferencePrimaryKey, + TYPE as ChannelMemberNotificationPreferenceType, + getInstance as getNotificationPreferenceInstance, +} from "./channel-member-notification-preferences"; + +export { + ChannelThreadUsers, + ChannelThreadUsersPrimaryKey, + TYPE as ChannelThreadUsersType, + getInstance as getChannelThreadUsersInstance, +} from "./channel-thread-users"; + +export { + UserNotificationBadge, + UserNotificationBadgePrimaryKey, + TYPE as UserNotificationBadgeType, + getInstance as getUserNotificationBadgeInstance, +} from "./user-notification-badges"; diff --git a/twake/backend/node/src/services/notifications/entities/user-notification-badges.ts b/twake/backend/node/src/services/notifications/entities/user-notification-badges.ts new file mode 100644 index 00000000..fb19ee47 --- /dev/null +++ b/twake/backend/node/src/services/notifications/entities/user-notification-badges.ts @@ -0,0 +1,78 @@ +import { Type } from "class-transformer"; +import { ChannelType } from "../../../utils/types"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import { v4 as uuidv4 } from "uuid"; +import { merge } from "lodash"; + +export const TYPE = "user_notification_badges"; +/** + * Table user-notification-badges + */ +@Entity(TYPE, { + primaryKey: [["company_id"], "user_id", "workspace_id", "channel_id", "thread_id"], + type: TYPE, +}) +export class UserNotificationBadge { + /** + * UUIDv4 + * Primary key / partition key + */ + @Type(() => String) + @Column("company_id", "uuid") + company_id: string; + + /** + * UUIDv4 + */ + @Type(() => String) + @Column("user_id", "uuid") + user_id: string; + + /** + * Text + * Primary key + */ + @Type(() => String) + @Column("workspace_id", "string") + workspace_id: string | ChannelType.DIRECT; + + /** + * UUIDv4 + * Primary key + */ + @Type(() => String) + @Column("channel_id", "uuid") + channel_id: string; + + /** + * UUIDv4 + * Primary key + */ + @Type(() => String) + @Column("thread_id", "string") //It can be null + thread_id: string; + + @Type(() => String) + @Column("message_id", "string") //It can be null + message_id: string; + + /** + * UUIDv4 + * Only used because crud entities must always have an id + */ + @Type(() => String) + @Column("id", "uuid") + id: string = uuidv4(); + + @Column("mention_type", "string") + mention_type: "reply" | "global" | "me" | "unread" | null = "me"; +} + +export type UserNotificationBadgePrimaryKey = Pick< + UserNotificationBadge, + "user_id" | "company_id" | "workspace_id" | "channel_id" | "thread_id" +>; + +export function getInstance(badge: UserNotificationBadge): UserNotificationBadge { + return merge(new UserNotificationBadge(), badge); +} diff --git a/twake/backend/node/src/services/notifications/entities/user-notification-digest.ts b/twake/backend/node/src/services/notifications/entities/user-notification-digest.ts new file mode 100644 index 00000000..cbbcfdde --- /dev/null +++ b/twake/backend/node/src/services/notifications/entities/user-notification-digest.ts @@ -0,0 +1,43 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "user_notification_digest"; +/** + * Table user-notification-digest + */ +@Entity(TYPE, { + primaryKey: [["company_id"], "user_id"], + type: TYPE, +}) +export class UserNotificationDigest { + /** + * UUIDv4 + * Primary key / partition key + */ + @Type(() => String) + @Column("company_id", "uuid") + company_id: string; + + /** + * UUIDv4 + */ + @Type(() => String) + @Column("user_id", "uuid") + user_id: string; + + @Column("created_at", "number") + created_at: number; + + @Column("deliver_at", "number") + deliver_at: number; +} + +export type UserNotificationDigestPrimaryKey = Pick< + UserNotificationDigest, + "user_id" | "company_id" +>; + +export function getInstance(digest: UserNotificationDigest): UserNotificationDigest { + return merge(new UserNotificationDigest(), digest); +} diff --git a/twake/backend/node/src/services/notifications/index.ts b/twake/backend/node/src/services/notifications/index.ts new file mode 100644 index 00000000..10cbb157 --- /dev/null +++ b/twake/backend/node/src/services/notifications/index.ts @@ -0,0 +1,22 @@ +import { Prefix, TwakeService } from "../../core/platform/framework"; +import WebServerAPI from "../../core/platform/services/webserver/provider"; +import web from "./web"; + +@Prefix("/internal/services/notifications/v1") +export default class NotificationService extends TwakeService { + version = "1"; + name = "notifications"; + + public async doInit(): Promise { + const fastify = this.context.getProvider("webserver").getServer(); + fastify.register((instance, _opts, next) => { + web(instance, { prefix: this.prefix }); + next(); + }); + return this; + } + // TODO: remove + api(): undefined { + return undefined; + } +} diff --git a/twake/backend/node/src/services/notifications/notifiers/index.ts b/twake/backend/node/src/services/notifications/notifiers/index.ts new file mode 100644 index 00000000..23899d66 --- /dev/null +++ b/twake/backend/node/src/services/notifications/notifiers/index.ts @@ -0,0 +1,5 @@ +export * from "./mobile-push"; + +export interface Notifier { + notify(user: string, message: Message): Promise; +} diff --git a/twake/backend/node/src/services/notifications/notifiers/mobile-push.ts b/twake/backend/node/src/services/notifications/notifiers/mobile-push.ts new file mode 100644 index 00000000..2d8e7ca4 --- /dev/null +++ b/twake/backend/node/src/services/notifications/notifiers/mobile-push.ts @@ -0,0 +1,32 @@ +import { logger } from "../../../core/platform/framework"; +import { MessageQueueServiceAPI } from "../../../core/platform/services/message-queue/api"; +import { Notifier } from "."; + +const TOPIC = "notification:push:mobile"; + +export class MobilePushNotifier implements Notifier { + private static instance: MobilePushNotifier; + + static get(messageQueue: MessageQueueServiceAPI): Notifier { + if (!MobilePushNotifier.instance) { + MobilePushNotifier.instance = new MobilePushNotifier(messageQueue); + } + + return MobilePushNotifier.instance; + } + + private constructor(private messageQueue: MessageQueueServiceAPI) {} + + async notify(user: string, message: Message): Promise { + logger.info(`MobilePushNotifier - Push to mobile ${user}`); + logger.debug(`MobilePushNotifier - Push to mobile ${user}, ${JSON.stringify(message)}`); + + try { + await this.messageQueue.publish(TOPIC, { + data: message, + }); + } catch (err) { + logger.warn({ err }, `MobilePushNotifier - Error while sending notification to user ${user}`); + } + } +} diff --git a/twake/backend/node/src/services/notifications/services/bages.ts b/twake/backend/node/src/services/notifications/services/bages.ts new file mode 100644 index 00000000..bf278211 --- /dev/null +++ b/twake/backend/node/src/services/notifications/services/bages.ts @@ -0,0 +1,302 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { + Initializable, + RealtimeDeleted, + RealtimeSaved, + TwakeContext, + TwakeServiceProvider, +} from "../../../core/platform/framework"; +import { ResourcePath } from "../../../core/platform/services/realtime/types"; +import { + CrudException, + DeleteResult, + ExecutionContext, + ListResult, + OperationType, + Pagination, + SaveResult, +} from "../../../core/platform/framework/api/crud-service"; +import { + getUserNotificationBadgeInstance, + UserNotificationBadge, + UserNotificationBadgePrimaryKey, + UserNotificationBadgeType, +} from "../entities"; +import { NotificationExecutionContext } from "../types"; +import { getNotificationRoomName } from "./realtime"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import gr from "../../global-resolver"; +import _, { pick, uniq } from "lodash"; + +export class UserNotificationBadgeService implements TwakeServiceProvider, Initializable { + version: "1"; + repository: Repository; + + async init(context: TwakeContext): Promise { + this.repository = await gr.database.getRepository( + UserNotificationBadgeType, + UserNotificationBadge, + ); + + return this; + } + + async get( + pk: UserNotificationBadgePrimaryKey, + context: ExecutionContext, + ): Promise { + return await this.repository.findOne(pk, {}, context); + } + + @RealtimeSaved((badge, context) => { + return [ + { + room: ResourcePath.get(getNotificationRoomName(badge.user_id)), + }, + ]; + }) + async save( + badge: UserNotificationBadge, + context: ExecutionContext, + ): Promise> { + //Initiate the digest + await gr.services.notifications.digest.putBadge(badge); + + await this.repository.save(getUserNotificationBadgeInstance(badge), context); + return new SaveResult(UserNotificationBadgeType, badge, OperationType.CREATE); + } + + @RealtimeDeleted((badge, context) => { + return [ + { + room: ResourcePath.get(getNotificationRoomName(badge.user_id)), + }, + ]; + }) + async delete( + pk: UserNotificationBadgePrimaryKey, + context?: NotificationExecutionContext, + ): Promise> { + //Cancel the current digest as we just read the badges + await gr.services.notifications.digest.cancelDigest(pk.company_id, pk.user_id); + + await this.repository.remove(pk as UserNotificationBadge, context); + return new DeleteResult(UserNotificationBadgeType, pk as UserNotificationBadge, true); + } + + list(): Promise> { + throw new Error("Not implemented"); + } + + async listForUserPerCompanies( + user_id: string, + context: ExecutionContext, + ): Promise> { + //We remove all badge from current company as next block will create dupicates + const companies_ids = (await gr.services.companies.getAllForUser(user_id)).map( + gu => gu.group_id, + ); + + let result: UserNotificationBadge[] = []; + let type = ""; + for (const company_id of companies_ids) { + const find = await this.repository.find( + { + company_id, + user_id, + }, + { + pagination: new Pagination("", "1"), + }, + context, + ); + type = find.type; + result = result.concat(find.getEntities()); + } + + const badges = new ListResult(type, result); + await this.ensureBadgesAreReachable(badges, context); + + return badges; + } + + async listForUser( + company_id: string, + user_id: string, + filter: Pick, + context?: ExecutionContext, + ): Promise> { + if (!company_id || !user_id) { + throw CrudException.badRequest("company_id and user_id are required"); + } + + //Cancel the current digest as we just read the badges + await gr.services.notifications.digest.cancelDigest(company_id, user_id); + + const badges = await this.repository.find( + { + ...{ + company_id, + user_id, + }, + ...pick(filter, ["workspace_id", "channel_id", "thread_id"]), + }, + {}, + context, + ); + + await this.ensureBadgesAreReachable(badges, context); + + return badges; + } + + // This will ensure we are still in the channels and if not, we'll remove the badge + // We need to also ensure more than that + // - Are we in the workspace? + // - Are we in the company? + async ensureBadgesAreReachable( + badges: ListResult, + context?: ExecutionContext, + ): Promise> { + if (badges.getEntities().length === 0) { + return badges; + } + + const userId = badges.getEntities()[0].user_id; + + const channels = uniq(badges.getEntities().map(r => r.channel_id)); + for (const channelId of channels) { + const someBadge = badges.getEntities().find(b => b.channel_id === channelId); + const channelMemberPk = { + company_id: someBadge.company_id, + workspace_id: someBadge.workspace_id, + channel_id: channelId, + user_id: userId, + }; + const context = { + user: { id: channelMemberPk.user_id, server_request: true }, + channel: { id: channelId, ...channelMemberPk }, + }; + const exists = + (await gr.services.channels.channels.get( + { + id: channelId, + ..._.pick(channelMemberPk, "company_id", "workspace_id"), + }, + context, + )) && (await gr.services.channels.members.get(channelMemberPk, context)); + if (!exists) { + for (const badge of badges.getEntities()) { + if (badge.channel_id === channelId) this.removeUserChannelBadges(badge, context); + } + badges.filterEntities(b => b.channel_id !== channelId); + } + } + + const badgePerWorkspace = _.uniqBy(badges.getEntities(), r => r.workspace_id); + for (const badge of badgePerWorkspace) { + const workspaceId = badge.workspace_id; + const companyId = badge.company_id; + if (!workspaceId || workspaceId === "direct") { + continue; + } + try { + const exists = + (await gr.services.workspaces.get({ + id: workspaceId, + company_id: companyId, + })) && + (await gr.services.workspaces.getUser({ + workspaceId, + userId, + })); + if (!exists) { + await gr.services.channels.members.ensureUserNotInWorkspaceIsNotInChannel( + { id: userId }, + { id: workspaceId, company_id: companyId }, + context, + ); + for (const badge of badges.getEntities()) { + if (badge.workspace_id === workspaceId) this.removeUserChannelBadges(badge, context); + } + badges.filterEntities(b => b.workspace_id !== workspaceId); + } + } catch (e) {} + } + + return badges; + } + + /** + * FIXME: This is a temporary implementation which is sending as many websocket notifications as there are badges to remove + * A better implementation will be to do a bulk delete and have a single websocket notification event + * @param filter + * @param context + */ + async removeUserChannelBadges( + filter: Pick< + UserNotificationBadgePrimaryKey, + "workspace_id" | "company_id" | "channel_id" | "user_id" + >, + context?: ExecutionContext, + ): Promise { + const badges = ( + await this.repository.find( + _.pick(filter, ["workspace_id", "company_id", "channel_id", "user_id"]), + {}, + context, + ) + ).getEntities(); + + return ( + await Promise.all( + badges.map(async badge => { + try { + return (await this.delete(badge)).deleted; + } catch (err) {} + }), + ) + ).filter(Boolean).length; + } + + /** + * acknowledge a notification and set the message status to delivered. + * + * @param {UserNotificationBadgePrimaryKey} pk - The primary key of the badge to acknowledge + * @param {ExecutionContext} context - The context of the acknowledge + * @returns {Promise} - The result of the acknowledge + */ + async acknowledge( + notification: UserNotificationBadgePrimaryKey & { message_id: string }, + context: ExecutionContext, + ): Promise { + const { message_id, ...pk } = notification; + const badge = await this.repository.findOne(pk, {}, context); + const payload = badge || notification; + + const ThreadExecutionContext = { + company: { + id: payload.company_id, + }, + thread: { + id: payload.thread_id, + }, + message_id, + ...context, + }; + + const result = await gr.services.messages.messages.updateDeliveryStatus( + { + ...payload, + status: "delivered", + }, + ThreadExecutionContext, + ); + + if (result) { + return true; + } + + return false; + } +} diff --git a/twake/backend/node/src/services/notifications/services/channel-preferences.ts b/twake/backend/node/src/services/notifications/services/channel-preferences.ts new file mode 100644 index 00000000..8fa21c3f --- /dev/null +++ b/twake/backend/node/src/services/notifications/services/channel-preferences.ts @@ -0,0 +1,157 @@ +import _ from "lodash"; +import { + DeleteResult, + ExecutionContext, + ListResult, + OperationType, + SaveResult, +} from "../../../core/platform/framework/api/crud-service"; +import { + ChannelMemberNotificationPreference, + ChannelMemberNotificationPreferencePrimaryKey, +} from "../entities"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import { Initializable, logger, TwakeServiceProvider } from "../../../core/platform/framework"; +import gr from "../../global-resolver"; + +const TYPE = "channel_members_notification_preferences"; + +export class ChannelMemberPreferencesServiceImpl implements TwakeServiceProvider, Initializable { + version: "1"; + repository: Repository; + + async init(): Promise { + this.repository = await gr.database.getRepository( + TYPE, + ChannelMemberNotificationPreference, + ); + + return this; + } + + async save( + entity: ChannelMemberNotificationPreference, + context: ExecutionContext, + ): Promise> { + const pk: ChannelMemberNotificationPreferencePrimaryKey = { + user_id: entity.user_id, + company_id: entity.company_id, + channel_id: entity.channel_id, + }; + + let preference = await this.repository.findOne(pk, {}, context); + + if (!preference) { + preference = new ChannelMemberNotificationPreference(); + preference = _.merge(entity, pk); + } + + preference = _.merge(preference, entity); + + await this.repository.save(preference, context); + + return new SaveResult(TYPE, preference, OperationType.CREATE); + } + + async get( + pk: ChannelMemberNotificationPreferencePrimaryKey, + context: ExecutionContext, + ): Promise { + return await this.repository.findOne(pk, {}, context); + } + + async delete( + pk: ChannelMemberNotificationPreferencePrimaryKey, + context?: ExecutionContext, + ): Promise> { + await this.repository.remove(pk as ChannelMemberNotificationPreference, context); + + return new DeleteResult(TYPE, pk as ChannelMemberNotificationPreference, true); + } + + list(): Promise> { + throw new Error("Not implemented"); + } + + async getChannelPreferencesForUsers( + channelAndCompany: Pick< + ChannelMemberNotificationPreferencePrimaryKey, + "channel_id" | "company_id" + >, + users?: string[] | null, + lastRead?: { + lessThan: number; + }, + context?: ExecutionContext, + ): Promise> { + logger.debug( + `ChannelMemberPreferenceService - Get Channel preferences for users ${JSON.stringify( + users, + )} with lastRead < ${lastRead?.lessThan}`, + ); + const result = await this.repository.find( + users ? { ...channelAndCompany, ...{ user_id: users } } : channelAndCompany, + {}, + context, + ); + + if (result.getEntities().length > 0 && lastRead && lastRead.lessThan) { + result.filterEntities(entity => entity.last_read < lastRead.lessThan); + } + + logger.debug( + `ChannelMemberPreferenceService - Result ${JSON.stringify( + result.getEntities().map(preference => preference.user_id), + )}`, + ); + + return result; + } + + async getChannelPreferencesForUsersFilteredByReadTime( + channelAndCompany: Pick< + ChannelMemberNotificationPreferencePrimaryKey, + "channel_id" | "company_id" + >, + users: string[] = [], + lastRead: number, + context?: ExecutionContext, + ): Promise> { + const result = await this.repository.find( + { ...channelAndCompany, ...{ user_id: users } }, + {}, + context, + ); + + if (result.getEntities().length > 0 && lastRead) { + result.filterEntities(entity => entity.last_read < lastRead); + } + + return result; + } + + async updateLastRead( + channelAndCompany: Pick, + user_id: string, + lastRead: number, + context?: ExecutionContext, + ): Promise { + const pk: ChannelMemberNotificationPreferencePrimaryKey = { + user_id, + company_id: channelAndCompany.company_id, + channel_id: channelAndCompany.channel_id, + }; + + const preference = await this.repository.findOne(pk, {}, context); + + if (!preference) { + return; + } + + preference.last_read = lastRead; + + await this.repository.save(preference, context); + + return preference; + } +} diff --git a/twake/backend/node/src/services/notifications/services/channel-thread-users.ts b/twake/backend/node/src/services/notifications/services/channel-thread-users.ts new file mode 100644 index 00000000..2c490bfc --- /dev/null +++ b/twake/backend/node/src/services/notifications/services/channel-thread-users.ts @@ -0,0 +1,68 @@ +import { + DeleteResult, + ExecutionContext, + ListResult, + OperationType, + SaveResult, +} from "../../../core/platform/framework/api/crud-service"; +import { + ChannelThreadUsers, + ChannelThreadUsersPrimaryKey, + ChannelThreadUsersType, +} from "../entities"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import gr from "../../global-resolver"; +import { Initializable, TwakeServiceProvider } from "../../../core/platform/framework"; + +export class ChannelThreadUsersServiceImpl implements TwakeServiceProvider, Initializable { + version: "1"; + repository: Repository; + + async init(): Promise { + this.repository = await gr.database.getRepository( + ChannelThreadUsersType, + ChannelThreadUsers, + ); + + return this; + } + + async bulkSave( + entities: ChannelThreadUsers[], + context: ExecutionContext, + ): Promise> { + await this.repository.saveAll(entities, context); + + return new SaveResult(ChannelThreadUsersType, entities, OperationType.CREATE); + } + + async get( + pk: ChannelThreadUsersPrimaryKey, + context: ExecutionContext, + ): Promise { + return await this.repository.findOne(pk, {}, context); + } + + async delete( + pk: ChannelThreadUsersPrimaryKey, + context: ExecutionContext, + ): Promise> { + await this.repository.remove(pk as ChannelThreadUsers, context); + + return new DeleteResult(ChannelThreadUsersType, pk as ChannelThreadUsers, true); + } + + list(): Promise> { + throw new Error("Not implemented"); + } + + async getUsersInThread( + pk: ChannelThreadUsersPrimaryKey, + context: ExecutionContext, + ): Promise> { + if (!pk.company_id || !pk.channel_id || !pk.thread_id) { + throw new Error("Missing required fields"); + } + return this.repository.find(pk, {}, context); + } +} diff --git a/twake/backend/node/src/services/notifications/services/digest.ts b/twake/backend/node/src/services/notifications/services/digest.ts new file mode 100644 index 00000000..a9cf3c23 --- /dev/null +++ b/twake/backend/node/src/services/notifications/services/digest.ts @@ -0,0 +1,168 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { MessageWithReplies } from "../../../services/messages/types"; +import { Initializable, TwakeServiceProvider } from "../../../core/platform/framework"; +import { Paginable, Pagination } from "../../../core/platform/framework/api/crud-service"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import { Channel } from "../../../services/channels/entities"; +import { Message } from "../../../services/messages/entities/messages"; +import { UserObject } from "../../../services/user/web/types"; +import Workspace from "../../../services/workspaces/entities/workspace"; +import gr from "../../global-resolver"; +import { UserNotificationBadge } from "../entities"; +import { getInstance, TYPE, UserNotificationDigest } from "../entities/user-notification-digest"; + +export class UserNotificationDigestService implements TwakeServiceProvider, Initializable { + version: "1"; + repository: Repository; + + async init(): Promise { + this.repository = await gr.database.getRepository( + TYPE, + UserNotificationDigest, + ); + + gr.platformServices.cron.schedule( + "*/15 * * * *", + async () => { + //This being multi-node we will try to avoid running them at the exact same time + //Fixme: this is until we find a better solution of course + await new Promise(r => setTimeout(r, 1000 * 60 * Math.random())); + await this.processDigests(); + }, + "Find and process digests", + ); + + return this; + } + + async getDigest(companyId: string, userId: string): Promise { + return await this.repository.findOne({ company_id: companyId, user_id: userId }); + } + + async cancelDigest(companyId: string, userId: string) { + const digest = await this.getDigest(companyId, userId); + if (digest) await this.repository.remove(digest); + } + + async putBadge(badge: UserNotificationBadge): Promise { + const digest = await this.getDigest(badge.company_id, badge.user_id); + let deliver_at = digest?.deliver_at; + if (!deliver_at) { + //Get user preferences to set the deliver at + const preferences = await gr.services.notifications.preferences.getMerged({ + company_id: badge.company_id, + user_id: badge.user_id, + workspace_id: "all", + }); + let emailNotificationsDelay = preferences?.preferences?.email_notifications_delay; + if (emailNotificationsDelay === undefined) emailNotificationsDelay = 15; + if (!emailNotificationsDelay) { + return; + } else { + deliver_at = Date.now() + emailNotificationsDelay * 1000 * 60; + } + } + await this.repository.save( + getInstance({ + company_id: badge.company_id, + user_id: badge.user_id, + created_at: digest?.created_at || Date.now(), + deliver_at, + }), + ); + } + + async processDigests(): Promise { + let digestsPagination: Paginable = new Pagination(null, "100"); + do { + const digests = await this.repository.find({}); + const digestsEntities = digests.getEntities().filter(d => { + return d.deliver_at < Date.now(); + }); + + for (const digest of digestsEntities) { + await this.repository.remove(digest); + } + + for (const digest of digestsEntities) { + await this.processDigest(digest); + } + + digestsPagination = new Pagination(digests.nextPage.page_token, "100"); + } while (digestsPagination.page_token); + } + + async processDigest(digest: UserNotificationDigest): Promise { + const badges = await gr.services.notifications.badges.listForUser( + digest.company_id, + digest.user_id, + {} as any, + ); + + const user = await gr.services.users.get({ id: digest.user_id }); + const company = await gr.services.companies.getCompany({ id: digest.company_id }); + const notifications: { + channel: Channel; + workspace: Workspace; + message: Message & { user: UserObject }; + }[] = []; + const workspaces: { [key: string]: Workspace } = {}; + const channels: { [key: string]: Channel } = {}; + + for (const badge of badges.getEntities()) { + if (!badge.thread_id) continue; + try { + const message = await gr.services.messages.messages.includeUsersInMessageWithReplies( + (await gr.services.messages.messages.get({ + id: badge.thread_id, + thread_id: badge.thread_id, + })) as MessageWithReplies, + ); + + if (message.created_at < digest.created_at - 60 * 1000) continue; + + channels[badge.channel_id] = + channels[badge.channel_id] || + (await gr.services.channels.channels.get({ + company_id: badge.company_id, + workspace_id: badge.workspace_id, + id: badge.channel_id, + })); + + workspaces[badge.workspace_id] = + badge.workspace_id && badge.workspace_id !== "direct" + ? workspaces[badge.workspace_id] || + (await gr.services.workspaces.get({ + company_id: badge.company_id, + id: badge.workspace_id, + })) + : null; + + notifications.push({ + channel: channels[badge.channel_id], + workspace: workspaces[badge.workspace_id], + message: { ...message, user: (message.users || []).find(u => u.id === message.user_id) }, + }); + } catch (e) {} + } + + const etaEntry = { + user, + company, + notifications, + }; + + if (notifications.length > 0) { + const { html, text, subject } = await gr.platformServices.emailPusher.build( + "notification-digest", + user.language, + etaEntry, + ); + await gr.platformServices.emailPusher.send(user.email_canonical, { + subject, + html, + text, + }); + } + } +} diff --git a/twake/backend/node/src/services/notifications/services/engine/index.ts b/twake/backend/node/src/services/notifications/services/engine/index.ts new file mode 100644 index 00000000..96b6fe4e --- /dev/null +++ b/twake/backend/node/src/services/notifications/services/engine/index.ts @@ -0,0 +1,36 @@ +import { Initializable } from "../../../../core/platform/framework"; +import { MarkChannelAsReadMessageProcessor } from "./processors/mark-channel-as-read"; +import { MarkChannelAsUnreadMessageProcessor } from "./processors/mark-channel-as-unread"; +import { NewChannelMessageProcessor } from "./processors/new-channel-message"; +import { PushNotificationMessageProcessor } from "./processors/mobile-push-notifications"; +import { PushNotificationToUsersMessageProcessor } from "./processors/push-to-users"; +import { LeaveChannelMessageProcessor } from "./processors/channel-member-deleted"; +import { JoinChannelMessageProcessor } from "./processors/channel-member-created"; +import { UpdateChannelMemberMessageProcessor } from "./processors/channel-member-updated"; +import { PushReactionNotification } from "./processors/reaction-notification"; +import gr from "../../../global-resolver"; + +/** + * The notification engine is in charge of processing data and delivering user notifications on the right place + */ +export class NotificationEngine implements Initializable { + async init(): Promise { + gr.platformServices.messageQueue.processor.addHandler( + new UpdateChannelMemberMessageProcessor(), + ); + gr.platformServices.messageQueue.processor.addHandler(new JoinChannelMessageProcessor()); + gr.platformServices.messageQueue.processor.addHandler(new LeaveChannelMessageProcessor()); + gr.platformServices.messageQueue.processor.addHandler(new MarkChannelAsReadMessageProcessor()); + gr.platformServices.messageQueue.processor.addHandler( + new MarkChannelAsUnreadMessageProcessor(), + ); + gr.platformServices.messageQueue.processor.addHandler(new NewChannelMessageProcessor()); + gr.platformServices.messageQueue.processor.addHandler(new PushNotificationMessageProcessor()); + gr.platformServices.messageQueue.processor.addHandler( + new PushNotificationToUsersMessageProcessor(), + ); + gr.platformServices.messageQueue.processor.addHandler(new PushReactionNotification()); + + return this; + } +} diff --git a/twake/backend/node/src/services/notifications/services/engine/processors/channel-member-created.ts b/twake/backend/node/src/services/notifications/services/engine/processors/channel-member-created.ts new file mode 100644 index 00000000..a12e6466 --- /dev/null +++ b/twake/backend/node/src/services/notifications/services/engine/processors/channel-member-created.ts @@ -0,0 +1,79 @@ +import { + ChannelMemberNotificationPreference, + getNotificationPreferenceInstance, +} from "../../../entities"; +import { logger } from "../../../../../core/platform/framework"; +import { Channel, ChannelMember } from "../../../../channels/entities"; +import gr from "../../../../global-resolver"; +import { NotificationMessageQueueHandler } from "../../../types"; +import { ExecutionContext } from "../../../../../core/platform/framework/api/crud-service"; + +type JoinChannelMessage = { channel: Channel; member: ChannelMember }; + +export class JoinChannelMessageProcessor + implements NotificationMessageQueueHandler +{ + readonly topics = { + in: "channel:member:created", + }; + + readonly options = { + unique: true, + ack: true, + }; + + readonly name = "JoinChannelMessageProcessor"; + + validate(message: JoinChannelMessage): boolean { + return !!(message && message.channel && message.member); + } + + async process(message: JoinChannelMessage, context?: ExecutionContext): Promise { + logger.info( + `${this.name} - Processing join channel message for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + + try { + let preference: ChannelMemberNotificationPreference; + + if (Channel.isDirectChannel(message.channel)) { + // Check if the user already have preference for this channel in case he already joined it before + preference = await gr.services.notifications.channelPreferences.get( + { + company_id: message.member.company_id, + channel_id: message.member.channel_id, + user_id: message.member.user_id, + }, + context, + ); + } + + if (preference) { + logger.info( + `${this.name} - Notification preference already exists for user ${message.member.user_id} in direct channel ${message.channel.id}`, + ); + + return; + } + + preference = getNotificationPreferenceInstance({ + channel_id: message.member.channel_id, + company_id: message.member.company_id, + user_id: message.member.user_id, + last_read: message.member.last_access || 0, + preferences: message.member.notification_level, + }); + + await gr.services.notifications.channelPreferences.save(preference, context); + + logger.info( + `${this.name} - Notification preference has been created for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + } catch (err) { + logger.warn( + { err }, + `${this.name} - Error while creating notification preference from pubsub`, + ); + } + } +} diff --git a/twake/backend/node/src/services/notifications/services/engine/processors/channel-member-deleted.ts b/twake/backend/node/src/services/notifications/services/engine/processors/channel-member-deleted.ts new file mode 100644 index 00000000..fa7c873d --- /dev/null +++ b/twake/backend/node/src/services/notifications/services/engine/processors/channel-member-deleted.ts @@ -0,0 +1,101 @@ +import { assign, merge } from "lodash"; +import { ChannelMemberNotificationPreference, UserNotificationBadge } from "../../../entities"; +import { logger } from "../../../../../core/platform/framework"; +import { Channel, ChannelMember } from "../../../../channels/entities"; +import { isDirectChannel } from "../../../../channels/utils"; +import gr from "../../../../global-resolver"; +import { NotificationMessageQueueHandler } from "../../../types"; +import { ExecutionContext } from "../../../../../core/platform/framework/api/crud-service"; + +type LeaveChannelMessage = { channel: Channel; member: ChannelMember }; + +export class LeaveChannelMessageProcessor + implements NotificationMessageQueueHandler +{ + readonly topics = { + in: "channel:member:deleted", + }; + + readonly options = { + unique: true, + ack: true, + }; + + readonly name = "LeaveChannelMessageProcessor"; + + validate(message: LeaveChannelMessage): boolean { + return !!(message && message.channel && message.member); + } + + async process(message: LeaveChannelMessage, context?: ExecutionContext): Promise { + logger.info( + `${this.name} - Processing leave channel message for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + + if (Channel.isDirectChannel(message.channel)) { + logger.info( + `${this.name} - Channel is direct, do not clean resources for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + return; + } + + await Promise.all([this.removeBadges(message, context), this.removePreferences(message)]); + } + + async removeBadges(message: LeaveChannelMessage, context: ExecutionContext): Promise { + logger.info( + `${this.name} - Removing badges for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + + try { + const badgeEntity = new UserNotificationBadge(); + assign(badgeEntity, { + workspace_id: message.channel.workspace_id, + company_id: message.channel.company_id, + channel_id: message.channel.id, + user_id: message.member.user_id, + }); + const removedBadges = await gr.services.notifications.badges.removeUserChannelBadges( + badgeEntity, + context, + ); + + logger.info( + `${this.name} - Removed ${removedBadges} badges for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + } catch (err) { + logger.warn( + { err }, + `${this.name} - Error while removing badges for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + } + } + + async removePreferences(message: LeaveChannelMessage): Promise { + if (isDirectChannel(message.channel)) { + logger.info( + `${this.name} - Notification preference was kept for user ${message.member.user_id} in direct channel ${message.channel.id}`, + ); + return; + } + + try { + const preference = merge(new ChannelMemberNotificationPreference(), { + channel_id: message.member.channel_id, + company_id: message.member.company_id, + user_id: message.member.user_id, + }); + + await gr.services.notifications.channelPreferences.delete(preference); + + logger.info( + `${this.name} - Notification preference has been deleted for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + } catch (err) { + logger.warn( + { err }, + `${this.name} - Error while removing preferences for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + } + } +} diff --git a/twake/backend/node/src/services/notifications/services/engine/processors/channel-member-updated.ts b/twake/backend/node/src/services/notifications/services/engine/processors/channel-member-updated.ts new file mode 100644 index 00000000..69904e15 --- /dev/null +++ b/twake/backend/node/src/services/notifications/services/engine/processors/channel-member-updated.ts @@ -0,0 +1,55 @@ +import { merge } from "lodash"; +import { ChannelMemberNotificationPreference } from "../../../entities"; +import { logger } from "../../../../../core/platform/framework"; +import { Channel, ChannelMember } from "../../../../channels/entities"; +import gr from "../../../../global-resolver"; +import { NotificationMessageQueueHandler } from "../../../types"; +import { ExecutionContext } from "../../../../../core/platform/framework/api/crud-service"; + +type UpdateChannelMessage = { channel: Channel; member: ChannelMember }; + +export class UpdateChannelMemberMessageProcessor + implements NotificationMessageQueueHandler +{ + readonly topics = { + in: "channel:member:updated", + }; + + readonly options = { + unique: true, + ack: true, + }; + + readonly name = "UpdateChannelMemberMessageProcessor"; + + validate(message: UpdateChannelMessage): boolean { + return !!(message && message.channel && message.member); + } + + async process(message: UpdateChannelMessage, context?: ExecutionContext): Promise { + logger.info( + `${this.name} - Processing update channel member message for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + + const preference = merge(new ChannelMemberNotificationPreference(), { + channel_id: message.member.channel_id, + company_id: message.member.company_id, + user_id: message.member.user_id, + last_read: message.member.last_access || 0, + preferences: message.member.notification_level, + }); + + try { + await gr.services.notifications.channelPreferences.save(preference, context); + + logger.info( + `${this.name} - Channel member notification preference has been updated for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + } catch (err) { + logger.error( + { err }, + `${this.name} - Error while updating channel member notification preference for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + } + } +} diff --git a/twake/backend/node/src/services/notifications/services/engine/processors/mark-channel-as-read.ts b/twake/backend/node/src/services/notifications/services/engine/processors/mark-channel-as-read.ts new file mode 100644 index 00000000..46d7e27f --- /dev/null +++ b/twake/backend/node/src/services/notifications/services/engine/processors/mark-channel-as-read.ts @@ -0,0 +1,70 @@ +import _ from "lodash"; +import { UserNotificationBadge } from "../../../entities"; +import { logger } from "../../../../../core/platform/framework"; +import { ChannelReadMessage, NotificationMessageQueueHandler } from "../../../types"; +import gr from "../../../../global-resolver"; +import { ExecutionContext } from "../../../../../core/platform/framework/api/crud-service"; + +export class MarkChannelAsReadMessageProcessor + implements NotificationMessageQueueHandler +{ + readonly topics = { + in: "channel:read", + }; + + readonly options = { + unique: true, + ack: true, + }; + + readonly name = "MarkChannelAsReadMessageProcessor"; + + validate(message: ChannelReadMessage): boolean { + return !!( + message && + message.channel && + message.channel.workspace_id && + message.channel.company_id && + message.channel.id && + message.member && + message.member.user_id + ); + } + + async process(message: ChannelReadMessage, context?: ExecutionContext): Promise { + logger.info( + `${this.name} - Processing message for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + + await this.removeBadges(message, context); + } + + async removeBadges(message: ChannelReadMessage, context: ExecutionContext): Promise { + logger.info( + `${this.name} - Removing badges for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + + try { + const badgeEntity = new UserNotificationBadge(); + _.assign(badgeEntity, { + workspace_id: message.channel.workspace_id, + company_id: message.channel.company_id, + channel_id: message.channel.id, + user_id: message.member.user_id, + }); + const removedBadges = await gr.services.notifications.badges.removeUserChannelBadges( + badgeEntity, + context, + ); + + logger.info( + `${this.name} - Removed ${removedBadges} badges for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + } catch (err) { + logger.warn( + { err }, + `${this.name} - Error while removing badges for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + } + } +} diff --git a/twake/backend/node/src/services/notifications/services/engine/processors/mark-channel-as-unread.ts b/twake/backend/node/src/services/notifications/services/engine/processors/mark-channel-as-unread.ts new file mode 100644 index 00000000..bb83b1e9 --- /dev/null +++ b/twake/backend/node/src/services/notifications/services/engine/processors/mark-channel-as-unread.ts @@ -0,0 +1,68 @@ +import _ from "lodash"; +import { UserNotificationBadge } from "../../../entities"; +import { logger } from "../../../../../core/platform/framework"; +import { ChannelUnreadMessage, NotificationMessageQueueHandler } from "../../../types"; +import gr from "../../../../global-resolver"; +import { ExecutionContext } from "../../../../../core/platform/framework/api/crud-service"; + +export class MarkChannelAsUnreadMessageProcessor + implements NotificationMessageQueueHandler +{ + readonly topics = { + in: "channel:unread", + }; + + readonly options = { + unique: true, + ack: true, + }; + + readonly name = "MarkChannelAsUnreadMessageProcessor"; + + validate(message: ChannelUnreadMessage): boolean { + return !!( + message && + message.channel && + message.channel.workspace_id && + message.channel.company_id && + message.channel.id && + message.member && + message.member.user_id + ); + } + + async process(message: ChannelUnreadMessage, context?: ExecutionContext): Promise { + logger.info( + `${this.name} - Processing message for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + + await this.addBadge(message, context); + } + + async addBadge(message: ChannelUnreadMessage, context: ExecutionContext): Promise { + logger.info( + `${this.name} - Creating a badge for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + + try { + const badgeEntity = new UserNotificationBadge(); + _.assign(badgeEntity, { + workspace_id: message.channel.workspace_id, + company_id: message.channel.company_id, + channel_id: message.channel.id, + user_id: message.member.user_id, + mention_type: "unread", + }); + gr.services.notifications.badges.save(badgeEntity, context); + + logger.info( + `${this.name} - Created new badge for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + } catch (err) { + logger.warn( + { err }, + `${this.name} - Error while creating new badge for user ${message.member.user_id} in channel ${message.channel.id}`, + ); + } + } +} diff --git a/twake/backend/node/src/services/notifications/services/engine/processors/mobile-push-notifications.ts b/twake/backend/node/src/services/notifications/services/engine/processors/mobile-push-notifications.ts new file mode 100644 index 00000000..5ba22d58 --- /dev/null +++ b/twake/backend/node/src/services/notifications/services/engine/processors/mobile-push-notifications.ts @@ -0,0 +1,48 @@ +import { logger } from "../../../../../core/platform/framework"; +import { + NotificationMessageQueueHandler, + PushNotificationMessage, + PushNotificationMessageResult, +} from "../../../types"; +import gr from "../../../../global-resolver"; + +/** + * Push new message notification to a set of users + */ +export class PushNotificationMessageProcessor + implements + NotificationMessageQueueHandler +{ + readonly topics = { + in: "notification:push:mobile", + }; + + readonly options = { + unique: true, + ack: true, + }; + + name = "PushMobileNotificationProcessor"; + + validate(message: PushNotificationMessage): boolean { + return !!( + message && + message.channel_id && + message.company_id && + message.workspace_id && + message.message_id && + message.badge_value && + message.user + ); + } + + async process(message: PushNotificationMessage): Promise { + logger.info( + `${this.name} - Processing mobile push notification for channel ${message.channel_id}`, + ); + + await gr.services.notifications.mobilePush.push(message); + + return message; + } +} diff --git a/twake/backend/node/src/services/notifications/services/engine/processors/new-channel-message.ts b/twake/backend/node/src/services/notifications/services/engine/processors/new-channel-message.ts new file mode 100644 index 00000000..175bdff1 --- /dev/null +++ b/twake/backend/node/src/services/notifications/services/engine/processors/new-channel-message.ts @@ -0,0 +1,259 @@ +import { isDirectChannel } from "../../../../channels/utils"; +import { logger } from "../../../../../core/platform/framework"; +import { MessageNotification } from "../../../../messages/types"; +import { + ChannelMemberNotificationPreference, + ChannelThreadUsers, + getChannelThreadUsersInstance, +} from "../../../entities"; +import { ChannelMemberNotificationLevel } from "../../../../channels/types"; +import { MentionNotification, NotificationMessageQueueHandler } from "../../../types"; +import { ChannelType } from "../../../../../utils/types"; +import gr from "../../../../global-resolver"; +import { ExecutionContext } from "../../../../../core/platform/framework/api/crud-service"; + +export class NewChannelMessageProcessor + implements NotificationMessageQueueHandler +{ + readonly topics = { + in: "message:created", + out: "notification:mentions", + }; + + readonly options = { + unique: true, + ack: true, + queue: "message:created:consumer2", + }; + + readonly name = "NewChannelMessageProcessor"; + + validate(message: MessageNotification): boolean { + return !!( + message && + message.channel_id && + message.company_id && + message.workspace_id && + message.creation_date > Date.now() - 5 * 60 * 1000 + ); + } + + async process(message: MessageNotification): Promise { + logger.info( + `${this.name} - Processing notification for message ${message.thread_id}/${message.id} in channel ${message.channel_id}`, + ); + logger.debug(`${this.name} - Notification message ${JSON.stringify(message)}`); + + try { + if (message.workspace_id === ChannelType.DIRECT) { + //Fixme: Monkey fix until we find a way to add user to channel BEFORE to add the badge to this channel + await new Promise(r => setTimeout(r, 1000)); + } + + const usersToNotify = await this.getUsersToNotify(message); + + if (!usersToNotify?.length) { + logger.info( + `${this.name} - No users to notify for message ${message.thread_id}/${message.id} in channel ${message.channel_id}`, + ); + return; + } + + logger.info( + `${this.name} - Users to notify for message ${message.thread_id}/${message.id} in channel ${ + message.channel_id + } : ['${usersToNotify.join("', '")}']`, + ); + + //Fixme Add user full names if known, need to import microservice + const users_names = {}; + //Fixme add channel full names, need to import microservice + const channels_names = {}; + + return { + channel_id: message.channel_id, + company_id: message.company_id, + message_id: message.id, + thread_id: message.thread_id, + workspace_id: message.workspace_id, + creation_date: message.creation_date, + mentions: { + users: usersToNotify || [], + }, + object_names: { + users: users_names, + channels: channels_names, + }, + + //Temp: should not be used like this when migrating messages to node + //But we don't remember why, so keeping this like this as it works well + text: message.text, + title: message.title, + } as MentionNotification; + } catch (err) { + logger.error( + { err }, + `${this.name} - Error while gettings users to notify for message ${message.thread_id}/${message.id} in channel ${message.channel_id}`, + ); + } + } + + async getUsersToNotify( + message: MessageNotification, + context?: ExecutionContext, + ): Promise { + let channelPreferencesForUsers: ChannelMemberNotificationPreference[]; + const threadId = message.thread_id || message.id; + const isNewThread = !message.thread_id || `${message.thread_id}` === `${message.id}`; + const isDirect = isDirectChannel({ workspace_id: message.workspace_id }); + const isAllOrHereMention = this.isAllOrHereMention(message); + + const users: ChannelThreadUsers[] = [ + // message sender is a user in the thread + ...[ + getChannelThreadUsersInstance({ + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: threadId, + user_id: message.sender, + }), + ], + + // mentionned users are users in the thread + ...(message?.mentions?.users?.length + ? message.mentions.users.map(user_id => + getChannelThreadUsersInstance({ + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: threadId, + user_id, + }), + ) + : []), + ]; + + await gr.services.notifications.channelThreads.bulkSave(users, context); + + if (isNewThread || isDirect || isAllOrHereMention) { + //get the channel level preferences + channelPreferencesForUsers = ( + await gr.services.notifications.channelPreferences.getChannelPreferencesForUsers({ + company_id: message.company_id, + channel_id: message.channel_id, + }) + ).getEntities(); + + return this.filterMembersToNotify(message, channelPreferencesForUsers).map(m => m.user_id); + } + + // get the preferences of the users involved in the thread + channelPreferencesForUsers = await this.getAllInvolvedUsersPreferences( + { + channel_id: message.channel_id, + company_id: message.company_id, + thread_id: threadId, + }, + context, + ); + + return this.filterThreadMembersToNotify(message, channelPreferencesForUsers).map( + m => m.user_id, + ); + } + + protected filterMembersToNotify( + message: MessageNotification, + membersPreferences: ChannelMemberNotificationPreference[], + ): ChannelMemberNotificationPreference[] { + logger.debug(`${this.name} - Filter members ${JSON.stringify(membersPreferences)}`); + const isAllOrHere = this.isAllOrHereMention(message); + const isDirect = isDirectChannel({ workspace_id: message.workspace_id }); + return ( + membersPreferences + // 1. Remove the ones which does not want any notification (preference === NONE) + .filter(preference => preference.preferences !== ChannelMemberNotificationLevel.NONE) + // 2. Remove the sender + .filter(preference => String(preference.user_id) !== String(message.sender)) + // 3. Filter based on truth table based on user preferences and current message + .filter(memberPreference => { + const userIsMentionned = this.userIsMentionned(memberPreference.user_id, message); + + const truthTable = [ + isDirect, + // all + memberPreference.preferences === ChannelMemberNotificationLevel.ALL, + // mentions + memberPreference.preferences === ChannelMemberNotificationLevel.MENTIONS && + (isAllOrHere || userIsMentionned), + // me + memberPreference.preferences === ChannelMemberNotificationLevel.ME && userIsMentionned, + ]; + + logger.debug( + `${this.name} - ${ + memberPreference.user_id + } truth table [direct, all, mentions, me] : ${JSON.stringify(truthTable)}`, + ); + + return truthTable.includes(true); + }) + ); + } + + protected filterThreadMembersToNotify( + message: MessageNotification, + membersPreferences: ChannelMemberNotificationPreference[], + ): ChannelMemberNotificationPreference[] { + logger.debug(`${this.name} - Filter thread members ${JSON.stringify(membersPreferences)}`); + return ( + membersPreferences + // 1. Remove the ones which does not want any notification (preference === NONE) + .filter(preference => preference.preferences !== ChannelMemberNotificationLevel.NONE) + //2. Remove the sender + .filter(preference => String(preference.user_id) !== String(message.sender)) + ); + } + + /** + * When message is a response in a thread, get all the users involved in the thread + * ie the ones who where initially mentionned, mentionned in children messages, and the ones who replied + */ + protected async getAllInvolvedUsersPreferences( + thread: { + company_id: string; + channel_id: string; + thread_id: string; + }, + context: ExecutionContext, + ): Promise { + const usersIds: string[] = ( + await gr.services.notifications.channelThreads.getUsersInThread(thread, context) + ) + .getEntities() + .map(thread => thread.user_id); + + return ( + await gr.services.notifications.channelPreferences.getChannelPreferencesForUsers( + { company_id: thread.company_id, channel_id: thread.channel_id }, + usersIds, + undefined, + context, + ) + ).getEntities(); + } + + private isAllOrHereMention(message: MessageNotification): boolean { + return ( + message.mentions && + message.mentions.specials && + (message.mentions.specials.includes("all") || + message.mentions.specials.includes("here") || + message.mentions.specials.includes("channel") || + message.mentions.specials.includes("everyone")) + ); + } + + private userIsMentionned(user: string, message: MessageNotification) { + return message?.mentions?.users?.includes(String(user)); + } +} diff --git a/twake/backend/node/src/services/notifications/services/engine/processors/push-to-users.ts b/twake/backend/node/src/services/notifications/services/engine/processors/push-to-users.ts new file mode 100644 index 00000000..44e1445f --- /dev/null +++ b/twake/backend/node/src/services/notifications/services/engine/processors/push-to-users.ts @@ -0,0 +1,219 @@ +import { logger } from "../../../../../core/platform/framework"; +import { MobilePushNotifier } from "../../../notifiers"; +import { + MentionNotification, + MentionNotificationResult, + NotificationMessageQueueHandler, + PushNotificationMessage, +} from "../../../types"; +import { ChannelMemberNotificationPreference } from "../../../entities"; +import { UserNotificationBadge } from "../../../entities"; +import _ from "lodash"; +import { websocketEventBus } from "../../../../../core/platform/services/realtime/bus"; +import { + RealtimeEntityActionType, + ResourcePath, +} from "../../../../../core/platform/services/realtime/types"; +import { getNotificationRoomName } from "../../realtime"; +import gr from "../../../../global-resolver"; +import { ExecutionContext } from "../../../../../core/platform/framework/api/crud-service"; + +/** + * Push new message notification to a set of users + */ +export class PushNotificationToUsersMessageProcessor + implements NotificationMessageQueueHandler +{ + readonly topics = { + in: "notification:mentions", + }; + + readonly options = { + unique: true, + ack: true, + }; + + name = "PushNotificationToUsersMessageProcessor"; + + validate(message: MentionNotification): boolean { + return !!( + message && + message.channel_id && + message.company_id && + message.workspace_id && + message.creation_date + ); + } + + async process( + message: MentionNotification, + context?: ExecutionContext, + ): Promise { + logger.info(`${this.name} - Processing mention notification for channel ${message.channel_id}`); + + if ( + !message.company_id || + !message.workspace_id || + !message.channel_id || + !message.creation_date + ) { + throw new Error("Missing required fields"); + } + + if (!message.mentions || !message.mentions.users || !message.mentions.users.length) { + logger.info(`${this.name} - Message does not have any user to mention`); + return; + } + + const usersToUpdate = await this.filterUsersOnLastReadChannelTime( + { channel_id: message.channel_id, company_id: message.company_id }, + message.mentions.users, + message.creation_date, + context, + ); + + if (!usersToUpdate.length) { + logger.info(`${this.name} - There are no users to notify from the last read channel date`); + return; + } + + const badges = await this.addNewMessageBadgesForUsers( + { + channel_id: message.channel_id, + company_id: message.company_id, + workspace_id: message.workspace_id, + thread_id: message.thread_id || message.message_id, + message_id: message.message_id, + }, + usersToUpdate, + message.mentions, + context, + ); + + badges.forEach(badge => { + const badgeLocation = { + company_id: message.company_id, + workspace_id: message.workspace_id, + channel_id: message.channel_id, + user: badge.user_id.toString(), + thread_id: message.thread_id || message.message_id, + message_id: message.message_id, + }; + + websocketEventBus.publish(RealtimeEntityActionType.Event, { + type: "notification:desktop", + room: ResourcePath.get(getNotificationRoomName(badge.user_id)), + entity: { + ...badgeLocation, + title: message.title, + text: formatNotificationMessage(message), + }, + resourcePath: null, + result: null, + }); + + this.sendPushNotification(badge.user_id, { + ...badgeLocation, + badge_value: 1, + title: message.title, + text: formatNotificationMessage(message), + }); + }); + } + + async filterUsersOnLastReadChannelTime( + channel: Pick, + users: string[] = [], + timestamp: number, + context?: ExecutionContext, + ): Promise { + if (!users.length) { + return []; + } + + return ( + await gr.services.notifications.channelPreferences.getChannelPreferencesForUsers( + channel, + users, + { + lessThan: timestamp, + }, + context, + ) + ) + .getEntities() + .map((preference: ChannelMemberNotificationPreference) => preference.user_id); + } + + async addNewMessageBadgesForUsers( + badge: Pick< + UserNotificationBadge, + "channel_id" | "company_id" | "thread_id" | "workspace_id" | "message_id" + >, + users: string[] = [], + mentions: MentionNotification["mentions"], + context: ExecutionContext, + ): Promise> { + logger.info(`${this.name} - Update badge for users ${users.join("/")}`); + + return ( + await Promise.all( + users.map(user => { + const badgeEntity = new UserNotificationBadge(); + _.assign(badgeEntity, { + channel_id: badge.channel_id, + company_id: badge.company_id, + workspace_id: badge.workspace_id, + thread_id: badge.thread_id, + message_id: badge.message_id, + user_id: user, + mention_type: mentions.users.includes(user) + ? "me" + : mentions.specials.length > 0 + ? "global" + : badge.thread_id !== badge.message_id + ? "reply" + : null, + }); + return this.saveBadge(badgeEntity, context); + }), + ) + ).filter(Boolean); + } + + private saveBadge( + badge: UserNotificationBadge, + context: ExecutionContext, + ): Promise { + return gr.services.notifications.badges + .save(badge, context) + .then(result => result.entity) + .catch(err => { + logger.warn({ err }, `${this.name} - A badge has not been saved for user ${badge.user_id}`); + return null; + }); + } + + sendPushNotification(user: string, pushNotification: PushNotificationMessage): void { + MobilePushNotifier.get(gr.platformServices.messageQueue).notify(user, pushNotification); + } +} + +function formatNotificationMessage(message: MentionNotification): string { + let text = message.text; + // Clean the message text to remove @userName:id-id-id + ((text || "").match(/@[^: ]+:([0-f-]{36})/gm) || []).forEach(match => { + const string = (match || "").trim(); + const id = string.split(":").pop(); + const fallback = string.split(":").shift(); + text = text.replace(string, message.object_names?.users[id] || fallback); + }); + // Clean the message text to remove #channelName:id-id-id + ((text || "").match(/#[^: ]+:([0-f-]{36})/gm) || []).forEach(match => { + const string = (match || "").trim(); + const id = string.split(":").pop(); + const fallback = string.split(":").shift(); + text = text.replace(string, message.object_names?.channels[id] || fallback); + }); + return text; +} diff --git a/twake/backend/node/src/services/notifications/services/engine/processors/reaction-notification.ts b/twake/backend/node/src/services/notifications/services/engine/processors/reaction-notification.ts new file mode 100644 index 00000000..044cd01d --- /dev/null +++ b/twake/backend/node/src/services/notifications/services/engine/processors/reaction-notification.ts @@ -0,0 +1,132 @@ +import { + NotificationMessageQueueHandler, + PushNotificationMessage, + ReactionNotification, +} from "../../../types"; +import { logger } from "../../../../../core/platform/framework"; +import { websocketEventBus } from "../../../../../core/platform/services/realtime/bus"; +import { + RealtimeEntityActionType, + ResourcePath, +} from "../../../../../core/platform/services/realtime/types"; +import { MobilePushNotifier } from "../../../notifiers"; +import gr from "../../../../global-resolver"; +import { getNotificationRoomName } from "../../realtime"; +import { Channel } from "../../../../channels/entities/channel"; +import User from "../../../../user/entities/user"; +export class PushReactionNotification + implements NotificationMessageQueueHandler +{ + readonly topics = { + in: "notification:reaction", + }; + + readonly options = { + unique: true, + ack: true, + }; + + name = "PushReactionToUsersMessageProcessor"; + + validate(message: ReactionNotification): boolean { + return !!( + message && + message.message_id && + message.channel_id && + message.company_id && + message.workspace_id && + message.thread_id && + message.user_id && + message.reaction && + message.creation_date && + message.reaction_user_id + ); + } + + async process(task: ReactionNotification): Promise { + logger.info(`${this.name} - Processing reaction notification for message ${task.message_id}`); + + const location = { + company_id: task.company_id, + workspace_id: task.workspace_id, + channel_id: task.channel_id, + user: task.user_id.toString(), + thread_id: task.thread_id || task.message_id, + message_id: task.message_id, + }; + + const { title, text } = await this.buildNotificationMessageContent(task); + + websocketEventBus.publish(RealtimeEntityActionType.Event, { + type: "notification:desktop", + room: ResourcePath.get(getNotificationRoomName(task.user_id)), + entity: { + ...location, + title, + text, + }, + resourcePath: null, + result: null, + }); + + this.sendPushNotification(task.user_id, { + ...location, + title, + text, + }); + } + + sendPushNotification(user: string, reaction: PushNotificationMessage): void { + MobilePushNotifier.get(gr.platformServices.messageQueue).notify(user, reaction); + } + + async buildNotificationMessageContent( + message: ReactionNotification, + ): Promise<{ title: string; text: string }> { + const { company_id, workspace_id, reaction_user_id, reaction, thread_id } = message; + let title = ""; + + const channel: Channel = await gr.services.channels.channels.get({ + id: message.channel_id, + company_id: company_id, + workspace_id: workspace_id, + }); + + const [company, workspace, user] = await Promise.all([ + gr.services.companies.getCompany({ id: company_id }), + workspace_id === "direct" + ? null + : gr.services.workspaces.get({ + company_id: company_id, + id: workspace_id, + }), + gr.services.users.get({ id: reaction_user_id }), + ]); + + const msg = await gr.services.messages.messages.get({ + thread_id: thread_id, + id: message.message_id, + }); + + const companyName = company?.name || ""; + const workspaceName = workspace_id === "direct" ? "Direct" : workspace?.name || ""; + const userName = this.getUserName(user) || "Twake"; + + if (Channel.isDirectChannel(channel)) { + title = `${userName} in ${companyName}`; + } else { + title = `${channel.name} in ${companyName} β€’ ${workspaceName}`; + } + + return { + title, + text: `${userName}: ${reaction} to ${msg?.text || "your message"}`, + }; + } + + getUserName(user: User): string { + return ( + `${user?.first_name || ""} ${user?.last_name || ""}`.trim() || `@${user?.username_canonical}` + ); + } +} diff --git a/twake/backend/node/src/services/notifications/services/mobile-push.ts b/twake/backend/node/src/services/notifications/services/mobile-push.ts new file mode 100644 index 00000000..9c08810e --- /dev/null +++ b/twake/backend/node/src/services/notifications/services/mobile-push.ts @@ -0,0 +1,59 @@ +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import { PushNotificationMessage } from "../types"; +import User, { TYPE as UserType } from "../../user/entities/user"; +import { CrudException, ExecutionContext } from "../../../core/platform/framework/api/crud-service"; +import gr from "../../global-resolver"; + +export class MobilePushService { + name: "MobilePushService"; + version: "1"; + userRepository: Repository; + + async init(): Promise { + this.userRepository = await gr.database.getRepository(UserType, User); + return this; + } + + //Fixme: add a bulk system to group requests to fcm + async push(message: PushNotificationMessage, context?: ExecutionContext): Promise { + // Get devices and loop over devices + const userId = message.user; + + const user = await this.userRepository.findOne({ id: userId }, {}, context); + + if (!user) { + throw CrudException.notFound(`User ${userId} not found`); + } + + const notification = { + title: message.title, + body: message.text, + sound: "default", + badge: message.badge_value, + }; + + const options = { + notification_data: { + company_id: message.company_id, + workspace_id: message.workspace_id, + channel_id: message.channel_id, + message_id: message.message_id, + thread_id: message.thread_id, + }, + collapse_key: message.channel_id, + }; + + const { preferences } = await gr.services.notifications.preferences.getMerged( + { user_id: user.id, company_id: message.company_id, workspace_id: message.workspace_id }, + user, + ); + if (preferences.mobile_notifications === "never") { + return; + } + if (preferences.private_message_content) { + notification.body = "[Private]"; + } + + await gr.platformServices.push.push(user.devices, notification, options); + } +} diff --git a/twake/backend/node/src/services/notifications/services/preferences.ts b/twake/backend/node/src/services/notifications/services/preferences.ts new file mode 100644 index 00000000..7314e30b --- /dev/null +++ b/twake/backend/node/src/services/notifications/services/preferences.ts @@ -0,0 +1,147 @@ +import _ from "lodash"; +import { Initializable, TwakeServiceProvider } from "../../../core/platform/framework"; +import { + CrudException, + DeleteResult, + ExecutionContext, + ListResult, + OperationType, + SaveResult, +} from "../../../core/platform/framework/api/crud-service"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import User, { UserNotificationPreferences } from "../../../services/user/entities/user"; +import gr from "../../global-resolver"; + +type UserNotificationPreferencesPrimaryKey = { + company_id: string; + workspace_id: string; + user_id: string; +}; + +export class NotificationPreferencesService implements TwakeServiceProvider, Initializable { + version: "1"; + repository: Repository; + + async init(): Promise { + return this; + } + + async list(): Promise> { + throw new Error("Not implemented"); + } + + async get( + pk: UserNotificationPreferencesPrimaryKey, + user?: User, + ): Promise { + user = user || (await gr.services.users.get({ id: pk.user_id })); + const notificationPreferences = (user?.preferences?.notifications || []).find(n => { + return n.company_id === pk.company_id && n.workspace_id === pk.workspace_id; + }); + return ( + notificationPreferences || { + company_id: pk.company_id, + workspace_id: pk.workspace_id, + preferences: { + highlight_words: [], + night_break: { + enable: false, + from: 0, + to: 0, + }, + private_message_content: false, + mobile_notifications: "always", + email_notifications_delay: 15, + deactivate_notifications_until: 0, + notification_sound: "default", + }, + } + ); + } + + /** We can define preferences for specifically a workspace or for all a company or all Twake + * This function will ensure we get all with inherit and all + */ + async getMerged( + pk: UserNotificationPreferencesPrimaryKey, + user?: User, + ): Promise { + let preferences = await this.get(pk, user); + if (pk.workspace_id !== "all") + preferences = _.merge(await this.get({ ...pk, workspace_id: "all" }), preferences); + if (pk.company_id !== "all") + preferences = _.merge( + await this.get({ ...pk, workspace_id: "all", company_id: "all" }), + preferences, + ); + return preferences; + } + + async delete( + pk: UserNotificationPreferencesPrimaryKey, + context?: ExecutionContext, + ): Promise> { + const user = await gr.services.users.get({ id: pk.user_id }); + const notificationPreferences = (user?.preferences?.notifications || []).filter(n => { + return n.company_id !== pk.company_id || n.workspace_id !== pk.workspace_id; + }); + + await gr.services.users.setPreferences( + { id: pk.user_id }, + { + notifications: notificationPreferences, + }, + context, + ); + + return new DeleteResult("user_notifications_preference", pk as any, true); + } + + async listPreferences( + workspace_id: string, + company_id: string, + user_id: string, + ): Promise> { + if (!workspace_id || !company_id || !user_id) { + throw CrudException.badRequest("workspace_id, company_id and user_id are required"); + } + + const user = await gr.services.users.get({ id: user_id }); + + const notificationPreferences = (user?.preferences?.notifications || []).filter(n => { + return n.company_id === company_id && n.workspace_id === workspace_id; + }); + + return new ListResult("user_notifications_preference", notificationPreferences); + } + + async savePreferences( + singleNotificationPreferences: UserNotificationPreferences, + userId: string, + context: ExecutionContext, + ): Promise> { + const user = await gr.services.users.get({ id: userId }); + + const notificationPreferences = (user?.preferences?.notifications || []).filter(n => { + return ( + n.company_id !== singleNotificationPreferences.company_id || + n.workspace_id !== singleNotificationPreferences.workspace_id + ); + }); + notificationPreferences.push(singleNotificationPreferences); + + await gr.services.users.setPreferences( + { id: userId }, + { + notifications: notificationPreferences, + }, + context, + ); + + return new SaveResult( + "user_notifications_preference", + singleNotificationPreferences, + OperationType.CREATE, + ); + } +} diff --git a/twake/backend/node/src/services/notifications/services/realtime.ts b/twake/backend/node/src/services/notifications/services/realtime.ts new file mode 100644 index 00000000..b71d949e --- /dev/null +++ b/twake/backend/node/src/services/notifications/services/realtime.ts @@ -0,0 +1,12 @@ +import { User, WebsocketMetadata } from "../../../utils/types"; + +export function getWebsocketInformation(user: User): WebsocketMetadata { + return { + room: getNotificationRoomName(user.id), + token: "", + }; +} + +export function getNotificationRoomName(userId: string): string { + return `/notifications?type=private&user=${userId}`; +} diff --git a/twake/backend/node/src/services/notifications/types.ts b/twake/backend/node/src/services/notifications/types.ts new file mode 100644 index 00000000..dc62345e --- /dev/null +++ b/twake/backend/node/src/services/notifications/types.ts @@ -0,0 +1,99 @@ +import { ExecutionContext } from "../../core/platform/framework/api/crud-service"; +import { Channel, ChannelMember } from "../channels/entities"; +import { PaginationQueryParameters } from "../channels/web/types"; +import { SpecialMention } from "../messages/types"; +import { uuid } from "../../utils/types"; +import { MessageQueueHandler } from "../../core/platform/services/message-queue/api"; + +export type NotificationConfiguration = { + push: { + type: "fcm"; + fcm: { + endpoint: string; + key: string; + }; + }; +}; + +export type NotificationExecutionContext = ExecutionContext; + +export type MentionNotification = { + company_id: uuid; + workspace_id: uuid | "direct"; + channel_id: uuid; + thread_id: uuid; + message_id: uuid; + creation_date: number; + mentions?: { + users: uuid[]; + specials?: SpecialMention[]; + }; + object_names?: { + users: { [id: string]: string }; + channels: { [id: string]: string }; + }; + title: string; + text: string; +}; + +export type MentionNotificationResult = MentionNotification; + +export type ChannelReadMessage = { member: ChannelMember; channel: Channel }; +export type ChannelUnreadMessage = ChannelReadMessage; + +export type PushNotificationMessage = { + company_id: uuid; + workspace_id: uuid | "direct"; + channel_id: uuid; + message_id: uuid; + thread_id: uuid; + badge_value?: number; + user: string; + title: string; + text: string; +}; +export type PushNotificationMessageResult = PushNotificationMessage; + +export interface NotificationListQueryParameters extends PaginationQueryParameters { + company_id: uuid; + workspace_id: uuid | "direct"; + channel_id: uuid; + thread_id: uuid; + all_companies: boolean; +} + +export interface NotificationListUrlParameters { + company_id: uuid; +} + +export interface NotificationPreferenceListQueryParameters extends PaginationQueryParameters { + workspace_id: uuid | "all"; + company_id: uuid | "all"; + user_id: uuid; +} + +export type NotificationMessageQueueHandler = MessageQueueHandler< + InputMessage, + OutputMessage +>; + +export type ReactionNotification = { + company_id: uuid; + workspace_id: uuid | "direct"; + channel_id: uuid; + thread_id: uuid; + message_id: uuid; + creation_date: number; + user_id: string; + reaction: string; + reaction_user_id: string; +}; + +export type ReactionNotificationResult = ReactionNotification; + +export type NotificationAcknowledgeBody = { + thread_id: uuid; + workspace_id: uuid | "direct"; + channel_id: uuid; + message_id: uuid; +}; diff --git a/twake/backend/node/src/services/notifications/web/controllers/index.ts b/twake/backend/node/src/services/notifications/web/controllers/index.ts new file mode 100644 index 00000000..3d6bbf8f --- /dev/null +++ b/twake/backend/node/src/services/notifications/web/controllers/index.ts @@ -0,0 +1,2 @@ +export * from "./notification"; +export * from "./preferences"; diff --git a/twake/backend/node/src/services/notifications/web/controllers/notification.ts b/twake/backend/node/src/services/notifications/web/controllers/notification.ts new file mode 100644 index 00000000..0519552b --- /dev/null +++ b/twake/backend/node/src/services/notifications/web/controllers/notification.ts @@ -0,0 +1,122 @@ +import { FastifyReply, FastifyRequest } from "fastify"; +import { CrudController } from "../../../../core/platform/services/webserver/types"; +import { NotificationAcknowledgeBody, NotificationListQueryParameters } from "../../types"; +import { + ResourceCreateResponse, + ResourceDeleteResponse, + ResourceGetResponse, + ResourceListResponse, +} from "../../../../utils/types"; +import { UserNotificationBadge } from "../../entities"; +import { getWebsocketInformation } from "../../services/realtime"; +import gr from "../../../global-resolver"; +import { WorkspaceExecutionContext } from "../../../channels/types"; + +export class NotificationController + implements + CrudController< + ResourceGetResponse, + ResourceCreateResponse, + ResourceListResponse, + ResourceDeleteResponse + > +{ + async list( + request: FastifyRequest<{ + Querystring: NotificationListQueryParameters; + }>, + ): Promise> { + const context = getExecutionContext(request); + + let resources: UserNotificationBadge[] = []; + let page_token = ""; + + //Get one badge per company if requested + if (request.query.all_companies) { + const list = await gr.services.notifications.badges.listForUserPerCompanies( + request.currentUser.id, + context, + ); + resources = resources.concat(list.getEntities()); + } + + if (request.query.company_id) { + const list = await gr.services.notifications.badges.listForUser( + request.query.company_id, + request.currentUser.id, + { ...request.query }, + context, + ); + resources = resources.concat(list.getEntities()); + page_token = list.page_token; + } + + return { + ...{ + resources, + }, + ...(request.query.websockets && { + websockets: gr.platformServices.realtime.sign( + [getWebsocketInformation(request.currentUser)], + request.currentUser.id, + ), + }), + ...(page_token && { + next_page_token: page_token, + }), + }; + } + + /** + * Acknowledge a notification + * + * @param {FastifyRequest} request - The request object + * @param {FastifyReply} reply - The reply object + * @returns {Promise} - The response object + */ + async acknowledge( + request: FastifyRequest<{ + Params: { + company_id: string; + }; + Body: NotificationAcknowledgeBody; + }>, + reply: FastifyReply, + ): Promise { + const context = getExecutionContext(request); + const { company_id } = request.params; + const { workspace_id, channel_id, thread_id, message_id } = request.body; + + try { + await gr.services.notifications.badges.acknowledge( + { + channel_id, + company_id, + thread_id, + user_id: context.user.id, + workspace_id, + message_id, + }, + context, + ); + + return reply.send(true); + } catch (err) { + return reply.send(false); + } + } +} + +function getExecutionContext(request: FastifyRequest): WorkspaceExecutionContext { + return { + user: request.currentUser, + url: request.url, + method: request.routerMethod, + reqId: request.id, + transport: "http", + workspace: { + company_id: undefined, + workspace_id: undefined, + }, + }; +} diff --git a/twake/backend/node/src/services/notifications/web/controllers/preferences.ts b/twake/backend/node/src/services/notifications/web/controllers/preferences.ts new file mode 100644 index 00000000..5114d78c --- /dev/null +++ b/twake/backend/node/src/services/notifications/web/controllers/preferences.ts @@ -0,0 +1,78 @@ +import { FastifyReply, FastifyRequest } from "fastify"; +import { ExecutionContext } from "../../../../core/platform/framework/api/crud-service"; +import { UserNotificationPreferences } from "../../../../services/user/entities/user"; +import { handleError } from "../../../../utils/handleError"; +import { ResourceCreateResponse, ResourceListResponse } from "../../../../utils/types"; +import gr from "../../../global-resolver"; +import { NotificationPreferenceListQueryParameters } from "../../types"; + +const ALL = "all"; + +export class NotificationPreferencesController { + async list( + request: FastifyRequest<{ + Querystring: NotificationPreferenceListQueryParameters; + }>, + ): Promise> { + const list = await gr.services.notifications.preferences.listPreferences( + ALL, + ALL, + request.currentUser.id, + ); + + let resources = list.getEntities(); + + if (!resources.length) { + resources = [ + { + company_id: ALL, + workspace_id: ALL, + preferences: { + highlight_words: [], + night_break: { enable: false, from: 0, to: 0 }, + private_message_content: false, + mobile_notifications: "always", + email_notifications_delay: 15, + deactivate_notifications_until: 0, + notification_sound: "default", + }, + }, + ]; + } + + return { resources }; + } + + async save( + request: FastifyRequest<{ Body: { resource: UserNotificationPreferences } }>, + reply: FastifyReply, + context?: ExecutionContext, + ): Promise> { + const entity = { + workspace_id: ALL, + company_id: ALL, + user_id: request.currentUser.id, + preferences: { + ...request.body.resource, + }, + }; + + try { + const result = await gr.services.notifications.preferences.savePreferences( + entity as UserNotificationPreferences, + request.currentUser.id, + context, + ); + + if (result) { + reply.code(201); + } + + return { + resource: result.entity, + }; + } catch (err) { + handleError(reply, err); + } + } +} diff --git a/twake/backend/node/src/services/notifications/web/index.ts b/twake/backend/node/src/services/notifications/web/index.ts new file mode 100644 index 00000000..cef68280 --- /dev/null +++ b/twake/backend/node/src/services/notifications/web/index.ts @@ -0,0 +1,12 @@ +import { FastifyInstance, FastifyRegisterOptions } from "fastify"; +import routes from "./routes"; + +export default ( + fastify: FastifyInstance, + options: FastifyRegisterOptions<{ + prefix: string; + }>, +): void => { + fastify.log.debug("Configuring /internal/services/notifications/v1 routes"); + fastify.register(routes, options); +}; diff --git a/twake/backend/node/src/services/notifications/web/middleware.ts b/twake/backend/node/src/services/notifications/web/middleware.ts new file mode 100644 index 00000000..e69de29b diff --git a/twake/backend/node/src/services/notifications/web/routes.ts b/twake/backend/node/src/services/notifications/web/routes.ts new file mode 100644 index 00000000..2749c367 --- /dev/null +++ b/twake/backend/node/src/services/notifications/web/routes.ts @@ -0,0 +1,44 @@ +import { FastifyInstance, FastifyPluginCallback } from "fastify"; +import { NotificationController, NotificationPreferencesController } from "./controllers"; +import { createNotificationPreferencesSchema } from "./schemas"; + +const badgesUrl = "/badges"; +const notificationPreferencesUrl = "/preferences"; + +const routes: FastifyPluginCallback = (fastify: FastifyInstance, options, next) => { + const notificationController = new NotificationController(); + const notificationPreferencesController = new NotificationPreferencesController(); + + fastify.route({ + method: "GET", + url: badgesUrl, + preValidation: [fastify.authenticate], + handler: notificationController.list.bind(notificationController), + }); + + fastify.route({ + method: "GET", + url: notificationPreferencesUrl, + preValidation: [fastify.authenticate], + handler: notificationPreferencesController.list.bind(notificationPreferencesController), + }); + + fastify.route({ + method: "POST", + url: notificationPreferencesUrl, + preValidation: [fastify.authenticate], + schema: createNotificationPreferencesSchema, + handler: notificationPreferencesController.save.bind(notificationPreferencesController), + }); + + fastify.route({ + method: "POST", + url: `${badgesUrl}/:company_id/acknowledge`, + preValidation: [fastify.authenticate], + handler: notificationController.acknowledge.bind(notificationController), + }); + + next(); +}; + +export default routes; diff --git a/twake/backend/node/src/services/notifications/web/schemas.ts b/twake/backend/node/src/services/notifications/web/schemas.ts new file mode 100644 index 00000000..40517676 --- /dev/null +++ b/twake/backend/node/src/services/notifications/web/schemas.ts @@ -0,0 +1,43 @@ +const notificationPreferencesSchema = { + type: "object", + properties: { + preferences: { + type: "object", + properties: { + highlight_words: { type: "array" }, + night_break: { + type: "object", + properties: { + enable: { type: "boolean" }, + from: { type: "number" }, + to: { type: "number" }, + }, + }, + private_message_content: { type: "boolean" }, + mobile_notifications: { type: "string" }, + email_notifications_delay: { type: "number" }, + deactivate_notifications_until: { type: "number" }, + notification_sound: { type: "string" }, + }, + }, + }, +}; + +export const createNotificationPreferencesSchema = { + body: { + type: "object", + properties: { + resource: notificationPreferencesSchema, + }, + required: ["resource"], + }, + response: { + 201: { + type: "object", + properties: { + resource: notificationPreferencesSchema, + }, + required: ["resource"], + }, + }, +}; diff --git a/twake/backend/node/src/services/notifications/web/types.ts b/twake/backend/node/src/services/notifications/web/types.ts new file mode 100644 index 00000000..e69de29b diff --git a/twake/backend/node/src/services/online/api.ts b/twake/backend/node/src/services/online/api.ts new file mode 100644 index 00000000..ca78f8ed --- /dev/null +++ b/twake/backend/node/src/services/online/api.ts @@ -0,0 +1,25 @@ +import { TwakeServiceProvider } from "../../core/platform/framework"; +import UserOnline, { UserOnlinePrimaryKey } from "./entities/user-online"; + +export type OnlineEvent = { + company_id: string; + user_id: string; + is_online: boolean; +}; + +export type UsersOnlineMessage = Array; + +export type OnlineGetRequest = { + /* Array of ids to get status */ + data: Array; +}; + +export type OnlineGetResponse = { + data: Array<[string, boolean]>; +}; + +export interface OnlineServiceAPI extends TwakeServiceProvider { + isOnline(userId: string): Promise; + setLastSeenOnline(userIds: Array, lastSeen: number, is_connected: boolean): Promise; + get(userId: UserOnlinePrimaryKey): Promise; +} diff --git a/twake/backend/node/src/services/online/constants.ts b/twake/backend/node/src/services/online/constants.ts new file mode 100644 index 00000000..f4538600 --- /dev/null +++ b/twake/backend/node/src/services/online/constants.ts @@ -0,0 +1,2 @@ +export const DISCONNECTED_DELAY = 900000; +export const ONLINE_TOPIC = "user:online"; diff --git a/twake/backend/node/src/services/online/entities/user-online.ts b/twake/backend/node/src/services/online/entities/user-online.ts new file mode 100644 index 00000000..9071edbd --- /dev/null +++ b/twake/backend/node/src/services/online/entities/user-online.ts @@ -0,0 +1,32 @@ +import { Type } from "class-transformer"; +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "user_online"; + +@Entity(TYPE, { + primaryKey: ["user_id"], + type: TYPE, +}) +export default class UserOnline { + @Type(() => String) + @Column("user_id", "timeuuid", { generator: "timeuuid" }) + user_id: string; + + @Type(() => Boolean) + @Column("is_connected", "boolean") + is_connected: boolean; + + /** + * Save the date the user has been seen connected + */ + @Type(() => Number) + @Column("last_seen", "number") + last_seen: number; +} + +export type UserOnlinePrimaryKey = { user_id: string }; + +export function getInstance(element: Partial): UserOnline { + return merge(new UserOnline(), element); +} diff --git a/twake/backend/node/src/services/online/index.ts b/twake/backend/node/src/services/online/index.ts new file mode 100644 index 00000000..9c9f9f02 --- /dev/null +++ b/twake/backend/node/src/services/online/index.ts @@ -0,0 +1,15 @@ +import { Prefix, TwakeService } from "../../core/platform/framework"; + +@Prefix("/internal/services/online/v1") +export default class OnlineService extends TwakeService { + version = "1"; + name = "online"; + + api(): undefined { + return undefined; + } + + public async doInit(): Promise { + return this; + } +} diff --git a/twake/backend/node/src/services/online/pubsub/index.ts b/twake/backend/node/src/services/online/pubsub/index.ts new file mode 100644 index 00000000..44ac7680 --- /dev/null +++ b/twake/backend/node/src/services/online/pubsub/index.ts @@ -0,0 +1,29 @@ +import { getLogger, Initializable, TwakeLogger } from "../../../core/platform/framework"; +import { UsersOnlineMessage } from "../api"; +import { ONLINE_TOPIC } from "../constants"; +import { UserOnlineProcessor } from "./processor"; +import gr from "../../global-resolver"; + +export class OnlinePubsubService implements Initializable { + private logger: TwakeLogger; + constructor() { + this.logger = getLogger("online.pubsub.OnlinePubsubService"); + } + + async init(): Promise { + gr.platformServices.messageQueue.processor.addHandler(new UserOnlineProcessor()); + return this; + } + + async broadcastOnline(online: UsersOnlineMessage = []): Promise { + if (!online.length) { + return; + } + + this.logger.debug(`Publishing online users ${online.map(u => u.user_id).join(",")}`); + + return gr.platformServices.messageQueue.publish(ONLINE_TOPIC, { + data: online, + }); + } +} diff --git a/twake/backend/node/src/services/online/pubsub/processor.ts b/twake/backend/node/src/services/online/pubsub/processor.ts new file mode 100644 index 00000000..a73e48f9 --- /dev/null +++ b/twake/backend/node/src/services/online/pubsub/processor.ts @@ -0,0 +1,52 @@ +import _ from "lodash"; +import { getLogger, TwakeLogger } from "../../../core/platform/framework"; +import { MessageQueueHandler } from "../../../core/platform/services/message-queue/api"; +import { websocketEventBus } from "../../../core/platform/services/realtime/bus"; +import { + RealtimeEntityActionType, + ResourcePath, +} from "../../../core/platform/services/realtime/types"; +import { UsersOnlineMessage } from "../api"; +import { ONLINE_TOPIC } from "../constants"; + +export class UserOnlineProcessor implements MessageQueueHandler { + private logger: TwakeLogger; + readonly topics = { + in: ONLINE_TOPIC, + }; + + readonly options = { + unique: false, + ack: true, + }; + + readonly name = "UserOnlineProcessor"; + + constructor() { + this.logger = getLogger(`online.pubsub.${this.name}`); + } + + validate(message: UsersOnlineMessage): boolean { + return !!(message && message.length); + } + + async process(message: UsersOnlineMessage): Promise { + this.logger.debug( + `Pushing user online status for users ${message.map(u => u.user_id).join(",")}`, + ); + + const grouped_data = _.groupBy(message, "company_id"); + + Object.values(grouped_data).forEach((messagePerCompany: UsersOnlineMessage) => { + websocketEventBus.publish(RealtimeEntityActionType.Event, { + type: "user:online", + room: ResourcePath.get(`/users/online/${messagePerCompany[0].company_id}`), + entity: { online: messagePerCompany }, + resourcePath: null, + result: null, + }); + }); + + return; + } +} diff --git a/twake/backend/node/src/services/online/service/index.ts b/twake/backend/node/src/services/online/service/index.ts new file mode 100644 index 00000000..98e6a360 --- /dev/null +++ b/twake/backend/node/src/services/online/service/index.ts @@ -0,0 +1,174 @@ +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; + +import { OnlineGetRequest, OnlineGetResponse, OnlineServiceAPI } from "../api"; +import { OnlinePubsubService } from "../pubsub"; +import { DISCONNECTED_DELAY } from "../constants"; +import UserOnline, { + getInstance, + TYPE as ONLINE_TYPE, + UserOnlinePrimaryKey, +} from "../entities/user-online"; +import gr from "../../global-resolver"; +import { getLogger, TwakeLogger, TwakeServiceProvider } from "../../../core/platform/framework"; +import { getUserRoom } from "../../../services/user/realtime"; +import User from "../../../services/user/entities/user"; +import { WebsocketUserEvent } from "../../../core/platform/services/websocket/types"; +import { ExecutionContext } from "../../../core/platform/framework/api/crud-service"; + +export default class OnlineServiceImpl implements TwakeServiceProvider { + version = "1"; + service: OnlineServiceAPI; + private pubsubService: OnlinePubsubService; + onlineRepository: Repository; + private logger: TwakeLogger; + + constructor() { + this.logger = getLogger("online.service"); + } + + public async init(): Promise { + this.onlineRepository = await gr.database.getRepository(ONLINE_TYPE, UserOnline); + + this.pubsubService = new OnlinePubsubService(); + + await this.pubsubService.init(); + + gr.platformServices.websocket.onUserConnected(async event => { + const user: User = await gr.services.users.get({ + id: event.user.id, + }); + + const companies = user?.cache?.companies; + + this.logger.info("User connected", event.user.id); + // save the last connection date + this.setLastSeenOnline([event.user.id], Date.now(), true); + // broadcast to global pubsub so that everyone can publish to websockets + this.broadcastOnline(event, companies); + + event.socket.on( + "online:get", + async (request: OnlineGetRequest, ack: (response: OnlineGetResponse) => void) => { + this.logger.debug(`Got an online:get request for ${(request.data || []).length} users`); + ack({ data: await this.getOnlineStatuses(request.data) }); + }, + ); + + event.socket.on( + "online:set", + async (request: OnlineGetRequest, ack: () => void): Promise => { + this.logger.debug(`Got an online:set request for ${(request.data || []).length} users`); + + this.broadcastOnline(event, companies); + this.setLastSeenOnline([event.user.id], Date.now(), true); + ack(); + }, + ); + }); + + gr.platformServices.websocket.onUserDisconnected(async event => { + this.logger.info("User disconnected", event.user.id); + // Since the user can be connected on several nodes, we cannot directly set it status to offline + const room = getUserRoom(event.user.id); + const userSockets = await event.socket.in(room).allSockets(); + + if (userSockets.size === 0) { + this.pubsubService.broadcastOnline([ + { + company_id: "toBeFetched", + user_id: event.user.id, + is_online: false, + }, + ]); + this.setLastSeenOnline([event.user.id], Date.now(), false); + } + }); + + return this; + } + + private async getOnlineStatuses(ids: Array): Promise> { + console.log("socket getOnlineStatuses", ids); + return this.areOnline(ids); + } + + async setLastSeenOnline( + userIds: Array = [], + date: number, + is_connected: boolean, + ): Promise { + this.logger.debug(`setLastSeenOnline ${userIds.join(",")}`); + if (!userIds.length) { + return; + } + const last_seen = date || Date.now(); + const uniqueIds = new Set(userIds); + this.logger.info(`Update last active state for users ${userIds.join(",")}`); + const onlineUsers: UserOnline[] = Array.from(uniqueIds.values()).map(user_id => + getInstance({ user_id, last_seen, is_connected }), + ); + await this.onlineRepository.saveAll(onlineUsers); + + //Send websocket event + onlineUsers.forEach(u => { + gr.services.users.publishPublicUserRealtime(u.user_id); + }); + } + + async isOnline(userId: string, context?: ExecutionContext): Promise { + const user = await this.onlineRepository.findOne({ user_id: userId }, {}, context); + + if (!user) { + return false; + } + + return Date.now() - user.last_seen < DISCONNECTED_DELAY; + } + + private async areOnline( + ids: Array = [], + context?: ExecutionContext, + ): Promise> { + const users = []; + //This foreach is needed for $in operators https://github.com/linagora/Twake/issues/1246 + for (let i = 0; i < ids.length; i += 100) { + users.push( + ...( + await this.onlineRepository.find( + {}, + { $in: [["user_id", ids.slice(i, i + 100)]] }, + context, + ) + ).getEntities(), + ); + } + + return users.map(user => [ + user.user_id, + this.isStillConnected(user.last_seen, user.is_connected), + ]); + } + + /** + * let's say that a user is connected when its last connection is more than some delay ago + */ + private isStillConnected(date: number, is_connected: boolean): boolean { + return Date.now() - date < DISCONNECTED_DELAY && is_connected; + } + + private broadcastOnline(event: WebsocketUserEvent, companies: Array): void { + (companies || []).forEach(company => { + this.pubsubService.broadcastOnline([ + { + company_id: company, + user_id: event.user.id, + is_online: true, + }, + ]); + }); + } + + async get(pk: UserOnlinePrimaryKey): Promise { + return await this.onlineRepository.findOne(pk); + } +} diff --git a/twake/backend/node/src/services/previews/index.ts b/twake/backend/node/src/services/previews/index.ts new file mode 100644 index 00000000..222ae336 --- /dev/null +++ b/twake/backend/node/src/services/previews/index.ts @@ -0,0 +1,23 @@ +import WebServerAPI from "../../core/platform/services/webserver/provider"; +import { Prefix, TwakeService } from "../../core/platform/framework"; +import web from "./web"; + +@Prefix("/internal/services/previews/v1") +export default class PreviewsService extends TwakeService { + version = "1"; + name = "previews"; + + public async doInit(): Promise { + const fastify = this.context.getProvider("webserver").getServer(); + fastify.register((instance, _opts, next) => { + web(instance, { prefix: this.prefix }); + next(); + }); + return this; + } + + // TODO: remove + api(): undefined { + return undefined; + } +} diff --git a/twake/backend/node/src/services/previews/services/files/engine/clear.ts b/twake/backend/node/src/services/previews/services/files/engine/clear.ts new file mode 100644 index 00000000..06749c49 --- /dev/null +++ b/twake/backend/node/src/services/previews/services/files/engine/clear.ts @@ -0,0 +1,48 @@ +import { logger, TwakeContext } from "../../../../../core/platform/framework"; +import { PreviewClearMessageQueueRequest, PreviewMessageQueueCallback } from "../../../types"; +import gr from "../../../../global-resolver"; +import { MessageQueueHandler } from "../../../../../core/platform/services/message-queue/api"; + +/** + * Clear thumbnails when the delete task is called + */ +export class ClearProcessor + implements MessageQueueHandler +{ + readonly name = "ClearProcessor"; + + readonly topics = { + in: "services:preview:clear", + out: "services:preview:callback", + }; + + readonly options = { + unique: true, + ack: true, + }; + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + init?(context?: TwakeContext): Promise { + throw new Error("Method not implemented."); + } + + validate(message: PreviewClearMessageQueueRequest): boolean { + return !!(message && message.document); + } + + async process(message: PreviewClearMessageQueueRequest): Promise { + logger.info(`${this.name} - Processing preview generation ${message.document.id}`); + + if (!this.validate(message)) { + throw new Error("Missing required fields"); + } + + for (let i = 0; i < message.document.thumbnails_number; i++) { + await gr.platformServices.storage.remove( + `${message.document.path.replace(/\/$/, "")}/${i}.png`, + ); + } + + return { document: message.document, thumbnails: [] }; + } +} diff --git a/twake/backend/node/src/services/previews/services/files/engine/index.ts b/twake/backend/node/src/services/previews/services/files/engine/index.ts new file mode 100644 index 00000000..0d04a2b5 --- /dev/null +++ b/twake/backend/node/src/services/previews/services/files/engine/index.ts @@ -0,0 +1,15 @@ +import { Initializable } from "../../../../../core/platform/framework"; +import { ClearProcessor } from "./clear"; +import { PreviewProcessor } from "./service"; +import gr from "../../../../global-resolver"; + +/** + * The notification engine is in charge of processing data and delivering user notifications on the right place + */ +export class PreviewEngine implements Initializable { + async init(): Promise { + gr.platformServices.messageQueue.processor.addHandler(new PreviewProcessor()); + gr.platformServices.messageQueue.processor.addHandler(new ClearProcessor()); + return this; + } +} diff --git a/twake/backend/node/src/services/previews/services/files/engine/service.ts b/twake/backend/node/src/services/previews/services/files/engine/service.ts new file mode 100644 index 00000000..46f85930 --- /dev/null +++ b/twake/backend/node/src/services/previews/services/files/engine/service.ts @@ -0,0 +1,118 @@ +import fs, { promises as fsPromise } from "fs"; +import { logger } from "../../../../../core/platform/framework"; +import { + PreviewMessageQueueCallback, + PreviewMessageQueueRequest, + ThumbnailResult, +} from "../../../types"; +import gr from "../../../../global-resolver"; +import { MessageQueueHandler } from "../../../../../core/platform/services/message-queue/api"; +import { getTmpFile } from "../../../../../utils/files"; + +const { unlink } = fsPromise; +/** + * Generate thumbnails when the upload is finished + */ +export class PreviewProcessor + implements MessageQueueHandler +{ + readonly name = "PreviewProcessor"; + + init?(): Promise { + throw new Error("Method not implemented."); + } + + readonly topics = { + in: "services:preview", + out: "services:preview:callback", + }; + + readonly options = { + unique: true, + ack: true, + }; + + validate(message: PreviewMessageQueueRequest): boolean { + return !!(message && message.document && message.output); + } + + async process(message: PreviewMessageQueueRequest): Promise { + logger.info(`${this.name} - Processing preview generation ${message.document.id}`); + + let res: PreviewMessageQueueCallback = { document: message.document, thumbnails: [] }; + try { + res = await this.generate(message); + } catch (err) { + logger.error(`${this.name} - Can't generate thumbnails ${err}`); + } + + logger.info( + `${this.name} - Generated ${res.thumbnails.length} thumbnails from ${ + message.document.filename || message.document.id + }`, + ); + + return res; + } + + async generate(message: PreviewMessageQueueRequest): Promise { + //Download original file + const readable = await gr.platformServices.storage.read(message.document.path, { + totalChunks: message.document.chunks, + encryptionAlgo: message.document.encryption_algo, + encryptionKey: message.document.encryption_key, + }); + if (!readable) { + return { document: message.document, thumbnails: [] }; + } + + const inputPath = getTmpFile(); + const writable = fs.createWriteStream(inputPath); + + readable.pipe(writable); + + await new Promise(r => { + writable.on("finish", r); + }); + + writable.end(); + + //Generate previews + let localThumbnails: ThumbnailResult[] = []; + + try { + localThumbnails = await gr.services.preview.files.generateThumbnails( + { path: inputPath, mime: message.document.mime, filename: message.document.filename }, + message.output, + ); + } catch (err) { + logger.error(`${this.name} - Can't generate thumbnails ${err}`); + localThumbnails = []; + throw Error("Can't generate thumbnails."); + } + + const thumbnails: PreviewMessageQueueCallback["thumbnails"] = []; + + for (let i = 0; i < localThumbnails.length; i++) { + const uploadThumbnailPath = `${message.output.path.replace(/\/$/, "")}/${i}.png`; + const uploadThumbnail = fs.createReadStream(localThumbnails[i].path); + + await gr.platformServices.storage.write(uploadThumbnailPath, uploadThumbnail, { + encryptionAlgo: message.output.encryption_algo, + encryptionKey: message.output.encryption_key, + }); + + thumbnails.push({ + path: uploadThumbnailPath, + size: localThumbnails[i].size, + type: localThumbnails[i].type, + width: localThumbnails[i].width, + height: localThumbnails[i].height, + }); + + await unlink(localThumbnails[i].path); + } + + return { document: message.document, thumbnails }; + } +} diff --git a/twake/backend/node/src/services/previews/services/files/processing/image.ts b/twake/backend/node/src/services/previews/services/files/processing/image.ts new file mode 100644 index 00000000..349f5b22 --- /dev/null +++ b/twake/backend/node/src/services/previews/services/files/processing/image.ts @@ -0,0 +1,54 @@ +import sharp from "sharp"; +import { cleanFiles, getTmpFile } from "../../../../../utils/files"; +import { PreviewMessageQueueRequest, ThumbnailResult } from "../../../types"; +import { logger } from "../../../../../core/platform/framework/logger"; + +export async function generatePreview( + inputPaths: string[], + options: PreviewMessageQueueRequest["output"], +): Promise<{ + output: ThumbnailResult[]; + done: boolean; + error?: string; +}> { + const output: ThumbnailResult[] = []; + + for (const inputPath of inputPaths) { + let result: sharp.OutputInfo; + const outputPath = getTmpFile(); + try { + const inputMetadata = await sharp(inputPath).metadata(); + const outputFormat = computeNewFormat(inputMetadata, options); + + result = await sharp(inputPath).rotate().resize(outputFormat).toFile(outputPath); + output.push({ + path: outputPath, + width: result.width, + height: result.height, + type: "image/png", + size: result.size, + }); + } catch (error) { + logger.info(`sharp cant process ${error}`); + cleanFiles([outputPath]); + throw Error("Can't resize thumnail with Sharp"); + } + } + + return { + output, + done: true, + }; +} + +function computeNewFormat( + inputMetadata: sharp.Metadata, + options?: PreviewMessageQueueRequest["output"], +): { width: number; height: number } { + const maxOutputWidth = options?.width || 600; + const maxOutputHeight = options?.height || 400; + const inputWidth = inputMetadata.width; + const inputHeight = inputMetadata.height; + const scale = Math.max(inputWidth / maxOutputWidth, inputHeight / maxOutputHeight); + return { width: Math.round(inputWidth / scale), height: Math.round(inputHeight / scale) }; +} diff --git a/twake/backend/node/src/services/previews/services/files/processing/office.ts b/twake/backend/node/src/services/previews/services/files/processing/office.ts new file mode 100644 index 00000000..2cd99a3c --- /dev/null +++ b/twake/backend/node/src/services/previews/services/files/processing/office.ts @@ -0,0 +1,29 @@ +// eslint-disable-next-line @typescript-eslint/no-var-requires +const unoconv = require("unoconv-promise"); +import { cleanFiles } from "../../../../../utils/files"; +import { logger } from "../../../../../core/platform/framework/logger"; + +export async function convertFromOffice( + path: string, + options: { + numberOfPages?: number; + }, +): Promise<{ output: string; done: boolean }> { + if (options.numberOfPages >= 1) { + const outputPath = `${path}.pdf`; + try { + await unoconv.run({ + file: path, + output: outputPath, + export: `PageRange=1-${options.numberOfPages}`, + }); + } catch (err) { + logger.error(`unoconv cant process ${err}`); + cleanFiles([outputPath]); + throw Error("Can't convert file with unoconv"); + } + return { output: outputPath, done: true }; + } else { + logger.error("Unoconv can't processe, number of pages lower than 1"); + } +} diff --git a/twake/backend/node/src/services/previews/services/files/processing/pdf.ts b/twake/backend/node/src/services/previews/services/files/processing/pdf.ts new file mode 100644 index 00000000..4ce052af --- /dev/null +++ b/twake/backend/node/src/services/previews/services/files/processing/pdf.ts @@ -0,0 +1,43 @@ +import { fromPath } from "pdf2pic"; +import { mkdirSync } from "fs"; +import { cleanFiles, getTmpFile } from "../../../../../utils/files"; + +export async function convertFromPdf( + inputPath: string, + options: { + numberOfPages: number; + }, +): Promise<{ output: string[]; done: boolean }> { + const pages: string[] = []; + + try { + const pdfOptions = { + density: 100, + saveFilename: "output", + savePath: getTmpFile(), + format: "png", + }; + mkdirSync(pdfOptions.savePath, { recursive: true }); + const storeAsImage = fromPath(inputPath, pdfOptions); + try { + for (let i = 1; i <= options.numberOfPages; i++) { + const image = await storeAsImage(i); + pages.push( + `${pdfOptions.savePath}/${pdfOptions.saveFilename}.${image.page}.${pdfOptions.format}`, + ); + } + } catch (err) { + if (!pages.length) { + throw err; + } + //Just no more page to convert + } + } catch (error) { + console.error(error); + for (const file of pages) { + cleanFiles([file]); + } + throw Error("Can't convert file with pdf-image."); + } + return { output: pages, done: true }; +} diff --git a/twake/backend/node/src/services/previews/services/files/processing/service.ts b/twake/backend/node/src/services/previews/services/files/processing/service.ts new file mode 100644 index 00000000..139a5316 --- /dev/null +++ b/twake/backend/node/src/services/previews/services/files/processing/service.ts @@ -0,0 +1,71 @@ +import { generatePreview as thumbnailsFromImages } from "./image"; +import { convertFromOffice } from "./office"; +import { convertFromPdf } from "./pdf"; +import { isFileType } from "../../../utils"; +import { + imageExtensions, + officeExtensions, + pdfExtensions, + videoExtensions, +} from "../../../../../utils/mime"; +import { PreviewMessageQueueRequest, ThumbnailResult } from "../../../types"; +import { generateVideoPreview } from "./video"; +import { Initializable, TwakeServiceProvider } from "../../../../../core/platform/framework"; +import { cleanFiles } from "../../../../../utils/files"; + +export class PreviewProcessService implements TwakeServiceProvider, Initializable { + name: "PreviewProcessService"; + version: "1"; + + async init(): Promise { + return this; + } + + async generateThumbnails( + document: Pick, + options: PreviewMessageQueueRequest["output"], + ): Promise { + if (isFileType(document.mime, document.filename, officeExtensions)) { + const pdfPath = await convertFromOffice(document.path, { + numberOfPages: options.pages, + }); + await cleanFiles([document.path]); + const thumbnailPath = await convertFromPdf(pdfPath.output, { + numberOfPages: options.pages, + }); + await cleanFiles([pdfPath.output]); + const images = (await thumbnailsFromImages(thumbnailPath.output, options)).output; + await cleanFiles(thumbnailPath.output); + return images; + } + + if (isFileType(document.mime, document.filename, pdfExtensions)) { + const thumbnailPath = await convertFromPdf(document.path, { + numberOfPages: options.pages, + }); + await cleanFiles([document.path]); + const images = (await thumbnailsFromImages(thumbnailPath.output, options)).output; + await cleanFiles(thumbnailPath.output); + return images; + } + + if (isFileType(document.mime, document.filename, imageExtensions)) { + const images = (await thumbnailsFromImages([document.path], options)).output; + await cleanFiles([document.path]); + return images; + } + + if (isFileType(document.mime, document.filename, videoExtensions)) { + try { + const images = await generateVideoPreview([document.path]); + await cleanFiles([document.path]); + + return images; + } catch (error) { + throw Error("failed to generate video preview"); + } + } + + throw "Can not proccess, file type can't be defined"; + } +} diff --git a/twake/backend/node/src/services/previews/services/files/processing/video.ts b/twake/backend/node/src/services/previews/services/files/processing/video.ts new file mode 100644 index 00000000..e64041dc --- /dev/null +++ b/twake/backend/node/src/services/previews/services/files/processing/video.ts @@ -0,0 +1,167 @@ +import ffmpeg from "fluent-ffmpeg"; +import { temporaryThumbnailFile, ThumbnailResult } from "../../../types"; +import fs from "fs"; +import { cleanFiles, getTmpFile } from "../../../../../utils/files"; + +/** + * Generate thumbnails for given video files. + * + * @param {String[]} videoPaths - the input video paths + * @returns {Promise} - resolves when the thumbnails are generated + */ +export async function generateVideoPreview(videoPaths: string[]): Promise { + const output: ThumbnailResult[] = []; + + for (const videoPath of videoPaths) { + const { fileName, folder, filePath } = getTemporaryThumbnailFile(); + + try { + const { width, height } = await takeVideoScreenshot(videoPath, folder, fileName); + + output.push({ + ...getThumbnailInformation(filePath), + width, + height, + }); + } catch (error) { + cleanFiles([filePath]); + throw Error(`failed to generate video preview: ${error}`); + } + } + + return output; +} + +/** + * Generate one thumbnail from a single video file. + * the thumbnail is the first frame from the video + * + * @param {String} inputPath - the input video Path + * @param {String} outputFolder - the output folder + * @param {String} outputFile - the output file name + * @returns {Primise} - resolves when the thumbnail is generated + */ +const takeVideoScreenshot = async ( + inputPath: string, + outputFolder: string, + outputFile: string, +): Promise<{ width: number; height: number }> => { + return new Promise(async (resolve, reject) => { + try { + const { width, height } = await getVideoDimensions(inputPath); + const { width: outputWidth, height: outputHeight } = calculateThumbnailDimensions( + width, + height, + ); + + ffmpeg(inputPath) + .screenshot({ + count: 1, + filename: outputFile, + folder: outputFolder, + timemarks: ["0"], + size: `${outputWidth}x${outputHeight}`, + }) + .on("end", () => { + resolve({ width: outputWidth, height: outputHeight }); + }) + .on("error", error => { + reject(error); + }); + } catch (error) { + reject(error); + } + }); +}; + +/** + * Get the generated thumbnail information. + * + * @param {String} path - the path to the thumbnail + * @param {PreviewMessageQueueRequest["output"]} options - the options for the thumbnails + * @returns { { path: string, type: string, size: number } } - the thumbnail information + */ +const getThumbnailInformation = ( + path: string, +): { + path: string; + type: string; + size: number; +} => { + const stats = fs.statSync(path); + + return { + size: stats.size, + type: "image/jpg", + path, + }; +}; + +/** + * generate a temporary thumbnail file. + * + * @returns {temporaryThumbnailFile} - the temporary thumbnail file information + */ +const getTemporaryThumbnailFile = (): temporaryThumbnailFile => { + const filePath = `${getTmpFile()}.jpg`; + const fileName = filePath.split("/").pop(); + const folder = filePath.substring(0, filePath.lastIndexOf("/")); + + return { + folder, + fileName, + filePath, + }; +}; + +/** + * Detect video dimensions + * + * @param {String} videoPath - the video path + * @returns {Promise<{ width: number, height: number }>} - the video dimensions + */ +async function getVideoDimensions(videoPath: string): Promise<{ width: number; height: number }> { + return new Promise((resolve, reject) => { + ffmpeg.ffprobe(videoPath, (err, metadata) => { + if (err) { + reject(err); + } + + const { width, height } = metadata.streams[0]; + resolve({ width, height }); + }); + }); +} + +/** + * Calculate the thumbnail dimensions. + * maximum dimension is 1080p and the minimum dimension is 320x240. + * The aspect ratio is preserved. + * + * @param {Number} width - the video width + * @param {Number} height - the video height + * @returns { { width: number, height: number } } - the thumbnail dimensions + */ +function calculateThumbnailDimensions( + width: number, + height: number, +): { + width: number; + height: number; +} { + let newWidth = Math.min(width, 1920); + let newHeight = Math.min(height, 1080); + const ratio = width / height; + + if (width > 1920 || height > 1080) { + newWidth = Math.min(1920, width); + newHeight = Math.min(1080, newWidth / ratio); + } + + if (width < 320 || height < 240) { + newWidth = Math.max(320, width); + newHeight = Math.max(240, newWidth / ratio); + } + + return { width: newWidth, height: newHeight }; +} diff --git a/twake/backend/node/src/services/previews/services/links/engine/index.ts b/twake/backend/node/src/services/previews/services/links/engine/index.ts new file mode 100644 index 00000000..8f857fa3 --- /dev/null +++ b/twake/backend/node/src/services/previews/services/links/engine/index.ts @@ -0,0 +1,11 @@ +import { Initializable } from "../../../../../core/platform/framework"; +import { LinkPreviewProcessor } from "./service"; +import gr from "../../../../global-resolver"; + +export class LinkPreviewEngine implements Initializable { + async init(): Promise { + gr.platformServices.messageQueue.processor.addHandler(new LinkPreviewProcessor()); + + return this; + } +} diff --git a/twake/backend/node/src/services/previews/services/links/engine/service.ts b/twake/backend/node/src/services/previews/services/links/engine/service.ts new file mode 100644 index 00000000..8cd7d39e --- /dev/null +++ b/twake/backend/node/src/services/previews/services/links/engine/service.ts @@ -0,0 +1,80 @@ +import { + LinkPreview, + LinkPreviewMessageQueueCallback, + LinkPreviewMessageQueueRequest, +} from "../../../types"; +import { logger } from "../../../../../core/platform/framework"; +import gr from "../../../../global-resolver"; +import { MessageQueueHandler } from "../../../../../core/platform/services/message-queue/api"; + +export class LinkPreviewProcessor + implements MessageQueueHandler +{ + readonly name = "LinkPreviewProcessor"; + + readonly topics = { + in: "services:preview:links", + out: "services:preview:links:callback", + }; + + readonly options = { + unique: true, + ack: true, + }; + + init?(): Promise { + throw new Error("Method not implemented."); + } + + /** + * Checks if the message is valid + * + * @param {LinkPreviewMessageQueueRequest} message - The message to check + * @returns {Boolean} - true if the message is valid + */ + validate(message: LinkPreviewMessageQueueRequest): boolean { + return !!(message && message.links && message.links.length); + } + + /** + * process the links preview generation message + * + * @param {LinkPreviewMessageQueueRequest} message - The message to process + * @returns {Promise} - links preview callback + */ + async process(message: LinkPreviewMessageQueueRequest): Promise { + logger.info(`${this.name} - Processing preview generation for ${message.links.length} links`); + + let res: LinkPreviewMessageQueueCallback = { previews: [], message: message.message }; + + try { + res = await this.generate(message); + } catch (err) { + logger.error(`${this.name} - Can't generate link previews ${err}`); + } + + logger.info(`${this.name} - Generated ${res.previews.length} link previews`); + + return res; + } + + /** + * Generate previews for links + * + * @param {LinkPreviewMessageQueueRequest} message - The message to process + * @returns {Promise} - links preview callback + */ + async generate( + message: LinkPreviewMessageQueueRequest, + ): Promise { + let previews: LinkPreview[] = []; + try { + previews = await gr.services.preview.links.generatePreviews(message.links); + } catch (err) { + logger.error(`${this.name} - Can't generate link previews ${err}`); + throw Error(`cannot generate link previews: ${err}`); + } + + return { previews, message: message.message }; + } +} diff --git a/twake/backend/node/src/services/previews/services/links/processing/image.ts b/twake/backend/node/src/services/previews/services/links/processing/image.ts new file mode 100644 index 00000000..77a6c3f3 --- /dev/null +++ b/twake/backend/node/src/services/previews/services/links/processing/image.ts @@ -0,0 +1,37 @@ +import { LinkPreview } from "../../../types"; +import { logger } from "../../../../../core/platform/framework"; +import imageProbe from "probe-image-size"; +import { getUrlFavicon, getDomain } from "../../../utils"; + +/** + * Generate a preview for a given image url. + * + * @param {String} url - the input url + * @returns {Promise} - resolves when the preview is generated + */ +export const generateImageUrlPreview = async (url: string): Promise => { + try { + const favicon = (await getUrlFavicon(getWebsiteUrl(url))) || null; + const domain = getDomain(url); + const title = url.split("/").pop(); + const { height: img_height, width: img_width } = await imageProbe(url); + + return { + title, + domain, + favicon, + url, + img_height, + img_width, + description: null, + img: url, + }; + } catch (error) { + logger.error(`failed to generate image url preview: ${error}`); + } +}; + +const getWebsiteUrl = (url: string) => { + const urlObj = new URL(url); + return `${urlObj.protocol}//${urlObj.hostname}`; +}; diff --git a/twake/backend/node/src/services/previews/services/links/processing/link.ts b/twake/backend/node/src/services/previews/services/links/processing/link.ts new file mode 100644 index 00000000..292699fb --- /dev/null +++ b/twake/backend/node/src/services/previews/services/links/processing/link.ts @@ -0,0 +1,77 @@ +import { parser } from "html-metadata-parser"; +import { LinkPreview } from "../../../types"; +import { logger } from "../../../../../core/platform/framework"; +import imageProbe from "probe-image-size"; +import { getUrlFavicon, getDomain, TIMEOUT, MAX_SIZE } from "../../../utils"; +import ua from "random-useragent"; + +type HtmlImage = { + src: string; +}; + +/** + * Generate a thumbnail for a given url. + * + * @param {String[]} urls - the input urls + * @returns {Promise} - resolves when the preview is generated + */ +export async function generateLinkPreview(url: string): Promise { + try { + return await getUrlInformation(url); + } catch (error) { + logger.error(`failed to generate link preview: ${error}`); + } +} + +/** + * get url information + * + * @param {String} url - the input url + * @returns {Promise} - resolves when the information is retrieved + */ +const getUrlInformation = async (url: string): Promise => { + try { + const parsedPage = await parser(url, { + timeout: TIMEOUT, + maxContentLength: MAX_SIZE, + headers: { + "User-Agent": ua.getRandom(), + }, + }); + const title = parsedPage.og?.title || parsedPage.meta?.title || null; + const description = parsedPage.og?.description || parsedPage.meta?.description || null; + let img = parsedPage.og?.image || parsedPage.meta?.image || parsedPage.images?.[0] || null; + + if (!title && !description && !img) { + throw new Error("not enough information to generate link preview"); + } + + const favicon = (await getUrlFavicon(url)) || null; + const domain = getDomain(url); + let img_height: number | null = null, + img_width: number | null = null; + + if (img) { + if (typeof img === "object") { + img = (img as HtmlImage).src; + } + + const dimensions = await imageProbe(img); + img_height = dimensions.height; + img_width = dimensions.width; + } + + return { + title, + domain, + description, + favicon, + img, + img_height, + img_width, + url, + }; + } catch (error) { + throw Error(`failed to get url information: ${error}`); + } +}; diff --git a/twake/backend/node/src/services/previews/services/links/processing/service.ts b/twake/backend/node/src/services/previews/services/links/processing/service.ts new file mode 100644 index 00000000..7a38236d --- /dev/null +++ b/twake/backend/node/src/services/previews/services/links/processing/service.ts @@ -0,0 +1,52 @@ +import { LinkPreview, LinkPreviewMessageQueueRequest } from "../../../types"; +import { generateLinkPreview } from "./link"; +import { checkUrlContents } from "../../../utils"; +import { generateImageUrlPreview } from "./image"; +import { + Initializable, + logger, + TwakeServiceProvider, +} from "../../../../../core/platform/framework"; + +export class LinkPreviewProcessService implements TwakeServiceProvider, Initializable { + name: "LinkPreviewProcessService"; + version: "1"; + + async init(): Promise { + return this; + } + + /** + * Generate previews for links + * + * @param {LinkPreviewMessageQueueRequest["links"]} links - input urls + * @returns {Promise} - The generated url previews + */ + async generatePreviews(links: LinkPreviewMessageQueueRequest["links"]): Promise { + const result: LinkPreview[] = []; + + for (const link of links) { + try { + const contentType = await checkUrlContents(link); + + if (!contentType) { + continue; + } + + if (contentType.includes("text/html")) { + result.push(await generateLinkPreview(link)); + } + + if (contentType.startsWith("image")) { + result.push(await generateImageUrlPreview(link)); + } + } catch (error) { + logger.error(`failed to generate link preview: ${error}`); + } + } + + return result.filter( + preview => preview && (preview.title || preview.description || preview.img), + ); + } +} diff --git a/twake/backend/node/src/services/previews/types.ts b/twake/backend/node/src/services/previews/types.ts new file mode 100644 index 00000000..5232ef37 --- /dev/null +++ b/twake/backend/node/src/services/previews/types.ts @@ -0,0 +1,84 @@ +import { MessageLocalEvent } from "../messages/types"; + +export type PreviewMessageQueueRequest = { + document: { + id: string; + provider: string; + path: string; + encryption_algo?: string; + encryption_key?: string; + chunks?: number; + mime?: string; + filename?: string; + }; + output: { + provider: string; + path: string; + encryption_algo?: string; + encryption_key?: string; + pages?: number; //Max number of pages for the document + width?: number; //Max width for the thumbnails + height?: number; //Max height for the thumbnails + }; +}; + +export type PreviewClearMessageQueueRequest = { + document: { + id: string; + provider: string; + path: string; + thumbnails_number: number; + }; +}; + +export type PreviewMessageQueueCallback = { + document: { + id: string; + path: string; + provider: string; + }; + thumbnails: { + path: string; + size: number; + type: string; + width: number; + height: number; + provider?: string; + index?: number; + }[]; +}; + +export type ThumbnailResult = { + path: string; + width: number; + height: number; + size: number; + type: string; +}; + +export type temporaryThumbnailFile = { + filePath: string; + fileName: string; + folder: string; +}; + +export type LinkPreview = { + title: string; + description: string | null; + domain: string; + favicon: string | null; + img: string | null; + img_height: number | null; + img_width: number | null; + url: string; +}; + +export type LinkPreviewMessageQueueRequest = { + links: string[]; + message: MessageLocalEvent; +}; + +export type LinkPreviewMessageQueueCallback = { + message: MessageLocalEvent; + previews: LinkPreview[]; +}; diff --git a/twake/backend/node/src/services/previews/utils.ts b/twake/backend/node/src/services/previews/utils.ts new file mode 100644 index 00000000..5d829358 --- /dev/null +++ b/twake/backend/node/src/services/previews/utils.ts @@ -0,0 +1,67 @@ +import mimes from "../../utils/mime"; +import getFavicons from "get-website-favicon"; +import { logger } from "../../core/platform/framework"; +import axios from "axios"; + +export const TIMEOUT = 5 * 1000; +export const MAX_SIZE = 5 * 1024 * 1024; + +export function isFileType(fileMime: string, fileName: string, requiredExtensions: string[]): any { + const extension = fileName.split(".").pop(); + const secondaryExtensions = Object.keys(mimes).filter(k => mimes[k] === fileMime); + const fileExtensions = [extension, ...secondaryExtensions]; + return fileExtensions.some(e => requiredExtensions.includes(e)); +} + +/** + * get url favicon + * + * @param {String} url - the input url + * @returns {Promise} - resolves when the favicon is retrieved + */ +export const getUrlFavicon = async (url: string): Promise => { + try { + const result = await getFavicons(url); + if (!result.icons || !result.icons.length) { + return; + } + + return result.icons[0].src; + } catch (error) { + logger.error(`failed to get url favicon: ${error}`); + } +}; + +/** + * Get domain from a given url. + * + * @param {String} url - the input url + * @returns {String} - resolves when the domain is retrieved + */ +export const getDomain = (url: string): string => { + try { + const domain = new URL(url).hostname; + return domain.replace(/^www\./, ""); + } catch (error) { + throw Error(`failed to get domain: ${error}`); + } +}; + +/** + * Get url content type headers + * + * @param {string} url - the input url + * @returns {Promise} - the request headers + */ +export const checkUrlContents = async (url: string): Promise => { + try { + const response = await axios(url, { + maxContentLength: MAX_SIZE, + timeout: TIMEOUT, + }); + + return response.headers["content-type"]; + } catch (error) { + throw Error(`failed to check url contents: ${error}`); + } +}; diff --git a/twake/backend/node/src/services/previews/web/controllers/index.ts b/twake/backend/node/src/services/previews/web/controllers/index.ts new file mode 100644 index 00000000..8581813f --- /dev/null +++ b/twake/backend/node/src/services/previews/web/controllers/index.ts @@ -0,0 +1 @@ +export * from "./previews"; diff --git a/twake/backend/node/src/services/previews/web/controllers/previews.ts b/twake/backend/node/src/services/previews/web/controllers/previews.ts new file mode 100644 index 00000000..21fa83a0 --- /dev/null +++ b/twake/backend/node/src/services/previews/web/controllers/previews.ts @@ -0,0 +1 @@ +export class PreviewController {} diff --git a/twake/backend/node/src/services/previews/web/index.ts b/twake/backend/node/src/services/previews/web/index.ts new file mode 100644 index 00000000..e5dd872c --- /dev/null +++ b/twake/backend/node/src/services/previews/web/index.ts @@ -0,0 +1,12 @@ +import { FastifyInstance, FastifyRegisterOptions } from "fastify"; +import routes from "./routes"; + +export default ( + fastify: FastifyInstance, + options: FastifyRegisterOptions<{ + prefix: string; + }>, +): void => { + fastify.log.debug("Configuring /internal/services/previews/v1 routes"); + fastify.register(routes, options); +}; diff --git a/twake/backend/node/src/services/previews/web/routes.ts b/twake/backend/node/src/services/previews/web/routes.ts new file mode 100644 index 00000000..f10656d3 --- /dev/null +++ b/twake/backend/node/src/services/previews/web/routes.ts @@ -0,0 +1,7 @@ +import { FastifyInstance, FastifyPluginCallback } from "fastify"; + +const routes: FastifyPluginCallback = (fastify: FastifyInstance, options, next) => { + next(); +}; + +export default routes; diff --git a/twake/backend/node/src/services/statistics/entities/statistics.ts b/twake/backend/node/src/services/statistics/entities/statistics.ts new file mode 100644 index 00000000..a5fbfbf4 --- /dev/null +++ b/twake/backend/node/src/services/statistics/entities/statistics.ts @@ -0,0 +1,30 @@ +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "statistics"; + +@Entity(TYPE, { + primaryKey: [["company_id", "event_name"], "month_id"], + type: TYPE, +}) +export default class StatisticsEntity { + @Column("company_id", "string") + company_id: string; + + @Column("event_name", "string") + event_name: string; + + @Column("month_id", "number") + month_id: number; + + @Column("value", "counter") + value: number; +} + +export type StatisticsPrimaryKey = Pick; + +export function getInstance( + statisticsEntity: Partial & StatisticsPrimaryKey, +): StatisticsEntity { + return merge(new StatisticsEntity(), statisticsEntity); +} diff --git a/twake/backend/node/src/services/statistics/index.ts b/twake/backend/node/src/services/statistics/index.ts new file mode 100644 index 00000000..78479bdd --- /dev/null +++ b/twake/backend/node/src/services/statistics/index.ts @@ -0,0 +1,15 @@ +import { TwakeService } from "../../core/platform/framework"; + +export default class StatisticService extends TwakeService { + version = "1"; + name = "statistics"; + + public async doInit(): Promise { + return this; + } + + // TODO: remove + api(): undefined { + return undefined; + } +} diff --git a/twake/backend/node/src/services/statistics/pubsub/messages.ts b/twake/backend/node/src/services/statistics/pubsub/messages.ts new file mode 100644 index 00000000..1a489e5f --- /dev/null +++ b/twake/backend/node/src/services/statistics/pubsub/messages.ts @@ -0,0 +1,36 @@ +import { MessageQueueHandler } from "../../../core/platform/services/message-queue/api"; +import { getLogger } from "../../../core/platform/framework"; +import { MessageNotification } from "../../messages/types"; +import gr from "../../global-resolver"; + +const logger = getLogger("statistics.messages"); + +export class StatisticsMessageProcessor implements MessageQueueHandler { + readonly topics = { + in: "message:created", + }; + + readonly options = { + unique: true, + ack: true, + queue: "message:created:statistics-consumer", + }; + + readonly name = "Channel::StatisticsMessageProcessor"; + + validate(message: MessageNotification): boolean { + return !!(message && message.channel_id && message.company_id && message.workspace_id); + } + + async process(message: MessageNotification): Promise { + logger.info(`${this.name} - Processing increasing messages counter for ${message.company_id}`); + try { + await gr.services.statistics.increase(message.company_id, "messages"); + } catch (err) { + logger.error( + { err }, + `${this.name} - Error while processing direct channel members for message ${message.thread_id}/${message.id} in channel ${message.channel_id}`, + ); + } + } +} diff --git a/twake/backend/node/src/services/statistics/service/index.ts b/twake/backend/node/src/services/statistics/service/index.ts new file mode 100644 index 00000000..f1048c6e --- /dev/null +++ b/twake/backend/node/src/services/statistics/service/index.ts @@ -0,0 +1,69 @@ +import { STATISTICS_GLOBAL_KEY } from "../types"; +import StatisticsEntity, { + getInstance as getStatisticsEntityInstance, + TYPE as StatisticsEntityType, +} from "../entities/statistics"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import gr from "../../global-resolver"; +import { Initializable, TwakeServiceProvider } from "../../../core/platform/framework"; +import { ExecutionContext } from "../../../core/platform/framework/api/crud-service"; + +export class StatisticsServiceImpl implements TwakeServiceProvider, Initializable { + version: "1"; + private repository: Repository; + + async init(): Promise { + this.repository = await gr.database.getRepository( + StatisticsEntityType, + StatisticsEntity, + ); + return this; + } + + async increase(companyId: string, eventName: string, value: number = 1): Promise { + const now = new Date(); + const monthId = +(now.getFullYear() + now.getMonth().toString().padStart(2, "0")); // format 202108 + + //return Promise.all([ + await this.dbIncrement(STATISTICS_GLOBAL_KEY, eventName, monthId, value); + await this.dbIncrement(STATISTICS_GLOBAL_KEY, eventName, 0, value); + await this.dbIncrement(companyId, eventName, monthId, value); + await this.dbIncrement(companyId, eventName, 0, value); + //]).then(() => null); + } + + async get( + companyId: string = STATISTICS_GLOBAL_KEY, + eventName: string, + context?: ExecutionContext, + ): Promise { + const res = await this.repository.findOne( + { + company_id: companyId, + event_name: eventName, + month_id: 0, + }, + {}, + context, + ); + + return res?.value || 0; + } + + private dbIncrement( + companyId: string, + eventName: string, + monthId: number, + value: number = 1, + context?: ExecutionContext, + ): Promise { + const entity = getStatisticsEntityInstance({ + company_id: companyId, + event_name: eventName, + month_id: monthId, + }); + + entity.value = value; + return this.repository.save(entity, context); + } +} diff --git a/twake/backend/node/src/services/statistics/types.ts b/twake/backend/node/src/services/statistics/types.ts new file mode 100644 index 00000000..493236eb --- /dev/null +++ b/twake/backend/node/src/services/statistics/types.ts @@ -0,0 +1,8 @@ +import { Initializable, TwakeServiceProvider } from "../../core/platform/framework"; + +export interface StatisticsAPI extends TwakeServiceProvider, Initializable { + increase(companyId: string, eventName: string, value?: number): Promise; + get(companyId: string | null, eventName: string): Promise; +} + +export const STATISTICS_GLOBAL_KEY = "global"; diff --git a/twake/backend/node/src/services/tags/entities/index.ts b/twake/backend/node/src/services/tags/entities/index.ts new file mode 100644 index 00000000..46e89d34 --- /dev/null +++ b/twake/backend/node/src/services/tags/entities/index.ts @@ -0,0 +1 @@ +export { Tag, TYPE as TagsType, TagsPrimaryKey } from "./tags"; diff --git a/twake/backend/node/src/services/tags/entities/tags.ts b/twake/backend/node/src/services/tags/entities/tags.ts new file mode 100644 index 00000000..ac98f384 --- /dev/null +++ b/twake/backend/node/src/services/tags/entities/tags.ts @@ -0,0 +1,52 @@ +import { Type } from "class-transformer"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "tags"; +/** + * Table tags + */ +@Entity(TYPE, { + primaryKey: [["company_id"], "tag_id"], + type: TYPE, +}) +export class Tag { + /** + * UUIDv4 + * Primary key / partition key + * Company ID + */ + @Type(() => String) + @Column("company_id", "uuid") + company_id: string; + + /** + * UUIDv4 + * Primary key / sort key + * Tag id + */ + @Type(() => String) + @Column("tag_id", "string") + tag_id: string; + + /** + * name + */ + @Type(() => String) + @Column("name", "string") + name: string; + + /** + * colour + */ + @Type(() => String) + @Column("colour", "string") + colour: string; +} + +export type TagsPrimaryKey = Pick; + +export const createTagEntity = (tag?: Partial): Tag => { + return Object.assign(new Tag(), { + ...tag, + }); +}; diff --git a/twake/backend/node/src/services/tags/index.ts b/twake/backend/node/src/services/tags/index.ts new file mode 100644 index 00000000..0993400c --- /dev/null +++ b/twake/backend/node/src/services/tags/index.ts @@ -0,0 +1,23 @@ +import WebServerAPI from "../../core/platform/services/webserver/provider"; +import { Prefix, TwakeService } from "../../core/platform/framework"; +import web from "./web"; + +@Prefix("/internal/services/tags/v1") +export default class TagsService extends TwakeService { + version = "1"; + name = "tags"; + + public doInit: () => Promise = async () => { + const fastify = this.context.getProvider("webserver").getServer(); + fastify.register((instance, _opts, next) => { + web(instance, { prefix: this.prefix }); + next(); + }); + return this; + }; + + // TODO: remove + api(): undefined { + return undefined; + } +} diff --git a/twake/backend/node/src/services/tags/services/tags.ts b/twake/backend/node/src/services/tags/services/tags.ts new file mode 100644 index 00000000..f5a2baf9 --- /dev/null +++ b/twake/backend/node/src/services/tags/services/tags.ts @@ -0,0 +1,59 @@ +import { TwakeServiceProvider, Initializable } from "src/core/platform/framework/api"; +import Repository from "src/core/platform/services/database/services/orm/repository/repository"; +import { Tag, TagsType, TagsPrimaryKey } from "../entities"; +import gr from "../../global-resolver"; +import { + DeleteResult, + ExecutionContext, + ListResult, + OperationType, + SaveResult, +} from "../../../core/platform/framework/api/crud-service"; +import { plainToClass } from "class-transformer"; +import { createTagEntity, TYPE } from "../entities/tags"; +import { logger } from "../../../core/platform/framework"; + +export class TagsService implements TwakeServiceProvider, Initializable { + version: "1"; + repository: Repository; + + async init(): Promise { + try { + this.repository = await gr.database.getRepository(TYPE, Tag); + } catch (err) { + console.log(err); + logger.error("Error while initializing tags service"); + } + return this; + } + + async get(pk: TagsPrimaryKey): Promise { + return await this.repository.findOne({ company_id: pk.company_id, tag_id: pk.tag_id }); + } + + async save(tag: Tag, context: ExecutionContext): Promise> { + const tagToSave = createTagEntity(tag); + tagToSave.tag_id = tag.name.toLocaleLowerCase().replace(/[^a-z0-9]/gm, "_"); + await this.repository.save(tagToSave, context); + return new SaveResult(TagsType, tagToSave, OperationType.CREATE); + } + + async delete(pk: TagsPrimaryKey, context: ExecutionContext): Promise> { + const tag = await this.get(pk); + const entity = createTagEntity(tag); + await this.repository.remove(entity, context); + return new DeleteResult(TagsType, entity, true); + } + + async list(pk: { company_id: string }): Promise> { + const result = await this.repository.find({ + company_id: pk.company_id, + }); + + return new ListResult( + "tags", + result.getEntities().map(tag => plainToClass(Tag, { tag_id: tag.tag_id, ...tag })), + result.nextPage, + ); + } +} diff --git a/twake/backend/node/src/services/tags/types.ts b/twake/backend/node/src/services/tags/types.ts new file mode 100644 index 00000000..a709ac74 --- /dev/null +++ b/twake/backend/node/src/services/tags/types.ts @@ -0,0 +1,6 @@ +export type Tag = { + company_id: string; + name: string; + id: number; + colour: number; +}; diff --git a/twake/backend/node/src/services/tags/web/controllers/index.ts b/twake/backend/node/src/services/tags/web/controllers/index.ts new file mode 100644 index 00000000..006f4bf5 --- /dev/null +++ b/twake/backend/node/src/services/tags/web/controllers/index.ts @@ -0,0 +1 @@ +export * from "./tags"; diff --git a/twake/backend/node/src/services/tags/web/controllers/tags.ts b/twake/backend/node/src/services/tags/web/controllers/tags.ts new file mode 100644 index 00000000..7fba2fb6 --- /dev/null +++ b/twake/backend/node/src/services/tags/web/controllers/tags.ts @@ -0,0 +1,126 @@ +import { FastifyReply, FastifyRequest } from "fastify"; +import { CrudController } from "../../../../core/platform/services/webserver/types"; +import { + ResourceCreateResponse, + ResourceDeleteResponse, + ResourceGetResponse, + ResourceListResponse, +} from "../../../../utils/types"; +import { Tag } from "../../entities"; +import gr from "../../../global-resolver"; +import { ExecutionContext } from "src/core/platform/framework/api/crud-service"; +import { handleError } from "../../../../utils/handleError"; + +export class TagsController + implements + CrudController< + ResourceGetResponse, + ResourceCreateResponse, + ResourceListResponse, + ResourceDeleteResponse + > +{ + async get( + request: FastifyRequest<{ Params: { company_id: string; tag_id: string } }>, + reply: FastifyReply, + ): Promise> { + try { + const tag = await gr.services.tags.get({ + company_id: request.params.company_id, + tag_id: request.params.tag_id, + }); + if (tag) { + reply.code(200); + } + return { resource: tag }; + } catch (err) { + reply.code(404); + handleError(reply, err); + } + } + + async list( + request: FastifyRequest<{ Params: { company_id: string } }>, + reply: FastifyReply, + ): Promise> { + const list = await gr.services.tags.list({ + company_id: request.params.company_id, + }); + try { + const resources = list.getEntities(); + if (resources) { + reply.code(200); + } + return { resources }; + } catch (err) { + handleError(reply, err); + } + } + + async save( + request: FastifyRequest<{ + Params: { company_id: string; tag_id?: string }; + Body: { name: string; colour: string }; + }>, + reply: FastifyReply, + ): Promise> { + const context = getExecutionContext(request); + const tag_id = request.params.tag_id ? request.params.tag_id : ""; + + const entity = { + company_id: request.params.company_id, + tag_id: tag_id, + name: request.body.name, + colour: request.body.colour, + }; + + try { + const save_result = await gr.services.tags.save(entity, context); + + if (save_result) { + reply.code(201); + } + + return { + resource: save_result.entity, + }; + } catch (err) { + handleError(reply, err); + } + } + + async delete( + request: FastifyRequest<{ Params: { company_id: string; tag_id: string } }>, + reply: FastifyReply, + ): Promise { + const context = getExecutionContext(request); + + try { + const deleteResult = await gr.services.tags.delete( + { + company_id: request.params.company_id, + tag_id: request.params.tag_id, + }, + context, + ); + + if (deleteResult) { + reply.code(200); + return { + status: "success", + }; + } + } catch (err) { + handleError(reply, err); + } + } +} + +function getExecutionContext(request: FastifyRequest): ExecutionContext { + return { + user: request.currentUser, + url: request.url, + method: request.routerMethod, + transport: "http", + }; +} diff --git a/twake/backend/node/src/services/tags/web/index.ts b/twake/backend/node/src/services/tags/web/index.ts new file mode 100644 index 00000000..36567d65 --- /dev/null +++ b/twake/backend/node/src/services/tags/web/index.ts @@ -0,0 +1,12 @@ +import { FastifyInstance, FastifyRegisterOptions } from "fastify"; +import routes from "./routes"; + +export default ( + fastify: FastifyInstance, + options: FastifyRegisterOptions<{ + prefix: string; + }>, +): void => { + fastify.log.debug("Configuring /internal/services/tags/v1 routes"); + fastify.register(routes, options); +}; diff --git a/twake/backend/node/src/services/tags/web/routes.ts b/twake/backend/node/src/services/tags/web/routes.ts new file mode 100644 index 00000000..35ab58f4 --- /dev/null +++ b/twake/backend/node/src/services/tags/web/routes.ts @@ -0,0 +1,73 @@ +import { FastifyInstance, FastifyPluginCallback, FastifyRequest } from "fastify"; +import { checkUserBelongsToCompany } from "../../../utils/company"; +import { Tag } from "../types"; +import { TagsController } from "./controllers"; +import gr from "../../global-resolver"; +import CompanyUser from "src/services/user/entities/company_user"; + +const tagsUrl = "/companies/:company_id/tags"; + +const routes: FastifyPluginCallback = (fastify: FastifyInstance, options, next) => { + const tagsController = new TagsController(); + + const accessControlCompanyOnly = async (request: FastifyRequest<{ Params: Tag }>) => { + await checkUserBelongsToCompany(request.currentUser.id, request.params.company_id); + }; + + const accessControlOwnerOrAdmin = async (request: FastifyRequest<{ Params: Tag }>) => { + const user: CompanyUser = await gr.services.companies.getCompanyUser( + { id: request.params.company_id }, + { id: request.currentUser.id }, + ); + + const authorization = user.role === "owner" || user.role === "admin" ? true : false; + + if (!authorization) { + throw fastify.httpErrors.unauthorized("Only owner and Company Administrator have permission"); + } + }; + + fastify.route({ + method: "GET", + url: `${tagsUrl}/:tag_id`, + preHandler: accessControlCompanyOnly, + preValidation: [fastify.authenticate], + handler: tagsController.get.bind(tagsController), + }); + + fastify.route({ + method: "GET", + url: tagsUrl, + preHandler: accessControlCompanyOnly, + preValidation: [fastify.authenticate], + handler: tagsController.list.bind(tagsController), + }); + + fastify.route({ + method: "POST", + url: tagsUrl, + preHandler: accessControlOwnerOrAdmin, + preValidation: [fastify.authenticate], + handler: tagsController.save.bind(tagsController), + }); + + fastify.route({ + method: "POST", + url: `${tagsUrl}/:tag_id`, + preHandler: accessControlOwnerOrAdmin, + preValidation: [fastify.authenticate], + handler: tagsController.save.bind(tagsController), + }); + + fastify.route({ + method: "DELETE", + url: `${tagsUrl}/:tag_id`, + preHandler: accessControlOwnerOrAdmin, + preValidation: [fastify.authenticate], + handler: tagsController.delete.bind(tagsController), + }); + + next(); +}; + +export default routes; diff --git a/twake/backend/node/src/services/user/entities/company.ts b/twake/backend/node/src/services/user/entities/company.ts new file mode 100644 index 00000000..8473a55b --- /dev/null +++ b/twake/backend/node/src/services/user/entities/company.ts @@ -0,0 +1,62 @@ +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import { CompanyFeaturesObject, CompanyLimitsObject } from "../web/types"; + +// backward compatibility with PHP where companies used to be `group_entity` +export const TYPE = "group_entity"; + +@Entity(TYPE, { + primaryKey: [["id"]], + type: TYPE, +}) +export default class Company { + @Column("id", "timeuuid") + id: string; + + @Column("name", "encoded_string") + name: string; + + @Column("display_name", "encoded_string") + displayName: string; + + @Column("plan", "encoded_json") + plan?: { + name: string; + limits: CompanyLimitsObject; + features: CompanyFeaturesObject; + }; + + @Column("stats", "encoded_json") + stats: any; + + @Column("logo_id", "timeuuid") + logofile: string; + + @Column("logo", "encoded_string") + logo: string; + + @Column("date_added", "number") + dateAdded: number; + + @Column("on_creation_data", "encoded_json") + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onCreationData: any; + + @Column("member_count", "number") + memberCount: number; + + @Column("identity_provider", "encoded_string") + identity_provider: string; + + @Column("identity_provider_id", "encoded_string") + identity_provider_id: string; +} + +export type CompanyPrimaryKey = Pick; +export type CompanySearchKey = Partial< + Pick +>; + +export function getInstance(company: Partial): Company { + return merge(new Company(), company); +} diff --git a/twake/backend/node/src/services/user/entities/company_user.ts b/twake/backend/node/src/services/user/entities/company_user.ts new file mode 100644 index 00000000..3d9c1a52 --- /dev/null +++ b/twake/backend/node/src/services/user/entities/company_user.ts @@ -0,0 +1,63 @@ +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import { CompanyUserRole } from "../web/types"; + +// backward compatibility with PHP where companies used to be `group` +export const TYPE = "group_user"; + +/** + * Link between a company and a user + */ +@Entity(TYPE, { + primaryKey: [["user_id"], "group_id", "id"], + type: TYPE, +}) +export default class CompanyUser { + @Column("group_id", "timeuuid") + group_id: string; + + @Column("user_id", "timeuuid") + user_id: string; + + @Column("id", "timeuuid") + id: string; + + @Column("role", "string") + role: CompanyUserRole = "member"; + + @Column("applications", "json") + applications: string[] = []; + + @Column("nb_workspace", "number") + nbWorkspaces: number; + + @Column("date_added", "number") + dateAdded: number; + + @Column("last_update_day", "number") + lastUpdateDay: number; + + /** + * 0: member, + * 1, 2, 3: admin, + */ + @Column("level", "number") + level: number; //Depreciated + + @Column("is_externe", "twake_boolean") + isExterne: boolean; //Depreciated + + @Column("did_connect_today", "twake_boolean") + didConnectToday: boolean; //Depreciated + + @Column("app_used_today", "json") + appUsedToday: Array; //Depreciated +} + +export type CompanyUserPrimaryKey = Partial>; + +export function getInstance( + companyUser: Partial & CompanyUserPrimaryKey, +): CompanyUser { + return merge(new CompanyUser(), companyUser); +} diff --git a/twake/backend/node/src/services/user/entities/device.ts b/twake/backend/node/src/services/user/entities/device.ts new file mode 100644 index 00000000..dfb5943d --- /dev/null +++ b/twake/backend/node/src/services/user/entities/device.ts @@ -0,0 +1,32 @@ +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import { uuid } from "../../../utils/types"; + +export const TYPE = "devices"; + +@Entity(TYPE, { + primaryKey: [["id"]], + type: TYPE, +}) +export default class Device { + @Column("id", "string") + id: string; + + @Column("user_id", "uuid") + user_id: uuid; + + @Column("type", "string") + type: string; + + @Column("version", "string") + version: string; + + @Column("push_notifications", "boolean") + push_notifications: boolean; +} + +export type UserDevicePrimaryKey = Pick; + +export function getInstance(userDevice: Partial & UserDevicePrimaryKey): Device { + return merge(new Device(), userDevice); +} diff --git a/twake/backend/node/src/services/user/entities/external_company.ts b/twake/backend/node/src/services/user/entities/external_company.ts new file mode 100644 index 00000000..7ef69114 --- /dev/null +++ b/twake/backend/node/src/services/user/entities/external_company.ts @@ -0,0 +1,27 @@ +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "external_group_repository"; + +@Entity(TYPE, { + primaryKey: [["service_id"], "external_id", "company_id"], + type: TYPE, +}) +export default class ExternalGroup { + @Column("service_id", "string") + service_id: string; + + @Column("external_id", "string") + external_id: string; + + @Column("company_id", "string") + company_id: string; +} + +export type ExternalGroupPrimaryKey = Pick; + +export function getInstance( + group: Partial & ExternalGroupPrimaryKey, +): ExternalGroup { + return merge(new ExternalGroup(), group); +} diff --git a/twake/backend/node/src/services/user/entities/external_user.ts b/twake/backend/node/src/services/user/entities/external_user.ts new file mode 100644 index 00000000..6fd80ebb --- /dev/null +++ b/twake/backend/node/src/services/user/entities/external_user.ts @@ -0,0 +1,25 @@ +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "external_user_repository"; + +@Entity(TYPE, { + primaryKey: [["service_id"], "external_id", "user_id"], + type: TYPE, +}) +export default class ExternalUser { + @Column("service_id", "string") + service_id: string; + + @Column("external_id", "string") + external_id: string; + + @Column("user_id", "timeuuid") + user_id: string; +} + +export type ExternalUserPrimaryKey = Pick; + +export function getInstance(user: Partial & ExternalUserPrimaryKey): ExternalUser { + return merge(new ExternalUser(), user); +} diff --git a/twake/backend/node/src/services/user/entities/user.search.ts b/twake/backend/node/src/services/user/entities/user.search.ts new file mode 100644 index 00000000..b7729fe1 --- /dev/null +++ b/twake/backend/node/src/services/user/entities/user.search.ts @@ -0,0 +1,43 @@ +import User from "./user"; + +export default { + index: "user", + source: (entity: User) => { + const source: any = { + first_name: entity.first_name, + last_name: entity.last_name, + email: entity.email_canonical, + username: entity.username_canonical, + }; + if (entity.cache?.companies) { + return { + companies: entity.cache?.companies, + ...source, + }; + } + return source; + }, + mongoMapping: { + text: { + first_name: "text", + last_name: "text", + email: "text", + username: "text", + }, + prefix: { + first_name: "prefix", + last_name: "prefix", + email: "prefix", + username: "prefix", + }, + }, + esMapping: { + properties: { + first_name: { type: "text", index_prefixes: { min_chars: 1 } }, + last_name: { type: "text", index_prefixes: { min_chars: 1 } }, + email: { type: "text", index_prefixes: { min_chars: 1 } }, + username: { type: "text", index_prefixes: { min_chars: 1 } }, + companies: { type: "keyword" }, + }, + }, +}; diff --git a/twake/backend/node/src/services/user/entities/user.ts b/twake/backend/node/src/services/user/entities/user.ts new file mode 100644 index 00000000..aa7987bf --- /dev/null +++ b/twake/backend/node/src/services/user/entities/user.ts @@ -0,0 +1,147 @@ +import { isNumber, merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import search from "./user.search"; +import { uuid } from "../../../utils/types"; + +export const TYPE = "user"; + +@Entity(TYPE, { + primaryKey: [["id"]], + globalIndexes: [["email_canonical"], ["username_canonical"]], + type: TYPE, + search, +}) +export default class User { + @Column("id", "timeuuid") + id: uuid; + + @Column("first_name", "encoded_string") + first_name: string; + + @Column("last_name", "encoded_string") + last_name: string; + + @Column("picture", "encoded_string") + picture: string; + + @Column("status_icon", "string") + private _status_icon: string; // = '["", ""]'; + + public get status_icon(): string { + if (this._status_icon && this._status_icon.startsWith("[\\")) { + try { + // eslint-disable-next-line quotes + const parsed = JSON.parse(this._status_icon.replace(/\\"/g, '"').replace(/\\\\/g, "\\")); + return `${parsed[0]} ${parsed[1]}`; + } catch (e) { + return ""; + } + } + return this._status_icon; + } + + public set status_icon(status: string) { + this._status_icon = status; + } + + @Column("last_activity", "number") + last_activity: number; + + @Column("creation_date", "twake_datetime") + creation_date: number; + + @Column("notification_preference", "encoded_json") + // FIXME= Which type to use with encoded json? This is an object at the end + notification_preference: any; + + @Column("identity_provider", "encoded_string") + identity_provider: string; + + @Column("identity_provider_id", "encoded_string") + identity_provider_id: string; + + @Column("token_login", "encoded_string") + token_login: string; + + // TODO: Index + @Column("username_canonical", "string") + username_canonical: string; + + // TODO: Index + @Column("email_canonical", "string") + email_canonical: string; + + @Column("password", "string") + password: string; + + @Column("deleted", "twake_boolean") + deleted: boolean; + + @Column("mail_verified", "twake_boolean") + mail_verified: boolean; + + @Column("phone", "string") + phone: string; + + @Column("thumbnail_id", "timeuuid") + thumbnail_id: string; + + @Column("language", "string") + language: string; //Depreciated (php legacy) + + @Column("timezone", "string") + timezone: string; //Depreciated (php legacy) + + @Column("preferences", "encoded_json") + preferences: null | { + locale?: string; + timezone?: number; + language?: string; + allow_tracking?: boolean; + tutorial_done?: boolean; + channel_ordering?: "chronological" | "alphabetical"; + recent_workspaces?: { company_id: string; workspace_id: string }[]; + knowledge_graph?: "all" | "nothing" | "metadata"; + notifications?: UserNotificationPreferences[]; + }; + + @Column("cache", "encoded_json") + cache: null | { + companies: string[]; + }; + + @Column("devices", "encoded_json") + devices: Array; + + @Column("salt", "string") + salt: string; + + constructor(id?: string) { + this.id = id; + } +} + +export type UserNotificationPreferences = { + company_id: string | "all"; + workspace_id: string | "all"; + preferences: { + highlight_words?: string[]; + night_break?: { + enable: boolean; + from: number; + to: number; + }; + private_message_content?: boolean; + mobile_notifications?: "never" | "when_inactive" | "always"; + email_notifications_delay?: number; //0: never send email, 1 and more in minutes from first unread notification + deactivate_notifications_until?: number; + notification_sound?: "default" | "none" | string; + }; +}; + +export type UserPrimaryKey = Pick; + +export function getInstance(user: Partial): User { + user.creation_date = !isNumber(user.creation_date) ? Date.now() : user.creation_date; + return merge(new User(), user); +} diff --git a/twake/backend/node/src/services/user/index.ts b/twake/backend/node/src/services/user/index.ts new file mode 100644 index 00000000..90bbd4d9 --- /dev/null +++ b/twake/backend/node/src/services/user/index.ts @@ -0,0 +1,23 @@ +import { Prefix, TwakeService } from "../../core/platform/framework"; +import WebServerAPI from "../../core/platform/services/webserver/provider"; +import web from "./web"; + +@Prefix("/internal/services/users/v1") +export default class UserService extends TwakeService { + version = "1"; + name = "user"; + + public async doInit(): Promise { + const fastify = this.context.getProvider("webserver").getServer(); + fastify.register((instance, _opts, next) => { + web(instance, { prefix: this.prefix }); + next(); + }); + return this; + } + + // TODO: remove + api(): undefined { + return undefined; + } +} diff --git a/twake/backend/node/src/services/user/realtime.ts b/twake/backend/node/src/services/user/realtime.ts new file mode 100644 index 00000000..f7f131a3 --- /dev/null +++ b/twake/backend/node/src/services/user/realtime.ts @@ -0,0 +1,45 @@ +import { WebsocketMetadata } from "../../utils/types"; +import CompanyEntity from "./entities/company"; +import UserEntity from "./entities/user"; + +/** + * User Rooms + */ +export function getUserRooms(user: UserEntity): WebsocketMetadata[] { + return [ + { + room: getUserRoom(user.id), + }, + ]; +} + +export function getUserRoom(userId: string): string { + return `/me/${userId}`; +} + +export function getPublicUserRoom(userId: string): string { + return `/users/${userId}`; +} + +export function getUserName(userId: string): string { + return `user-room-${userId}`; +} + +/** + * Company Rooms + */ +export function getCompanyRooms(company: CompanyEntity): WebsocketMetadata[] { + return [ + { + room: getCompanyRoom(company.id), + }, + ]; +} + +export function getCompanyRoom(companyId: string): string { + return `/company/${companyId}`; +} + +export function getCompanyName(companyId: string): string { + return `company-room-${companyId}`; +} diff --git a/twake/backend/node/src/services/user/services/companies.ts b/twake/backend/node/src/services/user/services/companies.ts new file mode 100644 index 00000000..24693f8a --- /dev/null +++ b/twake/backend/node/src/services/user/services/companies.ts @@ -0,0 +1,355 @@ +import _, { merge } from "lodash"; + +import { + CrudException, + DeleteResult, + ExecutionContext, + ListResult, + OperationType, + Paginable, + Pagination, + SaveResult, +} from "../../../core/platform/framework/api/crud-service"; +import Repository, { + FindOptions, +} from "../../../core/platform/services/database/services/orm/repository/repository"; +import { UserPrimaryKey } from "../entities/user"; +import Company, { + CompanyPrimaryKey, + CompanySearchKey, + getInstance as getCompanyInstance, +} from "../entities/company"; +import CompanyUser, { + CompanyUserPrimaryKey, + getInstance as getCompanyUserInstance, +} from "../entities/company_user"; +import { ListUserOptions } from "./users/types"; +import { CompanyUserRole } from "../web/types"; +import { ResourceEventsPayload, uuid } from "../../../utils/types"; +import ExternalGroup, { + ExternalGroupPrimaryKey, + getInstance as getExternalGroupInstance, +} from "../entities/external_company"; +import { logger, RealtimeSaved } from "../../../core/platform/framework"; +import { getCompanyRoom, getUserRoom } from "../realtime"; +import gr from "../../global-resolver"; +import { localEventBus } from "../../../core/platform/framework/event-bus"; +import { + KnowledgeGraphEvents, + KnowledgeGraphGenericEventPayload, +} from "../../../core/platform/services/knowledge-graph/types"; + +export class CompanyServiceImpl { + version: "1"; + companyRepository: Repository; + externalCompanyRepository: Repository; + companyUserRepository: Repository; + + async init(): Promise { + this.companyRepository = await gr.database.getRepository("group_entity", Company); + this.companyUserRepository = await gr.database.getRepository( + "group_user", + CompanyUser, + ); + this.externalCompanyRepository = await gr.database.getRepository( + "external_group_repository", + ExternalGroup, + ); + + return this; + } + + private getExtCompany(pk: ExternalGroupPrimaryKey, context?: ExecutionContext) { + return this.externalCompanyRepository.findOne(pk, {}, context); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + @RealtimeSaved((company, _context) => { + return [ + { + room: getCompanyRoom(company.id), + resource: company, + }, + ]; + }) + async updateCompany( + company: Company, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _options?: SaveOptions, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + context?: ExecutionContext, + ): Promise> { + if (company.identity_provider_id && !company.identity_provider) { + company.identity_provider = "console"; + } + + await this.companyRepository.save(company, context); + + if (company.identity_provider_id) { + const key = { + service_id: company.identity_provider, + external_id: company.identity_provider_id, + }; + + const extCompany = (await this.getExtCompany(key, context)) || getExternalGroupInstance(key); + + extCompany.company_id = company.id; + extCompany.external_id = company.identity_provider_id; + extCompany.service_id = company.identity_provider; + + await this.externalCompanyRepository.save(extCompany, context); + } + + localEventBus.publish>( + KnowledgeGraphEvents.COMPANY_UPSERT, + { + id: company.id, + resource: company, + links: [], + }, + ); + + return new SaveResult("company", company, OperationType.UPDATE); + } + + async createCompany(company: Company): Promise { + const companyToCreate: Company = getCompanyInstance({ + ...company, + ...{ + dateAdded: Date.now(), + }, + }); + + const result = await this.updateCompany(companyToCreate); + + return result.entity; + } + + async getCompany( + companySearchKey: CompanySearchKey, + context?: ExecutionContext, + ): Promise { + if (companySearchKey.id) { + return this.companyRepository.findOne(companySearchKey, {}, context); + } else if (companySearchKey.identity_provider_id) { + const extCompany = await this.getExtCompany( + { + external_id: companySearchKey.identity_provider_id, + service_id: companySearchKey.identity_provider || "console", + }, + context, + ); + if (!extCompany) { + return null; + } + return await this.companyRepository.findOne({ id: extCompany.company_id }, {}, context); + } + } + + async getCompanyUser( + company: CompanyPrimaryKey, + user: UserPrimaryKey, + context?: ExecutionContext, + ): Promise { + const companyUser = await this.companyUserRepository.findOne( + { + group_id: company.id, + user_id: user.id, + }, + {}, + context, + ); + if (companyUser) companyUser.applications = []; + return companyUser; + } + + async getAllForUser(userId: uuid, context?: ExecutionContext): Promise { + const list = await this.companyUserRepository + .find({ user_id: userId }, {}, context) + .then(a => a.getEntities()); + + // Update user cache with companies + const user = await gr.services.users.get({ id: userId }); + if ( + user.cache?.companies.length === 0 || + _.difference( + list.map(c => c.group_id), + user.cache?.companies || [], + ).length != 0 + ) { + if (!user.cache) user.cache = { companies: [] }; + user.cache.companies = list.map(c => c.group_id); + await gr.services.users.save(user, { user: { id: user.id, server_request: true } }); + } + + return list; + } + + getCompanies(paginable?: Paginable, context?: ExecutionContext): Promise> { + return this.companyRepository.find( + {}, + { + pagination: new Pagination( + paginable?.page_token, + paginable?.limitStr || "100", + paginable?.reversed, + ), + }, + context, + ); + } + + @RealtimeSaved((companyUser, _) => { + return [ + { + room: getUserRoom(companyUser?.user_id), + resource: companyUser, + }, + ]; + }) + async removeUserFromCompany( + companyPk: CompanyPrimaryKey, + userPk: UserPrimaryKey, + context?: ExecutionContext, + ): Promise> { + const entity = await this.companyUserRepository.findOne( + { + group_id: companyPk.id, + user_id: userPk.id, + }, + {}, + context, + ); + if (entity) { + await Promise.all([this.companyUserRepository.remove(entity, context)]); + + const user = await gr.services.users.get(userPk); + if ((user.cache?.companies || []).includes(companyPk.id)) { + // Update user cache with companies + user.cache.companies = user.cache.companies.filter(id => id != companyPk.id); + await gr.services.users.save(user, { user: { id: user.id, server_request: true } }); + } + + localEventBus.publish("company:user:deleted", { + user: user, + company: companyPk, + }); + } + + return new DeleteResult("company_user", entity, true); + } + + async getUsers( + companyId: CompanyUserPrimaryKey, + pagination?: Pagination, + options?: ListUserOptions, + context?: ExecutionContext, + ): Promise> { + const findOptions: FindOptions = { + pagination, + }; + + if (options?.userIds) { + findOptions.$in = [["user_id", options.userIds]]; + } + + return this.companyUserRepository.find({ group_id: companyId.group_id }, findOptions, context); + } + + async delete(pk: CompanyPrimaryKey, context?: ExecutionContext): Promise> { + const instance = await this.companyRepository.findOne(pk, {}, context); + if (instance) await this.companyRepository.remove(instance, context); + return new DeleteResult("company", instance, !!instance); + } + + @RealtimeSaved((companyUser, _) => { + return [ + { + room: getUserRoom(companyUser?.user_id), + resource: companyUser, + }, + ]; + }) + async setUserRole( + companyId: uuid, + userId: uuid, + role: CompanyUserRole = "member", + applications: string[] = [], + context?: ExecutionContext, + ): Promise> { + const key = { + group_id: companyId, + user_id: userId, + }; + let entity = await this.companyUserRepository.findOne(key, {}, context); + + if (entity == null) { + entity = getCompanyUserInstance(merge(key, { dateAdded: Date.now() })); + } + + entity.role = role; + entity.applications = applications; + await this.companyUserRepository.save(entity, context); + + const user = await gr.services.users.get({ id: userId }); + if (!(user.cache?.companies || []).includes(companyId)) { + // Update user cache with companies + if (!user.cache) user.cache = { companies: [] }; + user.cache.companies.push(companyId); + await gr.services.users.save(user, { user: { id: user.id, server_request: true } }); + } + + return new SaveResult("company_user", entity, OperationType.UPDATE); + } + + async removeCompany(searchKey: CompanySearchKey, context?: ExecutionContext): Promise { + if (searchKey.identity_provider_id) { + const extCompany = await this.getExtCompany( + { + service_id: searchKey.identity_provider, + external_id: searchKey.identity_provider_id, + }, + context, + ); + if (!extCompany) { + throw CrudException.notFound(`Company ${searchKey.identity_provider_id} not found`); + } + await this.externalCompanyRepository.remove(extCompany, context); + searchKey.id = extCompany.company_id; + } + + const company = await this.getCompany({ id: searchKey.id }); + if (!company) { + throw CrudException.notFound(`Company ${searchKey.id} not found`); + } + + await this.companyRepository.remove(company, context); + + return Promise.resolve(null); + } + + async getUsersCount(companyId: string): Promise { + return this.getCompany({ id: companyId }).then(a => a.memberCount); + } + + async getUserRole(companyId: uuid, userId: uuid): Promise { + if (!userId) return "guest"; + const companyUser = await this.getCompanyUser({ id: companyId }, { id: userId }); + if (!companyUser) { + return "guest"; + } + return companyUser.role; + } + + async ensureDeletedUserNotInCompanies(userPk: UserPrimaryKey): Promise { + const user = await gr.services.users.get(userPk); + if (user.deleted) { + const companies = await this.getAllForUser(user.id); + for (const company of companies) { + logger.warn(`User ${userPk.id} is deleted so removed from company ${company.id}`); + await this.removeUserFromCompany(company, user); + await gr.services.workspaces.ensureUserNotInCompanyIsNotInWorkspace(userPk, company.id); + } + } + } +} diff --git a/twake/backend/node/src/services/user/services/external_links/index.ts b/twake/backend/node/src/services/user/services/external_links/index.ts new file mode 100644 index 00000000..18f60ea9 --- /dev/null +++ b/twake/backend/node/src/services/user/services/external_links/index.ts @@ -0,0 +1,66 @@ +import Repository from "../../../../core/platform/services/database/services/orm/repository/repository"; +import ExternalUser from "../../entities/external_user"; +import ExternalGroup from "../../entities/external_company"; + +import Company from "../../entities/company"; +import User from "../../entities/user"; +import gr from "../../../global-resolver"; +import { ExecutionContext } from "../../../../core/platform/framework/api/crud-service"; + +export class UserExternalLinksServiceImpl { + version: "1"; + private externalUserRepository: Repository; + private externalGroupRepository: Repository; + private companyRepository: Repository; + private userRepository: Repository; + + async init(): Promise { + this.externalUserRepository = await gr.database.getRepository( + "external_user_repository", + ExternalUser, + ); + this.externalGroupRepository = await gr.database.getRepository( + "external_group_repository", + ExternalGroup, + ); + this.companyRepository = await gr.database.getRepository("group_entity", Company); + this.userRepository = await gr.database.getRepository("user", User); + + return this; + } + + async createExternalUser(user: ExternalUser, context?: ExecutionContext): Promise { + await this.externalUserRepository.save(user, context); + + //Save user provider and provider id here + const internalUser = await this.userRepository.findOne({ id: user.user_id }, {}, context); + if (internalUser) { + internalUser.identity_provider = user.service_id; + internalUser.identity_provider_id = user.external_id; + this.userRepository.save(internalUser, context); + } + + return user; + } + + async createExternalGroup( + group: ExternalGroup, + context?: ExecutionContext, + ): Promise { + await this.externalGroupRepository.save(group, context); + + //Save company provider and provider id here + const internalCompany = await this.companyRepository.findOne( + { id: group.company_id }, + {}, + context, + ); + if (internalCompany) { + internalCompany.identity_provider = group.service_id; + internalCompany.identity_provider_id = group.external_id; + this.companyRepository.save(internalCompany, context); + } + + return group; + } +} diff --git a/twake/backend/node/src/services/user/services/users/service.ts b/twake/backend/node/src/services/user/services/users/service.ts new file mode 100644 index 00000000..cd8c6041 --- /dev/null +++ b/twake/backend/node/src/services/user/services/users/service.ts @@ -0,0 +1,394 @@ +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/ban-ts-comment */ +import { + CreateResult, + CrudException, + DeleteResult, + ExecutionContext, + ListResult, + OperationType, + Pagination, + SaveResult, + UpdateResult, +} from "../../../../core/platform/framework/api/crud-service"; +import Repository, { + FindFilter, + FindOptions, +} from "../../../../core/platform/services/database/services/orm/repository/repository"; +import User, { UserPrimaryKey } from "../../entities/user"; +import { ListUserOptions, SearchUserOptions } from "./types"; +import CompanyUser from "../../entities/company_user"; +import SearchRepository from "../../../../core/platform/services/search/repository"; +import ExternalUser, { getInstance as getExternalUserInstance } from "../../entities/external_user"; +import Device, { + getInstance as getDeviceInstance, + TYPE as DeviceType, +} from "../../entities/device"; +import PasswordEncoder from "../../../../utils/password-encoder"; +import assert from "assert"; +import { localEventBus } from "../../../../core/platform/framework/event-bus"; +import { ResourceEventsPayload } from "../../../../utils/types"; +import { isNumber, isString } from "lodash"; +import { RealtimeSaved } from "../../../../core/platform/framework"; +import { getPublicUserRoom, getUserRoom } from "../../realtime"; +import NodeCache from "node-cache"; +import gr from "../../../global-resolver"; +import { + KnowledgeGraphEvents, + KnowledgeGraphGenericEventPayload, +} from "../../../../core/platform/services/knowledge-graph/types"; +import { formatUser } from "../../../../utils/users"; + +export class UserServiceImpl { + version: "1"; + repository: Repository; + searchRepository: SearchRepository; + companyUserRepository: Repository; + extUserRepository: Repository; + private deviceRepository: Repository; + private cache: NodeCache; + + async init(): Promise { + this.searchRepository = gr.platformServices.search.getRepository("user", User); + this.repository = await gr.database.getRepository("user", User); + this.companyUserRepository = await gr.database.getRepository( + "group_user", + CompanyUser, + ); + this.extUserRepository = await gr.database.getRepository( + "external_user_repository", + ExternalUser, + ); + + this.deviceRepository = await gr.database.getRepository(DeviceType, Device); + + this.cache = new NodeCache({ stdTTL: 0.2, checkperiod: 120 }); + + //If user deleted from Twake, remove it from all companies + localEventBus.subscribe("user:deleted", async data => { + if (data?.user?.id) gr.services.companies.ensureDeletedUserNotInCompanies(data.user); + }); + + return this; + } + + private async updateExtRepository(user: User, context?: ExecutionContext) { + if (user.identity_provider_id) { + const key = { service_id: user.identity_provider, external_id: user.identity_provider_id }; + const extUser = + (await this.extUserRepository.findOne(key, {}, context)) || getExternalUserInstance(key); + extUser.user_id = user.id; + await this.extUserRepository.save(extUser, context); + } + } + + private assignDefaults(user: User) { + user.creation_date = !isNumber(user.creation_date) ? Date.now() : user.creation_date; + if (user.identity_provider_id && !user.identity_provider) user.identity_provider = "console"; + if (user.email_canonical) user.email_canonical = user.email_canonical.toLocaleLowerCase(); + if (user.username_canonical) + user.username_canonical = (user.username_canonical || "") + .toLocaleLowerCase() + .replace(/[^a-z0-9_-]/, ""); + } + + async create(user: User, context?: ExecutionContext): Promise> { + await this.save(user, context); + return new CreateResult("user", user); + } + + update(pk: Partial, item: User, context?: ExecutionContext): Promise> { + throw new Error("Method not implemented."); + } + + @RealtimeSaved((user, _context) => { + return [ + { + room: getPublicUserRoom(user.id), + resource: user, + }, + ]; + }) + async publishPublicUserRealtime(userId: string): Promise { + const user = await this.get({ id: userId }); + new SaveResult("user", formatUser(user, { includeCompanies: true }), OperationType.UPDATE); + } + + @RealtimeSaved((user, _context) => { + return [ + { + room: getUserRoom(user.id), + resource: formatUser(user), // FIX ME we should formatUser here + }, + ]; + }) + async save(user: User, context?: ExecutionContext): Promise> { + this.assignDefaults(user); + await this.repository.save(user, context); + await this.updateExtRepository(user); + + localEventBus.publish>( + KnowledgeGraphEvents.USER_UPSERT, + { + id: user.id, + resource: user, + links: [ + { + // FIXME: We should provide the company id here + id: "", + relation: "parent", + type: "company", + }, + ], + }, + ); + + await this.publishPublicUserRealtime(user.id); + + return new SaveResult("user", user, OperationType.UPDATE); + } + + async delete(pk: Partial, context?: ExecutionContext): Promise> { + const instance = await this.repository.findOne(pk, {}, context); + if (instance) await this.repository.remove(instance, context); + return new DeleteResult("user", instance, !!instance); + } + + async anonymizeAndDelete(pk: UserPrimaryKey, context?: ExecutionContext) { + const user = await this.get(pk); + + if (context.user.server_request || context.user.id === user.id) { + //We keep a part of the user id as new name + const partialId = user.id.toString().split("-")[0]; + + user.username_canonical = `deleted-user-${partialId}`; + user.email_canonical = `${partialId}@twake.removed`; + user.first_name = ""; + user.last_name = ""; + user.phone = ""; + user.picture = ""; + user.thumbnail_id = null; + user.status_icon = null; + user.deleted = true; + + await this.save(user); + + localEventBus.publish("user:deleted", { + user: user, + }); + } + } + + async search( + pagination: Pagination, + options?: SearchUserOptions, + context?: ExecutionContext, + ): Promise> { + return await this.searchRepository.search( + {}, + { + pagination, + ...(options.companyId ? { $in: [["companies", [options.companyId]]] } : {}), + ...(options.workspaceId ? { $in: [["workspaces", [options.workspaceId]]] } : {}), + $text: { + $search: options.search, + }, + }, + context, + ); + } + + async list( + pagination: Pagination, + options?: ListUserOptions, + context?: ExecutionContext, + ): Promise> { + const findFilter: FindFilter = {}; + const findOptions: FindOptions = { + pagination, + }; + + if (options?.userIds) { + findOptions.$in = [["id", options.userIds]]; + } + + return this.repository.find(findFilter, findOptions, context); + } + + getByEmail(email: string, context?: ExecutionContext): Promise { + return this.repository.findOne({ email_canonical: email }, {}, context); + } + + getByEmails(emails: string[], context?: ExecutionContext): Promise { + return Promise.all(emails.map(email => this.getByEmail(email))).then(emails => + emails.filter(a => a), + ); + } + + async setPreferences( + pk: UserPrimaryKey, + preferences: User["preferences"], + context?: ExecutionContext, + ): Promise { + const user = await this.repository.findOne(pk, {}, context); + if (!user.preferences) user.preferences = {}; + for (const key in preferences) { + //@ts-ignore + user.preferences[key] = preferences[key]; + } + + await this.save(user); + return user.preferences; + } + + async get(pk: UserPrimaryKey, context?: ExecutionContext): Promise { + return await this.repository.findOne(pk, {}, context); + } + + async getCached(pk: UserPrimaryKey, context?: ExecutionContext): Promise { + if (!(pk.id && isString(pk.id))) return null; + if (this.cache.has(pk.id)) return this.cache.get(pk.id); + const entity = await this.get(pk); + this.cache.set(pk.id, entity); + return entity; + } + + async getByUsername(username: string, context?: ExecutionContext): Promise { + return await this.repository.findOne( + { + username_canonical: (username || "").toLocaleLowerCase(), + }, + {}, + context, + ); + } + + async getByConsoleId( + id: string, + service_id: string = "console", + context?: ExecutionContext, + ): Promise { + const extUser = await this.extUserRepository.findOne( + { service_id, external_id: id }, + {}, + context, + ); + if (!extUser) { + return null; + } + return this.repository.findOne({ id: extUser.user_id }, {}, context); + } + + async getUserCompanies(pk: UserPrimaryKey, context?: ExecutionContext): Promise { + return await this.companyUserRepository + .find({ user_id: pk.id }, {}, context) + .then(a => a.getEntities()); + } + + async isEmailAlreadyInUse(email: string, context?: ExecutionContext): Promise { + return this.repository + .findOne({ email_canonical: email }, {}, context) + .then(user => Boolean(user)); + } + async getAvailableUsername(username: string, context?: ExecutionContext): Promise { + const user = await this.getByUsername(username); + + if (!user) { + return username; + } + + let suitableUsername = null; + + for (let i = 1; i < 1000; i++) { + const dynamicUsername = username + i; + if (!(await this.getByUsername(dynamicUsername.toLocaleLowerCase()))) { + suitableUsername = dynamicUsername; + break; + } + } + return suitableUsername; + } + + async getUserDevices( + userPrimaryKey: UserPrimaryKey, + context?: ExecutionContext, + ): Promise { + const user = await this.get(userPrimaryKey); + if (!user) { + throw CrudException.notFound(`User ${userPrimaryKey} not found`); + } + if (!user.devices || user.devices.length == 0) { + return []; + } + return Promise.all( + user.devices.map(id => this.deviceRepository.findOne({ id }, {}, context)), + ).then(a => a.filter(a => a)); + } + + async registerUserDevice( + userPrimaryKey: UserPrimaryKey, + id: string, + type: string, + version: string, + context?: ExecutionContext, + ): Promise { + await this.deregisterUserDevice(id); + + const user = await this.get(userPrimaryKey); + if (!user) { + throw CrudException.notFound(`User ${userPrimaryKey} not found`); + } + user.devices = user.devices || []; + user.devices.push(id); + + await this.repository.save(user, context); + await this.deviceRepository.save( + getDeviceInstance({ id, type, version, user_id: user.id }), + context, + ); + } + + async deregisterUserDevice(id: string, context?: ExecutionContext): Promise { + const existedDevice = await this.deviceRepository.findOne({ id }, {}, context); + + if (existedDevice) { + const user = await this.get({ id: existedDevice.user_id }); + if (user) { + user.devices = (user.devices || []).filter(d => d !== id); + await this.repository.save(user, context); + } + await this.deviceRepository.remove(existedDevice, context); + } + } + + async setPassword( + userPrimaryKey: UserPrimaryKey, + password: string, + context?: ExecutionContext, + ): Promise { + assert(password, "UserAPI.setPassword: Password is not defined"); + const passwordEncoder = new PasswordEncoder(); + const user = await this.get(userPrimaryKey); + if (!user) { + throw CrudException.notFound(`User ${userPrimaryKey.id} not found`); + } + user.password = await passwordEncoder.encodePassword(password); + user.salt = null; + await this.repository.save(user, context); + } + + async getHashedPassword( + userPrimaryKey: UserPrimaryKey, + context?: ExecutionContext, + ): Promise<[string, string]> { + const user = await this.get(userPrimaryKey); + if (!user) { + throw CrudException.notFound(`User ${userPrimaryKey.id} not found`); + } + + if (user.salt) { + return [user.password, user.salt]; + } + + return [user.password, null]; + } +} diff --git a/twake/backend/node/src/services/user/services/users/types.ts b/twake/backend/node/src/services/user/services/users/types.ts new file mode 100644 index 00000000..18a8d752 --- /dev/null +++ b/twake/backend/node/src/services/user/services/users/types.ts @@ -0,0 +1,10 @@ +export type ListUserOptions = { + userIds?: Array; +}; + +export type SearchUserOptions = { + search?: string; + companyId?: string; + workspaceId?: string; + channelId?: string; +}; diff --git a/twake/backend/node/src/services/user/services/workspace/types.ts b/twake/backend/node/src/services/user/services/workspace/types.ts new file mode 100644 index 00000000..15e94b40 --- /dev/null +++ b/twake/backend/node/src/services/user/services/workspace/types.ts @@ -0,0 +1,4 @@ +export type ListWorkspaceOptions = { + companiesIds?: string[]; + company_id?: string; +}; diff --git a/twake/backend/node/src/services/user/utils.ts b/twake/backend/node/src/services/user/utils.ts new file mode 100644 index 00000000..a66ce095 --- /dev/null +++ b/twake/backend/node/src/services/user/utils.ts @@ -0,0 +1,75 @@ +import Company from "./entities/company"; +import { + CompanyFeaturesEnum, + CompanyLimitsEnum, + CompanyObject, + CompanyStatsObject, + CompanyUserObject, +} from "./web/types"; + +export function formatCompany( + companyEntity: Company, + companyUserObject?: CompanyUserObject, + companyStats?: CompanyStatsObject, +): CompanyObject { + const res: CompanyObject = { + id: companyEntity.id, + name: companyEntity.name || "", + logo: companyEntity.logo || "", + plan: companyEntity.plan, + identity_provider: companyEntity.identity_provider, + identity_provider_id: companyEntity.identity_provider_id, + }; + + if (companyUserObject) { + res.status = "active"; // FIXME: Deactivated console user are removed from company on twake side + res.role = companyUserObject.role; + } + + if (companyStats) { + res.stats = companyStats; + } + + res.plan = { + name: res.plan?.name || "free", + limits: res.plan?.limits || {}, + features: res.plan?.features || {}, + }; + + res.plan.limits = Object.assign( + { + [CompanyLimitsEnum.CHAT_MESSAGE_HISTORY_LIMIT]: 10000, + [CompanyLimitsEnum.COMPANY_MEMBERS_LIMIT]: -1, + [CompanyLimitsEnum.COMPANY_GUESTS_LIMIT]: -1, + }, + res.plan?.limits || {}, + ); + + res.plan.features = Object.assign( + { + [CompanyFeaturesEnum.CHAT_GUESTS]: true, + [CompanyFeaturesEnum.CHAT_MESSAGE_HISTORY]: true, + [CompanyFeaturesEnum.CHAT_MULTIPLE_WORKSPACES]: true, + [CompanyFeaturesEnum.CHAT_EDIT_FILES]: true, + [CompanyFeaturesEnum.CHAT_UNLIMITED_STORAGE]: true, + [CompanyFeaturesEnum.COMPANY_INVITE_MEMBER]: true, + }, + { + ...(res.plan?.features || {}), + [CompanyFeaturesEnum.COMPANY_INVITE_MEMBER]: + res.plan?.limits[CompanyLimitsEnum.COMPANY_MEMBERS_LIMIT] <= 0 || + res.stats.total_members < res.plan?.limits[CompanyLimitsEnum.COMPANY_MEMBERS_LIMIT], + }, + ); + + return res; +} + +export function getCompanyStats(company: Company, total_messages: number = 0): CompanyStatsObject { + return { + created_at: company.dateAdded, + total_members: company.stats?.total_members || 0, + total_guests: company.stats?.total_guests || 0, + total_messages, + }; +} diff --git a/twake/backend/node/src/services/user/web/controller.ts b/twake/backend/node/src/services/user/web/controller.ts new file mode 100644 index 00000000..5900271e --- /dev/null +++ b/twake/backend/node/src/services/user/web/controller.ts @@ -0,0 +1,329 @@ +import { FastifyReply, FastifyRequest } from "fastify"; +import { + CrudException, + ExecutionContext, + ListResult, + Pagination, +} from "../../../core/platform/framework/api/crud-service"; +import { uniq } from "lodash"; + +import { CrudController } from "../../../core/platform/services/webserver/types"; +import { + ResourceCreateResponse, + ResourceDeleteResponse, + ResourceGetResponse, + ResourceListResponse, +} from "../../../utils/types"; + +import User from "../entities/user"; +import { + CompanyObject, + CompanyParameters, + CompanyStatsObject, + CompanyUserObject, + DeregisterDeviceParams, + RegisterDeviceBody, + RegisterDeviceParams, + UserListQueryParameters, + UserObject, + UserParameters, +} from "./types"; +import Company from "../entities/company"; +import CompanyUser from "../entities/company_user"; +import coalesce from "../../../utils/coalesce"; +import { getCompanyRooms, getUserRooms } from "../realtime"; +import { formatCompany, getCompanyStats } from "../utils"; +import { formatUser } from "../../../utils/users"; +import gr from "../../global-resolver"; +import { UserChannel, UsersIncludedChannel } from "../../channels/entities"; + +export class UsersCrudController + implements + CrudController< + ResourceGetResponse, + ResourceCreateResponse, + ResourceListResponse, + ResourceDeleteResponse + > +{ + async get( + request: FastifyRequest<{ Params: UserParameters }>, + _reply: FastifyReply, + ): Promise> { + const context = getExecutionContext(request); + + let id = request.params.id; + if (request.params.id === "me") { + id = context.user.id; + } + + const user = await gr.services.users.get({ id: id }); + + if (!user) { + throw CrudException.notFound(`User ${id} not found`); + } + + const userObject = await formatUser(user, { + includeCompanies: context.user.id === id, + }); + + return { + resource: userObject, + websocket: context.user.id + ? gr.platformServices.realtime.sign(getUserRooms(user), context.user.id)[0] + : undefined, + }; + } + + async save( + request: FastifyRequest<{ Body: { resource: Partial }; Params: UserParameters }>, + reply: FastifyReply, + ): Promise> { + const context = getExecutionContext(request); + + const user = await gr.services.users.get({ id: context.user.id }); + if (!user) { + reply.notFound(`User ${context.user.id} not found`); + return; + } + + user.status_icon = coalesce(request.body.resource, user.status_icon); + + await gr.services.users.save(user, context); + + return { + resource: await formatUser(user), + }; + } + + async setPreferences( + request: FastifyRequest<{ Body: User["preferences"] }>, + ): Promise { + const preferences = await gr.services.users.setPreferences( + { id: request.currentUser.id }, + request.body, + ); + return preferences; + } + + async list( + request: FastifyRequest<{ Querystring: UserListQueryParameters }>, + ): Promise> { + const context = getExecutionContext(request); + + const userIds = request.query.user_ids ? request.query.user_ids.split(",") : []; + + let users: ListResult; + if (request.query.search) { + users = await gr.services.users.search( + new Pagination(request.query.page_token, request.query.limit), + { + search: request.query.search, + companyId: request.query.search_company_id, + }, + context, + ); + } else { + users = await gr.services.users.list( + new Pagination(request.query.page_token, request.query.limit), + { userIds }, + context, + ); + } + + const resUsers = await Promise.all( + users.getEntities().map(user => + formatUser(user, { + includeCompanies: request.query.include_companies, + }), + ), + ); + + // return users; + return { + resources: resUsers, + websockets: gr.platformServices.realtime.sign([], context.user.id), + }; + } + + async getUserCompanies( + request: FastifyRequest<{ Params: UserParameters }>, + _reply: FastifyReply, + ): Promise> { + const context = getExecutionContext(request); + + const user = await gr.services.users.get({ id: request.params.id }); + + if (!user) { + throw CrudException.notFound(`User ${request.params.id} not found`); + } + + const [currentUserCompanies, requestedUserCompanies] = await Promise.all( + [context.user.id, request.params.id].map(userId => + gr.services.users.getUserCompanies({ id: userId }), + ), + ); + + const currentUserCompaniesIds = new Set(currentUserCompanies.map(a => a.group_id)); + + const companiesCache = new Map(); + const retrieveCompanyCached = async (companyId: string): Promise => { + const company = + companiesCache.get(companyId) || + (await gr.services.companies.getCompany({ id: companyId })); + companiesCache.set(companyId, company); + return company; + }; + + const combos = (await Promise.all( + requestedUserCompanies + .filter(a => currentUserCompaniesIds.has(a.group_id)) + .map((uc: CompanyUser) => + retrieveCompanyCached(uc.group_id).then(async (c: Company) => [ + c, + uc, + getCompanyStats(c, await gr.services.statistics.get(c.id, "messages")), + ]), + ), + )) as [Company, CompanyUserObject, CompanyStatsObject][]; + + return { + resources: combos.map(combo => formatCompany(...combo)), + websockets: gr.platformServices.realtime.sign([], context.user.id), + }; + } + + async getCompany( + request: FastifyRequest<{ Params: CompanyParameters }>, + _reply: FastifyReply, + ): Promise> { + const company = await gr.services.companies.getCompany({ id: request.params.id }); + const context = getExecutionContext(request); + + if (!company) { + throw CrudException.notFound(`Company ${request.params.id} not found`); + } + + let companyUserObj: CompanyUserObject | null = null; + if (context?.user?.id) { + const companyUser = await gr.services.companies.getCompanyUser(company, { + id: context.user.id, + }); + companyUserObj = { + company: company, + role: companyUser.role, + status: "active", + }; + } + + return { + resource: formatCompany( + company, + companyUserObj, + getCompanyStats(company, await gr.services.statistics.get(company.id, "messages")), + ), + websocket: context.user?.id + ? gr.platformServices.realtime.sign(getCompanyRooms(company), context.user.id)[0] + : undefined, + }; + } + + async registerUserDevice( + request: FastifyRequest<{ Body: RegisterDeviceBody }>, + _reply: FastifyReply, + ): Promise> { + const resource = request.body.resource; + if (resource.type !== "FCM") { + throw CrudException.badRequest("Type should be FCM only"); + } + const context = getExecutionContext(request); + + await gr.services.users.registerUserDevice( + { id: context.user.id }, + resource.value, + resource.type, + resource.version, + ); + + return { + resource: request.body.resource, + }; + } + + async getRegisteredDevices( + request: FastifyRequest<{ Params: UserParameters }>, + _reply: FastifyReply, + ): Promise> { + const context = getExecutionContext(request); + + const userDevices = await gr.services.users.getUserDevices({ id: context.user.id }); + + return { + resources: userDevices.map( + ud => ({ type: ud.type, value: ud.id, version: ud.version } as RegisterDeviceParams), + ), + }; + } + + async deregisterUserDevice( + request: FastifyRequest<{ Params: DeregisterDeviceParams }>, + reply: FastifyReply, + ): Promise { + const context = getExecutionContext(request); + const userDevices = await gr.services.users.getUserDevices({ id: context.user.id }); + const device = await userDevices.find(ud => ud.id == request.params.value); + if (device) { + await gr.services.users.deregisterUserDevice(device.id); + } + reply.status(204); + return { + status: "success", + }; + } + + async recent( + request: FastifyRequest<{ Params: CompanyParameters; Querystring: { limit: 100 } }>, + _reply: FastifyReply, + ): Promise> { + const context = getExecutionContext(request); + const userId = context.user.id; + const companyId = request.params.id; + + let channels: UserChannel[] = await gr.services.channels.channels + .getChannelsForUsersInWorkspace(companyId, "direct", userId, undefined, context) + .then(list => list.getEntities()); + + channels = channels.sort((a, b) => b.last_activity - a.last_activity); + channels = channels.slice(0, 100); + + const userIncludedChannels: UsersIncludedChannel[] = await Promise.all( + channels.map( + channel => + gr.services.channels.channels.includeUsersInDirectChannel( + channel, + userId, + ) as Promise, + ), + ); + + const users: UserObject[] = []; + for (const channel of userIncludedChannels) { + for (const user of channel.users) { + if (user.id != request.currentUser.id) users.push(user); + } + } + + return { + resources: [...uniq(users).slice(0, request.query.limit)], + }; + } +} + +function getExecutionContext(request: FastifyRequest): ExecutionContext { + return { + user: request.currentUser, + url: request.url, + method: request.routerMethod, + transport: "http", + }; +} diff --git a/twake/backend/node/src/services/user/web/index.ts b/twake/backend/node/src/services/user/web/index.ts new file mode 100644 index 00000000..f83ffff2 --- /dev/null +++ b/twake/backend/node/src/services/user/web/index.ts @@ -0,0 +1,13 @@ +import { FastifyInstance, FastifyRegisterOptions } from "fastify"; + +import routes from "./routes"; + +export default ( + fastify: FastifyInstance, + options: FastifyRegisterOptions<{ + prefix: string; + }>, +): void => { + fastify.log.debug("Configuring /users routes"); + fastify.register(routes, options); +}; diff --git a/twake/backend/node/src/services/user/web/routes.ts b/twake/backend/node/src/services/user/web/routes.ts new file mode 100644 index 00000000..f9072612 --- /dev/null +++ b/twake/backend/node/src/services/user/web/routes.ts @@ -0,0 +1,120 @@ +import { FastifyInstance, FastifyPluginCallback } from "fastify"; +import { UsersCrudController } from "./controller"; +import { + deleteDeviceSchema, + getCompanySchema, + getDevicesSchema, + getUserCompaniesSchema, + getUserSchema, + getUsersSchema, + postDevicesSchema, + setUserPreferencesSchema, +} from "./schemas"; + +const usersUrl = "/users"; + +const routes: FastifyPluginCallback = (fastify: FastifyInstance, options, next) => { + const usersController = new UsersCrudController(); + const accessControl = async () => { + // TODO: Handle Access Control + const authorized = true; + + if (!authorized) { + throw fastify.httpErrors.badRequest("Invalid company/workspace"); + } + }; + + fastify.route({ + method: "GET", + url: `${usersUrl}/:id`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + schema: getUserSchema, + handler: usersController.get.bind(usersController), + }); + + fastify.route({ + method: "POST", + url: `${usersUrl}/me/preferences`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + schema: setUserPreferencesSchema, + handler: usersController.setPreferences.bind(usersController), + }); + + fastify.route({ + method: "POST", + url: `${usersUrl}/me`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + schema: setUserPreferencesSchema, + handler: usersController.save.bind(usersController), + }); + + fastify.route({ + method: "GET", + url: `${usersUrl}`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + schema: getUsersSchema, + handler: usersController.list.bind(usersController), + }); + + // Get a list of companies for a user, only common companies with current user are returned. + fastify.route({ + method: "GET", + url: `${usersUrl}/:id/companies`, + preHandler: accessControl, + preValidation: [fastify.authenticate], + schema: getUserCompaniesSchema, //Fixme currently not working because we don't know features in advances and so it doesn't pass + handler: usersController.getUserCompanies.bind(usersController), + }); + + //Get a company by id and public information (this route is public and doesn't need to be authenticated) + fastify.route({ + method: "GET", + url: "/companies/:id", + preValidation: [fastify.authenticateOptional], + schema: getCompanySchema, //Fixme currently not working because we don't know features in advances and so it doesn't pass + handler: usersController.getCompany.bind(usersController), + }); + + fastify.route({ + method: "POST", + url: "/devices", + preHandler: accessControl, + preValidation: [fastify.authenticate], + schema: postDevicesSchema, + handler: usersController.registerUserDevice.bind(usersController), + }); + + fastify.route({ + method: "GET", + url: "/devices", + preHandler: accessControl, + preValidation: [fastify.authenticate], + schema: getDevicesSchema, + handler: usersController.getRegisteredDevices.bind(usersController), + }); + + fastify.route({ + method: "DELETE", + url: "/devices/:value", + preHandler: accessControl, + preValidation: [fastify.authenticate], + schema: deleteDeviceSchema, + handler: usersController.deregisterUserDevice.bind(usersController), + }); + + // recent users the current user has interacted with + fastify.route({ + method: "GET", + url: "/companies/:id/users/recent", + preValidation: [fastify.authenticateOptional], + handler: usersController.recent.bind(usersController), + }); + + next(); +}; + +export default routes; diff --git a/twake/backend/node/src/services/user/web/schemas.ts b/twake/backend/node/src/services/user/web/schemas.ts new file mode 100644 index 00000000..f97c5c81 --- /dev/null +++ b/twake/backend/node/src/services/user/web/schemas.ts @@ -0,0 +1,247 @@ +import { webSocketSchema } from "../../../utils/types"; +import { CompanyFeaturesEnum, CompanyLimitsEnum } from "./types"; + +export const userObjectSchema = { + type: "object", + properties: { + id: { type: "string" }, + provider: { type: "string" }, + provider_id: { type: "string" }, + + email: { type: "string" }, + username: { type: "string" }, + is_verified: { type: "boolean" }, + picture: { type: "string" }, + first_name: { type: "string" }, + last_name: { type: "string" }, + created_at: { type: "number" }, + deleted: { type: "boolean" }, + + status: { type: "string" }, + last_activity: { type: "number" }, + + // cache: { type: ["object", "null"] }, + cache: { + type: "object", + properties: { + companies: { type: ["array", "null"] }, + }, + }, + + //Below is only if this is myself + preferences: { + type: "object", + properties: { + tutorial_done: { type: ["boolean", "null"] }, + channel_ordering: { type: ["string", "null"] }, + recent_workspaces: { type: ["array", "null"] }, + knowledge_graph: { type: ["string", "null"] }, + locale: { type: ["string", "null"] }, + timezone: { type: ["number", "null"] }, + language: { type: ["string", "null"] }, + allow_tracking: { type: ["boolean", "null"] }, + }, + }, + companies: { + type: "array", + items: { + type: "object", + properties: { + role: { type: "string", enum: ["owner", "admin", "member", "guest"] }, + status: { type: "string", enum: ["owner", "deactivated", "invited"] }, + company: { + type: "object", + properties: { + id: { type: "string" }, + name: { type: "string" }, + logo: { type: "string" }, + }, + }, + }, + }, + }, + // TODO this is temporary, should be deleted + preference: {}, + }, +}; + +export const companyObjectSchema = { + type: "object", + properties: { + id: { type: "string" }, + name: { type: "string" }, + logo: { type: "string" }, + plan: { + type: ["object", "null"], + properties: { + name: { type: "string" }, + limits: { + type: ["object", "null"], + properties: { + [CompanyLimitsEnum.CHAT_MESSAGE_HISTORY_LIMIT]: { type: "number" }, + [CompanyLimitsEnum.COMPANY_MEMBERS_LIMIT]: { type: "number" }, + [CompanyLimitsEnum.COMPANY_GUESTS_LIMIT]: { type: "number" }, + }, + }, + features: { + type: "object", + properties: { + [CompanyFeaturesEnum.CHAT_EDIT_FILES]: { type: ["boolean"] }, + [CompanyFeaturesEnum.CHAT_GUESTS]: { type: ["boolean"] }, + [CompanyFeaturesEnum.CHAT_MESSAGE_HISTORY]: { type: "boolean" }, + [CompanyFeaturesEnum.CHAT_MULTIPLE_WORKSPACES]: { type: "boolean" }, + [CompanyFeaturesEnum.CHAT_UNLIMITED_STORAGE]: { type: "boolean" }, + [CompanyFeaturesEnum.COMPANY_INVITE_MEMBER]: { type: "boolean" }, + guests: { type: "number" }, // to rename or delete + members: { type: "number" }, // to rename or delete + storage: { type: "number" }, // to rename or delete + }, + required: [] as string[], + }, + }, + }, + stats: { + type: ["object", "null"], + properties: { + created_at: { type: "number" }, + total_members: { type: "number" }, + total_guests: { type: "number" }, + total_messages: { type: "number" }, + }, + }, + identity_provider_id: { type: "string" }, + identity_provider: { type: "string" }, + role: { type: "string", enum: ["owner", "admin", "member", "guest"] }, + status: { type: "string", enum: ["owner", "deactivated", "invited"] }, + }, +}; + +export const getUserSchema = { + response: { + "2xx": { + type: "object", + properties: { + resource: userObjectSchema, + websocket: webSocketSchema, + }, + required: ["resource"], + }, + }, +}; + +export const setUserPreferencesSchema = { + request: { + properties: { + tutorial_done: { type: ["boolean", "null"] }, + channel_ordering: { type: ["string", "null"] }, + recent_workspaces: { type: ["array", "null"] }, + knowledge_graph: { type: ["string", "null"] }, + locale: { type: ["string", "null"] }, + timezone: { type: ["number", "null"] }, + language: { type: ["string", "null"] }, + allow_tracking: { type: ["boolean", "null"] }, + }, + required: [] as any[], + }, + response: { + "2xx": userObjectSchema.properties.preferences, + }, +}; + +export const getUsersSchema = { + type: "object", + properties: { + user_ids: { type: "string" }, + include_companies: { type: "boolean" }, + }, + response: { + "2xx": { + type: "object", + properties: { + resources: { type: "array", items: userObjectSchema }, + }, + required: ["resources"], + }, + }, +}; + +//Not used because it causes issues with the features json object +export const getUserCompaniesSchema = { + type: "object", + response: { + "2xx": { + type: "object", + properties: { + resources: { type: "array", items: companyObjectSchema }, + }, + required: ["resources"], + }, + }, +}; + +//Not used because it causes issues with the features json object +export const getCompanySchema = { + type: "object", + response: { + "2xx": { + type: "object", + properties: { + resource: companyObjectSchema, + websocket: webSocketSchema, + }, + required: ["resource"], + }, + }, +}; + +const deviceSchema = { + type: "object", + properties: { + type: { type: "string" }, + value: { type: "string" }, + version: { type: "string" }, + }, + required: ["type", "value", "version"], +}; + +export const postDevicesSchema = { + type: "object", + body: { + type: "object", + properties: { + resource: deviceSchema, + }, + }, + required: ["resource"], + response: { + "2xx": { + type: "object", + properties: { + resource: deviceSchema, + }, + required: ["resource"], + }, + }, +}; + +export const getDevicesSchema = { + response: { + "2xx": { + type: "object", + properties: { + resources: { type: "array", items: deviceSchema }, + }, + }, + }, +}; + +export const deleteDeviceSchema = { + response: { + "2xx": { + type: "object", + properties: { + success: { type: "boolean" }, + }, + }, + }, +}; diff --git a/twake/backend/node/src/services/user/web/types.ts b/twake/backend/node/src/services/user/web/types.ts new file mode 100644 index 00000000..d3de93ea --- /dev/null +++ b/twake/backend/node/src/services/user/web/types.ts @@ -0,0 +1,135 @@ +import { PaginationQueryParameters } from "../../../utils/types"; +import User from "../entities/user"; + +export interface UserListQueryParameters extends PaginationQueryParameters { + user_ids?: string; + include_companies?: boolean; + search?: string; + search_company_id?: string; +} + +export interface UserParameters { + /* user id */ + id: string; +} + +export interface CompanyParameters { + /* company id */ + id: string; +} + +export interface UsersParameters { + ids?: string; + companies?: string; +} + +export type CompanyUserRole = "owner" | "admin" | "member" | "guest"; +export type CompanyUserStatus = "active" | "deactivated" | "invited"; + +export interface CompanyShort { + id: string; //Related to console "code" + name: string; + logo: string; +} + +export interface CompanyUserObject { + company: CompanyShort; + role: CompanyUserRole; + status: CompanyUserStatus; +} + +export interface UserObject { + id: string; + provider: string; + provider_id: string; + email: string; + username: string; + is_verified: boolean; + picture: string; + first_name: string; + last_name: string; + full_name: string; + created_at: number; + deleted: boolean; + status: string; //Single string for the status + last_activity: number; + last_seen?: number; + is_connected?: boolean; + cache: { companies: string[] }; + + //Below is only if this is myself + preferences?: User["preferences"]; + companies?: CompanyUserObject[]; + + // TODO this is temporary, should be deleted + preference?: User["preferences"]; +} + +export enum CompanyLimitsEnum { + CHAT_MESSAGE_HISTORY_LIMIT = "chat:message_history_limit", + COMPANY_MEMBERS_LIMIT = "company:members_limit", // 100 + COMPANY_GUESTS_LIMIT = "company:guests_limit", +} + +export enum CompanyFeaturesEnum { + CHAT_GUESTS = "chat:guests", + CHAT_MESSAGE_HISTORY = "chat:message_history", + CHAT_MULTIPLE_WORKSPACES = "chat:multiple_workspaces", + CHAT_EDIT_FILES = "chat:edit_files", + CHAT_UNLIMITED_STORAGE = "chat:unlimited_storage", + COMPANY_INVITE_MEMBER = "company:invite_member", +} + +export type CompanyFeaturesObject = { + [CompanyFeaturesEnum.CHAT_GUESTS]?: boolean; + [CompanyFeaturesEnum.CHAT_MESSAGE_HISTORY]?: boolean; + [CompanyFeaturesEnum.CHAT_MULTIPLE_WORKSPACES]?: boolean; + [CompanyFeaturesEnum.CHAT_EDIT_FILES]?: boolean; + [CompanyFeaturesEnum.CHAT_UNLIMITED_STORAGE]?: boolean; + [CompanyFeaturesEnum.COMPANY_INVITE_MEMBER]?: boolean; +}; + +export type CompanyLimitsObject = { + [CompanyLimitsEnum.CHAT_MESSAGE_HISTORY_LIMIT]?: number; + [CompanyLimitsEnum.COMPANY_MEMBERS_LIMIT]?: number; + [CompanyLimitsEnum.COMPANY_GUESTS_LIMIT]?: number; +}; + +export interface CompanyPlanObject { + name: string; + limits?: CompanyLimitsObject; + features?: CompanyFeaturesObject; +} + +export interface CompanyStatsObject { + created_at: number; + total_members: number; + total_guests: number; + total_messages: number; +} + +export interface CompanyObject { + id: string; + name: string; + logo: string; + plan?: CompanyPlanObject; + stats?: CompanyStatsObject; + role?: CompanyUserRole; + status?: CompanyUserStatus; + identity_provider: string; + identity_provider_id: string; +} + +export interface RegisterDeviceBody { + resource: RegisterDeviceParams; +} + +export interface RegisterDeviceParams { + type: "FCM"; + value: string; + version: string; +} + +export interface DeregisterDeviceParams { + value: "string"; +} diff --git a/twake/backend/node/src/services/workspaces/entities/workspace.ts b/twake/backend/node/src/services/workspaces/entities/workspace.ts new file mode 100644 index 00000000..42836e52 --- /dev/null +++ b/twake/backend/node/src/services/workspaces/entities/workspace.ts @@ -0,0 +1,50 @@ +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "workspaces"; + +@Entity(TYPE, { + primaryKey: [["company_id"], "id"], + type: TYPE, +}) +export default class Workspace { + @Column("id", "timeuuid") + id: string; + + @Column("company_id", "timeuuid") + company_id: string; + + @Column("name", "encoded_string") + name: string; + + @Column("logo", "encoded_string") + logo: string; + + @Column("stats", "encoded_string") + stats: string; + + @Column("is_deleted", "boolean") + isDeleted: boolean; + + @Column("is_archived", "boolean") + isArchived: boolean; + + @Column("is_default", "boolean") + isDefault: boolean; + + @Column("date_added", "number") + dateAdded: number; + + @Column("preferences", "encoded_json") + preferences: null | { + invite_domain?: string; + }; +} + +export type WorkspacePrimaryKey = Pick; + +export function getInstance( + workspace: Partial & Partial, +): Workspace { + return merge(new Workspace(), workspace); +} diff --git a/twake/backend/node/src/services/workspaces/entities/workspace_counters.ts b/twake/backend/node/src/services/workspaces/entities/workspace_counters.ts new file mode 100644 index 00000000..b770bf9a --- /dev/null +++ b/twake/backend/node/src/services/workspaces/entities/workspace_counters.ts @@ -0,0 +1,24 @@ +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "workspace_counters"; + +@Entity(TYPE, { + primaryKey: [["id"], "counter_type"], + type: TYPE, +}) +export class WorkspaceCounterEntity { + @Column("id", "timeuuid") + id: string; + + @Column("counter_type", "string") + counter_type: string; + + @Column("value", "counter") + value: number; +} + +export type WorkspaceCounterPrimaryKey = Pick; + +export enum WorkspaceCounterType { + MEMBERS = "members", +} diff --git a/twake/backend/node/src/services/workspaces/entities/workspace_invite_domain.ts b/twake/backend/node/src/services/workspaces/entities/workspace_invite_domain.ts new file mode 100644 index 00000000..03aee6d1 --- /dev/null +++ b/twake/backend/node/src/services/workspaces/entities/workspace_invite_domain.ts @@ -0,0 +1,30 @@ +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "workspace_invite_domain"; + +@Entity(TYPE, { + primaryKey: [["domain"], "company_id", "workspace_id"], + type: TYPE, +}) +export default class WorkspaceInviteDomain { + @Column("company_id", "timeuuid") + company_id: string; + + @Column("workspace_id", "timeuuid") + workspace_id: string; + + @Column("domain", "encoded_string") + domain: string; +} + +export type WorkspaceInviteDomainPrimaryKey = Pick< + WorkspaceInviteDomain, + "domain" | "company_id" | "workspace_id" +>; + +export function getInstance( + workspaceInviteDomain: Partial & Partial, +): WorkspaceInviteDomain { + return merge(new WorkspaceInviteDomain(), workspaceInviteDomain); +} diff --git a/twake/backend/node/src/services/workspaces/entities/workspace_invite_tokens.ts b/twake/backend/node/src/services/workspaces/entities/workspace_invite_tokens.ts new file mode 100644 index 00000000..23859e22 --- /dev/null +++ b/twake/backend/node/src/services/workspaces/entities/workspace_invite_tokens.ts @@ -0,0 +1,36 @@ +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; + +export const TYPE = "workspace_invite_tokens"; + +@Entity(TYPE, { + primaryKey: [["company_id"], "workspace_id", "user_id", "invite_token"], + type: TYPE, +}) +export default class WorkspaceInviteTokens { + @Column("company_id", "uuid") + company_id: string; + + @Column("workspace_id", "string") + workspace_id: string; + + @Column("user_id", "string") + user_id: string; + + @Column("invite_token", "string") + invite_token: string; + + @Column("channels", "encoded_json") + channels: null | string[]; +} + +export type WorkspaceInviteTokensPrimaryKey = Pick< + WorkspaceInviteTokens, + "company_id" | "workspace_id" | "user_id" | "invite_token" +>; + +export function getInstance( + workspaceInviteTokens: Partial & Partial, +): WorkspaceInviteTokens { + return merge(new WorkspaceInviteTokens(), workspaceInviteTokens); +} diff --git a/twake/backend/node/src/services/workspaces/entities/workspace_pending_users.ts b/twake/backend/node/src/services/workspaces/entities/workspace_pending_users.ts new file mode 100644 index 00000000..39ad14fd --- /dev/null +++ b/twake/backend/node/src/services/workspaces/entities/workspace_pending_users.ts @@ -0,0 +1,37 @@ +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import { WorkspaceUserRole } from "../types"; +import { CompanyUserRole } from "../../user/web/types"; + +export const TYPE = "workspace_pending_users"; + +/** + * A list of users awaiting invitation + */ +@Entity(TYPE, { + primaryKey: [["workspace_id"], "email"], + type: TYPE, +}) +export default class WorkspacePendingUser { + @Column("workspace_id", "uuid") + workspace_id: string; + + @Column("email", "string") + email: string; + + @Column("role", "string") + role: WorkspaceUserRole; + + @Column("company_role", "string") + company_role: CompanyUserRole; +} + +export type WorkspacePendingUserPrimaryKey = Partial< + Pick +>; + +export function getInstance( + workspaceUser: Partial & WorkspacePendingUserPrimaryKey, +): WorkspacePendingUser { + return merge(new WorkspacePendingUser(), workspaceUser); +} diff --git a/twake/backend/node/src/services/workspaces/entities/workspace_user.ts b/twake/backend/node/src/services/workspaces/entities/workspace_user.ts new file mode 100644 index 00000000..49144725 --- /dev/null +++ b/twake/backend/node/src/services/workspaces/entities/workspace_user.ts @@ -0,0 +1,49 @@ +import { merge } from "lodash"; +import { Column, Entity } from "../../../core/platform/services/database/services/orm/decorators"; +import { WorkspaceUserRole } from "../types"; + +export const TYPE = "workspace_user"; + +/** + * Link between a workspace and a user + */ +@Entity(TYPE, { + primaryKey: [["workspace_id"], "user_id", "id"], + type: TYPE, +}) +export default class WorkspaceUser { + @Column("workspace_id", "timeuuid") + workspaceId: string; + + @Column("user_id", "timeuuid") + userId: string; + + @Column("id", "timeuuid") + id: string; + + @Column("role", "string") + role: WorkspaceUserRole = "member"; //Relative to workspace only (not relative to company) + + @Column("date_added", "number") + dateAdded: number; + + @Column("last_access", "number") + lastAccess: number; + + @Column("is_externe", "twake_boolean") + isExternal: boolean; //Depreciated +} + +export type WorkspaceUserPrimaryKey = Partial>; + +export function getInstance( + workspaceUser: Partial & WorkspaceUserPrimaryKey, +): WorkspaceUser { + return merge(new WorkspaceUser(), workspaceUser); +} + +export function formatWorkspaceUser(workspaceUser: WorkspaceUser): WorkspaceUser { + if (!workspaceUser) return workspaceUser; + workspaceUser.role = workspaceUser.role || "member"; + return workspaceUser; +} diff --git a/twake/backend/node/src/services/workspaces/index.ts b/twake/backend/node/src/services/workspaces/index.ts new file mode 100644 index 00000000..4b940982 --- /dev/null +++ b/twake/backend/node/src/services/workspaces/index.ts @@ -0,0 +1,23 @@ +import { Prefix, TwakeService } from "../../core/platform/framework"; +import WebServerAPI from "../../core/platform/services/webserver/provider"; +import web from "./web"; +import { WorkspaceServiceImpl } from "./services/workspace"; + +@Prefix("/internal/services/workspaces/v1") +export default class Service extends TwakeService { + version = "1"; + name = "workspaces"; + + public async doInit(): Promise { + const fastify = this.context.getProvider("webserver").getServer(); + fastify.register((instance, _opts, next) => { + web(instance, { prefix: this.prefix }); + next(); + }); + return this; + } + + api(): WorkspaceServiceImpl { + return null; + } +} diff --git a/twake/backend/node/src/services/workspaces/realtime.ts b/twake/backend/node/src/services/workspaces/realtime.ts new file mode 100644 index 00000000..da0c44fd --- /dev/null +++ b/twake/backend/node/src/services/workspaces/realtime.ts @@ -0,0 +1,30 @@ +import { WebsocketMetadata } from "../../utils/types"; +import Workspace from "./entities/workspace"; +import { WorkspaceExecutionContext } from "./types"; + +export function getWebsocketInformation(workspace: Workspace): WebsocketMetadata { + return { + name: workspace.name, + room: getWorkspacePath(workspace), + }; +} + +export function getWorkspaceRooms(context: WorkspaceExecutionContext): WebsocketMetadata[] { + return [ + { + name: "workspaces", + room: getRoomName(context), + }, + ]; +} + +export function getRoomName(context: Pick): string { + return `/companies/${context.company_id}/workspaces`; +} + +export function getWorkspacePath( + workspace: Pick, + context?: WorkspaceExecutionContext, +): string { + return `/companies/${context?.company_id}/workspaces/${workspace.id}`; +} diff --git a/twake/backend/node/src/services/workspaces/services/workspace.ts b/twake/backend/node/src/services/workspaces/services/workspace.ts new file mode 100644 index 00000000..281f9527 --- /dev/null +++ b/twake/backend/node/src/services/workspaces/services/workspace.ts @@ -0,0 +1,864 @@ +import { concat, EMPTY, from, Observable } from "rxjs"; +import { mergeMap } from "rxjs/operators"; +import { + CreateResult, + CrudException, + DeleteResult, + ExecutionContext, + ListResult, + OperationType, + Paginable, + Pagination, + SaveResult, +} from "../../../core/platform/framework/api/crud-service"; +import Repository from "../../../core/platform/services/database/services/orm/repository/repository"; +import WorkspaceUser, { + formatWorkspaceUser, + getInstance as getWorkspaceUserInstance, + TYPE as WorkspaceUserType, + WorkspaceUserPrimaryKey, +} from "../../workspaces/entities/workspace_user"; +import Workspace, { + getInstance as getWorkspaceInstance, + TYPE, + TYPE as WorkspaceType, + WorkspacePrimaryKey, +} from "../../workspaces/entities/workspace"; +import { WorkspaceExecutionContext, WorkspaceUserRole } from "../types"; +import User, { UserPrimaryKey } from "../../user/entities/user"; +import { CompanyPrimaryKey } from "../../user/entities/company"; +import _, { merge } from "lodash"; +import WorkspacePendingUser, { + TYPE as WorkspacePendingUserType, + WorkspacePendingUserPrimaryKey, +} from "../entities/workspace_pending_users"; +import { CompanyUserRole } from "../../user/web/types"; +import { ResourceEventsPayload, uuid } from "../../../utils/types"; +import { CounterProvider } from "../../../core/platform/services/counter/provider"; +import { + TYPE as WorkspaceCounterEntityType, + WorkspaceCounterEntity, + WorkspaceCounterPrimaryKey, +} from "../entities/workspace_counters"; +import { countRepositoryItems } from "../../../utils/counters"; +import { + Initializable, + RealtimeSaved, + TwakeServiceProvider, +} from "../../../core/platform/framework"; +import { ResourcePath } from "../../../core/platform/services/realtime/types"; +import { getRoomName, getWorkspacePath } from "../realtime"; +import { InviteTokenObject, WorkspaceInviteTokenObject } from "../web/types"; +import WorkspaceInviteTokens, { + getInstance as getWorkspaceInviteTokensInstance, + TYPE as WorkspaceInviteTokensType, + WorkspaceInviteTokensPrimaryKey, +} from "../entities/workspace_invite_tokens"; +import { randomBytes } from "crypto"; +import { Readable } from "stream"; +import { expandUUID4, reduceUUID4 } from "../../../utils/uuid-reducer"; +import gr from "../../global-resolver"; +import { logger } from "@sentry/utils"; +import { localEventBus } from "../../../core/platform/framework/event-bus"; +import { + KnowledgeGraphEvents, + KnowledgeGraphGenericEventPayload, +} from "../../../core/platform/services/knowledge-graph/types"; +import WorkspaceInviteDomain, { + TYPE as WorkspaceInviteDomainType, + getInstance as getWorkspaceInviteDomainInstance, +} from "../entities/workspace_invite_domain"; + +export class WorkspaceServiceImpl implements TwakeServiceProvider, Initializable { + version: "1"; + private workspaceUserRepository: Repository; + private workspaceRepository: Repository; + private workspacePendingUserRepository: Repository; + private workspaceCounter: CounterProvider; + private workspaceInviteTokensRepository: Repository; + private workspaceInviteDomainRepository: Repository; + + async init(): Promise { + this.workspaceUserRepository = await gr.database.getRepository( + WorkspaceUserType, + WorkspaceUser, + ); + + this.workspaceRepository = await gr.database.getRepository(WorkspaceType, Workspace); + + const workspaceCountersRepository = await gr.database.getRepository( + WorkspaceCounterEntityType, + WorkspaceCounterEntity, + ); + + this.workspacePendingUserRepository = await gr.database.getRepository( + WorkspacePendingUserType, + WorkspacePendingUser, + ); + + this.workspaceCounter = await gr.platformServices.counter.getCounter( + workspaceCountersRepository, + ); + + this.workspaceCounter.setReviseCallback(async (pk: WorkspaceCounterPrimaryKey) => { + if (pk.counter_type == "members") { + return countRepositoryItems(this.workspaceUserRepository, { workspace_id: pk.id }); + } + return 0; + }); + + this.workspaceInviteTokensRepository = await gr.database.getRepository( + WorkspaceInviteTokensType, + WorkspaceInviteTokens, + ); + + this.workspaceInviteDomainRepository = await gr.database.getRepository( + WorkspaceInviteDomainType, + WorkspaceInviteDomain, + ); + + //If user deleted from a company, remove it from all workspace + localEventBus.subscribe("company:user:deleted", async data => { + if (data?.user?.id && data?.company?.id) + gr.services.workspaces.ensureUserNotInCompanyIsNotInWorkspace(data.user, data.company.id); + }); + + return this; + } + + get(pk: WorkspacePrimaryKey, context?: ExecutionContext): Promise { + return this.workspaceRepository.findOne(pk, {}, context); + } + + // TODO: remove logic from context + async create(workspace: Workspace, context?: ExecutionContext): Promise> { + const workspaceToCreate: Workspace = getWorkspaceInstance({ + ...workspace, + ...{ + name: await this.getWorkspaceName(workspace.name, workspace.company_id, workspace.id), + dateAdded: Date.now(), + isDeleted: false, + isArchived: false, + }, + }); + + const userId = context?.user?.id || ""; + + const created = await this.save( + workspaceToCreate, + {}, + { company_id: workspace.company_id, user: { id: userId, server_request: true } }, + ); + + await gr.services.applications.companyApps.initWithDefaultApplications( + created.entity.company_id, + { + company: { id: created.entity.company_id }, + user: { id: userId, server_request: true }, + }, + ); + + return new CreateResult(TYPE, created.entity); + } + + // TODO: remove logic from context + @RealtimeSaved((workspace, context) => [ + { + // FIXME: For now the room is defined at the company level + // It meay be good to have a special room where just some users are receiving this event + room: ResourcePath.get(getRoomName(workspace)), + path: getWorkspacePath(workspace, context as WorkspaceExecutionContext), + }, + ]) + async save( + item: Partial, + options?: SaveOptions & { logo_b64?: string }, + context?: WorkspaceExecutionContext, + ): Promise> { + let workspace = getWorkspaceInstance({ + ...item, + ...{ + company_id: (context.user.server_request ? item.company_id : null) || context.company_id, + name: "", + dateAdded: Date.now(), + isArchived: false, + isDefault: false, + }, + }); + + if (item.id && !context?.user?.server_request) { + // ON UPDATE + workspace = await this.get({ + id: item.id, + company_id: context.company_id, + }); + + if (!workspace) { + throw new Error(`Unable to edit inexistent workspace ${item.id}`); + } + } + + const logoInternalPath = `/workspaces/${workspace.id}/thumbnail.png`; + const logoPublicPath = `/internal/services/workspaces/v1/companies/${ + workspace.company_id + }/workspaces/${workspace.id}/thumbnail?t=${new Date().getTime()}`; + let logoPublicUrl = undefined; + + if (workspace.logo && item.logo === "none") { + if (!options.logo_b64) { + //If options.logo_b64 then we'll just replace the file content + await gr.platformServices.storage.remove(logoInternalPath); + workspace.logo = null; + } + } + + if (options.logo_b64) { + const s = new Readable(); + s.push(Buffer.from(options.logo_b64.split(",").pop(), "base64")); + s.push(null); + await gr.platformServices.storage.write(logoInternalPath, s); + logoPublicUrl = logoPublicPath; + } + + workspace = merge(workspace, { + name: await this.getWorkspaceName(item.name, context.company_id, workspace.id), + isArchived: item.isArchived, + isDefault: item.isDefault, + logo: logoPublicUrl || workspace.logo, + }); + + await this.workspaceRepository.save(workspace, context); + + if (!item.id && context.user.id) { + await this.addUser( + { id: workspace.id, company_id: workspace.company_id }, + { id: context.user.id }, + "moderator", + ); + } + + // On created + if (!item.id) { + gr.platformServices.messageQueue.publish("workspace:added", { + data: { + company_id: workspace.company_id, + workspace_id: workspace.id, + }, + }); + } + + localEventBus.publish>( + KnowledgeGraphEvents.WORKSPACE_UPSERT, + { + id: workspace.id, + resource: workspace, + links: [{ relation: "parent", type: "company", id: workspace.company_id }], + }, + ); + + return new SaveResult( + TYPE, + workspace, + item.id ? OperationType.UPDATE : OperationType.CREATE, + ); + } + + async thumbnail(workspaceId: string, context?: ExecutionContext): Promise<{ file: Readable }> { + const logoInternalPath = `/workspaces/${workspaceId}/thumbnail.png`; + const file = await gr.platformServices.storage.read(logoInternalPath, {}, context); + return { file }; + } + + async delete( + pk: WorkspacePrimaryKey, + context?: ExecutionContext, + ): Promise> { + const primaryKey: Workspace = merge(new Workspace(), pk); + await this.workspaceRepository.remove(primaryKey, context); + return new DeleteResult(TYPE, primaryKey, true); + } + + // TODO: remove logic from context + list( + pagination: Pagination, + options?: ListOptions, + context?: WorkspaceExecutionContext, + ): Promise> { + const pk = { company_id: context.company_id }; + + return this.workspaceRepository.find(pk, { pagination }, context); + } + + async getAllForCompany(companyId: uuid, context?: ExecutionContext): Promise { + let allCompanyWorkspaces: Workspace[] = []; + let nextPage: Pagination = new Pagination("", "100"); + do { + const tmp = await this.workspaceRepository.find( + { company_id: companyId }, + { pagination: nextPage }, + context, + ); + nextPage = tmp.nextPage as Pagination; + allCompanyWorkspaces = [...allCompanyWorkspaces, ...tmp.getEntities()]; + } while (nextPage.page_token); + + //Check there is at least one workspace in this company or enforce one + if (allCompanyWorkspaces.length == 0) { + const created = await this.create( + getWorkspaceInstance({ + company_id: companyId, + name: "Home", + isDefault: true, + }), + ); + allCompanyWorkspaces.push(created.entity); + } + + return allCompanyWorkspaces; + } + + async addUser( + workspacePk: WorkspacePrimaryKey, + userPk: UserPrimaryKey, + role: WorkspaceUserRole, + context?: ExecutionContext, + ): Promise { + const wurPk = { + workspaceId: workspacePk.id, + userId: userPk.id, + }; + + const alreadyExists = await this.getUser(wurPk); + if (!alreadyExists) { + await this.userCounterIncrease(workspacePk.id, 1); + } + + await this.workspaceUserRepository.save( + getWorkspaceUserInstance({ + workspaceId: workspacePk.id, + userId: userPk.id, + role: role, + }), + context, + ); + + await gr.platformServices.messageQueue.publish( + "workspace:member:added", + { + data: { + company_id: workspacePk.company_id, + workspace_id: workspacePk.id, + user_id: userPk.id, + }, + }, + context, + ); + } + + async updateUserRole( + workspaceUserPk: WorkspaceUserPrimaryKey, + role: WorkspaceUserRole, + context?: ExecutionContext, + ): Promise { + const workspaceUser = await this.getUser(workspaceUserPk); + if (!workspaceUser) { + throw CrudException.notFound("WorkspaceUser entity not found"); + } + await this.workspaceUserRepository.save(merge(workspaceUser, { role }), context); + } + + async checkWorkspaceHasOtherAdmin(_workspaceUserPk: WorkspaceUserPrimaryKey): Promise { + //TODO: not implemented, we should check there is still an admin in the workspace before removal. + // Note: company admin and owner are always workspace admins. + return true; + } + + async removeUser( + workspaceUserPk: WorkspaceUserPrimaryKey, + companyId: string, + context?: ExecutionContext, + ): Promise> { + const entity = await this.getUser(workspaceUserPk); + + if (!entity) { + throw CrudException.notFound("WorkspaceUser entity not found"); + } + + if (!(await this.checkWorkspaceHasOtherAdmin(workspaceUserPk))) { + throw CrudException.notFound("No other admin found in workspace"); + } + + await this.workspaceUserRepository.remove(entity, context); + await this.userCounterIncrease(workspaceUserPk.workspaceId, -1, context); + + localEventBus.publish( + "workspace:user:deleted", + { + user: entity, + workspace: { id: workspaceUserPk.workspaceId, company_id: companyId }, + }, + context, + ); + + return new DeleteResult(WorkspaceUserType, workspaceUserPk, true); + } + + async getUsers( + workspaceId: Pick, + pagination?: Paginable, + context?: ExecutionContext, + ): Promise> { + const list = await this.workspaceUserRepository.find( + { workspace_id: workspaceId.workspaceId }, + { pagination: { limitStr: pagination?.limitStr, page_token: pagination?.page_token } }, + context, + ); + list.mapEntities(m => formatWorkspaceUser(m) as any); + return list; + } + + async getUser( + workspaceUserPk: Pick, + context?: ExecutionContext, + ): Promise { + return formatWorkspaceUser( + await this.workspaceUserRepository.findOne( + { + workspace_id: workspaceUserPk.workspaceId, + user_id: workspaceUserPk.userId, + }, + {}, + context, + ), + ); + } + + async processPendingUser( + user: User, + companyId?: string, + _context?: ExecutionContext, + ): Promise { + let userCompanies = []; + if (!companyId) { + userCompanies = await gr.services.companies.getAllForUser(user.id); + } else { + userCompanies = [ + await gr.services.companies.getCompanyUser({ id: companyId }, { id: user.id }), + ]; + } + for (const userCompany of userCompanies) { + const workspaces = await this.getAllForCompany(userCompany.group_id); + for (const workspace of workspaces) { + const pendingUserPk = { + workspace_id: workspace.id, + email: user.email_canonical, + }; + const pendingUser = await this.getPendingUser(pendingUserPk); + + if (pendingUser) { + await this.removePendingUser(pendingUserPk); + await this.addUser( + { id: workspace.id, company_id: workspace.company_id }, + { id: user.id }, + pendingUser.role, + ); + } + } + } + } + + async getAllForUser( + userId: Pick, + companyId: CompanyPrimaryKey, + context?: ExecutionContext, + ): Promise { + //Process pending invitation to workspace for this user + const user = await gr.services.users.get({ id: userId.userId }); + await this.processPendingUser(user, companyId?.id); + + //Get all workspaces for this user + const allCompanyWorkspaces = await this.getAllForCompany(companyId.id, context); + const userWorkspaces = ( + await Promise.all( + allCompanyWorkspaces.map(workspace => + this.workspaceUserRepository.findOne( + { + user_id: userId.userId, + workspace_id: workspace.id, + }, + {}, + context, + ), + ), + ) + ) + .map(m => formatWorkspaceUser(m)) + .filter(uw => uw); + + //If user is in no workspace, then it must be invited in the default workspaces, expect if he's guest + if (userWorkspaces.length === 0) { + for (const workspace of allCompanyWorkspaces) { + if (workspace.isDefault && !workspace.isArchived && !workspace.isDeleted) { + try { + //Role will match the company role in the default workspaces + const companyRole = await gr.services.companies.getCompanyUser( + { id: companyId.id }, + { id: userId.userId }, + context, + ); + let role: WorkspaceUserRole = "member"; + if (companyRole.role == "admin" || companyRole.role == "owner") role = "moderator"; + + if (companyRole.role !== "guest") { + await this.addUser(workspace, { id: userId.userId }, role, context); + const uw = formatWorkspaceUser( + await this.workspaceUserRepository.findOne( + { + user_id: userId.userId, + workspace_id: workspace.id, + }, + {}, + context, + ), + ); + if (uw) { + userWorkspaces.push(uw); + } + } + } catch (err) { + console.log(err); + } + } + } + } + + return userWorkspaces; + } + + getAllUsers$( + workspaceId: Pick, + pagination?: Paginable, + ): Observable { + return from(this.getUsers(workspaceId, pagination)).pipe( + mergeMap(workspaceUsers => { + const items$ = from(workspaceUsers.getEntities()); + const next$ = workspaceUsers?.nextPage?.page_token + ? this.getAllUsers$(workspaceId, workspaceUsers.nextPage) + : EMPTY; + + return concat(items$, next$); + }), + ); + } + + async addPendingUser( + primaryKey: WorkspacePendingUserPrimaryKey, + workspaceRole: WorkspaceUserRole, + companyRole: CompanyUserRole, + context?: ExecutionContext, + ): Promise { + if (await this.getPendingUser(primaryKey)) { + throw CrudException.badRequest("User is pending already"); + } + const workspacePendingUser = merge(new WorkspacePendingUser(), { + workspace_id: primaryKey.workspace_id, + email: primaryKey.email, + role: workspaceRole, + company_role: companyRole, + }); + await this.workspacePendingUserRepository.save(workspacePendingUser, context); + } + + getPendingUser( + primaryKey: WorkspacePendingUserPrimaryKey, + context?: ExecutionContext, + ): Promise { + return this.workspacePendingUserRepository.findOne(primaryKey, {}, context); + } + + async getPendingUsers( + primaryKey: Pick, + context?: ExecutionContext, + ): Promise { + return this.workspacePendingUserRepository + .find(primaryKey, {}, context) + .then(a => a.getEntities()); + } + + async removePendingUser( + primaryKey: WorkspacePendingUserPrimaryKey, + context?: ExecutionContext, + ): Promise> { + const pendingUser = await this.getPendingUser(primaryKey); + if (!pendingUser) { + throw CrudException.notFound("Pending user not found"); + } + await this.workspacePendingUserRepository.remove(pendingUser, context); + return new DeleteResult(WorkspacePendingUserType, primaryKey, true); + } + + /** + * @name GetWorkspaceName + * @param exceptedName workspace name that user excepted to have + * @param companyId company that user excepted to create or update the workspace + * @param workspaceId + * @param context + * @returns if workspace name is already used in the company, this will return the exceptedName with the current duplicates number otherwise simply return the exceptedName + */ + private async getWorkspaceName(exceptedName: string, companyId: string, workspaceId: string) { + const workspacesList = await this.list( + null, + {}, + { company_id: companyId, user: { id: null, server_request: true } }, + ); + + workspacesList.filterEntities( + entity => entity.id !== workspaceId && _.includes(entity.name, exceptedName), + ); + + const shouldRenameWorkspace = !workspacesList.isEmpty(); + const duplicatesCount = workspacesList.getEntities().length; + + return shouldRenameWorkspace ? `${exceptedName}(${duplicatesCount + 1})` : exceptedName; + } + + private wsCountPk = (id: string) => ({ id, counter_type: "members" }); + + private userCounterIncrease( + workspaceId: string, + increaseValue: number, + context?: ExecutionContext, + ) { + return this.workspaceCounter.increase(this.wsCountPk(workspaceId), increaseValue, context); + } + + getUsersCount(workspaceId: string, context?: ExecutionContext): Promise { + return this.workspaceCounter.get(this.wsCountPk(workspaceId), context); + } + + async getInviteToken( + companyId: string, + workspaceId: string, + userId: string, + context?: ExecutionContext, + ): Promise { + const pk = { company_id: companyId, workspace_id: workspaceId, user_id: userId }; + const res = await this.workspaceInviteTokensRepository.findOne(pk, {}, context); + if (!res) return null; + + return { + token: this.encodeInviteToken(companyId, workspaceId, userId, res.invite_token), + }; + } + + async createInviteToken( + companyId: string, + workspaceId: string, + userId: string, + channels: string[], + context?: ExecutionContext, + ): Promise { + await this.deleteInviteToken(companyId, workspaceId, userId); + const token = randomBytes(32).toString("base64"); + const pk = { company_id: companyId, workspace_id: workspaceId, user_id: userId }; + await this.workspaceInviteTokensRepository.save( + getWorkspaceInviteTokensInstance({ ...pk, invite_token: token, channels }), + context, + ); + return { + token: this.encodeInviteToken(companyId, workspaceId, userId, token), + }; + } + + async deleteInviteToken( + companyId: string, + workspaceId: string, + userId: string, + context?: ExecutionContext, + ): Promise { + const pk = { company_id: companyId, workspace_id: workspaceId, user_id: userId }; + const currentRecord = await this.workspaceInviteTokensRepository.findOne( + pk, + undefined, + context, + ); + if (!currentRecord) { + return false; + } + await this.workspaceInviteTokensRepository.remove(currentRecord, context); + return true; + } + + async getInviteTokenInfo( + encodedToken: string, + context?: ExecutionContext, + ): Promise { + let tokenInfo: InviteTokenObject; + try { + tokenInfo = this.decodeInviteToken(encodedToken); + } catch (e) {} + + if (!tokenInfo) { + return null; + } + + const pk: WorkspaceInviteTokensPrimaryKey = { + company_id: tokenInfo.c, + workspace_id: tokenInfo.w, + user_id: tokenInfo.u, + invite_token: tokenInfo.t, + }; + return this.workspaceInviteTokensRepository.findOne(pk, {}, context); + } + + public encodeInviteToken( + companyId: string, + workspaceId: string, + userId: string, + token: string, + ): string { + // Change base64 characters to make them url safe + token = token.replace(/\+/g, ".").replace(/\//g, "_").replace(/=/g, "-"); + const encodedToken = `${reduceUUID4(companyId)}-${reduceUUID4(workspaceId)}-${reduceUUID4( + userId, + )}-${token}`; + return encodedToken; + } + + public decodeInviteToken(encodedToken: string): InviteTokenObject | null { + try { + const split = encodedToken.split("-"); + //We split on "-" but the token can contain "-" so be careful + // eslint-disable-next-line prefer-const + let [companyId, workspaceId, userId, token] = [ + split.shift(), + split.shift(), + split.shift(), + split.join("-"), + ]; + if (!token) { + return; + } + // Change back url safe characters to base64 + token = token.replace(/\./g, "+").replace(/_/g, "/").replace(/-/g, "="); + return { + c: expandUUID4(companyId), + w: expandUUID4(workspaceId), + u: expandUUID4(userId), + t: token, + }; + } catch (e) { + return null; + } + } + + async ensureUserNotInCompanyIsNotInWorkspace( + userPk: UserPrimaryKey, + companyId: string, + context?: ExecutionContext, + ): Promise { + const workspaces = await this.getAllForCompany(companyId); + for (const workspace of workspaces) { + const companyUser = await gr.services.companies.getCompanyUser( + { id: workspace.company_id }, + userPk, + context, + ); + if (!companyUser) { + logger.warn( + `User ${userPk.id} is not in company ${workspace.company_id} so removing from workspace ${workspace.id}`, + ); + this.removeUser({ workspaceId: workspace.id, userId: userPk.id }, companyId, context).then( + () => null, + ); + } + } + } + + /** + * Sets the invitation domain for the specified workspace + * + * @param {{ company_id: string; workspace_id: string }} pk - the primary key + * @param {String} domain - domain + * @param {ExecutionContext} context - the execution context + */ + setInviteDomain = async ( + pk: { company_id: string; workspace_id: string }, + domain: string, + context?: ExecutionContext, + ): Promise => { + const workspace = await gr.services.workspaces.get( + { + company_id: pk.company_id, + id: pk.workspace_id, + }, + context, + ); + + if (!workspace) { + logger.error("failed to set invitation domain: workspace not found"); + throw CrudException.notFound("Workspace entity not found"); + } + + if (workspace.preferences && workspace.preferences?.invite_domain !== domain) { + await this.workspaceInviteDomainRepository.remove({ + company_id: workspace.company_id, + domain: workspace.preferences.invite_domain, + workspace_id: workspace.id, + }); + } + + if (workspace.preferences && workspace.preferences?.invite_domain === domain) { + logger.warn("invite domain is already set"); + return; + } + + workspace.preferences = { + invite_domain: domain, + }; + + await this.workspaceRepository.save(workspace); + + const workspaceInvitationDomainEntry = await this.workspaceInviteDomainRepository.findOne( + { + ...pk, + domain, + }, + {}, + context, + ); + + if (!workspaceInvitationDomainEntry) { + await this.workspaceInviteDomainRepository.save( + getWorkspaceInviteDomainInstance({ + ...pk, + domain, + }), + ); + } + }; + + /** + * Get the workspaceinvitedomain entries for the specified domain + * + * @param {String} domain - the desired domain + * @param {ExecutionContext} context - the execution context + * @returns {Promise} + */ + getInviteDomainWorkspaces = async ( + domain: string, + context?: ExecutionContext, + ): Promise => { + const inviteDomainEntry = await this.workspaceInviteDomainRepository.find( + { domain }, + {}, + context, + ); + + if (!inviteDomainEntry) { + throw CrudException.notFound("workspace invite domain not found"); + } + + return inviteDomainEntry.getEntities(); + }; +} diff --git a/twake/backend/node/src/services/workspaces/types.ts b/twake/backend/node/src/services/workspaces/types.ts new file mode 100644 index 00000000..d2e89ab3 --- /dev/null +++ b/twake/backend/node/src/services/workspaces/types.ts @@ -0,0 +1,17 @@ +import { ExecutionContext } from "../../core/platform/framework/api/crud-service"; + +export interface WorkspaceExecutionContext extends ExecutionContext { + company_id: string; +} + +export interface WorkspaceUsersExecutionContext extends ExecutionContext { + company_id: string; + workspace_id: string; +} + +export interface WorkspaceInviteTokensExecutionContext extends ExecutionContext { + company_id: string; + workspace_id: string; +} + +export type WorkspaceUserRole = "moderator" | "member"; diff --git a/twake/backend/node/src/services/workspaces/web/controllers/workspace-invite-tokens.ts b/twake/backend/node/src/services/workspaces/web/controllers/workspace-invite-tokens.ts new file mode 100644 index 00000000..e37da73b --- /dev/null +++ b/twake/backend/node/src/services/workspaces/web/controllers/workspace-invite-tokens.ts @@ -0,0 +1,275 @@ +import { CrudController } from "../../../../core/platform/services/webserver/types"; +import { + ResourceCreateResponse, + ResourceDeleteResponse, + ResourceGetResponse, + ResourceListResponse, +} from "../../../../utils/types"; +import { + WorkspaceInviteTokenBody, + WorkspaceInviteTokenDeleteRequest, + WorkspaceInviteTokenGetRequest, + WorkspaceInviteTokenObject, + WorkspaceJoinByTokenRequest, + WorkspaceJoinByTokenResponse, +} from "../types"; +import { FastifyReply, FastifyRequest } from "fastify"; + +import { WorkspaceInviteTokensExecutionContext } from "../../types"; +import { CrudException } from "../../../../core/platform/framework/api/crud-service"; +import { pick } from "lodash"; +import { ConsoleCompany } from "../../../console/types"; +import { formatCompany, getCompanyStats } from "../../../../services/user/utils"; +import gr from "../../../global-resolver"; + +export class WorkspaceInviteTokensCrudController + implements + CrudController< + ResourceGetResponse, + ResourceCreateResponse, + ResourceListResponse, + ResourceDeleteResponse + > +{ + async list( + request: FastifyRequest<{ Params: WorkspaceInviteTokenGetRequest }>, + _reply: FastifyReply, + ): Promise> { + const context = getExecutionContext(request); + + const res = await gr.services.workspaces.getInviteToken( + context.company_id, + context.workspace_id, + context.user.id, + ); + + if (!res) { + throw CrudException.notFound("Invite token not found"); + } + + return { + resources: [{ token: res.token }], + }; + } + + async save( + request: FastifyRequest<{ + Params: WorkspaceInviteTokenGetRequest; + Body: WorkspaceInviteTokenBody; + }>, + _reply: FastifyReply, + ): Promise> { + const context = getExecutionContext(request); + + const res = await gr.services.workspaces.createInviteToken( + context.company_id, + context.workspace_id, + context.user.id, + request.body.channels, + ); + + return { + resource: { token: res.token }, + }; + } + + async delete( + request: FastifyRequest<{ Params: WorkspaceInviteTokenDeleteRequest }>, + reply: FastifyReply, + ): Promise { + const context = getExecutionContext(request); + + const tokenInfo = gr.services.workspaces.decodeInviteToken(request.params.token); + + if (!tokenInfo) { + throw CrudException.notFound("Invite token malformed"); + } + + const deleted = await gr.services.workspaces.deleteInviteToken( + context.company_id, + context.workspace_id, + context.user.id, + ); + + if (!deleted) { + throw CrudException.notFound("Invite token not found"); + } + + reply.code(204); + + return { + status: "success", + }; + } + + async join( + request: FastifyRequest<{ Body: WorkspaceJoinByTokenRequest }>, + _reply: FastifyReply, + ): Promise> { + const entity = await gr.services.workspaces.getInviteTokenInfo(request.body.token); + + if (!entity) { + throw CrudException.notFound("Token not found"); + } + + const { company_id, workspace_id } = entity; + + const [company, workspace] = await Promise.all([ + gr.services.companies.getCompany({ id: company_id }), + gr.services.workspaces.get({ + company_id: company_id, + id: workspace_id, + }), + ]); + const total_messages = await gr.services.statistics.get(company.id, "messages"); + + const resource: WorkspaceJoinByTokenResponse = { + company: { + name: company.name, + stats: formatCompany(company, undefined, getCompanyStats(company, total_messages))?.stats, + plan: formatCompany(company, undefined, getCompanyStats(company, total_messages))?.plan, + }, + workspace: { name: workspace.name }, + auth_required: false, + }; + + if (!request.currentUser) { + resource.auth_required = true; + } else { + if (request.body.join) { + const userId = request.currentUser.id; + const user = await gr.services.users.get({ id: userId }); + + let companyUser = await gr.services.companies.getCompanyUser( + { id: company_id }, + { id: userId }, + ); + if (!companyUser) { + const inviter = await gr.services.users.get({ + id: entity.user_id, + }); + + await gr.services.console + .getClient() + .addUserToCompany( + { id: company.id, code: company.identity_provider_id } as ConsoleCompany, + { + id: userId, + email: request.currentUser.email, + password: null, + firstName: null, + lastName: null, + name: null, + avatar: { + type: null, + value: null, + }, + role: "member", + skipInvite: false, + inviterEmail: inviter.email_canonical, + }, + ); + + await gr.services.console + .getClient() + .updateLocalUserFromConsole(user.identity_provider_id); + companyUser = await gr.services.companies.getCompanyUser( + { id: company_id }, + { id: userId }, + ); + } + if (!companyUser) { + throw CrudException.badRequest("Unable to add user to the company"); + } + + const userEmailDomain = user.email_canonical.split("@").pop(); + const inviteDomainEntries = await gr.services.workspaces.getInviteDomainWorkspaces( + userEmailDomain, + ); + + inviteDomainEntries.map(async entry => { + const workspace = await gr.services.workspaces.get({ + company_id: entry.company_id, + id: entry.workspace_id, + }); + + if (!workspace) { + return; + } + + if ( + !workspace.preferences.invite_domain || + workspace.preferences.invite_domain !== userEmailDomain + ) { + return; + } + + const existingUser = await gr.services.workspaces.getUser({ + userId, + workspaceId: entry.workspace_id, + }); + + if (existingUser) { + return; + } + + await gr.services.workspaces.addUser( + { + company_id: entry.company_id, + id: entry.workspace_id, + }, + { id: userId }, + "member", + ); + }); + + const workspaceUser = await gr.services.workspaces.getUser({ + workspaceId: workspace.id, + userId: userId, + }); + if (!workspaceUser) { + await gr.services.workspaces.addUser( + pick(workspace, ["company_id", "id"]), + { id: userId }, + "member", + ); + } + + await gr.services.channelPendingEmail.proccessPendingEmails( + { + company_id, + user_id: userId, + workspace_id, + }, + { + company_id, + workspace_id, + }, + { + user: request.currentUser, + url: request.url, + method: request.routerMethod, + transport: "http", + }, + ); + resource.company.id = company.id; + resource.workspace.id = workspace.id; + } + } + + return { resource }; + } +} + +function getExecutionContext( + request: FastifyRequest<{ Params: WorkspaceInviteTokenGetRequest }>, +): WorkspaceInviteTokensExecutionContext { + return { + user: request.currentUser, + company_id: request.params.company_id, + workspace_id: request.params.workspace_id, + url: request.url, + method: request.routerMethod, + transport: "http", + }; +} diff --git a/twake/backend/node/src/services/workspaces/web/controllers/workspace-users.ts b/twake/backend/node/src/services/workspaces/web/controllers/workspace-users.ts new file mode 100644 index 00000000..d6cc88d6 --- /dev/null +++ b/twake/backend/node/src/services/workspaces/web/controllers/workspace-users.ts @@ -0,0 +1,583 @@ +import { CrudController } from "../../../../core/platform/services/webserver/types"; +import { + ResourceCreateResponse, + ResourceDeleteResponse, + ResourceGetResponse, + ResourceListResponse, + uuid, +} from "../../../../utils/types"; +import { + WorkspacePendingUserRequest, + WorkspaceUserInvitationResponse, + WorkspaceUserInvitationResponseItem, + WorkspaceUserObject, + WorkspaceUsersAddBody, + WorkspaceUsersBaseRequest, + WorkspaceUsersInvitationItem, + WorkspaceUsersInvitationRequestBody, + WorkspaceUsersRequest, +} from "../types"; +import { FastifyReply, FastifyRequest } from "fastify"; + +import { WorkspaceUsersExecutionContext } from "../../types"; +import WorkspaceUser from "../../entities/workspace_user"; +import User from "../../../user/entities/user"; +import CompanyUser from "../../../user/entities/company_user"; +import { CompanyShort, CompanyUserRole, CompanyUserStatus } from "../../../user/web/types"; +import Company from "../../../user/entities/company"; +import { chain } from "lodash"; +import { + CrudException, + ListResult, + Pagination, +} from "../../../../core/platform/framework/api/crud-service"; +import WorkspacePendingUser from "../../entities/workspace_pending_users"; +import { ConsoleCompany, CreateConsoleUser } from "../../../console/types"; +import { hasCompanyAdminLevel } from "../../../../utils/company"; +import gr from "../../../global-resolver"; +import { getChannelPendingEmailsInstance } from "../../../channels/entities"; + +export class WorkspaceUsersCrudController + implements + CrudController< + ResourceGetResponse, + ResourceCreateResponse, + ResourceListResponse, + ResourceDeleteResponse + > +{ + private formatWorkspaceUser( + workspaceUser: WorkspaceUser, + currentCompanyId: uuid, + user: User, + userCompanies: CompanyUser[], + companiesMap: Map, + ): WorkspaceUserObject { + //Company admins should be workspace moderators automatically + if ( + currentCompanyId && + userCompanies && + hasCompanyAdminLevel(userCompanies.find(uc => uc.group_id === currentCompanyId)?.role) + ) { + workspaceUser.role = "moderator"; + } + + const res: WorkspaceUserObject = { + id: workspaceUser.id, + company_id: currentCompanyId, + user_id: workspaceUser.userId, + workspace_id: workspaceUser.workspaceId, + created_at: workspaceUser.dateAdded, + role: workspaceUser.role || "member", + user: { + id: user.id, + provider: user.identity_provider, + provider_id: user.identity_provider_id, + email: user.email_canonical, + username: user.username_canonical, + is_verified: Boolean(user.mail_verified), + picture: user.picture, + first_name: user.first_name, + last_name: user.last_name, + full_name: [user.first_name, user.last_name].join(" "), + created_at: user.creation_date, + deleted: Boolean(user.deleted), + status: user.status_icon, + last_activity: user.last_activity, + cache: { + companies: user.cache?.companies || [], + }, + companies: userCompanies + .filter(cu => companiesMap.get(cu.group_id)) + .map(cu => { + const company = companiesMap.get(cu.group_id); + return { + role: (cu.role as CompanyUserRole) || "guest", + status: "active" as CompanyUserStatus, // FIXME: with real status + company: { + id: company.id, + name: company.name, + logo: company.logo, + } as CompanyShort, + }; + }), + }, + }; + + return res; + } + + private async getCompaniesMap(companyUsers: CompanyUser[]) { + const companiesMap: Map = new Map( + ( + await Promise.all( + chain(companyUsers) + .map("group_id") + .uniq() + .value() + .map(companyId => gr.services.companies.getCompany({ id: companyId })), + ) + ) + .filter(c => c) + .map(c => [c.id, c]), + ); + return companiesMap; + } + + async list( + request: FastifyRequest<{ + Params: WorkspaceUsersBaseRequest; + Querystring: { search?: string; page_token?: string; limit?: string }; + }>, + _reply: FastifyReply, + ): Promise> { + const context = getExecutionContext(request); + let nextPageToken: string | null = null; + + let allWorkspaceUsers: WorkspaceUser[] = []; + if (request.query.search) { + const users: ListResult = await gr.services.users.search( + new Pagination(request.query.page_token, request.query.limit), + { + search: request.query.search, + companyId: context.company_id, + }, + context, + ); + + nextPageToken = users.nextPage?.page_token; + + for (const user of users.getEntities()) { + const res = await gr.services.workspaces.getUser({ + workspaceId: context.workspace_id, + userId: user.id, + }); + + if (res) allWorkspaceUsers.push(res); + } + } else { + const result = await gr.services.workspaces.getUsers( + { + workspaceId: context.workspace_id, + }, + new Pagination(request.query.page_token, request.query.limit), + ); + + allWorkspaceUsers = result.getEntities(); + + nextPageToken = result.page_token; + } + + const allUsersMap = new Map( + ( + await Promise.all( + allWorkspaceUsers.map(wu => gr.services.users.get({ id: wu.userId })), + ).then(users => users.filter(a => a)) + ).map(user => [user.id, user]), + ); + + const allCompanyUsers: CompanyUser[] = [].concat( + ...(await Promise.all( + allWorkspaceUsers.map(wu => gr.services.users.getUserCompanies({ id: wu.userId })), + )), + ); + + const companyUsersMap = new Map>(); + + for (const companyUser of allCompanyUsers) { + if (!companyUsersMap.has(companyUser.user_id)) { + companyUsersMap.set(companyUser.user_id, new Set()); + } + companyUsersMap.get(companyUser.user_id).add(companyUser); + } + + const companiesMap = await this.getCompaniesMap(allCompanyUsers); + + const resources = allWorkspaceUsers + .filter(wu => allUsersMap.get(wu.userId)) + .map(async wu => + this.formatWorkspaceUser( + wu, + context.company_id, + allUsersMap.get(wu.userId), + Array.from(companyUsersMap.get(wu.userId) || []), + companiesMap, + ), + ); + + return { + resources: await Promise.all(resources), + next_page_token: nextPageToken, + }; + } + + private async getForOne( + userId: uuid, + context: WorkspaceUsersExecutionContext, + ): Promise { + const workspaceUser = await gr.services.workspaces.getUser({ + workspaceId: context.workspace_id, + userId: userId, + }); + + const user = await gr.services.users.get({ id: userId }); + + if (!user) { + throw CrudException.badRequest("User entity not found"); + } + + const userCompanies: CompanyUser[] = await gr.services.users.getUserCompanies({ id: userId }); + + const companiesMap = await this.getCompaniesMap(userCompanies); + + return this.formatWorkspaceUser( + workspaceUser, + context.company_id, + user, + userCompanies, + companiesMap, + ); + } + + async get( + request: FastifyRequest<{ Params: WorkspaceUsersRequest }>, + _reply: FastifyReply, + ): Promise> { + const context = getExecutionContext(request); + + const resource = await this.getForOne(context.user.id, context); + + return { + resource, + }; + } + + async save( + request: FastifyRequest<{ Body: WorkspaceUsersAddBody; Params: WorkspaceUsersRequest }>, + reply: FastifyReply, + ): Promise> { + const context = getExecutionContext(request); + const userId = request.params.user_id || request.body.resource.user_id; + const role = request.body.resource.role; + + const companyUser = await gr.services.companies.getCompanyUser( + { id: context.company_id }, + { id: userId }, + ); + + if (!companyUser) { + throw CrudException.badRequest(`User ${userId} does not belong to this company`); + } + + const workspaceUser = await gr.services.workspaces.getUser({ + workspaceId: context.workspace_id, + userId: userId, + }); + + if (request.params.user_id) { + // ON UPDATE + if (!workspaceUser) { + throw CrudException.notFound(`User ${userId} not found in this workspace`); + } + await gr.services.workspaces.updateUserRole( + { workspaceId: context.workspace_id, userId }, + role, + ); + } else { + // ON ADD + if (!workspaceUser) { + await gr.services.workspaces.addUser( + { id: context.workspace_id, company_id: context.company_id }, + { id: userId }, + role, + ); + } + + const user = await gr.services.users.get({ + id: userId, + }); + + if (user) { + const userEmailDomain = user.email_canonical.split("@").pop(); + const inviteDomainEntries = await gr.services.workspaces.getInviteDomainWorkspaces( + userEmailDomain, + ); + + inviteDomainEntries.map(async entry => { + const workspace = await gr.services.workspaces.get({ + company_id: entry.company_id, + id: entry.workspace_id, + }); + + if (!workspace) { + return; + } + + if ( + !workspace.preferences.invite_domain || + workspace.preferences.invite_domain !== userEmailDomain + ) { + return; + } + + const existingUser = await gr.services.workspaces.getUser({ + userId, + workspaceId: entry.workspace_id, + }); + + if (existingUser) { + return; + } + + await gr.services.workspaces.addUser( + { + company_id: entry.company_id, + id: entry.workspace_id, + }, + { id: userId }, + "member", + ); + }); + } + } + + const resource = await this.getForOne(userId, context); + + reply.status(201); + + return { + resource: resource, + }; + } + + async delete( + request: FastifyRequest<{ Params: WorkspaceUsersRequest }>, + reply: FastifyReply, + ): Promise { + const context = getExecutionContext(request); + + const workspaceUser = await gr.services.workspaces.getUser({ + workspaceId: context.workspace_id, + userId: request.params.user_id, + }); + + if (!workspaceUser) { + throw CrudException.notFound("Default channel has not been found"); + } + + await gr.services.workspaces.removeUser( + { + workspaceId: context.workspace_id, + userId: request.params.user_id, + }, + request.params.company_id, + ); + + reply.status(204); + return { + status: "success", + }; + } + + async invite( + request: FastifyRequest<{ + Body: WorkspaceUsersInvitationRequestBody; + Params: WorkspaceUsersRequest; + }>, + _reply: FastifyReply, + ): Promise { + const context = getExecutionContext(request); + + const usersInTwake: Map = new Map( + await gr.services.users + .getByEmails(request.body.invitations.map(a => a.email)) + .then(users => users.map(user => [user.email_canonical, user])), + ); + + const workspacePendingUsers: Map = new Map( + await gr.services.workspaces + .getPendingUsers({ + workspace_id: context.workspace_id, + }) + .then(pendingUsers => pendingUsers.map(pendingUser => [pendingUser.email, pendingUser])), + ); + + const responses: WorkspaceUserInvitationResponseItem[] = []; + + const putUserToPending = async (invitation: WorkspaceUsersInvitationItem) => { + await gr.services.workspaces.addPendingUser( + { + workspace_id: context.workspace_id, + email: invitation.email, + }, + invitation.role, + invitation.company_role, + ); + (request.body.channels || []).forEach(async channelId => { + const channelPendingEmail = getChannelPendingEmailsInstance({ + channel_id: channelId, + company_id: request.params.company_id, + email: invitation.email, + workspace_id: context.workspace_id, + }); + + await gr.services.channelPendingEmail.create(channelPendingEmail, context); + }); + responses.push({ email: invitation.email, status: "ok" }); + }; + + const usersToProcessImmediately = []; + + for (const invitation of request.body.invitations) { + if (workspacePendingUsers.has(invitation.email)) { + responses.push({ + email: invitation.email, + status: "error", + message: "Pending user already exists", + }); + continue; + } + + let userInCompany = false; + let user: User = null; + + const consoleClient = gr.services.console.getClient(); + + if (usersInTwake.has(invitation.email)) { + user = usersInTwake.get(invitation.email); + usersToProcessImmediately.push(user); + + if (user) { + userInCompany = Boolean( + await gr.services.companies.getCompanyUser({ id: context.company_id }, { id: user.id }), + ); + } + } else { + user = await consoleClient.addUserToTwake({ + email: invitation.email, + password: invitation.password, + }); + } + + if (!userInCompany) { + const company = await gr.services.companies.getCompany({ + id: context.company_id, + }); + const createUser: CreateConsoleUser = { + id: user ? user.id : null, + email: invitation.email, + firstName: null, + lastName: null, + name: null, + avatar: { + type: null, + value: null, + }, + password: invitation.password, + role: invitation.company_role || "guest", + skipInvite: false, + inviterEmail: context.user.email, + }; + + try { + await consoleClient.addUserToCompany( + { id: company.id, code: company.identity_provider_id } as ConsoleCompany, + createUser, + ); + } catch (err) { + responses.push({ + email: invitation.email, + status: "error", + message: "Unable to invite this user to your company " + err, + }); + continue; + } + } + + const userInWorkspace = Boolean( + user && + (await gr.services.workspaces.getUser({ + workspaceId: context.workspace_id, + userId: user.id, + })), + ); + + if (userInWorkspace) { + responses.push({ + email: invitation.email, + status: "error", + message: "User is already in workspace", + }); + } else { + await putUserToPending(invitation); + } + } + + await Promise.all( + usersToProcessImmediately.map(user => { + gr.services.console.processPendingUser(user); + gr.services.channelPendingEmail.proccessPendingEmails( + { + company_id: context.company_id, + user_id: user.id, + workspace_id: context.workspace_id, + }, + { + workspace_id: context.workspace_id, + company_id: context.company_id, + }, + context, + ); + }), + ); + + return { + resources: responses, + }; + } + + async deletePending( + request: FastifyRequest<{ Params: WorkspacePendingUserRequest }>, + _reply: FastifyReply, + ): Promise { + try { + await gr.services.workspaces.removePendingUser({ + workspace_id: request.params.workspace_id, + email: request.params.email, + }); + + return { status: "success" }; + } catch (e) { + console.error(e); + return { + status: "error", + }; + } + } + + async listPending( + request: FastifyRequest<{ Params: WorkspacePendingUserRequest }>, + _reply: FastifyReply, + ): Promise> { + const resources = await gr.services.workspaces.getPendingUsers({ + workspace_id: request.params.workspace_id, + }); + + return { + resources, + }; + } +} + +function getExecutionContext( + request: FastifyRequest<{ Params: WorkspaceUsersBaseRequest }>, +): WorkspaceUsersExecutionContext { + return { + user: request.currentUser, + company_id: request.params.company_id, + workspace_id: request.params.workspace_id, + url: request.url, + method: request.routerMethod, + transport: "http", + }; +} diff --git a/twake/backend/node/src/services/workspaces/web/controllers/workspaces.ts b/twake/backend/node/src/services/workspaces/web/controllers/workspaces.ts new file mode 100644 index 00000000..3a4446d0 --- /dev/null +++ b/twake/backend/node/src/services/workspaces/web/controllers/workspaces.ts @@ -0,0 +1,324 @@ +import { CrudController } from "../../../../core/platform/services/webserver/types"; +import { + ResourceCreateResponse, + ResourceDeleteResponse, + ResourceGetResponse, + ResourceListResponse, +} from "../../../../utils/types"; +import { + UpdateWorkspaceBody, + WorkspaceBaseRequest, + WorkspaceInviteDomainBody, + WorkspaceObject, + WorkspaceRequest, + WorkspacesListRequest, +} from "../types"; +import { FastifyReply, FastifyRequest } from "fastify"; +import Workspace from "../../entities/workspace"; +import { WorkspaceExecutionContext } from "../../types"; +import { plainToClass } from "class-transformer"; +import { hasCompanyAdminLevel, hasCompanyMemberLevel } from "../../../../utils/company"; +import { hasWorkspaceAdminLevel } from "../../../../utils/workspace"; +import { getWorkspaceRooms } from "../../realtime"; +import { + CrudException, + ExecutionContext, +} from "../../../../core/platform/framework/api/crud-service"; +import CompanyUser from "../../../user/entities/company_user"; +import gr from "../../../global-resolver"; +import { getLogger, TwakeLogger } from "../../../../core/platform/framework"; + +export class WorkspacesCrudController + implements + CrudController< + ResourceGetResponse, + ResourceCreateResponse, + ResourceListResponse, + ResourceDeleteResponse + > +{ + private logger: TwakeLogger; + private getCompanyUserRole(companyId: string, userId: string, context?: ExecutionContext) { + return gr.services.companies + .getCompanyUser({ id: companyId }, { id: userId }, context) + .then(a => (a ? a.role : null)); + } + + private getWorkspaceUserRole(workspaceId: string, userId: string, context?: ExecutionContext) { + return gr.services.workspaces + .getUser({ workspaceId, userId }, context) + .then(a => (a ? a.role || "member" : null)); + } + + private getWorkspaceUsersCount(workspaceId: string, context?: ExecutionContext) { + return gr.services.workspaces.getUsersCount(workspaceId, context); + } + + private async formatWorkspace( + workspace: Workspace, + usersCount: number, + userId?: string, + ): Promise { + const res: WorkspaceObject = { + id: workspace.id, + company_id: workspace.company_id, + name: workspace.name, + logo: workspace.logo, + + default: workspace.isDefault, + archived: workspace.isArchived, + + stats: { + created_at: workspace.dateAdded, + total_members: usersCount, + }, + + preferences: workspace.preferences, + }; + + if (userId) { + let role = await this.getWorkspaceUserRole(workspace.id, userId); + if (role !== "moderator") { + //Company admins should be workspace moderators automatically + const companyUser: CompanyUser = await gr.services.companies.getCompanyUser( + { id: workspace.company_id }, + { id: userId }, + ); + if (companyUser && hasCompanyAdminLevel(companyUser?.role)) { + role = "moderator"; + } + } + res.role = role; + } + + return res; + } + + async thumbnail( + request: FastifyRequest<{ Params: WorkspaceRequest }>, + response: FastifyReply, + ): Promise { + const data = await gr.services.workspaces.thumbnail(request.params.id); + const filename = "thumbnail.png"; + + response.header("Content-disposition", `inline; filename="${filename}"`); + response.type("image/png"); + + response.send(data.file); + } + + async get( + request: FastifyRequest<{ Params: WorkspaceRequest }>, + _reply: FastifyReply, + ): Promise> { + const context = getExecutionContext(request); + + const workspace = await gr.services.workspaces.get({ + company_id: context.company_id, + id: request.params.id, + }); + + if (!workspace) { + throw CrudException.notFound(`Workspace ${request.params.id} not found`); + } + + const workspaceUserRole = await this.getWorkspaceUserRole(request.params.id, context.user.id); + if (!workspaceUserRole) { + const companyUserRole = await this.getCompanyUserRole(context.company_id, context.user.id); + if (companyUserRole !== "admin") { + throw CrudException.forbidden(`You are not belong to workspace ${request.params.id}`); + } + } + + const count = await this.getWorkspaceUsersCount(workspace.id); + return { + resource: await this.formatWorkspace(workspace, count, context.user.id), + }; + } + + async list( + request: FastifyRequest<{ Params: WorkspacesListRequest }>, + ): Promise> { + const context = getExecutionContext(request); + + const allCompanyWorkspaces = await gr.services.workspaces.getAllForCompany(context.company_id); + + const allUserWorkspaceRolesMap = await gr.services.workspaces + .getAllForUser({ userId: context.user.id }, { id: context.company_id }) + .then( + uws => + // eslint-disable-next-line @typescript-eslint/no-explicit-any + new Map( + uws.map(uw => [ + uw.workspaceId, + hasCompanyAdminLevel(uw.role) ? "moderator" : uw.role || "member", + ]), + ), + ); + + const userWorkspaces = allCompanyWorkspaces.filter(workspace => + allUserWorkspaceRolesMap.has(workspace.id.toString()), + ); + + return { + resources: await Promise.all( + userWorkspaces.map(async ws => + this.formatWorkspace(ws, await this.getWorkspaceUsersCount(ws.id), context.user.id), + ), + ), + websockets: gr.platformServices.realtime.sign(getWorkspaceRooms(context), context.user.id), + }; + } + + async save( + request: FastifyRequest<{ Params: WorkspaceRequest; Body: UpdateWorkspaceBody }>, + reply: FastifyReply, + ): Promise> { + const context = getExecutionContext(request); + const companyUserRole = await this.getCompanyUserRole(context.company_id, context.user.id); + + if (!hasCompanyMemberLevel(companyUserRole)) { + throw CrudException.forbidden(`You are not a member of company ${context.company_id}`); + } + + if (!hasCompanyAdminLevel(companyUserRole) && request.params.id) { + const workspaceUserRole = await this.getWorkspaceUserRole(request.params.id, context.user.id); + const companyUserRole = await this.getCompanyUserRole(context.company_id, context.user.id); + + if (!hasWorkspaceAdminLevel(workspaceUserRole, companyUserRole)) { + throw CrudException.forbidden("You are not a admin of workspace or company"); + } + } + + const r = request.body.resource; + const opt = request.body.options; + + const existedEntity = request.params.id + ? await gr.services.workspaces.get({ + company_id: request.params.company_id, + id: request.params.id, + }) + : null; + + const entity = plainToClass(Workspace, { + ...{ + name: r.name || existedEntity?.name, + logo: r.logo || existedEntity?.logo, + isDefault: r.default || existedEntity?.isDefault, + isArchived: r.archived || existedEntity?.isArchived, + }, + ...{ + group_id: request.params.company_id, + id: request.params.id, + }, + }); + + const workspaceEntity = await gr.services.workspaces + .save(entity, opt || {}, context) + .then(a => a.entity); + + request.params.id ? reply.code(200) : reply.code(201); + + return { + resource: await this.formatWorkspace( + workspaceEntity, + await this.getWorkspaceUsersCount(workspaceEntity.id), + context.user.id, + ), + }; + } + + async delete( + request: FastifyRequest<{ Params: WorkspaceRequest }>, + reply: FastifyReply, + ): Promise { + const context = getExecutionContext(request); + + await this.checkWorkspaceModeratorAccess(request, context); + + const deleteResult = await gr.services.workspaces.delete({ + id: request.params.id, + company_id: context.company_id, + }); + + if (deleteResult.deleted) { + reply.code(204); + + return { + status: "success", + }; + } + + return { + status: "error", + }; + } + + /** + * Sets the invitation domain for the workspace. + * + * @param {FastifyRequest<{ Params: WorkspaceRequest; Body: WorkspaceInviteDomainBody }>} request - the request + * @param {FastifyReply} _reply - the reply + * @returns {Promise<{ status: string }>} + */ + setInviteDomain = async ( + request: FastifyRequest<{ Params: WorkspaceRequest; Body: WorkspaceInviteDomainBody }>, + _reply: FastifyReply, + ): Promise<{ status: string }> => { + const context = getExecutionContext(request); + + await this.checkWorkspaceModeratorAccess(request, context); + + try { + const { company_id, id } = request.params; + await gr.services.workspaces.setInviteDomain( + { company_id, workspace_id: id }, + request.body.domain, + context, + ); + } catch (error) { + throw CrudException.badRequest("Failed to set invitation domain"); + } + + return { + status: "success", + }; + }; + + /** + * Checks whether the current user have moderator access level to the workspace. + * + * @param {FastifyRequest<{ Params: WorkspaceRequest }>} request - the request + * @param {WorkspaceExecutionContext} context - the workspace execution context + */ + checkWorkspaceModeratorAccess = async ( + request: FastifyRequest<{ Params: WorkspaceRequest }>, + context: WorkspaceExecutionContext, + ): Promise => { + const workspaceUserRole = await this.getWorkspaceUserRole(request.params.id, context.user.id); + const companyUserRole = await this.getCompanyUserRole(context.company_id, context.user.id); + + if (!hasWorkspaceAdminLevel(workspaceUserRole, companyUserRole)) { + const companyUserRole = await this.getCompanyUserRole(context.company_id, context.user.id); + if (companyUserRole !== "admin") { + throw CrudException.forbidden("You are not a admin of workspace or company"); + } + } + }; + + constructor() { + this.logger = getLogger("Workspaces controller"); + } +} + +function getExecutionContext( + request: FastifyRequest<{ Params: WorkspaceBaseRequest }>, +): WorkspaceExecutionContext { + return { + user: request.currentUser, + company_id: request.params.company_id, + url: request.url, + method: request.routerMethod, + transport: "http", + }; +} diff --git a/twake/backend/node/src/services/workspaces/web/index.ts b/twake/backend/node/src/services/workspaces/web/index.ts new file mode 100644 index 00000000..2f9ff109 --- /dev/null +++ b/twake/backend/node/src/services/workspaces/web/index.ts @@ -0,0 +1,12 @@ +import { FastifyInstance, FastifyRegisterOptions } from "fastify"; +import routes from "./routes"; + +export default ( + fastify: FastifyInstance, + options: FastifyRegisterOptions<{ + prefix: string; + }>, +): void => { + fastify.log.debug("Configuring /workspaces routes"); + fastify.register(routes, options); +}; diff --git a/twake/backend/node/src/services/workspaces/web/routes.ts b/twake/backend/node/src/services/workspaces/web/routes.ts new file mode 100644 index 00000000..9a306455 --- /dev/null +++ b/twake/backend/node/src/services/workspaces/web/routes.ts @@ -0,0 +1,359 @@ +import { FastifyInstance, FastifyPluginCallback, FastifyRequest } from "fastify"; +import { WorkspacesCrudController } from "./controllers/workspaces"; +import { + createWorkspaceSchema, + createWorkspaceUserSchema, + deleteWorkspaceInviteTokenSchema, + deleteWorkspacePendingUsersSchema, + deleteWorkspaceUserSchema, + getWorkspaceInviteTokenSchema, + getWorkspacePendingUsersSchema, + getWorkspaceSchema, + getWorkspacesSchema, + getWorkspaceUserSchema, + getWorkspaceUsersSchema, + inviteWorkspaceUserSchema, + joinInviteTokenSchema, + postWorkspaceInviteTokenSchema, + updateWorkspaceSchema, + updateWorkspaceUserSchema, +} from "./schemas"; +import { + WorkspaceBaseRequest, + WorkspaceInviteDomainBody, + WorkspaceRequest, + WorkspaceUsersBaseRequest, + WorkspaceUsersRequest, +} from "./types"; +import { WorkspaceUsersCrudController } from "./controllers/workspace-users"; +import { hasWorkspaceAdminLevel, hasWorkspaceMemberLevel } from "../../../utils/workspace"; +import { WorkspaceInviteTokensCrudController } from "./controllers/workspace-invite-tokens"; +import WorkspaceUser from "../entities/workspace_user"; +import { checkUserBelongsToCompany, hasCompanyMemberLevel } from "../../../utils/company"; +import gr from "../../global-resolver"; +import freeEmailDomains from "free-email-domains"; + +const workspacesUrl = "/companies/:company_id/workspaces"; +const workspacePendingUsersUrl = "/companies/:company_id/workspaces/:workspace_id/pending"; +const workspaceUsersUrl = "/companies/:company_id/workspaces/:workspace_id/users"; +const workspaceInviteTokensUrl = "/companies/:company_id/workspaces/:workspace_id/users/tokens"; + +const routes: FastifyPluginCallback = (fastify: FastifyInstance, options, next) => { + const workspacesController = new WorkspacesCrudController(); + const workspaceUsersController = new WorkspaceUsersCrudController(); + const workspaceInviteTokensController = new WorkspaceInviteTokensCrudController(); + + const accessControl = async () => { + // TODO + const authorized = true; + + if (!authorized) { + throw fastify.httpErrors.badRequest("Invalid company/workspace"); + } + }; + + const companyCheck = async (request: FastifyRequest<{ Params: WorkspaceBaseRequest }>) => { + await checkUserBelongsToCompany(request.currentUser.id, request.params.company_id); + }; + + const checkWorkspace = async (request: FastifyRequest<{ Params: WorkspaceUsersBaseRequest }>) => { + const workspace = await gr.services.workspaces.get({ + company_id: request.params.company_id, + id: request.params.workspace_id, + }); + if (!workspace) { + throw fastify.httpErrors.notFound(`Workspace ${request.params.workspace_id} not found`); + } + }; + + const checkUserWorkspace = async ( + request: FastifyRequest<{ Params: WorkspaceUsersRequest }>, + ): Promise => { + const companyId = request.params.workspace_id; + const workspaceId = request.params.workspace_id; + const userId = request.currentUser.id; + const workspaceUser = await gr.services.workspaces.getUser({ + workspaceId, + userId, + }); + + if (!workspaceUser) { + const workspace = await gr.services.workspaces.get({ + company_id: companyId, + id: workspaceId, + }); + if (!workspace) { + throw fastify.httpErrors.notFound(`Workspace ${workspaceId} not found`); + } else { + throw fastify.httpErrors.forbidden("Not member of the workspace"); + } + } + return workspaceUser; + }; + + const checkUserHasCompanyMemberLevel = async ( + request: FastifyRequest<{ Params: WorkspaceUsersRequest }>, + ) => { + if (!request.currentUser.id) { + throw fastify.httpErrors.forbidden("You must be authenticated"); + } + const companyUser = await gr.services.companies.getCompanyUser( + { id: request.params.company_id }, + { id: request.currentUser.id }, + ); + + if (!hasCompanyMemberLevel(companyUser?.role)) { + throw fastify.httpErrors.forbidden("Only company member can perform this action"); + } + }; + + const checkUserIsWorkspaceAdmin = async ( + request: FastifyRequest<{ Params: WorkspaceUsersRequest }>, + ) => { + if (!request.currentUser.id) { + throw fastify.httpErrors.forbidden("You must be authenticated"); + } + const workspaceUser = await checkUserWorkspace(request); + const companyUser = await gr.services.companies.getCompanyUser( + { id: request.params.company_id }, + { id: request.currentUser.id }, + ); + if (!hasWorkspaceAdminLevel(workspaceUser?.role, companyUser?.role)) { + throw fastify.httpErrors.forbidden("Only workspace moderator can perform this action"); + } + }; + + const checkUserIsWorkspaceMember = async ( + request: FastifyRequest<{ Params: WorkspaceUsersRequest }>, + ) => { + if (!request.currentUser.id) { + throw fastify.httpErrors.forbidden("You must be authenticated"); + } + const workspaceUser = await checkUserWorkspace(request); + const companyUser = await gr.services.companies.getCompanyUser( + { id: request.params.company_id }, + { id: request.currentUser.id }, + ); + if (!hasWorkspaceMemberLevel(workspaceUser?.role, companyUser?.role)) { + throw fastify.httpErrors.forbidden("Only workspace members can perform this action"); + } + }; + + const validateDomain = async ( + request: FastifyRequest<{ Params: WorkspaceRequest; Body: WorkspaceInviteDomainBody }>, + ) => { + const { domain } = request.body; + + if ( + /^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,1}\.(xn--)?([a-z0-9\-]{1,61}|[a-z0-9-]{1,30}\.[a-z]{2,})$/.test( + domain, + ) === false + ) { + throw fastify.httpErrors.badRequest("invalid domain"); + } + + if (freeEmailDomains.includes(domain)) { + throw fastify.httpErrors.badRequest("invalid email provider"); + } + }; + + fastify.route({ + method: "GET", + url: `${workspacesUrl}`, + preHandler: [accessControl, companyCheck], + preValidation: [fastify.authenticate], + schema: getWorkspacesSchema, + handler: workspacesController.list.bind(workspacesController), + }); + + fastify.route({ + method: "GET", + url: `${workspacesUrl}/:id`, + preHandler: [accessControl, companyCheck], + preValidation: [fastify.authenticate], + schema: getWorkspaceSchema, + handler: workspacesController.get.bind(workspacesController), + }); + + fastify.route({ + method: "GET", + url: `${workspacesUrl}/:id/thumbnail`, + handler: workspacesController.thumbnail.bind(workspacesController), + }); + + fastify.route({ + method: "POST", + url: `${workspacesUrl}`, + preHandler: [accessControl, companyCheck], + preValidation: [fastify.authenticate], + schema: createWorkspaceSchema, + handler: workspacesController.save.bind(workspacesController), + }); + + fastify.route({ + method: "POST", + url: `${workspacesUrl}/:id`, + preHandler: [accessControl, companyCheck], + preValidation: [fastify.authenticate], + schema: updateWorkspaceSchema, + handler: workspacesController.save.bind(workspacesController), + }); + + fastify.route({ + method: "DELETE", + url: `${workspacesUrl}/:id`, + preHandler: [accessControl, companyCheck], + preValidation: [fastify.authenticate], + handler: workspacesController.delete.bind(workspacesController), + }); + + fastify.route({ + method: "POST", + url: `${workspacesUrl}/:id/invite_domain`, + preHandler: [validateDomain, companyCheck], + preValidation: [fastify.authenticate], + handler: workspacesController.setInviteDomain.bind(workspacesController), + }); + + fastify.route({ + method: "GET", + url: `${workspaceUsersUrl}`, + preHandler: [accessControl, companyCheck, checkWorkspace], + preValidation: [fastify.authenticate], + schema: getWorkspaceUsersSchema, + handler: workspaceUsersController.list.bind(workspaceUsersController), + }); + + fastify.route({ + method: "GET", + url: `${workspaceUsersUrl}/:user_id`, + preHandler: [accessControl, companyCheck, checkWorkspace], + preValidation: [fastify.authenticate], + schema: getWorkspaceUserSchema, + handler: workspaceUsersController.get.bind(workspaceUsersController), + }); + + fastify.route({ + method: "POST", + url: `${workspaceUsersUrl}`, + preHandler: [accessControl, companyCheck, checkUserIsWorkspaceAdmin], + preValidation: [fastify.authenticate], + schema: createWorkspaceUserSchema, + handler: workspaceUsersController.save.bind(workspaceUsersController), + }); + + fastify.route({ + method: "POST", + url: `${workspaceUsersUrl}/:user_id`, + preHandler: [accessControl, companyCheck, checkUserIsWorkspaceAdmin], + preValidation: [fastify.authenticate], + schema: updateWorkspaceUserSchema, + handler: workspaceUsersController.save.bind(workspaceUsersController), + }); + + fastify.route({ + method: "DELETE", + url: `${workspaceUsersUrl}/:user_id`, + preHandler: [accessControl, companyCheck, checkUserIsWorkspaceAdmin], + preValidation: [fastify.authenticate], + schema: deleteWorkspaceUserSchema, + handler: workspaceUsersController.delete.bind(workspaceUsersController), + }); + + fastify.route({ + method: "POST", + url: `${workspaceUsersUrl}/invite`, + preHandler: [ + accessControl, + companyCheck, + checkUserHasCompanyMemberLevel, + checkUserIsWorkspaceMember, + ], + preValidation: [fastify.authenticate], + schema: inviteWorkspaceUserSchema, + handler: workspaceUsersController.invite.bind(workspaceUsersController), + }); + + fastify.route({ + method: "DELETE", + url: `${workspacePendingUsersUrl}/:email`, + preHandler: [ + accessControl, + companyCheck, + checkUserHasCompanyMemberLevel, + checkUserIsWorkspaceMember, + ], + preValidation: [fastify.authenticate], + schema: deleteWorkspacePendingUsersSchema, + handler: workspaceUsersController.deletePending.bind(workspaceUsersController), + }); + + fastify.route({ + method: "GET", + url: `${workspacePendingUsersUrl}`, + preHandler: [ + accessControl, + companyCheck, + checkUserHasCompanyMemberLevel, + checkUserIsWorkspaceMember, + ], + preValidation: [fastify.authenticate], + schema: getWorkspacePendingUsersSchema, + handler: workspaceUsersController.listPending.bind(workspaceUsersController), + }); + + fastify.route({ + method: "GET", + url: `${workspaceInviteTokensUrl}`, + preHandler: [ + accessControl, + companyCheck, + checkUserIsWorkspaceMember, + checkUserHasCompanyMemberLevel, + ], + preValidation: [fastify.authenticate], + schema: getWorkspaceInviteTokenSchema, + handler: workspaceInviteTokensController.list.bind(workspaceInviteTokensController), + }); + + fastify.route({ + method: "POST", + url: `${workspaceInviteTokensUrl}`, + preHandler: [ + accessControl, + companyCheck, + checkUserIsWorkspaceMember, + checkUserHasCompanyMemberLevel, + ], + preValidation: [fastify.authenticate], + schema: postWorkspaceInviteTokenSchema, + handler: workspaceInviteTokensController.save.bind(workspaceInviteTokensController), + }); + + fastify.route({ + method: "DELETE", + url: `${workspaceInviteTokensUrl}/:token`, + preHandler: [ + accessControl, + companyCheck, + checkUserIsWorkspaceMember, + checkUserHasCompanyMemberLevel, + ], + preValidation: [fastify.authenticate], + schema: deleteWorkspaceInviteTokenSchema, + handler: workspaceInviteTokensController.delete.bind(workspaceInviteTokensController), + }); + + fastify.route({ + method: "POST", + url: "/join", + preHandler: [], + preValidation: [fastify.authenticateOptional], + schema: joinInviteTokenSchema, + handler: workspaceInviteTokensController.join.bind(workspaceInviteTokensController), + }); + + next(); +}; + +export default routes; diff --git a/twake/backend/node/src/services/workspaces/web/schemas.ts b/twake/backend/node/src/services/workspaces/web/schemas.ts new file mode 100644 index 00000000..2e2d9543 --- /dev/null +++ b/twake/backend/node/src/services/workspaces/web/schemas.ts @@ -0,0 +1,376 @@ +import { webSocketSchema } from "../../../utils/types"; +import { companyObjectSchema, userObjectSchema } from "../../user/web/schemas"; + +const workspaceObjectSchema = { + type: "object", + properties: { + id: { type: "string" }, + company_id: { type: "string" }, + name: { type: "string" }, + logo: { type: "string" }, + default: { type: "boolean" }, + archived: { type: "boolean" }, + stats: { + type: "object", + properties: { + created_at: { type: "number" }, + total_members: { type: "number" }, + }, + }, + role: { type: "string", enum: ["moderator", "member"] }, + preferences: { + type: ["object", "null"], + properties: { + invite_domain: { + type: ["string", "null"], + }, + }, + }, + }, +}; + +export const getWorkspacesSchema = { + response: { + "2xx": { + type: "object", + properties: { + resources: { type: "array", items: workspaceObjectSchema }, + websockets: { type: "array", items: webSocketSchema }, + }, + required: ["resources"], + }, + }, +}; + +export const getWorkspaceSchema = { + response: { + "2xx": { + type: "object", + properties: { + resource: workspaceObjectSchema, + }, + required: ["resource"], + }, + }, +}; + +export const createWorkspaceSchema = { + body: { + type: "object", + properties: { + resource: { + type: "object", + properties: { + name: { type: "string" }, + logo: { type: "string" }, + default: { type: "boolean" }, + }, + required: ["name", "logo", "default"], + }, + options: { + type: "object", + properties: { + logo_b64: { type: "string" }, + }, + }, + }, + required: ["resource"], + }, + response: { + "2xx": { + type: "object", + properties: { + resource: workspaceObjectSchema, + }, + required: ["resource"], + }, + }, +}; + +export const updateWorkspaceSchema = { + body: { + type: "object", + properties: { + resource: { + type: "object", + properties: { + name: { type: "string" }, + logo: { type: "string" }, + default: { type: "boolean" }, + archived: { type: "boolean" }, + }, + }, + options: { + type: "object", + properties: { + logo_b64: { type: "string" }, + }, + }, + }, + required: ["resource"], + }, + response: { + "2xx": { + type: "object", + properties: { + resource: workspaceObjectSchema, + }, + required: ["resource"], + }, + }, +}; + +export const deleteWorkspaceSchema = { + response: { + "2xx": { + type: "object", + properties: { + resource: workspaceObjectSchema, + }, + required: ["resource"], + }, + }, +}; + +const workspaceUserObjectSchema = { + type: "object", + properties: { + id: { type: "string" }, + company_id: { type: "string" }, + workspace_id: { type: "string" }, + user_id: { type: "string" }, + created_at: { type: "number" }, + role: { type: "string", enum: ["moderator", "member"] }, + user: userObjectSchema, + }, +}; + +export const getWorkspaceUsersSchema = { + response: { + "2xx": { + type: "object", + properties: { + resources: { type: "array", items: workspaceUserObjectSchema }, + next_page_token: { type: "string" }, + }, + required: ["resources"], + }, + }, +}; + +export const getWorkspaceUserSchema = { + response: { + "2xx": { + type: "object", + properties: { + resource: workspaceUserObjectSchema, + }, + required: ["resource"], + }, + }, +}; + +export const createWorkspaceUserSchema = { + body: { + type: "object", + properties: { + resource: { + type: "object", + properties: { + user_id: { type: "string" }, + role: { type: "string", enum: ["moderator", "member"] }, + }, + required: ["user_id", "role"], + }, + }, + required: ["resource"], + }, + response: { + "2xx": { + type: "object", + properties: { + resource: workspaceUserObjectSchema, + }, + required: ["resource"], + }, + }, +}; + +export const updateWorkspaceUserSchema = { + body: { + type: "object", + properties: { + resource: { + type: "object", + properties: { + role: { type: "string", enum: ["moderator", "member"] }, + }, + required: ["role"], + }, + }, + required: ["resource"], + }, + response: { + "2xx": { + type: "object", + properties: { + resource: workspaceUserObjectSchema, + }, + required: ["resource"], + }, + }, +}; + +export const deleteWorkspaceUserSchema = { + response: { + "2xx": { + type: "object", + // properties: { + // resource: workspaceObjectSchema, + // }, + // required: ["resource"], + }, + }, +}; + +export const inviteWorkspaceUserSchema = { + body: { + type: "object", + properties: { + invitations: { + type: "array", + items: { + type: "object", + properties: { + email: { type: "string" }, + role: { type: "string", enum: ["moderator", "member"] }, + company_role: { type: "string", enum: ["owner", "admin", "member", "guest"] }, + }, + required: ["email", "role", "company_role"], + }, + }, + channels: { + type: "array", + items: { + type: "string", + }, + }, + }, + required: ["invitations"], + }, +}; + +export const getWorkspacePendingUsersSchema = { + response: { + "2xx": { + type: "object", + properties: { + resources: { + type: "array", + items: { + type: "object", + properties: { + email: { type: "string" }, + role: { type: "string", enum: ["moderator", "member"] }, + company_role: { type: "string", enum: ["owner", "admin", "member", "guest"] }, + }, + required: ["email", "role", "company_role"], + }, + }, + }, + required: ["resources"], + }, + }, +}; + +export const deleteWorkspacePendingUsersSchema = { + response: { + "204": {}, + }, +}; + +const workspaceInviteTokenObjectSchema = { + type: "object", + properties: { + token: { type: "string" }, + }, +}; + +export const getWorkspaceInviteTokenSchema = { + response: { + "2xx": { + type: "object", + properties: { + resources: { type: "array", items: workspaceInviteTokenObjectSchema }, + }, + required: ["resources"], + }, + }, +}; + +export const postWorkspaceInviteTokenSchema = { + body: { + type: "object", + properties: { + channels: { + type: "array", + items: { + type: "string", + }, + }, + }, + required: ["channels"], + }, + response: { + "2xx": { + type: "object", + properties: { + resource: workspaceInviteTokenObjectSchema, + }, + required: ["resource"], + }, + }, +}; + +export const deleteWorkspaceInviteTokenSchema = { + response: { + "204": {}, + }, +}; + +export const joinInviteTokenSchema = { + body: { + type: "object", + properties: { + join: { type: "boolean" }, + token: { type: "string" }, + }, + required: ["join", "token"], + }, + response: { + "2xx": { + type: "object", + properties: { + resource: { + type: "object", + properties: { + company: { + type: "object", + properties: { + id: { type: "string" }, + name: { type: "string" }, + plan: companyObjectSchema["properties"]["plan"], + stats: companyObjectSchema["properties"]["stats"], + }, + }, + workspace: { + type: "object", + properties: { id: { type: "string" }, name: { type: "string" } }, + }, + auth_required: { type: "boolean" }, + }, + }, + }, + }, + }, +}; diff --git a/twake/backend/node/src/services/workspaces/web/types.ts b/twake/backend/node/src/services/workspaces/web/types.ts new file mode 100644 index 00000000..8f413496 --- /dev/null +++ b/twake/backend/node/src/services/workspaces/web/types.ts @@ -0,0 +1,153 @@ +import { PaginationQueryParameters, uuid } from "../../../utils/types"; +import { WorkspaceUserRole } from "../types"; +import { + CompanyPlanObject, + CompanyStatsObject, + CompanyUserRole, + UserObject, +} from "../../user/web/types"; +import Company from "../../user/entities/company"; +export interface WorkspaceRequest extends WorkspaceBaseRequest { + id: uuid; +} + +export interface WorkspaceBaseRequest { + company_id: uuid; +} + +export interface WorkspaceUsersBaseRequest extends WorkspaceBaseRequest { + workspace_id: uuid; +} + +export interface WorkspacesListRequest extends WorkspaceBaseRequest, PaginationQueryParameters {} + +export interface WorkspaceUsersRequest extends WorkspaceUsersBaseRequest { + user_id: uuid; +} + +export interface WorkspacePendingUserRequest extends WorkspaceUsersBaseRequest { + email: string; +} + +export interface WorkspaceUsersAddBody { + resource: { + user_id: uuid; + role: WorkspaceUserRole; + }; +} + +export interface WorkspaceUsersInvitationItem { + email: string; + role: WorkspaceUserRole; + company_role: CompanyUserRole; + password?: string; +} + +export interface WorkspaceUsersInvitationRequestBody { + invitations: WorkspaceUsersInvitationItem[]; + channels?: string[]; +} + +export interface WorkspaceUserInvitationResponseItem { + email: string; + status: "ok" | "error"; + message?: string; +} + +export interface WorkspaceUserInvitationResponse { + resources: WorkspaceUserInvitationResponseItem[]; +} + +export type WorkspaceCreateResource = Pick; +export type WorkspaceUpdateResource = Pick< + WorkspaceObject, + "name" | "logo" | "default" | "archived" +>; + +export interface CreateWorkspaceBody { + resource: WorkspaceCreateResource; + options?: { logo_b64?: string }; +} + +export interface UpdateWorkspaceBody { + resource: WorkspaceUpdateResource; + options?: { logo_b64?: string }; +} + +export interface WorkspaceObject { + id: string; + company_id: string; + name: string; + logo: string; + + default: boolean; + archived: boolean; + + stats: { + created_at: number; + total_members: number; + }; + + role?: WorkspaceUserRole; + + preferences: null | { + invite_domain?: string; + }; +} + +export interface WorkspaceUserObject { + id: string; + company_id: string; + workspace_id: string; + user_id: string; + created_at: number; //Timestamp in ms + role: WorkspaceUserRole; + user: UserObject; +} + +export interface WorkspaceInviteTokenGetRequest extends WorkspaceBaseRequest { + workspace_id: uuid; +} + +export interface WorkspaceInviteTokenBody { + channels: string[]; +} + +export interface WorkspaceInviteTokenDeleteRequest extends WorkspaceBaseRequest { + workspace_id: uuid; + token: string; +} + +export interface WorkspaceInviteTokenObject { + token: string; +} + +export interface InviteTokenObject { + c: string; + w: string; + u: string; + t: string; +} + +export interface WorkspaceJoinByTokenRequest extends WorkspaceBaseRequest { + join: boolean; + token: string; +} + +export interface WorkspaceJoinByTokenResponse { + company: { + id?: Company["id"]; + name: Company["name"]; + stats?: CompanyStatsObject; + plan?: CompanyPlanObject; + }; + workspace: { + id?: string; + name: string; + }; + auth_required: boolean; +} + +export interface WorkspaceInviteDomainBody { + domain: string; +} diff --git a/twake/backend/node/src/twake.ts b/twake/backend/node/src/twake.ts new file mode 100644 index 00000000..b07a221e --- /dev/null +++ b/twake/backend/node/src/twake.ts @@ -0,0 +1,62 @@ +import path from "path"; +import { TwakePlatform, TwakePlatformConfiguration } from "./core/platform/platform"; + +import globalResolver from "./services/global-resolver"; + +/** + * Instantiate and start a new TwakePlatform with the given services. + */ +async function run(services: string[] = []): Promise { + let platform: TwakePlatform; + + const start = async (): Promise => { + try { + const configuration: TwakePlatformConfiguration = { + services, + servicesPath: path.resolve(__dirname, "./services/"), + }; + platform = new TwakePlatform(configuration); + await platform.init(); + await platform.start(); + await globalResolver.doInit(platform); + return platform; + } catch (err) { + console.error("Will exit process because of: ", err); + process.exit(-1); + } + }; + + async function stop() { + try { + await platform?.stop(); + } catch (err) { + console.error(err); + } + } + + process.on("uncaughtException", error => { + console.error(error); + }); + + process.on("unhandledRejection", error => { + console.error(error); + }); + + process.on("SIGINT", async () => { + await stop(); + process.kill(process.pid, "SIGUSR2"); + }); + + process.once("SIGUSR2", async () => { + await stop(); + process.kill(process.pid, "SIGUSR2"); + }); + + await start(); + + return platform; +} + +export default { + run, +}; diff --git a/twake/backend/node/src/utils/coalesce.ts b/twake/backend/node/src/utils/coalesce.ts new file mode 100644 index 00000000..30c5f233 --- /dev/null +++ b/twake/backend/node/src/utils/coalesce.ts @@ -0,0 +1,7 @@ +// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types +export default (a: any, b: any): any => { + if (a === undefined) { + return b; + } + return a; +}; diff --git a/twake/backend/node/src/utils/company.ts b/twake/backend/node/src/utils/company.ts new file mode 100644 index 00000000..dc7ef115 --- /dev/null +++ b/twake/backend/node/src/utils/company.ts @@ -0,0 +1,47 @@ +import gr from "../services/global-resolver"; +import CompanyUser from "../services/user/entities/company_user"; + +export function hasCompanyAdminLevel(role: string): boolean { + return role === "admin" || isCompanyOwnerRole(role); +} + +export function hasCompanyMemberLevel(role: string): boolean { + return role === "member" || hasCompanyAdminLevel(role); +} + +export function hasCompanyGuestLevel(role: string): boolean { + return role === "guest" || hasCompanyMemberLevel(role); +} + +export function isCompanyOwnerRole(role: string): boolean { + return role === "owner"; +} + +export function isCompanyAdminRole(role: string): boolean { + return role === "admin"; +} + +export function isCompanyMemberRole(role: string): boolean { + return role === "member"; +} + +export function isCompanyGuestRole(role: string): boolean { + return role === "guest"; +} + +export async function checkUserBelongsToCompany( + userId: string, + companyId: string, +): Promise { + const companyUser = await gr.services.companies.getCompanyUser({ id: companyId }, { id: userId }); + + if (!companyUser) { + const company = await gr.services.companies.getCompany({ id: companyId }); + if (!company) { + throw gr.fastify.httpErrors.notFound(`Company ${companyId} not found`); + } + throw gr.fastify.httpErrors.forbidden("User does not belong to this company"); + } + + return companyUser; +} diff --git a/twake/backend/node/src/utils/counters.ts b/twake/backend/node/src/utils/counters.ts new file mode 100644 index 00000000..8586162a --- /dev/null +++ b/twake/backend/node/src/utils/counters.ts @@ -0,0 +1,23 @@ +import Repository, { + FindFilter, +} from "../core/platform/services/database/services/orm/repository/repository"; +import { ExecutionContext, Pagination } from "../core/platform/framework/api/crud-service"; +import { isMatch } from "lodash"; + +export const countRepositoryItems = async ( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + repository: Repository, + pk: FindFilter, + filter: Record = {}, + context?: ExecutionContext, +): Promise => { + let pagination: Pagination = { limitStr: "100" }; + let total = 0; + do { + const listResult = await repository.find(pk, { pagination }, context); + listResult.filterEntities(a => isMatch(a, filter)); + total += listResult.getEntities().length; + pagination = listResult.nextPage as Pagination; + } while (pagination.page_token); + return total; +}; diff --git a/twake/backend/node/src/utils/files.ts b/twake/backend/node/src/utils/files.ts new file mode 100644 index 00000000..2a24385c --- /dev/null +++ b/twake/backend/node/src/utils/files.ts @@ -0,0 +1,106 @@ +import { mkdirSync, existsSync, promises as fsPromise, createWriteStream, readFileSync } from "fs"; +import { Readable } from "stream"; +import { v4 as uuidv4 } from "uuid"; + +const { unlink } = fsPromise; + +/** + * Generates a random temporary file path + * + * @param {string} suffix - the file extension. + * @returns {string} - the temporary file. + */ +export const getTmpFile = (suffix: string = ""): string => { + const targetDir = "/tmp/"; + mkdirSync(targetDir, { recursive: true }); + return `${targetDir}${uuidv4()}${suffix}`; +}; + +/** + * Removes files from disk + * + * @param {string[]} paths - the paths to be deleted. + */ +export const cleanFiles = async (paths: string[]): Promise => { + for (const path of paths) { + if (existsSync(path)) await unlink(path); + } +}; + +/** + * Writes a File stream into a temporary file path + * + * @param {Readable} input - the input stream. + * @param {string} extension - the file extension. + * @returns {Promise} - the generated file. + */ +export const writeToTemporaryFile = async (input: Readable, extension: string): Promise => { + try { + const temporaryFilePath = getTmpFile(`.${extension}`); + + const writable = createWriteStream(temporaryFilePath); + + input.pipe(writable); + + await new Promise(r => { + writable.on("finish", r); + }); + + writable.end(); + + return temporaryFilePath; + } catch (error) { + console.debug(error); + + throw Error(error); + } +}; + +/** + * Reads a file from the disk + * + * @returns {Promise} - the file readable stream. + */ +export const readFromTemporaryFile = async (path: string): Promise => { + return readFileSync(path); +}; + +/** + * Converts a readable stream into a Buffer. + * + * @param {Readable} input - the input stream. + * @returns {Promise} + */ +export const readableToBuffer = async (input: Readable): Promise => { + return new Promise((resolve, reject) => { + const buffer: Uint8Array[] = []; + + input.on("data", chunk => buffer.push(chunk)); + input.on("end", () => resolve(Buffer.concat(buffer))); + input.on("error", err => reject(err)); + }); +}; + +/** + * Converts a file readable stream to string + * + * @param {Readable} readable - the file stream + * @returns {Promise} + */ +export const readableToString = async (readable: Readable): Promise => { + let content = ""; + + return new Promise((resolve, reject) => { + readable.on("data", data => { + content += data.toString(); + }); + + readable.on("end", () => { + resolve(content); + }); + + readable.on("error", error => { + reject(error); + }); + }); +}; diff --git a/twake/backend/node/src/utils/handleError.ts b/twake/backend/node/src/utils/handleError.ts new file mode 100644 index 00000000..69f83050 --- /dev/null +++ b/twake/backend/node/src/utils/handleError.ts @@ -0,0 +1,12 @@ +import { FastifyReply } from "fastify"; +import { HttpErrorCodes } from "fastify-sensible/lib/httpError"; +import { CrudException } from "../core/platform/framework/api/crud-service"; + +export function handleError(reply: FastifyReply, err: Error): void { + if (err instanceof CrudException) { + const crudException: CrudException = err; + reply.getHttpError(crudException.status as HttpErrorCodes, crudException.message); + } else { + throw err; + } +} diff --git a/twake/backend/node/src/utils/messages.ts b/twake/backend/node/src/utils/messages.ts new file mode 100644 index 00000000..44959d28 --- /dev/null +++ b/twake/backend/node/src/utils/messages.ts @@ -0,0 +1,111 @@ +import _ from "lodash"; +import { ThreadExecutionContext } from "../services/messages/types"; +import { getInstance, Message, MessageReaction } from "../services/messages/entities/messages"; + +export function getSubtype( + item: Pick, + context?: ThreadExecutionContext, +): null | "application" | "deleted" | "system" { + //Application request + if (context?.user?.application_id) { + return item.subtype === "application" || item.subtype === "deleted" ? item.subtype : null; + } + //System request + else if (context?.user?.server_request) { + return item.subtype; + } + + //User cannot set a subtype itself + return null; +} + +export function updateMessageReactions( + message: Message, + selectedReactions: string[], + userId: string, +): void { + const reactions: { [key: string]: MessageReaction } = {}; + for (const reaction of message.reactions || []) { + reactions[reaction.name] = reaction; + } + for (const reaction of selectedReactions) { + reactions[reaction] = reactions[reaction] || { name: reaction, count: 0, users: [] }; + } + for (const key in reactions) { + if (reactions[key].users.includes(userId)) { + reactions[key].count--; + reactions[key].users = reactions[key].users.filter(u => u != userId); + } + if (selectedReactions.includes(key)) { + reactions[key].count++; + reactions[key].users.push(userId); + } + if (reactions[key].count === 0) { + delete reactions[key]; + } + } + + message.reactions = Object.values(reactions); +} + +export function getDefaultMessageInstance( + item: Partial, + context: ThreadExecutionContext, +): Message { + let instance = getInstance({ + id: undefined, + ephemeral: + (context?.user?.application_id || context?.user?.server_request) && item.ephemeral + ? item.ephemeral + : null, + thread_id: (context?.user?.server_request ? item.thread_id : null) || context.thread.id, + type: context?.user?.server_request && item.type === "event" ? "event" : "message", + subtype: getSubtype({ subtype: item?.subtype || null }, context), + created_at: (context?.user?.server_request ? item.created_at : null) || new Date().getTime(), + user_id: + (context?.user?.server_request || context?.user?.application_id ? item.user_id : null) || + context.user.id, + application_id: + (context?.user?.server_request ? item.application_id : null) || + context?.user?.application_id || + null, + text: item.text || "", + blocks: item.blocks || [], + files: item.files || null, + context: item.context || null, + edited: (context?.user?.server_request ? item.edited : null) || null, //Message cannot be created with edition status + pinned_info: item.pinned_info + ? { + pinned_at: new Date().getTime(), + pinned_by: context.user.id, + } + : null, + quote_message: item.quote_message + ? { + channel_id: context.channel.id, + workspace_id: context.workspace.id, + company_id: context.company.id, + ...item.quote_message, + } + : null, + reactions: (context?.user?.server_request ? item.reactions : null) || null, // Reactions cannot be set on creation + bookmarks: (context?.user?.server_request ? item.bookmarks : null) || null, + override: + (context?.user?.application_id || context?.user?.server_request) && item.override + ? { + title: item.override.title, + picture: item.override.picture, + } + : null, // Only apps and server can set an override on a message + status: item.status || "sent", + }); + + if (context.user.server_request) { + instance = _.assign( + instance, + _.pickBy(item, v => v !== undefined), + ); + } + + return instance; +} diff --git a/twake/backend/node/src/utils/mime.ts b/twake/backend/node/src/utils/mime.ts new file mode 100644 index 00000000..57c4bd5b --- /dev/null +++ b/twake/backend/node/src/utils/mime.ts @@ -0,0 +1,1233 @@ +export const officeExtensions = [ + "odp", + "odt", + "ott", + "fodt", + "uot", + "docx", + "dotx", + "xml", + "doc", + "dot", + "html", + "rtf", + "txt", + "docm", + "ods", + "docx", + "docm", + "dotx", + "dotm", + "ods", + "ots", + "fods", + "uos", + "xlsx", + "xltx", + "xls", + "xltx", + "xls", + "xlt", + "dif", + "dbf", + "slk", + "csv", + "xlsm", + "otp", + "odg", + "fodp", + "uop", + "pptx", + "ppsx", + "potx", + "ppt", + "pps", + "pot", + "pptm", +]; +export const pdfExtensions = ["pdf"]; +export const imageExtensions = ["jpeg", "jpg", "png", "webp", "avif", "tiff", "gif", "svg"]; +export const videoExtensions = [ + "mp4", + "webm", + "mkv", + "avi", + "mov", + "flv", + "wmv", + "mpg", + "mpeg", + "m4v", +]; +export const textExtensions = ["txt"]; + +const mimes: any = { + "123": "application/vnd.lotus-1-2-3", + "1km": "application/vnd.1000minds.decision-model+xml", + "3dml": "text/vnd.in3d.3dml", + "3ds": "image/x-3ds", + "3g2": "video/3gpp2", + "3gp": "video/3gpp", + "3gpp": "video/3gpp", + "3mf": "model/3mf", + "7z": "application/x-7z-compressed", + aab: "application/x-authorware-bin", + aac: "audio/x-aac", + aam: "application/x-authorware-map", + aas: "application/x-authorware-seg", + abw: "application/x-abiword", + ac: "application/vnd.nokia.n-gage.ac+xml", + acc: "application/vnd.americandynamics.acc", + ace: "application/x-ace-compressed", + acu: "application/vnd.acucobol", + acutc: "application/vnd.acucorp", + adp: "audio/adpcm", + aep: "application/vnd.audiograph", + afm: "application/x-font-type1", + afp: "application/vnd.ibm.modcap", + ahead: "application/vnd.ahead.space", + ai: "application/postscript", + aif: "audio/x-aiff", + aifc: "audio/x-aiff", + aiff: "audio/x-aiff", + air: "application/vnd.adobe.air-application-installer-package+zip", + ait: "application/vnd.dvb.ait", + ami: "application/vnd.amiga.ami", + amr: "audio/amr", + apk: "application/vnd.android.package-archive", + apng: "image/apng", + appcache: "text/cache-manifest", + application: "application/x-ms-application", + apr: "application/vnd.lotus-approach", + arc: "application/x-freearc", + arj: "application/x-arj", + asc: "application/pgp-signature", + asf: "video/x-ms-asf", + asm: "text/x-asm", + aso: "application/vnd.accpac.simply.aso", + asx: "video/x-ms-asf", + atc: "application/vnd.acucorp", + atom: "application/atom+xml", + atomcat: "application/atomcat+xml", + atomdeleted: "application/atomdeleted+xml", + atomsvc: "application/atomsvc+xml", + atx: "application/vnd.antix.game-component", + au: "audio/basic", + avi: "video/x-msvideo", + avif: "image/avif", + aw: "application/applixware", + azf: "application/vnd.airzip.filesecure.azf", + azs: "application/vnd.airzip.filesecure.azs", + azv: "image/vnd.airzip.accelerator.azv", + azw: "application/vnd.amazon.ebook", + b16: "image/vnd.pco.b16", + bat: "application/x-msdownload", + bcpio: "application/x-bcpio", + bdf: "application/x-font-bdf", + bdm: "application/vnd.syncml.dm+wbxml", + bdoc: "application/x-bdoc", + bed: "application/vnd.realvnc.bed", + bh2: "application/vnd.fujitsu.oasysprs", + bin: "application/octet-stream", + blb: "application/x-blorb", + blorb: "application/x-blorb", + bmi: "application/vnd.bmi", + bmml: "application/vnd.balsamiq.bmml+xml", + bmp: "image/x-ms-bmp", + book: "application/vnd.framemaker", + box: "application/vnd.previewsystems.box", + boz: "application/x-bzip2", + bpk: "application/octet-stream", + bsp: "model/vnd.valve.source.compiled-map", + btif: "image/prs.btif", + buffer: "application/octet-stream", + bz: "application/x-bzip", + bz2: "application/x-bzip2", + c: "text/x-c", + c11amc: "application/vnd.cluetrust.cartomobile-config", + c11amz: "application/vnd.cluetrust.cartomobile-config-pkg", + c4d: "application/vnd.clonk.c4group", + c4f: "application/vnd.clonk.c4group", + c4g: "application/vnd.clonk.c4group", + c4p: "application/vnd.clonk.c4group", + c4u: "application/vnd.clonk.c4group", + cab: "application/vnd.ms-cab-compressed", + caf: "audio/x-caf", + cap: "application/vnd.tcpdump.pcap", + car: "application/vnd.curl.car", + cat: "application/vnd.ms-pki.seccat", + cb7: "application/x-cbr", + cba: "application/x-cbr", + cbr: "application/x-cbr", + cbt: "application/x-cbr", + cbz: "application/x-cbr", + cc: "text/x-c", + cco: "application/x-cocoa", + cct: "application/x-director", + ccxml: "application/ccxml+xml", + cdbcmsg: "application/vnd.contact.cmsg", + cdf: "application/x-netcdf", + cdfx: "application/cdfx+xml", + cdkey: "application/vnd.mediastation.cdkey", + cdmia: "application/cdmi-capability", + cdmic: "application/cdmi-container", + cdmid: "application/cdmi-domain", + cdmio: "application/cdmi-object", + cdmiq: "application/cdmi-queue", + cdx: "chemical/x-cdx", + cdxml: "application/vnd.chemdraw+xml", + cdy: "application/vnd.cinderella", + cer: "application/pkix-cert", + cfs: "application/x-cfs-compressed", + cgm: "image/cgm", + chat: "application/x-chat", + chm: "application/vnd.ms-htmlhelp", + chrt: "application/vnd.kde.kchart", + cif: "chemical/x-cif", + cii: "application/vnd.anser-web-certificate-issue-initiation", + cil: "application/vnd.ms-artgalry", + cjs: "application/node", + cla: "application/vnd.claymore", + class: "application/java-vm", + clkk: "application/vnd.crick.clicker.keyboard", + clkp: "application/vnd.crick.clicker.palette", + clkt: "application/vnd.crick.clicker.template", + clkw: "application/vnd.crick.clicker.wordbank", + clkx: "application/vnd.crick.clicker", + clp: "application/x-msclip", + cmc: "application/vnd.cosmocaller", + cmdf: "chemical/x-cmdf", + cml: "chemical/x-cml", + cmp: "application/vnd.yellowriver-custom-menu", + cmx: "image/x-cmx", + cod: "application/vnd.rim.cod", + coffee: "text/coffeescript", + com: "application/x-msdownload", + conf: "text/plain", + cpio: "application/x-cpio", + cpp: "text/x-c", + cpt: "application/mac-compactpro", + crd: "application/x-mscardfile", + crl: "application/pkix-crl", + crt: "application/x-x509-ca-cert", + crx: "application/x-chrome-extension", + cryptonote: "application/vnd.rig.cryptonote", + csh: "application/x-csh", + csl: "application/vnd.citationstyles.style+xml", + csml: "chemical/x-csml", + csp: "application/vnd.commonspace", + css: "text/css", + cst: "application/x-director", + csv: "text/csv", + cu: "application/cu-seeme", + curl: "text/vnd.curl", + cww: "application/prs.cww", + cxt: "application/x-director", + cxx: "text/x-c", + dae: "model/vnd.collada+xml", + daf: "application/vnd.mobius.daf", + dart: "application/vnd.dart", + dataless: "application/vnd.fdsn.seed", + davmount: "application/davmount+xml", + dbf: "application/vnd.dbf", + dbk: "application/docbook+xml", + dcr: "application/x-director", + dcurl: "text/vnd.curl.dcurl", + dd2: "application/vnd.oma.dd2+xml", + ddd: "application/vnd.fujixerox.ddd", + ddf: "application/vnd.syncml.dmddf+xml", + dds: "image/vnd.ms-dds", + deb: "application/x-debian-package", + def: "text/plain", + deploy: "application/octet-stream", + der: "application/x-x509-ca-cert", + dfac: "application/vnd.dreamfactory", + dgc: "application/x-dgc-compressed", + dic: "text/x-c", + dir: "application/x-director", + dis: "application/vnd.mobius.dis", + "disposition-notification": "message/disposition-notification", + dist: "application/octet-stream", + distz: "application/octet-stream", + djv: "image/vnd.djvu", + djvu: "image/vnd.djvu", + dll: "application/x-msdownload", + dmg: "application/x-apple-diskimage", + dmp: "application/vnd.tcpdump.pcap", + dms: "application/octet-stream", + dna: "application/vnd.dna", + doc: "application/msword", + docm: "application/vnd.ms-word.document.macroenabled.12", + docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + dot: "application/msword", + dotm: "application/vnd.ms-word.template.macroenabled.12", + dotx: "application/vnd.openxmlformats-officedocument.wordprocessingml.template", + dp: "application/vnd.osgi.dp", + dpg: "application/vnd.dpgraph", + dra: "audio/vnd.dra", + drle: "image/dicom-rle", + dsc: "text/prs.lines.tag", + dssc: "application/dssc+der", + dtb: "application/x-dtbook+xml", + dtd: "application/xml-dtd", + dts: "audio/vnd.dts", + dtshd: "audio/vnd.dts.hd", + dump: "application/octet-stream", + dvb: "video/vnd.dvb.file", + dvi: "application/x-dvi", + dwd: "application/atsc-dwd+xml", + dwf: "model/vnd.dwf", + dwg: "image/vnd.dwg", + dxf: "image/vnd.dxf", + dxp: "application/vnd.spotfire.dxp", + dxr: "application/x-director", + ear: "application/java-archive", + ecelp4800: "audio/vnd.nuera.ecelp4800", + ecelp7470: "audio/vnd.nuera.ecelp7470", + ecelp9600: "audio/vnd.nuera.ecelp9600", + ecma: "application/ecmascript", + edm: "application/vnd.novadigm.edm", + edx: "application/vnd.novadigm.edx", + efif: "application/vnd.picsel", + ei6: "application/vnd.pg.osasli", + elc: "application/octet-stream", + emf: "image/emf", + eml: "message/rfc822", + emma: "application/emma+xml", + emotionml: "application/emotionml+xml", + emz: "application/x-msmetafile", + eol: "audio/vnd.digital-winds", + eot: "application/vnd.ms-fontobject", + eps: "application/postscript", + epub: "application/epub+zip", + es: "application/ecmascript", + es3: "application/vnd.eszigno3+xml", + esa: "application/vnd.osgi.subsystem", + esf: "application/vnd.epson.esf", + et3: "application/vnd.eszigno3+xml", + etx: "text/x-setext", + eva: "application/x-eva", + evy: "application/x-envoy", + exe: "application/x-msdownload", + exi: "application/exi", + exr: "image/aces", + ext: "application/vnd.novadigm.ext", + ez: "application/andrew-inset", + ez2: "application/vnd.ezpix-album", + ez3: "application/vnd.ezpix-package", + f: "text/x-fortran", + f4v: "video/x-f4v", + f77: "text/x-fortran", + f90: "text/x-fortran", + fbs: "image/vnd.fastbidsheet", + fcdt: "application/vnd.adobe.formscentral.fcdt", + fcs: "application/vnd.isac.fcs", + fdf: "application/vnd.fdf", + fdt: "application/fdt+xml", + fe_launch: "application/vnd.denovo.fcselayout-link", + fg5: "application/vnd.fujitsu.oasysgp", + fgd: "application/x-director", + fh: "image/x-freehand", + fh4: "image/x-freehand", + fh5: "image/x-freehand", + fh7: "image/x-freehand", + fhc: "image/x-freehand", + fig: "application/x-xfig", + fits: "image/fits", + flac: "audio/x-flac", + fli: "video/x-fli", + flo: "application/vnd.micrografx.flo", + flv: "video/x-flv", + flw: "application/vnd.kde.kivio", + flx: "text/vnd.fmi.flexstor", + fly: "text/vnd.fly", + fm: "application/vnd.framemaker", + fnc: "application/vnd.frogans.fnc", + fo: "application/vnd.software602.filler.form+xml", + for: "text/x-fortran", + fpx: "image/vnd.fpx", + frame: "application/vnd.framemaker", + fsc: "application/vnd.fsc.weblaunch", + fst: "image/vnd.fst", + ftc: "application/vnd.fluxtime.clip", + fti: "application/vnd.anser-web-funds-transfer-initiation", + fvt: "video/vnd.fvt", + fxp: "application/vnd.adobe.fxp", + fxpl: "application/vnd.adobe.fxp", + fzs: "application/vnd.fuzzysheet", + g2w: "application/vnd.geoplan", + g3: "image/g3fax", + g3w: "application/vnd.geospace", + gac: "application/vnd.groove-account", + gam: "application/x-tads", + gbr: "application/rpki-ghostbusters", + gca: "application/x-gca-compressed", + gdl: "model/vnd.gdl", + gdoc: "application/vnd.google-apps.document", + geo: "application/vnd.dynageo", + geojson: "application/geo+json", + gex: "application/vnd.geometry-explorer", + ggb: "application/vnd.geogebra.file", + ggt: "application/vnd.geogebra.tool", + ghf: "application/vnd.groove-help", + gif: "image/gif", + gim: "application/vnd.groove-identity-message", + glb: "model/gltf-binary", + gltf: "model/gltf+json", + gml: "application/gml+xml", + gmx: "application/vnd.gmx", + gnumeric: "application/x-gnumeric", + gph: "application/vnd.flographit", + gpx: "application/gpx+xml", + gqf: "application/vnd.grafeq", + gqs: "application/vnd.grafeq", + gram: "application/srgs", + gramps: "application/x-gramps-xml", + gre: "application/vnd.geometry-explorer", + grv: "application/vnd.groove-injector", + grxml: "application/srgs+xml", + gsf: "application/x-font-ghostscript", + gsheet: "application/vnd.google-apps.spreadsheet", + gslides: "application/vnd.google-apps.presentation", + gtar: "application/x-gtar", + gtm: "application/vnd.groove-tool-message", + gtw: "model/vnd.gtw", + gv: "text/vnd.graphviz", + gxf: "application/gxf", + gxt: "application/vnd.geonext", + gz: "application/gzip", + h: "text/x-c", + h261: "video/h261", + h263: "video/h263", + h264: "video/h264", + hal: "application/vnd.hal+xml", + hbci: "application/vnd.hbci", + hbs: "text/x-handlebars-template", + hdd: "application/x-virtualbox-hdd", + hdf: "application/x-hdf", + heic: "image/heic", + heics: "image/heic-sequence", + heif: "image/heif", + heifs: "image/heif-sequence", + hej2: "image/hej2k", + held: "application/atsc-held+xml", + hh: "text/x-c", + hjson: "application/hjson", + hlp: "application/winhlp", + hpgl: "application/vnd.hp-hpgl", + hpid: "application/vnd.hp-hpid", + hps: "application/vnd.hp-hps", + hqx: "application/mac-binhex40", + hsj2: "image/hsj2", + htc: "text/x-component", + htke: "application/vnd.kenameaapp", + htm: "text/html", + html: "text/html", + hvd: "application/vnd.yamaha.hv-dic", + hvp: "application/vnd.yamaha.hv-voice", + hvs: "application/vnd.yamaha.hv-script", + i2g: "application/vnd.intergeo", + icc: "application/vnd.iccprofile", + ice: "x-conference/x-cooltalk", + icm: "application/vnd.iccprofile", + ico: "image/x-icon", + ics: "text/calendar", + ief: "image/ief", + ifb: "text/calendar", + ifm: "application/vnd.shana.informed.formdata", + iges: "model/iges", + igl: "application/vnd.igloader", + igm: "application/vnd.insors.igm", + igs: "model/iges", + igx: "application/vnd.micrografx.igx", + iif: "application/vnd.shana.informed.interchange", + img: "application/octet-stream", + imp: "application/vnd.accpac.simply.imp", + ims: "application/vnd.ms-ims", + in: "text/plain", + ini: "text/plain", + ink: "application/inkml+xml", + inkml: "application/inkml+xml", + install: "application/x-install-instructions", + iota: "application/vnd.astraea-software.iota", + ipfix: "application/ipfix", + ipk: "application/vnd.shana.informed.package", + irm: "application/vnd.ibm.rights-management", + irp: "application/vnd.irepository.package+xml", + iso: "application/x-iso9660-image", + itp: "application/vnd.shana.informed.formtemplate", + its: "application/its+xml", + ivp: "application/vnd.immervision-ivp", + ivu: "application/vnd.immervision-ivu", + jad: "text/vnd.sun.j2me.app-descriptor", + jade: "text/jade", + jam: "application/vnd.jam", + jar: "application/java-archive", + jardiff: "application/x-java-archive-diff", + java: "text/x-java-source", + jhc: "image/jphc", + jisp: "application/vnd.jisp", + jls: "image/jls", + jlt: "application/vnd.hp-jlyt", + jng: "image/x-jng", + jnlp: "application/x-java-jnlp-file", + joda: "application/vnd.joost.joda-archive", + jp2: "image/jp2", + jpe: "image/jpeg", + jpeg: "image/jpeg", + jpf: "image/jpx", + jpg: "image/jpeg", + jpg2: "image/jp2", + jpgm: "video/jpm", + jpgv: "video/jpeg", + jph: "image/jph", + jpm: "video/jpm", + jpx: "image/jpx", + js: "application/javascript", + json: "application/json", + json5: "application/json5", + jsonld: "application/ld+json", + jsonml: "application/jsonml+json", + jsx: "text/jsx", + jxr: "image/jxr", + jxra: "image/jxra", + jxrs: "image/jxrs", + jxs: "image/jxs", + jxsc: "image/jxsc", + jxsi: "image/jxsi", + jxss: "image/jxss", + kar: "audio/midi", + karbon: "application/vnd.kde.karbon", + kdbx: "application/x-keepass2", + key: "application/vnd.apple.keynote", + kfo: "application/vnd.kde.kformula", + kia: "application/vnd.kidspiration", + kml: "application/vnd.google-earth.kml+xml", + kmz: "application/vnd.google-earth.kmz", + kne: "application/vnd.kinar", + knp: "application/vnd.kinar", + kon: "application/vnd.kde.kontour", + kpr: "application/vnd.kde.kpresenter", + kpt: "application/vnd.kde.kpresenter", + kpxx: "application/vnd.ds-keypoint", + ksp: "application/vnd.kde.kspread", + ktr: "application/vnd.kahootz", + ktx: "image/ktx", + ktx2: "image/ktx2", + ktz: "application/vnd.kahootz", + kwd: "application/vnd.kde.kword", + kwt: "application/vnd.kde.kword", + lasxml: "application/vnd.las.las+xml", + latex: "application/x-latex", + lbd: "application/vnd.llamagraphics.life-balance.desktop", + lbe: "application/vnd.llamagraphics.life-balance.exchange+xml", + les: "application/vnd.hhe.lesson-player", + less: "text/less", + lgr: "application/lgr+xml", + lha: "application/x-lzh-compressed", + link66: "application/vnd.route66.link66+xml", + list: "text/plain", + list3820: "application/vnd.ibm.modcap", + listafp: "application/vnd.ibm.modcap", + litcoffee: "text/coffeescript", + lnk: "application/x-ms-shortcut", + log: "text/plain", + lostxml: "application/lost+xml", + lrf: "application/octet-stream", + lrm: "application/vnd.ms-lrm", + ltf: "application/vnd.frogans.ltf", + lua: "text/x-lua", + luac: "application/x-lua-bytecode", + lvp: "audio/vnd.lucent.voice", + lwp: "application/vnd.lotus-wordpro", + lzh: "application/x-lzh-compressed", + m13: "application/x-msmediaview", + m14: "application/x-msmediaview", + m1v: "video/mpeg", + m21: "application/mp21", + m2a: "audio/mpeg", + m2v: "video/mpeg", + m3a: "audio/mpeg", + m3u: "audio/x-mpegurl", + m3u8: "application/vnd.apple.mpegurl", + m4a: "audio/x-m4a", + m4p: "application/mp4", + m4s: "video/iso.segment", + m4u: "video/vnd.mpegurl", + m4v: "video/x-m4v", + ma: "application/mathematica", + mads: "application/mads+xml", + maei: "application/mmt-aei+xml", + mag: "application/vnd.ecowin.chart", + maker: "application/vnd.framemaker", + man: "text/troff", + manifest: "text/cache-manifest", + map: "application/json", + mar: "application/octet-stream", + markdown: "text/markdown", + mathml: "application/mathml+xml", + mb: "application/mathematica", + mbk: "application/vnd.mobius.mbk", + mbox: "application/mbox", + mc1: "application/vnd.medcalcdata", + mcd: "application/vnd.mcd", + mcurl: "text/vnd.curl.mcurl", + md: "text/markdown", + mdb: "application/x-msaccess", + mdi: "image/vnd.ms-modi", + mdx: "text/mdx", + me: "text/troff", + mesh: "model/mesh", + meta4: "application/metalink4+xml", + metalink: "application/metalink+xml", + mets: "application/mets+xml", + mfm: "application/vnd.mfmp", + mft: "application/rpki-manifest", + mgp: "application/vnd.osgeo.mapguide.package", + mgz: "application/vnd.proteus.magazine", + mid: "audio/midi", + midi: "audio/midi", + mie: "application/x-mie", + mif: "application/vnd.mif", + mime: "message/rfc822", + mj2: "video/mj2", + mjp2: "video/mj2", + mjs: "application/javascript", + mk3d: "video/x-matroska", + mka: "audio/x-matroska", + mkd: "text/x-markdown", + mks: "video/x-matroska", + mkv: "video/x-matroska", + mlp: "application/vnd.dolby.mlp", + mmd: "application/vnd.chipnuts.karaoke-mmd", + mmf: "application/vnd.smaf", + mml: "text/mathml", + mmr: "image/vnd.fujixerox.edmics-mmr", + mng: "video/x-mng", + mny: "application/x-msmoney", + mobi: "application/x-mobipocket-ebook", + mods: "application/mods+xml", + mov: "video/quicktime", + movie: "video/x-sgi-movie", + mp2: "audio/mpeg", + mp21: "application/mp21", + mp2a: "audio/mpeg", + mp3: "audio/mpeg", + mp4: "video/mp4", + mp4a: "audio/mp4", + mp4s: "application/mp4", + mp4v: "video/mp4", + mpc: "application/vnd.mophun.certificate", + mpd: "application/dash+xml", + mpe: "video/mpeg", + mpeg: "video/mpeg", + mpg: "video/mpeg", + mpg4: "video/mp4", + mpga: "audio/mpeg", + mpkg: "application/vnd.apple.installer+xml", + mpm: "application/vnd.blueice.multipass", + mpn: "application/vnd.mophun.application", + mpp: "application/vnd.ms-project", + mpt: "application/vnd.ms-project", + mpy: "application/vnd.ibm.minipay", + mqy: "application/vnd.mobius.mqy", + mrc: "application/marc", + mrcx: "application/marcxml+xml", + ms: "text/troff", + mscml: "application/mediaservercontrol+xml", + mseed: "application/vnd.fdsn.mseed", + mseq: "application/vnd.mseq", + msf: "application/vnd.epson.msf", + msg: "application/vnd.ms-outlook", + msh: "model/mesh", + msi: "application/x-msdownload", + msl: "application/vnd.mobius.msl", + msm: "application/octet-stream", + msp: "application/octet-stream", + msty: "application/vnd.muvee.style", + mtl: "model/mtl", + mts: "model/vnd.mts", + mus: "application/vnd.musician", + musd: "application/mmt-usd+xml", + musicxml: "application/vnd.recordare.musicxml+xml", + mvb: "application/x-msmediaview", + mwf: "application/vnd.mfer", + mxf: "application/mxf", + mxl: "application/vnd.recordare.musicxml", + mxmf: "audio/mobile-xmf", + mxml: "application/xv+xml", + mxs: "application/vnd.triscape.mxs", + mxu: "video/vnd.mpegurl", + "n-gage": "application/vnd.nokia.n-gage.symbian.install", + n3: "text/n3", + nb: "application/mathematica", + nbp: "application/vnd.wolfram.player", + nc: "application/x-netcdf", + ncx: "application/x-dtbncx+xml", + nfo: "text/x-nfo", + ngdat: "application/vnd.nokia.n-gage.data", + nitf: "application/vnd.nitf", + nlu: "application/vnd.neurolanguage.nlu", + nml: "application/vnd.enliven", + nnd: "application/vnd.noblenet-directory", + nns: "application/vnd.noblenet-sealer", + nnw: "application/vnd.noblenet-web", + npx: "image/vnd.net-fpx", + nq: "application/n-quads", + nsc: "application/x-conference", + nsf: "application/vnd.lotus-notes", + nt: "application/n-triples", + ntf: "application/vnd.nitf", + numbers: "application/vnd.apple.numbers", + nzb: "application/x-nzb", + oa2: "application/vnd.fujitsu.oasys2", + oa3: "application/vnd.fujitsu.oasys3", + oas: "application/vnd.fujitsu.oasys", + obd: "application/x-msbinder", + obgx: "application/vnd.openblox.game+xml", + obj: "model/obj", + oda: "application/oda", + odb: "application/vnd.oasis.opendocument.database", + odc: "application/vnd.oasis.opendocument.chart", + odf: "application/vnd.oasis.opendocument.formula", + odft: "application/vnd.oasis.opendocument.formula-template", + odg: "application/vnd.oasis.opendocument.graphics", + odi: "application/vnd.oasis.opendocument.image", + odm: "application/vnd.oasis.opendocument.text-master", + odp: "application/vnd.oasis.opendocument.presentation", + ods: "application/vnd.oasis.opendocument.spreadsheet", + odt: "application/vnd.oasis.opendocument.text", + oga: "audio/ogg", + ogex: "model/vnd.opengex", + ogg: "audio/ogg", + ogv: "video/ogg", + ogx: "application/ogg", + omdoc: "application/omdoc+xml", + onepkg: "application/onenote", + onetmp: "application/onenote", + onetoc: "application/onenote", + onetoc2: "application/onenote", + opf: "application/oebps-package+xml", + opml: "text/x-opml", + oprc: "application/vnd.palm", + opus: "audio/ogg", + org: "text/x-org", + osf: "application/vnd.yamaha.openscoreformat", + osfpvg: "application/vnd.yamaha.openscoreformat.osfpvg+xml", + osm: "application/vnd.openstreetmap.data+xml", + otc: "application/vnd.oasis.opendocument.chart-template", + otf: "font/otf", + otg: "application/vnd.oasis.opendocument.graphics-template", + oth: "application/vnd.oasis.opendocument.text-web", + oti: "application/vnd.oasis.opendocument.image-template", + otp: "application/vnd.oasis.opendocument.presentation-template", + ots: "application/vnd.oasis.opendocument.spreadsheet-template", + ott: "application/vnd.oasis.opendocument.text-template", + ova: "application/x-virtualbox-ova", + ovf: "application/x-virtualbox-ovf", + owl: "application/rdf+xml", + oxps: "application/oxps", + oxt: "application/vnd.openofficeorg.extension", + p: "text/x-pascal", + p10: "application/pkcs10", + p12: "application/x-pkcs12", + p7b: "application/x-pkcs7-certificates", + p7c: "application/pkcs7-mime", + p7m: "application/pkcs7-mime", + p7r: "application/x-pkcs7-certreqresp", + p7s: "application/pkcs7-signature", + p8: "application/pkcs8", + pac: "application/x-ns-proxy-autoconfig", + pages: "application/vnd.apple.pages", + pas: "text/x-pascal", + paw: "application/vnd.pawaafile", + pbd: "application/vnd.powerbuilder6", + pbm: "image/x-portable-bitmap", + pcap: "application/vnd.tcpdump.pcap", + pcf: "application/x-font-pcf", + pcl: "application/vnd.hp-pcl", + pclxl: "application/vnd.hp-pclxl", + pct: "image/x-pict", + pcurl: "application/vnd.curl.pcurl", + pcx: "image/x-pcx", + pdb: "application/x-pilot", + pde: "text/x-processing", + pdf: "application/pdf", + pem: "application/x-x509-ca-cert", + pfa: "application/x-font-type1", + pfb: "application/x-font-type1", + pfm: "application/x-font-type1", + pfr: "application/font-tdpfr", + pfx: "application/x-pkcs12", + pgm: "image/x-portable-graymap", + pgn: "application/x-chess-pgn", + pgp: "application/pgp-encrypted", + php: "application/x-httpd-php", + pic: "image/x-pict", + pkg: "application/octet-stream", + pki: "application/pkixcmp", + pkipath: "application/pkix-pkipath", + pkpass: "application/vnd.apple.pkpass", + pl: "application/x-perl", + plb: "application/vnd.3gpp.pic-bw-large", + plc: "application/vnd.mobius.plc", + plf: "application/vnd.pocketlearn", + pls: "application/pls+xml", + pm: "application/x-perl", + pml: "application/vnd.ctc-posml", + png: "image/png", + pnm: "image/x-portable-anymap", + portpkg: "application/vnd.macports.portpkg", + pot: "application/vnd.ms-powerpoint", + potm: "application/vnd.ms-powerpoint.template.macroenabled.12", + potx: "application/vnd.openxmlformats-officedocument.presentationml.template", + ppam: "application/vnd.ms-powerpoint.addin.macroenabled.12", + ppd: "application/vnd.cups-ppd", + ppm: "image/x-portable-pixmap", + pps: "application/vnd.ms-powerpoint", + ppsm: "application/vnd.ms-powerpoint.slideshow.macroenabled.12", + ppsx: "application/vnd.openxmlformats-officedocument.presentationml.slideshow", + ppt: "application/vnd.ms-powerpoint", + pptm: "application/vnd.ms-powerpoint.presentation.macroenabled.12", + pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation", + pqa: "application/vnd.palm", + prc: "application/x-pilot", + pre: "application/vnd.lotus-freelance", + prf: "application/pics-rules", + provx: "application/provenance+xml", + ps: "application/postscript", + psb: "application/vnd.3gpp.pic-bw-small", + psd: "image/vnd.adobe.photoshop", + psf: "application/x-font-linux-psf", + pskcxml: "application/pskc+xml", + pti: "image/prs.pti", + ptid: "application/vnd.pvi.ptid1", + pub: "application/x-mspublisher", + pvb: "application/vnd.3gpp.pic-bw-var", + pwn: "application/vnd.3m.post-it-notes", + pya: "audio/vnd.ms-playready.media.pya", + pyv: "video/vnd.ms-playready.media.pyv", + qam: "application/vnd.epson.quickanime", + qbo: "application/vnd.intu.qbo", + qfx: "application/vnd.intu.qfx", + qps: "application/vnd.publishare-delta-tree", + qt: "video/quicktime", + qwd: "application/vnd.quark.quarkxpress", + qwt: "application/vnd.quark.quarkxpress", + qxb: "application/vnd.quark.quarkxpress", + qxd: "application/vnd.quark.quarkxpress", + qxl: "application/vnd.quark.quarkxpress", + qxt: "application/vnd.quark.quarkxpress", + ra: "audio/x-realaudio", + ram: "audio/x-pn-realaudio", + raml: "application/raml+yaml", + rapd: "application/route-apd+xml", + rar: "application/x-rar-compressed", + ras: "image/x-cmu-raster", + rcprofile: "application/vnd.ipunplugged.rcprofile", + rdf: "application/rdf+xml", + rdz: "application/vnd.data-vision.rdz", + relo: "application/p2p-overlay+xml", + rep: "application/vnd.businessobjects", + res: "application/x-dtbresource+xml", + rgb: "image/x-rgb", + rif: "application/reginfo+xml", + rip: "audio/vnd.rip", + ris: "application/x-research-info-systems", + rl: "application/resource-lists+xml", + rlc: "image/vnd.fujixerox.edmics-rlc", + rld: "application/resource-lists-diff+xml", + rm: "application/vnd.rn-realmedia", + rmi: "audio/midi", + rmp: "audio/x-pn-realaudio-plugin", + rms: "application/vnd.jcp.javame.midlet-rms", + rmvb: "application/vnd.rn-realmedia-vbr", + rnc: "application/relax-ng-compact-syntax", + rng: "application/xml", + roa: "application/rpki-roa", + roff: "text/troff", + rp9: "application/vnd.cloanto.rp9", + rpm: "application/x-redhat-package-manager", + rpss: "application/vnd.nokia.radio-presets", + rpst: "application/vnd.nokia.radio-preset", + rq: "application/sparql-query", + rs: "application/rls-services+xml", + rsat: "application/atsc-rsat+xml", + rsd: "application/rsd+xml", + rsheet: "application/urc-ressheet+xml", + rss: "application/rss+xml", + rtf: "text/rtf", + rtx: "text/richtext", + run: "application/x-makeself", + rusd: "application/route-usd+xml", + s: "text/x-asm", + s3m: "audio/s3m", + saf: "application/vnd.yamaha.smaf-audio", + sass: "text/x-sass", + sbml: "application/sbml+xml", + sc: "application/vnd.ibm.secure-container", + scd: "application/x-msschedule", + scm: "application/vnd.lotus-screencam", + scq: "application/scvp-cv-request", + scs: "application/scvp-cv-response", + scss: "text/x-scss", + scurl: "text/vnd.curl.scurl", + sda: "application/vnd.stardivision.draw", + sdc: "application/vnd.stardivision.calc", + sdd: "application/vnd.stardivision.impress", + sdkd: "application/vnd.solent.sdkm+xml", + sdkm: "application/vnd.solent.sdkm+xml", + sdp: "application/sdp", + sdw: "application/vnd.stardivision.writer", + sea: "application/x-sea", + see: "application/vnd.seemail", + seed: "application/vnd.fdsn.seed", + sema: "application/vnd.sema", + semd: "application/vnd.semd", + semf: "application/vnd.semf", + senmlx: "application/senml+xml", + sensmlx: "application/sensml+xml", + ser: "application/java-serialized-object", + setpay: "application/set-payment-initiation", + setreg: "application/set-registration-initiation", + "sfd-hdstx": "application/vnd.hydrostatix.sof-data", + sfs: "application/vnd.spotfire.sfs", + sfv: "text/x-sfv", + sgi: "image/sgi", + sgl: "application/vnd.stardivision.writer-global", + sgm: "text/sgml", + sgml: "text/sgml", + sh: "application/x-sh", + shar: "application/x-shar", + shex: "text/shex", + shf: "application/shf+xml", + shtml: "text/html", + sid: "image/x-mrsid-image", + sieve: "application/sieve", + sig: "application/pgp-signature", + sil: "audio/silk", + silo: "model/mesh", + sis: "application/vnd.symbian.install", + sisx: "application/vnd.symbian.install", + sit: "application/x-stuffit", + sitx: "application/x-stuffitx", + siv: "application/sieve", + skd: "application/vnd.koan", + skm: "application/vnd.koan", + skp: "application/vnd.koan", + skt: "application/vnd.koan", + sldm: "application/vnd.ms-powerpoint.slide.macroenabled.12", + sldx: "application/vnd.openxmlformats-officedocument.presentationml.slide", + slim: "text/slim", + slm: "text/slim", + sls: "application/route-s-tsid+xml", + slt: "application/vnd.epson.salt", + sm: "application/vnd.stepmania.stepchart", + smf: "application/vnd.stardivision.math", + smi: "application/smil+xml", + smil: "application/smil+xml", + smv: "video/x-smv", + smzip: "application/vnd.stepmania.package", + snd: "audio/basic", + snf: "application/x-font-snf", + so: "application/octet-stream", + spc: "application/x-pkcs7-certificates", + spdx: "text/spdx", + spf: "application/vnd.yamaha.smaf-phrase", + spl: "application/x-futuresplash", + spot: "text/vnd.in3d.spot", + spp: "application/scvp-vp-response", + spq: "application/scvp-vp-request", + spx: "audio/ogg", + sql: "application/x-sql", + src: "application/x-wais-source", + srt: "application/x-subrip", + sru: "application/sru+xml", + srx: "application/sparql-results+xml", + ssdl: "application/ssdl+xml", + sse: "application/vnd.kodak-descriptor", + ssf: "application/vnd.epson.ssf", + ssml: "application/ssml+xml", + st: "application/vnd.sailingtracker.track", + stc: "application/vnd.sun.xml.calc.template", + std: "application/vnd.sun.xml.draw.template", + stf: "application/vnd.wt.stf", + sti: "application/vnd.sun.xml.impress.template", + stk: "application/hyperstudio", + stl: "model/stl", + str: "application/vnd.pg.format", + stw: "application/vnd.sun.xml.writer.template", + styl: "text/stylus", + stylus: "text/stylus", + sub: "text/vnd.dvb.subtitle", + sus: "application/vnd.sus-calendar", + susp: "application/vnd.sus-calendar", + sv4cpio: "application/x-sv4cpio", + sv4crc: "application/x-sv4crc", + svc: "application/vnd.dvb.service", + svd: "application/vnd.svd", + svg: "image/svg+xml", + svgz: "image/svg+xml", + swa: "application/x-director", + swf: "application/x-shockwave-flash", + swi: "application/vnd.aristanetworks.swi", + swidtag: "application/swid+xml", + sxc: "application/vnd.sun.xml.calc", + sxd: "application/vnd.sun.xml.draw", + sxg: "application/vnd.sun.xml.writer.global", + sxi: "application/vnd.sun.xml.impress", + sxm: "application/vnd.sun.xml.math", + sxw: "application/vnd.sun.xml.writer", + t: "text/troff", + t3: "application/x-t3vm-image", + t38: "image/t38", + taglet: "application/vnd.mynfc", + tao: "application/vnd.tao.intent-module-archive", + tap: "image/vnd.tencent.tap", + tar: "application/x-tar", + tcap: "application/vnd.3gpp2.tcap", + tcl: "application/x-tcl", + td: "application/urc-targetdesc+xml", + teacher: "application/vnd.smart.teacher", + tei: "application/tei+xml", + teicorpus: "application/tei+xml", + tex: "application/x-tex", + texi: "application/x-texinfo", + texinfo: "application/x-texinfo", + text: "text/plain", + tfi: "application/thraud+xml", + tfm: "application/x-tex-tfm", + tfx: "image/tiff-fx", + tga: "image/x-tga", + thmx: "application/vnd.ms-officetheme", + tif: "image/tiff", + tiff: "image/tiff", + tk: "application/x-tcl", + tmo: "application/vnd.tmobile-livetv", + toml: "application/toml", + torrent: "application/x-bittorrent", + tpl: "application/vnd.groove-tool-template", + tpt: "application/vnd.trid.tpt", + tr: "text/troff", + tra: "application/vnd.trueapp", + trm: "application/x-msterminal", + ts: "video/mp2t", + tsd: "application/timestamped-data", + tsv: "text/tab-separated-values", + ttc: "font/collection", + ttf: "font/ttf", + ttl: "text/turtle", + ttml: "application/ttml+xml", + twd: "application/vnd.simtech-mindmapper", + twds: "application/vnd.simtech-mindmapper", + txd: "application/vnd.genomatix.tuxedo", + txf: "application/vnd.mobius.txf", + txt: "text/plain", + u32: "application/x-authorware-bin", + u8dsn: "message/global-delivery-status", + u8hdr: "message/global-headers", + u8mdn: "message/global-disposition-notification", + u8msg: "message/global", + ubj: "application/ubjson", + udeb: "application/x-debian-package", + ufd: "application/vnd.ufdl", + ufdl: "application/vnd.ufdl", + ulx: "application/x-glulx", + umj: "application/vnd.umajin", + unityweb: "application/vnd.unity", + uoml: "application/vnd.uoml+xml", + uri: "text/uri-list", + uris: "text/uri-list", + urls: "text/uri-list", + usdz: "model/vnd.usdz+zip", + ustar: "application/x-ustar", + utz: "application/vnd.uiq.theme", + uu: "text/x-uuencode", + uva: "audio/vnd.dece.audio", + uvd: "application/vnd.dece.data", + uvf: "application/vnd.dece.data", + uvg: "image/vnd.dece.graphic", + uvh: "video/vnd.dece.hd", + uvi: "image/vnd.dece.graphic", + uvm: "video/vnd.dece.mobile", + uvp: "video/vnd.dece.pd", + uvs: "video/vnd.dece.sd", + uvt: "application/vnd.dece.ttml+xml", + uvu: "video/vnd.uvvu.mp4", + uvv: "video/vnd.dece.video", + uvva: "audio/vnd.dece.audio", + uvvd: "application/vnd.dece.data", + uvvf: "application/vnd.dece.data", + uvvg: "image/vnd.dece.graphic", + uvvh: "video/vnd.dece.hd", + uvvi: "image/vnd.dece.graphic", + uvvm: "video/vnd.dece.mobile", + uvvp: "video/vnd.dece.pd", + uvvs: "video/vnd.dece.sd", + uvvt: "application/vnd.dece.ttml+xml", + uvvu: "video/vnd.uvvu.mp4", + uvvv: "video/vnd.dece.video", + uvvx: "application/vnd.dece.unspecified", + uvvz: "application/vnd.dece.zip", + uvx: "application/vnd.dece.unspecified", + uvz: "application/vnd.dece.zip", + vbox: "application/x-virtualbox-vbox", + "vbox-extpack": "application/x-virtualbox-vbox-extpack", + vcard: "text/vcard", + vcd: "application/x-cdlink", + vcf: "text/x-vcard", + vcg: "application/vnd.groove-vcard", + vcs: "text/x-vcalendar", + vcx: "application/vnd.vcx", + vdi: "application/x-virtualbox-vdi", + vhd: "application/x-virtualbox-vhd", + vis: "application/vnd.visionary", + viv: "video/vnd.vivo", + vmdk: "application/x-virtualbox-vmdk", + vob: "video/x-ms-vob", + vor: "application/vnd.stardivision.writer", + vox: "application/x-authorware-bin", + vrml: "model/vrml", + vsd: "application/vnd.visio", + vsf: "application/vnd.vsf", + vss: "application/vnd.visio", + vst: "application/vnd.visio", + vsw: "application/vnd.visio", + vtf: "image/vnd.valve.source.texture", + vtt: "text/vtt", + vtu: "model/vnd.vtu", + vxml: "application/voicexml+xml", + w3d: "application/x-director", + wad: "application/x-doom", + wadl: "application/vnd.sun.wadl+xml", + war: "application/java-archive", + wasm: "application/wasm", + wav: "audio/x-wav", + wax: "audio/x-ms-wax", + wbmp: "image/vnd.wap.wbmp", + wbs: "application/vnd.criticaltools.wbs+xml", + wbxml: "application/vnd.wap.wbxml", + wcm: "application/vnd.ms-works", + wdb: "application/vnd.ms-works", + wdp: "image/vnd.ms-photo", + weba: "audio/webm", + webapp: "application/x-web-app-manifest+json", + webm: "video/webm", + webmanifest: "application/manifest+json", + webp: "image/webp", + wg: "application/vnd.pmi.widget", + wgt: "application/widget", + wks: "application/vnd.ms-works", + wm: "video/x-ms-wm", + wma: "audio/x-ms-wma", + wmd: "application/x-ms-wmd", + wmf: "image/wmf", + wml: "text/vnd.wap.wml", + wmlc: "application/vnd.wap.wmlc", + wmls: "text/vnd.wap.wmlscript", + wmlsc: "application/vnd.wap.wmlscriptc", + wmv: "video/x-ms-wmv", + wmx: "video/x-ms-wmx", + wmz: "application/x-msmetafile", + woff: "font/woff", + woff2: "font/woff2", + wpd: "application/vnd.wordperfect", + wpl: "application/vnd.ms-wpl", + wps: "application/vnd.ms-works", + wqd: "application/vnd.wqd", + wri: "application/x-mswrite", + wrl: "model/vrml", + wsc: "message/vnd.wfa.wsc", + wsdl: "application/wsdl+xml", + wspolicy: "application/wspolicy+xml", + wtb: "application/vnd.webturbo", + wvx: "video/x-ms-wvx", + x32: "application/x-authorware-bin", + x3d: "model/x3d+xml", + x3db: "model/x3d+fastinfoset", + x3dbz: "model/x3d+binary", + x3dv: "model/x3d-vrml", + x3dvz: "model/x3d+vrml", + x3dz: "model/x3d+xml", + x_b: "model/vnd.parasolid.transmit.binary", + x_t: "model/vnd.parasolid.transmit.text", + xaml: "application/xaml+xml", + xap: "application/x-silverlight-app", + xar: "application/vnd.xara", + xav: "application/xcap-att+xml", + xbap: "application/x-ms-xbap", + xbd: "application/vnd.fujixerox.docuworks.binder", + xbm: "image/x-xbitmap", + xca: "application/xcap-caps+xml", + xcs: "application/calendar+xml", + xdf: "application/xcap-diff+xml", + xdm: "application/vnd.syncml.dm+xml", + xdp: "application/vnd.adobe.xdp+xml", + xdssc: "application/dssc+xml", + xdw: "application/vnd.fujixerox.docuworks", + xel: "application/xcap-el+xml", + xenc: "application/xenc+xml", + xer: "application/patch-ops-error+xml", + xfdf: "application/vnd.adobe.xfdf", + xfdl: "application/vnd.xfdl", + xht: "application/xhtml+xml", + xhtml: "application/xhtml+xml", + xhvml: "application/xv+xml", + xif: "image/vnd.xiff", + xla: "application/vnd.ms-excel", + xlam: "application/vnd.ms-excel.addin.macroenabled.12", + xlc: "application/vnd.ms-excel", + xlf: "application/xliff+xml", + xlm: "application/vnd.ms-excel", + xls: "application/vnd.ms-excel", + xlsb: "application/vnd.ms-excel.sheet.binary.macroenabled.12", + xlsm: "application/vnd.ms-excel.sheet.macroenabled.12", + xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + xlt: "application/vnd.ms-excel", + xltm: "application/vnd.ms-excel.template.macroenabled.12", + xltx: "application/vnd.openxmlformats-officedocument.spreadsheetml.template", + xlw: "application/vnd.ms-excel", + xm: "audio/xm", + xml: "text/xml", + xns: "application/xcap-ns+xml", + xo: "application/vnd.olpc-sugar", + xop: "application/xop+xml", + xpi: "application/x-xpinstall", + xpl: "application/xproc+xml", + xpm: "image/x-xpixmap", + xpr: "application/vnd.is-xpr", + xps: "application/vnd.ms-xpsdocument", + xpw: "application/vnd.intercon.formnet", + xpx: "application/vnd.intercon.formnet", + xsd: "application/xml", + xsl: "application/xslt+xml", + xslt: "application/xslt+xml", + xsm: "application/vnd.syncml+xml", + xspf: "application/xspf+xml", + xul: "application/vnd.mozilla.xul+xml", + xvm: "application/xv+xml", + xvml: "application/xv+xml", + xwd: "image/x-xwindowdump", + xyz: "chemical/x-xyz", + xz: "application/x-xz", + yaml: "text/yaml", + yang: "application/yang", + yin: "application/yin+xml", + yml: "text/yaml", + ymp: "text/x-suse-ymp", + z1: "application/x-zmachine", + z2: "application/x-zmachine", + z3: "application/x-zmachine", + z4: "application/x-zmachine", + z5: "application/x-zmachine", + z6: "application/x-zmachine", + z7: "application/x-zmachine", + z8: "application/x-zmachine", + zaz: "application/vnd.zzazz.deck+xml", + zip: "application/zip", + zir: "application/vnd.zul", + zirz: "application/vnd.zul", + zmm: "application/vnd.handheld-entertainment+xml", +}; + +export default mimes; diff --git a/twake/backend/node/src/utils/password-encoder.ts b/twake/backend/node/src/utils/password-encoder.ts new file mode 100644 index 00000000..df2ce45d --- /dev/null +++ b/twake/backend/node/src/utils/password-encoder.ts @@ -0,0 +1,82 @@ +import { CrudException } from "../core/platform/framework/api/crud-service"; +import crypto from "crypto"; +import assert from "assert"; +import bcrypt from "bcrypt"; + +export default class { + private readonly algorithm = "sha512"; + private readonly encodeHashAsBase64 = true; + private readonly iterations = 5000; + private readonly encodedLength: number; + + constructor() { + this.encodedLength = this.encodePasswordOldWay("", "salt").length; + } + + protected mergePasswordAndSalt(password: string, salt?: string): string { + if (!salt) { + return password; + } + + return password + "{" + salt + "}"; + } + + protected isPasswordTooLong(password: string): boolean { + return password.length > 4096; + } + + public encodePassword(password: string): Promise { + assert(password, "Password is not defined for encodePassword"); + return bcrypt.hash(password, 10); + } + + public encodePasswordOldWay(raw: string, salt?: string): string { + if (this.isPasswordTooLong(raw)) { + throw CrudException.badRequest("Invalid password."); + } + const salted = Buffer.from(this.mergePasswordAndSalt(raw, salt)); + let digest = crypto.createHash(this.algorithm).update(salted).digest(); + for (let i = 1; i < this.iterations; ++i) { + digest = crypto + .createHash(this.algorithm) + .update(Buffer.concat([digest, salted])) + .digest(); + } + return Buffer.from(digest).toString("base64"); + } + + public isPasswordValid(encoded: string, raw: string, salt?: string): Promise { + if (salt) { + // Old implementation + return Promise.resolve().then(() => { + if (encoded.length !== this.encodedLength) { + return false; + } + + return ( + !this.isPasswordTooLong(raw) && + this.hashEquals(encoded, this.encodePasswordOldWay(raw, salt)) + ); + }); + } else { + return bcrypt.compare(raw, encoded); + } + } + + private hashEquals = (answer: string, guess: string) => { + assert( + typeof answer === "string" && typeof guess === "string", + "both arguments should be strings", + ); + + const rb = crypto.pseudoRandomBytes(32); + const ahmac = crypto.createHmac("sha256", rb).update(answer).digest("hex"); + const ghmac = crypto.createHmac("sha256", rb).update(guess).digest("hex"); + const len = ahmac.length; + let result = 0; + for (let i = 0; i < len; ++i) { + result |= ahmac.charCodeAt(i) ^ ghmac.charCodeAt(i); + } + return result === 0; + }; +} diff --git a/twake/backend/node/src/utils/pick.ts b/twake/backend/node/src/utils/pick.ts new file mode 100644 index 00000000..dcbee055 --- /dev/null +++ b/twake/backend/node/src/utils/pick.ts @@ -0,0 +1,9 @@ +/** + * Picks properties from an input object and return them in a new object + * + * @param obj + * @param keys + */ +export function pick(obj: T, ...keys: K[]): Pick { + return keys.reduce((o, k) => ((o[k] = obj[k]), o), {} as Pick); +} diff --git a/twake/backend/node/src/utils/types.ts b/twake/backend/node/src/utils/types.ts new file mode 100644 index 00000000..f81d0bb5 --- /dev/null +++ b/twake/backend/node/src/utils/types.ts @@ -0,0 +1,142 @@ +/** + * Common types for business services + */ + +import { WorkspacePrimaryKey } from "../services/workspaces/entities/workspace"; +import { + Channel as ChannelEntity, + ChannelMember, + ChannelPendingEmails, + ChannelTab, +} from "../services/channels/entities"; +import { ChannelParameters } from "../services/channels/web/types"; +import { MessageNotification } from "../services/messages/types"; + +export type uuid = string; + +export type Maybe = T | undefined; + +/** + * User in platform: + * + * { + * id: "uuid", + * } + */ +export interface User { + // unique user id + id: uuid; + // unique console user id + identity_provider_id?: uuid; + // user email + email?: string; + // server request + server_request?: boolean; //Set to true if request if from the user, can be used to cancel any access restriction + // application call + application_id?: string; + // allow_tracking + allow_tracking?: boolean; +} + +export const webSocketSchema = { + type: "object", + properties: { + name: { type: "string" }, + room: { type: "string" }, + token: { type: "string" }, + }, +}; + +export interface Channel extends Workspace { + id: string; +} + +export enum ChannelType { + DIRECT = "direct", +} + +export interface Workspace { + company_id: string; + workspace_id: string; +} + +export interface WebsocketMetadata { + room: string; + name?: string; + token?: string; +} + +export class ResourceListResponse { + resources: T[]; + websockets?: ResourceWebsocket[]; + next_page_token?: string; + total?: number; +} + +export class ResourceGetResponse { + websocket?: ResourceWebsocket; + resource: T; +} +export class ResourceUpdateResponse { + websocket?: ResourceWebsocket; + resource: T; +} +export class ResourceCreateResponse { + websocket?: ResourceWebsocket; + resource: T; +} + +export class ResourceDeleteResponse { + status: DeleteStatus; +} + +export interface ResourceListQueryParameters extends PaginationQueryParameters { + search_query?: string; + mine?: boolean; +} + +export declare type DeleteStatus = "success" | "error"; +export interface ResourceWebsocket { + room: string; + token?: string; +} + +export interface ResourceEventsPayload { + user: User; + channel?: ChannelEntity; + channelParameters?: ChannelParameters; + guest?: ChannelPendingEmails; + member?: ChannelMember; + message?: Pick; + actor?: User; + resourcesBefore?: (User | ChannelEntity | ChannelTab | ChannelMember)[]; + resourcesAfter?: (User | ChannelEntity | ChannelTab | ChannelMember)[]; + tab?: ChannelTab; + company?: { id: string }; + workspace?: WorkspacePrimaryKey; +} + +export interface PaginationQueryParameters { + page_token?: string; + limit?: string; + websockets?: boolean; +} + +export interface AccessToken { + time: number; + expiration: number; + refresh_expiration: number; + value: string; + refresh: string; + type: "Bearer"; +} + +export interface JWTObject { + exp: number; + type: string; + iat: number; + nbf: number; + sub: string; + email: string; + track: boolean; +} diff --git a/twake/backend/node/src/utils/users.ts b/twake/backend/node/src/utils/users.ts new file mode 100644 index 00000000..2b6d4c20 --- /dev/null +++ b/twake/backend/node/src/utils/users.ts @@ -0,0 +1,95 @@ +import User from "../services/user/entities/user"; +import { + CompanyShort, + CompanyUserObject, + CompanyUserRole, + CompanyUserStatus, + UserObject, +} from "../services/user/web/types"; +import gr from "../services/global-resolver"; + +export async function formatUser( + user: User, + options?: { includeCompanies?: boolean }, +): Promise { + if (!user) return null; + + let resUser = { + id: user.id, + provider: user.identity_provider, + provider_id: user.identity_provider_id, + email: user.email_canonical, + username: user.username_canonical, + is_verified: Boolean(user.mail_verified), + picture: user.picture, + first_name: user.first_name, + last_name: user.last_name, + full_name: [user.first_name, user.last_name].join(" "), + created_at: user.creation_date, + deleted: Boolean(user.deleted), + status: user.status_icon, + last_activity: user.last_activity, + cache: { companies: user.cache?.companies || [] }, + } as UserObject; + + const userOnline = await gr.services.online.get({ user_id: user.id }); + if (userOnline) { + const { last_seen, is_connected } = userOnline; + + resUser = { + ...resUser, + last_seen, + is_connected, + last_activity: last_seen, + }; + } + + if (options?.includeCompanies) { + const userCompanies = await gr.services.users.getUserCompanies({ id: user.id }); + + const companies = await Promise.all( + userCompanies.map(async uc => { + const company = await gr.services.companies.getCompany({ id: uc.group_id }); + return { + role: uc.role as CompanyUserRole, + status: "active" as CompanyUserStatus, // FIXME: with real status + company: { + id: uc.group_id, + name: company.name, + logo: company.logo, + } as CompanyShort, + } as CompanyUserObject; + }), + ); + + resUser = { + ...resUser, + preferences: { + ...user.preferences, + locale: user.preferences?.language || user.language || "en", + timezone: user.preferences?.timezone || parseInt(user.timezone) || 0, + allow_tracking: user.preferences?.allow_tracking || false, + }, + + companies, + }; + + // Fixme: this is for retro compatibility, should be deleted after march 2022 if mobile did implement it https://github.com/linagora/Twake-Mobile/issues/1265 + resUser.preference = resUser.preferences; + + let name: string = resUser?.username; + if (!name) { + resUser.full_name = "Anonymous"; + } else { + if (resUser.deleted) { + name = "Deleted user"; + } else { + name = [resUser.first_name, resUser.last_name].filter(a => a).join(" "); + name = name || resUser.username; + } + resUser.full_name = name.charAt(0).toUpperCase() + name.slice(1); + } + } + + return resUser; +} diff --git a/twake/backend/node/src/utils/uuid-reducer.ts b/twake/backend/node/src/utils/uuid-reducer.ts new file mode 100644 index 00000000..4d4c771b --- /dev/null +++ b/twake/backend/node/src/utils/uuid-reducer.ts @@ -0,0 +1,20 @@ +export const reduceUUID4 = function (id: string): string { + if (!id) return undefined; + + return id + .replace(/(.)\1{2,3}/g, "$1i") + .replace(/(.)\1{1,2}/g, "$1h") + .replace(/-/g, "g"); +}; + +export const expandUUID4 = function (id: string): string { + if (!id) return undefined; + + return ( + id + .replace(/(.)i/g, "$1$1$1") + .replace(/(.)h/g, "$1$1") + .replace(/[^0-9a-g]/g, "") + .replace(/g/g, "-") || undefined + ); +}; diff --git a/twake/backend/node/src/utils/uuid.ts b/twake/backend/node/src/utils/uuid.ts new file mode 100644 index 00000000..31a73b91 --- /dev/null +++ b/twake/backend/node/src/utils/uuid.ts @@ -0,0 +1,14 @@ +export function compareTimeuuid(a?: string, b?: string): number { + return timeuuidToDate(a || "") - timeuuidToDate(b || ""); +} + +export function timeuuidToDate(time_str: string): number { + if (!time_str) { + return 0; + } + + const uuid_arr = time_str.split("-"); + const time_string = [uuid_arr[2].substring(1), uuid_arr[1], uuid_arr[0]].join(""); + + return parseInt(time_string, 16); +} diff --git a/twake/backend/node/src/utils/workspace.ts b/twake/backend/node/src/utils/workspace.ts new file mode 100644 index 00000000..455c381a --- /dev/null +++ b/twake/backend/node/src/utils/workspace.ts @@ -0,0 +1,64 @@ +import { User, Workspace } from "./types"; +import WorkspaceUser from "../services/workspaces/entities/workspace_user"; +import { hasCompanyAdminLevel } from "./company"; +import gr from "../services/global-resolver"; + +export async function isWorkspaceAdmin(user?: User, workspace?: Workspace): Promise { + if (!user || !workspace) { + return false; + } + + const companyUser = await gr.services.companies.getCompanyUser( + { id: workspace.company_id }, + { id: user.id }, + ); + if (companyUser && hasCompanyAdminLevel(companyUser.role)) { + return true; + } + + const workspaceUser = await getWorkspaceUser(user, workspace); + + if (!workspaceUser) { + return false; + } + + return workspaceUser.role === "moderator"; +} + +export function hasWorkspaceAdminLevel(role: string, companyRole: string): boolean { + return role === "moderator" || hasCompanyAdminLevel(companyRole); +} + +export function hasWorkspaceMemberLevel(role: string, companyRole: string): boolean { + return role === "member" || hasWorkspaceAdminLevel(role, companyRole); +} + +export async function getWorkspaceUser(user?: User, workspace?: Workspace): Promise { + if (!user || !workspace) { + return null; + } + + const workspaceUser = await gr.services.workspaces.getUser({ + workspaceId: workspace.workspace_id, + userId: user.id, + }); + + return workspaceUser; +} + +// export async function getCompanyUser(user?: User, company?: Company): Promise { +// if (!user || !company) { +// return null; +// } +// +// const companyUser = await gr.services.companies.getCompanyUser( +// { +// id: company.id, +// }, +// { +// id: user.id, +// }, +// ); +// +// return companyUser; +// } diff --git a/twake/backend/node/src/version.ts b/twake/backend/node/src/version.ts new file mode 100644 index 00000000..7166ce9b --- /dev/null +++ b/twake/backend/node/src/version.ts @@ -0,0 +1,7 @@ +export default { + current: /* @VERSION_DETAIL */ "2023.Q1.1223", + minimal: { + web: /* @MIN_VERSION_WEB */ "2022.Q2.975", + mobile: /* @MIN_VERSION_MOBILE */ "2022.Q2.975", + }, +}; diff --git a/twake/backend/node/test/e2e/application/app-create-update.spec.ts b/twake/backend/node/test/e2e/application/app-create-update.spec.ts new file mode 100644 index 00000000..8b26d40a --- /dev/null +++ b/twake/backend/node/test/e2e/application/app-create-update.spec.ts @@ -0,0 +1,351 @@ +import { afterAll, beforeAll, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { TestDbService } from "../utils.prepare.db"; +import { Api } from "../utils.api"; +import Application, { + PublicApplicationObject, +} from "../../../src/services/applications/entities/application"; +import { cloneDeep } from "lodash"; + +import { logger as log } from "../../../src/core/platform/framework"; +import { v1 as uuidv1 } from "uuid"; + +describe("Applications", () => { + const url = "/internal/services/applications/v1"; + + let platform: TestPlatform; + let testDbService: TestDbService; + let api: Api; + let appRepo; + + beforeAll(async ends => { + platform = await init(); + await platform.database.getConnector().drop(); + testDbService = await TestDbService.getInstance(platform, true); + await testDbService.createDefault(); + postPayload.company_id = platform.workspace.company_id; + api = new Api(platform); + appRepo = await testDbService.getRepository("application", Application); + ends(); + }); + + afterAll(done => { + platform.tearDown().then(() => done()); + }); + + const publishApp = async id => { + const entity = await appRepo.findOne({ id }); + if (!entity) throw new Error(`entity ${id} not found`); + entity.publication.published = true; + await appRepo.save(entity); + }; + + describe("Create application", function () { + it("should 403 if creator is not a company admin", async done => { + const payload = { resource: cloneDeep(postPayload) }; + + const user = await testDbService.createUser([testDbService.defaultWorkspace()], { + companyRole: "member", + }); + + const response = await api.post(`${url}/applications`, payload, user.id); + expect(response.statusCode).toBe(403); + done(); + }); + + it("should 200 on application create", async done => { + const payload = { resource: cloneDeep(postPayload) }; + const response = await api.post(`${url}/applications`, payload); + expect(response.statusCode).toBe(200); + + const r = response.resource; + + expect(r.company_id).toBe(payload.resource.company_id); + expect(!!r.is_default).toBe(false); + expect(r.identity).toMatchObject(payload.resource.identity); + expect(r.access).toMatchObject(payload.resource.access); + expect(r.display).toMatchObject(payload.resource.display); + expect(r.publication).toMatchObject(payload.resource.publication); + expect(r.stats).toMatchObject({ + created_at: expect.any(Number), + updated_at: expect.any(Number), + version: 0, + }); + + expect(r.api).toMatchObject({ + hooks_url: payload.resource.api.hooks_url, + allowed_ips: payload.resource.api.allowed_ips, + private_key: expect.any(String), + }); + + expect(r.api.private_key).not.toBe(""); + + const dbData = await appRepo.findOne({ id: response.resource.id }); + + expect(dbData.api).toMatchObject({ + allowed_ips: payload.resource.api.allowed_ips, + hooks_url: payload.resource.api.hooks_url, + private_key: expect.any(String), + }); + + done(); + }); + }); + describe("Update application", function () { + let createdApp: PublicApplicationObject; + + beforeAll(async done => { + const payload = { resource: cloneDeep(postPayload) }; + const response = await api.post(`${url}/applications`, payload); + createdApp = response.resource; + + done(); + }); + + it("should 403 if editor is not a company admin", async done => { + if (!createdApp) throw new Error("can't find created app"); + log.debug(createdApp); + + const user = await testDbService.createUser([testDbService.defaultWorkspace()], { + companyRole: "member", + }); + + const response = await api.post(`${url}/applications/${createdApp.id}`, postPayload, user.id); + expect(response.statusCode).toBe(403); + done(); + }); + + it("should 404 if application not found", async done => { + const response = await api.post(`${url}/applications/${uuidv1()}`, { resource: postPayload }); + expect(response.statusCode).toBe(404); + done(); + }); + + describe("Unpublished application", () => { + it("should 200 on application update", async done => { + const payload = { resource: cloneDeep(postPayload) }; + + payload.resource.is_default = true; + payload.resource.identity.name = "test2"; + payload.resource.api.hooks_url = "123123"; + payload.resource.access.read = []; + payload.resource.publication.requested = true; + + const response = await api.post(`${url}/applications/${createdApp.id}`, payload); + expect(response.statusCode).toBe(200); + + const r = response.resource; + + expect(r.company_id).toBe(payload.resource.company_id); + expect(!!r.is_default).toBe(false); + expect(r.identity).toMatchObject(payload.resource.identity); + + expect(r.access).toMatchObject(payload.resource.access); + expect(r.display).toMatchObject(payload.resource.display); + expect(r.publication).toMatchObject(payload.resource.publication); + expect(r.stats).toMatchObject({ + created_at: expect.any(Number), + updated_at: expect.any(Number), + version: 1, + }); + + expect(r.api).toBeTruthy(); + + const dbData = await appRepo.findOne({ id: response.resource.id }); + + expect(dbData.api).toMatchObject({ + allowed_ips: payload.resource.api.allowed_ips, + hooks_url: payload.resource.api.hooks_url, + private_key: expect.any(String), + }); + + done(); + }); + }); + + describe.skip("Published application", () => { + beforeAll(async done => { + const payload = { resource: cloneDeep(postPayload) }; + const response = await api.post(`${url}/applications`, payload); + createdApp = response.resource; + await publishApp(createdApp.id); + done(); + }); + + it("should 200 on update if allowed fields changed", async done => { + const payload = { resource: cloneDeep(createdApp) as Application }; + const entity = await appRepo.findOne({ id: createdApp.id }); + payload.resource.api = cloneDeep(entity.api); + payload.resource.publication.requested = true; + const response = await api.post(`${url}/applications/${createdApp.id}`, payload); + expect(response.statusCode).toBe(200); + + expect(response.resource.publication).toMatchObject({ + requested: true, + published: true, + }); + done(); + }); + + it("should 400 on update if not allowed fields changed", async done => { + const payload = { resource: cloneDeep(createdApp) as Application }; + const entity = await appRepo.findOne({ id: createdApp.id }); + payload.resource.api = cloneDeep(entity.api); + const response = await api.post(`${url}/applications/${createdApp.id}`, payload); + expect(response.statusCode).toBe(400); + done(); + }); + }); + }); + describe("Get applications", function () { + let firstApp: PublicApplicationObject; + let secondApp: PublicApplicationObject; + let thirdApp: PublicApplicationObject; + beforeAll(async done => { + const payload = { resource: cloneDeep(postPayload) }; + firstApp = (await api.post(`${url}/applications`, payload)).resource; + secondApp = (await api.post(`${url}/applications`, payload)).resource; + thirdApp = (await api.post(`${url}/applications`, payload)).resource; + + await publishApp(firstApp.id); + await publishApp(secondApp.id); + + done(); + }); + + it("should list published applications", async done => { + const response = await api.get(`${url}/applications`); + expect(response.statusCode).toBe(200); + + const published = response.resources.filter(a => a.publication.published).length; + const unpublished = response.resources.filter(a => a.publication.unpublished).length; + + expect(published).toBeGreaterThanOrEqual(2); + expect(unpublished).toEqual(0); + + expect(response.resources.map(a => a.id)).toEqual( + expect.arrayContaining([firstApp.id, secondApp.id]), + ); + + done(); + }); + + it("should return public object for published application to any user", async done => { + const response = await api.get(`${url}/applications/${firstApp.id}`, uuidv1()); + expect(response.statusCode).toBe(200); + expect(response.resource.id).toEqual(firstApp.id); + expect(response.resource.api).toBeFalsy(); + done(); + }); + + it("should return public object for unpublished application to any user", async done => { + const response = await api.get(`${url}/applications/${thirdApp.id}`, uuidv1()); + expect(response.statusCode).toBe(200); + expect(response.resource.id).toEqual(thirdApp.id); + expect(response.resource.api).toBeFalsy(); + done(); + }); + + it("should return whole object for published application to admin", async done => { + const response = await api.get(`${url}/applications/${firstApp.id}`); + expect(response.statusCode).toBe(200); + expect(response.resource.id).toEqual(firstApp.id); + expect(response.resource.api).toBeTruthy(); + + done(); + }); + + it("should return whole object for unpublished application to admin", async done => { + const response = await api.get(`${url}/applications/${thirdApp.id}`); + expect(response.statusCode).toBe(200); + expect(response.resource.id).toEqual(thirdApp.id); + expect(response.resource.api).toBeTruthy(); + done(); + }); + }); +}); + +const postPayload = { + is_default: true, + company_id: null, + identity: { + code: "code", + name: "name", + icon: "icon", + description: "description", + website: "website", + categories: [], + compatibility: [], + }, + api: { + hooks_url: "hooks_url", + allowed_ips: "allowed_ips", + }, + access: { + read: ["messages"], + write: ["messages"], + delete: ["messages"], + hooks: ["messages"], + }, + display: { + twake: { + version: 1, + + files: { + editor: { + preview_url: "string", //Open a preview inline (iframe) + edition_url: "string", //Url to edit the file (full screen) + extensions: [], //Main extensions app can read + // if file was created by the app, then the app is able to edit with or without extension + empty_files: [ + { + url: "string", // "https://[...]/empty.docx"; + filename: "string", // "Untitled.docx"; + name: "string", // "Word Document"; + }, + ], + }, + actions: [ + //List of action that can apply on a file + { + name: "string", + id: "string", + }, + ], + }, + + //Chat plugin + chat: { + input: true, + commands: [ + { + command: "string", // my_app mycommand + description: "string", + }, + ], + actions: [ + //List of action that can apply on a message + { + name: "string", + id: "string", + }, + ], + }, + + //Allow app to appear as a bot user in direct chat + direct: false, + + //Display app as a standalone application in a tab + tab: { url: "string" }, + + //Display app as a standalone application on the left bar + standalone: { url: "string" }, + + //Define where the app can be configured from + configuration: ["global", "channel"], + }, + }, + publication: { + requested: false, //Publication requested + }, +}; diff --git a/twake/backend/node/test/e2e/application/application-events.spec.ts b/twake/backend/node/test/e2e/application/application-events.spec.ts new file mode 100644 index 00000000..42c9bf81 --- /dev/null +++ b/twake/backend/node/test/e2e/application/application-events.spec.ts @@ -0,0 +1,118 @@ +import * as crypto from "crypto"; +import { afterAll, beforeAll, describe, expect, it } from "@jest/globals"; +import { FastifyInstance, FastifyPluginCallback, FastifyReply, FastifyRequest } from "fastify"; + +import { init, TestPlatform } from "../setup"; +import { TestDbService } from "../utils.prepare.db"; +import { Api } from "../utils.api"; + +import { logger as log } from "../../../src/core/platform/framework"; + +let signingSecret = ""; + +describe("Application events", () => { + const url = "/internal/services/applications/v1"; + let platform: TestPlatform; + let api: Api; + let appId: string; + + beforeAll(async ends => { + platform = await init(undefined, testAppHookRoute); + + await platform.database.getConnector().drop(); + + await TestDbService.getInstance(platform, true); + api = new Api(platform); + + postPayload.company_id = platform.workspace.company_id; + + const createdApplication = await api.post("/internal/services/applications/v1/applications", { + resource: postPayload, + }); + + appId = createdApplication.resource.id; + signingSecret = createdApplication.resource.api.private_key; + + ends(); + + afterAll(done => { + platform.tearDown().then(() => done()); + }); + }); + + it("Should 200 on sending well formed event", async done => { + const payload = { + company_id: platform.workspace.company_id, + workspace_id: platform.workspace.workspace_id, + type: "some type", + name: "name", + content: {}, + }; + + const response = await api.post(`${url}/applications/${appId}/event`, payload); + expect(response.statusCode).toBe(200); + expect(response.resource).toMatchObject({ a: "b" }); + done(); + }); +}); + +const postPayload = { + is_default: false, + company_id: null, + identity: { + code: "code", + name: "name", + icon: "icon", + description: "description", + website: "website", + categories: [], + compatibility: [], + }, + api: { + hooks_url: "http://localhost:3000/test/appHook", + allowed_ips: "allowed_ips", + }, + access: { + read: ["messages"], + write: ["messages"], + delete: ["messages"], + hooks: ["messages"], + }, + display: {}, + publication: { + requested: true, + }, +}; + +const testAppHookRoute = (fastify: FastifyInstance) => { + const routes: FastifyPluginCallback = (fastify: FastifyInstance, options, next) => { + fastify.route({ + method: "POST", + url: "/test/appHook", + handler: (request: FastifyRequest, reply: FastifyReply): Promise => { + const signature = request.headers["x-twake-signature"]; + if (!signature) { + reply.status(403); + reply.send({ error: "Signature is missing" }); + return undefined; + } + + const expectedSignature = crypto + .createHmac("sha256", signingSecret) + .update(JSON.stringify(request.body)) + .digest("hex"); + if (expectedSignature != signature) { + reply.status(403); + reply.send({ error: "Wrong signature" }); + return undefined; + } + + log.debug({ signatureMatched: expectedSignature == signature }); + return Promise.resolve({ a: "b" }); + }, + }); + + next(); + }; + fastify.register(routes); +}; diff --git a/twake/backend/node/test/e2e/application/application-login.spec.ts b/twake/backend/node/test/e2e/application/application-login.spec.ts new file mode 100644 index 00000000..e07e10dd --- /dev/null +++ b/twake/backend/node/test/e2e/application/application-login.spec.ts @@ -0,0 +1,141 @@ +import { afterAll, beforeAll, describe, expect, it } from "@jest/globals"; + +import { init, TestPlatform } from "../setup"; +import { TestDbService } from "../utils.prepare.db"; +import { Api } from "../utils.api"; +import { logger as log } from "../../../src/core/platform/framework"; +import { ApplicationLoginResponse } from "../../../src/services/applicationsapi/web/types"; + +describe("Applications", () => { + let platform: TestPlatform; + let testDbService: TestDbService; + let api: Api; + let appId: string; + let private_key: string; + let accessToken: ApplicationLoginResponse["access_token"]; + + beforeAll(async ends => { + platform = await init(); + await platform.database.getConnector().drop(); + testDbService = await TestDbService.getInstance(platform, true); + api = new Api(platform); + + postPayload.company_id = platform.workspace.company_id; + + const createdApplication = await api.post("/internal/services/applications/v1/applications", { + resource: postPayload, + }); + + appId = createdApplication.resource.id; + private_key = createdApplication.resource.api.private_key; + + ends(); + }); + + afterAll(done => { + platform.tearDown().then(() => done()); + }); + + describe("Login", function () { + it("Should be ok on valid token", async done => { + expect(appId).toBeTruthy(); + + const response = await api.post("/api/console/v1/login", { + id: appId, + secret: private_key, + }); + expect(response.statusCode).toBe(200); + + const resource = (await response.json()).resource as ApplicationLoginResponse; + + expect(resource).toMatchObject({ + access_token: { + time: expect.any(Number), + expiration: expect.any(Number), + refresh_expiration: expect.any(Number), + value: expect.any(String), + refresh: expect.any(String), + type: expect.any(String), + }, + }); + + accessToken = resource.access_token; + + done(); + }); + }); + + describe("Get myself", function () { + it("Should be 401 on invalid token", async done => { + const response = await platform.app.inject({ + method: "GET", + url: "/api/console/v1/me", + headers: { + authorization: `Bearer ${accessToken.value + "!!"}`, + }, + }); + log.debug(response.json()); + expect(response.statusCode).toBe(401); + done(); + }); + + it("Should be 403 on auth by users (not company) token", async done => { + const userToken = await platform.auth.getJWTToken(); + + const response = await platform.app.inject({ + method: "GET", + url: "/api/console/v1/me", + headers: { + authorization: `Bearer ${userToken}`, + }, + }); + log.debug(response.json()); + expect(response.statusCode).toBe(403); + done(); + }); + + it("Should be ok on valid token", async done => { + const response = await platform.app.inject({ + method: "GET", + url: "/api/console/v1/me", + headers: { + authorization: `Bearer ${accessToken.value}`, + }, + }); + + expect(response.statusCode).toBe(200); + const resource = (await response.json()).resource; + log.debug(resource); + expect(resource).toMatchObject(postPayload); + done(); + }); + }); +}); + +const postPayload = { + is_default: false, + company_id: null, + identity: { + code: "code", + name: "name", + icon: "icon", + description: "description", + website: "website", + categories: [], + compatibility: [], + }, + api: { + hooks_url: "hooks_url", + allowed_ips: "allowed_ips", + }, + access: { + read: ["messages"], + write: ["messages"], + delete: ["messages"], + hooks: ["messages"], + }, + display: {}, + publication: { + requested: true, + }, +}; diff --git a/twake/backend/node/test/e2e/channels/channels.realtime.spec.ts b/twake/backend/node/test/e2e/channels/channels.realtime.spec.ts new file mode 100644 index 00000000..d66cefe6 --- /dev/null +++ b/twake/backend/node/test/e2e/channels/channels.realtime.spec.ts @@ -0,0 +1,176 @@ +import "reflect-metadata"; +import { afterEach, beforeEach, describe, expect, it } from "@jest/globals"; +import { ObjectId } from "mongodb"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import io from "socket.io-client"; +import { Channel } from "../../../src/services/channels/entities/channel"; +import { + getChannelPath, + getPublicRoomName, +} from "../../../src/services/channels/services/channel/realtime"; +import { WorkspaceExecutionContext } from "../../../src/services/channels/types"; +import { init, TestPlatform } from "../setup"; +import { ChannelUtils, get as getChannelUtils } from "./utils"; +import gr from "../../../src/services/global-resolver"; + +describe("The Channels Realtime feature", () => { + const url = "/internal/services/channels/v1"; + let platform: TestPlatform; + let socket: SocketIOClient.Socket; + let channelUtils: ChannelUtils; + + beforeEach(async () => { + platform = await init({ + services: [ + "webserver", + "database", + "search", + "storage", + "message-queue", + "user", + "search", + "websocket", + "applications", + "webserver", + "channels", + "auth", + "search", + "realtime", + "counter", + "statistics", + "platform-services", + ], + }); + channelUtils = getChannelUtils(platform); + }); + + afterEach(async () => { + await platform.tearDown(); + platform = null; + socket && socket.close(); + socket = null; + }); + + function connect() { + socket = io.connect("http://localhost:3000", { path: "/socket" }); + socket.connect(); + } + + describe("On channel creation", () => { + it("should notify the client", async done => { + const jwtToken = await platform.auth.getJWTToken(); + const roomToken = "twake"; + const channelName = new ObjectId().toString(); + + connect(); + socket.on("connect", () => { + socket + .emit("authenticate", { token: jwtToken }) + .on("authenticated", () => { + socket.emit("realtime:join", { + name: getPublicRoomName(platform.workspace), + token: roomToken, + }); + socket.on("realtime:join:error", () => done(new Error("Should not occur"))); + socket.on("realtime:join:success", async () => { + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: { + name: channelName, + }, + }, + }); + + expect(response.statusCode).toEqual(201); + }); + socket.on( + "realtime:resource", + (event: { type: any; action: any; resource: { name: any } }) => { + // we can also receive other types of events (channel_activity etc) + if (event.type === "channel") { + expect(event.type).toEqual("channel"); + expect(event.action).toEqual("saved"); + expect(event.resource.name).toEqual(channelName); + done(); + } + }, + ); + }) + .on("unauthorized", () => { + done(new Error("Should not occur")); + }); + }); + }); + }); + + describe("On channel removal", () => { + it("should notify the client", async done => { + const jwtToken = await platform.auth.getJWTToken(); + const roomToken = "twake"; + const channelName = new ObjectId().toString(); + + const channel = channelUtils.getChannel(platform.currentUser.id); + channel.name = channelName; + + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + channelUtils.getContext({ id: channel.owner }), + ); + + connect(); + socket.on("connect", () => { + socket + .emit("authenticate", { token: jwtToken }) + .on("authenticated", () => { + socket.on( + "realtime:resource", + (event: { action: string; type: any; path: any; resource: { id: any } }) => { + if (event.action !== "deleted" || event.type !== "channel") { + // we can receive event when resource is created... + // we can also receive other types of events (channel_activity etc) + return; + } + + expect(event.type).toEqual("channel"); + expect(event.action).toEqual("deleted"); + expect(event.path).toEqual( + getChannelPath( + { id: creationResult.entity.id } as Channel, + { + workspace: platform.workspace, + } as WorkspaceExecutionContext, + ), + ); + expect(event.resource.id).toEqual(creationResult.entity.id); + done(); + }, + ); + socket.emit("realtime:join", { + name: getPublicRoomName(platform.workspace), + token: roomToken, + }); + socket.on("realtime:join:error", () => done(new Error("Should not occur"))); + socket.on("realtime:join:success", async () => { + await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${creationResult.entity.company_id}/workspaces/${creationResult.entity.workspace_id}/channels/${creationResult.entity.id}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + }); + }) + .on("unauthorized", () => { + done(new Error("Should not occur")); + }); + }); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/channels/channels.rest.spec.ts b/twake/backend/node/test/e2e/channels/channels.rest.spec.ts new file mode 100644 index 00000000..2bf97a75 --- /dev/null +++ b/twake/backend/node/test/e2e/channels/channels.rest.spec.ts @@ -0,0 +1,1350 @@ +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "@jest/globals"; +import { v1 as uuidv1 } from "uuid"; +import { deserialize } from "class-transformer"; +import { init, TestPlatform } from "../setup"; +import { + ResourceGetResponse, + ResourceListResponse, + ResourceUpdateResponse, + User, + Workspace, +} from "../../../src/utils/types"; +import { Channel, ChannelMember } from "../../../src/services/channels/entities"; +import { + ChannelExecutionContext, + ChannelVisibility, + WorkspaceExecutionContext, +} from "../../../src/services/channels/types"; +import { + getPrivateRoomName, + getPublicRoomName, +} from "../../../src/services/channels/services/channel/realtime"; +import { ChannelUtils, get as getChannelUtils } from "./utils"; +import { TestDbService } from "../utils.prepare.db"; +import { ChannelObject } from "../../../src/services/channels/services/channel/types"; +import { Api } from "../utils.api"; +import gr from "../../../src/services/global-resolver"; +import { createMessage, e2e_createThread } from "../messages/utils"; + +describe("The /internal/services/channels/v1 API", () => { + const url = "/internal/services/channels/v1"; + let platform: TestPlatform; + let channelUtils: ChannelUtils; + let testDbService: TestDbService; + let api: Api; + + beforeAll(async end => { + // platform = await init(); + // await platform.database.getConnector().drop(); + end(); + }); + + beforeEach(async () => { + platform = await init(); + testDbService = new TestDbService(platform); + api = new Api(platform); + channelUtils = getChannelUtils(platform); + }); + + afterEach(async () => { + await platform?.tearDown(); + platform = null; + }); + + async function testAccess(url, method, done) { + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method, + url, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + expect(response.statusCode).toBe(400); + done(); + } + + function getContext(user?: User): WorkspaceExecutionContext { + return { + workspace: platform.workspace, + user: user || platform.currentUser, + }; + } + + /** + * Get a new channel instance + * + * @param owner will be a random uuidv4 if not defined + */ + function getChannel(owner: string = uuidv1()): Channel { + const channel = new Channel(); + + channel.name = "Test Channel"; + channel.company_id = platform.workspace.company_id; + channel.workspace_id = platform.workspace.workspace_id; + channel.is_default = false; + channel.visibility = ChannelVisibility.PRIVATE; + channel.archived = false; + channel.owner = owner; + + return channel; + } + + async function getChannelREST(channelId: string): Promise { + const response = await api.get( + `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${channelId}`, + ); + + expect(response.statusCode).toEqual(200); + + const channelGetResult: ResourceGetResponse = deserialize( + ResourceGetResponse, + response.body, + ); + + return channelGetResult.resource; + } + + describe("The GET /companies/:companyId/workspaces/:workspaceId/channels route", () => { + it("should 400 when companyId is not valid", async done => { + testAccess( + `${url}/companies/123/workspaces/${platform.workspace.workspace_id}/channels`, + "GET", + done, + ); + }); + + it("should 400 when workspaceId is not valid", async done => { + testAccess( + `${url}/companies/${platform.workspace.company_id}/workspaces/123/channels`, + "GET", + done, + ); + }); + + it("should return empty list of channels", async done => { + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + const result: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resources.length).toEqual(0); + + done(); + }); + + it("should return list of workspace channels", async done => { + const channel = new Channel(); + channel.name = "Test Channel"; + const creationResult = await gr.services.channels.channels.save(channel, {}, getContext()); + + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + const result: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resources.length).toEqual(1); + expect(result.resources[0]).toMatchObject({ + id: creationResult.entity.id, + name: channel.name, + }); + + result.resources.forEach(r => { + expect(r.stats).toMatchObject({ + members: 1, + messages: 0, + }); + }); + + done(); + }); + + it("should return list of channels the user is member of", async done => { + const ws0pk = { id: uuidv1(), company_id: platform.workspace.company_id }; + await testDbService.createWorkspace(ws0pk); + const newUser = await testDbService.createUser([ws0pk]); + + const channel1 = getChannel(); + const channel2 = getChannel(); + + channel1.name = "Test Channel1"; + channel2.name = "Test Channel2"; + + const creationResults = await Promise.all([ + gr.services.channels.channels.save(channel1, {}, getContext()), + gr.services.channels.channels.save(channel2, {}, getContext()), + ]); + + await gr.services.channels.members.save( + { + channel_id: channel1.id, + workspace_id: channel1.workspace_id, + company_id: channel1.company_id, + user_id: newUser.id, + } as ChannelMember, + channelUtils.getChannelContext(channel1, platform.currentUser), + ); + + const jwtToken = await platform.auth.getJWTToken({ sub: newUser.id }); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + query: { + mine: "true", + }, + }); + + console.log(response.body); + const result: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resources.length).toEqual(1); + expect(result.resources[0]).toMatchObject({ + id: creationResults[0].entity.id, + }); + + done(); + }); + + it("should return pagination information when not all channels are returned", async done => { + await Promise.all( + "0123456789".split("").map(name => { + const channel = new Channel(); + channel.name = name; + return gr.services.channels.channels.save(channel, {}, getContext()); + }), + ).catch(() => done(new Error("Failed on creation"))); + + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + query: { + limit: "5", + }, + }); + + const result: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resources.length).toEqual(5); + expect(result.next_page_token).toBeDefined; + + done(); + }); + + it("should be able to paginate over channels from pagination information", async done => { + await platform.database.getConnector().drop(); + + await Promise.all( + "0123456789".split("").map(name => { + const channel = new Channel(); + channel.name = name; + return gr.services.channels.channels.save(channel, {}, getContext()); + }), + ).catch(() => done(new Error("Failed on creation"))); + + const jwtToken = await platform.auth.getJWTToken(); + const firstPage = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + query: { + limit: "5", + }, + }); + + const firstPageChannels: ResourceListResponse = deserialize( + ResourceListResponse, + firstPage.body, + ); + + expect(firstPage.statusCode).toBe(200); + expect(firstPageChannels.resources.length).toEqual(5); + expect(firstPageChannels.next_page_token).toBeDefined; + + const nextPage = firstPageChannels.next_page_token; + const secondPage = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + query: { + limit: "5", + page_token: nextPage, + }, + }); + + const secondPageChannels: ResourceListResponse = deserialize( + ResourceListResponse, + secondPage.body, + ); + + expect(secondPage.statusCode).toBe(200); + expect(secondPageChannels.resources.length).toEqual(5); + + expect( + new Set([ + ...firstPageChannels.resources.map(resource => resource.id), + ...secondPageChannels.resources.map(resource => resource.id), + ]).size, + ).toEqual(10); + + done(); + }); + + it("should not return pagination information when all channels are returned", async done => { + await Promise.all( + "0123456789".split("").map(name => { + const channel = new Channel(); + channel.name = name; + return gr.services.channels.channels.save(channel, {}, getContext()); + }), + ).catch(() => done(new Error("Failed on creation"))); + + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + query: { + limit: "11", + }, + }); + + const result: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resources.length).toEqual(10); + expect(result.next_page_token).not.toBeDefined; + + done(); + }); + + it("should return websockets information", async done => { + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + query: { + websockets: "true", + }, + }); + + const result: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.websockets).toMatchObject([ + { room: getPublicRoomName(platform.workspace) }, + // user id is randomly generated + { room: expect.stringContaining(getPrivateRoomName(platform.workspace, { id: "" })) }, + ]); + + done(); + }); + + it.skip("should return websockets and direct information", async done => { + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + query: { + websockets: "true", + mine: "true", + }, + }); + + const result: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.websockets.length).toEqual(3); + + done(); + }); + }); + + describe("The GET /companies/:companyId/workspaces/:workspaceId/channels/:id route", () => { + it("should 400 when companyId is not valid", async done => { + const channelId = "1"; + + testAccess( + `${url}/companies/123/workspaces/${platform.workspace.workspace_id}/channels/${channelId}`, + "GET", + done, + ); + }); + + it("should 400 when workspaceId is not valid", async done => { + const channelId = "1"; + + testAccess( + `${url}/companies/${platform.workspace.company_id}/workspaces/123/channels/${channelId}`, + "GET", + done, + ); + }); + + it("should return the requested channel", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const channel = new Channel(); + channel.name = "Test Channel"; + channel.company_id = platform.workspace.company_id; + channel.workspace_id = platform.workspace.workspace_id; + + const creationResult = await gr.services.channels.channels.save(channel, {}, getContext()); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${creationResult.entity.id}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + expect(response.statusCode).toEqual(200); + + const channelGetResult: ResourceGetResponse = deserialize( + ResourceGetResponse, + response.body, + ); + + expect(channelGetResult.resource).toBeDefined(); + expect(channelGetResult.resource).toMatchObject({ + id: String(creationResult.entity.id), + name: creationResult.entity.name, + }); + expect(channelGetResult.websocket).toBeDefined(); + expect(channelGetResult.websocket).toMatchObject({ + name: creationResult.entity.name, + room: `/channels/${creationResult.entity.id}`, + token: expect.any(String), + }); + + done(); + }); + + it("channel counters", async done => { + await platform.database.getConnector().drop(); + + await testDbService.createDefault(platform); + + const channel = new Channel(); + channel.name = "Test counters Channel"; + channel.company_id = platform.workspace.company_id; + channel.workspace_id = platform.workspace.workspace_id; + channel.is_default = true; + channel.visibility = ChannelVisibility.PUBLIC; + channel.description = "test counters"; + channel.channel_group = "my channel group"; + + const creationResult = await gr.services.channels.channels.save(channel, {}, getContext()); + + const channelId = creationResult.entity.id; + + let resource = await getChannelREST(channelId); + + expect(resource).toMatchObject({ + company_id: platform.workspace.company_id, + workspace_id: platform.workspace.workspace_id, + // type: expect.stringMatching(/workspace|direct/), // TODO + id: expect.any(String), + icon: expect.any(String), + name: channel.name, + description: channel.description, + channel_group: channel.channel_group, + visibility: channel.visibility, + default: channel.is_default, + owner: platform.currentUser.id, + last_activity: expect.any(Number), + archived: false, + archivation_date: 0, //Timestamp + user_member: expect.any(Object), + stats: expect.any(Object), + }); + + expect(resource.stats).toMatchObject({ + members: 1, + messages: 0, + }); + + expect(resource.user_member).toMatchObject({ + id: expect.any(String), + user_id: platform.currentUser.id, + type: expect.stringMatching(/member|guest|bot/), + last_access: 0, //Timestamp in seconds + last_increment: 0, //Number + favorite: false, + // notification_level: "all" | "none" | "group_mentions" | "user_mentions", // TODO + }); + + const anotherUserId = uuidv1(); + await gr.services.channels.members.addUsersToChannel( + [ + { id: anotherUserId }, + { id: uuidv1() }, + { id: uuidv1() }, + { id: uuidv1() }, + { id: uuidv1() }, + ], + creationResult.entity, + { + user: { id: platform.currentUser.id }, + }, + ); + + resource = await getChannelREST(channelId); + + expect(resource.stats).toMatchObject({ + members: 6, + messages: 0, + }); + + await gr.services.channels.members.delete( + { + ...platform.workspace, + channel_id: channelId, + user_id: anotherUserId, + }, + { channel: creationResult.entity, user: platform.currentUser } as ChannelExecutionContext, + ); + + resource = await getChannelREST(channelId); + + expect(resource.stats).toMatchObject({ + members: 5, + messages: 0, + }); + + done(); + }); + }); + + describe("The POST /companies/:companyId/workspaces/:workspaceId/channels route", () => { + it("should 400 when companyId is not valid", async done => { + testAccess( + `${url}/companies/123/workspaces/${platform.workspace.workspace_id}/channels`, + "POST", + done, + ); + }); + + it("should 400 when workspaceId is not valid", async done => { + testAccess( + `${url}/companies/${platform.workspace.company_id}/workspaces/123/channels`, + "POST", + done, + ); + }); + + it("should create a channel", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: { + name: "Test channel", + }, + }, + }); + + expect(response.statusCode).toEqual(201); + + const channelCreateResult: ResourceGetResponse = deserialize( + ResourceGetResponse, + response.body, + ); + + expect(channelCreateResult.resource).toBeDefined(); + expect(channelCreateResult.websocket).toBeDefined(); + + const res = channelCreateResult.resource; + + const createdChannel = await gr.services.channels.channels.get({ + company_id: res.company_id, + workspace_id: res.workspace_id, + id: res.id, + }); + + expect(channelCreateResult.websocket).toMatchObject({ + room: `/channels/${createdChannel.id}`, + token: expect.any(String), + }); + expect(createdChannel).toBeDefined(); + done(); + }); + + it("should fail when channel name is not defined", async done => { + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: { + description: "The channel description", + }, + }, + }); + + expect(response.statusCode).toEqual(400); + done(); + }); + }); + + describe.skip("The POST /companies/:companyId/workspaces/:workspaceId/channels/:id route", () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + async function updateChannel(jwtToken: string, id: string, resource: any): Promise { + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${id}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource, + }, + }); + + const channelUpdateResult: ResourceUpdateResponse = deserialize( + ResourceUpdateResponse, + response.body, + ); + + expect(channelUpdateResult.resource).toBeDefined(); + expect(channelUpdateResult.websocket).toBeDefined(); + + return await gr.services.channels.channels.get({ + id, + company_id: platform.workspace.company_id, + workspace_id: platform.workspace.workspace_id, + }); + } + + async function updateChannelFail( + jwtToken: string, + id: string, + resource: unknown, + expectedCode: number, + ): Promise { + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${id}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource, + }, + }); + + expect(response.statusCode).toEqual(expectedCode); + } + + it("should 400 when companyId is not valid", async done => { + testAccess( + `${url}/companies/123/workspaces/${platform.workspace.workspace_id}/channels/1`, + "POST", + done, + ); + }); + + it("should 400 when workspaceId is not valid", async done => { + testAccess( + `${url}/companies/${platform.workspace.company_id}/workspaces/123/channels/1`, + "POST", + done, + ); + }); + + describe("When user is workspace moderator and channel has been created by other user", () => { + beforeEach(() => { + platform.currentUser.isWorkspaceModerator = true; + }); + + it("should fail when resource is not defined", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(); + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + await updateChannelFail(jwtToken, creationResult.entity.id, {}, 400); + done(); + }); + + it("should be able to update the is_default field", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(); + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + const updatedChannel = await updateChannel(jwtToken, creationResult.entity.id, { + is_default: true, + }); + + expect(updatedChannel).toMatchObject({ + id: channel.id, + name: "Test Channel", + company_id: channel.company_id, + workspace_id: channel.workspace_id, + is_default: true, + visibility: channel.visibility, + archived: channel.archived, + owner: channel.owner, + }); + done(); + }); + + it("should be able to update the visibility field", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(); + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + const updatedChannel = await updateChannel(jwtToken, creationResult.entity.id, { + visibility: ChannelVisibility.PUBLIC, + }); + + expect(updatedChannel).toMatchObject({ + id: channel.id, + name: "Test Channel", + company_id: channel.company_id, + workspace_id: channel.workspace_id, + is_default: channel.is_default, + visibility: ChannelVisibility.PUBLIC, + archived: channel.archived, + owner: channel.owner, + }); + done(); + }); + + it("should be able to update the archived field", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(); + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + const updatedChannel = await updateChannel(jwtToken, creationResult.entity.id, { + archived: true, + }); + expect(updatedChannel).toMatchObject({ + id: channel.id, + name: "Test Channel", + company_id: channel.company_id, + workspace_id: channel.workspace_id, + is_default: channel.is_default, + visibility: channel.visibility, + archived: true, + owner: channel.owner, + }); + done(); + }); + + it("should be able to update all the fields at the same time", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(); + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + const updatedChannel = await updateChannel(jwtToken, creationResult.entity.id, { + visibility: ChannelVisibility.PUBLIC, + is_default: true, + archived: true, + }); + + expect(updatedChannel).toMatchObject({ + id: channel.id, + name: "Test Channel", + company_id: channel.company_id, + workspace_id: channel.workspace_id, + is_default: true, + visibility: ChannelVisibility.PUBLIC, + archived: true, + owner: channel.owner, + }); + + done(); + }); + }); + + describe("When user is channel owner", () => { + beforeEach(() => { + platform.currentUser.isWorkspaceModerator = false; + }); + + it("should be able to update the is_default field", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(platform.currentUser.id); + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + const updatedChannel = await updateChannel(jwtToken, creationResult.entity.id, { + is_default: true, + }); + + expect(updatedChannel).toMatchObject({ + id: channel.id, + name: "Test Channel", + company_id: channel.company_id, + workspace_id: channel.workspace_id, + is_default: true, + visibility: channel.visibility, + archived: channel.archived, + owner: channel.owner, + }); + + done(); + }); + + it("should be able to update the visibility field", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(platform.currentUser.id); + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + const updatedChannel = await updateChannel(jwtToken, creationResult.entity.id, { + visibility: ChannelVisibility.PUBLIC, + }); + + expect(updatedChannel).toMatchObject({ + id: channel.id, + name: "Test Channel", + company_id: channel.company_id, + workspace_id: channel.workspace_id, + is_default: channel.is_default, + visibility: ChannelVisibility.PUBLIC, + archived: channel.archived, + owner: channel.owner, + }); + + done(); + }); + + it("should be able to update the archived field", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(platform.currentUser.id); + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + const updatedChannel = await updateChannel(jwtToken, creationResult.entity.id, { + archived: true, + }); + + expect(updatedChannel).toMatchObject({ + id: channel.id, + name: "Test Channel", + company_id: channel.company_id, + workspace_id: channel.workspace_id, + is_default: channel.is_default, + visibility: channel.visibility, + archived: true, + owner: channel.owner, + }); + done(); + }); + + it("should be able to update all the fields at the same time", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(platform.currentUser.id); + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + const updatedChannel = await updateChannel(jwtToken, creationResult.entity.id, { + visibility: ChannelVisibility.PUBLIC, + is_default: true, + archived: true, + }); + + expect(updatedChannel).toMatchObject({ + id: channel.id, + name: "Test Channel", + company_id: channel.company_id, + workspace_id: channel.workspace_id, + is_default: true, + visibility: ChannelVisibility.PUBLIC, + archived: true, + owner: channel.owner, + }); + + done(); + }); + }); + + describe("When user is 'standard' user and is not channel owner", () => { + beforeEach(() => { + platform.currentUser.isWorkspaceModerator = false; + }); + + it("should not be able to update the is_default field", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(); + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + await updateChannelFail( + jwtToken, + creationResult.entity.id, + { + is_default: true, + }, + 400, + ); + + done(); + }); + + it("should not be able to update the visibility field", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(); + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + await updateChannelFail( + jwtToken, + creationResult.entity.id, + { + visibility: ChannelVisibility.PUBLIC, + }, + 400, + ); + + done(); + }); + + it("should not be able to update the archived field", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(); + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + await updateChannelFail( + jwtToken, + creationResult.entity.id, + { + archived: true, + }, + 400, + ); + + done(); + }); + + it("should be able to update the 'name', 'description', 'icon' fields", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(); + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + const updatedChannel = await updateChannel(jwtToken, creationResult.entity.id, { + name: "This is a new name", + description: "This is a new description", + icon: "This is a new icon", + }); + + expect(updatedChannel).toMatchObject({ + id: channel.id, + name: "This is a new name", + description: "This is a new description", + icon: "This is a new icon", + company_id: channel.company_id, + workspace_id: channel.workspace_id, + is_default: channel.is_default, + visibility: channel.visibility, + archived: channel.archived, + owner: channel.owner, + }); + + done(); + }); + }); + }); + + describe.skip("The DELETE /companies/:companyId/workspaces/:workspaceId/channels/:id route", () => { + async function expectDeleteResult( + jwtToken: string, + url: string, + status: number, + ): Promise { + const response = await platform.app.inject({ + method: "DELETE", + url, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + expect(response.statusCode).toEqual(status); + } + + it("should 400 when companyId is not valid", async done => { + testAccess( + `${url}/companies/123/workspaces/${platform.workspace.workspace_id}/channels/1`, + "DELETE", + done, + ); + }); + + it("should 400 when workspaceId is not valid", async done => { + testAccess( + `${url}/companies/${platform.workspace.company_id}/workspaces/123/channels/1`, + "DELETE", + done, + ); + }); + + describe("When user is workspace moderator", () => { + beforeEach(() => { + platform.currentUser.isWorkspaceModerator = true; + }); + + it("should not be able to delete a direct channel", async done => { + platform.workspace.workspace_id = "direct"; + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(); + + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + await expectDeleteResult( + jwtToken, + `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${creationResult.entity.id}`, + 400, + ); + done(); + }); + + it("should be able to delete any channel of the workspace", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(); + + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + await expectDeleteResult( + jwtToken, + `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${creationResult.entity.id}`, + 204, + ); + done(); + }); + }); + + describe("When user is channel owner", () => { + beforeEach(() => { + platform.currentUser.isWorkspaceModerator = false; + }); + + it("should not be able to delete a direct channel", async done => { + platform.workspace.workspace_id = "direct"; + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(platform.currentUser.id); + + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + await expectDeleteResult( + jwtToken, + `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${creationResult.entity.id}`, + 400, + ); + done(); + }); + + it("should be able to delete the channel", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(platform.currentUser.id); + + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + await expectDeleteResult( + jwtToken, + `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${creationResult.entity.id}`, + 204, + ); + done(); + }); + }); + + describe("When user is not creator nor workspace moderator", () => { + beforeEach(() => { + platform.currentUser.isWorkspaceModerator = false; + }); + + it("should not be able to delete the channel", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(); + + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + await expectDeleteResult( + jwtToken, + `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${creationResult.entity.id}`, + 400, + ); + done(); + }); + + it("should not be able to delete a direct channel", async done => { + platform.workspace.workspace_id = "direct"; + const jwtToken = await platform.auth.getJWTToken(); + + const channel = getChannel(); + + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + getContext({ id: channel.owner }), + ); + + await expectDeleteResult( + jwtToken, + `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${creationResult.entity.id}`, + 400, + ); + done(); + }); + }); + }); + + describe("The GET /companies/:companyId/workspaces/:workspaceId/recent route", () => { + it("should return list of recent channels for workspace", async done => { + await testDbService.createDefault(platform); + + const channels = []; + + for (let i = 0; i < 5; i++) { + const channel = new Channel(); + channel.name = `Regular Channel ${i}`; + channel.visibility = ChannelVisibility.PUBLIC; + const creationResult = await gr.services.channels.channels.save(channel, {}, getContext()); + channels.push(creationResult.entity); + } + + for (let i = 0; i < 5; i++) { + // const channel = channelUtils.getChannel(); + const directChannelIn = channelUtils.getDirectChannel(); + + const nextUser = await testDbService.createUser( + [{ id: platform.workspace.workspace_id, company_id: platform.workspace.company_id }], + { firstName: "FirstName" + i, lastName: "LastName" + i }, + ); + + const members = [platform.currentUser.id, nextUser.id]; + const directWorkspace: Workspace = { + company_id: platform.workspace.company_id, + workspace_id: ChannelVisibility.DIRECT, + }; + await Promise.all([ + // gr.services.channels.channels.save(channel, {}, getContext()), + gr.services.channels.channels.save( + directChannelIn, + { + members, + }, + { ...getContext(), ...{ workspace: directWorkspace } }, + ), + ]); + channels.push(directChannelIn); + } + + await new Promise(resolve => setTimeout(resolve, 2000)); + + console.log("done awaiting"); + + await e2e_createThread( + platform, + [ + { + company_id: platform.workspace.company_id, + created_at: 0, + created_by: "", + id: channels[2].id, + type: "channel", + workspace_id: platform.workspace.workspace_id, + }, + ], + createMessage({ text: "Initial thread message for regular channel" }), + ); + + await e2e_createThread( + platform, + [ + { + company_id: platform.workspace.company_id, + created_at: 0, + created_by: "", + id: channels[7].id, + type: "channel", + workspace_id: "direct", + }, + ], + createMessage({ text: "Some message" }), + ); + + await gr.services.channels.channels.markAsRead(channels[2], { id: platform.currentUser.id }); + await gr.services.channels.channels.markAsRead(channels[7], { id: platform.currentUser.id }); + + await new Promise(resolve => setTimeout(resolve, 2000)); + + const jwtToken = await platform.auth.getJWTToken(); + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/channels/recent`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + expect(response.statusCode).toBe(200); + + const result: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + console.log(result.resources[0]); + console.log(result.resources.map(a => `${a.name} β€” ${a.last_activity}`)); + + expect(result.resources.length).toEqual(10); + + expect(result.resources[0].name).toEqual("FirstName2 LastName2"); + expect(result.resources[1].name).toEqual("Regular Channel 2"); + + done(); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/channels/channels.search.spec.ts b/twake/backend/node/test/e2e/channels/channels.search.spec.ts new file mode 100644 index 00000000..bb1da691 --- /dev/null +++ b/twake/backend/node/test/e2e/channels/channels.search.spec.ts @@ -0,0 +1,136 @@ +import { afterEach, beforeEach, describe, expect, it } from "@jest/globals"; +import { v1 as uuidv1 } from "uuid"; +import { deserialize } from "class-transformer"; +import { init, TestPlatform } from "../setup"; +import { ResourceGetResponse, ResourceListResponse, User } from "../../../src/utils/types"; +import { Channel } from "../../../src/services/channels/entities"; +import { ChannelVisibility, WorkspaceExecutionContext } from "../../../src/services/channels/types"; +import { ChannelMember } from "../../../src/services/channels/entities"; +import { ChannelUtils, get as getChannelUtils } from "./utils"; +import { TestDbService } from "../utils.prepare.db"; +import { ChannelObject } from "../../../src/services/channels/services/channel/types"; +import { Api } from "../utils.api"; +import gr from "../../../src/services/global-resolver"; + +describe("The /internal/services/channels/v1 API", () => { + const url = "/internal/services/channels/v1"; + let platform: TestPlatform; + let channelUtils: ChannelUtils; + let testDbService: TestDbService; + let api: Api; + + beforeEach(async () => { + platform = await init(); + testDbService = new TestDbService(platform); + api = new Api(platform); + channelUtils = getChannelUtils(platform); + }); + + afterEach(async () => { + await platform?.tearDown(); + platform = null; + }); + + async function testAccess(url, method, done) { + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method, + url, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + expect(response.statusCode).toBe(400); + done(); + } + + function getContext(user?: User): WorkspaceExecutionContext { + return { + workspace: platform.workspace, + user: user || platform.currentUser, + }; + } + + /** + * Get a new channel instance + * + * @param owner will be a random uuidv4 if not defined + */ + function getChannel(owner: string = uuidv1()): Channel { + const channel = new Channel(); + + channel.name = "Test Channel"; + channel.company_id = platform.workspace.company_id; + channel.workspace_id = platform.workspace.workspace_id; + channel.is_default = false; + channel.visibility = ChannelVisibility.PRIVATE; + channel.archived = false; + channel.owner = owner; + + return channel; + } + + async function getChannelREST(channelId: string): Promise { + const response = await api.get( + `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${channelId}`, + ); + + expect(response.statusCode).toEqual(200); + + const channelGetResult: ResourceGetResponse = deserialize( + ResourceGetResponse, + response.body, + ); + + return channelGetResult.resource; + } + + describe("Channels search", () => { + it("Should find channels by name", async done => { + const ws0pk = { id: uuidv1(), company_id: platform.workspace.company_id }; + await testDbService.createWorkspace(ws0pk); + const newUser = await testDbService.createUser([ws0pk]); + + for (let i = 0; i < 10; i++) { + const channel = getChannel(); + channel.name = `test channel ${i}`; + await gr.services.channels.channels.save(channel, {}, getContext()); + + if (i == 0) continue; + await gr.services.channels.members.save( + { + channel_id: channel.id, + workspace_id: channel.workspace_id, + company_id: channel.company_id, + user_id: newUser.id, + } as ChannelMember, + channelUtils.getChannelContext(channel, platform.currentUser), + ); + } + + await new Promise(r => setTimeout(() => r(true), 1000)); + + const jwtToken = await platform.auth.getJWTToken({ sub: newUser.id }); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/search`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + query: { + q: "test", + }, + }); + + const result: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resources.length).toEqual(9); + done(); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/channels/direct-channels.spec.ts b/twake/backend/node/test/e2e/channels/direct-channels.spec.ts new file mode 100644 index 00000000..8c49e156 --- /dev/null +++ b/twake/backend/node/test/e2e/channels/direct-channels.spec.ts @@ -0,0 +1,420 @@ +import { afterEach, beforeEach, describe, expect, it } from "@jest/globals"; +import { v1 as uuidv1 } from "uuid"; +import { deserialize } from "class-transformer"; +import { init, TestPlatform } from "../setup"; +import { + ResourceCreateResponse, + ResourceListResponse, + User, + Workspace, +} from "../../../src/utils/types"; +import { Channel } from "../../../src/services/channels/entities"; +import { ChannelVisibility, WorkspaceExecutionContext } from "../../../src/services/channels/types"; +import { ChannelUtils, get as getChannelUtils } from "./utils"; +import { DirectChannel } from "../../../src/services/channels/entities/direct-channel"; +import gr from "../../../src/services/global-resolver"; + +describe("The direct channels API", () => { + const url = "/internal/services/channels/v1"; + let platform: TestPlatform; + let channelUtils: ChannelUtils; + + beforeEach(async () => { + platform = await init({ + services: [ + "webserver", + "database", + "search", + "storage", + "message-queue", + "user", + "applications", + "websocket", + "channels", + "auth", + "storage", + "counter", + "statistics", + ], + }); + channelUtils = getChannelUtils(platform); + }); + + afterEach(async () => { + await platform.tearDown(); + }); + + function getContext(user?: User): WorkspaceExecutionContext { + return { + workspace: platform.workspace, + user: user || platform.currentUser, + }; + } + + describe("Channel List - GET /channels", () => { + it("should return empty list of direct channels", async done => { + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/direct/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + const result: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resources.length).toEqual(0); + + done(); + }); + + it("should return list of direct channels the user is member of", async done => { + const channel = channelUtils.getChannel(); + const directChannelIn = channelUtils.getDirectChannel(); + const directChannelNotIn = channelUtils.getDirectChannel(); + const members = [platform.currentUser.id, uuidv1()]; + const directWorkspace: Workspace = { + company_id: platform.workspace.company_id, + workspace_id: ChannelVisibility.DIRECT, + }; + + const creationResult = await Promise.all([ + gr.services.channels.channels.save(channel, {}, getContext()), + gr.services.channels.channels.save( + directChannelIn, + { + members, + }, + { ...getContext(), ...{ workspace: directWorkspace } }, + ), + gr.services.channels.channels.save( + directChannelNotIn, + { + members: [uuidv1(), uuidv1()], + }, + { ...getContext({ id: uuidv1() }), ...{ workspace: directWorkspace } }, + ), + ]); + + const jwtToken = await platform.auth.getJWTToken(); + const directResponse = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/direct/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + const directResult: ResourceListResponse = deserialize( + ResourceListResponse, + directResponse.body, + ); + + expect(directResponse.statusCode).toBe(200); + expect(directResult.resources.length).toEqual(1); + + expect(directResult.resources[0]).toMatchObject({ + id: creationResult[1].entity.id, + workspace_id: ChannelVisibility.DIRECT, + user_member: { + user_id: platform.currentUser.id, + }, + }); + + expect(directResult.resources[0].members).toContain(members[0]); + expect(directResult.resources[0].members).toContain(members[1]); + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + const result: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resources.length).toEqual(1); + expect(result.resources[0]).toMatchObject({ + id: creationResult[0].entity.id, + }); + + done(); + }); + + it("should not return direct channels in workspace list", async done => { + const channel = channelUtils.getChannel(); + const directChannelIn = channelUtils.getDirectChannel(); + const directChannelIn2 = channelUtils.getDirectChannel(); + const directChannelNotIn = channelUtils.getDirectChannel(); + const members = [platform.currentUser.id, uuidv1()]; + const directWorkspace: Workspace = { + company_id: platform.workspace.company_id, + workspace_id: ChannelVisibility.DIRECT, + }; + + const creationResult = await Promise.all([ + //This channel will automatically contains the requester because it is added automatically in it + gr.services.channels.channels.save(channel, {}, getContext()), + + //It will contain the currentUser + gr.services.channels.channels.save( + directChannelIn, + { + members, + }, + { ...getContext({ id: uuidv1() }), ...{ workspace: directWorkspace } }, + ), + + //This channel will automatically contains the requester because it is added automatically in it + gr.services.channels.channels.save( + directChannelIn2, + { + members: [uuidv1(), uuidv1()], + }, + { ...getContext(), ...{ workspace: directWorkspace } }, + ), + + //This channel will not contain the currentUser + gr.services.channels.channels.save( + directChannelNotIn, + { + members: [uuidv1(), uuidv1()], + }, + { ...getContext({ id: uuidv1() }), ...{ workspace: directWorkspace } }, + ), + ]); + + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + const result: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resources.length).toEqual(1); + expect(result.resources[0]).toMatchObject({ + id: creationResult[0].entity.id, + }); + expect(result.resources[0].visibility).not.toEqual(ChannelVisibility.DIRECT); + + done(); + }); + + it("should not return direct channels in workspace list with mine parameter", async done => { + const channel = channelUtils.getChannel(); + const channel2 = channelUtils.getChannel(); + const directChannelIn = channelUtils.getDirectChannel(); + const directChannelNotIn = channelUtils.getDirectChannel(); + const members = [platform.currentUser.id, uuidv1()]; + const directWorkspace: Workspace = { + company_id: platform.workspace.company_id, + workspace_id: ChannelVisibility.DIRECT, + }; + + await Promise.all([ + //This channel will automatically contains the requester because it is added automatically in it + gr.services.channels.channels.save(channel, {}, getContext()), + + //This channel will not contain currentUser + gr.services.channels.channels.save(channel2, {}, getContext({ id: uuidv1() })), + + //This channel will automatically contains the requester because it is added automatically in it + gr.services.channels.channels.save( + directChannelIn, + { + members, + }, + { ...getContext(), ...{ workspace: directWorkspace } }, + ), + + gr.services.channels.channels.save( + directChannelNotIn, + { + members: [uuidv1(), uuidv1(), uuidv1()], + }, + { ...getContext(), ...{ workspace: directWorkspace } }, + ), + ]); + + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + query: { + mine: "true", + }, + }); + + const result: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resources.length).toEqual(1); + + done(); + }); + }); + + describe("Create direct channel - POST /channels", () => { + it("should be able to create a direct channel with members", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const members = [uuidv1(), platform.currentUser.id]; + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/direct/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + options: { + members, + }, + resource: { + description: "A direct channel description", + visibility: "direct", + }, + }, + }); + + expect(response.statusCode).toEqual(201); + + const channelCreateResult: ResourceCreateResponse = deserialize( + ResourceCreateResponse, + response.body, + ); + + expect(channelCreateResult.resource).toBeDefined(); + + const createdChannel = await gr.services.channels.channels.get({ + id: channelCreateResult.resource.id, + company_id: channelCreateResult.resource.company_id, + workspace_id: ChannelVisibility.DIRECT, + }); + expect(createdChannel).toBeDefined(); + + const directChannelEntity = await gr.services.channels.channels.getDirectChannel({ + channel_id: createdChannel.id, + company_id: createdChannel.company_id, + users: DirectChannel.getUsersAsString(members), + }); + expect(directChannelEntity).toBeDefined(); + + const directChannelsInCompany = await gr.services.channels.channels.getDirectChannelInCompany( + createdChannel.company_id, + members, + ); + expect(directChannelsInCompany).toBeDefined(); + + done(); + }); + + it("should not be able to create the same direct channel twice (with same users)", async done => { + function createChannel(members: string[]) { + return platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/direct/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + options: { + members, + }, + resource: { + name: "Hello", + visibility: "direct", + }, + }, + }); + } + + const jwtToken = await platform.auth.getJWTToken(); + const members = [uuidv1(), platform.currentUser.id]; + const ids = new Set(); + + let response = await createChannel(members); + expect(response.statusCode).toEqual(201); + let channelCreateResult: ResourceCreateResponse = deserialize( + ResourceCreateResponse, + response.body, + ); + ids.add(channelCreateResult.resource.id); + + response = await createChannel(members); + expect(response.statusCode).toEqual(201); + channelCreateResult = deserialize(ResourceCreateResponse, response.body); + ids.add(channelCreateResult.resource.id); + + expect(ids.size).toEqual(1); + + done(); + }); + + it("should not be able to create the same direct channel twice (with same users not in the same order)", async done => { + function createChannel(members: string[]) { + return platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/direct/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + options: { + members, + }, + resource: { + name: "Hello", + visibility: "direct", + }, + }, + }); + } + + const jwtToken = await platform.auth.getJWTToken(); + const members = [uuidv1(), platform.currentUser.id]; + const ids = new Set(); + + let response = await createChannel(members); + expect(response.statusCode).toEqual(201); + let channelCreateResult: ResourceCreateResponse = deserialize( + ResourceCreateResponse, + response.body, + ); + ids.add(channelCreateResult.resource.id); + + response = await createChannel(members.reverse()); + expect(response.statusCode).toEqual(201); + channelCreateResult = deserialize(ResourceCreateResponse, response.body); + ids.add(channelCreateResult.resource.id); + + expect(ids.size).toEqual(1); + + done(); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/channels/skip-channel-members.realtime.spec.ts b/twake/backend/node/test/e2e/channels/skip-channel-members.realtime.spec.ts new file mode 100644 index 00000000..eede90a7 --- /dev/null +++ b/twake/backend/node/test/e2e/channels/skip-channel-members.realtime.spec.ts @@ -0,0 +1,177 @@ +import "reflect-metadata"; +import { afterEach, beforeEach, describe, expect, it } from "@jest/globals"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import io from "socket.io-client"; +import { Channel, ChannelMember } from "../../../src/services/channels/entities"; +import { init, TestPlatform } from "../setup"; +import { ChannelUtils, get as getChannelUtils } from "./utils"; +import { getPublicRoomName } from "../../../src/services/channels/services/member/realtime"; +import { SaveResult } from "../../../src/core/platform/framework/api/crud-service"; +import gr from "../../../src/services/global-resolver"; + +describe.skip("The Channels Members Realtime feature", () => { + const url = "/internal/services/channels/v1"; + let platform: TestPlatform; + let socket: SocketIOClient.Socket; + let channelUtils: ChannelUtils; + + beforeEach(async () => { + platform = await init({ + services: [ + "message-queue", + "user", + "search", + "websocket", + "webserver", + "channels", + "auth", + "database", + "search", + "realtime", + ], + }); + channelUtils = getChannelUtils(platform); + }); + + afterEach(async () => { + await platform.tearDown(); + platform = null; + socket && socket.close(); + socket = null; + }); + + function connect() { + socket = io.connect("http://localhost:3000", { path: "/socket.io" }); + socket.connect(); + } + + describe("On channel member creation", () => { + let channel; + let createdChannel: SaveResult; + + beforeEach(async () => { + channel = channelUtils.getChannel(); + createdChannel = await gr.services.channels.channels.save( + channel, + {}, + channelUtils.getContext({ id: channel.owner }), + ); + }); + + it("should notify the client", async done => { + const jwtToken = await platform.auth.getJWTToken(); + const roomToken = "twake"; + + connect(); + socket.on("connect", () => { + socket + .emit("authenticate", { token: jwtToken }) + .on("authenticated", () => { + socket.emit("realtime:join", { + name: getPublicRoomName(createdChannel.entity), + token: roomToken, + }); + socket.on("realtime:join:error", () => done(new Error("Should not occur"))); + socket.on("realtime:join:success", async () => { + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${createdChannel.entity.id}/members`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: { + user_id: platform.currentUser.id, + }, + }, + }); + + expect(response.statusCode).toEqual(201); + }); + socket.on("realtime:resource", event => { + expect(event.type).toEqual("channel_member"); + expect(event.action).toEqual("saved"); + expect(event.resource).toMatchObject({ + company_id: platform.workspace.company_id, + workspace_id: platform.workspace.workspace_id, + user_id: platform.currentUser.id, + channel_id: createdChannel.entity.id, + }); + done(); + }); + }) + .on("unauthorized", () => { + done(new Error("Should not occur")); + }); + }); + }); + }); + + describe("On channel member removal", () => { + it("should notify the client", async done => { + const jwtToken = await platform.auth.getJWTToken(); + const roomToken = "twake"; + + const channel = channelUtils.getChannel(platform.currentUser.id); + + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + channelUtils.getContext({ id: channel.owner }), + ); + const member = { + channel_id: creationResult.entity.id, + workspace_id: platform.workspace.workspace_id, + company_id: platform.workspace.company_id, + user_id: platform.currentUser.id, + } as ChannelMember; + + await gr.services.channels.members.save(member, { + channel: creationResult.entity, + user: platform.currentUser, + }); + + connect(); + socket.on("connect", () => { + socket + .emit("authenticate", { token: jwtToken }) + .on("authenticated", () => { + socket.on("realtime:resource", event => { + if (event.action !== "deleted") { + // we can receive event when resource is created... + return; + } + + expect(event.type).toEqual("channel_member"); + expect(event.action).toEqual("deleted"); + expect(event.resource).toMatchObject({ + company_id: platform.workspace.company_id, + workspace_id: platform.workspace.workspace_id, + user_id: platform.currentUser.id, + channel_id: creationResult.entity.id, + }); + done(); + }); + socket.emit("realtime:join", { + name: getPublicRoomName(creationResult.entity), + token: roomToken, + }); + socket.on("realtime:join:error", () => done(new Error("Should not occur"))); + socket.on("realtime:join:success", async () => { + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${creationResult.entity.company_id}/workspaces/${creationResult.entity.workspace_id}/channels/${creationResult.entity.id}/members/${platform.currentUser.id}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + }); + }) + .on("unauthorized", () => { + done(new Error("Should not occur")); + }); + }); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/channels/skip-channel-members.rest.spec.ts b/twake/backend/node/test/e2e/channels/skip-channel-members.rest.spec.ts new file mode 100644 index 00000000..10e6ece9 --- /dev/null +++ b/twake/backend/node/test/e2e/channels/skip-channel-members.rest.spec.ts @@ -0,0 +1,401 @@ +import { afterEach, beforeEach, describe, expect, it } from "@jest/globals"; +import { v1 as uuidv1, v4 as uuidv4 } from "uuid"; +import { deserialize } from "class-transformer"; +import { init, TestPlatform } from "../setup"; +import { Channel } from "../../../src/services/channels/entities/channel"; +import { ChannelMember } from "../../../src/services/channels/entities/channel-member"; +import { + ChannelExecutionContext, + ChannelVisibility, + WorkspaceExecutionContext, +} from "../../../src/services/channels/types"; +import { ResourceGetResponse, ResourceListResponse, User } from "../../../src/utils/types"; +import gr from "../../../src/services/global-resolver"; + +describe.skip("The ChannelMembers REST API", () => { + const url = "/internal/services/channels/v1"; + let platform: TestPlatform; + + beforeEach(async () => { + platform = await init({ + services: ["websocket", "webserver", "channels", "auth", "database"], + }); + }); + + afterEach(async () => { + await platform.tearDown(); + platform = null; + }); + + function getWorkspaceContext(user?: User): WorkspaceExecutionContext { + return { + workspace: platform.workspace, + user: user || platform.currentUser, + }; + } + + function getContext(channel: Channel, user?: User): ChannelExecutionContext { + return { + channel, + user, + }; + } + + /** + * Get a new channel instance + * + * @param owner will be a random uuidv4 if not defined + */ + function getChannel(owner: string = uuidv1()): Channel { + const channel = new Channel(); + + channel.name = "Test Channel"; + channel.company_id = platform.workspace.company_id; + channel.workspace_id = platform.workspace.workspace_id; + channel.is_default = false; + channel.visibility = ChannelVisibility.PRIVATE; + channel.archived = false; + channel.owner = owner; + + return channel; + } + + function getMember(channel: Channel, user: User): ChannelMember { + const member = new ChannelMember(); + + member.company_id = platform.workspace.company_id; + member.workspace_id = platform.workspace.workspace_id; + member.channel_id = channel?.id; + member.user_id = user?.id; + + return member; + } + + describe("The GET / - Get members list", () => { + let channel; + let createdChannel; + + beforeEach(async () => { + channel = getChannel(); + createdChannel = await gr.services.channels.channels.save(channel, {}, getWorkspaceContext()); + }); + + it("should 404 when channel does not exists", done => { + done(); + }); + + it("should return empty list of members", async done => { + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${createdChannel.entity.id}/members`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + const result: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resources.length).toEqual(0); + + done(); + }); + + it("should return list of members the user has access to", async done => { + const member = getMember(createdChannel.entity, platform.currentUser); + const memberCreationResult = await gr.services.channels.members.save( + member, + getContext(channel), + ); + + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${createdChannel.entity.id}/members`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + const result: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resources.length).toEqual(1); + expect(result.resources[0]).toMatchObject({ + channel_id: memberCreationResult.entity.channel_id, + workspace_id: memberCreationResult.entity.workspace_id, + company_id: memberCreationResult.entity.company_id, + user_id: memberCreationResult.entity.user_id, + }); + + done(); + }); + }); + + describe("The POST / - Add member", () => { + let channel; + let createdChannel; + + beforeEach(async () => { + channel = getChannel(); + createdChannel = await gr.services.channels.channels.save(channel, {}, getWorkspaceContext()); + }); + + it("should fail when user_id is not defined", async done => { + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${createdChannel.entity.id}/members`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: {}, + }, + }); + + expect(response.statusCode).toEqual(400); + + done(); + }); + + it("should be able to add current member", async done => { + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${createdChannel.entity.id}/members`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: { + user_id: platform.currentUser.id, + }, + }, + }); + + expect(response.statusCode).toEqual(201); + + done(); + }); + + it("should be able to add another member", async done => { + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${createdChannel.entity.id}/members`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: { + user_id: uuidv1(), + }, + }, + }); + + expect(response.statusCode).toEqual(201); + done(); + }); + }); + + describe("The GET /:member_id - Get a member", () => { + let channel; + let createdChannel; + + beforeEach(async () => { + channel = getChannel(); + createdChannel = await gr.services.channels.channels.save(channel, {}, getWorkspaceContext()); + }); + + it("should 404 when member does not exist", async done => { + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${ + platform.workspace.workspace_id + }/channels/${createdChannel.entity.id}/members/${uuidv1()}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + expect(response.statusCode).toEqual(404); + done(); + }); + + it("should send back member", async done => { + const member = getMember(createdChannel.entity, platform.currentUser); + const memberCreationResult = await gr.services.channels.members.save( + member, + getContext(channel), + ); + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${createdChannel.entity.id}/members/${memberCreationResult.entity.user_id}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + expect(response.statusCode).toEqual(200); + const result: ResourceGetResponse = deserialize( + ResourceGetResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resource).toMatchObject({ + channel_id: memberCreationResult.entity.channel_id, + workspace_id: memberCreationResult.entity.workspace_id, + company_id: memberCreationResult.entity.company_id, + user_id: memberCreationResult.entity.user_id, + }); + + done(); + }); + }); + + describe("The POST /:member_id - Update a member", () => { + let channel; + let createdChannel; + + beforeEach(async () => { + channel = getChannel(); + createdChannel = await gr.services.channels.channels.save(channel, {}, getWorkspaceContext()); + }); + + it("should not be able to update a member when current user is not the member", async done => { + const member = getMember(createdChannel.entity, { id: uuidv4() }); + const memberCreationResult = await gr.services.channels.members.save( + member, + getContext(channel), + ); + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${createdChannel.entity.id}/members/${memberCreationResult.entity.user_id}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: { + favorite: true, + }, + }, + }); + + expect(response.statusCode).toEqual(400); + done(); + }); + + it("should be able to update member when current user is the member", async done => { + const member = getMember(createdChannel.entity, platform.currentUser); + const memberCreationResult = await gr.services.channels.members.save( + member, + getContext(channel), + ); + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${createdChannel.entity.id}/members/${memberCreationResult.entity.user_id}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: { + favorite: true, + }, + }, + }); + + expect(response.statusCode).toEqual(200); + + const channelMember: ChannelMember = await gr.services.channels.members.get(member); + + expect(channelMember).toMatchObject({ + channel_id: memberCreationResult.entity.channel_id, + workspace_id: memberCreationResult.entity.workspace_id, + company_id: memberCreationResult.entity.company_id, + user_id: memberCreationResult.entity.user_id, + favorite: true, + }); + + done(); + }); + }); + + describe("The DELETE /:member_id - Remove a member", () => { + let channel; + let createdChannel; + + beforeEach(async () => { + channel = getChannel(); + createdChannel = await gr.services.channels.channels.save(channel, {}, getWorkspaceContext()); + }); + + it("should 404 when member does not exist", async done => { + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${ + platform.workspace.workspace_id + }/channels/${createdChannel.entity.id}/members/${uuidv1()}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: { + favorite: true, + }, + }, + }); + + expect(response.statusCode).toEqual(404); + done(); + }); + + it("should not be able to remove the member when current user does not have enough rights", async done => { + // const member = getMember(createdChannel.entity, { id: uuidv4() }); + // const memberCreationResult = await gr.services.channels.members.save(member); + // const jwtToken = await platform.auth.getJWTToken(); + // const response = await platform.app.inject({ + // method: "DELETE", + // url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${createdChannel.entity.id}/members/${memberCreationResult.entity.user_id}`, + // headers: { + // authorization: `Bearer ${jwtToken}`, + // }, + // }); + // + // expect(response.statusCode).toEqual(400); + // done(); + }); + + it("should be able to remove the member when current user is the member", async done => { + const member = getMember(createdChannel.entity, platform.currentUser); + const memberCreationResult = await gr.services.channels.members.save( + member, + getContext(channel), + ); + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${platform.workspace.company_id}/workspaces/${platform.workspace.workspace_id}/channels/${createdChannel.entity.id}/members/${memberCreationResult.entity.user_id}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + expect(response.statusCode).toEqual(204); + done(); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/channels/utils.ts b/twake/backend/node/test/e2e/channels/utils.ts new file mode 100644 index 00000000..b68024a6 --- /dev/null +++ b/twake/backend/node/test/e2e/channels/utils.ts @@ -0,0 +1,90 @@ +import { v1 as uuidv1 } from "uuid"; +import { ChannelMember } from "../../../src/services/channels/entities"; +import { Channel } from "../../../src/services/channels/entities/channel"; +import { + ChannelExecutionContext, + ChannelVisibility, + WorkspaceExecutionContext, +} from "../../../src/services/channels/types"; +import { User } from "../../../src/utils/types"; +import { TestPlatform } from "../setup"; + +export interface ChannelUtils { + getContext(user?: User): WorkspaceExecutionContext; + getChannel(owner?: string): Channel; + getDirectChannel(owner?: string): Channel; + getChannelContext(channel: Channel, user: User): ChannelExecutionContext; +} + +export interface ChannelMemberUtils { + getMember(channel: Channel, user: User): ChannelMember; +} + +export function getMemberUtils(platform: TestPlatform): ChannelMemberUtils { + return { + getMember, + }; + + function getMember(channel: Channel, user: User): ChannelMember { + const member = new ChannelMember(); + + member.company_id = platform.workspace.company_id; + member.workspace_id = platform.workspace.workspace_id; + member.channel_id = channel?.id; + member.user_id = user?.id; + + return member; + } +} + +export function get(platform: TestPlatform): ChannelUtils { + return { + getContext, + getChannel, + getDirectChannel, + getChannelContext, + }; + + function getContext(user?: User): WorkspaceExecutionContext { + return { + workspace: platform.workspace, + user: user || platform.currentUser, + }; + } + + function getChannelContext(channel: Channel, user?: User): ChannelExecutionContext { + return { + channel, + user, + }; + } + + /** + * Get a new channel instance + * + * @param owner will be a random uuidv4 if not defined + */ + function getChannel(owner: string = uuidv1()): Channel { + const channel = new Channel(); + + channel.name = "Test Channel"; + channel.company_id = platform.workspace.company_id; + channel.workspace_id = platform.workspace.workspace_id; + channel.is_default = false; + channel.visibility = ChannelVisibility.PUBLIC; + channel.archived = false; + channel.owner = owner; + + return channel; + } + + function getDirectChannel(owner: string = uuidv1()): Channel { + const channel = getChannel(owner); + + channel.visibility = ChannelVisibility.DIRECT; + channel.workspace_id = ChannelVisibility.DIRECT; + channel.name = "A direct channel"; + + return channel; + } +} diff --git a/twake/backend/node/test/e2e/console/console-auth.spec.ts b/twake/backend/node/test/e2e/console/console-auth.spec.ts new file mode 100644 index 00000000..f542f795 --- /dev/null +++ b/twake/backend/node/test/e2e/console/console-auth.spec.ts @@ -0,0 +1,272 @@ +import { afterAll, beforeAll, describe, expect, it as _it, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { TestDbService } from "../utils.prepare.db"; +import { v1 as uuidv1 } from "uuid"; +import gr from "../../../src/services/global-resolver"; + +export const itRemote = (name: string, cb: (a: any) => void) => { + _it(name, async done => { + if (gr.services.console.consoleType === "remote") { + cb(done); + } else { + console.warn(`[skipped]: ${name} (console-mode only)`); + done(); + } + }); +}; + +describe("The console API auth", () => { + const loginUrl = "/internal/services/console/v1/login"; + const tokenRefreshUrl = "/internal/services/console/v1/token"; + + let platform: TestPlatform; + + let testDbService: TestDbService; + const companyId = uuidv1(); + + const firstEmail = "superman@email.com"; + + const firstUserPassword = "superPassw0rd"; + + beforeAll(async ends => { + platform = await init({ + services: [ + "database", + "message-queue", + "search", + "applications", + "webserver", + "user", + "workspaces", + "auth", + "console", + "storage", + "counter", + "statistics", + "platform-services", + ], + }); + + await platform.database.getConnector().init(); + testDbService = await TestDbService.getInstance(platform); + await testDbService.createCompany(companyId); + const ws0pk = { id: uuidv1(), company_id: companyId }; + // const ws1pk = { id: uuidv1(), company_id: companyId }; + await testDbService.createWorkspace(ws0pk); + // await testDbService.createWorkspace(ws1pk); + await testDbService.createUser([ws0pk], { + companyRole: "member", + workspaceRole: "moderator", + email: firstEmail, + firstName: "superman", + password: firstUserPassword, + }); + // await testDbService.createUser([ws0pk], "member", "member"); + // await testDbService.createUser([ws1pk], "member", "member", emailForExistedUser); + + await new Promise(r => setTimeout(r, 1000)); + + ends(); + }); + + afterAll(async ends => { + await platform.tearDown(); + ends(); + }); + + describe("Common checks", () => { + it("should 400 when required params are missing ", async done => { + const response = await platform.app.inject({ + method: "POST", + url: `${loginUrl}`, + payload: { + email: "", + password: "", + remote_access_token: "", + }, + }); + expect(response.statusCode).toBe(400); + expect(response.json()).toMatchObject({ + statusCode: 400, + error: "Bad Request", + message: "remote_access_token or email+password are required", + }); + done(); + }); + }); + describe("Auth using token", () => { + itRemote("should 403 when token is invalid", async done => { + const response = await platform.app.inject({ + method: "POST", + url: `${loginUrl}`, + payload: { + remote_access_token: "12345", + }, + }); + expect(response.json()).toMatchObject({ + error: "Forbidden", + message: "Bad access token credentials", + statusCode: 403, + }); + expect(response.statusCode).toBe(403); + + done(); + }); + + itRemote("should 200 when token is valid", async done => { + const response = await platform.app.inject({ + method: "POST", + url: `${loginUrl}`, + payload: { + email: "", + password: "", + remote_access_token: "a550c8b8b942bd92e447271343ac6b29", + }, + }); + expect(response.json()).toMatchObject({ + access_token: { + time: expect.any(Number), + expiration: expect.any(Number), + refresh_expiration: expect.any(Number), + value: expect.any(String), + refresh: expect.any(String), + type: "Bearer", + }, + }); + expect(response.statusCode).toBe(200); + done(); + }); + }); + describe("Auth using email/password", () => { + it("should 403 when user doesn't exists", async done => { + const response = await platform.app.inject({ + method: "POST", + url: `${loginUrl}`, + payload: { + email: "randomEmail", + password: "randomPass", + }, + }); + expect(response.statusCode).toBe(403); + expect(response.json()).toMatchObject({ + error: "Forbidden", + message: "User doesn't exists", + statusCode: 403, + }); + done(); + }); + + it("should 403 when password doesn't match", async done => { + const user = testDbService.users[0]; + + const response = await platform.app.inject({ + method: "POST", + url: `${loginUrl}`, + payload: { + email: user.email_canonical, + password: "randomPass", + }, + }); + expect(response.statusCode).toBe(403); + expect(response.json()).toMatchObject({ + error: "Forbidden", + message: "Password doesn't match", + statusCode: 403, + }); + done(); + }); + + it("should 200 when credentials is valid", async done => { + const user = testDbService.users[0]; + + const response = await platform.app.inject({ + method: "POST", + url: `${loginUrl}`, + payload: { + email: user.email_canonical, + password: firstUserPassword, + }, + }); + expect(response.statusCode).toBe(200); + expect(response.json()).toMatchObject({ + access_token: { + time: expect.any(Number), + expiration: expect.any(Number), + refresh_expiration: expect.any(Number), + value: expect.any(String), + refresh: expect.any(String), + type: "Bearer", + }, + }); + + done(); + }); + }); + describe("Token renewal", () => { + it("should 200 when refresh from access_token", async done => { + const user = testDbService.users[0]; + + const firstResponse = await platform.app.inject({ + method: "POST", + url: `${loginUrl}`, + payload: { + email: user.email_canonical, + password: firstUserPassword, + }, + }); + + const firstRes = firstResponse.json().access_token; + expect(firstRes.value).toBeTruthy(); + + setTimeout(async () => { + const response = await platform.app.inject({ + method: "POST", + url: `${tokenRefreshUrl}`, + headers: { + authorization: `Bearer ${firstRes.value}`, + }, + }); + + const secondRes = response.json().access_token; + + expect(secondRes.expiration).toBeGreaterThan(firstRes.expiration); + expect(secondRes.refresh_expiration).toBeGreaterThan(firstRes.refresh_expiration); + + done(); + }, 2000); + }); + + it("should 200 when refresh from refresh_token", async done => { + const user = testDbService.users[0]; + + const firstResponse = await platform.app.inject({ + method: "POST", + url: `${loginUrl}`, + payload: { + email: user.email_canonical, + password: firstUserPassword, + }, + }); + + const firstRes = firstResponse.json().access_token; + expect(firstRes.refresh).toBeTruthy(); + + setTimeout(async () => { + const response = await platform.app.inject({ + method: "POST", + url: `${tokenRefreshUrl}`, + headers: { + authorization: `Bearer ${firstRes.refresh}`, + }, + }); + + const secondRes = response.json().access_token; + + expect(secondRes.expiration).toBeGreaterThan(firstRes.expiration); + expect(secondRes.refresh_expiration).toBeGreaterThan(firstRes.refresh_expiration); + + done(); + }, 2000); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/console/console-hooks.spec.ts b/twake/backend/node/test/e2e/console/console-hooks.spec.ts new file mode 100644 index 00000000..fadbbec9 --- /dev/null +++ b/twake/backend/node/test/e2e/console/console-hooks.spec.ts @@ -0,0 +1,545 @@ +import { afterAll, beforeAll, describe, expect, it as _it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { TestDbService } from "../utils.prepare.db"; +import { v1 as uuidv1 } from "uuid"; +import { sign as cryptoSign } from "crypto"; +import gr from "../../../src/services/global-resolver"; +import { ConsoleServiceImpl } from "../../../src/services/console/service"; +/* + THIS TESTS RUNS ONLY FOR THE CONSOLE-MODE (CONSOLE TYPE: REMOTE) +*/ + +export const it = (name: string, cb: (a: any) => void) => { + _it(name, async done => { + if (gr.services.console.consoleType === "remote") { + cb(done); + } else { + console.warn(`[skipped]: ${name} (console-mode only)`); + done(); + } + }); +}; + +describe("The console API hooks", () => { + const url = "/internal/services/console/v1/hook"; + + let platform: TestPlatform; + + let testDbService: TestDbService; + const companyId = uuidv1(); + + const firstEmail = "superman@email.com"; + const secondEmail = "C.o.n.sole_created-user@email.com"; + const thirdEmail = "superman@someogherservice.com"; + + const secret = "ohquoo1fohzeigitochaJeepoowug4Yuqueite6etojieg1oowaeraeshiW8ku8g"; + + beforeAll(async ends => { + platform = await init({ + services: [ + "database", + "message-queue", + "webserver", + "search", + "user", + "workspaces", + "auth", + "console", + "applications", + "storage", + "counter", + "statistics", + "platform-services", + ], + }); + + await platform.database.getConnector().init(); + testDbService = await TestDbService.getInstance(platform); + await testDbService.createCompany(companyId); + const ws0pk = { id: uuidv1(), company_id: companyId }; + + await testDbService.createWorkspace(ws0pk); + + await testDbService.createUser([ws0pk], { + companyRole: "member", + workspaceRole: "moderator", + username: "superman", + }); + + const console = platform.platform.getProvider("console"); + + ends(); + }); + + afterAll(async ends => { + await platform.tearDown(); + ends(); + }); + + const getPayload = (type: string, content: Record) => { + const data = { + content: content, + type: type, + } as any; + + const sign = cryptoSign( + "RSA-SHA512", + Buffer.from(JSON.stringify(data)), + "-----BEGIN PRIVATE KEY-----\nMIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQD15kALIEHoe1bt\nADG/oOqHLRgnzNoiGl8aQ6LD/9c4F5+IVP9gPxGm26haSMW2Z9doJeTucvV8syQV\nbdwc9z0NUhNhFG1RLsj0+ePgpuBfKv+uzEICrRedP7wsmWC37K1NmGZ+LzO21oeu\nLO0L39kNk+qspJnqqx8PIfUmeQ6DDkEKW/J0ISeOsBOetKiJC2n5F4Fkifh1Bq2T\nsFfW9Tz47hfLAKkNUyoulBbqX/xViUhlhFb59sxhoMesCL/VJf7OmTLvryXBW/TU\nCYFssAZXXSWOOzc2k+X2VX3QslKfCHsnCO75I+FPFd9YtFWKlaHeq36ZHlYxnYqp\nRcdixzhjAgMBAAECggEANtvoe9L1gUVLDlLVxnfC+udflTmJjMQvZW+jd3Czdisn\nB0ZXNwS7DmvA8mt72IbwMqcJnPz+sZRRv4oj6j5qW3dtJWJmRQ9X+/doFG2GbxTr\nt/aP34L4WremZpjNUBs4SrBuZUZolijkWkJhnB2Tkgjm+R87y3Pj2P9tbujhCPGM\nMQf+s5lOh/AXDyqYGyEJAZBJT3DevrB9Cl3uhYWZ0fFUz4hwATeB0Va8YT8ZJea2\nXwajg/NnOOpdSGVgv0+7zhPYvkvg8bMZeH24VxYkAfdww8vANPuk4wUwDvnh39+Q\nI4uHQGXgjf8SJ5Z7G7A5Q4r7Ma4drJDbCOfNTi84+QKBgQD+ar48b7c5ffMT/ta7\nGUfMiHCjLfauHt/1f1CkFN1OpJW2ZrS34jYusqBXos32X2gx+wsOGtzOrhkkpvgp\nL7jaZmUnQTwfn6Sx4Duq+LVVMH/uj+W/Zj24AKnoylzM9XC6D2kwKAfHs4Mg6+fe\no6VRBR/yw01ShR+YDVAEN0B7ZwKBgQD3bfCIlp1DpTjFKEBFaC4jRNJPaf8OLt/U\nYHOBwwltb406I4s13M3A1N74Btk5ycx6n/a6RHIGB6+E2xn9AnYI51M/+n9vBLPc\nnnqjOZP/7FdK7qL/g4JtXae/CyroXYaYXUNsdJttQC62QRW+xhp6fYxWt/nAcc9R\nvXmninx5pQJ/CPG3vmgvCNZktU9APVOmMoqZayMyiOyM8xSGwT36ick/eioiMFTD\nkuC0wl/23bJ890TcHqLTIHD+cUttbgU/em4fIEIq2vHB2H8JmfkkZtpNpRVp/lCZ\n2t4rGwQCPzJhxCjGiereWyb0dTPV8v3N0gtcFCzJix0i/zV4mq1WlwKBgGfV1F6N\nznun57YdmTNHcC1O4W+ATRA3rakjvPWU0u0BJmRirDYzbolhDB1MSncM7+n6HYG3\n3Z4YNZlslXBvSveblH1B8560e4K3Y0IClNCO72c71F2kY+Tfq9jpp90R+r0QTo5C\nNUPY7oF/uM9xtYT4ESAHXyFa4aUs/dPIs0odAoGBAKYqeAsbLIsb2ruMkeH5itbe\nxdgVHZ8d2Pxk1h+52SGyptuBzlt7c6Gb3KNxpIc61tZklOn5yj+QmJHN82rXGdIE\nCkdrkEmqZU52X2OInozV1Py8L7akH9wijzy5ULWqxapIE2ItnPkgcC7+x6vglkfd\nI0VcGHm8cgqCpzRaIZjH\n-----END PRIVATE KEY-----", + ); + + data.signature = sign.toString("base64"); + + return data; + }; + + describe("Common checks", () => { + it("should 404 when not POST ", async done => { + const response = await platform.app.inject({ + method: "GET", + url: `${url}`, + }); + expect(response.statusCode).toBe(404); + done(); + }); + + it("should 400 when secret key is missing", async done => { + const response = await platform.app.inject({ + method: "POST", + url: `${url}`, + payload: getPayload("a", {}), + }); + expect(response.statusCode).toBe(400); + expect(response.json()).toMatchObject({ + statusCode: 400, + error: "Bad Request", + message: "querystring should have required property 'secret_key'", + }); + done(); + }); + + it("should 403 when secret key is not valid ", async done => { + const response = await platform.app.inject({ + method: "POST", + url: `${url}?secret_key=wrongOne`, + payload: getPayload("a", {}), + }); + expect(response.statusCode).toBe(403); + expect(response.json()).toMatchObject({ + statusCode: 403, + error: "Forbidden", + message: "Wrong secret", + }); + done(); + }); + + it("should 501 when type is not implemented", async done => { + const response = await platform.app.inject({ + method: "POST", + url: `${url}?secret_key=${secret}`, + payload: getPayload("unknown_type", {}), + }); + expect(response.statusCode).toBe(501); + done(); + }); + }); + + describe("User related hooks", () => { + describe("User created/updated", () => { + it("should 200 when updated existing user", async done => { + const user = testDbService.users[0]; + + const response = await platform.app.inject({ + method: "POST", + url: `${url}?secret_key=${secret}`, + payload: getPayload("user_updated", { + user: { + _id: user.identity_provider_id, + roles: [ + { targetCode: companyId, roleCode: "owner", applications: [{ code: "twake" }] }, + ], + email: firstEmail, + firstName: "firstName", + lastName: "lastName", + isVerified: true, + preference: { + locale: "en", + timeZone: 2, + }, + avatar: { + type: "unknown", + value: "123456.jpg", + }, + }, + }), + }); + + expect(response.statusCode).toBe(200); + + const updatedUser = await testDbService.getUserFromDb({ + id: user.id, + }); + + expect(updatedUser).toMatchObject({ + id: user.id, + email_canonical: firstEmail, + first_name: "firstName", + last_name: "lastName", + mail_verified: true, + timezone: 2, + language: "en", + picture: + gr.services.console.consoleOptions.url.replace(/\/$/, "") + "/avatars/123456.jpg", + }); + + const userRoles = await testDbService.getCompanyUser(companyId, updatedUser.id); + + expect(userRoles).toEqual( + expect.objectContaining({ + role: "owner", + }), + ); + + done(); + }); + + it("should 200 when creating new user", async done => { + const newUserConsoleId = String(testDbService.rand()); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}?secret_key=${secret}`, + payload: getPayload("user_updated", { + user: { + _id: newUserConsoleId, + roles: [ + { targetCode: companyId, roleCode: "admin", applications: [{ code: "twake" }] }, + ], + email: secondEmail, + firstName: "consoleFirst", + lastName: "consoleSecond", + isVerified: true, + preference: { + locale: "ru", + timeZone: 3, + }, + avatar: { + type: "unknown", + value: "5678.jpg", + }, + }, + }), + }); + + expect(response.statusCode).toBe(200); + + const updatedUser = await testDbService.getUserFromDb({ + identity_provider_id: newUserConsoleId, + }); + + expect(updatedUser).toMatchObject({ + first_name: "consoleFirst", + last_name: "consoleSecond", + mail_verified: true, + timezone: 3, + language: "ru", + creation_date: expect.any(String), + deleted: false, + email_canonical: secondEmail.toLocaleLowerCase(), + identity_provider: "console", + identity_provider_id: newUserConsoleId, + username_canonical: "consolecreateduser", + picture: gr.services.console.consoleOptions.url.replace(/\/$/, "") + "/avatars/5678.jpg", + }); + + const userRoles = await testDbService.getCompanyUser(companyId, updatedUser.id); + + expect(userRoles).toEqual( + expect.objectContaining({ + role: "moderator", + }), + ); + done(); + }); + + it("should 200 when creating new user with same username (generating new one)", async done => { + const newUserConsoleId = String(testDbService.rand()); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}?secret_key=${secret}`, + payload: getPayload("user_updated", { + user: { + _id: newUserConsoleId, + roles: [ + { targetCode: companyId, roleCode: "member", applications: [{ code: "twake" }] }, + ], + email: thirdEmail, + firstName: "superman", + lastName: "superman-lastname", + isVerified: true, + preference: { + locale: "ru", + timeZone: 3, + }, + avatar: { + type: "unknown", + value: "5679.jpg", + }, + }, + }), + }); + + expect(response.statusCode).toBe(200); + + const updatedUser = await testDbService.getUserFromDb({ + identity_provider_id: newUserConsoleId, + }); + + expect(updatedUser).toMatchObject({ + first_name: "superman", + last_name: "superman-lastname", + mail_verified: true, + timezone: 3, + language: "ru", + creation_date: expect.any(String), + deleted: false, + email_canonical: thirdEmail.toLocaleLowerCase(), + identity_provider: "console", + identity_provider_id: newUserConsoleId, + username_canonical: "superman1", + picture: gr.services.console.consoleOptions.url.replace(/\/$/, "") + "/avatars/5679.jpg", + }); + + const userRoles = await testDbService.getCompanyUser(companyId, updatedUser.id); + + expect(userRoles).toEqual( + expect.objectContaining({ + role: "member", + }), + ); + done(); + }); + + it("should 400 when creating user with email that already exists", async done => { + const newUserConsoleId = String(testDbService.rand()); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}?secret_key=${secret}`, + payload: getPayload("user_updated", { + user: { + _id: newUserConsoleId, + email: firstEmail, + }, + }), + }); + + expect(response.statusCode).toBe(400); + expect(response.json()).toMatchObject({ + error: "Console user not created because email already exists", + }); + done(); + }); + }); + describe("User removed", () => { + it("should 200 when deleting", async done => { + const company = testDbService.company; + let users = await testDbService.getCompanyUsers(company.id); + let user = users.find(a => a.username_canonical == "consolecreateduser"); + expect(user).toBeTruthy(); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}?secret_key=${secret}`, + payload: getPayload("company_user_deactivated", { + company: { code: company.identity_provider_id }, + user: { + _id: user.identity_provider_id, + }, + }), + }); + + expect(response.statusCode).toBe(200); + + users = await testDbService.getCompanyUsers(company.id); + user = users.find(a => a.username_canonical == "consolecreateduser"); + expect(user).toBeFalsy(); + + done(); + }); + + it("should 400 when user not found", async done => { + const company = testDbService.company; + + const response = await platform.app.inject({ + method: "POST", + url: `${url}?secret_key=${secret}`, + payload: getPayload("company_user_deactivated", { + company: { code: company.identity_provider_id }, + user: { + _id: 123456789, + }, + }), + }); + + expect(response.statusCode).toBe(400); + + done(); + }); + }); + }); + + describe("Company related hooks", () => { + describe("Company added", () => { + it("should 200 when company created", async done => { + const newCompanyCode = String(testDbService.rand()); + const response = await platform.app.inject({ + method: "POST", + url: `${url}?secret_key=${secret}`, + payload: getPayload("company_created", { + company: { + code: newCompanyCode, + stats: "stats", + plan: { name: "plan name", limits: {} }, + value: "value", + details: { + logo: "logo", + avatar: { + value: "avatar.jpg", + type: "type", + }, + name: "company name", + }, + }, + }), + }); + + expect(response.statusCode).toBe(200); + + const createdCompany = await testDbService.getCompanyFromDbByCode(newCompanyCode); + expect(createdCompany).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: "company name", + plan: { name: "plan name", limits: {} }, + stats: "stats", + logo: "logo", + dateAdded: expect.any(Number), + identity_provider: "console", + identity_provider_id: newCompanyCode, + // details: + }), + ); + + done(); + }); + }); + describe("Company updated", () => { + it("should 200 when company updated", async done => { + const company = testDbService.company; + expect(company).toBeTruthy(); + expect(company.identity_provider_id).toBeTruthy(); + const response = await platform.app.inject({ + method: "POST", + url: `${url}?secret_key=${secret}`, + payload: getPayload("company_updated", { + company: { + code: company.identity_provider_id, + stats: "stats", + plan: { name: "plan name", limits: {} }, + value: "value", + details: { + logo: "logo", + avatar: { + value: "avatar.jpg", + type: "type", + }, + name: "new company name", + }, + }, + }), + }); + + expect(response.statusCode).toBe(200); + + const createdCompany = await testDbService.getCompanyFromDb(company.id); + expect(createdCompany).toEqual( + expect.objectContaining({ + id: company.id, + name: "new company name", + plan: { name: "plan name", limits: {} }, + stats: "stats", + logo: "logo", + dateAdded: expect.any(Number), + identity_provider: "console", + identity_provider_id: company.identity_provider_id, + // details: + }), + ); + + done(); + }); + }); + describe("Plan updated", () => { + it("should 200 when plan updated", async done => { + const company = testDbService.company; + expect(company).toBeTruthy(); + expect(company.identity_provider_id).toBeTruthy(); + const response = await platform.app.inject({ + method: "POST", + url: `${url}?secret_key=${secret}`, + payload: getPayload("plan_updated", { + company: { + code: company.identity_provider_id, + plan: { name: "another plan name", limits: {} }, + }, + }), + }); + + expect(response.statusCode).toBe(200); + + const createdCompany = await testDbService.getCompanyFromDb(company.id); + expect(createdCompany).toEqual( + expect.objectContaining({ + id: company.id, + name: "new company name", + plan: { name: "another plan name", limits: {} }, + stats: "stats", + logo: "logo", + dateAdded: expect.any(Number), + identity_provider: "console", + identity_provider_id: company.identity_provider_id, + // details: + }), + ); + + done(); + }); + }); + + describe("Company removed", () => { + it("should 200 when company removed", async done => { + const company = testDbService.company; + expect(company).toBeTruthy(); + expect(company.identity_provider_id).toBeTruthy(); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}?secret_key=${secret}`, + payload: getPayload("company_deleted", { + company: { + code: company.identity_provider_id, + }, + }), + }); + + expect(response.statusCode).toBe(200); + const deletedCompany = await testDbService.getCompanyFromDb(company.id); + expect(deletedCompany).toBeFalsy(); + + done(); + }); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/counters.spec.ts b/twake/backend/node/test/e2e/counters.spec.ts new file mode 100644 index 00000000..d26a3cc5 --- /dev/null +++ b/twake/backend/node/test/e2e/counters.spec.ts @@ -0,0 +1,239 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck +import { beforeAll, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "./setup"; +import { v1 as uuidv1 } from "uuid"; +import { CounterAPI } from "../../src/core/platform/services/counter/types"; +import { + WorkspaceCounterEntity, + WorkspaceCounterPrimaryKey, + WorkspaceCounterType, +} from "../../src/services/workspaces/entities/workspace_counters"; +import { CounterProvider } from "../../src/core/platform/services/counter/provider"; +import WorkspaceUser, { + getInstance as getWorkspaceUserInstance, + TYPE as WorkspaceUserEntityType, +} from "../../src/services/workspaces/entities/workspace_user"; + +import { countRepositoryItems } from "../../src/utils/counters"; +import { TestDbService } from "./utils.prepare.db"; +import { + ChannelCounterEntity, + ChannelCounterPrimaryKey, + ChannelUserCounterType, +} from "../../src/services/channels/entities/channel-counters"; +import { ChannelMemberType } from "../../src/services/channels/types"; +import { getMemberOfChannelInstance, MemberOfChannel } from "../../src/services/channels/entities"; +import gr from "../../src/services/global-resolver"; + +describe("Counters implementation", () => { + let platform: TestPlatform; + // let database: DatabaseServiceAPI; + let counterApi: CounterAPI; + let testDbService: TestDbService; + + beforeAll(async ends => { + platform = await init(); + + testDbService = new TestDbService(platform); + + await gr.database.getConnector().drop(); + + counterApi = platform.platform.getProvider("counter"); + expect(counterApi).toBeTruthy(); + + ends(); + }); + + afterAll(done => { + platform.tearDown().then(done); + }); + + const getCounter = async (type, entity) => { + return counterApi.getCounter(await testDbService.getRepository(type, entity)); + }; + + describe("Workspace counters", () => { + let counter: CounterProvider; + const counterPk = { id: uuidv1(), counter_type: WorkspaceCounterType.MEMBERS }; + + beforeAll(async ends => { + counter = await getCounter("workspace_counters", WorkspaceCounterEntity); + + const workspaceUserRepository = await testDbService.getRepository( + WorkspaceUserEntityType, + WorkspaceUser, + ); + + await workspaceUserRepository.save( + getWorkspaceUserInstance({ + workspaceId: counterPk.id, + userId: uuidv1(), + id: uuidv1(), + }), + ); + + expect(counter).toBeTruthy(); + + ends(); + }); + + it("Initializing empty value", async done => { + await counter.increase(counterPk, 0); + const val = await counter.get(counterPk); + expect(val).toEqual(0); + done(); + }); + + it("Adding value", async done => { + // adding 1 + + await counter.increase(counterPk, 1); + let val = await counter.get(counterPk); + expect(val).toEqual(1); + + // adding 2 + + await counter.increase(counterPk, 2); + val = await counter.get(counterPk); + expect(val).toEqual(3); + + done(); + }); + + it("Subtracting value", async done => { + // Subtracting 2 + + await counter.increase(counterPk, -2); + let val = await counter.get(counterPk); + expect(val).toEqual(1); + + // Subtracting 10 + + await counter.increase(counterPk, -10); + val = await counter.get(counterPk); + expect(val).toEqual(-9); + + done(); + }); + + it("Revising counter", async done => { + // Subtracting 2 + + const workspaceUserRepository = await testDbService.getRepository( + WorkspaceUserEntityType, + WorkspaceUser, + ); + + counter.setReviseCallback(async (pk: WorkspaceCounterPrimaryKey) => { + if (pk.counter_type == "members") { + return countRepositoryItems(workspaceUserRepository, { workspace_id: pk.id }); + } + }, 4); + + await counter.increase(counterPk, 1); + const val = await counter.get(counterPk); + expect(val).toEqual(1); + + done(); + }); + }); + + describe("Channel counters", () => { + let counter: CounterProvider; + let counterPk: ChannelCounterPrimaryKey; + + beforeAll(async ends => { + counterPk = { + id: uuidv1(), + company_id: uuidv1(), + workspace_id: uuidv1(), + counter_type: ChannelUserCounterType.MEMBERS, + }; + + counter = await getCounter("channel_counters", ChannelCounterEntity); + + const memberOfChannelRepository = await testDbService.getRepository( + "channel_members", + MemberOfChannel, + ); + + await memberOfChannelRepository.save( + getMemberOfChannelInstance({ + company_id: counterPk.company_id, + workspace_id: counterPk.workspace_id, + channel_id: counterPk.id, + user_id: uuidv1(), + }), + ); + + expect(counter).toBeTruthy(); + + ends(); + }); + + it("Initializing empty value", async done => { + await counter.increase(counterPk, 0); + const val = await counter.get(counterPk); + expect(val).toEqual(0); + done(); + }); + + it("Adding value", async done => { + // adding 1 + + await counter.increase(counterPk, 1); + let val = await counter.get(counterPk); + expect(val).toEqual(1); + + // adding 2 + + await counter.increase(counterPk, 2); + val = await counter.get(counterPk); + expect(val).toEqual(3); + + done(); + }); + + it("Subtracting value", async done => { + // Subtracting 2 + + await counter.increase(counterPk, -2); + let val = await counter.get(counterPk); + expect(val).toEqual(1); + + // Subtracting 10 + + await counter.increase(counterPk, -10); + val = await counter.get(counterPk); + expect(val).toEqual(-9); + + done(); + }); + + it("Revising counter", async done => { + // Subtracting 2 + + const memberOfChannelRepository = await testDbService.getRepository( + "channel_members", + MemberOfChannel, + ); + + counter.setReviseCallback(async (pk: ChannelCounterPrimaryKey) => { + if (pk.counter_type == ChannelUserCounterType.MEMBERS) { + return countRepositoryItems( + memberOfChannelRepository, + { channel_id: pk.id, company_id: pk.company_id, workspace_id: pk.workspace_id }, + { type: ChannelMemberType.MEMBER }, + ); + } + }, 4); + + await counter.increase(counterPk, 1); + const val = await counter.get(counterPk); + expect(val).toEqual(1); + + done(); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/documents/assets/test.txt b/twake/backend/node/test/e2e/documents/assets/test.txt new file mode 100644 index 00000000..9daeafb9 --- /dev/null +++ b/twake/backend/node/test/e2e/documents/assets/test.txt @@ -0,0 +1 @@ +test diff --git a/twake/backend/node/test/e2e/documents/documents-tab.spec.ts b/twake/backend/node/test/e2e/documents/documents-tab.spec.ts new file mode 100644 index 00000000..e9d6c84e --- /dev/null +++ b/twake/backend/node/test/e2e/documents/documents-tab.spec.ts @@ -0,0 +1,183 @@ +import { afterAll, afterEach, beforeEach, describe, expect, it } from "@jest/globals"; +import { deserialize } from "class-transformer"; +import { AccessInformation } from "../../../src/services/documents/entities/drive-file"; +import { init, TestPlatform } from "../setup"; +import { TestDbService } from "../utils.prepare.db"; +import { e2e_createDocument, e2e_getDocument } from "./utils"; + +const url = "/internal/services/documents/v1"; + +describe("the Drive Twake tabs feature", () => { + let platform: TestPlatform; + + class DriveFileMockClass { + id: string; + name: string; + size: number; + added: string; + parent_id: string; + access_info: AccessInformation; + } + + class DriveItemDetailsMockClass { + path: string[]; + item: DriveFileMockClass; + children: DriveFileMockClass[]; + versions: Record[]; + } + + beforeEach(async () => { + platform = await init({ + services: [ + "webserver", + "database", + "applications", + "search", + "storage", + "message-queue", + "user", + "search", + "files", + "websocket", + "messages", + "auth", + "realtime", + "channels", + "counter", + "statistics", + "platform-services", + "documents", + ], + }); + }); + + afterEach(async () => { + await platform.tearDown(); + }); + + afterAll(async () => { + await platform.app.close(); + }); + + it("did create a tab configuration on Drive side", async done => { + await TestDbService.getInstance(platform, true); + + const item = { + name: "new tab test file", + parent_id: "root", + company_id: platform.workspace.company_id, + }; + + const version = {}; + + const response = await e2e_createDocument(platform, item, version); + const doc = deserialize(DriveFileMockClass, response.body); + + const tab = { + company_id: platform.workspace.company_id, + tab_id: "1234567890", + channel_id: "abcdefghij", + item_id: doc.id, + level: "write", + }; + + const token = await platform.auth.getJWTToken(); + + const createdTab = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/tabs/${tab.tab_id}`, + headers: { + authorization: `Bearer ${token}`, + }, + payload: tab, + }); + + expect(createdTab.statusCode).toBe(200); + expect(createdTab.body).toBeDefined(); + expect(createdTab.json().company_id).toBe(tab.company_id); + expect(createdTab.json().tab_id).toBe(tab.tab_id); + expect(createdTab.json().item_id).toBe(tab.item_id); + + const getTabResponse = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/tabs/${tab.tab_id}`, + headers: { + authorization: `Bearer ${token}`, + }, + }); + + expect(getTabResponse.statusCode).toBe(200); + expect(getTabResponse.body).toBeDefined(); + expect(getTabResponse.json().company_id).toBe(tab.company_id); + expect(getTabResponse.json().tab_id).toBe(tab.tab_id); + expect(getTabResponse.json().item_id).toBe(tab.item_id); + + const documentResponse = await e2e_getDocument(platform, doc.id); + const documentResult = deserialize( + DriveItemDetailsMockClass, + documentResponse.body, + ); + + console.log(documentResult?.item); + + expect( + documentResult?.item?.access_info?.entities?.find( + a => a?.type === "channel" && a.id === "abcdefghij" && a.level === "write", + ), + ).toBeDefined(); + + done?.(); + }); + + it("did refuse to create a tab configuration for an item I can't manage", async done => { + const dbService = await TestDbService.getInstance(platform, true); + const ws0pk = { + id: platform.workspace.workspace_id, + company_id: platform.workspace.company_id, + }; + const otherUser = await dbService.createUser([ws0pk]); + + const item = { + name: "new tab test file", + parent_id: "root", + company_id: platform.workspace.company_id, + access_info: { + entities: [ + { + type: "folder", + id: "parent", + level: "none", + } as any, + ], + }, + }; + + const version = {}; + + const response = await e2e_createDocument(platform, item, version); + const doc = deserialize(DriveFileMockClass, response.body); + + const tab = { + company_id: platform.workspace.company_id, + tab_id: "1234567890", + channel_id: "abcdefghij", + item_id: doc.id, + level: "read", + }; + + const token = await platform.auth.getJWTToken({ sub: otherUser.id }); + + const createdTab = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/tabs/${tab.tab_id}`, + headers: { + authorization: `Bearer ${token}`, + }, + payload: tab, + }); + + expect(createdTab.statusCode).toBe(403); + + done?.(); + }); +}); diff --git a/twake/backend/node/test/e2e/documents/documents.spec.ts b/twake/backend/node/test/e2e/documents/documents.spec.ts new file mode 100644 index 00000000..d964740e --- /dev/null +++ b/twake/backend/node/test/e2e/documents/documents.spec.ts @@ -0,0 +1,238 @@ +import { describe, beforeEach, afterEach, it, expect, afterAll } from "@jest/globals"; +import { deserialize } from "class-transformer"; +import { File } from "../../../src/services/files/entities/file"; +import { ResourceUpdateResponse } from "../../../src/utils/types"; +import { init, TestPlatform } from "../setup"; +import { TestDbService } from "../utils.prepare.db"; +import { + e2e_createDocument, + e2e_createDocumentFile, + e2e_createVersion, + e2e_deleteDocument, + e2e_getDocument, + e2e_searchDocument, + e2e_updateDocument, +} from "./utils"; + +describe("the Drive feature", () => { + let platform: TestPlatform; + + class DriveFileMockClass { + id: string; + name: string; + size: number; + added: string; + parent_id: string; + } + + class DriveItemDetailsMockClass { + path: string[]; + item: DriveFileMockClass; + children: DriveFileMockClass[]; + versions: Record[]; + } + + class SearchResultMockClass { + entities: DriveFileMockClass[]; + } + + beforeEach(async () => { + platform = await init({ + services: [ + "webserver", + "database", + "applications", + "search", + "storage", + "message-queue", + "user", + "search", + "files", + "websocket", + "messages", + "auth", + "realtime", + "channels", + "counter", + "statistics", + "platform-services", + "documents", + ], + }); + }); + + afterEach(async () => { + await platform.tearDown(); + }); + + afterAll(async () => { + await platform.app.close(); + }); + + const createItem = async (): Promise => { + await TestDbService.getInstance(platform, true); + + const item = { + name: "new test file", + parent_id: "root", + company_id: platform.workspace.company_id, + }; + + const version = {}; + + const response = await e2e_createDocument(platform, item, version); + return deserialize(DriveFileMockClass, response.body); + }; + + it("did create the drive item", async done => { + const result = await createItem(); + + expect(result).toBeDefined(); + expect(result.name).toEqual("new test file"); + expect(result.added).toBeDefined(); + + done?.(); + }); + + it("did fetch the drive item", async done => { + await TestDbService.getInstance(platform, true); + + const response = await e2e_getDocument(platform, ""); + const result = deserialize(DriveItemDetailsMockClass, response.body); + + expect(result.item.name).toEqual("root"); + + done?.(); + }); + + it("did fetch the trash", async done => { + await TestDbService.getInstance(platform, true); + + const response = await e2e_getDocument(platform, "trash"); + const result = deserialize(DriveItemDetailsMockClass, response.body); + + expect(result.item.name).toEqual("trash"); + + done?.(); + }); + + it("did delete an item", async done => { + const createItemResult = await createItem(); + + expect(createItemResult.id).toBeDefined(); + + const deleteResponse = await e2e_deleteDocument(platform, createItemResult.id); + expect(deleteResponse.statusCode).toEqual(200); + + done?.(); + }); + + it("did update an item", async done => { + const createItemResult = await createItem(); + + expect(createItemResult.id).toBeDefined(); + + const update = { + name: "somethingelse", + }; + + const updateItemResponse = await e2e_updateDocument(platform, createItemResult.id, update); + const updateItemResult = deserialize( + DriveFileMockClass, + updateItemResponse.body, + ); + + expect(createItemResult.id).toEqual(updateItemResult.id); + expect(updateItemResult.name).toEqual("somethingelse"); + + done?.(); + }); + + it("did move an item to trash", async done => { + const createItemResult = await createItem(); + + expect(createItemResult.id).toBeDefined(); + + const moveToTrashResponse = await e2e_deleteDocument(platform, createItemResult.id); + expect(moveToTrashResponse.statusCode).toEqual(200); + + const listTrashResponse = await e2e_getDocument(platform, "trash"); + const listTrashResult = deserialize( + DriveItemDetailsMockClass, + listTrashResponse.body, + ); + + expect(listTrashResult.item.name).toEqual("trash"); + expect(listTrashResult.children.some(({ id }) => id === createItemResult.id)).toBeTruthy(); + + done?.(); + }); + + // TODO: wait for elastic search index + it("did search for an item", async done => { + const createItemResult = await createItem(); + + expect(createItemResult.id).toBeDefined(); + + await e2e_getDocument(platform, "root"); + await e2e_getDocument(platform, createItemResult.id); + + await new Promise(resolve => setTimeout(resolve, 3000)); + + const searchPayload = { + search: "test", + }; + + const searchResponse = await e2e_searchDocument(platform, searchPayload); + const searchResult = deserialize( + SearchResultMockClass, + searchResponse.body, + ); + + expect(searchResult.entities.length).toBeGreaterThanOrEqual(1); + + done?.(); + }); + + it("did search for an item that doesn't exist", async done => { + await createItem(); + + const unexistingSeachPayload = { + search: "somethingthatdoesn'tandshouldn'texist", + }; + const failSearchResponse = await e2e_searchDocument(platform, unexistingSeachPayload); + const failSearchResult = deserialize( + SearchResultMockClass, + failSearchResponse.body, + ); + + expect(failSearchResult.entities).toHaveLength(0); + + done?.(); + }); + + it("did create a version for a drive item", async done => { + const item = await createItem(); + const fileUploadResponse = await e2e_createDocumentFile(platform); + const fileUploadResult = deserialize>( + ResourceUpdateResponse, + fileUploadResponse.body, + ); + + const file_metadata = { external_id: fileUploadResult.resource.id }; + + await e2e_createVersion(platform, item.id, { filename: "file2", file_metadata }); + await e2e_createVersion(platform, item.id, { filename: "file3", file_metadata }); + await e2e_createVersion(platform, item.id, { filename: "file4", file_metadata }); + + const fetchItemResponse = await e2e_getDocument(platform, item.id); + const fetchItemResult = deserialize( + DriveItemDetailsMockClass, + fetchItemResponse.body, + ); + + expect(fetchItemResult.versions).toHaveLength(4); + + done?.(); + }); +}); diff --git a/twake/backend/node/test/e2e/documents/utils.ts b/twake/backend/node/test/e2e/documents/utils.ts new file mode 100644 index 00000000..1104441c --- /dev/null +++ b/twake/backend/node/test/e2e/documents/utils.ts @@ -0,0 +1,116 @@ +import { DriveFile } from "../../../src/services/documents/entities/drive-file"; +import { FileVersion } from "../../../src/services/documents/entities/file-version"; +import { TestPlatform } from "../setup"; +import formAutoContent from "form-auto-content"; +import fs from "fs"; + +const url = "/internal/services/documents/v1"; + +export const e2e_createDocument = async ( + platform: TestPlatform, + item: Partial, + version: Partial, +) => { + const token = await platform.auth.getJWTToken(); + + return await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/item`, + headers: { + authorization: `Bearer ${token}`, + }, + payload: { + item, + version, + }, + }); +}; + +export const e2e_getDocument = async (platform: TestPlatform, id: string | "root" | "trash") => { + const token = await platform.auth.getJWTToken(); + + return await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/item/${id}`, + headers: { + authorization: `Bearer ${token}`, + }, + }); +}; + +export const e2e_deleteDocument = async (platform: TestPlatform, id: string | "root" | "trash") => { + const token = await platform.auth.getJWTToken(); + + return await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${platform.workspace.company_id}/item/${id}`, + headers: { + authorization: `Bearer ${token}`, + }, + }); +}; + +export const e2e_updateDocument = async ( + platform: TestPlatform, + id: string | "root" | "trash", + item: Partial, +) => { + const token = await platform.auth.getJWTToken(); + + return await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/item/${id}`, + headers: { + authorization: `Bearer ${token}`, + }, + payload: item, + }); +}; + +export const e2e_searchDocument = async ( + platform: TestPlatform, + payload: Record, +) => { + const token = await platform.auth.getJWTToken(); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/search`, + headers: { + authorization: `Bearer ${token}`, + }, + payload, + }); + + return response; +}; + +export const e2e_createVersion = async ( + platform: TestPlatform, + id: string, + payload: Partial, +) => { + const token = await platform.auth.getJWTToken(); + + return await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/item/${id}/version`, + headers: { + authorization: `Bearer ${token}`, + }, + payload, + }); +}; + +export const e2e_createDocumentFile = async (platform: TestPlatform) => { + const filePath = `${__dirname}/assets/test.txt`; + const token = await platform.auth.getJWTToken(); + const form = formAutoContent({ file: fs.createReadStream(filePath) }); + form.headers["authorization"] = `Bearer ${token}`; + + return await platform.app.inject({ + method: "POST", + url: `/internal/services/files/v1/companies/${platform.workspace.company_id}/files`, + ...form, + }); +}; diff --git a/twake/backend/node/test/e2e/files/assets/sample.doc b/twake/backend/node/test/e2e/files/assets/sample.doc new file mode 100644 index 00000000..7e12e3d2 Binary files /dev/null and b/twake/backend/node/test/e2e/files/assets/sample.doc differ diff --git a/twake/backend/node/test/e2e/files/assets/sample.gif b/twake/backend/node/test/e2e/files/assets/sample.gif new file mode 100644 index 00000000..25d1a062 Binary files /dev/null and b/twake/backend/node/test/e2e/files/assets/sample.gif differ diff --git a/twake/backend/node/test/e2e/files/assets/sample.mp4 b/twake/backend/node/test/e2e/files/assets/sample.mp4 new file mode 100644 index 00000000..7936dc09 Binary files /dev/null and b/twake/backend/node/test/e2e/files/assets/sample.mp4 differ diff --git a/twake/backend/node/test/e2e/files/assets/sample.pdf b/twake/backend/node/test/e2e/files/assets/sample.pdf new file mode 100644 index 00000000..c0e31a07 --- /dev/null +++ b/twake/backend/node/test/e2e/files/assets/sample.pdf @@ -0,0 +1,198 @@ +%PDF-1.3 +%βγΟΣ + +1 0 obj +<< +/Type /Catalog +/Outlines 2 0 R +/Pages 3 0 R +>> +endobj + +2 0 obj +<< +/Type /Outlines +/Count 0 +>> +endobj + +3 0 obj +<< +/Type /Pages +/Count 2 +/Kids [ 4 0 R 6 0 R ] +>> +endobj + +4 0 obj +<< +/Type /Page +/Parent 3 0 R +/Resources << +/Font << +/F1 9 0 R +>> +/ProcSet 8 0 R +>> +/MediaBox [0 0 612.0000 792.0000] +/Contents 5 0 R +>> +endobj + +5 0 obj +<< /Length 1074 >> +stream +2 J +BT +0 0 0 rg +/F1 0027 Tf +57.3750 722.2800 Td +( A Simple PDF File ) Tj +ET +BT +/F1 0010 Tf +69.2500 688.6080 Td +( This is a small demonstration .pdf file - ) Tj +ET +BT +/F1 0010 Tf +69.2500 664.7040 Td +( just for use in the Virtual Mechanics tutorials. More text. And more ) Tj +ET +BT +/F1 0010 Tf +69.2500 652.7520 Td +( text. And more text. And more text. And more text. ) Tj +ET +BT +/F1 0010 Tf +69.2500 628.8480 Td +( And more text. And more text. And more text. And more text. And more ) Tj +ET +BT +/F1 0010 Tf +69.2500 616.8960 Td +( text. And more text. Boring, zzzzz. And more text. And more text. And ) Tj +ET +BT +/F1 0010 Tf +69.2500 604.9440 Td +( more text. And more text. And more text. And more text. And more text. ) Tj +ET +BT +/F1 0010 Tf +69.2500 592.9920 Td +( And more text. And more text. ) Tj +ET +BT +/F1 0010 Tf +69.2500 569.0880 Td +( And more text. And more text. And more text. And more text. And more ) Tj +ET +BT +/F1 0010 Tf +69.2500 557.1360 Td +( text. And more text. And more text. Even more. Continued on page 2 ...) Tj +ET +endstream +endobj + +6 0 obj +<< +/Type /Page +/Parent 3 0 R +/Resources << +/Font << +/F1 9 0 R +>> +/ProcSet 8 0 R +>> +/MediaBox [0 0 612.0000 792.0000] +/Contents 7 0 R +>> +endobj + +7 0 obj +<< /Length 676 >> +stream +2 J +BT +0 0 0 rg +/F1 0027 Tf +57.3750 722.2800 Td +( Simple PDF File 2 ) Tj +ET +BT +/F1 0010 Tf +69.2500 688.6080 Td +( ...continued from page 1. Yet more text. And more text. And more text. ) Tj +ET +BT +/F1 0010 Tf +69.2500 676.6560 Td +( And more text. And more text. And more text. And more text. And more ) Tj +ET +BT +/F1 0010 Tf +69.2500 664.7040 Td +( text. Oh, how boring typing this stuff. But not as boring as watching ) Tj +ET +BT +/F1 0010 Tf +69.2500 652.7520 Td +( paint dry. And more text. And more text. And more text. And more text. ) Tj +ET +BT +/F1 0010 Tf +69.2500 640.8000 Td +( Boring. More, a little more text. The end, and just as well. ) Tj +ET +endstream +endobj + +8 0 obj +[/PDF /Text] +endobj + +9 0 obj +<< +/Type /Font +/Subtype /Type1 +/Name /F1 +/BaseFont /Helvetica +/Encoding /WinAnsiEncoding +>> +endobj + +10 0 obj +<< +/Creator (Rave \(http://www.nevrona.com/rave\)) +/Producer (Nevrona Designs) +/CreationDate (D:20060301072826) +>> +endobj + +xref +0 11 +0000000000 65535 f +0000000019 00000 n +0000000093 00000 n +0000000147 00000 n +0000000222 00000 n +0000000390 00000 n +0000001522 00000 n +0000001690 00000 n +0000002423 00000 n +0000002456 00000 n +0000002574 00000 n + +trailer +<< +/Size 11 +/Root 1 0 R +/Info 10 0 R +>> + +startxref +2714 +%%EOF diff --git a/twake/backend/node/test/e2e/files/assets/sample.png b/twake/backend/node/test/e2e/files/assets/sample.png new file mode 100644 index 00000000..e978edb7 Binary files /dev/null and b/twake/backend/node/test/e2e/files/assets/sample.png differ diff --git a/twake/backend/node/test/e2e/files/assets/sample.zip b/twake/backend/node/test/e2e/files/assets/sample.zip new file mode 100644 index 00000000..60516f49 Binary files /dev/null and b/twake/backend/node/test/e2e/files/assets/sample.zip differ diff --git a/twake/backend/node/test/e2e/files/files.spec.ts b/twake/backend/node/test/e2e/files/files.spec.ts new file mode 100644 index 00000000..32f8da32 --- /dev/null +++ b/twake/backend/node/test/e2e/files/files.spec.ts @@ -0,0 +1,72 @@ +import "reflect-metadata"; +import { afterAll, beforeAll, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { ResourceUpdateResponse } from "../../../src/utils/types"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import fs from "fs"; +import { File } from "../../../src/services/files/entities/file"; +import { deserialize } from "class-transformer"; +import formAutoContent from "form-auto-content"; + +describe.skip("The Files feature", () => { + const url = "/internal/services/files/v1"; + let platform: TestPlatform; + + beforeAll(async () => { + platform = await init({ + services: ["webserver", "database", "storage", "message-queue", "files", "previews"], + }); + }); + + afterAll(async done => { + await platform?.tearDown(); + platform = null; + done(); + }); + + describe("On user send files", () => { + const files = [ + "assets/sample.png", + "assets/sample.gif", + "assets/sample.pdf", + "assets/sample.doc", + "assets/sample.zip", + "assets/sample.mp4", + ].map(p => `${__dirname}/${p}`); + const thumbnails = [1, 1, 2, 5, 0, 1]; + + it("should save file and generate previews", async done => { + for (const i in files) { + const file = files[i]; + + const form = formAutoContent({ file: fs.createReadStream(file) }); + form.headers["authorization"] = `Bearer ${await platform.auth.getJWTToken()}`; + + const filesUploadRaw = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/files?thumbnail_sync=1`, + ...form, + }); + const filesUpload: ResourceUpdateResponse = deserialize( + ResourceUpdateResponse, + filesUploadRaw.body, + ); + + expect(filesUpload.resource.id).not.toBeFalsy(); + expect(filesUpload.resource.encryption_key).toBeFalsy(); //This must not be disclosed + expect(filesUpload.resource.thumbnails.length).toBe(thumbnails[i]); + + for (const thumb of filesUpload.resource.thumbnails) { + const thumbnails = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/files/${filesUpload.resource.id}/thumbnails/${thumb.index}`, + }); + expect(thumbnails.statusCode).toBe(200); + } + } + + done(); + }, 120000); + }); +}); diff --git a/twake/backend/node/test/e2e/messages/messages.files.search.spec.ts b/twake/backend/node/test/e2e/messages/messages.files.search.spec.ts new file mode 100644 index 00000000..5da6fcb5 --- /dev/null +++ b/twake/backend/node/test/e2e/messages/messages.files.search.spec.ts @@ -0,0 +1,165 @@ +import "reflect-metadata"; +import { afterAll, beforeAll, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { createMessage, createParticipant, e2e_createThread } from "./utils"; +import { MessageFile } from "../../../src/services/messages/entities/message-files"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import fs from "fs"; +import formAutoContent from "form-auto-content"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import uuid from "node-uuid"; +import { ChannelUtils, get as getChannelUtils } from "../channels/utils"; +import gr from "../../../src/services/global-resolver"; +import User from "../../../src/services/user/entities/user"; +import { WorkspaceExecutionContext } from "../../../src/services/channels/types"; + +describe("Search files", () => { + const filesUrl = "/internal/services/files/v1"; + const messagesUrl = "/internal/services/messages/v1"; + let platform: TestPlatform; + let channelUtils: ChannelUtils; + + beforeAll(async () => { + platform = await init({ + services: ["webserver", "database", "storage", "message-queue", "files", "previews"], + }); + await platform.database.getConnector().drop(); + channelUtils = getChannelUtils(platform); + }); + + afterAll(async done => { + await platform?.tearDown(); + platform = null; + done(); + }); + + const files = [ + "../files/assets/sample.png", + "../files/assets/sample.gif", + "../files/assets/sample.pdf", + "../files/assets/sample.doc", + "../files/assets/sample.zip", + ].map(p => `${__dirname}/${p}`); + + function getContext(user?: User): WorkspaceExecutionContext { + return { + workspace: platform.workspace, + user: user || platform.currentUser, + }; + } + + it("should return uploaded files", async done => { + let channel = channelUtils.getChannel(); + channel = (await gr.services.channels.channels.save(channel, {}, getContext())).entity; + const channelId = channel.id; + + const uploadedFiles = []; + for (const i in files) { + const file = files[i]; + + const form = formAutoContent({ file: fs.createReadStream(file) }); + form.headers["authorization"] = `Bearer ${await platform.auth.getJWTToken()}`; + + const uploadedFile = await platform.app.inject({ + method: "POST", + url: `${filesUrl}/companies/${platform.workspace.company_id}/files?thumbnail_sync=1`, + ...form, + }); + + const resource = uploadedFile.json().resource; + + const messageFile: Partial = { + id: uuid.v1(), + company_id: platform.workspace.company_id, + metadata: { + source: "internal", + external_id: { + company_id: platform.workspace.company_id, + id: resource.id, + }, + ...resource.metadata, + }, + }; + + await e2e_createThread( + platform, + [ + createParticipant( + { + type: "channel", + id: channelId, + }, + platform, + ), + ], + createMessage({ text: "Some message", files: [messageFile] }), + ); + + uploadedFiles.push(uploadedFile.json().resource); + } + + await new Promise(r => setTimeout(r, 2000)); + + let resources = await search("sample"); + expect(resources.length).toEqual(5); + + resources = await search("sample", { extension: "png" }); + expect(resources.length).toEqual(1); + + resources = await search("sample", { is_file: true }); + expect(resources.length).toEqual(3); + + resources = await search("sample", { is_media: true }); + expect(resources.length).toEqual(2); + + resources = await search("sam"); + expect(resources.length).toEqual(5); + + done(); + }); + + async function search( + searchString: string, + options?: { + company_id?: string; + workspace_id?: string; + channel_id?: string; + limit?: number; + sender?: string; + is_file?: boolean; + is_media?: boolean; + extension?: string; + }, + ): Promise { + const jwtToken = await platform.auth.getJWTToken(); + + const query: any = options || {}; + + const response = await platform.app.inject({ + method: "GET", + url: `${messagesUrl}/companies/${platform.workspace.company_id}/files/search`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + query: { + ...query, + q: searchString, + }, + }); + + expect(response.statusCode).toBe(200); + const json = response.json(); + expect(json).toMatchObject({ resources: expect.any(Array) }); + const resources = json.resources; + return resources; + } +}); + +function getContext(platform: TestPlatform) { + return { + company: { id: platform.workspace.company_id }, + user: { id: platform.currentUser.id }, + }; +} diff --git a/twake/backend/node/test/e2e/messages/messages.files.spec.ts b/twake/backend/node/test/e2e/messages/messages.files.spec.ts new file mode 100644 index 00000000..01b50f79 --- /dev/null +++ b/twake/backend/node/test/e2e/messages/messages.files.spec.ts @@ -0,0 +1,364 @@ +import "reflect-metadata"; +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { ResourceUpdateResponse } from "../../../src/utils/types"; +import { deserialize } from "class-transformer"; +import { Thread } from "../../../src/services/messages/entities/threads"; +import { createMessage, e2e_createThread } from "./utils"; +import { MessageFile } from "../../../src/services/messages/entities/message-files"; +import { Message } from "../../../src/services/messages/entities/messages"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import fs from "fs"; +import formAutoContent from "form-auto-content"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import uuid, { v1 } from "node-uuid"; + +describe("The Messages Files feature", () => { + const url = "/internal/services/messages/v1"; + let platform: TestPlatform; + + beforeEach(async () => { + platform = await init({ + services: [ + "webserver", + "database", + "applications", + "search", + "storage", + "message-queue", + "user", + "search", + "files", + "websocket", + "messages", + "auth", + "realtime", + "channels", + "counter", + "statistics", + "platform-services", + ], + }); + }); + + afterEach(async () => { + await platform.tearDown(); + }); + + describe("On user send files", () => { + it("did add the files when full information is given (external source)", async done => { + const file: MessageFile = { + cache: { channel_id: "", company_id: "", user_id: "", workspace_id: "" }, + company_id: "", + created_at: 0, + id: "", + metadata: { + source: "linshare", + external_id: "1234", + name: "My LinShare File", + thumbnails: [], + }, + }; + + const response = await e2e_createThread( + platform, + [], + createMessage({ text: "Some message", files: [file] }), + ); + const result: ResourceUpdateResponse = deserialize( + ResourceUpdateResponse, + response.body, + ); + + expect(result.resource.message.files.length).toBe(1); + expect(result.resource.message.files[0].id).not.toBeFalsy(); + expect(result.resource.message.files[0].message_id).not.toBeFalsy(); + expect(result.resource.message.files[0].metadata.external_id).toBe("1234"); + expect(result.resource.message.files[0].metadata.source).toBe("linshare"); + + done(); + }); + + it("did not deduplicate files", async done => { + const file: MessageFile = { + cache: { channel_id: "", company_id: "", user_id: "", workspace_id: "" }, + company_id: "", + created_at: 0, + id: "", + metadata: { + source: "linshare", + external_id: "1234", + name: "My LinShare File", + thumbnails: [], + }, + }; + + const file2: MessageFile = { + cache: { channel_id: "", company_id: "", user_id: "", workspace_id: "" }, + company_id: "", + created_at: 0, + id: "", + metadata: { + source: "linshare2", + external_id: "5678", + name: "My LinShare 2 File", + thumbnails: [], + }, + }; + + const response = await e2e_createThread( + platform, + [], + createMessage({ text: "Some message", files: [file] }), + ); + const result: ResourceUpdateResponse = deserialize( + ResourceUpdateResponse, + response.body, + ); + + const message = result.resource.message; + const firstFileId = message.files[0].id; + + message.files.push(file2); + + const messageUpdatedRaw = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/threads/${message.thread_id}/messages/${message.id}`, + headers: { + authorization: `Bearer ${await platform.auth.getJWTToken()}`, + }, + payload: { + resource: message, + }, + }); + const messageUpdated: ResourceUpdateResponse = deserialize( + ResourceUpdateResponse, + messageUpdatedRaw.body, + ); + + expect(messageUpdated.resource.files.length).toBe(2); + expect(messageUpdated.resource.files.filter(f => f.id === firstFileId).length).toBe(1); + + done(); + }); + }); +}); + +describe("List user files", () => { + const filesUrl = "/internal/services/files/v1"; + const messagesUrl = "/internal/services/messages/v1"; + let platform: TestPlatform; + + beforeAll(async () => { + platform = await init({ + services: ["webserver", "database", "storage", "message-queue", "files", "previews"], + }); + await platform.database.getConnector().drop(); + }); + + afterAll(async done => { + await platform?.tearDown(); + platform = null; + done(); + }); + + const files = [ + "../files/assets/sample.png", + "../files/assets/sample.gif", + "../files/assets/sample.pdf", + "../files/assets/sample.doc", + "../files/assets/sample.zip", + ].map(p => `${__dirname}/${p}`); + + it("should return uploaded files", async done => { + const jwtToken = await platform.auth.getJWTToken(); + + const uploadedFiles = []; + + for (const i in files) { + const file = files[i]; + + const form = formAutoContent({ file: fs.createReadStream(file) }); + form.headers["authorization"] = `Bearer ${await platform.auth.getJWTToken()}`; + + const uploadedFile = await platform.app.inject({ + method: "POST", + url: `${filesUrl}/companies/${platform.workspace.company_id}/files?thumbnail_sync=1`, + ...form, + }); + + expect(uploadedFile.statusCode).toBe(200); + + const resource = uploadedFile.json().resource; + + const messageFile: MessageFile = { + cache: { channel_id: "", company_id: "", user_id: "", workspace_id: "" }, + created_at: 0, + id: uuid.v1(), + company_id: platform.workspace.company_id, + metadata: { + source: "internal", + external_id: { + company_id: platform.workspace.company_id, + id: resource.id, + }, + ...resource.metadata, + }, + }; + + await e2e_createThread( + platform, + [], + createMessage({ text: "Some message", files: [messageFile] }), + ); + + uploadedFiles.push(uploadedFile.json().resource); + } + + function checkResource(resource) { + expect(resource).toMatchObject({ + company_id: expect.any(String), + id: expect.any(String), + created_at: expect.any(Number), + metadata: expect.any(Object), + }); + } + + let response = await platform.app.inject({ + method: "GET", + url: `${messagesUrl}/companies/${platform.workspace.company_id}/files?type=user_upload&limit=3`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + await new Promise(resolve => setTimeout(resolve, 1000)); + + expect(response.statusCode).toBe(200); + + let resources = response.json().resources; + expect(resources.length).toBe(3); + + resources.forEach(checkResource); + + const nextPageToken = response.json().next_page_token; + + response = await platform.app.inject({ + method: "GET", + url: `${messagesUrl}/companies/${platform.workspace.company_id}/files?type=user_upload&page_token=${nextPageToken}limit=100`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + await new Promise(resolve => setTimeout(resolve, 1000)); + + expect(response.statusCode).toBe(200); + + resources = response.json().resources; + expect(resources.length).toBe(5); + + expect(response.json().resources[0]).toMatchObject({ + company_id: expect.any(String), + id: expect.any(String), + created_at: expect.any(Number), + metadata: expect.any(Object), + user: expect.any(Object), + context: expect.any(Object), + }); + + resources.forEach(checkResource); + + done(); + }); + + it("should return downloaded files", async done => { + const jwtToken = await platform.auth.getJWTToken({ sub: v1() }); + const uploadedFiles = []; + for (const i in files) { + const file = files[i]; + + const form = formAutoContent({ file: fs.createReadStream(file) }); + form.headers["authorization"] = `Bearer ${await platform.auth.getJWTToken()}`; + + const uploadedFile = await platform.app.inject({ + method: "POST", + url: `${filesUrl}/companies/${platform.workspace.company_id}/files?thumbnail_sync=1`, + ...form, + }); + + const resource = uploadedFile.json().resource; + + const messageFile: MessageFile = { + cache: { channel_id: "", company_id: "", user_id: "", workspace_id: "" }, + created_at: 0, + id: uuid.v1(), + company_id: platform.workspace.company_id, + metadata: { + source: "internal", + external_id: { + company_id: platform.workspace.company_id, + id: resource.id, + }, + ...resource.metadata, + }, + }; + + const thread = await e2e_createThread( + platform, + [], + createMessage({ text: "Some message", files: [messageFile] }), + ); + + uploadedFiles.push(uploadedFile.json().resource); + + await platform.app.inject({ + method: "POST", + url: `${messagesUrl}/companies/${platform.workspace.company_id}/threads/${ + thread.json().resource.message.thread_id + }/messages/${thread.json().resource.message.id}/download/${ + thread.json().resource.message.files[0].id + }`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + } + + await new Promise(resolve => setTimeout(resolve, 1000)); + + const response = await platform.app.inject({ + method: "GET", + url: `${messagesUrl}/companies/${platform.workspace.company_id}/files?type=user_download`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + await new Promise(resolve => setTimeout(resolve, 1000)); + + expect(response.statusCode).toBe(200); + + expect(response.json().resources.length).toBe(5); + + expect(response.json().resources[0]).toMatchObject({ + company_id: expect.any(String), + id: expect.any(String), + created_at: expect.any(Number), + metadata: expect.any(Object), + user: expect.any(Object), + context: expect.any(Object), + }); + + done(); + }); +}); + +function getContext(platform: TestPlatform) { + return { + company: { id: platform.workspace.company_id }, + user: { id: platform.currentUser.id }, + }; +} diff --git a/twake/backend/node/test/e2e/messages/messages.messages.spec.ts b/twake/backend/node/test/e2e/messages/messages.messages.spec.ts new file mode 100644 index 00000000..2d30b256 --- /dev/null +++ b/twake/backend/node/test/e2e/messages/messages.messages.spec.ts @@ -0,0 +1,199 @@ +import "reflect-metadata"; +import { afterEach, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { + ResourceListResponse, + ResourceUpdateResponse, + User, + Workspace, +} from "../../../src/utils/types"; +import { deserialize } from "class-transformer"; +import { ParticipantObject, Thread } from "../../../src/services/messages/entities/threads"; +import { + createMessage, + createParticipant, + e2e_createChannel, + e2e_createMessage, + e2e_createThread, +} from "./utils"; +import { Message } from "../../../src/services/messages/entities/messages"; +import { v1 as uuidv1 } from "uuid"; +import { MessageWithReplies } from "../../../src/services/messages/types"; +import { TestDbService } from "../utils.prepare.db"; +import gr from "../../../src/services/global-resolver"; +import { ChannelVisibility, WorkspaceExecutionContext } from "../../../src/services/channels/types"; +import { ChannelSaveOptions } from "../../../src/services/channels/web/types"; +import { ChannelUtils, get as getChannelUtils } from "../channels/utils"; + +describe("The Messages feature", () => { + const url = "/internal/services/messages/v1"; + let platform: TestPlatform; + let testDbService: TestDbService; + let channelUtils: ChannelUtils; + + function getContext(user?: User): WorkspaceExecutionContext { + return { + workspace: platform.workspace, + user: user || platform.currentUser, + }; + } + + beforeAll(async () => { + platform = await init({ + services: [ + "webserver", + "database", + "search", + "storage", + "message-queue", + "applications", + "user", + "websocket", + "webserver", + "messages", + "files", + "auth", + "search", + "realtime", + "channels", + "counter", + "statistics", + "platform-services", + ], + }); + await gr.database.getConnector().drop(); + + channelUtils = getChannelUtils(platform); + }); + + afterEach(async () => { + await platform.tearDown(); + }); + + describe("On user use messages in a thread", () => { + it("should create a message in a thread", async () => { + const response = await e2e_createThread( + platform, + [], + createMessage({ text: "Initial thread message" }), + ); + const result: ResourceUpdateResponse = deserialize( + ResourceUpdateResponse, + response.body, + ); + const threadId = result.resource.id; + + await e2e_createMessage(platform, threadId, createMessage({ text: "Reply 1" })); + + await e2e_createMessage(platform, threadId, createMessage({ text: "Reply 2" })); + + const jwtToken = await platform.auth.getJWTToken(); + const listResponse = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/threads/${threadId}/messages`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + const listResult: ResourceListResponse = deserialize( + ResourceListResponse, + listResponse.body, + ); + + expect(listResponse.statusCode).toBe(200); + expect(listResult.resources.length).toBe(3); + }); + }); + + describe("Inbox", () => { + it("Should get recent user messages", async done => { + const directChannelIn = channelUtils.getDirectChannel(); + const members = [platform.currentUser.id, uuidv1()]; + const directWorkspace: Workspace = { + company_id: platform.workspace.company_id, + workspace_id: ChannelVisibility.DIRECT, + }; + + await Promise.all([ + gr.services.channels.channels.save( + directChannelIn, + { + members, + }, + { ...getContext(), ...{ workspace: directWorkspace } }, + ), + ]); + + const recipient: ParticipantObject = { + created_at: 0, + created_by: "", + type: "channel", + company_id: directChannelIn.company_id, + workspace_id: "direct", + id: directChannelIn.id, + }; + + for (let i = 0; i < 6; i++) { + const response = await e2e_createThread( + platform, + [recipient], + createMessage({ text: `Initial thread message ${i}` }), + ); + const result: ResourceUpdateResponse = deserialize( + ResourceUpdateResponse, + response.body, + ); + const threadId = result.resource.id; + + const replies = []; + for (let j = 0; j < 3; j++) { + replies.push( + e2e_createMessage( + platform, + threadId, + createMessage({ text: `Reply ${j} to message ${i}` }), + ), + ); + } + await Promise.all(replies); + } + + const jwtToken = await platform.auth.getJWTToken({ sub: members[0] }); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/inbox?limit=5`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + expect(response.statusCode).toEqual(200); + + const inbox: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + expect(inbox.resources.length).toEqual(5); + + for (const resource of inbox.resources) { + expect(resource).toMatchObject({ + id: expect.any(String), + thread_id: expect.any(String), + created_at: expect.any(Number), + updated_at: expect.any(Number), + user_id: platform.currentUser.id, + application_id: null, + text: expect.any(String), + cache: { + company_id: directChannelIn.company_id, + channel_id: directChannelIn.id, + }, + }); + } + + done(); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/messages/messages.search.spec.ts b/twake/backend/node/test/e2e/messages/messages.search.spec.ts new file mode 100644 index 00000000..f1c3afde --- /dev/null +++ b/twake/backend/node/test/e2e/messages/messages.search.spec.ts @@ -0,0 +1,264 @@ +import { afterAll, beforeAll, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { TestDbService } from "../utils.prepare.db"; +import { v1 as uuidv1 } from "uuid"; +import { createMessage, e2e_createChannel, e2e_createMessage, e2e_createThread } from "./utils"; +import { ResourceUpdateResponse } from "../../../src/utils/types"; +import { ParticipantObject, Thread } from "../../../src/services/messages/entities/threads"; +import { deserialize } from "class-transformer"; +import { Channel } from "../../../src/services/channels/entities"; +import { ChannelUtils, get as getChannelUtils } from "../channels/utils"; +import { MessageFile } from "../../../src/services/messages/entities/message-files"; +import gr from "../../../src/services/global-resolver"; + +describe("The /messages API", () => { + const url = "/internal/services/messages/v1"; + let platform: TestPlatform; + let channelUtils: ChannelUtils; + + beforeAll(async ends => { + platform = await init({ + services: [ + "database", + "search", + "message-queue", + "websocket", + "webserver", + "user", + "auth", + "applications", + "storage", + "counter", + "workspaces", + "console", + "statistics", + "platform-services", + ], + }); + + await platform.database.getConnector().drop(); + channelUtils = getChannelUtils(platform); + + const testDbService = new TestDbService(platform); + await testDbService.createCompany(platform.workspace.company_id); + + const workspacePk = { + id: platform.workspace.workspace_id, + company_id: platform.workspace.company_id, + }; + + const workspacePk2 = { + id: uuidv1(), + company_id: uuidv1(), + }; + await testDbService.createWorkspace(workspacePk); + + const user = await testDbService.createUser([workspacePk], {}); + + platform.currentUser.id = user.id; + + ends(); + }); + + afterAll(async ends => { + platform && (await platform.tearDown()); + platform = null; + ends(); + }); + + describe("The GET /messages/?search=... route", () => { + it("Should find the searched messages", async done => { + // await testDbService.createWorkspace(workspacePk2); + + const channel = await createChannel(); + + const participant = { + type: "channel", + id: channel.id, + company_id: platform.workspace.company_id, + workspace_id: platform.workspace.workspace_id, + } as ParticipantObject; + + const firstThreadId = await createThread("First thread", [participant]); + await createReply(firstThreadId, "First reply of first thread"); + await createReply(firstThreadId, "Second reply of first thread"); + + const secondThreadId = await createThread("Another thread", [participant]); + await createReply(secondThreadId, "First reply of second thread"); + await createReply(secondThreadId, "Second reply of second thread is also a message"); + + //Wait for indexation to happen + await new Promise(r => setTimeout(r, 3000)); + + let resources = await search("Reply"); + expect(resources.length).toEqual(4); + + resources = await search("fdfsd"); + expect(resources.length).toEqual(0); + + resources = await search("first"); + expect(resources.length).toEqual(4); + + resources = await search("second"); + expect(resources.length).toEqual(3); + + resources = await search("another"); + expect(resources.length).toEqual(1); + + resources = await search("also"); + expect(resources.length).toEqual(1); + + resources = await search("of"); + expect(resources.length).toEqual(4); + + resources = await search("a"); + + //sleep 1s + await new Promise(r => setTimeout(r, 2000)); + + expect(resources.length).toEqual(1); + + done(); + }); + it("Filter out messages from channels we are not member of", async done => { + const anotherUserId = uuidv1(); + const channel = await e2e_createChannel(platform, [platform.currentUser.id, anotherUserId]); + const anotherChannel = await e2e_createChannel(platform, [anotherUserId], anotherUserId); //Test user is not the owner + + const participant = { + type: "channel", + id: channel.resource.id, + company_id: channel.resource.company_id, + workspace_id: channel.resource.workspace_id, + } as ParticipantObject; + + const participant2 = { + type: "channel", + id: anotherChannel.resource.id, + company_id: anotherChannel.resource.company_id, + workspace_id: anotherChannel.resource.workspace_id, + } as ParticipantObject; + + const file = new MessageFile(); + file.metadata = { external_id: undefined, source: undefined, name: "test" }; + + const firstThreadId = await createThread("Filtered thread", [participant]); + await createReply(firstThreadId, "Filtered message 1-1"); + await createReply(firstThreadId, "Filtered message 1-2"); + await createReply(firstThreadId, "Filtered message 1-3"); + await createReply(firstThreadId, "Filtered message 1-4", { files: [file] }); + + const secondThreadId = await createThread("Filtered thread 2", [participant2], anotherUserId); + await createReply(secondThreadId, "Filtered message 2-1"); + await createReply(secondThreadId, "Filtered message 2-2"); + await createReply(secondThreadId, "Filtered message 2-3"); + await createReply(secondThreadId, "Filtered message 2-4"); + + const thirdThreadId = await createThread("Filtered thread 3", [participant]); + await createReply(thirdThreadId, "Filtered message 3-1"); + await createReply(thirdThreadId, "Filtered message 3-2", { userId: anotherUserId }); + await createReply(thirdThreadId, "Filtered message 3-3", { userId: anotherUserId }); + await createReply(thirdThreadId, "Filtered message 3-4", { + userId: anotherUserId, + files: [file], + }); + + //Wait for indexation to happen + await new Promise(r => setTimeout(r, 3000)); + + // no limit + const resources0 = await search("Filtered", { limit: 10000 }); + expect(resources0.length).toEqual(10); + + const resources = await search("Filtered", { limit: 9 }); + expect(resources.length).toEqual(9); + + // check for the empty result set + const resources2 = await search("Nothing", { limit: 10 }); + expect(resources2.length).toEqual(0); + + // check for the user + const resources3 = await search("Filtered", { sender: anotherUserId }); + expect(resources3.length).toEqual(3); + + // check for the files + const resources4 = await search("Filtered", { has_files: true }); + expect(resources4.length).toEqual(2); + + // check for the user and files + const resources5 = await search("Filtered", { sender: anotherUserId, has_files: true }); + expect(resources5.length).toEqual(1); + + done(); + }); + }); + + async function createChannel(userId = platform.currentUser.id): Promise { + const channel = channelUtils.getChannel(userId); + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + channelUtils.getContext({ id: userId }), + ); + + return creationResult.entity; + } + + async function createThread(text, participants: ParticipantObject[], owner?: string) { + const response = await e2e_createThread( + platform, + participants, + createMessage({ text: text, user_id: owner }), + owner, + ); + + const result: ResourceUpdateResponse = deserialize( + ResourceUpdateResponse, + response.body, + ); + return result.resource.id; + } + + async function createReply(threadId, text, options?: { userId?: string; files?: MessageFile[] }) { + const cr = options?.userId ? { currentUser: { id: options?.userId } } : undefined; + + const message = { text, ...(options?.files ? { files: options.files } : {}) }; + + return e2e_createMessage(platform, threadId, createMessage(message, cr as TestPlatform)); + } + + async function search( + searchString: string, + options?: { + company_id?: string; + workspace_id?: string; + channel_id?: string; + limit?: number; + sender?: string; + has_files?: boolean; + }, + ): Promise { + const jwtToken = await platform.auth.getJWTToken(); + + const query: any = options || {}; + + const response = await platform.app.inject({ + method: "GET", + // url: `${url}/companies/${platform.workspace.company_id}/woskpaces/`, + url: `${url}/companies/${platform.workspace.company_id}/search`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + query: { + ...query, + q: searchString, + }, + }); + + expect(response.statusCode).toBe(200); + const json = response.json(); + expect(json).toMatchObject({ resources: expect.any(Array) }); + const resources = json.resources; + return resources; + } +}); diff --git a/twake/backend/node/test/e2e/messages/messages.threads.spec.ts b/twake/backend/node/test/e2e/messages/messages.threads.spec.ts new file mode 100644 index 00000000..98d798a2 --- /dev/null +++ b/twake/backend/node/test/e2e/messages/messages.threads.spec.ts @@ -0,0 +1,249 @@ +import "reflect-metadata"; +import { afterEach, beforeEach, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { ResourceUpdateResponse } from "../../../src/utils/types"; +import { deserialize } from "class-transformer"; +import { v1 as uuidv1, v4 as uuidv4 } from "uuid"; +import { Thread } from "../../../src/services/messages/entities/threads"; +import { createMessage, createParticipant, e2e_createThread } from "./utils"; +import gr from "../../../src/services/global-resolver"; + +describe("The Messages Threads feature", () => { + const url = "/internal/services/messages/v1"; + let platform: TestPlatform; + + beforeEach(async () => { + platform = await init({ + services: [ + "webserver", + "database", + "applications", + "search", + "storage", + "message-queue", + "user", + "search", + "files", + "websocket", + "messages", + "auth", + "realtime", + "channels", + "counter", + "statistics", + "platform-services", + ], + }); + }); + + afterEach(async () => { + await platform.tearDown(); + }); + + describe("On user manage threads", () => { + it("should create new thread", async done => { + const response = await e2e_createThread( + platform, + [ + createParticipant( + { + type: "user", + id: platform.currentUser.id, + }, + platform, + ), + ], + createMessage( + { + text: "Hello!", + }, + platform, + ), + ); + + const result: ResourceUpdateResponse = deserialize( + ResourceUpdateResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resource?.created_by).toBe(platform.currentUser.id); + expect(result.resource.participants.length).toBe(1); + expect(result.resource.participants[0]).toMatchObject({ + type: "user", + id: platform.currentUser.id, + created_by: platform.currentUser.id, + }); + expect(result.resource.participants[0].created_at).toBeDefined(); + + done(); + }); + + it("should enforce requester in thread participants", async done => { + const response = await e2e_createThread( + platform, + [ + createParticipant( + { + type: "user", + id: uuidv1(), + }, + platform, + ), + ], + createMessage( + { + text: "Hello!", + }, + platform, + ), + ); + + const result: ResourceUpdateResponse = deserialize( + ResourceUpdateResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resource).toMatchObject({ + created_by: platform.currentUser.id, + }); + expect(result.resource.participants.length).toBe(2); + expect( + result.resource.participants.filter(p => p.id === platform.currentUser.id)[0], + ).toMatchObject({ + type: "user", + id: platform.currentUser.id, + }); + + done(); + }); + + it("should update thread participants when add participant", async done => { + //Create thread + const thread = await gr.services.messages.threads.save( + { + id: undefined, + participants: [ + { + type: "user", + id: platform.currentUser.id, + company_id: platform.workspace.company_id, + }, + ], + }, + { + message: createMessage( + { + text: "Hello!", + }, + platform, + ), + }, + getContext(platform), + ); + + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/threads/${thread.entity.id}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: {}, + options: { + participants: { + add: [ + { + type: "user", + id: uuidv1(), + }, + ], + }, + }, + }, + }); + + const result: ResourceUpdateResponse = deserialize( + ResourceUpdateResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resource.participants.length).toBe(2); + + done(); + }); + + it("should update thread participants when remove participant", async done => { + //Create thread + const thread = await gr.services.messages.threads.save( + { + id: undefined, + participants: [ + { + type: "user", + id: platform.currentUser.id, + company_id: platform.workspace.company_id, + }, + { + type: "channel", + id: uuidv4(), + workspace_id: platform.workspace.workspace_id, + company_id: platform.workspace.company_id, + }, + ], + }, + { + message: createMessage( + { + text: "Hello!", + }, + platform, + ), + }, + getContext(platform), + ); + + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/threads/${thread.entity.id}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: {}, + options: { + participants: { + remove: [ + { + type: "user", + id: platform.currentUser.id, + }, + ], + }, + }, + }, + }); + + const result: ResourceUpdateResponse = deserialize( + ResourceUpdateResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resource.participants.length).toBe(1); + + done(); + }); + }); +}); + +function getContext(platform: TestPlatform) { + return { + company: { id: platform.workspace.company_id }, + user: { id: platform.currentUser.id }, + }; +} diff --git a/twake/backend/node/test/e2e/messages/messages.user-bookmarks.realtime.spec.ts b/twake/backend/node/test/e2e/messages/messages.user-bookmarks.realtime.spec.ts new file mode 100644 index 00000000..a407e009 --- /dev/null +++ b/twake/backend/node/test/e2e/messages/messages.user-bookmarks.realtime.spec.ts @@ -0,0 +1,143 @@ +import "reflect-metadata"; +import { afterEach, beforeEach, describe, expect, it } from "@jest/globals"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import io from "socket.io-client"; +import { init, TestPlatform } from "../setup"; +import gr from "../../../src/services/global-resolver"; + +describe("The Bookmarks Realtime feature", () => { + const url = "/internal/services/messages/v1"; + let platform: TestPlatform; + let socket: SocketIOClient.Socket; + + beforeEach(async () => { + platform = await init({ + services: [ + "webserver", + "database", + "search", + "storage", + "message-queue", + "files", + "user", + "websocket", + "webserver", + "messages", + "applications", + "auth", + "search", + "realtime", + "channels", + "counter", + "statistics", + "platform-services", + ], + }); + }); + + afterEach(async () => { + await platform.tearDown(); + platform = null; + }); + + function connect() { + socket = io.connect("http://localhost:3000", { path: "/socket" }); + socket.connect(); + } + + describe("On bookmark creation", () => { + it("should notify the client", async done => { + const jwtToken = await platform.auth.getJWTToken(); + const roomToken = "twake"; + + connect(); + socket.on("connect", () => { + socket + .emit("authenticate", { token: jwtToken }) + .on("authenticated", () => { + socket.on("realtime:join:error", () => done(new Error("Should not occur"))); + socket.on("realtime:join:success", async () => { + await gr.services.messages.userBookmarks.save( + { + company_id: platform.workspace.company_id, + user_id: platform.currentUser.id, + name: "mybookmarksaved", + id: undefined, + }, + getContext(platform), + ); + }); + socket.on("realtime:resource", (event: any) => { + expect(event.type).toEqual("user_message_bookmark"); + expect(event.action).toEqual("saved"); + expect(event.resource.name).toEqual("mybookmarksaved"); + done(); + }); + socket.emit("realtime:join", { + name: `/companies/${platform.workspace.company_id}/messages/bookmarks`, + token: roomToken, + }); + }) + .on("unauthorized", () => { + done(new Error("Should not occur")); + }); + }); + }); + }); + + describe("On bookmark removal", () => { + it("should notify the client", async done => { + const instance = await gr.services.messages.userBookmarks.save( + { + company_id: platform.workspace.company_id, + user_id: platform.currentUser.id, + name: "mybookmark", + id: undefined, + }, + getContext(platform), + ); + + const jwtToken = await platform.auth.getJWTToken(); + const roomToken = "twake"; + + connect(); + socket.on("connect", () => { + socket + .emit("authenticate", { token: jwtToken }) + .on("authenticated", () => { + socket.on("realtime:join:error", () => done(new Error("Should not occur"))); + socket.on("realtime:join:success", async () => { + await gr.services.messages.userBookmarks.delete( + { + company_id: platform.workspace.company_id, + user_id: platform.currentUser.id, + id: instance.entity.id, + }, + getContext(platform), + ); + }); + socket.on("realtime:resource", (event: any) => { + expect(event.type).toEqual("user_message_bookmark"); + expect(event.action).toEqual("deleted"); + done(); + }); + socket.emit("realtime:join", { + name: `/companies/${platform.workspace.company_id}/messages/bookmarks`, + token: roomToken, + }); + }) + .on("unauthorized", () => { + done(new Error("Should not occur")); + }); + }); + }); + }); +}); + +function getContext(platform: TestPlatform) { + return { + company: { id: platform.workspace.company_id }, + user: { id: platform.currentUser.id }, + }; +} diff --git a/twake/backend/node/test/e2e/messages/messages.user-bookmarks.spec.ts b/twake/backend/node/test/e2e/messages/messages.user-bookmarks.spec.ts new file mode 100644 index 00000000..68cb0240 --- /dev/null +++ b/twake/backend/node/test/e2e/messages/messages.user-bookmarks.spec.ts @@ -0,0 +1,217 @@ +import "reflect-metadata"; +import { afterEach, beforeEach, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { UserMessageBookmark } from "../../../src/services/messages/entities/user-message-bookmarks"; +import { ResourceListResponse, ResourceUpdateResponse } from "../../../src/utils/types"; +import { deserialize } from "class-transformer"; +import { v4 as uuidv4 } from "uuid"; +import gr from "../../../src/services/global-resolver"; + +describe("The Messages User Bookmarks feature", () => { + const url = "/internal/services/messages/v1"; + let platform: TestPlatform; + + beforeEach(async () => { + platform = await init({ + services: [ + "webserver", + "database", + "search", + "files", + "storage", + "applications", + "message-queue", + "user", + "search", + "websocket", + "messages", + "auth", + "realtime", + "channels", + "counter", + "statistics", + "platform-services", + ], + }); + }); + + afterEach(async () => { + await platform.tearDown(); + }); + + describe("On user manage bookmmarks", () => { + it("should create new bookmark", async done => { + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/preferences/bookmarks/`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: { + name: "mybookmark", + }, + }, + }); + + const result: ResourceUpdateResponse = deserialize( + ResourceUpdateResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resource).toMatchObject({ + user_id: platform.currentUser.id, + name: "mybookmark", + }); + + const context = getContext(platform); + + const list = await gr.services.messages.userBookmarks.list({ + user_id: context.user.id, + company_id: context.company.id, + }); + expect(list.getEntities().length).toBe(1); + + done(); + }); + + it("should prevent duplicated bookmark", async done => { + // const uuid = uuidv4(); + + const context = getContext(platform); + + const data = await gr.services.messages.userBookmarks.save( + { + company_id: platform.workspace.company_id, + user_id: platform.currentUser.id, + name: "mybookmark", + test: "123", + }, + context, + ); + const uuid = data.entity.id; + + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/preferences/bookmarks/`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: { + name: "mybookmark", + }, + }, + }); + + const result: ResourceUpdateResponse = deserialize( + ResourceUpdateResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resource).toMatchObject({ + id: uuid, + user_id: platform.currentUser.id, + name: "mybookmark", + }); + + const list = await gr.services.messages.userBookmarks.list({ + user_id: context.user.id, + company_id: context.company.id, + }); + expect(list.getEntities().length).toBe(1); + + done(); + }); + + it("should remove bookmark", async done => { + const id = uuidv4(); + const context = getContext(platform); + + await gr.services.messages.userBookmarks.save( + { + id, + company_id: platform.workspace.company_id, + user_id: platform.currentUser.id, + name: "mybookmark", + }, + context, + ); + + let list = await gr.services.messages.userBookmarks.list({ + user_id: context.user.id, + company_id: context.company.id, + }); + expect(list.getEntities().length).toBe(1); + + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${platform.workspace.company_id}/preferences/bookmarks/${id}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + expect(response.statusCode).toBe(200); + + list = await gr.services.messages.userBookmarks.list({ + user_id: context.user.id, + company_id: context.company.id, + }); + expect(list.getEntities().length).toBe(0); + + done(); + }); + + it("should list bookmarks", async done => { + const context = getContext(platform); + + await gr.services.messages.userBookmarks.save( + { + id: uuidv4(), + company_id: platform.workspace.company_id, + user_id: platform.currentUser.id, + name: "mybookmark", + }, + context, + ); + + const list = await gr.services.messages.userBookmarks.list({ + user_id: context.user.id, + company_id: context.company.id, + }); + expect(list.getEntities().length).toBe(1); + + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/preferences/bookmarks`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + const result: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + expect(response.statusCode).toBe(200); + expect(result.resources.length).toBe(1); + expect(result.resources[0].name).toBe("mybookmark"); + done(); + }); + }); +}); + +function getContext(platform: TestPlatform) { + return { + company: { id: platform.workspace.company_id }, + user: { id: platform.currentUser.id }, + }; +} diff --git a/twake/backend/node/test/e2e/messages/messages.views.channel.spec.ts b/twake/backend/node/test/e2e/messages/messages.views.channel.spec.ts new file mode 100644 index 00000000..14b00298 --- /dev/null +++ b/twake/backend/node/test/e2e/messages/messages.views.channel.spec.ts @@ -0,0 +1,144 @@ +import "reflect-metadata"; +import { afterEach, beforeEach, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { ResourceListResponse, ResourceUpdateResponse } from "../../../src/utils/types"; +import { deserialize } from "class-transformer"; +import { v4 as uuidv4 } from "uuid"; +import { Thread } from "../../../src/services/messages/entities/threads"; +import { + createMessage, + createParticipant, + e2e_createChannel, + e2e_createMessage, + e2e_createThread, +} from "./utils"; +import { MessageWithReplies } from "../../../src/services/messages/types"; + +describe("The Messages feature", () => { + const url = "/internal/services/messages/v1"; + let platform: TestPlatform; + + beforeEach(async () => { + platform = await init({ + services: [ + "webserver", + "database", + "search", + "storage", + "files", + "applications", + "message-queue", + "user", + "websocket", + "messages", + "auth", + "search", + "realtime", + "channels", + "counter", + "statistics", + "platform-services", + ], + }); + }); + + afterEach(async () => { + await platform.tearDown(); + }); + + describe("On user use messages in channel view", () => { + it("should create a message and retrieve it in channel view", async () => { + const channel = await e2e_createChannel(platform, [platform.currentUser.id]); + + const response = await e2e_createThread( + platform, + [ + createParticipant( + { + type: "channel", + id: channel.resource.id, + workspace_id: channel.resource.workspace_id, + company_id: channel.resource.company_id, + }, + platform, + ), + ], + createMessage({ text: "Initial thread 1 message" }), + ); + const result: ResourceUpdateResponse = deserialize( + ResourceUpdateResponse, + response.body, + ); + const threadId = result.resource.id; + + await e2e_createMessage(platform, threadId, createMessage({ text: "Reply 1" })); + + await e2e_createMessage(platform, threadId, createMessage({ text: "Reply 2" })); + + await e2e_createThread( + platform, + [ + createParticipant( + { + type: "channel", + id: channel.resource.id, + workspace_id: channel.resource.workspace_id, + company_id: channel.resource.company_id, + }, + platform, + ), + ], + createMessage({ text: "Initial thread 2 message" }), + ); + + await e2e_createMessage(platform, threadId, createMessage({ text: "Reply 3" })); + + await e2e_createThread( + platform, + [ + createParticipant( + { + type: "channel", + id: channel.resource.id, + workspace_id: channel.resource.workspace_id, + company_id: channel.resource.company_id, + }, + platform, + ), + ], + createMessage({ text: "Initial thread 3 message" }), + ); + + const jwtToken = await platform.auth.getJWTToken(); + const listResponse = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${channel.resource.company_id}/workspaces/${channel.resource.workspace_id}/channels/${channel.resource.id}/feed?replies_per_thread=3&include_users=1`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + const listResult: ResourceListResponse = deserialize( + ResourceListResponse, + listResponse.body, + ); + + await new Promise(resolve => setTimeout(resolve, 5000)); + + expect(listResponse.statusCode).toBe(200); + expect(listResult.resources.length).toBe(3); + + expect(listResult.resources[0].text).toBe("Initial thread 2 message"); + expect(listResult.resources[1].text).toBe("Initial thread 1 message"); + expect(listResult.resources[2].text).toBe("Initial thread 3 message"); + + expect(listResult.resources[0].stats.replies).toBe(1); + expect(listResult.resources[1].stats.replies).toBe(4); //Thread initial message + 3 replies + expect(listResult.resources[2].stats.replies).toBe(1); + + expect(listResult.resources[1].last_replies.length).toBe(3); //We requested 3 replies per posts + expect(listResult.resources[1].last_replies[0].text).toBe("Reply 1"); //Check order is OK + expect(listResult.resources[1].last_replies[2].text).toBe("Reply 3"); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/messages/utils.ts b/twake/backend/node/test/e2e/messages/utils.ts new file mode 100644 index 00000000..6a5380ec --- /dev/null +++ b/twake/backend/node/test/e2e/messages/utils.ts @@ -0,0 +1,114 @@ +import { deserialize } from "class-transformer"; +import { + getInstance as getMessageInstance, + Message, +} from "../../../src/services/messages/entities/messages"; +import { ParticipantObject } from "../../../src/services/messages/entities/threads"; +import { Channel, ResourceCreateResponse } from "../../../src/utils/types"; +import { TestPlatform } from "../setup"; + +const url = "/internal/services/messages/v1"; + +export const e2e_createChannel = async ( + platform: TestPlatform, + members: string[], + owner?: string, +) => { + const jwtToken = await platform.auth.getJWTToken({ sub: owner || platform.currentUser.id }); + const response = await platform.app.inject({ + method: "POST", + url: `/internal/services/channels/v1/companies/${platform.workspace.company_id}/workspaces/direct/channels`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + options: { + members, + }, + resource: { + description: "A direct channel description", + visibility: "direct", + }, + }, + }); + const channelCreateResult: ResourceCreateResponse = deserialize( + ResourceCreateResponse, + response.body, + ); + return channelCreateResult; +}; + +export const e2e_createThread = async ( + platform: TestPlatform, + participants: ParticipantObject[], + message: Message, + owner?: string, +) => { + const jwtToken = await platform.auth.getJWTToken({ sub: owner || platform.currentUser.id }); + const res = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/threads`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: { + participants: participants || [], + }, + options: { + message: message, + }, + }, + }); + await new Promise(resolve => setTimeout(resolve, 200)); + return res; +}; + +export const e2e_createMessage = async ( + platform: TestPlatform, + threadId: string, + message: Message, +) => { + const jwtToken = await platform.auth.getJWTToken( + message.user_id ? { sub: message.user_id } : undefined, + ); + const res = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/threads/${threadId}/messages`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: message, + }, + }); + await new Promise(resolve => setTimeout(resolve, 200)); + return res; +}; + +export const createMessage = (message: Partial, platform?: TestPlatform): Message => { + return getMessageInstance({ + //Default values + created_at: new Date().getTime(), + user_id: platform?.currentUser.id || undefined, + + ...message, + }); +}; + +export const createParticipant = ( + participant: Partial, + platform?: TestPlatform, +): ParticipantObject => { + return { + //Default values: + created_at: new Date().getTime(), + created_by: platform?.currentUser.id || "", + company_id: platform?.workspace.company_id || "", + workspace_id: platform?.workspace.workspace_id || "", + id: platform?.currentUser.id || "", + type: "user", + + ...participant, + }; +}; diff --git a/twake/backend/node/test/e2e/notifications/mention.spec.ts b/twake/backend/node/test/e2e/notifications/mention.spec.ts new file mode 100644 index 00000000..bc3ae7d8 --- /dev/null +++ b/twake/backend/node/test/e2e/notifications/mention.spec.ts @@ -0,0 +1,381 @@ +import { afterAll, beforeAll, describe, expect, it } from "@jest/globals"; +import { v1 as uuidv1 } from "uuid"; +import { init, TestPlatform } from "../setup"; +import { Channel } from "../../../src/services/channels/entities/channel"; +import { ChannelMemberNotificationLevel } from "../../../src/services/channels/types"; +import { User } from "../../../src/utils/types"; +import { + ChannelMemberUtils, + ChannelUtils, + get as getChannelUtils, + getMemberUtils, +} from "../channels/utils"; +import { MessageNotification } from "../../../src/services/messages/types"; +import { + IncomingPubsubMessage, + MessageQueueServiceAPI, +} from "../../../src/core/platform/services/message-queue/api"; +import { ChannelMember } from "../../../src/services/channels/entities"; +import { MentionNotification } from "../../../src/services/notifications/types"; +import gr from "../../../src/services/global-resolver"; + +describe("The notification for user mentions", () => { + let platform: TestPlatform; + let channelUtils: ChannelUtils; + let channelMemberUtils: ChannelMemberUtils; + let pubsubService: MessageQueueServiceAPI; + // eslint-disable-next-line @typescript-eslint/no-empty-function + let pubsubHandler: (message: IncomingPubsubMessage) => void = _ => {}; + + beforeAll(async () => { + platform = await init({ + services: [ + "webserver", + "database", + "search", + "storage", + "message-queue", + "user", + "websocket", + "channels", + "auth", + "search", + "applications", + "files", + "push", + "notifications", + "counter", + "statistics", + "platform-services", + ], + }); + channelUtils = getChannelUtils(platform); + channelMemberUtils = getMemberUtils(platform); + pubsubService = platform.platform.getProvider("message-queue"); + pubsubService.subscribe("notification:mentions", message => { + pubsubHandler(message); + }); + }); + + afterAll(async () => { + await platform?.tearDown(); + platform = null; + }); + + async function createChannel(): Promise { + const channel = channelUtils.getChannel(platform.currentUser.id); + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + channelUtils.getContext(), + ); + + return creationResult.entity; + } + + async function joinChannel( + userId: string, + channel: Channel, + notificationLevel?: ChannelMemberNotificationLevel, + ): Promise { + const user: User = { id: userId }; + const member = channelMemberUtils.getMember(channel, user); + + if (notificationLevel) member.notification_level = notificationLevel; + + const memberCreationResult = await gr.services.channels.members.save( + member, + channelUtils.getChannelContext(channel, user), + ); + return memberCreationResult.entity; + } + + async function updateNotificationLevel( + channel: Channel, + member: ChannelMember, + level: ChannelMemberNotificationLevel, + ): Promise { + member.notification_level = level; + await gr.services.channels.members.save( + member, + channelUtils.getChannelContext(channel, { id: member.user_id }), + ); + + return; + } + + function pushMessage(message: MessageNotification): Promise { + return pubsubService.publish("message:created", { + data: message, + }); + } + + it("should mention all users when preferences are MENTION", async done => { + const threadId = uuidv1(); + const messageId = uuidv1(); + const unknownUser = uuidv1(); + const channel = await createChannel(); + const member = await joinChannel( + platform.currentUser.id, + channel, + ChannelMemberNotificationLevel.MENTIONS, + ); + const member2 = await joinChannel(uuidv1(), channel, ChannelMemberNotificationLevel.MENTIONS); + const member3 = await joinChannel(uuidv1(), channel, ChannelMemberNotificationLevel.MENTIONS); + + pushMessage({ + channel_id: channel.id, + company_id: channel.company_id, + creation_date: Date.now(), + id: messageId, + sender: platform.currentUser.id, + thread_id: threadId, + workspace_id: channel.workspace_id, + mentions: { + users: [member.user_id, member2.user_id, unknownUser, member3.user_id], + }, + title: "test", + text: "should mention all users when preferences are MENTION ones", + }); + + const message = await new Promise>( + resolve => (pubsubHandler = resolve), + ); + expect(message.data.mentions.users).not.toContain(member.user_id); //The sender is not in the notified users + expect(message.data.mentions.users).toContain(member2.user_id); + expect(message.data.mentions.users).toContain(member3.user_id); + expect(message.data.mentions.users).not.toContain(unknownUser); + + done(); + }); + + it("should mention all users when preferences are default ones (ALL)", async done => { + const messageId = uuidv1(); + const unknownUser = uuidv1(); + const channel = await createChannel(); + const member = await joinChannel(platform.currentUser.id, channel); + const member2 = await joinChannel(uuidv1(), channel); + const member3 = await joinChannel(uuidv1(), channel); + + await new Promise(resolve => setTimeout(resolve, 500)); //Wait for the channel members to be created on all services + + pushMessage({ + channel_id: channel.id, + company_id: channel.company_id, + creation_date: Date.now(), + id: messageId, + sender: platform.currentUser.id, + thread_id: messageId, //Only thread initial messages generate notifications + workspace_id: channel.workspace_id, + title: "test", + text: "should mention all users when preferences are default ones (ALL)", + }); + + const message = await new Promise>( + resolve => (pubsubHandler = resolve), + ); + expect(message.data.mentions.users).not.toContain(member.user_id); //The sender is not in the notified users + expect(message.data.mentions.users).toContain(member2.user_id); + expect(message.data.mentions.users).toContain(member3.user_id); + expect(message.data.mentions.users).not.toContain(unknownUser); + + done(); + }); + + it("should not mention users with preferences ALL for replies of threads there are not member of", async done => { + const threadId = uuidv1(); + const messageId = uuidv1(); + const channel = await createChannel(); + const member = await joinChannel(platform.currentUser.id, channel); + const member2 = await joinChannel(uuidv1(), channel); + const member3 = await joinChannel(uuidv1(), channel); + + await new Promise(resolve => setTimeout(resolve, 500)); //Wait for the channel members to be created on all services + + pushMessage({ + channel_id: channel.id, + company_id: channel.company_id, + creation_date: Date.now(), + id: messageId, + sender: platform.currentUser.id, + thread_id: threadId, + workspace_id: channel.workspace_id, + mentions: { + users: [member.user_id, member2.user_id], + }, + title: "test", + text: "should mention all users when preferences are default ones (ALL)", + }); + + const message = await new Promise>( + resolve => (pubsubHandler = resolve), + ); + expect(message.data.mentions.users).not.toContain(member.user_id); //The sender is not in the notified users + expect(message.data.mentions.users).not.toContain(member3.user_id); + + done(); + }); + + it("should not mention user when notification level is set to NONE", async done => { + const threadId = uuidv1(); + const messageId = uuidv1(); + const unknownUser = uuidv1(); + const channel = await createChannel(); + const member = await joinChannel( + platform.currentUser.id, + channel, + ChannelMemberNotificationLevel.MENTIONS, + ); + const member2 = await joinChannel(uuidv1(), channel, ChannelMemberNotificationLevel.NONE); + const member3 = await joinChannel(uuidv1(), channel, ChannelMemberNotificationLevel.MENTIONS); + + await new Promise(resolve => setTimeout(resolve, 500)); //Wait for the channel members to be created on all services + + pushMessage({ + channel_id: channel.id, + company_id: channel.company_id, + creation_date: Date.now(), + id: messageId, + sender: platform.currentUser.id, + thread_id: threadId, + workspace_id: channel.workspace_id, + mentions: { + users: [member.user_id, member2.user_id, unknownUser, member3.user_id], + }, + title: "test", + text: "should not mention user when notification level is set to NONE", + }); + + const message = await new Promise>( + resolve => (pubsubHandler = resolve), + ); + expect(message.data.mentions.users).not.toContain(member.user_id); + expect(message.data.mentions.users).toContain(member3.user_id); + expect(message.data.mentions.users).not.toContain(member2.user_id); + + done(); + }); + + it("should mention user when notification level is set to channel mention and notification is for @all", async done => { + const threadId = uuidv1(); + const messageId = uuidv1(); + const channel = await createChannel(); + const member = await joinChannel( + platform.currentUser.id, + channel, + ChannelMemberNotificationLevel.MENTIONS, + ); + const member2 = await joinChannel(uuidv1(), channel, ChannelMemberNotificationLevel.MENTIONS); + const member3 = await joinChannel(uuidv1(), channel, ChannelMemberNotificationLevel.ME); + + await new Promise(resolve => setTimeout(resolve, 500)); //Wait for the channel members to be created on all services + + pushMessage({ + channel_id: channel.id, + company_id: channel.company_id, + creation_date: Date.now(), + id: messageId, + sender: platform.currentUser.id, + thread_id: threadId, + workspace_id: channel.workspace_id, + mentions: { + users: [], + specials: ["all"], + }, + title: "test", + text: "should mention user when notification level is set to channel mention and notification is for @all", + }); + + const message = await new Promise>( + resolve => (pubsubHandler = resolve), + ); + expect(message.data.mentions.users).not.toContain(member.user_id); + expect(message.data.mentions.users).toContain(member2.user_id); + expect(message.data.mentions.users).not.toContain(member3.user_id); + + done(); + }); + + it("should mention user when notification level is set to channel mention and notification is for @here", async done => { + const threadId = uuidv1(); + const messageId = uuidv1(); + const channel = await createChannel(); + const member = await joinChannel(platform.currentUser.id, channel); + const member2 = await joinChannel(uuidv1(), channel, ChannelMemberNotificationLevel.MENTIONS); + const member3 = await joinChannel(uuidv1(), channel, ChannelMemberNotificationLevel.ME); + + await new Promise(resolve => setTimeout(resolve, 500)); //Wait for the channel members to be created on all services + + pushMessage({ + channel_id: channel.id, + company_id: channel.company_id, + creation_date: Date.now(), + id: messageId, + sender: platform.currentUser.id, + thread_id: threadId, + workspace_id: channel.workspace_id, + mentions: { + users: [], + specials: ["here"], + }, + title: "test", + text: "should mention user when notification level is set to channel mention and notification is for @here", + }); + + const message = await new Promise>( + resolve => (pubsubHandler = resolve), + ); + + //Sender dont get notified + expect(message.data.mentions.users).not.toContain(member.user_id); + expect(message.data.mentions.users).toContain(member2.user_id); + expect(message.data.mentions.users).not.toContain(member3.user_id); + + done(); + }); + + it("should mention user when notification level is set to ME and updated notification later", async done => { + const threadId = uuidv1(); + const messageId = uuidv1(); + const channel = await createChannel(); + const member = await joinChannel( + platform.currentUser.id, + channel, + ChannelMemberNotificationLevel.NONE, + ); + const member2 = await joinChannel(uuidv1(), channel, ChannelMemberNotificationLevel.NONE); + const member3 = await joinChannel(uuidv1(), channel, ChannelMemberNotificationLevel.NONE); + + await new Promise(resolve => setTimeout(resolve, 1000)); //Wait for the channel members to be created + + await updateNotificationLevel(channel, member, ChannelMemberNotificationLevel.MENTIONS); + await updateNotificationLevel(channel, member2, ChannelMemberNotificationLevel.ME); + await updateNotificationLevel(channel, member3, ChannelMemberNotificationLevel.MENTIONS); + + await new Promise(resolve => setTimeout(resolve, 1000)); //Wait for the channel members to be created + + pushMessage({ + channel_id: channel.id, + company_id: channel.company_id, + creation_date: Date.now(), + id: messageId, + sender: platform.currentUser.id, + thread_id: threadId, + workspace_id: channel.workspace_id, + mentions: { + users: [member2.user_id], + }, + title: "test", + text: "should mention user when notification level is set to ME and updated notification later", + }); + + const message = await new Promise>( + resolve => (pubsubHandler = resolve), + ); + expect(message.data.mentions.users).not.toContain(member.user_id); + expect(message.data.mentions.users).not.toContain(member3.user_id); + expect(message.data.mentions.users).toContain(member2.user_id); + + done(); + }); +}); diff --git a/twake/backend/node/test/e2e/run-all.js b/twake/backend/node/test/e2e/run-all.js new file mode 100644 index 00000000..78d09aac --- /dev/null +++ b/twake/backend/node/test/e2e/run-all.js @@ -0,0 +1,104 @@ +/** + * To run all tests in local development mode: + * cd twake/; docker-compose -f docker-compose.dev.tests.mongo.yml run -e NODE_OPTIONS=--unhandled-rejections=warn -e SEARCH_DRIVER=mongodb -e DB_DRIVER=mongodb -e PUBSUB_TYPE=local node npm run test:e2e + * + * To run only specific tests: + * cd twake/; docker-compose -f docker-compose.dev.tests.mongo.yml run -e NODE_OPTIONS=--unhandled-rejections=warn -e SEARCH_DRIVER=mongodb -e DB_DRIVER=mongodb -e PUBSUB_TYPE=local node npm run test:e2e -- test/e2e/application/app-create-update.spec.ts test/e2e/application/application-events.spec.ts + */ + +const fs = require("fs"); +const path = require("path"); +const cp = require("child_process"); + +let localDevTests = process.argv.slice(2); + +//If we are in the CI tests we will run all the tests +if (process.env.CI || localDevTests.length === 0) { + localDevTests = false; +} + +if (localDevTests) { + console.log("Only this tests will be run:", localDevTests); +} else { + console.log("Will run all the tests"); +} + +function exec(command, args, debug = false) { + return new Promise(done => { + const cmd = cp.spawn(command, args, { + shell: true, + }); + + let data = ""; + let error = ""; + + cmd.stdout.on("data", function (data) { + if (debug) console.log(data.toString()); + data += data.toString() + "\n"; + }); + + cmd.stderr.on("data", function (data) { + if (debug) console.log(data.toString()); + error += data.toString() + "\n"; + }); + + cmd.on("exit", function (code) { + cmd.kill(9); + + //The delay is to make sure we get all the missing logs + setTimeout(() => done({ code, data, error }), code === 0 ? 1 : 5000); + }); + }); +} + +let srcFiles = []; +let srcPath = __dirname; +function throughDirectory(directory) { + fs.readdirSync(directory).forEach(file => { + const abs = path.join(directory, file); + if (fs.statSync(abs).isDirectory()) return throughDirectory(abs); + else return srcFiles.push(abs); + }); +} +throughDirectory(srcPath); + +srcFiles = srcFiles.filter(p => p.indexOf(".spec.ts") >= 0 || p.indexOf(".test.ts") >= 0); + +(async () => { + let failed = 0; + let passed = 0; + + let summary = ""; + + for (const path of localDevTests || srcFiles) { + const test = path.split("test/e2e/")[1]; + const testName = `test/e2e/${test}`; + const args = `${testName} --forceExit --detectOpenHandles --coverage --coverageDirectory=coverage/e2e/${test} --runInBand --testTimeout=60000 --verbose=true`; + + try { + //Show logs in the console if we are doing local dev tests + const out = await exec("jest", args.split(" "), !!localDevTests); + if (out.code !== 0) { + //To get all the logs, we run it again + console.log(`FAIL ${testName}`); + console.log(out.data); + console.log(out.error); + if (!localDevTests) await exec("jest", args.split(" "), true); + failed++; + summary += `FAIL ${testName}\n`; + } else { + passed++; + console.log(`PASS ${testName}`); + } + } catch (err) { + console.log(`ERROR ${testName}`); + console.log(`-- Error\n ${err}`); + failed++; + } + } + + console.log(`\nResults: ${passed} passed, ${failed} failed, total ${failed + passed}`); + console.log(summary); + + process.exit(failed > 0 ? 1 : 0); +})(); diff --git a/twake/backend/node/test/e2e/setup/default.test.json b/twake/backend/node/test/e2e/setup/default.test.json new file mode 100644 index 00000000..ec387742 --- /dev/null +++ b/twake/backend/node/test/e2e/setup/default.test.json @@ -0,0 +1,24 @@ +{ + "services": [], + "webserver": { + "port": 3000, + "logger": { + "level": "warn" + } + }, + "websocket": { + "path": "/socket", + "adapters": { + "types": ["redis"], + "redis": { + "host": "localhost", + "port": 6379 + } + } + }, + "auth": { + "jwt": { + "secret": "supersecret" + } + } +} diff --git a/twake/backend/node/test/e2e/setup/index.ts b/twake/backend/node/test/e2e/setup/index.ts new file mode 100644 index 00000000..54026c35 --- /dev/null +++ b/twake/backend/node/test/e2e/setup/index.ts @@ -0,0 +1,125 @@ +import { resolve as pathResolve } from "path"; +import { v1 as uuidv1 } from "uuid"; +import { FastifyInstance } from "fastify"; +import { TwakePlatform, TwakePlatformConfiguration } from "../../../src/core/platform/platform"; +import WebServerAPI from "../../../src/core/platform/services/webserver/provider"; +import { DatabaseServiceAPI } from "../../../src/core/platform/services/database/api"; +import AuthServiceAPI from "../../../src/core/platform/services/auth/provider"; +import { Workspace } from "../../../src/utils/types"; +import { MessageQueueServiceAPI } from "../../../src/core/platform/services/message-queue/api"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import config from "config"; +import globalResolver from "../../../src/services/global-resolver"; + +type TokenPayload = { + sub: string; + org?: { + [companyId: string]: { + role: string; + }; + }; +}; + +type User = { + id: string; + isWorkspaceModerator?: boolean; +}; + +export interface TestPlatform { + currentUser: User; + platform: TwakePlatform; + workspace: Workspace; + app: FastifyInstance; + database: DatabaseServiceAPI; + messageQueue: MessageQueueServiceAPI; + authService: AuthServiceAPI; + auth: { + getJWTToken(payload?: TokenPayload): Promise; + }; + tearDown(): Promise; +} + +export interface TestPlatformConfiguration { + services: string[]; +} + +let testPlatform: TestPlatform = null; + +export async function init( + testConfig?: TestPlatformConfiguration, + prePlatformStartCallback?: (fastify: FastifyInstance) => void, +): Promise { + if (!testPlatform) { + const configuration: TwakePlatformConfiguration = { + services: config.get("services"), + servicesPath: pathResolve(__dirname, "../../../src/services/"), + }; + const platform = new TwakePlatform(configuration); + await platform.init(); + await globalResolver.doInit(platform); + + const app = platform.getProvider("webserver").getServer(); + + if (prePlatformStartCallback) { + prePlatformStartCallback(app); + } + + await platform.start(); + + const database = platform.getProvider("database"); + const messageQueue = platform.getProvider("message-queue"); + const auth = platform.getProvider("auth"); + + testPlatform = { + platform, + app, + messageQueue, + database, + workspace: { company_id: "", workspace_id: "" }, + currentUser: { id: "" }, + authService: auth, + auth: { + getJWTToken, + }, + tearDown, + }; + } + + testPlatform.app.server.close(); + + testPlatform.currentUser = { id: uuidv1() }; + testPlatform.workspace = { + company_id: uuidv1(), + workspace_id: uuidv1(), + }; + + testPlatform.app.server.listen(3000); + //await testPlatform.messageQueue.start(); + + async function getJWTToken( + payload: TokenPayload = { sub: testPlatform.currentUser.id }, + ): Promise { + if (!payload.sub) { + payload.sub = testPlatform.currentUser.id; + } + + if (testPlatform.currentUser.isWorkspaceModerator) { + payload.org = {}; + payload.org[testPlatform.workspace.company_id] = { + role: "", + }; + } + + return testPlatform.authService.sign(payload); + } + + async function tearDown(): Promise { + if (testPlatform) { + testPlatform.app.server.close(); + //await testPlatform.messageQueue.stop(); + } + } + + return testPlatform; +} diff --git a/twake/backend/node/test/e2e/statistics.spec.ts b/twake/backend/node/test/e2e/statistics.spec.ts new file mode 100644 index 00000000..4d70b35f --- /dev/null +++ b/twake/backend/node/test/e2e/statistics.spec.ts @@ -0,0 +1,155 @@ +import { afterAll, beforeAll, beforeEach, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "./setup"; + +import { v1 as uuidv1 } from "uuid"; +import { + createMessage, + createParticipant, + e2e_createMessage, + e2e_createThread, +} from "./messages/utils"; +import { Thread } from "../../src/services/messages/entities/threads"; +import { deserialize } from "class-transformer"; +import { WorkspaceExecutionContext } from "../../src/services/channels/types"; +import { ChannelUtils, get as getChannelUtils } from "./channels/utils"; +import { ResourceUpdateResponse, User } from "../../src/utils/types"; +import gr from "../../src/services/global-resolver"; + +describe("Statistics implementation", () => { + let platform: TestPlatform; + // let database: DatabaseServiceAPI; + let channelUtils: ChannelUtils; + + beforeAll(async ends => { + platform = await init({ + services: ["database", "statistics", "webserver", "auth"], + }); + + expect(gr.services.statistics).toBeTruthy(); + + ends(); + channelUtils = getChannelUtils(platform); + }); + + beforeEach(async ends => { + await platform.database.getConnector().drop(); + ends(); + }); + + afterAll(async done => { + await platform.tearDown(); + done(); + }); + + it("Check statistics counters", async done => { + console.log(await gr.services.statistics.get(undefined, "counter-test")); + + expect(await gr.services.statistics.get(undefined, "counter-test")).toEqual(0); + + await gr.services.statistics.increase(platform.workspace.company_id, "counter-test"); + await gr.services.statistics.increase(platform.workspace.company_id, "counter-test"); + const secondCompanyId = uuidv1(); + await gr.services.statistics.increase(secondCompanyId, "counter-test"); + await gr.services.statistics.increase(secondCompanyId, "counter-test"); + await gr.services.statistics.increase(platform.workspace.company_id, "counter-test2"); + + expect(await gr.services.statistics.get(platform.workspace.company_id, "counter-test")).toEqual( + 2, + ); + expect(await gr.services.statistics.get(secondCompanyId, "counter-test")).toEqual(2); + expect(await gr.services.statistics.get(undefined, "counter-test")).toEqual(4); + + expect( + await gr.services.statistics.get(platform.workspace.company_id, "counter-test2"), + ).toEqual(1); + expect(await gr.services.statistics.get(secondCompanyId, "counter-test2")).toEqual(0); + expect(await gr.services.statistics.get(undefined, "counter-test2")).toEqual(1); + + done(); + }); + + function getContext(user?: User): WorkspaceExecutionContext { + return { + workspace: platform.workspace, + user: user || platform.currentUser, + }; + } + + async function sleep(timeout = 0) { + return new Promise(r => setTimeout(r, timeout)); + } + + describe("On user use messages in channel view", () => { + it("should create a message and retrieve it in channel view", async () => { + const channel = channelUtils.getChannel(); + await gr.services.channels.channels.save(channel, {}, getContext()); + const channelId = channel.id; + + //Reset global value because messages could have been created somewhere else + const value = await gr.services.statistics.get(undefined, "messages"); + await gr.services.statistics.increase(undefined, "messages", -value); + + const response = await e2e_createThread( + platform, + [ + createParticipant( + { + type: "channel", + id: channelId, + }, + platform, + ), + ], + createMessage({ text: "Initial thread 1 message" }), + ); + + await sleep(); + + const result: ResourceUpdateResponse = deserialize( + ResourceUpdateResponse, + response.body, + ); + const threadId = result.resource.id; + + await e2e_createMessage(platform, threadId, createMessage({ text: "Reply 1" })); + + await e2e_createMessage(platform, threadId, createMessage({ text: "Reply 2" })); + await e2e_createThread( + platform, + [ + createParticipant( + { + type: "channel", + id: channelId, + }, + platform, + ), + ], + createMessage({ text: "Initial thread 2 message" }), + ); + + await e2e_createMessage(platform, threadId, createMessage({ text: "Reply 3" })); + + await e2e_createThread( + platform, + [ + createParticipant( + { + type: "channel", + id: channelId, + }, + platform, + ), + ], + createMessage({ text: "Initial thread 3 message" }), + ); + + await new Promise(r => setTimeout(r, 5000)); + + expect(await gr.services.statistics.get(undefined, "messages")).toEqual(6); + expect(await gr.services.statistics.get(platform.workspace.company_id, "messages")).toEqual( + 6, + ); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/tags/tags.spec.ts b/twake/backend/node/test/e2e/tags/tags.spec.ts new file mode 100644 index 00000000..bdb6129d --- /dev/null +++ b/twake/backend/node/test/e2e/tags/tags.spec.ts @@ -0,0 +1,308 @@ +import "reflect-metadata"; +import { afterAll, beforeAll, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { TestDbService } from "../utils.prepare.db"; +import { Tags } from "../../../src/services/tags/entities/tags"; +import { deserialize } from "class-transformer"; +import { + ResourceCreateResponse, + ResourceGetResponse, + ResourceListResponse, +} from "../../../src/utils/types"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore + +describe("The Tags feature", () => { + const url = "/internal/services/tags/v1"; + let platform: TestPlatform; + let testDbService: TestDbService; + const tagIds: string[] = []; + + beforeAll(async ends => { + platform = await init({ + services: ["webserver", "database", "storage", "message-queue", "tags"], + }); + testDbService = await TestDbService.getInstance(platform, true); + ends(); + }); + + afterAll(async done => { + for (let i = 0; i < tagIds.length; i++) { + for (let j = 0; j < tagIds.length; j++) { + if (tagIds[j] === tagIds[i] && j !== i) { + throw new Error("Tag are not unique"); + } + } + } + await platform?.tearDown(); + platform = null; + done(); + }); + + describe("Create tag", () => { + it("should 201 if creator is a company admin", async done => { + const user = await testDbService.createUser([testDbService.defaultWorkspace()], { + companyRole: "admin", + }); + + const jwtToken = await platform.auth.getJWTToken({ sub: user.id }); + + for (let i = 0; i < 3; i++) { + const createTag = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/tags`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + name: `test${i}`, + colour: `#00000${i}`, + }, + }); + + const tagResult: ResourceCreateResponse = deserialize( + ResourceCreateResponse, + createTag.body, + ); + expect(createTag.statusCode).toBe(201); + expect(tagResult.resource).toBeDefined(); + expect(tagResult.resource.name).toBe(`test${i}`); + expect(tagResult.resource.colour).toBe(`#00000${i}`); + expect(tagResult.resource.company_id).toBe(platform.workspace.company_id); + expect(tagResult.resource.tag_id).toBe(`test${i}`); + + const getTag = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/tags/${tagResult.resource.tag_id}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + expect(getTag.statusCode).toBe(200); + + tagIds.push(tagResult.resource.tag_id); + } + done(); + }); + + it("should 401 if creator is not a company admin", async done => { + const user = await testDbService.createUser([testDbService.defaultWorkspace()], { + companyRole: "member", + }); + const jwtToken = await platform.auth.getJWTToken({ sub: user.id }); + const createTag = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/tags`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + name: "testNotAdmin", + colour: "#000000", + }, + }); + expect(createTag.statusCode).toBe(401); + + const tagResult: ResourceCreateResponse = deserialize( + ResourceCreateResponse, + createTag.body, + ); + expect(tagResult.resource).toBe(undefined); + done(); + }); + }); + + describe("Get tag", () => { + it("should 200 get a tag", async done => { + const user = await testDbService.createUser([testDbService.defaultWorkspace()], { + companyRole: "member", + }); + const jwtToken = await platform.auth.getJWTToken({ sub: user.id }); + const getTag = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/tags/${tagIds[0]}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + expect(getTag.statusCode).toBe(200); + + const getResult: ResourceGetResponse = deserialize(ResourceGetResponse, getTag.body); + expect(getResult.resource).toBeDefined(); + expect(getResult.resource.name).toBe("test0"); + expect(getResult.resource.colour).toBe("#000000"); + expect(getResult.resource.company_id).toBe(platform.workspace.company_id); + + done(); + }); + + it("should 200 tag does not exist", async done => { + const user = await testDbService.createUser([testDbService.defaultWorkspace()], { + companyRole: "member", + }); + const jwtToken = await platform.auth.getJWTToken({ sub: user.id }); + const getTag = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/tags/NonExistingTag`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + expect(getTag.statusCode).toBe(200); + + const getResult: ResourceGetResponse = deserialize(ResourceGetResponse, getTag.body); + expect(getResult.resource).toBe(null); + + done(); + }); + }); + + describe("Update tag", () => { + it("Should 204 if user is admin", async done => { + const user = await testDbService.createUser([testDbService.defaultWorkspace()], { + companyRole: "admin", + }); + const jwtToken = await platform.auth.getJWTToken({ sub: user.id }); + const updateTag = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/tags`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + name: "test1", + colour: "#000003", + }, + }); + expect(updateTag.statusCode).toBe(201); + + const tagUpdatedResult: ResourceCreateResponse = deserialize( + ResourceCreateResponse, + updateTag.body, + ); + expect(tagUpdatedResult.resource).toBeDefined(); + expect(tagUpdatedResult.resource.name).toBe("test1"); + expect(tagUpdatedResult.resource.colour).toBe("#000003"); + expect(tagUpdatedResult.resource.company_id).toBe(platform.workspace.company_id); + expect(tagUpdatedResult.resource.tag_id).toBe("test1"); + + const getUpdatedTag = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/tags/${tagUpdatedResult.resource.tag_id}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + expect(getUpdatedTag.statusCode).toBe(200); + + done(); + }); + + it("should 401 if creator is not a company admin", async done => { + const user = await testDbService.createUser([testDbService.defaultWorkspace()], { + companyRole: "member", + }); + const jwtToken = await platform.auth.getJWTToken({ sub: user.id }); + const createTag = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${platform.workspace.company_id}/tags/testNotAdmin`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + name: "testNotAdmin", + colour: "#000000", + }, + }); + expect(createTag.statusCode).toBe(401); + + const tagResult: ResourceCreateResponse = deserialize( + ResourceCreateResponse, + createTag.body, + ); + console.log("tagResult2", tagResult, jwtToken); + expect(tagResult.resource).toBe(undefined); + + done(); + }); + }); + + describe("List tags", () => { + it("should 200 list a tag", async done => { + const user = await testDbService.createUser([testDbService.defaultWorkspace()], { + companyRole: "member", + }); + const jwtToken = await platform.auth.getJWTToken({ sub: user.id }); + const listTag = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/tags`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + expect(listTag.statusCode).toBe(200); + + const tagResult: ResourceListResponse = deserialize(ResourceListResponse, listTag.body); + expect(tagResult.resources).toBeDefined(); + for (const tag of tagResult.resources) { + expect(tag.name).toBeDefined(); + expect(tag.colour).toBeDefined(); + expect(tag.company_id).toBe(platform.workspace.company_id); + expect(tag.tag_id).toBeDefined(); + } + + done(); + }); + }); + + describe("Delete tag", () => { + it("should 200 if admin delete a tag", async done => { + const user = await testDbService.createUser([testDbService.defaultWorkspace()], { + companyRole: "admin", + }); + const jwtToken = await platform.auth.getJWTToken({ sub: user.id }); + const deleteTag = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${platform.workspace.company_id}/tags/${tagIds[0]}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + expect(deleteTag.statusCode).toBe(200); + + done(); + }); + + it("should 200 if tag does not exist", async done => { + const user = await testDbService.createUser([testDbService.defaultWorkspace()], { + companyRole: "admin", + }); + const jwtToken = await platform.auth.getJWTToken({ sub: user.id }); + const deleteTag = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${platform.workspace.company_id}/tags/NonExistingTag`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + expect(deleteTag.statusCode).toBe(200); + done(); + }); + + it("should 401 if not admin", async done => { + const user = await testDbService.createUser([testDbService.defaultWorkspace()], { + companyRole: "member", + }); + const jwtToken = await platform.auth.getJWTToken({ sub: user.id }); + const deleteTag = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${platform.workspace.company_id}/tags/${tagIds[0]}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + expect(deleteTag.statusCode).toBe(401); + done(); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/users/users.search.spec.ts b/twake/backend/node/test/e2e/users/users.search.spec.ts new file mode 100644 index 00000000..b95d1320 --- /dev/null +++ b/twake/backend/node/test/e2e/users/users.search.spec.ts @@ -0,0 +1,149 @@ +import { afterEach, beforeEach, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { TestDbService } from "../utils.prepare.db"; +import { v1 as uuidv1 } from "uuid"; + +describe("The /users API", () => { + const url = "/internal/services/users/v1"; + let platform: TestPlatform; + + beforeEach(async ends => { + platform = await init({ + services: [ + "database", + "search", + "message-queue", + "websocket", + "webserver", + "user", + "auth", + "applications", + "storage", + "counter", + "workspaces", + "console", + "statistics", + "platform-services", + ], + }); + ends(); + }); + + afterEach(async ends => { + platform && (await platform.tearDown()); + platform = null; + ends(); + }); + + describe("The GET /users/?search=... route", () => { + it("Should find the searched users", async done => { + const testDbService = new TestDbService(platform); + await testDbService.createCompany(platform.workspace.company_id); + const workspacePk = { + id: platform.workspace.workspace_id, + company_id: platform.workspace.company_id, + }; + const workspacePk2 = { + id: uuidv1(), + company_id: uuidv1(), + }; + await testDbService.createWorkspace(workspacePk); + await testDbService.createWorkspace(workspacePk2); + await testDbService.createUser([workspacePk], { + firstName: "Ha", + lastName: "Nguyen", + email: "hnguyen@twake.app", + }); + await testDbService.createUser([workspacePk], { + firstName: "Harold", + lastName: "Georges", + email: "hgeorges@twake.app", + }); + await testDbService.createUser([workspacePk], { + firstName: "Bob", + lastName: "Smith", + email: "bob@twake.app", + }); + await testDbService.createUser([workspacePk], { + firstName: "Bob", + lastName: "Rabiot", + email: "rabiot.b@twake.app", + }); + await testDbService.createUser([workspacePk, workspacePk2], { + firstName: "Bob", + lastName: "Smith-Rabiot", + email: "rbs@twake.app", + }); + await testDbService.createUser([workspacePk], { + firstName: "AlexΓ―s", + lastName: "GoΓ©lΓ’ns", + email: "alexis.goelans@twake.app", + }); + + //Wait for indexation to happen + await new Promise(r => setTimeout(r, 5000)); + + let resources = await search("ha"); + expect(resources.length).toBe(2); + + resources = await search("bob rabiot"); + + expect(resources.map(e => e.email).includes("rabiot.b@twake.app")).toBe(true); + expect(resources.map(e => e.email).includes("rbs@twake.app")).toBe(true); + expect(resources.map(e => e.email).includes("bob@twake.app")).toBe(true); + + resources = await search("alexis"); + expect(resources[0].email).toBe("alexis.goelans@twake.app"); + + resources = await search("ALEXIS"); + expect(resources[0].email).toBe("alexis.goelans@twake.app"); + + resources = await search("AleXis"); + expect(resources[0].email).toBe("alexis.goelans@twake.app"); + + resources = await search("alex"); + expect(resources[0].email).toBe("alexis.goelans@twake.app"); + + resources = await search("Γ lΓ¨XΓ―s"); + expect(resources[0].email).toBe("alexis.goelans@twake.app"); + + resources = await search("rbs"); + expect(resources[0].email).toBe("rbs@twake.app"); + + resources = await search("rbs@twake.app"); + expect(resources[0].email).toBe("rbs@twake.app"); + + resources = await search("bob", workspacePk2.company_id); + expect(resources.length).toBe(1); + + resources = await search("rbs@twake.app", workspacePk.company_id); + expect(resources[0].email).toBe("rbs@twake.app"); + + resources = await search("rbs@twake.app", uuidv1()); + expect(resources.length).toBe(0); + + done(); + }); + }); + + async function search(search: string, companyId?: string): Promise { + const jwtToken = await platform.auth.getJWTToken(); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/users`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + query: { + search: search, + ...(companyId ? { search_company_id: companyId } : {}), + }, + }); + + expect(response.statusCode).toBe(200); + const json = response.json(); + expect(json).toMatchObject({ resources: expect.any(Array) }); + const resources = json.resources; + return resources; + } +}); diff --git a/twake/backend/node/test/e2e/users/users.spec.ts b/twake/backend/node/test/e2e/users/users.spec.ts new file mode 100644 index 00000000..a8c03130 --- /dev/null +++ b/twake/backend/node/test/e2e/users/users.spec.ts @@ -0,0 +1,645 @@ +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { TestDbService } from "../utils.prepare.db"; +import { v1 as uuidv1 } from "uuid"; +import { CompanyLimitsEnum, UserObject } from "../../../src/services/user/web/types"; +import { ChannelVisibility } from "../../../src/services/channels/types"; +import gr from "../../../src/services/global-resolver"; +import { ResourceListResponse, Workspace } from "../../../src/utils/types"; +import { ChannelSaveOptions } from "../../../src/services/channels/web/types"; +import { createMessage, e2e_createThread } from "../messages/utils"; +import { deserialize } from "class-transformer"; +import { get as getChannelUtils } from "../channels/utils"; + +describe("The /users API", () => { + const url = "/internal/services/users/v1"; + let platform: TestPlatform; + + let testDbService: TestDbService; + + const nonExistentId = uuidv1(); + + beforeEach(async ends => { + platform = await init(); + ends(); + }); + afterEach(async ends => { + await platform.tearDown(); + platform = null; + ends(); + }); + + beforeAll(async ends => { + const platform = await init({ + services: [ + "database", + "search", + "message-queue", + "websocket", + "applications", + "webserver", + "user", + "auth", + "storage", + "counter", + "console", + "workspaces", + "statistics", + "platform-services", + ], + }); + + testDbService = await TestDbService.getInstance(platform); + await testDbService.createCompany(); + const workspacePk = { id: uuidv1(), company_id: testDbService.company.id }; + await testDbService.createWorkspace(workspacePk); + await testDbService.createUser([workspacePk], { + workspaceRole: "moderator", + companyRole: "admin", + email: "admin@admin.admin", + username: "adminuser", + firstName: "admin", + }); + await testDbService.createUser([workspacePk]); + + ends(); + }); + + afterAll(async ends => { + ends(); + }); + + describe("The GET /users/:id route", () => { + it("should 401 when not authenticated", async done => { + const response = await platform.app.inject({ + method: "GET", + url: `${url}/users/1`, + }); + + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 404 when user does not exists", async done => { + const jwtToken = await platform.auth.getJWTToken({ sub: testDbService.users[0].id }); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/users/${nonExistentId}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + expect(response.statusCode).toBe(404); + expect(response.json()).toEqual({ + error: "Not Found", + message: `User ${nonExistentId} not found`, + statusCode: 404, + }); + done(); + }); + + it("should 200 and big response for myself", async done => { + const myId = testDbService.users[0].id; + const jwtToken = await platform.auth.getJWTToken({ sub: myId }); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/users/${myId}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + expect(response.statusCode).toBe(200); + + const resource = response.json()["resource"]; + + expect(resource).toMatchObject({ + id: myId, + provider: expect.any(String), + provider_id: expect.any(String), + email: expect.any(String), + is_verified: expect.any(Boolean), + picture: expect.any(String), + first_name: expect.any(String), + last_name: expect.any(String), + created_at: expect.any(Number), + deleted: expect.any(Boolean), + status: expect.any(String), + last_activity: expect.any(Number), + + //Below is only if this is myself + + preference: expect.objectContaining({ + locale: expect.any(String), + timezone: expect.any(Number), + }), + }); + + expect(resource["companies"]).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + role: expect.stringMatching(/owner|admin|member|guest/), + status: expect.stringMatching(/active|deactivated|invited/), + company: { + id: expect.any(String), + name: expect.any(String), + logo: expect.any(String), + }, + }), + ]), + ); + + done(); + }); + + it("should 200 and short response for another user", async done => { + const myId = testDbService.users[0].id; + const anotherUserId = testDbService.users[1].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: myId }); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/users/${anotherUserId}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + expect(response.statusCode).toBe(200); + + const resource = response.json()["resource"]; + + expect(resource).toMatchObject({ + id: anotherUserId, + provider: expect.any(String), + provider_id: expect.any(String), + email: expect.any(String), + is_verified: expect.any(Boolean), + picture: expect.any(String), + first_name: expect.any(String), + last_name: expect.any(String), + created_at: expect.any(Number), + deleted: expect.any(Boolean), + status: expect.any(String), + last_activity: expect.any(Number), + }); + + expect(resource).not.toMatchObject({ + locale: expect.anything(), + timezone: expect.anything(), + companies: expect.anything(), + }); + + done(); + }); + }); + + describe("The GET /users route", () => { + it("should 401 when user is not authenticated", async done => { + const response = await platform.app.inject({ + method: "GET", + url: `${url}/users`, + }); + + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 200 with array of users", async done => { + const myId = testDbService.users[0].id; + const anotherUserId = testDbService.users[1].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: myId }); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/users`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + query: { + user_ids: `${myId},${anotherUserId}`, + company_ids: "fd96c8a8-ae77-11eb-a1a1-0242ac120005", + }, + }); + + expect(response.statusCode).toBe(200); + const json = response.json(); + expect(json).toMatchObject({ resources: expect.any(Array) }); + const resources = json.resources; + + done(); + }); + }); + + describe("The GET /users/:user_id/companies route", () => { + it("should 401 when not authenticated", async done => { + const response = await platform.app.inject({ + method: "GET", + url: `${url}/users/1/companies`, + }); + + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 404 when user does not exists", async done => { + const jwtToken = await platform.auth.getJWTToken({ sub: testDbService.users[0].id }); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/users/${nonExistentId}/companies`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + expect(response.statusCode).toBe(404); + expect(response.json()).toEqual({ + error: "Not Found", + message: `User ${nonExistentId} not found`, + statusCode: 404, + }); + done(); + }); + + it("should 200 and on correct request", async done => { + const myId = testDbService.users[0].id; + const anotherUserId = testDbService.users[1].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: myId }); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/users/${anotherUserId}/companies`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + expect(response.statusCode).toBe(200); + + const resources = response.json()["resources"]; + expect(resources.length).toBeGreaterThan(0); + + for (const resource of resources) { + expect(resource).toMatchObject({ + id: expect.any(String), + name: expect.any(String), + logo: expect.any(String), + role: expect.stringMatching(/owner|admin|member|guest/), + status: expect.stringMatching(/active|deactivated|invited/), + }); + + if (resource.plan) { + expect(resource.plan).toMatchObject({ + name: expect.any(String), + limits: expect.objectContaining({ + [CompanyLimitsEnum.CHAT_MESSAGE_HISTORY_LIMIT]: expect.any(Number || undefined), + [CompanyLimitsEnum.COMPANY_MEMBERS_LIMIT]: expect.any(Number || undefined), + }), + }); + } + if (resources.stats) { + expect(resource.plan).toMatchObject({ + created_at: expect.any(Number), + total_members: expect.any(Number), + total_guests: expect.any(Number), + }); + } + } + done(); + }); + }); + + describe("The GET /companies/:company_id route", () => { + it("should 404 when company does not exists", async done => { + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/11111111-1111-1111-1111-111111111111`, + }); + expect(response.statusCode).toBe(404); + done(); + }); + + it("should 200 when company exists", async done => { + const companyId = testDbService.company.id; + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}`, + }); + expect(response.statusCode).toBe(200); + + const json = response.json(); + + expect(json.resource).toMatchObject({ + id: expect.any(String), + name: expect.any(String), + logo: expect.any(String), + }); + + if (json.resource.plan) { + expect(json.resource.plan).toMatchObject({ + name: expect.any(String), + limits: expect.objectContaining({ + [CompanyLimitsEnum.CHAT_MESSAGE_HISTORY_LIMIT]: expect.any(Number || undefined), + [CompanyLimitsEnum.COMPANY_MEMBERS_LIMIT]: expect.any(Number || undefined), + }), + }); + } + + expect(json.resource.stats).toMatchObject({ + created_at: expect.any(Number), + total_members: expect.any(Number), + total_guests: expect.any(Number), + total_messages: expect.any(Number), + }); + + done(); + }); + }); + + describe("User's device management", () => { + const deviceToken = "testDeviceToken"; + + describe("Register device (POST)", () => { + it("should 400 when type is not FCM", async done => { + const myId = testDbService.users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: myId }); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/devices`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: { + type: "another", + value: "value", + version: "version", + }, + }, + }); + + const resp = response.json(); + expect(response.statusCode).toBe(400); + expect(resp).toMatchObject({ + statusCode: 400, + error: "Bad Request", + message: "Type should be FCM only", + }); + done(); + }); + + it("should 200 when ok", async done => { + const firstId = testDbService.users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: firstId }); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/devices`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: { + type: "FCM", + value: deviceToken, + version: "1", + }, + }, + }); + + const resp = response.json(); + expect(response.statusCode).toBe(200); + + expect(resp.resource).toMatchObject({ + type: "FCM", + value: deviceToken, + version: "1", + }); + + const user = await testDbService.getUserFromDb({ id: firstId }); + expect(user.devices).toMatchObject([deviceToken]); + const device = await testDbService.getDeviceFromDb(deviceToken); + expect(device).toMatchObject({ + id: deviceToken, + user_id: firstId, + type: "FCM", + version: "1", + }); + + done(); + }); + + it("should 200 when register token to another person", async done => { + const firstId = testDbService.users[0].id; + const secondId = testDbService.users[1].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: secondId }); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/devices`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + payload: { + resource: { + type: "FCM", + value: deviceToken, + version: "1", + }, + }, + }); + + const resp = response.json(); + expect(response.statusCode).toBe(200); + + expect(resp.resource).toMatchObject({ + type: "FCM", + value: deviceToken, + version: "1", + }); + + // second user should have now this token + let user = await testDbService.getUserFromDb({ id: secondId }); + expect(user.devices).toMatchObject([deviceToken]); + const device = await testDbService.getDeviceFromDb(deviceToken); + expect(device).toMatchObject({ + id: deviceToken, + user_id: secondId, + type: "FCM", + version: "1", + }); + + // and first β€” not + + user = await testDbService.getUserFromDb({ id: firstId }); + expect(user.devices).toMatchObject([]); + + done(); + }); + }); + describe("List registered devices (GET)", () => { + it("should 200 when request devices", async done => { + const myId = testDbService.users[1].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: myId }); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/devices`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + const resp = response.json(); + expect(response.statusCode).toBe(200); + expect(resp).toMatchObject({ + resources: [ + { + type: "FCM", + value: "testDeviceToken", + version: "1", + }, + ], + }); + done(); + }); + }); + + describe("De-register device (DELETE)", () => { + it("should 200 when device not found for the user", async done => { + const myId = testDbService.users[1].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: myId }); + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/devices/somethingRandom`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + expect(response.statusCode).toBe(204); + + const user = await testDbService.getUserFromDb({ id: myId }); + expect(user.devices).toMatchObject([deviceToken]); + const device = await testDbService.getDeviceFromDb(deviceToken); + expect(device).toMatchObject({ + id: deviceToken, + user_id: myId, + type: "FCM", + version: "1", + }); + + done(); + }); + + it("should 200 when device found and device should be removed", async done => { + const myId = testDbService.users[1].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: myId }); + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/devices/${deviceToken}`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + expect(response.statusCode).toBe(204); + + const user = await testDbService.getUserFromDb({ id: myId }); + expect(user.devices).toMatchObject([]); + const device = await testDbService.getDeviceFromDb(deviceToken); + expect(device).toBeFalsy(); + + done(); + }); + }); + }); + + describe("Recent contacts", () => { + it("should return list of recent contacts of user", async done => { + // api = new Api(platform); + const channelUtils = getChannelUtils(platform); + + await testDbService.createDefault(platform); + + const channels = []; + + for (let i = 0; i < 5; i++) { + // const channel = channelUtils.getChannel(); + const directChannelIn = channelUtils.getDirectChannel(); + + const nextUser = await testDbService.createUser( + [{ id: platform.workspace.workspace_id, company_id: platform.workspace.company_id }], + { firstName: "FirstName" + i, lastName: "LastName" + i }, + ); + + const members = [platform.currentUser.id, nextUser.id]; + const directWorkspace: Workspace = { + company_id: platform.workspace.company_id, + workspace_id: ChannelVisibility.DIRECT, + }; + await Promise.all([ + // gr.services.channels.channels.save(channel, {}, getContext()), + gr.services.channels.channels.save( + directChannelIn, + { + members, + }, + { + ...{ + workspace: platform.workspace, + user: platform.currentUser, + }, + ...{ workspace: directWorkspace }, + }, + ), + ]); + channels.push(directChannelIn); + } + + await new Promise(resolve => setTimeout(resolve, 1000)); + + await e2e_createThread( + platform, + [ + { + company_id: platform.workspace.company_id, + created_at: 0, + created_by: "", + id: channels[2].id, + type: "channel", + workspace_id: "direct", + }, + ], + createMessage({ text: "Some message" }), + ); + + await new Promise(resolve => setTimeout(resolve, 1000)); + + const jwtToken = await platform.auth.getJWTToken(); + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${platform.workspace.company_id}/users/recent`, + headers: { + authorization: `Bearer ${jwtToken}`, + }, + }); + + expect(response.statusCode).toBe(200); + + const result: ResourceListResponse = deserialize( + ResourceListResponse, + response.body, + ); + + expect(result.resources.length).toEqual(5); + expect(result.resources[0].first_name).toEqual("FirstName2"); + + done(); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/utils.api.ts b/twake/backend/node/test/e2e/utils.api.ts new file mode 100644 index 00000000..b7ef87ab --- /dev/null +++ b/twake/backend/node/test/e2e/utils.api.ts @@ -0,0 +1,73 @@ +import { TestPlatform } from "./setup"; +import { InjectPayload, Response } from "light-my-request"; +import { logger as log } from "../../src/core/platform/framework"; + +declare global { + interface ApiResponse extends Response { + resources: any[]; + resource: any; + } +} + +export class Api { + constructor(protected platform: TestPlatform) {} + + private async convertResponse(response: Promise): Promise { + const apiResponse = (await response) as ApiResponse; + if (apiResponse.statusCode !== 204) { + const json = apiResponse.json(); + apiResponse.resources = json.resources; + apiResponse.resource = json.resource; + } + return apiResponse; + } + + private getJwtToken(userId: string) { + return this.platform.auth.getJWTToken({ sub: userId }); + } + + async request( + method: "GET" | "POST", + url: string, + payload: InjectPayload, + userId: string, + headers: any, + ): Promise { + if (!userId) userId = this.platform.currentUser.id; + + let totalHeaders = { authorization: `Bearer ${await this.getJwtToken(userId)}` }; + + if (headers) { + totalHeaders = { ...totalHeaders, ...headers }; + } + + return this.convertResponse( + this.platform.app + .inject({ + method, + url, + headers: totalHeaders, + payload, + }) + .then(a => { + if (a.statusCode !== 204) { + log.debug(a.json(), `${method} ${url}`); + } + return a; + }), + ); + } + + public async get(url: string, userId?: string, headers?: any): Promise { + return this.request("GET", url, undefined, userId, headers); + } + + public async post( + url: string, + payload: InjectPayload, + userId?: string, + headers?: any, + ): Promise { + return this.request("POST", url, payload, userId, headers); + } +} diff --git a/twake/backend/node/test/e2e/utils.prepare.db.ts b/twake/backend/node/test/e2e/utils.prepare.db.ts new file mode 100644 index 00000000..b8cdfa3c --- /dev/null +++ b/twake/backend/node/test/e2e/utils.prepare.db.ts @@ -0,0 +1,273 @@ +import { TestPlatform } from "./setup"; +import User from "./../../src/services/user/entities/user"; +import Company, { + getInstance as getCompanyInstance, +} from "./../../src/services/user/entities/company"; +import Workspace, { + getInstance as getWorkspaceInstance, + WorkspacePrimaryKey, +} from "./../../src/services/workspaces/entities/workspace"; + +import { v1 as uuidv1 } from "uuid"; +import CompanyUser from "../../src/services/user/entities/company_user"; +import { DatabaseServiceAPI } from "../../src/core/platform/services/database/api"; +import Repository from "../../src/core/platform/services/database/services/orm/repository/repository"; +import Device from "../../src/services/user/entities/device"; + +import gr from "../../src/services/global-resolver"; +import { Channel } from "../../src/services/channels/entities"; +import { get as getChannelUtils } from "./channels/utils"; + +export type uuid = string; + +export class TestDbService { + private deviceRepository: Repository; + + public static async getInstance( + testPlatform: TestPlatform, + createDefault = false, + ): Promise { + const instance = new this(testPlatform); + await instance.init(); + if (createDefault) { + await instance.createDefault(testPlatform); + } + return instance; + } + + public company: Company; + public users: User[]; + private workspacesMap: Map; + private userService; + + rand = () => Math.floor(Math.random() * 100000); + private database: DatabaseServiceAPI; + + private companyUserRepository: Repository; + private userRepository: Repository; + + constructor(protected testPlatform: TestPlatform) { + this.database = this.testPlatform.platform.getProvider("database"); + this.users = []; + this.workspacesMap = new Map(); + this.workspacesMap.set("direct", { + workspace: { id: "direct" } as Workspace, + users: [], + }); + } + + private async init() { + this.userRepository = await this.database.getRepository("user", User); + this.companyUserRepository = await this.database.getRepository( + "group_user", + CompanyUser, + ); + this.deviceRepository = await this.database.getRepository("device", Device); + } + + public get workspaces() { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + return [...this.workspacesMap.values()].filter(w => w.workspace.id !== "direct"); + } + + async createCompany(id?: uuid, name?: string): Promise { + if (!name) { + name = `TwakeAutotests-test-company-${this.rand()}`; + } + this.company = await gr.services.companies.createCompany( + getCompanyInstance({ + id: id || uuidv1(), + name: name, + displayName: name, + identity_provider_id: id, + }), + ); + return this.company; + } + + async createWorkspace( + workspacePk: WorkspacePrimaryKey, + name = `TwakeAutotests-test-workspace-${this.rand()}`, + ): Promise { + if (!workspacePk.company_id) throw new Error("company_id is not defined for workspace"); + + const workspace = await gr.services.workspaces.create( + getWorkspaceInstance({ + id: workspacePk.id, + name: name, + logo: "workspace_logo", + company_id: workspacePk.company_id, + }), + { user: { id: "", server_request: true } }, + ); + + const createdWorkspace = await gr.services.workspaces.get({ + id: workspacePk.id, + company_id: workspacePk.company_id, + }); + + if (!createdWorkspace) { + throw new Error("workspace wasn't created"); + } + + const createdWorkspaceEntity = workspace.entity; + this.workspacesMap.set(createdWorkspaceEntity.id, { + workspace: createdWorkspaceEntity, + users: [], + }); + return createdWorkspaceEntity; + } + + async createUser( + workspacesPk?: Array, + options: { + companyRole?: "member" | "admin" | "guest"; + workspaceRole?: "member" | "moderator"; + firstName?: string; + lastName?: string; + email?: string; + username?: string; + password?: string; + cache?: User["cache"]; + } = {}, + id: string = uuidv1(), + ): Promise { + const user = new User(); + const random = this.rand(); + user.id = id; + user.username_canonical = options.username || `test${random}`; + user.first_name = options.firstName || `test${random}_first_name`; + user.last_name = options.lastName || `test${random}_last_name`; + user.email_canonical = options.email || `test${random}@twake.app`; + user.identity_provider_id = user.id; + user.cache = options.cache || user.cache || { companies: [] }; + + //Fixme this is cheating, we should correctly set the cache in internal mode in the code + user.cache.companies = [ + ...(user.cache.companies || []), + ...workspacesPk.map(w => w.company_id), + ]; + if (options.email) { + user.email_canonical = options.email; + } + const createdUser = (await gr.services.users.create(user)).entity; + + if (options.password) { + await gr.services.users.setPassword({ id: createdUser.id }, options.password); + } + + this.users.push(createdUser); + await gr.services.companies.setUserRole( + this.company ? this.company.id : workspacesPk[0].company_id, + createdUser.id, + options.companyRole ? options.companyRole : "member", + ); + + if (workspacesPk && workspacesPk.length) { + for (const workspacePk of workspacesPk) { + await gr.services.workspaces.addUser( + workspacePk, + { id: createdUser.id }, + options.workspaceRole ? options.workspaceRole : "member", + ); + const wsContainer = this.workspacesMap.get(workspacePk.id); + wsContainer.users.push(createdUser); + } + } + + return createdUser; + } + + async getUserFromDb(user: Partial>): Promise { + if (user.id) { + return gr.services.users.get({ id: user.id }); + } else if (user.identity_provider_id) { + return gr.services.users.getByConsoleId(user.identity_provider_id); + } else { + throw new Error("getUserFromDb: Id not provided"); + } + } + + async getDeviceFromDb(id: string): Promise { + return this.deviceRepository.findOne({ id }); + } + + getCompanyFromDb(companyId: uuid) { + return gr.services.companies.getCompany({ id: companyId }); + } + + getCompanyFromDbByCode(code: uuid) { + return gr.services.companies.getCompany({ identity_provider_id: code }); + } + + async getCompanyUsers(companyId: uuid): Promise { + const allUsers = await this.userRepository.find({}).then(a => a.getEntities()); + + const companyUsers: User[] = []; + + for (const user of allUsers) { + const userInCompany = await this.companyUserRepository.findOne({ + user_id: user.id, + group_id: companyId, + }); + if (userInCompany) { + companyUsers.push(user); + } + } + return companyUsers; + } + + getCompanyUser(companyId: uuid, userId: uuid): Promise { + return gr.services.companies.getCompanyUser({ id: companyId }, { id: userId }); + } + + getWorkspaceUsersCountFromDb(workspaceId: string) { + return gr.services.workspaces.getUsersCount(workspaceId); + } + + async getCompanyUsersCountFromDb(companyId: string) { + return gr.services.companies.getUsersCount(companyId); + } + + async createDefault( + platform: TestPlatform = this.testPlatform, + isAdmin: boolean = true, + ): Promise { + await this.createCompany(platform.workspace.company_id); + const ws0pk = { + id: platform.workspace.workspace_id, + company_id: platform.workspace.company_id, + }; + await this.createWorkspace(ws0pk); + await this.createUser( + [ws0pk], + { + firstName: "defaultUser", + companyRole: isAdmin ? "admin" : "member", + workspaceRole: isAdmin ? "moderator" : "member", + }, + platform.currentUser.id, + ); + return this; + } + + getRepository = (type, entity) => { + return this.database.getRepository(type, entity); + }; + + defaultWorkspace() { + return this.workspaces[0].workspace; + } + + async createChannel(userId): Promise { + const channelUtils = getChannelUtils(this.testPlatform); + const channel = channelUtils.getChannel(userId); + const creationResult = await gr.services.channels.channels.save( + channel, + {}, + channelUtils.getContext({ id: userId }), + ); + return creationResult.entity; + } +} diff --git a/twake/backend/node/test/e2e/websocket/auth.spec.ts b/twake/backend/node/test/e2e/websocket/auth.spec.ts new file mode 100644 index 00000000..2326101c --- /dev/null +++ b/twake/backend/node/test/e2e/websocket/auth.spec.ts @@ -0,0 +1,90 @@ +import { afterEach, beforeEach, describe, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import io from "socket.io-client"; + +describe("The Websocket authentication", () => { + let platform: TestPlatform; + let socket: SocketIOClient.Socket; + + beforeEach(async ends => { + platform = await init({ + services: [ + "webserver", + "database", + "search", + "storage", + "message-queue", + "user", + "websocket", + "webserver", + "applications", + "auth", + "realtime", + "channels" /* FIXME: platform is not started if a business service is not in dependencies */, + "counter", + "statistics", + "platform-services", + ], + }); + + socket = io.connect("http://localhost:3000", { path: "/socket" }); + + ends(); + }); + + afterEach(async ends => { + platform && (await platform.tearDown()); + platform = null; + socket && socket.close(); + socket = null; + ends(); + }); + + describe("JWT-based Authentication", () => { + it("should not be able to connect without a JWT token", done => { + socket.connect(); + socket.on("connect", () => { + socket + .emit("authenticate", {}) + .on("authenticated", () => { + done(new Error("Should not occur")); + }) + .on("unauthorized", (msg: any) => { + done(); + }); + }); + }); + + it("should not be able to connect with something which is not a JWT token", done => { + socket.connect(); + socket.on("connect", () => { + socket + .emit("authenticate", { token: "Not a JWT token" }) + .on("authenticated", () => { + done(new Error("Should not occur")); + }) + .on("unauthorized", (msg: any) => { + done(); + }); + }); + }); + + it("should be able to connect with a JWT token", async done => { + const token = await platform.auth.getJWTToken(); + + socket.connect(); + socket.on("connect", () => { + socket + .emit("authenticate", { token }) + .on("authenticated", () => { + done(); + }) + .on("unauthorized", () => { + done(new Error("Should not occur")); + }); + }); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/websocket/realtime.spec.ts b/twake/backend/node/test/e2e/websocket/realtime.spec.ts new file mode 100644 index 00000000..d5199328 --- /dev/null +++ b/twake/backend/node/test/e2e/websocket/realtime.spec.ts @@ -0,0 +1,157 @@ +import { afterEach, beforeEach, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import io from "socket.io-client"; + +describe("The Realtime API", () => { + let platform: TestPlatform; + let socket: SocketIOClient.Socket; + + beforeEach(async ends => { + platform = await init({ + services: [ + "webserver", + "database", + "search", + "storage", + "message-queue", + "applications", + "user", + "auth", + "websocket", + "realtime", + "channels" /* FIXME: platform is not started if a business service is not in dependencies */, + "counter", + "statistics", + "platform-services", + ], + }); + + socket = io.connect("http://localhost:3000", { path: "/socket" }); + + ends(); + }); + + afterEach(async ends => { + await platform.tearDown(); + platform = null; + socket && socket.close(); + socket = null; + + ends(); + }); + + describe("Joining rooms", () => { + it("should fail when token is not defined", async done => { + const token = await platform.auth.getJWTToken(); + const name = "/ping"; + + socket.on("connect", () => { + socket + .emit("authenticate", { token }) + .on("authenticated", () => { + socket.emit("realtime:join", { name }); + socket.on("realtime:join:error", (event: any) => { + expect(event.name).toEqual(name); + done(); + }); + socket.on("realtime:join:success", () => done(new Error("Should not occur"))); + }) + .on("unauthorized", () => { + done(new Error("Should not occur")); + }); + }); + }); + + it("should fail when token is not valid", async done => { + const token = await platform.auth.getJWTToken(); + const name = "/ping"; + const roomToken = "invalid token"; + + socket.on("connect", () => { + socket + .emit("authenticate", { token }) + .on("authenticated", () => { + socket.emit("realtime:join", { name, token: roomToken }); + socket.on("realtime:join:error", (event: any) => { + expect(event.name).toEqual(name); + done(); + }); + socket.on("realtime:join:success", () => done(new Error("Should not occur"))); + }) + .on("unauthorized", () => { + done(new Error("Should not occur")); + }); + }); + }); + + it("should receive a realtime:join:success when token is valid and room has been joined", async done => { + const token = await platform.auth.getJWTToken(); + const name = "test"; + const roomToken = "twake"; + + socket.on("connect", () => { + socket + .emit("authenticate", { token }) + .on("authenticated", () => { + socket.emit("realtime:join", { name, token: roomToken }); + socket.on("realtime:join:error", () => done(new Error("Should not occur"))); + socket.on("realtime:join:success", (event: any) => { + expect(event.name).toEqual(name); + done(); + }); + }) + .on("unauthorized", () => { + done(new Error("Should not occur")); + }); + }); + }); + }); + + describe("Leaving rooms", () => { + it("should not fail when room has not been joined first", async done => { + const token = await platform.auth.getJWTToken(); + const name = "roomtest"; + + socket.on("connect", () => { + socket + .emit("authenticate", { token }) + .on("authenticated", () => { + socket.emit("realtime:leave", { name }); + socket.on("realtime:leave:error", () => done(new Error("should not fail"))); + socket.on("realtime:leave:success", (event: any) => { + expect(event.name).toEqual(name); + done(); + }); + }) + .on("unauthorized", () => { + done(new Error("Should not occur")); + }); + }); + }); + + it("should send success when room has been joined first", async done => { + const token = await platform.auth.getJWTToken(); + const roomToken = "twake"; + const name = "roomtest"; + + socket.on("connect", () => { + socket + .emit("authenticate", { token }) + .on("authenticated", () => { + socket.emit("realtime:join", { name, token: roomToken }); + socket.emit("realtime:leave", { name }); + socket.on("realtime:leave:error", () => done(new Error("should not fail"))); + socket.on("realtime:leave:success", (event: any) => { + expect(event.name).toEqual(name); + done(); + }); + }) + .on("unauthorized", () => { + done(new Error("Should not occur")); + }); + }); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/workspaces/workspace-pending-users.spec.ts b/twake/backend/node/test/e2e/workspaces/workspace-pending-users.spec.ts new file mode 100644 index 00000000..cc021fcb --- /dev/null +++ b/twake/backend/node/test/e2e/workspaces/workspace-pending-users.spec.ts @@ -0,0 +1,437 @@ +import { afterAll, beforeAll, describe, expect, it as _it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { TestDbService } from "../utils.prepare.db"; +import { v1 as uuidv1 } from "uuid"; +import gr from "../../../src/services/global-resolver"; +/* + THIS TESTS RUNS ONLY FOR THE CONSOLE-MODE (CONSOLE TYPE: INTERNAL) +*/ + +export const it = (name: string, cb: (a: any) => void) => { + _it(name, async done => { + if (gr.services.console.consoleType === "internal") { + cb(done); + } else { + console.warn(`[skipped]: ${name} (no-console mode only)`); + done(); + } + }); +}; + +describe("The /workspace/pending users API", () => { + const url = "/internal/services/workspaces/v1"; + let platform: TestPlatform; + + let testDbService: TestDbService; + + const nonExistentId = uuidv1(); + const companyId = uuidv1(); + + const firstEmail = "first@test-user.com"; + const secondEmail = "second@test-user.com"; + const thirdEmail = "third@test-user.com"; + const fourthUser = "fourth@test-user.com"; + const emailForExistedUser = "exist@email.com"; + + async function doTheTest() { + return Promise.resolve(gr.services.console.consoleType === "remote"); + } + + beforeAll(async ends => { + platform = await init({ + services: [ + "user", + "database", + "message-queue", + "webserver", + "search", + "workspaces", + "applications", + "auth", + "console", + "storage", + "counter", + "statistics", + "platform-services", + ], + }); + + await platform.database.getConnector().drop(); + await platform.database.getConnector().init(); + testDbService = new TestDbService(platform); + await testDbService.createCompany(companyId); + const ws0pk = { id: uuidv1(), company_id: companyId }; + const ws1pk = { id: uuidv1(), company_id: companyId }; + const ws2pk = { id: uuidv1(), company_id: companyId }; + await testDbService.createWorkspace(ws0pk); + await testDbService.createWorkspace(ws1pk); + await testDbService.createWorkspace(ws2pk); + await testDbService.createUser([ws0pk], { companyRole: "member", workspaceRole: "moderator" }); + await testDbService.createUser([ws0pk], { companyRole: "member", workspaceRole: "member" }); + await testDbService.createUser([ws1pk], { + companyRole: "member", + workspaceRole: "member", + email: emailForExistedUser, + }); + await testDbService.createUser([ws2pk], { + companyRole: "guest", + workspaceRole: "member", + email: fourthUser, + }); + + ends(); + }); + + afterAll(async ends => { + await platform.tearDown(); + ends(); + }); + + describe("Invite users to a workspace by email", () => { + it("should 401 when not authenticated", async done => { + const companyId = testDbService.company.id; + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${nonExistentId}/users/invite`, + }); + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 404 when workspace not found", async done => { + const userId = testDbService.users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${nonExistentId}/users/invite`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + invitations: [ + { + email: firstEmail, + role: "member", + company_role: "member", + }, + ], + }, + }); + + expect(response.statusCode).toBe(404); + done(); + }); + + it("should 403 when requester is not at least workspace member", async done => { + const workspace_id = testDbService.workspaces[2].workspace.id; + const userId = testDbService.workspaces[2].users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspace_id}/users/invite`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + invitations: [ + { + email: firstEmail, + role: "member", + company_role: "member", + }, + ], + }, + }); + expect(response.statusCode).toBe(403); + done(); + }); + + it("should 200 when ok", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[0].workspace.id; + const userId = testDbService.workspaces[0].users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/invite`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + invitations: [ + { + email: firstEmail, + role: "member", + company_role: "member", + }, + { + email: secondEmail, + role: "member", + company_role: "member", + }, + { + email: "exist@email.com", + role: "member", + company_role: "member", + }, + ], + }, + }); + expect(response.statusCode).toBe(200); + + const resources = response.json()["resources"]; + + expect(resources.length).toBe(3); + + for (const item of resources) { + expect(item).toMatchObject({ + email: expect.stringMatching(/first@test-user.com|second@test-user.com|exist@email.com/), + status: "ok", + }); + } + + done(); + }); + + it("should fail in response with already added users", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[0].workspace.id; + const userId = testDbService.workspaces[0].users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/invite`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + invitations: [ + { + email: firstEmail, + role: "member", + company_role: "member", + }, + { + email: thirdEmail, + role: "member", + company_role: "member", + }, + ], + }, + }); + expect(response.statusCode).toBe(200); + + const resources = response.json()["resources"]; + + expect(resources.length).toBe(2); + + expect(resources[0]).toMatchObject({ + email: "first@test-user.com", + status: "error", + }); + + expect(resources[1]).toMatchObject({ + email: "third@test-user.com", + status: "ok", + }); + + done(); + }); + }); + + describe("Delete a pending user from a workspace", () => { + it("should 401 when not authenticated", async done => { + const companyId = testDbService.company.id; + const email = "first@test-user.com"; + + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${companyId}/workspaces/${nonExistentId}/pending/${email}`, + }); + + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 404 when workspace not found", async done => { + const companyId = testDbService.company.id; + const email = "first@test-user.com"; + + const userId = testDbService.users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${companyId}/workspaces/${nonExistentId}/pending/${email}`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(response.statusCode).toBe(404); + done(); + }); + + it("should 403 when requester is not at least workspace member", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[2].workspace.id; + const userId = testDbService.workspaces[2].users[0].id; + const email = "first@test-user.com"; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/pending/${email}`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(response.statusCode).toBe(403); + done(); + }); + + it("should {status:error} when email is absent in pending list", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[0].workspace.id; + const userId = testDbService.workspaces[0].users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/pending/non-exist-email`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(response.statusCode).toBe(200); + expect(response.json()).toMatchObject({ + status: "error", + }); + + done(); + }); + + it("should 200 when ok", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[0].workspace.id; + const userId = testDbService.workspaces[0].users[0].id; + const email = "first@test-user.com"; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/pending/${email}`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(response.statusCode).toBe(200); + expect(response.json()).toMatchObject({ + status: "success", + }); + + done(); + }); + }); + + describe("Get list of pending users in workspace", () => { + it("should 401 when not authenticated", async done => { + const companyId = testDbService.company.id; + const email = "first@test-user.com"; + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${nonExistentId}/pending`, + }); + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 404 when workspace not found", async done => { + const companyId = testDbService.company.id; + const email = "first@test-user.com"; + + const userId = testDbService.users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${nonExistentId}/pending`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(response.statusCode).toBe(404); + done(); + }); + + it("should 403 when requester is not at least workspace member", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[2].workspace.id; + const userId = testDbService.workspaces[2].users[0].id; + const email = "first@test-user.com"; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/pending`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(response.statusCode).toBe(403); + done(); + }); + + it("should 200 when ok", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[0].workspace.id; + const userId = testDbService.workspaces[0].users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/pending`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(response.statusCode).toBe(200); + + const resources = response.json()["resources"]; + console.log("resources A: ", resources); + expect(resources.length).toBe(2); + + expect(resources[0]).toMatchObject({ + email: "second@test-user.com", + role: "member", + company_role: "member", + }); + + expect(resources[1]).toMatchObject({ + email: "third@test-user.com", + role: "member", + company_role: "member", + }); + + done(); + }); + + it("existed user should be added instantly", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[0].workspace.id; + const userId = testDbService.workspaces[0].users[0].id; + const email = "first@test-user.com"; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(response.statusCode).toBe(200); + + const resources = response.json()["resources"]; + + console.log("resources B: ", resources); + expect(resources.find((a: any) => a.user.email === emailForExistedUser)).toBeDefined(); + + done(); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/workspaces/workspace-users.spec.ts b/twake/backend/node/test/e2e/workspaces/workspace-users.spec.ts new file mode 100644 index 00000000..c70f2e83 --- /dev/null +++ b/twake/backend/node/test/e2e/workspaces/workspace-users.spec.ts @@ -0,0 +1,469 @@ +import { afterAll, beforeAll, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { TestDbService, uuid } from "../utils.prepare.db"; +import { v1 as uuidv1 } from "uuid"; + +describe("The /workspace users API", () => { + const url = "/internal/services/workspaces/v1"; + let platform: TestPlatform; + + let testDbService: TestDbService; + + const nonExistentId = uuidv1(); + let companyId = ""; + + const checkUserObject = (resource: any) => { + expect(resource).toMatchObject({ + id: expect.any(String), + company_id: expect.any(String), + workspace_id: expect.any(String), + user_id: expect.any(String), + created_at: expect.any(Number), + role: expect.stringMatching(/moderator|member/), + user: { + id: expect.any(String), + provider: expect.any(String), + provider_id: expect.any(String), + email: expect.any(String), + is_verified: expect.any(Boolean), + picture: expect.any(String), + first_name: expect.any(String), + last_name: expect.any(String), + created_at: expect.any(Number), + deleted: expect.any(Boolean), + status: expect.any(String), + last_activity: expect.any(Number), + }, + }); + }; + + beforeAll(async ends => { + platform = await init({ + services: [ + "database", + "message-queue", + "search", + "webserver", + "user", + "workspaces", + "applications", + "auth", + "console", + "counter", + "storage", + "statistics", + "platform-services", + ], + }); + + companyId = platform.workspace.company_id; + + await platform.database.getConnector().init(); + testDbService = new TestDbService(platform); + await testDbService.createCompany(companyId); + const ws0pk = { id: uuidv1(), company_id: companyId }; + const ws1pk = { id: uuidv1(), company_id: companyId }; + const ws2pk = { id: uuidv1(), company_id: companyId }; + const ws3pk = { id: uuidv1(), company_id: companyId }; + await testDbService.createWorkspace(ws0pk); + await testDbService.createWorkspace(ws1pk); + await testDbService.createWorkspace(ws2pk); + await testDbService.createWorkspace(ws3pk); + await testDbService.createUser([ws0pk, ws1pk]); + await testDbService.createUser([ws2pk], { companyRole: "admin" }); + await testDbService.createUser([ws2pk], { workspaceRole: "moderator" }); + await testDbService.createUser([ws2pk], { workspaceRole: "member" }); + await testDbService.createUser([ws2pk], { workspaceRole: "member" }); + await testDbService.createUser([], { companyRole: "member" }); + await testDbService.createUser([ws3pk], { companyRole: "guest", workspaceRole: "member" }); + ends(); + }); + + afterAll(async ends => { + await platform.tearDown(); + ends(); + }); + + describe("The GET /workspaces/users route", () => { + it("should 401 when not authenticated", async done => { + const companyId = testDbService.company.id; + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${nonExistentId}/users`, + }); + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 404 when workspace not found", async done => { + const userId = testDbService.users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${nonExistentId}/users`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + expect(response.statusCode).toBe(404); + done(); + }); + + it("should 200 when ok", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[2].workspace.id; + const userId = testDbService.workspaces[2].users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + expect(response.statusCode).toBe(200); + + const resources = response.json()["resources"]; + + expect(resources.length).toBeGreaterThan(0); + + for (const resource of resources) { + checkUserObject(resource); + } + + done(); + }); + }); + + describe("The GET /workspaces/users/:user_id route", () => { + it("should 401 when not authenticated", async done => { + const companyId = testDbService.company.id; + const userId = testDbService.users[0].id; + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${nonExistentId}/users/${userId}`, + }); + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 404 when workspace not found", async done => { + const userId = testDbService.users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${nonExistentId}/users/${userId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + expect(response.statusCode).toBe(404); + done(); + }); + + it("should 200 when ok", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[0].workspace.id; + const userId = testDbService.workspaces[0].users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/${userId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + expect(response.statusCode).toBe(200); + + const resource = response.json()["resource"]; + checkUserObject(resource); + done(); + }); + }); + + describe("The POST /workspaces/users route (add)", () => { + it("should 401 when not authenticated", async done => { + const companyId = testDbService.company.id; + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${nonExistentId}/users`, + }); + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 403 user is not workspace moderator", async done => { + const userId = testDbService.users[0].id; + const anotherUserId = testDbService.users[1].id; + const workspaceId = testDbService.workspaces[0].workspace.id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + resource: { + user_id: anotherUserId, + role: "moderator", + }, + }, + }); + expect(response.statusCode).toBe(403); + done(); + }); + + it("should 400 when requested user not in company", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[2].workspace.id; + const userId = testDbService.workspaces[2].users[1].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + resource: { + user_id: nonExistentId, + role: "moderator", + }, + }, + }); + expect(response.statusCode).toBe(400); + done(); + }); + + it("should 201 when requested already in workspace (ignore)", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[2].workspace.id; + const userId = testDbService.workspaces[2].users[1].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + resource: { + user_id: userId, + role: "moderator", + }, + }, + }); + expect(response.statusCode).toBe(201); + done(); + }); + + it("should 200 when ok", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[2].workspace.id; + const userId = testDbService.workspaces[2].users[1].id; + const anotherUserId = testDbService.workspaces[0].users[0].id; + + let workspaceUsersCount = await testDbService.getWorkspaceUsersCountFromDb(workspaceId); + let companyUsersCount = await testDbService.getCompanyUsersCountFromDb(companyId); + + console.log(testDbService.workspaces[2].users); + console.log(workspaceUsersCount); + + expect(workspaceUsersCount).toBe(4); + // expect(companyUsersCount).toBe(6); + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + resource: { + user_id: anotherUserId, + role: "moderator", + }, + }, + }); + + expect(response.statusCode).toBe(201); + const resource = response.json()["resource"]; + checkUserObject(resource); + + workspaceUsersCount = await testDbService.getWorkspaceUsersCountFromDb(workspaceId); + companyUsersCount = await testDbService.getCompanyUsersCountFromDb(companyId); + expect(workspaceUsersCount).toBe(5); + // expect(companyUsersCount).toBe(6); + + done(); + }); + }); + + describe("The POST /workspaces/users/:user_id route (update)", () => { + it("should 401 when not authenticated", async done => { + const companyId = testDbService.company.id; + const userId = testDbService.users[0].id; + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${nonExistentId}/users/${userId}`, + }); + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 403 user is not workspace moderator", async done => { + const userId = testDbService.users[0].id; + const anotherUserId = testDbService.users[1].id; + const workspaceId = testDbService.workspaces[0].workspace.id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/${userId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + resource: { + user_id: anotherUserId, + role: "moderator", + }, + }, + }); + expect(response.statusCode).toBe(403); + done(); + }); + + it("should 404 when user not found in workspace", async done => { + const workspaceId = testDbService.workspaces[2].workspace.id; + const userId = testDbService.workspaces[2].users[1].id; + const anotherWorkspaceUserId = testDbService.workspaces[3].users[0].id; + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/${anotherWorkspaceUserId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + resource: { + role: "moderator", + }, + }, + }); + + expect(response.statusCode).toBe(404); + done(); + }); + + it("should 200 when ok", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[2].workspace.id; + const userId = testDbService.workspaces[2].users[1].id; + const anotherUserId = testDbService.workspaces[2].users[2].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/${anotherUserId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + resource: { + role: "moderator", + }, + }, + }); + + expect(response.statusCode).toBe(201); + const resource = response.json()["resource"]; + checkUserObject(resource); + + expect(resource["role"]).toBe("moderator"); + + const usersCount = await testDbService.getWorkspaceUsersCountFromDb(workspaceId); + expect(usersCount).toBe(5); + + done(); + }); + }); + + describe("The DELETE /workspaces/users/:user_id route", () => { + it("should 401 when not authenticated", async done => { + const companyId = testDbService.company.id; + const anotherUserId = testDbService.users[1].id; + + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${companyId}/workspaces/${nonExistentId}/users/${anotherUserId}`, + }); + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 403 user is not workspace moderator", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[2].workspace.id; + const userId = testDbService.workspaces[2].users[3].id; + const anotherUserId = testDbService.workspaces[2].users[1].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/${anotherUserId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + console.log(response.body); + + expect(response.statusCode).toBe(403); + done(); + }); + + it("should 404 when user not found in workspace", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[2].workspace.id; + const userId = testDbService.workspaces[2].users[1].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/${nonExistentId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(response.statusCode).toBe(404); + + done(); + }); + + it("should 200 when ok", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[2].workspace.id; + const userId = testDbService.workspaces[2].users[1].id; + const anotherUserId = testDbService.workspaces[2].users[2].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + let response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/${anotherUserId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(response.statusCode).toBe(204); + + response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(response.statusCode).toBe(200); + const resources = response.json()["resources"]; + expect(resources.find((a: { user_id: uuid }) => a.user_id === anotherUserId)).toBeUndefined(); + + const usersCount = await testDbService.getWorkspaceUsersCountFromDb(workspaceId); + expect(usersCount).toBe(4); + + done(); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/workspaces/workspaces.invite-tokens.spec.ts b/twake/backend/node/test/e2e/workspaces/workspaces.invite-tokens.spec.ts new file mode 100644 index 00000000..90853467 --- /dev/null +++ b/twake/backend/node/test/e2e/workspaces/workspaces.invite-tokens.spec.ts @@ -0,0 +1,521 @@ +import { afterAll, beforeAll, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { TestDbService } from "../utils.prepare.db"; +import { v1 as uuidv1 } from "uuid"; +import AuthService from "../../../src/core/platform/services/auth/provider"; +import { InviteTokenObject } from "../../../src/services/workspaces/web/types"; +import gr from "../../../src/services/global-resolver"; + +describe("The /workspaces API (invite tokens)", () => { + const url = "/internal/services/workspaces/v1"; + let platform: TestPlatform; + + let testDbService: TestDbService; + let authServiceApi: AuthService; + + let companyId = uuidv1(); + + const startup = async () => { + platform = await init({ + services: [ + "database", + "message-queue", + "webserver", + "user", + "search", + "workspaces", + "auth", + "console", + "counter", + "storage", + "applications", + "statistics", + "platform-services", + ], + }); + + companyId = platform.workspace.company_id; + + await platform.platform.getProvider("auth"); + testDbService = new TestDbService(platform); + await resetDatabase(); + }; + + const shutdown = async () => { + await platform.tearDown(); + }; + + const resetDatabase = async () => { + // await platform.database.getConnector().init(); + await platform.database.getConnector().drop(); + await testDbService.createCompany(companyId, "TestJoinCompany"); + const ws0pk = { id: uuidv1(), company_id: companyId }; + const ws1pk = { id: uuidv1(), company_id: companyId }; + const ws2pk = { id: uuidv1(), company_id: companyId }; + await testDbService.createWorkspace(ws0pk, "FirstWorkspace"); + await testDbService.createWorkspace(ws1pk, "SecondWorkspace"); + await testDbService.createWorkspace(ws2pk, "ThirdWorkspace"); + await testDbService.createUser([ws0pk, ws1pk]); + await testDbService.createUser([ws2pk], { companyRole: "admin" }); + await testDbService.createUser([ws2pk], { companyRole: undefined, workspaceRole: "moderator" }); + await testDbService.createUser([], { companyRole: "guest" }); + }; + + const decodeToken = (token: string): InviteTokenObject => { + return gr.services.workspaces.decodeInviteToken(token); + }; + + describe("The GET /tokens/ route", () => { + beforeAll(startup); + afterAll(shutdown); + it("should 401 when not authenticated", async done => { + const companyId = testDbService.company.id; + + const workspaceId = testDbService.workspaces[0].workspace.id; + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens`, + }); + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 403 when user is not a workspace member", async done => { + const workspaceId = testDbService.workspaces[0].workspace.id; + const userIdFromAnotherWorkspace = platform.currentUser.id; + const companyId = testDbService.company.id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userIdFromAnotherWorkspace }); + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + expect(response.statusCode).toBe(403); + + done(); + }); + + it("should 404 when token doesn't exists yet", async done => { + const workspaceId = testDbService.workspaces[0].workspace.id; + const userId = testDbService.workspaces[0].users[0].id; + const companyId = testDbService.company.id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(response.statusCode).toBe(404); + + done(); + }); + + it("should 200 when user is a workspace member", async done => { + const workspaceId = testDbService.workspaces[0].workspace.id; + const userId = testDbService.workspaces[0].users[0].id; + const companyId = testDbService.company.id; + + await gr.services.workspaces.createInviteToken(companyId, workspaceId, userId); + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(response.statusCode).toBe(200); + + expect(response.json()).toMatchObject({ + resources: [ + { + token: expect.any(String), + }, + ], + }); + + done(); + }); + }); + + describe("The POST /tokens/ route", () => { + beforeAll(startup); + afterAll(shutdown); + + it("should 401 when not authenticated", async done => { + const companyId = testDbService.company.id; + + const workspaceId = testDbService.workspaces[0].workspace.id; + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens`, + }); + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 403 when user is not a workspace member", async done => { + const workspaceId = testDbService.workspaces[0].workspace.id; + const userIdFromAnotherWorkspace = platform.currentUser.id; + const companyId = testDbService.company.id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userIdFromAnotherWorkspace }); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + channels: ["test"], + }, + }); + expect(response.statusCode).toBe(403); + + done(); + }); + + it("should 200 when user is a workspace member", async done => { + const workspaceId = testDbService.workspaces[0].workspace.id; + const userId = testDbService.workspaces[0].users[0].id; + const companyId = testDbService.company.id; + const channel = await testDbService.createChannel(userId); + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const beforeResponse = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(beforeResponse.statusCode).toBe(404); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + channels: [channel.id], + }, + }); + + expect(response.statusCode).toBe(200); + + expect(response.json()).toMatchObject({ + resource: { + token: expect.any(String), + }, + }); + + const createToken = decodeToken(response.json().resource.token); + + const afterResponse = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(afterResponse.statusCode).toBe(200); + + expect(afterResponse.json()).toMatchObject({ + resources: [ + { + token: expect.any(String), + }, + ], + }); + + const getToken = decodeToken(afterResponse.json().resources[0].token); + + expect(createToken.t).toEqual(getToken.t); + + done(); + }); + + it("should 200 when when recreate token", async done => { + const workspaceId = testDbService.workspaces[0].workspace.id; + const userId = testDbService.workspaces[0].users[0].id; + const companyId = testDbService.company.id; + const channel = await testDbService.createChannel(userId); + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const beforeResponse = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(beforeResponse.statusCode).toBe(200); + + const beforeResponseResource = beforeResponse.json()["resources"][0]; + + expect(beforeResponseResource).toMatchObject({ + token: expect.any(String), + }); + + const beforeResponseToken = decodeToken(beforeResponseResource.token).t; + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + channels: [channel.id], + }, + }); + + expect(response.statusCode).toBe(200); + + const responseResource = response.json()["resource"]; + + expect(responseResource).toMatchObject({ + token: expect.any(String), + }); + + const responseToken = decodeToken(responseResource.token).t; + + expect(responseToken).not.toEqual(beforeResponseToken); + + const afterResponse = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(afterResponse.statusCode).toBe(200); + + const afterResponseResource = afterResponse.json()["resources"][0]; + + expect(afterResponseResource).toMatchObject({ + token: expect.any(String), + }); + + const afterResponseToken = decodeToken(afterResponseResource.token).t; + + expect(responseToken).toEqual(afterResponseToken); + expect(afterResponseToken).not.toEqual(beforeResponseToken); + + done(); + }); + }); + + describe("The DELETE /tokens/ route", () => { + beforeAll(startup); + afterAll(shutdown); + + it("should 401 when not authenticated", async done => { + const companyId = testDbService.company.id; + + const workspaceId = testDbService.workspaces[0].workspace.id; + + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens/fake1-${new Date().getTime()}`, + }); + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 403 when user is not a workspace member", async done => { + const workspaceId = testDbService.workspaces[0].workspace.id; + const userIdFromAnotherWorkspace = platform.currentUser.id; + const companyId = testDbService.company.id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userIdFromAnotherWorkspace }); + + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens/fake2-${new Date().getTime()}`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: {}, + }); + expect(response.statusCode).toBe(403); + + done(); + }); + + it("should 204 when user is a workspace member", async done => { + const workspaceId = testDbService.workspaces[0].workspace.id; + const userId = testDbService.workspaces[0].users[0].id; + const companyId = testDbService.company.id; + + await gr.services.workspaces.createInviteToken(companyId, workspaceId, userId); + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const beforeResponse = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(beforeResponse.statusCode).toBe(200); + + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens/${ + beforeResponse.json().resources[0].token + }`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(response.statusCode).toBe(204); + + const afterResponse = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(afterResponse.statusCode).toBe(404); + + done(); + }); + + it("should 404 when deleting token that doesn't exists", async done => { + const workspaceId = testDbService.workspaces[0].workspace.id; + const userId = testDbService.workspaces[0].users[0].id; + const companyId = testDbService.company.id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}/users/tokens/fake3-${new Date().getTime()}`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: {}, + }); + expect(response.statusCode).toBe(404); + + done(); + }); + }); + + describe("Join workspace using token", () => { + let workspaceId; + let userId; + let companyId; + let inviteToken; + + beforeAll(async () => { + await startup(); + companyId = testDbService.company.id; + workspaceId = testDbService.workspaces[0].workspace.id; + userId = testDbService.workspaces[2].users[0].id; + inviteToken = await gr.services.workspaces.createInviteToken(companyId, workspaceId, userId); + }); + afterAll(shutdown); + + it("should 404 when when token not found", async done => { + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/join`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + join: false, + token: "SOME FAKE TOKEN", + }, + }); + expect(response.statusCode).toBe(404); + done(); + }); + + it("should 200 when user is not authorized", async done => { + const response = await platform.app.inject({ + method: "POST", + url: `${url}/join`, + // headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + join: false, + token: inviteToken.token, + }, + }); + expect(response.statusCode).toBe(200); + + const resource = response.json()["resource"]; + + expect(resource).toMatchObject({ + company: { + name: "TestJoinCompany", + }, + workspace: { + name: "FirstWorkspace", + }, + auth_required: true, + }); + + done(); + }); + + it("should 200 when user is authorized and not joining", async done => { + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/join`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + join: false, + token: inviteToken.token, + }, + }); + expect(response.statusCode).toBe(200); + + const resource = response.json()["resource"]; + + expect(resource).toMatchObject({ + company: { + name: "TestJoinCompany", + }, + workspace: { + name: "FirstWorkspace", + }, + auth_required: false, + }); + + done(); + }); + + it("should 200 when user is authorized and joining", async done => { + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/join`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + join: true, + token: inviteToken.token, + }, + }); + expect(response.statusCode).toBe(200); + + const resource = response.json()["resource"]; + + expect(resource).toMatchObject({ + company: { + id: companyId, + name: "TestJoinCompany", + }, + workspace: { + id: workspaceId, + name: "FirstWorkspace", + }, + auth_required: false, + }); + + done(); + }); + }); +}); diff --git a/twake/backend/node/test/e2e/workspaces/workspaces.spec.ts b/twake/backend/node/test/e2e/workspaces/workspaces.spec.ts new file mode 100644 index 00000000..d251e304 --- /dev/null +++ b/twake/backend/node/test/e2e/workspaces/workspaces.spec.ts @@ -0,0 +1,513 @@ +import { afterAll, beforeAll, describe, expect, it } from "@jest/globals"; +import { init, TestPlatform } from "../setup"; +import { TestDbService } from "../utils.prepare.db"; +import { v1 as uuidv1 } from "uuid"; + +describe("The /workspaces API", () => { + const url = "/internal/services/workspaces/v1"; + let platform: TestPlatform; + + let testDbService: TestDbService; + + const nonExistentId = uuidv1(); + let companyId = ""; + + beforeAll(async ends => { + platform = await init({ + services: [ + "database", + "message-queue", + "webserver", + "user", + "search", + "workspaces", + "auth", + "console", + "counter", + "storage", + "applications", + "statistics", + "platform-services", + ], + }); + + companyId = platform.workspace.company_id; + + await platform.database.getConnector().init(); + testDbService = new TestDbService(platform); + await testDbService.createCompany(companyId); + const ws0pk = { id: uuidv1(), company_id: companyId }; + const ws1pk = { id: uuidv1(), company_id: companyId }; + const ws2pk = { id: uuidv1(), company_id: companyId }; + await testDbService.createWorkspace(ws0pk); + await testDbService.createWorkspace(ws1pk); + await testDbService.createWorkspace(ws2pk); + await testDbService.createUser([ws0pk, ws1pk]); + await testDbService.createUser([ws2pk], { companyRole: "admin" }); + await testDbService.createUser([ws2pk], { companyRole: undefined, workspaceRole: "moderator" }); + await testDbService.createUser([], { companyRole: "guest" }); + ends(); + }); + + afterAll(async ends => { + await platform.tearDown(); + ends(); + }); + + describe("The GET /workspaces/ route", () => { + it("should 401 when not authenticated", async done => { + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${nonExistentId}/workspaces`, + }); + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 404 when company not found", async done => { + const userId = testDbService.workspaces[0].users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${nonExistentId}/workspaces`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + expect(response.statusCode).toBe(404); + done(); + }); + + it("should 200 when company belongs to user", async done => { + const userId = testDbService.workspaces[0].users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + const companyId = testDbService.company.id; + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + expect(response.statusCode).toBe(200); + + const resources = response.json()["resources"]; + + expect(resources.length).toBe(2); + + for (const resource of resources) { + expect(resource).toMatchObject({ + id: expect.any(String), + company_id: expect.any(String), + name: expect.any(String), + logo: expect.any(String), + default: expect.any(Boolean), + archived: expect.any(Boolean), + role: expect.stringMatching(/moderator|member/), + }); + + if (resource.stats) { + expect(resource.stats).toMatchObject({ + created_at: expect.any(Number), + total_members: 1, + }); + } + } + + done(); + }); + }); + + describe("The GET /workspaces/:workspace_id route", () => { + it("should 401 when not authenticated", async done => { + const workspaceId = testDbService.workspaces[0].workspace.id; + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${nonExistentId}/workspaces/${workspaceId}`, + }); + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 404 when workspace not found", async done => { + const userId = testDbService.workspaces[0].users[0].id; + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${uuidv1()}`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + expect(response.statusCode).toBe(404); + done(); + }); + + it("should 403 when user not belong to workspace and not company_admin", async done => { + const workspaceId = testDbService.workspaces[2].workspace.id; + const userIdFromAnotherWorkspace = testDbService.workspaces[0].users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userIdFromAnotherWorkspace }); + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + expect(response.statusCode).toBe(403); + + expect(response.json()).toEqual({ + error: "Forbidden", + message: `You are not belong to workspace ${workspaceId}`, + statusCode: 403, + }); + + done(); + }); + + it("should 200 when user is company_admin", async done => { + const workspaceId = testDbService.workspaces[0].workspace.id; + const userIdFromAnotherWorkspace = testDbService.workspaces[2].users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userIdFromAnotherWorkspace }); + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + expect(response.statusCode).toBe(200); + + const resource = response.json()["resource"]; + + expect(resource).toMatchObject({ + id: expect.any(String), + company_id: expect.any(String), + name: expect.any(String), + logo: expect.any(String), + default: expect.any(Boolean), + archived: expect.any(Boolean), + }); + + if (resource.stats) { + expect(resource.stats).toMatchObject({ + created_at: expect.any(Number), + total_members: 1, + }); + } + + done(); + }); + + it("should 200 when user is belong to workspace", async done => { + const workspaceId = testDbService.workspaces[0].workspace.id; + const userIdFromThisWorkspace = testDbService.workspaces[0].users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userIdFromThisWorkspace }); + + const response = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + expect(response.statusCode).toBe(200); + + const resource = response.json()["resource"]; + + expect(resource).toMatchObject({ + id: expect.any(String), + company_id: expect.any(String), + name: expect.any(String), + logo: expect.any(String), + default: expect.any(Boolean), + archived: expect.any(Boolean), + role: expect.stringMatching(/moderator|member/), + }); + + if (resource.stats) { + expect(resource.stats).toMatchObject({ + created_at: expect.any(Number), + total_members: 1, + }); + } + + done(); + }); + }); + + // create + + describe("The POST /workspaces route (creating workspace)", () => { + it("should 401 when not authenticated", async done => { + const companyId = testDbService.company.id; + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${nonExistentId}`, + }); + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 403 when user is not (company member or company admin) ", async done => { + const companyId = testDbService.company.id; + const userId = testDbService.users[3].id; + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + resource: { + name: "Some channel name", + logo: "", + default: false, + }, + }, + }); + + expect(response.statusCode).toBe(403); + done(); + }); + + it("should 201 when workspace created well", async done => { + const companyId = testDbService.company.id; + const userId = testDbService.users[0].id; + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + resource: { + name: "Random channel name", + logo: "logo", + default: false, + }, + }, + }); + + expect(response.statusCode).toBe(201); + + const resource = response.json()["resource"]; + + expect(resource).toMatchObject({ + id: expect.any(String), + company_id: expect.any(String), + name: expect.any(String), + logo: expect.any(String), + default: expect.any(Boolean), + archived: expect.any(Boolean), + role: expect.stringMatching(/moderator/), + }); + + done(); + }); + }); + + // update + + describe("The POST /workspaces/:workspace_id route (updating workspace)", () => { + it("should 401 when not authenticated", async done => { + const companyId = testDbService.company.id; + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${nonExistentId}`, + payload: { resource: {} }, + }); + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 403 when not workspace not found", async done => { + const companyId = testDbService.company.id; + const userId = testDbService.workspaces[0].users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${nonExistentId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { resource: {} }, + }); + + expect(response.statusCode).toBe(403); + + done(); + }); + + it("should 403 when not belong to workspace", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[1].workspace.id; + const userId = testDbService.workspaces[0].users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { resource: {} }, + }); + + expect(response.statusCode).toBe(403); + + done(); + }); + + it("should 403 when not workspace moderator", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[1].workspace.id; + const userId = testDbService.workspaces[0].users[0].id; + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { resource: {} }, + }); + + expect(response.statusCode).toBe(403); + + done(); + }); + + it("should 200 when admin of company (full update)", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[2].workspace.id; + const userId = testDbService.workspaces[2].users[0].id; // company owner + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + resource: { + name: "Another workspace name", + logo: "logo", + default: false, + archived: false, + }, + }, + }); + + expect(response.statusCode).toBe(200); + + const resource = response.json()["resource"]; + + expect(resource).toMatchObject({ + id: workspaceId, + company_id: companyId, + name: "Another workspace name", + logo: expect.any(String), + default: false, + archived: false, + role: "moderator", //Company admin is a moderator + }); + + done(); + }); + + it("should 200 when moderator of workspace (partial update)", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[2].workspace.id; + const userId = testDbService.workspaces[2].users[1].id; // workspace admin + + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "POST", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + payload: { + resource: { + name: "My awesome workspace", + default: true, + logo: "", + }, + }, + }); + + expect(response.statusCode).toBe(200); + + const resource = response.json()["resource"]; + + expect(resource).toMatchObject({ + id: workspaceId, + company_id: companyId, + name: "My awesome workspace", + logo: expect.any(String), + default: true, + archived: false, + role: "moderator", + }); + + done(); + }); + }); + + // delete + + describe("The DELETE /workspaces route", () => { + it("should 401 when not authenticated", async done => { + const companyId = testDbService.company.id; + + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${companyId}/workspaces/${nonExistentId}`, + }); + expect(response.statusCode).toBe(401); + done(); + }); + + it("should 403 when user is not (company member or company admin) ", async done => { + const companyId = testDbService.company.id; + const userId = testDbService.users[3].id; + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + const workspaceId = testDbService.workspaces[0].workspace.id; + + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(response.statusCode).toBe(403); + done(); + }); + + it("should 204 when workspace deleted", async done => { + const companyId = testDbService.company.id; + const workspaceId = testDbService.workspaces[2].workspace.id; + const userId = testDbService.workspaces[2].users[0].id; + const jwtToken = await platform.auth.getJWTToken({ sub: userId }); + + const response = await platform.app.inject({ + method: "DELETE", + url: `${url}/companies/${companyId}/workspaces/${workspaceId}`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + expect(response.statusCode).toBe(204); + + const checkResponse = await platform.app.inject({ + method: "GET", + url: `${url}/companies/${companyId}/workspaces`, + headers: { authorization: `Bearer ${jwtToken}` }, + }); + + const checkResponseJson = checkResponse.json(); + + expect(checkResponseJson.resources.find((a: any) => a.id === workspaceId)).toBe(undefined); + + done(); + }); + }); +}); diff --git a/twake/backend/node/test/http/README.md b/twake/backend/node/test/http/README.md new file mode 100644 index 00000000..2f2333c3 --- /dev/null +++ b/twake/backend/node/test/http/README.md @@ -0,0 +1,3 @@ +# Sample HTTP Requests + +Files in this folder works with the [REST Client VSCode extension](https://github.com/Huachao/vscode-restclient). diff --git a/twake/backend/node/test/http/badges.http b/twake/backend/node/test/http/badges.http new file mode 100644 index 00000000..932df6ea --- /dev/null +++ b/twake/backend/node/test/http/badges.http @@ -0,0 +1,19 @@ +@company_id = bcfe2f79-8e81-42a3-b551-3a32d49b2b4c +@workspace_id = 3328552c-5ccd-4172-b84a-d876d56aa71b +@user_id = 3328552c-5ccd-4172-b84a-d876d56aa71c + +@baseURL = http://localhost:3000 +@badgesURL = {{baseURL}}/internal/services/notifications/v1/badges + +# @name login +GET {{baseURL}}/api/auth/login + +@authToken = {{login.response.body.token}} +@currentUserId = {{login.response.body.user.id}} + +### List badges with all websockets + +GET {{badgesURL}}/?company_id={{company_id}}&websockets=true&limit=5 +Content-Type: application/json +Authorization: Bearer {{authToken}} + diff --git a/twake/backend/node/test/http/channel-as-read.http b/twake/backend/node/test/http/channel-as-read.http new file mode 100644 index 00000000..880d90d2 --- /dev/null +++ b/twake/backend/node/test/http/channel-as-read.http @@ -0,0 +1,61 @@ +@company_id = bcfe2f79-8e81-42a3-b551-3a32d49b2b4c +@workspace_id = 3328552c-5ccd-4172-b84a-d876d56aa71b +@user_id = 3328552c-5ccd-4172-b84a-d876d56aa71c + +@baseURL = http://localhost:3000 +@channelsURL = {{baseURL}}/internal/services/channels/v1/companies/{{company_id}}/workspaces/{{workspace_id}} +@directChannelsURL = {{baseURL}}/internal/services/channels/v1/companies/{{company_id}}/workspaces/direct + +# @name login +GET {{baseURL}}/api/auth/login + +@authToken = {{login.response.body.token}} +@currentUserId = {{login.response.body.user.id}} + +### Create a channel + +# @name createChannel +POST {{channelsURL}}/channels +Content-Type: application/json +Authorization: Bearer {{authToken}} + +{ + "resource": { + "name": "My channel", + "icon": "twake logo", + "description": "This channel allow twake's team to chat easily", + "channel_group": "twake", + "visibility": "public", + "is_default": true, + "archived": false + } +} + +### Get a single channel + +@getId = {{createChannel.response.body.resource.id}} + +GET {{channelsURL}}/channels/{{getId}} +Authorization: Bearer {{authToken}} + +### Add current user as member to a channel (join channel) + +POST {{channelsURL}}/channels/{{getId}}/members +Content-Type: application/json +Authorization: Bearer {{authToken}} + +{ + "resource": { + "user_id": "{{currentUserId}}" + } +} + +### Mark the channel as read/unread + +POST {{channelsURL}}/channels/{{getId}}/read +Content-Type: application/json +Authorization: Bearer {{authToken}} + +{ + "value": true +} diff --git a/twake/backend/node/test/http/channels.http b/twake/backend/node/test/http/channels.http new file mode 100644 index 00000000..29eb21bf --- /dev/null +++ b/twake/backend/node/test/http/channels.http @@ -0,0 +1,133 @@ +@company_id = bcfe2f79-8e81-42a3-b551-3a32d49b2b4c +@workspace_id = 3328552c-5ccd-4172-b84a-d876d56aa71b +@user_id = 3328552c-5ccd-4172-b84a-d876d56aa71c + +@baseURL = http://localhost:3000 +@channelsURL = {{baseURL}}/internal/services/channels/v1/companies/{{company_id}}/workspaces/{{workspace_id}} +@directChannelsURL = {{baseURL}}/internal/services/channels/v1/companies/{{company_id}}/workspaces/direct + +# @name login +GET {{baseURL}}/api/auth/login + +@authToken = {{login.response.body.token}} +@currentUserId = {{login.response.body.user.id}} + +### List workspace channels with all websockets + +GET {{channelsURL}}/channels?websockets=true&limit=5 +Content-Type: application/json +Authorization: Bearer {{authToken}} + +### List user channels with all websockets + +@authToken = {{login.response.body.token}} +GET {{channelsURL}}/channels?websockets=true&mine=true&limit=5 +Content-Type: application/json +Authorization: Bearer {{authToken}} + +### Create a channel + +# @name createChannel +POST {{channelsURL}}/channels +Content-Type: application/json +Authorization: Bearer {{authToken}} + +{ + "resource": { + "name": "My channel", + "icon": "twake logo", + "description": "This channel allow twake's team to chat easily", + "channel_group": "twake", + "visibility": "public", + "is_default": true, + "archived": false + } +} + +### Get a single channel + +@getId = {{createChannel.response.body.resource.id}} + +GET {{channelsURL}}/channels/{{getId}} +Authorization: Bearer {{authToken}} + +### Update a channel +@updateId = {{createChannel.response.body.resource.id}} + +POST {{channelsURL}}/channels/{{updateId}} +Content-Type: application/json +Authorization: Bearer {{authToken}} + +{ + "resource": { + "name": "My channel", + "description": "Hello world", + "is_default": false + } +} + +### Delete a channel + +@deleteId = {{createChannel.response.body.resource.id}} + +DELETE {{channelsURL}}/channels/{{deleteId}} +Authorization: Bearer {{authToken}} + + +### Get all channel members + +GET {{channelsURL}}/channels/{{getId}}/members?websockets=true +Content-Type: application/json +Authorization: Bearer {{authToken}} + + +### Add current user as member to a channel (join channel) + +POST {{channelsURL}}/channels/{{getId}}/members +Content-Type: application/json +Authorization: Bearer {{authToken}} + +{ + "resource": { + "user_id": "{{currentUserId}}" + } +} + +### Get a channel member + +GET {{channelsURL}}/channels/{{getId}}/members/{{currentUserId}} +Content-Type: application/json +Authorization: Bearer {{authToken}} + +### Update current channel member + +POST {{channelsURL}}/channels/{{getId}}/members/{{currentUserId}} +Content-Type: application/json +Authorization: Bearer {{authToken}} + +{ + "resource": { + "favorite": true, + "notification_level": "none", + "hello": 1 + } +} + +### Current user quits the channel + +DELETE {{channelsURL}}/channels/{{getId}}/members/{{currentUserId}} +Content-Type: application/json +Authorization: Bearer {{authToken}} + +### Errors Tests + +### Call without the JWT token should HTTP 401 + +GET {{channelsURL}}/channels +Content-Type: application/json + +### Get a channel which may not exists + +GET {{channelsURL}}/channels/0b0e1492-f596-46b9-a4fb-c12d71b2696e +Authorization: Bearer {{authToken}} + diff --git a/twake/backend/node/test/http/direct-channels.http b/twake/backend/node/test/http/direct-channels.http new file mode 100644 index 00000000..ee436a2e --- /dev/null +++ b/twake/backend/node/test/http/direct-channels.http @@ -0,0 +1,163 @@ +@company_id = bcfe2f79-8e81-42a3-b551-3a32d49b2b4c +@workspace_id = 3328552c-5ccd-4172-b84a-d876d56aa71b + +@baseURL = http://localhost:3000 +@channelsURL = {{baseURL}}/internal/services/channels/v1/companies/{{company_id}}/workspaces/{{workspace_id}} +@directChannelsURL = {{baseURL}}/internal/services/channels/v1/companies/{{company_id}}/workspaces/direct + +### Login as user 1 + +# @name login +GET {{baseURL}}/api/auth/login + +@authToken1 = {{login.response.body.token}} +@userId1 = {{login.response.body.user.id}} + +### Login as user 2 + +# @name login2 + +GET {{baseURL}}/api/auth/login + +@authToken2 = {{login2.response.body.token}} +@userId2 = {{login2.response.body.user.id}} + +### Login as user 3 + +# @name login3 + +GET {{baseURL}}/api/auth/login + +@authToken3 = {{login3.response.body.token}} +@userId3 = {{login3.response.body.user.id}} + +### Create a direct channel + +# @name createDirectChannel +POST {{directChannelsURL}}/channels +Content-Type: application/json +Authorization: Bearer {{authToken1}} + +{ + "options": { + "members": ["{{userId2}}"] + }, + "resource": { + "icon": "hello", + "description": "A direct channel", + "channel_group": "twake", + "is_default": false, + "archived": false + } +} + +### Direct channel details as user 1 should work +@directId = {{createDirectChannel.response.body.resource.id}} + +GET {{directChannelsURL}}/channels/{{directId}} +Content-Type: application/json +Authorization: Bearer {{authToken1}} + +### Direct channel details as user 2 (member) should work + +GET {{directChannelsURL}}/channels/{{directId}} +Content-Type: application/json +Authorization: Bearer {{authToken2}} + +### Direct channel details as user 3 (not member) should not work + +GET {{directChannelsURL}}/channels/{{directId}} +Content-Type: application/json +Authorization: Bearer {{authToken3}} + +### Direct channel members + +GET {{directChannelsURL}}/channels/{{directId}}/members?websockets=true +Content-Type: application/json +Authorization: Bearer {{authToken1}} + +### List direct channels for user in company + +@authToken = {{login.response.body.token}} +GET {{directChannelsURL}}/channels?websockets=true&limit=5 +Content-Type: application/json +Authorization: Bearer {{authToken1}} + +### Update the direct channel description + +POST {{directChannelsURL}}/channels/{{directId}} +Content-Type: application/json +Authorization: Bearer {{authToken1}} + +{ + "resource": { + "description": "A new direct channel description" + } +} + +### Update the direct channel name will do nothing since the name is useless +POST {{directChannelsURL}}/channels/{{directId}} +Content-Type: application/json +Authorization: Bearer {{authToken1}} + +{ + "resource": { + "name": "A new direct channel name" + } +} + +### Update the direct channel member settings for current user + +POST {{directChannelsURL}}/channels/{{directId}}/members/{{userId1}} +Content-Type: application/json +Authorization: Bearer {{authToken1}} + +{ + "resource": { + "favorite": true, + "notification_level": "all" + } +} + +### Update another user member settings should fail + +POST {{directChannelsURL}}/channels/{{directId}}/members/{{userId2}} +Content-Type: application/json +Authorization: Bearer {{authToken1}} + +{ + "resource": { + "favorite": true, + "notification_level": "none" + } +} + +### Get member settings as user1 + +GET {{directChannelsURL}}/channels/{{directId}}/members/{{userId1}} +Content-Type: application/json +Authorization: Bearer {{authToken1}} + +### Get member settings as user2 + +GET {{directChannelsURL}}/channels/{{directId}}/members/{{userId2}} +Content-Type: application/json +Authorization: Bearer {{authToken2}} + +### Get other member settings should fail + +GET {{directChannelsURL}}/channels/{{directId}}/members/{{userId2}} +Content-Type: application/json +Authorization: Bearer {{authToken1}} + +### Leave a direct channel of another user should fail + +DELETE {{directChannelsURL}}/channels/{{directId}}/members/{{userId2}} +Content-Type: application/json +Authorization: Bearer {{authToken1}} + +### Leave a direct channel should not fail + +DELETE {{directChannelsURL}}/channels/{{directId}}/members/{{userId1}} +Content-Type: application/json +Authorization: Bearer {{authToken1}} diff --git a/twake/backend/node/test/http/private-channels-membership.http b/twake/backend/node/test/http/private-channels-membership.http new file mode 100644 index 00000000..12c75b2d --- /dev/null +++ b/twake/backend/node/test/http/private-channels-membership.http @@ -0,0 +1,108 @@ +@company_id = bcfe2f79-8e81-42a3-b551-3a32d49b2b4c +@workspace_id = 3328552c-5ccd-4172-b84a-d876d56aa71b +@baseURL = http://localhost:3000 +@channelsURL = {{baseURL}}/internal/services/channels/v1/companies/{{company_id}}/workspaces/{{workspace_id}} +@directChannelsURL = {{baseURL}}/internal/services/channels/v1/companies/{{company_id}}/workspaces/direct + +### Login as user 1 + +# @name login +GET {{baseURL}}/api/auth/login + +@authTokenUser1 = {{login.response.body.token}} +@currentUserId1 = {{login.response.body.user.id}} + +### Login as user 2 + +# @name login2 +GET {{baseURL}}/api/auth/login + +@authTokenUser2 = {{login2.response.body.token}} +@currentUserId2 = {{login2.response.body.user.id}} + +### User 1 creates a private channel + +# @name createChannel +POST {{channelsURL}}/channels +Content-Type: application/json +Authorization: Bearer {{authTokenUser1}} + +{ + "resource": { + "name": "My private channel", + "icon": "twake logo", + "description": "This channel allow twake's team to chat easily", + "channel_group": "twake", + "visibility": "private", + "is_default": true, + "archived": false + } +} + +### Get the private channel + +@getId = {{createChannel.response.body.resource.id}} + +GET {{channelsURL}}/channels/{{getId}} +Authorization: Bearer {{authTokenUser1}} + +### Get all channel members + +GET {{channelsURL}}/channels/{{getId}}/members?websockets=true +Content-Type: application/json +Authorization: Bearer {{authTokenUser1}} + + +### The user 2 tries to join the private channel, this should reject + +POST {{channelsURL}}/channels/{{getId}}/members +Content-Type: application/json +Authorization: Bearer {{authTokenUser2}} + +{ + "resource": { + "user_id": "{{currentUserId2}}" + } +} + +### The user 1 adds the user 2 as channel member, this should be OK + +POST {{channelsURL}}/channels/{{getId}}/members +Content-Type: application/json +Authorization: Bearer {{authTokenUser1}} + +{ + "resource": { + "user_id": "{{currentUserId2}}" + } +} + +### User 2 lists his channels + +GET {{channelsURL}}/channels?websockets=true&mine=true&limit=5 +Content-Type: application/json +Authorization: Bearer {{authTokenUser2}} + +### Get all channel members as user 1 + +GET {{channelsURL}}/channels/{{getId}}/members?websockets=true +Content-Type: application/json +Authorization: Bearer {{authTokenUser1}} + +### Get all channel members as user 2 + +GET {{channelsURL}}/channels/{{getId}}/members?websockets=true +Content-Type: application/json +Authorization: Bearer {{authTokenUser2}} + +### User 1 leaves the channel he created + +DELETE {{channelsURL}}/channels/{{getId}}/members/{{currentUserId1}} +Content-Type: application/json +Authorization: Bearer {{authTokenUser1}} + +### User 2 leaves the channel: Error since he is the last member, he can not leave + +DELETE {{channelsURL}}/channels/{{getId}}/members/{{currentUserId2}} +Content-Type: application/json +Authorization: Bearer {{authTokenUser2}} diff --git a/twake/backend/node/test/http/private-channels.http b/twake/backend/node/test/http/private-channels.http new file mode 100644 index 00000000..35dc682e --- /dev/null +++ b/twake/backend/node/test/http/private-channels.http @@ -0,0 +1,70 @@ +@company_id = bcfe2f79-8e81-42a3-b551-3a32d49b2b4c +@workspace_id = 3328552c-5ccd-4172-b84a-d876d56aa71b +@user_id = 3328552c-5ccd-4172-b84a-d876d56aa71c + +@baseURL = http://localhost:3000 +@channelsURL = {{baseURL}}/internal/services/channels/v1/companies/{{company_id}}/workspaces/{{workspace_id}} +@directChannelsURL = {{baseURL}}/internal/services/channels/v1/companies/{{company_id}}/workspaces/direct + +# @name login +GET {{baseURL}}/api/auth/login + +@authToken = {{login.response.body.token}} +@currentUserId = {{login.response.body.user.id}} + +### List workspace channels with all websockets + +GET {{channelsURL}}/channels?websockets=true&limit=5 +Content-Type: application/json +Authorization: Bearer {{authToken}} + +### List user channels with all websockets + +@authToken = {{login.response.body.token}} +GET {{channelsURL}}/channels?websockets=true&mine=true&limit=5 +Content-Type: application/json +Authorization: Bearer {{authToken}} + +### Create a private channel + +# @name createChannel +POST {{channelsURL}}/channels +Content-Type: application/json +Authorization: Bearer {{authToken}} + +{ + "resource": { + "name": "My private channel", + "icon": "twake logo", + "description": "A private channel", + "channel_group": "twake", + "visibility": "private", + "is_default": true, + "archived": false + } +} + +### Get the private channel + +@getId = {{createChannel.response.body.resource.id}} + +GET {{channelsURL}}/channels/{{getId}} +Authorization: Bearer {{authToken}} + +### Get members of the private channel + +GET {{channelsURL}}/channels/{{getId}}/members?websockets=true +Content-Type: application/json +Authorization: Bearer {{authToken}} + +### Get current user as member + +GET {{channelsURL}}/channels/{{getId}}/members/{{currentUserId}} +Content-Type: application/json +Authorization: Bearer {{authToken}} + +### Current user quits the private channel will fail because he is the only one in it + +DELETE {{channelsURL}}/channels/{{getId}}/members/{{currentUserId}} +Content-Type: application/json +Authorization: Bearer {{authToken}} diff --git a/twake/backend/node/test/http/public-channels-membership.http b/twake/backend/node/test/http/public-channels-membership.http new file mode 100644 index 00000000..ed8447f5 --- /dev/null +++ b/twake/backend/node/test/http/public-channels-membership.http @@ -0,0 +1,108 @@ +@company_id = bcfe2f79-8e81-42a3-b551-3a32d49b2b4c +@workspace_id = 3328552c-5ccd-4172-b84a-d876d56aa71b +@baseURL = http://localhost:3000 +@channelsURL = {{baseURL}}/internal/services/channels/v1/companies/{{company_id}}/workspaces/{{workspace_id}} +@directChannelsURL = {{baseURL}}/internal/services/channels/v1/companies/{{company_id}}/workspaces/direct + +### Login as user 1 + +# @name login +GET {{baseURL}}/api/auth/login + +@authTokenUser1 = {{login.response.body.token}} +@currentUserId1 = {{login.response.body.user.id}} + +### Login as user 2 + +# @name login2 +GET {{baseURL}}/api/auth/login + +@authTokenUser2 = {{login2.response.body.token}} +@currentUserId2 = {{login2.response.body.user.id}} + +### User 1 creates a public channel + +# @name createChannel +POST {{channelsURL}}/channels +Content-Type: application/json +Authorization: Bearer {{authTokenUser1}} + +{ + "resource": { + "name": "A public channel", + "icon": "twake logo", + "description": "This channel allow twake's team to chat easily", + "channel_group": "twake", + "visibility": "public", + "is_default": true, + "archived": false + } +} + +### Get the public channel + +@getId = {{createChannel.response.body.resource.id}} + +GET {{channelsURL}}/channels/{{getId}} +Authorization: Bearer {{authTokenUser1}} + +### Get all channel members + +GET {{channelsURL}}/channels/{{getId}}/members?websockets=true +Content-Type: application/json +Authorization: Bearer {{authTokenUser1}} + + +### The user 2 joins the public channel, this should be OK + +POST {{channelsURL}}/channels/{{getId}}/members +Content-Type: application/json +Authorization: Bearer {{authTokenUser2}} + +{ + "resource": { + "user_id": "{{currentUserId2}}" + } +} + +### Get all channel members, there are now 2 members + +GET {{channelsURL}}/channels/{{getId}}/members?websockets=true +Content-Type: application/json +Authorization: Bearer {{authTokenUser1}} + +### User 1 lists his channels + +GET {{channelsURL}}/channels?mine=true +Content-Type: application/json +Authorization: Bearer {{authTokenUser1}} + +### User 2 lists his channels + +GET {{channelsURL}}/channels?mine=true +Content-Type: application/json +Authorization: Bearer {{authTokenUser2}} + +### User 2 leaves the channel + +DELETE {{channelsURL}}/channels/{{getId}}/members/{{currentUserId2}} +Content-Type: application/json +Authorization: Bearer {{authTokenUser2}} + +### Get all channel members, there are now 1 member, the initial one + +GET {{channelsURL}}/channels/{{getId}}/members?websockets=true +Content-Type: application/json +Authorization: Bearer {{authTokenUser1}} + +### List channels as user 2, current channel appears since it is public + +GET {{channelsURL}}/channels +Content-Type: application/json +Authorization: Bearer {{authTokenUser2}} + +### User 2 list his public channels, current channel does not appear since he left it + +GET {{channelsURL}}/channels?mine=true +Content-Type: application/json +Authorization: Bearer {{authTokenUser2}} \ No newline at end of file diff --git a/twake/backend/node/test/http/tabs.http b/twake/backend/node/test/http/tabs.http new file mode 100644 index 00000000..1306d705 --- /dev/null +++ b/twake/backend/node/test/http/tabs.http @@ -0,0 +1,85 @@ +@company_id = bcfe2f79-8e81-42a3-b551-3a32d49b2b4c +@workspace_id = 3328552c-5ccd-4172-b84a-d876d56aa71a + + +@baseURL = http://localhost:3000 +@tabsURL = {{baseURL}}/internal/services/channels/v1/companies/{{company_id}}/workspaces/{{workspace_id}}/channels +@channelsURL = {{baseURL}}/internal/services/channels/v1/companies/{{company_id}}/workspaces/{{workspace_id}} + + +# @name login +GET {{baseURL}}/api/auth/login + +@authToken = {{login.response.body.token}} +@currentUserId = {{login.response.body.user.id}} + + +### List channel's tab with all websockets +GET {{tabsURL}}/{{channelId}}/tabs?websockets=true&limit=5 +Content-Type: application/json +Authorization: Bearer {{authToken}} + + +### Create a channel +# @name createChannel +POST {{channelsURL}}/channels +Content-Type: application/json +Authorization: Bearer {{authToken}} + +{ + "resource": { + "name": "My channel", + "icon": "twake logo", + "description": "This channel allow twake's team to chat easily", + "channel_group": "twake", + "visibility": "public", + "is_default": true, + "archived": false + } +} + + +### Create a tab +# @name createTab +@channelId = {{createChannel.response.body.resource.id}} + +POST {{tabsURL}}/{{channelId}}/tabs +Content-Type: application/json +Authorization: Bearer {{authToken}} + +{ + "resource": { + // WARNING : special caracter in tab's name does not work + "name": "My tabs name", + "configuration": "JSON" + } +} + + +### Get a single tab +@getId = {{createTab.response.body.resource.id}} + +GET {{tabsURL}}/{{channelId}}/tabs/{{getId}} +Authorization: Bearer {{authToken}} + + +### Update a tab +@updateId = {{createTab.response.body.resource.id}} + +POST {{tabsURL}}/{{channelId}}/tabs/{{updateId}} +Content-Type: application/json +Authorization: Bearer {{authToken}} + +{ + "resource": { + "name": "My tab updated", + "configuration": "JSON" + } +} + + +### Delete a tab +@deleteId = {{createTab.response.body.resource.id}} + +DELETE {{tabsURL}}/{{channelId}}/tabs/{{deleteId}} +Authorization: Bearer {{authToken}} \ No newline at end of file diff --git a/twake/backend/node/test/http/users.http b/twake/backend/node/test/http/users.http new file mode 100644 index 00000000..14afcdc5 --- /dev/null +++ b/twake/backend/node/test/http/users.http @@ -0,0 +1,18 @@ +@company_id = bcfe2f79-8e81-42a3-b551-3a32d49b2b4c +@workspace_id = 3328552c-5ccd-4172-b84a-d876d56aa71b +@user_id = 508c8c1a-706f-11eb-b6be-0242ac120002 + +@baseURL = http://localhost:3000 +@usersURL = {{baseURL}}/internal/services/users/v1 + +# @name login +GET {{baseURL}}/api/auth/login + +@authToken = {{login.response.body.token}} +@currentUserId = {{login.response.body.user.id}} + +### Get a single user + +GET {{usersURL}}/users/{{user_id}} +Content-Type: application/json +Authorization: Bearer {{authToken}} diff --git a/twake/backend/node/test/http/workspaces.http b/twake/backend/node/test/http/workspaces.http new file mode 100644 index 00000000..81dae28d --- /dev/null +++ b/twake/backend/node/test/http/workspaces.http @@ -0,0 +1,58 @@ +@baseURL = http://localhost:8000 + +@workspacesURL = {{baseURL}}/internal/services/workspaces/v1 +@usersURL = {{baseURL}}/internal/services/users/v1 + +@company_id = 357d0f1c-9dc9-11eb-ae20-0242ac120002 +@workspace_id = 361a5be0-f509-11eb-a69b-d9862196e0cd +@user_id = ca68bc2a-81a4-11eb-8cf1-0242ac1e0002 + +# @name login +POST {{baseURL}}/internal/services/console/v1/login +Content-Type: application/json + +{ + "email": "", + "password": "" +} + +### AUTH - GET TOKEN +@authToken = {{login.response.body.access_token.value}} + +### USERS - GET +GET {{usersURL}}/users/{{user_id}} +Content-Type: application/json +Authorization: Bearer {{authToken}} + +### WORKSPACES - LIST +GET {{workspacesURL}}/companies/{{company_id}}/workspaces +Content-Type: application/json +Authorization: Bearer {{authToken}} + +### WORKSPACES - CREATE +POST {{workspacesURL}}/companies/{{company_id}}/workspaces +Content-Type: application/json +Authorization: Bearer {{authToken}} + +{ + "resource": { + "name": "created workspace", + "logo": "", + "default": false, + "archived": false + } +} + +### WORKSPACES - UPDATE +POST {{workspacesURL}}/companies/{{company_id}}/workspaces/{{workspace_id}} +Content-Type: application/json +Authorization: Bearer {{authToken}} + +{ + "resource": { + "name": "updated workspace", + "logo": "", + "default": false, + "archived": false + } +} \ No newline at end of file diff --git a/twake/backend/node/test/unit/core/platform/framework/decorators/realtime/created.test.ts b/twake/backend/node/test/unit/core/platform/framework/decorators/realtime/created.test.ts new file mode 100644 index 00000000..19cd9250 --- /dev/null +++ b/twake/backend/node/test/unit/core/platform/framework/decorators/realtime/created.test.ts @@ -0,0 +1,116 @@ +import { describe, expect, it, jest } from "@jest/globals"; +import { CreateResult } from "../../../../../../../src/core/platform/framework/api/crud-service"; +import { RealtimeCreated } from "../../../../../../../src/core/platform/framework/decorators"; +import { websocketEventBus } from "../../../../../../../src/core/platform/services/realtime/bus"; +import { ResourcePath } from "../../../../../../../src/core/platform/services/realtime/types"; + +describe("The RealtimeCreated decorator", () => { + it("should call the original method send back original result but do not emit event if result type is wrong", async done => { + const emitSpy = jest.spyOn(websocketEventBus, "emit"); + + class TestMe { + @RealtimeCreated({ room: "/foo/bar" }) + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + reverseMeBaby(input: string): Promise { + return Promise.resolve(input.split("").reverse().join("")); + } + } + + const test = new TestMe(); + const originalSpy = jest.spyOn(test, "reverseMeBaby"); + const result = await test.reverseMeBaby("yolo"); + + expect(result).toEqual("oloy"); + expect(originalSpy).toHaveBeenCalledTimes(1); + expect(originalSpy).toHaveBeenCalledWith("yolo"); + expect(emitSpy).toHaveBeenCalledTimes(0); + + emitSpy.mockRestore(); + done(); + }); + + it("should call the original method send back original result and emit event", async done => { + const emitSpy = jest.spyOn(websocketEventBus, "emit"); + + class TestMe { + @RealtimeCreated({ room: "/foo/bar", path: "/foo/bar/baz" }) + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + async reverseMeBaby(input: string): Promise> { + return new CreateResult("string", input.split("").reverse().join("")); + } + } + + const test = new TestMe(); + const originalSpy = jest.spyOn(test, "reverseMeBaby"); + const result = await test.reverseMeBaby("yolo"); + + expect(result.entity).toEqual("oloy"); + expect(originalSpy).toHaveBeenCalledTimes(1); + expect(originalSpy).toHaveBeenCalledWith("yolo"); + expect(emitSpy).toHaveBeenCalledTimes(1); + expect(emitSpy).toHaveBeenCalledWith("created", { + room: { + name: "default", + path: ["/foo/bar"], + } as ResourcePath, + resourcePath: "/foo/bar/baz", + entity: "oloy", + type: "string", + result: { + entity: "oloy", + type: "string", + context: undefined, + operation: "create", + raw: undefined, + } as CreateResult, + }); + + emitSpy.mockRestore(); + done(); + }); + + it("should emit event with path computed from function", async done => { + const emitSpy = jest.spyOn(websocketEventBus, "emit"); + + class TestMe { + @RealtimeCreated(input => [ + { room: ResourcePath.get(`/foo/bar/${input}`), path: "/foo/bar/baz" }, + ]) + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + async reverseMeBaby(input: string): Promise> { + return new CreateResult("string", input.split("").reverse().join("")); + } + } + + const test = new TestMe(); + const originalSpy = jest.spyOn(test, "reverseMeBaby"); + const result = await test.reverseMeBaby("yolo"); + + expect(result.entity).toEqual("oloy"); + expect(originalSpy).toHaveBeenCalledTimes(1); + expect(originalSpy).toHaveBeenCalledWith("yolo"); + expect(emitSpy).toHaveBeenCalledTimes(1); + expect(emitSpy).toHaveBeenCalledWith("created", { + room: { + name: "default", + path: ["/foo/bar/oloy"], + } as ResourcePath, + resourcePath: "/foo/bar/baz", + entity: "oloy", + type: "string", + result: { + entity: "oloy", + context: undefined, + operation: "create", + type: "string", + raw: undefined, + } as CreateResult, + }); + + emitSpy.mockRestore(); + done(); + }); +}); diff --git a/twake/backend/node/test/unit/core/platform/framework/decorators/realtime/deleted.test.ts b/twake/backend/node/test/unit/core/platform/framework/decorators/realtime/deleted.test.ts new file mode 100644 index 00000000..d41290ba --- /dev/null +++ b/twake/backend/node/test/unit/core/platform/framework/decorators/realtime/deleted.test.ts @@ -0,0 +1,116 @@ +import { describe, expect, it, jest } from "@jest/globals"; +import { DeleteResult } from "../../../../../../../src/core/platform/framework/api/crud-service"; +import { RealtimeDeleted } from "../../../../../../../src/core/platform/framework/decorators"; +import { websocketEventBus } from "../../../../../../../src/core/platform/services/realtime/bus"; +import { ResourcePath } from "../../../../../../../src/core/platform/services/realtime/types"; + +describe("The RealtimeDeleted decorator", () => { + it("should call the original method send back original result but do not emit event if result type is wrong", async done => { + const emitSpy = jest.spyOn(websocketEventBus, "emit"); + + class TestMe { + @RealtimeDeleted({ room: "/foo/bar" }) + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + reverseMeBaby(input: string): Promise { + return Promise.resolve(input.split("").reverse().join("")); + } + } + + const test = new TestMe(); + const originalSpy = jest.spyOn(test, "reverseMeBaby"); + const result = await test.reverseMeBaby("yolo"); + + expect(result).toEqual("oloy"); + expect(originalSpy).toHaveBeenCalledTimes(1); + expect(originalSpy).toHaveBeenCalledWith("yolo"); + expect(emitSpy).toHaveBeenCalledTimes(0); + + emitSpy.mockRestore(); + done(); + }); + + it("should call the original method send back original result and emit event", async done => { + const emitSpy = jest.spyOn(websocketEventBus, "emit"); + + class TestMe { + @RealtimeDeleted({ room: "/foo/bar", path: "/foo/bar/baz" }) + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + async reverseMeBaby(input: string): Promise> { + return new DeleteResult("string", input.split("").reverse().join(""), true); + } + } + + const test = new TestMe(); + const originalSpy = jest.spyOn(test, "reverseMeBaby"); + const result = await test.reverseMeBaby("yolo"); + + expect(result.entity).toEqual("oloy"); + expect(originalSpy).toHaveBeenCalledTimes(1); + expect(originalSpy).toHaveBeenCalledWith("yolo"); + expect(emitSpy).toHaveBeenCalledTimes(1); + expect(emitSpy).toHaveBeenCalledWith("deleted", { + room: { + name: "default", + path: ["/foo/bar"], + } as ResourcePath, + resourcePath: "/foo/bar/baz", + entity: "oloy", + type: "string", + result: { + entity: "oloy", + context: undefined, + operation: "delete", + deleted: true, + type: "string", + } as DeleteResult, + }); + + emitSpy.mockRestore(); + done(); + }); + + it("should emit event with path computed from function", async done => { + const emitSpy = jest.spyOn(websocketEventBus, "emit"); + + class TestMe { + @RealtimeDeleted(result => [ + { room: ResourcePath.get(`/foo/bar/${result}`), path: "/foo/bar/baz" }, + ]) + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + async reverseMeBaby(input: string): Promise> { + return new DeleteResult("string", input.split("").reverse().join(""), true); + } + } + + const test = new TestMe(); + const originalSpy = jest.spyOn(test, "reverseMeBaby"); + const result = await test.reverseMeBaby("yolo"); + + expect(result.entity).toEqual("oloy"); + expect(originalSpy).toHaveBeenCalledTimes(1); + expect(originalSpy).toHaveBeenCalledWith("yolo"); + expect(emitSpy).toHaveBeenCalledTimes(1); + expect(emitSpy).toHaveBeenCalledWith("deleted", { + room: { + name: "default", + path: ["/foo/bar/oloy"], + } as ResourcePath, + resourcePath: "/foo/bar/baz", + entity: "oloy", + type: "string", + result: { + entity: "oloy", + context: undefined, + operation: "delete", + deleted: true, + type: "string", + } as DeleteResult, + }); + + emitSpy.mockRestore(); + done(); + }); +}); diff --git a/twake/backend/node/test/unit/core/platform/framework/decorators/realtime/updated.test.ts b/twake/backend/node/test/unit/core/platform/framework/decorators/realtime/updated.test.ts new file mode 100644 index 00000000..af2929cb --- /dev/null +++ b/twake/backend/node/test/unit/core/platform/framework/decorators/realtime/updated.test.ts @@ -0,0 +1,118 @@ +import { describe, expect, it, jest } from "@jest/globals"; +import { UpdateResult } from "../../../../../../../src/core/platform/framework/api/crud-service"; +import { RealtimeUpdated } from "../../../../../../../src/core/platform/framework/decorators"; +import { websocketEventBus } from "../../../../../../../src/core/platform/services/realtime/bus"; +import { ResourcePath } from "../../../../../../../src/core/platform/services/realtime/types"; + +describe("The RealtimeUpdated decorator", () => { + it("should call the original method send back original result but do not emit event if result type is wrong", async done => { + const emitSpy = jest.spyOn(websocketEventBus, "emit"); + + class TestMe { + @RealtimeUpdated({ room: "/foo/bar" }) + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + reverseMeBaby(input: string): Promise { + return Promise.resolve(input.split("").reverse().join("")); + } + } + + const test = new TestMe(); + const originalSpy = jest.spyOn(test, "reverseMeBaby"); + const result = await test.reverseMeBaby("yolo"); + + expect(result).toEqual("oloy"); + expect(originalSpy).toHaveBeenCalledTimes(1); + expect(originalSpy).toHaveBeenCalledWith("yolo"); + expect(emitSpy).toHaveBeenCalledTimes(0); + + emitSpy.mockRestore(); + done(); + }); + + it("should call the original method send back original result and emit event", async done => { + const emitSpy = jest.spyOn(websocketEventBus, "emit"); + + class TestMe { + @RealtimeUpdated({ room: "/foo/bar", path: "/foo/bar/baz" }) + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + async reverseMeBaby(input: string): Promise> { + return new UpdateResult("string", input.split("").reverse().join("")); + } + } + + const test = new TestMe(); + const originalSpy = jest.spyOn(test, "reverseMeBaby"); + const result = await test.reverseMeBaby("yolo"); + + expect(result.entity).toEqual("oloy"); + expect(originalSpy).toHaveBeenCalledTimes(1); + expect(originalSpy).toHaveBeenCalledWith("yolo"); + expect(emitSpy).toHaveBeenCalledTimes(1); + expect(emitSpy).toHaveBeenCalledWith("updated", { + entity: "oloy", + room: { + name: "default", + path: ["/foo/bar"], + } as ResourcePath, + resourcePath: "/foo/bar/baz", + type: "string", + result: { + type: "string", + entity: "oloy", + affected: undefined, + context: undefined, + operation: "update", + raw: undefined, + } as UpdateResult, + }); + + emitSpy.mockRestore(); + done(); + }); + + it("should emit event with path computed from function", async done => { + const emitSpy = jest.spyOn(websocketEventBus, "emit"); + + class TestMe { + @RealtimeUpdated(result => [ + { room: ResourcePath.get(`/foo/bar/${result}`), path: "/foo/bar/baz" }, + ]) + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + async reverseMeBaby(input: string): Promise> { + return new UpdateResult("string", input.split("").reverse().join("")); + } + } + + const test = new TestMe(); + const originalSpy = jest.spyOn(test, "reverseMeBaby"); + const result = await test.reverseMeBaby("yolo"); + + expect(result.entity).toEqual("oloy"); + expect(originalSpy).toHaveBeenCalledTimes(1); + expect(originalSpy).toHaveBeenCalledWith("yolo"); + expect(emitSpy).toHaveBeenCalledTimes(1); + expect(emitSpy).toHaveBeenCalledWith("updated", { + entity: "oloy", + room: { + name: "default", + path: ["/foo/bar/oloy"], + } as ResourcePath, + resourcePath: "/foo/bar/baz", + type: "string", + result: { + type: "string", + context: undefined, + operation: "update", + entity: "oloy", + affected: undefined, + raw: undefined, + } as UpdateResult, + }); + + emitSpy.mockRestore(); + done(); + }); +}); diff --git a/twake/backend/node/test/unit/core/services/database/services/orm/connectors/cassandra/query-builder.test.ts b/twake/backend/node/test/unit/core/services/database/services/orm/connectors/cassandra/query-builder.test.ts new file mode 100644 index 00000000..62f111d6 --- /dev/null +++ b/twake/backend/node/test/unit/core/services/database/services/orm/connectors/cassandra/query-builder.test.ts @@ -0,0 +1,181 @@ +import "reflect-metadata"; +import { describe, expect, it } from "@jest/globals"; +import { + buildSelectQuery, + buildComparison, + buildIn, +} from "../../../../../../../../../src/core/platform/services/database/services/orm/connectors/cassandra/query-builder"; +import { ChannelMemberNotificationPreference } from "../../../../../../../../../src/services/notifications/entities/channel-member-notification-preferences"; + +describe("The QueryBuilder module", () => { + describe("The buildSelectQuery function", () => { + it("should build a valid query from primary key parameters", () => { + const filters = { + company_id: "comp1", + channel_id: "chan1", + }; + const result = buildSelectQuery( + ChannelMemberNotificationPreference, + filters, + {}, + { keyspace: "twake" }, + ); + + expect(result).toEqual( + "SELECT * FROM twake.channel_members_notification_preferences WHERE company_id = comp1 AND channel_id = chan1;", + ); + }); + + it("should build a valid query from primary key parameters and comparison", () => { + const filters = { + company_id: "comp1", + channel_id: "chan1", + }; + const result = buildSelectQuery( + ChannelMemberNotificationPreference, + filters, + { + $lt: [["last_read", 1000]], + }, + { keyspace: "twake" }, + ); + + expect(result).toEqual( + "SELECT * FROM twake.channel_members_notification_preferences WHERE company_id = comp1 AND channel_id = chan1 AND last_read < 1000;", + ); + }); + + it("should build IN query from array parameters", () => { + const filters = { + company_id: "comp1", + channel_id: "chan1", + user_id: ["u1", "u2", "u3"], + }; + const result = buildSelectQuery( + ChannelMemberNotificationPreference, + filters, + {}, + { keyspace: "twake" }, + ); + + expect(result).toEqual( + "SELECT * FROM twake.channel_members_notification_preferences WHERE company_id = comp1 AND channel_id = chan1 AND user_id IN (u1,u2,u3);", + ); + }); + + it("should not build IN query from array parameters when array is empty", () => { + const filters = { + company_id: "comp1", + channel_id: "chan1", + user_id: [], + }; + const result = buildSelectQuery( + ChannelMemberNotificationPreference, + filters, + {}, + { keyspace: "twake" }, + ); + + expect(result).toEqual( + "SELECT * FROM twake.channel_members_notification_preferences WHERE company_id = comp1 AND channel_id = chan1;", + ); + }); + }); + + describe("The buildComparison function", () => { + it("should create a valid < string", () => { + expect( + buildComparison({ + $lt: [["foo", 1]], + }), + ).toContain("foo < 1"); + + const result = buildComparison({ + $lt: [ + ["foo", 1], + ["bar", 2], + ], + }); + + expect(result).toContain("foo < 1"); + expect(result).toContain("bar < 2"); + }); + + it("should create a valid <= string", () => { + expect( + buildComparison({ + $lte: [["foo", 1]], + }), + ).toContain("foo <= 1"); + + const result = buildComparison({ + $lte: [ + ["foo", 1], + ["bar", 2], + ], + }); + + expect(result).toContain("foo <= 1"); + expect(result).toContain("bar <= 2"); + }); + + it("should create a valid > string", () => { + expect( + buildComparison({ + $gt: [["foo", 1]], + }), + ).toContain("foo > 1"); + + const result = buildComparison({ + $gt: [ + ["foo", 1], + ["bar", 2], + ], + }); + + expect(result).toContain("foo > 1"); + expect(result).toContain("bar > 2"); + }); + + it("should create a valid >= string", () => { + expect( + buildComparison({ + $gte: [["foo", 1]], + }), + ).toContain("foo >= 1"); + + const result = buildComparison({ + $gte: [ + ["foo", 1], + ["bar", 2], + ], + }); + + expect(result).toContain("foo >= 1"); + expect(result).toContain("bar >= 2"); + }); + + it("should combine conditions", () => { + const result = buildComparison({ + $gt: [["foo", 1]], + $gte: [["bar", 2]], + $lt: [["baz", 3]], + $lte: [["qix", 4]], + }); + expect(result).toContain("foo > 1"); + expect(result).toContain("bar >= 2"); + expect(result).toContain("baz < 3"); + expect(result).toContain("qix <= 4"); + }); + }); + + describe("The buildIn function", () => { + it("should create a id IN (ids) string", () => { + expect( + buildIn({ + $in: [["id", ["1", "2", "3"]]], + }), + ).toContain("id IN (1,2,3)"); + }); + }); +}); diff --git a/twake/backend/node/test/unit/core/services/database/services/utils.test.ts b/twake/backend/node/test/unit/core/services/database/services/utils.test.ts new file mode 100644 index 00000000..11fbac06 --- /dev/null +++ b/twake/backend/node/test/unit/core/services/database/services/utils.test.ts @@ -0,0 +1,31 @@ +import "reflect-metadata"; +import { describe, expect, it } from "@jest/globals"; +import { + fromMongoDbOrderable, + toMongoDbOrderable, +} from "../../../../../../src/core/platform/services/database/services/orm/utils"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import _ from "lodash"; +import { v1 as uuidv1 } from "uuid"; + +describe("The MongoDb to Orderable module", () => { + describe("The to/from orderable function", () => { + it("should be unique", () => { + const uuid1 = toMongoDbOrderable(uuidv1()); + const uuid2 = toMongoDbOrderable(uuidv1()); + const uuid3 = toMongoDbOrderable(uuidv1()); + const uuid4 = toMongoDbOrderable(uuidv1()); + + expect(_.uniq([uuid1, uuid2, uuid3, uuid4]).length).toBe(4); + }); + + it("should convert both ways", () => { + const uuid = uuidv1(); + const orderable = toMongoDbOrderable(uuid); + + expect(fromMongoDbOrderable(orderable)).toBe(uuid); + expect(orderable).toBe(toMongoDbOrderable(fromMongoDbOrderable(orderable))); + }); + }); +}); diff --git a/twake/backend/node/test/unit/core/services/encryption/encryption.test.ts b/twake/backend/node/test/unit/core/services/encryption/encryption.test.ts new file mode 100644 index 00000000..83f7ea1c --- /dev/null +++ b/twake/backend/node/test/unit/core/services/encryption/encryption.test.ts @@ -0,0 +1,31 @@ +import { describe, expect, it } from "@jest/globals"; +import { decrypt } from "../../../../../src/core/crypto/index"; +import v2 from "../../../../../src/core/crypto/v2"; +import v1 from "../../../../../src/core/crypto/v1"; +import legacy from "../../../../../src/core/crypto/legacy"; + +describe("Encryption", () => { + const encryptionKey = "a7c06651a7c063bb3e90c0c9a17eab88ab8977665127196a"; + + describe("The encrypt/decrypt functions", () => { + it("should successfully describe legacy encrypted values", async () => { + const legacyEncrypted = "encrypted_DwMLnKhuFbIanqBJPA5rcw=="; + + expect(legacy.decrypt(legacyEncrypted, encryptionKey).data).toBe("My company"); + expect(decrypt(legacyEncrypted, encryptionKey).data).toBe("My company"); + }); + + it("should successfully describe all versions", async () => { + const myData = { key: "some data" }; + + const v1Encrypted = v1.encrypt(myData, encryptionKey); + const v2Encrypted = v2.encrypt(myData, encryptionKey); + + expect(v1.decrypt(v1Encrypted.data, encryptionKey).data).toMatchObject(myData); + expect(v2.decrypt(v2Encrypted.data, encryptionKey).data).toMatchObject(myData); + + expect(decrypt(v1Encrypted.data, encryptionKey).data).toMatchObject(myData); + expect(decrypt(v2Encrypted.data, encryptionKey).data).toMatchObject(myData); + }); + }); +}); diff --git a/twake/backend/node/test/unit/core/services/pubsub/processor/pubsubserviceprocessor.test.ts b/twake/backend/node/test/unit/core/services/pubsub/processor/pubsubserviceprocessor.test.ts new file mode 100644 index 00000000..854f301e --- /dev/null +++ b/twake/backend/node/test/unit/core/services/pubsub/processor/pubsubserviceprocessor.test.ts @@ -0,0 +1,305 @@ +import { describe, expect, it, jest, beforeEach, afterEach } from "@jest/globals"; +import { + IncomingMessageQueueMessage, + MessageQueueHandler, + MessageQueueServiceAPI, + MessageQueueServiceProcessor, +} from "../../../../../../src/core/platform/services/message-queue/api"; + +describe("The MessageQueueServiceProcessor class", () => { + let pubsubService: MessageQueueServiceAPI; + let subscribe; + let publish; + let topic; + let errorTopic; + let outTopic; + + beforeEach(() => { + topic = "inputtopic"; + errorTopic = "errorTopic"; + outTopic = "outTopic"; + subscribe = jest.fn(); + publish = jest.fn(); + pubsubService = { + publish, + subscribe, + } as unknown as MessageQueueServiceAPI; + }); + + afterEach(() => { + jest.restoreAllMocks(); + jest.resetAllMocks(); + }); + + describe("The init function", () => { + it("should not subscribe when topics is not defined", async () => { + subscribe.mockResolvedValue(true); + const processor = new MessageQueueServiceProcessor( + {} as MessageQueueHandler, + pubsubService, + ); + + await processor.init(); + expect(subscribe).not.toHaveBeenCalled; + }); + + it("should not subscribe when topics.in is not defined", async () => { + subscribe.mockResolvedValue(true); + const processor = new MessageQueueServiceProcessor( + { + topics: {}, + } as MessageQueueHandler, + pubsubService, + ); + + await processor.init(); + expect(subscribe).not.toHaveBeenCalled; + }); + + it("should subscribe when topics.in is defined", async () => { + subscribe.mockResolvedValue(true); + const processor = new MessageQueueServiceProcessor( + { + topics: { + in: topic, + }, + } as MessageQueueHandler, + pubsubService, + ); + + await processor.init(); + expect(subscribe).toHaveBeenCalledTimes(1); + expect(subscribe).toHaveBeenCalledWith(topic, expect.any(Function), undefined); + }); + }); + + describe("The function handling incoming messages", () => { + describe("When handler.validate is defined", () => { + it("should not process data when data is not valid", async () => { + const message = { + data: "foo", + } as IncomingMessageQueueMessage; + const validate = jest.fn().mockReturnValue(false); + const process = jest.fn().mockReturnValue(true); + const processor = new MessageQueueServiceProcessor( + { + topics: { + in: topic, + }, + validate, + process, + } as unknown as MessageQueueHandler, + pubsubService, + ); + + await processor.init(); + const processMessage = subscribe.mock.calls[0][1]; + await processMessage(message); + + expect(validate).toBeCalledTimes(1); + expect(validate).toBeCalledWith(message.data); + expect(process).not.toHaveBeenCalled; + }); + + it("should process data when data is valid", async () => { + const message = { + data: "foo", + } as IncomingMessageQueueMessage; + const validate = jest.fn().mockReturnValue(true); + const process = jest.fn().mockReturnValue(true); + const processor = new MessageQueueServiceProcessor( + { + topics: { + in: topic, + }, + validate, + process, + } as unknown as MessageQueueHandler, + pubsubService, + ); + + await processor.init(); + const processMessage = subscribe.mock.calls[0][1]; + await processMessage(message); + + expect(validate).toBeCalledTimes(1); + expect(validate).toBeCalledWith(message.data); + expect(process).toHaveBeenCalled; + }); + }); + + describe("When processing message", () => { + it("should not publish error when topics.error is not defined", async () => { + const message = { + data: "foo", + } as IncomingMessageQueueMessage; + const process = jest.fn().mockRejectedValue(new Error("I failed to process")); + const processor = new MessageQueueServiceProcessor( + { + topics: { + in: topic, + }, + process, + } as unknown as MessageQueueHandler, + pubsubService, + ); + + await processor.init(); + const processMessage = subscribe.mock.calls[0][1]; + await processMessage(message); + + expect(process).toBeCalledTimes(1); + expect(process).toHaveBeenCalledWith(message.data); + expect(publish).not.toBeCalled; + }); + + it("should publish error when topics.error is defined", async () => { + const message = { + data: "foo", + } as IncomingMessageQueueMessage; + const process = jest.fn().mockRejectedValue(new Error("I failed to process")); + const processor = new MessageQueueServiceProcessor( + { + topics: { + in: topic, + error: errorTopic, + }, + process, + } as unknown as MessageQueueHandler, + pubsubService, + ); + + await processor.init(); + const processMessage = subscribe.mock.calls[0][1]; + await processMessage(message); + + expect(process).toBeCalledTimes(1); + expect(process).toHaveBeenCalledWith(message.data); + expect(publish).toBeCalledTimes(1); + expect(publish).toBeCalledWith(errorTopic, expect.anything()); + }); + + it("should not publish when processing does not return result", async () => { + const message = { + data: "foo", + } as IncomingMessageQueueMessage; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const process = jest.fn().mockResolvedValue(null); + const processor = new MessageQueueServiceProcessor( + { + topics: { + in: topic, + out: outTopic, + error: errorTopic, + }, + process, + } as unknown as MessageQueueHandler, + pubsubService, + ); + + await processor.init(); + const processMessage = subscribe.mock.calls[0][1]; + await processMessage(message); + + expect(process).toBeCalledTimes(1); + expect(process).toHaveBeenCalledWith(message.data); + expect(publish).not.toBeCalled; + }); + + it("should not publish when out topic is not defined", async () => { + const message = { + data: "foo", + } as IncomingMessageQueueMessage; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const process = jest.fn().mockResolvedValue(true); + const processor = new MessageQueueServiceProcessor( + { + topics: { + in: topic, + error: errorTopic, + }, + process, + } as unknown as MessageQueueHandler, + pubsubService, + ); + + await processor.init(); + const processMessage = subscribe.mock.calls[0][1]; + await processMessage(message); + + expect(process).toBeCalledTimes(1); + expect(process).toHaveBeenCalledWith(message.data); + expect(publish).not.toBeCalled; + }); + + it("should publish when out topic is defined and process returns result", async () => { + const result = "processing result"; + const message = { + data: "foo", + } as IncomingMessageQueueMessage; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const process = jest.fn().mockResolvedValue(result); + const processor = new MessageQueueServiceProcessor( + { + topics: { + in: topic, + error: errorTopic, + out: outTopic, + }, + process, + } as unknown as MessageQueueHandler, + pubsubService, + ); + + await processor.init(); + const processMessage = subscribe.mock.calls[0][1]; + await processMessage(message); + + expect(process).toBeCalledTimes(1); + expect(process).toHaveBeenCalledWith(message.data); + expect(publish).toBeCalledTimes(1); + expect(publish).toBeCalledWith( + outTopic, + expect.objectContaining({ + data: result, + }), + ); + }); + + it("should publish error when result can not be published", async () => { + publish.mockRejectedValue(new Error("I failed to publish")); + const result = "processing result"; + const message = { + data: "foo", + } as IncomingMessageQueueMessage; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const process = jest.fn().mockResolvedValue(result); + const processor = new MessageQueueServiceProcessor( + { + topics: { + in: topic, + error: errorTopic, + out: outTopic, + }, + process, + } as unknown as MessageQueueHandler, + pubsubService, + ); + + await processor.init(); + const processMessage = subscribe.mock.calls[0][1]; + await processMessage(message); + + expect(process).toBeCalledTimes(1); + expect(process).toHaveBeenCalledWith(message.data); + expect(publish).toBeCalledTimes(2); + expect(publish.mock.calls[0][0]).toEqual(outTopic); + expect(publish.mock.calls[1][0]).toEqual(errorTopic); + }); + }); + }); +}); diff --git a/twake/backend/node/test/unit/pick.test.ts b/twake/backend/node/test/unit/pick.test.ts new file mode 100644 index 00000000..31f666dd --- /dev/null +++ b/twake/backend/node/test/unit/pick.test.ts @@ -0,0 +1,35 @@ +import { describe, expect, it } from "@jest/globals"; +import * as pickUtils from "../../src/utils/pick"; + +describe("The pick utils", () => { + describe("The pick function", () => { + it("should return an object wich contains only the defined properties", () => { + class TestClass { + keep: string; + me: string; + skip: string; + } + + const keysToKeep = ["keep", "me"] as const; + const object = { keep: "foo", me: "bar", skip: "baz" } as TestClass; + const result = pickUtils.pick(object, ...keysToKeep); + + expect(result).toEqual({ keep: "foo", me: "bar" }); + expect(result).not.toContain("skip"); + }); + + it("should return an empty object when input is empty", () => { + class TestClass { + keep: string; + me: string; + skip: string; + } + + const keysToKeep = [] as const; + const object = { keep: "foo", me: "bar", skip: "baz" } as TestClass; + const result = pickUtils.pick(object, ...keysToKeep); + + expect(result).toEqual({}); + }); + }); +}); diff --git a/twake/backend/node/test/unit/services/notifications/services/engine/processors/new-channel-message/index.test.ts b/twake/backend/node/test/unit/services/notifications/services/engine/processors/new-channel-message/index.test.ts new file mode 100644 index 00000000..4688d431 --- /dev/null +++ b/twake/backend/node/test/unit/services/notifications/services/engine/processors/new-channel-message/index.test.ts @@ -0,0 +1,504 @@ +import { afterEach, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import { + ListResult, + OperationType, + SaveResult, +} from "../../../../../../../../src/core/platform/framework/api/crud-service"; +import { ChannelMemberNotificationLevel } from "../../../../../../../../src/services/channels/types"; +import { MessageNotification } from "../../../../../../../../src/services/messages/types"; +import { + ChannelMemberNotificationPreference, + ChannelThreadUsers, +} from "../../../../../../../../src/services/notifications/entities"; +import { ChannelType } from "../../../../../../../../src/utils/types"; +import gr from "../../../../../../../../src/services/global-resolver"; +import { NewChannelMessageProcessor } from "../../../../../../../../src/services/notifications/services/engine/processors/new-channel-message"; + +describe("The NewChannelMessageProcessor class", () => { + let channel_id, company_id, workspace_id, thread_id; + let service: any; + let processor: NewChannelMessageProcessor; + let getUsersInThread; + let getChannelPreferencesForUsers; + + beforeEach(() => { + channel_id = "channel_id"; + company_id = "company_id"; + workspace_id = "workspace_id"; + + getUsersInThread = jest.fn(); + getChannelPreferencesForUsers = jest.fn(); + + setPreferences(); + setUsersInThread(); + + service = { + channelThreads: { + bulkSave: jest + .fn() + .mockResolvedValue( + new SaveResult("thread", [], OperationType.CREATE) as never, + ), + getUsersInThread, + }, + channelPreferences: { + getChannelPreferencesForUsers, + }, + }; + + gr.services = { + notifications: service, + } as any; + + processor = new NewChannelMessageProcessor(); + }); + + afterEach(() => { + jest.restoreAllMocks(); + jest.resetAllMocks(); + }); + + function getMessage(newThread: boolean = false): MessageNotification { + const message = { + company_id, + workspace_id, + channel_id, + id: "id", + thread_id: "thread_id", + sender: "sender", + mentions: { + users: [], + }, + } as MessageNotification; + + if (newThread) { + // message is new thread when thread_id is not defined + message.thread_id = undefined; + } + + return message; + } + + function setPreferences(preferences: ChannelMemberNotificationPreference[] = []): void { + getChannelPreferencesForUsers.mockResolvedValue( + new ListResult("preferences", preferences), + ); + } + + function setUsersInThread(users: string[] = []) { + getUsersInThread.mockResolvedValue( + new ListResult( + "users", + users.map( + user_id => + ({ + company_id, + channel_id, + workspace_id, + thread_id, + user_id, + } as ChannelThreadUsers), + ), + ), + ); + } + + describe("The process method", () => { + describe("When message is a new thread", () => { + function setNewThreadPreferences() { + setPreferences([ + { + channel_id, + company_id, + user_id: "1", + last_read: Date.now(), + preferences: ChannelMemberNotificationLevel.ALL, + }, + { + channel_id, + company_id, + user_id: "2", + last_read: Date.now(), + preferences: ChannelMemberNotificationLevel.MENTIONS, + }, + { + channel_id, + company_id, + user_id: "3", + last_read: Date.now(), + preferences: ChannelMemberNotificationLevel.ME, + }, + { + channel_id, + company_id, + user_id: "4", + last_read: Date.now(), + preferences: ChannelMemberNotificationLevel.NONE, + }, + ]); + } + + it("should return undefined when there is no one to notify", async done => { + const message = getMessage(true); + const result = await processor.process(message); + + expect(service.channelThreads.bulkSave).toBeCalledTimes(1); + expect(service.channelThreads.bulkSave).toBeCalledWith( + [ + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.id, + user_id: message.sender, + }, + ], + undefined, + ); + + expect(service.channelThreads.getUsersInThread).not.toBeCalled; + expect(service.channelPreferences.getChannelPreferencesForUsers).toBeCalledTimes(1); + expect(service.channelPreferences.getChannelPreferencesForUsers).toBeCalledWith({ + company_id: message.company_id, + channel_id: message.channel_id, + }); + + expect(result).toBeUndefined(); + done(); + }); + + it("without mentions, should get the preferences for all channel members and return only the ones who want to be notified", async done => { + const message = getMessage(true); + setNewThreadPreferences(); + const result = await processor.process(message); + + expect(service.channelThreads.bulkSave).toBeCalledTimes(1); + expect(service.channelThreads.bulkSave).toBeCalledWith( + [ + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.id, + user_id: message.sender, + }, + ], + undefined, + ); + + expect(service.channelThreads.getUsersInThread).not.toBeCalled; + expect(service.channelPreferences.getChannelPreferencesForUsers).toBeCalledTimes(1); + expect(service.channelPreferences.getChannelPreferencesForUsers).toBeCalledWith({ + company_id: message.company_id, + channel_id: message.channel_id, + }); + + expect(result.mentions.users).toEqual(["1"]); + done(); + }); + + it("with @all mention, should get the preferences for all channel members and return only the ones who want to be notified", async done => { + const message = getMessage(true); + message.mentions.specials = ["all"]; + setNewThreadPreferences(); + const result = await processor.process(message); + + expect(service.channelThreads.bulkSave).toBeCalledTimes(1); + expect(service.channelThreads.bulkSave).toBeCalledWith( + [ + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.id, + user_id: message.sender, + }, + ], + undefined, + ); + + expect(service.channelThreads.getUsersInThread).not.toBeCalled; + expect(service.channelPreferences.getChannelPreferencesForUsers).toBeCalledTimes(1); + expect(service.channelPreferences.getChannelPreferencesForUsers).toBeCalledWith({ + company_id: message.company_id, + channel_id: message.channel_id, + }); + + expect(result.mentions.users).toEqual(["1", "2"]); + done(); + }); + + it("with @here mentions, should get the preferences for all channel members and return only the ones who want to be notified", async done => { + const message = getMessage(true); + message.mentions.specials = ["here"]; + setNewThreadPreferences(); + const result = await processor.process(message); + + expect(service.channelThreads.bulkSave).toBeCalledTimes(1); + expect(service.channelThreads.bulkSave).toBeCalledWith( + [ + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.id, + user_id: message.sender, + }, + ], + undefined, + ); + + expect(service.channelThreads.getUsersInThread).not.toBeCalled; + expect(service.channelPreferences.getChannelPreferencesForUsers).toBeCalledTimes(1); + expect(service.channelPreferences.getChannelPreferencesForUsers).toBeCalledWith({ + company_id: message.company_id, + channel_id: message.channel_id, + }); + + expect(result.mentions.users).toEqual(["1", "2"]); + done(); + }); + + it("with @user mentions, should get the preferences for all channel members and return only the ones who want to be notified", async done => { + const message = getMessage(true); + message.mentions.users = ["1", "2", "3", "4"]; + setNewThreadPreferences(); + const result = await processor.process(message); + + expect(service.channelThreads.bulkSave).toBeCalledTimes(1); + expect(service.channelThreads.bulkSave).toBeCalledWith( + [ + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.id, + user_id: message.sender, + }, + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.id, + user_id: "1", + }, + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.id, + user_id: "2", + }, + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.id, + user_id: "3", + }, + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.id, + user_id: "4", + }, + ], + undefined, + ); + + expect(service.channelThreads.getUsersInThread).not.toBeCalled; + expect(service.channelPreferences.getChannelPreferencesForUsers).toBeCalledTimes(1); + expect(service.channelPreferences.getChannelPreferencesForUsers).toBeCalledWith({ + company_id: message.company_id, + channel_id: message.channel_id, + }); + + expect(result.mentions.users).toEqual(["1", "2", "3"]); + done(); + }); + + it("When message is a direct message", async done => { + const message = getMessage(true); + message.workspace_id = ChannelType.DIRECT; + message.mentions.users = ["1", "2", "3", "4"]; + setNewThreadPreferences(); + const result = await processor.process(message); + + expect(service.channelThreads.bulkSave).toBeCalledTimes(1); + expect(service.channelThreads.bulkSave).toBeCalledWith( + [ + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.id, + user_id: message.sender, + }, + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.id, + user_id: "1", + }, + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.id, + user_id: "2", + }, + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.id, + user_id: "3", + }, + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.id, + user_id: "4", + }, + ], + undefined, + ); + + expect(service.channelThreads.getUsersInThread).not.toBeCalled; + expect(service.channelPreferences.getChannelPreferencesForUsers).toBeCalledTimes(1); + expect(service.channelPreferences.getChannelPreferencesForUsers).toBeCalledWith({ + company_id: message.company_id, + channel_id: message.channel_id, + }); + + expect(result.mentions.users).toEqual(["1", "2", "3"]); + done(); + }); + }); + + describe("When message is a response to a thread", () => { + function setThreadResponsePreferences() { + setPreferences([ + { + channel_id, + company_id, + user_id: "1", + last_read: Date.now(), + preferences: ChannelMemberNotificationLevel.ALL, + }, + { + channel_id, + company_id, + user_id: "2", + last_read: Date.now(), + preferences: ChannelMemberNotificationLevel.MENTIONS, + }, + { + channel_id, + company_id, + user_id: "3", + last_read: Date.now(), + preferences: ChannelMemberNotificationLevel.ME, + }, + { + channel_id, + company_id, + user_id: "4", + last_read: Date.now(), + preferences: ChannelMemberNotificationLevel.NONE, + }, + ]); + } + + it("should return undefined when there is no one to notify", async done => { + const message = getMessage(); + setUsersInThread(["1", "2", "3", "4"]); + const result = await processor.process(message); + + expect(service.channelThreads.bulkSave).toBeCalledTimes(1); + expect(service.channelThreads.bulkSave).toBeCalledWith( + [ + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.thread_id, + user_id: message.sender, + }, + ], + undefined, + ); + + expect(service.channelThreads.getUsersInThread).toBeCalled; + expect(service.channelPreferences.getChannelPreferencesForUsers).toBeCalledTimes(1); + + expect(result).toBeUndefined(); + done(); + }); + + it("without mentions, should get the preferences for all members involved and return only the ones with preference !== NONE", async done => { + const message = getMessage(); + setUsersInThread(["1", "2", "3", "4"]); + setThreadResponsePreferences(); + const result = await processor.process(message); + + expect(service.channelThreads.bulkSave).toBeCalledTimes(1); + expect(service.channelThreads.bulkSave).toBeCalledWith( + [ + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.thread_id, + user_id: message.sender, + }, + ], + undefined, + ); + + expect(service.channelThreads.getUsersInThread).toBeCalled; + expect(service.channelPreferences.getChannelPreferencesForUsers).toBeCalledTimes(1); + + expect(result.mentions.users).toEqual(["1", "2", "3"]); + done(); + }); + + it("with @user mentions, should get the preferences for all members involved and return only the ones who want to be notified", async done => { + const message = getMessage(); + message.mentions.users = ["1", "2", "3", "4"]; + setUsersInThread(["1", "2", "3", "4"]); + setThreadResponsePreferences(); + const result = await processor.process(message); + + expect(service.channelThreads.bulkSave).toBeCalledTimes(1); + expect(service.channelThreads.bulkSave).toBeCalledWith( + [ + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.thread_id, + user_id: message.sender, + }, + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.thread_id, + user_id: "1", + }, + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.thread_id, + user_id: "2", + }, + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.thread_id, + user_id: "3", + }, + { + company_id: message.company_id, + channel_id: message.channel_id, + thread_id: message.thread_id, + user_id: "4", + }, + ], + undefined, + ); + + expect(service.channelThreads.getUsersInThread).toBeCalled; + expect(service.channelPreferences.getChannelPreferencesForUsers).toBeCalledTimes(1); + expect(result.mentions.users).toEqual(["1", "2", "3"]); + done(); + }); + }); + }); +}); diff --git a/twake/backend/node/test/unit/services/notifications/services/engine/processors/push-to-users/index.test.ts b/twake/backend/node/test/unit/services/notifications/services/engine/processors/push-to-users/index.test.ts new file mode 100644 index 00000000..11207143 --- /dev/null +++ b/twake/backend/node/test/unit/services/notifications/services/engine/processors/push-to-users/index.test.ts @@ -0,0 +1,244 @@ +import "reflect-metadata"; +import { afterEach, beforeEach, describe, expect, it, jest } from "@jest/globals"; +import { + ListResult, + OperationType, + SaveResult, +} from "../../../../../../../../src/core/platform/framework/api/crud-service"; +import { MessageQueueServiceAPI } from "../../../../../../../../src/core/platform/services/message-queue/api"; +import { ChannelMemberNotificationLevel } from "../../../../../../../../src/services/channels/types"; +import { + ChannelMemberNotificationPreference, + ChannelThreadUsers, +} from "../../../../../../../../src/services/notifications/entities"; +import { + TYPE as UserNotificationBadgeType, + UserNotificationBadge, +} from "../../../../../../../../src/services/notifications/entities/user-notification-badges"; +import { MentionNotification } from "../../../../../../../../src/services/notifications/types"; +import { uniqueId } from "lodash"; +import { PushNotificationToUsersMessageProcessor } from "../../../../../../../../src/services/notifications/services/engine/processors/push-to-users"; +import gr from "../../../../../../../../src/services/global-resolver"; + +describe("The PushNotificationToUsersMessageProcessor class", () => { + let channel_id, company_id, workspace_id, thread_id; + let pubsubService: MessageQueueServiceAPI; + let processor: PushNotificationToUsersMessageProcessor; + let getUsersInThread; + let getChannelPreferencesForUsers; + let saveBadge; + + beforeEach(async () => { + channel_id = "channel_id"; + company_id = "company_id"; + workspace_id = "workspace_id"; + thread_id: "thread_id"; + + getUsersInThread = jest.fn(); + getChannelPreferencesForUsers = jest.fn(); + saveBadge = jest.fn(); + + setPreferences(); + setUsersInThread(); + + pubsubService = { + publish: jest.fn(), + } as unknown as MessageQueueServiceAPI; + // + const service = { + badges: { + save: saveBadge, + }, + channelPreferences: { + getChannelPreferencesForUsers, + }, + }; + + gr.platformServices = { + messageQueue: pubsubService, + } as any; + + gr.services = { + notifications: service, + } as any; + processor = new PushNotificationToUsersMessageProcessor(); + }); + + afterEach(() => { + jest.restoreAllMocks(); + jest.resetAllMocks(); + }); + + function getMessage(newThread: boolean = false): MentionNotification { + const message = { + company_id, + workspace_id, + channel_id, + message_id: "id", + creation_date: Date.now(), + thread_id, + mentions: { + users: [], + }, + } as MentionNotification; + + if (newThread) { + // message is new thread when thread_id is not defined + message.thread_id = undefined; + } + + return message; + } + + function setPreferences(preferences: ChannelMemberNotificationPreference[] = []): void { + getChannelPreferencesForUsers.mockResolvedValue( + new ListResult("preferences", preferences), + ); + } + + function setBadgeResults(badges: UserNotificationBadge[] = []): void { + badges.forEach(badge => + saveBadge.mockResolvedValueOnce( + new SaveResult(UserNotificationBadgeType, badge, OperationType.CREATE), + ), + ); + } + + function setUsersInThread(users: string[] = []) { + getUsersInThread.mockResolvedValue( + new ListResult( + "users", + users.map( + user_id => + ({ + company_id, + channel_id, + workspace_id, + thread_id, + user_id, + } as ChannelThreadUsers), + ), + ), + ); + } + + describe("The process method", () => { + it("will fail when channel_id is not defined", async () => { + const message = getMessage(); + delete message.channel_id; + + await expect(processor.process(message)).rejects.toThrowError("Missing required fields"); + }); + + it("will fail when company_id is not defined", async () => { + const message = getMessage(); + delete message.company_id; + + await expect(processor.process(message)).rejects.toThrowError("Missing required fields"); + }); + + it("will fail when workspace_id is not defined", async () => { + const message = getMessage(); + delete message.workspace_id; + + await expect(processor.process(message)).rejects.toThrowError("Missing required fields"); + }); + + it("will fail when creation_date is not defined", async () => { + const message = getMessage(); + delete message.creation_date; + + await expect(processor.process(message)).rejects.toThrowError("Missing required fields"); + }); + + it("will do nothing when mentions is not defined", async done => { + const message = getMessage(); + delete message.mentions; + + await processor.process(message); + + expect(gr.services.notifications.channelPreferences.getChannelPreferencesForUsers).not + .toBeCalled; + done(); + }); + + it("will do nothing when mentions.users is not defined", async done => { + const message = getMessage(); + message.mentions = { users: undefined }; + + await processor.process(message); + + expect(gr.services.notifications.channelPreferences.getChannelPreferencesForUsers).not + .toBeCalled; + done(); + }); + + it("will do nothing when mentions.users is empty", async done => { + const message = getMessage(); + message.mentions = { users: [] }; + + await processor.process(message); + + expect(gr.services.notifications.channelPreferences.getChannelPreferencesForUsers).not + .toBeCalled; + done(); + }); + + it("will keep users who did not read the channel yet", async done => { + const message = getMessage(); + + setPreferences([ + { + channel_id, + company_id, + last_read: Date.now(), + user_id: "1", + preferences: ChannelMemberNotificationLevel.ALL, + }, + { + channel_id, + company_id, + last_read: Date.now(), + user_id: "3", + preferences: ChannelMemberNotificationLevel.ALL, + }, + ]); + setBadgeResults([ + { + channel_id, + company_id, + thread_id, + user_id: "1", + workspace_id, + message_id: message.message_id, + id: uniqueId(), + }, + { + channel_id, + company_id, + thread_id, + user_id: "3", + workspace_id, + message_id: message.message_id, + id: uniqueId(), + }, + ]); + + const lessThan = message.creation_date; + const users = ["1", "2", "3", "4"]; + const channel = { + channel_id, + company_id, + }; + message.mentions = { users }; + + await processor.process(message); + + expect(getChannelPreferencesForUsers).toBeCalledWith(channel, users, { lessThan }, undefined); + expect(gr.services.notifications.badges.save).toBeCalledTimes(2); + expect(pubsubService.publish).toBeCalledTimes(2); + + done(); + }); + }); +}); diff --git a/twake/backend/node/test/unit/services/previews/services/files/processing/video.test.ts b/twake/backend/node/test/unit/services/previews/services/files/processing/video.test.ts new file mode 100644 index 00000000..a7051a34 --- /dev/null +++ b/twake/backend/node/test/unit/services/previews/services/files/processing/video.test.ts @@ -0,0 +1,176 @@ +import { describe, expect, it, jest, beforeEach, afterEach, afterAll } from "@jest/globals"; +import { generateVideoPreview } from "../../../../../../../src/services/previews/services/files/processing/video"; +import ffmpeg, { ffprobe } from "fluent-ffmpeg"; +import { cleanFiles, getTmpFile } from "../../../../../../../src/utils/files"; +import fs from "fs"; + +jest.mock("fluent-ffmpeg"); +jest.mock("../../../../../../../src/utils/files"); + +const ffmpegMock = { + screenshot: jest.fn().mockReturnValue({ + on: function (e, cb) { + cb(); + return this; + }, + }), +}; + +beforeEach(() => { + jest.spyOn(fs, "statSync").mockReturnValue({ size: 1 } as any); + (ffmpeg as any).mockImplementation(() => ffmpegMock); + (cleanFiles as any).mockImplementation(() => jest.fn()); + (getTmpFile as any).mockImplementation(() => "/tmp/file"); + (ffprobe as any).mockImplementation((i, cb) => { + cb(null, { + streams: [ + { + width: 320, + height: 240, + }, + ], + }); + }); +}); + +afterEach(() => { + jest.clearAllMocks(); +}); + +afterAll(() => { + jest.restoreAllMocks(); +}); + +describe("the generateVideoPreview function", () => { + it("should return a promise", () => { + const result = generateVideoPreview([]); + expect(result).toBeInstanceOf(Promise); + }); + + it("should attempt to create a screenshot using ffmpeg", async () => { + await generateVideoPreview(["/foo/bar"]); + expect(ffmpeg as any).toBeCalledWith("/foo/bar"); + }); + + it("should call ffmpeg screenshot method with the original video dimentions", async () => { + (getTmpFile as any).mockImplementation(() => "/tmp/some-random-file"); + (ffprobe as any).mockImplementation((i, cb) => { + cb(null, { + streams: [ + { + width: 500, + height: 500, + }, + ], + }); + }); + + await generateVideoPreview(["/foo/bar"]); + expect(ffmpegMock.screenshot).toBeCalledWith({ + count: 1, + filename: "some-random-file.jpg", + folder: "/tmp", + timemarks: ["0"], + size: "500x500", + }); + }); + + it("should attempt to generate a temporary file", async () => { + await generateVideoPreview(["/foo/bar"]); + + expect(getTmpFile).toBeCalled(); + }); + + it("should attempt to clean up the temporary file in case of errors", async () => { + const expectedError = new Error("failed to generate video preview: Error: foo"); + (ffmpeg as any).mockImplementation(() => { + throw new Error("foo"); + }); + + (ffprobe as any).mockImplementation((i, cb) => { + cb(null, { + streams: [ + { + width: 500, + height: 500, + }, + ], + }); + }); + + await expect(generateVideoPreview(["/foo/bar"])).rejects.toThrow(expectedError); + + expect(cleanFiles).toBeCalledWith(["/tmp/file.jpg"]); + }); + + it("should return the thumbnail information", async () => { + const result = await generateVideoPreview(["/foo/bar"]); + expect(result).toEqual([ + { + width: 320, + height: 240, + type: "image/jpg", + size: 1, + path: "/tmp/file.jpg", + }, + ]); + }); + + it("should generate thumbnails for multiple files", async () => { + const result = await generateVideoPreview(["/foo/bar", "/foo/baz", "/foo/tar"]); + expect(result).toHaveLength(3); + }); + + it("should use ffprobe to get the video dimensions", async () => { + await generateVideoPreview(["/foo/bar"]); + expect(ffprobe).toBeCalledWith("/foo/bar", expect.any(Function)); + }); + + it("should use 1080p as the maximum video dimensions", async () => { + (ffprobe as any).mockImplementation((i, cb) => { + cb(null, { + streams: [ + { + width: 5000, + height: 5000, + }, + ], + }); + }); + + const result = await generateVideoPreview(["/foo/bar"]); + expect(result).toEqual([ + { + width: 1920, + height: 1080, + type: "image/jpg", + size: 1, + path: "/tmp/file.jpg", + }, + ]); + }); + + it("should use 320x240 as the minimum video dimensions", async () => { + (ffprobe as any).mockImplementation((i, cb) => { + cb(null, { + streams: [ + { + width: 320, + height: 180, + }, + ], + }); + }); + + const result = await generateVideoPreview(["/foo/bar"]); + expect(result).toEqual([ + { + width: 320, + height: 240, + type: "image/jpg", + size: 1, + path: "/tmp/file.jpg", + }, + ]); + }); +}); diff --git a/twake/backend/node/test/unit/services/previews/services/links/processing/images.test.ts b/twake/backend/node/test/unit/services/previews/services/links/processing/images.test.ts new file mode 100644 index 00000000..c3b0550b --- /dev/null +++ b/twake/backend/node/test/unit/services/previews/services/links/processing/images.test.ts @@ -0,0 +1,61 @@ +import { describe, expect, it, jest, beforeEach, afterEach, afterAll } from "@jest/globals"; +import { generateImageUrlPreview } from "../../../../../../../src/services/previews/services/links/processing/image"; + +import getFavicons from "get-website-favicon"; +import imageProbe from "probe-image-size"; + +jest.mock("get-website-favicon"); +jest.mock("probe-image-size"); + +beforeEach(() => { + (imageProbe as any).mockImplementation(() => ({ + width: 320, + height: 240, + })); + + (getFavicons as any).mockImplementation(() => ({ + icons: [ + { + src: "http://foo.bar/favicon.ico", + }, + ], + })); +}); + +afterEach(() => { + jest.clearAllMocks(); +}); + +afterAll(() => { + jest.restoreAllMocks(); +}); + +describe("the generateImageUrlPreview function", () => { + it("should return a promise", () => { + const result = generateImageUrlPreview("http://foo.bar"); + expect(result).toBeInstanceOf(Promise); + }); + + it("should generate a preview for a given image url", async () => { + const result = await generateImageUrlPreview("https://foo.bar/image.jpg"); + expect(result).toEqual({ + title: "image.jpg", // title should be the file name + domain: "foo.bar", + favicon: "http://foo.bar/favicon.ico", + url: "https://foo.bar/image.jpg", + img_height: 240, + img_width: 320, + description: null, + img: "https://foo.bar/image.jpg", + }); + }); + + it("should return nothing in case of error", async () => { + (imageProbe as any).mockImplementation(() => { + throw new Error("failed to probe image"); + }); + + const result = await generateImageUrlPreview("https://foo.bar/image.jpg"); + expect(result).toBeUndefined(); + }); +}); diff --git a/twake/backend/node/test/unit/services/previews/services/links/processing/links.test.ts b/twake/backend/node/test/unit/services/previews/services/links/processing/links.test.ts new file mode 100644 index 00000000..30eaa585 --- /dev/null +++ b/twake/backend/node/test/unit/services/previews/services/links/processing/links.test.ts @@ -0,0 +1,186 @@ +import { describe, expect, it, jest, beforeEach, afterEach, afterAll } from "@jest/globals"; +import { generateLinkPreview } from "../../../../../../../src/services/previews/services/links/processing/link"; +import { parser } from "html-metadata-parser"; +import getFavicons from "get-website-favicon"; +import imageProbe from "probe-image-size"; + +jest.mock("html-metadata-parser"); +jest.mock("get-website-favicon"); +jest.mock("probe-image-size"); + +beforeEach(() => { + (imageProbe as any).mockImplementation(() => ({ + width: 320, + height: 240, + })); + + (getFavicons as any).mockImplementation(() => ({ + icons: [ + { + src: "http://foo.bar/favicon.ico", + }, + ], + })); + + (parser as any).mockImplementation(() => ({ + og: { + title: "Foo", + description: "Bar", + image: "http://foo.bar/image.jpg", + }, + meta: { + title: "Foo", + description: "Bar", + image: "http://foo.bar/image1.jpg", + }, + images: ["http://foo.bar/image2.jpg"], + })); +}); + +afterEach(() => { + jest.clearAllMocks(); +}); + +afterAll(() => { + jest.restoreAllMocks(); +}); + +describe("the generateLinkPreview service", () => { + it("should return a promise", () => { + const result = generateLinkPreview("http://foo.bar"); + expect(result).toBeInstanceOf(Promise); + }); + + it("should return a promise that resolves to a preview", async () => { + const result = await generateLinkPreview("https://foo.bar"); + expect(result).toEqual({ + title: "Foo", + description: "Bar", + img: "http://foo.bar/image.jpg", + favicon: "http://foo.bar/favicon.ico", + img_width: 320, + img_height: 240, + domain: "foo.bar", + url: "https://foo.bar", + }); + }); + + it("should return a promise that resolves to undefined if no previews are found", async () => { + (parser as any).mockImplementation(() => { + throw new Error("failed to parse"); + }); + (getFavicons as any).mockImplementation(() => []); + (imageProbe as any).mockImplementation(() => ({})); + + const result = await generateLinkPreview("https://foo.bar"); + expect(result).toBeUndefined(); + }); + + it("should use og information as first choice", async () => { + (parser as any).mockImplementation(() => ({ + og: { + title: "test", + description: "test", + image: "http://foo.bar/test.jpg", + }, + meta: { + title: "test2", + description: "test2", + image: "http://foo.bar/test2.jpg", + }, + images: ["http://foo.bar/test3.jpg"], + })); + + const result = await generateLinkPreview("https://foo.bar"); + expect(result).toEqual({ + title: "test", + description: "test", + img: "http://foo.bar/test.jpg", + favicon: "http://foo.bar/favicon.ico", + img_width: 320, + img_height: 240, + domain: "foo.bar", + url: "https://foo.bar", + }); + }); + + it("should use meta information as second choice", async () => { + (parser as any).mockImplementation(() => ({ + meta: { + title: "test2", + description: "test2", + image: "http://foo.bar/test2.jpg", + }, + images: [], + })); + + const result = await generateLinkPreview("https://foo.bar"); + expect(result).toEqual({ + title: "test2", + description: "test2", + img: "http://foo.bar/test2.jpg", + favicon: "http://foo.bar/favicon.ico", + img_width: 320, + img_height: 240, + domain: "foo.bar", + url: "https://foo.bar", + }); + }); + + it("should use the first image found in the url when none are present in the og or meta information", async () => { + (parser as any).mockImplementation(() => ({ + og: { + title: "test", + description: "test", + }, + meta: { + title: "test2", + description: "test2", + }, + images: ["http://foo.bar/test3.jpg", "http://foo.bar/test4.jpg"], + })); + + const result = await generateLinkPreview("https://foo.bar"); + expect(result).toEqual({ + title: "test", + description: "test", + img: "http://foo.bar/test3.jpg", + favicon: "http://foo.bar/favicon.ico", + img_width: 320, + img_height: 240, + domain: "foo.bar", + url: "https://foo.bar", + }); + }); + + it("shouldn't attempt to probe for image size when none are found", async () => { + (parser as any).mockImplementation(() => ({ + og: { + title: "test", + description: "test", + }, + meta: { + title: "test2", + description: "test2", + }, + images: [], + })); + + await generateLinkPreview("https://foo.bar"); + expect(imageProbe).not.toHaveBeenCalled(); + }); + + it("should strip www from the domain", async () => { + const result = await generateLinkPreview("https://www.foo.bar"); + expect(result).toEqual({ + title: "Foo", + description: "Bar", + img: "http://foo.bar/image.jpg", + favicon: "http://foo.bar/favicon.ico", + img_width: 320, + img_height: 240, + domain: "foo.bar", + url: "https://www.foo.bar", + }); + }); +}); diff --git a/twake/backend/node/test/unit/services/previews/services/links/processing/service.test.ts b/twake/backend/node/test/unit/services/previews/services/links/processing/service.test.ts new file mode 100644 index 00000000..b6293649 --- /dev/null +++ b/twake/backend/node/test/unit/services/previews/services/links/processing/service.test.ts @@ -0,0 +1,109 @@ +import { + describe, + expect, + it, + jest, + beforeEach, + afterEach, + afterAll, + beforeAll, +} from "@jest/globals"; +import { LinkPreviewProcessService } from "../../../../../../../src/services/previews/services/links/processing/service"; +import { generateLinkPreview } from "../../../../../../../src/services/previews/services/links/processing/link"; +import { generateImageUrlPreview } from "../../../../../../../src/services/previews/services/links/processing/image"; +import axios from "axios"; + +jest.mock("axios"); +jest.mock("../../../../../../../src/services/previews/services/links/processing/link"); +jest.mock("../../../../../../../src/services/previews/services/links/processing/image"); + +let service: LinkPreviewProcessService; + +beforeEach(async () => { + (axios as any).mockImplementation(() => ({ + headers: { + "content-type": "text/html", + }, + })); + + (generateLinkPreview as any).mockImplementation(() => ({ + title: "Foo", + description: "Bar", + img: "http://foo.bar/image.jpg", + favicon: "http://foo.bar/favicon.ico", + })); + + (generateImageUrlPreview as any).mockImplementation(() => ({ + title: "image.jpg", + description: null, + img: "http://foo.bar/image.jpg", + favicon: "http://foo.bar/favicon.ico", + })); +}); + +afterEach(() => { + jest.clearAllMocks(); +}); + +afterAll(() => { + jest.restoreAllMocks(); +}); + +beforeAll(async () => { + service = await new LinkPreviewProcessService().init(); +}); + +describe("the LinkPreviewProcessService service", () => { + it("should return a promise", () => { + const result = service.generatePreviews(["http://foo.bar"]); + expect(result).toBeInstanceOf(Promise); + }); + + it("should call generateLinkPreview when it's a html page", async () => { + (axios as any).mockImplementation(() => ({ + headers: { + "content-type": "text/html", + }, + })); + + await service.generatePreviews(["http://foo.bar"]); + expect(generateLinkPreview).toHaveBeenCalled(); + }); + + it("should call generateImageUrlPreview when it's an image", async () => { + (axios as any).mockImplementation(() => ({ + headers: { + "content-type": "image/jpeg", + }, + })); + + await service.generatePreviews(["http://foo.bar/image.jpg"]); + expect(generateImageUrlPreview).toHaveBeenCalled(); + }); + + it("should skip if the url content is not supported", async () => { + (axios as any).mockImplementation(() => ({ + headers: { + "content-type": "application/json", + }, + })); + + await service.generatePreviews(["http://foo.bar"]); + expect(generateLinkPreview).not.toHaveBeenCalled(); + expect(generateImageUrlPreview).not.toHaveBeenCalled(); + }); + + // should filter null values + it("should filter null values", async () => { + (axios as any).mockImplementation(() => ({ + headers: { + "content-type": "text/html", + }, + })); + + (generateLinkPreview as any).mockImplementation(() => null); + + const result = await service.generatePreviews(["http://foo.bar", "http://foo.xyz"]); + expect(result).toEqual([]); + }); +}); diff --git a/twake/backend/node/tsconfig.json b/twake/backend/node/tsconfig.json new file mode 100644 index 00000000..6414f30f --- /dev/null +++ b/twake/backend/node/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "module": "commonjs", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "target": "es6", + "noImplicitAny": true, + "moduleResolution": "node", + "sourceMap": true, + "outDir": "dist", + "baseUrl": ".", + "paths": { + "*": [ + "node_modules/*", + "src/types/*" + ], + "src/*": ["src/*"] + } + }, + "include": [ + "src/**/*" + ] +} \ No newline at end of file diff --git a/twake/backend/node/yarn.lock b/twake/backend/node/yarn.lock new file mode 100644 index 00000000..f02992f8 --- /dev/null +++ b/twake/backend/node/yarn.lock @@ -0,0 +1,10144 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.1.0": + version "2.2.0" + resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.6.tgz" + integrity sha512-tzulrgDT0QD6U7BJ4TKVk2SDDg7wlP39P9yAx1RfLy7vP/7rsDRlWVfbWxElslu56+r7QOhB2NSDsabYYruoZQ== + +"@babel/compat-data@^7.18.8": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d" + integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ== + +"@babel/core@^7.1.0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.7.5": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.18.6.tgz" + integrity sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.6" + "@babel/helper-compilation-targets" "^7.18.6" + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helpers" "^7.18.6" + "@babel/parser" "^7.18.6" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.6" + "@babel/types" "^7.18.6" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.1" + semver "^6.3.0" + +"@babel/generator@^7.18.10": + version "7.18.12" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.12.tgz#fa58daa303757bd6f5e4bbca91b342040463d9f4" + integrity sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg== + dependencies: + "@babel/types" "^7.18.10" + "@jridgewell/gen-mapping" "^0.3.2" + jsesc "^2.5.1" + +"@babel/generator@^7.18.6": + version "7.18.7" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz" + integrity sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A== + dependencies: + "@babel/types" "^7.18.7" + "@jridgewell/gen-mapping" "^0.3.2" + jsesc "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz" + integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.6.tgz" + integrity sha512-KT10c1oWEpmrIRYnthbzHgoOf6B+Xd6a5yhdbNtdhtG7aO1or5HViuf1TQR36xY/QprXA5nvxO6nAjhJ4y38jw== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.18.6" + "@babel/types" "^7.18.6" + +"@babel/helper-compilation-targets@^7.13.0": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf" + integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg== + dependencies: + "@babel/compat-data" "^7.18.8" + "@babel/helper-validator-option" "^7.18.6" + browserslist "^4.20.2" + semver "^6.3.0" + +"@babel/helper-compilation-targets@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.6.tgz" + integrity sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg== + dependencies: + "@babel/compat-data" "^7.18.6" + "@babel/helper-validator-option" "^7.18.6" + browserslist "^4.20.2" + semver "^6.3.0" + +"@babel/helper-create-class-features-plugin@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.6.tgz" + integrity sha512-YfDzdnoxHGV8CzqHGyCbFvXg5QESPFkXlHtvdCkesLjjVMT2Adxe4FGUR5ChIb3DxSaXO12iIOCWoXdsUVwnqw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.6" + "@babel/helper-function-name" "^7.18.6" + "@babel/helper-member-expression-to-functions" "^7.18.6" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + +"@babel/helper-create-regexp-features-plugin@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz" + integrity sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + regexpu-core "^5.1.0" + +"@babel/helper-define-polyfill-provider@^0.3.1": + version "0.3.1" + resolved "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz" + integrity sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA== + dependencies: + "@babel/helper-compilation-targets" "^7.13.0" + "@babel/helper-module-imports" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/traverse" "^7.13.0" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + +"@babel/helper-environment-visitor@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz" + integrity sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q== + +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== + +"@babel/helper-explode-assignable-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz" + integrity sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-function-name@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz" + integrity sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw== + dependencies: + "@babel/template" "^7.18.6" + "@babel/types" "^7.18.6" + +"@babel/helper-function-name@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz#940e6084a55dee867d33b4e487da2676365e86b0" + integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A== + dependencies: + "@babel/template" "^7.18.6" + "@babel/types" "^7.18.9" + +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-member-expression-to-functions@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.6.tgz" + integrity sha512-CeHxqwwipekotzPDUuJOfIMtcIHBuc7WAzLmTYWctVigqS5RktNMQ5bEwQSuGewzYnCtTWa3BARXeiLxDTv+Ng== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-transforms@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.6.tgz" + integrity sha512-L//phhB4al5uucwzlimruukHB3jRd5JGClwRMD/ROrVjXfLqovYnvQrK/JK36WYyVwGGO7OD3kMyVTjx+WVPhw== + dependencies: + "@babel/helper-environment-visitor" "^7.18.6" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.18.6" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.6" + "@babel/types" "^7.18.6" + +"@babel/helper-optimise-call-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz" + integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz" + integrity sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg== + +"@babel/helper-plugin-utils@^7.13.0": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz#4b8aea3b069d8cb8a72cdfe28ddf5ceca695ef2f" + integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w== + +"@babel/helper-remap-async-to-generator@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.6.tgz" + integrity sha512-z5wbmV55TveUPZlCLZvxWHtrjuJd+8inFhk7DG0WW87/oJuGDcjDiu7HIvGcpf5464L6xKCg3vNkmlVVz9hwyQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.6" + "@babel/helper-wrap-function" "^7.18.6" + "@babel/types" "^7.18.6" + +"@babel/helper-replace-supers@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.18.6.tgz" + integrity sha512-fTf7zoXnUGl9gF25fXCWE26t7Tvtyn6H4hkLSYhATwJvw2uYxd3aoXplMSe0g9XbwK7bmxNes7+FGO0rB/xC0g== + dependencies: + "@babel/helper-environment-visitor" "^7.18.6" + "@babel/helper-member-expression-to-functions" "^7.18.6" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/traverse" "^7.18.6" + "@babel/types" "^7.18.6" + +"@babel/helper-simple-access@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz" + integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-skip-transparent-expression-wrappers@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.6.tgz" + integrity sha512-4KoLhwGS9vGethZpAhYnMejWkX64wsnHPDwvOsKWU6Fg4+AlK2Jz3TyjQLMEPvz+1zemi/WBdkYxCD0bAfIkiw== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56" + integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw== + +"@babel/helper-validator-identifier@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz" + integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== + +"@babel/helper-validator-option@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz" + integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== + +"@babel/helper-wrap-function@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.6.tgz" + integrity sha512-I5/LZfozwMNbwr/b1vhhuYD+J/mU+gfGAj5td7l5Rv9WYmH6i3Om69WGKNmlIpsVW/mF6O5bvTKbvDQZVgjqOw== + dependencies: + "@babel/helper-function-name" "^7.18.6" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.6" + "@babel/types" "^7.18.6" + +"@babel/helpers@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.6.tgz" + integrity sha512-vzSiiqbQOghPngUYt/zWGvK3LAsPhz55vc9XNN0xAl2gV4ieShI2OQli5duxWHD+72PZPTKAcfcZDE1Cwc5zsQ== + dependencies: + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.6" + "@babel/types" "^7.18.6" + +"@babel/highlight@^7.10.4", "@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.18.6.tgz" + integrity sha512-uQVSa9jJUe/G/304lXspfWVpKpK4euFLgGiMQFOCpM/bgcAdeoHwi/OQz23O9GK2osz26ZiXRRV9aV+Yl1O8tw== + +"@babel/parser@^7.18.11": + version "7.18.11" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.11.tgz#68bb07ab3d380affa9a3f96728df07969645d2d9" + integrity sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ== + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz" + integrity sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.6.tgz" + integrity sha512-Udgu8ZRgrBrttVz6A0EVL0SJ1z+RLbIeqsu632SA1hf0awEppD6TvdznoH+orIF8wtFFAV/Enmw9Y+9oV8TQcw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.6" + "@babel/plugin-proposal-optional-chaining" "^7.18.6" + +"@babel/plugin-proposal-async-generator-functions@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.6.tgz" + integrity sha512-WAz4R9bvozx4qwf74M+sfqPMKfSqwM0phxPTR6iJIi8robgzXwkEgmeJG1gEKhm6sDqT/U9aV3lfcqybIpev8w== + dependencies: + "@babel/helper-environment-visitor" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-remap-async-to-generator" "^7.18.6" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-proposal-class-properties@^7.10.4", "@babel/plugin-proposal-class-properties@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz" + integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-proposal-class-static-block@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz" + integrity sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-proposal-decorators@^7.10.5": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.18.6.tgz" + integrity sha512-gAdhsjaYmiZVxx5vTMiRfj31nB7LhwBJFMSLzeDxc7X4tKLixup0+k9ughn0RcpBrv9E3PBaXJW7jF5TCihAOg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/plugin-syntax-decorators" "^7.18.6" + +"@babel/plugin-proposal-dynamic-import@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz" + integrity sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-export-namespace-from@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.6.tgz" + integrity sha512-zr/QcUlUo7GPo6+X1wC98NJADqmy5QTFWWhqeQWiki4XHafJtLl/YMGkmRB2szDD2IYJCCdBTd4ElwhId9T7Xw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz" + integrity sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-proposal-logical-assignment-operators@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.6.tgz" + integrity sha512-zMo66azZth/0tVd7gmkxOkOjs2rpHyhpcFo565PUP37hSp6hSd9uUKIfTDFMz58BwqgQKhJ9YxtM5XddjXVn+Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz" + integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-proposal-numeric-separator@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz" + integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.6.tgz" + integrity sha512-9yuM6wr4rIsKa1wlUAbZEazkCrgw2sMPEXCr4Rnwetu7cEW1NydkCWytLuYletbf8vFxdJxFhwEZqMpOx2eZyw== + dependencies: + "@babel/compat-data" "^7.18.6" + "@babel/helper-compilation-targets" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.18.6" + +"@babel/plugin-proposal-optional-catch-binding@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz" + integrity sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.6.tgz" + integrity sha512-PatI6elL5eMzoypFAiYDpYQyMtXTn+iMhuxxQt5mAXD4fEmKorpSI3PHd+i3JXBJN3xyA6MvJv7at23HffFHwA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.6" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-proposal-private-methods@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz" + integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-proposal-private-property-in-object@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz" + integrity sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-proposal-unicode-property-regex@^7.18.6", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz" + integrity sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-decorators@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.18.6.tgz" + integrity sha512-fqyLgjcxf/1yhyZ6A+yo1u9gJ7eleFQod2lkaUsF9DQ7sbbY3Ligym3L0+I2c0WmqNKDpoD9UTb1AKP3qRMOAQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-import-assertions@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz" + integrity sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz" + integrity sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-arrow-functions@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz" + integrity sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-async-to-generator@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz" + integrity sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag== + dependencies: + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-remap-async-to-generator" "^7.18.6" + +"@babel/plugin-transform-block-scoped-functions@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz" + integrity sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-block-scoping@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.6.tgz" + integrity sha512-pRqwb91C42vs1ahSAWJkxOxU1RHWDn16XAa6ggQ72wjLlWyYeAcLvTtE0aM8ph3KNydy9CQF2nLYcjq1WysgxQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-classes@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.6.tgz" + integrity sha512-XTg8XW/mKpzAF3actL554Jl/dOYoJtv3l8fxaEczpgz84IeeVf+T1u2CSvPHuZbt0w3JkIx4rdn/MRQI7mo0HQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.6" + "@babel/helper-function-name" "^7.18.6" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.6.tgz" + integrity sha512-9repI4BhNrR0KenoR9vm3/cIc1tSBIo+u1WVjKCAynahj25O8zfbiE6JtAtHPGQSs4yZ+bA8mRasRP+qc+2R5A== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-destructuring@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.6.tgz" + integrity sha512-tgy3u6lRp17ilY8r1kP4i2+HDUwxlVqq3RTc943eAWSzGgpU1qhiKpqZ5CMyHReIYPHdo3Kg8v8edKtDqSVEyQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz" + integrity sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-duplicate-keys@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.6.tgz" + integrity sha512-NJU26U/208+sxYszf82nmGYqVF9QN8py2HFTblPT9hbawi8+1C5a9JubODLTGFuT0qlkqVinmkwOD13s0sZktg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-exponentiation-operator@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz" + integrity sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-for-of@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.6.tgz" + integrity sha512-WAjoMf4wIiSsy88KmG7tgj2nFdEK7E46tArVtcgED7Bkj6Fg/tG5SbvNIOKxbFS2VFgNh6+iaPswBeQZm4ox8w== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-function-name@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.6.tgz" + integrity sha512-kJha/Gbs5RjzIu0CxZwf5e3aTTSlhZnHMT8zPWnJMjNpLOUgqevg+PN5oMH68nMCXnfiMo4Bhgxqj59KHTlAnA== + dependencies: + "@babel/helper-compilation-targets" "^7.18.6" + "@babel/helper-function-name" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.6.tgz" + integrity sha512-x3HEw0cJZVDoENXOp20HlypIHfl0zMIhMVZEBVTfmqbObIpsMxMbmU5nOEO8R7LYT+z5RORKPlTI5Hj4OsO9/Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-member-expression-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz" + integrity sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-modules-amd@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz" + integrity sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg== + dependencies: + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-commonjs@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz" + integrity sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q== + dependencies: + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-simple-access" "^7.18.6" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-systemjs@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.6.tgz" + integrity sha512-UbPYpXxLjTw6w6yXX2BYNxF3p6QY225wcTkfQCy3OMnSlS/C3xGtwUjEzGkldb/sy6PWLiCQ3NbYfjWUTI3t4g== + dependencies: + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-validator-identifier" "^7.18.6" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-umd@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz" + integrity sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ== + dependencies: + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz" + integrity sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-new-target@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz" + integrity sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-object-super@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz" + integrity sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.6" + +"@babel/plugin-transform-parameters@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.6.tgz" + integrity sha512-FjdqgMv37yVl/gwvzkcB+wfjRI8HQmc5EgOG9iGNvUY1ok+TjsoaMP7IqCDZBhkFcM5f3OPVMs6Dmp03C5k4/A== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-property-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz" + integrity sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-regenerator@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz" + integrity sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + regenerator-transform "^0.15.0" + +"@babel/plugin-transform-reserved-words@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz" + integrity sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-shorthand-properties@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz" + integrity sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-spread@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.6.tgz" + integrity sha512-ayT53rT/ENF8WWexIRg9AiV9h0aIteyWn5ptfZTZQrjk/+f3WdrJGCY4c9wcgl2+MKkKPhzbYp97FTsquZpDCw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.6" + +"@babel/plugin-transform-sticky-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz" + integrity sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-template-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.6.tgz" + integrity sha512-UuqlRrQmT2SWRvahW46cGSany0uTlcj8NYOS5sRGYi8FxPYPoLd5DDmMd32ZXEj2Jq+06uGVQKHxa/hJx2EzKw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-typeof-symbol@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.6.tgz" + integrity sha512-7m71iS/QhsPk85xSjFPovHPcH3H9qeyzsujhTc+vcdnsXavoWYJ74zx0lP5RhpC5+iDnVLO+PPMHzC11qels1g== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-typescript@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.18.6.tgz" + integrity sha512-ijHNhzIrLj5lQCnI6aaNVRtGVuUZhOXFLRVFs7lLrkXTHip4FKty5oAuQdk4tywG0/WjXmjTfQCWmuzrvFer1w== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-typescript" "^7.18.6" + +"@babel/plugin-transform-unicode-escapes@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.6.tgz" + integrity sha512-XNRwQUXYMP7VLuy54cr/KS/WeL3AZeORhrmeZ7iewgu+X2eBqmpaLI/hzqr9ZxCeUoq0ASK4GUzSM0BDhZkLFw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-unicode-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz" + integrity sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/preset-env@^7.11.5": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.6.tgz" + integrity sha512-WrthhuIIYKrEFAwttYzgRNQ5hULGmwTj+D6l7Zdfsv5M7IWV/OZbUfbeL++Qrzx1nVJwWROIFhCHRYQV4xbPNw== + dependencies: + "@babel/compat-data" "^7.18.6" + "@babel/helper-compilation-targets" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.6" + "@babel/plugin-proposal-async-generator-functions" "^7.18.6" + "@babel/plugin-proposal-class-properties" "^7.18.6" + "@babel/plugin-proposal-class-static-block" "^7.18.6" + "@babel/plugin-proposal-dynamic-import" "^7.18.6" + "@babel/plugin-proposal-export-namespace-from" "^7.18.6" + "@babel/plugin-proposal-json-strings" "^7.18.6" + "@babel/plugin-proposal-logical-assignment-operators" "^7.18.6" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6" + "@babel/plugin-proposal-numeric-separator" "^7.18.6" + "@babel/plugin-proposal-object-rest-spread" "^7.18.6" + "@babel/plugin-proposal-optional-catch-binding" "^7.18.6" + "@babel/plugin-proposal-optional-chaining" "^7.18.6" + "@babel/plugin-proposal-private-methods" "^7.18.6" + "@babel/plugin-proposal-private-property-in-object" "^7.18.6" + "@babel/plugin-proposal-unicode-property-regex" "^7.18.6" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-import-assertions" "^7.18.6" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-transform-arrow-functions" "^7.18.6" + "@babel/plugin-transform-async-to-generator" "^7.18.6" + "@babel/plugin-transform-block-scoped-functions" "^7.18.6" + "@babel/plugin-transform-block-scoping" "^7.18.6" + "@babel/plugin-transform-classes" "^7.18.6" + "@babel/plugin-transform-computed-properties" "^7.18.6" + "@babel/plugin-transform-destructuring" "^7.18.6" + "@babel/plugin-transform-dotall-regex" "^7.18.6" + "@babel/plugin-transform-duplicate-keys" "^7.18.6" + "@babel/plugin-transform-exponentiation-operator" "^7.18.6" + "@babel/plugin-transform-for-of" "^7.18.6" + "@babel/plugin-transform-function-name" "^7.18.6" + "@babel/plugin-transform-literals" "^7.18.6" + "@babel/plugin-transform-member-expression-literals" "^7.18.6" + "@babel/plugin-transform-modules-amd" "^7.18.6" + "@babel/plugin-transform-modules-commonjs" "^7.18.6" + "@babel/plugin-transform-modules-systemjs" "^7.18.6" + "@babel/plugin-transform-modules-umd" "^7.18.6" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.18.6" + "@babel/plugin-transform-new-target" "^7.18.6" + "@babel/plugin-transform-object-super" "^7.18.6" + "@babel/plugin-transform-parameters" "^7.18.6" + "@babel/plugin-transform-property-literals" "^7.18.6" + "@babel/plugin-transform-regenerator" "^7.18.6" + "@babel/plugin-transform-reserved-words" "^7.18.6" + "@babel/plugin-transform-shorthand-properties" "^7.18.6" + "@babel/plugin-transform-spread" "^7.18.6" + "@babel/plugin-transform-sticky-regex" "^7.18.6" + "@babel/plugin-transform-template-literals" "^7.18.6" + "@babel/plugin-transform-typeof-symbol" "^7.18.6" + "@babel/plugin-transform-unicode-escapes" "^7.18.6" + "@babel/plugin-transform-unicode-regex" "^7.18.6" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.18.6" + babel-plugin-polyfill-corejs2 "^0.3.1" + babel-plugin-polyfill-corejs3 "^0.5.2" + babel-plugin-polyfill-regenerator "^0.3.1" + core-js-compat "^3.22.1" + semver "^6.3.0" + +"@babel/preset-modules@^0.1.5": + version "0.1.5" + resolved "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/preset-typescript@^7.10.4": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz" + integrity sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-transform-typescript" "^7.18.6" + +"@babel/runtime@^7.8.4": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.6.tgz" + integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.18.6", "@babel/template@^7.3.3": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz" + integrity sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.18.6" + "@babel/types" "^7.18.6" + +"@babel/traverse@^7.1.0", "@babel/traverse@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.6.tgz" + integrity sha512-zS/OKyqmD7lslOtFqbscH6gMLFYOfG1YPqCKfAW5KrTeolKqvB8UelR49Fpr6y93kYkW2Ik00mT1LOGiAGvizw== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.6" + "@babel/helper-function-name" "^7.18.6" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.18.6" + "@babel/types" "^7.18.6" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/traverse@^7.13.0": + version "7.18.11" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.11.tgz#3d51f2afbd83ecf9912bcbb5c4d94e3d2ddaa16f" + integrity sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.10" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.18.11" + "@babel/types" "^7.18.10" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.18.7", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": + version "7.18.7" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.18.7.tgz" + integrity sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + to-fast-properties "^2.0.0" + +"@babel/types@^7.18.10", "@babel/types@^7.18.9": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.10.tgz#4908e81b6b339ca7c6b7a555a5fc29446f26dde6" + integrity sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ== + dependencies: + "@babel/helper-string-parser" "^7.18.10" + "@babel/helper-validator-identifier" "^7.18.6" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@cnakazawa/watch@^1.0.3": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" + integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== + dependencies: + exec-sh "^0.3.2" + minimist "^1.2.0" + +"@elastic/elasticsearch@7": + version "7.17.0" + resolved "https://registry.npmjs.org/@elastic/elasticsearch/-/elasticsearch-7.17.0.tgz" + integrity sha512-5QLPCjd0uLmLj1lSuKSThjNpq39f6NmlTy9ROLFwG5gjyTgpwSqufDeYG/Fm43Xs05uF7WcscoO7eguI3HuuYA== + dependencies: + debug "^4.3.1" + hpagent "^0.1.1" + ms "^2.1.3" + secure-json-parse "^2.4.0" + +"@eslint/eslintrc@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" + integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^13.9.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@fastify/ajv-compiler@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@fastify/ajv-compiler/-/ajv-compiler-1.1.0.tgz#5ce80b1fc8bebffc8c5ba428d5e392d0f9ed10a1" + integrity sha512-gvCOUNpXsWrIQ3A4aXCLIdblL0tDq42BG/2Xw7oxbil9h11uow10ztS2GuFazNBfjbrsZ5nl+nPl5jDSjj5TSg== + dependencies: + ajv "^6.12.6" + +"@fastify/busboy@^1.0.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@fastify/busboy/-/busboy-1.1.0.tgz" + integrity sha512-Fv854f94v0CzIDllbY3i/0NJPNBRNLDawf3BTYVGCe9VrIIs3Wi7AFx24F9NzCxdf0wyx/x0Q9kEVnvDOPnlxA== + dependencies: + text-decoding "^1.0.0" + +"@fastify/caching@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@fastify/caching/-/caching-7.0.0.tgz#8e142fb88f4e6f3f873e6d190e18c4df32cff1ec" + integrity sha512-zMZzUmtByWKeqW8WMt0PILgGIUHLopSGjVPK2pDSPhcrdf9/B/gA4FiW4ylJVY0fhkW18awqI3z+tgUiY6mPsw== + dependencies: + abstract-cache "^1.0.1" + fastify-plugin "^3.0.1" + uid-safe "^2.1.5" + +"@fastify/error@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@fastify/error/-/error-2.0.0.tgz" + integrity sha512-wI3fpfDT0t7p8E6dA2eTECzzOd+bZsZCJ2Hcv+Onn2b7ZwK3RwD27uW2QDaMtQhAfWQQP+WNK7nKf0twLsBf9w== + +"@fastify/formbody@^6.0.0": + version "6.0.1" + resolved "https://registry.npmjs.org/@fastify/formbody/-/formbody-6.0.1.tgz" + integrity sha512-yIwCitoES4Sh0tPc6v+uHBqZEKw3CooSZ4kUvO9NC8Y7oRBCW+aC+pTgUZ8M3r2DOzRkNO+Pq0jMQkyL2k8jZQ== + dependencies: + fastify-plugin "^3.0.0" + +"@fastify/static@^5.0.1": + version "5.0.2" + resolved "https://registry.npmjs.org/@fastify/static/-/static-5.0.2.tgz" + integrity sha512-HvyXZ5a7hUHoSBRq9jKUuKIUCkHMkCDcmiAeEmixXlGOx8pEWx3NYOIaiivcjWa6/NLvfdUT+t/jzfVQ2PA7Gw== + dependencies: + content-disposition "^0.5.3" + encoding-negotiator "^2.0.1" + fastify-plugin "^3.0.0" + glob "^7.1.4" + p-limit "^3.1.0" + readable-stream "^3.4.0" + send "^0.17.1" + +"@ffprobe-installer/darwin-arm64@5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@ffprobe-installer/darwin-arm64/-/darwin-arm64-5.0.1.tgz#a020a623955d55aa8daf45cb668c3044876b553b" + integrity sha512-vwNCNjokH8hfkbl6m95zICHwkSzhEvDC3GVBcUp5HX8+4wsX10SP3B+bGur7XUzTIZ4cQpgJmEIAx6TUwRepMg== + +"@ffprobe-installer/darwin-x64@5.0.0": + version "5.0.0" + resolved "https://registry.npmjs.org/@ffprobe-installer/darwin-x64/-/darwin-x64-5.0.0.tgz" + integrity sha512-Zl0UkZ+wW/eyMKBPLTUCcNQch2VDnZz/cBn1DXv3YtCBVbYd9aYzGj4MImdxgWcoE0+GpbfbO6mKGwMq5HCm6A== + +"@ffprobe-installer/ffprobe@^1.4.1": + version "1.4.1" + resolved "https://registry.npmjs.org/@ffprobe-installer/ffprobe/-/ffprobe-1.4.1.tgz" + integrity sha512-3WJvxU0f4d7IOZdzoVCAj9fYtiQNC6E0521FJFe9iP5Ej8auTXU7TsrUzIAG1CydeQI+BnM3vGog92SCcF9KtA== + optionalDependencies: + "@ffprobe-installer/darwin-arm64" "5.0.1" + "@ffprobe-installer/darwin-x64" "5.0.0" + "@ffprobe-installer/linux-arm" "5.0.0" + "@ffprobe-installer/linux-arm64" "5.0.0" + "@ffprobe-installer/linux-ia32" "5.0.0" + "@ffprobe-installer/linux-x64" "5.0.0" + "@ffprobe-installer/win32-ia32" "5.0.0" + "@ffprobe-installer/win32-x64" "5.0.0" + +"@ffprobe-installer/linux-arm64@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@ffprobe-installer/linux-arm64/-/linux-arm64-5.0.0.tgz#8e50c2ac0fa9f1ccaf553114c09cc9d2f9571de2" + integrity sha512-IwFbzhe1UydR849YXLPP0RMpHgHXSuPO1kznaCHcU5FscFBV5gOZLkdD8e/xrcC8g/nhKqy0xMjn5kv6KkFQlQ== + +"@ffprobe-installer/linux-arm@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@ffprobe-installer/linux-arm/-/linux-arm-5.0.0.tgz#0a67b1610284e4be115da1656f150abc4706fe08" + integrity sha512-mM1PPxP2UX5SUvhy0urcj5U8UolwbYgmnXA/eBWbW78k6N2Wk1COvcHYzOPs6c5yXXL6oshS2rZHU1kowigw7g== + +"@ffprobe-installer/linux-ia32@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@ffprobe-installer/linux-ia32/-/linux-ia32-5.0.0.tgz#38714de93ce3842887e51a8b0c9dab3297777dbb" + integrity sha512-c3bWlWEDMST59SAZycVh0oyc2eNS/CxxeRjoNryGRgqcZX3EJWJJQL1rAXbpQOMLMi8to1RqnmMuwPJgLLjjUA== + +"@ffprobe-installer/linux-x64@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@ffprobe-installer/linux-x64/-/linux-x64-5.0.0.tgz#dc51a99acf74675035c02f59c4d73270ba3742f7" + integrity sha512-zgLnWJFvMGCaw1txGtz84sMEQt6mQUzdw86ih9S/kZOWnp06Gj/ams/EXxEkAxgAACCVM6/O0mkDe/6biY5tgA== + +"@ffprobe-installer/win32-ia32@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@ffprobe-installer/win32-ia32/-/win32-ia32-5.0.0.tgz#77f5cfba1aa91e47255562d23a07432b3e087bb1" + integrity sha512-NnDdAZD6ShFXzJeCkAFl2ZjAv7GcJWYudLA+0T/vjZwvskBop+sq1PGfdmVltfFDcdQiomoThRhn9Xiy9ZC71g== + +"@ffprobe-installer/win32-x64@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@ffprobe-installer/win32-x64/-/win32-x64-5.0.0.tgz#8ed741260b7db346c7bfe77d2fd9acbe3bd70d2f" + integrity sha512-P4ZMRFxVMnfMsOyTfBM/+nkTodLeOUfXNPo+X1bKEWBiZxRErqX/IHS5sLA0yAH8XmtKZcL7Cu6M26ztGcQYxw== + +"@hapi/bourne@^2.0.0": + version "2.1.0" + resolved "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.1.0.tgz" + integrity sha512-i1BpaNDVLJdRBEKeJWkVO6tYX6DMFBuwMhSuWqLsY4ufeTKGVuV5rBsUhxPayXqnnWHgXUAmWK16H/ykO5Wj4Q== + +"@humanwhocodes/config-array@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" + integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== + dependencies: + "@humanwhocodes/object-schema" "^1.2.0" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.0": + version "1.2.1" + resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" + integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^26.6.2" + jest-util "^26.6.2" + slash "^3.0.0" + +"@jest/core@^26.6.3": + version "26.6.3" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" + integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== + dependencies: + "@jest/console" "^26.6.2" + "@jest/reporters" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-changed-files "^26.6.2" + jest-config "^26.6.3" + jest-haste-map "^26.6.2" + jest-message-util "^26.6.2" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-resolve-dependencies "^26.6.3" + jest-runner "^26.6.3" + jest-runtime "^26.6.3" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + jest-watcher "^26.6.2" + micromatch "^4.0.2" + p-each-series "^2.1.0" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" + integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== + dependencies: + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + +"@jest/fake-timers@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" + integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== + dependencies: + "@jest/types" "^26.6.2" + "@sinonjs/fake-timers" "^6.0.1" + "@types/node" "*" + jest-message-util "^26.6.2" + jest-mock "^26.6.2" + jest-util "^26.6.2" + +"@jest/globals@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" + integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/types" "^26.6.2" + expect "^26.6.2" + +"@jest/reporters@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" + integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.2.4" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^4.0.3" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.0.2" + jest-haste-map "^26.6.2" + jest-resolve "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^7.0.0" + optionalDependencies: + node-notifier "^8.0.0" + +"@jest/source-map@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.6.2.tgz#29af5e1e2e324cafccc936f218309f54ab69d535" + integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.4" + source-map "^0.6.0" + +"@jest/test-result@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" + integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== + dependencies: + "@jest/console" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^26.6.3": + version "26.6.3" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz#98e8a45100863886d074205e8ffdc5a7eb582b17" + integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== + dependencies: + "@jest/test-result" "^26.6.2" + graceful-fs "^4.2.4" + jest-haste-map "^26.6.2" + jest-runner "^26.6.3" + jest-runtime "^26.6.3" + +"@jest/transform@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" + integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^26.6.2" + babel-plugin-istanbul "^6.0.0" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.4" + jest-haste-map "^26.6.2" + jest-regex-util "^26.0.0" + jest-util "^26.6.2" + micromatch "^4.0.2" + pirates "^4.0.1" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + +"@jest/types@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" + integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.0.8" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.8.tgz" + integrity sha512-YK5G9LaddzGbcucK4c8h5tWFmMPBvRZ/uyWmN1/SbBdIvqGUdWGkJ5BAaccgs6XbzVLsqbPJrBSFwKv3kT9i7w== + +"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.9": + version "0.3.14" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz" + integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@mapbox/node-pre-gyp@^1.0.0": + version "1.0.9" + resolved "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz" + integrity sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw== + dependencies: + detect-libc "^2.0.0" + https-proxy-agent "^5.0.0" + make-dir "^3.1.0" + node-fetch "^2.6.7" + nopt "^5.0.0" + npmlog "^5.0.1" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.11" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@redis/bloom@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.0.2.tgz#42b82ec399a92db05e29fffcdfd9235a5fc15cdf" + integrity sha512-EBw7Ag1hPgFzdznK2PBblc1kdlj5B5Cw3XwI9/oG7tSn85/HKy3X9xHy/8tm/eNXJYHLXHJL/pkwBpFMVVefkw== + +"@redis/client@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@redis/client/-/client-1.2.0.tgz#be2ef974881e57276123cb76d08756c03eed946f" + integrity sha512-a8Nlw5fv2EIAFJxTDSSDVUT7yfBGpZO96ybZXzQpgkyLg/dxtQ1uiwTc0EGfzg1mrPjZokeBSEGTbGXekqTNOg== + dependencies: + cluster-key-slot "1.1.0" + generic-pool "3.8.2" + yallist "4.0.0" + +"@redis/graph@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@redis/graph/-/graph-1.0.1.tgz#eabc58ba99cd70d0c907169c02b55497e4ec8a99" + integrity sha512-oDE4myMCJOCVKYMygEMWuriBgqlS5FqdWerikMoJxzmmTUErnTRRgmIDa2VcgytACZMFqpAOWDzops4DOlnkfQ== + +"@redis/json@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@redis/json/-/json-1.0.3.tgz#a13fde1d22ebff0ae2805cd8e1e70522b08ea866" + integrity sha512-4X0Qv0BzD9Zlb0edkUoau5c1bInWSICqXAGrpwEltkncUwcxJIGEcVryZhLgb0p/3PkKaLIWkjhHRtLe9yiA7Q== + +"@redis/search@1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@redis/search/-/search-1.0.6.tgz#53d7451c2783f011ebc48ec4c2891264e0b22f10" + integrity sha512-pP+ZQRis5P21SD6fjyCeLcQdps+LuTzp2wdUbzxEmNhleighDDTD5ck8+cYof+WLec4csZX7ks+BuoMw0RaZrA== + +"@redis/time-series@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.0.3.tgz#4cfca8e564228c0bddcdf4418cba60c20b224ac4" + integrity sha512-OFp0q4SGrTH0Mruf6oFsHGea58u8vS/iI5+NpYdicaM+7BgqBZH8FFvNZ8rYYLrUO/QRqMq72NpXmxLVNcdmjA== + +"@segment/loosely-validate-event@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz#87dfc979e5b4e7b82c5f1d8b722dfd5d77644681" + integrity sha512-ZMCSfztDBqwotkl848ODgVcAmN4OItEWDCkshcKz0/W6gGSQayuuCtWV/MlodFivAZD793d6UgANd6wCXUfrIw== + dependencies: + component-type "^1.2.1" + join-component "^1.1.0" + +"@selderee/plugin-htmlparser2@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.6.0.tgz#27e994afd1c2cb647ceb5406a185a5574188069d" + integrity sha512-J3jpy002TyBjd4N/p6s+s90eX42H2eRhK3SbsZuvTDv977/E8p2U3zikdiehyJja66do7FlxLomZLPlvl2/xaA== + dependencies: + domhandler "^4.2.0" + selderee "^0.6.0" + +"@sentry/core@6.19.7": + version "6.19.7" + resolved "https://registry.npmjs.org/@sentry/core/-/core-6.19.7.tgz" + integrity sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw== + dependencies: + "@sentry/hub" "6.19.7" + "@sentry/minimal" "6.19.7" + "@sentry/types" "6.19.7" + "@sentry/utils" "6.19.7" + tslib "^1.9.3" + +"@sentry/hub@6.19.7": + version "6.19.7" + resolved "https://registry.npmjs.org/@sentry/hub/-/hub-6.19.7.tgz" + integrity sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA== + dependencies: + "@sentry/types" "6.19.7" + "@sentry/utils" "6.19.7" + tslib "^1.9.3" + +"@sentry/minimal@6.19.7": + version "6.19.7" + resolved "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.19.7.tgz" + integrity sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ== + dependencies: + "@sentry/hub" "6.19.7" + "@sentry/types" "6.19.7" + tslib "^1.9.3" + +"@sentry/node@^6.19.7": + version "6.19.7" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.19.7.tgz#32963b36b48daebbd559e6f13b1deb2415448592" + integrity sha512-gtmRC4dAXKODMpHXKfrkfvyBL3cI8y64vEi3fDD046uqYcrWdgoQsffuBbxMAizc6Ez1ia+f0Flue6p15Qaltg== + dependencies: + "@sentry/core" "6.19.7" + "@sentry/hub" "6.19.7" + "@sentry/types" "6.19.7" + "@sentry/utils" "6.19.7" + cookie "^0.4.1" + https-proxy-agent "^5.0.0" + lru_map "^0.3.3" + tslib "^1.9.3" + +"@sentry/tracing@^6.19.7": + version "6.19.7" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.19.7.tgz#54bb99ed5705931cd33caf71da347af769f02a4c" + integrity sha512-ol4TupNnv9Zd+bZei7B6Ygnr9N3Gp1PUrNI761QSlHtPC25xXC5ssSD3GMhBgyQrcvpuRcCFHVNNM97tN5cZiA== + dependencies: + "@sentry/hub" "6.19.7" + "@sentry/minimal" "6.19.7" + "@sentry/types" "6.19.7" + "@sentry/utils" "6.19.7" + tslib "^1.9.3" + +"@sentry/types@6.19.7": + version "6.19.7" + resolved "https://registry.npmjs.org/@sentry/types/-/types-6.19.7.tgz" + integrity sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg== + +"@sentry/utils@6.19.7": + version "6.19.7" + resolved "https://registry.npmjs.org/@sentry/utils/-/utils-6.19.7.tgz" + integrity sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA== + dependencies: + "@sentry/types" "6.19.7" + tslib "^1.9.3" + +"@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== + +"@sindresorhus/is@^4.0.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" + integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== + +"@sinonjs/commons@^1.7.0": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" + integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@socket.io/component-emitter@~3.1.0": + version "3.1.0" + resolved "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz" + integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== + +"@socket.io/redis-adapter@^7.1.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@socket.io/redis-adapter/-/redis-adapter-7.2.0.tgz" + integrity sha512-/r6oF6Myz0K9uatB/pfCi0BhKg/KRMh1OokrqcjlNz6aq40WiXdFLRbHJQuwGHq/KvB+D6141K+IynbVxZGvhw== + dependencies: + debug "~4.3.1" + notepack.io "~2.2.0" + socket.io-adapter "^2.4.0" + uid2 "0.0.3" + +"@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== + dependencies: + defer-to-connect "^1.0.1" + +"@szmarczak/http-timer@^4.0.5": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" + integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== + dependencies: + defer-to-connect "^2.0.0" + +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + +"@types/amqp-connection-manager@^2.0.10": + version "2.0.12" + resolved "https://registry.yarnpkg.com/@types/amqp-connection-manager/-/amqp-connection-manager-2.0.12.tgz#809a01207193ffc15b1689806b51dfeba7b3f9f3" + integrity sha512-2GX1jG6ECpEXQF0X68gTTZc8MQ8GA0dM2mAd1irTpWlKzGKlGzCBtb1YnqLHozNNsoLtGI6UXSp0q06jU1LA6g== + dependencies: + "@types/amqplib" "*" + +"@types/amqplib@*": + version "0.8.2" + resolved "https://registry.yarnpkg.com/@types/amqplib/-/amqplib-0.8.2.tgz#9c46f2c7fac381e4f81bcb612c00d54549697d22" + integrity sha512-p+TFLzo52f8UanB+Nq6gyUi65yecAcRY3nYowU6MPGFtaJvEDxcnFWrxssSTkF+ts1W3zyQDvgVICLQem5WxRA== + dependencies: + "@types/bluebird" "*" + "@types/node" "*" + +"@types/analytics-node@^3.1.5": + version "3.1.9" + resolved "https://registry.npmjs.org/@types/analytics-node/-/analytics-node-3.1.9.tgz" + integrity sha512-C7L7/Dd/CmBST7AvgoCnf4yI9h6W5aYfCOcfUZS5GHlXDQjnXLVOUDpTdwTIZjW4lKECeil6+G+Ul6Xzwv/P0g== + +"@types/archiver@^5.3.1": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-5.3.1.tgz#02991e940a03dd1a32678fead4b4ca03d0e387ca" + integrity sha512-wKYZaSXaDvTZuInAWjCeGG7BEAgTWG2zZW0/f7IYFcoHB2X2d9lkVFnrOlXl3W6NrvO6Ml3FLLu8Uksyymcpnw== + dependencies: + "@types/glob" "*" + +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": + version "7.1.19" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz" + integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.4" + resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": + version "7.17.1" + resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz" + integrity sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA== + dependencies: + "@babel/types" "^7.3.0" + +"@types/bcrypt@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/bcrypt/-/bcrypt-5.0.0.tgz#a835afa2882d165aff5690893db314eaa98b9f20" + integrity sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw== + dependencies: + "@types/node" "*" + +"@types/bluebird@*": + version "3.5.36" + resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.36.tgz#00d9301d4dc35c2f6465a8aec634bb533674c652" + integrity sha512-HBNx4lhkxN7bx6P0++W8E289foSu8kO8GCk2unhuVggO+cE7rh9DhZUyPhUxNRG9m+5B5BTKxZQ5ZP92x/mx9Q== + +"@types/busboy@^0.2.3": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@types/busboy/-/busboy-0.2.4.tgz#19922f8c7076ad6d47b2565da8c0a94c88776315" + integrity sha512-f+ZCVjlcN8JW/zf3iR0GqO4gjOUlltMTtZjn+YR1mlK+MVu6esTiIecO0/GQlmYQPQLdBnc7+5vG3Xb+SkvFLw== + dependencies: + "@types/node" "*" + +"@types/cacheable-request@^6.0.1": + version "6.0.3" + resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" + integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== + dependencies: + "@types/http-cache-semantics" "*" + "@types/keyv" "^3.1.4" + "@types/node" "*" + "@types/responselike" "^1.0.0" + +"@types/chai@^4.2.12": + version "4.3.1" + resolved "https://registry.npmjs.org/@types/chai/-/chai-4.3.1.tgz" + integrity sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ== + +"@types/cli-table@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@types/cli-table/-/cli-table-0.3.0.tgz#f1857156bf5fd115c6a2db260ba0be1f8fc5671c" + integrity sha512-QnZUISJJXyhyD6L1e5QwXDV/A5i2W1/gl6D6YMc8u0ncPepbv/B4w3S+izVvtAg60m6h+JP09+Y/0zF2mojlFQ== + +"@types/component-emitter@^1.2.10": + version "1.2.11" + resolved "https://registry.yarnpkg.com/@types/component-emitter/-/component-emitter-1.2.11.tgz#50d47d42b347253817a39709fef03ce66a108506" + integrity sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ== + +"@types/config@0.0.36": + version "0.0.36" + resolved "https://registry.yarnpkg.com/@types/config/-/config-0.0.36.tgz#bf53ca640f3a1a6a2072a9f33e02a44def07a40b" + integrity sha512-EoAeT1MyFWh2BJvBDEFInY714bQBbHOAucqxqqhprhbBFqr+B7fuN5T9CJqUIGDzvwubnKKRqmSo6yPo0aSpNw== + +"@types/cookie@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" + integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== + +"@types/cookiejar@*": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.2.tgz#66ad9331f63fe8a3d3d9d8c6e3906dd10f6446e8" + integrity sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog== + +"@types/cors@^2.8.12": + version "2.8.12" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" + integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== + +"@types/eslint@^7.2.3": + version "7.29.0" + resolved "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz" + integrity sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*": + version "0.0.52" + resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.52.tgz" + integrity sha512-BZWrtCU0bMVAIliIV+HJO1f1PR41M7NKjfxrFJwwhKI1KwhwOxYw1SXg9ao+CIMt774nFuGiG6eU+udtbEI9oQ== + +"@types/fastify-multipart@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@types/fastify-multipart/-/fastify-multipart-0.7.0.tgz#fcbabfb35e69af0290a1c6c83199fc7e03855a51" + integrity sha512-dKK9S8nBesXhSfUlgyGE7mNJ5a1TxiBeIalJFdPbUj5bJywgjo3ixpm+LcIpTK2UwQ10OWptny/Kjc3GprREtg== + dependencies: + fastify-multipart "*" + +"@types/fastify-static@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@types/fastify-static/-/fastify-static-2.2.1.tgz#7e8f7e87d894bc5bf4bb8eef8a13229290aaa622" + integrity sha512-jDE4J3nkhmBbDwopkaEmJzbGnCc1YWlkCeKPtdh9B6SuPH3RJv8SMf1Tv3nGel/RL2GUWN3tkhhFVJogqrmtMw== + dependencies: + fastify-static "*" + +"@types/fluent-ffmpeg@^2.1.20": + version "2.1.20" + resolved "https://registry.npmjs.org/@types/fluent-ffmpeg/-/fluent-ffmpeg-2.1.20.tgz" + integrity sha512-B+OvhCdJ3LgEq2PhvWNOiB/EfwnXLElfMCgc4Z1K5zXgSfo9I6uGKwR/lqmNPFQuebNnes7re3gqkV77SyypLg== + dependencies: + "@types/node" "*" + +"@types/glob@*": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-8.0.0.tgz#321607e9cbaec54f687a0792b2d1d370739455d2" + integrity sha512-l6NQsDDyQUVeoTynNpC9uRvCUint/gSUXQA2euwmTuWGvPY5LSDUu6tkCtJB2SvGQlJQzLaKqcGZP4//7EDveA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + +"@types/graceful-fs@^4.1.2": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== + dependencies: + "@types/node" "*" + +"@types/html-to-text@^8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@types/html-to-text/-/html-to-text-8.1.1.tgz#0c5573207c14f618f24da5a2910c510285573094" + integrity sha512-QFcqfc7TiVbvIX8Fc2kWUxakruI1Ay6uitaGCYHzI5M0WHQROV5D2XeSaVrK0FmvssivXum4yERVnJsiuH61Ww== + +"@types/http-cache-semantics@*": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812" + integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ== + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^26.0.14": + version "26.0.24" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.24.tgz#943d11976b16739185913a1936e0de0c4a7d595a" + integrity sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w== + dependencies: + jest-diff "^26.0.0" + pretty-format "^26.0.0" + +"@types/json-schema@*", "@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + +"@types/jsonwebtoken@^8.5.0": + version "8.5.8" + resolved "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.8.tgz" + integrity sha512-zm6xBQpFDIDM6o9r6HSgDeIcLy82TKWctCXEPbJJcXb5AKmi5BNNdLXneixK4lplX3PqIVcwLBCGE/kAGnlD4A== + dependencies: + "@types/node" "*" + +"@types/keyv@^3.1.4": + version "3.1.4" + resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" + integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== + dependencies: + "@types/node" "*" + +"@types/lodash@^4.14.165": + version "4.14.182" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz" + integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q== + +"@types/long@^4.0.0": + version "4.0.2" + resolved "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz" + integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== + +"@types/minimatch@*": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" + integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== + +"@types/minimist@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" + integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== + +"@types/minio@^7.0.7": + version "7.0.13" + resolved "https://registry.npmjs.org/@types/minio/-/minio-7.0.13.tgz" + integrity sha512-Warrx6uN4KEpBCAWiTh7ngrPoaNIckawtBXqWbFzaatG/NPRZToAv/fa9yAPA7a2FHAGhe154KqaVIqacIn2pQ== + dependencies: + "@types/node" "*" + +"@types/mongodb@^4.0.7": + version "4.0.7" + resolved "https://registry.yarnpkg.com/@types/mongodb/-/mongodb-4.0.7.tgz#ebaa80c53b684ea52ccfe7721c0f5c9ef7b4f511" + integrity sha512-lPUYPpzA43baXqnd36cZ9xxorprybxXDzteVKCPAdp14ppHtFJHnXYvNpmBvtMUTb5fKXVv6sVbzo1LHkWhJlw== + dependencies: + mongodb "*" + +"@types/needle@*": + version "2.5.3" + resolved "https://registry.npmjs.org/@types/needle/-/needle-2.5.3.tgz" + integrity sha512-RwgTwMRaedfyCBe5SSWMpm1Yqzc5UPZEMw0eAd09OSyV93nLRj9/evMGZmgFeHKzUOd4xxtHvgtc+rjcBjI1Qg== + dependencies: + "@types/node" "*" + +"@types/node-cron@^3.0.0": + version "3.0.2" + resolved "https://registry.npmjs.org/@types/node-cron/-/node-cron-3.0.2.tgz" + integrity sha512-SK/4GYWiWvGLPl/yv+Tm5oLYbzMx1V3y7CsNTvOb3vF8O9oXH11U6/zckISHnBl4YH8MvXHFIUXbYoBONSdmzw== + +"@types/node-fetch@^2.5.12": + version "2.6.2" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.2.tgz#d1a9c5fd049d9415dce61571557104dec3ec81da" + integrity sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A== + dependencies: + "@types/node" "*" + form-data "^3.0.0" + +"@types/node-uuid@^0.0.28": + version "0.0.28" + resolved "https://registry.npmjs.org/@types/node-uuid/-/node-uuid-0.0.28.tgz" + integrity sha512-FOZsQldDy39ox+grtoZfGC43zLz88fBZo+YbH+ROXqrHw2stPSnOL5nMTrq4I2q+Kd8rBU2PEXMN/HO9nIrvQQ== + dependencies: + "@types/node" "*" + +"@types/node@*", "@types/node@>=10.0.0", "@types/node@>=8", "@types/node@^14.0.1", "@types/node@^14.11.2": + version "14.18.21" + resolved "https://registry.npmjs.org/@types/node/-/node-14.18.21.tgz" + integrity sha512-x5W9s+8P4XteaxT/jKF0PSb7XEvo5VmqEWgsMlyeY4ZlLK8I6aH6g5TPPyDlLAep+GYf4kefb7HFyc7PAO3m+Q== + +"@types/normalize-package-data@^2.4.0": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" + integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== + +"@types/pdf-image@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/pdf-image/-/pdf-image-2.0.1.tgz#c05af33ba65d70e9dad2da99b33c9c027d0686f7" + integrity sha512-WSG+F90yd53I2iA3/MiRolRmP0hT0GLkfdq2CYg1sW1AmsWK9bitc9v0EaakkMvFebESzoU/P4vsUhYnDz/OYw== + +"@types/pino-pretty@*": + version "4.7.5" + resolved "https://registry.npmjs.org/@types/pino-pretty/-/pino-pretty-4.7.5.tgz" + integrity sha512-rfHe6VIknk14DymxGqc9maGsRe8/HQSvM2u46EAz2XrS92qsAJnW16dpdFejBuZKD8cRJX6Aw6uVZqIQctMpAg== + dependencies: + "@types/node" "*" + "@types/pino" "6.3" + +"@types/pino-std-serializers@*": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@types/pino-std-serializers/-/pino-std-serializers-2.4.1.tgz#f8bd52a209c8b3c97d1533b1ba27f57c816382bf" + integrity sha512-17XcksO47M24IVTVKPeAByWUd3Oez7EbIjXpSbzMPhXVzgjGtrOa49gKBwxH9hb8dKv58OelsWQ+A1G1l9S3wQ== + dependencies: + "@types/node" "*" + +"@types/pino@6.3", "@types/pino@^6.3.2": + version "6.3.12" + resolved "https://registry.npmjs.org/@types/pino/-/pino-6.3.12.tgz" + integrity sha512-dsLRTq8/4UtVSpJgl9aeqHvbh6pzdmjYD3C092SYgLD2TyoCqHpTJk6vp8DvCTGGc7iowZ2MoiYiVUUCcu7muw== + dependencies: + "@types/node" "*" + "@types/pino-pretty" "*" + "@types/pino-std-serializers" "*" + sonic-boom "^2.1.0" + +"@types/prettier@^2.0.0": + version "2.6.3" + resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.3.tgz" + integrity sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg== + +"@types/probe-image-size@^7.0.1": + version "7.2.0" + resolved "https://registry.npmjs.org/@types/probe-image-size/-/probe-image-size-7.2.0.tgz" + integrity sha512-R5H3vw62gHNHrn+JGZbKejb+Z2D/6E5UNVlhCzIaBBLroMQMOFqy5Pap2gM+ZZHdqBtVU0/cx/M6to+mOJcoew== + dependencies: + "@types/needle" "*" + "@types/node" "*" + +"@types/pump@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/pump/-/pump-1.1.1.tgz#edb3475e2bad0f4552bdaa91c6c43b82e08ff15e" + integrity sha512-wpRerjHDxFBQ4r8XNv3xHJZeuqrBBoeQ/fhgkooV2F7KsPIYRROb/+f9ODgZfOEyO5/w2ej4YQdpPPXipT8DAA== + dependencies: + "@types/node" "*" + +"@types/random-useragent@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@types/random-useragent/-/random-useragent-0.3.1.tgz#1f0e1e08151f04d2c023ab77c8173dfa5b5049d2" + integrity sha512-yVz7897JjjwS6V+lmxlu8pktzNnNWgtF9MGxfaRfI8o+hQageO9K+0hfwr8PspdFJIIRE9KkLqp4o5tlQqv/0w== + +"@types/redis@^4.0.11": + version "4.0.11" + resolved "https://registry.yarnpkg.com/@types/redis/-/redis-4.0.11.tgz#0bb4c11ac9900a21ad40d2a6768ec6aaf651c0e1" + integrity sha512-bI+gth8La8Wg/QCR1+V1fhrL9+LZUSWfcqpOj2Kc80ZQ4ffbdL173vQd5wovmoV9i071FU9oP2g6etLuEwb6Rg== + dependencies: + redis "*" + +"@types/responselike@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" + integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== + dependencies: + "@types/node" "*" + +"@types/semver@^7.3.12": + version "7.3.13" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" + integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== + +"@types/sharp@^0.29.5": + version "0.29.5" + resolved "https://registry.yarnpkg.com/@types/sharp/-/sharp-0.29.5.tgz#9c7032d30d138ad16dde6326beaff2af757b91b3" + integrity sha512-3TC+S3H5RwnJmLYMHrcdfNjz/CaApKmujjY9b6PU/pE6n0qfooi99YqXGWoW8frU9EWYj/XTI35Pzxa+ThAZ5Q== + dependencies: + "@types/node" "*" + +"@types/socket.io-client@^1.4.34": + version "1.4.36" + resolved "https://registry.yarnpkg.com/@types/socket.io-client/-/socket.io-client-1.4.36.tgz#e4f1ca065f84c20939e9850e70222202bd76ff3f" + integrity sha512-ZJWjtFBeBy1kRSYpVbeGYTElf6BqPQUkXDlHHD4k/42byCN5Rh027f4yARHCink9sKAkbtGZXEAmR0ZCnc2/Ag== + +"@types/socket.io-parser@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/socket.io-parser/-/socket.io-parser-3.0.0.tgz#9726d3ab9235757a0a30dd5ccf8975dce54e5e2c" + integrity sha512-Ry/rbTE6HQNL9eu3LpL1Ocup5VexXu1bSSGlSho/IR5LuRc8YvxwSNJ3JxqTltVJEATLbZkMQETSbxfKNgp4Ew== + dependencies: + socket.io-parser "*" + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/strip-bom@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz" + integrity sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ== + +"@types/strip-json-comments@0.0.30": + version "0.0.30" + resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1" + integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ== + +"@types/superagent@*": + version "4.1.15" + resolved "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.15.tgz" + integrity sha512-mu/N4uvfDN2zVQQ5AYJI/g4qxn2bHB6521t1UuH09ShNWjebTqN0ZFuYK9uYjcgmI0dTQEs+Owi1EO6U0OkOZQ== + dependencies: + "@types/cookiejar" "*" + "@types/node" "*" + +"@types/supertest@2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.4.tgz#28770e13293365e240a842d7d5c5a1b3d2dee593" + integrity sha512-0TvOJ+6XVMSImgqc2ClNllfVffCxHQhFbsbwOGzGTjdFydoaG052LPqnP8SnmSlnokOcQiPPcbz+Yi30LxWPyA== + dependencies: + "@types/superagent" "*" + +"@types/uuid@^8.3.0": + version "8.3.4" + resolved "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz" + integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== + +"@types/webidl-conversions@*": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz#e33bc8ea812a01f63f90481c666334844b12a09e" + integrity sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q== + +"@types/whatwg-url@^8.2.1": + version "8.2.2" + resolved "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz" + integrity sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA== + dependencies: + "@types/node" "*" + "@types/webidl-conversions" "*" + +"@types/ws@^7.2.7": + version "7.4.7" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" + integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== + dependencies: + "@types/node" "*" + +"@types/yargs-parser@*": + version "21.0.0" + resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + +"@types/yargs@^15.0.0": + version "15.0.14" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" + integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@^5.0.0": + version "5.48.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.2.tgz#112e6ae1e23a1dc8333ce82bb9c65c2608b4d8a3" + integrity sha512-sR0Gja9Ky1teIq4qJOl0nC+Tk64/uYdX+mi+5iB//MH8gwyx8e3SOyhEzeLZEFEEfCaLf8KJq+Bd/6je1t+CAg== + dependencies: + "@typescript-eslint/scope-manager" "5.48.2" + "@typescript-eslint/type-utils" "5.48.2" + "@typescript-eslint/utils" "5.48.2" + debug "^4.3.4" + ignore "^5.2.0" + natural-compare-lite "^1.4.0" + regexpp "^3.2.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^4.2.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz" + integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== + dependencies: + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" + debug "^4.3.1" + +"@typescript-eslint/scope-manager@4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz" + integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + +"@typescript-eslint/scope-manager@5.48.2": + version "5.48.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz#bb7676cb78f1e94921eaab637a4b5d596f838abc" + integrity sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw== + dependencies: + "@typescript-eslint/types" "5.48.2" + "@typescript-eslint/visitor-keys" "5.48.2" + +"@typescript-eslint/type-utils@5.48.2": + version "5.48.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.48.2.tgz#7d3aeca9fa37a7ab7e3d9056a99b42f342c48ad7" + integrity sha512-QVWx7J5sPMRiOMJp5dYshPxABRoZV1xbRirqSk8yuIIsu0nvMTZesKErEA3Oix1k+uvsk8Cs8TGJ6kQ0ndAcew== + dependencies: + "@typescript-eslint/typescript-estree" "5.48.2" + "@typescript-eslint/utils" "5.48.2" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz" + integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== + +"@typescript-eslint/types@5.48.2": + version "5.48.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.48.2.tgz#635706abb1ec164137f92148f06f794438c97b8e" + integrity sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA== + +"@typescript-eslint/typescript-estree@4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz" + integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/typescript-estree@5.48.2": + version "5.48.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz#6e206b462942b32383582a6c9251c05021cc21b0" + integrity sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg== + dependencies: + "@typescript-eslint/types" "5.48.2" + "@typescript-eslint/visitor-keys" "5.48.2" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.48.2": + version "5.48.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.48.2.tgz#3777a91dcb22b8499a25519e06eef2e9569295a3" + integrity sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow== + dependencies: + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.48.2" + "@typescript-eslint/types" "5.48.2" + "@typescript-eslint/typescript-estree" "5.48.2" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + semver "^7.3.7" + +"@typescript-eslint/visitor-keys@4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz" + integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== + dependencies: + "@typescript-eslint/types" "4.33.0" + eslint-visitor-keys "^2.0.0" + +"@typescript-eslint/visitor-keys@5.48.2": + version "5.48.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz#c247582a0bcce467461d7b696513bf9455000060" + integrity sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ== + dependencies: + "@typescript-eslint/types" "5.48.2" + eslint-visitor-keys "^3.3.0" + +"@zxing/text-encoding@0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz#fb50ffabc6c7c66a0c96b4c03e3d9be74864b70b" + integrity sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA== + +abab@^2.0.3, abab@^2.0.5: + version "2.0.6" + resolved "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz" + integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +abstract-cache@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/abstract-cache/-/abstract-cache-1.0.1.tgz#136151becf5c32e0ea27f78728d073d8fe07932a" + integrity sha512-EfUeMhRUbG5bVVbrSY/ogLlFXoyfMAPxMlSP7wrEqH53d+59r2foVy9a5KjmprLKFLOfPQCNKEfpBN/nQ76chw== + dependencies: + clone "^2.1.1" + lru_map "^0.3.3" + merge-options "^1.0.0" + +abstract-logging@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/abstract-logging/-/abstract-logging-2.0.1.tgz#6b0c371df212db7129b57d2e7fcf282b8bf1c839" + integrity sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA== + +accepts@~1.3.4: + version "1.3.8" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + +acorn-jsx@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + +acorn@^7.1.1, acorn@^7.4.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.2.4: + version "8.7.1" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz" + integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== + +adm-zip@^0.5.3: + version "0.5.9" + resolved "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.9.tgz" + integrity sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg== + +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +aggregate-error@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-4.0.1.tgz#25091fe1573b9e0be892aeda15c7c66a545f758e" + integrity sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w== + dependencies: + clean-stack "^4.0.0" + indent-string "^5.0.0" + +ajv@^6.10.0, ajv@^6.11.0, ajv@^6.12.4, ajv@^6.12.6: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.1, ajv@^8.1.0: + version "8.11.0" + resolved "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +amqp-connection-manager@^3.7.0: + version "3.9.0" + resolved "https://registry.npmjs.org/amqp-connection-manager/-/amqp-connection-manager-3.9.0.tgz" + integrity sha512-ZKw9ckJKz40Lc2pC7DY0NVocpzPalMaCgv0sBn+N4er2QFAJul9pIiMOm/FsPHeCzB+FulV7PckOpmZvWvewGQ== + dependencies: + promise-breaker "^5.0.0" + +amqplib@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/amqplib/-/amqplib-0.8.0.tgz#088d10bc61cc5ac5a49ac72033c7ac66c23aeb61" + integrity sha512-icU+a4kkq4Y1PS4NNi+YPDMwdlbFcZ1EZTQT2nigW3fvOb6AOgUQ9+Mk4ue0Zu5cBg/XpDzB40oH10ysrk2dmA== + dependencies: + bitsyntax "~0.1.0" + bluebird "^3.7.2" + buffer-more-ints "~1.0.0" + readable-stream "1.x >=1.1.9" + safe-buffer "~5.2.1" + url-parse "~1.5.1" + +analytics-node@^5.0.0: + version "5.1.2" + resolved "https://registry.npmjs.org/analytics-node/-/analytics-node-5.1.2.tgz" + integrity sha512-WZ8gkXtLuqD2Q2xEOr/2/LJiR0AnhWHfXZhfPnMZpB7vEwCsh3HapYAUmA1cPj1abrhAqBX7POWuWo/1wUu/Fw== + dependencies: + "@segment/loosely-validate-event" "^2.0.0" + axios "^0.21.4" + axios-retry "3.2.0" + lodash.isstring "^4.0.1" + md5 "^2.2.1" + ms "^2.0.0" + remove-trailing-slash "^0.1.0" + uuid "^8.3.2" + +ansi-align@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" + integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== + dependencies: + string-width "^4.1.0" + +ansi-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.0, ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +anymatch@^3.0.3, anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +"aproba@^1.0.3 || ^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + +archiver-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" + integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== + dependencies: + glob "^7.1.4" + graceful-fs "^4.2.0" + lazystream "^1.0.0" + lodash.defaults "^4.2.0" + lodash.difference "^4.5.0" + lodash.flatten "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.union "^4.6.0" + normalize-path "^3.0.0" + readable-stream "^2.0.0" + +archiver@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.3.1.tgz#21e92811d6f09ecfce649fbefefe8c79e57cbbb6" + integrity sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w== + dependencies: + archiver-utils "^2.1.0" + async "^3.2.3" + buffer-crc32 "^0.2.1" + readable-stream "^3.6.0" + readdir-glob "^1.0.0" + tar-stream "^2.2.0" + zip-stream "^4.1.0" + +archy@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz" + integrity sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw== + +are-we-there-yet@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz" + integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +args-js@~0.10.12: + version "0.10.12" + resolved "https://registry.yarnpkg.com/args-js/-/args-js-0.10.12.tgz#a327aea80e41072a3d85f9c274db6511eb95e49c" + integrity sha512-tR5vYVPA1lIqK4xr8F9ysseHuqgpqHhYe7i1iCW0Vh3zGjrqL9Fti/y5McZkRga2pWOC9Z9rnLIKW1l6I6AVgw== + +args@^5.0.1: + version "5.0.3" + resolved "https://registry.npmjs.org/args/-/args-5.0.3.tgz" + integrity sha512-h6k/zfFgusnv3i5TU08KQkVKuCPBtL/PWQbWkHUxvJrZ2nAyeaUupneemcrgn1xmqxPQsPIzwkUhOpoqPDRZuA== + dependencies: + camelcase "5.0.0" + chalk "2.4.2" + leven "2.1.0" + mri "1.1.4" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz" + integrity sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA== + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz" + integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== + +array-parallel@~0.1.3: + version "0.1.3" + resolved "https://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz" + integrity sha512-TDPTwSWW5E4oiFiKmz6RGJ/a80Y91GuLgUYuLd49+XBS75tYo8PNgaT2K/OxuQYqkoI852MDGBorg9OcUSTQ8w== + +array-series@~0.1.5: + version "0.1.5" + resolved "https://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz" + integrity sha512-L0XlBwfx9QetHOsbLDrE/vh2t018w9462HM3iaFfxRiK83aJjAt/Ja3NMkOW7FICwWTlQBa3ZbL5FKhuQWkDrg== + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz" + integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ== + +arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== + +arrify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-3.0.0.tgz#ccdefb8eaf2a1d2ab0da1ca2ce53118759fd46bc" + integrity sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw== + +asn1.js@^5.2.0: + version "5.4.1" + resolved "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz" + integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +async@>=0.2.9, async@^3.1.0, async@^3.2.3, async@~3.2.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" + integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +atomic-sleep@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" + integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== + +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +avvio@^7.1.2: + version "7.2.5" + resolved "https://registry.npmjs.org/avvio/-/avvio-7.2.5.tgz" + integrity sha512-AOhBxyLVdpOad3TujtC9kL/9r3HnTkxwQ5ggOsYrvvZP1cCFvzHWJd5XxZDFuTn+IN8vkKSG5SEJrd27vCSbeA== + dependencies: + archy "^1.0.0" + debug "^4.0.0" + fastq "^1.6.1" + queue-microtask "^1.1.2" + +axios-retry@3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/axios-retry/-/axios-retry-3.2.0.tgz" + integrity sha512-RK2cLMgIsAQBDhlIsJR5dOhODPigvel18XUv1dDXW+4k1FzebyfRk+C+orot6WPZOYFKSfhLwHPwVmTVOODQ5w== + dependencies: + is-retry-allowed "^1.1.0" + +axios@^0.18.0: + version "0.18.1" + resolved "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz" + integrity sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g== + dependencies: + follow-redirects "1.5.10" + is-buffer "^2.0.2" + +axios@^0.21.3, axios@^0.21.4: + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + +axios@^0.24.0: + version "0.24.0" + resolved "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz" + integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA== + dependencies: + follow-redirects "^1.14.4" + +babel-jest@^26.5.2, babel-jest@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" + integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== + dependencies: + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/babel__core" "^7.1.7" + babel-plugin-istanbul "^6.0.0" + babel-preset-jest "^26.6.2" + chalk "^4.0.0" + graceful-fs "^4.2.4" + slash "^3.0.0" + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-istanbul@^6.0.0: + version "6.1.1" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" + integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + +babel-plugin-parameter-decorator@^1.0.16: + version "1.0.16" + resolved "https://registry.yarnpkg.com/babel-plugin-parameter-decorator/-/babel-plugin-parameter-decorator-1.0.16.tgz#1c889c3a1f3bbf03801fcbc2e95b8bae7468df3f" + integrity sha512-yUT2WPTUg1JaPmRGRSF557m1HJ9vdFQInRWOkiOyO5a9HhqlXffJu+fQ2xd5+qU/35ICMrrk9eWKsHCairKA9w== + +babel-plugin-polyfill-corejs2@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz" + integrity sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w== + dependencies: + "@babel/compat-data" "^7.13.11" + "@babel/helper-define-polyfill-provider" "^0.3.1" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.5.2: + version "0.5.2" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz" + integrity sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.1" + core-js-compat "^3.21.0" + +babel-plugin-polyfill-regenerator@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz" + integrity sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.1" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" + integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== + dependencies: + babel-plugin-jest-hoist "^26.6.2" + babel-preset-current-node-syntax "^1.0.0" + +backo2@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-arraybuffer@0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz" + integrity sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg== + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +base64id@2.0.0, base64id@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" + integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +bcrypt@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-5.0.1.tgz#f1a2c20f208e2ccdceea4433df0c8b2c54ecdf71" + integrity sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw== + dependencies: + "@mapbox/node-pre-gyp" "^1.0.0" + node-addon-api "^3.1.0" + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bitsyntax@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/bitsyntax/-/bitsyntax-0.1.0.tgz#b0c59acef03505de5a2ed62a2f763c56ae1d6205" + integrity sha512-ikAdCnrloKmFOugAfxWws89/fPc+nw0OOG1IzIE72uSOg/A3cYptKCjSUhDTuj7fhsJtzkzlv7l3b8PzRHLN0Q== + dependencies: + buffer-more-ints "~1.0.0" + debug "~2.6.9" + safe-buffer "~5.1.2" + +bl@^4.0.3, bl@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +block-stream2@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/block-stream2/-/block-stream2-2.1.0.tgz#ac0c5ef4298b3857796e05be8ebed72196fa054b" + integrity sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg== + dependencies: + readable-stream "^3.4.0" + +bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.0.0, bn.js@^5.1.1: + version "5.2.1" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz" + integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== + +boxen@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64" + integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ== + dependencies: + ansi-align "^3.0.0" + camelcase "^5.3.1" + chalk "^3.0.0" + cli-boxes "^2.2.0" + string-width "^4.1.0" + term-size "^2.1.0" + type-fest "^0.8.1" + widest-line "^3.1.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +brorand@^1.0.1, brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +browser-or-node@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/browser-or-node/-/browser-or-node-1.3.0.tgz" + integrity sha512-0F2z/VSnLbmEeBcUrSuDH5l0HxTXdQQzLjkmBR4cYfvg1zJrKSlmIZFqyFR8oX0NrwPhy3c3HQ6i3OxMbew4Tg== + +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: + version "4.1.0" + resolved "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.1" + resolved "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz" + integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== + dependencies: + bn.js "^5.1.1" + browserify-rsa "^4.0.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.3" + inherits "^2.0.4" + parse-asn1 "^5.1.5" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +browserslist@^4.20.2, browserslist@^4.21.0: + version "4.21.1" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.1.tgz" + integrity sha512-Nq8MFCSrnJXSc88yliwlzQe3qNe3VntIjhsArW9IJOEPSHNx23FalwApUVbzAWABLhYJJ7y8AynWI/XM8OdfjQ== + dependencies: + caniuse-lite "^1.0.30001359" + electron-to-chromium "^1.4.172" + node-releases "^2.0.5" + update-browserslist-db "^1.0.4" + +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +bson@^4.6.3: + version "4.6.4" + resolved "https://registry.npmjs.org/bson/-/bson-4.6.4.tgz" + integrity sha512-TdQ3FzguAu5HKPPlr0kYQCyrYUYh8tFM+CMTpxjNzVzxeiJY00Rtuj3LXLHSgiGvmaWlZ8PE+4KyM2thqE38pQ== + dependencies: + buffer "^5.6.0" + +buffer-crc32@^0.2.1, buffer-crc32@^0.2.13: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== + +buffer-from@1.x, buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-more-ints@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz#ef4f8e2dddbad429ed3828a9c55d44f05c611422" + integrity sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz" + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== + +buffer@^5.5.0, buffer@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cacheable-lookup@^5.0.3: + version "5.0.4" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" + integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== + +cacheable-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" + integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^1.0.2" + +cacheable-request@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27" + integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^4.0.0" + lowercase-keys "^2.0.0" + normalize-url "^6.0.1" + responselike "^2.0.0" + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase-keys@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-7.0.2.tgz#d048d8c69448745bb0de6fc4c1c52a30dfbe7252" + integrity sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg== + dependencies: + camelcase "^6.3.0" + map-obj "^4.1.0" + quick-lru "^5.1.1" + type-fest "^1.2.1" + +camelcase@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" + integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== + +camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.0.0, camelcase@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001359: + version "1.0.30001361" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001361.tgz" + integrity sha512-ybhCrjNtkFji1/Wto6SSJKkWk6kZgVQsDq5QI83SafsF6FXv2JB4df9eEdH6g8sdGgqTXrFLjAxqBGgYoU3azQ== + +capture-exit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" + integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== + dependencies: + rsvp "^4.8.4" + +cassandra-driver@^4.6.0: + version "4.6.4" + resolved "https://registry.yarnpkg.com/cassandra-driver/-/cassandra-driver-4.6.4.tgz#a916018d2dfee73d00e51cedac84c44aff07bcbd" + integrity sha512-SksbIK0cZ2QZRx8ti7w+PnLqldyY+6kU2gRWFChwXFTtrD/ce8cQICDEHxyPwx+DeILwRnMrPf9cjUGizYw9Vg== + dependencies: + "@types/long" "^4.0.0" + "@types/node" ">=8" + adm-zip "^0.5.3" + long "^2.2.0" + +cb2promise@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/cb2promise/-/cb2promise-1.1.1.tgz#6d97ef9d031202175564eee48af09b17eceded68" + integrity sha512-ShCxBARPFJlSO+Y4pxSpbXh6y+tW54Dmy4jKf0gB1C7qUslRqWqFi80+W9416zSoj6RsqMsnKUcpkt3bOrZmDg== + dependencies: + mimic-fn "~2.0.0" + sliced "~1.0.1" + +chai@^4.2.0: + version "4.3.6" + resolved "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz" + integrity sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.2" + deep-eql "^3.0.1" + get-func-name "^2.0.0" + loupe "^2.3.1" + pathval "^1.1.1" + type-detect "^4.0.5" + +chalk@2.4.2, chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +charenc@0.0.2: + version "0.0.2" + resolved "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz" + integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== + +check-error@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz" + integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA== + +cheerio-select@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz" + integrity sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g== + dependencies: + boolbase "^1.0.0" + css-select "^5.1.0" + css-what "^6.1.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + domutils "^3.0.1" + +cheerio@^1.0.0-rc.2: + version "1.0.0-rc.12" + resolved "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz" + integrity sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q== + dependencies: + cheerio-select "^2.1.0" + dom-serializer "^2.0.0" + domhandler "^5.0.3" + domutils "^3.0.1" + htmlparser2 "^8.0.1" + parse5 "^7.0.0" + parse5-htmlparser2-tree-adapter "^7.0.0" + +chokidar@^3.2.2, chokidar@^3.5.1: + version "3.5.3" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +cjs-module-lexer@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" + integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== + +class-transformer@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.3.2.tgz#779ef5f124784324b40f8e927c774bd96cdecd4b" + integrity sha512-9QY6QXBH/+Gt1C3HBmJCrgY6+EFpIa6aLjfDnlXFx0zQl/HjrCE7qoaI0srNrxpMIfsobCpgUdDG5JYtJOpVsw== + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +clean-stack@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-4.2.0.tgz#c464e4cde4ac789f4e0735c5d75beb49d7b30b31" + integrity sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg== + dependencies: + escape-string-regexp "5.0.0" + +cli-boxes@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" + integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-spinners@^2.5.0: + version "2.6.1" + resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz" + integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== + +cli-table@^0.3.6: + version "0.3.11" + resolved "https://registry.npmjs.org/cli-table/-/cli-table-0.3.11.tgz" + integrity sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ== + dependencies: + colors "1.0.3" + +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clone-response@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz" + integrity sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q== + dependencies: + mimic-response "^1.0.0" + +clone@2.x, clone@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz" + integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== + +cluster-key-slot@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" + integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz" + integrity sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw== + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.9.0: + version "1.9.1" + resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color-support@^1.1.2: + version "1.1.3" + resolved "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + +color@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/color/-/color-4.2.3.tgz" + integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A== + dependencies: + color-convert "^2.0.1" + color-string "^1.9.0" + +colors@1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz" + integrity sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw== + +combined-stream@^1.0.6, combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^2.19.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +component-emitter@^1.2.0, component-emitter@^1.2.1, component-emitter@~1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +component-type@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/component-type/-/component-type-1.2.1.tgz" + integrity sha512-Kgy+2+Uwr75vAi6ChWXgHuLvd+QLD7ssgpaRq2zCvt80ptvAfMc/hijcJxXkBa2wMlEZcJvC2H8Ubo+A9ATHIg== + +compress-commons@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.1.tgz#df2a09a7ed17447642bad10a85cc9a19e5c42a7d" + integrity sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ== + dependencies: + buffer-crc32 "^0.2.13" + crc32-stream "^4.0.2" + normalize-path "^3.0.0" + readable-stream "^3.6.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +config@^3.3.2: + version "3.3.7" + resolved "https://registry.npmjs.org/config/-/config-3.3.7.tgz" + integrity sha512-mX/n7GKDYZMqvvkY6e6oBY49W8wxdmQt+ho/5lhwFDXqQW9gI+Ahp8EKp8VAbISPnmf2+Bv5uZK7lKXZ6pf1aA== + dependencies: + json5 "^2.1.1" + +configstore@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" + integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== + dependencies: + dot-prop "^5.2.0" + graceful-fs "^4.1.2" + make-dir "^3.0.0" + unique-string "^2.0.0" + write-file-atomic "^3.0.0" + xdg-basedir "^4.0.0" + +console-control-strings@^1.0.0, console-control-strings@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz" + integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== + +content-disposition@^0.5.3: + version "0.5.4" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +cookie@^0.4.1, cookie@~0.4.1: + version "0.4.2" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz" + integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== + +cookie@^0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + +cookiejar@^2.1.0: + version "2.1.3" + resolved "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz" + integrity sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ== + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz" + integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== + +core-js-compat@^3.21.0, core-js-compat@^3.22.1: + version "3.23.3" + resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.23.3.tgz" + integrity sha512-WSzUs2h2vvmKsacLHNTdpyOC9k43AEhcGoFlVgCY4L7aw98oSBKtPL6vD0/TqZjRWRQYdDSLkzZIni4Crbbiqw== + dependencies: + browserslist "^4.21.0" + semver "7.0.0" + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cors@~2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +cp-file@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/cp-file/-/cp-file-9.1.0.tgz#e98e30db72d57d47b5b1d444deb70d05e5684921" + integrity sha512-3scnzFj/94eb7y4wyXRWwvzLFaQp87yyfTnChIjlfYrVqp5lVO3E2hIJMeQIltUT0K2ZAB3An1qXcBmwGyvuwA== + dependencies: + graceful-fs "^4.1.2" + make-dir "^3.0.0" + nested-error-stacks "^2.0.0" + p-event "^4.1.0" + +cpy-cli@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/cpy-cli/-/cpy-cli-4.2.0.tgz#d60bf9ac776486af20aac2fa4fb95f8f10b35ce8" + integrity sha512-b04b+cbdr29CdpREPKw/itrfjO43Ty0Aj7wRM6M6LoE4GJxZJCk9Xp+Eu1IqztkKh3LxIBt1tDplENsa6KYprg== + dependencies: + cpy "^9.0.0" + meow "^10.1.2" + +cpy@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/cpy/-/cpy-9.0.1.tgz#7f3ad0ad5bafe0bc70645c4bb567969927cadb9f" + integrity sha512-D9U0DR5FjTCN3oMTcFGktanHnAG5l020yvOCR1zKILmAyPP7I/9pl6NFgRbDcmSENtbK1sQLBz1p9HIOlroiNg== + dependencies: + arrify "^3.0.0" + cp-file "^9.1.0" + globby "^13.1.1" + junk "^4.0.0" + micromatch "^4.0.4" + nested-error-stacks "^2.1.0" + p-filter "^3.0.0" + p-map "^5.3.0" + +crc-32@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + +crc32-stream@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-4.0.2.tgz#c922ad22b38395abe9d3870f02fa8134ed709007" + integrity sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w== + dependencies: + crc-32 "^1.2.0" + readable-stream "^3.4.0" + +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-spawn@^4.0.0: + version "4.0.2" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz" + integrity sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA== + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + +cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +crypt@0.0.2: + version "0.0.2" + resolved "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz" + integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== + +crypto-browserify@^3.12.0: + version "3.12.0" + resolved "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +crypto-random-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" + integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== + +css-select@^4.2.1: + version "4.3.0" + resolved "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz" + integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== + dependencies: + boolbase "^1.0.0" + css-what "^6.0.1" + domhandler "^4.3.1" + domutils "^2.8.0" + nth-check "^2.0.1" + +css-select@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz" + integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg== + dependencies: + boolbase "^1.0.0" + css-what "^6.1.0" + domhandler "^5.0.2" + domutils "^3.0.1" + nth-check "^2.0.1" + +css-what@^6.0.1, css-what@^6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz" + integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== + +cssom@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== + +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" + +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + +dateformat@^4.5.1: + version "4.6.3" + resolved "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz" + integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== + +debug@2, debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@~2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@=3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@^3.1.0, debug@^3.2.6: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +decamelize-keys@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" + integrity sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg== + dependencies: + decamelize "^1.1.0" + map-obj "^1.0.0" + +decamelize@^1.1.0, decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== + +decamelize@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-5.0.1.tgz#db11a92e58c741ef339fb0a2868d8a06a9a7b1e9" + integrity sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA== + +decimal.js@^10.2.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz" + integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og== + +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz" + integrity sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA== + dependencies: + mimic-response "^1.0.0" + +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + +deep-eql@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" + integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== + dependencies: + type-detect "^4.0.0" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@^0.1.3, deep-is@~0.1.3: + version "0.1.4" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deep-object-diff@^1.1.0: + version "1.1.7" + resolved "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.7.tgz" + integrity sha512-QkgBca0mL08P6HiOjoqvmm6xOAl2W6CT2+34Ljhg0OeFan8cwlcdq8jrLKsBBuUFAZLsN5b6y491KdKEoSo9lg== + +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz" + integrity sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA== + dependencies: + clone "^1.0.2" + +defer-to-connect@^1.0.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" + integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== + +defer-to-connect@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" + integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== + +define-properties@^1.1.3, define-properties@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz" + integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== + dependencies: + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz" + integrity sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA== + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz" + integrity sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA== + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" + integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== + +denque@^1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" + integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== + +denque@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz" + integrity sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ== + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz" + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== + +des.js@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz" + integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz" + integrity sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg== + +detect-indent@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" + integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== + +detect-libc@^2.0.0, detect-libc@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz" + integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" + integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +discontinuous-range@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a" + integrity sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ== + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dom-serializer@^1.0.1: + version "1.4.1" + resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz" + integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.0" + entities "^2.0.0" + +dom-serializer@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz" + integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + entities "^4.2.0" + +domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== + dependencies: + webidl-conversions "^5.0.0" + +domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1: + version "4.3.1" + resolved "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz" + integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== + dependencies: + domelementtype "^2.2.0" + +domhandler@^5.0.1, domhandler@^5.0.2, domhandler@^5.0.3: + version "5.0.3" + resolved "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz" + integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== + dependencies: + domelementtype "^2.3.0" + +domutils@^2.5.2, domutils@^2.8.0: + version "2.8.0" + resolved "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + +domutils@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz" + integrity sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.1" + +dot-prop@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== + dependencies: + is-obj "^2.0.0" + +duplexer3@^0.1.4: + version "0.1.5" + resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz" + integrity sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA== + +duplexer@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + +dynamic-dedupe@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz" + integrity sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ== + dependencies: + xtend "^4.0.0" + +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.4.172: + version "1.4.176" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.176.tgz" + integrity sha512-92JdgyRlcNDwuy75MjuFSb3clt6DGJ2IXSpg0MCjKd3JV9eSmuUAIyWiGAp/EtT0z2D4rqbYqThQLV90maH3Zw== + +elliptic@^6.5.3: + version "6.5.4" + resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +emittery@^0.7.1: + version "0.7.2" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" + integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ== + +emoji-name-map@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/emoji-name-map/-/emoji-name-map-1.2.9.tgz#32a0788e748d9c7185a29a000102fb263fe2892d" + integrity sha512-MSM8y6koSqh/2uEMI2VoKA+Ac0qL5RkgFGP/pzL6n5FOrOJ7FOZFxgs7+uNpqA+AT+WmdbMPXkd3HnFXXdz4AA== + dependencies: + emojilib "^2.0.2" + iterate-object "^1.3.1" + map-o "^2.0.1" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emojilib@^2.0.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/emojilib/-/emojilib-2.4.0.tgz#ac518a8bb0d5f76dda57289ccb2fdf9d39ae721e" + integrity sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +encoding-negotiator@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/encoding-negotiator/-/encoding-negotiator-2.0.1.tgz#79871bb5473b81f6a0670e8de5303fb5ee0868a3" + integrity sha512-GSK7qphNR4iPcejfAlZxKDoz3xMhnspwImK+Af5WhePS9jUpK/Oh7rUdyENWu+9rgDflOCTmAojBsgsvM8neAQ== + +end-of-stream@^1.1.0, end-of-stream@^1.4.1, end-of-stream@^1.4.4: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +engine.io-client@~4.1.0: + version "4.1.4" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-4.1.4.tgz#0bda5ba4bd87bced2ad00b93c67e133d0fb981ba" + integrity sha512-843fqAdKeUMFqKi1sSjnR11tJ4wi8sIefu6+JC1OzkkJBmjtc/gM/rZ53tJfu5Iae/3gApm5veoS+v+gtT0+Fg== + dependencies: + base64-arraybuffer "0.1.4" + component-emitter "~1.3.0" + debug "~4.3.1" + engine.io-parser "~4.0.1" + has-cors "1.1.0" + parseqs "0.0.6" + parseuri "0.0.6" + ws "~7.4.2" + xmlhttprequest-ssl "~1.6.2" + yeast "0.1.2" + +engine.io-parser@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-4.0.3.tgz#83d3a17acfd4226f19e721bb22a1ee8f7662d2f6" + integrity sha512-xEAAY0msNnESNPc00e19y5heTPX4y/TJ36gr8t1voOaNmTojP9b3oK3BbJLFufW2XFPQaaijpFewm2g2Um3uqA== + dependencies: + base64-arraybuffer "0.1.4" + +engine.io-parser@~5.0.3: + version "5.0.4" + resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz" + integrity sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg== + +engine.io@~6.2.0: + version "6.2.0" + resolved "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz" + integrity sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg== + dependencies: + "@types/cookie" "^0.4.1" + "@types/cors" "^2.8.12" + "@types/node" ">=10.0.0" + accepts "~1.3.4" + base64id "2.0.0" + cookie "~0.4.1" + cors "~2.8.5" + debug "~4.3.1" + engine.io-parser "~5.0.3" + ws "~8.2.3" + +enquirer@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== + dependencies: + ansi-colors "^4.1.1" + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +entities@^4.2.0, entities@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/entities/-/entities-4.3.0.tgz" + integrity sha512-/iP1rZrSEJ0DTlPiX+jbzlA3eVkY/e8L8SozroF395fIqE3TYF/Nz7YOMAawta+vLmyJ/hkGNNPcSbMADCCXbg== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.19.0, es-abstract@^1.19.5, es-abstract@^1.20.0: + version "1.20.1" + resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz" + integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + function.prototype.name "^1.1.5" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-weakref "^1.0.2" + object-inspect "^1.12.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + regexp.prototype.flags "^1.4.3" + string.prototype.trimend "^1.0.5" + string.prototype.trimstart "^1.0.5" + unbox-primitive "^1.0.2" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +es6-error@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" + integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-goat@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" + integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8" + integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escodegen@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-config-prettier@^6.15.0: + version "6.15.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz#7f93f6cb7d45a92f1537a70ecc06366e1ac6fed9" + integrity sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw== + dependencies: + get-stdin "^6.0.0" + +eslint-plugin-prettier@^3.1.4: + version "3.4.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz#e9ddb200efb6f3d05ffe83b1665a716af4a387e5" + integrity sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g== + dependencies: + prettier-linter-helpers "^1.0.0" + +eslint-plugin-unused-imports@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-2.0.0.tgz#d8db8c4d0cfa0637a8b51ce3fd7d1b6bc3f08520" + integrity sha512-3APeS/tQlTrFa167ThtP0Zm0vctjr4M44HMpeg1P4bK6wItarumq0Ma82xorMKdFsWpphQBlRPzw/pxiVELX1A== + dependencies: + eslint-rule-composer "^0.3.0" + +eslint-rule-composer@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" + integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint@^7.10.0: + version "7.32.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" + integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== + dependencies: + "@babel/code-frame" "7.12.11" + "@eslint/eslintrc" "^0.4.3" + "@humanwhocodes/config-array" "^0.5.0" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + escape-string-regexp "^4.0.0" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.1.2" + globals "^13.6.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^6.0.9" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^7.3.0, espree@^7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^1.3.0" + +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +eta@^1.12.3: + version "1.12.3" + resolved "https://registry.yarnpkg.com/eta/-/eta-1.12.3.tgz#2982d08adfbef39f9fa50e2fbd42d7337e7338b1" + integrity sha512-qHixwbDLtekO/d51Yr4glcaUJCIjGVJyTzuqV4GPlgZo1YpgOKG+avQynErZIYrfM6JIJdtiG2Kox8tbb+DoGg== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +event-stream@=3.3.4: + version "3.3.4" + resolved "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz" + integrity sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g== + dependencies: + duplexer "~0.1.1" + from "~0" + map-stream "~0.1.0" + pause-stream "0.0.11" + split "0.3" + stream-combiner "~0.0.4" + through "~2.3.1" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +exec-sh@^0.3.2: + version "0.3.6" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" + integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz" + integrity sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA== + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-template@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== + +expect@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" + integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== + dependencies: + "@jest/types" "^26.6.2" + ansi-styles "^4.0.0" + jest-get-type "^26.3.0" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-regex-util "^26.0.0" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz" + integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug== + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz" + integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +fast-decode-uri-component@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" + integrity sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + +fast-glob@^3.2.11: + version "3.2.12" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" + integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-json-stringify@^2.5.2: + version "2.7.13" + resolved "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-2.7.13.tgz" + integrity sha512-ar+hQ4+OIurUGjSJD1anvYSDcUflywhKjfxnsW4TBTD7+u0tJufv6DKRWoQk3vI6YBOWMoz0TQtfbe7dxbQmvA== + dependencies: + ajv "^6.11.0" + deepmerge "^4.2.2" + rfdc "^1.2.0" + string-similarity "^4.0.1" + +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fast-proxy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-proxy/-/fast-proxy-2.1.0.tgz#f4544e1db5fa72cb584a6a28497717cc88c561a6" + integrity sha512-ihCPWH8j4pfSIULx6evT39RzZjCkGScCVn2BRyJElDu3v96NCWjPJPX8Olnzxv30mMQUEEijonTKroqCVpXjUQ== + dependencies: + end-of-stream "^1.4.4" + pump "^3.0.0" + semver "^7.3.5" + tiny-lru "^7.0.6" + undici "^3.3.6" + +fast-redact@^3.0.0: + version "3.1.1" + resolved "https://registry.npmjs.org/fast-redact/-/fast-redact-3.1.1.tgz" + integrity sha512-odVmjC8x8jNeMZ3C+rPMESzXVSEU8tSWSHv9HFxP2mm89G/1WwqhrerJDQm9Zus8X6aoRgQDThKqptdNA6bt+A== + +fast-safe-stringify@^2.0.7, fast-safe-stringify@^2.0.8, fast-safe-stringify@~2.1.0: + version "2.1.1" + resolved "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz" + integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== + +fast-xml-parser@^3.17.5: + version "3.21.1" + resolved "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-3.21.1.tgz" + integrity sha512-FTFVjYoBOZTJekiUsawGsSYV9QL0A+zDYCRj7y34IO6Jg+2IMYEtQa+bbictpdpV8dHxXywqU7C0gRDEOFtBFg== + dependencies: + strnum "^1.0.4" + +fastfall@^1.5.0: + version "1.5.1" + resolved "https://registry.npmjs.org/fastfall/-/fastfall-1.5.1.tgz" + integrity sha512-KH6p+Z8AKPXnmA7+Iz2Lh8ARCMr+8WNPVludm1LGkZoD2MjY6LVnRMtTKhkdzI+jr0RzQWXKzKyBJm1zoHEL4Q== + dependencies: + reusify "^1.0.0" + +fastify-cors@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/fastify-cors/-/fastify-cors-4.1.0.tgz#ae6e2533f42b033a35da85ed3d585aafd56c2210" + integrity sha512-Vr4AgypDkRwG16cs1ORnYItZx6FMN+gCpHvP3/nzNZL1HFzf7U/NaSgmC784VqtK8yiqSXZEoTGCsmzeSp8JVw== + dependencies: + fastify-plugin "^2.0.0" + vary "^1.1.2" + +fastify-error@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/fastify-error/-/fastify-error-0.3.1.tgz#8eb993e15e3cf57f0357fc452af9290f1c1278d2" + integrity sha512-oCfpcsDndgnDVgiI7bwFKAun2dO+4h84vBlkWsWnz/OUK9Reff5UFoFl241xTiLeHWX/vU9zkDVXqYUxjOwHcQ== + +"fastify-formbody-deprecated@npm:fastify-formbody@5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/fastify-formbody/-/fastify-formbody-5.2.0.tgz" + integrity sha512-d8Y5hCL82akPyoFiXh2wYOm3es0pV9jqoPo3pO9OV2cNF0cQx39J5WAVXzCh4MSt9Z2qF4Fy5gHlvlyESwjtvg== + dependencies: + fastify-plugin "^3.0.0" + +fastify-formbody@^5.0.0: + version "5.3.0" + resolved "https://registry.npmjs.org/fastify-formbody/-/fastify-formbody-5.3.0.tgz" + integrity sha512-7cjFV2HE/doojyfTwCLToIFD6Hmbw2jVTbfqZ2lbUZznQWlSXu+MBQgqBU8T2nHcMfqSi9vx6PyX0LwTehuKkg== + dependencies: + fastify-formbody-deprecated "npm:fastify-formbody@5.2.0" + process-warning "^1.0.0" + +fastify-jwt@^2.2.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/fastify-jwt/-/fastify-jwt-2.5.0.tgz#6cd4d9b979638edccb6fd3d7f9972c0157cd3bf7" + integrity sha512-QXOSfo65OxSk30TTecLh8J0LEmuQJwRPqXMDvPA9HfLdsX/xPdq/QSvQFvR5Aj1kwrFFjsyb1SNAOQmbkmpj4w== + dependencies: + "@types/jsonwebtoken" "^8.5.0" + fastify-plugin "^3.0.0" + http-errors "^1.8.0" + jsonwebtoken "^8.5.1" + steed "^1.1.3" + +"fastify-multipart-deprecated@npm:fastify-multipart@5.3.1", fastify-multipart@5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/fastify-multipart/-/fastify-multipart-5.3.1.tgz#05254d8aa43dc02af6ce01f4e513a6c30bea2886" + integrity sha512-c2pnGfkJmiNpYqzFYT2QfBg/06AxG531O+n1elqc8YUbWPRzufdqn3yfGAIV3RA7J4Vnf7Pfvgx0iaWqaRTOVA== + dependencies: + "@fastify/busboy" "^1.0.0" + deepmerge "^4.2.2" + end-of-stream "^1.4.4" + fastify-error "^0.3.0" + fastify-plugin "^3.0.0" + hexoid "^1.0.0" + secure-json-parse "^2.4.0" + stream-wormhole "^1.1.0" + +fastify-multipart@*: + version "5.4.0" + resolved "https://registry.yarnpkg.com/fastify-multipart/-/fastify-multipart-5.4.0.tgz#4dcb5e7581ca8e0c95163b4088e8a45feb9e2259" + integrity sha512-Pafy4mtcuFUnFM/t0kgCdL854KIEoDymNVdv4nD7uBfV7lBCQq/NVEuNnaNXAbuCTpeXzYRzi50lSDa9ZM838A== + dependencies: + fastify-multipart-deprecated "npm:fastify-multipart@5.3.1" + process-warning "^1.0.0" + +fastify-plugin@^2.0.0, fastify-plugin@^2.3.4: + version "2.3.4" + resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-2.3.4.tgz#b17abdc36a97877d88101fb86ad8a07f2c07de87" + integrity sha512-I+Oaj6p9oiRozbam30sh39BiuiqBda7yK2nmSPVwDCfIBlKnT8YB3MY+pRQc2Fcd07bf6KPGklHJaQ2Qu81TYQ== + dependencies: + semver "^7.3.2" + +fastify-plugin@^3.0.0, fastify-plugin@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-3.0.1.tgz#79e84c29f401020f38b524f59f2402103fd21ed2" + integrity sha512-qKcDXmuZadJqdTm6vlCqioEbyewF60b/0LOFCcYN1B6BIZGlYJumWWOYs70SFYLDAH4YqdE1cxH/RKMG7rFxgA== + +fastify-sensible@=3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fastify-sensible/-/fastify-sensible-3.0.1.tgz#9577ecb1c499b72b80ffabf6fae3b2d2b26f2dbc" + integrity sha512-XVgrQySnpNq6FTUEhLLyA0i6eB7DKF6OJV05gxCDQ008cEgzOs97L/TOd1tT3fgRf3Z6tyA2zb/wMdFX5o1C2Q== + dependencies: + "@types/node" "^14.0.1" + fast-deep-equal "^3.1.1" + fastify-plugin "^2.0.0" + forwarded "^0.1.2" + http-errors "^1.7.3" + type-is "^1.6.18" + vary "^1.1.2" + +fastify-socket.io@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/fastify-socket.io/-/fastify-socket.io-3.0.0.tgz#9fa74b4fbba48675ea4367e9751d855b092c9a14" + integrity sha512-rVNs6NPY6ZoUQFMxZCRQreQpNyNkyKXrTbzXXzw55/grEegTW0meKBI02JAyWd2/T+k7nKB+d/7aNhYlB/Q5Bg== + dependencies: + fastify-plugin "^3.0.0" + +"fastify-static-deprecated@npm:fastify-static@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/fastify-static/-/fastify-static-4.6.1.tgz#687131da76f1d4391fb8b47f71ea2118cdc85803" + integrity sha512-vy7N28U4AMhuOim12ZZWHulEE6OQKtzZbHgiB8Zj4llUuUQXPka0WHAQI3njm1jTCx4W6fixUHfpITxweMtAIA== + dependencies: + content-disposition "^0.5.3" + encoding-negotiator "^2.0.1" + fastify-plugin "^3.0.0" + glob "^7.1.4" + p-limit "^3.1.0" + readable-stream "^3.4.0" + send "^0.17.1" + +fastify-static@*, fastify-static@^4.0.0, fastify-static@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/fastify-static/-/fastify-static-4.7.0.tgz#e802658d69c1dcddb380b9afc2456d467a3494be" + integrity sha512-zZhCfJv/hkmud2qhWqpU3K9XVAuy3+IV8Tp9BC5J5U+GyA2XwoB6h8lh9GqpEIqdXOw01WyWQllV7dOWVyAlXg== + dependencies: + fastify-static-deprecated "npm:fastify-static@4.6.1" + process-warning "^1.0.0" + +fastify-swagger@^4.12.6: + version "4.17.1" + resolved "https://registry.npmjs.org/fastify-swagger/-/fastify-swagger-4.17.1.tgz" + integrity sha512-VUo8W7C+YIw/e+YbNTc15Nhl5xa9MpRMPFDKkRgwvgh0cn1mvGgT34sk77mlDclKwiEO471ayW+EFSL0OYXE1A== + dependencies: + fastify-plugin "^3.0.0" + fastify-static "^4.0.0" + js-yaml "^4.0.0" + json-schema-resolver "^1.3.0" + openapi-types "^10.0.0" + +fastify-websocket@^2.0.11: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fastify-websocket/-/fastify-websocket-2.1.0.tgz#3e0e83d09512e19d5084f0440d9767e289cf91c2" + integrity sha512-u5zClCarOHctvzKq76Gc0rDwtWfU7pw+JGYETfSu77YzZ/uzXLDX4jB70vLliUc3nqK0zXFRDK2/KnEnfdF9Kw== + dependencies: + fastify-plugin "^3.0.0" + find-my-way "^3.0.5" + ws "^7.4.2" + +fastify@^3.29.4: + version "3.29.4" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.29.4.tgz#294e33017b55f3cb72f315c41cf51431bc9b7a34" + integrity sha512-BEyKidZQvscNaiF1BLh+YLE7AzHH03NexhPzrwZP6KBQ+jG2czdgq72X+RFB5rK9hbqdaafVb5yiWN+hCvHfYg== + dependencies: + "@fastify/ajv-compiler" "^1.0.0" + "@fastify/error" "^2.0.0" + abstract-logging "^2.0.0" + avvio "^7.1.2" + content-type "^1.0.4" + fast-json-stringify "^2.5.2" + find-my-way "^4.5.0" + flatstr "^1.0.12" + light-my-request "^4.2.0" + pino "^6.13.0" + process-warning "^1.0.0" + proxy-addr "^2.0.7" + rfdc "^1.1.4" + secure-json-parse "^2.0.0" + semver "^7.3.2" + tiny-lru "^8.0.1" + +fastparallel@^2.2.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/fastparallel/-/fastparallel-2.4.1.tgz#0d984a5813ffa67f30b4a5cb4cb8cbe61c7ee5a5" + integrity sha512-qUmhxPgNHmvRjZKBFUNI0oZuuH9OlSIOXmJ98lhKPxMZZ7zS/Fi0wRHOihDSz0R1YiIOjxzOY4bq65YTcdBi2Q== + dependencies: + reusify "^1.0.4" + xtend "^4.0.2" + +fastq@^1.3.0, fastq@^1.6.0, fastq@^1.6.1: + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + +fastseries@^1.7.0: + version "1.7.2" + resolved "https://registry.npmjs.org/fastseries/-/fastseries-1.7.2.tgz" + integrity sha512-dTPFrPGS8SNSzAt7u/CbMKCJ3s01N04s4JFbORHcmyvVfVKmbhMD1VtRbh5enGHxkaQDqWyLefiKOGGmohGDDQ== + dependencies: + reusify "^1.0.0" + xtend "^4.0.0" + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +file-type@^7.6.0: + version "7.7.1" + resolved "https://registry.npmjs.org/file-type/-/file-type-7.7.1.tgz" + integrity sha512-bTrKkzzZI6wH+NXhyD3SOXtb2zXTw2SbwI2RxUlRcXVsnN7jNL5hJzVQLYv7FOQhxFkK4XWdAflEaWFpaLLWpQ== + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz" + integrity sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ== + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-my-way@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-3.0.5.tgz#f71c5ef1b4865401e1b97ba428121a8f55439eec" + integrity sha512-FweGg0cv1sBX8z7WhvBX5B5AECW4Zdh/NiB38Oa0qwSNIyPgRBCl/YjxuZn/rz38E/MMBHeVKJ22i7W3c626Gg== + dependencies: + fast-decode-uri-component "^1.0.1" + safe-regex2 "^2.0.0" + semver-store "^0.3.0" + +find-my-way@^4.5.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-4.5.1.tgz#758e959194b90aea0270db18fff75e2fceb2239f" + integrity sha512-kE0u7sGoUFbMXcOG/xpkmz4sRLCklERnBcg7Ftuu1iAxsfEt2S46RLJ3Sq7vshsEy2wJT2hZxE58XZK27qa8kg== + dependencies: + fast-decode-uri-component "^1.0.1" + fast-deep-equal "^3.1.3" + safe-regex2 "^2.0.0" + semver-store "^0.3.0" + +find-my-way@^5.2.0: + version "5.6.0" + resolved "https://registry.npmjs.org/find-my-way/-/find-my-way-5.6.0.tgz" + integrity sha512-pFTzbl2u+iSrvVOGtfKenvDmNIhNtEcwbzvRMfx3TGO69fbO5udgTKtAZAaUfIUrHQWLkkWvhNafNz179kaCIw== + dependencies: + fast-decode-uri-component "^1.0.1" + fast-deep-equal "^3.1.3" + safe-regex2 "^2.0.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatstr@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/flatstr/-/flatstr-1.0.12.tgz#c2ba6a08173edbb6c9640e3055b95e287ceb5931" + integrity sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw== + +flatted@^3.1.0: + version "3.2.6" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz" + integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ== + +fluent-ffmpeg@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz" + integrity sha512-IZTB4kq5GK0DPp7sGQ0q/BWurGHffRtQQwVkiqDgeO6wYJLLV5ZhgNOQ65loZxxuPMKZKZcICCUnaGtlxBiR0Q== + dependencies: + async ">=0.2.9" + which "^1.1.1" + +fold-to-ascii@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/fold-to-ascii/-/fold-to-ascii-5.0.1.tgz#d0b4f06e7b511e959bd502fa49e8e3678b9fc6cc" + integrity sha512-VdMFm+u7pSzUWj0IDOniuHekp4lbMOtwKi6EsVx03DGVQaNI+77kxotj8hYaMmNkpym7wwv6c1woY4OZXYdqfg== + +follow-redirects@1.5.10: + version "1.5.10" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz" + integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== + dependencies: + debug "=3.1.0" + +follow-redirects@^1.14.0, follow-redirects@^1.14.4: + version "1.15.1" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz" + integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz" + integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ== + +form-auto-content@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/form-auto-content/-/form-auto-content-2.2.0.tgz#8ab8d26d6315e9d592e3876053d8da5d1da4a8b1" + integrity sha512-OT4qi6hNGc+fJJGieTjy+WmV1nDhg4ULATNR0Fx92YUIy9gPw8odX3z8c+IiivWITzTg8j4TcKKbsAku8l2dwQ== + dependencies: + form-data "^3.0.0" + +form-data@^2.3.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" + integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +formidable@^1.2.0: + version "1.2.6" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.6.tgz#d2a51d60162bbc9b4a055d8457a7c75315d1a168" + integrity sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ== + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +forwarded@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz" + integrity sha512-Ua9xNhH0b8pwE3yRbFfXJvfdWF0UHNCdeyb2sbi9Ul/M+r3PTdrz7Cv4SCfZRMjmzEM9PhraqfZFbGTIg3OMyA== + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz" + integrity sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA== + dependencies: + map-cache "^0.2.2" + +free-email-domains@1.0.26: + version "1.0.26" + resolved "https://registry.yarnpkg.com/free-email-domains/-/free-email-domains-1.0.26.tgz#ecc48c11890298940e3535024774ec43a42c59af" + integrity sha512-nEMSDa99ccSIb78AZr7OIzFk0Np/wsN/wZuXSVi1jzutDJ250tLy6ZU0hCf5wuCT03B7K+Gi+pxCkUwGfpnP/w== + dependencies: + got "~11.8.5" + json-future "~2.2.13" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +from@~0: + version "0.1.7" + resolved "https://registry.npmjs.org/from/-/from-0.1.7.tgz" + integrity sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g== + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + +fs-extra@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^2.1.2, fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +function.prototype.name@^1.1.5: + version "1.1.5" + resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + +functions-have-names@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +gauge@^3.0.0: + version "3.0.2" + resolved "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz" + integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" + console-control-strings "^1.0.0" + has-unicode "^2.0.1" + object-assign "^4.1.1" + signal-exit "^3.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.2" + +generate-password@^1.6.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/generate-password/-/generate-password-1.7.0.tgz#00ba4eb1e71f89a72307b0d6604ee0d4e7f5770c" + integrity sha512-WPCtlfy0jexf7W5IbwxGUgpIDvsZIohbI2DAq2Q6TSlKKis+G4GT9sxvPxrZUGL8kP6WUXMWNqYnxY6DDKAdFA== + +generic-pool@3.8.2: + version "3.8.2" + resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.8.2.tgz#aab4f280adb522fdfbdc5e5b64d718d3683f04e9" + integrity sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.1, get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-func-name@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz" + integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.2" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz" + integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stdin@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" + integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== + +get-stream@^4.0.0, get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-stream@^5.0.0, get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz" + integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== + +get-website-favicon@^0.0.7: + version "0.0.7" + resolved "https://registry.npmjs.org/get-website-favicon/-/get-website-favicon-0.0.7.tgz" + integrity sha512-FD452CzghMhdMytp09Ax5R/IAi6835DcFsbF/kXNDa5Aep+aVN+c2kmy5wDTLPtY2Tnlh4eq1j6GgXtUGK3gYQ== + dependencies: + axios "^0.18.0" + cheerio "^1.0.0-rc.2" + file-type "^7.6.0" + +github-from-package@0.0.0: + version "0.0.0" + resolved "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz" + integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-dirs@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d" + integrity sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ== + dependencies: + ini "1.3.7" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.6.0, globals@^13.9.0: + version "13.15.0" + resolved "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz" + integrity sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog== + dependencies: + type-fest "^0.20.2" + +globby@^11.0.3, globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +globby@^13.1.1: + version "13.1.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-13.1.2.tgz#29047105582427ab6eca4f905200667b056da515" + integrity sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ== + dependencies: + dir-glob "^3.0.1" + fast-glob "^3.2.11" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^4.0.0" + +gm@^1.23.1: + version "1.23.1" + resolved "https://registry.npmjs.org/gm/-/gm-1.23.1.tgz" + integrity sha512-wYGVAa8/sh9ggF5qWoOs6eArcAgwEPkDNvf637jHRHkMUznvs7m/Q2vrc0KLN6B8px3nnRJqJcXK4mTK6lLFmg== + dependencies: + array-parallel "~0.1.3" + array-series "~0.1.5" + cross-spawn "^4.0.0" + debug "^3.1.0" + +got@^9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + +got@~11.8.5: + version "11.8.6" + resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" + integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== + dependencies: + "@sindresorhus/is" "^4.0.0" + "@szmarczak/http-timer" "^4.0.5" + "@types/cacheable-request" "^6.0.1" + "@types/responselike" "^1.0.0" + cacheable-lookup "^5.0.3" + cacheable-request "^7.0.2" + decompress-response "^6.0.0" + http2-wrapper "^1.0.0-beta.5.2" + lowercase-keys "^2.0.0" + p-cancelable "^2.0.0" + responselike "^2.0.0" + +graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: + version "4.2.10" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +growly@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz" + integrity sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw== + +hard-rejection@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" + integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-cors@1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz" + integrity sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + +has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has-unicode@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz" + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz" + integrity sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q== + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz" + integrity sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw== + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz" + integrity sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ== + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz" + integrity sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ== + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has-yarn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" + integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +he@1.2.0, he@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +hexoid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18" + integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g== + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hosted-git-info@^2.1.4: + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== + +hosted-git-info@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" + integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== + dependencies: + lru-cache "^6.0.0" + +hpagent@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/hpagent/-/hpagent-0.1.2.tgz#cab39c66d4df2d4377dbd212295d878deb9bdaa9" + integrity sha512-ePqFXHtSQWAFXYmj+JtOTHr84iNrII4/QRlAAPPE+zqnKy4xJo7Ie1Y4kC7AdB+LxLxSTTzBMASsEcy0q8YyvQ== + +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== + dependencies: + whatwg-encoding "^1.0.5" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +html-metadata-parser@^2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/html-metadata-parser/-/html-metadata-parser-2.0.4.tgz" + integrity sha512-pBjST/bbe3nuy/fNmvyY4G+ypukQ/QHiGc+YnS4up2OVnT4vI0CZA4x2J0Ri77sQkQGH2IMAAug0fE78FfDrLw== + dependencies: + axios "^0.24.0" + node-html-parser "^5.2.0" + +html-to-text@^8.2.1: + version "8.2.1" + resolved "https://registry.yarnpkg.com/html-to-text/-/html-to-text-8.2.1.tgz#4a75b8a1b646149bd71c50527adb568990bf459b" + integrity sha512-aN/3JvAk8qFsWVeE9InWAWueLXrbkoVZy0TkzaGhoRBC2gCFEeRLDDJN3/ijIGHohy6H+SZzUQWN/hcYtaPK8w== + dependencies: + "@selderee/plugin-htmlparser2" "^0.6.0" + deepmerge "^4.2.2" + he "^1.2.0" + htmlparser2 "^6.1.0" + minimist "^1.2.6" + selderee "^0.6.0" + +htmlparser2@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" + integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.0.0" + domutils "^2.5.2" + entities "^2.0.0" + +htmlparser2@^8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz" + integrity sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + domutils "^3.0.1" + entities "^4.3.0" + +http-cache-semantics@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" + integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== + +http-errors@1.8.1, http-errors@^1.7.3, http-errors@^1.8.0: + version "1.8.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" + integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.1" + +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + +http2-wrapper@^1.0.0-beta.5.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" + integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.0.0" + +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +human-signals@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== + +iconv-lite@0.4.24, iconv-lite@^0.4.4: + version "0.4.24" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore-by-default@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz" + integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA== + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-lazy@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz" + integrity sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A== + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-5.0.0.tgz#4fd2980fccaf8622d14c64d694f4cf33c81951a5" + integrity sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" + integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== + +ini@~1.3.0: + version "1.3.8" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + +ip@^1.1.5: + version "1.1.8" + resolved "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz" + integrity sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +ipaddr.js@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz" + integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz" + integrity sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A== + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-buffer@^1.1.5, is-buffer@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-buffer@^2.0.2: + version "2.0.5" + resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz" + integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== + +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-core-module@^2.5.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed" + integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== + dependencies: + has "^1.0.3" + +is-core-module@^2.9.0: + version "2.9.0" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz" + integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== + dependencies: + has "^1.0.3" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz" + integrity sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg== + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz" + integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw== + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-generator-function@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-installed-globally@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" + integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g== + dependencies: + global-dirs "^2.0.1" + is-path-inside "^3.0.1" + +is-interactive@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" + integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== + +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-npm@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" + integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz" + integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg== + dependencies: + kind-of "^3.0.2" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-path-inside@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-plain-obj@^1.1, is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== + +is-plain-obj@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + +is-promise@~1, is-promise@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-1.0.1.tgz#31573761c057e33c2e91aab9e96da08cefbe76e5" + integrity sha512-mjWH5XxnhMA8cFnDchr6qRP9S/kLntKuEfIYku+PaN1CnS8v+OG9O/BKpRCVRJvpIkgAZm0Pf5Is3iSSOILlcg== + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-retry-allowed@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" + integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz" + integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.3, is-typed-array@^1.1.9: + version "1.1.9" + resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz" + integrity sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-abstract "^1.20.0" + for-each "^0.3.3" + has-tostringtag "^1.0.0" + +is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +is-yarn-global@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" + integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" + integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz" + integrity sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA== + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-instrument@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" + integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== + dependencies: + "@babel/core" "^7.7.5" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.0.0" + semver "^6.3.0" + +istanbul-lib-instrument@^5.0.4: + version "5.2.0" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz" + integrity sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.0.2: + version "3.1.4" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz" + integrity sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +iterate-object@^1.3.0, iterate-object@^1.3.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/iterate-object/-/iterate-object-1.3.4.tgz#fa50b1d9e58e340a7dd6b4c98c8a5e182e790096" + integrity sha512-4dG1D1x/7g8PwHS9aK6QV5V94+ZvyP4+d19qDv43EzImmrndysIl4prmJ1hWWIGCqrZHyaHBm6BSEWHOLnpoNw== + +jest-changed-files@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" + integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== + dependencies: + "@jest/types" "^26.6.2" + execa "^4.0.0" + throat "^5.0.0" + +jest-cli@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" + integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== + dependencies: + "@jest/core" "^26.6.3" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.4" + import-local "^3.0.2" + is-ci "^2.0.0" + jest-config "^26.6.3" + jest-util "^26.6.2" + jest-validate "^26.6.2" + prompts "^2.0.1" + yargs "^15.4.1" + +jest-config@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" + integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== + dependencies: + "@babel/core" "^7.1.0" + "@jest/test-sequencer" "^26.6.3" + "@jest/types" "^26.6.2" + babel-jest "^26.6.3" + chalk "^4.0.0" + deepmerge "^4.2.2" + glob "^7.1.1" + graceful-fs "^4.2.4" + jest-environment-jsdom "^26.6.2" + jest-environment-node "^26.6.2" + jest-get-type "^26.3.0" + jest-jasmine2 "^26.6.3" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + micromatch "^4.0.2" + pretty-format "^26.6.2" + +jest-diff@^26.0.0, jest-diff@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" + integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== + dependencies: + chalk "^4.0.0" + diff-sequences "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + +jest-docblock@^26.0.0: + version "26.0.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" + integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== + dependencies: + detect-newline "^3.0.0" + +jest-each@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.6.2.tgz#02526438a77a67401c8a6382dfe5999952c167cb" + integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== + dependencies: + "@jest/types" "^26.6.2" + chalk "^4.0.0" + jest-get-type "^26.3.0" + jest-util "^26.6.2" + pretty-format "^26.6.2" + +jest-environment-jsdom@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" + integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + jest-util "^26.6.2" + jsdom "^16.4.0" + +jest-environment-node@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.6.2.tgz#824e4c7fb4944646356f11ac75b229b0035f2b0c" + integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + jest-util "^26.6.2" + +jest-get-type@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" + integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== + +jest-haste-map@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" + integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== + dependencies: + "@jest/types" "^26.6.2" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.4" + jest-regex-util "^26.0.0" + jest-serializer "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" + micromatch "^4.0.2" + sane "^4.0.3" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.1.2" + +jest-jasmine2@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" + integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== + dependencies: + "@babel/traverse" "^7.1.0" + "@jest/environment" "^26.6.2" + "@jest/source-map" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + expect "^26.6.2" + is-generator-fn "^2.0.0" + jest-each "^26.6.2" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-runtime "^26.6.3" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + pretty-format "^26.6.2" + throat "^5.0.0" + +jest-leak-detector@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" + integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== + dependencies: + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + +jest-matcher-utils@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" + integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw== + dependencies: + chalk "^4.0.0" + jest-diff "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + +jest-message-util@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" + integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA== + dependencies: + "@babel/code-frame" "^7.0.0" + "@jest/types" "^26.6.2" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + micromatch "^4.0.2" + pretty-format "^26.6.2" + slash "^3.0.0" + stack-utils "^2.0.2" + +jest-mock@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" + integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== + +jest-regex-util@^26.0.0: + version "26.0.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" + integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== + +jest-resolve-dependencies@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz#6680859ee5d22ee5dcd961fe4871f59f4c784fb6" + integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== + dependencies: + "@jest/types" "^26.6.2" + jest-regex-util "^26.0.0" + jest-snapshot "^26.6.2" + +jest-resolve@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" + integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ== + dependencies: + "@jest/types" "^26.6.2" + chalk "^4.0.0" + graceful-fs "^4.2.4" + jest-pnp-resolver "^1.2.2" + jest-util "^26.6.2" + read-pkg-up "^7.0.1" + resolve "^1.18.1" + slash "^3.0.0" + +jest-runner@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.6.3.tgz#2d1fed3d46e10f233fd1dbd3bfaa3fe8924be159" + integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== + dependencies: + "@jest/console" "^26.6.2" + "@jest/environment" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.7.1" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-config "^26.6.3" + jest-docblock "^26.0.0" + jest-haste-map "^26.6.2" + jest-leak-detector "^26.6.2" + jest-message-util "^26.6.2" + jest-resolve "^26.6.2" + jest-runtime "^26.6.3" + jest-util "^26.6.2" + jest-worker "^26.6.2" + source-map-support "^0.5.6" + throat "^5.0.0" + +jest-runtime@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" + integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== + dependencies: + "@jest/console" "^26.6.2" + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/globals" "^26.6.2" + "@jest/source-map" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + cjs-module-lexer "^0.6.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.4" + jest-config "^26.6.3" + jest-haste-map "^26.6.2" + jest-message-util "^26.6.2" + jest-mock "^26.6.2" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + slash "^3.0.0" + strip-bom "^4.0.0" + yargs "^15.4.1" + +jest-serializer@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" + integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.4" + +jest-snapshot@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" + integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== + dependencies: + "@babel/types" "^7.0.0" + "@jest/types" "^26.6.2" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.0.0" + chalk "^4.0.0" + expect "^26.6.2" + graceful-fs "^4.2.4" + jest-diff "^26.6.2" + jest-get-type "^26.3.0" + jest-haste-map "^26.6.2" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-resolve "^26.6.2" + natural-compare "^1.4.0" + pretty-format "^26.6.2" + semver "^7.3.2" + +jest-util@^26.1.0, jest-util@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" + integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + graceful-fs "^4.2.4" + is-ci "^2.0.0" + micromatch "^4.0.2" + +jest-validate@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" + integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== + dependencies: + "@jest/types" "^26.6.2" + camelcase "^6.0.0" + chalk "^4.0.0" + jest-get-type "^26.3.0" + leven "^3.1.0" + pretty-format "^26.6.2" + +jest-watcher@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975" + integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== + dependencies: + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^26.6.2" + string-length "^4.0.1" + +jest-worker@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^7.0.0" + +jest@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef" + integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q== + dependencies: + "@jest/core" "^26.6.3" + import-local "^3.0.2" + jest-cli "^26.6.3" + +jmespath@^0.15.0: + version "0.15.0" + resolved "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz" + integrity sha512-+kHj8HXArPfpPEKGLZ+kB5ONRTCiGQXo8RQYL0hH8t6pWXUBBK5KkkQmTNOwKK4LEsd0yTsgtjJVm4UBSZea4w== + +join-component@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/join-component/-/join-component-1.1.0.tgz" + integrity sha512-bF7vcQxbODoGK1imE2P9GS9aw4zD0Sd+Hni68IMZLj7zRnquH7dXUmMw9hDI5S/Jzt7q+IyTXN0rSg2GI0IKhQ== + +joycon@^2.2.5: + version "2.2.5" + resolved "https://registry.yarnpkg.com/joycon/-/joycon-2.2.5.tgz#8d4cf4cbb2544d7b7583c216fcdfec19f6be1615" + integrity sha512-YqvUxoOcVPnCp0VU1/56f+iKSdvIRJYPznH22BdXV3xMk75SFXhWeJkZ8C9XxUWt1b5x2X1SxuFygW1U0FmkEQ== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsdom@^16.4.0: + version "16.7.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.6" + xml-name-validator "^3.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz" + integrity sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-future@~2.2.13: + version "2.2.18" + resolved "https://registry.yarnpkg.com/json-future/-/json-future-2.2.18.tgz#f93d1d42062430162c9f12e8558c4cb9c604a271" + integrity sha512-o0tlS8WYaiUq65480fv7Rn4inT+KN+cmnXXFMa8NGvyY2drgQGcuQY08bPym1ms+mWT7fZ41F5zFW2LNRD5DAw== + dependencies: + args-js "~0.10.12" + async "~3.2.0" + cb2promise "~1.1.1" + fast-safe-stringify "~2.1.0" + load-json-file "~6.2.0" + nodeify "~1.0.1" + parse-json "~5.2.0" + sliced "~1.0.1" + write-json-file "~4.3.0" + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-resolver@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/json-schema-resolver/-/json-schema-resolver-1.3.0.tgz#0840864b06780363d31fb03cdfae5047e2f81fbb" + integrity sha512-EX7W1r8aZ/T3j8GbbBxPXi60bnsELfT90OiA1QrbGMvwzVSbyMNOAzvMFcFb8m7gKCXZLJpGe+cJOvWgoFl29A== + dependencies: + debug "^4.1.1" + rfdc "^1.1.4" + uri-js "^4.2.2" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/json-stream/-/json-stream-1.0.0.tgz" + integrity sha512-H/ZGY0nIAg3QcOwE1QN/rK/Fa7gJn7Ii5obwp6zyPO4xiPNwpIMjqy2gwjBEGqzkF/vSWEIBQCBuN19hYiL6Qg== + +json-stringify-safe@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + +json5@2.x, json5@^2.1.1, json5@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonwebtoken@^8.5.1: + version "8.5.1" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" + integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^5.6.0" + +junk@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/junk/-/junk-4.0.0.tgz#9b1104ddf5281cd24ffa3c8a7443d19ce192b37f" + integrity sha512-ojtSU++zLJ3jQG9bAYjg94w+/DOJtRyD7nPaerMFrBhmdVmiV5/exYH5t4uHga4G/95nT6hr1OJoKIFbYbrW5w== + +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + +keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== + dependencies: + json-buffer "3.0.0" + +keyv@^4.0.0, keyv@^4.5.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.2.tgz#0e310ce73bf7851ec702f2eaf46ec4e3805cce56" + integrity sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g== + dependencies: + json-buffer "3.0.1" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" + integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz" + integrity sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw== + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +latest-version@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" + integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== + dependencies: + package-json "^6.3.0" + +lazystream@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" + integrity sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw== + dependencies: + readable-stream "^2.0.5" + +leven@2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz" + integrity sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" + integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +light-my-request@^4.2.0: + version "4.10.1" + resolved "https://registry.npmjs.org/light-my-request/-/light-my-request-4.10.1.tgz" + integrity sha512-l+zWk0HXGhGzY7IYTZnYEqIpj3Mpcyk2f8+FkKUyREywvaiWCf2jyQVxpasKRsploY/nVpoqTlxx72CIeQNcIQ== + dependencies: + ajv "^8.1.0" + cookie "^0.5.0" + process-warning "^1.0.0" + set-cookie-parser "^2.4.1" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +load-json-file@~6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-6.2.0.tgz#5c7770b42cafa97074ca2848707c61662f4251a1" + integrity sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ== + dependencies: + graceful-fs "^4.1.15" + parse-json "^5.0.0" + strip-bom "^4.0.0" + type-fest "^0.6.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== + +lodash.difference@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" + integrity sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA== + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz" + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== + +lodash.union@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + integrity sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw== + +lodash@4.x, lodash@^4.17.21, lodash@^4.7.0: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +long@^2.2.0: + version "2.4.0" + resolved "https://registry.npmjs.org/long/-/long-2.4.0.tgz" + integrity sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ== + +loupe@^2.3.1: + version "2.3.4" + resolved "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz" + integrity sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ== + dependencies: + get-func-name "^2.0.0" + +lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +lru_map@^0.3.3: + version "0.3.3" + resolved "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz" + integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ== + +make-dir@^3.0.0, make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +make-error@1.x, make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz" + integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== + +map-o@^2.0.1: + version "2.0.10" + resolved "https://registry.yarnpkg.com/map-o/-/map-o-2.0.10.tgz#b656a75cead939a936c338fb5df8c9d55f0dbb23" + integrity sha512-BxazE81fVByHWasyXhqKeo2m7bFKYu+ZbEfiuexMOnklXW+tzDvnlTi/JaklEeuuwqcqJzPaf9q+TWptSGXeLg== + dependencies: + iterate-object "^1.3.0" + +map-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + integrity sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg== + +map-obj@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" + integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== + +map-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz" + integrity sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g== + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz" + integrity sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w== + dependencies: + object-visit "^1.0.0" + +match-all@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/match-all/-/match-all-1.2.6.tgz#66d276ad6b49655551e63d3a6ee53e8be0566f8d" + integrity sha512-0EESkXiTkWzrQQntBu2uzKvLu6vVkUGz40nGPbSZuegcfE5UuSzNjLaIu76zJWuaT/2I3Z/8M06OlUOZLGwLlQ== + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +md5@^2.2.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== + dependencies: + charenc "0.0.2" + crypt "0.0.2" + is-buffer "~1.1.6" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +memory-pager@^1.0.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" + integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== + +meow@^10.1.2: + version "10.1.3" + resolved "https://registry.yarnpkg.com/meow/-/meow-10.1.3.tgz#21689959a7d00e8901aff30d208acb2122eb8088" + integrity sha512-0WL7RMCPPdUTE00+GxJjL4d5Dm6eUbmAzxlzywJWiRUKCW093owmZ7/q74tH9VI91vxw9KJJNxAcvdpxb2G4iA== + dependencies: + "@types/minimist" "^1.2.2" + camelcase-keys "^7.0.0" + decamelize "^5.0.0" + decamelize-keys "^1.1.0" + hard-rejection "^2.1.0" + minimist-options "4.1.0" + normalize-package-data "^3.0.2" + read-pkg-up "^8.0.0" + redent "^4.0.0" + trim-newlines "^4.0.2" + type-fest "^1.2.2" + yargs-parser "^20.2.9" + +merge-options@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-options/-/merge-options-1.0.1.tgz#2a64b24457becd4e4dc608283247e94ce589aa32" + integrity sha512-iuPV41VWKWBIOpBsjoxjDZw8/GbSfZ2mk7N1453bwMrfzdrIk7EzBd+8UVR6rkw67th7xnk9Dytl3J+lHPdxvg== + dependencies: + is-plain-obj "^1.1" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@^1.1.1, methods@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12, mime-types@^2.1.14, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0, mime@^1.4.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.4.0: + version "2.6.0" + resolved "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-fn@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.0.0.tgz#0913ff0b121db44ef5848242c38bbb35d44cabde" + integrity sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA== + +mimic-response@^1.0.0, mimic-response@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + +min-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.1.0: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimist-options@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" + integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== + dependencies: + arrify "^1.0.1" + is-plain-obj "^1.1.0" + kind-of "^6.0.3" + +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + +minio@^7.0.18: + version "7.0.28" + resolved "https://registry.npmjs.org/minio/-/minio-7.0.28.tgz" + integrity sha512-4Oua0R73oCxxmxhh2NiXDJo4Md159I/mdG8ybu6351leMQoB2Sy8S4HmgG6CxuPlEJ0h9M8/WyaI2CARDeeDTQ== + dependencies: + async "^3.1.0" + block-stream2 "^2.0.0" + browser-or-node "^1.3.0" + buffer-crc32 "^0.2.13" + crypto-browserify "^3.12.0" + es6-error "^4.1.1" + fast-xml-parser "^3.17.5" + ipaddr.js "^2.0.1" + json-stream "^1.0.0" + lodash "^4.17.21" + mime-types "^2.1.14" + mkdirp "^0.5.1" + querystring "0.2.0" + through2 "^3.0.1" + web-encoding "^1.1.5" + xml "^1.0.0" + xml2js "^0.4.15" + +minipass@^3.0.0: + version "3.3.4" + resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz" + integrity sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw== + dependencies: + yallist "^4.0.0" + +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + +mkdirp@1.x, mkdirp@^1.0.3, mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +mkdirp@^0.5.1: + version "0.5.6" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +moment@^2.29.4: + version "2.29.4" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" + integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== + +mongodb-connection-string-url@^2.5.2: + version "2.5.2" + resolved "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.2.tgz" + integrity sha512-tWDyIG8cQlI5k3skB6ywaEA5F9f5OntrKKsT/Lteub2zgwSUlhqEN2inGgBTm8bpYJf8QYBdA/5naz65XDpczA== + dependencies: + "@types/whatwg-url" "^8.2.1" + whatwg-url "^11.0.0" + +mongodb@*, mongodb@^4.1.0: + version "4.7.0" + resolved "https://registry.npmjs.org/mongodb/-/mongodb-4.7.0.tgz" + integrity sha512-HhVar6hsUeMAVlIbwQwWtV36iyjKd9qdhY+s4wcU8K6TOj4Q331iiMy+FoPuxEntDIijTYWivwFJkLv8q/ZgvA== + dependencies: + bson "^4.6.3" + denque "^2.0.1" + mongodb-connection-string-url "^2.5.2" + socks "^2.6.2" + optionalDependencies: + saslprep "^1.0.3" + +moo@^0.5.0, moo@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.1.tgz#7aae7f384b9b09f620b6abf6f74ebbcd1b65dbc4" + integrity sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w== + +mri@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" + integrity sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multistream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/multistream/-/multistream-4.1.0.tgz#7bf00dfd119556fbc153cff3de4c6d477909f5a8" + integrity sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw== + dependencies: + once "^1.4.0" + readable-stream "^3.6.0" + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +napi-build-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" + integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== + +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +nearley@^2.20.1: + version "2.20.1" + resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.20.1.tgz#246cd33eff0d012faf197ff6774d7ac78acdd474" + integrity sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ== + dependencies: + commander "^2.19.0" + moo "^0.5.0" + railroad-diagrams "^1.0.0" + randexp "0.4.6" + +needle@^2.5.2: + version "2.9.1" + resolved "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz" + integrity sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz#26c8a3cee6cc05fbcf1e333cd2fc3e003326c0b5" + integrity sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-abi@^3.3.0: + version "3.22.0" + resolved "https://registry.npmjs.org/node-abi/-/node-abi-3.22.0.tgz" + integrity sha512-u4uAs/4Zzmp/jjsD9cyFYDXeISfUWaAVWshPmDZOFOv4Xl4SbzTXm53I04C2uRueYJ+0t5PEtLH/owbn2Npf/w== + dependencies: + semver "^7.3.5" + +node-addon-api@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== + +node-addon-api@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz" + integrity sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA== + +node-cache@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/node-cache/-/node-cache-5.1.2.tgz#f264dc2ccad0a780e76253a694e9fd0ed19c398d" + integrity sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg== + dependencies: + clone "2.x" + +node-cleanup@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz" + integrity sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw== + +node-cron@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/node-cron/-/node-cron-3.0.1.tgz" + integrity sha512-RAWZTNn2M5KDIUV/389UX0EXsqvdFAwc9QwHQceh0Ga56dygqSRthqIjwpgZsoDspHGt2rkHdk9Z4RgfPMdALw== + +node-fetch@^2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + +node-html-parser@^5.2.0: + version "5.3.3" + resolved "https://registry.npmjs.org/node-html-parser/-/node-html-parser-5.3.3.tgz" + integrity sha512-ncg1033CaX9UexbyA7e1N0aAoAYRDiV8jkTvzEnfd1GDvzFdrsXLzR4p4ik8mwLgnaKP/jyUFWDy9q3jvRT2Jw== + dependencies: + css-select "^4.2.1" + he "1.2.0" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-notifier@^8.0.0: + version "8.0.2" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.2.tgz#f3167a38ef0d2c8a866a83e318c1ba0efeb702c5" + integrity sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg== + dependencies: + growly "^1.3.0" + is-wsl "^2.2.0" + semver "^7.3.2" + shellwords "^0.1.1" + uuid "^8.3.0" + which "^2.0.2" + +node-releases@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz" + integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q== + +node-uuid@^1.4.8: + version "1.4.8" + resolved "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz" + integrity sha512-TkCET/3rr9mUuRp+CpO7qfgT++aAxfDRaalQhwPFzI9BY/2rCDn6OfpZOVggi1AXfTPpfkTrg5f5WQx5G1uLxA== + +nodeify@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/nodeify/-/nodeify-1.0.1.tgz#64ab69a7bdbaf03ce107b4f0335c87c0b9e91b1d" + integrity sha512-n7C2NyEze8GCo/z73KdbjRsBiLbv6eBn1FxwYKQ23IqGo7pQY3mhQan61Sv7eEDJCiyUjTVrVkXTzJCo1dW7Aw== + dependencies: + is-promise "~1.0.0" + promise "~1.3.0" + +nodemon@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.4.tgz#55b09319eb488d6394aa9818148c0c2d1c04c416" + integrity sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ== + dependencies: + chokidar "^3.2.2" + debug "^3.2.6" + ignore-by-default "^1.0.1" + minimatch "^3.0.4" + pstree.remy "^1.1.7" + semver "^5.7.1" + supports-color "^5.5.0" + touch "^3.1.0" + undefsafe "^2.0.2" + update-notifier "^4.0.0" + +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + +nopt@~1.0.10: + version "1.0.10" + resolved "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz" + integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg== + dependencies: + abbrev "1" + +normalize-package-data@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-package-data@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" + integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== + dependencies: + hosted-git-info "^4.0.1" + is-core-module "^2.5.0" + semver "^7.3.4" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz" + integrity sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w== + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-url@^4.1.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" + integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== + +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + +notepack.io@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/notepack.io/-/notepack.io-2.2.0.tgz#d7ea71d1cb90094f88c6f3c8d84277c2d0cd101c" + integrity sha512-9b5w3t5VSH6ZPosoYnyDONnUTF8o0UkBw7JLA6eBlYJWyGT1Q3vQa8Hmuj1/X6RYvHjjygBDgw6fJhe0JEojfw== + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz" + integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw== + dependencies: + path-key "^2.0.0" + +npm-run-path@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +npmlog@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== + dependencies: + are-we-there-yet "^2.0.0" + console-control-strings "^1.1.0" + gauge "^3.0.0" + set-blocking "^2.0.0" + +nth-check@^2.0.1: + version "2.1.1" + resolved "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz" + integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== + dependencies: + boolbase "^1.0.0" + +nwsapi@^2.2.0: + version "2.2.1" + resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.1.tgz" + integrity sha512-JYOWTeFoS0Z93587vRJgASD5Ut11fYl5NyihP3KrYBvMe1FRRs6RN7m20SA/16GM4P6hTnZjT+UmDOt38UeXNg== + +object-assign@^4, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz" + integrity sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ== + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.12.0, object-inspect@^1.9.0: + version "1.12.2" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz" + integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz" + integrity sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA== + dependencies: + isobject "^3.0.0" + +object.assign@^4.1.0, object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz" + integrity sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ== + dependencies: + isobject "^3.0.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz" + integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== + dependencies: + ee-first "1.1.1" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +openapi-types@^10.0.0: + version "10.0.0" + resolved "https://registry.npmjs.org/openapi-types/-/openapi-types-10.0.0.tgz" + integrity sha512-Y8xOCT2eiKGYDzMW9R4x5cmfc3vGaaI4EL2pwhDmodWw1HlK18YcZ4uJxc7Rdp7/gGzAygzH9SXr6GKYIXbRcQ== + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +ora@^5.4.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" + integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== + dependencies: + bl "^4.1.0" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + is-unicode-supported "^0.1.0" + log-symbols "^4.1.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + +p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + +p-cancelable@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" + integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== + +p-each-series@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" + integrity sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA== + +p-event@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/p-event/-/p-event-4.2.0.tgz#af4b049c8acd91ae81083ebd1e6f5cae2044c1b5" + integrity sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ== + dependencies: + p-timeout "^3.1.0" + +p-filter@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-filter/-/p-filter-3.0.0.tgz#ce50e03b24b23930e11679ab8694bd09a2d7ed35" + integrity sha512-QtoWLjXAW++uTX67HZQz1dbTpqBfiidsB6VtQUC9iR85S120+s0T5sO6s+B5MLzFcZkrEd/DGMmCjR+f2Qpxwg== + dependencies: + p-map "^5.1.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz" + integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2, p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-map@^5.1.0, p-map@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-5.5.0.tgz#054ca8ca778dfa4cf3f8db6638ccb5b937266715" + integrity sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg== + dependencies: + aggregate-error "^4.0.0" + +p-timeout@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" + integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== + dependencies: + p-finally "^1.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +package-json@^6.3.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" + integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== + dependencies: + got "^9.6.0" + registry-auth-token "^4.0.0" + registry-url "^5.0.0" + semver "^6.2.0" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-asn1@^5.0.0, parse-asn1@^5.1.5: + version "5.1.6" + resolved "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== + dependencies: + asn1.js "^5.2.0" + browserify-aes "^1.0.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-json@^5.0.0, parse-json@^5.2.0, parse-json@~5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse5-htmlparser2-tree-adapter@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz" + integrity sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g== + dependencies: + domhandler "^5.0.2" + parse5 "^7.0.0" + +parse5@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + +parse5@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz" + integrity sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g== + dependencies: + entities "^4.3.0" + +parseley@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/parseley/-/parseley-0.7.0.tgz#9949e3a0ed05c5072adb04f013c2810cf49171a8" + integrity sha512-xyOytsdDu077M3/46Am+2cGXEKM9U9QclBDv7fimY7e+BBlxh2JcBp2mgNsmkyA9uvgyTjVzDi7cP1v4hcFxbw== + dependencies: + moo "^0.5.1" + nearley "^2.20.1" + +parseqs@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.6.tgz#8e4bb5a19d1cdc844a08ac974d34e273afa670d5" + integrity sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w== + +parseuri@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.6.tgz#e1496e829e3ac2ff47f39a4dd044b32823c4a25a" + integrity sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow== + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz" + integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz" + integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pathval@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== + +pause-stream@0.0.11: + version "0.0.11" + resolved "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz" + integrity sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A== + dependencies: + through "~2.3" + +pbkdf2@^3.0.3: + version "3.1.2" + resolved "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +pdf2pic@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/pdf2pic/-/pdf2pic-2.1.4.tgz#5c6cbd7809a60b11f6504eb85c386aa2012b1dcf" + integrity sha512-8QOCvxZlYs7wsmBQbqpIApSWD/eqgXMQU+4VM0vWrXifLgXS+Ns3484sUa1Q7ddr+gwnruq/xKHzu7x1scqX6w== + dependencies: + fs-extra "^9.1.0" + gm "^1.23.1" + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pino-pretty@^4.7.1: + version "4.8.0" + resolved "https://registry.yarnpkg.com/pino-pretty/-/pino-pretty-4.8.0.tgz#f2f3055bf222456217b14ffb04d8be0a0cc17fce" + integrity sha512-mhQfHG4rw5ZFpWL44m0Utjo4GC2+HMfdNvxyA8lLw0sIqn6fCf7uQe6dPckUcW/obly+OQHD7B/MTso6LNizYw== + dependencies: + "@hapi/bourne" "^2.0.0" + args "^5.0.1" + chalk "^4.0.0" + dateformat "^4.5.1" + fast-safe-stringify "^2.0.7" + jmespath "^0.15.0" + joycon "^2.2.5" + pump "^3.0.0" + readable-stream "^3.6.0" + rfdc "^1.3.0" + split2 "^3.1.1" + strip-json-comments "^3.1.1" + +pino-std-serializers@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz#b56487c402d882eb96cd67c257868016b61ad671" + integrity sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg== + +pino@^6.13.0, pino@^6.8.0: + version "6.14.0" + resolved "https://registry.npmjs.org/pino/-/pino-6.14.0.tgz" + integrity sha512-iuhEDel3Z3hF9Jfe44DPXR8l07bhjuFY3GMHIXbjnY9XcafbyDDwl2sN2vw2GjMPf5Nkoe+OFao7ffn9SXaKDg== + dependencies: + fast-redact "^3.0.0" + fast-safe-stringify "^2.0.8" + flatstr "^1.0.12" + pino-std-serializers "^3.1.0" + process-warning "^1.0.0" + quick-format-unescaped "^4.0.3" + sonic-boom "^1.0.2" + +pirates@^4.0.1: + version "4.0.5" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz" + integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz" + integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== + +prebuild-install@^7.1.1: + version "7.1.1" + resolved "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz" + integrity sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw== + dependencies: + detect-libc "^2.0.0" + expand-template "^2.0.3" + github-from-package "0.0.0" + minimist "^1.2.3" + mkdirp-classic "^0.5.3" + napi-build-utils "^1.0.1" + node-abi "^3.3.0" + pump "^3.0.0" + rc "^1.2.7" + simple-get "^4.0.0" + tar-fs "^2.0.0" + tunnel-agent "^0.6.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" + integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz" + integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA== + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^2.1.2: + version "2.7.1" + resolved "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz" + integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== + +pretty-format@^26.0.0, pretty-format@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" + integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== + dependencies: + "@jest/types" "^26.6.2" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^17.0.1" + +probe-image-size@^7.2.3: + version "7.2.3" + resolved "https://registry.npmjs.org/probe-image-size/-/probe-image-size-7.2.3.tgz" + integrity sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w== + dependencies: + lodash.merge "^4.6.2" + needle "^2.5.2" + stream-parser "~0.3.1" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process-warning@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-1.0.0.tgz#980a0b25dc38cd6034181be4b7726d89066b4616" + integrity sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q== + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +promise-breaker@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/promise-breaker/-/promise-breaker-5.0.0.tgz#58e8541f1619554057da95a211794d7834d30c1d" + integrity sha512-mgsWQuG4kJ1dtO6e/QlNDLFtMkMzzecsC69aI5hlLEjGHFNpHrvGhFi4LiK5jg2SMQj74/diH+wZliL9LpGsyA== + +promise@~1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/promise/-/promise-1.3.0.tgz#e5cc9a4c8278e4664ffedc01c7da84842b040175" + integrity sha512-R9WrbTF3EPkVtWjp7B7umQGVndpsi+rsDAfrR4xAALQpFLa/+2OriecLhawxzvii2gd9+DZFwROWDuUUaqS5yA== + dependencies: + is-promise "~1" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +proxy-addr@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +ps-tree@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.2.0.tgz#5e7425b89508736cdd4f2224d028f7bb3f722ebd" + integrity sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA== + dependencies: + event-stream "=3.3.4" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz" + integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ== + +psl@^1.1.33: + version "1.9.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + +pstree.remy@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" + integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +pupa@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" + integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A== + dependencies: + escape-goat "^2.0.0" + +qs@^6.5.1: + version "6.11.0" + resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz" + integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +queue-microtask@^1.1.2, queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +quick-format-unescaped@^4.0.3: + version "4.0.4" + resolved "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz" + integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== + +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + +railroad-diagrams@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e" + integrity sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A== + +randexp@0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3" + integrity sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ== + dependencies: + discontinuous-range "1.0.0" + ret "~0.1.10" + +random-bytes@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" + integrity sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ== + +random-seed@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/random-seed/-/random-seed-0.3.0.tgz#d945f2e1f38f49e8d58913431b8bf6bb937556cd" + integrity sha512-y13xtn3kcTlLub3HKWXxJNeC2qK4mB59evwZ5EkeRlolx+Bp2ztF7LbcZmyCnOqlHQrLnfuNbi1sVmm9lPDlDA== + dependencies: + json-stringify-safe "^5.0.1" + +random-useragent@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/random-useragent/-/random-useragent-0.5.0.tgz#83a92dfdfb2366972d0a1f81fc93d5ef85807ae8" + integrity sha512-FUMkqVdZeoSff5tErNL3FFGYXElDWZ1bEuedhm5u9MdCFwANriJWbHvDRYrLTOzp/fBsBGu5J1cWtDgifa97aQ== + dependencies: + random-seed "^0.3.0" + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.1.0" + resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +rc@1.2.8, rc@^1.2.7, rc@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +read-pkg-up@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== + dependencies: + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" + +read-pkg-up@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-8.0.0.tgz#72f595b65e66110f43b052dd9af4de6b10534670" + integrity sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ== + dependencies: + find-up "^5.0.0" + read-pkg "^6.0.0" + type-fest "^1.0.1" + +read-pkg@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" + +read-pkg@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-6.0.0.tgz#a67a7d6a1c2b0c3cd6aa2ea521f40c458a4a504c" + integrity sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^3.0.2" + parse-json "^5.2.0" + type-fest "^1.0.1" + +"readable-stream@1.x >=1.1.9": + version "1.1.14" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz" + integrity sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +"readable-stream@2 || 3", readable-stream@^3.0.0, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.3.5: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readdir-glob@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.2.tgz#b185789b8e6a43491635b6953295c5c5e3fd224c" + integrity sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA== + dependencies: + minimatch "^5.1.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +redent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-4.0.0.tgz#0c0ba7caabb24257ab3bb7a4fd95dd1d5c5681f9" + integrity sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag== + dependencies: + indent-string "^5.0.0" + strip-indent "^4.0.0" + +redis-commands@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" + integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== + +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz" + integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w== + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz" + integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A== + dependencies: + redis-errors "^1.0.0" + +redis@*: + version "4.2.0" + resolved "https://registry.yarnpkg.com/redis/-/redis-4.2.0.tgz#1278a265b8aa1e096a585d103bdead027cd04e43" + integrity sha512-bCR0gKVhIXFg8zCQjXEANzgI01DDixtPZgIUZHBCmwqixnu+MK3Tb2yqGjh+HCLASQVVgApiwhNkv+FoedZOGQ== + dependencies: + "@redis/bloom" "1.0.2" + "@redis/client" "1.2.0" + "@redis/graph" "1.0.1" + "@redis/json" "1.0.3" + "@redis/search" "1.0.6" + "@redis/time-series" "1.0.3" + +redis@3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/redis/-/redis-3.1.2.tgz#766851117e80653d23e0ed536254677ab647638c" + integrity sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw== + dependencies: + denque "^1.5.0" + redis-commands "^1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + +reflect-metadata@^0.1.13: + version "0.1.13" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" + integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== + +regenerate-unicode-properties@^10.0.1: + version "10.0.1" + resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz" + integrity sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +regenerator-transform@^0.15.0: + version "0.15.0" + resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz" + integrity sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg== + dependencies: + "@babel/runtime" "^7.8.4" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexp.prototype.flags@^1.4.3: + version "1.4.3" + resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz" + integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + functions-have-names "^1.2.2" + +regexpp@^3.1.0, regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +regexpu-core@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.1.0.tgz" + integrity sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^10.0.1" + regjsgen "^0.6.0" + regjsparser "^0.8.2" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.0.0" + +registry-auth-token@^4.0.0: + version "4.2.2" + resolved "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz" + integrity sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg== + dependencies: + rc "1.2.8" + +registry-url@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" + integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== + dependencies: + rc "^1.2.8" + +regjsgen@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz" + integrity sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA== + +regjsparser@^0.8.2: + version "0.8.4" + resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz" + integrity sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA== + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz" + integrity sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw== + +remove-trailing-slash@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz#be2285a59f39c74d1bce4f825950061915e3780d" + integrity sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA== + +repeat-element@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz" + integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-alpn@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" + integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz" + integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg== + +resolve@^1.0.0, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.18.1: + version "1.22.1" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +responselike@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz" + integrity sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ== + dependencies: + lowercase-keys "^1.0.0" + +responselike@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" + integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw== + dependencies: + lowercase-keys "^2.0.0" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +ret@~0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.2.2.tgz#b6861782a1f4762dce43402a71eb7a283f44573c" + integrity sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ== + +reusify@^1.0.0, reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rfdc@^1.1.4, rfdc@^1.2.0, rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + +rimraf@^2.6.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rsvp@^4.8.4: + version "4.8.5" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" + integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@^6.6.3: + version "6.6.7" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== + dependencies: + tslib "^1.9.0" + +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0, safe-buffer@~5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1, safe-buffer@~5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-regex2@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/safe-regex2/-/safe-regex2-2.0.0.tgz#b287524c397c7a2994470367e0185e1916b1f5b9" + integrity sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ== + dependencies: + ret "~0.2.0" + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz" + integrity sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg== + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sane@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" + integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== + dependencies: + "@cnakazawa/watch" "^1.0.3" + anymatch "^2.0.0" + capture-exit "^2.0.0" + exec-sh "^0.3.2" + execa "^1.0.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + +saslprep@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" + integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== + dependencies: + sparse-bitfield "^3.0.3" + +sax@>=0.6.0, sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + +secure-json-parse@^2.0.0, secure-json-parse@^2.4.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.5.0.tgz#f929829df2adc7ccfb53703569894d051493a6ac" + integrity sha512-ZQruFgZnIWH+WyO9t5rWt4ZEGqCKPwhiw+YbzTwpmT9elgLrLcfuyUiSnwwjUiVy9r4VM3urtbNF1xmEh9IL2w== + +selderee@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/selderee/-/selderee-0.6.0.tgz#f3bee66cfebcb6f33df98e4a1df77388b42a96f7" + integrity sha512-ibqWGV5aChDvfVdqNYuaJP/HnVBhlRGSRrlbttmlMpHcLuTqqbMH36QkSs9GEgj5M88JDYLI8eyP94JaQ8xRlg== + dependencies: + parseley "^0.7.0" + +semver-diff@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" + integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg== + dependencies: + semver "^6.3.0" + +semver-store@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/semver-store/-/semver-store-0.3.0.tgz#ce602ff07df37080ec9f4fb40b29576547befbe9" + integrity sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg== + +"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@7.x, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7: + version "7.3.7" + resolved "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +send@^0.17.1: + version "0.17.2" + resolved "https://registry.npmjs.org/send/-/send-0.17.2.tgz" + integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "1.8.1" + mime "1.6.0" + ms "2.1.3" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + +set-cookie-parser@^2.4.1: + version "2.5.0" + resolved "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.0.tgz" + integrity sha512-cHMAtSXilfyBePduZEBVPTCftTQWz6ehWJD5YNUg4mqvRosrrjKbo4WS8JkB0/RxonMoohHm7cOGH60mDkRQ9w== + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +sharp@^0.30.5: + version "0.30.7" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.30.7.tgz#7862bda98804fdd1f0d5659c85e3324b90d94c7c" + integrity sha512-G+MY2YW33jgflKPTXXptVO28HvNOo9G3j0MybYAHeEmby+QuD2U98dT6ueht9cv/XDqZspSpIhoSW+BAKJ7Hig== + dependencies: + color "^4.2.3" + detect-libc "^2.0.1" + node-addon-api "^5.0.0" + prebuild-install "^7.1.1" + semver "^7.3.7" + simple-get "^4.0.1" + tar-fs "^2.1.1" + tunnel-agent "^0.6.0" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz" + integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== + dependencies: + shebang-regex "^1.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz" + integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shellwords@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.7" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +simple-get@^4.0.0, simple-get@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543" + integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA== + dependencies: + decompress-response "^6.0.0" + once "^1.3.1" + simple-concat "^1.0.0" + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slash@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" + integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +sliced@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" + integrity sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA== + +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +socket.io-adapter@^2.4.0, socket.io-adapter@~2.4.0: + version "2.4.0" + resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz" + integrity sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg== + +socket.io-client@^3.0.0: + version "3.1.3" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-3.1.3.tgz#57ddcefea58cfab71f0e94c21124de8e3c5aa3e2" + integrity sha512-4sIGOGOmCg3AOgGi7EEr6ZkTZRkrXwub70bBB/F0JSkMOUFpA77WsL87o34DffQQ31PkbMUIadGOk+3tx1KGbw== + dependencies: + "@types/component-emitter" "^1.2.10" + backo2 "~1.0.2" + component-emitter "~1.3.0" + debug "~4.3.1" + engine.io-client "~4.1.0" + parseuri "0.0.6" + socket.io-parser "~4.0.4" + +socket.io-parser@*: + version "4.2.1" + resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz" + integrity sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + +socket.io-parser@~4.0.4: + version "4.0.5" + resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.5.tgz" + integrity sha512-sNjbT9dX63nqUFIOv95tTVm6elyIU4RvB1m8dOeZt+IgWwcWklFDOdmGcfo3zSiRsnR/3pJkjY5lfoGqEe4Eig== + dependencies: + "@types/component-emitter" "^1.2.10" + component-emitter "~1.3.0" + debug "~4.3.1" + +socket.io@4: + version "4.5.1" + resolved "https://registry.npmjs.org/socket.io/-/socket.io-4.5.1.tgz" + integrity sha512-0y9pnIso5a9i+lJmsCdtmTTgJFFSvNQKDnPQRz28mGNnxbmqYg2QPtJTLFxhymFZhAIn50eHAKzJeiNaKr+yUQ== + dependencies: + accepts "~1.3.4" + base64id "~2.0.0" + debug "~4.3.2" + engine.io "~6.2.0" + socket.io-adapter "~2.4.0" + socket.io-parser "~4.0.4" + +socks@^2.6.2: + version "2.6.2" + resolved "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz" + integrity sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA== + dependencies: + ip "^1.1.5" + smart-buffer "^4.2.0" + +sonic-boom@^1.0.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.4.1.tgz#d35d6a74076624f12e6f917ade7b9d75e918f53e" + integrity sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg== + dependencies: + atomic-sleep "^1.0.0" + flatstr "^1.0.12" + +sonic-boom@^2.1.0: + version "2.8.0" + resolved "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.8.0.tgz" + integrity sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg== + dependencies: + atomic-sleep "^1.0.0" + +sort-keys@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-4.2.0.tgz#6b7638cee42c506fff8c1cecde7376d21315be18" + integrity sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg== + dependencies: + is-plain-obj "^2.0.0" + +source-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.5.12, source-map-support@^0.5.17, source-map-support@^0.5.6: + version "0.5.21" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== + +source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.7.3: + version "0.7.4" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + +sparse-bitfield@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz" + integrity sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ== + dependencies: + memory-pager "^1.0.2" + +spdx-correct@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.11" + resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz" + integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +split2@^3.1.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" + integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== + dependencies: + readable-stream "^3.0.0" + +split@0.3: + version "0.3.3" + resolved "https://registry.npmjs.org/split/-/split-0.3.3.tgz" + integrity sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA== + dependencies: + through "2" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.2: + version "2.0.5" + resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== + dependencies: + escape-string-regexp "^2.0.0" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz" + integrity sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g== + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + +steed@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/steed/-/steed-1.1.3.tgz" + integrity sha512-EUkci0FAUiE4IvGTSKcDJIQ/eRUP2JJb56+fvZ4sdnguLTqIdKjSxUe138poW8mkvKWXW2sFPrgTsxqoISnmoA== + dependencies: + fastfall "^1.5.0" + fastparallel "^2.2.0" + fastq "^1.3.0" + fastseries "^1.7.0" + reusify "^1.0.0" + +stream-combiner@~0.0.4: + version "0.0.4" + resolved "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz" + integrity sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw== + dependencies: + duplexer "~0.1.1" + +stream-parser@~0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz" + integrity sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ== + dependencies: + debug "2" + +stream-wormhole@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/stream-wormhole/-/stream-wormhole-1.1.0.tgz#300aff46ced553cfec642a05251885417693c33d" + integrity sha512-gHFfL3px0Kctd6Po0M8TzEvt3De/xu6cnRrjlfYNhwbhLPLwigI2t1nc6jrzNuaYg5C4YF78PPFuQPzRiqn9ew== + +string-argv@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.1.2.tgz#c5b7bc03fb2b11983ba3a72333dd0559e77e4738" + integrity sha512-mBqPGEOMNJKXRo7z0keX0wlAhbBAjilUdPW13nN0PecVryZxdHIeM7TqbsSUA7VYuS00HGC6mojP7DlQzfa9ZA== + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-similarity@^4.0.1: + version "4.0.4" + resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.4.tgz#42d01ab0b34660ea8a018da8f56a3309bb8b2a5b" + integrity sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ== + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string.prototype.trimend@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz" + integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + +string.prototype.trimstart@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz" + integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" + integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz" + integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-4.0.0.tgz#b41379433dd06f5eae805e21d631e07ee670d853" + integrity sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA== + dependencies: + min-indent "^1.0.1" + +strip-json-comments@^2.0.0, strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strnum@^1.0.4: + version "1.0.5" + resolved "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz" + integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== + +superagent@^3.8.3: + version "3.8.3" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" + integrity sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA== + dependencies: + component-emitter "^1.2.0" + cookiejar "^2.1.0" + debug "^3.1.0" + extend "^3.0.0" + form-data "^2.3.1" + formidable "^1.2.0" + methods "^1.1.1" + mime "^1.4.1" + qs "^6.5.1" + readable-stream "^2.3.5" + +supertest@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/supertest/-/supertest-4.0.2.tgz#c2234dbdd6dc79b6f15b99c8d6577b90e4ce3f36" + integrity sha512-1BAbvrOZsGA3YTCWqbmh14L0YEq0EGICX/nBnfkfVJn7SrxQV1I3pMYjSzG9y/7ZU2V9dWqyqk2POwxlb09duQ== + dependencies: + methods "^1.1.2" + superagent "^3.8.3" + +supports-color@^5.3.0, supports-color@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +table@^6.0.9: + version "6.8.0" + resolved "https://registry.npmjs.org/table/-/table-6.8.0.tgz" + integrity sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA== + dependencies: + ajv "^8.0.1" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + +tar-fs@^2.0.0, tar-fs@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" + integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" + +tar-stream@^2.1.4, tar-stream@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + +tar@^6.1.11: + version "6.1.11" + resolved "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + +term-size@^2.1.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" + integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== + +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-decoding@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/text-decoding/-/text-decoding-1.0.0.tgz#38a5692d23b5c2b12942d6e245599cb58b1bc52f" + integrity sha512-/0TJD42KDnVwKmDK6jj3xP7E2MG7SHAOG4tyTgyUCRPdHwvkquYNLEQltmdMa3owq3TkddCVcTsoctJI8VQNKA== + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +throat@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" + integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== + +through2@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4" + integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ== + dependencies: + inherits "^2.0.4" + readable-stream "2 || 3" + +through@2, through@~2.3, through@~2.3.1: + version "2.3.8" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +tiny-lru@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/tiny-lru/-/tiny-lru-7.0.6.tgz#b0c3cdede1e5882aa2d1ae21cb2ceccf2a331f24" + integrity sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow== + +tiny-lru@^8.0.1: + version "8.0.2" + resolved "https://registry.npmjs.org/tiny-lru/-/tiny-lru-8.0.2.tgz" + integrity sha512-ApGvZ6vVvTNdsmt676grvCkUCGwzG9IqXma5Z07xJgiC5L7akUMof5U8G2JTI9Rz/ovtVhJBlY6mNhEvtjzOIg== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz" + integrity sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg== + dependencies: + kind-of "^3.0.2" + +to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz" + integrity sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg== + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +touch@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" + integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA== + dependencies: + nopt "~1.0.10" + +tough-cookie@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.1.2" + +tr46@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== + dependencies: + punycode "^2.1.1" + +tr46@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz" + integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== + dependencies: + punycode "^2.1.1" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + +trim-newlines@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-4.0.2.tgz#d6aaaf6a0df1b4b536d183879a6b939489808c7c" + integrity sha512-GJtWyq9InR/2HRiLZgpIKv+ufIKrVrvjQWEj7PxAXNc5dwbNJkqhAUoAGgzRmULAnoOM5EIpveYd3J2VeSAIew== + +ts-jest@^26.4.0: + version "26.5.6" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.6.tgz#c32e0746425274e1dfe333f43cd3c800e014ec35" + integrity sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA== + dependencies: + bs-logger "0.x" + buffer-from "1.x" + fast-json-stable-stringify "2.x" + jest-util "^26.1.0" + json5 "2.x" + lodash "4.x" + make-error "1.x" + mkdirp "1.x" + semver "7.x" + yargs-parser "20.x" + +ts-node-dev@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ts-node-dev/-/ts-node-dev-1.1.8.tgz#95520d8ab9d45fffa854d6668e2f8f9286241066" + integrity sha512-Q/m3vEwzYwLZKmV6/0VlFxcZzVV/xcgOt+Tx/VjaaRHyiBcFlV0541yrT09QjzzCxlDZ34OzKjrFAynlmtflEg== + dependencies: + chokidar "^3.5.1" + dynamic-dedupe "^0.3.0" + minimist "^1.2.5" + mkdirp "^1.0.4" + resolve "^1.0.0" + rimraf "^2.6.1" + source-map-support "^0.5.12" + tree-kill "^1.2.2" + ts-node "^9.0.0" + tsconfig "^7.0.0" + +ts-node@^9.0.0: + version "9.1.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d" + integrity sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg== + dependencies: + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + source-map-support "^0.5.17" + yn "3.1.1" + +tsc-watch@^4.2.9: + version "4.6.2" + resolved "https://registry.npmjs.org/tsc-watch/-/tsc-watch-4.6.2.tgz" + integrity sha512-eHWzZGkPmzXVGQKbqQgf3BFpGiZZw1jQ29ZOJeaSe8JfyUvphbd221NfXmmsJUGGPGA/nnaSS01tXipUcyxAxg== + dependencies: + cross-spawn "^7.0.3" + node-cleanup "^2.1.2" + ps-tree "^1.2.0" + string-argv "^0.1.1" + strip-ansi "^6.0.0" + +tsconfig@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-7.0.0.tgz#84538875a4dc216e5c4a5432b3a4dec3d54e91b7" + integrity sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw== + dependencies: + "@types/strip-bom" "^3.0.0" + "@types/strip-json-comments" "0.0.30" + strip-bom "^3.0.0" + strip-json-comments "^2.0.0" + +tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== + dependencies: + safe-buffer "^5.0.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" + integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== + dependencies: + prelude-ls "~1.1.2" + +type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +type-fest@^1.0.1, type-fest@^1.2.1, type-fest@^1.2.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" + integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== + +type-is@^1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typescript@^4.0.3: + version "4.7.4" + resolved "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== + +uid-safe@^2.1.5: + version "2.1.5" + resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.5.tgz#2b3d5c7240e8fc2e58f8aa269e5ee49c0857bd3a" + integrity sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA== + dependencies: + random-bytes "~1.0.0" + +uid2@0.0.3: + version "0.0.3" + resolved "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz" + integrity sha512-5gSP1liv10Gjp8cMEnFd6shzkL/D6W1uhXSFNCxDC+YI8+L8wkCYCbJ7n77Ezb4wE/xzMogecE+DtamEe9PZjg== + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + +undefsafe@^2.0.2: + version "2.0.5" + resolved "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz" + integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== + +undici@^3.3.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/undici/-/undici-3.3.6.tgz#06d3b97b7eeff46bce6f8a71079c09f64dd59dc1" + integrity sha512-/j3YTZ5AobMB4ZrTY72mzM54uFUX32v0R/JRW9G2vOyF1uSKYAx+WT8dMsAcRS13TOFISv094TxIyWYk+WEPsA== + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz" + integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz" + integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +unique-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" + integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== + dependencies: + crypto-random-string "^2.0.0" + +universalify@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +unoconv-promise@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/unoconv-promise/-/unoconv-promise-1.0.8.tgz#8d4b9fcba8364908a4910c35899e3ee27a3df24a" + integrity sha512-YBVskYpnYj5KQS5aCnE+a+n7jFOmL9dOKzfymw5mKsZhO2K6LrBLAGzReXpOU3x77tTEeJzZYTgrhqIbtF9Acw== + dependencies: + chai "^4.2.0" + debug "^4.1.1" + mime "^2.4.0" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz" + integrity sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ== + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +update-browserslist-db@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.4.tgz" + integrity sha512-jnmO2BEGUjsMOe/Fg9u0oczOe/ppIDZPebzccl1yDWGLFP16Pa1/RM5wEoKYPG2zstNcDuAStejyxsOuKINdGA== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +update-notifier@^4.0.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3" + integrity sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A== + dependencies: + boxen "^4.2.0" + chalk "^3.0.0" + configstore "^5.0.1" + has-yarn "^2.1.0" + import-lazy "^2.1.0" + is-ci "^2.0.0" + is-installed-globally "^0.3.1" + is-npm "^4.0.0" + is-yarn-global "^0.3.0" + latest-version "^5.0.0" + pupa "^2.0.1" + semver-diff "^3.1.1" + xdg-basedir "^4.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz" + integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg== + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz" + integrity sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ== + dependencies: + prepend-http "^2.0.0" + +url-parse@~1.5.1: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +util@^0.12.3: + version "0.12.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.4.tgz#66121a31420df8f01ca0c464be15dfa1d1850253" + integrity sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + safe-buffer "^5.1.2" + which-typed-array "^1.1.2" + +uuid-time@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/uuid-time/-/uuid-time-1.0.0.tgz" + integrity sha512-F0EzKK+aqt41uDutE+qukIta0CkMJ212qkIWT7uUCy0DjbyMEGpNkiLQfdByBveEt28Z/ywZU7u4CQ/a03oCaA== + +uuid@^8.3.0, uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +v8-to-istanbul@^7.0.0: + version "7.1.2" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz#30898d1a7fa0c84d225a2c1434fb958f290883c1" + integrity sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +vary@^1, vary@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + +walker@^1.0.7, walker@~1.0.5: + version "1.0.8" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz" + integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== + dependencies: + defaults "^1.0.3" + +web-encoding@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/web-encoding/-/web-encoding-1.1.5.tgz#fc810cf7667364a6335c939913f5051d3e0c4864" + integrity sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA== + dependencies: + util "^0.12.3" + optionalDependencies: + "@zxing/text-encoding" "0.9.0" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== + +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + +whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^11.0.0: + version "11.0.0" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz" + integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== + dependencies: + tr46 "^3.0.0" + webidl-conversions "^7.0.0" + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +whatwg-url@^8.0.0, whatwg-url@^8.5.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== + dependencies: + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz" + integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== + +which-typed-array@^1.1.2: + version "1.1.8" + resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz" + integrity sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-abstract "^1.20.0" + for-each "^0.3.3" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.9" + +which@^1.1.1, which@^1.2.9: + version "1.3.1" + resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1, which@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.2: + version "1.1.5" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" + +widest-line@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" + integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== + dependencies: + string-width "^4.0.0" + +word-wrap@^1.2.3, word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +write-json-file@~4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-4.3.0.tgz#908493d6fd23225344af324016e4ca8f702dd12d" + integrity sha512-PxiShnxf0IlnQuMYOPPhPkhExoCQuTUNPOa/2JWCYTmBquU9njyyDuwRKN26IZBlp4yn1nt+Agh2HOOBl+55HQ== + dependencies: + detect-indent "^6.0.0" + graceful-fs "^4.1.15" + is-plain-obj "^2.0.0" + make-dir "^3.0.0" + sort-keys "^4.0.0" + write-file-atomic "^3.0.0" + +ws@^7.4.2, ws@^7.4.6: + version "7.5.8" + resolved "https://registry.npmjs.org/ws/-/ws-7.5.8.tgz" + integrity sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw== + +ws@~7.4.2: + version "7.4.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + +ws@~8.2.3: + version "8.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" + integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== + +xdg-basedir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" + integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + +xml2js@^0.4.15: + version "0.4.23" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" + integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + +xml@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz" + integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== + +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +xmlhttprequest-ssl@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz#03b713873b01659dfa2c1c5d056065b27ddc2de6" + integrity sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q== + +xtend@^4.0.0, xtend@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@4.0.0, yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A== + +yargs-parser@20.x, yargs-parser@^20.2.2, yargs-parser@^20.2.9: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs@^15.4.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.2" + +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yeast@0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz" + integrity sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg== + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zip-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.1.0.tgz#51dd326571544e36aa3f756430b313576dc8fc79" + integrity sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A== + dependencies: + archiver-utils "^2.1.0" + compress-commons "^4.1.0" + readable-stream "^3.6.0" \ No newline at end of file diff --git a/twake/default-configuration/backend-node/production.json b/twake/default-configuration/backend-node/production.json new file mode 100644 index 00000000..0b421da1 --- /dev/null +++ b/twake/default-configuration/backend-node/production.json @@ -0,0 +1,39 @@ +{ + "phpnode": { + "secret": "api_supersecret" + }, + "websocket": { + "path": "/socket/", + "adapters": { + "types": [] + }, + "auth": { + "jwt": { + "secret": "supersecret" + } + } + }, + "auth": { + "jwt": { + "secret": "supersecret" + } + }, + "database": { + "secret": "ab63bb3e90c0271c9a1c06651a7c0967eab8851a7a897766", + "type": "cassandra", + "cassandra": { + "contactPoints": ["scylladb:9042"], + "localDataCenter": "datacenter1", + "keyspace": "twake", + "wait": false, + "retries": 10, + "delay": 200 + } + }, + "pubsub": { + "type": "amqp", + "amqp": { + "urls": ["amqp://guest:guest@rabbitmq:5672"] + } + } +} diff --git a/twake/default-configuration/backend-node/production.json.template b/twake/default-configuration/backend-node/production.json.template new file mode 100644 index 00000000..34e9d24d --- /dev/null +++ b/twake/default-configuration/backend-node/production.json.template @@ -0,0 +1,40 @@ +{ + "phpnode": { + "secret": "api_supersecret (set the same in php later)" + }, + "websocket": { + "path": "/socket/", + "adapters": { + "types": [] + }, + "auth": { + "jwt": { + "secret": "supersecret (use the same as in php)" + } + } + }, + "auth": { + "jwt": { + "secret": "supersecret (use the same as in php)" + } + }, + "database": { + "secret": "GET YOUR SECRET FROM PHP Parameters.php: db.secret", + "type": "cassandra", + "cassandra": { + "contactPoints": [ + "scylladb:9042" + ], + "localDataCenter": "datacenter1", + "keyspace": "twake", + "wait": false, + "retries": 10, + "delay": 200 + } + }, + "pubsub": { + "urls": [ + "amqp://admin:admin@rabbitmq:5672" + ] + } +} diff --git a/twake/default-configuration/backend/Parameters.php b/twake/default-configuration/backend/Parameters.php new file mode 100644 index 00000000..24692b18 --- /dev/null +++ b/twake/default-configuration/backend/Parameters.php @@ -0,0 +1,220 @@ +configuration = [ + "env" => [ + "type" => "prod", + "timer" => false, + "admin_api_token" => "", + "licence_key" => "", + "standalone" => true, + //"frontend_server_name" => "http://localhost:8000/", // define only if needed + "server_name" => "http://localhost:8000/", + "internal_server_name" => "http://nginx/" + ], + "jwt" => [ + "secret" => "supersecret", + "expiration" => 60*60, //1 hour + "refresh_expiration" => 60*60*24*31 //1 month + ], + "node" => [ + "api" => "http://node:3000/private/", + "secret" => "api_supersecret" + ], + "db" => [ + "driver" => "pdo_cassandra", + "host" => "scylladb", + "port" => 9042, + "dbname" => "twake", + "user" => "root", + "password" => "root", + "encryption_key" => "ab63bb3e90c0271c9a1c06651a7c0967eab8851a7a897766", + "replication" => "{'class': 'SimpleStrategy', 'replication_factor': '1'}" + ], + "es" => [ + "host" => false + ], + "queues" => [ + "rabbitmq" => [ + "use" => true, + "host" => "rabbitmq", + "port" => 5672, + "username" => "guest", + "password" => "guest", + "vhost" => false + ] + ], + "storage" => [ + "drive_previews_tmp_folder" => "/tmp/", + "drive_tmp_folder" => "/tmp/", + "drive_salt" => "SecretPassword", + "providers" => [ + [ + "label" => "someOpenStack", + "type" => "openstack", + "use" => false, + "project_id" => "", + "auth_url" => "https//auth.cloud.ovh.net/v3", + "buckets_prefix" => "", + "disable_encryption" => false, + "buckets" => [ + "fr" => [ + "public" => "", + "private" => "", + "region" => "SBG5" + ] + ], + "user" => [ + "id" => "", + "password" => "", + "domain_name" => "default" + ] + ], + [ + "label" => "someS3", + "type" => "S3", + "base_url" => "http://127.0.0.1:9000", + "use" => false, + "version" => "latest", + "disable_encryption" => false, + "buckets_prefix" => "dev.", + "buckets" => [ + "fr" => "eu-west-3" + ], + "credentials" => [ + "key" => "", + "secret" => "" + ] + ], + [ + "label" => "someLocal", + "type" => "local", + "use" => true, + "disable_encryption" => false, + "location" => "../drive/", + "preview_location" => "../web/medias/", + "preview_public_path" => "/medias/" + ], + ], + ], + "mail" => [ + "sender" => [ + "host" => "", + "port" => "", + "username" => "", + "password" => "", + "auth_mode" => "plain" + ], + "template_dir" => "/src/Twake/Core/Resources/views/", + "twake_domain_url" => "https://twakeapp.com/", + "from" => "noreply@twakeapp.com", + "from_name" => "Twake", + "twake_address" => "Twake, 54000 Nancy, France", + "dkim" => [ + "private_key" => "", + "domain_name" => '', + "selector" => '' + ], + "mailjet"=> [ + "contact_list_subscribe"=> false, + "contact_list_newsletter"=> false + ] + ], + "push_notifications" => [ + "apns_certificate" => __DIR__ . "/certs/apns_prod.pem", + "firebase_api_key" => "KEY", + ], + + //Defaults values for all clients but editable in database + "defaults" => [ + "applications" => [ + "twake_drive" => [ "default" => true ], //False to not install + "twake_calendar" => [ "default" => true ], + "twake_tasks" => [ "default" => true ], + "connectors" => [ + "jitsi" => [ "default" => true ], + ] + ], + "connectors" => [ + ], + "branding" => [ + "name" => "Twake", + "enable_newsletter" => false, + /* + "header" => [ + "logo" => 'https://openpaas.linagora.com/images/white-logo.svg', + "apps" => [ + [ + "name"=> 'Accueil', + "url"=> 'https://openpaas.linagora.com/', + "icon"=> 'https://openpaas.linagora.com/images/application-menu/home-icon.svg', + ], + [ + "name"=> 'Inbox', + "url"=> 'https://openpaas.linagora.com/#/unifiedinbox/inbox', + "icon"=> 'https://openpaas.linagora.com/unifiedinbox/images/inbox-icon.svg', + ], + [ + "name"=> 'Calendrier', + "url"=> 'https://openpaas.linagora.com/#/calendar', + "icon"=> 'https://openpaas.linagora.com/calendar/images/calendar-icon.svg', + ], + [ + "name"=> 'Contacts', + "url"=> 'https://openpaas.linagora.com/#/contact/addressbooks/', + "icon"=> 'https://openpaas.linagora.com/contact/images/contacts-icon.svg', + ], + ], + ], + "style" => [ + "color" => '#2196F3', + "default_border_radius" => '2', + ], + "link" => "https://open-paas.org/", + "logo" => "https://open-paas.org/wp-content/uploads/2019/10/openpaas.png" + */ + ], + "auth" => [ + "internal" => [ + "use" => true, + "disable_account_creation" => false, + "disable_email_verification" => true + ], + "openid" => [ + "use" => false, + "provider_uri" => 'https://auth0.com', + "client_id" => '', + "client_secret" => '', + //"disable_logout_redirect" => false + "provider_config" => [ + //token_endpoint + //token_endpoint_auth_methods_supported + //userinfo_endpoint + //end_session_endpoint + //authorization_endpoint + ] + ], + "cas" => [ + "use" => false, + "base_url" => '', + "email_key" => '', + "lastname_key" => '', + "firstname_key" => '' + ], + "console" => [ + "use" => false + ] + ] + ], + ]; + } + +} diff --git a/twake/default-configuration/frontend/environment.ts b/twake/default-configuration/frontend/environment.ts new file mode 100644 index 00000000..0be31154 --- /dev/null +++ b/twake/default-configuration/frontend/environment.ts @@ -0,0 +1,16 @@ +export default { + env_dev: true, + sentry_dsn: false, + front_root_url: + (document.location.protocol || "http") + "//" + document.location.host, + api_root_url: + (document.location.protocol || "http") + "//" + document.location.host, + socketio_url: + (document.location.protocol || "http").replace("http", "ws") + + "//" + + document.location.host, + websocket_url: + (document.location.protocol || "http").replace("http", "ws") + + "//" + + document.location.host, +}; diff --git a/twake/docker-compose.dev.mongo.yml b/twake/docker-compose.dev.mongo.yml new file mode 100644 index 00000000..8b2f14fc --- /dev/null +++ b/twake/docker-compose.dev.mongo.yml @@ -0,0 +1,62 @@ +version: "3.4" + +services: + mongo: + container_name: mongo + image: mongo + volumes: + - ./docker-data/mongo:/data/db + ports: + - 27017:27017 + networks: + - twake_network + + plugins: + container_name: plugins + image: twaketech/twake-plugins + privileged: true + volumes: + - ./plugins/plugins:/usr/src/app/plugins + - ./plugins/plugins.json:/usr/src/app/plugins.json + build: + context: . + dockerfile: ./docker/twake-plugins/Dockerfile + ports: + - 8080:8080 + networks: + - twake_network + + node: + image: twaketech/twake-node + container_name: node + ports: + - 4000:3000 + - 8000:3000 + - 9229:9229 + environment: + - DEV=dev + - SEARCH_DRIVER=mongodb + - DB_DRIVER=mongodb + - PUBSUB_TYPE=local + build: + context: . + dockerfile: ./docker/twake-node/Dockerfile + target: development + volumes: + - ./backend/node:/usr/src/app + - ./docker-data/documents/:/storage/ + depends_on: + - mongo + links: + - mongo + networks: + - twake_network + +networks: + twake_network: + driver: bridge + ipam: + config: + - subnet: 172.21.0.0/16 + gateway: 172.21.0.1 + diff --git a/twake/docker-compose.dev.tests.cassandra.yml b/twake/docker-compose.dev.tests.cassandra.yml new file mode 100644 index 00000000..2db16bf1 --- /dev/null +++ b/twake/docker-compose.dev.tests.cassandra.yml @@ -0,0 +1,50 @@ +version: "3.4" + +services: + scylladb: + image: scylladb/scylla:4.1.0 + command: --seeds=scylladb --smp 1 --memory 400M --overprovisioned 1 --api-address 0.0.0.0 + volumes: + - ./docker-data/scylladb:/var/lib/scylla + rabbitmq: + image: rabbitmq:3 + ports: + - 5672:5672 + - 15672:15672 + node: + image: twaketech/twake-node:test + build: + context: . + dockerfile: ./docker/twake-node/Dockerfile + target: test + environment: + - NODE_ENV=test + - DB_DRIVER + - PUBSUB_URLS=amqp://guest:guest@rabbitmq:5672 + - SEARCH_ES_ENDPOINT=http://elasticsearch:9200 + - SEARCH_ES_FLUSHINTERVAL=1 + volumes: + - ./backend/node:/usr/src/app + - ./docker-data/documents/:/storage/ + depends_on: + - scylladb + - rabbitmq + - elasticsearch + links: + - scylladb + - rabbitmq + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:7.13.4 + environment: + - xpack.security.enabled=false + - bootstrap.memory_lock=true + - discovery.type=single-node + - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + ulimits: + memlock: + soft: -1 + hard: -1 + volumes: + - ./docker-data/es_twake:/usr/share/elasticsearch/data + ports: + - 9200:9200 diff --git a/twake/docker-compose.dev.tests.mongo.yml b/twake/docker-compose.dev.tests.mongo.yml new file mode 100644 index 00000000..f57066d5 --- /dev/null +++ b/twake/docker-compose.dev.tests.mongo.yml @@ -0,0 +1,30 @@ +version: "3.4" + +# docker-compose -f docker-compose.dev.tests.mongo.yml stop mongo; rm -R docker-data/mongo/; docker-compose -f docker-compose.dev.tests.mongo.yml run -e SEARCH_DRIVER=mongodb -e DB_DRIVER=mongodb node npm run test:e2e + +services: + mongo: + container_name: mongo + image: mongo + volumes: + - ./docker-data/mongo:/data/db + ports: + - 27017:27017 + node: + image: twaketech/twake-node:test + container_name: node-test + build: + context: . + dockerfile: ./docker/twake-node/Dockerfile + target: test + environment: + - NODE_ENV=test + - DB_DRIVER + - PUBSUB_URLS=amqp://guest:guest@rabbitmq:5672 + volumes: + - ./backend/node:/usr/src/app + - ./docker-data/documents/:/storage/ + depends_on: + - mongo + links: + - mongo diff --git a/twake/docker-compose.dev.yml b/twake/docker-compose.dev.yml new file mode 100644 index 00000000..d1039ba9 --- /dev/null +++ b/twake/docker-compose.dev.yml @@ -0,0 +1,89 @@ +version: "3.4" + +services: + scylladb: + image: scylladb/scylla:4.1.0 + command: --smp 1 --memory 400M + ports: + - 9042:9042 + volumes: + - ./docker-data/scylladb:/var/lib/scylla + rabbitmq: + image: rabbitmq:3 + + node: + image: twaketech/twake-node + ports: + - 9229:9229 + environment: + - DEV=dev + - DB_DRIVER=cassandra + - DB_CASSANDRA_URI=scylladb:9042 + - DB_CASSANDRA_KEYSPACE=twake + - PUBSUB_URLS=amqp://guest:guest@rabbitmq:5672 + build: + context: . + dockerfile: ./docker/twake-node/Dockerfile + target: development + volumes: + - ./backend/node:/usr/src/app + - ./docker-data/documents/:/storage/ + depends_on: + - scylladb + - rabbitmq + - elasticsearch + links: + - scylladb + extra_hosts: + - "host.docker.internal:host-gateway" + php: + image: twaketech/twake-php + environment: + - DEV=dev + build: + context: . + dockerfile: docker/twake-php/Dockerfile + volumes: + - ./backend/core/:/twake-core:cached + - ./docker-data/drive/:/twake-core/drive/ + - ./docker-data/fpm/:/etc/docker-data/fpm/ + - ./docker-data/drive-preview/:/twake-core/web/medias/ + - ./docker-data/uploads/:/twake-core/web/upload/ + depends_on: + - scylladb + - rabbitmq + - elasticsearch + links: + - scylladb + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:7.13.4 + environment: + - cluster.name=docker-cluster + - discovery.type=single-node + - bootstrap.memory_lock=true + - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + ulimits: + memlock: + soft: -1 + hard: -1 + volumes: + - ./docker-data/es:/usr/share/elasticsearch/data + + nginx: + image: twaketech/twake-nginx + environment: + - DEV=dev + build: + context: . + dockerfile: docker/twake-nginx/Dockerfile + ports: + - 8000:80 + depends_on: + - php + - node + volumes: + - ./docker-data/logs/nginx/:/var/log/nginx + - ./docker-data/letsencrypt/:/etc/letsencrypt/ + - ./frontend/:/twake-react/ + - ./docker-data/drive-preview/:/twake-core/web/medias/ + - ./docker-data/uploads/:/twake-core/web/upload/ diff --git a/twake/docker-compose.onpremise.mongo.yml b/twake/docker-compose.onpremise.mongo.yml new file mode 100644 index 00000000..e313dcee --- /dev/null +++ b/twake/docker-compose.onpremise.mongo.yml @@ -0,0 +1,26 @@ +version: "3.4" + +services: + mongo: + container_name: mongo + image: mongo + volumes: + - ./docker-data/mongo:/data/db + + node: + image: twaketech/twake-node:latest + ports: + - 3000:3000 + - 8000:3000 + environment: + - DEV=production + - SEARCH_DRIVER=mongodb + - DB_DRIVER=mongodb + - PUBSUB_TYPE=local + volumes: + - ./configuration/backend-node/production.json:/usr/src/app/config/production.json + - ./docker-data/documents/:/storage/ + depends_on: + - mongo + links: + - mongo diff --git a/twake/docker-compose.onpremise.yml b/twake/docker-compose.onpremise.yml new file mode 100644 index 00000000..2e9d0aa3 --- /dev/null +++ b/twake/docker-compose.onpremise.yml @@ -0,0 +1,79 @@ +version: "3.4" + +services: + scylladb: + image: scylladb/scylla:4.1.0 + command: --smp 1 --memory 1G + ports: + - 9042:9042 + volumes: + - ./docker-data/scylladb:/var/lib/scylla + healthcheck: + test: ["CMD-SHELL", "nodetool status | grep UN"] + interval: 30s + timeout: 10s + retries: 3 + + rabbitmq: + image: rabbitmq:3 + healthcheck: + test: rabbitmq-diagnostics -q ping + interval: 30s + timeout: 10s + retries: 3 + + node: + build: + context: . + dockerfile: docker/twake-node/Dockerfile + environment: + - NODE_ENV=production + - PUBSUB_URLS=amqp://guest:guest@rabbitmq:5672 + volumes: + - ./default-configuration/backend-node/production.json:/usr/src/app/config/production.json + - ./docker-data/documents/:/storage/ + depends_on: + scylladb: + condition: service_healthy + rabbitmq: + condition: service_healthy + + php: + build: + context: . + dockerfile: docker/twake-php/Dockerfile + environment: + - DEV=production + volumes: + - ./default-configuration/backend/Parameters.php:/configuration/Parameters.php + - ./connectors/:/twake-core/src/BuiltInConnectors/Connectors + - ./docker-data/drive/:/twake-core/drive/ + - ./docker-data/fpm/:/etc/docker-data/fpm/ + - ./docker-data/drive-preview/:/twake-core/web/medias/ + - ./docker-data/uploads/:/twake-core/web/upload/ + depends_on: + scylladb: + condition: service_healthy + rabbitmq: + condition: service_healthy + + nginx: + build: + context: . + dockerfile: docker/twake-nginx/Dockerfile + environment: + - DEV=production + - SSL_CERTS=selfsigned + ports: + - 80:80 + - 8000:80 + - 443:443 + depends_on: + - php + - node + volumes: + - ./docker-data/logs/nginx/:/var/log/nginx + - ./docker-data/letsencrypt/:/etc/letsencrypt/ + - ./docker-data/drive-preview/:/twake-core/web/medias/ + - ./docker-data/uploads/:/twake-core/web/upload/ + - ./docker-data/ssl:/etc/nginx/ssl diff --git a/twake/docker-compose.tests.yml b/twake/docker-compose.tests.yml new file mode 100644 index 00000000..6a544493 --- /dev/null +++ b/twake/docker-compose.tests.yml @@ -0,0 +1,84 @@ +version: "2" + +services: + scylladb: + image: scylladb/scylla:4.1.0 + command: --seeds=scylladb --smp 1 --memory 400M --overprovisioned 1 --api-address 0.0.0.0 + scylladb2: + image: scylladb/scylla:4.1.0 + command: --seeds=scylladb --smp 1 --memory 400M --overprovisioned 1 --api-address 0.0.0.0 + rabbitmq: + image: rabbitmq:3 + ports: + - 5672:5672 + - 15672:15672 + mongo: + container_name: mongo + image: mongo + ports: + - 27017:27017 + redis: + image: "redis:alpine" + command: redis-server --requirepass some_password + ports: + - "6379:6379" + environment: + - REDIS_REPLICATION_MODE=master + node: + image: twaketech/twake-node:test + build: + context: . + dockerfile: ./docker/twake-node/Dockerfile + target: test + volumes: + - ./coverage/:/usr/src/app/coverage/ + environment: + - NODE_ENV=test + - DB_DRIVER + - PUBSUB_URLS=amqp://guest:guest@rabbitmq:5672 + - SEARCH_ES_ENDPOINT=http://elasticsearch:9200 + - SEARCH_ES_FLUSHINTERVAL=1 + depends_on: + - mongo + - scylladb + - rabbitmq + - elasticsearch + links: + - mongo + - scylladb + - rabbitmq + php: + image: twaketech/twake-php + volumes: + - ./backend/core/:/twake-core:cached + - ./docker-data/drive/:/twake-core/drive/ + - ./docker-data/fpm/:/etc/docker-data/fpm/ + depends_on: + - scylladb + - rabbitmq + - elasticsearch + links: + - scylladb + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:7.13.4 + environment: + - xpack.security.enabled=false + - bootstrap.memory_lock=true + - discovery.type=single-node + - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + ulimits: + memlock: + soft: -1 + hard: -1 + ports: + - 9200:9200 + nginx: + image: twaketech/twake-nginx + ports: + - 8000:80 + links: + - php + volumes: + - ./docker-data/logs/nginx/:/var/log/nginx + - ./docker-data/letsencrypt/:/etc/letsencrypt/ + - ./frontend/:/twake-react/ \ No newline at end of file diff --git a/twake/docker/integration-test/Dockerfile b/twake/docker/integration-test/Dockerfile new file mode 100644 index 00000000..3be2cdbd --- /dev/null +++ b/twake/docker/integration-test/Dockerfile @@ -0,0 +1,20 @@ +FROM node:slim + +# We don't need the standalone Chromium +ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true + +# Install Google Chrome Stable and fonts +# Note: this installs the necessary libs to make the browser work with Puppeteer. +RUN apt-get update && apt-get install curl gnupg -y \ + && curl --location --silent https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \ + && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \ + && apt-get update \ + && apt-get install google-chrome-stable -y --no-install-recommends \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app +COPY integration-test /app + +RUN npm install + +ENTRYPOINT npm run test:all \ No newline at end of file diff --git a/twake/docker/php7.1-cassandra/Dockerfile b/twake/docker/php7.1-cassandra/Dockerfile new file mode 100644 index 00000000..25aab596 --- /dev/null +++ b/twake/docker/php7.1-cassandra/Dockerfile @@ -0,0 +1,133 @@ +# MUST BE BUILT FROM . +# docker build . -t php7.1-cassandra -f ./Dockerfile +FROM php:7.4-fpm + +MAINTAINER Romaric Mourgues + +ARG TIMEZONE +ARG APCU_VERSION=5.1.11 + +# Set timezone +RUN ln -snf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime +RUN echo ${TIMEZONE} > /etc/timezone +RUN printf '[PHP]\ndate.timezone = "%s"\n', ${TIMEZONE} > /usr/local/etc/php/conf.d/tzone.ini +RUN "date" + +RUN apt-get update && apt-get install -y cron + +RUN apt-get update && apt-get install -y \ + openssl \ + git \ + unzip + +RUN apt-get update && apt-get install -y libpng-dev + +#MBSTRING +RUN docker-php-ext-install mbstring + +RUN apt-get update && apt-get install -y \ + libfreetype6-dev \ + libjpeg62-turbo-dev \ + libmcrypt-dev \ + libpng-dev \ + && docker-php-ext-install -j$(nproc) iconv mcrypt \ + && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \ + && docker-php-ext-install -j$(nproc) gd + +#ZIP +RUN apt-get update && apt-get install -y zlib1g-dev +RUN docker-php-ext-install zip + +#GD images +RUN apt-get update && apt-get install -y \ + libfreetype6-dev \ + libjpeg62-turbo-dev \ + libpng-dev \ + && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \ + && docker-php-ext-install -j$(nproc) gd + +#ZMQ +RUN apt-get update && apt-get install -y zlib1g-dev libzmq3-dev wget git \ + && pecl install zmq-beta \ + && docker-php-ext-install zip \ + && docker-php-ext-enable zmq + +#Imagick +RUN apt-get update && apt-get install -y ghostscript && apt-get clean +RUN apt-get update && apt-get install -y libmagickwand-dev --no-install-recommends && rm -rf /var/lib/apt/lists/* +RUN pecl install imagick && docker-php-ext-enable imagick + +#Unoconv +RUN apt-get update && apt-get install -y --force-yes unoconv libxml2-dev +RUN docker-php-ext-install soap +RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +# Install Composer +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer +RUN composer --version + +# Type docker-php-ext-install to see available extensions +RUN docker-php-ext-install pdo pdo_mysql + +ENV CASSANDRA_PHP_DRIVER_VERSION 1.3.2 + +RUN rm /var/lib/apt/lists/* -vrf && \ + apt-get clean && apt-get update + +RUN apt-get update && \ + apt-get install -y git wget libssl-dev zlib1g-dev libicu-dev g++ make cmake libuv-dev libgmp-dev uuid-dev && \ + apt-get autoclean -y && \ + apt-get clean -y + +# Install datastax php-driver fox cassandra +RUN git clone https://github.com/datastax/php-driver.git /usr/src/datastax-php-driver && \ + cd /usr/src/datastax-php-driver && \ + git checkout --detach v${CASSANDRA_PHP_DRIVER_VERSION} && \ + git submodule update --init && \ + cd ext && \ + ./install.sh && \ + echo extension=cassandra.so > /usr/local/etc/php/conf.d/cassandra.ini + +# Install PHP extensions +RUN docker-php-ext-install zip mbstring intl opcache bcmath && \ + echo extension=bcmath.so > /usr/local/etc/php/conf.d/docker-php-ext-bcmath.ini && \ + apt-get install -y php5-xdebug && \ + echo zend_extension=xdebug.so > /usr/local/etc/php/conf.d/xdebug.ini && \ + pecl install apcu-5.1.5 && \ + echo extension=apcu.so > /usr/local/etc/php/conf.d/apcu.ini && \ + pecl install uuid && \ + echo extension=uuid.so > /usr/local/etc/php/conf.d/uuid.ini + + +RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ + && php composer-setup.php && php -r "unlink('composer-setup.php');" \ + && mv composer.phar /usr/local/bin/composer + +## Cleanup +RUN apt-get purge -y \ + g++ \ + git \ + && rm -rf /var/lib/apt/lists/* + +#ACPU +RUN pecl install apcu-${APCU_VERSION} && docker-php-ext-enable apcu +RUN echo "extension=apcu.so" >> /usr/local/etc/php/php.ini +RUN echo "apc.enable_cli=1" >> /usr/local/etc/php/php.ini +RUN echo "apc.enable=1" >> /usr/local/etc/php/php.ini + +RUN echo 'alias sf="php app/console"' >> ~/.bashrc +RUN echo 'alias sf3="php bin/console"' >> ~/.bashrc + +ADD ./uploads.ini /usr/local/etc/php/conf.d/uploads.ini + +ADD ./www.conf /usr/local/etc/php-fpm.d/ + +#ENCRYPTION +RUN apt-get update && apt-get install -y git +RUN git clone https://github.com/jedisct1/libsodium --branch stable +RUN cd libsodium && ./configure && make && make check && make install +RUN pecl install -f libsodium +RUN echo "extension = sodium.so" >> /usr/local/etc/php/php.ini + +#Sockets for amqp +RUN docker-php-ext-install sockets \ No newline at end of file diff --git a/twake/docker/php7.1-cassandra/uploads.ini b/twake/docker/php7.1-cassandra/uploads.ini new file mode 100644 index 00000000..15ef60b7 --- /dev/null +++ b/twake/docker/php7.1-cassandra/uploads.ini @@ -0,0 +1,5 @@ +file_uploads = On +memory_limit = 5G +upload_max_filesize = 5G +post_max_size = 5G +max_execution_time = 600 diff --git a/twake/docker/php7.1-cassandra/www.conf b/twake/docker/php7.1-cassandra/www.conf new file mode 100644 index 00000000..e57f7e4f --- /dev/null +++ b/twake/docker/php7.1-cassandra/www.conf @@ -0,0 +1,20 @@ +[www] + +user = www-data +group = www-data + +listen = /run/php/php7.0-fpm.sock + +listen.owner = www-data +listen.group = www-data + +; 30 childen if php is alone on 2cpu + 2go ram: --> 2go ram available - 0.5 (margin) divided by 50mo (average ram by process) +pm = ondemand +pm.max_children = 50 +pm.process_idle_timeout = 10s +pm.max_requests = 100 + +catch_workers_output = yes +php_flag[display_errors] = on +php_admin_value[error_log] = /var/log/fpm-php.www.log +php_admin_flag[log_errors] = on diff --git a/twake/docker/twake-nginx-php-only/Dockerfile b/twake/docker/twake-nginx-php-only/Dockerfile new file mode 100644 index 00000000..97aa8eab --- /dev/null +++ b/twake/docker/twake-nginx-php-only/Dockerfile @@ -0,0 +1,52 @@ + +FROM debian:11 + +RUN apt-get update && apt-get -y install cron + +RUN apt-get update && apt-get install -y \ + nginx + +RUN apt-get update && apt-get install -y wget + +RUN rm /etc/nginx/sites-enabled/default + +RUN usermod -u 1000 www-data + +RUN apt-get remove certbot +RUN apt-get install -y python3 python3-venv libaugeas0 +RUN python3 -m venv /opt/certbot/ +RUN /opt/certbot/bin/pip install --upgrade pip +RUN /opt/certbot/bin/pip install certbot +RUN ln -s /opt/certbot/bin/certbot /usr/bin/certbot + +ADD docker/twake-nginx-php-only/nginx.conf /etc/nginx/nginx.conf + +# Install yarn +RUN apt-get update +RUN apt-get -y install curl +RUN apt-get -y install apt-transport-https ca-certificates apt-utils gnupg +RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - +RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list +RUN apt-get update +RUN apt-get -y install yarn +RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - +RUN apt-get install -y nodejs +RUN yarn global add webpack +RUN yarn global add webpack-cli +RUN apt-get update +RUN apt-get -y install git + +# Install php + +ADD docker/twake-nginx/site.conf /etc/nginx/sites-available/site.template +ADD docker/twake-nginx-php-only/nginx.conf /etc/nginx/nginx.conf +RUN apt-get update && apt-get install gettext-base + +RUN echo "upstream php-upstream { server php:9000; }" > /etc/nginx/conf.d/upstream.conf + +COPY docker/twake-nginx-php-only/entrypoint.sh / +RUN chmod 0777 /entrypoint.sh +ENTRYPOINT /entrypoint.sh + +EXPOSE 80 +EXPOSE 443 diff --git a/twake/docker/twake-nginx-php-only/entrypoint.sh b/twake/docker/twake-nginx-php-only/entrypoint.sh new file mode 100644 index 00000000..6aea2e40 --- /dev/null +++ b/twake/docker/twake-nginx-php-only/entrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +NODE_HOST="${NODE_HOST:-http://node:3000}" +PHP_UPSTREAM="${PHP_UPSTREAM:-php:9000}" +export NODE_HOST +export PHP_UPSTREAM +envsubst '$${NODE_HOST}' < /etc/nginx/sites-available/site.template > /etc/nginx/sites-enabled/site +echo "upstream php-upstream { server ${PHP_UPSTREAM}; }" > /etc/nginx/conf.d/upstream.conf + +cron -f & +nginx -g "daemon off;" diff --git a/twake/docker/twake-nginx-php-only/nginx.conf b/twake/docker/twake-nginx-php-only/nginx.conf new file mode 100644 index 00000000..4e801068 --- /dev/null +++ b/twake/docker/twake-nginx-php-only/nginx.conf @@ -0,0 +1,65 @@ +user www-data; +worker_processes 4; +pid /run/nginx.pid; + +events { + worker_connections 768; + # multi_accept on; +} + +http { + + client_max_body_size 200M; + + ## + # Basic Settings + ## + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + # server_tokens off; + + # server_names_hash_bucket_size 64; + # server_name_in_redirect off; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + ## + # SSL Settings + ## + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE + ssl_prefer_server_ciphers on; + + ## + # Logging Settings + ## + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + ## + # Gzip Settings + ## + + gzip on; + gzip_disable "msie6"; + + # gzip_vary on; + # gzip_proxied any; + # gzip_comp_level 6; + # gzip_buffers 16 8k; + # gzip_http_version 1.1; + # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + ## + # Virtual Host Configs + ## + + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/sites-enabled/*; +} diff --git a/twake/docker/twake-nginx-php-only/site.conf b/twake/docker/twake-nginx-php-only/site.conf new file mode 100644 index 00000000..5a0ae1e4 --- /dev/null +++ b/twake/docker/twake-nginx-php-only/site.conf @@ -0,0 +1,66 @@ +server { + + listen 80; + server_name localhost; + root /twake-core/web; + + add_header Strict-Transport-Security "max-age=31536000"; + + location / { + return 302 https://web.twake.app/; + } + + location ~ ^/(internal|plugins).* { + proxy_pass http://node:3000; + } + + location ~ ^/(api|administration)/v2/.* { + proxy_pass http://node:3000; + } + + location ~ ^/socket/.* { + proxy_pass http://node:3000; + # this magic is needed for WebSocket + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_connect_timeout 7d; + proxy_send_timeout 7d; + proxy_read_timeout 7d; + } + + location ~ ^/(ajax|api|administration|upload|bundle|medias).* { + # try to serve file directly, fallback to rewrite + try_files $uri @rewriteapp; + } + + location @rewriteapp { + # rewrite all to app.php + rewrite ^(.*)$ /app.php/$1 last; + } + + location ~ /.well-known { + allow all; + } + + location ~ ^/(app|app_dev|config|dev\/.*)\.php(/|$) { + fastcgi_pass php-upstream; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param HTTPS off; + fastcgi_buffer_size 128k; + fastcgi_buffers 4 256k; + fastcgi_busy_buffers_size 256k; + } + + location ~ /.well-known { + allow all; + } + + error_log /var/log/nginx/twakeapp_dev_error.log; + access_log /var/log/nginx/twakeapp_dev_access.log; + +} diff --git a/twake/docker/twake-nginx/Dockerfile b/twake/docker/twake-nginx/Dockerfile new file mode 100755 index 00000000..144df56c --- /dev/null +++ b/twake/docker/twake-nginx/Dockerfile @@ -0,0 +1,31 @@ +# First stage: building frontend +FROM node:lts AS build + +RUN yarn global add webpack webpack-cli +COPY frontend /twake-react/ + +WORKDIR /twake-react/ + +ENV GENERATE_SOURCEMAP=false +RUN cp /twake-react/src/app/environment/environment.ts.dist /twake-react/src/app/environment/environment.ts && \ + yarn install --network-timeout 1000000000 && \ + # cat /twake-react/src/app/environment/environment.ts.dist && \ + # cat /twake-react/src/app/environment/environment.ts && \ + yarn build && \ + rm -rf node_modules + +# Second stage: configuring nginx and copying build artifacts +FROM nginx:latest +COPY docker/twake-nginx/nginx.conf /etc/nginx/nginx.conf +COPY docker/twake-nginx/site.conf /etc/nginx/sites-available/site.template +COPY docker/twake-nginx/redirect.conf /etc/nginx/sites-available/redirect +COPY docker/twake-nginx/entrypoint.sh / +COPY docker/twake-nginx/self-signed.sh /usr/local/bin/ +COPY --from=build /twake-react /twake-react + +RUN chmod +x /entrypoint.sh && rm /etc/nginx/conf.d/default.conf + +ENTRYPOINT ["/entrypoint.sh", "$DEV"] + +EXPOSE 80 +EXPOSE 443 diff --git a/twake/docker/twake-nginx/entrypoint.sh b/twake/docker/twake-nginx/entrypoint.sh new file mode 100755 index 00000000..2d7ee37c --- /dev/null +++ b/twake/docker/twake-nginx/entrypoint.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +if [ "$1" = "dev" ] +then + if test -f "/twake-react/src/app/environment/environment.ts"; then + echo "Configuration exists, doing nothing." + else + cp /twake-react/src/app/environment/environment.ts.dist.dev /twake-react/src/app/environment/environment.ts + fi +else + if test -f "/configuration/environment.ts"; then + cp /configuration/environment.ts /twake-react/src/app/environment/environment.ts + else + cp /twake-react/src/app/environment/environment.ts.dist /twake-react/src/app/environment/environment.ts + fi +fi + +[[ -d "/etc/nginx/sites-enabled" ]] || mkdir /etc/nginx/sites-enabled + +function _selfsigned() { + self-signed.sh + export NGINX_LISTEN="443 ssl" + ln -sf /etc/nginx/sites-available/redirect /etc/nginx/sites-enabled/ +} + +case $SSL_CERTS in + selfsigned) + _selfsigned + ;; + off|no|non|none|false) + export NGINX_LISTEN="80" + sed -i '/ *ssl_/d' /etc/nginx/sites-available/site.template + ;; + *) + echo: "SSL_CERTS var not defined setting selfsigned" + export SSL_CERTS=selfsigned + _selfsigned + ;; +esac + +NODE_HOST="${NODE_HOST:-http://node:3000}" +PHP_UPSTREAM="${PHP_UPSTREAM:-php:9000}" +export NODE_HOST +export PHP_UPSTREAM +envsubst '$${NODE_HOST} $${NGINX_LISTEN}' < /etc/nginx/sites-available/site.template > /etc/nginx/sites-enabled/site +echo "upstream php-upstream { server ${PHP_UPSTREAM}; }" > /etc/nginx/conf.d/upstream.conf + +nginx -g "daemon off;" diff --git a/twake/docker/twake-nginx/nginx.conf b/twake/docker/twake-nginx/nginx.conf new file mode 100644 index 00000000..4e801068 --- /dev/null +++ b/twake/docker/twake-nginx/nginx.conf @@ -0,0 +1,65 @@ +user www-data; +worker_processes 4; +pid /run/nginx.pid; + +events { + worker_connections 768; + # multi_accept on; +} + +http { + + client_max_body_size 200M; + + ## + # Basic Settings + ## + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + # server_tokens off; + + # server_names_hash_bucket_size 64; + # server_name_in_redirect off; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + ## + # SSL Settings + ## + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE + ssl_prefer_server_ciphers on; + + ## + # Logging Settings + ## + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + ## + # Gzip Settings + ## + + gzip on; + gzip_disable "msie6"; + + # gzip_vary on; + # gzip_proxied any; + # gzip_comp_level 6; + # gzip_buffers 16 8k; + # gzip_http_version 1.1; + # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + ## + # Virtual Host Configs + ## + + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/sites-enabled/*; +} diff --git a/twake/docker/twake-nginx/redirect.conf b/twake/docker/twake-nginx/redirect.conf new file mode 100644 index 00000000..78d040a0 --- /dev/null +++ b/twake/docker/twake-nginx/redirect.conf @@ -0,0 +1,7 @@ +server { + listen 80; + server_name localhost; + location / { + return 302 https://$server_name$request_uri; + } +} diff --git a/twake/docker/twake-nginx/self-signed.sh b/twake/docker/twake-nginx/self-signed.sh new file mode 100755 index 00000000..b4412342 --- /dev/null +++ b/twake/docker/twake-nginx/self-signed.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# Script to create selfsigned certificates if they don't exist. All certificate +# information can be customized using env variables. +# Licence: GPL +# Note: derivated from https://gitlab.com/live9/docker/containers/openssl/-/blob/master/entrypoint +# +set -eo pipefail +[ "${DEBUG}" = "yes" ] && set -x + +SSL_PATH="/etc/nginx/ssl/" +SSL_KEY="${SSL_PATH}/selfsigned.key" +SSL_CERT_REQUEST="${SSL_PATH}/selfsigned.csr" +SSL_CERTIFICATE="${SSL_PATH}/selfsigned.crt" +SSL_DHPARAM_FILE="${SSL_PATH}/dhparam.pem" + +# Certificate creation params +SSL_VALID_DAYS="${SSL_VALID_DAYS:-365}" +SSL_SUBJ_COUNTRY="${SSL_SUBJ_COUNTRY:-FR}" +SSL_SUBJ_STATE="${SSL_SUBJ_STATE:-Hauts-de-France}" +SSL_SUBJ_LOCALITY="${SSL_SUBJ_LOCALITY:-Paris}" +SSL_SUBJ_ORG="${SSL_SUBJ_ORG:-Linagora}" +SSL_SUBJ_ORG_UNIT="${SSL_SUBJ_ORG_UNIT:- Twake}" +SSL_SUBJ_CN="${SSL_SUBJ_CN:-localhost}" +SSL_SUBJECT="/C=${SSL_SUBJ_COUNTRY}/ST=${SSL_SUBJ_STATE}/L=${SSL_SUBJ_LOCALITY}/O=${SSL_SUBJ_ORG}/OU=${SSL_SUBJ_ORG_UNIT}/CN=${SSL_SUBJ_CN}" +SSL_KEY_LENGTH=${SSL_KEY_LENGTH:-2048} + + +if [ ! -f ${SSL_CERTIFICATE} ]; then + echo "Creating certificate sigining request..." + mkdir -p ${SSL_PATH} + openssl req \ + -newkey rsa:${SSL_KEY_LENGTH} \ + -sha256 \ + -nodes \ + -keyout ${SSL_KEY} \ + -out ${SSL_CERT_REQUEST} \ + -subj "${SSL_SUBJECT}" + echo "Creating self-signed certificate..." + openssl x509 -req -days ${SSL_VALID_DAYS} \ + -in ${SSL_CERT_REQUEST} \ + -signkey ${SSL_KEY} \ + -out ${SSL_CERTIFICATE} + + echo "Creating dhparam file..." + # When SSL_DHPARAM_FILE is present the whole process is done + openssl dhparam -out ${SSL_DHPARAM_FILE}.tmp ${SSL_KEY_LENGTH} + mv ${SSL_DHPARAM_FILE}.tmp ${SSL_DHPARAM_FILE} + + echo "Done." +else + echo "Selfsigned certificate already exists, skipping." +fi diff --git a/twake/docker/twake-nginx/site.conf b/twake/docker/twake-nginx/site.conf new file mode 100644 index 00000000..12740940 --- /dev/null +++ b/twake/docker/twake-nginx/site.conf @@ -0,0 +1,111 @@ +server { + listen ${NGINX_LISTEN}; + ssl_dhparam /etc/nginx/ssl/dhparam.pem; + ssl_certificate /etc/nginx/ssl/selfsigned.crt; + ssl_certificate_key /etc/nginx/ssl/selfsigned.key; + + server_name localhost; + root /twake-core/web; + + add_header Strict-Transport-Security "max-age=31536000"; + + location /.well-known { + alias /twake-react/build/.well-known/; + + gzip on; + gzip_disable "msie6"; + + add_header Cache-Control "no-store, public, max-age=0"; + add_header Cross-Origin-Opener-Policy 'same-origin-allow-popups; report-to="DurableDeepLinkUi"'; + add_header Cross-Origin-Resource-Policy "same-site"; + add_header Content-Type "application/json; charset=utf-8"; + add_header Last-Modified ""; + add_header Vary "Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site"; + add_header X-Content-Type-Options "nosniff"; + add_header X-Frame-Options "SAMEORIGIN"; + add_header X-XSS-Protection "0"; + + proxy_buffering off; + if_modified_since off; + expires 0s; + allow all; + + try_files $uri /index.html; + } + + location / { + gzip on; + gzip_disable "msie6"; + + gzip_comp_level 6; + gzip_min_length 1100; + gzip_buffers 16 8k; + gzip_proxied any; + gzip_types + text/plain + text/css + text/js + text/xml + text/javascript + application/javascript + application/x-javascript + application/json + application/xml + application/rss+xml + image/svg+xml; + alias /twake-react/build/; + allow all; + try_files $uri /index.html; + } + + location ~ ^/(internal).* { + proxy_set_header X-Forwarded-Host $host; + proxy_pass ${NODE_HOST}; + } + + location ~ ^/(plugins).* { + set $target http://plugins_container:8080; + proxy_set_header X-Forwarded-Host $host; + proxy_pass $target; + } + + location ~ ^/(api|administration/v2/).* { + proxy_set_header X-Forwarded-Host $host; + proxy_pass ${NODE_HOST}; + } + + location ~ ^/socket/.* { + proxy_pass ${NODE_HOST}; + # this magic is needed for WebSocket + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_connect_timeout 7d; + proxy_send_timeout 7d; + proxy_read_timeout 7d; + } + + location ~ ^/(ajax|api|administration|upload|bundle|medias).* { + # try to serve file directly, fallback to rewrite + try_files $uri @rewriteapp; + } + + location @rewriteapp { + # rewrite all to app.php + rewrite ^(.*)$ /app.php/$1 last; + } + + location ~ ^/(app|app_dev|config|dev\/.*)\.php(/|$) { + fastcgi_pass php-upstream; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param HTTPS off; + fastcgi_buffer_size 128k; + fastcgi_buffers 4 256k; + fastcgi_busy_buffers_size 256k; + } + +} diff --git a/twake/docker/twake-node/Dockerfile b/twake/docker/twake-node/Dockerfile new file mode 100755 index 00000000..344cc8fd --- /dev/null +++ b/twake/docker/twake-node/Dockerfile @@ -0,0 +1,66 @@ +# Common node machine +FROM node:lts as node-base + +### Install dependancies +RUN apt-get update && \ + apt-get install -y ghostscript graphicsmagick wget unoconv libxml2-dev ffmpeg python-is-python3 && \ + # upgrade unoconv + wget -N https://raw.githubusercontent.com/dagwieers/unoconv/master/unoconv -O /usr/bin/unoconv && \ + chmod +x /usr/bin/unoconv +#Docker mac issue +# RUN apt-get update && apt-get install -y libc6 +# RUN ln -s /lib/libc.musl-x86_64.so.1 /lib/ld-linux-x86-64.so.2 + + +### Install Twake + +WORKDIR /usr/src/app +COPY backend/node/package*.json ./ + +# Test Stage +FROM node-base as test + +RUN npm install +COPY backend/node/ . + +# Add frontend Stage +FROM node-base as with-frontend + +COPY backend/node/ . +#Install dev dependancies for build +RUN NODE_ENV=development npm install && \ + #Build in production mode + export NODE_ENV=production && \ + npm run build && \ + rm -rf node_modules && \ + #Install prod dependancies after build + npm install --legacy-peer-deps + +# Add frontend into node +COPY frontend/ ../public_build/ +RUN export NODE_ENV=development && \ + apt-get install -y build-essential && \ + cd ../public_build/ && \ + yarn install --network-timeout 1000000000 && \ + yarn global add webpack webpack-cli jest && \ + cp src/app/environment/environment.ts.dist src/app/environment/environment.ts && \ + export NODE_ENV=production && \ + yarn build && \ + rm -R node_modules && \ + mv build/* ../app/public && \ + cd .. && rm -R public_build/ + +# Development Stage +FROM with-frontend as development + +ENV NODE_ENV=development +RUN npm install -g pino-pretty && \ + npm install -g tsc-watch && \ + yarn install +CMD ["npm", "run", "dev:debug"] + +# Production Stage +FROM with-frontend as production + +EXPOSE 3000 +CMD ["npm", "run", "serve"] diff --git a/twake/docker/twake-php/Dockerfile b/twake/docker/twake-php/Dockerfile new file mode 100755 index 00000000..dd57e7bd --- /dev/null +++ b/twake/docker/twake-php/Dockerfile @@ -0,0 +1,18 @@ +FROM twaketech/php7.1-cassandra + +LABEL org.opencontainers.image.authors="Romaric Mourgues ,Nguyen Thai " + +#Crontab +ADD docker/twake-php/crontab /etc/cron.d/twake-cron +COPY backend/core/ /twake-core/ +COPY docker/twake-php/entrypoint.sh / + +RUN chmod 0644 /etc/cron.d/twake-cron && \ + touch /var/log/cron.log && \ + cd /twake-core/ && php composer.phar install && \ + chmod +x /entrypoint.sh + +#For exec +WORKDIR /twake-core/ + +ENTRYPOINT ["/entrypoint.sh", "$DEV"] diff --git a/twake/docker/twake-php/crontab b/twake/docker/twake-php/crontab new file mode 100644 index 00000000..a9b9a00c --- /dev/null +++ b/twake/docker/twake-php/crontab @@ -0,0 +1,30 @@ +# /etc/crontab: system-wide crontab +# Unlike any other crontab you don't have to run the `crontab' +# command to install the new version when you edit this file +# and files in /etc/cron.d. These files also have username fields, +# that none of the other crontabs do. + +SHELL=/bin/sh +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +# m h dom mon dow user command +* * * * * root cd /twake-core/; php bin/console twake:mails_queue; +* * * * * root cd /twake-core/; php bin/console twake:node:push_mobile; +* * * * * root cd /twake-core/; php bin/console twake:node:push_channel_activity; + +* * * * * root cd /twake-core/; php bin/console twake:calendar_check; +* * * * * root cd /twake-core/; php bin/console twake:tasks_check_reminders; + +* * * * * root cd /twake-core/; php bin/console twake:notifications_mail; + +* * * * * root cd /twake-core/; php bin/console twake:preview_worker; + +* * * * * root cd /twake-core/; php bin/console twake:scheduled_notifications_consume_timetable +* * * * * root cd /twake-core/; php bin/console twake:scheduled_notifications_consume_shard + +* * * * * root chmod -R 777 /twake-core/cache; + +32 * * * * root kill -USR2 1; +# +# + diff --git a/twake/docker/twake-php/entrypoint.sh b/twake/docker/twake-php/entrypoint.sh new file mode 100644 index 00000000..acd4aa39 --- /dev/null +++ b/twake/docker/twake-php/entrypoint.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +if [ -z "$TIMEZONE" ]; then + TIMEZONE=Etc/UTC +fi + +echo $TIMEZONE > /etc/timezone && \ +dpkg-reconfigure -f noninteractive tzdata + +sed -i "s|;date.timezone =.*|date.timezone = $TIMEZONE|" /etc/php5/*/php.ini + +if [ -n "$PHP_MEMORY_LIMIT" ]; then + sed -i "s/^memory_limit =.*/memory_limit = $PHP_MEMORY_LIMIT/" /etc/php5/*/php.ini +fi + +chmod -R 777 /var/www & +chmod -R 777 /tmp/ +rm -R /tmp/* +chmod -R 777 /twake-core/ & +mkdir /twake-core/cache +chmod -R 777 /twake-core/cache & + +if [ "$1" = "dev" ] +then + if test -f "/twake-core/app/Configuration/Parameters.php"; then + echo "Configuration exists, doing nothing." + else + cp /twake-core/app/Configuration/Parameters.php.dist /twake-core/app/Configuration/Parameters.php + fi + + php composer.phar install +else + if test -f "/configuration/Parameters.php"; then + cp /configuration/Parameters.php /twake-core/app/Configuration/Parameters.php + else + cp /twake-core/app/Configuration/Parameters.php.dist /twake-core/app/Configuration/Parameters.php + fi +fi + +(php composer.phar dump-autoload --optimize; php composer.phar dump-autoload --classmap-authoritative; php composer.phar dump-autoload --apcu; php bin/console twake:schema:update; php bin/console twake:init; php bin/console twake:init_connector; php bin/console twake:mapping) & + +mkdir /twake-core/cache +chmod -R 777 /twake-core/cache & + +echo "" >> /etc/cron.d/twake-cron + +cron -f & +docker-php-entrypoint php-fpm diff --git a/twake/docker/twake-plugins/Dockerfile b/twake/docker/twake-plugins/Dockerfile new file mode 100644 index 00000000..06eca58d --- /dev/null +++ b/twake/docker/twake-plugins/Dockerfile @@ -0,0 +1,26 @@ +# syntax=docker/dockerfile:1 + + +FROM docker:20.10.17-dind-alpine3.16 + + +RUN apk add --update nodejs-current npm bash curl + +WORKDIR /usr/src/app + +COPY plugins/ . + +VOLUME /usr/src/app +RUN chmod -R +x scripts +RUN mv scripts/* /bin +RUN apk update +RUN apk add git + + + + + + + + + diff --git a/twake/frontend/.eslintignore b/twake/frontend/.eslintignore new file mode 100644 index 00000000..cf44e148 --- /dev/null +++ b/twake/frontend/.eslintignore @@ -0,0 +1 @@ +**/*.js \ No newline at end of file diff --git a/twake/frontend/.eslintrc.js b/twake/frontend/.eslintrc.js new file mode 100644 index 00000000..3318823e --- /dev/null +++ b/twake/frontend/.eslintrc.js @@ -0,0 +1,39 @@ +module.exports = { + env: { + browser: true, + es2021: true, + }, + extends: [ + 'eslint:recommended', + 'plugin:react/recommended', + 'plugin:@typescript-eslint/recommended', + ], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + ecmaVersion: 'latest', + sourceType: 'module', + }, + plugins: ['react', 'react-hooks', 'eslint-plugin-jsx-a11y', '@typescript-eslint'], + ignorePatterns: ['**/deprecated/*.js', '**/deprecated/*.jsx', '**/*.jsx'], + rules: { + 'react/display-name': 'off', + '@typescript-eslint/triple-slash-reference': 'off', + 'react/react-in-jsx-scope': 'off', + 'jsx-a11y/anchor-is-valid': 'off', + 'react-hooks/exhaustive-deps': 'off', + 'react/no-children-prop': 'off', + 'react/no-unescaped-entities': 'off', + 'no-async-promise-executor': 'off', + 'no-control-regex': 'warn', + '@typescript-eslint/no-this-alias': 'warn', + 'react/prop-types': 'warn', + 'no-useless-escape': 'warn', + '@typescript-eslint/no-empty-function': 'warn', + '@typescript-eslint/ban-types': 'warn', + '@typescript-eslint/ban-ts-comment': 'warn', + 'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx', '.ts', '.tsx'] }], + }, +}; diff --git a/twake/frontend/.gitignore b/twake/frontend/.gitignore new file mode 100644 index 00000000..9b9a9e1a --- /dev/null +++ b/twake/frontend/.gitignore @@ -0,0 +1,34 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules +/dist + +# testing +/coverage +/src/app/environment/environment.ts +/src/app/environment/*-e + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local +.bin + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +/.bin/ +/.idea/ +/public/dist/ +/public/public/dist/ +/storybook-static/ +/public/storybook/ +/public/styles/tailwind.css +/build/ +/counter-clone/ +__old +/public/styles/tailwind.css \ No newline at end of file diff --git a/twake/frontend/.gitlab-ci.yml b/twake/frontend/.gitlab-ci.yml new file mode 100644 index 00000000..f0483811 --- /dev/null +++ b/twake/frontend/.gitlab-ci.yml @@ -0,0 +1,18 @@ +image: node:9.4.0 + +before_script: + - apk update -qq && apk add git + +stages: + - test + +test: + stage: test + + script: + + - echo install front + - yarn install + - yarn run dev-build + + when: manual diff --git a/twake/frontend/.jsbeautifyrc b/twake/frontend/.jsbeautifyrc new file mode 100644 index 00000000..d14e98b9 --- /dev/null +++ b/twake/frontend/.jsbeautifyrc @@ -0,0 +1,13 @@ +{ + "html": { + "brace_style": "collapse", + "indent_char": " ", + "indent_scripts": "normal", + "indent_size": 2, + "wrap_indent": 8, + "wrap_line_length": 80, + "max_preserve_newlines": 1, + "preserve_newlines": true, + "unformatted": ["a", "sub", "sup", "b", "i", "u"] + } +} diff --git a/twake/frontend/.prettierignore b/twake/frontend/.prettierignore new file mode 100644 index 00000000..41b07685 --- /dev/null +++ b/twake/frontend/.prettierignore @@ -0,0 +1,11 @@ +dist +vendor +node_modules +src/client/public +src/client/images +public +build +.idea +.storybook +.git +utils/scaffolds diff --git a/twake/frontend/.prettierrc b/twake/frontend/.prettierrc new file mode 100644 index 00000000..a6d54033 --- /dev/null +++ b/twake/frontend/.prettierrc @@ -0,0 +1,10 @@ +{ + "printWidth": 100, + "tabWidth": 2, + "useTabs": false, + "semi": true, + "singleQuote": true, + "trailingComma": "all", + "bracketSpacing": true, + "arrowParens": "avoid" +} diff --git a/twake/frontend/.storybook/__mocks__/languages-service.js b/twake/frontend/.storybook/__mocks__/languages-service.js new file mode 100644 index 00000000..4d4230c8 --- /dev/null +++ b/twake/frontend/.storybook/__mocks__/languages-service.js @@ -0,0 +1,9 @@ +import en from '../../public/locales/en.json'; + +export default { + t: term => en[term] || term, +} + +export function decorator(story) { + return story(); +} diff --git a/twake/frontend/.storybook/main.js b/twake/frontend/.storybook/main.js new file mode 100644 index 00000000..5838a029 --- /dev/null +++ b/twake/frontend/.storybook/main.js @@ -0,0 +1,77 @@ +const path = require('path'); +const alias = require('../tsconfig.paths.json'); +const webpack = require("webpack"); + +module.exports = { + stories: ['../src/app/**/*.stories.tsx'], + addons: [ + '@storybook/addon-links', + '@storybook/addon-essentials', + '@storybook/preset-create-react-app', + 'storybook-dark-mode', + ], + framework: '@storybook/react', + webpackFinal(config, { configType }) { + let updatedAlias = {}; + for (const key in alias?.compilerOptions?.paths || {}) { + updatedAlias[key.replace(/\/\*$/, '')] = path.resolve( + __dirname, + '../' + alias?.compilerOptions?.paths?.[key][0].replace(/\/\*$/, ''), + ); + } + config = { + ...config, + resolve: { + ...config.resolve, + roots: [ + ...(config.resolve.roots || []), + path.resolve(__dirname, '../public'), + 'node_modules', + ], + alias: { + ...updatedAlias, + ...config.resolve.alias, + }, + }, + }; + + config.module.rules.push({ + test: /\,css&/, + use: [ + { + loader: 'postcss-loader', + options: { + ident: 'postcss', + plugins: [require('tailwindcss'), require('autoprefixer')], + }, + }, + ], + include: path.resolve(__dirname, '../'), + }); + + config.plugins.push( + new webpack.NormalModuleReplacementPlugin( + /languages-service/, + path.resolve(__dirname, './__mocks__/languages-service.js'), + ) + ); + + return config; + }, + babel: async options => ({ + ...options, + presets: [ + ...options.presets, + [ + '@babel/preset-react', + { + runtime: 'automatic', + }, + 'preset-react-jsx-transform', // Can name this anything, just an arbitrary alias to avoid duplicate presets' + ], + ], + }), + core: { + builder: 'webpack5', + } +}; diff --git a/twake/frontend/.storybook/preview.js b/twake/frontend/.storybook/preview.js new file mode 100644 index 00000000..7a056834 --- /dev/null +++ b/twake/frontend/.storybook/preview.js @@ -0,0 +1,20 @@ +import '../src/tailwind.css'; + +export const parameters = { + actions: { argTypesRegex: '^on[A-Z].*' }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/, + }, + }, + previewTabs: { + 'storybook/docs/panel': { index: -1 }, + }, + darkMode: { + stylePreview: true, + }, + docs: { + source: { type: 'code' } + }, +}; diff --git a/twake/frontend/config/env.js b/twake/frontend/config/env.js new file mode 100644 index 00000000..09ec03c5 --- /dev/null +++ b/twake/frontend/config/env.js @@ -0,0 +1,101 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const paths = require('./paths'); + +// Make sure that including paths.js after env.js will read .env variables. +delete require.cache[require.resolve('./paths')]; + +const NODE_ENV = process.env.NODE_ENV; +if (!NODE_ENV) { + throw new Error( + 'The NODE_ENV environment variable is required but was not specified.' + ); +} + +// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use +const dotenvFiles = [ + `${paths.dotenv}.${NODE_ENV}.local`, + `${paths.dotenv}.${NODE_ENV}`, + // Don't include `.env.local` for `test` environment + // since normally you expect tests to produce the same + // results for everyone + NODE_ENV !== 'test' && `${paths.dotenv}.local`, + paths.dotenv, +].filter(Boolean); + +// Load environment variables from .env* files. Suppress warnings using silent +// if this file is missing. dotenv will never modify any environment variables +// that have already been set. Variable expansion is supported in .env files. +// https://github.com/motdotla/dotenv +// https://github.com/motdotla/dotenv-expand +dotenvFiles.forEach(dotenvFile => { + if (fs.existsSync(dotenvFile)) { + require('dotenv-expand')( + require('dotenv').config({ + path: dotenvFile, + }) + ); + } +}); + +// We support resolving modules according to `NODE_PATH`. +// This lets you use absolute paths in imports inside large monorepos: +// https://github.com/facebook/create-react-app/issues/253. +// It works similar to `NODE_PATH` in Node itself: +// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders +// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored. +// Otherwise, we risk importing Node.js core modules into an app instead of webpack shims. +// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421 +// We also resolve them to make sure all tools using them work consistently. +const appDirectory = fs.realpathSync(process.cwd()); +process.env.NODE_PATH = (process.env.NODE_PATH || '') + .split(path.delimiter) + .filter(folder => folder && !path.isAbsolute(folder)) + .map(folder => path.resolve(appDirectory, folder)) + .join(path.delimiter); + +// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be +// injected into the application via DefinePlugin in webpack configuration. +const REACT_APP = /^REACT_APP_/i; + +function getClientEnvironment(publicUrl) { + const raw = Object.keys(process.env) + .filter(key => REACT_APP.test(key)) + .reduce( + (env, key) => { + env[key] = process.env[key]; + return env; + }, + { + // Useful for determining whether we’re running in production mode. + // Most importantly, it switches React into the correct mode. + NODE_ENV: process.env.NODE_ENV || 'development', + // Useful for resolving the correct path to static assets in `public`. + // For example, . + // This should only be used as an escape hatch. Normally you would put + // images into the `src` and `import` them in code to get their paths. + PUBLIC_URL: publicUrl, + // We support configuring the sockjs pathname during development. + // These settings let a developer run multiple simultaneous projects. + // They are used as the connection `hostname`, `pathname` and `port` + // in webpackHotDevClient. They are used as the `sockHost`, `sockPath` + // and `sockPort` options in webpack-dev-server. + WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST, + WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH, + WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT, + } + ); + // Stringify all values so we can feed into webpack DefinePlugin + const stringified = { + 'process.env': Object.keys(raw).reduce((env, key) => { + env[key] = JSON.stringify(raw[key]); + return env; + }, {}), + }; + + return { raw, stringified }; +} + +module.exports = getClientEnvironment; diff --git a/twake/frontend/config/getHttpsConfig.js b/twake/frontend/config/getHttpsConfig.js new file mode 100644 index 00000000..013d493c --- /dev/null +++ b/twake/frontend/config/getHttpsConfig.js @@ -0,0 +1,66 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const crypto = require('crypto'); +const chalk = require('react-dev-utils/chalk'); +const paths = require('./paths'); + +// Ensure the certificate and key provided are valid and if not +// throw an easy to debug error +function validateKeyAndCerts({ cert, key, keyFile, crtFile }) { + let encrypted; + try { + // publicEncrypt will throw an error with an invalid cert + encrypted = crypto.publicEncrypt(cert, Buffer.from('test')); + } catch (err) { + throw new Error( + `The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}` + ); + } + + try { + // privateDecrypt will throw an error with an invalid key + crypto.privateDecrypt(key, encrypted); + } catch (err) { + throw new Error( + `The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${ + err.message + }` + ); + } +} + +// Read file and throw an error if it doesn't exist +function readEnvFile(file, type) { + if (!fs.existsSync(file)) { + throw new Error( + `You specified ${chalk.cyan( + type + )} in your env, but the file "${chalk.yellow(file)}" can't be found.` + ); + } + return fs.readFileSync(file); +} + +// Get the https config +// Return cert files if provided in env, otherwise just true or false +function getHttpsConfig() { + const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env; + const isHttps = HTTPS === 'true'; + + if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) { + const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE); + const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE); + const config = { + cert: readEnvFile(crtFile, 'SSL_CRT_FILE'), + key: readEnvFile(keyFile, 'SSL_KEY_FILE'), + }; + + validateKeyAndCerts({ ...config, keyFile, crtFile }); + return config; + } + return isHttps; +} + +module.exports = getHttpsConfig; diff --git a/twake/frontend/config/jest/cssTransform.js b/twake/frontend/config/jest/cssTransform.js new file mode 100644 index 00000000..8f651148 --- /dev/null +++ b/twake/frontend/config/jest/cssTransform.js @@ -0,0 +1,14 @@ +'use strict'; + +// This is a custom Jest transformer turning style imports into empty objects. +// http://facebook.github.io/jest/docs/en/webpack.html + +module.exports = { + process() { + return 'module.exports = {};'; + }, + getCacheKey() { + // The output is always the same. + return 'cssTransform'; + }, +}; diff --git a/twake/frontend/config/jest/fileTransform.js b/twake/frontend/config/jest/fileTransform.js new file mode 100644 index 00000000..aab67618 --- /dev/null +++ b/twake/frontend/config/jest/fileTransform.js @@ -0,0 +1,40 @@ +'use strict'; + +const path = require('path'); +const camelcase = require('camelcase'); + +// This is a custom Jest transformer turning file imports into filenames. +// http://facebook.github.io/jest/docs/en/webpack.html + +module.exports = { + process(src, filename) { + const assetFilename = JSON.stringify(path.basename(filename)); + + if (filename.match(/\.svg$/)) { + // Based on how SVGR generates a component name: + // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6 + const pascalCaseFilename = camelcase(path.parse(filename).name, { + pascalCase: true, + }); + const componentName = `Svg${pascalCaseFilename}`; + return `const React = require('react'); + module.exports = { + __esModule: true, + default: ${assetFilename}, + ReactComponent: React.forwardRef(function ${componentName}(props, ref) { + return { + $$typeof: Symbol.for('react.element'), + type: 'svg', + ref: ref, + key: null, + props: Object.assign({}, props, { + children: ${assetFilename} + }) + }; + }), + };`; + } + + return `module.exports = ${assetFilename};`; + }, +}; diff --git a/twake/frontend/config/modules.js b/twake/frontend/config/modules.js new file mode 100644 index 00000000..c8efd0dd --- /dev/null +++ b/twake/frontend/config/modules.js @@ -0,0 +1,141 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const paths = require('./paths'); +const chalk = require('react-dev-utils/chalk'); +const resolve = require('resolve'); + +/** + * Get additional module paths based on the baseUrl of a compilerOptions object. + * + * @param {Object} options + */ +function getAdditionalModulePaths(options = {}) { + const baseUrl = options.baseUrl; + + // We need to explicitly check for null and undefined (and not a falsy value) because + // TypeScript treats an empty string as `.`. + if (baseUrl == null) { + // If there's no baseUrl set we respect NODE_PATH + // Note that NODE_PATH is deprecated and will be removed + // in the next major release of create-react-app. + + const nodePath = process.env.NODE_PATH || ''; + return nodePath.split(path.delimiter).filter(Boolean); + } + + const baseUrlResolved = path.resolve(paths.appPath, baseUrl); + + // We don't need to do anything if `baseUrl` is set to `node_modules`. This is + // the default behavior. + if (path.relative(paths.appNodeModules, baseUrlResolved) === '') { + return null; + } + + // Allow the user set the `baseUrl` to `appSrc`. + if (path.relative(paths.appSrc, baseUrlResolved) === '') { + return [paths.appSrc]; + } + + // If the path is equal to the root directory we ignore it here. + // We don't want to allow importing from the root directly as source files are + // not transpiled outside of `src`. We do allow importing them with the + // absolute path (e.g. `src/Components/Button.js`) but we set that up with + // an alias. + if (path.relative(paths.appPath, baseUrlResolved) === '') { + return null; + } + + // Otherwise, throw an error. + throw new Error( + chalk.red.bold( + "Your project's `baseUrl` can only be set to `src` or `node_modules`." + + ' Create React App does not support other values at this time.' + ) + ); +} + +/** + * Get webpack aliases based on the baseUrl of a compilerOptions object. + * + * @param {*} options + */ +function getWebpackAliases(options = {}) { + const baseUrl = options.baseUrl; + + if (!baseUrl) { + return {}; + } + + const baseUrlResolved = path.resolve(paths.appPath, baseUrl); + + if (path.relative(paths.appPath, baseUrlResolved) === '') { + return { + src: paths.appSrc, + }; + } +} + +/** + * Get jest aliases based on the baseUrl of a compilerOptions object. + * + * @param {*} options + */ +function getJestAliases(options = {}) { + const baseUrl = options.baseUrl; + + if (!baseUrl) { + return {}; + } + + const baseUrlResolved = path.resolve(paths.appPath, baseUrl); + + if (path.relative(paths.appPath, baseUrlResolved) === '') { + return { + '^src/(.*)$': '/src/$1', + }; + } +} + +function getModules() { + // Check if TypeScript is setup + const hasTsConfig = fs.existsSync(paths.appTsConfig); + const hasJsConfig = fs.existsSync(paths.appJsConfig); + + if (hasTsConfig && hasJsConfig) { + throw new Error( + 'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.' + ); + } + + let config; + + // If there's a tsconfig.json we assume it's a + // TypeScript project and set up the config + // based on tsconfig.json + if (hasTsConfig) { + const ts = require(resolve.sync('typescript', { + basedir: paths.appNodeModules, + })); + config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config; + // Otherwise we'll check if there is jsconfig.json + // for non TS projects. + } else if (hasJsConfig) { + config = require(paths.appJsConfig); + } + + config = config || {}; + const options = config.compilerOptions || {}; + + const additionalModulePaths = getAdditionalModulePaths(options); + + return { + additionalModulePaths: additionalModulePaths, + webpackAliases: getWebpackAliases(options), + jestAliases: getJestAliases(options), + hasTsConfig, + }; +} + +module.exports = getModules(); diff --git a/twake/frontend/config/paths.js b/twake/frontend/config/paths.js new file mode 100644 index 00000000..b3fd764a --- /dev/null +++ b/twake/frontend/config/paths.js @@ -0,0 +1,72 @@ +'use strict'; + +const path = require('path'); +const fs = require('fs'); +const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath'); + +// Make sure any symlinks in the project folder are resolved: +// https://github.com/facebook/create-react-app/issues/637 +const appDirectory = fs.realpathSync(process.cwd()); +const resolveApp = relativePath => path.resolve(appDirectory, relativePath); + +// We use `PUBLIC_URL` environment variable or "homepage" field to infer +// "public path" at which the app is served. +// webpack needs to know it to put the right + + + + + diff --git a/twake/frontend/public/locales/.prettierrc b/twake/frontend/public/locales/.prettierrc new file mode 100644 index 00000000..65e6dbcb --- /dev/null +++ b/twake/frontend/public/locales/.prettierrc @@ -0,0 +1,10 @@ +{ + "printWidth": 100, + "tabWidth": 4, + "useTabs": false, + "semi": true, + "singleQuote": true, + "trailingComma": "all", + "bracketSpacing": true, + "arrowParens": "avoid" +} diff --git a/twake/frontend/public/locales/cleanup.js b/twake/frontend/public/locales/cleanup.js new file mode 100644 index 00000000..8dee867b --- /dev/null +++ b/twake/frontend/public/locales/cleanup.js @@ -0,0 +1,66 @@ +/** This too will clean up the languages keys if they are not used anywhere in the code */ + +const fs = require('fs'); +const path = require('path'); + +const dryRun = false; + +let allKeys = {}; +const files = fs.readdirSync(__dirname); +for (const file of files) { + if (file.indexOf('.json') >= 0) { + const content = JSON.parse(fs.readFileSync(__dirname + '/' + file)); + allKeys = { ...allKeys, ...content }; + } +} +allKeys = Object.keys(allKeys); + +console.log(allKeys.length); + +let srcFiles = []; +let srcPath = __dirname + '/../../src/'; +function throughDirectory(directory) { + fs.readdirSync(directory).forEach(file => { + const abs = path.join(directory, file); + if (fs.statSync(abs).isDirectory()) return throughDirectory(abs); + else return srcFiles.push(abs); + }); +} +throughDirectory(srcPath); + +const foundKeys = {}; +for (const srcFile of srcFiles) { + if ( + srcFile.indexOf('.tsx') >= 0 || + srcFile.indexOf('.ts') >= 0 || + srcFile.indexOf('.jsx') >= 0 || + srcFile.indexOf('.js') >= 0 + ) { + const content = fs.readFileSync(srcFile); + for (const key of allKeys) { + if (!foundKeys[key]) foundKeys[key] = 0; + //We keep the apps translations + if (content.indexOf(key) >= 0 || key.indexOf('app.name.') === 0) { + foundKeys[key]++; + } + } + } +} + +const found = Object.keys(foundKeys).filter(key => foundKeys[key] > 0); +const notFound = Object.keys(foundKeys).filter(key => foundKeys[key] == 0); + +console.log('Found: ', found.length); +console.log('Not found: ', notFound.length); + +if (!dryRun) { + for (const file of files) { + if (file.indexOf('.json') >= 0) { + const content = JSON.parse(fs.readFileSync(__dirname + '/' + file)); + for (const remove of notFound) { + delete content[remove]; + } + fs.writeFileSync(__dirname + '/' + file, JSON.stringify(content, null, 4)); + } + } +} diff --git a/twake/frontend/public/locales/de.json b/twake/frontend/public/locales/de.json new file mode 100644 index 00000000..36f994d5 --- /dev/null +++ b/twake/frontend/public/locales/de.json @@ -0,0 +1,1008 @@ +{ + "general.close": "Schließen", + "general.save": "Speichern", + "general.cancel": "Abbrechen", + "general.create": "Erstellen", + "general.edit": "Bearbeiten", + "general.continue": "Weiter", + "general.back": "ZurΓΌck", + "general.confirm": "BestΓ€tigen", + "general.delete": "LΓΆschen", + "general.update": "Aktualisierung", + "general.remove": "LΓΆschen", + "general.add": "HinzufΓΌgen", + "scenes.app.workspaces.create_company.group_data": "Konfigurieren Sie Ihre neue Gruppe", + "scenes.app.workspaces.create_company.group_data.group_type": "Gruppenart", + "scenes.app.workspaces.create_company.group_data.group_type.company": "Unternehmen oder Unternehmensabteilung", + "scenes.app.workspaces.create_company.group_data.group_type.public_organization": "Γ–ffentliche Einrichtung", + "scenes.app.workspaces.create_company.group_data.group_type.university_school": "UniversitΓ€t oder Schule", + "scenes.app.workspaces.create_company.group_data.group_type.society_club_charity": "Firma, Verein oder Verband", + "scenes.app.workspaces.create_company.group_data.group_type.other_group": "Sonstige", + "scenes.app.workspaces.create_company.group_data.group_size": "Grâße der Gruppe", + "scenes.app.workspaces.create_company.group_data.group_size.less_3": "Weniger als 4 Personen", + "scenes.app.workspaces.create_company.group_data.group_size.4_10": "4 - 10 Personen", + "scenes.app.workspaces.create_company.group_data.group_size.10_50": "11 - 49 Personen", + "scenes.app.workspaces.create_company.group_data.group_size.50_100": "50 - 99 Personen", + "scenes.app.workspaces.create_company.group_data.group_size.100_500": "100 - 499 Personen", + "scenes.app.workspaces.create_company.group_data.group_size.500_1000": "500 - 999 Personen", + "scenes.app.workspaces.create_company.group_data.group_size.1000_5000": "1000 - 4999 Personen", + "scenes.app.workspaces.create_company.group_data.group_size.5000_more": "Mehr als 5000 Personen", + "scenes.app.workspaces.create_company.group_data.group_main_activity": "HaupttΓ€tigkeit", + "scenes.app.workspaces.create_company.group_data.group_main_activity.food": "Lebensmittelindustrie", + "scenes.app.workspaces.create_company.group_data.group_main_activity.bank": "Bank / Versicherung", + "scenes.app.workspaces.create_company.group_data.group_main_activity.printing_paper": "Druckerei / Papier", + "scenes.app.workspaces.create_company.group_data.group_main_activity.construction_building": "Baumaterialien / Bauwirtschaft", + "scenes.app.workspaces.create_company.group_data.group_main_activity.real_estate": "Immobilien", + "scenes.app.workspaces.create_company.group_data.group_main_activity.materials": "Werkstoffe", + "scenes.app.workspaces.create_company.group_data.group_main_activity.chemistry": "Chemie", + "scenes.app.workspaces.create_company.group_data.group_main_activity.trade_commerce_distribution": "Handel / Verkauf / Vertrieb", + "scenes.app.workspaces.create_company.group_data.group_main_activity.publishing_communication_multimedia": "Verlagswesen / Kommunikation / Multimedia", + "scenes.app.workspaces.create_company.group_data.group_main_activity.electronics_electricity_energy": "Elektronik / ElektrizitΓ€t / Energie", + "scenes.app.workspaces.create_company.group_data.group_main_activity.studies_and_advice": "Planung und Beratung", + "scenes.app.workspaces.create_company.group_data.group_main_activity.pharmaceutical_industry": "Pharmazeutische Industrie", + "scenes.app.workspaces.create_company.group_data.group_main_activity.it_telecom": "IT / Telekommunikation", + "scenes.app.workspaces.create_company.group_data.group_main_activity.machinery_automotive": "Maschinenbau / Automobil", + "scenes.app.workspaces.create_company.group_data.group_main_activity.business_services": "Unternehmensdienste", + "scenes.app.workspaces.create_company.group_data.group_main_activity.entertainment": "Unterhaltung", + "scenes.app.workspaces.create_company.group_data.group_main_activity.textile_clothing_shoes": "Textilien / Kleidung / Schuhe", + "scenes.app.workspaces.create_company.group_data.group_main_activity.transport_logistics": "Transport / Logistik", + "scenes.app.workspaces.create_company.group_data.group_main_activity.research": "Forschung", + "scenes.app.workspaces.create_company.group_data.group_main_activity.education": "Bildung", + "scenes.app.workspaces.create_company.group_data.group_main_activity.administration": "Verwaltung", + "scenes.app.workspaces.create_company.group_data.group_main_activity.other": "Sonstige", + "components.application.messages": "Nachrichten", + "components.drive_dropzone.uploading": "Hochladen ...", + "components.user_picker.modal_no_result": "Kein Ergebnis gefunden", + "components.users_picker.add_me": "Mich hinzufΓΌgen", + "scenes.app.workspaces.create_company.invitations.title": "Konfigurieren Sie Ihren Arbeitsbereich.", + "scenes.app.header.disconnected": "Sie sind nicht verbunden", + "scenes.app.header.disconnected.reload": "Neu laden", + "scenes.app.header.alt_notifications": "Benachrichtigungen", + "scenes.apps.calendar.calendar.week_btn": "Woche", + "scenes.apps.calendar.calendar.list_btn": "Liste", + "scenes.apps.calendar.event_edition.deadline_tag": "FΓ€lligkeit", + "scenes.apps.calendar.event_edition.checkbox_all_day": "GanztΓ€gig", + "scenes.apps.calendar.event_edition.title_confidentiality": "Teilnehmer", + "scenes.apps.calendar.event_view.article_until": "bis", + "scenes.apps.calendar.calendar_modal.participants": "Teilnehmer", + "scenes.apps.calendar.calendar_modal.placeholder": "Name", + "scenes.apps.calendar.left.calendars": "Kalender", + "scenes.apps.drive.left.search": "Suchen", + "scenes.apps.drive.navigators.navigator_content.directory_name": "Verzeichnisname", + "scenes.apps.drive.navigators.navigator_content.files": "Dateien", + "scenes.apps.drive.navigators.navigator_labels.title": "Etiketten", + "scenes.apps.drive.navigators.new_file.untitled": "Unbenannt", + "scenes.apps.drive.navigators.new_file.create_file.type": "Art", + "scenes.apps.drive.navigators.new_file": "Neue Datei", + "scenes.apps.drive.preview_bloc.operations_download": "Herunterladen", + "scenes.apps.drive.preview_bloc.error_file": "Datei nicht gefunden", + "scenes.apps.drive.right_preview.operations_restore": "Wiederherstellen", + "scenes.apps.drive.right_preview.operations_delete": "In den Papierkorb", + "scenes.apps.drive.right_preview.public_link": "Γ–ffentlicher Link", + "scenes.apps.messages.messages": "Nachrichten", + "scenes.apps.messages.chatbox.chat.delete_message": "Diese Nachricht lΓΆschen", + "scenes.apps.messages.chatbox.chat.delete_message_btn": "LΓΆschen", + "scenes.apps.messages.left_bar.stream_modal.placeholder_name": "Name", + "scenes.apps.parameters.workspace_sections.workspace": "Arbeitsbereich", + "scenes.apps.parameters.workspace_sections.members": "Teilnehmende", + "scenes.apps.parameters.group_sections.workspaces": "Arbeitsbereiche", + "scenes.apps.parameters.group_sections.apps": "Anwendungen", + "scenes.apps.account.title": "Kontoeinstellungen", + "scenes.apps.account.account.menu_title": "Konto", + "scenes.apps.account.languages.menu_title": "Sprachen", + "scenes.apps.account.account.firstname": "Vorname", + "scenes.apps.account.account.lastname": "Nachname", + "scenes.apps.account.account.username": "Benutzername", + "scenes.apps.account.account.change_username": "Γ„ndern Sie Ihren eindeutigen Benutzernamen.", + "scenes.apps.account.account.emails": "E-Mail-Adressen", + "scenes.apps.account.account.main_email": "Haupt-E-Mail-Adresse", + "scenes.apps.account.account.email_add": "Neue E-Mail-Adresse hinzufΓΌgen", + "scenes.apps.account.account.email_add_modal.invalid_code": "Dieser Code ist ungΓΌltig", + "scenes.apps.account.account.password": "Passwort", + "scenes.apps.account.account.password_modal.old_password": "Aktuelles Passwort", + "scenes.apps.account.account.password_modal.password": "Neues Passwort", + "scenes.apps.account.account.password_modal.bad_old_password": "Das alte Passwort ist falsch.", + "scenes.apps.account.account.password_modal.bad_password": "Ihre PasswΓΆrter stimmen nicht ΓΌberein oder sind zu kurz; bitte geben Sie ein Passwort mit mindestens 8 Zeichen ein.", + "scenes.apps.account.account.logout": "Abmelden", + "scenes.apps.account.languages.text": "Sprache von Twake Γ€ndern.", + "scenes.apps.account.notifications.title": "Benachrichtigungen", + "scenes.apps.account.notifications.keywords_subtitle": "SchlΓΌsselwΓΆrter", + "scenes.apps.account.notifications.keywords_placeholder": "Dev, WLAN, Code, ...", + "scenes.apps.account.notifications.disturb_option_a": "Keine Benachrichtigungen auf mein Telefon senden zwischen ", + "scenes.apps.account.notifications.disturb_option_b": " und ", + "scenes.apps.account.notifications.disturb_option_c": " (lokale Zeitzone)", + "scenes.apps.account.notifications.devices_subtitle": "Benachrichtigungen auf PeripheriegerΓ€te", + "scenes.apps.account.notifications.devices_option_ever": "Senden Sie mir immer Benachrichtigungen auf mein Telefon", + "scenes.apps.account.notifications.devices_option_inactive": "Senden Sie mir Benachrichtigungen auf mein Telefon, wenn ich auf dem Arbeitsplatzrechner nicht aktiv bin", + "scenes.apps.account.notifications.devices_option_never": "Senden Sie niemals Benachrichtigungen auf mein Telefon", + "scenes.apps.account.notifications.privacy_subtitle": "IntimitΓ€t", + "scenes.apps.account.notifications.mail_subtitle": "E-Mail-Benachrichtigungen", + "scenes.apps.parameters.group_sections.apps.badge_extension": "Erweiterung", + "scenes.apps.parameters.workspace_sections.members.members": "Mitglieder", + "scenes.apps.parameters.workspace_sections.members.pending": "Ausstehende E-Mails", + "scenes.apps.parameters.workspace_sections.members.invite": "Neue Mitglieder einladen", + "scenes.apps.parameters.workspace_sections.members.invite_btn": "Mitglieder hinzufΓΌgen", + "scenes.apps.tasks.boards": "Tabellen", + "scenes.apps.tasks.new_board.title": "Neue Tabelle", + "scenes.apps.tasks.new_board.edit_title": "Tabelle bearbeiten", + "scenes.apps.tasks.task": "Aufgabe", + "scenes.apps.tasks.no_tasks": "Keine Aufgabe", + "scenes.apps.tasks.task_status.todo": "Zu erledigen", + "scenes.apps.tasks.task_status.current": "In Bearbeitung", + "scenes.apps.tasks.task_status.done": "Beendet", + "scenes.apps.tasks.task.description": "Beschreibung", + "scenes.apps.tasks.task.assignees": "Zugewiesen", + "scenes.apps.tasks.task.edit.dates": "Daten", + "scenes.apps.tasks.list_modal.modify_list": "Liste bearbeiten", + "scenes.apps.tasks.list_modal.new_list": "Neue Liste", + "scenes.apps.tasks.list_modal.remove": "Liste und Aufgaben lΓΆschen", + "scenes.login.footer.go_to_twake": "Auf twakeapp.com gehen", + "scenes.login.create_account.title": "Neues Konto einrichten", + "scenes.login.create_account.email": "E-Mail-Adresse", + "scenes.login.create_account.email_used": "Diese E-Mail-Adresse wird bereits verwendet.", + "scenes.login.create_account.username": "Benutzername", + "scenes.login.create_account.username_already_exist": "Dieser Benutzername ist bereits vergeben", + "scenes.login.create_account.fill_in_username": "Sie mΓΌssen einen Benutzernamen wΓ€hlen", + "scenes.login.create_account.fill_in_email": "Sie mΓΌssen eine korrekte Adresse im E-Mail-Feld eingeben", + "scenes.login.create_account.too_short_password": "Ihr Passwort muss mindestens 8 Zeichen umfassen.", + "scenes.login.create_account.firstname": "Vorname", + "scenes.login.create_account.newsletter": "Erhalten Sie Informationen ΓΌber Twake", + "scenes.login.create_account.lastname": "Nachname", + "scenes.login.forgot_password.title": "Passwort vergessen?", + "scenes.login.forgot_password.text": "Sie erhalten 9 Ziffern per E-Mail, um Ihre IdentitΓ€t zu bestΓ€tigen.", + "scenes.login.forgot_password.email_to_recover": "Wiederherstellungs-Mail-Adresse", + "scenes.login.forgot_password.mail_doesnt_exist": "Diese E-Mail-Adresse existiert nicht", + "scenes.login.forgot_password.text2": "Sie erhalten einen 9-stelligen Code; bitte geben Sie ihn in das folgende Feld ein, um fortzufahren.", + "scenes.login.forgot_password.invalid_code": "Dieser Code ist ungΓΌltig.", + "scenes.login.forgot_password.text3": "Bitte geben Sie ein neues Passwort ein.", + "scenes.login.forgot_password.password": "Passwort", + "scenes.login.forgot_password.password2": "BestΓ€tigen Sie das Passwort", + "scenes.login.forgot_password.password_dont_match": "Ihre PasswΓΆrter stimmen nicht ΓΌberein oder sind zu kurz; bitte geben Sie ein Passwort mit mindestens 8 Zeichen ein.", + "scenes.login.home.title": "Auf Twake anmelden", + "scenes.login.home.email": "E-Mail-Adresse", + "scenes.login.home.unable_to_connect": "ID-Angaben ungΓΌltig", + "scenes.login.home.password": "Passwort", + "scenes.login.home.login_btn": "Anmelden", + "scenes.login.home.lost_password": "Passwort vergessen?", + "scenes.login.home.create_account": "Konto einrichten", + "general.help": "Hilfe", + "general.help.support": "UnterstΓΌtzung", + "general.help.documentation": "Dokumentation", + "scenes.login.footer.branding": "Sie befinden sich auf einem privaten {{$1}} ({{$2}}) Twake-Server. ", + "scenes.login.home.subtitle": "SchΓΆn dich zu sehen", + "scenes.login.create_account.password": "Passwort", + "scenes.login.create_account.step_1_subtitle": "Nichts einfacher als das, wir brauchen nur ein paar Informationen.", + "scenes.login.create_account.step_2_subtitle_a": "FΓΌgen Sie Ihren vollstΓ€ndigen Namen fΓΌr Ihre Mitarbeiter hinzu, um Sie zu erkennen.", + "scenes.login.create_account.step_2_subtitle_b": "Ihre Telefonnummer bleibt privat.", + "scenes.login.create_account.step_3_mail_sent": "Wir haben Ihnen einen Aktivierungslink per E-Mail geschickt.", + "scenes.login.create_account.step_3_subtitle": "Im letzten Schritt mΓΌssen wir sicherstellen, dass Sie kein Roboter sind!", + "scenes.app.workspaces.create_company.company_name.placeholder": "Name der Firma", + "scenes.app.workspaces.create_company.company_name.title_1": "Beginnen,", + "scenes.app.workspaces.create_company.company_name.title_2": "zunΓ€chst den Namen Ihres Unternehmens an.", + "scenes.app.workspaces.create_company.default_workspace_name": "PrimΓ€r", + "scenes.app.workspaces.create_company.group_data.title": "Machen wir es schnell, wir brauchen nur statistische Informationen.", + "scenes.app.workspaces.create_company.importations.title_1": "Arbeiten Sie bereits mit digitalen Tools? Importieren oder integrieren Sie Ihre Tools jetzt!", + "scenes.app.workspaces.create_company.importations.title_2": "Keine Sorge, das kΓΆnnen Sie spΓ€ter machen!", + "scenes.app.workspaces.create_company.invitations.title_2": "HinzufΓΌgen Ihrer Teammitglieder.", + "scenes.app.workspaces.create_company.title": "Schaffe meine Firma", + "scenes.app.workspaces.welcome_page.add_secondary_emails": "FΓΌgen Sie eine sekundΓ€re E-Mail hinzu", + "scenes.app.workspaces.welcome_page.added_to_company": "Sie wurden zu dieser Firma eingeladen: ", + "scenes.app.workspaces.welcome_page.create_my_company": "Schaffe meine Firma", + "scenes.app.workspaces.welcome_page.lets_go": "Lass uns gehen!", + "scenes.app.workspaces.welcome_page.may_be_invited_with_secondary_emails": "Sie wurden mΓΆglicherweise mit einer anderen E-Mail-Adresse eingeladen?", + "scenes.app.workspaces.welcome_page.no_company_subtitle": "Noch hat Sie niemand zu irgendeiner Firma eingeladen.", + "scenes.app.workspaces.welcome_page.ready_to_work": "Sie kΓΆnnen jetzt arbeiten.", + "scenes.app.workspaces.welcome_page.see_you_soon": "Wir sehen uns!", + "scenes.app.workspaces.welcome_page.try_again": "Versuchen Sie es nochmal", + "scenes.app.workspaces.welcome_page.twake_team": "Twake", + "scenes.app.workspaces.welcome_page.welcome_header": "Willkommen bei Twake!", + "scenes.app.workspaces.welcome_page.add_secondary_emails_comment": "Sie kΓΆnnen mehrere E-Mail-Adressen mit Ihrem Konto verknΓΌpfen, es wird nur eine Adresse verwendet, um Ihnen Benachrichtigungen zu senden.", + "scenes.app.workspaces.welcome_page.main_mail_title": "Hauptadresse", + "scenes.app.workspaces.welcome_page.other_mail_title": "SekundΓ€radressen", + "scenes.app.workspaces.welcome_page.add_new_email": "Eine E-Mail hinzufΓΌgen", + "scenes.app.workspaces.welcome_page.code_verification": "BestΓ€tigungscode", + "scenes.app.workspaces.welcome_page.new_email": "HinzufΓΌgen einer sekundΓ€ren E-Mail", + "scenes.app.workspaces.welcome_page.we_sent_you_mail": "Wir haben Ihnen einen Verifizierungscode ΓΌber {{$1}} geschickt", + "scenes.app.workspaces.welcome_page.done": "Ich bin fertig", + "scenes.login.forgot_password.finished": "Ihr Passwort wurde erfolgreich aktualisiert.", + "scenes.apps.account.account.description_main": "Ihre Hauptadresse ist diejenige, an die Twake Ihre Benachrichtigungen sendet. Ihre sekundΓ€ren Adressen ermΓΆglichen es Ihnen, automatisch zu den Arbeitsbereichen eingeladen zu werden, die sie verwenden.", + "scenes.apps.account.account.emails.description": "Verwalten Sie Ihre verschiedenen E-Mail-Adressen.", + "scenes.apps.account.account.make_main": "Hauptleitung einstellen", + "scenes.apps.account.account.password.description": "Γ„ndern Sie Ihr Passwort.", + "scenes.apps.account.identity": "IdentitΓ€t", + "scenes.apps.account.identity.description": "Γ„ndere deinen Vornamen, Nachnamen und dein Profilbild fΓΌr andere Twake-Benutzer sichtbar.", + "scenes.apps.account.preference": "PrΓ€ferenzen", + "general.open": "Offen", + "scenes.apps.account.thumbnail.max_weight": "Maximales Gewicht 5 mo", + "scenes.apps.account.account.email_add_modal.confirm": "Diese E-Mail bestΓ€tigen", + "app.name.twake_tasks": "Aufgaben", + "app.name.twake_calendar": "Kalender", + "app.name.twake_drive": "Dokumente", + "components.calendar.repetition.after": "FΓΌr", + "components.calendar.repetition.annually_on": "Jedes Jahr am {{$1}}", + "components.calendar.repetition.custom": "Benutzerdefiniert …", + "components.calendar.repetition.custom_recurrence": "Benutzerdefinierte Wiederholung", + "components.calendar.repetition.days": "Tag(e)", + "components.calendar.repetition.does_not_repeat": "Wiederholt sich nicht", + "components.calendar.repetition.ends": "Endet", + "components.calendar.repetition.every_weekday": "Jeden Wochentag", + "components.calendar.repetition.everyday": "TΓ€glich", + "components.calendar.repetition.monthly_on": "Monatlich am {{$1}} {{$2}}", + "components.calendar.repetition.monthly_on_day": "Monatlich am {{$1}}", + "components.calendar.repetition.months": "Monat(e)", + "components.calendar.repetition.never": "Noch nie", + "components.calendar.repetition.occurrence": "Vorkommen", + "components.calendar.repetition.on": "Auf", + "components.calendar.repetition.repeat": "Wiederhole jeden", + "components.calendar.repetition.repeat_on": "Wiederholen Sie auf", + "components.calendar.repetition.weekly_on": "WΓΆchentlich am {{$1}}", + "components.calendar.repetition.weeks": "woche(n)", + "components.calendar.repetition.years": "jahr(e)", + "scenes.app.channelsbar.channel_leaving": "Kanal verlassen", + "scenes.app.channelsbar.channel_removing": "Kanal lΓΆschen", + "scenes.app.channelsbar.channelsuser.new_private_discussion": "Neue private Diskussion", + "scenes.app.channelsbar.channelsuser.no_private_message_invite_collaboraters": "Keine private Nachricht, laden Sie Ihre Mitarbeiter ein!", + "scenes.app.channelsbar.channelsuser.private_messages": "Private Nachrichten", + "scenes.app.channelsbar.channelsworkspace.channel_title": "KANΓ„LE", + "scenes.app.channelsbar.channelsworkspace.channel_title.favorite": "Favoriten", + "scenes.app.channelsbar.channelsworkspace.create_channel": "Erstelle einen Kanal", + "scenes.app.channelsbar.channelsworkspace.no_channel": "Du bist noch keinem Kanal beigetreten", + "scenes.app.channelsbar.company_invitation_alert_subtitle": "Sie kΓΆnnen diese KanΓ€le in Ihr Unternehmen importieren, um die Übersicht zu behalten, indem Sie auf diesen Rahmen klicken.", + "scenes.app.channelsbar.company_invitation_alert_title": "Sie werden in die Firma eingeladen ", + "scenes.app.channelsbar.currentuser.add_apps": "Suchen Sie nach Anwendungen", + "scenes.app.channelsbar.currentuser.change_my_status": "Γ„ndere meinen Status", + "scenes.app.channelsbar.currentuser.collaborateurs": "Mitarbeiter", + "scenes.app.channelsbar.currentuser.create_workspace_page": "Erstellen Sie einen Arbeitsbereich", + "scenes.app.channelsbar.currentuser.disable_notifications": "Deaktivieren", + "scenes.app.channelsbar.currentuser.disabling_notifications": "1 Stunde lang deaktivieren", + "scenes.app.channelsbar.currentuser.disabling_notifications_until": "Deaktivieren Sie bis morgen 9 Uhr", + "scenes.app.channelsbar.currentuser.invited_status": "Du bist ein Gast.", + "scenes.app.channelsbar.currentuser.logout": "Ausloggen", + "scenes.app.channelsbar.currentuser.reactivate_notifications": "Reaktivieren", + "scenes.app.channelsbar.currentuser.title": "Kontoeinstellungen", + "scenes.app.channelsbar.currentuser.update": "Aktualisieren", + "scenes.app.channelsbar.currentuser.user_parameter": "Benachrichtigungseinstellungen", + "scenes.app.channelsbar.currentuser.workspace_info": "Sie befinden sich im Arbeitsbereich {{$1}} aus der Gruppe {{$2}}", + "scenes.app.channelsbar.currentuser.workspace_parameters": "Arbeitsbereichseinstellungen", + "scenes.app.channelsbar.initial_instructions_tutorial": "WΓ€hle einen Vornamen, einen Namen und ein Profilbild.", + "scenes.app.channelsbar.installation_desktop_tutorial": "Installieren Sie die Desktopanwendung", + "scenes.app.channelsbar.invitation_collaboraors_tutorial": "Laden Sie Ihre Mitarbeiter in Ihren Arbeitsbereich ein.", + "scenes.app.channelsbar.modify_channel_menu": "Kanal bearbeiten", + "scenes.app.channelsbar.private_channel_label": "Privater Kanal", + "scenes.app.channelsbar.read_sign": "als gelesen markieren", + "scenes.app.channelsbar.sending_message_instruction": "Senden Sie eine erste Nachricht in einer Diskussion", + "scenes.app.channelsbar.tutorial_alert": "Diesen Rahmen nie wieder anzeigen?", + "scenes.app.channelsbar.unread_sign": "als ungelesen markieren", + "scenes.app.channelsbar.welcome": "Willkommen bei Twake", + "scenes.app.channelsbar.welcoming_message_subtitle": "Werden Sie mit nur wenigen Klicks ein Twake-Profi !", + "scenes.app.mainview.instruction_current_tab": "Beginnen Sie mit der Auswahl eines Kanals auf der linken Seite.", + "scenes.app.mainview.tabs.no_connected_connectors_for_channel": "Sie haben keinen Anschluss, der eine Verbindung zu einem Kanal herstellen kann.", + "scenes.app.mainview.tabs.rename": "Umbenennen", + "scenes.app.mainview.tabs.searching_connectors": "Konnektoren suchen ...", + "scenes.app.popup.adduser.adresses_message": "Bitte trennen Sie die Adressen mit einem Komma. Denken Sie daran, dass Twake die Anzahl der Einladungen basierend auf Ihrem Abonnement begrenzen kann.", + "scenes.app.popup.appsparameters.pages._app_identity": "IdentitΓ€t der Anwendung", + "scenes.app.popup.appsparameters.pages._appareance_message_twakcode": "Testen Sie das Erscheinungsbild Ihrer Twacode-Nachrichten", + "scenes.app.popup.appsparameters.pages.alert_published_app": "Ihre Bewerbung ist verΓΆffentlicht, Sie kΓΆnnen sie nicht bearbeiten.", + "scenes.app.popup.appsparameters.pages.allowed_ip_adresses_method": "Verwenden Sie * in der Entwicklung, um alle IP-Adressen zuzulassen.", + "scenes.app.popup.appsparameters.pages.amazing_app_name": "Meine tolle Anwendung", + "scenes.app.popup.appsparameters.pages.api_data_description": "NΓΌtzliche Daten fΓΌr die Twake-API.", + "scenes.app.popup.appsparameters.pages.api_parameters_label": "API-Einstellungen", + "scenes.app.popup.appsparameters.pages.app_modification_right": "Alle Manager dieses Unternehmens kΓΆnnen diese Anwendung bearbeiten.", + "scenes.app.popup.appsparameters.pages.app_privileges_information": "Definieren Sie, was Ihre Anwendung bearbeiten und lesen kann.", + "scenes.app.popup.appsparameters.pages.app_privileges_label": "Anwendungsrechte", + "scenes.app.popup.appsparameters.pages.application_title": "Anwendung", + "scenes.app.popup.appsparameters.pages.apps_connectors_small_text": "Erstellen und verwalten Sie Ihre Anwendungen und Konnektoren.", + "scenes.app.popup.appsparameters.pages.apps_title": "Ihre Anwendungen und Konnektoren", + "scenes.app.popup.appsparameters.pages.automatique_label": "Automatisch", + "scenes.app.popup.appsparameters.pages.automatique_option_information": "Wenn Sie \"Automatisch\" aktivieren, wird diese Anwendung automatisch zu den nΓ€chsten Arbeitsbereichen dieser Firma hinzugefΓΌgt.", + "scenes.app.popup.appsparameters.pages.autorised_ip_adresses_label": "ZulΓ€ssige IP-Adressen", + "scenes.app.popup.appsparameters.pages.available_publication_alert": "Die VerΓΆffentlichung Ihrer Bewerbung wartet derzeit auf die Validierung durch die Twake-Teams.", + "scenes.app.popup.appsparameters.pages.button_force": "Kraft im gesamten Unternehmen", + "scenes.app.popup.appsparameters.pages.company_label": "Firmeninhaber", + "scenes.app.popup.appsparameters.pages.configuration_label": "Aufbau", + "scenes.app.popup.appsparameters.pages.create_app_button": "Erstellen Sie eine Anwendung", + "scenes.app.popup.appsparameters.pages.create_my_app": "Meine Bewerbung erstellen", + "scenes.app.popup.appsparameters.pages.current_informations_apps_connectors": "Sie haben noch keine App erstellt. Stellen Sie vor dem Erstellen einer Anwendung oder eines Connectors sicher, dass diese nicht bereits auf unserem Anwendungsmarkt vorhanden ist.", + "scenes.app.popup.appsparameters.pages.danger_zone_description": "Anwendung lΓΆschen", + "scenes.app.popup.appsparameters.pages.danger_zone_label": "GefΓ€hrliche Zone", + "scenes.app.popup.appsparameters.pages.danger_zone_small_text": "Sie kΓΆnnen diese App nicht lΓΆschen, wenn sie verΓΆffentlicht ist.", + "scenes.app.popup.appsparameters.pages.description_label": "Beschreibung", + "scenes.app.popup.appsparameters.pages.developped_apps_subtitle": "Vom Unternehmen entwickelte Anwendungen", + "scenes.app.popup.appsparameters.pages.dispalyed_parameters_description": "Hier kΓΆnnen Sie festlegen, wo Ihre Anwendung sichtbar sein soll.", + "scenes.app.popup.appsparameters.pages.displayed_parameters_label": "Bildschirmeinstellungen", + "scenes.app.popup.appsparameters.pages.error_app_simple_name_message": "Der vereinfachte Name Ihrer Anwendung wird bereits von einer anderen Anwendung verwendet. Bitte Γ€ndern Sie ihn.", + "scenes.app.popup.appsparameters.pages.error_app_update_message": "Beim Aktualisieren der Anwendung ist ein Fehler aufgetreten.", + "scenes.app.popup.appsparameters.pages.error_check_needed": "Ein Fehler ist aufgetreten, ΓΌberprΓΌfen Sie Ihre Angaben.", + "scenes.app.popup.appsparameters.pages.error_message": "Dieser Name wird bereits von einer anderen Anwendung verwendet. Bitte wΓ€hlen Sie einen anderen aus.", + "scenes.app.popup.appsparameters.pages.error_user_code": "error", + "scenes.app.popup.appsparameters.pages.event_subtitle": "Veranstaltungen", + "scenes.app.popup.appsparameters.pages.filter_information": "Dieser Filter beschrΓ€nkt die Verwendung Ihres API-SchlΓΌssels auf Server in Ihrem Connector.", + "scenes.app.popup.appsparameters.pages.go_back": "ZurΓΌck", + "scenes.app.popup.appsparameters.pages.grp_section_name-error": "Dieser Name wird bereits von einer anderen Anwendung verwendet. Bitte wΓ€hlen Sie einen anderen aus.", + "scenes.app.popup.appsparameters.pages.grp_section_surname_label": "Vereinfachter Name", + "scenes.app.popup.appsparameters.pages.installation": "Instal.", + "scenes.app.popup.appsparameters.pages.instruction_message_twakecode": "Beginnen Sie, indem Sie Ihre Nachricht im JSON-Format schreiben.", + "scenes.app.popup.appsparameters.pages.interne_availability_application": "Interne Anwendung", + "scenes.app.popup.appsparameters.pages.json_configuration_information": "Rufen Sie die Dokumentation auf, um Ihre Konfiguration im JSON-Format zu generieren.", + "scenes.app.popup.appsparameters.pages.loading": "Wird geladen...", + "scenes.app.popup.appsparameters.pages.message_data_next_event": "Passive Daten, die beim nΓ€chsten Event gesendet werden", + "scenes.app.popup.appsparameters.pages.modify_public_data": "Bearbeiten Sie die ΓΆffentlichen Daten Ihrer Anwendung.", + "scenes.app.popup.appsparameters.pages.new_app_title": "Neue Bewerbung", + "scenes.app.popup.appsparameters.pages.optimal_format": "Optimales Format: 48x48px.", + "scenes.app.popup.appsparameters.pages.parameters_form_small_text": "Die unverΓΆffentlichte Anwendung funktioniert nur in Ihrem Unternehmen. Wenn Sie sie allen Twake-Benutzern zur VerfΓΌgung stellen mΓΆchten, aktivieren Sie diese Option.", + "scenes.app.popup.appsparameters.pages.public_availability_application": "Γ–ffentliche Bewerbung", + "scenes.app.popup.appsparameters.pages.public_login_label": "Γ–ffentliche Kennung", + "scenes.app.popup.appsparameters.pages.publication_description": "Bestimmen Sie die Sichtbarkeit Ihrer Anwendung.", + "scenes.app.popup.appsparameters.pages.publication_label": "VerΓΆffentlichung", + "scenes.app.popup.appsparameters.pages.publish_app_label": "Bewerbung verΓΆffentlichen", + "scenes.app.popup.appsparameters.pages.read_privileges_label": "Leserechte", + "scenes.app.popup.appsparameters.pages.remove_app": "LΓΆschen Sie die Anwendung {{$1}} dauerhaft.", + "scenes.app.popup.appsparameters.pages.remove_app_button": "Anwendung lΓΆschen", + "scenes.app.popup.appsparameters.pages.remove_app_from_company": "Entfernen Sie aus der gesamten Firma", + "scenes.app.popup.appsparameters.pages.remove_app_from_workspace": "Vom Arbeitsbereich entfernen", + "scenes.app.popup.appsparameters.pages.show_button": "Anzeigen", + "scenes.app.popup.appsparameters.pages.status_tilte": "Zustand", + "scenes.app.popup.appsparameters.pages.string_information": "Diese Zeichenfolge identifiziert Ihre Anwendung und wird in Nachrichtenbefehlen verwendet.", + "scenes.app.popup.appsparameters.pages.title_tester": "Twakecode-Tester", + "scenes.app.popup.appsparameters.pages.update_button": "Aktualisieren", + "scenes.app.popup.appsparameters.pages.url_reception_events_label": "URL des Veranstaltungsempfangs", + "scenes.app.popup.appsparameters.pages.waiting_availability_application": "Warten auf …", + "scenes.app.popup.appsparameters.pages.website_label": "Webseite", + "scenes.app.popup.appsparameters.pages.write_privileges_label": "Schreibrechte", + "scenes.app.popup.createworkspacepage.add_subtitle": "Brauche mehr Platz?", + "scenes.app.popup.createworkspacepage.create_new_workspace": "Erstellen Sie einen neuen Arbeitsbereich", + "scenes.app.popup.createworkspacepage.placeholder_name": "Name des Arbeitsbereichs", + "scenes.app.popup.userparameter.pages.frequency_notif_configuration_description": "Legen Sie die HΓ€ufigkeit von Handybenachrichtigungen fest.", + "scenes.app.popup.userparameter.pages.frequency_notif_subtitle": "HΓ€ufigkeit der Benachrichtigungen", + "scenes.app.popup.userparameter.pages.keywords_notif_description": "Markieren Sie die folgenden SchlΓΌsselwΓΆrter:", + "scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description": "Legen Sie die HΓ€ufigkeit der E-Mail-Benachrichtigungen fest.", + "scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description": "WΓ€hlen Sie einen Zeitraum aus, in dem Sie keine Benachrichtigungen erhalten.", + "scenes.app.popup.userparameter.pages.no_night_disturbing_label": "Bitte nicht nachts stΓΆren", + "scenes.app.popup.userparameter.pages.notif_content_label": "Inhalt der Mitteilungen", + "scenes.app.mainview.quick_search_placeholder": "Schnelle Suche", + "scenes.app.popup.userparameter.personnal_workspaces_title": "Ihre Arbeitsbereiche", + "scenes.app.popup.workspaceparameter.admin_current_status": "Sie sind Moderator.", + "scenes.app.popup.workspaceparameter.admin_manager_current_status": "Sie sind Direktor und Manager des Unternehmens.", + "scenes.app.popup.workspaceparameter.manager_current_status": "Sie sind der Manager des Unternehmens.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace": "Leerzeichen lΓΆschen", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace_description": "Um zu bestΓ€tigen, dass Sie diesen Arbeitsbereich lΓΆschen mΓΆchten, geben Sie bitte den Namen unten ein und drΓΌcken Sie auf LΓΆschen.", + "scenes.app.popup.workspaceparameter.pages.enter": "Eingeben ", + "scenes.app.popup.workspaceparameter.pages.access_apps": "Greifen Sie auf Ihre Anwendungen und Konnektoren zu", + "scenes.app.popup.workspaceparameter.pages.moderator_status": "Moderator", + "scenes.app.popup.workspaceparameter.pages.alert_impossible_removing": "Sie kΓΆnnen den Arbeitsbereich nicht verlassen, da Sie der letzte Moderator sind. Sie kΓΆnnen einen neuen Moderator definieren oder diesen Arbeitsbereich lΓΆschen / archivieren.", + "scenes.app.popup.workspaceparameter.pages.all_apps_small_text": "Alle Anwendungen", + "scenes.app.popup.workspaceparameter.pages.apps_company_small_text": "Bewerbungen Ihres Unternehmens", + "scenes.app.popup.workspaceparameter.pages.apps_connectors_title": "Integrationen", + "scenes.app.popup.workspaceparameter.pages.apps_research_title": "Suchen Sie nach Anwendungen", + "scenes.app.popup.workspaceparameter.pages.apps_small_text": "Anwendungen dieses Arbeitsbereichs", + "scenes.app.popup.workspaceparameter.pages.back_to_search_button": "ZurΓΌck zur Suche", + "scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button": "Benutzer einladen", + "scenes.app.popup.workspaceparameter.pages.collaborateurs": "Mitarbeiter", + "scenes.app.popup.workspaceparameter.pages.company_developped_apps_subtitle": "Vom Unternehmen entwickelte Anwendungen", + "scenes.app.popup.workspaceparameter.pages.company_identity_title": "IdentitΓ€t des Unternehmens", + "scenes.app.popup.workspaceparameter.pages.company_name_description": "Γ„ndern Sie den Namen dieser Firma", + "scenes.app.popup.workspaceparameter.pages.company_name_label": "Name der Firma", + "scenes.app.popup.workspaceparameter.pages.configuration_notif": "Aufbau", + "scenes.app.popup.workspaceparameter.pages.configure_button": "Konfigurieren", + "scenes.app.popup.workspaceparameter.pages.description": "Beschreibung", + "scenes.app.popup.workspaceparameter.pages.developped_apps_small_text": "Vom Unternehmen entwickelte Anwendungen", + "scenes.app.popup.workspaceparameter.pages.displayed_preferencies_subtitle": "Anzeigeeinstellungen", + "scenes.app.popup.workspaceparameter.pages.install_button": "Installieren", + "scenes.app.popup.workspaceparameter.pages.installed_app_information": "Installieren Sie die Anwendung in diesem Arbeitsbereich.", + "scenes.app.popup.workspaceparameter.pages.installed_apps_information": "In diesem Arbeitsbereich installierte Anwendungen {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_message": "Anwendungen in anderen Bereichen des Unternehmens installiert {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_subtitle": "Installierte Anwendungen", + "scenes.app.popup.workspaceparameter.pages.invitation_error": "Beim Einladen der folgenden Personen ist ein Fehler aufgetreten: ", + "scenes.app.popup.workspaceparameter.pages.invited_guest_check_message": "ÜberprΓΌfen Sie, ob der Benutzername oder die E-Mail-Adresse gΓΌltig ist.", + "scenes.app.popup.workspaceparameter.pages.logo_modify_description": "Bearbeiten Sie das Bild dieses Arbeitsbereichs", + "scenes.app.popup.workspaceparameter.pages.logo_subtitle": "Logo", + "scenes.app.popup.workspaceparameter.pages.name_description": "Γ„ndern Sie den Namen dieses Arbeitsbereichs", + "scenes.app.popup.workspaceparameter.pages.name_label": "Name des Arbeitsbereichs", + "scenes.app.popup.workspaceparameter.pages.no_access": "Kein Zugang.", + "scenes.app.popup.workspaceparameter.pages.no_app_information": "Sie haben keine Anwendungen in diesem Arbeitsbereich", + "scenes.app.popup.workspaceparameter.pages.quit_workspace_menu": "Verlasse diesen Arbeitsbereich", + "scenes.app.popup.workspaceparameter.pages.read_access_subtitle": "Lesezugriff", + "scenes.app.popup.workspaceparameter.pages.remove_from_company_text": "Entfernen Sie aus der gesamten Firma", + "scenes.app.popup.workspaceparameter.pages.research_by": "Suchen Sie Anwendungen nach Namen und Kategorien", + "scenes.app.popup.workspaceparameter.pages.researching_apps_button": "Anwendungen suchen ...", + "scenes.app.popup.workspaceparameter.pages.show_button": "Anzeige", + "scenes.app.popup.workspaceparameter.pages.title": "Arbeitsbereichseinstellungen", + "scenes.app.popup.workspaceparameter.pages.webhooks_access_subtitle": "Zugriff auf Webhooks", + "scenes.app.popup.workspaceparameter.pages.weight_max_small_text": "Maximale Grâße 5Β MB.", + "scenes.app.popup.workspaceparameter.pages.withdraw_button": "Aus diesem Arbeitsbereich entfernen", + "scenes.app.popup.workspaceparameter.pages.worspace_notif": "arbeitsplatz", + "scenes.app.popup.workspaceparameter.pages.write_access_subtitle": "Schreibzugriff", + "scenes.app.popup.workspaceparameter.pages.your_apps_label": "Ihre Bewerbungen", + "scenes.app.popup.workspaceparameter.payments_subscriptions_title": "Zahlungen und Abonnements", + "scenes.app.workspacesbar.components.change_company_title": "Γ„nderung der Firma", + "scenes.app.workspacesbar.components.create_company_menu": "Erstellen Sie eine Firma", + "scenes.app.workspacesbar.components.grp_parameters": "{{$1}} Einstellungen", + "scenes.apps.calendar.add_calendar_menu": "FΓΌgen Sie einen Kalender hinzu", + "scenes.apps.calendar.connectors_menu": "AnschlΓΌsse ...", + "scenes.apps.calendar.connectors_search_menu": "Konnektoren suchen ...", + "scenes.apps.calendar.create_calendar_title": "Erstellen Sie einen Kalender", + "scenes.apps.calendar.day_option": "Tag", + "scenes.apps.calendar.edit_calendar_title": "Bearbeiten Sie den Kalender", + "scenes.apps.calendar.export_title": "Export", + "scenes.apps.calendar.export_view_menu": "Ansicht exportieren ...", + "scenes.apps.calendar.ics_download_menu": "Laden Sie eine ICS-Datei herunter", + "scenes.apps.calendar.ics_subscription_menu": "Holen Sie sich einen ICS-Abonnement-Link", + "scenes.apps.calendar.modals.advanced_options": "Erweiterte Optionen", + "scenes.apps.calendar.modals.description_placeholder": "Beschreibung", + "scenes.apps.calendar.modals.details_title": "Einzelheiten", + "scenes.apps.calendar.modals.event_adresse_placeholder": "Adresse", + "scenes.apps.calendar.modals.event_description_placeholder": "Beschreibung", + "scenes.apps.calendar.modals.event_title_placeholder": "Titel", + "scenes.apps.calendar.modals.modify_event_button": "Event bearbeiten", + "scenes.apps.calendar.modals.part.participants": "Teilnehmer", + "scenes.apps.calendar.modals.participants_event": "Teilnehmer", + "scenes.apps.calendar.modals.reminders": "Erinnerungen", + "scenes.apps.calendar.modals.remove_button": "LΓΆschen", + "scenes.apps.calendar.modals.remove_event_button": "Ereignis lΓΆschen", + "scenes.apps.calendar.modals.remove_event_text": "Ereignis lΓΆschen ?", + "scenes.apps.calendar.modals.title_placeholder": "Titel", + "scenes.apps.calendar.modify_calendar_menu": "Bearbeiten Sie den Kalender", + "scenes.apps.calendar.month_option": "Monat", + "scenes.apps.calendar.my_calendar": "Mein Kalender", + "scenes.apps.calendar.my_calendar_label": "Mein Kalender", + "scenes.apps.calendar.my_calendar_menu": "Mein Kalender", + "scenes.apps.calendar.no_calendar_text": "Mein Sie haben fΓΌr diesen Arbeitsbereich keine Kalender festgelegt.", + "scenes.apps.calendar.no_connectors_menu_text": "Sie haben keine Connectors, die eine Verbindung zu einem Kalender herstellen kΓΆnnen.", + "scenes.apps.calendar.remove_calendar_confirmation": "Kalender und Termine endgΓΌltig lΓΆschen?", + "scenes.apps.calendar.today_menu": "Heute", + "scenes.apps.calendar.week_option": "Woche", + "scenes.apps.calendar.workspace": "Arbeitsplatz", + "scenes.apps.calendar.workspace_label": "Dieser Arbeitsbereich", + "scenes.apps.calendar.workspace_menu": "Arbeitsplatz", + "scenes.apps.drive.add_button": "HinzufΓΌgen", + "scenes.apps.drive.choose_folder_button": "WΓ€hlen Sie einen Datensatz", + "scenes.apps.drive.create_folder_button": "Erstellen", + "scenes.apps.drive.download_button": "Herunterladen", + "scenes.apps.drive.open_link": "Verbindung ΓΆffnen", + "scenes.apps.drive.files_subtitle": "Dateien", + "scenes.apps.drive.folder_subtitle": "Aufzeichnungen", + "scenes.apps.drive.go_out_trash_menu": "Raus aus dem MΓΌll", + "scenes.apps.drive.go_trash_menu": "Geh in den MΓΌll", + "scenes.apps.drive.import_from_computer_menu": "Vom Computer importieren", + "scenes.apps.drive.move_text": "Bewegung", + "scenes.apps.drive.new_file_menu": "Neue Datei", + "scenes.apps.drive.new_file_title": "Neue Datei", + "scenes.apps.drive.new_folder_title": "Neuer Eintrag", + "scenes.apps.drive.no_file_alert": "Sie haben keine Anwendung, mit der Sie eine Datei erstellen kΓΆnnen.", + "scenes.apps.drive.remove_definitely_menu": "Auf jeden Fall lΓΆschen", + "scenes.apps.drive.restore_menu": "Wiederherstellen", + "scenes.apps.drive.throw_menu": "In den MΓΌll werfen", + "scenes.apps.drive.trash_empty_menu": "Den Papierkorb leeren", + "scenes.apps.drive.unconfigured_tab": "Diese Registerkarte ist noch nicht konfiguriert.", + "scenes.apps.drive.viewer.edit_with_button": "Bearbeiten Sie mit {{$1}}", + "scenes.apps.drive.viewer.loading_preview_message": "Wird geladen...", + "scenes.apps.drive.viewer.no_preview_message": "Kann diese Art von Datei nicht anzeigen.", + "scenes.apps.drive.viewer.open_with_button": "Γ–ffnen mit...", + "scenes.apps.messages.input.placeholder": "Schreiben Sie eine Nachricht und zitieren Sie einen Benutzer mit @.", + "scenes.apps.messages.just_you": "Nur fΓΌr dich sichtbar", + "scenes.apps.messages.message.new_messages_bar": "Neue Nachrichten", + "scenes.apps.messages.message.cancel_button": "Stornieren", + "scenes.apps.messages.message.modify_button": "Bearbeiten", + "scenes.apps.messages.message.pinned": "Stift", + "scenes.apps.messages.message.remove_button": "Delete", + "scenes.apps.messages.message.reply_button": "Antworten", + "scenes.apps.messages.message.save_button": "Speichern", + "scenes.apps.messages.message.show_button": "Anzeige", + "scenes.apps.messages.message.show_responses_button": "Alle Antworten anzeigen", + "scenes.apps.messages.message.types.first_channel_message_text": "Dies ist die erste Nachricht des Kanals", + "scenes.apps.messages.message.types.first_message_text": "Dies ist die erste Nachricht", + "scenes.apps.messages.messageslist.get_writing_user": "schreibt...", + "scenes.apps.messages.messageslist.get_writing_users": "schreiben...", + "scenes.apps.messages.messageslist.go_last_message_button": "Gehe zum letzten Beitrag", + "scenes.apps.messages.messageslist.go_last_message_button.new_messages": "Neue Nachrichten", + "scenes.error_on_twake": "\"Houston, wir haben ein Problem\"", + "scenes.help_us": "Wenn Sie uns jedoch bei der Behebung dieses Fehlers helfen mΓΆchten, senden Sie uns die folgende Nachricht: ", + "scenes.login.verifymail.alert": "Wir ΓΌberprΓΌfen Ihre E-Mail !", + "scenes.login.verifymail.error_message": "Ein Fehler ist aufgetreten", + "scenes.login.verifymail.signin_button": "Einloggen", + "scenes.login.verifymail.success": "Ihre E-Mail wurde erfolgreich verifiziert !", + "scenes.login.verifymail.verification_waiting": "Warten auf ÜberprΓΌfung...", + "scenes.no_panic": "Keine Panik, lade diese Seite einfach neu, um Twake zu finden.", + "services.apps.calendar.deadline_icon": "Frist", + "services.apps.calendar.event_icon": "Veranstaltung", + "services.apps.calendar.move_icon": "Bewegung", + "services.apps.calendar.reminder_icon": "Erinnerung", + "services.apps.messages.no_app": "Diese Anwendung existiert nicht.", + "services.apps.messages.no_command_possible": "Der Befehl '{{$1}}' kann nicht ausgefΓΌhrt werden, da '{{$2}}' nicht vorhanden ist oder keine Befehle erstellt werden kΓΆnnen.", + "services.user.notification_parameters_update_alert": "Die Benachrichtigungseinstellungen wurden aktualisiert.", + "services.user.update_password_alert": "Dein Passwort wurde aktualisiert.", + "scenes.app.popup.appsparameters.pages.icon": "Symbol", + "general.send": "Abschicken", + "general.unarchive": "Dearchivieren", + "general.archive": "Archivieren", + "scenes.app.popup.appsparameters.pages.app_update": "App {{$1}} aktualisieren (Die App wird {{$2}} mal verwendet)", + "scenes.app.popup.appsparameters.pages.app_name_label": "Anwendungsname", + "scenes.app.channelsbar.public_channel_label": "Γ–ffentlich", + "scenes.app.channelsbar.guest_management": "GΓ€ste verwalten", + "scenes.apps.tasks.list_modal.remove_archived_tasks": "Archivierte Aufgaben entfernen ({{$1}})", + "scenes.apps.tasks.list_modal.archive_all_tasks": "Alle Aufgaben archivieren", + "scenes.apps.tasks.list_modal.predefined_participants": "Vordefinierte Teilnehmer", + "scenes.apps.tasks.choose_board_button": "Board auswΓ€hlen", + "scenes.apps.tasks.unconfigured_tab": "Dieser Tab ist noch nicht konfiguriert.", + "scenes.apps.tasks.no_connectors_menu_text": "Sie haben keine Konnektoren, die eine Verbindung zu einem Kalender herstellen kΓΆnnen.", + "scenes.apps.tasks.connectors_search_menu": "Konnektoren suchen...", + "scenes.apps.tasks.connectors_menu": "Konnektoren...", + "scenes.apps.account.notifications.sound": "Benachrichtigungston", + "scenes.apps.messages.left_bar.stream.notifications.never": "Nichts", + "scenes.apps.messages.left_bar.stream.notifications.me": "Nur {{$1}}", + "scenes.apps.messages.left_bar.stream.notifications.mentions": "{{$1}}, {{$2}} und {{$3}}", + "scenes.apps.messages.left_bar.stream.notifications.all": "Alle Nachrichten", + "scenes.apps.messages.left_bar.stream.notifications": "Benachrichtigungen...", + "scenes.apps.messages.left_bar.stream.remove_from_favorites": "Aus Favoriten entfernen", + "scenes.apps.messages.left_bar.stream.add_to_favorites": "Zu Favoriten hinzufΓΌgen", + "scenes.app.side_app.messages_thread_title": "{{$1}} β€’ Nachrichten-Thread", + "general.connexion_status.connecting": "Wiederverbinden…", + "general.connexion_status.connected": "Sie sind online", + "general.connexion_status.disconnected": "Sie sind offline", + "scenes.apps.drive.new_external_storage": "Neuer externer Speicher", + "scenes.apps.drive.choose_file_button": "Datei auswΓ€hlen", + "scenes.apps.drive.message_added_file_no_name": "{{$1}} hat eine Datei gesendet.", + "scenes.apps.drive.message_added_mutiple_files": "{{$1}} hat mehrere Dateien gesendet.", + "scenes.apps.drive.message_added_file": "{{$1}} hat {{$2}} gesendet.", + "scenes.app.popup.userparameter.pages.private_message_content.hide": "Inhalt privater Nachrichten verbergen", + "scenes.app.popup.userparameter.pages.private_message_content.show": "Inhalt privater Nachrichten anzeigen", + "scenes.app.popup.appsparameters.pages.ok_user_code": "ok", + "scenes.app.popup.appsparameters.pages.call_event_handlers": "Ereignis vom Typ {{$1}} und id {{$2}}, mit Handlern {{$3}}", + "components.emoji_picker.categories.not_found": "Kein Emoji gefunden", + "components.emoji_picker.categories.search_result": "Suchergebnisse", + "components.emoji_picker.categories.flags": "Flaggen", + "components.emoji_picker.categories.symbols": "Symbole", + "components.emoji_picker.categories.objects": "Objekte", + "components.emoji_picker.categories.travel_and_places": "Reisen & Orte", + "components.emoji_picker.categories.activity": "AktivitΓ€t", + "components.emoji_picker.categories.food_and_drink": "Essen & Trinken", + "components.emoji_picker.categories.animals_and_nature": "Tiere & Natur", + "components.emoji_picker.categories.smileys_and_people": "Smileys & Personen", + "components.emoji_picker.categories.frequently_used": "HΓ€ufig benutzt", + "components.upload.drop_files.toaster.error": "Sie kΓΆnnen nicht mehr als {{$1}} Dateien hochladen", + "general.uploading": "Hochladen", + "components.member.user_parts.and_more_user_text": " und {{$1}} mehr Benutzer", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_input_placeholder": "Sie kΓΆnnen nicht mehr als 10 Benutzer hinzufΓΌgen", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_text": " stattdessen", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_link": "Privaten Kanal erstellen", + "scenes.apps.messages.message.parts.deleted_content.text": "{{$1}} hat seine/ihre Nachricht gelΓΆscht", + "scenes.apps.messages.message.parts.deleted_content.text.current_user": "Sie haben diese Nachricht gelΓΆscht", + "services.apps.messages.message_editor_service.upload_error_toaster": "{{$1}} - Sie kΓΆnnen nicht mehr als {{$2}} Dateien in einer Nachricht hinzufΓΌgen", + "components.emoji_picker.input_search_placeholder": "Suchen", + "scenes.apps.drive.default_link_name": "Unbenannt", + "scenes.apps.drive.new_link_title": "Neue VerknΓΌpfung", + "scenes.client.main_view.main_header.search_input": "Suche", + "scenes.app.popup.workspaceparameter.pages.table_title": "Name", + "scenes.apps.messages.input.attach_file.from_computer": "Vom Computer", + "scenes.apps.tasks.select_user": "Benutzer suchen", + "scenes.apps.tasks.select_user_button": "Aufgaben anderer Benutzer anzeigen", + "components.on_boarding.popups.blocked_company.company_selector": "Zu einer anderen Organisation wechseln", + "components.on_boarding.popups.blocked_company.or": "Oder", + "components.on_boarding.popups.blocked_company.company_subscription_plan_button": "Hier klicken", + "components.on_boarding.popups.blocked_company.learn_more_text": "MΓΆchten Sie mehr ΓΌber den Abonnements fΓΌr Organisationen erfahren?", + "components.on_boarding.popups.blocked_company.description": "Ihr Abonnement fΓΌr Twake ist abgelaufen. Bitte kontaktieren Sie den Administrator Ihrer Organisation, um es zu erneuern und wieder mit Ihrem Team kommunizieren zu kΓΆnnen !", + "components.on_boarding.popups.blocked_company.title": "Ihre Organisation ist wegen eines Problems bei der Zahlungsabwicklung gesperrt", + "components.on_boarding.company_billing_banner.link": "Abonnement fΓΌr Organisationen", + "components.on_boarding.company_billing_banner.guest_or_member_text": "Es gibt ein Problem mit Ihrem Organisationsabonnement. Bitte kontaktieren Sie den Organisatinsadministrator!", + "components.on_boarding.company_billing_banner.admin_or_owner_text": "Es gibt ein Problem mit Ihrem Organisationsabonnement. Bitte prΓΌfen Sie Ihr", + "components.locked_features.locked_guests_popup.or": "Oder", + "components.locked_features.locked_guests_popup.skip_for_now_button": "Überspringen", + "components.locked_features.locked_guests_popup.learn_more_button": "Mehr erfahren", + "components.locked_features.locked_guests_popup.description": "Ups!!! Es scheint, dass Sie externe Benutzer zu Ihrem Arbeitsbereich einladen mΓΆchten. Sie sollten ein Upgrade Ihres Tarifs in Betracht ziehen, wenn Sie mit GΓ€sten und externen Partnern zusammenarbeiten mΓΆchten. PrΓΌfen Sie unsere Preisoptionen und wΓ€hlen Sie die beste Option fΓΌr Ihre Anforderungen an die Zusammenarbeit im Team.", + "components.locked_features.locked_guests_popup.subtitle": "Diese Funktion ist in der kostenlosen Version von Twake nicht verfΓΌgbar", + "components.locked_features.locked_guests_popup.title": "GΓ€stefunktion ist gesperrt", + "components.locked_features.locked_history_banner.button": "Mehr erfahren", + "components.locked_features.locked_history_banner.description": "Ihre Organisation hat eine Menge Nachrichten! Aktualisieren Sie jetzt, um auf den gesamten Nachrichtenverlauf zuzugreifen.", + "components.locked_features.locked_history_banner.title": "Sie haben das Nachrichtenlimit erreicht", + "components.richtexteditor.toolbar.code-block": "Code-Block", + "components.richtexteditor.toolbar.blockquote": "Feste Laufweite", + "components.richtexteditor.toolbar.ordered-list": "Nummerierung", + "components.richtexteditor.toolbar.unordered-list": "AufzΓ€hlung", + "components.richtexteditor.toolbar.code": "Code", + "components.richtexteditor.toolbar.strikethrough": "Durchgestrichen", + "components.richtexteditor.toolbar.italic": "Kursiv", + "components.richtexteditor.toolbar.underline": "Unterstrichen", + "components.richtexteditor.toolbar.bold": "Fett", + "general.user.deleted": "GelΓΆschtes Benutzerkonto", + "general.user.role.company.guest": "Gast", + "general.user.role.company.member": "Mitglied", + "general.user.role.company.admin": "Organisationsadministrator", + "scenes.client.channels_bar.modals.parts.channel_member_row.label.pending_email": "E-Mail gesendet", + "scenes.client.channels_bar.modals.guest_management.tips": "Beginnen Sie mit dem HinzufΓΌgen oder Suchen nach E-Mail-Adressen, indem Sie die obige Eingabe verwenden", + "scenes.client.channels_bar.modals.guest_management.input_placeholder": "GΓ€ste und ausstehende E-Mail-Adressen suchen", + "scenes.client.channels_bar.modals.guest_management.title": "GΓ€ste in {{$1}} verwalten", + "services.console_services.toaster.success_invite_emails": "{{$1}} Benutzer wurde(n) erfolgreich hinzugefΓΌgt", + "scenes.app.popup.workspaceparameter.edit_from_console": "In Konsole ansehen", + "services.console_services.toaster.success_verify_email": "Ein BestΓ€tigungslink wurde an Ihre E-Mail-Adresse verschickt", + "services.console_services.toaster.add_email_error_message": "Fehler beim HinzufΓΌgen von {{$1}}", + "services.console_services.toaster.add_emails_error": "Beim HinzufΓΌgen der E-Mail-Adresse(n) ist ein Fehler aufgetreten", + "components.verify_mail.paragraph": "Sie kΓΆnnen dies spΓ€ter tun, unbestΓ€tigte Konten haben aber nur einen begrenzten Zugriff auf die Funktionen von Twake", + "components.verify_mail.text": "Im ersten Schritt mΓΌssen Sie ihre E-Mail-Adresse bestΓ€tigen. Wir haben einen BestΓ€tigungslink an folgende Adresse geschickt", + "components.verify_mail.button": "Benutzer hinzufΓΌgen", + "components.verify_mail.title_2": "Sie sind jetzt ein Twake-Benutzer!", + "components.verify_mail.title_1": "Herzlichen GlΓΌckwunsch", + "components.add_mails_workspace.text_area_placeholder": "Geben Sie die E-Mails ihrer Benutzer ein*", + "components.add_mails_workspace.title_2": "Twake ist ein Tool zur Zusammenarbeit in Teams, also laden Sie ein paar Anwender ein, um den Arbeitsbereich zu testen, den wir fΓΌr Sie erstellt haben.", + "components.add_mails_workspace.title_1": "FΓΌgen Sie Benutzer hinzu", + "components.add_mails_workspace.button": "Anfangen Twake zu benutzen", + "components.blocked_account.trial_period_over": "Ihr Testzeitraum ist abgelaufen. Um ihr Benuzterkonto zu entsperren und Zugriff auf alle Funktionen zu erhalten, bestΓ€tigen Sie Ihr Benutzerkonto per E-Mail", + "components.unverified_account.re_send_email": "Sie haben keine Mail bekommen?", + "components.account_verication_status_blocked": "Gesperrt", + "components.account_verication_status_unverified": "UnbestΓ€tigt", + "components.account_verification_status_sentence": "Der Status ihres Benutzerkontos ist: {{$1}}", + "components.unverified_account.verification_details": "Wir haben die Verifizierungsdaten an folgende Adresse geschickt", + "components.unverified_account.typography_text_danger": "Sie haben noch {{$1}} Tage in Ihrer vom Testzeitraum ΓΌbrig. Ihr Testzugang wird nach 7 Tagen gesperrt und 1 Monat nach der Registrierung dauerhaft gelΓΆscht. Sie kΓΆnnen Ihr Benutzerprofil bestΓ€tigen, indem Sie in der Mail, die wir Ihnen geschickt haben, auf den Link β€žBenutzerprofil bestΓ€tigenβ€œ klicken.", + "general.verify": "ÜberprΓΌfen", + "general.re_send": "Erneut senden", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.loader": "Mehr laden", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.tag": "Sie sind kein Mitglied", + "components.alert.leave_private_channel.description": "Sie werden dem privaten Kanal nicht wieder beitreten kΓΆnnen bis sie jemand einlΓ€dt.", + "components.alert.leave_private_channel.title": "Sind Sie sicher, dass sie den Kanal verlassen mΓΆchten?", + "scenes.client.channelbar.channelmemberslist.tag": "Sie", + "scenes.apps.messages.message.activity_message.a_deleted_channel_connector": "{{$1}} hat einen Konnektor entfernt {{$2}}", + "scenes.apps.messages.message.activity_message.a_created_channel_connector": "{{$1}} hat einen neuen Konnektor hinzugefΓΌgt {{$2}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_tab": "{{$1}} hat {{$2}} Tab entfernt {{$3}}", + "scenes.apps.messages.message.activity_message.a_created_channel_tab": "{{$1}} hat eine neuen {{$2}} Tab {{$3}} hinzugefΓΌgt", + "scenes.apps.messages.message.activity_message.a_updated_channel_name": "{{$1}} hat den Kanal in {{$2}} umbenannt", + "scenes.apps.messages.message.activity_message.a_updated_channel_description": "{{$1}} hat die Beschreibung geΓ€ndert", + "scenes.apps.messages.message.activity_message.a_removed_b_from_the_channel": "{{$1}} hat {{$2}} aus dem Kanal entfernt", + "scenes.apps.messages.message.activity_message.a_added_b_to_the_channel": "{{$1}} hat {{$2}} dem Kanal hinzugefΓΌgt", + "components.inputs.input_with_select.button.tooltip": "Einen Abschnitt im Kanal festlegen", + "components.inputs.input_with_select.select.no_sections": "Schreiben Sie den Namen des ersten Abschnitts in diesem Kanal.", + "components.inputs.input_with_select.select.placeholder": "Gruppenname", + "components.inputs.input_with_select.input.placeholder": "Kanalname", + "scenes.apps.drive.download_all_button": "Alle herunterladen", + "components.newversion.new_version_modal.title": "Neues Update verfΓΌgbar !", + "components.newversion.new_version_component.link": "Hier klicken um neu zu laden", + "components.newversion.new_version_component.row.part_2": "Wir schlagen vor, die App neu zu laden und die neuen Features zu nutzen!", + "components.newversion.new_version_component.row.part_1": "Sie benutzen eine veraltete Version von Twake", + "scenes.app.popup.adduserfromtwakeconsole.current_users_state": "{{$1}} E-Mail(s) werden hinzugefΓΌgt", + "scenes.app.channelsbar.hide_discussion_leaving.menu": "Diskussion verbergen", + "scenes.client.channelbar.channelmemberslist.no_members": "Es gibt keine Benutzer in diesem Kanal, Sie kΓΆnnen durch Klick auf \"Benutzer hinzufΓΌgen\" welche hinzufΓΌgen.", + "scenes.client.mainview.tabs.tabstemplateeditor.select_placeholder": "Anwendung", + "components.notifications.hidden_notifications_button.children": "Neue Nachrichten", + "components.connectorslistmanager.add_connectors": "Konnektoren hinzufΓΌgen", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_edition": "{{$1}} umbenennen", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_creation": "Neuen Tab erstellen", + "scenes.client.channelbar.workspacechannellist.autocomplete": "Kanal, Benutzer oder Nachricht suchen", + "components.channelworkspacelist.title": "KanΓ€le", + "components.leftbar.channel.workspaceschannels.menu.option_2": "Einem Kanal beitreten", + "components.leftbar.channel.workspaceschannels.menu.option_1": "Einen Kanal erstellen", + "scenes.client.channelbar.channelmemberslist.menu.option_2": "Aus Kanal entfernen", + "scenes.client.channelbar.channelmemberslist.autocomplete": "Benutzer hinzufΓΌgen oder suchen", + "scenes.client.channelbar.channelmemberslist.loader": "Mehr laden", + "scenes.client.channelbar.channelmemberslist.title": "Benutzer in {{$1}}", + "scenes.client.channelbar.channeltemplateeditor.checkbox": "Alle Benutzer des Workspace automatisch zu diesem Channel einladen", + "scenes.app.mainview.channel_description": "Kanalbeschreibung", + "scenes.app.popup.appsparameters.pages.smalltext_group_id": "Aktuelle Gruppen ID", + "scenes.app.popup.appsparameters.pages.smalltext_workspace_id": "Aktuelle Workspace ID", + "scenes.app.popup.appsparameters.pages.smalltext_user_id": "Aktuelle Benutzer ID", + "scenes.app.popup.appsparameters.pages.subtitle_informations": "Informationen zur Anwendungsverwaltung", + "scenes.app.popup.appsparameters.pages.title_informations": "Basisinformation", + "scenes.apps.drive.right_preview.versions": "Versionen", + "scenes.apps.tasks.active_tasks": "Aktive Aufgaben", + "scenes.app.popup.workspace.create_temp": "TemporΓ€ren Account anlegen", + "scenes.app.popup.workspace.edit_temp": "TemporΓ€ren Account bearbeiten", + "scenes.app.popup.createcompany.try_again": "Bitte versuchen Sie es erneut.", + "components.drive.elements.manage_version": "Versionen verwalten", + "components.drive.elements.configurate_mod": "Modul konfigurieren...", + "scenes.apps.drive.right_preview.public": "Γ–ffentlicher Zugriff", + "components.drive.elements.current_name": "Aktueller Name: ", + "components.drive.elements.see": "ansehen", + "scenes.apps.drive.remove_attachs": "AnhΓ€nge entfernen", + "components.attachmentpicker.remove_attach": "Anhang entfernen", + "components.attachmentpicker.file": "Datei", + "components.attachmentpicker.from_twake": "Aus Twake Dokumenten", + "components.attachmentpicker.from_computer": "Vom GerΓ€t", + "scenes.apps.drive.move_text2": "Verschieben", + "components.calendar.calendarselector.from": "Von", + "scenes.apps.tasks.modals.attachments": "AnhΓ€nge", + "components.tagpicker.notag": "Kein Tag", + "scenes.app.mainview.discussion": "Diskussion", + "scenes.apps.calendar.video_link": "Klicken um Link zu ΓΆffnen", + "scenes.apps.calendar.reminders": "Erinnerung(en)", + "components.reminder.by_email": "E-Mail", + "components.reminder.weeks_bef": "Wochen vorher", + "components.reminder.days_bef": "Tage vorher", + "components.reminder.hours_bef": "Stunden vorher", + "components.reminder.minutes_bef": "Minuten vorher", + "components.reminder.notification": "Benachrichtigung", + "scenes.apps.drive.used": "in diesem Ordner verwendet", + "components.userlistmanager.no_users": "Keine Benutzer.", + "scenes.apps.board.all_boards": "Alle Boards", + "scenes.apps.board.new_task": "+ Neue Aufgabe", + "scenes.apps.board.display_as": "Anzeigen als", + "scenes.apps.board.kanban": "Kanban", + "scenes.apps.board.active_tasks": "Aktive Aufgaben", + "scenes.apps.board.archived_tasks": "Archivierte Aufgaben ({{$1}})", + "general.more": "Mehr", + "components.searchpopup.load_more": "Weitere Ergebnisse laden", + "components.searchpopup.show_filters": "Filter anzeigen", + "components.searchpopup.hide_filters": "Filter verbergen", + "scenes.app.mainview.advanced_search_placeholder": "Erweiterte Suche", + "components.searchpopup.tasks": "Aufgaben", + "components.alert.confirm_click": "Bitte bestΓ€tigen Sie, indem Sie auf OK klicken.", + "components.alert.confirm": "BestΓ€tigen Sie Ihre Aktion", + "components.searchpopup.only_pinned": "Nur angeheftete Nachrichten", + "components.searchpopup.mentions": "ErwΓ€hnungen", + "components.searchpopup.sender": "Absender", + "components.searchpopup.last_modif": "Letzte Γ„nderung", + "components.searchpopup.update_search": "Suche aktualisieren", + "components.searchpopup.creation": "Erstellung", + "components.searchpopup.size": "Grâße", + "components.searchpopup.tags": "Tags", + "components.searchpopup.filter_ws": "Workspaces filtern", + "components.searchpopup.loading": "Weitere Ergebnisse werden geladen", + "components.searchpopup.enter_text": "Geben Sie einen Text ein, um Twake zu durchsuchen.", + "components.workspace.calendar.invalid": "UngΓΌltig", + "components.workspace.list_manager.all": "Alle", + "components.workspace.list_manager.current_company": "Aktuelle Organisation", + "components.workspace.list_manager.current_space": "Aktueller Arbeitsbereich", + "components.workspace.list_manager.add": "Workspace hinzufΓΌgen", + "components.workspace.list_manager.no_workspace": "Kein Workspace", + "components.upload.drop_files": "Dateien hier ablegen, um sie hochzuladen", + "components.tagpicker.tag_name": "Tag Name", + "components.drive.modify_uslist": "Benutzerliste bearbeiten", + "components.drive.moove_here": "Hierher bewegen", + "components.drive.right_preview.create_link": "Link erzeugen", + "components.drive.right_preview.suppress_link": "Link unterdrΓΌcken", + "components.drive.navigators.directory_not_found": "Verzeichnis nicht gefunden.", + "components.drive.new_versions": "Neue Version hinzufΓΌgen", + "components.input.copied": "Kopiert", + "components.attachmentpicker.add_attachment": "Anhang hinzufΓΌgen", + "scenes.apps.tasks.no_connector": "Kein Konnektor", + "components.listmanager.filter": "Filter", + "scenes.app.taskpicker.select": "AuswΓ€hlen", + "scenes.apps.parameters.workspace_sections.members.invite_all": "Alle einladen", + "scenes.apps.calendar.modals.reminder_add": "Erinnerung hinzufΓΌgen", + "scenes.app.mainview.create_account": "Erstellen Sie ihren Workspace kostenlos unter ", + "scenes.app.mainview.link_expired": "Dieser ΓΆffentliche Link ist ungΓΌltig oder abgelaufen.", + "scenes.apps.account.message_user_signin": "Der Benutzer kann sich jederzeit mit der gleichen E-Mail anmelden und sein temporΓ€res Konto in ein normales Konto umwandeln.", + "scenes.apps.account.message_temporary": "Ein temporΓ€rer Account funktioniert wie ein normaler Twake Account, aber Sie erzeugen sein Passwort und kΓΆnnen es bei Bedarf zurΓΌcksetzen.", + "scenes.apps.account.account.save": "Account speichern", + "scenes.apps.account.account.send_info": "Schicken Sie diese Anmeldedaten an den Benutzer.", + "scenes.apps.account.account.password_for_user": "Ihr Passwort", + "login.email_login": "E-Mail / Login", + "scenes.apps.account.account.fullname": "VollstΓ€ndiger Name", + "scenes.app.popup.workspaceparameter.pages.cancel_invitation": "Einladung zurΓΌckziehen", + "scenes.app.popup.workspaceparameter.pages.logo_company_modify_description": "Organisationslogo bearbeiten ", + "scenes.apps.parameters.workspace_sections.workspace.logo_company": "Logo der Organisation", + "scenes.app.popup.sync_calendar": "Synchronisieren Sie ihre Kalender.", + "scenes.apps.tasks.board.list_name": "Listenname", + "scenes.apps.tasks.board.ends": "Fertig bis", + "scenes.apps.tasks.board.starts": "Start am", + "scenes.apps.tasks.board.tasks.in_list": "In Liste", + "scenes.apps.tasks.board.tasks.use_starttime": "Startzeit verwenden", + "scenes.apps.tasks.board.tasks.use_deadline": "Deadline verwenden", + "scenes.apps.tasks.board.tasks.add_subtask": "Unteraufgabe hinzufΓΌgen", + "scenes.apps.tasks.board.tasks.subtask": "Unteraufgabe", + "scenes.apps.tasks.board.place_holder": "Name des Boards", + "scenes.apps.tasks.my_tasks": "Meine Aufgaben", + "scenes.apps.drive.viewer.download_desktop": "Laden Sie Twake Desktop herunter, um die Vorschau in der App anzuzeigen", + "scenes.apps.messages.input.show_formatting": "Formatierungen anzeigen", + "scenes.apps.messages.input.send_message": "Nachricht senden", + "scenes.apps.messages.new_thread": "Neue Diskussion beginnen", + "scenes.apps.drive.top_menu_no_items": "{{$1}} Elemente", + "scenes.apps.drive.top_menu_more": "Mehr", + "scenes.apps.drive.trash": "Papierkorb", + "scenes.apps.messages.message.pin_button": "Nachricht anheften", + "scenes.apps.messages.input.edited": "Bearbeitet", + "scenes.apps.drive.no_storage_app_alert": "Sie haben keine Anwendungen, die es erlauben, externen Speicher hinzuzufΓΌgen.", + "scenes.tell_us": "Bitte teilen Sie uns mit, was Sie gemacht haben:", + "scenes.apps.messages.input.hide_formatting": "Formatierungen ausblenden", + "scenes.apps.messages.input.emoji": "Emoji", + "scenes.apps.calendar.unconfigured_tab": "Dieser Tab ist noch nicht konfiguriert.", + "scenes.app.workspaces.components.skip": "Überspringen", + "scenes.apps.messages.message.copy_link": "Link zur Nachricht kopieren", + "scenes.apps.messages.message.unpin_button": "Nachricht lΓΆsen", + "components.locked_features.locked_workspace_popup.title": "Sie kΓΆnnen keine weiteren Arbeitsbereiche erstellen", + "components.locked_features.locked_workspace_popup.subtitle": "In der kostenlosen Version kΓΆnnen Sie nur 1 Arbeitsbereich in Ihrem Unternehmen haben.", + "components.locked_features.locked_workspace_popup.text": "Hoppla!! MΓΆchten Sie einen neuen Arbeitsbereich in Ihrer Organisation erstellen? Sie sollten ein Upgrade Ihres Plans in Betracht ziehen. PrΓΌfen Sie unsere Preisoptionen und wΓ€hlen Sie die beste Wahl fΓΌr Ihre Anforderungen aus.", + "components.locked_features.locked_drive_popup.title": "Du hast gerade das Fahrlimit erreicht", + "components.locked_features.locked_drive_popup.subtitle": "In der kostenlosen Version kΓΆnnen Sie nur 6 GB speichern.", + "general.email": "E-Mail", + "scenes.app.popup.workspaceparameter.pages.workspace_partner_tabs.members.table.tags": "Rolle", + "scenes.app.popup.workspaceparameter.pages.error_workspace_member": "Sie mΓΌssen die einzige Person im Arbeitsbereich sein, um ihn entfernen zu kΓΆnnen. Entfernen Sie alle Mitglieder und versuchen Sie es erneut.", + "general.retry": "Wiederholen", + "components.locked_features.locked_only_office_popup.text": "Hoppla!! Es sieht so aus, als wollten Sie die Datei in twake bearbeiten. Wenn Sie Office-Dateien bearbeiten mΓΆchten, mΓΌssen Sie ein Upgrade Ihres Tarifs durchfΓΌhren. Informieren Sie sich ΓΌber unsere Preisoptionen und wΓ€hlen Sie die beste Option fΓΌr Ihre Anforderungen an die Zusammenarbeit im Team.", + "components.locked_features.locked_only_office_popup.subtitle": "Onlyoffice ist in der freien Version nicht verfΓΌgbar.", + "components.locked_features.locked_only_office_popup.title": "Sie kΓΆnnen diese Datei nicht bearbeiten", + "application.load.longer": "Der Server braucht lΓ€nger zum Antworten als erwartet, bitte warten Sie oder laden Sie die Seite erneut …", + "general.resume": "Fortsetzen", + "general.pause": "Pause", + "scenes.app.integrations_parameters.title": "Integrationen", + "scenes.app.integrations_parameters.applications_table.name": "Name", + "scenes.app.integrations_parameters.applications_table.title": "Andere Integrationen", + "scenes.app.integrations_parameters.applications_table.search_placeholder": "Anwendung suchen", + "scenes.app.integrations_parameters.company_application_popup.tag": "Eingerichtet", + "scenes.app.integrations_parameters.company_application_popup.btn": "Installieren", + "scenes.app.integrations_parameters.company_application_popup.tab_btn_info": "Informationen", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.description_item": "Beschreibung", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.website_item": "Webseite", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.created_item": "Erstellungsdatum", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.version_item": "AusfΓΌhrung", + "scenes.app.integrations_parameters.company_applications_table.more_menu.show_application": "Zeigen", + "scenes.app.integrations_parameters.company_applications_table.more_menu.remove_application": "Aus dem Unternehmen entfernen", + "scenes.app.integrations_parameters.company_applications_table.name": "Name", + "scenes.app.integrations_parameters.company_applications_table.title": "In Ihrem Unternehmen installiert", + "app.state.recoil.hooks.use_current_company_applications.toaster_delete": "{{$1}} erfolgreich aus Ihrem Unternehmen gelΓΆscht", + "app.state.recoil.hooks.use_current_company_applications.toaster_add": "{{$1}} erfolgreich zu Ihrem Unternehmen hinzugefΓΌgt", + "scenes.app.channelsbar.currentuser.company_messages_counter_link": "Weitere PlΓ€ne anzeigen", + "scenes.app.channelsbar.currentuser.company_messages_counter_header": "Anzahl Nachrichten", + "scenes.app.channelsbar.currentuser.company_messages_counter_info": "In der kostenfreien Version von Twake kΓΆnnen Sie nur die {{$1}} neusten Nachrichten ansehen.", + "scenes.apps.messages.input.replied_to": "antwortete auf ", + "scenes.app.popup.adduser.magiclinks.new_link_generated": "Neuer Link generiert", + "scenes.app.popup.adduser.magiclinks.copied_to_clipboard": "Erfolgreich in die Zwischenablage kopiert", + "scenes.app.popup.adduser.magiclinks.genrator_info": "Einladungslink zum Arbeitsbereich", + "scenes.app.popup.adduser.magiclinks.action_copy": "Kopieren", + "scenes.app.popup.adduser.magiclinks.action_generate": "Generieren", + "scenes.join.loading": "Wird geladen …", + "scenes.join.wrong_link_title": "Dieser Link ist nicht mehr verfΓΌgbar", + "scenes.join.wrong_link_description": "Bitten Sie die Person, die Sie eingeladen hat, diesem Unternehmen beizutreten, um einen neuen Link oder grΓΌnden Sie Ihr eigenes Unternehmen", + "scenes.join.join_workspace_from_company": "Treten Sie {{$1}} von {{$2}} bei!", + "scenes.join.twake_description": "Twake ist ein digitaler quelloffener Arbeitsbereich, der die ProduktivitΓ€t Ihres Teams verbessert", + "scenes.join.login_first_button": "Melden Sie sich an oder erstellen Sie zunΓ€chst ein Konto", + "scenes.join.join_the_team_button": "Treten Sie dem Team bei", + "scenes.join.create_the_company_button": "Das Unternehmen erstellen", + "\"": "\"", + "login.login_error": "Fehler bei der Anmeldung", + "'": "'", + "login.create_account": "Konto erstellen", + "scenes.app.messages.input.parts.is_writing.message.user_is_writing": "{{$1}} schreibt gerade...", + "scenes.app.messages.input.parts.is_writing.message.users_are_writing": "{{$1}} und {{$2}} schreiben...", + "scenes.app.messages.input.parts.is_writing.message.users_and_more_are_writing": "{{$1}}, {{$2}} und {{$3}} weitere Benutzer schreiben...", + "scenes.app.workspaces.welcome_page.no_workspace_subtitle": "Niemand hat Sie bisher zu einem Arbeitsbereich eingeladen.", + "scenes.apps.messages.message.types.no_message_in_thread": "Es hat noch niemand geantwortet.", + "components.rich_text_editor.plugins.suggestions.default_message.display_results": "Schreiben Sie mindestens drei Buchstaben, um Benutzer anzuzeigen", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.label": "Standardarbeitsbereich", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.description": "Alle Workspace-Benutzer automatisch zu diesem Kanal einladen", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.title": "Sie sind im Begriff, {{$1}} zu lΓΆschen", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.alert_total_members": "Du hast noch {{$1}} Mitglieder in {{$2}}. Sie sollten alle Mitglieder entfernen, um diesen Arbeitsbereich lΓΆschen zu kΓΆnnen.", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.checkbox": "Mir ist bewusst, dass alle Nachrichten und Dateien meines Arbeitsbereichs gelΓΆscht werden.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.max_size": "Die maximale Logogrâße betrΓ€gt 5 MB", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.bad_format": "Schlechtes Format, nur png gif und jpg sind erlaubt", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.unknown": "Unbekannter Fehler", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.prefix": "Fehler", + "components.rich_text_editor.plugins.suggestions.default_message.no_user_found": "Kein Benutzer gefunden", + "scenes.app.channelsbar.currentuser.reset": "ZurΓΌcksetzen", + "components.rich_text_editor.plugins.suggestions.default_message.no_emoji_found": "Keine Emojis gefunden", + "components.rich_text_editor.plugins.suggestions.default_message.no_command_found": "Kein Befehl gefunden", + "components.locked_features_components.locked_invite_alert.message_part_1": "Ihr Unternehmen hat die maximale Anzahl von {{$1}} Mitgliedern erreicht. Bitte ", + "components.locked_features_components.locked_invite_alert.message_link": "aktualisieren Sie Ihr Unternehmen", + "components.locked_features_components.locked_invite_alert.message_part_2": ", um weitere Mitglieder einzuladen.", + "components.locked_features_components.locked_invite_alert.message_magic_link": " wenden Sie sich an den EigentΓΌmer oder Verwalter Ihres Unternehmens.", + "views.client.popup.workspace_parameter.pages.workspace_members.link_to_console": "Alle Mitglieder meines Unternehmens auf der Konsole sehen", + "scenes.app.popup.appsparameters.pages.amazing_app_description": "Beschreiben Sie Ihre Bewerbung in wenigen Worten", + "scenes.app.popup.appsparameters.pages.application_creator.title": "Neue Integration", + "scenes.app.popup.appsparameters.pages.application_creator.checkbox": "Mir ist bekannt, dass der Inhaber und die Verwalter dieses Unternehmens diesen Antrag Γ€ndern und verΓΆffentlichen kΓΆnnen.", + "twake.application.access.title": "WΓ€hlen Sie die richtigen Bereiche fΓΌr Ihre Anwendung.", + "twake.application.access.no_default_scopes_available'": "Diese Integration hat keinen Zugang zu {{$1}}", + "scenes.app.popup.appsparameters.pages.application_editor.help_link": "die Twake-API-Dokumentation", + "scenes.app.popup.appsparameters.pages.application_editor.help_text": "Wenn Sie nicht wissen, wie Sie diese ausfΓΌllen sollen, gehen Sie zu ", + "scenes.app.popup.appsparameters.pages.app.private_key": "Privat SchlΓΌssel", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed": "Anwendung {{$1}} erfolgreich entfernt!", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed_error": "Fehler beim Entfernen der Anwendung {{$1}} !", + "scenes.app.popup.appsparameters.pages.application_editor.application_published": "Erfolgreiche {{$1}} Bewerbung!", + "scenes.app.integrations_parameters.add_application": "Neue Einbindung", + "scenes.app.integrations_parameters.company_applications_table.more_menu.developer_settings": "Entwicklereinstellungen", + "components.rich_text_editor.plugins.suggestions.loading": "Auf der Suche nach mehr", + "components.open_desktop_popup.subtitle": "in der Twake-App geΓΆffnet", + "components.open_desktop_popup.open_here_link": "Γ–ffnen Sie stattdessen hier", + "molecules.download_banner.title": "Holen Sie das Beste aus Twake heraus, laden Sie jetzt die Desktop-App herunter", + "molecules.download_banner.download_button": "Laden Sie die Desktop-App herunter", + "scenes.app.channelsbar.channel_copy_link": "Kanallink kopieren", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.success.update": "Erfolgreich aktualisiert", + "components.searchpopup.files": "Dateien", + "components.searchpopup.recent_chats": "Aktuelle Chats", + "components.searchpopup.recent_media": "Aktuelle Medien", + "components.searchpopup.recent_files": "Aktuelle Dateien", + "components.searchpopup.no_results_for": "Es gab keine Ergebnisse fΓΌr", + "components.searchpopup.try_new_search": "Versuchen Sie eine neue Suche", + "components.searchpopup.all": "Alle", + "components.searchpopup.chats": "Chats", + "components.searchpopup.media": "Medien", + "components.searchpopup.recent_channels_and_contacts": "Letzte KanΓ€le und Kontakte", + "components.searchpopup.header_title": "Suche", + "components.searchpopup.scope.company": "in aller Gesellschaft", + "components.searchpopup.scope.channel": "in diesem Kanal", + "components.searchpopup.channels": "KanΓ€le", + "components.searchpopup.messages": "Mitteilungen", + "components.searchpopup.see_more": "Mehr sehen", + "scenes.client.join_private_channel.info": "Dieser Inhalt dieses Kanals ist eingeschrΓ€nkt oder existiert nicht. Bitte kontaktieren Sie ein Mitglied dieses Kanals, um eingeladen zu werden.", + "general.yes": "Ja", + "general.no": "Nein", + "components.searchpopup.start_search": "Geben Sie einige SchlΓΌsselwΓΆrter ein, um die Suche zu starten.", + "scenes.client.channelbar.channelmemberslist.search_invite": "Suchen Sie nach Benutzern und laden Sie sie zu diesem Kanal ein", + "scenes.client.channelbar.channelmemberslist.search_invite_notice": "Es gibt nicht viele Mitglieder in diesem Kanal. Suchen und laden Sie Benutzer jetzt per E-Mail oder Name ein.", + "scenes.client.channelbar.channelmemberslist.invite_email_button": "Nur als Gast zum Kanal hinzufΓΌgen", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace": "Als Mitglied zum Channel und Workspace hinzufΓΌgen", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace_confirm": "{{$1}} als Mitglied zum Workspace einladen?", + "scenes.client.channelbar.channelmemberslist.search_invite_type_email": "Geben Sie eine gΓΌltige Adresse ein, um per E-Mail einzuladen.", + "scenes.client.channelbar.channelmemberslist.pending_section": "Benutzer warten auf Einladung", + "scenes.client.channelbar.channelmemberslist.members_section": "Benutzer in diesem Kanal", + "scenes.client.channelbar.channelmemberslist.not_members_section": "Benutzer nicht in diesem Kanal", + "scenes.client.join_public_channel": "Tritt diesem Kanal bei", + "scenes.client.join_public_channel.info": "Sie sind kein Mitglied dieses direkten Kanals. Klicken Sie auf diese SchaltflΓ€che, um die Diskussion jetzt zu beginnen.", + "components.open_desktop_popup.open_here_link_forever": "Versuchen Sie nie wieder, die App zu ΓΆffnen", + "components.channel_attachement_list.medias": "Medien", + "components.channel_attachement_list.files": "Dateien", + "components.channel_attachement_list.title": "Kanaldateien und Medien", + "components.channel_attachement_list.nothing_found": "Hier noch nichts", + "molecules.message_quote.deleted": "Diese Nachricht wurde gelΓΆscht", + "scenes.apps.messages.jump": "Zur Nachricht springen", + "components.channel_attachement_list.open": "Galerie ΓΆffnen", + "scenes.apps.account.on_console": "Um Ihre globalen Kontoeinstellungen zu bearbeiten, klicken Sie auf Go to Console.", + "scenes.apps.account.assistant.description": "Der Twake-Assistent ist in der Lage, Ihre tΓ€gliche Arbeit mit Twake zu verstehen und intelligente VerknΓΌpfungen und Aktionen wΓ€hrend Ihres Tages bereitzustellen. Der Assistent ist Teil der Work@Home-Initiative https://workathome.linagora.com/ und wird derzeit nur im Unternehmen Linagora getestet und befindet sich in der Lernphase. Das bedeutet, dass wir Twake-Nutzungsdaten senden, um unsere zukΓΌnftige Assistentenfunktion zu trainieren.", + "scenes.apps.account.assistant.share.all": "Teilen Sie alles, einschließlich Nachrichten und Dateiinhalte", + "scenes.apps.account.assistant.share.metadata": "Teilen Sie Metadaten, aber keine Inhalte", + "scenes.apps.account.assistant.success": "Ihre Einstellungen wurden erfolgreich aktualisiert.", + "scenes.apps.account.assistant.title": "Assistent", + "scenes.apps.account.assistant.share.nothing": "Nichts mit dem Assistenten teilen (Assistent deaktivieren)", + "components.message_seen_by.title": "Benutzer, die die Nachricht gesehen haben", + "components.message_seen_by.none_seen_it": "Die Nachricht hat noch niemand gesehen", + "components.message_seen_by.btn": "Information", + "molecules.quoted_content.attachements": "{{$1}} AnhΓ€nge", + "scenes.apps.messages.message.user_deactivated": "Sie sehen sich das Archiv eines deaktivierten Kontos an", + "general.user.deactivated": "Benutzer ist nicht mehr in diesem Unternehmen", + "general.user.connected": "Online", + "scenes.app.popup.userparameter.pages.email_notif_delay_never": "Niemals", + "scenes.app.popup.userparameter.pages.email_notif_delay_quarter_hour": "15 Minuten", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_day": "1 Tag", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_hour": "1 Stunde", + "scenes.app.popup.userparameter.pages.notification_sound.defaut": "Standard", + "scenes.app.popup.userparameter.pages.notification_sound.none": "Keiner", + "scenes.client.channelbar.readonly_channel.checkbox": "BeschrΓ€nken Sie die SchreibfΓ€higkeit", + "scenes.apps.messages.message.forward": "Nach vorne", + "scenes.apps.messages.message.forward.title": "Nachricht weiterleiten", + "scenes.apps.messages.message.forward.comment": "FΓΌge eine Nachricht hinzu", + "scenes.apps.messages.message.forward.confirm": "An $1 Kanal(e) senden", + "scenes.apps.messages.message.forward.send": "Nachricht weitergeleitet", + "components.channelselector.title": "KanΓ€le auswΓ€hlen", + "components.channelselector.confirm": "WΓ€hle $1 Kanal(e)", + "components.channelselector.search": "KanΓ€le und Diskussionen durchsuchen", + "scenes.app.channelsbar.channel_access": "Kanalzugriff", + "scenes.app.channelsbar.channel_access.save": "Zugriffseinstellungen speichern", + "scenes.app.channelsbar.channel_access.readonly": "Nur-Lese-Kanal", + "scenes.app.channelsbar.channel_access.visibility": "Γ–ffentliche Sichtbarkeit", + "scenes.app.channelsbar.channel_access.readonly.info": "BeschrΓ€nken Sie das Schreiben auf Moderatoren, Administratoren und EigentΓΌmer.", + "scenes.app.channelsbar.channel_access.visibility.info": "Mitmachen kann jeder außer FirmengΓ€sten.", + "scenes.app.channelsbar.channel_access.default": "Automatisch beitreten", + "scenes.app.channelsbar.channel_access.default.info": "Neue Mitglieder werden hier automatisch hinzugefΓΌgt.", + "scenes.app.channelsbar.channel_information": "Kanalinformationen bearbeiten", + "scenes.app.channelsbar.channel_information.logo.add": "Bild hochladen", + "scenes.app.channelsbar.channel_information.logo.remove": "Bild entfernen", + "scenes.app.channelsbar.channel_information.name": "Kanal Name", + "scenes.app.channelsbar.channel_information.description": "Kanal Beschreibung", + "scenes.app.channelsbar.channel_information.description.placeholder": "Kanalbeschreibung, Sie kΓΆnnen Markdown verwenden.", + "scenes.app.channelsbar.channel_information.group": "Kanalgruppe", + "scenes.app.channelsbar.channel_information.group.none": "Nicht ausgewΓ€hlt", + "scenes.app.channelsbar.channel_information.group.new": "Erstellen Sie eine neue Gruppe", + "scenes.app.channelsbar.channel_information.group.save": "Stellen Sie die Kanalgruppe auf $1 ein", + "scenes.app.channelsbar.channel_information.group.save_none": "Kanalgruppe nicht einstellen", + "scenes.app.channelsbar.channel_information.save": "Informationen speichern", + "components.invitation.allow_anyone_by_email.text": "Jedem mit @{{$1}}-E-Mail-Adresse diesen Workspace beitreten lassen", + "components.invitation.invitation_channels.button": "Zu KanΓ€len einladen", + "components.invitation.invitation_input_list.add": "HinzufΓΌgen", + "scenes.client.channelbar.channelmemberslist.invite_to_workspace": "Lade {{$1}} in den Arbeitsbereich ein ➑", + "components.invitation.reached_limit.text": "Sie haben die maximale Anzahl von Benutzern in Ihrem Unternehmen erreicht. ErhΓΆhen Sie Ihr Abonnement oder fΓΌgen Sie diese Benutzer als GΓ€ste hinzu", + "components.invitation.invitation_input_list.member": "Mitglied", + "components.invitation.invitation_input_list.guest": "Gast", + "components.invitation.invitation_input_list.placeholder": "Beginnen Sie mit der Eingabe einer E-Mail", + "components.invitation.invitation_sent.title": "Einladungen wurden erfolgreich versendet", + "components.invitation.invitation_sent.subtitle_status": "Sie kΓΆnnen den Einladungsstatus verfolgen in:", + "components.invitation.invitation_sent.subtitle_location": "Workspace-Einstellungen > Mitgliederverwaltung", + "components.invitation.invitation_sent.link": "ÜberprΓΌfen Sie den Einladungsstatus", + "components.invitation.invitation_sent.button": "Senden Sie mehr Einladungen", + "components.invitation.invitation_target.invite_as_guests": "Laden Sie alle als GΓ€ste ein", + "components.invitation.invitation_target.invite_as_members": "Laden Sie alle als Mitglieder ein", + "components.invitation.invitation_target.channels_button": "KanΓ€le zum Einladen", + "components.invitation.workspace_link.text": "Workspace-Einladungslink", + "components.invitation.workspace_link.button": "Kopieren", + "components.invitation.title": "Leute zu {{$1}} einladen", + "components.invitation.bulk_invitation": "Bulk-Einladung", + "components.invitation.button": "Einladungen verschicken", + "scenes.client.readonly.info": "Dieser Kanal ist ein schreibgeschΓΌtzter Feed, aber Sie kΓΆnnen in den Threads kommentieren.", + "scenes.app.channelsbar.channel_information.group.title": "Kanalgruppen", + "components.invitation.custom_role_invitation": "Klassische Einladung", + "components.invitation.link": "VerknΓΌpfung" +} diff --git a/twake/frontend/public/locales/en.json b/twake/frontend/public/locales/en.json new file mode 100644 index 00000000..925453cb --- /dev/null +++ b/twake/frontend/public/locales/en.json @@ -0,0 +1,1009 @@ +{ + "general.close": "Close", + "general.save": "Save", + "general.cancel": "Cancel", + "general.retry": "Retry", + "general.create": "Create", + "general.edit": "Edit", + "general.continue": "Continue", + "general.back": "Back", + "general.confirm": "Confirm", + "general.delete": "Delete", + "general.archive": "Archive", + "general.unarchive": "Unarchive", + "general.help": "Help", + "general.help.support": "Support", + "general.help.documentation": "Documentation", + "general.send": "Send message", + "general.update": "Update", + "general.remove": "Remove", + "general.add": "Add", + "general.connexion_status.disconnected": "You are offline", + "general.connexion_status.connected": "You are online", + "general.connexion_status.connecting": "Reconnecting…", + "application.load.longer": "Server takes longer than expected to reply, please wait or reload the page...", + "scenes.app.side_app.messages_thread_title": "{{$1}} β€’ Messages thread", + "scenes.app.workspaces.create_company.group_data": "Configure your new group", + "scenes.app.workspaces.create_company.group_data.group_type": "Group type", + "scenes.app.workspaces.create_company.group_data.group_type.company": "Company or company department", + "scenes.app.workspaces.create_company.group_data.group_type.public_organization": "Public organization", + "scenes.app.workspaces.create_company.group_data.group_type.university_school": "University or school", + "scenes.app.workspaces.create_company.group_data.group_type.society_club_charity": "Society, club or charity", + "scenes.app.workspaces.create_company.group_data.group_type.other_group": "Other", + "scenes.app.workspaces.create_company.group_data.group_size": "Group size", + "scenes.app.workspaces.create_company.group_data.group_size.less_3": "Less than 4 users", + "scenes.app.workspaces.create_company.group_data.group_size.4_10": "4 - 10 users", + "scenes.app.workspaces.create_company.group_data.group_size.10_50": "11 - 49 users", + "scenes.app.workspaces.create_company.group_data.group_size.50_100": "50 - 99 users", + "scenes.app.workspaces.create_company.group_data.group_size.100_500": "100 - 499 users", + "scenes.app.workspaces.create_company.group_data.group_size.500_1000": "500 - 999 users", + "scenes.app.workspaces.create_company.group_data.group_size.1000_5000": "1000 - 4999 users", + "scenes.app.workspaces.create_company.group_data.group_size.5000_more": "More than 5000 users", + "scenes.app.workspaces.create_company.group_data.group_main_activity": "Main activity", + "scenes.app.workspaces.create_company.group_data.group_main_activity.food": "Food", + "scenes.app.workspaces.create_company.group_data.group_main_activity.bank": "Bank / Insurance", + "scenes.app.workspaces.create_company.group_data.group_main_activity.printing_paper": "Printing / Paper", + "scenes.app.workspaces.create_company.group_data.group_main_activity.construction_building": "Construction / Building materials", + "scenes.app.workspaces.create_company.group_data.group_main_activity.real_estate": "Real estate", + "scenes.app.workspaces.create_company.group_data.group_main_activity.materials": "Materials", + "scenes.app.workspaces.create_company.group_data.group_main_activity.chemistry": "Chemistry", + "scenes.app.workspaces.create_company.group_data.group_main_activity.trade_commerce_distribution": "Trade / Commerce / Distribution", + "scenes.app.workspaces.create_company.group_data.group_main_activity.publishing_communication_multimedia": "Publishing / Communication / Multimedia", + "scenes.app.workspaces.create_company.group_data.group_main_activity.electronics_electricity_energy": "Electronics / Electricity / Energy", + "scenes.app.workspaces.create_company.group_data.group_main_activity.studies_and_advice": "Studies and advice", + "scenes.app.workspaces.create_company.group_data.group_main_activity.pharmaceutical_industry": "Pharmaceutical industry", + "scenes.app.workspaces.create_company.group_data.group_main_activity.it_telecom": "IT / Telecom", + "scenes.app.workspaces.create_company.group_data.group_main_activity.machinery_automotive": "Machinery / Automotive", + "scenes.app.workspaces.create_company.group_data.group_main_activity.business_services": "Business services", + "scenes.app.workspaces.create_company.group_data.group_main_activity.entertainment": "Entertainment", + "scenes.app.workspaces.create_company.group_data.group_main_activity.textile_clothing_shoes": "Textile / Clothing / Shoes", + "scenes.app.workspaces.create_company.group_data.group_main_activity.transport_logistics": "Transport / Logistics", + "scenes.app.workspaces.create_company.group_data.group_main_activity.research": "Research", + "scenes.app.workspaces.create_company.group_data.group_main_activity.education": "Education", + "scenes.app.workspaces.create_company.group_data.group_main_activity.administration": "Administration", + "scenes.app.workspaces.create_company.group_data.group_main_activity.other": "Other", + "components.application.messages": "Messages", + "components.drive_dropzone.uploading": "Uploading...", + "components.user_picker.modal_no_result": "No results found", + "components.users_picker.add_me": "Add me", + "scenes.app.workspaces.create_company.invitations.title": "Configure your workspace.", + "scenes.app.header.disconnected": "You are disconnected", + "scenes.app.header.disconnected.reload": "Reload", + "scenes.app.header.alt_notifications": "Notifications", + "scenes.apps.calendar.calendar.week_btn": "Week", + "scenes.apps.calendar.calendar.list_btn": "List", + "scenes.apps.calendar.event_edition.deadline_tag": "Deadline", + "scenes.apps.calendar.event_edition.checkbox_all_day": "All day", + "scenes.apps.calendar.event_edition.title_confidentiality": "Confidentiality", + "scenes.apps.calendar.event_view.article_until": "to", + "scenes.apps.calendar.calendar_modal.participants": "Participants", + "scenes.apps.calendar.calendar_modal.placeholder": "Name", + "scenes.apps.calendar.left.calendars": "Calendars", + "scenes.apps.drive.left.search": "Search", + "scenes.apps.drive.navigators.navigator_content.directory_name": "Directory name", + "scenes.apps.drive.navigators.navigator_content.files": "Files", + "scenes.apps.drive.navigators.navigator_labels.title": "Labels", + "scenes.apps.drive.navigators.new_file.untitled": "Untitled", + "scenes.apps.drive.navigators.new_file.create_file.type": "Type", + "scenes.apps.drive.navigators.new_file": "New file", + "scenes.apps.drive.preview_bloc.operations_download": "Download", + "scenes.apps.drive.preview_bloc.error_file": "File not found", + "scenes.apps.drive.right_preview.operations_restore": "Restore", + "scenes.apps.drive.right_preview.operations_delete": "Move to trash", + "scenes.apps.drive.right_preview.public_link": "Public link", + "scenes.apps.messages.messages": "Messages", + "scenes.apps.messages.jump": "Jump to message", + "scenes.apps.messages.chatbox.chat.delete_message": "Delete this message", + "scenes.apps.messages.chatbox.chat.delete_message_btn": "Delete message", + "scenes.apps.messages.left_bar.stream_modal.placeholder_name": "Name", + "scenes.apps.messages.left_bar.stream.add_to_favorites": "Add to favorites", + "scenes.apps.messages.left_bar.stream.remove_from_favorites": "Remove from favorites", + "scenes.apps.messages.left_bar.stream.notifications": "Notifications...", + "scenes.apps.messages.left_bar.stream.notifications.all": "Any message", + "scenes.apps.messages.left_bar.stream.notifications.mentions": "{{$1}}, {{$2}} and {{$3}}", + "scenes.apps.messages.left_bar.stream.notifications.me": "{{$1}} only", + "scenes.apps.messages.left_bar.stream.notifications.never": "Nothing", + "scenes.apps.parameters.workspace_sections.workspace": "Workspace", + "scenes.apps.parameters.workspace_sections.members": "Members", + "scenes.apps.parameters.group_sections.workspaces": "Workspaces", + "scenes.apps.parameters.group_sections.apps": "Apps", + "scenes.apps.account.title": "Account parameters", + "scenes.apps.account.on_console": "To edit your global account preferences, click on Go to Console.", + "scenes.apps.account.account.menu_title": "Account", + "scenes.apps.account.languages.menu_title": "Language", + "scenes.apps.account.account.firstname": "First name", + "scenes.apps.account.account.lastname": "Last name", + "scenes.apps.account.account.username": "Username", + "scenes.apps.account.account.change_username": "Change your unique username.", + "scenes.apps.account.account.emails": "E-mails", + "scenes.apps.account.account.main_email": "Main e-mail", + "scenes.apps.account.account.email_add": "Add new e-mail", + "scenes.apps.account.account.email_add_modal.invalid_code": "This code is invalid", + "scenes.apps.account.account.password": "Password", + "scenes.apps.account.account.password_modal.old_password": "Current password", + "scenes.apps.account.account.password_modal.password": "New password", + "scenes.apps.account.account.password_modal.bad_old_password": "Old password is not correct.", + "scenes.apps.account.account.password_modal.bad_password": "Your passwords do not match or they are too short. Please type a password with at least 8 characters.", + "scenes.apps.account.account.logout": "Logout", + "scenes.apps.account.languages.text": "Change Twake language.", + "scenes.apps.account.assistant.title": "Assistant", + "scenes.apps.account.assistant.description": "Twake assistant is able to make sense of your everyday work on Twake and provide smart shortcuts and actions during your day. The assistant is part of the Work@Home initiative https://workathome.linagora.com/ and is currently being tested only in the Linagora company and is in the learning phase. It means we will send Twake usage data in order to train our future assistant feature.", + "scenes.apps.account.assistant.share.nothing": "Do not share anything with the assistant (disable assistant)", + "scenes.apps.account.assistant.share.all": "Share everything including messages and files contents", + "scenes.apps.account.assistant.share.metadata": "Share metadata but not contents", + "scenes.apps.account.assistant.success": "Your preferences have been updated with success.", + "scenes.apps.account.notifications.title": "Notifications", + "scenes.apps.account.notifications.keywords_subtitle": "Keywords", + "scenes.apps.account.notifications.keywords_placeholder": "dev, wifi, code, ...", + "scenes.apps.account.notifications.disturb_option_a": "Don't send me push notifications between ", + "scenes.apps.account.notifications.disturb_option_b": " and ", + "scenes.apps.account.notifications.disturb_option_c": " (local timezone)", + "scenes.apps.account.notifications.devices_subtitle": "Device notifications", + "scenes.apps.account.notifications.devices_option_ever": "Always send me push notifications", + "scenes.apps.account.notifications.devices_option_inactive": "Send me push notifications when I'm inactive on desktop", + "scenes.apps.account.notifications.devices_option_never": "Never send me push notifications", + "scenes.apps.account.notifications.privacy_subtitle": "Privacy", + "scenes.apps.account.notifications.mail_subtitle": "E-mail notifications", + "scenes.apps.account.notifications.sound": "Sound notification", + "scenes.apps.parameters.group_sections.apps.badge_extension": "Extension", + "scenes.apps.parameters.workspace_sections.members.members": "Users", + "scenes.apps.parameters.workspace_sections.members.pending": "Pending emails", + "scenes.apps.parameters.workspace_sections.members.invite": "Invite new user", + "scenes.apps.parameters.workspace_sections.members.invite_btn": "Add user", + "scenes.apps.tasks.boards": "Boards", + "scenes.apps.tasks.connectors_menu": "Connectors...", + "scenes.apps.tasks.connectors_search_menu": "Search connectors...", + "scenes.apps.tasks.no_connectors_menu_text": "You do not have any connectors that can connect to a calendar.", + "scenes.apps.tasks.unconfigured_tab": "This tab is not configured yet.", + "scenes.apps.tasks.choose_board_button": "Choose a board", + "scenes.apps.tasks.new_board.title": "New board", + "scenes.apps.tasks.new_board.edit_title": "Edit board", + "scenes.apps.tasks.task": "Task", + "scenes.apps.tasks.no_tasks": "No task", + "scenes.apps.tasks.task_status.todo": "To do", + "scenes.apps.tasks.task_status.current": "Current", + "scenes.apps.tasks.task_status.done": "Done", + "scenes.apps.tasks.task.description": "Description", + "scenes.apps.tasks.task.assignees": "Assignees", + "scenes.apps.tasks.task.edit.dates": "Dates", + "scenes.apps.tasks.list_modal.modify_list": "Modify list", + "scenes.apps.tasks.list_modal.new_list": "New list", + "scenes.apps.tasks.list_modal.remove": "Remove list and tasks", + "scenes.apps.tasks.list_modal.predefined_participants": "Predefined participants", + "scenes.apps.tasks.list_modal.archive_all_tasks": "Archive all tasks", + "scenes.apps.tasks.list_modal.remove_archived_tasks": "Remove archived tasks ({{$1}})", + "scenes.login.footer.go_to_twake": "Go to twakeapp.com", + "scenes.login.footer.branding": "You are on a {{$1}} ({{$2}}) private Twake server. ", + "scenes.login.create_account.title": "Create a new account", + "scenes.login.create_account.email": "E-mail", + "scenes.login.create_account.email_used": "This e-mail is already in use.", + "scenes.login.create_account.username": "Username", + "scenes.login.create_account.username_already_exist": "This username is already in use", + "scenes.login.create_account.fill_in_username": "You must fill in your username", + "scenes.login.create_account.fill_in_email": "You must fill in your email with a correct email", + "scenes.login.create_account.too_short_password": "Your password must contain at least 8 characters.", + "scenes.login.create_account.firstname": "First name", + "scenes.login.create_account.newsletter": "Receive information about Twake", + "scenes.login.create_account.lastname": "Last name", + "scenes.login.forgot_password.title": "Forgot password?", + "scenes.login.forgot_password.text": "You will receive a 9-digit code by e-mail to verify your identity.", + "scenes.login.forgot_password.email_to_recover": "Email to recover", + "scenes.login.forgot_password.mail_doesnt_exist": "This e-mail doesn't exist", + "scenes.login.forgot_password.text2": "You will received a 9-digit code. Please enter it in the field bellow in order to continue.", + "scenes.login.forgot_password.invalid_code": "This code is not valid.", + "scenes.login.forgot_password.text3": "Enter a new password for your account.", + "scenes.login.forgot_password.password": "Password", + "scenes.login.forgot_password.password2": "Confirm password", + "scenes.login.forgot_password.password_dont_match": "Your passwords don't match or they are too short. Please type a password with at least 8 characters.", + "scenes.login.home.title": "Sign in to Twake", + "scenes.login.home.subtitle": "Happy to see you", + "scenes.login.home.email": "E-mail", + "scenes.login.home.unable_to_connect": "Invalid credentials", + "scenes.login.home.password": "Password", + "scenes.login.home.login_btn": "Log in", + "scenes.login.home.lost_password": "Forgot password?", + "scenes.login.home.create_account": "Create an account", + "scenes.login.create_account.password": "Password", + "scenes.login.create_account.step_1_subtitle": "It couldn't be simpler β€” we just need some information.", + "scenes.login.create_account.step_2_subtitle_a": "Add your full name for other users to recognize you.", + "scenes.login.create_account.step_2_subtitle_b": "Your phone number remains private.", + "scenes.login.create_account.step_3_mail_sent": "We have sent you an activation link by e-mail.", + "scenes.login.create_account.step_3_subtitle": "Last step β€” we need to verify you're not a robot!", + "scenes.app.workspaces.create_company.company_name.placeholder": "Company name", + "scenes.app.workspaces.create_company.company_name.title_1": "To begin,", + "scenes.app.workspaces.create_company.company_name.title_2": "indicate the name of your company.", + "scenes.app.workspaces.create_company.default_workspace_name": "Main", + "scenes.app.workspaces.create_company.group_data.title": "We'll be quick β€” we just need some statistical information.", + "scenes.app.workspaces.create_company.importations.title_1": "Already working with digital tools? Import or integrate your tools now!", + "scenes.app.workspaces.create_company.importations.title_2": "No worries, you can do this later!", + "scenes.app.workspaces.create_company.invitations.title_2": "Add users to your team.", + "scenes.app.workspaces.create_company.title": "Create my company", + "scenes.app.workspaces.welcome_page.add_secondary_emails": "Add a secondary email", + "scenes.app.workspaces.welcome_page.added_to_company": "You have been invited to ", + "scenes.app.workspaces.welcome_page.create_my_company": "Create my company", + "scenes.app.workspaces.welcome_page.lets_go": "Let's go!", + "scenes.app.workspaces.welcome_page.may_be_invited_with_secondary_emails": "Were you invited using another email address?", + "scenes.app.workspaces.welcome_page.no_company_subtitle": "Oh, well... It looks like no one has invited you to a company yet.", + "scenes.app.workspaces.welcome_page.no_workspace_subtitle": "No one has invited you to a workspace yet.", + "scenes.app.workspaces.welcome_page.ready_to_work": "You're ready to work now.", + "scenes.app.workspaces.welcome_page.see_you_soon": "See you soon!", + "scenes.app.workspaces.welcome_page.try_again": "Try again", + "scenes.app.workspaces.welcome_page.twake_team": "Twake", + "scenes.app.workspaces.welcome_page.welcome_header": "Welcome to Twake!", + "scenes.app.workspaces.welcome_page.add_secondary_emails_comment": "You can link multiple e-mail addresses to your account; only one address will be used to send you notifications.", + "scenes.app.workspaces.welcome_page.main_mail_title": "Main address", + "scenes.app.workspaces.welcome_page.other_mail_title": "Secondary addresses", + "scenes.app.workspaces.welcome_page.add_new_email": "Add an e-mail", + "scenes.app.workspaces.welcome_page.code_verification": "Verification code", + "scenes.app.workspaces.welcome_page.new_email": "Add a secondary e-mail", + "scenes.app.workspaces.welcome_page.we_sent_you_mail": "We sent you a verification code via {{$1}}", + "scenes.app.workspaces.welcome_page.done": "I'm done", + "scenes.login.forgot_password.finished": "Your password was successfully updated.", + "scenes.apps.account.account.description_main": "Your main address is where Twake sends your notifications. Your secondary addresses allow you to be automatically invited to the workspaces that use them.", + "scenes.apps.account.account.emails.description": "Manage your different e-mail addresses.", + "scenes.apps.account.account.make_main": "Set main", + "scenes.apps.account.account.password.description": "Change your password.", + "scenes.apps.account.identity": "Identity", + "scenes.apps.account.identity.description": "Change your first name, last name and profile image visible to other Twake users.", + "scenes.apps.account.preference": "Preferences", + "general.open": "Open", + "scenes.apps.account.thumbnail.max_weight": "Maximum size 5 MB", + "scenes.apps.account.account.email_add_modal.confirm": "Confirm this e-mail", + "app.name.twake_calendar": "Calendar", + "app.name.twake_drive": "Documents", + "app.name.twake_tasks": "Tasks", + "components.calendar.repetition.everyday": "Daily", + "components.calendar.repetition.does_not_repeat": "Does not repeat", + "components.calendar.repetition.weekly_on": "Weekly on {{$1}}", + "components.calendar.repetition.monthly_on": "Monthly on the {{$1}} {{$2}}", + "components.calendar.repetition.monthly_on_day": "Monthly on day {{$1}}", + "components.calendar.repetition.annually_on": "Annually on {{$1}}", + "components.calendar.repetition.every_weekday": "Every weekday (Mon to Fri)", + "components.calendar.repetition.custom": "Custom...", + "components.calendar.repetition.repeat": "Repeat every", + "components.calendar.repetition.ends": "Ends", + "components.calendar.repetition.never": "Never", + "components.calendar.repetition.on": "On", + "components.calendar.repetition.after": "After", + "components.calendar.repetition.days": "day(s)", + "components.calendar.repetition.weeks": "week(s)", + "components.calendar.repetition.months": "month(s)", + "components.calendar.repetition.years": "year(s)", + "components.calendar.repetition.custom_recurrence": "Custom recurrence", + "components.calendar.repetition.occurrence": "Occurrence(s)", + "components.calendar.repetition.repeat_on": "Repeat on", + "scenes.app.channelsbar.currentuser.add_apps": "Search applications", + "scenes.app.channelsbar.currentuser.change_my_status": "Change my status", + "scenes.app.channelsbar.currentuser.collaborateurs": "Users", + "scenes.app.channelsbar.currentuser.create_workspace_page": "Create a workspace", + "scenes.app.channelsbar.currentuser.invited_status": "You are a guest.", + "scenes.app.channelsbar.currentuser.title": "Account settings", + "scenes.app.channelsbar.currentuser.workspace_info": "You are in the workspace {{$1}} from the group {{$2}}", + "scenes.app.channelsbar.currentuser.workspace_parameters": "Workspace settings", + "scenes.app.channelsbar.currentuser.logout": "Sign out", + "scenes.app.channelsbar.currentuser.update": "Update", + "scenes.app.channelsbar.currentuser.disable_notifications": "Disable", + "scenes.app.channelsbar.currentuser.disabling_notifications": "Disable for 1h", + "scenes.app.channelsbar.currentuser.disabling_notifications_until": "Disable until 9 A.M. tomorrow", + "scenes.app.channelsbar.currentuser.reactivate_notifications": "Reactivate", + "scenes.app.channelsbar.currentuser.user_parameter": "Notification settings", + "scenes.app.channelsbar.currentuser.company_messages_counter_header": "Messages number", + "scenes.app.channelsbar.currentuser.company_messages_counter_info": "On the free version of Twake, you cannot access more than {{$1}} recent messages.", + "scenes.app.channelsbar.currentuser.company_messages_counter_link": "Show more plans", + "scenes.app.channelsbar.channelsuser.new_private_discussion": "New private discussion", + "scenes.app.channelsbar.channelsuser.no_private_message_invite_collaboraters": "No private messages. Invite users!", + "scenes.app.channelsbar.channelsuser.private_messages": "Direct messages", + "scenes.app.channelsbar.channelsworkspace.channel_title": "CHANNELS", + "scenes.app.channelsbar.channelsworkspace.channel_title.favorite": "FAVORITES", + "scenes.app.channelsbar.channelsworkspace.create_channel": "Create a channel", + "scenes.app.channelsbar.channelsworkspace.no_channel": "You did not join any channel yet", + "scenes.app.channelsbar.modify_channel_menu": "Channel settings", + "scenes.app.channelsbar.guest_management": "Guest management", + "scenes.app.channelsbar.read_sign": "Mark as read", + "scenes.app.channelsbar.unread_sign": "Mark as unread", + "scenes.app.channelsbar.channel_copy_link": "Copy channel link", + "scenes.app.channelsbar.channel_leaving": "Leave channel", + "scenes.app.channelsbar.channel_access": "Channel access", + "scenes.app.channelsbar.channel_access.save": "Save access settings", + "scenes.app.channelsbar.channel_access.readonly": "Read-only channel", + "scenes.app.channelsbar.channel_access.readonly.info": "Restrict write to moderators, admins and owners.", + "scenes.app.channelsbar.channel_access.visibility": "Public visibility", + "scenes.app.channelsbar.channel_access.visibility.info": "Anyone except company guests can join.", + "scenes.app.channelsbar.channel_access.default": "Auto join", + "scenes.app.channelsbar.channel_access.default.info": "New members will be added here automatically.", + "scenes.app.channelsbar.channel_information": "Edit channel information", + "scenes.app.channelsbar.channel_information.logo.add": "Upload picture", + "scenes.app.channelsbar.channel_information.logo.remove": "Remove picture", + "scenes.app.channelsbar.channel_information.name": "Channel name", + "scenes.app.channelsbar.channel_information.description": "Channel description", + "scenes.app.channelsbar.channel_information.description.placeholder": "Channel description, you can use markdown.", + "scenes.app.channelsbar.channel_information.group": "Channel group", + "scenes.app.channelsbar.channel_information.group.none": "Not selected", + "scenes.app.channelsbar.channel_information.group.new": "Create a new group", + "scenes.app.channelsbar.channel_information.group.save": "Set channel group to {{$1}}", + "scenes.app.channelsbar.channel_information.group.title": "Channel groups", + "scenes.app.channelsbar.channel_information.group.save_none": "Do not set channel group", + "scenes.app.channelsbar.channel_information.save": "Save information", + "scenes.app.channelsbar.channel_removing": "Delete channel", + "scenes.app.channelsbar.company_invitation_alert_subtitle": "You can import these channels into your business to stay organized by clicking on this frame.", + "scenes.app.channelsbar.company_invitation_alert_title": "You are invited to the company ", + "scenes.app.channelsbar.initial_instructions_tutorial": "Choose a first name, a name and a profile picture.", + "scenes.app.channelsbar.installation_desktop_tutorial": "Install the desktop application", + "scenes.app.channelsbar.invitation_collaboraors_tutorial": "Invite users into your workspace.", + "scenes.app.channelsbar.public_channel_label": "Public", + "scenes.app.channelsbar.private_channel_label": "Private", + "scenes.app.channelsbar.sending_message_instruction": "Send your first message in a discussion", + "scenes.app.channelsbar.tutorial_alert": "Never show this frame again?", + "scenes.app.channelsbar.welcome": "Welcome to Twake", + "scenes.app.channelsbar.welcoming_message_subtitle": "Become a Twake pro in just a few clicks!", + "scenes.app.mainview.instruction_current_tab": "Start by selecting a channel on your left.", + "scenes.app.mainview.tabs.no_connected_connectors_for_channel": "You have no connector that can connect to a channel.", + "scenes.app.mainview.tabs.rename": "Rename", + "scenes.app.mainview.tabs.searching_connectors": "Search connectors...", + "scenes.app.popup.adduser.adresses_message": "Please separate the addresses with a comma or space. Remember that Twake can limit the number of invitations based on your subscription.", + "scenes.app.popup.adduser.magiclinks.genrator_info": "Invitation link to the workspace", + "scenes.app.popup.adduser.magiclinks.new_link_generated": "New link generated", + "scenes.app.popup.adduser.magiclinks.copied_to_clipboard": "Successfully copied to clipboard", + "scenes.app.popup.adduser.magiclinks.action_copy": "Copy", + "scenes.app.popup.adduser.magiclinks.action_generate": "Generate", + "scenes.app.popup.appsparameters.pages._app_identity": "Identity of the application", + "scenes.app.popup.appsparameters.pages._appareance_message_twakcode": "Test the appearance of your Twacode messages", + "scenes.app.popup.appsparameters.pages.alert_published_app": "Your application is published, you can not edit it.", + "scenes.app.popup.appsparameters.pages.allowed_ip_adresses_method": "Use * in development to allow all IP addresses.", + "scenes.app.popup.appsparameters.pages.amazing_app_name": "My amazing app", + "scenes.app.popup.appsparameters.pages.api_data_description": "Useful data for the Twake API.", + "scenes.app.popup.appsparameters.pages.api_parameters_label": "API settings", + "scenes.app.popup.appsparameters.pages.app_name_label": "Application name", + "scenes.app.popup.appsparameters.pages.app_modification_right": "All managers of this company will be able to edit this application.", + "scenes.app.popup.appsparameters.pages.app_privileges_information": "Define what your application can edit and read.", + "scenes.app.popup.appsparameters.pages.app_privileges_label": "Application privileges", + "scenes.app.popup.appsparameters.pages.app_update": "Update the app {{$1}} (the app is used {{$2}} times)", + "scenes.app.popup.appsparameters.pages.application_title": "Application", + "scenes.app.popup.appsparameters.pages.apps_title": "Your applications and connectors", + "scenes.app.popup.appsparameters.pages.automatique_label": "Automatic", + "scenes.app.popup.appsparameters.pages.automatique_option_information": "If you activate 'Automatic', this application will automatically be added to the next workspaces of this company.", + "scenes.app.popup.appsparameters.pages.autorised_ip_adresses_label": "Allowed IP addresses", + "scenes.app.popup.appsparameters.pages.available_publication_alert": "The publication of your application is currently awaiting validation by the Twake team.", + "scenes.app.popup.appsparameters.pages.button_force": "Force throughout the company", + "scenes.app.popup.appsparameters.pages.call_event_handlers": "Event of type '{{$1}}' and id '{{$2}}' with passives '{{$3}}'", + "scenes.app.popup.appsparameters.pages.company_label": "Company owner", + "scenes.app.popup.appsparameters.pages.configuration_label": "Configuration", + "scenes.app.popup.appsparameters.pages.create_app_button": "Create an application", + "scenes.app.popup.appsparameters.pages.create_my_app": "Create my application", + "scenes.app.popup.appsparameters.pages.current_informations_apps_connectors": "You have not created an app yet. Before you create an application or connector, make sure that it does not already exist in our application market.", + "scenes.app.popup.appsparameters.pages.danger_zone_description": "Delete application", + "scenes.app.popup.appsparameters.pages.danger_zone_label": "Dangerous zone", + "scenes.app.popup.appsparameters.pages.description_label": "Description", + "scenes.app.popup.appsparameters.pages.developped_apps_subtitle": "Applications developed by the company", + "scenes.app.popup.appsparameters.pages.dispalyed_parameters_description": "Allows you to define where your application will be visible.", + "scenes.app.popup.appsparameters.pages.displayed_parameters_label": "Display settings", + "scenes.app.popup.appsparameters.pages.error_check_needed": "An error has occurred; check your information.", + "scenes.app.popup.appsparameters.pages.error_message": "This name is already used by another application; please choose another one.", + "scenes.app.popup.appsparameters.pages.error_user_code": "error", + "scenes.app.popup.appsparameters.pages.event_subtitle": "Events", + "scenes.app.popup.appsparameters.pages.filter_information": "This filter limits the use of your API key to servers in your connector only.", + "scenes.app.popup.appsparameters.pages.go_back": "Back", + "scenes.app.popup.appsparameters.pages.grp_section_name-error": "This name is already in use by another application. Please choose another one.", + "scenes.app.popup.appsparameters.pages.grp_section_surname_label": "Simpified name", + "scenes.app.popup.appsparameters.pages.installation": "Instal.", + "scenes.app.popup.appsparameters.pages.instruction_message_twakecode": "Start by writing your message in JSON format.", + "scenes.app.popup.appsparameters.pages.interne_availability_application": "Internal application", + "scenes.app.popup.appsparameters.pages.json_configuration_information": "Go to the documentation to generate your configuration in JSON format.", + "scenes.app.popup.appsparameters.pages.loading": "Loading...", + "scenes.app.popup.appsparameters.pages.message_data_next_event": "Passive data that will be sent in the next Event", + "scenes.app.popup.appsparameters.pages.modify_public_data": "Edit the public data of your application.", + "scenes.app.popup.appsparameters.pages.new_app_title": "New application", + "scenes.app.popup.appsparameters.pages.ok_user_code": "ok", + "scenes.app.popup.appsparameters.pages.optimal_format": "Optimal format : 48x48px.", + "scenes.app.popup.appsparameters.pages.parameters_form_small_text": "The unpublished application will only work in your company. If you want to make it available to all Twake users, activate this option.", + "scenes.app.popup.appsparameters.pages.public_availability_application": "Public application", + "scenes.app.popup.appsparameters.pages.public_login_label": "Public identifier", + "scenes.app.popup.appsparameters.pages.publication_description": "Determine the visibility of your application.", + "scenes.app.popup.appsparameters.pages.publication_label": "Publication", + "scenes.app.popup.appsparameters.pages.publish_app_label": "Publish application", + "scenes.app.popup.appsparameters.pages.read_privileges_label": "Read privileges", + "scenes.app.popup.appsparameters.pages.remove_app": "Delete the application {{$1}} permanently.", + "scenes.app.popup.appsparameters.pages.remove_app_from_company": "Remove from the whole company", + "scenes.app.popup.appsparameters.pages.remove_app_from_workspace": "Remove from workspace", + "scenes.app.popup.appsparameters.pages.show_button": "Show", + "scenes.app.popup.appsparameters.pages.status_tilte": "State", + "scenes.app.popup.appsparameters.pages.string_information": "This string identifies your application and will be used in message commands.", + "scenes.app.popup.appsparameters.pages.title_tester": "Twakecode tester", + "scenes.app.popup.appsparameters.pages.url_reception_events_label": "Url of events reception", + "scenes.app.popup.appsparameters.pages.waiting_availability_application": "Awaiting...", + "scenes.app.popup.appsparameters.pages.website_label": "Website", + "scenes.app.popup.appsparameters.pages.write_privileges_label": "Write privileges", + "scenes.app.popup.appsparameters.pages.danger_zone_small_text": "You can not delete this app if it is published.", + "scenes.app.popup.appsparameters.pages.error_app_simple_name_message": "The simplified name of your application is already used by another application. Please change it.", + "scenes.app.popup.appsparameters.pages.error_app_update_message": "An error occurred while updating the application.", + "scenes.app.popup.appsparameters.pages.remove_app_button": "Delete application", + "scenes.app.popup.appsparameters.pages.update_button": "Update", + "scenes.app.popup.createworkspacepage.add_subtitle": "Need more space?", + "scenes.app.popup.createworkspacepage.create_new_workspace": "Create a new workspace", + "scenes.app.popup.createworkspacepage.placeholder_name": "Name of the workspace", + "scenes.app.popup.userparameter.pages.email_notif_delay_never": "Never", + "scenes.app.popup.userparameter.pages.email_notif_delay_quarter_hour": "15 minutes", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_day": "1 day", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_hour": "1 hour", + "scenes.app.popup.userparameter.pages.frequency_notif_configuration_description": "Configure mobile push notifications.", + "scenes.app.popup.userparameter.pages.frequency_notif_subtitle": "Frenquency of notifications", + "scenes.app.popup.userparameter.pages.keywords_notif_description": "Highlight the following keywords:", + "scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description": "Configure email notifications digest.", + "scenes.app.popup.userparameter.pages.private_message_content.show": "Hide the content of messages in push notifications", + "scenes.app.popup.userparameter.pages.private_message_content.hide": "Replace push notification content with '[Private]'", + "scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description": "Choose a period during which you do not receive notifications.", + "scenes.app.popup.userparameter.pages.no_night_disturbing_label": "Do not disturb at night", + "scenes.app.popup.userparameter.pages.notif_content_label": "Content of notifications", + "scenes.app.popup.userparameter.pages.notification_sound.defaut": "Default", + "scenes.app.popup.userparameter.pages.notification_sound.none": "None", + "scenes.app.mainview.quick_search_placeholder": "Quick search", + "scenes.app.popup.userparameter.personnal_workspaces_title": "Your workspaces", + "scenes.app.popup.workspaceparameter.admin_current_status": "You are an Administrator.", + "scenes.app.popup.workspaceparameter.admin_manager_current_status": "You are a workspace administrator.", + "scenes.app.popup.workspaceparameter.manager_current_status": "You are a company administrator.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace": "Delete workspace", + "scenes.app.popup.workspaceparameter.pages.error_workspace_member": "You must be alone in the workspace to remove it. Remove your collaborators and try again.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace_description": "Deleting a workspace cannot be undone. All messages and files will be irretrievable.", + "scenes.app.popup.workspaceparameter.pages.enter": "Enter ", + "scenes.app.popup.workspaceparameter.pages.access_apps": "Access your applications and connectors", + "scenes.app.popup.workspaceparameter.pages.moderator_status": "Workspace moderator", + "scenes.app.popup.workspaceparameter.pages.alert_impossible_removing": "You can not leave the workspace, because you are the last administrator. You can define a new administrator or delete/archive this workspace.", + "scenes.app.popup.workspaceparameter.pages.all_apps_small_text": "All applications", + "scenes.app.popup.workspaceparameter.pages.apps_company_small_text": "Your company's applications", + "scenes.app.popup.workspaceparameter.pages.apps_connectors_title": "Integrations", + "scenes.app.popup.workspaceparameter.pages.apps_research_title": "Search applications", + "scenes.app.popup.workspaceparameter.pages.apps_small_text": "Applications of this workspace", + "scenes.app.popup.workspaceparameter.pages.back_to_search_button": "Return to the search", + "scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button": "Invite users", + "scenes.app.popup.workspaceparameter.pages.collaborateurs": "Users", + "scenes.app.popup.workspaceparameter.pages.company_developped_apps_subtitle": "Applications developed by the company", + "scenes.app.popup.workspaceparameter.pages.company_identity_title": "Identity of the company", + "scenes.app.popup.workspaceparameter.pages.company_name_description": "Change the name of this company", + "scenes.app.popup.workspaceparameter.pages.company_name_label": "Name of the company", + "scenes.app.popup.workspaceparameter.pages.configuration_notif": "configuration", + "scenes.app.popup.workspaceparameter.pages.configure_button": "Preferences ", + "scenes.app.popup.workspaceparameter.pages.description": "Description", + "scenes.app.popup.workspaceparameter.pages.developped_apps_small_text": "Applications developed by the company", + "scenes.app.popup.workspaceparameter.pages.displayed_preferencies_subtitle": "Display preferences", + "scenes.app.popup.workspaceparameter.pages.install_button": "Install", + "scenes.app.popup.workspaceparameter.pages.installed_app_information": "Install the application in this workspace.", + "scenes.app.popup.workspaceparameter.pages.installed_apps_information": "Applications installed in this workspace {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_message": "Applications installed in other areas of the company {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_subtitle": "Installed applications", + "scenes.app.popup.workspaceparameter.pages.invitation_error": "An error occurred while inviting the following users: ", + "scenes.app.popup.workspaceparameter.pages.invited_guest_check_message": "Check that the username or e-mail used is valid.", + "scenes.app.popup.workspaceparameter.pages.logo_modify_description": "Edit the image of this workspace", + "scenes.app.popup.workspaceparameter.pages.logo_subtitle": "Logo", + "scenes.app.popup.workspaceparameter.pages.name_description": "Change the name of this workspace", + "scenes.app.popup.workspaceparameter.pages.name_label": "Name of the workspace", + "scenes.app.popup.workspaceparameter.pages.no_access": "No access.", + "scenes.app.popup.workspaceparameter.pages.no_app_information": "You have no applications in this workspace", + "scenes.app.popup.workspaceparameter.pages.quit_workspace_menu": "Leave this workspace", + "scenes.app.popup.workspaceparameter.pages.read_access_subtitle": "Read access", + "scenes.app.popup.workspaceparameter.pages.remove_from_company_text": "Remove from the whole company", + "scenes.app.popup.workspaceparameter.pages.research_by": "Search applications by name and categories", + "scenes.app.popup.workspaceparameter.pages.researching_apps_button": "Search applications...", + "scenes.app.popup.workspaceparameter.pages.show_button": "Display", + "scenes.app.popup.workspaceparameter.pages.title": "Workspace settings", + "scenes.app.popup.workspaceparameter.pages.webhooks_access_subtitle": "Access to webhooks", + "scenes.app.popup.workspaceparameter.pages.weight_max_small_text": "Maximum size 5 MB.", + "scenes.app.popup.workspaceparameter.pages.withdraw_button": "Remove from this workspace", + "scenes.app.popup.workspaceparameter.pages.worspace_notif": "workspace", + "scenes.app.popup.workspaceparameter.pages.write_access_subtitle": "Write access", + "scenes.app.popup.workspaceparameter.pages.your_apps_label": "Your applications", + "scenes.app.popup.workspaceparameter.payments_subscriptions_title": "Payments and subscriptions", + "scenes.app.workspacesbar.components.change_company_title": "Change company", + "scenes.app.workspacesbar.components.create_company_menu": "Create a company", + "scenes.app.workspacesbar.components.grp_parameters": "{{$1}} settings", + "scenes.apps.calendar.add_calendar_menu": "Add a calendar", + "scenes.apps.calendar.connectors_menu": "Connectors...", + "scenes.apps.calendar.connectors_search_menu": "Search connectors...", + "scenes.apps.calendar.create_calendar_title": "Create a calendar", + "scenes.apps.calendar.day_option": "Day", + "scenes.apps.calendar.edit_calendar_title": "Edit the calendar", + "scenes.apps.calendar.export_title": "Export", + "scenes.apps.calendar.export_view_menu": "Export the view...", + "scenes.apps.calendar.ics_download_menu": "Download an ICS file", + "scenes.apps.calendar.ics_subscription_menu": "Get an ICS subscription link", + "scenes.apps.calendar.modals.advanced_options": "Advanced options", + "scenes.apps.calendar.modals.description_placeholder": "Description", + "scenes.apps.calendar.modals.details_title": "Details", + "scenes.apps.calendar.modals.event_adresse_placeholder": "Address", + "scenes.apps.calendar.modals.event_description_placeholder": "Description", + "scenes.apps.calendar.modals.event_title_placeholder": "Title", + "scenes.apps.calendar.modals.modify_event_button": "Edit event", + "scenes.apps.calendar.modals.part.participants": "Participants", + "scenes.apps.calendar.modals.participants_event": "Participants", + "scenes.apps.calendar.modals.reminders": "Reminders", + "scenes.apps.calendar.modals.remove_button": "Delete", + "scenes.apps.calendar.modals.remove_event_button": "Delete event", + "scenes.apps.calendar.modals.remove_event_text": "Delete the event?", + "scenes.apps.calendar.modals.title_placeholder": "Title", + "scenes.apps.calendar.modify_calendar_menu": "Edit the calendar", + "scenes.apps.calendar.month_option": "Month", + "scenes.apps.calendar.my_calendar": "My calendar", + "scenes.apps.calendar.my_calendar_label": "My calendar", + "scenes.apps.calendar.my_calendar_menu": "My calendar", + "scenes.apps.calendar.no_calendar_text": "You have not set any calendars for this workspace.", + "scenes.apps.calendar.no_connectors_menu_text": "You do not have any connectors that can connect to a calendar.", + "scenes.apps.calendar.remove_calendar_confirmation": "Delete the calendar and its events permanently?", + "scenes.apps.calendar.today_menu": "Today", + "scenes.apps.calendar.week_option": "Week", + "scenes.apps.calendar.workspace": "Workspace", + "scenes.apps.calendar.workspace_label": "This workspace", + "scenes.apps.calendar.workspace_menu": "Workspace", + "scenes.apps.drive.add_button": "Add", + "scenes.apps.drive.message_added_file": "{{$1}} sent {{$2}}.", + "scenes.apps.drive.message_added_mutiple_files": "{{$1}} sent multiple files.", + "scenes.apps.drive.message_added_file_no_name": "{{$1}} sent a file.", + "scenes.apps.drive.choose_folder_button": "Choose a directory", + "scenes.apps.drive.choose_file_button": "Select a file", + "scenes.apps.drive.create_folder_button": "Create", + "scenes.apps.drive.download_button": "Download", + "scenes.apps.drive.open_link": "Open link in new window", + "scenes.apps.drive.files_subtitle": "Files", + "scenes.apps.drive.folder_subtitle": "Folders", + "scenes.apps.drive.go_out_trash_menu": "Leave trash", + "scenes.apps.drive.go_trash_menu": "Go to trash", + "scenes.apps.drive.import_from_computer_menu": "Upload from computer", + "scenes.apps.drive.move_text": "Move", + "scenes.apps.drive.new_file_menu": "New file", + "scenes.apps.drive.new_file_title": "New file", + "scenes.apps.drive.new_external_storage": "New external storage", + "scenes.apps.drive.new_folder_title": "New folder", + "scenes.apps.drive.no_file_alert": "You have no applications that allow you to create a file.", + "scenes.apps.drive.no_storage_app_alert": "You have no applications that allow you to add external storage.", + "scenes.apps.drive.remove_definitely_menu": "Delete permanently", + "scenes.apps.drive.restore_menu": "Restore", + "scenes.apps.drive.throw_menu": "Send to the trash", + "scenes.apps.drive.trash_empty_menu": "Empty the trash", + "scenes.apps.drive.unconfigured_tab": "This tab is not configured yet.", + "scenes.apps.drive.viewer.edit_with_button": "Edit with {{$1}}", + "scenes.apps.drive.viewer.loading_preview_message": "Loading...", + "scenes.apps.drive.viewer.no_preview_message": "Can not view this kind of file.", + "scenes.apps.drive.viewer.open_with_button": "Open with...", + "scenes.apps.messages.input.placeholder": "Write a message. Use @ to quote a user.", + "scenes.apps.messages.input.edited": "Edited", + "scenes.apps.messages.just_you": "Visible only to you", + "scenes.apps.messages.message.new_messages_bar": "New messages", + "scenes.apps.messages.message.cancel_button": "Cancel", + "scenes.apps.messages.message.modify_button": "Edit", + "scenes.apps.messages.message.forward": "Forward", + "scenes.apps.messages.message.forward.title": "Forward message", + "scenes.apps.messages.message.forward.comment": "Add a message", + "scenes.apps.messages.message.forward.confirm": "Send to {{$1}} channel(s)", + "scenes.apps.messages.message.forward.send": "Message forwarded", + "scenes.apps.messages.message.pin_button": "Pin message", + "scenes.apps.messages.message.unpin_button": "Unpin message", + "scenes.apps.messages.message.copy_link": "Copy link to message", + "scenes.apps.messages.message.pinned": "Pinned", + "scenes.apps.messages.message.remove_button": "Delete", + "scenes.apps.messages.message.reply_button": "Reply", + "scenes.apps.messages.message.save_button": "Save", + "scenes.apps.messages.message.show_button": "Display", + "scenes.apps.messages.message.show_responses_button": "See previous answers", + "scenes.apps.messages.message.types.first_channel_message_text": "This is the first message of the channel", + "scenes.apps.messages.message.types.first_message_text": "This is the first message", + "scenes.apps.messages.message.types.no_message_in_thread": "Nobody replied yet.", + "scenes.apps.messages.message.user_deactivated": "You are viewing the archives of a deactivated account", + "scenes.apps.messages.messageslist.get_writing_user": "is writing...", + "scenes.apps.messages.messageslist.get_writing_users": "are writing...", + "scenes.apps.messages.messageslist.go_last_message_button": "Go to last message", + "scenes.apps.messages.messageslist.go_last_message_button.new_messages": "New messages", + "scenes.error_on_twake": "β€œHouston we have a problemβ€œ", + "scenes.help_us": "However, if you would like to help us fix this error, send us a message below: ", + "scenes.login.verifymail.alert": "We are checking your e-mail!", + "scenes.login.verifymail.error_message": "An error occurred", + "scenes.login.verifymail.signin_button": "Log in", + "scenes.login.verifymail.success": "Your e-mail was successfully verified!", + "scenes.login.verifymail.verification_waiting": "Waiting for verification...", + "scenes.no_panic": "Don't panic! Just reload this page to fix Twake.", + "services.apps.calendar.deadline_icon": "Deadline", + "services.apps.calendar.event_icon": "Event", + "services.apps.calendar.move_icon": "Move", + "services.apps.calendar.reminder_icon": "Reminder", + "services.apps.messages.no_app": "This application does not exist.", + "services.apps.messages.no_command_possible": "We can not execute the command '{{$1}}' because '{{$2}}' does not exist or does not allow to create commands.", + "services.user.notification_parameters_update_alert": "The notification settings have been updated.", + "services.user.update_password_alert": "Your password has been updated.", + "'": "'", + "\"": "\"", + "login.create_account": "Create account", + "login.login_error": "Error during login", + "scenes.app.workspaces.components.skip": "Skip", + "scenes.apps.calendar.unconfigured_tab": "This tab is not configured yet.", + "scenes.apps.drive.trash": "Trash", + "scenes.apps.drive.top_menu_more": "More", + "scenes.apps.drive.top_menu_no_items": "{{$1}} items", + "scenes.apps.messages.new_thread": "Start a new discussion", + "scenes.apps.messages.input.send_message": "Send message", + "scenes.apps.messages.input.emoji": "Emoji", + "scenes.apps.messages.input.hide_formatting": "Hide formatting", + "scenes.apps.messages.input.show_formatting": "Show formatting", + "scenes.tell_us": "Please tell us what you were doing at:", + "scenes.apps.drive.viewer.download_desktop": "Download Twake Desktop to preview in app", + "scenes.apps.tasks.my_tasks": "My tasks", + "scenes.apps.tasks.board.place_holder": "Board name", + "scenes.apps.tasks.board.tasks.subtask": "Subtask", + "scenes.apps.tasks.board.tasks.add_subtask": "Add a subtask", + "scenes.apps.tasks.board.tasks.use_deadline": "Use deadline", + "scenes.apps.tasks.board.tasks.use_starttime": "Use start time", + "scenes.apps.tasks.board.tasks.in_list": "In list", + "scenes.apps.tasks.board.starts": "Starts the", + "scenes.apps.tasks.board.ends": "To be done for the", + "scenes.apps.tasks.board.list_name": "List name", + "scenes.app.popup.sync_calendar": "Synchronize your calendars.", + "scenes.apps.parameters.workspace_sections.workspace.logo_company": "Logo of the company", + "scenes.app.popup.workspaceparameter.pages.logo_company_modify_description": "Edit company image ", + "scenes.app.popup.workspaceparameter.pages.cancel_invitation": "Cancel the invitation", + "scenes.apps.account.account.fullname": "Full name", + "login.email_login": "E-mail / Login", + "scenes.apps.account.account.password_for_user": "Password for your user", + "scenes.apps.account.account.send_info": "Send this credential information to your user.", + "scenes.apps.account.account.save": "Save account", + "scenes.apps.account.message_temporary": "A temporary account works like a normal Twake account, but you create the password and you will be able to reset it if necessary.", + "scenes.apps.account.message_user_signin": "Your user can sign in at anytime using this same e-mail and change the temporary account to a normal account.", + "scenes.app.mainview.link_expired": "This public link is invalid or has expired.", + "scenes.app.mainview.create_account": "Create your workspace for free on ", + "scenes.apps.calendar.modals.reminder_add": "Add a reminder", + "scenes.apps.parameters.workspace_sections.members.invite_all": "Invite all", + "scenes.app.taskpicker.select": "Select", + "components.listmanager.filter": "Filter", + "scenes.apps.tasks.no_connector": "No connector", + "components.attachmentpicker.add_attachment": "Add attachments", + "components.input.copied": "Copied", + "components.drive.new_versions": "Add a new version", + "components.drive.navigators.directory_not_found": "Directory not found.", + "components.drive.right_preview.suppress_link": "Suppress the link", + "components.drive.right_preview.create_link": "Create an access link", + "components.drive.moove_here": "Move here", + "components.drive.modify_uslist": "Modify user list", + "components.tagpicker.tag_name": "Tag name", + "components.upload.drop_files": "Drop your files here", + "components.workspace.list_manager.no_workspace": "No workspace", + "components.workspace.list_manager.add": "Add workspaces", + "components.workspace.list_manager.current_space": "Current workspace", + "components.workspace.list_manager.current_company": "Current company", + "components.workspace.list_manager.all": "All", + "components.workspace.calendar.invalid": "Invalid", + "components.searchpopup.header_title": "Search", + "components.searchpopup.enter_text": "Enter some text to search Twake.", + "components.searchpopup.loading": "Loading more results", + "components.searchpopup.filter_ws": "Filter workspaces", + "components.searchpopup.tags": "Tags", + "components.searchpopup.size": "Size", + "components.searchpopup.creation": "Creation", + "components.searchpopup.update_search": "Update search", + "components.searchpopup.last_modif": "Last modification", + "components.searchpopup.sender": "Sender", + "components.searchpopup.mentions": "Mentions", + "components.searchpopup.only_pinned": "Only pinned messages", + "components.alert.confirm": "Confirm your action", + "components.alert.confirm_click": "Confirm your action by clicking on OK.", + "components.searchpopup.tasks": "Tasks", + "scenes.app.mainview.advanced_search_placeholder": "Advanced search", + "components.searchpopup.hide_filters": "hide filters", + "components.searchpopup.show_filters": "show filters", + "components.searchpopup.load_more": "Load more results", + "components.searchpopup.start_search": "Enter few keywords to start the search.", + "components.searchpopup.no_results_for": "There were no results for", + "components.searchpopup.try_new_search": "Try a new search", + "components.searchpopup.scope.company": "in all company", + "components.searchpopup.scope.channel": "in this channel", + "components.searchpopup.all": "All", + "components.searchpopup.chats": "Chats", + "components.searchpopup.channels": "Channels", + "components.searchpopup.messages": "Messages", + "components.searchpopup.media": "Media", + "components.searchpopup.files": "Files", + "components.searchpopup.drive": "Drive", + "components.searchpopup.see_more": "See more", + "components.searchpopup.recent_chats": "Recent chats", + "components.searchpopup.recent_media": "Recent media", + "components.searchpopup.recent_files": "Recent files", + "components.searchpopup.recent_channels_and_contacts": "Recent channels and contacts", + "components.channelselector.title": "Select channels", + "components.channelselector.confirm": "Select ${{1}} channel(s)", + "components.channelselector.search": "Search channels and discussions", + "general.more": "More", + "scenes.apps.board.archived_tasks": "Archived tasks ({{$1}})", + "scenes.apps.board.active_tasks": "Active tasks", + "scenes.apps.board.kanban": "Kanban", + "scenes.apps.board.display_as": "Display as", + "scenes.apps.board.new_task": "+ New task", + "scenes.apps.board.all_boards": "All Boards", + "components.userlistmanager.no_users": "No users.", + "scenes.apps.drive.used": "used in this folder", + "components.reminder.notification": "Notification", + "components.reminder.minutes_bef": "minutes before", + "components.reminder.hours_bef": "hours before", + "components.reminder.days_bef": "days before", + "components.reminder.weeks_bef": "weeks before", + "components.reminder.by_email": "E-Mail", + "scenes.apps.calendar.reminders": "reminder(s)", + "scenes.apps.calendar.video_link": "Click to open link", + "scenes.app.mainview.discussion": "Discussion", + "components.tagpicker.notag": "No tag", + "scenes.apps.tasks.modals.attachments": "Attachments", + "components.calendar.calendarselector.from": "From", + "scenes.apps.drive.move_text2": "Move", + "components.attachmentpicker.from_computer": "From your device", + "components.attachmentpicker.from_twake": "From Twake Documents", + "components.attachmentpicker.file": "File", + "components.attachmentpicker.remove_attach": "Remove attachment", + "scenes.apps.drive.remove_attachs": "Remove attachments", + "components.drive.elements.see": "See", + "components.drive.elements.current_name": "Current name: ", + "scenes.apps.drive.right_preview.public": "Public access", + "components.drive.elements.configurate_mod": "Configure the mod...", + "components.drive.elements.manage_version": "Manage versions", + "scenes.app.popup.createcompany.try_again": "Please try again.", + "scenes.app.popup.workspace.edit_temp": "Edit temporary account", + "scenes.app.popup.workspace.create_temp": "Create temporary account", + "scenes.apps.tasks.active_tasks": "active tasks", + "scenes.apps.drive.right_preview.versions": "Versions", + "scenes.app.popup.appsparameters.pages.apps_connectors_small_text": "Manage your applications and connectors.", + "scenes.app.popup.appsparameters.pages.icon": "Icon", + "scenes.app.popup.appsparameters.pages.title_informations": "Basic information", + "scenes.app.popup.appsparameters.pages.subtitle_informations": "Information related to application management", + "scenes.app.popup.appsparameters.pages.smalltext_user_id": "Current user id", + "scenes.app.popup.appsparameters.pages.smalltext_workspace_id": "Current workspace id", + "scenes.app.popup.appsparameters.pages.smalltext_group_id": "Current group id", + "scenes.app.mainview.channel_description": "Describe the channel", + "scenes.client.channelbar.channeltemplateeditor.checkbox": "Automatically invite all workspace users to this channel", + "scenes.client.channelbar.channelmemberslist.title": "Users in {{$1}}", + "scenes.client.channelbar.channelmemberslist.loader": "Load more", + "scenes.client.channelbar.channelmemberslist.autocomplete": "Search users", + "scenes.client.channelbar.channelmemberslist.search_invite": "Search and invite users to this channel", + "scenes.client.channelbar.channelmemberslist.search_invite_notice": "There is not a lot of members in this channel. Search and invite users now by email or name.", + "scenes.client.channelbar.channelmemberslist.invite_email_button": "Add to channel only as guest", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace": "Add to channel and workspace as member", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace_confirm": "Invite {{$1}} to workspace as member?", + "scenes.client.channelbar.channelmemberslist.search_invite_type_email": "Type a valid addess to invite by email.", + "scenes.client.channelbar.channelmemberslist.pending_section": "Users pending invitation", + "scenes.client.channelbar.channelmemberslist.members_section": "Users in this channel", + "scenes.client.channelbar.channelmemberslist.not_members_section": "Users not in this channel", + "scenes.client.channelbar.channelmemberslist.menu.option_2": "Remove from channel", + "scenes.client.channelbar.readonly_channel.checkbox": "Restrict write-abitility", + "components.leftbar.channel.workspaceschannels.menu.option_1": "Create a channel", + "components.leftbar.channel.workspaceschannels.menu.option_2": "Join a channel", + "components.channelworkspacelist.title": "Channels", + "scenes.client.channelbar.workspacechannellist.autocomplete": "Search channel, user or direct messages", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_creation": "Create a new tab", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_edition": "Rename {{$1}}", + "components.connectorslistmanager.add_connectors": "Add connectors", + "components.notifications.hidden_notifications_button.children": "New messages", + "scenes.client.mainview.tabs.tabstemplateeditor.select_placeholder": "Application", + "scenes.client.channelbar.channelmemberslist.no_members": "There is no user in this channel, you can invite them by clicking on Add users.", + "scenes.app.channelsbar.hide_discussion_leaving.menu": "Hide discussion", + "scenes.app.popup.adduserfromtwakeconsole.current_users_state": "{{$1}} email(s) will be added", + "components.newversion.new_version_component.row.part_1": "You are running an outdated Twake version", + "components.newversion.new_version_component.row.part_2": "we suggest you to reload the app and enjoy our new features!", + "components.newversion.new_version_component.link": "Click here to reload", + "components.newversion.new_version_modal.title": "New update available !", + "scenes.apps.drive.download_all_button": "Download all", + "components.inputs.input_with_select.input.placeholder": "Channel name", + "components.inputs.input_with_select.select.placeholder": "Section name", + "components.inputs.input_with_select.select.no_sections": "You can group your channels here", + "components.inputs.input_with_select.button.tooltip": "Set a channel section", + "scenes.apps.messages.message.activity_message.a_added_b_to_the_channel": "{{$1}} added {{$2}} to the channel", + "scenes.apps.messages.message.activity_message.a_removed_b_from_the_channel": "{{$1}} removed {{$2}} from the channel", + "scenes.apps.messages.message.activity_message.a_updated_channel_description": "{{$1}} changed the description", + "scenes.apps.messages.message.activity_message.a_updated_channel_name": "{{$1}} renamed the channel to {{$2}}", + "scenes.apps.messages.message.activity_message.a_created_channel_tab": "{{$1}} added a new {{$2}} tab {{$3}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_tab": "{{$1}} removed {{$2}} tab {{$3}}", + "scenes.apps.messages.message.activity_message.a_created_channel_connector": "{{$1}} added a new connector {{$2}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_connector": "{{$1}} removed a connector {{$2}}", + "scenes.client.channelbar.channelmemberslist.tag": "You", + "components.alert.leave_private_channel.title": "Are you sure you want to leave the channel ?", + "components.alert.leave_private_channel.description": "You will not be able to join this private channel again unless someone invite you.", + "scenes.client.join_private_channel.info": "The content of this channel is restricted or doesn't exist. Please contact a member of this channel to get invited.", + "scenes.client.readonly.info": "This channel is a read-only feed but you can comment in the threads.", + "scenes.client.join_public_channel": "Join this channel", + "scenes.client.join_public_channel.info": "You are not a member of this direct channel. Click this button to start the discussion now.", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.tag": "You are not a member", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.loader": "Load more", + "general.re_send": "Re-send", + "general.verify": "Verify", + "general.yes": "Yes", + "general.no": "No", + "components.unverified_account.typography_text_danger": "Please verify your account within {{$1}} days. If not, your account will be blocked after 7 days and permanently deleted after 30 days. You can verify your account through the verification email.", + "components.unverified_account.verification_details": "We have sent verification email to", + "components.account_verification_status_sentence": "Your account status is: {{$1}}", + "components.account_verication_status_unverified": "Unverified", + "components.account_verication_status_blocked": "Locked", + "components.unverified_account.re_send_email": "Didn’t receive the email?", + "components.blocked_account.trial_period_over": "Your trial period is over. To unlock your account and get access to all functionalities, please verify your account via email confirmation", + "components.add_mails_workspace.button": "Start using Twake", + "components.add_mails_workspace.title_1": "Add some users", + "components.add_mails_workspace.title_2": "Twake is a team collaboration tool, so invite some users to test a workspace we created for you.", + "components.add_mails_workspace.text_area_placeholder": "Enter emails of your users*", + "components.verify_mail.title_1": "Congratulations", + "components.verify_mail.title_2": "You are an official Twake user now!", + "components.verify_mail.button": "Add user", + "components.verify_mail.text": "First of all, you have to verify your email address. We’ve sent a verification link to", + "components.verify_mail.paragraph": "You can do it later if you want but unverified accounts have access to only a limited version of Twake", + "services.console_services.toaster.add_emails_error": "Error while adding email(s)", + "services.console_services.toaster.add_email_error_message": "Error while adding {{$1}}", + "services.console_services.toaster.success_verify_email": "A verification link has been sent to your email account", + "scenes.app.popup.workspaceparameter.edit_from_console": "See in Console", + "services.console_services.toaster.success_invite_emails": "Successfully added {{$1}} user(s)", + "scenes.client.channels_bar.modals.guest_management.title": "Manage guests in {{$1}}", + "scenes.client.channels_bar.modals.guest_management.input_placeholder": "Search guests or pending emails", + "scenes.client.channels_bar.modals.guest_management.tips": "Start adding or searching email by using the input above", + "scenes.client.channels_bar.modals.parts.channel_member_row.label.pending_email": "Mail sent", + "general.user.role.company.admin": "Company administrator", + "general.user.role.company.member": "Member", + "general.user.role.company.guest": "Guest", + "general.user.deleted": "Deleted Account", + "general.user.deactivated": "User is no longer in this company", + "general.user.connected": "Online", + "components.richtexteditor.toolbar.bold": "Bold", + "components.richtexteditor.toolbar.underline": "Underline", + "components.richtexteditor.toolbar.italic": "Italic", + "components.richtexteditor.toolbar.strikethrough": "Strikethrough", + "components.richtexteditor.toolbar.code": "Code", + "components.richtexteditor.toolbar.unordered-list": "Bulleted list", + "components.richtexteditor.toolbar.ordered-list": "Ordered list", + "components.richtexteditor.toolbar.blockquote": "Blockquote", + "components.richtexteditor.toolbar.code-block": "Code Block", + "components.locked_features.locked_history_banner.title": "You have just reached the message limit", + "components.locked_features.locked_history_banner.description": "Your company has a lot of messages! Upgrade now to access all your message history.", + "components.locked_features.locked_history_banner.button": "Learn more", + "components.locked_features.locked_guests_popup.title": "Guests feature is locked", + "components.locked_features.locked_guests_popup.subtitle": "This feature is not available in the Twake free version", + "components.locked_features.locked_guests_popup.description": "Whoops!! Seems like you want to invite external users to your workspace. You might want to consider upgrading your plan if you want to collaborate with guests and external partners. Explore our pricing options and select the best option for your team collaboration needs.", + "components.locked_features.locked_guests_popup.learn_more_button": "Learn more", + "components.locked_features.locked_guests_popup.skip_for_now_button": "Skip for Now", + "components.locked_features.locked_guests_popup.or": "Or", + "components.on_boarding.company_billing_banner.admin_or_owner_text": "There is an issue with your company subscription. Please, take a look at your", + "components.on_boarding.company_billing_banner.guest_or_member_text": "There is an issue with your company subscription. Please contact the owner or administrator of the company!", + "components.on_boarding.company_billing_banner.link": "company subscription plan", + "components.on_boarding.popups.blocked_company.title": "Your company is locked because of a payment issue", + "components.on_boarding.popups.blocked_company.description": "Your subscription to Twake has expired. Please contact the owner or administrator of your company to renew it and be able to communicate with your team again !", + "components.on_boarding.popups.blocked_company.learn_more_text": "Want to learn more about companies subscription plan ?", + "components.on_boarding.popups.blocked_company.company_subscription_plan_button": "Click here", + "components.on_boarding.popups.blocked_company.or": "Or", + "components.on_boarding.popups.blocked_company.company_selector": "Switch to another company", + "scenes.apps.tasks.select_user_button": "View tasks for an other user", + "scenes.apps.tasks.select_user": "Search user", + "scenes.apps.messages.input.attach_file.from_computer": "From computer", + "scenes.app.popup.workspaceparameter.pages.table_title": "Name", + "scenes.client.main_view.main_header.search_input": "Search", + "scenes.apps.drive.new_link_title": "New link", + "scenes.apps.drive.default_link_name": "Untitled", + "components.emoji_picker.input_search_placeholder": "Search", + "services.apps.messages.message_editor_service.upload_error_toaster": "{{$1}} - You can not add more than {{$2}} files in a message", + "scenes.apps.messages.message.parts.deleted_content.text.current_user": "You deleted this message", + "scenes.apps.messages.message.parts.deleted_content.text": "{{$1}} deleted his message", + "components.member.user_parts.and_more_user_text": " and {{$1}} more users", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_link": "Create a private channel", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_text": " instead", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_input_placeholder": "You cannot add more than 10 users", + "general.uploading": "Uploading", + "components.upload.drop_files.toaster.error": "You cannot upload more than {{$1}} files", + "components.emoji_picker.categories.frequently_used": "Frequently Used", + "components.emoji_picker.categories.smileys_and_people": "Smileys & People", + "components.emoji_picker.categories.animals_and_nature": "Animals & Nature", + "components.emoji_picker.categories.food_and_drink": "Food & Drink", + "components.emoji_picker.categories.activity": "Activity", + "components.emoji_picker.categories.travel_and_places": "Travel & Places", + "components.emoji_picker.categories.objects": "Objects", + "components.emoji_picker.categories.symbols": "Symbols", + "components.emoji_picker.categories.flags": "Flags", + "components.emoji_picker.categories.search_result": "Search Results", + "components.emoji_picker.categories.not_found": "No Emoji Found", + "scenes.app.popup.workspaceparameter.pages.workspace_partner_tabs.members.table.tags": "Role", + "general.email": "Email", + "components.locked_features.locked_workspace_popup.title": "You can not create more workspaces", + "components.locked_features.locked_workspace_popup.subtitle": "In the free version, you can have just one workspace in your company.", + "components.locked_features.locked_workspace_popup.text": "Whoops!! Do you want to create a new workspace in your company? You might want to consider upgrading your plan. Explore our pricing options and select the best choice for your team collaboration needs.", + "components.locked_features.locked_only_office_popup.title": "You can not edit this file", + "components.locked_features.locked_only_office_popup.subtitle": "In the free version, you can not use onlyoffice.", + "components.locked_features.locked_only_office_popup.text": "Whoops!! Seems like you want to edit the file from Twake. You might want to consider upgrading your plan if you want to collaborate around office files. Explore our pricing options and select the best option for your team collaboration needs.", + "components.locked_features.locked_drive_popup.title": "You have just reached the drive limit", + "components.locked_features.locked_drive_popup.subtitle": "In the free version, you can store only 6GB.", + "general.resume": "Resume", + "general.pause": "Pause", + "scenes.app.integrations_parameters.title": "Integrations", + "scenes.app.integrations_parameters.applications_table.name": "Name", + "scenes.app.integrations_parameters.applications_table.title": "Other integrations", + "scenes.app.integrations_parameters.applications_table.search_placeholder": "Search application", + "scenes.app.integrations_parameters.company_application_popup.tag": "Installed", + "scenes.app.integrations_parameters.company_application_popup.btn": "Install", + "scenes.app.integrations_parameters.company_application_popup.tab_btn_info": "Informations", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.description_item": "Description", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.website_item": "Website", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.created_item": "Creation date", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.version_item": "Version", + "scenes.app.integrations_parameters.company_applications_table.more_menu.show_application": "Show details", + "scenes.app.integrations_parameters.company_applications_table.more_menu.remove_application": "Remove from the company", + "scenes.app.integrations_parameters.company_applications_table.name": "Name", + "scenes.app.integrations_parameters.company_applications_table.title": "Installed in your company", + "app.state.recoil.hooks.use_current_company_applications.toaster_delete": "Successfully deleted {{$1}} from your company", + "app.state.recoil.hooks.use_current_company_applications.toaster_add": "Successfully added {{$1}} in your company", + "scenes.apps.messages.input.replied_to": "replied to ", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.label": "Default workspace", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.description": "Automatically invite all new company users to this workspace", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.title": "You are about to delete {{$1}}", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.alert_total_members": "You still have {{$1}} members in {{$2}}. You should remove all the members to be able to delete this workspace.", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.checkbox": "I understand that all of my workspace's messages and files will be deleted.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.max_size": "Max logo size is 5mb", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.bad_format": "Bad format, only png gif and jpg are allowed", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.unknown": "Unknown error", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.prefix": "Error", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.success.update": "Successfully updated", + "scenes.join.loading": "Loading…", + "scenes.join.wrong_link_title": "This link is not available anymore", + "scenes.join.wrong_link_description": "Ask the person who invited you to join this company for a new link or create your own company", + "scenes.join.create_the_company_button": "Create the company", + "scenes.join.join_workspace_from_company": "Join {{$1}} from {{$2}}!", + "scenes.join.twake_description": "Twake is an open-source digital workspace built to improve your team productivity", + "scenes.join.login_first_button": "Log in or create an account first", + "scenes.join.join_the_team_button": "Join the team", + "scenes.app.channelsbar.currentuser.reset": "Reset", + "components.rich_text_editor.plugins.suggestions.default_message.display_results": "Write at least three letters to display users", + "components.rich_text_editor.plugins.suggestions.loading": "Looking for more", + "components.rich_text_editor.plugins.suggestions.default_message.no_user_found": "No user found", + "components.rich_text_editor.plugins.suggestions.default_message.no_emoji_found": "No emoji found", + "components.rich_text_editor.plugins.suggestions.default_message.no_command_found": "No command found", + "scenes.app.messages.input.parts.is_writing.message.user_is_writing": "{{$1}} is writing...", + "scenes.app.messages.input.parts.is_writing.message.users_are_writing": "{{$1}} and {{$2}} are writing...", + "scenes.app.messages.input.parts.is_writing.message.users_and_more_are_writing": "{{$1}}, {{$2}} and {{$3}} more users are writing...", + "components.locked_features_components.locked_invite_alert.message_part_1": "Your company has reached its maximum limit of {{$1}} members. Please ", + "components.locked_features_components.locked_invite_alert.message_link": "upgrade your company", + "components.locked_features_components.locked_invite_alert.message_part_2": " to invite more members.", + "components.locked_features_components.locked_invite_alert.message_magic_link": " contact the owner or administrator of your company.", + "views.client.popup.workspace_parameter.pages.workspace_members.link_to_console": "See all my company members on the console", + "scenes.app.popup.appsparameters.pages.amazing_app_description": "Describe your application in a few words", + "scenes.app.popup.appsparameters.pages.application_creator.title": "New integration", + "scenes.app.popup.appsparameters.pages.application_creator.checkbox": "I understand that the owner and administrators of this company will be able to modify and publish this application.", + "twake.application.access.title": "Select the right scopes for your application.", + "twake.application.access.no_default_scopes_available'": "This integration doesn't have any {{$1}} access", + "scenes.app.popup.appsparameters.pages.application_editor.help_link": "the Twake API documentation", + "scenes.app.popup.appsparameters.pages.application_editor.help_text": "If you do not know how to fill these, go to ", + "scenes.app.popup.appsparameters.pages.app.private_key": "Private key", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed": "Successfully removed application {{$1}} !", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed_error": "Error while removing application {{$1}} !", + "scenes.app.popup.appsparameters.pages.application_editor.application_published": "Successfully {{$1}} application!", + "scenes.app.integrations_parameters.add_application": "New integration", + "scenes.app.integrations_parameters.company_applications_table.more_menu.developer_settings": "Developer settings", + "components.open_desktop_popup.subtitle": "Opened in Twake app", + "components.open_desktop_popup.open_here_link": "Open in web instead", + "components.open_desktop_popup.open_here_link_forever": "Never try to open app again", + "molecules.download_banner.title": "Get the most out of Twake, download the desktop app now", + "molecules.download_banner.download_button": "Download desktop app", + "components.channel_attachement_list.medias": "Medias", + "components.channel_attachement_list.files": "Files", + "components.channel_attachement_list.title": "Medias and documents", + "components.channel_attachement_list.open": "Open gallery", + "components.channel_attachement_list.nothing_found": "Nothing here yet", + "molecules.message_quote.deleted": "This message was deleted", + "molecules.quoted_content.attachements": "{{$1}} attachments", + "components.message_seen_by.title": "Users who've seen the message", + "components.message_seen_by.none_seen_it": "No one has seen the message yet", + "components.message_seen_by.btn": "Information", + "scenes.client.channelbar.channelmemberslist.invite_to_workspace": "Invite {{$1}} to the workspace ➑", + "components.invitation.reached_limit.text": "you reached the maximum number of users inside your company. Increase your subscription or add these users as guests", + "components.invitation.allow_anyone_by_email.text": "Let anyone with @{{$1}} email join this workspace", + "components.invitation.invitation_channels.button": "Invite to channels", + "components.invitation.invitation_input_list.add": "Add", + "components.invitation.invitation_input_list.member": "Member", + "components.invitation.invitation_input_list.guest": "Guest", + "components.invitation.invitation_input_list.placeholder": "Start typing an email", + "components.invitation.invitation_sent.title": "Invitations have successfully been sent", + "components.invitation.invitation_sent.subtitle_status": "You can track invitaion status in:", + "components.invitation.invitation_sent.subtitle_location": "Workspace settings > Member management", + "components.invitation.invitation_sent.link": "Check invitation status", + "components.invitation.invitation_sent.button": "Send more invitations", + "components.invitation.invitation_target.invite_as_guests": "Invite all as guests", + "components.invitation.invitation_target.invite_as_members": "Invite all as members", + "components.invitation.invitation_target.channels_button": "Select channels", + "components.invitation.workspace_link.text": "Workspace invitation link", + "components.invitation.workspace_link.button": "Copy", + "components.invitation.title": "Invite people to {{$1}}", + "components.invitation.custom_role_invitation": "Classic invitation", + "components.invitation.bulk_invitation": "Multiple emails", + "components.invitation.link": "Link", + "components.invitation.button": "Send invitations" +} diff --git a/twake/frontend/public/locales/eo.json b/twake/frontend/public/locales/eo.json new file mode 100644 index 00000000..b496f0a8 --- /dev/null +++ b/twake/frontend/public/locales/eo.json @@ -0,0 +1,1008 @@ +{ + "scenes.app.workspaces.create_company.group_data.group_main_activity.materials": "Materialoj", + "scenes.app.workspaces.create_company.group_data.group_main_activity.chemistry": "Kemio", + "scenes.app.workspaces.create_company.group_data.group_main_activity.trade_commerce_distribution": "Komerco / Komerco / Distribuado", + "scenes.app.workspaces.create_company.group_data.group_main_activity.publishing_communication_multimedia": "Eldonado / Komunikado / Plurmedia", + "scenes.app.workspaces.create_company.group_data.group_main_activity.machinery_automotive": "Maŝinaro / AΕ­tomobilo", + "scenes.app.workspaces.create_company.group_data.group_main_activity.business_services": "Komercaj servoj", + "scenes.app.workspaces.create_company.group_data.group_main_activity.entertainment": "Amuzado / spektakloj", + "scenes.app.workspaces.create_company.group_data.group_main_activity.textile_clothing_shoes": "Tekstilo / VestaΔ΅o / Ŝuoj", + "scenes.app.workspaces.create_company.group_data.group_main_activity.transport_logistics": "Transporto / Loĝistiko", + "scenes.apps.messages.left_bar.stream_modal.placeholder_name": "Nomo", + "scenes.apps.messages.left_bar.stream.add_to_favorites": "Aldoni al plej ŝatataj", + "scenes.apps.messages.left_bar.stream.notifications": "Sciigoj…", + "scenes.apps.messages.left_bar.stream.notifications.all": "Ajna mesaĝo", + "scenes.apps.messages.left_bar.stream.notifications.mentions": "{{$1}}, {{$2}} kaj {{$3}}", + "scenes.apps.messages.left_bar.stream.notifications.me": "{{$1}} nur", + "scenes.apps.account.account.lastname": "Familia nomo", + "scenes.apps.account.account.username": "Salutnomo", + "scenes.apps.account.account.change_username": "Ŝanĝu vian unikan uzantnomon.", + "scenes.apps.account.account.emails": "Retpoŝtoj", + "scenes.apps.account.account.main_email": "Ĉefa retpoŝto", + "scenes.apps.account.account.email_add": "Aldonu novan retpoŝton", + "scenes.apps.account.account.email_add_modal.invalid_code": "Ĉi tiu kodo estas nevalida", + "scenes.apps.account.notifications.title": "Sciigoj", + "scenes.apps.account.notifications.disturb_option_b": " kaj ", + "scenes.apps.account.notifications.disturb_option_c": " (loka horzono)", + "scenes.apps.account.notifications.devices_subtitle": "Aparataj sciigoj", + "scenes.apps.tasks.task": "Tasko", + "scenes.login.create_account.username": "Salutnomo", + "scenes.login.create_account.username_already_exist": "Ĉi tiu uzantnomo jam estas uzata", + "scenes.login.create_account.fill_in_username": "Vi devas plenigi vian uzantnomon", + "scenes.login.create_account.fill_in_email": "Vi devas plenigi vian retpoŝton per ĝusta retpoŝto", + "scenes.login.create_account.too_short_password": "Via pasvorto devas enhavi almenaΕ­ 8 signojn.", + "scenes.login.create_account.firstname": "AntaΕ­nomo", + "scenes.login.forgot_password.text3": "Enigu novan pasvorton por via konto.", + "scenes.login.forgot_password.password": "Pasvorto", + "scenes.login.forgot_password.password2": "Konfirmu pasvorton", + "scenes.login.forgot_password.password_dont_match": "Viaj pasvortoj ne kongruas aΕ­ ili estas tro mallongaj. Bonvolu tajpi pasvorton kun almenaΕ­ 8 signoj.", + "scenes.login.home.title": "Ensalutu al Twake", + "scenes.login.home.subtitle": "FeliΔ‰a vidi vin", + "scenes.login.home.email": "Retpoŝto", + "scenes.login.create_account.step_2_subtitle_b": "Via telefonnumero restas privata.", + "scenes.login.create_account.step_3_mail_sent": "Ni sendis al vi aktivigan ligilon retpoŝte.", + "scenes.login.create_account.step_3_subtitle": "Lasta paŝo β€” ni devas kontroli, ke vi ne estas roboto!", + "scenes.app.workspaces.welcome_page.try_again": "Provu denove", + "scenes.app.workspaces.welcome_page.twake_team": "Twake", + "scenes.app.workspaces.welcome_page.welcome_header": "Bonvenon al Twake!", + "scenes.app.workspaces.welcome_page.other_mail_title": "MalΔ‰efaj adresoj", + "components.calendar.repetition.everyday": "Ĉiutage", + "components.calendar.repetition.does_not_repeat": "Ne ripetas", + "components.calendar.repetition.weekly_on": "Ĉiusemajne je {{$1}}", + "components.calendar.repetition.monthly_on": "Ĉiumonate sur la {{$1}} {{$2}}", + "components.calendar.repetition.monthly_on_day": "Ĉiumonate tage {{$1}}", + "components.calendar.repetition.annually_on": "Ĉiujare sur {{$1}}", + "components.calendar.repetition.every_weekday": "Ĉiun labortagon (lun al vendredo)", + "components.calendar.repetition.custom": "Propra...", + "components.calendar.repetition.on": "On", + "components.calendar.repetition.after": "Post", + "scenes.app.channelsbar.currentuser.create_workspace_page": "Kreu laborspacon", + "scenes.app.channelsbar.currentuser.invited_status": "Vi estas gasto.", + "scenes.app.channelsbar.currentuser.title": "Kontagordoj", + "scenes.app.channelsbar.currentuser.workspace_parameters": "Agordoj de laborspaco", + "scenes.app.channelsbar.modify_channel_menu": "Redaktu kanalon", + "scenes.app.channelsbar.guest_management": "Gastadministrado", + "scenes.app.channelsbar.read_sign": "Marku kiel legita", + "scenes.app.channelsbar.unread_sign": "Marki kiel nelegita", + "scenes.app.channelsbar.channel_leaving": "Forlasu kanalon", + "scenes.app.channelsbar.channel_removing": "Forigi kanalon", + "scenes.app.popup.appsparameters.pages.app_privileges_information": "Difinu kion via aplikaΔ΅o povas redakti kaj legi.", + "scenes.app.popup.appsparameters.pages.app_privileges_label": "Aplikaj privilegioj", + "scenes.app.popup.appsparameters.pages.app_update": "Ĝisdatigu la apon {{$1}} (la programo estas uzata {{$2}} fojojn)", + "scenes.app.popup.appsparameters.pages.application_title": "Programo", + "scenes.app.popup.appsparameters.pages.automatique_option_information": "Se vi aktivigas 'AΕ­tomata', Δ‰i tiu aplikaΔ΅o aΕ­tomate estos aldonita al la sekvaj laborspacoj de Δ‰i tiu kompanio.", + "scenes.app.popup.appsparameters.pages.autorised_ip_adresses_label": "Permesitaj IP-adresoj", + "scenes.app.popup.appsparameters.pages.available_publication_alert": "La publikigo de via aplikaΔ΅o nuntempe atendas validigon de la teamo de Twake.", + "scenes.app.popup.appsparameters.pages.go_back": "Reen", + "scenes.app.popup.appsparameters.pages.instruction_message_twakecode": "Komencu skribante vian mesaĝon en formato JSON.", + "scenes.app.popup.appsparameters.pages.interne_availability_application": "Interna aplikaΔ΅o", + "scenes.app.popup.appsparameters.pages.json_configuration_information": "Iru al la dokumentado por generi vian agordon en formato JSON.", + "scenes.app.popup.appsparameters.pages.loading": "Ŝargante…", + "scenes.app.popup.appsparameters.pages.publication_description": "Determini la videblecon de via aplikaΔ΅o.", + "scenes.app.popup.userparameter.pages.private_message_content.hide": "Kaŝi enhavon pri privataj mesaĝoj", + "scenes.app.mainview.quick_search_placeholder": "Rapida serΔ‰o", + "scenes.app.popup.userparameter.personnal_workspaces_title": "Viaj laborspacoj", + "scenes.app.popup.workspaceparameter.pages.back_to_search_button": "Reiru al la serΔ‰o", + "scenes.app.popup.workspaceparameter.pages.displayed_preferencies_subtitle": "Montru preferojn", + "scenes.app.popup.workspaceparameter.pages.install_button": "Instali", + "scenes.apps.messages.message.reply_button": "Respondi", + "scenes.apps.messages.message.save_button": "Konservi", + "scenes.apps.messages.message.show_button": "Montru", + "scenes.apps.messages.message.show_responses_button": "Rigardu Δ‰iujn respondojn", + "scenes.apps.messages.message.types.first_channel_message_text": "Ĉi tiu estas la unua mesaĝo de la kanalo", + "scenes.login.verifymail.error_message": "Eraro okazis", + "scenes.login.verifymail.signin_button": "Ensaluti", + "scenes.login.verifymail.success": "Via retpoŝto estis sukcese kontrolita!", + "scenes.apps.tasks.board.place_holder": "Nomo de la estraro", + "scenes.apps.tasks.board.tasks.subtask": "Subtasko", + "scenes.apps.tasks.board.tasks.add_subtask": "Aldonu subtaskon", + "scenes.apps.tasks.board.tasks.use_deadline": "Uzu limdaton", + "components.input.copied": "Kopiita", + "components.drive.new_versions": "Aldonu novan version", + "components.drive.navigators.directory_not_found": "Dosierujo ne trovita.", + "components.upload.drop_files": "Forigu viajn dosierojn Δ‰i tie", + "components.channelworkspacelist.title": "Kanaloj", + "scenes.app.popup.adduserfromtwakeconsole.current_users_state": "{{$1}} retpoŝto(j) estos aldonitaj", + "components.newversion.new_version_component.row.part_1": "Vi funkcias malmodernan Twake-version", + "components.newversion.new_version_component.row.part_2": "ni sugestas vin reŝargi la apon kaj ĝui niajn novajn funkciojn!", + "components.newversion.new_version_component.link": "Klaku Δ‰i tie por reŝargi", + "components.newversion.new_version_modal.title": "Nova ĝisdatigo disponebla!", + "scenes.apps.drive.download_all_button": "Elŝutu Δ‰ion", + "scenes.apps.messages.message.activity_message.a_created_channel_tab": "{{$1}} aldonis novan {{$2}} langeton {{$3}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_tab": "{{$1}} forigis {{$2}} langeton {{$3}}", + "scenes.apps.messages.message.activity_message.a_created_channel_connector": "{{$1}} aldonis novan konektilon {{$2}}", + "components.account_verification_status_sentence": "Via konta stato estas: {{$1}}", + "scenes.client.channels_bar.modals.guest_management.input_placeholder": "SerΔ‰u gastojn aΕ­ pritraktatajn retpoŝtojn", + "general.user.deleted": "Forigita Konto", + "components.richtexteditor.toolbar.bold": "Grasa", + "components.richtexteditor.toolbar.underline": "Substreki", + "components.richtexteditor.toolbar.italic": "Kursiva", + "components.on_boarding.company_billing_banner.guest_or_member_text": "Estas problemo kun via firmaa abono. Bonvolu kontakti la posedanton aΕ­ administranton de la kompanio!", + "general.uploading": "Alŝutante", + "components.emoji_picker.categories.search_result": "SerΔ‰rezultoj", + "components.locked_features.locked_only_office_popup.subtitle": "En la senpaga versio, vi ne povas uzi nur oficejon.", + "components.locked_features.locked_drive_popup.title": "Vi Δ΅us atingis la veturlimon", + "general.resume": "Rekomenci", + "scenes.app.integrations_parameters.company_application_popup.tag": "Instalita", + "scenes.app.integrations_parameters.company_application_popup.btn": "Instali", + "scenes.app.integrations_parameters.company_application_popup.tab_btn_info": "Informoj", + "scenes.join.loading": "Ŝargante…", + "scenes.join.wrong_link_title": "Ĉi tiu ligilo ne plu disponeblas", + "scenes.join.wrong_link_description": "Demandu al la persono, kiu invitis vin aliĝi al Δ‰i tiu kompanio, pri nova ligilo aΕ­ kreu vian propran kompanion", + "general.close": "Fermi", + "general.save": "Konservi", + "general.cancel": "Nuligi", + "general.retry": "Reprovi", + "general.create": "Krei", + "general.edit": "Redakti", + "general.continue": "DaΕ­rigi", + "general.back": "Reen", + "general.confirm": "Konfirmi", + "general.delete": "Forviŝi", + "general.archive": "Enarkivigi", + "general.unarchive": "Elarkivigi", + "general.help": "Helpo", + "general.help.support": "Subteno", + "general.help.documentation": "Dokumentaro", + "general.send": "Sendi mesaĝon", + "general.update": "Ĝisdatigi", + "general.remove": "Forigi", + "general.add": "Aldoni", + "general.connexion_status.disconnected": "Vi estas eksterrete", + "general.connexion_status.connected": "Vi estas enreta", + "general.connexion_status.connecting": "Rekonektante…", + "application.load.longer": "Servilo daΕ­ras pli longe ol atendite por respondi, bonvolu atendi aΕ­ reŝargi la paĝon...", + "scenes.app.side_app.messages_thread_title": "{{$1}} β€’ Fadeno de mesaĝoj", + "scenes.app.workspaces.create_company.group_data": "Agordu vian novan grupon", + "scenes.app.workspaces.create_company.group_data.group_type": "Speco de grupo", + "scenes.app.workspaces.create_company.group_data.group_type.company": "Firmao aΕ­ kompania fako", + "scenes.app.workspaces.create_company.group_data.group_type.public_organization": "Publika organizaΔ΅o", + "scenes.app.workspaces.create_company.group_data.group_type.university_school": "Universitato aΕ­ lernejo", + "scenes.app.workspaces.create_company.group_data.group_type.society_club_charity": "Societo, klubo aΕ­ bonfarado", + "scenes.app.workspaces.create_company.group_data.group_type.other_group": "Alia", + "scenes.app.workspaces.create_company.group_data.group_size": "Grando de grupo", + "scenes.app.workspaces.create_company.group_data.group_size.less_3": "Malpli ol 4 uzantoj", + "scenes.app.workspaces.create_company.group_data.group_size.4_10": "4–10 uzantoj", + "scenes.app.workspaces.create_company.group_data.group_size.10_50": "11–49 uzantoj", + "scenes.app.workspaces.create_company.group_data.group_size.50_100": "50–99 uzantoj", + "scenes.app.workspaces.create_company.group_data.group_size.100_500": "100–499 uzantoj", + "scenes.app.workspaces.create_company.group_data.group_size.500_1000": "500–999 uzantoj", + "scenes.app.workspaces.create_company.group_data.group_size.1000_5000": "1000–4999 uzantoj", + "scenes.app.workspaces.create_company.group_data.group_size.5000_more": "Pli ol 5000 uzantoj", + "scenes.app.workspaces.create_company.group_data.group_main_activity": "Ĉefa agado", + "scenes.app.workspaces.create_company.group_data.group_main_activity.food": "Manĝo", + "scenes.app.workspaces.create_company.group_data.group_main_activity.bank": "Banko / asekuro", + "scenes.app.workspaces.create_company.group_data.group_main_activity.printing_paper": "Presado / papero", + "scenes.app.workspaces.create_company.group_data.group_main_activity.construction_building": "Konstruado / konstrumaterialoj", + "scenes.app.workspaces.create_company.group_data.group_main_activity.real_estate": "NemoveblaΔ΅oj", + "scenes.app.workspaces.create_company.group_data.group_main_activity.electronics_electricity_energy": "Elektroniko / elektro / energio", + "scenes.app.workspaces.create_company.group_data.group_main_activity.studies_and_advice": "Studoj kaj konsiloj", + "scenes.app.workspaces.create_company.group_data.group_main_activity.pharmaceutical_industry": "Farmacia industrio", + "scenes.app.workspaces.create_company.group_data.group_main_activity.it_telecom": "IT / Telekomunikado", + "scenes.app.workspaces.create_company.group_data.group_main_activity.research": "Esplorado", + "scenes.app.workspaces.create_company.group_data.group_main_activity.education": "Edukado", + "scenes.app.workspaces.create_company.group_data.group_main_activity.administration": "Administrado", + "scenes.app.workspaces.create_company.group_data.group_main_activity.other": "Alia", + "components.application.messages": "Mesaĝoj", + "components.drive_dropzone.uploading": "Alŝutante…", + "components.user_picker.modal_no_result": "Neniuj rezultoj trovitaj", + "components.users_picker.add_me": "Aldonu min", + "scenes.app.workspaces.create_company.invitations.title": "Agordu vian laborspacon.", + "scenes.app.header.disconnected": "Vi estas malkonektita", + "scenes.app.header.disconnected.reload": "Reŝargi", + "scenes.app.header.alt_notifications": "Sciigoj", + "scenes.apps.calendar.calendar.week_btn": "Semajno", + "scenes.apps.calendar.calendar.list_btn": "Listo", + "scenes.apps.calendar.event_edition.deadline_tag": "Limdato", + "scenes.apps.calendar.event_edition.checkbox_all_day": "Tuta tago", + "scenes.apps.calendar.event_edition.title_confidentiality": "Konfidenco", + "scenes.apps.calendar.event_view.article_until": "al", + "scenes.apps.calendar.calendar_modal.participants": "Partoprenantoj", + "scenes.apps.calendar.calendar_modal.placeholder": "Nomo", + "scenes.apps.calendar.left.calendars": "Kalendaroj", + "scenes.apps.drive.left.search": "SerΔ‰i", + "scenes.apps.drive.navigators.navigator_content.directory_name": "Dosierujo nomo", + "scenes.apps.drive.navigators.navigator_content.files": "Dosieroj", + "scenes.apps.drive.navigators.navigator_labels.title": "Etikedoj", + "scenes.apps.drive.navigators.new_file.untitled": "Sentitola", + "scenes.apps.drive.navigators.new_file.create_file.type": "Dosiertipo", + "scenes.apps.drive.navigators.new_file": "Nova dosiero", + "scenes.apps.drive.preview_bloc.operations_download": "Elŝuti", + "scenes.apps.drive.preview_bloc.error_file": "Dosiero ne trovita", + "scenes.apps.drive.right_preview.operations_restore": "RestaΕ­ri", + "scenes.apps.drive.right_preview.operations_delete": "Movu al rubujo", + "scenes.apps.drive.right_preview.public_link": "Publika ligilo", + "scenes.apps.messages.messages": "Mesaĝoj", + "scenes.apps.messages.chatbox.chat.delete_message": "Forigu Δ‰i tiun mesaĝon", + "scenes.apps.messages.chatbox.chat.delete_message_btn": "Forigi mesaĝon", + "scenes.apps.messages.left_bar.stream.remove_from_favorites": "Forigi el plej ŝatataj", + "scenes.apps.messages.left_bar.stream.notifications.never": "Nenio", + "scenes.apps.parameters.workspace_sections.workspace": "Laborejo", + "scenes.apps.parameters.workspace_sections.members": "Partoprenantoj", + "scenes.apps.parameters.group_sections.workspaces": "Laborejoj", + "scenes.apps.parameters.group_sections.apps": "Programoj", + "scenes.apps.account.title": "Kontaj parametroj", + "scenes.apps.account.account.menu_title": "Konto", + "scenes.apps.account.languages.menu_title": "Lingvo", + "scenes.apps.account.account.firstname": "AntaΕ­nomo", + "scenes.apps.account.account.password": "Pasvorto", + "scenes.apps.account.account.password_modal.old_password": "Aktuala Pasvorto", + "scenes.apps.account.account.password_modal.password": "Nova pasvorto", + "scenes.apps.account.account.password_modal.bad_old_password": "Malnova pasvorto ne estas ĝusta.", + "scenes.apps.account.account.password_modal.bad_password": "Viaj pasvortoj ne kongruas aΕ­ ili estas tro mallongaj. Bonvolu tajpi pasvorton kun almenaΕ­ 8 signoj.", + "scenes.apps.account.account.logout": "AdiaΕ­i", + "scenes.apps.account.languages.text": "Ŝanĝu Twake-lingvon.", + "scenes.apps.account.notifications.keywords_subtitle": "Ŝlosilvortoj", + "scenes.apps.account.notifications.keywords_placeholder": "dev, wifi, kodo, ...", + "scenes.apps.account.notifications.disturb_option_a": "Ne sendu al mi puŝajn sciigojn inter ", + "scenes.apps.account.notifications.devices_option_ever": "Ĉiam sendu al mi puŝajn sciigojn", + "scenes.apps.account.notifications.devices_option_inactive": "Sendu al mi puŝajn sciigojn kiam mi estas neaktiva sur labortablo", + "scenes.apps.account.notifications.devices_option_never": "Neniam sendu al mi puŝajn sciigojn", + "scenes.apps.account.notifications.privacy_subtitle": "Privateco", + "scenes.apps.account.notifications.mail_subtitle": "Retpoŝtaj sciigoj", + "scenes.apps.account.notifications.sound": "Sona sciigo", + "scenes.apps.parameters.group_sections.apps.badge_extension": "Etendo", + "scenes.apps.parameters.workspace_sections.members.members": "Uzantoj", + "scenes.apps.parameters.workspace_sections.members.pending": "Atendantaj retpoŝtoj", + "scenes.apps.parameters.workspace_sections.members.invite": "Invitu novan uzanton", + "scenes.apps.parameters.workspace_sections.members.invite_btn": "Aldonu uzanton", + "scenes.apps.tasks.boards": "Tabuloj", + "scenes.apps.tasks.connectors_menu": "Konektiloj…", + "scenes.apps.tasks.connectors_search_menu": "SerΔ‰u konektilojn...", + "scenes.apps.tasks.no_connectors_menu_text": "Vi ne havas konektilojn, kiuj povas konektiĝi al kalendaro.", + "scenes.apps.tasks.unconfigured_tab": "Ĉi tiu langeto ankoraΕ­ ne estas agordita.", + "scenes.apps.tasks.choose_board_button": "Elektu tabulon", + "scenes.apps.tasks.new_board.title": "Nova tabulo", + "scenes.apps.tasks.new_board.edit_title": "Redakti tabulon", + "scenes.apps.tasks.no_tasks": "Neniu tasko", + "scenes.apps.tasks.task_status.todo": "FarendaΔ΅o", + "scenes.apps.tasks.task_status.current": "Aktuala", + "scenes.apps.tasks.task_status.done": "Farita", + "scenes.apps.tasks.task.description": "Priskribo", + "scenes.apps.tasks.task.assignees": "Asignitoj", + "scenes.apps.tasks.task.edit.dates": "Datoj", + "scenes.apps.tasks.list_modal.modify_list": "Modifi liston", + "scenes.apps.tasks.list_modal.new_list": "Nova listo", + "scenes.apps.tasks.list_modal.remove": "Forigi liston kaj taskojn", + "scenes.apps.tasks.list_modal.predefined_participants": "AntaΕ­difinitaj partoprenantoj", + "scenes.apps.tasks.list_modal.archive_all_tasks": "Arkivu Δ‰iujn taskojn", + "scenes.apps.tasks.list_modal.remove_archived_tasks": "Forigi arkivitajn taskojn ({{$1}})", + "scenes.login.footer.go_to_twake": "Iru al twakeapp.com", + "scenes.login.footer.branding": "Vi estas sur {{$1}} ({{$2}}) privata Twake-servilo. ", + "scenes.login.create_account.title": "Kreu novan konton", + "scenes.login.create_account.email": "Retpoŝto", + "scenes.login.create_account.email_used": "Ĉi tiu retpoŝto jam estas uzata.", + "scenes.login.create_account.newsletter": "Ricevu informojn pri Twake", + "scenes.login.create_account.lastname": "Familia nomo", + "scenes.login.forgot_password.title": "Ĉu vi forgesis la pasvorton?", + "scenes.login.forgot_password.text": "Vi ricevos 9-ciferan kodon retpoŝte por kontroli vian identecon.", + "scenes.login.forgot_password.email_to_recover": "Retpoŝto por reakiri", + "scenes.login.forgot_password.mail_doesnt_exist": "Ĉi tiu retpoŝto ne ekzistas", + "scenes.login.forgot_password.text2": "Vi ricevos 9-ciferan kodon. Bonvolu enigi ĝin en la suban kampon por daΕ­rigi.", + "scenes.login.forgot_password.invalid_code": "Ĉi tiu kodo ne validas.", + "scenes.login.home.unable_to_connect": "Nevalida akreditaΔ΅ojn", + "scenes.login.home.password": "Pasvorto", + "scenes.login.home.login_btn": "Ensaluti", + "scenes.login.home.lost_password": "Ĉu vi forgesis la pasvorton?", + "scenes.login.home.create_account": "Krei konton", + "scenes.login.create_account.password": "Pasvorto", + "scenes.login.create_account.step_1_subtitle": "Ĝi ne povus esti pli simpla β€” ni nur bezonas iom da informoj.", + "scenes.login.create_account.step_2_subtitle_a": "Aldonu vian plenan nomon por ke aliaj uzantoj rekonu vin.", + "scenes.app.workspaces.create_company.company_name.placeholder": "Nomo de Firmo", + "scenes.app.workspaces.create_company.company_name.title_1": "Komenci,", + "scenes.app.workspaces.create_company.company_name.title_2": "indiku la nomon de via kompanio.", + "scenes.app.workspaces.create_company.default_workspace_name": "Ĉeflaborejo", + "scenes.app.workspaces.create_company.group_data.title": "Ni rapidos β€” ni bezonas nur kelkajn statistikajn informojn.", + "scenes.app.workspaces.create_company.importations.title_1": "Ĉu vi jam laboras kun ciferecaj iloj? Importu aΕ­ integru viajn ilojn nun!", + "scenes.app.workspaces.create_company.importations.title_2": "Ne zorgu, vi povas fari tion poste!", + "scenes.app.workspaces.create_company.invitations.title_2": "Aldonu uzantojn al via teamo.", + "scenes.app.workspaces.create_company.title": "Kreu mian kompanion", + "scenes.app.workspaces.welcome_page.add_secondary_emails": "Aldonu sekundaran retpoŝton", + "scenes.app.workspaces.welcome_page.added_to_company": "Vi estis invitita al ", + "scenes.app.workspaces.welcome_page.create_my_company": "Kreu mian kompanion", + "scenes.app.workspaces.welcome_page.lets_go": "Ni iru!", + "scenes.app.workspaces.welcome_page.may_be_invited_with_secondary_emails": "Ĉu vi estis invitita uzante alian retadreson?", + "scenes.app.workspaces.welcome_page.no_company_subtitle": "Ho, nu... Ŝajnas, ke neniu ankoraΕ­ invitis vin al firmao.", + "scenes.app.workspaces.welcome_page.no_workspace_subtitle": "Neniu ankoraΕ­ invitis vin al laborspaco.", + "scenes.app.workspaces.welcome_page.ready_to_work": "Vi estas preta labori nun.", + "scenes.app.workspaces.welcome_page.see_you_soon": "Ĝis baldaΕ­!", + "scenes.app.workspaces.welcome_page.add_secondary_emails_comment": "Vi povas ligi plurajn retadresojn al via konto; nur unu adreso estos uzata por sendi al vi sciigojn.", + "scenes.app.workspaces.welcome_page.main_mail_title": "Ĉefa adreso", + "scenes.app.workspaces.welcome_page.add_new_email": "Aldonu retmesaĝon", + "scenes.app.workspaces.welcome_page.code_verification": "Konfirmkodo", + "scenes.app.workspaces.welcome_page.new_email": "Aldonu duaran retpoŝton", + "scenes.app.workspaces.welcome_page.we_sent_you_mail": "Ni sendis al vi konfirmkodon per {{$1}}", + "scenes.app.workspaces.welcome_page.done": "Mi finis", + "scenes.login.forgot_password.finished": "Via pasvorto estis sukcese ĝisdatigita.", + "scenes.apps.account.account.description_main": "Via Δ‰efa adreso estas kie Twake sendas viajn sciigojn. Viaj malΔ‰efaj adresoj permesas vin aΕ­tomate inviti al la laborspacoj, kiuj uzas ilin.", + "scenes.apps.account.account.emails.description": "Administru viajn malsamajn retadresojn.", + "scenes.apps.account.account.make_main": "Agordu Δ‰efa", + "scenes.apps.account.account.password.description": "Ŝanĝu vian pasvorton.", + "scenes.apps.account.identity": "Identeco", + "scenes.apps.account.identity.description": "Ŝanĝu vian antaΕ­nomon, familian nomon kaj profilbildon videblan por aliaj uzantoj de Twake.", + "scenes.apps.account.preference": "Agordoj", + "general.open": "Malfermi", + "scenes.apps.account.thumbnail.max_weight": "Maksimuma grandeco 5 MB", + "scenes.apps.account.account.email_add_modal.confirm": "Konfirmu Δ‰i tiun retmesaĝon", + "app.name.twake_calendar": "Kalendaro", + "app.name.twake_drive": "Dokumentoj", + "app.name.twake_tasks": "Taskoj", + "components.calendar.repetition.repeat": "Ripetu Δ‰iun", + "components.calendar.repetition.ends": "Finiĝas", + "components.calendar.repetition.never": "Neniam", + "components.calendar.repetition.days": "tago(j)", + "components.calendar.repetition.weeks": "semajno(j)", + "components.calendar.repetition.months": "monato(j)", + "components.calendar.repetition.years": "jaro(j)", + "components.calendar.repetition.custom_recurrence": "Propra ripetiĝo", + "components.calendar.repetition.occurrence": "Okazo(j)", + "components.calendar.repetition.repeat_on": "Ripeti plu", + "scenes.app.channelsbar.currentuser.add_apps": "SerΔ‰u aplikojn", + "scenes.app.channelsbar.currentuser.change_my_status": "Ŝanĝu mian statuson", + "scenes.app.channelsbar.currentuser.collaborateurs": "Uzantoj", + "scenes.app.channelsbar.currentuser.workspace_info": "Vi estas en la laborspaco {{$1}} de la grupo {{$2}}", + "scenes.app.channelsbar.currentuser.logout": "AdiaΕ­i", + "scenes.app.channelsbar.currentuser.update": "Ĝisdatigi", + "scenes.app.channelsbar.currentuser.disable_notifications": "Malebligu", + "scenes.app.channelsbar.currentuser.disabling_notifications": "Malebligu dum 1 h", + "scenes.app.channelsbar.currentuser.disabling_notifications_until": "Malebligu ĝis 9 a.m. morgaΕ­", + "scenes.app.channelsbar.currentuser.reactivate_notifications": "Reaktivigi", + "scenes.app.channelsbar.currentuser.user_parameter": "Sciigaj agordoj", + "scenes.app.channelsbar.currentuser.company_messages_counter_header": "Numero de mesaĝoj", + "scenes.app.channelsbar.currentuser.company_messages_counter_info": "En la senpaga versio de Twake, vi ne povas aliri pli ol {{$1}} lastatempajn mesaĝojn.", + "scenes.app.channelsbar.currentuser.company_messages_counter_link": "Montru pliajn planojn", + "scenes.app.channelsbar.channelsuser.new_private_discussion": "Nova privata diskuto", + "scenes.app.channelsbar.channelsuser.no_private_message_invite_collaboraters": "Neniuj privataj mesaĝoj. Invitu uzantojn!", + "scenes.app.channelsbar.channelsuser.private_messages": "Rektaj mesaĝoj", + "scenes.app.channelsbar.channelsworkspace.channel_title": "KANALOJ", + "scenes.app.channelsbar.channelsworkspace.channel_title.favorite": "PREFERATOJ", + "scenes.app.channelsbar.channelsworkspace.create_channel": "Kreu kanalon", + "scenes.app.channelsbar.channelsworkspace.no_channel": "Vi ankoraΕ­ ne aliĝis al iu ajn kanalo", + "scenes.app.channelsbar.company_invitation_alert_subtitle": "Vi povas importi Δ‰i tiujn kanalojn en vian komercon por resti organizita klakante sur Δ‰i tiu kadro.", + "scenes.app.channelsbar.company_invitation_alert_title": "Vi estas invitita al la kompanio ", + "scenes.app.channelsbar.initial_instructions_tutorial": "Elektu antaΕ­nomon, nomon kaj profilbildon.", + "scenes.app.channelsbar.installation_desktop_tutorial": "Instalu la labortablan aplikaΔ΅on", + "scenes.app.channelsbar.invitation_collaboraors_tutorial": "Invitu uzantojn en vian laborspacon.", + "scenes.app.channelsbar.public_channel_label": "Publika", + "scenes.app.channelsbar.private_channel_label": "Privata", + "scenes.app.channelsbar.sending_message_instruction": "Sendu vian unuan mesaĝon en diskuto", + "scenes.app.channelsbar.tutorial_alert": "Ĉu vi neniam plu montri Δ‰i tiun kadron?", + "scenes.app.channelsbar.welcome": "Bonvenon al Twake", + "scenes.app.channelsbar.welcoming_message_subtitle": "Fariĝu Twake-profesiulo per nur kelkaj klakoj!", + "scenes.app.mainview.instruction_current_tab": "Komencu elektante kanalon maldekstre.", + "scenes.app.mainview.tabs.no_connected_connectors_for_channel": "Vi ne havas konektilon, kiu povas konektiĝi al kanalo.", + "scenes.app.mainview.tabs.rename": "Ŝanĝi nomon", + "scenes.app.mainview.tabs.searching_connectors": "SerΔ‰u konektilojn...", + "scenes.app.popup.adduser.adresses_message": "Bonvolu apartigi la adresojn per komo aΕ­ spaco. Memoru, ke Twake povas limigi la nombron da invitoj laΕ­ via abono.", + "scenes.app.popup.adduser.magiclinks.genrator_info": "Invita ligo al la laborspaco", + "scenes.app.popup.adduser.magiclinks.new_link_generated": "Nova ligilo generita", + "scenes.app.popup.adduser.magiclinks.copied_to_clipboard": "Sukcese kopiita al tondujo", + "scenes.app.popup.adduser.magiclinks.action_copy": "Kopii", + "scenes.app.popup.adduser.magiclinks.action_generate": "Generi", + "scenes.app.popup.appsparameters.pages._app_identity": "Identeco de la aplikaΔ΅o", + "scenes.app.popup.appsparameters.pages._appareance_message_twakcode": "Testu la aspekton de viaj Twacode-mesaĝoj", + "scenes.app.popup.appsparameters.pages.alert_published_app": "Via kandidatiĝo estas publikigita, vi ne povas redakti ĝin.", + "scenes.app.popup.appsparameters.pages.allowed_ip_adresses_method": "Uzu * en evoluo por permesi Δ‰iujn IP-adresojn.", + "scenes.app.popup.appsparameters.pages.amazing_app_name": "Mia mirinda apo", + "scenes.app.popup.appsparameters.pages.api_data_description": "Utilaj datumoj por la Twake API.", + "scenes.app.popup.appsparameters.pages.api_parameters_label": "API-agordoj", + "scenes.app.popup.appsparameters.pages.app_name_label": "Nomo de la aplikaΔ΅o", + "scenes.app.popup.appsparameters.pages.app_modification_right": "Ĉiuj administrantoj de Δ‰i tiu kompanio povos redakti Δ‰i tiun aplikaΔ΅on.", + "scenes.app.popup.appsparameters.pages.apps_title": "Viaj aplikoj kaj konektiloj", + "scenes.app.popup.appsparameters.pages.automatique_label": "AΕ­tomata", + "scenes.app.popup.appsparameters.pages.button_force": "Forto tra la kompanio", + "scenes.app.popup.appsparameters.pages.call_event_handlers": "OkazaΔ΅o de tipo '{{$1}}' kaj id '{{$2}}' kun pasivoj '{{$3}}'", + "scenes.app.popup.appsparameters.pages.company_label": "Kompanio posedanto", + "scenes.app.popup.appsparameters.pages.configuration_label": "Agordo", + "scenes.app.popup.appsparameters.pages.create_app_button": "Krei aplikaΔ΅on", + "scenes.app.popup.appsparameters.pages.create_my_app": "Kreu mian aplikaΔ΅on", + "scenes.app.popup.appsparameters.pages.current_informations_apps_connectors": "Vi ankoraΕ­ ne kreis apon. AntaΕ­ ol vi kreas aplikaΔ΅on aΕ­ konektilon, certigu, ke ĝi ne jam ekzistas en nia aplikaΔ΅a merkato.", + "scenes.app.popup.appsparameters.pages.danger_zone_description": "Forigi aplikaΔ΅on", + "scenes.app.popup.appsparameters.pages.danger_zone_label": "Danĝera zono", + "scenes.app.popup.appsparameters.pages.description_label": "Priskribo", + "scenes.app.popup.appsparameters.pages.developped_apps_subtitle": "Aplikoj evoluigitaj de la kompanio", + "scenes.app.popup.appsparameters.pages.dispalyed_parameters_description": "Permesas al vi difini kie via aplikaΔ΅o estos videbla.", + "scenes.app.popup.appsparameters.pages.displayed_parameters_label": "Montraj agordoj", + "scenes.app.popup.appsparameters.pages.error_check_needed": "Eraro okazis; kontrolu viajn informojn.", + "scenes.app.popup.appsparameters.pages.error_message": "Tiu Δ‰i nomo jam estas uzata de alia aplikaΔ΅o; bonvolu elekti alian.", + "scenes.app.popup.appsparameters.pages.error_user_code": "eraro", + "scenes.app.popup.appsparameters.pages.event_subtitle": "Eventoj", + "scenes.app.popup.appsparameters.pages.filter_information": "Ĉi tiu filtrilo limigas la uzon de via API-ŝlosilo nur al serviloj en via konektilo.", + "scenes.app.popup.appsparameters.pages.grp_section_name-error": "Ĉi tiu nomo jam estas uzata de alia aplikaΔ΅o. Bonvolu elekti alian.", + "scenes.app.popup.appsparameters.pages.grp_section_surname_label": "Simpligita nomo", + "scenes.app.popup.appsparameters.pages.installation": "Instali.", + "scenes.app.popup.appsparameters.pages.message_data_next_event": "Pasivaj datumoj, kiuj estos senditaj en la venonta Evento", + "scenes.app.popup.appsparameters.pages.modify_public_data": "Redaktu la publikajn datumojn de via aplikaΔ΅o.", + "scenes.app.popup.appsparameters.pages.new_app_title": "Nova aplikaΔ΅o", + "scenes.app.popup.appsparameters.pages.ok_user_code": "bone", + "scenes.app.popup.appsparameters.pages.optimal_format": "Optimuma formato: 48x48px.", + "scenes.app.popup.appsparameters.pages.parameters_form_small_text": "La neeldonita aplikaΔ΅o funkcios nur en via kompanio. Se vi volas disponigi ĝin al Δ‰iuj uzantoj de Twake, aktivigu Δ‰i tiun opcion.", + "scenes.app.popup.appsparameters.pages.public_availability_application": "Publika aplikado", + "scenes.app.popup.appsparameters.pages.public_login_label": "Publika identigilo", + "scenes.app.popup.appsparameters.pages.publication_label": "Publikigo", + "scenes.app.popup.appsparameters.pages.publish_app_label": "Eldoni aplikaΔ΅on", + "scenes.app.popup.appsparameters.pages.read_privileges_label": "Legu privilegiojn", + "scenes.app.popup.appsparameters.pages.remove_app": "Forigu la aplikaΔ΅on {{$1}} konstante.", + "scenes.app.popup.appsparameters.pages.remove_app_from_company": "Forigu de la tuta kompanio", + "scenes.app.popup.appsparameters.pages.remove_app_from_workspace": "Forigi el laborspaco", + "scenes.app.popup.appsparameters.pages.show_button": "Montri", + "scenes.app.popup.appsparameters.pages.status_tilte": "Stato", + "scenes.app.popup.appsparameters.pages.string_information": "Ĉi tiu Δ‰eno identigas vian aplikaΔ΅on kaj estos uzata en mesaĝaj komandoj.", + "scenes.app.popup.appsparameters.pages.title_tester": "Twakecode-testilo", + "scenes.app.popup.appsparameters.pages.url_reception_events_label": "Url de evento-ricevo", + "scenes.app.popup.appsparameters.pages.waiting_availability_application": "Atendante…", + "scenes.app.popup.appsparameters.pages.website_label": "Retejo", + "scenes.app.popup.appsparameters.pages.write_privileges_label": "Skribu privilegiojn", + "scenes.app.popup.appsparameters.pages.danger_zone_small_text": "Vi ne povas forigi Δ‰i tiun apon se ĝi estas publikigita.", + "scenes.app.popup.appsparameters.pages.error_app_simple_name_message": "La simpligita nomo de via aplikaΔ΅o jam estas uzata de alia aplikaΔ΅o. Bonvolu ŝanĝi ĝin.", + "scenes.app.popup.appsparameters.pages.error_app_update_message": "Okazis eraro dum la ĝisdatigo de la aplikaΔ΅o.", + "scenes.app.popup.appsparameters.pages.remove_app_button": "Forigi aplikaΔ΅on", + "scenes.app.popup.appsparameters.pages.update_button": "Ĝisdatigi", + "scenes.app.popup.createworkspacepage.add_subtitle": "Ĉu vi bezonas pli da spaco?", + "scenes.app.popup.createworkspacepage.create_new_workspace": "Kreu novan laborspacon", + "scenes.app.popup.createworkspacepage.placeholder_name": "Nomo de la laborspaco", + "scenes.app.popup.userparameter.pages.frequency_notif_configuration_description": "Agordu la oftecon de moveblaj sciigoj.", + "scenes.app.popup.userparameter.pages.frequency_notif_subtitle": "Ofteco de sciigoj", + "scenes.app.popup.userparameter.pages.keywords_notif_description": "Emfazu la sekvajn ŝlosilvortojn:", + "scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description": "Agordu la oftecon de retpoŝtaj sciigoj.", + "scenes.app.popup.userparameter.pages.private_message_content.show": "Montri enhavon pri privataj mesaĝoj", + "scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description": "Elektu periodon dum kiu vi ne ricevas sciigojn.", + "scenes.app.popup.userparameter.pages.no_night_disturbing_label": "Ne ĝenu nokte", + "scenes.app.popup.userparameter.pages.notif_content_label": "Enhavo de sciigoj", + "scenes.app.popup.workspaceparameter.admin_current_status": "Vi estas Administranto.", + "scenes.app.popup.workspaceparameter.admin_manager_current_status": "Vi estas administranto de laborspaco.", + "scenes.app.popup.workspaceparameter.manager_current_status": "Vi estas administranto de la kompanio.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace": "Forigi laborspacon", + "scenes.app.popup.workspaceparameter.pages.error_workspace_member": "Vi devas esti sola en la laborspaco por forigi ĝin. Forigu viajn kunlaborantojn kaj provu denove.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace_description": "Forigo de laborspaco ne povas esti malfarita. Ĉiuj mesaĝoj kaj dosieroj estos nereveneblaj.", + "scenes.app.popup.workspaceparameter.pages.enter": "Eniru ", + "scenes.app.popup.workspaceparameter.pages.access_apps": "Aliru viajn aplikaΔ΅ojn kaj konektilojn", + "scenes.app.popup.workspaceparameter.pages.moderator_status": "Moderiganto de laborspaco", + "scenes.app.popup.workspaceparameter.pages.alert_impossible_removing": "Vi ne povas forlasi la laborspacon, Δ‰ar vi estas la lasta administranto. Vi povas difini novan administranton aΕ­ forigi/arkivi Δ‰i tiun laborspacon.", + "scenes.app.popup.workspaceparameter.pages.all_apps_small_text": "Ĉiuj aplikoj", + "scenes.app.popup.workspaceparameter.pages.apps_company_small_text": "Aplikoj de via kompanio", + "scenes.app.popup.workspaceparameter.pages.apps_connectors_title": "Integriĝoj", + "scenes.app.popup.workspaceparameter.pages.apps_research_title": "SerΔ‰u aplikojn", + "scenes.app.popup.workspaceparameter.pages.apps_small_text": "Aplikoj de Δ‰i tiu laborspaco", + "scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button": "Invitu uzantojn", + "scenes.app.popup.workspaceparameter.pages.collaborateurs": "Uzantoj", + "scenes.app.popup.workspaceparameter.pages.company_developped_apps_subtitle": "Aplikoj evoluigitaj de la kompanio", + "scenes.app.popup.workspaceparameter.pages.company_identity_title": "Identeco de la kompanio", + "scenes.app.popup.workspaceparameter.pages.company_name_description": "Ŝanĝu la nomon de Δ‰i tiu kompanio", + "scenes.app.popup.workspaceparameter.pages.company_name_label": "Nomo de la kompanio", + "scenes.app.popup.workspaceparameter.pages.configuration_notif": "agordo", + "scenes.app.popup.workspaceparameter.pages.configure_button": "Agordoj ", + "scenes.app.popup.workspaceparameter.pages.description": "Priskribo", + "scenes.app.popup.workspaceparameter.pages.developped_apps_small_text": "Aplikoj evoluigitaj de la kompanio", + "scenes.app.popup.workspaceparameter.pages.installed_app_information": "Instalu la aplikaΔ΅on en Δ‰i tiu laborspaco.", + "scenes.app.popup.workspaceparameter.pages.installed_apps_information": "Aplikoj instalitaj en Δ‰i tiu laborspaco {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_message": "Aplikoj instalitaj en aliaj areoj de la kompanio {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_subtitle": "Instalitaj aplikaΔ΅oj", + "scenes.app.popup.workspaceparameter.pages.invitation_error": "Okazis eraro dum invitado de la sekvaj uzantoj: ", + "scenes.app.popup.workspaceparameter.pages.invited_guest_check_message": "Kontrolu, ke la uzantnomo aΕ­ retpoŝto uzata estas valida.", + "scenes.app.popup.workspaceparameter.pages.logo_modify_description": "Redaktu la bildon de Δ‰i tiu laborspaco", + "scenes.app.popup.workspaceparameter.pages.logo_subtitle": "Emblemo", + "scenes.app.popup.workspaceparameter.pages.name_description": "Ŝanĝu la nomon de Δ‰i tiu laborspaco", + "scenes.app.popup.workspaceparameter.pages.name_label": "Nomo de la laborspaco", + "scenes.app.popup.workspaceparameter.pages.no_access": "Neniu aliro.", + "scenes.app.popup.workspaceparameter.pages.no_app_information": "Vi ne havas aplikojn en Δ‰i tiu laborspaco", + "scenes.app.popup.workspaceparameter.pages.quit_workspace_menu": "Forlasu Δ‰i tiun laborspacon", + "scenes.app.popup.workspaceparameter.pages.read_access_subtitle": "Lega aliro", + "scenes.app.popup.workspaceparameter.pages.remove_from_company_text": "Forigu de la tuta kompanio", + "scenes.app.popup.workspaceparameter.pages.research_by": "SerΔ‰u aplikojn laΕ­ nomo kaj kategorioj", + "scenes.app.popup.workspaceparameter.pages.researching_apps_button": "SerΔ‰u aplikaΔ΅ojn...", + "scenes.app.popup.workspaceparameter.pages.show_button": "Montru", + "scenes.app.popup.workspaceparameter.pages.title": "Agordoj de laborspaco", + "scenes.app.popup.workspaceparameter.pages.webhooks_access_subtitle": "Aliro al rethokoj", + "scenes.app.popup.workspaceparameter.pages.weight_max_small_text": "Maksimuma grandeco 5 MB.", + "scenes.app.popup.workspaceparameter.pages.withdraw_button": "Forigu el Δ‰i tiu laborspaco", + "scenes.app.popup.workspaceparameter.pages.worspace_notif": "laborejo", + "scenes.app.popup.workspaceparameter.pages.write_access_subtitle": "Skriba aliro", + "scenes.app.popup.workspaceparameter.pages.your_apps_label": "Viaj aplikoj", + "scenes.app.popup.workspaceparameter.payments_subscriptions_title": "Pagoj kaj abonoj", + "scenes.app.workspacesbar.components.change_company_title": "Ŝanĝi firmaon", + "scenes.app.workspacesbar.components.create_company_menu": "Kreu kompanion", + "scenes.app.workspacesbar.components.grp_parameters": "{{$1}} agordoj", + "scenes.apps.calendar.add_calendar_menu": "Aldonu kalendaron", + "scenes.apps.calendar.connectors_menu": "Konektiloj…", + "scenes.apps.calendar.connectors_search_menu": "SerΔ‰u konektilojn...", + "scenes.apps.calendar.create_calendar_title": "Kreu kalendaron", + "scenes.apps.calendar.day_option": "Tago", + "scenes.apps.calendar.edit_calendar_title": "Redaktu la kalendaron", + "scenes.apps.calendar.export_title": "Elporti", + "scenes.apps.calendar.export_view_menu": "Eksportu la vidon...", + "scenes.apps.calendar.ics_download_menu": "Elŝutu ICS-dosieron", + "scenes.apps.calendar.ics_subscription_menu": "Akiru ICS-abonligon", + "scenes.apps.calendar.modals.advanced_options": "Altnivelaj opcioj", + "scenes.apps.calendar.modals.description_placeholder": "Priskribo", + "scenes.apps.calendar.modals.details_title": "Detaloj", + "scenes.apps.calendar.modals.event_adresse_placeholder": "Adreso", + "scenes.apps.calendar.modals.event_description_placeholder": "Priskribo", + "scenes.apps.calendar.modals.event_title_placeholder": "Titolo", + "scenes.apps.calendar.modals.modify_event_button": "Redaktu eventon", + "scenes.apps.calendar.modals.part.participants": "Partoprenantoj", + "scenes.apps.calendar.modals.participants_event": "Partoprenantoj", + "scenes.apps.calendar.modals.reminders": "Rememorigiloj", + "scenes.apps.calendar.modals.remove_button": "Forviŝi", + "scenes.apps.calendar.modals.remove_event_button": "Forigi eventon", + "scenes.apps.calendar.modals.remove_event_text": "Ĉu forigi la eventon?", + "scenes.apps.calendar.modals.title_placeholder": "Titolo", + "scenes.apps.calendar.modify_calendar_menu": "Redaktu la kalendaron", + "scenes.apps.calendar.month_option": "Monato", + "scenes.apps.calendar.my_calendar": "Mia kalendaro", + "scenes.apps.calendar.my_calendar_label": "Mia kalendaro", + "scenes.apps.calendar.week_option": "Semajno", + "scenes.apps.calendar.workspace": "Laborejo", + "scenes.apps.calendar.my_calendar_menu": "Mia kalendaro", + "scenes.apps.calendar.no_calendar_text": "Vi ne agordis iujn ajn kalendarojn por Δ‰i tiu laborspaco.", + "scenes.apps.calendar.no_connectors_menu_text": "Vi ne havas konektilojn, kiuj povas konektiĝi al kalendaro.", + "scenes.apps.calendar.remove_calendar_confirmation": "Ĉu forigi la kalendaron kaj ĝiajn eventojn konstante?", + "scenes.apps.calendar.today_menu": "HodiaΕ­", + "scenes.apps.calendar.workspace_label": "Ĉi tiu laborspaco", + "scenes.apps.calendar.workspace_menu": "Laborejo", + "scenes.apps.drive.add_button": "Aldoni", + "scenes.apps.drive.message_added_file": "{{$1}} sendis {{$2}}.", + "scenes.apps.drive.message_added_mutiple_files": "{{$1}} sendis plurajn dosierojn.", + "scenes.apps.drive.message_added_file_no_name": "{{$1}} sendis dosieron.", + "scenes.apps.drive.choose_folder_button": "Elektu dosierujon", + "scenes.apps.drive.choose_file_button": "Elektu dosieron", + "scenes.apps.drive.create_folder_button": "Krei", + "scenes.apps.drive.go_trash_menu": "Iru al rubujo", + "scenes.apps.drive.import_from_computer_menu": "Alŝutu de komputilo", + "scenes.apps.drive.move_text": "Movi", + "scenes.apps.drive.new_file_menu": "Nova dosiero", + "scenes.apps.drive.download_button": "Elŝuti", + "scenes.apps.drive.open_link": "Malfermu ligilon en nova fenestro", + "scenes.apps.drive.files_subtitle": "Dosieroj", + "scenes.apps.drive.folder_subtitle": "Dosierujoj", + "scenes.apps.drive.go_out_trash_menu": "Lasu rubon", + "scenes.apps.drive.new_file_title": "Nova dosiero", + "scenes.apps.drive.new_external_storage": "Nova ekstera stokado", + "scenes.apps.drive.no_file_alert": "Vi ne havas aplikaΔ΅ojn, kiuj permesas krei dosieron.", + "scenes.apps.drive.no_storage_app_alert": "Vi ne havas aplikojn, kiuj permesas vin aldoni eksteran stokadon.", + "scenes.apps.drive.new_folder_title": "Nova dosierujo", + "scenes.apps.drive.remove_definitely_menu": "Forigu konstante", + "scenes.apps.drive.restore_menu": "RestaΕ­ri", + "scenes.apps.drive.throw_menu": "Sendu al la rubujo", + "scenes.apps.drive.trash_empty_menu": "Malplenigu la rubon", + "scenes.apps.drive.unconfigured_tab": "Ĉi tiu langeto ankoraΕ­ ne estas agordita.", + "scenes.apps.drive.viewer.edit_with_button": "Redaktu per {{$1}}", + "scenes.apps.drive.viewer.loading_preview_message": "Ŝargante…", + "scenes.apps.drive.viewer.no_preview_message": "Ne povas vidi tian dosieron.", + "scenes.apps.drive.viewer.open_with_button": "Malfermu kun...", + "scenes.apps.messages.input.placeholder": "Skribu mesaĝon. Uzu @ por citi uzanton.", + "scenes.apps.messages.input.edited": "Redaktita", + "scenes.apps.messages.just_you": "Videbla nur por vi", + "scenes.apps.messages.message.new_messages_bar": "Novaj mesaĝoj", + "scenes.apps.messages.message.cancel_button": "Nuligi", + "scenes.apps.messages.message.modify_button": "Modifi", + "scenes.apps.messages.message.pin_button": "Pin mesaĝo", + "scenes.apps.messages.message.unpin_button": "Malfiksi mesaĝon", + "scenes.apps.messages.message.copy_link": "Kopiu ligilon al mesaĝo", + "scenes.apps.messages.message.pinned": "Alpinglita", + "scenes.apps.messages.message.remove_button": "Forviŝi", + "scenes.apps.messages.message.types.first_message_text": "Ĉi tiu estas la unua mesaĝo", + "scenes.apps.messages.message.types.no_message_in_thread": "Neniu ankoraΕ­ respondis.", + "scenes.apps.messages.messageslist.get_writing_user": "skribas...", + "scenes.apps.messages.messageslist.get_writing_users": "skribas...", + "scenes.apps.messages.messageslist.go_last_message_button": "Iru al la lasta mesaĝo", + "scenes.apps.messages.messageslist.go_last_message_button.new_messages": "Novaj mesaĝoj", + "scenes.error_on_twake": "\"Houston ni havas problemon\"", + "scenes.help_us": "Tamen, se vi ŝatus helpi nin ripari Δ‰i tiun eraron, sendu al ni mesaĝon sube: ", + "scenes.login.verifymail.alert": "Ni kontrolas vian retpoŝton!", + "scenes.login.verifymail.verification_waiting": "Atendante konfirmon...", + "scenes.no_panic": "Ne paniku! Nur reŝargi Δ‰i tiun paĝon por ripari Twake.", + "services.apps.calendar.deadline_icon": "Limdato", + "services.apps.calendar.event_icon": "Evento", + "services.apps.calendar.move_icon": "Movi", + "services.apps.calendar.reminder_icon": "Rememorigilo", + "services.apps.messages.no_app": "Ĉi tiu aplikaΔ΅o ne ekzistas.", + "services.apps.messages.no_command_possible": "Ni ne povas ekzekuti la komandon '{{$1}}' Δ‰ar '{{$2}}' ne ekzistas aΕ­ ne permesas krei komandojn.", + "scenes.apps.drive.top_menu_more": "Pli", + "scenes.apps.drive.top_menu_no_items": "{{$1}} eroj", + "scenes.apps.messages.new_thread": "Komencu novan diskuton", + "scenes.apps.messages.input.send_message": "Sendi mesaĝon", + "services.user.notification_parameters_update_alert": "La sciigaj agordoj estis ĝisdatigitaj.", + "services.user.update_password_alert": "Via pasvorto estas ĝisdatigita.", + "'": "'", + "\"": "\"", + "login.create_account": "Krei konton", + "login.login_error": "Eraro dum ensaluto", + "scenes.app.workspaces.components.skip": "Saltu", + "scenes.apps.calendar.unconfigured_tab": "Ĉi tiu langeto ankoraΕ­ ne estas agordita.", + "scenes.apps.drive.trash": "Rubujo", + "scenes.apps.messages.input.emoji": "Mienvinjetoj", + "scenes.apps.messages.input.hide_formatting": "Kaŝi formatadon", + "scenes.apps.messages.input.show_formatting": "Montru formatadon", + "scenes.tell_us": "Bonvolu diri al ni, kion vi faris Δ‰e:", + "scenes.apps.drive.viewer.download_desktop": "Elŝutu Twake Desktop por antaΕ­rigardi en la programo", + "scenes.apps.tasks.my_tasks": "Miaj taskoj", + "scenes.apps.tasks.board.tasks.use_starttime": "Uzu komencan tempon", + "scenes.apps.tasks.board.tasks.in_list": "En listo", + "scenes.apps.tasks.board.starts": "Komencas la", + "scenes.apps.tasks.board.ends": "Farenda por la", + "scenes.apps.tasks.board.list_name": "Listo nomo", + "scenes.app.popup.sync_calendar": "Sinkronigu viajn kalendarojn.", + "scenes.apps.parameters.workspace_sections.workspace.logo_company": "Logo de la firmao", + "scenes.app.popup.workspaceparameter.pages.logo_company_modify_description": "Redakti firmaobildon ", + "scenes.apps.account.account.save": "Konservu konton", + "scenes.apps.account.message_temporary": "Provizora konto funkcias kiel normala Twake-konto, sed vi kreas la pasvorton kaj vi povos rekomencigi ĝin se necese.", + "scenes.apps.account.message_user_signin": "Via uzanto povas ensaluti iam ajn uzante Δ‰i tiun saman retpoŝton kaj ŝanĝi la provizoran konton al normala konto.", + "scenes.app.mainview.link_expired": "Ĉi tiu publika ligo estas nevalida aΕ­ eksvalidiĝis.", + "scenes.app.mainview.create_account": "Kreu vian laborspacon senpage ", + "scenes.app.popup.workspaceparameter.pages.cancel_invitation": "Nuligi la inviton", + "scenes.apps.account.account.fullname": "Plena nomo", + "login.email_login": "Retpoŝto / Ensalutu", + "scenes.apps.account.account.password_for_user": "Pasvorto por via uzanto", + "scenes.apps.account.account.send_info": "Sendu Δ‰i tiujn akreditaΔ΅ojn al via uzanto.", + "scenes.apps.calendar.modals.reminder_add": "Aldonu memorigilon", + "scenes.apps.parameters.workspace_sections.members.invite_all": "Invitu Δ‰iujn", + "scenes.app.taskpicker.select": "Elekti", + "components.listmanager.filter": "Filtri", + "scenes.apps.tasks.no_connector": "Neniu konektilo", + "components.attachmentpicker.add_attachment": "Aldonu aldonaΔ΅ojn", + "components.drive.right_preview.suppress_link": "Subpremi la ligilon", + "components.drive.right_preview.create_link": "Kreu alirligilon", + "components.drive.moove_here": "Movu Δ‰i tien", + "components.drive.modify_uslist": "Modifi uzantliston", + "components.tagpicker.tag_name": "Etikedo nomo", + "components.workspace.list_manager.no_workspace": "Neniu laborspaco", + "components.workspace.list_manager.add": "Aldonu laborspacojn", + "components.workspace.list_manager.current_space": "Nuna laborspaco", + "components.workspace.list_manager.current_company": "Nuna firmao", + "components.workspace.list_manager.all": "Ĉiuj", + "components.workspace.calendar.invalid": "Nevalida", + "components.searchpopup.enter_text": "Enigu iun tekston por serΔ‰i Twake.", + "components.searchpopup.loading": "Ŝargante pliajn rezultojn", + "components.searchpopup.filter_ws": "Filtri la laborspacojn", + "components.searchpopup.tags": "Etikedoj", + "components.searchpopup.size": "Grando", + "components.searchpopup.creation": "Kreado", + "components.searchpopup.update_search": "Ĝisdatigu serΔ‰on", + "components.searchpopup.last_modif": "Lasta modifo", + "components.searchpopup.sender": "Sendinto", + "components.searchpopup.mentions": "Mencioj", + "scenes.apps.board.archived_tasks": "Arkivitaj taskoj ({{$1}})", + "scenes.apps.board.active_tasks": "Aktivaj taskoj", + "components.searchpopup.only_pinned": "Nur alpinglitaj mesaĝoj", + "components.alert.confirm": "Konfirmu vian agon", + "components.alert.confirm_click": "Konfirmu vian agon alklakante OK.", + "components.searchpopup.tasks": "Taskoj", + "scenes.app.mainview.advanced_search_placeholder": "Altnivela serΔ‰o", + "components.searchpopup.hide_filters": "kaŝi filtrilojn", + "components.searchpopup.show_filters": "montri filtrilojn", + "components.searchpopup.load_more": "Ŝarĝu pli da rezultoj", + "general.more": "Pli", + "scenes.apps.board.kanban": "Kanban", + "scenes.apps.board.display_as": "Montru kiel", + "scenes.apps.board.new_task": "+ Nova tasko", + "scenes.apps.board.all_boards": "Ĉiuj Estraroj", + "components.reminder.by_email": "Retpoŝto", + "components.userlistmanager.no_users": "Neniuj uzantoj.", + "scenes.apps.drive.used": "uzata en Δ‰i tiu dosierujo", + "components.reminder.notification": "Sciigo", + "components.reminder.minutes_bef": "minutojn antaΕ­e", + "components.reminder.hours_bef": "horojn antaΕ­e", + "components.reminder.days_bef": "tagojn antaΕ­e", + "components.reminder.weeks_bef": "semajnoj antaΕ­e", + "scenes.apps.calendar.reminders": "memorigilo(j)", + "scenes.apps.calendar.video_link": "Klaku por malfermi ligilon", + "scenes.app.mainview.discussion": "Diskuto", + "components.tagpicker.notag": "Neniu etikedo", + "scenes.apps.tasks.modals.attachments": "AldonaΔ΅oj", + "components.calendar.calendarselector.from": "De", + "scenes.apps.drive.move_text2": "Movi", + "components.attachmentpicker.from_computer": "De via aparato", + "components.attachmentpicker.from_twake": "De Twake Dokumentoj", + "components.attachmentpicker.file": "Dosiero", + "components.attachmentpicker.remove_attach": "Forigi aldonaΔ΅on", + "scenes.apps.drive.remove_attachs": "Forigi aldonaΔ΅ojn", + "components.drive.elements.see": "Vidu", + "components.drive.elements.current_name": "Nuna nomo: ", + "scenes.apps.drive.right_preview.public": "Publika aliro", + "components.drive.elements.configurate_mod": "Agordi la modon...", + "components.drive.elements.manage_version": "Administri versiojn", + "scenes.app.popup.createcompany.try_again": "Bonvolu reprovi.", + "scenes.app.popup.workspace.edit_temp": "Redaktu provizoran konton", + "scenes.app.popup.workspace.create_temp": "Krei provizoran konton", + "scenes.apps.tasks.active_tasks": "aktivaj taskoj", + "scenes.apps.drive.right_preview.versions": "Versioj", + "scenes.app.popup.appsparameters.pages.apps_connectors_small_text": "Administru viajn aplikojn kaj konektilojn.", + "scenes.app.popup.appsparameters.pages.icon": "Piktogramo", + "scenes.app.popup.appsparameters.pages.title_informations": "Bazaj informoj", + "scenes.app.popup.appsparameters.pages.subtitle_informations": "Informoj rilataj al aplika administrado", + "scenes.app.popup.appsparameters.pages.smalltext_user_id": "Nuna uzantidentigilo", + "scenes.app.popup.appsparameters.pages.smalltext_workspace_id": "Nuna laborspaca id", + "scenes.client.channelbar.channelmemberslist.loader": "Ŝarĝu pli", + "scenes.client.channelbar.channelmemberslist.autocomplete": "SerΔ‰u uzantojn", + "scenes.client.channelbar.channelmemberslist.menu.option_2": "Forigi el kanalo", + "components.leftbar.channel.workspaceschannels.menu.option_1": "Kreu kanalon", + "scenes.app.popup.appsparameters.pages.smalltext_group_id": "Nuna grupid", + "scenes.app.mainview.channel_description": "Priskribu la kanalon", + "scenes.client.channelbar.channeltemplateeditor.checkbox": "AΕ­tomate invitu Δ‰iujn uzantojn de laborspaco al Δ‰i tiu kanalo", + "scenes.client.channelbar.channelmemberslist.title": "Uzantoj en {{$1}}", + "components.leftbar.channel.workspaceschannels.menu.option_2": "Aliĝu al kanalo", + "scenes.client.channelbar.workspacechannellist.autocomplete": "SerΔ‰u kanalon, uzanton aΕ­ rektajn mesaĝojn", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_creation": "Kreu novan langeton", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_edition": "Alinomigi {{$1}}", + "components.connectorslistmanager.add_connectors": "Aldonu konektilojn", + "components.notifications.hidden_notifications_button.children": "Novaj mesaĝoj", + "scenes.client.mainview.tabs.tabstemplateeditor.select_placeholder": "Programo", + "scenes.client.channelbar.channelmemberslist.no_members": "Ne estas uzanto en Δ‰i tiu kanalo, vi povas inviti ilin alklakante Aldoni uzantojn.", + "scenes.app.channelsbar.hide_discussion_leaving.menu": "Kaŝi diskuton", + "components.inputs.input_with_select.input.placeholder": "Kanala nomo", + "components.inputs.input_with_select.select.placeholder": "Nomo de sekcio", + "components.inputs.input_with_select.select.no_sections": "Vi povas grupigi viajn kanalojn Δ‰i tie", + "components.inputs.input_with_select.button.tooltip": "Agordu kanalan sekcion", + "scenes.apps.messages.message.activity_message.a_added_b_to_the_channel": "{{$1}} aldonis {{$2}} al la kanalo", + "scenes.apps.messages.message.activity_message.a_removed_b_from_the_channel": "{{$1}} forigis {{$2}} de la kanalo", + "scenes.apps.messages.message.activity_message.a_updated_channel_description": "{{$1}} ŝanĝis la priskribon", + "scenes.apps.messages.message.activity_message.a_updated_channel_name": "{{$1}} renomis la kanalon al {{$2}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_connector": "{{$1}} forigis konektilon {{$2}}", + "components.alert.leave_private_channel.description": "Vi ne povos denove aliĝi al Δ‰i tiu privata kanalo krom se iu invitas vin.", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.tag": "Vi ne estas membro", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.loader": "Ŝarĝu pli", + "general.re_send": "Resendi", + "general.verify": "Kontrolu", + "scenes.client.channelbar.channelmemberslist.tag": "Vi", + "components.alert.leave_private_channel.title": "Ĉu vi certas, ke vi volas forlasi la kanalon?", + "components.unverified_account.typography_text_danger": "Bonvolu kontroli vian konton ene de {{$1}} tagoj. Se ne, via konto estos blokita post 7 tagoj kaj konstante forigita post 30 tagoj. Vi povas kontroli vian konton per la konfirma retpoŝto.", + "components.unverified_account.verification_details": "Ni sendis konfirman retpoŝton al", + "components.account_verication_status_unverified": "Nekontrolita", + "components.account_verication_status_blocked": "Ŝlosita", + "components.unverified_account.re_send_email": "Ĉu ne ricevis la retmesaĝon?", + "components.blocked_account.trial_period_over": "Via provperiodo finiĝis. Por malŝlosi vian konton kaj akiri aliron al Δ‰iuj funkcioj, bonvolu kontroli vian konton per retpoŝta konfirmo", + "components.add_mails_workspace.button": "Komencu uzi Twake", + "components.add_mails_workspace.title_1": "Aldonu kelkajn uzantojn", + "components.add_mails_workspace.title_2": "Twake estas teama kunlabora ilo, do invitu kelkajn uzantojn testi laborspacon, kiun ni kreis por vi.", + "components.add_mails_workspace.text_area_placeholder": "Enigu retpoŝtojn de viaj uzantoj*", + "components.verify_mail.title_1": "Gratulon", + "components.verify_mail.title_2": "Vi estas oficiala Twake-uzanto nun!", + "components.verify_mail.button": "Aldonu uzanton", + "components.verify_mail.text": "AntaΕ­ Δ‰io, vi devas kontroli vian retadreson. Ni sendis konfirman ligon al", + "components.verify_mail.paragraph": "Vi povas fari ĝin poste, se vi volas, sed nekontrolitaj kontoj havas aliron al nur limigita versio de Twake", + "services.console_services.toaster.add_emails_error": "Eraro dum aldono de retpoŝto(j)", + "services.console_services.toaster.add_email_error_message": "Eraro dum aldono de {{$1}}", + "services.console_services.toaster.success_verify_email": "Konfirma ligilo estis sendita al via retpoŝta konto", + "scenes.app.popup.workspaceparameter.edit_from_console": "Vidu en Konzolo", + "services.console_services.toaster.success_invite_emails": "Sukcese aldonis {{$1}} uzanto(j)", + "scenes.client.channels_bar.modals.guest_management.title": "Administri gastojn en {{$1}}", + "scenes.client.channels_bar.modals.guest_management.tips": "Komencu aldoni aΕ­ serΔ‰i retpoŝton per la enigo supre", + "scenes.client.channels_bar.modals.parts.channel_member_row.label.pending_email": "Poŝto sendita", + "general.user.role.company.admin": "Administranto de la kompanio", + "general.user.role.company.member": "Membro", + "general.user.role.company.guest": "Gasto", + "components.richtexteditor.toolbar.strikethrough": "Trastreki", + "components.richtexteditor.toolbar.ordered-list": "Ordigita listo", + "components.richtexteditor.toolbar.blockquote": "BlokcitaΔ΅o", + "components.richtexteditor.toolbar.code": "Kodo", + "components.richtexteditor.toolbar.unordered-list": "Kuglolisto", + "components.richtexteditor.toolbar.code-block": "Kodbloko", + "components.locked_features.locked_history_banner.title": "Vi Δ΅us atingis la mesaĝlimon", + "components.locked_features.locked_history_banner.description": "Via kompanio havas multajn mesaĝojn! Ĝisdatigu nun por aliri vian tutan mesaĝhistorion.", + "components.locked_features.locked_history_banner.button": "Lernu pli", + "components.locked_features.locked_guests_popup.title": "Gastoj funkcio estas ŝlosita", + "components.locked_features.locked_guests_popup.subtitle": "Ĉi tiu funkcio ne disponeblas en la senpaga versio de Twake", + "components.locked_features.locked_guests_popup.description": "Hus!! Ŝajnas, ke vi volas inviti eksterajn uzantojn al via laborejo. Vi eble volas konsideri ĝisdatigi vian planon se vi volas kunlabori kun gastoj kaj eksteraj partneroj. Esploru niajn prezajn elektojn kaj elektu la plej bonan eblon por viaj teamaj kunlaboraj bezonoj.", + "components.locked_features.locked_guests_popup.learn_more_button": "Lernu pli", + "components.locked_features.locked_guests_popup.skip_for_now_button": "Saltu por Nun", + "components.locked_features.locked_guests_popup.or": "AΕ­", + "components.on_boarding.company_billing_banner.admin_or_owner_text": "Estas problemo kun via firmaa abono. Bonvolu rigardi vian", + "components.on_boarding.company_billing_banner.link": "abonplano de kompanio", + "components.on_boarding.popups.blocked_company.title": "Via firmao estas ŝlosita pro pagoproblemo", + "components.on_boarding.popups.blocked_company.description": "Via abono al Twake eksvalidiĝis. Bonvolu kontakti la posedanton aΕ­ administranton de via firmao por renovigi ĝin kaj povi komuniki kun via teamo denove!", + "components.on_boarding.popups.blocked_company.learn_more_text": "Ĉu vi volas lerni pli pri firmaa abonplano?", + "components.on_boarding.popups.blocked_company.company_subscription_plan_button": "Klaku Δ‰i tie", + "components.on_boarding.popups.blocked_company.or": "AΕ­", + "components.on_boarding.popups.blocked_company.company_selector": "Ŝanĝu al alia kompanio", + "scenes.apps.tasks.select_user_button": "Rigardu taskojn por alia uzanto", + "scenes.apps.tasks.select_user": "SerΔ‰u uzanton", + "scenes.apps.messages.input.attach_file.from_computer": "De komputilo", + "scenes.app.popup.workspaceparameter.pages.table_title": "Nomo", + "scenes.client.main_view.main_header.search_input": "SerΔ‰i", + "scenes.apps.drive.new_link_title": "Nova ligilo", + "scenes.apps.drive.default_link_name": "Sentitola", + "components.emoji_picker.input_search_placeholder": "SerΔ‰i", + "services.apps.messages.message_editor_service.upload_error_toaster": "{{$1}} - Vi ne povas aldoni pli ol {{$2}} dosierojn en mesaĝo", + "scenes.apps.messages.message.parts.deleted_content.text.current_user": "Vi forigis Δ‰i tiun mesaĝon", + "scenes.apps.messages.message.parts.deleted_content.text": "{{$1}} forigis sian mesaĝon", + "components.member.user_parts.and_more_user_text": " kaj {{$1}} pli da uzantoj", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_link": "Kreu privatan kanalon", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_text": " anstataΕ­e", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_input_placeholder": "Vi ne povas aldoni pli ol 10 uzantojn", + "components.upload.drop_files.toaster.error": "Vi ne povas alŝuti pli ol {{$1}} dosierojn", + "components.emoji_picker.categories.frequently_used": "Ofte Uzata", + "components.emoji_picker.categories.smileys_and_people": "Ridetonoj & Homoj", + "components.emoji_picker.categories.animals_and_nature": "Bestoj kaj Naturo", + "components.emoji_picker.categories.food_and_drink": "ManĝaΔ΅o & TrinkaΔ΅o", + "components.emoji_picker.categories.activity": "Aktivecoj", + "components.emoji_picker.categories.travel_and_places": "Vojaĝoj & Lokoj", + "components.emoji_picker.categories.objects": "Objektoj", + "components.emoji_picker.categories.symbols": "Simboloj", + "components.emoji_picker.categories.flags": "Flagoj", + "components.emoji_picker.categories.not_found": "Neniu Emoji Trovita", + "scenes.app.popup.workspaceparameter.pages.workspace_partner_tabs.members.table.tags": "Rolo", + "general.email": "Retpoŝto", + "components.locked_features.locked_workspace_popup.title": "Vi ne povas krei pliajn laborspacojn", + "components.locked_features.locked_workspace_popup.subtitle": "En la senpaga versio, vi povas havi nur unu laborspacon en via kompanio.", + "components.locked_features.locked_workspace_popup.text": "Hus!! Ĉu vi volas krei novan laborspacon en via kompanio? Vi eble volas konsideri ĝisdatigi vian planon. Esploru niajn prezajn elektojn kaj elektu la plej bonan elekton por viaj teamaj kunlaboraj bezonoj.", + "components.locked_features.locked_only_office_popup.title": "Vi ne povas redakti Δ‰i tiun dosieron", + "components.locked_features.locked_only_office_popup.text": "Hus!! Ŝajnas, ke vi volas redakti la dosieron de Twake. Vi eble volas konsideri ĝisdatigi vian planon se vi volas kunlabori Δ‰irkaΕ­ oficejaj dosieroj. Esploru niajn prezajn elektojn kaj elektu la plej bonan eblon por viaj teamaj kunlaboraj bezonoj.", + "components.locked_features.locked_drive_popup.subtitle": "En la senpaga versio, vi povas stoki nur 6GB.", + "general.pause": "PaΕ­zo", + "scenes.app.integrations_parameters.title": "Integriĝoj", + "scenes.app.integrations_parameters.applications_table.name": "Nomo", + "scenes.app.integrations_parameters.applications_table.title": "Aliaj integriĝoj", + "scenes.app.integrations_parameters.applications_table.search_placeholder": "SerΔ‰u aplikaΔ΅on", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.description_item": "Priskribo", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.website_item": "Retejo", + "scenes.app.integrations_parameters.company_applications_table.more_menu.show_application": "Montru", + "scenes.app.integrations_parameters.company_applications_table.more_menu.remove_application": "Forigi el la kompanio", + "scenes.app.integrations_parameters.company_applications_table.name": "Nomo", + "scenes.app.integrations_parameters.company_applications_table.title": "Instalita en via kompanio", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.created_item": "Kreodato", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.version_item": "Versio", + "app.state.recoil.hooks.use_current_company_applications.toaster_delete": "Sukcese forigita {{$1}} de via kompanio", + "app.state.recoil.hooks.use_current_company_applications.toaster_add": "Sukcese aldonis {{$1}} en via kompanio", + "scenes.apps.messages.input.replied_to": "respondis al ", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.label": "DefaΕ­lta laborspaco", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.description": "AΕ­tomate invitu Δ‰iujn novajn firmaajn uzantojn al Δ‰i tiu laborspaco", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.title": "Vi estas forigonta {{$1}}", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.alert_total_members": "Vi ankoraΕ­ havas {{$1}} membrojn en {{$2}}. Vi devus forigi Δ‰iujn membrojn por povi forigi Δ‰i tiun laborspacon.", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.checkbox": "Mi komprenas, ke Δ‰iuj mesaĝoj kaj dosieroj de mia laborspaco estos forigitaj.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.max_size": "Maksimuma logograndeco estas 5mb", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.bad_format": "Malbona formato, nur png gif kaj jpg estas permesitaj", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.unknown": "Nekonata eraro", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.prefix": "Eraro", + "scenes.join.create_the_company_button": "Kreu la kompanion", + "scenes.join.join_workspace_from_company": "Aliĝu al {{$1}} de {{$2}}!", + "scenes.join.twake_description": "Twake estas malfermfonta cifereca laborejo konstruita por plibonigi vian teaman produktivecon", + "scenes.join.login_first_button": "Ensalutu aΕ­ kreu konton unue", + "scenes.join.join_the_team_button": "Aliĝu al la teamo", + "scenes.app.channelsbar.currentuser.reset": "Restarigi", + "components.rich_text_editor.plugins.suggestions.default_message.no_command_found": "Neniu komando trovita", + "components.rich_text_editor.plugins.suggestions.default_message.display_results": "Skribu almenaΕ­ tri leterojn por montri uzantojn", + "components.rich_text_editor.plugins.suggestions.default_message.no_user_found": "Neniu uzanto trovita", + "components.rich_text_editor.plugins.suggestions.default_message.no_emoji_found": "Neniu emoji trovita", + "scenes.app.messages.input.parts.is_writing.message.user_is_writing": "{{$1}} skribas...", + "scenes.app.messages.input.parts.is_writing.message.users_are_writing": "{{$1}} kaj {{$2}} skribas...", + "scenes.app.messages.input.parts.is_writing.message.users_and_more_are_writing": "{{$1}}, {{$2}} kaj {{$3}} pliaj uzantoj skribas...", + "components.locked_features_components.locked_invite_alert.message_part_1": "Via firmao atingis ĝian maksimuman limon de {{$1}} membroj. Bonvolu ", + "components.locked_features_components.locked_invite_alert.message_link": "altgradigu vian kompanion", + "components.locked_features_components.locked_invite_alert.message_part_2": " por inviti pliajn membrojn.", + "components.locked_features_components.locked_invite_alert.message_magic_link": " kontaktu la posedanton aΕ­ administranton de via kompanio.", + "views.client.popup.workspace_parameter.pages.workspace_members.link_to_console": "Vidu Δ‰iujn miajn firmaanojn sur la konzolo", + "scenes.app.popup.appsparameters.pages.amazing_app_description": "Priskribu vian aplikaΔ΅on per kelkaj vortoj", + "scenes.app.popup.appsparameters.pages.application_creator.title": "Nova integriĝo", + "scenes.app.popup.appsparameters.pages.application_creator.checkbox": "Mi komprenas, ke la posedanto kaj administrantoj de Δ‰i tiu kompanio povos modifi kaj publikigi Δ‰i tiun aplikaΔ΅on.", + "twake.application.access.title": "Elektu la ĝustajn mediojn por via aplikaΔ΅o.", + "twake.application.access.no_default_scopes_available'": "Ĉi tiu integriĝo ne havas aliron {{$1}}.", + "scenes.app.popup.appsparameters.pages.application_editor.help_link": "la Twake API-dokumentado", + "scenes.app.popup.appsparameters.pages.application_editor.help_text": "Se vi ne scias kiel plenigi Δ‰i tiujn, iru al ", + "scenes.app.popup.appsparameters.pages.app.private_key": "Privata ŝlosilo", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed": "Sukcese forigita aplikaΔ΅o {{$1}} !", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed_error": "Eraro dum forigo de aplikaΔ΅o {{$1}} !", + "scenes.app.popup.appsparameters.pages.application_editor.application_published": "Sukcese {{$1}} aplikaΔ΅o!", + "scenes.app.integrations_parameters.add_application": "Nova integriĝo", + "scenes.app.integrations_parameters.company_applications_table.more_menu.developer_settings": "Agordoj por programistoj", + "components.rich_text_editor.plugins.suggestions.loading": "SerΔ‰ante pli", + "components.open_desktop_popup.subtitle": "malfermita en Twake-aplikaΔ΅o", + "components.open_desktop_popup.open_here_link": "Malfermu Δ‰i tie anstataΕ­e", + "molecules.download_banner.title": "Profitu la plej grandan parton de Twake, elŝutu la labortablon nun", + "molecules.download_banner.download_button": "Elŝutu labortablan apon", + "scenes.app.channelsbar.channel_copy_link": "Kopiu kanala ligilo", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.success.update": "Sukcese ĝisdatigita", + "components.searchpopup.no_results_for": "Ne estis rezultoj por", + "components.searchpopup.try_new_search": "Provu novan serΔ‰on", + "components.searchpopup.all": "Ĉiuj", + "components.searchpopup.chats": "Babiloj", + "components.searchpopup.media": "Amaskomunikiloj", + "components.searchpopup.files": "Dosieroj", + "components.searchpopup.recent_chats": "Lastatempaj babilejoj", + "components.searchpopup.recent_media": "Lastatempaj amaskomunikiloj", + "components.searchpopup.recent_files": "Lastatempaj dosieroj", + "components.searchpopup.recent_channels_and_contacts": "Lastatempaj kanaloj kaj kontaktoj", + "components.searchpopup.header_title": "SerΔ‰i", + "components.searchpopup.scope.company": "en tuta kompanio", + "components.searchpopup.scope.channel": "en Δ‰i tiu kanalo", + "components.searchpopup.channels": "Kanaloj", + "components.searchpopup.messages": "Mesaĝoj", + "components.searchpopup.start_search": "Enigu kelkajn ŝlosilvortojn por komenci la serΔ‰on.", + "components.searchpopup.see_more": "Vidu pli", + "scenes.client.channelbar.channelmemberslist.search_invite": "SerΔ‰u kaj invitu uzantojn al Δ‰i tiu kanalo", + "scenes.client.channelbar.channelmemberslist.search_invite_notice": "Ne estas multaj membroj en Δ‰i tiu kanalo. SerΔ‰u kaj invitu uzantojn nun per retpoŝto aΕ­ nomo.", + "scenes.client.channelbar.channelmemberslist.invite_email_button": "Aldonu al kanalo nur kiel gasto", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace": "Aldonu al kanalo kaj laborspaco kiel membron", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace_confirm": "Inviti {{$1}} al laborspaco kiel membro?", + "scenes.client.channelbar.channelmemberslist.search_invite_type_email": "Tajpu validan adreson por inviti retpoŝte.", + "scenes.client.channelbar.channelmemberslist.pending_section": "Uzantoj atendas inviton", + "scenes.client.channelbar.channelmemberslist.members_section": "Uzantoj en Δ‰i tiu kanalo", + "scenes.client.channelbar.channelmemberslist.not_members_section": "Uzantoj ne en Δ‰i tiu kanalo", + "scenes.client.join_private_channel.info": "Ĉi tiu enhavo de Δ‰i tiu kanalo estas limigita aΕ­ ne ekzistas. Bonvolu kontakti membron de Δ‰i tiu kanalo por esti invitita.", + "scenes.client.join_public_channel": "Aliĝu al Δ‰i tiu kanalo", + "scenes.client.join_public_channel.info": "Vi ne estas membro de Δ‰i tiu rekta kanalo. Alklaku Δ‰i tiun butonon por komenci la diskuton nun.", + "general.yes": "Jes", + "general.no": "Ne", + "components.open_desktop_popup.open_here_link_forever": "Neniam provu malfermi la apon denove", + "components.channel_attachement_list.medias": "Medias", + "components.channel_attachement_list.files": "Dosieroj", + "components.channel_attachement_list.title": "Kanalaj dosieroj kaj amaskomunikiloj", + "components.channel_attachement_list.nothing_found": "Nenio Δ‰i tie ankoraΕ­", + "molecules.message_quote.deleted": "Ĉi tiu mesaĝo estis forigita", + "scenes.apps.messages.jump": "Saltu al mesaĝo", + "components.channel_attachement_list.open": "Malfermu galerion", + "scenes.apps.account.on_console": "Por redakti viajn tutmondajn kontajn preferojn, alklaku Iru al Konzolo.", + "scenes.apps.account.assistant.description": "Twake-asistanto kapablas kompreni vian Δ‰iutagan laboron Δ‰e Twake kaj provizi inteligentajn ŝparvojojn kaj agojn dum via tago. La asistanto estas parto de la iniciato Work@Home https://workathome.linagora.com/ kaj nuntempe estas testata nur en la kompanio Linagora kaj estas en la lernado. Ĝi signifas, ke ni sendos datumojn pri uzado de Twake por trejni nian estontan asistantan funkcion.", + "scenes.apps.account.assistant.share.nothing": "Ne dividu ion kun la asistanto (malŝaltu asistanton)", + "scenes.apps.account.assistant.share.all": "Kunhavigu Δ‰ion inkluzive de mesaĝoj kaj dosieroj enhavoj", + "scenes.apps.account.assistant.share.metadata": "Kunhavigu metadatumojn sed ne enhavojn", + "scenes.apps.account.assistant.success": "Viaj preferoj estis ĝisdatigitaj kun sukceso.", + "scenes.apps.account.assistant.title": "Asistanto", + "components.message_seen_by.title": "Uzantoj, kiuj vidis la mesaĝon", + "components.message_seen_by.none_seen_it": "Neniu ankoraΕ­ vidis la mesaĝon", + "components.message_seen_by.btn": "Informoj", + "molecules.quoted_content.attachements": "{{$1}} aldonaΔ΅oj", + "scenes.apps.messages.message.user_deactivated": "Vi rigardas la arkivojn de malaktivigita konto", + "general.user.deactivated": "Uzanto ne plu estas en Δ‰i tiu kompanio", + "general.user.connected": "Rete", + "scenes.app.popup.userparameter.pages.email_notif_delay_never": "Neniam", + "scenes.app.popup.userparameter.pages.email_notif_delay_quarter_hour": "15 minutoj", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_day": "1 tago", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_hour": "1 horo", + "scenes.app.popup.userparameter.pages.notification_sound.defaut": "DefaΕ­lte", + "scenes.app.popup.userparameter.pages.notification_sound.none": "Neniu", + "scenes.client.channelbar.readonly_channel.checkbox": "Limigi skribkapablon", + "scenes.apps.messages.message.forward": "AntaΕ­en", + "components.channelselector.title": "Elektu kanalojn", + "components.channelselector.confirm": "Elektu $1-kanalon(j)", + "scenes.apps.messages.message.forward.title": "AntaΕ­en mesaĝon", + "scenes.apps.messages.message.forward.comment": "Aldonu mesaĝon", + "scenes.apps.messages.message.forward.confirm": "Sendu al $1 kanalo(j)", + "scenes.apps.messages.message.forward.send": "Mesaĝo plusendita", + "components.channelselector.search": "SerΔ‰u kanalojn kaj diskutojn", + "scenes.app.channelsbar.channel_information.name": "Kanala nomo", + "scenes.app.channelsbar.channel_access": "Kanala aliro", + "scenes.app.channelsbar.channel_access.save": "Konservu alir-agordojn", + "scenes.app.channelsbar.channel_access.readonly": "Nurlegebla kanalo", + "scenes.app.channelsbar.channel_access.readonly.info": "Limigi skribon al moderigantoj, administrantoj kaj posedantoj.", + "scenes.app.channelsbar.channel_access.visibility": "Publika videbleco", + "scenes.app.channelsbar.channel_access.visibility.info": "Iu ajn krom firmaaj gastoj povas aliĝi.", + "scenes.app.channelsbar.channel_access.default": "AΕ­tomata aliĝo", + "scenes.app.channelsbar.channel_access.default.info": "Novaj membroj estos aldonitaj Δ‰i tie aΕ­tomate.", + "scenes.app.channelsbar.channel_information": "Redaktu informojn pri kanalo", + "scenes.app.channelsbar.channel_information.logo.add": "Alŝutu bildon", + "scenes.app.channelsbar.channel_information.logo.remove": "Forigi bildon", + "scenes.app.channelsbar.channel_information.description": "Kanala priskribo", + "scenes.app.channelsbar.channel_information.description.placeholder": "Kanala priskribo, vi povas uzi markdown.", + "scenes.app.channelsbar.channel_information.group": "Kanala grupo", + "scenes.app.channelsbar.channel_information.group.none": "Ne elektita", + "scenes.app.channelsbar.channel_information.group.new": "Kreu novan grupon", + "scenes.app.channelsbar.channel_information.group.save": "Agordu kanalgrupon al $1", + "scenes.app.channelsbar.channel_information.group.save_none": "Ne agordu kanalgrupon", + "scenes.app.channelsbar.channel_information.save": "Konservu informojn", + "scenes.client.channelbar.channelmemberslist.invite_to_workspace": "Invitu {{$1}} al la laborspaco ➑", + "components.invitation.invitation_channels.button": "Invitu al kanaloj", + "components.invitation.invitation_input_list.add": "Aldoni", + "components.invitation.invitation_input_list.member": "Membro", + "components.invitation.invitation_input_list.guest": "Gasto", + "components.invitation.invitation_input_list.placeholder": "Komencu tajpi retpoŝton", + "components.invitation.invitation_sent.button": "Sendu pliajn invitojn", + "components.invitation.reached_limit.text": "vi atingis la maksimuman nombron da uzantoj en via kompanio. Pliigu vian abonon aΕ­ aldonu Δ‰i tiujn uzantojn kiel gastojn", + "components.invitation.allow_anyone_by_email.text": "Permesu al iu ajn kun @{{$1}} retpoŝto aliĝi al Δ‰i tiu laborspaco", + "components.invitation.invitation_sent.title": "Invitoj estas sukcese senditaj", + "components.invitation.invitation_sent.subtitle_status": "Vi povas spuri la staton de la invito en:", + "components.invitation.invitation_sent.subtitle_location": "Agordoj de laborspaco > Administrado de membroj", + "components.invitation.invitation_sent.link": "Kontrolu la staton de la invito", + "components.invitation.invitation_target.invite_as_guests": "Invitu Δ‰iujn kiel gastojn", + "components.invitation.invitation_target.invite_as_members": "Invitu Δ‰iujn kiel membrojn", + "components.invitation.invitation_target.channels_button": "Kanaloj por inviti", + "components.invitation.workspace_link.text": "Laborspaca invitligo", + "components.invitation.workspace_link.button": "Kopiu", + "components.invitation.title": "inviti homojn al {{$1}}", + "components.invitation.bulk_invitation": "Pogranda invito", + "components.invitation.button": "Sendu invitojn", + "scenes.client.readonly.info": "Ĉi tiu kanalo estas nurlegebla fonto, sed vi povas komenti en la fadenoj.", + "scenes.app.channelsbar.channel_information.group.title": "Kanalaj grupoj", + "components.invitation.custom_role_invitation": "Klasika invito", + "components.invitation.link": "Ligo" +} diff --git a/twake/frontend/public/locales/es.json b/twake/frontend/public/locales/es.json new file mode 100644 index 00000000..bbb4abe6 --- /dev/null +++ b/twake/frontend/public/locales/es.json @@ -0,0 +1,1008 @@ +{ + "general.close": "Cerrar", + "general.save": "Guardar", + "general.cancel": "Cancelar", + "general.create": "Crear", + "general.edit": "Editar", + "general.continue": "Continuar", + "general.back": "AtrΓ‘s", + "general.confirm": "Confirmar", + "general.delete": "Borrar", + "components.application.messages": "Mensajes", + "components.drive_dropzone.uploading": "Subiendo ...", + "components.user_picker.modal_no_result": "No se han encontrado resultados", + "scenes.app.header.disconnected": "EstΓ‘s desconectado", + "scenes.app.header.disconnected.reload": "Recargar", + "scenes.app.header.alt_notifications": "Notificaciones", + "scenes.apps.calendar.calendar.week_btn": "Semana", + "scenes.apps.calendar.calendar.list_btn": "Lista", + "scenes.apps.calendar.event_edition.deadline_tag": "Fecha tope", + "scenes.apps.calendar.event_edition.checkbox_all_day": "Todo el dia", + "scenes.apps.calendar.event_edition.title_confidentiality": "Participantes", + "scenes.apps.calendar.event_view.article_until": "hasta", + "scenes.apps.calendar.calendar_modal.participants": "Participantes", + "scenes.apps.calendar.calendar_modal.placeholder": "Nombre", + "scenes.apps.calendar.left.calendars": "Calendarios", + "scenes.apps.drive.left.search": "Buscar", + "scenes.apps.drive.navigators.navigator_content.directory_name": "Nombre del directorio", + "scenes.apps.drive.navigators.navigator_content.files": "Archivos", + "scenes.apps.drive.navigators.navigator_labels.title": "Etiquetas", + "scenes.apps.drive.navigators.new_file.untitled": "Intitulado", + "scenes.apps.drive.navigators.new_file.create_file.type": "Tipo", + "scenes.apps.drive.navigators.new_file": "Archivo nuevo", + "scenes.apps.drive.preview_bloc.operations_download": "Descargar", + "scenes.apps.drive.preview_bloc.error_file": "Archivo no encontrado", + "scenes.apps.drive.right_preview.operations_restore": "Restaurar", + "scenes.apps.drive.right_preview.operations_delete": "Mover a la papelera", + "scenes.apps.messages.messages": "Mensajes", + "scenes.apps.messages.chatbox.chat.delete_message": "Eliminar este mensaje", + "scenes.apps.messages.chatbox.chat.delete_message_btn": "Borrar", + "scenes.apps.messages.left_bar.stream_modal.placeholder_name": "Nombre", + "scenes.apps.parameters.workspace_sections.workspace": "Espacio de trabajo", + "scenes.apps.parameters.workspace_sections.members": "Participantes", + "scenes.apps.parameters.group_sections.workspaces": "Espacios de trabajo", + "scenes.apps.parameters.group_sections.apps": "Aplicaciones", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace": "Eliminar espacio", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace_description": "Para confirmar que desea eliminar este espacio de trabajo, escriba el nombre que aparece a continuaciΓ³n y pulse suprimir.", + "scenes.app.popup.workspaceparameter.pages.enter": "Entrar ", + "scenes.apps.account.title": "ParΓ‘metros de cuenta", + "scenes.apps.account.account.menu_title": "Cuenta", + "scenes.apps.account.languages.menu_title": "Idioma", + "scenes.apps.account.account.firstname": "Nombre de pila", + "scenes.apps.account.account.lastname": "Apellido", + "scenes.apps.account.account.username": "Nombre de usuario", + "scenes.apps.account.account.change_username": "Cambie el nombre de usuario ΓΊnico.", + "scenes.apps.account.account.emails": "Los correos electrΓ³nicos", + "scenes.apps.account.account.main_email": "Correo electrΓ³nico principal", + "scenes.apps.account.account.email_add": "Agregar nuevo correo electrΓ³nico", + "scenes.apps.account.account.email_add_modal.invalid_code": "Este cΓ³digo no es vΓ‘lido", + "scenes.apps.account.account.password": "ContraseΓ±a", + "scenes.apps.account.account.password_modal.old_password": "ContraseΓ±a actual", + "scenes.apps.account.account.password_modal.password": "Nueva contraseΓ±a", + "scenes.apps.account.account.password_modal.bad_old_password": "La contraseΓ±a anterior no es correcta.", + "scenes.apps.account.account.password_modal.bad_password": "Sus contraseΓ±as no coinciden o son demasiado pequeΓ±as, por favor escriba una contraseΓ±a con al menos 8 caracteres.", + "scenes.apps.account.account.logout": "Cerrar sesiΓ³n", + "scenes.apps.account.languages.text": "Cambiar el idioma de Twake.", + "scenes.apps.account.notifications.title": "Notificaciones", + "scenes.apps.account.notifications.keywords_subtitle": "Palabras clave", + "scenes.apps.account.notifications.keywords_placeholder": "dev, wifi, cΓ³digo, ...", + "scenes.apps.account.notifications.disturb_option_a": "No me envΓ­e notificaciones automΓ‘ticas entre ", + "scenes.apps.account.notifications.disturb_option_b": " y ", + "scenes.apps.account.notifications.disturb_option_c": " (zona horaria local)", + "scenes.apps.account.notifications.devices_subtitle": "Notificaciones de dispositivos", + "scenes.apps.account.notifications.devices_option_ever": "Siempre envΓ­ame notificaciones push", + "scenes.apps.account.notifications.devices_option_inactive": "Enviarme notificaciones automΓ‘ticas cuando estoy inactivo en el escritorio", + "scenes.apps.account.notifications.devices_option_never": "Nunca me envΓ­e notificaciones automΓ‘ticas", + "scenes.apps.account.notifications.privacy_subtitle": "Intimidad", + "scenes.apps.parameters.group_sections.apps.badge_extension": "ExtensiΓ³n", + "scenes.apps.parameters.workspace_sections.members.members": "Miembros", + "scenes.apps.parameters.workspace_sections.members.pending": "Correos electrΓ³nicos pendientes", + "scenes.apps.parameters.workspace_sections.members.invite": "Invita nuevos miembros", + "scenes.apps.parameters.workspace_sections.members.invite_btn": "AΓ±adir miembros", + "scenes.login.footer.go_to_twake": "Ir a twakeapp.com", + "scenes.login.create_account.title": "Crea una cuenta nueva", + "scenes.login.create_account.email": "E-mail", + "scenes.login.create_account.email_used": "Este correo electrΓ³nico ya estΓ‘ usado.", + "scenes.login.create_account.username": "Nombre de usuario", + "scenes.login.create_account.username_already_exist": "El nombre de usuario ya esta siendo usado", + "scenes.login.create_account.fill_in_username": "Debes completar tu nombre de usuario", + "scenes.login.create_account.fill_in_email": "Debe completar su correo electrΓ³nico con un correo electrΓ³nico correcto", + "scenes.login.create_account.too_short_password": "Su contraseΓ±a debe tener al menos 8 caracteres.", + "scenes.login.create_account.firstname": "Nombre de pila", + "scenes.login.create_account.newsletter": "Reciba informaciΓ³n sobre Twake", + "scenes.login.create_account.lastname": "Apellido", + "scenes.login.forgot_password.title": "Se te olvidΓ³ tu contraseΓ±a ?", + "scenes.login.forgot_password.text": "RecibirΓ‘ 9 dΓ­gitos por correo electrΓ³nico para verificar su identidad.", + "scenes.login.forgot_password.email_to_recover": "Correo electrΓ³nico para recuperar", + "scenes.login.forgot_password.mail_doesnt_exist": "Este correo electrΓ³nico no existe", + "scenes.login.forgot_password.text2": "RecibirΓ‘ un cΓ³digo de 9 caracteres. Por favor ingrΓ©salo en el campo abajo para continuar.", + "scenes.login.forgot_password.invalid_code": "Este cΓ³digo no es vΓ‘lido.", + "scenes.login.forgot_password.text3": "Ingrese una nueva contraseΓ±a para su cuenta.", + "scenes.login.forgot_password.password": "ContraseΓ±a", + "scenes.login.forgot_password.password2": "Confirmar contraseΓ±a", + "scenes.login.forgot_password.password_dont_match": "Sus contraseΓ±as no coinciden o son demasiado pequeΓ±as, por favor escriba una contraseΓ±a con al menos 8 caracteres.", + "scenes.login.home.title": "Iniciar sesiΓ³n en Twake", + "scenes.login.home.email": "Correo electrΓ³nico", + "scenes.login.home.unable_to_connect": "Credenciales no vΓ‘lidas", + "scenes.login.home.password": "ContraseΓ±a", + "scenes.login.home.login_btn": "Iniciar sesiΓ³n", + "scenes.login.home.lost_password": "ΒΏHa olvidado su contraseΓ±a?", + "scenes.login.home.create_account": "Crea una cuenta", + "scenes.app.popup.appsparameters.pages.icon": "icono", + "general.help.support": "Soporte", + "general.help": "Ayuda", + "general.archive": "Archivar", + "scenes.app.workspaces.create_company.invitations.title": "Configure su espacio de trabajo.", + "components.users_picker.add_me": "AΓ±adirme", + "scenes.app.workspaces.create_company.group_data.group_main_activity.other": "Otros", + "scenes.app.workspaces.create_company.group_data.group_main_activity.administration": "AdministraciΓ³n", + "scenes.app.workspaces.create_company.group_data.group_main_activity.education": "EducaciΓ³n", + "scenes.app.workspaces.create_company.group_data.group_main_activity.research": "InvestigaciΓ³n", + "scenes.app.workspaces.create_company.group_data.group_main_activity.transport_logistics": "Transporte / LogΓ­stica", + "scenes.app.workspaces.create_company.group_data.group_main_activity.textile_clothing_shoes": "Textil / Ropa / Calzado", + "scenes.app.workspaces.create_company.group_data.group_main_activity.entertainment": "Entretenimiento", + "scenes.app.workspaces.create_company.group_data.group_main_activity.business_services": "Servicios empresariales", + "scenes.app.workspaces.create_company.group_data.group_main_activity.machinery_automotive": "Maquinaria / AutomociΓ³n", + "scenes.app.workspaces.create_company.group_data.group_main_activity.it_telecom": "InformΓ‘tica / Telecomunicaciones", + "scenes.app.workspaces.create_company.group_data.group_main_activity.pharmaceutical_industry": "Industria farmacΓ©utica", + "scenes.app.workspaces.create_company.group_data.group_main_activity.studies_and_advice": "Estudios y consejos", + "scenes.app.workspaces.create_company.group_data.group_main_activity.electronics_electricity_energy": "ElectrΓ³nica / Electricidad / EnergΓ­a", + "scenes.app.workspaces.create_company.group_data.group_main_activity.publishing_communication_multimedia": "PublicaciΓ³n / ComunicaciΓ³n / Multimedia", + "scenes.app.workspaces.create_company.group_data.group_main_activity.trade_commerce_distribution": "Comercio / DistribuciΓ³n", + "scenes.app.workspaces.create_company.group_data.group_main_activity.chemistry": "QuΓ­mica", + "scenes.app.workspaces.create_company.group_data.group_main_activity.materials": "Materiales", + "scenes.app.workspaces.create_company.group_data.group_main_activity.real_estate": "Inmobiliaria", + "scenes.app.workspaces.create_company.group_data.group_main_activity.construction_building": "ConstrucciΓ³n / Materiales de construcciΓ³n", + "scenes.app.workspaces.create_company.group_data.group_main_activity.printing_paper": "ImpresiΓ³n / Papel", + "scenes.app.workspaces.create_company.group_data.group_main_activity.bank": "Banco / Seguro", + "scenes.app.workspaces.create_company.group_data.group_main_activity.food": "Comida", + "scenes.app.workspaces.create_company.group_data.group_main_activity": "Actividad principal", + "scenes.app.workspaces.create_company.group_data.group_size.5000_more": "MΓ‘s de 5000 usuarios", + "scenes.app.workspaces.create_company.group_data.group_size.1000_5000": "1000 - 4999 usuarios", + "scenes.app.workspaces.create_company.group_data.group_size.500_1000": "500 - 999 usuarios", + "scenes.app.workspaces.create_company.group_data.group_size.100_500": "100 - 499 usuarios", + "scenes.app.workspaces.create_company.group_data.group_size.50_100": "50 - 99 usuarios", + "scenes.app.workspaces.create_company.group_data.group_size.10_50": "11 - 49 usuarios", + "scenes.app.workspaces.create_company.group_data.group_size.4_10": "4 - 10 usuarios", + "scenes.app.workspaces.create_company.group_data.group_size.less_3": "Menos de 4 usuarios", + "scenes.app.workspaces.create_company.group_data.group_size": "TamaΓ±o del grupo", + "scenes.app.workspaces.create_company.group_data.group_type.other_group": "Otros", + "scenes.app.workspaces.create_company.group_data.group_type.society_club_charity": "Sociedad, club o asociaciΓ³n benΓ©fica", + "scenes.app.workspaces.create_company.group_data.group_type.university_school": "Universidad o escuela", + "scenes.app.workspaces.create_company.group_data.group_type.public_organization": "OrganizaciΓ³n pΓΊblica", + "scenes.app.workspaces.create_company.group_data.group_type.company": "Empresa o departamento de la empresa", + "scenes.app.workspaces.create_company.group_data.group_type": "Tipo de grupo", + "scenes.app.workspaces.create_company.group_data": "Configure su nuevo grupo", + "scenes.app.side_app.messages_thread_title": "{{$1}} β€’ Hilo de mensajes", + "general.connexion_status.connecting": "Reconectando…", + "general.connexion_status.connected": "Usted estΓ‘ en lΓ­nea", + "general.connexion_status.disconnected": "Usted estΓ‘ desconectado", + "general.add": "AΓ±adir", + "general.remove": "Eliminar", + "general.update": "ActualizaciΓ³n", + "general.send": "Enviar mensaje", + "general.help.documentation": "DocumentaciΓ³n", + "general.unarchive": "Desarchivar", + "scenes.apps.drive.right_preview.public_link": "Enlace pΓΊblico", + "components.calendar.repetition.never": "Nunca", + "components.calendar.repetition.ends": "Finaliza", + "components.calendar.repetition.repeat": "Repetir cada", + "components.calendar.repetition.custom": "Personalizado...", + "components.calendar.repetition.every_weekday": "Todos los dΓ­as de la semana (de lunes a viernes)", + "components.calendar.repetition.annually_on": "Anualmente en {{$1}}", + "components.calendar.repetition.monthly_on_day": "Mensualmente en el dΓ­a {{$1}}", + "components.calendar.repetition.monthly_on": "Mensualmente en el {{$1}} {{$2}}", + "components.calendar.repetition.weekly_on": "Semanalmente en {{$1}}", + "components.calendar.repetition.does_not_repeat": "No se repite", + "components.calendar.repetition.everyday": "Diariamente", + "app.name.twake_tasks": "Tareas", + "app.name.twake_drive": "Documentos", + "app.name.twake_calendar": "Calendario", + "scenes.apps.account.account.email_add_modal.confirm": "Confirme este correo electrΓ³nico", + "scenes.apps.account.thumbnail.max_weight": "TamaΓ±o mΓ‘ximo 5 MB", + "general.open": "Abrir", + "scenes.apps.account.preference": "Preferencias", + "scenes.apps.account.identity.description": "Cambia tu nombre, apellido e imagen de perfil visible para otros usuarios de Twake.", + "scenes.apps.account.identity": "Identidad", + "scenes.apps.account.account.password.description": "Cambia tu contraseΓ±a.", + "scenes.apps.account.account.make_main": "Establecer principal", + "scenes.apps.account.account.emails.description": "Gestione sus diferentes direcciones de correo electrΓ³nico.", + "scenes.apps.account.account.description_main": "Tu direcciΓ³n principal es donde Twake envΓ­a tus notificaciones. Tus direcciones secundarias te permiten ser invitado automΓ‘ticamente a los espacios de trabajo que las utilizan.", + "scenes.login.forgot_password.finished": "Su contraseΓ±a ha sido actualizada con Γ©xito.", + "scenes.app.workspaces.welcome_page.done": "He terminado", + "scenes.app.workspaces.welcome_page.we_sent_you_mail": "Te hemos enviado un cΓ³digo de verificaciΓ³n a travΓ©s de {{$1}}", + "scenes.app.workspaces.welcome_page.new_email": "AΓ±adir un correo electrΓ³nico secundario", + "scenes.app.workspaces.welcome_page.code_verification": "CΓ³digo de verificaciΓ³n", + "scenes.app.workspaces.welcome_page.add_new_email": "AΓ±adir un correo electrΓ³nico", + "scenes.app.workspaces.welcome_page.other_mail_title": "Direcciones secundarias", + "scenes.app.workspaces.welcome_page.main_mail_title": "DirecciΓ³n principal", + "scenes.app.workspaces.welcome_page.add_secondary_emails_comment": "Puede vincular varias direcciones de correo electrΓ³nico a su cuenta; sΓ³lo se utilizarΓ‘ una direcciΓ³n para enviarle notificaciones.", + "scenes.app.workspaces.welcome_page.welcome_header": "Β‘Bienvenido a Twake!", + "scenes.app.workspaces.welcome_page.twake_team": "Twake", + "scenes.app.workspaces.welcome_page.try_again": "IntΓ©ntalo de nuevo", + "scenes.app.workspaces.welcome_page.see_you_soon": "Β‘Hasta pronto!", + "scenes.app.workspaces.welcome_page.ready_to_work": "Ya estΓ‘s listo para trabajar.", + "scenes.app.workspaces.welcome_page.no_company_subtitle": "Oh, vaya... Parece que nadie te ha invitado a un espacio de trabajo todavΓ­a.", + "scenes.app.workspaces.welcome_page.may_be_invited_with_secondary_emails": "ΒΏTe han invitado con otra direcciΓ³n de correo electrΓ³nico?", + "scenes.app.workspaces.welcome_page.lets_go": "Β‘Vamos!", + "scenes.app.workspaces.welcome_page.create_my_company": "Crear mi empresa", + "scenes.app.workspaces.welcome_page.added_to_company": "Se le ha invitado a ", + "scenes.app.workspaces.welcome_page.add_secondary_emails": "AΓ±adir un correo electrΓ³nico secundario", + "scenes.app.workspaces.create_company.title": "Crear mi empresa", + "scenes.app.workspaces.create_company.invitations.title_2": "AΓ±ade usuarios a tu equipo.", + "scenes.app.workspaces.create_company.importations.title_2": "Β‘No te preocupes, puedes hacerlo mΓ‘s tarde!", + "scenes.app.workspaces.create_company.importations.title_1": "ΒΏYa trabaja con herramientas digitales? Β‘Importe o integre sus herramientas ahora!", + "scenes.app.workspaces.create_company.group_data.title": "Seremos rΓ‘pidos, sΓ³lo necesitamos informaciΓ³n estadΓ­stica.", + "scenes.app.workspaces.create_company.default_workspace_name": "Principal", + "scenes.app.workspaces.create_company.company_name.title_2": "indique el nombre de su empresa.", + "scenes.app.workspaces.create_company.company_name.title_1": "Para empezar,", + "scenes.app.workspaces.create_company.company_name.placeholder": "Nombre de la empresa", + "scenes.login.create_account.step_3_subtitle": "Último paso: Β‘Necesitamos verificar que no eres un robot!", + "scenes.login.create_account.step_3_mail_sent": "Le hemos enviado un enlace de activaciΓ³n por correo electrΓ³nico.", + "scenes.login.create_account.step_2_subtitle_b": "Su nΓΊmero de telΓ©fono sigue siendo privado.", + "scenes.login.create_account.step_2_subtitle_a": "AΓ±ade tu nombre completo para que otros usuarios te reconozcan.", + "scenes.login.create_account.step_1_subtitle": "No podrΓ­a ser mΓ‘s sencillo: sΓ³lo necesitamos algo de informaciΓ³n.", + "scenes.login.create_account.password": "ContraseΓ±a", + "scenes.login.home.subtitle": "Me alegro de verte", + "scenes.login.footer.branding": "EstΓ‘s en un servidor Twake privado de {{$1}} ({{$2}}). ", + "scenes.apps.tasks.list_modal.remove_archived_tasks": "Eliminar tareas archivadas ({{$1}})", + "scenes.apps.tasks.list_modal.archive_all_tasks": "Archivar todas las tareas", + "scenes.apps.tasks.list_modal.predefined_participants": "Participantes predefinidos", + "scenes.apps.tasks.list_modal.remove": "Eliminar la lista y las tareas", + "scenes.apps.tasks.list_modal.new_list": "Nueva lista", + "scenes.apps.tasks.list_modal.modify_list": "Modificar la lista", + "scenes.apps.tasks.task.edit.dates": "Fechas", + "scenes.apps.tasks.task.assignees": "Asignados", + "scenes.apps.tasks.task.description": "DescripciΓ³n", + "scenes.apps.tasks.task_status.done": "Hecho", + "scenes.apps.tasks.task_status.current": "Actual", + "scenes.apps.tasks.task_status.todo": "Para hacer", + "scenes.apps.tasks.no_tasks": "Ninguna tarea", + "scenes.apps.tasks.task": "Tarea", + "scenes.apps.tasks.new_board.edit_title": "Editar tablero", + "scenes.apps.tasks.new_board.title": "Nuevo tablero", + "scenes.apps.tasks.choose_board_button": "Elija una tabla", + "scenes.apps.tasks.unconfigured_tab": "Esta pestaΓ±a aΓΊn no estΓ‘ configurada.", + "scenes.apps.tasks.no_connectors_menu_text": "No tiene ningΓΊn conector que pueda conectarse a un calendario.", + "scenes.apps.tasks.connectors_search_menu": "Buscar conectores...", + "scenes.apps.tasks.connectors_menu": "Conectores...", + "scenes.apps.tasks.boards": "Tableros", + "scenes.apps.account.notifications.sound": "NotificaciΓ³n de sonido", + "scenes.apps.account.notifications.mail_subtitle": "Notificaciones por correo electrΓ³nico", + "scenes.apps.messages.left_bar.stream.notifications.never": "Nada", + "scenes.apps.messages.left_bar.stream.notifications.me": "sΓ³lo {{$1}}", + "scenes.apps.messages.left_bar.stream.notifications.mentions": "{{$1}}, {{$2}} y {{$3}}", + "scenes.apps.messages.left_bar.stream.notifications.all": "Cualquier mensaje", + "scenes.apps.messages.left_bar.stream.notifications": "Notificaciones...", + "scenes.apps.messages.left_bar.stream.remove_from_favorites": "Eliminar de los favoritos", + "scenes.apps.messages.left_bar.stream.add_to_favorites": "AΓ±adir a favoritos", + "components.locked_features.locked_workspace_popup.title": "No se puede crear mΓ‘s espacio de trabajo", + "components.locked_features.locked_workspace_popup.subtitle": "En la versiΓ³n gratuita, solo puede tener 1 espacio de trabajo en su empresa.", + "components.locked_features.locked_workspace_popup.text": "Β‘Ups! Parece que desea crear un nuevo espacio de trabajo en su empresa. Es posible que desee considerar actualizar su plan si desea colaborar en varios espacios de trabajo. Explore nuestras opciones de precios y seleccione la mejor opciΓ³n para las necesidades de colaboraciΓ³n de su equipo.", + "components.locked_features.locked_only_office_popup.title": "No puedes editar este archivo", + "components.locked_features.locked_only_office_popup.subtitle": "En la versiΓ³n gratuita, no puede usar onlyoffice.", + "components.locked_features.locked_only_office_popup.text": "Β‘Ups! Parece que desea editar el archivo de Twake. Es posible que desee considerar la posibilidad de actualizar su plan si desea colaborar en torno a los archivos de Office. Explore nuestras opciones de precios y seleccione la mejor opciΓ³n para las necesidades de colaboraciΓ³n de su equipo.", + "components.locked_features.locked_drive_popup.title": "No puedes subir mas archivos", + "components.locked_features.locked_drive_popup.subtitle": "En la versiΓ³n gratuita, puede almacenar solo 6 GB.", + "components.calendar.repetition.repeat_on": "Repetir en", + "components.calendar.repetition.occurrence": "Ocurrencia(s)", + "components.calendar.repetition.custom_recurrence": "Recurrencia personalizada", + "components.calendar.repetition.months": "mes(es)", + "components.calendar.repetition.weeks": "semana(s)", + "components.calendar.repetition.days": "dΓ­a(s)", + "scenes.app.channelsbar.currentuser.add_apps": "Buscar aplicaciones", + "components.calendar.repetition.years": "aΓ±o(s)", + "components.calendar.repetition.after": "DespuΓ©s de", + "components.calendar.repetition.on": "En", + "general.retry": "Reintentar", + "scenes.app.popup.appsparameters.pages.application_title": "AplicaciΓ³n", + "scenes.app.popup.appsparameters.pages.app_update": "Actualizar la aplicaciΓ³n {{$1}} (la aplicaciΓ³n utiliza {{$2}} veces.)", + "scenes.app.popup.appsparameters.pages.app_privileges_label": "Privilegios de aplicaciΓ³n", + "scenes.app.popup.appsparameters.pages.app_privileges_information": "Defina lo que su aplicaciΓ³n puede editar y leer.", + "scenes.app.popup.appsparameters.pages.app_modification_right": "Todos los directivos de esta empresa podrΓ‘n editar esta aplicaciΓ³n.", + "scenes.app.popup.appsparameters.pages.app_name_label": "Nombre de la aplicaciΓ³n", + "scenes.app.popup.appsparameters.pages.api_parameters_label": "Opciones de la API", + "scenes.app.popup.appsparameters.pages.api_data_description": "Datos ΓΊtiles para la API de Twake.", + "scenes.app.popup.appsparameters.pages.amazing_app_name": "Mi increΓ­ble aplicaciΓ³n", + "scenes.app.popup.appsparameters.pages.allowed_ip_adresses_method": "Utilice * en el desarrollo para permitir todas las direcciones IP.", + "scenes.app.popup.appsparameters.pages.alert_published_app": "Su solicitud estΓ‘ publicada, no puede editarla.", + "scenes.app.popup.appsparameters.pages._appareance_message_twakcode": "Prueba la apariencia de tus mensajes Twacode", + "scenes.app.popup.appsparameters.pages._app_identity": "Identidad de la aplicaciΓ³n", + "scenes.app.popup.adduser.adresses_message": "Por favor, separe las direcciones con una coma o un espacio. Recuerda que Twake puede limitar el nΓΊmero de invitaciones en funciΓ³n de tu suscripciΓ³n.", + "scenes.app.mainview.tabs.searching_connectors": "Buscar conectores...", + "scenes.app.mainview.tabs.rename": "Renombrar", + "scenes.app.mainview.tabs.no_connected_connectors_for_channel": "No tiene ningΓΊn conector que pueda conectarse a un canal.", + "scenes.app.mainview.instruction_current_tab": "Comienza seleccionando un canal a tu izquierda.", + "scenes.app.channelsbar.welcoming_message_subtitle": "Β‘ConviΓ©rtete en un profesional de Twake en unos pocos clics!", + "scenes.app.channelsbar.welcome": "Bienvenido a Twake", + "scenes.app.channelsbar.tutorial_alert": "ΒΏNo volver a mostrar este marco?", + "scenes.app.channelsbar.sending_message_instruction": "EnvΓ­e su primer mensaje en un debate", + "scenes.app.channelsbar.private_channel_label": "Privado", + "scenes.app.channelsbar.public_channel_label": "PΓΊblico", + "scenes.app.channelsbar.invitation_collaboraors_tutorial": "Invite a los usuarios a su espacio de trabajo.", + "scenes.app.channelsbar.installation_desktop_tutorial": "Instalar la aplicaciΓ³n de escritorio", + "scenes.app.channelsbar.initial_instructions_tutorial": "Elige un nombre, un apellido y una foto de perfil.", + "scenes.app.channelsbar.company_invitation_alert_title": "Ha sido invitado a la empresa ", + "scenes.app.channelsbar.company_invitation_alert_subtitle": "Puede importar estos canales a su negocio para mantenerse organizado haciendo clic en este marco.", + "scenes.app.channelsbar.channel_removing": "Borrar el canal", + "scenes.app.channelsbar.channel_leaving": "Abandonar el canal", + "scenes.app.channelsbar.unread_sign": "Marcar como no leΓ­do", + "scenes.app.channelsbar.read_sign": "Marcar como leΓ­do", + "scenes.app.channelsbar.guest_management": "GestiΓ³n de invitados", + "scenes.app.channelsbar.modify_channel_menu": "Editar canal", + "scenes.app.channelsbar.channelsworkspace.no_channel": "TodavΓ­a no te has unido a ningΓΊn canal", + "scenes.app.channelsbar.channelsworkspace.create_channel": "Crear un canal", + "scenes.app.channelsbar.channelsworkspace.channel_title.favorite": "FAVORITOS", + "scenes.app.channelsbar.channelsworkspace.channel_title": "CANALES", + "scenes.app.channelsbar.channelsuser.private_messages": "Mensajes directos", + "scenes.app.channelsbar.channelsuser.no_private_message_invite_collaboraters": "No hay mensajes privados. Β‘Invite a usuarios!", + "scenes.app.channelsbar.channelsuser.new_private_discussion": "Nuevo debate privado", + "scenes.app.channelsbar.currentuser.user_parameter": "ConfiguraciΓ³n de las notificaciones", + "scenes.app.channelsbar.currentuser.reactivate_notifications": "Reactivar", + "scenes.app.channelsbar.currentuser.disabling_notifications_until": "Desactivar hasta las 9 de la maΓ±ana", + "scenes.app.channelsbar.currentuser.disabling_notifications": "Desactivar 1h", + "scenes.app.channelsbar.currentuser.disable_notifications": "Desactivar", + "scenes.app.channelsbar.currentuser.update": "Actualizar", + "scenes.app.channelsbar.currentuser.logout": "Cerrar sesiΓ³n", + "scenes.app.channelsbar.currentuser.workspace_info": "Se encuentra en el espacio de trabajo {{$1}} del grupo {{$2}}", + "scenes.app.channelsbar.currentuser.title": "ConfiguraciΓ³n de la cuenta", + "scenes.app.channelsbar.currentuser.create_workspace_page": "Crear un espacio de trabajo", + "scenes.app.channelsbar.currentuser.collaborateurs": "Usuarios", + "scenes.app.channelsbar.currentuser.change_my_status": "Cambiar mi estado", + "scenes.app.channelsbar.currentuser.workspace_parameters": "ConfiguraciΓ³n del espacio de trabajo", + "scenes.app.channelsbar.currentuser.invited_status": "Usted es un invitado.", + "scenes.app.popup.appsparameters.pages.parameters_form_small_text": "La aplicaciΓ³n no publicada sΓ³lo funcionarΓ‘ en su empresa. Si desea que estΓ© disponible para todos los usuarios de Twake, active esta opciΓ³n.", + "scenes.app.popup.appsparameters.pages.optimal_format": "Formato Γ³ptimo : 48x48px.", + "scenes.app.popup.appsparameters.pages.ok_user_code": "ok", + "scenes.app.popup.appsparameters.pages.new_app_title": "Nueva aplicaciΓ³n", + "scenes.app.popup.appsparameters.pages.modify_public_data": "Edite los datos pΓΊblicos de su aplicaciΓ³n.", + "scenes.app.popup.appsparameters.pages.message_data_next_event": "Datos pasivos que se enviarΓ‘n en el prΓ³ximo Evento", + "scenes.app.popup.appsparameters.pages.loading": "Cargando...", + "scenes.app.popup.appsparameters.pages.json_configuration_information": "Vaya a la documentaciΓ³n para generar su configuraciΓ³n en formato JSON.", + "scenes.app.popup.appsparameters.pages.interne_availability_application": "AplicaciΓ³n interna", + "scenes.app.popup.appsparameters.pages.instruction_message_twakecode": "Empiece por escribir su mensaje en formato JSON.", + "scenes.app.popup.appsparameters.pages.installation": "Install.", + "scenes.app.popup.appsparameters.pages.grp_section_surname_label": "Nombre simplificado", + "scenes.app.popup.appsparameters.pages.grp_section_name-error": "Este nombre ya estΓ‘ siendo utilizado por otra aplicaciΓ³n. Por favor, elija otro.", + "scenes.app.popup.appsparameters.pages.go_back": "Volver", + "scenes.app.popup.appsparameters.pages.filter_information": "Este filtro limita el uso de su clave API sΓ³lo a los servidores de su conector.", + "scenes.app.popup.appsparameters.pages.event_subtitle": "Eventos", + "scenes.app.popup.appsparameters.pages.error_user_code": "error", + "scenes.app.popup.appsparameters.pages.error_message": "Este nombre ya es utilizado por otra aplicaciΓ³n; por favor, elija otro.", + "scenes.app.popup.appsparameters.pages.error_check_needed": "Se ha producido un error; compruebe sus datos.", + "scenes.app.popup.appsparameters.pages.displayed_parameters_label": "ConfiguraciΓ³n de la pantalla", + "scenes.app.popup.appsparameters.pages.dispalyed_parameters_description": "Te permite definir dΓ³nde serΓ‘ visible tu aplicaciΓ³n.", + "scenes.app.popup.appsparameters.pages.developped_apps_subtitle": "Aplicaciones desarrolladas por la empresa", + "scenes.app.popup.appsparameters.pages.description_label": "DescripciΓ³n", + "scenes.app.popup.appsparameters.pages.danger_zone_label": "Zona peligrosa", + "scenes.app.popup.appsparameters.pages.danger_zone_description": "Eliminar la aplicaciΓ³n", + "scenes.app.popup.appsparameters.pages.current_informations_apps_connectors": "TodavΓ­a no has creado una aplicaciΓ³n. Antes de crear una aplicaciΓ³n o un conector, asegΓΊrate de que no existe ya en nuestra tienda de aplicaciones.", + "scenes.app.popup.appsparameters.pages.create_my_app": "Crear mi aplicaciΓ³n", + "scenes.app.popup.appsparameters.pages.create_app_button": "Crear una aplicaciΓ³n", + "scenes.app.popup.appsparameters.pages.configuration_label": "ConfiguraciΓ³n", + "scenes.app.popup.appsparameters.pages.company_label": "Propietario de la empresa", + "scenes.app.popup.appsparameters.pages.call_event_handlers": "Evento de tipo '{{$1}}' e id '{{$2}}' con pasivos '{{$3}}'", + "scenes.app.popup.appsparameters.pages.button_force": "Forzar en toda la empresa", + "scenes.app.popup.appsparameters.pages.available_publication_alert": "La publicaciΓ³n de su solicitud estΓ‘ actualmente a la espera de ser validada por el equipo de Twake.", + "scenes.app.popup.appsparameters.pages.autorised_ip_adresses_label": "Direcciones IP permitidas", + "scenes.app.popup.appsparameters.pages.automatique_option_information": "Si activa Β«AutomΓ‘ticoΒ», esta aplicaciΓ³n se aΓ±adirΓ‘ automΓ‘ticamente a los siguientes espacios de trabajo de esta empresa.", + "scenes.app.popup.appsparameters.pages.automatique_label": "AutomΓ‘tico", + "scenes.app.popup.appsparameters.pages.apps_title": "Tus aplicaciones y conectores", + "scenes.app.popup.appsparameters.pages.show_button": "Mostrar", + "scenes.app.popup.appsparameters.pages.remove_app_from_workspace": "Eliminar del espacio de trabajo", + "scenes.app.popup.appsparameters.pages.remove_app_from_company": "Eliminar de toda la empresa", + "scenes.app.popup.appsparameters.pages.remove_app": "Eliminar la aplicaciΓ³n {{$1}} de forma permanente.", + "scenes.app.popup.appsparameters.pages.read_privileges_label": "Leer privilegios", + "scenes.app.popup.appsparameters.pages.publish_app_label": "Publicar la aplicaciΓ³n", + "scenes.app.popup.appsparameters.pages.publication_label": "PublicaciΓ³n", + "scenes.app.popup.appsparameters.pages.publication_description": "Determine la visibilidad de su aplicaciΓ³n.", + "scenes.app.popup.appsparameters.pages.public_login_label": "Identificador pΓΊblico", + "scenes.app.popup.appsparameters.pages.public_availability_application": "AplicaciΓ³n pΓΊblica", + "scenes.apps.calendar.edit_calendar_title": "Editar el calendario", + "scenes.app.popup.workspaceparameter.pages.configuration_notif": "configuraciΓ³n", + "scenes.apps.calendar.workspace": "Espacio de trabajo", + "scenes.app.popup.workspaceparameter.pages.company_identity_title": "Identidad de la empresa", + "scenes.apps.calendar.modals.event_adresse_placeholder": "DirecciΓ³n", + "scenes.apps.calendar.modals.event_description_placeholder": "DescripciΓ³n", + "scenes.apps.drive.move_text": "Mover", + "scenes.apps.calendar.no_connectors_menu_text": "No tiene ningΓΊn conector que pueda conectarse a un calendario.", + "scenes.apps.calendar.modals.description_placeholder": "DescripciΓ³n", + "scenes.app.workspacesbar.components.grp_parameters": "ConfiguraciΓ³n {{$1}}", + "scenes.apps.drive.go_trash_menu": "Ir a la papelera", + "scenes.app.popup.appsparameters.pages.url_reception_events_label": "Url de recepciΓ³n de eventos", + "scenes.app.popup.workspaceparameter.pages.name_description": "Cambiar el nombre de este espacio de trabajo", + "scenes.apps.calendar.create_calendar_title": "Crear un calendario", + "scenes.apps.calendar.modals.details_title": "Detalles", + "scenes.app.popup.workspaceparameter.pages.access_apps": "Acceda a sus aplicaciones y conectores", + "scenes.apps.drive.message_added_mutiple_files": "{{$1}} varios archivos enviados.", + "scenes.apps.drive.unconfigured_tab": "Esta pestaΓ±a aΓΊn no estΓ‘ configurada.", + "scenes.app.popup.appsparameters.pages.danger_zone_small_text": "No puedes eliminar esta aplicaciΓ³n si estΓ‘ publicada.", + "scenes.app.popup.workspaceparameter.pages.your_apps_label": "Tus solicitudes", + "scenes.apps.calendar.ics_subscription_menu": "Obtener un enlace de suscripciΓ³n a ICS", + "scenes.app.popup.workspaceparameter.pages.error_workspace_member": "Debes estar solo en el espacio de trabajo para eliminarlo. Elimina a tus colaboradores y vuelve a intentarlo.", + "scenes.app.popup.appsparameters.pages.error_app_simple_name_message": "El nombre simplificado de su aplicaciΓ³n ya es utilizado por otra aplicaciΓ³n. Por favor, cΓ‘mbielo.", + "scenes.apps.calendar.modals.modify_event_button": "Editar evento", + "scenes.apps.calendar.my_calendar": "Mi calendario", + "scenes.app.popup.workspaceparameter.pages.install_button": "Instalar", + "scenes.apps.calendar.connectors_search_menu": "Buscar conectores...", + "scenes.apps.drive.choose_folder_button": "Elija un directorio", + "scenes.apps.calendar.modals.event_title_placeholder": "TΓ­tulo", + "scenes.app.popup.workspaceparameter.pages.installed_apps_message": "Aplicaciones instaladas en otras Γ‘reas de la empresa {{$1}}", + "scenes.apps.drive.viewer.edit_with_button": "Editar con {{$1}}", + "scenes.app.popup.workspaceparameter.pages.withdraw_button": "Eliminar de este espacio de trabajo", + "scenes.app.popup.appsparameters.pages.update_button": "Actualizar", + "scenes.app.popup.appsparameters.pages.error_app_update_message": "OcurriΓ³ un error al actualizar la aplicaciΓ³n.", + "scenes.app.popup.createworkspacepage.add_subtitle": "ΒΏNecesita mΓ‘s espacio?", + "scenes.app.popup.createworkspacepage.create_new_workspace": "Crea un nuevo espacio de trabajo", + "scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description": "Establezca la frecuencia de las notificaciones por correo electrΓ³nico.", + "scenes.app.popup.userparameter.pages.private_message_content.hide": "Ocultar contenido de mensajes privados", + "scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description": "Elija un periodo durante el cual no reciba notificaciones.", + "scenes.app.popup.userparameter.pages.no_night_disturbing_label": "No molestar por la noche", + "scenes.app.popup.userparameter.pages.notif_content_label": "Contenido de notificaciones", + "scenes.app.mainview.quick_search_placeholder": "BΓΊsqueda rΓ‘pida", + "scenes.app.popup.userparameter.personnal_workspaces_title": "Tus espacios de trabajo", + "scenes.app.popup.workspaceparameter.admin_current_status": "Eres un administrador.", + "scenes.app.popup.workspaceparameter.pages.moderator_status": "Moderador del espacio de trabajo", + "scenes.app.popup.workspaceparameter.pages.all_apps_small_text": "Todas las aplicaciones", + "scenes.app.popup.workspaceparameter.pages.apps_research_title": "Buscar aplicaciones", + "scenes.app.popup.workspaceparameter.pages.apps_small_text": "Aplicaciones de este espacio de trabajo", + "scenes.app.popup.workspaceparameter.pages.back_to_search_button": "Regresar a la bΓΊsqueda", + "scenes.app.popup.workspaceparameter.pages.collaborateurs": "Usuarios", + "scenes.app.popup.workspaceparameter.pages.company_developped_apps_subtitle": "Aplicaciones desarrolladas por la empresa", + "scenes.app.popup.workspaceparameter.pages.company_name_description": "Cambiar el nombre de esta empresa", + "scenes.app.popup.workspaceparameter.pages.installed_app_information": "Instala la aplicaciΓ³n en este espacio de trabajo.", + "scenes.app.popup.workspaceparameter.pages.installed_apps_information": "Aplicaciones instaladas en este espacio de trabajo {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_subtitle": "Aplicaciones instaladas", + "scenes.app.popup.workspaceparameter.pages.invitation_error": "Se ha producido un error al invitar a los siguientes usuarios: ", + "scenes.app.popup.workspaceparameter.pages.invited_guest_check_message": "Compruebe que el nombre de usuario o el correo electrΓ³nico utilizado es vΓ‘lido.", + "scenes.app.popup.workspaceparameter.pages.name_label": "Nombre del espacio de trabajo", + "scenes.app.popup.workspaceparameter.pages.no_access": "Sin acceso.", + "scenes.app.popup.workspaceparameter.pages.research_by": "Buscar aplicaciones por nombre y categorΓ­as", + "scenes.app.popup.workspaceparameter.pages.show_button": "Mostrar", + "scenes.app.popup.workspaceparameter.pages.title": "ConfiguraciΓ³n del espacio de trabajo", + "scenes.app.popup.workspaceparameter.pages.webhooks_access_subtitle": "Acceso a los webhooks", + "scenes.app.popup.workspaceparameter.pages.weight_max_small_text": "TamaΓ±o mΓ‘ximo 5 MB.", + "scenes.app.popup.workspaceparameter.pages.worspace_notif": "espacio de trabajo", + "scenes.app.popup.workspaceparameter.pages.write_access_subtitle": "Acceso de escritura", + "scenes.app.popup.workspaceparameter.payments_subscriptions_title": "Pagos y suscripciones", + "scenes.app.workspacesbar.components.change_company_title": "Cambiar de empresa", + "scenes.app.workspacesbar.components.create_company_menu": "Crear una empresa", + "scenes.apps.calendar.add_calendar_menu": "Agregar un calendario", + "scenes.apps.calendar.connectors_menu": "Conectores...", + "scenes.apps.calendar.day_option": "DΓ­a", + "scenes.apps.calendar.export_title": "Exportar", + "scenes.apps.calendar.export_view_menu": "Exportar la vista...", + "scenes.apps.calendar.ics_download_menu": "Descarga un archivo ICS", + "scenes.apps.calendar.modals.part.participants": "Participantes", + "scenes.apps.calendar.modals.participants_event": "Participantes", + "scenes.apps.calendar.modals.reminders": "Recordatorios", + "scenes.apps.calendar.modals.remove_button": "Eliminar", + "scenes.apps.calendar.modals.remove_event_button": "Eliminar evento", + "scenes.apps.calendar.modals.remove_event_text": "ΒΏEliminar el evento?", + "scenes.apps.calendar.modify_calendar_menu": "Editar el calendario", + "scenes.apps.calendar.no_calendar_text": "No ha establecido ningΓΊn calendario para este espacio de trabajo.", + "scenes.apps.calendar.remove_calendar_confirmation": "ΒΏEliminar el calendario y sus eventos de forma permanente?", + "scenes.apps.drive.message_added_file_no_name": "{{$1}} enviΓ³ un archivo.", + "scenes.apps.drive.choose_file_button": "Selecciona un archivo", + "scenes.apps.drive.create_folder_button": "Crear", + "scenes.apps.drive.download_button": "Descargar", + "scenes.apps.drive.open_link": "Abrir enlace en ventana nueva", + "scenes.apps.drive.files_subtitle": "Archivos", + "scenes.apps.drive.folder_subtitle": "Carpetas", + "scenes.apps.drive.go_out_trash_menu": "Dejar la papelera", + "scenes.apps.drive.import_from_computer_menu": "Subir desde la computadora", + "scenes.apps.drive.new_file_menu": "Archivo nuevo", + "scenes.apps.drive.new_external_storage": "Nuevo almacenamiento externo", + "scenes.apps.drive.new_folder_title": "Carpeta nueva", + "scenes.apps.drive.no_file_alert": "No tiene aplicaciones que le permitan crear un archivo.", + "scenes.apps.drive.no_storage_app_alert": "No tiene aplicaciones que le permitan agregar almacenamiento externo.", + "scenes.apps.drive.restore_menu": "Restaurar", + "scenes.apps.drive.throw_menu": "Enviar a la papelera", + "scenes.apps.drive.trash_empty_menu": "Vaciar la papelera", + "scenes.app.popup.appsparameters.pages.status_tilte": "Estado", + "scenes.app.popup.appsparameters.pages.title_tester": "Realizador de pruebas de cΓ³digo Twake", + "scenes.app.popup.appsparameters.pages.remove_app_button": "Eliminar aplicaciΓ³n", + "scenes.app.popup.createworkspacepage.placeholder_name": "Nombre del espacio de trabajo", + "scenes.app.popup.userparameter.pages.frequency_notif_configuration_description": "Establece la frecuencia de las notificaciones del mΓ³vil.", + "scenes.app.popup.userparameter.pages.frequency_notif_subtitle": "Frecuencia de las notificaciones", + "scenes.app.popup.userparameter.pages.keywords_notif_description": "Resalte las siguientes palabras clave:", + "scenes.app.popup.userparameter.pages.private_message_content.show": "Mostrar el contenido de los mensajes privados", + "scenes.app.popup.workspaceparameter.admin_manager_current_status": "Eres administrador del espacio de trabajo.", + "scenes.app.popup.workspaceparameter.manager_current_status": "Eres un administrador de la empresa.", + "scenes.app.popup.workspaceparameter.pages.alert_impossible_removing": "No puede abandonar el espacio de trabajo, porque es el ΓΊltimo administrador. Puede definir un nuevo administrador o eliminar/archivar este espacio de trabajo.", + "scenes.app.popup.workspaceparameter.pages.company_name_label": "Nombre de la empresa", + "scenes.app.popup.workspaceparameter.pages.description": "DescripciΓ³n", + "scenes.app.popup.workspaceparameter.pages.logo_modify_description": "Edita la imagen de este espacio de trabajo", + "scenes.app.popup.workspaceparameter.pages.logo_subtitle": "Logo", + "scenes.app.popup.workspaceparameter.pages.apps_company_small_text": "Aplicaciones de su empresa", + "scenes.apps.calendar.modals.title_placeholder": "TΓ­tulo", + "scenes.app.popup.workspaceparameter.pages.apps_connectors_title": "Integraciones", + "scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button": "Invitar usuarios", + "scenes.app.popup.workspaceparameter.pages.researching_apps_button": "Buscar aplicaciones...", + "scenes.app.popup.workspaceparameter.pages.configure_button": "Configurar", + "scenes.app.popup.workspaceparameter.pages.developped_apps_small_text": "Aplicaciones desarrolladas por la empresa", + "scenes.app.popup.workspaceparameter.pages.displayed_preferencies_subtitle": "Mostrar preferencias", + "scenes.app.popup.workspaceparameter.pages.quit_workspace_menu": "Salir de este espacio de trabajo", + "scenes.app.popup.workspaceparameter.pages.read_access_subtitle": "Acceso de lectura", + "scenes.app.popup.workspaceparameter.pages.no_app_information": "No tienes aplicaciones en este espacio de trabajo", + "scenes.app.popup.workspaceparameter.pages.remove_from_company_text": "Eliminar de toda la empresa", + "scenes.apps.calendar.modals.advanced_options": "Opciones avanzadas", + "scenes.apps.calendar.my_calendar_label": "Mi calendario", + "scenes.apps.calendar.my_calendar_menu": "Mi calendario", + "scenes.apps.calendar.month_option": "Mes", + "scenes.apps.calendar.today_menu": "Hoy", + "scenes.apps.calendar.week_option": "Semana", + "scenes.apps.calendar.workspace_label": "Este espacio de trabajo", + "scenes.apps.calendar.workspace_menu": "Espacio de trabajo", + "scenes.apps.drive.add_button": "Agregar", + "scenes.apps.drive.message_added_file": "{{$1}} enviΓ³ {{$2}}.", + "scenes.apps.drive.new_file_title": "Archivo nuevo", + "scenes.apps.drive.remove_definitely_menu": "Eliminar permanentemente", + "scenes.apps.drive.viewer.loading_preview_message": "Cargando...", + "scenes.apps.drive.viewer.no_preview_message": "No puede ver este tipo de archivo.", + "scenes.apps.drive.viewer.open_with_button": "Abrir con...", + "scenes.apps.messages.input.placeholder": "Escribe un mensaje. Utilice @ para citar a un usuario.", + "application.load.longer": "El servidor tarda mΓ‘s de lo previsto en responder, por favor espere o recargue la pΓ‘gina...", + "scenes.apps.board.display_as": "Mostrar como", + "components.channelworkspacelist.title": "Canales", + "components.reminder.notification": "NotificaciΓ³n", + "scenes.apps.drive.move_text2": "Mover", + "scenes.apps.account.message_user_signin": "Su usuario puede iniciar sesiΓ³n en cualquier momento con este mismo correo electrΓ³nico y cambiar la cuenta temporal a una cuenta normal.", + "services.apps.calendar.deadline_icon": "Fecha lΓ­mite", + "components.searchpopup.sender": "Remitente", + "scenes.apps.messages.message.modify_button": "Editar", + "components.leftbar.channel.workspaceschannels.menu.option_1": "Crear un canal", + "components.add_mails_workspace.text_area_placeholder": "Ingresa los correos electrΓ³nicos de tus usuarios *", + "general.more": "MΓ‘s", + "components.drive.moove_here": "Mover aquΓ­", + "scenes.app.popup.appsparameters.pages.title_informations": "InformaciΓ³n bΓ‘sica", + "scenes.apps.messages.input.emoji": "Emoji", + "components.account_verification_status_sentence": "El estado de su cuenta es: {{$1}}", + "scenes.apps.drive.viewer.download_desktop": "Descargar Twake Desktop para obtener una vista previa en la aplicaciΓ³n", + "components.workspace.calendar.invalid": "InvΓ‘lido", + "scenes.apps.calendar.reminders": "recordatorio (s)", + "components.drive.elements.see": "Ver", + "scenes.apps.messages.message.show_responses_button": "Ver todas las respuestas", + "components.verify_mail.title_2": "Β‘Ahora eres un usuario oficial de Twake!", + "components.searchpopup.update_search": "Actualizar la bΓΊsqueda", + "components.newversion.new_version_modal.title": "Β‘Nueva actualizaciΓ³n disponible!", + "components.searchpopup.enter_text": "Ingresa algΓΊn texto para buscar en Twake.", + "scenes.apps.messages.messageslist.go_last_message_button": "Ir al ΓΊltimo mensaje", + "scenes.apps.messages.messageslist.go_last_message_button.new_messages": "Mensajes nuevos", + "scenes.apps.calendar.unconfigured_tab": "Esta pestaΓ±a aΓΊn no estΓ‘ configurada.", + "services.user.update_password_alert": "Su contraseΓ±a ha sido actualizada.", + "components.searchpopup.mentions": "Menciones", + "scenes.client.channels_bar.modals.guest_management.input_placeholder": "Buscar invitados o correos electrΓ³nicos pendientes", + "scenes.login.verifymail.alert": "Estamos revisando su correo electrΓ³nico.", + "services.console_services.toaster.add_email_error_message": "Error al agregar {{$1}}", + "scenes.app.channelsbar.hide_discussion_leaving.menu": "Ocultar discusiΓ³n", + "components.reminder.by_email": "Correo electrΓ³nico", + "components.drive.right_preview.suppress_link": "Suprimir el enlace", + "scenes.apps.board.kanban": "Kanban", + "scenes.apps.tasks.board.ends": "Se harΓ‘ para el", + "scenes.apps.messages.message.save_button": "Guardar", + "scenes.apps.tasks.board.tasks.use_starttime": "Utilizar la hora de inicio", + "components.input.copied": "Copiado", + "components.unverified_account.verification_details": "Hemos enviado los datos de verificaciΓ³n a", + "scenes.apps.messages.message.pin_button": "Anclar mensaje", + "components.searchpopup.show_filters": "mostrar filtros", + "scenes.apps.messages.input.show_formatting": "Mostrar formato", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_edition": "Cambiar el nombre {{$1}}", + "scenes.client.channels_bar.modals.guest_management.title": "Administrar invitados en {{$1}}", + "scenes.app.popup.appsparameters.pages.smalltext_group_id": "ID del grupo actual", + "scenes.app.popup.appsparameters.pages.website_label": "Sitio web", + "components.verify_mail.text": "En primer lugar, tienes que verificar tu direcciΓ³n de correo electrΓ³nico. Hemos enviado un enlace de verificaciΓ³n a", + "components.searchpopup.tasks": "Tareas", + "scenes.login.verifymail.success": "Β‘Su correo electrΓ³nico ha sido verificado con Γ©xito!", + "scenes.apps.tasks.no_connector": "Sin conector", + "components.reminder.minutes_bef": "minutos antes", + "general.verify": "Verifica", + "services.console_services.toaster.success_invite_emails": "Se han aΓ±adido con Γ©xito los usuarios {{$1}}", + "general.re_send": "Reenviar", + "scenes.app.popup.appsparameters.pages.string_information": "Esta cadena identifica su aplicaciΓ³n y se utilizarΓ‘ en los comandos de los mensajes.", + "scenes.app.popup.appsparameters.pages.waiting_availability_application": "Esperando...", + "scenes.app.popup.appsparameters.pages.write_privileges_label": "Privilegios de escritura", + "scenes.apps.messages.input.edited": "Editado", + "scenes.apps.messages.just_you": "Visible solo para ti", + "scenes.apps.messages.message.new_messages_bar": "Mensajes nuevos", + "scenes.apps.messages.message.cancel_button": "Cancelar", + "scenes.apps.messages.message.unpin_button": "Desanclar mensaje", + "scenes.apps.messages.message.copy_link": "Copiar enlace al mensaje", + "scenes.apps.messages.message.pinned": "Fijado", + "scenes.apps.messages.message.remove_button": "Eliminar", + "scenes.apps.messages.message.reply_button": "Contestar", + "scenes.apps.messages.message.show_button": "Mostrar", + "scenes.apps.messages.message.types.first_channel_message_text": "Este es el primer mensaje del canal", + "scenes.apps.messages.message.types.first_message_text": "Este es el primer mensaje", + "scenes.apps.messages.messageslist.get_writing_user": "estΓ‘ escribiendo...", + "scenes.apps.drive.trash": "Papelera", + "scenes.apps.drive.top_menu_more": "MΓ‘s", + "scenes.apps.drive.top_menu_no_items": "{{$1}} artΓ­culos", + "scenes.apps.messages.new_thread": "Inicio una discusiΓ³n nueva", + "scenes.apps.messages.input.send_message": "Enviar mensaje", + "scenes.apps.messages.input.hide_formatting": "Ocultar formato", + "scenes.tell_us": "Por favor, dΓ­ganos lo que estaba haciendo en:", + "scenes.apps.tasks.my_tasks": "Mis tareas", + "scenes.apps.tasks.board.place_holder": "Nombre de la junta directiva", + "scenes.apps.tasks.board.tasks.subtask": "Subtarea", + "scenes.apps.tasks.board.tasks.add_subtask": "Agregar una subtarea", + "scenes.apps.tasks.board.tasks.use_deadline": "Utilizar la fecha lΓ­mite", + "scenes.apps.tasks.board.tasks.in_list": "En la lista", + "scenes.apps.tasks.board.starts": "Inicia el", + "scenes.apps.tasks.board.list_name": "Nombre de la lista", + "scenes.app.popup.sync_calendar": "Sincroniza tus calendarios.", + "scenes.apps.parameters.workspace_sections.workspace.logo_company": "Logo de la empresa", + "scenes.app.popup.workspaceparameter.pages.logo_company_modify_description": "Editar la imagen de la empresa ", + "scenes.app.popup.workspaceparameter.pages.cancel_invitation": "Cancelar la invitaciΓ³n", + "scenes.apps.account.account.fullname": "Nombre completo", + "login.email_login": "Correo electrΓ³nico/Inicio de sesiΓ³n", + "scenes.apps.account.account.password_for_user": "ContraseΓ±a para su usuario", + "scenes.apps.account.account.send_info": "EnvΓ­e esta informaciΓ³n de credencial a su usuario.", + "scenes.apps.account.account.save": "Guardar cuenta", + "scenes.app.mainview.link_expired": "Este enlace pΓΊblico no es vΓ‘lido o ha caducado.", + "scenes.app.mainview.create_account": "Crea tu espacio de trabajo de forma gratuita en ", + "scenes.apps.calendar.modals.reminder_add": "Agregar un recordatorio", + "scenes.apps.parameters.workspace_sections.members.invite_all": "Invitar a todos", + "scenes.app.taskpicker.select": "Selecciona", + "components.listmanager.filter": "Filtrar", + "components.attachmentpicker.add_attachment": "Agregar archivos adjuntos", + "components.drive.new_versions": "Agregar una nueva versiΓ³n", + "components.drive.navigators.directory_not_found": "Directorio no encontrado.", + "components.workspace.list_manager.no_workspace": "No hay espacio de trabajo", + "components.searchpopup.loading": "Cargando mΓ‘s resultados", + "components.searchpopup.only_pinned": "SΓ³lo los mensajes anclados", + "components.alert.confirm": "Confirme su acciΓ³n", + "components.alert.confirm_click": "Confirme su acciΓ³n haciendo clic en OK.", + "scenes.apps.board.active_tasks": "Tareas activas", + "scenes.apps.board.new_task": "+ Tarea nueva", + "scenes.apps.board.all_boards": "Todos los tableros", + "components.userlistmanager.no_users": "Sin usuarios.", + "scenes.apps.drive.used": "utilizados en esta carpeta", + "components.reminder.hours_bef": "horas antes", + "components.reminder.days_bef": "dΓ­as antes", + "components.reminder.weeks_bef": "semanas antes", + "scenes.apps.calendar.video_link": "Haga clic para abrir el enlace", + "scenes.app.mainview.discussion": "DiscusiΓ³n", + "components.tagpicker.notag": "Sin etiqueta", + "scenes.apps.tasks.modals.attachments": "Archivos adjuntos", + "components.calendar.calendarselector.from": "De", + "components.attachmentpicker.from_computer": "Desde su dispositivo", + "components.attachmentpicker.from_twake": "De los documentos de Twake", + "components.attachmentpicker.file": "Archivo", + "components.attachmentpicker.remove_attach": "Eliminar archivo adjunto", + "scenes.apps.drive.remove_attachs": "Eliminar archivos adjuntos", + "components.drive.elements.current_name": "Nombre actual: ", + "components.connectorslistmanager.add_connectors": "Agregar conectores", + "components.notifications.hidden_notifications_button.children": "Mensajes nuevos", + "scenes.client.mainview.tabs.tabstemplateeditor.select_placeholder": "AplicaciΓ³n", + "scenes.client.channelbar.channelmemberslist.no_members": "No hay ningΓΊn usuario en este canal, puede invitarlos haciendo clic en Agregar usuarios.", + "scenes.app.popup.adduserfromtwakeconsole.current_users_state": "Se agregarΓ‘n correos electrΓ³nicos {{$1}}", + "components.newversion.new_version_component.row.part_1": "EstΓ‘ ejecutando una versiΓ³n obsoleta de Twake", + "components.newversion.new_version_component.row.part_2": "Β‘Te sugerimos que vuelvas a cargar la aplicaciΓ³n y disfrutes de nuestras nuevas funciones!", + "components.newversion.new_version_component.link": "Haga clic aquΓ­ para recargar", + "scenes.apps.drive.download_all_button": "Descargar todo", + "components.inputs.input_with_select.input.placeholder": "Nombre del Canal", + "components.inputs.input_with_select.select.placeholder": "Nombre de la secciΓ³n", + "components.inputs.input_with_select.select.no_sections": "Comienza a escribir el nombre de tu primera secciΓ³n del canal.", + "components.inputs.input_with_select.button.tooltip": "Establece una secciΓ³n de canal", + "scenes.apps.messages.message.activity_message.a_added_b_to_the_channel": "{{$1}} ha aΓ±adido a {{$2}} al canal", + "scenes.apps.messages.message.activity_message.a_removed_b_from_the_channel": "{{$1}} eliminΓ³ a {{$2}} del canal", + "scenes.apps.messages.message.activity_message.a_updated_channel_description": "{{$1}} cambiΓ³ la descripciΓ³n", + "scenes.apps.messages.message.activity_message.a_updated_channel_name": "{{$1}} cambiΓ³ el nombre del canal a {{$2}}", + "scenes.apps.messages.message.activity_message.a_created_channel_tab": "{{$1}} agregΓ³ una nueva pestaΓ±a {{$2}} {{$3}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_tab": "{{$1}} eliminΓ³ la pestaΓ±a {{$2}} {{$3}}", + "scenes.apps.messages.message.activity_message.a_created_channel_connector": "{{$1}} agregΓ³ un conector nuevo {{$2}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_connector": "{{$1}} ha retirado un conector {{$2}}", + "scenes.client.channelbar.channelmemberslist.tag": "TΓΊ", + "components.alert.leave_private_channel.title": "ΒΏEstΓ‘s seguro de que quieres dejar el canal?", + "components.alert.leave_private_channel.description": "No podrΓ‘s volver a unirte a este canal privado a menos que alguien te invite.", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.tag": "No eres un miembro", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.loader": "Cargar mΓ‘s", + "components.verify_mail.title_1": "Felicidades", + "components.verify_mail.button": "Agregar usuario", + "components.verify_mail.paragraph": "Puedes hacerlo despuΓ©s si quieres, pero las cuentas no verificadas sΓ³lo tienen acceso a una versiΓ³n limitada de Twake", + "services.console_services.toaster.add_emails_error": "Error al agregar correos electrΓ³nicos", + "services.console_services.toaster.success_verify_email": "Se ha enviado un enlace de verificaciΓ³n a su cuenta de correo electrΓ³nico.", + "scenes.app.popup.workspaceparameter.edit_from_console": "Ver en la consola", + "scenes.apps.messages.messageslist.get_writing_users": "estΓ‘n escribiendo...", + "scenes.login.verifymail.error_message": "OcurriΓ³ un error", + "scenes.login.verifymail.signin_button": "Iniciar sesiΓ³n", + "scenes.error_on_twake": "\"Houston, tenemos un problema\"", + "scenes.help_us": "Sin embargo, si quieres ayudarnos a solucionar este error, envΓ­anos un mensaje a continuaciΓ³n: ", + "scenes.login.verifymail.verification_waiting": "Esperando verificaciΓ³n ...", + "scenes.no_panic": "Β‘Que no cunda el pΓ‘nico! Simplemente vuelva a cargar esta pΓ‘gina para arreglar Twake.", + "services.apps.calendar.move_icon": "Mover", + "scenes.app.workspaces.components.skip": "Saltar", + "services.apps.messages.no_command_possible": "No podemos ejecutar el comando '{{$1}}' porque '{{$2}}' no existe o no permite crear comandos.", + "services.apps.calendar.event_icon": "Evento", + "services.apps.calendar.reminder_icon": "Recordatorio", + "services.apps.messages.no_app": "Esta aplicaciΓ³n no existe.", + "services.user.notification_parameters_update_alert": "Se ha actualizado la configuraciΓ³n de las notificaciones.", + "scenes.apps.account.message_temporary": "Una cuenta temporal funciona como una cuenta normal de Twake, pero puedes crear la contraseΓ±a y restablecerla si es necesario.", + "components.drive.modify_uslist": "Modificar la lista de usuarios", + "components.upload.drop_files": "Suelta tus archivos aquΓ­", + "components.workspace.list_manager.add": "Agregar espacios de trabajo", + "components.workspace.list_manager.current_space": "Espacio de trabajo actual", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_creation": "Crear una pestaΓ±a nueva", + "scenes.app.mainview.advanced_search_placeholder": "BΓΊsqueda avanzada", + "components.drive.right_preview.create_link": "Crear un enlace de acceso", + "components.tagpicker.tag_name": "Nombre de la etiqueta", + "components.searchpopup.load_more": "Cargar mΓ‘s resultados", + "components.workspace.list_manager.current_company": "Empresa actual", + "components.workspace.list_manager.all": "Todo", + "components.searchpopup.filter_ws": "Filtrar espacios de trabajo", + "components.searchpopup.size": "TamaΓ±o", + "components.searchpopup.hide_filters": "ocultar filtros", + "components.searchpopup.tags": "Etiquetas", + "components.searchpopup.creation": "CreaciΓ³n", + "components.searchpopup.last_modif": "Última modificaciΓ³n", + "scenes.apps.board.archived_tasks": "Tareas archivadas ({{$1}})", + "scenes.app.popup.workspace.create_temp": "Crear una cuenta temporal", + "scenes.app.popup.appsparameters.pages.apps_connectors_small_text": "Administre sus aplicaciones y conectores.", + "scenes.app.popup.appsparameters.pages.smalltext_workspace_id": "ID del espacio de trabajo actual", + "scenes.client.channelbar.channeltemplateeditor.checkbox": "Invite automΓ‘ticamente a todos los usuarios del espacio de trabajo a este canal", + "scenes.client.channelbar.channelmemberslist.menu.option_2": "Eliminar del canal", + "components.drive.elements.configurate_mod": "Configurar el mod...", + "components.drive.elements.manage_version": "Administrar versiones", + "scenes.client.channelbar.workspacechannellist.autocomplete": "Buscar canal, usuario o mensajes directos", + "scenes.apps.drive.right_preview.public": "Acceso pΓΊblico", + "scenes.app.popup.createcompany.try_again": "Por favor, intΓ©ntalo de nuevo.", + "scenes.app.popup.workspace.edit_temp": "Editar la cuenta temporal", + "scenes.apps.drive.right_preview.versions": "Versiones", + "scenes.client.channelbar.channelmemberslist.title": "Usuarios en {{$1}}", + "scenes.client.channelbar.channelmemberslist.loader": "Cargar mΓ‘s", + "scenes.client.channelbar.channelmemberslist.autocomplete": "Buscar usuario", + "components.leftbar.channel.workspaceschannels.menu.option_2": "Unirse a un canal", + "scenes.apps.tasks.active_tasks": "Tareas activas", + "scenes.app.popup.appsparameters.pages.subtitle_informations": "InformaciΓ³n relacionada con la gestiΓ³n de aplicaciones", + "scenes.app.popup.appsparameters.pages.smalltext_user_id": "ID de usuario actual", + "scenes.app.mainview.channel_description": "Describe el canal", + "components.unverified_account.typography_text_danger": "Quedan {{$1}} dΓ­as de prueba. La cuenta de prueba se bloquearΓ‘ despuΓ©s de 7 dΓ­as y se eliminarΓ‘ permanentemente despuΓ©s de 1 mes de registro. Puedes verificar tu cuenta haciendo clic en el botΓ³n \"Verificar mi cuenta\" del correo electrΓ³nico de verificaciΓ³n que te hemos enviado.", + "components.account_verication_status_blocked": "Bloqueado", + "components.unverified_account.re_send_email": "ΒΏNo recibiΓ³ el correo electrΓ³nico?", + "components.account_verication_status_unverified": "Sin verificar", + "components.blocked_account.trial_period_over": "Su perΓ­odo de prueba ha terminado. Para desbloquear su cuenta y tener acceso a todas las funcionalidades, por favor verifique su cuenta a travΓ©s del correo electrΓ³nico de confirmaciΓ³n", + "components.add_mails_workspace.button": "Empiece a usar Twake", + "components.add_mails_workspace.title_1": "AΓ±ade algunos usuarios", + "components.add_mails_workspace.title_2": "Twake es una herramienta de colaboraciΓ³n en equipo, asΓ­ que invita a algunos usuarios a probar el espacio de trabajo que hemos creado para ti.", + "general.uploading": "Subiendo", + "components.on_boarding.popups.blocked_company.or": "O", + "components.on_boarding.popups.blocked_company.company_subscription_plan_button": "Haga clic aquΓ­", + "components.on_boarding.company_billing_banner.link": "plan de suscripciΓ³n de la empresa", + "components.emoji_picker.categories.search_result": "Resultados de la bΓΊsqueda", + "components.emoji_picker.categories.not_found": "No se ha encontrado ningΓΊn emoji", + "components.richtexteditor.toolbar.bold": "Negrita", + "components.on_boarding.popups.blocked_company.description": "Su suscripciΓ³n a Twake ha expirado. Β‘Por favor, pΓ³ngase en contacto con el propietario o administrador de su empresa para renovarla y poder volver a comunicarse con su equipo!", + "components.emoji_picker.categories.symbols": "SΓ­mbolos", + "general.user.role.company.guest": "Invitado", + "components.locked_features.locked_history_banner.button": "MΓ‘s informaciΓ³n", + "scenes.apps.drive.new_link_title": "Nuevo enlace", + "components.locked_features.locked_history_banner.title": "Acabas de alcanzar el lΓ­mite de mensajes", + "components.locked_features.locked_guests_popup.or": "O", + "components.locked_features.locked_guests_popup.subtitle": "Esta caracterΓ­stica no estΓ‘ disponible en la versiΓ³n gratuita de Twake", + "scenes.client.channels_bar.modals.parts.channel_member_row.label.pending_email": "Correo enviado", + "components.richtexteditor.toolbar.underline": "Subrayado", + "components.richtexteditor.toolbar.italic": "Cursiva", + "components.richtexteditor.toolbar.code": "CΓ³digo", + "components.richtexteditor.toolbar.unordered-list": "Lista con viΓ±etas", + "components.richtexteditor.toolbar.ordered-list": "Lista ordenada", + "general.resume": "Reanudar", + "scenes.client.channels_bar.modals.guest_management.tips": "Empieza a aΓ±adir o buscar correos electrΓ³nicos utilizando la entrada de arriba", + "general.user.role.company.admin": "Administrador de la empresa", + "general.user.role.company.member": "Miembro", + "general.user.deleted": "Cuenta eliminada", + "components.richtexteditor.toolbar.strikethrough": "Tachado", + "components.richtexteditor.toolbar.blockquote": "Cita en bloque", + "components.richtexteditor.toolbar.code-block": "Bloque de cΓ³digo", + "components.locked_features.locked_history_banner.description": "Β‘Su empresa tiene muchos mensajes! Actualice ahora para acceder a todo su historial de mensajes.", + "components.locked_features.locked_guests_popup.title": "La funciΓ³n de invitados estΓ‘ bloqueada", + "components.locked_features.locked_guests_popup.description": "Β‘Ups! Parece que quieres invitar a usuarios externos a tu espacio de trabajo. Es posible que desee considerar la actualizaciΓ³n de su plan si desea colaborar con invitados y socios externos. Explora nuestras opciones de precios y selecciona la mejor opciΓ³n para tus necesidades de colaboraciΓ³n en equipo.", + "components.on_boarding.popups.blocked_company.company_selector": "Cambiar a otra empresa", + "scenes.apps.tasks.select_user_button": "Ver las tareas de otro usuario", + "scenes.apps.tasks.select_user": "Buscar usuario", + "scenes.apps.messages.input.attach_file.from_computer": "Desde el ordenador", + "scenes.app.popup.workspaceparameter.pages.table_title": "Nombre", + "scenes.apps.drive.default_link_name": "Sin tΓ­tulo", + "components.emoji_picker.input_search_placeholder": "Buscar", + "services.apps.messages.message_editor_service.upload_error_toaster": "{{$1}} - No puedes aΓ±adir mΓ‘s de {{$2}} archivos en un mensaje", + "components.locked_features.locked_guests_popup.learn_more_button": "MΓ‘s informaciΓ³n", + "components.locked_features.locked_guests_popup.skip_for_now_button": "Saltar por ahora", + "components.on_boarding.company_billing_banner.admin_or_owner_text": "Hay un problema con la suscripciΓ³n de su empresa. Por favor, eche un vistazo a su", + "components.on_boarding.company_billing_banner.guest_or_member_text": "Hay un problema con la suscripciΓ³n de su empresa. Β‘PΓ³ngase en contacto con el propietario o el administrador de la empresa!", + "components.on_boarding.popups.blocked_company.title": "Su empresa estΓ‘ bloqueada debido a un problema de pago", + "components.on_boarding.popups.blocked_company.learn_more_text": "ΒΏQuiere saber mΓ‘s sobre el plan de suscripciΓ³n de las empresas?", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_link": "Crear un canal privado", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_text": " en cambio", + "components.emoji_picker.categories.objects": "Objetos", + "components.emoji_picker.categories.flags": "Banderas", + "scenes.apps.messages.message.parts.deleted_content.text.current_user": "Has borrado este mensaje", + "scenes.apps.messages.message.parts.deleted_content.text": "{{$1}} borrΓ³ su mensaje", + "components.member.user_parts.and_more_user_text": " y {{$1}} mΓ‘s usuarios", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_input_placeholder": "No puedes aΓ±adir mΓ‘s de 10 usuarios", + "components.upload.drop_files.toaster.error": "No puedes subir mΓ‘s de {{$1}} archivos", + "components.emoji_picker.categories.frequently_used": "Usado frecuentemente", + "components.emoji_picker.categories.food_and_drink": "AlimentaciΓ³n y Bebidas", + "components.emoji_picker.categories.animals_and_nature": "Animales y Naturaleza", + "components.emoji_picker.categories.smileys_and_people": "Smileys y Personas", + "components.emoji_picker.categories.travel_and_places": "Viajes y Lugares", + "scenes.app.popup.workspaceparameter.pages.workspace_partner_tabs.members.table.tags": "Rol", + "general.email": "Correo electrΓ³nico", + "scenes.app.integrations_parameters.title": "Integraciones", + "scenes.app.integrations_parameters.applications_table.name": "Nombre", + "scenes.app.integrations_parameters.applications_table.title": "Otras integraciones", + "scenes.app.integrations_parameters.applications_table.search_placeholder": "AplicaciΓ³n de bΓΊsqueda", + "scenes.app.integrations_parameters.company_application_popup.tag": "Instalado", + "scenes.app.integrations_parameters.company_application_popup.btn": "Instalar", + "scenes.app.integrations_parameters.company_application_popup.tab_btn_info": "Informaciones", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.description_item": "DescripciΓ³n", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.website_item": "Sitio web", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.created_item": "Fecha de creaciΓ³n", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.version_item": "VersiΓ³n", + "scenes.app.integrations_parameters.company_applications_table.more_menu.show_application": "Mostrar", + "scenes.app.integrations_parameters.company_applications_table.more_menu.remove_application": "Eliminar de la empresa", + "scenes.app.integrations_parameters.company_applications_table.name": "Nombre", + "scenes.app.integrations_parameters.company_applications_table.title": "Instalado en su empresa", + "app.state.recoil.hooks.use_current_company_applications.toaster_delete": "{{$1}} eliminado correctamente de su empresa", + "app.state.recoil.hooks.use_current_company_applications.toaster_add": "{{$1}} instalado correctamente en su empresa", + "components.emoji_picker.categories.activity": "Actividad", + "scenes.client.main_view.main_header.search_input": "Buscar", + "general.pause": "Pausa", + "scenes.apps.messages.input.replied_to": "respondiΓ³ a ", + "components.rich_text_editor.plugins.suggestions.default_message.display_results": "Escriba al menos tres letras para mostrar los usuarios", + "components.rich_text_editor.plugins.suggestions.default_message.no_user_found": "No se han encontrado usuarios", + "components.rich_text_editor.plugins.suggestions.default_message.no_emoji_found": "No se han encontrado emojis", + "components.rich_text_editor.plugins.suggestions.default_message.no_command_found": "No se han encontrado comandos", + "scenes.app.popup.adduser.magiclinks.copied_to_clipboard": "Copiado correctamente al portapapeles", + "scenes.app.popup.adduser.magiclinks.action_copy": "Dupdo", + "scenes.app.popup.adduser.magiclinks.action_generate": "Generar", + "scenes.join.login_first_button": "Inicie sesiΓ³n o cree una cuenta primero", + "scenes.join.join_the_team_button": "Únete al equipo", + "scenes.app.popup.adduser.magiclinks.genrator_info": "Enlace de invitaciΓ³n al espacio de trabajo", + "scenes.app.popup.adduser.magiclinks.new_link_generated": "Nuevo enlace generado", + "scenes.join.loading": "Cargando…", + "scenes.join.wrong_link_title": "Este enlace ya no estΓ‘ disponible.", + "scenes.join.wrong_link_description": "PΓ­dale a la persona que lo invitΓ³ a unirse a esta empresa un nuevo enlace o cree su propia empresa", + "scenes.join.create_the_company_button": "Crea la empresa", + "scenes.join.join_workspace_from_company": "‘Únase a {{$1}} desde {{$2}}!", + "scenes.join.twake_description": "Twake es un espacio de trabajo digital de cΓ³digo abierto creado para mejorar la productividad de su equipo", + "scenes.app.channelsbar.currentuser.company_messages_counter_header": "NΓΊmero de mensajes", + "scenes.app.channelsbar.currentuser.company_messages_counter_info": "En la versiΓ³n gratuita de Twake, no puede acceder a mΓ‘s mensajes que {{$1}} mΓ‘s recientes.", + "scenes.app.channelsbar.currentuser.company_messages_counter_link": "Mostrar mΓ‘s planes", + "scenes.app.messages.input.parts.is_writing.message.user_is_writing": "{{$1}} estΓ‘ escribiendo...", + "scenes.app.messages.input.parts.is_writing.message.users_are_writing": "{{$1}} y {{$2}} estΓ‘n escribiendo...", + "scenes.app.messages.input.parts.is_writing.message.users_and_more_are_writing": "{{$1}}, {{$2}} y {{$3}} usuarios mΓ‘s estΓ‘n escribiendo...", + "scenes.apps.messages.message.types.no_message_in_thread": "Nadie respondiΓ³ todavΓ­a.", + "login.login_error": "Error durante el inicio de sesiΓ³n", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.label": "Espacio de trabajo predeterminado", + "login.create_account": "Crear una cuenta", + "'": "'", + "scenes.app.workspaces.welcome_page.no_workspace_subtitle": "Nadie te ha invitado a un espacio de trabajo todavΓ­a.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.description": "Invite automΓ‘ticamente a todos los usuarios del espacio de trabajo a este canal", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.title": "EstΓ‘s a punto de eliminar {{$1}}", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.alert_total_members": "AΓΊn tienes {{$1}} miembros en {{$2}}. Debe eliminar todos los miembros para poder eliminar este espacio de trabajo.", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.checkbox": "Entiendo que se eliminarΓ‘n todos los mensajes y archivos de mi espacio de trabajo.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.max_size": "El tamaΓ±o mΓ‘ximo del logotipo es de 5 MB", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.bad_format": "Formato incorrecto, solo se permiten png gif y jpg", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.unknown": "Error desconocido", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.prefix": "Error", + "scenes.app.channelsbar.currentuser.reset": "Reiniciar", + "components.locked_features_components.locked_invite_alert.message_part_1": "Su empresa ha alcanzado el nΓΊmero mΓ‘ximo de {{$1}} miembros. Por favor, ", + "components.locked_features_components.locked_invite_alert.message_link": "actualice su empresa", + "components.locked_features_components.locked_invite_alert.message_part_2": " para invitar a mΓ‘s miembros.", + "components.locked_features_components.locked_invite_alert.message_magic_link": " entre en contacto con el propietario o administrador de su empresa.", + "views.client.popup.workspace_parameter.pages.workspace_members.link_to_console": "Ver todos los miembros de mi empresa en la consola", + "scenes.app.popup.appsparameters.pages.amazing_app_description": "Β‘Describa su aplicaciΓ³n en pocas palabras", + "scenes.app.popup.appsparameters.pages.application_creator.title": "Nueva integraciΓ³n", + "scenes.app.popup.appsparameters.pages.application_creator.checkbox": "Entiendo que el propietario y los administradores de esta empresa podrΓ‘n modificar y publicar esta aplicaciΓ³n.", + "twake.application.access.title": "Seleccione los alcances adecuados para su aplicaciΓ³n.", + "twake.application.access.no_default_scopes_available'": "Esta integraciΓ³n no tiene ningΓΊn acceso {{$1}}", + "\"": "\"", + "scenes.app.popup.appsparameters.pages.application_editor.help_link": "la documentaciΓ³n de la API de Twake", + "scenes.app.popup.appsparameters.pages.application_editor.help_text": "Si no sabe cΓ³mo llenarlos, vaya a ", + "scenes.app.popup.appsparameters.pages.app.private_key": "Llave privada", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed": "Β‘AplicaciΓ³n eliminada con Γ©xito {{$1}}!", + "scenes.app.integrations_parameters.add_application": "Nueva integraciΓ³n", + "scenes.app.integrations_parameters.company_applications_table.more_menu.developer_settings": "ConfiguraciΓ³n de desarrollador", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed_error": "Β‘Error al eliminar la aplicaciΓ³n {{$1}}!", + "scenes.app.popup.appsparameters.pages.application_editor.application_published": "Β‘AplicaciΓ³n exitosa {{$1}}!", + "components.rich_text_editor.plugins.suggestions.loading": "Buscando por mas", + "components.open_desktop_popup.subtitle": "abierto en la aplicaciΓ³n Twake", + "components.open_desktop_popup.open_here_link": "Abrir aquΓ­ en su lugar", + "molecules.download_banner.title": "Aproveche al mΓ‘ximo Twake, descargue la aplicaciΓ³n de escritorio ahora", + "molecules.download_banner.download_button": "Descargar aplicaciΓ³n de escritorio", + "scenes.app.channelsbar.channel_copy_link": "Copiar enlace del canal", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.success.update": "Actualizado exitosamente", + "components.searchpopup.media": "Medios de comunicaciΓ³n", + "components.searchpopup.files": "archivos", + "components.searchpopup.recent_chats": "Chats recientes", + "components.searchpopup.recent_media": "Medios recientes", + "components.searchpopup.recent_files": "Archivos recientes", + "components.searchpopup.recent_channels_and_contacts": "Canales y contactos recientes", + "components.searchpopup.no_results_for": "No hubo resultados para", + "components.searchpopup.try_new_search": "Prueba una nueva bΓΊsqueda", + "components.searchpopup.all": "Todos", + "components.searchpopup.chats": "charlas", + "components.searchpopup.header_title": "BΓΊsqueda", + "components.searchpopup.scope.company": "en toda compaΓ±Γ­a", + "components.searchpopup.scope.channel": "en este canal", + "components.searchpopup.channels": "Canales", + "components.searchpopup.messages": "Mensajes", + "components.searchpopup.see_more": "Ver mΓ‘s", + "scenes.client.join_public_channel.info": "No eres miembro de este canal directo. Haga clic en este botΓ³n para iniciar la discusiΓ³n ahora.", + "components.searchpopup.start_search": "Introduzca algunas palabras clave para iniciar la bΓΊsqueda.", + "scenes.client.channelbar.channelmemberslist.search_invite": "Buscar e invitar usuarios a este canal", + "scenes.client.channelbar.channelmemberslist.search_invite_notice": "No hay muchos miembros en este canal. Busque e invite a los usuarios ahora por correo electrΓ³nico o nombre.", + "scenes.client.channelbar.channelmemberslist.invite_email_button": "Agregar al canal solo como invitado", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace": "Agregar al canal y al espacio de trabajo como miembro", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace_confirm": "ΒΏInvitar a {{$1}} al espacio de trabajo como miembro?", + "scenes.client.channelbar.channelmemberslist.search_invite_type_email": "Escriba una direcciΓ³n vΓ‘lida para invitar por correo electrΓ³nico.", + "scenes.client.channelbar.channelmemberslist.pending_section": "Usuarios pendientes de invitaciΓ³n", + "scenes.client.channelbar.channelmemberslist.members_section": "Usuarios en este canal", + "scenes.client.channelbar.channelmemberslist.not_members_section": "Usuarios que no estΓ‘n en este canal", + "scenes.client.join_private_channel.info": "Este contenido de este canal estΓ‘ restringido o no existe. PΓ³ngase en contacto con un miembro de este canal para recibir una invitaciΓ³n.", + "scenes.client.join_public_channel": "Únete a este canal", + "general.yes": "SΓ­", + "general.no": "No", + "components.open_desktop_popup.open_here_link_forever": "Nunca intente abrir la aplicaciΓ³n de nuevo", + "components.channel_attachement_list.medias": "Medios", + "components.channel_attachement_list.files": "archivos", + "components.channel_attachement_list.title": "Archivos de canales y medios", + "components.channel_attachement_list.nothing_found": "nada aquΓ­ todavΓ­a", + "molecules.message_quote.deleted": "Este mensaje fue eliminado", + "scenes.apps.messages.jump": "Saltar al mensaje", + "components.channel_attachement_list.open": "Abrir galerΓ­a", + "scenes.apps.account.assistant.description": "El asistente de Twake puede dar sentido a su trabajo diario en Twake y proporcionar atajos y acciones inteligentes durante el dΓ­a. El asistente forma parte de la iniciativa Work@Home https://workathome.linagora.com/ y actualmente estΓ‘ siendo probado solo en la empresa Linagora y estΓ‘ en fase de aprendizaje. Significa que enviaremos datos de uso de Twake para entrenar nuestra futura funciΓ³n de asistente.", + "scenes.apps.account.assistant.share.metadata": "Comparte metadatos pero no contenidos", + "scenes.apps.account.assistant.success": "Sus preferencias se han actualizado con Γ©xito.", + "scenes.apps.account.on_console": "Para editar las preferencias de su cuenta global, haga clic en Ir a la consola.", + "scenes.apps.account.assistant.title": "Asistente", + "scenes.apps.account.assistant.share.nothing": "No comparta nada con el asistente (deshabilitar asistente)", + "scenes.apps.account.assistant.share.all": "Comparta todo, incluidos los mensajes y el contenido de los archivos.", + "components.message_seen_by.title": "Usuarios que han visto el mensaje", + "components.message_seen_by.none_seen_it": "Nadie ha visto el mensaje todavΓ­a.", + "components.message_seen_by.btn": "InformaciΓ³n", + "molecules.quoted_content.attachements": "{{$1}} archivos adjuntos", + "scenes.apps.messages.message.user_deactivated": "EstΓ‘s viendo los archivos de una cuenta desactivada", + "general.user.deactivated": "El usuario ya no estΓ‘ en esta empresa", + "general.user.connected": "En lΓ­nea", + "scenes.app.popup.userparameter.pages.email_notif_delay_never": "Nunca", + "scenes.app.popup.userparameter.pages.email_notif_delay_quarter_hour": "15 minutos", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_day": "1 dΓ­a", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_hour": "1 hora", + "scenes.app.popup.userparameter.pages.notification_sound.defaut": "Defecto", + "scenes.app.popup.userparameter.pages.notification_sound.none": "Ninguna", + "scenes.client.channelbar.readonly_channel.checkbox": "Restringir capacidad de escritura", + "scenes.apps.messages.message.forward": "Delantero", + "scenes.apps.messages.message.forward.title": "Reenviar mensaje", + "components.channelselector.title": "Seleccionar canales", + "components.channelselector.confirm": "Selecciona $1 canal(es)", + "components.channelselector.search": "Buscar canales y debates", + "scenes.apps.messages.message.forward.comment": "AΓ±ade un mensaje", + "scenes.apps.messages.message.forward.confirm": "Enviar a $1 canal(es)", + "scenes.apps.messages.message.forward.send": "Mensaje reenviado", + "scenes.app.channelsbar.channel_information.description.placeholder": "DescripciΓ³n del canal, puede usar Markdown.", + "scenes.app.channelsbar.channel_information.group": "grupo de canales", + "scenes.app.channelsbar.channel_information.group.none": "No seleccionado", + "scenes.app.channelsbar.channel_access": "Acceso al canal", + "scenes.app.channelsbar.channel_access.save": "Guardar configuraciΓ³n de acceso", + "scenes.app.channelsbar.channel_access.readonly": "Canal de solo lectura", + "scenes.app.channelsbar.channel_access.readonly.info": "Restrinja la escritura a moderadores, administradores y propietarios.", + "scenes.app.channelsbar.channel_access.visibility": "Visibilidad pΓΊblica", + "scenes.app.channelsbar.channel_access.visibility.info": "Cualquier persona, excepto los invitados de la empresa, puede unirse.", + "scenes.app.channelsbar.channel_access.default": "UniΓ³n automΓ‘tica", + "scenes.app.channelsbar.channel_access.default.info": "Los nuevos miembros se agregarΓ‘n aquΓ­ automΓ‘ticamente.", + "scenes.app.channelsbar.channel_information": "Editar informaciΓ³n del canal", + "scenes.app.channelsbar.channel_information.logo.add": "Subir foto", + "scenes.app.channelsbar.channel_information.logo.remove": "Quitar imagen", + "scenes.app.channelsbar.channel_information.name": "Nombre del Canal", + "scenes.app.channelsbar.channel_information.description": "descripciΓ³n del canal", + "scenes.app.channelsbar.channel_information.group.new": "Crear un nuevo grupo", + "scenes.app.channelsbar.channel_information.group.save": "Establecer grupo de canales en $1", + "scenes.app.channelsbar.channel_information.group.save_none": "No establecer grupo de canales", + "scenes.app.channelsbar.channel_information.save": "Guardar informaciΓ³n", + "scenes.client.channelbar.channelmemberslist.invite_to_workspace": "Invita {{$1}} al espacio de trabajo ➑", + "components.invitation.reached_limit.text": "Alcanzaste el nΓΊmero mΓ‘ximo de usuarios dentro de tu empresa. Aumente su suscripciΓ³n o agregue estos usuarios como invitados", + "components.invitation.allow_anyone_by_email.text": "Permitir que cualquiera con el correo electrΓ³nico @{{$1}} se una a este espacio de trabajo", + "components.invitation.invitation_channels.button": "Invitar a canales", + "components.invitation.invitation_input_list.add": "Agregar", + "components.invitation.invitation_input_list.member": "Miembro", + "components.invitation.invitation_input_list.guest": "Invitado", + "components.invitation.invitation_input_list.placeholder": "Empezar a escribir un correo electrΓ³nico", + "components.invitation.invitation_sent.title": "Las invitaciones se han enviado con Γ©xito.", + "components.invitation.invitation_sent.subtitle_status": "Puede realizar un seguimiento del estado de la invitaciΓ³n en:", + "components.invitation.invitation_sent.subtitle_location": "ConfiguraciΓ³n del espacio de trabajo > GestiΓ³n de miembros", + "components.invitation.invitation_sent.link": "Comprobar el estado de la invitaciΓ³n", + "components.invitation.invitation_sent.button": "Enviar mΓ‘s invitaciones", + "components.invitation.invitation_target.invite_as_guests": "Invitar a todos como invitados", + "components.invitation.invitation_target.invite_as_members": "Invitar a todos como miembros", + "components.invitation.invitation_target.channels_button": "Canales para invitar", + "components.invitation.workspace_link.text": "Enlace de invitaciΓ³n del espacio de trabajo", + "components.invitation.workspace_link.button": "Copiar", + "components.invitation.title": "invitar a personas a {{$1}}", + "components.invitation.bulk_invitation": "InvitaciΓ³n masiva", + "components.invitation.button": "Enviar invitaciones", + "scenes.client.readonly.info": "Este canal es un feed de solo lectura, pero puedes comentar en los hilos.", + "scenes.app.channelsbar.channel_information.group.title": "Grupos de canales", + "components.invitation.custom_role_invitation": "InvitaciΓ³n clΓ‘sica", + "components.invitation.link": "Enlace" +} diff --git a/twake/frontend/public/locales/eu.json b/twake/frontend/public/locales/eu.json new file mode 100644 index 00000000..9e6ba1f1 --- /dev/null +++ b/twake/frontend/public/locales/eu.json @@ -0,0 +1,1008 @@ +{ + "general.edit": "Editatu", + "general.create": "Sortu", + "general.cancel": "Ezeztatu", + "general.save": "Gorde", + "general.close": "Itxi", + "scenes.app.popup.appsparameters.pages.error_check_needed": "Akats bat gertatu da; egiaztatu zure informazioa.", + "scenes.app.popup.appsparameters.pages.json_configuration_information": "Joan dokumentaziora zure konfigurazioa JSON formatuan sortzeko.", + "scenes.app.popup.appsparameters.pages.message_data_next_event": "Hurrengo Ekitaldian bidaliko diren datu pasiboak", + "scenes.app.popup.userparameter.pages.frequency_notif_configuration_description": "Ezarri mugikorreko jakinarazpenen maiztasuna.", + "scenes.app.popup.userparameter.pages.frequency_notif_subtitle": "Jakinarazpenen maiztasuna", + "scenes.app.popup.userparameter.pages.keywords_notif_description": "Nabarmendu gako-hitz hauek:", + "scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description": "Ezarri posta elektronikoko jakinarazpenen maiztasuna.", + "scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description": "Aukeratu jakinarazpenak jasotzen ez dituzun epe bat.", + "scenes.app.popup.userparameter.pages.no_night_disturbing_label": "Ez molestatu gauez", + "scenes.app.popup.workspaceparameter.pages.apps_connectors_title": "Integrazioak", + "scenes.app.popup.workspaceparameter.pages.company_name_description": "Aldatu enpresa honen izena", + "scenes.apps.calendar.export_view_menu": "Esportatu ikuspegia...", + "scenes.apps.calendar.ics_subscription_menu": "Lortu ICS harpidetza esteka", + "scenes.apps.calendar.modals.event_title_placeholder": "Izenburua", + "scenes.apps.calendar.modals.modify_event_button": "Editatu gertaera", + "scenes.apps.calendar.modals.part.participants": "Parte hartzaileak", + "scenes.apps.calendar.modals.participants_event": "Parte hartzaileak", + "scenes.apps.calendar.modals.reminders": "Oroigarriak", + "scenes.apps.calendar.modals.remove_button": "Ezabatu", + "scenes.apps.calendar.modals.remove_event_button": "Ezabatu gertaera", + "scenes.apps.calendar.modify_calendar_menu": "Editatu egutegia", + "scenes.apps.calendar.month_option": "Hilabetea", + "scenes.apps.calendar.my_calendar": "Nire egutegia", + "scenes.apps.calendar.my_calendar_menu": "Nire egutegia", + "scenes.apps.drive.add_button": "Gehitu", + "scenes.apps.drive.message_added_file": "{{$1}} {{$2}} bidali du.", + "scenes.apps.drive.message_added_mutiple_files": "{{$1}} hainbat fitxategi bidali ditu.", + "scenes.apps.drive.message_added_file_no_name": "{{$1}} fitxategi bat bidali du.", + "scenes.apps.drive.choose_folder_button": "Aukeratu direktorio bat", + "scenes.apps.drive.go_trash_menu": "Joan zaborrontzira", + "scenes.apps.drive.import_from_computer_menu": "Ordenagailutik kargatu", + "scenes.apps.drive.new_file_menu": "Fitxategi berria", + "scenes.apps.drive.new_file_title": "Fitxategi berria", + "scenes.apps.drive.new_external_storage": "Kanpoko biltegiratze berria", + "scenes.apps.drive.new_folder_title": "Karpeta berria", + "scenes.apps.drive.no_file_alert": "Ez duzu fitxategi bat sortzeko aukera ematen duen aplikaziorik.", + "scenes.apps.drive.no_storage_app_alert": "Ez duzu kanpoko biltegia gehitzeko aukera ematen duen aplikaziorik.", + "scenes.apps.drive.remove_definitely_menu": "Ezabatu betiko", + "scenes.apps.drive.restore_menu": "Berreskuratu", + "scenes.apps.drive.throw_menu": "Bidali zakarrontzira", + "scenes.apps.drive.trash_empty_menu": "Zaborrontzia hustu", + "scenes.apps.drive.unconfigured_tab": "Fitxa hau ez dago konfiguratuta oraindik.", + "scenes.apps.drive.viewer.loading_preview_message": "Kargatzen...", + "scenes.apps.drive.viewer.no_preview_message": "Ezin da fitxategi mota hau ikusi.", + "scenes.apps.messages.input.emoji": "Emojia", + "scenes.apps.messages.input.hide_formatting": "Ezkutatu formatua", + "scenes.apps.tasks.board.tasks.add_subtask": "Gehitu azpizeregin bat", + "scenes.apps.tasks.board.tasks.use_deadline": "Erabili epea", + "scenes.apps.tasks.board.tasks.use_starttime": "Erabili hasiera-ordua", + "scenes.apps.tasks.board.tasks.in_list": "Zerrendan", + "scenes.app.popup.workspaceparameter.pages.cancel_invitation": "Utzi gonbidapena", + "scenes.apps.account.account.fullname": "Izen osoa", + "login.email_login": "Posta elektronikoa / Saioa hasi", + "scenes.apps.account.account.password_for_user": "Zure erabiltzailearen pasahitza", + "scenes.apps.account.account.send_info": "Bidali kredentzial-informazio hau zure erabiltzaileari.", + "components.listmanager.filter": "Iragazkia", + "components.upload.drop_files": "Jaregin zure fitxategiak hemen", + "components.workspace.list_manager.no_workspace": "Lan-esparrurik ez", + "components.searchpopup.loading": "Emaitza gehiago kargatzen", + "components.searchpopup.filter_ws": "Iragazi lan-eremuak", + "components.searchpopup.tags": "Etiketak", + "components.searchpopup.sender": "Bidaltzailea", + "components.searchpopup.mentions": "Aipamenak", + "scenes.apps.drive.used": "karpeta honetan erabiltzen da", + "components.reminder.notification": "Jakinarazpena", + "components.reminder.hours_bef": "orduak lehenago", + "scenes.app.mainview.discussion": "Eztabaida", + "components.attachmentpicker.from_twake": "Twake Documents-etik", + "components.attachmentpicker.remove_attach": "Kendu eranskina", + "scenes.apps.drive.remove_attachs": "Kendu eranskinak", + "components.drive.elements.see": "Ikusi", + "scenes.client.channelbar.channelmemberslist.title": "Erabiltzaileak {{$1}}", + "scenes.client.channelbar.channelmemberslist.loader": "Gehiago kargatu", + "scenes.client.channelbar.channelmemberslist.autocomplete": "Gehitu edo bilatu erabiltzailea", + "scenes.client.channelbar.channelmemberslist.menu.option_2": "Kendu kanaletik", + "components.leftbar.channel.workspaceschannels.menu.option_2": "Sartu kanal batean", + "scenes.client.mainview.tabs.tabstemplateeditor.select_placeholder": "Aplikazio", + "scenes.client.channelbar.channelmemberslist.no_members": "Kanal honetan ez dago erabiltzailerik, Gehitu erabiltzaileak sakatuta gonbida ditzakezu.", + "scenes.app.channelsbar.hide_discussion_leaving.menu": "Ezkutatu eztabaida", + "scenes.app.popup.adduserfromtwakeconsole.current_users_state": "{{$1}} mezu elektronikoak gehituko dira", + "components.newversion.new_version_component.row.part_1": "Twake bertsio zaharkitua exekutatzen ari zara", + "components.newversion.new_version_component.row.part_2": "aplikazioa berriro kargatzea eta gure funtzio berriez gozatzea gomendatzen dizugu!", + "components.newversion.new_version_component.link": "Egin klik hemen berriro kargatzeko", + "components.newversion.new_version_modal.title": "Eguneratze berria eskuragarri!", + "components.inputs.input_with_select.input.placeholder": "Kanalaren izena", + "components.inputs.input_with_select.select.placeholder": "Atalaren izena", + "components.inputs.input_with_select.select.no_sections": "Hasi zure lehen kanalaren atalaren izena idazten.", + "components.inputs.input_with_select.button.tooltip": "Ezarri kanal atal bat", + "scenes.apps.messages.message.activity_message.a_added_b_to_the_channel": "{{$1}}-k {{$2}} gehitu du kanalean", + "scenes.apps.messages.message.activity_message.a_deleted_channel_connector": "{{$1}} konektore bat kendu du {{$2}}", + "components.alert.leave_private_channel.title": "Ziur kanala utzi nahi duzula?", + "components.alert.leave_private_channel.description": "Ezingo zara berriro sartu kanal pribatu honetan norbaitek gonbidatzen zaituen artean.", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.tag": "Ez zara kide", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.loader": "Gehiago kargatu", + "components.unverified_account.verification_details": "Honi egiaztatzeko xehetasunak bidali dizkiogu", + "components.account_verification_status_sentence": "Zure kontuaren egoera hau da: {{$1}}", + "components.account_verication_status_unverified": "Egiaztatu gabe", + "components.account_verication_status_blocked": "Blokeatua", + "components.unverified_account.re_send_email": "Ez al duzu mezu elektronikoa jaso?", + "components.blocked_account.trial_period_over": "Zure proba-aldia amaitu da. Zure kontua desblokeatzeko eta funtzio guztietarako sarbidea lortzeko, egiaztatu zure kontua posta elektronikoaren berrespenaren bidez", + "components.add_mails_workspace.button": "Hasi Twake erabiltzen", + "components.add_mails_workspace.title_1": "Gehitu erabiltzaile batzuk", + "components.add_mails_workspace.title_2": "Twake talde lankidetzarako tresna bat da, beraz, gonbidatu erabiltzaile batzuk zuretzat sortu dugun lan-eremu bat probatzera.", + "components.add_mails_workspace.text_area_placeholder": "Sartu zure erabiltzaileen helbide elektronikoak*", + "components.verify_mail.title_1": "Zorionak", + "components.verify_mail.title_2": "Twake-ren erabiltzaile ofiziala zara orain!", + "components.verify_mail.button": "Gehitu erabiltzailea", + "services.console_services.toaster.success_verify_email": "Egiaztapen-esteka bat bidali da zure posta-kontura", + "scenes.app.popup.workspaceparameter.pages.table_title": "Izena", + "scenes.client.main_view.main_header.search_input": "Bilatu", + "scenes.apps.drive.new_link_title": "Esteka berria", + "scenes.app.integrations_parameters.company_applications_table.more_menu.remove_application": "Enpresatik kendu", + "scenes.app.integrations_parameters.company_applications_table.name": "Izena", + "app.state.recoil.hooks.use_current_company_applications.toaster_add": "Behar bezala gehitu da {{$1}} zure enpresan", + "scenes.apps.messages.input.replied_to": "erantzun zion ", + "scenes.app.workspaces.create_company.group_data.group_size.50_100": "50 - 99 erabiltzaile", + "components.locked_features.locked_only_office_popup.title": "Ezin duzu fitxategi hau editatu", + "components.drive.new_versions": "Gehitu bertsio berri bat", + "scenes.apps.parameters.group_sections.workspaces": "Lan-eremuak", + "scenes.apps.calendar.my_calendar_label": "Nire egutegia", + "general.help.documentation": "Dokumentazioa", + "general.send": "Mezua bidali", + "general.help.support": "Laguntza", + "scenes.apps.parameters.workspace_sections.members.pending": "Zain dauden mezu elektronikoak", + "scenes.app.workspacesbar.components.grp_parameters": "{{$1}} ezarpenak", + "components.leftbar.channel.workspaceschannels.menu.option_1": "Sortu kanal bat", + "scenes.apps.messages.message.activity_message.a_deleted_channel_tab": "{{$1}} kendu du {{$2}} fitxa {{$3}}", + "scenes.apps.messages.left_bar.stream.notifications.mentions": "{{$1}}, {{$2}} eta {{$3}}", + "scenes.login.create_account.firstname": "Izena", + "scenes.apps.tasks.board.ends": "Egin beharrekoa", + "general.user.role.company.member": "Kide", + "scenes.apps.messages.input.send_message": "Mezua bidali", + "components.locked_features.locked_workspace_popup.subtitle": "Doako bertsioan, lan-eremu bakarra izan dezakezu zure enpresan.", + "general.unarchive": "Desartxiboa", + "components.users_picker.add_me": "Gehitu nazazu", + "general.retry": "Saiatu berriro", + "scenes.app.popup.workspaceparameter.pages.researching_apps_button": "Bilatu aplikazioak...", + "scenes.app.popup.workspaceparameter.pages.show_button": "Bistaratzea", + "components.workspace.list_manager.current_company": "Egungo enpresa", + "scenes.app.workspaces.create_company.group_data.group_size.1000_5000": "1000 - 4999 erabiltzaile", + "scenes.login.create_account.fill_in_email": "Zure posta elektronikoa mezu elektroniko zuzen batekin bete behar duzu", + "scenes.apps.calendar.modals.remove_event_text": "Gertaera ezabatu?", + "scenes.app.workspaces.create_company.group_data.group_main_activity.transport_logistics": "Garraioa / Logistika", + "scenes.apps.account.account.password_modal.old_password": "Oraingo pasahitza", + "scenes.apps.messages.messageslist.go_last_message_button": "Joan azken mezura", + "general.add": "Gehitu", + "scenes.app.workspaces.create_company.group_data.group_size.500_1000": "500 - 999 erabiltzaile", + "scenes.app.workspaces.create_company.group_data.group_main_activity.chemistry": "Kimika", + "scenes.app.workspaces.create_company.group_data.group_main_activity.textile_clothing_shoes": "Ehungintza / Arropa / Oinetakoak", + "general.archive": "Artxiboa", + "scenes.login.forgot_password.mail_doesnt_exist": "E-mail hau ez da existitzen", + "scenes.app.popup.userparameter.personnal_workspaces_title": "Zure lan-eremuak", + "scenes.app.popup.workspaceparameter.pages.name_label": "Lan-eremuaren izena", + "scenes.apps.drive.open_link": "Ireki esteka leiho berri batean", + "scenes.app.workspaces.create_company.group_data.group_main_activity.publishing_communication_multimedia": "Argitalpena / Komunikazioa / Multimedia", + "components.application.messages": "Mezuak", + "scenes.app.workspaces.create_company.group_data.group_main_activity.education": "Hezkuntza", + "scenes.apps.board.kanban": "Kanban", + "scenes.login.forgot_password.password": "Pasahitza", + "components.unverified_account.typography_text_danger": "{{$1}} egun geratzen zaizu proba-aldian. Probako kontua 7 egun igaro ondoren blokeatuko da eta behin betiko ezabatuko da erregistratu eta hilabete igaro ondoren. Zure kontua egiazta dezakezu bidali dizugun egiaztapen-mezuan dagoen \"Egiaztatu nire kontua\" botoian klik eginez.", + "scenes.app.popup.workspaceparameter.pages.title": "Laneko eremuaren ezarpenak", + "scenes.app.popup.workspaceparameter.pages.install_button": "Instalatu", + "scenes.app.channelsbar.currentuser.workspace_parameters": "Laneko eremuaren ezarpenak", + "scenes.app.channelsbar.currentuser.disable_notifications": "Desgaitu", + "general.delete": "Ezabatu", + "general.continue": "Jarraitu", + "components.user_picker.modal_no_result": "Ez da emaitzarik aurkitu", + "scenes.app.workspaces.create_company.group_data.group_type.public_organization": "Erakunde publikoa", + "scenes.app.workspaces.create_company.group_data.group_type.society_club_charity": "Elkartea, kluba edo ongintza", + "scenes.app.workspaces.create_company.group_data.group_type.other_group": "Bestela", + "scenes.app.workspaces.create_company.group_data.group_size": "Taldearen tamaina", + "scenes.app.workspaces.create_company.group_data.group_size.less_3": "4 erabiltzaile baino gutxiago", + "scenes.app.workspaces.create_company.group_data.group_size.4_10": "4-10 erabiltzaile", + "scenes.app.workspaces.create_company.group_data.group_size.5000_more": "5000 erabiltzaile baino gehiago", + "scenes.app.workspaces.create_company.group_data.group_main_activity": "Jarduera nagusia", + "scenes.app.workspaces.create_company.group_data.group_main_activity.food": "Janari", + "scenes.app.workspaces.create_company.group_data.group_main_activity.bank": "Bankua / Aseguruak", + "scenes.app.workspaces.create_company.group_data.group_main_activity.construction_building": "Eraikuntza / Materiales de construcciΓ³n", + "scenes.app.workspaces.create_company.group_data.group_main_activity.real_estate": "Higiezinak", + "scenes.app.workspaces.create_company.group_data.group_main_activity.materials": "Materialak", + "scenes.app.workspaces.create_company.group_data.group_main_activity.trade_commerce_distribution": "Merkataritza / Merkataritza / Banaketa", + "scenes.app.workspaces.create_company.group_data.group_main_activity.studies_and_advice": "Ikasketak eta aholkularitza", + "scenes.app.workspaces.create_company.group_data.group_main_activity.pharmaceutical_industry": "Industria farmazeutikoa", + "scenes.app.workspaces.create_company.group_data.group_main_activity.it_telecom": "Informatika / Telekomunikazioa", + "scenes.app.workspaces.create_company.group_data.group_main_activity.business_services": "Enpresa zerbitzuak", + "scenes.app.workspaces.create_company.group_data.group_main_activity.entertainment": "Entretenimendua", + "scenes.app.workspaces.create_company.group_data.group_main_activity.research": "Ikerketa", + "scenes.app.workspaces.create_company.group_data.group_main_activity.administration": "Administrazioa", + "scenes.app.workspaces.create_company.group_data.group_main_activity.other": "Bestela", + "scenes.app.workspaces.create_company.invitations.title": "Konfiguratu zure lan-eremua.", + "scenes.app.header.disconnected": "Deskonektatuta zaude", + "scenes.app.header.disconnected.reload": "Berriz kargatu", + "scenes.app.header.alt_notifications": "Jakinarazpenak", + "scenes.apps.calendar.calendar.list_btn": "Zerrenda", + "scenes.apps.calendar.event_edition.deadline_tag": "Epemuga", + "scenes.apps.calendar.event_edition.checkbox_all_day": "Egun osoan", + "scenes.apps.calendar.event_edition.title_confidentiality": "Konfidentzialtasuna", + "scenes.apps.calendar.event_view.article_until": "to", + "scenes.apps.calendar.calendar_modal.participants": "Parte hartzaileak", + "scenes.apps.calendar.calendar_modal.placeholder": "Izena", + "scenes.apps.calendar.left.calendars": "Egutegiak", + "scenes.apps.drive.left.search": "Bilatu", + "scenes.apps.drive.navigators.navigator_content.directory_name": "Direktorioaren izena", + "scenes.apps.drive.navigators.navigator_labels.title": "Etiketak", + "scenes.apps.drive.navigators.new_file.untitled": "Izenbururik gabe", + "scenes.apps.drive.navigators.new_file.create_file.type": "Mota", + "scenes.apps.drive.navigators.new_file": "Fitxategi berria", + "scenes.apps.drive.preview_bloc.operations_download": "Deskargatu", + "scenes.apps.drive.preview_bloc.error_file": "Fitxategia ez da aurkitu", + "scenes.apps.drive.right_preview.operations_restore": "Berreskuratu", + "scenes.apps.drive.right_preview.operations_delete": "Eraman zaborrontzira", + "scenes.apps.drive.right_preview.public_link": "Esteka publikoa", + "scenes.apps.messages.messages": "Mezuak", + "scenes.apps.messages.chatbox.chat.delete_message": "Ezabatu mezu hau", + "scenes.apps.messages.chatbox.chat.delete_message_btn": "Ezabatu mezua", + "scenes.apps.messages.left_bar.stream_modal.placeholder_name": "Izena", + "scenes.apps.messages.left_bar.stream.add_to_favorites": "Gehitu gogokoetara", + "scenes.apps.messages.left_bar.stream.notifications": "Jakinarazpenak...", + "scenes.apps.messages.left_bar.stream.notifications.all": "Edozein mezu", + "scenes.apps.messages.left_bar.stream.notifications.never": "Ezer ez", + "scenes.apps.parameters.workspace_sections.workspace": "Langunea", + "scenes.apps.parameters.workspace_sections.members": "Parte hartzaileak", + "scenes.apps.parameters.group_sections.apps": "Aplikazioak", + "scenes.apps.account.title": "Kontuaren parametroak", + "scenes.apps.account.account.menu_title": "Kontua", + "scenes.apps.account.languages.menu_title": "Hizkuntza", + "scenes.apps.account.account.firstname": "Izena", + "scenes.apps.account.account.lastname": "Abizena", + "scenes.apps.account.account.username": "Erabiltzaile izena", + "scenes.apps.account.account.change_username": "Aldatu zure erabiltzaile-izen berezia.", + "scenes.apps.account.account.email_add": "Gehitu e-mail berria", + "scenes.apps.account.account.email_add_modal.invalid_code": "Kode hau baliogabea da", + "scenes.apps.account.account.password": "Pasahitza", + "scenes.apps.account.account.password_modal.password": "Pasahitz berria", + "scenes.apps.account.account.password_modal.bad_old_password": "Pasahitz zaharra ez da zuzena.", + "scenes.apps.account.account.password_modal.bad_password": "Zure pasahitzak ez datoz bat edo laburregiak dira. Mesedez, idatzi gutxienez 8 karaktere dituen pasahitza.", + "scenes.apps.account.account.logout": "Saioa amaitu", + "scenes.apps.account.languages.text": "Aldatu Twake hizkuntza.", + "scenes.apps.account.notifications.title": "Jakinarazpenak", + "scenes.apps.account.notifications.keywords_subtitle": "Gako-hitzak", + "scenes.apps.account.notifications.keywords_placeholder": "garatzailea, wifia, kodea, ...", + "scenes.apps.account.notifications.disturb_option_a": "Ez bidali push jakinarazpen artean ", + "scenes.apps.account.notifications.disturb_option_b": " eta ", + "scenes.apps.account.notifications.disturb_option_c": " (tokiko ordu-eremua)", + "scenes.apps.account.notifications.devices_subtitle": "Gailuaren jakinarazpenak", + "scenes.apps.account.notifications.devices_option_ever": "Bidali beti push jakinarazpenak", + "scenes.apps.account.notifications.devices_option_inactive": "Bidali push jakinarazpenak mahaigainean inaktibo nagoenean", + "scenes.apps.account.notifications.devices_option_never": "Inoiz ez bidali push jakinarazpenik", + "scenes.apps.account.notifications.privacy_subtitle": "Pribatutasuna", + "scenes.apps.account.notifications.mail_subtitle": "Posta elektroniko bidezko jakinarazpenak", + "scenes.apps.parameters.group_sections.apps.badge_extension": "Luzapena", + "scenes.apps.parameters.workspace_sections.members.members": "Erabiltzaileak", + "scenes.apps.parameters.workspace_sections.members.invite": "Gonbidatu erabiltzaile berria", + "scenes.apps.parameters.workspace_sections.members.invite_btn": "Gehitu erabiltzailea", + "scenes.apps.tasks.boards": "Oholak", + "scenes.apps.tasks.connectors_search_menu": "Bilatu konektoreak...", + "scenes.apps.tasks.no_connectors_menu_text": "Ez duzu egutegi batera konektatu daitekeen konektorerik.", + "scenes.apps.tasks.unconfigured_tab": "Fitxa hau ez dago konfiguratuta oraindik.", + "scenes.apps.tasks.choose_board_button": "Aukeratu taula bat", + "scenes.apps.tasks.new_board.title": "Taula berria", + "scenes.apps.tasks.new_board.edit_title": "Editatu taula", + "scenes.apps.tasks.task": "Zeregin", + "scenes.apps.tasks.no_tasks": "Zereginik ez", + "scenes.apps.tasks.task_status.todo": "Egin", + "scenes.apps.tasks.task_status.current": "Oraingoa", + "scenes.apps.tasks.task_status.done": "Eginda", + "scenes.apps.tasks.task.description": "Deskribapena", + "scenes.apps.tasks.task.assignees": "Esleipendunak", + "scenes.apps.tasks.task.edit.dates": "Datak", + "scenes.apps.tasks.list_modal.modify_list": "Aldatu zerrenda", + "scenes.apps.tasks.list_modal.new_list": "Zerrenda berria", + "scenes.apps.tasks.list_modal.remove": "Kendu zerrenda eta zereginak", + "scenes.apps.tasks.list_modal.predefined_participants": "Aurrez zehaztutako parte-hartzaileak", + "scenes.apps.tasks.list_modal.remove_archived_tasks": "Kendu artxibatutako zereginak ({{$1}})", + "scenes.login.footer.go_to_twake": "Joan twakeapp.com helbidera", + "scenes.login.footer.branding": "{{$1}} ({{$2}}) Twake zerbitzari pribatu batean zaude. ", + "scenes.login.create_account.title": "Sortu kontu berri bat", + "scenes.login.create_account.email": "Posta elektronikoa", + "scenes.login.create_account.email_used": "Posta elektroniko hau dagoeneko erabiltzen ari da.", + "scenes.login.create_account.username_already_exist": "Erabiltzaile-izen hau dagoeneko erabiltzen ari da", + "scenes.login.create_account.fill_in_username": "Zure erabiltzaile-izena bete behar duzu", + "scenes.login.create_account.too_short_password": "Zure pasahitzak 8 karaktere izan behar ditu gutxienez.", + "scenes.login.create_account.newsletter": "Jaso Twake-ri buruzko informazioa", + "scenes.login.create_account.lastname": "Abizena", + "scenes.login.forgot_password.title": "Pasahitza ahaztua?", + "scenes.login.forgot_password.text": "9 digituko kode bat jasoko duzu posta elektronikoz zure nortasuna egiaztatzeko.", + "scenes.login.forgot_password.email_to_recover": "Posta elektronikoa berreskuratzeko", + "scenes.login.forgot_password.invalid_code": "Kode honek ez du balio.", + "scenes.login.forgot_password.text3": "Sartu pasahitz berri bat zure konturako.", + "scenes.login.forgot_password.password2": "Pasahitza baieztatu", + "scenes.login.forgot_password.password_dont_match": "Zure pasahitzak ez datoz bat edo laburregiak dira. Mesedez, idatzi gutxienez 8 karaktere dituen pasahitza.", + "scenes.login.home.subtitle": "Pozik zu ikusteaz", + "scenes.login.home.unable_to_connect": "Kredentzialak baliogabeak", + "scenes.login.home.password": "Pasahitza", + "scenes.login.home.login_btn": "Saioa hasi", + "scenes.login.home.lost_password": "Pasahitza ahaztua?", + "scenes.login.home.create_account": "Kontu bat sortu", + "scenes.login.create_account.password": "Pasahitza", + "scenes.login.create_account.step_1_subtitle": "Ezin da sinpleagoa izan; informazio pixka bat besterik ez dugu behar.", + "scenes.login.create_account.step_2_subtitle_a": "Gehitu zure izen osoa beste erabiltzaileek zu ezagutu dezaten.", + "scenes.login.create_account.step_2_subtitle_b": "Zure telefono-zenbakiak pribatua izaten jarraitzen du.", + "scenes.login.create_account.step_3_mail_sent": "Posta elektronikoz aktibatzeko esteka bidali dizugu.", + "scenes.login.create_account.step_3_subtitle": "Azken urratsa: robot bat ez zarela egiaztatu behar dugu!", + "scenes.app.workspaces.create_company.company_name.placeholder": "Enpresaren izena", + "scenes.app.workspaces.create_company.company_name.title_1": "Hasi,", + "scenes.app.workspaces.create_company.company_name.title_2": "adierazi zure enpresaren izena.", + "scenes.app.workspaces.create_company.default_workspace_name": "Nagusia", + "scenes.app.workspaces.create_company.importations.title_1": "Dagoeneko tresna digitalekin lan egiten duzu? Inportatu edo integratu zure tresnak orain!", + "scenes.app.workspaces.create_company.importations.title_2": "Ez kezkatu, geroago egin dezakezu!", + "scenes.app.workspaces.create_company.invitations.title_2": "Gehitu erabiltzaileak zure taldean.", + "scenes.app.workspaces.create_company.title": "Sortu nire enpresa", + "scenes.app.workspaces.welcome_page.add_secondary_emails": "Gehitu bigarren mailako mezu elektroniko bat", + "scenes.app.workspaces.welcome_page.added_to_company": "Gonbidatu zaituzte ", + "scenes.app.workspaces.welcome_page.create_my_company": "Sortu nire enpresa", + "scenes.app.workspaces.welcome_page.lets_go": "Goazen!", + "scenes.app.workspaces.welcome_page.may_be_invited_with_secondary_emails": "Beste helbide elektroniko bat erabilita gonbidatu zaituzte?", + "scenes.app.workspaces.welcome_page.no_company_subtitle": "A, tira... Badirudi oraindik inork ez zaituela gonbidatu lan gune batera.", + "scenes.app.workspaces.welcome_page.ready_to_work": "Lan egiteko prest zaude orain.", + "scenes.app.workspaces.welcome_page.add_secondary_emails_comment": "Hainbat helbide elektroniko lotu ditzakezu zure kontuarekin; helbide bakarra erabiliko da jakinarazpenak bidaltzeko.", + "scenes.app.workspaces.welcome_page.main_mail_title": "Helbide nagusia", + "scenes.app.workspaces.welcome_page.other_mail_title": "Bigarren mailako helbideak", + "scenes.app.workspaces.welcome_page.add_new_email": "Gehitu e-mail bat", + "scenes.app.workspaces.welcome_page.code_verification": "Egiaztapen-kodea", + "scenes.app.workspaces.welcome_page.new_email": "Gehitu bigarren mailako mezu elektroniko bat", + "scenes.app.workspaces.welcome_page.we_sent_you_mail": "Egiaztapen-kode bat bidali dizugu {{$1}} bidez", + "scenes.app.workspaces.welcome_page.done": "bukatu dut", + "scenes.login.forgot_password.finished": "Zure pasahitza behar bezala eguneratu da.", + "scenes.apps.account.account.description_main": "Zure helbide nagusia da Twake-k zure jakinarazpenak bidaltzen dituena. Zure bigarren mailako helbideak haiek erabiltzen dituzten lan-eremuetara automatikoki gonbidatzeko aukera ematen dute.", + "scenes.apps.account.account.emails.description": "Kudeatu zure helbide elektroniko desberdinak.", + "scenes.apps.account.account.make_main": "Ezarri nagusia", + "scenes.apps.account.account.password.description": "Aldatu pasahitza.", + "scenes.apps.account.identity": "Identitatea", + "scenes.apps.account.identity.description": "Aldatu zure izena, abizena eta profilaren irudia Twake-ko beste erabiltzaileek ikusgai.", + "scenes.apps.account.preference": "Hobespenak", + "general.open": "Ireki", + "scenes.apps.account.thumbnail.max_weight": "Gehienezko tamaina 5 MB", + "scenes.apps.account.account.email_add_modal.confirm": "Berretsi e-mail hau", + "app.name.twake_calendar": "Egutegia", + "app.name.twake_drive": "Dokumentuak", + "app.name.twake_tasks": "Zereginak", + "components.calendar.repetition.everyday": "Egunero", + "components.calendar.repetition.does_not_repeat": "Ez da errepikatzen", + "components.calendar.repetition.weekly_on": "Astero {{$1}}", + "components.calendar.repetition.monthly_on": "Hilero {{$1}} {{$2}}", + "components.calendar.repetition.monthly_on_day": "Hilero egunean {{$1}}", + "components.calendar.repetition.annually_on": "Urtero {{$1}}", + "components.calendar.repetition.every_weekday": "Astegunero (astelehenetik ostiralera)", + "components.calendar.repetition.custom": "Pertsonalizatua...", + "components.calendar.repetition.repeat": "Errepikatu bakoitzean", + "components.calendar.repetition.ends": "Amaierak", + "components.calendar.repetition.never": "Inoiz ez", + "components.calendar.repetition.repeat_on": "Errepikatu", + "scenes.app.channelsbar.currentuser.add_apps": "Bilatu aplikazioak", + "scenes.app.channelsbar.currentuser.change_my_status": "Aldatu nire egoera", + "scenes.app.channelsbar.currentuser.create_workspace_page": "Sortu lan-eremu bat", + "scenes.app.channelsbar.currentuser.invited_status": "Gonbidatua zara.", + "scenes.app.channelsbar.currentuser.title": "Kontu ezarpenak", + "scenes.app.channelsbar.currentuser.logout": "Amaitu saioa", + "scenes.app.channelsbar.currentuser.update": "Eguneratu", + "scenes.app.channelsbar.currentuser.disabling_notifications_until": "Desgaitu 9:00ak arte. bihar", + "scenes.app.channelsbar.currentuser.reactivate_notifications": "Berriz aktibatu", + "scenes.app.channelsbar.currentuser.user_parameter": "Jakinarazpen-ezarpenak", + "scenes.app.channelsbar.initial_instructions_tutorial": "Aukeratu izen bat, izena eta profileko argazki bat.", + "scenes.app.channelsbar.installation_desktop_tutorial": "Instalatu mahaigaineko aplikazioa", + "scenes.app.channelsbar.invitation_collaboraors_tutorial": "Gonbidatu erabiltzaileak zure laneko gunera.", + "scenes.app.channelsbar.public_channel_label": "Publiko", + "scenes.app.channelsbar.private_channel_label": "Pribatua", + "scenes.app.channelsbar.sending_message_instruction": "Bidali zure lehen mezua eztabaida batean", + "scenes.app.channelsbar.tutorial_alert": "Ez duzu inoiz marko hau berriro erakutsi?", + "scenes.app.channelsbar.welcome": "Ongi etorri Twake-ra", + "scenes.app.channelsbar.welcoming_message_subtitle": "Egin zaitez Twake-ko profesional bat klik gutxitan!", + "scenes.app.mainview.instruction_current_tab": "Hasi zure ezkerreko kanal bat hautatuz.", + "scenes.app.mainview.tabs.no_connected_connectors_for_channel": "Ez duzu kanal batera konektatzeko moduko konektorerik.", + "scenes.app.mainview.tabs.rename": "Aldatu izena", + "scenes.app.mainview.tabs.searching_connectors": "Bilatu konektoreak...", + "scenes.app.popup.adduser.adresses_message": "Mesedez, bereizi helbideak koma edo zuriune batekin. Gogoratu Twake-k zure harpidetzaren arabera gonbidapen kopurua muga dezakeela.", + "scenes.app.popup.appsparameters.pages._app_identity": "Aplikazioaren identitatea", + "scenes.app.popup.appsparameters.pages._appareance_message_twakcode": "Probatu zure Twacode mezuen itxura", + "scenes.app.popup.appsparameters.pages.alert_published_app": "Zure aplikazioa argitaratu da, ezin duzu editatu.", + "scenes.app.popup.appsparameters.pages.allowed_ip_adresses_method": "Erabili * garapenean IP helbide guztiak baimentzeko.", + "scenes.app.popup.appsparameters.pages.amazing_app_name": "Nire aplikazio harrigarria", + "scenes.app.popup.appsparameters.pages.api_data_description": "Twake APIrako datu erabilgarriak.", + "components.locked_features.locked_only_office_popup.subtitle": "Doako bertsioan, ezin duzu bulegoa bakarrik erabili.", + "scenes.app.popup.adduser.magiclinks.genrator_info": "Lanerako gonbidapenaren esteka", + "scenes.app.popup.adduser.magiclinks.new_link_generated": "Esteka berria sortu da", + "scenes.app.popup.adduser.magiclinks.copied_to_clipboard": "Behar bezala kopiatu da arbelean", + "scenes.app.popup.adduser.magiclinks.action_copy": "Kopiatu", + "scenes.app.popup.adduser.magiclinks.action_generate": "Sortu", + "scenes.app.popup.appsparameters.pages.error_message": "Izen hau beste aplikazio batek erabiltzen du jada; mesedez aukeratu beste bat.", + "scenes.app.popup.appsparameters.pages.filter_information": "Iragazki honek zure API gakoaren erabilera zure konektoreko zerbitzarietara mugatzen du.", + "scenes.app.popup.appsparameters.pages.go_back": "Itzuli", + "scenes.app.popup.appsparameters.pages.grp_section_name-error": "Izen hau beste aplikazio batek erabiltzen du dagoeneko. Mesedez, aukeratu beste bat.", + "scenes.app.popup.appsparameters.pages.grp_section_surname_label": "Izen sinplifikatua", + "scenes.app.popup.appsparameters.pages.installation": "Instalatu.", + "scenes.app.popup.appsparameters.pages.instruction_message_twakecode": "Hasi zure mezua JSON formatuan idazten.", + "scenes.app.popup.appsparameters.pages.interne_availability_application": "Barne aplikazioa", + "scenes.app.popup.appsparameters.pages.loading": "Kargatzen...", + "scenes.app.popup.appsparameters.pages.modify_public_data": "Editatu zure aplikazioaren datu publikoak.", + "scenes.app.popup.appsparameters.pages.new_app_title": "Aplikazio berria", + "scenes.app.popup.createworkspacepage.placeholder_name": "Lan-eremuaren izena", + "scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button": "Gonbidatu erabiltzaileak", + "scenes.app.popup.workspaceparameter.pages.collaborateurs": "Erabiltzaileak", + "scenes.app.popup.workspaceparameter.pages.company_developped_apps_subtitle": "Enpresak garatutako aplikazioak", + "scenes.app.popup.workspaceparameter.pages.company_identity_title": "Enpresaren identitatea", + "scenes.app.popup.workspaceparameter.pages.company_name_label": "Enpresaren izena", + "scenes.app.popup.workspaceparameter.pages.configuration_notif": "konfigurazioa", + "scenes.app.popup.workspaceparameter.pages.configure_button": "Konfiguratu", + "scenes.app.popup.workspaceparameter.pages.description": "Deskribapena", + "scenes.app.popup.workspaceparameter.pages.displayed_preferencies_subtitle": "Bistaratu hobespenak", + "scenes.app.popup.workspaceparameter.pages.installed_app_information": "Instalatu aplikazioa lan eremu honetan.", + "scenes.app.popup.workspaceparameter.pages.your_apps_label": "Zure aplikazioak", + "scenes.app.popup.workspaceparameter.payments_subscriptions_title": "Ordainketak eta harpidetzak", + "scenes.app.workspacesbar.components.change_company_title": "Enpresa aldatu", + "scenes.app.workspacesbar.components.create_company_menu": "Enpresa bat sortu", + "scenes.apps.calendar.add_calendar_menu": "Gehitu egutegi bat", + "scenes.apps.calendar.connectors_menu": "Konektoreak...", + "scenes.apps.calendar.connectors_search_menu": "Bilatu konektoreak...", + "scenes.apps.calendar.create_calendar_title": "Sortu egutegi bat", + "scenes.apps.calendar.day_option": "Eguna", + "scenes.apps.calendar.edit_calendar_title": "Editatu egutegia", + "scenes.apps.calendar.export_title": "Esportatu", + "scenes.apps.calendar.modals.advanced_options": "Aukera aurreratuak", + "scenes.apps.calendar.modals.description_placeholder": "Deskribapena", + "scenes.apps.calendar.modals.details_title": "Xehetasunak", + "scenes.apps.calendar.modals.event_adresse_placeholder": "Helbidea", + "scenes.apps.calendar.modals.event_description_placeholder": "Deskribapena", + "scenes.apps.calendar.no_calendar_text": "Ez duzu egutegirik ezarri lan-eremu honetarako.", + "scenes.apps.calendar.no_connectors_menu_text": "Ez duzu egutegi batera konektatu daitekeen konektorerik.", + "scenes.apps.calendar.remove_calendar_confirmation": "Egutegia eta bere gertaerak betiko ezabatu nahi dituzu?", + "scenes.apps.calendar.today_menu": "Gaur", + "scenes.apps.calendar.week_option": "Astea", + "scenes.apps.calendar.workspace": "Langunea", + "scenes.apps.calendar.workspace_label": "Lan eremu hau", + "scenes.apps.calendar.workspace_menu": "Langunea", + "scenes.apps.drive.choose_file_button": "Hautatu fitxategi bat", + "scenes.apps.drive.create_folder_button": "Sortu", + "scenes.apps.drive.download_button": "Deskargatu", + "scenes.apps.drive.files_subtitle": "Fitxategiak", + "scenes.apps.drive.folder_subtitle": "Karpetak", + "scenes.apps.drive.go_out_trash_menu": "Utzi zaborra", + "scenes.apps.drive.move_text": "Mugitu", + "scenes.apps.drive.viewer.open_with_button": "Ireki...", + "scenes.apps.messages.input.placeholder": "Idatzi mezu bat. Erabili @ erabiltzaile bat aipatzeko.", + "scenes.apps.messages.input.edited": "Editatua", + "scenes.apps.messages.just_you": "Zuretzat bakarrik ikusgai", + "scenes.apps.messages.message.new_messages_bar": "Mezu berriak", + "scenes.apps.messages.message.cancel_button": "Utzi", + "scenes.apps.messages.message.modify_button": "Editatu", + "scenes.apps.messages.input.show_formatting": "Erakutsi formatua", + "scenes.tell_us": "Mesedez, esaiguzu zertan ari zinen:", + "scenes.apps.drive.viewer.download_desktop": "Deskargatu Twake Desktop aplikazioan aurreikusteko", + "scenes.apps.tasks.my_tasks": "Nire zereginak", + "scenes.apps.tasks.board.place_holder": "Kontseiluaren izena", + "scenes.apps.tasks.board.tasks.subtask": "Azpizeregin", + "scenes.apps.tasks.board.starts": "hasten da", + "scenes.apps.tasks.board.list_name": "Zerrendaren izena", + "scenes.app.popup.sync_calendar": "Sinkronizatu zure egutegiak.", + "scenes.apps.parameters.workspace_sections.workspace.logo_company": "Enpresaren logotipoa", + "scenes.app.popup.workspaceparameter.pages.logo_company_modify_description": "Editatu enpresaren irudia ", + "components.workspace.list_manager.add": "Gehitu lan-eremuak", + "components.workspace.list_manager.current_space": "Egungo lan-espazioa", + "components.workspace.list_manager.all": "Denak", + "components.workspace.calendar.invalid": "Baliogabea", + "components.searchpopup.enter_text": "Sartu testu bat Twake bilatzeko.", + "components.searchpopup.size": "Tamaina", + "components.searchpopup.creation": "Sorkuntza", + "components.searchpopup.update_search": "Eguneratu bilaketa", + "components.searchpopup.last_modif": "Azken aldaketa", + "components.reminder.days_bef": "egun lehenago", + "components.reminder.weeks_bef": "aste lehenago", + "components.reminder.by_email": "Posta elektronikoa", + "scenes.apps.calendar.reminders": "abisua(k)", + "scenes.apps.calendar.video_link": "Egin klik esteka irekitzeko", + "components.tagpicker.notag": "Etiketarik ez", + "scenes.apps.tasks.modals.attachments": "Eranskinak", + "components.calendar.calendarselector.from": "Bertatik", + "scenes.apps.drive.move_text2": "Mugitu", + "components.attachmentpicker.from_computer": "Zure gailutik", + "components.attachmentpicker.file": "Fitxategia", + "components.drive.elements.current_name": "Egungo izena: ", + "scenes.apps.drive.right_preview.public": "Sarbide publikoa", + "components.drive.elements.configurate_mod": "Konfiguratu mod...", + "components.drive.elements.manage_version": "Kudeatu bertsioak", + "scenes.app.popup.createcompany.try_again": "Saiatu berriro mesedez.", + "scenes.app.popup.workspace.edit_temp": "Editatu aldi baterako kontua", + "scenes.apps.tasks.active_tasks": "zeregin aktiboak", + "scenes.apps.drive.right_preview.versions": "Bertsioak", + "scenes.app.popup.appsparameters.pages.apps_connectors_small_text": "Kudeatu zure aplikazioak eta konektoreak.", + "scenes.app.popup.appsparameters.pages.icon": "Ikonoa", + "scenes.app.popup.appsparameters.pages.title_informations": "Oinarrizko informazioa", + "scenes.app.popup.appsparameters.pages.subtitle_informations": "Aplikazioen kudeaketarekin lotutako informazioa", + "scenes.app.popup.appsparameters.pages.smalltext_user_id": "Uneko erabiltzailearen IDa", + "scenes.app.popup.appsparameters.pages.smalltext_workspace_id": "Uneko lan-eremuaren ID", + "scenes.app.popup.appsparameters.pages.smalltext_group_id": "Uneko taldearen IDa", + "scenes.app.mainview.channel_description": "Deskribatu kanala", + "scenes.client.channelbar.channeltemplateeditor.checkbox": "Gonbidatu automatikoki lan-eremuko erabiltzaile guztiak kanal honetara", + "components.channelworkspacelist.title": "Kanalak", + "scenes.client.channelbar.workspacechannellist.autocomplete": "Bilatu kanala, erabiltzailea edo zuzeneko mezuak", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_creation": "Sortu fitxa berri bat", + "components.notifications.hidden_notifications_button.children": "Mezu berriak", + "scenes.apps.drive.download_all_button": "Deskargatu guztiak", + "scenes.apps.messages.message.activity_message.a_removed_b_from_the_channel": "{{$1}}-k {{$2}} kendu du kanaletik", + "scenes.apps.messages.message.activity_message.a_updated_channel_description": "{{$1}} deskribapena aldatu du", + "scenes.apps.messages.message.activity_message.a_updated_channel_name": "{{$1}} kanalari izena aldatu dio {{$2}}", + "scenes.apps.messages.message.activity_message.a_created_channel_connector": "{{$1}} konektore berri bat gehitu du {{$2}}", + "components.verify_mail.text": "Lehenik eta behin, zure helbide elektronikoa egiaztatu behar duzu. Hona egiaztapen-esteka bat bidali dugu", + "components.verify_mail.paragraph": "Geroago egin dezakezu nahi baduzu, baina egiaztatu gabeko kontuek Twake-ren bertsio mugatu baterako sarbidea dute", + "services.console_services.toaster.add_emails_error": "Errore bat gertatu da mezu elektronikoak gehitzean", + "services.console_services.toaster.add_email_error_message": "Errore bat gertatu da {{$1}} gehitzean", + "scenes.apps.drive.default_link_name": "Izenbururik gabe", + "components.emoji_picker.input_search_placeholder": "Bilatu", + "services.apps.messages.message_editor_service.upload_error_toaster": "{{$1}} - Ezin duzu {{$2}} fitxategi baino gehiago gehitu mezu batean", + "scenes.apps.messages.message.parts.deleted_content.text.current_user": "Mezu hau ezabatu duzu", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.version_item": "Bertsioa", + "scenes.app.integrations_parameters.company_applications_table.more_menu.show_application": "Erakutsi", + "scenes.app.integrations_parameters.company_applications_table.title": "Zure enpresan instalatuta", + "app.state.recoil.hooks.use_current_company_applications.toaster_delete": "Behar bezala ezabatu da {{$1}} zure enpresatik", + "scenes.apps.account.account.emails": "Posta elektronikoak", + "scenes.apps.account.account.main_email": "Posta elektroniko nagusia", + "scenes.apps.account.notifications.sound": "Soinu jakinarazpena", + "scenes.app.popup.appsparameters.pages.application_title": "Aplikazio", + "scenes.app.popup.appsparameters.pages.danger_zone_label": "Zona arriskutsua", + "scenes.app.popup.appsparameters.pages.description_label": "Deskribapena", + "scenes.app.popup.appsparameters.pages.developped_apps_subtitle": "Enpresak garatutako aplikazioak", + "scenes.app.popup.appsparameters.pages.string_information": "Kate honek zure aplikazioa identifikatzen du eta mezuen komandoetan erabiliko da.", + "scenes.app.popup.workspaceparameter.admin_manager_current_status": "Lan-eremuaren administratzailea zara.", + "scenes.app.popup.workspaceparameter.pages.developped_apps_small_text": "Enpresak garatutako aplikazioak", + "scenes.apps.drive.viewer.edit_with_button": "Editatu {{$1}}", + "services.apps.calendar.move_icon": "Mugitu", + "scenes.apps.board.display_as": "Erakutsi gisa", + "scenes.app.popup.workspace.create_temp": "Sortu aldi baterako kontua", + "general.re_send": "Berriz bidali", + "general.verify": "Egiaztatu", + "scenes.app.popup.workspaceparameter.edit_from_console": "Ikusi Kontsolan", + "scenes.apps.calendar.modals.title_placeholder": "Izenburua", + "scenes.apps.account.message_temporary": "Aldi baterako kontu batek Twake-ko kontu arrunt baten moduan funtzionatzen du, baina pasahitza sortzen duzu eta behar izanez gero berrezarri ahal izango duzu.", + "scenes.app.popup.appsparameters.pages.danger_zone_small_text": "Ezin duzu aplikazio hau ezabatu argitaratzen bada.", + "scenes.app.popup.appsparameters.pages.error_app_simple_name_message": "Zure aplikazioaren izen sinplifikatua beste aplikazio batek erabiltzen du dagoeneko. Mesedez, aldatu.", + "scenes.app.workspaces.welcome_page.see_you_soon": "Laster arte!", + "scenes.app.workspaces.welcome_page.try_again": "Saiatu berriro", + "scenes.app.workspaces.welcome_page.twake_team": "Esnatu", + "scenes.app.workspaces.welcome_page.welcome_header": "Ongi etorri Twake-ra!", + "scenes.app.popup.userparameter.pages.private_message_content.hide": "Ezkutatu mezu pribatuen edukia", + "scenes.no_panic": "Ez zaitez izutu! Besterik gabe, kargatu orri hau Twake konpontzeko.", + "scenes.app.workspaces.components.skip": "Saltatu", + "components.on_boarding.company_billing_banner.link": "enpresaren harpidetza plana", + "components.on_boarding.popups.blocked_company.title": "Zure enpresa blokeatuta dago ordainketa-arazo bat dela eta", + "scenes.app.channelsbar.currentuser.disabling_notifications": "Desgaitu 1 orduz", + "scenes.app.popup.appsparameters.pages.app_update": "Eguneratu aplikazioa {{$1}} (aplikazioa {{$2}} aldiz erabiltzen da).", + "scenes.app.popup.appsparameters.pages.remove_app_from_workspace": "Kendu lan-eremutik", + "scenes.app.popup.appsparameters.pages.show_button": "Erakutsi", + "scenes.client.channelbar.channelmemberslist.tag": "Zuk", + "scenes.join.loading": "Kargatzen…", + "scenes.join.wrong_link_title": "Esteka hau jada ez dago erabilgarri", + "scenes.join.wrong_link_description": "Eskatu enpresa honetan sartzera gonbidatu zaituenari esteka berri bat edo sortu zure enpresa", + "scenes.join.create_the_company_button": "Sortu enpresa", + "scenes.join.join_workspace_from_company": "Sartu {{$1}} {{$2}}-tik!", + "scenes.join.twake_description": "Twake zure taldearen produktibitatea hobetzeko kode irekiko lan-espazio digitala da", + "scenes.join.login_first_button": "Hasi saioa edo sortu kontu bat lehenik", + "scenes.join.join_the_team_button": "Sartu taldean", + "scenes.apps.tasks.connectors_menu": "Konektoreak...", + "scenes.app.workspaces.create_company.group_data.group_size.10_50": "11 - 49 erabiltzaile", + "scenes.app.popup.userparameter.pages.private_message_content.show": "Erakutsi mezu pribatuen edukia", + "scenes.app.workspaces.create_company.group_data.group_main_activity.printing_paper": "Inprimaketa / Papera", + "scenes.app.workspaces.create_company.group_data.group_type.university_school": "Unibertsitatea edo eskola", + "scenes.apps.messages.left_bar.stream.remove_from_favorites": "Kendu gogokoetatik", + "scenes.app.popup.appsparameters.pages.remove_app": "Ezabatu {{$1}} aplikazioa betiko.", + "scenes.apps.calendar.ics_download_menu": "Deskargatu ICS fitxategi bat", + "general.help": "Laguntza", + "scenes.apps.messages.left_bar.stream.notifications.me": "{{$1}} soilik", + "scenes.apps.drive.navigators.navigator_content.files": "Fitxategiak", + "scenes.app.popup.workspaceparameter.pages.access_apps": "Sartu zure aplikazio eta konektoreak", + "scenes.apps.calendar.calendar.week_btn": "Astea", + "general.update": "Eguneratu", + "scenes.apps.messages.message.activity_message.a_created_channel_tab": "{{$1}} {{$2}} fitxa berri bat gehitu du {{$3}}", + "components.calendar.repetition.custom_recurrence": "Errepikapen pertsonalizatua", + "general.confirm": "Berretsi", + "general.connexion_status.connected": "Sarean zaude", + "scenes.apps.tasks.list_modal.archive_all_tasks": "Zeregin guztiak artxibatu", + "scenes.login.forgot_password.text2": "9 digituko kodea jasoko duzu. Mesedez, sartu beheko eremuan jarraitzeko.", + "general.back": "Itzuli", + "general.remove": "Kendu", + "general.connexion_status.connecting": "Berriro konektatzen…", + "scenes.app.workspaces.create_company.group_data.group_main_activity.machinery_automotive": "Makineria / Automozioa", + "scenes.apps.drive.trash": "Zaborrontzia", + "components.locked_features.locked_guests_popup.title": "Gonbidatuen funtzioa blokeatuta dago", + "scenes.app.workspaces.create_company.group_data.group_size.100_500": "100 - 499 erabiltzaile", + "components.drive_dropzone.uploading": "Kargatzen...", + "scenes.app.workspaces.create_company.group_data.group_main_activity.electronics_electricity_energy": "Elektronika / Elektrizitatea / Energia", + "scenes.login.create_account.username": "Erabiltzaile izena", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_edition": "Aldatu izena {{$1}}", + "components.connectorslistmanager.add_connectors": "Gehitu konektoreak", + "scenes.app.popup.workspaceparameter.pages.installed_apps_information": "Laneko eremu honetan instalatutako aplikazioak {{$1}}", + "scenes.app.popup.workspaceparameter.pages.quit_workspace_menu": "Utzi lan-eremu hau", + "scenes.app.popup.appsparameters.pages.publication_description": "Zehaztu zure aplikazioaren ikusgarritasuna.", + "scenes.app.popup.appsparameters.pages.event_subtitle": "Gertaerak", + "scenes.app.channelsbar.modify_channel_menu": "Editatu kanala", + "scenes.app.channelsbar.read_sign": "Markatu irakurritako gisa", + "scenes.app.channelsbar.currentuser.collaborateurs": "Erabiltzaileak", + "scenes.app.channelsbar.currentuser.workspace_info": "{{$2}} taldeko {{$1}} lan eremuan zaude", + "scenes.login.home.email": "Posta elektronikoa", + "general.connexion_status.disconnected": "Lineaz kanpo zaude", + "scenes.login.home.title": "Hasi saioa Twake-n", + "scenes.app.integrations_parameters.title": "Integrazioak", + "scenes.app.integrations_parameters.applications_table.name": "Izena", + "scenes.app.integrations_parameters.applications_table.title": "Beste integrazio batzuk", + "scenes.app.integrations_parameters.applications_table.search_placeholder": "Bilatu aplikazioa", + "scenes.app.integrations_parameters.company_application_popup.tag": "Instalatua", + "scenes.app.integrations_parameters.company_application_popup.btn": "Instalatu", + "scenes.app.integrations_parameters.company_application_popup.tab_btn_info": "Informazioak", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.description_item": "Deskribapena", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.website_item": "Webgunea", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.created_item": "Sortze data", + "application.load.longer": "Zerbitzariak uste baino denbora gehiago behar du erantzuteko, mesedez itxaron edo berriro kargatu orria...", + "scenes.app.side_app.messages_thread_title": "{{$1}} β€’ Mezuen haria", + "scenes.app.workspaces.create_company.group_data": "Konfiguratu zure talde berria", + "scenes.app.workspaces.create_company.group_data.group_type": "Talde mota", + "scenes.app.workspaces.create_company.group_data.group_type.company": "Enpresa edo enpresa saila", + "components.calendar.repetition.on": "On", + "components.calendar.repetition.after": "Ondoren", + "components.calendar.repetition.days": "eguna(k)", + "components.calendar.repetition.weeks": "astea(k)", + "components.calendar.repetition.months": "hilabetea(k)", + "components.calendar.repetition.years": "urtea(k)", + "components.calendar.repetition.occurrence": "Gertaera(k)", + "scenes.app.workspaces.create_company.group_data.title": "Azkar ibiliko gara; informazio estatistiko bat besterik ez dugu behar.", + "scenes.app.channelsbar.currentuser.company_messages_counter_header": "Mezuen zenbakia", + "scenes.app.channelsbar.currentuser.company_messages_counter_info": "Twake-ren doako bertsioan, ezin duzu {{$1}} mezu berriagoak baino gehiago sartu.", + "scenes.app.channelsbar.currentuser.company_messages_counter_link": "Erakutsi plan gehiago", + "scenes.app.channelsbar.channelsuser.new_private_discussion": "Eztabaida pribatu berria", + "scenes.app.channelsbar.channelsuser.no_private_message_invite_collaboraters": "Ez dago mezu pribaturik. Gonbidatu erabiltzaileak!", + "scenes.app.channelsbar.channelsuser.private_messages": "Mezu zuzenak", + "scenes.app.channelsbar.channelsworkspace.channel_title": "KANALAK", + "scenes.app.channelsbar.channelsworkspace.channel_title.favorite": "GOGOKOOAK", + "scenes.app.channelsbar.channelsworkspace.create_channel": "Sortu kanal bat", + "scenes.app.channelsbar.channelsworkspace.no_channel": "Oraindik ez zara sartu inongo kanalean", + "scenes.app.channelsbar.guest_management": "Gonbidatuen kudeaketa", + "scenes.app.channelsbar.unread_sign": "Markatu irakurri gabeko gisa", + "scenes.app.channelsbar.channel_leaving": "Irten kanala", + "scenes.app.channelsbar.channel_removing": "Ezabatu kanala", + "scenes.app.channelsbar.company_invitation_alert_subtitle": "Kanal hauek zure negoziora inporta ditzakezu antolatuta egoteko marko honetan klik eginez.", + "scenes.app.channelsbar.company_invitation_alert_title": "Enpresara gonbidatuta zaude ", + "scenes.app.popup.appsparameters.pages.api_parameters_label": "API ezarpenak", + "scenes.app.popup.appsparameters.pages.app_name_label": "Aplikazioaren izena", + "scenes.app.popup.appsparameters.pages.app_modification_right": "Enpresa honetako kudeatzaile guztiek aplikazio hau editatu ahal izango dute.", + "scenes.app.popup.appsparameters.pages.app_privileges_information": "Definitu zure aplikazioak zer edita eta irakur dezakeen.", + "scenes.app.popup.appsparameters.pages.app_privileges_label": "Aplikazio-pribilegioak", + "scenes.app.popup.appsparameters.pages.apps_title": "Zure aplikazioak eta konektoreak", + "scenes.app.popup.appsparameters.pages.automatique_label": "Automatikoa", + "scenes.app.popup.appsparameters.pages.automatique_option_information": "'Automatiko' aktibatzen baduzu, aplikazio hau automatikoki gehituko da enpresa honen hurrengo lan-eremuetan.", + "scenes.app.popup.appsparameters.pages.autorised_ip_adresses_label": "Baimendutako IP helbideak", + "scenes.app.popup.appsparameters.pages.available_publication_alert": "Zure aplikazioaren argitalpena Twake taldeak baliozkotzeko zain dago.", + "scenes.app.popup.appsparameters.pages.button_force": "Indarra enpresa osoan", + "scenes.app.popup.appsparameters.pages.call_event_handlers": "'{{$1}}' eta '{{$2}}' id motako gertaera '{{$3}}' pasiboekin", + "scenes.app.popup.appsparameters.pages.company_label": "Enpresaren jabea", + "scenes.app.popup.appsparameters.pages.configuration_label": "Konfigurazioa", + "scenes.app.popup.appsparameters.pages.create_app_button": "Sortu aplikazio bat", + "scenes.app.popup.appsparameters.pages.create_my_app": "Sortu nire aplikazioa", + "scenes.app.popup.appsparameters.pages.current_informations_apps_connectors": "Oraindik ez duzu aplikaziorik sortu. Aplikazio edo konektore bat sortu aurretik, ziurtatu ez dagoela gure aplikazioen merkatuan.", + "scenes.app.popup.appsparameters.pages.danger_zone_description": "Ezabatu aplikazioa", + "scenes.app.popup.appsparameters.pages.dispalyed_parameters_description": "Zure aplikazioa non ikusgai egongo den definitzeko aukera ematen du.", + "scenes.app.popup.appsparameters.pages.displayed_parameters_label": "Bistaratzeko ezarpenak", + "scenes.app.popup.appsparameters.pages.error_user_code": "akatsa", + "scenes.app.popup.appsparameters.pages.ok_user_code": "Ados", + "scenes.app.popup.appsparameters.pages.optimal_format": "Formatu optimoa: 48x48px.", + "scenes.app.popup.appsparameters.pages.parameters_form_small_text": "Argitaratu gabeko aplikazioak zure enpresan bakarrik funtzionatuko du. Twake-ren erabiltzaile guztientzat erabilgarri jarri nahi baduzu, aktibatu aukera hau.", + "scenes.app.popup.appsparameters.pages.public_availability_application": "Eskaera publikoa", + "scenes.app.popup.appsparameters.pages.public_login_label": "Identifikatzaile publikoa", + "scenes.app.popup.appsparameters.pages.publication_label": "Argitalpena", + "scenes.app.popup.appsparameters.pages.publish_app_label": "Argitaratu aplikazioa", + "scenes.app.popup.appsparameters.pages.read_privileges_label": "Irakurri pribilegioak", + "scenes.app.popup.appsparameters.pages.remove_app_from_company": "Kendu enpresa osotik", + "scenes.app.popup.appsparameters.pages.status_tilte": "Estatu", + "scenes.app.popup.appsparameters.pages.title_tester": "Twakecode probatzailea", + "scenes.app.popup.appsparameters.pages.url_reception_events_label": "Gertaeren harreraren URLa", + "scenes.app.popup.appsparameters.pages.waiting_availability_application": "Zain...", + "scenes.app.popup.appsparameters.pages.website_label": "Webgunea", + "scenes.app.popup.appsparameters.pages.write_privileges_label": "Idatzi pribilegioak", + "scenes.app.popup.appsparameters.pages.error_app_update_message": "Errore bat gertatu da aplikazioa eguneratzean.", + "scenes.app.popup.appsparameters.pages.remove_app_button": "Ezabatu aplikazioa", + "scenes.app.popup.appsparameters.pages.update_button": "Eguneratu", + "scenes.app.popup.createworkspacepage.add_subtitle": "Leku gehiago behar duzu?", + "scenes.app.popup.createworkspacepage.create_new_workspace": "Sortu lan-eremu berri bat", + "scenes.app.popup.userparameter.pages.notif_content_label": "Jakinarazpenen edukia", + "scenes.app.mainview.quick_search_placeholder": "Bilaketa azkarra", + "scenes.app.popup.workspaceparameter.admin_current_status": "Administratzailea zara.", + "scenes.app.popup.workspaceparameter.manager_current_status": "Enpresaren administratzailea zara.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace": "Ezabatu lan-eremua", + "scenes.app.popup.workspaceparameter.pages.error_workspace_member": "Laneko eremuan bakarrik egon behar zara kentzeko. Kendu kolaboratzaileak eta saiatu berriro.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace_description": "Lan-eremu hau ezabatu nahi duzula berresteko, idatzi beheko izena eta sakatu Ezabatu.", + "scenes.app.popup.workspaceparameter.pages.enter": "Sartu ", + "scenes.app.popup.workspaceparameter.pages.moderator_status": "Laneko moderatzailea", + "scenes.app.popup.workspaceparameter.pages.alert_impossible_removing": "Ezin duzu lan-eremutik irten, azken administratzailea zarelako. Administratzaile berri bat defini dezakezu edo lan-eremu hau ezabatu/artxibatu dezakezu.", + "scenes.app.popup.workspaceparameter.pages.all_apps_small_text": "Aplikazio guztiak", + "scenes.app.popup.workspaceparameter.pages.apps_company_small_text": "Zure enpresaren aplikazioak", + "scenes.app.popup.workspaceparameter.pages.apps_research_title": "Bilatu aplikazioak", + "scenes.app.popup.workspaceparameter.pages.apps_small_text": "Lan-eremu honen aplikazioak", + "scenes.app.popup.workspaceparameter.pages.back_to_search_button": "Itzuli bilaketara", + "scenes.app.popup.workspaceparameter.pages.installed_apps_message": "Enpresako beste eremu batzuetan instalatutako aplikazioak {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_subtitle": "Instalatutako aplikazioak", + "scenes.app.popup.workspaceparameter.pages.invitation_error": "Errore bat gertatu da erabiltzaile hauek gonbidatzean: ", + "scenes.app.popup.workspaceparameter.pages.invited_guest_check_message": "Egiaztatu erabilitako erabiltzaile-izena edo posta elektronikoa baliozkoa dela.", + "scenes.app.popup.workspaceparameter.pages.logo_modify_description": "Editatu lan-eremu honen irudia", + "scenes.app.popup.workspaceparameter.pages.logo_subtitle": "Logotipoa", + "scenes.app.popup.workspaceparameter.pages.name_description": "Aldatu lan-eremu honen izena", + "scenes.app.popup.workspaceparameter.pages.no_access": "Sarbiderik ez.", + "scenes.app.popup.workspaceparameter.pages.no_app_information": "Ez duzu aplikaziorik lan-eremu honetan", + "scenes.app.popup.workspaceparameter.pages.read_access_subtitle": "Irakurtzeko sarbidea", + "scenes.app.popup.workspaceparameter.pages.remove_from_company_text": "Kendu enpresa osotik", + "scenes.app.popup.workspaceparameter.pages.research_by": "Bilatu aplikazioak izenaren eta kategorien arabera", + "scenes.app.popup.workspaceparameter.pages.webhooks_access_subtitle": "Webhooketarako sarbidea", + "scenes.app.popup.workspaceparameter.pages.weight_max_small_text": "Gehienezko tamaina 5 MB.", + "scenes.app.popup.workspaceparameter.pages.withdraw_button": "Kendu lan-eremu honetatik", + "scenes.app.popup.workspaceparameter.pages.worspace_notif": "lan-eremua", + "scenes.app.popup.workspaceparameter.pages.write_access_subtitle": "Idazteko sarbidea", + "scenes.apps.messages.message.pin_button": "Ainguratu mezua", + "scenes.apps.messages.message.unpin_button": "Kendu mezua", + "scenes.apps.messages.message.copy_link": "Kopiatu esteka mezurako", + "scenes.apps.messages.message.pinned": "Ainguratuta", + "scenes.apps.messages.message.remove_button": "Ezabatu", + "scenes.apps.messages.message.reply_button": "Erantzun", + "scenes.apps.messages.message.save_button": "Gorde", + "scenes.apps.messages.message.show_button": "Bistaratzea", + "scenes.apps.messages.message.show_responses_button": "Ikusi erantzun guztiak", + "scenes.apps.messages.message.types.first_channel_message_text": "Hau da kanalaren lehen mezua", + "scenes.apps.messages.message.types.first_message_text": "Hau da lehen mezua", + "scenes.apps.messages.messageslist.get_writing_user": "idazten ari da...", + "scenes.apps.messages.messageslist.get_writing_users": "idazten ari dira...", + "scenes.apps.messages.messageslist.go_last_message_button.new_messages": "Mezu berriak", + "scenes.error_on_twake": "\"Houston arazo bat dugu\"", + "scenes.help_us": "Hala ere, errore hau konpontzen lagundu nahi badiguzu, bidali mezu bat behean: ", + "scenes.login.verifymail.alert": "Zure e-maila egiaztatzen ari gara!", + "scenes.login.verifymail.error_message": "Akats bat gertatu da", + "scenes.login.verifymail.signin_button": "Saioa hasi", + "scenes.login.verifymail.success": "Zure e-posta behar bezala egiaztatu da!", + "scenes.login.verifymail.verification_waiting": "Egiaztapenaren zain...", + "services.apps.calendar.deadline_icon": "Epemuga", + "services.apps.calendar.event_icon": "Gertaera", + "services.apps.calendar.reminder_icon": "Oroigarria", + "services.apps.messages.no_app": "Aplikazio hau ez da existitzen.", + "services.apps.messages.no_command_possible": "Ezin dugu '{{$1}}' komandoa exekutatu '{{$2}}' ez delako existitzen edo ez duelako komandoak sortzeko aukera ematen.", + "services.user.notification_parameters_update_alert": "Jakinarazpenen ezarpenak eguneratu dira.", + "services.user.update_password_alert": "Zure pasahitza eguneratu da.", + "scenes.apps.calendar.unconfigured_tab": "Fitxa hau ez dago konfiguratuta oraindik.", + "scenes.apps.drive.top_menu_more": "Gehiago", + "scenes.apps.drive.top_menu_no_items": "{{$1}} elementuak", + "scenes.apps.messages.new_thread": "Hasi eztabaida berri bat", + "scenes.apps.account.account.save": "Gorde kontua", + "scenes.apps.account.message_user_signin": "Zure erabiltzaileak edonoiz hasi dezake saioa e-posta bera erabiliz eta behin-behineko kontua kontu arrunt batera alda dezake.", + "scenes.app.mainview.link_expired": "Esteka publiko hau baliogabea da edo iraungi egin da.", + "scenes.app.mainview.create_account": "Sortu zure lan-eremua doan ", + "scenes.apps.calendar.modals.reminder_add": "Gehitu abisua", + "scenes.apps.parameters.workspace_sections.members.invite_all": "Gonbidatu guztiak", + "scenes.app.taskpicker.select": "Hautatu", + "scenes.apps.tasks.no_connector": "Ez dago konektorerik", + "components.attachmentpicker.add_attachment": "Gehitu eranskinak", + "components.input.copied": "Kopiatua", + "components.drive.navigators.directory_not_found": "Direktorioa ez da aurkitu.", + "components.drive.right_preview.suppress_link": "Ezabatu esteka", + "components.drive.right_preview.create_link": "Sortu sarbide-esteka bat", + "components.drive.moove_here": "Mugitu hona", + "components.drive.modify_uslist": "Erabiltzaileen zerrenda aldatu", + "components.tagpicker.tag_name": "Etiketa izena", + "components.searchpopup.only_pinned": "Ainguratutako mezuak soilik", + "components.alert.confirm": "Berretsi zure ekintza", + "components.alert.confirm_click": "Berretsi zure ekintza Ados sakatuz.", + "components.searchpopup.tasks": "Zereginak", + "scenes.app.mainview.advanced_search_placeholder": "Bilaketa aurreratua", + "components.searchpopup.hide_filters": "iragazkiak ezkutatu", + "components.searchpopup.show_filters": "iragazkiak erakutsi", + "components.searchpopup.load_more": "Kargatu emaitza gehiago", + "general.more": "Gehiago", + "scenes.apps.board.archived_tasks": "Artxibatutako zereginak ({{$1}})", + "scenes.apps.board.active_tasks": "Zeregin aktiboak", + "scenes.apps.board.new_task": "+ Zeregin berria", + "scenes.apps.board.all_boards": "Batzorde guztiak", + "components.userlistmanager.no_users": "Erabiltzailerik ez.", + "components.reminder.minutes_bef": "minutu lehenago", + "services.console_services.toaster.success_invite_emails": "Gehitu dira {{$1}} erabiltzaile(k)", + "scenes.client.channels_bar.modals.guest_management.title": "Kudeatu gonbidatuak {{$1}}-n", + "scenes.client.channels_bar.modals.guest_management.input_placeholder": "Bilatu gonbidatuak edo zain dauden mezu elektronikoak", + "scenes.client.channels_bar.modals.guest_management.tips": "Hasi mezu elektronikoak gehitzen edo bilatzen goiko sarrera erabiliz", + "scenes.client.channels_bar.modals.parts.channel_member_row.label.pending_email": "Bidalitako posta", + "general.user.role.company.admin": "Enpresako administratzailea", + "general.user.role.company.guest": "Gonbidatua", + "general.user.deleted": "Ezabatutako kontua", + "components.richtexteditor.toolbar.bold": "Lodia", + "components.richtexteditor.toolbar.underline": "Azpimarratu", + "components.richtexteditor.toolbar.italic": "Etzana", + "components.richtexteditor.toolbar.strikethrough": "Markatua", + "components.richtexteditor.toolbar.code": "Kodea", + "components.richtexteditor.toolbar.unordered-list": "Buletaren zerrenda", + "components.richtexteditor.toolbar.ordered-list": "Zerrenda ordenatua", + "components.richtexteditor.toolbar.blockquote": "Blokeoa", + "components.richtexteditor.toolbar.code-block": "Kode blokea", + "components.locked_features.locked_history_banner.title": "Mezuen mugara iritsi berri zara", + "components.locked_features.locked_history_banner.description": "Zure enpresak mezu asko ditu! Berritu orain zure mezuen historia guztia atzitzeko.", + "components.locked_features.locked_history_banner.button": "Gehiago ikasi", + "components.locked_features.locked_guests_popup.subtitle": "Ezaugarri hau ez dago eskuragarri Twake doako bertsioan", + "components.locked_features.locked_guests_popup.description": "Aupa!! Kanpoko erabiltzaileak zure laneko gunera gonbidatu nahi dituzula dirudi. Baliteke zure plana berritzea kontuan hartu nahi izatea gonbidatuekin eta kanpoko bazkideekin elkarlanean aritu nahi baduzu. Arakatu gure prezio-aukerak eta hautatu aukerarik onena zure taldeko lankidetza-beharretarako.", + "components.locked_features.locked_guests_popup.learn_more_button": "Gehiago ikasi", + "components.locked_features.locked_guests_popup.skip_for_now_button": "Saltatu orain", + "components.locked_features.locked_guests_popup.or": "Edo", + "components.on_boarding.company_billing_banner.admin_or_owner_text": "Arazo bat dago zure enpresaren harpidetzarekin. Mesedez, begiratu zureari", + "components.on_boarding.company_billing_banner.guest_or_member_text": "Arazo bat dago zure enpresaren harpidetzarekin. Mesedez, jarri harremanetan enpresaren jabearekin edo administratzailearekin!", + "components.on_boarding.popups.blocked_company.description": "Twake-rako harpidetza iraungi da. Mesedez, jarri harremanetan zure enpresaren jabearekin edo administratzailearekin hura berritzeko eta zure taldearekin berriro komunikatu ahal izateko!", + "components.on_boarding.popups.blocked_company.learn_more_text": "Enpresen harpidetza-planari buruz gehiago jakin nahi duzu?", + "components.on_boarding.popups.blocked_company.company_subscription_plan_button": "Klikatu hemen", + "components.on_boarding.popups.blocked_company.or": "Edo", + "components.on_boarding.popups.blocked_company.company_selector": "Aldatu beste enpresa batera", + "scenes.apps.tasks.select_user_button": "Ikusi beste erabiltzaile baten zereginak", + "scenes.apps.tasks.select_user": "Bilatu erabiltzailea", + "scenes.apps.messages.input.attach_file.from_computer": "Ordenagailutik", + "scenes.apps.messages.message.parts.deleted_content.text": "{{$1}}-ek bere mezua ezabatu du", + "components.member.user_parts.and_more_user_text": " eta {{$1}} erabiltzaile gehiago", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_link": "Sortu kanal pribatu bat", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_text": " horren ordez", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_input_placeholder": "Ezin duzu 10 erabiltzaile baino gehiago gehitu", + "general.uploading": "Kargatzen", + "components.upload.drop_files.toaster.error": "Ezin duzu {{$1}} fitxategi baino gehiago kargatu", + "components.emoji_picker.categories.frequently_used": "Maiz erabiltzen da", + "components.emoji_picker.categories.smileys_and_people": "Irribarreak eta jendea", + "components.emoji_picker.categories.animals_and_nature": "Animaliak eta Natura", + "components.emoji_picker.categories.food_and_drink": "Janaria eta edaria", + "components.emoji_picker.categories.activity": "Jarduera", + "components.emoji_picker.categories.travel_and_places": "Bidaiak eta Lekuak", + "components.emoji_picker.categories.objects": "Objektuak", + "components.emoji_picker.categories.symbols": "Sinboloak", + "components.emoji_picker.categories.flags": "Banderak", + "components.emoji_picker.categories.search_result": "Bilaketa-emaitzak", + "components.emoji_picker.categories.not_found": "Ez da emojirik aurkitu", + "scenes.app.popup.workspaceparameter.pages.workspace_partner_tabs.members.table.tags": "Rola", + "general.email": "Posta elektronikoa", + "components.locked_features.locked_workspace_popup.title": "Ezin duzu lan-eremu gehiago sortu", + "components.locked_features.locked_workspace_popup.text": "Aupa!! Zure enpresan lan-eremu berri bat sortu nahi duzu? Baliteke plana berritzea kontuan hartu nahi izatea. Arakatu gure prezio-aukerak eta hautatu aukerarik onena zure taldeko lankidetza-beharretarako.", + "components.locked_features.locked_only_office_popup.text": "Aupa!! Twake-tik fitxategia editatu nahi duzula dirudi. Baliteke zure plana berritzea kontuan hartu nahi izatea bulegoko fitxategien inguruan elkarlanean aritu nahi baduzu. Arakatu gure prezio-aukerak eta hautatu aukerarik onena zure taldeko lankidetza-beharretarako.", + "components.locked_features.locked_drive_popup.title": "Gidatzeko mugara iritsi berri zara", + "components.locked_features.locked_drive_popup.subtitle": "Doako bertsioan, 6GB bakarrik gorde ditzakezu.", + "general.resume": "Jarraitu", + "general.pause": "Etenaldia", + "\"": "\"", + "login.create_account": "Kontua sortu", + "login.login_error": "Errorea saioa hastean", + "'": "'", + "scenes.app.workspaces.welcome_page.no_workspace_subtitle": "Inork ez zaitu laneko gune batera gonbidatu oraindik.", + "scenes.apps.messages.message.types.no_message_in_thread": "Oraindik inork ez zuen erantzun.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.label": "Lan-eremu lehenetsia", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.description": "Gonbidatu automatikoki laneko erabiltzaile guztiak kanal honetara", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.title": "{{$1}} ezabatzera zoaz", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.alert_total_members": "Oraindik {{$1}} kideak dituzu {{$2}}-n. Kide guztiak kendu behar dituzu lan-eremu hau ezabatu ahal izateko.", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.checkbox": "Ulertzen dut nire lan-eremuko mezu eta fitxategi guztiak ezabatuko direla.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.max_size": "Gehienezko logotipoaren tamaina 5 MB da", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.bad_format": "Formatu txarra, png gif eta jpg bakarrik onartzen dira", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.unknown": "Errore ezezaguna", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.prefix": "Errorea", + "scenes.app.channelsbar.currentuser.reset": "Berrezarri", + "components.rich_text_editor.plugins.suggestions.default_message.display_results": "Idatzi gutxienez hiru letra erabiltzaileak erakusteko", + "components.rich_text_editor.plugins.suggestions.default_message.no_user_found": "Ez da erabiltzailerik aurkitu", + "components.rich_text_editor.plugins.suggestions.default_message.no_emoji_found": "Ez da emojirik aurkitu", + "components.rich_text_editor.plugins.suggestions.default_message.no_command_found": "Ez da komandorik aurkitu", + "scenes.app.messages.input.parts.is_writing.message.user_is_writing": "{{$1}} idazten ari da...", + "scenes.app.messages.input.parts.is_writing.message.users_are_writing": "{{$1}} eta {{$2}} idazten ari dira...", + "scenes.app.messages.input.parts.is_writing.message.users_and_more_are_writing": "{{$1}}, {{$2}} eta {{$3}} erabiltzaile gehiago idazten ari dira...", + "components.locked_features_components.locked_invite_alert.message_part_1": "Zure enpresak {{$1}} kideen gehienezko mugara iritsi da. Mesedez ", + "components.locked_features_components.locked_invite_alert.message_link": "berritu zure enpresa", + "components.locked_features_components.locked_invite_alert.message_part_2": " kide gehiago gonbidatzeko.", + "components.locked_features_components.locked_invite_alert.message_magic_link": " jarri harremanetan zure enpresaren jabearekin edo administratzailearekin.", + "views.client.popup.workspace_parameter.pages.workspace_members.link_to_console": "Ikusi nire konpainiako kide guztiak kontsolan", + "scenes.app.popup.appsparameters.pages.amazing_app_description": "Deskribatu zure aplikazioa hitz gutxitan", + "scenes.app.popup.appsparameters.pages.application_creator.title": "Integrazio berria", + "scenes.app.popup.appsparameters.pages.application_creator.checkbox": "Ulertzen dut enpresa honen jabeak eta administratzaileak aplikazio hau aldatu eta argitaratu ahal izango dutela.", + "twake.application.access.title": "Hautatu zure aplikaziorako esparru egokiak.", + "twake.application.access.no_default_scopes_available'": "Integrazio honek ez du {{$1}} sarbiderik", + "scenes.app.popup.appsparameters.pages.application_editor.help_link": "Twake APIaren dokumentazioa", + "scenes.app.popup.appsparameters.pages.application_editor.help_text": "Hauek nola bete ez badakizu, joan hona ", + "scenes.app.popup.appsparameters.pages.app.private_key": "Gako pribatua", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed": "Behar bezala kendu da aplikazioa {{$1}}!", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed_error": "Errore bat gertatu da {{$1}} aplikazioa kentzean!", + "scenes.app.popup.appsparameters.pages.application_editor.application_published": "Arrakastaz {{$1}} aplikazioa!", + "scenes.app.integrations_parameters.add_application": "Integrazio berria", + "scenes.app.integrations_parameters.company_applications_table.more_menu.developer_settings": "Garatzaileen ezarpenak", + "components.rich_text_editor.plugins.suggestions.loading": "Gehiagoren bila", + "components.open_desktop_popup.subtitle": "Twake aplikazioan ireki da", + "components.open_desktop_popup.open_here_link": "Ireki hemen ordez", + "molecules.download_banner.title": "Atera etekinik handiena Twake-ri, deskargatu mahaigaineko aplikazioa orain", + "molecules.download_banner.download_button": "Deskargatu mahaigaineko aplikazioa", + "scenes.app.channelsbar.channel_copy_link": "Kopiatu kanalaren esteka", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.success.update": "Behar bezala eguneratu da", + "components.searchpopup.no_results_for": "Ez zen emaitzarik izan", + "components.searchpopup.try_new_search": "Saiatu bilaketa berri bat", + "components.searchpopup.all": "Denak", + "components.searchpopup.chats": "Txatak", + "components.searchpopup.media": "Komunikabideak", + "components.searchpopup.files": "Fitxategiak", + "components.searchpopup.recent_chats": "Azken txatak", + "components.searchpopup.recent_media": "Azken komunikabideak", + "components.searchpopup.recent_files": "Azken fitxategiak", + "components.searchpopup.recent_channels_and_contacts": "Azken kanalak eta kontaktuak", + "components.searchpopup.header_title": "Bilatu", + "components.searchpopup.scope.company": "konpainia guztietan", + "components.searchpopup.scope.channel": "kanal honetan", + "components.searchpopup.channels": "Kanalak", + "components.searchpopup.messages": "Mezuak", + "scenes.client.channelbar.channelmemberslist.invite_email_button": "Gehitu kanalera gonbidatu gisa soilik", + "scenes.client.join_public_channel.info": "Ez zara zuzeneko kanal honetako kide. Egin klik botoi honetan eztabaida hasteko.", + "components.searchpopup.start_search": "Idatzi gako-hitz batzuk bilaketa hasteko.", + "components.searchpopup.see_more": "Gehiago ikusi", + "scenes.client.channelbar.channelmemberslist.search_invite": "Bilatu eta gonbidatu erabiltzaileak kanal honetara", + "scenes.client.channelbar.channelmemberslist.search_invite_notice": "Ez dago kide asko kanal honetan. Bilatu eta gonbidatu erabiltzaileak posta elektronikoz edo izenez.", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace": "Gehitu kanalean eta lan-eremuan kide gisa", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace_confirm": "{{$1}} lan-eremura kide gisa gonbidatu nahi duzu?", + "scenes.client.channelbar.channelmemberslist.search_invite_type_email": "Idatzi posta elektronikoz gonbidatzeko balio duen helbide bat.", + "scenes.client.channelbar.channelmemberslist.pending_section": "Erabiltzaileak gonbidapenaren zain", + "scenes.client.channelbar.channelmemberslist.members_section": "Kanal honetako erabiltzaileak", + "scenes.client.channelbar.channelmemberslist.not_members_section": "Kanal honetan ez dauden erabiltzaileak", + "scenes.client.join_private_channel.info": "Kanal honen edukia mugatuta dago edo ez dago. Mesedez, jarri harremanetan kanal honetako kide batekin gonbidapena jasotzeko.", + "scenes.client.join_public_channel": "Sartu kanal honetan", + "general.yes": "Bai", + "general.no": "Ez", + "components.open_desktop_popup.open_here_link_forever": "Ez saiatu berriro aplikazioa irekitzen", + "components.channel_attachement_list.medias": "Medias", + "components.channel_attachement_list.files": "Fitxategiak", + "components.channel_attachement_list.title": "Kanal-fitxategiak eta euskarriak", + "components.channel_attachement_list.nothing_found": "Hemen oraindik ez dago ezer", + "molecules.message_quote.deleted": "Mezu hau ezabatu egin da", + "scenes.apps.messages.jump": "Salto mezura", + "components.channel_attachement_list.open": "Galeria irekia", + "scenes.apps.account.assistant.title": "Laguntzailea", + "scenes.apps.account.assistant.description": "Twake laguntzaileak Twake-n egiten duzun eguneroko lanari zentzua emateko gai da eta zure egunean zehar lasterbide eta ekintza adimendunak eskaintzen ditu. Laguntzaile https://workathome.linagora.com/ Work@Home ekimenaren parte da eta oraingoz Linagora enpresan bakarrik probatzen ari da eta ikasketa fasean dago. Horrek esan nahi du Twake-ren erabilera datuak bidaliko ditugula gure etorkizuneko laguntzailearen funtzioa trebatzeko.", + "scenes.apps.account.assistant.share.nothing": "Ez partekatu ezer laguntzailearekin (desgaitu laguntzailea)", + "scenes.apps.account.assistant.share.all": "Partekatu dena, mezuak eta fitxategien edukia barne", + "scenes.apps.account.assistant.share.metadata": "Partekatu metadatuak baina ez edukiak", + "scenes.apps.account.assistant.success": "Zure hobespenak arrakastaz eguneratu dira.", + "scenes.apps.account.on_console": "Zure kontu globalaren hobespenak editatzeko, sakatu Joan kontsolara.", + "components.message_seen_by.title": "Mezua ikusi duten erabiltzaileak", + "components.message_seen_by.none_seen_it": "Inork ez du mezua ikusi oraindik", + "components.message_seen_by.btn": "Informazioa", + "molecules.quoted_content.attachements": "{{$1}} eranskinak", + "scenes.apps.messages.message.user_deactivated": "Desaktibatuta dagoen kontu baten artxiboak ikusten ari zara", + "general.user.deactivated": "Erabiltzailea jada ez dago enpresa honetan", + "general.user.connected": "Sarean", + "scenes.app.popup.userparameter.pages.email_notif_delay_quarter_hour": "15 minutu", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_day": "1 egun", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_hour": "1 ordu", + "scenes.app.popup.userparameter.pages.email_notif_delay_never": "Inoiz ez", + "scenes.app.popup.userparameter.pages.notification_sound.defaut": "Lehenetsia", + "scenes.app.popup.userparameter.pages.notification_sound.none": "Bat ere ez", + "scenes.client.channelbar.readonly_channel.checkbox": "Murriztu idazteko gaitasuna", + "scenes.apps.messages.message.forward": "Aurrera", + "components.channelselector.title": "Hautatu kanalak", + "components.channelselector.confirm": "Hautatu $1 kanala(k)", + "components.channelselector.search": "Bilatu kanalak eta eztabaidak", + "scenes.apps.messages.message.forward.title": "Birbidali mezua", + "scenes.apps.messages.message.forward.comment": "Gehitu mezu bat", + "scenes.apps.messages.message.forward.confirm": "Bidali $1 kanalera", + "scenes.apps.messages.message.forward.send": "Mezua birbidali da", + "scenes.app.channelsbar.channel_access.save": "Gorde sarbide-ezarpenak", + "scenes.app.channelsbar.channel_access": "Kanalerako sarbidea", + "scenes.app.channelsbar.channel_access.readonly": "Irakurtzeko soilik kanala", + "scenes.app.channelsbar.channel_access.readonly.info": "Mugatu moderatzaile, administratzaile eta jabeei idaztea.", + "scenes.app.channelsbar.channel_access.visibility": "Ikusgarritasuna publikoa", + "scenes.app.channelsbar.channel_access.visibility.info": "Enpresako gonbidatuak izan ezik edonor sar daiteke.", + "scenes.app.channelsbar.channel_access.default": "Sartu automatikoki", + "scenes.app.channelsbar.channel_access.default.info": "Kide berriak automatikoki gehituko dira hemen.", + "scenes.app.channelsbar.channel_information": "Editatu kanalaren informazioa", + "scenes.app.channelsbar.channel_information.logo.add": "Kargatu argazkia", + "scenes.app.channelsbar.channel_information.logo.remove": "Kendu argazkia", + "scenes.app.channelsbar.channel_information.name": "Kanalaren izena", + "scenes.app.channelsbar.channel_information.description": "Kanalaren deskribapena", + "scenes.app.channelsbar.channel_information.description.placeholder": "Kanalaren deskribapena, markdown erabil dezakezu.", + "scenes.app.channelsbar.channel_information.group": "Txanela taldea", + "scenes.app.channelsbar.channel_information.group.none": "Ez da hautatua", + "scenes.app.channelsbar.channel_information.group.new": "Sortu talde berri bat", + "scenes.app.channelsbar.channel_information.group.save": "Ezarri kanal-taldea $1-en", + "scenes.app.channelsbar.channel_information.group.save_none": "Ez ezarri kanal talderik", + "scenes.app.channelsbar.channel_information.save": "Gorde informazioa", + "components.invitation.invitation_sent.subtitle_location": "Laneko eremuaren ezarpenak > Kideen kudeaketa", + "components.invitation.invitation_sent.link": "Egiaztatu gonbidapenaren egoera", + "scenes.client.channelbar.channelmemberslist.invite_to_workspace": "Gonbidatu {{$1}} lan-eremura ➑", + "components.invitation.reached_limit.text": "zure enpresa barruko gehieneko erabiltzaile kopurura iritsi zara. Handitu harpidetza edo gehitu erabiltzaile hauek gonbidatu gisa", + "components.invitation.allow_anyone_by_email.text": "Utzi @{{$1}} posta elektronikoa duen edonori sartzea lan eremu honetan", + "components.invitation.invitation_channels.button": "Gonbidatu kanaletara", + "components.invitation.invitation_input_list.add": "Gehitu", + "components.invitation.invitation_input_list.member": "Kide", + "components.invitation.invitation_input_list.guest": "Gonbidatua", + "components.invitation.invitation_input_list.placeholder": "Hasi mezu elektroniko bat idazten", + "components.invitation.invitation_sent.title": "Gonbidapenak behar bezala bidali dira", + "components.invitation.invitation_sent.subtitle_status": "Gonbidapenaren egoeraren jarraipena egin dezakezu:", + "components.invitation.invitation_sent.button": "Bidali gonbidapen gehiago", + "components.invitation.invitation_target.invite_as_guests": "Gonbidatu guztiak gonbidatu gisa", + "components.invitation.invitation_target.invite_as_members": "Gonbidatu guztiak kide gisa", + "components.invitation.invitation_target.channels_button": "Gonbidatzeko kanalak", + "components.invitation.workspace_link.text": "Lanerako gonbidapenaren esteka", + "components.invitation.workspace_link.button": "Kopiatu", + "components.invitation.title": "gonbidatu jendea {{$1}}-ra", + "components.invitation.bulk_invitation": "Gonbidapen masiboa", + "components.invitation.button": "Bidali gonbidapenak", + "scenes.client.readonly.info": "Kanal hau irakurtzeko soilik den jarioa da, baina harietan iruzkin dezakezu.", + "scenes.app.channelsbar.channel_information.group.title": "Kanal taldeak", + "components.invitation.custom_role_invitation": "Gonbidapen klasikoa", + "components.invitation.link": "Esteka" +} diff --git a/twake/frontend/public/locales/fi.json b/twake/frontend/public/locales/fi.json new file mode 100644 index 00000000..cf81ba17 --- /dev/null +++ b/twake/frontend/public/locales/fi.json @@ -0,0 +1,1008 @@ +{ + "general.save": "Tallenna", + "general.add": "LisÀÀ", + "general.close": "Sulje", + "general.cancel": "Peruuta", + "general.retry": "YritΓ€ uudelleen", + "general.edit": "Muokkaa", + "general.continue": "Jatka", + "general.back": "Takaisin", + "general.confirm": "Vahvista", + "general.delete": "Poista", + "general.help": "Ohje", + "general.help.support": "Tuki", + "general.help.documentation": "Dokumentaatio", + "general.send": "LΓ€hetΓ€ viesti", + "general.update": "PΓ€ivitΓ€", + "general.remove": "Poista", + "general.connexion_status.disconnected": "Olet yhteydettΓΆmΓ€ssΓ€ tilassa", + "general.connexion_status.connected": "Olet yhteydellisessΓ€ tilassa", + "general.create": "Luo", + "general.connexion_status.connecting": "YhdistetÀÀn uudelleen…", + "scenes.app.workspaces.create_company.group_data.group_type.public_organization": "Julkinen organisaatio", + "scenes.app.workspaces.create_company.group_data.group_size.50_100": "50 - 99 kΓ€yttΓ€jÀÀ", + "scenes.app.workspaces.create_company.group_data.group_size.10_50": "11 - 49 kΓ€yttΓ€jÀÀ", + "scenes.app.workspaces.create_company.group_data.group_size.5000_more": "Yli 5000 kΓ€yttΓ€jÀÀ", + "components.application.messages": "Viestit", + "components.drive_dropzone.uploading": "LΓ€hetetÀÀn...", + "components.user_picker.modal_no_result": "Tuloksia ei lΓΆytynyt", + "components.users_picker.add_me": "LisÀÀ minut", + "scenes.app.header.disconnected": "Et ole yhdistettynΓ€", + "scenes.app.header.disconnected.reload": "Lataa uudelleen", + "scenes.apps.calendar.calendar.week_btn": "Viikko", + "scenes.apps.calendar.event_edition.deadline_tag": "Takaraja", + "scenes.apps.calendar.event_edition.checkbox_all_day": "Koko pΓ€ivΓ€", + "scenes.apps.calendar.calendar_modal.participants": "Osallistujat", + "scenes.apps.calendar.calendar_modal.placeholder": "Nimi", + "scenes.apps.calendar.left.calendars": "Kalenterit", + "scenes.apps.drive.left.search": "Haku", + "scenes.apps.drive.navigators.new_file.untitled": "NimetΓΆn", + "scenes.apps.drive.navigators.new_file.create_file.type": "Tyyppi", + "scenes.apps.drive.navigators.new_file": "Uusi tiedosto", + "scenes.apps.drive.right_preview.operations_delete": "SiirrΓ€ roskakoriin", + "scenes.apps.drive.right_preview.public_link": "Julkinen linkki", + "scenes.apps.messages.messages": "Viestit", + "scenes.apps.messages.chatbox.chat.delete_message": "Poista tΓ€mΓ€ viesti", + "scenes.apps.messages.left_bar.stream_modal.placeholder_name": "Nimi", + "scenes.apps.messages.left_bar.stream.add_to_favorites": "LisÀÀ suosikkeihin", + "scenes.apps.messages.left_bar.stream.notifications": "Ilmoitukset...", + "scenes.apps.messages.left_bar.stream.notifications.all": "MistΓ€ tahansa viestistΓ€", + "scenes.apps.parameters.workspace_sections.workspace": "TyΓΆtila", + "scenes.apps.parameters.group_sections.workspaces": "TyΓΆtilat", + "scenes.apps.parameters.group_sections.apps": "Sovellukset", + "scenes.apps.account.account.menu_title": "Tili", + "scenes.apps.account.account.username": "KΓ€yttΓ€jΓ€nimi", + "scenes.apps.account.account.change_username": "Vaihda yksilΓΆllinen kΓ€yttΓ€jΓ€nimesi.", + "scenes.apps.account.account.emails": "SΓ€hkΓΆpostiosoitteet", + "scenes.apps.account.account.main_email": "Ensisijainen sΓ€hkΓΆposti", + "scenes.apps.account.account.email_add": "LisÀÀ uusi sΓ€hkΓΆpostiosoite", + "scenes.apps.account.account.email_add_modal.invalid_code": "Koodi ei kelpaa", + "scenes.apps.account.account.password": "Salasana", + "scenes.apps.account.account.password_modal.password": "Uusi salasana", + "scenes.apps.account.account.password_modal.bad_old_password": "Vanha salasana ei ole oikein.", + "scenes.apps.account.account.password_modal.bad_password": "Salasanat eivΓ€t tΓ€smÀÀ tai salasana on liian lyhyt. Valitse vΓ€hintÀÀn 8-merkkinen salasana.", + "scenes.apps.account.account.logout": "Kirjaudu ulos", + "scenes.apps.account.notifications.privacy_subtitle": "Yksityisyys", + "scenes.apps.parameters.workspace_sections.members.members": "KΓ€yttΓ€jΓ€t", + "scenes.apps.tasks.list_modal.archive_all_tasks": "Arkistoi kaikki tehtΓ€vΓ€t", + "scenes.login.create_account.username": "KΓ€yttΓ€jΓ€nimi", + "scenes.login.create_account.username_already_exist": "TΓ€mΓ€ kΓ€yttΓ€jΓ€nimi on jo kΓ€ytΓΆssΓ€", + "scenes.login.create_account.fill_in_username": "TΓ€ytΓ€ kΓ€yttΓ€jΓ€nimi", + "scenes.login.create_account.firstname": "Etunimi", + "scenes.login.create_account.lastname": "Sukunimi", + "scenes.login.create_account.newsletter": "Vastaanota tietoja Twakesta", + "scenes.login.create_account.too_short_password": "Salasanan tulee sisΓ€ltÀÀ vΓ€hintÀÀn kahdeksan merkkiΓ€.", + "scenes.login.forgot_password.title": "Unohditko salasanasi?", + "scenes.login.forgot_password.text": "Vastaanotat 9-numeroisen koodin sΓ€hkΓΆpostitse, jotta voit vahvistaa identiteettisi.", + "scenes.login.forgot_password.email_to_recover": "Palautettava sΓ€hkΓΆpostiosoite", + "scenes.login.forgot_password.mail_doesnt_exist": "TΓ€tΓ€ sΓ€hkΓΆpostiosoitetta ei ole olemassa", + "scenes.app.workspaces.create_company.invitations.title_2": "LisÀÀ kΓ€yttΓ€jiΓ€ tiimiisi.", + "scenes.app.workspaces.create_company.title": "Luo oma yritys", + "scenes.app.workspaces.welcome_page.add_secondary_emails": "LisÀÀ toissijainen sΓ€hkΓΆpostiosoite", + "scenes.app.workspaces.welcome_page.see_you_soon": "NΓ€hdÀÀn pian!", + "scenes.app.workspaces.welcome_page.try_again": "YritΓ€ uudelleen", + "scenes.app.workspaces.welcome_page.twake_team": "Twake", + "scenes.app.workspaces.welcome_page.welcome_header": "Tervetuloa, tΓ€mΓ€ on Twake!", + "scenes.app.workspaces.welcome_page.add_secondary_emails_comment": "Voit linkittÀÀ useita sΓ€hkΓΆpostiosoitteita tiliisi; vain yhtΓ€ osoitetta kΓ€ytetÀÀn ilmoitusten vΓ€littΓ€miseen.", + "scenes.app.workspaces.welcome_page.main_mail_title": "Ensisijainen osoite", + "scenes.app.workspaces.welcome_page.add_new_email": "LisÀÀ sΓ€hkΓΆpostiosoite", + "scenes.app.workspaces.welcome_page.done": "Olen valmis", + "scenes.login.forgot_password.finished": "Salasanasi pΓ€ivitettiin onnistuneesti.", + "scenes.apps.account.account.emails.description": "Hallitse eri sΓ€hkΓΆpostiosoitteitasi.", + "scenes.apps.account.account.make_main": "Aseta ensisijainen", + "scenes.apps.account.account.password.description": "Vaihda salasanasi.", + "scenes.apps.account.identity": "Identiteetti", + "scenes.apps.account.preference": "Asetukset", + "general.open": "Avaa", + "scenes.apps.account.account.email_add_modal.confirm": "Vahvista tΓ€mΓ€ sΓ€hkΓΆpostiosoite", + "app.name.twake_calendar": "Kalenteri", + "app.name.twake_drive": "Asiakirjat", + "app.name.twake_tasks": "TehtΓ€vΓ€t", + "components.calendar.repetition.everyday": "PΓ€ivittΓ€in", + "components.calendar.repetition.custom": "Mukautettu...", + "components.calendar.repetition.ends": "PÀÀttyy", + "components.calendar.repetition.never": "Ei koskaan", + "scenes.app.channelsbar.currentuser.invited_status": "Olet vieras.", + "scenes.app.channelsbar.currentuser.title": "Tiliasetukset", + "scenes.app.channelsbar.currentuser.workspace_parameters": "TyΓΆtilan asetukset", + "scenes.app.channelsbar.currentuser.logout": "Kirjaudu ulos", + "scenes.app.channelsbar.currentuser.user_parameter": "Ilmoitusasetukset", + "scenes.app.channelsbar.channelsuser.new_private_discussion": "Uusi yksityinen keskustelu", + "scenes.app.channelsbar.channelsuser.no_private_message_invite_collaboraters": "Ei yksityisviestejΓ€. Kutsu kΓ€yttΓ€jiΓ€!", + "scenes.app.channelsbar.channelsworkspace.channel_title": "KANAVAT", + "scenes.app.channelsbar.channelsworkspace.channel_title.favorite": "SUOSIKIT", + "scenes.app.channelsbar.channelsworkspace.no_channel": "Et ole vielΓ€ liittynyt yhdellekÀÀn kanavalle", + "scenes.app.channelsbar.modify_channel_menu": "Muokkaa kanavaa", + "scenes.app.channelsbar.guest_management": "Vieraiden hallinta", + "scenes.app.channelsbar.unread_sign": "Merkitse lukemattomaksi", + "scenes.app.channelsbar.installation_desktop_tutorial": "Asenna tyΓΆpΓΆytΓ€sovellus", + "scenes.app.channelsbar.invitation_collaboraors_tutorial": "Kutsu kΓ€yttΓ€jiΓ€ tyΓΆtiloihin.", + "scenes.app.channelsbar.public_channel_label": "Julkinen", + "scenes.app.channelsbar.private_channel_label": "Yksityinen", + "scenes.app.channelsbar.sending_message_instruction": "LΓ€hetΓ€ ensimmΓ€inen viestisi keskusteluun", + "scenes.app.channelsbar.tutorial_alert": "Γ„lΓ€ nΓ€ytΓ€ uudelleen?", + "scenes.app.channelsbar.welcome": "Tervetuloa, tΓ€mΓ€ on Twake", + "scenes.app.mainview.instruction_current_tab": "Aloita valitsemalla kanava vasemmalta.", + "scenes.app.mainview.tabs.rename": "NimeΓ€ uudelleen", + "scenes.app.mainview.tabs.searching_connectors": "Etsi yhdistΓ€jÀÀ...", + "scenes.app.popup.appsparameters.pages.api_parameters_label": "API-asetukset", + "scenes.app.popup.appsparameters.pages._app_identity": "Sovelluksen identiteetti", + "scenes.app.popup.appsparameters.pages.app_privileges_label": "Sovelluksen oikeudet", + "scenes.app.popup.appsparameters.pages.application_title": "Sovellus", + "scenes.app.popup.appsparameters.pages.automatique_label": "Automaattinen", + "scenes.app.popup.appsparameters.pages.autorised_ip_adresses_label": "Sallitut IP-osoitteet", + "scenes.app.popup.appsparameters.pages.create_app_button": "Luo sovellus", + "scenes.app.popup.appsparameters.pages.create_my_app": "Luo oma sovellus", + "scenes.app.popup.appsparameters.pages.danger_zone_description": "Poista sovellus", + "scenes.app.popup.appsparameters.pages.danger_zone_label": "VaaravyΓΆhyke", + "scenes.app.popup.appsparameters.pages.description_label": "Kuvaus", + "scenes.app.popup.appsparameters.pages.go_back": "Takaisin", + "scenes.app.popup.appsparameters.pages.new_app_title": "Uusi sovellus", + "scenes.app.popup.appsparameters.pages.public_availability_application": "Julkinen sovellus", + "scenes.app.popup.appsparameters.pages.public_login_label": "Julkinen tunniste", + "scenes.app.popup.appsparameters.pages.website_label": "Verkkosivu", + "scenes.app.popup.appsparameters.pages.remove_app_button": "Poista sovellus", + "scenes.app.popup.appsparameters.pages.update_button": "PΓ€ivitΓ€", + "scenes.app.popup.createworkspacepage.create_new_workspace": "Luo uusi tyΓΆtila", + "scenes.app.popup.createworkspacepage.add_subtitle": "Tarvitsetko lisÀÀ tilaa?", + "scenes.app.popup.workspaceparameter.admin_manager_current_status": "Olet tyΓΆtilan yllΓ€pitΓ€jΓ€.", + "scenes.app.popup.userparameter.personnal_workspaces_title": "TyΓΆtilat", + "scenes.app.popup.workspaceparameter.admin_current_status": "Olet yllΓ€pitΓ€jΓ€.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace": "Poista tyΓΆtila", + "scenes.app.popup.workspaceparameter.pages.back_to_search_button": "Palaa hakuun", + "scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button": "Kutsu kΓ€yttΓ€jiΓ€", + "scenes.app.popup.workspaceparameter.pages.collaborateurs": "KΓ€yttΓ€jΓ€t", + "scenes.app.popup.workspaceparameter.pages.install_button": "Asenna", + "scenes.app.popup.workspaceparameter.pages.no_app_information": "Sinulla ei ole sovelluksia tΓ€ssΓ€ tyΓΆtilassa", + "scenes.app.popup.workspaceparameter.pages.quit_workspace_menu": "Poistu tΓ€stΓ€ tyΓΆtilasta", + "scenes.apps.calendar.modals.advanced_options": "LisΓ€asetukset", + "scenes.apps.calendar.modals.description_placeholder": "Kuvaus", + "scenes.apps.calendar.modals.details_title": "Tiedot", + "scenes.apps.calendar.modals.event_adresse_placeholder": "Osoite", + "scenes.apps.calendar.modals.event_description_placeholder": "Kuvaus", + "scenes.apps.calendar.modals.event_title_placeholder": "Otsikko", + "scenes.apps.calendar.modals.modify_event_button": "Muokkaa tapahtumaa", + "scenes.apps.calendar.modals.part.participants": "Osallistujat", + "scenes.apps.calendar.modals.participants_event": "Osallistujat", + "scenes.apps.calendar.modals.reminders": "Muistutukset", + "scenes.apps.calendar.modals.remove_button": "Poista", + "scenes.apps.calendar.modals.remove_event_button": "Poista tapahtuma", + "scenes.apps.calendar.modals.remove_event_text": "Poistetaanko tapahtuma?", + "scenes.apps.calendar.modals.title_placeholder": "Otsikko", + "scenes.apps.calendar.modify_calendar_menu": "Muokkaa kalenteria", + "scenes.apps.calendar.month_option": "Kuukausi", + "scenes.apps.calendar.my_calendar": "Oma kalenteri", + "scenes.apps.calendar.my_calendar_menu": "Oma kalenteri", + "scenes.apps.calendar.today_menu": "TΓ€nÀÀn", + "scenes.apps.calendar.week_option": "Viikko", + "scenes.apps.calendar.workspace": "TyΓΆtila", + "scenes.apps.calendar.workspace_menu": "TyΓΆtila", + "scenes.apps.drive.add_button": "LisÀÀ", + "scenes.apps.drive.message_added_file": "{{$1}} lΓ€hetti {{$2}}.", + "scenes.apps.drive.message_added_mutiple_files": "{{$1}} lΓ€hetti useita tiedostoja.", + "scenes.apps.drive.message_added_file_no_name": "{{$1}} lΓ€hetti tiedoston.", + "scenes.apps.drive.choose_folder_button": "Valitse kansio", + "scenes.apps.drive.choose_file_button": "Valitse tiedosto", + "scenes.apps.drive.open_link": "Avaa linkki uudessa ikkunassa", + "scenes.apps.drive.files_subtitle": "Tiedostot", + "scenes.apps.drive.folder_subtitle": "Kansiot", + "scenes.apps.drive.go_out_trash_menu": "Poistu roskakorista", + "scenes.apps.drive.go_trash_menu": "Siirry roskakoriin", + "scenes.apps.drive.import_from_computer_menu": "LΓ€hetΓ€ tietokoneelta", + "scenes.apps.drive.move_text": "SiirrΓ€", + "scenes.apps.drive.new_file_menu": "Uusi tiedosto", + "scenes.apps.drive.new_file_title": "Uusi tiedosto", + "scenes.apps.drive.new_folder_title": "Uusi kansio", + "scenes.apps.drive.new_external_storage": "Uusi erillinen tallennustila", + "scenes.apps.drive.remove_definitely_menu": "Poista pysyvΓ€sti", + "scenes.apps.drive.restore_menu": "Palauta", + "scenes.apps.drive.viewer.loading_preview_message": "Ladataan...", + "scenes.apps.drive.viewer.no_preview_message": "Et voi katsella tΓ€mΓ€ntyyppistΓ€ tiedostoa.", + "scenes.apps.drive.viewer.open_with_button": "Avaa sovelluksella...", + "scenes.apps.messages.message.pin_button": "KiinnitΓ€ viesti", + "scenes.apps.messages.message.unpin_button": "Irrota viesti kiinnityksestΓ€", + "scenes.apps.messages.message.copy_link": "Kopioi linkki viestiin", + "scenes.apps.messages.message.pinned": "Kiinnitetty", + "scenes.apps.messages.message.save_button": "Tallenna", + "scenes.apps.messages.message.types.first_channel_message_text": "TΓ€mΓ€ on kanavan ensimmΓ€inen viesti", + "scenes.apps.messages.message.types.first_message_text": "TΓ€mΓ€ on ensimmΓ€inen viesti", + "scenes.login.verifymail.error_message": "Tapahtui virhe", + "scenes.login.verifymail.signin_button": "Kirjaudu sisÀÀn", + "scenes.login.verifymail.success": "SΓ€hkΓΆpostisi vahvistettiin onnistuneesti!", + "scenes.login.verifymail.verification_waiting": "Odotetaan vahvistusta...", + "scenes.app.workspaces.components.skip": "Ohita", + "scenes.apps.drive.top_menu_more": "LisÀÀ", + "scenes.apps.messages.new_thread": "Aloita uusi keskustelu", + "scenes.apps.messages.input.send_message": "LΓ€hetΓ€ viesti", + "scenes.apps.messages.input.emoji": "Emoji", + "scenes.apps.messages.input.hide_formatting": "Piilota muotoilu", + "scenes.apps.tasks.board.tasks.add_subtask": "LisÀÀ alitehtΓ€vΓ€", + "scenes.apps.parameters.workspace_sections.workspace.logo_company": "Yrityksen logo", + "scenes.app.popup.workspaceparameter.pages.cancel_invitation": "Peruuta kutsu", + "scenes.apps.account.account.fullname": "Koko nimi", + "login.email_login": "SΓ€hkΓΆposti / kirjautuminen", + "scenes.apps.account.account.save": "Tallenna tili", + "components.listmanager.filter": "Suodatin", + "components.drive.new_versions": "LisÀÀ uusi versio", + "components.upload.drop_files": "Pudota tiedostot tΓ€hΓ€n", + "components.workspace.list_manager.no_workspace": "Ei tyΓΆtilaa", + "components.workspace.list_manager.add": "LisÀÀ tyΓΆtiloja", + "components.searchpopup.loading": "Ladaan lisÀÀ tuloksia", + "components.searchpopup.enter_text": "Kirjoita tekstiΓ€ etsiΓ€ksesi Twakesta.", + "components.searchpopup.size": "Koko", + "components.searchpopup.creation": "Luonti", + "components.searchpopup.last_modif": "Viimeisin muokkaus", + "components.alert.confirm": "Vahvista toimintosi", + "components.alert.confirm_click": "Vahvista toimintosi napsauttamalla OK.", + "components.searchpopup.load_more": "Lataa lisÀÀ tuloksia", + "general.more": "LisÀÀ", + "scenes.apps.board.kanban": "Kanban", + "scenes.apps.board.archived_tasks": "Arkistoidut tehtΓ€vΓ€t ({{$1}})", + "scenes.apps.board.new_task": "+ Uusi tehtΓ€vΓ€", + "scenes.apps.board.all_boards": "Kaikki taulut", + "components.userlistmanager.no_users": "Ei kΓ€yttΓ€jiΓ€.", + "components.reminder.notification": "Ilmoitus", + "components.reminder.minutes_bef": "minuuttia ennen", + "components.reminder.hours_bef": "tuntia ennen", + "components.reminder.days_bef": "pΓ€ivÀÀ ennen", + "components.reminder.weeks_bef": "viikkoa ennen", + "components.reminder.by_email": "SΓ€hkΓΆposti", + "scenes.apps.calendar.video_link": "Avaa linkki napsuttamalla", + "scenes.app.mainview.discussion": "Keskustelu", + "scenes.client.channelbar.channelmemberslist.autocomplete": "LisÀÀ tai etsi kΓ€yttΓ€jÀÀ", + "scenes.client.channelbar.workspacechannellist.autocomplete": "Etsi kanavaa, kΓ€yttΓ€jiΓ€ tai suoraviestejΓ€", + "components.connectorslistmanager.add_connectors": "LisÀÀ yhdistΓ€jiΓ€", + "components.alert.leave_private_channel.title": "Haluatko varmasti poistua kanavalta?", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.tag": "Et ole jΓ€sen", + "general.re_send": "LΓ€hetΓ€ uudelleen", + "scenes.apps.messages.message.activity_message.a_added_b_to_the_channel": "{{$1}} asetti {{$2}} kanavalle", + "scenes.apps.drive.download_all_button": "Lataa kaikki", + "scenes.apps.messages.message.activity_message.a_removed_b_from_the_channel": "{{$1}} poisti {{$2}} kanavalta", + "scenes.apps.messages.message.activity_message.a_updated_channel_description": "{{$1}} vaihtoi kuvauksen", + "components.alert.leave_private_channel.description": "Et voi liittyΓ€ tΓ€lle yksityiselle kanavalle uudelleen, ellei joku kutsu sinua.", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.loader": "Lataa lisÀÀ", + "components.account_verification_status_sentence": "Tilisi tila on: {{$1}}", + "components.account_verication_status_unverified": "Vahvistamaton", + "components.account_verication_status_blocked": "Lukittu", + "components.unverified_account.re_send_email": "EtkΓΆ saanut sΓ€hkΓΆpostia?", + "general.user.role.company.guest": "Vieras", + "general.user.deleted": "Poistettu tili", + "scenes.client.channels_bar.modals.parts.channel_member_row.label.pending_email": "SΓ€hkΓΆposti lΓ€hetetty", + "components.emoji_picker.categories.travel_and_places": "Matkustaminen ja paikat", + "components.emoji_picker.categories.objects": "Objektit", + "components.emoji_picker.categories.symbols": "Symbolit", + "scenes.app.workspaces.create_company.group_data.group_size.100_500": "100 - 499 kΓ€yttΓ€jÀÀ", + "scenes.apps.messages.chatbox.chat.delete_message_btn": "Poista viesti", + "scenes.app.workspaces.create_company.group_data": "MÀÀritΓ€ uuden ryhmΓ€n asetukset", + "scenes.app.workspaces.create_company.group_data.group_type.university_school": "Yliopisto tai koulu", + "scenes.app.workspaces.create_company.group_data.group_size.less_3": "VΓ€hemmΓ€n kuin 4 kΓ€yttΓ€jÀÀ", + "scenes.app.workspaces.create_company.invitations.title": "MÀÀritΓ€ tyΓΆtilan asetukset.", + "scenes.app.workspaces.create_company.group_data.group_type": "RyhmΓ€n tyyppi", + "scenes.app.workspaces.create_company.group_data.group_type.other_group": "Muu", + "scenes.app.workspaces.create_company.group_data.group_size": "RyhmΓ€n koko", + "scenes.app.workspaces.create_company.group_data.group_size.4_10": "4 - 10 kΓ€yttΓ€jÀÀ", + "scenes.app.workspaces.create_company.group_data.group_size.500_1000": "500 - 999 kΓ€yttΓ€jÀÀ", + "scenes.app.workspaces.create_company.group_data.group_size.1000_5000": "1000 - 4999 kΓ€yttΓ€jÀÀ", + "scenes.app.header.alt_notifications": "Ilmoitukset", + "scenes.apps.drive.navigators.navigator_content.files": "Tiedostot", + "scenes.apps.drive.navigators.navigator_content.directory_name": "Kansion nimi", + "scenes.apps.drive.preview_bloc.operations_download": "Lataa", + "scenes.apps.drive.preview_bloc.error_file": "Tiedostoa ei lΓΆydy", + "scenes.apps.drive.right_preview.operations_restore": "Palauta", + "scenes.apps.messages.left_bar.stream.remove_from_favorites": "Poista suosikeista", + "scenes.apps.account.notifications.sound": "ÄÀni-ilmoitus", + "scenes.apps.account.notifications.title": "Ilmoitukset", + "scenes.apps.account.languages.menu_title": "Kieli", + "scenes.apps.account.account.firstname": "Etunimi", + "scenes.apps.account.account.lastname": "Sukunimi", + "scenes.apps.messages.left_bar.stream.notifications.never": "Ei mitÀÀn", + "scenes.apps.parameters.workspace_sections.members": "Osallistujat", + "scenes.login.home.password": "Salasana", + "scenes.apps.account.languages.text": "Vaihda Twaken kieli.", + "scenes.apps.account.notifications.mail_subtitle": "SΓ€hkΓΆposti-ilmoitukset", + "scenes.apps.account.account.password_modal.old_password": "Nykyinen salasana", + "scenes.apps.account.notifications.keywords_subtitle": "Avainsanat", + "scenes.apps.account.notifications.devices_subtitle": "Laiteilmoitukset", + "scenes.apps.parameters.workspace_sections.members.invite_btn": "LisÀÀ kΓ€yttΓ€jΓ€", + "scenes.login.home.lost_password": "Unohditko salasanasi?", + "scenes.login.create_account.step_3_mail_sent": "LΓ€hetimme sinulle aktivointilinkin sΓ€hkΓΆpostitse.", + "scenes.login.forgot_password.password2": "Vahvista salasana", + "scenes.login.create_account.password": "Salasana", + "scenes.apps.tasks.no_tasks": "Ei tehtΓ€vÀÀ", + "scenes.apps.tasks.task.description": "Kuvaus", + "scenes.app.channelsbar.channel_leaving": "Poistu kanavalta", + "scenes.apps.parameters.workspace_sections.members.invite": "Kutsu uusi kΓ€yttΓ€jΓ€", + "scenes.login.forgot_password.text3": "Anna uusi salasana tilillesi.", + "scenes.login.home.title": "Kirjaudu Twakeen", + "scenes.login.home.login_btn": "Kirjaudu sisÀÀn", + "scenes.login.home.create_account": "Luo tili", + "scenes.login.create_account.title": "Luo uusi tili", + "scenes.login.home.email": "SΓ€hkΓΆpostiosoite", + "scenes.login.home.unable_to_connect": "Virheelliset kirjautumistiedot", + "scenes.login.create_account.step_2_subtitle_a": "LisÀÀ koko nimesi, jotta muut kΓ€yttΓ€jΓ€t tunnistavat sinut.", + "scenes.login.create_account.email": "SΓ€hkΓΆpostiosoite", + "scenes.login.create_account.email_used": "TΓ€mΓ€ sΓ€hkΓΆpostiosoite on jo kΓ€ytΓΆssΓ€.", + "scenes.apps.drive.create_folder_button": "Luo", + "scenes.apps.drive.download_button": "Lataa", + "scenes.login.forgot_password.invalid_code": "Koodi ei ole kelvollinen.", + "scenes.login.forgot_password.password": "Salasana", + "scenes.login.home.subtitle": "Kiva nΓ€hdΓ€ sinua", + "scenes.login.create_account.step_1_subtitle": "TΓ€mΓ€ ei voisi olla helpompaa β€” tarvitsemme vain vΓ€hΓ€n tietoja.", + "scenes.login.create_account.step_2_subtitle_b": "Puhelinnumerosi pysyy yksityisenΓ€.", + "scenes.app.workspaces.welcome_page.new_email": "LisÀÀ toissijainen sΓ€hkΓΆpostiosoite", + "components.calendar.repetition.does_not_repeat": "Ei toistoa", + "scenes.apps.calendar.create_calendar_title": "Luo kalenteri", + "scenes.apps.calendar.edit_calendar_title": "Muokkaa kalenteria", + "scenes.app.workspaces.welcome_page.code_verification": "Vahvistuskoodi", + "scenes.apps.account.thumbnail.max_weight": "EnimmΓ€iskoko 5 Mt", + "scenes.app.channelsbar.currentuser.collaborateurs": "KΓ€yttΓ€jΓ€t", + "scenes.login.create_account.step_3_subtitle": "Viimeinen vaihe β€” meidΓ€n tulee varmistua, ettet ole robotti!", + "scenes.app.workspaces.create_company.company_name.placeholder": "Yrityksen nimi", + "scenes.app.workspaces.welcome_page.other_mail_title": "Toissijaiset osoitteet", + "scenes.app.channelsbar.currentuser.change_my_status": "Vaihda tilaa", + "scenes.app.channelsbar.currentuser.create_workspace_page": "Luo tyΓΆtila", + "scenes.app.channelsbar.channelsworkspace.create_channel": "Luo kanava", + "scenes.app.channelsbar.read_sign": "Merkitse luetuksi", + "scenes.app.channelsbar.channel_removing": "Poista kanava", + "scenes.app.popup.workspaceparameter.payments_subscriptions_title": "Maksut ja tilaukset", + "scenes.app.popup.appsparameters.pages.apps_title": "Sovellukset ja yhdistΓ€jΓ€t", + "scenes.app.popup.appsparameters.pages.app_name_label": "Sovelluksen nimi", + "scenes.apps.calendar.add_calendar_menu": "LisÀÀ kalenteri", + "scenes.app.popup.workspaceparameter.pages.weight_max_small_text": "EnimmΓ€iskoko 5 Mt.", + "scenes.app.popup.appsparameters.pages.remove_app_from_workspace": "Poista tyΓΆtilasta", + "scenes.app.popup.createworkspacepage.placeholder_name": "TyΓΆtilan nimi", + "scenes.app.popup.userparameter.pages.private_message_content.show": "NΓ€ytΓ€ yksityisiviestien sisΓ€ltΓΆ", + "scenes.app.popup.workspaceparameter.manager_current_status": "Olet yrityksen yllΓ€pitΓ€jΓ€.", + "scenes.app.popup.workspaceparameter.pages.installed_apps_subtitle": "Asennetut sovellukset", + "scenes.app.popup.workspaceparameter.pages.title": "TyΓΆtilan asetukset", + "scenes.apps.calendar.connectors_menu": "YhdistΓ€jΓ€t...", + "scenes.apps.calendar.export_title": "Vie", + "scenes.apps.calendar.export_view_menu": "Vie nΓ€kymΓ€...", + "scenes.apps.calendar.ics_subscription_menu": "Hanki ICS-tilauslinkki", + "scenes.apps.calendar.my_calendar_label": "Oma kalenteri", + "scenes.apps.calendar.workspace_label": "TΓ€mΓ€ tyΓΆtila", + "scenes.app.popup.appsparameters.pages.loading": "Ladataan...", + "scenes.app.popup.workspaceparameter.pages.company_name_label": "Yrityksen nimi", + "scenes.app.popup.workspaceparameter.pages.description": "Kuvaus", + "scenes.app.popup.workspaceparameter.pages.logo_modify_description": "Muokkaa tyΓΆtilan kuvaa", + "scenes.app.popup.workspaceparameter.pages.logo_subtitle": "Logo", + "scenes.app.popup.workspaceparameter.pages.name_label": "TyΓΆtilan nimi", + "scenes.app.popup.userparameter.pages.private_message_content.hide": "Piilota yksityisviestien sisΓ€ltΓΆ", + "scenes.apps.calendar.ics_download_menu": "Lataa ICS-tiedosto", + "services.user.update_password_alert": "Salasanasi on pΓ€ivitetty.", + "components.channelworkspacelist.title": "Kanavat", + "scenes.client.mainview.tabs.tabstemplateeditor.select_placeholder": "Sovellus", + "components.newversion.new_version_component.row.part_1": "KΓ€ytΓΆssΓ€si on vanhentunut Twaken versio", + "general.user.role.company.member": "JΓ€sen", + "scenes.apps.drive.throw_menu": "LΓ€hetΓ€ roskakoriin", + "scenes.apps.messages.message.new_messages_bar": "Uudet viestit", + "scenes.apps.messages.message.modify_button": "Muokkaa", + "scenes.apps.messages.message.remove_button": "Poista", + "scenes.apps.drive.trash": "Roskakori", + "scenes.apps.drive.top_menu_no_items": "{{$1}} tietuetta", + "scenes.apps.account.account.password_for_user": "Salasana kΓ€yttΓ€jΓ€llesi", + "scenes.app.taskpicker.select": "Valitse", + "components.workspace.list_manager.current_space": "Nykyinen tyΓΆtila", + "components.workspace.list_manager.all": "Kaikki", + "components.searchpopup.sender": "LΓ€hettΓ€", + "components.searchpopup.show_filters": "nΓ€ytΓ€ suodattimet", + "scenes.apps.messages.just_you": "NΓ€kyy vain sinulle", + "scenes.apps.messages.message.cancel_button": "Peruuta", + "scenes.apps.messages.message.reply_button": "Vastaa", + "services.user.notification_parameters_update_alert": "Ilmoitusasetukset on pΓ€ivitetty.", + "scenes.apps.messages.input.show_formatting": "NΓ€ytΓ€ muotoilu", + "scenes.app.popup.workspaceparameter.pages.logo_company_modify_description": "Muokkaa yrityksen kuvaa ", + "scenes.app.mainview.link_expired": "TΓ€mΓ€ julkinen linkki on virheellinen tai se on vanhentunut.", + "scenes.apps.parameters.workspace_sections.members.invite_all": "Kutsu kaikki", + "components.searchpopup.mentions": "Maininnat", + "components.searchpopup.hide_filters": "piilota suodattimet", + "components.workspace.list_manager.current_company": "Nykyinen yritys", + "components.workspace.calendar.invalid": "Virheellinen", + "scenes.app.popup.workspace.edit_temp": "Muokkaa vΓ€liaikaista tiliΓ€", + "components.leftbar.channel.workspaceschannels.menu.option_2": "Liity kanavalle", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_creation": "Luo uusi vΓ€lilehti", + "scenes.app.channelsbar.hide_discussion_leaving.menu": "Piilota keskustelu", + "components.inputs.input_with_select.input.placeholder": "Kanavan nimi", + "scenes.apps.tasks.board.tasks.subtask": "AlitehtΓ€vΓ€", + "components.drive.elements.current_name": "Nykyinen nimi: ", + "scenes.app.popup.createcompany.try_again": "YritΓ€ uudelleen.", + "scenes.apps.tasks.modals.attachments": "Liitteet", + "scenes.app.popup.workspace.create_temp": "Luo vΓ€liaikainen tili", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_edition": "NimeΓ€ uudelleen {{$1}}", + "components.newversion.new_version_modal.title": "Uusi versio saatavilla!", + "scenes.apps.messages.message.activity_message.a_updated_channel_name": "{{$1}} asetti kanavan uudeksi nimeksi {{$2}}", + "components.emoji_picker.categories.activity": "Aktiviteetti", + "components.emoji_picker.categories.flags": "Liput", + "scenes.client.channelbar.channelmemberslist.loader": "Lataa lisÀÀ", + "components.leftbar.channel.workspaceschannels.menu.option_1": "Luo kanava", + "scenes.client.channelbar.channelmemberslist.menu.option_2": "Poista kanavalta", + "components.emoji_picker.categories.frequently_used": "Usein kΓ€ytetyt", + "components.emoji_picker.categories.smileys_and_people": "HymiΓΆt ja ihmiset", + "components.emoji_picker.categories.animals_and_nature": "ElΓ€imet ja luonto", + "components.emoji_picker.categories.food_and_drink": "Ruoka ja juoma", + "general.user.role.company.admin": "Yrityksen yllΓ€pitΓ€jΓ€", + "components.emoji_picker.categories.search_result": "Hakutulokset", + "components.emoji_picker.categories.not_found": "Emojia ei lΓΆytynyt", + "scenes.app.popup.adduser.magiclinks.action_generate": "Tuottaa", + "scenes.app.popup.appsparameters.pages.current_informations_apps_connectors": "Et ole vielΓ€ luonut sovellusta. Ennen kuin luot sovelluksen tai liittimen, varmista, ettei sitΓ€ ole jo olemassa sovellusmarkkinoillamme.", + "scenes.app.popup.appsparameters.pages.publication_description": "MÀÀritΓ€ sovelluksesi nΓ€kyvyys.", + "scenes.app.popup.appsparameters.pages.remove_app_from_company": "Poista koko yrityksestΓ€", + "scenes.app.popup.appsparameters.pages.show_button": "NΓ€ytΓ€", + "scenes.app.popup.appsparameters.pages.status_tilte": "Osavaltio", + "scenes.app.popup.appsparameters.pages.string_information": "TΓ€mΓ€ merkkijono identifioi sovelluksesi ja sitΓ€ kΓ€ytetÀÀn viestikomennoissa.", + "scenes.app.popup.appsparameters.pages.title_tester": "Twakecode-testeri", + "scenes.app.integrations_parameters.applications_table.name": "Nimi", + "scenes.app.integrations_parameters.applications_table.title": "Muut integraatiot", + "scenes.app.integrations_parameters.applications_table.search_placeholder": "Hakusovellus", + "scenes.app.integrations_parameters.company_application_popup.tag": "Asennettu", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.website_item": "Verkkosivusto", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.created_item": "LuomispΓ€ivΓ€", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.version_item": "Versio", + "scenes.app.integrations_parameters.company_applications_table.more_menu.show_application": "NΓ€ytΓ€", + "scenes.app.integrations_parameters.company_applications_table.more_menu.remove_application": "Poista yhtiΓΆstΓ€", + "scenes.app.integrations_parameters.company_applications_table.name": "Nimi", + "scenes.apps.messages.input.replied_to": "vastasi ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.real_estate": "KiinteistΓΆt", + "scenes.app.workspaces.create_company.group_data.group_main_activity.chemistry": "Kemia", + "scenes.app.workspaces.create_company.group_data.group_main_activity.trade_commerce_distribution": "Kauppa / Kauppa / Jakelu", + "scenes.app.workspaces.create_company.group_data.group_main_activity.publishing_communication_multimedia": "Kustannustoiminta / ViestintΓ€ / Multimedia", + "scenes.app.workspaces.create_company.group_data.group_main_activity.electronics_electricity_energy": "Elektroniikka / SΓ€hkΓΆ / Energia", + "scenes.app.workspaces.create_company.group_data.group_main_activity.studies_and_advice": "Opintoja ja neuvoja", + "scenes.app.workspaces.create_company.group_data.group_main_activity.pharmaceutical_industry": "LÀÀketeollisuus", + "scenes.app.workspaces.create_company.group_data.group_main_activity.it_telecom": "IT / Telecom", + "scenes.app.workspaces.create_company.group_data.group_main_activity.machinery_automotive": "Koneet / Autot", + "scenes.app.workspaces.create_company.group_data.group_main_activity.business_services": "Liikepalveluja", + "scenes.app.workspaces.create_company.group_data.group_main_activity.entertainment": "Viihde", + "scenes.app.workspaces.create_company.group_data.group_main_activity.textile_clothing_shoes": "Tekstiilit / Vaatteet / KengΓ€t", + "scenes.app.workspaces.create_company.group_data.group_main_activity.transport_logistics": "Kuljetus / Logistiikka", + "scenes.app.workspaces.create_company.group_data.group_main_activity.research": "Tutkimus", + "scenes.app.workspaces.create_company.group_data.group_main_activity.education": "koulutus", + "scenes.app.workspaces.create_company.group_data.group_main_activity.administration": "Hallinto", + "scenes.app.workspaces.create_company.group_data.group_main_activity.other": "muu", + "scenes.apps.tasks.list_modal.modify_list": "Muokkaa listaa", + "scenes.apps.tasks.list_modal.new_list": "Uusi lista", + "scenes.apps.tasks.list_modal.remove": "Poista luettelo ja tehtΓ€vΓ€t", + "scenes.apps.tasks.list_modal.predefined_participants": "Ennalta mÀÀrΓ€tyt osallistujat", + "scenes.apps.tasks.list_modal.remove_archived_tasks": "Poista arkistoidut tehtΓ€vΓ€t ({{$1}})", + "scenes.app.workspaces.welcome_page.create_my_company": "Luo yritykseni", + "scenes.app.workspaces.welcome_page.lets_go": "MennÀÀn!", + "scenes.app.workspaces.welcome_page.may_be_invited_with_secondary_emails": "Kutsuttiinko sinut toisella sΓ€hkΓΆpostiosoitteella?", + "scenes.app.workspaces.welcome_page.no_company_subtitle": "Voi, no... NΓ€yttÀÀ siltΓ€, ettei kukaan ole vielΓ€ kutsunut sinua tyΓΆtilaan.", + "scenes.app.workspaces.welcome_page.ready_to_work": "Olet nyt valmis tyΓΆskentelemÀÀn.", + "components.calendar.repetition.months": "kuukaudet)", + "components.calendar.repetition.years": "vuosi(t)", + "components.calendar.repetition.custom_recurrence": "Mukautettu toistuminen", + "components.calendar.repetition.occurrence": "Tapahtuma(t)", + "components.calendar.repetition.repeat_on": "Toista", + "scenes.app.channelsbar.currentuser.add_apps": "Hae sovelluksia", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace_description": "Vahvista, ettΓ€ haluat poistaa tΓ€mΓ€n tyΓΆtilan, kirjoita nimi alle ja paina Poista.", + "scenes.app.popup.adduser.magiclinks.genrator_info": "Kutsulinkki tyΓΆtilaan", + "scenes.app.popup.adduser.magiclinks.new_link_generated": "Uusi linkki luotu", + "scenes.app.popup.adduser.magiclinks.copied_to_clipboard": "Kopiointi leikepΓΆydΓ€lle onnistui", + "scenes.app.popup.adduser.magiclinks.action_copy": "Kopio", + "scenes.app.popup.appsparameters.pages.publication_label": "Julkaisu", + "scenes.app.popup.appsparameters.pages.publish_app_label": "Julkaise hakemus", + "scenes.app.popup.appsparameters.pages.read_privileges_label": "Lukuoikeudet", + "scenes.app.popup.appsparameters.pages.remove_app": "Poista sovellus {{$1}} pysyvΓ€sti.", + "components.drive.moove_here": "Muuta tΓ€nne", + "components.drive.modify_uslist": "Muokkaa kΓ€yttΓ€jΓ€luetteloa", + "components.tagpicker.tag_name": "Merkin nimi", + "components.searchpopup.only_pinned": "Vain kiinnitetyt viestit", + "components.searchpopup.tasks": "TehtΓ€vΓ€t", + "scenes.app.mainview.advanced_search_placeholder": "Tarkennettu Haku", + "scenes.app.integrations_parameters.title": "Integraatiot", + "scenes.app.integrations_parameters.company_application_popup.btn": "Asentaa", + "scenes.app.integrations_parameters.company_application_popup.tab_btn_info": "Tiedot", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.description_item": "Kuvaus", + "scenes.app.integrations_parameters.company_applications_table.title": "Asennettu yritykseesi", + "app.state.recoil.hooks.use_current_company_applications.toaster_delete": "{{$1}} poistettiin onnistuneesti yrityksestΓ€si", + "app.state.recoil.hooks.use_current_company_applications.toaster_add": "{{$1}} lisΓ€tty yritykseesi", + "scenes.join.loading": "Ladataan…", + "scenes.join.wrong_link_title": "TΓ€mΓ€ linkki ei ole enÀÀ saatavilla", + "scenes.join.wrong_link_description": "PyydΓ€ henkilΓΆltΓ€, joka kutsui sinut tΓ€hΓ€n yritykseen, uusi linkki tai luo oma yritys", + "scenes.join.create_the_company_button": "Luo yritys", + "scenes.join.join_workspace_from_company": "Liity {{$1}}:ÀÀn {{$2}}:stΓ€!", + "scenes.join.twake_description": "Twake on avoimen lΓ€hdekoodin digitaalinen tyΓΆtila, joka on suunniteltu parantamaan tiimisi tuottavuutta", + "scenes.join.login_first_button": "Kirjaudu sisÀÀn tai luo ensin tili", + "scenes.join.join_the_team_button": "Liity joukkueeseen", + "general.archive": "Arkisto", + "general.unarchive": "Poista arkistosta", + "application.load.longer": "Palvelimella kestÀÀ odotettua kauemmin vastata, odota tai lataa sivu uudelleen...", + "scenes.app.side_app.messages_thread_title": "{{$1}} β€’ Viestiketju", + "scenes.app.workspaces.create_company.group_data.group_type.company": "Yritys tai yrityksen osasto", + "scenes.app.workspaces.create_company.group_data.group_type.society_club_charity": "Seura, klubi tai hyvΓ€ntekevΓ€isyysjΓ€rjestΓΆ", + "scenes.app.workspaces.create_company.group_data.group_main_activity": "PÀÀaktiviteetti", + "scenes.app.workspaces.create_company.group_data.group_main_activity.food": "Ruokaa", + "scenes.app.workspaces.create_company.group_data.group_main_activity.bank": "Pankki / vakuutus", + "scenes.app.workspaces.create_company.group_data.group_main_activity.printing_paper": "Tulostus / Paperi", + "scenes.app.workspaces.create_company.group_data.group_main_activity.construction_building": "Rakentaminen / Rakennusmateriaalit", + "scenes.apps.calendar.calendar.list_btn": "Lista", + "scenes.apps.calendar.event_edition.title_confidentiality": "Luottamuksellisuus", + "scenes.apps.calendar.event_view.article_until": "kohtaan", + "scenes.apps.drive.navigators.navigator_labels.title": "Tarrat", + "scenes.apps.messages.left_bar.stream.notifications.mentions": "{{$1}}, {{$2}} ja {{$3}}", + "scenes.apps.messages.left_bar.stream.notifications.me": "Vain {{$1}}", + "scenes.apps.account.title": "Tilin parametrit", + "scenes.apps.account.notifications.keywords_placeholder": "kehittΓ€jΓ€, wifi, koodi, ...", + "scenes.apps.account.notifications.disturb_option_a": "Γ„lΓ€ lΓ€hetΓ€ minulle push-ilmoituksia vΓ€lillΓ€ ", + "scenes.apps.account.notifications.disturb_option_b": " ja ", + "scenes.apps.account.notifications.disturb_option_c": " (paikallinen aikavyΓΆhyke)", + "scenes.apps.account.notifications.devices_option_ever": "LΓ€hetΓ€ minulle aina push-ilmoituksia", + "scenes.apps.account.notifications.devices_option_inactive": "LΓ€hetΓ€ minulle push-ilmoituksia, kun en ole aktiivinen tyΓΆpΓΆydΓ€llΓ€", + "scenes.apps.account.notifications.devices_option_never": "Γ„lΓ€ koskaan lΓ€hetΓ€ minulle push-ilmoituksia", + "scenes.apps.parameters.group_sections.apps.badge_extension": "Laajennus", + "scenes.apps.parameters.workspace_sections.members.pending": "Odottavat sΓ€hkΓΆpostit", + "scenes.apps.tasks.no_connectors_menu_text": "Sinulla ei ole liittimiΓ€, jotka voisivat muodostaa yhteyden kalenteriin.", + "scenes.apps.tasks.boards": "Taulut", + "scenes.apps.tasks.connectors_menu": "Liittimet...", + "scenes.apps.tasks.connectors_search_menu": "Hae liittimiΓ€...", + "scenes.apps.tasks.unconfigured_tab": "TΓ€tΓ€ vΓ€lilehteΓ€ ei ole vielΓ€ mÀÀritetty.", + "scenes.apps.tasks.choose_board_button": "Valitse taulu", + "scenes.apps.tasks.new_board.title": "Uusi lauta", + "scenes.apps.tasks.new_board.edit_title": "Muokkaa taulua", + "scenes.apps.tasks.task": "TehtΓ€vΓ€", + "scenes.apps.tasks.task_status.todo": "TehdΓ€", + "scenes.apps.tasks.task_status.current": "Nykyinen", + "scenes.apps.tasks.task_status.done": "Tehty", + "scenes.apps.tasks.task.assignees": "Valtuutetut", + "scenes.apps.tasks.task.edit.dates": "PΓ€ivΓ€mÀÀrΓ€t", + "scenes.login.footer.go_to_twake": "Siirry osoitteeseen twakeapp.com", + "scenes.login.footer.branding": "Olet {{$1}} ({{$2}}) yksityisellΓ€ Twake-palvelimella. ", + "scenes.login.create_account.fill_in_email": "Sinun tulee tΓ€yttÀÀ sΓ€hkΓΆpostisi oikealla sΓ€hkΓΆpostiosoitteella", + "scenes.login.forgot_password.text2": "Saat 9-numeroisen koodin. Kirjoita se alla olevaan kenttÀÀn jatkaaksesi.", + "scenes.login.forgot_password.password_dont_match": "Salasanasi eivΓ€t tΓ€smÀÀ tai ne ovat liian lyhyitΓ€. Kirjoita salasana, jossa on vΓ€hintÀÀn 8 merkkiΓ€.", + "scenes.app.workspaces.create_company.company_name.title_1": "Aloittaa,", + "scenes.app.workspaces.create_company.company_name.title_2": "ilmoittaa yrityksesi nimi.", + "scenes.app.workspaces.create_company.default_workspace_name": "Main", + "scenes.app.workspaces.create_company.importations.title_1": "TyΓΆskenteletkΓΆ jo digitaalisten tyΓΆkalujen kanssa? Tuo tai integroi tyΓΆkalusi nyt!", + "scenes.app.workspaces.create_company.importations.title_2": "Ei hΓ€tÀÀ, voit tehdΓ€ tΓ€mΓ€n myΓΆhemmin!", + "scenes.app.workspaces.welcome_page.added_to_company": "Sinut on kutsuttu ", + "scenes.app.workspaces.create_company.group_data.title": "Toimimme nopeasti – tarvitsemme vain tilastotietoja.", + "scenes.app.workspaces.welcome_page.we_sent_you_mail": "LΓ€hetimme sinulle vahvistuskoodin {{$1}}:n kautta", + "scenes.apps.account.account.description_main": "PÀÀosoitteesi on paikka, johon Twake lΓ€hettÀÀ ilmoituksesi. Toissijaisten osoitteiden avulla sinut kutsutaan automaattisesti niitΓ€ kΓ€yttΓ€viin tyΓΆtiloihin.", + "scenes.apps.account.identity.description": "Muuta etunimesi, sukunimesi ja profiilikuvasi, joka nΓ€kyy muille Twaken kΓ€yttΓ€jille.", + "components.calendar.repetition.weekly_on": "Viikoittain {{$1}}", + "components.calendar.repetition.monthly_on": "Kuukausittain {{$1}} {{$2}}", + "components.calendar.repetition.monthly_on_day": "Kuukausittain pΓ€ivΓ€nΓ€ {{$1}}", + "components.calendar.repetition.annually_on": "Vuosittain {{$1}}", + "components.calendar.repetition.every_weekday": "Joka arkipΓ€ivΓ€ (ma-pe)", + "components.calendar.repetition.repeat": "Toista joka", + "components.calendar.repetition.on": "PÀÀllΓ€", + "components.calendar.repetition.after": "JΓ€lkeen", + "components.calendar.repetition.days": "pΓ€ivΓ€(t)", + "components.calendar.repetition.weeks": "viikko(t)", + "scenes.app.channelsbar.currentuser.workspace_info": "Olet tyΓΆtilassa {{$1}} ryhmΓ€stΓ€ {{$2}}", + "scenes.app.channelsbar.currentuser.update": "PΓ€ivittÀÀ", + "scenes.app.channelsbar.currentuser.disable_notifications": "Poista kΓ€ytΓΆstΓ€", + "scenes.app.channelsbar.currentuser.disabling_notifications": "Pois kΓ€ytΓΆstΓ€ 1h", + "scenes.app.channelsbar.currentuser.disabling_notifications_until": "Pois kΓ€ytΓΆstΓ€ klo 9 asti. huomenna", + "scenes.app.channelsbar.currentuser.reactivate_notifications": "Aktivoi uudelleen", + "scenes.app.channelsbar.channelsuser.private_messages": "Suorat viestit", + "scenes.app.channelsbar.company_invitation_alert_subtitle": "Voit tuoda nΓ€mΓ€ kanavat yritykseesi pysyΓ€ksesi jΓ€rjestyksessΓ€ napsauttamalla tΓ€tΓ€ kehystΓ€.", + "scenes.app.channelsbar.initial_instructions_tutorial": "Valitse etunimi, nimi ja profiilikuva.", + "scenes.app.channelsbar.welcoming_message_subtitle": "Ryhdy Twake-ammattilaiseksi muutamalla napsautuksella!", + "scenes.app.mainview.tabs.no_connected_connectors_for_channel": "Sinulla ei ole liitintΓ€, joka voi muodostaa yhteyden kanavaan.", + "scenes.app.popup.adduser.adresses_message": "Erota osoitteet pilkulla tai vΓ€lilyΓΆnnillΓ€. Muista, ettΓ€ Twake voi rajoittaa kutsujen mÀÀrÀÀ tilauksesi perusteella.", + "scenes.app.popup.appsparameters.pages._appareance_message_twakcode": "Testaa Twacode-viestiesi ulkoasua", + "scenes.app.channelsbar.company_invitation_alert_title": "Sinut on kutsuttu yritykseen ", + "scenes.app.popup.appsparameters.pages.app_modification_right": "Kaikki tΓ€mΓ€n yrityksen johtajat voivat muokata tΓ€tΓ€ sovellusta.", + "scenes.app.popup.appsparameters.pages.app_privileges_information": "MÀÀritΓ€, mitΓ€ sovelluksesi voi muokata ja lukea.", + "scenes.app.popup.appsparameters.pages.app_update": "PΓ€ivitΓ€ sovellus {{$1}} (sovellusta kΓ€ytetÀÀn {{$2}} kertaa.)", + "scenes.app.popup.appsparameters.pages.automatique_option_information": "Jos aktivoit \"Automaattinen\", tΓ€mΓ€ sovellus lisΓ€tÀÀn automaattisesti tΓ€mΓ€n yrityksen seuraaviin tyΓΆtiloihin.", + "scenes.app.popup.appsparameters.pages.available_publication_alert": "Hakemuksesi julkaisu odottaa tΓ€llΓ€ hetkellΓ€ Twake-tiimin vahvistusta.", + "scenes.app.popup.appsparameters.pages.button_force": "Voimia koko yrityksessΓ€", + "scenes.app.popup.appsparameters.pages.call_event_handlers": "Tapahtuman tyyppi {{$1}} ja tunnus {{$2}} passiivisilla merkinnΓΆillΓ€ {{$3}}", + "scenes.app.popup.appsparameters.pages.installation": "Asentaa.", + "scenes.app.popup.appsparameters.pages.instruction_message_twakecode": "Aloita kirjoittamalla viestisi JSON-muodossa.", + "scenes.app.popup.appsparameters.pages.interne_availability_application": "SisΓ€inen sovellus", + "scenes.app.popup.appsparameters.pages.json_configuration_information": "Siirry dokumentaatioon luodaksesi mÀÀritykset JSON-muodossa.", + "scenes.app.popup.appsparameters.pages.message_data_next_event": "Passiivinen data, joka lΓ€hetetÀÀn seuraavassa tapahtumassa", + "scenes.app.popup.appsparameters.pages.modify_public_data": "Muokkaa sovelluksesi julkisia tietoja.", + "scenes.app.popup.appsparameters.pages.ok_user_code": "okei", + "scenes.app.popup.userparameter.pages.frequency_notif_configuration_description": "Aseta mobiili-ilmoitusten tiheys.", + "scenes.app.popup.userparameter.pages.frequency_notif_subtitle": "Ilmoitusten tiheys", + "scenes.app.popup.userparameter.pages.keywords_notif_description": "Korosta seuraavat avainsanat:", + "scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description": "Aseta sΓ€hkΓΆposti-ilmoitusten tiheys.", + "scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description": "Valitse ajanjakso, jonka aikana et saa ilmoituksia.", + "scenes.app.popup.userparameter.pages.no_night_disturbing_label": "Γ„lΓ€ hΓ€iritse yΓΆllΓ€", + "scenes.app.popup.userparameter.pages.notif_content_label": "Ilmoitusten sisΓ€ltΓΆ", + "scenes.app.popup.workspaceparameter.pages.company_name_description": "Muuta tΓ€mΓ€n yrityksen nimi", + "scenes.app.popup.workspaceparameter.pages.show_button": "NΓ€yttΓΆ", + "scenes.app.popup.workspaceparameter.pages.webhooks_access_subtitle": "PÀÀsy webhookeihin", + "scenes.app.popup.workspaceparameter.pages.withdraw_button": "Poista tΓ€stΓ€ tyΓΆtilasta", + "scenes.app.popup.workspaceparameter.pages.worspace_notif": "tyΓΆtila", + "scenes.app.popup.workspaceparameter.pages.write_access_subtitle": "Kirjoitusoikeus", + "scenes.app.popup.workspaceparameter.pages.your_apps_label": "Sinun sovelluksesi", + "scenes.app.workspacesbar.components.change_company_title": "Vaihda yritystΓ€", + "scenes.app.workspacesbar.components.create_company_menu": "Luo yritys", + "scenes.app.workspacesbar.components.grp_parameters": "{{$1}} asetukset", + "scenes.apps.calendar.connectors_search_menu": "Hae liittimiΓ€...", + "scenes.apps.calendar.no_calendar_text": "Et ole asettanut kalentereita tΓ€lle tyΓΆtilalle.", + "scenes.apps.calendar.no_connectors_menu_text": "Sinulla ei ole liittimiΓ€, jotka voisivat muodostaa yhteyden kalenteriin.", + "scenes.apps.calendar.remove_calendar_confirmation": "Poistetaanko kalenteri ja sen tapahtumat pysyvΓ€sti?", + "scenes.apps.drive.no_file_alert": "Sinulla ei ole sovelluksia, joiden avulla voit luoda tiedoston.", + "scenes.apps.drive.no_storage_app_alert": "Sinulla ei ole sovelluksia, joiden avulla voit lisΓ€tΓ€ ulkoista tallennustilaa.", + "scenes.apps.drive.trash_empty_menu": "TyhjennΓ€ roskakori", + "scenes.apps.drive.unconfigured_tab": "TΓ€tΓ€ vΓ€lilehteΓ€ ei ole vielΓ€ mÀÀritetty.", + "scenes.apps.drive.viewer.edit_with_button": "Muokkaa kΓ€yttΓ€mΓ€llΓ€ {{$1}}", + "scenes.apps.messages.input.placeholder": "Kirjoittaa viestin. KΓ€ytΓ€ @ lainataksesi kΓ€yttΓ€jÀÀ.", + "scenes.apps.messages.message.show_button": "NΓ€yttΓΆ", + "scenes.apps.messages.message.show_responses_button": "Katso kaikki vastaukset", + "scenes.apps.messages.messageslist.get_writing_user": "kirjoittaa...", + "scenes.apps.messages.messageslist.get_writing_users": "kirjoittavat...", + "scenes.apps.messages.messageslist.go_last_message_button": "Siirry viimeiseen viestiin", + "scenes.apps.messages.messageslist.go_last_message_button.new_messages": "Uusia viestejΓ€", + "scenes.error_on_twake": "\"Houston, meillΓ€ on ongelma\"", + "scenes.help_us": "Jos kuitenkin haluat auttaa meitΓ€ korjaamaan tΓ€mΓ€n virheen, lΓ€hetΓ€ meille viesti alla: ", + "scenes.login.verifymail.alert": "Tarkistamme sΓ€hkΓΆpostisi!", + "scenes.no_panic": "Γ„lΓ€ panikoi! Korjaa Twake lataamalla tΓ€mΓ€ sivu uudelleen.", + "services.apps.calendar.reminder_icon": "Muistutus", + "services.apps.messages.no_app": "TΓ€tΓ€ sovellusta ei ole olemassa.", + "services.apps.messages.no_command_possible": "Emme voi suorittaa komentoa \"{{$1}}\", koska \"{{$2}}\" ei ole olemassa tai se ei salli komentojen luomista.", + "scenes.apps.calendar.unconfigured_tab": "TΓ€tΓ€ vΓ€lilehteΓ€ ei ole vielΓ€ mÀÀritetty.", + "scenes.tell_us": "Kerro meille mitΓ€ olit tekemΓ€ssΓ€:", + "scenes.apps.drive.viewer.download_desktop": "Lataa Twake Desktop esikatsellaksesi sovelluksessa", + "scenes.apps.tasks.my_tasks": "Minun tehtΓ€vΓ€ni", + "scenes.apps.tasks.board.place_holder": "Hallituksen nimi", + "scenes.apps.tasks.board.tasks.use_deadline": "KΓ€ytΓ€ mÀÀrΓ€aikaa", + "scenes.apps.tasks.board.tasks.use_starttime": "KΓ€ytΓ€ aloitusaikaa", + "scenes.apps.tasks.board.tasks.in_list": "Luettelossa", + "scenes.apps.tasks.board.starts": "Aloittaa", + "scenes.apps.tasks.board.ends": "TehtΓ€vÀÀ varten", + "scenes.apps.tasks.board.list_name": "Listanimi", + "scenes.app.popup.sync_calendar": "Synkronoi kalenterisi.", + "components.searchpopup.filter_ws": "Suodata tyΓΆtilat", + "components.searchpopup.tags": "Tunnisteet", + "components.searchpopup.update_search": "PΓ€ivitΓ€ haku", + "scenes.apps.drive.remove_attachs": "Poista liitteet", + "components.drive.elements.see": "Katso", + "scenes.apps.drive.right_preview.public": "Julkinen pÀÀsy", + "components.drive.elements.configurate_mod": "MÀÀritΓ€ mode...", + "components.drive.elements.manage_version": "Hallitse versioita", + "scenes.apps.tasks.active_tasks": "aktiivisia tehtΓ€viΓ€", + "scenes.apps.drive.right_preview.versions": "Versiot", + "scenes.app.popup.appsparameters.pages.apps_connectors_small_text": "Hallitse sovelluksiasi ja liittimiΓ€si.", + "scenes.app.popup.appsparameters.pages.icon": "Kuvake", + "scenes.app.popup.appsparameters.pages.title_informations": "Perustiedot", + "scenes.app.popup.appsparameters.pages.subtitle_informations": "Sovellusten hallintaan liittyvΓ€t tiedot", + "scenes.app.popup.adduserfromtwakeconsole.current_users_state": "{{$1}} sΓ€hkΓΆpostiosoitetta lisΓ€tÀÀn", + "components.newversion.new_version_component.row.part_2": "Suosittelemme lataamaan sovelluksen uudelleen ja nauttimaan uusista ominaisuuksistamme!", + "components.newversion.new_version_component.link": "Napsauta tΓ€tΓ€ ladataksesi uudelleen", + "components.inputs.input_with_select.select.placeholder": "Osion nimi", + "components.inputs.input_with_select.select.no_sections": "Aloita ensimmΓ€isen kanavaosiosi nimen kirjoittaminen.", + "components.inputs.input_with_select.button.tooltip": "Aseta kanavaosio", + "components.add_mails_workspace.button": "Aloita Twaken kΓ€yttΓΆ", + "components.add_mails_workspace.title_1": "LisÀÀ kΓ€yttΓ€jiΓ€", + "components.add_mails_workspace.title_2": "Twake on tiimin yhteistyΓΆtyΓΆkalu, joten kutsu joitain kΓ€yttΓ€jiΓ€ testaamaan sinulle luomaamme tyΓΆtilaa.", + "components.locked_features.locked_guests_popup.skip_for_now_button": "Ohita nyt", + "components.locked_features.locked_guests_popup.or": "Tai", + "components.on_boarding.company_billing_banner.admin_or_owner_text": "Yrityksesi tilauksessa on ongelma. Ole hyvΓ€ ja katso omaasi", + "components.on_boarding.company_billing_banner.guest_or_member_text": "Yrityksesi tilauksessa on ongelma. Ota yhteyttΓ€ yrityksen omistajaan tai yllΓ€pitΓ€jÀÀn!", + "components.on_boarding.company_billing_banner.link": "yrityksen tilaussuunnitelma", + "components.on_boarding.popups.blocked_company.company_subscription_plan_button": "Klikkaa tΓ€stΓ€", + "components.locked_features.locked_only_office_popup.title": "Et voi muokata tΓ€tΓ€ tiedostoa", + "scenes.app.workspaces.create_company.group_data.group_main_activity.materials": "Materiaalit", + "scenes.app.channelsbar.currentuser.company_messages_counter_header": "Viestien numero", + "scenes.app.channelsbar.currentuser.company_messages_counter_info": "Twaken ilmaisessa versiossa et voi kΓ€yttÀÀ enempÀÀ kuin {{$1}} uudempia viestejΓ€.", + "scenes.app.channelsbar.currentuser.company_messages_counter_link": "NΓ€ytΓ€ lisÀÀ suunnitelmia", + "scenes.app.popup.appsparameters.pages.alert_published_app": "Hakemuksesi on julkaistu, et voi muokata sitΓ€.", + "scenes.app.popup.appsparameters.pages.allowed_ip_adresses_method": "KΓ€ytΓ€ * kehitysvaiheessa salliaksesi kaikki IP-osoitteet.", + "scenes.app.popup.appsparameters.pages.amazing_app_name": "Minun hΓ€mmΓ€styttΓ€vΓ€ sovellus", + "scenes.app.popup.appsparameters.pages.api_data_description": "HyΓΆdyllistΓ€ tietoa Twake API:lle.", + "scenes.app.popup.appsparameters.pages.company_label": "Yrityksen omistaja", + "scenes.app.popup.appsparameters.pages.configuration_label": "Kokoonpano", + "scenes.app.popup.appsparameters.pages.developped_apps_subtitle": "Yrityksen kehittΓ€mΓ€t sovellukset", + "scenes.app.popup.appsparameters.pages.dispalyed_parameters_description": "Voit mÀÀrittÀÀ, missΓ€ sovelluksesi nΓ€kyy.", + "scenes.app.popup.appsparameters.pages.displayed_parameters_label": "NΓ€yttΓΆasetukset", + "scenes.app.popup.appsparameters.pages.error_check_needed": "Tapahtui virhe; tarkista tietosi.", + "scenes.app.popup.appsparameters.pages.error_message": "TΓ€mΓ€ nimi on jo toisen sovelluksen kΓ€ytΓΆssΓ€; ole hyvΓ€ ja valitse toinen.", + "scenes.app.popup.appsparameters.pages.error_user_code": "virhe", + "scenes.app.popup.appsparameters.pages.event_subtitle": "Tapahtumat", + "scenes.app.popup.appsparameters.pages.filter_information": "TΓ€mΓ€ suodatin rajoittaa API-avaimesi kΓ€ytΓΆn vain liittimessΓ€si oleviin palvelimiin.", + "scenes.app.popup.appsparameters.pages.grp_section_name-error": "TΓ€mΓ€ nimi on jo toisen sovelluksen kΓ€ytΓΆssΓ€. Valitse toinen.", + "scenes.app.popup.appsparameters.pages.grp_section_surname_label": "Yksinkertaistettu nimi", + "scenes.app.popup.appsparameters.pages.optimal_format": "Optimaalinen muoto: 48x48px.", + "scenes.app.popup.appsparameters.pages.parameters_form_small_text": "Julkaisematon sovellus toimii vain yrityksessΓ€si. Jos haluat asettaa sen kaikkien Twaken kΓ€yttΓ€jien saataville, aktivoi tΓ€mΓ€ vaihtoehto.", + "scenes.app.popup.appsparameters.pages.url_reception_events_label": "Tapahtuman vastaanoton URL-osoite", + "scenes.app.popup.appsparameters.pages.waiting_availability_application": "Odotetaan...", + "scenes.app.popup.appsparameters.pages.write_privileges_label": "Kirjoitusoikeudet", + "scenes.app.popup.appsparameters.pages.danger_zone_small_text": "Et voi poistaa tΓ€tΓ€ sovellusta, jos se on julkaistu.", + "scenes.app.popup.appsparameters.pages.error_app_simple_name_message": "Sovelluksesi yksinkertaistettu nimi on jo toisen sovelluksen kΓ€ytΓΆssΓ€. Vaihda se.", + "scenes.app.popup.appsparameters.pages.error_app_update_message": "Sovellusta pΓ€ivitettΓ€essΓ€ tapahtui virhe.", + "scenes.app.mainview.quick_search_placeholder": "Pikahaku", + "scenes.app.popup.workspaceparameter.pages.error_workspace_member": "Sinun on oltava yksin tyΓΆtilassa, jotta voit poistaa sen. Poista yhteiskΓ€yttΓ€jΓ€t ja yritΓ€ uudelleen.", + "scenes.app.popup.workspaceparameter.pages.enter": "Tulla sisÀÀn ", + "scenes.app.popup.workspaceparameter.pages.access_apps": "KΓ€ytΓ€ sovelluksiasi ja liittimiΓ€si", + "scenes.app.popup.workspaceparameter.pages.moderator_status": "TyΓΆtilan moderaattori", + "scenes.app.popup.workspaceparameter.pages.alert_impossible_removing": "Et voi poistua tyΓΆtilasta, koska olet viimeinen jΓ€rjestelmΓ€nvalvoja. Voit mÀÀrittÀÀ uuden jΓ€rjestelmΓ€nvalvojan tai poistaa/arkistoida tΓ€mΓ€n tyΓΆtilan.", + "scenes.app.popup.workspaceparameter.pages.all_apps_small_text": "Kaikki sovellukset", + "scenes.app.popup.workspaceparameter.pages.apps_company_small_text": "Yrityksesi sovellukset", + "scenes.app.popup.workspaceparameter.pages.apps_connectors_title": "Integraatiot", + "scenes.app.popup.workspaceparameter.pages.apps_research_title": "Hae sovelluksia", + "scenes.app.popup.workspaceparameter.pages.apps_small_text": "TΓ€mΓ€n tyΓΆtilan sovellukset", + "scenes.app.popup.workspaceparameter.pages.company_developped_apps_subtitle": "Yrityksen kehittΓ€mΓ€t sovellukset", + "scenes.app.popup.workspaceparameter.pages.company_identity_title": "Yrityksen identiteetti", + "scenes.app.popup.workspaceparameter.pages.configuration_notif": "kokoonpano", + "scenes.app.popup.workspaceparameter.pages.configure_button": "MÀÀritΓ€", + "scenes.app.popup.workspaceparameter.pages.developped_apps_small_text": "Yrityksen kehittΓ€mΓ€t sovellukset", + "scenes.app.popup.workspaceparameter.pages.displayed_preferencies_subtitle": "NΓ€yttΓΆasetukset", + "scenes.app.popup.workspaceparameter.pages.installed_app_information": "Asenna sovellus tΓ€hΓ€n tyΓΆtilaan.", + "scenes.app.popup.workspaceparameter.pages.installed_apps_information": "TΓ€hΓ€n tyΓΆtilaan asennetut sovellukset {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_message": "Yrityksen muille alueille asennetut sovellukset {{$1}}", + "scenes.app.popup.workspaceparameter.pages.invitation_error": "Seuraavia kΓ€yttΓ€jiΓ€ kutsuttaessa tapahtui virhe: ", + "scenes.app.popup.workspaceparameter.pages.invited_guest_check_message": "Tarkista, ettΓ€ kΓ€yttΓ€mΓ€si kΓ€yttΓ€jΓ€tunnus tai sΓ€hkΓΆpostiosoite on oikea.", + "scenes.app.popup.workspaceparameter.pages.name_description": "Muuta tΓ€mΓ€n tyΓΆtilan nimeΓ€", + "scenes.app.popup.workspaceparameter.pages.no_access": "Ei pÀÀsyΓ€.", + "scenes.app.popup.workspaceparameter.pages.read_access_subtitle": "Lukuoikeus", + "scenes.app.popup.workspaceparameter.pages.remove_from_company_text": "Poista koko yrityksestΓ€", + "scenes.app.popup.workspaceparameter.pages.research_by": "Hae sovelluksia nimen ja luokkien mukaan", + "scenes.app.popup.workspaceparameter.pages.researching_apps_button": "Hae sovelluksia...", + "scenes.apps.calendar.day_option": "PΓ€ivΓ€", + "scenes.apps.messages.input.edited": "Muokattu", + "services.apps.calendar.deadline_icon": "Takaraja", + "services.apps.calendar.event_icon": "Tapahtuma", + "services.apps.calendar.move_icon": "Liikkua", + "scenes.apps.account.account.send_info": "LΓ€hetΓ€ nΓ€mΓ€ tunnistetiedot kΓ€yttΓ€jΓ€llesi.", + "scenes.apps.account.message_temporary": "VΓ€liaikainen tili toimii kuten tavallinen Twake-tili, mutta sinΓ€ luot salasanan ja voit nollata sen tarvittaessa.", + "scenes.apps.account.message_user_signin": "KΓ€yttΓ€jΓ€si voi kirjautua sisÀÀn milloin tahansa tΓ€llΓ€ samalla sΓ€hkΓΆpostilla ja vaihtaa vΓ€liaikaisen tilin tavalliseksi tiliksi.", + "scenes.app.mainview.create_account": "Luo tyΓΆtilasi ilmaiseksi osoitteessa ", + "scenes.apps.calendar.modals.reminder_add": "LisÀÀ muistutus", + "scenes.apps.tasks.no_connector": "Ei liitintΓ€", + "components.attachmentpicker.add_attachment": "LisÀÀ liitteitΓ€", + "components.input.copied": "Kopioitu", + "components.drive.navigators.directory_not_found": "Hakemistoa ei lΓΆydy.", + "components.drive.right_preview.suppress_link": "Sulje linkki", + "components.drive.right_preview.create_link": "Luo pÀÀsylinkki", + "scenes.apps.board.active_tasks": "Aktiiviset tehtΓ€vΓ€t", + "scenes.apps.board.display_as": "NΓ€ytΓ€ muodossa", + "scenes.apps.drive.used": "kΓ€ytetÀÀn tΓ€ssΓ€ kansiossa", + "scenes.apps.calendar.reminders": "muistutus", + "components.tagpicker.notag": "Ei tagia", + "components.calendar.calendarselector.from": "From", + "scenes.apps.drive.move_text2": "Liikkua", + "components.attachmentpicker.from_computer": "laitteestasi", + "components.attachmentpicker.from_twake": "Twake Documentsista", + "components.attachmentpicker.file": "Tiedosto", + "components.attachmentpicker.remove_attach": "Poista liite", + "scenes.app.popup.appsparameters.pages.smalltext_user_id": "Nykyinen kΓ€yttΓ€jΓ€tunnus", + "scenes.app.popup.appsparameters.pages.smalltext_workspace_id": "Nykyinen tyΓΆtilan tunnus", + "scenes.app.popup.appsparameters.pages.smalltext_group_id": "Nykyisen ryhmΓ€n tunnus", + "scenes.app.mainview.channel_description": "Kuvaile kanavaa", + "scenes.client.channelbar.channeltemplateeditor.checkbox": "Kutsu kaikki tyΓΆtilan kΓ€yttΓ€jΓ€t automaattisesti tΓ€lle kanavalle", + "scenes.client.channelbar.channelmemberslist.title": "KΓ€yttΓ€jΓ€t kohteessa {{$1}}", + "components.notifications.hidden_notifications_button.children": "Uusia viestejΓ€", + "scenes.client.channelbar.channelmemberslist.no_members": "TΓ€llΓ€ kanavalla ei ole kΓ€yttΓ€jiΓ€, voit kutsua heidΓ€t napsauttamalla LisÀÀ kΓ€yttΓ€jiΓ€.", + "scenes.apps.messages.message.activity_message.a_created_channel_tab": "{{$1}} lisΓ€si uuden {{$2}}-vΓ€lilehden {{$3}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_tab": "{{$1}} poisti vΓ€lilehden {{$2}} {{$3}}", + "scenes.apps.messages.message.activity_message.a_created_channel_connector": "{{$1}} lisΓ€si uuden liittimen {{$2}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_connector": "{{$1}} poisti liittimen {{$2}}", + "scenes.client.channelbar.channelmemberslist.tag": "SinΓ€", + "general.verify": "Vahvista", + "components.unverified_account.typography_text_danger": "Sinulla on {{$1}} pΓ€ivÀÀ jΓ€ljellΓ€ kokeilujaksoa. Kokeilutili estetÀÀn 7 pΓ€ivΓ€n kuluttua ja poistetaan pysyvΓ€sti 1 kuukauden rekisterΓΆinnin jΓ€lkeen. Voit vahvistaa tilisi napsauttamalla \"Vahvista tilini\" -painiketta sinulle lΓ€hettΓ€mΓ€ssΓ€mme vahvistussΓ€hkΓΆpostissa.", + "components.unverified_account.verification_details": "Olemme lΓ€hettΓ€neet vahvistustiedot osoitteeseen", + "components.blocked_account.trial_period_over": "Kokeilujaksosi on ohi. Avaa tilisi lukitus ja pÀÀset kΓ€yttΓ€mÀÀn kaikkia toimintoja vahvistamalla tilisi sΓ€hkΓΆpostivahvistuksella", + "components.add_mails_workspace.text_area_placeholder": "Anna kΓ€yttΓ€jiesi sΓ€hkΓΆpostiosoitteet*", + "components.verify_mail.title_1": "Onnittelut", + "components.verify_mail.title_2": "Olet nyt virallinen Twaken kΓ€yttΓ€jΓ€!", + "components.verify_mail.button": "LisÀÀ kΓ€yttΓ€jΓ€", + "components.verify_mail.text": "EnsinnΓ€kin sinun on vahvistettava sΓ€hkΓΆpostiosoitteesi. Olemme lΓ€hettΓ€neet vahvistuslinkin osoitteeseen", + "components.verify_mail.paragraph": "Voit tehdΓ€ sen myΓΆhemmin, jos haluat, mutta vahvistamattomilla tileillΓ€ on pÀÀsy vain rajoitettuun Twaken versioon", + "services.console_services.toaster.add_emails_error": "Virhe lisΓ€ttΓ€essΓ€ sΓ€hkΓΆposteja", + "services.console_services.toaster.add_email_error_message": "Virhe lisΓ€ttΓ€essΓ€ {{$1}}", + "services.console_services.toaster.success_verify_email": "Vahvistuslinkki on lΓ€hetetty sΓ€hkΓΆpostitilillesi", + "scenes.app.popup.workspaceparameter.edit_from_console": "Katso konsolista", + "services.console_services.toaster.success_invite_emails": "{{$1}} kΓ€yttΓ€jΓ€n lisΓ€ys onnistui", + "scenes.client.channels_bar.modals.guest_management.title": "Hallinnoi vieraita kohteessa {{$1}}", + "scenes.client.channels_bar.modals.guest_management.input_placeholder": "Hae vieraita tai odottavia sΓ€hkΓΆposteja", + "scenes.client.channels_bar.modals.guest_management.tips": "Aloita sΓ€hkΓΆpostin lisÀÀminen tai etsiminen kΓ€yttΓ€mΓ€llΓ€ yllΓ€ olevaa syΓΆtettΓ€", + "components.richtexteditor.toolbar.bold": "Lihavoitu", + "components.richtexteditor.toolbar.underline": "Korostaa", + "components.richtexteditor.toolbar.italic": "Kursiivi", + "components.richtexteditor.toolbar.strikethrough": "Yliviivattu", + "components.richtexteditor.toolbar.code": "Koodi", + "components.richtexteditor.toolbar.unordered-list": "Ranskalaiset viivat", + "components.richtexteditor.toolbar.ordered-list": "Tilattu lista", + "components.richtexteditor.toolbar.blockquote": "Lohkolainaus", + "components.richtexteditor.toolbar.code-block": "Koodilohko", + "components.locked_features.locked_history_banner.title": "Olet juuri saavuttanut viestirajan", + "components.locked_features.locked_history_banner.description": "YrityksellΓ€si on paljon viestejΓ€! PΓ€ivitΓ€ nyt, niin pÀÀset kΓ€yttΓ€mÀÀn kaikkea viestihistoriaasi.", + "components.locked_features.locked_history_banner.button": "Lue lisÀÀ", + "components.locked_features.locked_guests_popup.title": "Vieraat-ominaisuus on lukittu", + "components.locked_features.locked_guests_popup.subtitle": "TΓ€mΓ€ ominaisuus ei ole kΓ€ytettΓ€vissΓ€ Twaken ilmaisessa versiossa", + "components.locked_features.locked_guests_popup.description": "Oho!! Vaikuttaa siltΓ€, ettΓ€ haluat kutsua ulkoisia kΓ€yttΓ€jiΓ€ tyΓΆtilaan. Sinun kannattaa harkita suunnitelmasi pΓ€ivittΓ€mistΓ€, jos haluat tehdΓ€ yhteistyΓΆtΓ€ vieraiden ja ulkoisten kumppaneiden kanssa. Tutustu hinnoitteluvaihtoehtoihimme ja valitse tiimisi yhteistyΓΆtarpeisiisi paras vaihtoehto.", + "components.locked_features.locked_guests_popup.learn_more_button": "Lue lisÀÀ", + "components.on_boarding.popups.blocked_company.title": "Yrityksesi on lukittu maksuongelman vuoksi", + "components.on_boarding.popups.blocked_company.description": "Twake-tilauksesi on vanhentunut. Ota yhteyttΓ€ yrityksesi omistajaan tai jΓ€rjestelmΓ€nvalvojaan uusitaksesi sen ja pystyt kommunikoimaan tiimisi kanssa uudelleen!", + "components.on_boarding.popups.blocked_company.learn_more_text": "Haluatko tietÀÀ lisÀÀ yritysten tilaussuunnitelmasta?", + "components.on_boarding.popups.blocked_company.or": "Tai", + "components.on_boarding.popups.blocked_company.company_selector": "Vaihda toiseen yritykseen", + "scenes.apps.tasks.select_user_button": "Tarkastele toisen kΓ€yttΓ€jΓ€n tehtΓ€viΓ€", + "scenes.apps.tasks.select_user": "Etsi kΓ€yttΓ€jΓ€", + "scenes.apps.messages.input.attach_file.from_computer": "Tietokoneelta", + "scenes.app.popup.workspaceparameter.pages.table_title": "Nimi", + "scenes.client.main_view.main_header.search_input": "Hae", + "scenes.apps.drive.new_link_title": "Uusi linkki", + "scenes.apps.drive.default_link_name": "NimetΓΆn", + "components.emoji_picker.input_search_placeholder": "Hae", + "services.apps.messages.message_editor_service.upload_error_toaster": "{{$1}} - Et voi lisΓ€tΓ€ viestiin enempÀÀ kuin {{$2}} tiedostoa", + "scenes.apps.messages.message.parts.deleted_content.text.current_user": "Poistit tΓ€mΓ€n viestin", + "scenes.apps.messages.message.parts.deleted_content.text": "{{$1}} poisti viestinsΓ€", + "components.member.user_parts.and_more_user_text": " ja {{$1}} enemmΓ€n kΓ€yttΓ€jiΓ€", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_link": "Luo yksityinen kanava", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_text": " sen sijaan", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_input_placeholder": "Et voi lisΓ€tΓ€ enempÀÀ kuin 10 kΓ€yttΓ€jÀÀ", + "general.uploading": "LΓ€hetetÀÀn", + "components.upload.drop_files.toaster.error": "Et voi lΓ€hettÀÀ enempÀÀ kuin {{$1}} tiedostoa", + "scenes.app.popup.workspaceparameter.pages.workspace_partner_tabs.members.table.tags": "Rooli", + "general.email": "SΓ€hkΓΆposti", + "components.locked_features.locked_workspace_popup.title": "Et voi luoda lisÀÀ tyΓΆtiloja", + "components.locked_features.locked_workspace_popup.subtitle": "Ilmaisessa versiossa sinulla voi olla vain yksi tyΓΆtila yrityksessΓ€si.", + "components.locked_features.locked_workspace_popup.text": "Oho!! Haluatko luoda uuden tyΓΆtilan yritykseesi? Sinun kannattaa harkita suunnitelmasi pΓ€ivittΓ€mistΓ€. Tutustu hinnoitteluvaihtoehtoihimme ja valitse paras vaihtoehto tiimin yhteistyΓΆtarpeisiisi.", + "components.locked_features.locked_only_office_popup.subtitle": "Ilmaisessa versiossa et voi kΓ€yttÀÀ onlyofficea.", + "components.locked_features.locked_only_office_popup.text": "Oho!! Vaikuttaa siltΓ€, ettΓ€ haluat muokata Twaken tiedostoa. Sinun kannattaa harkita suunnitelmasi pΓ€ivittΓ€mistΓ€, jos haluat tehdΓ€ yhteistyΓΆtΓ€ Office-tiedostojen parissa. Tutustu hinnoitteluvaihtoehtoihimme ja valitse tiimisi yhteistyΓΆtarpeisiisi paras vaihtoehto.", + "components.locked_features.locked_drive_popup.title": "Olet juuri saavuttanut ajorajan", + "components.locked_features.locked_drive_popup.subtitle": "Ilmaisessa versiossa voit tallentaa vain 6 Gt.", + "general.resume": "Jatkaa", + "general.pause": "Tauko", + "'": "'", + "\"": "\"", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.label": "OletustyΓΆtila", + "login.create_account": "Luo tili", + "login.login_error": "Virhe kirjautumisen aikana", + "scenes.app.workspaces.welcome_page.no_workspace_subtitle": "Kukaan ei ole vielΓ€ kutsunut sinua tyΓΆtilaan.", + "scenes.apps.messages.message.types.no_message_in_thread": "Kukaan ei vastannut vielΓ€.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.description": "Kutsu kaikki tyΓΆtilan kΓ€yttΓ€jΓ€t automaattisesti tΓ€lle kanavalle", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.title": "Olet poistamassa {{$1}}", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.alert_total_members": "Sinulla on edelleen {{$1}} jΓ€seniΓ€ ryhmΓ€ssΓ€ {{$2}}. Sinun tulee poistaa kaikki jΓ€senet, jotta voit poistaa tΓ€mΓ€n tyΓΆtilan.", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.checkbox": "YmmΓ€rrΓ€n, ettΓ€ kaikki tyΓΆtilani viestit ja tiedostot poistetaan.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.max_size": "Logon maksimikoko on 5 mb", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.bad_format": "VÀÀrΓ€ muoto, vain png gif ja jpg ovat sallittuja", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.unknown": "Tuntematon virhe", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.prefix": "Virhe", + "scenes.app.channelsbar.currentuser.reset": "Nollaa", + "components.rich_text_editor.plugins.suggestions.default_message.display_results": "Kirjoita vΓ€hintÀÀn kolme kirjainta nΓ€yttΓ€ville kΓ€yttΓ€jille", + "components.rich_text_editor.plugins.suggestions.default_message.no_user_found": "KΓ€yttΓ€jiΓ€ ei lΓΆytynyt", + "components.rich_text_editor.plugins.suggestions.default_message.no_emoji_found": "Emojia ei lΓΆytynyt", + "components.rich_text_editor.plugins.suggestions.default_message.no_command_found": "Komentoa ei lΓΆytynyt", + "scenes.app.messages.input.parts.is_writing.message.user_is_writing": "{{$1}} kirjoittaa...", + "scenes.app.messages.input.parts.is_writing.message.users_are_writing": "{{$1}} ja {{$2}} kirjoittavat...", + "scenes.app.messages.input.parts.is_writing.message.users_and_more_are_writing": "{{$1}}, {{$2}} ja {{$3}} lisÀÀ kΓ€yttΓ€jiΓ€ kirjoittaa...", + "components.locked_features_components.locked_invite_alert.message_part_1": "Yrityksesi on saavuttanut {{$1}} jΓ€senten enimmΓ€israjan. Ole kiltti ", + "components.locked_features_components.locked_invite_alert.message_link": "pΓ€ivittÀÀ yritystΓ€si", + "components.locked_features_components.locked_invite_alert.message_part_2": " kutsua lisÀÀ jΓ€seniΓ€.", + "components.locked_features_components.locked_invite_alert.message_magic_link": " ota yhteyttΓ€ yrityksesi omistajaan tai yllΓ€pitΓ€jÀÀn.", + "views.client.popup.workspace_parameter.pages.workspace_members.link_to_console": "Katso kaikki yritykseni jΓ€senet konsolissa", + "scenes.app.popup.appsparameters.pages.application_editor.help_text": "Jos et tiedΓ€ kuinka tΓ€yttÀÀ nΓ€mΓ€, mene osoitteeseen ", + "scenes.app.popup.appsparameters.pages.app.private_key": "Yksityinen avain", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed": "Sovelluksen {{$1}} poistaminen onnistui!", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed_error": "Virhe poistettaessa sovellusta {{$1}} !", + "scenes.app.popup.appsparameters.pages.amazing_app_description": "Kuvaile hakemustasi muutamalla sanalla", + "scenes.app.popup.appsparameters.pages.application_creator.title": "Uusi integraatio", + "scenes.app.popup.appsparameters.pages.application_creator.checkbox": "YmmΓ€rrΓ€n, ettΓ€ tΓ€mΓ€n yrityksen omistaja ja jΓ€rjestelmΓ€nvalvojat voivat muokata ja julkaista tΓ€tΓ€ sovellusta.", + "twake.application.access.title": "Valitse sovelluksellesi oikeat laajuudet.", + "twake.application.access.no_default_scopes_available'": "TΓ€llΓ€ integraatiolla ei ole {{$1}}-kΓ€yttΓΆoikeutta", + "scenes.app.popup.appsparameters.pages.application_editor.help_link": "Twake API -dokumentaatio", + "scenes.app.popup.appsparameters.pages.application_editor.application_published": "{{$1}} -sovellus onnistui!", + "scenes.app.integrations_parameters.add_application": "Uusi integraatio", + "scenes.app.integrations_parameters.company_applications_table.more_menu.developer_settings": "KehittΓ€jΓ€asetukset", + "components.rich_text_editor.plugins.suggestions.loading": "EtsitkΓΆ lisÀÀ", + "components.open_desktop_popup.subtitle": "avattu Twake-sovelluksessa", + "components.open_desktop_popup.open_here_link": "Avaa sen sijaan tΓ€stΓ€", + "molecules.download_banner.title": "Ota kaikki irti Twakesta ja lataa tyΓΆpΓΆytΓ€sovellus nyt", + "molecules.download_banner.download_button": "Lataa tyΓΆpΓΆytΓ€sovellus", + "scenes.app.channelsbar.channel_copy_link": "Kopioi kanavan linkki", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.success.update": "PΓ€ivitetty onnistuneesti", + "components.searchpopup.no_results_for": "Ei ollut tuloksia kohteelle", + "components.searchpopup.try_new_search": "Kokeile uutta hakua", + "components.searchpopup.all": "Kaikki", + "components.searchpopup.chats": "Chatit", + "components.searchpopup.media": "Media", + "components.searchpopup.files": "Tiedostot", + "components.searchpopup.recent_chats": "Viimeaikaiset keskustelut", + "components.searchpopup.recent_media": "Viimeaikainen media", + "components.searchpopup.recent_files": "Viimeaikaiset tiedostot", + "components.searchpopup.recent_channels_and_contacts": "ViimeisimmΓ€t kanavat ja yhteystiedot", + "components.searchpopup.header_title": "Hae", + "components.searchpopup.scope.company": "kaikessa seurassa", + "components.searchpopup.scope.channel": "tΓ€llΓ€ kanavalla", + "components.searchpopup.channels": "Kanavat", + "components.searchpopup.messages": "Viestit", + "scenes.client.channelbar.channelmemberslist.not_members_section": "KΓ€yttΓ€jΓ€t, jotka eivΓ€t ole tΓ€llΓ€ kanavalla", + "scenes.client.join_public_channel": "Liity tΓ€lle kanavalle", + "scenes.client.join_public_channel.info": "Et ole tΓ€mΓ€n suoran kanavan jΓ€sen. Napsauta tΓ€tΓ€ painiketta aloittaaksesi keskustelun nyt.", + "components.searchpopup.start_search": "SyΓΆtΓ€ muutama avainsana aloittaaksesi haun.", + "components.searchpopup.see_more": "Katso lisÀÀ", + "scenes.client.channelbar.channelmemberslist.search_invite": "Etsi ja kutsu kΓ€yttΓ€jiΓ€ tΓ€lle kanavalle", + "scenes.client.channelbar.channelmemberslist.search_invite_notice": "TΓ€llΓ€ kanavalla ei ole paljon jΓ€seniΓ€. Hae ja kutsu kΓ€yttΓ€jiΓ€ nyt sΓ€hkΓΆpostitse tai nimellΓ€.", + "scenes.client.channelbar.channelmemberslist.invite_email_button": "LisÀÀ kanavalle vain vieraana", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace": "LisÀÀ kanavaan ja tyΓΆtilaan jΓ€senenΓ€", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace_confirm": "Kutsutaanko {{$1}} tyΓΆtilaan jΓ€seneksi?", + "scenes.client.channelbar.channelmemberslist.search_invite_type_email": "Kirjoita kelvollinen lisΓ€ys kutsuaksesi sΓ€hkΓΆpostitse.", + "scenes.client.channelbar.channelmemberslist.pending_section": "KΓ€yttΓ€jΓ€t odottavat kutsua", + "scenes.client.channelbar.channelmemberslist.members_section": "TΓ€mΓ€n kanavan kΓ€yttΓ€jΓ€t", + "scenes.client.join_private_channel.info": "TΓ€mΓ€ tΓ€mΓ€n kanavan sisΓ€ltΓΆ on rajoitettu tai sitΓ€ ei ole olemassa. Ota yhteyttΓ€ tΓ€mΓ€n kanavan jΓ€seneen saadaksesi kutsun.", + "general.yes": "Joo", + "general.no": "Ei", + "components.open_desktop_popup.open_here_link_forever": "Γ„lΓ€ koskaan yritΓ€ avata sovellusta uudelleen", + "components.channel_attachement_list.medias": "Medias", + "components.channel_attachement_list.files": "Tiedostot", + "components.channel_attachement_list.title": "Kanavatiedostot ja mediat", + "components.channel_attachement_list.nothing_found": "Ei tÀÀllΓ€ vielΓ€ mitÀÀn", + "molecules.message_quote.deleted": "TΓ€mΓ€ viesti poistettiin", + "components.channel_attachement_list.open": "Avaa galleria", + "scenes.apps.messages.jump": "Siirry viestiin", + "scenes.apps.account.on_console": "Voit muokata yleisiΓ€ tiliasetuksiasi napsauttamalla Siirry konsoliin.", + "scenes.apps.account.assistant.description": "Twake-assistentti pystyy ymmΓ€rtΓ€mÀÀn jokapΓ€ivΓ€istΓ€ tyΓΆtΓ€si Twakella ja tarjoamaan Γ€lykkΓ€itΓ€ pikakuvakkeita ja toimintoja pΓ€ivΓ€n aikana. Assistentti on osa Work@Home-hanketta https://workathome.linagora.com/ ja sitΓ€ testataan tΓ€llΓ€ hetkellΓ€ vain Linagora-yrityksessΓ€ ja se on oppimisvaiheessa. Se tarkoittaa, ettΓ€ lΓ€hetΓ€mme Twaken kΓ€yttΓΆtietoja tulevan avustajaominaisuuden kouluttamiseksi.", + "scenes.apps.account.assistant.share.nothing": "Γ„lΓ€ jaa mitÀÀn avustajan kanssa (poista avustaja kΓ€ytΓΆstΓ€)", + "scenes.apps.account.assistant.share.all": "Jaa kaikki, mukaan lukien viestit ja tiedostojen sisΓ€ltΓΆ", + "scenes.apps.account.assistant.share.metadata": "Jaa metatietoja, mutta Γ€lΓ€ sisΓ€ltΓΆΓ€", + "scenes.apps.account.assistant.success": "Asetuksesi on pΓ€ivitetty onnistuneesti.", + "scenes.apps.account.assistant.title": "Assistant", + "components.message_seen_by.title": "Viestin nΓ€hneet kΓ€yttΓ€jΓ€t", + "components.message_seen_by.none_seen_it": "Kukaan ei ole vielΓ€ nΓ€hnyt viestiΓ€", + "components.message_seen_by.btn": "Tiedot", + "molecules.quoted_content.attachements": "{{$1}} liitteet", + "scenes.apps.messages.message.user_deactivated": "Katselet deaktivoidun tilin arkistoja", + "general.user.deactivated": "KΓ€yttΓ€jΓ€ ei ole enÀÀ tΓ€ssΓ€ yrityksessΓ€", + "general.user.connected": "verkossa", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_day": "1 pΓ€ivΓ€", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_hour": "1 tunti", + "scenes.app.popup.userparameter.pages.email_notif_delay_never": "Ei milloinkaan", + "scenes.app.popup.userparameter.pages.email_notif_delay_quarter_hour": "15 minuuttia", + "scenes.app.popup.userparameter.pages.notification_sound.defaut": "Oletus", + "scenes.app.popup.userparameter.pages.notification_sound.none": "Ei mitÀÀn", + "scenes.client.channelbar.readonly_channel.checkbox": "Rajoita kirjoituskykyΓ€", + "scenes.apps.messages.message.forward": "EteenpΓ€in", + "scenes.apps.messages.message.forward.title": "LΓ€hetΓ€ viesti eteenpΓ€in", + "scenes.apps.messages.message.forward.comment": "LisÀÀ viesti", + "scenes.apps.messages.message.forward.confirm": "LΓ€hetΓ€ $1 kanavalle", + "scenes.apps.messages.message.forward.send": "Viesti vΓ€litetty", + "components.channelselector.title": "Valitse kanavat", + "components.channelselector.confirm": "Valitse $1 kanava(a)", + "components.channelselector.search": "Etsi kanavia ja keskusteluja", + "scenes.app.channelsbar.channel_access": "Kanavan kΓ€yttΓΆoikeus", + "scenes.app.channelsbar.channel_access.save": "Tallenna kΓ€yttΓΆoikeusasetukset", + "scenes.app.channelsbar.channel_access.readonly": "Vain luku -kanava", + "scenes.app.channelsbar.channel_access.readonly.info": "Rajoita kirjoittaminen moderaattoreihin, yllΓ€pitΓ€jiin ja omistajiin.", + "scenes.app.channelsbar.channel_access.visibility": "Julkinen nΓ€kyvyys", + "scenes.app.channelsbar.channel_access.visibility.info": "Kaikki muut paitsi yrityksen vieraat voivat liittyΓ€.", + "scenes.app.channelsbar.channel_access.default": "Automaattinen liittyminen", + "scenes.app.channelsbar.channel_access.default.info": "Uudet jΓ€senet lisΓ€tÀÀn tΓ€nne automaattisesti.", + "scenes.app.channelsbar.channel_information": "Muokkaa kanavan tietoja", + "scenes.app.channelsbar.channel_information.logo.add": "Lataa kuva", + "scenes.app.channelsbar.channel_information.logo.remove": "Poista kuva", + "scenes.app.channelsbar.channel_information.name": "Kanavan nimi", + "scenes.app.channelsbar.channel_information.description": "Kanavan kuvaus", + "scenes.app.channelsbar.channel_information.description.placeholder": "Kanavan kuvaus, voit kΓ€yttÀÀ markdownia.", + "scenes.app.channelsbar.channel_information.group": "KanavaryhmΓ€", + "scenes.app.channelsbar.channel_information.group.none": "Ei valittu", + "scenes.app.channelsbar.channel_information.group.new": "Luo uusi ryhmΓ€", + "scenes.app.channelsbar.channel_information.group.save": "Aseta kanavaryhmΓ€ksi $1", + "scenes.app.channelsbar.channel_information.group.save_none": "Γ„lΓ€ aseta kanavaryhmÀÀ", + "scenes.app.channelsbar.channel_information.save": "Tallenna tiedot", + "scenes.client.channelbar.channelmemberslist.invite_to_workspace": "Kutsu {{$1}} tyΓΆtilaan ➑", + "components.invitation.invitation_input_list.member": "JΓ€sen", + "components.invitation.invitation_input_list.guest": "Vieras", + "components.invitation.reached_limit.text": "saavutit yrityksesi enimmΓ€ismÀÀrΓ€n kΓ€yttΓ€jiΓ€. Kasvata tilaustasi tai lisÀÀ nΓ€mΓ€ kΓ€yttΓ€jΓ€t vieraiksi", + "components.invitation.allow_anyone_by_email.text": "Anna kenen tahansa, jolla on @{{$1}}-sΓ€hkΓΆposti, liittyΓ€ tΓ€hΓ€n tyΓΆtilaan", + "components.invitation.invitation_channels.button": "Kutsu kanaville", + "components.invitation.invitation_input_list.add": "LisΓ€tΓ€", + "components.invitation.invitation_input_list.placeholder": "Aloita sΓ€hkΓΆpostin kirjoittaminen", + "components.invitation.invitation_sent.title": "Kutsut on lΓ€hetetty onnistuneesti", + "components.invitation.invitation_sent.subtitle_status": "Voit seurata kutsun tilaa:", + "components.invitation.invitation_sent.subtitle_location": "TyΓΆtilan asetukset > JΓ€senten hallinta", + "components.invitation.invitation_sent.link": "Tarkista kutsun tila", + "components.invitation.invitation_sent.button": "LΓ€hetΓ€ lisÀÀ kutsuja", + "components.invitation.invitation_target.invite_as_guests": "Kutsu kaikki vieraiksi", + "components.invitation.invitation_target.invite_as_members": "Kutsu kaikki jΓ€seniksi", + "components.invitation.invitation_target.channels_button": "Kutsuttavat kanavat", + "components.invitation.workspace_link.text": "TyΓΆtilan kutsulinkki", + "components.invitation.workspace_link.button": "Kopio", + "components.invitation.title": "kutsu ihmisiΓ€ {{$1}}", + "components.invitation.bulk_invitation": "Joukkokutsu", + "components.invitation.button": "LΓ€hettÀÀ kutsuja", + "scenes.client.readonly.info": "TΓ€mΓ€ kanava on vain luku -syΓΆte, mutta voit kommentoida sΓ€ikeissΓ€.", + "scenes.app.channelsbar.channel_information.group.title": "KanavaryhmΓ€t", + "components.invitation.custom_role_invitation": "Klassinen kutsu", + "components.invitation.link": "Linkki" +} diff --git a/twake/frontend/public/locales/fr.json b/twake/frontend/public/locales/fr.json new file mode 100644 index 00000000..324906b2 --- /dev/null +++ b/twake/frontend/public/locales/fr.json @@ -0,0 +1,1008 @@ +{ + "general.close": "Fermer", + "general.save": "Enregistrer", + "general.cancel": "Annuler", + "general.retry": "RΓ©essayer", + "general.create": "CrΓ©er", + "general.edit": "Modifier", + "general.continue": "Continuer", + "general.back": "Retour", + "general.confirm": "Confirmer", + "general.delete": "Supprimer", + "general.archive": "Archiver", + "general.unarchive": "DΓ©sarchiver", + "general.help": "Aide", + "general.help.support": "Support", + "general.help.documentation": "Documentation", + "general.send": "Envoyer un message", + "general.update": "Mettre Γ  jour", + "general.remove": "Supprimer", + "general.add": "Ajouter", + "general.yes": "Oui", + "general.no": "Non", + "general.connexion_status.disconnected": "Vous Γͺtes hors ligne", + "general.connexion_status.connected": "Vous Γͺtes connectΓ©", + "general.connexion_status.connecting": "Reconnexion en cours…", + "application.load.longer": "Le serveur met plus de temps que prΓ©vu Γ  rΓ©pondre, veuillez attendre ou rechargez la page...", + "scenes.app.side_app.messages_thread_title": "{{$1}} β€’ RΓ©ponses Γ  un message", + "scenes.app.workspaces.create_company.group_data": "Configurez votre nouveau groupe", + "scenes.app.workspaces.create_company.group_data.group_type": "Type de groupe", + "scenes.app.workspaces.create_company.group_data.group_type.company": "Entreprise ou dΓ©partement d'entreprise", + "scenes.app.workspaces.create_company.group_data.group_type.public_organization": "Organisation publique", + "scenes.app.workspaces.create_company.group_data.group_type.university_school": "UniversitΓ© ou Γ©cole", + "scenes.app.workspaces.create_company.group_data.group_type.society_club_charity": "SociΓ©tΓ©, club ou association", + "scenes.app.workspaces.create_company.group_data.group_type.other_group": "Autre", + "scenes.app.workspaces.create_company.group_data.group_size": "Taille du groupe", + "scenes.app.workspaces.create_company.group_data.group_size.less_3": "Moins de 4 utilisateurs", + "scenes.app.workspaces.create_company.group_data.group_size.4_10": "4 - 10 utilisateurs", + "scenes.app.workspaces.create_company.group_data.group_size.10_50": "11 - 49 utilisateurs", + "scenes.app.workspaces.create_company.group_data.group_size.50_100": "50 - 99 utilisateurs", + "scenes.app.workspaces.create_company.group_data.group_size.100_500": "100 - 499 utilisateurs", + "scenes.app.workspaces.create_company.group_data.group_size.500_1000": "500 - 999 utilisateurs", + "scenes.app.workspaces.create_company.group_data.group_size.1000_5000": "1000 - 4999 utilisateurs", + "scenes.app.workspaces.create_company.group_data.group_size.5000_more": "Plus de 5000 utilisateurs", + "scenes.app.workspaces.create_company.group_data.group_main_activity": "ActivitΓ© principale", + "scenes.app.workspaces.create_company.group_data.group_main_activity.food": "Agroalimentaire", + "scenes.app.workspaces.create_company.group_data.group_main_activity.bank": "Banque / Assurance", + "scenes.app.workspaces.create_company.group_data.group_main_activity.printing_paper": "Impression / Papier", + "scenes.app.workspaces.create_company.group_data.group_main_activity.construction_building": "MatΓ©riaux de construction / BTP", + "scenes.app.workspaces.create_company.group_data.group_main_activity.real_estate": "Immobilier", + "scenes.app.workspaces.create_company.group_data.group_main_activity.materials": "MatΓ©riaux", + "scenes.app.workspaces.create_company.group_data.group_main_activity.chemistry": "Chimie", + "scenes.app.workspaces.create_company.group_data.group_main_activity.trade_commerce_distribution": "Commerce / NΓ©goce / Distribution", + "scenes.app.workspaces.create_company.group_data.group_main_activity.publishing_communication_multimedia": "Publication / Communication / MultimΓ©dia", + "scenes.app.workspaces.create_company.group_data.group_main_activity.electronics_electricity_energy": "Γ‰lectronique / Γ‰lectricitΓ© / Γ‰nergie", + "scenes.app.workspaces.create_company.group_data.group_main_activity.studies_and_advice": "Γ‰tudes et conseils", + "scenes.app.workspaces.create_company.group_data.group_main_activity.pharmaceutical_industry": "Industrie pharmaceutique", + "scenes.app.workspaces.create_company.group_data.group_main_activity.it_telecom": "Informatique / TΓ©lΓ©coms", + "scenes.app.workspaces.create_company.group_data.group_main_activity.machinery_automotive": "Machines / Automobile", + "scenes.app.workspaces.create_company.group_data.group_main_activity.business_services": "Services aux entreprises", + "scenes.app.workspaces.create_company.group_data.group_main_activity.entertainment": "Divertissements", + "scenes.app.workspaces.create_company.group_data.group_main_activity.textile_clothing_shoes": "Textile / Habillement / Chaussures", + "scenes.app.workspaces.create_company.group_data.group_main_activity.transport_logistics": "Transports / Logistique", + "scenes.app.workspaces.create_company.group_data.group_main_activity.research": "Recherche", + "scenes.app.workspaces.create_company.group_data.group_main_activity.education": "Γ‰ducation", + "scenes.app.workspaces.create_company.group_data.group_main_activity.administration": "Administration", + "scenes.app.workspaces.create_company.group_data.group_main_activity.other": "Autre", + "components.application.messages": "Messages", + "components.drive_dropzone.uploading": "TΓ©lΓ©chargement...", + "components.user_picker.modal_no_result": "Aucun rΓ©sultat trouvΓ©", + "components.users_picker.add_me": "M'ajouter", + "scenes.app.workspaces.create_company.invitations.title": "Configurez votre espace de travail.", + "scenes.app.header.disconnected": "Vous Γͺtes dΓ©connectΓ©", + "scenes.app.header.disconnected.reload": "Recharger", + "scenes.app.header.alt_notifications": "Notifications", + "scenes.apps.calendar.calendar.week_btn": "Semaine", + "scenes.apps.calendar.calendar.list_btn": "Liste", + "scenes.apps.calendar.event_edition.deadline_tag": "Date limite", + "scenes.apps.calendar.event_edition.checkbox_all_day": "Toute la journΓ©e", + "scenes.apps.calendar.event_edition.title_confidentiality": "Participants", + "scenes.apps.calendar.event_view.article_until": "Γ ", + "scenes.apps.calendar.calendar_modal.participants": "Participants", + "scenes.apps.calendar.calendar_modal.placeholder": "Nom", + "scenes.apps.calendar.left.calendars": "Calendriers", + "scenes.apps.drive.left.search": "Recherche", + "scenes.apps.drive.navigators.navigator_content.directory_name": "Nom du rΓ©pertoire", + "scenes.apps.drive.navigators.navigator_content.files": "Fichiers", + "scenes.apps.drive.navigators.navigator_labels.title": "Γ‰tiquettes", + "scenes.apps.drive.navigators.new_file.untitled": "Sans titre", + "scenes.apps.drive.navigators.new_file.create_file.type": "Type", + "scenes.apps.drive.navigators.new_file": "Nouveau fichier", + "scenes.apps.drive.preview_bloc.operations_download": "TΓ©lΓ©charger", + "scenes.apps.drive.preview_bloc.error_file": "Fichier non trouvΓ©", + "scenes.apps.drive.right_preview.operations_restore": "Restaurer", + "scenes.apps.drive.right_preview.operations_delete": "Mettre Γ  la corbeille", + "scenes.apps.drive.right_preview.public_link": "Lien public", + "scenes.apps.messages.messages": "Messages", + "scenes.apps.messages.chatbox.chat.delete_message": "Supprimer ce message", + "scenes.apps.messages.chatbox.chat.delete_message_btn": "Supprimer", + "scenes.apps.messages.left_bar.stream_modal.placeholder_name": "Nom", + "scenes.apps.messages.left_bar.stream.add_to_favorites": "Ajouter aux favoris", + "scenes.apps.messages.left_bar.stream.remove_from_favorites": "Retirer des favoris", + "scenes.apps.messages.left_bar.stream.notifications": "Notifications...", + "scenes.apps.messages.left_bar.stream.notifications.all": "Tous les messages", + "scenes.apps.messages.left_bar.stream.notifications.mentions": "{{$1}}, {{$2}} et {{$3}}", + "scenes.apps.messages.left_bar.stream.notifications.me": "{{$1}} seulement", + "scenes.apps.messages.left_bar.stream.notifications.never": "Aucun message", + "scenes.apps.parameters.workspace_sections.workspace": "Espace de travail", + "scenes.apps.parameters.workspace_sections.members": "Participants de la chaΓne", + "scenes.apps.parameters.group_sections.workspaces": "Espaces de travail", + "scenes.apps.parameters.group_sections.apps": "Applications", + "scenes.apps.account.title": "ParamΓ¨tres du compte", + "scenes.apps.account.account.menu_title": "Compte", + "scenes.apps.account.languages.menu_title": "Langues", + "scenes.apps.account.account.firstname": "PrΓ©nom", + "scenes.apps.account.account.lastname": "Nom de famille", + "scenes.apps.account.account.username": "Nom d'utilisateur", + "scenes.apps.account.account.change_username": "Modifiez votre nom unique d'utilisateur.", + "scenes.apps.account.account.emails": "Courriels", + "scenes.apps.account.account.main_email": "E-mail principal", + "scenes.apps.account.account.email_add": "Ajouter un nouvel e-mail", + "scenes.apps.account.account.email_add_modal.invalid_code": "Ce code est invalide", + "scenes.apps.account.account.password": "Mot de passe", + "scenes.apps.account.account.password_modal.old_password": "Mot de passe actuel", + "scenes.apps.account.account.password_modal.password": "Nouveau mot de passe", + "scenes.apps.account.account.password_modal.bad_old_password": "L'ancien mot de passe n'est pas correct.", + "scenes.apps.account.account.password_modal.bad_password": "Vos mots de passe ne correspondent pas ou sont trop petits, veuillez saisir un mot de passe d'au moins 8 caractΓ¨res.", + "scenes.apps.account.account.logout": "DΓ©connecter", + "scenes.apps.account.languages.text": "Changer la langue de Twake.", + "scenes.apps.account.notifications.title": "Notifications", + "scenes.apps.account.notifications.keywords_subtitle": "Mots clΓ©s", + "scenes.apps.account.notifications.keywords_placeholder": "important, wifi, code, ...", + "scenes.apps.account.notifications.disturb_option_a": "Ne pas envoyez de notifications sur tΓ©lΓ©phone entre ", + "scenes.apps.account.notifications.disturb_option_b": " et ", + "scenes.apps.account.notifications.disturb_option_c": " (fuseau horaire local)", + "scenes.apps.account.notifications.devices_subtitle": "Notifications de pΓ©riphΓ©riques", + "scenes.apps.account.notifications.devices_option_ever": "Envoyez-moi toujours des notifications sur tΓ©lΓ©phone", + "scenes.apps.account.notifications.devices_option_inactive": "Envoyez-moi des notifications sur tΓ©lΓ©phone lorsque je suis inactif sur le bureau", + "scenes.apps.account.notifications.devices_option_never": "Ne jamais envoyez de notifications sur tΓ©lΓ©phone", + "scenes.apps.account.notifications.privacy_subtitle": "ConfidentialitΓ©", + "scenes.apps.account.notifications.mail_subtitle": "Notifications e-mail", + "scenes.apps.account.notifications.sound": "Notification sonore", + "scenes.apps.parameters.group_sections.apps.badge_extension": "Extension", + "scenes.apps.parameters.workspace_sections.members.members": "Utilisateurs", + "scenes.apps.parameters.workspace_sections.members.pending": "Email(s) en attente", + "scenes.apps.parameters.workspace_sections.members.invite": "Inviter de nouveaux utilisateurs", + "scenes.apps.parameters.workspace_sections.members.invite_btn": "Ajouter des utilisateurs", + "scenes.apps.tasks.boards": "Tableaux", + "scenes.apps.tasks.connectors_menu": "Connecteurs...", + "scenes.apps.tasks.connectors_search_menu": "Chercher des connecteurs...", + "scenes.apps.tasks.no_connectors_menu_text": "Vous n'avez pas de connecteur qui peut se connecter Γ  un calendrier.", + "scenes.apps.tasks.unconfigured_tab": "Cet onglet n'est pas encore configurΓ©.", + "scenes.apps.tasks.new_board.title": "Nouveau tableau", + "scenes.apps.tasks.choose_board_button": "Choisir un tableau", + "scenes.apps.tasks.new_board.edit_title": "Γ‰diter le tableau", + "scenes.apps.tasks.task": "TΓ’che", + "scenes.apps.tasks.no_tasks": "Aucune tΓ’che", + "scenes.apps.tasks.task_status.todo": "Non commencΓ©es", + "scenes.apps.tasks.task_status.current": "En cours", + "scenes.apps.tasks.task_status.done": "TerminΓ©es", + "scenes.apps.tasks.task.description": "Description", + "scenes.apps.tasks.task.assignees": "AssignΓ©s", + "scenes.apps.tasks.task.edit.dates": "Dates", + "scenes.apps.tasks.list_modal.modify_list": "Modifier la liste", + "scenes.apps.tasks.list_modal.new_list": "Nouvelle liste", + "scenes.apps.tasks.list_modal.remove": "Supprimer la liste et les tΓ’ches", + "scenes.apps.tasks.list_modal.predefined_participants": "Participants prΓ©dΓ©finis", + "scenes.apps.tasks.list_modal.archive_all_tasks": "Archiver toutes les tΓ’ches", + "scenes.apps.tasks.list_modal.remove_archived_tasks": "Supprimer les archivΓ©es ({{$1}})", + "scenes.login.footer.go_to_twake": "Aller Γ  twakeapp.com", + "scenes.login.footer.branding": "Vous Γͺtes sur un serveur privΓ© Twake appartenant Γ  {{$1}} ({{$2}}). ", + "scenes.login.create_account.title": "CrΓ©er un nouveau compte", + "scenes.login.create_account.email": "E-mail", + "scenes.login.create_account.email_used": "Cette adresse mail est dΓ©jΓ  utilisΓ©e.", + "scenes.login.create_account.username": "Nom d'utilisateur", + "scenes.login.create_account.username_already_exist": "Ce nom d'utilisateur est dΓ©jΓ  utilisΓ©", + "scenes.login.create_account.fill_in_username": "Vous devez choisir un nom d'utilisateur", + "scenes.login.create_account.fill_in_email": "Vous devez complΓ©ter le champs e-mail avec une adresse correcte", + "scenes.login.create_account.too_short_password": "Votre mot de passe doit contenir au minimum 8 caractΓ¨res.", + "scenes.login.create_account.firstname": "PrΓ©nom", + "scenes.login.create_account.newsletter": "Recevoir des informations Γ  propos de Twake", + "scenes.login.create_account.lastname": "Nom", + "scenes.login.forgot_password.title": "Mot de passe oubliΓ© ?", + "scenes.login.forgot_password.text": "Vous recevrez 9 chiffres par e-mail afin de vΓ©rifier votre identitΓ©.", + "scenes.login.forgot_password.email_to_recover": "E-mail de rΓ©cupΓ©ration", + "scenes.login.forgot_password.mail_doesnt_exist": "Cet e-mail n'existe pas", + "scenes.login.forgot_password.text2": "Vous recevrez un code de 9 caractΓ¨res. S'il vous plaΓt entrer dans le champ ci-dessous afin de continuer.", + "scenes.login.forgot_password.invalid_code": "Ce code n'est pas valide.", + "scenes.login.forgot_password.text3": "Veuillez entrer un nouveau mot de passe.", + "scenes.login.forgot_password.password": "Mot de passe", + "scenes.login.forgot_password.password2": "Confirmez le mot de passe", + "scenes.login.forgot_password.password_dont_match": "Vos mots de passe ne correspondent pas ou sont trop petits, veuillez saisir un mot de passe d'au moins 8 caractΓ¨res.", + "scenes.login.home.title": "Connectez-vous Γ  Twake", + "scenes.login.home.subtitle": "Heureux de vous revoir", + "scenes.login.home.email": "Email", + "scenes.login.home.unable_to_connect": "Informations d'identification invalides", + "scenes.login.home.password": "Mot de passe", + "scenes.login.home.login_btn": "S'identifier", + "scenes.login.home.lost_password": "Mot de passe oubliΓ© ?", + "scenes.login.home.create_account": "CrΓ©er un compte", + "scenes.login.create_account.password": "Mot de passe", + "scenes.login.create_account.step_1_subtitle": "Rien de plus simple, nous avons besoin de quelques informations.", + "scenes.login.create_account.step_2_subtitle_a": "Ajoutez un prΓ©nom et un nom pour que les utilisateurs vous reconnaissent.", + "scenes.login.create_account.step_2_subtitle_b": "Votre numΓ©ro de tΓ©lΓ©phone, lui, reste privΓ©.", + "scenes.login.create_account.step_3_mail_sent": "Nous vous avons envoyΓ© un lien d'activation par courriel.", + "scenes.login.create_account.step_3_subtitle": "DerniΓ¨re Γ©tape, nous avons besoin de vΓ©rifier que vous n’Γͺtes pas un robot !", + "scenes.app.workspaces.create_company.company_name.placeholder": "Nom de votre entreprise", + "scenes.app.workspaces.create_company.company_name.title_1": "Pour commencer,", + "scenes.app.workspaces.create_company.company_name.title_2": "indiquez le nom de votre entreprise.", + "scenes.app.workspaces.create_company.default_workspace_name": "Principal", + "scenes.app.workspaces.create_company.group_data.title": "Faisons vite, nous avons juste besoin de quelques informations statistiques.", + "scenes.app.workspaces.create_company.importations.title_1": "Vous travaillez dΓ©jΓ  avec des outils numΓ©riques ? Importez ou intΓ©grez vos outils dΓ¨s maintenant !", + "scenes.app.workspaces.create_company.importations.title_2": "Pas d’inquiΓ©tude, vous pourrez y revenir plus tard !", + "scenes.app.workspaces.create_company.invitations.title_2": "Ajoutez vos utilisateurs.", + "scenes.app.workspaces.create_company.title": "CrΓ©ation de mon entreprise", + "scenes.app.workspaces.welcome_page.add_secondary_emails": "Ajouter un e-mail secondaire", + "scenes.app.workspaces.welcome_page.added_to_company": "Vous avez Γ©tΓ© invitΓ© dans l’entreprise ", + "scenes.app.workspaces.welcome_page.create_my_company": "CrΓ©er mon entreprise", + "scenes.app.workspaces.welcome_page.lets_go": "C'est parti !", + "scenes.app.workspaces.welcome_page.may_be_invited_with_secondary_emails": "Vous avez peut-Γͺtre Γ©tΓ© invitΓ© Γ  l’aide d’une autre adresse e-mail ?", + "scenes.app.workspaces.welcome_page.no_company_subtitle": "Ha, mince… Il semblerait que personne ne vous ait invitΓ© dans une entreprise pour le moment.", + "scenes.app.workspaces.welcome_page.no_workspace_subtitle": "Personne ne vous a invitΓ© dans un espace de travail pour le moment.", + "scenes.app.workspaces.welcome_page.ready_to_work": "Vous Γͺtes prΓͺt Γ  travailler maintenant.", + "scenes.app.workspaces.welcome_page.see_you_soon": "Γ€ trΓ¨s bientΓ΄t !", + "scenes.app.workspaces.welcome_page.try_again": "RΓ©essayer", + "scenes.app.workspaces.welcome_page.twake_team": "L'Γ©quipe Twake", + "scenes.app.workspaces.welcome_page.welcome_header": "Bienvenue sur Twake !", + "scenes.app.workspaces.welcome_page.add_secondary_emails_comment": "Vous pouvez lier plusieurs adresse e-mail Γ  votre compte, seule une adresse sera utilisΓ©e pour vous envoyer des notifications.", + "scenes.app.workspaces.welcome_page.main_mail_title": "Adresse principale", + "scenes.app.workspaces.welcome_page.other_mail_title": "Adresses secondaires", + "scenes.app.workspaces.welcome_page.add_new_email": "Ajouter un e-mail", + "scenes.app.workspaces.welcome_page.code_verification": "Code de vΓ©rification", + "scenes.app.workspaces.welcome_page.new_email": "Ajouter un e-mail secondaire", + "scenes.app.workspaces.welcome_page.we_sent_you_mail": "Nous vous avons envoyΓ© un code de vΓ©rification via l’adresse {{$1}}", + "scenes.app.workspaces.welcome_page.done": "J'ai fini", + "scenes.login.forgot_password.finished": "Votre mot de passe a bien Γ©tΓ© mis Γ  jour.", + "scenes.apps.account.account.description_main": "Votre adresse principale est celle Γ  qui Twake envoie vos notifications. Vos adresses secondaires vous permettent d'Γͺtre invitΓ© automatiquement dans les espaces de travail qui les utilisent.", + "scenes.apps.account.account.emails.description": "GΓ©rez vos diffΓ©rentes adresses email.", + "scenes.apps.account.account.make_main": "DΓ©finir principale", + "scenes.apps.account.account.password.description": "Modifiez votre mot de passe.", + "scenes.apps.account.identity": "IdentitΓ©", + "scenes.apps.account.identity.description": "Modifiez votre prΓ©nom, nom et votre image de profil visible par les autres utilisateurs de Twake.", + "scenes.apps.account.preference": "PrΓ©fΓ©rences", + "general.open": "Ouvrir", + "scenes.apps.account.thumbnail.max_weight": "Poids maximum 5 mo", + "scenes.apps.account.account.email_add_modal.confirm": "Confirmer cet email", + "app.name.twake_calendar": "Calendrier", + "app.name.twake_drive": "Documents", + "app.name.twake_tasks": "TΓ’ches", + "components.calendar.repetition.everyday": "Tous les jours", + "components.calendar.repetition.does_not_repeat": "Une seule fois", + "components.calendar.repetition.weekly_on": "Toutes les semaines le {{$1}}", + "components.calendar.repetition.monthly_on": "Tous les mois le {{$1}} {{$2}}", + "components.calendar.repetition.annually_on": "Tous les ans le {{$1}}", + "components.calendar.repetition.monthly_on_day": "tous les {{$1}} du mois", + "components.calendar.repetition.every_weekday": "Tous les jours de la semaine", + "components.calendar.repetition.custom": "Personnalisé…", + "components.calendar.repetition.repeat": "RΓ©peter chaque", + "components.calendar.repetition.ends": "Jusqu'Γ ", + "components.calendar.repetition.never": "Jamais", + "components.calendar.repetition.on": "En", + "components.calendar.repetition.after": "Pendant", + "components.calendar.repetition.days": "jour(s)", + "components.calendar.repetition.weeks": "semaine(s)", + "components.calendar.repetition.months": "Mois", + "components.calendar.repetition.years": "annΓ©e(s)", + "components.calendar.repetition.custom_recurrence": "RΓ©pΓ©titions personnalisΓ©es", + "components.calendar.repetition.occurrence": "Occurrence(s)", + "components.calendar.repetition.repeat_on": "Repeter le", + "scenes.app.channelsbar.currentuser.add_apps": "Chercher des applications", + "scenes.app.channelsbar.currentuser.change_my_status": "Changer mon statut", + "scenes.app.channelsbar.currentuser.collaborateurs": "Utilisateurs", + "scenes.app.channelsbar.currentuser.create_workspace_page": "CrΓ©er un espace de travail", + "scenes.app.channelsbar.currentuser.invited_status": "Vous Γͺtes un invitΓ©(e).", + "scenes.app.channelsbar.currentuser.title": "ParamΓ¨tres du compte", + "scenes.app.channelsbar.currentuser.workspace_info": "Vous Γͺtes dans l'espace de travail {{$1}} du groupe {{$2}}", + "scenes.app.channelsbar.currentuser.workspace_parameters": "ParamΓ¨tres de l'espace", + "scenes.app.channelsbar.currentuser.logout": "Se dΓ©connecter", + "scenes.app.channelsbar.currentuser.update": "Mettre Γ  jour", + "scenes.app.channelsbar.currentuser.disable_notifications": "DΓ©sactiver", + "scenes.app.channelsbar.currentuser.disabling_notifications": "DΓ©sactiver pendant 1h", + "scenes.app.channelsbar.currentuser.disabling_notifications_until": "DΓ©sactiver jusqu'Γ  demain 9h", + "scenes.app.channelsbar.currentuser.reactivate_notifications": "RΓ©activer", + "scenes.app.channelsbar.currentuser.user_parameter": "ParamΓ¨tres de notification", + "scenes.app.channelsbar.channelsuser.new_private_discussion": "Nouvelle discussion privΓ©e", + "scenes.app.channelsbar.channelsuser.no_private_message_invite_collaboraters": "Aucun message privΓ©, invitez des utilisateursΒ !", + "scenes.app.channelsbar.channelsuser.private_messages": "Messages directs", + "scenes.app.channelsbar.channelsworkspace.channel_title": "CHAÎNES", + "scenes.app.channelsbar.channelsworkspace.channel_title.favorite": "FAVORIS", + "scenes.app.channelsbar.channelsworkspace.create_channel": "CrΓ©er une chaΓne", + "scenes.app.channelsbar.channelsworkspace.no_channel": "Vous n'avez encore rejoint aucune chaΓne", + "scenes.app.channelsbar.modify_channel_menu": "Modifier la chaΓne", + "scenes.app.channelsbar.guest_management": "Gestion des invitΓ©s", + "scenes.app.channelsbar.read_sign": "Marquer comme lu", + "scenes.app.channelsbar.unread_sign": "Marquer comme non lu", + "scenes.app.channelsbar.channel_copy_link": "Copier le lien de la chaΓne", + "scenes.app.channelsbar.channel_leaving": "Quitter la chaΓne", + "scenes.app.channelsbar.channel_removing": "Supprimer la chaΓne", + "scenes.app.channelsbar.company_invitation_alert_subtitle": "Vous pouvez importer ces chaΓnes dans votre entreprise pour rester organisΓ© en cliquant sur ce cadre.", + "scenes.app.channelsbar.company_invitation_alert_title": "Vous Γͺtes invitΓ©(e) dans l'entreprise ", + "scenes.app.channelsbar.initial_instructions_tutorial": "Choisissez un prΓ©nom, un nom et une image de profil.", + "scenes.app.channelsbar.installation_desktop_tutorial": "Installer l'application desktop", + "scenes.app.channelsbar.invitation_collaboraors_tutorial": "Invitez vos utilisateurs dans votre espace de travail.", + "scenes.app.channelsbar.public_channel_label": "ChaΓne publique", + "scenes.app.channelsbar.private_channel_label": "ChaΓne privΓ©e", + "scenes.app.channelsbar.sending_message_instruction": "Envoyer un premier message dans une discussion", + "scenes.app.channelsbar.tutorial_alert": "Ne plus jamais afficher ce cadre ?", + "scenes.app.channelsbar.welcome": "Bienvenue sur Twake", + "scenes.app.channelsbar.welcoming_message_subtitle": "Devenez un pro de Twake en seulement quelques clics !", + "scenes.app.mainview.instruction_current_tab": "Commencez par sΓ©lectionner une chaΓne sur votre gauche.", + "scenes.app.mainview.tabs.no_connected_connectors_for_channel": "Vous n'avez aucun connecteur capable de se connecter Γ  une chaΓne.", + "scenes.app.mainview.tabs.rename": "Renommer", + "scenes.app.mainview.tabs.searching_connectors": "Chercher des connecteurs...", + "scenes.app.popup.adduser.adresses_message": "Veuillez sΓ©parer les adresses par une virgule ou un espace. N'oubliez pas que Twake peut limiter le nombre d'invitation en fonction de votre abonnement.", + "scenes.app.popup.appsparameters.pages._app_identity": "IdentitΓ© de l'application", + "scenes.app.popup.appsparameters.pages._appareance_message_twakcode": "Testez l'apparence de vos messages Twacode", + "scenes.app.popup.appsparameters.pages.alert_published_app": "Votre application est publiΓ©e, vous ne pouvez pas la modifier.", + "scenes.app.popup.appsparameters.pages.allowed_ip_adresses_method": "Utilisez * en dΓ©veloppement pour autoriser toutes les adresses IP.", + "scenes.app.popup.appsparameters.pages.amazing_app_name": "Ma super application", + "scenes.app.popup.appsparameters.pages.api_data_description": "DonnΓ©es utiles pour l'API Twake.", + "scenes.app.popup.appsparameters.pages.api_parameters_label": "ParamΓ¨tres de l'API", + "scenes.app.popup.appsparameters.pages.app_name_label": "Nom de l'application", + "scenes.app.popup.appsparameters.pages.app_modification_right": "Tous les gΓ©rants de cette entreprise pourront modifier cette application.", + "scenes.app.popup.appsparameters.pages.app_privileges_information": "Permet de dΓ©finir ce que votre application peut modifier et lire.", + "scenes.app.popup.appsparameters.pages.app_privileges_label": "PrivilΓ¨ges de l'application", + "scenes.app.popup.appsparameters.pages.app_update": "Mettre Γ  jour l'application {{$1}} (l'application est utilisΓ©e {{$2}} fois.)", + "scenes.app.popup.appsparameters.pages.application_title": "Application", + "scenes.app.popup.appsparameters.pages.apps_title": "Vos applications et connecteurs", + "scenes.app.popup.appsparameters.pages.automatique_label": "Automatique", + "scenes.app.popup.appsparameters.pages.automatique_option_information": "Si vous activez 'Automatique', cette application sera automatiquement ajoutΓ©e dans les prochains espaces de travail de cette entreprise.", + "scenes.app.popup.appsparameters.pages.autorised_ip_adresses_label": "Adresses IP autorisΓ©es", + "scenes.app.popup.appsparameters.pages.available_publication_alert": "La publication de votre application est actuellement en attente de validation par les Γ©quipes de Twake.", + "scenes.app.popup.appsparameters.pages.button_force": "Forcer dans toute l'entreprise", + "scenes.app.popup.appsparameters.pages.call_event_handlers": "Γ‰vΓ¨nement de type {{$1}} et d'identifiant {{$2}}, avec les passifs {{$3}}", + "scenes.app.popup.appsparameters.pages.company_label": "PropriΓ©taire de l'entreprise", + "scenes.app.popup.appsparameters.pages.configuration_label": "Configuration", + "scenes.app.popup.appsparameters.pages.create_app_button": "CrΓ©er une application", + "scenes.app.popup.appsparameters.pages.create_my_app": "CrΓ©er mon application", + "scenes.app.popup.appsparameters.pages.current_informations_apps_connectors": "Vous n'avez pas créé d'application pour le moment. Avant de crΓ©er une application ou un connecteur, vΓ©rifiez que celle-ci n'existe pas dΓ©jΓ  dans notre marchΓ© d'applications.", + "scenes.app.popup.appsparameters.pages.danger_zone_description": "Supprimer l'application", + "scenes.app.popup.appsparameters.pages.danger_zone_label": "Zone dangereuse", + "scenes.app.popup.appsparameters.pages.description_label": "Description", + "scenes.app.popup.appsparameters.pages.developped_apps_subtitle": "Applications dΓ©veloppΓ©es par l'entreprise", + "scenes.app.popup.appsparameters.pages.dispalyed_parameters_description": "Permet de dΓ©finir l'endroit oΓΉ votre application sera visible.", + "scenes.app.popup.appsparameters.pages.displayed_parameters_label": "ParamΓ¨tres d'affichage", + "scenes.app.popup.appsparameters.pages.error_check_needed": "Une erreur est survenue, vΓ©rifiez vos informations.", + "scenes.app.popup.appsparameters.pages.error_message": "Ce nom est dΓ©jΓ  utilisΓ© par une autre application, veuillez en choisir un autre.", + "scenes.app.popup.appsparameters.pages.error_user_code": "erreur", + "scenes.app.popup.appsparameters.pages.event_subtitle": "Γ‰vΓ©nements", + "scenes.app.popup.appsparameters.pages.filter_information": "Ce filtre permet de limiter l'utilisation de votre clΓ© API aux serveurs de votre connecteur uniquement.", + "scenes.app.popup.appsparameters.pages.go_back": "Retour", + "scenes.app.popup.appsparameters.pages.grp_section_name-error": "Ce nom est dΓ©jΓ  utilisΓ© par une autre application, veuillez en choisir un autre.", + "scenes.app.popup.appsparameters.pages.grp_section_surname_label": "Nom simplifiΓ©", + "scenes.app.popup.appsparameters.pages.installation": "Instal.", + "scenes.app.popup.appsparameters.pages.instruction_message_twakecode": "Commencez par Γ©crire votre message sous le format JSON.", + "scenes.app.popup.appsparameters.pages.interne_availability_application": "Application interne", + "scenes.app.popup.appsparameters.pages.json_configuration_information": "Rendez-vous sur la documentation afin de gΓ©nΓ©rer votre configuration au format JSON.", + "scenes.app.popup.appsparameters.pages.loading": "Chargement...", + "scenes.app.popup.appsparameters.pages.message_data_next_event": "DonnΓ©es passives qui seront envoyΓ©es dans le prochain Γ‰vΓ©nement", + "scenes.app.popup.appsparameters.pages.modify_public_data": "Modifier les donnΓ©es publiques de votre application.", + "scenes.app.popup.appsparameters.pages.new_app_title": "Nouvelle application", + "scenes.app.popup.appsparameters.pages.ok_user_code": "ok", + "scenes.app.popup.appsparameters.pages.optimal_format": "Format optimal : 48x48px.", + "scenes.app.popup.appsparameters.pages.parameters_form_small_text": "L'application non publiΓ©e ne fonctionnera que dans votre entreprise, si vous souhaitez la rendre disponible Γ  tous les utilisateurs de Twake, activez cette option.", + "scenes.app.popup.appsparameters.pages.public_availability_application": "Application publique", + "scenes.app.popup.appsparameters.pages.public_login_label": "Identifiant public", + "scenes.app.popup.appsparameters.pages.publication_description": "DΓ©terminez la visibilitΓ© de votre application.", + "scenes.app.popup.appsparameters.pages.publication_label": "Publication", + "scenes.app.popup.appsparameters.pages.publish_app_label": "Publier l'application", + "scenes.app.popup.appsparameters.pages.read_privileges_label": "PrivilΓ¨ges en lecture", + "scenes.app.popup.appsparameters.pages.remove_app": "Supprimer l'application {{$1}} dΓ©finitivement.", + "scenes.app.popup.appsparameters.pages.remove_app_from_company": "Supprimer de toute l'entreprise", + "scenes.app.popup.appsparameters.pages.remove_app_from_workspace": "Supprimer de l'espace", + "scenes.app.popup.appsparameters.pages.show_button": "Afficher", + "scenes.app.popup.appsparameters.pages.status_tilte": "Statut", + "scenes.app.popup.appsparameters.pages.string_information": "Cette chaine de caractΓ¨res permet d'identifier votre application et sera utilisΓ©e dans les commandes de message.", + "scenes.app.popup.appsparameters.pages.title_tester": "Testeur Twacode", + "scenes.app.popup.appsparameters.pages.url_reception_events_label": "Url de reception des Γ©vΓ¨nements", + "scenes.app.popup.appsparameters.pages.waiting_availability_application": "En attente...", + "scenes.app.popup.appsparameters.pages.website_label": "Site web", + "scenes.app.popup.appsparameters.pages.write_privileges_label": "PrivilΓ¨ges en Γ©criture", + "scenes.app.popup.appsparameters.pages.danger_zone_small_text": "Vous ne pouvez pas supprimer cette application si elle est publiΓ©e.", + "scenes.app.popup.appsparameters.pages.error_app_simple_name_message": "Le nom simplifiΓ© de votre application est dΓ©jΓ  utilisΓ© par une autre application, veuillez le changer.", + "scenes.app.popup.appsparameters.pages.error_app_update_message": "Une erreur s'est produite lors de la mise Γ  jour de l'application.", + "scenes.app.popup.appsparameters.pages.remove_app_button": "Supprimer l'application", + "scenes.app.popup.appsparameters.pages.update_button": "Mettre Γ  jour", + "scenes.app.popup.createworkspacepage.add_subtitle": "Besoin de plus de place ?", + "scenes.app.popup.createworkspacepage.create_new_workspace": "CrΓ©er un nouvel espace de travail", + "scenes.app.popup.createworkspacepage.placeholder_name": "Nom de l'espace de travail", + "scenes.app.popup.userparameter.pages.email_notif_delay_never": "Jamais", + "scenes.app.popup.userparameter.pages.email_notif_delay_quarter_hour": "15 minutes", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_day": "1 jour", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_hour": "1 heure", + "scenes.app.popup.userparameter.pages.frequency_notif_configuration_description": "Configurez les notifications push mobiles.", + "scenes.app.popup.userparameter.pages.frequency_notif_subtitle": "FrΓ©quence des notifications", + "scenes.app.popup.userparameter.pages.keywords_notif_description": "Mettre en surbrillance les mots clΓ©s suivants :", + "scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description": "Configurer l'envoi des notifications manquΓ©es par email", + "scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description": "Choisissez une pΓ©riode pendant laquelle vous ne recevez pas de notifications.", + "scenes.app.popup.userparameter.pages.no_night_disturbing_label": "Ne pas dΓ©ranger la nuit", + "scenes.app.popup.userparameter.pages.notif_content_label": "Contenu des notifications", + "scenes.app.popup.userparameter.pages.notification_sound.defaut": "Par dΓ©faut", + "scenes.app.popup.userparameter.pages.notification_sound.none": "DΓ©sactivΓ©", + "scenes.app.mainview.quick_search_placeholder": "Recherche rapide", + "scenes.app.popup.userparameter.personnal_workspaces_title": "Vos espaces de travail", + "scenes.app.popup.userparameter.pages.private_message_content.show": "Afficher le contenu des messages privΓ©s", + "scenes.app.popup.userparameter.pages.private_message_content.hide": "Masquer le contenu des messages privΓ©s", + "scenes.app.popup.workspaceparameter.admin_current_status": "Vous Γͺtes Administrateur.", + "scenes.app.popup.workspaceparameter.admin_manager_current_status": "Vous Γͺtes Administrateur et GΓ©rant de l'entreprise.", + "scenes.app.popup.workspaceparameter.manager_current_status": "Vous Γͺtes GΓ©rant de l'entreprise.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace": "Supprimer l'espace", + "scenes.app.popup.workspaceparameter.pages.error_workspace_member": "Vous devez Γͺtre seul dans l'espace de travail pour le supprimer.\nRetirez vos collaborateurs et recommencer l'opΓ©ration.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace_description": "La suppression d'un espace de travail ne peut pas Γͺtre annulΓ©e. Tous les messages et fichiers seront irrΓ©cupΓ©rables.", + "scenes.app.popup.workspaceparameter.pages.enter": "Entrer ", + "scenes.app.popup.workspaceparameter.pages.access_apps": "AccΓ©dez Γ  vos applications et connecteurs", + "scenes.app.popup.workspaceparameter.pages.moderator_status": "Moderateur de l'espace", + "scenes.app.popup.workspaceparameter.pages.alert_impossible_removing": "Impossible de quitter l'espace de travail car vous Γͺtes le dernier administrateur. Vous pouvez dΓ©finir un nouvel administrateur ou bien supprimer / archiver cet espace de travail.", + "scenes.app.popup.workspaceparameter.pages.all_apps_small_text": "Toutes les applications", + "scenes.app.popup.workspaceparameter.pages.apps_company_small_text": "Applications de votre entreprise", + "scenes.app.popup.workspaceparameter.pages.apps_connectors_title": "IntΓ©grations", + "scenes.app.popup.workspaceparameter.pages.apps_research_title": "Rechercher des applications", + "scenes.app.popup.workspaceparameter.pages.apps_small_text": "Applications de cet espace de travail", + "scenes.app.popup.workspaceparameter.pages.back_to_search_button": "Retour Γ  la recherche", + "scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button": "Inviter des utilisateurs", + "scenes.app.popup.workspaceparameter.pages.collaborateurs": "Utilisateurs", + "scenes.app.popup.workspaceparameter.pages.company_developped_apps_subtitle": "Applications dΓ©veloppΓ©es par l'entreprise", + "scenes.app.popup.workspaceparameter.pages.company_identity_title": "IdentitΓ© de l'entreprise", + "scenes.app.popup.workspaceparameter.pages.company_name_description": "Modifiez le nom de cette entreprise", + "scenes.app.popup.workspaceparameter.pages.company_name_label": "Nom de l'entreprise", + "scenes.app.popup.workspaceparameter.pages.configuration_notif": "configuration", + "scenes.app.popup.workspaceparameter.pages.configure_button": "PrΓ©fΓ©rences ", + "scenes.app.popup.workspaceparameter.pages.description": "Description", + "scenes.app.popup.workspaceparameter.pages.developped_apps_small_text": "Applications dΓ©veloppΓ©es par votre entreprise", + "scenes.app.popup.workspaceparameter.pages.displayed_preferencies_subtitle": "PrΓ©fΓ©rences d'affichage", + "scenes.app.popup.workspaceparameter.pages.install_button": "Installer", + "scenes.app.popup.workspaceparameter.pages.installed_app_information": "Installer l'application dans cet espace de travail.", + "scenes.app.popup.workspaceparameter.pages.installed_apps_information": "Applications installΓ©es dans cet espaces de travail {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_message": "Applications installΓ©es dans d'autres espaces de l'entreprise {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_subtitle": "Applications installΓ©es", + "scenes.app.popup.workspaceparameter.pages.invitation_error": "Une erreur s'est produite lors de l'invitation des utilisateurs suivant : ", + "scenes.app.popup.workspaceparameter.pages.invited_guest_check_message": "VΓ©rifiez que le nom d'utilisateur ou le mail utilisΓ© est valide.", + "scenes.app.popup.workspaceparameter.pages.logo_modify_description": "Modifiez l'image de cet espace de travail", + "scenes.app.popup.workspaceparameter.pages.logo_subtitle": "Logo", + "scenes.app.popup.workspaceparameter.pages.name_description": "Modifiez le nom de cet espace de travail", + "scenes.app.popup.workspaceparameter.pages.name_label": "Nom de l'espace", + "scenes.app.popup.workspaceparameter.pages.no_access": "Aucun accΓ¨s.", + "scenes.app.popup.workspaceparameter.pages.no_app_information": "Vous n'avez aucune application dans cet espace de travail", + "scenes.app.popup.workspaceparameter.pages.quit_workspace_menu": "Quitter cet espace", + "scenes.app.popup.workspaceparameter.pages.read_access_subtitle": "AccΓ¨s en lecture", + "scenes.app.popup.workspaceparameter.pages.remove_from_company_text": "Supprimer de toute l'entreprise", + "scenes.app.popup.workspaceparameter.pages.research_by": "Rechercher des applications par nom et catΓ©gories", + "scenes.app.popup.workspaceparameter.pages.researching_apps_button": "Rechercher des applications...", + "scenes.app.popup.workspaceparameter.pages.show_button": "Afficher", + "scenes.app.popup.workspaceparameter.pages.title": "ParamΓ¨tres de l'espace de travail", + "scenes.app.popup.workspaceparameter.pages.webhooks_access_subtitle": "AccΓ¨s aux webhooks", + "scenes.app.popup.workspaceparameter.pages.weight_max_small_text": "Taille maximale de 5Β Mo.", + "scenes.app.popup.workspaceparameter.pages.withdraw_button": "Retirer de cet espace", + "scenes.app.popup.workspaceparameter.pages.worspace_notif": "espace de travail", + "scenes.app.popup.workspaceparameter.pages.write_access_subtitle": "AccΓ¨s en Γ©criture", + "scenes.app.popup.workspaceparameter.pages.your_apps_label": "Vos applications", + "scenes.app.popup.workspaceparameter.payments_subscriptions_title": "Paiements et abonnements", + "scenes.app.workspacesbar.components.change_company_title": "Changer d'entreprise", + "scenes.app.workspacesbar.components.create_company_menu": "CrΓ©er une entreprise", + "scenes.app.workspacesbar.components.grp_parameters": "ParamΓ¨tres de {{$1}}", + "scenes.apps.calendar.add_calendar_menu": "Ajouter un calendrier", + "scenes.apps.calendar.connectors_menu": "Connecteurs...", + "scenes.apps.calendar.connectors_search_menu": "Chercher des connecteurs...", + "scenes.apps.calendar.create_calendar_title": "CrΓ©er un calendrier", + "scenes.apps.calendar.day_option": "Jour", + "scenes.apps.calendar.edit_calendar_title": "Γ‰diter le calendrier", + "scenes.apps.calendar.export_title": "Exporter", + "scenes.apps.calendar.export_view_menu": "Exporter la vue...", + "scenes.apps.calendar.ics_download_menu": "TΓ©lΓ©charger un fichier ICS", + "scenes.apps.calendar.ics_subscription_menu": "Obtenir un lien d'abonnement ICS", + "scenes.apps.calendar.modals.advanced_options": "Options avancΓ©es", + "scenes.apps.calendar.modals.description_placeholder": "Description", + "scenes.apps.calendar.modals.details_title": "DΓ©tails", + "scenes.apps.calendar.modals.event_adresse_placeholder": "Adresse", + "scenes.apps.calendar.modals.event_description_placeholder": "Description", + "scenes.apps.calendar.modals.event_title_placeholder": "Titre", + "scenes.apps.calendar.modals.modify_event_button": "Modifier l'Γ©vΓ¨nement", + "scenes.apps.calendar.modals.part.participants": "Participants", + "scenes.apps.calendar.modals.participants_event": "Participants", + "scenes.apps.calendar.modals.reminders": "Rappels", + "scenes.apps.calendar.modals.remove_button": "Supprimer", + "scenes.apps.calendar.modals.remove_event_button": "Supprimer l'Γ©vΓ©nement", + "scenes.apps.calendar.modals.remove_event_text": "Supprimer l'Γ©vΓ©nement ?", + "scenes.apps.calendar.modals.title_placeholder": "Titre", + "scenes.apps.calendar.modify_calendar_menu": "Modifier le calendrier", + "scenes.apps.calendar.month_option": "Mois", + "scenes.apps.calendar.my_calendar": "Mon calendrier", + "scenes.apps.calendar.my_calendar_label": "Mon calendrier", + "scenes.apps.calendar.my_calendar_menu": "Mon calendrier", + "scenes.apps.calendar.no_calendar_text": "Vous n'avez dΓ©fini aucun calendrier pour cet espace de travail.", + "scenes.apps.calendar.no_connectors_menu_text": "Vous n'avez aucun connecteur capable de se connecter Γ  un calendrier.", + "scenes.apps.calendar.remove_calendar_confirmation": "Supprimer le calendrier et ses Γ©vΓ©nements dΓ©finitivement ?", + "scenes.apps.calendar.today_menu": "Aujourd'hui", + "scenes.apps.calendar.week_option": "Semaine", + "scenes.apps.calendar.workspace": "Espace de travail", + "scenes.apps.calendar.workspace_label": "Cet espace de travail", + "scenes.apps.calendar.workspace_menu": "Espace de travail", + "scenes.apps.drive.add_button": "Ajouter", + "scenes.apps.drive.message_added_file": "{{$1}} a envoyΓ© {{$2}}.", + "scenes.apps.drive.message_added_mutiple_files": "{{$1}} a envoyΓ© plusieurs fichiers.", + "scenes.apps.drive.message_added_file_no_name": "{{$1}} a envoyΓ© un fichier.", + "scenes.apps.drive.choose_folder_button": "Choisir un dossier", + "scenes.apps.drive.choose_file_button": "Choisir un fichier", + "scenes.apps.drive.create_folder_button": "CrΓ©er", + "scenes.apps.drive.download_button": "TΓ©lΓ©charger", + "scenes.apps.drive.open_link": "Ouvrir le lien dans une nouvelle fenΓͺtre", + "scenes.apps.drive.files_subtitle": "Fichiers", + "scenes.apps.drive.folder_subtitle": "Dossiers", + "scenes.apps.drive.go_out_trash_menu": "Sortir de la corbeille", + "scenes.apps.drive.go_trash_menu": "AccΓ©der Γ  la corbeille", + "scenes.apps.drive.import_from_computer_menu": "TΓ©lΓ©charger depuis l'ordinateur", + "scenes.apps.drive.move_text": "DΓ©placer", + "scenes.apps.drive.new_file_menu": "Nouveau fichier", + "scenes.apps.drive.new_file_title": "Nouveau fichier", + "scenes.apps.drive.new_external_storage": "Ajouter un stockage externe", + "scenes.apps.drive.new_folder_title": "Nouveau dossier", + "scenes.apps.drive.no_file_alert": "Vous n'avez aucune application vous permettant de crΓ©er un fichier.", + "scenes.apps.drive.no_storage_app_alert": "Vous n'avez aucune application vous permettant d'ajouter un stockage externe.", + "scenes.apps.drive.remove_definitely_menu": "Supprimer dΓ©finitivement", + "scenes.apps.drive.restore_menu": "Restaurer", + "scenes.apps.drive.throw_menu": "Mettre Γ  la corbeille", + "scenes.apps.drive.trash_empty_menu": "Vider la corbeille", + "scenes.apps.drive.unconfigured_tab": "Cet onglet n'est pas encore configurΓ©.", + "scenes.apps.drive.viewer.edit_with_button": "Editer avec {{$1}}", + "scenes.apps.drive.viewer.loading_preview_message": "Chargement...", + "scenes.apps.drive.viewer.no_preview_message": "Impossible de visualiser ce type de fichier.", + "scenes.apps.drive.viewer.open_with_button": "Ouvrir avec...", + "scenes.apps.messages.input.placeholder": "Γ‰crivez un message, utilisez @ pour citer un utilisateur.", + "scenes.apps.messages.input.edited": "EditΓ©", + "scenes.apps.messages.just_you": "Visible uniquement par vous", + "scenes.apps.messages.message.new_messages_bar": "Nouveaux messages", + "scenes.apps.messages.message.cancel_button": "Annuler", + "scenes.apps.messages.message.modify_button": "Modifier", + "scenes.apps.messages.message.unpin_button": "DΓ©sΓ©pingler le message", + "scenes.apps.messages.message.pin_button": "Γ‰pingler le message", + "scenes.apps.messages.message.copy_link": "Copier le lien vers le message", + "scenes.apps.messages.message.pinned": "Γ‰pinglΓ©", + "scenes.apps.messages.message.remove_button": "Supprimer", + "scenes.apps.messages.message.reply_button": "RΓ©pondre", + "scenes.apps.messages.message.save_button": "Enregistrer", + "scenes.apps.messages.message.show_button": "Afficher", + "scenes.apps.messages.message.show_responses_button": "Voir les rΓ©ponses prΓ©cΓ©dentes", + "scenes.apps.messages.message.types.first_channel_message_text": "Ceci est le premier message de la chaΓne", + "scenes.apps.messages.message.types.first_message_text": "C'est le premier message", + "scenes.apps.messages.message.types.no_message_in_thread": "Personne n'a rΓ©pondu.", + "scenes.apps.messages.message.user_deactivated": "Vous consultez les archives d'un compte dΓ©sactivΓ©", + "scenes.apps.messages.messageslist.get_writing_user": "est en train d'Γ©crire...", + "scenes.apps.messages.messageslist.get_writing_users": "sont en train d'Γ©crire...", + "scenes.apps.messages.messageslist.go_last_message_button": "Aller au dernier message", + "scenes.apps.messages.messageslist.go_last_message_button.new_messages": "Nouveaux messages", + "scenes.error_on_twake": "β€œHouston nous avons un problΓ¨meβ€œ", + "scenes.help_us": "Cependant, si vous souhaitez nous aider Γ  rΓ©parer cette erreur, envoyez nous le message ci-dessous : ", + "scenes.login.verifymail.alert": "Nous vΓ©rifions votre e-mail !", + "scenes.login.verifymail.error_message": "Une erreur s'est produite", + "scenes.login.verifymail.signin_button": "Se connecter", + "scenes.login.verifymail.success": "Votre e-mail a Γ©tΓ© vΓ©rifiΓ© avec succΓ¨s !", + "scenes.login.verifymail.verification_waiting": "En attente de vΓ©rification...", + "scenes.no_panic": "Ne paniquez pas, recharger simplement cette page pour retrouver Twake.", + "services.apps.calendar.deadline_icon": "Deadline", + "services.apps.calendar.event_icon": "Γ‰vΓ©nement", + "services.apps.calendar.move_icon": "DΓ©placement", + "services.apps.calendar.reminder_icon": "Rappel", + "services.apps.messages.no_app": "Cette application n'existe pas.", + "services.apps.messages.no_command_possible": "Nous ne pouvons pas executer la commande '{{$1}}' car '{{$2}}' n'existe pas ou ne permet pas de crΓ©er des commandes.", + "services.user.notification_parameters_update_alert": "Les paramΓ¨tres de notification ont Γ©tΓ© mis Γ  jour.", + "services.user.update_password_alert": "Votre mot de passe a Γ©tΓ© mis Γ  jour.", + "scenes.app.workspaces.components.skip": "Passer", + "scenes.apps.calendar.unconfigured_tab": "Cet onglet n'est pas encore configurΓ©.", + "scenes.apps.drive.trash": "Corbeille", + "scenes.apps.drive.top_menu_more": "Plus", + "scenes.apps.drive.top_menu_no_items": "{{$1}} Γ©lΓ©ments", + "scenes.apps.messages.new_thread": "Commencer une nouvelle discussion", + "scenes.apps.messages.input.send_message": "Envoyer le message", + "scenes.apps.messages.input.emoji": "Emoji", + "scenes.apps.messages.input.hide_formatting": "Masquer le formatage", + "scenes.apps.messages.input.show_formatting": "Montrer le formatage", + "scenes.tell_us": "Dites-nous ce que vous faisiez Γ  :", + "scenes.apps.drive.viewer.download_desktop": "TΓ©lΓ©chargez Twake pour bureau pour visualiser dans l'application", + "scenes.apps.tasks.my_tasks": "Mes TΓ’ches", + "scenes.apps.tasks.board.place_holder": "Nom du tableau", + "scenes.apps.tasks.board.tasks.subtask": "Sous-tΓ’che", + "scenes.apps.tasks.board.tasks.add_subtask": "Ajouter une sous-tΓ’che", + "scenes.apps.tasks.board.tasks.use_deadline": "Utiliser la date limite", + "scenes.apps.tasks.board.tasks.use_starttime": "Utiliser la date de dΓ©but", + "scenes.apps.tasks.board.tasks.in_list": "Dans la liste", + "scenes.apps.tasks.board.starts": "DΓ©marre le", + "scenes.apps.tasks.board.ends": "Γ€ terminer avant le", + "scenes.apps.tasks.board.list_name": "Nom de la liste", + "scenes.app.popup.sync_calendar": "Synchronisez vos calendriers.", + "scenes.apps.parameters.workspace_sections.workspace.logo_company": "Logo de l'entreprise", + "scenes.app.popup.workspaceparameter.pages.logo_company_modify_description": "Editer le logo de l'entreprise ", + "scenes.app.popup.workspaceparameter.pages.cancel_invitation": "Annuler l'invitation", + "scenes.apps.account.account.fullname": "Nom complet", + "login.email_login": "Email / Login", + "scenes.apps.account.account.password_for_user": "Mot de passe pour l'utilisateur", + "scenes.apps.account.account.send_info": "Envoyez cette information Γ  votre utilisateur pour lui communiquer dΓ¨s maintenant ses nouveaux identifiants.", + "scenes.apps.account.account.save": "Sauvegarder le compte", + "scenes.apps.account.message_temporary": "Un compte temporaire fonctionne comme un compte Twake habituel, mais vous gΓ©nΓ©rez son mot de passe et vous aurez la possibilitΓ© de le rΓ©initialiser si besoin.", + "scenes.apps.account.message_user_signin": "Votre utilisateur peut se connecter Γ  tout moment en utilisant ce mΓͺme courriel et changer son compte temporaire en un compte normal.", + "scenes.app.mainview.link_expired": "Ce lien public est invalide ou a expirΓ©.", + "scenes.app.mainview.create_account": "CrΓ©ez votre espace de travail gratuitement sur ", + "scenes.apps.calendar.modals.reminder_add": "Ajouter un rappel", + "scenes.apps.parameters.workspace_sections.members.invite_all": "Inviter tous", + "scenes.app.taskpicker.select": "SΓ©lectionner", + "components.listmanager.filter": "Filtrer", + "scenes.apps.tasks.no_connector": "Pas de connecteur", + "components.attachmentpicker.add_attachment": "Ajouter des piΓ¨ces-jointes", + "components.input.copied": "CopiΓ©", + "components.drive.new_versions": "Ajouter une nouvelle version", + "components.drive.navigators.directory_not_found": "RΓ©pertoire non trouvΓ©.", + "components.drive.right_preview.suppress_link": "Supprimer le lien", + "components.drive.right_preview.create_link": "CrΓ©er un lien d'accΓ¨s", + "components.drive.moove_here": "DΓ©placer ici", + "components.drive.modify_uslist": "Modifier la liste d'utilisateurs", + "components.tagpicker.tag_name": "Nom du tag", + "components.upload.drop_files": "DΓ©posez vos fichiers ici", + "components.workspace.list_manager.no_workspace": "Pas d'espace de travail", + "components.workspace.list_manager.add": "Ajouter des espaces de travail", + "components.workspace.list_manager.current_space": "Espace de travail courant", + "components.workspace.list_manager.current_company": "Entreprise courante", + "components.workspace.list_manager.all": "Tous", + "components.workspace.calendar.invalid": "Invalide", + "components.searchpopup.enter_text": "Entrez du texte Γ  chercher dans Twake.", + "components.searchpopup.loading": "Chargement de plus de rΓ©sultats", + "components.searchpopup.filter_ws": "Filtrer les espaces de travail", + "components.searchpopup.tags": "Tags", + "components.searchpopup.size": "Taille", + "components.searchpopup.creation": "CrΓ©ation", + "components.searchpopup.update_search": "Mettre Γ  jour la recherche", + "components.searchpopup.last_modif": "DerniΓ¨re modification", + "components.searchpopup.sender": "ExpΓ©diteur", + "components.searchpopup.mentions": "Mentions", + "components.searchpopup.only_pinned": "Seulement les messages Γ©pinglΓ©s", + "components.alert.confirm": "Confirmez votre action", + "components.alert.confirm_click": "Confirmez votre action en cliquant sur OK.", + "components.searchpopup.tasks": "TΓ’ches", + "scenes.app.mainview.advanced_search_placeholder": "Recherche avancΓ©e", + "components.searchpopup.hide_filters": "rΓ©duire", + "components.searchpopup.show_filters": "filtres", + "components.searchpopup.load_more": "Charger plus de rΓ©sultats", + "general.more": "Plus", + "scenes.apps.board.archived_tasks": "TΓ’ches archivΓ©es ({{$1}})", + "scenes.apps.board.active_tasks": "TΓ’ches actives", + "scenes.apps.board.kanban": "Kanban", + "scenes.apps.board.display_as": "Afficher en tant que", + "scenes.apps.board.new_task": "+ Nouvelle tΓ’che", + "scenes.apps.board.all_boards": "Tous les tableaux", + "components.userlistmanager.no_users": "Aucun utilisateur.", + "scenes.apps.drive.used": "utilisΓ© dans ce dossier", + "components.reminder.notification": "Notification", + "components.reminder.minutes_bef": "minutes avant", + "components.reminder.hours_bef": "heures avant", + "components.reminder.days_bef": "jours avant", + "components.reminder.weeks_bef": "semaines avant", + "components.reminder.by_email": "E-Mail", + "scenes.apps.calendar.reminders": "rappel(s)", + "scenes.apps.calendar.video_link": "Cliquez pour ouvrir le lien", + "scenes.app.mainview.discussion": "Discussion", + "components.tagpicker.notag": "Pas de tag", + "scenes.apps.tasks.modals.attachments": "PiΓ¨ces jointes", + "components.calendar.calendarselector.from": "Depuis", + "scenes.apps.drive.move_text2": "DΓ©placer", + "components.attachmentpicker.from_computer": "Depuis l'ordinateur", + "components.attachmentpicker.from_twake": "Depuis les Documents Twake", + "components.attachmentpicker.file": "Fichier", + "components.attachmentpicker.remove_attach": "Enlever la piΓ¨ce-jointe", + "scenes.apps.drive.remove_attachs": "Enlever les piΓ¨ces-jointes", + "components.drive.elements.see": "Voir", + "components.drive.elements.current_name": "Nom actuel : ", + "scenes.apps.drive.right_preview.public": "AccΓ¨s public", + "components.drive.elements.configurate_mod": "Configurer le module...", + "components.drive.elements.manage_version": "GΓ©rer les versions", + "scenes.app.popup.createcompany.try_again": "Veuillez rΓ©essayer.", + "scenes.app.popup.workspace.edit_temp": "Modifier un compte temporaire", + "scenes.app.popup.workspace.create_temp": "CrΓ©er un compte temporaire", + "scenes.apps.tasks.active_tasks": "tΓ’ches actives", + "scenes.apps.drive.right_preview.versions": "Versions", + "scenes.app.popup.appsparameters.pages.apps_connectors_small_text": "GΓ©rer vos applications et connecteurs.", + "scenes.app.popup.appsparameters.pages.icon": "IcΓ΄ne", + "scenes.app.popup.appsparameters.pages.title_informations": "Informations de base", + "scenes.app.popup.appsparameters.pages.subtitle_informations": "Informations liΓ©es Γ  la gestion des applications", + "scenes.app.popup.appsparameters.pages.smalltext_user_id": "Identifiant utilisateur actuel", + "scenes.app.popup.appsparameters.pages.smalltext_workspace_id": "Identifiant espace de travail actuel", + "scenes.app.popup.appsparameters.pages.smalltext_group_id": "Identifiant de groupe actuel", + "scenes.app.mainview.channel_description": "Description de la chaΓne", + "scenes.client.channelbar.channeltemplateeditor.checkbox": "Inviter automatiquement tout les utilisateurs de l'espace de travail sur cette chaΓne", + "scenes.client.channelbar.channelmemberslist.title": "Utilisateurs de {{$1}}", + "scenes.client.channelbar.channelmemberslist.loader": "Charger plus", + "scenes.client.channelbar.channelmemberslist.autocomplete": "Rechercher des utilisateurs", + "scenes.client.channelbar.channelmemberslist.menu.option_2": "Supprimer de la chaΓne", + "components.leftbar.channel.workspaceschannels.menu.option_1": "CrΓ©er une chaΓne", + "components.leftbar.channel.workspaceschannels.menu.option_2": "Rejoindre une chaΓne", + "components.channelworkspacelist.title": "ChaΓnes", + "scenes.client.channelbar.workspacechannellist.autocomplete": "Rechercher une chaΓne de discussion", + "scenes.client.channelbar.readonly_channel.checkbox": "Restreindre l'accΓ¨s en Γ©criture", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_creation": "CrΓ©er un onglet", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_edition": "Renommer {{$1}}", + "components.connectorslistmanager.add_connectors": "Ajouter des connecteurs", + "components.notifications.hidden_notifications_button.children": "Nouveaux messages", + "scenes.client.mainview.tabs.tabstemplateeditor.select_placeholder": "Application", + "scenes.client.channelbar.channelmemberslist.no_members": "Il n'y a aucun utilisateur dans cette chaΓne, vous pouvez les inviter en cliquant sur Ajouter des utilisateurs.", + "scenes.app.channelsbar.hide_discussion_leaving.menu": "Masquer la discussion", + "scenes.app.popup.adduserfromtwakeconsole.current_users_state": "{{$1}} email(s) seront ajoutΓ©s", + "components.newversion.new_version_component.row.part_1": "Vous utilisez une version obsolΓ¨te de Twake", + "components.newversion.new_version_component.row.part_2": "nous vous suggΓ©rons de recharger l'application et de profiter de nos nouvelles fonctionnalitΓ©s !", + "components.newversion.new_version_component.link": "Cliquez ici pour recharger", + "components.newversion.new_version_modal.title": "Nouvelle mise Γ  jour disponible !", + "scenes.apps.drive.download_all_button": "Tout tΓ©lΓ©charger", + "components.inputs.input_with_select.input.placeholder": "Ma chaΓne", + "components.inputs.input_with_select.select.placeholder": "Mon groupe", + "components.inputs.input_with_select.button.tooltip": "DΓ©finir un groupe de chaΓnes", + "scenes.apps.messages.message.activity_message.a_added_b_to_the_channel": "{{$1}} a ajoutΓ© {{$2}} Γ  la chaΓne", + "scenes.apps.messages.message.activity_message.a_updated_channel_description": "{{$1}} a changer la description", + "scenes.apps.messages.message.activity_message.a_updated_channel_name": "{{$1}} a renommΓ© la chaΓne en {{$2}}", + "scenes.apps.messages.message.activity_message.a_created_channel_tab": "{{$1}} a ajoutΓ© un nouveau onglet {{$2}} {{$3}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_tab": "{{$1}} a supprimΓ© l'onglet {{$2}} {{$3}}", + "scenes.apps.messages.message.activity_message.a_created_channel_connector": "{{$1}} a ajoutΓ© un nouveau connecteur {{$2}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_connector": "{{$1}} a supprimΓ© le connecteur {{$2}}", + "scenes.client.channelbar.channelmemberslist.tag": "C'est vous", + "components.alert.leave_private_channel.title": "Voulez-vous vraiment quitter la chaΓne ?", + "components.alert.leave_private_channel.description": "Vous ne pourrez plus rejoindre cette chaΓne privΓ©e Γ  moins que quelqu'un ne vous invite.", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.tag": "Vous n'Γͺtes pas membre", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.loader": "Charger plus", + "general.re_send": "Renvoyer", + "general.verify": "VΓ©rifier", + "components.unverified_account.typography_text_danger": "Il vous reste {{$1}} jour(s) de votre pΓ©riode d'essai. Le compte d'essai sera bloquΓ© aprΓ¨s 7 jours et supprimΓ© dΓ©finitivement aprΓ¨s 1 mois d'inscription. Vous pouvez vΓ©rifier votre compte en cliquant sur le bouton « VΓ©rifier mon compteΒ Β» dans le courriel de vΓ©rification que nous vous avons envoyΓ©.", + "components.unverified_account.verification_details": "Nous avons envoyΓ© les dΓ©tails de vΓ©rification Γ ", + "components.account_verification_status_sentence": "L'Γ©tat de votre compte est : {{$1}}", + "components.account_verication_status_unverified": "Non vΓ©rifiΓ©", + "components.account_verication_status_blocked": "VerrouillΓ©", + "components.unverified_account.re_send_email": "Vous n'avez pas reΓ§u l'e-mail ?", + "components.blocked_account.trial_period_over": "Votre pΓ©riode d'essai est terminΓ©e. Pour dΓ©verrouiller votre compte et accΓ©der Γ  toutes les fonctionnalitΓ©s, veuillez vΓ©rifier votre compte par e-mail de confirmation", + "components.add_mails_workspace.button": "Commencez Γ  utiliser Twake", + "components.add_mails_workspace.title_1": "Ajouter des utilisateurs", + "components.add_mails_workspace.title_2": "Twake est un outil de collaboration d'Γ©quipe, alors invitez des utilisateurs Γ  tester un espace de travail que nous avons créé pour vous.", + "components.add_mails_workspace.text_area_placeholder": "Saisissez les e-mails des utilisateurs*", + "components.verify_mail.title_1": "FΓ©licitations", + "components.verify_mail.title_2": "Vous Γͺtes un utilisateur officiel de Twake !", + "components.verify_mail.button": "Ajouter des utilisateurs", + "components.verify_mail.text": "Tout d'abord, vous devez vΓ©rifier votre adresse e-mail. Nous avons envoyΓ© un lien de vΓ©rification Γ ", + "components.verify_mail.paragraph": "Vous pouvez le faire plus tard si vous le souhaitez, mais les comptes non vΓ©rifiΓ©s n'ont accΓ¨s qu'Γ  une version limitΓ©e de Twake", + "services.console_services.toaster.add_emails_error": "Une erreur s'est produite pendant l'ajout de(s) email(s)", + "services.console_services.toaster.add_email_error_message": "Une erreur s'est produite lors de l'ajout de {{$1}}", + "services.console_services.toaster.success_verify_email": "Un lien de vΓ©rification a Γ©tΓ© envoyΓ© Γ  votre compte de messagerie", + "scenes.app.popup.workspaceparameter.edit_from_console": "Voir dans Console", + "services.console_services.toaster.success_invite_emails": "{{$1}} utilisateur(s) ajoutΓ©(s) avec succΓ¨s", + "scenes.client.channels_bar.modals.guest_management.title": "GΓ©rez les invitΓ©s dans {{$1}}", + "scenes.client.channels_bar.modals.guest_management.input_placeholder": "Rechercher des invitΓ©s ou e-mails en attente", + "scenes.client.channels_bar.modals.guest_management.tips": "Commencez Γ  ajouter ou Γ  rechercher des e-mails", + "scenes.client.channels_bar.modals.parts.channel_member_row.label.pending_email": "Mail envoyΓ©", + "general.user.role.company.admin": "Administrateur de l'entreprise", + "general.user.role.company.member": "Utilisateur", + "general.user.role.company.guest": "InvitΓ©", + "general.user.deleted": "Compte supprimΓ©", + "general.user.deactivated": "Cet utilisateur n'est plus dans cette l'entreprise", + "general.user.connected": "ConnectΓ©", + "components.richtexteditor.toolbar.bold": "Gras", + "components.richtexteditor.toolbar.underline": "SoulignΓ©", + "components.richtexteditor.toolbar.italic": "Italique", + "components.richtexteditor.toolbar.strikethrough": "BarrΓ©", + "components.richtexteditor.toolbar.code": "Code", + "components.richtexteditor.toolbar.unordered-list": "Liste", + "components.richtexteditor.toolbar.ordered-list": "List ordonnΓ©e", + "components.richtexteditor.toolbar.blockquote": "Citation", + "components.richtexteditor.toolbar.code-block": "Bloc de code", + "components.locked_features.locked_history_banner.title": "Vous venez d'atteindre la limite de messages", + "components.locked_features.locked_history_banner.description": "Votre entreprise a beaucoup de messages ! Mettez Γ  niveau maintenant pour accΓ©der Γ  tout l'historique de vos messages.", + "components.locked_features.locked_history_banner.button": "Voir plus", + "components.locked_features.locked_guests_popup.title": "La fonctionnalitΓ© est verrouillΓ©e", + "components.locked_features.locked_guests_popup.subtitle": "Cette fonctionnalitΓ© n'est pas disponible dans la version gratuite", + "components.locked_features.locked_guests_popup.description": "Oupsβ€―!! Il semble que vous souhaitiez inviter des utilisateurs externes dans votre espace de travail. Vous pouvez envisager de mettre Γ  niveau votre plan si vous souhaitez collaborer avec des invitΓ©s et des partenaires externes. Explorez nos options de tarification et sΓ©lectionnez la meilleure option pour les besoins de collaboration de votre Γ©quipe.", + "components.locked_features.locked_guests_popup.learn_more_button": "Voir plus", + "components.locked_features.locked_guests_popup.skip_for_now_button": "Ignorer", + "components.locked_features.locked_guests_popup.or": "Ou", + "components.on_boarding.company_billing_banner.admin_or_owner_text": "Il y a un problΓ¨me avec l'abonnement de votre entreprise. Veuillez consulter votre", + "components.on_boarding.company_billing_banner.guest_or_member_text": "Il y a un problΓ¨me avec l'abonnement de votre entreprise. Veuillez contacter le propriΓ©taire ou l'administrateur de l'entreprise !", + "components.on_boarding.company_billing_banner.link": "plan d'abonnement d'entreprise", + "components.on_boarding.popups.blocked_company.title": "Votre entreprise est bloquΓ©e Γ  cause d'un problΓ¨me de paiement", + "components.on_boarding.popups.blocked_company.description": "Votre abonnement Γ  Twake a expirΓ©. Veuillez contacter le propriΓ©taire ou l'administrateur de votre entreprise pour le renouveler et pouvoir Γ  nouveau communiquer avec votre Γ©quipe !", + "components.on_boarding.popups.blocked_company.learn_more_text": "Envie d'en savoir plus sur l'abonnement entreprise ?", + "components.on_boarding.popups.blocked_company.company_subscription_plan_button": "Cliquez ici", + "components.on_boarding.popups.blocked_company.or": "Ou", + "components.on_boarding.popups.blocked_company.company_selector": "Changer d'entreprise", + "scenes.apps.tasks.select_user_button": "Afficher les tΓ’ches d'un autre utilisateur", + "scenes.apps.tasks.select_user": "Rechercher un utilisateur", + "scenes.apps.messages.input.attach_file.from_computer": "Depuis mon ordinateur", + "scenes.app.popup.workspaceparameter.pages.table_title": "Nom", + "scenes.client.main_view.main_header.search_input": "Rechercher", + "scenes.apps.drive.new_link_title": "Nouveau lien", + "scenes.apps.drive.default_link_name": "Sans titre", + "components.emoji_picker.input_search_placeholder": "Rechercher", + "scenes.apps.messages.message.activity_message.a_removed_b_from_the_channel": "{{$1}} a retirΓ© {{$2}} de la chaine", + "components.inputs.input_with_select.select.no_sections": "Vous pouvez grouper vos chaines ici", + "services.apps.messages.message_editor_service.upload_error_toaster": "{{$1}} - Vous ne pouvez pas ajouter plus de {{$2}} fichiers dans un message", + "scenes.apps.messages.message.parts.deleted_content.text.current_user": "Vous avez supprimΓ© ce message", + "scenes.apps.messages.message.parts.deleted_content.text": "{{$1}} a supprimΓ© son message", + "components.member.user_parts.and_more_user_text": " et {{$1}} autres utilisateurs", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_link": "CrΓ©er une chaΓne privΓ©e", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_text": " Γ  la place", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_input_placeholder": "Vous ne pouvez pas ajouter plus de 10 utilisateurs", + "general.uploading": "Envoi", + "components.upload.drop_files.toaster.error": "Vous ne pouvez pas envoyer plus de {{$1}} fichiers", + "components.emoji_picker.categories.frequently_used": "FrΓ©quemment utilisΓ©(s)", + "components.emoji_picker.categories.smileys_and_people": "Smileys et personnes", + "components.emoji_picker.categories.animals_and_nature": "Animaux et Nature", + "components.emoji_picker.categories.food_and_drink": "Nourriture et boisson", + "components.emoji_picker.categories.activity": "ActivitΓ©", + "components.emoji_picker.categories.travel_and_places": "Voyages et lieux", + "components.emoji_picker.categories.objects": "Objets", + "components.emoji_picker.categories.symbols": "Symboles", + "components.emoji_picker.categories.flags": "Drapeaux", + "components.emoji_picker.categories.search_result": "RΓ©sultats de la recherche", + "components.emoji_picker.categories.not_found": "Aucun Emoji trouvΓ©", + "scenes.app.popup.workspaceparameter.pages.workspace_partner_tabs.members.table.tags": "RΓ΄le", + "general.email": "Email", + "components.locked_features.locked_workspace_popup.title": "Vous ne pouvez pas crΓ©er plus d'espaces", + "components.locked_features.locked_workspace_popup.subtitle": "Dans la version gratuite, vous ne pouvez avoir qu'un seul espace de travail dans votre entreprise.", + "components.locked_features.locked_workspace_popup.text": "Oups !! Vous souhaitez crΓ©er un nouvel espace de travail dans votre entreprise. Vous pouvez envisager de mettre Γ  niveau votre plan si vous souhaitez collaborer dans plusieurs espaces de travail. Explorez nos options de tarification et sΓ©lectionnez la meilleure option pour les besoins de collaboration de votre Γ©quipe.", + "components.locked_features.locked_only_office_popup.title": "Vous ne pouvez pas Γ©diter ce fichier", + "components.locked_features.locked_only_office_popup.subtitle": "Dans la version gratuite, vous ne pouvez pas utiliser Onlyoffice.", + "components.locked_features.locked_only_office_popup.text": "Oups !! Vous souhaitez modifier le fichier Γ  partir de Twake. Vous voudrez peut-Γͺtre envisager de mettre Γ  niveau votre plan si vous souhaitez collaborer autour de fichiers bureautiques. Explorez nos options de tarification et sΓ©lectionnez la meilleure option pour les besoins de collaboration de votre Γ©quipe.", + "components.locked_features.locked_drive_popup.title": "Vous venez d'atteindre la limite d'importation", + "components.locked_features.locked_drive_popup.subtitle": "Dans la version gratuite, vous ne pouvez stocker que 6 Go.", + "general.resume": "Reprendre", + "general.pause": "Pause", + "scenes.app.integrations_parameters.title": "IntΓ©grations", + "scenes.app.integrations_parameters.applications_table.name": "Nom", + "scenes.app.integrations_parameters.applications_table.title": "Autres intΓ©grations", + "scenes.app.integrations_parameters.applications_table.search_placeholder": "Rechercher une application", + "scenes.app.integrations_parameters.company_application_popup.tag": "InstallΓ©", + "scenes.app.integrations_parameters.company_application_popup.btn": "Installer", + "scenes.app.integrations_parameters.company_application_popup.tab_btn_info": "Informations", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.description_item": "Description", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.website_item": "Site web", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.created_item": "Date de crΓ©ation", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.version_item": "Version", + "scenes.app.integrations_parameters.company_applications_table.more_menu.show_application": "Afficher dΓ©tails", + "scenes.app.integrations_parameters.company_applications_table.more_menu.remove_application": "Retirer de l'entreprise", + "scenes.app.integrations_parameters.company_applications_table.name": "Nom", + "scenes.app.integrations_parameters.company_applications_table.title": "InstallΓ© dans votre entreprise", + "app.state.recoil.hooks.use_current_company_applications.toaster_delete": "{{$1}} supprimΓ© avec succΓ¨s de votre entreprise", + "app.state.recoil.hooks.use_current_company_applications.toaster_add": "{{$1}} ajoutΓ© avec succΓ¨s dans votre entreprise", + "scenes.apps.messages.input.replied_to": "a rΓ©pondu Γ  ", + "scenes.app.popup.adduser.magiclinks.copied_to_clipboard": "CopiΓ© avec succΓ¨s dans le presse-papiers", + "scenes.app.popup.adduser.magiclinks.genrator_info": "Lien d'invitation Γ  l'espace de travail", + "scenes.app.popup.adduser.magiclinks.new_link_generated": "Nouveau lien gΓ©nΓ©rΓ©", + "scenes.app.popup.adduser.magiclinks.action_generate": "GΓ©nΓ©rer", + "scenes.app.popup.adduser.magiclinks.action_copy": "Copier", + "scenes.app.channelsbar.currentuser.company_messages_counter_header": "Nombre de messages", + "scenes.app.channelsbar.currentuser.company_messages_counter_info": "Dans la version gratuite de Twake, vous pouvez seulement accΓ©der aux {{$1}} messages les plus rΓ©cents.", + "scenes.app.channelsbar.currentuser.company_messages_counter_link": "Afficher d'autres offres", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.label": "Espace par dΓ©faut", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.description": "Invite automatiquement tous les utilisateurs de l'entreprise dans cet espace de travail", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.title": "Vous Γͺtes sur le point de supprimer {{$1}}", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.alert_total_members": "Vous avez encore {{$1}} membres dans {{$2}}. Vous devez supprimer tous les membres pour pouvoir supprimer cet espace de travail.", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.checkbox": "Je comprends que tous les messages et fichiers de mon espace de travail seront supprimΓ©s.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.max_size": "La taille maximale du logo est de 5 Mo", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.bad_format": "Mauvais format, seuls les png, gif et jpg sont autorisΓ©s", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.unknown": "Erreur inconnue", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.prefix": "Erreur", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.success.update": "Mise Γ  jour rΓ©ussie", + "scenes.app.channelsbar.currentuser.reset": "RΓ©initialiser", + "components.rich_text_editor.plugins.suggestions.default_message.display_results": "Γ‰crivez au moins trois lettres pour afficher des utilisateurs", + "components.rich_text_editor.plugins.suggestions.loading": "Recherche en cours", + "components.rich_text_editor.plugins.suggestions.default_message.no_user_found": "Aucun utilisateur trouvΓ©", + "components.rich_text_editor.plugins.suggestions.default_message.no_emoji_found": "Aucun emoji trouvΓ©", + "components.rich_text_editor.plugins.suggestions.default_message.no_command_found": "Aucune commande trouvΓ©", + "scenes.join.loading": "Chargement…", + "scenes.join.wrong_link_title": "Ce lien n'est plus disponible", + "scenes.join.twake_description": "Twake est un espace de travail numΓ©rique Γ  code ouvert conΓ§u pour amΓ©liorer la productivitΓ© de votre Γ©quipe", + "scenes.join.login_first_button": "Connectez-vous ou crΓ©ez d'abord un compte", + "scenes.join.wrong_link_description": "Demandez Γ  la personne qui vous a invitΓ©(e) de rejoindre cette entreprise par un nouveau lien ou crΓ©ez votre propre entreprise", + "scenes.join.join_the_team_button": "Rejoindre l'Γ©quipe", + "scenes.join.create_the_company_button": "CrΓ©er l'entreprise", + "scenes.join.join_workspace_from_company": "Rejoignez {{$1}} Γ  partir de {{$2}}β€―!", + "\"": "\"", + "'": "'", + "login.create_account": "CrΓ©er un compte", + "login.login_error": "Erreur lors de la connexion", + "scenes.app.messages.input.parts.is_writing.message.user_is_writing": "{{$1}} est en train d'Γ©crire...", + "scenes.app.messages.input.parts.is_writing.message.users_are_writing": "{{$1}} et {{$2}} sont en train d'Γ©crire...", + "scenes.app.messages.input.parts.is_writing.message.users_and_more_are_writing": "{{$1}}, {{$2}} et {{$3}} autres utilisateurs sont en train d'Γ©crire...", + "components.locked_features_components.locked_invite_alert.message_part_1": "Votre entreprise a atteint sa limite maximale de {{$1}} membres. Veuillez ", + "components.locked_features_components.locked_invite_alert.message_link": "mettre Γ  niveau votre entreprise", + "components.locked_features_components.locked_invite_alert.message_part_2": " pour inviter davantage de membres.", + "components.locked_features_components.locked_invite_alert.message_magic_link": " contacter le propriΓ©taire ou l'administrateur de votre entreprise.", + "views.client.popup.workspace_parameter.pages.workspace_members.link_to_console": "Voir tous les membres de mon entreprise sur la console", + "scenes.app.popup.appsparameters.pages.amazing_app_description": "DΓ©crivez votre application en quelques mots", + "scenes.app.popup.appsparameters.pages.application_creator.title": "Nouvelle intΓ©gration", + "scenes.app.popup.appsparameters.pages.application_creator.checkbox": "Je comprends que le propriΓ©taire et les administrateurs de cette entreprise pourront modifier et publier cette application.", + "twake.application.access.title": "SΓ©lectionnez les portΓ©es adaptΓ©es Γ  votre application.", + "twake.application.access.no_default_scopes_available'": "Cette intΓ©gration n'a pas d'accΓ¨s {{$1}}.", + "scenes.app.popup.appsparameters.pages.application_editor.help_link": "la documentation de l'API Twake.", + "scenes.app.popup.appsparameters.pages.application_editor.help_text": "Si vous ne savez pas comment les remplir, consultez ", + "scenes.app.popup.appsparameters.pages.app.private_key": "ClΓ© privΓ©e", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed": "L'application {{$1}} a Γ©tΓ© supprimΓ©e avec succΓ¨s !", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed_error": "Erreur lors de la suppression de l'application {{$1}} !", + "scenes.app.popup.appsparameters.pages.application_editor.application_published": "Application {{$1}} rΓ©ussie !", + "scenes.app.integrations_parameters.company_applications_table.more_menu.developer_settings": "ParamΓ¨tres du dΓ©veloppeur", + "scenes.app.integrations_parameters.add_application": "Nouvelle intΓ©gration", + "components.open_desktop_popup.subtitle": "Ouvert dans l'application Twake", + "components.open_desktop_popup.open_here_link": "Ouvrir dans la version web", + "molecules.download_banner.title": "Tirez le meilleur parti de Twake, tΓ©lΓ©chargez l'application de bureau maintenant", + "molecules.download_banner.download_button": "TΓ©lΓ©charger l'application de bureau", + "components.searchpopup.no_results_for": "Il n'y a pas eu de rΓ©sultats pour", + "components.searchpopup.try_new_search": "Essayez une nouvelle recherche", + "components.searchpopup.all": "Tout", + "components.searchpopup.chats": "Chats", + "components.searchpopup.media": "MΓ©dias", + "components.searchpopup.files": "Des dossiers", + "components.searchpopup.recent_chats": "Chats rΓ©cents", + "components.searchpopup.recent_media": "MΓ©dias rΓ©cents", + "components.searchpopup.recent_files": "Fichiers rΓ©cents", + "components.searchpopup.recent_channels_and_contacts": "Canaux et contacts rΓ©cents", + "components.searchpopup.header_title": "Chercher", + "components.searchpopup.scope.company": "dans toute compagnie", + "components.searchpopup.scope.channel": "dans ce canal", + "components.searchpopup.channels": "Canaux", + "components.searchpopup.messages": "messages", + "components.searchpopup.start_search": "Entrez quelques mots clΓ©s pour lancer la recherche.", + "components.searchpopup.see_more": "Voir plus", + "scenes.client.channelbar.channelmemberslist.search_invite": "Rechercher et inviter des utilisateurs sur cette chaΓne", + "scenes.client.channelbar.channelmemberslist.search_invite_notice": "Il n'y a pas beaucoup de membres sur cette chaΓne. Recherchez et invitez des utilisateurs maintenant par e-mail ou par nom.", + "scenes.client.channelbar.channelmemberslist.invite_email_button": "Ajouter Γ  la chaΓne uniquement en tant qu'invitΓ©", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace": "Ajouter au canal et Γ  l'espace de travail en tant que membre", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace_confirm": "Inviter {{$1}} dans l'espace de travail en tant que membreΒ ?", + "scenes.client.channelbar.channelmemberslist.search_invite_type_email": "Saisissez une adresse valide pour inviter par e-mail.", + "scenes.client.channelbar.channelmemberslist.pending_section": "Utilisateurs en attente d'invitation", + "scenes.client.channelbar.channelmemberslist.members_section": "Utilisateurs de ce canal", + "scenes.client.channelbar.channelmemberslist.not_members_section": "Utilisateurs absents de ce canal", + "scenes.client.join_private_channel.info": "Le contenu de cette chaΓne est restreint ou n'existe pas. Veuillez contacter un membre de cette chaΓne pour Γͺtre invitΓ©.", + "scenes.client.join_public_channel": "Rejoignez cette chaΓne", + "scenes.client.join_public_channel.info": "Vous n'Γͺtes pas membre de cette chaΓne directe. Cliquez sur ce bouton pour dΓ©marrer la discussion maintenant.", + "components.open_desktop_popup.open_here_link_forever": "N'essayez plus jamais d'ouvrir l'application", + "components.channel_attachement_list.medias": "Des mΓ©dias", + "components.channel_attachement_list.files": "Des dossiers", + "components.channel_attachement_list.title": "Fichiers et mΓ©dias de la chaΓne", + "components.channel_attachement_list.nothing_found": "Rien ici encore", + "molecules.message_quote.deleted": "Ce message a Γ©tΓ© supprimΓ©", + "components.channel_attachement_list.open": "Ouvrir la galerie", + "scenes.apps.messages.jump": "Aller au message", + "scenes.apps.account.on_console": "Pour modifier les prΓ©fΓ©rences globales de votre compte, cliquez sur Aller Γ  la console.", + "scenes.apps.account.assistant.description": "L'assistant Twake est capable de donner un sens Γ  votre travail quotidien sur Twake et de fournir des raccourcis et des actions intelligents au cours de votre journΓ©e. L'assistant fait partie de l'initiative Work@Home https://workathome.linagora.com/ et est actuellement testΓ© uniquement dans l'entreprise Linagora et est en phase d'apprentissage. Cela signifie que nous enverrons des donnΓ©es d'utilisation de Twake afin de former notre future fonction d'assistant.", + "scenes.apps.account.assistant.share.nothing": "Ne rien partager avec l'assistant (dΓ©sactiver l'assistant)", + "scenes.apps.account.assistant.share.all": "Partagez tout, y compris les messages et le contenu des fichiers", + "scenes.apps.account.assistant.share.metadata": "Partager les mΓ©tadonnΓ©es mais pas le contenu", + "scenes.apps.account.assistant.success": "Vos prΓ©fΓ©rences ont Γ©tΓ© mises Γ  jour avec succΓ¨s.", + "scenes.apps.account.assistant.title": "Assistant", + "components.message_seen_by.title": "Utilisateurs ayant vu le message", + "components.message_seen_by.none_seen_it": "Personne n'a encore vu le message", + "components.message_seen_by.btn": "Informations", + "molecules.quoted_content.attachements": "{{$1}} piΓ¨ces jointes", + "scenes.apps.messages.message.forward": "Vers l'avant", + "scenes.apps.messages.message.forward.title": "TransfΓ©rer le message", + "scenes.apps.messages.message.forward.comment": "Ajouter un message", + "scenes.apps.messages.message.forward.confirm": "Envoyer Γ  $1 canaux", + "scenes.apps.messages.message.forward.send": "Message transfΓ©rΓ©", + "components.channelselector.title": "SΓ©lectionnez les chaΓnes", + "components.channelselector.confirm": "SΓ©lectionnez $1 chaΓne(s)", + "components.channelselector.search": "Rechercher des canaux et des discussions", + "scenes.app.channelsbar.channel_access": "AccΓ¨s au canal", + "scenes.app.channelsbar.channel_access.save": "Enregistrer les paramΓ¨tres d'accΓ¨s", + "scenes.app.channelsbar.channel_access.readonly": "Canal en lecture seule", + "scenes.app.channelsbar.channel_access.readonly.info": "Limitez l'Γ©criture aux modΓ©rateurs, administrateurs et propriΓ©taires.", + "scenes.app.channelsbar.channel_access.visibility": "VisibilitΓ© publique", + "scenes.app.channelsbar.channel_access.visibility.info": "Tout le monde, Γ  l'exception des invitΓ©s de l'entreprise, peut participer.", + "scenes.app.channelsbar.channel_access.default": "Joindre automatiquement", + "scenes.app.channelsbar.channel_access.default.info": "Les nouveaux membres seront ajoutΓ©s ici automatiquement.", + "scenes.app.channelsbar.channel_information": "Modifier les informations de la chaΓne", + "scenes.app.channelsbar.channel_information.logo.add": "Charger une photo", + "scenes.app.channelsbar.channel_information.logo.remove": "Supprimer l'image", + "scenes.app.channelsbar.channel_information.name": "Nom du canal", + "scenes.app.channelsbar.channel_information.description": "Description de la chaΓne", + "scenes.app.channelsbar.channel_information.description.placeholder": "Description de la chaΓne, vous pouvez utiliser Markdown.", + "scenes.app.channelsbar.channel_information.group": "Groupe de canaux", + "scenes.app.channelsbar.channel_information.group.none": "Non sΓ©lΓ©ctionnΓ©", + "scenes.app.channelsbar.channel_information.group.new": "CrΓ©er un nouveau groupe", + "scenes.app.channelsbar.channel_information.group.save": "DΓ©finir le groupe de canaux sur $1", + "scenes.app.channelsbar.channel_information.group.save_none": "Ne pas dΓ©finir de groupe de canaux", + "scenes.app.channelsbar.channel_information.save": "Enregistrer les informations", + "components.invitation.invitation_target.channels_button": "ChaΓnes Γ  inviter", + "scenes.client.channelbar.channelmemberslist.invite_to_workspace": "Invitez {{$1}} dans l'espace de travail ➑", + "components.invitation.reached_limit.text": "vous avez atteint le nombre maximum d'utilisateurs au sein de votre entreprise. Augmentez votre abonnement ou ajoutez ces utilisateurs en tant qu'invitΓ©s", + "components.invitation.allow_anyone_by_email.text": "Autoriser toute personne disposant d'une adresse e-mail @{{$1}} Γ  rejoindre cet espace de travail", + "components.invitation.invitation_channels.button": "Inviter sur des chaΓnes", + "components.invitation.invitation_input_list.add": "Ajouter", + "components.invitation.invitation_input_list.member": "Membre", + "components.invitation.invitation_input_list.guest": "InvitΓ©", + "components.invitation.invitation_input_list.placeholder": "Commencez Γ  taper un e-mail", + "components.invitation.invitation_sent.title": "Les invitations ont Γ©tΓ© envoyΓ©es avec succΓ¨s", + "components.invitation.invitation_sent.subtitle_status": "Vous pouvez suivre l'Γ©tat de l'invitation dansΒ :", + "components.invitation.invitation_sent.subtitle_location": "ParamΓ¨tres de l'espace de travail > Gestion des membres", + "components.invitation.invitation_sent.link": "VΓ©rifier l'Γ©tat de l'invitation", + "components.invitation.invitation_sent.button": "Envoyer plus d'invitations", + "components.invitation.invitation_target.invite_as_guests": "Invitez tous en tant qu'invitΓ©s", + "components.invitation.invitation_target.invite_as_members": "Invitez tous en tant que membres", + "components.invitation.workspace_link.text": "Lien d'invitation Γ  l'espace de travail", + "components.invitation.workspace_link.button": "Copie", + "components.invitation.title": "inviter des personnes Γ  {{$1}}", + "components.invitation.bulk_invitation": "Invitation groupΓ©e", + "components.invitation.button": "Envoyer des invitations", + "scenes.client.readonly.info": "Cette chaΓne est un flux en lecture seule, mais vous pouvez commenter dans les fils de discussion.", + "scenes.app.channelsbar.channel_information.group.title": "Groupes de canaux", + "components.invitation.custom_role_invitation": "Invitation classique", + "components.invitation.link": "Lien" +} diff --git a/twake/frontend/public/locales/it.json b/twake/frontend/public/locales/it.json new file mode 100644 index 00000000..4a1e5b37 --- /dev/null +++ b/twake/frontend/public/locales/it.json @@ -0,0 +1,1008 @@ +{ + "general.save": "Salva", + "scenes.login.create_account.email_used": "Questa posta elettronica Γ¨ giΓ  in uso.", + "scenes.login.create_account.username": "Nome utente", + "scenes.login.create_account.username_already_exist": "Questo nome utente Γ¨ giΓ  in uso", + "scenes.login.create_account.fill_in_username": "Devi inserire il tuo nome utente", + "scenes.login.forgot_password.invalid_code": "Questo codice non Γ¨ valido.", + "scenes.login.forgot_password.text3": "Inserisci una nuova password per il tuo account.", + "scenes.login.forgot_password.password": "Password", + "scenes.login.forgot_password.password2": "Conferma password", + "scenes.login.forgot_password.password_dont_match": "Le tue password non corrispondono o sono troppo corte. Si prega di digitare una password con almeno 8 caratteri.", + "scenes.login.home.title": "Accedi a Twake", + "scenes.login.create_account.step_1_subtitle": "Non potrebbe essere piΓΉ semplice: abbiamo solo bisogno di alcune informazioni.", + "scenes.login.create_account.step_2_subtitle_a": "Aggiungi il tuo nome completo per consentire agli altri utenti di riconoscerti.", + "scenes.app.workspaces.welcome_page.twake_team": "Twake", + "scenes.app.workspaces.welcome_page.welcome_header": "Benvenuto a Twake!", + "scenes.app.workspaces.welcome_page.add_secondary_emails_comment": "Puoi collegare piΓΉ indirizzi e-mail al tuo account; verrΓ  utilizzato un solo indirizzo per inviarti le notifiche.", + "scenes.app.workspaces.welcome_page.main_mail_title": "Indirizzo principale", + "scenes.app.workspaces.welcome_page.other_mail_title": "Indirizzi secondari", + "general.open": "Aprire", + "scenes.app.channelsbar.read_sign": "Segna come letto", + "scenes.app.popup.adduser.magiclinks.new_link_generated": "Nuovo link generato", + "scenes.app.popup.appsparameters.pages.alert_published_app": "La tua domanda Γ¨ pubblicata, non puoi modificarla.", + "scenes.app.popup.appsparameters.pages.allowed_ip_adresses_method": "Utilizzare * in fase di sviluppo per consentire tutti gli indirizzi IP.", + "scenes.app.popup.appsparameters.pages.app_privileges_label": "Privilegi dell'applicazione", + "scenes.app.popup.appsparameters.pages.available_publication_alert": "La pubblicazione della tua domanda Γ¨ attualmente in attesa di convalida da parte del team Twake.", + "scenes.app.popup.appsparameters.pages.button_force": "Forza in tutta l'azienda", + "scenes.app.popup.appsparameters.pages.call_event_handlers": "Evento di tipo '{{$1}}' e id '{{$2}}' con passivi '{{$3}}'", + "scenes.app.popup.appsparameters.pages.company_label": "Proprietario della compagnia", + "scenes.app.popup.appsparameters.pages.configuration_label": "Configurazione", + "scenes.app.popup.appsparameters.pages.go_back": "Indietro", + "scenes.app.popup.appsparameters.pages.grp_section_name-error": "Questo nome Γ¨ giΓ  utilizzato da un'altra applicazione. Si prega di sceglierne un altro.", + "scenes.app.popup.appsparameters.pages.grp_section_surname_label": "Nome semplificato", + "scenes.app.popup.appsparameters.pages.installation": "Installare.", + "scenes.app.popup.appsparameters.pages.instruction_message_twakecode": "Inizia scrivendo il tuo messaggio in formato JSON.", + "scenes.app.popup.appsparameters.pages.interne_availability_application": "Applicazione interna", + "scenes.app.popup.appsparameters.pages.json_configuration_information": "Vai alla documentazione per generare la tua configurazione in formato JSON.", + "scenes.app.popup.appsparameters.pages.loading": "Caricamento in corso...", + "scenes.app.popup.appsparameters.pages.message_data_next_event": "Dati passivi che verranno inviati al prossimo Evento", + "scenes.app.popup.appsparameters.pages.modify_public_data": "Modifica i dati pubblici della tua applicazione.", + "scenes.app.popup.appsparameters.pages.optimal_format": "Formato ottimale: 48x48px.", + "scenes.app.popup.appsparameters.pages.public_availability_application": "Applicazione pubblica", + "scenes.app.popup.workspaceparameter.pages.error_workspace_member": "Devi essere il solo partecipante nello spazio di lavoro per rimuoverlo. Rimuovi i tuoi collaboratori e riprova.", + "scenes.app.popup.workspaceparameter.pages.enter": "Entrare ", + "scenes.app.popup.workspaceparameter.pages.moderator_status": "Moderatore dello spazio di lavoro", + "scenes.app.popup.workspaceparameter.pages.alert_impossible_removing": "Non puoi lasciare lo spazio di lavoro, perchΓ© sei l'ultimo amministratore. Puoi definire un nuovo amministratore o cancellare/archiviare questo spazio di lavoro.", + "scenes.app.popup.workspaceparameter.pages.all_apps_small_text": "Tutte le applicazioni", + "scenes.app.popup.workspaceparameter.pages.apps_company_small_text": "Le applicazioni della tua azienda", + "scenes.app.popup.workspaceparameter.pages.installed_app_information": "Installa l'applicazione in questo spazio di lavoro.", + "scenes.app.popup.workspaceparameter.pages.name_label": "Nome dello spazio di lavoro", + "scenes.app.popup.workspaceparameter.pages.worspace_notif": "spazio di lavoro", + "scenes.app.popup.workspaceparameter.pages.write_access_subtitle": "Accesso di scrittura", + "scenes.app.popup.workspaceparameter.pages.your_apps_label": "Le tue applicazioni", + "scenes.app.popup.workspaceparameter.payments_subscriptions_title": "Pagamenti e abbonamenti", + "scenes.app.workspacesbar.components.change_company_title": "Cambia azienda", + "scenes.apps.calendar.day_option": "Giorno", + "scenes.apps.calendar.modals.description_placeholder": "Descrizione", + "scenes.apps.calendar.modals.details_title": "Particolari", + "scenes.apps.calendar.modals.event_adresse_placeholder": "Indirizzo", + "scenes.apps.calendar.modals.event_description_placeholder": "Descrizione", + "components.searchpopup.loading": "Caricamento di piΓΉ risultati", + "components.searchpopup.filter_ws": "Filtra le aree di lavoro", + "components.searchpopup.tags": "tag", + "components.searchpopup.size": "Misurare", + "components.searchpopup.creation": "Creazione", + "components.searchpopup.update_search": "Aggiorna ricerca", + "components.searchpopup.last_modif": "Ultima modifica", + "components.searchpopup.sender": "Mittente", + "components.searchpopup.mentions": "menzioni", + "components.searchpopup.only_pinned": "Solo messaggi appuntati", + "components.alert.confirm": "Conferma la tua azione", + "components.alert.confirm_click": "Conferma la tua azione facendo clic su OK.", + "components.searchpopup.tasks": "Compiti", + "scenes.app.mainview.advanced_search_placeholder": "Ricerca Avanzata", + "scenes.apps.drive.right_preview.public": "Accesso pubblico", + "components.drive.elements.configurate_mod": "Configura la modalitΓ ...", + "components.drive.elements.manage_version": "Gestisci versioni", + "scenes.client.channelbar.workspacechannellist.autocomplete": "Cerca canale, utente o messaggi diretti", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_creation": "Crea una nuova scheda", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_edition": "Rinomina {{$1}}", + "components.connectorslistmanager.add_connectors": "Aggiungi connettori", + "scenes.client.mainview.tabs.tabstemplateeditor.select_placeholder": "Applicazione", + "scenes.client.channelbar.channelmemberslist.no_members": "Non ci sono utenti in questo canale, puoi invitarli facendo clic su Aggiungi utenti.", + "scenes.app.channelsbar.hide_discussion_leaving.menu": "Nascondi discussione", + "scenes.app.popup.adduserfromtwakeconsole.current_users_state": "{{$1}} email verranno aggiunte", + "components.newversion.new_version_component.row.part_2": "ti consigliamo di ricaricare l'app e goderti le nostre nuove funzionalitΓ !", + "components.newversion.new_version_component.link": "Clicca qui per ricaricare", + "components.newversion.new_version_modal.title": "Nuovo aggiornamento disponibile !", + "scenes.apps.drive.download_all_button": "Scarica tutto", + "components.inputs.input_with_select.input.placeholder": "Nome del canale", + "components.inputs.input_with_select.select.placeholder": "Nome della sezione", + "components.inputs.input_with_select.select.no_sections": "Puoi raggruppare i tuoi canali qui", + "components.inputs.input_with_select.button.tooltip": "Imposta una sezione del canale", + "scenes.apps.messages.message.activity_message.a_added_b_to_the_channel": "{{$1}} ha aggiunto {{$2}} al canale", + "scenes.apps.messages.message.activity_message.a_removed_b_from_the_channel": "{{$1}} ha rimosso {{$2}} dal canale", + "scenes.apps.messages.message.activity_message.a_updated_channel_description": "{{$1}} ha cambiato la descrizione", + "scenes.apps.messages.message.activity_message.a_updated_channel_name": "{{$1}} ha rinominato il canale in {{$2}}", + "scenes.apps.messages.message.activity_message.a_created_channel_tab": "{{$1}} ha aggiunto una nuova scheda {{$2}} {{$3}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_tab": "{{$1}} rimosso scheda {{$2}} {{$3}}", + "scenes.client.channelbar.channelmemberslist.tag": "Voi", + "general.re_send": "Invia di nuovo", + "components.unverified_account.verification_details": "Abbiamo inviato un'e-mail di verifica a", + "components.account_verification_status_sentence": "Lo stato del tuo account Γ¨: {{$1}}", + "components.account_verication_status_unverified": "Non verificato", + "components.account_verication_status_blocked": "bloccato", + "components.unverified_account.re_send_email": "Non hai ricevuto l'e-mail?", + "components.verify_mail.title_1": "Congratulazioni", + "components.richtexteditor.toolbar.code": "Codice", + "components.on_boarding.popups.blocked_company.company_subscription_plan_button": "Clicca qui", + "components.on_boarding.popups.blocked_company.or": "o", + "components.on_boarding.popups.blocked_company.company_selector": "Passa a un'altra azienda", + "scenes.apps.tasks.select_user": "Cerca utente", + "components.locked_features.locked_only_office_popup.text": "Ops!! Sembra che tu voglia modificare il file da Twake. Potresti prendere in considerazione l'aggiornamento del tuo piano se desideri collaborare sui file dell'ufficio. Esplora le nostre opzioni di prezzo e seleziona l'opzione migliore per le esigenze di collaborazione del tuo team.", + "components.locked_features.locked_drive_popup.title": "Hai appena raggiunto il limite di unitΓ ", + "components.locked_features.locked_drive_popup.subtitle": "Nella versione gratuita, puoi archiviare solo 6 GB.", + "general.resume": "Riprendere", + "general.pause": "Pausa", + "scenes.app.integrations_parameters.title": "integrazioni", + "scenes.app.integrations_parameters.applications_table.name": "Nome", + "scenes.app.integrations_parameters.applications_table.title": "Altre integrazioni", + "scenes.app.integrations_parameters.applications_table.search_placeholder": "Cerca applicazione", + "scenes.join.wrong_link_title": "Questo link non Γ¨ piΓΉ disponibile", + "scenes.join.wrong_link_description": "Chiedi alla persona che ti ha invitato a entrare a far parte di questa azienda un nuovo collegamento o crea la tua azienda", + "scenes.join.create_the_company_button": "Crea l'azienda", + "scenes.join.join_workspace_from_company": "Unisciti a {{$1}} da {{$2}}!", + "scenes.join.twake_description": "Twake Γ¨ uno spazio di lavoro digitale open source creato per migliorare la produttivitΓ  del tuo team", + "scenes.join.login_first_button": "Accedi o crea un account prima", + "scenes.join.join_the_team_button": "Unisciti alla squadra", + "general.close": "Vicino", + "general.cancel": "Annulla", + "general.retry": "Riprova", + "general.create": "Crea", + "general.edit": "Modifica", + "general.continue": "Continua", + "general.back": "Indietro", + "general.confirm": "Conferma", + "general.delete": "Eliminare", + "general.archive": "Archivio", + "general.unarchive": "Annulla archiviazione", + "general.help": "Aiuto", + "general.help.support": "Supporto", + "general.help.documentation": "Documentazione", + "general.send": "Invia messaggio", + "general.update": "Aggiorna", + "general.remove": "Rimuovi", + "general.add": "Aggiungi", + "general.connexion_status.disconnected": "Sei offline", + "general.connexion_status.connected": "Sei online", + "general.connexion_status.connecting": "Riconnessione in corso…", + "application.load.longer": "Il server impiega piΓΉ tempo del previsto per rispondere, attendere o ricaricare la pagina...", + "scenes.app.side_app.messages_thread_title": "{{$1}} β€’ Thread dei messaggi", + "scenes.app.workspaces.create_company.group_data": "Configura il tuo nuovo gruppo", + "scenes.app.workspaces.create_company.group_data.group_type": "Tipo di gruppo", + "scenes.app.workspaces.create_company.group_data.group_type.company": "Azienda o dipartimento aziendale", + "scenes.app.workspaces.create_company.group_data.group_type.public_organization": "Organizzazione pubblica", + "scenes.app.workspaces.create_company.group_data.group_type.university_school": "UniversitΓ  o scuola", + "scenes.app.workspaces.create_company.group_data.group_type.society_club_charity": "SocietΓ , club o beneficenza", + "scenes.app.workspaces.create_company.group_data.group_type.other_group": "Altro", + "scenes.app.workspaces.create_company.group_data.group_size": "Dimensione del gruppo", + "scenes.app.workspaces.create_company.group_data.group_size.less_3": "Meno di 4 utenti", + "scenes.app.workspaces.create_company.group_data.group_size.4_10": "4 - 10 utenti", + "scenes.app.workspaces.create_company.group_data.group_size.10_50": "11 - 49 utenti", + "scenes.app.workspaces.create_company.group_data.group_size.50_100": "50 - 99 utenti", + "scenes.app.workspaces.create_company.group_data.group_size.100_500": "100 - 499 utenti", + "scenes.app.workspaces.create_company.group_data.group_size.500_1000": "500 - 999 utenti", + "scenes.app.workspaces.create_company.group_data.group_size.1000_5000": "1000 - 4999 utenti", + "scenes.app.workspaces.create_company.group_data.group_size.5000_more": "PiΓΉ di 5000 utenti", + "scenes.app.workspaces.create_company.group_data.group_main_activity": "AttivitΓ  principale", + "scenes.app.workspaces.create_company.group_data.group_main_activity.food": "Cibo", + "scenes.app.workspaces.create_company.group_data.group_main_activity.bank": "Banca / Assicurazione", + "scenes.app.workspaces.create_company.group_data.group_main_activity.printing_paper": "Stampa / Carta", + "scenes.app.workspaces.create_company.group_data.group_main_activity.construction_building": "Edilizia / Materiali da costruzione", + "scenes.app.workspaces.create_company.group_data.group_main_activity.real_estate": "Immobiliare", + "scenes.app.workspaces.create_company.group_data.group_main_activity.materials": "Materiali", + "scenes.app.workspaces.create_company.group_data.group_main_activity.chemistry": "Chimica", + "scenes.app.workspaces.create_company.group_data.group_main_activity.trade_commerce_distribution": "Vendita/Commercio/Distribuzione", + "scenes.app.workspaces.create_company.group_data.group_main_activity.publishing_communication_multimedia": "Editoria / Comunicazione / Multimedia", + "scenes.app.workspaces.create_company.group_data.group_main_activity.electronics_electricity_energy": "Elettronica/ElettricitΓ /Energia", + "scenes.app.workspaces.create_company.group_data.group_main_activity.studies_and_advice": "Studi e consigli", + "scenes.app.workspaces.create_company.group_data.group_main_activity.pharmaceutical_industry": "Industria farmaceutica", + "scenes.app.workspaces.create_company.group_data.group_main_activity.it_telecom": "IT / Telecomunicazioni", + "scenes.app.workspaces.create_company.group_data.group_main_activity.machinery_automotive": "Macchinari / Automotive", + "scenes.app.workspaces.create_company.group_data.group_main_activity.business_services": "Servizi per gli affari", + "scenes.app.workspaces.create_company.group_data.group_main_activity.entertainment": "Divertimento", + "scenes.app.workspaces.create_company.group_data.group_main_activity.textile_clothing_shoes": "Tessile / Abbigliamento / Scarpe", + "scenes.app.workspaces.create_company.group_data.group_main_activity.transport_logistics": "Trasporti / Logistica", + "scenes.app.workspaces.create_company.group_data.group_main_activity.research": "Ricerca", + "scenes.app.workspaces.create_company.group_data.group_main_activity.education": "Formazione scolastica", + "scenes.app.workspaces.create_company.group_data.group_main_activity.administration": "Amministrazione", + "scenes.app.workspaces.create_company.group_data.group_main_activity.other": "Altro", + "components.application.messages": "Messaggi", + "components.drive_dropzone.uploading": "Caricamento in corso...", + "components.user_picker.modal_no_result": "Nessun risultato trovato", + "components.users_picker.add_me": "Aggiungimi", + "scenes.app.workspaces.create_company.invitations.title": "Configura il tuo spazio di lavoro.", + "scenes.app.header.disconnected": "Sei disconnesso", + "scenes.app.header.disconnected.reload": "Ricarica", + "scenes.app.header.alt_notifications": "Notifiche", + "scenes.apps.calendar.calendar.week_btn": "Settimana", + "scenes.apps.calendar.calendar.list_btn": "Elenco", + "scenes.apps.calendar.event_edition.deadline_tag": "Scadenza", + "scenes.apps.calendar.event_edition.checkbox_all_day": "Tutto il giorno", + "scenes.apps.calendar.event_edition.title_confidentiality": "Riservatezza", + "scenes.apps.calendar.event_view.article_until": "a", + "scenes.apps.calendar.calendar_modal.participants": "partecipanti", + "scenes.apps.calendar.calendar_modal.placeholder": "Nome", + "scenes.apps.calendar.left.calendars": "Calendari", + "scenes.apps.drive.left.search": "Ricerca", + "scenes.apps.drive.navigators.navigator_content.directory_name": "Nome della directory", + "scenes.apps.drive.navigators.navigator_content.files": "File", + "scenes.apps.drive.navigators.navigator_labels.title": "Etichette", + "scenes.apps.drive.navigators.new_file.untitled": "Senza titolo", + "scenes.apps.drive.navigators.new_file.create_file.type": "Tipo", + "scenes.apps.drive.navigators.new_file": "Nuovo file", + "scenes.apps.drive.preview_bloc.operations_download": "Scarica", + "scenes.apps.drive.preview_bloc.error_file": "File non trovato", + "scenes.apps.drive.right_preview.operations_restore": "Ristabilire", + "scenes.apps.drive.right_preview.operations_delete": "Sposta nel cestino", + "scenes.apps.drive.right_preview.public_link": "Link pubblico", + "scenes.apps.messages.messages": "Messaggi", + "scenes.apps.messages.chatbox.chat.delete_message": "Elimina questo messaggio", + "scenes.apps.messages.chatbox.chat.delete_message_btn": "Elimina il messaggio", + "scenes.apps.messages.left_bar.stream_modal.placeholder_name": "Nome", + "scenes.apps.messages.left_bar.stream.add_to_favorites": "Aggiungi ai preferiti", + "scenes.apps.messages.left_bar.stream.remove_from_favorites": "Rimuovi dai preferiti", + "scenes.apps.messages.left_bar.stream.notifications": "Notifiche...", + "scenes.apps.messages.left_bar.stream.notifications.all": "Qualsiasi messaggio", + "scenes.apps.messages.left_bar.stream.notifications.mentions": "{{$1}}, {{$2}} e {{$3}}", + "scenes.apps.messages.left_bar.stream.notifications.me": "Solo {{$1}}", + "scenes.apps.messages.left_bar.stream.notifications.never": "Niente", + "scenes.apps.parameters.workspace_sections.workspace": "Spazio di lavoro", + "scenes.apps.parameters.workspace_sections.members": "Partecipanti", + "scenes.apps.parameters.group_sections.workspaces": "Spazi di lavoro", + "scenes.apps.parameters.group_sections.apps": "App", + "scenes.apps.account.title": "Parametri dell'account", + "scenes.apps.account.account.menu_title": "Account", + "scenes.apps.account.languages.menu_title": "Lingua", + "scenes.apps.account.account.firstname": "Nome", + "scenes.apps.account.account.lastname": "Cognome", + "scenes.apps.account.account.username": "Nome utente", + "scenes.apps.account.account.change_username": "Cambia il tuo nome utente univoco.", + "scenes.apps.account.account.emails": "E-mail", + "scenes.apps.account.account.main_email": "E-mail principale", + "scenes.apps.account.account.email_add": "Aggiungi una nuova e-mail", + "scenes.apps.account.account.email_add_modal.invalid_code": "Questo codice non Γ¨ valido", + "scenes.apps.account.account.password": "Password", + "scenes.apps.account.account.password_modal.old_password": "Password attuale", + "scenes.apps.account.account.password_modal.password": "Nuova password", + "scenes.apps.account.account.password_modal.bad_old_password": "La vecchia password non Γ¨ corretta.", + "scenes.apps.account.account.password_modal.bad_password": "Le tue password non corrispondono o sono troppo corte. Si prega di digitare una password con almeno 8 caratteri.", + "scenes.apps.account.account.logout": "Disconnettersi", + "scenes.apps.account.languages.text": "Cambia la lingua di Twake.", + "scenes.apps.account.notifications.title": "Notifiche", + "scenes.apps.account.notifications.keywords_subtitle": "Parole chiave", + "scenes.apps.account.notifications.keywords_placeholder": "dev, wifi, codice, ...", + "scenes.apps.account.notifications.disturb_option_a": "Non inviarmi notifiche push tra ", + "scenes.apps.account.notifications.disturb_option_b": " e ", + "scenes.apps.account.notifications.disturb_option_c": " (fuso orario locale)", + "scenes.apps.account.notifications.devices_subtitle": "Notifiche del dispositivo", + "scenes.apps.account.notifications.devices_option_ever": "Inviami sempre notifiche push", + "scenes.apps.account.notifications.devices_option_inactive": "Inviami notifiche push quando sono inattivo sul desktop", + "scenes.apps.account.notifications.devices_option_never": "Non inviarmi notifiche push mai", + "scenes.apps.account.notifications.privacy_subtitle": "Riservatezza", + "scenes.apps.account.notifications.mail_subtitle": "Notifiche di posta elettronica", + "scenes.apps.account.notifications.sound": "Notifica sonora", + "scenes.apps.parameters.group_sections.apps.badge_extension": "Estensione", + "scenes.apps.parameters.workspace_sections.members.members": "Utenti", + "scenes.apps.parameters.workspace_sections.members.pending": "Email in attesa", + "scenes.apps.parameters.workspace_sections.members.invite": "Invita nuovo utente", + "scenes.apps.parameters.workspace_sections.members.invite_btn": "Aggiungi utente", + "scenes.apps.tasks.boards": "Tavole", + "scenes.apps.tasks.connectors_menu": "Connettori...", + "scenes.apps.tasks.connectors_search_menu": "Cerchiamo connettori...", + "scenes.apps.tasks.no_connectors_menu_text": "Non disponi di connettori che possono connettersi a un calendario.", + "scenes.apps.tasks.unconfigured_tab": "Questa scheda non Γ¨ ancora configurata.", + "scenes.apps.tasks.choose_board_button": "Scegli una tavola", + "scenes.apps.tasks.new_board.title": "Nuova tavola", + "scenes.apps.tasks.new_board.edit_title": "Modifica la tavola", + "scenes.apps.tasks.task": "Compito", + "scenes.apps.tasks.no_tasks": "Nessun compito", + "scenes.apps.tasks.task_status.todo": "Da fare", + "scenes.apps.tasks.task_status.current": "Attuale", + "scenes.apps.tasks.task_status.done": "Fatto", + "scenes.apps.tasks.task.description": "Descrizione", + "scenes.apps.tasks.task.assignees": "Assegnatari", + "scenes.apps.tasks.task.edit.dates": "Date", + "scenes.apps.tasks.list_modal.modify_list": "Modifica l'elenco", + "scenes.apps.tasks.list_modal.new_list": "Nuovo elenco", + "scenes.apps.tasks.list_modal.remove": "Rimuovi l'elenco ed i compiti", + "scenes.apps.tasks.list_modal.predefined_participants": "Partecipanti predefiniti", + "scenes.apps.tasks.list_modal.archive_all_tasks": "Archivia tutti i compiti", + "scenes.apps.tasks.list_modal.remove_archived_tasks": "Rimuovi i compiti archiviati ({{$1}})", + "scenes.login.footer.go_to_twake": "Vai su twakeapp.com", + "scenes.login.footer.branding": "Sei su un server Twake privato {{$1}} ({{$2}}). ", + "scenes.login.create_account.title": "Crea un nuovo account", + "scenes.login.create_account.email": "Posta elettronica", + "scenes.login.create_account.fill_in_email": "Devi compilare la tua email con una email corretta", + "scenes.login.create_account.too_short_password": "La tua password deve contenere almeno 8 caratteri.", + "scenes.login.create_account.firstname": "Nome", + "scenes.login.create_account.newsletter": "Ricevere informazioni su Twake", + "scenes.login.create_account.lastname": "Cognome", + "scenes.login.forgot_password.title": "Hai dimenticato la password?", + "scenes.login.forgot_password.text": "Riceverai un codice di 9 cifre via e-mail per verificare la tua identitΓ .", + "scenes.login.forgot_password.email_to_recover": "E-mail da recuperare", + "scenes.login.forgot_password.mail_doesnt_exist": "Questa e-mail non esiste", + "scenes.login.forgot_password.text2": "Riceverai un codice di 9 cifre. Inseriscilo nel campo sottostante per continuare.", + "scenes.login.home.subtitle": "Benvenuto", + "scenes.login.home.email": "E-mail", + "scenes.login.home.unable_to_connect": "Credenziali non valide", + "scenes.login.home.password": "Password", + "scenes.login.home.login_btn": "Accedi", + "scenes.login.home.lost_password": "Hai dimenticato la password?", + "scenes.login.home.create_account": "Crea un account", + "scenes.login.create_account.password": "Password", + "scenes.login.create_account.step_2_subtitle_b": "Il tuo numero di telefono rimane privato.", + "scenes.login.create_account.step_3_mail_sent": "Ti abbiamo inviato un link di attivazione via e-mail.", + "scenes.login.create_account.step_3_subtitle": "Ultimo passaggio: dobbiamo verificare che non sei un robot!", + "scenes.app.workspaces.create_company.company_name.placeholder": "Nome dell'azienda", + "scenes.app.workspaces.create_company.company_name.title_1": "Per iniziare,", + "scenes.app.workspaces.create_company.company_name.title_2": "indica il nome della tua azienda.", + "scenes.app.workspaces.create_company.default_workspace_name": "Principale", + "scenes.app.workspaces.create_company.group_data.title": "Saremo veloci: abbiamo solo bisogno di alcune informazioni statistiche.", + "scenes.app.workspaces.create_company.importations.title_1": "Lavori giΓ  con strumenti digitali? Importa o integra subito i tuoi strumenti!", + "scenes.app.workspaces.create_company.importations.title_2": "Non preoccuparti, puoi farlo piΓΉ tardi!", + "scenes.app.workspaces.create_company.invitations.title_2": "Aggiungi utenti al tuo team.", + "scenes.app.workspaces.create_company.title": "Crea la mia azienda", + "scenes.app.workspaces.welcome_page.add_secondary_emails": "Aggiungi un'email secondaria", + "scenes.app.workspaces.welcome_page.added_to_company": "Sei stato invitato a ", + "scenes.app.workspaces.welcome_page.create_my_company": "Crea la mia azienda", + "scenes.app.workspaces.welcome_page.lets_go": "Andiamo!", + "scenes.app.workspaces.welcome_page.may_be_invited_with_secondary_emails": "Sei stato invitato utilizzando un altro email?", + "scenes.app.workspaces.welcome_page.no_company_subtitle": "Oh, beh... Sembra che nessuno ti abbia ancora invitato in un'azienda.", + "scenes.app.workspaces.welcome_page.ready_to_work": "Ora sei pronto a lavorare.", + "scenes.app.workspaces.welcome_page.see_you_soon": "A presto!", + "scenes.app.workspaces.welcome_page.try_again": "Riprova", + "scenes.app.workspaces.welcome_page.add_new_email": "Aggiungi una e-mail", + "scenes.app.workspaces.welcome_page.code_verification": "Codice di verifica", + "scenes.app.workspaces.welcome_page.new_email": "Aggiungi un'e-mail secondaria", + "scenes.app.workspaces.welcome_page.we_sent_you_mail": "Ti abbiamo inviato un codice di verifica tramite {{$1}}", + "scenes.app.workspaces.welcome_page.done": "Ho finito", + "scenes.login.forgot_password.finished": "La tua password Γ¨ stata aggiornata con successo.", + "scenes.apps.account.account.description_main": "Il tuo indirizzo principale Γ¨ dove Twake invia le tue notifiche. I tuoi indirizzi secondari ti consentono di essere invitato automaticamente agli spazi di lavoro che li utilizzano.", + "scenes.apps.account.account.emails.description": "Gestisci i tuoi diversi indirizzi e-mail.", + "scenes.apps.account.account.make_main": "Imposta la e-mail principale", + "scenes.apps.account.account.password.description": "Cambia la tua password.", + "scenes.apps.account.identity": "IdentitΓ ", + "scenes.apps.account.identity.description": "Modifica il tuo nome, cognome e immagine del profilo visibile agli altri utenti di Twake.", + "scenes.apps.account.preference": "Preferenze", + "scenes.apps.account.thumbnail.max_weight": "Dimensione massima 5 MB", + "scenes.apps.account.account.email_add_modal.confirm": "Conferma questa e-mail", + "app.name.twake_calendar": "Calendario", + "app.name.twake_drive": "Documenti", + "app.name.twake_tasks": "Compiti", + "components.calendar.repetition.everyday": "Quotidiano", + "components.calendar.repetition.does_not_repeat": "Non si ripete", + "components.calendar.repetition.weekly_on": "Settimanale il {{$1}}", + "components.calendar.repetition.monthly_on": "Mensile il {{$1}} {{$2}}", + "components.calendar.repetition.monthly_on_day": "Mensile il giorno {{$1}}", + "components.calendar.repetition.annually_on": "Annualmente il {{$1}}", + "components.calendar.repetition.every_weekday": "Tutti i giorni feriali (dal lunedΓ¬ al venerdΓ¬)", + "components.calendar.repetition.custom": "Personalizzato...", + "components.calendar.repetition.repeat": "Ripetere ogni", + "components.calendar.repetition.ends": "Finisce", + "components.calendar.repetition.never": "Mai", + "components.calendar.repetition.on": "Il", + "components.calendar.repetition.after": "Dopo", + "components.calendar.repetition.days": "giorno/i", + "components.calendar.repetition.weeks": "settimana(e)", + "components.calendar.repetition.months": "mese(i)", + "components.calendar.repetition.years": "anno(i)", + "components.calendar.repetition.custom_recurrence": "Ricorrenza personalizzata", + "components.calendar.repetition.occurrence": "Evento(i)", + "components.calendar.repetition.repeat_on": "Ripetere il", + "scenes.app.channelsbar.currentuser.add_apps": "Cerchiamo applicazioni", + "scenes.app.channelsbar.currentuser.change_my_status": "Cambiare il mio stato", + "scenes.app.channelsbar.currentuser.collaborateurs": "Utenti", + "scenes.app.channelsbar.currentuser.create_workspace_page": "Crea uno spazio di lavoro", + "scenes.app.channelsbar.currentuser.invited_status": "Sei un ospite.", + "scenes.app.channelsbar.currentuser.title": "Impostazioni dell 'account", + "scenes.app.channelsbar.currentuser.workspace_info": "Sei nello spazio di lavoro {{$1}} dal gruppo {{$2}}", + "scenes.app.channelsbar.currentuser.workspace_parameters": "Impostazioni dello spazio di lavoro", + "scenes.app.channelsbar.currentuser.logout": "Esci", + "scenes.app.channelsbar.currentuser.update": "Aggiornare", + "scenes.app.channelsbar.currentuser.disable_notifications": "Disattivare", + "scenes.app.channelsbar.currentuser.disabling_notifications": "Disattivare per 1h", + "scenes.app.channelsbar.currentuser.disabling_notifications_until": "Disattivare fino alle 9:00 Domani", + "scenes.app.channelsbar.currentuser.reactivate_notifications": "Riattivare", + "scenes.app.channelsbar.currentuser.user_parameter": "Impostazioni di notifica", + "scenes.app.channelsbar.currentuser.company_messages_counter_header": "Numero di messaggi", + "scenes.app.channelsbar.currentuser.company_messages_counter_info": "Nella versione gratuita di Twake, non Γ¨ possibile accedere a piΓΉ di {{$1}} messaggi piΓΉ recenti.", + "scenes.app.channelsbar.currentuser.company_messages_counter_link": "Mostra piΓΉ piani", + "scenes.app.channelsbar.channelsuser.new_private_discussion": "Nuova discussione privata", + "scenes.app.channelsbar.channelsuser.no_private_message_invite_collaboraters": "Nessun messaggio privato. Invita gli utenti!", + "scenes.app.channelsbar.channelsuser.private_messages": "Messaggi diretti", + "scenes.app.channelsbar.channelsworkspace.channel_title": "CANALI", + "scenes.app.channelsbar.channelsworkspace.channel_title.favorite": "PREFERITI", + "scenes.app.channelsbar.channelsworkspace.create_channel": "Crea un canale", + "scenes.app.channelsbar.channelsworkspace.no_channel": "Non ti sei ancora iscritto a nessun canale", + "scenes.app.channelsbar.modify_channel_menu": "Impostazioni del canale", + "scenes.app.channelsbar.guest_management": "Gestione degli ospiti", + "scenes.app.channelsbar.unread_sign": "Segna come non letto", + "scenes.app.channelsbar.channel_leaving": "Lasciare il canale", + "scenes.app.channelsbar.channel_removing": "Eliminare il canale", + "scenes.app.channelsbar.company_invitation_alert_subtitle": "Puoi importare questi canali nella tua attivitΓ  per rimanere organizzato facendo clic su questo riquadro.", + "scenes.app.channelsbar.company_invitation_alert_title": "Sei invitato in azienda ", + "scenes.app.channelsbar.initial_instructions_tutorial": "Scegli un nome, un cognome ed un'immagine del profilo.", + "scenes.app.channelsbar.installation_desktop_tutorial": "Installa l'applicazione desktop", + "scenes.app.channelsbar.invitation_collaboraors_tutorial": "Invita gli utenti nel tuo spazio di lavoro.", + "scenes.app.channelsbar.public_channel_label": "Pubblico", + "scenes.app.channelsbar.private_channel_label": "Privato", + "scenes.app.channelsbar.sending_message_instruction": "Invia il tuo primo messaggio in una discussione", + "scenes.app.channelsbar.tutorial_alert": "Non mostrare piΓΉ questa cornice mai?", + "scenes.app.channelsbar.welcome": "Benvenuto a Twake", + "scenes.app.channelsbar.welcoming_message_subtitle": "Diventa un professionista di Twake in pochi clic!", + "scenes.app.mainview.instruction_current_tab": "Inizia selezionando un canale alla tua sinistra.", + "scenes.app.mainview.tabs.no_connected_connectors_for_channel": "Non hai un connettore in grado di connettersi a un canale.", + "scenes.app.mainview.tabs.rename": "Rinominare", + "scenes.app.mainview.tabs.searching_connectors": "Cerchiamo di connettori...", + "scenes.app.popup.adduser.adresses_message": "Si prega di separare gli indirizzi con una virgola o uno spazio. Ricorda che Twake puΓ² limitare il numero di inviti in base al tuo abbonamento.", + "scenes.app.popup.adduser.magiclinks.genrator_info": "Link di invito allo spazio di lavoro", + "scenes.app.popup.adduser.magiclinks.copied_to_clipboard": "Copiato negli appunti con successo", + "scenes.app.popup.adduser.magiclinks.action_copy": "Copiare", + "scenes.app.popup.adduser.magiclinks.action_generate": "Creare", + "scenes.app.popup.appsparameters.pages._app_identity": "IdentitΓ  dell'applicazione", + "scenes.app.popup.appsparameters.pages._appareance_message_twakcode": "Prova l'aspetto dei tuoi messaggi Twacode", + "scenes.app.popup.appsparameters.pages.amazing_app_name": "La mia fantastica app", + "scenes.app.popup.appsparameters.pages.api_data_description": "Dati utili per l'API Twake.", + "scenes.app.popup.appsparameters.pages.api_parameters_label": "Impostazioni API", + "scenes.app.popup.appsparameters.pages.app_name_label": "Nome dell'applicazione", + "scenes.app.popup.appsparameters.pages.app_modification_right": "Tutti i manager di questa azienda potranno modificare questa applicazione.", + "scenes.app.popup.appsparameters.pages.app_privileges_information": "Definisci cosa puΓ² modificare e leggere la tua applicazione.", + "scenes.app.popup.appsparameters.pages.app_update": "Aggiorna l'app {{$1}} (l'app viene utilizzata {{$2}} volte)", + "scenes.app.popup.appsparameters.pages.application_title": "Applicazione", + "scenes.app.popup.appsparameters.pages.apps_title": "Le tue applicazioni e connettori", + "scenes.app.popup.appsparameters.pages.automatique_label": "Automatico", + "scenes.app.popup.appsparameters.pages.automatique_option_information": "Se attivi 'Automatico', questa applicazione verrΓ  automaticamente aggiunta ai prossimi spazi di lavoro di questa azienda.", + "scenes.app.popup.appsparameters.pages.autorised_ip_adresses_label": "Indirizzi IP consentiti", + "scenes.app.popup.appsparameters.pages.create_app_button": "Crea un'applicazione", + "scenes.app.popup.appsparameters.pages.create_my_app": "Crea la mia applicazione", + "scenes.app.popup.appsparameters.pages.current_informations_apps_connectors": "Non hai ancora creato un'app. Prima di creare un'applicazione o un connettore, assicurati che non esista giΓ  nel nostro mercato delle applicazioni.", + "scenes.app.popup.appsparameters.pages.danger_zone_description": "Elimina l'applicazione", + "scenes.app.popup.appsparameters.pages.danger_zone_label": "Zona pericolosa", + "scenes.app.popup.appsparameters.pages.description_label": "Descrizione", + "scenes.app.popup.appsparameters.pages.developped_apps_subtitle": "Applicazioni sviluppate dall'azienda", + "scenes.app.popup.appsparameters.pages.dispalyed_parameters_description": "Ti consente di definire dove sarΓ  visibile la tua applicazione.", + "scenes.app.popup.appsparameters.pages.displayed_parameters_label": "Impostazioni di visualizzazione", + "scenes.app.popup.appsparameters.pages.error_check_needed": "C'Γ¨ stato un errore; controlla le tue informazioni.", + "scenes.app.popup.appsparameters.pages.error_message": "Questo nome Γ¨ giΓ  utilizzato da un'altra applicazione; per favore scegline un altro.", + "scenes.app.popup.appsparameters.pages.error_user_code": "errore", + "scenes.app.popup.appsparameters.pages.event_subtitle": "Eventi", + "scenes.app.popup.appsparameters.pages.filter_information": "Questo filtro limita l'uso della tua chiave API ai soli server nel tuo connettore.", + "scenes.app.popup.appsparameters.pages.new_app_title": "Nuova applicazione", + "scenes.app.popup.appsparameters.pages.ok_user_code": "ok", + "scenes.app.popup.appsparameters.pages.parameters_form_small_text": "L'applicazione non pubblicata funzionerΓ  solo nella tua azienda. Se vuoi renderlo disponibile a tutti gli utenti Twake, attiva questa opzione.", + "scenes.app.popup.appsparameters.pages.public_login_label": "Identificatore pubblico", + "scenes.app.popup.appsparameters.pages.publication_description": "Determina la visibilitΓ  della tua applicazione.", + "scenes.app.popup.appsparameters.pages.publication_label": "Pubblicazione", + "scenes.app.popup.appsparameters.pages.publish_app_label": "Pubblica l'applicazione", + "scenes.app.popup.appsparameters.pages.read_privileges_label": "Privilegi di lettura", + "scenes.app.popup.appsparameters.pages.remove_app": "Eliminare l'applicazione {{$1}} in modo permanente.", + "scenes.app.popup.appsparameters.pages.remove_app_from_company": "Rimuovere da tutta l'azienda", + "scenes.app.popup.appsparameters.pages.remove_app_from_workspace": "Rimuovi dallo spazio di lavoro", + "scenes.app.popup.appsparameters.pages.show_button": "Mostra", + "scenes.app.popup.appsparameters.pages.status_tilte": "Stato", + "scenes.app.popup.appsparameters.pages.string_information": "Questa stringa identifica la tua applicazione e verrΓ  utilizzata nei comandi dei messaggi.", + "scenes.app.popup.appsparameters.pages.title_tester": "Tester di Twakecode", + "scenes.app.popup.appsparameters.pages.url_reception_events_label": "URL della ricezione degli eventi", + "scenes.app.popup.appsparameters.pages.waiting_availability_application": "In attesa...", + "scenes.app.popup.appsparameters.pages.website_label": "Sito web", + "scenes.app.popup.appsparameters.pages.write_privileges_label": "Privilegi di scrittura", + "scenes.app.popup.appsparameters.pages.danger_zone_small_text": "Non puoi eliminare questa app se Γ¨ pubblicata.", + "scenes.app.popup.appsparameters.pages.error_app_simple_name_message": "Il nome semplificato della tua applicazione Γ¨ giΓ  utilizzato da un'altra applicazione. Per favore cambialo.", + "scenes.app.popup.appsparameters.pages.error_app_update_message": "Si Γ¨ verificato un errore durante l'aggiornamento dell'applicazione.", + "scenes.app.popup.appsparameters.pages.remove_app_button": "Elimina l'applicazione", + "scenes.app.popup.appsparameters.pages.update_button": "Aggiornare", + "scenes.app.popup.createworkspacepage.add_subtitle": "Bisogno di piΓΉ spazio?", + "scenes.app.popup.createworkspacepage.create_new_workspace": "Crea un nuovo spazio di lavoro", + "scenes.app.popup.createworkspacepage.placeholder_name": "Nome dello spazio di lavoro", + "scenes.app.popup.userparameter.pages.frequency_notif_configuration_description": "Configura le notifiche push mobili.", + "scenes.app.popup.userparameter.pages.frequency_notif_subtitle": "Frequenza delle notifiche", + "scenes.app.popup.userparameter.pages.keywords_notif_description": "Evidenzia le seguenti parole chiave:", + "scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description": "Configura il digest e-mail delle notifiche.", + "scenes.app.popup.userparameter.pages.private_message_content.show": "Nascondere il contenuto dei messaggi nelle notifiche push", + "scenes.app.popup.userparameter.pages.private_message_content.hide": "Sostituire il contenuto delle notifiche push con \"[Privato]\"", + "scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description": "Scegli un periodo durante il quale non ricevi notifiche.", + "scenes.app.popup.userparameter.pages.no_night_disturbing_label": "Non disturbare di notte", + "scenes.app.popup.userparameter.pages.notif_content_label": "Contenuto delle notifiche", + "scenes.app.mainview.quick_search_placeholder": "Ricerca rapida", + "scenes.app.popup.userparameter.personnal_workspaces_title": "I tuoi spazi di lavoro", + "scenes.app.popup.workspaceparameter.admin_current_status": "Sei un amministratore.", + "scenes.app.popup.workspaceparameter.admin_manager_current_status": "Sei un amministratore dello spazio di lavoro.", + "scenes.app.popup.workspaceparameter.manager_current_status": "Sei un amministratore dell'azienda.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace": "Elimina lo spazio di lavoro", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace_description": "La cancellazione di uno spazio di lavoro non puΓ² essere annullata. Tutti i messaggi e i file saranno irrecuperabili.", + "scenes.app.popup.workspaceparameter.pages.access_apps": "Accedi alle tue applicazioni e ai tuoi connettori", + "scenes.app.popup.workspaceparameter.pages.apps_connectors_title": "Integrazioni", + "scenes.app.popup.workspaceparameter.pages.apps_research_title": "Cerchiamo di applicazioni", + "scenes.app.popup.workspaceparameter.pages.apps_small_text": "Applicazioni di questo spazio di lavoro", + "scenes.app.popup.workspaceparameter.pages.back_to_search_button": "Torna alla ricerca", + "scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button": "Invita utenti", + "scenes.app.popup.workspaceparameter.pages.collaborateurs": "Utenti", + "scenes.app.popup.workspaceparameter.pages.company_developped_apps_subtitle": "Applicazioni sviluppate dall'azienda", + "scenes.app.popup.workspaceparameter.pages.company_identity_title": "IdentitΓ  dell'azienda", + "scenes.app.popup.workspaceparameter.pages.company_name_description": "Cambia il nome di questa azienda", + "scenes.app.popup.workspaceparameter.pages.company_name_label": "Nome dell 'azienda", + "scenes.app.popup.workspaceparameter.pages.configuration_notif": "configurazione", + "scenes.app.popup.workspaceparameter.pages.configure_button": "Configura ", + "scenes.app.popup.workspaceparameter.pages.description": "Descrizione", + "scenes.app.popup.workspaceparameter.pages.developped_apps_small_text": "Applicazioni sviluppate dall'azienda", + "scenes.app.popup.workspaceparameter.pages.displayed_preferencies_subtitle": "Preferenze di visualizzazione", + "scenes.app.popup.workspaceparameter.pages.install_button": "Installare", + "scenes.app.popup.workspaceparameter.pages.installed_apps_information": "Applicazioni installate in questo spazio di lavoro {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_message": "Applicazioni installate in altre aree dell'azienda {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_subtitle": "Applicazioni installate", + "scenes.app.popup.workspaceparameter.pages.invitation_error": "Si Γ¨ verificato un errore durante l'invito ai seguenti utenti: ", + "scenes.app.popup.workspaceparameter.pages.invited_guest_check_message": "Verifica che il nome utente o l'e-mail utilizzati siano validi.", + "scenes.app.popup.workspaceparameter.pages.logo_modify_description": "Modifica l'immagine di questo spazio di lavoro", + "scenes.app.popup.workspaceparameter.pages.logo_subtitle": "Logo", + "scenes.app.popup.workspaceparameter.pages.name_description": "Cambia il nome di questo spazio di lavoro", + "scenes.app.popup.workspaceparameter.pages.no_access": "Nessun accesso.", + "scenes.app.popup.workspaceparameter.pages.no_app_information": "Non hai applicazioni in questo spazio di lavoro", + "scenes.app.popup.workspaceparameter.pages.quit_workspace_menu": "Lascia questo spazio di lavoro", + "scenes.app.popup.workspaceparameter.pages.read_access_subtitle": "Accesso in lettura", + "scenes.app.popup.workspaceparameter.pages.remove_from_company_text": "Rimuovere da tutta l'azienda", + "scenes.app.popup.workspaceparameter.pages.research_by": "Cerca applicazioni per nome e categorie", + "scenes.app.popup.workspaceparameter.pages.researching_apps_button": "Cerchiamo di applicazioni...", + "scenes.app.popup.workspaceparameter.pages.show_button": "Schermo", + "scenes.app.popup.workspaceparameter.pages.title": "Impostazioni dello spazio di lavoro", + "scenes.app.popup.workspaceparameter.pages.webhooks_access_subtitle": "Accesso ai webhook", + "scenes.app.popup.workspaceparameter.pages.weight_max_small_text": "Dimensione massima 5 MB.", + "scenes.app.popup.workspaceparameter.pages.withdraw_button": "Rimuovi da questo spazio di lavoro", + "scenes.app.workspacesbar.components.create_company_menu": "Creare un'azienda", + "scenes.app.workspacesbar.components.grp_parameters": "{{$1}} impostazioni", + "scenes.apps.calendar.add_calendar_menu": "Aggiungi un calendario", + "scenes.apps.calendar.connectors_menu": "Connettori...", + "scenes.apps.calendar.connectors_search_menu": "Cerchiamo di connettori...", + "scenes.apps.calendar.create_calendar_title": "Crea un calendario", + "scenes.apps.calendar.edit_calendar_title": "Modifica il calendario", + "scenes.apps.calendar.export_title": "Esportazione", + "scenes.apps.calendar.export_view_menu": "Esporta la vista...", + "scenes.apps.calendar.ics_download_menu": "Scarica un file ICS", + "scenes.apps.calendar.ics_subscription_menu": "Ottieni un link di abbonamento ICS", + "scenes.apps.calendar.modals.advanced_options": "Opzioni avanzate", + "scenes.apps.calendar.modals.event_title_placeholder": "Titolo", + "scenes.apps.calendar.modals.modify_event_button": "Modifica evento", + "scenes.apps.calendar.modals.part.participants": "Partecipanti", + "scenes.apps.calendar.modals.participants_event": "Partecipanti", + "scenes.apps.calendar.modals.reminders": "Promemoria", + "scenes.apps.calendar.modals.remove_button": "Eliminare", + "scenes.apps.calendar.modals.remove_event_button": "Elimina evento", + "scenes.apps.calendar.modals.remove_event_text": "Eliminare l'evento?", + "scenes.apps.calendar.modals.title_placeholder": "Titolo", + "scenes.apps.calendar.modify_calendar_menu": "Modifica il calendario", + "scenes.apps.calendar.month_option": "Mese", + "scenes.apps.calendar.my_calendar": "Il mio calendario", + "scenes.apps.calendar.my_calendar_label": "Il mio calendario", + "scenes.apps.calendar.my_calendar_menu": "Il mio calendario", + "scenes.apps.calendar.no_calendar_text": "Non hai impostato alcun calendario per questo spazio di lavoro.", + "scenes.apps.calendar.no_connectors_menu_text": "Non disponi di connettori che possono connettersi a un calendario.", + "scenes.apps.calendar.remove_calendar_confirmation": "Eliminare il calendario e i suoi eventi in modo permanente?", + "scenes.apps.calendar.today_menu": "Oggi", + "scenes.apps.calendar.week_option": "Settimana", + "scenes.apps.calendar.workspace": "Spazio di lavoro", + "scenes.apps.calendar.workspace_label": "Questo spazio di lavoro", + "scenes.apps.calendar.workspace_menu": "Spazio di lavoro", + "scenes.apps.drive.add_button": "Aggiungere", + "scenes.apps.drive.message_added_file": "{{$1}} ha inviato {{$2}}.", + "scenes.apps.drive.message_added_mutiple_files": "{{$1}} ha inviato piΓΉ file.", + "scenes.apps.drive.message_added_file_no_name": "{{$1}} ha inviato un file.", + "scenes.apps.drive.choose_folder_button": "Scegli una directory", + "scenes.apps.drive.choose_file_button": "Seleziona un file", + "scenes.apps.drive.create_folder_button": "Creare", + "scenes.apps.drive.download_button": "Scarica", + "scenes.apps.drive.open_link": "Aprire il link in una nuova finestra", + "scenes.apps.drive.files_subtitle": "File", + "scenes.apps.drive.folder_subtitle": "Cartelle", + "scenes.apps.drive.go_out_trash_menu": "Lascia il cestino", + "scenes.apps.drive.go_trash_menu": "Vai nel cestino", + "scenes.apps.drive.import_from_computer_menu": "Caricare dal computer", + "scenes.apps.drive.move_text": "Mossa", + "scenes.apps.drive.new_file_menu": "Nuovo file", + "scenes.apps.drive.new_file_title": "Nuovo file", + "scenes.apps.drive.new_external_storage": "Nuova memoria esterna", + "scenes.apps.drive.new_folder_title": "Nuova cartella", + "scenes.apps.drive.no_file_alert": "Non hai applicazioni che ti consentono di creare un file.", + "scenes.apps.drive.no_storage_app_alert": "Non hai applicazioni che ti consentono di aggiungere spazio di archiviazione esterno.", + "scenes.apps.drive.remove_definitely_menu": "Elimina definitivamente", + "scenes.apps.drive.restore_menu": "Ristabilire", + "scenes.apps.drive.throw_menu": "Invia nel cestino", + "scenes.apps.drive.trash_empty_menu": "Svuota il cestino", + "scenes.apps.drive.unconfigured_tab": "Questa scheda non Γ¨ ancora configurata.", + "scenes.apps.drive.viewer.edit_with_button": "Modifica con {{$1}}", + "scenes.apps.drive.viewer.loading_preview_message": "Caricamento in corso...", + "scenes.apps.drive.viewer.no_preview_message": "Impossibile visualizzare questo tipo di file.", + "scenes.apps.drive.viewer.open_with_button": "Aperta con...", + "scenes.apps.messages.input.placeholder": "Scrivi un messaggio. Usa @ per citare un utente.", + "scenes.apps.messages.input.edited": "Modificato", + "scenes.apps.messages.just_you": "Visibile solo a te", + "scenes.apps.messages.message.new_messages_bar": "Nuovo messaggio", + "scenes.apps.messages.message.cancel_button": "Annulla", + "scenes.apps.messages.message.modify_button": "Modificare", + "scenes.apps.messages.message.pin_button": "Pin messaggio", + "scenes.apps.messages.message.unpin_button": "Sblocca messaggio", + "scenes.apps.messages.message.copy_link": "Copia il link al messaggio", + "scenes.apps.messages.message.pinned": "appuntato", + "scenes.apps.messages.message.remove_button": "Eliminare", + "scenes.apps.messages.message.reply_button": "Rispondere", + "scenes.apps.messages.message.save_button": "Salva", + "scenes.apps.messages.message.show_button": "Schermo", + "scenes.apps.messages.message.show_responses_button": "Visualizza tutte le risposte", + "scenes.apps.messages.message.types.first_channel_message_text": "Questo Γ¨ il primo messaggio del canale", + "scenes.apps.messages.message.types.first_message_text": "Questo Γ¨ il primo messaggio", + "scenes.apps.messages.messageslist.get_writing_user": "Sta scrivendo...", + "scenes.apps.messages.messageslist.get_writing_users": "stanno scrivendo...", + "scenes.apps.messages.messageslist.go_last_message_button": "Vai all'ultimo messaggio", + "scenes.apps.messages.messageslist.go_last_message_button.new_messages": "Nuovo messaggio", + "scenes.error_on_twake": "\"Houston abbiamo un problema\"", + "scenes.help_us": "Tuttavia, se desideri aiutarci a correggere questo errore, inviaci un messaggio di seguito: ", + "scenes.login.verifymail.alert": "Stiamo controllando la tua posta elettronica!", + "scenes.login.verifymail.error_message": "Si Γ¨ verificato un errore", + "scenes.login.verifymail.signin_button": "Accesso", + "scenes.login.verifymail.success": "La tua e-mail Γ¨ stata verificata con successo!", + "scenes.login.verifymail.verification_waiting": "In attesa di verifica...", + "scenes.no_panic": "Niente panico! Basta ricaricare questa pagina per correggere Twake.", + "services.apps.calendar.deadline_icon": "Scadenza", + "services.apps.calendar.event_icon": "Evento", + "services.apps.calendar.move_icon": "Mossa", + "services.apps.calendar.reminder_icon": "Promemoria", + "services.apps.messages.no_app": "Questa applicazione non esiste.", + "services.apps.messages.no_command_possible": "Non possiamo eseguire il comando '{{$1}}' perchΓ© '{{$2}}' non esiste o non consente di creare comandi.", + "services.user.notification_parameters_update_alert": "Le impostazioni di notifica sono state aggiornate.", + "services.user.update_password_alert": "La tua password Γ¨ stata aggiornata.", + "scenes.app.workspaces.components.skip": "Saltare", + "scenes.apps.calendar.unconfigured_tab": "Questa scheda non Γ¨ ancora configurata.", + "scenes.apps.drive.trash": "Spazzatura", + "scenes.apps.drive.top_menu_more": "Di piΓΉ", + "scenes.apps.drive.top_menu_no_items": "{{$1}} elementi", + "scenes.apps.messages.new_thread": "Inizia una nuova discussione", + "scenes.apps.messages.input.send_message": "Invia messaggio", + "scenes.apps.messages.input.emoji": "emoji", + "scenes.apps.messages.input.hide_formatting": "Nascondi formattazione", + "scenes.apps.messages.input.show_formatting": "Mostra formattazione", + "scenes.tell_us": "Per favore dicci cosa stavi facendo a:", + "scenes.apps.drive.viewer.download_desktop": "Scarica Twak Desktop per l'anteprima nell'app", + "scenes.apps.tasks.my_tasks": "I miei compiti", + "scenes.apps.tasks.board.place_holder": "Nome del consiglio", + "scenes.apps.tasks.board.tasks.subtask": "SottoattivitΓ ", + "scenes.apps.tasks.board.tasks.add_subtask": "Aggiungi un'attivitΓ  secondaria", + "scenes.apps.tasks.board.tasks.use_deadline": "Usa scadenza", + "scenes.apps.tasks.board.tasks.use_starttime": "Usa l'ora di inizio", + "scenes.apps.tasks.board.tasks.in_list": "nella lista", + "scenes.apps.tasks.board.starts": "inizia il", + "scenes.apps.tasks.board.ends": "Da fare per il", + "scenes.apps.tasks.board.list_name": "Lista nome", + "scenes.app.popup.sync_calendar": "Sincronizza i tuoi calendari.", + "scenes.apps.parameters.workspace_sections.workspace.logo_company": "Logo dell'azienda", + "scenes.app.popup.workspaceparameter.pages.logo_company_modify_description": "Modifica l'immagine dell'azienda ", + "scenes.app.popup.workspaceparameter.pages.cancel_invitation": "Annulla l'invito", + "scenes.apps.account.account.fullname": "Nome e cognome", + "login.email_login": "E-mail / Login", + "scenes.apps.account.account.password_for_user": "Password per il tuo utente", + "scenes.apps.account.account.send_info": "Invia queste informazioni sulle credenziali al tuo utente.", + "scenes.apps.account.account.save": "Salva account", + "scenes.apps.account.message_temporary": "Un account temporaneo funziona come un normale account Twake, ma crei la password e potrai reimpostarla se necessario.", + "scenes.apps.account.message_user_signin": "Il tuo utente puΓ² accedere in qualsiasi momento utilizzando la stessa e-mail e modificare l'account temporaneo in un account normale.", + "scenes.app.mainview.link_expired": "Questo collegamento pubblico non Γ¨ valido o Γ¨ scaduto.", + "scenes.app.mainview.create_account": "Crea il tuo spazio di lavoro gratuitamente su ", + "scenes.apps.calendar.modals.reminder_add": "Aggiungi un promemoria", + "scenes.apps.parameters.workspace_sections.members.invite_all": "Invita tutti", + "scenes.app.taskpicker.select": "Selezionare", + "components.listmanager.filter": "Filtro", + "scenes.apps.tasks.no_connector": "Nessun connettore", + "components.attachmentpicker.add_attachment": "Aggiungi allegati", + "components.input.copied": "copiato", + "components.drive.new_versions": "Aggiungi una nuova versione", + "components.drive.navigators.directory_not_found": "Directory non trovata.", + "components.drive.right_preview.suppress_link": "Sopprimere il collegamento", + "components.drive.right_preview.create_link": "Crea un link di accesso", + "components.drive.moove_here": "Vieni qui", + "components.drive.modify_uslist": "Modifica elenco utenti", + "components.tagpicker.tag_name": "Nome del tag", + "components.upload.drop_files": "Trascina qui i tuoi file", + "components.workspace.list_manager.no_workspace": "Nessuno spazio di lavoro", + "components.workspace.list_manager.add": "Aggiungi aree di lavoro", + "components.workspace.list_manager.current_space": "Area di lavoro attuale", + "components.workspace.list_manager.current_company": "Compagnia corrente", + "components.workspace.list_manager.all": "Tutto", + "components.workspace.calendar.invalid": "Non valido", + "components.searchpopup.enter_text": "Inserisci del testo per cercare Twak.", + "components.searchpopup.hide_filters": "nascondi filtri", + "components.searchpopup.show_filters": "mostra filtri", + "components.searchpopup.load_more": "Carica piΓΉ risultati", + "general.more": "Di piΓΉ", + "scenes.apps.board.archived_tasks": "AttivitΓ  archiviate ({{$1}})", + "scenes.apps.board.active_tasks": "Compiti attivi", + "scenes.apps.board.kanban": "Kanban", + "scenes.apps.board.display_as": "Mostra come", + "scenes.apps.board.new_task": "+ Nuova attivitΓ ", + "scenes.apps.board.all_boards": "Tutte le schede", + "components.userlistmanager.no_users": "Nessun utente.", + "scenes.apps.drive.used": "usato in questa cartella", + "components.reminder.notification": "Notifica", + "components.reminder.minutes_bef": "minuti prima", + "components.reminder.hours_bef": "ore prima", + "components.reminder.days_bef": "giorni prima", + "components.reminder.weeks_bef": "settimane prima", + "components.reminder.by_email": "E-mail", + "scenes.apps.calendar.reminders": "promemoria", + "scenes.apps.calendar.video_link": "Clicca per aprire il link", + "scenes.app.mainview.discussion": "Discussione", + "components.tagpicker.notag": "Nessun tag", + "scenes.apps.tasks.modals.attachments": "Allegati", + "components.calendar.calendarselector.from": "A partire dal", + "scenes.apps.drive.move_text2": "Mossa", + "components.attachmentpicker.from_computer": "Dal tuo dispositivo", + "components.attachmentpicker.from_twake": "Dai documenti Twak", + "components.attachmentpicker.file": "File", + "components.attachmentpicker.remove_attach": "Rimuovi allegato", + "scenes.apps.drive.remove_attachs": "Rimuovi allegati", + "components.drive.elements.see": "Vedere", + "components.drive.elements.current_name": "Nome corrente: ", + "scenes.app.popup.createcompany.try_again": "Per favore riprova.", + "scenes.app.popup.workspace.edit_temp": "Modifica account temporaneo", + "scenes.app.popup.workspace.create_temp": "Crea un account temporaneo", + "scenes.apps.tasks.active_tasks": "compiti attivi", + "scenes.apps.drive.right_preview.versions": "versioni", + "scenes.app.popup.appsparameters.pages.apps_connectors_small_text": "Gestisci le tue applicazioni e i tuoi connettori.", + "scenes.app.popup.appsparameters.pages.icon": "Icona", + "scenes.app.popup.appsparameters.pages.title_informations": "Informazioni di base", + "scenes.app.popup.appsparameters.pages.subtitle_informations": "Informazioni relative alla gestione delle applicazioni", + "scenes.app.popup.appsparameters.pages.smalltext_user_id": "ID utente corrente", + "scenes.app.popup.appsparameters.pages.smalltext_workspace_id": "ID area di lavoro corrente", + "scenes.app.popup.appsparameters.pages.smalltext_group_id": "ID gruppo corrente", + "scenes.app.mainview.channel_description": "Descrivi il canale", + "scenes.client.channelbar.channeltemplateeditor.checkbox": "Invita automaticamente tutti gli utenti dell'area di lavoro a questo canale", + "scenes.client.channelbar.channelmemberslist.title": "Utenti in {{$1}}", + "scenes.client.channelbar.channelmemberslist.loader": "Carica di piΓΉ", + "scenes.client.channelbar.channelmemberslist.autocomplete": "Cerca utenti", + "scenes.client.channelbar.channelmemberslist.menu.option_2": "Rimuovi dal canale", + "components.leftbar.channel.workspaceschannels.menu.option_1": "Crea un canale", + "components.leftbar.channel.workspaceschannels.menu.option_2": "Unisciti a un canale", + "components.channelworkspacelist.title": "Canali", + "components.notifications.hidden_notifications_button.children": "Nuovo messaggio", + "components.newversion.new_version_component.row.part_1": "Stai utilizzando una versione Twake obsoleta", + "scenes.apps.messages.message.activity_message.a_created_channel_connector": "{{$1}} ha aggiunto un nuovo connettore {{$2}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_connector": "{{$1}} ha rimosso un connettore {{$2}}", + "components.alert.leave_private_channel.title": "Sei sicuro di voler lasciare il canale?", + "components.alert.leave_private_channel.description": "Non potrai piΓΉ unirti a questo canale privato a meno che qualcuno non ti inviti.", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.tag": "Non sei un membro", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.loader": "Carica di piΓΉ", + "general.verify": "Verificare", + "components.unverified_account.typography_text_danger": "Si prega di verificare il tuo account entro {{$1}} giorni. In caso contrario, il tuo account verrΓ  bloccato dopo 7 giorni e cancellato definitivamente dopo 30 giorni. Puoi verificare il tuo account attraverso l'email di verifica.", + "components.blocked_account.trial_period_over": "Il tuo periodo di prova Γ¨ terminato. Per sbloccare il tuo account e ottenere l'accesso a tutte le funzionalitΓ , verifica il tuo account tramite e-mail di conferma", + "components.add_mails_workspace.button": "Inizia a usare Twake", + "components.add_mails_workspace.title_1": "Aggiungi alcuni utenti", + "components.add_mails_workspace.title_2": "Twake Γ¨ uno strumento di collaborazione in team, quindi invita alcuni utenti a testare uno spazio di lavoro che abbiamo creato per te.", + "components.add_mails_workspace.text_area_placeholder": "Inserisci le email dei tuoi utenti*", + "components.verify_mail.title_2": "Ora sei un utente ufficiale di Twake!", + "components.verify_mail.button": "Aggiungi utente", + "components.verify_mail.text": "Prima di tutto, devi verificare il tuo indirizzo email. Abbiamo inviato un link di verifica a", + "components.verify_mail.paragraph": "Puoi farlo in seguito, se lo desideri, ma gli account non verificati hanno accesso solo a una versione limitata di Twake", + "services.console_services.toaster.add_emails_error": "Errore durante l'aggiunta di email", + "services.console_services.toaster.add_email_error_message": "Errore durante l'aggiunta di {{$1}}", + "services.console_services.toaster.success_verify_email": "È stato inviato un collegamento di verifica al tuo account di posta elettronica", + "scenes.app.popup.workspaceparameter.edit_from_console": "Vedi in Console", + "services.console_services.toaster.success_invite_emails": "Utenti {{$1}} aggiunti con successo", + "scenes.client.channels_bar.modals.guest_management.title": "Gestisci gli ospiti in {{$1}}", + "scenes.client.channels_bar.modals.guest_management.input_placeholder": "Cerca ospiti o email in attesa", + "scenes.client.channels_bar.modals.guest_management.tips": "Inizia ad aggiungere o cercare e-mail utilizzando l'input sopra", + "scenes.client.channels_bar.modals.parts.channel_member_row.label.pending_email": "Posta inviata", + "general.user.role.company.admin": "amministratore dell'azienda", + "general.user.role.company.member": "Membro", + "general.user.role.company.guest": "Ospite", + "general.user.deleted": "Account cancellato", + "components.richtexteditor.toolbar.bold": "Grassetto", + "components.richtexteditor.toolbar.underline": "Sottolineare", + "components.richtexteditor.toolbar.italic": "Corsivo", + "components.richtexteditor.toolbar.strikethrough": "barrato", + "components.richtexteditor.toolbar.unordered-list": "Elenco puntato", + "components.richtexteditor.toolbar.ordered-list": "Lista ordinata", + "components.richtexteditor.toolbar.blockquote": "citazione", + "components.richtexteditor.toolbar.code-block": "Blocco codice", + "components.locked_features.locked_history_banner.title": "Hai appena raggiunto il limite di messaggi", + "components.locked_features.locked_history_banner.description": "La tua azienda ha molti messaggi! Esegui l'upgrade ora per accedere a tutta la cronologia dei tuoi messaggi.", + "components.locked_features.locked_history_banner.button": "Scopri di piΓΉ", + "components.locked_features.locked_guests_popup.title": "La funzione Ospiti Γ¨ bloccata", + "components.locked_features.locked_guests_popup.subtitle": "Questa funzione non Γ¨ disponibile nella versione gratuita di Twake", + "components.locked_features.locked_guests_popup.description": "Ops!! Sembra che tu voglia invitare utenti esterni nel tuo spazio di lavoro. Potresti prendere in considerazione l'upgrade del tuo piano se desideri collaborare con ospiti e partner esterni. Esplora le nostre opzioni di prezzo e seleziona l'opzione migliore per le esigenze di collaborazione del tuo team.", + "components.locked_features.locked_guests_popup.learn_more_button": "Scopri di piΓΉ", + "components.locked_features.locked_guests_popup.skip_for_now_button": "Salta per ora", + "components.locked_features.locked_guests_popup.or": "o", + "components.on_boarding.company_billing_banner.admin_or_owner_text": "Si Γ¨ verificato un problema con l'abbonamento aziendale. Per favore, dai un'occhiata al tuo", + "components.on_boarding.company_billing_banner.guest_or_member_text": "Si Γ¨ verificato un problema con l'abbonamento aziendale. Si prega di contattare il proprietario o l'amministratore dell'azienda!", + "components.on_boarding.company_billing_banner.link": "piano di abbonamento aziendale", + "components.on_boarding.popups.blocked_company.title": "La tua azienda Γ¨ bloccata a causa di un problema di pagamento", + "components.on_boarding.popups.blocked_company.description": "Il tuo abbonamento a Twake Γ¨ scaduto. Contatta il proprietario o l'amministratore della tua azienda per rinnovarla ed essere in grado di comunicare nuovamente con il tuo team!", + "components.on_boarding.popups.blocked_company.learn_more_text": "Vuoi saperne di piΓΉ sul piano di abbonamento delle aziende?", + "scenes.apps.tasks.select_user_button": "Visualizza le attivitΓ  di un altro utente", + "scenes.apps.messages.input.attach_file.from_computer": "Dal computer", + "scenes.app.popup.workspaceparameter.pages.table_title": "Nome", + "scenes.client.main_view.main_header.search_input": "Ricerca", + "scenes.apps.drive.new_link_title": "Nuovo collegamento", + "scenes.apps.drive.default_link_name": "Senza titolo", + "components.emoji_picker.input_search_placeholder": "Ricerca", + "services.apps.messages.message_editor_service.upload_error_toaster": "{{$1}} - Non puoi aggiungere piΓΉ di {{$2}} file in un messaggio", + "scenes.apps.messages.message.parts.deleted_content.text.current_user": "Hai cancellato questo messaggio", + "scenes.apps.messages.message.parts.deleted_content.text": "{{$1}} ha cancellato il suo messaggio", + "components.member.user_parts.and_more_user_text": " e {{$1}} piΓΉ utenti", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_link": "Crea un canale privato", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_text": " invece", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_input_placeholder": "Non puoi aggiungere piΓΉ di 10 utenti", + "general.uploading": "Caricamento", + "components.upload.drop_files.toaster.error": "Non puoi caricare piΓΉ di {{$1}} file", + "components.emoji_picker.categories.frequently_used": "Usato frequentemente", + "components.emoji_picker.categories.smileys_and_people": "Faccine e persone", + "components.emoji_picker.categories.animals_and_nature": "Animali e natura", + "components.emoji_picker.categories.food_and_drink": "Cibo bevanda", + "components.emoji_picker.categories.activity": "AttivitΓ ", + "components.emoji_picker.categories.travel_and_places": "Viaggi e luoghi", + "components.emoji_picker.categories.objects": "oggetti", + "components.emoji_picker.categories.symbols": "Simboli", + "components.emoji_picker.categories.flags": "bandiere", + "components.emoji_picker.categories.search_result": "risultati di ricerca", + "components.emoji_picker.categories.not_found": "Nessun emoji trovato", + "scenes.app.popup.workspaceparameter.pages.workspace_partner_tabs.members.table.tags": "Ruolo", + "general.email": "E-mail", + "components.locked_features.locked_workspace_popup.title": "Non puoi creare piΓΉ spazi di lavoro", + "components.locked_features.locked_workspace_popup.subtitle": "Nella versione gratuita, puoi avere un solo spazio di lavoro nella tua azienda.", + "components.locked_features.locked_workspace_popup.text": "Ops!! Vuoi creare un nuovo spazio di lavoro nella tua azienda? Potresti prendere in considerazione l'aggiornamento del tuo piano. Esplora le nostre opzioni di prezzo e seleziona la scelta migliore per le esigenze di collaborazione del tuo team.", + "components.locked_features.locked_only_office_popup.title": "Non puoi modificare questo file", + "components.locked_features.locked_only_office_popup.subtitle": "Nella versione gratuita, non puoi usare solooffice.", + "scenes.app.integrations_parameters.company_application_popup.tag": "Installato", + "scenes.app.integrations_parameters.company_application_popup.btn": "Installare", + "scenes.app.integrations_parameters.company_application_popup.tab_btn_info": "Informazioni", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.description_item": "Descrizione", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.website_item": "Sito web", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.created_item": "Data di creazione", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.version_item": "Versione", + "scenes.app.integrations_parameters.company_applications_table.more_menu.show_application": "Spettacolo", + "scenes.app.integrations_parameters.company_applications_table.more_menu.remove_application": "Rimuovere dall'azienda", + "scenes.app.integrations_parameters.company_applications_table.name": "Nome", + "scenes.app.integrations_parameters.company_applications_table.title": "Installato nella tua azienda", + "app.state.recoil.hooks.use_current_company_applications.toaster_delete": "Eliminato con successo {{$1}} dalla tua azienda", + "app.state.recoil.hooks.use_current_company_applications.toaster_add": "Aggiunto con successo {{$1}} nella tua azienda", + "scenes.apps.messages.input.replied_to": "risposto a ", + "scenes.join.loading": "Caricamento in corso…", + "\"": "\"", + "login.create_account": "Creare un account", + "login.login_error": "Errore durante l'accesso", + "'": "'", + "scenes.app.workspaces.welcome_page.no_workspace_subtitle": "Nessuno ti ha ancora invitato in uno spazio di lavoro.", + "components.rich_text_editor.plugins.suggestions.default_message.no_user_found": "Nessun utente trovato", + "components.rich_text_editor.plugins.suggestions.default_message.no_emoji_found": "Nessuna emoji trovata", + "components.rich_text_editor.plugins.suggestions.default_message.no_command_found": "Nessun comando trovato", + "scenes.apps.messages.message.types.no_message_in_thread": "Nessuno ha ancora risposto.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.label": "Area di lavoro predefinita", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.description": "Invita automaticamente tutti gli utenti dello spazio di lavoro a questo canale", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.title": "Stai per eliminare {{$1}}", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.alert_total_members": "Hai ancora {{$1}} membri in {{$2}}. È necessario rimuovere tutti i membri per poter eliminare questo spazio di lavoro.", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.checkbox": "Comprendo che tutti i messaggi e i file del mio spazio di lavoro verranno eliminati.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.max_size": "La dimensione massima del logo Γ¨ 5mb", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.bad_format": "Formato non valido, sono consentiti solo png, gif e jpg", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.unknown": "Errore sconosciuto", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.prefix": "Errore", + "scenes.app.channelsbar.currentuser.reset": "Ripristina", + "components.rich_text_editor.plugins.suggestions.default_message.display_results": "Scrivi almeno tre lettere per visualizzare gli utenti", + "scenes.app.messages.input.parts.is_writing.message.user_is_writing": "{{$1}} sta scrivendo...", + "scenes.app.messages.input.parts.is_writing.message.users_and_more_are_writing": "{{$1}}, {{$2}} e {{$3}} altri utenti stanno scrivendo...", + "scenes.app.messages.input.parts.is_writing.message.users_are_writing": "{{$1}} e {{$2}} stanno scrivendo...", + "components.locked_features_components.locked_invite_alert.message_part_1": "La tua azienda ha raggiunto il limite massimo di membri {{$1}}. Per favore ", + "components.locked_features_components.locked_invite_alert.message_link": "migliora la tua azienda", + "components.locked_features_components.locked_invite_alert.message_part_2": " per invitare piΓΉ membri.", + "components.locked_features_components.locked_invite_alert.message_magic_link": " contatta il proprietario o l'amministratore della tua azienda.", + "views.client.popup.workspace_parameter.pages.workspace_members.link_to_console": "Vedi tutti i membri della mia azienda sulla console", + "scenes.app.popup.appsparameters.pages.amazing_app_description": "Descrivi la tua candidatura in poche parole", + "scenes.app.popup.appsparameters.pages.application_creator.title": "Nuova integrazione", + "scenes.app.popup.appsparameters.pages.application_creator.checkbox": "Comprendo che il proprietario e gli amministratori di questa azienda potranno modificare e pubblicare questa applicazione.", + "twake.application.access.title": "Seleziona gli ambiti giusti per la tua applicazione.", + "scenes.app.integrations_parameters.company_applications_table.more_menu.developer_settings": "Impostazioni dello sviluppatore", + "twake.application.access.no_default_scopes_available'": "Questa integrazione non ha alcun accesso {{$1}}", + "scenes.app.popup.appsparameters.pages.application_editor.help_link": "la documentazione dell'API Twake", + "scenes.app.popup.appsparameters.pages.application_editor.help_text": "Se non sai come riempirli, vai a ", + "scenes.app.popup.appsparameters.pages.app.private_key": "Chiave privata", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed": "Applicazione rimossa con successo {{$1}} !", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed_error": "Errore durante la rimozione dell'applicazione {{$1}} !", + "scenes.app.popup.appsparameters.pages.application_editor.application_published": "Applicazione {{$1}} riuscita!", + "scenes.app.integrations_parameters.add_application": "Nuova integrazione", + "components.rich_text_editor.plugins.suggestions.loading": "Alla ricerca di piΓΉ", + "components.open_desktop_popup.subtitle": "aperto nell'app Twake", + "components.open_desktop_popup.open_here_link": "Apri qui invece", + "molecules.download_banner.title": "Ottieni il massimo da Twake, scarica subito l'app desktop", + "molecules.download_banner.download_button": "Scarica l'app desktop", + "scenes.app.channelsbar.channel_copy_link": "Copia il link del canale", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.success.update": "Aggiornato con successo", + "components.searchpopup.no_results_for": "Non ci sono risultati per", + "components.searchpopup.try_new_search": "Prova una nuova ricerca", + "components.searchpopup.chats": "Chat", + "components.searchpopup.all": "Tutti", + "components.searchpopup.media": "Media", + "components.searchpopup.files": "File", + "components.searchpopup.recent_chats": "Chat recenti", + "components.searchpopup.recent_media": "Media recenti", + "components.searchpopup.recent_files": "File recenti", + "components.searchpopup.recent_channels_and_contacts": "Canali e contatti recenti", + "components.searchpopup.header_title": "Cerca", + "components.searchpopup.scope.company": "in tutta l'azienda", + "components.searchpopup.scope.channel": "in questo canale", + "components.searchpopup.channels": "Canali", + "components.searchpopup.messages": "Messaggi", + "scenes.client.join_private_channel.info": "Contenuto di questo canale Γ¨ limitato o non esiste. Contatta un membro di questo canale per essere invitato.", + "scenes.client.join_public_channel": "Unisciti a questo canale", + "scenes.client.join_public_channel.info": "Non sei un membro di questo canale diretto. Fare clic su questo pulsante per avviare la discussione ora.", + "general.yes": "SΓ¬", + "components.searchpopup.start_search": "Inserisci alcune parole chiave per iniziare la ricerca.", + "components.searchpopup.see_more": "Scopri di piΓΉ", + "scenes.client.channelbar.channelmemberslist.search_invite": "Cerca e invita gli utenti a questo canale", + "scenes.client.channelbar.channelmemberslist.search_invite_notice": "Non ci sono molti membri in questo canale. Cerca e invita subito gli utenti tramite e-mail o nome.", + "scenes.client.channelbar.channelmemberslist.invite_email_button": "Aggiungi al canale solo come ospite", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace": "Aggiungi al canale e all'area di lavoro come membro", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace_confirm": "Invitare {{$1}} all'area di lavoro come membro?", + "scenes.client.channelbar.channelmemberslist.search_invite_type_email": "Digita un indirizzo valido per invitare via email.", + "scenes.client.channelbar.channelmemberslist.pending_section": "Utenti in attesa di invito", + "scenes.client.channelbar.channelmemberslist.members_section": "Utenti in questo canale", + "scenes.client.channelbar.channelmemberslist.not_members_section": "Utenti non presenti in questo canale", + "general.no": "No", + "components.open_desktop_popup.open_here_link_forever": "Non provare mai piΓΉ ad aprire l'app", + "components.channel_attachement_list.medias": "Media", + "components.channel_attachement_list.files": "File", + "components.channel_attachement_list.title": "Media e documenti", + "components.channel_attachement_list.nothing_found": "Non c'Γ¨ ancora nulla qui", + "molecules.message_quote.deleted": "Questo messaggio Γ¨ stato eliminato", + "scenes.apps.messages.jump": "Vai al messaggio", + "components.channel_attachement_list.open": "Apri galleria", + "scenes.apps.account.on_console": "Per modificare le preferenze del tuo account globale, fai clic su Vai alla console.", + "scenes.apps.account.assistant.description": "L'assistente Twake Γ¨ in grado di dare un senso al tuo lavoro quotidiano su Twake e fornire scorciatoie e azioni intelligenti durante la tua giornata. L'assistente fa parte dell'iniziativa Work@Home https://workathome.linagora.com/ ed Γ¨ attualmente in fase di sperimentazione solo in azienda Linagora ed Γ¨ in fase di apprendimento. Significa che invieremo i dati sull'utilizzo di Twake per addestrare la nostra futura funzione di assistente.", + "scenes.apps.account.assistant.share.nothing": "Non condividere nulla con l'assistente (disabilita assistente)", + "scenes.apps.account.assistant.share.all": "Condividi tutto, inclusi messaggi e contenuti di file", + "scenes.apps.account.assistant.share.metadata": "Condividi i metadati ma non i contenuti", + "scenes.apps.account.assistant.success": "Le tue preferenze sono state aggiornate con successo.", + "scenes.apps.account.assistant.title": "Assistente", + "components.message_seen_by.title": "Utenti che hanno visto il messaggio", + "components.message_seen_by.none_seen_it": "Nessuno ha ancora visto il messaggio", + "components.message_seen_by.btn": "Informazione", + "molecules.quoted_content.attachements": "{{$1}} allegati", + "scenes.apps.messages.message.user_deactivated": "Stai visualizzando gli archivi di un account disattivato", + "general.user.deactivated": "L'utente non Γ¨ piΓΉ in questa azienda", + "general.user.connected": "Online", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_day": "1 giorno", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_hour": "1 ora", + "scenes.app.popup.userparameter.pages.email_notif_delay_never": "Mai", + "scenes.app.popup.userparameter.pages.email_notif_delay_quarter_hour": "15 minuti", + "scenes.app.popup.userparameter.pages.notification_sound.defaut": "Predefinito", + "scenes.app.popup.userparameter.pages.notification_sound.none": "Nessuno", + "scenes.client.channelbar.readonly_channel.checkbox": "Limita l'abilitΓ  di scrittura", + "scenes.apps.messages.message.forward": "Inoltrare", + "scenes.apps.messages.message.forward.title": "Inoltrare messaggio", + "scenes.apps.messages.message.forward.comment": "Aggiungi un messaggio", + "scenes.apps.messages.message.forward.confirm": "Invia a {{$1}} canale/i", + "scenes.apps.messages.message.forward.send": "Messaggio inoltrato", + "components.channelselector.confirm": "Seleziona ${{1}} canale/i", + "components.channelselector.search": "Cerca canali e discussioni", + "components.channelselector.title": "Seleziona i canali", + "scenes.app.channelsbar.channel_access": "Accesso al canale", + "scenes.app.channelsbar.channel_access.save": "Salva le impostazioni di accesso", + "scenes.app.channelsbar.channel_access.readonly": "Canale di sola lettura", + "scenes.app.channelsbar.channel_access.readonly.info": "Limita la scrittura a moderatori, amministratori e proprietari.", + "scenes.app.channelsbar.channel_access.visibility": "VisibilitΓ  pubblica", + "scenes.app.channelsbar.channel_access.visibility.info": "Chiunque tranne gli ospiti dell'azienda puΓ² partecipare.", + "scenes.app.channelsbar.channel_access.default": "Partecipazione automatica", + "scenes.app.channelsbar.channel_access.default.info": "I nuovi membri verranno aggiunti qui automaticamente.", + "scenes.app.channelsbar.channel_information": "Modifica le informazioni sul canale", + "scenes.app.channelsbar.channel_information.logo.add": "Carica l'immagine", + "scenes.app.channelsbar.channel_information.logo.remove": "Rimuovere l'immagine", + "scenes.app.channelsbar.channel_information.name": "Nome del canale", + "scenes.app.channelsbar.channel_information.description": "Descrizione del canale", + "scenes.app.channelsbar.channel_information.description.placeholder": "Descrizione del canale, puoi usare il markdown.", + "scenes.app.channelsbar.channel_information.group": "Gruppo di canali", + "scenes.app.channelsbar.channel_information.group.none": "Non selezionato", + "scenes.app.channelsbar.channel_information.group.new": "Crea un nuovo gruppo", + "scenes.app.channelsbar.channel_information.group.save": "Imposta il gruppo di canali su {{$1}}", + "scenes.app.channelsbar.channel_information.group.save_none": "Non imposta il gruppo di canali", + "scenes.app.channelsbar.channel_information.save": "Salva informazioni", + "components.invitation.reached_limit.text": "hai raggiunto il numero massimo di utenti all'interno della tua azienda. Aumenta la tua iscrizione o aggiungi questi utenti come ospiti", + "components.invitation.invitation_input_list.placeholder": "Inizia a digitare un'e-mail", + "components.invitation.invitation_sent.button": "Invia piΓΉ inviti", + "scenes.client.channelbar.channelmemberslist.invite_to_workspace": "Invita {{$1}} nello spazio di lavoro ➑", + "components.invitation.allow_anyone_by_email.text": "Chiunque abbia un'email @{{$1}} puΓ² unirsi a questo spazio di lavoro", + "components.invitation.invitation_channels.button": "Invito ai canali", + "components.invitation.invitation_input_list.add": "Aggiungere", + "components.invitation.invitation_input_list.member": "Membro", + "components.invitation.invitation_input_list.guest": "Ospite", + "components.invitation.invitation_sent.title": "Gli inviti sono stati inviati con successo", + "components.invitation.invitation_sent.subtitle_status": "Puoi monitorare lo stato dell'invito in:", + "components.invitation.invitation_sent.subtitle_location": "Impostazioni dello spazio di lavoro > Gestione dei membri", + "components.invitation.invitation_sent.link": "Controlla lo stato dell'invito", + "components.invitation.invitation_target.invite_as_guests": "Invita tutti come ospiti", + "components.invitation.invitation_target.invite_as_members": "Invita tutti come membri", + "components.invitation.invitation_target.channels_button": "Seleziona i canali", + "components.invitation.workspace_link.text": "Link di invito allo spazio di lavoro", + "components.invitation.workspace_link.button": "Copia", + "components.invitation.title": "Invita persone a {{$1}}", + "components.invitation.bulk_invitation": "Email multiple", + "components.invitation.button": "Invia inviti", + "scenes.client.readonly.info": "Questo canale Γ¨ un feed di sola lettura ma puoi commentare nei thread.", + "scenes.app.channelsbar.channel_information.group.title": "Gruppi di canali", + "components.invitation.custom_role_invitation": "Invito classico", + "components.invitation.link": "Link" +} diff --git a/twake/frontend/public/locales/ja.json b/twake/frontend/public/locales/ja.json new file mode 100644 index 00000000..fb4dc814 --- /dev/null +++ b/twake/frontend/public/locales/ja.json @@ -0,0 +1,1008 @@ +{ + "general.close": "ι–‰γ˜γ‚‹", + "general.save": "γ‚»γƒΌγƒ–", + "general.cancel": "キャンセル", + "general.create": "δ½œζˆγ™γ‚‹", + "general.edit": "編集", + "general.continue": "ζŒηΆšγ™γ‚‹", + "general.back": "バック", + "general.confirm": "η’Ίθͺ", + "general.delete": "ε‰Šι™€", + "components.application.messages": "パッセージ", + "components.drive_dropzone.uploading": "をップロード中...", + "components.user_picker.modal_no_result": "η΅ζžœγŒθ¦‹γ€γ‹γ‚ŠγΎγ›γ‚“", + "scenes.app.header.disconnected": "あγͺγŸγ―εˆ‡ζ–­γ•γ‚Œγ¦γ„γΎγ™", + "scenes.app.header.disconnected.reload": "γƒͺロード", + "scenes.app.header.alt_notifications": "ι€šηŸ₯", + "scenes.apps.calendar.calendar.week_btn": "ι€±ι–“", + "scenes.apps.calendar.calendar.list_btn": "γƒͺγ‚Ήγƒˆ", + "scenes.apps.calendar.event_edition.deadline_tag": "η· γ‚εˆ‡γ‚Š", + "scenes.apps.calendar.event_edition.checkbox_all_day": "δΈ€ζ—₯δΈ­", + "scenes.apps.calendar.event_edition.title_confidentiality": "ε‚εŠ θ€…", + "scenes.apps.calendar.event_view.article_until": "γ€œγΎγ§", + "scenes.apps.calendar.calendar_modal.participants": "ε‚εŠ θ€…", + "scenes.apps.calendar.calendar_modal.placeholder": "名", + "scenes.apps.calendar.left.calendars": "カレンダー", + "scenes.apps.drive.left.search": "ァーチ", + "scenes.apps.drive.navigators.navigator_content.directory_name": "γƒ‡γ‚£γƒ¬γ‚―γƒˆγƒͺ名", + "scenes.apps.drive.navigators.navigator_content.files": "フゑむル", + "scenes.apps.drive.navigators.navigator_labels.title": "ラベル", + "scenes.apps.drive.navigators.new_file.untitled": "η„‘ι‘Œ", + "scenes.apps.drive.navigators.new_file.create_file.type": "γ‚Ώγ‚€γƒ—", + "scenes.apps.drive.navigators.new_file": "新しいフゑむル", + "scenes.apps.drive.preview_bloc.operations_download": "ダウンロード", + "scenes.apps.drive.preview_bloc.error_file": "γƒ•γ‚‘γ‚€γƒ«γŒθ¦‹γ€γ‹γ‚ŠγΎγ›γ‚“", + "scenes.apps.drive.right_preview.operations_restore": "γƒͺγ‚Ήγƒˆγ‚’", + "scenes.apps.drive.right_preview.operations_delete": "γ‚΄γƒŸη±γ«η§»ε‹•", + "scenes.apps.messages.messages": "パッセージ", + "scenes.apps.messages.chatbox.chat.delete_message": "こγγƒ‘γƒƒγ‚»γƒΌγ‚Έγ‚’ε‰Šι™€γ™γ‚‹", + "scenes.apps.messages.chatbox.chat.delete_message_btn": "ε–γ‚Šι™€γγΎγ™", + "scenes.apps.messages.left_bar.stream_modal.placeholder_name": "名", + "scenes.apps.parameters.workspace_sections.workspace": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ή", + "scenes.apps.parameters.workspace_sections.members": "パンバー", + "scenes.apps.parameters.group_sections.workspaces": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ή", + "scenes.apps.parameters.group_sections.apps": "γ‚’γƒ—γƒͺ", + "scenes.apps.account.title": "γ‚’γ‚«γ‚¦γƒ³γƒˆγγƒ‘ラパータ", + "scenes.apps.account.account.menu_title": "γ‚’γ‚«γ‚¦γƒ³γƒˆ", + "scenes.apps.account.languages.menu_title": "言θͺž", + "scenes.apps.account.account.firstname": "γƒ•γ‚‘γƒΌγ‚ΉγƒˆγƒγƒΌγƒ ", + "scenes.apps.account.account.lastname": "θ‹—ε­—", + "scenes.apps.account.account.username": "ユーアー名", + "scenes.apps.account.account.change_username": "ユーアー名を倉更する", + "scenes.apps.account.account.emails": "パール", + "scenes.apps.account.account.main_email": "パむン電子パール", + "scenes.apps.account.account.email_add": "ζ–°γ—γ„ι›»ε­γƒ‘γƒΌγƒ«γ‚’θΏ½εŠ γ™γ‚‹", + "scenes.apps.account.account.email_add_modal.invalid_code": "こγγ‚³γƒΌγƒ‰γ―η„‘εŠΉγ§γ™", + "scenes.apps.account.account.password": "パスワード", + "scenes.apps.account.account.password_modal.old_password": "現在γγƒ‘γ‚Ήγƒ―ード", + "scenes.apps.account.account.password_modal.password": "新しいパスワード", + "scenes.apps.account.account.password_modal.bad_old_password": "ε€γ„γƒ‘γ‚Ήγƒ―γƒΌγƒ‰γŒζ­£γ—γγ‚γ‚ŠγΎγ›γ‚“γ€‚", + "scenes.apps.account.account.password_modal.bad_password": "γƒ‘γ‚Ήγƒ―γƒΌγƒ‰γŒδΈ€θ‡΄γ—γͺγ„γ‹ε°γ•γ™γŽγΎγ™γ€‚ε°‘γͺくとも8ζ–‡ε­—δ»₯上γγƒ‘γ‚Ήγƒ―ードをε…₯εŠ›γ—γ¦γγ γ•γ„γ€‚", + "scenes.apps.account.account.logout": "γƒ­γ‚°γ‚’γ‚¦γƒˆ", + "scenes.apps.account.languages.text": "Twake言θͺžγ‚’倉更します。", + "scenes.apps.account.notifications.title": "ι€šηŸ₯", + "scenes.apps.account.notifications.keywords_subtitle": "キーワード", + "scenes.apps.account.notifications.keywords_placeholder": "dev、wifi、code、...", + "scenes.apps.account.notifications.disturb_option_a": "間にプッシγƒ₯ι€šηŸ₯を送俑しγͺい", + "scenes.apps.account.notifications.disturb_option_b": "そして", + "scenes.apps.account.notifications.disturb_option_c": "οΌˆγƒ­γƒΌγ‚«γƒ«γ‚Ώγ‚€γƒ γ‚ΎγƒΌγƒ³οΌ‰", + "scenes.apps.account.notifications.devices_subtitle": "γƒ‡γƒγ‚€γ‚Ήι€šηŸ₯", + "scenes.apps.account.notifications.devices_option_ever": "常にプッシγƒ₯ι€šηŸ₯を送俑する", + "scenes.apps.account.notifications.devices_option_inactive": "γƒ‡γ‚Ήγ‚―γƒˆγƒƒγƒ—γ§ιžθ‘¨η€Ίγ«γͺっているときにプッシγƒ₯ι€šηŸ₯を送俑する", + "scenes.apps.account.notifications.devices_option_never": "プッシγƒ₯ι€šηŸ₯を送俑しγͺい", + "scenes.apps.account.notifications.privacy_subtitle": "プラむバシー", + "scenes.apps.parameters.group_sections.apps.badge_extension": "ζ‹‘εΌ΅", + "scenes.apps.parameters.workspace_sections.members.members": "パンバー", + "scenes.apps.parameters.workspace_sections.members.pending": "保留中γγƒ‘ンバー", + "scenes.apps.parameters.workspace_sections.members.invite": "新しいパンバーを招待する", + "scenes.apps.parameters.workspace_sections.members.invite_btn": "γƒ‘γƒ³γƒγƒΌγ‚’θΏ½εŠ ", + "scenes.login.footer.go_to_twake": "twakeapp.comにをクセス", + "scenes.login.create_account.title": "ζ–°γ—γ„γ‚’γ‚«γ‚¦γƒ³γƒˆγ‚’δ½œζˆγ™γ‚‹", + "scenes.login.create_account.email": "Eパール", + "scenes.login.create_account.email_used": "こγι›»ε­γƒ‘γƒΌγƒ«γ―ζ—’γ«δ½Ώη”¨γ•γ‚Œγ¦γ„γΎγ™γ€‚", + "scenes.login.create_account.username": "ユーアー名", + "scenes.login.create_account.username_already_exist": "こγγƒ¦γƒΌγ‚ΆγƒΌεγ―ζ—’γ«δ½Ώη”¨γ•γ‚Œγ¦γ„γΎγ™", + "scenes.login.create_account.fill_in_username": "あγͺγŸγ―γƒ¦γƒΌγ‚ΆγƒΌεγ‚’θ¨˜ε…₯γ™γ‚‹εΏ…θ¦γŒγ‚γ‚ŠγΎγ™", + "scenes.login.create_account.fill_in_email": "あγͺγŸγ―γ‚γͺたγι›»ε­γƒ‘γƒΌγƒ«γ«ζ­£γ—γ„ι›»ε­γƒ‘γƒΌγƒ«γ‚’θ¨˜ε…₯γ™γ‚‹εΏ…θ¦γŒγ‚γ‚ŠγΎγ™", + "scenes.login.create_account.too_short_password": "パスワードは8ζ–‡ε­—δ»₯上でγͺγ‘γ‚Œγ°γͺγ‚ŠγΎγ›γ‚“γ€‚", + "scenes.login.create_account.firstname": "γƒ•γ‚‘γƒΌγ‚ΉγƒˆγƒγƒΌγƒ ", + "scenes.login.create_account.lastname": "θ‹—ε­—", + "scenes.login.forgot_password.title": "γƒ‘γ‚Ήγƒ―γƒΌγƒ‰γ‚’γŠεΏ˜γ‚Œγ§γ™γ‹ ?", + "scenes.login.forgot_password.text": "あγͺγŸγ―γ‚γͺたγθΊ«ε…ƒγ‚’η’Ίθͺγ™γ‚‹γŸγ‚γ«ι›»ε­γƒ‘ールで9摁γζ•°ε­—γ‚’ε—γ‘ε–γ‚ŠγΎγ™γ€‚", + "scenes.login.forgot_password.email_to_recover": "ε›žεΎ©γ™γ‚‹γƒ‘γƒΌγƒ«", + "scenes.login.forgot_password.mail_doesnt_exist": "こγι›»ε­γƒ‘γƒΌγƒ«γ―ε­˜εœ¨γ—γΎγ›γ‚“", + "scenes.login.forgot_password.text2": "あγͺたは9ζ–‡ε­—γγ‚³γƒΌγƒ‰γ‚’ε—γ‘ε–γ‚ŠγΎγ™γ€‚ηΆšθ‘Œγ™γ‚‹γ«γ―、欄にε…₯εŠ›γ—γ¦γγ γ•γ„γ€‚", + "scenes.login.forgot_password.invalid_code": "こγγ‚³γƒΌγƒ‰γ―η„‘εŠΉγ§γ™γ€‚", + "scenes.login.forgot_password.text3": "あγͺたγγ‚’γ‚«γ‚¦γƒ³γƒˆγζ–°γ—いパスワードをε…₯εŠ›γ—γ¦γγ γ•γ„γ€‚", + "scenes.login.forgot_password.password": "パスワード", + "scenes.login.forgot_password.password2": "パスワードをθͺθ¨Όγ™γ‚‹", + "scenes.login.forgot_password.password_dont_match": "γƒ‘γ‚Ήγƒ―γƒΌγƒ‰γŒδΈ€θ‡΄γ—γͺγ„γ‹ε°γ•γ™γŽγΎγ™γ€‚ε°‘γͺくとも8ζ–‡ε­—δ»₯上γγƒ‘γ‚Ήγƒ―ードをε…₯εŠ›γ—γ¦γγ γ•γ„γ€‚", + "scenes.login.home.title": "Twakeにァむンむンする", + "scenes.login.home.email": "電子パむル", + "scenes.login.home.unable_to_connect": "η„‘εŠΉγͺ資格情報", + "scenes.login.home.password": "パスワード", + "scenes.login.home.login_btn": "ログむン", + "scenes.login.home.lost_password": "γƒ‘γ‚Ήγƒ―γƒΌγƒ‰γ‚’γŠεΏ˜γ‚Œγ§γ™γ‹", + "scenes.login.home.create_account": "γ‚’γ‚«γ‚¦γƒ³γƒˆγ‚’δ½œζˆγ™γ‚‹", + "scenes.app.popup.appsparameters.pages.icon": "をむコン", + "scenes.apps.account.notifications.mail_subtitle": "ι›»ε­γƒ‘γƒΌγƒ«ι€šηŸ₯", + "scenes.app.popup.appsparameters.pages.app_privileges_information": "γ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γŒη·¨ι›†γŠγ‚ˆγ³θͺ­γΏε–γ‚Šγ§γγ‚‹γ‚‚γγ‚’εšηΎ©γ—ます。", + "scenes.app.popup.appsparameters.pages.message_data_next_event": "欑γγ‚€γƒ™γƒ³γƒˆγ§ι€δΏ‘γ•γ‚Œγ‚‹γƒ‘γƒƒγ‚·γƒ–γƒ‡γƒΌγ‚Ώ", + "scenes.app.popup.appsparameters.pages.parameters_form_small_text": "ζœͺε…¬ι–‹γγ‚’γƒ—γƒͺケーションは、あγͺたγδΌšη€Ύγ§γγΏζ©Ÿθƒ½γ—ます。すべてγTwakeγƒ¦γƒΌγ‚ΆγƒΌγŒεˆ©η”¨γ§γγ‚‹γ‚ˆγ†γ«γ™γ‚‹ε ΄εˆγ―γ€γ“γγ‚ͺγƒ—γ‚·γƒ§γƒ³γ‚’ζœ‰εŠΉγ«γ—γΎγ™γ€‚", + "scenes.app.popup.appsparameters.pages.public_login_label": "ε…¬ι–‹θ­˜εˆ₯子", + "scenes.app.popup.appsparameters.pages.danger_zone_small_text": "ε…¬ι–‹γ•γ‚Œγ¦γ„γ‚‹ε ΄εˆγ€γ“γγ‚’γƒ—γƒͺγ‚’ε‰Šι™€γ™γ‚‹γ“γ¨γ―γ§γγΎγ›γ‚“γ€‚", + "scenes.app.popup.appsparameters.pages.error_app_simple_name_message": "γ‚’γƒ—γƒͺケーションγη°‘η•₯名は、すでにεˆ₯γγ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ§δ½Ώη”¨γ•γ‚Œγ¦γ„γΎγ™γ€‚ε€‰ζ›΄γ—γ¦γγ γ•γ„γ€‚", + "scenes.app.popup.appsparameters.pages.error_app_update_message": "γ‚’γƒ—γƒͺケーションγζ›΄ζ–°δΈ­γ«γ‚¨γƒ©γƒΌγŒη™Ίη”Ÿγ—γΎγ—γŸγ€‚", + "scenes.app.popup.createworkspacepage.placeholder_name": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγεε‰", + "scenes.app.popup.userparameter.pages.frequency_notif_configuration_description": "γƒ’γƒγ‚€γƒ«ι€šηŸ₯γι »εΊ¦γ‚’θ¨­εšγ—ます。", + "scenes.app.popup.userparameter.pages.frequency_notif_subtitle": "ι€šηŸ₯γι »εΊ¦", + "scenes.app.popup.userparameter.pages.keywords_notif_description": "欑γγ‚­γƒΌγƒ―ードを強θͺΏθ‘¨η€Ίγ—ます。", + "scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description": "ι›»ε­γƒ‘γƒΌγƒ«ι€šηŸ₯γι »εΊ¦γ‚’θ¨­εšγ—ます。", + "scenes.app.popup.userparameter.pages.private_message_content.show": "γƒ—γƒ©γ‚€γƒ™γƒΌγƒˆγƒ‘γƒƒγ‚»γƒΌγ‚Έγγ‚³γƒ³γƒ†γƒ³γƒ„を葨瀺する", + "scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description": "ι€šηŸ₯を受け取らγͺγ„ζœŸι–“γ‚’ιΈζŠžγ—γ¦γγ γ•γ„γ€‚", + "scenes.app.popup.userparameter.pages.no_night_disturbing_label": "倜はι‚ͺ魔しγͺいでください", + "scenes.app.popup.workspaceparameter.pages.back_to_search_button": "ζ€œη΄’γ«ζˆ»γ‚‹", + "scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button": "ユーアーを招待する", + "scenes.app.popup.workspaceparameter.pages.company_developped_apps_subtitle": "δΌšη€ΎγŒι–‹η™Ίγ—γŸγ‚’γƒ—γƒͺケーション", + "scenes.app.popup.workspaceparameter.pages.company_identity_title": "会瀾γγ‚’むデンティティ", + "scenes.app.popup.workspaceparameter.pages.company_name_description": "こγδΌšη€Ύγεε‰γ‚’倉更します", + "scenes.app.popup.workspaceparameter.pages.company_name_label": "会瀾名", + "scenes.app.popup.workspaceparameter.pages.configuration_notif": "ζ§‹ζˆ", + "scenes.app.popup.workspaceparameter.pages.configure_button": "ζ§‹ζˆγ€θ¨­εš", + "scenes.app.popup.workspaceparameter.pages.description": "θͺ¬ζ˜Ž", + "scenes.app.popup.workspaceparameter.pages.name_label": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγεε‰", + "scenes.app.popup.workspaceparameter.pages.withdraw_button": "こγγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‹γ‚‰ε‰Šι™€γ—γΎγ™", + "scenes.app.popup.workspaceparameter.pages.worspace_notif": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ή", + "scenes.app.popup.workspaceparameter.pages.write_access_subtitle": "書き込みをクセス", + "scenes.app.popup.workspaceparameter.pages.your_apps_label": "γ‚’γƒ—γƒͺケーション", + "scenes.app.popup.workspaceparameter.payments_subscriptions_title": "支払いとァブスクγƒͺプション", + "scenes.app.workspacesbar.components.change_company_title": "δΌšη€Ύγ‚’ε€‰ζ›΄γ™γ‚‹", + "scenes.app.workspacesbar.components.create_company_menu": "δΌšη€Ύγ‚’δ½œγ‚‹", + "scenes.app.workspacesbar.components.grp_parameters": "{{$1}}θ¨­εš", + "scenes.apps.calendar.connectors_menu": "コネクタ..。", + "scenes.apps.drive.new_file_menu": "新しいフゑむル", + "scenes.apps.drive.new_file_title": "新しいフゑむル", + "scenes.apps.drive.new_external_storage": "ζ–°γ—γ„ε€–ιƒ¨γ‚Ήγƒˆγƒ¬γƒΌγ‚Έ", + "scenes.apps.drive.new_folder_title": "新しいフォルダ", + "scenes.apps.drive.no_file_alert": "γƒ•γ‚‘γ‚€γƒ«γ‚’δ½œζˆγ§γγ‚‹γ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ―γ‚γ‚ŠγΎγ›γ‚“γ€‚", + "scenes.apps.drive.no_storage_app_alert": "ε€–ιƒ¨γ‚Ήγƒˆγƒ¬γƒΌγ‚Έγ‚’θΏ½εŠ γ§γγ‚‹γ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ―γ‚γ‚ŠγΎγ›γ‚“γ€‚", + "scenes.apps.drive.remove_definitely_menu": "εŒε…¨γ«ε‰Šι™€γ™γ‚‹", + "scenes.apps.drive.restore_menu": "ζˆ»γ™", + "scenes.apps.drive.throw_menu": "γ‚΄γƒŸη±γ«ι€γ‚‹", + "scenes.apps.drive.trash_empty_menu": "γ‚΄γƒŸη±γ‚’空にする", + "scenes.apps.drive.unconfigured_tab": "こγγ‚Ώγƒ–γ―γΎγ ζ§‹ζˆγ•γ‚Œγ¦γ„γΎγ›γ‚“γ€‚", + "scenes.apps.messages.message.unpin_button": "パッセージγε›Ίεšγ‚’解陀する", + "scenes.apps.messages.message.copy_link": "パッセージへγγƒͺンクをコピー", + "scenes.no_panic": "ζ…Œγ¦γ‚‹εΏ…θ¦γ―γ‚γ‚ŠγΎγ›γ‚“οΌγ“γγƒšγƒΌγ‚Έγ‚’γƒͺロードするだけでTwakeγ‚’δΏζ­£γ§γγΎγ™γ€‚", + "services.apps.calendar.event_icon": "γ‚€γƒ™γƒ³γƒˆ", + "services.apps.calendar.move_icon": "動く", + "services.apps.calendar.reminder_icon": "γƒͺγƒžγ‚€γƒ³γƒ€γƒΌ", + "services.apps.messages.no_app": "こγγ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ―ε­˜εœ¨γ—γΎγ›γ‚“γ€‚", + "services.apps.messages.no_command_possible": "'{{$2}}'γŒε­˜εœ¨γ—γͺγ„γ‹γ€γ‚³γƒžγƒ³γƒ‰γδ½œζˆγŒθ¨±ε―γ•γ‚Œγ¦γ„γͺγ„γŸγ‚γ€γ‚³γƒžγƒ³γƒ‰ '{{$1}}'γ‚’εŸθ‘Œγ§γγΎγ›γ‚“。", + "services.user.notification_parameters_update_alert": "ι€šηŸ₯θ¨­εšγŒζ›΄ζ–°γ•γ‚ŒγΎγ—γŸγ€‚", + "services.user.update_password_alert": "γƒ‘γ‚Ήγƒ―γƒΌγƒ‰γŒζ›΄ζ–°γ•γ‚ŒγΎγ—γŸγ€‚", + "scenes.app.workspaces.components.skip": "スキップ", + "scenes.apps.calendar.unconfigured_tab": "こγγ‚Ώγƒ–γ―γΎγ ζ§‹ζˆγ•γ‚Œγ¦γ„γΎγ›γ‚“γ€‚", + "scenes.apps.drive.trash": "ごみ", + "components.add_mails_workspace.title_1": "一部γγƒ¦γƒΌγ‚ΆγƒΌγ‚’θΏ½εŠ ", + "components.add_mails_workspace.title_2": "Twakeγ―γƒγƒΌγƒ γ‚³γƒ©γƒœγƒ¬γƒΌγ‚·γƒ§γƒ³γƒ„γƒΌγƒ«γͺγγ§γ€η§γŸγ‘γŒδ½œζˆγ—γŸγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‚’γƒ†γ‚Ήγƒˆγ™γ‚‹γŸγ‚γ«δ½•δΊΊγ‹γγƒ¦γƒΌγ‚ΆγƒΌγ‚’招待します。", + "components.add_mails_workspace.text_area_placeholder": "ユーアーγγƒ‘ールをドレスをε…₯εŠ›γ—γ¦γγ γ•γ„*", + "components.verify_mail.title_1": "γŠγ‚γ§γ¨γ†", + "components.verify_mail.title_2": "あγͺγŸγ―δ»Šγ€Twakeγε…¬εΌγƒ¦γƒΌγ‚ΆγƒΌγ§γ™οΌ", + "services.console_services.toaster.add_emails_error": "パールγθΏ½εŠ δΈ­γ«γ‚¨γƒ©γƒΌγŒη™Ίη”Ÿγ—γΎγ—γŸ", + "services.console_services.toaster.add_email_error_message": "{{$1}}γθΏ½εŠ δΈ­γ«γ‚¨γƒ©γƒΌγŒη™Ίη”Ÿγ—γΎγ—γŸ", + "components.richtexteditor.toolbar.code-block": "コードブロック", + "components.locked_features.locked_history_banner.title": "γƒ‘γƒƒγ‚»γƒΌγ‚ΈεˆΆι™γ«ι”γ—γΎγ—γŸ", + "components.locked_features.locked_history_banner.button": "もっと詳しくηŸ₯γ‚‹", + "components.locked_features.locked_guests_popup.title": "γ‚²γ‚Ήγƒˆζ©Ÿθƒ½γ―γƒ­γƒƒγ‚―γ•γ‚Œγ¦γ„γΎγ™", + "components.locked_features.locked_guests_popup.subtitle": "こγζ©Ÿθƒ½γ―、Twake焑料バージョンでは使用できません", + "components.locked_features.locked_guests_popup.description": "γŠγ£γ¨οΌε€–ιƒ¨γƒ¦γƒΌγ‚ΆγƒΌγ‚’γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ«ζ‹›εΎ…γ—γŸγ„γ‚ˆγ†γ§γ™γ€‚γ‚²γ‚Ήγƒˆγ‚„ε€–ιƒ¨γƒ‘γƒΌγƒˆγƒŠγƒΌγ¨γ‚³γƒ©γƒœγƒ¬γƒΌγ‚·γƒ§γƒ³γ—γŸγ„ε ΄εˆγ―γ€γƒ—γƒ©γƒ³γγ‚’γƒƒγƒ—γ‚°γƒ¬γƒΌγƒ‰γ‚’ζ€œθ¨Žγ™γ‚‹γ“γ¨γ‚’γŠε‹§γ‚γ—γΎγ™γ€‚δΎ‘ζ Όθ¨­εšγ‚ͺプションをθͺΏγΉγ¦γ€γƒγƒΌγƒ γ‚³γƒ©γƒœγƒ¬γƒΌγ‚·γƒ§γƒ³γγƒ‹γƒΌγ‚Ίγ«ζœ€ι©γͺγ‚ͺγƒ—γ‚·γƒ§γƒ³γ‚’ιΈζŠžγ—γ¦γγ γ•γ„γ€‚", + "components.locked_features.locked_guests_popup.learn_more_button": "もっと詳しくηŸ₯γ‚‹", + "components.locked_features.locked_guests_popup.skip_for_now_button": "δ»Šγ™γγ‚Ήγ‚­γƒƒγƒ—", + "components.locked_features.locked_guests_popup.or": "または", + "components.on_boarding.popups.blocked_company.company_selector": "εˆ₯γδΌšη€Ύγ«εˆ‡γ‚Šζ›Ώγˆγ‚‹", + "scenes.apps.tasks.select_user_button": "δ»–γγƒ¦γƒΌγ‚ΆγƒΌγγ‚Ώγ‚Ήγ‚―を葨瀺する", + "scenes.apps.messages.input.attach_file.from_computer": "コンピγƒ₯ーターから", + "scenes.app.popup.workspaceparameter.pages.table_title": "名前", + "scenes.client.main_view.main_header.search_input": "怜紒", + "scenes.apps.drive.new_link_title": "新しいγƒͺンク", + "scenes.apps.drive.default_link_name": "η„‘ι‘Œ", + "components.emoji_picker.input_search_placeholder": "怜紒", + "services.apps.messages.message_editor_service.upload_error_toaster": "{{$1}}-パッセージに{{$2}}γ‚’θΆ…γˆγ‚‹γƒ•γ‚‘γ‚€γƒ«γ‚’θΏ½εŠ γ™γ‚‹γ“γ¨γ―γ§γγΎγ›γ‚“", + "scenes.apps.messages.message.parts.deleted_content.text.current_user": "こγγƒ‘γƒƒγ‚»γƒΌγ‚Έγ‚’ε‰Šι™€γ—γΎγ—γŸ", + "scenes.apps.messages.message.parts.deleted_content.text": "{{$1}}は彼γγƒ‘γƒƒγ‚»γƒΌγ‚Έγ‚’ε‰Šι™€γ—γΎγ—γŸ", + "components.member.user_parts.and_more_user_text": " γŠγ‚ˆγ³{{$1}}γ‚ˆγ‚Šε€šγγγƒ¦γƒΌγ‚ΆγƒΌ", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_link": "γƒ—γƒ©γ‚€γƒ™γƒΌγƒˆγƒγƒ£γƒγƒ«γ‚’δ½œζˆγ™γ‚‹", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_text": " δ»£γ‚γ‚Šγ―", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_input_placeholder": "10δΊΊγ‚’θΆ…γˆγ‚‹γƒ¦γƒΌγ‚ΆγƒΌγ‚’θΏ½εŠ γ™γ‚‹γ“γ¨γ―γ§γγΎγ›γ‚“", + "general.uploading": "をップロード", + "components.upload.drop_files.toaster.error": "{{$1}}γ‚’θΆ…γˆγ‚‹γƒ•γ‚‘γ‚€γƒ«γ‚’γ‚’γƒƒγƒ—γƒ­γƒΌγƒ‰γ™γ‚‹γ“γ¨γ―γ§γγΎγ›γ‚“", + "components.emoji_picker.categories.frequently_used": "γ‚ˆγδ½Ώγ†", + "components.emoji_picker.categories.animals_and_nature": "動物とθ‡ͺη„Ά", + "components.emoji_picker.categories.food_and_drink": "ι£ŸγΉη‰©ι£²γΏη‰©", + "components.locked_features.locked_workspace_popup.text": "γŠγ£γ¨οΌδΌšη€Ύγ«ζ–°γ—γ„γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‚’δ½œζˆγ—γΎγ™γ‹οΌŸθ¨ˆη”»γγ‚’γƒƒγƒ—γ‚°γƒ¬γƒΌγƒ‰γ‚’ζ€œθ¨Žγ™γ‚‹γ“γ¨γ‚’γŠε‹§γ‚γ—γΎγ™γ€‚δΎ‘ζ Όθ¨­εšγ‚ͺプションをθͺΏγΉγ¦γ€γƒγƒΌγƒ γ‚³γƒ©γƒœγƒ¬γƒΌγ‚·γƒ§γƒ³γγƒ‹γƒΌγ‚Ίγ«ζœ€ι©γͺιΈζŠžθ‚’γ‚’ιΈζŠžγ—γ¦γγ γ•γ„γ€‚", + "components.locked_features.locked_only_office_popup.text": "おっと! Twakeγ‹γ‚‰γƒ•γ‚‘γ‚€γƒ«γ‚’η·¨ι›†γ—γŸγ„γ‚ˆγ†γ§γ™γ€‚ Officeγƒ•γ‚‘γ‚€γƒ«γ‚’δΈ­εΏƒγ«ε…±εŒδ½œζ₯­γ‚’θ‘Œγ†ε ΄εˆγ―、プランγγ‚’γƒƒγƒ—γ‚°γƒ¬γƒΌγƒ‰γ‚’ζ€œθ¨Žγ™γ‚‹γ“γ¨γ‚’γŠε‹§γ‚γ—γΎγ™γ€‚δΎ‘ζ Όθ¨­εšγ‚ͺプションをθͺΏγΉγ¦γ€γƒγƒΌγƒ γ‚³γƒ©γƒœγƒ¬γƒΌγ‚·γƒ§γƒ³γγƒ‹γƒΌγ‚Ίγ«ζœ€ι©γͺγ‚ͺγƒ—γ‚·γƒ§γƒ³γ‚’ιΈζŠžγ—γ¦γγ γ•γ„γ€‚", + "components.locked_features.locked_drive_popup.title": "γƒ‰γƒ©γ‚€γƒ–εˆΆι™γ«ι”γ—γΎγ—γŸ", + "components.locked_features.locked_drive_popup.subtitle": "η„‘ζ–™η‰ˆγ§γ―γ€6GBγ—γ‹δΏε­˜γ§γγΎγ›γ‚“γ€‚", + "scenes.app.integrations_parameters.title": "硱合", + "scenes.app.integrations_parameters.company_applications_table.more_menu.show_application": "見せる", + "scenes.app.integrations_parameters.company_applications_table.more_menu.remove_application": "δΌšη€Ύγ‹γ‚‰ε‰Šι™€γ™γ‚‹", + "scenes.app.channelsbar.currentuser.reactivate_notifications": "ε†γ‚’γ‚―γƒ†γ‚£γƒ–εŒ–", + "scenes.join.login_first_button": "ζœ€εˆγ«γƒ­γ‚°γ‚€γƒ³γ™γ‚‹γ‹γ€γ‚’γ‚«γ‚¦γƒ³γƒˆγ‚’δ½œζˆγ—γ¦γγ γ•γ„", + "scenes.join.join_the_team_button": "γƒγƒΌγƒ γ«ε‚εŠ γ™γ‚‹", + "scenes.apps.account.account.save": "γ‚’γ‚«γ‚¦γƒ³γƒˆγ‚’δΏε­˜", + "scenes.apps.tasks.board.list_name": "γƒͺγ‚Ήγƒˆε", + "scenes.apps.calendar.workspace_label": "こγγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ή", + "scenes.app.popup.appsparameters.pages.update_button": "γ‚’γƒƒγƒ—γƒ‡γƒΌγƒˆ", + "scenes.app.popup.workspaceparameter.pages.invited_guest_check_message": "δ½Ώη”¨γ—γŸγƒ¦γƒΌγ‚ΆγƒΌεγΎγŸγ―ι›»ε­γƒ‘γƒΌγƒ«γŒζœ‰εŠΉγ§γ‚γ‚‹γ“γ¨γ‚’η’Ίθͺγ—てください。", + "components.calendar.repetition.occurrence": "η™Ίη”ŸοΌˆsοΌ‰", + "general.retry": "γƒͺγƒˆγƒ©γ‚€", + "scenes.app.popup.appsparameters.pages.show_button": "見せる", + "scenes.apps.calendar.no_connectors_menu_text": "カレンダーにζŽ₯ηΆšγ§γγ‚‹γ‚³γƒγ‚―γ‚ΏγŒγ‚γ‚ŠγΎγ›γ‚“γ€‚", + "components.emoji_picker.categories.smileys_and_people": "SmileysοΌ†People", + "components.locked_features.locked_history_banner.description": "あγͺたγδΌšη€Ύγ«γ―γŸγγ•γ‚“γγƒ‘γƒƒγ‚»γƒΌγ‚ΈγŒγ‚γ‚ŠγΎγ™οΌδ»Šγ™γγ‚’γƒƒγƒ—γ‚°γƒ¬γƒΌγƒ‰γ—γ¦γ€γ™γΉγ¦γγƒ‘ッセージε±₯歴にをクセスしてください。", + "scenes.app.workspaces.create_company.title": "私γδΌšη€Ύγ‚’δ½œγ‚‹", + "scenes.app.popup.workspaceparameter.pages.collaborateurs": "ユーアー", + "scenes.app.popup.appsparameters.pages.app_name_label": "γ‚’γƒ—γƒͺケーション名", + "scenes.apps.messages.message.activity_message.a_removed_b_from_the_channel": "{{$1}}はチャネルから{{$2}}γ‚’ε‰Šι™€γ—γΎγ—γŸ", + "scenes.apps.messages.left_bar.stream.notifications.mentions": "{{$1}}、{{$2}}、{{$3}}", + "components.searchpopup.tags": "γ‚Ώγ‚°", + "scenes.app.workspaces.create_company.group_data.group_main_activity.machinery_automotive": "機撰/θ‡ͺε‹•θ»Š", + "general.help.documentation": "ドキγƒ₯パンテーション", + "general.connexion_status.connected": "あγͺたはγ‚ͺンラむンです", + "general.update": "γ‚’γƒƒγƒ—γƒ‡γƒΌγƒˆ", + "general.send": "パッセージを送る", + "general.unarchive": "をーカむブ解陀", + "scenes.app.popup.appsparameters.pages.app_privileges_label": "γ‚’γƒ—γƒͺケーション特権", + "scenes.login.create_account.step_2_subtitle_b": "あγͺたγι›»θ©±η•ͺε·γ―ιžε…¬ι–‹γγΎγΎγ§γ™γ€‚", + "scenes.login.create_account.step_3_mail_sent": "をクティベーションγƒͺγƒ³γ‚―γ‚’γƒ‘γƒΌγƒ«γ§γŠι€γ‚Šγ—γΎγ—γŸγ€‚", + "general.add": "追加", + "scenes.app.workspaces.create_company.group_data.group_main_activity.bank": "ιŠ€θ‘Œ/保険", + "scenes.app.workspaces.create_company.group_data.group_main_activity.it_telecom": "IT /テレコム", + "scenes.app.workspaces.create_company.group_data.group_main_activity.studies_and_advice": "研穢とをドバむス", + "general.connexion_status.disconnected": "γ‚ͺフラむンです", + "components.locked_features.locked_workspace_popup.subtitle": "η„‘ζ–™η‰ˆγ§γ―γ€δΌšη€Ύγ«γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‚’1γ€γ γ‘ε«γ‚γ‚‹γ“γ¨γŒγ§γγΎγ™γ€‚", + "application.load.longer": "γ‚΅γƒΌγƒγƒΌγŒεΏœη­”γ™γ‚‹γγ«δΊˆζƒ³γ‚ˆγ‚Šγ‚‚ζ™‚ι–“γŒγ‹γ‹γ‚ŠγΎγ™γ€‚γ—γ°γ‚‰γεΎ…γ€γ‹γ€γƒšγƒΌγ‚Έγ‚’γƒͺロードしてください...", + "scenes.app.workspaces.create_company.group_data": "ζ–°γ—γ„γ‚°γƒ«γƒΌγƒ—γ‚’ζ§‹ζˆγ—γΎγ™", + "scenes.app.workspaces.create_company.group_data.group_type": "グループタむプ", + "scenes.app.workspaces.create_company.group_data.group_type.company": "会瀾または会瀾γιƒ¨ι–€", + "scenes.app.workspaces.create_company.group_data.group_type.public_organization": "ε…¬ηš„ζ©Ÿι–’", + "scenes.app.workspaces.create_company.group_data.group_type.society_club_charity": "η€ΎδΌšγ€γ‚―γƒ©γƒ–γΎγŸγ―ζ…ˆε–„ε›£δ½“", + "scenes.app.workspaces.create_company.group_data.group_type.other_group": "δ»–γ", + "scenes.app.workspaces.create_company.group_data.group_size": "グループァむズ", + "scenes.app.workspaces.create_company.group_data.group_size.less_3": "4δΊΊζœͺζΊ€γγƒ¦γƒΌγ‚ΆγƒΌ", + "scenes.app.workspaces.create_company.group_data.group_size.4_10": "4γ€œ10δΊΊγγƒ¦γƒΌγ‚ΆγƒΌ", + "scenes.app.workspaces.create_company.group_data.group_size.10_50": "11γ€œ49δΊΊγγƒ¦γƒΌγ‚ΆγƒΌ", + "scenes.app.workspaces.create_company.group_data.group_size.50_100": "50γ€œ99δΊΊγγƒ¦γƒΌγ‚ΆγƒΌ", + "scenes.app.workspaces.create_company.group_data.group_size.100_500": "100γ€œ499ユーアー", + "scenes.app.workspaces.create_company.group_data.group_size.500_1000": "500γ€œ999ユーアー", + "scenes.app.workspaces.create_company.group_data.group_size.1000_5000": "1000γ€œ4999ユーアー", + "scenes.app.workspaces.create_company.group_data.group_size.5000_more": "5000δΊΊδ»₯上γγƒ¦γƒΌγ‚ΆγƒΌ", + "scenes.app.workspaces.create_company.group_data.group_main_activity": "δΈ»γͺζ΄»ε‹•", + "scenes.app.workspaces.create_company.group_data.group_main_activity.food": "ι£ŸγΉη‰©", + "scenes.app.workspaces.create_company.group_data.group_main_activity.printing_paper": "印刷/η΄™", + "scenes.app.workspaces.create_company.group_data.group_main_activity.construction_building": "ε»Ίθ¨­/建材", + "scenes.app.workspaces.create_company.group_data.group_main_activity.real_estate": "不動産", + "scenes.app.workspaces.create_company.group_data.group_main_activity.chemistry": "εŒ–ε­¦", + "scenes.app.workspaces.create_company.group_data.group_main_activity.trade_commerce_distribution": "θ²Ώζ˜“/商取引/ζ΅ι€š", + "scenes.app.workspaces.create_company.group_data.group_main_activity.publishing_communication_multimedia": "ε‡Ίη‰ˆ/γ‚³γƒŸγƒ₯ニケーション/γƒžγƒ«γƒγƒ‘γƒ‡γ‚£γ‚’", + "scenes.app.workspaces.create_company.group_data.group_main_activity.pharmaceutical_industry": "θ£½θ–¬ζ₯­η•Œ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.business_services": "ビジネスァービス", + "scenes.app.workspaces.create_company.group_data.group_main_activity.entertainment": "γ‚¨γƒ³γ‚ΏγƒΌγƒ†γ‚€γƒ‘γƒ³γƒˆ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.textile_clothing_shoes": "テキスタむル/董鑞/靴", + "scenes.app.workspaces.create_company.group_data.group_main_activity.transport_logistics": "輸送/ロジスティクス", + "scenes.app.workspaces.create_company.group_data.group_main_activity.research": "γƒͺァーチ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.education": "ζ•™θ‚²", + "scenes.app.workspaces.create_company.group_data.group_main_activity.administration": "η‘理", + "scenes.app.workspaces.create_company.invitations.title": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‚’ζ§‹ζˆγ—γΎγ™γ€‚", + "scenes.apps.messages.left_bar.stream.remove_from_favorites": "γŠζ°—γ«ε…₯γ‚Šγ‹γ‚‰ε‰Šι™€", + "scenes.apps.messages.left_bar.stream.notifications": "ι€šηŸ₯...", + "scenes.apps.messages.left_bar.stream.notifications.all": "パッセージ", + "scenes.apps.messages.left_bar.stream.notifications.me": "{{$1}}γγΏ", + "scenes.apps.messages.left_bar.stream.notifications.never": "何もγͺい", + "scenes.apps.account.notifications.sound": "ιŸ³ε£°ι€šηŸ₯", + "scenes.apps.tasks.connectors_menu": "コネクタ..。", + "scenes.apps.tasks.connectors_search_menu": "γ‚³γƒγ‚―γ‚Ώγ‚’ζ€œη΄’...", + "scenes.apps.tasks.no_connectors_menu_text": "カレンダーにζŽ₯ηΆšγ§γγ‚‹γ‚³γƒγ‚―γ‚ΏγŒγ‚γ‚ŠγΎγ›γ‚“γ€‚", + "scenes.apps.tasks.unconfigured_tab": "こγγ‚Ώγƒ–γ―γΎγ ζ§‹ζˆγ•γ‚Œγ¦γ„γΎγ›γ‚“γ€‚", + "scenes.apps.tasks.choose_board_button": "γƒœγƒΌγƒ‰γ‚’ιΈζŠžγ—γ¦γγ γ•γ„", + "scenes.apps.tasks.new_board.title": "ζ–°γ—γ„γƒœγƒΌγƒ‰", + "scenes.apps.tasks.new_board.edit_title": "γƒœγƒΌγƒ‰γ‚’η·¨ι›†", + "scenes.apps.tasks.task_status.todo": "する", + "scenes.apps.tasks.task_status.done": "η΅‚γ‚γ‚Š", + "scenes.apps.tasks.task.description": "θͺ¬ζ˜Ž", + "scenes.apps.tasks.task.assignees": "譲受人", + "scenes.apps.tasks.task.edit.dates": "ζ—₯付", + "scenes.apps.tasks.list_modal.modify_list": "γƒͺγ‚Ήγƒˆγ‚’ε€‰ζ›΄", + "scenes.apps.tasks.list_modal.new_list": "新しいγƒͺγ‚Ήγƒˆ", + "scenes.apps.tasks.list_modal.remove": "γƒͺγ‚Ήγƒˆγ¨γ‚Ώγ‚Ήγ‚―γ‚’ε‰Šι™€γ™γ‚‹", + "scenes.apps.tasks.list_modal.predefined_participants": "事前εšηΎ©γ•γ‚ŒγŸε‚εŠ θ€…", + "scenes.apps.tasks.list_modal.archive_all_tasks": "すべてγγ‚Ώγ‚Ήγ‚―ををーカむブする", + "scenes.apps.tasks.list_modal.remove_archived_tasks": "γ‚’γƒΌγ‚«γ‚€γƒ–γ•γ‚ŒγŸγ‚Ώγ‚Ήγ‚―γ‚’ε‰Šι™€γ™γ‚‹οΌˆ{{$1}}οΌ‰", + "scenes.login.footer.branding": "{{$1}}({{$2}}οΌ‰γƒ—γƒ©γ‚€γƒ™γƒΌγƒˆTwakeァーバーを使用しています。 ", + "scenes.login.create_account.newsletter": "Twakeに閒する情報を受け取る", + "scenes.login.home.subtitle": "γŠδΌšγ„γ§γγ¦ε¬‰γ—γ„γ§γ™", + "scenes.login.create_account.password": "パスワード", + "scenes.login.create_account.step_1_subtitle": "γ“γ‚Œδ»₯上簑単γͺγ“γ¨γ―γ‚γ‚ŠγΎγ›γ‚“β€”εΏ…θ¦γͺγγ―いく぀かγζƒ…報だけです。", + "scenes.login.create_account.step_2_subtitle_a": "δ»–γγƒ¦γƒΌγ‚ΆγƒΌγŒγ‚γͺγŸγ‚’θͺθ­˜γ§γγ‚‹γ‚ˆγ†γ«γ€γƒ•γƒ«γƒγƒΌγƒ γ‚’θΏ½εŠ γ—γΎγ™γ€‚", + "scenes.login.create_account.step_3_subtitle": "ζœ€εΎŒγγ‚Ήγƒ†γƒƒγƒ——あγͺγŸγŒγƒ­γƒœγƒƒγƒˆγ§γ―γͺいことを璺θͺγ™γ‚‹εΏ…θ¦γŒγ‚γ‚ŠγΎγ™οΌ", + "scenes.app.workspaces.create_company.company_name.placeholder": "会瀾名", + "scenes.app.workspaces.create_company.company_name.title_2": "あγͺたγδΌšη€Ύγεε‰γ‚’瀺してください。", + "scenes.app.workspaces.create_company.default_workspace_name": "主要", + "scenes.app.workspaces.create_company.importations.title_1": "γ™γ§γ«γƒ‡γ‚Έγ‚Ώγƒ«γƒ„γƒΌγƒ«γ‚’δ½Ώη”¨γ—γ¦γ„γΎγ™γ‹οΌŸδ»Šγ™γγƒ„γƒΌγƒ«γ‚’γ‚€γƒ³γƒγƒΌγƒˆγΎγŸγ―η΅±εˆγ—γ¦γγ γ•γ„οΌ", + "scenes.app.workspaces.create_company.importations.title_2": "εΏƒι…γ‚γ‚ŠγΎγ›γ‚“γ€‚εΎŒγ§γ“γ‚Œγ‚’θ‘Œγ†γ“γ¨γŒγ§γγΎγ™γ€‚", + "scenes.app.workspaces.create_company.invitations.title_2": "γƒγƒΌγƒ γ«γƒ¦γƒΌγ‚ΆγƒΌγ‚’θΏ½εŠ γ—γΎγ™γ€‚", + "scenes.app.workspaces.welcome_page.add_secondary_emails": "δΊˆε‚™γγƒ‘γƒΌγƒ«γ‚’θΏ½εŠ γ™γ‚‹", + "scenes.app.workspaces.welcome_page.added_to_company": "あγͺγŸγ―γ«ζ‹›εΎ…γ•γ‚ŒγΎγ—γŸ ", + "scenes.app.workspaces.welcome_page.create_my_company": "私γδΌšη€Ύγ‚’δ½œγ‚‹", + "scenes.app.workspaces.welcome_page.may_be_invited_with_secondary_emails": "εˆ₯γγƒ‘γƒΌγƒ«γ‚’γƒ‰γƒ¬γ‚Ήγ‚’δ½Ώη”¨γ—γ¦ζ‹›εΎ…γ•γ‚ŒγΎγ—γŸγ‹οΌŸ", + "scenes.app.workspaces.welcome_page.no_company_subtitle": "ああ、まあ...まだθͺ°γ‚‚あγͺγŸγ‚’γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ«ζ‹›εΎ…γ—γ¦γ„γͺγ„γ‚ˆγ†γ§γ™γ€‚", + "scenes.app.workspaces.welcome_page.ready_to_work": "γ“γ‚Œγ§δ½œζ₯­γ™γ‚‹ζΊ–ε‚™γŒζ•΄γ„γΎγ—γŸγ€‚", + "scenes.app.workspaces.welcome_page.try_again": "ε†θ©¦θ‘Œ", + "scenes.app.workspaces.welcome_page.twake_team": "γƒˆγ‚¦γ‚§γ‚€γ‚―", + "scenes.app.workspaces.welcome_page.welcome_header": "TwakeγΈγ‚ˆγ†γ“γοΌ", + "scenes.app.workspaces.welcome_page.add_secondary_emails_comment": "耇数γι›»ε­γƒ‘γƒΌγƒ«γ‚’γƒ‰γƒ¬γ‚Ήγ‚’γ‚’γ‚«γ‚¦γƒ³γƒˆγ«γƒͺγƒ³γ‚―γ§γγΎγ™γ€‚ι€šηŸ₯γι€δΏ‘γ«δ½Ώη”¨γ•γ‚Œγ‚‹γ‚’γƒ‰γƒ¬γ‚Ήγ―1぀だけです。", + "scenes.app.workspaces.welcome_page.main_mail_title": "パむンをドレス", + "scenes.app.workspaces.welcome_page.other_mail_title": "セカンダγƒͺをドレス", + "scenes.app.workspaces.welcome_page.add_new_email": "ι›»ε­γƒ‘γƒΌγƒ«γ‚’θΏ½εŠ γ™γ‚‹", + "scenes.app.workspaces.welcome_page.code_verification": "ζ€œθ¨Όγ‚³γƒΌγƒ‰", + "scenes.app.workspaces.welcome_page.we_sent_you_mail": "{{$1}}η΅Œη”±γ§η’Ίθͺγ‚³γƒΌγƒ‰γ‚’γŠι€γ‚Šγ—γΎγ—γŸ", + "scenes.login.forgot_password.finished": "γƒ‘γ‚Ήγƒ―γƒΌγƒ‰γ―ζ­£εΈΈγ«ζ›΄ζ–°γ•γ‚ŒγΎγ—γŸγ€‚", + "scenes.apps.account.account.description_main": "パむンをドレスは、TwakeγŒι€šηŸ₯を送俑する場所です。セカンダγƒͺγ‚’γƒ‰γƒ¬γ‚Ήγ‚’δ½Ώη”¨γ™γ‚‹γ¨γ€γγ‚Œγ‚‰γ‚’δ½Ώη”¨γ™γ‚‹γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ«θ‡ͺε‹•ηš„γ«ζ‹›εΎ…γ•γ‚ŒγΎγ™γ€‚", + "scenes.apps.account.account.emails.description": "さまざまγͺ電子パールをドレスをη‘理します。", + "scenes.apps.account.account.password.description": "パスワードを倉更してください。", + "scenes.apps.account.identity.description": "δ»–γTwakeγƒ¦γƒΌγ‚ΆγƒΌγ«θ‘¨η€Ίγ•γ‚Œγ‚‹εε‰γ€εε‰γ€γƒ—γƒ­γƒ•γ‚£γƒΌγƒ«η”»εƒγ‚’ε€‰ζ›΄γ—γΎγ™γ€‚", + "scenes.apps.account.preference": "η’°ε’ƒθ¨­εš", + "general.open": "開ける", + "scenes.apps.account.thumbnail.max_weight": "ζœ€ε€§γ‚΅γ‚€γ‚Ί5MB", + "scenes.apps.account.account.email_add_modal.confirm": "こγγƒ‘ールを璺θͺγ—てください", + "app.name.twake_calendar": "カレンダー", + "app.name.twake_drive": "ドキγƒ₯γƒ‘γƒ³γƒˆ", + "app.name.twake_tasks": "γ‚Ώγ‚Ήγ‚―", + "components.calendar.repetition.everyday": "毎ζ—₯", + "components.calendar.repetition.does_not_repeat": "ηΉ°γ‚ŠθΏ”γ•γͺい", + "components.calendar.repetition.weekly_on": "ζ―Žι€±{{$1}}", + "components.calendar.repetition.monthly_on": "{{$1}} {{$2}}で毎月", + "components.calendar.repetition.annually_on": "毎年{{$1}}", + "components.calendar.repetition.every_weekday": "εΉ³ζ—₯οΌˆζœˆγ€œι‡‘οΌ‰", + "components.calendar.repetition.custom": "γ‚«γ‚Ήγ‚Ώγƒ ...", + "components.calendar.repetition.repeat": "ζ―Žε›žηΉ°γ‚ŠθΏ”γ™", + "components.calendar.repetition.never": "δΈ€εΊ¦γ‚‚γͺい", + "components.calendar.repetition.on": "γ‚ͺン", + "components.calendar.repetition.after": "後", + "components.calendar.repetition.months": "月", + "components.calendar.repetition.years": "εΉ΄", + "components.calendar.repetition.custom_recurrence": "カスタム再発", + "components.calendar.repetition.repeat_on": "ηΉ°γ‚ŠθΏ”γ—γΎγ™", + "scenes.app.channelsbar.currentuser.add_apps": "γ‚’γƒ—γƒͺケーションγζ€œη΄’", + "scenes.app.channelsbar.currentuser.change_my_status": "ステータスを倉更する", + "scenes.app.channelsbar.currentuser.collaborateurs": "ユーアー", + "scenes.app.channelsbar.currentuser.create_workspace_page": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‚’δ½œζˆγ™γ‚‹", + "scenes.app.channelsbar.currentuser.invited_status": "あγͺγŸγ―γ‚²γ‚Ήγƒˆγ§γ™γ€‚", + "scenes.app.channelsbar.currentuser.workspace_info": "グループ{{$2}}γγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ή{{$1}}にいます", + "scenes.app.channelsbar.currentuser.workspace_parameters": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήθ¨­εš", + "scenes.app.channelsbar.currentuser.logout": "γ‚΅γ‚€γƒ³γ‚’γ‚¦γƒˆ", + "scenes.app.channelsbar.currentuser.update": "γ‚’γƒƒγƒ—γƒ‡γƒΌγƒˆ", + "scenes.app.channelsbar.currentuser.disable_notifications": "η„‘εŠΉγ«γ™γ‚‹", + "scenes.app.channelsbar.currentuser.disabling_notifications": "1ζ™‚ι–“η„‘εŠΉγ«γ™γ‚‹", + "scenes.app.channelsbar.currentuser.disabling_notifications_until": "εˆε‰9ζ™‚γΎγ§η„‘εŠΉγ«γ™γ‚‹ζ˜Žζ—₯", + "scenes.app.channelsbar.currentuser.user_parameter": "ι€šηŸ₯θ¨­εš", + "scenes.app.popup.appsparameters.pages.write_privileges_label": "書き込み権限", + "scenes.app.channelsbar.company_invitation_alert_title": "あγͺγŸγ―δΌšη€Ύγ«ζ‹›εΎ…γ•γ‚Œγ¦γ„γΎγ™ ", + "scenes.app.channelsbar.initial_instructions_tutorial": "εγ€εε‰γ€γƒ—γƒ­γƒ•γ‚£γƒΌγƒ«ε†™ηœŸγ‚’ιΈζŠžγ—γΎγ™γ€‚", + "scenes.app.channelsbar.installation_desktop_tutorial": "γƒ‡γ‚Ήγ‚―γƒˆγƒƒγƒ—γ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ‚’γ‚€γƒ³γ‚ΉγƒˆγƒΌγƒ«γ—γΎγ™", + "scenes.app.channelsbar.invitation_collaboraors_tutorial": "γƒ¦γƒΌγ‚ΆγƒΌγ‚’γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ«ζ‹›εΎ…γ—γΎγ™γ€‚", + "scenes.app.channelsbar.public_channel_label": "公葆", + "scenes.app.channelsbar.sending_message_instruction": "γƒ‡γ‚£γ‚Ήγ‚«γƒƒγ‚·γƒ§γƒ³γ§ζœ€εˆγγƒ‘ッセージを送俑する", + "scenes.app.channelsbar.tutorial_alert": "こγγƒ•γƒ¬γƒΌγƒ γ‚’δΊŒεΊ¦γ¨θ‘¨η€Ίγ—γΎγ›γ‚“γ‹οΌŸ", + "scenes.app.channelsbar.welcome": "TwakeγΈγ‚ˆγ†γ“γ", + "scenes.app.channelsbar.welcoming_message_subtitle": "ζ•°ε›žγ‚―γƒͺックするだけでTwakeプロにγͺγ‚ŠγΎγ—γ‚‡γ†οΌ", + "scenes.app.mainview.instruction_current_tab": "左側γγƒγƒ£γƒ³γƒγƒ«γ‚’ιΈζŠžγ™γ‚‹γ“γ¨γ‹γ‚‰ε§‹γ‚γΎγ™γ€‚", + "scenes.app.mainview.tabs.no_connected_connectors_for_channel": "チャネルにζŽ₯ηΆšγ§γγ‚‹γ‚³γƒγ‚―γ‚ΏγŒγ‚γ‚ŠγΎγ›γ‚“γ€‚", + "scenes.app.mainview.tabs.rename": "名前を倉更", + "scenes.app.mainview.tabs.searching_connectors": "γ‚³γƒγ‚―γ‚Ώγ‚’ζ€œη΄’...", + "scenes.app.popup.adduser.adresses_message": "γ‚’γƒ‰γƒ¬γ‚Ήγ―γ‚«γƒ³γƒžγΎγŸγ―γ‚ΉγƒšγƒΌγ‚Ήγ§εŒΊεˆ‡γ‚ŠγΎγ™γ€‚ Twakeは、ァブスクγƒͺγƒ—γ‚·γƒ§γƒ³γ«εŸΊγ₯いて招待γζ•°γ‚’εˆΆι™γ§γγ‚‹γ“γ¨γ«ζ³¨ζ„γ—γ¦γγ γ•γ„γ€‚", + "scenes.app.popup.appsparameters.pages._app_identity": "γ‚’γƒ—γƒͺケーションγID", + "scenes.app.popup.appsparameters.pages._appareance_message_twakcode": "Twacodeパッセージγε€–θ¦³γ‚’γƒ†γ‚Ήγƒˆγ—γΎγ™", + "scenes.app.popup.appsparameters.pages.alert_published_app": "γ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ―ε…¬ι–‹γ•γ‚Œγ¦γ„γΎγ™γ€‚η·¨ι›†γ™γ‚‹γ“γ¨γ―γ§γγΎγ›γ‚“γ€‚", + "scenes.app.popup.appsparameters.pages.allowed_ip_adresses_method": "開発時に*を使用して、すべてγIPをドレスを許可します。", + "scenes.app.popup.appsparameters.pages.amazing_app_name": "私γη΄ ζ™΄γ‚‰γ—いをプγƒͺ", + "scenes.app.popup.appsparameters.pages.api_data_description": "TwakeAPIに役立぀データ。", + "scenes.apps.calendar.no_calendar_text": "こγγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ«γ‚«γƒ¬γƒ³γƒ€γƒΌγ‚’θ¨­εšγ—ていません。", + "scenes.apps.calendar.remove_calendar_confirmation": "カレンダーとそγγ‚€γƒ™γƒ³γƒˆγ‚’εŒε…¨γ«ε‰Šι™€γ—γΎγ™γ‹οΌŸ", + "scenes.app.mainview.advanced_search_placeholder": "高度γͺ怜紒", + "components.searchpopup.hide_filters": "γƒ•γ‚£γƒ«γ‚Ώγ‚’ιžθ‘¨η€Ίγ«γ™γ‚‹", + "components.searchpopup.show_filters": "フィルタを葨瀺", + "components.searchpopup.load_more": "γ‚ˆγ‚Šε€šγγη΅ζžœγ‚’ロードする", + "general.more": "もっと", + "scenes.app.popup.adduser.magiclinks.genrator_info": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚ΉγΈγζ‹›εΎ…γƒͺンク", + "scenes.app.popup.adduser.magiclinks.new_link_generated": "新しいγƒͺγƒ³γ‚―γŒη”Ÿζˆγ•γ‚ŒγΎγ—γŸ", + "scenes.app.popup.adduser.magiclinks.copied_to_clipboard": "γ‚―γƒͺγƒƒγƒ—γƒœγƒΌγƒ‰γ«ζ­£εΈΈγ«γ‚³γƒ”γƒΌγ•γ‚ŒγΎγ—γŸ", + "scenes.app.popup.adduser.magiclinks.action_copy": "コピー", + "scenes.app.popup.adduser.magiclinks.action_generate": "η”Ÿζˆ", + "scenes.app.popup.appsparameters.pages.api_parameters_label": "APIθ¨­εš", + "scenes.app.popup.appsparameters.pages.app_modification_right": "こγδΌšη€Ύγγ™γΉγ¦γγƒžγƒγƒΌγ‚Έγƒ£γƒΌγ―、こγγ‚’γƒ—γƒͺケーションを編集できます。", + "scenes.app.popup.appsparameters.pages.filter_information": "こγγƒ•ィルターは、APIγ‚­γƒΌγδ½Ώη”¨γ‚’コネクター内γγ‚΅γƒΌγƒγƒΌγγΏγ«εˆΆι™γ—ます。", + "scenes.app.popup.appsparameters.pages.installation": "γ‚€γƒ³γ‚ΉγƒˆγƒΌγƒ«γ€‚", + "scenes.app.popup.appsparameters.pages.instruction_message_twakecode": "γΎγšγ€γƒ‘γƒƒγ‚»γƒΌγ‚Έγ‚’JSONε½’εΌγ§θ¨˜θΏ°γ—γΎγ™γ€‚", + "scenes.app.popup.appsparameters.pages.interne_availability_application": "内部をプγƒͺケーション", + "scenes.app.popup.appsparameters.pages.loading": "θͺ­γΏθΎΌγ‚“でいます...", + "scenes.app.popup.appsparameters.pages.modify_public_data": "γ‚’γƒ—γƒͺケーションγε…¬ι–‹γƒ‡γƒΌγ‚Ώγ‚’編集します。", + "scenes.app.popup.appsparameters.pages.new_app_title": "新しいをプγƒͺ", + "scenes.app.popup.appsparameters.pages.ok_user_code": "γ‚γ‹γ£γŸ", + "scenes.app.popup.appsparameters.pages.optimal_format": "ζœ€ι©γͺγƒ•γ‚©γƒΌγƒžγƒƒγƒˆοΌš48x48px。", + "scenes.app.popup.appsparameters.pages.public_availability_application": "ε…¬ι–‹γ‚’γƒ—γƒͺケーション", + "scenes.app.popup.appsparameters.pages.remove_app_button": "γ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ‚’ε‰Šι™€γ™γ‚‹", + "scenes.app.popup.createworkspacepage.add_subtitle": "γ‚ˆγ‚Šε€šγγγ‚ΉγƒšγƒΌγ‚ΉγŒεΏ…θ¦γ§γ™γ‹οΌŸ", + "scenes.app.popup.createworkspacepage.create_new_workspace": "ζ–°γ—γ„γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‚’δ½œζˆγ—γΎγ™", + "scenes.app.popup.workspaceparameter.pages.apps_connectors_title": "硱合", + "scenes.app.popup.workspaceparameter.pages.displayed_preferencies_subtitle": "葨瀺設εš", + "scenes.app.popup.workspaceparameter.pages.logo_subtitle": "γƒ­γ‚΄", + "scenes.app.popup.workspaceparameter.pages.name_description": "こγγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγεε‰γ‚’倉更します", + "scenes.apps.drive.viewer.edit_with_button": "{{$1}}で編集", + "scenes.apps.drive.viewer.loading_preview_message": "θͺ­γΏθΎΌγ‚“でいます...", + "scenes.apps.messages.message.new_messages_bar": "新しいパッセージ", + "scenes.apps.messages.message.cancel_button": "キャンセル", + "scenes.apps.messages.message.modify_button": "編集", + "scenes.apps.messages.message.pin_button": "ピンパッセージ", + "components.verify_mail.text": "γΎγšγ€γƒ‘γƒΌγƒ«γ‚’γƒ‰γƒ¬γ‚Ήγ‚’η’Ίθͺγ™γ‚‹εΏ…θ¦γŒγ‚γ‚ŠγΎγ™γ€‚γ«η’Ίθͺγƒͺγƒ³γ‚―γ‚’ι€δΏ‘γ—γΎγ—γŸ", + "components.verify_mail.paragraph": "εΏ…θ¦γ«εΏœγ˜γ¦εΎŒγ§θ‘Œγ†γ“γ¨γŒγ§γγΎγ™γŒγ€ζœͺη’Ίθͺγγ‚’γ‚«γ‚¦γƒ³γƒˆγ―ι™εšγƒγƒΌγ‚Έγƒ§γƒ³γTwakeにしかをクセスできません", + "components.richtexteditor.toolbar.blockquote": "γƒ–γƒ­γƒƒγ‚―γ‚―γ‚©γƒΌγƒˆ", + "components.on_boarding.company_billing_banner.admin_or_owner_text": "会瀾γγ‚΅γƒ–γ‚Ήγ‚―γƒͺγƒ—γ‚·γƒ§γƒ³γ«ε•ι‘ŒγŒγ‚γ‚ŠγΎγ™γ€‚γ©γ†γžγ€γ‚γͺたγ", + "components.on_boarding.company_billing_banner.guest_or_member_text": "会瀾γγ‚΅γƒ–γ‚Ήγ‚―γƒͺγƒ—γ‚·γƒ§γƒ³γ«ε•ι‘ŒγŒγ‚γ‚ŠγΎγ™γ€‚δΌšη€Ύγζ‰€ζœ‰θ€…γΎγŸγ―η‘理者に連硑してください!", + "components.on_boarding.company_billing_banner.link": "会瀾γγ‚΅γƒ–γ‚Ήγ‚―γƒͺプションプラン", + "components.on_boarding.popups.blocked_company.description": "Twakeγγ‚΅γƒ–γ‚Ήγ‚―γƒͺプションγζœ‰εŠΉζœŸι™γŒεˆ‡γ‚Œγ¦γ„γΎγ™γ€‚δΌšη€Ύγζ‰€ζœ‰θ€…γΎγŸγ―η‘η†θ€…γ«ι€£η΅‘γ—γ¦ζ›΄ζ–°γ—γ€γƒγƒΌγƒ γ¨ε†εΊ¦ι€£η΅‘γ§γγ‚‹γ‚ˆγ†γ«γ—γ¦γγ γ•γ„γ€‚", + "components.on_boarding.popups.blocked_company.learn_more_text": "企ζ₯­γγ‚΅γƒ–γ‚Ήγ‚―γƒͺプションプランに぀いてもっとηŸ₯γ‚ŠγŸγ„γ§γ™γ‹οΌŸ", + "components.on_boarding.popups.blocked_company.or": "または", + "scenes.apps.tasks.select_user": "γƒ¦γƒΌγ‚ΆγƒΌγ‚’ζ€œη΄’", + "components.emoji_picker.categories.activity": "をクティビティ", + "scenes.app.popup.workspaceparameter.pages.workspace_partner_tabs.members.table.tags": "役割", + "general.email": "Eパール", + "components.locked_features.locked_only_office_popup.title": "こγγƒ•γ‚‘むルは編集できません", + "components.locked_features.locked_only_office_popup.subtitle": "η„‘ζ–™η‰ˆγ§γ―γ€officeγγΏγ―使用できません。", + "scenes.app.integrations_parameters.applications_table.name": "名前", + "scenes.app.integrations_parameters.applications_table.title": "そγδ»–γη΅±εˆ", + "scenes.app.integrations_parameters.applications_table.search_placeholder": "ζ€œη΄’γ‚’γƒ—γƒͺケーション", + "scenes.app.integrations_parameters.company_application_popup.tag": "γ‚€γƒ³γ‚ΉγƒˆγƒΌγƒ«ζΈˆγΏ", + "scenes.app.integrations_parameters.company_application_popup.btn": "γ‚€γƒ³γ‚ΉγƒˆγƒΌγƒ«", + "scenes.app.integrations_parameters.company_application_popup.tab_btn_info": "ζƒ…ε ±", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.description_item": "θͺ¬ζ˜Ž", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.website_item": "Webγ‚΅γ‚€γƒˆ", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.created_item": "作成ζ—₯", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.version_item": "バージョン", + "scenes.app.integrations_parameters.company_applications_table.name": "名前", + "scenes.app.integrations_parameters.company_applications_table.title": "あγͺたγδΌšη€Ύγ«γ‚€γƒ³γ‚ΉγƒˆγƒΌγƒ«γ•γ‚Œγ¦γ„γΎγ™", + "app.state.recoil.hooks.use_current_company_applications.toaster_delete": "δΌšη€Ύγ‹γ‚‰{{$1}}γ‚’ζ­£εΈΈγ«ε‰Šι™€γ—γΎγ—γŸ", + "app.state.recoil.hooks.use_current_company_applications.toaster_add": "あγͺたγδΌšη€Ύγ«{{$1}}γŒζ­£εΈΈγ«θΏ½εŠ γ•γ‚ŒγΎγ—γŸ", + "scenes.apps.messages.input.replied_to": "に返俑 ", + "components.workspace.list_manager.all": "全て", + "general.help": "γƒ˜γƒ«γƒ—", + "scenes.apps.drive.go_out_trash_menu": "γ‚΄γƒŸγ‚’ζ‹γ™", + "components.account_verification_status_sentence": "γ‚’γ‚«γ‚¦γƒ³γƒˆγγ‚Ήγƒ†γƒΌγ‚Ώγ‚Ήγ―欑γγ¨γŠγ‚Šγ§γ™οΌš{{$1}}", + "scenes.apps.tasks.no_tasks": "θžγ‹γͺい", + "scenes.app.popup.appsparameters.pages.grp_section_name-error": "こγεε‰γ―、εˆ₯γγ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ§γ™γ§γ«δ½Ώη”¨γ•γ‚Œγ¦γ„γΎγ™γ€‚εˆ₯γγ‚‚γγ‚’ιΈζŠžγ—γ¦γγ γ•γ„γ€‚", + "scenes.app.popup.appsparameters.pages.grp_section_surname_label": "η°‘η•₯名", + "scenes.apps.messages.message.pinned": "ε›Ίεš", + "general.user.role.company.member": "パンバー", + "scenes.app.popup.userparameter.pages.private_message_content.hide": "γƒ—γƒ©γ‚€γƒ™γƒΌγƒˆγƒ‘γƒƒγ‚»γƒΌγ‚Έγγ‚³γƒ³γƒ†γƒ³γƒ„γ‚’ιžθ‘¨η€Ίγ«γ™γ‚‹", + "scenes.apps.messages.message.show_button": "画青", + "scenes.apps.messages.messageslist.get_writing_users": "書いています...", + "login.email_login": "Eパール/ログむン", + "scenes.app.channelsbar.unread_sign": "ζœͺθͺ­γ¨γ—γ¦γƒžγƒΌγ‚―", + "scenes.app.popup.userparameter.personnal_workspaces_title": "あγͺたγγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ή", + "scenes.apps.calendar.add_calendar_menu": "γ‚«γƒ¬γƒ³γƒ€γƒΌγ‚’θΏ½εŠ γ™γ‚‹", + "scenes.apps.drive.top_menu_more": "もっと", + "scenes.apps.drive.top_menu_no_items": "【X0X】をむテム", + "scenes.join.loading": "θͺ­γΏθΎΌγ‚“でいます…", + "scenes.join.wrong_link_title": "こγγƒͺγƒ³γ‚―γ―γ‚‚γ†εˆ©η”¨γ§γγΎγ›γ‚“", + "scenes.join.wrong_link_description": "あγͺγŸγ‚’γ“γδΌšη€Ύγ«ζ‹›εΎ…γ—γŸδΊΊγ«ζ–°γ—γ„γƒͺンクを求めるか、あγͺたθ‡ͺθΊ«γδΌšη€Ύγ‚’δ½œγ‚ŠγΎγ—γ‚‡γ†", + "scenes.join.create_the_company_button": "δΌšη€Ύγ‚’δ½œγ‚‹", + "scenes.join.join_workspace_from_company": "{{$2}}から{{$1}}γ«ε‚εŠ γ—γΎγ—γ‚‡γ†οΌ", + "scenes.join.twake_description": "Twakeは、チームγη”Ÿη”£ζ€§γ‚’ε‘δΈŠγ•γ›γ‚‹γŸγ‚γ«ζ§‹η―‰γ•γ‚ŒγŸγ‚ͺープンソースγγƒ‡γ‚Έγ‚Ώγƒ«γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ§γ™γ€‚", + "scenes.app.workspaces.create_company.company_name.title_1": "始める、", + "scenes.apps.account.account.make_main": "パむンを設εš", + "components.verify_mail.button": "γƒ¦γƒΌγ‚ΆγƒΌγ‚’θΏ½εŠ γ™γ‚‹", + "services.apps.calendar.deadline_icon": "η· γ‚εˆ‡γ‚Š", + "components.calendar.repetition.days": "ζ—₯γ€…οΌ‰", + "scenes.app.workspaces.welcome_page.see_you_soon": "γΎγŸθΏ‘γ„γ†γ‘γ«γŠδΌšγ„γ—γΎγ—γ‚‡γ†οΌ", + "scenes.app.workspaces.welcome_page.new_email": "δΊˆε‚™γι›»ε­γƒ‘γƒΌγƒ«γ‚’θΏ½εŠ γ™γ‚‹", + "components.calendar.repetition.ends": "η΅‚δΊ†", + "components.on_boarding.popups.blocked_company.title": "あγͺたγδΌšη€Ύγ―支払いγε•ι‘ŒγγŸγ‚γ«γƒ­γƒƒγ‚―γ•γ‚Œγ¦γ„γΎγ™", + "scenes.app.popup.workspaceparameter.pages.no_access": "γ‚’γ‚―γ‚»γ‚Ήγͺし。", + "components.users_picker.add_me": "η§γ‚’θΏ½εŠ γ—γ¦γγ γ•γ„", + "scenes.apps.drive.right_preview.public": "パブγƒͺック・をクセス", + "scenes.apps.calendar.modals.event_description_placeholder": "θͺ¬ζ˜Ž", + "scenes.app.popup.workspaceparameter.pages.developped_apps_small_text": "δΌšη€ΎγŒι–‹η™Ίγ—γŸγ‚’γƒ—γƒͺケーション", + "scenes.apps.drive.right_preview.public_link": "パブγƒͺックγƒͺンク", + "scenes.apps.account.identity": "θΊ«ε…ƒ", + "scenes.app.popup.appsparameters.pages.apps_connectors_small_text": "γ‚’γƒ—γƒͺケーションとコネクタをη‘理します。", + "scenes.app.channelsbar.currentuser.title": "γ‚’γ‚«γ‚¦γƒ³γƒˆθ¨­εš", + "scenes.app.popup.appsparameters.pages.json_configuration_information": "ドキγƒ₯γƒ‘γƒ³γƒˆγ«η§»ε‹•γ—γ¦γ€JSONε½’εΌγ§ζ§‹ζˆγ‚’η”Ÿζˆγ—γΎγ™γ€‚", + "scenes.app.popup.workspaceparameter.admin_manager_current_status": "あγͺγŸγ―γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήη‘理者です。", + "scenes.app.channelsbar.private_channel_label": "γƒ—γƒ©γ‚€γƒ™γƒΌγƒˆ", + "scenes.app.workspaces.welcome_page.lets_go": "γ•γ‚θ‘Œγ“γ†οΌ", + "scenes.apps.tasks.task_status.current": "現在", + "scenes.apps.tasks.board.tasks.in_list": "γƒͺγ‚Ήγƒˆγ«", + "components.calendar.repetition.weeks": "ι€±", + "scenes.apps.drive.go_trash_menu": "γ‚΄γƒŸη±γ«θ‘Œγ", + "scenes.app.popup.appsparameters.pages.autorised_ip_adresses_label": "θ¨±ε―γ•γ‚ŒγŸIPをドレス", + "scenes.apps.calendar.video_link": "γ‚―γƒͺックしてγƒͺンクを開く", + "components.calendar.repetition.monthly_on_day": "ζ―Žζœˆε½“ζ—₯{{$1}}", + "general.connexion_status.connecting": "再ζŽ₯ηΆšγ—γ¦γ„γΎγ™β€¦", + "scenes.app.workspaces.create_company.group_data.group_main_activity.materials": "材料", + "scenes.apps.tasks.boards": "γƒœγƒΌγƒ‰", + "general.remove": "ε‰Šι™€γ™γ‚‹", + "scenes.app.side_app.messages_thread_title": "{{$1}}‒パッセージスレッド", + "scenes.app.workspaces.create_company.group_data.group_type.university_school": "倧学または学树", + "general.help.support": "γ‚΅γƒγƒΌγƒˆ", + "general.archive": "γ‚’γƒΌγ‚«γ‚€γƒ–", + "scenes.app.workspaces.create_company.group_data.group_main_activity.electronics_electricity_energy": "γ‚¨γƒ¬γ‚―γƒˆγƒ­γƒ‹γ‚―γ‚Ή/ι›»ζ°—/エネルγ‚γƒΌ", + "scenes.apps.messages.left_bar.stream.add_to_favorites": "γŠζ°—γ«ε…₯γ‚Šγ«θΏ½εŠ ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.other": "δ»–γ", + "components.locked_features.locked_workspace_popup.title": "γ“γ‚Œδ»₯δΈŠγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‚’δ½œζˆγ™γ‚‹γ“γ¨γ―γ§γγΎγ›γ‚“", + "components.searchpopup.size": "γ‚΅γ‚€γ‚Ί", + "general.resume": "ε±₯ζ­΄ζ›Έ", + "general.pause": "δΈ€ζ™‚εœζ­’", + "scenes.app.workspaces.welcome_page.done": "η§γ―γ“γ‚Œγ§η΅‚γ‚γ‚Šγ§γ™", + "scenes.apps.tasks.task": "γ‚Ώγ‚Ήγ‚―", + "scenes.app.workspaces.create_company.group_data.title": "θΏ…ι€Ÿγ«ε―ΎεΏœγ—γΎγ™β€”εΏ…θ¦γͺγγ―η΅±θ¨ˆζƒ…ε ±γ γ‘γ§γ™γ€‚", + "scenes.app.channelsbar.currentuser.company_messages_counter_header": "パッセージη•ͺ号", + "scenes.app.channelsbar.currentuser.company_messages_counter_info": "η„‘ζ–™η‰ˆγTwakeでは、{{$1}}γ‚ˆγ‚Šζ–°γ—γ„γƒ‘γƒƒγ‚»γƒΌγ‚Έγ«γ‚’γ‚―γ‚»γ‚Ήγ™γ‚‹γ“γ¨γ―γ§γγΎγ›γ‚“γ€‚", + "scenes.app.channelsbar.currentuser.company_messages_counter_link": "γ‚ˆγ‚Šε€šγγθ¨ˆη”»γ‚’葨瀺する", + "scenes.app.channelsbar.channelsuser.new_private_discussion": "ζ–°γ—γ„γƒ—γƒ©γ‚€γƒ™γƒΌγƒˆγƒ‡γ‚£γ‚Ήγ‚«γƒƒγ‚·γƒ§γƒ³", + "scenes.app.channelsbar.channelsuser.no_private_message_invite_collaboraters": "γƒ—γƒ©γ‚€γƒ™γƒΌγƒˆγƒ‘γƒƒγ‚»γƒΌγ‚Έγ―γ‚γ‚ŠγΎγ›γ‚“γ€‚γƒ¦γƒΌγ‚ΆγƒΌγ‚’ζ‹›εΎ…γ—γΎγ—γ‚‡γ†οΌ", + "scenes.app.channelsbar.channelsuser.private_messages": "γƒ€γ‚€γƒ¬γ‚―γƒˆγƒ‘γƒƒγ‚»γƒΌγ‚Έ", + "scenes.app.channelsbar.channelsworkspace.channel_title": "チャンネル", + "scenes.app.channelsbar.channelsworkspace.channel_title.favorite": "γŠζ°—γ«ε…₯γ‚Š", + "scenes.app.channelsbar.channelsworkspace.create_channel": "γƒγƒ£γƒγƒ«γ‚’δ½œζˆγ™γ‚‹", + "scenes.app.channelsbar.channelsworkspace.no_channel": "まだどγγƒγƒ£γƒ³γƒγƒ«γ«γ‚‚ε‚εŠ γ—γ¦γ„γΎγ›γ‚“", + "scenes.app.channelsbar.modify_channel_menu": "チャンネルを編集", + "scenes.app.channelsbar.guest_management": "γ‚²γ‚Ήγƒˆη‘理", + "scenes.app.channelsbar.read_sign": "ζ—’θͺ­γ«γ™γ‚‹", + "scenes.app.channelsbar.channel_leaving": "γƒγƒ£γƒγƒ«γ‚’ι›’γ‚Œγ‚‹", + "scenes.app.channelsbar.channel_removing": "γƒγƒ£γƒγƒ«γ‚’ε‰Šι™€", + "scenes.app.channelsbar.company_invitation_alert_subtitle": "こγγƒ•レームをクγƒͺγƒƒγ‚―γ™γ‚‹γ¨γ€γ“γ‚Œγ‚‰γγƒγƒ£γƒγƒ«γ‚’γƒ“γ‚Έγƒγ‚Ήγ«γ‚€γƒ³γƒγƒΌγƒˆγ—γ¦γ€ζ•΄η†γ•γ‚ŒγŸηŠΆζ…‹γ‚’δΏγ€γ“γ¨γŒγ§γγΎγ™γ€‚", + "scenes.app.popup.appsparameters.pages.app_update": "γ‚’γƒ—γƒͺγ‚’{{$1}}ζ›΄ζ–°γ—γΎγ™οΌˆγ‚’γƒ—γƒͺは{{$2}}ε›žδ½Ώη”¨γ•γ‚ŒγΎγ™οΌ‰γ€‚", + "scenes.app.popup.appsparameters.pages.application_title": "εΏœη”¨", + "scenes.app.popup.appsparameters.pages.apps_title": "γ‚’γƒ—γƒͺケーションとコネクタ", + "scenes.app.popup.appsparameters.pages.automatique_label": "θ‡ͺε‹•", + "scenes.app.popup.appsparameters.pages.automatique_option_information": "γ€Œθ‡ͺε‹•γ€γ‚’ζœ‰εŠΉγ«γ™γ‚‹γ¨γ€γ“γγ‚’γƒ—γƒͺケーションはこγδΌšη€Ύγζ¬‘γγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ«θ‡ͺε‹•ηš„γ«θΏ½εŠ γ•γ‚ŒγΎγ™γ€‚", + "scenes.app.popup.appsparameters.pages.available_publication_alert": "γ‚’γƒ—γƒͺケーションγε…¬ι–‹γ―ηΎεœ¨γ€TwakeγƒγƒΌγƒ γ«γ‚ˆγ‚‹ζ€œθ¨Όγ‚’εΎ…γ£γ¦γ„γΎγ™γ€‚", + "scenes.app.popup.appsparameters.pages.button_force": "δΌšη€Ύε…¨δ½“γεŠ›", + "scenes.app.popup.appsparameters.pages.call_event_handlers": "γ‚Ώγ‚€γƒ— '{{$1}}'γŠγ‚ˆγ³ID '{{$2}}'γγ‚€γƒ™γƒ³γƒˆγ¨γƒ‘ッシブ '{{$3}}'", + "scenes.app.popup.appsparameters.pages.company_label": "会瀾γγ‚ͺγƒΌγƒŠγƒΌ", + "scenes.app.popup.appsparameters.pages.configuration_label": "ζ§‹ζˆ", + "scenes.app.popup.appsparameters.pages.create_app_button": "γ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ‚’δ½œζˆγ™γ‚‹", + "scenes.app.popup.appsparameters.pages.create_my_app": "γ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ‚’δ½œζˆγ™γ‚‹", + "scenes.app.popup.appsparameters.pages.current_informations_apps_connectors": "まだをプγƒͺγ‚’δ½œζˆγ—γ¦γ„γΎγ›γ‚“γ€‚γ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γΎγŸγ―γ‚³γƒγ‚―γ‚Ώγ‚’δ½œζˆγ™γ‚‹ε‰γ«γ€γγ‚Œγ‚‰γŒγ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³εΈ‚ε ΄γ«γΎγ ε­˜εœ¨γ—γ¦γ„γͺいことを璺θͺγ—てください。", + "scenes.app.popup.appsparameters.pages.danger_zone_description": "γ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ‚’ε‰Šι™€γ™γ‚‹", + "scenes.app.popup.appsparameters.pages.danger_zone_label": "ε±ι™Ίεœ°εΈ―", + "scenes.app.popup.appsparameters.pages.description_label": "θͺ¬ζ˜Ž", + "scenes.app.popup.appsparameters.pages.developped_apps_subtitle": "δΌšη€ΎγŒι–‹η™Ίγ—γŸγ‚’γƒ—γƒͺケーション", + "scenes.app.popup.appsparameters.pages.dispalyed_parameters_description": "γ‚’γƒ—γƒͺケーションを葨瀺する場所をεšηΎ©γ§γγΎγ™γ€‚", + "scenes.app.popup.appsparameters.pages.displayed_parameters_label": "ディスプレむγθ¨­εš", + "scenes.app.popup.appsparameters.pages.error_check_needed": "γ‚¨γƒ©γƒΌγŒη™Ίη”Ÿγ—γΎγ—γŸ;あγͺたγζƒ…ε ±γ‚’η’Ίθͺγ—てください。", + "scenes.app.popup.appsparameters.pages.error_message": "こγεε‰γ―すでにεˆ₯γγ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ§δ½Ώη”¨γ•γ‚Œγ¦γ„γΎγ™γ€‚εˆ₯γγ‚‚γγ‚’ιΈζŠžγ—γ¦γγ γ•γ„γ€‚", + "scenes.app.popup.appsparameters.pages.error_user_code": "エラー", + "scenes.app.popup.appsparameters.pages.event_subtitle": "γ‚€γƒ™γƒ³γƒˆ", + "scenes.app.popup.appsparameters.pages.go_back": "ζˆ»γ‚‹", + "scenes.app.popup.appsparameters.pages.publication_description": "γ‚’γƒ—γƒͺケーションγε―θ¦–ζ€§γ‚’εˆ€ζ–­γ—γΎγ™γ€‚", + "scenes.app.popup.appsparameters.pages.publication_label": "ε‡Ίη‰ˆη‰©", + "scenes.app.popup.appsparameters.pages.publish_app_label": "γ‚’γƒ—γƒͺケーションを公開する", + "scenes.app.popup.appsparameters.pages.read_privileges_label": "θͺ­γΏε–γ‚Šζ¨©ι™", + "scenes.app.popup.appsparameters.pages.remove_app": "γ‚’γƒ—γƒͺケーション{{$1}}γ‚’εŒε…¨γ«ε‰Šι™€γ—ます。", + "scenes.app.popup.appsparameters.pages.remove_app_from_company": "δΌšη€Ύε…¨δ½“γ‹γ‚‰ε‰Šι™€γ™γ‚‹", + "scenes.app.popup.appsparameters.pages.remove_app_from_workspace": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‹γ‚‰ε‰Šι™€", + "scenes.app.popup.appsparameters.pages.status_tilte": "州", + "scenes.app.popup.appsparameters.pages.string_information": "こγζ–‡ε­—εˆ—γ―γ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ‚’θ­˜εˆ₯γ—γ€γƒ‘γƒƒγ‚»γƒΌγ‚Έγ‚³γƒžγƒ³γƒ‰γ§δ½Ώη”¨γ•γ‚ŒγΎγ™γ€‚", + "scenes.app.popup.appsparameters.pages.title_tester": "Twakecodeテスター", + "scenes.app.popup.appsparameters.pages.url_reception_events_label": "γ‚€γƒ™γƒ³γƒˆγƒ¬γ‚»γƒ—γ‚·γƒ§γƒ³γURL", + "scenes.app.popup.appsparameters.pages.waiting_availability_application": "待っています...", + "scenes.app.popup.appsparameters.pages.website_label": "Webγ‚΅γ‚€γƒˆ", + "scenes.app.popup.userparameter.pages.notif_content_label": "ι€šηŸ₯γε†…εΉ", + "scenes.app.mainview.quick_search_placeholder": "γ‚―γ‚€γƒƒγ‚―ζ€œη΄’", + "scenes.app.popup.workspaceparameter.admin_current_status": "あγͺたはη‘理者です。", + "scenes.app.popup.workspaceparameter.manager_current_status": "あγͺたは会瀾γη‘理者です。", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‚’ε‰Šι™€γ™γ‚‹", + "scenes.app.popup.workspaceparameter.pages.error_workspace_member": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‚’ε‰Šι™€γ™γ‚‹γ«γ―γ€γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ«δΈ€δΊΊγ§γ„γ‚‹εΏ…θ¦γŒγ‚γ‚ŠγΎγ™γ€‚ε…±εŒη·¨ι›†θ€…γ‚’ε‰Šι™€γ—γ¦γ€ε†θ©¦θ‘Œγ—γ¦γγ γ•γ„γ€‚", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace_description": "こγγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‚’ε‰Šι™€γ™γ‚‹γ“γ¨γ‚’η’Ίθͺγ™γ‚‹γ«γ―、δ»₯下に名前をε…₯εŠ›γ—γ¦[ε‰Šι™€]γ‚’γ‚―γƒͺックしてください。", + "scenes.app.popup.workspaceparameter.pages.enter": "ε…₯εŠ› ", + "scenes.app.popup.workspaceparameter.pages.access_apps": "γ‚’γƒ—γƒͺケーションとコネクタにをクセスする", + "scenes.app.popup.workspaceparameter.pages.moderator_status": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγƒ’γƒ‡γƒ¬γƒΌγ‚ΏγƒΌ", + "scenes.app.popup.workspaceparameter.pages.alert_impossible_removing": "あγͺγŸγŒζœ€εΎŒγη‘η†θ€…γ§γ‚γ‚‹γŸγ‚γ€γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‚’ι›’γ‚Œγ‚‹γ“γ¨γ―γ§γγΎγ›γ‚“γ€‚ζ–°γ—γ„η‘理者をεšηΎ©γ™γ‚‹γ‹γ€γ“γγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‚’ε‰Šι™€/をーカむブできます。", + "scenes.app.popup.workspaceparameter.pages.all_apps_small_text": "すべてγγ‚’γƒ—γƒͺケーション", + "scenes.app.popup.workspaceparameter.pages.apps_company_small_text": "あγͺたγδΌšη€Ύγγ‚’γƒ—γƒͺケーション", + "scenes.app.popup.workspaceparameter.pages.apps_research_title": "γ‚’γƒ—γƒͺケーションγζ€œη΄’", + "scenes.app.popup.workspaceparameter.pages.apps_small_text": "こγγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγγ‚’γƒ—γƒͺケーション", + "scenes.app.popup.workspaceparameter.pages.install_button": "γ‚€γƒ³γ‚ΉγƒˆγƒΌγƒ«", + "scenes.app.popup.workspaceparameter.pages.installed_app_information": "こγγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ«γ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ‚’γ‚€γƒ³γ‚ΉγƒˆγƒΌγƒ«γ—γΎγ™γ€‚", + "scenes.app.popup.workspaceparameter.pages.installed_apps_information": "こγγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ«γ‚€γƒ³γ‚ΉγƒˆγƒΌγƒ«γ•γ‚Œγ¦γ„γ‚‹γ‚’γƒ—γƒͺケーション{{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_message": "会瀾γδ»–γι ˜εŸŸγ«γ‚€γƒ³γ‚ΉγƒˆγƒΌγƒ«γ•γ‚Œγ¦γ„γ‚‹γ‚’γƒ—γƒͺケーション{{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_subtitle": "γ‚€γƒ³γ‚ΉγƒˆγƒΌγƒ«γ•γ‚Œγ¦γ„γ‚‹γ‚’γƒ—γƒͺケーション", + "scenes.app.popup.workspaceparameter.pages.invitation_error": "欑γγƒ¦γƒΌγ‚ΆγƒΌγ‚’ζ‹›εΎ…γ—γ¦γ„γ‚‹γ¨γγ«γ‚¨γƒ©γƒΌγŒη™Ίη”Ÿγ—γΎγ—γŸγ€‚ ", + "scenes.app.popup.workspaceparameter.pages.logo_modify_description": "こγγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγη”»εƒγ‚’編集します", + "scenes.app.popup.workspaceparameter.pages.no_app_information": "こγγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ«γ―γ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γŒγ‚γ‚ŠγΎγ›γ‚“", + "scenes.app.popup.workspaceparameter.pages.quit_workspace_menu": "こγγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‚’ι›’γ‚Œγ‚‹", + "scenes.app.popup.workspaceparameter.pages.read_access_subtitle": "θͺ­γΏε–γ‚Šγ‚’γ‚―γ‚»γ‚Ή", + "scenes.app.popup.workspaceparameter.pages.remove_from_company_text": "δΌšη€Ύε…¨δ½“γ‹γ‚‰ε‰Šι™€γ™γ‚‹", + "scenes.app.popup.workspaceparameter.pages.research_by": "名前とカテゴγƒͺでをプγƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ‚’ζ€œη΄’γ™γ‚‹", + "scenes.app.popup.workspaceparameter.pages.researching_apps_button": "γ‚’γƒ—γƒͺケーションγζ€œη΄’...", + "scenes.app.popup.workspaceparameter.pages.show_button": "画青", + "scenes.app.popup.workspaceparameter.pages.title": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήθ¨­εš", + "scenes.app.popup.workspaceparameter.pages.webhooks_access_subtitle": "Webhookへγγ‚’γ‚―γ‚»γ‚Ή", + "scenes.app.popup.workspaceparameter.pages.weight_max_small_text": "ζœ€ε€§γ‚΅γ‚€γ‚Ίγ―5MBです。", + "scenes.apps.calendar.connectors_search_menu": "γ‚³γƒγ‚―γ‚Ώγ‚’ζ€œη΄’...", + "scenes.apps.calendar.create_calendar_title": "γ‚«γƒ¬γƒ³γƒ€γƒΌγ‚’δ½œζˆγ™γ‚‹", + "scenes.apps.calendar.day_option": "ζ—₯", + "scenes.apps.calendar.edit_calendar_title": "カレンダーを編集する", + "scenes.apps.calendar.export_title": "書き出す", + "scenes.apps.calendar.export_view_menu": "ビγƒ₯γƒΌγ‚’γ‚¨γ‚―γ‚ΉγƒγƒΌγƒˆ...", + "scenes.apps.calendar.ics_download_menu": "ICSフゑむルをダウンロードする", + "scenes.apps.calendar.ics_subscription_menu": "ICSγ‚΅γƒ–γ‚Ήγ‚―γƒͺプションγƒͺンクを取得する", + "scenes.apps.calendar.modals.advanced_options": "高度γͺγ‚ͺプション", + "scenes.apps.calendar.modals.description_placeholder": "θͺ¬ζ˜Ž", + "scenes.apps.calendar.modals.details_title": "θ©³η΄°", + "scenes.apps.calendar.modals.event_adresse_placeholder": "住所", + "scenes.apps.calendar.modals.event_title_placeholder": "鑌名", + "scenes.apps.calendar.modals.modify_event_button": "γ‚€γƒ™γƒ³γƒˆγη·¨ι›†", + "scenes.apps.calendar.modals.part.participants": "ε‚εŠ θ€…", + "scenes.apps.calendar.modals.participants_event": "ε‚εŠ θ€…", + "scenes.apps.calendar.modals.reminders": "γƒͺγƒžγ‚€γƒ³γƒ€γƒΌ", + "scenes.apps.calendar.modals.remove_button": "梈去", + "scenes.apps.calendar.modals.remove_event_button": "γ‚€γƒ™γƒ³γƒˆγ‚’ε‰Šι™€", + "scenes.apps.calendar.modals.remove_event_text": "γ‚€γƒ™γƒ³γƒˆγ‚’ε‰Šι™€γ—γΎγ™γ‹οΌŸ", + "scenes.apps.calendar.modals.title_placeholder": "鑌名", + "scenes.apps.calendar.modify_calendar_menu": "カレンダーを編集する", + "scenes.apps.calendar.month_option": "月", + "scenes.apps.calendar.my_calendar": "私γγ‚«γƒ¬γƒ³γƒ€γƒΌ", + "scenes.apps.calendar.my_calendar_label": "私γγ‚«γƒ¬γƒ³γƒ€γƒΌ", + "scenes.apps.calendar.my_calendar_menu": "私γγ‚«γƒ¬γƒ³γƒ€γƒΌ", + "scenes.apps.calendar.today_menu": "今ζ—₯", + "scenes.apps.calendar.week_option": "ι€±", + "scenes.apps.calendar.workspace": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ή", + "scenes.apps.calendar.workspace_menu": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ή", + "scenes.apps.drive.add_button": "追加", + "scenes.apps.drive.message_added_file": "{{$1}}は{{$2}}γ‚’ι€δΏ‘γ—γΎγ—γŸγ€‚", + "scenes.apps.drive.message_added_mutiple_files": "{{$1}}は耇数γγƒ•γ‚‘γ‚€γƒ«γ‚’ι€δΏ‘γ—γΎγ—γŸγ€‚", + "scenes.apps.drive.message_added_file_no_name": "{{$1}}γ―γƒ•γ‚‘γ‚€γƒ«γ‚’ι€δΏ‘γ—γΎγ—γŸγ€‚", + "scenes.apps.drive.choose_folder_button": "γƒ‡γ‚£γƒ¬γ‚―γƒˆγƒͺγ‚’ιΈζŠžγ—γ¦γγ γ•γ„", + "scenes.apps.drive.choose_file_button": "γƒ•γ‚‘γ‚€γƒ«γ‚’ιΈζŠž", + "scenes.apps.drive.create_folder_button": "作成", + "scenes.apps.drive.download_button": "ダウンロード", + "scenes.apps.drive.open_link": "新しいウィンドウでγƒͺンクを開く", + "scenes.apps.drive.files_subtitle": "フゑむル", + "scenes.apps.drive.folder_subtitle": "フォルダー", + "scenes.apps.drive.import_from_computer_menu": "コンピγƒ₯ータからをップロード", + "scenes.apps.drive.move_text": "動く", + "scenes.apps.drive.viewer.no_preview_message": "こγη¨γγƒ•γ‚‘むルは葨瀺できません。", + "scenes.apps.drive.viewer.open_with_button": "で開く...", + "scenes.apps.messages.input.placeholder": "パッセージを書く。 @を使用してユーアーを引用します。", + "scenes.apps.messages.input.edited": "η·¨ι›†ζΈˆγΏ", + "scenes.apps.messages.just_you": "あγͺγŸγ γ‘γ«θ¦‹γˆγ‚‹", + "scenes.apps.messages.message.remove_button": "梈去", + "scenes.apps.messages.message.reply_button": "θΏ”δΊ‹", + "scenes.apps.messages.message.save_button": "δΏε­˜γ™γ‚‹", + "scenes.apps.messages.message.show_responses_button": "すべてγε›žη­”を葨瀺", + "scenes.apps.messages.message.types.first_channel_message_text": "γ“γ‚Œγ―γƒγƒ£γƒ³γƒγƒ«γζœ€εˆγγƒ‘ッセージです", + "scenes.apps.messages.message.types.first_message_text": "γ“γ‚ŒγŒζœ€εˆγγƒ‘ッセージです", + "scenes.apps.messages.messageslist.get_writing_user": "書いています...", + "scenes.apps.messages.messageslist.go_last_message_button": "ζœ€εΎŒγγƒ‘ッセージに移動", + "scenes.apps.messages.messageslist.go_last_message_button.new_messages": "新しいパッセージ", + "scenes.error_on_twake": "γ€Œγƒ’γƒ₯γƒΌγ‚Ήγƒˆγƒ³γ€η§γŸγ‘γ―ε•ι‘Œγ‚’ζŠ±γˆγ¦γ„γΎγ™γ€", + "scenes.help_us": "γŸγ γ—γ€γ“γγ‚¨γƒ©γƒΌγδΏζ­£γ‚’ζ”―ζ΄γ—γŸγ„ε ΄εˆγ―γ€δ»₯δΈ‹γγƒ‘ッセージを送俑してください。 ", + "scenes.login.verifymail.alert": "η§γŸγ‘γ―γ‚γͺたγι›»ε­γƒ‘ールをチェックしています!", + "scenes.login.verifymail.error_message": "γ‚¨γƒ©γƒΌγŒη™Ίη”Ÿγ—γΎγ—γŸ", + "scenes.login.verifymail.signin_button": "ログむン", + "scenes.login.verifymail.success": "あγͺたγι›»ε­γƒ‘ールは正常に璺θͺγ•γ‚ŒγΎγ—γŸοΌ", + "scenes.login.verifymail.verification_waiting": "η’Ίθͺγ‚’待っています...", + "scenes.apps.messages.new_thread": "新しいディスカッションを開始します", + "scenes.apps.messages.input.send_message": "パッセージを送る", + "scenes.apps.messages.input.emoji": "η΅΅ζ–‡ε­—", + "scenes.apps.messages.input.hide_formatting": "γƒ•γ‚©γƒΌγƒžγƒƒγƒˆγ‚’ιžθ‘¨η€Ί", + "scenes.apps.messages.input.show_formatting": "γƒ•γ‚©γƒΌγƒžγƒƒγƒˆγ‚’θ‘¨η€Ί", + "scenes.tell_us": "あγͺγŸγŒδ½•γ‚’γ—γ¦γ„γŸγ‹ζ•™γˆγ¦γγ γ•γ„οΌš", + "scenes.apps.drive.viewer.download_desktop": "γ‚’γƒ—γƒͺでプレビγƒ₯ーするには、Twakeγƒ‡γ‚Ήγ‚―γƒˆγƒƒγƒ—γ‚’γƒ€γ‚¦γƒ³γƒ­γƒΌγƒ‰γ—γ¦γγ γ•γ„", + "scenes.apps.tasks.my_tasks": "私γγ‚Ώγ‚Ήγ‚―", + "scenes.apps.tasks.board.place_holder": "γƒœγƒΌγƒ‰ε", + "scenes.apps.tasks.board.tasks.subtask": "γ‚΅γƒ–γ‚Ώγ‚Ήγ‚―", + "scenes.apps.tasks.board.tasks.add_subtask": "γ‚΅γƒ–γ‚Ώγ‚Ήγ‚―γ‚’θΏ½εŠ γ™γ‚‹", + "scenes.apps.tasks.board.tasks.use_deadline": "ζœŸι™γ‚’δ½Ώη”¨γ™γ‚‹", + "scenes.apps.tasks.board.tasks.use_starttime": "開始時間を使用する", + "scenes.apps.tasks.board.starts": "を開始します", + "scenes.apps.tasks.board.ends": "γγŸγ‚γ«θ‘Œγ‚γ‚Œγ‚‹", + "scenes.app.popup.sync_calendar": "γ‚«γƒ¬γƒ³γƒ€γƒΌγ‚’εŒζœŸγ—γΎγ™γ€‚", + "scenes.apps.parameters.workspace_sections.workspace.logo_company": "会瀾γγƒ­γ‚΄", + "scenes.app.popup.workspaceparameter.pages.logo_company_modify_description": "会瀾γη”»εƒγ‚’編集する ", + "scenes.app.popup.workspaceparameter.pages.cancel_invitation": "招待をキャンセルする", + "scenes.apps.account.account.fullname": "フルネーム", + "scenes.apps.account.account.password_for_user": "ユーアーγγƒ‘γ‚Ήγƒ―ード", + "scenes.apps.account.account.send_info": "こγθ³‡ζ Όζƒ…報をユーアーに送俑します。", + "scenes.apps.account.message_temporary": "δΈ€ζ™‚γ‚’γ‚«γ‚¦γƒ³γƒˆγ―ι€šεΈΈγTwakeγ‚’γ‚«γ‚¦γƒ³γƒˆγ¨εŒγ˜γ‚ˆγ†γ«ζ©Ÿθƒ½γ—γΎγ™γŒγ€γƒ‘γ‚Ήγƒ―γƒΌγƒ‰γ‚’δ½œζˆγ™γ‚‹γ¨γ€εΏ…θ¦γ«εΏœγ˜γ¦γƒ‘γ‚Ήγƒ―γƒΌγƒ‰γ‚’γƒͺγ‚»γƒƒγƒˆγ§γγΎγ™γ€‚", + "scenes.apps.account.message_user_signin": "ユーアーは、こγεŒγ˜ι›»ε­γƒ‘γƒΌγƒ«γ‚’δ½Ώη”¨γ—γ¦γ„γ€γ§γ‚‚γ‚΅γ‚€γƒ³γ‚€γƒ³γ—γ€δΈ€ζ™‚γ‚’γ‚«γ‚¦γƒ³γƒˆγ‚’ι€šεΈΈγγ‚’γ‚«γ‚¦γƒ³γƒˆγ«ε€‰ζ›΄γ§γγΎγ™γ€‚", + "scenes.app.mainview.link_expired": "こγγƒ‘γƒ–γƒͺックγƒͺγƒ³γ‚―γ―η„‘εŠΉγ§γ‚γ‚‹γ‹γ€ζœ‰εŠΉζœŸι™γŒεˆ‡γ‚Œγ¦γ„γΎγ™γ€‚", + "scenes.app.mainview.create_account": "γ§η„‘ζ–™γ§γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‚’δ½œζˆγ™γ‚‹ ", + "scenes.apps.calendar.modals.reminder_add": "γƒͺγƒžγ‚€γƒ³γƒ€γƒΌγ‚’θΏ½εŠ γ™γ‚‹", + "scenes.apps.parameters.workspace_sections.members.invite_all": "すべてを招待する", + "scenes.app.taskpicker.select": "ιΈζŠžγ™γ‚‹", + "components.listmanager.filter": "フィルター", + "scenes.apps.tasks.no_connector": "コネクタγͺし", + "components.attachmentpicker.add_attachment": "ζ·»δ»˜γƒ•γ‚‘γ‚€γƒ«γ‚’θΏ½εŠ γ™γ‚‹", + "components.input.copied": "コピー", + "components.drive.new_versions": "ζ–°γ—γ„γƒγƒΌγ‚Έγƒ§γƒ³γ‚’θΏ½εŠ γ™γ‚‹", + "components.drive.navigators.directory_not_found": "γƒ‡γ‚£γƒ¬γ‚―γƒˆγƒͺγŒθ¦‹γ€γ‹γ‚ŠγΎγ›γ‚“γ€‚", + "components.drive.right_preview.suppress_link": "γƒͺγƒ³γ‚―γ‚’ζŠ‘εˆΆγ—γΎγ™", + "components.drive.right_preview.create_link": "γ‚’γ‚―γ‚»γ‚Ήγƒͺγƒ³γ‚―γ‚’δ½œζˆγ™γ‚‹", + "components.drive.moove_here": "ここに移動", + "components.drive.modify_uslist": "ユーアーγƒͺγ‚Ήγƒˆγ‚’ε€‰ζ›΄γ™γ‚‹", + "components.tagpicker.tag_name": "タグ名", + "components.upload.drop_files": "ここにフゑむルをドロップします", + "components.workspace.list_manager.no_workspace": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγͺし", + "components.workspace.list_manager.add": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‚’θΏ½εŠ γ™γ‚‹", + "components.workspace.list_manager.current_space": "現在γγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ή", + "components.workspace.list_manager.current_company": "現在γδΌšη€Ύ", + "components.workspace.calendar.invalid": "η„‘εŠΉ", + "components.searchpopup.enter_text": "Twakeγ‚’ζ€œη΄’γ™γ‚‹γŸγ‚γγƒ†γ‚­γ‚Ήγƒˆγ‚’ε…₯εŠ›γ—γΎγ™γ€‚", + "components.searchpopup.loading": "γ‚ˆγ‚Šε€šγγη΅ζžœγ‚’ロードする", + "components.searchpopup.filter_ws": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‚’γƒ•γ‚£γƒ«γ‚Ώγƒͺングする", + "components.searchpopup.creation": "剡造", + "components.searchpopup.update_search": "ζ€œη΄’γ‚’ζ›΄ζ–°", + "components.searchpopup.last_modif": "ζœ€η΅‚ε€‰ζ›΄", + "components.searchpopup.sender": "送俑者", + "components.searchpopup.mentions": "θ¨€εŠ", + "components.searchpopup.only_pinned": "ε›Ίεšγ•γ‚ŒγŸγƒ‘ッセージγγΏ", + "components.alert.confirm": "をクションを璺θͺγ™γ‚‹", + "components.alert.confirm_click": "[OK]γ‚’γ‚―γƒͺックしてをクションを璺θͺγ—ます。", + "components.searchpopup.tasks": "γ‚Ώγ‚Ήγ‚―", + "scenes.apps.board.archived_tasks": "γ‚’γƒΌγ‚«γ‚€γƒ–γ•γ‚ŒγŸγ‚Ώγ‚Ήγ‚―οΌˆ{{$1}}οΌ‰", + "scenes.apps.board.active_tasks": "をクティブγͺγ‚Ώγ‚Ήγ‚―", + "scenes.apps.board.kanban": "かんばん", + "scenes.apps.board.display_as": "葨瀺", + "scenes.apps.board.new_task": "+新しいタスク", + "scenes.apps.board.all_boards": "すべてγγƒœγƒΌγƒ‰", + "components.userlistmanager.no_users": "ユーアーはいません。", + "scenes.apps.drive.used": "こγγƒ•γ‚©γƒ«γƒ€γ§δ½Ώη”¨γ•γ‚ŒγΎγ™", + "components.reminder.notification": "ι€šηŸ₯", + "components.reminder.minutes_bef": "ζ•°εˆ†ε‰", + "components.reminder.hours_bef": "数時間前", + "components.reminder.days_bef": "前ζ—₯", + "components.reminder.weeks_bef": "数週間前", + "components.reminder.by_email": "Eパール", + "scenes.apps.calendar.reminders": "γƒͺγƒžγ‚€γƒ³γƒ€γƒΌ", + "scenes.app.mainview.discussion": "θ­°θ«–", + "components.tagpicker.notag": "γ‚Ώγ‚°γͺし", + "scenes.apps.tasks.modals.attachments": "ζ·»δ»˜γƒ•γ‚‘γ‚€γƒ«", + "components.calendar.calendarselector.from": "から", + "scenes.apps.drive.move_text2": "動く", + "components.attachmentpicker.from_computer": "γŠδ½Ώγ„γγƒ‡γƒγ‚€γ‚Ήγ‹γ‚‰", + "components.attachmentpicker.from_twake": "Twakeドキγƒ₯γƒ‘γƒ³γƒˆγ‹γ‚‰", + "components.attachmentpicker.file": "フゑむル", + "components.attachmentpicker.remove_attach": "ζ·»δ»˜γƒ•γ‚‘γ‚€γƒ«γ‚’ε‰Šι™€γ—γΎγ™", + "scenes.apps.drive.remove_attachs": "ζ·»δ»˜γƒ•γ‚‘γ‚€γƒ«γ‚’ε‰Šι™€γ—γΎγ™", + "components.drive.elements.see": "見る", + "components.drive.elements.current_name": "現在γεε‰οΌš ", + "components.drive.elements.configurate_mod": "modγ‚’θ¨­εšγ—ます...", + "components.drive.elements.manage_version": "バージョンをη‘理する", + "scenes.app.popup.createcompany.try_again": "γ‚‚γ†δΈ€εΊ¦γ‚„γ‚Šη›΄γ—γ¦γγ γ•γ„γ€‚", + "scenes.app.popup.workspace.edit_temp": "δΈ€ζ™‚ηš„γͺγ‚’γ‚«γ‚¦γƒ³γƒˆγ‚’η·¨ι›†γ™γ‚‹", + "scenes.app.popup.workspace.create_temp": "δΈ€ζ™‚ηš„γͺγ‚’γ‚«γ‚¦γƒ³γƒˆγ‚’δ½œζˆγ™γ‚‹", + "scenes.apps.tasks.active_tasks": "をクティブγͺγ‚Ώγ‚Ήγ‚―", + "scenes.apps.drive.right_preview.versions": "バージョン", + "scenes.app.popup.appsparameters.pages.title_informations": "εŸΊζœ¬ζƒ…ε ±", + "scenes.app.popup.appsparameters.pages.subtitle_informations": "γ‚’γƒ—γƒͺケーションη‘理に閒する情報", + "scenes.app.popup.appsparameters.pages.smalltext_user_id": "現在γγƒ¦γƒΌγ‚ΆγƒΌID", + "scenes.app.popup.appsparameters.pages.smalltext_workspace_id": "現在γγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚ΉID", + "scenes.app.popup.appsparameters.pages.smalltext_group_id": "現在γγ‚°γƒ«γƒΌγƒ—ID", + "scenes.app.mainview.channel_description": "チャネルに぀いてθͺ¬ζ˜Žγ™γ‚‹", + "scenes.client.channelbar.channeltemplateeditor.checkbox": "すべてγγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγƒ¦γƒΌγ‚ΆγƒΌγ‚’γ“γγƒγƒ£γƒγƒ«γ«θ‡ͺε‹•ηš„γ«ζ‹›εΎ…γ—γΎγ™", + "scenes.client.channelbar.channelmemberslist.title": "{{$1}}γγƒ¦γƒΌγ‚ΆγƒΌ", + "scenes.client.channelbar.channelmemberslist.loader": "もっとθͺ­γΏθΎΌγ‚€", + "scenes.client.channelbar.channelmemberslist.autocomplete": "γƒ¦γƒΌγ‚ΆγƒΌγ‚’θΏ½εŠ γΎγŸγ―ζ€œη΄’γ™γ‚‹", + "scenes.client.channelbar.channelmemberslist.menu.option_2": "γƒγƒ£γƒγƒ«γ‹γ‚‰ε‰Šι™€", + "components.leftbar.channel.workspaceschannels.menu.option_1": "γƒγƒ£γƒγƒ«γ‚’δ½œζˆγ™γ‚‹", + "components.leftbar.channel.workspaceschannels.menu.option_2": "γƒγƒ£γƒ³γƒγƒ«γ«ε‚εŠ γ™γ‚‹", + "components.channelworkspacelist.title": "チャンネル", + "scenes.client.channelbar.workspacechannellist.autocomplete": "γƒγƒ£γƒγƒ«γ€γƒ¦γƒΌγ‚ΆγƒΌγ€γΎγŸγ―γƒ€γ‚€γƒ¬γ‚―γƒˆγƒ‘γƒƒγ‚»γƒΌγ‚Έγ‚’ζ€œη΄’γ™γ‚‹", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_creation": "ζ–°γ—γ„γ‚Ώγƒ–γ‚’δ½œζˆγ™γ‚‹", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_edition": "名前を倉更{{$1}}", + "components.connectorslistmanager.add_connectors": "γ‚³γƒγ‚―γ‚Ώγ‚’θΏ½εŠ γ—γΎγ™", + "components.notifications.hidden_notifications_button.children": "新しいパッセージ", + "scenes.client.mainview.tabs.tabstemplateeditor.select_placeholder": "εΏœη”¨", + "scenes.client.channelbar.channelmemberslist.no_members": "こγγƒγƒ£γƒγƒ«γ«γ―γƒ¦γƒΌγ‚ΆγƒΌγŒγ„γΎγ›γ‚“γ€‚[ユーアーγθΏ½εŠ ]γ‚’γ‚―γƒͺックして招待できます。", + "scenes.app.channelsbar.hide_discussion_leaving.menu": "γƒ‡γ‚£γ‚Ήγ‚«γƒƒγ‚·γƒ§γƒ³γ‚’ιžθ‘¨η€Ί", + "scenes.app.popup.adduserfromtwakeconsole.current_users_state": "{{$1}}γƒ‘γƒΌγƒ«γŒθΏ½εŠ γ•γ‚ŒγΎγ™", + "components.newversion.new_version_component.row.part_1": "叀いバージョンγTwakeγ‚’εŸθ‘Œγ—ています", + "components.newversion.new_version_component.row.part_2": "γ‚’γƒ—γƒͺγ‚’γƒͺγƒ­γƒΌγƒ‰γ—γ¦γ€ζ–°ζ©Ÿθƒ½γ‚’γŠζ₯½γ—みください。", + "components.newversion.new_version_component.link": "γƒͺロードするには、ここをクγƒͺックしてください", + "components.newversion.new_version_modal.title": "ζ–°γ—γ„γ‚’γƒƒγƒ—γƒ‡γƒΌγƒˆγŒεˆ©η”¨ε―θƒ½γ§γ™οΌ", + "scenes.apps.drive.download_all_button": "すべてダウンロード", + "components.inputs.input_with_select.input.placeholder": "チャンネル名", + "components.inputs.input_with_select.select.placeholder": "セクション名", + "components.inputs.input_with_select.select.no_sections": "ζœ€εˆγγƒγƒ£γƒ³γƒγƒ«γ‚»γ‚―ションγεε‰γ‚’書き始めます。", + "components.inputs.input_with_select.button.tooltip": "チャネルセクションを設εšγ™γ‚‹", + "scenes.apps.messages.message.activity_message.a_added_b_to_the_channel": "{{$1}}が{{$2}}γ‚’γƒγƒ£γƒ³γƒγƒ«γ«θΏ½εŠ γ—γΎγ—γŸ", + "scenes.apps.messages.message.activity_message.a_updated_channel_description": "{{$1}}θͺ¬ζ˜Žγ‚’ε€‰ζ›΄γ—γΎγ—γŸ", + "scenes.apps.messages.message.activity_message.a_updated_channel_name": "{{$1}}はチャネルγεε‰γ‚’{{$2}}γ«ε€‰ζ›΄γ—γΎγ—γŸ", + "scenes.apps.messages.message.activity_message.a_created_channel_tab": "{{$1}}は新しい{{$2}}γ‚Ώγƒ–γ‚’θΏ½εŠ γ—γΎγ—γŸ{{$3}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_tab": "{{$1}}は{{$2}}γ‚Ώγƒ–{{$3}}γ‚’ε‰Šι™€γ—γΎγ—γŸ", + "scenes.apps.messages.message.activity_message.a_created_channel_connector": "{{$1}}γ―ζ–°γ—γ„γ‚³γƒγ‚―γ‚Ώγ‚’θΏ½εŠ γ—γΎγ—γŸ{{$2}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_connector": "{{$1}}γ‚³γƒγ‚―γ‚Ώγ‚’ε–γ‚Šε€–γ—γΎγ—γŸ{{$2}}", + "scenes.client.channelbar.channelmemberslist.tag": "君は", + "components.alert.leave_private_channel.title": "γƒγƒ£γƒ³γƒγƒ«γ‚’ι›’γ‚Œγ¦γ‚‚γ‚ˆγ‚γ—γ„γ§γ™γ‹οΌŸ", + "components.alert.leave_private_channel.description": "θͺ°γ‹γŒγ‚γͺγŸγ‚’ζ‹›εΎ…γ—γͺγ„ι™γ‚Šγ€γ“γγƒ—γƒ©γ‚€γƒ™γƒΌγƒˆγƒγƒ£γƒ³γƒγƒ«γ«ε†γ³ε‚εŠ γ™γ‚‹γ“γ¨γ―できません。", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.tag": "あγͺγŸγ―δΌšε“‘γ§γ―γ‚γ‚ŠγΎγ›γ‚“", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.loader": "もっとθͺ­γΏθΎΌγ‚€", + "general.re_send": "再送俑", + "general.verify": "η’Ίθͺ", + "components.unverified_account.typography_text_danger": "θ©¦η”¨ζœŸι–“γζ‹γ‚Šζ—₯数は{{$1}}γ§γ™γ€‚γƒˆγƒ©γ‚€γ‚’γƒ«γ‚’γ‚«γ‚¦γƒ³γƒˆγ―7ζ—₯εΎŒγ«γƒ–γƒ­γƒƒγ‚―γ•γ‚Œγ€η™»ιŒ²γ‹γ‚‰1γ‹ζœˆεΎŒγ«εŒε…¨γ«ε‰Šι™€γ•γ‚ŒγΎγ™γ€‚ι€δΏ‘γ•γ‚ŒγŸη’Ίθͺγƒ‘ールγ[γ‚’γ‚«γ‚¦γƒ³γƒˆγ‚’η’Ίθͺ]γƒœγ‚Ώγƒ³γ‚’γ‚―γƒͺγƒƒγ‚―γ™γ‚‹γ¨γ€γ‚’γ‚«γ‚¦γƒ³γƒˆγ‚’η’Ίθͺγ§γγΎγ™γ€‚", + "components.unverified_account.verification_details": "η’Ίθͺγθ©³η΄°γ‚’γ«ι€δΏ‘γ—γΎγ—γŸ", + "components.account_verication_status_unverified": "ζœͺη’Ίθͺ", + "components.account_verication_status_blocked": "γƒ­γƒƒγ‚―ζΈˆγΏ", + "components.unverified_account.re_send_email": "γƒ‘γƒΌγƒ«γŒε±ŠγγΎγ›γ‚“γ§γ—γŸγ‹οΌŸ", + "components.blocked_account.trial_period_over": "θ©¦η”¨ζœŸι–“γŒη΅‚δΊ†γ—γΎγ—γŸγ€‚γ‚’γ‚«γ‚¦γƒ³γƒˆγγƒ­γƒƒγ‚―を解陀してすべてγζ©Ÿθƒ½γ«γ‚’クセスするには、璺θͺγƒ‘γƒΌγƒ«γ§γ‚’γ‚«γ‚¦γƒ³γƒˆγ‚’η’Ίθͺγ—てください", + "components.add_mails_workspace.button": "Twakeγδ½Ώη”¨γ‚’開始します", + "services.console_services.toaster.success_verify_email": "η’Ίθͺγƒͺγƒ³γ‚―γŒγƒ‘γƒΌγƒ«γ‚’γ‚«γ‚¦γƒ³γƒˆγ«ι€δΏ‘γ•γ‚ŒγΎγ—γŸ", + "scenes.app.popup.workspaceparameter.edit_from_console": "コンソールで見る", + "services.console_services.toaster.success_invite_emails": "{{$1}}γƒ¦γƒΌγ‚ΆγƒΌγŒζ­£εΈΈγ«θΏ½εŠ γ•γ‚ŒγΎγ—γŸ", + "scenes.client.channels_bar.modals.guest_management.title": "{{$1}}γ§γ‚²γ‚Ήγƒˆγ‚’η‘理する", + "scenes.client.channels_bar.modals.guest_management.input_placeholder": "γ‚²γ‚ΉγƒˆγΎγŸγ―δΏη•™δΈ­γγƒ‘γƒΌγƒ«γ‚’ζ€œη΄’", + "scenes.client.channels_bar.modals.guest_management.tips": "上記γε…₯εŠ›γ‚’δ½Ώη”¨γ—γ¦γ€γƒ‘γƒΌγƒ«γθΏ½εŠ γΎγŸγ―ζ€œη΄’γ‚’ι–‹ε§‹γ—γΎγ™", + "scenes.client.channels_bar.modals.parts.channel_member_row.label.pending_email": "γƒ‘γƒΌγƒ«γŒι€δΏ‘γ•γ‚ŒγΎγ—γŸ", + "general.user.role.company.admin": "会瀾γη‘理者", + "general.user.role.company.guest": "γ‚²γ‚Ήγƒˆ", + "general.user.deleted": "ε‰Šι™€γ•γ‚ŒγŸγ‚’γ‚«γ‚¦γƒ³γƒˆ", + "components.richtexteditor.toolbar.bold": "倧胆γͺ", + "components.richtexteditor.toolbar.underline": "δΈ‹η·šγ‚’εΌ•γ", + "components.richtexteditor.toolbar.italic": "γ‚€γ‚Ώγƒͺック", + "components.richtexteditor.toolbar.strikethrough": "ε–γ‚ŠζΆˆγ—η·š", + "components.richtexteditor.toolbar.code": "コード", + "components.richtexteditor.toolbar.unordered-list": "η‡ζ‘書き", + "components.richtexteditor.toolbar.ordered-list": "注文γƒͺγ‚Ήγƒˆ", + "components.on_boarding.popups.blocked_company.company_subscription_plan_button": "ここをクγƒͺック", + "components.emoji_picker.categories.travel_and_places": "ζ—…θ‘Œγ¨ε ΄ζ‰€", + "components.emoji_picker.categories.objects": "γ‚ͺγƒ–γ‚Έγ‚§γ‚―γƒˆ", + "components.emoji_picker.categories.symbols": "記号", + "components.emoji_picker.categories.flags": "フラグ", + "components.emoji_picker.categories.search_result": "γζ€œη΄’硐果", + "components.emoji_picker.categories.not_found": "η΅΅ζ–‡ε­—γŒθ¦‹γ€γ‹γ‚ŠγΎγ›γ‚“", + "'": "'", + "\"": "γ€Œγ€", + "login.create_account": "γ‚’γ‚«γ‚¦γƒ³γƒˆγ‚’δ½œζˆγ™γ‚‹", + "scenes.apps.messages.message.types.no_message_in_thread": "まだθͺ°γ‚‚返事をしγͺγ‹γ£γŸγ€‚", + "login.login_error": "ログむン中γγ‚¨γƒ©γƒΌ", + "scenes.app.workspaces.welcome_page.no_workspace_subtitle": "まだθͺ°γ‚‚あγͺγŸγ‚’γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ«ζ‹›εΎ…γ—γ¦γ„γΎγ›γ‚“γ€‚", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.label": "γƒ‡γƒ•γ‚©γƒ«γƒˆγγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ή", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.description": "すべてγγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγƒ¦γƒΌγ‚ΆγƒΌγ‚’γ“γγƒγƒ£γƒγƒ«γ«θ‡ͺε‹•ηš„γ«ζ‹›εΎ…γ—γΎγ™", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.title": "{{$1}}γ‚’ε‰Šι™€γ—γ‚ˆγ†γ¨γ—γ¦γ„γΎγ™", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.alert_total_members": "{{$2}}にはまだ{{$1}}γƒ‘γƒ³γƒγƒΌγŒγ„γΎγ™γ€‚γ“γγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ‚’ε‰Šι™€γ§γγ‚‹γ‚ˆγ†γ«γ™γ‚‹γ«γ―γ€γ™γΉγ¦γγƒ‘γƒ³γƒγƒΌγ‚’ε‰Šι™€γ™γ‚‹εΏ…θ¦γŒγ‚γ‚ŠγΎγ™γ€‚", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.checkbox": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγγƒ‘γƒƒγ‚»γƒΌγ‚Έγ¨γƒ•γ‚‘γ‚€γƒ«γŒγ™γΉγ¦ε‰Šι™€γ•γ‚Œγ‚‹γ“γ¨γ‚’η†θ§£γ—γ¦γ„γΎγ™γ€‚", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.max_size": "γƒ­γ‚΄γζœ€ε€§γ‚΅γ‚€γ‚Ίγ―5MBです", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.bad_format": "ε½’εΌγŒζ­£γ—γγ‚γ‚ŠγΎγ›γ‚“γ€‚pnggifとjpgγγΏγŒθ¨±ε―γ•γ‚ŒγΎγ™", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.unknown": "不明γͺエラー", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.prefix": "エラー", + "scenes.app.channelsbar.currentuser.reset": "γƒͺγ‚»γƒƒγƒˆ", + "components.rich_text_editor.plugins.suggestions.default_message.display_results": "γƒ¦γƒΌγ‚ΆγƒΌγ‚’θ‘¨η€Ίγ™γ‚‹γŸγ‚γ«ε°‘γͺくとも3文字を書く", + "components.rich_text_editor.plugins.suggestions.default_message.no_user_found": "γƒ¦γƒΌγ‚ΆγƒΌγŒθ¦‹γ€γ‹γ‚ŠγΎγ›γ‚“", + "components.rich_text_editor.plugins.suggestions.default_message.no_emoji_found": "η΅΅ζ–‡ε­—γŒθ¦‹γ€γ‹γ‚ŠγΎγ›γ‚“", + "components.rich_text_editor.plugins.suggestions.default_message.no_command_found": "γ‚³γƒžγƒ³γƒ‰γŒθ¦‹γ€γ‹γ‚ŠγΎγ›γ‚“", + "scenes.app.messages.input.parts.is_writing.message.user_is_writing": "{{$1}}γŒζ›Έγ„γ¦γ„γΎγ™...", + "scenes.app.messages.input.parts.is_writing.message.users_are_writing": "{{$1}}と{{$2}}γŒζ›Έγ„γ¦γ„γΎγ™...", + "scenes.app.messages.input.parts.is_writing.message.users_and_more_are_writing": "{{$1}}、{{$2}}、{{$3}}γ‚ˆγ‚Šε€šγγγƒ¦γƒΌγ‚ΆγƒΌγŒζ›Έγ„ています...", + "components.locked_features_components.locked_invite_alert.message_part_1": "あγͺたγδΌšη€Ύγ―{{$1}}パンバーγδΈŠι™γ«ι”γ—γΎγ—γŸγ€‚γŠι‘˜γ„γ—γΎγ™ ", + "components.locked_features_components.locked_invite_alert.message_link": "あγͺたγδΌšη€Ύγ‚’γ‚’ップグレードする", + "components.locked_features_components.locked_invite_alert.message_part_2": " γ‚ˆγ‚Šε€šγγγƒ‘ンバーを招待します。", + "components.locked_features_components.locked_invite_alert.message_magic_link": " 会瀾γζ‰€ζœ‰θ€…γΎγŸγ―η‘理者に連硑してください。", + "views.client.popup.workspace_parameter.pages.workspace_members.link_to_console": "コンソールですべてγδΌšη€Ύγγƒ‘ンバーを見る", + "scenes.app.popup.appsparameters.pages.amazing_app_description": "γ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ‚’η°‘ε˜γ«θͺ¬ζ˜Žγ—てください", + "scenes.app.popup.appsparameters.pages.application_creator.checkbox": "こγδΌšη€Ύγζ‰€ζœ‰θ€…とη‘η†θ€…γŒγ“γγ‚’γƒ—γƒͺケーションを倉更して公開できることを理解しています。", + "scenes.app.popup.appsparameters.pages.application_creator.title": "ζ–°γ—γ„η΅±εˆ", + "twake.application.access.title": "γ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ«ι©γ—γŸγ‚Ήγ‚³γƒΌγƒ—γ‚’ιΈζŠžγ—γ¦γγ γ•γ„γ€‚", + "twake.application.access.no_default_scopes_available'": "こγη΅±εˆγ«γ―{{$1}}γ‚’γ‚―γ‚»γ‚Ήγ―γ‚γ‚ŠγΎγ›γ‚“", + "scenes.app.popup.appsparameters.pages.application_editor.help_link": "TwakeAPIドキγƒ₯γƒ‘γƒ³γƒˆ", + "scenes.app.popup.appsparameters.pages.application_editor.help_text": "γ“γ‚Œγ‚‰γ‚’εŸ‹γ‚γ‚‹ζ–Ήζ³•γŒγ‚γ‹γ‚‰γͺγ„ε ΄εˆγ―γ€ ", + "scenes.app.popup.appsparameters.pages.app.private_key": "η§˜ε―†ι΅", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed": "γ‚’γƒ—γƒͺケーション{{$1}}γŒζ­£εΈΈγ«ε‰Šι™€γ•γ‚ŒγΎγ—γŸοΌ", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed_error": "γ‚’γƒ—γƒͺケーションγε‰Šι™€δΈ­γ«γ‚¨γƒ©γƒΌγŒη™Ίη”Ÿγ—γΎγ—γŸ{{$1}}!", + "scenes.app.popup.appsparameters.pages.application_editor.application_published": "{{$1}}γ‚’γƒ—γƒͺγ‚±γƒΌγ‚·γƒ§γƒ³γ«ζˆεŠŸγ—γΎγ—γŸοΌ", + "scenes.app.integrations_parameters.add_application": "ζ–°γ—γ„η΅±εˆ", + "scenes.app.integrations_parameters.company_applications_table.more_menu.developer_settings": "ι–‹η™Ίθ€…θ¨­εš", + "components.rich_text_editor.plugins.suggestions.loading": "γ‚‚γ£γ¨γŠζŽ’γ—γ§γ™γ‹", + "components.open_desktop_popup.subtitle": "Twakeγ‚’γƒ—γƒͺγ§ι–‹γγΎγ—γŸ", + "components.open_desktop_popup.open_here_link": "δ»£γ‚γ‚Šγ«γ“γ“γ‚’ι–‹γ", + "molecules.download_banner.title": "Twakeγ‚’ζœ€ε€§ι™γ«ζ΄»η”¨γ—γ€δ»Šγ™γγƒ‡γ‚Ήγ‚―γƒˆγƒƒγƒ—γ‚’γƒ—γƒͺをダウンロードしてください", + "molecules.download_banner.download_button": "γƒ‡γ‚Ήγ‚―γƒˆγƒƒγƒ—γ‚’γƒ—γƒͺをダウンロード", + "scenes.app.channelsbar.channel_copy_link": "チャネルγƒͺンクをコピーする", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.success.update": "ζ­£εΈΈγ«ζ›΄ζ–°γ•γ‚ŒγΎγ—γŸ", + "components.searchpopup.no_results_for": "γη΅ζžœγ―γ‚γ‚ŠγΎγ›γ‚“γ§γ—γŸ", + "components.searchpopup.try_new_search": "ζ–°γ—γ„ζ€œη΄’γ‚’γŠθ©¦γ—γγ γ•γ„", + "components.searchpopup.all": "全て", + "components.searchpopup.chats": "γƒγƒ£γƒƒγƒˆ", + "components.searchpopup.media": "パディを", + "components.searchpopup.files": "フゑむル", + "components.searchpopup.recent_chats": "ζœ€θΏ‘γγƒγƒ£γƒƒγƒˆ", + "components.searchpopup.recent_media": "ζœ€θΏ‘γγƒ‘ディを", + "components.searchpopup.recent_files": "ζœ€θΏ‘δ½Ώη”¨γ—γŸγƒ•γ‚‘γ‚€γƒ«", + "components.searchpopup.recent_channels_and_contacts": "ζœ€θΏ‘γγƒγƒ£γƒ³γƒγƒ«γ¨ι€£η΅‘ε…ˆ", + "components.searchpopup.header_title": "ζŽ’γ™", + "components.searchpopup.scope.company": "すべてγδΌšη€Ύγ§", + "components.searchpopup.scope.channel": "こγγƒγƒ£γƒ³γƒγƒ«γ§", + "components.searchpopup.channels": "チャネル", + "components.searchpopup.messages": "パッセージ", + "scenes.client.join_public_channel": "こγγƒγƒ£γƒ³γƒγƒ«γ«ε‚εŠ γ™γ‚‹", + "general.yes": "はい", + "components.searchpopup.start_search": "いく぀かγγ‚­γƒΌγƒ―ードをε…₯εŠ›γ—γ¦ζ€œη΄’γ‚’ι–‹ε§‹γ—γΎγ™γ€‚", + "components.searchpopup.see_more": "ηΆšγγ‚’θ¦‹γ‚‹", + "scenes.client.channelbar.channelmemberslist.search_invite": "γƒ¦γƒΌγ‚ΆγƒΌγ‚’ζ€œη΄’γ—γ¦γ“γγƒγƒ£γƒγƒ«γ«ζ‹›εΎ…します", + "scenes.client.channelbar.channelmemberslist.search_invite_notice": "こγγƒγƒ£γƒ³γƒγƒ«γ«γ―倚くγγƒ‘γƒ³γƒγƒΌγŒγ„γΎγ›γ‚“γ€‚γƒ‘γƒΌγƒ«γΎγŸγ―εε‰γ§γƒ¦γƒΌγ‚ΆγƒΌγ‚’ζ€œη΄’γ—γ¦ζ‹›εΎ…γ—γΎγ™γ€‚", + "scenes.client.channelbar.channelmemberslist.invite_email_button": "γ‚²γ‚Ήγƒˆγ¨γ—γ¦γγΏγƒγƒ£γƒ³γƒγƒ«γ«θΏ½εŠ ", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace": "γƒγƒ£γƒ³γƒγƒ«γ¨γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ«γƒ‘γƒ³γƒγƒΌγ¨γ—γ¦θΏ½εŠ ", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace_confirm": "{{$1}}γ‚’γƒ‘γƒ³γƒγƒΌγ¨γ—γ¦γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ«ζ‹›εΎ…γ—γΎγ™γ‹οΌŸ", + "scenes.client.channelbar.channelmemberslist.search_invite_type_email": "γƒ‘γƒΌγƒ«γ§ζ‹›εΎ…γ™γ‚‹ζœ‰εŠΉγͺをドレスをε…₯εŠ›γ—γ¦γγ γ•γ„γ€‚", + "scenes.client.channelbar.channelmemberslist.pending_section": "招待を保留しているユーアー", + "scenes.client.channelbar.channelmemberslist.members_section": "こγγƒγƒ£γƒ³γƒγƒ«γγƒ¦γƒΌγ‚ΆγƒΌ", + "scenes.client.channelbar.channelmemberslist.not_members_section": "こγγƒγƒ£γƒ³γƒγƒ«γ«ε‚εŠ γ—γ¦γ„γͺいユーアー", + "scenes.client.join_private_channel.info": "こγγƒγƒ£γƒ³γƒγƒ«γγ“γγ‚³γƒ³γƒ†γƒ³γƒ„γ―εˆΆι™γ•γ‚Œγ¦γ„γ‚‹γ‹γ€ε­˜εœ¨γ—γΎγ›γ‚“γ€‚ζ‹›εΎ…γ‚’ε—γ‘γ‚‹γ«γ―γ€γ“γγƒγƒ£γƒ³γƒγƒ«γγƒ‘ンバーに連硑してください。", + "scenes.client.join_public_channel.info": "あγͺγŸγ―γ“γη›΄ζŽ₯チャンネルγγƒ‘γƒ³γƒγƒΌγ§γ―γ‚γ‚ŠγΎγ›γ‚“γ€‚γ“γγƒœγ‚Ώγƒ³γ‚’γ‚―γƒͺγƒƒγ‚―γ—γ¦γ€δ»Šγ™γγƒ‡γ‚£γ‚Ήγ‚«γƒƒγ‚·γƒ§γƒ³γ‚’ι–‹ε§‹γ—γ¦γγ γ•γ„γ€‚", + "general.no": "γ„γ„γˆ", + "components.open_desktop_popup.open_here_link_forever": "もう一度をプγƒͺを開こうとしγͺいでください", + "components.channel_attachement_list.medias": "パディを", + "components.channel_attachement_list.files": "フゑむル", + "components.channel_attachement_list.title": "チャネルフゑむルとパディを", + "components.channel_attachement_list.nothing_found": "γ“γ“γ«γ―γΎγ δ½•γ‚‚γ‚γ‚ŠγΎγ›γ‚“", + "molecules.message_quote.deleted": "こγγƒ‘γƒƒγ‚»γƒΌγ‚Έγ―ε‰Šι™€γ•γ‚ŒγΎγ—γŸ", + "components.channel_attachement_list.open": "γ‚ャラγƒͺーを開く", + "scenes.apps.messages.jump": "パッセージへジャンプ", + "scenes.apps.account.on_console": "グローバル γ‚’γ‚«γ‚¦γƒ³γƒˆθ¨­εšγ‚’編集するには、[コンソールに移動] γ‚’γ‚―γƒͺックします。", + "scenes.apps.account.assistant.title": "γ‚’γ‚·γ‚Ήγ‚Ώγƒ³γƒˆ", + "scenes.apps.account.assistant.description": "Twake γ‚’γ‚·γ‚Ήγ‚Ώγƒ³γƒˆγ―γ€Twake でγζ―Žζ—₯γδ½œζ₯­γ‚’理解し、1 ζ—₯γι–“γ«γ‚ΉγƒžγƒΌγƒˆγͺγ‚·γƒ§γƒΌγƒˆγ‚«γƒƒγƒˆγ¨γ‚’γ‚―γ‚·γƒ§γƒ³γ‚’ζδΎ›γ—γΎγ™γ€‚γ“γγ‚’γ‚·γ‚Ήγ‚Ώγƒ³γƒˆγ― Work@Home むニシをチブ https://workathome.linagora.com/ γδΈ€ιƒ¨γ§γ‚γ‚Šγ€ηΎεœ¨γ― Linagora 瀾でγγΏγƒ†γ‚Ήγƒˆγ•γ‚Œγ¦γŠγ‚Šγ€ε­¦ηΏ’ζ΅ιšŽγ«γ‚γ‚ŠγΎγ™γ€‚γ“γ‚Œγ―、将ζ₯γγ‚’γ‚·γ‚Ήγ‚Ώγƒ³γƒˆζ©Ÿθƒ½γ‚’γƒˆγƒ¬γƒΌγƒ‹γƒ³γ‚°γ™γ‚‹γŸγ‚γ«γ€Twake γδ½Ώη”¨ηŠΆζ³γƒ‡γƒΌγ‚Ώγ‚’ι€δΏ‘することを意味します。", + "scenes.apps.account.assistant.share.nothing": "γ‚’γ‚·γ‚Ήγ‚Ώγƒ³γƒˆγ¨γ―δ½•γ‚‚ε…±ζœ‰γ—γͺい (γ‚’γ‚·γ‚Ήγ‚Ώγƒ³γƒˆγ‚’η„‘εŠΉγ«γ™γ‚‹)", + "scenes.apps.account.assistant.share.all": "パッセージやフゑむルγε†…εΉγ‚’ε«γ‚€γ™γΉγ¦γ‚’ε…±ζœ‰γ™γ‚‹", + "scenes.apps.account.assistant.share.metadata": "コンテンツではγͺγγƒ‘γ‚Ώγƒ‡γƒΌγ‚Ώγ‚’ε…±ζœ‰γ™γ‚‹", + "scenes.apps.account.assistant.success": "θ¨­εšγŒζ­£εΈΈγ«ζ›΄ζ–°γ•γ‚ŒγΎγ—γŸγ€‚", + "components.message_seen_by.title": "γƒ‘γƒƒγ‚»γƒΌγ‚Έγ‚’θ¦‹γŸγƒ¦γƒΌγ‚ΆγƒΌ", + "components.message_seen_by.none_seen_it": "パッセージをまだθͺ°γ‚‚見ていません", + "components.message_seen_by.btn": "ζƒ…ε ±", + "molecules.quoted_content.attachements": "【X0Xγ€‘γ‚’γ‚Ώγƒƒγƒγƒ‘γƒ³γƒˆ", + "general.user.deactivated": "ユーアーはこγδΌšη€Ύγ«ζ‰€ε±žγ—ていません", + "scenes.apps.messages.message.user_deactivated": "ιžγ‚’γ‚―γƒ†γ‚£γƒ–εŒ–γ•γ‚ŒγŸγ‚’γ‚«γ‚¦γƒ³γƒˆγγ‚’ーカむブを葨瀺しています", + "general.user.connected": "γ‚ͺンラむン", + "scenes.app.popup.userparameter.pages.email_notif_delay_never": "δΈ€εΊ¦γ‚‚γͺい", + "scenes.app.popup.userparameter.pages.email_notif_delay_quarter_hour": "15εˆ†", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_day": "1ζ—₯", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_hour": "1ζ™‚ι–“", + "scenes.app.popup.userparameter.pages.notification_sound.defaut": "γƒ‡γƒ•γ‚©γƒ«γƒˆ", + "scenes.app.popup.userparameter.pages.notification_sound.none": "γͺし", + "scenes.client.channelbar.readonly_channel.checkbox": "ζ›ΈγθΎΌγΏθƒ½εŠ›γ‚’εˆΆι™γ™γ‚‹", + "scenes.apps.messages.message.forward": "前方", + "scenes.apps.messages.message.forward.title": "パッセージを軒送する", + "scenes.apps.messages.message.forward.comment": "γƒ‘γƒƒγ‚»γƒΌγ‚Έγ‚’θΏ½εŠ ", + "scenes.apps.messages.message.forward.confirm": "$1 チャンネルに送俑", + "scenes.apps.messages.message.forward.send": "γƒ‘γƒƒγ‚»γƒΌγ‚Έγ‚’θ»’ι€γ—γΎγ—γŸ", + "components.channelselector.title": "γƒγƒ£γƒ³γƒγƒ«γ‚’ιΈζŠž", + "components.channelselector.confirm": "$1 γƒγƒ£γƒ³γƒγƒ«γ‚’ιΈζŠž", + "components.channelselector.search": "γƒγƒ£γƒ³γƒγƒ«γ¨γƒ‡γ‚£γ‚Ήγ‚«γƒƒγ‚·γƒ§γƒ³γ‚’ζ€œη΄’", + "scenes.app.channelsbar.channel_information.logo.remove": "η”»εƒγ‚’ε‰Šι™€", + "scenes.app.channelsbar.channel_access": "チャンネルへγγ‚’γ‚―γ‚»γ‚Ή", + "scenes.app.channelsbar.channel_access.save": "γ‚’γ‚―γ‚»γ‚Ήθ¨­εšγ‚’δΏε­˜", + "scenes.app.channelsbar.channel_access.readonly": "θͺ­γΏε–γ‚Šε°‚η”¨γƒγƒ£γƒγƒ«", + "scenes.app.channelsbar.channel_access.readonly.info": "書き込みをヒデレーター、η‘η†θ€…γ€γŠγ‚ˆγ³ζ‰€ζœ‰θ€…γ«εˆΆι™γ—γΎγ™γ€‚", + "scenes.app.channelsbar.channel_access.visibility": "δΈ€θˆ¬ε…¬ι–‹", + "scenes.app.channelsbar.channel_access.visibility.info": "η€Ύε“‘δ»₯ε€–γͺらどγͺγŸγ§γ‚‚ε‚εŠ γ§γγΎγ™γ€‚", + "scenes.app.channelsbar.channel_access.default": "θ‡ͺε‹•ε‚εŠ ", + "scenes.app.channelsbar.channel_access.default.info": "新しいパンバーはここにθ‡ͺε‹•ηš„γ«θΏ½εŠ γ•γ‚ŒγΎγ™γ€‚", + "scenes.app.channelsbar.channel_information": "チャンネル情報を編集する", + "scenes.app.channelsbar.channel_information.logo.add": "ε†™ηœŸγ‚’γ‚’γƒƒγƒ—γƒ­γƒΌγƒ‰γ™γ‚‹", + "scenes.app.channelsbar.channel_information.name": "チャンネル名", + "scenes.app.channelsbar.channel_information.description": "チャンネルγθͺ¬ζ˜Ž", + "scenes.app.channelsbar.channel_information.description.placeholder": "チャンネルγθͺ¬ζ˜Žγ€γƒžγƒΌγ‚―ダウンを使用できます。", + "scenes.app.channelsbar.channel_information.group": "チャンネルグループ", + "scenes.app.channelsbar.channel_information.group.none": "ιΈζŠžγ•γ‚Œγ¦γ„γͺい", + "scenes.app.channelsbar.channel_information.group.new": "ζ–°γ—γ„γ‚°γƒ«γƒΌγƒ—γ‚’δ½œζˆγ™γ‚‹", + "scenes.app.channelsbar.channel_information.group.save": "チャネル グループを $1 に設εš", + "scenes.app.channelsbar.channel_information.group.save_none": "チャネルグループを設εšγ—γͺい", + "scenes.app.channelsbar.channel_information.save": "δΏε­˜ζƒ…ε ±", + "components.invitation.invitation_sent.link": "ζ‹›εΎ…ηŠΆζ³γ‚’η’Ίθͺγ™γ‚‹", + "scenes.client.channelbar.channelmemberslist.invite_to_workspace": "{{$1}}γ‚’γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ«ζ‹›εΎ…βž‘", + "components.invitation.reached_limit.text": "η€Ύε†…γζœ€ε€§γƒ¦γƒΌγ‚ΆγƒΌζ•°γ«ι”γ—γΎγ—γŸγ€‚γ‚΅γƒ–γ‚Ήγ‚―γƒͺγƒ—γ‚·γƒ§γƒ³γ‚’ε’—γ‚„γ™γ‹γ€γ“γ‚Œγ‚‰γγƒ¦γƒΌγ‚ΆγƒΌγ‚’γ‚²γ‚Ήγƒˆγ¨γ—γ¦θΏ½εŠ γ—γ¦γγ γ•γ„", + "components.invitation.allow_anyone_by_email.text": "@{{$1}} γγƒ‘γƒΌγƒ«γ‚’γƒ‰γƒ¬γ‚Ήγ‚’ζŒγ£γ¦γ„γ‚‹δΊΊγͺらθͺ°γ§γ‚‚こγγƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήγ«ε‚εŠ γ§γγΎγ™", + "components.invitation.invitation_channels.button": "チャンネルに招待する", + "components.invitation.invitation_input_list.add": "追加", + "components.invitation.invitation_input_list.member": "パンバー", + "components.invitation.invitation_input_list.guest": "γ‚²γ‚Ήγƒˆ", + "components.invitation.invitation_input_list.placeholder": "パールγε…₯εŠ›γ‚’ι–‹ε§‹γ™γ‚‹", + "components.invitation.invitation_sent.title": "ζ‹›εΎ…ηŠΆγ―ζ­£εΈΈγ«ι€δΏ‘γ•γ‚ŒγΎγ—γŸ", + "components.invitation.invitation_sent.subtitle_status": "ζ‹›εΎ…ηŠΆζ³γ―ζ¬‘γε ΄ζ‰€γ§θΏ½θ·‘できます。", + "components.invitation.invitation_sent.subtitle_location": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚Ήθ¨­εš > パンバーη‘理", + "components.invitation.invitation_sent.button": "γ•γ‚‰γ«ζ‹›εΎ…ηŠΆγ‚’ι€γ‚‹", + "components.invitation.invitation_target.invite_as_guests": "ε…¨ε“‘γ‚’γ‚²γ‚Ήγƒˆγ¨γ—γ¦ζ‹›εΎ…", + "components.invitation.invitation_target.invite_as_members": "全哑をパンバーとして招待", + "components.invitation.workspace_link.button": "コピー", + "components.invitation.invitation_target.channels_button": "招待するチャンネル", + "components.invitation.workspace_link.text": "γƒ―γƒΌγ‚―γ‚ΉγƒšγƒΌγ‚ΉγΈγζ‹›εΎ…γƒͺンク", + "components.invitation.title": "{{$1}} に招待する", + "components.invitation.bulk_invitation": "一括招待", + "components.invitation.button": "ζ‹›εΎ…ηŠΆγ‚’ι€γ‚‹", + "scenes.client.readonly.info": "こγγƒγƒ£γƒ³γƒγƒ«γ―θͺ­γΏε–γ‚Šε°‚η”¨γγƒ•γ‚£γƒΌγƒ‰γ§γ™γŒγ€γ‚Ήγƒ¬γƒƒγƒ‰γ«γ‚³γƒ‘γƒ³γƒˆγ§γγΎγ™γ€‚", + "scenes.app.channelsbar.channel_information.group.title": "チャネル グループ", + "components.invitation.custom_role_invitation": "ε€ε…Έηš„γͺζ‹›εΎ…ηŠΆ", + "components.invitation.link": "γƒͺンク" +} diff --git a/twake/frontend/public/locales/nb_NO.json b/twake/frontend/public/locales/nb_NO.json new file mode 100644 index 00000000..eca59fa1 --- /dev/null +++ b/twake/frontend/public/locales/nb_NO.json @@ -0,0 +1,1008 @@ +{ + "general.close": "Lukk", + "general.save": "Lagre", + "general.cancel": "Avbryt", + "general.retry": "PrΓΈv om igjen", + "general.create": "Opprett", + "general.edit": "Rediger", + "general.delete": "Slett", + "general.continue": "Fortsett", + "general.confirm": "Bekreft", + "general.archive": "Arkiver", + "general.help": "Hjelp", + "general.help.support": "StΓΈtte", + "general.send": "Send melding", + "general.update": "Oppdater", + "general.remove": "Fjern", + "general.add": "Legg til", + "general.connexion_status.disconnected": "Du er frakoblet", + "general.connexion_status.connected": "Du er tilkoblet", + "general.connexion_status.connecting": "Kobler til pΓ₯ nytt…", + "application.load.longer": "Serveren bruker lenger tid enn vanlig pΓ₯ Γ₯ svare, vennligst vent eller last inn siden pΓ₯ nytt…", + "scenes.app.side_app.messages_thread_title": "{{$1}} β€’ MeldingstrΓ₯d", + "scenes.app.workspaces.create_company.group_data": "Konfigurer den nye gruppen", + "scenes.app.workspaces.create_company.group_data.group_type": "Gruppetype", + "scenes.app.workspaces.create_company.group_data.group_type.public_organization": "Offentlig organisasjon", + "scenes.app.workspaces.create_company.group_data.group_type.university_school": "Universitet eller skole", + "scenes.app.workspaces.create_company.group_data.group_type.society_club_charity": "Samfunn, klubb eller veldedighet", + "scenes.app.workspaces.create_company.group_data.group_size": "GruppestΓΈrrelse", + "scenes.app.workspaces.create_company.group_data.group_size.100_500": "100 - 499 brukere", + "scenes.app.workspaces.create_company.group_data.group_size.500_1000": "500 - 999 brukere", + "scenes.app.workspaces.create_company.group_data.group_size.1000_5000": "1000 - 4999 brukere", + "scenes.app.workspaces.create_company.group_data.group_size.5000_more": "Flere enn 5000 brukere", + "scenes.app.workspaces.create_company.group_data.group_main_activity": "Hovedaktivitet", + "scenes.app.workspaces.create_company.group_data.group_main_activity.food": "Mat", + "scenes.app.workspaces.create_company.group_data.group_main_activity.bank": "Bank / Forsikring", + "scenes.app.workspaces.create_company.group_data.group_main_activity.printing_paper": "Utskrift / Papir", + "scenes.app.workspaces.create_company.group_data.group_main_activity.construction_building": "Konstruksjon / Byggematerialer", + "scenes.app.workspaces.create_company.group_data.group_main_activity.real_estate": "Eiendom", + "scenes.app.workspaces.create_company.group_data.group_main_activity.materials": "Materialer", + "scenes.app.workspaces.create_company.group_data.group_main_activity.chemistry": "Kjemi", + "scenes.app.workspaces.create_company.group_data.group_main_activity.trade_commerce_distribution": "Handel / Distribusjon", + "scenes.app.workspaces.create_company.group_data.group_main_activity.publishing_communication_multimedia": "Forlag / Kommunikasjon / Multimedia", + "scenes.app.workspaces.create_company.group_data.group_main_activity.electronics_electricity_energy": "Elektronikk / Elektrisitet / Energi", + "scenes.app.workspaces.create_company.group_data.group_main_activity.studies_and_advice": "Studier og rΓ₯d", + "scenes.app.workspaces.create_company.group_data.group_main_activity.pharmaceutical_industry": "Apotekindustri", + "scenes.app.workspaces.create_company.group_data.group_main_activity.it_telecom": "IT / Telekommunikasjon", + "scenes.app.workspaces.create_company.group_data.group_main_activity.machinery_automotive": "Maskineri / Bil", + "scenes.app.workspaces.create_company.group_data.group_main_activity.business_services": "Forretningstjenester", + "scenes.app.workspaces.create_company.group_data.group_main_activity.entertainment": "Underholdning", + "components.users_picker.add_me": "Legg meg til", + "scenes.app.header.disconnected": "Du er frakoblet", + "scenes.app.header.disconnected.reload": "Last inn pΓ₯ nytt", + "scenes.app.header.alt_notifications": "Varsler", + "scenes.apps.calendar.event_edition.title_confidentiality": "Konfidensialitet", + "scenes.apps.calendar.calendar_modal.participants": "Deltagere", + "scenes.apps.calendar.calendar_modal.placeholder": "Navn", + "scenes.apps.calendar.left.calendars": "Kalendere", + "scenes.apps.drive.left.search": "SΓΈk", + "scenes.apps.drive.navigators.navigator_content.directory_name": "Navn pΓ₯ filsti", + "scenes.apps.drive.navigators.navigator_content.files": "Filer", + "scenes.apps.drive.navigators.navigator_labels.title": "Merkelapper", + "scenes.apps.drive.navigators.new_file.create_file.type": "Type", + "scenes.apps.drive.navigators.new_file": "Ny fil", + "scenes.apps.drive.preview_bloc.operations_download": "Last ned", + "scenes.apps.drive.preview_bloc.error_file": "Fil ikke funnet", + "scenes.apps.drive.right_preview.operations_restore": "Gjenopprett", + "scenes.apps.drive.right_preview.operations_delete": "Flytt til sΓΈppelbΓΈtte", + "scenes.apps.messages.messages": "Meldinger", + "scenes.apps.messages.chatbox.chat.delete_message": "Slett denne meldingen", + "scenes.apps.messages.chatbox.chat.delete_message_btn": "Slett melding", + "general.back": "Tilbake", + "scenes.app.workspaces.create_company.group_data.group_size.10_50": "11 - 49 brukere", + "general.help.documentation": "Dokumentasjon", + "scenes.app.workspaces.create_company.group_data.group_type.other_group": "Annet", + "scenes.app.workspaces.create_company.group_data.group_size.4_10": "4 - 10 brukere", + "scenes.app.workspaces.create_company.group_data.group_type.company": "Firma eller firmaavdeling", + "scenes.app.workspaces.create_company.group_data.group_size.50_100": "50 - 99 brukere", + "scenes.app.workspaces.create_company.group_data.group_main_activity.textile_clothing_shoes": "Tekstil / KlΓ¦r / Sko", + "scenes.app.workspaces.create_company.group_data.group_size.less_3": "Mindre enn 4 brukere", + "scenes.app.workspaces.create_company.group_data.group_main_activity.education": "Utdanning", + "components.application.messages": "Meldinger", + "scenes.app.workspaces.create_company.group_data.group_main_activity.transport_logistics": "Transport / Logistikk", + "scenes.app.workspaces.create_company.group_data.group_main_activity.research": "Forskning", + "scenes.app.workspaces.create_company.group_data.group_main_activity.administration": "Administrasjon", + "scenes.app.workspaces.create_company.group_data.group_main_activity.other": "Annet", + "scenes.apps.calendar.calendar.list_btn": "Liste", + "components.drive_dropzone.uploading": "Laster opp…", + "components.user_picker.modal_no_result": "Ingen resultater funnet", + "scenes.app.workspaces.create_company.invitations.title": "Konfigurer arbeidsrommet ditt.", + "scenes.apps.calendar.event_edition.deadline_tag": "Deadline", + "scenes.apps.calendar.event_edition.checkbox_all_day": "Hele dagen", + "scenes.apps.calendar.calendar.week_btn": "Uke", + "scenes.apps.drive.navigators.new_file.untitled": "Uten navn", + "scenes.apps.drive.right_preview.public_link": "Offentlig lenke", + "scenes.app.popup.appsparameters.pages.remove_app_button": "Slett sΓΈknad", + "scenes.apps.calendar.modals.details_title": "Detaljer", + "scenes.apps.board.new_task": "+ Ny oppgave", + "scenes.app.popup.workspace.edit_temp": "Rediger midlertidig konto", + "scenes.app.popup.adduserfromtwakeconsole.current_users_state": "{{$1}} e-post(er) vil bli lagt til", + "components.newversion.new_version_component.row.part_1": "Du kjΓΈrer en utdatert Twake-versjon", + "scenes.apps.messages.message.activity_message.a_updated_channel_name": "{{$1}} ga nytt navn til kanalen til {{$2}}", + "scenes.apps.messages.message.activity_message.a_created_channel_tab": "{{$1}} la til en ny {{$2}}-fane {{$3}}", + "scenes.client.channelbar.channelmemberslist.tag": "Du", + "scenes.app.integrations_parameters.title": "Integrasjoner", + "scenes.app.integrations_parameters.applications_table.name": "Navn", + "scenes.app.integrations_parameters.applications_table.title": "Andre integrasjoner", + "scenes.app.integrations_parameters.applications_table.search_placeholder": "SΓΈkeapplikasjon", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.website_item": "Nettsted", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.created_item": "Opprettelsesdato", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.version_item": "Versjon", + "scenes.app.integrations_parameters.company_applications_table.more_menu.show_application": "Forestilling", + "scenes.app.integrations_parameters.company_applications_table.more_menu.remove_application": "Fjern fra selskapet", + "scenes.apps.messages.input.replied_to": "svarte pΓ₯ ", + "scenes.join.login_first_button": "Logg inn eller opprett en konto fΓΈrst", + "scenes.join.join_the_team_button": "Bli med pΓ₯ laget", + "scenes.app.popup.appsparameters.pages.website_label": "Nettsted", + "scenes.app.popup.appsparameters.pages.write_privileges_label": "Skriveprivilegier", + "scenes.app.popup.appsparameters.pages.danger_zone_small_text": "Du kan ikke slette denne appen hvis den er publisert.", + "scenes.app.popup.appsparameters.pages.error_app_update_message": "Det oppstod en feil under oppdatering av applikasjonen.", + "scenes.app.popup.workspaceparameter.pages.apps_research_title": "SΓΈk i applikasjoner", + "scenes.app.popup.workspaceparameter.pages.apps_small_text": "Applikasjoner av dette arbeidsomrΓ₯det", + "scenes.app.popup.workspaceparameter.pages.back_to_search_button": "GΓ₯ tilbake til sΓΈket", + "scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button": "Inviter brukere", + "scenes.app.popup.workspaceparameter.pages.collaborateurs": "Brukere", + "scenes.app.popup.workspaceparameter.pages.company_developped_apps_subtitle": "Applikasjoner utviklet av selskapet", + "scenes.app.popup.workspaceparameter.pages.company_identity_title": "Identiteten til selskapet", + "scenes.app.popup.workspaceparameter.pages.apps_connectors_title": "Integrasjoner", + "scenes.apps.calendar.day_option": "Dag", + "scenes.apps.calendar.modals.modify_event_button": "Rediger hendelse", + "scenes.apps.calendar.modals.part.participants": "Deltakere", + "scenes.apps.drive.throw_menu": "Send til sΓΈpla", + "scenes.apps.drive.trash_empty_menu": "TΓΈm sΓΈpla", + "scenes.help_us": "Men hvis du ΓΈnsker Γ₯ hjelpe oss med Γ₯ fikse denne feilen, send oss en melding nedenfor: ", + "scenes.login.verifymail.alert": "Vi sjekker e-posten din!", + "scenes.login.verifymail.error_message": "En feil oppstod", + "scenes.apps.calendar.unconfigured_tab": "Denne fanen er ikke konfigurert ennΓ₯.", + "scenes.apps.drive.trash": "SΓΈppel", + "scenes.apps.drive.top_menu_more": "Mer", + "scenes.apps.drive.top_menu_no_items": "{{$1}} elementer", + "scenes.apps.messages.new_thread": "Start en ny diskusjon", + "scenes.apps.messages.input.send_message": "Sende melding", + "scenes.apps.messages.input.emoji": "Emoji", + "scenes.apps.messages.input.hide_formatting": "Skjul formatering", + "scenes.apps.messages.input.show_formatting": "Vis formatering", + "scenes.tell_us": "Fortell oss hva du gjorde pΓ₯:", + "scenes.apps.drive.viewer.download_desktop": "Last ned Twake Desktop for Γ₯ forhΓ₯ndsvise i appen", + "scenes.apps.tasks.my_tasks": "Mine oppgaver", + "scenes.apps.tasks.board.place_holder": "Styrenavn", + "scenes.apps.tasks.board.tasks.subtask": "Deloppgave", + "scenes.apps.tasks.board.tasks.add_subtask": "Legg til en deloppgave", + "scenes.apps.tasks.board.tasks.use_deadline": "Bruk frist", + "scenes.apps.parameters.workspace_sections.members.invite_all": "Inviter alle", + "scenes.app.taskpicker.select": "Plukke ut", + "components.listmanager.filter": "Filter", + "scenes.apps.tasks.no_connector": "Ingen kontakt", + "scenes.apps.drive.used": "brukt i denne mappen", + "components.reminder.notification": "Melding", + "components.reminder.minutes_bef": "minutter fΓΈr", + "components.reminder.hours_bef": "timer fΓΈr", + "components.reminder.days_bef": "dager fΓΈr", + "components.reminder.weeks_bef": "uker fΓΈr", + "components.reminder.by_email": "E-post", + "components.alert.leave_private_channel.title": "Er du sikker pΓ₯ at du vil forlate kanalen?", + "components.alert.leave_private_channel.description": "Du vil ikke kunne bli med i denne private kanalen igjen med mindre noen inviterer deg.", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.tag": "Du er ikke medlem", + "components.emoji_picker.categories.frequently_used": "Ofte brukt", + "components.emoji_picker.categories.smileys_and_people": "Smileys og mennesker", + "components.emoji_picker.categories.animals_and_nature": "Dyr og natur", + "components.emoji_picker.categories.food_and_drink": "Mat drikke", + "components.emoji_picker.categories.activity": "Aktivitet", + "components.emoji_picker.categories.travel_and_places": "Reise og steder", + "components.emoji_picker.categories.objects": "Objekter", + "components.emoji_picker.categories.symbols": "Symboler", + "components.emoji_picker.categories.flags": "Flagg", + "components.emoji_picker.categories.search_result": "SΓΈkeresultater", + "scenes.apps.messages.left_bar.stream.add_to_favorites": "Legg til i favoritter", + "scenes.apps.messages.left_bar.stream.remove_from_favorites": "Fjern fra favoritter", + "scenes.apps.messages.left_bar.stream.notifications": "Varsler...", + "scenes.apps.messages.left_bar.stream.notifications.all": "Enhver melding", + "scenes.apps.messages.left_bar.stream.notifications.mentions": "{{$1}}, {{$2}} og {{$3}}", + "scenes.apps.messages.left_bar.stream.notifications.me": "Bare {{$1}}", + "scenes.apps.messages.left_bar.stream.notifications.never": "Ingenting", + "scenes.apps.parameters.workspace_sections.workspace": "ArbeidsomrΓ₯de", + "scenes.apps.parameters.workspace_sections.members": "Deltakere", + "scenes.apps.parameters.group_sections.workspaces": "ArbeidsomrΓ₯der", + "scenes.apps.parameters.group_sections.apps": "Apper", + "scenes.apps.account.title": "Kontoparametere", + "scenes.apps.account.languages.menu_title": "SprΓ₯k", + "scenes.apps.account.account.firstname": "Fornavn", + "scenes.apps.account.account.lastname": "Etternavn", + "scenes.apps.account.account.username": "Brukernavn", + "scenes.apps.account.account.change_username": "Endre ditt unike brukernavn.", + "scenes.apps.account.account.emails": "E-poster", + "scenes.apps.account.account.main_email": "Hoved e-post", + "scenes.apps.account.account.email_add": "Legg til ny e-post", + "scenes.apps.account.account.email_add_modal.invalid_code": "Denne koden er ugyldig", + "scenes.apps.account.account.password": "Passord", + "scenes.apps.account.account.password_modal.old_password": "NΓ₯vΓ¦rende passord", + "scenes.apps.account.account.password_modal.password": "Nytt passord", + "scenes.apps.account.account.password_modal.bad_old_password": "Gammelt passord er ikke riktig.", + "scenes.apps.account.account.password_modal.bad_password": "Passordene dine stemmer ikke overens, eller de er for korte. Vennligst skriv inn et passord med minst 8 tegn.", + "scenes.apps.account.account.logout": "Logg ut", + "scenes.apps.account.languages.text": "Endre Twake-sprΓ₯ket.", + "scenes.apps.account.notifications.title": "Varsler", + "scenes.apps.account.notifications.keywords_subtitle": "NΓΈkkelord", + "scenes.apps.account.notifications.keywords_placeholder": "dev, wifi, kode, ...", + "scenes.apps.account.notifications.disturb_option_a": "Ikke send meg push-varsler mellom ", + "scenes.apps.account.notifications.disturb_option_b": " og ", + "scenes.apps.account.notifications.disturb_option_c": " (lokal tidssone)", + "scenes.apps.account.notifications.devices_subtitle": "Enhetsvarsler", + "scenes.apps.account.notifications.devices_option_ever": "Send meg alltid push-varsler", + "scenes.apps.account.notifications.devices_option_inactive": "Send meg push-varsler nΓ₯r jeg er inaktiv pΓ₯ skrivebordet", + "scenes.apps.account.notifications.devices_option_never": "Send meg aldri push-varsler", + "scenes.apps.account.notifications.privacy_subtitle": "Personvern", + "scenes.apps.account.notifications.mail_subtitle": "E-postvarsler", + "scenes.apps.account.notifications.sound": "Lydvarsling", + "scenes.apps.parameters.group_sections.apps.badge_extension": "Utvidelse", + "scenes.apps.parameters.workspace_sections.members.members": "Brukere", + "scenes.apps.parameters.workspace_sections.members.pending": "Ventende e-poster", + "scenes.apps.parameters.workspace_sections.members.invite": "Inviter ny bruker", + "scenes.apps.parameters.workspace_sections.members.invite_btn": "Legg til bruker", + "scenes.apps.tasks.connectors_menu": "Koblinger...", + "scenes.apps.tasks.connectors_search_menu": "SΓΈk etter koblinger...", + "scenes.apps.tasks.no_connectors_menu_text": "Du har ingen koblinger som kan kobles til en kalender.", + "scenes.apps.tasks.unconfigured_tab": "Denne fanen er ikke konfigurert ennΓ₯.", + "scenes.apps.tasks.choose_board_button": "Velg et brett", + "scenes.apps.tasks.new_board.title": "Nytt styre", + "scenes.apps.tasks.new_board.edit_title": "Rediger tavle", + "scenes.apps.tasks.task": "Oppgave", + "scenes.apps.tasks.no_tasks": "Ikke spΓΈr", + "scenes.apps.tasks.task_status.todo": "Γ… gjΓΈre", + "scenes.apps.tasks.task_status.current": "StrΓΈm", + "scenes.apps.tasks.task_status.done": "Ferdig", + "scenes.apps.tasks.task.description": "Beskrivelse", + "scenes.apps.tasks.task.assignees": "Oppdragstakere", + "scenes.apps.tasks.task.edit.dates": "Datoer", + "scenes.apps.tasks.list_modal.modify_list": "Endre listen", + "scenes.apps.tasks.list_modal.new_list": "Ny liste", + "scenes.apps.tasks.list_modal.remove": "Fjern liste og oppgaver", + "scenes.apps.tasks.list_modal.predefined_participants": "ForhΓ₯ndsdefinerte deltakere", + "scenes.apps.tasks.list_modal.archive_all_tasks": "Arkiver alle oppgaver", + "scenes.apps.tasks.list_modal.remove_archived_tasks": "Fjern arkiverte oppgaver ({{$1}})", + "scenes.login.footer.go_to_twake": "GΓ₯ til twakeapp.com", + "scenes.login.footer.branding": "Du er pΓ₯ en {{$1}} ({{$2}}) privat Twake-server. ", + "scenes.login.create_account.title": "Lag en ny bruker", + "scenes.login.create_account.email": "E-post", + "scenes.login.create_account.email_used": "Denne e-posten er allerede i bruk.", + "scenes.login.create_account.username": "Brukernavn", + "scenes.login.create_account.username_already_exist": "dette brukernavnet er allerede i bruk", + "scenes.login.create_account.fill_in_username": "Du mΓ₯ fylle inn brukernavnet ditt", + "scenes.login.create_account.fill_in_email": "Du mΓ₯ fylle ut e-posten din med riktig e-post", + "scenes.login.create_account.too_short_password": "Passordet ditt mΓ₯ inneholde minst 8 tegn.", + "scenes.login.create_account.firstname": "Fornavn", + "scenes.login.create_account.newsletter": "Motta informasjon om Twake", + "scenes.login.create_account.lastname": "Etternavn", + "scenes.login.forgot_password.title": "Glemt passord?", + "scenes.login.forgot_password.text": "Du vil motta en 9-sifret kode pΓ₯ e-post for Γ₯ bekrefte identiteten din.", + "scenes.login.forgot_password.email_to_recover": "E-post for Γ₯ gjenopprette", + "scenes.login.forgot_password.mail_doesnt_exist": "Denne e-posten eksisterer ikke", + "scenes.login.forgot_password.text2": "Du vil motta en 9-sifret kode. Vennligst skriv det inn i feltet under for Γ₯ fortsette.", + "scenes.login.forgot_password.invalid_code": "Denne koden er ikke gyldig.", + "scenes.login.forgot_password.text3": "Skriv inn et nytt passord for kontoen din.", + "scenes.login.forgot_password.password": "Passord", + "scenes.login.forgot_password.password2": "Bekreft passord", + "scenes.login.forgot_password.password_dont_match": "Passordene dine stemmer ikke overens, eller de er for korte. Vennligst skriv inn et passord med minst 8 tegn.", + "scenes.login.home.title": "Logg pΓ₯ Twake", + "scenes.login.home.subtitle": "Glad for Γ₯ se deg", + "scenes.login.home.email": "E-post", + "scenes.login.home.unable_to_connect": "Ugyldige legitimasjon", + "scenes.login.home.password": "Passord", + "scenes.login.home.login_btn": "Logg Inn", + "scenes.login.home.lost_password": "Glemt passord?", + "scenes.login.home.create_account": "Opprett en konto", + "scenes.login.create_account.password": "Passord", + "scenes.login.create_account.step_1_subtitle": "Det kunne ikke vΓ¦rt enklere – vi trenger bare litt informasjon.", + "scenes.login.create_account.step_2_subtitle_a": "Legg til hele navnet ditt slik at andre brukere kan gjenkjenne deg.", + "scenes.login.create_account.step_2_subtitle_b": "Telefonnummeret ditt forblir privat.", + "scenes.login.create_account.step_3_mail_sent": "Vi har sendt deg en aktiveringslenke pΓ₯ e-post.", + "scenes.login.create_account.step_3_subtitle": "Siste trinn – vi mΓ₯ bekrefte at du ikke er en robot!", + "scenes.app.workspaces.create_company.company_name.placeholder": "Selskapsnavn", + "scenes.app.workspaces.create_company.company_name.title_1": "Γ… begynne,", + "scenes.app.workspaces.create_company.company_name.title_2": "angi navnet pΓ₯ bedriften din.", + "scenes.app.workspaces.create_company.default_workspace_name": "Hoved", + "scenes.app.workspaces.create_company.importations.title_1": "Jobber du allerede med digitale verktΓΈy? Importer eller integrer verktΓΈyene dine nΓ₯!", + "scenes.app.workspaces.create_company.importations.title_2": "Ingen grunn til bekymring, du kan gjΓΈre dette senere!", + "scenes.app.workspaces.create_company.invitations.title_2": "Legg til brukere i teamet ditt.", + "scenes.app.workspaces.create_company.title": "Opprett firmaet mitt", + "scenes.app.workspaces.welcome_page.add_secondary_emails": "Legg til en sekundΓ¦r e-post", + "scenes.app.workspaces.welcome_page.added_to_company": "Du er invitert til ", + "scenes.app.workspaces.welcome_page.create_my_company": "Opprett firmaet mitt", + "scenes.app.workspaces.welcome_page.lets_go": "La oss gΓ₯!", + "scenes.app.workspaces.welcome_page.may_be_invited_with_secondary_emails": "Ble du invitert med en annen e-postadresse?", + "scenes.app.workspaces.welcome_page.no_company_subtitle": "Γ…, vel... Det ser ut til at ingen har invitert deg til en arbeidsplass ennΓ₯.", + "scenes.app.workspaces.welcome_page.ready_to_work": "Du er klar til Γ₯ jobbe nΓ₯.", + "scenes.app.workspaces.welcome_page.see_you_soon": "Ser deg snart!", + "scenes.app.workspaces.welcome_page.try_again": "PrΓΈv igjen", + "scenes.app.workspaces.welcome_page.twake_team": "Twake", + "scenes.app.workspaces.welcome_page.welcome_header": "Velkommen til Twake!", + "scenes.app.workspaces.welcome_page.add_secondary_emails_comment": "Du kan koble flere e-postadresser til kontoen din; kun Γ©n adresse vil bli brukt til Γ₯ sende deg varsler.", + "scenes.app.workspaces.welcome_page.main_mail_title": "Hovedadresse", + "scenes.app.workspaces.welcome_page.other_mail_title": "SekundΓ¦re adresser", + "scenes.app.workspaces.welcome_page.add_new_email": "Legg til en e-post", + "scenes.app.workspaces.welcome_page.code_verification": "Bekreftelseskode", + "scenes.app.workspaces.welcome_page.new_email": "Legg til en sekundΓ¦r e-post", + "scenes.app.workspaces.welcome_page.we_sent_you_mail": "Vi sendte deg en bekreftelseskode via {{$1}}", + "scenes.app.workspaces.welcome_page.done": "jeg er ferdig", + "scenes.login.forgot_password.finished": "Passordet ditt ble oppdatert.", + "scenes.apps.account.account.description_main": "Hovedadressen din er der Twake sender varslene dine. Dine sekundΓ¦re adresser lar deg automatisk inviteres til arbeidsomrΓ₯dene som bruker dem.", + "scenes.apps.account.account.emails.description": "Administrer de forskjellige e-postadressene dine.", + "scenes.apps.account.account.make_main": "Sett hoved", + "scenes.apps.account.account.password.description": "Bytt passord.", + "scenes.apps.account.identity": "Identitet", + "scenes.apps.account.identity.description": "Endre fornavn, etternavn og profilbilde synlig for andre Twake-brukere.", + "scenes.apps.account.preference": "Preferanser", + "scenes.apps.account.thumbnail.max_weight": "Maksimal stΓΈrrelse 5 MB", + "scenes.apps.account.account.email_add_modal.confirm": "Bekreft denne e-posten", + "app.name.twake_calendar": "Kalender", + "app.name.twake_drive": "Dokumenter", + "app.name.twake_tasks": "Oppgaver", + "components.calendar.repetition.everyday": "Daglig", + "components.calendar.repetition.does_not_repeat": "Gjentas ikke", + "components.calendar.repetition.weekly_on": "Ukentlig pΓ₯ {{$1}}", + "components.calendar.repetition.monthly_on": "MΓ₯nedlig pΓ₯ {{$1}} {{$2}}", + "components.calendar.repetition.monthly_on_day": "MΓ₯nedlig pΓ₯ dag {{$1}}", + "components.calendar.repetition.annually_on": "Γ…rlig pΓ₯ {{$1}}", + "components.calendar.repetition.every_weekday": "Hver ukedag (man-fre)", + "components.calendar.repetition.custom": "Tilpasset...", + "components.calendar.repetition.repeat": "Gjenta hver", + "components.calendar.repetition.ends": "Slutter", + "components.calendar.repetition.never": "Aldri", + "components.calendar.repetition.after": "Etter", + "components.calendar.repetition.days": "dager)", + "components.calendar.repetition.weeks": "uke(r)", + "components.calendar.repetition.months": "mΓ₯neder)", + "components.calendar.repetition.years": "Γ₯r", + "components.calendar.repetition.custom_recurrence": "Tilpasset gjentakelse", + "components.calendar.repetition.occurrence": "Forekomst(er)", + "components.calendar.repetition.repeat_on": "Gjenta pΓ₯", + "scenes.app.channelsbar.currentuser.add_apps": "SΓΈk i applikasjoner", + "scenes.app.channelsbar.currentuser.change_my_status": "Endre statusen min", + "scenes.app.channelsbar.currentuser.collaborateurs": "Brukere", + "scenes.app.channelsbar.currentuser.create_workspace_page": "Lag et arbeidsomrΓ₯de", + "scenes.app.channelsbar.currentuser.invited_status": "Du er en gjest.", + "scenes.app.channelsbar.currentuser.title": "Kontoinnstillinger", + "scenes.app.channelsbar.currentuser.workspace_info": "Du er i arbeidsomrΓ₯det {{$1}} fra gruppen {{$2}}", + "scenes.app.channelsbar.currentuser.workspace_parameters": "ArbeidsomrΓ₯deinnstillinger", + "scenes.app.channelsbar.currentuser.logout": "Logg ut", + "scenes.app.channelsbar.currentuser.update": "Oppdater", + "scenes.app.channelsbar.currentuser.disable_notifications": "Deaktiver", + "scenes.app.channelsbar.currentuser.disabling_notifications": "Deaktiver i 1 time", + "scenes.app.channelsbar.currentuser.disabling_notifications_until": "Deaktiver til kl. 09.00 i morgen", + "scenes.app.channelsbar.currentuser.reactivate_notifications": "Aktiver pΓ₯ nytt", + "scenes.app.channelsbar.currentuser.user_parameter": "Varslingsinnstillinger", + "scenes.app.channelsbar.company_invitation_alert_subtitle": "Du kan importere disse kanalene til virksomheten din for Γ₯ holde deg organisert ved Γ₯ klikke pΓ₯ denne rammen.", + "scenes.apps.drive.viewer.edit_with_button": "Rediger med {{$1}}", + "scenes.apps.drive.viewer.loading_preview_message": "Laster inn...", + "scenes.apps.drive.viewer.no_preview_message": "Kan ikke se denne typen fil.", + "scenes.apps.drive.viewer.open_with_button": "Γ…pne med...", + "scenes.apps.messages.input.placeholder": "Skrive en melding. Bruk @ for Γ₯ sitere en bruker.", + "scenes.apps.messages.input.edited": "Redigert", + "scenes.apps.messages.just_you": "Bare synlig for deg", + "scenes.apps.messages.message.new_messages_bar": "Nye meldinger", + "scenes.apps.messages.message.cancel_button": "Avbryt", + "scenes.apps.messages.message.modify_button": "Redigere", + "scenes.apps.messages.message.pin_button": "Fest melding", + "scenes.apps.messages.message.unpin_button": "LΓΈsne melding", + "scenes.apps.messages.message.copy_link": "Kopier lenke til melding", + "scenes.apps.messages.message.pinned": "Festet", + "scenes.apps.messages.message.remove_button": "Slett", + "scenes.apps.messages.message.reply_button": "Svare", + "scenes.apps.messages.message.save_button": "Lagre", + "scenes.apps.messages.message.show_button": "Vise", + "scenes.apps.messages.message.show_responses_button": "Se alle svarene", + "scenes.apps.messages.message.types.first_channel_message_text": "Dette er kanalens fΓΈrste melding", + "scenes.apps.messages.message.types.first_message_text": "Dette er den fΓΈrste meldingen", + "scenes.apps.messages.messageslist.get_writing_user": "skriver...", + "scenes.apps.messages.messageslist.get_writing_users": "skriver...", + "components.workspace.list_manager.all": "Alle", + "general.more": "Mer", + "scenes.apps.board.archived_tasks": "Arkiverte oppgaver ({{$1}})", + "scenes.apps.board.active_tasks": "Aktive oppgaver", + "scenes.apps.board.kanban": "Kanban", + "scenes.apps.board.display_as": "Vis som", + "scenes.apps.messages.message.activity_message.a_deleted_channel_tab": "{{$1}} fjernet {{$2}}-fanen {{$3}}", + "components.locked_features.locked_only_office_popup.text": "Huff!! Det virker som du vil redigere filen fra Twake. Det kan vΓ¦re lurt Γ₯ vurdere Γ₯ oppgradere planen din hvis du vil samarbeide rundt kontorfiler. Utforsk prisalternativene vΓ₯re og velg det beste alternativet for teamsamarbeidsbehovene dine.", + "general.resume": "Gjenoppta", + "scenes.app.popup.workspaceparameter.pages.logo_modify_description": "Rediger bildet av dette arbeidsomrΓ₯det", + "scenes.app.popup.workspaceparameter.pages.research_by": "SΓΈk etter applikasjoner etter navn og kategorier", + "scenes.app.popup.workspaceparameter.pages.researching_apps_button": "SΓΈk i apper...", + "scenes.app.popup.workspaceparameter.pages.show_button": "Vise", + "scenes.app.popup.workspaceparameter.pages.title": "ArbeidsomrΓ₯deinnstillinger", + "scenes.apps.calendar.modals.description_placeholder": "Beskrivelse", + "scenes.app.popup.adduser.magiclinks.genrator_info": "Invitasjonslenke til arbeidsomrΓ₯det", + "scenes.app.popup.adduser.magiclinks.new_link_generated": "Ny lenke generert", + "scenes.app.popup.adduser.magiclinks.copied_to_clipboard": "Kopiert til utklippstavlen", + "scenes.app.popup.adduser.magiclinks.action_copy": "Kopiere", + "scenes.app.popup.adduser.magiclinks.action_generate": "generere", + "scenes.app.popup.workspace.create_temp": "Opprett en midlertidig konto", + "scenes.apps.tasks.active_tasks": "aktive oppgaver", + "scenes.apps.drive.right_preview.versions": "Versjoner", + "scenes.app.popup.appsparameters.pages.apps_connectors_small_text": "Administrer applikasjonene og koblingene dine.", + "scenes.app.popup.appsparameters.pages.icon": "Ikon", + "scenes.app.channelsbar.hide_discussion_leaving.menu": "Skjul diskusjon", + "general.pause": "Pause", + "scenes.app.integrations_parameters.company_application_popup.tag": "Installert", + "scenes.app.integrations_parameters.company_application_popup.btn": "Installere", + "scenes.app.integrations_parameters.company_application_popup.tab_btn_info": "Informasjon", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.description_item": "Beskrivelse", + "scenes.app.integrations_parameters.company_applications_table.name": "Navn", + "scenes.app.integrations_parameters.company_applications_table.title": "Installert i din bedrift", + "app.state.recoil.hooks.use_current_company_applications.toaster_delete": "Slettet {{$1}} fra bedriften din", + "scenes.join.loading": "Laster inn …", + "scenes.join.wrong_link_title": "Denne lenken er ikke lenger tilgjengelig", + "scenes.join.wrong_link_description": "Be personen som inviterte deg til Γ₯ bli med i dette selskapet om en ny lenke eller opprette ditt eget selskap", + "scenes.join.create_the_company_button": "Opprett selskapet", + "scenes.join.join_workspace_from_company": "Bli med {{$1}} fra {{$2}}!", + "scenes.join.twake_description": "Twake er et digitalt arbeidsomrΓ₯de med Γ₯pen kildekode bygget for Γ₯ forbedre teamets produktivitet", + "general.unarchive": "Avarkiver", + "scenes.apps.calendar.event_view.article_until": "til", + "scenes.apps.messages.left_bar.stream_modal.placeholder_name": "Navn", + "scenes.apps.tasks.boards": "Styrer", + "general.open": "Γ…pen", + "scenes.app.popup.appsparameters.pages.json_configuration_information": "GΓ₯ til dokumentasjonen for Γ₯ generere konfigurasjonen i JSON-format.", + "scenes.app.popup.appsparameters.pages.loading": "Laster inn...", + "scenes.app.popup.appsparameters.pages.message_data_next_event": "Passive data som vil bli sendt i neste hendelse", + "scenes.app.popup.appsparameters.pages.waiting_availability_application": "Venter...", + "scenes.app.popup.workspaceparameter.pages.logo_subtitle": "Logo", + "scenes.app.popup.workspaceparameter.pages.name_description": "Endre navnet pΓ₯ dette arbeidsomrΓ₯det", + "scenes.app.popup.workspaceparameter.pages.name_label": "Navn pΓ₯ arbeidsomrΓ₯det", + "scenes.app.popup.workspaceparameter.pages.no_access": "Ingen adgang.", + "scenes.app.popup.workspaceparameter.pages.no_app_information": "Du har ingen applikasjoner i dette arbeidsomrΓ₯det", + "scenes.app.popup.workspaceparameter.pages.quit_workspace_menu": "Forlat dette arbeidsomrΓ₯det", + "scenes.app.popup.workspaceparameter.pages.read_access_subtitle": "Lesetilgang", + "scenes.app.popup.workspaceparameter.pages.remove_from_company_text": "Fjern fra hele selskapet", + "scenes.apps.calendar.modals.event_adresse_placeholder": "Adresse", + "scenes.apps.calendar.modals.event_description_placeholder": "Beskrivelse", + "scenes.apps.calendar.modals.event_title_placeholder": "Tittel", + "scenes.apps.drive.no_file_alert": "Du har ingen programmer som lar deg lage en fil.", + "scenes.apps.drive.no_storage_app_alert": "Du har ingen applikasjoner som lar deg legge til ekstern lagring.", + "scenes.apps.drive.remove_definitely_menu": "Slett permanent", + "scenes.apps.drive.restore_menu": "Restaurere", + "scenes.error_on_twake": "\"Houston vi har et problem\"", + "scenes.app.workspaces.components.skip": "Hopp over", + "scenes.client.channelbar.channelmemberslist.menu.option_2": "Fjern fra kanalen", + "components.leftbar.channel.workspaceschannels.menu.option_1": "Lag en kanal", + "components.leftbar.channel.workspaceschannels.menu.option_2": "Bli med i en kanal", + "components.upload.drop_files.toaster.error": "Du kan ikke laste opp flere enn {{$1}}-filer", + "app.state.recoil.hooks.use_current_company_applications.toaster_add": "Lagt til {{$1}} i bedriften din", + "scenes.apps.account.account.menu_title": "Regnskap", + "components.calendar.repetition.on": "PΓ₯", + "scenes.app.workspaces.create_company.group_data.title": "Vi skal vΓ¦re raske - vi trenger bare litt statistisk informasjon.", + "scenes.apps.drive.new_file_menu": "Ny fil", + "scenes.apps.drive.new_file_title": "Ny fil", + "scenes.apps.drive.new_external_storage": "Ny ekstern lagring", + "scenes.apps.drive.new_folder_title": "Ny mappe", + "scenes.apps.drive.unconfigured_tab": "Denne fanen er ikke konfigurert ennΓ₯.", + "scenes.apps.messages.messageslist.go_last_message_button": "GΓ₯ til siste melding", + "scenes.apps.messages.messageslist.go_last_message_button.new_messages": "Nye meldinger", + "scenes.login.verifymail.signin_button": "Logg Inn", + "scenes.login.verifymail.success": "E-posten din ble bekreftet!", + "scenes.login.verifymail.verification_waiting": "Venter pΓ₯ bekreftelse...", + "scenes.no_panic": "Ikke fΓ₯ panikk! Bare last inn denne siden pΓ₯ nytt for Γ₯ fikse Twake.", + "services.apps.calendar.deadline_icon": "Frist", + "services.apps.calendar.event_icon": "Begivenhet", + "services.apps.calendar.move_icon": "Bevege seg", + "services.apps.calendar.reminder_icon": "PΓ₯minnelse", + "services.apps.messages.no_app": "Denne applikasjonen eksisterer ikke.", + "services.apps.messages.no_command_possible": "Vi kan ikke utfΓΈre kommandoen '{{$1}}' fordi '{{$2}}' ikke eksisterer eller ikke tillater Γ₯ lage kommandoer.", + "services.user.notification_parameters_update_alert": "Varslingsinnstillingene er oppdatert.", + "services.user.update_password_alert": "Passordet ditt er oppdatert.", + "scenes.apps.tasks.board.tasks.use_starttime": "Bruk starttid", + "scenes.apps.tasks.board.tasks.in_list": "PΓ₯ listen", + "scenes.apps.tasks.board.starts": "Starter", + "scenes.apps.tasks.board.ends": "Skal gjΓΈres for", + "scenes.apps.tasks.board.list_name": "Liste navn", + "scenes.app.popup.sync_calendar": "Synkroniser kalenderne dine.", + "scenes.apps.parameters.workspace_sections.workspace.logo_company": "Logoen til selskapet", + "scenes.app.popup.workspaceparameter.pages.logo_company_modify_description": "Rediger firmabilde ", + "scenes.app.popup.workspaceparameter.pages.cancel_invitation": "Avbryt invitasjonen", + "scenes.apps.account.account.fullname": "Fullt navn", + "login.email_login": "E-post/pΓ₯logging", + "scenes.apps.account.account.password_for_user": "Passord for brukeren din", + "scenes.apps.account.account.send_info": "Send denne legitimasjonsinformasjonen til brukeren din.", + "scenes.apps.account.account.save": "Lagre konto", + "scenes.apps.account.message_temporary": "En midlertidig konto fungerer som en vanlig Twake-konto, men du oppretter passordet og du vil kunne tilbakestille det om nΓΈdvendig.", + "scenes.apps.account.message_user_signin": "Brukeren din kan nΓ₯r som helst logge pΓ₯ med den samme e-posten og endre den midlertidige kontoen til en vanlig konto.", + "scenes.app.mainview.link_expired": "Denne offentlige lenken er ugyldig eller har utlΓΈpt.", + "scenes.app.mainview.create_account": "Lag arbeidsomrΓ₯det ditt gratis pΓ₯ ", + "scenes.apps.calendar.modals.reminder_add": "Legg til en pΓ₯minnelse", + "components.attachmentpicker.add_attachment": "Legg til vedlegg", + "components.input.copied": "Kopiert", + "components.drive.new_versions": "Legg til en ny versjon", + "components.drive.navigators.directory_not_found": "Katalog ikke funnet.", + "components.drive.right_preview.suppress_link": "Undertrykk koblingen", + "components.drive.right_preview.create_link": "Opprett en tilgangslenke", + "components.drive.moove_here": "Flytt her", + "components.drive.modify_uslist": "Endre brukerliste", + "components.tagpicker.tag_name": "Tag navn", + "components.upload.drop_files": "Slipp filene dine her", + "components.workspace.list_manager.no_workspace": "Ingen arbeidsplass", + "components.workspace.list_manager.add": "Legg til arbeidsomrΓ₯der", + "components.workspace.list_manager.current_space": "NΓ₯vΓ¦rende arbeidsomrΓ₯de", + "components.workspace.list_manager.current_company": "NΓ₯vΓ¦rende selskap", + "components.workspace.calendar.invalid": "Ugyldig", + "components.searchpopup.enter_text": "Skriv inn litt tekst for Γ₯ sΓΈke etter Twake.", + "components.searchpopup.loading": "Laster inn flere resultater", + "components.searchpopup.filter_ws": "Filtrer arbeidsomrΓ₯der", + "components.searchpopup.tags": "Tagger", + "components.searchpopup.size": "StΓΈrrelse", + "components.searchpopup.creation": "Opprettelse", + "components.searchpopup.update_search": "Oppdater sΓΈket", + "components.searchpopup.last_modif": "Siste modifikasjon", + "components.searchpopup.sender": "Avsender", + "components.searchpopup.mentions": "Omtaler", + "components.searchpopup.only_pinned": "Bare festede meldinger", + "components.alert.confirm": "Bekreft handlingen din", + "components.alert.confirm_click": "Bekreft handlingen ved Γ₯ klikke pΓ₯ OK.", + "components.searchpopup.tasks": "Oppgaver", + "scenes.app.mainview.advanced_search_placeholder": "Avansert sΓΈk", + "components.searchpopup.hide_filters": "skjule filtre", + "components.searchpopup.show_filters": "vis filtre", + "components.searchpopup.load_more": "Last inn flere resultater", + "scenes.apps.board.all_boards": "Alle brett", + "components.userlistmanager.no_users": "Ingen brukere.", + "scenes.apps.calendar.reminders": "pΓ₯minnelse(r)", + "scenes.apps.calendar.video_link": "Klikk for Γ₯ Γ₯pne lenken", + "scenes.app.mainview.discussion": "Diskusjon", + "components.tagpicker.notag": "Ingen tag", + "scenes.apps.tasks.modals.attachments": "Vedlegg", + "components.calendar.calendarselector.from": "Fra", + "scenes.apps.drive.move_text2": "Bevege seg", + "components.attachmentpicker.from_computer": "Fra enheten din", + "components.attachmentpicker.from_twake": "Fra Twake Documents", + "components.attachmentpicker.file": "Fil", + "components.attachmentpicker.remove_attach": "Fjern vedlegg", + "scenes.apps.drive.remove_attachs": "Fjern vedlegg", + "components.drive.elements.see": "Se", + "components.drive.elements.current_name": "NΓ₯vΓ¦rende navn: ", + "scenes.apps.drive.right_preview.public": "Offentlig tilgang", + "components.drive.elements.configurate_mod": "Konfigurer moden...", + "components.drive.elements.manage_version": "Administrer versjoner", + "scenes.app.popup.createcompany.try_again": "VΓ¦r sΓ₯ snill, prΓΈv pΓ₯ nytt.", + "scenes.app.popup.appsparameters.pages.title_informations": "Grunnleggende informasjon", + "scenes.app.popup.appsparameters.pages.subtitle_informations": "Informasjon knyttet til applikasjonsadministrasjon", + "scenes.app.popup.appsparameters.pages.smalltext_user_id": "Gjeldende bruker-ID", + "scenes.app.popup.appsparameters.pages.smalltext_workspace_id": "Gjeldende arbeidsomrΓ₯de-ID", + "scenes.app.popup.appsparameters.pages.smalltext_group_id": "Gjeldende gruppe-id", + "scenes.app.mainview.channel_description": "Beskriv kanalen", + "scenes.client.channelbar.channeltemplateeditor.checkbox": "Inviter automatisk alle arbeidsomrΓ₯debrukere til denne kanalen", + "scenes.client.channelbar.channelmemberslist.title": "Brukere i {{$1}}", + "scenes.client.channelbar.channelmemberslist.loader": "Last mer", + "scenes.client.channelbar.channelmemberslist.autocomplete": "Legg til eller sΓΈk bruker", + "components.channelworkspacelist.title": "Kanaler", + "scenes.client.channelbar.workspacechannellist.autocomplete": "SΓΈk etter kanal, bruker eller direktemeldinger", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_creation": "Opprett en ny fane", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_edition": "Gi nytt navn til {{$1}}", + "components.connectorslistmanager.add_connectors": "Legg til kontakter", + "components.notifications.hidden_notifications_button.children": "Nye meldinger", + "scenes.client.mainview.tabs.tabstemplateeditor.select_placeholder": "applikasjon", + "scenes.client.channelbar.channelmemberslist.no_members": "Det er ingen bruker i denne kanalen, du kan invitere dem ved Γ₯ klikke pΓ₯ Legg til brukere.", + "components.newversion.new_version_component.row.part_2": "vi foreslΓ₯r at du laster appen pΓ₯ nytt og nyter de nye funksjonene vΓ₯re!", + "components.newversion.new_version_component.link": "Klikk her for Γ₯ laste inn pΓ₯ nytt", + "components.newversion.new_version_modal.title": "Ny oppdatering tilgjengelig !", + "scenes.apps.drive.download_all_button": "Last ned alle", + "components.inputs.input_with_select.input.placeholder": "Kanalnavn", + "components.inputs.input_with_select.select.placeholder": "Seksjonsnavn", + "components.inputs.input_with_select.select.no_sections": "Begynn Γ₯ skrive navnet pΓ₯ din fΓΈrste kanalseksjon.", + "components.inputs.input_with_select.button.tooltip": "Angi en kanalseksjon", + "scenes.apps.messages.message.activity_message.a_added_b_to_the_channel": "{{$1}} la til {{$2}} til kanalen", + "scenes.apps.messages.message.activity_message.a_removed_b_from_the_channel": "{{$1}} fjernet {{$2}} fra kanalen", + "scenes.apps.messages.message.activity_message.a_updated_channel_description": "{{$1}} endret beskrivelsen", + "scenes.apps.messages.message.activity_message.a_created_channel_connector": "{{$1}} la til en ny kobling {{$2}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_connector": "{{$1}} fjernet en kobling {{$2}}", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.loader": "Last mer", + "general.re_send": "Send pΓ₯ nytt", + "general.verify": "Bekrefte", + "components.unverified_account.typography_text_danger": "Du har {{$1}} dag(er) igjen av prΓΈveperioden. PrΓΈvekonto vil bli blokkert etter 7 dager og slettet permanent etter 1 mΓ₯ned etter registrering. Du kan bekrefte kontoen din ved Γ₯ klikke pΓ₯ \"Bekreft kontoen min\"-knappen i bekreftelses-e-posten vi sendte deg.", + "components.unverified_account.verification_details": "Vi har sendt bekreftelsesdetaljer til", + "components.account_verification_status_sentence": "Kontostatusen din er: {{$1}}", + "components.account_verication_status_unverified": "Ubekreftet", + "components.account_verication_status_blocked": "LΓ₯st", + "components.unverified_account.re_send_email": "Har du ikke mottatt e-posten?", + "components.blocked_account.trial_period_over": "PrΓΈveperioden din er over. For Γ₯ lΓ₯se opp kontoen din og fΓ₯ tilgang til alle funksjoner, vennligst bekreft kontoen din via e-postbekreftelse", + "components.add_mails_workspace.button": "Begynn Γ₯ bruke Twake", + "components.add_mails_workspace.title_1": "Legg til noen brukere", + "components.add_mails_workspace.title_2": "Twake er et teamsamarbeidsverktΓΈy, sΓ₯ inviter noen brukere til Γ₯ teste et arbeidsomrΓ₯de vi har laget for deg.", + "components.add_mails_workspace.text_area_placeholder": "Skriv inn e-poster til brukerne dine*", + "components.verify_mail.title_1": "Gratulerer", + "components.verify_mail.title_2": "Du er en offisiell Twake-bruker nΓ₯!", + "components.verify_mail.button": "Legg til bruker", + "components.verify_mail.text": "FΓΈrst av alt mΓ₯ du bekrefte e-postadressen din. Vi har sendt en bekreftelseslenke til", + "components.verify_mail.paragraph": "Du kan gjΓΈre det senere hvis du vil, men ubekreftede kontoer har bare tilgang til en begrenset versjon av Twake", + "services.console_services.toaster.add_emails_error": "Feil ved Γ₯ legge til e-post(er)", + "services.console_services.toaster.add_email_error_message": "Feil under tillegging av {{$1}}", + "services.console_services.toaster.success_verify_email": "En bekreftelseslenke er sendt til e-postkontoen din", + "scenes.app.popup.workspaceparameter.edit_from_console": "Se i konsoll", + "services.console_services.toaster.success_invite_emails": "Vellykket lagt til {{$1}} bruker(e)", + "scenes.client.channels_bar.modals.guest_management.title": "Administrer gjester i {{$1}}", + "scenes.client.channels_bar.modals.guest_management.input_placeholder": "SΓΈk etter gjester eller ventende e-poster", + "scenes.client.channels_bar.modals.guest_management.tips": "Begynn Γ₯ legge til eller sΓΈke etter e-post ved Γ₯ bruke inndataene ovenfor", + "scenes.client.channels_bar.modals.parts.channel_member_row.label.pending_email": "Mail sendt", + "general.user.role.company.admin": "Bedriftsadministrator", + "general.user.role.company.member": "Medlem", + "general.user.role.company.guest": "Gjest", + "general.user.deleted": "Slettet konto", + "components.richtexteditor.toolbar.bold": "Modig", + "components.richtexteditor.toolbar.underline": "Understrek", + "components.richtexteditor.toolbar.italic": "Kursiv", + "components.richtexteditor.toolbar.strikethrough": "Gjennomstreking", + "components.richtexteditor.toolbar.code": "Kode", + "components.richtexteditor.toolbar.unordered-list": "Punktliste", + "components.richtexteditor.toolbar.ordered-list": "Bestilt liste", + "components.richtexteditor.toolbar.blockquote": "Blockquote", + "components.richtexteditor.toolbar.code-block": "Kodeblokk", + "components.locked_features.locked_history_banner.title": "Du har akkurat nΓ₯dd meldingsgrensen", + "components.locked_features.locked_history_banner.description": "Din bedrift har mange meldinger! Oppgrader nΓ₯ for Γ₯ fΓ₯ tilgang til hele meldingsloggen din.", + "components.locked_features.locked_history_banner.button": "LΓ¦re mer", + "components.locked_features.locked_guests_popup.title": "Gjestefunksjonen er lΓ₯st", + "components.locked_features.locked_guests_popup.subtitle": "Denne funksjonen er ikke tilgjengelig i Twake gratisversjonen", + "components.locked_features.locked_guests_popup.description": "Huff!! Det virker som du ΓΈnsker Γ₯ invitere eksterne brukere til arbeidsomrΓ₯det ditt. Det kan vΓ¦re lurt Γ₯ vurdere Γ₯ oppgradere planen din hvis du ΓΈnsker Γ₯ samarbeide med gjester og eksterne partnere. Utforsk prisalternativene vΓ₯re og velg det beste alternativet for teamsamarbeidsbehovene dine.", + "components.locked_features.locked_guests_popup.learn_more_button": "LΓ¦re mer", + "components.locked_features.locked_guests_popup.skip_for_now_button": "Hopp over for nΓ₯", + "components.locked_features.locked_guests_popup.or": "Eller", + "components.on_boarding.company_billing_banner.admin_or_owner_text": "Det er et problem med firmaabonnementet ditt. Vennligst ta en titt pΓ₯ din", + "components.on_boarding.company_billing_banner.guest_or_member_text": "Det er et problem med firmaabonnementet ditt. Ta kontakt med eieren eller administratoren av selskapet!", + "components.on_boarding.company_billing_banner.link": "selskapets abonnementsplan", + "components.on_boarding.popups.blocked_company.title": "Firmaet ditt er lΓ₯st pΓ₯ grunn av et betalingsproblem", + "components.on_boarding.popups.blocked_company.description": "Ditt abonnement pΓ₯ Twake har utlΓΈpt. Ta kontakt med eieren eller administratoren av firmaet ditt for Γ₯ fornye det og vΓ¦re i stand til Γ₯ kommunisere med teamet ditt igjen!", + "components.on_boarding.popups.blocked_company.learn_more_text": "Vil du lΓ¦re mer om bedriftens abonnementsplan?", + "components.on_boarding.popups.blocked_company.company_subscription_plan_button": "Klikk her", + "components.on_boarding.popups.blocked_company.or": "Eller", + "components.on_boarding.popups.blocked_company.company_selector": "Bytt til et annet selskap", + "scenes.apps.tasks.select_user_button": "Se oppgaver for en annen bruker", + "scenes.apps.tasks.select_user": "SΓΈk bruker", + "scenes.apps.messages.input.attach_file.from_computer": "Fra datamaskinen", + "scenes.app.popup.workspaceparameter.pages.table_title": "Navn", + "scenes.client.main_view.main_header.search_input": "SΓΈk", + "scenes.apps.drive.new_link_title": "Ny lenke", + "scenes.apps.drive.default_link_name": "Uten navn", + "components.emoji_picker.input_search_placeholder": "SΓΈk", + "services.apps.messages.message_editor_service.upload_error_toaster": "{{$1}} - Du kan ikke legge til flere enn {{$2}} filer i en melding", + "scenes.apps.messages.message.parts.deleted_content.text.current_user": "Du slettet denne meldingen", + "scenes.apps.messages.message.parts.deleted_content.text": "{{$1}} slettet meldingen hans", + "components.member.user_parts.and_more_user_text": " og {{$1}} flere brukere", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_link": "Opprett en privat kanal", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_text": " i stedet", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_input_placeholder": "Du kan ikke legge til mer enn 10 brukere", + "general.uploading": "Laster opp", + "components.emoji_picker.categories.not_found": "Ingen emoji funnet", + "scenes.app.popup.workspaceparameter.pages.workspace_partner_tabs.members.table.tags": "Rolle", + "general.email": "E-post", + "components.locked_features.locked_workspace_popup.title": "Du kan ikke opprette flere arbeidsomrΓ₯der", + "components.locked_features.locked_workspace_popup.subtitle": "I gratisversjonen kan du bare ha ett arbeidsomrΓ₯de i bedriften din.", + "components.locked_features.locked_workspace_popup.text": "Huff!! Ønsker du Γ₯ skape et nytt arbeidsomrΓ₯de i din bedrift? Det kan vΓ¦re lurt Γ₯ vurdere Γ₯ oppgradere planen din. Utforsk vΓ₯re prisalternativer og velg det beste valget for teamsamarbeidsbehovene dine.", + "components.locked_features.locked_only_office_popup.title": "Du kan ikke redigere denne filen", + "components.locked_features.locked_only_office_popup.subtitle": "I gratisversjonen kan du ikke bruke onlyoffice.", + "components.locked_features.locked_drive_popup.title": "Du har akkurat nΓ₯dd kjΓΈregrensen", + "components.locked_features.locked_drive_popup.subtitle": "I gratisversjonen kan du kun lagre 6 GB.", + "scenes.app.channelsbar.currentuser.company_messages_counter_header": "Meldingsnummer", + "scenes.app.channelsbar.currentuser.company_messages_counter_info": "PΓ₯ gratisversjonen av Twake kan du ikke fΓ₯ tilgang til mer enn de {{$1}} nyere meldingene.", + "scenes.app.channelsbar.currentuser.company_messages_counter_link": "Vis flere planer", + "scenes.app.channelsbar.channelsuser.new_private_discussion": "Ny privat diskusjon", + "scenes.app.channelsbar.channelsuser.no_private_message_invite_collaboraters": "Ingen private meldinger. Inviter brukere!", + "scenes.app.channelsbar.channelsuser.private_messages": "Direktemeldinger", + "scenes.app.channelsbar.channelsworkspace.channel_title": "KANALER", + "scenes.app.channelsbar.channelsworkspace.channel_title.favorite": "FAVORITER", + "scenes.app.channelsbar.channelsworkspace.create_channel": "Lag en kanal", + "scenes.app.channelsbar.channelsworkspace.no_channel": "Du har ikke blitt med i noen kanal ennΓ₯", + "scenes.app.channelsbar.modify_channel_menu": "Rediger kanal", + "scenes.app.channelsbar.guest_management": "Gjesteledelse", + "scenes.app.channelsbar.read_sign": "Merk som lest", + "scenes.app.channelsbar.unread_sign": "Merk som ulest", + "scenes.app.channelsbar.channel_leaving": "Forlat kanalen", + "scenes.app.channelsbar.channel_removing": "Slett kanal", + "scenes.app.channelsbar.company_invitation_alert_title": "Du inviteres til selskapet ", + "scenes.app.channelsbar.initial_instructions_tutorial": "Velg et fornavn, et navn og et profilbilde.", + "scenes.app.channelsbar.installation_desktop_tutorial": "Installer skrivebordsapplikasjonen", + "scenes.app.channelsbar.invitation_collaboraors_tutorial": "Inviter brukere til arbeidsomrΓ₯det ditt.", + "scenes.app.channelsbar.public_channel_label": "Offentlig", + "scenes.app.channelsbar.private_channel_label": "Privat", + "scenes.app.channelsbar.sending_message_instruction": "Send din fΓΈrste melding i en diskusjon", + "scenes.app.channelsbar.tutorial_alert": "Vil du aldri vise denne rammen igjen?", + "scenes.app.channelsbar.welcome": "Velkommen til Twake", + "scenes.app.channelsbar.welcoming_message_subtitle": "Bli en Twake-proff med bare noen fΓ₯ klikk!", + "scenes.app.mainview.instruction_current_tab": "Start med Γ₯ velge en kanal til venstre.", + "scenes.app.mainview.tabs.no_connected_connectors_for_channel": "Du har ingen kobling som kan koble til en kanal.", + "scenes.app.mainview.tabs.rename": "Gi nytt navn", + "scenes.app.mainview.tabs.searching_connectors": "SΓΈk etter koblinger...", + "scenes.app.popup.adduser.adresses_message": "Vennligst skill adressene med komma eller mellomrom. Husk at Twake kan begrense antall invitasjoner basert pΓ₯ abonnementet ditt.", + "scenes.app.popup.appsparameters.pages._app_identity": "SΓΈknadens identitet", + "scenes.app.popup.appsparameters.pages._appareance_message_twakcode": "Test utseendet til Twacode-meldingene dine", + "scenes.app.popup.appsparameters.pages.alert_published_app": "SΓΈknaden din er publisert, du kan ikke redigere den.", + "scenes.app.popup.appsparameters.pages.allowed_ip_adresses_method": "Bruk * i utviklingen for Γ₯ tillate alle IP-adresser.", + "scenes.app.popup.appsparameters.pages.amazing_app_name": "Min fantastiske app", + "scenes.app.popup.appsparameters.pages.api_data_description": "Nyttige data for Twake API.", + "scenes.app.popup.appsparameters.pages.api_parameters_label": "API-innstillinger", + "scenes.app.popup.appsparameters.pages.app_name_label": "Programnavn", + "scenes.app.popup.appsparameters.pages.app_modification_right": "Alle ledere av dette selskapet vil kunne redigere denne applikasjonen.", + "scenes.app.popup.appsparameters.pages.app_privileges_information": "Definer hva applikasjonen din kan redigere og lese.", + "scenes.app.popup.appsparameters.pages.app_privileges_label": "Applikasjonsrettigheter", + "scenes.app.popup.appsparameters.pages.app_update": "Oppdater appen {{$1}} (appen brukes {{$2}} ganger.)", + "scenes.app.popup.appsparameters.pages.application_title": "applikasjon", + "scenes.app.popup.appsparameters.pages.apps_title": "Dine applikasjoner og koblinger", + "scenes.app.popup.appsparameters.pages.automatique_label": "Automatisk", + "scenes.app.popup.appsparameters.pages.automatique_option_information": "Hvis du aktiverer 'Automatisk', vil denne applikasjonen automatisk bli lagt til de neste arbeidsomrΓ₯dene til dette selskapet.", + "scenes.app.popup.appsparameters.pages.autorised_ip_adresses_label": "Tillatte IP-adresser", + "scenes.app.popup.appsparameters.pages.available_publication_alert": "Publiseringen av sΓΈknaden din venter for ΓΈyeblikket pΓ₯ validering av Twake-teamet.", + "scenes.app.popup.appsparameters.pages.button_force": "Kraft i hele selskapet", + "scenes.app.popup.appsparameters.pages.call_event_handlers": "Hendelse av typen Β«{{$1}}Β» og id Β«{{$2}}Β» med passive Β«{{$3}}Β»", + "scenes.app.popup.appsparameters.pages.company_label": "Bedriftseier", + "scenes.app.popup.appsparameters.pages.configuration_label": "Konfigurasjon", + "scenes.app.popup.appsparameters.pages.create_app_button": "Opprett en applikasjon", + "scenes.app.popup.appsparameters.pages.create_my_app": "Opprett sΓΈknaden min", + "scenes.app.popup.appsparameters.pages.current_informations_apps_connectors": "Du har ikke opprettet en app ennΓ₯. FΓΈr du oppretter en applikasjon eller kobling, sΓΈrg for at den ikke allerede eksisterer i vΓ₯rt applikasjonsmarked.", + "scenes.app.popup.appsparameters.pages.danger_zone_description": "Slett sΓΈknad", + "scenes.app.popup.appsparameters.pages.danger_zone_label": "Farlig sone", + "scenes.app.popup.appsparameters.pages.description_label": "Beskrivelse", + "scenes.app.popup.appsparameters.pages.developped_apps_subtitle": "Applikasjoner utviklet av selskapet", + "scenes.app.popup.appsparameters.pages.dispalyed_parameters_description": "Lar deg definere hvor applikasjonen din skal vΓ¦re synlig.", + "scenes.app.popup.appsparameters.pages.displayed_parameters_label": "Skjerminnstillinger", + "scenes.app.popup.appsparameters.pages.error_check_needed": "Det har oppstΓ₯tt en feil; sjekk informasjonen din.", + "scenes.app.popup.appsparameters.pages.error_message": "Dette navnet er allerede brukt av en annen applikasjon; vennligst velg en annen.", + "scenes.app.popup.appsparameters.pages.error_user_code": "feil", + "scenes.app.popup.appsparameters.pages.event_subtitle": "arrangementer", + "scenes.app.popup.appsparameters.pages.filter_information": "Dette filteret begrenser bruken av API-nΓΈkkelen til kun servere i koblingen din.", + "scenes.app.popup.appsparameters.pages.go_back": "Tilbake", + "scenes.app.popup.appsparameters.pages.grp_section_name-error": "Dette navnet er allerede i bruk av en annen applikasjon. Vennligst velg en annen.", + "scenes.app.popup.appsparameters.pages.grp_section_surname_label": "Forenklet navn", + "scenes.app.popup.appsparameters.pages.installation": "Installer.", + "scenes.app.popup.appsparameters.pages.instruction_message_twakecode": "Start med Γ₯ skrive meldingen i JSON-format.", + "scenes.app.popup.appsparameters.pages.interne_availability_application": "Intern sΓΈknad", + "scenes.app.popup.appsparameters.pages.modify_public_data": "Rediger de offentlige dataene til applikasjonen din.", + "scenes.app.popup.appsparameters.pages.new_app_title": "Ny sΓΈknad", + "scenes.app.popup.appsparameters.pages.ok_user_code": "ok", + "scenes.app.popup.appsparameters.pages.optimal_format": "Optimalt format: 48x48px.", + "scenes.app.popup.appsparameters.pages.parameters_form_small_text": "Den upubliserte applikasjonen vil kun fungere i din bedrift. Hvis du ΓΈnsker Γ₯ gjΓΈre det tilgjengelig for alle Twake-brukere, aktiver dette alternativet.", + "scenes.app.popup.appsparameters.pages.public_availability_application": "Offentlig sΓΈknad", + "scenes.app.popup.appsparameters.pages.public_login_label": "Offentlig identifikator", + "scenes.app.popup.appsparameters.pages.publication_description": "Bestem synligheten til sΓΈknaden din.", + "scenes.app.popup.appsparameters.pages.publication_label": "Utgivelse", + "scenes.app.popup.appsparameters.pages.publish_app_label": "Publiser sΓΈknad", + "scenes.app.popup.appsparameters.pages.read_privileges_label": "Les privilegier", + "scenes.app.popup.appsparameters.pages.remove_app": "Slett applikasjonen {{$1}} permanent.", + "scenes.app.popup.appsparameters.pages.remove_app_from_company": "Fjern fra hele selskapet", + "scenes.app.popup.appsparameters.pages.remove_app_from_workspace": "Fjern fra arbeidsomrΓ₯det", + "scenes.app.popup.appsparameters.pages.show_button": "Forestilling", + "scenes.app.popup.appsparameters.pages.status_tilte": "Stat", + "scenes.app.popup.appsparameters.pages.string_information": "Denne strengen identifiserer applikasjonen din og vil bli brukt i meldingskommandoer.", + "scenes.app.popup.appsparameters.pages.title_tester": "Twakecode tester", + "scenes.app.popup.appsparameters.pages.url_reception_events_label": "URL til arrangementsmottak", + "scenes.app.popup.appsparameters.pages.error_app_simple_name_message": "Det forenklede navnet pΓ₯ applikasjonen din brukes allerede av en annen applikasjon. Vennligst endre den.", + "scenes.app.popup.appsparameters.pages.update_button": "Oppdater", + "scenes.app.popup.createworkspacepage.add_subtitle": "Trenger mer rom?", + "scenes.app.popup.createworkspacepage.create_new_workspace": "Opprett et nytt arbeidsomrΓ₯de", + "scenes.app.popup.createworkspacepage.placeholder_name": "Navn pΓ₯ arbeidsomrΓ₯det", + "scenes.app.popup.userparameter.pages.frequency_notif_configuration_description": "Still inn frekvensen for mobilvarsler.", + "scenes.app.popup.userparameter.pages.frequency_notif_subtitle": "Hyppighet av varsler", + "scenes.app.popup.userparameter.pages.keywords_notif_description": "Uthev fΓΈlgende sΓΈkeord:", + "scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description": "Angi frekvensen for e-postvarsler.", + "scenes.app.popup.userparameter.pages.private_message_content.show": "Vis innhold i private meldinger", + "scenes.app.popup.userparameter.pages.private_message_content.hide": "Skjul innhold i private meldinger", + "scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description": "Velg en periode der du ikke mottar varsler.", + "scenes.app.popup.userparameter.pages.no_night_disturbing_label": "Ikke forstyrr om natten", + "scenes.app.popup.userparameter.pages.notif_content_label": "Innhold i varsler", + "scenes.app.mainview.quick_search_placeholder": "Raskt sΓΈk", + "scenes.app.popup.userparameter.personnal_workspaces_title": "ArbeidsomrΓ₯dene dine", + "scenes.app.popup.workspaceparameter.admin_current_status": "Du er en administrator.", + "scenes.app.popup.workspaceparameter.admin_manager_current_status": "Du er en arbeidsomrΓ₯deadministrator.", + "scenes.app.popup.workspaceparameter.manager_current_status": "Du er en bedriftsadministrator.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace": "Slett arbeidsomrΓ₯de", + "scenes.app.popup.workspaceparameter.pages.error_workspace_member": "Du mΓ₯ vΓ¦re alene pΓ₯ arbeidsomrΓ₯det for Γ₯ fjerne det. Fjern samarbeidspartnerne dine og prΓΈv pΓ₯ nytt.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace_description": "For Γ₯ bekrefte at du vil slette dette arbeidsomrΓ₯det, skriv inn navnet nedenfor og trykk pΓ₯ Slett.", + "scenes.app.popup.workspaceparameter.pages.enter": "Tast inn ", + "scenes.app.popup.workspaceparameter.pages.access_apps": "FΓ₯ tilgang til applikasjonene og koblingene dine", + "scenes.app.popup.workspaceparameter.pages.moderator_status": "ArbeidsomrΓ₯de moderator", + "scenes.app.popup.workspaceparameter.pages.alert_impossible_removing": "Du kan ikke forlate arbeidsomrΓ₯det, fordi du er den siste administratoren. Du kan definere en ny administrator eller slette/arkivere dette arbeidsomrΓ₯det.", + "scenes.app.popup.workspaceparameter.pages.all_apps_small_text": "Alle applikasjoner", + "scenes.app.popup.workspaceparameter.pages.apps_company_small_text": "Din bedrifts applikasjoner", + "scenes.app.popup.workspaceparameter.pages.company_name_description": "Endre navnet pΓ₯ dette selskapet", + "scenes.app.popup.workspaceparameter.pages.company_name_label": "Navn pΓ₯ selskapet", + "scenes.app.popup.workspaceparameter.pages.configuration_notif": "konfigurasjon", + "scenes.app.popup.workspaceparameter.pages.configure_button": "Konfigurer", + "scenes.app.popup.workspaceparameter.pages.description": "Beskrivelse", + "scenes.app.popup.workspaceparameter.pages.developped_apps_small_text": "Applikasjoner utviklet av selskapet", + "scenes.app.popup.workspaceparameter.pages.displayed_preferencies_subtitle": "Vis preferanser", + "scenes.app.popup.workspaceparameter.pages.install_button": "Installere", + "scenes.app.popup.workspaceparameter.pages.installed_app_information": "Installer applikasjonen i dette arbeidsomrΓ₯det.", + "scenes.app.popup.workspaceparameter.pages.installed_apps_information": "Apper installert i dette arbeidsomrΓ₯det {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_message": "Applikasjoner installert i andre omrΓ₯der av selskapet {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_subtitle": "Installerte applikasjoner", + "scenes.app.popup.workspaceparameter.pages.invitation_error": "Det oppsto en feil under invitasjonen av fΓΈlgende brukere: ", + "scenes.app.popup.workspaceparameter.pages.invited_guest_check_message": "Sjekk at brukernavnet eller e-posten som brukes er gyldig.", + "scenes.app.popup.workspaceparameter.pages.webhooks_access_subtitle": "Tilgang til webhooks", + "scenes.app.popup.workspaceparameter.pages.weight_max_small_text": "Maksimal stΓΈrrelse 5 MB.", + "scenes.app.popup.workspaceparameter.pages.withdraw_button": "Fjern fra dette arbeidsomrΓ₯det", + "scenes.app.popup.workspaceparameter.pages.worspace_notif": "arbeidsomrΓ₯de", + "scenes.app.popup.workspaceparameter.pages.write_access_subtitle": "Skrivetilgang", + "scenes.app.popup.workspaceparameter.pages.your_apps_label": "Dine sΓΈknader", + "scenes.app.popup.workspaceparameter.payments_subscriptions_title": "Betalinger og abonnementer", + "scenes.app.workspacesbar.components.change_company_title": "Bytt selskap", + "scenes.app.workspacesbar.components.create_company_menu": "Opprett et selskap", + "scenes.app.workspacesbar.components.grp_parameters": "{{$1}} innstillinger", + "scenes.apps.calendar.add_calendar_menu": "Legg til en kalender", + "scenes.apps.calendar.connectors_menu": "Koblinger...", + "scenes.apps.calendar.connectors_search_menu": "SΓΈk etter koblinger...", + "scenes.apps.calendar.create_calendar_title": "Lag en kalender", + "scenes.apps.calendar.edit_calendar_title": "Rediger kalenderen", + "scenes.apps.calendar.export_title": "Eksport", + "scenes.apps.calendar.export_view_menu": "Eksporter visningen...", + "scenes.apps.calendar.ics_download_menu": "Last ned en ICS-fil", + "scenes.apps.calendar.ics_subscription_menu": "FΓ₯ en ICS-abonnementslenke", + "scenes.apps.calendar.modals.advanced_options": "Avanserte instillinger", + "scenes.apps.calendar.modals.participants_event": "Deltakere", + "scenes.apps.calendar.modals.reminders": "PΓ₯minnelser", + "scenes.apps.calendar.modals.remove_button": "Slett", + "scenes.apps.calendar.modals.remove_event_button": "Slett hendelsen", + "scenes.apps.calendar.modals.remove_event_text": "Vil du slette arrangementet?", + "scenes.apps.calendar.modals.title_placeholder": "Tittel", + "scenes.apps.calendar.modify_calendar_menu": "Rediger kalenderen", + "scenes.apps.calendar.month_option": "MΓ₯ned", + "scenes.apps.calendar.my_calendar": "Min kalender", + "scenes.apps.calendar.my_calendar_label": "Min kalender", + "scenes.apps.calendar.my_calendar_menu": "Min kalender", + "scenes.apps.calendar.no_calendar_text": "Du har ikke angitt noen kalendere for dette arbeidsomrΓ₯det.", + "scenes.apps.calendar.no_connectors_menu_text": "Du har ingen koblinger som kan kobles til en kalender.", + "scenes.apps.calendar.remove_calendar_confirmation": "Vil du slette kalenderen og dens hendelser permanent?", + "scenes.apps.calendar.today_menu": "I dag", + "scenes.apps.calendar.week_option": "Uke", + "scenes.apps.calendar.workspace": "ArbeidsomrΓ₯de", + "scenes.apps.calendar.workspace_label": "Dette arbeidsomrΓ₯det", + "scenes.apps.calendar.workspace_menu": "ArbeidsomrΓ₯de", + "scenes.apps.drive.add_button": "Legge til", + "scenes.apps.drive.message_added_file": "{{$1}} sendte {{$2}}.", + "scenes.apps.drive.message_added_mutiple_files": "{{$1}} sendte flere filer.", + "scenes.apps.drive.message_added_file_no_name": "{{$1}} sendte en fil.", + "scenes.apps.drive.choose_folder_button": "Velg en katalog", + "scenes.apps.drive.choose_file_button": "Velg en fil", + "scenes.apps.drive.create_folder_button": "Skape", + "scenes.apps.drive.download_button": "nedlasting", + "scenes.apps.drive.open_link": "Γ…pne lenken i nytt vindu", + "scenes.apps.drive.files_subtitle": "Filer", + "scenes.apps.drive.folder_subtitle": "Mapper", + "scenes.apps.drive.go_out_trash_menu": "Legg igjen sΓΈppel", + "scenes.apps.drive.go_trash_menu": "GΓ₯ til sΓΈpla", + "scenes.apps.drive.import_from_computer_menu": "Last opp fra datamaskinen", + "scenes.apps.drive.move_text": "Bevege seg", + "'": "'", + "\"": "\"", + "login.login_error": "Feil under pΓ₯logging", + "scenes.app.workspaces.welcome_page.no_workspace_subtitle": "Ingen har invitert deg til et arbeidsomrΓ₯de ennΓ₯.", + "scenes.apps.messages.message.types.no_message_in_thread": "Ingen har svart ennΓ₯.", + "login.create_account": "Opprett konto", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.label": "Standard arbeidsomrΓ₯de", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.description": "Inviter automatisk alle arbeidsomrΓ₯debrukere til denne kanalen", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.title": "Du er i ferd med Γ₯ slette {{$1}}", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.alert_total_members": "Du har fortsatt {{$1}} medlemmer i {{$2}}. Du bΓΈr fjerne alle medlemmene for Γ₯ kunne slette dette arbeidsomrΓ₯det.", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.checkbox": "Jeg forstΓ₯r at alle meldingene og filene pΓ₯ arbeidsomrΓ₯det mitt vil bli slettet.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.max_size": "Maks logostΓΈrrelse er 5mb", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.bad_format": "DΓ₯rlig format, kun png gif og jpg er tillatt", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.unknown": "Ukjent feil", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.prefix": "Feil", + "scenes.app.channelsbar.currentuser.reset": "Nullstille", + "components.rich_text_editor.plugins.suggestions.default_message.display_results": "Skriv minst tre bokstaver for Γ₯ vise brukere", + "components.rich_text_editor.plugins.suggestions.default_message.no_user_found": "Ingen bruker funnet", + "components.rich_text_editor.plugins.suggestions.default_message.no_emoji_found": "Ingen emoji funnet", + "components.rich_text_editor.plugins.suggestions.default_message.no_command_found": "Ingen kommando funnet", + "scenes.app.messages.input.parts.is_writing.message.user_is_writing": "{{$1}} skriver...", + "scenes.app.messages.input.parts.is_writing.message.users_are_writing": "{{$1}} og {{$2}} skriver...", + "scenes.app.messages.input.parts.is_writing.message.users_and_more_are_writing": "{{$1}}, {{$2}} og {{$3}} flere brukere skriver...", + "components.locked_features_components.locked_invite_alert.message_part_1": "Firmaet ditt har nΓ₯dd sin maksimale grense pΓ₯ {{$1}} medlemmer. VΓ¦r sΓ₯ snill ", + "components.locked_features_components.locked_invite_alert.message_link": "oppgradere bedriften din", + "components.locked_features_components.locked_invite_alert.message_part_2": " Γ₯ invitere flere medlemmer.", + "components.locked_features_components.locked_invite_alert.message_magic_link": " kontakt eieren eller administratoren av bedriften din.", + "views.client.popup.workspace_parameter.pages.workspace_members.link_to_console": "Se alle firmamedlemmene mine pΓ₯ konsollen", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed": "Fjernet applikasjonen {{$1}} !", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed_error": "Feil under fjerning av applikasjonen {{$1}} !", + "scenes.app.popup.appsparameters.pages.application_editor.application_published": "Vellykket {{$1}}-applikasjon!", + "scenes.app.integrations_parameters.add_application": "Ny integrasjon", + "scenes.app.integrations_parameters.company_applications_table.more_menu.developer_settings": "Utviklerinnstillinger", + "scenes.app.popup.appsparameters.pages.application_editor.help_link": "Twake API-dokumentasjonen", + "scenes.app.popup.appsparameters.pages.app.private_key": "Privat nΓΈkkel", + "scenes.app.popup.appsparameters.pages.amazing_app_description": "Beskriv sΓΈknaden din med noen fΓ₯ ord", + "scenes.app.popup.appsparameters.pages.application_creator.title": "Ny integrasjon", + "scenes.app.popup.appsparameters.pages.application_creator.checkbox": "Jeg forstΓ₯r at eieren og administratorene av dette selskapet vil kunne endre og publisere denne applikasjonen.", + "twake.application.access.title": "Velg de riktige omfangene for applikasjonen din.", + "twake.application.access.no_default_scopes_available'": "Denne integrasjonen har ingen {{$1}}-tilgang", + "scenes.app.popup.appsparameters.pages.application_editor.help_text": "Hvis du ikke vet hvordan du fyller disse, gΓ₯ til ", + "components.rich_text_editor.plugins.suggestions.loading": "Ser etter mer", + "components.open_desktop_popup.subtitle": "Γ₯pnet i Twake-appen", + "components.open_desktop_popup.open_here_link": "Γ…pne her i stedet", + "molecules.download_banner.title": "FΓ₯ mest mulig ut av Twake, last ned skrivebordsappen nΓ₯", + "molecules.download_banner.download_button": "Last ned desktop app", + "scenes.app.channelsbar.channel_copy_link": "Kopier kanallinken", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.success.update": "Vellykket oppdatert", + "components.searchpopup.no_results_for": "Det var ingen resultater for", + "components.searchpopup.try_new_search": "PrΓΈv et nytt sΓΈk", + "components.searchpopup.all": "Alle", + "components.searchpopup.chats": "Chatter", + "components.searchpopup.media": "Media", + "components.searchpopup.files": "Filer", + "components.searchpopup.recent_chats": "Nylige chatter", + "components.searchpopup.recent_media": "Nylige medier", + "components.searchpopup.recent_files": "Nylige filer", + "components.searchpopup.recent_channels_and_contacts": "Nylige kanaler og kontakter", + "components.searchpopup.header_title": "SΓΈk", + "components.searchpopup.scope.company": "i alle selskap", + "components.searchpopup.scope.channel": "i denne kanalen", + "components.searchpopup.channels": "Kanaler", + "components.searchpopup.messages": "Meldinger", + "scenes.client.channelbar.channelmemberslist.search_invite_type_email": "Skriv inn en gyldig adresse for Γ₯ invitere via e-post.", + "scenes.client.join_private_channel.info": "Dette innholdet pΓ₯ denne kanalen er begrenset eller eksisterer ikke. Ta kontakt med et medlem av denne kanalen for Γ₯ bli invitert.", + "scenes.client.join_public_channel": "Bli med pΓ₯ denne kanalen", + "general.yes": "Ja", + "components.searchpopup.start_search": "Skriv inn noen fΓ₯ nΓΈkkelord for Γ₯ starte sΓΈket.", + "components.searchpopup.see_more": "Se mer", + "scenes.client.channelbar.channelmemberslist.search_invite": "SΓΈk etter og inviter brukere til denne kanalen", + "scenes.client.channelbar.channelmemberslist.search_invite_notice": "Det er ikke mange medlemmer i denne kanalen. SΓΈk og inviter brukere nΓ₯ via e-post eller navn.", + "scenes.client.channelbar.channelmemberslist.invite_email_button": "Legg kun til i kanalen som gjest", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace": "Legg til kanal og arbeidsomrΓ₯de som medlem", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace_confirm": "Invitere {{$1}} til arbeidsomrΓ₯det som medlem?", + "scenes.client.channelbar.channelmemberslist.pending_section": "Brukere venter pΓ₯ invitasjon", + "scenes.client.channelbar.channelmemberslist.members_section": "Brukere i denne kanalen", + "scenes.client.channelbar.channelmemberslist.not_members_section": "Brukere som ikke er i denne kanalen", + "scenes.client.join_public_channel.info": "Du er ikke medlem av denne direkte kanalen. Klikk pΓ₯ denne knappen for Γ₯ starte diskusjonen nΓ₯.", + "general.no": "Nei", + "components.open_desktop_popup.open_here_link_forever": "PrΓΈv aldri Γ₯ Γ₯pne appen igjen", + "components.channel_attachement_list.medias": "Medias", + "components.channel_attachement_list.files": "Filer", + "components.channel_attachement_list.title": "Kanalfiler og media", + "components.channel_attachement_list.nothing_found": "Ingenting her ennΓ₯", + "molecules.message_quote.deleted": "Denne meldingen ble slettet", + "scenes.apps.messages.jump": "GΓ₯ til melding", + "components.channel_attachement_list.open": "Γ…pent galleri", + "scenes.apps.account.on_console": "For Γ₯ redigere dine globale kontopreferanser, klikk pΓ₯ GΓ₯ til konsoll.", + "scenes.apps.account.assistant.description": "Twake-assistenten er i stand til Γ₯ gi mening om det daglige arbeidet ditt pΓ₯ Twake og gi smarte snarveier og handlinger i lΓΈpet av dagen. Assistenten er en del av Work@Home-initiativet https://workathome.linagora.com/ og testes forelΓΈpig kun i Linagora-selskapet og er i lΓ¦ringsfasen. Det betyr at vi vil sende Twake-bruksdata for Γ₯ trene vΓ₯r fremtidige assistentfunksjon.", + "scenes.apps.account.assistant.share.nothing": "Ikke del noe med assistenten (deaktiver assistent)", + "scenes.apps.account.assistant.share.all": "Del alt inkludert meldinger og filinnhold", + "scenes.apps.account.assistant.share.metadata": "Del metadata, men ikke innhold", + "scenes.apps.account.assistant.success": "Dine preferanser har blitt oppdatert med suksess.", + "scenes.apps.account.assistant.title": "Assistent", + "components.message_seen_by.title": "Brukere som har sett meldingen", + "components.message_seen_by.none_seen_it": "Ingen har sett meldingen ennΓ₯", + "components.message_seen_by.btn": "Informasjon", + "molecules.quoted_content.attachements": "{{$1}} vedlegg", + "scenes.apps.messages.message.user_deactivated": "Du ser pΓ₯ arkivene til en deaktivert konto", + "general.user.deactivated": "Brukeren er ikke lenger i dette selskapet", + "general.user.connected": "pΓ₯ nett", + "scenes.app.popup.userparameter.pages.email_notif_delay_never": "Aldri", + "scenes.app.popup.userparameter.pages.email_notif_delay_quarter_hour": "15 minutter", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_day": "1 dag", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_hour": "1 time", + "scenes.app.popup.userparameter.pages.notification_sound.defaut": "Misligholde", + "scenes.app.popup.userparameter.pages.notification_sound.none": "Ingen", + "scenes.client.channelbar.readonly_channel.checkbox": "Begrens skriveevnen", + "scenes.apps.messages.message.forward": "Framover", + "scenes.apps.messages.message.forward.title": "Videresend melding", + "scenes.apps.messages.message.forward.comment": "Legg til en melding", + "scenes.apps.messages.message.forward.confirm": "Send til $1 kanal(er)", + "scenes.apps.messages.message.forward.send": "Melding videresendt", + "components.channelselector.title": "Velg kanaler", + "components.channelselector.confirm": "Velg $1 kanal(er)", + "components.channelselector.search": "SΓΈk i kanaler og diskusjoner", + "scenes.app.channelsbar.channel_access": "Kanaltilgang", + "scenes.app.channelsbar.channel_access.save": "Lagre tilgangsinnstillinger", + "scenes.app.channelsbar.channel_access.readonly": "Skrivebeskyttet kanal", + "scenes.app.channelsbar.channel_access.readonly.info": "Begrens skriving til moderatorer, administratorer og eiere.", + "scenes.app.channelsbar.channel_access.visibility": "Offentlig synlighet", + "scenes.app.channelsbar.channel_access.visibility.info": "Alle unntatt bedriftsgjester kan vΓ¦re med.", + "scenes.app.channelsbar.channel_access.default": "Bli med automatisk", + "scenes.app.channelsbar.channel_access.default.info": "Nye medlemmer legges til her automatisk.", + "scenes.app.channelsbar.channel_information": "Rediger kanalinformasjon", + "scenes.app.channelsbar.channel_information.logo.add": "Last opp bilde", + "scenes.app.channelsbar.channel_information.logo.remove": "Fjern bildet", + "scenes.app.channelsbar.channel_information.name": "Kanalnavn", + "scenes.app.channelsbar.channel_information.description": "Kanalbeskrivelse", + "scenes.app.channelsbar.channel_information.description.placeholder": "Kanalbeskrivelse, du kan bruke markdown.", + "scenes.app.channelsbar.channel_information.group": "Kanalgruppe", + "scenes.app.channelsbar.channel_information.group.none": "Ikke valgt", + "scenes.app.channelsbar.channel_information.group.new": "Opprett en ny gruppe", + "scenes.app.channelsbar.channel_information.group.save": "Sett kanalgruppen til $1", + "scenes.app.channelsbar.channel_information.group.save_none": "Ikke still inn kanalgruppe", + "scenes.app.channelsbar.channel_information.save": "Lagre informasjon", + "components.invitation.invitation_sent.button": "Send flere invitasjoner", + "scenes.client.channelbar.channelmemberslist.invite_to_workspace": "Inviter {{$1}} til arbeidsomrΓ₯det ➑", + "components.invitation.reached_limit.text": "du nΓ₯dde maksimalt antall brukere i bedriften din. Øk abonnementet ditt eller legg til disse brukerne som gjester", + "components.invitation.allow_anyone_by_email.text": "La alle med @{{$1}} e-post bli med i dette arbeidsomrΓ₯det", + "components.invitation.invitation_channels.button": "Inviter til kanaler", + "components.invitation.invitation_input_list.add": "Legge til", + "components.invitation.invitation_input_list.member": "Medlem", + "components.invitation.invitation_input_list.guest": "Gjest", + "components.invitation.invitation_input_list.placeholder": "Begynn Γ₯ skrive en e-post", + "components.invitation.invitation_sent.title": "Invitasjoner er sendt", + "components.invitation.invitation_sent.subtitle_status": "Du kan spore invitasjonsstatus i:", + "components.invitation.invitation_sent.subtitle_location": "ArbeidsomrΓ₯deinnstillinger > Medlemsadministrasjon", + "components.invitation.invitation_sent.link": "Sjekk invitasjonsstatus", + "components.invitation.invitation_target.invite_as_guests": "Inviter alle som gjester", + "components.invitation.invitation_target.invite_as_members": "Inviter alle som medlemmer", + "components.invitation.invitation_target.channels_button": "Kanaler Γ₯ invitere", + "components.invitation.workspace_link.text": "Invitasjonslenke til arbeidsomrΓ₯de", + "components.invitation.workspace_link.button": "Kopiere", + "components.invitation.title": "inviter folk til {{$1}}", + "components.invitation.bulk_invitation": "Masseinvitasjon", + "components.invitation.button": "Send invitasjoner", + "scenes.client.readonly.info": "Denne kanalen er en skrivebeskyttet feed, men du kan kommentere i trΓ₯dene.", + "scenes.app.channelsbar.channel_information.group.title": "Kanalgrupper", + "components.invitation.custom_role_invitation": "Klassisk invitasjon", + "components.invitation.link": "Link" +} diff --git a/twake/frontend/public/locales/pt.json b/twake/frontend/public/locales/pt.json new file mode 100644 index 00000000..7c5872ee --- /dev/null +++ b/twake/frontend/public/locales/pt.json @@ -0,0 +1,1008 @@ +{ + "scenes.app.channelsbar.currentuser.company_messages_counter_header": "NΓΊmero das mensagens", + "scenes.app.mainview.tabs.rename": "Renomear", + "scenes.app.popup.adduser.magiclinks.action_copy": "cΓ³pia de", + "scenes.app.popup.appsparameters.pages.alert_published_app": "Seu aplicativo foi publicado, vocΓͺ nΓ£o pode editΓ‘-lo.", + "scenes.app.popup.appsparameters.pages.automatique_label": "AutomΓ‘tico", + "services.apps.calendar.deadline_icon": "Data limite", + "components.input.copied": "Copiado", + "scenes.apps.tasks.active_tasks": "tarefas ativas", + "scenes.app.popup.appsparameters.pages.icon": "Ícone", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_edition": "Renomear {{$1}}", + "components.alert.leave_private_channel.title": "Tem certeza de que deseja sair do canal?", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.loader": "Carregue mais", + "components.add_mails_workspace.title_1": "Adicionar alguns usuΓ‘rios", + "components.locked_features.locked_history_banner.button": "Saber mais", + "components.locked_features.locked_workspace_popup.subtitle": "Na versΓ£o gratuita, vocΓͺ pode ter apenas um workspace em sua empresa.", + "scenes.apps.messages.input.replied_to": "respondeu a ", + "scenes.app.popup.appsparameters.pages.application_creator.title": "Nova integraΓ§Γ£o", + "scenes.app.popup.appsparameters.pages.app.private_key": "Chave privada", + "scenes.app.channelsbar.currentuser.company_messages_counter_info": "Na versΓ£o gratuita do Twake, vocΓͺ nΓ£o pode acessar mais de {{$1}} mensagens recentes.", + "scenes.app.channelsbar.currentuser.company_messages_counter_link": "Mostrar mais planos", + "scenes.app.channelsbar.channelsuser.new_private_discussion": "Nova discussΓ£o privada", + "scenes.app.channelsbar.channelsuser.no_private_message_invite_collaboraters": "Sem mensagens privadas. Convide usuΓ‘rios!", + "scenes.app.channelsbar.channelsuser.private_messages": "Mensagens diretas", + "scenes.app.channelsbar.channelsworkspace.channel_title": "CANAIS", + "scenes.app.channelsbar.channelsworkspace.channel_title.favorite": "FAVORITOS", + "scenes.app.channelsbar.channelsworkspace.create_channel": "Criar um canal", + "scenes.app.channelsbar.channelsworkspace.no_channel": "VocΓͺ ainda nΓ£o entrou em nenhum canal", + "scenes.app.channelsbar.modify_channel_menu": "Editar canal", + "scenes.app.channelsbar.guest_management": "Gerenciamento de convidados", + "scenes.app.channelsbar.read_sign": "Marcar como Lido", + "scenes.app.channelsbar.unread_sign": "Marcar como nΓ£o lido", + "scenes.app.channelsbar.channel_copy_link": "Copiar link do canal", + "scenes.app.channelsbar.channel_leaving": "Sair do canal", + "scenes.app.channelsbar.channel_removing": "Excluir canal", + "scenes.app.channelsbar.company_invitation_alert_subtitle": "VocΓͺ pode importar esses canais para o seu negΓ³cio para se manter organizado clicando nesta moldura.", + "scenes.app.channelsbar.company_invitation_alert_title": "VocΓͺ estΓ‘ convidado para a empresa ", + "scenes.app.channelsbar.initial_instructions_tutorial": "Escolha um nome e uma foto de perfil.", + "scenes.app.channelsbar.installation_desktop_tutorial": "Instale o aplicativo de desktop", + "scenes.app.channelsbar.invitation_collaboraors_tutorial": "Convide usuΓ‘rios para seu espaΓ§o de trabalho.", + "scenes.app.channelsbar.public_channel_label": "PΓΊblico", + "scenes.app.channelsbar.private_channel_label": "Privado", + "scenes.app.channelsbar.sending_message_instruction": "Envie sua primeira mensagem em uma discussΓ£o", + "scenes.app.channelsbar.tutorial_alert": "Nunca mostrar este quadro novamente?", + "scenes.app.channelsbar.welcome": "Bem-vindo ao Twike", + "scenes.app.channelsbar.welcoming_message_subtitle": "Torne-se um profissional Twake em apenas alguns cliques!", + "scenes.app.mainview.instruction_current_tab": "Comece selecionando um canal Γ  sua esquerda.", + "scenes.app.mainview.tabs.no_connected_connectors_for_channel": "VocΓͺ nΓ£o tem nenhum conector que possa se conectar a um canal.", + "scenes.app.mainview.tabs.searching_connectors": "Pesquisar conectores...", + "scenes.app.popup.adduser.adresses_message": "Por favor, separe os endereΓ§os com uma vΓ­rgula ou espaΓ§o. Lembre-se de que o Twake pode limitar o nΓΊmero de convites com base em sua assinatura.", + "scenes.app.popup.adduser.magiclinks.genrator_info": "Link de convite para o espaΓ§o de trabalho", + "scenes.app.popup.adduser.magiclinks.new_link_generated": "Novo link gerado", + "scenes.app.popup.adduser.magiclinks.copied_to_clipboard": "Copiado com sucesso para a Γ‘rea de transferΓͺncia", + "scenes.app.popup.adduser.magiclinks.action_generate": "Gerar", + "scenes.app.popup.appsparameters.pages._app_identity": "Identidade do aplicativo", + "scenes.app.popup.appsparameters.pages._appareance_message_twakcode": "Teste a aparΓͺncia de suas mensagens Twacode", + "scenes.app.popup.appsparameters.pages.allowed_ip_adresses_method": "Use * em desenvolvimento para permitir todos os endereΓ§os IP.", + "scenes.app.popup.appsparameters.pages.amazing_app_name": "Meu aplicativo incrΓ­vel", + "scenes.app.popup.appsparameters.pages.api_data_description": "Dados ΓΊteis para a API Twake.", + "scenes.app.popup.appsparameters.pages.api_parameters_label": "ConfiguraΓ§Γ΅es da API", + "scenes.app.popup.appsparameters.pages.app_name_label": "Nome da AplicaΓ§Γ£o", + "scenes.app.popup.appsparameters.pages.app_modification_right": "Todos os gerentes desta empresa poderΓ£o editar este aplicativo.", + "scenes.app.popup.appsparameters.pages.app_privileges_information": "Defina o que seu aplicativo pode editar e ler.", + "scenes.app.popup.appsparameters.pages.app_privileges_label": "PrivilΓ©gios do aplicativo", + "scenes.app.popup.appsparameters.pages.app_update": "Atualize o aplicativo {{$1}} (o aplicativo Γ© usado {{$2}} vezes)", + "scenes.app.popup.appsparameters.pages.application_title": "InscriΓ§Γ£o", + "scenes.app.popup.appsparameters.pages.apps_title": "Seus aplicativos e conectores", + "scenes.app.popup.appsparameters.pages.automatique_option_information": "Se vocΓͺ ativar 'AutomΓ‘tico', este aplicativo serΓ‘ adicionado automaticamente aos prΓ³ximos workspaces desta empresa.", + "scenes.app.popup.appsparameters.pages.autorised_ip_adresses_label": "EndereΓ§os IP permitidos", + "scenes.app.popup.appsparameters.pages.available_publication_alert": "A publicaΓ§Γ£o do seu pedido estΓ‘ atualmente aguardando validaΓ§Γ£o pela equipe Twake.", + "scenes.app.popup.appsparameters.pages.button_force": "ForΓ§a em toda a empresa", + "scenes.app.popup.appsparameters.pages.call_event_handlers": "Evento do tipo '{{$1}}' e id '{{$2}}' com passivas '{{$3}}'", + "scenes.app.popup.appsparameters.pages.company_label": "ProprietΓ‘rio da empresa", + "scenes.app.popup.appsparameters.pages.configuration_label": "ConfiguraΓ§Γ£o", + "scenes.app.popup.appsparameters.pages.create_app_button": "Criar um aplicativo", + "scenes.app.popup.appsparameters.pages.create_my_app": "Criar meu aplicativo", + "scenes.app.popup.appsparameters.pages.current_informations_apps_connectors": "VocΓͺ ainda nΓ£o criou um aplicativo. Antes de criar um aplicativo ou conector, certifique-se de que ele ainda nΓ£o exista em nosso mercado de aplicativos.", + "scenes.app.popup.appsparameters.pages.danger_zone_description": "Excluir aplicativo", + "scenes.app.popup.appsparameters.pages.danger_zone_label": "Zona perigosa", + "scenes.app.popup.appsparameters.pages.description_label": "DescriΓ§Γ£o", + "scenes.app.popup.appsparameters.pages.developped_apps_subtitle": "Aplicativos desenvolvidos pela empresa", + "scenes.app.popup.appsparameters.pages.dispalyed_parameters_description": "Permite definir onde seu aplicativo ficarΓ‘ visΓ­vel.", + "scenes.app.popup.appsparameters.pages.displayed_parameters_label": "ConfiguraΓ§Γ΅es do visor", + "scenes.app.popup.appsparameters.pages.error_check_needed": "Ocorreu um erro; verifique suas informaΓ§Γ΅es.", + "scenes.app.popup.appsparameters.pages.error_message": "Esse nome jΓ‘ Γ© usado por outro aplicativo; por favor escolha outro.", + "scenes.app.popup.appsparameters.pages.error_user_code": "erro", + "scenes.app.popup.appsparameters.pages.event_subtitle": "Eventos", + "scenes.app.popup.appsparameters.pages.filter_information": "Este filtro limita o uso de sua chave de API apenas para servidores em seu conector.", + "scenes.app.popup.appsparameters.pages.go_back": "De volta", + "scenes.app.popup.appsparameters.pages.grp_section_name-error": "Este nome jΓ‘ estΓ‘ em uso por outro aplicativo. Por favor escolha outro.", + "scenes.app.popup.appsparameters.pages.grp_section_surname_label": "Nome simplificado", + "scenes.app.popup.appsparameters.pages.installation": "Instalar.", + "scenes.app.popup.appsparameters.pages.instruction_message_twakecode": "Comece escrevendo sua mensagem no formato JSON.", + "scenes.app.popup.appsparameters.pages.interne_availability_application": "Aplicativo interno", + "scenes.app.popup.appsparameters.pages.json_configuration_information": "Acesse a documentaΓ§Γ£o para gerar sua configuraΓ§Γ£o no formato JSON.", + "scenes.app.popup.appsparameters.pages.loading": "Carregando...", + "scenes.app.popup.appsparameters.pages.message_data_next_event": "Dados passivos que serΓ£o enviados no prΓ³ximo Evento", + "scenes.app.popup.appsparameters.pages.modify_public_data": "Edite os dados pΓΊblicos do seu aplicativo.", + "scenes.app.popup.appsparameters.pages.new_app_title": "Nova aplicaΓ§Γ£o", + "scenes.app.popup.appsparameters.pages.ok_user_code": "OK", + "scenes.app.popup.appsparameters.pages.optimal_format": "Formato ideal: 48x48px.", + "scenes.app.popup.appsparameters.pages.parameters_form_small_text": "O aplicativo nΓ£o publicado funcionarΓ‘ apenas na sua empresa. Se vocΓͺ deseja disponibilizΓ‘-lo para todos os usuΓ‘rios do Twake, ative esta opΓ§Γ£o.", + "scenes.app.popup.appsparameters.pages.public_availability_application": "Aplicativo pΓΊblico", + "scenes.app.popup.appsparameters.pages.public_login_label": "Identificador pΓΊblico", + "scenes.app.popup.appsparameters.pages.publication_description": "Determine a visibilidade do seu aplicativo.", + "scenes.app.popup.appsparameters.pages.publication_label": "PublicaΓ§Γ£o", + "scenes.app.popup.appsparameters.pages.publish_app_label": "Publicar aplicativo", + "scenes.app.popup.appsparameters.pages.read_privileges_label": "PrivilΓ©gios de leitura", + "scenes.app.popup.appsparameters.pages.remove_app": "Exclua o aplicativo {{$1}} permanentemente.", + "scenes.app.popup.appsparameters.pages.remove_app_from_company": "Remover de toda a empresa", + "scenes.app.popup.appsparameters.pages.remove_app_from_workspace": "Remover do espaΓ§o de trabalho", + "scenes.app.popup.appsparameters.pages.show_button": "mostrar", + "scenes.app.popup.appsparameters.pages.status_tilte": "Estado", + "scenes.app.popup.appsparameters.pages.string_information": "Essa cadeia identifica o sua aplicaΓ§Γ£o e serΓ‘ usada em comandos de mensagem.", + "scenes.app.popup.appsparameters.pages.title_tester": "Testador de Twakecode", + "scenes.app.popup.appsparameters.pages.url_reception_events_label": "URL de recepΓ§Γ£o de eventos", + "scenes.app.popup.appsparameters.pages.waiting_availability_application": "Aguardando...", + "scenes.app.popup.appsparameters.pages.website_label": "Local na rede Internet", + "scenes.app.popup.appsparameters.pages.write_privileges_label": "PrivilΓ©gios de gravaΓ§Γ£o", + "scenes.app.popup.appsparameters.pages.danger_zone_small_text": "VocΓͺ nΓ£o pode excluir este aplicativo se ele for publicado.", + "scenes.app.popup.appsparameters.pages.error_app_simple_name_message": "O nome simplificado do seu aplicativo jΓ‘ Γ© usado por outro aplicativo. Por favor, altere-o.", + "scenes.app.popup.appsparameters.pages.error_app_update_message": "Ocorreu um erro ao atualizar o aplicativo.", + "scenes.app.popup.appsparameters.pages.remove_app_button": "Excluir aplicativo", + "scenes.app.popup.appsparameters.pages.update_button": "Atualizar", + "scenes.app.popup.createworkspacepage.add_subtitle": "Preciso de mais espaΓ§o?", + "scenes.app.popup.createworkspacepage.create_new_workspace": "Criar um novo espaΓ§o de trabalho", + "scenes.app.popup.createworkspacepage.placeholder_name": "Nome do espaΓ§o de trabalho", + "scenes.app.popup.userparameter.pages.frequency_notif_configuration_description": "Defina a frequΓͺncia das notificaΓ§Γ΅es mΓ³veis.", + "scenes.app.popup.userparameter.pages.frequency_notif_subtitle": "FrequΓͺncia de notificaΓ§Γ΅es", + "scenes.app.popup.userparameter.pages.keywords_notif_description": "Destaque as seguintes palavras-chave:", + "scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description": "Defina a frequΓͺncia das notificaΓ§Γ΅es por e-mail.", + "scenes.app.popup.userparameter.pages.private_message_content.show": "Mostrar conteΓΊdo de mensagens privadas", + "scenes.app.popup.userparameter.pages.private_message_content.hide": "Ocultar o conteΓΊdo das mensagens privadas", + "scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description": "Escolha um perΓ­odo durante o qual vocΓͺ nΓ£o recebe notificaΓ§Γ΅es.", + "scenes.app.popup.userparameter.pages.no_night_disturbing_label": "NΓ£o perturbe Γ  noite", + "scenes.app.popup.userparameter.pages.notif_content_label": "ConteΓΊdo das notificaΓ§Γ΅es", + "scenes.app.mainview.quick_search_placeholder": "Pesquisa rΓ‘pida", + "scenes.app.popup.userparameter.personnal_workspaces_title": "Seus espaΓ§os de trabalho", + "scenes.app.popup.workspaceparameter.admin_current_status": "VocΓͺ Γ© um Administrador.", + "scenes.app.popup.workspaceparameter.admin_manager_current_status": "VocΓͺ Γ© um administrador do espaΓ§o de trabalho.", + "scenes.app.popup.workspaceparameter.manager_current_status": "VocΓͺ Γ© um administrador da empresa.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace": "Excluir espaΓ§o de trabalho", + "scenes.app.popup.workspaceparameter.pages.error_workspace_member": "VocΓͺ deve estar sozinho no espaΓ§o de trabalho para removΓͺ-lo. Remova seus colaboradores e tente novamente.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace_description": "A exclusΓ£o de um espaΓ§o de trabalho nΓ£o pode ser desfeita. Todas as mensagens e arquivos serΓ£o irrecuperΓ‘veis.", + "scenes.app.popup.workspaceparameter.pages.enter": "Digitar ", + "scenes.app.popup.workspaceparameter.pages.access_apps": "Acesse seus aplicativos e conectores", + "scenes.app.popup.workspaceparameter.pages.moderator_status": "Moderador do espaΓ§o de trabalho", + "scenes.app.popup.workspaceparameter.pages.alert_impossible_removing": "VocΓͺ nΓ£o pode sair da Γ‘rea de trabalho, porque vocΓͺ Γ© o ΓΊltimo administrador. VocΓͺ pode definir um novo administrador ou excluir/arquivar este espaΓ§o de trabalho.", + "scenes.app.popup.workspaceparameter.pages.all_apps_small_text": "Todos os aplicativos", + "scenes.app.popup.workspaceparameter.pages.apps_company_small_text": "Aplicativos da sua empresa", + "scenes.app.popup.workspaceparameter.pages.apps_connectors_title": "IntegraΓ§Γ΅es", + "scenes.app.popup.workspaceparameter.pages.apps_research_title": "Aplicativos de pesquisa", + "scenes.app.popup.workspaceparameter.pages.apps_small_text": "AplicaΓ§Γ΅es deste espaΓ§o de trabalho", + "scenes.app.popup.workspaceparameter.pages.back_to_search_button": "Voltar para a pesquisa", + "scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button": "Convidar usuΓ‘rios", + "scenes.app.popup.workspaceparameter.pages.collaborateurs": "UsuΓ‘rios", + "scenes.app.popup.workspaceparameter.pages.company_developped_apps_subtitle": "Aplicativos desenvolvidos pela empresa", + "scenes.app.popup.workspaceparameter.pages.company_identity_title": "Identidade da empresa", + "scenes.app.popup.workspaceparameter.pages.company_name_description": "Alterar o nome desta empresa", + "scenes.app.popup.workspaceparameter.pages.company_name_label": "Nome da empresa", + "scenes.app.popup.workspaceparameter.pages.configuration_notif": "configuraΓ§Γ£o", + "scenes.app.popup.workspaceparameter.pages.configure_button": "PreferΓͺncias ", + "scenes.app.popup.workspaceparameter.pages.description": "DescriΓ§Γ£o", + "scenes.app.popup.workspaceparameter.pages.developped_apps_small_text": "Aplicativos desenvolvidos pela empresa", + "scenes.app.popup.workspaceparameter.pages.displayed_preferencies_subtitle": "PreferΓͺncias de exibiΓ§Γ£o", + "scenes.app.popup.workspaceparameter.pages.install_button": "Instalar", + "scenes.app.popup.workspaceparameter.pages.installed_app_information": "Instale o aplicativo neste espaΓ§o de trabalho.", + "scenes.app.popup.workspaceparameter.pages.installed_apps_information": "Aplicativos instalados neste espaΓ§o de trabalho {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_message": "Aplicativos instalados em outras Γ‘reas da empresa {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_subtitle": "Aplicativos instalados", + "scenes.app.popup.workspaceparameter.pages.invitation_error": "Ocorreu um erro ao convidar os seguintes usuΓ‘rios: ", + "scenes.app.popup.workspaceparameter.pages.invited_guest_check_message": "Verifique se o nome de usuΓ‘rio ou e-mail usado Γ© vΓ‘lido.", + "scenes.app.popup.workspaceparameter.pages.logo_modify_description": "Edite a imagem deste espaΓ§o de trabalho", + "scenes.app.popup.workspaceparameter.pages.logo_subtitle": "Logotipo", + "scenes.app.popup.workspaceparameter.pages.name_description": "Alterar o nome deste espaΓ§o de trabalho", + "scenes.app.popup.workspaceparameter.pages.name_label": "Nome do espaΓ§o de trabalho", + "scenes.app.popup.workspaceparameter.pages.no_access": "Sem acesso.", + "scenes.app.popup.workspaceparameter.pages.no_app_information": "VocΓͺ nΓ£o tem aplicativos neste espaΓ§o de trabalho", + "scenes.app.popup.workspaceparameter.pages.quit_workspace_menu": "Sair deste espaΓ§o de trabalho", + "scenes.app.popup.workspaceparameter.pages.read_access_subtitle": "Acesso de leitura", + "scenes.app.popup.workspaceparameter.pages.remove_from_company_text": "Remover de toda a empresa", + "scenes.app.popup.workspaceparameter.pages.research_by": "Pesquise aplicativos por nome e categorias", + "scenes.app.popup.workspaceparameter.pages.researching_apps_button": "Pesquisar aplicativos...", + "scenes.app.popup.workspaceparameter.pages.show_button": "ExibiΓ§Γ£o", + "scenes.app.popup.workspaceparameter.pages.title": "ConfiguraΓ§Γ΅es do espaΓ§o de trabalho", + "scenes.app.popup.workspaceparameter.pages.webhooks_access_subtitle": "Acesso a webhooks", + "scenes.app.popup.workspaceparameter.pages.weight_max_small_text": "Tamanho mΓ‘ximo 5 MB.", + "scenes.app.popup.workspaceparameter.pages.withdraw_button": "Remover deste espaΓ§o de trabalho", + "scenes.app.popup.workspaceparameter.pages.worspace_notif": "Γ‘rea de trabalho", + "scenes.app.popup.workspaceparameter.pages.write_access_subtitle": "Acesso de gravaΓ§Γ£o", + "scenes.app.popup.workspaceparameter.pages.your_apps_label": "Seus aplicativos", + "scenes.app.popup.workspaceparameter.payments_subscriptions_title": "Pagamentos e assinaturas", + "scenes.app.workspacesbar.components.change_company_title": "Mudar empresa", + "scenes.app.workspacesbar.components.create_company_menu": "Crie uma empresa", + "scenes.app.workspacesbar.components.grp_parameters": "{{$1}} configuraΓ§Γ΅es", + "scenes.apps.calendar.add_calendar_menu": "Adicionar um calendΓ‘rio", + "scenes.apps.calendar.connectors_menu": "Conectores...", + "scenes.apps.calendar.connectors_search_menu": "Pesquisar conectores...", + "scenes.apps.calendar.create_calendar_title": "Criar um calendΓ‘rio", + "scenes.apps.calendar.day_option": "Dia", + "scenes.apps.calendar.edit_calendar_title": "Editar o calendΓ‘rio", + "scenes.apps.calendar.export_title": "Exportar", + "scenes.apps.calendar.export_view_menu": "Exportar a visualizaΓ§Γ£o...", + "scenes.apps.calendar.ics_download_menu": "Baixar um arquivo ICS", + "scenes.apps.calendar.ics_subscription_menu": "Obter um link de assinatura do ICS", + "scenes.apps.calendar.modals.advanced_options": "OpΓ§Γ΅es avanΓ§adas", + "scenes.apps.calendar.modals.description_placeholder": "DescriΓ§Γ£o", + "scenes.apps.calendar.modals.details_title": "Detalhes", + "scenes.apps.calendar.modals.event_adresse_placeholder": "EndereΓ§o", + "scenes.apps.calendar.modals.event_description_placeholder": "DescriΓ§Γ£o", + "scenes.apps.calendar.modals.event_title_placeholder": "TΓ­tulo", + "scenes.apps.calendar.modals.modify_event_button": "Editar evento", + "scenes.apps.calendar.modals.part.participants": "Participantes", + "scenes.apps.calendar.modals.participants_event": "Participantes", + "scenes.apps.calendar.modals.reminders": "Lembretes", + "scenes.apps.calendar.modals.remove_button": "Excluir", + "scenes.apps.calendar.modals.remove_event_button": "Excluir evento", + "scenes.apps.calendar.modals.remove_event_text": "Excluir o evento?", + "scenes.apps.calendar.modals.title_placeholder": "TΓ­tulo", + "scenes.apps.calendar.modify_calendar_menu": "Editar o calendΓ‘rio", + "scenes.apps.calendar.month_option": "MΓͺs", + "scenes.apps.calendar.my_calendar": "Meu calendario", + "scenes.apps.calendar.my_calendar_label": "Meu calendario", + "scenes.apps.calendar.my_calendar_menu": "Meu calendario", + "scenes.apps.calendar.no_calendar_text": "VocΓͺ nΓ£o definiu nenhum calendΓ‘rio para este workspace.", + "scenes.apps.calendar.no_connectors_menu_text": "VocΓͺ nΓ£o tem nenhum conector que possa se conectar a um calendΓ‘rio.", + "scenes.apps.calendar.remove_calendar_confirmation": "Excluir o calendΓ‘rio e seus eventos permanentemente?", + "scenes.apps.calendar.today_menu": "Hoje", + "scenes.apps.calendar.week_option": "Semana", + "scenes.apps.calendar.workspace": "Área de trabalho", + "scenes.apps.calendar.workspace_label": "Este espaΓ§o de trabalho", + "scenes.apps.calendar.workspace_menu": "Área de trabalho", + "scenes.apps.drive.add_button": "Adicionar", + "scenes.apps.drive.message_added_file": "{{$1}} enviou {{$2}}.", + "scenes.apps.drive.message_added_mutiple_files": "{{$1}} enviou vΓ‘rios arquivos.", + "scenes.apps.drive.message_added_file_no_name": "{{$1}} enviou um arquivo.", + "scenes.apps.drive.choose_folder_button": "Escolha um diretΓ³rio", + "scenes.apps.drive.choose_file_button": "Selecione um arquivo", + "scenes.apps.drive.create_folder_button": "Crio", + "scenes.apps.drive.download_button": "Download", + "scenes.apps.drive.open_link": "Abrir link em nova janela", + "scenes.apps.drive.files_subtitle": "arquivos", + "scenes.apps.drive.folder_subtitle": "Pastas", + "scenes.apps.drive.go_out_trash_menu": "Deixar lixo", + "scenes.apps.drive.go_trash_menu": "Ir para o lixo", + "scenes.apps.drive.import_from_computer_menu": "Fazer upload de computador", + "scenes.apps.drive.move_text": "Jogada", + "scenes.apps.drive.new_file_menu": "Novo arquivo", + "scenes.apps.drive.new_file_title": "Novo arquivo", + "scenes.apps.drive.new_external_storage": "Novo armazenamento externo", + "scenes.apps.drive.new_folder_title": "Nova pasta", + "scenes.apps.drive.no_file_alert": "VocΓͺ nΓ£o tem aplicativos que permitem criar um arquivo.", + "scenes.apps.drive.no_storage_app_alert": "VocΓͺ nΓ£o tem aplicativos que permitem adicionar armazenamento externo.", + "scenes.apps.drive.remove_definitely_menu": "Apagar permanentemente", + "scenes.apps.drive.restore_menu": "Restaurar", + "scenes.apps.drive.throw_menu": "Enviar para o lixo", + "scenes.apps.drive.trash_empty_menu": "Esvazie a lixeira", + "scenes.apps.drive.unconfigured_tab": "Esta guia ainda nΓ£o estΓ‘ configurada.", + "scenes.apps.drive.viewer.edit_with_button": "Editar com {{$1}}", + "scenes.apps.drive.viewer.loading_preview_message": "Carregando...", + "scenes.apps.drive.viewer.no_preview_message": "NΓ£o Γ© possΓ­vel visualizar este tipo de arquivo.", + "scenes.apps.drive.viewer.open_with_button": "Abrir com...", + "scenes.apps.messages.input.placeholder": "Escreve uma mensagem. Use @ para citar um usuΓ‘rio.", + "scenes.apps.messages.input.edited": "Editado", + "scenes.apps.messages.just_you": "VisΓ­vel apenas para vocΓͺ", + "scenes.apps.messages.message.new_messages_bar": "Novas mensagens", + "scenes.apps.messages.message.cancel_button": "Cancelar", + "scenes.apps.messages.message.modify_button": "Editar", + "scenes.apps.messages.message.pin_button": "Fixar mensagem", + "scenes.apps.messages.message.unpin_button": "Liberar mensagem", + "scenes.apps.messages.message.copy_link": "Copiar link para mensagem", + "scenes.apps.messages.message.pinned": "Fixado", + "scenes.apps.messages.message.remove_button": "Excluir", + "scenes.apps.messages.message.reply_button": "Responder", + "scenes.apps.messages.message.save_button": "Salvar", + "scenes.apps.messages.message.show_button": "ExibiΓ§Γ£o", + "scenes.apps.messages.message.show_responses_button": "Ver respostas anteriores", + "scenes.apps.messages.message.types.first_channel_message_text": "Esta Γ© a primeira mensagem do canal", + "scenes.apps.messages.message.types.first_message_text": "Esta Γ© a primeira mensagem", + "scenes.apps.messages.message.types.no_message_in_thread": "NinguΓ©m respondeu ainda.", + "scenes.apps.messages.messageslist.get_writing_user": "estΓ‘ escrevendo...", + "scenes.apps.messages.messageslist.get_writing_users": "estΓ£o escrevendo...", + "scenes.apps.messages.messageslist.go_last_message_button": "Ir para a ΓΊltima mensagem", + "scenes.apps.messages.messageslist.go_last_message_button.new_messages": "Novas mensagens", + "scenes.error_on_twake": "\"Houston, nΓ³s temos um problema\"", + "scenes.help_us": "No entanto, se vocΓͺ quiser nos ajudar a corrigir esse erro, envie-nos uma mensagem abaixo: ", + "scenes.login.verifymail.alert": "Estamos verificando seu e-mail!", + "scenes.login.verifymail.error_message": "Um erro ocorreu", + "scenes.login.verifymail.signin_button": "Conecte-se", + "scenes.login.verifymail.success": "Seu e-mail foi verificado com sucesso!", + "scenes.login.verifymail.verification_waiting": "Aguardando verificaΓ§Γ£o...", + "scenes.no_panic": "NΓ£o entrar em pΓ’nico! Basta recarregar esta pΓ‘gina para corrigir o Twake.", + "services.apps.calendar.event_icon": "Evento", + "services.apps.calendar.move_icon": "Jogada", + "services.apps.calendar.reminder_icon": "Lembrete", + "services.apps.messages.no_app": "Este aplicativo nΓ£o existe.", + "services.apps.messages.no_command_possible": "NΓ£o podemos executar o comando '{{$1}}' porque '{{$2}}' nΓ£o existe ou nΓ£o permite criar comandos.", + "services.user.notification_parameters_update_alert": "As configuraΓ§Γ΅es de notificaΓ§Γ£o foram atualizadas.", + "services.user.update_password_alert": "Sua senha foi atualizada.", + "'": "'", + "\"": "\"", + "login.create_account": "Criar Conta", + "login.login_error": "Erro durante o login", + "scenes.app.workspaces.components.skip": "Pular", + "scenes.apps.calendar.unconfigured_tab": "Esta guia ainda nΓ£o estΓ‘ configurada.", + "scenes.apps.drive.trash": "Lixo", + "scenes.apps.drive.top_menu_more": "Mais", + "scenes.apps.drive.top_menu_no_items": "{{$1}} itens", + "scenes.apps.messages.new_thread": "Iniciar uma nova discussΓ£o", + "scenes.apps.messages.input.send_message": "Enviar mensagem", + "scenes.apps.messages.input.emoji": "Emoji", + "scenes.apps.messages.input.hide_formatting": "Ocultar formataΓ§Γ£o", + "scenes.apps.messages.input.show_formatting": "Mostrar formataΓ§Γ£o", + "scenes.tell_us": "Por favor, diga-nos o que vocΓͺ estava fazendo em:", + "scenes.apps.drive.viewer.download_desktop": "Baixe o Twake Desktop para visualizar no aplicativo", + "scenes.apps.tasks.my_tasks": "Minhas tarefas", + "scenes.apps.tasks.board.place_holder": "Nome do conselho", + "scenes.apps.tasks.board.tasks.subtask": "Subtarefa", + "scenes.apps.tasks.board.tasks.add_subtask": "Adicionar uma subtarefa", + "scenes.apps.tasks.board.tasks.use_deadline": "Usar prazo", + "scenes.apps.tasks.board.tasks.use_starttime": "Usar hora de inΓ­cio", + "scenes.apps.tasks.board.tasks.in_list": "Na lista", + "scenes.apps.tasks.board.starts": "Inicia o", + "scenes.apps.tasks.board.ends": "A ser feito para o", + "scenes.apps.tasks.board.list_name": "Lista de nomes", + "scenes.app.popup.sync_calendar": "Sincronize seus calendΓ‘rios.", + "scenes.apps.parameters.workspace_sections.workspace.logo_company": "Logo da empresa", + "scenes.app.popup.workspaceparameter.pages.logo_company_modify_description": "Editar imagem da empresa ", + "scenes.app.popup.workspaceparameter.pages.cancel_invitation": "Cancelar o convite", + "scenes.apps.account.account.fullname": "Nome completo", + "login.email_login": "E-mail / Entrar", + "scenes.apps.account.account.password_for_user": "Senha do seu usuΓ‘rio", + "scenes.apps.account.account.send_info": "Envie essas informaΓ§Γ΅es de credencial para seu usuΓ‘rio.", + "scenes.apps.account.account.save": "Salvar conta", + "scenes.apps.account.message_temporary": "Uma conta temporΓ‘ria funciona como uma conta Twake normal, mas vocΓͺ cria a senha e poderΓ‘ redefini-la, se necessΓ‘rio.", + "scenes.apps.account.message_user_signin": "Seu usuΓ‘rio pode fazer login a qualquer momento usando este mesmo e-mail e alterar a conta temporΓ‘ria para uma conta normal.", + "scenes.app.mainview.link_expired": "Este link pΓΊblico Γ© invΓ‘lido ou expirou.", + "scenes.app.mainview.create_account": "Crie seu espaΓ§o de trabalho gratuitamente em ", + "scenes.apps.calendar.modals.reminder_add": "Adicionar um lembrete", + "scenes.apps.parameters.workspace_sections.members.invite_all": "Convide todos", + "scenes.app.taskpicker.select": "Selecionar", + "components.listmanager.filter": "Filtro", + "scenes.apps.tasks.no_connector": "Sem conector", + "components.attachmentpicker.add_attachment": "Adicionar Anexos", + "components.drive.new_versions": "Adicionar uma nova versΓ£o", + "components.drive.navigators.directory_not_found": "DiretΓ³rio nΓ£o encontrado.", + "components.drive.right_preview.suppress_link": "Suprimir o link", + "components.drive.right_preview.create_link": "Criar um link de acesso", + "components.drive.moove_here": "Mover aqui", + "components.drive.modify_uslist": "Modificar lista de usuΓ‘rios", + "components.tagpicker.tag_name": "Nome da etiqueta", + "components.upload.drop_files": "Solte seus arquivos aqui", + "components.workspace.list_manager.no_workspace": "Sem espaΓ§o de trabalho", + "components.workspace.list_manager.add": "Adicionar espaΓ§os de trabalho", + "components.workspace.list_manager.current_space": "Área de trabalho atual", + "components.workspace.list_manager.current_company": "Empresa atual", + "components.workspace.list_manager.all": "Tudo", + "components.workspace.calendar.invalid": "InvΓ‘lido", + "components.searchpopup.header_title": "Procurar", + "components.searchpopup.enter_text": "Digite algum texto para pesquisar Twake.", + "components.searchpopup.loading": "Carregando mais resultados", + "components.searchpopup.filter_ws": "Filtrar espaΓ§os de trabalho", + "components.searchpopup.tags": "Tag", + "components.searchpopup.size": "Tamanho", + "components.searchpopup.creation": "CriaΓ§Γ£o", + "components.searchpopup.update_search": "Atualizar pesquisa", + "components.searchpopup.last_modif": "Última modificaΓ§Γ£o", + "components.searchpopup.sender": "Remetente", + "components.searchpopup.mentions": "MenΓ§Γ΅es", + "components.searchpopup.only_pinned": "Apenas mensagens fixadas", + "components.alert.confirm": "Confirme sua aΓ§Γ£o", + "components.alert.confirm_click": "Confirme sua aΓ§Γ£o clicando em OK.", + "components.searchpopup.tasks": "Tarefas", + "scenes.app.mainview.advanced_search_placeholder": "Busca AvanΓ§ada", + "components.searchpopup.hide_filters": "ocultar filtros", + "components.searchpopup.show_filters": "mostrar filtros", + "components.searchpopup.load_more": "Carregar mais resultados", + "components.searchpopup.start_search": "Digite algumas palavras-chave para iniciar a pesquisa.", + "components.searchpopup.no_results_for": "NΓ£o houve resultados para", + "components.searchpopup.try_new_search": "Tente uma nova pesquisa", + "components.searchpopup.scope.company": "em toda empresa", + "components.searchpopup.scope.channel": "neste canal", + "components.searchpopup.all": "Tudo", + "components.searchpopup.chats": "Bate-papo", + "components.searchpopup.channels": "Canais", + "components.searchpopup.messages": "Mensagens", + "components.searchpopup.media": "meios de comunicaΓ§Γ£o", + "components.searchpopup.files": "arquivos", + "components.searchpopup.see_more": "Ver mais", + "components.searchpopup.recent_chats": "Bate-papos recentes", + "components.searchpopup.recent_media": "MΓ­dia recente", + "components.searchpopup.recent_files": "Arquivos recentes", + "components.searchpopup.recent_channels_and_contacts": "Canais e contatos recentes", + "general.more": "Mais", + "scenes.apps.board.archived_tasks": "Tarefas arquivadas ({{$1}})", + "scenes.apps.board.active_tasks": "Tarefas ativas", + "scenes.apps.board.kanban": "Kanban", + "scenes.apps.board.display_as": "Mostrar como", + "scenes.apps.board.new_task": "+ Nova tarefa", + "scenes.apps.board.all_boards": "Todos os Quadros", + "components.userlistmanager.no_users": "Nenhum usuΓ‘rio.", + "scenes.apps.drive.used": "usado nesta pasta", + "components.reminder.notification": "NotificaΓ§Γ£o", + "components.reminder.minutes_bef": "minutos antes", + "components.reminder.hours_bef": "horas antes", + "components.reminder.days_bef": "dias antes", + "components.reminder.weeks_bef": "semanas antes", + "components.reminder.by_email": "O email", + "scenes.apps.calendar.reminders": "lembrete(s)", + "scenes.apps.calendar.video_link": "Clique para abrir o link", + "scenes.app.mainview.discussion": "DiscussΓ£o", + "components.tagpicker.notag": "Sem etiqueta", + "scenes.apps.tasks.modals.attachments": "Anexos", + "components.calendar.calendarselector.from": "A partir de", + "scenes.apps.drive.move_text2": "Jogada", + "components.attachmentpicker.from_computer": "Do seu dispositivo", + "components.attachmentpicker.from_twake": "De documentos Twake", + "components.attachmentpicker.file": "Arquivo", + "components.attachmentpicker.remove_attach": "Remover anexo", + "scenes.apps.drive.remove_attachs": "Remover anexos", + "components.drive.elements.see": "Ver", + "components.drive.elements.current_name": "Nome atual: ", + "scenes.apps.drive.right_preview.public": "Acesso pΓΊblico", + "components.drive.elements.configurate_mod": "Configure o modo...", + "components.drive.elements.manage_version": "Gerenciar versΓ΅es", + "scenes.app.popup.createcompany.try_again": "Por favor, tente novamente.", + "scenes.app.popup.workspace.edit_temp": "Editar conta temporΓ‘ria", + "scenes.app.popup.workspace.create_temp": "Criar conta temporΓ‘ria", + "scenes.apps.drive.right_preview.versions": "VersΓ΅es", + "scenes.app.popup.appsparameters.pages.apps_connectors_small_text": "Gerencie seus aplicativos e conectores.", + "scenes.app.popup.appsparameters.pages.title_informations": "InformaΓ§Γ£o bΓ‘sica", + "scenes.app.popup.appsparameters.pages.subtitle_informations": "InformaΓ§Γ΅es relacionadas ao gerenciamento de aplicativos", + "scenes.app.popup.appsparameters.pages.smalltext_user_id": "ID de usuΓ‘rio atual", + "scenes.app.popup.appsparameters.pages.smalltext_workspace_id": "ID do workspace atual", + "scenes.app.popup.appsparameters.pages.smalltext_group_id": "ID do grupo atual", + "scenes.app.mainview.channel_description": "Descreva o canal", + "scenes.client.channelbar.channeltemplateeditor.checkbox": "Convidar automaticamente todos os usuΓ‘rios do workspace para este canal", + "scenes.client.channelbar.channelmemberslist.title": "UsuΓ‘rios em {{$1}}", + "scenes.client.channelbar.channelmemberslist.loader": "Carregue mais", + "scenes.client.channelbar.channelmemberslist.autocomplete": "Pesquisar usuΓ‘rios", + "scenes.client.channelbar.channelmemberslist.search_invite": "Pesquise e convide usuΓ‘rios para este canal", + "scenes.client.channelbar.channelmemberslist.search_invite_notice": "NΓ£o hΓ‘ muitos membros neste canal. Pesquise e convide usuΓ‘rios agora por e-mail ou nome.", + "scenes.client.channelbar.channelmemberslist.invite_email_button": "Adicionar ao canal apenas como convidado", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace": "Adicionar ao canal e espaΓ§o de trabalho como membro", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace_confirm": "Convidar {{$1}} para o workspace como membro?", + "scenes.client.channelbar.channelmemberslist.search_invite_type_email": "Digite um endereΓ§o vΓ‘lido para convidar por e-mail.", + "scenes.client.channelbar.channelmemberslist.pending_section": "UsuΓ‘rios com convite pendente", + "scenes.client.channelbar.channelmemberslist.members_section": "UsuΓ‘rios neste canal", + "scenes.client.channelbar.channelmemberslist.not_members_section": "UsuΓ‘rios que nΓ£o estΓ£o neste canal", + "scenes.client.channelbar.channelmemberslist.menu.option_2": "Remover do canal", + "components.leftbar.channel.workspaceschannels.menu.option_1": "Criar um canal", + "components.leftbar.channel.workspaceschannels.menu.option_2": "Junte-se a um canal", + "components.channelworkspacelist.title": "Canais", + "scenes.client.channelbar.workspacechannellist.autocomplete": "Pesquisar canal, usuΓ‘rio ou mensagens diretas", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_creation": "Criar uma nova guia", + "components.connectorslistmanager.add_connectors": "Adicionar conectores", + "components.notifications.hidden_notifications_button.children": "Novas mensagens", + "scenes.client.mainview.tabs.tabstemplateeditor.select_placeholder": "InscriΓ§Γ£o", + "scenes.client.channelbar.channelmemberslist.no_members": "NΓ£o hΓ‘ usuΓ‘rios neste canal, vocΓͺ pode convidΓ‘-los clicando em Adicionar usuΓ‘rios.", + "scenes.app.channelsbar.hide_discussion_leaving.menu": "Ocultar discussΓ£o", + "scenes.app.popup.adduserfromtwakeconsole.current_users_state": "{{$1}} e-mail(s) serΓ£o adicionados", + "components.newversion.new_version_component.row.part_1": "VocΓͺ estΓ‘ executando uma versΓ£o desatualizada do Twake", + "components.newversion.new_version_component.row.part_2": "sugerimos que vocΓͺ recarregue o aplicativo e aproveite nossos novos recursos!", + "components.newversion.new_version_component.link": "Clique aqui para recarregar", + "components.newversion.new_version_modal.title": "Nova atualizaΓ§Γ£o disponΓ­vel !", + "scenes.apps.drive.download_all_button": "Baixar tudo", + "components.inputs.input_with_select.input.placeholder": "Nome do canal", + "components.inputs.input_with_select.select.placeholder": "Nome da SeΓ§Γ£o", + "components.inputs.input_with_select.select.no_sections": "VocΓͺ pode agrupar seus canais aqui", + "components.inputs.input_with_select.button.tooltip": "Definir uma seΓ§Γ£o de canal", + "scenes.apps.messages.message.activity_message.a_added_b_to_the_channel": "{{$1}} adicionou {{$2}} ao canal", + "scenes.apps.messages.message.activity_message.a_removed_b_from_the_channel": "{{$1}} removeu {{$2}} do canal", + "scenes.apps.messages.message.activity_message.a_updated_channel_description": "{{$1}} alterou a descriΓ§Γ£o", + "scenes.apps.messages.message.activity_message.a_updated_channel_name": "{{$1}} renomeou o canal para {{$2}}", + "scenes.apps.messages.message.activity_message.a_created_channel_tab": "{{$1}} adicionou uma nova guia {{$2}} {{$3}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_tab": "{{$1}} removeu a guia {{$2}} {{$3}}", + "scenes.apps.messages.message.activity_message.a_created_channel_connector": "{{$1}} adicionou um novo conector {{$2}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_connector": "{{$1}} removeu um conector {{$2}}", + "scenes.client.channelbar.channelmemberslist.tag": "VocΓͺ", + "components.alert.leave_private_channel.description": "VocΓͺ nΓ£o poderΓ‘ participar deste canal privado novamente, a menos que alguΓ©m o convide.", + "scenes.client.join_private_channel.info": "Este conteΓΊdo deste canal Γ© restrito ou nΓ£o existe. Entre em contato com um membro deste canal para ser convidado.", + "scenes.client.join_public_channel": "Junte-se a este canal", + "scenes.client.join_public_channel.info": "VocΓͺ nΓ£o Γ© membro deste canal direto. Clique neste botΓ£o para iniciar a discussΓ£o agora.", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.tag": "VocΓͺ nao Γ© um membro", + "general.re_send": "Reenviar", + "general.verify": "Verificar", + "general.yes": "Sim", + "general.no": "NΓ£o", + "components.unverified_account.typography_text_danger": "Verifique sua conta dentro de {{$1}} dias. Caso contrΓ‘rio, sua conta serΓ‘ bloqueada apΓ³s 7 dias e excluΓ­da permanentemente apΓ³s 30 dias. VocΓͺ pode verificar sua conta atravΓ©s do e-mail de verificaΓ§Γ£o.", + "components.unverified_account.verification_details": "Enviamos e-mail de verificaΓ§Γ£o para", + "components.account_verification_status_sentence": "O status da sua conta Γ©: {{$1}}", + "components.account_verication_status_unverified": "NΓ£o verificado", + "components.account_verication_status_blocked": "Bloqueado", + "components.unverified_account.re_send_email": "NΓ£o recebeu o e-mail?", + "components.blocked_account.trial_period_over": "Seu perΓ­odo de teste acabou. Para desbloquear sua conta e ter acesso a todas as funcionalidades, verifique sua conta por e-mail de confirmaΓ§Γ£o", + "components.add_mails_workspace.button": "Comece a usar o Twake", + "components.add_mails_workspace.title_2": "Twake Γ© uma ferramenta de colaboraΓ§Γ£o em equipe, entΓ£o convide alguns usuΓ‘rios para testar um espaΓ§o de trabalho que criamos para vocΓͺ.", + "components.add_mails_workspace.text_area_placeholder": "Insira os e-mails de seus usuΓ‘rios*", + "components.verify_mail.title_1": "ParabΓ©ns", + "components.verify_mail.title_2": "VocΓͺ Γ© um usuΓ‘rio oficial do Twake agora!", + "components.verify_mail.button": "Adicionar usuΓ‘rio", + "components.verify_mail.text": "Antes de tudo, vocΓͺ precisa verificar seu endereΓ§o de e-mail. Enviamos um link de verificaΓ§Γ£o para", + "components.verify_mail.paragraph": "VocΓͺ pode fazer isso mais tarde, se quiser, mas contas nΓ£o verificadas tΓͺm acesso apenas a uma versΓ£o limitada do Twake", + "services.console_services.toaster.add_emails_error": "Erro ao adicionar e-mail(s)", + "services.console_services.toaster.add_email_error_message": "Erro ao adicionar {{$1}}", + "services.console_services.toaster.success_verify_email": "Um link de verificaΓ§Γ£o foi enviado para sua conta de e-mail", + "scenes.app.popup.workspaceparameter.edit_from_console": "Ver no console", + "services.console_services.toaster.success_invite_emails": "UsuΓ‘rio(s) {{$1}} adicionados com sucesso", + "scenes.client.channels_bar.modals.guest_management.title": "Gerenciar convidados em {{$1}}", + "scenes.client.channels_bar.modals.guest_management.input_placeholder": "Pesquisar convidados ou e-mails pendentes", + "scenes.client.channels_bar.modals.guest_management.tips": "Comece a adicionar ou pesquisar e-mails usando a entrada acima", + "scenes.client.channels_bar.modals.parts.channel_member_row.label.pending_email": "Mail enviado", + "general.user.role.company.admin": "Administrador da empresa", + "general.user.role.company.member": "Membro", + "general.user.role.company.guest": "Convidado", + "general.user.deleted": "Conta excluΓ­da", + "components.richtexteditor.toolbar.bold": "Audacioso", + "components.richtexteditor.toolbar.underline": "Sublinhado", + "components.richtexteditor.toolbar.italic": "itΓ‘lico", + "components.richtexteditor.toolbar.strikethrough": "Tachado", + "components.richtexteditor.toolbar.code": "CΓ³digo", + "components.richtexteditor.toolbar.unordered-list": "Lista com marcadores", + "components.richtexteditor.toolbar.ordered-list": "Lista ordenada", + "components.richtexteditor.toolbar.blockquote": "Bloco de citaΓ§Γ£o", + "components.richtexteditor.toolbar.code-block": "Bloco de cΓ³digo", + "components.locked_features.locked_history_banner.title": "VocΓͺ acabou de atingir o limite de mensagens", + "components.locked_features.locked_history_banner.description": "Sua empresa tem muitas mensagens! Atualize agora para acessar todo o seu histΓ³rico de mensagens.", + "components.locked_features.locked_guests_popup.title": "O recurso de convidados estΓ‘ bloqueado", + "components.locked_features.locked_guests_popup.subtitle": "Este recurso nΓ£o estΓ‘ disponΓ­vel na versΓ£o gratuita do Twake", + "components.locked_features.locked_guests_popup.description": "Opa!! Parece que vocΓͺ quer convidar usuΓ‘rios externos para seu workspace. VocΓͺ pode considerar atualizar seu plano se quiser colaborar com convidados e parceiros externos. Explore nossas opΓ§Γ΅es de preΓ§os e selecione a melhor opΓ§Γ£o para suas necessidades de colaboraΓ§Γ£o em equipe.", + "components.locked_features.locked_guests_popup.learn_more_button": "Saber mais", + "components.locked_features.locked_guests_popup.skip_for_now_button": "Pular por enquanto", + "components.locked_features.locked_guests_popup.or": "Ou", + "components.on_boarding.company_billing_banner.admin_or_owner_text": "HΓ‘ um problema com a assinatura da sua empresa. Por favor, dΓͺ uma olhada no seu", + "components.on_boarding.company_billing_banner.guest_or_member_text": "HΓ‘ um problema com a assinatura da sua empresa. Entre em contato com o proprietΓ‘rio ou administrador da empresa!", + "components.on_boarding.company_billing_banner.link": "plano de assinatura da empresa", + "components.on_boarding.popups.blocked_company.title": "Sua empresa estΓ‘ bloqueada devido a um problema de pagamento", + "components.on_boarding.popups.blocked_company.description": "Sua assinatura do Twake expirou. Entre em contato com o proprietΓ‘rio ou administrador de sua empresa para renovΓ‘-lo e poder se comunicar novamente com sua equipe!", + "components.on_boarding.popups.blocked_company.learn_more_text": "Quer saber mais sobre o plano de assinatura das empresas?", + "components.on_boarding.popups.blocked_company.company_subscription_plan_button": "Clique aqui", + "components.on_boarding.popups.blocked_company.or": "Ou", + "components.on_boarding.popups.blocked_company.company_selector": "Mudar para outra empresa", + "scenes.apps.tasks.select_user_button": "Exibir tarefas para outro usuΓ‘rio", + "scenes.apps.tasks.select_user": "Pesquisar usuΓ‘rio", + "scenes.apps.messages.input.attach_file.from_computer": "Do computador", + "scenes.app.popup.workspaceparameter.pages.table_title": "Nome", + "scenes.client.main_view.main_header.search_input": "Procurar", + "scenes.apps.drive.new_link_title": "Novo link", + "scenes.apps.drive.default_link_name": "Sem tΓ­tulo", + "components.emoji_picker.input_search_placeholder": "Procurar", + "services.apps.messages.message_editor_service.upload_error_toaster": "{{$1}} - VocΓͺ nΓ£o pode adicionar mais de {{$2}} arquivos em uma mensagem", + "scenes.apps.messages.message.parts.deleted_content.text.current_user": "VocΓͺ excluiu esta mensagem", + "scenes.apps.messages.message.parts.deleted_content.text": "{{$1}} excluiu sua mensagem", + "components.member.user_parts.and_more_user_text": " e {{$1}} mais usuΓ‘rios", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_link": "Criar um canal privado", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_text": " em vez de", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_input_placeholder": "VocΓͺ nΓ£o pode adicionar mais de 10 usuΓ‘rios", + "general.uploading": "Enviando", + "components.upload.drop_files.toaster.error": "VocΓͺ nΓ£o pode carregar mais de arquivos {{$1}}", + "components.emoji_picker.categories.frequently_used": "Usado frequentemente", + "components.emoji_picker.categories.smileys_and_people": "Sorrisos e pessoas", + "components.emoji_picker.categories.animals_and_nature": "Animais e Natureza", + "components.emoji_picker.categories.food_and_drink": "Comida e bebida", + "components.emoji_picker.categories.activity": "Atividade", + "components.emoji_picker.categories.travel_and_places": "Viagens e lugares", + "components.emoji_picker.categories.objects": "Objetos", + "components.emoji_picker.categories.symbols": "SΓ­mbolos", + "components.emoji_picker.categories.flags": "Bandeiras", + "components.emoji_picker.categories.search_result": "Procurar Resultados", + "components.emoji_picker.categories.not_found": "Nenhum emoji encontrado", + "scenes.app.popup.workspaceparameter.pages.workspace_partner_tabs.members.table.tags": "FunΓ§Γ£o", + "general.email": "E-mail", + "components.locked_features.locked_workspace_popup.title": "VocΓͺ nΓ£o pode criar mais espaΓ§os de trabalho", + "components.locked_features.locked_workspace_popup.text": "Opa!! Quer criar um novo espaΓ§o de trabalho na sua empresa? VocΓͺ pode querer considerar atualizar seu plano. Explore nossas opΓ§Γ΅es de preΓ§os e selecione a melhor opΓ§Γ£o para suas necessidades de colaboraΓ§Γ£o em equipe.", + "components.locked_features.locked_only_office_popup.title": "VocΓͺ nΓ£o pode editar este arquivo", + "components.locked_features.locked_only_office_popup.subtitle": "Na versΓ£o gratuita, vocΓͺ nΓ£o pode usar apenas o office.", + "components.locked_features.locked_only_office_popup.text": "Opa!! Parece que vocΓͺ deseja editar o arquivo do Twake. VocΓͺ pode considerar atualizar seu plano se quiser colaborar em arquivos do Office. Explore nossas opΓ§Γ΅es de preΓ§os e selecione a melhor opΓ§Γ£o para suas necessidades de colaboraΓ§Γ£o em equipe.", + "components.locked_features.locked_drive_popup.title": "VocΓͺ acabou de atingir o limite de percurso", + "components.locked_features.locked_drive_popup.subtitle": "Na versΓ£o gratuita, vocΓͺ pode armazenar apenas 6 GB.", + "general.resume": "Retomar", + "general.pause": "Pausa", + "scenes.app.integrations_parameters.title": "IntegraΓ§Γ΅es", + "scenes.app.integrations_parameters.applications_table.name": "Nome", + "scenes.app.integrations_parameters.applications_table.title": "Outras integraΓ§Γ΅es", + "scenes.app.integrations_parameters.applications_table.search_placeholder": "Aplicativo de pesquisa", + "scenes.app.integrations_parameters.company_application_popup.tag": "Instalado", + "scenes.app.integrations_parameters.company_application_popup.btn": "Instalar", + "scenes.app.integrations_parameters.company_application_popup.tab_btn_info": "InformaΓ§Γ΅es", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.description_item": "DescriΓ§Γ£o", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.website_item": "Local na rede Internet", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.created_item": "Data de criaΓ§Γ£o", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.version_item": "VersΓ£o", + "scenes.app.integrations_parameters.company_applications_table.more_menu.show_application": "Mostrar detalhes", + "scenes.app.integrations_parameters.company_applications_table.more_menu.remove_application": "Retirar da empresa", + "scenes.app.integrations_parameters.company_applications_table.name": "Nome", + "scenes.app.integrations_parameters.company_applications_table.title": "Instalado em sua empresa", + "app.state.recoil.hooks.use_current_company_applications.toaster_delete": "{{$1}} excluΓ­do com sucesso de sua empresa", + "app.state.recoil.hooks.use_current_company_applications.toaster_add": "{{$1}} adicionado com sucesso em sua empresa", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.label": "EspaΓ§o de trabalho padrΓ£o", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.description": "Convide automaticamente todos os novos usuΓ‘rios da empresa para este workspace", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.title": "VocΓͺ estΓ‘ prestes a excluir {{$1}}", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.alert_total_members": "VocΓͺ ainda tem membros {{$1}} em {{$2}}. VocΓͺ deve remover todos os membros para poder excluir este espaΓ§o de trabalho.", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.checkbox": "Entendo que todas as mensagens e arquivos do meu workspace serΓ£o excluΓ­dos.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.max_size": "O tamanho mΓ‘ximo do logotipo Γ© 5mb", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.bad_format": "Formato incorreto, apenas png gif e jpg sΓ£o permitidos", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.unknown": "Erro desconhecido", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.prefix": "Erro", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.success.update": "Atualizado com sucesso", + "scenes.join.loading": "Carregando…", + "scenes.join.wrong_link_title": "Este link nΓ£o estΓ‘ mais disponΓ­vel", + "scenes.join.wrong_link_description": "PeΓ§a Γ  pessoa que o convidou para se juntar a esta empresa para um novo link ou crie sua prΓ³pria empresa", + "scenes.join.create_the_company_button": "Crie a empresa", + "scenes.join.join_workspace_from_company": "Junte-se a {{$1}} de {{$2}}!", + "scenes.join.twake_description": "Twake Γ© um espaΓ§o de trabalho digital de cΓ³digo aberto criado para melhorar a produtividade da sua equipe", + "scenes.join.login_first_button": "FaΓ§a login ou crie uma conta primeiro", + "scenes.join.join_the_team_button": "Junte-se Γ  equipe", + "scenes.app.channelsbar.currentuser.reset": "Redefinir", + "components.rich_text_editor.plugins.suggestions.default_message.display_results": "Escreva pelo menos trΓͺs letras para exibir os usuΓ‘rios", + "components.rich_text_editor.plugins.suggestions.loading": "Procurando mais", + "components.rich_text_editor.plugins.suggestions.default_message.no_user_found": "Nenhum usuΓ‘rio encontrado", + "components.rich_text_editor.plugins.suggestions.default_message.no_emoji_found": "Nenhum emoji encontrado", + "components.rich_text_editor.plugins.suggestions.default_message.no_command_found": "Nenhum comando encontrado", + "scenes.app.messages.input.parts.is_writing.message.user_is_writing": "{{$1}} estΓ‘ escrevendo...", + "scenes.app.messages.input.parts.is_writing.message.users_are_writing": "{{$1}} e {{$2}} estΓ£o escrevendo...", + "scenes.app.messages.input.parts.is_writing.message.users_and_more_are_writing": "{{$1}}, {{$2}} e {{$3}} mais usuΓ‘rios estΓ£o escrevendo...", + "components.locked_features_components.locked_invite_alert.message_part_1": "Sua empresa atingiu o limite mΓ‘ximo de membros {{$1}}. Por favor ", + "components.locked_features_components.locked_invite_alert.message_link": "atualize sua empresa", + "components.locked_features_components.locked_invite_alert.message_part_2": " para convidar mais membros.", + "components.locked_features_components.locked_invite_alert.message_magic_link": " entre em contato com o proprietΓ‘rio ou administrador de sua empresa.", + "views.client.popup.workspace_parameter.pages.workspace_members.link_to_console": "Ver todos os membros da minha empresa no console", + "scenes.app.popup.appsparameters.pages.amazing_app_description": "Descreva sua aplicaΓ§Γ£o em poucas palavras", + "scenes.app.popup.appsparameters.pages.application_creator.checkbox": "Entendo que o proprietΓ‘rio e os administradores desta empresa poderΓ£o modificar e publicar este aplicativo.", + "twake.application.access.title": "Selecione os escopos certos para seu aplicativo.", + "twake.application.access.no_default_scopes_available'": "Esta integraΓ§Γ£o nΓ£o tem acesso {{$1}}", + "scenes.app.popup.appsparameters.pages.application_editor.help_link": "a documentaΓ§Γ£o da API Twake", + "scenes.app.popup.appsparameters.pages.application_editor.help_text": "Se vocΓͺ nΓ£o sabe como preenchΓͺ-los, vΓ‘ para ", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed": "Aplicativo removido com sucesso {{$1}} !", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed_error": "Erro ao remover o aplicativo {{$1}} !", + "scenes.app.popup.appsparameters.pages.application_editor.application_published": "AplicaΓ§Γ£o {{$1}} com sucesso!", + "scenes.app.integrations_parameters.add_application": "Nova integraΓ§Γ£o", + "scenes.app.integrations_parameters.company_applications_table.more_menu.developer_settings": "ConfiguraΓ§Γ΅es do desenvolvedor", + "components.open_desktop_popup.subtitle": "Aberto no aplicativo Twake", + "components.open_desktop_popup.open_here_link": "Abrir na Web em vez disso", + "components.open_desktop_popup.open_here_link_forever": "Nunca tente abrir o aplicativo novamente", + "molecules.download_banner.title": "Aproveite ao mΓ‘ximo o Twake, baixe o aplicativo para desktop agora", + "molecules.download_banner.download_button": "Baixe o aplicativo de desktop", + "components.channel_attachement_list.medias": "MΓ­dias", + "components.channel_attachement_list.files": "arquivos", + "components.channel_attachement_list.title": "Arquivos de canal e mΓ­dias", + "components.channel_attachement_list.open": "Abrir galeria", + "components.channel_attachement_list.nothing_found": "Nada aqui ainda", + "molecules.message_quote.deleted": "Esta mensagem foi excluΓ­da", + "general.save": "Salvar", + "general.retry": "Tentar novamente", + "general.close": "Fechar", + "general.cancel": "Cancelar", + "general.edit": "Editar", + "general.continue": "Continuar", + "general.back": "Voltar", + "general.confirm": "Confirmar", + "general.delete": "Excluir", + "general.archive": "Arquivo", + "general.unarchive": "Desarquivar", + "general.help": "Ajuda", + "general.help.support": "Suporte", + "general.help.documentation": "DocumentaΓ§Γ£o", + "general.send": "Enviar mensagem", + "general.remove": "Remover", + "general.add": "Adicionar", + "general.connexion_status.disconnected": "VocΓͺ estΓ‘ offline", + "general.connexion_status.connected": "VocΓͺ estΓ‘ online", + "general.connexion_status.connecting": "Reconectando…", + "application.load.longer": "O servidor demora mais do que o esperado para responder, aguarde ou recarregue a pΓ‘gina...", + "scenes.app.side_app.messages_thread_title": "{{$1}} β€’ TΓ³pico de mensagens", + "scenes.app.workspaces.create_company.group_data": "Configure seu novo grupo", + "scenes.app.workspaces.create_company.group_data.group_type": "Tipo de grupo", + "scenes.app.workspaces.create_company.group_data.group_type.company": "Empresa ou departamento da empresa", + "scenes.app.workspaces.create_company.group_data.group_type.public_organization": "OrganizaΓ§Γ£o pΓΊblica", + "scenes.app.workspaces.create_company.group_data.group_type.university_school": "Universidade ou escola", + "scenes.app.workspaces.create_company.group_data.group_type.society_club_charity": "Sociedade, clube ou caridade", + "scenes.app.workspaces.create_company.group_data.group_type.other_group": "Outro", + "scenes.app.workspaces.create_company.group_data.group_size": "Tamanho do grupo", + "scenes.app.workspaces.create_company.group_data.group_size.4_10": "4 - 10 usuΓ‘rios", + "scenes.app.workspaces.create_company.group_data.group_size.10_50": "11 - 49 usuΓ‘rios", + "scenes.app.workspaces.create_company.group_data.group_size.50_100": "50 - 99 usuΓ‘rios", + "scenes.app.workspaces.create_company.group_data.group_size.100_500": "100 - 499 usuΓ‘rios", + "scenes.app.workspaces.create_company.group_data.group_size.500_1000": "500 - 999 usuΓ‘rios", + "scenes.app.workspaces.create_company.group_data.group_size.1000_5000": "1.000 - 4.999 usuΓ‘rios", + "scenes.app.workspaces.create_company.group_data.group_size.5000_more": "Mais de 5.000 usuΓ‘rios", + "scenes.app.workspaces.create_company.group_data.group_main_activity": "Atividade principal", + "scenes.app.workspaces.create_company.group_data.group_main_activity.food": "Comida", + "scenes.app.workspaces.create_company.group_data.group_main_activity.bank": "Banco / Seguro", + "scenes.app.workspaces.create_company.group_data.group_main_activity.printing_paper": "ImpressΓ£o / Papel", + "scenes.app.workspaces.create_company.group_data.group_main_activity.construction_building": "ConstruΓ§Γ£o / Materiais de construΓ§Γ£o", + "scenes.app.workspaces.create_company.group_data.group_main_activity.real_estate": "PatrimΓ³nio", + "scenes.app.workspaces.create_company.group_data.group_main_activity.materials": "Materiais", + "scenes.app.workspaces.create_company.group_data.group_main_activity.chemistry": "QuΓ­mica", + "scenes.app.workspaces.create_company.group_data.group_main_activity.trade_commerce_distribution": "NegΓ³cio / ComΓ©rcio / DistribuiΓ§Γ£o", + "scenes.app.workspaces.create_company.group_data.group_main_activity.publishing_communication_multimedia": "EditoraΓ§Γ£o / ComunicaΓ§Γ£o / MultimΓ­dia", + "scenes.app.workspaces.create_company.group_data.group_main_activity.electronics_electricity_energy": "EletrΓ΄nica / Eletricidade / Energia", + "scenes.app.workspaces.create_company.group_data.group_main_activity.studies_and_advice": "Estudos e conselhos", + "scenes.app.workspaces.create_company.group_data.group_main_activity.pharmaceutical_industry": "IndΓΊstria farmacΓͺutica", + "scenes.app.workspaces.create_company.group_data.group_main_activity.it_telecom": "TI / Telecom", + "scenes.app.workspaces.create_company.group_data.group_main_activity.machinery_automotive": "MaquinΓ‘rio / Automotivo", + "scenes.app.workspaces.create_company.group_data.group_main_activity.business_services": "ServiΓ§os prestados Γ s empresas", + "scenes.app.workspaces.create_company.group_data.group_main_activity.entertainment": "Entretenimento", + "scenes.app.workspaces.create_company.group_data.group_main_activity.textile_clothing_shoes": "TΓͺxtil / VestuΓ‘rio / CalΓ§ado", + "scenes.app.workspaces.create_company.group_data.group_main_activity.transport_logistics": "Transporte / LogΓ­stica", + "scenes.app.workspaces.create_company.group_data.group_main_activity.research": "Pesquisar", + "scenes.app.workspaces.create_company.group_data.group_main_activity.education": "EducaΓ§Γ£o", + "scenes.app.workspaces.create_company.group_data.group_main_activity.administration": "AdministraΓ§Γ£o", + "scenes.app.workspaces.create_company.group_data.group_main_activity.other": "Outras", + "components.application.messages": "Mensagens", + "components.drive_dropzone.uploading": "Enviando...", + "components.user_picker.modal_no_result": "Nenhum resultado encontrado", + "components.users_picker.add_me": "Me adicione", + "scenes.app.workspaces.create_company.invitations.title": "Configure seu espaΓ§o de trabalho.", + "scenes.app.header.disconnected": "VocΓͺ estΓ‘ desconectado", + "scenes.app.header.disconnected.reload": "Recarregar", + "scenes.app.header.alt_notifications": "NotificaΓ§Γ΅es", + "scenes.apps.calendar.calendar.week_btn": "Semana", + "scenes.apps.calendar.calendar.list_btn": "Lista", + "scenes.apps.calendar.event_edition.deadline_tag": "Data limite", + "scenes.apps.calendar.event_edition.checkbox_all_day": "Todo o dia", + "scenes.apps.calendar.event_edition.title_confidentiality": "Confidencialidade", + "scenes.apps.calendar.event_view.article_until": "para", + "scenes.apps.calendar.calendar_modal.participants": "Participantes", + "scenes.apps.calendar.calendar_modal.placeholder": "Nome", + "scenes.apps.calendar.left.calendars": "CalendΓ‘rios", + "scenes.apps.drive.left.search": "Procurar", + "scenes.apps.drive.navigators.navigator_content.directory_name": "Nome do diretΓ³rio", + "scenes.apps.drive.navigators.navigator_content.files": "Arquivos", + "scenes.apps.drive.navigators.navigator_labels.title": "RΓ³tulos", + "scenes.apps.drive.navigators.new_file.untitled": "Sem tΓ­tulo", + "scenes.apps.drive.navigators.new_file.create_file.type": "Tipo", + "scenes.apps.drive.navigators.new_file": "Novo arquivo", + "scenes.apps.drive.preview_bloc.operations_download": "Descarregar", + "scenes.apps.drive.preview_bloc.error_file": "Arquivo nΓ£o encontrado", + "scenes.apps.drive.right_preview.public_link": "Link pΓΊblico", + "scenes.apps.messages.messages": "Mensagens", + "scenes.apps.messages.jump": "Ir para a mensagem", + "scenes.apps.messages.chatbox.chat.delete_message": "Excluir esta mensagem", + "scenes.apps.messages.chatbox.chat.delete_message_btn": "Apagar mensagem", + "scenes.apps.messages.left_bar.stream_modal.placeholder_name": "Nome", + "scenes.apps.messages.left_bar.stream.add_to_favorites": "Adicionar aos favoritos", + "scenes.apps.messages.left_bar.stream.remove_from_favorites": "Remover dos favoritos", + "scenes.apps.messages.left_bar.stream.notifications": "NotificaΓ§Γ΅es...", + "scenes.apps.messages.left_bar.stream.notifications.all": "Qualquer mensagem", + "scenes.apps.messages.left_bar.stream.notifications.mentions": "{{$1}}, {{$2}} e {{$3}}", + "scenes.apps.messages.left_bar.stream.notifications.me": "{{$1}} apenas", + "scenes.apps.messages.left_bar.stream.notifications.never": "Nada", + "scenes.apps.parameters.workspace_sections.workspace": "Área de trabalho", + "scenes.apps.parameters.workspace_sections.members": "Participantes do canal", + "scenes.apps.parameters.group_sections.workspaces": "EspaΓ§os de trabalho", + "scenes.apps.parameters.group_sections.apps": "Aplicativos", + "scenes.apps.account.title": "ParΓ’metros da conta", + "scenes.apps.account.account.menu_title": "Conta", + "scenes.apps.account.languages.menu_title": "Idioma", + "scenes.apps.account.account.firstname": "Primeiro nome", + "scenes.apps.account.account.lastname": "Sobrenome", + "scenes.apps.account.account.username": "Nome de usuΓ‘rio", + "scenes.apps.account.account.change_username": "Altere seu nome de usuΓ‘rio exclusivo.", + "scenes.apps.account.account.emails": "Emails", + "scenes.apps.account.account.main_email": "Email principal", + "scenes.apps.account.account.email_add": "Adicionar novo email", + "scenes.apps.account.account.email_add_modal.invalid_code": "Este cΓ³digo Γ© invΓ‘lido", + "scenes.apps.account.account.password": "Senha", + "scenes.apps.account.account.password_modal.old_password": "Senha atual", + "scenes.apps.account.account.password_modal.password": "Nova Senha", + "scenes.apps.account.account.password_modal.bad_old_password": "A senha antiga nΓ£o estΓ‘ correta.", + "scenes.apps.account.account.password_modal.bad_password": "Suas senhas nΓ£o correspondem ou sΓ£o muito curtas. Digite uma senha com pelo menos 8 caracteres.", + "scenes.apps.account.account.logout": "Sair", + "scenes.apps.account.languages.text": "Altere o idioma do Twake.", + "scenes.apps.account.notifications.title": "NotificaΓ§Γ΅es", + "scenes.apps.account.notifications.keywords_subtitle": "Palavras-chave", + "scenes.apps.account.notifications.keywords_placeholder": "dev, wifi, cΓ³digo, ...", + "scenes.apps.account.notifications.disturb_option_a": "NΓ£o me envie notificaΓ§Γ΅es push entre ", + "scenes.apps.account.notifications.disturb_option_b": " e ", + "scenes.apps.account.notifications.disturb_option_c": " (fuso horΓ‘rio local)", + "scenes.apps.account.notifications.devices_subtitle": "NotificaΓ§Γ΅es do dispositivo", + "scenes.apps.account.notifications.devices_option_ever": "Sempre me enviar notificaΓ§Γ΅es push", + "scenes.apps.account.notifications.devices_option_inactive": "Envie-me notificaΓ§Γ΅es por push quando estiver inativo na Γ‘rea de trabalho", + "scenes.apps.account.notifications.devices_option_never": "Nunca me envie notificaΓ§Γ΅es push", + "scenes.apps.account.notifications.privacy_subtitle": "Privacidade", + "scenes.apps.account.notifications.sound": "NotificaΓ§Γ£o de som", + "scenes.apps.parameters.group_sections.apps.badge_extension": "ExtensΓ£o", + "scenes.apps.parameters.workspace_sections.members.members": "UsuΓ‘rios", + "scenes.apps.parameters.workspace_sections.members.pending": "Emails pendentes", + "scenes.apps.parameters.workspace_sections.members.invite": "Convidar novo usuΓ‘rio", + "scenes.apps.parameters.workspace_sections.members.invite_btn": "Adicionar usuΓ‘rio", + "scenes.apps.tasks.boards": "Quadros", + "scenes.apps.tasks.connectors_menu": "Conectores...", + "scenes.apps.tasks.connectors_search_menu": "Pesquisar conectores...", + "scenes.apps.tasks.no_connectors_menu_text": "VocΓͺ nΓ£o tem nenhum conector que possa se conectar a um calendΓ‘rio.", + "scenes.apps.tasks.unconfigured_tab": "Esta guia ainda nΓ£o estΓ‘ configurada.", + "scenes.apps.tasks.choose_board_button": "Escolha um quadro", + "scenes.apps.tasks.new_board.title": "Novo quadro", + "scenes.apps.tasks.new_board.edit_title": "Editar quadro", + "scenes.apps.tasks.task": "Tarefa", + "scenes.apps.tasks.no_tasks": "Sem tarefas", + "scenes.apps.tasks.task_status.todo": "Para fazer", + "scenes.apps.tasks.task_status.current": "Atual", + "scenes.apps.tasks.task_status.done": "Feito", + "scenes.apps.tasks.task.description": "DescriΓ§Γ£o", + "scenes.apps.tasks.task.assignees": "AtribuΓ­do a", + "scenes.apps.tasks.task.edit.dates": "Datas", + "scenes.apps.tasks.list_modal.modify_list": "Modificar lista", + "scenes.apps.tasks.list_modal.new_list": "Nova lista", + "scenes.apps.tasks.list_modal.remove": "Remover lista e tarefas", + "scenes.apps.tasks.list_modal.predefined_participants": "Participantes predefinidos", + "scenes.apps.tasks.list_modal.archive_all_tasks": "Arquivar todas as tarefas", + "scenes.apps.tasks.list_modal.remove_archived_tasks": "Remover tarefas arquivadas ({{$1}})", + "scenes.login.footer.go_to_twake": "Acesse twakeapp.com", + "scenes.login.footer.branding": "VocΓͺ estΓ‘ em um servidor Twake privado {{$1}} ({{$2}}). ", + "scenes.login.create_account.title": "Criar uma nova conta", + "scenes.login.create_account.email": "Email", + "scenes.login.create_account.email_used": "Esse email jΓ‘ estΓ‘ em uso.", + "scenes.login.create_account.username": "Nome de usuΓ‘rio", + "scenes.login.create_account.username_already_exist": "Este nome de usuΓ‘rio jΓ‘ estΓ‘ em uso", + "scenes.login.create_account.fill_in_username": "VocΓͺ deve preencher seu nome de usuΓ‘rio", + "scenes.login.create_account.fill_in_email": "VocΓͺ deve preencher seu e-mail com um e-mail correto", + "scenes.login.create_account.too_short_password": "Sua senha deve conter pelo menos 8 caracteres.", + "scenes.login.create_account.firstname": "Primeiro nome", + "scenes.login.create_account.newsletter": "Receba informaΓ§Γ΅es sobre o Twake", + "scenes.login.create_account.lastname": "Sobrenome", + "scenes.login.forgot_password.text": "VocΓͺ receberΓ‘ um cΓ³digo de 9 dΓ­gitos por e-mail para verificar sua identidade.", + "scenes.login.forgot_password.email_to_recover": "Email para recuperar", + "scenes.login.forgot_password.mail_doesnt_exist": "Este email nΓ£o existe", + "scenes.login.forgot_password.text2": "VocΓͺ receberΓ‘ um cΓ³digo de 9 dΓ­gitos. Por favor, insira-o no campo abaixo para continuar.", + "scenes.login.forgot_password.text3": "Digite uma nova senha para sua conta.", + "scenes.login.forgot_password.password": "Senha", + "scenes.login.forgot_password.password2": "Confirme a senha", + "scenes.login.forgot_password.password_dont_match": "Suas senhas nΓ£o correspondem ou sΓ£o muito curtas. Digite uma senha com pelo menos 8 caracteres.", + "scenes.login.home.title": "FaΓ§a login no Twake", + "scenes.login.home.subtitle": "Feliz em ver vocΓͺ", + "scenes.login.home.email": "Email", + "scenes.login.home.unable_to_connect": "Credenciais invΓ‘lidas", + "scenes.login.home.password": "Senha", + "scenes.login.home.login_btn": "Entrar", + "scenes.login.home.create_account": "Crie uma conta", + "scenes.login.create_account.password": "Senha", + "scenes.login.create_account.step_1_subtitle": "NΓ£o poderia ser mais simples - sΓ³ precisamos de algumas informaΓ§Γ΅es.", + "scenes.login.create_account.step_2_subtitle_a": "Adicione seu nome completo para que outros usuΓ‘rios o reconheΓ§am.", + "scenes.login.create_account.step_2_subtitle_b": "Seu nΓΊmero de telefone permanece privado.", + "scenes.login.create_account.step_3_mail_sent": "Enviamos um link de ativaΓ§Γ£o por email.", + "scenes.login.create_account.step_3_subtitle": "Última etapa - precisamos verificar se vocΓͺ nΓ£o Γ© um robΓ΄!", + "scenes.app.workspaces.create_company.company_name.placeholder": "Nome da empresa", + "scenes.app.workspaces.create_company.company_name.title_1": "Para comeΓ§ar,", + "scenes.app.workspaces.create_company.company_name.title_2": "indique o nome da sua empresa.", + "scenes.app.workspaces.create_company.default_workspace_name": "Principal", + "scenes.app.workspaces.create_company.group_data.title": "Seremos rΓ‘pidos - sΓ³ precisamos de algumas informaΓ§Γ΅es estatΓ­sticas.", + "scenes.app.workspaces.create_company.importations.title_1": "JΓ‘ trabalha com ferramentas digitais? Importe ou integre suas ferramentas agora!", + "scenes.app.workspaces.create_company.importations.title_2": "NΓ£o se preocupe, vocΓͺ pode fazer isso mais tarde!", + "scenes.app.workspaces.create_company.invitations.title_2": "Adicione usuΓ‘rios Γ  sua equipe.", + "scenes.app.workspaces.create_company.title": "Criar minha empresa", + "scenes.app.workspaces.welcome_page.add_secondary_emails": "Adicionar um email secundΓ‘rio", + "scenes.app.workspaces.welcome_page.added_to_company": "VocΓͺ foi convidado para ", + "scenes.app.workspaces.welcome_page.create_my_company": "Criar minha empresa", + "scenes.app.workspaces.welcome_page.may_be_invited_with_secondary_emails": "VocΓͺ foi convidado usando outro endereΓ§o de email?", + "scenes.app.workspaces.welcome_page.no_company_subtitle": "Oh, bem... Parece que ninguΓ©m te convidou para uma empresa ainda.", + "scenes.app.workspaces.welcome_page.no_workspace_subtitle": "NinguΓ©m convidou vocΓͺ para um espaΓ§o de trabalho ainda.", + "scenes.app.workspaces.welcome_page.ready_to_work": "VocΓͺ estΓ‘ pronto para trabalhar agora.", + "scenes.app.workspaces.welcome_page.see_you_soon": "AtΓ© breve!", + "scenes.app.workspaces.welcome_page.try_again": "Tente novamente", + "scenes.app.workspaces.welcome_page.twake_team": "Twake", + "scenes.app.workspaces.welcome_page.welcome_header": "Bem-vindo ao Twake!", + "scenes.app.workspaces.welcome_page.add_secondary_emails_comment": "VocΓͺ pode vincular vΓ‘rios endereΓ§os de email Γ  sua conta; apenas um endereΓ§o serΓ‘ usado para enviar notificaΓ§Γ΅es.", + "scenes.app.workspaces.welcome_page.main_mail_title": "EndereΓ§o principal", + "scenes.app.workspaces.welcome_page.other_mail_title": "EndereΓ§os secundΓ‘rios", + "scenes.app.workspaces.welcome_page.add_new_email": "Adicionar um email", + "scenes.app.workspaces.welcome_page.code_verification": "CΓ³digo de verificaΓ§Γ£o", + "scenes.app.workspaces.welcome_page.new_email": "Adicionar um email secundΓ‘rio", + "scenes.app.workspaces.welcome_page.we_sent_you_mail": "EnviΓ‘mos a vocΓͺ um cΓ³digo de verificaΓ§Γ£o via {{$1}}", + "scenes.app.workspaces.welcome_page.done": "Terminei", + "scenes.login.forgot_password.finished": "Sua senha foi atualizada com sucesso.", + "scenes.apps.account.account.description_main": "Seu endereΓ§o principal Γ© para onde o Twake envia suas notificaΓ§Γ΅es. Seus endereΓ§os secundΓ‘rios permitem que vocΓͺ seja convidado automaticamente para os espaΓ§os de trabalho que os utilizam.", + "scenes.apps.account.account.emails.description": "Gerencie seus diferentes endereΓ§os de e-mail.", + "scenes.apps.account.account.make_main": "Definir principal", + "scenes.apps.account.account.password.description": "Mude sua senha.", + "scenes.apps.account.identity": "Identidade", + "scenes.apps.account.identity.description": "Altere seu nome, sobrenome e imagem de perfil visΓ­veis para outros usuΓ‘rios do Twake.", + "scenes.apps.account.preference": "PreferΓͺncias", + "general.open": "Abrir", + "scenes.apps.account.thumbnail.max_weight": "Tamanho mΓ‘ximo 5 MB", + "scenes.apps.account.account.email_add_modal.confirm": "Confirme este email", + "app.name.twake_calendar": "CalendΓ‘rio", + "app.name.twake_drive": "Documentos", + "app.name.twake_tasks": "Tarefas", + "components.calendar.repetition.everyday": "DiΓ‘rio", + "components.calendar.repetition.does_not_repeat": "NΓ£o se repete", + "components.calendar.repetition.weekly_on": "Semanalmente em {{$1}}", + "components.calendar.repetition.monthly_on": "Mensalmente no {{$1}} {{$2}}", + "components.calendar.repetition.monthly_on_day": "Mensalmente no dia {{$1}}", + "components.calendar.repetition.annually_on": "Anualmente em {{$1}}", + "components.calendar.repetition.every_weekday": "Todos os dias da semana (Seg a Sex)", + "components.calendar.repetition.custom": "Personalizado...", + "components.calendar.repetition.repeat": "Repita a cada", + "components.calendar.repetition.ends": "Termina", + "components.calendar.repetition.never": "Nunca", + "components.calendar.repetition.on": "De", + "components.calendar.repetition.after": "Depois", + "components.calendar.repetition.days": "dia(s)", + "components.calendar.repetition.weeks": "semana(s)", + "components.calendar.repetition.months": "mΓͺs/meses", + "components.calendar.repetition.years": "ano(s)", + "components.calendar.repetition.custom_recurrence": "RecorrΓͺncia personalizada", + "components.calendar.repetition.occurrence": "OcorrΓͺncia(s)", + "components.calendar.repetition.repeat_on": "Repetir em", + "scenes.app.channelsbar.currentuser.add_apps": "Procurar aplicativos", + "scenes.app.channelsbar.currentuser.change_my_status": "Alterar meu status", + "scenes.app.channelsbar.currentuser.collaborateurs": "UsuΓ‘rios", + "scenes.app.channelsbar.currentuser.create_workspace_page": "Crie um espaΓ§o de trabalho", + "scenes.app.channelsbar.currentuser.invited_status": "VocΓͺ Γ© um convidado.", + "scenes.app.channelsbar.currentuser.title": "ConfiguraΓ§Γ΅es da conta", + "scenes.app.channelsbar.currentuser.workspace_info": "VocΓͺ estΓ‘ na Γ‘rea de trabalho {{$1}} do grupo {{$2}}", + "scenes.app.channelsbar.currentuser.workspace_parameters": "ConfiguraΓ§Γ΅es do espaΓ§o de trabalho", + "scenes.app.channelsbar.currentuser.logout": "Sair", + "scenes.app.channelsbar.currentuser.update": "Atualizar", + "scenes.app.channelsbar.currentuser.disable_notifications": "Desativar", + "scenes.app.channelsbar.currentuser.disabling_notifications": "Desativar por 1h", + "scenes.app.channelsbar.currentuser.disabling_notifications_until": "Desativar atΓ© Γ s 9h de amanhΓ£", + "scenes.app.channelsbar.currentuser.reactivate_notifications": "Reativar", + "scenes.app.channelsbar.currentuser.user_parameter": "ConfiguraΓ§Γ΅es de notificaΓ§Γ£o", + "general.update": "Atualizar", + "scenes.app.workspaces.create_company.group_data.group_size.less_3": "Menos de 4 usuΓ‘rios", + "scenes.apps.drive.right_preview.operations_restore": "Restaurar", + "scenes.apps.drive.right_preview.operations_delete": "Mover para lixeira", + "scenes.apps.account.notifications.mail_subtitle": "NotificaΓ§Γ΅es por email", + "scenes.login.forgot_password.title": "Esqueceu a senha?", + "scenes.login.forgot_password.invalid_code": "Este cΓ³digo nΓ£o Γ© vΓ‘lido.", + "scenes.login.home.lost_password": "Esqueceu a senha?", + "scenes.app.workspaces.welcome_page.lets_go": "Vamos lΓ‘!", + "general.create": "Criar", + "scenes.apps.account.assistant.title": "Assistente", + "scenes.apps.account.assistant.description": "O assistente Twake Γ© capaz de entender seu trabalho diΓ‘rio no Twake e fornecer atalhos e aΓ§Γ΅es inteligentes durante o dia. O assistente faz parte da iniciativa Work@Home https://workathome.linagora.com/ e atualmente estΓ‘ sendo testado apenas na empresa Linagora e estΓ‘ em fase de aprendizagem. Isso significa que enviaremos dados de uso do Twake para treinar nosso futuro recurso de assistente.", + "scenes.apps.account.assistant.share.nothing": "NΓ£o compartilhe nada com o assistente (desativar assistente)", + "scenes.apps.account.assistant.share.all": "Compartilhe tudo, incluΓ­ndo mensagens e conteΓΊdo de arquivos", + "scenes.apps.account.assistant.share.metadata": "Compartilhe metadados, mas nΓ£o conteΓΊdo", + "scenes.apps.account.assistant.success": "Suas preferΓͺncias foram atualizadas com sucesso.", + "scenes.apps.account.on_console": "Para editar suas preferΓͺncias de conta global, clique em Ir para a Consola.", + "components.message_seen_by.title": "UsuΓ‘rios que viram a mensagem", + "components.message_seen_by.none_seen_it": "NinguΓ©m viu a mensagem ainda", + "components.message_seen_by.btn": "Em formaΓ§Γ£o", + "molecules.quoted_content.attachements": "{{$1}} anexos", + "scenes.apps.messages.message.user_deactivated": "VocΓͺ estΓ‘ visualizando os arquivos de uma conta desativada", + "general.user.deactivated": "O usuΓ‘rio nΓ£o estΓ‘ mais nesta empresa", + "general.user.connected": "Conectados", + "scenes.app.popup.userparameter.pages.email_notif_delay_never": "Nunca", + "scenes.app.popup.userparameter.pages.email_notif_delay_quarter_hour": "15 minutos", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_day": "1 dia", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_hour": "1 hora", + "scenes.app.popup.userparameter.pages.notification_sound.defaut": "PredefiniΓ§Γ£o", + "scenes.app.popup.userparameter.pages.notification_sound.none": "Nenhum", + "scenes.client.channelbar.readonly_channel.checkbox": "Restringir a capacidade de gravaΓ§Γ£o", + "scenes.apps.messages.message.forward": "AvanΓ§ar", + "scenes.apps.messages.message.forward.title": "Encaminhar mensagem", + "scenes.apps.messages.message.forward.comment": "Adiciona uma mensagem", + "scenes.apps.messages.message.forward.confirm": "Enviar para canal(s) de $ 1", + "scenes.apps.messages.message.forward.send": "Mensagem encaminhada", + "components.channelselector.title": "Selecionar canais", + "components.channelselector.confirm": "Selecione $ 1 canal(is)", + "components.channelselector.search": "Pesquisar canais e discussΓ΅es", + "scenes.app.channelsbar.channel_access": "Acesso ao canal", + "scenes.app.channelsbar.channel_access.save": "Salvar configuraΓ§Γ΅es de acesso", + "scenes.app.channelsbar.channel_access.readonly": "Canal somente leitura", + "scenes.app.channelsbar.channel_access.readonly.info": "Restrinja a gravaΓ§Γ£o a moderadores, administradores e proprietΓ‘rios.", + "scenes.app.channelsbar.channel_access.visibility": "Visibilidade pΓΊblica", + "scenes.app.channelsbar.channel_access.visibility.info": "Qualquer pessoa, exceto convidados da empresa, pode participar.", + "scenes.app.channelsbar.channel_access.default": "ParticipaΓ§Γ£o automΓ‘tica", + "scenes.app.channelsbar.channel_access.default.info": "Novos membros serΓ£o adicionados aqui automaticamente.", + "scenes.app.channelsbar.channel_information": "Editar informaΓ§Γ΅es do canal", + "scenes.app.channelsbar.channel_information.logo.add": "Carregar foto", + "scenes.app.channelsbar.channel_information.logo.remove": "Remover imagem", + "scenes.app.channelsbar.channel_information.name": "Nome do canal", + "scenes.app.channelsbar.channel_information.description": "descriΓ§Γ£o do canal", + "scenes.app.channelsbar.channel_information.description.placeholder": "DescriΓ§Γ£o do canal, vocΓͺ pode usar markdown.", + "scenes.app.channelsbar.channel_information.group": "Grupo de canais", + "scenes.app.channelsbar.channel_information.group.none": "NΓ£o selecionado", + "scenes.app.channelsbar.channel_information.group.new": "Criar um novo grupo", + "scenes.app.channelsbar.channel_information.group.save": "Definir grupo de canais para $1", + "scenes.app.channelsbar.channel_information.group.save_none": "NΓ£o definir grupo de canais", + "scenes.app.channelsbar.channel_information.save": "Salvar informaΓ§Γ΅es", + "components.invitation.allow_anyone_by_email.text": "Permitir que qualquer pessoa com e-mail @{{$1}} participe deste workspace", + "scenes.client.channelbar.channelmemberslist.invite_to_workspace": "Convide {{$1}} para o espaΓ§o de trabalho ➑", + "components.invitation.reached_limit.text": "vocΓͺ atingiu o nΓΊmero mΓ‘ximo de usuΓ‘rios dentro de sua empresa. Aumente sua assinatura ou adicione esses usuΓ‘rios como convidados", + "components.invitation.invitation_channels.button": "Convidar para canais", + "components.invitation.invitation_input_list.add": "Adicionar", + "components.invitation.invitation_input_list.member": "Membro", + "components.invitation.invitation_input_list.guest": "Convidado", + "components.invitation.invitation_input_list.placeholder": "Comece a digitar um e-mail", + "components.invitation.invitation_sent.title": "Os convites foram enviados com sucesso", + "components.invitation.invitation_sent.subtitle_status": "VocΓͺ pode acompanhar o status do convite em:", + "components.invitation.invitation_sent.subtitle_location": "ConfiguraΓ§Γ΅es do espaΓ§o de trabalho > Gerenciamento de membros", + "components.invitation.invitation_sent.link": "Verifique o status do convite", + "components.invitation.invitation_sent.button": "Envie mais convites", + "components.invitation.invitation_target.invite_as_guests": "Convidar todos como convidados", + "components.invitation.invitation_target.invite_as_members": "Convidar todos como membros", + "components.invitation.invitation_target.channels_button": "Canais para convidar", + "components.invitation.workspace_link.text": "Link de convite do workspace", + "components.invitation.workspace_link.button": "cΓ³pia de", + "components.invitation.title": "convidar pessoas para {{$1}}", + "components.invitation.bulk_invitation": "Convite em massa", + "components.invitation.button": "Enviar convites", + "scenes.client.readonly.info": "Este canal Γ© um feed somente leitura, mas vocΓͺ pode comentar nos tΓ³picos.", + "scenes.app.channelsbar.channel_information.group.title": "grupos de canais", + "components.invitation.custom_role_invitation": "convite clΓ‘ssico", + "components.invitation.link": "Link" +} diff --git a/twake/frontend/public/locales/ru.json b/twake/frontend/public/locales/ru.json new file mode 100644 index 00000000..c3fded61 --- /dev/null +++ b/twake/frontend/public/locales/ru.json @@ -0,0 +1,1008 @@ +{ + "general.close": "Π—Π°ΠΊΡ€Ρ‹Ρ‚ΡŒ", + "general.save": "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ", + "general.cancel": "ΠžΡ‚ΠΌΠ΅Π½Π°", + "general.create": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ", + "general.edit": "Π Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ", + "general.continue": "ΠŸΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ", + "general.back": "Назад", + "general.confirm": "ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚ΡŒ", + "general.delete": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ", + "general.archive": "ΠΡ€Ρ…ΠΈΠ²ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ", + "general.unarchive": "Π Π°Π·Π°Ρ€Ρ…ΠΈΠ²ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ", + "general.help": "ΠŸΠΎΠΌΠΎΡ‰ΡŒ", + "general.help.support": "ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ°", + "general.help.documentation": "ДокумСнтация", + "general.send": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ сообщСниС", + "general.update": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ", + "general.remove": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ", + "general.add": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ", + "general.connexion_status.disconnected": "Π’Ρ‹ Π½Π΅ Π² сСти", + "general.connexion_status.connected": "Π’Ρ‹ Π² сСти", + "general.connexion_status.connecting": "ΠŸΠ΅Ρ€Π΅ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅β€¦", + "scenes.app.side_app.messages_thread_title": "{{$1}} β€’ Π’Π΅Ρ‚ΠΊΠ° сообщСний", + "scenes.app.workspaces.create_company.group_data": "ΠΠ°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Π³Ρ€ΡƒΠΏΠΏΡƒ", + "scenes.app.workspaces.create_company.group_data.group_type": "Π’ΠΈΠΏ Π³Ρ€ΡƒΠΏΠΏΡ‹", + "scenes.app.workspaces.create_company.group_data.group_type.company": "Компания ΠΈΠ»ΠΈ ΠΎΡ‚Π΄Π΅Π» ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "scenes.app.workspaces.create_company.group_data.group_type.public_organization": "ΠžΠ±Ρ‰Π΅ΡΡ‚Π²Π΅Π½Π½Π°Ρ организация", + "scenes.app.workspaces.create_company.group_data.group_type.university_school": "УнивСрситСт ΠΈΠ»ΠΈ школа", + "scenes.app.workspaces.create_company.group_data.group_type.society_club_charity": "ΠžΠ±Ρ‰Π΅ΡΡ‚Π²ΠΎ, ΠΊΠ»ΡƒΠ± ΠΈΠ»ΠΈ Π±Π»Π°Π³ΠΎΡ‚Π²ΠΎΡ€ΠΈΡ‚Π΅Π»ΡŒΠ½Π°Ρ организация", + "scenes.app.workspaces.create_company.group_data.group_type.other_group": "ΠŸΡ€ΠΎΡ‡Π΅Π΅", + "scenes.app.workspaces.create_company.group_data.group_size": "Π Π°Π·ΠΌΠ΅Ρ€ Π³Ρ€ΡƒΠΏΠΏΡ‹", + "scenes.app.workspaces.create_company.group_data.group_size.less_3": "МСнСС 4 ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ", + "scenes.app.workspaces.create_company.group_data.group_size.4_10": "4 - 10 ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ", + "scenes.app.workspaces.create_company.group_data.group_size.10_50": "11 - 49 ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ", + "scenes.app.workspaces.create_company.group_data.group_size.50_100": "50 - 99 ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ", + "scenes.app.workspaces.create_company.group_data.group_size.100_500": "100 - 499 ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ", + "scenes.app.workspaces.create_company.group_data.group_size.500_1000": "500 - 999 ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ", + "scenes.app.workspaces.create_company.group_data.group_size.1000_5000": "1000 - 4999 ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ", + "scenes.app.workspaces.create_company.group_data.group_size.5000_more": "Π‘ΠΎΠ»Π΅Π΅ 5000 ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ", + "scenes.app.workspaces.create_company.group_data.group_main_activity": "Основной Π²ΠΈΠ΄ Π΄Π΅ΡΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.food": "ΠŸΡ€ΠΎΠ΄ΡƒΠΊΡ‚Ρ‹ питания", + "scenes.app.workspaces.create_company.group_data.group_main_activity.bank": "Π‘Π°Π½ΠΊ / страхованиС", + "scenes.app.workspaces.create_company.group_data.group_main_activity.printing_paper": "ΠŸΠΎΠ»ΠΈΠ³Ρ€Π°Ρ„ΠΈΡ / ΠŸΠ΅Ρ‡Π°Ρ‚ΡŒ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.construction_building": "Π‘Ρ‚Ρ€ΠΎΠΈΡ‚Π΅Π»ΡŒΡΡ‚Π²ΠΎ / Π‘Ρ‚Ρ€ΠΎΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Ρ‹", + "scenes.app.workspaces.create_company.group_data.group_main_activity.real_estate": "НСдвиТимоС имущСство", + "scenes.app.workspaces.create_company.group_data.group_main_activity.materials": "ΠœΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Ρ‹", + "scenes.app.workspaces.create_company.group_data.group_main_activity.chemistry": "Π₯имия", + "scenes.app.workspaces.create_company.group_data.group_main_activity.trade_commerce_distribution": "Ворговля / ΠšΠΎΠΌΠΌΠ΅Ρ€Ρ†ΠΈΡ / РаспрСдСлСниС", + "scenes.app.workspaces.create_company.group_data.group_main_activity.publishing_communication_multimedia": "Π˜Π·Π΄Π°Ρ‚Π΅Π»ΡŒΡΡ‚Π²ΠΎ / ΠšΠΎΠΌΠΌΡƒΠ½ΠΈΠΊΠ°Ρ†ΠΈΠΈ / ΠœΡƒΠ»ΡŒΡ‚ΠΈΠΌΠ΅Π΄ΠΈΠ°", + "scenes.app.workspaces.create_company.group_data.group_main_activity.electronics_electricity_energy": "Π­Π»Π΅ΠΊΡ‚Ρ€ΠΎΠ½ΠΈΠΊΠ° / ЭлСктричСство / Π­Π½Π΅Ρ€Π³Π΅Ρ‚ΠΈΠΊΠ°", + "scenes.app.workspaces.create_company.group_data.group_main_activity.studies_and_advice": "ИсслСдования ΠΈ консалтинг", + "scenes.app.workspaces.create_company.group_data.group_main_activity.pharmaceutical_industry": "ЀармацСвтичСская ΠΏΡ€ΠΎΠΌΡ‹ΡˆΠ»Π΅Π½Π½ΠΎΡΡ‚ΡŒ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.it_telecom": "ИВ / ВСлСсвязь", + "scenes.app.workspaces.create_company.group_data.group_main_activity.machinery_automotive": "ΠžΠ±ΠΎΡ€ΡƒΠ΄ΠΎΠ²Π°Π½ΠΈΠ΅ / Автомобили", + "scenes.app.workspaces.create_company.group_data.group_main_activity.business_services": "БизнСс-услуги", + "scenes.app.workspaces.create_company.group_data.group_main_activity.entertainment": "РазвлСчСния", + "scenes.app.workspaces.create_company.group_data.group_main_activity.textile_clothing_shoes": "Π’Π΅ΠΊΡΡ‚ΠΈΠ»ΡŒ / ОдСТда / ΠžΠ±ΡƒΠ²ΡŒ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.transport_logistics": "Вранспорт / Логистика", + "scenes.app.workspaces.create_company.group_data.group_main_activity.research": "ИсслСдования", + "scenes.app.workspaces.create_company.group_data.group_main_activity.education": "ΠžΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅", + "scenes.app.workspaces.create_company.group_data.group_main_activity.administration": "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅", + "scenes.app.workspaces.create_company.group_data.group_main_activity.other": "ΠŸΡ€ΠΎΡ‡Π΅Π΅", + "components.application.messages": "БообщСния", + "components.drive_dropzone.uploading": "Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ°...", + "components.user_picker.modal_no_result": "Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ² Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½ΠΎ", + "components.users_picker.add_me": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ мСня", + "scenes.app.workspaces.create_company.invitations.title": "Настройка Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды.", + "scenes.app.header.disconnected": "Π‘ΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠ΅ отсутствуСт", + "scenes.app.header.disconnected.reload": "ΠŸΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ", + "scenes.app.header.alt_notifications": "УвСдомлСния", + "scenes.apps.calendar.calendar.week_btn": "НСдСля", + "scenes.apps.calendar.calendar.list_btn": "Бписок", + "scenes.apps.calendar.event_edition.deadline_tag": "ΠšΡ€Π°ΠΉΠ½ΠΈΠΉ срок", + "scenes.apps.calendar.event_edition.checkbox_all_day": "Π’Π΅ΡΡŒ дСнь", + "scenes.apps.calendar.event_edition.title_confidentiality": "ΠšΠΎΠ½Ρ„ΠΈΠ΄Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ", + "scenes.apps.calendar.event_view.article_until": "Π΄ΠΎ", + "scenes.apps.calendar.calendar_modal.participants": "Участники", + "scenes.apps.calendar.calendar_modal.placeholder": "Имя", + "scenes.apps.calendar.left.calendars": "ΠšΠ°Π»Π΅Π½Π΄Π°Ρ€ΠΈ", + "scenes.apps.drive.left.search": "Поиск", + "scenes.apps.drive.navigators.navigator_content.directory_name": "НазваниС ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π°", + "scenes.apps.drive.navigators.navigator_content.files": "Π€Π°ΠΉΠ»Ρ‹", + "scenes.apps.drive.navigators.navigator_labels.title": "Π―Ρ€Π»Ρ‹ΠΊΠΈ", + "scenes.apps.drive.navigators.new_file.untitled": "Π‘Π΅Π· названия", + "scenes.apps.drive.navigators.new_file.create_file.type": "Π’ΠΈΠΏ Ρ„Π°ΠΉΠ»Π°", + "scenes.apps.drive.navigators.new_file": "Новый Ρ„Π°ΠΉΠ»", + "scenes.apps.drive.preview_bloc.operations_download": "Π‘ΠΊΠ°Ρ‡Π°Ρ‚ΡŒ", + "scenes.apps.drive.preview_bloc.error_file": "Π€Π°ΠΉΠ» Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½", + "scenes.apps.drive.right_preview.operations_restore": "Π’ΠΎΡΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ", + "scenes.apps.drive.right_preview.operations_delete": "ΠŸΠ΅Ρ€Π΅ΠΌΠ΅ΡΡ‚ΠΈΡ‚ΡŒ Π² ΠΊΠΎΡ€Π·ΠΈΠ½Ρƒ", + "scenes.apps.drive.right_preview.public_link": "ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚Π°Ρ ссылка", + "scenes.apps.messages.messages": "БообщСния", + "scenes.apps.messages.chatbox.chat.delete_message": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ сообщСниС", + "scenes.apps.messages.chatbox.chat.delete_message_btn": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ сообщСниС", + "scenes.apps.messages.left_bar.stream_modal.placeholder_name": "НазваниС", + "scenes.apps.messages.left_bar.stream.add_to_favorites": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π² ΠΈΠ·Π±Ρ€Π°Π½Π½ΠΎΠ΅", + "scenes.apps.messages.left_bar.stream.remove_from_favorites": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΈΠ· ΠΈΠ·Π±Ρ€Π°Π½Π½ΠΎΠ³ΠΎ", + "scenes.apps.messages.left_bar.stream.notifications": "УвСдомлСния...", + "scenes.apps.messages.left_bar.stream.notifications.all": "ВсС сообщСния", + "scenes.apps.messages.left_bar.stream.notifications.mentions": "{{$1}}, {{$2}} ΠΈ {{$3}}", + "scenes.apps.messages.left_bar.stream.notifications.me": "Ρ‚ΠΎΠ»ΡŒΠΊΠΎ {{$1}}", + "scenes.apps.messages.left_bar.stream.notifications.never": "Никогда", + "scenes.apps.parameters.workspace_sections.workspace": "Рабочая срСда", + "scenes.apps.parameters.workspace_sections.members": "Участники", + "scenes.apps.parameters.group_sections.workspaces": "Π Π°Π±ΠΎΡ‡ΠΈΠ΅ срСды", + "scenes.apps.parameters.group_sections.apps": "ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ", + "scenes.apps.account.title": "Настройки Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°", + "scenes.apps.account.account.menu_title": "Аккаунт", + "scenes.apps.account.languages.menu_title": "Π―Π·Ρ‹ΠΊ", + "scenes.apps.account.account.firstname": "Имя", + "scenes.apps.account.account.lastname": "Ѐамилия", + "scenes.apps.account.account.username": "Имя ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ", + "scenes.apps.account.account.change_username": "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ имя ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ.", + "scenes.apps.account.account.emails": "Аккаунты элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹", + "scenes.apps.account.account.main_email": "Основной Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹", + "scenes.apps.account.account.email_add": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π½ΠΎΠ²Ρ‹ΠΉ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹", + "scenes.apps.account.account.email_add_modal.invalid_code": "Π”Π°Π½Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ нСдСйствитСлСн", + "scenes.apps.account.account.password": "ΠŸΠ°Ρ€ΠΎΠ»ΡŒ", + "scenes.apps.account.account.password_modal.old_password": "Π’Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ", + "scenes.apps.account.account.password_modal.password": "Новый ΠΏΠ°Ρ€ΠΎΠ»ΡŒ", + "scenes.apps.account.account.password_modal.bad_old_password": "Π‘Ρ‚Π°Ρ€Ρ‹ΠΉ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ Π²Π²Π΅Π΄Π΅Π½ Π½Π΅Π²Π΅Ρ€Π½ΠΎ.", + "scenes.apps.account.account.password_modal.bad_password": "Π’Π°ΡˆΠΈ ΠΏΠ°Ρ€ΠΎΠ»ΠΈ Π½Π΅ ΡΠΎΠ²ΠΏΠ°Π΄Π°ΡŽΡ‚ ΠΈΠ»ΠΈ содСрТат нСдостаточно символов. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π²Π²Π΅Π΄ΠΈΡ‚Π΅ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ Π½Π΅ ΠΌΠ΅Π½Π΅Π΅ Ρ‡Π΅ΠΌ ΠΈΠ· 8 символов.", + "scenes.apps.account.account.logout": "Π’Ρ‹ΠΉΡ‚ΠΈ", + "scenes.apps.account.languages.text": "Π‘ΠΌΠ΅Π½ΠΈΡ‚ΡŒ язык Twake.", + "scenes.apps.account.notifications.title": "УвСдомлСния", + "scenes.apps.account.notifications.keywords_subtitle": "ΠšΠ»ΡŽΡ‡Π΅Π²Ρ‹Π΅ слова", + "scenes.apps.account.notifications.keywords_placeholder": "Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ°, Wi-Fi, ΠΊΠΎΠ΄, ...", + "scenes.apps.account.notifications.disturb_option_a": "НС ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ ΠΌΠ½Π΅ push-увСдомлСния ΠΌΠ΅ΠΆΠ΄Ρƒ ", + "scenes.apps.account.notifications.disturb_option_b": " ΠΈ ", + "scenes.apps.account.notifications.disturb_option_c": " (часовой пояс)", + "scenes.apps.account.notifications.devices_subtitle": "УвСдомлСния Π½Π° устройствах", + "scenes.apps.account.notifications.devices_option_ever": "ВсСгда ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ push-увСдомлСния", + "scenes.apps.account.notifications.devices_option_inactive": "ΠžΡ‚ΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ push-увСдомлСния, ΠΊΠΎΠ³Π΄Π° я Π½Π΅Π°ΠΊΡ‚ΠΈΠ²Π΅Π½ Π² дСсктопной вСрсии", + "scenes.apps.account.notifications.devices_option_never": "Никогда Π½Π΅ ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ push-увСдомлСния", + "scenes.apps.account.notifications.privacy_subtitle": "ΠšΠΎΠ½Ρ„ΠΈΠ΄Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ", + "scenes.apps.account.notifications.mail_subtitle": "УвСдомлСния ΠΏΠΎ элСктронной ΠΏΠΎΡ‡Ρ‚Π΅", + "scenes.apps.parameters.group_sections.apps.badge_extension": "Π Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅", + "scenes.apps.parameters.workspace_sections.members.members": "Участники", + "scenes.apps.parameters.workspace_sections.members.pending": "Письма Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ", + "scenes.apps.parameters.workspace_sections.members.invite": "ΠŸΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚ΡŒ Π½ΠΎΠ²ΠΎΠ³ΠΎ участника", + "scenes.apps.parameters.workspace_sections.members.invite_btn": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ участника", + "scenes.apps.tasks.boards": "Доски", + "scenes.apps.tasks.connectors_menu": "Π Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ...", + "scenes.apps.tasks.connectors_search_menu": "Поиск Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠΉ...", + "scenes.apps.tasks.no_connectors_menu_text": "Π£ вас Π½Π΅Ρ‚ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ ΠΊ ΠΊΠ°Π»Π΅Π½Π΄Π°Ρ€ΡŽ.", + "scenes.apps.tasks.unconfigured_tab": "Π­Ρ‚Π° Π²ΠΊΠ»Π°Π΄ΠΊΠ° Π΅Ρ‰Π΅ Π½Π΅ настроСна.", + "scenes.apps.tasks.choose_board_button": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ доску", + "scenes.apps.tasks.new_board.title": "Новая доска", + "scenes.apps.tasks.new_board.edit_title": "Π Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ доску", + "scenes.apps.tasks.task": "Π—Π°Π΄Π°Ρ‡Π°", + "scenes.apps.tasks.no_tasks": "Π£ вас Π½Π΅Ρ‚ Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹Ρ… Π·Π°Π΄Π°Ρ‡", + "scenes.apps.tasks.task_status.todo": "Бписок Π·Π°Π΄Π°Ρ‡", + "scenes.apps.tasks.task_status.current": "Π’Π΅ΠΊΡƒΡ‰ΠΈΠ΅ Π·Π°Π΄Π°Ρ‡ΠΈ", + "scenes.apps.tasks.task_status.done": "Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π½Ρ‹Π΅ Π·Π°Π΄Π°Ρ‡ΠΈ", + "scenes.apps.tasks.task.description": "ОписаниС", + "scenes.apps.tasks.task.assignees": "НазначСнныС Π»ΠΈΡ†Π°", + "scenes.apps.tasks.task.edit.dates": "Π”Π°Ρ‚Ρ‹", + "scenes.apps.tasks.list_modal.modify_list": "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ список", + "scenes.apps.tasks.list_modal.new_list": "Новый список", + "scenes.apps.tasks.list_modal.remove": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ список ΠΈ Π·Π°Π΄Π°Ρ‡ΠΈ", + "scenes.apps.tasks.list_modal.predefined_participants": "ΠŸΡ€Π΅Π΄ΠΏΠΎΠ»Π°Π³Π°Π΅ΠΌΡ‹Π΅ участники", + "scenes.apps.tasks.list_modal.archive_all_tasks": "ΠΡ€Ρ…ΠΈΠ²ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ всС Π·Π°Π΄Π°Ρ‡ΠΈ", + "scenes.apps.tasks.list_modal.remove_archived_tasks": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ Π·Π°Π°Ρ€Ρ…ΠΈΠ²ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Π΅ Π·Π°Π΄Π°Ρ‡ΠΈ ({{$1}})", + "scenes.login.footer.go_to_twake": "ΠŸΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ ΠΊ twakeapp.com", + "scenes.login.footer.branding": "Π’Ρ‹ Π½Π°Ρ…ΠΎΠ΄ΠΈΡ‚Π΅ΡΡŒ Π½Π° частном сСрвСрС, ΠΏΡ€ΠΈΠ½Π°Π΄Π»Π΅ΠΆΠ°Ρ‰Π΅ΠΌ {{$1}} ({{$2}}). ", + "scenes.login.create_account.title": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²Ρ‹ΠΉ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚", + "scenes.login.create_account.email": "ЭлСктронная ΠΏΠΎΡ‡Ρ‚Π°", + "scenes.login.create_account.email_used": "Π­Ρ‚ΠΎΡ‚ адрСс элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹ ΡƒΠΆΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ.", + "scenes.login.create_account.username": "Имя ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ", + "scenes.login.create_account.username_already_exist": "Π­Ρ‚ΠΎ имя ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ ΡƒΠΆΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ", + "scenes.login.create_account.fill_in_username": "НСобходимо ввСсти имя ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ", + "scenes.login.create_account.fill_in_email": "НСобходимо ввСсти Π²Π΅Ρ€Π½Ρ‹ΠΉ адрСс элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹", + "scenes.login.create_account.too_short_password": "Π’Π°Ρˆ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ Π½Π΅ ΠΌΠ΅Π½Π΅Π΅ 8 символов.", + "scenes.login.create_account.firstname": "Имя", + "scenes.login.create_account.newsletter": "ΠŸΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ ΠΎ Twake", + "scenes.login.create_account.lastname": "Ѐамилия", + "scenes.login.forgot_password.title": "Π—Π°Π±Ρ‹Π»ΠΈ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ?", + "scenes.login.forgot_password.text": "Π’Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ ΠΊΠΎΠ΄ ΠΈΠ· 9 Ρ†ΠΈΡ„Ρ€ ΠΏΠΎ элСктронной ΠΏΠΎΡ‡Ρ‚Π΅, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹ΠΉ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚ΡŒ Π²Π°ΡˆΡƒ Π»ΠΈΡ‡Π½ΠΎΡΡ‚ΡŒ.", + "scenes.login.forgot_password.email_to_recover": "ЭлСктронная ΠΏΠΎΡ‡Ρ‚Π° для восстановлСния", + "scenes.login.forgot_password.mail_doesnt_exist": "Π”Π°Π½Π½Ρ‹ΠΉ адрСс элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹ Π½Π΅ сущСствуСт", + "scenes.login.forgot_password.text2": "Π’Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ ΠΊΠΎΠ΄ ΠΈΠ· 9 символов. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π²Π²Π΅Π΄ΠΈΡ‚Π΅ Π΅Π³ΠΎ Π² ΠΏΠΎΠ»Π΅ Π½ΠΈΠΆΠ΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ.", + "scenes.login.forgot_password.invalid_code": "Π­Ρ‚ΠΎΡ‚ ΠΊΠΎΠ΄ нСдСйствитСлСн.", + "scenes.login.forgot_password.text3": "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ Π½ΠΎΠ²Ρ‹ΠΉ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ для вашСго Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°.", + "scenes.login.forgot_password.password": "ΠŸΠ°Ρ€ΠΎΠ»ΡŒ", + "scenes.login.forgot_password.password2": "ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚Π΅ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ", + "scenes.login.forgot_password.password_dont_match": "Π’Π°ΡˆΠΈ ΠΏΠ°Ρ€ΠΎΠ»ΠΈ Π½Π΅ ΡΠΎΠ²ΠΏΠ°Π΄Π°ΡŽΡ‚ ΠΈΠ»ΠΈ содСрТат нСдостаточно символов, поТалуйста, Π²Π²Π΅Π΄ΠΈΡ‚Π΅ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ, состоящий Π½Π΅ ΠΌΠ΅Π½Π΅Π΅ Ρ‡Π΅ΠΌ ΠΈΠ· 8 символов.", + "scenes.login.home.title": "Π’Ρ…ΠΎΠ΄ Π² Twake", + "scenes.login.home.subtitle": "Π”ΠΎΠ±Ρ€ΠΎ ΠΏΠΎΠΆΠ°Π»ΠΎΠ²Π°Ρ‚ΡŒ", + "scenes.login.home.email": "ΠŸΠΎΡ‡Ρ‚Π°", + "scenes.login.home.unable_to_connect": "ΠΠ΅Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΎΠ½Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅", + "scenes.login.home.password": "ΠŸΠ°Ρ€ΠΎΠ»ΡŒ", + "scenes.login.home.login_btn": "Π’ΠΎΠΉΡ‚ΠΈ", + "scenes.login.home.lost_password": "Π—Π°Π±Ρ‹Π»ΠΈ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ?", + "scenes.login.home.create_account": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚", + "scenes.login.create_account.password": "ΠŸΠ°Ρ€ΠΎΠ»ΡŒ", + "scenes.login.create_account.step_1_subtitle": "ВсС ΠΎΡ‡Π΅Π½ΡŒ просто: Π½Π°ΠΌ понадобится ΠΊΠΎΠ΅-какая информация.", + "scenes.login.create_account.step_2_subtitle_a": "Π”ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ вашС ΠΏΠΎΠ»Π½ΠΎΠ΅ имя, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΊΠΎΠ»Π»Π΅Π³ΠΈ ΠΌΠΎΠ³Π»ΠΈ ΡƒΠ·Π½Π°Ρ‚ΡŒ вас.", + "scenes.login.create_account.step_2_subtitle_b": "Π’Π°Ρˆ Π½ΠΎΠΌΠ΅Ρ€ Ρ‚Π΅Π»Π΅Ρ„ΠΎΠ½Π° Π½Π΅ Π²ΠΈΠ΄Π΅Π½ Π΄Ρ€ΡƒΠ³ΠΈΠΌ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡΠΌ.", + "scenes.login.create_account.step_3_mail_sent": "ΠœΡ‹ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ»ΠΈ Π²Π°ΠΌ ссылку для Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ ΠΏΠΎ элСктронной ΠΏΠΎΡ‡Ρ‚Π΅.", + "scenes.login.create_account.step_3_subtitle": "ПослСдний шаг, ΠΌΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΡƒΠ±Π΅Π΄ΠΈΡ‚ΡŒΡΡ, Ρ‡Ρ‚ΠΎ Π²Ρ‹ Π½Π΅ Ρ€ΠΎΠ±ΠΎΡ‚!", + "scenes.app.workspaces.create_company.company_name.placeholder": "НазваниС ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "scenes.app.workspaces.create_company.company_name.title_1": "Для Π½Π°Ρ‡Π°Π»Π°,", + "scenes.app.workspaces.create_company.company_name.title_2": "ΡƒΠΊΠ°ΠΆΠΈΡ‚Π΅ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ.", + "scenes.app.workspaces.create_company.default_workspace_name": "Π“Π»Π°Π²Π½ΠΎΠ΅", + "scenes.app.workspaces.create_company.group_data.title": "Π­Ρ‚ΠΎ Π½Π΅ Π·Π°ΠΉΠΌΠ΅Ρ‚ ΠΌΠ½ΠΎΠ³ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ: Π½Π°ΠΌ просто Π½ΡƒΠΆΠ½Π° статистичСская информация.", + "scenes.app.workspaces.create_company.importations.title_1": "Π£ΠΆΠ΅ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚Π΅ с Ρ†ΠΈΡ„Ρ€ΠΎΠ²Ρ‹ΠΌΠΈ инструмСнтами? Π˜ΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΠΉΡ‚Π΅ ΠΈΠ»ΠΈ ΠΈΠ½Ρ‚Π΅Π³Ρ€ΠΈΡ€ΡƒΠΉΡ‚Π΅ свои инструмСнты прямо сСйчас!", + "scenes.app.workspaces.create_company.importations.title_2": "НС Π²ΠΎΠ»Π½ΡƒΠΉΡ‚Π΅ΡΡŒ, Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ это ΠΏΠΎΠ·ΠΆΠ΅!", + "scenes.app.workspaces.create_company.invitations.title_2": "Π”ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ Ρ‡Π»Π΅Π½ΠΎΠ² своСй ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹.", + "scenes.app.workspaces.create_company.title": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ свою компанию", + "scenes.app.workspaces.welcome_page.add_secondary_emails": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π΅Ρ‰Π΅ ΠΎΠ΄ΠΈΠ½ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹", + "scenes.app.workspaces.welcome_page.added_to_company": "Π’Ρ‹ Π±Ρ‹Π»ΠΈ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½Ρ‹ Π² ", + "scenes.app.workspaces.welcome_page.create_my_company": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ свою компанию", + "scenes.app.workspaces.welcome_page.lets_go": "ΠŸΠΎΠ΅Ρ…Π°Π»ΠΈ!", + "scenes.app.workspaces.welcome_page.may_be_invited_with_secondary_emails": "Π’ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ, вас пригласили ΠΏΠΎ Π΄Ρ€ΡƒΠ³ΠΎΠΌΡƒ элСктронному адрСсу?", + "scenes.app.workspaces.welcome_page.no_company_subtitle": "НС Π²Ρ‹ΡˆΠ»ΠΎ... ΠŸΠΎΡ…ΠΎΠΆΠ΅, вас Π΅Ρ‰Π΅ Π½Π΅ пригласили Π² эту компанию.", + "scenes.app.workspaces.welcome_page.ready_to_work": "ВсС Π³ΠΎΡ‚ΠΎΠ²ΠΎ для Ρ€Π°Π±ΠΎΡ‚Ρ‹.", + "scenes.app.workspaces.welcome_page.see_you_soon": "Π”ΠΎ скорого!", + "scenes.app.workspaces.welcome_page.try_again": "ΠŸΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ Π΅Ρ‰Π΅ Ρ€Π°Π·", + "scenes.app.workspaces.welcome_page.twake_team": "Twake", + "scenes.app.workspaces.welcome_page.welcome_header": "Π”ΠΎΠ±Ρ€ΠΎ ΠΏΠΎΠΆΠ°Π»ΠΎΠ²Π°Ρ‚ΡŒ Π² Twake!", + "scenes.app.workspaces.welcome_page.add_secondary_emails_comment": "Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠ²ΡΠ·Π°Ρ‚ΡŒ нСсколько адрСсов элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹ с вашим Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ΠΎΠΌ, Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄ΠΈΠ½ ΠΈΠ· Π½ΠΈΡ… Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ для ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠΈ Π²Π°ΠΌ ΡƒΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠΉ.", + "scenes.app.workspaces.welcome_page.main_mail_title": "Основной адрСс", + "scenes.app.workspaces.welcome_page.other_mail_title": "ΠŸΡ€ΠΎΡ‡ΠΈΠ΅ адрСса", + "scenes.app.workspaces.welcome_page.add_new_email": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹", + "scenes.app.workspaces.welcome_page.code_verification": "Код ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ", + "scenes.app.workspaces.welcome_page.new_email": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π΅Ρ‰Π΅ ΠΎΠ΄ΠΈΠ½ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹", + "scenes.app.workspaces.welcome_page.we_sent_you_mail": "ΠœΡ‹ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ»ΠΈ Π²Π°ΠΌ ΠΊΠΎΠ΄ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ Ρ‡Π΅Ρ€Π΅Π· {{$1}}", + "scenes.app.workspaces.welcome_page.done": "Π“ΠΎΡ‚ΠΎΠ²ΠΎ", + "scenes.login.forgot_password.finished": "Π’Π°Ρˆ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ Π±Ρ‹Π» ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½.", + "scenes.apps.account.account.description_main": "Π’Π°Ρˆ основной адрСс - это Ρ‚ΠΎΡ‚, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Twake отправляСт увСдомлСния. ΠŸΡ€ΠΎΡ‡ΠΈΠ΅ адрСса ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ автоматичСски ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ°Ρ‚ΡŒ вас Π² Ρ€Π°Π±ΠΎΡ‡ΠΈΠ΅ срСды, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΈΡ… ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚.", + "scenes.apps.account.account.emails.description": "УправляйтС Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹ΠΌΠΈ адрСсами элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹.", + "scenes.apps.account.account.make_main": "Π‘Π΄Π΅Π»Π°Ρ‚ΡŒ основным", + "scenes.apps.account.account.password.description": "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ.", + "scenes.apps.account.identity": "Π›ΠΈΡ‡Π½ΠΎΡΡ‚ΡŒ", + "scenes.apps.account.identity.description": "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚Π΅ имя, Ρ„Π°ΠΌΠΈΠ»ΠΈΡŽ ΠΈ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ профиля, Π²ΠΈΠ΄ΠΈΠΌΡ‹Π΅ Π΄Ρ€ΡƒΠ³ΠΈΠΌΠΈ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡΠΌ Twake.", + "scenes.apps.account.preference": "ΠŸΡ€Π΅Π΄ΠΏΠΎΡ‡Ρ‚Π΅Π½ΠΈΡ", + "general.open": "ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ", + "scenes.apps.account.thumbnail.max_weight": "ΠœΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ€Π°Π·ΠΌΠ΅Ρ€ - 5 Мб", + "scenes.apps.account.account.email_add_modal.confirm": "ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚ΡŒ Π΄Π°Π½Π½ΡƒΡŽ ΡΠ»Π΅ΠΊΡ‚Ρ€ΠΎΠ½Π½ΡƒΡŽ ΠΏΠΎΡ‡Ρ‚Ρƒ", + "app.name.twake_calendar": "ΠšΠ°Π»Π΅Π½Π΄Π°Ρ€ΡŒ", + "app.name.twake_drive": "Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Ρ‹", + "app.name.twake_tasks": "Π—Π°Π΄Π°Ρ‡ΠΈ", + "components.calendar.repetition.everyday": "Π•ΠΆΠ΅Π΄Π½Π΅Π²Π½ΠΎ", + "components.calendar.repetition.does_not_repeat": "ΠžΠ΄Π½ΠΎΠΊΡ€Π°Ρ‚Π½ΠΎ", + "components.calendar.repetition.weekly_on": "Π•ΠΆΠ΅Π½Π΅Π΄Π΅Π»ΡŒΠ½ΠΎ {{$1}}", + "components.calendar.repetition.monthly_on": "ЕТСмСсячно {{$1}} {{$2}}", + "components.calendar.repetition.monthly_on_day": "ЕТСмСсячно {{$1}} числа", + "components.calendar.repetition.annually_on": "Π•ΠΆΠ΅Π³ΠΎΠ΄Π½ΠΎ {{$1}}", + "components.calendar.repetition.every_weekday": "ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ€Π°Π±ΠΎΡ‡ΠΈΠΉ дСнь (с ΠΏΠ½ ΠΏΠΎ ΠΏΡ‚)", + "components.calendar.repetition.custom": "ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚...", + "components.calendar.repetition.repeat": "ΠŸΠΎΠ²Ρ‚ΠΎΡ€ΡΡ‚ΡŒ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ", + "components.calendar.repetition.ends": "ΠžΠΊΠΎΠ½Ρ‡Π°Π½ΠΈΠ΅", + "components.calendar.repetition.never": "Никогда", + "components.calendar.repetition.after": "ПослС", + "components.calendar.repetition.days": "дня/Π΄Π½Π΅ΠΉ", + "components.calendar.repetition.weeks": "Π½Π΅Π΄Π΅Π»ΠΈ(ь)", + "components.calendar.repetition.months": "мСсяца(Π΅Π²)", + "components.calendar.repetition.years": "Π³ΠΎΠ΄Π°/Π»Π΅Ρ‚", + "components.calendar.repetition.custom_recurrence": "ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚", + "components.calendar.repetition.occurrence": "ΠŸΠΎΠ²Ρ‚ΠΎΡ€(Ρ‹)", + "components.calendar.repetition.repeat_on": "ΠŸΠΎΠ²Ρ‚ΠΎΡ€ΠΈΡ‚ΡŒ", + "scenes.app.channelsbar.currentuser.add_apps": "Поиск ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ", + "scenes.app.channelsbar.currentuser.change_my_status": "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ ΠΌΠΎΠΉ статус", + "scenes.app.channelsbar.currentuser.collaborateurs": "ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΠΈ", + "scenes.app.channelsbar.currentuser.create_workspace_page": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ срСду", + "scenes.app.channelsbar.currentuser.invited_status": "Π’Ρ‹ ΡΠ²Π»ΡΠ΅Ρ‚Π΅ΡΡŒ гостСм.", + "scenes.app.channelsbar.currentuser.title": "Настройки Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°", + "scenes.app.channelsbar.currentuser.workspace_info": "Π’Ρ‹ Π² Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСдС {{$1}} Π³Ρ€ΡƒΠΏΠΏΡ‹ {{$2}}", + "scenes.app.channelsbar.currentuser.workspace_parameters": "Настройки Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды", + "scenes.app.channelsbar.currentuser.logout": "Π’Ρ‹Ρ…ΠΎΠ΄", + "scenes.app.channelsbar.currentuser.update": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ", + "scenes.app.channelsbar.currentuser.disable_notifications": "ΠžΡ‚ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ", + "scenes.app.channelsbar.currentuser.disabling_notifications": "ΠžΡ‚ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Π½Π° 1 час", + "scenes.app.channelsbar.currentuser.disabling_notifications_until": "ΠžΡ‚ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Π΄ΠΎ 9:00 Π·Π°Π²Ρ‚Ρ€Π°ΡˆΠ½Π΅Π³ΠΎ дня", + "scenes.app.channelsbar.currentuser.reactivate_notifications": "Π’ΠΎΠ·ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ", + "scenes.app.channelsbar.currentuser.user_parameter": "Настройки ΡƒΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠΉ", + "scenes.app.channelsbar.channelsuser.new_private_discussion": "НовоС Π»ΠΈΡ‡Π½ΠΎΠ΅ сообщСниС", + "scenes.app.channelsbar.channelsuser.no_private_message_invite_collaboraters": "Π›ΠΈΡ‡Π½Ρ‹Ρ… сообщСний Π½Π΅Ρ‚. ΠŸΡ€ΠΈΠ³Π»Π°ΡˆΠ°ΠΉΡ‚Π΅ своих сотрудников!", + "scenes.app.channelsbar.channelsuser.private_messages": "Π›ΠΈΡ‡Π½Ρ‹Π΅ сообщСния", + "scenes.app.channelsbar.channelsworkspace.channel_title": "ΠšΠΠΠΠ›Π«", + "scenes.app.channelsbar.channelsworkspace.channel_title.favorite": "Π˜Π—Π‘Π ΠΠΠΠžΠ•", + "scenes.app.channelsbar.channelsworkspace.create_channel": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΊΠ°Π½Π°Π»", + "scenes.app.channelsbar.channelsworkspace.no_channel": "Π’Ρ‹ Π΅Ρ‰Π΅ Π½Π΅ ΠΏΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΠ»ΠΈΡΡŒ Π½ΠΈ ΠΊ ΠΎΠ΄Π½ΠΎΠΌΡƒ ΠΊΠ°Π½Π°Π»Ρƒ", + "scenes.app.channelsbar.modify_channel_menu": "Настройки ΠΊΠ°Π½Π°Π»Π°", + "scenes.app.channelsbar.guest_management": "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ участниками", + "scenes.app.channelsbar.read_sign": "ΠžΡ‚ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ ΠΊΠ°ΠΊ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π½Π½ΠΎΠ΅", + "scenes.app.channelsbar.unread_sign": "ΠžΡ‚ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ ΠΊΠ°ΠΊ Π½Π΅ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π½Π½ΠΎΠ΅", + "scenes.app.channelsbar.channel_leaving": "ΠŸΠΎΠΊΠΈΠ½ΡƒΡ‚ΡŒ ΠΊΠ°Π½Π°Π»", + "scenes.app.channelsbar.channel_removing": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΊΠ°Π½Π°Π»", + "scenes.app.channelsbar.company_invitation_alert_subtitle": "Для Π»ΡƒΡ‡ΡˆΠ΅ΠΉ ΠΎΡ€Π³Π°Π½ΠΈΠ·Π°Ρ†ΠΈΠΈ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ пСрСнСсти эти ΠΊΠ°Π½Π°Π»Ρ‹ Π² Ρ€Π°Π·Π΄Π΅Π» своСго бизнСса, Π½Π°ΠΆΠ°Π² сюда.", + "scenes.app.channelsbar.company_invitation_alert_title": "Π’Ρ‹ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½Ρ‹ Π² компанию ", + "scenes.app.channelsbar.initial_instructions_tutorial": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ имя, Ρ„Π°ΠΌΠΈΠ»ΠΈΡŽ ΠΈ Ρ„ΠΎΡ‚ΠΎΠ³Ρ€Π°Ρ„ΠΈΡŽ профиля.", + "scenes.app.channelsbar.installation_desktop_tutorial": "Π£ΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ Π½Π°ΡΡ‚ΠΎΠ»ΡŒΠ½ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "scenes.app.channelsbar.invitation_collaboraors_tutorial": "ΠŸΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚Π΅ своих сотрудников Π² Π²Π°ΡˆΡƒ Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ срСду.", + "scenes.app.channelsbar.public_channel_label": "ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΉ ΠΊΠ°Π½Π°Π»", + "scenes.app.channelsbar.private_channel_label": "Частный ΠΊΠ°Π½Π°Π»", + "scenes.app.channelsbar.sending_message_instruction": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΠΏΠ΅Ρ€Π²ΠΎΠ΅ сообщСниС Π² обсуТдСниС", + "scenes.app.channelsbar.tutorial_alert": "Никогда большС Π½Π΅ ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ этот Π±Π»ΠΎΠΊ?", + "scenes.app.channelsbar.welcome": "Π”ΠΎΠ±Ρ€ΠΎ ΠΏΠΎΠΆΠ°Π»ΠΎΠ²Π°Ρ‚ΡŒ Π² Twake", + "scenes.app.channelsbar.welcoming_message_subtitle": "Π‘Ρ‚Π°Π½ΡŒΡ‚Π΅ профСссионалом Twake всСго Π·Π° нСсколько ΠΊΠ»ΠΈΠΊΠΎΠ²!", + "scenes.app.mainview.instruction_current_tab": "НачнитС с Π²Ρ‹Π±ΠΎΡ€Π° ΠΊΠ°Π½Π°Π»Π° Π² Π»Π΅Π²ΠΎΠΉ части экрана.", + "scenes.app.mainview.tabs.no_connected_connectors_for_channel": "Π£ вас Π½Π΅Ρ‚ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒΡΡ ΠΊ ΠΊΠ°Π½Π°Π»Ρƒ.", + "scenes.app.mainview.tabs.rename": "ΠŸΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Ρ‚ΡŒ", + "scenes.app.mainview.tabs.searching_connectors": "Поиск Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠΉ...", + "scenes.app.popup.adduser.adresses_message": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Ρ€Π°Π·Π΄Π΅Π»ΠΈΡ‚Π΅ адрСса запятой ΠΈΠ»ΠΈ ΠΏΡ€ΠΎΠ±Π΅Π»ΠΎΠΌ. ΠŸΠΎΠΌΠ½ΠΈΡ‚Π΅, Ρ‡Ρ‚ΠΎ Twake ΠΌΠΎΠΆΠ΅Ρ‚ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡ΠΈΡ‚ΡŒ количСство ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠΉ Π² зависимости ΠΎΡ‚ вашСй подписки.", + "scenes.app.popup.appsparameters.pages._app_identity": "Π˜Π΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡ прилоТСния", + "scenes.app.popup.appsparameters.pages._appareance_message_twakcode": "ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡŒΡ‚Π΅ внСшний Π²ΠΈΠ΄ Π²Π°ΡˆΠΈΡ… сообщСний Twacode", + "scenes.app.popup.appsparameters.pages.alert_published_app": "Π’Π°ΡˆΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΎΠΏΡƒΠ±Π»ΠΈΠΊΠΎΠ²Π°Π½ΠΎ, Π²Ρ‹ большС Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΅Π³ΠΎ Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ.", + "scenes.app.popup.appsparameters.pages.allowed_ip_adresses_method": "Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ * Π² Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Ρ€Π°Π·Ρ€Π΅ΡˆΠΈΡ‚ΡŒ всС IP-адрСса.", + "scenes.app.popup.appsparameters.pages.amazing_app_name": "МоС ΡƒΠ΄ΠΈΠ²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "scenes.app.popup.appsparameters.pages.api_data_description": "ΠŸΠΎΠ»Π΅Π·Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ для Twake API.", + "scenes.app.popup.appsparameters.pages.api_parameters_label": "Настройки API", + "scenes.app.popup.appsparameters.pages.app_name_label": "НазваниС прилоТСния", + "scenes.app.popup.appsparameters.pages.app_modification_right": "ВсС ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€Ρ‹ этой ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ смогут Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ это ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅.", + "scenes.app.popup.appsparameters.pages.app_privileges_information": "ΠžΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚Π΅, доступ ΠΊ ΠΊΠ°ΠΊΠΈΠΌ Π΄Π°Π½Π½Ρ‹ΠΌ для просмотра ΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ ΠΈΠΌΠ΅Π΅Ρ‚ вашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅.", + "scenes.app.popup.appsparameters.pages.app_privileges_label": "ΠŸΡ€Π΅ΠΈΠΌΡƒΡ‰Π΅ΡΡ‚Π²Π° прилоТСния", + "scenes.app.popup.appsparameters.pages.app_update": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ {{$1}} (это ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ использовано {{$2}} Ρ€Π°Π·(Π°))", + "scenes.app.popup.appsparameters.pages.application_title": "ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "scenes.app.popup.appsparameters.pages.apps_connectors_small_text": "УправляйтС своими прилоТСниями ΠΈ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡΠΌΠΈ.", + "scenes.app.popup.appsparameters.pages.apps_title": "Π’Π°ΡˆΠΈ прилоТСния ΠΈ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ", + "scenes.app.popup.appsparameters.pages.automatique_label": "АвтоматичСски", + "scenes.app.popup.appsparameters.pages.automatique_option_information": "Если Π’Ρ‹ Π°ΠΊΡ‚ΠΈΠ²ΠΈΡ€ΡƒΠ΅Ρ‚Π΅ 'АвтоматичСски', Ρ‚ΠΎ это ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ автоматичСски Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΎ ΠΊ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ Ρ€Π°Π±ΠΎΡ‡ΠΈΠΌ срСдам этой ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ.", + "scenes.app.popup.appsparameters.pages.autorised_ip_adresses_label": "Π Π°Π·Ρ€Π΅ΡˆΠ΅Π½Π½Ρ‹Π΅ IP-адрСса", + "scenes.app.popup.appsparameters.pages.available_publication_alert": "ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ вашСй заявки Π² настоящСС врСмя ΠΎΠΆΠΈΠ΄Π°Π΅Ρ‚ подтвСрТдСния ΠΊΠΎΠΌΠ°Π½Π΄Π°ΠΌΠΈ Twake.", + "scenes.app.popup.appsparameters.pages.button_force": "ΠŸΡ€ΠΈΠΌΠ΅Π½ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ½ΡƒΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΏΠΎ всСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "scenes.app.popup.appsparameters.pages.call_event_handlers": "Π‘ΠΎΠ±Ρ‹Ρ‚ΠΈΠ΅ Ρ‚ΠΈΠΏΠ° '{{$1}}' ΠΈ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ '{{$2}}' с пассивами '{{$3}}'", + "scenes.app.popup.appsparameters.pages.company_label": "Π’Π»Π°Π΄Π΅Π»Π΅Ρ† ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "scenes.app.popup.appsparameters.pages.configuration_label": "ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ", + "scenes.app.popup.appsparameters.pages.create_app_button": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "scenes.app.popup.appsparameters.pages.create_my_app": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΌΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "scenes.app.popup.appsparameters.pages.current_informations_apps_connectors": "Π’Ρ‹ Π΅Ρ‰Π΅ Π½Π΅ создали ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅. ΠŸΡ€Π΅ΠΆΠ΄Π΅ Ρ‡Π΅ΠΌ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ»ΠΈ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅, ΡƒΠ±Π΅Π΄ΠΈΡ‚Π΅ΡΡŒ, Ρ‡Ρ‚ΠΎ Π΅Π³ΠΎ Π΅Ρ‰Π΅ Π½Π΅Ρ‚ Π½Π° нашСм Ρ€Ρ‹Π½ΠΊΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ.", + "scenes.app.popup.appsparameters.pages.danger_zone_description": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "scenes.app.popup.appsparameters.pages.danger_zone_label": "Опасная Π·ΠΎΠ½Π°", + "scenes.app.popup.appsparameters.pages.description_label": "ОписаниС", + "scenes.app.popup.appsparameters.pages.developped_apps_subtitle": "ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ, Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π°Π½Π½Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠ΅ΠΉ", + "scenes.app.popup.appsparameters.pages.dispalyed_parameters_description": "ΠŸΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ‚ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ, Π³Π΄Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²ΠΈΠ΄ΠΈΠΌΠΎ вашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅.", + "scenes.app.popup.appsparameters.pages.displayed_parameters_label": "ΠžΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Ρ‚ΡŒ настройки", + "scenes.app.popup.appsparameters.pages.error_check_needed": "ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка, ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡŒΡ‚Π΅ ваши Π΄Π°Π½Π½Ρ‹Π΅.", + "scenes.app.popup.appsparameters.pages.error_message": "Π­Ρ‚ΠΎ имя ΡƒΠΆΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π΄Ρ€ΡƒΠ³ΠΈΠΌ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ, поТалуйста, Π²Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Π΄Ρ€ΡƒΠ³ΠΎΠ΅.", + "scenes.app.popup.appsparameters.pages.error_user_code": "ошибка", + "scenes.app.popup.appsparameters.pages.event_subtitle": "Бобытия", + "scenes.app.popup.appsparameters.pages.filter_information": "Π­Ρ‚ΠΎΡ‚ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡ΠΈΠ²Π°Π΅Ρ‚ использованиС вашСго API ΠΊΠ»ΡŽΡ‡Π° Ρ‚ΠΎΠ»ΡŒΠΊΠΎ сСрвСрами вашСго Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ.", + "scenes.app.popup.appsparameters.pages.go_back": "Назад", + "scenes.app.popup.appsparameters.pages.grp_section_name-error": "Π­Ρ‚ΠΎ имя ΡƒΠΆΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π΄Ρ€ΡƒΠ³ΠΈΠΌ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ, поТалуйста, Π²Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Π΄Ρ€ΡƒΠ³ΠΎΠ΅.", + "scenes.app.popup.appsparameters.pages.grp_section_surname_label": "Π£ΠΏΡ€ΠΎΡ‰Π΅Π½Π½ΠΎΠ΅ имя", + "scenes.app.popup.appsparameters.pages.installation": "Π£ΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ.", + "scenes.app.popup.appsparameters.pages.instruction_message_twakecode": "НачнитС с написания сообщСния Π² Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅ JSON.", + "scenes.app.popup.appsparameters.pages.interne_availability_application": "Π’Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅Π΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "scenes.app.popup.appsparameters.pages.json_configuration_information": "ΠŸΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ Π² Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡŽ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠ³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π²Π°ΡˆΡƒ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ Π² Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅ JSON.", + "scenes.app.popup.appsparameters.pages.loading": "Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ°...", + "scenes.app.popup.appsparameters.pages.message_data_next_event": "ΠŸΠ°ΡΡΠΈΠ²Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½Ρ‹ Π²ΠΎ врСмя ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π³ΠΎ события", + "scenes.app.popup.appsparameters.pages.modify_public_data": "Π Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΡƒΠΉΡ‚Π΅ ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ вашСго прилоТСния.", + "scenes.app.popup.appsparameters.pages.new_app_title": "НовоС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "scenes.app.popup.appsparameters.pages.ok_user_code": "ΠΎΠΊ", + "scenes.app.popup.appsparameters.pages.optimal_format": "ΠžΠΏΡ‚ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ : 48x48пкс.", + "scenes.app.popup.appsparameters.pages.parameters_form_small_text": "НСопубликованноС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ, Ссли Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π΅Π³ΠΎ доступным для всСх ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ Twake, Π°ΠΊΡ‚ΠΈΠ²ΠΈΡ€ΡƒΠΉΡ‚Π΅ эту ΠΎΠΏΡ†ΠΈΡŽ.", + "scenes.app.popup.appsparameters.pages.public_availability_application": "ΠŸΡƒΠ±Π»ΠΈΡ‡Π½ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "scenes.app.popup.appsparameters.pages.public_login_label": "ΠŸΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΉ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€", + "scenes.app.popup.appsparameters.pages.publication_description": "ΠžΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚Π΅ Π²ΠΈΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ вашСго прилоТСния.", + "scenes.app.popup.appsparameters.pages.publication_label": "ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ", + "scenes.app.popup.appsparameters.pages.publish_app_label": "ΠžΠΏΡƒΠ±Π»ΠΈΠΊΠ°Π²Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "scenes.app.popup.appsparameters.pages.read_privileges_label": "ΠŸΡ€Π°Π²Π° Π½Π° просмотр", + "scenes.app.popup.appsparameters.pages.remove_app": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ {{$1}} навсСгда.", + "scenes.app.popup.appsparameters.pages.remove_app_from_company": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΈΠ· всСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "scenes.app.popup.appsparameters.pages.remove_app_from_workspace": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΈΠ· Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды", + "scenes.app.popup.appsparameters.pages.show_button": "ΠŸΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ", + "scenes.app.popup.appsparameters.pages.status_tilte": "Бтатус", + "scenes.app.popup.appsparameters.pages.string_information": "Π­Ρ‚Π° строка ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΡ†ΠΈΡ€ΡƒΠ΅Ρ‚ вашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ Π² ΠΊΠΎΠΌΠ°Π½Π΄Π°Ρ….", + "scenes.app.popup.appsparameters.pages.title_tester": "ВСстСр Twakecode", + "scenes.app.popup.appsparameters.pages.url_reception_events_label": "Url получСния событий", + "scenes.app.popup.appsparameters.pages.waiting_availability_application": "ОТиданиС...", + "scenes.app.popup.appsparameters.pages.website_label": "Π‘Π°ΠΉΡ‚", + "scenes.app.popup.appsparameters.pages.write_privileges_label": "ΠŸΡ€Π°Π²Π° Π½Π° Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅", + "scenes.app.popup.appsparameters.pages.danger_zone_small_text": "Π’Ρ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ это ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, Ссли ΠΎΠ½ΠΎ ΠΎΠΏΡƒΠ±Π»ΠΈΠΊΠΎΠ²Π°Π½ΠΎ.", + "scenes.app.popup.appsparameters.pages.error_app_simple_name_message": "Π£ΠΏΡ€ΠΎΡ‰Π΅Π½Π½ΠΎΠ΅ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ вашСго прилоТСния ΡƒΠΆΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π΄Ρ€ΡƒΠ³ΠΈΠΌ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ, поТалуйста, ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚Π΅ Π΅Π³ΠΎ.", + "scenes.app.popup.appsparameters.pages.error_app_update_message": "ΠŸΡ€ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΈ прилоТСния ΠΏΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка.", + "scenes.app.popup.appsparameters.pages.remove_app_button": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "scenes.app.popup.appsparameters.pages.update_button": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ", + "scenes.app.popup.createworkspacepage.add_subtitle": "НуТно большС мСста?", + "scenes.app.popup.createworkspacepage.create_new_workspace": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ срСду", + "scenes.app.popup.createworkspacepage.placeholder_name": "НазваниС Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды", + "scenes.app.popup.userparameter.pages.frequency_notif_configuration_description": "ΠΠ°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΌΠΎΠ±ΠΈΠ»ΡŒΠ½Ρ‹Π΅ push-увСдомлСния.", + "scenes.app.popup.userparameter.pages.frequency_notif_subtitle": "Частота ΡƒΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠΉ", + "scenes.app.popup.userparameter.pages.keywords_notif_description": "Π’Ρ‹Π΄Π΅Π»ΠΈΡ‚Π΅ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ ΠΊΠ»ΡŽΡ‡Π΅Π²Ρ‹Π΅ слова:", + "scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description": "ΠΠ°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ дайдТСст ΠΏΠΎ элСктронной ΠΏΠΎΡ‡Ρ‚Π΅.", + "scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ ΠΏΠ΅Ρ€ΠΈΠΎΠ΄, Π² Ρ‚Π΅Ρ‡Π΅Π½ΠΈΠ΅ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Π²Ρ‹ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚Π΅ ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ увСдомлСния.", + "scenes.app.popup.userparameter.pages.no_night_disturbing_label": "НС Π±Π΅ΡΠΏΠΎΠΊΠΎΠΈΡ‚ΡŒ Π½ΠΎΡ‡ΡŒΡŽ", + "scenes.app.popup.userparameter.pages.notif_content_label": "Π‘ΠΎΠ΄Π΅Ρ€ΠΆΠΈΠΌΠΎΠ΅ ΡƒΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠΉ", + "scenes.app.mainview.quick_search_placeholder": "Быстрый поиск", + "scenes.app.popup.userparameter.personnal_workspaces_title": "Π’Π°ΡˆΠΈ Ρ€Π°Π±ΠΎΡ‡ΠΈΠ΅ срСды", + "scenes.app.popup.workspaceparameter.admin_current_status": "Π’Ρ‹ ΡΠ²Π»ΡΠ΅Ρ‚Π΅ΡΡŒ администратором.", + "scenes.app.popup.workspaceparameter.admin_manager_current_status": "Π’Ρ‹ ΡΠ²Π»ΡΠ΅Ρ‚Π΅ΡΡŒ администратором Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды.", + "scenes.app.popup.workspaceparameter.manager_current_status": "Π’Ρ‹ ΡΠ²Π»ΡΠ΅Ρ‚Π΅ΡΡŒ администратором ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ срСду", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace_description": "Π£Π΄Π°Π»Π΅Π½ΠΈΠ΅ Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды нСльзя ΠΎΡ‚ΠΌΠ΅Π½ΠΈΡ‚ΡŒ. ВсС сообщСния ΠΈ Ρ„Π°ΠΉΠ»Ρ‹ Π½Π΅ смогут Π±Ρ‹Ρ‚ΡŒ восстановлСны.", + "scenes.app.popup.workspaceparameter.pages.enter": "ВвСсти ", + "scenes.app.popup.workspaceparameter.pages.access_apps": "Доступ ΠΊ вашим прилоТСниям ΠΈ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡΠΌ", + "scenes.app.popup.workspaceparameter.pages.moderator_status": "Администратор Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды", + "scenes.app.popup.workspaceparameter.pages.alert_impossible_removing": "Π’Ρ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΠΎΠΊΠΈΠ½ΡƒΡ‚ΡŒ Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ срСду, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ Π²Ρ‹ послСдний администратор. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ Π½ΠΎΠ²ΠΎΠ³ΠΎ администратора ΠΈΠ»ΠΈ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ/Π°Ρ€Ρ…ΠΈΠ²ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ эту Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ срСду.", + "scenes.app.popup.workspaceparameter.pages.all_apps_small_text": "ВсС прилоТСния", + "scenes.app.popup.workspaceparameter.pages.apps_company_small_text": "ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "scenes.app.popup.workspaceparameter.pages.apps_connectors_title": "Π˜Π½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠΈ", + "scenes.app.popup.workspaceparameter.pages.apps_research_title": "Поиск ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ", + "scenes.app.popup.workspaceparameter.pages.apps_small_text": "ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ этой Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды", + "scenes.app.popup.workspaceparameter.pages.back_to_search_button": "Π’Π΅Ρ€Π½ΡƒΡ‚ΡŒΡΡ ΠΊ поиску", + "scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button": "ΠŸΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ", + "scenes.app.popup.workspaceparameter.pages.collaborateurs": "Π‘ΠΎΡ‚Ρ€ΡƒΠ΄Π½ΠΈΠΊΠΈ", + "scenes.app.popup.workspaceparameter.pages.company_developped_apps_subtitle": "ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ, Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π°Π½Π½Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠ΅ΠΉ", + "scenes.app.popup.workspaceparameter.pages.company_identity_title": "Π˜Π΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "scenes.app.popup.workspaceparameter.pages.company_name_description": "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚Π΅ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ этой ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "scenes.app.popup.workspaceparameter.pages.company_name_label": "НазваниС ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "scenes.app.popup.workspaceparameter.pages.configuration_notif": "настройка", + "scenes.app.popup.workspaceparameter.pages.configure_button": "Настройки ", + "scenes.app.popup.workspaceparameter.pages.description": "ОписаниС", + "scenes.app.popup.workspaceparameter.pages.developped_apps_small_text": "ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ, Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π°Π½Π½Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠ΅ΠΉ", + "scenes.app.popup.workspaceparameter.pages.displayed_preferencies_subtitle": "ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ отобраТСния", + "scenes.app.popup.workspaceparameter.pages.install_button": "Π£ΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ", + "scenes.app.popup.workspaceparameter.pages.installed_app_information": "Π£ΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π² этой Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСдС.", + "scenes.app.popup.workspaceparameter.pages.installed_apps_information": "ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ, установлСнныС Π² этой Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСдС {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_message": "ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ, установлСнныС Π² Π΄Ρ€ΡƒΠ³ΠΈΡ… областях ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_subtitle": "УстановлСнныС прилоТСния", + "scenes.app.popup.workspaceparameter.pages.invitation_error": "ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка ΠΏΡ€ΠΈ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠΈ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… людСй: ", + "scenes.app.popup.workspaceparameter.pages.invited_guest_check_message": "Π£Π±Π΅Π΄ΠΈΡ‚Π΅ΡΡŒ, Ρ‡Ρ‚ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΠΎΠ΅ имя ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ ΠΈΠ»ΠΈ элСктронная ΠΏΠΎΡ‡Ρ‚Π° Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹.", + "scenes.app.popup.workspaceparameter.pages.logo_modify_description": "Π Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ изобраТСния этой Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды", + "scenes.app.popup.workspaceparameter.pages.logo_subtitle": "Π›ΠΎΠ³ΠΎΡ‚ΠΈΠΏ", + "scenes.app.popup.workspaceparameter.pages.name_description": "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ этой Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды", + "scenes.app.popup.workspaceparameter.pages.name_label": "НазваниС Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды", + "scenes.app.popup.workspaceparameter.pages.no_access": "НСт доступа.", + "scenes.app.popup.workspaceparameter.pages.no_app_information": "Π£ вас Π½Π΅Ρ‚ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π² этой Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСдС", + "scenes.app.popup.workspaceparameter.pages.quit_workspace_menu": "ΠŸΠΎΠΊΠΈΠ½ΡƒΡ‚ΡŒ эту Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ срСду", + "scenes.app.popup.workspaceparameter.pages.read_access_subtitle": "Доступ с ΠΏΡ€Π°Π²ΠΎΠΌ чтСния", + "scenes.app.popup.workspaceparameter.pages.remove_from_company_text": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΈΠ· всСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "scenes.app.popup.workspaceparameter.pages.research_by": "Поиск ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ ΠΏΠΎ названию ΠΈ ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ", + "scenes.app.popup.workspaceparameter.pages.researching_apps_button": "Поиск ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ...", + "scenes.app.popup.workspaceparameter.pages.show_button": "ΠŸΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ", + "scenes.app.popup.workspaceparameter.pages.title": "Настройки Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды", + "scenes.app.popup.workspaceparameter.pages.webhooks_access_subtitle": "Доступ ΠΊ webhooks", + "scenes.app.popup.workspaceparameter.pages.weight_max_small_text": "ΠœΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ вСс 5 ΠΌΠ±.", + "scenes.app.popup.workspaceparameter.pages.withdraw_button": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΈΠ· этой Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды", + "scenes.app.popup.workspaceparameter.pages.worspace_notif": "рабочая срСда", + "scenes.app.popup.workspaceparameter.pages.write_access_subtitle": "ΠŸΡ€Π°Π²Π° Π½Π° Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅", + "scenes.app.popup.workspaceparameter.pages.your_apps_label": "Π’Π°ΡˆΠΈ прилоТСния", + "scenes.app.popup.workspaceparameter.payments_subscriptions_title": "ΠŸΠ»Π°Ρ‚Π΅ΠΆΠΈ ΠΈ подписки", + "scenes.app.workspacesbar.components.change_company_title": "Π‘ΠΌΠ΅Π½ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "scenes.app.workspacesbar.components.create_company_menu": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ компанию", + "scenes.app.workspacesbar.components.grp_parameters": "Настройки {{$1}}", + "scenes.apps.calendar.add_calendar_menu": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠ°Π»Π΅Π½Π΄Π°Ρ€ΡŒ", + "scenes.apps.calendar.connectors_menu": "Π Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ...", + "scenes.apps.calendar.connectors_search_menu": "Поиск Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠΉ...", + "scenes.apps.calendar.create_calendar_title": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΊΠ°Π»Π΅Π½Π΄Π°Ρ€ΡŒ", + "scenes.apps.calendar.day_option": "Π”Π΅Π½ΡŒ", + "scenes.apps.calendar.edit_calendar_title": "Π Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠ°Π»Π΅Π½Π΄Π°Ρ€ΡŒ", + "scenes.apps.calendar.export_title": "Π­ΠΊΡΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ", + "scenes.apps.calendar.export_view_menu": "Π­ΠΊΡΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅...", + "scenes.apps.calendar.ics_download_menu": "Π‘ΠΊΠ°Ρ‡Π°Ρ‚ΡŒ ICS Ρ„Π°ΠΉΠ»", + "scenes.apps.calendar.ics_subscription_menu": "ΠŸΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ссылку Π½Π° подписку Π½Π° ICS", + "scenes.apps.calendar.modals.advanced_options": "Π”ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΎΠΏΡ†ΠΈΠΈ", + "scenes.apps.calendar.modals.description_placeholder": "ОписаниС", + "scenes.apps.calendar.modals.details_title": "ΠŸΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎΡΡ‚ΠΈ", + "scenes.apps.calendar.modals.event_adresse_placeholder": "АдрСс", + "scenes.apps.calendar.modals.event_description_placeholder": "ОписаниС", + "scenes.apps.calendar.modals.event_title_placeholder": "НазваниС", + "scenes.apps.calendar.modals.modify_event_button": "Π Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ событиС", + "scenes.apps.calendar.modals.part.participants": "Участники", + "scenes.apps.calendar.modals.participants_event": "Участники", + "scenes.apps.calendar.modals.reminders": "Напоминания", + "scenes.apps.calendar.modals.remove_button": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ", + "scenes.apps.calendar.modals.remove_event_button": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ событиС", + "scenes.apps.calendar.modals.remove_event_text": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ событиС?", + "scenes.apps.calendar.modals.title_placeholder": "НазваниС", + "scenes.apps.calendar.modify_calendar_menu": "Π Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠ°Π»Π΅Π½Π΄Π°Ρ€ΡŒ", + "scenes.apps.calendar.month_option": "ΠœΠ΅ΡΡΡ†", + "scenes.apps.calendar.my_calendar": "Мой ΠΊΠ°Π»Π΅Π½Π΄Π°Ρ€ΡŒ", + "scenes.apps.calendar.my_calendar_label": "Мой ΠΊΠ°Π»Π΅Π½Π΄Π°Ρ€ΡŒ", + "scenes.apps.calendar.my_calendar_menu": "Мой ΠΊΠ°Π»Π΅Π½Π΄Π°Ρ€ΡŒ", + "scenes.apps.calendar.no_calendar_text": "Π’Ρ‹ Π½Π΅ установили Π½ΠΈΠΊΠ°ΠΊΠΈΡ… ΠΊΠ°Π»Π΅Π½Π΄Π°Ρ€Π΅ΠΉ для этой Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды.", + "scenes.apps.calendar.no_connectors_menu_text": "Π£ вас Π½Π΅Ρ‚ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠ³ΡƒΡ‚ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒΡΡ ΠΊ ΠΊΠ°Π»Π΅Π½Π΄Π°Ρ€ΡŽ.", + "scenes.apps.calendar.remove_calendar_confirmation": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΊΠ°Π»Π΅Π½Π΄Π°Ρ€ΡŒ ΠΈ события ΠΈΠ· Π½Π΅Π³ΠΎ навсСгда?", + "scenes.apps.calendar.today_menu": "БСгодня", + "scenes.apps.calendar.week_option": "НСдСля", + "scenes.apps.calendar.workspace": "Рабочая срСда", + "scenes.apps.calendar.workspace_label": "Π­Ρ‚Π° рабочая срСда", + "scenes.apps.calendar.workspace_menu": "Рабочая срСда", + "scenes.apps.drive.add_button": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ", + "scenes.apps.drive.message_added_file": "{{$1}} ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ» {{$2}}.", + "scenes.apps.drive.message_added_file_no_name": "{{$1}} ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ» Ρ„Π°ΠΉΠ».", + "scenes.apps.drive.choose_folder_button": "Π’Ρ‹Π±Ρ€Π°Ρ‚ΡŒ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³", + "scenes.apps.drive.choose_file_button": "Π’Ρ‹Π±Ρ€Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ»", + "scenes.apps.drive.create_folder_button": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ", + "scenes.apps.drive.download_button": "Π‘ΠΊΠ°Ρ‡Π°Ρ‚ΡŒ", + "scenes.apps.drive.open_link": "ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ ссылку Π² Π½ΠΎΠ²ΠΎΠΌ ΠΎΠΊΠ½Π΅", + "scenes.apps.drive.files_subtitle": "Π€Π°ΠΉΠ»Ρ‹", + "scenes.apps.drive.folder_subtitle": "Папки", + "scenes.apps.drive.go_out_trash_menu": "Π’Ρ‹ΠΉΡ‚ΠΈ ΠΈΠ· ΠΊΠΎΡ€Π·ΠΈΠ½Ρ‹", + "scenes.apps.drive.go_trash_menu": "ΠŸΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ Π² ΠΊΠΎΡ€Π·ΠΈΠ½Ρƒ", + "scenes.apps.drive.import_from_computer_menu": "Π—Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ с ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π°", + "scenes.apps.drive.move_text": "ΠŸΠ΅Ρ€Π΅ΠΌΠ΅ΡΡ‚ΠΈΡ‚ΡŒ", + "scenes.apps.drive.new_file_menu": "Новый Ρ„Π°ΠΉΠ»", + "scenes.apps.drive.new_file_title": "Новый Ρ„Π°ΠΉΠ»", + "scenes.apps.drive.new_external_storage": "НовоС внСшнСС Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅", + "scenes.apps.drive.new_folder_title": "Новая ΠΏΠ°ΠΏΠΊΠ°", + "scenes.apps.drive.no_file_alert": "Π£ вас Π½Π΅Ρ‚ прилоТСния, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΠ»ΠΎ Π±Ρ‹ Π²Π°ΠΌ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ».", + "scenes.apps.drive.no_storage_app_alert": "Π£ вас Π½Π΅Ρ‚ прилоТСния, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰Π΅Π³ΠΎ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ внСшнСС Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅.", + "scenes.apps.drive.remove_definitely_menu": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ навсСгда", + "scenes.apps.drive.restore_menu": "Π’ΠΎΡΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ", + "scenes.apps.drive.throw_menu": "ΠŸΠ΅Ρ€Π΅ΠΌΠ΅ΡΡ‚ΠΈΡ‚ΡŒ Π² ΠΊΠΎΡ€Π·ΠΈΠ½Ρƒ", + "scenes.apps.drive.trash_empty_menu": "ΠžΡ‡ΠΈΡΡ‚ΠΈΡ‚ΡŒ ΠΊΠΎΡ€Π·ΠΈΠ½Ρƒ", + "scenes.apps.drive.unconfigured_tab": "Π­Ρ‚Π° Π²ΠΊΠ»Π°Π΄ΠΊΠ° Π΅Ρ‰Π΅ Π½Π΅ настроСна.", + "scenes.apps.drive.viewer.edit_with_button": "ΠžΡ‚Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ {{$1}}", + "scenes.apps.drive.viewer.loading_preview_message": "Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ°...", + "scenes.apps.drive.viewer.no_preview_message": "НСльзя ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ этот Ρ‚ΠΈΠΏ Ρ„Π°ΠΉΠ»Π°.", + "scenes.apps.drive.viewer.open_with_button": "ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ...", + "scenes.apps.messages.input.placeholder": "ΠΠ°ΠΏΠΈΡΠ°Ρ‚ΡŒ сообщСниС. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ @ для упоминания ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠ³ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ.", + "scenes.apps.messages.just_you": "Π’ΠΈΠ΄ΠΈΠΌΠΎ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π²Π°ΠΌ", + "scenes.apps.messages.message.new_messages_bar": "НовыС сообщСния", + "scenes.apps.messages.message.cancel_button": "ΠžΡ‚ΠΌΠ΅Π½ΠΈΡ‚ΡŒ", + "scenes.apps.messages.message.modify_button": "Π Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ", + "scenes.apps.messages.message.pinned": "Π—Π°ΠΊΡ€Π΅ΠΏΠ»Π΅Π½Π½ΠΎΠ΅ сообщСниС", + "scenes.apps.messages.message.remove_button": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ", + "scenes.apps.messages.message.reply_button": "ΠžΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ", + "scenes.apps.messages.message.save_button": "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ", + "scenes.apps.messages.message.show_button": "ΠŸΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ", + "scenes.apps.messages.message.show_responses_button": "ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€ всСх ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ²", + "scenes.apps.messages.message.types.first_channel_message_text": "Π­Ρ‚ΠΎ ΠΏΠ΅Ρ€Π²ΠΎΠ΅ сообщСниС ΠΊΠ°Π½Π°Π»Π°", + "scenes.apps.messages.message.types.first_message_text": "Π­Ρ‚ΠΎ ΠΏΠ΅Ρ€Π²ΠΎΠ΅ сообщСниС", + "scenes.apps.messages.messageslist.get_writing_user": "ΠΏΠ΅Ρ‡Π°Ρ‚Π°Π΅Ρ‚...", + "scenes.apps.messages.messageslist.get_writing_users": "ΠΏΠ΅Ρ‡Π°Ρ‚Π°ΡŽΡ‚...", + "scenes.apps.messages.messageslist.go_last_message_button": "ΠŸΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ ΠΊ послСднСму ΡΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΡŽ", + "scenes.apps.messages.messageslist.go_last_message_button.new_messages": "НовыС сообщСния", + "scenes.error_on_twake": "β€œΠ₯ΡŒΡŽΡΡ‚ΠΎΠ½, Ρƒ нас ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ°β€œ", + "scenes.help_us": "Если Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΏΠΎΠΌΠΎΡ‡ΡŒ Π½Π°ΠΌ ΠΈΡΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ эту ΠΎΡˆΠΈΠ±ΠΊΡƒ, ΠΎΡ‚ΠΏΡ€Π°Π²ΡŒΡ‚Π΅ сообщСниС Π½ΠΈΠΆΠ΅: ", + "scenes.login.verifymail.alert": "ΠœΡ‹ провСряСм Π²Π°ΡˆΡƒ ΡΠ»Π΅ΠΊΡ‚Ρ€ΠΎΠ½Π½ΡƒΡŽ ΠΏΠΎΡ‡Ρ‚Ρƒ!", + "scenes.login.verifymail.error_message": "ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка", + "scenes.login.verifymail.signin_button": "Π’Ρ…ΠΎΠ΄", + "scenes.login.verifymail.success": "Π’Π°ΡˆΠ° элСктронная ΠΏΠΎΡ‡Ρ‚Π° Π±Ρ‹Π»Π° ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½Π°!", + "scenes.login.verifymail.verification_waiting": "ОТиданиС подтвСрТдСния...", + "scenes.no_panic": "Π‘Π΅Π· ΠΏΠ°Π½ΠΈΠΊΠΈ! ΠŸΡ€ΠΎΡΡ‚ΠΎ ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚Π΅ Π΄Π°Π½Π½ΡƒΡŽ страницу, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΡ‡ΠΈΠ½ΠΈΡ‚ΡŒ Twake.", + "services.apps.calendar.deadline_icon": "ΠšΡ€Π°ΠΉΠ½ΠΈΠΉ срок", + "services.apps.calendar.event_icon": "CΠΎΠ±Ρ‹Ρ‚ΠΈΠ΅", + "services.apps.calendar.move_icon": "ΠŸΠ΅Ρ€Π΅Π½Π΅ΡΡ‚ΠΈ", + "services.apps.calendar.reminder_icon": "НапоминаниС", + "services.apps.messages.no_app": "Π­Ρ‚ΠΎΠ³ΠΎ прилоТСния Π½Π΅ сущСствуСт.", + "services.apps.messages.no_command_possible": "ΠœΡ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅ΠΌ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ '{{$1}}', ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ '{{$2}}' Π½Π΅ сущСствуСт ΠΈΠ»ΠΈ Π½Π΅ позволяСт ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹.", + "services.user.notification_parameters_update_alert": "Настройки ΡƒΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠΉ Π±Ρ‹Π»ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½Ρ‹.", + "services.user.update_password_alert": "Π’Π°Ρˆ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ Π±Ρ‹Π» ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½.", + "scenes.app.workspaces.components.skip": "ΠŸΡ€ΠΎΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ", + "scenes.apps.calendar.unconfigured_tab": "Π­Ρ‚Π° Π²ΠΊΠ»Π°Π΄ΠΊΠ° Π΅Ρ‰Π΅ Π½Π΅ настроСна.", + "scenes.apps.drive.trash": "ΠšΠΎΡ€Π·ΠΈΠ½Π°", + "scenes.apps.drive.top_menu_more": "Π‘ΠΎΠ»ΡŒΡˆΠ΅", + "scenes.apps.drive.top_menu_no_items": "{{$1}} элСмСнты", + "scenes.tell_us": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, расскаТитС Π½Π°ΠΌ, Ρ‡Ρ‚ΠΎ Π²Ρ‹ Π΄Π΅Π»Π°Π»ΠΈ Π² :", + "scenes.apps.drive.viewer.download_desktop": "Π‘ΠΊΠ°Ρ‡Π°Ρ‚ΡŒ Twake Desktop для ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ просмотра Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΈ", + "scenes.apps.tasks.my_tasks": "Мои Π·Π°Π΄Π°Ρ‡ΠΈ", + "scenes.apps.tasks.board.place_holder": "НазваниС доски", + "scenes.apps.tasks.board.tasks.subtask": "ΠŸΠΎΠ΄Π·Π°Π΄Π°Ρ‡Π°", + "scenes.apps.tasks.board.tasks.add_subtask": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΏΠΎΠ΄Π·Π°Π΄Π°Ρ‡Ρƒ", + "scenes.apps.tasks.board.tasks.use_deadline": "Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΡ€Π°ΠΉΠ½ΠΈΠΉ срок", + "scenes.apps.tasks.board.tasks.use_starttime": "Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ врСмя Π½Π°Ρ‡Π°Π»Π°", + "scenes.apps.tasks.board.tasks.in_list": "Π’ спискС", + "scenes.apps.tasks.board.starts": "НачинаСтся", + "scenes.apps.tasks.board.ends": "Π”ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ сдСлано ΠΊ", + "scenes.apps.tasks.board.list_name": "НазваниС списка", + "scenes.app.popup.sync_calendar": "Π‘ΠΈΠ½Ρ…Ρ€ΠΎΠ½ΠΈΠ·ΠΈΡ€ΡƒΠΉΡ‚Π΅ свои ΠΊΠ°Π»Π΅Π½Π΄Π°Ρ€ΠΈ.", + "scenes.apps.parameters.workspace_sections.workspace.logo_company": "Π›ΠΎΠ³ΠΎΡ‚ΠΈΠΏ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "scenes.app.popup.workspaceparameter.pages.logo_company_modify_description": "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ этой ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ ", + "scenes.app.popup.workspaceparameter.pages.cancel_invitation": "ΠžΡ‚ΠΌΠ΅Π½ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅", + "scenes.apps.account.account.fullname": "ПолноС имя", + "login.email_login": "ЭлСктронная ΠΏΠΎΡ‡Ρ‚Π° / Π›ΠΎΠ³ΠΈΠ½", + "scenes.apps.account.account.password_for_user": "ΠŸΠ°Ρ€ΠΎΠ»ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ", + "scenes.apps.account.account.send_info": "ΠžΡ‚ΠΏΡ€Π°Π²ΡŒΡ‚Π΅ Π΄Π°Π½Π½ΡƒΡŽ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ Π²Π°ΡˆΠ΅ΠΌΡƒ сотруднику, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ½ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ» Π½ΠΎΠ²Ρ‹Π΅ ΡƒΡ‡Π΅Ρ‚Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅.", + "scenes.apps.account.account.save": "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚", + "scenes.apps.account.message_temporary": "Π’Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΊΠ°ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ Twake, Π½ΠΎ Π²Ρ‹ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚Π΅ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ ΠΊ Π½Π΅ΠΌΡƒ ΠΈ ΠΏΡ€ΠΈ нСобходимости ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΅Π³ΠΎ ΡΠ±Ρ€ΠΎΡΠΈΡ‚ΡŒ.", + "scenes.apps.account.message_user_signin": "Π’Π°Ρˆ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ ΠΌΠΎΠΆΠ΅Ρ‚ Π²ΠΎΠΉΡ‚ΠΈ Π² систСму Π² любоС врСмя, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ эту ΠΆΠ΅ ΠΏΠΎΡ‡Ρ‚Ρƒ, ΠΈ ΡΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ Π½Π° ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ.", + "scenes.app.mainview.link_expired": "Π­Ρ‚Π° публичная ссылка Π½Π΅Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½Π° ΠΈΠ»ΠΈ срок Π΅Π΅ дСйствия истСк.", + "scenes.app.mainview.create_account": "Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ свою Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ срСду бСсплатно Π² ", + "scenes.apps.calendar.modals.reminder_add": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π½Π°ΠΏΠΎΠΌΠΈΠ½Π°Π½ΠΈΠ΅", + "scenes.apps.parameters.workspace_sections.members.invite_all": "ΠŸΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚ΡŒ всСх", + "scenes.app.taskpicker.select": "Π’Ρ‹Π±Ρ€Π°Ρ‚ΡŒ", + "components.listmanager.filter": "Π€ΠΈΠ»ΡŒΡ‚Ρ€", + "scenes.apps.tasks.no_connector": "НСт Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ", + "components.attachmentpicker.add_attachment": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ влоТСния", + "components.input.copied": "Π‘ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Π½ΠΎ", + "components.drive.new_versions": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Π²Π΅Ρ€ΡΠΈΡŽ", + "components.drive.navigators.directory_not_found": "ΠšΠ°Ρ‚Π°Π»ΠΎΠ³ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½.", + "components.drive.right_preview.suppress_link": "Π‘ΠΊΡ€Ρ‹Ρ‚ΡŒ ссылку", + "components.drive.right_preview.create_link": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ ссылку доступа", + "components.drive.moove_here": "ΠŸΠ΅Ρ€Π΅ΠΌΠ΅ΡΡ‚ΠΈΡ‚ΡŒ сюда", + "components.drive.modify_uslist": "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ список ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ", + "components.tagpicker.tag_name": "НазваниС ΠΌΠ΅Ρ‚ΠΊΠΈ", + "components.upload.drop_files": "ΠŸΠ΅Ρ€Π΅Ρ‚Π°Ρ‰ΠΈΡ‚ΡŒ Ρ„Π°ΠΉΠ»Ρ‹ сюда", + "components.workspace.list_manager.no_workspace": "НСт Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды", + "components.workspace.list_manager.add": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Ρ€Π°Π±ΠΎΡ‡ΠΈΠ΅ срСды", + "components.workspace.list_manager.current_space": "ВСкущая рабочая срСда", + "components.workspace.list_manager.current_company": "ВСкущая компания", + "components.workspace.list_manager.all": "ВсС", + "components.workspace.calendar.invalid": "ΠΠ΅Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹", + "components.searchpopup.enter_text": "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ тСкст для поиска Π² Twake.", + "components.searchpopup.loading": "Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ° Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ²", + "components.searchpopup.filter_ws": "Π€ΠΈΠ»ΡŒΡ‚Ρ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ€Π°Π±ΠΎΡ‡ΠΈΠ΅ срСды", + "components.searchpopup.tags": "ΠœΠ΅Ρ‚ΠΊΠΈ", + "components.searchpopup.size": "Π Π°Π·ΠΌΠ΅Ρ€", + "components.searchpopup.creation": "Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅", + "components.searchpopup.update_search": "ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ поиск", + "components.searchpopup.last_modif": "ПослСдняя модификация", + "components.searchpopup.sender": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚Π΅Π»ΡŒ", + "components.searchpopup.mentions": "Упоминания", + "components.searchpopup.only_pinned": "Волько Π·Π°ΠΊΡ€Π΅ΠΏΠ»Π΅Π½Π½Ρ‹Π΅ сообщСния", + "components.alert.confirm": "ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚Π΅ вашС дСйствиС", + "components.alert.confirm_click": "ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚Π΅ вашС дСйствиС, Π½Π°ΠΆΠ°Π² Π½Π° ΠΊΠ½ΠΎΠΏΠΊΡƒ \"ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚ΡŒ\".", + "components.searchpopup.tasks": "Π—Π°Π΄Π°Ρ‡ΠΈ", + "scenes.app.mainview.advanced_search_placeholder": "Π Π°ΡΡˆΠΈΡ€Π΅Π½Π½Ρ‹ΠΉ поиск", + "components.searchpopup.hide_filters": "ΡΠΊΡ€Ρ‹Ρ‚ΡŒ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Ρ‹", + "components.searchpopup.show_filters": "ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Ρ‹", + "components.searchpopup.load_more": "Π—Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ большС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ²", + "general.more": "Π‘ΠΎΠ»ΡŒΡˆΠ΅", + "scenes.apps.board.archived_tasks": "Π—Π°Π°Ρ€Ρ…ΠΈΠ²ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Π΅ Π·Π°Π΄Π°Ρ‡ΠΈ ({{$1}})", + "scenes.apps.board.active_tasks": "АктивныС Π·Π°Π΄Π°Ρ‡ΠΈ", + "scenes.apps.board.kanban": "Канбан", + "scenes.apps.board.display_as": "ΠžΡ‚ΠΎΠ±Ρ€Π°Π·ΠΈΡ‚ΡŒ ΠΊΠ°ΠΊ", + "scenes.apps.board.new_task": "+ Новая Π·Π°Π΄Π°Ρ‡Π°", + "scenes.apps.board.all_boards": "ВсС доски", + "components.userlistmanager.no_users": "НСт ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ.", + "scenes.apps.drive.used": "использовано Π² этой ΠΏΠ°ΠΏΠΊΠ΅", + "components.reminder.notification": "УвСдомлСния", + "components.reminder.minutes_bef": "ΠΌΠΈΠ½ΡƒΡ‚(Ρ‹) Π΄ΠΎ", + "components.reminder.hours_bef": "часа(ΠΎΠ²) Π΄ΠΎ", + "components.reminder.days_bef": "дня(Π΄Π½Π΅ΠΉ) Π΄ΠΎ", + "components.reminder.weeks_bef": "нСдСль(ΠΈ) Π΄ΠΎ", + "components.reminder.by_email": "По элСктронной ΠΏΠΎΡ‡Ρ‚Π΅", + "scenes.apps.calendar.reminders": "Π½Π°ΠΏΠΎΠΌΠΈΠ½Π°Π½ΠΈe(я)", + "scenes.apps.calendar.video_link": "НаТмитС, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ ссылку", + "scenes.app.mainview.discussion": "ΠžΠ±ΡΡƒΠΆΠ΄Π΅Π½ΠΈΠ΅", + "components.tagpicker.notag": "НСт ΠΌΠ΅Ρ‚ΠΊΠΈ", + "scenes.apps.tasks.modals.attachments": "ВлоТСния", + "components.calendar.calendarselector.from": "C", + "scenes.apps.drive.move_text2": "ΠŸΠ΅Ρ€Π΅ΠΌΠ΅ΡΡ‚ΠΈΡ‚ΡŒ", + "components.attachmentpicker.from_computer": "Π‘ ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π°", + "components.attachmentpicker.from_twake": "Из Twake Documents", + "components.attachmentpicker.file": "Π€Π°ΠΉΠ»", + "components.attachmentpicker.remove_attach": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ Π²Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "scenes.apps.drive.remove_attachs": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ влоТСния", + "components.drive.elements.see": "ΠŸΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ", + "components.drive.elements.current_name": "Π’Π΅ΠΊΡƒΡ‰Π΅Π΅ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ : ", + "scenes.apps.drive.right_preview.public": "ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΉ доступ", + "components.drive.elements.configurate_mod": "Настройка модуля...", + "components.drive.elements.manage_version": "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ вСрсиями", + "scenes.app.popup.createcompany.try_again": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π° ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΠΈΡ‚Π΅ ΠΏΠΎΠΏΡ‹Ρ‚ΠΊΡƒ.", + "scenes.app.popup.workspace.edit_temp": "Π Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚", + "scenes.app.popup.workspace.create_temp": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚", + "scenes.apps.tasks.active_tasks": "Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹Π΅(Ρ…) Π·Π°Π΄Π°Ρ‡ΠΈ(ь)", + "scenes.apps.drive.right_preview.versions": "ВСрсии", + "components.locked_features.locked_workspace_popup.title": "Π’Ρ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ большС Ρ€Π°Π±ΠΎΡ‡ΠΈΡ… срСд", + "components.locked_features.locked_workspace_popup.subtitle": "Π’ бСсплатной вСрсии Ρƒ вас ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ 1 рабочая срСда Π² ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ.", + "components.locked_features.locked_workspace_popup.text": "Ой... ΠŸΠΎΡ…ΠΎΠΆΠ΅, Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ срСду Π² своСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ. Π’Π°ΠΌ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ свой ΠΏΠ»Π°Π½. Π˜Π·ΡƒΡ‡ΠΈΡ‚Π΅ нашС Ρ†Π΅Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ Π²Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Π»ΡƒΡ‡ΡˆΠΈΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ для совмСстной Ρ€Π°Π±ΠΎΡ‚Ρ‹ вашСй ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹.", + "components.locked_features.locked_only_office_popup.title": "Π’Ρ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ этот Ρ„Π°ΠΉΠ»", + "components.locked_features.locked_only_office_popup.subtitle": "Π’ бСсплатной вСрсии Π²Ρ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ onlyoffice.", + "components.locked_features.locked_only_office_popup.text": "Ой... ΠŸΠΎΡ…ΠΎΠΆΠ΅, Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΎΡ‚Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ» ΠΈΠ· Twake. Π’Π°ΠΌ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ свой ΠΏΠ»Π°Π½, Ρ‡Ρ‚ΠΎΠ±Ρ‹ совмСстно ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ»Ρ‹. Π˜Π·ΡƒΡ‡ΠΈΡ‚Π΅ нашС Ρ†Π΅Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ Π²Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Π»ΡƒΡ‡ΡˆΠΈΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ для совмСстной Ρ€Π°Π±ΠΎΡ‚Ρ‹ вашСй ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹.", + "components.locked_features.locked_drive_popup.title": "Π’Ρ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ большС Ρ„Π°ΠΉΠ»ΠΎΠ²", + "components.locked_features.locked_drive_popup.subtitle": "Π’ бСсплатной вСрсии ΠΌΠΎΠΆΠ½ΠΎ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ 6 Π“Π‘.", + "scenes.app.integrations_parameters.title": "Π˜Π½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠΈ", + "scenes.app.integrations_parameters.applications_table.name": "Имя", + "scenes.app.integrations_parameters.applications_table.title": "Π”Ρ€ΡƒΠ³ΠΈΠ΅ ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠΈ", + "scenes.app.integrations_parameters.applications_table.search_placeholder": "ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ для поиска", + "scenes.app.integrations_parameters.company_application_popup.tag": "УстановлСны", + "scenes.app.integrations_parameters.company_application_popup.btn": "Π£ΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ", + "scenes.app.integrations_parameters.company_application_popup.tab_btn_info": "Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.description_item": "ОписаниС", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.website_item": "Π’Π΅Π±-сайт", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.created_item": "Π”Π°Ρ‚Π° создания", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.version_item": "ВСрсия", + "scenes.app.integrations_parameters.company_applications_table.more_menu.show_application": "ΠŸΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ", + "scenes.app.integrations_parameters.company_applications_table.more_menu.remove_application": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΈΠ· ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "scenes.app.integrations_parameters.company_applications_table.name": "Имя", + "scenes.app.integrations_parameters.company_applications_table.title": "УстановлСн Π² вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "components.rich_text_editor.plugins.suggestions.default_message.display_results": "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ ΠΌΠΈΠ½ΠΈΠΌΡƒΠΌ Ρ‚Ρ€ΠΈ символа для отобраТСния ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ", + "components.rich_text_editor.plugins.suggestions.default_message.no_user_found": "ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½", + "components.rich_text_editor.plugins.suggestions.default_message.no_emoji_found": "НС Π½Π°ΠΉΠ΄Π΅Π½ΠΎ Π½ΠΈ ΠΎΠ΄Π½ΠΎΠ³ΠΎ эмодзи", + "components.rich_text_editor.plugins.suggestions.default_message.no_command_found": "Команда Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Π°", + "general.retry": "ΠŸΠΎΠ²Ρ‚ΠΎΡ€ΠΈΡ‚ΡŒ ΠΏΠΎΠΏΡ‹Ρ‚ΠΊΡƒ", + "scenes.app.popup.adduser.magiclinks.genrator_info": "ΠŸΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚Π΅Π»ΡŒΠ½Π°Ρ ссылка для Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды", + "application.load.longer": "Π‘Π΅Ρ€Π²Π΅Ρ€ Π½Π΅ ΠΎΡ‚Π²Π΅Ρ‡Π°Π΅Ρ‚ слишком Π΄ΠΎΠ»Π³ΠΎ; ΠΏΠΎΠ΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅ ΠΈΠ»ΠΈ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚Π΅ страницу...", + "scenes.apps.account.notifications.sound": "Π—Π²ΡƒΠΊΠΎΠ²Ρ‹Π΅ увСдомлСния", + "scenes.app.channelsbar.currentuser.company_messages_counter_header": "ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ сообщСний", + "scenes.app.channelsbar.currentuser.company_messages_counter_info": "Π’ бСсплатной вСрсии Twake Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ лишь ΠΊ {{$1}} послСдним сообщСниям.", + "scenes.app.channelsbar.currentuser.company_messages_counter_link": "Π‘ΠΎΠ»ΡŒΡˆΠ΅ ΠΏΠ»Π°Π½ΠΎΠ²", + "scenes.apps.messages.input.hide_formatting": "Π‘ΠΊΡ€Ρ‹Ρ‚ΡŒ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅", + "scenes.apps.messages.input.show_formatting": "ΠžΡ‚ΠΎΠ±Ρ€Π°Π·ΠΈΡ‚ΡŒ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅", + "scenes.app.popup.appsparameters.pages.subtitle_informations": "Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ, связанная с ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ΠΌ прилоТСниями", + "components.newversion.new_version_modal.title": "Доступно Π½ΠΎΠ²ΠΎΠ΅ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ !", + "scenes.apps.drive.download_all_button": "Π‘ΠΊΠ°Ρ‡Π°Ρ‚ΡŒ всС", + "components.inputs.input_with_select.input.placeholder": "НазваниС ΠΊΠ°Π½Π°Π»Π°", + "components.inputs.input_with_select.select.placeholder": "НазваниС Ρ€Π°Π·Π΄Π΅Π»Π°", + "components.inputs.input_with_select.select.no_sections": "Π—Π΄Π΅ΡΡŒ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π³Ρ€ΡƒΠΏΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ свои ΠΊΠ°Π½Π°Π»Ρ‹", + "scenes.apps.messages.message.activity_message.a_removed_b_from_the_channel": "{{$1}} ΡƒΠ΄Π°Π»ΠΈΠ» {{$2}} ΠΈΠ· ΠΊΠ°Π½Π°Π»Π°", + "scenes.apps.messages.message.activity_message.a_updated_channel_description": "{{$1}} ΠΈΠ·ΠΌΠ΅Π½ΠΈΠ» описаниС", + "scenes.apps.messages.message.activity_message.a_updated_channel_name": "{{$1}} ΠΏΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π» ΠΊΠ°Π½Π°Π» Π² {{$2}}", + "scenes.apps.messages.message.activity_message.a_created_channel_tab": "{{$1}} Π΄ΠΎΠ±Π°Π²ΠΈΠ» Π½ΠΎΠ²ΡƒΡŽ Π²ΠΊΠ»Π°Π΄ΠΊΡƒ {{$2}} {{$3}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_tab": "{{$1}} ΡƒΠ΄Π°Π»ΠΈΠ» Π²ΠΊΠ»Π°Π΄ΠΊΡƒ {{$2}} {{$3}}", + "scenes.apps.messages.message.activity_message.a_created_channel_connector": "{{$1}} Π΄ΠΎΠ±Π°Π²ΠΈΠ» Π½ΠΎΠ²ΠΎΠ΅ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ {{$2}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_connector": "{{$1}} ΡƒΠ΄Π°Π»ΠΈΠ» Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ {{$2}}", + "components.alert.leave_private_channel.description": "Π’Ρ‹ Π½Π΅ смоТСтС снова ΠΏΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒΡΡ ΠΊ этому частному ΠΊΠ°Π½Π°Π»Ρƒ, Ссли вас Π½ΠΈΠΊΡ‚ΠΎ Π½Π΅ пригласит.", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.tag": "Π’Ρ‹ Π½Π΅ ΡΠ²Π»ΡΠ΅Ρ‚Π΅ΡΡŒ Ρ‡Π»Π΅Π½ΠΎΠΌ", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.loader": "Π—Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ большС", + "components.unverified_account.typography_text_danger": "ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚Π΅ свою ΡƒΡ‡Π΅Ρ‚Π½ΡƒΡŽ запись Π² Ρ‚Π΅Ρ‡Π΅Π½ΠΈΠ΅ {{$1}} Π΄Π½Π΅ΠΉ. Π’ ΠΏΡ€ΠΎΡ‚ΠΈΠ²Π½ΠΎΠΌ случаС учСтная запись Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½Π° Ρ‡Π΅Ρ€Π΅Π· 7 Π΄Π½Π΅ΠΉ ΠΈ ΠΎΠΊΠΎΠ½Ρ‡Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ ΡƒΠ΄Π°Π»Π΅Π½Π° Ρ‡Π΅Ρ€Π΅Π· 30 Π΄Π½Π΅ΠΉ. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚ΡŒ свою ΡƒΡ‡Π΅Ρ‚Π½ΡƒΡŽ запись с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ элСктронного письма с ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ΠΈΠ΅ΠΌ.", + "components.unverified_account.verification_details": "ΠœΡ‹ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ»ΠΈ элСктронноС письмо с ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ΠΈΠ΅ΠΌ ΠΏΠΎ адрСсу", + "components.account_verification_status_sentence": "Бтатус вашСй ΡƒΡ‡Π΅Ρ‚Π½ΠΎΠΉ записи: {{$1}}", + "components.account_verication_status_unverified": "ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π½Π΅ ΠΏΡ€ΠΎΠΉΠ΄Π΅Π½Π°", + "components.account_verication_status_blocked": "Π—Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½", + "components.unverified_account.re_send_email": "НС ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΈ письмо?", + "components.add_mails_workspace.title_2": "Twake - это инструмСнт для совмСстной Ρ€Π°Π±ΠΎΡ‚Ρ‹ Π² ΠΊΠΎΠΌΠ°Π½Π΄Π΅, поэтому ΠΌΡ‹ совСтуСм ΠΏΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚ΡŒ Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΡ‚Π΅ΡΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΡΠΎΠ·Π΄Π°Π½Π½ΡƒΡŽ для вас Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ срСду.", + "components.add_mails_workspace.text_area_placeholder": "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ адрСса элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ*", + "components.verify_mail.title_2": "Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π²Ρ‹ ΡΠ²Π»ΡΠ΅Ρ‚Π΅ΡΡŒ ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½Ρ‹ΠΌ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΌ Twake!", + "services.console_services.toaster.success_verify_email": "Бсылка для подтвСрТдСния Π±Ρ‹Π»Π° ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½Π° ΠΏΠΎ Π²Π°ΡˆΠ΅ΠΌΡƒ адрСсу элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹", + "scenes.app.popup.workspaceparameter.edit_from_console": "Π‘ΠΌ. Π² \"Консоли\"", + "services.console_services.toaster.success_invite_emails": "УспСшно Π΄ΠΎΠ±Π°Π²Π»Π΅Π½(ΠΎ) {{$1}} ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ(Π΅ΠΉ)", + "scenes.client.channels_bar.modals.guest_management.input_placeholder": "Поиск гостСй ΠΈΠ»ΠΈ ΠΎΠΆΠΈΠ΄Π°ΡŽΡ‰ΠΈΡ… писСм", + "scenes.client.channels_bar.modals.guest_management.tips": "Π”ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ ΠΈΠ»ΠΈ Π½Π°ΠΉΠ΄ΠΈΡ‚Π΅ ΡΠ»Π΅ΠΊΡ‚Ρ€ΠΎΠ½Π½ΡƒΡŽ ΠΏΠΎΡ‡Ρ‚Ρƒ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ Π²Π²Π΅Π΄Π΅Π½Π½Ρ‹Π΅ Π²Ρ‹ΡˆΠ΅ Π΄Π°Π½Π½Ρ‹Π΅", + "general.user.role.company.guest": "Π“ΠΎΡΡ‚ΡŒ", + "general.user.deleted": "УдалСнная учСтная запись", + "components.richtexteditor.toolbar.underline": "ΠŸΠΎΠ΄Ρ‡Π΅Ρ€ΠΊΠ½ΡƒΡ‚Ρ‹ΠΉ", + "components.richtexteditor.toolbar.italic": "ΠšΡƒΡ€ΡΠΈΠ²", + "components.richtexteditor.toolbar.ordered-list": "Π—Π°ΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΉ список", + "components.richtexteditor.toolbar.code-block": "Π‘Π»ΠΎΠΊ ΠΊΠΎΠ΄Π°", + "components.locked_features.locked_history_banner.title": "Π’Ρ‹ достигли Π»ΠΈΠΌΠΈΡ‚Π° сообщСний", + "components.locked_features.locked_history_banner.description": "Π£ вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ ΠΌΠ½ΠΎΠ³ΠΎ сообщСний! ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚Π΅ сСйчас, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ ΠΊΠΎ всСй истории сообщСний.", + "components.locked_features.locked_history_banner.button": "Π£Π·Π½Π°Ρ‚ΡŒ большС", + "components.locked_features.locked_guests_popup.title": "Ѐункция гостСй Π·Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½Π°", + "components.locked_features.locked_guests_popup.subtitle": "Π­Ρ‚Π° функция нСдоступна Π² бСсплатной вСрсии Twake", + "components.on_boarding.company_billing_banner.admin_or_owner_text": "Π’ΠΎΠ·Π½ΠΈΠΊΠ»Π° ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° с подпиской вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΈΠ·ΡƒΡ‡ΠΈΡ‚Π΅ ваш", + "components.on_boarding.company_billing_banner.link": "ΠΏΠ»Π°Π½ подписки ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "components.on_boarding.popups.blocked_company.title": "Π’Π°ΡˆΠ° компания Π·Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½Π° ΠΈΠ·-Π·Π° ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ с ΠΎΠΏΠ»Π°Ρ‚ΠΎΠΉ", + "components.on_boarding.popups.blocked_company.description": "Π‘Ρ€ΠΎΠΊ дСйствия вашСй подписки Π½Π° Twake истСк. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΡΠ²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π΅ΠΌ ΠΈΠ»ΠΈ администратором вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠ΄Π»ΠΈΡ‚ΡŒ подписку ΠΈ снова ΠΈΠΌΠ΅Ρ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΠΎΠ±Ρ‰Π°Ρ‚ΡŒΡΡ с ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ!", + "components.on_boarding.popups.blocked_company.learn_more_text": "Π₯ΠΎΡ‚ΠΈΡ‚Π΅ ΡƒΠ·Π½Π°Ρ‚ΡŒ большС ΠΎ ΠΏΠ»Π°Π½Π΅ подписки для ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΉ?", + "components.on_boarding.popups.blocked_company.company_subscription_plan_button": "ΠšΠ»ΠΈΠΊΠ½ΠΈΡ‚Π΅ сюда", + "components.on_boarding.popups.blocked_company.or": "Или", + "components.on_boarding.popups.blocked_company.company_selector": "ΠŸΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ Π² Π΄Ρ€ΡƒΠ³ΡƒΡŽ компанию", + "services.apps.messages.message_editor_service.upload_error_toaster": "{{$1}} - Π’Ρ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΡ€ΠΈΠΊΡ€Π΅ΠΏΠΈΡ‚ΡŒ Π±ΠΎΠ»Π΅Π΅ {{$2}} Ρ„Π°ΠΉΠ»ΠΎΠ² ΠΊ ΡΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΡŽ", + "scenes.apps.messages.message.parts.deleted_content.text": "{{$1}} ΡƒΠ΄Π°Π»ΠΈΠ» своС сообщСниС", + "components.member.user_parts.and_more_user_text": " ΠΈ Π΅Ρ‰Π΅ {{$1}} ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_link": "Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ частный ΠΊΠ°Π½Π°Π»", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_text": " вмСсто", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_input_placeholder": "Π’Ρ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π±ΠΎΠ»Π΅Π΅ 10 ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ", + "general.uploading": "Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ°", + "components.upload.drop_files.toaster.error": "Π’Ρ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ Π±ΠΎΠ»Π΅Π΅ {{$1}} Ρ„Π°ΠΉΠ»ΠΎΠ²", + "components.emoji_picker.categories.frequently_used": "Часто ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Π΅", + "components.emoji_picker.categories.smileys_and_people": "Π‘ΠΌΠ°ΠΉΠ»ΠΈΠΊΠΈ ΠΈ люди", + "components.emoji_picker.categories.animals_and_nature": "Π–ΠΈΠ²ΠΎΡ‚Π½Ρ‹Π΅ ΠΈ ΠΏΡ€ΠΈΡ€ΠΎΠ΄Π°", + "components.emoji_picker.categories.food_and_drink": "Π•Π΄Π° ΠΈ Π½Π°ΠΏΠΈΡ‚ΠΊΠΈ", + "components.emoji_picker.categories.travel_and_places": "ΠŸΡƒΡ‚Π΅ΡˆΠ΅ΡΡ‚Π²ΠΈΡ ΠΈ мСста", + "components.emoji_picker.categories.objects": "ΠžΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹", + "components.emoji_picker.categories.symbols": "Π‘ΠΈΠΌΠ²ΠΎΠ»Ρ‹", + "scenes.app.popup.workspaceparameter.pages.workspace_partner_tabs.members.table.tags": "Роль", + "general.email": "Π­Π». адрСс", + "scenes.join.join_workspace_from_company": "ΠŸΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΡΠΉΡ‚Π΅ΡΡŒ ΠΊ {{$1}} с {{$2}}!", + "scenes.join.twake_description": "Twake - это цифровая рабочая срСда с ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΌ исходным ΠΊΠΎΠ΄ΠΎΠΌ, созданная для ΠΏΠΎΠ²Ρ‹ΡˆΠ΅Π½ΠΈΡ продуктивности вашСй ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹", + "scenes.join.login_first_button": "Π’ΠΎΠΉΡ‚ΠΈ ΠΈΠ»ΠΈ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΡƒΡ‡Π΅Ρ‚Π½ΡƒΡŽ запись", + "scenes.join.join_the_team_button": "ΠŸΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒΡΡ ΠΊ ΠΊΠΎΠΌΠ°Π½Π΄Π΅", + "general.verify": "ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ", + "components.inputs.input_with_select.button.tooltip": "Π£ΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ Ρ€Π°Π·Π΄Π΅Π» ΠΊΠ°Π½Π°Π»Π°", + "scenes.app.popup.adduser.magiclinks.new_link_generated": "Π‘ΠΎΠ·Π΄Π°Π½Π° новая ссылка", + "scenes.app.popup.adduser.magiclinks.copied_to_clipboard": "УспСшно скопировано Π² Π±ΡƒΡ„Π΅Ρ€ ΠΎΠ±ΠΌΠ΅Π½Π°", + "scenes.app.popup.adduser.magiclinks.action_copy": "ΠšΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ", + "scenes.app.popup.adduser.magiclinks.action_generate": "Π‘Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ", + "scenes.app.popup.workspaceparameter.pages.error_workspace_member": "Π’Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ СдинствСнным участником Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ Π΅Π΅. Π£Π΄Π°Π»ΠΈΡ‚Π΅ ΠΏΡ€ΠΎΡ‡ΠΈΡ… участников ΠΈ ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ Π΅Ρ‰Π΅ Ρ€Π°Π·.", + "scenes.apps.messages.input.emoji": "Π­ΠΌΠΎΠ΄Π·ΠΈ", + "components.verify_mail.title_1": "ΠŸΠΎΠ·Π΄Ρ€Π°Π²Π»ΡΠ΅ΠΌ", + "components.verify_mail.text": "ΠŸΡ€Π΅ΠΆΠ΄Π΅ всСго, Π²Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚ΡŒ свой адрСс элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹. ΠœΡ‹ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ»ΠΈ ссылку для подтвСрТдСния ΠΏΠΎ адрСсу", + "components.verify_mail.paragraph": "Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ это ΠΏΠΎΠ·ΠΆΠ΅, Π½ΠΎ Π½Π΅ΠΏΡ€ΠΎΠ²Π΅Ρ€Π΅Π½Π½Ρ‹Π΅ ΡƒΡ‡Π΅Ρ‚Π½Ρ‹Π΅ записи ΠΈΠΌΠ΅ΡŽΡ‚ доступ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΊ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½Π½ΠΎΠΉ вСрсии Twake", + "services.console_services.toaster.add_email_error_message": "Ошибка ΠΏΡ€ΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠΈ {{$1}}", + "scenes.client.channels_bar.modals.parts.channel_member_row.label.pending_email": "Письмо ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½ΠΎ", + "general.user.role.company.admin": "Администратор ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "components.richtexteditor.toolbar.strikethrough": "Π—Π°Ρ‡Π΅Ρ€ΠΊΠ½ΡƒΡ‚Ρ‹ΠΉ", + "components.richtexteditor.toolbar.code": "Код", + "components.richtexteditor.toolbar.unordered-list": "ΠœΠ°Ρ€ΠΊΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ список", + "components.locked_features.locked_guests_popup.description": "Ой... ΠŸΠΎΡ…ΠΎΠΆΠ΅, Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΏΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚ΡŒ Π²Π½Π΅ΡˆΠ½ΠΈΡ… ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ Π² свою Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ срСду. Π’Π°ΠΌ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ свой ΠΏΠ»Π°Π½, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠΎΡ‚Ρ€ΡƒΠ΄Π½ΠΈΡ‡Π°Ρ‚ΡŒ с гостями ΠΈ внСшними ΠΏΠ°Ρ€Ρ‚Π½Π΅Ρ€Π°ΠΌΠΈ. Π˜Π·ΡƒΡ‡ΠΈΡ‚Π΅ нашС Ρ†Π΅Π½ΠΎΠ²ΠΎΠ΅ ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ Π²Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ Π»ΡƒΡ‡ΡˆΠΈΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ для совмСстной Ρ€Π°Π±ΠΎΡ‚Ρ‹ вашСй ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹.", + "components.locked_features.locked_guests_popup.learn_more_button": "Π£Π·Π½Π°Ρ‚ΡŒ большС", + "components.locked_features.locked_guests_popup.or": "Или", + "scenes.apps.messages.input.attach_file.from_computer": "Π‘ ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π°", + "scenes.client.main_view.main_header.search_input": "Поиск", + "scenes.apps.drive.new_link_title": "Новая ссылка", + "scenes.apps.drive.default_link_name": "Π‘Π΅Π· названия", + "components.emoji_picker.input_search_placeholder": "Поиск", + "scenes.apps.messages.message.parts.deleted_content.text.current_user": "Π’Ρ‹ ΡƒΠ΄Π°Π»ΠΈΠ»ΠΈ это сообщСниС", + "components.emoji_picker.categories.flags": "Π€Π»Π°Π³ΠΈ", + "components.emoji_picker.categories.search_result": "Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ поиска", + "components.emoji_picker.categories.not_found": "Π­ΠΌΠΎΠ΄Π·ΠΈ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Ρ‹", + "general.resume": "ΠŸΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ΡŒ", + "general.pause": "ΠŸΠ°ΡƒΠ·Π°", + "scenes.client.channels_bar.modals.guest_management.title": "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ гостями Π² {{$1}}", + "components.channelworkspacelist.title": "ΠšΠ°Π½Π°Π»Ρ‹", + "general.user.role.company.member": "Участник", + "components.richtexteditor.toolbar.bold": "ΠŸΠΎΠ»ΡƒΠΆΠΈΡ€Π½Ρ‹ΠΉ", + "scenes.client.channelbar.channelmemberslist.tag": "Π’Ρ‹", + "components.alert.leave_private_channel.title": "Π’Ρ‹ ΡƒΠ²Π΅Ρ€Π΅Π½Ρ‹, Ρ‡Ρ‚ΠΎ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΏΠΎΠΊΠΈΠ½ΡƒΡ‚ΡŒ ΠΊΠ°Π½Π°Π»?", + "components.richtexteditor.toolbar.blockquote": "Π¦ΠΈΡ‚Π°Ρ‚Π°", + "components.emoji_picker.categories.activity": "Π”Π΅ΡΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ", + "scenes.apps.messages.input.edited": "ΠžΡ‚Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΎ", + "components.locked_features.locked_guests_popup.skip_for_now_button": "ΠžΡ‚Π»ΠΎΠΆΠΈΡ‚ΡŒ", + "scenes.join.loading": "Загрузка…", + "scenes.join.wrong_link_title": "Π­Ρ‚Π° ссылка большС Π½Π΅ доступна", + "scenes.join.wrong_link_description": "ΠŸΠΎΠΏΡ€ΠΎΡΠΈΡ‚Π΅ Ρ‡Π΅Π»ΠΎΠ²Π΅ΠΊΠ°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ пригласил вас ΠΏΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒΡΡ ΠΊ этой ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ, Π²Ρ‹ΡΠ»Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ ссылку ΠΈΠ»ΠΈ создайтС ΡΠΎΠ±ΡΡ‚Π²Π΅Π½Π½ΡƒΡŽ компанию", + "scenes.join.create_the_company_button": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ компанию", + "scenes.apps.messages.message.activity_message.a_added_b_to_the_channel": "{{$1}} Π΄ΠΎΠ±Π°Π²ΠΈΠ» {{$2}} Π½Π° ΠΊΠ°Π½Π°Π»", + "scenes.app.mainview.channel_description": "ΠžΠΏΠΈΡˆΠΈΡ‚Π΅ ΠΊΠ°Π½Π°Π»", + "scenes.apps.messages.message.unpin_button": "ΠžΡ‚ΠΊΡ€Π΅ΠΏΠΈΡ‚ΡŒ сообщСниС", + "components.calendar.repetition.on": "На", + "scenes.apps.messages.new_thread": "ΠΠ°Ρ‡Π°Ρ‚ΡŒ Π½ΠΎΠ²ΠΎΠ΅ обсуТдСниС", + "scenes.apps.messages.input.send_message": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ сообщСниС", + "scenes.client.channelbar.channeltemplateeditor.checkbox": "АвтоматичСски ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ°Ρ‚ΡŒ всСх ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды Π½Π° этот ΠΊΠ°Π½Π°Π»", + "components.blocked_account.trial_period_over": "Π’Π°Ρˆ ΠΏΡ€ΠΎΠ±Π½Ρ‹ΠΉ ΠΏΠ΅Ρ€ΠΈΠΎΠ΄ закончился. Π§Ρ‚ΠΎΠ±Ρ‹ Ρ€Π°Π·Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΡƒΡ‡Π΅Ρ‚Π½ΡƒΡŽ запись ΠΈ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ ΠΊΠΎ всСм функциям, поТалуйста, ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚Π΅ Π΅Π΅ ΠΏΠΎ элСктронной ΠΏΠΎΡ‡Ρ‚Π΅", + "components.add_mails_workspace.button": "ΠΠ°Ρ‡Π°Ρ‚ΡŒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Twake", + "components.add_mails_workspace.title_1": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ", + "scenes.app.popup.userparameter.pages.private_message_content.show": "Π‘ΠΊΡ€Ρ‹Ρ‚ΡŒ содСрТимоС сообщСний Π² push-увСдомлСниях", + "scenes.app.popup.userparameter.pages.private_message_content.hide": "Π—Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ содСрТимоС push-ΡƒΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠΉ Π½Π° '[Π‘ΠΊΡ€Ρ‹Ρ‚ΠΎ]'", + "scenes.apps.drive.message_added_mutiple_files": "{{$1}} ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΠ» нСсколько Ρ„Π°ΠΉΠ»ΠΎΠ².", + "scenes.apps.messages.message.pin_button": "Π—Π°ΠΊΡ€Π΅ΠΏΠΈΡ‚ΡŒ сообщСниС", + "scenes.apps.messages.message.copy_link": "Π‘ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ссылку Π½Π° сообщСниС", + "scenes.app.popup.appsparameters.pages.icon": "Π—Π½Π°Ρ‡ΠΎΠΊ", + "scenes.app.popup.appsparameters.pages.title_informations": "Основная информация", + "scenes.app.popup.appsparameters.pages.smalltext_user_id": "Π’Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ", + "scenes.app.popup.appsparameters.pages.smalltext_workspace_id": "Π’Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды", + "scenes.app.popup.appsparameters.pages.smalltext_group_id": "Π’Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π³Ρ€ΡƒΠΏΠΏΡ‹", + "scenes.client.channelbar.channelmemberslist.title": "ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΠΈ Π² {{$1}}", + "scenes.client.channelbar.channelmemberslist.loader": "Π—Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ большС", + "scenes.client.channelbar.channelmemberslist.autocomplete": "Поиск ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ", + "scenes.client.channelbar.channelmemberslist.menu.option_2": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ с ΠΊΠ°Π½Π°Π»Π°", + "components.leftbar.channel.workspaceschannels.menu.option_1": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΊΠ°Π½Π°Π»", + "components.leftbar.channel.workspaceschannels.menu.option_2": "ΠŸΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒΡΡ ΠΊ ΠΊΠ°Π½Π°Π»Ρƒ", + "scenes.client.channelbar.workspacechannellist.autocomplete": "Поиск ΠΊΠ°Π½Π°Π»Π°, ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΡ… ΠΈΠ»ΠΈ Π»ΠΈΡ‡Π½Ρ‹Ρ… сообщСний", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_creation": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Π²ΠΊΠ»Π°Π΄ΠΊΡƒ", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_edition": "ΠŸΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Ρ‚ΡŒ {{$1}}", + "components.connectorslistmanager.add_connectors": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ", + "components.notifications.hidden_notifications_button.children": "НовыС сообщСния", + "scenes.client.mainview.tabs.tabstemplateeditor.select_placeholder": "Заявка", + "scenes.client.channelbar.channelmemberslist.no_members": "На этом ΠΊΠ°Π½Π°Π»Π΅ Π½Π΅Ρ‚ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚ΡŒ ΠΈΡ…, Π½Π°ΠΆΠ°Π² \"Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ\".", + "scenes.app.channelsbar.hide_discussion_leaving.menu": "Π‘ΠΊΡ€Ρ‹Ρ‚ΡŒ обсуТдСниС", + "scenes.app.popup.adduserfromtwakeconsole.current_users_state": "{{$1}} адрСс(Π°) элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹ Π±ΡƒΠ΄Π΅Ρ‚(ΡƒΡ‚) Π΄ΠΎΠ±Π°Π²Π»Π΅Π½(Ρ‹)", + "components.newversion.new_version_component.row.part_1": "Π’Π°ΡˆΠ° вСрсия Twake устарСла", + "components.newversion.new_version_component.row.part_2": "ΠΏΡ€Π΅Π΄Π»Π°Π³Π°Π΅ΠΌ Π²Π°ΠΌ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ ΠΏΠΎΠΏΡ€ΠΎΠ±ΠΎΠ²Π°Ρ‚ΡŒ наши Π½ΠΎΠ²Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ!", + "components.newversion.new_version_component.link": "НаТмитС сюда, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ", + "general.re_send": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ снова", + "components.verify_mail.button": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ", + "services.console_services.toaster.add_emails_error": "Ошибка ΠΏΡ€ΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠΈ адрСса(ΠΎΠ²) элСктронной ΠΏΠΎΡ‡Ρ‚Ρ‹", + "components.on_boarding.company_billing_banner.guest_or_member_text": "Π’ΠΎΠ·Π½ΠΈΠΊΠ»Π° ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° с подпиской вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ. ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ΡΡŒ ΠΊ Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Ρƒ ΠΈΠ»ΠΈ администратору ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ!", + "scenes.apps.tasks.select_user_button": "ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€ Π·Π°Π΄Π°Ρ‡ для Π΄Ρ€ΡƒΠ³ΠΎΠ³ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ", + "scenes.apps.tasks.select_user": "Поиск ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ", + "scenes.app.popup.workspaceparameter.pages.table_title": "Имя", + "login.create_account": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ ΡƒΡ‡Π΅Ρ‚Π½ΡƒΡŽ запись", + "'": "'", + "login.login_error": "Ошибка ΠΏΡ€ΠΈ Π²Ρ…ΠΎΠ΄Π΅ Π² систСму", + "\"": "\"", + "app.state.recoil.hooks.use_current_company_applications.toaster_delete": "УспСшно ΡƒΠ΄Π°Π»ΠΈΠ» {{$1}} ΠΈΠ· вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "app.state.recoil.hooks.use_current_company_applications.toaster_add": "{{$1}} ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ Π² Π²Π°ΡˆΡƒ компанию", + "scenes.apps.messages.input.replied_to": "ΠΎΡ‚Π²Π΅Ρ‚ΠΈΠ» ", + "scenes.app.messages.input.parts.is_writing.message.user_is_writing": "{{$1}} ΠΏΠΈΡˆΠ΅Ρ‚...", + "scenes.app.messages.input.parts.is_writing.message.users_are_writing": "{{$1}} ΠΈ {{$2}} ΠΏΠΈΡˆΡƒΡ‚...", + "scenes.app.messages.input.parts.is_writing.message.users_and_more_are_writing": "{{$1}}, {{$2}} ΠΈ Π΅Ρ‰Π΅ {{$3}} ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ ΠΏΠΈΡˆΡƒΡ‚...", + "scenes.apps.messages.message.types.no_message_in_thread": "Пока Π½ΠΈΠΊΡ‚ΠΎ Π½Π΅ ΠΎΡ‚Π²Π΅Ρ‚ΠΈΠ».", + "scenes.app.workspaces.welcome_page.no_workspace_subtitle": "Вас Π΅Ρ‰Π΅ Π½ΠΈΠΊΡ‚ΠΎ Π½Π΅ пригласил Π² Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ срСду.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.label": "Рабочая срСда ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.description": "АвтоматичСски ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ°Ρ‚ΡŒ всСх ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды Π½Π° этот ΠΊΠ°Π½Π°Π»", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.title": "Π’Ρ‹ ΡΠΎΠ±ΠΈΡ€Π°Π΅Ρ‚Π΅ΡΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ {{$1}}", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.alert_total_members": "Π£ вас всС Π΅Ρ‰Π΅ Π΅ΡΡ‚ΡŒ {{$1}} участников Π² {{$2}}. Π’Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ всСх участников, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠΌΠ΅Ρ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ эту Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ срСду.", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.checkbox": "Π― понимаю, Ρ‡Ρ‚ΠΎ всС сообщСния ΠΈ Ρ„Π°ΠΉΠ»Ρ‹ ΠΌΠΎΠ΅ΠΉ Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды Π±ΡƒΠ΄ΡƒΡ‚ ΡƒΠ΄Π°Π»Π΅Π½Ρ‹.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.max_size": "ΠœΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ€Π°Π·ΠΌΠ΅Ρ€ Π»ΠΎΠ³ΠΎΡ‚ΠΈΠΏΠ° 5 ΠœΠ‘", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.bad_format": "НСвСрный Ρ„ΠΎΡ€ΠΌΠ°Ρ‚, Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½Ρ‹ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Ρ‹ png, gif ΠΈ jpg", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.unknown": "НСизвСстная ошибка", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.prefix": "Ошибка", + "scenes.app.channelsbar.currentuser.reset": "ΠŸΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ", + "components.locked_features_components.locked_invite_alert.message_part_1": "Π’Π°ΡˆΠ° компания достигла максимального Π»ΠΈΠΌΠΈΡ‚Π° Π² {{$1}} участников. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ", + "components.locked_features_components.locked_invite_alert.message_link": "ΠΏΠΎΠ²Ρ‹ΡΡŒΡ‚Π΅ статус вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "components.locked_features_components.locked_invite_alert.message_part_2": " Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚ΡŒ большС участников.", + "views.client.popup.workspace_parameter.pages.workspace_members.link_to_console": "Π’ΠΈΠ΄Π΅Ρ‚ΡŒ всСх Ρ‡Π»Π΅Π½ΠΎΠ² ΠΌΠΎΠ΅ΠΉ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ Π½Π° консоли", + "components.locked_features_components.locked_invite_alert.message_magic_link": " ΠΎΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ΡΡŒ ΠΊ Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Ρƒ ΠΈΠ»ΠΈ администратору вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ.", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed": "ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ {{$1}} ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΡƒΠ΄Π°Π»Π΅Π½ΠΎ!", + "scenes.app.popup.appsparameters.pages.amazing_app_description": "ΠžΠΏΠΈΡˆΠΈΡ‚Π΅ вашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π² Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… словах", + "scenes.app.popup.appsparameters.pages.application_creator.title": "Новая интСграция", + "scenes.app.popup.appsparameters.pages.application_creator.checkbox": "Π― понимаю, Ρ‡Ρ‚ΠΎ Π²Π»Π°Π΄Π΅Π»Π΅Ρ† ΠΈ администраторы этой ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ смогут ΠΈΠ·ΠΌΠ΅Π½ΡΡ‚ΡŒ ΠΈ ΠΏΡƒΠ±Π»ΠΈΠΊΠΎΠ²Π°Ρ‚ΡŒ это ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅.", + "twake.application.access.title": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹Π΅ области для вашСго прилоТСния.", + "twake.application.access.no_default_scopes_available'": "Π£ этой ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠΈ Π½Π΅Ρ‚ доступа {{$1}}", + "scenes.app.popup.appsparameters.pages.application_editor.help_link": "докумСнтация ΠΏΠΎ API Twake", + "scenes.app.popup.appsparameters.pages.application_editor.help_text": "Если Π²Ρ‹ Π½Π΅ Π·Π½Π°Π΅Ρ‚Π΅, ΠΊΠ°ΠΊ ΠΈΡ… Π·Π°ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ, ΠΏΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ Π½Π° ", + "scenes.app.popup.appsparameters.pages.app.private_key": "Π—Π°ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΉ ΠΊΠ»ΡŽΡ‡", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed_error": "Ошибка ΠΏΡ€ΠΈ ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠΈ прилоТСния {{$1}}!", + "scenes.app.popup.appsparameters.pages.application_editor.application_published": "УспСшная заявка {{$1}}!", + "scenes.app.integrations_parameters.add_application": "Новая интСграция", + "scenes.app.integrations_parameters.company_applications_table.more_menu.developer_settings": "Настройки Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°", + "components.rich_text_editor.plugins.suggestions.loading": "Π˜Ρ‰Π΅Ρ‚Π΅ большС", + "components.open_desktop_popup.subtitle": "ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΠΎ Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΈ Twake", + "components.open_desktop_popup.open_here_link": "ВмСсто этого ΠΎΡ‚ΠΊΡ€ΠΎΠΉΡ‚Π΅ здСсь", + "molecules.download_banner.title": "ΠŸΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ максимум ΠΎΡ‚ Twake, Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚Π΅ Π½Π°ΡΡ‚ΠΎΠ»ΡŒΠ½ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ прямо сСйчас", + "molecules.download_banner.download_button": "Π‘ΠΊΠ°Ρ‡Π°Ρ‚ΡŒ Π½Π°ΡΡ‚ΠΎΠ»ΡŒΠ½ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "scenes.app.channelsbar.channel_copy_link": "Π‘ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ссылку Π½Π° ΠΊΠ°Π½Π°Π»", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.success.update": "УспСшно ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΎ", + "components.searchpopup.all": "ВсС", + "components.searchpopup.no_results_for": "НС Π½Π°ΠΉΠ΄Π΅Π½ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ² для", + "components.searchpopup.try_new_search": "Π˜ΡΠΊΠ°Ρ‚ΡŒ Π΅Ρ‰Π΅ Ρ€Π°Π·", + "components.searchpopup.chats": "Π§Π°Ρ‚Ρ‹", + "components.searchpopup.media": "МСдиа", + "components.searchpopup.files": "Π€Π°ΠΉΠ»Ρ‹", + "components.searchpopup.recent_chats": "НСдавниС Ρ‡Π°Ρ‚Ρ‹", + "components.searchpopup.recent_media": "ПослСдниС ΠΌΠ΅Π΄ΠΈΠ°", + "components.searchpopup.recent_files": "ПослСдниС Ρ„Π°ΠΉΠ»Ρ‹", + "components.searchpopup.recent_channels_and_contacts": "ПослСдниС ΠΊΠ°Π½Π°Π»Ρ‹ ΠΈ ΠΊΠΎΠ½Ρ‚Π°ΠΊΡ‚Ρ‹", + "components.searchpopup.header_title": "Поиск", + "components.searchpopup.scope.company": "Π²ΠΎ всСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "components.searchpopup.scope.channel": "Π² этом ΠΊΠ°Π½Π°Π»Π΅", + "components.searchpopup.channels": "ΠšΠ°Π½Π°Π»Ρ‹", + "components.searchpopup.messages": "БообщСния", + "components.searchpopup.start_search": "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ ΠΊΠ»ΡŽΡ‡Π΅Π²Ρ‹Π΅ слова, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π°Ρ‡Π°Ρ‚ΡŒ поиск.", + "components.searchpopup.see_more": "Π£Π·Π½Π°Ρ‚ΡŒ большС", + "scenes.client.channelbar.channelmemberslist.search_invite": "НайдитС ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ ΠΈ пригласитС ΠΈΡ… Π½Π° этот ΠΊΠ°Π½Π°Π»", + "scenes.client.channelbar.channelmemberslist.search_invite_notice": "На этом ΠΊΠ°Π½Π°Π»Π΅ ΠΌΠ°Π»ΠΎ участников. Π˜Ρ‰ΠΈΡ‚Π΅ ΠΈ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ°ΠΉΡ‚Π΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ ΠΏΠΎ элСктронной ΠΏΠΎΡ‡Ρ‚Π΅ ΠΈΠ»ΠΈ ΠΏΠΎ ΠΈΠΌΠ΅Π½ΠΈ.", + "scenes.client.channelbar.channelmemberslist.invite_email_button": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π½Π° ΠΊΠ°Π½Π°Π» Π² качСствС гостя", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π² ΠΊΠ°Π½Π°Π» ΠΈ Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ срСду Π² качСствС участника", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace_confirm": "ΠŸΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚ΡŒ {{$1}} Π² Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ срСду Π² качСствС участника?", + "scenes.client.channelbar.channelmemberslist.search_invite_type_email": "Π’Π²Π΅Π΄ΠΈΡ‚Π΅ Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ адрСс для ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΡ ΠΏΠΎ элСктронной ΠΏΠΎΡ‡Ρ‚Π΅.", + "scenes.client.channelbar.channelmemberslist.pending_section": "ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΠΈ, ΠΎΠΆΠΈΠ΄Π°ΡŽΡ‰ΠΈΠ΅ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΡ", + "scenes.client.channelbar.channelmemberslist.members_section": "ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΠΈ этого ΠΊΠ°Π½Π°Π»Π°", + "scenes.client.channelbar.channelmemberslist.not_members_section": "ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΠΈ Π²Π½Π΅ этого ΠΊΠ°Π½Π°Π»Π°", + "scenes.client.join_private_channel.info": "ΠšΠΎΠ½Ρ‚Π΅Π½Ρ‚ Π΄Π°Π½Π½ΠΎΠ³ΠΎ ΠΊΠ°Π½Π°Π»Π° ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ ΠΈΠ»ΠΈ Π½Π΅ сущСствуСт. Π‘Π²ΡΠΆΠΈΡ‚Π΅ΡΡŒ с участником ΠΊΠ°Π½Π°Π»Π°, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅.", + "scenes.client.join_public_channel": "ΠŸΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚Π΅ΡΡŒ ΠΊ этому ΠΊΠ°Π½Π°Π»Ρƒ", + "scenes.client.join_public_channel.info": "Π’Ρ‹ Π½Π΅ ΡΠ²Π»ΡΠ΅Ρ‚Π΅ΡΡŒ участником этого ΠΊΠ°Π½Π°Π»Π°. НаТмитС сюда, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π°Ρ‡Π°Ρ‚ΡŒ бСсСду.", + "general.yes": "Π”Π°", + "general.no": "НСт", + "components.open_desktop_popup.open_here_link_forever": "Π‘ΠΎΠ»ΡŒΡˆΠ΅ Π½Π΅ ΠΎΡ‚ΠΊΡ€Ρ‹Π²Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅", + "components.channel_attachement_list.medias": "МСдиа", + "components.channel_attachement_list.files": "Π€Π°ΠΉΠ»Ρ‹", + "components.channel_attachement_list.title": "МСдиа ΠΈ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Ρ‹", + "components.channel_attachement_list.nothing_found": "Π—Π΄Π΅ΡΡŒ ΠΏΠΎΠΊΠ° пусто", + "molecules.message_quote.deleted": "Π­Ρ‚ΠΎ сообщСниС Π±Ρ‹Π»ΠΎ ΡƒΠ΄Π°Π»Π΅Π½ΠΎ", + "scenes.apps.messages.jump": "ΠŸΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ ΠΊ ΡΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΡŽ", + "components.channel_attachement_list.open": "ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ Π³Π°Π»Π΅Ρ€Π΅ΡŽ", + "scenes.apps.account.on_console": "Π§Ρ‚ΠΎΠ±Ρ‹ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π³Π»ΠΎΠ±Π°Π»ΡŒΠ½Ρ‹Π΅ настройки ΡƒΡ‡Π΅Ρ‚Π½ΠΎΠΉ записи, Π½Π°ΠΆΠΌΠΈΡ‚Π΅ Β«ΠŸΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ ΠΊ консоли».", + "scenes.apps.account.assistant.title": "АссистСнт", + "scenes.apps.account.assistant.description": "АссистСнт Twake ΠΎΡ€Π³Π°Π½ΠΈΠ·ΡƒΠ΅Ρ‚ Π²Π°ΡˆΡƒ Ρ€Π°Π±ΠΎΡ‚Ρƒ ΠΈ ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠΈΡ‚ ΡƒΠΌΠ½Ρ‹Π΅ ярлыки ΠΈ дСйствия Π² Ρ‚Π΅Ρ‡Π΅Π½ΠΈΠ΅ дня. АссистСнт являСтся Ρ‡Π°ΡΡ‚ΡŒΡŽ ΠΈΠ½ΠΈΡ†ΠΈΠ°Ρ‚ΠΈΠ²Ρ‹ Work@Home https://workathome.linagora.com/ ΠΈ Π½Π° Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚ тСстируСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ Linagora ΠΈ находится Π½Π° этапС обучСния. Π­Ρ‚ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ отправляСм Π΄Π°Π½Π½Ρ‹Π΅ ΠΎΠ± использовании Twake, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ±ΡƒΡ‡ΠΈΡ‚ΡŒ Π±ΡƒΠ΄ΡƒΡ‰ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ ассистСнта.", + "scenes.apps.account.assistant.share.nothing": "НС Π΄Π΅Π»ΠΈΡ‚ΡŒΡΡ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠ΅ΠΉ с ассистСнтом (ΠΎΡ‚ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ)", + "scenes.apps.account.assistant.share.all": "Π”Π΅Π»ΠΈΡ‚ΡŒΡΡ всСм, Π²ΠΊΠ»ΡŽΡ‡Π°Ρ сообщСния ΠΈ содСрТимоС Ρ„Π°ΠΉΠ»ΠΎΠ²", + "scenes.apps.account.assistant.share.metadata": "Π”Π΅Π»ΠΈΡ‚ΡŒΡΡ ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹ΠΌΠΈ, Π½ΠΎ Π½Π΅ содСрТимым", + "scenes.apps.account.assistant.success": "Настройки ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½Ρ‹.", + "components.message_seen_by.title": "ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π²ΠΈΠ΄Π΅Π»ΠΈ сообщСниС", + "components.message_seen_by.none_seen_it": "Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅ Π΅Ρ‰Π΅ Π½ΠΈΠΊΡ‚ΠΎ Π½Π΅ Π²ΠΈΠ΄Π΅Π»", + "components.message_seen_by.btn": "Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ", + "molecules.quoted_content.attachements": "{{$1}} Π²Π»ΠΎΠΆΠ΅Π½ΠΈΠΉ", + "scenes.apps.messages.message.user_deactivated": "Π’Ρ‹ просматриваСтС Π°Ρ€Ρ…ΠΈΠ² Π΄Π΅Π°ΠΊΡ‚ΠΈΠ²ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°", + "general.user.deactivated": "ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ большС Π½Π΅ состоит Π² этой ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ", + "general.user.connected": "Онлайн", + "scenes.app.popup.userparameter.pages.email_notif_delay_never": "Никогда", + "scenes.app.popup.userparameter.pages.email_notif_delay_quarter_hour": "15 ΠΌΠΈΠ½ΡƒΡ‚", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_day": "1 дСнь", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_hour": "1 час", + "scenes.app.popup.userparameter.pages.notification_sound.defaut": "По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ", + "scenes.app.popup.userparameter.pages.notification_sound.none": "Никто", + "scenes.client.channelbar.readonly_channel.checkbox": "ΠžΠ³Ρ€Π°Π½ΠΈΡ‡ΠΈΡ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ записи", + "scenes.apps.messages.message.forward": "ΠŸΠ΅Ρ€Π΅ΡΠ»Π°Ρ‚ΡŒ", + "scenes.apps.messages.message.forward.title": "ΠŸΠ΅Ρ€Π΅ΡΠ»Π°Ρ‚ΡŒ сообщСниС", + "scenes.apps.messages.message.forward.comment": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ сообщСниС", + "scenes.apps.messages.message.forward.confirm": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ Π² {{$1}} ΠΊΠ°Π½Π°Π»(ΠΎΠ²)", + "scenes.apps.messages.message.forward.send": "Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅ ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½ΠΎ", + "components.channelselector.title": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ ΠΊΠ°Π½Π°Π»Ρ‹", + "components.channelselector.confirm": "Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ ${{1}} ΠΊΠ°Π½Π°Π»Π°(ΠΎΠ²)", + "components.channelselector.search": "Поиск ΠΊΠ°Π½Π°Π»ΠΎΠ² ΠΈ обсуТдСний", + "scenes.app.channelsbar.channel_access": "Доступ ΠΊ ΠΊΠ°Π½Π°Π»Ρƒ", + "scenes.app.channelsbar.channel_access.save": "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ настройки доступа", + "scenes.app.channelsbar.channel_access.readonly": "Канал Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для чтСния", + "scenes.app.channelsbar.channel_access.readonly.info": "Π Π°Π·Ρ€Π΅ΡˆΠΈΡ‚ΡŒ ΠΏΠΈΡΠ°Ρ‚ΡŒ Π² ΠΊΠ°Π½Π°Π» Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΌΠΎΠ΄Π΅Ρ€Π°Ρ‚ΠΎΡ€Π°ΠΌ, администраторам ΠΈ Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π°ΠΌ.", + "scenes.app.channelsbar.channel_access.visibility": "ΠŸΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΉ доступ", + "scenes.app.channelsbar.channel_access.visibility.info": "ΠŸΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒΡΡ ΠΌΠΎΠΆΠ΅Ρ‚ любой ΠΆΠ΅Π»Π°ΡŽΡ‰ΠΈΠΉ, ΠΊΡ€ΠΎΠΌΠ΅ гостСй.", + "scenes.app.channelsbar.channel_access.default": "АвтоматичСскоС ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅", + "scenes.app.channelsbar.channel_access.default.info": "НовыС участники Π±ΡƒΠ΄ΡƒΡ‚ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒΡΡ Π² ΠΊΠ°Π½Π°Π» автоматичСски.", + "scenes.app.channelsbar.channel_information": "Π Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ ΠΎ ΠΊΠ°Π½Π°Π»Π΅", + "scenes.app.channelsbar.channel_information.logo.add": "Π—Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅", + "scenes.app.channelsbar.channel_information.logo.remove": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅", + "scenes.app.channelsbar.channel_information.name": "НазваниС ΠΊΠ°Π½Π°Π»Π°", + "scenes.app.channelsbar.channel_information.description": "ОписаниС ΠΊΠ°Π½Π°Π»Π°", + "scenes.app.channelsbar.channel_information.description.placeholder": "ОписаниС ΠΊΠ°Π½Π°Π»Π°; Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ markdown.", + "scenes.app.channelsbar.channel_information.group": "Π“Ρ€ΡƒΠΏΠΏΠ° ΠΊΠ°Π½Π°Π»ΠΎΠ²", + "scenes.app.channelsbar.channel_information.group.none": "НС Π²Ρ‹Π±Ρ€Π°Π½ΠΎ", + "scenes.app.channelsbar.channel_information.group.new": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Π³Ρ€ΡƒΠΏΠΏΡƒ", + "scenes.app.channelsbar.channel_information.group.save": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π² Π³Ρ€ΡƒΠΏΠΏΡƒ ΠΊΠ°Π½Π°Π»ΠΎΠ² {{$1}}", + "scenes.app.channelsbar.channel_information.group.save_none": "НС Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ Π² Π³Ρ€ΡƒΠΏΠΏΡƒ ΠΊΠ°Π½Π°Π»ΠΎΠ²", + "scenes.app.channelsbar.channel_information.save": "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ измСнСния", + "components.invitation.invitation_channels.button": "ΠŸΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚ΡŒ Π² ΠΊΠ°Π½Π°Π»Ρ‹", + "components.invitation.workspace_link.button": "ΠšΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ", + "scenes.client.channelbar.channelmemberslist.invite_to_workspace": "ΠŸΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚ΡŒ {{$1}} Π² Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ срСду ➑", + "components.invitation.reached_limit.text": "Π’Ρ‹ достигли максимального количСства ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ. Π Π°ΡΡˆΠΈΡ€ΡŒΡ‚Π΅ подписку ΠΈΠ»ΠΈ Π΄ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ этих ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ Π² качСствС гостСй", + "components.invitation.allow_anyone_by_email.text": "Π Π°Π·Ρ€Π΅ΡˆΠΈΡ‚ΡŒ всСм ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡΠΌ с Π΄ΠΎΠΌΠ΅Π½ΠΎΠΌ @{{$1}} ΠΏΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΡΡ‚ΡŒΡΡ ΠΊ этой Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСдС", + "components.invitation.invitation_input_list.add": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ", + "components.invitation.invitation_input_list.member": "Участник", + "components.invitation.invitation_input_list.guest": "Π“ΠΎΡΡ‚ΡŒ", + "components.invitation.invitation_input_list.placeholder": "НачнитС Π²Π²ΠΎΠ΄ΠΈΡ‚ΡŒ адрСс ΠΏΠΎΡ‡Ρ‚Ρ‹", + "components.invitation.invitation_sent.title": "ΠŸΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΡ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½Ρ‹", + "components.invitation.invitation_sent.subtitle_status": "Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΎΡ‚ΡΠ»Π΅ΠΆΠΈΠ²Π°Ρ‚ΡŒ статус ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΡ здСсь:", + "components.invitation.invitation_sent.subtitle_location": "Настройки Ρ€Π°Π±ΠΎΡ‡Π΅ΠΉ срСды > Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ участниками", + "components.invitation.invitation_sent.link": "ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ статус ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΡ", + "components.invitation.invitation_sent.button": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ Π΅Ρ‰Π΅ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΡ", + "components.invitation.invitation_target.invite_as_guests": "ΠŸΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚ΡŒ всСх Π² качСствС гостСй", + "components.invitation.invitation_target.invite_as_members": "ΠŸΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚ΡŒ всСх Π² качСствС участников", + "components.invitation.invitation_target.channels_button": "Π’Ρ‹Π±Ρ€Π°Ρ‚ΡŒ ΠΊΠ°Π½Π°Π»Ρ‹", + "components.invitation.workspace_link.text": "Бсылка для ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΡ Π² Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ срСду", + "components.invitation.title": "ΠŸΡ€ΠΈΠ³Π»Π°ΡΠΈΡ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ Π² {{$1}}", + "components.invitation.bulk_invitation": "НСсколько адрСсов", + "components.invitation.button": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΡ", + "scenes.client.readonly.info": "Π­Ρ‚ΠΎΡ‚ ΠΊΠ°Π½Π°Π» доступСн Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для чтСния, Π½ΠΎ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΎΡΡ‚Π°Π²Π»ΡΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΈ.", + "scenes.app.channelsbar.channel_information.group.title": "Π“Ρ€ΡƒΠΏΠΏΡ‹ ΠΊΠ°Π½Π°Π»ΠΎΠ²", + "components.invitation.custom_role_invitation": "Π‘Ρ‚Π°Π½Π΄Π°Ρ€Ρ‚Π½ΠΎΠ΅ ΠΏΡ€ΠΈΠ³Π»Π°ΡˆΠ΅Π½ΠΈΠ΅", + "components.invitation.link": "Бсылка" +} diff --git a/twake/frontend/public/locales/si.json b/twake/frontend/public/locales/si.json new file mode 100644 index 00000000..a45acaaf --- /dev/null +++ b/twake/frontend/public/locales/si.json @@ -0,0 +1,1008 @@ +{ + "general.save": "ΰ·ƒΰ·”ΰΆ»ΰΆšΰ·’ΰΆ±ΰ·ŠΰΆ±", + "general.close": "ΰ·€ΰ·ƒΰΆ±ΰ·ŠΰΆ±", + "general.help.documentation": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ½ΰ·šΰΆ›ΰΆ±ΰΆΊ", + "general.remove": "ΰΆ‰ΰ·€ΰΆ­ΰ·Š ࢚ࢻࢱ්ࢱ", + "general.cancel": "ΰΆ…ΰ·€ΰΆ½ΰΆ‚ΰΆœΰ·”", + "general.continue": "ΰΆ‰ΰΆ―ΰ·’ΰΆ»ΰ·’ΰΆΊΰΆ§", + "general.back": "ΰΆ†ΰΆ΄ΰ·ƒΰ·”", + "general.help": "ΰΆ‹ΰΆ―ΰ·€ΰ·Š", + "general.send": "ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊ ΰΆΊΰ·€ΰΆ±ΰ·ŠΰΆ±", + "general.create": "ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "general.edit": "ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ", + "general.help.support": "සහාࢺ", + "scenes.app.workspaces.create_company.group_data.group_type.other_group": "ΰ·€ΰ·™ΰΆ±ΰΆ­ΰ·Š", + "scenes.app.workspaces.create_company.group_data.group_size": "ΰ·ƒΰΆΈΰ·–ΰ·„ΰΆΊΰ·š ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆΈΰ·ΰΆ«ΰΆΊ", + "general.update": "ΰΆΊΰ·ΰ·€ΰΆ­ΰ·ŠΰΆšΰ·ΰΆ½", + "general.archive": "ΰ·ƒΰΆ‚ΰΆ»ΰΆšΰ·Šβ€ΰ·‚ΰΆ«ΰΆΊ", + "scenes.apps.parameters.workspace_sections.members": "ΰ·ƒΰ·„ΰΆ·ΰ·ΰΆœΰ·“ΰ·€ΰΆ±ΰ·ŠΰΆ±ΰΆ±ΰ·Š", + "scenes.app.workspaces.create_company.group_data.group_main_activity.administration": "ࢴࢻිࢴාࢽࢱࢺ", + "scenes.app.header.disconnected.reload": "ΰΆΊΰ·…ΰ·’ ΰΆ΄ΰ·–ΰΆ»ΰΆ«ΰΆΊ", + "scenes.apps.calendar.event_edition.checkbox_all_day": "ΰΆ―ΰ·€ΰ·ƒ ࢴුࢻා", + "scenes.apps.drive.navigators.navigator_content.files": "ΰΆœΰ·œΰΆ±ΰ·”", + "scenes.app.workspaces.create_company.group_data.group_size.500_1000": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š 500 - 999", + "scenes.apps.drive.right_preview.public_link": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·ƒΰ·’ΰΆ―ΰ·ŠΰΆ° සࢢැࢳිࢺ", + "scenes.apps.messages.left_bar.stream_modal.placeholder_name": "ΰΆ±ΰΆΈ", + "scenes.apps.messages.left_bar.stream.add_to_favorites": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰΆ­ΰΆΈΰΆΊΰΆ±ΰ·ŠΰΆ§ ΰΆ‘ΰΆšΰΆ­ΰ·”ΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.messages.left_bar.stream.remove_from_favorites": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰΆ­ΰΆΈΰΆΊΰΆ±ΰ·ŠΰΆœΰ·™ΰΆ±ΰ·Š ΰΆ‰ΰ·€ΰΆ­ΰ·ŠΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.messages.left_bar.stream.notifications": "ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·Š...", + "scenes.apps.messages.left_bar.stream.notifications.all": "ΰΆ•ΰΆ±ΰ·‘ΰΆΈ ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊΰΆšΰ·Š", + "general.add": "ΰΆ‘ΰΆšΰΆ­ΰ·”", + "general.connexion_status.connecting": "ΰΆΊΰ·…ΰ·’ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ° ΰ·€ΰ·™ΰΆΈΰ·’ΰΆ±ΰ·Šβ€¦", + "scenes.app.workspaces.create_company.group_data.group_size.1000_5000": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š 1000 - 4999", + "scenes.app.workspaces.create_company.group_data.group_size.5000_more": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š 5000 ΰΆ§ වࢩා", + "scenes.app.workspaces.create_company.group_data.group_main_activity.food": "ࢆහාࢻ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.other": "ΰ·€ΰ·™ΰΆ±ΰΆ­ΰ·Š", + "components.application.messages": "ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©", + "scenes.app.workspaces.create_company.group_data.group_main_activity": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ°ΰ·ΰΆ± ΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰ·ΰΆšΰ·ΰΆ»ΰΆšΰΆΈ", + "scenes.app.workspaces.create_company.group_data": "ΰΆ±ΰ·€ ΰ·ƒΰΆΈΰ·–ΰ·„ΰΆΊ ΰ·€ΰ·’ΰΆ±ΰ·Šβ€ΰΆΊΰ·ΰ·ƒΰΆœΰΆ­ ࢚ࢻࢱ්ࢱ", + "scenes.app.workspaces.create_company.group_data.group_type.university_school": "ΰ·ƒΰΆ»ΰ·ƒΰ·€ΰ·’ΰΆΊ හෝ ࢴාසැࢽ", + "scenes.apps.calendar.event_edition.deadline_tag": "ΰΆ±ΰ·’ΰΆΊΰΆΈΰ·’ΰΆ­ ࢚ාࢽࢺ", + "scenes.apps.messages.left_bar.stream.notifications.me": "{{$1}} ΰΆ΄ΰΆΈΰΆ«ΰ·’", + "general.retry": "ΰΆΊΰ·…ΰ·’ ΰΆ‹ΰΆ­ΰ·Šΰ·ƒΰ·ΰ·„ΰΆΊ", + "scenes.app.workspaces.create_company.group_data.group_type": "ΰ·ƒΰΆΈΰ·–ΰ·„ΰΆΊΰ·š ΰ·€ΰΆ»ΰ·ŠΰΆœΰΆΊ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.business_services": "ΰ·€ΰ·Šβ€ΰΆΊΰ·ΰΆ΄ΰ·ΰΆ»ΰ·’ΰΆš ΰ·ƒΰ·šΰ·€ΰ·", + "components.drive_dropzone.uploading": "ΰΆ‹ΰΆ©ΰ·”ΰΆœΰΆ­ ΰ·€ΰ·™ΰΆΈΰ·’ΰΆ±ΰ·Š...", + "scenes.app.header.alt_notifications": "ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·Š", + "scenes.apps.calendar.calendar.week_btn": "ΰ·ƒΰΆ­ΰ·’ΰΆΊ", + "scenes.apps.drive.navigators.new_file": "ΰΆ±ΰ·€ ΰΆœΰ·œΰΆ±ΰ·”ΰ·€", + "scenes.apps.messages.left_bar.stream.notifications.mentions": "{{$1}}, {{$2}} ΰ·ƒΰ·„ {{$3}}", + "application.load.longer": "ΰ·ƒΰ·šΰ·€ΰ·ΰΆ―ΰ·ΰΆΊΰΆšΰΆΊ ΰΆ΄ΰ·’ΰ·…ΰ·’ΰΆ­ΰ·”ΰΆ»ΰ·” ΰΆ―ΰ·“ΰΆΈΰΆ§ ΰΆ…ΰΆ΄ΰ·šΰΆšΰ·Šβ€ΰ·‚ΰ· ΰΆšΰ·…ΰ·ΰΆ§ වࢩා ࢚ාࢽࢺ්࢚ ΰΆœΰΆ­ΰΆšΰΆ»ΰΆΊΰ·’, ΰΆ΄ΰ·’ΰΆ§ΰ·”ΰ·€ ΰΆΊΰ·…ΰ·’ ΰΆ΄ΰ·–ΰΆ»ΰΆ«ΰΆΊ ࢚ࢻࢱ්ࢱ හෝ ΰΆ»ΰ·ΰΆ³ΰ·™ΰΆ±ΰ·ŠΰΆ±...", + "scenes.app.workspaces.create_company.group_data.group_type.public_organization": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·ƒΰ·’ΰΆ―ΰ·ŠΰΆ° සࢂවිࢰාࢱࢺ", + "scenes.app.workspaces.create_company.group_data.group_type.society_club_charity": "ΰ·ƒΰΆΈΰ·’ΰΆ­ΰ·’ΰΆΊ, සࢸා࢒ࢺ හෝ ΰΆ΄ΰ·”ΰΆ«ΰ·Šβ€ΰΆΊΰ·ΰΆ­ΰΆ±ΰΆΊ", + "scenes.app.workspaces.create_company.group_data.group_size.less_3": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š 4ΰΆ§ ΰΆ…ΰΆ©ΰ·”", + "scenes.app.workspaces.create_company.group_data.group_size.4_10": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š 4 - 10", + "scenes.app.workspaces.create_company.group_data.group_size.10_50": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š 11 - 49", + "scenes.app.workspaces.create_company.group_data.group_size.50_100": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š 50 - 99", + "scenes.app.workspaces.create_company.group_data.group_size.100_500": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š 100 - 499", + "scenes.apps.messages.messages": "ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©", + "scenes.app.header.disconnected": "ΰΆ”ΰΆΆ ΰ·€ΰ·’ΰ·ƒΰΆ±ΰ·ŠΰΆ°ΰ·’ΰ·€ ΰΆ‡ΰΆ­", + "scenes.apps.calendar.event_edition.title_confidentiality": "ΰ·€ΰ·’ΰ·ΰ·Šΰ·€ΰ·ƒΰΆ±ΰ·“ΰΆΊΰ·€", + "scenes.apps.calendar.event_view.article_until": "ΰ·€ΰ·™ΰΆ­", + "scenes.apps.calendar.calendar_modal.participants": "ΰ·ƒΰ·„ΰΆ·ΰ·ΰΆœΰ·“ΰ·€ΰΆ±ΰ·ŠΰΆ±ΰΆ±ΰ·Š", + "scenes.apps.calendar.calendar_modal.placeholder": "ΰΆ±ΰΆΈ", + "scenes.apps.calendar.left.calendars": "ΰΆ―ΰ·’ΰΆ± ΰΆ―ΰ·ƒΰ·”ΰΆ±ΰ·Š", + "scenes.apps.drive.left.search": "ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.drive.navigators.navigator_content.directory_name": "ΰΆ±ΰ·ΰΆΈΰ·ΰ·€ΰΆ½ΰ·’ΰΆΊΰ·š ΰΆ±ΰΆΈ", + "scenes.apps.drive.navigators.new_file.untitled": "ΰ·ƒΰ·’ΰΆ»ΰ·ΰ·ƒΰ·’ΰΆΊΰΆšΰ·Š ࢱැࢭ", + "scenes.apps.drive.navigators.new_file.create_file.type": "ΰ·€ΰΆ»ΰ·ŠΰΆœΰΆΊ", + "scenes.apps.drive.preview_bloc.operations_download": "ࢢා࢜ࢱ්ࢱ", + "scenes.apps.drive.right_preview.operations_restore": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ­ΰ·Šβ€ΰΆΊΰΆ»ΰ·ŠΰΆ΄ΰΆ«ΰΆΊ", + "scenes.apps.parameters.group_sections.apps": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š", + "scenes.apps.account.account.menu_title": "ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈ", + "scenes.apps.account.languages.menu_title": "ࢷාෂාව", + "scenes.apps.account.account.firstname": "ΰΆ΄ΰ·…ΰΆΈΰ·” ΰΆ±ΰΆΈ", + "scenes.apps.account.account.lastname": "ΰΆ…ΰΆœ ΰΆ±ΰΆΈ", + "scenes.apps.account.account.username": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆš ࢱාࢸࢺ", + "scenes.apps.account.account.change_username": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ…ΰΆ±ΰΆ±ΰ·Šβ€ΰΆΊ ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆ±ΰ·ΰΆΈΰΆΊ ΰ·€ΰ·™ΰΆ±ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±.", + "scenes.apps.account.account.emails": "ΰ·€ΰ·’-ࢭැࢴැࢽ්", + "scenes.apps.account.account.email_add": "ΰΆ±ΰ·€ ΰ·€ΰ·’-ࢭැࢴෑࢽ ΰΆ‘ΰΆšΰΆ­ΰ·”ΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.account.account.password": "ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊ", + "scenes.apps.account.languages.text": "ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š ࢷාෂාව ΰ·€ΰ·™ΰΆ±ΰ·ƒΰ·Š ࢚ࢻࢱ්ࢱ.", + "scenes.apps.account.notifications.title": "ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·Š", + "scenes.apps.account.notifications.keywords_subtitle": "ΰΆΈΰ·–ΰΆ½ΰΆ΄ΰΆ―", + "scenes.apps.account.notifications.disturb_option_b": " ΰ·ƒΰ·„ ", + "scenes.apps.account.notifications.privacy_subtitle": "ΰΆ΄ΰ·žΰΆ―ΰ·ŠΰΆœΰΆ½ΰ·’ΰΆšΰΆ­ΰ·Šΰ·€ΰΆΊ", + "scenes.apps.account.account.password_modal.bad_password": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ― ࢱො࢜ැࢽࢴේ හෝ ࢒වා ࢉࢭා ΰΆšΰ·™ΰΆ§ΰ·’ ΰΆΊ. ΰΆ…ΰ·€ΰΆΈ ΰ·€ΰ·ΰΆΊΰ·™ΰΆ±ΰ·Š ΰΆ…ΰΆšΰ·”ΰΆ»ΰ·” 8 ්࢚ ΰ·ƒΰ·„ΰ·’ΰΆ­ ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊΰΆšΰ·Š ࢺොࢯࢱ්ࢱ.", + "scenes.apps.account.account.password_modal.old_password": "ΰ·€ΰΆ­ΰ·ŠΰΆΈΰΆ±ΰ·Š ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊ", + "scenes.apps.account.account.password_modal.password": "ΰΆ±ΰ·€ ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊ", + "scenes.apps.account.account.email_add_modal.invalid_code": "ΰΆΈΰ·™ΰΆΈ ࢚ේࢭࢺ ΰ·€ΰΆ½ΰΆ‚ΰΆœΰ·” ΰΆ±ΰ·œΰ·€ΰ·š", + "scenes.apps.account.account.password_modal.bad_old_password": "ΰΆ΄ΰΆ»ΰΆ« ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊ ࢱිවැࢻࢯි ΰΆ±ΰ·œΰ·€ΰ·š.", + "scenes.apps.account.account.main_email": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ°ΰ·ΰΆ± ΰ·€ΰ·’-ࢭැࢴෑࢽ", + "scenes.apps.account.notifications.devices_subtitle": "ΰΆ‹ΰΆ΄ΰ·ΰΆ‚ΰΆœ ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·Š", + "scenes.apps.account.account.logout": "ΰΆ±ΰ·’ΰΆšΰ·ŠΰΆΈΰ·™ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.account.notifications.mail_subtitle": "ΰ·€ΰ·’-ࢭැࢴැࢽ් ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·Š", + "scenes.apps.tasks.no_connectors_menu_text": "ΰΆ―ΰ·’ΰΆ± ΰΆ―ΰ·ƒΰ·”ΰΆ± ࢚ࢧ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ° ΰΆšΰ·… ΰ·„ΰ·ΰΆšΰ·’ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆšΰΆΊΰΆšΰ·Š ΰΆ”ΰΆΆ ΰ·ƒΰΆ­ΰ·”ΰ·€ ࢱැࢭ.", + "scenes.login.create_account.username_already_exist": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆš ࢱාࢸࢺ ࢯැࢱࢧࢸࢭ් ΰΆ·ΰ·ΰ·€ΰ·’ΰΆ­ΰΆΊΰ·š ΰΆ‡ΰΆ­", + "scenes.login.create_account.fill_in_email": "ࢱිවැࢻࢯි ΰ·€ΰ·’-ΰΆ­ΰ·ΰΆ΄ΰ·‘ΰΆ½ΰΆšΰ·’ΰΆ±ΰ·Š ΰΆ”ΰΆΆΰΆœΰ·š ΰ·€ΰ·’-ࢭැࢴෑࢽ ΰΆ΄ΰ·’ΰΆ»ΰ·€ΰ·’ΰΆΊ ΰΆΊΰ·”ΰΆ­ΰ·”ΰΆΊ", + "scenes.login.create_account.email": "ΰ·€ΰ·’-ࢭැࢴෑࢽ", + "scenes.login.create_account.too_short_password": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊΰ·š ΰΆ…ΰ·€ΰΆΈ ΰ·€ΰ·ΰΆΊΰ·™ΰΆ±ΰ·Š ΰΆ…ΰΆšΰ·”ΰΆ»ΰ·” 8 ්࢚ ΰ·€ΰΆ­ΰ·Š ΰΆ­ΰ·’ΰΆΆΰ·’ΰΆΊ ΰΆΊΰ·”ΰΆ­ΰ·”ΰΆΊ.", + "scenes.login.create_account.firstname": "ΰΆ΄ΰ·…ΰΆΈΰ·” ΰΆ±ΰΆΈ", + "scenes.login.create_account.newsletter": "ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š ΰΆ΄ΰ·’ΰ·…ΰ·’ΰΆΆΰΆ³ ΰΆ­ΰ·œΰΆ»ΰΆ­ΰ·”ΰΆ»ΰ·” ࢽࢢා ࢜ࢱ්ࢱ", + "scenes.login.create_account.lastname": "ΰΆ…ΰΆœ ΰΆ±ΰΆΈ", + "scenes.apps.parameters.workspace_sections.members.invite": "ΰΆ±ΰ·€ ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·™ΰΆšΰ·”ΰΆ§ ࢆࢻාࢰࢱා", + "scenes.apps.parameters.workspace_sections.members.invite_btn": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ· ΰΆ‘ΰΆšΰ·ŠΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.tasks.connectors_menu": "ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆš...", + "scenes.apps.tasks.task_status.current": "ΰ·€ΰΆ­ΰ·ŠΰΆΈΰΆ±ΰ·Š", + "scenes.apps.tasks.task.edit.dates": "ΰΆ―ΰ·’ΰΆ±", + "scenes.login.footer.go_to_twake": "twakeapp.com ΰ·€ΰ·™ΰΆ­ ࢺࢱ්ࢱ", + "scenes.login.footer.branding": "ΰΆ”ΰΆΆ ΰ·ƒΰ·’ΰΆ§ΰ·’ΰΆ±ΰ·ŠΰΆ±ΰ·š {{$1}} ({{$2}}) ΰΆ΄ΰ·žΰΆ―ΰ·ŠΰΆœΰΆ½ΰ·’ΰΆš ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š ΰ·ƒΰ·šΰ·€ΰ·ΰΆ―ΰ·ΰΆΊΰΆšΰΆΊΰΆš ΰΆΊ. ", + "scenes.login.create_account.title": "ΰΆ±ΰ·€ ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈΰΆšΰ·Š ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "scenes.login.forgot_password.title": "ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊ ΰΆ…ΰΆΈΰΆ­ΰΆš වුࢫා ΰΆ―?", + "scenes.login.forgot_password.email_to_recover": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ­ΰ·’ΰ·ƒΰ·ΰΆ°ΰΆ±ΰΆΊ සࢳහා ΰ·€ΰ·’-ࢭැࢴෑࢽ", + "scenes.login.forgot_password.mail_doesnt_exist": "ΰΆΈΰ·™ΰΆΈ ΰ·€ΰ·’-ࢭැࢴෑࢽ ΰΆ±ΰ·œΰΆ΄ΰ·€ΰΆ­ΰ·“", + "scenes.login.forgot_password.text2": "ΰΆ”ΰΆΆΰΆ§ ΰΆ…ΰΆ‚ΰΆš 9 ࢚ ࢚ේࢭࢺ්࢚ ࢽැࢢෙࢱු ΰΆ‡ΰΆ­. ΰΆ‰ΰΆ―ΰ·’ΰΆ»ΰ·’ΰΆΊΰΆ§ ࢺාࢸࢧ ΰΆ΄ΰ·„ΰΆ­ ΰΆšΰ·Šΰ·‚ΰ·šΰΆ­ΰ·Šβ€ΰΆ»ΰΆΊΰ·™ΰ·„ΰ·’ ΰΆ‘ΰΆΊ ΰΆ‡ΰΆ­ΰ·”ΰΆ½ΰ·Š ࢚ࢻࢱ්ࢱ.", + "scenes.login.forgot_password.invalid_code": "ΰΆΈΰ·™ΰΆΈ ࢚ේࢭࢺ ΰ·€ΰΆ½ΰΆ‚ΰΆœΰ·” ΰΆ±ΰ·œΰ·€ΰ·š.", + "scenes.login.create_account.email_used": "ΰΆΈΰ·™ΰΆΈ ΰ·€ΰ·’-ࢭැࢴෑࢽ ࢯැࢱࢧࢸࢭ් ΰΆ·ΰ·ΰ·€ΰ·’ΰΆ­ΰΆΊΰ·š ΰΆ‡ΰΆ­.", + "scenes.login.forgot_password.text3": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈ සࢳහා ΰΆ±ΰ·€ ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊΰΆšΰ·Š ΰΆ‡ΰΆ­ΰ·”ΰΆ½ΰ·Š ࢚ࢻࢱ්ࢱ.", + "scenes.login.forgot_password.password": "ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊ", + "scenes.apps.parameters.workspace_sections.members.members": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š", + "scenes.login.create_account.username": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆš ࢱාࢸࢺ", + "scenes.login.create_account.fill_in_username": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆš ࢱාࢸࢺ ΰΆ΄ΰ·’ΰΆ»ΰ·€ΰ·’ΰΆΊ ΰΆΊΰ·”ΰΆ­ΰ·”ΰΆΊ", + "scenes.apps.account.notifications.sound": "ශࢢ්ࢯ ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈ", + "scenes.apps.tasks.connectors_search_menu": "ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆš ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ±...", + "scenes.app.channelsbar.currentuser.update": "ΰΆΊΰ·ΰ·€ΰΆ­ΰ·ŠΰΆšΰ·ΰΆ½", + "scenes.app.popup.appsparameters.pages.title_informations": "ΰΆΈΰ·–ΰΆ½ΰ·’ΰΆš ΰΆ­ΰ·œΰΆ»ΰΆ­ΰ·”ΰΆ»ΰ·”", + "scenes.apps.messages.message.activity_message.a_created_channel_connector": "{{$1}} ΰΆ±ΰ·€ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆšΰΆΊΰΆšΰ·Š {{$2}} ΰΆ§ ΰΆ‘ΰΆšΰΆ­ΰ·” ΰΆšΰ·…ΰ·", + "general.user.role.company.admin": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰΆ΄ΰΆ»ΰ·’ΰΆ΄ΰ·ΰΆ½ΰΆš", + "scenes.apps.messages.input.attach_file.from_computer": "ΰΆ΄ΰΆ»ΰ·’ΰΆœΰΆ«ΰΆšΰΆΊΰ·™ΰΆ±ΰ·Š", + "scenes.app.popup.workspace.create_temp": "ΰΆ­ΰ·ΰ·€ΰΆšΰ·ΰΆ½ΰ·’ΰΆš ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈΰΆšΰ·Š ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.popup.appsparameters.pages.apps_connectors_small_text": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š ΰ·ƒΰ·„ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆš ΰΆšΰ·…ΰΆΈΰΆ±ΰ·ΰΆšΰΆ»ΰΆ«ΰΆΊ ࢚ࢻࢱ්ࢱ.", + "scenes.app.popup.workspaceparameter.pages.apps_company_small_text": "ΰΆ”ΰΆΆΰΆœΰ·š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š", + "scenes.app.popup.workspaceparameter.pages.company_name_description": "ΰΆΈΰ·™ΰΆΈ ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰΆ±ΰΆΈ ΰ·€ΰ·™ΰΆ±ΰ·ƒΰ·Š ࢚ࢻࢱ්ࢱ", + "app.name.twake_drive": "ΰΆ½ΰ·šΰΆ›ΰΆ±", + "components.calendar.repetition.everyday": "ࢯිࢱࢴࢭා", + "components.calendar.repetition.weeks": "ΰ·ƒΰΆ­ΰ·’(ΰΆΊ)", + "scenes.app.channelsbar.modify_channel_menu": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ", + "scenes.app.channelsbar.guest_management": "ΰΆ…ΰΆΈΰ·”ΰΆ­ΰ·ŠΰΆ­ΰΆ±ΰ·Š ΰΆšΰ·…ΰΆΈΰΆ±ΰ·ΰΆšΰΆ»ΰΆ«ΰΆΊ", + "scenes.app.channelsbar.read_sign": "ΰΆšΰ·’ΰΆΊΰ·€ΰ·– ΰΆ½ΰ·™ΰ·ƒ ΰ·ƒΰΆ½ΰΆšΰ·”ΰΆ«ΰ·” ࢚ࢻࢱ්ࢱ", + "scenes.app.channelsbar.private_channel_label": "ΰΆ΄ΰ·žΰΆ―ΰ·ŠΰΆœΰΆ½ΰ·’ΰΆš", + "scenes.app.mainview.tabs.rename": "ΰΆΊΰ·…ΰ·’ ࢱࢸ් ࢚ࢻࢱ්ࢱ", + "scenes.app.workspaces.welcome_page.ready_to_work": "ΰΆ”ΰΆΆ ࢯැࢱ් වැࢩ ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰ·ƒΰ·–ΰΆ―ΰ·ΰΆ±ΰΆΈΰ·Š.", + "scenes.app.workspaces.welcome_page.twake_team": "ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š", + "scenes.app.workspaces.welcome_page.main_mail_title": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ°ΰ·ΰΆ± ΰΆ½ΰ·’ΰΆ΄ΰ·’ΰΆ±ΰΆΊ", + "scenes.app.workspaces.welcome_page.other_mail_title": "ΰΆ―ΰ·Šΰ·€ΰ·’ΰΆ­ΰ·“ΰΆΊΰ·’ΰΆš ΰΆ½ΰ·’ΰΆ΄ΰ·’ΰΆ±", + "app.name.twake_calendar": "ΰΆ―ΰ·’ΰΆ± ΰΆ―ΰ·ƒΰ·”ΰΆ±", + "scenes.app.channelsbar.currentuser.title": "ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈΰ·š ΰ·ƒΰ·ΰΆšΰ·ƒΰ·”ΰΆΈΰ·Š", + "components.locked_features.locked_only_office_popup.subtitle": "ΰΆ”ΰΆΆΰΆ§ ΰΆ±ΰ·œΰΆΈΰ·’ΰΆ½ΰ·š ࢅࢱුවාࢯࢺෙහි ΰΆ”ΰΆ±ΰ·ŠΰΆ½ΰ·’ΰΆ”ΰ·†ΰ·’ΰ·ƒΰ·Š ࢷාවිࢭා ΰΆšΰ·… ΰΆ±ΰ·œΰ·„ΰ·ΰΆšΰ·’ΰΆΊ.", + "components.locked_features.locked_drive_popup.subtitle": "ΰΆ±ΰ·œΰΆΈΰ·’ΰΆ½ΰ·š ࢅࢱුවාࢯࢺෙහි ΰΆ”ΰΆΆΰΆ§ ΰΆœΰ·’.ΰΆΆ. GB ්࢚ ࢜ࢢࢩා ΰΆšΰ·… ΰ·„ΰ·ΰΆšΰ·’ΰΆΊ.", + "scenes.app.channelsbar.unread_sign": "ΰΆ±ΰ·œΰΆšΰ·’ΰΆΊΰ·€ΰ·– ΰΆ½ΰ·™ΰ·ƒ ΰ·ƒΰΆ½ΰΆšΰ·”ΰΆ«ΰ·” ࢚ࢻࢱ්ࢱ", + "scenes.app.channelsbar.channel_leaving": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ හැࢻ ࢺࢱ්ࢱ", + "scenes.app.channelsbar.public_channel_label": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·ƒΰ·’ΰΆ―ΰ·ŠΰΆ°", + "scenes.app.channelsbar.welcome": "ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š ΰ·€ΰ·™ΰΆ­ ΰ·ƒΰ·ΰΆ―ΰΆ»ΰΆΊΰ·™ΰΆ±ΰ·Š ΰΆ΄ΰ·’ΰ·…ΰ·’ΰΆœΰΆ±ΰ·’ΰΆΈΰ·”", + "scenes.app.popup.appsparameters.pages.public_login_label": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·ƒΰ·’ΰΆ―ΰ·ŠΰΆ° ΰ·„ΰΆ³ΰ·”ΰΆ±ΰ·Šΰ·€ΰΆ±ΰΆΊ", + "scenes.app.popup.appsparameters.pages.show_button": "ΰΆ΄ΰ·™ΰΆ±ΰ·Šΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.popup.userparameter.pages.private_message_content.hide": "ΰΆ΄ΰ·žΰΆ―ΰ·ŠΰΆœΰΆ½ΰ·’ΰΆš ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ© ΰΆ…ΰΆ±ΰ·ŠΰΆ­ΰΆ»ΰ·ŠΰΆœΰΆ­ΰΆΊ ΰ·ƒΰΆŸΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.popup.userparameter.pages.notif_content_label": "ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·Š ΰ·€ΰΆ½ ΰΆ…ΰΆ±ΰ·ŠΰΆ­ΰΆ»ΰ·ŠΰΆœΰΆ­ΰΆΊ", + "scenes.app.popup.workspaceparameter.manager_current_status": "ΰΆ”ΰΆΆ ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰΆš ΰΆ΄ΰΆ»ΰ·’ΰΆ΄ΰ·ΰΆ½ΰΆšΰΆΊΰ·™ΰΆšΰ·’.", + "scenes.app.popup.workspaceparameter.pages.access_apps": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š ΰ·ƒΰ·„ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆš ΰ·€ΰ·™ΰΆ­ ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·€ΰ·šΰ·ΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.calendar.export_title": "ΰΆ±ΰ·’ΰΆ»ΰ·ŠΰΆΊΰ·ΰΆ­ ࢚ࢻࢱ්ࢱ", + "scenes.apps.calendar.ics_download_menu": "ΰΆ…ΰΆΊΰ·’ΰ·ƒΰ·“ΰΆ‘ΰ·ƒΰ·Š ΰΆœΰ·œΰΆ±ΰ·”ΰ·€ΰΆšΰ·Š ࢢා࢜ࢱ්ࢱ", + "scenes.apps.calendar.modals.advanced_options": "වැࢩිࢯුࢻ ΰ·€ΰ·’ΰΆšΰΆ½ΰ·ŠΰΆ΄", + "scenes.apps.calendar.modals.event_title_placeholder": "සිࢻැසිࢺ", + "scenes.apps.calendar.my_calendar_menu": "ࢸා࢜ේ ΰΆ―ΰ·’ΰΆ± ΰΆ―ΰ·ƒΰ·”ΰΆ±", + "scenes.apps.drive.import_from_computer_menu": "ΰΆ΄ΰΆ»ΰ·’ΰΆœΰΆ«ΰΆšΰΆΊΰ·™ΰΆ±ΰ·Š ΰΆ‹ΰΆ©ΰ·”ΰΆœΰΆ­ ࢚ࢻࢱ්ࢱ", + "scenes.apps.drive.no_file_alert": "ΰΆœΰ·œΰΆ±ΰ·”ΰ·€ΰΆšΰ·Š ΰ·ƒΰ·‘ΰΆ―ΰ·“ΰΆΈΰΆ§ ΰΆ‰ΰΆ© ΰΆ―ΰ·™ΰΆ± ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š ΰΆ”ΰΆΆ ΰ·ƒΰΆ­ΰ·”ΰ·€ ࢱැࢭ.", + "scenes.apps.drive.viewer.edit_with_button": "{{$1}} ΰ·ƒΰΆΈΰΆŸ ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ", + "scenes.apps.drive.viewer.open_with_button": "ΰ·ƒΰΆΈΰΆŸ ΰ·€ΰ·’ΰ·€ΰ·˜ΰΆ­ ࢚ࢻࢱ්ࢱ...", + "scenes.apps.messages.input.placeholder": "ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊΰΆšΰ·Š ΰΆ½ΰ·’ΰΆΊΰΆ±ΰ·ŠΰΆ±. ࢋࢴුࢧා ΰΆ―ΰ·ΰΆšΰ·Šΰ·€ΰ·“ΰΆΈΰΆ§ @ ࢷාවිࢭා ࢚ࢻࢱ්ࢱ.", + "scenes.apps.messages.message.save_button": "ΰ·ƒΰ·”ΰΆ»ΰΆšΰ·’ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.popup.sync_calendar": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ―ΰ·’ΰΆ±ΰΆ―ΰ·ƒΰ·”ΰΆ± ΰ·ƒΰΆΈΰΆΈΰ·”ΰ·„ΰ·–ΰΆ»ΰ·ŠΰΆ­ ࢚ࢻࢱ්ࢱ.", + "scenes.apps.account.account.fullname": "ΰ·ƒΰΆΈΰ·ŠΰΆ΄ΰ·–ΰΆ»ΰ·ŠΰΆ« ΰΆ±ΰΆΈ", + "scenes.apps.account.account.save": "ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈ ΰ·ƒΰ·”ΰΆ»ΰΆšΰ·’ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.mainview.link_expired": "ΰΆΈΰ·™ΰΆΈ ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·ƒΰ·’ΰΆ―ΰ·ŠΰΆ° සࢢැࢳිࢺ ΰ·€ΰΆ½ΰΆ‚ΰΆœΰ·” ࢱැࢭ ΰ·„ΰ·œΰ·Š ࢚ࢽ් ΰΆ‰ΰΆšΰ·”ΰΆ­ΰ·Š ΰ·€ΰ·“ ΰΆ‡ΰΆ­.", + "components.attachmentpicker.add_attachment": "ΰΆ‡ΰΆΈΰ·”ΰΆ«ΰ·”ΰΆΈΰ·Š ΰΆ‘ΰΆšΰΆ­ΰ·” ࢚ࢻࢱ්ࢱ", + "components.leftbar.channel.workspaceschannels.menu.option_2": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰΆšΰΆ§ ΰΆ‘ΰΆšΰ·Šΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.client.channelbar.workspacechannellist.autocomplete": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·, ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·™ΰΆšΰ·” හෝ ΰ·ƒΰ·˜ΰΆ’ΰ·” ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ© ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ±", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_edition": "{{$1}} ΰΆΊΰ·…ΰ·’ ࢱࢸ්࢚ࢻࢱ්ࢱ", + "components.connectorslistmanager.add_connectors": "ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆš ΰΆ‘ΰΆšΰΆ­ΰ·”ΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "components.notifications.hidden_notifications_button.children": "ΰΆ±ΰ·€ ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©", + "scenes.app.channelsbar.channelsuser.no_private_message_invite_collaboraters": "ΰΆ΄ΰ·žΰΆ―ΰ·ŠΰΆœΰΆ½ΰ·’ΰΆš ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ© ࢱැࢭ. ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·ŠΰΆ§ ࢆࢻාࢰࢱා ࢚ࢻࢱ්ࢱ!", + "scenes.apps.drive.right_preview.versions": "ࢅࢱුවාࢯ", + "components.channelworkspacelist.title": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·", + "components.upload.drop_files.toaster.error": "ΰΆ”ΰΆΆΰΆ§ ΰΆœΰ·œΰΆ±ΰ·” {{$1}} ࢚ࢧ වࢩා ΰΆ‹ΰΆ©ΰ·”ΰΆœΰΆ­ ΰΆšΰ·… ΰΆ±ΰ·œΰ·„ΰ·ΰΆšΰ·’ΰΆΊ", + "scenes.app.popup.appsparameters.pages._app_identity": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·š ΰΆ…ΰΆ±ΰΆ±ΰ·Šβ€ΰΆΊΰΆ­ΰ·ΰ·€ΰΆΊ", + "components.emoji_picker.categories.objects": "ΰ·€ΰ·ƒΰ·ŠΰΆ­ΰ·–ΰΆ±ΰ·Š", + "components.emoji_picker.categories.flags": "ΰΆšΰ·œΰΆ©ΰ·’", + "scenes.app.mainview.tabs.searching_connectors": "ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆš ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ±...", + "scenes.app.popup.appsparameters.pages.allowed_ip_adresses_method": "ΰ·ƒΰ·’ΰΆΊΰ·…ΰ·”ΰΆΈ ΰΆ….ΰΆ’.ΰΆšΰ·™. ΰΆ½ΰ·’ΰΆ΄ΰ·’ΰΆ± ΰ·€ΰΆ½ΰΆ§ ΰΆ‰ΰΆ© ΰΆ―ΰ·“ΰΆΈΰΆ§ ΰ·ƒΰΆ‚ΰ·€ΰΆ»ΰ·ŠΰΆ°ΰΆ±ΰΆΊΰ·šΰΆ―ΰ·“ * ࢷාවිࢭා ࢚ࢻࢱ්ࢱ.", + "scenes.app.popup.appsparameters.pages.amazing_app_name": "ࢸා࢜ේ ΰΆ΄ΰ·”ΰΆ―ΰ·”ΰΆΈΰ·ΰΆšΰ·ΰΆ» ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ", + "scenes.app.popup.appsparameters.pages.api_parameters_label": "ΰΆΊΰ·™.ΰΆšΰ·Šβ€ΰΆ».ΰΆΈΰ·”. ΰ·ƒΰ·ΰΆšΰ·ƒΰ·”ΰΆΈΰ·Š", + "scenes.app.popup.appsparameters.pages.application_title": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ", + "scenes.app.popup.appsparameters.pages.apps_title": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š ΰ·ƒΰ·„ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆš", + "scenes.app.popup.appsparameters.pages.automatique_label": "ΰ·ƒΰ·Šΰ·€ΰΆΊΰΆ‚ΰΆšΰ·Šβ€ΰΆ»ΰ·“ΰΆΊ", + "scenes.app.popup.appsparameters.pages.autorised_ip_adresses_label": "ΰΆ‰ΰΆ© ΰΆ―ΰ·”ΰΆ±ΰ·Š ΰΆ….࢒ා.ΰΆšΰ·™. ΰΆ½ΰ·’ΰΆ΄ΰ·’ΰΆ±", + "scenes.app.popup.appsparameters.pages.button_force": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ ࢴුࢻාࢸ ΰΆΆΰΆ½ ࢚ࢻࢱ්ࢱ", + "scenes.app.popup.appsparameters.pages.company_label": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰ·„ΰ·’ΰΆΈΰ·’ΰΆšΰΆ»ΰ·”", + "scenes.app.popup.appsparameters.pages.configuration_label": "ΰ·€ΰ·’ΰΆ±ΰ·Šβ€ΰΆΊΰ·ΰ·ƒΰΆΊ", + "scenes.app.popup.appsparameters.pages.create_app_button": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰΆšΰ·Š ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.popup.appsparameters.pages.create_my_app": "ࢸා࢜ේ ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.popup.appsparameters.pages.danger_zone_label": "ΰΆ…ΰΆ±ΰΆ­ΰ·”ΰΆ»ΰ·”ΰΆ―ΰ·ΰΆΊΰΆš ࢚ࢽාࢴࢺ", + "scenes.app.popup.appsparameters.pages.developped_apps_subtitle": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ ΰ·€ΰ·’ΰ·ƒΰ·’ΰΆ±ΰ·Š ΰ·ƒΰΆ‚ΰ·€ΰΆ»ΰ·ŠΰΆ°ΰΆ±ΰΆΊ ΰΆšΰ·… ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š", + "scenes.app.popup.appsparameters.pages.error_check_needed": "ΰΆ―ΰ·ΰ·‚ΰΆΊΰΆšΰ·Š ΰ·ƒΰ·’ΰΆ―ΰ·” ΰ·€ΰ·“ ΰΆ‡ΰΆ­; ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ­ΰ·œΰΆ»ΰΆ­ΰ·”ΰΆ»ΰ·” ΰΆ΄ΰΆ»ΰ·“ΰΆšΰ·Šΰ·‚ΰ· ࢚ࢻࢱ්ࢱ.", + "scenes.app.popup.appsparameters.pages.go_back": "ΰΆ†ΰΆ΄ΰ·ƒΰ·”", + "scenes.app.popup.appsparameters.pages.grp_section_surname_label": "ΰ·ƒΰΆ»ΰΆ½ ΰΆšΰ·… ΰΆ±ΰΆΈ", + "scenes.app.popup.appsparameters.pages.interne_availability_application": "ΰΆ…ΰΆ·ΰ·Šβ€ΰΆΊΰΆ±ΰ·ŠΰΆ­ΰΆ» ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ", + "scenes.app.popup.appsparameters.pages.loading": "ΰΆ΄ΰ·–ΰΆ»ΰΆ«ΰΆΊ ΰ·€ΰ·™ΰΆΈΰ·’ΰΆ±ΰ·Š...", + "scenes.app.popup.appsparameters.pages.public_availability_application": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·ƒΰ·’ΰΆ―ΰ·ŠΰΆ° ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ", + "scenes.app.popup.workspaceparameter.pages.apps_connectors_title": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š ΰ·ƒΰ·„ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆš", + "scenes.app.popup.workspaceparameter.pages.apps_research_title": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ±", + "scenes.app.popup.workspaceparameter.pages.configuration_notif": "ΰ·€ΰ·’ΰΆ±ΰ·Šβ€ΰΆΊΰ·ΰ·ƒΰΆΊ", + "scenes.app.popup.workspaceparameter.pages.configure_button": "ΰ·€ΰ·’ΰΆ±ΰ·Šβ€ΰΆΊΰ·ΰ·ƒΰΆœΰΆ­ ࢚ࢻࢱ්ࢱ", + "scenes.app.popup.workspaceparameter.pages.developped_apps_small_text": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ ΰ·€ΰ·’ΰ·ƒΰ·’ΰΆ±ΰ·Š ΰ·ƒΰΆ‚ΰ·€ΰΆ»ΰ·ŠΰΆ°ΰΆ±ΰΆΊ ΰΆšΰ·… ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š", + "scenes.app.popup.workspaceparameter.pages.installed_apps_subtitle": "ΰ·ƒΰ·ŠΰΆΰ·ΰΆ΄ΰ·’ΰΆ­ ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š", + "scenes.app.popup.workspaceparameter.pages.logo_subtitle": "ࢽාࢂ࢑ࢱࢺ", + "scenes.app.popup.workspaceparameter.pages.write_access_subtitle": "ΰΆ½ΰ·’ΰ·€ΰ·“ΰΆΈΰ·š ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·€ΰ·šΰ·ΰΆΊ", + "scenes.app.popup.workspaceparameter.pages.your_apps_label": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š", + "scenes.app.workspacesbar.components.change_company_title": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ ΰ·€ΰ·™ΰΆ±ΰ·ƒΰ·Š ࢚ࢻࢱ්ࢱ", + "scenes.app.workspacesbar.components.create_company_menu": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰΆšΰ·Š ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.calendar.edit_calendar_title": "ΰΆ―ΰ·’ΰΆ± ΰΆ―ΰ·ƒΰ·”ΰΆ± ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ", + "scenes.apps.calendar.modals.details_title": "ΰ·€ΰ·’ΰ·ƒΰ·ŠΰΆ­ΰΆ»", + "scenes.apps.calendar.modals.event_adresse_placeholder": "ΰΆ½ΰ·’ΰΆ΄ΰ·’ΰΆ±ΰΆΊ", + "scenes.apps.calendar.modals.part.participants": "ΰ·ƒΰ·„ΰΆ·ΰ·ΰΆœΰ·’ΰ·€ΰΆ±ΰ·ŠΰΆ±ΰΆ±ΰ·Š", + "scenes.apps.calendar.modals.participants_event": "ΰ·ƒΰ·„ΰΆ·ΰ·ΰΆœΰ·’ΰ·€ΰΆ±ΰ·ŠΰΆ±ΰΆ±ΰ·Š", + "scenes.apps.calendar.today_menu": "ΰΆ…ΰΆ―", + "scenes.apps.calendar.week_option": "ΰ·ƒΰΆ­ΰ·’ΰΆΊ", + "scenes.apps.drive.add_button": "ΰΆ‘ΰΆšΰΆ­ΰ·”", + "scenes.apps.drive.create_folder_button": "ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.drive.download_button": "ࢢා࢜ࢱ්ࢱ", + "scenes.apps.drive.open_link": "සࢢැࢳිࢺ ΰΆ±ΰ·€ ΰΆšΰ·€ΰ·”ΰ·…ΰ·”ΰ·€ΰΆšΰ·’ΰΆ±ΰ·Š ΰ·€ΰ·’ΰ·€ΰ·˜ΰΆ­ ࢚ࢻࢱ්ࢱ", + "scenes.apps.drive.files_subtitle": "ΰΆœΰ·œΰΆ±ΰ·”", + "scenes.apps.drive.viewer.loading_preview_message": "ΰΆ΄ΰ·–ΰΆ»ΰΆ«ΰΆΊ ΰ·€ΰ·™ΰΆΈΰ·’ΰΆ±ΰ·Š...", + "scenes.apps.messages.message.new_messages_bar": "ΰΆ±ΰ·€ ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©", + "scenes.apps.messages.message.cancel_button": "ΰΆ…ΰ·€ΰΆ½ΰΆ‚ΰΆœΰ·”", + "scenes.apps.messages.message.modify_button": "ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ", + "scenes.apps.messages.message.copy_link": "සࢢැࢳිࢺ ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊΰΆšΰΆ§ ΰΆ΄ΰ·’ΰΆ§ΰΆ΄ΰΆ­ΰ·ŠΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.messages.message.reply_button": "ΰΆ΄ΰ·’ΰΆ½ΰ·’ΰΆ­ΰ·”ΰΆ»ΰ·”", + "scenes.apps.messages.message.types.first_channel_message_text": "ΰΆΈΰ·™ΰΆΈ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰ·š ΰΆ΄ΰ·…ΰΆΈΰ·” ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊ ΰΆΈΰ·™ΰΆΊΰΆΊΰ·’", + "scenes.apps.messages.message.types.first_message_text": "ΰΆΈΰ·™ΰΆΊ ΰΆ΄ΰ·…ΰΆΈΰ·” ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊΰΆΊΰ·’", + "scenes.apps.messages.messageslist.get_writing_user": "ΰΆ½ΰ·’ΰΆΊΰΆΈΰ·’ΰΆ±ΰ·Š...", + "scenes.login.verifymail.alert": "ΰΆ…ΰΆ΄ΰ·’ ΰΆ”ΰΆΆΰΆœΰ·š ΰ·€ΰ·’-ࢭැࢴෑࢽ ΰΆ΄ΰΆ»ΰ·“ΰΆšΰ·Šβ€ΰ·‚ΰ· ΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±ΰ·™ΰΆΈΰ·”!", + "scenes.login.verifymail.signin_button": "ΰΆ‡ΰΆ­ΰ·”ΰΆ½ΰ·Š ΰ·€ΰΆ±ΰ·ŠΰΆ±", + "services.apps.messages.no_app": "ΰΆΈΰ·™ΰΆΈ ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰΆ±ΰ·œΰΆ΄ΰ·€ΰΆ­ΰ·“.", + "scenes.apps.messages.input.send_message": "ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊ ΰΆΊΰ·€ΰΆ±ΰ·ŠΰΆ±", + "components.listmanager.filter": "ΰΆ΄ΰ·™ΰΆ»ΰ·„ΰΆ±", + "scenes.apps.tasks.no_connector": "ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆšΰΆΊΰΆšΰ·Š ࢱැࢭ", + "components.drive.moove_here": "ࢸෙࢭැࢱࢧ ΰΆœΰ·™ΰΆ±ΰΆΊΰΆ±ΰ·ŠΰΆ±", + "components.workspace.calendar.invalid": "ΰ·€ΰΆ½ΰΆ‚ΰΆœΰ·” ΰΆ±ΰ·œΰ·€ΰ·š", + "components.searchpopup.loading": "ΰΆ­ΰ·€ ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ­ΰ·’ΰΆ΅ΰΆ½ ΰΆ΄ΰ·–ΰΆ»ΰΆ«ΰΆΊ ΰ·€ΰ·™ΰΆΈΰ·’ΰΆ±ΰ·Š", + "components.searchpopup.size": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆΈΰ·ΰΆ«ΰΆΊ", + "components.searchpopup.show_filters": "ΰΆ΄ΰ·™ΰΆ»ΰ·„ΰΆ±ΰ·Š ΰΆ΄ΰ·™ΰΆ±ΰ·Šΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.board.kanban": "࢚ࢱ්ࢢࢱ්", + "components.userlistmanager.no_users": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š ࢱැࢭ.", + "components.reminder.by_email": "ΰ·€ΰ·’-ࢭැࢴෑࢽ", + "scenes.app.mainview.discussion": "ΰ·ƒΰ·ΰΆšΰΆ ΰ·ŠΰΆ‘ΰ·", + "components.attachmentpicker.from_twake": "ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š ΰΆ½ΰ·šΰΆ›ΰΆ± ΰ·€ΰ·™ΰΆ­ΰ·’ΰΆ±ΰ·Š", + "components.attachmentpicker.file": "ΰΆœΰ·œΰΆ±ΰ·”ΰ·€", + "scenes.apps.drive.remove_attachs": "ΰΆ‡ΰΆΈΰ·”ΰΆ«ΰ·”ΰΆΈΰ·Š ΰΆ‰ΰ·€ΰΆ­ΰ·ŠΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "components.drive.elements.manage_version": "ࢅࢱුවාࢯ ΰΆšΰ·…ΰΆΈΰΆ«ΰ·ΰΆšΰΆ»ΰΆ±ΰΆΊ", + "scenes.app.popup.workspace.edit_temp": "ΰΆ­ΰ·ΰ·€ΰΆšΰ·ΰΆ½ΰ·’ΰΆš ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈ ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ", + "scenes.app.popup.appsparameters.pages.icon": "ΰΆ±ΰ·’ΰΆ»ΰ·–ΰΆ΄ΰΆšΰΆΊ", + "scenes.app.popup.appsparameters.pages.smalltext_user_id": "ΰ·€ΰΆ­ΰ·ŠΰΆΈΰΆ±ΰ·Š ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆš ΰ·„ΰ·ΰΆ³ΰ·”ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ΄ΰΆ­", + "scenes.client.channelbar.channelmemberslist.autocomplete": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·™ΰΆšΰ·” ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ± හෝ ΰΆ‘ΰΆšΰΆ­ΰ·”ΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "scenes.client.mainview.tabs.tabstemplateeditor.select_placeholder": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ", + "components.newversion.new_version_component.row.part_1": "ΰΆ”ΰΆΆ ࢺࢽ් ࢴැࢱ ΰΆœΰ·’ΰΆΊ ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š ΰΆ…ΰΆ±ΰ·”ΰ·€ΰ·ΰΆ―ΰΆΊΰΆšΰ·Š ࢰාවࢱࢺ ΰΆšΰΆ»ΰΆΈΰ·’ΰΆ±ΰ·Š", + "scenes.apps.drive.download_all_button": "ΰ·ƒΰ·’ΰΆΊΰΆ½ΰ·ŠΰΆ½ ࢢා࢜ࢱ්ࢱ", + "components.inputs.input_with_select.input.placeholder": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰ·š ΰΆ±ΰΆΈ", + "scenes.apps.messages.message.activity_message.a_deleted_channel_connector": "{{$1}} ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆΊΰΆšΰ·Š ΰΆ‰ΰ·€ΰΆ­ΰ·Š ΰΆšΰ·…ΰ· {{$2}}", + "components.unverified_account.re_send_email": "ΰ·€ΰ·’-ࢭැࢴෑࢽ ΰΆ±ΰ·œΰΆ½ΰ·ΰΆΆΰ·”ΰΆ±ΰ·šΰΆ―?", + "components.add_mails_workspace.button": "ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š ࢷාවිࢭා ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈ ΰΆ…ΰΆ»ΰΆΉΰΆ±ΰ·ŠΰΆ±", + "services.console_services.toaster.add_email_error_message": "{{$1}} ΰΆ‘ΰΆšΰΆ­ΰ·” ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈ ΰΆ…ΰΆ­ΰΆ»ΰΆ­ΰ·”ΰΆ» ΰΆ―ΰ·ΰ·‚ΰΆΊΰΆšΰ·’", + "services.console_services.toaster.success_invite_emails": "ΰ·ƒΰ·ΰΆ»ΰ·ŠΰΆΰΆšΰ·€ ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š {{$1}} ්࢚ ΰΆ‘ΰΆšΰΆ­ΰ·” ΰΆšΰ·™ΰΆ»ΰ·’ΰΆ«ΰ·’", + "scenes.client.channels_bar.modals.parts.channel_member_row.label.pending_email": "ࢭැࢴෑࢽ ࢺැවිࢫි", + "components.richtexteditor.toolbar.underline": "ΰΆΊΰΆ§ΰ·’ΰΆ‰ΰΆ»", + "components.locked_features.locked_history_banner.title": "ΰΆ”ΰΆΆ ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ© සීࢸාවࢧ ࢽ࢟ා ΰ·€ΰ·“ ΰΆ‡ΰΆ­", + "components.locked_features.locked_guests_popup.skip_for_now_button": "ࢯැࢱࢧ ࢸ࢟ ΰ·„ΰΆ»ΰ·’ΰΆ±ΰ·ŠΰΆ±", + "components.on_boarding.popups.blocked_company.company_subscription_plan_button": "ࢸෙࢭැࢱ ΰΆ”ΰΆΆΰΆ±ΰ·ŠΰΆ±", + "scenes.app.popup.workspaceparameter.pages.table_title": "ΰΆ±ΰΆΈ", + "scenes.client.main_view.main_header.search_input": "ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.drive.default_link_name": "ΰ·ƒΰ·’ΰΆ»ΰ·ΰ·ƒΰ·’ΰΆΊΰΆšΰ·Š ࢱැࢭ", + "components.emoji_picker.input_search_placeholder": "ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ±", + "services.apps.messages.message_editor_service.upload_error_toaster": "{{$1}} - ΰΆ”ΰΆΆΰΆ§ {{$2}} ΰΆ§ වࢩා ΰΆœΰ·œΰΆ±ΰ·” ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊΰΆšΰΆ§ ΰΆ‘ΰΆšΰΆ­ΰ·” ΰΆšΰ·… ΰΆ±ΰ·œΰ·„ΰ·ΰΆšΰ·’ΰΆΊ", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_link": "ΰΆ΄ΰ·žΰΆ―ΰ·ŠΰΆœΰΆ½ΰ·’ΰΆš ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰΆšΰ·Š ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "general.uploading": "ΰΆ‹ΰΆ©ΰ·”ΰΆœΰΆ­ ΰ·€ΰ·™ΰΆΈΰ·’ΰΆ±ΰ·Š", + "components.emoji_picker.categories.food_and_drink": "ࢆහාࢻ හා ࢴාࢱ", + "components.emoji_picker.categories.activity": "ΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰ·ΰΆšΰ·ΰΆ»ΰΆšΰΆΈΰ·Š", + "components.emoji_picker.categories.travel_and_places": "ΰΆ ΰ·ΰΆ»ΰ·’ΰΆšΰ· හා ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ―ΰ·šΰ·", + "components.emoji_picker.categories.search_result": "ΰ·ƒΰ·™ΰ·€ΰ·”ΰΆΈΰ·Š ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ­ΰ·’ΰΆ΅ΰΆ½", + "general.email": "ΰ·€ΰ·’-ࢭැࢴෑࢽ", + "components.locked_features.locked_only_office_popup.title": "ΰΆ”ΰΆΆΰΆ§ ΰΆΈΰ·™ΰΆΈ ΰΆœΰ·œΰΆ±ΰ·”ΰ·€ ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ ΰΆšΰ·… ΰΆ±ΰ·œΰ·„ΰ·ΰΆšΰ·’ΰΆΊ", + "scenes.app.mainview.tabs.no_connected_connectors_for_channel": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰΆšΰΆ§ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ° ΰΆšΰ·… ΰ·„ΰ·ΰΆšΰ·’ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆšΰΆΊΰΆšΰ·Š ΰΆ”ΰΆΆ ΰ·ƒΰΆ­ΰ·”ΰ·€ ࢱැࢭ.", + "scenes.app.popup.appsparameters.pages.app_name_label": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·š ΰΆ±ΰΆΈ", + "scenes.app.popup.appsparameters.pages.app_modification_right": "ΰΆΈΰ·™ΰΆΈ ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰ·ƒΰ·’ΰΆΊΰ·…ΰ·”ΰΆΈ ΰΆšΰ·…ΰΆΈΰΆ±ΰ·ΰΆšΰΆ»ΰ·”ΰ·€ΰΆ±ΰ·ŠΰΆ§ ΰΆΈΰ·™ΰΆΈ ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰ·„ΰ·ΰΆšΰ·’ ΰΆΊ.", + "scenes.app.popup.userparameter.pages.private_message_content.show": "ΰΆ΄ΰ·žΰΆ―ΰ·ŠΰΆœΰΆ½ΰ·’ΰΆš ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ© ΰΆ…ΰΆ±ΰ·ŠΰΆ­ΰΆ»ΰ·ŠΰΆœΰΆ­ΰΆΊ ΰΆ΄ΰ·™ΰΆ±ΰ·Šΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.popup.userparameter.pages.no_night_disturbing_label": "ΰΆ»ΰ·ΰΆ­ΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰΆ§ ࢢාࢰා ࢚ࢻࢱ්ࢱ ࢑ࢴා", + "scenes.app.popup.workspaceparameter.pages.company_name_label": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰΆ±ΰΆΈ", + "scenes.apps.drive.folder_subtitle": "ΰΆΆΰ·„ΰ·ΰΆ½ΰ·”ΰΆΈΰ·Š", + "scenes.client.channels_bar.modals.guest_management.title": "{{$1}} ΰ·„ΰ·’ ΰΆ…ΰΆΈΰ·”ΰΆ­ΰ·ŠΰΆ­ΰΆ±ΰ·Š ΰΆšΰ·…ΰΆΈΰΆ«ΰ·ΰΆšΰΆ»ΰΆ±ΰΆΊ", + "scenes.app.popup.workspaceparameter.pages.company_developped_apps_subtitle": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ ΰ·€ΰ·’ΰ·ƒΰ·’ΰΆ±ΰ·Š ΰ·ƒΰΆ‚ΰ·€ΰΆ»ΰ·ŠΰΆ°ΰΆ±ΰΆΊ ΰΆšΰ·… ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š", + "scenes.error_on_twake": "\"࢚ࢸࢽ්, ΰΆ…ΰΆ΄ΰ·’ΰΆ§ ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·ΰ·ŠΰΆ±ΰΆΊΰΆšΰ·Š ࢭිࢺෙࢱවා\"", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.tag": "ΰΆ”ΰΆΆ ΰ·ƒΰ·ΰΆΈΰ·ΰΆ’ΰ·’ΰΆšΰΆΊΰ·™ΰΆšΰ·” ΰΆ±ΰ·œΰ·€ΰ·š", + "scenes.app.popup.workspaceparameter.pages.company_identity_title": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰΆ…ΰΆ±ΰΆ±ΰ·ŠΰΆΊΰΆ­ΰ·ΰ·€ΰΆΊ", + "components.drive.new_versions": "ΰΆ±ΰ·€ ΰΆ…ΰΆ±ΰ·”ΰ·€ΰ·ΰΆ―ΰΆΊΰΆšΰ·Š ΰΆ‘ΰΆšΰΆ­ΰ·” ࢚ࢻࢱ්ࢱ", + "components.searchpopup.hide_filters": "ΰΆ΄ΰ·™ΰΆ»ΰ·„ΰΆ±ΰ·Š ΰ·ƒΰΆŸΰ·€ΰΆ±ΰ·ŠΰΆ±", + "components.attachmentpicker.remove_attach": "ΰΆ‡ΰΆΈΰ·”ΰΆ«ΰ·”ΰΆΈ ΰΆ‰ΰ·€ΰΆ­ΰ·ŠΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.drive.move_text": "ΰΆœΰ·™ΰΆ±ΰΆΊΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.messages.messageslist.go_last_message_button.new_messages": "ΰΆ±ΰ·€ ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©", + "scenes.apps.account.message_temporary": "ΰΆ­ΰ·ΰ·€ΰΆšΰ·ΰΆ½ΰ·’ΰΆš ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈΰΆšΰ·Š ΰ·ƒΰ·ΰΆΈΰ·ΰΆ±ΰ·Šβ€ΰΆΊ ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈΰΆšΰ·Š ΰΆΈΰ·™ΰΆ±ΰ·Š ΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰ· ࢚ࢻࢱ ΰΆ±ΰΆΈΰ·”ΰΆ­ΰ·Š ΰΆ”ΰΆΆ ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊ සාࢯࢱ ΰΆ…ΰΆ­ΰΆ» ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊ ࢱࢸ් ΰΆ”ΰΆΆΰΆ§ ΰΆ‘ΰΆΊ ࢱැවࢭ ΰ·ƒΰ·ΰΆšΰ·ƒΰ·“ΰΆΈΰΆ§ ΰ·„ΰ·ΰΆšΰ·’ΰΆΊ.", + "components.input.copied": "ΰΆ΄ΰ·’ΰΆ§ΰΆ΄ΰΆ­ΰ·Š ΰ·€ΰ·’ΰΆΊ", + "components.drive.right_preview.create_link": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·€ΰ·šΰ· ΰ·€ΰ·“ΰΆΈΰ·š ΰ·ƒΰΆΆΰ·ΰΆ³ΰ·’ΰΆΊΰΆšΰ·Š ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "components.drive.elements.current_name": "ΰ·€ΰΆ­ΰ·ŠΰΆΈΰΆ±ΰ·Š ΰΆ±ΰΆΈ: ", + "scenes.client.channelbar.channelmemberslist.tag": "ΰΆ”ΰΆΆ", + "components.alert.leave_private_channel.title": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ හැࢻࢺාࢸࢧ ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊ ΰΆΆΰ·€ ΰΆ”ΰΆΆΰΆ§ ΰ·€ΰ·’ΰ·ΰ·Šΰ·€ΰ·ΰ·ƒΰΆ―?", + "components.on_boarding.popups.blocked_company.company_selector": "ΰ·€ΰ·™ΰΆ±ΰΆ­ΰ·Š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰΆ§ΰΆšΰΆ§ ΰΆΈΰ·ΰΆ»ΰ·”ΰ·€ΰΆ±ΰ·ŠΰΆ±", + "components.member.user_parts.and_more_user_text": " ΰ·ƒΰ·„ ΰΆ­ΰ·€ΰΆ­ΰ·Š ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š {{$1}}", + "components.emoji_picker.categories.frequently_used": "ΰΆ±ΰ·’ΰΆ­ΰΆ» ࢷාවිࢭා ΰ·€ΰ·–", + "components.emoji_picker.categories.animals_and_nature": "ΰ·ƒΰΆ­ΰ·”ΰΆ±ΰ·Š ΰ·ƒΰ·„ ΰ·ƒΰ·œΰΆΆΰ·ΰΆ―ΰ·„ΰΆΈ", + "components.leftbar.channel.workspaceschannels.menu.option_1": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰΆšΰ·Š ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "components.on_boarding.popups.blocked_company.or": "හෝ", + "scenes.apps.messages.message.activity_message.a_updated_channel_name": "{{$1}} ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰ·š ΰΆ±ΰΆΈ {{$2}} ΰΆ§ ΰ·€ΰ·™ΰΆ±ΰ·ƒΰ·Š ΰΆšΰ·…ΰ·", + "general.user.role.company.member": "ΰ·ƒΰ·ΰΆΈΰ·ΰΆ’ΰ·’ΰΆšΰΆΊΰ·", + "scenes.login.home.login_btn": "ΰΆ‡ΰΆ­ΰ·”ΰΆ½ΰ·Š ΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.login.home.lost_password": "ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊ ΰΆ…ΰΆΈΰΆ­ΰΆš වුࢫා ΰΆ―?", + "scenes.login.create_account.password": "ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊ", + "scenes.app.workspaces.create_company.company_name.placeholder": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰΆ±ΰΆΈ", + "scenes.app.workspaces.create_company.default_workspace_name": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ°ΰ·ΰΆ±", + "scenes.app.workspaces.create_company.importations.title_2": "࢚ࢻࢯࢻ ΰΆ±ΰ·œΰ·€ΰΆ±ΰ·ŠΰΆ±, ΰΆΈΰ·™ΰΆΊ ΰΆ΄ΰ·ƒΰ·”ΰ·€ ΰΆšΰ·… ΰ·„ΰ·ΰΆšΰ·’ΰΆΊ!", + "scenes.app.workspaces.welcome_page.create_my_company": "ࢸා࢜ේ ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.workspaces.welcome_page.try_again": "ΰΆΊΰ·…ΰ·’ ΰΆ‹ΰΆ­ΰ·Šΰ·ƒΰ·ΰ·„ ࢚ࢻࢱ්ࢱ", + "scenes.login.home.title": "ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š ΰ·€ΰ·™ΰΆ­ ΰΆ‡ΰΆ­ΰ·”ΰΆ½ΰ·Šΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.login.home.subtitle": "ΰΆ”ΰΆΆΰ·€ ΰΆ―ΰ·ΰΆšΰ·“ΰΆΈ ΰ·ƒΰΆ­ΰ·”ΰΆ§ΰΆšΰ·Š", + "scenes.login.home.email": "ΰ·€ΰ·’-ࢭැࢴෑࢽ", + "scenes.login.home.password": "ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊ", + "components.calendar.repetition.every_weekday": "ΰ·ƒΰ·‘ΰΆΈ ΰ·ƒΰΆ­ΰ·’ΰΆΊΰ·š ΰΆ―ΰ·’ΰΆ±ΰΆšΰΆΈ (සࢳුࢯා ΰ·ƒΰ·’ΰΆ§ ΰ·ƒΰ·’ΰΆšΰ·”)", + "scenes.app.popup.workspaceparameter.pages.collaborateurs": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š", + "scenes.app.popup.workspaceparameter.pages.install_button": "ΰ·ƒΰ·ŠΰΆΰ·ΰΆ΄ΰΆ±ΰΆΊ", + "scenes.apps.messages.messageslist.get_writing_users": "ΰΆ½ΰ·’ΰΆΊΰΆΈΰ·’ΰΆ±ΰ·Š...", + "scenes.apps.messages.messageslist.go_last_message_button": "ࢅවසාࢱ ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊΰΆ§ ࢺࢱ්ࢱ", + "components.newversion.new_version_modal.title": "ΰΆ±ΰ·€ ΰΆΊΰ·ΰ·€ΰΆ­ΰ·ŠΰΆšΰ·ΰΆ½ΰΆΊΰΆšΰ·Š ΰΆ­ΰ·’ΰΆΆΰ·š !", + "components.inputs.input_with_select.select.placeholder": "ΰΆ…ΰΆ‚ΰ·ΰΆΊΰ·š ΰΆ±ΰΆΈ", + "components.inputs.input_with_select.select.no_sections": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ΄ΰ·…ΰΆΈΰ·” ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ· ΰΆ…ΰΆ‚ΰ·ΰΆΊΰ·š ΰΆ±ΰΆΈ ΰΆ½ΰ·’ΰ·€ΰ·“ΰΆΈ ΰΆ…ΰΆ»ΰΆΉΰΆ±ΰ·ŠΰΆ±.", + "general.open": "ΰ·€ΰ·’ΰ·€ΰ·˜ΰΆ­", + "scenes.apps.account.thumbnail.max_weight": "ΰΆ‹ΰΆ΄ΰΆ»ΰ·’ΰΆΈ ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆΈΰ·ΰΆ«ΰΆΊ ΰΆΈΰ·™.ΰΆΆ. 5", + "scenes.app.channelsbar.channelsuser.private_messages": "ΰ·ƒΰ·˜ΰΆ’ΰ·” ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©", + "scenes.app.popup.workspaceparameter.pages.researching_apps_button": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ±...", + "scenes.app.popup.workspaceparameter.pages.enter": "ΰΆ‡ΰΆ­ΰ·”ΰΆ½ΰ·Š ࢚ࢻࢱ්ࢱ ", + "scenes.app.popup.appsparameters.pages.smalltext_group_id": "ΰ·€ΰΆ­ΰ·ŠΰΆΈΰΆ±ΰ·Š ΰ·ƒΰΆΈΰ·–ΰ·„ΰΆΊΰ·š හැࢳු.", + "scenes.client.channelbar.channelmemberslist.loader": "ΰΆ­ΰ·€ ΰΆ΄ΰ·–ΰΆ»ΰΆ«ΰΆΊ", + "scenes.client.channelbar.channelmemberslist.menu.option_2": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰ·™ΰΆ±ΰ·Š ΰΆ‰ΰ·€ΰΆ­ΰ·ŠΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "components.workspace.list_manager.current_company": "ΰ·€ΰΆ­ΰ·ŠΰΆΈΰΆ±ΰ·Š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ", + "components.workspace.list_manager.all": "ΰ·ƒΰ·’ΰΆΊΰΆ½ΰ·ŠΰΆ½", + "components.searchpopup.sender": "ΰΆΊΰ·€ΰΆ±ΰ·ŠΰΆ±ΰ·", + "scenes.app.mainview.advanced_search_placeholder": "ΰΆ‹ΰ·ƒΰ·ƒΰ·Š ΰ·ƒΰ·™ΰ·€ΰ·”ΰΆΈ", + "components.searchpopup.load_more": "ΰΆ­ΰ·€ ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ­ΰ·’ΰΆ΅ΰΆ½ ΰΆ΄ΰ·–ΰΆ»ΰΆ«ΰΆΊ ࢚ࢻࢱ්ࢱ", + "general.more": "ΰΆ­ΰ·€", + "scenes.apps.drive.used": "ΰΆΈΰ·™ΰΆΈ ΰΆΆΰ·„ΰ·ΰΆ½ΰ·”ΰΆΈΰ·š ࢷාවිࢭා ࢚ࢻ ΰΆ‡ΰΆ­", + "scenes.app.channelsbar.channelsuser.new_private_discussion": "ΰΆ±ΰ·€ ΰΆ΄ΰ·žΰΆ―ΰ·ŠΰΆœΰΆ½ΰ·’ΰΆš ΰ·ƒΰ·ΰΆšΰΆ ΰ·ŠΰΆ‘ΰ·ΰ·€", + "scenes.app.channelsbar.channelsworkspace.create_channel": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰΆšΰ·Š ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.channelsbar.channelsworkspace.no_channel": "ΰΆ”ΰΆΆ ΰΆ­ΰ·€ΰΆΈΰΆ­ΰ·Š ΰΆšΰ·’ΰ·ƒΰ·’ΰΆ―ΰ·” ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰΆšΰΆ§ ΰΆ‘ΰΆšΰ·Š ΰ·€ΰ·“ ࢱැࢭ", + "scenes.app.channelsbar.sending_message_instruction": "ΰ·ƒΰ·ΰΆšΰΆ ΰ·ŠΰΆ‘ΰ·ΰ·€ΰΆš ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ΄ΰ·…ΰΆΈΰ·” ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊ ΰΆΊΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.popup.appsparameters.pages.error_user_code": "ΰΆ―ΰ·ΰ·‚ΰΆΊΰΆšΰ·’", + "scenes.app.popup.appsparameters.pages.modify_public_data": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·ƒΰ·’ΰΆ―ΰ·ŠΰΆ° ࢯࢭ්ࢭ ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ ࢚ࢻࢱ්ࢱ.", + "scenes.app.popup.appsparameters.pages.new_app_title": "ΰΆ±ΰ·€ ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ", + "scenes.app.popup.appsparameters.pages.ok_user_code": "ΰ·„ΰΆ»ΰ·’", + "scenes.app.popup.appsparameters.pages.website_label": "ΰ·€ΰ·’ΰΆΊΰΆΈΰΆ± ΰΆ…ΰΆ©ΰ·€ΰ·’ΰΆΊ", + "scenes.app.popup.appsparameters.pages.update_button": "ΰΆΊΰ·ΰ·€ΰΆ­ΰ·ŠΰΆšΰ·ΰΆ½", + "scenes.app.popup.workspaceparameter.pages.all_apps_small_text": "ΰ·ƒΰ·’ΰΆΊΰ·…ΰ·”ΰΆΈ ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š", + "scenes.app.popup.workspaceparameter.pages.no_access": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·€ΰ·šΰ·ΰΆΊ ࢱැࢭ.", + "scenes.app.popup.workspaceparameter.pages.read_access_subtitle": "ΰΆšΰ·’ΰΆΊΰ·€ΰ·“ΰΆΈΰ·š ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·€ΰ·šΰ·ΰΆΊ", + "scenes.app.popup.workspaceparameter.pages.remove_from_company_text": "ΰ·ƒΰΆΈΰ·ƒΰ·ŠΰΆ ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·™ΰΆ±ΰ·ŠΰΆΈ ΰΆ‰ΰ·€ΰΆ­ΰ·Š ࢚ࢻࢱ්ࢱ", + "scenes.app.popup.workspaceparameter.pages.research_by": "ΰΆ±ΰΆΈΰ·’ΰΆ±ΰ·Š ΰ·ƒΰ·„ ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·€ΰΆ»ΰ·ŠΰΆœΰΆΊΰΆ±ΰ·Š ΰΆœΰ·™ΰΆ±ΰ·Š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ±", + "scenes.app.workspacesbar.components.grp_parameters": "{{$1}} ΰ·ƒΰ·ΰΆšΰ·ƒΰ·”ΰΆΈΰ·Š", + "scenes.apps.calendar.add_calendar_menu": "ΰΆ―ΰ·’ΰΆ± ΰΆ―ΰ·ƒΰ·”ΰΆ±ΰΆšΰ·Š ΰΆ‘ΰΆšΰΆ­ΰ·” ࢚ࢻࢱ්ࢱ", + "scenes.apps.calendar.connectors_menu": "ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆš...", + "scenes.apps.calendar.connectors_search_menu": "ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆš ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ±...", + "scenes.apps.calendar.create_calendar_title": "ΰΆ―ΰ·’ΰΆ± ΰΆ―ΰ·ƒΰ·”ΰΆ±ΰΆšΰ·Š ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.calendar.day_option": "ΰΆ―ΰ·€ΰ·ƒ", + "scenes.apps.calendar.modals.title_placeholder": "සිࢻැසිࢺ", + "scenes.apps.calendar.modify_calendar_menu": "ΰΆ―ΰ·’ΰΆ± ΰΆ―ΰ·ƒΰ·”ΰΆ± ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ", + "scenes.apps.calendar.month_option": "ࢸාසࢺ", + "scenes.apps.calendar.my_calendar": "ࢸා࢜ේ ΰΆ―ΰ·’ΰΆ± ΰΆ―ΰ·ƒΰ·”ΰΆ±", + "scenes.apps.calendar.my_calendar_label": "ࢸා࢜ේ ΰΆ―ΰ·’ΰΆ± ΰΆ―ΰ·ƒΰ·”ΰΆ±", + "scenes.apps.drive.new_file_menu": "ΰΆ±ΰ·€ ΰΆœΰ·œΰΆ±ΰ·”ΰ·€", + "scenes.apps.drive.new_external_storage": "ΰΆ±ΰ·€ ࢢාහිࢻ ΰΆ†ΰΆ ΰΆΊΰΆ±ΰΆΊ", + "scenes.apps.drive.new_folder_title": "ΰΆ±ΰ·€ ࢢහාࢽුࢸ", + "scenes.apps.drive.restore_menu": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ­ΰ·Šβ€ΰΆΊΰΆ»ΰ·ŠΰΆ΄ΰΆ«ΰΆΊ", + "services.apps.calendar.deadline_icon": "ΰΆ±ΰ·’ΰΆΊΰΆΈΰ·’ΰΆ­ ࢚ාࢽࢺ", + "scenes.apps.tasks.modals.attachments": "ΰΆ‡ΰΆΈΰ·”ΰΆ«ΰ·”ΰΆΈΰ·Š", + "components.calendar.calendarselector.from": "ΰ·€ΰ·™ΰΆ­ΰ·’ΰΆ±ΰ·Š", + "scenes.app.workspaces.components.skip": "ΰΆΈΰΆŸΰ·„ΰΆ»ΰ·’ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.drive.top_menu_more": "ΰΆ­ΰ·€", + "scenes.apps.messages.new_thread": "ΰΆ±ΰ·€ ΰ·ƒΰ·ΰΆšΰΆ ΰ·ŠΰΆ‘ΰ·ΰ·€ΰΆšΰ·Š ΰΆ…ΰΆ»ΰΆΉΰΆ±ΰ·ŠΰΆ±", + "scenes.tell_us": "ΰΆ”ΰΆΆ ΰΆšΰΆ»ΰΆΈΰ·’ΰΆ±ΰ·Š ΰ·ƒΰ·’ΰΆ§ΰ·’ΰΆΊ ΰΆ―ΰ·‘ ΰΆ…ΰΆ΄ΰΆ§ ΰΆšΰ·’ΰΆΊΰΆ±ΰ·ŠΰΆ±:", + "scenes.apps.parameters.workspace_sections.workspace.logo_company": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ࢽාࢂ࢑ࢱࢺ", + "login.email_login": "ΰ·€ΰ·’-ࢭැࢴෑࢽ / ΰΆ‡ΰΆ­ΰ·”ΰΆ½ΰ·Šΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.account.account.password_for_user": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆš සࢳහා ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊ", + "scenes.apps.drive.right_preview.public": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·ƒΰ·’ΰΆ―ΰ·ŠΰΆ° ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·€ΰ·šΰ·ΰΆΊ", + "scenes.app.popup.createcompany.try_again": "ΰΆΊΰ·…ΰ·’ ΰΆ‹ΰΆ­ΰ·Šΰ·ƒΰ·ΰ·„ ࢚ࢻࢱ්ࢱ.", + "scenes.apps.account.message_user_signin": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·ΰΆ§ ΰΆ•ΰΆ±ΰ·‘ΰΆΈ ΰ·€ΰ·šΰΆ½ΰ·ΰ·€ΰΆš ΰΆ‘ΰΆšΰΆΈ ΰ·€ΰ·’-ࢭැࢴෑࢽ ࢷාවිࢭා ࢚ࢻ ΰΆ‡ΰΆ­ΰ·”ΰΆ½ΰ·Š ΰ·€ΰ·’ΰΆΊ ΰ·„ΰ·ΰΆšΰ·’ ΰΆ…ΰΆ­ΰΆ» ΰΆ­ΰ·ΰ·€ΰΆšΰ·ΰΆ½ΰ·’ΰΆš ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈ ΰ·ƒΰ·ΰΆΈΰ·ΰΆ±ΰ·Šβ€ΰΆΊ ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈΰΆšΰΆ§ ΰΆ― ΰ·€ΰ·™ΰΆ±ΰ·ƒΰ·Š ΰΆšΰ·… ΰ·„ΰ·ΰΆšΰ·’ΰΆΊ.", + "components.newversion.new_version_component.row.part_2": "ΰΆ…ΰΆ΄ΰ·’ ΰΆ”ΰΆΆΰΆ§ ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰΆΊΰ·…ΰ·’ ΰΆ΄ΰ·–ΰΆ»ΰΆ«ΰΆΊ ࢚ࢻ ΰΆ±ΰ·€ ΰ·€ΰ·’ΰ·ΰ·šΰ·‚ΰ·ΰΆ‚ΰΆœ ΰΆ…ΰΆ­ΰ·Šΰ·€ΰ·’ΰΆ―ΰ·’ΰΆ± ΰΆ½ΰ·™ΰ·ƒ ࢺෝ࢒ࢱා ΰΆšΰΆ»ΰΆΈΰ·”!", + "components.newversion.new_version_component.link": "ࢱැවࢭ ΰΆ΄ΰ·–ΰΆ»ΰΆ«ΰΆΊΰΆ§ ΰΆ”ΰΆΆΰΆ±ΰ·ŠΰΆ±", + "components.account_verication_status_blocked": "ΰΆ…ΰΆœΰ·”ΰ·…ΰ·” ࢯࢸා ΰΆ‡ΰΆ­", + "components.richtexteditor.toolbar.code": "ΰΆšΰ·™ΰ·ŠΰΆ­ΰΆΊ", + "scenes.apps.tasks.select_user": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆš ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ±", + "components.calendar.repetition.weekly_on": "සࢭිࢴࢭා {{$1}}", + "scenes.app.channelsbar.currentuser.invited_status": "ΰΆ”ΰΆΆ ΰΆ…ΰΆΈΰ·”ΰΆ­ΰ·ŠΰΆ­ΰ·™ΰΆšΰ·’.", + "scenes.app.channelsbar.channelsworkspace.channel_title.favorite": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰΆ­ΰΆΈΰΆΊΰΆ±ΰ·Š", + "scenes.app.workspaces.create_company.title": "ࢸා࢜ේ ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.channelsbar.currentuser.add_apps": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.account.identity": "ΰΆ…ΰΆ±ΰΆ±ΰ·Šβ€ΰΆΊΰΆ­ΰ·ΰ·€ΰΆΊ", + "scenes.app.popup.appsparameters.pages.api_data_description": "ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š ΰΆΊΰ·™.ΰΆšΰ·Šβ€ΰΆ».ΰΆΈΰ·”. සࢳහා ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆΊΰ·ΰΆ’ΰΆ±ΰ·€ΰΆ­ΰ·Š ࢯࢭ්ࢭ.", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.loader": "ΰΆ­ΰ·€ ΰΆ΄ΰ·–ΰΆ»ΰΆ«ΰΆΊ", + "general.re_send": "ࢱැවࢭ ΰΆΊΰ·€ΰΆ±ΰ·ŠΰΆ±", + "components.locked_features.locked_guests_popup.or": "හෝ", + "scenes.app.channelsbar.currentuser.disable_notifications": "ΰΆ…ΰΆΆΰΆ½ ࢚ࢻࢱ්ࢱ", + "scenes.app.channelsbar.currentuser.disabling_notifications": "ࢴැࢺ࢚ࢧ ΰΆ…ΰΆΆΰΆ½ ࢚ࢻࢱ්ࢱ", + "scenes.apps.drive.no_storage_app_alert": "ࢢාහිࢻ ΰΆ†ΰΆ ΰΆΊΰΆ±ΰΆΊ ΰΆ‘ΰΆšΰΆ­ΰ·” ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆ‰ΰΆ© ΰΆ―ΰ·™ΰΆ± ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š ΰΆ”ΰΆΆ ΰ·ƒΰΆ­ΰ·”ΰ·€ ࢱැࢭ.", + "scenes.app.popup.workspaceparameter.admin_current_status": "ΰΆ”ΰΆΆ ΰΆ΄ΰΆ»ΰ·’ΰΆ΄ΰ·ΰΆ½ΰΆšΰΆΊΰ·™ΰΆšΰ·’.", + "scenes.app.popup.workspaceparameter.pages.weight_max_small_text": "ΰΆ‹ΰΆ΄ΰΆ»ΰ·’ΰΆΈ ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆΈΰ·ΰΆ«ΰΆΊ ΰΆΈΰ·™.ΰΆΆ. 5.", + "components.searchpopup.mentions": "ΰ·ƒΰ·ΰΆ³ΰ·„ΰ·”ΰΆΈΰ·Š", + "components.reminder.notification": "ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·Š", + "components.attachmentpicker.from_computer": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ‹ΰΆ΄ΰ·ΰΆ‚ΰΆœΰΆΊΰ·™ΰΆ±ΰ·Š", + "scenes.apps.drive.move_text2": "ΰΆœΰ·™ΰΆ±ΰΆΊΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.calendar.video_link": "සࢢැࢳිࢺ ΰ·€ΰ·’ΰ·€ΰ·˜ΰΆ­ ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆ”ΰΆΆΰΆ±ΰ·ŠΰΆ±", + "components.inputs.input_with_select.button.tooltip": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰ·š ΰΆ…ΰΆ‚ΰ·ΰΆΊΰΆšΰ·Š ΰ·ƒΰΆšΰ·ƒΰΆ±ΰ·ŠΰΆ±", + "scenes.app.channelsbar.hide_discussion_leaving.menu": "ΰ·ƒΰ·ΰΆšΰΆ ΰ·ŠΰΆ‘ΰ· ΰ·ƒΰΆŸΰ·€ΰΆ±ΰ·ŠΰΆ±", + "components.account_verification_status_sentence": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈΰ·š ΰΆ­ΰΆ­ΰ·Šΰ·€ΰΆΊ: {{$1}}", + "scenes.apps.drive.new_link_title": "ΰΆ±ΰ·€ සࢢැࢳිࢺ", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_input_placeholder": "ΰΆ”ΰΆΆΰΆ§ ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š 10 ΰΆ§ වࢩා ΰΆ‘ΰΆšΰΆ­ΰ·” ΰΆšΰ·… ΰΆ±ΰ·œΰ·„ΰ·ΰΆšΰ·’ΰΆΊ", + "general.user.role.company.guest": "ΰΆ…ΰΆΈΰ·”ΰΆ­ΰ·ŠΰΆ­ΰ·", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_text": " ΰ·€ΰ·™ΰΆ±ΰ·”ΰ·€ΰΆ§", + "components.emoji_picker.categories.symbols": "ΰ·ƒΰΆ‚ΰΆšΰ·šΰΆ­", + "scenes.app.workspaces.welcome_page.add_new_email": "ΰ·€ΰ·’-ࢭැࢴෑࢽ ΰΆ‘ΰΆšΰΆ­ΰ·”ΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.workspaces.welcome_page.new_email": "ΰΆ―ΰ·Šΰ·€ΰ·’ΰΆ­ΰ·“ΰΆΊΰ·’ΰΆš ΰ·€ΰ·’-ΰΆ­ΰ·ΰΆ΄ΰ·‘ΰΆ½ΰΆšΰ·Š ΰΆ‘ΰΆšΰΆ­ΰ·” ࢚ࢻࢱ්ࢱ", + "scenes.login.forgot_password.finished": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊ ΰ·ƒΰ·ΰΆ»ΰ·ŠΰΆΰΆšΰ·€ ΰΆΊΰ·ΰ·€ΰΆ­ΰ·ŠΰΆšΰ·ΰΆ½ ΰΆšΰ·™ΰΆ»ΰ·’ΰΆ«ΰ·’.", + "components.calendar.repetition.custom": "ΰΆ…ΰΆ·ΰ·’ΰΆ»ΰ·”ΰΆ ΰ·’...", + "components.calendar.repetition.on": "ΰ·ƒΰΆšΰ·Šβ€ΰΆ»ΰ·“ΰΆΊΰΆΊΰ·’", + "components.calendar.repetition.months": "ࢸාස(ΰΆΊ)", + "scenes.app.channelsbar.currentuser.change_my_status": "ΰΆ­ΰΆ­ΰ·Šΰ·€ΰΆΊ ΰ·€ΰ·™ΰΆ±ΰ·ƒΰ·Š ࢚ࢻࢱ්ࢱ", + "scenes.app.channelsbar.currentuser.collaborateurs": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š", + "scenes.app.channelsbar.currentuser.disabling_notifications_until": "ΰ·„ΰ·™ΰΆ§ ΰΆ΄ΰ·™.ΰ·€. 9 ΰΆ―ΰΆšΰ·Šΰ·€ΰ· ΰΆ…ΰΆΆΰΆ½ ࢚ࢻࢱ්ࢱ", + "scenes.app.channelsbar.currentuser.user_parameter": "ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·š ΰ·ƒΰ·ΰΆšΰ·ƒΰ·”ΰΆΈΰ·Š", + "scenes.apps.drive.new_file_title": "ΰΆ±ΰ·€ ΰΆœΰ·œΰΆ±ΰ·”ΰ·€", + "services.apps.calendar.move_icon": "ΰΆœΰ·™ΰΆ±ΰΆΊΰΆ±ΰ·ŠΰΆ±", + "scenes.login.home.create_account": "ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈΰΆšΰ·Š ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "scenes.login.create_account.step_2_subtitle_a": "ΰ·€ΰ·™ΰΆ±ΰΆ­ΰ·Š ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·ŠΰΆ§ හࢳුࢱා ΰΆœΰ·ΰΆ±ΰ·“ΰΆΈΰΆ§ ΰ·ƒΰΆΈΰ·ŠΰΆ΄ΰ·–ΰΆ»ΰ·ŠΰΆ« ΰΆ±ΰΆΈ ΰΆ‘ΰΆšΰΆ­ΰ·” ࢚ࢻࢱ්ࢱ.", + "scenes.app.workspaces.create_company.invitations.title_2": "࢚ࢫ්ࢩාࢺࢸࢧ ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š ΰΆ‘ΰΆšΰΆ­ΰ·” ࢚ࢻࢱ්ࢱ.", + "scenes.app.workspaces.welcome_page.add_secondary_emails": "ΰΆ―ΰ·Šΰ·€ΰ·’ΰΆ­ΰ·“ΰΆΊΰ·’ΰΆš ΰ·€ΰ·’-ΰΆ­ΰ·ΰΆ΄ΰ·‘ΰΆ½ΰΆšΰ·Š ΰΆ‘ΰΆšΰΆ­ΰ·” ࢚ࢻࢱ්ࢱ", + "scenes.app.workspaces.welcome_page.welcome_header": "ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š ΰ·€ΰ·™ΰΆ­ ΰ·ƒΰ·ΰΆ―ΰΆ»ΰΆΊΰ·™ΰΆ±ΰ·Š ΰΆ΄ΰ·’ΰ·…ΰ·’ΰΆœΰΆ±ΰ·’ΰΆΈΰ·”!", + "scenes.apps.account.account.password.description": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊ ΰ·€ΰ·™ΰΆ±ΰ·ƒΰ·Š ࢚ࢻࢱ්ࢱ.", + "scenes.app.channelsbar.channelsworkspace.channel_title": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·", + "scenes.login.forgot_password.password_dont_match": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ― ࢱො࢜ැࢽࢴේ හෝ ࢒වා ࢉࢭා ΰΆšΰ·™ΰΆ§ΰ·’ ΰΆΊ. ΰΆ…ΰ·€ΰΆΈ ΰ·€ΰ·ΰΆΊΰ·™ΰΆ±ΰ·Š ΰΆ…ΰΆšΰ·”ΰΆ»ΰ·” 8 ්࢚ ΰ·ƒΰ·„ΰ·’ΰΆ­ ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊΰΆšΰ·Š ࢺොࢯࢱ්ࢱ.", + "scenes.app.popup.adduser.magiclinks.new_link_generated": "ΰΆ±ΰ·€ ΰ·ƒΰΆΆΰ·ΰΆ³ΰ·’ΰΆΊΰΆšΰ·Š ΰΆ’ΰΆ±ΰΆ±ΰΆΊ ΰΆšΰ·™ΰΆ»ΰ·’ΰΆ«ΰ·’", + "scenes.app.popup.adduser.magiclinks.action_generate": "ΰΆ’ΰΆ±ΰΆ±ΰΆΊ ࢚ࢻࢱ්ࢱ", + "scenes.app.popup.adduser.magiclinks.copied_to_clipboard": "ΰ·ƒΰ·ΰΆ»ΰ·ŠΰΆΰΆšΰ·€ ΰΆ΄ΰ·ƒΰ·”ΰΆ»ΰ·”ΰΆ΄ΰ·”ΰ·€ΰΆ»ΰ·”ΰ·€ΰΆ§ ΰΆ΄ΰ·’ΰΆ§ΰΆ΄ΰΆ­ΰ·Š ΰΆšΰ·™ΰΆ»ΰ·’ΰΆ«ΰ·’", + "scenes.app.popup.adduser.magiclinks.action_copy": "ΰΆ΄ΰ·’ΰΆ§ΰΆ΄ΰΆ­ΰ·Š", + "scenes.app.popup.adduser.magiclinks.genrator_info": "වැࢩࢢිࢧࢸ ࢆࢻාࢰࢱා සࢢැࢳිࢺ", + "scenes.app.popup.appsparameters.pages.json_configuration_information": "ΰΆ”ΰΆΆΰΆœΰ·š ΰ·€ΰ·’ΰΆ±ΰ·Šβ€ΰΆΊΰ·ΰ·ƒΰΆΊ JSON ΰΆ†ΰΆšΰ·˜ΰΆ­ΰ·’ΰΆΊΰ·™ΰΆ±ΰ·Š ΰΆ’ΰΆ±ΰΆ±ΰΆΊ ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ½ΰ·šΰΆ›ΰΆ±ΰΆΊ ΰ·€ΰ·™ΰΆ­ ࢺࢱ්ࢱ.", + "scenes.app.popup.appsparameters.pages.publication_label": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆšΰ·ΰ·ΰΆ±ΰΆΊ", + "scenes.app.popup.appsparameters.pages.publish_app_label": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·ƒΰ·’ΰΆ―ΰ·ŠΰΆ° ࢚ࢻࢱ්ࢱ", + "scenes.app.popup.appsparameters.pages.remove_app_from_company": "ΰ·ƒΰΆΈΰ·ƒΰ·ŠΰΆ ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·™ΰΆ±ΰ·ŠΰΆΈ ΰΆ‰ΰ·€ΰΆ­ΰ·Š ࢚ࢻࢱ්ࢱ", + "scenes.app.popup.appsparameters.pages.remove_app_from_workspace": "ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·™ΰΆ±ΰ·Š ΰΆ‰ΰ·€ΰΆ­ΰ·Š ࢚ࢻࢱ්ࢱ", + "scenes.app.popup.createworkspacepage.placeholder_name": "ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·š ΰΆ±ΰΆΈ", + "scenes.app.popup.userparameter.pages.frequency_notif_configuration_description": "ΰΆ’ΰΆ‚ΰΆœΰΆΈ ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·Š ΰ·€ΰ·ΰΆ»ΰΆœΰΆ«ΰΆ± ΰ·ƒΰΆšΰ·ƒΰΆ±ΰ·ŠΰΆ±.", + "scenes.app.popup.userparameter.pages.frequency_notif_subtitle": "ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·Š වාࢻ ࢜ࢫࢱ", + "scenes.app.popup.appsparameters.pages.title_tester": "ΰΆ§ΰ·Šΰ·€ΰ·™ΰΆšΰ·ŠΰΆšΰ·šΰΆ­ ΰΆ…ΰΆ­ΰ·Š", + "scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description": "ΰ·€ΰ·’-ࢭැࢴැࢽ් ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·Š වාࢻ ࢜ࢫࢱ ΰ·ƒΰΆšΰ·ƒΰΆ±ΰ·ŠΰΆ±.", + "scenes.app.popup.userparameter.pages.keywords_notif_description": "ΰΆ΄ΰ·„ΰΆ­ ΰΆΈΰ·–ΰΆ½ΰΆ΄ΰΆ― ΰΆ‰ΰ·ƒΰ·ŠΰΆΈΰΆ­ΰ·” ࢚ࢻࢱ්ࢱ:", + "scenes.app.popup.workspaceparameter.pages.quit_workspace_menu": "ΰΆΈΰ·™ΰΆΈ වැࢩࢢිࢸ ΰ·„ΰ·ΰΆ»ΰΆΊΰΆ±ΰ·ŠΰΆ±", + "scenes.app.popup.workspaceparameter.pages.worspace_notif": "වැࢩࢢිࢸ", + "scenes.app.popup.workspaceparameter.pages.no_app_information": "ΰΆΈΰ·™ΰΆΈ වැࢩࢢිࢸෙහි ΰΆ”ΰΆΆ ΰ·ƒΰΆ­ΰ·”ΰ·€ ΰΆšΰ·’ΰ·ƒΰ·’ΰΆΈ ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰΆšΰ·Š ࢱැࢭ", + "scenes.app.popup.workspaceparameter.admin_manager_current_status": "ΰΆ”ΰΆΆ වැࢩࢢිࢸෙහි ΰΆ΄ΰΆ»ΰ·’ΰΆ΄ΰ·ΰΆ½ΰΆšΰΆΊΰ·’.", + "scenes.app.popup.workspaceparameter.pages.error_workspace_member": "ΰΆ‘ΰΆΊ ΰΆ‰ΰ·€ΰΆ­ΰ·Š ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆ”ΰΆΆ ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·š ΰΆ­ΰΆ±ΰ·’ΰ·€ ΰ·ƒΰ·’ΰΆ§ΰ·’ΰΆΊ ΰΆΊΰ·”ΰΆ­ΰ·”ΰΆΊ. ΰ·ƒΰ·„ΰΆšΰ·ΰΆ»ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š ΰΆ‰ΰ·€ΰΆ­ΰ·Š ࢚ࢻ ΰΆΊΰ·…ΰ·’ ΰΆ‹ΰΆ­ΰ·Šΰ·ƒΰ·ΰ·„ ࢚ࢻࢱ්ࢱ.", + "scenes.app.mainview.quick_search_placeholder": "ΰΆ‰ΰΆšΰ·ŠΰΆΈΰΆ±ΰ·Š ΰ·ƒΰ·™ΰ·€ΰ·”ΰΆΈ", + "scenes.app.popup.userparameter.personnal_workspaces_title": "ΰΆ”ΰΆΆΰΆœΰ·š ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·Š", + "scenes.apps.drive.go_out_trash_menu": "ΰΆšΰ·”ΰΆ«ΰ·”ΰΆšΰ·–ΰΆ©ΰΆΊ ΰ·„ΰ·ΰΆ»ΰΆΊΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.drive.go_trash_menu": "ΰΆšΰ·”ΰΆ«ΰ·”ΰΆšΰ·–ΰΆ©ΰΆΊΰΆ§ ࢺࢱ්ࢱ", + "scenes.apps.messages.message.show_button": "ࢯࢻ්ශࢱࢺ", + "scenes.apps.messages.message.show_responses_button": "ΰ·ƒΰ·’ΰΆΊΰ·…ΰ·” ΰΆ‹ΰΆ­ΰ·ŠΰΆ­ΰΆ» ΰΆ―ΰΆšΰ·’ΰΆ±ΰ·ŠΰΆ±", + "components.workspace.list_manager.current_space": "ΰ·€ΰΆ­ΰ·ŠΰΆΈΰΆ±ΰ·Š වැࢩࢢිࢸ", + "components.upload.drop_files": "ΰ·ƒΰ·’ΰΆΊΰ·…ΰ·” ΰΆœΰ·œΰΆ±ΰ·” ΰΆΈΰ·™ΰ·„ΰ·’ ࢯࢸࢱ්ࢱ", + "components.tagpicker.tag_name": "ΰΆ…ΰΆ±ΰΆ±ΰ·Šβ€ΰΆΊΰΆ±ΰΆΊΰ·š ΰΆ±ΰΆΈ", + "components.reminder.hours_bef": "ࢴැࢺ ΰΆšΰ·’ΰ·„ΰ·’ΰΆ΄ΰΆΊΰΆšΰΆ§ ΰΆ΄ΰ·™ΰΆ»", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.website_item": "ΰ·€ΰ·’ΰΆΊΰΆΈΰΆ± ΰΆ…ΰΆ©ΰ·€ΰ·’ΰΆΊ", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.version_item": "ࢅࢱුවාࢯࢺ", + "scenes.app.integrations_parameters.company_applications_table.name": "ΰΆ±ΰΆΈ", + "scenes.app.integrations_parameters.company_applications_table.title": "ΰΆ”ΰΆΆΰΆœΰ·š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ ΰΆ­ΰ·”ΰ·… ΰ·ƒΰ·ŠΰΆΰ·ΰΆ΄ΰ·’ΰΆ­ΰΆΊΰ·’", + "components.locked_features.locked_workspace_popup.subtitle": "ΰΆ±ΰ·œΰΆΈΰ·’ΰΆ½ΰ·š ࢅࢱුවාࢯࢺෙහි, ΰΆ”ΰΆΆΰΆœΰ·š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ ΰΆ­ΰ·”ΰ·… ΰΆ‘ΰΆšΰ·Š ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰΆšΰ·Š ࢴࢸࢫ්࢚ ΰΆ½ΰΆ― ΰ·„ΰ·ΰΆšΰ·’ΰΆΊ.", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.description_item": "වැࢫුࢸ", + "components.locked_features.locked_drive_popup.title": "ΰΆ”ΰΆΆ ΰΆ°ΰ·ΰ·€ΰΆšΰΆΊΰ·š සීࢸාවࢸ ࢽ࢟ා ΰ·€ΰ·“ ΰΆ‡ΰΆ­", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.created_item": "ΰ·ƒΰ·‘ΰΆ―ΰ·– ΰΆ―ΰ·’ΰΆ±ΰΆΊ", + "scenes.app.integrations_parameters.company_applications_table.more_menu.show_application": "ΰΆ΄ΰ·™ΰΆ±ΰ·Šΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.join.join_the_team_button": "࢚ࢫ්ࢩාࢺࢸࢧ ΰΆ‘ΰΆšΰ·Šΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.integrations_parameters.company_applications_table.more_menu.remove_application": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·™ΰΆ±ΰ·Š ΰΆ‰ΰ·€ΰΆ­ΰ·Š ࢚ࢻࢱ්ࢱ", + "scenes.join.wrong_link_description": "ΰΆ”ΰΆΆΰΆ§ ΰΆΈΰ·™ΰΆΈ ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰΆ§ ΰΆ‘ΰΆšΰ·Šΰ·€ΰ·“ΰΆΈΰΆ§ ࢆࢻාࢰࢱා ΰΆšΰ·… ΰΆ΄ΰ·”ΰΆ―ΰ·ŠΰΆœΰΆ½ΰΆΊΰ·ΰΆœΰ·™ΰΆ±ΰ·Š ΰΆ±ΰ·€ ΰ·ƒΰΆΆΰ·ΰΆ³ΰ·’ΰΆΊΰΆšΰ·Š ΰ·€ΰ·’ΰΆΈΰ·ƒΰΆ±ΰ·ŠΰΆ± හෝ ΰΆ”ΰΆΆΰΆœΰ·šΰΆΈ ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰΆšΰ·Š ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "app.state.recoil.hooks.use_current_company_applications.toaster_add": "ΰΆ”ΰΆΆΰΆœΰ·š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰΆ§ {{$1}} ΰ·ƒΰ·ΰΆ»ΰ·ŠΰΆΰΆšΰ·€ ΰΆ‘ΰΆšΰ·Š ΰΆšΰ·™ΰΆ»ΰ·’ΰΆ«ΰ·’", + "scenes.join.twake_description": "ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š ΰΆΊΰΆ±ΰ·” ΰΆ”ΰΆΆΰΆœΰ·š ࢚ࢫ්ࢩාࢺࢸ් ࢡࢽࢯාࢺිࢭාව වැࢩිࢯිࢺුࢫු ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈ සࢳහා ࢜ොࢩࢱ࢜ා ΰΆ‡ΰΆ­ΰ·’ ΰ·€ΰ·’ΰ·€ΰ·˜ΰΆ­ ΰΆΈΰ·–ΰΆ½ΰ·ΰ·ΰ·Šβ€ΰΆ» ΰ·ƒΰΆ‚ΰΆ›ΰ·Šβ€ΰΆΊΰ·ΰΆ‚ΰΆš ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰΆšΰ·’", + "scenes.apps.messages.input.replied_to": "ΰ·€ΰ·™ΰΆ­ ΰΆ΄ΰ·’ΰ·…ΰ·’ΰΆ­ΰ·”ΰΆ»ΰ·” ΰΆ―ΰ·”ΰΆ«ΰ·’ ", + "components.searchpopup.tasks": "࢚ාࢻ්ࢺࢺࢱ්", + "scenes.join.loading": "ΰΆ΄ΰ·–ΰΆ»ΰΆ«ΰΆΊ ΰ·€ΰ·™ΰΆΈΰ·’ΰΆ±ΰ·Šβ€¦", + "scenes.join.wrong_link_title": "ΰΆΈΰ·™ΰΆΈ සࢢැࢳිࢺ ΰΆ­ΰ·€ΰΆ―ΰ·”ΰΆ»ΰΆ§ΰΆ­ΰ·Š ࢱැࢭ", + "scenes.join.create_the_company_button": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "scenes.join.login_first_button": "ΰΆ΄ΰ·”ΰΆ»ΰΆ±ΰ·ŠΰΆ± හෝ ΰΆ΄ΰ·…ΰΆΈΰ·”ΰ·€ ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈΰΆšΰ·Š ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "scenes.join.join_workspace_from_company": "{{$2}} ΰ·€ΰ·™ΰΆ­ΰ·’ΰΆ±ΰ·Š {{$1}} හා ΰΆ‘ΰΆšΰ·Šΰ·€ΰΆ±ΰ·ŠΰΆ±!", + "scenes.app.integrations_parameters.applications_table.name": "ΰΆ±ΰΆΈ", + "scenes.app.integrations_parameters.title": "ΰΆ…ΰΆ±ΰ·”ΰΆšΰΆ½ΰΆ±", + "scenes.app.integrations_parameters.applications_table.title": "ΰ·€ΰ·™ΰΆ±ΰΆ­ΰ·Š ΰΆ…ΰΆ±ΰ·”ΰΆšΰΆ½ΰΆ±", + "scenes.app.integrations_parameters.applications_table.search_placeholder": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ±", + "scenes.app.integrations_parameters.company_application_popup.tag": "ΰ·ƒΰ·ŠΰΆΰ·ΰΆ΄ΰ·’ΰΆ­ΰΆΊΰ·’", + "scenes.app.integrations_parameters.company_application_popup.btn": "ΰ·ƒΰ·ŠΰΆΰ·ΰΆ΄ΰΆ±ΰΆΊ", + "scenes.app.integrations_parameters.company_application_popup.tab_btn_info": "ΰΆ­ΰ·œΰΆ»ΰΆ­ΰ·”ΰΆ»ΰ·”", + "scenes.app.workspaces.create_company.group_data.group_main_activity.printing_paper": "ΰΆΈΰ·”ΰΆ―ΰ·Šβ€ΰΆ»ΰΆ«ΰΆΊ / ΰΆšΰΆ©ΰΆ―ΰ·ΰ·ƒΰ·’ΰΆΊ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.construction_building": "ΰΆ‰ΰΆ―ΰ·’ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰ·Š / ΰΆœΰ·œΰΆ©ΰΆ±ΰ·ΰΆœΰ·’ΰΆ½ΰ·’ ΰΆ―ΰ·Šβ€ΰΆ»ΰ·€ΰ·ŠΰΆΊ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.materials": "ΰΆ―ΰ·Šβ€ΰΆ»ΰ·€ΰ·ŠΰΆΊ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.chemistry": "ࢻසාࢺࢱࢺ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.trade_commerce_distribution": "ΰ·€ΰ·™ΰ·…ΰΆ³ / වාࢫි࢒ / ࢢෙࢯා හැࢻීࢸ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.publishing_communication_multimedia": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆšΰ·ΰ·ΰΆ±ΰΆΊ / ΰ·ƒΰΆ±ΰ·ŠΰΆ±ΰ·’ΰ·€ΰ·šΰΆ―ΰΆ±ΰΆΊ / ΰΆΆΰ·„ΰ·”ΰΆΈΰ·ΰΆ°ΰ·Šβ€ΰΆΊ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.studies_and_advice": "ΰΆ…ΰΆ°ΰ·Šβ€ΰΆΊΰΆΊΰΆ± ΰ·ƒΰ·„ ΰΆ‹ΰΆ΄ΰΆ―ΰ·™ΰ·ƒΰ·Š", + "scenes.app.workspaces.create_company.group_data.group_main_activity.pharmaceutical_industry": "ΰΆ–ΰ·‚ΰΆ° ࢚ࢻ්ࢸාࢱ්ࢭࢺ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.it_telecom": "ࢭො.ࢭා. / ΰ·€ΰ·’ΰΆ―ΰ·”ΰΆ½ΰ·’ ΰ·ƒΰΆ‚ΰΆ―ΰ·šΰ·", + "scenes.app.workspaces.create_company.group_data.group_type.company": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ හෝ ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰ·ΰΆ‚ΰ·ΰΆΊ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.entertainment": "ΰ·€ΰ·’ΰΆ±ΰ·ΰΆ―ΰ·ΰ·ƒΰ·Šΰ·€ΰ·ΰΆ―ΰΆΊ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.textile_clothing_shoes": "ΰΆ»ΰ·™ΰΆ―ΰ·’ / ΰΆ‡ΰΆ³ΰ·”ΰΆΈΰ·Š / ΰΆ΄ΰ·ΰ·€ΰ·„ΰΆ±ΰ·Š", + "scenes.app.workspaces.create_company.group_data.group_main_activity.research": "ΰΆ΄ΰΆ»ΰ·ŠΰΆΊΰ·šΰ·‚ΰΆ«", + "scenes.app.workspaces.create_company.group_data.group_main_activity.education": "ΰΆ…ΰΆ°ΰ·ŠΰΆΊΰ·ΰΆ΄ΰΆ±", + "components.users_picker.add_me": "ࢸාව ΰΆ‘ΰΆšΰ·ŠΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.workspaces.create_company.invitations.title": "ΰΆ”ΰΆΆΰΆœΰ·š වැࢩࢢිࢸ ΰ·€ΰ·’ΰΆ±ΰ·Šβ€ΰΆΊΰ·ΰ·ƒΰΆœΰΆ­ ࢚ࢻࢱ්ࢱ.", + "scenes.apps.drive.right_preview.operations_delete": "ΰΆšΰ·”ΰΆ«ΰ·”ΰΆšΰ·–ΰΆ©ΰΆΊΰΆ§ ΰΆœΰ·™ΰΆ±ΰΆΊΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.account.notifications.disturb_option_c": " (ΰ·ƒΰ·ŠΰΆΰ·ΰΆ±ΰ·“ΰΆΊ ΰ·€ΰ·šΰΆ½ΰ·ΰΆšΰΆ½ΰ·ΰΆ΄ΰΆΊ)", + "scenes.apps.parameters.workspace_sections.workspace": "වැࢩࢢිࢸ", + "scenes.apps.parameters.group_sections.workspaces": "ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·Š", + "scenes.apps.tasks.boards": "ΰΆ΄ΰ·”ΰ·€ΰΆ»ΰ·”", + "scenes.apps.tasks.task": "࢚ාࢻ්ࢺࢺ", + "scenes.apps.tasks.no_tasks": "࢚ාࢻ්ࢺࢺ ࢱැࢭ", + "scenes.apps.tasks.list_modal.archive_all_tasks": "ΰ·ƒΰ·’ΰΆΊΰ·…ΰ·”ΰΆΈ ࢚ාࢻ්ࢺࢺ ΰ·ƒΰΆ‚ΰΆ»ΰΆšΰ·Šβ€ΰ·‚ΰΆ«ΰΆΊ", + "scenes.apps.tasks.list_modal.remove_archived_tasks": "({{$1}}) ΰ·ƒΰΆ‚ΰΆ»ΰΆšΰ·Šβ€ΰ·‚ΰ·’ΰΆ­ ࢚ාࢻ්ࢺࢺ ΰΆ‰ΰ·€ΰΆ­ΰ·ŠΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.tasks.new_board.title": "ΰΆ±ΰ·€ ΰΆ΄ΰ·”ΰ·€ΰΆ»ΰ·”ΰ·€", + "scenes.apps.tasks.new_board.edit_title": "ΰΆ΄ΰ·”ΰ·€ΰΆ»ΰ·”ΰ·€ ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ", + "scenes.apps.tasks.task.description": "ΰ·ƒΰ·€ΰ·’ΰ·ƒΰ·ŠΰΆ­ΰΆ»ΰΆΊ", + "scenes.apps.tasks.task.assignees": "ΰΆ΄ΰ·ΰ·€ΰΆ»ΰ·”ΰΆΈΰ·ŠΰΆ½ΰ·ΰΆ·ΰ·“ΰΆ±ΰ·Š", + "scenes.app.workspaces.welcome_page.lets_go": "ΰΆ…ΰΆ΄ΰ·’ ΰΆΊΰΆΈΰ·”!", + "scenes.apps.account.account.emails.description": "ΰΆ”ΰΆΆΰΆœΰ·š ΰ·€ΰ·’ΰ·€ΰ·’ΰΆ° ΰ·€ΰ·’-ࢭැࢴැࢽ් ΰΆ½ΰ·’ΰΆ΄ΰ·’ΰΆ± ΰΆšΰ·…ΰΆΈΰΆ±ΰ·ΰΆšΰΆ»ΰΆ«ΰΆΊ ࢚ࢻࢱ්ࢱ.", + "scenes.login.create_account.step_2_subtitle_b": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ―ΰ·”.࢚. ΰΆ…ΰΆ‚ΰΆšΰΆΊ ΰΆ΄ΰ·žΰΆ―ΰ·ŠΰΆœΰΆ½ΰ·’ΰΆšΰ·€ ΰΆ­ΰ·’ΰΆΆΰ·™ΰΆ±ΰ·” ΰΆ‡ΰΆ­.", + "scenes.app.workspaces.create_company.company_name.title_2": "ΰΆ”ΰΆΆΰΆœΰ·š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰΆ±ΰΆΈ ΰΆ―ΰΆšΰ·Šΰ·€ΰΆ±ΰ·ŠΰΆ±.", + "scenes.app.workspaces.create_company.importations.title_1": "ࢯැࢱࢧࢸࢭ් ΰ·ƒΰΆ‚ΰΆ›ΰ·Šβ€ΰΆΊΰ·ΰΆ‚ΰΆš ΰΆΈΰ·™ΰ·€ΰΆ½ΰΆΈΰ·Š ΰ·ƒΰΆΈΰΆŸ වැࢩ ΰΆšΰΆ»ΰΆ±ΰ·€ΰ·ΰΆ―? ࢯැࢱ් ΰΆ”ΰΆΆΰΆœΰ·š ΰΆΈΰ·™ΰ·€ΰΆ½ΰΆΈΰ·Š ࢆࢺාࢭ හෝ ΰΆ…ΰΆ±ΰ·”ΰΆšΰΆ½ΰΆ±ΰΆΊ ࢚ࢻࢱ්ࢱ!", + "scenes.app.workspaces.welcome_page.no_company_subtitle": "ΰΆ­ΰ·€ΰΆΈ ΰΆšΰ·’ΰ·ƒΰ·’ΰ·€ΰ·™ΰΆšΰ·Š ΰΆ”ΰΆΆΰΆ§ ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰΆšΰΆ§ ࢆࢻාࢰࢱා ࢚ࢻ ࢱැࢭි ΰΆΆΰ·€ ΰΆ΄ΰ·™ΰΆ±ΰ·š.", + "scenes.app.workspaces.welcome_page.see_you_soon": "ΰΆ‰ΰΆšΰ·ŠΰΆΈΰΆ«ΰ·’ΰΆ±ΰ·Š ΰΆΈΰ·”ΰΆ«ΰΆœΰ·ΰ·ƒΰ·™ΰΆΈΰ·”!", + "scenes.app.workspaces.welcome_page.add_secondary_emails_comment": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈΰΆ§ ΰ·€ΰ·’-ࢭැࢴැࢽ් ΰΆšΰ·’ΰ·„ΰ·’ΰΆ΄ΰΆΊΰΆšΰ·Š ΰΆΊΰ·™ΰΆ―ΰ·’ΰΆΊ ΰ·„ΰ·ΰΆšΰ·’ΰΆΊ; ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·Š ΰΆ‘ΰ·€ΰ·“ΰΆΈΰΆ§ ΰΆ‘ΰΆšΰ·Š ΰΆ½ΰ·’ΰΆ΄ΰ·’ΰΆ±ΰΆΊΰΆšΰ·Š ࢴࢸࢫ්࢚ ࢷාවිࢭා ΰΆšΰ·™ΰΆ»ΰ·š.", + "scenes.app.workspaces.welcome_page.done": "ΰΆΈΰΆΈ ΰΆ…ΰ·„ΰ·€ΰΆ»ΰΆΊΰ·’", + "scenes.apps.account.account.description_main": "ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·Š ΰΆΊΰ·€ΰΆ±ΰ·ŠΰΆ±ΰ·š ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ°ΰ·ΰΆ± ΰΆ½ΰ·’ΰΆ΄ΰ·’ΰΆ±ΰΆΊΰΆ§ΰΆΊ. ࢷාවිࢭා ࢚ࢻࢱ ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·Š ΰ·€ΰ·™ΰΆ­ ΰ·ƒΰ·Šΰ·€ΰΆΊΰΆ‚ΰΆšΰ·Šβ€ΰΆ»ΰ·“ΰΆΊΰ·€ ࢆࢻාࢰࢱා ࢽැࢢීࢸࢧ ΰΆ―ΰ·Šΰ·€ΰ·’ΰΆ­ΰ·“ΰΆΊΰ·’ΰΆš ΰΆ½ΰ·’ΰΆ΄ΰ·’ΰΆ± ΰΆ‰ΰΆ© ΰ·ƒΰΆ½ΰ·ƒΰΆΊΰ·’.", + "scenes.app.channelsbar.currentuser.logout": "ΰ·€ΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "app.name.twake_tasks": "࢚ාࢻ්ࢺࢺ", + "components.calendar.repetition.never": "ΰΆšΰ·€ΰΆ―ΰ·ΰ·€ΰΆ­ΰ·Š", + "components.calendar.repetition.years": "ΰΆ…ΰ·€ΰ·”ΰΆ»ΰ·”ΰΆ―ΰ·”", + "components.calendar.repetition.days": "ΰΆ―ΰ·€ΰ·ƒΰ·Š", + "scenes.app.channelsbar.currentuser.create_workspace_page": "ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰΆšΰ·Š ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.channelsbar.currentuser.workspace_parameters": "ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·š ΰ·ƒΰ·ΰΆšΰ·ƒΰ·”ΰΆΈΰ·Š", + "scenes.app.channelsbar.currentuser.workspace_info": "ΰΆ”ΰΆΆ {{$2}} ΰ·ƒΰΆΈΰ·–ΰ·„ΰΆΊΰ·™ΰΆ±ΰ·Š {{$1}} වැࢩࢢිࢸෙහි ΰ·ƒΰ·’ΰΆ§ΰ·“", + "components.calendar.repetition.after": "ΰΆ΄ΰ·ƒΰ·”", + "scenes.apps.account.identity.description": "ΰΆ…ΰΆ±ΰ·™ΰΆšΰ·”ΰΆ­ΰ·Š ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·ŠΰΆ§ ΰΆ΄ΰ·™ΰΆ±ΰ·™ΰΆ± ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ΄ΰ·…ΰΆΈΰ·” ΰΆ±ΰΆΈ, ΰΆ…ΰΆœ ΰΆ±ΰΆΈ ΰ·ƒΰ·„ ΰΆ΄ΰ·ΰΆ­ΰ·’ΰΆšΰΆ© ΰΆ»ΰ·–ΰΆ΄ΰΆΊ ΰ·€ΰ·™ΰΆ±ΰ·ƒΰ·Š ࢚ࢻࢱ්ࢱ.", + "scenes.apps.account.account.make_main": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ°ΰ·ΰΆ± ΰ·ƒΰΆšΰ·ƒΰΆ±ΰ·ŠΰΆ±", + "components.locked_features.locked_workspace_popup.title": "ΰΆ”ΰΆΆΰΆ§ ΰΆ­ΰ·€ΰΆ­ΰ·Š ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·Š ΰ·ƒΰ·‘ΰΆ―ΰ·’ΰΆΊ ΰΆ±ΰ·œΰ·„ΰ·ΰΆšΰ·’ΰΆΊ", + "scenes.app.workspaces.create_company.group_data.title": "ΰΆ…ΰΆ΄ΰ·’ ΰΆ‰ΰΆšΰ·ŠΰΆΈΰΆ±ΰ·Š ΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±ΰ·™ΰΆΈΰ·” β€” ࢇවැසි ΰ·€ΰΆ±ΰ·ŠΰΆ±ΰ·š ΰ·ƒΰΆ‚ΰΆ›ΰ·Šβ€ΰΆΊΰ·ΰΆ± ΰΆ­ΰ·œΰΆ»ΰΆ­ΰ·”ΰΆ»ΰ·” ΰΆšΰ·’ΰ·„ΰ·’ΰΆ΄ΰΆΊΰΆšΰ·Š ΰΆ΄ΰΆΈΰΆ«ΰ·’.", + "scenes.app.popup.workspaceparameter.pages.workspace_partner_tabs.members.table.tags": "ΰΆ·ΰ·–ΰΆΈΰ·’ΰΆšΰ·ΰ·€", + "scenes.app.mainview.channel_description": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ ΰ·€ΰ·’ΰ·ƒΰ·ŠΰΆ­ΰΆ» ࢚ࢻࢱ්ࢱ", + "scenes.client.channelbar.channeltemplateeditor.checkbox": "ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·š ΰ·ƒΰ·’ΰΆΊΰ·…ΰ·”ΰΆΈ ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·ŠΰΆ§ ΰΆΈΰ·™ΰΆΈ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰΆ§ ΰ·ƒΰ·Šΰ·€ΰΆΊΰΆ‚ΰΆšΰ·Šβ€ΰΆ»ΰ·“ΰΆΊΰ·€ ࢆࢻාࢰࢱා ࢚ࢻࢱ්ࢱ", + "scenes.client.channelbar.channelmemberslist.title": "{{$1}} ΰ·„ΰ·’ ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š", + "scenes.apps.parameters.workspace_sections.members.invite_all": "ΰ·ƒΰ·’ΰΆΊΰΆ½ΰ·ŠΰΆ½ΰΆ±ΰ·ŠΰΆ§ ࢆࢻාࢰࢱා ࢚ࢻࢱ්ࢱ", + "scenes.apps.calendar.modals.reminder_add": "ΰ·ƒΰ·’ΰ·„ΰ·’ΰΆšΰ·ΰΆ³ΰ·€ΰ·”ΰΆΈΰΆšΰ·Š ΰΆ‘ΰΆšΰ·ŠΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.mainview.create_account": "ΰΆ”ΰΆΆΰΆœΰ·š වැࢩࢢිࢸ ΰΆ±ΰ·œΰΆΈΰ·’ΰΆ½ΰ·š ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ± ", + "components.drive.right_preview.suppress_link": "සࢢැࢳිࢺ ࢺࢧࢴࢭ් ࢚ࢻࢱ්ࢱ", + "components.workspace.list_manager.no_workspace": "ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·Š ࢱැࢭ", + "components.workspace.list_manager.add": "ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·Š ΰΆ‘ΰΆšΰ·ŠΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "components.searchpopup.enter_text": "ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š ΰ·„ΰ·’ ΰ·ƒΰ·™ΰ·€ΰ·”ΰΆΈΰΆ§ ࢴාࢨ ΰΆšΰ·’ΰ·„ΰ·’ΰΆ΄ΰΆΊΰΆšΰ·Š ࢺොࢯࢱ්ࢱ.", + "components.searchpopup.filter_ws": "ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·Š ΰΆ΄ΰ·™ΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "components.searchpopup.tags": "ΰΆ…ΰΆ±ΰΆ±ΰ·Šβ€ΰΆΊΰΆΊΰΆ±", + "components.searchpopup.creation": "ΰ·ƒΰ·‘ΰΆ―ΰ·“ΰΆΈ", + "components.searchpopup.update_search": "ΰ·ƒΰ·™ΰ·€ΰ·”ΰΆΈ ΰΆΊΰ·ΰ·€ΰΆ­ΰ·ŠΰΆšΰ·ΰΆ½", + "scenes.apps.board.archived_tasks": "({{$1}}) ΰ·ƒΰΆ‚ΰΆ»ΰΆšΰ·Šβ€ΰ·‚ΰ·’ΰΆ­ ࢚ාࢻ්ࢺࢺࢱ්", + "scenes.apps.board.active_tasks": "ΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰ·ΰΆ­ΰ·ŠΰΆΈΰΆš ࢚ාࢻ්ࢺࢺࢱ්", + "scenes.apps.board.display_as": "ΰΆ½ΰ·™ΰ·ƒ ࢯࢻ්ශࢱࢺ", + "scenes.apps.board.new_task": "+ ΰΆ±ΰ·€ ࢚ාࢻ්ࢺࢺ", + "scenes.apps.board.all_boards": "ΰ·ƒΰ·’ΰΆΊΰ·…ΰ·” ΰΆ΄ΰ·”ΰ·€ΰΆ»ΰ·”", + "scenes.app.channelsbar.currentuser.company_messages_counter_info": "ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š ΰΆ±ΰ·œΰΆΈΰ·’ΰΆ½ΰ·š ΰΆ…ΰΆ±ΰ·”ΰ·€ΰ·ΰΆ―ΰΆΊΰ·šΰΆ―ΰ·“, ΰΆ”ΰΆΆΰΆ§ ΰΆΈΰ·‘ΰΆ­ ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ© {{$1}} ࢚ࢧ වࢩා ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·€ΰ·šΰ· ΰ·€ΰ·’ΰΆΊ ΰΆ±ΰ·œΰ·„ΰ·ΰΆšΰ·’ΰΆΊ.", + "scenes.app.channelsbar.currentuser.company_messages_counter_link": "ΰΆ­ΰ·€ ΰ·ƒΰ·ΰΆ½ΰ·ƒΰ·”ΰΆΈΰ·Š ΰΆ΄ΰ·™ΰΆ±ΰ·Šΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.channelsbar.invitation_collaboraors_tutorial": "වැࢩࢢිࢸࢧ ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š ΰ·„ΰΆ§ ࢆࢻාࢰࢱා ࢚ࢻࢱ්ࢱ.", + "scenes.app.channelsbar.company_invitation_alert_title": "ΰΆ”ΰΆΆΰΆ§ ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰΆ§ ࢆࢻාࢰࢱා ࢚ࢻ ΰΆ‡ΰΆ­ ", + "scenes.app.popup.appsparameters.pages.alert_published_app": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆšΰ·ΰ·ΰΆ±ΰΆΊ ΰΆšΰ·™ΰΆ»ΰ·’ΰΆ«ΰ·’, ΰΆ‘ΰΆΊ ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ ΰΆšΰ·… ΰΆ±ΰ·œΰ·„ΰ·ΰΆšΰ·’ΰΆΊ.", + "scenes.app.popup.appsparameters.pages.automatique_option_information": "ΰΆ”ΰΆΆ 'ΰ·ƒΰ·Šΰ·€ΰΆΊΰΆ‚ΰΆšΰ·Šβ€ΰΆ»ΰ·“ΰΆΊ' ΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰ·ΰΆ­ΰ·ŠΰΆΈΰΆš ΰΆšΰ·…ΰ·„ΰ·œΰΆ­ΰ·Š, ΰΆΈΰ·™ΰΆΈ ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰΆŠΰ·…ΰΆŸ ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·Š ΰ·€ΰΆ½ΰΆ§ ΰΆ― ΰ·ƒΰ·Šΰ·€ΰΆΊΰΆ‚ΰΆšΰ·Šβ€ΰΆ»ΰ·“ΰΆΊΰ·€ ΰΆΈΰ·™ΰΆΈ ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰΆ‘ΰΆšΰΆ­ΰ·” ΰ·€ΰ·š.", + "components.reminder.minutes_bef": "විࢱාࢩි ΰΆšΰ·’ΰ·„ΰ·’ΰΆ΄ΰΆΊΰΆšΰΆ§ ΰΆ΄ΰ·™ΰΆ»", + "scenes.app.popup.appsparameters.pages.app_update": "{{$1}} ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰΆΊΰ·ΰ·€ΰΆ­ΰ·ŠΰΆšΰ·ΰΆ½ ࢚ࢻࢱ්ࢱ (වාࢻ {{$2}} ්࢚ ࢷාවිࢭා ࢚ࢻ ΰΆ‡ΰΆ­.)", + "scenes.app.popup.appsparameters.pages.displayed_parameters_label": "ࢯࢻ්ශࢱ ΰ·ƒΰ·ΰΆšΰ·ƒΰ·”ΰΆΈΰ·Š", + "scenes.app.popup.appsparameters.pages.event_subtitle": "ΰ·ƒΰ·’ΰΆ―ΰ·”ΰ·€ΰ·“ΰΆΈΰ·Š", + "scenes.app.popup.appsparameters.pages.current_informations_apps_connectors": "ΰΆ”ΰΆΆ ΰΆ­ΰ·€ΰΆΈΰΆ­ΰ·Š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰΆšΰ·Š සාࢯා ࢱැࢭ. ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰΆšΰ·Š හෝ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆšΰΆΊΰΆšΰ·Š ΰ·ƒΰ·‘ΰΆ―ΰ·“ΰΆΈΰΆ§ ΰΆ΄ΰ·™ΰΆ» ΰΆ‘ΰΆΊ ࢯැࢱࢧࢸࢭ් ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š ΰ·€ΰ·™ΰ·…ΰΆ³ΰΆ΄ΰ·œΰ·…ΰ·™ΰ·„ΰ·’ ࢱැࢭි ΰΆΆΰ·€ ΰ·ƒΰ·„ΰΆ­ΰ·’ΰΆš ࢚ࢻ࢜ࢱ්ࢱ.", + "scenes.app.popup.appsparameters.pages.instruction_message_twakecode": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊ JSON ΰΆ†ΰΆšΰ·˜ΰΆ­ΰ·’ΰΆΊΰ·™ΰΆ±ΰ·Š ΰΆ½ΰ·’ΰ·€ΰ·“ΰΆΈΰΆ§ ΰΆ…ΰΆ»ΰΆΉΰΆ±ΰ·ŠΰΆ±.", + "scenes.app.popup.appsparameters.pages.description_label": "වැࢫුࢸ", + "scenes.app.popup.createworkspacepage.create_new_workspace": "ΰΆ±ΰ·€ ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰΆšΰ·Š ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.popup.appsparameters.pages.error_app_update_message": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰΆΊΰ·ΰ·€ΰΆ­ΰ·ŠΰΆšΰ·ΰΆ½ ΰ·€ΰ·“ΰΆΈΰ·šΰΆ―ΰ·“ ΰΆ―ΰ·ΰ·‚ΰΆΊΰΆšΰ·Š ΰ·ƒΰ·’ΰΆ―ΰ·”ΰ·€ΰ·’ΰΆ«ΰ·’.", + "scenes.app.popup.createworkspacepage.add_subtitle": "ΰΆ­ΰ·€ ΰΆ‰ΰΆ© ࢇවැසිࢯ?", + "scenes.app.popup.appsparameters.pages.error_app_simple_name_message": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·™ΰ·„ΰ·’ ΰ·ƒΰΆ»ΰ·… ΰΆšΰ·… ΰΆ±ΰΆΈ ࢯැࢱࢧࢸࢭ් ΰ·€ΰ·™ΰΆ±ΰΆ­ΰ·Š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰΆšΰ·Š ࢷාවිࢭා ΰΆšΰΆ»ΰΆΊΰ·’. ΰ·€ΰ·™ΰΆ±ΰ·ƒΰ·Š ࢚ࢻࢱ්ࢱ.", + "scenes.app.popup.appsparameters.pages.waiting_availability_application": "ΰΆ»ΰ·ΰΆ³ΰ·™ΰΆΈΰ·’ΰΆ±ΰ·Š...", + "components.reminder.days_bef": "ΰΆ―ΰ·€ΰ·ƒΰ·Š ΰΆšΰ·’ΰ·„ΰ·’ΰΆ΄ΰΆΊΰΆšΰΆ§ ΰΆ΄ΰ·™ΰΆ»", + "scenes.app.popup.workspaceparameter.pages.logo_modify_description": "ΰΆΈΰ·™ΰΆΈ වැࢩࢢිࢸෙහි ΰΆ»ΰ·–ΰΆ΄ΰΆΊ ΰ·€ΰ·™ΰΆ±ΰ·ƒΰ·Š ࢚ࢻࢱ්ࢱ", + "scenes.app.popup.workspaceparameter.pages.invited_guest_check_message": "ΰ·€ΰ·’-ࢭැࢴෑࢽ හෝ ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆš ࢱාࢸࢺ ΰ·€ΰΆ½ΰΆ‚ΰΆœΰ·” ࢯැࢺි ΰΆ΄ΰΆ»ΰ·“ΰΆšΰ·Šβ€ΰ·‚ΰ· ࢚ࢻࢱ්ࢱ.", + "scenes.app.popup.workspaceparameter.pages.installed_app_information": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰΆΈΰ·™ΰΆΈ ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·š ΰ·ƒΰ·ŠΰΆΰ·ΰΆ΄ΰΆ±ΰΆΊ ࢚ࢻࢱ්ࢱ.", + "scenes.app.popup.workspaceparameter.pages.description": "වැࢫුࢸ", + "scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·ŠΰΆ§ ࢆࢻාࢰࢱࢺ", + "scenes.app.popup.workspaceparameter.pages.back_to_search_button": "ΰ·ƒΰ·™ΰ·€ΰ·”ΰΆΈΰΆ§ ΰΆ†ΰΆ΄ΰ·ƒΰ·”", + "scenes.app.popup.workspaceparameter.pages.apps_small_text": "ΰΆΈΰ·™ΰΆΈ වැࢩࢢිࢸෙහි ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š", + "scenes.app.popup.workspaceparameter.pages.invitation_error": "ΰΆ΄ΰ·„ΰΆ­ ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·ŠΰΆ§ ࢆࢻාࢰࢱා ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰ·šΰΆ―ΰ·“ ΰΆ―ΰ·ΰ·‚ΰΆΊΰΆšΰ·Š ΰ·ƒΰ·’ΰΆ―ΰ·”ΰ·€ΰ·’ΰΆ«ΰ·’: ", + "scenes.app.popup.workspaceparameter.pages.installed_apps_message": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰΆ…ΰΆ±ΰ·™ΰΆšΰ·”ΰΆ­ΰ·Š ࢴැࢭිවࢽ ΰ·ƒΰ·ŠΰΆΰ·ΰΆ΄ΰΆ±ΰΆΊ ࢚ࢻ ΰΆ‡ΰΆ­ΰ·’ ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_information": "ΰΆΈΰ·™ΰΆΈ {{$1}} ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·š ΰ·ƒΰ·ŠΰΆΰ·ΰΆ΄ΰ·’ΰΆ­ ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š", + "scenes.app.popup.workspaceparameter.pages.name_label": "වැࢩࢢිࢸෙහි ΰΆ±ΰΆΈ", + "scenes.app.popup.workspaceparameter.pages.name_description": "වැࢩࢢිࢸෙහි ΰΆ±ΰΆΈ ΰ·€ΰ·™ΰΆ±ΰ·ƒΰ·Š ࢚ࢻࢱ්ࢱ", + "components.reminder.weeks_bef": "ΰ·ƒΰΆ­ΰ·’ ΰΆšΰ·’ΰ·„ΰ·’ΰΆ΄ΰΆΊΰΆšΰΆ§ ΰΆ΄ΰ·™ΰΆ»", + "scenes.app.popup.workspaceparameter.pages.show_button": "ࢯࢻ්ශࢱࢺ", + "scenes.app.popup.workspaceparameter.pages.title": "ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·š ΰ·ƒΰ·ΰΆšΰ·ƒΰ·”ΰΆΈΰ·Š", + "scenes.app.popup.workspaceparameter.pages.withdraw_button": "ΰΆΈΰ·™ΰΆΈ ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·™ΰΆ±ΰ·Š ΰΆ‰ΰ·€ΰΆ­ΰ·Š ࢚ࢻࢱ්ࢱ", + "scenes.apps.calendar.modals.reminders": "ΰ·ƒΰ·’ΰ·„ΰ·’ΰΆšΰ·ΰΆ³ΰ·€ΰ·”ΰΆΈΰ·Š", + "scenes.apps.calendar.modals.modify_event_button": "ΰ·ƒΰ·’ΰΆ―ΰ·”ΰ·€ΰ·“ΰΆΈ ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ", + "scenes.apps.calendar.modals.event_description_placeholder": "වැࢫුࢸ", + "scenes.apps.calendar.modals.description_placeholder": "වැࢫුࢸ", + "scenes.apps.drive.message_added_file_no_name": "{{$1}} ΰΆœΰ·œΰΆ±ΰ·”ΰ·€ΰΆšΰ·Š ࢺවා ΰΆ‡ΰΆ­.", + "scenes.apps.drive.message_added_mutiple_files": "{{$1}} ΰΆœΰ·œΰΆ±ΰ·” ΰΆšΰ·’ΰ·„ΰ·’ΰΆ΄ΰΆΊΰΆšΰ·Š ࢺවා ΰΆ‡ΰΆ­.", + "scenes.apps.calendar.workspace_menu": "වැࢩࢢිࢸ", + "scenes.apps.calendar.workspace_label": "ΰΆΈΰ·™ΰΆΈ වැࢩࢢිࢸ", + "scenes.apps.calendar.workspace": "වැࢩࢢිࢸ", + "scenes.apps.calendar.no_connectors_menu_text": "ΰΆ―ΰ·’ΰΆ± ΰΆ―ΰ·ƒΰ·”ΰΆ±ΰΆšΰΆ§ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ° ΰΆšΰ·… ΰ·„ΰ·ΰΆšΰ·’ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆš ΰΆšΰ·’ΰ·ƒΰ·’ΰ·€ΰΆšΰ·Š ΰΆ”ΰΆΆ ΰ·ƒΰΆ­ΰ·”ΰ·€ ࢱැࢭ.", + "scenes.apps.calendar.no_calendar_text": "ΰΆ”ΰΆΆ ΰΆΈΰ·™ΰΆΈ වැࢩࢢිࢸࢧ ΰΆšΰ·’ΰ·ƒΰ·’ΰΆΈ ΰΆ―ΰ·’ΰΆ± ΰΆ―ΰ·ƒΰ·”ΰΆ±ΰΆšΰ·Š ΰ·ƒΰΆšΰ·ƒΰ· ࢱැࢭ.", + "scenes.apps.drive.throw_menu": "ΰΆšΰ·”ΰΆ«ΰ·”ΰΆšΰ·–ΰΆ©ΰΆΊΰΆ§ ΰΆΊΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.messages.input.edited": "ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ ΰΆšΰ·…ΰ·", + "scenes.apps.drive.trash_empty_menu": "ΰΆšΰ·”ΰΆ«ΰ·”ΰΆšΰ·–ΰΆ©ΰΆΊ ΰ·„ΰ·’ΰ·ƒΰ·Š ࢚ࢻࢱ්ࢱ", + "scenes.apps.drive.viewer.no_preview_message": "ࢸෙවැࢱි ΰΆœΰ·œΰΆ±ΰ·”ΰ·€ΰΆšΰ·Š ΰΆ―ΰ·ΰΆšΰ·“ΰΆΈΰΆ§ ΰΆ±ΰ·œΰ·„ΰ·ΰΆšΰ·’ΰΆΊ.", + "scenes.apps.messages.just_you": "ΰΆ”ΰΆΆΰΆ§ ࢴࢸࢫ්࢚ ΰΆ΄ΰ·™ΰΆ±ΰ·™ΰΆΊΰ·’", + "scenes.apps.calendar.reminders": "ΰ·ƒΰ·’ΰ·„ΰ·’ΰΆšΰ·ΰΆ³ΰ·€ΰ·”ΰΆΈΰ·Š", + "scenes.help_us": "ΰΆšΰ·™ΰ·ƒΰ·š ΰ·€ΰ·™ΰΆ­ΰΆ­ΰ·Š, ࢯෝෂࢺ ࢱිවැࢻࢯි ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆ…ΰΆ΄ΰΆ§ ΰΆ‹ΰΆ―ΰ·€ΰ·” ΰ·€ΰ·“ΰΆΈΰΆ§ ΰΆšΰ·ΰΆΈΰΆ­ΰ·’ ࢱࢸ්, ΰΆ΄ΰ·„ΰΆ­ΰ·’ΰΆ±ΰ·Š ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊΰΆšΰ·Š ΰΆ‘ΰ·€ΰΆ±ΰ·ŠΰΆ±: ", + "components.tagpicker.notag": "ΰΆ…ΰΆ±ΰΆ±ΰ·Šβ€ΰΆΊΰΆΊΰΆ± ࢱැࢭ", + "scenes.login.verifymail.error_message": "ΰΆ―ΰ·ΰ·‚ΰΆΊΰΆšΰ·Š ΰ·ƒΰ·’ΰΆ―ΰ·”ΰ·€ΰ·”ΰΆ«ΰ·’", + "scenes.no_panic": "࢚ࢽࢢࢽ ΰΆ±ΰ·œΰ·€ΰΆ±ΰ·ŠΰΆ±! ΰΆ§ΰ·Šΰ·€ΰ·šΰΆšΰ·Š ࢱිවැࢻࢯි ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆ΄ΰ·’ΰΆ§ΰ·”ΰ·€ ΰΆΊΰ·…ΰ·’ ΰΆ΄ΰ·–ΰΆ»ΰΆ«ΰΆΊ ࢚ࢻࢱ්ࢱ.", + "services.apps.calendar.event_icon": "ΰ·ƒΰ·’ΰΆ―ΰ·”ΰ·€ΰ·“ΰΆΈ", + "services.apps.calendar.reminder_icon": "ΰ·ƒΰ·’ΰ·„ΰ·’ΰΆšΰ·ΰΆ³ΰ·€ΰ·“ΰΆΈ", + "services.user.notification_parameters_update_alert": "ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·š ΰ·ƒΰ·ΰΆšΰ·ƒΰ·”ΰΆΈΰ·Š ΰΆΊΰ·ΰ·€ΰΆ­ΰ·ŠΰΆšΰ·ΰΆ½ ࢚ࢻ ΰΆ‡ΰΆ­.", + "services.user.update_password_alert": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊ ΰΆΊΰ·ΰ·€ΰΆ­ΰ·ŠΰΆšΰ·ΰΆ½ ࢚ࢻ ΰΆ‡ΰΆ­.", + "scenes.apps.drive.trash": "ΰΆšΰ·”ΰΆ«ΰ·”ΰΆšΰ·–ΰΆ©ΰΆΊ", + "scenes.apps.messages.input.emoji": "ࢉࢸෝ࢒ි", + "scenes.apps.messages.input.hide_formatting": "ΰΆ†ΰΆšΰ·˜ΰΆ­ΰ·’ΰΆšΰΆ»ΰΆ±ΰΆΊ ΰ·ƒΰΆŸΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.messages.input.show_formatting": "ΰΆ†ΰΆšΰ·˜ΰΆ­ΰ·’ΰΆšΰΆ»ΰΆ±ΰΆΊ ΰΆ΄ΰ·™ΰΆ±ΰ·Šΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.tasks.my_tasks": "ࢸා࢜ේ ࢚ාࢻ්ࢺࢺ", + "scenes.apps.tasks.board.tasks.subtask": "ΰΆ…ΰΆ±ΰ·”-࢚ාࢻ්ࢺࢺ", + "scenes.apps.tasks.board.place_holder": "ΰΆ΄ΰ·”ΰ·€ΰΆ»ΰ·”ΰ·€ΰ·š ΰΆ±ΰΆΈ", + "scenes.apps.tasks.board.tasks.add_subtask": "ΰΆ…ΰΆ±ΰ·”-࢚ාࢻ්ࢺ්࢚ ΰΆ‘ΰΆšΰ·ŠΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "components.drive.elements.see": "ΰΆ―ΰΆšΰ·’ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.popup.workspaceparameter.pages.cancel_invitation": "ΰΆ‡ΰΆ»ΰΆΊΰ·”ΰΆΈ ΰΆ…ΰ·€ΰΆ½ΰΆ‚ΰΆœΰ·” ࢚ࢻࢱ්ࢱ", + "scenes.apps.tasks.active_tasks": "ΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰ·ΰΆ­ΰ·ŠΰΆΈΰΆš ࢚ාࢻ්ࢺࢺ", + "scenes.app.popup.appsparameters.pages.subtitle_informations": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·Š ΰΆšΰ·…ΰΆΈΰΆ±ΰ·ΰΆšΰΆ»ΰΆ«ΰΆΊΰΆ§ ࢅࢯාළ ΰΆ­ΰ·œΰΆ»ΰΆ­ΰ·”ΰΆ»ΰ·”", + "scenes.app.popup.appsparameters.pages.smalltext_workspace_id": "ΰ·€ΰΆ­ΰ·ŠΰΆΈΰΆ±ΰ·Š ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·š හැࢳු.", + "scenes.client.channelbar.channelmemberslist.no_members": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰ·™ΰ·„ΰ·’ ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š ࢱැࢭ, ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š ΰΆ‘ΰΆšΰ·ŠΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ± ΰΆ‘ΰΆΆΰ·“ΰΆΈΰ·™ΰΆ±ΰ·Š ࢆࢻාࢰࢱා ΰΆšΰ·… ΰ·„ΰ·ΰΆšΰ·’ΰΆΊ.", + "scenes.apps.messages.message.activity_message.a_updated_channel_description": "{{$1}} ΰ·ƒΰ·€ΰ·’ΰ·ƒΰ·ŠΰΆ­ΰΆ»ΰΆΊ ΰ·€ΰ·™ΰΆ±ΰ·ƒΰ·Š ΰΆšΰ·…ΰ·", + "components.alert.leave_private_channel.description": "ΰΆ‡ΰΆ»ΰΆΊΰ·”ΰΆΈΰΆšΰ·’ΰΆ±ΰ·Š ΰΆ­ΰ·œΰΆ»ΰ·€ ΰΆ”ΰΆΆΰΆ§ ࢱැවࢭ ΰΆΈΰ·™ΰΆΈ ΰΆ΄ΰ·žΰΆ―ΰ·ŠΰΆœΰΆ½ΰ·’ΰΆš ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰΆ§ ΰΆ‘ΰΆšΰ·Šΰ·€ΰ·“ΰΆΈΰΆ§ ΰΆ±ΰ·œΰ·„ΰ·ΰΆšΰ·’ ΰ·€ΰΆ±ΰ·” ΰΆ‡ΰΆ­.", + "components.add_mails_workspace.title_1": "ΰΆšΰ·’ΰ·„ΰ·’ΰΆ΄ ΰΆ―ΰ·™ΰΆ±ΰ·™ΰΆšΰ·Š ΰΆ‘ΰΆšΰ·ŠΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "components.add_mails_workspace.title_2": "ΰΆ§ΰ·Šΰ·€ΰ·šΰΆ§ΰ·Š ΰΆΊΰΆ±ΰ·” ࢚ࢫ්ࢩාࢺࢸ් ΰ·ƒΰ·„ΰΆΊΰ·ΰΆœΰ·“ΰΆ­ΰ· ΰΆΈΰ·™ΰ·€ΰΆ½ΰΆΈΰΆšΰ·’, ΰΆ‘ΰΆΆΰ·ΰ·€ΰ·’ΰΆ±ΰ·Š ΰΆ…ΰΆ΄ΰ·’ ΰΆ”ΰΆΆ ΰ·€ΰ·™ΰΆ±ΰ·”ΰ·€ΰ·™ΰΆ±ΰ·Š ΰ·ƒΰ·‘ΰΆ―ΰ·– වැࢩࢢිࢸ ΰΆ΄ΰΆ»ΰ·“ΰΆšΰ·Šβ€ΰ·‚ΰ· ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š ΰΆšΰ·’ΰ·„ΰ·’ΰΆ΄ ΰΆ―ΰ·™ΰΆ±ΰ·™ΰΆšΰ·”ΰΆ§ ࢆࢻාࢰࢱා ࢚ࢻࢱ්ࢱ.", + "components.add_mails_workspace.text_area_placeholder": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·ŠΰΆœΰ·š ΰ·€ΰ·’-ࢭැࢴැࢽ් ΰΆ‡ΰΆ­ΰ·”ΰΆ½ΰ·Š ࢚ࢻࢱ්ࢱ*", + "components.verify_mail.title_1": "ΰ·ƒΰ·”ΰΆ· ΰΆ΄ΰ·ΰΆ­ΰ·”ΰΆΈΰ·Š", + "components.verify_mail.title_2": "ΰΆ”ΰΆΆ ࢯැࢱ් ΰΆ±ΰ·’ΰΆ½ ΰΆ§ΰ·Šΰ·€ΰ·šΰΆ§ΰ·Š ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·™ΰΆšΰ·’!", + "components.verify_mail.button": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆš ΰΆ‘ΰΆšΰ·ŠΰΆšΰΆ»ΰΆ±ΰ·ŠΰΆ±", + "scenes.client.channels_bar.modals.guest_management.tips": "ΰΆ‰ΰ·„ΰΆ­ ࢆࢯාࢱࢺ ΰΆ·ΰ·ΰ·€ΰ·’ΰΆ­ΰΆΊΰ·™ΰΆ±ΰ·Š ΰ·€ΰ·’-ࢭැࢴැࢽ් ΰΆ‘ΰΆšΰ·ŠΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈ හෝ ΰ·ƒΰ·™ΰ·€ΰ·“ΰΆΈ ΰΆ…ΰΆ»ΰΆΉΰΆ±ΰ·ŠΰΆ±", + "scenes.app.popup.workspaceparameter.edit_from_console": "ΰ·„ΰ·ƒΰ·”ΰΆ»ΰ·”ΰ·€ΰΆΈΰ·™ΰ·„ΰ·’ ࢢࢽࢱ්ࢱ", + "services.console_services.toaster.add_emails_error": "ΰ·€ΰ·’-ࢭැࢴැࢽ් ΰΆ½ΰ·’ΰΆ΄ΰ·’ΰΆ±(ΰΆΊ) ΰΆ‘ΰΆšΰ·ŠΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰ·šΰΆ―ΰ·“ ΰΆ―ΰ·ΰ·‚ΰΆΊΰΆšΰ·’", + "components.locked_features.locked_history_banner.button": "ΰΆ­ΰ·€ ࢯැࢱ࢜ࢱ්ࢱ", + "components.locked_features.locked_guests_popup.title": "ΰΆ…ΰΆΈΰ·”ΰΆ­ΰ·ŠΰΆ­ΰΆ±ΰ·ŠΰΆœΰ·š ΰ·€ΰ·’ΰ·ΰ·šΰ·‚ΰ·ΰΆ‚ΰΆœΰΆΊ ΰΆ…ΰΆœΰ·”ΰ·…ΰ·” ࢽා ΰΆ‡ΰΆ­", + "components.locked_features.locked_guests_popup.subtitle": "ΰΆΈΰ·™ΰΆΈ ΰ·€ΰ·’ΰ·ΰ·šΰ·‚ΰ·ΰΆ‚ΰΆœΰΆΊ ΰΆ§ΰ·Šΰ·€ΰ·šΰΆ§ΰ·Š ΰΆ±ΰ·œΰΆΈΰ·’ΰΆ½ΰ·š ࢅࢱුවාࢯࢺࢧ ࢱැࢭ", + "components.locked_features.locked_guests_popup.learn_more_button": "ΰΆ­ΰ·€ ࢯැࢱ࢜ࢱ්ࢱ", + "components.on_boarding.popups.blocked_company.title": "ΰΆœΰ·™ΰ·€ΰ·“ΰΆΈΰ·š ΰΆœΰ·ΰΆ§ΰ·…ΰ·”ΰ·€ΰΆšΰ·Š ࢱිසා ΰΆ”ΰΆΆΰΆœΰ·š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰΆ§ ΰΆ…ΰΆœΰ·”ΰ·…ΰ·” ࢽා ΰΆ‡ΰΆ­", + "scenes.apps.tasks.select_user_button": "ΰ·€ΰ·™ΰΆ±ΰΆ­ΰ·Š ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·™ΰΆšΰ·” සࢳහා ࢚ාࢻ්ࢺࢺࢱ් ΰΆ―ΰΆšΰ·’ΰΆ±ΰ·ŠΰΆ±", + "components.emoji_picker.categories.smileys_and_people": "ΰΆΈΰΆ―ΰ·„ΰ·ƒ හා ΰΆΈΰ·’ΰΆ±ΰ·’ΰ·ƒΰ·”ΰΆ±ΰ·Š", + "scenes.apps.account.notifications.devices_option_inactive": "ΰΆΈΰΆΈ ΰΆ©ΰ·™ΰ·ƒΰ·ŠΰΆšΰ·ŠΰΆ§ΰ·œΰΆ΄ΰ·Š ΰΆ‘ΰΆšΰ·š ΰΆ…ΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰ·€ ΰ·ƒΰ·’ΰΆ§ΰ·’ΰΆ± ΰ·€ΰ·’ΰΆ§ ΰΆΈΰΆ§ ΰΆ­ΰΆ½ΰ·ŠΰΆ½ΰ·” ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·Š ΰΆ‘ΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.parameters.group_sections.apps.badge_extension": "Extension", + "scenes.apps.parameters.workspace_sections.members.pending": "ΰΆ΄ΰ·œΰΆ»ΰ·œΰΆ­ΰ·ŠΰΆ­ΰ·” ࢊࢸේࢽ්", + "scenes.login.home.unable_to_connect": "ΰ·€ΰΆ½ΰΆ‚ΰΆœΰ·” ΰΆ±ΰ·œΰ·€ΰΆ± ΰΆ…ΰΆšΰ·ŠΰΆ­ΰΆ΄ΰΆ­ΰ·Šβ€ΰΆ»", + "scenes.login.create_account.step_1_subtitle": "ΰΆ‘ΰΆΊ ΰ·ƒΰΆ»ΰΆ½ ΰ·€ΰ·’ΰΆΊ ΰΆ±ΰ·œΰ·„ΰ·ΰΆšΰ·’ΰΆΊ β€” ΰΆ…ΰΆ΄ΰΆ§ ࢇවැසි ΰ·€ΰΆ±ΰ·ŠΰΆ±ΰ·š ΰΆ­ΰ·œΰΆ»ΰΆ­ΰ·”ΰΆ»ΰ·” ΰΆ§ΰ·’ΰΆšΰΆšΰ·Š ΰΆ΄ΰΆΈΰΆ«ΰ·’.", + "scenes.login.create_account.step_3_mail_sent": "ΰΆ…ΰΆ΄ΰ·’ ΰΆ”ΰΆΆΰΆ§ ΰ·€ΰ·’ΰΆ―ΰ·Šβ€ΰΆΊΰ·”ΰΆ­ΰ·Š ΰΆ­ΰ·ΰΆ΄ΰ·‘ΰΆ½ΰ·™ΰΆ±ΰ·Š ΰ·ƒΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊ ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰ·š ΰ·ƒΰΆΆΰ·ΰΆ³ΰ·’ΰΆΊΰΆšΰ·Š ࢑වා ΰΆ‡ΰΆ­.", + "scenes.login.create_account.step_3_subtitle": "ࢅවසාࢱ ΰΆ΄ΰ·’ΰΆΊΰ·€ΰΆ» β€” ΰΆ”ΰΆΆ ࢻොࢢෝ ΰΆšΰ·™ΰΆ±ΰ·™ΰΆšΰ·Š ΰΆ±ΰ·œΰ·€ΰΆ± ΰΆΆΰ·€ ΰΆ…ΰΆ΄ΰΆ§ ΰΆ­ΰ·„ΰ·€ΰ·”ΰΆ»ΰ·” ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊΰΆΊΰ·’!", + "scenes.app.workspaces.create_company.company_name.title_1": "ࢴࢧࢱ් ΰΆœΰ·ΰΆ±ΰ·“ΰΆΈΰΆ§,", + "scenes.app.workspaces.welcome_page.added_to_company": "ΰΆ”ΰΆΆΰΆ§ ࢆࢻාࢰࢱා ࢚ࢻ ΰΆ‡ΰΆ­ ", + "scenes.app.workspaces.welcome_page.may_be_invited_with_secondary_emails": "ΰ·€ΰ·™ΰΆ±ΰΆ­ΰ·Š ΰ·€ΰ·’ΰΆ―ΰ·Šβ€ΰΆΊΰ·”ΰΆ­ΰ·Š ࢭැࢴැࢽ් ΰΆ½ΰ·’ΰΆ΄ΰ·’ΰΆ±ΰΆΊΰΆšΰ·Š ࢷාවිࢭා ΰΆšΰΆ»ΰΆΈΰ·’ΰΆ±ΰ·Š ΰΆ”ΰΆΆΰΆ§ ࢆࢻාࢰࢱා ΰΆšΰ·…ΰ·šΰΆ―?", + "scenes.app.workspaces.welcome_page.code_verification": "ΰ·ƒΰΆ­ΰ·ŠΰΆΊΰ·ΰΆ΄ΰΆ± ࢚ේࢭࢺ", + "scenes.app.workspaces.welcome_page.we_sent_you_mail": "ΰΆ…ΰΆ΄ΰ·’ ΰΆ”ΰΆΆΰΆ§ {{$1}} හࢻහා ΰ·ƒΰΆ­ΰ·Šβ€ΰΆΊΰ·ΰΆ΄ΰΆ± ࢚ේࢭࢺ්࢚ ࢑වා ΰΆ‡ΰΆ­", + "scenes.apps.account.preference": "ࢸࢱාࢴ", + "components.calendar.repetition.monthly_on": "ΰΆΈΰ·ΰ·ƒΰ·’ΰΆšΰ·€ {{$1}} {{$2}}", + "scenes.apps.account.account.email_add_modal.confirm": "ΰΆΈΰ·™ΰΆΈ ΰ·€ΰ·’ΰΆ―ΰ·Šβ€ΰΆΊΰ·”ΰΆ­ΰ·Š ࢭැࢴෑࢽ ΰΆ­ΰ·„ΰ·€ΰ·”ΰΆ»ΰ·” ࢚ࢻࢱ්ࢱ", + "components.calendar.repetition.does_not_repeat": "ࢱැවࢭ ΰ·ƒΰ·’ΰΆ―ΰ·” ΰΆ±ΰ·œΰ·€ΰ·š", + "components.calendar.repetition.monthly_on_day": "ΰΆΈΰ·ΰ·ƒΰ·’ΰΆšΰ·€ ΰΆ―ΰ·’ΰΆ± {{$1}}", + "components.calendar.repetition.annually_on": "ΰ·€ΰ·ΰΆ»ΰ·Šΰ·‚ΰ·’ΰΆšΰ·€ {{$1}}", + "components.calendar.repetition.repeat": "ΰ·ƒΰ·‘ΰΆΈ ΰΆ‘ΰΆšΰΆšΰ·ŠΰΆΈ ࢱැවࢭ ࢱැවࢭ ࢚ࢻࢱ්ࢱ", + "components.calendar.repetition.ends": "ΰΆ…ΰ·€ΰ·ƒΰΆ±ΰ·Š ΰ·€ΰ·š", + "components.calendar.repetition.custom_recurrence": "ΰΆ…ΰΆ·ΰ·’ΰΆ»ΰ·”ΰΆ ΰ·’ ΰΆ΄ΰ·”ΰΆ±ΰΆ»ΰ·ΰ·€ΰΆ»ΰ·ŠΰΆ­ΰΆ±ΰΆΊ", + "components.calendar.repetition.occurrence": "ΰ·ƒΰ·’ΰΆ―ΰ·”ΰ·€ΰ·“ΰΆΈ(ΰΆΊ)", + "components.calendar.repetition.repeat_on": "ࢱැවࢭ ࢱැවࢭ ࢚ࢻࢱ්ࢱ", + "scenes.app.channelsbar.currentuser.reactivate_notifications": "ࢱැවࢭ ΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰ·ΰΆ­ΰ·ŠΰΆΈΰΆš", + "components.searchpopup.only_pinned": "ΰΆ‡ΰΆΈΰ·”ΰΆ«ΰ·”ΰΆΈΰ·Š ΰΆšΰ·… ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ© ΰΆ΄ΰΆΈΰΆ«ΰ·’", + "components.blocked_account.trial_period_over": "ΰΆ”ΰΆΆΰ·š ΰΆ…ΰΆ­ΰ·Šΰ·„ΰΆ―ΰ· ΰΆΆΰ·ΰΆ½ΰ·“ΰΆΈΰ·š ࢚ාࢽࢺ ΰΆ…ΰ·€ΰ·ƒΰΆ±ΰ·Š. ΰΆ”ΰΆΆΰΆœΰ·š ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈ ΰΆ…ΰΆœΰ·”ΰ·…ΰ·” ΰΆ‡ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰ·ƒΰ·„ ΰ·ƒΰ·’ΰΆΊΰΆ½ΰ·” ΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰ·ΰΆšΰ·ΰΆ»ΰ·“ΰΆ­ΰ·Šΰ·€ΰΆΊΰΆ±ΰ·Š ΰ·€ΰ·™ΰΆ­ ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·€ΰ·šΰ·ΰΆΊ ࢽࢢා ΰΆœΰ·ΰΆ±ΰ·“ΰΆΈΰΆ§, ΰΆšΰΆ»ΰ·”ΰΆ«ΰ·ΰΆšΰΆ» ΰΆ”ΰΆΆΰΆœΰ·š ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈ ΰ·€ΰ·’ΰΆ―ΰ·Šβ€ΰΆΊΰ·”ΰΆ­ΰ·Š ΰΆ­ΰ·ΰΆ΄ΰ·‘ΰΆ½ΰ·™ΰΆ±ΰ·Š ΰΆ­ΰ·„ΰ·€ΰ·”ΰΆ»ΰ·” ࢚ࢻࢱ්ࢱ", + "components.verify_mail.text": "ΰΆ΄ΰ·…ΰΆΈΰ·”ΰ·€ΰ·™ΰΆ±ΰ·ŠΰΆΈ, ΰΆ”ΰΆΆ ΰΆ”ΰΆΆΰΆœΰ·š ΰ·€ΰ·’ΰΆ―ΰ·Šβ€ΰΆΊΰ·”ΰΆ­ΰ·Š ࢭැࢴැࢽ් ΰΆ½ΰ·’ΰΆ΄ΰ·’ΰΆ±ΰΆΊ ΰ·ƒΰΆ­ΰ·Šβ€ΰΆΊΰ·ΰΆ΄ΰΆ±ΰΆΊ ΰΆšΰ·… ΰΆΊΰ·”ΰΆ­ΰ·”ΰΆΊ. ΰΆ…ΰΆ΄ΰ·’ ΰ·ƒΰΆ­ΰ·Šβ€ΰΆΊΰ·ΰΆ΄ΰΆ± ΰ·ƒΰΆΆΰ·ΰΆ³ΰ·’ΰΆΊΰΆšΰ·Š ࢺවා ΰΆ‡ΰΆ­", + "scenes.app.popup.appsparameters.pages.message_data_next_event": "ΰΆŠΰ·…ΰΆŸ ΰ·ƒΰ·’ΰΆ―ΰ·”ΰ·€ΰ·“ΰΆΈΰ·šΰΆ―ΰ·“ ΰΆΊΰ·€ΰΆ±ΰ·” ΰΆ½ΰΆΆΰΆ± ΰΆ±ΰ·’ΰ·‚ΰ·ŠΰΆšΰ·Šβ€ΰΆ»ΰ·“ΰΆΊ ࢯࢭ්ࢭ", + "scenes.app.popup.appsparameters.pages.publication_description": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰΆ΄ΰ·™ΰΆ±ΰ·Šΰ·€ΰ·“ΰΆΈ ΰΆ±ΰ·’ΰ·ΰ·ŠΰΆ ΰΆΊ ࢚ࢻࢱ්ࢱ.", + "scenes.app.popup.appsparameters.pages.read_privileges_label": "ΰΆšΰ·’ΰΆΊΰ·€ΰ·“ΰΆΈΰ·š ΰ·€ΰΆ»ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·ƒΰ·ΰΆ―ΰΆΊ", + "scenes.app.popup.appsparameters.pages.remove_app": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ {{$1}} ΰ·ƒΰ·ŠΰΆΰ·’ΰΆ»ΰ·€ΰΆΈ ࢸ࢚ࢱ්ࢱ.", + "scenes.app.popup.appsparameters.pages.status_tilte": "ΰΆ­ΰΆ­ΰ·Šΰ·€ΰΆΊ", + "scenes.app.popup.appsparameters.pages.string_information": "ΰΆΈΰ·™ΰΆΈ ΰΆ­ΰΆ±ΰ·ŠΰΆ­ΰ·”ΰ·€ ΰΆ”ΰΆΆΰΆœΰ·š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ හࢳුࢱා ࢜ࢱ්ࢱා ΰΆ…ΰΆ­ΰΆ» ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ© විࢰාࢱවࢽ ࢷාවිࢭා ΰΆšΰΆ»ΰΆ±ΰ·” ΰΆ‡ΰΆ­.", + "scenes.app.popup.appsparameters.pages.url_reception_events_label": "ΰ·ƒΰ·’ΰΆ―ΰ·”ΰ·€ΰ·“ΰΆΈΰ·Š ΰΆ΄ΰ·’ΰ·…ΰ·’ΰΆœΰ·ΰΆ±ΰ·“ΰΆΈΰ·š Url", + "scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description": "ΰΆ”ΰΆΆΰΆ§ ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·Š ΰΆ±ΰ·œΰΆ½ΰ·ΰΆΆΰ·™ΰΆ± ࢚ාࢽ ΰ·ƒΰ·“ΰΆΈΰ·ΰ·€ΰΆšΰ·Š ࢭෝࢻࢱ්ࢱ.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace": "࢚ාࢻ්ࢺ ΰΆ‰ΰΆ© ࢸ࢚ࢱ්ࢱ", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace_description": "ΰΆ”ΰΆΆΰΆ§ ΰΆΈΰ·™ΰΆΈ ࢚ාࢻ්ࢺ ΰΆ‰ΰΆ© ΰΆΈΰ·ΰΆšΰ·“ΰΆΈΰΆ§ ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊ ΰΆΆΰ·€ ΰΆ­ΰ·„ΰ·€ΰ·”ΰΆ»ΰ·” ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§, ΰΆšΰΆ»ΰ·”ΰΆ«ΰ·ΰΆšΰΆ» ΰΆ΄ΰ·„ΰΆ­ ΰΆ±ΰΆΈ ΰΆ§ΰΆΊΰ·’ΰΆ΄ΰ·Š ࢚ࢻ ࢸ࢚ࢱ්ࢱ ΰΆ”ΰΆΆΰΆ±ΰ·ŠΰΆ±.", + "scenes.app.popup.workspaceparameter.pages.moderator_status": "ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·š ΰΆΈΰ·ΰΆ―ΰ·’ΰ·„ΰΆ­ΰ·ŠΰΆšΰΆ»ΰ·”", + "scenes.app.popup.workspaceparameter.pages.alert_impossible_removing": "ΰΆ”ΰΆΆ ΰΆ…ΰ·€ΰ·ƒΰΆ±ΰ·Š ΰΆ΄ΰΆ»ΰ·’ΰΆ΄ΰ·ΰΆ½ΰΆšΰΆΊΰ· ΰ·€ΰΆ± ࢱිසා ΰΆ”ΰΆΆΰΆ§ වැࢩࢢිࢸ හැࢻ ࢺා ΰΆ±ΰ·œΰ·„ΰ·ΰΆš. ΰΆ”ΰΆΆΰΆ§ ΰΆ±ΰ·€ ΰΆ΄ΰΆ»ΰ·’ΰΆ΄ΰ·ΰΆ½ΰΆšΰΆΊΰ·™ΰΆšΰ·” ΰΆ±ΰ·’ΰΆ»ΰ·Šΰ·€ΰΆ ΰΆ±ΰΆΊ ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ හෝ ΰΆΈΰ·™ΰΆΈ ࢚ාࢻ්ࢺ ΰΆ‰ΰΆ© ࢸ࢚ා ࢯැࢸීࢸࢧ/ΰ·ƒΰΆ‚ΰΆ»ΰΆšΰ·Šΰ·‚ΰ·’ΰΆ­ ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰ·„ΰ·ΰΆšΰ·’ΰΆΊ.", + "scenes.app.popup.workspaceparameter.payments_subscriptions_title": "ΰΆœΰ·™ΰ·€ΰ·“ΰΆΈΰ·Š ΰ·ƒΰ·„ ΰΆ―ΰ·ΰΆΊΰΆšΰΆ­ΰ·Šΰ·€ΰΆΊΰΆ±ΰ·Š", + "scenes.apps.drive.choose_folder_button": "ΰΆ±ΰ·ΰΆΈΰ·ΰ·€ΰΆ½ΰ·’ΰΆΊΰΆšΰ·Š ࢭෝࢻࢱ්ࢱ", + "scenes.apps.drive.choose_file_button": "ΰΆœΰ·œΰΆ±ΰ·”ΰ·€ΰΆšΰ·Š ࢭෝࢻࢱ්ࢱ", + "components.alert.confirm_click": "OK ΰΆšΰ·ŠΰΆ½ΰ·’ΰΆšΰ·Š ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰ·™ΰΆ±ΰ·Š ΰΆ”ΰΆΆΰΆœΰ·š ΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰ·ΰ·€ ΰΆ­ΰ·„ΰ·€ΰ·”ΰΆ»ΰ·” ࢚ࢻࢱ්ࢱ.", + "app.state.recoil.hooks.use_current_company_applications.toaster_delete": "ΰΆ”ΰΆΆΰ·š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·™ΰΆ±ΰ·Š {{$1}} ΰ·ƒΰ·ΰΆ»ΰ·ŠΰΆΰΆšΰ·€ ࢸ࢚ා ΰΆ‡ΰΆ­", + "general.delete": "ࢸ࢚ࢱ්ࢱ", + "general.unarchive": "ΰΆ…ΰ·ƒΰΆ‚ΰΆ»ΰΆšΰ·Šΰ·‚ΰΆ«ΰΆΊ", + "general.confirm": "ΰΆ­ΰ·„ΰ·€ΰ·”ΰΆ»ΰ·” ࢚ࢻࢱ්ࢱ", + "general.connexion_status.disconnected": "ΰΆ”ΰΆΆ ΰΆ±ΰ·œΰΆΆΰ·ΰΆ³ΰ·’ΰΆΊ", + "general.connexion_status.connected": "ΰΆ”ΰΆΆ ࢸාࢻ්࢜࢜ࢭ ΰΆΊΰ·’", + "scenes.app.side_app.messages_thread_title": "{{$1}} β€’ Messages thread", + "scenes.app.workspaces.create_company.group_data.group_main_activity.bank": "ΰΆΆΰ·ΰΆ‚ΰΆšΰ·”ΰ·€ / ΰΆ»ΰΆšΰ·Šΰ·‚ΰΆ«ΰΆΊ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.real_estate": "ΰΆ―ΰ·šΰΆ΄ΰ·… ΰ·€ΰ·™ΰ·…ΰΆ―ΰ·ΰΆΈΰ·Š", + "scenes.app.workspaces.create_company.group_data.group_main_activity.electronics_electricity_energy": "ΰΆ‰ΰΆ½ΰ·™ΰΆšΰ·ŠΰΆ§ΰ·ŠΰΆ»ΰ·œΰΆ±ΰ·’ΰΆš / ΰ·€ΰ·’ΰΆ―ΰ·”ΰΆ½ΰ·’ / ΰΆΆΰΆ½ΰ·ΰΆšΰ·ŠΰΆ­ΰ·’", + "scenes.app.workspaces.create_company.group_data.group_main_activity.machinery_automotive": "ΰΆΊΰΆ±ΰ·ŠΰΆ­ΰ·Šβ€ΰΆ»ΰ·ΰΆ΄ΰΆšΰΆ»ΰΆ« / වාහࢱ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.transport_logistics": "ΰΆ΄ΰ·ŠΰΆ»ΰ·€ΰ·ΰ·„ΰΆ± / ΰ·ƒΰ·ΰΆ΄ΰΆΊΰ·”ΰΆΈΰ·Š", + "components.user_picker.modal_no_result": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ­ΰ·’ΰΆ΅ΰΆ½ ΰ·„ΰΆΈΰ·” ΰΆ±ΰ·œΰ·€ΰ·’ΰΆ«ΰ·’", + "scenes.apps.calendar.calendar.list_btn": "ΰΆ½ΰ·ΰΆΊΰ·’ΰ·ƒΰ·ŠΰΆ­ΰ·”ΰ·€", + "scenes.apps.drive.navigators.navigator_labels.title": "ࢽේࢢࢽ්", + "scenes.apps.drive.preview_bloc.error_file": "ΰΆœΰ·œΰΆ±ΰ·”ΰ·€ ΰ·„ΰΆΈΰ·” ΰΆ±ΰ·œΰ·€ΰ·’ΰΆ«ΰ·’", + "scenes.apps.messages.chatbox.chat.delete_message": "ΰΆΈΰ·™ΰΆΈ ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊ ࢸ࢚ࢱ්ࢱ", + "scenes.apps.messages.chatbox.chat.delete_message_btn": "ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊ ࢸ࢚ࢱ්ࢱ", + "scenes.apps.messages.left_bar.stream.notifications.never": "ΰΆšΰ·’ΰ·ƒΰ·’ΰ·€ΰΆšΰ·Š ࢱැࢭ", + "scenes.apps.account.title": "Account parameters", + "scenes.apps.account.notifications.keywords_placeholder": "ΰ·ƒΰΆ‚ΰ·€ΰΆ»ΰ·Š., ΰ·€ΰΆΊΰ·’ΰ·†ΰΆΊΰ·’, ࢚ේࢭࢺ, ...", + "scenes.apps.account.notifications.disturb_option_a": "ΰΆ…ΰΆ­ΰΆ» ΰΆΈΰΆ§ ΰΆ­ΰΆ½ΰ·ŠΰΆ½ΰ·” ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·Š ΰΆ‘ΰ·€ΰΆ±ΰ·ŠΰΆ± ࢑ࢴා ", + "scenes.apps.account.notifications.devices_option_ever": "ΰ·ƒΰ·‘ΰΆΈ ΰ·€ΰ·’ΰΆ§ΰΆΈ ΰΆΈΰΆ§ ΰΆ­ΰΆ½ΰ·ŠΰΆ½ΰ·” ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·Š ΰΆ‘ΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.account.notifications.devices_option_never": "ΰΆΈΰΆ§ ΰΆšΰ·’ΰ·ƒΰ·’ΰ·€ΰ·’ΰΆ§ΰΆš ΰΆ­ΰΆ½ΰ·ŠΰΆ½ΰ·” ΰΆ―ΰ·ΰΆ±ΰ·”ΰΆΈΰ·ŠΰΆ―ΰ·“ΰΆΈΰ·Š ΰΆ‘ΰ·€ΰΆ±ΰ·ŠΰΆ± ࢑ࢴා", + "scenes.apps.tasks.unconfigured_tab": "ΰΆΈΰ·™ΰΆΈ ࢧැࢢࢺ ΰΆ­ΰ·€ΰΆΈ ΰ·€ΰ·’ΰΆ±ΰ·Šβ€ΰΆΊΰ·ΰ·ƒ ࢚ࢻ ࢱොࢸැࢭ.", + "scenes.apps.tasks.choose_board_button": "ΰΆ΄ΰ·”ΰ·€ΰΆ»ΰ·”ΰ·€ΰΆšΰ·Š ࢭෝࢻࢱ්ࢱ", + "scenes.apps.tasks.task_status.todo": "ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§", + "scenes.apps.tasks.task_status.done": "ΰΆ…ΰ·„ΰ·€ΰΆ»", + "scenes.apps.tasks.list_modal.modify_list": "ΰΆ½ΰ·ΰΆΊΰ·’ΰ·ƒΰ·ŠΰΆ­ΰ·”ΰ·€ ΰ·€ΰ·™ΰΆ±ΰ·ƒΰ·Š ࢚ࢻࢱ්ࢱ", + "scenes.apps.tasks.list_modal.new_list": "ΰΆ±ΰ·€ ΰΆ½ΰ·ΰΆΊΰ·’ΰ·ƒΰ·ŠΰΆ­ΰ·”ΰ·€", + "scenes.apps.tasks.list_modal.remove": "ΰΆ½ΰ·ΰΆΊΰ·’ΰ·ƒΰ·ŠΰΆ­ΰ·”ΰ·€ ΰ·ƒΰ·„ ࢚ාࢻ්ࢺࢺࢱ් ΰΆ‰ΰ·€ΰΆ­ΰ·Š ࢚ࢻࢱ්ࢱ", + "scenes.apps.tasks.list_modal.predefined_participants": "ΰΆ΄ΰ·–ΰΆ»ΰ·Šΰ·€ ΰΆ±ΰ·’ΰ·ΰ·ŠΰΆ ΰ·’ΰΆ­ ΰ·ƒΰ·„ΰΆ·ΰ·ΰΆœΰ·’ΰ·€ΰΆ±ΰ·ŠΰΆ±ΰΆ±ΰ·Š", + "scenes.login.forgot_password.text": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ…ΰΆ±ΰΆ±ΰ·Šβ€ΰΆΊΰΆ­ΰ·ΰ·€ΰΆΊ ΰΆ­ΰ·„ΰ·€ΰ·”ΰΆ»ΰ·” ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈ සࢳහා ΰΆ”ΰΆΆΰΆ§ ΰ·€ΰ·’ΰΆ―ΰ·Šβ€ΰΆΊΰ·”ΰΆ­ΰ·Š ΰΆ­ΰ·ΰΆ΄ΰ·‘ΰΆ½ΰ·™ΰΆ±ΰ·Š ΰΆ‰ΰΆ½ΰΆšΰ·ŠΰΆšΰΆΈΰ·Š 9࢚ ࢚ේࢭࢺ්࢚ ࢽැࢢෙࢱු ΰΆ‡ΰΆ­.", + "scenes.login.forgot_password.password2": "ΰΆΈΰ·”ΰΆ»ΰΆ΄ΰΆ―ΰΆΊ ΰΆ­ΰ·„ΰ·€ΰ·”ΰΆ»ΰ·” ࢚ࢻࢱ්ࢱ", + "components.emoji_picker.categories.not_found": "ΰΆ‰ΰΆΈΰ·œΰΆ’ΰ·’ ΰ·„ΰΆΈΰ·” ΰΆ±ΰ·œΰ·€ΰ·’ΰΆ«ΰ·’", + "scenes.app.taskpicker.select": "ࢭෝࢻࢱ්ࢱ", + "components.drive.navigators.directory_not_found": "ࢱාࢸාවࢽිࢺ ΰ·„ΰΆΈΰ·” ΰΆ±ΰ·œΰ·€ΰ·’ΰΆ«ΰ·’.", + "components.drive.modify_uslist": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆš ΰΆ½ΰ·ΰΆΊΰ·’ΰ·ƒΰ·ŠΰΆ­ΰ·”ΰ·€ ΰ·€ΰ·™ΰΆ±ΰ·ƒΰ·Š ࢚ࢻࢱ්ࢱ", + "components.searchpopup.last_modif": "ࢅවසාࢱ ΰ·€ΰ·™ΰΆ±ΰ·ƒΰ·Š ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈ", + "components.alert.confirm": "ΰΆ”ΰΆΆΰ·š ΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰ·ΰ·€ ΰΆ­ΰ·„ΰ·€ΰ·”ΰΆ»ΰ·” ࢚ࢻࢱ්ࢱ", + "scenes.app.channelsbar.currentuser.company_messages_counter_header": "ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ© ΰΆ…ΰΆ‚ΰΆšΰΆΊ", + "scenes.app.channelsbar.channel_removing": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ ࢸ࢚ࢱ්ࢱ", + "scenes.app.channelsbar.company_invitation_alert_subtitle": "ΰ·ƒΰΆ‚ΰ·€ΰ·’ΰΆ°ΰ·ΰΆ±ΰ·ΰΆ­ΰ·ŠΰΆΈΰΆšΰ·€ ΰ·ƒΰ·’ΰΆ§ΰ·“ΰΆΈΰΆ§ ࢻාࢸුව ΰΆΈΰΆ­ ΰΆ‘ΰΆΆΰ·“ΰΆΈΰ·™ΰΆ±ΰ·Š ΰΆΈΰ·™ΰΆΈ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ· ΰΆ”ΰΆΆΰΆœΰ·š ΰ·€ΰ·Šβ€ΰΆΊΰ·ΰΆ΄ΰ·ΰΆ»ΰΆΊΰΆ§ ࢆࢺාࢭ ΰΆšΰ·… ΰ·„ΰ·ΰΆšΰ·’ΰΆΊ.", + "scenes.app.channelsbar.initial_instructions_tutorial": "ΰΆΈΰ·”ΰΆ½ΰ·Š ࢱࢸ්࢚, ࢱࢸ්࢚ ΰ·ƒΰ·„ ΰΆ΄ΰ·ΰΆ­ΰ·’ΰΆšΰΆ© ΰΆ΄ΰ·’ΰΆ±ΰ·ŠΰΆ­ΰ·–ΰΆ»ΰΆΊΰΆšΰ·Š ࢭෝࢻࢱ්ࢱ.", + "scenes.app.channelsbar.installation_desktop_tutorial": "ΰΆ©ΰ·™ΰ·ƒΰ·ŠΰΆšΰ·ŠΰΆ§ΰ·œΰΆ΄ΰ·Š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰ·ƒΰ·ŠΰΆΰ·ΰΆ΄ΰΆ±ΰΆΊ ࢚ࢻࢱ්ࢱ", + "scenes.app.channelsbar.tutorial_alert": "ΰΆΈΰ·™ΰΆΈ ࢻාࢸුව ΰΆΊΰ·…ΰ·’ ΰΆ±ΰ·œΰΆ΄ΰ·™ΰΆ±ΰ·Šΰ·€ΰΆ±ΰ·ŠΰΆ±ΰΆ―?", + "scenes.app.channelsbar.welcoming_message_subtitle": "ΰΆšΰ·ŠΰΆ½ΰ·’ΰΆšΰ·Š ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰ·Š ΰΆšΰ·’ΰ·„ΰ·’ΰΆ΄ΰΆΊΰΆšΰ·’ΰΆ±ΰ·Š Twake pro ΰΆšΰ·™ΰΆ±ΰ·™ΰΆšΰ·Š ΰ·€ΰΆ±ΰ·ŠΰΆ±!", + "scenes.app.mainview.instruction_current_tab": "ΰΆ”ΰΆΆΰΆœΰ·š ΰ·€ΰΆΈΰ·Š ΰΆ΄ΰ·ƒ ΰΆ‡ΰΆ­ΰ·’ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰΆšΰ·Š ΰΆ­ΰ·šΰΆ»ΰ·“ΰΆΈΰ·™ΰΆ±ΰ·Š ΰΆ†ΰΆ»ΰΆΈΰ·ŠΰΆ· ࢚ࢻࢱ්ࢱ.", + "scenes.app.popup.adduser.adresses_message": "ΰΆšΰΆ»ΰ·”ΰΆ«ΰ·ΰΆšΰΆ» ΰΆ½ΰ·’ΰΆ΄ΰ·’ΰΆ± ΰΆšΰ·œΰΆΈΰ·ΰ·€ΰΆšΰ·’ΰΆ±ΰ·Š හෝ ΰΆ‰ΰΆ©ΰΆšΰ·’ΰΆ±ΰ·Š ΰ·€ΰ·™ΰΆ±ΰ·Š ࢚ࢻࢱ්ࢱ. Twake ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ―ΰ·ΰΆΊΰΆšΰΆ­ΰ·Šΰ·€ΰΆΊ ΰΆΈΰΆ­ ΰΆ΄ΰΆ―ΰΆ±ΰΆΈΰ·Šΰ·€ ࢆࢻාࢰࢱා ࢜ࢫࢱ සීࢸා ΰΆšΰ·… ΰ·„ΰ·ΰΆšΰ·’ ΰΆΆΰ·€ ࢸࢭ࢚ ࢭࢢා ࢜ࢱ්ࢱ.", + "scenes.app.popup.appsparameters.pages._appareance_message_twakcode": "ΰΆ”ΰΆΆΰΆœΰ·š Twacode ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰ·€ΰΆ½ ΰΆ΄ΰ·™ΰΆ±ΰ·”ΰΆΈ ΰΆ΄ΰΆ»ΰ·“ΰΆšΰ·Šΰ·‚ΰ· ࢚ࢻࢱ්ࢱ", + "scenes.app.popup.appsparameters.pages.app_privileges_information": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰΆ§ ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ ΰ·ƒΰ·„ ΰΆšΰ·’ΰΆΊΰ·€ΰ·“ΰΆΈΰΆ§ ΰ·„ΰ·ΰΆšΰ·’ ࢯේ ΰΆ±ΰ·’ΰΆΊΰΆΈ ࢚ࢻࢱ්ࢱ.", + "scenes.app.popup.appsparameters.pages.app_privileges_label": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·š ΰ·€ΰΆ»ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·ƒΰ·ΰΆ―", + "scenes.app.popup.appsparameters.pages.available_publication_alert": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ…ΰΆΊΰΆ―ΰ·”ΰΆΈΰ·ŠΰΆ΄ΰΆ­ΰ·Šβ€ΰΆ»ΰΆΊ ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆšΰ·ΰ·ΰΆ±ΰΆΊ ࢯැࢱࢧ Twake ࢚ࢫ්ࢩාࢺࢸ ΰ·€ΰ·’ΰ·ƒΰ·’ΰΆ±ΰ·Š ΰ·€ΰΆ½ΰΆ‚ΰΆœΰ·” ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆšΰ·Š ΰΆΆΰΆ½ΰ·ΰΆ΄ΰ·œΰΆ»ΰ·œΰΆ­ΰ·ŠΰΆ­ΰ·”ΰ·€ΰ·™ΰΆ±ΰ·Š ΰ·ƒΰ·’ΰΆ§ΰ·“.", + "scenes.app.popup.appsparameters.pages.call_event_handlers": "ࢋࢯාසීࢱ '{{$3}}' ΰ·ƒΰ·„ΰ·’ΰΆ­ '{{$1}}' ΰ·ƒΰ·„ id '{{$2}}' ΰ·€ΰΆ»ΰ·ŠΰΆœΰΆΊΰ·š ΰ·ƒΰ·’ΰΆ―ΰ·”ΰ·€ΰ·“ΰΆΈ", + "scenes.app.popup.appsparameters.pages.danger_zone_description": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ࢸ࢚ࢱ්ࢱ", + "scenes.app.popup.appsparameters.pages.dispalyed_parameters_description": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰΆ΄ΰ·™ΰΆ±ΰ·Šΰ·€ΰΆ±ΰ·ŠΰΆ±ΰ·š ΰΆšΰ·œΰΆ­ΰ·ΰΆ±ΰΆ―ΰ·ΰΆΊΰ·’ ΰΆ±ΰ·’ΰΆΊΰΆΈ ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆ”ΰΆΆΰΆ§ ΰΆ‰ΰΆ© ΰ·ƒΰΆ½ΰ·ƒΰΆΊΰ·’.", + "scenes.app.popup.appsparameters.pages.error_message": "ΰΆΈΰ·™ΰΆΈ ΰΆ±ΰΆΈ ࢯැࢱࢧࢸࢭ් ΰ·€ΰ·™ΰΆ±ΰΆ­ΰ·Š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰΆšΰ·Š ΰ·€ΰ·’ΰ·ƒΰ·’ΰΆ±ΰ·Š ࢷාවිࢭා ࢚ࢻ ΰΆ‡ΰΆ­; ΰΆšΰΆ»ΰ·”ΰΆ«ΰ·ΰΆšΰΆ» ΰ·€ΰ·™ΰΆ±ΰΆ­ΰ·Š ΰΆ‘ΰΆšΰΆšΰ·Š ࢭෝࢻࢱ්ࢱ.", + "scenes.app.popup.appsparameters.pages.filter_information": "ΰΆΈΰ·™ΰΆΈ ΰΆ΄ΰ·™ΰΆ»ΰ·„ΰΆ± ΰΆ”ΰΆΆΰΆœΰ·š API ΰΆΊΰΆ­ΰ·”ΰΆ» ΰΆ”ΰΆΆΰΆœΰ·š ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆšΰΆΊΰ·š ΰΆ‡ΰΆ­ΰ·’ ΰ·ƒΰ·šΰ·€ΰ·ΰΆ―ΰ·ΰΆΊΰΆšΰΆΊΰΆ±ΰ·ŠΰΆ§ ࢴࢸࢫ්࢚ ࢷාවිࢭා ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈ සීࢸා ΰΆšΰΆ»ΰΆΊΰ·’.", + "scenes.app.popup.appsparameters.pages.grp_section_name-error": "ΰΆΈΰ·™ΰΆΈ ΰΆ±ΰΆΈ ࢯැࢱࢧࢸࢭ් ΰ·€ΰ·™ΰΆ±ΰΆ­ΰ·Š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰΆšΰ·’ΰΆ±ΰ·Š ࢷාවිࢭා ΰ·€ΰ·š. ΰΆšΰΆ»ΰ·”ΰΆ«ΰ·ΰΆšΰΆ» ΰ·€ΰ·™ΰΆ±ΰΆ­ΰ·Š ΰΆ‘ΰΆšΰΆšΰ·Š ࢭෝࢻࢱ්ࢱ.", + "scenes.app.popup.appsparameters.pages.installation": "ΰ·ƒΰ·ŠΰΆΰ·ΰΆ΄ΰΆ±ΰΆΊ ࢚ࢻࢱ්ࢱ.", + "scenes.app.popup.appsparameters.pages.optimal_format": "ΰΆ΄ΰ·ŠΰΆ»ΰ·ΰ·ƒΰ·ŠΰΆ­ ΰΆ†ΰΆšΰ·˜ΰΆ­ΰ·’ΰΆΊ: 48x48px.", + "scenes.app.popup.appsparameters.pages.parameters_form_small_text": "ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆšΰ·ΰ·ΰΆ±ΰΆΊ ΰΆ±ΰ·œΰΆšΰ·… ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰΆ”ΰΆΆΰ·š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ ΰΆ­ΰ·”ΰ·… ࢴࢸࢫ්࢚ ΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰ· ΰΆšΰΆ»ΰΆΊΰ·’. ΰΆ”ΰΆΆΰΆ§ ΰΆ‘ΰΆΊ ΰ·ƒΰ·’ΰΆΊΰΆ½ΰ·”ΰΆΈ Twake ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·ŠΰΆ§ ࢽࢢා ΰΆ―ΰ·“ΰΆΈΰΆ§ ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊ ࢱࢸ්, ΰΆΈΰ·™ΰΆΈ ΰ·€ΰ·’ΰΆšΰΆ½ΰ·ŠΰΆ΄ΰΆΊ ΰ·ƒΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊ ࢚ࢻࢱ්ࢱ.", + "scenes.app.popup.appsparameters.pages.write_privileges_label": "ΰΆ½ΰ·’ΰ·€ΰ·“ΰΆΈΰ·š ΰ·€ΰΆ»ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·ƒΰ·ΰΆ―", + "scenes.app.popup.appsparameters.pages.danger_zone_small_text": "You can not delete this app if it is published.", + "scenes.app.popup.appsparameters.pages.remove_app_button": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ࢸ࢚ࢱ්ࢱ", + "scenes.app.popup.workspaceparameter.pages.displayed_preferencies_subtitle": "ࢸࢱාࢴ ΰ·ƒΰΆ‚ΰΆ―ΰΆ»ΰ·Šΰ·ΰΆ± ࢚ࢻࢱ්ࢱ", + "scenes.app.popup.workspaceparameter.pages.webhooks_access_subtitle": "webhooks ΰ·€ΰ·™ΰΆ­ ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·€ΰ·šΰ·ΰΆΊ", + "scenes.apps.calendar.export_view_menu": "Export the view...", + "scenes.apps.calendar.ics_subscription_menu": "ICS ΰΆ―ΰ·ΰΆΊΰΆšΰΆ­ΰ·Šΰ·€ ΰ·ƒΰΆΆΰ·ΰΆ³ΰ·’ΰΆΊΰΆšΰ·Š ࢽࢢා ࢜ࢱ්ࢱ", + "scenes.apps.calendar.modals.remove_button": "ࢸ࢚ࢱ්ࢱ", + "scenes.apps.calendar.modals.remove_event_button": "ΰ·ƒΰ·’ΰΆ―ΰ·”ΰ·€ΰ·“ΰΆΈ ࢸ࢚ࢱ්ࢱ", + "scenes.apps.calendar.modals.remove_event_text": "ΰ·ƒΰ·’ΰΆ―ΰ·”ΰ·€ΰ·“ΰΆΈ ࢸ࢚ࢱ්ࢱࢯ?", + "scenes.apps.calendar.remove_calendar_confirmation": "ΰΆ―ΰ·’ΰΆ± ࢯࢻ්ශࢱࢺ ΰ·ƒΰ·„ ΰΆ‘ΰ·„ΰ·’ ΰ·ƒΰ·’ΰΆ―ΰ·”ΰ·€ΰ·“ΰΆΈΰ·Š ΰ·ƒΰ·ŠΰΆΰ·’ΰΆ»ΰ·€ΰΆΈ ࢸ࢚ࢱ්ࢱࢯ?", + "scenes.apps.drive.message_added_file": "{{$1}} {{$2}} ΰΆΊΰ·€ΰΆ± ΰΆ½ΰΆ―ΰ·“.", + "scenes.apps.drive.remove_definitely_menu": "ΰ·ƒΰ·ŠΰΆΰ·’ΰΆ»ΰ·€ΰΆΈ ࢸ࢚ࢱ්ࢱ", + "scenes.apps.drive.unconfigured_tab": "ΰΆΈΰ·™ΰΆΈ ࢧැࢢࢺ ΰΆ­ΰ·€ΰΆΈ ΰ·€ΰ·’ΰΆ±ΰ·Šβ€ΰΆΊΰ·ΰ·ƒ ࢚ࢻ ࢱොࢸැࢭ.", + "scenes.apps.messages.message.pin_button": "Pin message", + "scenes.apps.messages.message.unpin_button": "ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊ ΰΆ‡ΰΆΈΰ·”ΰΆ«ΰ·”ΰΆΈ ΰΆ‰ΰ·€ΰΆ­ΰ·Š ࢚ࢻࢱ්ࢱ", + "scenes.apps.messages.message.pinned": "ΰΆ΄ΰ·’ΰΆ±ΰ·Š ࢚ࢻ ΰΆ‡ΰΆ­", + "scenes.apps.messages.message.remove_button": "ࢸ࢚ࢱ්ࢱ", + "scenes.login.verifymail.success": "ΰΆ”ΰΆΆΰΆœΰ·š ΰ·€ΰ·’ΰΆ―ΰ·Šβ€ΰΆΊΰ·”ΰΆ­ΰ·Š ࢭැࢴෑࢽ ΰ·ƒΰ·ΰΆ»ΰ·ŠΰΆΰΆšΰ·€ ΰ·ƒΰΆ­ΰ·Šβ€ΰΆΊΰ·ΰΆ΄ΰΆ±ΰΆΊ ࢚ࢻࢱ ΰΆ½ΰΆ―ΰ·“!", + "scenes.login.verifymail.verification_waiting": "ΰ·ƒΰΆ­ΰ·Šβ€ΰΆΊΰ·ΰΆ΄ΰΆ±ΰΆΊ සࢳහා ࢻැࢳී ΰ·ƒΰ·’ΰΆ§ΰ·’ΰΆΈΰ·’ΰΆ±ΰ·Š...", + "services.apps.messages.no_command_possible": "'{{$2}}' ΰΆ±ΰ·œΰΆ΄ΰ·€ΰΆ­ΰ·’ΰΆ± ࢱිසා හෝ විࢰාࢱ ΰ·ƒΰ·‘ΰΆ―ΰ·“ΰΆΈΰΆ§ ΰΆ‰ΰΆ© ΰΆ±ΰ·œΰΆ―ΰ·™ΰΆ± ࢱිසා ΰΆ…ΰΆ΄ΰΆ§ '{{$1}}' විࢰාࢱࢺ ΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰ·ΰΆ­ΰ·ŠΰΆΈΰΆš ΰΆšΰ·… ΰΆ±ΰ·œΰ·„ΰ·ΰΆš.", + "scenes.apps.calendar.unconfigured_tab": "ΰΆΈΰ·™ΰΆΈ ࢧැࢢࢺ ΰΆ­ΰ·€ΰΆΈ ΰ·€ΰ·’ΰΆ±ΰ·Šβ€ΰΆΊΰ·ΰ·ƒ ࢚ࢻ ࢱොࢸැࢭ.", + "scenes.apps.drive.top_menu_no_items": "{{$1}} items", + "scenes.apps.drive.viewer.download_desktop": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈΰ·š ΰΆ΄ΰ·™ΰΆ»ΰΆ―ΰ·ƒΰ·”ΰΆ±ΰ·Š ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ Twake Desktop ࢢා࢜ࢱ්ࢱ", + "scenes.apps.tasks.board.tasks.use_deadline": "ΰΆ±ΰ·’ΰΆΊΰΆΈΰ·’ΰΆ­ ΰΆšΰ·ΰ·…ΰΆΊ ࢷාවිࢭࢺ", + "scenes.apps.tasks.board.tasks.use_starttime": "ΰΆ†ΰΆ»ΰΆΈΰ·ŠΰΆ·ΰΆš ΰ·€ΰ·šΰΆ½ΰ·ΰ·€ ࢷාවිࢭࢺ", + "scenes.apps.tasks.board.tasks.in_list": "ΰΆ½ΰ·ΰΆΊΰ·’ΰ·ƒΰ·ŠΰΆ­ΰ·”ΰ·€ΰ·š", + "scenes.apps.tasks.board.starts": "ΰΆ†ΰΆ»ΰΆΈΰ·ŠΰΆ· ΰΆšΰΆ»ΰΆΊΰ·’", + "scenes.apps.tasks.board.ends": "සࢳහා ΰ·ƒΰ·’ΰΆ―ΰ·” ΰΆšΰ·… ΰΆΊΰ·”ΰΆ­ΰ·”ΰΆΊ", + "scenes.apps.tasks.board.list_name": "ΰΆ½ΰ·ΰΆΊΰ·’ΰ·ƒΰ·ŠΰΆ­ΰ·”ΰ·€ΰ·š ΰΆ±ΰΆΈ", + "scenes.app.popup.workspaceparameter.pages.logo_company_modify_description": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰΆ…ΰΆ±ΰ·”ΰΆ»ΰ·”ΰ·€ ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ ", + "scenes.apps.account.account.send_info": "ΰΆΈΰ·™ΰΆΈ ΰΆ…ΰΆšΰ·ŠΰΆ­ΰΆ΄ΰΆ­ΰ·Šβ€ΰΆ» ΰΆ­ΰ·œΰΆ»ΰΆ­ΰ·”ΰΆ»ΰ·” ΰΆ”ΰΆΆΰ·š ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·ΰΆ§ ΰΆΊΰ·€ΰΆ±ΰ·ŠΰΆ±.", + "components.drive.elements.configurate_mod": "ΰΆΈΰ·ΰΆ―ΰ·’ΰ·„ΰΆ­ΰ·ŠΰΆšΰΆ»ΰ·” ΰ·€ΰ·’ΰΆ±ΰ·Šβ€ΰΆΊΰ·ΰ·ƒΰΆœΰΆ­ ࢚ࢻࢱ්ࢱ...", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_creation": "ΰΆ±ΰ·€ ࢧැࢢ් ΰΆ‘ΰΆšΰΆšΰ·Š ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.popup.adduserfromtwakeconsole.current_users_state": "{{$1}} ࢊࢸේࢽ්(ΰΆΊ) ΰΆ‘ΰΆšΰΆ­ΰ·” ΰ·€ΰΆ±ΰ·” ΰΆ‡ΰΆ­", + "scenes.apps.messages.message.activity_message.a_added_b_to_the_channel": "{{$1}} ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰΆ§ {{$2}} ΰΆ‘ΰΆšΰ·Š ΰΆšΰ·…ΰ·šΰΆΊ", + "scenes.apps.messages.message.activity_message.a_removed_b_from_the_channel": "{{$1}} {{$2}} ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰ·™ΰΆ±ΰ·Š ΰΆ‰ΰ·€ΰΆ­ΰ·Š ࢚ࢻࢱ ΰΆ½ΰΆ―ΰ·“", + "scenes.apps.messages.message.activity_message.a_created_channel_tab": "{{$1}} ΰΆ±ΰ·€ {{$2}} ࢧැࢢࢺ්࢚ {{$3}} ΰΆ‘ΰΆšΰ·Š ࢚ࢻࢱ ΰΆ½ΰΆ―ΰ·“", + "scenes.apps.messages.message.activity_message.a_deleted_channel_tab": "{{$1}} {{$2}} ࢧැࢢࢺ {{$3}} ΰΆ‰ΰ·€ΰΆ­ΰ·Š ࢚ࢻࢱ ΰΆ½ΰΆ―ΰ·“", + "general.verify": "ΰΆ­ΰ·„ΰ·€ΰ·”ΰΆ»ΰ·” ࢚ࢻࢱ්ࢱ", + "components.unverified_account.typography_text_danger": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ…ΰΆ­ΰ·Šΰ·„ΰΆ―ΰ· ΰΆΆΰ·ΰΆ½ΰ·“ΰΆΈΰ·š ࢚ාࢽ සීࢸාව ΰΆ­ΰ·”ΰ·… ΰΆ”ΰΆΆΰΆ§ {{$1}} ΰΆ―ΰ·’ΰΆ±(ΰΆΊ) ΰΆ‰ΰΆ­ΰ·’ΰΆ»ΰ·’ΰ·€ ΰΆ‡ΰΆ­. ΰΆ…ΰΆ­ΰ·Šΰ·„ΰΆ―ΰ· ΰΆΆΰ·ΰΆ½ΰ·“ΰΆΈΰ·š ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈ ΰΆ―ΰ·’ΰΆ± 7࢚ࢧ ΰΆ΄ΰ·ƒΰ·” ΰΆ…ΰ·€ΰ·„ΰ·’ΰΆ» ΰΆšΰΆ»ΰΆ±ΰ·” ΰΆ½ΰΆΆΰΆ± ΰΆ…ΰΆ­ΰΆ» ࢽිࢺාࢴࢯිࢂࢠි ΰ·€ΰ·“ ࢸාස 1࢚ࢧ ΰΆ΄ΰ·ƒΰ·” ΰ·ƒΰ·ŠΰΆΰ·’ΰΆ»ΰ·€ΰΆΈ ࢸ࢚ා ΰΆ―ΰΆΈΰΆ±ΰ·” ࢽැࢢේ. ΰΆ…ΰΆ΄ΰ·’ ΰΆ”ΰΆΆΰΆ§ ΰΆ‘ΰ·€ΰ·– ΰ·ƒΰΆ­ΰ·Šβ€ΰΆΊΰ·ΰΆ΄ΰΆ± ΰ·€ΰ·’ΰΆ―ΰ·Šβ€ΰΆΊΰ·”ΰΆ­ΰ·Š ࢭැࢴෑࢽෙහි \"ࢸ࢜ේ ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈ ΰ·ƒΰΆ­ΰ·Šβ€ΰΆΊΰ·ΰΆ΄ΰΆ±ΰΆΊ ࢚ࢻࢱ්ࢱ\" ࢢොࢭ්ࢭࢸ ΰΆšΰ·ŠΰΆ½ΰ·’ΰΆšΰ·Š ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰ·™ΰΆ±ΰ·Š ΰΆ”ΰΆΆΰΆ§ ΰΆ”ΰΆΆΰΆœΰ·š ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈ ΰ·ƒΰΆ­ΰ·Šβ€ΰΆΊΰ·ΰΆ΄ΰΆ±ΰΆΊ ΰΆšΰ·… ΰ·„ΰ·ΰΆš.", + "components.unverified_account.verification_details": "ΰΆ…ΰΆ΄ΰ·’ ΰ·ƒΰΆ­ΰ·Šβ€ΰΆΊΰ·ΰΆ΄ΰΆ± ΰ·€ΰ·’ΰ·ƒΰ·ŠΰΆ­ΰΆ» ࢺවා ΰΆ‡ΰΆ­", + "components.account_verication_status_unverified": "ΰΆ­ΰ·„ΰ·€ΰ·”ΰΆ»ΰ·” ΰΆ±ΰ·œΰΆšΰ·…", + "components.verify_mail.paragraph": "ΰΆ”ΰΆΆΰΆ§ ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊ ࢱࢸ් ΰΆ”ΰΆΆΰΆ§ ΰΆ‘ΰΆΊ ΰΆ΄ΰ·ƒΰ·”ΰ·€ ΰΆšΰ·… ΰ·„ΰ·ΰΆšΰ·’ ΰΆ±ΰΆΈΰ·”ΰΆ­ΰ·Š ΰ·ƒΰΆ­ΰ·Šβ€ΰΆΊΰ·ΰΆ΄ΰΆ±ΰΆΊ ΰΆ±ΰ·œΰΆšΰ·… ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈΰ·Šΰ·€ΰΆ½ΰΆ§ ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·€ΰ·šΰ·ΰΆΊ ΰΆ‡ΰΆ­ΰ·ŠΰΆ­ΰ·š Twake ΰ·„ΰ·’ ΰ·ƒΰ·“ΰΆΈΰ·’ΰΆ­ ΰΆ…ΰΆ±ΰ·”ΰ·€ΰ·ΰΆ―ΰΆΊΰΆšΰΆ§ ΰΆ΄ΰΆΈΰΆ«ΰ·’", + "services.console_services.toaster.success_verify_email": "ΰΆ”ΰΆΆΰΆœΰ·š ΰ·€ΰ·’ΰΆ―ΰ·Šβ€ΰΆΊΰ·”ΰΆ­ΰ·Š ࢭැࢴැࢽ් ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈΰΆ§ ΰ·ƒΰΆ­ΰ·Šβ€ΰΆΊΰ·ΰΆ΄ΰΆ± ΰ·ƒΰΆΆΰ·ΰΆ³ΰ·’ΰΆΊΰΆšΰ·Š ࢺවා ΰΆ‡ΰΆ­", + "scenes.client.channels_bar.modals.guest_management.input_placeholder": "ΰΆ…ΰΆΈΰ·”ΰΆ­ΰ·ŠΰΆ­ΰΆ±ΰ·Š හෝ ΰΆ­ΰ·’ΰΆΆΰ·™ΰΆ± ΰ·€ΰ·’-ࢭැࢴැࢽ් ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ±", + "general.user.deleted": "ࢸ࢚ා ࢯැࢸූ ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈ", + "components.richtexteditor.toolbar.bold": "ΰΆΈΰ·„ΰΆ­", + "components.richtexteditor.toolbar.italic": "ΰΆ‡ΰΆ½", + "components.richtexteditor.toolbar.strikethrough": "ΰΆ΄ΰ·„ΰΆ» හࢻහා", + "components.richtexteditor.toolbar.unordered-list": "ΰΆΆΰ·”ΰΆ½ΰΆ§ΰ·’ΰΆ­ ΰΆ½ΰ·ΰΆΊΰ·’ΰ·ƒΰ·ŠΰΆ­ΰ·”ΰ·€", + "components.richtexteditor.toolbar.ordered-list": "ΰΆ‡ΰΆ«ΰ·€ΰ·”ΰΆΈΰ·Š ΰΆšΰ·… ΰΆ½ΰ·ΰΆΊΰ·’ΰ·ƒΰ·ŠΰΆ­ΰ·”ΰ·€", + "components.richtexteditor.toolbar.blockquote": "වාࢻࢫ ࢋࢴුࢧා ΰΆ―ΰ·ΰΆšΰ·Šΰ·€ΰ·“ΰΆΈ", + "components.richtexteditor.toolbar.code-block": "Code Block", + "components.locked_features.locked_history_banner.description": "ΰΆ”ΰΆΆΰ·š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰΆ§ ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ© ࢜ොࢩ්࢚ ΰΆ­ΰ·’ΰΆΆΰ·š! ΰΆ”ΰΆΆΰΆœΰ·š ΰ·ƒΰ·’ΰΆΊΰΆ½ΰ·”ΰΆΈ ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ© ࢉࢭිහාසࢺࢧ ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·€ΰ·šΰ· ΰ·€ΰ·“ΰΆΈΰΆ§ ࢯැࢱ් ΰΆ‹ΰΆ­ΰ·Šΰ·ΰ·Šβ€ΰΆ»ΰ·šΰΆ«ΰ·’ ࢚ࢻࢱ්ࢱ.", + "components.locked_features.locked_guests_popup.description": "ΰΆ…ΰΆ΄ΰ·œΰΆΊΰ·’!! ΰΆ”ΰΆΆΰΆ§ ΰΆ”ΰΆΆΰ·š වැࢩࢢිࢸࢧ ࢢාහිࢻ ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·ŠΰΆ§ ࢆࢻාࢰࢱා ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊ ΰΆΆΰ·€ ΰΆ΄ΰ·™ΰΆ±ΰ·š. ΰΆ”ΰΆΆΰΆ§ ΰΆ…ΰΆΈΰ·”ΰΆ­ΰ·ŠΰΆ­ΰΆ±ΰ·Š ΰ·ƒΰ·„ ࢢාහිࢻ ΰ·„ΰ·€ΰ·”ΰΆ½ΰ·ŠΰΆšΰΆ»ΰ·”ΰ·€ΰΆ±ΰ·Š ΰ·ƒΰΆΈΰΆŸ ΰ·ƒΰ·„ΰΆΊΰ·ΰΆœΰΆΊΰ·™ΰΆ±ΰ·Š ΰΆšΰΆ§ΰΆΊΰ·”ΰΆ­ΰ·” ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊ ࢱࢸ් ΰΆ”ΰΆΆΰ·š සැࢽසුࢸ ΰΆ‹ΰΆ­ΰ·Šΰ·ΰ·Šβ€ΰΆ»ΰ·šΰΆ«ΰ·’ ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈ ΰ·ƒΰΆ½ΰΆšΰ· ࢢැࢽීࢸࢧ ΰΆ”ΰΆΆΰΆ§ ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊ ΰ·€ΰ·’ΰΆΊ ΰ·„ΰ·ΰΆšΰ·’ΰΆΊ. ΰΆ…ΰΆ΄ΰΆœΰ·š ΰΆΈΰ·’ΰΆ½ΰΆšΰΆ»ΰΆ« ΰ·€ΰ·’ΰΆšΰΆ½ΰ·ŠΰΆ΄ ΰΆœΰ·€ΰ·šΰ·‚ΰΆ«ΰΆΊ ࢚ࢻ ΰΆ”ΰΆΆΰ·š ࢚ࢫ්ࢩාࢺࢸ් ΰ·ƒΰ·„ΰΆΊΰ·ΰΆœΰ·“ΰΆ­ΰ· ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊΰΆ­ΰ· සࢳහා ΰ·„ΰ·œΰΆ³ΰΆΈ ΰ·€ΰ·’ΰΆšΰΆ½ΰ·ŠΰΆ΄ΰΆΊ ࢭෝࢻࢱ්ࢱ.", + "components.on_boarding.company_billing_banner.admin_or_owner_text": "ΰΆ”ΰΆΆΰ·š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·Š ΰΆ―ΰ·ΰΆΊΰΆšΰΆ­ΰ·Šΰ·€ΰΆΊΰ·š ΰΆœΰ·ΰΆ§ΰΆ½ΰ·”ΰ·€ΰΆšΰ·Š ΰΆ­ΰ·’ΰΆΆΰ·š. ΰΆšΰΆ»ΰ·”ΰΆ«ΰ·ΰΆšΰΆ» ΰΆ”ΰΆΆΰ·š ΰΆ‘ΰΆš ࢢࢽࢱ්ࢱ", + "components.on_boarding.company_billing_banner.guest_or_member_text": "ΰΆ”ΰΆΆΰ·š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·Š ΰΆ―ΰ·ΰΆΊΰΆšΰΆ­ΰ·Šΰ·€ΰΆΊΰ·š ΰΆœΰ·ΰΆ§ΰΆ½ΰ·”ΰ·€ΰΆšΰ·Š ΰΆ­ΰ·’ΰΆΆΰ·š. ΰΆšΰΆ»ΰ·”ΰΆ«ΰ·ΰΆšΰΆ» ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰ·„ΰ·’ΰΆΈΰ·’ΰΆšΰΆ»ΰ·” හෝ ΰΆ΄ΰΆ»ΰ·’ΰΆ΄ΰ·ΰΆ½ΰΆš ΰΆ…ΰΆΈΰΆ­ΰΆ±ΰ·ŠΰΆ±!", + "components.on_boarding.company_billing_banner.link": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·Š ࢯාࢺ࢚ ΰ·ƒΰ·ΰΆ½ΰ·ΰ·ƒΰ·ŠΰΆΈ", + "components.on_boarding.popups.blocked_company.description": "Twake ΰ·€ΰ·™ΰΆ­ ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ―ΰ·ΰΆΊΰΆšΰΆ­ΰ·Šΰ·€ΰΆΊ ࢚ࢽ් ΰΆ‰ΰΆšΰ·”ΰΆ­ΰ·Š ΰ·€ΰ·“ ΰΆ‡ΰΆ­. ΰΆšΰΆ»ΰ·”ΰΆ«ΰ·ΰΆšΰΆ» ΰΆ‘ΰΆΊ ΰΆ…ΰΆ½ΰ·”ΰΆ­ΰ·Š ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰ·ƒΰ·„ ΰΆ”ΰΆΆΰ·š ࢚ࢫ්ࢩාࢺࢸ ΰ·ƒΰΆΈΰΆŸ ࢱැවࢭ ΰ·ƒΰΆ±ΰ·ŠΰΆ±ΰ·’ΰ·€ΰ·šΰΆ―ΰΆ±ΰΆΊ ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰ·„ΰ·ΰΆšΰ·’ ΰ·€ΰ·“ΰΆΈ සࢳහා ΰΆ”ΰΆΆΰ·š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰ·„ΰ·’ΰΆΈΰ·’ΰΆšΰΆ»ΰ·” හෝ ΰΆ΄ΰΆ»ΰ·’ΰΆ΄ΰ·ΰΆ½ΰΆš ΰΆ…ΰΆΈΰΆ­ΰΆ±ΰ·ŠΰΆ±!", + "components.on_boarding.popups.blocked_company.learn_more_text": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·Š ࢯාࢺ࢚ ΰ·ƒΰ·ΰΆ½ΰ·ΰ·ƒΰ·ŠΰΆΈ ࢜ැࢱ ΰΆ­ΰ·€ ࢯැࢱ ΰΆœΰ·ΰΆ±ΰ·“ΰΆΈΰΆ§ ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊΰΆ―?", + "scenes.apps.messages.message.parts.deleted_content.text.current_user": "ΰΆ”ΰΆΆ ΰΆΈΰ·™ΰΆΈ ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊ ࢸ࢚ා ΰΆ‡ΰΆ­", + "scenes.apps.messages.message.parts.deleted_content.text": "{{$1}} ΰΆ”ΰ·„ΰ·”ΰΆœΰ·š ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊ ࢸ࢚ා ΰΆ‡ΰΆ­", + "components.locked_features.locked_workspace_popup.text": "ΰΆ…ΰΆ΄ΰ·œΰΆΊΰ·’!! ΰΆ”ΰΆΆΰ·š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ ΰΆ­ΰ·”ΰ·… ΰΆ±ΰ·€ වැࢩ ΰΆ‰ΰΆ©ΰΆšΰ·Š ΰΆ±ΰ·’ΰΆ»ΰ·ŠΰΆΈΰ·ΰΆ«ΰΆΊ ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆ”ΰΆΆΰΆ§ ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊΰΆ―? ΰΆ”ΰΆΆΰΆ§ ΰΆ”ΰΆΆΰ·š සැࢽසුࢸ ΰΆ‹ΰΆ­ΰ·Šΰ·ΰ·Šβ€ΰΆ»ΰ·šΰΆ«ΰ·’ ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈ ΰ·ƒΰΆ½ΰΆšΰ· ࢢැࢽීࢸࢧ ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊ ΰ·€ΰ·’ΰΆΊ ΰ·„ΰ·ΰΆšΰ·’ΰΆΊ. ΰΆ…ΰΆ΄ΰΆœΰ·š ΰΆΈΰ·’ΰΆ½ΰΆšΰΆ»ΰΆ« ΰ·€ΰ·’ΰΆšΰΆ½ΰ·ŠΰΆ΄ΰΆΊΰΆ±ΰ·Š ΰΆœΰ·€ΰ·šΰ·‚ΰΆ«ΰΆΊ ࢚ࢻ ΰΆ”ΰΆΆΰΆœΰ·š ࢚ࢫ්ࢩාࢺࢸ් ΰ·ƒΰ·„ΰΆΊΰ·ΰΆœΰ·“ΰΆ­ΰ· ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊΰΆ­ΰ· සࢳහා ΰ·„ΰ·œΰΆ³ΰΆΈ ΰΆ­ΰ·šΰΆ»ΰ·“ΰΆΈ ࢭෝࢻࢱ්ࢱ.", + "components.locked_features.locked_only_office_popup.text": "ΰΆ…ΰΆ΄ΰ·œΰΆΊΰ·’!! ΰΆ”ΰΆΆΰΆ§ Twake ΰ·€ΰ·™ΰΆ­ΰ·’ΰΆ±ΰ·Š ΰΆœΰ·œΰΆ±ΰ·”ΰ·€ ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊ ΰΆΆΰ·€ ΰΆ΄ΰ·™ΰΆ±ΰ·š. ΰΆ”ΰΆΆΰΆ§ ࢚ාࢻ්ࢺාࢽ ΰΆ½ΰ·’ΰΆ΄ΰ·’ΰΆœΰ·œΰΆ±ΰ·” වࢧා ΰ·ƒΰ·„ΰΆΊΰ·ΰΆœΰΆΊΰ·™ΰΆ±ΰ·Š ΰΆšΰΆ§ΰΆΊΰ·”ΰΆ­ΰ·” ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊ ࢱࢸ් ΰΆ”ΰΆΆΰ·š සැࢽසුࢸ ΰΆ‹ΰΆ­ΰ·Šΰ·ΰ·Šβ€ΰΆ»ΰ·šΰΆ«ΰ·’ ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈ ΰ·ƒΰΆ½ΰΆšΰ· ࢢැࢽීࢸࢧ ΰΆ”ΰΆΆΰΆ§ ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊ ΰ·€ΰ·’ΰΆΊ ΰ·„ΰ·ΰΆšΰ·’ΰΆΊ. ΰΆ…ΰΆ΄ΰΆœΰ·š ΰΆΈΰ·’ΰΆ½ΰΆšΰΆ»ΰΆ« ΰ·€ΰ·’ΰΆšΰΆ½ΰ·ŠΰΆ΄ ΰΆœΰ·€ΰ·šΰ·‚ΰΆ«ΰΆΊ ࢚ࢻ ΰΆ”ΰΆΆΰ·š ࢚ࢫ්ࢩාࢺࢸ් ΰ·ƒΰ·„ΰΆΊΰ·ΰΆœΰ·“ΰΆ­ΰ· ΰΆ…ΰ·€ΰ·ΰ·Šβ€ΰΆΊΰΆ­ΰ· සࢳහා ΰ·„ΰ·œΰΆ³ΰΆΈ ΰ·€ΰ·’ΰΆšΰΆ½ΰ·ŠΰΆ΄ΰΆΊ ࢭෝࢻࢱ්ࢱ.", + "general.resume": "ΰΆ…ΰΆ»ΰΆΉΰΆ±ΰ·ŠΰΆ±", + "general.pause": "Pause", + "login.create_account": "ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈ ࢭࢱࢱ්ࢱ", + "'": "'", + "scenes.apps.messages.message.types.no_message_in_thread": "ΰΆ­ΰ·€ΰΆΈ ΰΆšΰ·’ΰ·ƒΰ·’ΰ·€ΰ·™ΰΆšΰ·Š ΰΆ΄ΰ·’ΰ·…ΰ·’ΰΆ­ΰ·”ΰΆ»ΰ·” ΰΆ―ΰ·”ΰΆ±ΰ·ŠΰΆ±ΰ·š ࢱැࢭ.", + "\"": "\"", + "scenes.app.channelsbar.currentuser.reset": "ΰΆΊΰ·…ΰ·’ ΰΆ΄ΰ·’ΰ·„ΰ·’ΰΆ§ΰ·”ΰ·€ΰΆ±ΰ·ŠΰΆ±", + "login.login_error": "ΰΆ΄ΰ·”ΰΆ»ΰΆ±ΰΆΊ ΰ·€ΰ·“ΰΆΈΰ·šΰΆ―ΰ·“ ΰΆ―ΰ·ΰ·‚ΰΆΊΰΆšΰ·’", + "scenes.app.workspaces.welcome_page.no_workspace_subtitle": "ΰΆ­ΰ·€ΰΆΈ ΰΆšΰ·’ΰ·ƒΰ·’ΰ·€ΰ·™ΰΆšΰ·” ΰΆ”ΰΆΆΰΆ§ ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰΆšΰΆ§ ࢆࢻාࢰࢱා ࢚ࢻ ࢱැࢭ.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.label": "ΰΆ΄ΰ·™ΰΆ»ΰΆ±ΰ·’ΰΆΈΰ·’ වැࢩࢢිࢸ", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.description": "ΰΆΈΰ·™ΰΆΈ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰΆ§ ΰ·ƒΰ·’ΰΆΊΰΆ½ΰ·”ΰΆΈ වැࢩ ΰΆ‰ΰΆ© ࢷාවිࢭා ࢚ࢻࢱ්ࢱࢱ්ࢧ ΰ·ƒΰ·Šΰ·€ΰΆΊΰΆ‚ΰΆšΰ·Šβ€ΰΆ»ΰ·“ΰΆΊΰ·€ ࢆࢻාࢰࢱා ࢚ࢻࢱ්ࢱ", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.title": "ΰΆ”ΰΆΆ {{$1}} ΰΆΈΰ·ΰΆšΰ·“ΰΆΈΰΆ§ ΰΆ†ΰ·ƒΰΆ±ΰ·ŠΰΆ±ΰΆΊΰ·’", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.alert_total_members": "ΰΆ”ΰΆΆΰΆ§ ΰΆ­ΰ·€ΰΆΈΰΆ­ΰ·Š {{$2}} ΰ·„ΰ·’ {{$1}} ΰ·ƒΰ·ΰΆΈΰ·ΰΆ’ΰ·’ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š ΰ·ƒΰ·’ΰΆ§ΰ·“. ΰΆΈΰ·™ΰΆΈ ࢚ාࢻ්ࢺ ΰΆ‰ΰΆ© ࢸ࢚ා ࢯැࢸීࢸࢧ ΰ·„ΰ·ΰΆšΰ·’ ΰ·€ΰΆ± ΰΆ΄ΰΆ»ΰ·’ΰΆ―ΰ·’ ΰΆ”ΰΆΆ ΰ·ƒΰ·’ΰΆΊΰΆ½ΰ·”ΰΆΈ ΰ·ƒΰ·ΰΆΈΰ·ΰΆ’ΰ·’ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š ΰΆ‰ΰ·€ΰΆ­ΰ·Š ΰΆšΰ·… ΰΆΊΰ·”ΰΆ­ΰ·”ΰΆΊ.", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.checkbox": "ࢸ࢜ේ ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·š ΰ·ƒΰ·’ΰΆΊΰΆ½ΰ·”ΰΆΈ ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ© ΰ·ƒΰ·„ ΰΆœΰ·œΰΆ±ΰ·” ࢸ࢚ා ΰΆ―ΰΆΈΰΆ± ΰΆΆΰ·€ ΰΆΈΰΆ§ වැࢧහෙࢱවා.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.max_size": "ΰΆ‹ΰΆ΄ΰΆ»ΰ·’ΰΆΈ ࢽාࢂ࢑ࢱ ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆΈΰ·ΰΆ«ΰΆΊ 5mb ΰ·€ΰ·š", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.bad_format": "ࢱࢻ࢚ ΰΆ†ΰΆšΰ·˜ΰΆ­ΰ·’ΰΆΊ, png gif ΰ·ƒΰ·„ jpg ࢴࢸࢫ්࢚ ΰΆ…ΰ·€ΰ·ƒΰΆ» ΰΆ‡ΰΆ­", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.unknown": "ࢱොࢯࢱ්ࢱා ΰΆ―ΰ·ΰ·‚ΰΆΊΰΆšΰ·’", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.prefix": "ΰΆ―ΰ·ΰ·‚ΰΆΊΰΆšΰ·’", + "components.rich_text_editor.plugins.suggestions.default_message.display_results": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰΆ±ΰ·Š ΰ·ƒΰΆ‚ΰΆ―ΰΆ»ΰ·Šΰ·ΰΆ± ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆ…ΰ·€ΰΆΈ ΰ·€ΰ·ΰΆΊΰ·™ΰΆ±ΰ·Š ΰΆ…ΰΆšΰ·”ΰΆ»ΰ·” ΰΆ­ΰ·”ΰΆ±ΰΆšΰ·Š ΰΆ½ΰ·’ΰΆΊΰΆ±ΰ·ŠΰΆ±", + "components.rich_text_editor.plugins.suggestions.default_message.no_user_found": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·™ΰΆšΰ·” ΰ·„ΰΆΈΰ·” ΰΆ±ΰ·œΰ·€ΰ·“ΰΆΊ", + "components.rich_text_editor.plugins.suggestions.default_message.no_emoji_found": "ΰΆ‰ΰΆΈΰ·œΰΆ’ΰ·’ ΰ·„ΰΆΈΰ·” ΰΆ±ΰ·œΰ·€ΰ·“ΰΆΊ", + "components.rich_text_editor.plugins.suggestions.default_message.no_command_found": "ΰ·€ΰ·’ΰΆ°ΰ·ΰΆ±ΰΆΊΰΆšΰ·Š ΰ·„ΰΆΈΰ·” ΰΆ±ΰ·œΰ·€ΰ·“ΰΆΊ", + "scenes.app.messages.input.parts.is_writing.message.user_is_writing": "{{$1}} ࢽිࢺࢱවා...", + "scenes.app.messages.input.parts.is_writing.message.users_are_writing": "{{$1}} ΰ·ƒΰ·„ {{$2}} ࢽිࢺࢱවා...", + "scenes.app.messages.input.parts.is_writing.message.users_and_more_are_writing": "{{$1}}, {{$2}} ΰ·ƒΰ·„ {{$3}} ΰΆ­ΰ·€ΰΆ­ΰ·Š ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š ΰΆ½ΰ·’ΰΆΊΰΆ±ΰ·ŠΰΆ±ΰ·š...", + "components.locked_features_components.locked_invite_alert.message_part_1": "ΰΆ”ΰΆΆΰ·š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ ΰΆ‘ΰ·„ΰ·’ ΰΆ‹ΰΆ΄ΰΆ»ΰ·’ΰΆΈ ΰ·ƒΰ·ΰΆΈΰ·ΰΆ’ΰ·’ΰΆšΰΆΊΰ·’ΰΆ±ΰ·ŠΰΆœΰ·š {{$1}} සීࢸාවࢧ ΰ·…ΰΆŸΰ· ΰ·€ΰ·“ ΰΆ‡ΰΆ­. ΰΆšΰΆ»ΰ·”ΰΆ«ΰ·ΰΆšΰΆ» ", + "components.locked_features_components.locked_invite_alert.message_link": "ΰΆ”ΰΆΆΰ·š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ ΰΆ‹ΰ·ƒΰ·ƒΰ·Š ࢚ࢻࢱ්ࢱ", + "components.locked_features_components.locked_invite_alert.message_part_2": " ΰΆ­ΰ·€ΰΆ­ΰ·Š ΰ·ƒΰ·ΰΆΈΰ·ΰΆ’ΰ·’ΰΆšΰΆΊΰ·’ΰΆ±ΰ·ŠΰΆ§ ࢆࢻාࢰࢱා ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§.", + "components.locked_features_components.locked_invite_alert.message_magic_link": " ΰΆ”ΰΆΆΰ·š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰ·„ΰ·’ΰΆΈΰ·’ΰΆšΰΆ»ΰ·” හෝ ΰΆ΄ΰΆ»ΰ·’ΰΆ΄ΰ·ΰΆ½ΰΆš ΰΆ…ΰΆΈΰΆ­ΰΆ±ΰ·ŠΰΆ±.", + "views.client.popup.workspace_parameter.pages.workspace_members.link_to_console": "ΰΆšΰ·œΰΆ±ΰ·Šΰ·ƒΰ·ΰΆ½ΰΆΊ ΰΆΈΰΆ­ ࢸ࢜ේ ΰ·ƒΰ·’ΰΆΊΰΆ½ΰ·”ΰΆΈ ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·Š ΰ·ƒΰ·ΰΆΈΰ·ΰΆ’ΰ·’ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š ࢢࢽࢱ්ࢱ", + "scenes.app.popup.appsparameters.pages.application_creator.title": "ΰΆ±ΰ·€ ΰΆ’ΰΆšΰ·ΰΆΆΰΆ―ΰ·ŠΰΆ° ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈ", + "scenes.app.popup.appsparameters.pages.application_creator.checkbox": "ΰΆΈΰ·™ΰΆΈ ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰ·„ΰ·’ΰΆΈΰ·’ΰΆšΰΆ»ΰ·”ΰΆ§ ΰ·ƒΰ·„ ΰΆ΄ΰΆ»ΰ·’ΰΆ΄ΰ·ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·ŠΰΆ§ ΰΆΈΰ·™ΰΆΈ ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰ·€ΰ·™ΰΆ±ΰ·ƒΰ·Š ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰ·ƒΰ·„ ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆšΰ·ΰ· ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰ·„ΰ·ΰΆšΰ·’ ΰ·€ΰΆ±ΰ·” ΰΆ‡ΰΆ­ΰ·’ ΰΆΆΰ·€ ΰΆΈΰΆ§ ΰ·€ΰ·ΰΆ§ΰ·„ΰ·š.", + "twake.application.access.title": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ සࢳහා ࢱිවැࢻࢯි ΰ·€ΰ·’ΰ·‚ΰΆΊ ΰΆ΄ΰΆΰΆΊΰΆ±ΰ·Š ࢭෝࢻࢱ්ࢱ.", + "twake.application.access.no_default_scopes_available'": "ΰΆΈΰ·™ΰΆΈ ΰΆ…ΰΆ±ΰ·”ΰΆšΰΆ½ΰΆ±ΰΆΊΰΆ§ ΰΆšΰ·’ΰ·ƒΰ·’ΰΆ―ΰ·” {{$1}} ΰΆ΄ΰ·Šβ€ΰΆ»ΰ·€ΰ·šΰ·ΰΆΊΰΆšΰ·Š ࢱොࢸැࢭ", + "scenes.app.popup.appsparameters.pages.application_editor.help_link": "Twake API ΰΆ½ΰ·šΰΆ›ΰΆ±ΰΆœΰΆ­ ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈ", + "scenes.app.popup.appsparameters.pages.application_editor.help_text": "ΰΆ”ΰΆΆ ΰΆΈΰ·šΰ·€ΰ· ΰΆ΄ΰ·”ΰΆ»ΰ·€ΰΆ±ΰ·ŠΰΆ±ΰ·š ΰΆšΰ·™ΰ·ƒΰ·šΰΆ―ΰ·ΰΆΊΰ·’ ࢱොࢯࢱ්ࢱේ ࢱࢸ්, ࢺࢱ්ࢱ ", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰ·ƒΰ·ΰΆ»ΰ·ŠΰΆΰΆšΰ·€ ΰΆ‰ΰ·€ΰΆ­ΰ·Š ࢚ࢻࢱ ΰΆ½ΰΆ―ΰ·“ {{$1}} !", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed_error": "ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰΆ‰ΰ·€ΰΆ­ΰ·Š ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰ·šΰΆ―ΰ·“ ΰΆ―ΰ·ΰ·‚ΰΆΊΰΆšΰ·Š {{$1}} !", + "scenes.app.popup.appsparameters.pages.application_editor.application_published": "{{$1}} ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰ·ƒΰ·ΰΆ»ΰ·ŠΰΆΰΆšΰΆΊΰ·’!", + "scenes.app.integrations_parameters.add_application": "ΰΆ±ΰ·€ ΰΆ’ΰΆšΰ·ΰΆΆΰΆ―ΰ·ŠΰΆ° ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈ", + "scenes.app.integrations_parameters.company_applications_table.more_menu.developer_settings": "ΰ·ƒΰΆ‚ΰ·€ΰΆ»ΰ·ŠΰΆ°ΰΆš ΰ·ƒΰ·ΰΆšΰ·ƒΰ·”ΰΆΈΰ·Š", + "scenes.app.popup.appsparameters.pages.amazing_app_description": "ΰΆ”ΰΆΆΰ·š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰ·€ΰΆ ΰΆ± ΰΆšΰ·’ΰ·„ΰ·’ΰΆ΄ΰΆΊΰΆšΰ·’ΰΆ±ΰ·Š ΰ·€ΰ·’ΰ·ƒΰ·ŠΰΆ­ΰΆ» ࢚ࢻࢱ්ࢱ", + "scenes.app.popup.appsparameters.pages.app.private_key": "ΰΆ΄ΰ·”ΰΆ―ΰ·ŠΰΆœΰΆ½ΰ·’ΰΆš ΰΆΊΰΆ­ΰ·”ΰΆ»", + "components.rich_text_editor.plugins.suggestions.loading": "ΰΆ­ΰ·€ ΰ·„ΰ·œΰΆΊΰΆ±ΰ·€ΰ·", + "components.open_desktop_popup.subtitle": "Twake ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰΆ­ΰ·”ΰ·… ΰ·€ΰ·’ΰ·€ΰ·˜ΰΆ­ ࢚ࢻࢱ ΰΆ½ΰΆ―ΰ·“", + "components.open_desktop_popup.open_here_link": "ΰΆ’ ΰ·€ΰ·™ΰΆ±ΰ·”ΰ·€ΰΆ§ ΰΆΈΰ·™ΰΆ­ΰΆ± ΰ·€ΰ·’ΰ·€ΰ·˜ΰΆ­ ࢚ࢻࢱ්ࢱ", + "molecules.download_banner.title": "Twake ΰ·€ΰΆ½ΰ·’ΰΆ±ΰ·Š ΰΆ‹ΰΆ΄ΰΆ»ΰ·’ΰΆΈ ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆΊΰ·ΰΆ’ΰΆ± ࢽࢢා ࢜ࢱ්ࢱ, ࢯැࢱ් ΰΆ©ΰ·™ΰ·ƒΰ·ŠΰΆšΰ·ŠΰΆ§ΰ·œΰΆ΄ΰ·Š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ࢢා࢜ࢱ්ࢱ", + "molecules.download_banner.download_button": "ΰΆ©ΰ·™ΰ·ƒΰ·ŠΰΆšΰ·ŠΰΆ§ΰ·œΰΆ΄ΰ·Š ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ࢢා࢜ࢱ්ࢱ", + "scenes.app.channelsbar.channel_copy_link": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ· සࢢැࢳිࢺ ΰΆ΄ΰ·’ΰΆ§ΰΆ΄ΰΆ­ΰ·Š ࢚ࢻࢱ්ࢱ", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.success.update": "ΰ·ƒΰ·ΰΆ»ΰ·ŠΰΆΰΆšΰ·€ ΰΆΊΰ·ΰ·€ΰΆ­ΰ·ŠΰΆšΰ·ΰΆ½ΰ·“ΰΆ± ࢚ࢻࢱ ΰΆ½ΰΆ―ΰ·“", + "components.searchpopup.no_results_for": "සࢳහා ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ­ΰ·’ΰΆ΅ΰΆ½ ΰΆ­ΰ·’ΰΆΆΰ·”ΰΆ«ΰ·š ࢱැࢭ", + "components.searchpopup.try_new_search": "ΰΆ±ΰ·€ ΰ·ƒΰ·™ΰ·€ΰ·“ΰΆΈΰΆšΰ·Š ΰΆ‹ΰΆ­ΰ·Šΰ·ƒΰ·ΰ·„ ࢚ࢻࢱ්ࢱ", + "components.searchpopup.all": "ΰ·ƒΰ·’ΰΆΊΰΆ½ΰ·”ΰΆΈ", + "components.searchpopup.chats": "ΰΆšΰΆ­ΰ·ΰΆΆΰ·ƒΰ·Š", + "components.searchpopup.media": "ࢸාࢰ්ࢺ", + "components.searchpopup.files": "ΰΆœΰ·œΰΆ±ΰ·”", + "components.searchpopup.recent_chats": "ΰΆΈΰ·‘ΰΆ­ ΰΆšΰΆ­ΰ·ΰΆΆΰ·ƒΰ·Š", + "components.searchpopup.recent_media": "ΰΆΈΰ·‘ΰΆ­ ࢸාࢰ්ࢺ", + "components.searchpopup.recent_files": "ΰΆΈΰ·‘ΰΆ­ ΰΆœΰ·œΰΆ±ΰ·”", + "components.searchpopup.recent_channels_and_contacts": "ΰΆΈΰ·‘ΰΆ­ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ· ΰ·ƒΰ·„ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ°ΰΆ­ΰ·", + "components.searchpopup.header_title": "ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ±", + "components.searchpopup.scope.company": "ΰ·ƒΰ·’ΰΆΊΰΆ½ΰ·”ΰΆΈ ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ ΰΆ­ΰ·”ΰ·…", + "components.searchpopup.scope.channel": "ΰΆΈΰ·™ΰΆΈ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰ·š", + "components.searchpopup.channels": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·", + "components.searchpopup.messages": "ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©", + "scenes.client.channelbar.channelmemberslist.not_members_section": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰΆ±ΰ·Š ΰΆΈΰ·™ΰΆΈ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰ·š ࢱැࢭ", + "general.yes": "ΰΆ”ΰ·€ΰ·Š", + "components.channel_attachement_list.medias": "ࢸාࢰ්ࢺࢺࢱ්", + "components.channel_attachement_list.files": "ΰΆœΰ·œΰΆ±ΰ·”", + "components.searchpopup.start_search": "ΰ·ƒΰ·™ΰ·€ΰ·“ΰΆΈ ΰΆ†ΰΆ»ΰΆΈΰ·ŠΰΆ· ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆΈΰ·–ΰΆ½ ΰΆ΄ΰΆ― ΰΆšΰ·’ΰ·„ΰ·’ΰΆ΄ΰΆΊΰΆšΰ·Š ΰΆ‡ΰΆ­ΰ·”ΰ·…ΰΆ­ΰ·Š ࢚ࢻࢱ්ࢱ.", + "components.searchpopup.see_more": "ΰΆ­ΰ·€ ࢢࢽࢱ්ࢱ", + "scenes.client.channelbar.channelmemberslist.search_invite": "ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ± ΰ·ƒΰ·„ ΰΆΈΰ·™ΰΆΈ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰΆ§ ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·ŠΰΆ§ ࢆࢻාࢰࢱා ࢚ࢻࢱ්ࢱ", + "scenes.client.channelbar.channelmemberslist.search_invite_notice": "ΰΆΈΰ·™ΰΆΈ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰ·š ΰ·ƒΰ·ΰΆΈΰ·ΰΆ’ΰ·’ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š විශාࢽ ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆΈΰ·ΰΆ«ΰΆΊΰΆšΰ·Š ࢱොࢸැࢭ. ΰ·€ΰ·’ΰΆ―ΰ·Šβ€ΰΆΊΰ·”ΰΆ­ΰ·Š ΰΆ­ΰ·ΰΆ΄ΰ·‘ΰΆ½ΰ·™ΰΆ±ΰ·Š හෝ ΰΆ±ΰΆΈΰ·™ΰΆ±ΰ·Š ࢯැࢱ් ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ± ΰ·ƒΰ·„ ࢆࢻාࢰࢱා ࢚ࢻࢱ්ࢱ.", + "scenes.client.channelbar.channelmemberslist.invite_email_button": "ΰΆ†ΰΆœΰΆ±ΰ·ŠΰΆ­ΰ·”ΰΆšΰΆΊΰ·™ΰΆšΰ·” ΰΆ½ΰ·™ΰ·ƒ ࢴࢸࢫ්࢚ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰΆ§ ΰΆ‘ΰΆšΰ·Š ࢚ࢻࢱ්ࢱ", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace": "ΰ·ƒΰ·ΰΆΈΰ·ΰΆ’ΰ·’ΰΆšΰΆΊΰ·™ΰΆšΰ·” ΰΆ½ΰ·™ΰ·ƒ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰΆ§ ΰ·ƒΰ·„ වැࢩࢢිࢸࢧ ΰΆ‘ΰΆšΰ·Š ࢚ࢻࢱ්ࢱ", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace_confirm": "{{$1}} ΰ·ƒΰ·ΰΆΈΰ·ΰΆ’ΰ·’ΰΆšΰΆΊΰ·™ΰΆšΰ·” ΰΆ½ΰ·™ΰ·ƒ වැࢩࢢිࢸࢧ ࢆࢻාࢰࢱා ࢚ࢻࢱ්ࢱࢯ?", + "scenes.client.channelbar.channelmemberslist.search_invite_type_email": "ΰ·€ΰ·’ΰΆ―ΰ·Šβ€ΰΆΊΰ·”ΰΆ­ΰ·Š ΰΆ­ΰ·ΰΆ΄ΰ·‘ΰΆ½ΰ·™ΰΆ±ΰ·Š ࢆࢻාࢰࢱා ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰ·€ΰΆ½ΰΆ‚ΰΆœΰ·” ΰΆ‘ΰΆšΰΆ­ΰ·” ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆšΰ·Š ΰΆ§ΰΆΊΰ·’ΰΆ΄ΰ·Š ࢚ࢻࢱ්ࢱ.", + "scenes.client.channelbar.channelmemberslist.pending_section": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰΆ±ΰ·ŠΰΆœΰ·š ࢆࢻාࢰࢱාව ΰΆ΄ΰ·œΰΆ»ΰ·œΰΆ­ΰ·ŠΰΆ­ΰ·”ΰ·€ΰ·™ΰΆ±ΰ·Š", + "scenes.client.channelbar.channelmemberslist.members_section": "ΰΆΈΰ·™ΰΆΈ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰ·š ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š", + "scenes.client.join_private_channel.info": "ΰΆΈΰ·™ΰΆΈ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰ·š ΰΆΈΰ·™ΰΆΈ ΰΆ…ΰΆ±ΰ·ŠΰΆ­ΰΆ»ΰ·ŠΰΆœΰΆ­ΰΆΊ සීࢸා ࢚ࢻ ΰΆ‡ΰΆ­ හෝ ΰΆ±ΰ·œΰΆ΄ΰ·€ΰΆ­ΰ·’ΰΆΊΰ·’. ࢆࢻාࢰࢱා ࢽැࢢීࢸࢧ ΰΆšΰΆ»ΰ·”ΰΆ«ΰ·ΰΆšΰΆ» ΰΆΈΰ·™ΰΆΈ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰ·š ΰ·ƒΰ·ΰΆΈΰ·ΰΆ’ΰ·’ΰΆšΰΆΊΰ·™ΰΆšΰ·” ΰΆ…ΰΆΈΰΆ­ΰΆ±ΰ·ŠΰΆ±.", + "scenes.client.join_public_channel": "ΰΆΈΰ·™ΰΆΈ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰΆ§ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ° ΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.client.join_public_channel.info": "ΰΆ”ΰΆΆ ΰΆΈΰ·™ΰΆΈ ΰ·ƒΰ·˜ΰΆ’ΰ·” ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰ·š ΰ·ƒΰ·ΰΆΈΰ·ΰΆ’ΰ·’ΰΆšΰΆΊΰ·™ΰΆšΰ·Š ΰΆ±ΰ·œΰ·€ΰ·š. ࢯැࢱ් ΰ·ƒΰ·ΰΆšΰΆ ΰ·ŠΰΆ‘ΰ·ΰ·€ ΰΆ†ΰΆ»ΰΆΈΰ·ŠΰΆ· ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆΈΰ·™ΰΆΈ ࢢොࢭ්ࢭࢸ ΰΆšΰ·ŠΰΆ½ΰ·’ΰΆšΰ·Š ࢚ࢻࢱ්ࢱ.", + "general.no": "ࢱැࢭ", + "components.open_desktop_popup.open_here_link_forever": "ࢱැවࢭ ΰΆšΰ·’ΰ·ƒΰ·’ ΰΆ―ΰ·’ΰΆ±ΰ·™ΰΆš ΰΆΊΰ·™ΰΆ―ΰ·”ΰΆΈ ΰ·€ΰ·’ΰ·€ΰ·˜ΰΆ­ ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆ‹ΰΆ­ΰ·Šΰ·ƒΰ·ΰ·„ ࢱො࢚ࢻࢱ්ࢱ", + "components.channel_attachement_list.title": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ· ΰΆœΰ·œΰΆ±ΰ·” ΰ·ƒΰ·„ ΰΆΈΰ·ΰΆ°ΰ·Šβ€ΰΆΊ", + "components.channel_attachement_list.nothing_found": "ΰΆ­ΰ·€ΰΆΈΰΆ­ΰ·Š ΰΆΈΰ·™ΰ·„ΰ·’ ΰΆšΰ·’ΰ·ƒΰ·’ΰ·€ΰΆšΰ·Š ࢱැࢭ", + "molecules.message_quote.deleted": "ΰΆΈΰ·™ΰΆΈ ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊ ࢸ࢚ා ΰΆ―ΰΆΈΰΆ± ΰΆ½ΰΆ―ΰ·“", + "scenes.apps.messages.jump": "ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊΰΆ§ ΰΆ΄ΰΆ±ΰ·’ΰΆ±ΰ·ŠΰΆ±", + "components.channel_attachement_list.open": "ΰΆœΰ·ΰΆ½ΰΆ»ΰ·’ΰΆΊ ΰ·€ΰ·’ΰ·€ΰ·˜ΰΆ­ ࢚ࢻࢱ්ࢱ", + "scenes.apps.account.on_console": "ΰΆ”ΰΆΆΰΆœΰ·š ΰΆœΰ·ΰΆ½ΰ·“ΰΆΊ ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈΰ·Š ࢸࢱාࢴ ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§, Console ΰ·€ΰ·™ΰΆ­ ࢺࢱ්ࢱ ΰΆΈΰΆ­ ΰΆšΰ·ŠΰΆ½ΰ·’ΰΆšΰ·Š ࢚ࢻࢱ්ࢱ.", + "scenes.apps.account.assistant.description": "Twake ΰ·ƒΰ·„ΰΆšΰΆ»ΰ·”ΰΆ§ Twake ΰ·„ΰ·’ ΰΆ”ΰΆΆΰΆœΰ·š ࢑ࢯිࢱෙࢯා වැࢩ ΰΆ΄ΰ·’ΰ·…ΰ·’ΰΆΆΰΆ³ ΰΆ…ΰ·€ΰΆΆΰ·ΰΆ°ΰΆΊΰΆšΰ·Š ࢽࢢා ΰΆ―ΰ·“ΰΆΈΰΆ§ ΰ·ƒΰ·„ ΰΆ”ΰΆΆΰ·š ΰΆ―ΰ·€ΰ·ƒ ΰΆ­ΰ·”ΰ·… ΰ·ƒΰ·ŠΰΆΈΰ·ΰΆ»ΰ·ŠΰΆ§ΰ·Š ΰΆšΰ·™ΰΆ§ΰ·’ΰΆΈΰΆ‚ ΰ·ƒΰ·„ ΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊΰ· සැࢴࢺීࢸࢧ ΰ·„ΰ·ΰΆšΰ·’ ΰ·€ΰ·š. ΰ·ƒΰ·„ΰ·ΰΆΊΰΆšΰΆΊΰ· Work@Home ΰΆΈΰ·”ΰΆ½ΰΆ΄ΰ·’ΰΆ»ΰ·“ΰΆΈΰ·š ΰΆšΰ·œΰΆ§ΰ·ƒΰΆšΰ·’ https://workathome.linagora.com/ ΰ·ƒΰ·„ ࢯැࢱࢧ Linagora ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ ΰΆ­ΰ·”ΰ·… ࢴࢸࢫ්࢚ ΰΆ΄ΰΆ»ΰ·“ΰΆšΰ·Šβ€ΰ·‚ΰ· ΰΆšΰ·™ΰΆ»ΰ·™ΰΆ± ΰΆ…ΰΆ­ΰΆ» ΰΆ‰ΰΆœΰ·™ΰΆ±ΰ·“ΰΆΈΰ·š ΰΆ…ΰΆ―ΰ·’ΰΆΊΰΆ»ΰ·š ΰΆ΄ΰ·€ΰΆ­ΰ·“. ΰΆ‘ΰΆΊΰ·’ΰΆ±ΰ·Š ΰΆ…ΰΆ―ΰ·„ΰ·ƒΰ·Š ΰ·€ΰΆ±ΰ·ŠΰΆ±ΰ·š ΰΆ…ΰΆ΄ΰΆœΰ·š ΰΆ…ΰΆ±ΰ·ΰΆœΰΆ­ ΰ·ƒΰ·„ΰΆšΰ·ΰΆ» ΰ·€ΰ·’ΰ·ΰ·šΰ·‚ΰ·ΰΆ‚ΰΆœΰΆΊ ΰΆ΄ΰ·”ΰ·„ΰ·”ΰΆ«ΰ·” ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈ සࢳහා ΰΆ…ΰΆ΄ΰ·’ Twake ࢷාවිࢭ ࢯࢭ්ࢭ ΰΆΊΰ·€ΰΆ± ΰΆΆΰ·€ΰΆΊΰ·’.", + "scenes.apps.account.assistant.share.nothing": "ΰ·ƒΰ·„ΰΆšΰΆ»ΰ·” ΰ·ƒΰΆΈΰΆœ ΰΆšΰ·’ΰ·ƒΰ·’ΰ·€ΰΆšΰ·Š ࢢෙࢯා ࢱො࢜ࢱ්ࢱ (ΰ·ƒΰ·„ΰ·ΰΆΊΰΆš ΰΆ…ΰΆΆΰΆ½ ࢚ࢻࢱ්ࢱ)", + "scenes.apps.account.assistant.share.all": "ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ© ΰ·ƒΰ·„ ΰΆœΰ·œΰΆ±ΰ·” ΰΆ…ΰΆ±ΰ·ŠΰΆ­ΰΆ»ΰ·ŠΰΆœΰΆ­ΰΆΊ ΰΆ‡ΰΆ­ΰ·”ΰ·…ΰ·” ΰ·ƒΰ·’ΰΆΊΰΆ½ΰ·ŠΰΆ½ ࢢෙࢯා ࢜ࢱ්ࢱ", + "scenes.apps.account.assistant.share.metadata": "ࢴාࢻ-ࢯࢭ්ࢭ ࢢෙࢯා ࢜ࢱ්ࢱ, ΰΆ±ΰΆΈΰ·”ΰΆ­ΰ·Š ΰΆ…ΰΆ±ΰ·ŠΰΆ­ΰΆ»ΰ·ŠΰΆœΰΆ­ΰΆΊ ΰΆ±ΰ·œΰ·€ΰ·š", + "scenes.apps.account.assistant.success": "ΰΆ”ΰΆΆΰ·š ࢸࢱාࢴࢺࢱ් ΰ·ƒΰ·ΰΆ»ΰ·ŠΰΆΰΆš ΰΆ½ΰ·™ΰ·ƒ ΰΆΊΰ·ΰ·€ΰΆ­ΰ·ŠΰΆšΰ·ΰΆ½ΰ·“ΰΆ± ࢚ࢻ ΰΆ‡ΰΆ­.", + "scenes.apps.account.assistant.title": "ΰ·ƒΰ·„ΰΆšΰ·ΰΆ»", + "components.message_seen_by.title": "ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊ ࢯැ࢚ ΰΆ‡ΰΆ­ΰ·’ ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š", + "components.message_seen_by.none_seen_it": "ࢭාࢸ ΰΆšΰ·€ΰ·”ΰΆ»ΰ·”ΰΆ­ΰ·Š ΰΆΈΰ·ΰ·ƒΰ·šΰΆ’ΰ·Š ΰΆ‘ΰΆš ࢢࢽࢽා ΰΆ±ΰ·‘", + "components.message_seen_by.btn": "ΰ·€ΰ·’ΰ·ƒΰ·ŠΰΆ­ΰΆ»", + "molecules.quoted_content.attachements": "{{$1}} ΰΆ‡ΰΆΈΰ·”ΰΆ«ΰ·”ΰΆΈΰ·Š", + "scenes.apps.messages.message.user_deactivated": "ΰΆ”ΰΆΆ ΰΆ…ΰΆšΰ·Šβ€ΰΆ»ΰ·’ΰΆΊ ΰΆšΰ·… ΰΆœΰ·’ΰΆ«ΰ·”ΰΆΈΰΆš ΰΆ½ΰ·šΰΆ›ΰΆ±ΰ·ΰΆœΰ·ΰΆ»ΰΆΊ ΰΆ±ΰΆ»ΰΆΉΰΆΈΰ·’ΰΆ±ΰ·Š ΰ·ƒΰ·’ΰΆ§ΰ·“", + "general.user.deactivated": "ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ· ΰΆ­ΰ·€ΰΆ―ΰ·”ΰΆ»ΰΆ§ΰΆ­ΰ·Š ΰΆΈΰ·™ΰΆΈ ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·™ΰ·„ΰ·’ ࢱොࢸැࢭ", + "general.user.connected": "ΰΆ”ΰΆ±ΰ·ŠΰΆ½ΰΆΊΰ·’ΰΆ±ΰ·Š", + "scenes.app.popup.userparameter.pages.email_notif_delay_quarter_hour": "විࢱාࢩි 15 ΰΆΊΰ·’", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_day": "ΰΆ―ΰ·’ΰΆ± 1 ΰΆΊΰ·’", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_hour": "ࢴැࢺ 1 ΰΆΊΰ·’", + "scenes.app.popup.userparameter.pages.email_notif_delay_never": "ΰΆšΰ·€ΰΆ―ΰ·ΰ·€ΰΆ­ΰ·Š ࢱැහැ", + "scenes.app.popup.userparameter.pages.notification_sound.defaut": "ΰΆ΄ΰ·™ΰΆ»ΰΆ±ΰ·’ΰΆΈΰ·’ΰΆΊ", + "scenes.app.popup.userparameter.pages.notification_sound.none": "ΰΆšΰ·’ΰ·ƒΰ·’ΰ·€ΰΆšΰ·Š ࢱැࢭ", + "scenes.client.channelbar.readonly_channel.checkbox": "ΰΆ½ΰ·’ΰ·€ΰ·“ΰΆΈΰ·š ΰ·„ΰ·ΰΆšΰ·’ΰΆΊΰ·ΰ·€ සීࢸා ࢚ࢻࢱ්ࢱ", + "scenes.apps.messages.message.forward": "ΰΆ‰ΰΆ―ΰ·’ΰΆ»ΰ·’ΰΆΊΰΆ§", + "scenes.apps.messages.message.forward.title": "ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊ ΰΆΊΰ·œΰΆΈΰ·” ࢚ࢻࢱ්ࢱ", + "scenes.apps.messages.message.forward.comment": "ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊΰΆšΰ·Š ΰΆ‘ΰΆšΰ·Š ࢚ࢻࢱ්ࢱ", + "scenes.apps.messages.message.forward.confirm": "$1 ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰΆ§ ΰΆΊΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.apps.messages.message.forward.send": "ΰΆ΄ΰΆ«ΰ·’ΰ·€ΰ·’ΰΆ©ΰΆΊ ΰΆΊΰ·œΰΆΈΰ·” ࢚ࢻࢱ ΰΆ½ΰΆ―ΰ·“", + "components.channelselector.confirm": "$1 ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€(ΰΆΊ) ࢭෝࢻࢱ්ࢱ", + "components.channelselector.search": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ· ΰ·ƒΰ·„ ΰ·ƒΰ·ΰΆšΰΆ ΰ·ŠΰΆ‘ΰ· ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ±", + "components.channelselector.title": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ· ࢭෝࢻࢱ්ࢱ", + "scenes.app.channelsbar.channel_access": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ· ΰΆ΄ΰ·ŠΰΆ»ΰ·€ΰ·šΰ·ΰΆΊ", + "scenes.app.channelsbar.channel_access.save": "ΰΆ΄ΰ·ŠΰΆ»ΰ·€ΰ·šΰ· ΰ·ƒΰ·ΰΆšΰ·ƒΰ·”ΰΆΈΰ·Š ΰ·ƒΰ·”ΰΆ»ΰΆšΰ·’ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.channelsbar.channel_access.readonly": "ΰΆšΰ·’ΰΆΊΰ·€ΰ·“ΰΆΈΰΆ§ ࢴࢸࢫ්࢚ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€", + "scenes.app.channelsbar.channel_access.readonly.info": "ΰΆ΄ΰΆ»ΰ·’ΰΆ΄ΰ·ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·ŠΰΆ§, ΰΆ΄ΰΆ»ΰ·’ΰΆ΄ΰ·ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·ŠΰΆ§ ΰ·ƒΰ·„ ΰ·„ΰ·’ΰΆΈΰ·’ΰΆšΰΆ»ΰ·”ΰ·€ΰΆ±ΰ·ŠΰΆ§ ΰΆ½ΰ·’ΰ·€ΰ·“ΰΆΈ සීࢸා ࢚ࢻࢱ්ࢱ.", + "scenes.app.channelsbar.channel_access.visibility": "ΰΆ΄ΰ·œΰΆ―ΰ·” ΰΆ―ΰ·˜ΰ·ΰ·Šβ€ΰΆΊΰΆ­ΰ·ΰ·€", + "scenes.app.channelsbar.channel_access.visibility.info": "ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈΰ·š ΰΆ…ΰΆΈΰ·”ΰΆ­ΰ·ŠΰΆ­ΰΆ±ΰ·Š හැࢻ ΰΆ•ΰΆ±ΰ·‘ΰΆΈ ΰΆšΰ·™ΰΆ±ΰ·™ΰΆšΰ·”ΰΆ§ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ° ΰ·€ΰ·’ΰΆΊ ΰ·„ΰ·ΰΆš.", + "scenes.app.channelsbar.channel_access.default": "ΰ·ƒΰ·Šΰ·€ΰΆΊΰΆ‚ΰΆšΰ·Šβ€ΰΆ»ΰ·“ΰΆΊΰ·€ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ° ΰ·€ΰ·“ΰΆΈ", + "scenes.app.channelsbar.channel_access.default.info": "ΰΆ±ΰ·€ ΰ·ƒΰ·ΰΆΈΰ·ΰΆ’ΰ·’ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š ΰ·ƒΰ·Šΰ·€ΰΆΊΰΆ‚ΰΆšΰ·Šβ€ΰΆ»ΰ·“ΰΆΊΰ·€ ΰΆΈΰ·™ΰ·„ΰ·’ ΰΆ‘ΰΆšΰΆ­ΰ·” ΰ·€ΰ·š.", + "scenes.app.channelsbar.channel_information": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ· ΰΆ­ΰ·œΰΆ»ΰΆ­ΰ·”ΰΆ»ΰ·” ΰ·ƒΰΆ‚ΰ·ƒΰ·ŠΰΆšΰΆ»ΰΆ«ΰΆΊ ࢚ࢻࢱ්ࢱ", + "scenes.app.channelsbar.channel_information.logo.add": "ΰΆ΄ΰ·’ΰΆ±ΰ·ŠΰΆ­ΰ·–ΰΆ»ΰΆΊ ΰΆ‹ΰΆ©ΰ·”ΰΆœΰΆ­ ࢚ࢻࢱ්ࢱ", + "scenes.app.channelsbar.channel_information.logo.remove": "ΰΆ΄ΰ·’ΰΆ±ΰ·ŠΰΆ­ΰ·–ΰΆ»ΰΆΊ ΰΆ‰ΰ·€ΰΆ­ΰ·Š ࢚ࢻࢱ්ࢱ", + "scenes.app.channelsbar.channel_information.name": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ΰ·š ΰΆ±ΰΆΈ", + "scenes.app.channelsbar.channel_information.description": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ· ΰ·€ΰ·’ΰ·ƒΰ·ŠΰΆ­ΰΆ»ΰΆΊ", + "scenes.app.channelsbar.channel_information.description.placeholder": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ· ΰ·€ΰ·’ΰ·ƒΰ·ŠΰΆ­ΰΆ»ΰΆΊ, ΰΆ”ΰΆΆΰΆ§ markdown ࢷාවිࢭා ΰΆšΰ·… ΰ·„ΰ·ΰΆšΰ·’ΰΆΊ.", + "scenes.app.channelsbar.channel_information.group": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ· ࢚ࢫ්ࢩාࢺࢸ", + "scenes.app.channelsbar.channel_information.group.none": "ࢭෝࢻා ࢱැࢭ", + "scenes.app.channelsbar.channel_information.group.new": "ΰΆ±ΰ·€ ࢚ࢫ්ࢩාࢺࢸ්࢚ ΰ·ƒΰ·ΰΆ―ΰΆ±ΰ·ŠΰΆ±", + "scenes.app.channelsbar.channel_information.group.save": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ· ΰ·ƒΰΆΈΰ·–ΰ·„ΰΆΊ $1 ΰΆ½ΰ·™ΰ·ƒ ΰ·ƒΰΆšΰ·ƒΰΆ±ΰ·ŠΰΆ±", + "scenes.app.channelsbar.channel_information.group.save_none": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ· ࢚ࢫ්ࢩාࢺࢸ ΰ·ƒΰΆšΰ·ƒΰΆ±ΰ·ŠΰΆ± ࢑ࢴා", + "scenes.app.channelsbar.channel_information.save": "ΰΆ­ΰ·œΰΆ»ΰΆ­ΰ·”ΰΆ»ΰ·” ΰ·ƒΰ·”ΰΆ»ΰΆšΰ·’ΰΆ±ΰ·ŠΰΆ±", + "scenes.client.channelbar.channelmemberslist.invite_to_workspace": "{{$1}} වැࢩࢢිࢸࢧ ࢆࢻාࢰࢱා ࢚ࢻࢱ්ࢱ ➑", + "components.invitation.reached_limit.text": "ΰΆ”ΰΆΆ ΰΆ”ΰΆΆΰ·š ΰ·ƒΰΆΈΰ·ΰΆœΰΆΈ ΰΆ­ΰ·”ΰ·… ΰΆ‹ΰΆ΄ΰΆ»ΰ·’ΰΆΈ ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š ΰ·ƒΰΆ‚ΰΆ›ΰ·Šβ€ΰΆΊΰ·ΰ·€ΰΆ§ ΰ·…ΰΆŸΰ· ΰ·€ΰ·’ΰΆΊ. ΰΆ”ΰΆΆΰΆœΰ·š ΰΆ―ΰ·ΰΆΊΰΆšΰΆ­ΰ·Šΰ·€ΰΆΊ වැࢩි ࢚ࢻࢱ්ࢱ හෝ ΰΆΈΰ·™ΰΆΈ ΰΆ΄ΰΆ»ΰ·’ΰ·ΰ·“ΰΆ½ΰΆšΰΆΊΰ·’ΰΆ±ΰ·Š ΰΆ…ΰΆΈΰ·”ΰΆ­ΰ·ŠΰΆ­ΰΆ±ΰ·Š ΰΆ½ΰ·™ΰ·ƒ ΰΆ‘ΰΆšΰ·Š ࢚ࢻࢱ්ࢱ", + "components.invitation.allow_anyone_by_email.text": "@{{$1}} ΰ·€ΰ·’ΰΆ―ΰ·Šβ€ΰΆΊΰ·”ΰΆ­ΰ·Š ࢭැࢴෑࢽ ΰΆ‡ΰΆ­ΰ·’ ΰΆ•ΰΆ±ΰ·‘ΰΆΈ ΰΆšΰ·™ΰΆ±ΰ·™ΰΆšΰ·”ΰΆ§ ΰΆΈΰ·™ΰΆΈ වැࢩࢢිࢸࢧ ΰ·ƒΰΆΈΰ·ŠΰΆΆΰΆ±ΰ·ŠΰΆ° ΰ·€ΰ·“ΰΆΈΰΆ§ ΰΆ‰ΰΆ© ΰΆ―ΰ·™ΰΆ±ΰ·ŠΰΆ±", + "components.invitation.invitation_channels.button": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ· ΰ·€ΰΆ½ΰΆ§ ࢆࢻාࢰࢱා ࢚ࢻࢱ්ࢱ", + "components.invitation.invitation_input_list.add": "ΰΆ‘ΰΆšΰΆ­ΰ·” ࢚ࢻࢱ්ࢱ", + "components.invitation.invitation_input_list.member": "ΰ·ƒΰ·ΰΆΈΰ·ΰΆ’ΰ·’ΰΆš", + "components.invitation.invitation_input_list.guest": "ΰΆ…ΰΆΈΰ·”ΰΆ­ΰ·ŠΰΆ­ΰΆ±ΰ·ŠΰΆœΰ·š", + "components.invitation.invitation_input_list.placeholder": "ΰ·€ΰ·’ΰΆ―ΰ·Šβ€ΰΆΊΰ·”ΰΆ­ΰ·Š ΰΆ­ΰ·ΰΆ΄ΰ·‘ΰΆ½ΰΆšΰ·Š ΰΆ§ΰΆΊΰ·’ΰΆ΄ΰ·Š ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈ ΰΆ…ΰΆ»ΰΆΉΰΆ±ΰ·ŠΰΆ±", + "components.invitation.invitation_sent.title": "ࢆࢻාࢰࢱා ΰ·ƒΰ·ΰΆ»ΰ·ŠΰΆΰΆšΰ·€ ࢺවා ΰΆ‡ΰΆ­", + "components.invitation.invitation_sent.subtitle_status": "ΰΆ”ΰΆΆΰΆ§ ࢆࢻාࢰࢱා ΰΆ­ΰΆ­ΰ·ŠΰΆ­ΰ·Šΰ·€ΰΆΊ ΰΆ±ΰ·’ΰΆ»ΰ·“ΰΆšΰ·Šΰ·‚ΰΆ«ΰΆΊ ΰΆšΰ·… ΰ·„ΰ·ΰΆš:", + "components.invitation.invitation_sent.subtitle_location": "࢚ාࢻ්ࢺ ΰΆ‰ΰΆ© ΰ·ƒΰ·ΰΆšΰ·ƒΰ·“ΰΆΈΰ·Š > ΰ·ƒΰ·ΰΆΈΰ·ΰΆ’ΰ·’ΰΆš ΰΆšΰ·…ΰΆΈΰΆ±ΰ·ΰΆšΰΆ»ΰΆ«ΰΆΊ", + "components.invitation.invitation_sent.link": "ࢆࢻාࢰࢱා ΰΆ­ΰΆ­ΰ·ŠΰΆ­ΰ·Šΰ·€ΰΆΊ ΰΆ΄ΰΆ»ΰ·“ΰΆšΰ·Šΰ·‚ΰ· ࢚ࢻࢱ්ࢱ", + "components.invitation.invitation_sent.button": "ΰΆ­ΰ·€ΰΆ­ΰ·Š ࢆࢻාࢰࢱා ΰΆΊΰ·€ΰΆ±ΰ·ŠΰΆ±", + "components.invitation.invitation_target.invite_as_guests": "ΰΆ…ΰΆΈΰ·”ΰΆ­ΰ·ŠΰΆ­ΰΆ±ΰ·Š ΰΆ½ΰ·™ΰ·ƒ සැࢸࢧ ࢆࢻාࢰࢱා ࢚ࢻࢱ්ࢱ", + "components.invitation.invitation_target.invite_as_members": "ΰ·ƒΰ·ΰΆΈΰ·ΰΆ’ΰ·’ΰΆšΰΆΊΰΆ±ΰ·Š ΰΆ½ΰ·™ΰ·ƒ සැࢸࢧ ࢆࢻාࢰࢱා", + "components.invitation.invitation_target.channels_button": "ࢆࢻාࢰࢱා ΰΆšΰ·’ΰΆ»ΰ·“ΰΆΈΰΆ§ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·", + "components.invitation.workspace_link.text": "ΰ·€ΰ·ΰΆ©ΰΆΆΰ·’ΰΆΈΰ·Š ࢆࢻාࢰࢱා සࢢැࢳිࢺ", + "components.invitation.workspace_link.button": "ΰΆ΄ΰ·’ΰΆ§ΰΆ΄ΰΆ­ΰ·Š ࢚ࢻࢱ්ࢱ", + "components.invitation.title": "{{$1}} ΰ·€ΰ·™ΰΆ­ ΰΆΈΰ·’ΰΆ±ΰ·’ΰ·ƒΰ·”ΰΆ±ΰ·ŠΰΆ§ ࢆࢻාࢰࢱා ࢚ࢻࢱ්ࢱ", + "components.invitation.bulk_invitation": "ࢭො࢜ ࢆࢻාࢰࢱා", + "components.invitation.button": "ࢆࢻාࢰࢱා ΰΆΊΰ·€ΰΆ±ΰ·ŠΰΆ±", + "scenes.client.readonly.info": "ΰΆΈΰ·™ΰΆΈ ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ·ΰ·€ ΰΆšΰ·’ΰΆΊΰ·€ΰ·“ΰΆΈΰΆ§ ࢴࢸࢫ්࢚ ΰ·€ΰΆ± ΰ·ƒΰΆ‚ΰΆœΰ·Šβ€ΰΆ»ΰ·„ΰΆΊΰΆšΰ·Š ΰ·€ΰΆ± ΰΆ±ΰΆΈΰ·”ΰΆ­ΰ·Š ΰΆ”ΰΆΆΰΆ§ ΰΆ±ΰ·–ΰΆ½ΰ·Šΰ·€ΰΆ½ ΰΆ…ΰΆ―ΰ·„ΰ·ƒΰ·Š ΰΆ―ΰ·ΰΆšΰ·Šΰ·€ΰ·’ΰΆΊ ΰ·„ΰ·ΰΆš.", + "scenes.app.channelsbar.channel_information.group.title": "ΰΆ±ΰ·ΰΆ½ΰ·’ΰΆšΰ· ࢚ࢫ්ࢩාࢺࢸ්", + "components.invitation.custom_role_invitation": "ΰ·ƒΰΆΈΰ·ŠΰΆ·ΰ·ΰ·€ΰ·ŠΰΆΊ ࢆࢻාࢰࢱࢺ", + "components.invitation.link": "සࢢැࢳිࢺ" +} diff --git a/twake/frontend/public/locales/tr.json b/twake/frontend/public/locales/tr.json new file mode 100644 index 00000000..d41d8d9d --- /dev/null +++ b/twake/frontend/public/locales/tr.json @@ -0,0 +1,1008 @@ +{ + "general.send": "Mesaj gΓΆnder", + "general.create": "Oluştur", + "general.back": "Geri", + "general.help.support": "Destek", + "general.help.documentation": "DokΓΌmantasyon", + "general.add": "Ekle", + "general.close": "Kapat", + "general.save": "Kaydet", + "general.cancel": "Δ°ptal Et", + "general.retry": "Yeniden Dene", + "general.continue": "Devam Et", + "general.confirm": "Onayla", + "general.delete": "Sil", + "general.archive": "Arşivle", + "general.unarchive": "Arşivden Γ‡Δ±kar", + "general.help": "YardΔ±m", + "general.connexion_status.disconnected": "Γ‡evrimdışısΔ±nΔ±z", + "general.connexion_status.connected": "Γ‡evrimiΓ§isiniz", + "general.connexion_status.connecting": "Yeniden BağlanΔ±yor…", + "application.load.longer": "Sunucunun yanΔ±t vermesi beklenenden uzun sΓΌrΓΌyor, lΓΌtfen bekleyin veya sayfayΔ± yeniden yΓΌkleyin...", + "scenes.app.side_app.messages_thread_title": "{{$1}} β€’ Mesaj dizisi", + "scenes.app.workspaces.create_company.group_data": "Yeni grubunuzu yapΔ±landΔ±rΔ±n", + "scenes.app.workspaces.create_company.group_data.group_type": "Grup TΓΌrΓΌ", + "scenes.app.workspaces.create_company.group_data.group_type.company": "Şirket ya da Şirket DepartmanΔ±", + "scenes.app.workspaces.create_company.group_data.group_type.public_organization": "Kamu Kuruluşu", + "scenes.app.workspaces.create_company.group_data.group_type.university_school": "Üniversite ya da Okul", + "scenes.app.workspaces.create_company.group_data.group_type.society_club_charity": "Dernek, KulΓΌp ya da YardΔ±m Kuruluşu", + "scenes.app.workspaces.create_company.group_data.group_size": "Grup Boyutu", + "scenes.app.workspaces.create_company.group_data.group_size.less_3": "4 kullanΔ±cΔ±dan az", + "scenes.app.workspaces.create_company.group_data.group_size.4_10": "4 - 10 kullanΔ±cΔ±", + "scenes.app.workspaces.create_company.group_data.group_size.10_50": "11 - 49 kullanΔ±cΔ±", + "scenes.app.workspaces.create_company.group_data.group_size.50_100": "50 - 99 kullanΔ±cΔ±", + "scenes.app.workspaces.create_company.group_data.group_size.100_500": "100 - 499 kullanΔ±cΔ±", + "scenes.app.workspaces.create_company.group_data.group_size.500_1000": "500 - 999 kullanΔ±cΔ±", + "scenes.app.workspaces.create_company.group_data.group_size.5000_more": "5000 kullanΔ±cΔ±dan fazla", + "scenes.app.workspaces.create_company.group_data.group_main_activity": "Ana Faaliyet", + "scenes.app.workspaces.create_company.group_data.group_main_activity.food": "GΔ±da", + "scenes.app.workspaces.create_company.group_data.group_main_activity.bank": "Banka / Sigorta", + "scenes.app.workspaces.create_company.group_data.group_main_activity.printing_paper": "BasΔ±mevi / YayΔ±mevi", + "scenes.app.workspaces.create_company.group_data.group_main_activity.real_estate": "Emlak", + "scenes.app.workspaces.create_company.group_data.group_main_activity.studies_and_advice": "Eğitim ve DanışmanlΔ±k", + "scenes.app.workspaces.create_company.group_data.group_main_activity.pharmaceutical_industry": "Δ°laΓ§ EndΓΌstrisi", + "scenes.app.workspaces.create_company.group_data.group_main_activity.it_telecom": "Bilişim Teknolojileri(IT) / Telekom", + "scenes.app.workspaces.create_company.group_data.group_main_activity.machinery_automotive": "Makine / Otomotiv", + "scenes.app.workspaces.create_company.group_data.group_main_activity.business_services": "İş Hizmetleri", + "scenes.app.workspaces.create_company.group_data.group_main_activity.entertainment": "Eğlence", + "scenes.app.workspaces.create_company.group_data.group_main_activity.textile_clothing_shoes": "Tekstil / Giyim / AyakkabΔ±", + "scenes.app.workspaces.create_company.group_data.group_main_activity.research": "AraştΔ±rma ve Geliştirme", + "scenes.app.workspaces.create_company.group_data.group_main_activity.education": "Eğitim ve Γ–ΔŸretim", + "scenes.app.workspaces.create_company.group_data.group_main_activity.other": "Diğer", + "components.application.messages": "Mesajlar", + "general.edit": "DΓΌzenle", + "general.update": "GΓΌncelle", + "general.remove": "KaldΔ±r", + "scenes.app.workspaces.create_company.group_data.group_main_activity.construction_building": "Δ°nşaat / YapΔ± Malzemeleri", + "scenes.app.workspaces.create_company.group_data.group_type.other_group": "Diğer", + "scenes.app.workspaces.create_company.group_data.group_main_activity.electronics_electricity_energy": "Elektronik / Elektrik / Enerji", + "scenes.app.workspaces.create_company.group_data.group_size.1000_5000": "1000 - 4999 kullanΔ±cΔ±", + "scenes.app.workspaces.create_company.group_data.group_main_activity.chemistry": "Kimya", + "scenes.app.workspaces.create_company.group_data.group_main_activity.trade_commerce_distribution": "Ticaret / Alışveriş / DağıtΔ±m", + "scenes.app.workspaces.create_company.group_data.group_main_activity.materials": "Malzeme", + "scenes.app.workspaces.create_company.group_data.group_main_activity.publishing_communication_multimedia": "YayΔ±ncΔ±lΔ±k / Δ°letişim / Multimedya", + "scenes.app.workspaces.create_company.group_data.group_main_activity.transport_logistics": "TaşımacΔ±lΔ±k / Lojistik", + "scenes.app.workspaces.create_company.group_data.group_main_activity.administration": "YΓΆnetim", + "components.drive_dropzone.uploading": "YΓΌklΓΌyor...", + "scenes.app.popup.workspaceparameter.payments_subscriptions_title": "Γ–demeler ve abonelikler", + "scenes.app.workspacesbar.components.change_company_title": "Şirket değiştir", + "scenes.app.workspacesbar.components.create_company_menu": "Bir şirket oluşturun", + "scenes.apps.calendar.no_calendar_text": "Bu Γ§alışma alanΔ± iΓ§in herhangi bir takvim ayarlamadΔ±nΔ±z.", + "scenes.apps.calendar.no_connectors_menu_text": "Bir takvime bağlanabilecek bağlayΔ±cΔ±nΔ±z yok.", + "scenes.apps.calendar.remove_calendar_confirmation": "Takvim ve etkinlikleri kalΔ±cΔ± olarak silinsin mi?", + "scenes.apps.calendar.today_menu": "BugΓΌn", + "scenes.apps.calendar.week_option": "Hafta", + "scenes.apps.calendar.workspace": "Γ§alışma alanΔ±", + "scenes.apps.calendar.workspace_label": "Bu Γ§alışma alanΔ±", + "scenes.apps.calendar.workspace_menu": "Γ§alışma alanΔ±", + "scenes.apps.drive.add_button": "Ekle", + "scenes.apps.drive.message_added_file": "{{$1}}, {{$2}} gΓΆnderdi.", + "scenes.apps.drive.message_added_mutiple_files": "{{$1}} birden fazla dosya gΓΆnderdi.", + "scenes.apps.drive.message_added_file_no_name": "{{$1}} bir dosya gΓΆnderdi.", + "scenes.apps.messages.input.edited": "DΓΌzenlendi", + "scenes.apps.messages.just_you": "YalnΔ±zca size gΓΆrΓΌnΓΌr", + "scenes.apps.messages.message.new_messages_bar": "Yeni mesajlar", + "scenes.apps.messages.message.cancel_button": "Δ°ptal", + "scenes.apps.messages.message.modify_button": "DΓΌzenlemek", + "scenes.apps.messages.message.pin_button": "Pin mesajΔ±", + "scenes.apps.messages.message.unpin_button": "MesajΔ±n sabitlemesini kaldΔ±r", + "scenes.apps.messages.message.copy_link": "BağlantΔ±yΔ± mesaja kopyala", + "scenes.apps.messages.message.pinned": "sabitlenmiş", + "scenes.apps.messages.message.remove_button": "Silmek", + "scenes.apps.messages.message.reply_button": "Cevap vermek", + "scenes.apps.messages.message.save_button": "Kaydetmek", + "scenes.apps.messages.message.show_button": "GΓΆrΓΌntΓΌlemek", + "scenes.apps.messages.message.show_responses_button": "TΓΌm yanΔ±tlarΔ± gΓΆrΓΌntΓΌle", + "scenes.apps.messages.message.types.first_channel_message_text": "Bu kanalΔ±n ilk mesajΔ±", + "scenes.apps.messages.message.types.first_message_text": "Bu ilk mesaj", + "scenes.apps.messages.messageslist.get_writing_user": "yazΔ±yor...", + "services.apps.messages.no_app": "Bu uygulama mevcut değil.", + "services.apps.messages.no_command_possible": "'{{$1}}' komutunu Γ§alıştΔ±ramΔ±yoruz Γ§ΓΌnkΓΌ '{{$2}}' mevcut değil veya komut oluşturmaya izin vermiyor.", + "services.user.notification_parameters_update_alert": "Bildirim ayarlarΔ± gΓΌncellendi.", + "scenes.apps.drive.right_preview.public": "Kamu erişim", + "scenes.app.popup.appsparameters.pages.apps_connectors_small_text": "UygulamalarΔ±nΔ±zΔ± ve bağlayΔ±cΔ±larΔ±nΔ±zΔ± yΓΆnetin.", + "scenes.app.popup.appsparameters.pages.title_informations": "Temel bilgiler", + "scenes.app.popup.appsparameters.pages.subtitle_informations": "Uygulama yΓΆnetimi ile ilgili bilgiler", + "scenes.app.popup.appsparameters.pages.smalltext_user_id": "GeΓ§erli kullanΔ±cΔ± kimliği", + "scenes.app.popup.appsparameters.pages.smalltext_workspace_id": "GeΓ§erli Γ§alışma alanΔ± kimliği", + "scenes.app.popup.appsparameters.pages.smalltext_group_id": "GeΓ§erli grup kimliği", + "scenes.app.mainview.channel_description": "KanalΔ± tanΔ±mlayΔ±n", + "scenes.client.channelbar.channeltemplateeditor.checkbox": "TΓΌm Γ§alışma alanΔ± kullanΔ±cΔ±larΔ±nΔ± otomatik olarak bu kanala davet et", + "components.locked_features.locked_guests_popup.subtitle": "Bu ΓΆzellik Twake'in ΓΌcretsiz sΓΌrΓΌmΓΌnde mevcut değildir.", + "components.on_boarding.company_billing_banner.admin_or_owner_text": "Şirket aboneliğinizle ilgili bir sorun var. LΓΌtfen, kendinize bir gΓΆz atΔ±n", + "components.on_boarding.company_billing_banner.guest_or_member_text": "Şirket aboneliğinizle ilgili bir sorun var. LΓΌtfen şirket sahibi veya yΓΆneticisi ile iletişime geΓ§in!", + "components.on_boarding.company_billing_banner.link": "şirket abonelik planΔ±", + "components.on_boarding.popups.blocked_company.title": "Bir ΓΆdeme sorunu nedeniyle şirketiniz kilitlendi", + "components.on_boarding.popups.blocked_company.company_subscription_plan_button": "Buraya TΔ±kla", + "components.locked_features.locked_only_office_popup.subtitle": "Ücretsiz sΓΌrΓΌmde sadece ofis kullanamazsΔ±nΔ±z.", + "scenes.app.integrations_parameters.title": "Entegrasyonlar", + "scenes.app.integrations_parameters.applications_table.name": "Δ°sim", + "scenes.app.integrations_parameters.applications_table.title": "Diğer entegrasyonlar", + "scenes.app.integrations_parameters.applications_table.search_placeholder": "Uygulama ara", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.website_item": "Δ°nternet sitesi", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.created_item": "Oluşturulma tarihi", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.version_item": "sΓΌrΓΌm", + "app.state.recoil.hooks.use_current_company_applications.toaster_delete": "{{$1}} şirketinizden başarΔ±yla silindi", + "app.state.recoil.hooks.use_current_company_applications.toaster_add": "{{$1}} şirketinize başarΔ±yla eklendi", + "scenes.apps.messages.input.replied_to": "yanΔ±tladΔ± ", + "scenes.join.login_first_button": "Γ–nce giriş yapΔ±n veya bir hesap oluşturun", + "scenes.join.join_the_team_button": "TakΔ±ma katΔ±l", + "scenes.apps.account.title": "Hesap parametreleri", + "scenes.apps.account.account.menu_title": "Hesap", + "scenes.apps.account.languages.menu_title": "Dilim", + "scenes.apps.account.account.firstname": "Δ°lk adΔ±", + "scenes.apps.account.account.lastname": "SoyadΔ±", + "scenes.apps.account.account.username": "KullanΔ±cΔ± adΔ±", + "scenes.apps.account.account.change_username": "Benzersiz kullanΔ±cΔ± adΔ±nΔ±zΔ± değiştirin.", + "scenes.apps.account.account.emails": "e-postalar", + "scenes.apps.account.account.main_email": "ana e-posta", + "scenes.apps.account.account.email_add": "Yeni e-posta ekle", + "scenes.apps.account.account.email_add_modal.invalid_code": "Bu kod geΓ§ersiz", + "scenes.apps.account.account.password": "Parola", + "scenes.apps.account.account.password_modal.old_password": "Şimdiki Şifre", + "scenes.apps.account.account.password_modal.password": "Yeni Şifre", + "scenes.apps.account.account.password_modal.bad_old_password": "Eski şifre doğru değil.", + "scenes.apps.account.account.password_modal.bad_password": "Şifreleriniz uyuşmuyor veya Γ§ok kΔ±sa. LΓΌtfen en az 8 karakterden oluşan bir şifre giriniz.", + "scenes.apps.account.account.logout": "Γ‡Δ±kış Yap", + "scenes.apps.account.notifications.title": "Bildirimler", + "scenes.apps.account.notifications.keywords_subtitle": "anahtar kelimeler", + "scenes.apps.account.notifications.keywords_placeholder": "dev, wifi, kod, ...", + "scenes.apps.account.notifications.disturb_option_a": "arasΔ±nda bana push bildirimleri gΓΆnderme ", + "scenes.apps.account.notifications.disturb_option_b": " ve ", + "scenes.apps.account.notifications.disturb_option_c": " (yerel saat dilimi)", + "scenes.apps.account.notifications.devices_subtitle": "Cihaz bildirimleri", + "scenes.apps.account.notifications.devices_option_ever": "Bana her zaman push bildirimleri gΓΆnder", + "scenes.apps.account.notifications.devices_option_inactive": "MasaΓΌstΓΌnde etkin olmadığımda bana anΔ±nda iletme bildirimleri gΓΆnder", + "scenes.apps.account.notifications.devices_option_never": "Bana asla push bildirimleri gΓΆnderme", + "scenes.apps.account.notifications.privacy_subtitle": "Mahremiyet", + "scenes.apps.account.notifications.mail_subtitle": "E-posta Bildirimleri", + "scenes.apps.account.notifications.sound": "Sesli bildirim", + "scenes.apps.parameters.group_sections.apps.badge_extension": "UzantΔ±", + "scenes.apps.parameters.workspace_sections.members.members": "KullanΔ±cΔ±lar", + "scenes.apps.parameters.workspace_sections.members.pending": "bekleyen e-postalar", + "scenes.apps.parameters.workspace_sections.members.invite": "Yeni kullanΔ±cΔ± davet et", + "scenes.apps.parameters.workspace_sections.members.invite_btn": "KullanΔ±cΔ± Ekle", + "scenes.apps.tasks.new_board.title": "Yeni tahta", + "scenes.apps.tasks.new_board.edit_title": "Panoyu dΓΌzenle", + "scenes.apps.tasks.task": "GΓΆrev", + "scenes.apps.tasks.no_tasks": "Sorma", + "scenes.apps.tasks.task_status.todo": "Yapmak", + "scenes.apps.tasks.task_status.current": "AkΔ±m", + "scenes.apps.tasks.task_status.done": "TamamlandΔ±", + "scenes.apps.tasks.task.description": "AΓ§Δ±klama", + "scenes.apps.tasks.task.assignees": "atananlar", + "scenes.apps.tasks.task.edit.dates": "Tarih", + "scenes.apps.tasks.list_modal.modify_list": "Listeyi değiştir", + "scenes.apps.tasks.list_modal.new_list": "Yeni liste", + "scenes.apps.tasks.list_modal.remove": "Listeyi ve gΓΆrevleri kaldΔ±r", + "scenes.apps.tasks.list_modal.predefined_participants": "Γ–nceden tanΔ±mlanmış katΔ±lΔ±mcΔ±lar", + "scenes.apps.tasks.list_modal.archive_all_tasks": "TΓΌm gΓΆrevleri arşivle", + "scenes.apps.tasks.list_modal.remove_archived_tasks": "Arşivlenmiş gΓΆrevleri kaldΔ±rΔ±n ({{$1}})", + "scenes.login.footer.go_to_twake": "twakeapp.com'a gidin", + "scenes.login.footer.branding": "Bir {{$1}} ({{$2}}) ΓΆzel Twake sunucusundasΔ±nΔ±z. ", + "scenes.login.create_account.title": "Yeni bir hesap oluştur", + "scenes.login.create_account.email": "e-posta", + "scenes.login.create_account.email_used": "Bu e-posta zaten kullanΔ±lΔ±yor.", + "scenes.login.create_account.username": "KullanΔ±cΔ± adΔ±", + "scenes.login.create_account.username_already_exist": "Bu kullanΔ±cΔ± adΔ± zaten kullanΔ±lΔ±yor", + "scenes.login.create_account.fill_in_username": "KullanΔ±cΔ± adΔ±nΔ±zΔ± doldurmalΔ±sΔ±nΔ±z", + "scenes.login.create_account.fill_in_email": "E-postanΔ±zΔ± doğru bir e-posta ile doldurmalΔ±sΔ±nΔ±z", + "scenes.login.create_account.too_short_password": "Şifreniz en az 8 karakter iΓ§ermelidir.", + "scenes.login.create_account.firstname": "Δ°lk adΔ±", + "scenes.login.create_account.newsletter": "Twake hakkΔ±nda bilgi alΔ±n", + "scenes.login.create_account.lastname": "SoyadΔ±", + "scenes.login.forgot_password.title": "ParolanΔ±zΔ± mΔ± unuttunuz?", + "scenes.login.forgot_password.text": "Kimliğinizi doğrulamak iΓ§in e-posta ile 9 haneli bir kod alacaksΔ±nΔ±z.", + "scenes.login.forgot_password.email_to_recover": "Kurtarmak iΓ§in e-posta", + "scenes.login.forgot_password.mail_doesnt_exist": "Bu e-posta mevcut değil", + "scenes.login.forgot_password.text2": "9 haneli bir kod alacaksΔ±nΔ±z. Devam etmek iΓ§in lΓΌtfen aşağıdaki alana giriniz.", + "scenes.login.forgot_password.invalid_code": "Bu kod geΓ§erli değil.", + "scenes.login.forgot_password.text3": "HesabΔ±nΔ±z iΓ§in yeni bir şifre girin.", + "scenes.login.forgot_password.password": "Parola", + "scenes.login.forgot_password.password2": "Şifreyi Onayla", + "scenes.login.forgot_password.password_dont_match": "Şifreleriniz uyuşmuyor veya Γ§ok kΔ±sa. LΓΌtfen en az 8 karakterden oluşan bir şifre giriniz.", + "scenes.login.home.title": "Twake'te oturum aΓ§Δ±n", + "scenes.login.home.subtitle": "Seni gΓΆrdüğüme sevindim", + "scenes.app.popup.appsparameters.pages.alert_published_app": "Başvurunuz yayΔ±nlandΔ±, dΓΌzenleyemezsiniz.", + "scenes.app.popup.appsparameters.pages.allowed_ip_adresses_method": "TΓΌm IP adreslerine izin vermek iΓ§in geliştirme aşamasΔ±nda * kullanΔ±n.", + "scenes.app.popup.appsparameters.pages.api_data_description": "Twake API iΓ§in faydalΔ± veriler.", + "scenes.app.popup.appsparameters.pages.waiting_availability_application": "Bekleniyor...", + "scenes.app.popup.appsparameters.pages.website_label": "Δ°nternet sitesi", + "scenes.app.popup.appsparameters.pages.write_privileges_label": "Yazma ayrΔ±calΔ±klarΔ±", + "scenes.app.popup.appsparameters.pages.danger_zone_small_text": "YayΔ±nlanΔ±rsa bu uygulamayΔ± silemezsiniz.", + "scenes.app.popup.appsparameters.pages.error_app_update_message": "Uygulama gΓΌncellenirken bir hata oluştu.", + "scenes.app.popup.workspaceparameter.pages.apps_research_title": "UygulamalarΔ± ara", + "scenes.app.popup.workspaceparameter.pages.apps_small_text": "Bu Γ§alışma alanΔ±nΔ±n uygulamalarΔ±", + "scenes.app.popup.workspaceparameter.pages.back_to_search_button": "Aramaya dΓΆn", + "scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button": "KullanΔ±cΔ±larΔ± davet et", + "scenes.app.popup.workspaceparameter.pages.collaborateurs": "KullanΔ±cΔ±lar", + "scenes.app.popup.workspaceparameter.pages.apps_connectors_title": "Entegrasyonlar", + "scenes.app.popup.workspaceparameter.pages.read_access_subtitle": "Okuma erişimi", + "scenes.app.popup.workspaceparameter.pages.remove_from_company_text": "TΓΌm şirketten Γ§Δ±kar", + "scenes.apps.calendar.day_option": "GΓΌn", + "scenes.apps.calendar.modals.event_description_placeholder": "AΓ§Δ±klama", + "scenes.apps.calendar.modals.event_title_placeholder": "BaşlΔ±k", + "scenes.apps.calendar.modals.modify_event_button": "Etkinliği dΓΌzenle", + "scenes.apps.calendar.modals.part.participants": "KatΔ±lΔ±mcΔ±lar", + "scenes.apps.drive.no_storage_app_alert": "Harici depolama eklemenize izin veren uygulamanΔ±z yok.", + "scenes.apps.drive.remove_definitely_menu": "KalΔ±cΔ± olarak sil", + "scenes.apps.drive.restore_menu": "Onarmak", + "scenes.apps.drive.throw_menu": "Γ§ΓΆp kutusuna gΓΆnder", + "scenes.apps.drive.trash_empty_menu": "Boş Γ§ΓΆp", + "scenes.apps.drive.unconfigured_tab": "Bu sekme henΓΌz yapΔ±landΔ±rΔ±lmamış.", + "scenes.apps.drive.viewer.edit_with_button": "{{$1}} ile dΓΌzenleyin", + "scenes.apps.drive.viewer.loading_preview_message": "YΓΌkleniyor...", + "scenes.apps.messages.input.show_formatting": "BiΓ§imlendirmeyi gΓΆster", + "scenes.tell_us": "LΓΌtfen bize ne yaptığınΔ±zΔ± sΓΆyleyin:", + "scenes.apps.drive.viewer.download_desktop": "Uygulamada ΓΆnizlemek iΓ§in Twake Desktop'Δ± indirin", + "scenes.apps.tasks.my_tasks": "GΓΆrevlerim", + "scenes.apps.tasks.board.place_holder": "Kurul adΔ±", + "scenes.apps.tasks.board.tasks.subtask": "alt gΓΆrev", + "scenes.apps.tasks.board.tasks.add_subtask": "Alt gΓΆrev ekle", + "scenes.client.channelbar.channelmemberslist.menu.option_2": "Kanaldan kaldΔ±r", + "components.leftbar.channel.workspaceschannels.menu.option_1": "Kanal oluştur", + "components.leftbar.channel.workspaceschannels.menu.option_2": "Bir kanala katΔ±lΔ±n", + "components.channelworkspacelist.title": "Kanallar", + "scenes.client.channelbar.workspacechannellist.autocomplete": "Kanal, kullanΔ±cΔ± veya doğrudan mesajlarΔ± arayΔ±n", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_creation": "Yeni bir sekme oluştur", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_edition": "{{$1}}'i yeniden adlandΔ±r", + "components.connectorslistmanager.add_connectors": "BağlayΔ±cΔ± ekle", + "components.upload.drop_files.toaster.error": "{{$1}} dosyadan fazlasΔ±nΔ± yΓΌkleyemezsiniz", + "components.emoji_picker.categories.frequently_used": "SΔ±klΔ±kla kullanΔ±lan", + "components.emoji_picker.categories.smileys_and_people": "Suratlar ve Δ°nsanlar", + "components.emoji_picker.categories.animals_and_nature": "Hayvanlar ve Doğa", + "components.emoji_picker.categories.food_and_drink": "Yiyecek iΓ§ecek", + "scenes.login.home.email": "e-posta", + "scenes.login.home.unable_to_connect": "GeΓ§ersiz kimlik bilgileri", + "scenes.login.home.password": "Parola", + "scenes.login.home.login_btn": "Giriş yapmak", + "scenes.login.home.lost_password": "ParolanΔ±zΔ± mΔ± unuttunuz?", + "scenes.login.home.create_account": "Bir hesap oluşturun", + "scenes.login.create_account.password": "Parola", + "scenes.login.create_account.step_1_subtitle": "Daha basit olamazdΔ± - sadece biraz bilgiye ihtiyacΔ±mΔ±z var.", + "scenes.login.create_account.step_2_subtitle_a": "Diğer kullanΔ±cΔ±larΔ±n sizi tanΔ±masΔ± iΓ§in tam adΔ±nΔ±zΔ± ekleyin.", + "scenes.login.create_account.step_2_subtitle_b": "Telefon numaranΔ±z gizli kalΔ±r.", + "scenes.login.create_account.step_3_mail_sent": "Size e-posta ile bir aktivasyon linki gΓΆnderdik.", + "scenes.login.create_account.step_3_subtitle": "Son adΔ±m β€” robot olmadığınΔ±zΔ± doğrulamamΔ±z gerekiyor!", + "scenes.app.workspaces.create_company.company_name.placeholder": "Şirket AdΔ±", + "scenes.app.workspaces.create_company.company_name.title_1": "Başlamak,", + "scenes.app.workspaces.create_company.company_name.title_2": "şirketinizin adΔ±nΔ± belirtin.", + "scenes.app.workspaces.create_company.default_workspace_name": "Ana", + "scenes.app.workspaces.create_company.importations.title_1": "Zaten dijital araΓ§larla mΔ± Γ§alışıyorsunuz? AraΓ§larΔ±nΔ±zΔ± şimdi iΓ§e aktarΔ±n veya entegre edin!", + "scenes.app.workspaces.create_company.importations.title_2": "Endişelenme, bunu daha sonra yapabilirsin!", + "scenes.app.workspaces.create_company.invitations.title_2": "Ekibinize kullanΔ±cΔ±lar ekleyin.", + "scenes.app.workspaces.create_company.title": "şirketimi oluştur", + "scenes.app.workspaces.welcome_page.add_secondary_emails": "Δ°kincil bir e-posta ekleyin", + "scenes.app.workspaces.welcome_page.added_to_company": "davet edildiniz ", + "scenes.app.workspaces.welcome_page.create_my_company": "şirketimi oluştur", + "scenes.app.workspaces.welcome_page.lets_go": "Hadi gidelim!", + "scenes.app.workspaces.welcome_page.may_be_invited_with_secondary_emails": "Başka bir e-posta adresi kullanarak mΔ± davet edildiniz?", + "scenes.app.workspaces.welcome_page.no_company_subtitle": "Oh, peki... GΓΆrΓΌnüşe gΓΆre henΓΌz kimse seni bir Γ§alışma alanΔ±na davet etmemiş.", + "scenes.app.workspaces.welcome_page.ready_to_work": "ArtΔ±k Γ§alışmaya hazΔ±rsΔ±nΔ±z.", + "scenes.app.workspaces.welcome_page.see_you_soon": "YakΔ±nda gΓΆrüşürΓΌz!", + "scenes.app.workspaces.welcome_page.try_again": "Tekrar deneyin", + "scenes.app.workspaces.welcome_page.twake_team": "UyandΔ±rmak", + "scenes.app.workspaces.welcome_page.welcome_header": "Twake'e hoş geldiniz!", + "scenes.app.workspaces.welcome_page.add_secondary_emails_comment": "HesabΔ±nΔ±za birden fazla e-posta adresi bağlayabilirsiniz; size bildirim gΓΆndermek iΓ§in yalnΔ±zca bir adres kullanΔ±lacaktΔ±r.", + "scenes.app.workspaces.welcome_page.main_mail_title": "ana adres", + "scenes.app.workspaces.welcome_page.other_mail_title": "ikincil adresler", + "scenes.app.workspaces.welcome_page.add_new_email": "E-posta ekle", + "scenes.app.workspaces.welcome_page.code_verification": "Doğrulama kodu", + "scenes.app.workspaces.welcome_page.new_email": "Δ°kincil bir e-posta ekleyin", + "scenes.app.workspaces.welcome_page.we_sent_you_mail": "Size {{$1}} aracΔ±lığıyla bir doğrulama kodu gΓΆnderdik", + "scenes.app.workspaces.welcome_page.done": "bitirdim", + "scenes.login.forgot_password.finished": "Şifreniz başarΔ±yla gΓΌncellendi.", + "scenes.apps.account.account.description_main": "Ana adresiniz, Twake'in bildirimlerinizi gΓΆnderdiği yerdir. Δ°kincil adresleriniz, onlarΔ± kullanan Γ§alışma alanlarΔ±na otomatik olarak davet edilmenizi sağlar.", + "scenes.apps.account.account.emails.description": "FarklΔ± e-posta adreslerinizi yΓΆnetin.", + "scenes.apps.account.account.make_main": "Ana ayarla", + "scenes.apps.account.account.password.description": "Şifreni değiştir.", + "scenes.apps.account.identity": "Kimlik", + "scenes.apps.account.identity.description": "Diğer Twake kullanΔ±cΔ±larΔ± tarafΔ±ndan gΓΆrΓΌlebilen adΔ±nΔ±zΔ±, soyadΔ±nΔ±zΔ± ve profil resminizi değiştirin.", + "scenes.apps.account.preference": "tercihler", + "scenes.apps.account.thumbnail.max_weight": "Maksimum boyut 5 MB", + "scenes.apps.account.account.email_add_modal.confirm": "Bu e-postayΔ± onaylayΔ±n", + "app.name.twake_calendar": "Takvim", + "app.name.twake_drive": "Belgeler", + "app.name.twake_tasks": "GΓΆrevler", + "components.calendar.repetition.everyday": "GΓΌnlΓΌk", + "components.calendar.repetition.does_not_repeat": "tekrar etmez", + "components.calendar.repetition.weekly_on": "HaftalΔ±k {{$1}}", + "components.calendar.repetition.monthly_on": "{{$1}} {{$2}} tarihinde aylΔ±k", + "components.calendar.repetition.monthly_on_day": "AylΔ±k gΓΌn {{$1}}", + "components.calendar.repetition.annually_on": "{{$1}} tarihinde her yΔ±l", + "components.calendar.repetition.every_weekday": "Hafta iΓ§i her gΓΌn (Pzt'den Cuma'ya)", + "components.calendar.repetition.custom": "Gelenek...", + "components.calendar.repetition.repeat": "Her tekrarla", + "scenes.app.channelsbar.currentuser.workspace_parameters": "Γ‡alışma alanΔ± ayarlarΔ±", + "scenes.app.channelsbar.currentuser.logout": "oturumu Kapat", + "scenes.app.channelsbar.currentuser.update": "GΓΌncelleme", + "scenes.app.channelsbar.currentuser.disable_notifications": "Devre dışı bΔ±rakmak", + "scenes.app.channelsbar.currentuser.disabling_notifications": "1 saat devre dışı bΔ±rak", + "scenes.app.channelsbar.currentuser.disabling_notifications_until": "Sabah 9'a kadar devre dışı bΔ±rak yarΔ±n", + "scenes.app.channelsbar.currentuser.reactivate_notifications": "yeniden etkinleştir", + "scenes.app.channelsbar.currentuser.user_parameter": "Bildirim ayarlarΔ±", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace_description": "Bu Γ§alışma alanΔ±nΔ± silmek istediğinizi onaylamak iΓ§in lΓΌtfen aşağıya adΔ± yazΔ±n ve sil tuşuna basΔ±n.", + "scenes.app.mainview.tabs.no_connected_connectors_for_channel": "Bir kanala bağlanabilecek bağlayΔ±cΔ±nΔ±z yok.", + "scenes.app.mainview.tabs.rename": "Yeniden isimlendirmek", + "scenes.app.popup.appsparameters.pages.app_modification_right": "Bu şirketin tΓΌm yΓΆneticileri bu uygulamayΔ± dΓΌzenleyebilecek.", + "scenes.app.popup.appsparameters.pages.app_privileges_information": "UygulamanΔ±zΔ±n neleri dΓΌzenleyebileceğini ve okuyabileceğini tanΔ±mlayΔ±n.", + "scenes.app.popup.appsparameters.pages.automatique_label": "Otomatik", + "scenes.app.popup.appsparameters.pages.automatique_option_information": "'Otomatik' seΓ§eneğini etkinleştirirseniz, bu uygulama bu şirketin sonraki Γ§alışma alanlarΔ±na otomatik olarak eklenecektir.", + "scenes.app.popup.appsparameters.pages.autorised_ip_adresses_label": "Δ°zin verilen IP adresleri", + "scenes.app.popup.appsparameters.pages.available_publication_alert": "Başvurunuzun yayΔ±nlanmasΔ± şu anda Twake ekibi tarafΔ±ndan onaylanmayΔ± bekliyor.", + "scenes.app.popup.appsparameters.pages.button_force": "Şirket genelinde kuvvet", + "scenes.app.popup.appsparameters.pages.danger_zone_label": "tehlikeli bΓΆlge", + "scenes.app.popup.appsparameters.pages.description_label": "AΓ§Δ±klama", + "scenes.app.popup.appsparameters.pages.error_check_needed": "Bir hata oluştu; bilgilerinizi kontrol edin.", + "scenes.app.popup.appsparameters.pages.error_message": "Bu ad zaten başka bir uygulama tarafΔ±ndan kullanΔ±lΔ±yor; LΓΌtfen başka birini seΓ§iniz.", + "scenes.app.popup.appsparameters.pages.error_user_code": "hata", + "scenes.app.popup.appsparameters.pages.event_subtitle": "Olaylar", + "scenes.app.popup.appsparameters.pages.filter_information": "Bu filtre, API anahtarΔ±nΔ±zΔ±n kullanΔ±mΔ±nΔ± yalnΔ±zca bağlayΔ±cΔ±nΔ±zdaki sunucularla sΔ±nΔ±rlar.", + "scenes.app.popup.appsparameters.pages.go_back": "Geri", + "scenes.app.popup.appsparameters.pages.grp_section_name-error": "Bu ad zaten başka bir uygulama tarafΔ±ndan kullanΔ±lΔ±yor. LΓΌtfen başka birini seΓ§iniz.", + "scenes.app.popup.appsparameters.pages.grp_section_surname_label": "basitleştirilmiş ad", + "scenes.app.popup.appsparameters.pages.installation": "yΓΌkleyin.", + "scenes.app.popup.appsparameters.pages.instruction_message_twakecode": "MesajΔ±nΔ±zΔ± JSON formatΔ±nda yazarak başlayΔ±n.", + "scenes.app.popup.appsparameters.pages.interne_availability_application": "Dahili uygulama", + "scenes.app.popup.appsparameters.pages.json_configuration_information": "YapΔ±landΔ±rmanΔ±zΔ± JSON biΓ§iminde oluşturmak iΓ§in belgelere gidin.", + "scenes.app.popup.appsparameters.pages.loading": "YΓΌkleniyor...", + "scenes.app.popup.appsparameters.pages.message_data_next_event": "Bir sonraki Etkinlikte gΓΆnderilecek olan pasif veriler", + "scenes.app.popup.appsparameters.pages.modify_public_data": "UygulamanΔ±zΔ±n genel verilerini dΓΌzenleyin.", + "scenes.app.popup.appsparameters.pages.publication_label": "yayΔ±n", + "scenes.app.popup.appsparameters.pages.publish_app_label": "UygulamayΔ± yayΔ±nla", + "scenes.app.popup.appsparameters.pages.read_privileges_label": "Okuma ayrΔ±calΔ±klarΔ±", + "scenes.app.popup.appsparameters.pages.remove_app": "{{$1}} uygulamasΔ±nΔ± kalΔ±cΔ± olarak silin.", + "scenes.app.popup.appsparameters.pages.remove_app_from_company": "TΓΌm şirketten Γ§Δ±kar", + "scenes.app.popup.appsparameters.pages.remove_app_from_workspace": "Γ‡alışma alanΔ±ndan kaldΔ±r", + "scenes.app.popup.appsparameters.pages.show_button": "GΓΆstermek", + "scenes.app.popup.appsparameters.pages.status_tilte": "Durum", + "scenes.app.popup.appsparameters.pages.remove_app_button": "UygulamayΔ± sil", + "scenes.app.popup.appsparameters.pages.update_button": "GΓΌncelleme", + "scenes.app.popup.createworkspacepage.add_subtitle": "Daha fazla alana ihtiyaΓ§ var?", + "scenes.app.popup.createworkspacepage.create_new_workspace": "Yeni bir Γ§alışma alanΔ± oluşturun", + "scenes.app.popup.createworkspacepage.placeholder_name": "Γ‡alışma alanΔ±nΔ±n adΔ±", + "scenes.app.popup.userparameter.pages.frequency_notif_configuration_description": "Mobil bildirimlerin sΔ±klığınΔ± ayarlayΔ±n.", + "scenes.app.popup.userparameter.pages.frequency_notif_subtitle": "Bildirimlerin sΔ±klığı", + "scenes.app.popup.userparameter.pages.private_message_content.hide": "Γ–zel mesaj iΓ§eriğini gizle", + "scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description": "Bildirim almayacağınΔ±z bir dΓΆnem seΓ§in.", + "scenes.app.popup.userparameter.pages.no_night_disturbing_label": "geceleri rahatsΔ±z etmeyin", + "scenes.app.popup.userparameter.pages.notif_content_label": "Bildirimlerin iΓ§eriği", + "scenes.app.mainview.quick_search_placeholder": "HΔ±zlΔ± arama", + "scenes.app.popup.userparameter.personnal_workspaces_title": "Γ‡alışma alanlarΔ±nΔ±z", + "scenes.app.popup.workspaceparameter.admin_current_status": "Siz bir YΓΆneticisiniz.", + "scenes.app.popup.workspaceparameter.admin_manager_current_status": "Siz bir Γ§alışma alanΔ± yΓΆneticisisiniz.", + "scenes.app.popup.workspaceparameter.manager_current_status": "Siz bir şirket yΓΆneticisisiniz.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace": "Γ‡alışma alanΔ±nΔ± sil", + "scenes.app.popup.workspaceparameter.pages.error_workspace_member": "KaldΔ±rmak iΓ§in Γ§alışma alanΔ±nda yalnΔ±z olmalΔ±sΔ±nΔ±z. Ortak Γ§alışanlarΔ±nΔ±zΔ± kaldΔ±rΔ±n ve tekrar deneyin.", + "scenes.app.popup.workspaceparameter.pages.enter": "Girmek ", + "scenes.app.popup.workspaceparameter.pages.access_apps": "UygulamalarΔ±nΔ±za ve bağlayΔ±cΔ±larΔ±nΔ±za erişin", + "scenes.app.popup.workspaceparameter.pages.moderator_status": "Γ‡alışma alanΔ± moderatΓΆrΓΌ", + "scenes.app.popup.workspaceparameter.pages.installed_apps_message": "Şirketin diğer alanlarΔ±nda kurulu uygulamalar {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_subtitle": "YΓΌklΓΌ uygulamalar", + "scenes.app.popup.workspaceparameter.pages.invitation_error": "Aşağıdaki kullanΔ±cΔ±lar davet edilirken bir hata oluştu: ", + "scenes.app.popup.workspaceparameter.pages.invited_guest_check_message": "KullanΔ±lan kullanΔ±cΔ± adΔ±nΔ±n veya e-postanΔ±n geΓ§erli olup olmadığınΔ± kontrol edin.", + "scenes.app.popup.workspaceparameter.pages.logo_modify_description": "Bu Γ§alışma alanΔ±nΔ±n gΓΆrΓΌntΓΌsΓΌnΓΌ dΓΌzenleyin", + "scenes.app.popup.workspaceparameter.pages.research_by": "UygulamalarΔ± ada ve kategorilere gΓΆre arayΔ±n", + "scenes.app.popup.workspaceparameter.pages.researching_apps_button": "UygulamalarΔ± ara...", + "scenes.app.popup.workspaceparameter.pages.show_button": "GΓΆrΓΌntΓΌlemek", + "scenes.app.popup.workspaceparameter.pages.title": "Γ‡alışma alanΔ± ayarlarΔ±", + "scenes.app.popup.workspaceparameter.pages.webhooks_access_subtitle": "Web kancalarΔ±na erişim", + "scenes.app.popup.workspaceparameter.pages.weight_max_small_text": "Maksimum boyut 5 MB.", + "scenes.app.popup.workspaceparameter.pages.withdraw_button": "Bu Γ§alışma alanΔ±ndan kaldΔ±r", + "scenes.app.popup.workspaceparameter.pages.worspace_notif": "Γ§alışma alanΔ±", + "scenes.app.popup.workspaceparameter.pages.write_access_subtitle": "Yazma erişimi", + "scenes.app.popup.workspaceparameter.pages.your_apps_label": "UygulamalarΔ±nΔ±z", + "scenes.app.workspacesbar.components.grp_parameters": "{{$1}} ayarlarΔ±", + "scenes.apps.calendar.add_calendar_menu": "Takvim ekle", + "scenes.apps.calendar.connectors_menu": "KonektΓΆrler...", + "scenes.apps.calendar.connectors_search_menu": "BağlayΔ±cΔ± ara...", + "scenes.apps.calendar.create_calendar_title": "Bir takvim oluşturun", + "scenes.apps.calendar.edit_calendar_title": "Takvimi dΓΌzenle", + "scenes.apps.calendar.export_title": "Δ°hracat", + "scenes.apps.calendar.export_view_menu": "GΓΆrΓΌnΓΌmΓΌ dışa aktar...", + "scenes.apps.calendar.ics_download_menu": "Bir ICS dosyasΔ± indirin", + "scenes.apps.calendar.ics_subscription_menu": "Bir ICS abonelik bağlantΔ±sΔ± alΔ±n", + "scenes.apps.calendar.modals.advanced_options": "Gelişmiş seΓ§enekler", + "scenes.apps.calendar.modals.description_placeholder": "AΓ§Δ±klama", + "scenes.apps.calendar.modals.details_title": "Detaylar", + "scenes.apps.calendar.modals.participants_event": "KatΔ±lΔ±mcΔ±lar", + "scenes.apps.calendar.modals.reminders": "hatΔ±rlatΔ±cΔ±lar", + "scenes.apps.calendar.modals.remove_button": "Silmek", + "scenes.apps.calendar.modals.remove_event_button": "Etkinliği sil", + "scenes.apps.calendar.modals.remove_event_text": "Etkinlik silinsin mi?", + "scenes.apps.calendar.modals.title_placeholder": "BaşlΔ±k", + "scenes.apps.drive.create_folder_button": "Oluşturmak", + "scenes.apps.drive.download_button": "Δ°ndirmek", + "scenes.apps.drive.open_link": "BağlantΔ±yΔ± yeni pencerede aΓ§", + "scenes.apps.drive.files_subtitle": "Dosyalar", + "scenes.apps.drive.folder_subtitle": "klasΓΆrler", + "scenes.apps.drive.go_out_trash_menu": "Γ§ΓΆp bΔ±rak", + "scenes.apps.drive.go_trash_menu": "Γ§ΓΆp kutusuna git", + "scenes.apps.drive.import_from_computer_menu": "bilgisayardan yΓΌkle", + "scenes.apps.drive.move_text": "Hareket", + "scenes.apps.drive.new_file_menu": "Yeni dosya", + "scenes.apps.drive.new_file_title": "Yeni dosya", + "scenes.apps.drive.new_external_storage": "Yeni harici depolama", + "scenes.apps.drive.new_folder_title": "Yeni dosya", + "scenes.apps.drive.viewer.no_preview_message": "Bu tΓΌr bir dosya gΓΆrΓΌntΓΌlenemiyor.", + "scenes.apps.messages.messageslist.go_last_message_button": "son mesaja git", + "scenes.apps.messages.messageslist.go_last_message_button.new_messages": "Yeni mesajlar", + "services.user.update_password_alert": "Şifreniz gΓΌncellenmiştir.", + "scenes.apps.tasks.board.tasks.use_deadline": "Son tarihi kullan", + "scenes.apps.tasks.board.tasks.use_starttime": "BaşlangΔ±Γ§ zamanΔ±nΔ± kullan", + "scenes.apps.tasks.board.starts": "başlatΔ±r", + "scenes.apps.tasks.board.ends": "iΓ§in yapΔ±lacak", + "scenes.apps.tasks.board.list_name": "Liste adΔ±", + "scenes.app.popup.sync_calendar": "Takvimlerinizi senkronize edin.", + "scenes.apps.parameters.workspace_sections.workspace.logo_company": "şirket logosu", + "scenes.app.popup.workspaceparameter.pages.logo_company_modify_description": "Şirket resmini dΓΌzenle ", + "scenes.app.popup.workspaceparameter.pages.cancel_invitation": "daveti iptal et", + "scenes.apps.account.account.fullname": "Ad Soyad", + "login.email_login": "E-posta / Giriş", + "scenes.apps.account.account.password_for_user": "KullanΔ±cΔ±nΔ±z iΓ§in şifre", + "scenes.apps.account.account.send_info": "Bu kimlik bilgilerini kullanΔ±cΔ±nΔ±za gΓΆnderin.", + "scenes.apps.account.account.save": "HesabΔ± kaydet", + "scenes.apps.account.message_temporary": "GeΓ§ici bir hesap, normal bir Twake hesabΔ± gibi Γ§alışır, ancak parolayΔ± siz oluşturursunuz ve gerekirse parolayΔ± sΔ±fΔ±rlayabilirsiniz.", + "scenes.apps.account.message_user_signin": "KullanΔ±cΔ±nΔ±z bu aynΔ± e-postayΔ± kullanarak herhangi bir zamanda oturum aΓ§abilir ve geΓ§ici hesabΔ± normal bir hesapla değiştirebilir.", + "scenes.app.mainview.link_expired": "Bu genel bağlantΔ± geΓ§ersiz veya sΓΌresi dolmuş.", + "scenes.app.mainview.create_account": "ΓΌzerinde ΓΌcretsiz olarak Γ§alışma alanΔ±nΔ±zΔ± oluşturun ", + "scenes.apps.calendar.modals.reminder_add": "HatΔ±rlatΔ±cΔ± ekle", + "components.attachmentpicker.add_attachment": "Ek ekle", + "components.drive.new_versions": "Yeni bir sΓΌrΓΌm ekle", + "components.drive.navigators.directory_not_found": "Dizin bulunamadΔ±.", + "components.drive.right_preview.suppress_link": "BağlantΔ±yΔ± bastΔ±r", + "components.tagpicker.tag_name": "Etiket adΔ±", + "components.upload.drop_files": "DosyalarΔ±nΔ±zΔ± buraya bΔ±rakΔ±n", + "components.workspace.list_manager.no_workspace": "Γ‡alışma alanΔ± yok", + "components.workspace.list_manager.add": "Γ‡alışma alanlarΔ± ekle", + "components.workspace.list_manager.current_space": "GeΓ§erli Γ§alışma alanΔ±", + "components.workspace.list_manager.current_company": "Mevcut şirket", + "components.workspace.list_manager.all": "TΓΌm", + "components.workspace.calendar.invalid": "GeΓ§ersiz", + "components.searchpopup.enter_text": "Twake'i aramak iΓ§in bir metin girin.", + "components.searchpopup.loading": "Daha fazla sonuΓ§ yΓΌkleniyor", + "components.searchpopup.filter_ws": "Γ‡alışma alanlarΔ±nΔ± filtrele", + "components.searchpopup.tags": "Etiketler", + "components.searchpopup.size": "Boy", + "components.searchpopup.creation": "oluşturma", + "components.searchpopup.update_search": "AramayΔ± gΓΌncelle", + "components.searchpopup.last_modif": "Son değişiklik", + "components.searchpopup.sender": "GΓΆnderen", + "components.searchpopup.mentions": "Mansiyonlar", + "components.searchpopup.only_pinned": "YalnΔ±zca sabitlenmiş mesajlar", + "components.alert.confirm": "İşleminizi onaylayΔ±n", + "components.alert.confirm_click": "Tamam'a tΔ±klayarak işleminizi onaylayΔ±n.", + "components.searchpopup.tasks": "GΓΆrevler", + "scenes.app.mainview.advanced_search_placeholder": "Gelişmiş Arama", + "components.searchpopup.hide_filters": "filtreleri gizle", + "components.searchpopup.show_filters": "filtreleri gΓΆster", + "components.searchpopup.load_more": "Daha fazla sonuΓ§ yΓΌkle", + "general.more": "Daha", + "scenes.apps.board.archived_tasks": "Arşivlenmiş gΓΆrevler ({{$1}})", + "scenes.apps.board.active_tasks": "Aktif gΓΆrevler", + "scenes.apps.board.kanban": "kanban", + "scenes.apps.board.display_as": "olarak gΓΆster", + "scenes.apps.board.new_task": "+ Yeni gΓΆrev", + "scenes.apps.board.all_boards": "TΓΌm Panolar", + "components.userlistmanager.no_users": "KullanΔ±cΔ± yok.", + "scenes.apps.calendar.video_link": "BağlantΔ±yΔ± aΓ§mak iΓ§in tΔ±klayΔ±n", + "components.tagpicker.notag": "Etiket yok", + "scenes.apps.tasks.modals.attachments": "ekler", + "components.calendar.calendarselector.from": "Δ°tibaren", + "scenes.apps.drive.move_text2": "Hareket", + "components.attachmentpicker.from_computer": "cihazΔ±nΔ±zdan", + "components.attachmentpicker.from_twake": "Twake Belgelerinden", + "components.attachmentpicker.file": "Dosya", + "components.attachmentpicker.remove_attach": "Eki kaldΔ±r", + "scenes.apps.drive.remove_attachs": "Ekleri kaldΔ±r", + "components.drive.elements.see": "GΓΆrmek", + "components.drive.elements.current_name": "Şu anki ismi: ", + "scenes.app.channelsbar.hide_discussion_leaving.menu": "TartışmayΔ± gizle", + "scenes.app.popup.adduserfromtwakeconsole.current_users_state": "{{$1}} e-posta(lar)Δ± eklenecek", + "components.newversion.new_version_component.row.part_1": "Eski bir Twake sΓΌrΓΌmΓΌ Γ§alıştΔ±rΔ±yorsunuz", + "components.newversion.new_version_component.row.part_2": "UygulamayΔ± yeniden yΓΌklemenizi ve yeni ΓΆzelliklerimizin keyfini Γ§Δ±karmanΔ±zΔ± ΓΆneririz!", + "components.newversion.new_version_component.link": "Yeniden yΓΌklemek iΓ§in burayΔ± tΔ±klayΔ±n", + "components.newversion.new_version_modal.title": "Yeni gΓΌncelleme mevcut !", + "scenes.apps.drive.download_all_button": "Hepsini indir", + "components.inputs.input_with_select.input.placeholder": "Kanal ismi", + "components.inputs.input_with_select.select.placeholder": "BΓΆlΓΌm adΔ±", + "components.inputs.input_with_select.select.no_sections": "Δ°lk kanal bΓΆlΓΌmΓΌnΓΌzΓΌn adΔ±nΔ± yazmaya başlayΔ±n.", + "components.inputs.input_with_select.button.tooltip": "Bir kanal bΓΆlΓΌmΓΌ ayarla", + "scenes.apps.messages.message.activity_message.a_added_b_to_the_channel": "{{$1}}, kanala {{$2}} ekledi", + "scenes.apps.messages.message.activity_message.a_removed_b_from_the_channel": "{{$1}}, {{$2}}'i kanaldan kaldΔ±rdΔ±", + "scenes.apps.messages.message.activity_message.a_deleted_channel_connector": "{{$1}} bir konektΓΆrΓΌ Γ§Δ±kardΔ± {{$2}}", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.loader": "Daha fazla yΓΌkle", + "general.verify": "Doğrulamak", + "components.unverified_account.typography_text_danger": "Deneme sΓΌrenizde {{$1}} gΓΌnΓΌnΓΌz kaldΔ±. Deneme hesabΔ± 7 gΓΌn sonra bloke edilecek ve 1 aylΔ±k kayΔ±ttan sonra kalΔ±cΔ± olarak silinecektir. Size gΓΆnderdiğimiz doğrulama e-postasΔ±ndaki \"HesabΔ±mΔ± doğrula\" butonuna tΔ±klayarak hesabΔ±nΔ±zΔ± doğrulayabilirsiniz.", + "components.unverified_account.verification_details": "Doğrulama ayrΔ±ntΔ±larΔ±nΔ± şu adrese gΓΆnderdik:", + "components.account_verification_status_sentence": "Hesap durumunuz: {{$1}}", + "components.unverified_account.re_send_email": "E-postayΔ± almadΔ±nΔ±z mΔ±?", + "components.blocked_account.trial_period_over": "Deneme sΓΌreniz bitti. HesabΔ±nΔ±zΔ±n kilidini aΓ§mak ve tΓΌm işlevlere erişmek iΓ§in lΓΌtfen hesabΔ±nΔ±zΔ± e-posta onayΔ± ile doğrulayΔ±n.", + "components.add_mails_workspace.button": "Twake'i kullanmaya başlayΔ±n", + "components.add_mails_workspace.title_1": "BazΔ± kullanΔ±cΔ±lar ekle", + "components.add_mails_workspace.title_2": "Twake bir ekip işbirliği aracΔ±dΔ±r, bu nedenle bazΔ± kullanΔ±cΔ±larΔ± sizin iΓ§in oluşturduğumuz bir Γ§alışma alanΔ±nΔ± test etmeye davet edin.", + "components.add_mails_workspace.text_area_placeholder": "KullanΔ±cΔ±larΔ±nΔ±zΔ±n e-postalarΔ±nΔ± girin*", + "components.verify_mail.title_1": "Tebrikler", + "components.verify_mail.title_2": "ArtΔ±k resmi bir Twake kullanΔ±cΔ±sΔ±sΔ±nΔ±z!", + "components.verify_mail.button": "KullanΔ±cΔ± Ekle", + "components.verify_mail.text": "Her şeyden ΓΆnce, e-posta adresinizi doğrulamanΔ±z gerekir. Şu adrese bir doğrulama bağlantΔ±sΔ± gΓΆnderdik:", + "components.verify_mail.paragraph": "Δ°sterseniz bunu daha sonra yapabilirsiniz ancak doğrulanmamış hesaplarΔ±n Twake'in yalnΔ±zca sΔ±nΔ±rlΔ± bir sΓΌrΓΌmΓΌne erişimi vardΔ±r.", + "services.console_services.toaster.add_emails_error": "E-posta(lar) eklenirken hata oluştu", + "services.console_services.toaster.add_email_error_message": "{{$1}} eklenirken hata oluştu", + "services.console_services.toaster.success_verify_email": "E-posta hesabΔ±nΔ±za bir doğrulama bağlantΔ±sΔ± gΓΆnderildi", + "scenes.app.popup.workspaceparameter.edit_from_console": "Konsolda GΓΆr", + "services.console_services.toaster.success_invite_emails": "{{$1}} kullanΔ±cΔ±(lar) başarΔ±yla eklendi", + "scenes.client.channels_bar.modals.guest_management.title": "Misafirleri {{$1}} iΓ§inde yΓΆnetin", + "scenes.client.channels_bar.modals.guest_management.input_placeholder": "Misafirleri veya bekleyen e-postalarΔ± arayΔ±n", + "scenes.client.channels_bar.modals.guest_management.tips": "YukarΔ±daki girişi kullanarak e-posta eklemeye veya aramaya başlayΔ±n", + "scenes.client.channels_bar.modals.parts.channel_member_row.label.pending_email": "Mail gΓΆnderildi", + "general.user.role.company.admin": "şirket yΓΆneticisi", + "general.user.role.company.member": "Üye", + "general.user.role.company.guest": "Konuk", + "general.user.deleted": "Silinen Hesap", + "components.richtexteditor.toolbar.bold": "GΓΆzΓΌ pek", + "components.richtexteditor.toolbar.underline": "AltΔ±nΔ± Γ§izmek", + "components.richtexteditor.toolbar.italic": "Δ°talik", + "components.richtexteditor.toolbar.strikethrough": "ΓΌstΓΌ Γ§izili", + "components.richtexteditor.toolbar.code": "kod", + "components.richtexteditor.toolbar.unordered-list": "Maddeli liste", + "components.richtexteditor.toolbar.ordered-list": "SΔ±ralΔ± Liste", + "components.richtexteditor.toolbar.blockquote": "blok alΔ±ntΔ±", + "components.richtexteditor.toolbar.code-block": "Kod Bloğu", + "components.locked_features.locked_history_banner.title": "Az ΓΆnce mesaj sΔ±nΔ±rΔ±na ulaştΔ±nΔ±z", + "components.locked_features.locked_history_banner.button": "Daha fazla bilgi edin", + "components.on_boarding.popups.blocked_company.or": "Veya", + "components.on_boarding.popups.blocked_company.company_selector": "Başka bir şirkete geΓ§", + "scenes.apps.tasks.select_user_button": "Başka bir kullanΔ±cΔ± iΓ§in gΓΆrevleri gΓΆrΓΌntΓΌleyin", + "scenes.apps.tasks.select_user": "KullanΔ±cΔ± ara", + "scenes.apps.messages.input.attach_file.from_computer": "bilgisayardan", + "scenes.app.popup.workspaceparameter.pages.table_title": "Δ°sim", + "scenes.client.main_view.main_header.search_input": "Arama", + "scenes.apps.drive.new_link_title": "Yeni bağlantΔ±", + "scenes.apps.drive.default_link_name": "başlΔ±ksΔ±z", + "components.emoji_picker.input_search_placeholder": "Arama", + "services.apps.messages.message_editor_service.upload_error_toaster": "{{$1}} - Bir mesaja {{$2}}'ten fazla dosya ekleyemezsiniz", + "scenes.apps.messages.message.parts.deleted_content.text.current_user": "Bu mesajΔ± sildin", + "general.uploading": "yΓΌkleniyor", + "components.emoji_picker.categories.activity": "Aktivite", + "components.emoji_picker.categories.travel_and_places": "Seyahat ve Yerler", + "components.emoji_picker.categories.objects": "nesneler", + "components.emoji_picker.categories.symbols": "semboller", + "components.emoji_picker.categories.flags": "Bayraklar", + "components.emoji_picker.categories.search_result": "Arama SonuΓ§larΔ±", + "components.emoji_picker.categories.not_found": "Emoji BulunamadΔ±", + "scenes.app.popup.workspaceparameter.pages.workspace_partner_tabs.members.table.tags": "rol", + "general.email": "E-posta", + "components.locked_features.locked_only_office_popup.title": "Bu dosyayΔ± dΓΌzenleyemezsiniz", + "components.locked_features.locked_only_office_popup.text": "Hata!! DosyayΔ± Twake'den dΓΌzenlemek istiyor gibisiniz. Ofis dosyalarΔ± etrafΔ±nda işbirliği yapmak istiyorsanΔ±z planΔ±nΔ±zΔ± yΓΌkseltmeyi düşünebilirsiniz. FiyatlandΔ±rma seΓ§eneklerimizi keşfedin ve ekip işbirliği ihtiyaΓ§larΔ±nΔ±z iΓ§in en iyi seΓ§eneği belirleyin.", + "scenes.app.popup.adduser.magiclinks.genrator_info": "Γ‡alışma alanΔ±na davet bağlantΔ±sΔ±", + "scenes.app.popup.adduser.magiclinks.new_link_generated": "Yeni bağlantΔ± oluşturuldu", + "scenes.app.popup.adduser.magiclinks.copied_to_clipboard": "Panoya başarΔ±yla kopyalandΔ±", + "scenes.app.popup.adduser.magiclinks.action_copy": "kopyala", + "scenes.app.popup.adduser.magiclinks.action_generate": "ΓΌret", + "scenes.apps.calendar.modify_calendar_menu": "Takvimi dΓΌzenle", + "scenes.apps.calendar.month_option": "Ay", + "scenes.apps.calendar.my_calendar": "Takvimim", + "scenes.apps.calendar.my_calendar_label": "Takvimim", + "scenes.apps.calendar.my_calendar_menu": "Takvimim", + "scenes.apps.drive.choose_folder_button": "Bir dizin seΓ§in", + "scenes.apps.drive.choose_file_button": "Bir dosya seΓ§in", + "scenes.apps.drive.viewer.open_with_button": "Bununla aΓ§...", + "scenes.apps.messages.input.placeholder": "Bir mesaj yaz. Bir kullanΔ±cΔ±dan alΔ±ntΔ± yapmak iΓ§in @ kullanΔ±n.", + "components.drive.elements.configurate_mod": "Modu yapΔ±landΔ±rΔ±n...", + "components.drive.elements.manage_version": "SΓΌrΓΌmleri yΓΆnet", + "scenes.app.popup.createcompany.try_again": "LΓΌtfen tekrar deneyin.", + "scenes.app.popup.workspace.edit_temp": "GeΓ§ici hesabΔ± dΓΌzenle", + "scenes.app.popup.workspace.create_temp": "GeΓ§ici hesap oluştur", + "scenes.apps.tasks.active_tasks": "aktif gΓΆrevler", + "scenes.apps.drive.right_preview.versions": "SΓΌrΓΌmler", + "scenes.app.popup.appsparameters.pages.icon": "Simge", + "components.locked_features.locked_history_banner.description": "Şirketinizin Γ§ok fazla mesajΔ± var! TΓΌm mesaj geΓ§mişinize erişmek iΓ§in şimdi yΓΌkseltin.", + "components.locked_features.locked_guests_popup.title": "Misafirler ΓΆzelliği kilitli", + "components.locked_features.locked_guests_popup.description": "Hata!! GΓΆrΓΌnüşe gΓΆre harici kullanΔ±cΔ±larΔ± Γ§alışma alanΔ±nΔ±za davet etmek istiyorsunuz. Misafirler ve harici ortaklarla işbirliği yapmak istiyorsanΔ±z planΔ±nΔ±zΔ± yΓΌkseltmeyi düşünebilirsiniz. FiyatlandΔ±rma seΓ§eneklerimizi keşfedin ve ekip işbirliği ihtiyaΓ§larΔ±nΔ±z iΓ§in en iyi seΓ§eneği belirleyin.", + "components.locked_features.locked_guests_popup.learn_more_button": "Daha fazla bilgi edin", + "components.locked_features.locked_guests_popup.skip_for_now_button": "Şimdilik geΓ§", + "components.locked_features.locked_guests_popup.or": "Veya", + "components.on_boarding.popups.blocked_company.description": "Twake aboneliğinizin sΓΌresi doldu. Yenilemek ve ekibinizle tekrar iletişim kurabilmek iΓ§in lΓΌtfen şirketinizin sahibi veya yΓΆneticisi ile iletişime geΓ§in!", + "components.on_boarding.popups.blocked_company.learn_more_text": "Şirket abonelik planΔ± hakkΔ±nda daha fazla bilgi edinmek ister misiniz?", + "components.locked_features.locked_workspace_popup.text": "Hata!! Şirketinizde yeni bir Γ§alışma alanΔ± mΔ± yaratmak istiyorsunuz? PlanΔ±nΔ±zΔ± yΓΌkseltmeyi düşünebilirsiniz. FiyatlandΔ±rma seΓ§eneklerimizi keşfedin ve ekip işbirliği ihtiyaΓ§larΔ±nΔ±z iΓ§in en iyi seΓ§eneği belirleyin.", + "scenes.app.integrations_parameters.company_application_popup.tag": "Kurulmuş", + "scenes.app.integrations_parameters.company_application_popup.btn": "DΓΌzenlemek", + "scenes.app.integrations_parameters.company_application_popup.tab_btn_info": "bilgiler", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.description_item": "AΓ§Δ±klama", + "scenes.app.integrations_parameters.company_applications_table.more_menu.show_application": "GΓΆstermek", + "scenes.app.integrations_parameters.company_applications_table.more_menu.remove_application": "şirketten uzaklaştΔ±r", + "scenes.app.integrations_parameters.company_applications_table.name": "Δ°sim", + "scenes.app.integrations_parameters.company_applications_table.title": "Şirketinizde yΓΌklΓΌ", + "scenes.join.loading": "YΓΌkleniyor…", + "scenes.join.wrong_link_title": "Bu bağlantΔ± artΔ±k mevcut değil", + "scenes.join.wrong_link_description": "Sizi bu şirkete katΔ±lmaya davet eden kişiden yeni bir bağlantΔ± isteyin veya kendi şirketinizi oluşturun", + "scenes.join.create_the_company_button": "şirket oluştur", + "scenes.join.join_workspace_from_company": "{{$2}}'ten {{$1}}'e katΔ±lΔ±n!", + "scenes.join.twake_description": "Twake, ekip ΓΌretkenliğinizi artΔ±rmak iΓ§in oluşturulmuş aΓ§Δ±k kaynaklΔ± bir dijital Γ§alışma alanΔ±dΔ±r.", + "components.user_picker.modal_no_result": "SonuΓ§ bulunamadΔ±", + "components.users_picker.add_me": "beni ekle", + "scenes.app.workspaces.create_company.invitations.title": "Γ‡alışma alanΔ±nΔ±zΔ± yapΔ±landΔ±rΔ±n.", + "scenes.app.header.disconnected": "bağlantΔ±nΔ±z kesildi", + "scenes.app.header.disconnected.reload": "Tekrar yΓΌkle", + "scenes.app.header.alt_notifications": "Bildirimler", + "scenes.apps.calendar.calendar.week_btn": "Hafta", + "scenes.apps.calendar.calendar.list_btn": "Liste", + "scenes.apps.calendar.event_edition.deadline_tag": "Son teslim tarihi", + "scenes.apps.calendar.event_edition.checkbox_all_day": "TΓΌm gΓΌn", + "scenes.apps.calendar.event_edition.title_confidentiality": "Gizlilik", + "scenes.apps.calendar.event_view.article_until": "ile", + "scenes.apps.calendar.calendar_modal.participants": "KatΔ±lΔ±mcΔ±lar", + "scenes.apps.calendar.calendar_modal.placeholder": "Δ°sim", + "scenes.apps.calendar.left.calendars": "Takvimler", + "scenes.apps.drive.left.search": "Arama", + "scenes.apps.drive.navigators.navigator_content.directory_name": "dizin adΔ±", + "scenes.apps.drive.navigators.navigator_content.files": "Dosyalar", + "scenes.apps.drive.navigators.navigator_labels.title": "Etiketler", + "scenes.apps.drive.navigators.new_file.untitled": "başlΔ±ksΔ±z", + "scenes.apps.drive.navigators.new_file.create_file.type": "Tip", + "scenes.apps.drive.navigators.new_file": "Yeni dosya", + "scenes.apps.drive.preview_bloc.operations_download": "Δ°ndirmek", + "scenes.apps.drive.preview_bloc.error_file": "Dosya bulunamadΔ±", + "scenes.apps.drive.right_preview.operations_restore": "Onarmak", + "scenes.apps.drive.right_preview.operations_delete": "Çâp kutusuna taşıyΔ±n", + "scenes.apps.drive.right_preview.public_link": "Herkese aΓ§Δ±k bağlantΔ±", + "scenes.apps.messages.messages": "Mesajlar", + "scenes.apps.messages.chatbox.chat.delete_message": "Bu mesajΔ± sil", + "scenes.apps.messages.chatbox.chat.delete_message_btn": "MesajΔ± sil", + "scenes.apps.messages.left_bar.stream_modal.placeholder_name": "Δ°sim", + "scenes.apps.messages.left_bar.stream.add_to_favorites": "Favorilere ekle", + "scenes.apps.messages.left_bar.stream.remove_from_favorites": "Favorilerden Γ§Δ±kar", + "scenes.apps.messages.left_bar.stream.notifications": "Bildirimler...", + "scenes.apps.messages.left_bar.stream.notifications.all": "herhangi bir mesaj", + "scenes.apps.messages.left_bar.stream.notifications.mentions": "{{$1}}, {{$2}} ve {{$3}}", + "scenes.apps.messages.left_bar.stream.notifications.me": "sadece {{$1}}", + "scenes.apps.messages.left_bar.stream.notifications.never": "HiΓ§bir şey değil", + "scenes.apps.parameters.workspace_sections.workspace": "Γ§alışma alanΔ±", + "scenes.apps.parameters.workspace_sections.members": "KatΔ±lΔ±mcΔ±lar", + "scenes.apps.parameters.group_sections.workspaces": "Γ§alışma alanlarΔ±", + "scenes.apps.parameters.group_sections.apps": "uygulamalar", + "scenes.apps.account.languages.text": "Twake dilini değiştirin.", + "components.calendar.repetition.ends": "biter", + "scenes.apps.tasks.boards": "Panolar", + "scenes.apps.tasks.connectors_menu": "KonektΓΆrler...", + "scenes.apps.tasks.connectors_search_menu": "BağlayΔ±cΔ± ara...", + "scenes.apps.tasks.no_connectors_menu_text": "Bir takvime bağlanabilecek bağlayΔ±cΔ±nΔ±z yok.", + "scenes.apps.tasks.unconfigured_tab": "Bu sekme henΓΌz yapΔ±landΔ±rΔ±lmamış.", + "scenes.apps.tasks.choose_board_button": "Bir tahta seΓ§in", + "general.open": "AΓ§Δ±k", + "components.calendar.repetition.never": "HiΓ§bir zaman", + "components.calendar.repetition.on": "AΓ§Δ±k", + "components.calendar.repetition.after": "SonrasΔ±nda", + "components.calendar.repetition.days": "gΓΌn(ler)", + "components.calendar.repetition.weeks": "haftalar)", + "components.calendar.repetition.months": "ay(lar)", + "components.calendar.repetition.years": "yΔ±l(lar)", + "components.calendar.repetition.custom_recurrence": "Γ–zel yineleme", + "components.calendar.repetition.occurrence": "Olay(lar)", + "components.calendar.repetition.repeat_on": "tekrarla", + "scenes.app.channelsbar.currentuser.add_apps": "UygulamalarΔ± ara", + "scenes.app.channelsbar.currentuser.change_my_status": "durumumu değiştir", + "scenes.app.channelsbar.currentuser.collaborateurs": "KullanΔ±cΔ±lar", + "scenes.app.channelsbar.currentuser.create_workspace_page": "Bir Γ§alışma alanΔ± oluşturun", + "scenes.app.channelsbar.currentuser.invited_status": "sen misafirsin", + "scenes.app.channelsbar.currentuser.title": "Hesap ayarlarΔ±", + "scenes.app.channelsbar.currentuser.workspace_info": "{{$2}} grubundan {{$1}} Γ§alışma alanΔ±ndasΔ±nΔ±z", + "scenes.app.channelsbar.channelsworkspace.channel_title.favorite": "FAVORΔ°LER", + "scenes.app.channelsbar.channelsworkspace.create_channel": "Kanal oluştur", + "scenes.app.channelsbar.channelsworkspace.no_channel": "HenΓΌz herhangi bir kanala katΔ±lmadΔ±nΔ±z", + "scenes.app.channelsbar.modify_channel_menu": "KanalΔ± dΓΌzenle", + "scenes.app.channelsbar.guest_management": "misafir yΓΆnetimi", + "scenes.app.channelsbar.read_sign": "Okundu olarak işaretle", + "scenes.app.channelsbar.unread_sign": "okunmamış olarak işaretle", + "scenes.app.channelsbar.channel_leaving": "kanaldan ayrΔ±l", + "scenes.app.mainview.tabs.searching_connectors": "BağlayΔ±cΔ± ara...", + "scenes.app.popup.adduser.adresses_message": "LΓΌtfen adresleri virgΓΌl veya boşlukla ayΔ±rΔ±n. Twake'in aboneliğinize bağlΔ± olarak davet sayΔ±sΔ±nΔ± sΔ±nΔ±rlayabileceğini unutmayΔ±n.", + "scenes.app.popup.appsparameters.pages._app_identity": "UygulamanΔ±n kimliği", + "scenes.app.popup.appsparameters.pages._appareance_message_twakcode": "Twacode mesajlarΔ±nΔ±zΔ±n gΓΆrΓΌnΓΌmΓΌnΓΌ test edin", + "scenes.app.popup.appsparameters.pages.amazing_app_name": "benim harika uygulamam", + "scenes.app.popup.appsparameters.pages.developped_apps_subtitle": "FirmanΔ±n geliştirdiği uygulamalar", + "scenes.app.popup.appsparameters.pages.dispalyed_parameters_description": "UygulamanΔ±zΔ±n nerede gΓΆrΓΌneceğini belirlemenizi sağlar.", + "scenes.app.popup.appsparameters.pages.displayed_parameters_label": "GΓΆrΓΌntΓΌ ayarlarΔ±", + "scenes.app.popup.workspaceparameter.pages.logo_subtitle": "Logo", + "scenes.app.popup.workspaceparameter.pages.name_description": "Bu Γ§alışma alanΔ±nΔ±n adΔ±nΔ± değiştir", + "scenes.app.popup.workspaceparameter.pages.name_label": "Γ‡alışma alanΔ±nΔ±n adΔ±", + "scenes.app.popup.workspaceparameter.pages.no_access": "Erişim yok.", + "scenes.app.popup.workspaceparameter.pages.no_app_information": "Bu Γ§alışma alanΔ±nda uygulamanΔ±z yok", + "scenes.app.popup.workspaceparameter.pages.quit_workspace_menu": "Bu Γ§alışma alanΔ±ndan ayrΔ±l", + "scenes.apps.calendar.modals.event_adresse_placeholder": "Adres", + "scenes.apps.drive.no_file_alert": "Dosya oluşturmanΔ±za izin veren uygulamanΔ±z yok.", + "scenes.error_on_twake": "\"Bir problemimiz var Houston\"", + "scenes.help_us": "Ancak, bu hatayΔ± dΓΌzeltmemize yardΔ±mcΔ± olmak isterseniz, bize aşağıdan bir mesaj gΓΆnderin: ", + "scenes.login.verifymail.alert": "E-postanΔ±zΔ± kontrol ediyoruz!", + "scenes.login.verifymail.error_message": "Bir hata oluştu", + "scenes.login.verifymail.signin_button": "Giriş yapmak", + "scenes.login.verifymail.success": "E-postanΔ±z başarΔ±yla doğrulandΔ±!", + "scenes.login.verifymail.verification_waiting": "Doğrulama bekleniyor...", + "scenes.no_panic": "Panik yapma! Twake'i dΓΌzeltmek iΓ§in bu sayfayΔ± yeniden yΓΌkleyin.", + "services.apps.calendar.deadline_icon": "Son teslim tarihi", + "services.apps.calendar.event_icon": "Etkinlik", + "services.apps.calendar.move_icon": "Hareket", + "services.apps.calendar.reminder_icon": "HatΔ±rlatma", + "scenes.app.workspaces.components.skip": "Atlamak", + "scenes.apps.calendar.unconfigured_tab": "Bu sekme henΓΌz yapΔ±landΔ±rΔ±lmamış.", + "scenes.apps.drive.trash": "Çâp", + "scenes.apps.drive.top_menu_more": "Daha", + "scenes.apps.drive.top_menu_no_items": "{{$1}} âğeler", + "scenes.apps.messages.new_thread": "Yeni bir tartışma başlat", + "scenes.apps.messages.input.send_message": "Mesaj gΓΆnder", + "scenes.apps.messages.input.emoji": "emoji", + "scenes.apps.messages.input.hide_formatting": "BiΓ§imlendirmeyi gizle", + "scenes.apps.tasks.board.tasks.in_list": "Listede", + "scenes.apps.parameters.workspace_sections.members.invite_all": "TΓΌmΓΌnΓΌ davet et", + "scenes.app.taskpicker.select": "SeΓ§me", + "components.listmanager.filter": "filtre", + "scenes.apps.tasks.no_connector": "BağlayΔ±cΔ± yok", + "scenes.apps.drive.used": "Bu klasΓΆrde kullanΔ±lan", + "components.reminder.notification": "Bildirim", + "components.reminder.minutes_bef": "dakikalar ΓΆnce", + "components.reminder.hours_bef": "saatler ΓΆnce", + "components.reminder.days_bef": "GΓΌnler ΓΆnce", + "components.reminder.weeks_bef": "haftalar ΓΆnce", + "components.reminder.by_email": "E-Posta", + "components.alert.leave_private_channel.title": "Kanaldan ayrΔ±lmak istediğinizden emin misiniz?", + "components.alert.leave_private_channel.description": "Biri sizi davet etmedikΓ§e bu ΓΆzel kanala tekrar katΔ±lamazsΔ±nΔ±z.", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.tag": "ΓΌye değilsin", + "components.input.copied": "kopyalandΔ±", + "scenes.client.channelbar.channelmemberslist.tag": "Sen", + "components.locked_features.locked_workspace_popup.title": "Daha fazla Γ§alışma alanΔ± oluşturamazsΔ±nΔ±z", + "components.locked_features.locked_workspace_popup.subtitle": "Ücretsiz sΓΌrΓΌmde, şirketinizde yalnΔ±zca bir Γ§alışma alanΔ±nΔ±z olabilir.", + "scenes.app.workspaces.create_company.group_data.title": "HΔ±zlΔ± olacağız - sadece bazΔ± istatistiksel bilgilere ihtiyacΔ±mΔ±z var.", + "scenes.app.channelsbar.currentuser.company_messages_counter_header": "Mesaj numarasΔ±", + "scenes.app.channelsbar.currentuser.company_messages_counter_info": "Twake'in ΓΌcretsiz sΓΌrΓΌmΓΌnde, daha yeni olan {{$1}} mesajlarΔ±ndan daha fazlasΔ±na erişemezsiniz.", + "scenes.app.channelsbar.currentuser.company_messages_counter_link": "Daha fazla plan gΓΆster", + "scenes.app.channelsbar.channelsuser.new_private_discussion": "Yeni ΓΆzel tartışma", + "scenes.app.channelsbar.channelsuser.no_private_message_invite_collaboraters": "Γ–zel mesaj yok. KullanΔ±cΔ±larΔ± davet edin!", + "scenes.app.channelsbar.channelsuser.private_messages": "Doğrudan mesajlar", + "scenes.app.channelsbar.channelsworkspace.channel_title": "KANALLAR", + "scenes.app.channelsbar.channel_removing": "KanalΔ± sil", + "scenes.app.channelsbar.company_invitation_alert_subtitle": "Bu Γ§erΓ§eveye tΔ±klayarak dΓΌzenli kalmak iΓ§in bu kanallarΔ± işletmenize aktarabilirsiniz.", + "scenes.app.channelsbar.company_invitation_alert_title": "şirkete davetlisiniz ", + "scenes.app.channelsbar.initial_instructions_tutorial": "Bir ad, bir ad ve bir profil resmi seΓ§in.", + "scenes.app.channelsbar.installation_desktop_tutorial": "MasaΓΌstΓΌ uygulamasΔ±nΔ± yΓΌkleyin", + "scenes.app.channelsbar.invitation_collaboraors_tutorial": "KullanΔ±cΔ±larΔ± Γ§alışma alanΔ±nΔ±za davet edin.", + "scenes.app.channelsbar.public_channel_label": "Halk", + "scenes.app.channelsbar.private_channel_label": "Γ–zel", + "scenes.app.channelsbar.sending_message_instruction": "Bir tartışmada ilk mesajΔ±nΔ±zΔ± gΓΆnderin", + "scenes.app.channelsbar.tutorial_alert": "Bu kareyi bir daha gΓΆstermeyecek misin?", + "scenes.app.channelsbar.welcome": "Twake'e hoş geldiniz", + "scenes.app.channelsbar.welcoming_message_subtitle": "Sadece birkaΓ§ tΔ±klamayla Twake profesyoneli olun!", + "scenes.app.mainview.instruction_current_tab": "Solunuzda bir kanal seΓ§erek başlayΔ±n.", + "scenes.app.popup.appsparameters.pages.api_parameters_label": "API ayarlarΔ±", + "scenes.app.popup.appsparameters.pages.app_name_label": "Uygulama AdΔ±", + "scenes.app.popup.appsparameters.pages.app_privileges_label": "Uygulama ayrΔ±calΔ±klarΔ±", + "scenes.app.popup.appsparameters.pages.app_update": "UygulamayΔ± {{$1}} gΓΌncelleyin (uygulama {{$2}} kez kullanΔ±lΔ±r.)", + "scenes.app.popup.appsparameters.pages.application_title": "Başvuru", + "scenes.app.popup.appsparameters.pages.apps_title": "UygulamalarΔ±nΔ±z ve bağlayΔ±cΔ±larΔ±nΔ±z", + "scenes.app.popup.appsparameters.pages.call_event_handlers": "'{{$3}}' pasifleriyle '{{$1}}' tΓΌrΓΌ ve '{{$2}}' kimliği olayΔ±", + "scenes.app.popup.appsparameters.pages.company_label": "Şirket sahibi", + "scenes.app.popup.appsparameters.pages.configuration_label": "YapΔ±landΔ±rma", + "scenes.app.popup.appsparameters.pages.create_app_button": "Bir uygulama oluşturun", + "scenes.app.popup.appsparameters.pages.create_my_app": "UygulamamΔ± oluştur", + "scenes.app.popup.appsparameters.pages.current_informations_apps_connectors": "HenΓΌz bir uygulama oluşturmadΔ±nΔ±z. Bir uygulama veya bağlayΔ±cΔ± oluşturmadan ΓΆnce, uygulama pazarΔ±mΔ±zda mevcut olmadığından emin olun.", + "scenes.app.popup.appsparameters.pages.danger_zone_description": "UygulamayΔ± sil", + "scenes.app.popup.appsparameters.pages.new_app_title": "Yeni uygulama", + "scenes.app.popup.appsparameters.pages.ok_user_code": "Tamam", + "scenes.app.popup.appsparameters.pages.optimal_format": "En uygun biΓ§im : 48x48 piksel.", + "scenes.app.popup.appsparameters.pages.parameters_form_small_text": "YayΔ±nlanmayan uygulama yalnΔ±zca şirketinizde Γ§alışır. TΓΌm Twake kullanΔ±cΔ±larΔ±nΔ±n kullanΔ±mΔ±na sunmak istiyorsanΔ±z, bu seΓ§eneği etkinleştirin.", + "scenes.app.popup.appsparameters.pages.public_availability_application": "Genel uygulama", + "scenes.app.popup.appsparameters.pages.public_login_label": "Genel tanΔ±mlayΔ±cΔ±", + "scenes.app.popup.appsparameters.pages.publication_description": "UygulamanΔ±zΔ±n gΓΆrΓΌnΓΌrlüğünΓΌ belirleyin.", + "scenes.app.popup.appsparameters.pages.string_information": "Bu dize, uygulamanΔ±zΔ± tanΔ±mlar ve mesaj komutlarΔ±nda kullanΔ±lacaktΔ±r.", + "scenes.app.popup.appsparameters.pages.title_tester": "Twakecode test cihazΔ±", + "scenes.app.popup.appsparameters.pages.url_reception_events_label": "Etkinlik alma URL'si", + "scenes.app.popup.appsparameters.pages.error_app_simple_name_message": "UygulamanΔ±zΔ±n basitleştirilmiş adΔ± zaten başka bir uygulama tarafΔ±ndan kullanΔ±lΔ±yor. LΓΌtfen değiştirin.", + "scenes.app.popup.userparameter.pages.keywords_notif_description": "Aşağıdaki anahtar kelimeleri vurgulayΔ±n:", + "scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description": "E-posta bildirimlerinin sΔ±klığınΔ± ayarlayΔ±n.", + "scenes.app.popup.userparameter.pages.private_message_content.show": "Γ–zel mesaj iΓ§eriğini gΓΆster", + "scenes.app.popup.workspaceparameter.pages.alert_impossible_removing": "Son yΓΆnetici olduğunuz iΓ§in Γ§alışma alanΔ±ndan Γ§Δ±kamazsΔ±nΔ±z. Yeni bir yΓΆnetici tanΔ±mlayabilir veya bu Γ§alışma alanΔ±nΔ± silebilir/arşivleyebilirsiniz.", + "scenes.app.popup.workspaceparameter.pages.all_apps_small_text": "BΓΌtΓΌn uygulamalar", + "scenes.app.popup.workspaceparameter.pages.apps_company_small_text": "Şirketinizin uygulamalarΔ±", + "scenes.app.popup.workspaceparameter.pages.company_developped_apps_subtitle": "FirmanΔ±n geliştirdiği uygulamalar", + "scenes.app.popup.workspaceparameter.pages.company_identity_title": "Şirketin kimliği", + "scenes.app.popup.workspaceparameter.pages.company_name_description": "Bu şirketin adΔ±nΔ± değiştir", + "scenes.app.popup.workspaceparameter.pages.company_name_label": "Şirketin adΔ±", + "scenes.app.popup.workspaceparameter.pages.configuration_notif": "yapΔ±landΔ±rma", + "scenes.app.popup.workspaceparameter.pages.configure_button": "YapΔ±landΔ±r", + "scenes.app.popup.workspaceparameter.pages.description": "AΓ§Δ±klama", + "scenes.app.popup.workspaceparameter.pages.developped_apps_small_text": "FirmanΔ±n geliştirdiği uygulamalar", + "scenes.app.popup.workspaceparameter.pages.displayed_preferencies_subtitle": "GΓΆrΓΌntΓΌleme tercihleri", + "scenes.app.popup.workspaceparameter.pages.install_button": "DΓΌzenlemek", + "scenes.app.popup.workspaceparameter.pages.installed_app_information": "UygulamayΔ± bu Γ§alışma alanΔ±na yΓΌkleyin.", + "scenes.app.popup.workspaceparameter.pages.installed_apps_information": "Bu Γ§alışma alanΔ±nda yΓΌklΓΌ uygulamalar {{$1}}", + "scenes.apps.messages.messageslist.get_writing_users": "yazΔ±yorlar...", + "components.drive.right_preview.create_link": "Bir erişim bağlantΔ±sΔ± oluşturun", + "components.drive.moove_here": "Buraya taşın", + "components.drive.modify_uslist": "KullanΔ±cΔ± listesini değiştir", + "scenes.apps.calendar.reminders": "hatΔ±rlatΔ±cΔ±(lar)", + "scenes.app.mainview.discussion": "Tartışma", + "scenes.client.channelbar.channelmemberslist.title": "{{$1}} iΓ§indeki kullanΔ±cΔ±lar", + "scenes.client.channelbar.channelmemberslist.loader": "Daha fazla yΓΌkle", + "scenes.client.channelbar.channelmemberslist.autocomplete": "KullanΔ±cΔ± ekle veya ara", + "components.notifications.hidden_notifications_button.children": "Yeni mesajlar", + "scenes.client.mainview.tabs.tabstemplateeditor.select_placeholder": "Başvuru", + "scenes.client.channelbar.channelmemberslist.no_members": "Bu kanalda kullanΔ±cΔ± yok, KullanΔ±cΔ± ekle'ye tΔ±klayarak onlarΔ± davet edebilirsiniz.", + "scenes.apps.messages.message.activity_message.a_updated_channel_description": "{{$1}} aΓ§Δ±klamayΔ± değiştirdi", + "scenes.apps.messages.message.activity_message.a_updated_channel_name": "{{$1}}, kanalΔ± {{$2}} olarak yeniden adlandΔ±rdΔ±", + "scenes.apps.messages.message.activity_message.a_created_channel_tab": "{{$1}} yeni bir {{$2}} sekmesi ekledi {{$3}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_tab": "{{$1}}, {{$2}} sekmesini kaldΔ±rdΔ± {{$3}}", + "scenes.apps.messages.message.activity_message.a_created_channel_connector": "{{$1}} yeni bir bağlayΔ±cΔ± ekledi {{$2}}", + "general.re_send": "Yeniden gΓΆnder", + "components.account_verication_status_unverified": "Doğrulanmamış", + "components.account_verication_status_blocked": "Kilitli", + "scenes.apps.messages.message.parts.deleted_content.text": "{{$1}} mesajΔ±nΔ± sildi", + "components.member.user_parts.and_more_user_text": " ve {{$1}} daha fazla kullanΔ±cΔ±", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_link": "Γ–zel bir kanal oluşturun", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_text": " Bunun yerine", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_input_placeholder": "10'dan fazla kullanΔ±cΔ± ekleyemezsiniz", + "components.locked_features.locked_drive_popup.title": "Az ΓΆnce sΓΌrüş sΔ±nΔ±rΔ±na ulaştΔ±nΔ±z", + "components.locked_features.locked_drive_popup.subtitle": "Ücretsiz sΓΌrΓΌmde yalnΔ±zca 6 GB depolayabilirsiniz.", + "general.resume": "Devam et", + "general.pause": "Duraklat", + "scenes.app.workspaces.welcome_page.no_workspace_subtitle": "HenΓΌz kimse sizi bir Γ§alışma alanΔ±na davet etmedi.", + "'": "'", + "login.create_account": "Hesap oluştur", + "login.login_error": "Giriş sΔ±rasΔ±nda hata", + "scenes.apps.messages.message.types.no_message_in_thread": "HenΓΌz kimse cevap vermedi.", + "\"": "\"", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.label": "VarsayΔ±lan Γ§alışma alanΔ±", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.description": "TΓΌm Γ§alışma alanΔ± kullanΔ±cΔ±larΔ±nΔ± otomatik olarak bu kanala davet et", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.title": "{{$1}} silmek ΓΌzeresiniz", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.alert_total_members": "{{$2}} iΓ§inde hala {{$1}} ΓΌyeniz var. Bu Γ§alışma alanΔ±nΔ± silebilmek iΓ§in tΓΌm ΓΌyeleri kaldΔ±rmalΔ±sΔ±nΔ±z.", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.checkbox": "Γ‡alışma alanΔ±mΔ±n tΓΌm mesajlarΔ±nΔ±n ve dosyalarΔ±nΔ±n silineceğini anlΔ±yorum.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.max_size": "Maksimum logo boyutu 5mb'dir", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.bad_format": "Bozuk biΓ§im, yalnΔ±zca png gif ve jpg'ye izin verilir", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.unknown": "Bilinmeyen hata", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.prefix": "Hata", + "scenes.app.channelsbar.currentuser.reset": "SΔ±fΔ±rla", + "components.rich_text_editor.plugins.suggestions.default_message.display_results": "KullanΔ±cΔ±larΔ± gΓΆrΓΌntΓΌlemek iΓ§in en az ΓΌΓ§ harf yazΔ±n", + "components.rich_text_editor.plugins.suggestions.default_message.no_user_found": "KullanΔ±cΔ± bulunamadΔ±", + "components.rich_text_editor.plugins.suggestions.default_message.no_emoji_found": "Emoji bulunamadΔ±", + "components.rich_text_editor.plugins.suggestions.default_message.no_command_found": "Komut bulunamadΔ±", + "scenes.app.messages.input.parts.is_writing.message.user_is_writing": "{{$1}} yazΔ±yor...", + "scenes.app.messages.input.parts.is_writing.message.users_are_writing": "{{$1}} ve {{$2}} yazΔ±yor...", + "scenes.app.messages.input.parts.is_writing.message.users_and_more_are_writing": "{{$1}}, {{$2}} ve {{$3}} daha fazla kullanΔ±cΔ± yazΔ±yor...", + "components.locked_features_components.locked_invite_alert.message_part_1": "Şirketiniz maksimum {{$1}} ΓΌye sΔ±nΔ±rΔ±na ulaştΔ±. LΓΌtfen ", + "components.locked_features_components.locked_invite_alert.message_link": "şirketini yΓΌkselt", + "components.locked_features_components.locked_invite_alert.message_part_2": " daha fazla ΓΌye davet etmek iΓ§in.", + "components.locked_features_components.locked_invite_alert.message_magic_link": " şirketinizin sahibi veya yΓΆneticisiyle iletişime geΓ§in.", + "views.client.popup.workspace_parameter.pages.workspace_members.link_to_console": "TΓΌm şirket ΓΌyelerimi konsolda gΓΆrΓΌn", + "scenes.app.popup.appsparameters.pages.app.private_key": "Γ–zel anahtar", + "scenes.app.popup.appsparameters.pages.amazing_app_description": "UygulamanΔ±zΔ± birkaΓ§ kelimeyle tanΔ±mlayΔ±n", + "scenes.app.popup.appsparameters.pages.application_creator.title": "Yeni entegrasyon", + "scenes.app.popup.appsparameters.pages.application_creator.checkbox": "Bu şirketin sahibi ve yΓΆneticilerinin bu uygulamayΔ± değiştirebileceğini ve yayΔ±nlayabileceğini anlΔ±yorum.", + "twake.application.access.title": "UygulamanΔ±z iΓ§in doğru kapsamlarΔ± seΓ§in.", + "twake.application.access.no_default_scopes_available'": "Bu entegrasyon herhangi bir {{$1}} erişimine sahip değil", + "scenes.app.popup.appsparameters.pages.application_editor.help_link": "Twake API belgeleri", + "scenes.app.popup.appsparameters.pages.application_editor.help_text": "BunlarΔ± nasΔ±l dolduracağınΔ±zΔ± bilmiyorsanΔ±z, adresine gidin. ", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed": "{{$1}} uygulamasΔ± başarΔ±yla kaldΔ±rΔ±ldΔ±!", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed_error": "{{$1}} uygulamasΔ± kaldΔ±rΔ±lΔ±rken hata oluştu!", + "scenes.app.popup.appsparameters.pages.application_editor.application_published": "BaşarΔ±yla {{$1}} uygulamasΔ±!", + "scenes.app.integrations_parameters.add_application": "Yeni entegrasyon", + "scenes.app.integrations_parameters.company_applications_table.more_menu.developer_settings": "Geliştirici ayarlarΔ±", + "components.rich_text_editor.plugins.suggestions.loading": "daha fazlasΔ±nΔ± arΔ±yorum", + "components.open_desktop_popup.subtitle": "Twake uygulamasΔ±nda aΓ§Δ±ldΔ±", + "components.open_desktop_popup.open_here_link": "Bunun yerine burada aΓ§", + "molecules.download_banner.title": "Twake'den en iyi şekilde yararlanΔ±n, şimdi masaΓΌstΓΌ uygulamasΔ±nΔ± indirin", + "molecules.download_banner.download_button": "MasaΓΌstΓΌ uygulamasΔ±nΔ± indirin", + "scenes.app.channelsbar.channel_copy_link": "Kanal bağlantΔ±sΔ±nΔ± kopyala", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.success.update": "BaşarΔ±yla gΓΌncellendi", + "components.searchpopup.no_results_for": "iΓ§in sonuΓ§ bulunamadΔ±", + "components.searchpopup.try_new_search": "Yeni bir arama deneyin", + "components.searchpopup.all": "Herşey", + "components.searchpopup.chats": "sohbetler", + "components.searchpopup.media": "medya", + "components.searchpopup.files": "Dosyalar", + "components.searchpopup.recent_chats": "son sohbetler", + "components.searchpopup.recent_media": "son medya", + "components.searchpopup.recent_files": "Son Dosyalar", + "components.searchpopup.recent_channels_and_contacts": "Son kanallar ve kişiler", + "components.searchpopup.header_title": "Arama", + "components.searchpopup.scope.company": "tΓΌm şirkette", + "components.searchpopup.scope.channel": "bu kanalda", + "components.searchpopup.channels": "Kanallar", + "components.searchpopup.messages": "Mesajlar", + "scenes.client.channelbar.channelmemberslist.search_invite": "KullanΔ±cΔ±larΔ± arayΔ±n ve bu kanala davet edin", + "scenes.client.channelbar.channelmemberslist.invite_email_button": "Kanala yalnΔ±zca misafir olarak ekle", + "scenes.client.join_public_channel": "Bu kanala katΔ±l", + "general.yes": "Evet", + "components.open_desktop_popup.open_here_link_forever": "UygulamayΔ± bir daha asla aΓ§mayΔ± denemeyin", + "components.channel_attachement_list.medias": "Medyalar", + "components.channel_attachement_list.files": "Dosyalar", + "components.channel_attachement_list.title": "Kanal dosyalarΔ± ve medyalar", + "components.searchpopup.start_search": "AramayΔ± başlatmak iΓ§in birkaΓ§ anahtar kelime girin.", + "components.searchpopup.see_more": "Daha fazla gΓΆr", + "scenes.client.channelbar.channelmemberslist.search_invite_notice": "Bu kanalda Γ§ok fazla ΓΌye yok. KullanΔ±cΔ±larΔ± şimdi e-posta veya adla arayΔ±n ve davet edin.", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace": "Üye olarak kanala ve Γ§alışma alanΔ±na ekle", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace_confirm": "{{$1}} ΓΌye olarak Γ§alışma alanΔ±na davet edilsin mi?", + "scenes.client.channelbar.channelmemberslist.search_invite_type_email": "E-posta ile davet etmek iΓ§in geΓ§erli bir adres yazΔ±n.", + "scenes.client.channelbar.channelmemberslist.pending_section": "Davet bekleyen kullanΔ±cΔ±lar", + "scenes.client.channelbar.channelmemberslist.members_section": "Bu kanaldaki kullanΔ±cΔ±lar", + "scenes.client.channelbar.channelmemberslist.not_members_section": "Bu kanalda olmayan kullanΔ±cΔ±lar", + "scenes.client.join_private_channel.info": "Bu kanalΔ±n bu iΓ§eriği kΔ±sΔ±tlΔ± veya mevcut değil. Davet edilmek iΓ§in lΓΌtfen bu kanalΔ±n bir ΓΌyesiyle iletişime geΓ§in.", + "scenes.client.join_public_channel.info": "Bu doğrudan kanalΔ±n ΓΌyesi değilsiniz. TartışmayΔ± şimdi başlatmak iΓ§in bu düğmeye tΔ±klayΔ±n.", + "general.no": "Numara", + "components.channel_attachement_list.nothing_found": "Burada henΓΌz bir şey yok", + "molecules.message_quote.deleted": "Bu mesaj silindi", + "scenes.apps.messages.jump": "Mesaja atla", + "components.channel_attachement_list.open": "Galeriyi aΓ§", + "scenes.apps.account.assistant.description": "Twake asistanΔ±, Twake'deki gΓΌnlΓΌk Γ§alışmalarΔ±nΔ±zΔ± anlamlandΔ±rabilir ve gΓΌn boyunca akΔ±llΔ± kΔ±sayollar ve eylemler sağlayabilir. Asistan, https://workathome.linagora.com/ Work@Home girişiminin bir parΓ§asΔ±dΔ±r ve şu anda yalnΔ±zca Linagora şirketinde test edilmektedir ve âğrenme aşamasΔ±ndadΔ±r. Bu, gelecekteki asistan ΓΆzelliğimizi eğitmek iΓ§in Twake kullanΔ±m verilerini gΓΆndereceğimiz anlamΔ±na geliyor.", + "scenes.apps.account.assistant.share.nothing": "Asistanla hiΓ§bir şey paylaşmayΔ±n (asistanΔ± devre dışı bΔ±rakΔ±n)", + "scenes.apps.account.assistant.share.all": "Mesajlar ve dosya iΓ§erikleri dahil her şeyi paylaşın", + "scenes.apps.account.assistant.share.metadata": "Meta verileri paylaşın ancak iΓ§eriği değil", + "scenes.apps.account.assistant.success": "Tercihleriniz başarΔ±yla gΓΌncellendi.", + "scenes.apps.account.on_console": "Global hesap tercihlerinizi dΓΌzenlemek iΓ§in Konsola Git'e tΔ±klayΔ±n.", + "scenes.apps.account.assistant.title": "asistan", + "components.message_seen_by.title": "MesajΔ± gΓΆren kullanΔ±cΔ±lar", + "components.message_seen_by.none_seen_it": "HenΓΌz kimse mesajΔ± gΓΆrmedi", + "components.message_seen_by.btn": "Bilgi", + "molecules.quoted_content.attachements": "{{$1}} ekleri", + "scenes.apps.messages.message.user_deactivated": "Devre dışı bΔ±rakΔ±lmış bir hesabΔ±n arşivlerini gΓΆrΓΌntΓΌlΓΌyorsunuz", + "general.user.deactivated": "KullanΔ±cΔ± artΔ±k bu şirkette değil", + "general.user.connected": "Γ‡evrimiΓ§i", + "scenes.app.popup.userparameter.pages.email_notif_delay_never": "HiΓ§bir zaman", + "scenes.app.popup.userparameter.pages.email_notif_delay_quarter_hour": "15 dakika", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_day": "1 gΓΌn", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_hour": "1 saat", + "scenes.app.popup.userparameter.pages.notification_sound.defaut": "VarsayΔ±lan", + "scenes.app.popup.userparameter.pages.notification_sound.none": "HiΓ§biri", + "scenes.client.channelbar.readonly_channel.checkbox": "Yazma yeteneğini kΔ±sΔ±tla", + "scenes.apps.messages.message.forward": "Δ°leri", + "scenes.apps.messages.message.forward.title": "MesajΔ± iletmek", + "scenes.apps.messages.message.forward.comment": "Mesaj Ekle", + "scenes.apps.messages.message.forward.confirm": "$1 kanala gΓΆnder", + "scenes.apps.messages.message.forward.send": "Δ°leti iletildi", + "components.channelselector.title": "KanallarΔ± seΓ§in", + "components.channelselector.confirm": "$1 kanal(lar) seΓ§in", + "components.channelselector.search": "KanallarΔ± ve tartışmalarΔ± arayΔ±n", + "scenes.app.channelsbar.channel_information.description": "Kanal aΓ§Δ±klamasΔ±", + "scenes.app.channelsbar.channel_information.description.placeholder": "Kanal aΓ§Δ±klamasΔ±, işaretlemeyi kullanabilirsiniz.", + "scenes.app.channelsbar.channel_access": "Kanal erişimi", + "scenes.app.channelsbar.channel_access.save": "Erişim ayarlarΔ±nΔ± kaydet", + "scenes.app.channelsbar.channel_access.readonly": "Salt okunur kanal", + "scenes.app.channelsbar.channel_access.readonly.info": "ModeratΓΆrler, yΓΆneticiler ve sahiplerle yazmayΔ± kΔ±sΔ±tlayΔ±n.", + "scenes.app.channelsbar.channel_access.visibility": "Kamu gΓΆrΓΌnΓΌrlüğü", + "scenes.app.channelsbar.channel_access.visibility.info": "Şirket misafirleri dışında herkes katΔ±labilir.", + "scenes.app.channelsbar.channel_access.default": "Otomatik katΔ±lma", + "scenes.app.channelsbar.channel_access.default.info": "Yeni ΓΌyeler buraya otomatik olarak eklenecektir.", + "scenes.app.channelsbar.channel_information": "Kanal bilgilerini dΓΌzenle", + "scenes.app.channelsbar.channel_information.logo.add": "Resmi yΓΌkle", + "scenes.app.channelsbar.channel_information.logo.remove": "Resmi kaldΔ±r", + "scenes.app.channelsbar.channel_information.name": "Kanal ismi", + "scenes.app.channelsbar.channel_information.group": "Kanal grubu", + "scenes.app.channelsbar.channel_information.group.none": "SeΓ§ili değil", + "scenes.app.channelsbar.channel_information.group.new": "Yeni bir grup oluştur", + "scenes.app.channelsbar.channel_information.group.save": "Kanal grubunu $1 olarak ayarla", + "scenes.app.channelsbar.channel_information.group.save_none": "Kanal grubunu ayarlama", + "scenes.app.channelsbar.channel_information.save": "Bilgileri kaydet", + "scenes.client.channelbar.channelmemberslist.invite_to_workspace": "{{$1}}'i Γ§alışma alanΔ±na davet edin ➑", + "components.invitation.reached_limit.text": "şirketinizdeki maksimum kullanΔ±cΔ± sayΔ±sΔ±na ulaştΔ±nΔ±z. Aboneliğinizi artΔ±rΔ±n veya bu kullanΔ±cΔ±larΔ± misafir olarak ekleyin", + "components.invitation.allow_anyone_by_email.text": "@{{$1}} e-posta adresi olan herkesin bu Γ§alışma alanΔ±na katΔ±lmasΔ±na izin verin", + "components.invitation.invitation_channels.button": "Kanallara davet et", + "components.invitation.invitation_input_list.add": "Ekle", + "components.invitation.invitation_input_list.member": "Üye", + "components.invitation.invitation_input_list.guest": "Misafir", + "components.invitation.invitation_input_list.placeholder": "Bir e-posta yazmaya başlayΔ±n", + "components.invitation.invitation_sent.title": "Davetiyeler başarΔ±yla gΓΆnderildi", + "components.invitation.invitation_sent.subtitle_status": "Davet durumunu şurada takip edebilirsiniz:", + "components.invitation.invitation_sent.subtitle_location": "Γ‡alışma alanΔ± ayarlarΔ± > Üye yΓΆnetimi", + "components.invitation.invitation_sent.link": "Davet durumunu kontrol et", + "components.invitation.invitation_sent.button": "Daha fazla davetiye gΓΆnder", + "components.invitation.invitation_target.invite_as_guests": "Herkesi misafir olarak davet et", + "components.invitation.invitation_target.invite_as_members": "Herkesi ΓΌye olarak davet edin", + "components.invitation.invitation_target.channels_button": "Davet edilecek kanallar", + "components.invitation.workspace_link.text": "Γ‡alışma alanΔ± davet bağlantΔ±sΔ±", + "components.invitation.workspace_link.button": "kopyala", + "components.invitation.title": "insanlarΔ± {{$1}}'e davet et", + "components.invitation.bulk_invitation": "toplu davet", + "components.invitation.button": "davetiye gΓΆnder", + "scenes.client.readonly.info": "Bu kanal salt okunur bir beslemedir ancak ileti dizilerine yorum yapabilirsiniz.", + "scenes.app.channelsbar.channel_information.group.title": "Kanal gruplarΔ±", + "components.invitation.custom_role_invitation": "klasik davetiye", + "components.invitation.link": "BağlantΔ±" +} diff --git a/twake/frontend/public/locales/vi.json b/twake/frontend/public/locales/vi.json new file mode 100644 index 00000000..2b0bedbe --- /dev/null +++ b/twake/frontend/public/locales/vi.json @@ -0,0 +1,1008 @@ +{ + "general.connexion_status.connecting": "Đang kαΊΏt nα»‘i lαΊ‘i…", + "general.connexion_status.connected": "BαΊ‘n Δ‘ang trα»±c tuyαΊΏn", + "general.connexion_status.disconnected": "BαΊ‘n Δ‘ang ngoαΊ‘i tuyαΊΏn", + "general.add": "ThΓͺm", + "general.remove": "XΓ³a", + "general.update": "CαΊ­p nhαΊ­t", + "general.send": "Gα»­i tin nhαΊ―n", + "general.help.documentation": "TΓ i liệu", + "general.help.support": "Hα»— trợ", + "general.help": "Hα»— trợ", + "general.unarchive": "Bỏ lΖ°u trα»―", + "general.archive": "LΖ°u trα»―", + "general.delete": "XΓ³a", + "general.confirm": "XΓ‘c nhαΊ­n", + "general.back": "Quay lαΊ‘i", + "general.continue": "TiαΊΏp tα»₯c", + "general.edit": "Sα»­a", + "general.create": "TαΊ‘o", + "general.cancel": "Hα»§y", + "general.save": "LΖ°u", + "scenes.app.workspaces.create_company.group_data.group_size.50_100": "50 - 99 người dΓΉng", + "general.retry": "Thα»­ lαΊ‘i", + "scenes.app.workspaces.create_company.group_data.group_size.10_50": "11 - 49 người dΓΉng", + "general.close": "Đóng", + "scenes.app.side_app.messages_thread_title": "{{$1}} β€’ Luα»“ng tin nhαΊ―n", + "scenes.app.workspaces.create_company.group_data": "CαΊ₯u hΓ¬nh nhΓ³m mα»›i cα»§a bαΊ‘n", + "scenes.app.workspaces.create_company.group_data.group_main_activity.chemistry": "HoΓ‘ học", + "scenes.app.workspaces.create_company.group_data.group_main_activity": "HoαΊ‘t Δ‘α»™ng chΓ­nh", + "scenes.app.workspaces.create_company.group_data.group_type.society_club_charity": "XΓ£ hα»™i, cΓ’u lαΊ‘c bα»™ hoαΊ·c tα»• chα»©c tα»« thiện", + "application.load.longer": "MΓ‘y chα»§ cαΊ§n thΓͺm thời gian để phαΊ£n hα»“i, vui lΓ²ng chờ hoαΊ·c tαΊ£i lαΊ‘i trang ...", + "scenes.app.workspaces.create_company.group_data.group_size.5000_more": "Nhiều hΖ‘n 5000 người dΓΉng", + "scenes.app.workspaces.create_company.group_data.group_main_activity.food": "Đồ Δƒn", + "scenes.app.workspaces.create_company.group_data.group_main_activity.bank": "NgΓ’n hΓ ng / BαΊ£o hiểm", + "scenes.app.workspaces.create_company.group_data.group_type": "LoαΊ‘i nhΓ³m", + "scenes.app.workspaces.create_company.group_data.group_type.company": "CΓ΄ng ty hoαΊ·c bα»™ phαΊ­n cΓ΄ng ty", + "scenes.app.workspaces.create_company.group_data.group_type.public_organization": "Tα»• chα»©c cΓ΄ng cα»™ng", + "scenes.app.workspaces.create_company.group_data.group_type.university_school": "Đẑi học hoαΊ·c trường học", + "scenes.app.workspaces.create_company.group_data.group_type.other_group": "KhΓ‘c", + "scenes.app.workspaces.create_company.group_data.group_size": "Quy mΓ΄ nhΓ³m", + "scenes.app.workspaces.create_company.group_data.group_size.less_3": "Ít hΖ‘n 4 người dΓΉng", + "scenes.app.workspaces.create_company.group_data.group_size.4_10": "4 - 10 người dΓΉng", + "scenes.app.workspaces.create_company.group_data.group_size.100_500": "100 - 499 người dΓΉng", + "scenes.app.workspaces.create_company.group_data.group_size.500_1000": "500 - 999 người dΓΉng", + "scenes.app.workspaces.create_company.group_data.group_size.1000_5000": "1000 - 4999 người dΓΉng", + "scenes.app.workspaces.create_company.group_data.group_main_activity.construction_building": "VαΊ­t liệu xΓ’y dα»±ng", + "scenes.app.workspaces.create_company.group_data.group_main_activity.real_estate": "Địa α»‘c", + "scenes.app.workspaces.create_company.group_data.group_main_activity.materials": "VαΊ­t liệu", + "scenes.app.workspaces.create_company.group_data.group_main_activity.trade_commerce_distribution": "ThΖ°Ζ‘ng mαΊ‘i / ThΖ°Ζ‘ng mαΊ‘i / PhΓ’n phα»‘i", + "scenes.app.workspaces.create_company.group_data.group_main_activity.publishing_communication_multimedia": "XuαΊ₯t bαΊ£n / Truyền thΓ΄ng / Đa phΖ°Ζ‘ng tiện", + "scenes.app.workspaces.create_company.group_data.group_main_activity.electronics_electricity_energy": "Điện tα»­ / Điện / NΔƒng lượng", + "scenes.app.workspaces.create_company.group_data.group_main_activity.studies_and_advice": "Học vΓ  lời khuyΓͺn", + "scenes.app.workspaces.create_company.group_data.group_main_activity.printing_paper": "In αΊ₯n / GiαΊ₯y", + "scenes.apps.calendar.calendar.week_btn": "TuαΊ§n", + "scenes.app.header.alt_notifications": "ThΓ΄ng bΓ‘o", + "scenes.apps.calendar.event_edition.checkbox_all_day": "CαΊ£ ngΓ y", + "scenes.apps.calendar.event_view.article_until": "tα»›i", + "scenes.apps.calendar.calendar_modal.participants": "Người tham dα»±", + "scenes.apps.calendar.calendar_modal.placeholder": "TΓͺn", + "scenes.apps.calendar.left.calendars": "Lα»‹ch", + "scenes.apps.drive.left.search": "TΓ¬m kiαΊΏm", + "components.user_picker.modal_no_result": "KhΓ΄ng tΓ¬m thαΊ₯y kαΊΏt quαΊ£", + "scenes.apps.tasks.task.assignees": "Người được giao", + "scenes.app.workspaces.welcome_page.other_mail_title": "ThΖ° phα»₯", + "scenes.app.workspaces.create_company.group_data.group_main_activity.business_services": "Dα»‹ch vα»₯ kinh doanh", + "scenes.app.workspaces.create_company.group_data.group_main_activity.entertainment": "GiαΊ£i trΓ­", + "scenes.app.workspaces.create_company.group_data.group_main_activity.textile_clothing_shoes": "Dệt may / QuαΊ§n Γ‘o / GiΓ y", + "scenes.apps.account.languages.text": "Thay Δ‘α»•i ngΓ΄n ngα»―.", + "scenes.app.workspaces.create_company.group_data.group_main_activity.machinery_automotive": "MΓ‘y mΓ³c / Γ” tΓ΄", + "scenes.apps.messages.chatbox.chat.delete_message": "XΓ³a tin nhαΊ―n nΓ y", + "scenes.apps.messages.chatbox.chat.delete_message_btn": "XΓ³a tinh nhαΊ―n", + "scenes.apps.messages.left_bar.stream.notifications.all": "BαΊ₯t kΓ¬ tin nhαΊ―n nΓ o", + "scenes.apps.account.account.main_email": "ThΖ° Δ‘iện tα»­ chΓ­nh", + "scenes.apps.account.account.email_add": "ThΓͺm thΖ° Δ‘iện tα»­ mα»›i", + "scenes.apps.account.notifications.title": "ThΓ΄ng bΓ‘o", + "scenes.app.channelsbar.channelsworkspace.no_channel": "BαΊ‘n chΖ°a tham gia kΓͺnh nΓ o cαΊ£", + "scenes.app.channelsbar.company_invitation_alert_subtitle": "BαΊ‘n cΓ³ thể nhαΊ­p liệu cΓ‘c kΓͺnh vΓ o hệ thα»‘ng để quαΊ£n lΓ½ bαΊ±ng việc nhαΊ₯n vΓ o khung nΓ y.", + "scenes.apps.account.account.make_main": "Đặt lΓ m chΓ­nh", + "scenes.apps.calendar.modals.details_title": "Chi tiαΊΏt", + "scenes.apps.calendar.modals.event_adresse_placeholder": "Địa chỉ", + "scenes.apps.calendar.modals.event_description_placeholder": "MΓ΄ tαΊ£", + "scenes.apps.messages.message.cancel_button": "Huα»·", + "scenes.apps.messages.message.modify_button": "Sα»­a", + "scenes.app.channelsbar.currentuser.change_my_status": "Thay Δ‘α»•i trαΊ‘ng thΓ‘i cα»§a tΓ΄i", + "scenes.login.create_account.step_3_mail_sent": "ChΓΊng tΓ΄i Δ‘Γ£ gα»­i cho bαΊ‘n mα»™ thΖ° kΓ­ch hoαΊ‘t tΓ i khoαΊ£n.", + "scenes.app.workspaces.create_company.importations.title_2": "Khỏi lo, bαΊ‘n cΓ³ thể lΓ m việc nΓ y sau!", + "components.calendar.repetition.annually_on": "HΓ ng nΔƒng vΓ o {{$1}}", + "scenes.apps.calendar.month_option": "ThΓ‘ng", + "general.user.role.company.guest": "KhΓ‘ch", + "scenes.apps.tasks.no_connectors_menu_text": "BαΊ‘n khΓ΄ng cΓ³ liΓͺn kαΊΏt nΓ o kαΊΏt nα»‘i vα»›i vα»›i lα»‹ch.", + "scenes.apps.tasks.new_board.title": "BαΊ£ng mα»›i", + "scenes.apps.messages.left_bar.stream.notifications.me": "{{$1}} chỉ", + "scenes.apps.parameters.group_sections.apps": "Ứng dα»₯ng", + "scenes.apps.account.account.emails": "ThΖ° Δ‘iện tα»­", + "scenes.app.workspaces.create_company.group_data.group_main_activity.research": "NghiΓͺn cα»©u", + "scenes.login.home.create_account": "TαΊ‘o mα»™t tΓ i khoαΊ£n mα»›i", + "scenes.login.create_account.password": "MαΊ­t khαΊ©u", + "scenes.app.workspaces.create_company.company_name.placeholder": "TΓͺn cΓ΄ng ty", + "scenes.login.create_account.step_2_subtitle_b": "Sα»‘ Δ‘iện thoαΊ‘i cα»§a bαΊ‘n được bαΊ£o mαΊ­t.", + "scenes.app.workspaces.create_company.default_workspace_name": "ChΓ­nh", + "scenes.app.workspaces.create_company.company_name.title_1": "Để bαΊ―t Δ‘αΊ§u,", + "scenes.app.workspaces.welcome_page.added_to_company": "BαΊ‘n Δ‘Γ£ được mời tham gia ", + "scenes.app.workspaces.welcome_page.create_my_company": "TαΊ‘o cΓ΄ng ty cα»§a tΓ΄i", + "scenes.app.workspaces.welcome_page.ready_to_work": "BαΊ‘n cΓ³ thể bαΊ―t Δ‘αΊ§u cΓ΄ng việc ngay bΓ’y giờ.", + "scenes.app.workspaces.welcome_page.add_new_email": "ThΓͺm thΖ°", + "scenes.app.workspaces.welcome_page.done": "TΓ΄i Δ‘Γ£ xong", + "scenes.app.workspaces.welcome_page.try_again": "Thα»­ lαΊ‘i", + "scenes.app.workspaces.welcome_page.twake_team": "Twake", + "scenes.app.workspaces.welcome_page.code_verification": "MΓ£ xΓ‘c nhαΊ­n", + "app.name.twake_tasks": "CΓ΄ng việc", + "components.calendar.repetition.everyday": "HΓ ng ngΓ y", + "scenes.apps.account.thumbnail.max_weight": "Lα»›n nhαΊ₯t lΓ  5MB", + "components.calendar.repetition.weeks": "tuαΊ§n", + "scenes.apps.account.identity.description": "Thay tΓͺn, họ vΓ  αΊ£nh Δ‘αΊ‘i diện để người dΓΉng Twake thαΊ₯y bαΊ‘n.", + "components.calendar.repetition.custom": "TΓΉy chọn...", + "components.calendar.repetition.on": "VΓ o", + "components.calendar.repetition.after": "Sau", + "components.calendar.repetition.days": "ngΓ y", + "components.calendar.repetition.years": "nΔƒm", + "components.calendar.repetition.occurrence": "LαΊ·p lαΊ‘i", + "scenes.app.channelsbar.channelsuser.private_messages": "TΓ­n nhαΊ―n trα»±c tiαΊΏp", + "scenes.app.channelsbar.channelsworkspace.channel_title.favorite": "YÊU THÍCH", + "scenes.app.channelsbar.channelsworkspace.create_channel": "TαΊ‘o mα»™t kΓͺnh", + "scenes.app.channelsbar.channelsworkspace.channel_title": "KÊNH", + "scenes.app.channelsbar.channel_leaving": "Ra khỏi kΓͺnh", + "scenes.apps.parameters.workspace_sections.members.members": "Người dΓΉng", + "components.application.messages": "Tin nhαΊ―n", + "scenes.apps.calendar.event_edition.deadline_tag": "HαΊ‘n cuα»‘i", + "scenes.apps.drive.navigators.new_file": "Tệp mα»›i", + "scenes.apps.drive.right_preview.operations_delete": "Chuyển vΓ o thΓΉng rΓ‘c", + "scenes.apps.drive.right_preview.public_link": "LiΓͺn kαΊΏt cΓ΄ng khai", + "scenes.apps.messages.left_bar.stream.add_to_favorites": "ThΓͺm vΓ o yΓͺu thΓ­ch", + "scenes.apps.account.notifications.privacy_subtitle": "ChΓ­nh sΓ‘ch", + "scenes.app.mainview.quick_search_placeholder": "TΓ¬m nhanh", + "components.emoji_picker.input_search_placeholder": "TΓ¬m kiαΊΏm", + "scenes.apps.parameters.workspace_sections.members.pending": "ThΖ° Δ‘ang đợi", + "scenes.login.create_account.lastname": "Họ", + "app.name.twake_drive": "TΓ i liệu", + "scenes.login.forgot_password.password": "MαΊ­t khαΊ©u", + "scenes.apps.account.account.emails.description": "QuαΊ£n lΓ½ cΓ‘c thΖ° Δ‘iện tα»­ khΓ‘c nhau.", + "scenes.apps.tasks.new_board.edit_title": "Chỉnh sα»­a bαΊ£ng", + "scenes.app.workspaces.create_company.group_data.group_main_activity.transport_logistics": "VαΊ­n tαΊ£i / Logistics", + "scenes.app.workspaces.create_company.group_data.group_main_activity.education": "GiΓ‘o dα»₯c", + "components.users_picker.add_me": "ThΓͺm tΓ΄i", + "scenes.app.workspaces.create_company.invitations.title": "CΓ i Δ‘αΊ·t khΓ΄ng gian lΓ m việc.", + "scenes.app.header.disconnected": "BαΊ‘n Δ‘ang ngoαΊ‘i tuyαΊΏn", + "scenes.apps.calendar.calendar.list_btn": "Danh sΓ‘ch", + "scenes.apps.calendar.event_edition.title_confidentiality": "RiΓͺng tΖ°", + "scenes.apps.drive.navigators.navigator_content.directory_name": "TΓͺn thΖ° mα»₯c", + "scenes.apps.drive.preview_bloc.operations_download": "TαΊ£i về", + "scenes.apps.drive.preview_bloc.error_file": "KhΓ΄ng tΓ¬m thαΊ₯y tαΊ­p tin", + "scenes.apps.drive.right_preview.operations_restore": "KhΓ΄i phα»₯c", + "scenes.apps.messages.messages": "Tin nhαΊ―n", + "scenes.apps.messages.left_bar.stream.remove_from_favorites": "XΓ³a khỏi danh mα»₯c yΓͺu thΓ­ch", + "scenes.apps.messages.left_bar.stream.notifications": "ThΓ΄ng bΓ‘o...", + "scenes.apps.parameters.workspace_sections.workspace": "KhΓ΄ng gian lΓ m việc", + "scenes.apps.parameters.workspace_sections.members": "Người tham dα»±", + "scenes.apps.parameters.group_sections.workspaces": "KhΓ΄ng gian lΓ m việc", + "scenes.apps.account.account.menu_title": "TΓ i khoαΊ£n", + "scenes.apps.account.languages.menu_title": "NgΓ΄n ngα»―", + "scenes.apps.account.account.firstname": "TΓͺn", + "scenes.apps.account.account.lastname": "Họ", + "scenes.apps.account.account.username": "TΓͺn người dΓΉng", + "scenes.apps.account.account.change_username": "Thay Δ‘α»•i tΓͺn người dΓΉng duy nhαΊ₯t cα»§a bαΊ‘n.", + "scenes.apps.account.account.email_add_modal.invalid_code": "MΓ£ nΓ y khΓ΄ng hợp lệ", + "scenes.apps.account.account.password_modal.bad_old_password": "MαΊ­t khαΊ©u cΕ© khΓ΄ng Δ‘ΓΊng.", + "scenes.apps.account.account.password_modal.bad_password": "MαΊ­t khαΊ©u cα»§a bαΊ‘n khΓ΄ng khα»›p hoαΊ·c quΓ‘ ngαΊ―n. Vui lΓ²ng nhαΊ­p mαΊ­t khαΊ©u cΓ³ Γ­t nhαΊ₯t 8 kΓ½ tα»±.", + "scenes.apps.account.account.logout": "Đăng xuαΊ₯t", + "scenes.apps.account.notifications.keywords_subtitle": "Tα»« khΓ³a", + "scenes.apps.account.notifications.keywords_placeholder": "dev, wifi, code, ...", + "scenes.apps.parameters.workspace_sections.members.invite": "Mời người dΓΉng mα»›i", + "scenes.apps.parameters.workspace_sections.members.invite_btn": "ThΓͺm người dΓΉng", + "scenes.apps.tasks.boards": "BαΊ£ng", + "scenes.apps.tasks.connectors_menu": "KαΊΏt nα»‘i ...", + "scenes.apps.tasks.connectors_search_menu": "TΓ¬m kiαΊΏm kαΊΏt nα»‘i ...", + "scenes.apps.tasks.unconfigured_tab": "Tab nΓ y chΖ°a được cαΊ₯u hΓ¬nh", + "scenes.apps.tasks.choose_board_button": "Chọn mα»™t bαΊ£ng", + "scenes.apps.tasks.task": "CΓ΄ng việc", + "scenes.apps.tasks.no_tasks": "KhΓ΄ng cΓ³ cΓ΄ng việc nΓ o", + "scenes.apps.tasks.task_status.current": "Hiện tαΊ‘i", + "scenes.apps.tasks.task_status.done": "HoΓ n thΓ nh", + "scenes.apps.tasks.task.edit.dates": "NgΓ y", + "scenes.apps.tasks.list_modal.modify_list": "Chỉnh sα»­a danh sΓ‘ch", + "scenes.login.create_account.too_short_password": "MαΊ­t khαΊ©u phαΊ£i Γ­t nhαΊ₯t 8 kΓ½ tα»± trở lΓͺn.", + "scenes.login.forgot_password.email_to_recover": "ThΖ° để lαΊ₯y lαΊ‘i tΓ i khoαΊ£n", + "scenes.login.forgot_password.mail_doesnt_exist": "ThΖ° nΓ y khΓ΄ng tα»“n tαΊ‘i", + "scenes.login.forgot_password.text2": "BαΊ‘n sαΊ½ nhαΊ­n được mΓ£ sα»‘ bαΊ£o về gα»“m 9 chα»― sα»‘. HΓ£y Δ‘iền mΓ£ sα»‘ vΓ o Δ‘Γ’y vΓ  tiαΊΏp tα»₯c.", + "scenes.login.forgot_password.invalid_code": "MΓ£ sα»‘ khΓ΄ng Δ‘ΓΊng.", + "scenes.login.forgot_password.text3": "NhαΊ­p mαΊ­t khαΊ©u mα»›i cho tΓ i khoαΊ£n cα»§a bαΊ‘n.", + "scenes.login.forgot_password.password_dont_match": "MαΊ­t khαΊ©u khΓ΄ng khα»›p hoαΊ·c quΓ‘ ngαΊ―n. HΓ£y ghΓ΅ lαΊ‘i mαΊ­t khαΊ©u Γ­t nhαΊ₯t 8 kΓ½ tα»±.", + "scenes.login.home.title": "Đăng nhαΊ­p vΓ o Twake", + "scenes.login.home.subtitle": "ChΓ o mα»«ng trở lαΊ‘i", + "scenes.login.home.email": "ThΖ°", + "scenes.login.home.unable_to_connect": "ThΓ΄ng tin Δ‘Δƒng nhαΊ­p sai", + "scenes.login.home.login_btn": "Đăng nhαΊ­p", + "scenes.login.home.lost_password": "QuΓͺn mαΊ­t khαΊ©u?", + "scenes.login.create_account.step_1_subtitle": "NΓ³ lΓ  Δ‘Ζ‘n giαΊ£n β€” chΓΊng tΓ΄i chỉ cαΊ§n mα»™t sα»‘ thΓ΄ng tin.", + "scenes.login.create_account.step_2_subtitle_a": "VΓ  tΓͺn Δ‘αΊ§y Δ‘α»§ để mọi người biαΊΏt gọi bαΊ‘n thαΊΏ nΓ o.", + "scenes.app.workspaces.welcome_page.welcome_header": "ChΓ o mα»«ng Δ‘αΊΏn vα»›i Twake!", + "scenes.app.workspaces.welcome_page.add_secondary_emails_comment": "BαΊ‘n cΓ³ thể liΓͺn kαΊΏt nhiều thΖ° vΓ o tΓ i khoαΊ£n; chỉ mα»™t thΖ° được dΓΉng để gα»­i thΓ΄ng bΓ‘o.", + "scenes.app.workspaces.welcome_page.main_mail_title": "ThΖ° chΓ­nh", + "scenes.app.workspaces.welcome_page.new_email": "ThΓͺm thΖ° phα»₯", + "scenes.app.workspaces.welcome_page.we_sent_you_mail": "ChΓΊng tΓ΄i gα»­i mΓ£ xΓ‘c nhαΊ­n qua {{$1}}", + "scenes.login.forgot_password.finished": "MαΊ­t khαΊ©u cα»§a bαΊ‘n Δ‘Γ£ thay Δ‘α»•i thΓ nh cΓ΄ng.", + "scenes.apps.account.account.description_main": "ThΖ° chΓ­nh sαΊ½ được gα»­i thΓ΄ng bΓ‘o tα»« Twake. ThΖ° phα»₯ được tα»± Δ‘α»™ng mời vΓ o khΓ΄ng gian lΓ m việc khi bαΊ‘n dΓΉng.", + "scenes.apps.account.identity": "Danh tΓ­nh", + "general.open": "Mở", + "app.name.twake_calendar": "Lα»‹ch", + "components.calendar.repetition.monthly_on": "HΓ ng thΓ‘ng vΓ o {{$1}} {{$2}}", + "components.calendar.repetition.repeat": "LαΊ·p lαΊ‘i mα»—i", + "components.calendar.repetition.ends": "KαΊΏt thΓΊc vΓ o", + "components.calendar.repetition.never": "KhΓ΄ng bao giờ", + "components.calendar.repetition.months": "thΓ‘ng", + "components.calendar.repetition.custom_recurrence": "TΓΉy chọn lαΊ·p", + "components.calendar.repetition.repeat_on": "LαΊ·p lαΊ‘i vΓ o", + "scenes.app.channelsbar.currentuser.add_apps": "TΓ¬m α»©ng dα»₯ng", + "scenes.app.channelsbar.currentuser.collaborateurs": "Người dΓΉng", + "scenes.app.channelsbar.currentuser.create_workspace_page": "TαΊ‘o khΓ΄ng gian lΓ m việc", + "scenes.app.channelsbar.currentuser.workspace_parameters": "ThiαΊΏt Δ‘αΊ·t khΓ΄ng gian lΓ m việc", + "scenes.app.channelsbar.currentuser.update": "CαΊ­p nhαΊ­t", + "scenes.app.channelsbar.currentuser.disable_notifications": "VΓ΄ hiệu hΓ³a", + "scenes.app.channelsbar.currentuser.disabling_notifications": "VΓ΄ hiệu trong 1 tiαΊΏng", + "scenes.app.channelsbar.currentuser.company_messages_counter_link": "Hiện thΓͺm gΓ³i", + "scenes.app.channelsbar.channelsuser.new_private_discussion": "ThαΊ£o luαΊ­n riΓͺng tΖ° mα»›i", + "scenes.app.channelsbar.guest_management": "QuαΊ£n lΓ½ khΓ‘ch", + "scenes.app.channelsbar.company_invitation_alert_title": "BαΊ‘n được mời vΓ o cΓ΄ng ty ", + "scenes.app.channelsbar.initial_instructions_tutorial": "Chọn tΓͺn, họ vΓ  mα»™t αΊ£nh Δ‘αΊ‘i diện.", + "scenes.app.channelsbar.sending_message_instruction": "Gα»­i tin nhαΊ―n Δ‘αΊ§u tiΓͺn vΓ o thαΊ£o luαΊ­n", + "scenes.app.channelsbar.welcoming_message_subtitle": "Trở thΓ nh Twake chuyΓͺn nghiệp chỉ cαΊ§n mα»™t vΓ i nhαΊ₯n!", + "scenes.app.mainview.instruction_current_tab": "BαΊ―t Δ‘αΊ§u bαΊ±ng việc chọn kΓͺn bΓͺn phΓ­a trΓ‘i.", + "scenes.app.mainview.tabs.no_connected_connectors_for_channel": "BαΊ‘n khΓ΄ng cΓ³ kαΊΏt nα»‘i nΓ o Δ‘αΊΏn kΓͺnh.", + "scenes.app.mainview.tabs.searching_connectors": "TΓ¬m kiαΊΏm kαΊΏt nα»‘i...", + "scenes.app.popup.appsparameters.pages._app_identity": "Định danh α»©ng dα»₯ng", + "scenes.app.popup.appsparameters.pages.go_back": "Trở lαΊ‘i", + "scenes.app.popup.workspaceparameter.pages.description": "MΓ΄ tαΊ£", + "scenes.app.header.disconnected.reload": "TαΊ£i lαΊ‘i", + "scenes.apps.account.title": "ThΓ΄ng sα»‘ tΓ i khoαΊ£n", + "scenes.apps.account.notifications.devices_option_ever": "LuΓ΄n gα»­i thΓ΄ng bΓ‘o tα»›i tΓ΄i", + "scenes.app.workspaces.create_company.group_data.group_main_activity.other": "KhΓ‘c", + "scenes.apps.account.notifications.disturb_option_b": " vΓ  ", + "scenes.apps.account.account.password": "MαΊ­t khαΊ©u", + "scenes.apps.account.account.password_modal.old_password": "MαΊ­t khαΊ©u hiện tαΊ‘i", + "scenes.apps.account.account.password_modal.password": "MαΊ­t khαΊ©u mα»›i", + "scenes.apps.tasks.task.description": "MΓ΄ tαΊ£", + "scenes.login.forgot_password.password2": "XΓ‘c nhαΊ­n mαΊ­t khαΊ©u", + "scenes.login.home.password": "MαΊ­t khαΊ©u", + "scenes.app.popup.appsparameters.pages.description_label": "MΓ΄ tαΊ£", + "scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button": "Mời người dΓΉng", + "scenes.apps.drive.create_folder_button": "TαΊ‘o", + "scenes.apps.messages.message.remove_button": "XΓ³a bỏ", + "components.add_mails_workspace.button": "BαΊ―t Δ‘αΊ§u sα»­ dα»₯ng Twake", + "general.user.role.company.member": "ThΓ nh viΓͺn", + "components.locked_features.locked_history_banner.button": "TΓ¬m hiểu thΓͺm", + "components.locked_features.locked_guests_popup.learn_more_button": "TΓ¬m hiểu thΓͺm", + "scenes.app.popup.workspaceparameter.pages.table_title": "TΓͺn", + "general.email": "ThΖ° Δ‘iện tα»­", + "scenes.app.integrations_parameters.applications_table.name": "TΓͺn", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.description_item": "MΓ΄ tαΊ£", + "scenes.app.integrations_parameters.company_applications_table.name": "TΓͺn", + "scenes.app.workspaces.create_company.group_data.group_main_activity.it_telecom": "IT / Viα»…n thΓ΄ng", + "scenes.apps.messages.left_bar.stream.notifications.mentions": "{{$1}}, {{$2}} vΓ  {{$3}}", + "scenes.apps.messages.left_bar.stream.notifications.never": "KhΓ΄ng cΓ³ gΓ¬", + "scenes.apps.account.notifications.disturb_option_a": "KhΓ΄ng gα»­i thΓ΄ng bΓ‘o tα»›i tΓ΄i vΓ o khoαΊ£ng ", + "scenes.apps.account.notifications.sound": "ThΓ΄ng bΓ‘o Γ’m thanh", + "scenes.apps.parameters.group_sections.apps.badge_extension": "Mở rα»™ng", + "scenes.apps.tasks.task_status.todo": "Danh sΓ‘ch cαΊ§n lΓ m", + "scenes.apps.account.notifications.disturb_option_c": " (giờ Δ‘α»‹a phΖ°Ζ‘ng)", + "scenes.apps.account.notifications.devices_subtitle": "ThΓ΄ng bΓ‘o tα»« thiαΊΏt bα»‹", + "scenes.apps.account.notifications.devices_option_inactive": "Gα»­i thΓ΄ng bΓ‘o khi tΓ΄i Δ‘ang ngoαΊ‘i tuyαΊΏn trΓͺn mΓ‘y tΓ­nh", + "scenes.apps.account.notifications.devices_option_never": "KhΓ΄ng bao giờ gα»­i thΓ΄ng bΓ‘o tα»›i tΓ΄i", + "scenes.apps.account.notifications.mail_subtitle": "ThΓ΄ng bΓ‘o qua thΖ° Δ‘iện tα»­", + "scenes.apps.tasks.list_modal.remove": "XΓ³a danh sΓ‘ch vΓ  cΓ΄ng việc", + "scenes.apps.tasks.list_modal.remove_archived_tasks": "XΓ³a toΓ n bα»™ cΓ΄ng việc Δ‘Γ£ xong ({{$1}})", + "scenes.login.footer.branding": "BαΊ‘n Δ‘ang dΓΉng Twake {{$1}} ({{$2}}) ở mΓ‘y chα»§ riΓͺng ", + "scenes.login.create_account.email_used": "ThΖ° nΓ y Δ‘Γ£ được sα»­ dα»₯ng.", + "scenes.login.create_account.username": "TΓͺn người dΓΉng", + "scenes.login.create_account.fill_in_username": "BαΊ‘n cαΊ§n phαΊ£i Δ‘iền tΓͺn người dΓΉng", + "scenes.login.create_account.fill_in_email": "BαΊ‘i phαΊ£i Δ‘iền thΖ° Δ‘iện tα»­ vΓ  Δ‘ΓΊng Δ‘α»‹nh dαΊ‘ng", + "scenes.login.create_account.firstname": "TΓͺn", + "scenes.apps.tasks.list_modal.new_list": "Danh sΓ‘ch mα»›i", + "scenes.apps.tasks.list_modal.predefined_participants": "Danh sΓ‘ch người tham dα»± sαΊ΅n cΓ³", + "scenes.apps.tasks.list_modal.archive_all_tasks": "αΊ¨n toΓ n bα»™ cΓ΄ng việc", + "scenes.login.footer.go_to_twake": "Đi tα»›i twakeapp.com", + "scenes.login.create_account.title": "TαΊ‘o tΓ i khoαΊ£n mα»›i", + "scenes.login.create_account.username_already_exist": "TΓͺn ngời dΓΉng Δ‘Γ£ tα»“n tαΊ‘i", + "scenes.login.create_account.newsletter": "NhαΊ­n thΓ΄ng tin về Twake", + "scenes.login.forgot_password.title": "QuΓͺn mαΊ­t khαΊ©u?", + "scenes.login.create_account.email": "ThΖ°", + "scenes.login.forgot_password.text": "BαΊ‘n sαΊ½ nhαΊ­n được mΓ£ sα»‘ xΓ‘c nhαΊ­n dΓ i 9 chα»― sα»‘ qua thΖ° Δ‘iện tα»­.", + "scenes.app.channelsbar.currentuser.logout": "Đăng xuαΊ₯t", + "scenes.apps.account.account.password.description": "Thay Δ‘α»•i mαΊ­t khαΊ©u.", + "scenes.apps.account.preference": "CαΊ₯u hΓ¬nh", + "scenes.apps.account.account.email_add_modal.confirm": "XΓ‘c nhαΊ­n thΖ° nΓ y", + "components.calendar.repetition.does_not_repeat": "KhΓ΄ng lαΊ·p lαΊ‘i", + "components.calendar.repetition.weekly_on": "HΓ ng tuαΊ§n vΓ o {{$1}}", + "components.calendar.repetition.monthly_on_day": "HΓ ng thΓ‘ng vΓ o ngΓ y {{$1}}", + "components.calendar.repetition.every_weekday": "Mα»— ngΓ y trong tuαΊ§n (Thα»© 2 Δ‘αΊΏn thα»© 6)", + "scenes.app.channelsbar.currentuser.invited_status": "BαΊ‘n lΓ  khΓ‘ch.", + "scenes.app.channelsbar.currentuser.title": "ThiαΊΏt Δ‘αΊ·t tΓ i khoαΊ£n", + "scenes.app.channelsbar.currentuser.workspace_info": "BαΊ‘n ở khΓ΄ng gian lΓ m việc {{$1}} cΓΉng vα»›i nhΓ³m {{$2}}", + "scenes.apps.messages.message.save_button": "LΖ°u", + "scenes.app.channelsbar.welcome": "ChΓ o mα»«ng Δ‘αΊΏn vα»›i Twake", + "scenes.app.channelsbar.private_channel_label": "RiΓͺng tΖ°", + "scenes.app.mainview.tabs.rename": "Đổi tΓͺn", + "scenes.apps.calendar.modals.description_placeholder": "MΓ΄ tαΊ£", + "scenes.apps.calendar.modals.remove_button": "XΓ³a bỏ", + "scenes.app.popup.workspaceparameter.pages.workspace_partner_tabs.members.table.tags": "Vai trΓ²", + "scenes.client.main_view.main_header.search_input": "TΓ¬m kiαΊΏm", + "scenes.app.workspaces.welcome_page.see_you_soon": "HαΊΉn sα»›m gαΊ·p lαΊ‘i!", + "scenes.app.workspaces.welcome_page.may_be_invited_with_secondary_emails": "BαΊ‘n được mời qua thΖ° Δ‘iện tα»­?", + "scenes.login.create_account.step_3_subtitle": "BΖ°α»›c cuα»‘i β€” chΓΊng tΓ΄i cαΊ§n chαΊ―c chαΊ―n bαΊ‘n khΓ΄ng phαΊ£i lΓ  người mΓ‘y!", + "scenes.app.workspaces.create_company.company_name.title_2": "Δ‘iền thΓͺm thΓ΄ng tin về cΓ΄ng ty cα»§a bαΊ‘n.", + "scenes.app.workspaces.create_company.group_data.title": "SαΊ½ rαΊ₯t nhanh thΓ΄i β€” chΓΊng tΓ΄i cαΊ§n mα»™t vΓ i thΓ΄ng tin.", + "scenes.app.workspaces.create_company.invitations.title_2": "ThΓͺm người dΓΉng vΓ o nhΓ³m cα»§a bαΊ‘n.", + "scenes.app.workspaces.welcome_page.lets_go": "BαΊ―t Δ‘αΊ§u thΓ΄i!", + "scenes.app.workspaces.create_company.importations.title_1": "Đã tα»«ng lΓ m việc vα»›i cΓ΄ng cα»₯ sα»‘? NhαΊ­p hoαΊ·c tΓ­nh hợp cΓ΄ng cα»₯ cα»§a bαΊ‘n ngay bΓ’y giờ!", + "scenes.app.workspaces.create_company.title": "TαΊ‘o cΓ΄ng ty cα»§a tΓ΄i", + "scenes.app.workspaces.welcome_page.add_secondary_emails": "ThΓͺm thΖ° Δ‘iện tα»­ phα»₯", + "scenes.app.workspaces.welcome_page.no_company_subtitle": "Γ”i, được rα»“i... Dường nhΖ° bαΊ‘n chΖ°a được mời vΓ o mα»™t cΓ΄ng ty nΓ o cαΊ£.", + "scenes.app.channelsbar.currentuser.user_parameter": "CΓ i Δ‘αΊ·t thΓ΄ng bΓ‘o", + "scenes.app.channelsbar.currentuser.reactivate_notifications": "KΓ­ch hoαΊ‘t lαΊ‘i", + "scenes.app.channelsbar.currentuser.disabling_notifications_until": "VΓ΄ hiệu Δ‘αΊΏn 9 giờ sΓ‘ng hΓ΄m sau", + "scenes.app.channelsbar.currentuser.company_messages_counter_header": "Sα»‘ lượng tin nhαΊ―n", + "scenes.app.channelsbar.currentuser.company_messages_counter_info": "Ở phiΓͺn bαΊ£n miα»…n phΓ­ cα»§a Twake, bαΊ‘n khΓ΄ng thể truy cαΊ­p vΓ o nhiều hΖ‘n {{$1}} tin nhαΊ―n gαΊ§n Δ‘Γ’y.", + "scenes.app.channelsbar.channelsuser.no_private_message_invite_collaboraters": "KhΓ΄ng cΓ³ tin nhαΊ―n riΓͺng. HΓ£y mời thΓͺm người dΓΉng!", + "scenes.app.channelsbar.invitation_collaboraors_tutorial": "Mời người dΓΉng vΓ o khΓ΄ng gian lΓ m việc cα»§a bαΊ‘n.", + "scenes.app.channelsbar.modify_channel_menu": "Sα»­a kΓͺnh", + "scenes.app.channelsbar.read_sign": "ĐÑnh dαΊ₯u Δ‘Γ£ đọc", + "scenes.app.channelsbar.installation_desktop_tutorial": "CΓ i Δ‘αΊ·t α»©ng dα»₯ng trΓͺn mΓ‘y tΓ­nh", + "scenes.app.channelsbar.public_channel_label": "CΓ΄ng khai", + "scenes.app.channelsbar.tutorial_alert": "KhΓ΄ng muα»‘n thαΊ₯y lαΊ‘i khung nΓ y nα»―a?", + "scenes.app.popup.adduser.adresses_message": "NhαΊ­p thΖ° cΓ‘ch nhau bαΊ±ng dαΊ₯u phαΊ©y hoαΊ·c dαΊ₯u trαΊ―ng. LΖ°u Γ½ Twake sαΊ½ giα»›i hαΊ‘n việc mời người dΓΉng dα»±a vΓ o gΓ³i Δ‘Δƒng kΓ½ cα»§a bαΊ‘n.", + "scenes.app.channelsbar.unread_sign": "ĐÑnh dαΊ₯u chΖ°a đọc", + "scenes.app.channelsbar.channel_removing": "XΓ³a kΓͺnh", + "scenes.app.workspaces.create_company.group_data.group_main_activity.pharmaceutical_industry": "NgΓ nh dược", + "scenes.apps.drive.navigators.new_file.untitled": "ChΖ°a Δ‘αΊ·t tΓͺn", + "scenes.apps.messages.left_bar.stream_modal.placeholder_name": "TΓͺn", + "scenes.app.workspaces.create_company.group_data.group_main_activity.administration": "QuαΊ£n trα»‹", + "components.drive_dropzone.uploading": "Đang tαΊ£i lΓͺn...", + "scenes.apps.drive.navigators.navigator_content.files": "TΓ i liệu", + "scenes.apps.drive.navigators.navigator_labels.title": "NhΓ£n", + "scenes.apps.drive.navigators.new_file.create_file.type": "LoαΊ‘i", + "scenes.app.popup.appsparameters.pages.button_force": "BαΊ―t buα»™c toΓ n cΓ΄ng ty", + "scenes.app.popup.appsparameters.pages.apps_title": "Ứng dα»₯ng vΓ  kαΊΏt nα»‘i cα»§a bαΊ‘n", + "scenes.app.popup.appsparameters.pages.autorised_ip_adresses_label": "Cho phΓ©p Δ‘α»‹a chỉ IP", + "scenes.app.popup.appsparameters.pages.danger_zone_description": "XΓ³a α»©ng dα»₯ng", + "scenes.app.popup.appsparameters.pages._appareance_message_twakcode": "Kiểm tra việc xuαΊ₯t hiện vα»›i tin nhαΊ―n mΓ£ Twake", + "scenes.app.popup.appsparameters.pages.alert_published_app": "Ứng dα»₯ng cα»§a bαΊ‘n Δ‘Γ£ phΓ‘t hΓ nh, bαΊ‘n khΓ΄ng thể sα»­a được.", + "scenes.app.popup.appsparameters.pages.allowed_ip_adresses_method": "DΓΉng * trong quΓ‘ trΓ¬nh phΓ‘t triển để cho phΓ©p Δ‘α»‹a chỉ IP.", + "scenes.app.popup.appsparameters.pages.amazing_app_name": "Ứng dα»₯ng tuyệt vời cα»§a tΓ΄i", + "scenes.app.popup.appsparameters.pages.api_data_description": "Dα»― liệu cΓ³ Γ­ch cho Twake API.", + "scenes.app.popup.appsparameters.pages.api_parameters_label": "CΓ i Δ‘αΊ·t API", + "scenes.app.popup.appsparameters.pages.app_modification_right": "TαΊ₯t cαΊ£ nhα»―ng người quαΊ£n lΓ½ cΓ΄ng ty cΓ³ quyền chỉnh sα»­a α»©ng dα»₯ng.", + "scenes.app.popup.appsparameters.pages.app_privileges_information": "Định nghΔ©a α»©ng dα»₯ng cα»§a bαΊ‘n được đọc vΓ  chỉnh sα»­a.", + "scenes.app.popup.appsparameters.pages.app_privileges_label": "PhΓ’n quyền α»©ng dα»₯ng", + "scenes.app.popup.appsparameters.pages.available_publication_alert": "Việc phΓ‘t hΓ nh α»©ng dα»₯ng cα»§a bαΊ‘n Δ‘ang đợi phαΊ§n xΓ©t duyệt cα»§a Δ‘α»™i Twake.", + "scenes.app.popup.appsparameters.pages.call_event_handlers": "Sα»± kiện cα»§a '{{$1}}' vΓ  id '{{$2}}' được thΓ΄ng qua '{{$3}}'", + "scenes.app.popup.appsparameters.pages.company_label": "Chα»§ sở hα»―u cΓ΄ng ty", + "scenes.app.popup.appsparameters.pages.create_app_button": "TαΊ‘o α»©ng dα»₯ng", + "scenes.app.popup.appsparameters.pages.create_my_app": "TαΊ‘o α»©ng dα»₯ng cα»§a tΓ΄i", + "scenes.app.popup.appsparameters.pages.current_informations_apps_connectors": "BαΊ‘n chΖ°a tαΊ‘i α»©ng dα»₯ng nΓ o. TrΖ°α»›c khi tαΊ‘o α»©ng dα»₯ng hoαΊ·c kαΊΏt nα»‘i α»©ng dα»₯ng, bαΊ‘n phαΊ£i chαΊ―c chαΊ―n lΓ  α»©ng dα»₯ng chΖ°a cΓ³ trΓͺn kho α»©ng dα»₯ng cα»§a chΓΊng tΓ΄i.", + "scenes.app.popup.appsparameters.pages.danger_zone_label": "VΓΉng nguy hiểm", + "scenes.app.popup.appsparameters.pages.developped_apps_subtitle": "Ứng dα»₯ng phΓ‘t triển bởi cΓ΄ng ty", + "scenes.app.popup.appsparameters.pages.dispalyed_parameters_description": "Cho phΓ©p bαΊ‘n thiαΊΏt lαΊ­p α»©ng dα»₯ng cα»§a bαΊ‘n được nhΓ¬n thαΊ₯y.", + "scenes.app.popup.appsparameters.pages.displayed_parameters_label": "CΓ i Δ‘αΊ·t hiển thα»‹", + "scenes.app.popup.appsparameters.pages.configuration_label": "CαΊ₯u hΓ¬nh", + "scenes.app.popup.appsparameters.pages.app_name_label": "TΓͺn α»©ng dα»₯ng", + "scenes.app.popup.appsparameters.pages.automatique_label": "Tα»± Δ‘α»™ng", + "scenes.app.popup.appsparameters.pages.automatique_option_information": "NαΊΏu bαΊ‘n kΓ­ch hoαΊ‘t 'Tα»± Δ‘α»™ng', α»©ng dα»₯ng nΓ y sαΊ½ tα»± Δ‘α»™ng thΓͺm vΓ o khΓ΄ng gian lΓ m việc mα»›i cα»§a cΓ΄ng ty.", + "scenes.app.popup.appsparameters.pages.app_update": "CαΊ­p nhαΊ­t α»©ng dα»₯ng {{$1}} (α»©ng dα»₯ng được dΓΉng {{$2}} lαΊ§n.)", + "scenes.app.popup.appsparameters.pages.application_title": "Ứng dα»₯ng", + "scenes.app.popup.appsparameters.pages.error_check_needed": "CΓ³ lα»—i xαΊ£y ra; kiểm tra lαΊ‘i thΓ΄ng tin cα»§a bαΊ‘n.", + "scenes.app.popup.appsparameters.pages.public_availability_application": "Ứng dα»₯ng cΓ΄ng cα»™ng", + "scenes.app.popup.appsparameters.pages.error_message": "TΓͺn nΓ y Δ‘Γ£ dΓΉng cho mα»™t α»©ng dα»₯ng khΓ‘c; chọn tΓͺn khΓ‘c.", + "scenes.app.popup.appsparameters.pages.error_user_code": "lα»—i", + "scenes.app.popup.appsparameters.pages.installation": "CΓ i Δ‘αΊ·t.", + "scenes.app.popup.appsparameters.pages.instruction_message_twakecode": "BαΊ―t Δ‘αΊ§u bαΊ±ng việc viαΊΏt tin nhαΊ―n vα»›i Δ‘α»‹nh dαΊ‘ng JSON.", + "scenes.app.popup.appsparameters.pages.loading": "Đang tαΊ£i...", + "scenes.app.popup.appsparameters.pages.message_data_next_event": "Dα»― liệu bα»‹ Δ‘α»™ng sαΊ½ được gα»­i trong sα»± kiện tiαΊΏp theo", + "scenes.app.popup.appsparameters.pages.modify_public_data": "Chỉnh sα»­a dα»― liệu cΓ΄ng cα»™ng α»©ng dα»₯ng cα»§a ban.", + "scenes.app.popup.appsparameters.pages.new_app_title": "Ứng dα»₯ng mα»›i", + "scenes.app.popup.appsparameters.pages.ok_user_code": "Ok", + "scenes.app.popup.appsparameters.pages.optimal_format": "Định dαΊ‘ng tα»‘i Ζ°u: 48x48px.", + "scenes.app.popup.appsparameters.pages.public_login_label": "TΓͺn cΓ΄ng khai", + "scenes.app.popup.appsparameters.pages.publication_description": "Địn nghΔ©a sα»± hiển thα»‹ cα»§a α»©ng dα»₯ng.", + "scenes.app.popup.appsparameters.pages.publication_label": "PhΓ‘t hΓ nh", + "scenes.app.popup.appsparameters.pages.read_privileges_label": "Quyền đọc", + "scenes.app.popup.appsparameters.pages.remove_app": "XΓ³a α»©ng dα»₯ng {{$1}} vΔ©nh viα»…n.", + "scenes.app.popup.appsparameters.pages.remove_app_from_company": "XΓ³a ra khỏi toΓ n bα»™ cΓ΄ng ty", + "scenes.app.popup.appsparameters.pages.remove_app_from_workspace": "XΓ³a ra khỏi khΓ΄ng gian lΓ m việc", + "scenes.app.popup.appsparameters.pages.show_button": "Hiện", + "scenes.app.popup.appsparameters.pages.status_tilte": "TrαΊ‘ng thΓ‘i", + "scenes.app.popup.appsparameters.pages.title_tester": "Twakecode kiểm thα»­", + "scenes.app.popup.appsparameters.pages.publish_app_label": "PhΓ‘t hΓ nh α»©ng dα»₯ng", + "scenes.app.popup.appsparameters.pages.filter_information": "Lọc nΓ y giα»›i hαΊ‘n việc sα»­ dα»₯ng khΓ³a API kαΊΏt nα»‘i trong mΓ‘y chα»§ cα»§a bαΊ‘n.", + "scenes.app.popup.appsparameters.pages.grp_section_surname_label": "Đặt tΓͺn", + "scenes.app.popup.appsparameters.pages.parameters_form_small_text": "Ứng dα»₯ng chΖ°a phΓ‘t hΓ nh chỉ chαΊ‘y vα»›i cΓ΄ng ty cα»§a bαΊ‘n. NαΊΏu bαΊ‘ muα»‘n α»©ng dα»₯ng nΓ y được dΓΉng bởi tαΊ₯t cαΊ£ người dΓΉng Twake, kΓ­ch hoαΊ‘t lα»±a chọn nΓ y.", + "scenes.app.popup.appsparameters.pages.event_subtitle": "Sα»± kiện", + "scenes.app.popup.appsparameters.pages.grp_section_name-error": "TΓͺn nΓ y Δ‘Γ£ dΓΉng cho α»©ng dα»₯ng khΓ‘c. HΓ£y chọn tΓͺn khΓ‘c.", + "scenes.app.popup.appsparameters.pages.string_information": "Chuα»—i nΓ y Δ‘α»‹nh danh α»©ng dα»₯ng cα»§a bαΊ‘n vΓ  sαΊ½ được sα»­ dα»₯ng trong tin nhαΊ―n dΓ²ng lệnh.", + "scenes.app.popup.appsparameters.pages.interne_availability_application": "Ứng dα»₯ng nα»™i bα»™", + "scenes.app.popup.appsparameters.pages.json_configuration_information": "Đi tα»›i phαΊ§n tΓ i liệu vΓ  khởi tαΊ‘o cαΊ₯u hΓ¬nh vα»›i Δ‘α»‹n dαΊ‘ng JSON.", + "scenes.app.popup.appsparameters.pages.write_privileges_label": "Quyền ghi", + "scenes.app.popup.appsparameters.pages.danger_zone_small_text": "BαΊ‘n khΓ΄ng thể xΓ³a α»©ng dα»₯ng nΓ y nαΊΏu nΓ³ Δ‘Γ£ được phΓ‘t hΓ nh.", + "scenes.app.popup.appsparameters.pages.url_reception_events_label": "Đường dαΊ«n sα»± kiện", + "scenes.app.popup.appsparameters.pages.waiting_availability_application": "HΓ£y đợi...", + "scenes.app.popup.appsparameters.pages.website_label": "Trang mαΊ‘ng", + "scenes.app.popup.appsparameters.pages.error_app_update_message": "CΓ³ mα»™t lα»—i xαΊ©y ra trong khi cαΊ­p nhαΊ­t α»©ng dα»₯ng.", + "scenes.app.popup.workspaceparameter.pages.all_apps_small_text": "TαΊ₯t cαΊ£ α»©ng dα»₯ng", + "scenes.app.popup.userparameter.pages.frequency_notif_configuration_description": "CΓ i Δ‘αΊ·t mα»©c Δ‘α»™ thường xuyΓͺn cα»§a thΓ΄ng bΓ‘o.", + "scenes.app.popup.appsparameters.pages.update_button": "CαΊ­p nhαΊ­t", + "scenes.app.popup.userparameter.pages.frequency_notif_subtitle": "Thường xuyΓͺn thΓ΄ng bΓ‘o", + "scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description": "CΓ i Δ‘αΊ·t mα»©c Δ‘α»™ thường xuyΓͺn thΓ΄ng bΓ‘o qua thΖ°.", + "scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description": "Chọn khoαΊ£ng thời gian khΓ΄ng mα»‘n nhαΊ­n thΓ΄ng bΓ‘o.", + "scenes.app.popup.userparameter.pages.notif_content_label": "Nα»™i dung thΓ΄ng bΓ‘o", + "scenes.app.popup.workspaceparameter.pages.moderator_status": "Người kiểm duyệt khΓ΄ng gian lΓ m việc", + "scenes.app.popup.workspaceparameter.pages.company_name_description": "Thay Δ‘α»•i tΓͺn cΓ΄ng ty", + "scenes.app.popup.workspaceparameter.pages.configuration_notif": "cαΊ₯u hΓ¬nh", + "scenes.app.popup.workspaceparameter.pages.developped_apps_small_text": "Ứng dα»₯ng phΓ‘t triển bởi cΓ΄ng ty", + "scenes.app.popup.workspaceparameter.pages.name_label": "TΓͺn khΓ΄ng gian lΓ m việc", + "scenes.app.popup.workspaceparameter.pages.no_access": "KhΓ΄ng cΓ³ quyền truy cαΊ­p", + "scenes.app.popup.workspaceparameter.pages.installed_apps_information": "CΓ‘c α»©ng dα»₯ng Δ‘Γ£ cΓ i Δ‘αΊ·t cho khΓ΄ng gian lΓ m việc {{$1}}", + "scenes.app.popup.workspaceparameter.pages.configure_button": "Định dαΊ‘ng cαΊ₯u hΓ¬nh ", + "scenes.app.popup.workspaceparameter.pages.research_by": "TÌm kiαΊΏm α»©ng dα»₯ng theo tΓͺn vΓ  phΓ’n loαΊ‘i", + "scenes.app.popup.workspaceparameter.pages.researching_apps_button": "TΓ¬m kiαΊΏm α»©ng dα»₯ng", + "scenes.app.popup.workspaceparameter.pages.company_name_label": "TΓͺn cΓ΄ng ty", + "scenes.app.popup.workspaceparameter.admin_current_status": "BαΊ‘n lΓ  quαΊ£n trα»‹ viΓͺn.", + "scenes.app.popup.appsparameters.pages.error_app_simple_name_message": "TΓͺn α»©ng dα»₯ng cα»§a bαΊ‘n Δ‘Γ£ cΓ³. HΓ£y chọn tΓͺn khΓ‘c.", + "scenes.app.popup.createworkspacepage.add_subtitle": "CαΊ§n thΓͺm dung lượng?", + "scenes.app.popup.createworkspacepage.create_new_workspace": "TαΊ‘o khΓ΄ng gian lΓ m việc mα»›i", + "scenes.app.popup.userparameter.pages.keywords_notif_description": "NhαΊ₯n mαΊ‘nh nhα»―ng tα»« khΓ³a:", + "scenes.app.popup.userparameter.pages.no_night_disturbing_label": "KhΓ΄ng lΓ m phiền ban Δ‘Γͺm", + "scenes.app.popup.userparameter.personnal_workspaces_title": "KhΓ΄ng gian lΓ m việc cα»§a bαΊ‘n", + "scenes.app.popup.workspaceparameter.admin_manager_current_status": "BαΊ‘n lΓ  quαΊ£n trα»‹ viΓͺn khΓ΄ng gian lΓ m việc.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace": "XΓ³a khΓ΄ng gian lΓ m việc", + "scenes.app.popup.workspaceparameter.pages.error_workspace_member": "BαΊ‘n phαΊ£i lΓ  người cuα»‘i cΓΉng để xΓ³a được khΓ΄ng gian lΓ m việc. XΓ³a cΓ‘c thΓ nh viΓͺn khΓ‘c trΖ°α»›c vΓ  thα»­ lαΊ‘i.", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace_description": "Đễ xΓ‘c nhαΊ­n xΓ³a khΓ΄ng gian lΓ m việc, hΓ£y nhαΊ­p tΓͺn vΓ  nhαΊ₯n nΓΊt xΓ³a.", + "scenes.app.popup.workspaceparameter.pages.enter": "NhαΊ­p vΓ o ", + "scenes.app.popup.workspaceparameter.pages.access_apps": "Truy cαΊ­p vΓ o cΓ‘c α»©ng dα»₯ng vΓ  cΓ‘c liΓͺn kαΊΏt", + "scenes.app.popup.workspaceparameter.pages.apps_research_title": "TΓ¬m kiαΊΏm cΓ‘c α»©ng dα»₯ng", + "scenes.app.popup.workspaceparameter.pages.back_to_search_button": "Quay về phαΊ§n tΓ¬m kiαΊΏm", + "scenes.app.popup.workspaceparameter.pages.collaborateurs": "Người dΓΉng", + "scenes.app.popup.workspaceparameter.pages.displayed_preferencies_subtitle": "TΓΉy chọn hiển thα»‹", + "scenes.app.popup.workspaceparameter.pages.install_button": "CΓ i Δ‘αΊ·t", + "scenes.app.popup.workspaceparameter.pages.installed_apps_message": "CΓ‘c α»©ng dα»₯ng Δ‘Γ£ cΓ i Δ‘αΊ·t cho cΓ΄ng ty {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_subtitle": "Nhα»―ng α»©ng dα»₯ng Δ‘Γ£ cΓ i", + "scenes.app.popup.workspaceparameter.pages.invitation_error": "CΓ³ lα»—i xαΊ©y ra khi mời người dΓΉng: ", + "scenes.app.popup.workspaceparameter.pages.invited_guest_check_message": "Kiểm tra tΓͺn Δ‘Δƒng nhαΊ­p hoαΊ·c thΖ° cΓ³ thể bα»‹ sai.", + "scenes.app.popup.workspaceparameter.pages.logo_modify_description": "Sα»­ αΊ£nh Δ‘αΊ‘i diện cα»§a khΓ΄ng gian lΓ m việc", + "scenes.app.popup.workspaceparameter.pages.logo_subtitle": "Biểu tượng", + "scenes.app.popup.workspaceparameter.pages.name_description": "Đổi tΓͺn cho khΓ΄ng gian lΓ m việc nΓ y", + "scenes.app.popup.workspaceparameter.pages.no_app_information": "BαΊ‘n khΓ΄ng cΓ³ α»©ng dα»₯ng nΓ o trong khΓ΄ng gian lΓ  việc nΓ y", + "scenes.app.popup.workspaceparameter.pages.quit_workspace_menu": "Rời khỏi khΓ΄ng gian lΓ m việc", + "scenes.app.popup.workspaceparameter.pages.read_access_subtitle": "Chỉ cΓ³ quyền đọc", + "scenes.app.popup.workspaceparameter.pages.remove_from_company_text": "XΓ³a khỏi cΓ΄ng ty", + "scenes.app.popup.workspaceparameter.pages.apps_connectors_title": "CΓ‘c α»©ng dα»₯ng vΓ  cΓ‘c trΓ¬nh kαΊΏt nα»‘i", + "scenes.app.popup.workspaceparameter.pages.alert_impossible_removing": "BαΊ‘n khΓ΄ng thể rời khỏi khΓ΄ng gian lΓ m việc, vΓ¬ bαΊ‘n lΓ  quαΊ£n trα»‹ viΓͺn cuα»‘i cΓΉng. BαΊ‘n cΓ³ thể thΓͺm quαΊ£n trα»‹ viΓͺn khΓ‘c hoαΊ·c xΓ³a/lΖ°u trα»― khΓ΄ng gian lΓ m việc nΓ y.", + "scenes.app.popup.workspaceparameter.pages.apps_small_text": "CΓ‘c α»©ng dα»₯ng cα»§a khΓ΄ng gian lΓ m việc nΓ y", + "scenes.app.popup.workspaceparameter.pages.apps_company_small_text": "Ứng dα»₯ng cα»§a cΓ΄ng ty", + "scenes.app.popup.workspaceparameter.pages.company_identity_title": "Định danh cΓ΄ng ty", + "scenes.app.popup.workspaceparameter.pages.installed_app_information": "CΓ i Δ‘αΊ·t α»©ng dα»₯ng cho khΓ΄ng gian lΓ m việc nΓ y.", + "scenes.app.popup.workspaceparameter.pages.company_developped_apps_subtitle": "CΓ‘c α»©ng dα»₯ng được phΓ‘t triển bởi cΓ΄ng ty", + "scenes.app.popup.appsparameters.pages.remove_app_button": "XΓ³a α»©ng dα»₯ng", + "scenes.app.popup.userparameter.pages.private_message_content.hide": "αΊ¨n nα»™i dung tin nhαΊ―n riΓͺng tΖ°", + "scenes.app.popup.createworkspacepage.placeholder_name": "TΓͺn khΓ΄ng gian lΓ m việc", + "scenes.app.popup.userparameter.pages.private_message_content.show": "Hiện nα»™i dung tin nhαΊ―n riΓͺng tΖ°", + "scenes.app.popup.workspaceparameter.manager_current_status": "BαΊ‘n lΓ  quαΊ£n trα»‹ viΓͺn cΓ΄ng ty.", + "scenes.apps.messages.input.replied_to": "Δ‘Γ£ trαΊ£ lời ", + "scenes.apps.drive.import_from_computer_menu": "TαΊ£i lΓͺn tα»« mΓ‘y tΓ­nh", + "scenes.apps.drive.folder_subtitle": "Thα»© mα»₯c", + "scenes.apps.calendar.workspace_menu": "KhΓ΄ng gian lΓ m việc", + "scenes.apps.drive.files_subtitle": "Tệp", + "scenes.apps.drive.move_text": "Chuyển", + "scenes.apps.calendar.workspace": "KhΓ΄ng gian lΓ m việc", + "scenes.apps.calendar.week_option": "TuαΊ§n", + "scenes.apps.drive.choose_folder_button": "Chọn đường dαΊ«n", + "scenes.apps.messages.message.activity_message.a_added_b_to_the_channel": "{{$1}} thΓͺm {{$2}} vΓ o kΓͺnh", + "components.workspace.list_manager.current_company": "CΓ΄ng ty hiện tαΊ‘i", + "scenes.apps.drive.download_button": "TαΊ£i về", + "components.tagpicker.tag_name": "Tển thαΊ»", + "components.workspace.list_manager.add": "ThΓͺm khΓ΄ng gian lΓ m việc", + "components.workspace.list_manager.current_space": "KhΓ΄ng gian lΓ m việc hiện tαΊ‘i", + "components.inputs.input_with_select.select.placeholder": "TΓͺn Δ‘oαΊ‘n", + "scenes.apps.calendar.workspace_label": "KhΓ΄ng gian lΓ m việc hiện tαΊ‘i", + "scenes.apps.drive.message_added_file": "{{$1}} gα»­i {{$2}}.", + "scenes.apps.drive.message_added_mutiple_files": "{{$1}} Δ‘Γ£ gα»­i nhiều tΓ i liệu.", + "scenes.apps.drive.choose_file_button": "Chọn mα»™t file", + "components.drive.right_preview.suppress_link": "ChαΊ·n liΓͺn kαΊΏt", + "scenes.login.verifymail.success": "Email cα»§a bαΊ‘n Δ‘Γ£ được verify thΓ nh cΓ΄ng!", + "scenes.login.verifymail.verification_waiting": "Đang chờ xΓ‘c nhαΊ­n...", + "components.newversion.new_version_component.row.part_1": "BαΊ‘n Δ‘ang sα»­ dα»₯ng mα»™t phiΓͺn bαΊ£n cΕ© cα»§a Twake", + "components.newversion.new_version_component.row.part_2": "chΓΊng tΓ΄i gợi Γ½ bαΊ‘n tαΊ£i lαΊ‘i α»©ng dα»₯ng vΓ  trαΊ£i nghiệm nhα»―ng tΓ­nh nΔƒng mα»›i!", + "components.inputs.input_with_select.select.no_sections": "BαΊ―t Δ‘αΊ§u Δ‘αΊ·t tΓͺn cho kΓͺnh Δ‘αΊ§u tiΓͺn cα»§a bαΊ‘n.", + "components.inputs.input_with_select.button.tooltip": "Đặt mα»™t Δ‘oαΊ‘n kΓͺnh", + "scenes.apps.messages.message.activity_message.a_removed_b_from_the_channel": "{{$1}} xΓ³a {{$2}} ra khỏi kΓͺnh", + "scenes.apps.messages.message.activity_message.a_created_channel_connector": "{{$1}} Δ‘Γ£ thΓͺm liΓͺn mα»™t kαΊΏt mα»›i {{$2}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_connector": "{{$1}} Δ‘Γ£ xΓ³a mα»™t liΓͺn kαΊΏt {{$2}}", + "components.alert.leave_private_channel.title": "BαΊ‘n cΓ³ chαΊ―c chαΊ―n lΓ  muα»‘n rời bỏ kΓͺnh?", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.loader": "TαΊ£i thΓͺm", + "components.unverified_account.verification_details": "ChΓΊng tΓ΄i Δ‘Γ£ gα»­i cho bαΊ‘n mα»™t thΖ° xΓ‘c minh thΓ΄ng tin Δ‘αΊΏn", + "components.account_verification_status_sentence": "TrαΊ‘ng thΓ‘i tΓ i khoαΊ£n cα»§a bαΊ‘n lΓ : {{$1}}", + "components.account_verication_status_blocked": "KhΓ³a", + "components.add_mails_workspace.title_1": "ThΓͺm vΓ i người dΓΉng", + "services.console_services.toaster.success_verify_email": "Mα»™t dường dαΊ«n xΓ‘c minh Δ‘Γ£ gα»­i Δ‘αΊΏn thΖ° cα»§a bαΊ‘n", + "services.console_services.toaster.success_invite_emails": "ThΓͺm người dΓΉng {{$1}} thΓ nh cΓ΄ng", + "scenes.apps.tasks.select_user_button": "Xem cΓ΄ng việc cα»§a người dΓΉng khΓ‘c", + "scenes.apps.tasks.select_user": "TΓ¬m người dΓΉng", + "scenes.apps.messages.input.attach_file.from_computer": "Tα»« mΓ‘y tΓ­nh", + "scenes.apps.drive.default_link_name": "ChΖ°a Δ‘αΊ·t tΓͺn", + "services.apps.messages.message_editor_service.upload_error_toaster": "{{$1}} - BαΊ‘n khΓ΄ng thể thΓͺm quΓ‘ {{$2}} tΓ i liệu trong mα»™t tin nhαΊ―n", + "general.uploading": "TαΊ£i lΓͺn", + "components.upload.drop_files.toaster.error": "BαΊ‘n khΓ΄ng thể tαΊ£i lΓͺn quΓ‘ {{$1}} tΓ i liệu", + "components.emoji_picker.categories.food_and_drink": "Đồ Δƒn & Thα»©c uα»‘ng", + "components.emoji_picker.categories.activity": "HoαΊ‘t Δ‘α»™ng", + "components.emoji_picker.categories.objects": "TiΓͺu đề", + "scenes.apps.calendar.my_calendar_menu": "Lα»‹ch cα»§a tΓ΄i", + "scenes.apps.drive.message_added_file_no_name": "{{$1}} Δ‘Γ£ gα»­i mα»™t file.", + "scenes.apps.drive.new_external_storage": "TαΊ‘o α»• cα»©ng ngoΓ i", + "scenes.apps.drive.new_folder_title": "TαΊ‘o thΖ° mα»₯c mα»›i", + "scenes.help_us": "Tuy nhiΓͺn, nαΊΏu bαΊ‘n muα»‘n giΓΊp chΓΊng tΓ΄i sα»­a lα»—i, hΓ£y để lαΊ‘i lα»›i nhαΊ―n ở bΓͺn dΖ°α»›i: ", + "services.apps.calendar.deadline_icon": "HαΊ‘n chΓ³t", + "services.apps.calendar.move_icon": "Chuyển", + "services.apps.calendar.reminder_icon": "NhαΊ―c nhở", + "services.apps.messages.no_app": "Ứng dα»₯ng nΓ y khΓ΄ng tα»“n tαΊ‘i.", + "services.apps.messages.no_command_possible": "ChΓΊng tΓ΄i khΓ΄ng thể thα»±c hiện được '{{$1}}' vΓ¬ '{{$2}}' khΓ΄ng tα»“n tαΊ‘i hoαΊ·c khΓ΄ng cho phΓ©p thα»±c hiện lệnh.", + "scenes.apps.drive.viewer.download_desktop": "TαΊ£i Twake Desktop để xem trΖ°α»›c trΓͺn α»©ng dα»₯ng", + "scenes.apps.tasks.board.tasks.subtask": "Việc phα»₯", + "scenes.apps.tasks.board.tasks.add_subtask": "ThΓͺm việc phα»₯", + "scenes.apps.tasks.board.tasks.use_deadline": "Đặt hαΊ‘n chΓ³t", + "scenes.apps.tasks.board.ends": "PhαΊ£i xong để", + "scenes.apps.tasks.board.list_name": "TΓͺn danh sΓ‘ch", + "scenes.app.popup.sync_calendar": "Đồng bα»™ hΓ³a lα»‹ch cα»§a bαΊ‘n.", + "scenes.apps.parameters.workspace_sections.workspace.logo_company": "Logo cα»§a cΓ΄ng ty", + "scenes.apps.account.account.password_for_user": "MαΊ­t khαΊ©u cho người dΓΉng", + "components.attachmentpicker.add_attachment": "ThΓͺm tệp Δ‘Γ­nh kΓ¨m", + "components.input.copied": "Đã sao chΓ©p", + "components.drive.moove_here": "Chuyển tα»›i Δ‘Γ’y", + "components.drive.modify_uslist": "Chỉnh sα»­a danh sΓ‘ch người dΓΉng", + "components.workspace.list_manager.no_workspace": "KhΓ΄ng cΓ³ khΓ΄ng gian lΓ m việc nΓ o", + "components.searchpopup.filter_ws": "Lọc khΓ΄ng gian lΓ m việc", + "components.searchpopup.size": "Cα»‘", + "components.searchpopup.last_modif": "Chỉnh sα»­a lαΊ§n cuα»‘i", + "components.searchpopup.sender": "Người gα»­i", + "components.searchpopup.mentions": "NhαΊ―c Δ‘αΊΏn", + "components.searchpopup.only_pinned": "Chỉ cΓ³ tin nhαΊ―n ghim", + "scenes.app.popup.appsparameters.pages.subtitle_informations": "ThΓ΄ng tin liΓͺn quan Δ‘αΊΏn quαΊ£n lΓ½ α»©ng dα»₯ng", + "scenes.app.popup.appsparameters.pages.smalltext_user_id": "MΓ£ Δ‘α»‹nh danh người dΓΉng hiện tαΊ‘i", + "scenes.app.popup.appsparameters.pages.smalltext_group_id": "MΓ£ Δ‘α»‹nh danh nhΓ³m hiện tαΊ‘i", + "scenes.client.channelbar.channeltemplateeditor.checkbox": "Tα»± Δ‘α»™ng mời toΓ n bα»™ thΓ nh viΓͺn khΓ΄ng gian lΓ m việc vΓ o kΓͺnh nΓ y", + "scenes.client.channelbar.channelmemberslist.title": "Người dΓΉng trong {{$1}}", + "scenes.client.channelbar.channelmemberslist.autocomplete": "TΓ¬m kiαΊΏm người dΓΉng", + "scenes.client.channelbar.channelmemberslist.menu.option_2": "XΓ³a khỏi kΓͺnh", + "components.leftbar.channel.workspaceschannels.menu.option_1": "TαΊ‘o mα»™t kΓͺnh", + "components.leftbar.channel.workspaceschannels.menu.option_2": "Tham gia kΓͺnh", + "components.channelworkspacelist.title": "CΓ‘c kΓͺnh", + "scenes.client.channelbar.workspacechannellist.autocomplete": "TΓ¬m kΓͺnh, người dΓΉng hoαΊ·c tin nhαΊ―n trα»±c tiαΊΏp", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_creation": "TαΊ‘o mα»™t tab mα»›i", + "components.connectorslistmanager.add_connectors": "ThΓͺm kαΊΏt nα»‘i", + "scenes.client.mainview.tabs.tabstemplateeditor.select_placeholder": "Ứng dα»₯ng", + "scenes.client.channelbar.channelmemberslist.no_members": "KhΓ΄ng cΓ³ người dΓΉng nΓ o trong kΓͺnh, bαΊ‘n cΓ³ thể mời thΓͺm bαΊ±ng việc nhαΊ₯n vΓ o nΓΊt ThΓͺm người dΓΉng.", + "scenes.app.popup.adduserfromtwakeconsole.current_users_state": "{{$1}} thΖ° sαΊ½ được thΓͺm", + "scenes.apps.messages.message.activity_message.a_updated_channel_description": "{{$1}} thay Δ‘α»•i mΓ΄ tαΊ£", + "scenes.apps.messages.message.activity_message.a_updated_channel_name": "{{$1}} Δ‘Γ£ Δ‘α»•i tΓͺn kΓͺnh sang {{$2}}", + "scenes.apps.messages.message.activity_message.a_created_channel_tab": "{{$1}} Δ‘Γ£ thΓͺm {{$2}} tab {{$3}}", + "components.alert.leave_private_channel.description": "BαΊ‘n sαΊ½ khΓ΄ng thể tham gia vΓ o kΓͺnh riΓͺng tΖ° trα»« khi ai Δ‘Γ³ mời bαΊ‘n.", + "components.blocked_account.trial_period_over": "Thời gian dΓΉng thα»­ cα»§a bαΊ‘n Δ‘Γ£ hαΊΏt. Để mở khΓ³a tΓ i khoαΊ£n cα»§a bαΊ‘n vΓ  cΓ³ quyền truy cαΊ­p vΓ o tαΊ₯t cαΊ£ cΓ‘c chα»©c nΔƒng, vui lΓ²ng xΓ‘c minh tΓ i khoαΊ£n cα»§a bαΊ‘n qua email xΓ‘c nhαΊ­n", + "components.add_mails_workspace.title_2": "Twake lΓ  cΓ΄ng cα»₯ cα»™ng tΓ‘c nhΓ³m, hΓ£y mời người dΓΉng để sα»­ dα»₯ng khΓ΄ng gian lΓ m việc mΓ  chΓΊng tΓ΄i Δ‘Γ£ tαΊ‘o cho bαΊ‘n.", + "components.verify_mail.title_2": "Tα»« bΓ’y giờ bαΊ‘n lΓ  người dΓΉng chΓ­nh thα»©c cα»§a Twake!", + "components.verify_mail.text": "TrΖ°α»›c tiΓͺn, bαΊ‘n phαΊ£i xΓ‘c minh thΖ° Δ‘iện tα»­. ChΓΊng tΓ΄i Δ‘Γ£ gα»­i đường dαΊ«n xΓ‘c minh Δ‘αΊΏn", + "components.verify_mail.paragraph": "BαΊ‘n cΓ³ thể lΓ m việc nΓ y sau nhΖ°ng nαΊΏu bαΊ‘n chΖ°a xΓ‘c minh tΓ i khoαΊ£n bαΊ‘n chỉ được dΓΉng bαΊ£n giα»›i hαΊ‘n cα»§a Twake", + "services.console_services.toaster.add_emails_error": "Lα»—i khi thΓͺm thΖ° Δ‘iện tα»­", + "services.console_services.toaster.add_email_error_message": "LΓ΄i khi thΓͺm {{$1}}", + "scenes.client.channels_bar.modals.guest_management.title": "QuαΊ£n lΓ½ khΓ‘ch trong {{$1}}", + "scenes.client.channels_bar.modals.guest_management.input_placeholder": "TΓ¬m kiαΊΏm khΓ‘ch hoαΊ·c nhα»―ng thΖ° Δ‘ang chờ xα»­ lΓ½", + "scenes.client.channels_bar.modals.parts.channel_member_row.label.pending_email": "ThΖ° Δ‘Γ£ gα»­i", + "general.user.role.company.admin": "QuαΊ£n trα»‹ viΓͺn cΓ΄ng ty", + "general.user.deleted": "XΓ³a tΓ i khoαΊ£n", + "components.richtexteditor.toolbar.unordered-list": "GαΊ‘ch Δ‘αΊ§u dΓ²ng", + "components.richtexteditor.toolbar.ordered-list": "Danh sΓ‘ch Δ‘Γ£ sαΊ―p xαΊΏp", + "components.richtexteditor.toolbar.blockquote": "ĐÑnh dαΊ₯u khα»‘i", + "components.richtexteditor.toolbar.code-block": "Khα»‘i mΓ£", + "components.locked_features.locked_history_banner.title": "BαΊ‘n Δ‘Γ£ Δ‘αΊ‘t Δ‘αΊΏn giα»›i hαΊ‘n tin nhαΊ―n", + "components.locked_features.locked_history_banner.description": "CΓ΄ng ty bαΊ‘n cΓ³ quΓ‘ nhiều tin nhαΊ―n! HΓ£y nΓ’ng cαΊ₯p ngay để truy cαΊ­p được vΓ o toΓ n bα»™ lα»‹ch sα»­ tin nhαΊ―n.", + "components.locked_features.locked_guests_popup.title": "TΓ­nh nΔƒng KhΓ‘ch mời Δ‘Γ£ khΓ³a", + "components.locked_features.locked_guests_popup.subtitle": "TΓ­nh nΔƒng nΓ y khΓ΄ng cΓ³ trΓͺn bαΊ£n Twake miα»…n phΓ­", + "components.on_boarding.company_billing_banner.link": "gΓ³i Δ‘Δƒng kΓ½ cho cΓ΄ng ty", + "scenes.apps.messages.message.parts.deleted_content.text.current_user": "BαΊ‘n vα»«a xΓ³a tin nΓ y", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_text": " thay bαΊ±ng", + "components.locked_features.locked_only_office_popup.text": "Whoops!!CΓ³ vαΊ» nhΖ° bαΊ‘n muα»‘n chỉnh sα»­a file trΓͺn Twake.HΓ£y cΓ’n nhαΊ―c Δ‘Δƒng kΓ­ gΓ³i cao hΖ‘n. KhΓ‘m phΓ‘ cΓ‘c gΓ³i cα»§a chΓΊng tΓ΄i vΓ  chọn gΓ³i phΓΉ hợp nhαΊ₯t vα»›i nhu cαΊ§u cα»§a cΓ΄ng ty bαΊ‘n.", + "scenes.apps.drive.open_link": "Mở đường dαΊ«n ở mα»™t cα»­a sα»• khΓ‘c", + "scenes.app.popup.workspaceparameter.pages.your_apps_label": "Ứng dα»₯ng cα»§a bαΊ‘n", + "scenes.apps.drive.go_out_trash_menu": "Bỏ vΓ o thΓΉng rΓ‘c", + "scenes.apps.account.message_user_signin": "BαΊ‘n cΓ³ thể Δ‘Δƒng nhαΊ­p bαΊ₯t kΓ¬ lΓΊc nΓ o sα»­ dα»₯ng email Δ‘Γ£ Δ‘Δƒng kΓ­ vΓ  chuyển nΓ³ thΓ nh mα»™t tΓ i khoαΊ£n bΓ¬nh thường.", + "scenes.apps.account.message_temporary": "Mα»™t tΓ i khoαΊ£n tαΊ‘m thời sαΊ½ hoαΊ‘t Δ‘α»™ng nhΖ° mα»™t tΓ i khoαΊ£n Twake bΓ¬nh thường nhΖ°ng bαΊ‘n cΓ³ thể tαΊ‘o mαΊ­t khαΊ©u vΓ  Δ‘αΊ·t lαΊ‘i nΓ³ nαΊΏu cαΊ§n thiαΊΏt.", + "scenes.client.channels_bar.modals.guest_management.tips": "BαΊ―t Δ‘αΊ§u thΓͺm hoαΊ·c tΓ¬m kiαΊΏm bαΊ±ng việc sα»­ dα»₯ng Γ΄ nhαΊ­p liệu ở trΓͺn", + "components.on_boarding.popups.blocked_company.title": "CΓ΄ng ty cα»§a bαΊ‘n bα»‹ khΓ³a vΓ¬ vαΊ₯n đề thanh toΓ‘n", + "components.add_mails_workspace.text_area_placeholder": "NhαΊ­p thΖ° Δ‘iện tα»­ người dΓΉng cα»§a bαΊ‘n*", + "components.verify_mail.title_1": "ChΓΊc mα»«ng", + "components.locked_features.locked_guests_popup.skip_for_now_button": "Bỏ qua bΓ’y giờ", + "components.on_boarding.popups.blocked_company.company_subscription_plan_button": "NhαΊ₯n vΓ o Δ‘Γ’y", + "components.on_boarding.popups.blocked_company.or": "HoαΊ·c", + "components.member.user_parts.and_more_user_text": " vΓ  {{$1}} người dΓΉng nα»―a", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_link": "TαΊ‘o kΓͺnh riΓͺng tΖ°", + "components.locked_features.locked_guests_popup.description": "RαΊ₯t tiαΊΏc !! CΓ³ vαΊ» nhΖ° bαΊ‘n muα»‘n mời người dΓΉng bΓͺn ngoΓ i vΓ o khΓ΄ng gian lΓ m việc cα»§a mΓ¬nh. BαΊ‘n cΓ³ thể muα»‘n xem xΓ©t nΓ’ng cαΊ₯p gΓ³i cα»§a mΓ¬nh nαΊΏu bαΊ‘n muα»‘n cα»™ng tΓ‘c vα»›i khΓ‘ch vΓ  Δ‘α»‘i tΓ‘c bΓͺn ngoΓ i. KhΓ‘m phΓ‘ cΓ‘c tΓΉy chọn Δ‘α»‹nh giΓ‘ cα»§a chΓΊng tΓ΄i vΓ  chọn tΓΉy chọn tα»‘t nhαΊ₯t cho nhu cαΊ§u cα»™ng tΓ‘c nhΓ³m cα»§a bαΊ‘n.", + "components.on_boarding.company_billing_banner.admin_or_owner_text": "CΓ³ vαΊ₯n đề vα»›i gΓ³i Δ‘Δƒng kΓ½ cho cΓ΄ng cΓ΄ng ty cα»§a bαΊ‘n. LΓ m Ζ‘n hΓ£y kiểm tra", + "components.on_boarding.company_billing_banner.guest_or_member_text": "CΓ³ vαΊ₯n đề vα»›i gΓ³i Δ‘Δƒng kΓ½ cho cΓ΄ng cΓ΄ng ty cα»§a bαΊ‘n. LΓ m Ζ‘n hΓ£y liΓͺn hệ vα»›i chα»§ sở hα»―u hoαΊ·c quαΊ£n trα»‹ viΓͺn cα»§a cΓ΄ng ty!", + "components.on_boarding.popups.blocked_company.learn_more_text": "Muα»‘n tΓ¬m hiểu thΓͺm về cΓ‘c gΓ³i Δ‘Δƒng kΓ½ cho cΓ΄ng ty?", + "scenes.apps.messages.message.parts.deleted_content.text": "{{$1}} Δ‘Γ£ xΓ³a tin nhαΊ―n cα»§a mΓ¬nh", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_input_placeholder": "BαΊ‘n khΓ΄ng thể thΓͺm quΓ‘ 10 người dΓΉng", + "scenes.apps.drive.add_button": "ThΓͺm", + "scenes.apps.messages.messageslist.get_writing_user": "Δ‘ang nhαΊ­p...", + "scenes.apps.drive.top_menu_more": "TiαΊΏp", + "scenes.apps.drive.top_menu_no_items": "{{$1}} thα»©", + "scenes.apps.messages.new_thread": "BαΊ―t Δ‘αΊ§u mα»™t cuα»™c trΓ² chuyện mα»›i", + "scenes.apps.tasks.board.tasks.use_starttime": "Đặt thời gian bαΊ―t Δ‘αΊ§u", + "scenes.apps.tasks.board.tasks.in_list": "Trong danh sΓ‘ch", + "scenes.apps.tasks.board.starts": "BαΊ―t Δ‘αΊ§u", + "components.notifications.hidden_notifications_button.children": "Tin nhαΊ―n mα»›i", + "components.newversion.new_version_modal.title": "BαΊ£n cαΊ­p nhαΊ­t mα»›i Δ‘Γ£ sαΊ΅n sΓ ng!", + "components.unverified_account.re_send_email": "KhΓ΄ng nhαΊ­n được thΖ°?", + "components.verify_mail.button": "ThΓͺm người dΓΉng", + "components.locked_features.locked_guests_popup.or": "HoαΊ·c", + "components.emoji_picker.categories.travel_and_places": "Du lα»‹ch & Địa Δ‘iểm", + "scenes.apps.drive.viewer.edit_with_button": "Sα»­a vα»›i {{$1}}", + "services.apps.calendar.event_icon": "Sα»± kiện", + "scenes.apps.account.account.fullname": "TΓͺn Δ‘αΊ§y Δ‘α»§", + "scenes.app.popup.workspaceparameter.pages.logo_company_modify_description": "Sα»§a αΊ£nh cα»§a cΓ΄ng ty ", + "scenes.apps.calendar.modals.event_title_placeholder": "TiΓͺu đề", + "scenes.apps.calendar.modals.modify_event_button": "Sα»­a sα»± kiện", + "scenes.apps.calendar.modals.part.participants": "Người tham gia", + "scenes.apps.messages.message.new_messages_bar": "Tin nhαΊ―n mα»›i", + "scenes.app.mainview.link_expired": "Đường dαΊ«n nΓ y Δ‘Γ£ bα»‹ hαΊΏt hαΊ‘n hoαΊ·c khΓ΄ng hợp lệ.", + "scenes.app.mainview.create_account": "TαΊ‘o khΓ΄ng gian lΓ m việc miα»…n phΓ­ trΓͺn ", + "components.searchpopup.tags": "ThαΊ»", + "scenes.app.popup.workspaceparameter.pages.show_button": "HIển thα»‹", + "scenes.apps.calendar.my_calendar": "Lα»‹ch cα»§a tΓ΄i", + "scenes.apps.calendar.no_connectors_menu_text": "BαΊ‘n khΓ΄ng cΓ³ Δ‘αΊ§u mα»‘i nΓ o để liΓͺn kαΊΏt Δ‘αΊΏn lα»‹ch", + "scenes.apps.messages.message.types.first_message_text": "ĐÒy lΓ  tin nhαΊ―n Δ‘αΊ§u tiΓͺn", + "components.workspace.calendar.invalid": "Sai", + "scenes.apps.messages.input.edited": "Đã sα»­a", + "scenes.apps.calendar.modals.title_placeholder": "TΓͺn sα»± kiện", + "components.locked_features.locked_workspace_popup.title": "BαΊ‘n khΓ΄ng thể tαΊ‘o mα»›i thΓͺm khΓ΄ng gian lΓ m việc", + "components.searchpopup.creation": "Khởi tαΊ‘o", + "components.searchpopup.update_search": "CαΊ­p nhαΊ­t tΓ¬m kiαΊΏm", + "scenes.apps.drive.new_link_title": "LiΓͺn kαΊΏt mα»›i", + "scenes.apps.tasks.my_tasks": "CΓ΄ng việc cα»§a tΓ΄i", + "components.upload.drop_files": "KΓ©o thαΊ£ file cα»§a bαΊ‘n vΓ o Δ‘Γ’y", + "scenes.apps.messages.input.emoji": "Biểu tượng", + "scenes.apps.tasks.board.place_holder": "TΓͺn bαΊ£ng", + "components.searchpopup.loading": "TαΊ£i thΓͺm kαΊΏt quαΊ£", + "scenes.apps.drive.go_trash_menu": "Đi Δ‘αΊΏn thΓΉng rΓ‘c", + "components.locked_features.locked_workspace_popup.subtitle": "Khi ở gΓ³i miα»…n phΓ­, bαΊ‘n chỉ cΓ³ thể tαΊ‘o mα»™t khΓ΄ng gian lΓ m việc.", + "scenes.error_on_twake": "\"Houston chΓΊng tΓ΄i Δ‘ang gαΊ·p mα»™t vαΊ₯n đề\"", + "scenes.login.verifymail.alert": "ChΓΊng tΓ΄i Δ‘ang kiểm tra email cα»§a bαΊ‘n!", + "scenes.no_panic": "Đừng lo! Chỉ cαΊ§n tαΊ£i lαΊ‘i trang để sα»­a lα»—i.", + "scenes.apps.calendar.unconfigured_tab": "Tab nΓ y chΖ°a được cαΊ₯u hΓ¬nh.", + "scenes.apps.messages.input.send_message": "Gα»­i tin nhαΊ―n", + "components.drive.new_versions": "ThΓͺm mα»™t phiΓͺn bαΊ£n mα»›i", + "scenes.app.popup.appsparameters.pages.title_informations": "ThΓ΄ng tin cΖ‘ bαΊ£n", + "general.resume": "TΓ³m lược", + "scenes.app.popup.workspaceparameter.pages.title": "CΓ i Δ‘αΊ·t khΓ΄ng gian lΓ m việc", + "scenes.app.popup.workspaceparameter.pages.webhooks_access_subtitle": "Try cαΊ­p webhooks", + "scenes.app.popup.workspaceparameter.pages.weight_max_small_text": "KΓ­ch cα»‘ tα»‘i Δ‘a 5Mb", + "scenes.app.workspacesbar.components.change_company_title": "Đổi cΓ΄ng ty", + "scenes.app.workspacesbar.components.create_company_menu": "TαΊ‘o cΓ΄ng ty mα»›i", + "scenes.apps.calendar.add_calendar_menu": "ThΓͺm lα»‹ch", + "scenes.apps.calendar.connectors_menu": "Đầu nα»‘i", + "scenes.apps.calendar.connectors_search_menu": "TÌm Δ‘αΊ§u nα»‘i", + "scenes.apps.calendar.create_calendar_title": "TαΊ‘o lα»‹ch", + "scenes.apps.calendar.day_option": "NgΓ y", + "scenes.apps.calendar.edit_calendar_title": "Sα»§a lα»‹ch", + "scenes.apps.calendar.modals.reminders": "ThΓ΄ng bΓ‘o", + "scenes.apps.calendar.modals.remove_event_text": "XΓ³a sα»± kiện nΓ y?", + "scenes.apps.calendar.modify_calendar_menu": "Sα»­a lα»‹ch", + "scenes.apps.calendar.my_calendar_label": "Lα»‹ch cα»§a tΓ΄i", + "scenes.apps.calendar.no_calendar_text": "BαΊ‘n khΓ΄ng cΓ³ lα»‹ch nΓ o cho khΓ΄ng gian lΓ m việc nΓ y", + "scenes.apps.calendar.remove_calendar_confirmation": "XΓ³a lα»‹ch vΓ  sα»± kiện nΓ y vΔ©nh viα»…n", + "scenes.apps.calendar.today_menu": "HΓ΄m nay", + "scenes.apps.drive.restore_menu": "KhΓ΄i phα»₯c", + "scenes.apps.messages.message.pin_button": "Ghim tin nhαΊ―n", + "scenes.apps.messages.message.unpin_button": "Gα»‘ ghim tin nhαΊ―n", + "scenes.apps.messages.message.copy_link": "Copy vΓ  gα»­i đường dαΊ«n", + "scenes.apps.messages.message.pinned": "Đã ghim", + "scenes.apps.messages.messageslist.get_writing_users": "Δ‘ang nhαΊ­p...", + "scenes.apps.messages.messageslist.go_last_message_button": "Đi Δ‘αΊΏn tin nhαΊ―n mα»›i nhαΊ₯t", + "scenes.apps.messages.messageslist.go_last_message_button.new_messages": "Tin nhαΊ―n mα»›i", + "scenes.login.verifymail.signin_button": "Đăng nhαΊ­p", + "scenes.app.popup.workspaceparameter.pages.cancel_invitation": "Hα»§y lời mời", + "login.email_login": "E-mail/Đăng nhαΊ­p", + "scenes.apps.account.account.send_info": "Gα»­i thΓ΄ng tin Δ‘Δƒng nhαΊ­p cho người dΓΉng.", + "scenes.apps.calendar.modals.reminder_add": "TαΊ‘o mα»™t nhαΊ―c nhở", + "scenes.app.taskpicker.select": "Chọn", + "components.listmanager.filter": "Lọc", + "components.newversion.new_version_component.link": "NhαΊ₯n vΓ o Δ‘Γ’y để tαΊ£i lαΊ‘i", + "scenes.apps.drive.download_all_button": "TαΊ£i toΓ n bα»™", + "components.inputs.input_with_select.input.placeholder": "TΓͺn kΓͺnh", + "general.re_send": "Gα»­i lαΊ‘i", + "components.richtexteditor.toolbar.bold": "In Δ‘αΊ­m", + "components.richtexteditor.toolbar.strikethrough": "GαΊ‘ch ngang", + "components.richtexteditor.toolbar.code": "MΓ£", + "general.pause": "TαΊ‘m dα»«ng", + "scenes.app.popup.workspaceparameter.pages.worspace_notif": "KhΓ΄ng gian lΓ m việc", + "scenes.app.workspacesbar.components.grp_parameters": "{{$1}} cΓ i Δ‘αΊ·t", + "scenes.apps.calendar.export_view_menu": "XuαΊ₯t chαΊΏ Δ‘α»™ xem...", + "scenes.apps.messages.message.show_button": "Hiển thα»‹", + "components.drive.right_preview.create_link": "TαΊ‘o mα»™t đường dαΊ«n truy cαΊ­p", + "scenes.app.popup.workspaceparameter.pages.withdraw_button": "XΓ³a khỏi khΓ΄ng gian lΓ m việc nΓ y", + "scenes.app.popup.workspaceparameter.payments_subscriptions_title": "PhΖ°Ζ‘ng thα»©c thanh toΓ‘n vΓ  gΓ³i thuΓͺ bao", + "scenes.apps.drive.new_file_menu": "TαΊ‘o file mα»›i", + "scenes.apps.drive.new_file_title": "TαΊ‘o file mα»›i", + "scenes.apps.drive.remove_definitely_menu": "XΓ³a vΔ©nh viα»…n", + "scenes.apps.drive.viewer.no_preview_message": "KhΓ΄ng thể đọc được loαΊ‘i tệp nΓ y.", + "scenes.apps.messages.message.show_responses_button": "Xem tαΊ₯t cαΊ£ cΓ‘c cΓ’u trαΊ£ lời", + "scenes.apps.messages.message.reply_button": "TrαΊ£ lời", + "scenes.apps.calendar.export_title": "XuαΊ₯t", + "scenes.apps.calendar.ics_download_menu": "TαΊ£i file ICS", + "scenes.apps.calendar.modals.advanced_options": "TΓΉy chọn nΓ’ng cao", + "scenes.apps.calendar.modals.participants_event": "Người tham gia", + "scenes.apps.calendar.modals.remove_event_button": "XΓ³a sα»± kiện", + "scenes.apps.drive.throw_menu": "Bỏ vΓ o thΓΉng rΓ‘c", + "scenes.apps.drive.unconfigured_tab": "Cα»­a sα»• nΓ y chΖ°a được cΓ i Δ‘αΊ·t.", + "scenes.apps.drive.viewer.loading_preview_message": "Đang xα»­ lΓ½...", + "scenes.apps.drive.viewer.open_with_button": "Mở tệp nΓ y vα»›i...", + "scenes.apps.messages.just_you": "Chỉ hiển thα»‹ cho bαΊ‘n", + "scenes.apps.messages.input.show_formatting": "Hiện Δ‘α»‹nh dαΊ‘ng", + "services.user.notification_parameters_update_alert": "CΓ i Δ‘αΊ·t cα»§a chα»©c nΔƒng thΓ΄ng bΓ‘o Δ‘Γ£ được thay Δ‘α»•i.", + "services.user.update_password_alert": "MαΊ­t khαΊ©u cα»§a bαΊ‘n Δ‘Γ£ được thay Δ‘α»•i.", + "scenes.app.workspaces.components.skip": "Bỏ qua", + "scenes.apps.messages.input.hide_formatting": "αΊ¨n Δ‘α»‹nh dαΊ‘ng", + "scenes.apps.account.account.save": "LΖ°u tΓ i khoαΊ£n", + "scenes.apps.parameters.workspace_sections.members.invite_all": "Mời tαΊ₯t cαΊ£", + "components.workspace.list_manager.all": "TαΊ₯t cαΊ£", + "components.emoji_picker.categories.symbols": "Biểu tượng", + "components.emoji_picker.categories.not_found": "KhΓ΄ng cΓ³ biểu tuợng nΓ o", + "components.locked_features.locked_only_office_popup.title": "BαΊ‘n khΓ΄ng thể sα»­a file nΓ y", + "components.locked_features.locked_drive_popup.title": "BαΊ‘n Δ‘Γ£ hαΊΏt dung lượng drive", + "scenes.client.channelbar.channelmemberslist.tag": "BαΊ‘n", + "components.richtexteditor.toolbar.italic": "NghiΓͺng", + "scenes.apps.messages.message.activity_message.a_deleted_channel_tab": "{{$1}} Δ‘Γ£ xΓ³a {{$2}} tab {{$3}}", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.tag": "BαΊ‘n khΓ΄ng phαΊ£i lΓ  thΓ nh viΓͺn", + "general.verify": "XΓ‘c thα»±c", + "components.unverified_account.typography_text_danger": "HΓ£y xΓ‘c minh tΓ i khoαΊ£n trong vΓ²ng {{$ 1}} ngΓ y. TΓ i khoαΊ£n dΓΉng thα»­ sαΊ½ bα»‹ khΓ³a sau 7 ngΓ y vΓ  xΓ³a vΔ©nh viα»…n sau 1 thΓ‘ng Δ‘Δƒng kΓ½. BαΊ‘n cΓ³ thể xΓ‘c minh tΓ i khoαΊ£n cα»§a mΓ¬nh bαΊ±ng cΓ‘ch nhαΊ₯p vΓ o nΓΊt \"XΓ‘c minh tΓ i khoαΊ£n cα»§a tΓ΄i\" trong email xΓ‘c minh mΓ  chΓΊng tΓ΄i Δ‘Γ£ gα»­i cho bαΊ‘n.", + "scenes.app.popup.workspaceparameter.edit_from_console": "Xem trong bαΊ£ng Δ‘iều khiển", + "components.on_boarding.popups.blocked_company.description": "GΓ³i Δ‘Δƒng kΓ½ Twake cα»§a bαΊ‘n hαΊΏt hαΊ‘n. HΓ£y liΓͺn hệ vα»›i chα»§ sở hα»― cΓ΄ng ty hoαΊ·c quαΊ£n trα»‹ viΓͺn để kiểm tra vΓ  để tiαΊΏp tα»₯c cΓ³ thể trao Δ‘α»•i vα»›i nhΓ³m cα»§a bαΊ‘n!", + "components.richtexteditor.toolbar.underline": "GαΊ‘ch chΓ’n", + "scenes.app.popup.appsparameters.pages.smalltext_workspace_id": "MΓ£ Δ‘α»‹nh danh khΓ΄ng gian lΓ m việc hiện tαΊ‘i", + "scenes.app.mainview.channel_description": "MΓ΄ tαΊ£ kΓͺnh", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_edition": "Đổi tΓͺn{{$1}}", + "components.on_boarding.popups.blocked_company.company_selector": "Chuyển cΓ΄ng ty khΓ‘c", + "scenes.login.verifymail.error_message": "CΓ³ lα»—i Δ‘Γ£ xαΊ£y ra", + "scenes.apps.calendar.ics_subscription_menu": "LαΊ₯y đường link tα»›i file ICS", + "scenes.apps.messages.message.types.first_channel_message_text": "ĐÒy lΓ  tin nhαΊ―n Δ‘αΊ§u tiΓͺn cα»§a kΓͺnh", + "scenes.apps.drive.trash_empty_menu": "LΓ m trα»‘ng thΓΉng rΓ‘c", + "scenes.apps.messages.input.placeholder": "Để lαΊ‘i tin nhαΊ―n. DΓΉng @ để trΓ­ch dαΊ«n người dΓΉng.", + "scenes.app.popup.workspaceparameter.pages.write_access_subtitle": "Quyền được thay Δ‘α»•i", + "scenes.apps.drive.trash": "ThΓΉng rΓ‘c", + "scenes.tell_us": "HΓ£y cho chΓΊng tΓ΄i biαΊΏt bαΊ‘n Δ‘Γ£ thao tΓ‘c nhΖ° thαΊΏ nΓ o:", + "scenes.client.channelbar.channelmemberslist.loader": "TαΊ£i thΓͺm", + "scenes.app.channelsbar.hide_discussion_leaving.menu": "αΊ¨n thαΊ£o luαΊ­n", + "components.account_verication_status_unverified": "ChΖ°a xΓ‘c minh", + "components.drive.navigators.directory_not_found": "KhΓ΄ng tΓ¬m thαΊ₯y đường dαΊ«n.", + "components.emoji_picker.categories.frequently_used": "Được dΓΉng thường xuyΓͺn", + "components.emoji_picker.categories.smileys_and_people": "MαΊ·t cười & Con người", + "components.emoji_picker.categories.animals_and_nature": "Động vαΊ­t & ThiΓͺn nhiΓͺn", + "scenes.apps.drive.no_storage_app_alert": "BαΊ‘n khΓ΄ng cΓ³ α»©ng dα»₯ng nΓ o để được cαΊ₯p quyền tαΊ‘o α»• cα»©ng ngoΓ i.", + "scenes.apps.tasks.no_connector": "KhΓ΄ng cΓ³ kαΊΏt nα»‘i", + "components.searchpopup.enter_text": "Điền mα»™t vΓ i tα»« để tΓ¬m trong Twake.", + "components.emoji_picker.categories.flags": "ĐÑnh dαΊ₯u", + "components.emoji_picker.categories.search_result": "KαΊΏt quαΊ£ tΓ¬m kiαΊΏm", + "components.locked_features.locked_only_office_popup.subtitle": "Ở gΓ³i miα»…n phΓ­, bαΊ‘n khΓ΄ng thể sα»­ dα»₯ng onlyoffice.", + "components.locked_features.locked_drive_popup.subtitle": "Ở gΓ³i miα»…n phΓ­, bαΊ‘n chỉ cΓ³ thể lΖ°u trα»― tα»‘i Δ‘a 6GB.", + "scenes.apps.drive.no_file_alert": "BαΊ‘n khΓ΄ng cΓ³ α»©ng dα»₯ng nΓ o để cΓ³ thể cαΊ₯p quyền tαΊ‘o tệp.", + "components.alert.confirm": "XΓ‘c nhαΊ­n hΓ nh Δ‘α»™ng cα»§a bαΊ‘n", + "components.locked_features.locked_workspace_popup.text": "Whoops!!BαΊ‘n muα»‘n tαΊ‘o thΓͺm khΓ΄ng gian lΓ m việc mα»›i? HΓ£y cΓ’n nhαΊ―c Δ‘Δƒng kΓ­ gΓ³i cao hΖ‘n. KhΓ‘m phΓ‘ cΓ‘c gΓ³i cα»§a chΓΊng tΓ΄i vΓ  chọn gΓ³i phΓΉ hợp nhαΊ₯t vα»›i nhu cαΊ§u cα»§a cΓ΄ng ty bαΊ‘n.", + "scenes.app.popup.adduser.magiclinks.genrator_info": "LiΓͺn kαΊΏt lời mời Δ‘αΊΏn khΓ΄ng gian lΓ m việc", + "scenes.app.popup.adduser.magiclinks.new_link_generated": "LiΓͺn kαΊΏt mα»›i được tαΊ‘o", + "scenes.app.popup.adduser.magiclinks.copied_to_clipboard": "Đã sao chΓ©p thΓ nh cΓ΄ng vΓ o bα»™ nhα»› tαΊ‘m", + "scenes.app.popup.adduser.magiclinks.action_copy": "Sao chΓ©p", + "scenes.app.popup.adduser.magiclinks.action_generate": "TαΊ‘o ra", + "scenes.apps.board.new_task": "+ CΓ΄ng việc mα»›i", + "components.alert.confirm_click": "XΓ‘c nhαΊ­n hΓ nh Δ‘α»™ng cα»§a bαΊ‘n bαΊ±ng cΓ‘ch nhαΊ₯p vΓ o OK.", + "components.searchpopup.tasks": "CΓ΄ng việc", + "scenes.app.mainview.advanced_search_placeholder": "TΓ¬m kiαΊΏm nΓ’ng cao", + "components.searchpopup.hide_filters": "αΊ©n bα»™ lọc", + "components.searchpopup.show_filters": "hiện bα»™ lọc", + "components.searchpopup.load_more": "TαΊ£i thΓͺm kαΊΏt quαΊ£", + "general.more": "ThΓͺm", + "scenes.apps.board.archived_tasks": "CΓ΄ng việc Δ‘Γ£ lΖ°u trα»― ({{$ 1}})", + "scenes.apps.board.active_tasks": "CΓ΄ng việc Δ‘ang thα»±c hiện", + "scenes.apps.board.kanban": "Kanban", + "scenes.apps.board.display_as": "Hiển thα»‹ dΖ°α»›i dαΊ‘ng", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.version_item": "PhiΓͺn bαΊ£n", + "components.reminder.hours_bef": "giờ trΖ°α»›c", + "components.reminder.days_bef": "ngΓ y hΓ΄m trΖ°α»›c", + "components.reminder.weeks_bef": "vΓ i tuαΊ§n trΖ°α»›c", + "components.reminder.by_email": "E-mail", + "scenes.apps.calendar.reminders": "(cΓ‘c) lời nhαΊ―c nhở", + "scenes.apps.calendar.video_link": "NhαΊ₯p để mở liΓͺn kαΊΏt", + "scenes.app.mainview.discussion": "ThαΊ£o luαΊ­n", + "components.tagpicker.notag": "KhΓ΄ng cΓ³ thαΊ»", + "scenes.apps.tasks.modals.attachments": "TαΊ­p tin Δ‘Γ­nh kΓ¨m", + "components.calendar.calendarselector.from": "Tα»«", + "components.attachmentpicker.from_computer": "Tα»« thiαΊΏt bα»‹ cα»§a bαΊ‘n", + "components.attachmentpicker.from_twake": "Tα»« tΓ i liệu Twake", + "components.attachmentpicker.file": "TαΊ­p tin", + "components.attachmentpicker.remove_attach": "XΓ³a tệp Δ‘Γ­nh kΓ¨m", + "components.drive.elements.see": "NhΓ¬n thαΊ₯y", + "components.drive.elements.current_name": "TΓͺn thαΊ­t: ", + "scenes.app.integrations_parameters.company_application_popup.btn": "CΓ i Δ‘αΊ·t", + "scenes.app.integrations_parameters.company_application_popup.tab_btn_info": "ThΓ΄ng tin", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.website_item": "Trang mαΊ‘ng", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.created_item": "NgΓ y thΓ nh lαΊ­p", + "scenes.app.integrations_parameters.company_applications_table.more_menu.show_application": "Chi tiαΊΏt", + "scenes.app.integrations_parameters.company_applications_table.more_menu.remove_application": "XΓ³a khỏi cΓ΄ng ty", + "scenes.app.integrations_parameters.company_applications_table.title": "Đã cΓ i Δ‘αΊ·t trong cΓ΄ng ty cα»§a bαΊ‘n", + "app.state.recoil.hooks.use_current_company_applications.toaster_delete": "Đã xΓ³a thΓ nh cΓ΄ng {{$1}} khỏi cΓ΄ng ty cα»§a bαΊ‘n", + "app.state.recoil.hooks.use_current_company_applications.toaster_add": "Đã thΓͺm thΓ nh cΓ΄ng {{$1}} vΓ o cΓ΄ng ty cα»§a bαΊ‘n", + "components.reminder.notification": "ThΓ΄ng bΓ‘o", + "scenes.join.loading": "Đang tαΊ£i…", + "scenes.join.wrong_link_title": "LiΓͺn kαΊΏt nΓ y khΓ΄ng cΓ²n nα»―a", + "scenes.join.wrong_link_description": "YΓͺu cαΊ§u người Δ‘Γ£ mời bαΊ‘n tham gia cΓ΄ng ty nΓ y để cΓ³ liΓͺn kαΊΏt mα»›i hoαΊ·c tαΊ‘o cΓ΄ng ty cα»§a riΓͺng bαΊ‘n", + "scenes.join.create_the_company_button": "TαΊ‘o cΓ΄ng ty", + "scenes.join.join_workspace_from_company": "Tham gia {{$1}} tα»« {{$2}}!", + "scenes.join.twake_description": "Twake lΓ  mα»™t khΓ΄ng gian lΓ m việc kα»Ή thuαΊ­t sα»‘ mΓ£ nguα»“n mở được xΓ’y dα»±ng để cαΊ£i thiện nΔƒng suαΊ₯t nhΓ³m cα»§a bαΊ‘n", + "scenes.join.login_first_button": "Đăng nhαΊ­p hoαΊ·c tαΊ‘o tΓ i khoαΊ£n trΖ°α»›c", + "scenes.join.join_the_team_button": "Tham gia nhΓ³m", + "scenes.apps.drive.move_text2": "Di chuyển", + "scenes.apps.drive.remove_attachs": "XΓ³a tệp Δ‘Γ­nh kΓ¨m", + "scenes.app.popup.createcompany.try_again": "Vui lΓ²ng thα»­ lαΊ‘i.", + "scenes.apps.drive.right_preview.public": "Quyền truy cαΊ­p cΓ΄ng khai", + "components.drive.elements.configurate_mod": "Định cαΊ₯u hΓ¬nh mod ...", + "components.drive.elements.manage_version": "QuαΊ£n lΓ½ cΓ‘c phiΓͺn bαΊ£n", + "scenes.app.popup.workspace.edit_temp": "Chỉnh sα»­a tΓ i khoαΊ£n tαΊ‘m thời", + "scenes.app.popup.workspace.create_temp": "TαΊ‘o tΓ i khoαΊ£n tαΊ‘m thời", + "scenes.apps.tasks.active_tasks": "nhiệm vα»₯ tΓ­ch cα»±c", + "scenes.apps.drive.right_preview.versions": "PhiΓͺn bαΊ£n", + "scenes.app.popup.appsparameters.pages.apps_connectors_small_text": "QuαΊ£n lΓ½ cΓ‘c α»©ng dα»₯ng vΓ  trΓ¬nh kαΊΏt nα»‘i cα»§a bαΊ‘n.", + "scenes.app.popup.appsparameters.pages.icon": "Biểu tượng", + "scenes.app.integrations_parameters.title": "TΓ­ch hợp", + "scenes.app.integrations_parameters.applications_table.title": "CΓ‘c tΓ­ch hợp khΓ‘c", + "scenes.app.integrations_parameters.applications_table.search_placeholder": "Ứng dα»₯ng tΓ¬m kiαΊΏm", + "scenes.app.integrations_parameters.company_application_popup.tag": "CΓ i Δ‘αΊ·t", + "scenes.apps.board.all_boards": "TαΊ₯t cαΊ£ cΓ‘c bαΊ£ng", + "components.userlistmanager.no_users": "KhΓ΄ng cΓ³ người dΓΉng.", + "scenes.apps.drive.used": "được sα»­ dα»₯ng trong thΖ° mα»₯c nΓ y", + "components.reminder.minutes_bef": "phΓΊt trΖ°α»›c", + "login.create_account": "TαΊ‘o tΓ i khoαΊ£n", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.label": "KhΓ΄ng gian lΓ m việc mαΊ·c Δ‘α»‹nh", + "\"": "\"", + "scenes.app.workspaces.welcome_page.no_workspace_subtitle": "ChΖ°a cΓ³ ai mời bαΊ‘n vΓ o khΓ΄ng gian lΓ m việc.", + "scenes.apps.messages.message.types.no_message_in_thread": "ChΖ°a cΓ³ ai trαΊ£ lời.", + "'": "'", + "login.login_error": "Lα»—i khi Δ‘Δƒng nhαΊ­p", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.description": "Tα»± Δ‘α»™ng mời tαΊ₯t cαΊ£ người dΓΉng khΓ΄ng gian lΓ m việc vΓ o kΓͺnh nΓ y", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.title": "BαΊ‘n sαΊ―p xΓ³a {{$1}}", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.alert_total_members": "BαΊ‘n vαΊ«n cΓ²n thΓ nh viΓͺn {{$1}} trong {{$2}}. BαΊ‘n nΓͺn xΓ³a tαΊ₯t cαΊ£ cΓ‘c thΓ nh viΓͺn để cΓ³ thể xΓ³a khΓ΄ng gian lΓ m việc nΓ y.", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.checkbox": "TΓ΄i hiểu rαΊ±ng tαΊ₯t cαΊ£ cΓ‘c tin nhαΊ―n vΓ  tệp trong khΓ΄ng gian lΓ m việc cα»§a tΓ΄i sαΊ½ bα»‹ xΓ³a.", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.max_size": "KΓ­ch thΖ°α»›c biều tượng tα»‘i Δ‘a lΓ  5mb", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.bad_format": "Định dαΊ‘ng sai, chỉ cho phΓ©p png gif vΓ  jpg", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.unknown": "Lα»—i khΓ΄ng rΓ΅", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.prefix": "Lα»—i", + "scenes.app.channelsbar.currentuser.reset": "CΓ i lαΊ‘i", + "components.rich_text_editor.plugins.suggestions.default_message.display_results": "ViαΊΏt Γ­t nhαΊ₯t ba chα»― cΓ‘i để hiển thα»‹ người dΓΉng", + "components.rich_text_editor.plugins.suggestions.default_message.no_user_found": "KhΓ΄ng tΓ¬m thαΊ₯y người dΓΉng", + "components.rich_text_editor.plugins.suggestions.default_message.no_emoji_found": "KhΓ΄ng tΓ¬m thαΊ₯y biểu tượng cαΊ£m xΓΊc", + "components.rich_text_editor.plugins.suggestions.default_message.no_command_found": "KhΓ΄ng tΓ¬m thαΊ₯y lệnh", + "scenes.app.messages.input.parts.is_writing.message.user_is_writing": "{{$1}} Δ‘ang viαΊΏt ...", + "scenes.app.messages.input.parts.is_writing.message.users_are_writing": "{{$1}} vΓ  {{$2}} Δ‘ang viαΊΏt ...", + "scenes.app.messages.input.parts.is_writing.message.users_and_more_are_writing": "{{$1}}, {{$2}} vΓ  {{$3}} người dΓΉng khΓ‘c Δ‘ang viαΊΏt ...", + "components.locked_features_components.locked_invite_alert.message_part_1": "CΓ΄ng ty cα»§a bαΊ‘n Δ‘Γ£ Δ‘αΊ‘t Δ‘αΊΏn giα»›i hαΊ‘n tα»‘i Δ‘a lΓ  {{$1}} thΓ nh viΓͺn. Xin vui lΓ²ng ", + "components.locked_features_components.locked_invite_alert.message_link": "nΓ’ng cαΊ₯p cΓ΄ng ty cα»§a bαΊ‘n", + "components.locked_features_components.locked_invite_alert.message_part_2": " để mời thΓͺm thΓ nh viΓͺn.", + "components.locked_features_components.locked_invite_alert.message_magic_link": " liΓͺn hệ vα»›i chα»§ sở hα»―u hoαΊ·c quαΊ£n trα»‹ viΓͺn cα»§a cΓ΄ng ty bαΊ‘n.", + "views.client.popup.workspace_parameter.pages.workspace_members.link_to_console": "Xem tαΊ₯t cαΊ£ cΓ‘c thΓ nh viΓͺn cΓ΄ng ty cα»§a tΓ΄i trΓͺn bαΊ£ng Δ‘iều khiển", + "scenes.app.popup.appsparameters.pages.amazing_app_description": "MΓ΄ tαΊ£ α»©ng dα»₯ng cα»§a bαΊ‘n bαΊ±ng mα»™t vΓ i tα»«", + "scenes.app.popup.appsparameters.pages.application_creator.title": "TΓ­ch hợp mα»›i", + "scenes.app.popup.appsparameters.pages.application_editor.help_text": "NαΊΏu bαΊ‘n khΓ΄ng biαΊΏt lΓ m thαΊΏ nΓ o để Δ‘iền vΓ o nhα»―ng Δ‘iều nΓ y, hΓ£y truy cαΊ­p ", + "scenes.app.popup.appsparameters.pages.app.private_key": "KhΓ³a cΓ‘ nhΓ’n", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed": "Đã xΓ³a α»©ng dα»₯ng {{$1}} thΓ nh cΓ΄ng!", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed_error": "Lα»—i khi xΓ³a α»©ng dα»₯ng {{$1}}!", + "scenes.app.popup.appsparameters.pages.application_editor.application_published": "Ứng dα»₯ng {{$1}} thΓ nh cΓ΄ng!", + "scenes.app.integrations_parameters.add_application": "TΓ­ch hợp mα»›i", + "scenes.app.integrations_parameters.company_applications_table.more_menu.developer_settings": "CΓ i Δ‘αΊ·t nhΓ  phΓ‘t triển", + "scenes.app.popup.appsparameters.pages.application_creator.checkbox": "TΓ΄i hiểu rαΊ±ng chα»§ sở hα»―u vΓ  quαΊ£n trα»‹ viΓͺn cα»§a cΓ΄ng ty nΓ y sαΊ½ cΓ³ thể sα»­a Δ‘α»•i vΓ  xuαΊ₯t bαΊ£n α»©ng dα»₯ng nΓ y.", + "twake.application.access.title": "Chọn phαΊ‘m vi phΓΉ hợp cho α»©ng dα»₯ng cα»§a bαΊ‘n.", + "twake.application.access.no_default_scopes_available'": "TΓ­ch hợp nΓ y khΓ΄ng cΓ³ bαΊ₯t kα»³ quyền truy cαΊ­p {{$1}} nΓ o", + "scenes.app.popup.appsparameters.pages.application_editor.help_link": "tΓ i liệu API Twake", + "components.rich_text_editor.plugins.suggestions.loading": "TΓ¬m kiαΊΏm thΓͺm", + "components.open_desktop_popup.subtitle": "được mở trong α»©ng dα»₯ng Twake", + "components.open_desktop_popup.open_here_link": "Thay vΓ o Δ‘Γ³ hΓ£y mở ở Δ‘Γ’y", + "molecules.download_banner.title": "TαΊ­n dα»₯ng tα»‘i Δ‘a twake, tαΊ£i xuα»‘ng α»©ng dα»₯ng dΓ nh cho mΓ‘y tΓ­nh để bΓ n ngay bΓ’y giờ", + "molecules.download_banner.download_button": "TαΊ£i xuα»‘ng α»©ng dα»₯ng dΓ nh cho mΓ‘y tΓ­nh để bΓ n", + "scenes.app.channelsbar.channel_copy_link": "Sao chΓ©p liΓͺn kαΊΏt kΓͺnh", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.success.update": "CαΊ­p nhαΊ­t thΓ nh cΓ΄ng", + "components.searchpopup.no_results_for": "KhΓ΄ng cΓ³ kαΊΏt quαΊ£ cho", + "components.searchpopup.try_new_search": "Thα»­ mα»™t tΓ¬m kiαΊΏm mα»›i", + "components.searchpopup.all": "TαΊ₯t cαΊ£ cΓ‘c", + "components.searchpopup.chats": "TrΓ² chuyện", + "components.searchpopup.media": "PhΖ°Ζ‘ng tiện truyền thΓ΄ng", + "components.searchpopup.files": "CΓ‘c tαΊ­p tin", + "components.searchpopup.recent_chats": "CΓ‘c cuα»™c trΓ² chuyện gαΊ§n Δ‘Γ’y", + "components.searchpopup.recent_media": "PhΖ°Ζ‘ng tiện truyền thΓ΄ng gαΊ§n Δ‘Γ’y", + "components.searchpopup.recent_files": "Tệp gαΊ§n Δ‘Γ’y", + "components.searchpopup.recent_channels_and_contacts": "CΓ‘c kΓͺnh vΓ  Δ‘α»‹a chỉ liΓͺn hệ gαΊ§n Δ‘Γ’y", + "components.searchpopup.header_title": "TΓ¬m kiαΊΏm", + "components.searchpopup.scope.company": "trong tαΊ₯t cαΊ£ cΓ‘c cΓ΄ng ty", + "components.searchpopup.messages": "Tin nhαΊ―n", + "components.searchpopup.scope.channel": "trong kΓͺnh nΓ y", + "components.searchpopup.channels": "KΓͺnh chat", + "components.searchpopup.start_search": "NhαΊ­p mα»™t vΓ i tα»« khΓ³a để bαΊ―t Δ‘αΊ§u tΓ¬m kiαΊΏm.", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace": "ThΓͺm vΓ o kΓͺnh vΓ  khΓ΄ng gian lΓ m việc vα»›i tΖ° cΓ‘ch thΓ nh viΓͺn", + "scenes.client.join_public_channel": "Tham gia kΓͺnh nΓ y", + "scenes.client.join_public_channel.info": "BαΊ‘n khΓ΄ng phαΊ£i lΓ  thΓ nh viΓͺn cα»§a kΓͺnh trα»±c tiαΊΏp nΓ y. BαΊ₯m vΓ o nΓΊt nΓ y để bαΊ―t Δ‘αΊ§u thαΊ£o luαΊ­n ngay bΓ’y giờ.", + "general.yes": "Đúng", + "general.no": "KhΓ΄ng", + "components.searchpopup.see_more": "Xem thΓͺm", + "scenes.client.channelbar.channelmemberslist.search_invite": "TΓ¬m kiαΊΏm vΓ  mời người dΓΉng vΓ o kΓͺnh nΓ y", + "scenes.client.channelbar.channelmemberslist.search_invite_notice": "KhΓ΄ng cΓ³ nhiều thΓ nh viΓͺn trong kΓͺnh nΓ y. TΓ¬m kiαΊΏm vΓ  mời người dΓΉng ngay bΓ’y giờ bαΊ±ng email hoαΊ·c tΓͺn.", + "scenes.client.channelbar.channelmemberslist.invite_email_button": "Chỉ thΓͺm vΓ o kΓͺnh vα»›i tΖ° cΓ‘ch khΓ‘ch", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace_confirm": "Mời {{$1}} tham gia khΓ΄ng gian lΓ m việc vα»›i tΖ° cΓ‘ch thΓ nh viΓͺn?", + "scenes.client.channelbar.channelmemberslist.search_invite_type_email": "NhαΊ­p Δ‘α»‹a chỉ hợp lệ để mời qua email.", + "scenes.client.channelbar.channelmemberslist.pending_section": "Người dΓΉng Δ‘ang chờ lời mời", + "scenes.client.channelbar.channelmemberslist.members_section": "Người dΓΉng trong kΓͺnh nΓ y", + "scenes.client.channelbar.channelmemberslist.not_members_section": "Người dΓΉng khΓ΄ng cΓ³ trong kΓͺnh nΓ y", + "scenes.client.join_private_channel.info": "Nα»™i dung cα»§a kΓͺnh nΓ y bα»‹ hαΊ‘n chαΊΏ hoαΊ·c khΓ΄ng tα»“n tαΊ‘i. Vui lΓ²ng liΓͺn hệ vα»›i mα»™t thΓ nh viΓͺn cα»§a kΓͺnh nΓ y để được mời.", + "components.open_desktop_popup.open_here_link_forever": "KhΓ΄ng bao giờ cα»‘ mở lαΊ‘i α»©ng dα»₯ng", + "components.channel_attachement_list.medias": "Medias", + "components.channel_attachement_list.files": "CΓ‘c tαΊ­p tin", + "components.channel_attachement_list.title": "Tệp kΓͺnh vΓ  phΖ°Ζ‘ng tiện", + "components.channel_attachement_list.nothing_found": "ChΖ°a cΓ³ gΓ¬ ở Δ‘Γ’y", + "molecules.message_quote.deleted": "Tin nhαΊ―n nΓ y Δ‘Γ£ bα»‹ xΓ³a", + "scenes.apps.messages.jump": "Chuyển Δ‘αΊΏn tin nhαΊ―n", + "components.channel_attachement_list.open": "Mở thΖ° viện", + "scenes.apps.account.on_console": "Để chỉnh sα»­a tΓΉy chọn tΓ i khoαΊ£n toΓ n cαΊ§u cα»§a bαΊ‘n, hΓ£y nhαΊ₯p vΓ o Đi tα»›i BαΊ£ng Δ‘iều khiển.", + "scenes.apps.account.assistant.title": "Trợ lΓ½", + "scenes.apps.account.assistant.description": "Trợ lΓ½ Twake cΓ³ thể hiểu được cΓ΄ng việc hΓ ng ngΓ y cα»§a bαΊ‘n trΓͺn Twake vΓ  cung cαΊ₯p cΓ‘c phΓ­m tαΊ―t vΓ  hΓ nh Δ‘α»™ng thΓ΄ng minh trong ngΓ y cα»§a bαΊ‘n. Trợ lΓ½ lΓ  mα»™t phαΊ§n cα»§a sΓ‘ng kiαΊΏn Work @ Home https://workathome.linagora.com/ vΓ  hiện chỉ Δ‘ang được thα»­ nghiệm trong cΓ΄ng ty Linagora vΓ  Δ‘ang trong giai Δ‘oαΊ‘n học hỏi. NΓ³ cΓ³ nghΔ©a lΓ  chΓΊng tΓ΄i sαΊ½ gα»­i dα»― liệu sα»­ dα»₯ng Twake để Δ‘Γ o tαΊ‘o tΓ­nh nΔƒng trợ lΓ½ trong tΖ°Ζ‘ng lai cα»§a chΓΊng tΓ΄i.", + "scenes.apps.account.assistant.share.nothing": "KhΓ΄ng chia sαΊ» bαΊ₯t kα»³ thα»© gΓ¬ vα»›i trợ lΓ½ (tαΊ―t trợ lΓ½)", + "scenes.apps.account.assistant.share.all": "Chia sαΊ» mọi thα»© bao gα»“m cαΊ£ tin nhαΊ―n vΓ  nα»™i dung tệp", + "scenes.apps.account.assistant.share.metadata": "Chia sαΊ» siΓͺu dα»― liệu nhΖ°ng khΓ΄ng chia sαΊ» nα»™i dung", + "scenes.apps.account.assistant.success": "TΓΉy chọn cα»§a bαΊ‘n Δ‘Γ£ được cαΊ­p nhαΊ­t thΓ nh cΓ΄ng.", + "components.message_seen_by.title": "Người dΓΉng Δ‘Γ£ xem tin nhαΊ―n", + "components.message_seen_by.none_seen_it": "ChΖ°a ai thαΊ₯y tin nhαΊ―n", + "components.message_seen_by.btn": "ThΓ΄ng tin", + "molecules.quoted_content.attachements": "{{$1}} tệp Δ‘Γ­nh kΓ¨m", + "scenes.apps.messages.message.user_deactivated": "BαΊ‘n Δ‘ang xem cΓ‘c kho lΖ°u trα»― cα»§a mα»™t tΓ i khoαΊ£n Δ‘Γ£ bα»‹ hα»§y kΓ­ch hoαΊ‘t", + "general.user.deactivated": "Người dΓΉng khΓ΄ng cΓ²n ở trong cΓ΄ng ty nΓ y", + "general.user.connected": "Trα»±c tuyαΊΏn", + "scenes.app.popup.userparameter.pages.email_notif_delay_never": "KhΓ΄ng bao giờ", + "scenes.app.popup.userparameter.pages.email_notif_delay_quarter_hour": "15 phΓΊt", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_day": "1 ngΓ y", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_hour": "1 giờ", + "scenes.app.popup.userparameter.pages.notification_sound.defaut": "MαΊ·c Δ‘α»‹nh", + "scenes.app.popup.userparameter.pages.notification_sound.none": "KhΓ΄ng cΓ³", + "scenes.client.channelbar.readonly_channel.checkbox": "HαΊ‘n chαΊΏ khαΊ£ nΔƒng ghi", + "scenes.apps.messages.message.forward": "Ở Δ‘αΊ±ng trΖ°α»›c", + "scenes.apps.messages.message.forward.title": "Chuyển tiαΊΏp tin nhαΊ―n", + "scenes.apps.messages.message.forward.comment": "thΓͺm tin nhαΊ―n", + "scenes.apps.messages.message.forward.confirm": "Gα»­i Δ‘αΊΏn $ 1 kΓͺnh", + "scenes.apps.messages.message.forward.send": "Đã chuyển tiαΊΏp tin nhαΊ―n", + "components.channelselector.title": "Chọn kΓͺnh", + "components.channelselector.confirm": "Chọn $ 1 kΓͺnh", + "components.channelselector.search": "TΓ¬m kiαΊΏm kΓͺnh vΓ  thαΊ£o luαΊ­n", + "scenes.app.channelsbar.channel_access": "Quyền truy cαΊ­p kΓͺnh", + "scenes.app.channelsbar.channel_access.save": "LΖ°u cΓ i Δ‘αΊ·t quyền truy cαΊ­p", + "scenes.app.channelsbar.channel_access.readonly": "KΓͺnh chỉ đọc", + "scenes.app.channelsbar.channel_access.readonly.info": "HαΊ‘n chαΊΏ ghi cho người kiểm duyệt, quαΊ£n trα»‹ viΓͺn vΓ  chα»§ sở hα»―u.", + "scenes.app.channelsbar.channel_access.visibility": "Hiển thα»‹ cΓ΄ng khai", + "scenes.app.channelsbar.channel_access.visibility.info": "BαΊ₯t kα»³ ai ngoαΊ‘i trα»« khΓ‘ch cα»§a cΓ΄ng ty đều cΓ³ thể tham gia.", + "scenes.app.channelsbar.channel_access.default": "Tham gia tα»± Δ‘α»™ng", + "scenes.app.channelsbar.channel_access.default.info": "CΓ‘c thΓ nh viΓͺn mα»›i sαΊ½ tα»± Δ‘α»™ng được thΓͺm vΓ o Δ‘Γ’y.", + "scenes.app.channelsbar.channel_information": "Chỉnh sα»­a thΓ΄ng tin kΓͺnh", + "scenes.app.channelsbar.channel_information.logo.add": "TαΊ£i lΓͺn hΓ¬nh αΊ£nh", + "scenes.app.channelsbar.channel_information.logo.remove": "XoΓ‘ hΓ¬nh αΊ£nh", + "scenes.app.channelsbar.channel_information.name": "TΓͺn kΓͺnh", + "scenes.app.channelsbar.channel_information.description": "MΓ΄ tαΊ£ kΓͺnh", + "scenes.app.channelsbar.channel_information.description.placeholder": "MΓ΄ tαΊ£ kΓͺnh, bαΊ‘n cΓ³ thể sα»­ dα»₯ng Δ‘Γ‘nh dαΊ₯u.", + "scenes.app.channelsbar.channel_information.group": "NhΓ³m kΓͺnh", + "scenes.app.channelsbar.channel_information.group.none": "KhΓ΄ng được chọn", + "scenes.app.channelsbar.channel_information.group.new": "TαΊ‘o mα»™t nhΓ³m mα»›i", + "scenes.app.channelsbar.channel_information.group.save": "Đặt nhΓ³m kΓͺnh thΓ nh $ 1", + "scenes.app.channelsbar.channel_information.group.save_none": "KhΓ΄ng Δ‘αΊ·t nhΓ³m kΓͺnh", + "scenes.app.channelsbar.channel_information.save": "LΖ°u thΓ΄ng tin", + "components.invitation.invitation_sent.button": "Gα»­i thΓͺm lời mời", + "scenes.client.channelbar.channelmemberslist.invite_to_workspace": "Mời {{$1}} vΓ o khΓ΄ng gian lΓ m việc ➑", + "components.invitation.reached_limit.text": "bαΊ‘n Δ‘Γ£ Δ‘αΊ‘t Δ‘αΊΏn sα»‘ lượng người dΓΉng tα»‘i Δ‘a trong cΓ΄ng ty cα»§a mΓ¬nh. TΔƒng Δ‘Δƒng kΓ½ cα»§a bαΊ‘n hoαΊ·c thΓͺm nhα»―ng người dΓΉng nΓ y lΓ m khΓ‘ch", + "components.invitation.allow_anyone_by_email.text": "Cho phΓ©p bαΊ₯t kα»³ ai cΓ³ email @ {{$1}} tham gia khΓ΄ng gian lΓ m việc nΓ y", + "components.invitation.invitation_channels.button": "Mời vΓ o cΓ‘c kΓͺnh", + "components.invitation.invitation_input_list.add": "cα»™ng", + "components.invitation.invitation_input_list.member": "ThΓ nh viΓͺn", + "components.invitation.invitation_input_list.guest": "KhΓ‘ch mời", + "components.invitation.invitation_input_list.placeholder": "BαΊ―t Δ‘αΊ§u nhαΊ­p email", + "components.invitation.invitation_sent.title": "Lời mời Δ‘Γ£ được gα»­i thΓ nh cΓ΄ng", + "components.invitation.invitation_sent.subtitle_status": "BαΊ‘n cΓ³ thể theo dΓ΅i trαΊ‘ng thΓ‘i invitaion trong:", + "components.invitation.invitation_sent.subtitle_location": "CΓ i Δ‘αΊ·t khΓ΄ng gian lΓ m việc> QuαΊ£n lΓ½ thΓ nh viΓͺn", + "components.invitation.invitation_sent.link": "Kiểm tra trαΊ‘ng thΓ‘i lời mời", + "components.invitation.invitation_target.invite_as_guests": "Mời tαΊ₯t cαΊ£ vα»›i tΖ° cΓ‘ch lΓ  khΓ‘ch", + "components.invitation.invitation_target.invite_as_members": "Mời tαΊ₯t cαΊ£ vα»›i tΖ° cΓ‘ch thΓ nh viΓͺn", + "components.invitation.invitation_target.channels_button": "CΓ‘c kΓͺnh để mời", + "components.invitation.workspace_link.text": "LiΓͺn kαΊΏt lời mời khΓ΄ng gian lΓ m việc", + "components.invitation.workspace_link.button": "Sao chΓ©p", + "components.invitation.title": "mời mọi người tham gia {{$1}}", + "components.invitation.bulk_invitation": "Lời mời hΓ ng loαΊ‘t", + "components.invitation.button": "Gα»­i nhα»―ng lời mời", + "scenes.client.readonly.info": "KΓͺnh nΓ y lΓ  mα»™t nguα»“n cαΊ₯p dα»― liệu chỉ đọc nhΖ°ng bαΊ‘n cΓ³ thể nhαΊ­n xΓ©t trong cΓ‘c chα»§ đề.", + "scenes.app.channelsbar.channel_information.group.title": "NhΓ³m kΓͺnh", + "components.invitation.custom_role_invitation": "lời mời cα»• Δ‘iển", + "components.invitation.link": "liΓͺn kαΊΏt" +} diff --git a/twake/frontend/public/locales/zh_Hans.json b/twake/frontend/public/locales/zh_Hans.json new file mode 100644 index 00000000..d6e0fcb5 --- /dev/null +++ b/twake/frontend/public/locales/zh_Hans.json @@ -0,0 +1,1008 @@ +{ + "general.back": "θΏ”ε›ž", + "general.confirm": "η‘θ€", + "general.archive": "ε½’ζ‘£", + "general.help": "εΈεŠ©", + "general.update": "ζ›΄ζ–°", + "general.add": "添加", + "general.connexion_status.disconnected": "您η›ε‰δΈ‹ηΊΏ", + "general.connexion_status.connected": "您η›ε‰εœ¨ηΊΏ", + "general.connexion_status.connecting": "ι‡ζ–°θΏžζŽ₯中…", + "scenes.app.workspaces.create_company.group_data.group_type": "εˆ†η»„η±»εž‹", + "scenes.app.workspaces.create_company.group_data.group_size": "囒体规樑", + "scenes.app.workspaces.create_company.group_data.group_size.less_3": "ε°‘δΊŽ4δΈͺη”¨ζˆ·", + "scenes.app.workspaces.create_company.group_data.group_size.10_50": "11 - 49δΈͺη”¨ζˆ·", + "scenes.app.workspaces.create_company.group_data.group_size.100_500": "100 - 499δΈͺη”¨ζˆ·", + "scenes.app.workspaces.create_company.group_data.group_size.1000_5000": "1000 - 4999δΈͺη”¨ζˆ·", + "scenes.app.workspaces.create_company.group_data.group_main_activity.bank": "ι“Άθ‘Œ/保险", + "scenes.app.workspaces.create_company.group_data.group_main_activity.it_telecom": "IT/η”΅δΏ‘", + "scenes.app.workspaces.create_company.group_data.group_main_activity.machinery_automotive": "机撰/汽车", + "scenes.app.workspaces.create_company.group_data.group_main_activity.business_services": "ε•†δΈšζœεŠ‘", + "scenes.app.workspaces.create_company.group_data.group_main_activity.entertainment": "娱乐", + "scenes.app.workspaces.create_company.group_data.group_main_activity.textile_clothing_shoes": "纺织/ζœθ£…/ιž‹η±»", + "scenes.app.workspaces.create_company.group_data.group_main_activity.transport_logistics": "运输/物桁", + "scenes.app.workspaces.create_company.group_data.group_main_activity.research": "η ”η©Ά", + "scenes.app.workspaces.create_company.group_data.group_main_activity.education": "ζ•™θ‚²", + "scenes.app.header.disconnected.reload": "ι‡ζ–°εŠ θ½½", + "general.delete": "εˆ ι™€", + "general.help.support": "ζ”―ζŒ", + "general.send": "ε‘ι€ζΆˆζ―", + "general.remove": "εˆ ι™€", + "scenes.app.workspaces.create_company.group_data.group_type.company": "ε…¬εΈζˆ–ε…¬εΈιƒ¨ι—¨", + "scenes.app.workspaces.create_company.group_data.group_type.public_organization": "公共组织", + "scenes.app.workspaces.create_company.group_data.group_type.university_school": "ε€§ε­¦ζˆ–ε­¦ζ ‘", + "scenes.app.workspaces.create_company.group_data.group_type.society_club_charity": "εδΌšγ€δΏ±δΉιƒ¨ζˆ–ζ…ˆε–„ζœΊζž„", + "scenes.app.workspaces.create_company.group_data.group_type.other_group": "ε…Άδ»–", + "scenes.app.workspaces.create_company.group_data.group_size.4_10": "4 - 10δΈͺη”¨ζˆ·", + "scenes.app.workspaces.create_company.group_data.group_size.50_100": "50 - 99δΈͺη”¨ζˆ·", + "scenes.app.workspaces.create_company.group_data.group_size.500_1000": "500 - 999δΈͺη”¨ζˆ·", + "scenes.app.workspaces.create_company.group_data.group_main_activity.publishing_communication_multimedia": "ε‡Ίη‰ˆ/ ι€šδΏ‘ / 倚εͺ’体", + "scenes.app.workspaces.create_company.group_data.group_size.5000_more": "θΆ…θΏ‡ 5000 δΈͺη”¨ζˆ·", + "scenes.app.workspaces.create_company.group_data.group_main_activity": "主要活动", + "scenes.app.workspaces.create_company.group_data.group_main_activity.printing_paper": "印刷/ηΊΈεΌ ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.construction_building": "ε»Ίη­‘/建材", + "scenes.app.workspaces.create_company.group_data.group_main_activity.real_estate": "房地产", + "scenes.app.workspaces.create_company.group_data.group_main_activity.materials": "材料", + "scenes.app.workspaces.create_company.group_data.group_main_activity.chemistry": "εŒ–ε­¦", + "scenes.app.workspaces.create_company.group_data.group_main_activity.trade_commerce_distribution": "θ΄Έζ˜“/ε•†δΈš/εˆ†ι”€", + "scenes.app.workspaces.create_company.group_data.group_main_activity.electronics_electricity_energy": "甡子 / η”΅εŠ› / 能源", + "scenes.app.workspaces.create_company.group_data.group_main_activity.studies_and_advice": "η ”η©Άε’Œε»Ίθ", + "scenes.app.workspaces.create_company.group_data.group_main_activity.pharmaceutical_industry": "医药葌业", + "scenes.app.workspaces.create_company.group_data.group_main_activity.other": "ε…Άδ»–", + "components.application.messages": "梈息", + "components.drive_dropzone.uploading": "正在上传...", + "components.user_picker.modal_no_result": "ζœͺζ‰Ύεˆ°η»“ζžœ", + "general.save": "保存", + "components.users_picker.add_me": "ζ·»εŠ ζˆ‘", + "scenes.app.workspaces.create_company.invitations.title": "配η½δ½ ηš„ε·₯δ½œη©Ίι—΄γ€‚", + "scenes.apps.calendar.calendar.week_btn": "周", + "general.close": "ε…³ι—­", + "general.create": "εˆ›ε»Ί", + "general.edit": "ηΌ–θΎ‘", + "scenes.apps.calendar.calendar.list_btn": "εˆ—θ‘¨", + "scenes.app.header.disconnected": "ζ‚¨ε·²ζ–­εΌ€θΏžζŽ₯", + "scenes.app.header.alt_notifications": "ι€šηŸ₯", + "general.retry": "重试", + "general.cancel": "ε–ζΆˆ", + "general.continue": "η»§η»­", + "scenes.app.popup.adduser.magiclinks.genrator_info": "ε·₯δ½œεŒΊι‚€θ―·ι“ΎζŽ₯", + "scenes.app.popup.adduser.magiclinks.new_link_generated": "ζ–°ι“ΎζŽ₯ε·²η”Ÿζˆ", + "scenes.app.popup.adduser.magiclinks.copied_to_clipboard": "已成功倍刢到ε‰ͺ贴板", + "scenes.app.popup.adduser.magiclinks.action_copy": "倍刢", + "scenes.app.popup.adduser.magiclinks.action_generate": "δΊ§η”Ÿ", + "scenes.app.popup.appsparameters.pages.available_publication_alert": "ζ‚¨ηš„εΊ”η”¨η¨‹εΊηš„ε‘εΈƒη›ε‰ζ­£εœ¨η­‰εΎ… Twake ε›’ι˜Ÿηš„ιͺŒθ―γ€‚", + "scenes.app.popup.appsparameters.pages.button_force": "ζ•΄δΈͺε…¬εΈηš„εŠ›ι‡", + "scenes.app.popup.appsparameters.pages.read_privileges_label": "读取权限", + "scenes.app.popup.appsparameters.pages.remove_app": "ζ°ΈδΉ…εˆ ι™€εΊ”η”¨η¨‹εΊ {{$1}}。", + "scenes.app.popup.appsparameters.pages.remove_app_from_company": "δ»Žζ•΄δΈͺε…¬εΈδΈ­εˆ ι™€", + "scenes.app.popup.appsparameters.pages.remove_app_from_workspace": "从ε·₯δ½œεŒΊδΈ­εˆ ι™€", + "scenes.app.popup.appsparameters.pages.string_information": "ζ­€ε­—η¬¦δΈ²ζ ‡θ―†ζ‚¨ηš„εΊ”η”¨η¨‹εΊεΉΆε°†η”¨δΊŽζΆˆζ―ε‘½δ»€γ€‚", + "scenes.app.popup.appsparameters.pages.title_tester": "Twakecode ζ΅‹θ―•ε‘˜", + "scenes.app.popup.appsparameters.pages.url_reception_events_label": "活动ζŽ₯攢网址", + "scenes.app.popup.appsparameters.pages.waiting_availability_application": "η­‰εΎ…...", + "scenes.app.popup.appsparameters.pages.write_privileges_label": "写ε…₯权限", + "scenes.app.popup.appsparameters.pages.update_button": "ζ›΄ζ–°", + "scenes.app.popup.createworkspacepage.add_subtitle": "ιœ€θ¦ζ›΄ε€šηš„η©Ίι—΄οΌŸ", + "scenes.app.popup.createworkspacepage.create_new_workspace": "εˆ›ε»Ίζ–°ε·₯作区", + "scenes.app.popup.createworkspacepage.placeholder_name": "ε·₯作区名称", + "scenes.app.popup.userparameter.pages.frequency_notif_configuration_description": "θΎη½ζ‰‹ζœΊι€šηŸ₯ηš„ι’‘ηŽ‡γ€‚", + "scenes.app.popup.userparameter.pages.frequency_notif_subtitle": "ι€šηŸ₯ι’‘ηŽ‡", + "scenes.app.popup.workspaceparameter.pages.access_apps": "θΏι—ζ‚¨ηš„εΊ”η”¨η¨‹εΊε’ŒθΏžζŽ₯器", + "scenes.app.popup.workspaceparameter.pages.moderator_status": "ε·₯δ½œεŒΊη‰ˆδΈ»", + "scenes.app.popup.workspaceparameter.pages.alert_impossible_removing": "您不能离开ε·₯δ½œεŒΊοΌŒε› δΈΊζ‚¨ζ˜―ζœ€εŽδΈ€δ½η‘η†ε‘˜γ€‚ζ‚¨ε―δ»₯εšδΉ‰ζ–°η‘η†ε‘˜ζˆ–εˆ ι™€/ε½’ζ‘£ζ­€ε·₯δ½œεŒΊγ€‚", + "scenes.app.popup.workspaceparameter.pages.all_apps_small_text": "ζ‰€ζœ‰εΊ”η”¨", + "scenes.app.popup.workspaceparameter.payments_subscriptions_title": "δ»˜ζ¬Ύε’Œθ’ι˜…", + "scenes.apps.calendar.my_calendar": "ζˆ‘ηš„ζ—₯εŽ†", + "scenes.apps.calendar.my_calendar_label": "ζˆ‘ηš„ζ—₯εŽ†", + "scenes.apps.calendar.my_calendar_menu": "ζˆ‘ηš„ζ—₯εŽ†", + "scenes.apps.calendar.today_menu": "今倩", + "scenes.apps.calendar.week_option": "星期", + "scenes.apps.calendar.workspace": "ε·₯作区", + "scenes.apps.calendar.workspace_label": "θΏ™δΈͺε·₯作区", + "scenes.apps.calendar.workspace_menu": "ε·₯作区", + "scenes.apps.drive.add_button": "添加", + "services.apps.messages.no_command_possible": "ζˆ‘δ»¬ζ— ζ³•ζ‰§θ‘Œε‘½δ»€β€œ{{$1}}β€οΌŒε› δΈΊβ€œ{{$2}}β€δΈε­˜εœ¨ζˆ–δΈε…θΈεˆ›ε»Ίε‘½δ»€γ€‚", + "services.user.notification_parameters_update_alert": "ι€šηŸ₯θΎη½ε·²ζ›΄ζ–°γ€‚", + "services.user.update_password_alert": "ζ‚¨ηš„ε―†η ε·²ζ›΄ζ–°γ€‚", + "scenes.apps.tasks.board.tasks.use_deadline": "δ½Ώη”¨ζœŸι™", + "scenes.apps.tasks.board.tasks.use_starttime": "使用开始既间", + "scenes.apps.tasks.board.tasks.in_list": "εœ¨εˆ—θ‘¨δΈ­", + "scenes.apps.tasks.board.starts": "启动", + "scenes.apps.tasks.board.ends": "δΈΊ", + "scenes.apps.tasks.board.list_name": "εˆ—θ‘¨εη§°", + "scenes.app.popup.sync_calendar": "同ζ­₯ζ‚¨ηš„ζ—₯εŽ†γ€‚", + "scenes.apps.parameters.workspace_sections.workspace.logo_company": "公司标志", + "scenes.app.popup.workspaceparameter.pages.logo_company_modify_description": "编辑公司归豑 ", + "components.listmanager.filter": "筛选", + "scenes.apps.tasks.no_connector": "ζ— ζŽ₯倴", + "components.attachmentpicker.add_attachment": "ζ·»εŠ ι™„δ»Ά", + "components.input.copied": "已倍刢", + "components.drive.new_versions": "ζ·»εŠ ζ–°η‰ˆζœ¬", + "components.drive.navigators.directory_not_found": "ζœͺζ‰Ύεˆ°η›ε½•。", + "components.drive.right_preview.suppress_link": "ε–ζΆˆι“ΎζŽ₯", + "components.drive.right_preview.create_link": "εˆ›ε»ΊθΏι—ι“ΎζŽ₯", + "components.drive.moove_here": "搬ζ₯θΏ™", + "components.verify_mail.paragraph": "ε¦‚ζžœζ‚¨ζ„Ώζ„οΌŒζ‚¨ε―δ»₯η¨εŽε†εšοΌŒδ½†ζœͺ经ιͺŒθ―ηš„εΈζˆ·εͺ能θΏι—ζœ‰ι™η‰ˆζœ¬ηš„ Twake", + "services.console_services.toaster.add_email_error_message": "添加 {{$1}} ζ—Άε‡Ίι”™", + "scenes.client.channels_bar.modals.guest_management.input_placeholder": "搜紒ζ₯εΎζˆ–εΎ…ε€„η†ηš„η”΅ε­ι‚δ»Ά", + "scenes.client.channels_bar.modals.guest_management.tips": "δ½Ώη”¨δΈŠι’ηš„θΎ“ε…₯εΌ€ε§‹ζ·»εŠ ζˆ–ζœη΄’η”΅ε­ι‚δ»Ά", + "components.on_boarding.company_billing_banner.admin_or_owner_text": "ζ‚¨ηš„ε…¬εΈθ’ι˜…ε­˜εœ¨ι—ι’˜γ€‚θ―·ηœ‹ηœ‹δ½ ηš„", + "components.on_boarding.company_billing_banner.guest_or_member_text": "ζ‚¨ηš„ε…¬εΈθ’ι˜…ε­˜εœ¨ι—ι’˜γ€‚θ―·θ”η³»ε…¬εΈθ€ζΏζˆ–η‘η†ε‘˜οΌ", + "components.on_boarding.company_billing_banner.link": "公司θ€θ΄­θ‘εˆ’", + "components.on_boarding.popups.blocked_company.description": "您对 Twake ηš„θ’ι˜…ε·²θΏ‡ζœŸγ€‚θ―·θ”η³»θ΄΅ε…¬εΈηš„θ€ζΏζˆ–η‘η†ε‘˜θΏ›θ‘Œζ›΄ζ–°οΌŒδ»₯δΎΏε†ζ¬‘δΈŽζ‚¨ηš„ε›’ι˜Ÿζ²Ÿι€šοΌ", + "components.on_boarding.popups.blocked_company.learn_more_text": "ζƒ³δΊ†θ§£ζ›΄ε€šε…¬εΈθ’ι˜…θ‘εˆ’οΌŸ", + "components.upload.drop_files.toaster.error": "ζ‚¨δΈθƒ½δΈŠδΌ θΆ…θΏ‡ {{$1}} δΈͺζ–‡δ»Ά", + "components.emoji_picker.categories.frequently_used": "经常使用", + "components.emoji_picker.categories.activity": "活动", + "components.emoji_picker.categories.travel_and_places": "ζ—…θ‘Œε’Œεœ°ζ–Ή", + "components.emoji_picker.categories.objects": "对豑", + "components.emoji_picker.categories.symbols": "符号", + "components.emoji_picker.categories.flags": "ζ——εΈœ", + "components.emoji_picker.categories.search_result": "ζœη΄’η»“ζžœ", + "scenes.app.integrations_parameters.title": "ι›†ζˆ", + "scenes.app.integrations_parameters.applications_table.name": "姓名", + "scenes.app.integrations_parameters.applications_table.title": "ε…Άδ»–ι›†ζˆ", + "scenes.app.integrations_parameters.company_application_popup.btn": "ε‰θ£…", + "scenes.app.integrations_parameters.company_application_popup.tab_btn_info": "θ΅„θ―", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.created_item": "εˆ›η«‹ζ—₯期", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.version_item": "η‰ˆζœ¬", + "scenes.app.integrations_parameters.company_applications_table.more_menu.remove_application": "δ»Žε…¬εΈι™€ε", + "scenes.app.integrations_parameters.company_applications_table.name": "姓名", + "scenes.app.integrations_parameters.company_applications_table.title": "ε‰θ£…εœ¨θ΄΅ε…¬εΈ", + "scenes.join.loading": "ζ­£εœ¨εŠ θ½½β€¦", + "scenes.join.wrong_link_title": "ζ­€ι“ΎζŽ₯不再可用", + "scenes.join.wrong_link_description": "ε‘ι‚€θ―·ζ‚¨εŠ ε…₯θ―₯ε…¬εΈηš„δΊΊθ―’ι—ζ–°ι“ΎζŽ₯ζˆ–εˆ›ε»Ίζ‚¨θ‡ͺε·±ηš„ε…¬εΈ", + "scenes.join.create_the_company_button": "εˆ›ε»Ίε…¬εΈ", + "scenes.join.join_workspace_from_company": "从{{$2}}加ε…₯{{$1}}!", + "scenes.join.twake_description": "Twake ζ˜―δΈ€δΈͺ开源数字ε·₯δ½œεŒΊοΌŒζ—¨εœ¨ζι«˜ζ‚¨ηš„ε›’ι˜Ÿη”ŸδΊ§εŠ›", + "scenes.join.login_first_button": "ι¦–ε…ˆη™»ε½•ζˆ–εˆ›ε»ΊδΈ€δΈͺ帐户", + "scenes.join.join_the_team_button": "加ε…₯ε›’ι˜Ÿ", + "general.unarchive": "ε–ζΆˆε­˜ζ‘£", + "application.load.longer": "ζœεŠ‘ε™¨ε“εΊ”ζ—Άι—΄ζ―”ι’„ζœŸι•ΏοΌŒθ―·η¨ε€™ζˆ–ι‡ζ–°εŠ θ½½ι‘΅ι’...", + "scenes.app.side_app.messages_thread_title": "{{$1}} β€’ ζΆˆζ―ηΊΏη¨‹", + "scenes.app.workspaces.create_company.group_data": "配η½ζ‚¨ηš„ζ–°η»„", + "scenes.app.workspaces.create_company.group_data.group_main_activity.food": "ι£Ÿη‰©", + "scenes.app.workspaces.create_company.group_data.group_main_activity.administration": "θ‘Œζ”Ώ", + "scenes.apps.calendar.event_edition.checkbox_all_day": "一整倩", + "scenes.apps.calendar.event_edition.title_confidentiality": "保密", + "scenes.apps.calendar.event_view.article_until": "到", + "scenes.apps.calendar.calendar_modal.participants": "ε‚δΈŽθ€…", + "scenes.apps.calendar.calendar_modal.placeholder": "姓名", + "scenes.apps.calendar.left.calendars": "ζ—₯εŽ†", + "scenes.apps.drive.navigators.navigator_content.directory_name": "η›ε½•名", + "scenes.apps.drive.navigators.navigator_content.files": "ζ–‡δ»Ά", + "scenes.apps.drive.navigators.navigator_labels.title": "ζ ‡η­Ύ", + "scenes.apps.drive.navigators.new_file.untitled": "ζ— ζ ‡ι’˜", + "scenes.apps.drive.navigators.new_file.create_file.type": "η±»εž‹", + "scenes.apps.drive.navigators.new_file": "ζ–°ζ–‡δ»Ά", + "scenes.apps.drive.preview_bloc.operations_download": "δΈ‹θ½½", + "scenes.apps.drive.preview_bloc.error_file": "ζ–‡δ»Άζœͺζ‰Ύεˆ°", + "scenes.apps.drive.right_preview.operations_restore": "恒倍", + "scenes.apps.drive.right_preview.operations_delete": "η§»εˆ°εΊŸηΊΈη―“", + "scenes.apps.drive.right_preview.public_link": "ε…¬ε…±ι“ΎζŽ₯", + "scenes.apps.messages.messages": "留言", + "scenes.apps.messages.chatbox.chat.delete_message": "εˆ ι™€ζ­€ζΆˆζ―", + "scenes.apps.messages.chatbox.chat.delete_message_btn": "εˆ ι™€η•™θ¨€", + "scenes.apps.messages.left_bar.stream_modal.placeholder_name": "姓名", + "scenes.apps.messages.left_bar.stream.add_to_favorites": "ζ·»εŠ εˆ°ζ”Άθ—ε€Ή", + "scenes.apps.messages.left_bar.stream.remove_from_favorites": "δ»Žζ”Άθ—ε€ΉδΈ­εˆ ι™€", + "scenes.apps.messages.left_bar.stream.notifications": "ι€šηŸ₯...", + "scenes.apps.messages.left_bar.stream.notifications.all": "δ»»δ½•ζΆˆζ―", + "scenes.apps.messages.left_bar.stream.notifications.mentions": "{{$1}}、{{$2}} ε’Œ {{$3}}", + "scenes.apps.messages.left_bar.stream.notifications.me": "{{$1}} δ»…", + "scenes.apps.messages.left_bar.stream.notifications.never": "ζ²‘ζœ‰", + "scenes.apps.parameters.workspace_sections.workspace": "ε·₯作区", + "scenes.apps.parameters.workspace_sections.members": "ε‚δΈŽθ€…", + "scenes.apps.parameters.group_sections.workspaces": "ε·₯作区", + "scenes.apps.parameters.group_sections.apps": "应用", + "scenes.apps.account.title": "θ΄¦ζˆ·ε‚ζ•°", + "scenes.apps.account.account.menu_title": "帐户", + "scenes.apps.account.languages.menu_title": "θ―­", + "scenes.apps.account.account.firstname": "名", + "scenes.apps.account.account.lastname": "ε§“", + "scenes.apps.account.account.username": "η”¨ζˆ·ε", + "scenes.apps.account.account.change_username": "ζ›΄ζ”Ήζ‚¨ηš„ε”―δΈ€η”¨ζˆ·εγ€‚", + "scenes.apps.account.account.emails": "甡子ι‚δ»Ά", + "scenes.apps.account.account.main_email": "主要ι‚η±", + "scenes.apps.account.account.email_add": "ζ·»εŠ ζ–°η”΅ε­ι‚δ»Ά", + "scenes.apps.account.account.email_add_modal.invalid_code": "ζ­€δ»£η ζ— ζ•ˆ", + "scenes.apps.account.account.password": "密码", + "scenes.apps.account.account.password_modal.old_password": "当前密码", + "scenes.apps.account.account.password_modal.password": "新密码", + "scenes.apps.account.account.password_modal.bad_old_password": "旧密码不正η‘。", + "scenes.apps.account.account.password_modal.bad_password": "ζ‚¨ηš„ε―†η δΈεŒΉι…ζˆ–ε―†η ε€ͺηŸ­γ€‚θ―·θΎ“ε…₯至少 8 δΈͺε­—η¬¦ηš„ε―†η γ€‚", + "scenes.apps.account.account.logout": "η™»ε‡Ί", + "scenes.apps.account.languages.text": "ζ›΄ζ”Ή Twake 语言。", + "scenes.apps.account.notifications.title": "ι€šηŸ₯", + "scenes.apps.account.notifications.keywords_subtitle": "ε…³ι”词", + "scenes.apps.account.notifications.keywords_placeholder": "εΌ€ε‘οΌŒwifi,代码,...", + "scenes.apps.account.notifications.disturb_option_a": "δΉ‹ι—΄δΈθ¦ε‘ζˆ‘ε‘ι€ζŽ¨ι€ι€šηŸ₯ ", + "scenes.apps.account.notifications.disturb_option_b": " ε’Œ ", + "scenes.apps.account.notifications.disturb_option_c": " οΌˆε½“εœ°ζ—ΆεŒΊοΌ‰", + "scenes.apps.account.notifications.devices_subtitle": "θΎε€‡ι€šηŸ₯", + "scenes.apps.account.notifications.devices_option_ever": "ε§‹η»ˆε‘ζˆ‘ε‘ι€ζŽ¨ι€ι€šηŸ₯", + "scenes.apps.account.notifications.devices_option_inactive": "ε½“ζˆ‘εœ¨ζ‘Œι’δΈŠε€„δΊŽιžζ΄»εŠ¨ηŠΆζ€ζ—Άε‘ζˆ‘ε‘ι€ζŽ¨ι€ι€šηŸ₯", + "scenes.apps.account.notifications.devices_option_never": "δ»ŽδΈε‘ζˆ‘ε‘ι€ζŽ¨ι€ι€šηŸ₯", + "scenes.apps.account.notifications.privacy_subtitle": "隐私", + "scenes.apps.account.notifications.mail_subtitle": "甡子ι‚δ»Άι€šηŸ₯", + "scenes.apps.account.notifications.sound": "ε£°ιŸ³ι€šηŸ₯", + "scenes.apps.parameters.workspace_sections.members.invite_btn": "ζ·»εŠ η”¨ζˆ·", + "scenes.apps.tasks.boards": "板", + "scenes.apps.tasks.connectors_menu": "连ζŽ₯器...", + "scenes.apps.tasks.connectors_search_menu": "搜紒连ζŽ₯器...", + "scenes.apps.tasks.no_connectors_menu_text": "ζ‚¨ζ²‘ζœ‰δ»»δ½•ε―δ»₯连ζŽ₯到ζ—₯εŽ†ηš„θΏžζŽ₯器。", + "scenes.apps.tasks.unconfigured_tab": "ζ­€ι€‰ι‘Ήε‘ε°šζœͺ配η½γ€‚", + "scenes.apps.tasks.choose_board_button": "选择一块板", + "scenes.apps.tasks.new_board.title": "新板", + "scenes.apps.tasks.new_board.edit_title": "编辑板", + "scenes.apps.tasks.task": "任劑", + "scenes.apps.tasks.no_tasks": "ζ²‘ζœ‰δ»»εŠ‘", + "scenes.apps.tasks.task_status.todo": "去做", + "scenes.apps.tasks.task_status.current": "ε½“ε‰ηš„", + "scenes.apps.tasks.task_status.done": "εŒζ―•", + "scenes.apps.tasks.task.description": "描述", + "scenes.apps.tasks.task.assignees": "受θ©δΊΊ", + "scenes.apps.tasks.task.edit.dates": "ζ—₯期", + "scenes.apps.tasks.list_modal.remove_archived_tasks": "εˆ ι™€ε½’ζ‘£δ»»εŠ‘ ({{$1}})", + "scenes.login.footer.go_to_twake": "去 twakeapp.com", + "scenes.login.footer.branding": "ζ‚¨εœ¨ {{$1}} ({{$2}}) 私人 Twake ζœεŠ‘ε™¨δΈŠγ€‚ ", + "scenes.login.create_account.title": "εˆ›ε»ΊδΈ€δΈͺζ–°θ΄¦ζˆ·", + "scenes.login.create_account.email": "甡子ι‚δ»Ά", + "scenes.login.create_account.email_used": "歀甡子ι‚仢已蒫使用。", + "scenes.login.create_account.username": "η”¨ζˆ·ε", + "scenes.login.create_account.username_already_exist": "ζ­€η”¨ζˆ·εε·²θ’«δ½Ώη”¨", + "scenes.login.create_account.fill_in_username": "ζ‚¨εΏ…ι‘»ε‘«ε†™ζ‚¨ηš„η”¨ζˆ·ε", + "scenes.login.create_account.fill_in_email": "您必鑻使用正η‘ηš„η”΅ε­ι‚δ»Άε‘«ε†™ζ‚¨ηš„η”΅ε­ι‚δ»Ά", + "scenes.login.create_account.too_short_password": "ζ‚¨ηš„ε―†η εΏ…ι‘»θ‡³ε°‘εŒ…ε« 8 δΈͺ字符。", + "scenes.login.create_account.firstname": "名", + "scenes.login.create_account.newsletter": "ζŽ₯ζ”Άζœ‰ε…³ Twake ηš„δΏ‘ζ―", + "scenes.login.create_account.lastname": "ε§“", + "scenes.login.forgot_password.title": "忘θ°ε―†η οΌŸ", + "scenes.login.forgot_password.text": "ζ‚¨ε°†ι€šθΏ‡η”΅ε­ι‚δ»Άζ”Άεˆ°δΈ€δΈͺ 9 位代码δ»₯ιͺŒθ―ζ‚¨ηš„身份。", + "scenes.login.forgot_password.text2": "ζ‚¨ε°†ζ”Άεˆ°δΈ€δΈͺ 9 δ½ζ•°ηš„δ»£η γ€‚θ―·εœ¨δΈ‹ι’ηš„ε­—ζ΅δΈ­θΎ“ε…₯εƒδ»₯继续。", + "scenes.login.forgot_password.invalid_code": "ζ­€δ»£η ζ— ζ•ˆγ€‚", + "scenes.login.forgot_password.text3": "δΈΊζ‚¨ηš„εΈζˆ·θΎ“ε…₯新密码。", + "scenes.login.forgot_password.password": "密码", + "scenes.login.forgot_password.password2": "η‘θ€ε―†η ", + "scenes.login.forgot_password.password_dont_match": "ζ‚¨ηš„ε―†η δΈεŒΉι…ζˆ–ε―†η ε€ͺηŸ­γ€‚θ―·θΎ“ε…₯至少 8 δΈͺε­—η¬¦ηš„ε―†η γ€‚", + "scenes.login.home.title": "登录 Twake", + "scenes.login.home.subtitle": "ι«˜ε…΄ηœ‹εˆ°δ½ ", + "scenes.login.home.email": "甡子ι‚δ»Ά", + "scenes.login.home.unable_to_connect": "ζ— ζ•ˆθ―δ»Ά", + "scenes.login.home.password": "密码", + "scenes.login.home.login_btn": "登录", + "general.open": "打开", + "components.calendar.repetition.years": "εΉ΄οΌ‰", + "components.calendar.repetition.custom_recurrence": "θ‡ͺεšδΉ‰ι‡ε€", + "components.calendar.repetition.occurrence": "ε‘η”Ÿζ¬‘ζ•°", + "components.calendar.repetition.repeat_on": "重倍", + "scenes.app.channelsbar.currentuser.add_apps": "ζœη΄’εΊ”η”¨", + "scenes.app.channelsbar.currentuser.change_my_status": "ζ›΄ζ”Ήζˆ‘ηš„ηŠΆζ€", + "scenes.app.channelsbar.currentuser.collaborateurs": "η”¨ζˆ·", + "scenes.app.channelsbar.currentuser.create_workspace_page": "εˆ›ε»Ίε·₯作区", + "scenes.app.channelsbar.currentuser.invited_status": "你是ε’人。", + "scenes.app.channelsbar.currentuser.title": "帐号θΎεš", + "scenes.app.channelsbar.currentuser.workspace_info": "ζ‚¨δ½δΊŽ {{$2}} η»„ηš„ε·₯作区 {{$1}}", + "scenes.app.channelsbar.currentuser.workspace_parameters": "ε·₯作区θΎη½", + "scenes.app.channelsbar.currentuser.logout": "η™»ε‡Ί", + "scenes.app.channelsbar.currentuser.update": "ζ›΄ζ–°", + "scenes.app.channelsbar.currentuser.disable_notifications": "禁用", + "scenes.app.channelsbar.currentuser.disabling_notifications": "禁用 1 小既", + "scenes.app.channelsbar.currentuser.disabling_notifications_until": "η¦η”¨θ‡³δΈŠεˆ 9 η‚Ήζ˜Žε€©", + "scenes.app.channelsbar.currentuser.reactivate_notifications": "重新激活", + "scenes.app.channelsbar.modify_channel_menu": "编辑钑道", + "scenes.app.channelsbar.guest_management": "εΎε’η‘理", + "scenes.app.channelsbar.read_sign": "ζ ‡θ°δΈΊε·²θ―»", + "scenes.app.channelsbar.unread_sign": "ζ ‡θ°δΈΊζœͺθ―»", + "scenes.app.channelsbar.channel_leaving": "离开钑道", + "scenes.app.channelsbar.channel_removing": "εˆ ι™€ι’‘ι“", + "scenes.app.channelsbar.company_invitation_alert_subtitle": "您可δ»₯ι€šθΏ‡ε•ε‡»ζ­€ζ‘†ζžΆε°†θΏ™δΊ›ζΈ ι“ε―Όε…₯ζ‚¨ηš„δΈšεŠ‘δ»₯δΏζŒδΊ•δΊ•ζœ‰ζ‘γ€‚", + "scenes.app.channelsbar.company_invitation_alert_title": "公司邀请您 ", + "scenes.app.popup.appsparameters.pages.alert_published_app": "ζ‚¨ηš„εΊ”η”¨η¨‹εΊε·²ε‘εΈƒοΌŒζ‚¨ζ— ζ³•ε―Ήε…ΆθΏ›θ‘ŒηΌ–θΎ‘γ€‚", + "scenes.app.popup.appsparameters.pages.allowed_ip_adresses_method": "εœ¨εΌ€ε‘δΈ­δ½Ώη”¨ * δ»₯允θΈζ‰€ζœ‰ IP εœ°ε€γ€‚", + "scenes.app.popup.appsparameters.pages.error_check_needed": "ε‘η”ŸδΊ†ι”™θ――;ζ£€ζŸ₯ζ‚¨ηš„δΏ‘ζ―γ€‚", + "scenes.app.popup.appsparameters.pages.error_message": "歀名称已蒫另一δΈͺ应用程序使用;请选择另一δΈͺ。", + "scenes.app.popup.appsparameters.pages.event_subtitle": "活动", + "scenes.app.popup.workspaceparameter.pages.back_to_search_button": "θΏ”ε›žζœη΄’", + "scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button": "ι‚€θ―·η”¨ζˆ·", + "scenes.app.popup.workspaceparameter.pages.collaborateurs": "η”¨ζˆ·", + "scenes.app.popup.workspaceparameter.pages.company_developped_apps_subtitle": "ε…¬εΈεΌ€ε‘ηš„εΊ”η”¨", + "scenes.app.popup.workspaceparameter.pages.company_identity_title": "公司身份", + "scenes.app.popup.workspaceparameter.pages.company_name_description": "ζ›΄ζ”ΉθΏ™εΆε…¬εΈηš„名称", + "scenes.app.popup.workspaceparameter.pages.company_name_label": "公司名称", + "scenes.app.popup.workspaceparameter.pages.configuration_notif": "配η½", + "scenes.app.popup.workspaceparameter.pages.no_app_information": "ζ‚¨εœ¨ζ­€ε·₯δ½œεŒΊδΈ­ζ²‘ζœ‰εΊ”η”¨η¨‹εΊ", + "scenes.app.popup.workspaceparameter.pages.quit_workspace_menu": "离开这δΈͺε·₯作区", + "scenes.app.popup.workspaceparameter.pages.remove_from_company_text": "δ»Žζ•΄δΈͺε…¬εΈδΈ­εˆ ι™€", + "scenes.app.popup.workspaceparameter.pages.research_by": "ζŒ‰εη§°ε’Œη±»εˆ«ζœη΄’εΊ”η”¨η¨‹εΊ", + "scenes.app.popup.workspaceparameter.pages.researching_apps_button": "ζœη΄’εΊ”η”¨η¨‹εΊ...", + "scenes.app.popup.workspaceparameter.pages.show_button": "展瀺", + "scenes.apps.calendar.modals.remove_button": "εˆ ι™€", + "scenes.apps.calendar.modals.remove_event_button": "εˆ ι™€δΊ‹δ»Ά", + "scenes.apps.calendar.modals.remove_event_text": "εˆ ι™€ζ΄»εŠ¨οΌŸ", + "scenes.apps.calendar.modals.title_placeholder": "ζ ‡ι’˜", + "scenes.apps.calendar.modify_calendar_menu": "ηΌ–θΎ‘ζ—₯εŽ†", + "scenes.apps.calendar.month_option": "月", + "scenes.apps.drive.viewer.open_with_button": "打开用...", + "scenes.apps.messages.input.placeholder": "写一δΈͺ俑息。使用@ εΌ•η”¨η”¨ζˆ·γ€‚", + "scenes.apps.messages.input.edited": "ε·²ηΌ–θΎ‘", + "scenes.apps.messages.just_you": "仅对您可见", + "scenes.apps.messages.message.new_messages_bar": "ζ–°ζΆˆζ―", + "scenes.apps.messages.message.cancel_button": "ε–ζΆˆ", + "scenes.login.verifymail.signin_button": "登录", + "scenes.login.verifymail.success": "ζ‚¨ηš„ι‚η±ε·²ζˆεŠŸιͺŒθ―οΌ", + "scenes.login.verifymail.verification_waiting": "η­‰εΎ…ιͺŒθ―...", + "scenes.no_panic": "δΈθ¦ζƒŠζ…ŒοΌεͺιœ€ι‡ζ–°εŠ θ½½ζ­€ι‘΅ι’ε³ε―δΏε€ Twake。", + "services.apps.calendar.deadline_icon": "ζœ€εŽζœŸι™", + "services.apps.calendar.event_icon": "δΊ‹δ»Ά", + "services.apps.calendar.move_icon": "移动", + "services.apps.calendar.reminder_icon": "提醒", + "services.apps.messages.no_app": "ζ­€εΊ”η”¨η¨‹εΊδΈε­˜εœ¨γ€‚", + "scenes.apps.calendar.unconfigured_tab": "ζ­€ι€‰ι‘Ήε‘ε°šζœͺ配η½γ€‚", + "scenes.apps.drive.top_menu_more": "ζ›΄ε€šηš„", + "scenes.apps.drive.top_menu_no_items": "{{$1}} ι‘Ή", + "scenes.apps.messages.new_thread": "εΌ€ε§‹ζ–°ηš„θ¨θΊ", + "scenes.apps.messages.input.send_message": "发俑息", + "scenes.apps.messages.input.emoji": "葨情符号", + "scenes.apps.messages.input.hide_formatting": "ιšθ—ζ ΌεΌ", + "scenes.apps.messages.input.show_formatting": "显瀺格式", + "scenes.apps.tasks.my_tasks": "ζˆ‘ηš„δ»»εŠ‘", + "scenes.apps.tasks.board.place_holder": "板名", + "scenes.apps.tasks.board.tasks.subtask": "子任劑", + "scenes.apps.tasks.board.tasks.add_subtask": "添加子任劑", + "components.tagpicker.tag_name": "标签名称", + "components.upload.drop_files": "ε°†ζ‚¨ηš„ζ–‡δ»Άζ”Ύεœ¨θΏ™ι‡Œ", + "components.workspace.list_manager.no_workspace": "ζ²‘ζœ‰ε·₯作区", + "components.attachmentpicker.from_computer": "δ»Žζ‚¨ηš„θΎε€‡", + "components.attachmentpicker.from_twake": "δ»Žθ°ƒζ•΄ζ–‡δ»Ά", + "components.attachmentpicker.file": "ζ–‡δ»Ά", + "components.attachmentpicker.remove_attach": "εˆ ι™€ι™„δ»Ά", + "scenes.apps.drive.remove_attachs": "εˆ ι™€ι™„δ»Ά", + "components.drive.elements.see": "ηœ‹", + "components.drive.elements.current_name": "现名: ", + "scenes.apps.drive.right_preview.public": "ε…¬ε…±θΏι—", + "components.drive.elements.configurate_mod": "配η½ζ¨‘块...", + "components.drive.elements.manage_version": "η‘η†η‰ˆζœ¬", + "scenes.app.popup.createcompany.try_again": "请再试一欑。", + "components.notifications.hidden_notifications_button.children": "ζ–°ζΆˆζ―", + "scenes.client.mainview.tabs.tabstemplateeditor.select_placeholder": "应用", + "scenes.client.channelbar.channelmemberslist.no_members": "ζ­€ι’‘ι“δΈ­ζ²‘ζœ‰η”¨ζˆ·οΌŒζ‚¨ε―δ»₯ι€šθΏ‡ε•ε‡»ζ·»εŠ η”¨ζˆ·ζ₯邀请他们。", + "scenes.app.channelsbar.hide_discussion_leaving.menu": "ιšθ—θ¨θΊ", + "scenes.app.popup.adduserfromtwakeconsole.current_users_state": "{{$1}} 甡子ι‚δ»Άε°†θ’«ζ·»εŠ ", + "components.newversion.new_version_component.row.part_1": "ζ‚¨θΏθ‘Œηš„ζ˜―θΏ‡ζ—Άηš„ Twake η‰ˆζœ¬", + "general.re_send": "重发", + "components.account_verication_status_blocked": "锁εš", + "components.unverified_account.re_send_email": "ζ²‘ζœ‰ζ”Άεˆ°ι‚δ»ΆοΌŸ", + "components.blocked_account.trial_period_over": "ζ‚¨ηš„θ―•η”¨ζœŸε·²θΏ‡γ€‚θ¦θ§£ι”ζ‚¨ηš„εΈζˆ·εΉΆθΏι—ζ‰€ζœ‰εŠŸθƒ½οΌŒθ―·ι€šθΏ‡η”΅ε­ι‚δ»Άη‘θ€ιͺŒθ―ζ‚¨ηš„εΈζˆ·", + "scenes.app.popup.workspaceparameter.pages.workspace_partner_tabs.members.table.tags": "角色", + "general.email": "甡子ι‚δ»Ά", + "components.locked_features.locked_workspace_popup.title": "ζ‚¨ζ— ζ³•εˆ›ε»Ίζ›΄ε€šε·₯作区", + "scenes.login.create_account.step_3_mail_sent": "ζˆ‘δ»¬ε·²ι€šθΏ‡η”΅ε­ι‚仢向您发送激活链ζŽ₯。", + "scenes.login.create_account.step_3_subtitle": "ζœ€εŽδΈ€ζ­₯β€”β€”ζˆ‘δ»¬ιœ€θ¦ιͺŒθ―δ½ δΈζ˜―ζœΊε™¨δΊΊοΌ", + "scenes.app.workspaces.create_company.company_name.placeholder": "公司名", + "scenes.app.workspaces.create_company.company_name.title_1": "εΌ€ε§‹οΌŒ", + "scenes.app.workspaces.create_company.company_name.title_2": "ζ³¨ζ˜Žθ΄΅ε…¬εΈηš„εη§°γ€‚", + "scenes.app.workspaces.create_company.default_workspace_name": "δΈ»θ¦ηš„", + "scenes.app.workspaces.create_company.importations.title_1": "ε·²η»εœ¨δ½Ώη”¨ζ•°ε­—ε·₯ε…·οΌŸη«‹ε³ε―Όε…₯ζˆ–ι›†ζˆζ‚¨ηš„ε·₯具!", + "scenes.app.workspaces.create_company.importations.title_2": "δΈη”¨ζ‹…εΏƒοΌŒζ‚¨ε―δ»₯η¨εŽε†εšοΌ", + "scenes.app.workspaces.create_company.invitations.title_2": "ε°†η”¨ζˆ·ζ·»εŠ εˆ°ζ‚¨ηš„ε›’ι˜Ÿγ€‚", + "scenes.app.workspaces.create_company.title": "εˆ›ε»Ίζˆ‘ηš„ε…¬εΈ", + "scenes.app.workspaces.welcome_page.add_secondary_emails": "ζ·»εŠ θΎ…εŠ©η”΅ε­ι‚δ»Ά", + "scenes.app.workspaces.welcome_page.added_to_company": "ζ‚¨ε·²ε—ι‚€ε‚εŠ  ", + "scenes.app.workspaces.welcome_page.create_my_company": "εˆ›ε»Ίζˆ‘ηš„ε…¬εΈ", + "scenes.app.workspaces.welcome_page.lets_go": "ζˆ‘δ»¬θ΅°ε§οΌ", + "scenes.app.workspaces.welcome_page.may_be_invited_with_secondary_emails": "ζ‚¨ζ˜―δ½Ώη”¨ε…Άδ»–η”΅ε­ι‚δ»Άεœ°ε€θ’«ι‚€θ―·ηš„ε—οΌŸ", + "scenes.app.workspaces.welcome_page.no_company_subtitle": "ε“¦οΌŒε₯½ε§β€¦β€¦ηœ‹θ΅·ζ₯θΏ˜ζ²‘ζœ‰δΊΊι‚€θ―·δ½ εˆ°ε·₯δ½œεŒΊγ€‚", + "scenes.app.workspaces.welcome_page.ready_to_work": "ζ‚¨ηŽ°εœ¨ε―δ»₯εΌ€ε§‹ε·₯δ½œδΊ†γ€‚", + "scenes.app.workspaces.welcome_page.see_you_soon": "再见!", + "scenes.app.workspaces.welcome_page.try_again": "再试一欑", + "scenes.app.workspaces.welcome_page.twake_team": "θ°ƒζ•΄", + "scenes.app.workspaces.welcome_page.welcome_header": "欒迎ζ₯εˆ°η‰Ήη“¦ε…‹οΌ", + "scenes.app.workspaces.welcome_page.add_secondary_emails_comment": "您可δ»₯ε°†ε€šδΈͺ甡子ι‚δ»Άεœ°ε€ι“ΎζŽ₯εˆ°ζ‚¨ηš„εΈζˆ·οΌ›εͺζœ‰δΈ€δΈͺεœ°ε€ε°†η”¨δΊŽε‘ζ‚¨ε‘ι€ι€šηŸ₯。", + "scenes.app.workspaces.welcome_page.main_mail_title": "δΈ»θ¦εœ°ε€", + "scenes.app.workspaces.welcome_page.other_mail_title": "θΎ…εŠ©εœ°ε€", + "scenes.app.workspaces.welcome_page.add_new_email": "ζ·»εŠ η”΅ε­ι‚δ»Ά", + "scenes.app.workspaces.welcome_page.code_verification": "ιͺŒθ―η ", + "scenes.app.workspaces.welcome_page.new_email": "ζ·»εŠ θΎ…εŠ©η”΅ε­ι‚δ»Ά", + "scenes.app.workspaces.welcome_page.we_sent_you_mail": "ζˆ‘δ»¬ι€šθΏ‡ {{$1}} 向您发送了ιͺŒθ―η ", + "scenes.app.workspaces.welcome_page.done": "ζˆ‘ε—ε€ŸδΊ†", + "scenes.login.forgot_password.finished": "ζ‚¨ηš„ε―†η ε·²ζˆεŠŸζ›΄ζ–°γ€‚", + "scenes.apps.account.account.description_main": "ζ‚¨ηš„δΈ»θ¦εœ°ε€ζ˜― Twake ε‘ι€ι€šηŸ₯ηš„εœ°ζ–Ήγ€‚ζ‚¨ηš„θΎ…εŠ©εœ°ε€ε…θΈζ‚¨θ‡ͺεŠ¨θ’«ι‚€θ―·εˆ°δ½Ώη”¨εƒδ»¬ηš„ε·₯δ½œεŒΊγ€‚", + "scenes.apps.account.account.emails.description": "η‘η†ζ‚¨ηš„δΈεŒη”΅ε­ι‚δ»Άεœ°ε€γ€‚", + "scenes.apps.account.account.make_main": "θΎη½δΈ»θ¦", + "scenes.apps.account.account.password.description": "ζ›΄ζ”Ήζ‚¨ηš„ε―†η γ€‚", + "scenes.apps.account.identity": "θΊ«δ»½", + "scenes.apps.account.identity.description": "ζ›΄ζ”Ήε…Άδ»– Twake η”¨ζˆ·ε―θ§ηš„εε­—γ€ε§“ζ°ε’ŒδΈͺ人衄料图片。", + "scenes.apps.account.preference": "ε–œε₯½", + "scenes.apps.account.thumbnail.max_weight": "ζœ€ε€§ε€§ε° 5 MB", + "scenes.apps.account.account.email_add_modal.confirm": "η‘θ€ζ­€η”΅ε­ι‚δ»Ά", + "app.name.twake_calendar": "ζ—₯εŽ†", + "general.verify": "ζ Έεž", + "scenes.app.workspaces.create_company.group_data.title": "ζˆ‘δ»¬εΎˆεΏ«β€”β€”ζˆ‘δ»¬εͺιœ€θ¦δΈ€δΊ›η»Ÿθ‘俑息。", + "scenes.app.channelsbar.currentuser.company_messages_counter_header": "留言号码", + "scenes.app.channelsbar.currentuser.company_messages_counter_info": "在 Twake ηš„ε…θ΄Ήη‰ˆζœ¬δΈŠοΌŒζ‚¨εͺ能θΏι— {{$1}} ζ›΄ζ–°ηš„ζΆˆζ―γ€‚", + "scenes.app.channelsbar.currentuser.company_messages_counter_link": "ζ˜Ύη€Ίζ›΄ε€šθ‘εˆ’", + "scenes.app.channelsbar.channelsuser.new_private_discussion": "ζ–°ηš„η§δΊΊθ¨θΊ", + "scenes.app.channelsbar.channelsuser.no_private_message_invite_collaboraters": "ζ²‘ζœ‰η§δΏ‘γ€‚ι‚€θ―·η”¨ζˆ·οΌ", + "scenes.app.channelsbar.channelsuser.private_messages": "η›΄ζŽ₯梈息", + "scenes.app.channelsbar.channelsworkspace.channel_title": "钑道", + "scenes.app.channelsbar.channelsworkspace.channel_title.favorite": "攢藏倹", + "scenes.app.channelsbar.channelsworkspace.create_channel": "εˆ›ε»Ίι’‘ι“", + "scenes.app.channelsbar.channelsworkspace.no_channel": "ζ‚¨θΏ˜ζ²‘ζœ‰εŠ ε…₯任何钑道", + "scenes.app.channelsbar.initial_instructions_tutorial": "ι€‰ζ‹©εε­—γ€ε§“εε’ŒδΈͺ人衄料图片。", + "scenes.app.channelsbar.installation_desktop_tutorial": "ε‰θ£…ζ‘Œι’应用程序", + "scenes.app.channelsbar.invitation_collaboraors_tutorial": "ι‚€θ―·η”¨ζˆ·θΏ›ε…₯ζ‚¨ηš„ε·₯δ½œεŒΊγ€‚", + "scenes.app.channelsbar.public_channel_label": "ζ°‘δΌ—", + "scenes.app.channelsbar.private_channel_label": "η§δΊΊηš„", + "scenes.app.channelsbar.sending_message_instruction": "在θ¨θΊδΈ­ε‘ι€ζ‚¨ηš„η¬¬δΈ€ζ‘梈息", + "scenes.app.channelsbar.tutorial_alert": "δΈε†ζ˜Ύη€Ίζ­€ζ‘†ζžΆοΌŸ", + "scenes.app.channelsbar.welcome": "欒迎ζ₯到 Twake", + "scenes.app.channelsbar.welcoming_message_subtitle": "εͺιœ€η‚Ήε‡»ε‡ δΈ‹ε³ε―ζˆδΈΊ Twake δΈ“εΆοΌ", + "scenes.app.mainview.instruction_current_tab": "ι¦–ε…ˆι€‰ζ‹©ε·¦δΎ§ηš„ι’‘ι“γ€‚", + "scenes.app.mainview.tabs.no_connected_connectors_for_channel": "ζ‚¨ζ²‘ζœ‰ε―δ»₯连ζŽ₯εˆ°ι€šι“ηš„θΏžζŽ₯器。", + "scenes.app.mainview.tabs.rename": "改名", + "scenes.app.mainview.tabs.searching_connectors": "搜紒连ζŽ₯器...", + "scenes.app.popup.adduser.adresses_message": "θ―·η”¨ι€—ε·ζˆ–η©Ίζ Όεˆ†ιš”εœ°ε€γ€‚θ―·θ°δ½οΌŒTwake 可δ»₯ζ Ήζζ‚¨ηš„θ’ι˜…ι™εˆΆι‚€θ―·ζ•°ι‡γ€‚", + "scenes.app.popup.appsparameters.pages.amazing_app_name": "ζˆ‘ζƒŠδΊΊηš„εΊ”η”¨η¨‹εΊ", + "scenes.app.popup.appsparameters.pages.api_data_description": "Twake API ηš„ζœ‰η”¨ζ•°ζγ€‚", + "scenes.app.popup.appsparameters.pages.api_parameters_label": "ζŽ₯口θΎη½", + "scenes.app.popup.appsparameters.pages.app_name_label": "应用名称", + "scenes.app.popup.appsparameters.pages.app_modification_right": "θ―₯ε…¬εΈηš„ζ‰€ζœ‰η»η†ιƒ½ε―δ»₯编辑歀应用程序。", + "scenes.app.popup.appsparameters.pages.app_privileges_information": "εšδΉ‰ζ‚¨ηš„应用程序可δ»₯ηΌ–θΎ‘ε’Œθ―»ε–ηš„ε†…εΉγ€‚", + "scenes.app.popup.appsparameters.pages.app_privileges_label": "应用权限", + "scenes.app.popup.appsparameters.pages.app_update": "更新应用 {{$1}}οΌˆεΊ”η”¨δ½Ώη”¨ {{$2}} 欑。)", + "scenes.app.popup.appsparameters.pages.application_title": "应用", + "scenes.app.popup.appsparameters.pages.apps_title": "ζ‚¨ηš„εΊ”η”¨η¨‹εΊε’ŒθΏžζŽ₯器", + "scenes.app.popup.appsparameters.pages.automatique_label": "θ‡ͺεŠ¨ηš„", + "scenes.app.popup.appsparameters.pages.automatique_option_information": "ε¦‚ζžœζ‚¨ζΏ€ζ΄»β€œθ‡ͺεŠ¨β€οΌŒζ­€εΊ”η”¨η¨‹εΊε°†θ‡ͺ动添加到θ―₯ε…¬εΈηš„δΈ‹δΈ€δΈͺε·₯δ½œεŒΊγ€‚", + "scenes.app.popup.appsparameters.pages.autorised_ip_adresses_label": "允θΈηš„ IP εœ°ε€", + "scenes.app.popup.appsparameters.pages.create_my_app": "εˆ›ε»Ίζˆ‘ηš„εΊ”η”¨η¨‹εΊ", + "scenes.app.popup.appsparameters.pages.current_informations_apps_connectors": "ζ‚¨ε°šζœͺεˆ›ε»ΊεΊ”η”¨η¨‹εΊγ€‚εœ¨εˆ›ε»ΊεΊ”η”¨η¨‹εΊζˆ–θΏžζŽ₯ε™¨δΉ‹ε‰οΌŒθ―·η‘保εƒεœ¨ζˆ‘δ»¬ηš„εΊ”η”¨η¨‹εΊεΈ‚εœΊδΈ­ε°šδΈε­˜εœ¨γ€‚", + "scenes.app.popup.appsparameters.pages.danger_zone_description": "εˆ ι™€η”³θ―·", + "scenes.app.popup.appsparameters.pages.danger_zone_label": "ε±ι™©εœ°εΈ¦", + "scenes.app.popup.appsparameters.pages.description_label": "描述", + "scenes.app.popup.appsparameters.pages.developped_apps_subtitle": "ε…¬εΈεΌ€ε‘ηš„εΊ”η”¨", + "scenes.app.popup.appsparameters.pages.dispalyed_parameters_description": "允θΈζ‚¨εšδΉ‰εΊ”η”¨η¨‹εΊηš„ε―见位η½γ€‚", + "scenes.app.popup.appsparameters.pages.displayed_parameters_label": "显瀺θΎη½", + "scenes.app.popup.appsparameters.pages.filter_information": "歀过滀器将 API ε―†ι’₯ηš„δ½Ώη”¨δ»…ι™δΊŽθΏžζŽ₯ε™¨δΈ­ηš„ζœεŠ‘ε™¨γ€‚", + "scenes.app.popup.appsparameters.pages.go_back": "εŽι€€", + "scenes.app.popup.appsparameters.pages.grp_section_name-error": "歀名称已蒫另一δΈͺ应用程序使用。请选择另一δΈͺ。", + "scenes.app.popup.appsparameters.pages.grp_section_surname_label": "η€εŒ–名称", + "scenes.app.popup.appsparameters.pages.installation": "ε‰θ£…。", + "scenes.app.popup.appsparameters.pages.instruction_message_twakecode": "ι¦–ε…ˆδ»₯ JSON ζ ΌεΌηΌ–ε†™ζΆˆζ―γ€‚", + "scenes.app.popup.appsparameters.pages.interne_availability_application": "内部应用", + "scenes.app.popup.appsparameters.pages.json_configuration_information": "θ½¬εˆ°ζ–‡ζ‘£δ»₯η”Ÿζˆ JSON ζ ΌεΌηš„ι…η½γ€‚", + "scenes.app.popup.appsparameters.pages.loading": "正在加载...", + "scenes.app.popup.appsparameters.pages.message_data_next_event": "ε°†εœ¨δΈ‹δΈ€δΈͺ Event δΈ­ε‘ι€ηš„θ’«εŠ¨ζ•°ζ", + "scenes.app.popup.appsparameters.pages.modify_public_data": "ηΌ–θΎ‘εΊ”η”¨η¨‹εΊηš„ε…¬ε…±ζ•°ζγ€‚", + "scenes.app.popup.appsparameters.pages.new_app_title": "新应用", + "scenes.app.popup.appsparameters.pages.ok_user_code": "ε₯½ηš„", + "scenes.app.popup.appsparameters.pages.optimal_format": "ζœ€δ½³ζ ΌεΌοΌš48x48px。", + "scenes.app.popup.appsparameters.pages.parameters_form_small_text": "ζœͺε‘εΈƒηš„εΊ”η”¨η¨‹εΊδ»…ι€‚η”¨δΊŽζ‚¨ηš„ε…¬εΈγ€‚ε¦‚ζžœζ‚¨ζƒ³θ©ζ‰€ζœ‰ Twake η”¨ζˆ·ιƒ½ε―δ»₯使用εƒοΌŒθ―·ζΏ€ζ΄»ζ­€ι€‰ι‘Ήγ€‚", + "scenes.app.popup.appsparameters.pages.public_availability_application": "ε…¬εΌ€η”³θ―·", + "scenes.app.popup.appsparameters.pages.public_login_label": "公共标识符", + "scenes.app.popup.appsparameters.pages.publication_description": "η‘εšεΊ”η”¨η¨‹εΊηš„ε―见性。", + "scenes.app.popup.appsparameters.pages.publication_label": "ε‡Ίη‰ˆη‰©", + "scenes.app.popup.appsparameters.pages.publish_app_label": "发布应用", + "scenes.app.popup.userparameter.pages.keywords_notif_description": "ηͺε‡Ίζ˜Ύη€Ίδ»₯δΈ‹ε…³ι”ε­—οΌš", + "scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description": "θΎη½η”΅ε­ι‚δ»Άι€šηŸ₯ηš„ι’‘ηŽ‡γ€‚", + "scenes.app.popup.userparameter.pages.private_message_content.show": "ζ˜Ύη€Ίη§δΏ‘ε†…εΉ", + "scenes.app.popup.userparameter.pages.private_message_content.hide": "ιšθ—η§δΏ‘ε†…εΉ", + "scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description": "选择您不ζŽ₯ζ”Άι€šηŸ₯ηš„ζ—Άι—΄ζ΅γ€‚", + "scenes.app.popup.userparameter.pages.no_night_disturbing_label": "ζ™šδΈŠθ―·ε‹Ώζ‰“ζ‰°", + "scenes.app.popup.userparameter.pages.notif_content_label": "ι€šηŸ₯ε†…εΉ", + "scenes.app.mainview.quick_search_placeholder": "εΏ«ι€Ÿζœη΄’", + "scenes.app.popup.userparameter.personnal_workspaces_title": "ζ‚¨ηš„ε·₯δ½œη©Ίι—΄", + "scenes.app.popup.workspaceparameter.admin_current_status": "ζ‚¨ζ˜―η‘η†ε‘˜γ€‚", + "scenes.app.popup.workspaceparameter.admin_manager_current_status": "ζ‚¨ζ˜―ε·₯作区η‘η†ε‘˜γ€‚", + "scenes.app.popup.workspaceparameter.manager_current_status": "ζ‚¨ζ˜―ε…¬εΈη‘η†ε‘˜γ€‚", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace": "εˆ ι™€ε·₯作区", + "scenes.app.popup.workspaceparameter.pages.error_workspace_member": "您必鑻独θ‡ͺ在ε·₯δ½œεŒΊδΈ­ζ‰θƒ½ε°†ε…Άεˆ ι™€γ€‚εˆ ι™€ζ‚¨ηš„εδ½œθ€…οΌŒη„ΆεŽι‡θ―•γ€‚", + "scenes.app.popup.workspaceparameter.pages.enter": "θΏ›ε…₯ ", + "scenes.app.popup.workspaceparameter.pages.description": "描述", + "scenes.app.popup.workspaceparameter.pages.developped_apps_small_text": "ε…¬εΈεΌ€ε‘ηš„εΊ”η”¨", + "scenes.app.popup.workspaceparameter.pages.displayed_preferencies_subtitle": "ζ˜Ύη€Ίι¦–ι€‰ι‘Ή", + "scenes.app.popup.workspaceparameter.pages.install_button": "ε‰θ£…", + "scenes.app.popup.workspaceparameter.pages.installed_app_information": "在歀ε·₯作区中ε‰θ£…应用程序。", + "scenes.app.popup.workspaceparameter.pages.installed_apps_information": "ε‰θ£…εœ¨ζ­€ε·₯δ½œεŒΊδΈ­ηš„εΊ”η”¨η¨‹εΊ {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_message": "ε‰θ£…εœ¨ε…¬εΈε…Άδ»–ι’†εŸŸηš„εΊ”η”¨η¨‹εΊ {{$1}}", + "scenes.app.popup.workspaceparameter.pages.installed_apps_subtitle": "ε·²ε‰θ£…ηš„εΊ”η”¨η¨‹εΊ", + "scenes.app.popup.workspaceparameter.pages.invitation_error": "ι‚€θ―·δ»₯δΈ‹η”¨ζˆ·ζ—Άε‡Ίι”™οΌš ", + "scenes.app.popup.workspaceparameter.pages.invited_guest_check_message": "ζ£€ζŸ₯δ½Ώη”¨ηš„η”¨ζˆ·εζˆ–η”΅ε­ι‚δ»Άζ˜―ε¦ζœ‰ζ•ˆγ€‚", + "scenes.app.popup.workspaceparameter.pages.logo_modify_description": "ηΌ–θΎ‘ζ­€ε·₯δ½œεŒΊηš„ε›Ύεƒ", + "scenes.app.popup.workspaceparameter.pages.logo_subtitle": "ζ ‡θ―†", + "scenes.app.popup.workspaceparameter.pages.name_description": "ζ›΄ζ”Ήζ­€ε·₯δ½œεŒΊηš„εη§°", + "scenes.app.popup.workspaceparameter.pages.name_label": "ε·₯作区名称", + "scenes.app.popup.workspaceparameter.pages.no_access": "ζ²‘ζœ‰θΏι—权限。", + "scenes.app.popup.workspaceparameter.pages.title": "ε·₯作区θΎη½", + "scenes.app.popup.workspaceparameter.pages.webhooks_access_subtitle": "θΏι—η½‘η»œι’©ε­", + "scenes.apps.calendar.connectors_menu": "连ζŽ₯器...", + "scenes.apps.calendar.connectors_search_menu": "搜紒连ζŽ₯器...", + "scenes.apps.calendar.create_calendar_title": "εˆ›ε»Ίζ—₯εŽ†", + "scenes.apps.calendar.day_option": "ζ—₯", + "scenes.apps.calendar.edit_calendar_title": "ηΌ–θΎ‘ζ—₯εŽ†", + "scenes.apps.calendar.export_title": "出口", + "scenes.apps.calendar.export_view_menu": "导出视图...", + "scenes.apps.calendar.ics_download_menu": "δΈ‹θ½½ ICS ζ–‡δ»Ά", + "scenes.apps.calendar.ics_subscription_menu": "θŽ·ε– ICS θ’ι˜…ι“ΎζŽ₯", + "scenes.apps.calendar.modals.advanced_options": "ι«˜ηΊ§ι€‰ι‘Ή", + "scenes.apps.calendar.modals.description_placeholder": "描述", + "scenes.apps.calendar.modals.details_title": "η»†θŠ‚", + "scenes.apps.calendar.modals.event_adresse_placeholder": "εœ°ε€", + "scenes.apps.calendar.modals.event_description_placeholder": "描述", + "scenes.apps.calendar.modals.event_title_placeholder": "ζ ‡ι’˜", + "scenes.apps.calendar.modals.modify_event_button": "ηΌ–θΎ‘δΊ‹δ»Ά", + "scenes.apps.calendar.modals.part.participants": "ε‚δΈŽθ€…", + "scenes.apps.calendar.modals.participants_event": "ε‚δΈŽθ€…", + "scenes.apps.drive.message_added_file": "{{$1}} 发送 {{$2}}。", + "scenes.apps.drive.message_added_mutiple_files": "{{$1}} ε‘ι€δΊ†ε€šδΈͺ文仢。", + "scenes.apps.drive.message_added_file_no_name": "{{$1}} 发送了一δΈͺ文仢。", + "scenes.apps.drive.choose_folder_button": "选择一δΈͺη›ε½•", + "scenes.apps.drive.choose_file_button": "选择一δΈͺζ–‡δ»Ά", + "scenes.apps.drive.create_folder_button": "εˆ›ε»Ί", + "scenes.apps.drive.download_button": "δΈ‹θ½½", + "scenes.apps.drive.open_link": "εœ¨ζ–°ηͺ—口中打开链ζŽ₯", + "scenes.apps.drive.files_subtitle": "ζ–‡δ»Ά", + "scenes.apps.drive.folder_subtitle": "ζ–‡δ»Άε€Ή", + "scenes.apps.drive.go_out_trash_menu": "η•™δΈ‹εžƒεœΎ", + "scenes.apps.drive.go_trash_menu": "εŽ»εžƒεœΎη±", + "scenes.apps.drive.import_from_computer_menu": "δ»Žη”΅θ„‘δΈŠδΌ ", + "scenes.apps.drive.move_text": "移动", + "scenes.apps.drive.new_file_menu": "ζ–°ζ–‡δ»Ά", + "scenes.apps.drive.new_file_title": "ζ–°ζ–‡δ»Ά", + "scenes.apps.drive.new_external_storage": "ζ–°ηš„ε€–ιƒ¨ε­˜ε‚¨", + "scenes.apps.drive.new_folder_title": "ζ–°ε»Ίζ–‡δ»Άε€Ή", + "scenes.apps.drive.no_file_alert": "ζ‚¨ζ²‘ζœ‰ε…θΈζ‚¨εˆ›ε»Ίζ–‡δ»Άηš„应用程序。", + "scenes.apps.drive.no_storage_app_alert": "ζ‚¨ζ²‘ζœ‰ε…θΈζ·»εŠ ε€–ιƒ¨ε­˜ε‚¨ηš„εΊ”η”¨η¨‹εΊγ€‚", + "scenes.apps.drive.remove_definitely_menu": "ζ°ΈδΉ…εˆ ι™€", + "scenes.apps.drive.restore_menu": "恒倍", + "scenes.apps.drive.throw_menu": "ε‘ι€εˆ°εžƒεœΎη±", + "scenes.apps.drive.trash_empty_menu": "ζΈ…η©ΊεžƒεœΎ", + "scenes.apps.messages.message.modify_button": "ηΌ–θΎ‘", + "scenes.apps.messages.message.pin_button": "η½ι‘ΆζΆˆζ―", + "scenes.app.popup.workspaceparameter.pages.cancel_invitation": "ε–ζΆˆι‚€θ―·", + "scenes.apps.account.account.fullname": "全名", + "login.email_login": "甡子ι‚δ»Ά/登录", + "scenes.apps.account.account.password_for_user": "ζ‚¨ηš„η”¨ζˆ·ηš„ε―†η ", + "scenes.apps.account.account.send_info": "ε°†ζ­€ε‡­ζδΏ‘ζ―ε‘ι€η»™ζ‚¨ηš„η”¨ζˆ·γ€‚", + "scenes.apps.account.account.save": "保存帐号", + "components.workspace.list_manager.current_space": "当前ε·₯δ½œη©Ίι—΄", + "components.workspace.list_manager.all": "全部", + "components.searchpopup.loading": "εŠ θ½½ζ›΄ε€šη»“ζžœ", + "components.searchpopup.filter_ws": "过滀ε·₯作区", + "components.searchpopup.tags": "ζ ‡η­Ύ", + "components.searchpopup.size": "ε°Ίε―Έ", + "components.searchpopup.creation": "εˆ›ε»Ί", + "components.searchpopup.update_search": "ζ›΄ζ–°ζœη΄’", + "components.searchpopup.last_modif": "ζœ€εŽδΏζ”Ή", + "components.searchpopup.sender": "发仢人", + "components.searchpopup.mentions": "提及", + "components.searchpopup.only_pinned": "δ»…ε›ΊεšζΆˆζ―", + "components.alert.confirm": "η‘θ€ζ‚¨ηš„ζ“δ½œ", + "components.alert.confirm_click": "ε•ε‡»β€œη‘εšβ€η‘θ€ζ‚¨ηš„ζ“δ½œγ€‚", + "components.searchpopup.tasks": "任劑", + "scenes.app.mainview.advanced_search_placeholder": "高级搜紒", + "components.searchpopup.hide_filters": "ιšθ—θΏ‡ζ»€ε™¨", + "components.searchpopup.show_filters": "ζ˜Ύη€ΊθΏ‡ζ»€ε™¨", + "components.searchpopup.load_more": "εŠ θ½½ζ›΄ε€šη»“ζžœ", + "general.more": "ζ›΄ε€šηš„", + "scenes.apps.board.archived_tasks": "存摣任劑 ({{$1}})", + "scenes.apps.board.active_tasks": "活动任劑", + "scenes.apps.board.kanban": "ηœ‹ζΏ", + "components.userlistmanager.no_users": "ζ²‘ζœ‰η”¨ζˆ·γ€‚", + "scenes.apps.drive.used": "εœ¨θΏ™δΈͺ文仢倹中使用", + "scenes.apps.calendar.reminders": "提醒", + "scenes.app.popup.workspace.edit_temp": "ηΌ–θΎ‘δΈ΄ζ—Άθ΄¦ζˆ·", + "scenes.app.popup.workspace.create_temp": "εˆ›ε»ΊδΈ΄ζ—Άθ΄¦ζˆ·", + "scenes.apps.tasks.active_tasks": "活动任劑", + "scenes.apps.drive.right_preview.versions": "η‰ˆζœ¬", + "scenes.app.popup.appsparameters.pages.apps_connectors_small_text": "η‘η†ζ‚¨ηš„εΊ”η”¨η¨‹εΊε’ŒθΏžζŽ₯器。", + "scenes.app.popup.appsparameters.pages.icon": "ε›Ύζ ‡", + "scenes.app.popup.appsparameters.pages.title_informations": "基本俑息", + "scenes.app.popup.appsparameters.pages.subtitle_informations": "δΈŽεΊ”η”¨η¨‹εΊη‘η†η›Έε…³ηš„δΏ‘ζ―", + "scenes.app.popup.appsparameters.pages.smalltext_user_id": "ε½“ε‰η”¨ζˆ· ID", + "scenes.app.popup.appsparameters.pages.smalltext_workspace_id": "当前ε·₯作区 ID", + "scenes.app.popup.appsparameters.pages.smalltext_group_id": "当前组 ID", + "scenes.app.mainview.channel_description": "描述渠道", + "scenes.client.channelbar.channeltemplateeditor.checkbox": "θ‡ͺεŠ¨ι‚€θ―·ζ‰€ζœ‰ε·₯δ½œεŒΊη”¨ζˆ·εŠ ε…₯歀钑道", + "scenes.client.channelbar.channelmemberslist.title": "{{$1}} δΈ­ηš„η”¨ζˆ·", + "scenes.client.channelbar.channelmemberslist.loader": "θ£…θ½½ζ›΄ε€š", + "scenes.client.channelbar.channelmemberslist.autocomplete": "ζ·»εŠ ζˆ–ζœη΄’η”¨ζˆ·", + "scenes.client.channelbar.channelmemberslist.menu.option_2": "δ»Žι’‘ι“δΈ­εˆ ι™€", + "components.leftbar.channel.workspaceschannels.menu.option_1": "εˆ›ε»Ίι’‘ι“", + "components.leftbar.channel.workspaceschannels.menu.option_2": "加ε…₯钑道", + "components.channelworkspacelist.title": "钑道", + "scenes.client.channelbar.workspacechannellist.autocomplete": "ζœη΄’ι’‘ι“γ€η”¨ζˆ·ζˆ–η›΄ζŽ₯梈息", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_creation": "εˆ›ε»ΊδΈ€δΈͺ新选鑹卑", + "scenes.client.mainview.tabs.tabstemplateeditor.title_tab_edition": "重命名 {{$1}}", + "components.connectorslistmanager.add_connectors": "添加连ζŽ₯器", + "components.newversion.new_version_component.row.part_2": "ζˆ‘δ»¬ε»Ίθζ‚¨ι‡ζ–°εŠ θ½½εΊ”η”¨η¨‹εΊεΉΆδΊ«ε—ζˆ‘δ»¬ηš„ζ–°εŠŸθƒ½οΌ", + "components.newversion.new_version_component.link": "ε•ε‡»ζ­€ε€„ι‡ζ–°εŠ θ½½", + "components.newversion.new_version_modal.title": "ζœ‰ζ–°ηš„ζ›΄ζ–°ε―η”¨ !", + "scenes.apps.drive.download_all_button": "全部下载", + "components.inputs.input_with_select.input.placeholder": "钑道名称", + "components.inputs.input_with_select.select.placeholder": "栏η›εη§°", + "components.inputs.input_with_select.select.no_sections": "εΌ€ε§‹ε†™δΈ‹ζ‚¨ηš„η¬¬δΈ€δΈͺι’‘ι“ιƒ¨εˆ†ηš„εη§°γ€‚", + "components.inputs.input_with_select.button.tooltip": "θΎη½ι’‘ι“ιƒ¨εˆ†", + "scenes.apps.messages.message.activity_message.a_added_b_to_the_channel": "{{$1}} ι’‘ι“ζ–°ε’ž {{$2}}", + "scenes.apps.messages.message.activity_message.a_removed_b_from_the_channel": "{{$1}} δ»Žι’‘ι“δΈ­η§»ι™€ {{$2}}", + "scenes.apps.messages.message.activity_message.a_updated_channel_description": "{{$1}} 更改了描述", + "scenes.apps.messages.message.activity_message.a_updated_channel_name": "{{$1}} 将钑道重命名为 {{$2}}", + "scenes.apps.messages.message.activity_message.a_created_channel_tab": "【X0Xγ€‘ζ–°ε’žγ€X19X】标签【X30X】", + "scenes.apps.messages.message.activity_message.a_deleted_channel_tab": "{{$1}} 移陀 {{$2}} 选鑹卑 {{$3}}", + "scenes.apps.messages.message.activity_message.a_created_channel_connector": "{{$1}} ε’žεŠ δΊ†δΈ€δΈͺζ–°ηš„θΏžζŽ₯器 {{$2}}", + "scenes.apps.messages.message.activity_message.a_deleted_channel_connector": "{{$1}} 移陀了一δΈͺ连ζŽ₯器 {{$2}}", + "scenes.client.channelbar.channelmemberslist.tag": "δ½ ", + "components.alert.leave_private_channel.title": "您η‘εšθ¦η¦»εΌ€ι’‘ι“ε—οΌŸ", + "components.richtexteditor.toolbar.underline": "εΌΊθ°ƒ", + "components.richtexteditor.toolbar.italic": "ζ–œδ½“", + "components.richtexteditor.toolbar.strikethrough": "εˆ ι™€ηΊΏ", + "components.richtexteditor.toolbar.code": "代码", + "components.richtexteditor.toolbar.unordered-list": "ι‘Ήη›η¬¦ε·εˆ—葨", + "components.richtexteditor.toolbar.ordered-list": "ζœ‰εΊεˆ—θ‘¨", + "components.richtexteditor.toolbar.blockquote": "块引用", + "components.richtexteditor.toolbar.code-block": "代码块", + "components.locked_features.locked_history_banner.title": "ζ‚¨εˆšεˆšθΎΎεˆ°ζΆˆζ―ι™εˆΆ", + "components.locked_features.locked_history_banner.description": "θ΄΅ε…¬εΈζœ‰ε€§ι‡η•™θ¨€οΌη«‹ε³ε‡ηΊ§δ»₯θΏι—ζ‚¨ηš„ζ‰€ζœ‰ζΆˆζ―εŽ†ε²θ°ε½•。", + "components.locked_features.locked_history_banner.button": "δΊ†θ§£ζ›΄ε€š", + "components.locked_features.locked_guests_popup.title": "θΏε’εŠŸθƒ½ε·²ι”εš", + "components.locked_features.locked_guests_popup.subtitle": "ζ­€εŠŸθƒ½εœ¨ Twake ε…θ΄Ήη‰ˆδΈ­δΈε―η”¨", + "components.locked_features.locked_guests_popup.description": "ε“Žε“ŸοΌοΌδΌΌδΉŽζ‚¨ζƒ³ι‚€θ―·ε€–ιƒ¨η”¨ζˆ·εŠ ε…₯ζ‚¨ηš„ε·₯δ½œεŒΊγ€‚ε¦‚ζžœζ‚¨ζƒ³δΈŽε’δΊΊε’Œε€–ιƒ¨εˆδ½œδΌ™δΌ΄εδ½œοΌŒζ‚¨ε―θƒ½ιœ€θ¦θ€ƒθ™‘ε‡ηΊ§ζ‚¨ηš„θ‘εˆ’γ€‚ζŽ’η΄’ζˆ‘δ»¬ηš„εšδ»·ι€‰ι‘ΉεΉΆδΈΊζ‚¨ηš„ε›’ι˜Ÿεδ½œιœ€ζ±‚ι€‰ζ‹©ζœ€δ½³ι€‰ι‘Ήγ€‚", + "components.locked_features.locked_guests_popup.learn_more_button": "δΊ†θ§£ζ›΄ε€š", + "components.locked_features.locked_guests_popup.skip_for_now_button": "ζš‚ζ—Άθ·³θΏ‡", + "components.on_boarding.popups.blocked_company.company_selector": "εˆ‡ζ’εˆ°ε¦δΈ€εΆε…¬εΈ", + "scenes.apps.tasks.select_user_button": "ζŸ₯ηœ‹ε…Άδ»–η”¨ζˆ·ηš„δ»»εŠ‘", + "scenes.apps.messages.input.attach_file.from_computer": "δ»Žη”΅θ„‘", + "scenes.app.popup.workspaceparameter.pages.table_title": "姓名", + "scenes.client.main_view.main_header.search_input": "搜紒", + "scenes.apps.drive.new_link_title": "ζ–°ι“ΎζŽ₯", + "scenes.apps.drive.default_link_name": "ζ— ζ ‡ι’˜", + "components.emoji_picker.input_search_placeholder": "搜紒", + "services.apps.messages.message_editor_service.upload_error_toaster": "{{$1}} - ζ‚¨δΈθƒ½εœ¨ζΆˆζ―δΈ­ζ·»εŠ θΆ…θΏ‡ {{$2}} δΈͺζ–‡δ»Ά", + "scenes.apps.messages.message.parts.deleted_content.text.current_user": "δ½ εˆ ι™€δΊ†θΏ™ζ‘ζΆˆζ―", + "scenes.apps.messages.message.parts.deleted_content.text": "{{$1}} εˆ ι™€δΊ†δ»–ηš„ζΆˆζ―", + "components.member.user_parts.and_more_user_text": " ε’Œ {{$1}} ζ›΄ε€šη”¨ζˆ·", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_link": "εˆ›ε»Ίη§δΊΊι’‘ι“", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_text": " εθ€Œ", + "scenes.app.channelsbar.channelsuser.new_private_discussion.limit_reached_input_placeholder": "ζ‚¨ζ·»εŠ ηš„η”¨ζˆ·δΈθƒ½θΆ…θΏ‡ 10 δΈͺ", + "general.uploading": "上传", + "components.locked_features.locked_workspace_popup.text": "ε“Žε“ŸοΌοΌζ‚¨ζƒ³εœ¨ζ‚¨ηš„ε…¬εΈδΈ­εˆ›ε»ΊδΈ€δΈͺζ–°ηš„ε·₯δ½œη©Ίι—΄ε—οΌŸζ‚¨ε―θƒ½ιœ€θ¦θ€ƒθ™‘ε‡ηΊ§ζ‚¨ηš„θ‘εˆ’γ€‚ζŽ’η΄’ζˆ‘δ»¬ηš„εšδ»·ι€‰ι‘ΉεΉΆδΈΊζ‚¨ηš„ε›’ι˜Ÿεδ½œιœ€ζ±‚ι€‰ζ‹©ζœ€δ½³ι€‰ζ‹©γ€‚", + "components.locked_features.locked_only_office_popup.subtitle": "εœ¨ε…θ΄Ήη‰ˆζœ¬δΈ­οΌŒζ‚¨δΈθƒ½δ½Ώη”¨ onlyoffice。", + "components.locked_features.locked_only_office_popup.text": "ε“Žε“ŸοΌοΌδΌΌδΉŽζ‚¨ζƒ³δ»Ž Twake ηΌ–θΎ‘ζ–‡δ»Άγ€‚ε¦‚ζžœζ‚¨ζƒ³ε›΄η»•εŠžε…¬ζ–‡δ»ΆθΏ›θ‘Œεδ½œοΌŒζ‚¨ε―θƒ½ιœ€θ¦θ€ƒθ™‘ε‡ηΊ§ζ‚¨ηš„θ‘εˆ’γ€‚ζŽ’η΄’ζˆ‘δ»¬ηš„εšδ»·ι€‰ι‘ΉεΉΆδΈΊζ‚¨ηš„ε›’ι˜Ÿεδ½œιœ€ζ±‚ι€‰ζ‹©ζœ€δ½³ι€‰ι‘Ήγ€‚", + "components.locked_features.locked_drive_popup.title": "ζ‚¨εˆšεˆšθΎΎεˆ°ι©±εŠ¨ε™¨ι™εˆΆ", + "components.locked_features.locked_drive_popup.subtitle": "εœ¨ε…θ΄Ήη‰ˆζœ¬δΈ­οΌŒζ‚¨εͺθƒ½ε­˜ε‚¨ 6GB。", + "general.pause": "ζš‚εœ", + "scenes.app.popup.appsparameters.pages.call_event_handlers": "δΊ‹δ»Άη±»εž‹δΈΊβ€œ{{$1}}β€οΌŒid δΈΊβ€œ{{$2}}β€οΌŒθ’«εŠ¨δΈΊβ€œ{{$3}}”", + "scenes.app.popup.appsparameters.pages.company_label": "ε…¬εΈζ‰€ζœ‰θ€…", + "scenes.app.popup.appsparameters.pages.configuration_label": "配η½", + "scenes.app.popup.appsparameters.pages.create_app_button": "εˆ›ε»ΊεΊ”η”¨η¨‹εΊ", + "scenes.app.popup.appsparameters.pages.show_button": "展瀺", + "scenes.app.popup.appsparameters.pages.status_tilte": "ηŠΆζ€", + "scenes.app.popup.appsparameters.pages.website_label": "网站", + "scenes.app.popup.workspaceparameter.pages.apps_company_small_text": "θ΄΅ε…¬εΈηš„εΊ”η”¨", + "scenes.app.popup.workspaceparameter.pages.apps_connectors_title": "ι›†ζˆ", + "scenes.app.popup.workspaceparameter.pages.apps_research_title": "ζœη΄’εΊ”η”¨", + "scenes.app.popup.workspaceparameter.pages.apps_small_text": "ζ­€ε·₯δ½œεŒΊηš„εΊ”η”¨", + "scenes.app.popup.workspaceparameter.pages.configure_button": "配η½", + "scenes.app.popup.workspaceparameter.pages.weight_max_small_text": "ζœ€ε€§ε€§ε° 5 MB。", + "scenes.app.popup.workspaceparameter.pages.withdraw_button": "从歀ε·₯δ½œεŒΊδΈ­εˆ ι™€", + "scenes.app.popup.workspaceparameter.pages.worspace_notif": "ε·₯δ½œη©Ίι—΄", + "scenes.app.popup.workspaceparameter.pages.write_access_subtitle": "写权限", + "scenes.app.popup.workspaceparameter.pages.your_apps_label": "ζ‚¨ηš„εΊ”η”¨", + "scenes.app.workspacesbar.components.change_company_title": "捒公司", + "scenes.app.workspacesbar.components.create_company_menu": "εˆ›ε»Ίε…¬εΈ", + "scenes.app.workspacesbar.components.grp_parameters": "{{$1}} θΎη½", + "scenes.apps.calendar.add_calendar_menu": "添加ζ—₯εŽ†", + "scenes.apps.calendar.modals.reminders": "提醒事鑹", + "scenes.apps.calendar.no_calendar_text": "ζ‚¨ε°šζœͺδΈΊζ­€ε·₯作区θΎη½δ»»δ½•ζ—₯εŽ†γ€‚", + "scenes.apps.calendar.no_connectors_menu_text": "ζ‚¨ζ²‘ζœ‰δ»»δ½•ε―δ»₯连ζŽ₯到ζ—₯εŽ†ηš„θΏžζŽ₯器。", + "scenes.apps.calendar.remove_calendar_confirmation": "ζ°ΈδΉ…εˆ ι™€ζ—₯εŽ†εŠε…ΆδΊ‹δ»ΆοΌŸ", + "scenes.app.workspaces.components.skip": "θ·³θΏ‡", + "scenes.app.taskpicker.select": "选择", + "components.drive.modify_uslist": "δΏζ”Ήη”¨ζˆ·εˆ—葨", + "components.workspace.list_manager.add": "添加ε·₯作区", + "scenes.apps.board.display_as": "显瀺为", + "scenes.apps.board.new_task": "+ ζ–°δ»»εŠ‘", + "scenes.apps.board.all_boards": "ζ‰€ζœ‰ζΏ", + "components.alert.leave_private_channel.description": "ι™€ιžζœ‰δΊΊι‚€θ―·ζ‚¨οΌŒε¦εˆ™ζ‚¨ε°†ζ— ζ³•ε†ζ¬‘εŠ ε…₯歀私人钑道。", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.tag": "δ½ δΈζ˜―δΌšε‘˜", + "components.verify_mail.text": "ι¦–ε…ˆοΌŒζ‚¨εΏ…ι‘»ιͺŒθ―ζ‚¨ηš„甡子ι‚δ»Άεœ°ε€γ€‚ζˆ‘δ»¬ε·²ε°†ιͺŒθ―ι“ΎζŽ₯发送至", + "services.console_services.toaster.add_emails_error": "ζ·»εŠ η”΅ε­ι‚δ»Άζ—Άε‡Ίι”™", + "services.console_services.toaster.success_verify_email": "ιͺŒθ―ι“ΎζŽ₯ε·²ε‘ι€εˆ°ζ‚¨ηš„η”΅ε­ι‚δ»ΆεΈζˆ·", + "scenes.app.popup.workspaceparameter.edit_from_console": "在控刢台中ζŸ₯ηœ‹", + "services.console_services.toaster.success_invite_emails": "已成功添加 {{$1}} δΈͺη”¨ζˆ·", + "scenes.client.channels_bar.modals.guest_management.title": "在 {{$1}} δΈ­η‘理ζ₯εΎ", + "scenes.client.channels_bar.modals.parts.channel_member_row.label.pending_email": "ι‚仢已发送", + "general.user.role.company.admin": "公司η‘η†ε‘˜", + "general.user.role.company.guest": "ε’δΊΊ", + "general.user.deleted": "ε·²εˆ ι™€εΈζˆ·", + "components.richtexteditor.toolbar.bold": "胆倧", + "components.locked_features.locked_guests_popup.or": "ζˆ–θ€…", + "components.on_boarding.popups.blocked_company.title": "ζ‚¨ηš„ε…¬εΈε› δ»˜ζ¬Ύι—ι’˜θ€Œθ’«ι”εš", + "components.on_boarding.popups.blocked_company.company_subscription_plan_button": "η‚Ήε‡»θΏ™ι‡Œ", + "components.emoji_picker.categories.animals_and_nature": "εŠ¨η‰©δΈŽθ‡ͺη„Ά", + "components.emoji_picker.categories.food_and_drink": "ι£Ÿη‰©ε’Œι₯ζ–™", + "scenes.app.integrations_parameters.applications_table.search_placeholder": "ζœη΄’εΊ”η”¨", + "scenes.app.integrations_parameters.company_application_popup.tag": "ε·²ε‰θ£…", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.description_item": "描述", + "scenes.app.integrations_parameters.company_application_popup.tab_info.descriptions.website_item": "网站", + "scenes.app.integrations_parameters.company_applications_table.more_menu.show_application": "展瀺", + "app.state.recoil.hooks.use_current_company_applications.toaster_delete": "ε·²ζˆεŠŸδ»Žθ΄΅ε…¬εΈεˆ ι™€ {{$1}}", + "app.state.recoil.hooks.use_current_company_applications.toaster_add": "εœ¨θ΄΅ε…¬εΈζˆεŠŸζ·»εŠ γ€X19X】", + "scenes.apps.messages.input.replied_to": "ε›žε€ ", + "general.help.documentation": "ζ–‡ζ‘£", + "scenes.apps.calendar.event_edition.deadline_tag": "ζœ€εŽζœŸι™", + "scenes.apps.drive.left.search": "搜紒", + "scenes.apps.parameters.group_sections.apps.badge_extension": "廢期", + "scenes.apps.parameters.workspace_sections.members.members": "η”¨ζˆ·", + "scenes.apps.parameters.workspace_sections.members.pending": "εΎ…ε€„η†ηš„η”΅ε­ι‚δ»Ά", + "scenes.apps.parameters.workspace_sections.members.invite": "ι‚€θ―·ζ–°η”¨ζˆ·", + "scenes.apps.tasks.list_modal.modify_list": "δΏζ”Ήεˆ—葨", + "scenes.apps.tasks.list_modal.new_list": "新名单", + "scenes.apps.tasks.list_modal.remove": "εˆ ι™€εˆ—θ‘¨ε’Œδ»»εŠ‘", + "scenes.apps.tasks.list_modal.predefined_participants": "ι’„εšδΉ‰ε‚δΈŽθ€…", + "scenes.apps.tasks.list_modal.archive_all_tasks": "ε½’ζ‘£ζ‰€ζœ‰δ»»εŠ‘", + "scenes.app.popup.appsparameters.pages._app_identity": "εΊ”η”¨η¨‹εΊηš„θΊ«δ»½", + "scenes.app.popup.appsparameters.pages._appareance_message_twakcode": "ζ΅‹θ―•ζ‚¨ηš„ Twacode ζΆˆζ―ηš„ε€–θ§‚", + "scenes.app.popup.appsparameters.pages.error_user_code": "ι”™θ――", + "scenes.app.popup.appsparameters.pages.danger_zone_small_text": "ε¦‚ζžœζ­€εΊ”η”¨ε·²ε‘εΈƒοΌŒζ‚¨ε°†ζ— ζ³•εˆ ι™€εƒγ€‚", + "scenes.app.popup.appsparameters.pages.error_app_simple_name_message": "ζ‚¨ηš„εΊ”η”¨η¨‹εΊηš„η€εŒ–名称已蒫另一δΈͺεΊ”η”¨η¨‹εΊδ½Ώη”¨γ€‚θ―·ζ”Ήε˜εƒγ€‚", + "scenes.app.popup.appsparameters.pages.error_app_update_message": "更新应用程序既出错。", + "scenes.app.popup.appsparameters.pages.remove_app_button": "εˆ ι™€η”³θ―·", + "scenes.app.popup.workspaceparameter.pages.read_access_subtitle": "读取权限", + "scenes.apps.drive.unconfigured_tab": "ζ­€ι€‰ι‘Ήε‘ε°šζœͺ配η½γ€‚", + "scenes.apps.drive.viewer.edit_with_button": "使用 {{$1}} θΏ›θ‘ŒηΌ–θΎ‘", + "scenes.apps.drive.viewer.loading_preview_message": "正在加载...", + "scenes.apps.drive.viewer.no_preview_message": "无法ζŸ₯ηœ‹ζ­€η±»ζ–‡δ»Άγ€‚", + "scenes.login.verifymail.alert": "ζˆ‘δ»¬ζ­£εœ¨ζ£€ζŸ₯ζ‚¨ηš„η”΅ε­ι‚仢!", + "scenes.login.verifymail.error_message": "ε‘η”Ÿι”™θ――", + "scenes.apps.drive.trash": "εžƒεœΎ", + "scenes.tell_us": "θ―·ε‘Šθ―‰ζˆ‘δ»¬δ½ εœ¨εšδ»€δΉˆοΌš", + "scenes.apps.drive.viewer.download_desktop": "δΈ‹θ½½ Twake Desktop δ»₯εœ¨εΊ”η”¨η¨‹εΊδΈ­θΏ›θ‘Œι’„θ§ˆ", + "app.name.twake_drive": "ζ–‡δ»Ά", + "scenes.login.forgot_password.email_to_recover": "θ¦ζ’ε€ηš„η”΅ε­ι‚δ»Ά", + "scenes.login.forgot_password.mail_doesnt_exist": "ζ­€ι‚η±δΈε­˜εœ¨", + "scenes.login.home.lost_password": "忘θ°ε―†η οΌŸ", + "scenes.login.home.create_account": "εˆ›ε»ΊδΈ€δΈͺ帐户", + "scenes.login.create_account.password": "密码", + "scenes.login.create_account.step_1_subtitle": "再η€ε•δΈθΏ‡δΊ†β€”β€”ζˆ‘δ»¬εͺιœ€θ¦δΈ€δΊ›δΏ‘ζ―γ€‚", + "scenes.login.create_account.step_2_subtitle_a": "ζ·»εŠ ζ‚¨ηš„ε…¨εδ»₯δΎΏε…Άδ»–η”¨ζˆ·θ―†εˆ«ζ‚¨γ€‚", + "scenes.login.create_account.step_2_subtitle_b": "ζ‚¨ηš„η”΅θ―ε·η δΏζŒη§ε―†γ€‚", + "app.name.twake_tasks": "任劑", + "components.calendar.repetition.everyday": "ζ—₯εΈΈηš„", + "components.calendar.repetition.does_not_repeat": "不重倍", + "components.calendar.repetition.weekly_on": "每周 {{$1}}", + "components.calendar.repetition.monthly_on": "每月上 {{$1}} {{$2}}", + "components.calendar.repetition.monthly_on_day": "每月第 {{$1}}", + "components.calendar.repetition.annually_on": "每年在 {{$1}}", + "components.calendar.repetition.every_weekday": "每δΈͺε·₯作ζ—₯οΌˆε‘¨δΈ€θ‡³ε‘¨δΊ”οΌ‰", + "components.calendar.repetition.custom": "ι£ŽδΏ—...", + "components.calendar.repetition.repeat": "重倍每", + "components.calendar.repetition.ends": "η»“ζŸ", + "components.calendar.repetition.never": "绝不", + "components.calendar.repetition.on": "在", + "components.calendar.repetition.after": "后", + "components.calendar.repetition.days": "倩)", + "components.calendar.repetition.weeks": "周", + "components.calendar.repetition.months": "月", + "scenes.app.channelsbar.currentuser.user_parameter": "ι€šηŸ₯θΎη½", + "components.emoji_picker.categories.smileys_and_people": "η¬‘θ„ΈδΈŽδΊΊη‰©", + "general.resume": "恒倍", + "scenes.app.popup.workspaceparameter.pages.deleteworkspace_description": "要η‘θ€ζ‚¨θ¦εˆ ι™€ζ­€ε·₯δ½œεŒΊοΌŒθ―·εœ¨δΈ‹ι’ι”ε…₯εη§°εΉΆη‚Ήε‡»εˆ ι™€γ€‚", + "scenes.apps.messages.message.unpin_button": "ε–ζΆˆε›ΊεšζΆˆζ―", + "scenes.apps.messages.message.copy_link": "ε€εˆΆι“ΎζŽ₯到梈息", + "scenes.apps.messages.message.pinned": "ε›Ίεš", + "scenes.apps.messages.message.remove_button": "εˆ ι™€", + "scenes.apps.messages.message.reply_button": "ε›žε€", + "scenes.apps.messages.message.save_button": "θŠ‚ηœ", + "scenes.apps.messages.message.show_button": "展瀺", + "scenes.apps.messages.message.show_responses_button": "ζŸ₯ηœ‹ζ‰€ζœ‰η­”ζ‘ˆ", + "scenes.apps.messages.message.types.first_channel_message_text": "θΏ™ζ˜―ι’‘ι“ηš„η¬¬δΈ€ζ‘ζΆˆζ―", + "scenes.apps.messages.message.types.first_message_text": "θΏ™ζ˜―η¬¬δΈ€ζ‘ζΆˆζ―", + "scenes.apps.messages.messageslist.get_writing_user": "εœ¨ε†™ε­—...", + "scenes.apps.messages.messageslist.get_writing_users": "εœ¨ε†™...", + "scenes.apps.messages.messageslist.go_last_message_button": "θ½¬εˆ°ζœ€εŽδΈ€ζ‘ζΆˆζ―", + "scenes.apps.messages.messageslist.go_last_message_button.new_messages": "ζ–°ζΆˆζ―", + "scenes.error_on_twake": "β€œδΌ‘ζ–―ι‘ΏοΌŒζˆ‘δ»¬ζœ‰δΈ€δΈͺι—ι’˜β€", + "scenes.help_us": "δ½†ζ˜―οΌŒε¦‚ζžœζ‚¨ζƒ³εΈεŠ©ζˆ‘δ»¬θ§£ε†³ζ­€ι”™θ――οΌŒθ―·εœ¨δΈ‹ι’η»™ζˆ‘δ»¬ε‘ι€ζΆˆζ―οΌš ", + "scenes.apps.account.message_temporary": "δΈ΄ζ—ΆεΈζˆ·ηš„ε·₯δ½œζ–ΉεΌδΈŽζ™ι€šηš„ Twake εΈζˆ·η±»δΌΌοΌŒδ½†ζ‚¨εˆ›ε»ΊδΊ†ε―†η οΌŒεΉΆδΈ”ε―δ»₯εœ¨εΏ…θ¦ζ—Άι‡η½εƒγ€‚", + "scenes.apps.account.message_user_signin": "ζ‚¨ηš„η”¨ζˆ·ε―δ»₯ιšζ—Άδ½Ώη”¨εŒδΈ€η”΅ε­ι‚δ»Άη™»ε½•εΉΆε°†δΈ΄ζ—ΆεΈζˆ·ζ›΄ζ”ΉδΈΊζ™ι€šεΈζˆ·γ€‚", + "scenes.app.mainview.link_expired": "ζ­€ε…¬ε…±ι“ΎζŽ₯ζ— ζ•ˆζˆ–ε·²θΏ‡ζœŸγ€‚", + "scenes.app.mainview.create_account": "ε…θ΄Ήεˆ›ε»Ίζ‚¨ηš„ε·₯作区 ", + "scenes.apps.calendar.modals.reminder_add": "ζ·»εŠ ζι†’", + "scenes.apps.parameters.workspace_sections.members.invite_all": "ι‚€θ―·ζ‰€ζœ‰δΊΊ", + "components.workspace.list_manager.current_company": "ηŽ°δ»»ε…¬εΈ", + "components.workspace.calendar.invalid": "ζ— ζ•ˆηš„", + "components.searchpopup.enter_text": "θΎ“ε…₯δΈ€δΊ›ζ–‡ζœ¬δ»₯搜紒 Twake。", + "components.reminder.notification": "ι€šηŸ₯", + "components.reminder.minutes_bef": "ε‡ εˆ†ι’Ÿε‰", + "components.reminder.hours_bef": "几小既前", + "components.reminder.days_bef": "几倩前", + "components.reminder.weeks_bef": "几周前", + "components.reminder.by_email": "甡子ι‚δ»Ά", + "scenes.apps.calendar.video_link": "点击打开链ζŽ₯", + "scenes.app.mainview.discussion": "θ¨θΊ", + "components.tagpicker.notag": "ζ— ζ ‡η­Ύ", + "scenes.apps.tasks.modals.attachments": "ι™„δ»Ά", + "components.calendar.calendarselector.from": "从", + "scenes.apps.drive.move_text2": "移动", + "scenes.client.channelsbar.modals.workspace_channel_list.workspace_channel_row.loader": "θ£…θ½½ζ›΄ε€š", + "components.unverified_account.typography_text_danger": "ζ‚¨θΏ˜ζœ‰ {{$1}} ε€©ηš„θ―•η”¨ζœŸγ€‚θ―•η”¨εΈζˆ·ε°†εœ¨ 7 ε€©εŽθ’«ε†»η»“οΌŒεΉΆεœ¨ζ³¨ε†Œ 1 δΈͺζœˆεŽζ°ΈδΉ…εˆ ι™€γ€‚ζ‚¨ε―δ»₯ι€šθΏ‡ε•ε‡»ζˆ‘δ»¬ε‘ι€η»™ζ‚¨ηš„ιͺŒθ―η”΅ε­ι‚δ»ΆδΈ­ηš„β€œιͺŒθ―ζˆ‘ηš„εΈζˆ·β€ζŒ‰ι’ζ₯ιͺŒθ―ζ‚¨ηš„εΈζˆ·γ€‚", + "components.unverified_account.verification_details": "ζˆ‘δ»¬ε·²ε°†ιͺŒθ―θ―¦η»†δΏ‘息发送至", + "components.account_verification_status_sentence": "ζ‚¨ηš„εΈζˆ·ηŠΆζ€ζ˜―οΌš{{$1}}", + "components.account_verication_status_unverified": "ζœͺ经证εž", + "components.add_mails_workspace.button": "开始使用 Twake", + "components.add_mails_workspace.title_1": "ζ·»εŠ δΈ€δΊ›η”¨ζˆ·", + "components.add_mails_workspace.title_2": "Twake ζ˜―δΈ€δΈͺε›’ι˜Ÿεδ½œε·₯ε…·οΌŒε› ζ­€θ―·ι‚€θ―·δΈ€δΊ›η”¨ζˆ·ζ₯ζ΅‹θ―•ζˆ‘δ»¬δΈΊζ‚¨εˆ›ε»Ίηš„ε·₯δ½œεŒΊγ€‚", + "components.add_mails_workspace.text_area_placeholder": "θΎ“ε…₯ζ‚¨ηš„η”¨ζˆ·ηš„η”΅ε­ι‚δ»Ά*", + "components.verify_mail.title_1": "ζ­ε–œ", + "components.verify_mail.title_2": "ζ‚¨ηŽ°εœ¨ζ˜― Twake ηš„ζ­£εΌη”¨ζˆ·οΌ", + "components.verify_mail.button": "ζ·»εŠ η”¨ζˆ·", + "general.user.role.company.member": "ζˆε‘˜", + "components.on_boarding.popups.blocked_company.or": "ζˆ–θ€…", + "scenes.apps.tasks.select_user": "ζœη΄’η”¨ζˆ·", + "components.emoji_picker.categories.not_found": "ζœͺζ‰Ύεˆ°θ‘¨ζƒ…η¬¦ε·", + "components.locked_features.locked_workspace_popup.subtitle": "εœ¨ε…θ΄Ήη‰ˆζœ¬δΈ­οΌŒζ‚¨ηš„ε…¬εΈδΈ­εͺ能ζ‹₯ζœ‰δΈ€δΈͺε·₯δ½œεŒΊγ€‚", + "components.locked_features.locked_only_office_popup.title": "您无法编辑歀文仢", + "'": "'", + "scenes.apps.messages.message.types.no_message_in_thread": "θΏ˜ζ²‘ζœ‰δΊΊε›žε€γ€‚", + "login.create_account": "εˆ›ε»Ίθ΄¦ζˆ·", + "login.login_error": "登录既出错", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.label": "默θ€ε·₯作区", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.unknown": "ζœͺηŸ₯ι”™θ――", + "\"": "”", + "scenes.app.workspaces.welcome_page.no_workspace_subtitle": "θΏ˜ζ²‘ζœ‰δΊΊι‚€θ―·ζ‚¨εˆ°ε·₯δ½œεŒΊγ€‚", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.default_workspace.description": "θ‡ͺεŠ¨ι‚€θ―·ζ‰€ζœ‰ε·₯δ½œεŒΊη”¨ζˆ·εŠ ε…₯歀钑道", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.title": "ζ‚¨ε³ε°†εˆ ι™€ {{$1}}", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.alert_total_members": "ζ‚¨εœ¨ {{$2}} δΈ­δ»ζœ‰ {{$1}} ζˆε‘˜γ€‚ζ‚¨εΊ”θ―₯εˆ ι™€ζ‰€ζœ‰ζˆε‘˜ζ‰θƒ½εˆ ι™€ζ­€ε·₯δ½œεŒΊγ€‚", + "scenes.app.popup.workspaceparameter.pages.delete_workspace_popup.checkbox": "ζˆ‘δΊ†θ§£ζˆ‘ε·₯δ½œεŒΊηš„ζ‰€ζœ‰ζΆˆζ―ε’Œζ–‡δ»Άιƒ½ε°†θ’«εˆ ι™€γ€‚", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.max_size": "ζœ€ε€§εΎ½ζ ‡ε€§ε°δΈΊ 5mb", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.bad_format": "ζ ΌεΌι”™θ――οΌŒεͺ允θΈδ½Ώη”¨ png gif ε’Œ jpg", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.error.prefix": "ι”™θ――", + "scenes.app.channelsbar.currentuser.reset": "重启", + "components.rich_text_editor.plugins.suggestions.default_message.display_results": "至少写三δΈͺ字母ζ₯ζ˜Ύη€Ίη”¨ζˆ·", + "components.rich_text_editor.plugins.suggestions.default_message.no_user_found": "ζœͺζ‰Ύεˆ°η”¨ζˆ·", + "components.rich_text_editor.plugins.suggestions.default_message.no_emoji_found": "ζœͺζ‰Ύεˆ°θ‘¨ζƒ…η¬¦ε·", + "components.rich_text_editor.plugins.suggestions.default_message.no_command_found": "ζœͺζ‰Ύεˆ°ε‘½δ»€", + "scenes.app.messages.input.parts.is_writing.message.users_and_more_are_writing": "{{$1}}、{{$2}} ε’Œ {{$3}} ζ›΄ε€šη”¨ζˆ·ζ­£εœ¨ε†™...", + "scenes.app.messages.input.parts.is_writing.message.user_is_writing": "{{$1}} ζ­£εœ¨ε†™...", + "scenes.app.messages.input.parts.is_writing.message.users_are_writing": "{{$1}} ε’Œ {{$2}} ζ­£εœ¨ε†™ε…₯...", + "components.locked_features_components.locked_invite_alert.message_link": "ε‡ηΊ§ζ‚¨ηš„ε…¬εΈ", + "components.locked_features_components.locked_invite_alert.message_magic_link": " θ”η³»ζ‚¨ε…¬εΈηš„ζ‰€ζœ‰θ€…ζˆ–η‘η†ε‘˜γ€‚", + "components.locked_features_components.locked_invite_alert.message_part_1": "θ΄΅ε…¬εΈε·²θΎΎεˆ° {{$1}} ζˆε‘˜ηš„ζœ€ε€§ι™εˆΆγ€‚θ―· ", + "components.locked_features_components.locked_invite_alert.message_part_2": " ι‚€θ―·ζ›΄ε€šζˆε‘˜γ€‚", + "views.client.popup.workspace_parameter.pages.workspace_members.link_to_console": "在控刢台上ζŸ₯ηœ‹ζˆ‘ηš„ζ‰€ζœ‰ε…¬εΈζˆε‘˜", + "twake.application.access.title": "δΈΊζ‚¨ηš„εΊ”η”¨ι€‰ζ‹©ζ­£η‘ηš„θŒƒε›΄γ€‚", + "twake.application.access.no_default_scopes_available'": "ζ­€ι›†ζˆζ²‘ζœ‰δ»»δ½• {{$1}} θΏι—权限", + "scenes.app.popup.appsparameters.pages.application_editor.application_published": "{{$1}}η”³θ―·ζˆεŠŸοΌ", + "scenes.app.integrations_parameters.add_application": "ζ–°ζ•΄εˆ", + "scenes.app.integrations_parameters.company_applications_table.more_menu.developer_settings": "开发者θΎη½", + "scenes.app.popup.appsparameters.pages.amazing_app_description": "用几ε₯θ―ζθΏ°ζ‚¨ηš„εΊ”η”¨η¨‹εΊ", + "scenes.app.popup.appsparameters.pages.application_creator.title": "ζ–°ζ•΄εˆ", + "scenes.app.popup.appsparameters.pages.application_creator.checkbox": "ζˆ‘δΊ†θ§£θ―₯ε…¬εΈηš„ζ‰€ζœ‰θ€…ε’Œη‘η†ε‘˜ε°†θƒ½ε€ŸδΏζ”Ήε’Œε‘布歀应用程序。", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed": "ζˆεŠŸεˆ ι™€εΊ”η”¨η¨‹εΊ {{$1}} !", + "scenes.app.popup.appsparameters.pages.application_editor.application_removed_error": "εˆ ι™€εΊ”η”¨η¨‹εΊ {{$1}} 既出错!", + "scenes.app.popup.appsparameters.pages.application_editor.help_link": "Twake API ζ–‡ζ‘£", + "scenes.app.popup.appsparameters.pages.application_editor.help_text": "ε¦‚ζžœζ‚¨δΈηŸ₯ι“ε¦‚δ½•ε‘«ε†™θΏ™δΊ›οΌŒθ―·θΏι— ", + "scenes.app.popup.appsparameters.pages.app.private_key": "私ι’₯", + "components.rich_text_editor.plugins.suggestions.loading": "ε―»ζ‰Ύζ›΄ε€š", + "components.open_desktop_popup.subtitle": "在 Twake 應用中打開", + "components.open_desktop_popup.open_here_link": "ζ”Ήη‚Ίεœ¨ζ­€θ™•ζ‰“ι–‹", + "molecules.download_banner.title": "ε……εˆ†εˆ©η”¨ twakeοΌŒη«‹ε³δΈ‹θ½½ζ‘Œι’εΊ”η”¨η¨‹εΊ", + "molecules.download_banner.download_button": "δΈ‹θ½½ζ‘Œι’εΊ”η”¨η¨‹εΊ", + "scenes.app.channelsbar.channel_copy_link": "ε€εˆΆι’‘ι“ι“ΎζŽ₯", + "scenes.app.popup.workspaceparameter.pages.workspace_identity.toaster.success.update": "ζˆεŠŸζ›΄ζ–°", + "components.searchpopup.recent_media": "θΏ‘ζœŸεͺ’体", + "components.searchpopup.recent_files": "ζœ€θΏ‘ηš„ζ–‡δ»Ά", + "components.searchpopup.no_results_for": "ζ²‘ζœ‰η»“ζžœ", + "components.searchpopup.try_new_search": "ε°θ―•ζ–°ηš„ζœη΄’", + "components.searchpopup.all": "全部", + "components.searchpopup.chats": "聊倩", + "components.searchpopup.media": "εͺ’体", + "components.searchpopup.files": "ζ–‡δ»Ά", + "components.searchpopup.recent_chats": "ζœ€θΏ‘ηš„θŠε€©", + "components.searchpopup.recent_channels_and_contacts": "ζœ€θΏ‘ηš„ι’‘ι“ε’Œθ”η³»δΊΊ", + "components.searchpopup.header_title": "搜紒", + "components.searchpopup.scope.company": "εœ¨ζ‰€ζœ‰ε…¬εΈ", + "components.searchpopup.scope.channel": "εœ¨θΏ™δΈͺ钑道", + "components.searchpopup.channels": "钑道", + "components.searchpopup.messages": "留言", + "components.channel_attachement_list.medias": "εͺ’体", + "components.channel_attachement_list.files": "ζ–‡δ»Ά", + "components.channel_attachement_list.title": "ι’‘ι“ζ–‡δ»Άε’Œεͺ’体", + "components.searchpopup.start_search": "θΎ“ε…₯ε‡ δΈͺε…³ι”ε­—εΌ€ε§‹ζœη΄’。", + "components.searchpopup.see_more": "ηœ‹ζ›΄ε€š", + "scenes.client.channelbar.channelmemberslist.search_invite": "ζœη΄’εΉΆι‚€θ―·η”¨ζˆ·εŠ ε…₯歀钑道", + "scenes.client.channelbar.channelmemberslist.search_invite_notice": "θΏ™δΈͺι’‘ι“ηš„δΌšε‘˜δΈε€šγ€‚ηŽ°εœ¨ι€šθΏ‡η”΅ε­ι‚δ»Άζˆ–ε§“εζœη΄’ε’Œι‚€θ―·η”¨ζˆ·γ€‚", + "scenes.client.channelbar.channelmemberslist.invite_email_button": "δ»…δ»₯θΏε’θΊ«δ»½ζ·»εŠ εˆ°ι’‘ι“", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace": "δ½œδΈΊζˆε‘˜ζ·»εŠ εˆ°ι’‘ι“ε’Œε·₯作区", + "scenes.client.channelbar.channelmemberslist.invite_email_button_workspace_confirm": "ι‚€θ―· {{$1}} δ½œδΈΊζˆε‘˜εŠ ε…₯ε·₯作区?", + "scenes.client.channelbar.channelmemberslist.search_invite_type_email": "θΎ“ε…₯ζœ‰ζ•ˆεœ°ε€δ»₯ι€šθΏ‡η”΅ε­ι‚仢邀请。", + "scenes.client.channelbar.channelmemberslist.pending_section": "η”¨ζˆ·η­‰εΎ…ι‚€θ―·", + "scenes.client.channelbar.channelmemberslist.members_section": "θ―₯ι’‘ι“ηš„η”¨ζˆ·", + "scenes.client.channelbar.channelmemberslist.not_members_section": "δΈεœ¨ζ­€ι’‘ι“ηš„η”¨ζˆ·", + "scenes.client.join_private_channel.info": "ζ­€ι’‘ι“ηš„ζ­€ε†…εΉε—εˆ°ι™εˆΆζˆ–δΈε­˜εœ¨γ€‚θ―·θ”η³»ζ­€ι’‘ι“ηš„ζˆε‘˜δ»₯θŽ·εΎ—ι‚€θ―·γ€‚", + "scenes.client.join_public_channel": "加ε…₯θΏ™δΈͺ钑道", + "scenes.client.join_public_channel.info": "ζ‚¨δΈζ˜―ζ­€η›΄ζŽ₯ι’‘ι“ηš„ζˆε‘˜γ€‚ε•ε‡»ζ­€ζŒ‰ι’立即开始θ¨θΊγ€‚", + "general.yes": "ζ˜―ηš„", + "general.no": "不", + "components.open_desktop_popup.open_here_link_forever": "ζ°ΈθΏœδΈθ¦ε°θ―•ε†ζ¬‘ζ‰“εΌ€εΊ”η”¨η¨‹εΊ", + "components.channel_attachement_list.nothing_found": "θΏ™ι‡ŒθΏ˜ζ²‘ζœ‰", + "molecules.message_quote.deleted": "ζ­€ζΆˆζ―ε·²εˆ ι™€", + "components.channel_attachement_list.open": "ζ‰“εΌ€η”»ε»Š", + "scenes.apps.messages.jump": "跳转到梈息", + "scenes.apps.account.assistant.title": "εŠ©ζ‰‹", + "scenes.apps.account.on_console": "θ¦ηΌ–θΎ‘ζ‚¨ηš„ε…¨ε±€εΈζˆ·ι¦–ι€‰ι‘ΉοΌŒθ―·ε•ε‡»θ½¬εˆ°ζŽ§εˆΆε°γ€‚", + "scenes.apps.account.assistant.description": "Twake εŠ©ζ‰‹θƒ½ε€Ÿη†θ§£ζ‚¨εœ¨ Twake δΈŠηš„ζ—₯εΈΈε·₯δ½œοΌŒεΉΆεœ¨ζ‚¨ηš„δΈ€ε€©δΈ­ζδΎ›ζ™Ίθƒ½εΏ«ζ·ζ–ΉεΌε’Œζ“δ½œγ€‚θ―₯εŠ©ζ‰‹ζ˜― Work@Home 們θ https://workathome.linagora.com/ ηš„δΈ€ιƒ¨εˆ†οΌŒη›ε‰δ»…εœ¨ Linagora ε…¬εΈθΏ›θ‘Œζ΅‹θ―•οΌŒεΉΆε€„δΊŽε­¦δΉ ι˜Άζ΅γ€‚θΏ™ζ„ε‘³η€ζˆ‘δ»¬ε°†ε‘ι€ Twake 使用数ζδ»₯θ­η»ƒζˆ‘们ζœͺζ₯ηš„εŠ©ζ‰‹εŠŸθƒ½γ€‚", + "scenes.apps.account.assistant.share.nothing": "δΈδΈŽεŠ©ζ‰‹εˆ†δΊ«δ»»δ½•ε†…εΉοΌˆη¦η”¨εŠ©ζ‰‹οΌ‰", + "scenes.apps.account.assistant.share.all": "ε…±δΊ«ζ‰€ζœ‰ε†…εΉοΌŒεŒ…ζ‹¬ζΆˆζ―ε’Œζ–‡δ»Άε†…εΉ", + "scenes.apps.account.assistant.share.metadata": "ε…±δΊ«ε…ƒζ•°ζδ½†δΈε…±δΊ«ε†…εΉ", + "scenes.apps.account.assistant.success": "ζ‚¨ηš„εε₯½ε·²ζˆεŠŸζ›΄ζ–°γ€‚", + "components.message_seen_by.title": "ηœ‹εˆ°ζΆˆζ―ηš„η”¨ζˆ·", + "components.message_seen_by.none_seen_it": "θΏ˜ζ²‘ζœ‰δΊΊηœ‹εˆ°θΏ™ζ‘ζΆˆζ―", + "components.message_seen_by.btn": "俑息", + "molecules.quoted_content.attachements": "{{$1}} ι™„δ»Ά", + "general.user.deactivated": "η”¨ζˆ·ε·²δΈεœ¨θ―₯公司", + "scenes.apps.messages.message.user_deactivated": "ζ‚¨ζ­£εœ¨ζŸ₯ηœ‹ε·²εœη”¨εΈζˆ·ηš„ζ‘£ζ‘ˆ", + "general.user.connected": "εœ¨ηΊΏηš„", + "scenes.app.popup.userparameter.pages.email_notif_delay_quarter_hour": "15εˆ†ι’Ÿ", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_day": "1倩", + "scenes.app.popup.userparameter.pages.email_notif_delay_one_hour": "1小既", + "scenes.app.popup.userparameter.pages.email_notif_delay_never": "绝不", + "scenes.app.popup.userparameter.pages.notification_sound.defaut": "默θ€", + "scenes.app.popup.userparameter.pages.notification_sound.none": "ζ²‘ζœ‰δ»»δ½•", + "scenes.client.channelbar.readonly_channel.checkbox": "ι™εˆΆε―ε†™ζ€§", + "scenes.apps.messages.message.forward": "向前", + "scenes.apps.messages.message.forward.title": "转发俑息", + "scenes.apps.messages.message.forward.comment": "添加梈息", + "scenes.apps.messages.message.forward.confirm": "ε‘ι€εˆ° $1 钑道", + "scenes.apps.messages.message.forward.send": "ε·²θ½¬ε‘ζΆˆζ―", + "components.channelselector.title": "选择钑道", + "components.channelselector.confirm": "选择 $1 钑道", + "components.channelselector.search": "ζœη΄’ι’‘ι“ε’Œθ¨θΊ", + "scenes.app.channelsbar.channel_access": "钑道θΏι—", + "scenes.app.channelsbar.channel_access.save": "保存θΏι—θΎη½", + "scenes.app.channelsbar.channel_access.readonly": "εͺθ―»ι€šι“", + "scenes.app.channelsbar.channel_access.readonly.info": "ι™εˆΆε―Ήη‰ˆδΈ»γ€η‘η†ε‘˜ε’Œζ‰€ζœ‰θ€…ηš„ε†™ε…₯。", + "scenes.app.channelsbar.channel_access.visibility": "ε…¬δΌ—ηŸ₯名度", + "scenes.app.channelsbar.channel_access.visibility.info": "陀公司ε’δΊΊε€–οΌŒδ»»δ½•δΊΊε‡ε―εŠ ε…₯。", + "scenes.app.channelsbar.channel_access.default": "θ‡ͺ动加ε…₯", + "scenes.app.channelsbar.channel_access.default.info": "ζ–°ζˆε‘˜ε°†θ‡ͺεŠ¨ζ·»εŠ εˆ°ζ­€ε€„γ€‚", + "scenes.app.channelsbar.channel_information": "编辑钑道俑息", + "scenes.app.channelsbar.channel_information.logo.add": "δΈŠδΌ ε›Ύη‰‡", + "scenes.app.channelsbar.channel_information.logo.remove": "εˆ ι™€ε›Ύη‰‡", + "scenes.app.channelsbar.channel_information.name": "钑道名称", + "scenes.app.channelsbar.channel_information.description": "ι’‘ι“θ―΄ζ˜Ž", + "scenes.app.channelsbar.channel_information.description.placeholder": "ι’‘ι“ζθΏ°οΌŒε―δ»₯使用markdown。", + "scenes.app.channelsbar.channel_information.group": "钑道组", + "scenes.app.channelsbar.channel_information.group.none": "ζœͺι€‰δΈ­ηš„", + "scenes.app.channelsbar.channel_information.group.new": "εˆ›ε»ΊδΈ€δΈͺζ–°η»„", + "scenes.app.channelsbar.channel_information.group.save": "将钑道组θΎη½δΈΊ $1", + "scenes.app.channelsbar.channel_information.group.save_none": "不θΎη½ι’‘道组", + "scenes.app.channelsbar.channel_information.save": "保存俑息", + "components.invitation.bulk_invitation": "批量邀请", + "components.invitation.button": "发送邀请", + "scenes.client.channelbar.channelmemberslist.invite_to_workspace": "ι‚€θ―· {{$1}} 到ε·₯作区➑", + "components.invitation.reached_limit.text": "ζ‚¨ε·²θΎΎεˆ°ε…¬εΈε†…ιƒ¨ηš„ζœ€ε€§η”¨ζˆ·ζ•°γ€‚ε’žεŠ ζ‚¨ηš„θ’ι˜…ζˆ–ε°†θΏ™δΊ›η”¨ζˆ·ζ·»εŠ δΈΊθΏε’", + "components.invitation.allow_anyone_by_email.text": "θ©δ»»δ½•ζ‹₯ζœ‰@{{$1}} 甡子ι‚δ»Άηš„δΊΊεŠ ε…₯ζ­€ε·₯作区", + "components.invitation.invitation_channels.button": "邀请钑道", + "components.invitation.invitation_input_list.add": "添加", + "components.invitation.invitation_input_list.member": "ζˆε‘˜", + "components.invitation.invitation_input_list.guest": "ζ₯εΎ", + "components.invitation.invitation_input_list.placeholder": "εΌ€ε§‹θΎ“ε…₯甡子ι‚δ»Ά", + "components.invitation.invitation_sent.title": "ι‚€θ―·ε·²ζˆεŠŸε‘ι€", + "components.invitation.invitation_sent.subtitle_status": "您可δ»₯在δ»₯下位η½θ·ŸθΈͺι‚€θ―·ηŠΆζ€οΌš", + "components.invitation.invitation_sent.subtitle_location": "ε·₯作区θΎη½ > ζˆε‘˜η‘理", + "components.invitation.invitation_sent.link": "ζ£€ζŸ₯ι‚€θ―·ηŠΆζ€", + "components.invitation.invitation_sent.button": "ε‘ι€ζ›΄ε€šι‚€θ―·", + "components.invitation.invitation_target.invite_as_guests": "ι‚€θ―·ζ‰€ζœ‰δΊΊδ½œδΈΊε’δΊΊ", + "components.invitation.invitation_target.invite_as_members": "ι‚€θ―·ζ‰€ζœ‰δΊΊζˆδΈΊδΌšε‘˜", + "components.invitation.invitation_target.channels_button": "邀请渠道", + "components.invitation.workspace_link.text": "ε·₯δ½œεŒΊι‚€θ―·ι“ΎζŽ₯", + "components.invitation.workspace_link.button": "倍刢", + "components.invitation.title": "ι‚€θ―·δΊΊ {{$1}}", + "scenes.client.readonly.info": "ζ­€ι’‘ι“ζ˜―εͺθ―»ζθ¦οΌŒδ½†ζ‚¨ε―δ»₯εœ¨ηΊΏη¨‹δΈ­ε‘θ‘¨θ―„θΊγ€‚", + "scenes.app.channelsbar.channel_information.group.title": "钑道组", + "components.invitation.custom_role_invitation": "η»ε…Έθ―·ζŸ¬", + "components.invitation.link": "关联" +} diff --git a/twake/frontend/public/manifest.json b/twake/frontend/public/manifest.json new file mode 100644 index 00000000..4b59cdf8 --- /dev/null +++ b/twake/frontend/public/manifest.json @@ -0,0 +1,4 @@ +{ + "name": "Twake", + "short_name": "Twake" +} diff --git a/twake/frontend/public/public/emoji-datasource/apple/sheets-256/16.png b/twake/frontend/public/public/emoji-datasource/apple/sheets-256/16.png new file mode 100644 index 00000000..b7fda5f8 Binary files /dev/null and b/twake/frontend/public/public/emoji-datasource/apple/sheets-256/16.png differ diff --git a/twake/frontend/public/public/emoji-datasource/apple/sheets-256/20.png b/twake/frontend/public/public/emoji-datasource/apple/sheets-256/20.png new file mode 100644 index 00000000..948538dc Binary files /dev/null and b/twake/frontend/public/public/emoji-datasource/apple/sheets-256/20.png differ diff --git a/twake/frontend/public/public/emoji-datasource/apple/sheets-256/32.png b/twake/frontend/public/public/emoji-datasource/apple/sheets-256/32.png new file mode 100644 index 00000000..e5609b33 Binary files /dev/null and b/twake/frontend/public/public/emoji-datasource/apple/sheets-256/32.png differ diff --git a/twake/frontend/public/public/emoji-datasource/apple/sheets-256/64.png b/twake/frontend/public/public/emoji-datasource/apple/sheets-256/64.png new file mode 100644 index 00000000..c0b33abd Binary files /dev/null and b/twake/frontend/public/public/emoji-datasource/apple/sheets-256/64.png differ diff --git a/twake/frontend/public/public/emojione/128/0023-20e3.png b/twake/frontend/public/public/emojione/128/0023-20e3.png new file mode 100644 index 00000000..91eb5870 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0023-20e3.png differ diff --git a/twake/frontend/public/public/emojione/128/0023.png b/twake/frontend/public/public/emojione/128/0023.png new file mode 100644 index 00000000..b88ac0f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0023.png differ diff --git a/twake/frontend/public/public/emojione/128/002a-20e3.png b/twake/frontend/public/public/emojione/128/002a-20e3.png new file mode 100644 index 00000000..4e9b723d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/002a-20e3.png differ diff --git a/twake/frontend/public/public/emojione/128/002a.png b/twake/frontend/public/public/emojione/128/002a.png new file mode 100644 index 00000000..eca170e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/002a.png differ diff --git a/twake/frontend/public/public/emojione/128/0030-20e3.png b/twake/frontend/public/public/emojione/128/0030-20e3.png new file mode 100644 index 00000000..0b617c65 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0030-20e3.png differ diff --git a/twake/frontend/public/public/emojione/128/0030.png b/twake/frontend/public/public/emojione/128/0030.png new file mode 100644 index 00000000..0f628006 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0030.png differ diff --git a/twake/frontend/public/public/emojione/128/0031-20e3.png b/twake/frontend/public/public/emojione/128/0031-20e3.png new file mode 100644 index 00000000..dea699e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0031-20e3.png differ diff --git a/twake/frontend/public/public/emojione/128/0031.png b/twake/frontend/public/public/emojione/128/0031.png new file mode 100644 index 00000000..e950ed92 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0031.png differ diff --git a/twake/frontend/public/public/emojione/128/0032-20e3.png b/twake/frontend/public/public/emojione/128/0032-20e3.png new file mode 100644 index 00000000..36dbd3af Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0032-20e3.png differ diff --git a/twake/frontend/public/public/emojione/128/0032.png b/twake/frontend/public/public/emojione/128/0032.png new file mode 100644 index 00000000..b65f5007 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0032.png differ diff --git a/twake/frontend/public/public/emojione/128/0033-20e3.png b/twake/frontend/public/public/emojione/128/0033-20e3.png new file mode 100644 index 00000000..fc1393e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0033-20e3.png differ diff --git a/twake/frontend/public/public/emojione/128/0033.png b/twake/frontend/public/public/emojione/128/0033.png new file mode 100644 index 00000000..18394f3f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0033.png differ diff --git a/twake/frontend/public/public/emojione/128/0034-20e3.png b/twake/frontend/public/public/emojione/128/0034-20e3.png new file mode 100644 index 00000000..883714e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0034-20e3.png differ diff --git a/twake/frontend/public/public/emojione/128/0034.png b/twake/frontend/public/public/emojione/128/0034.png new file mode 100644 index 00000000..29b7226b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0034.png differ diff --git a/twake/frontend/public/public/emojione/128/0035-20e3.png b/twake/frontend/public/public/emojione/128/0035-20e3.png new file mode 100644 index 00000000..44df9adf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0035-20e3.png differ diff --git a/twake/frontend/public/public/emojione/128/0035.png b/twake/frontend/public/public/emojione/128/0035.png new file mode 100644 index 00000000..3a10644d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0035.png differ diff --git a/twake/frontend/public/public/emojione/128/0036-20e3.png b/twake/frontend/public/public/emojione/128/0036-20e3.png new file mode 100644 index 00000000..9fadcde5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0036-20e3.png differ diff --git a/twake/frontend/public/public/emojione/128/0036.png b/twake/frontend/public/public/emojione/128/0036.png new file mode 100644 index 00000000..f6d3bb69 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0036.png differ diff --git a/twake/frontend/public/public/emojione/128/0037-20e3.png b/twake/frontend/public/public/emojione/128/0037-20e3.png new file mode 100644 index 00000000..66b1cbb4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0037-20e3.png differ diff --git a/twake/frontend/public/public/emojione/128/0037.png b/twake/frontend/public/public/emojione/128/0037.png new file mode 100644 index 00000000..ad43ae41 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0037.png differ diff --git a/twake/frontend/public/public/emojione/128/0038-20e3.png b/twake/frontend/public/public/emojione/128/0038-20e3.png new file mode 100644 index 00000000..8d36a904 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0038-20e3.png differ diff --git a/twake/frontend/public/public/emojione/128/0038.png b/twake/frontend/public/public/emojione/128/0038.png new file mode 100644 index 00000000..32050082 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0038.png differ diff --git a/twake/frontend/public/public/emojione/128/0039-20e3.png b/twake/frontend/public/public/emojione/128/0039-20e3.png new file mode 100644 index 00000000..dea1ee1f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0039-20e3.png differ diff --git a/twake/frontend/public/public/emojione/128/0039.png b/twake/frontend/public/public/emojione/128/0039.png new file mode 100644 index 00000000..84cc5011 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/0039.png differ diff --git a/twake/frontend/public/public/emojione/128/00a9.png b/twake/frontend/public/public/emojione/128/00a9.png new file mode 100644 index 00000000..e17ca92d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/00a9.png differ diff --git a/twake/frontend/public/public/emojione/128/00ae.png b/twake/frontend/public/public/emojione/128/00ae.png new file mode 100644 index 00000000..c04eac1d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/00ae.png differ diff --git a/twake/frontend/public/public/emojione/128/1f004.png b/twake/frontend/public/public/emojione/128/1f004.png new file mode 100644 index 00000000..04f28be1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f004.png differ diff --git a/twake/frontend/public/public/emojione/128/1f0cf.png b/twake/frontend/public/public/emojione/128/1f0cf.png new file mode 100644 index 00000000..f8dc1f89 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f0cf.png differ diff --git a/twake/frontend/public/public/emojione/128/1f170.png b/twake/frontend/public/public/emojione/128/1f170.png new file mode 100644 index 00000000..9a3acb0d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f170.png differ diff --git a/twake/frontend/public/public/emojione/128/1f171.png b/twake/frontend/public/public/emojione/128/1f171.png new file mode 100644 index 00000000..f92c577e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f171.png differ diff --git a/twake/frontend/public/public/emojione/128/1f17e.png b/twake/frontend/public/public/emojione/128/1f17e.png new file mode 100644 index 00000000..7e88f608 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f17e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f17f.png b/twake/frontend/public/public/emojione/128/1f17f.png new file mode 100644 index 00000000..395b4eac Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f17f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f18e.png b/twake/frontend/public/public/emojione/128/1f18e.png new file mode 100644 index 00000000..f33d4134 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f18e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f191.png b/twake/frontend/public/public/emojione/128/1f191.png new file mode 100644 index 00000000..dfdc7eca Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f191.png differ diff --git a/twake/frontend/public/public/emojione/128/1f192.png b/twake/frontend/public/public/emojione/128/1f192.png new file mode 100644 index 00000000..0d9c9891 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f192.png differ diff --git a/twake/frontend/public/public/emojione/128/1f193.png b/twake/frontend/public/public/emojione/128/1f193.png new file mode 100644 index 00000000..6f00150b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f193.png differ diff --git a/twake/frontend/public/public/emojione/128/1f194.png b/twake/frontend/public/public/emojione/128/1f194.png new file mode 100644 index 00000000..539a4389 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f194.png differ diff --git a/twake/frontend/public/public/emojione/128/1f195.png b/twake/frontend/public/public/emojione/128/1f195.png new file mode 100644 index 00000000..fa09bf9c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f195.png differ diff --git a/twake/frontend/public/public/emojione/128/1f196.png b/twake/frontend/public/public/emojione/128/1f196.png new file mode 100644 index 00000000..c1fb8254 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f196.png differ diff --git a/twake/frontend/public/public/emojione/128/1f197.png b/twake/frontend/public/public/emojione/128/1f197.png new file mode 100644 index 00000000..3a625dd9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f197.png differ diff --git a/twake/frontend/public/public/emojione/128/1f198.png b/twake/frontend/public/public/emojione/128/1f198.png new file mode 100644 index 00000000..8eedd60f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f198.png differ diff --git a/twake/frontend/public/public/emojione/128/1f199.png b/twake/frontend/public/public/emojione/128/1f199.png new file mode 100644 index 00000000..bdad0e39 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f199.png differ diff --git a/twake/frontend/public/public/emojione/128/1f19a.png b/twake/frontend/public/public/emojione/128/1f19a.png new file mode 100644 index 00000000..78a496ee Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f19a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6-1f1e8.png b/twake/frontend/public/public/emojione/128/1f1e6-1f1e8.png new file mode 100644 index 00000000..7c2ccd51 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6-1f1e9.png b/twake/frontend/public/public/emojione/128/1f1e6-1f1e9.png new file mode 100644 index 00000000..7cf8fe8c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6-1f1ea.png b/twake/frontend/public/public/emojione/128/1f1e6-1f1ea.png new file mode 100644 index 00000000..bb094eeb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6-1f1eb.png b/twake/frontend/public/public/emojione/128/1f1e6-1f1eb.png new file mode 100644 index 00000000..e9ceba1e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6-1f1ec.png b/twake/frontend/public/public/emojione/128/1f1e6-1f1ec.png new file mode 100644 index 00000000..348a3cd5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6-1f1ee.png b/twake/frontend/public/public/emojione/128/1f1e6-1f1ee.png new file mode 100644 index 00000000..f8cd3033 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6-1f1f1.png b/twake/frontend/public/public/emojione/128/1f1e6-1f1f1.png new file mode 100644 index 00000000..f086f083 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6-1f1f2.png b/twake/frontend/public/public/emojione/128/1f1e6-1f1f2.png new file mode 100644 index 00000000..50d4f555 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6-1f1f4.png b/twake/frontend/public/public/emojione/128/1f1e6-1f1f4.png new file mode 100644 index 00000000..af2b4a26 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6-1f1f6.png b/twake/frontend/public/public/emojione/128/1f1e6-1f1f6.png new file mode 100644 index 00000000..3f24e322 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6-1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6-1f1f7.png b/twake/frontend/public/public/emojione/128/1f1e6-1f1f7.png new file mode 100644 index 00000000..074aaf5b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6-1f1f8.png b/twake/frontend/public/public/emojione/128/1f1e6-1f1f8.png new file mode 100644 index 00000000..52d8c26b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6-1f1f9.png b/twake/frontend/public/public/emojione/128/1f1e6-1f1f9.png new file mode 100644 index 00000000..08c40d0b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6-1f1fa.png b/twake/frontend/public/public/emojione/128/1f1e6-1f1fa.png new file mode 100644 index 00000000..656130a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6-1f1fc.png b/twake/frontend/public/public/emojione/128/1f1e6-1f1fc.png new file mode 100644 index 00000000..b3c33294 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6-1f1fd.png b/twake/frontend/public/public/emojione/128/1f1e6-1f1fd.png new file mode 100644 index 00000000..576c1267 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6-1f1fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6-1f1ff.png b/twake/frontend/public/public/emojione/128/1f1e6-1f1ff.png new file mode 100644 index 00000000..01dcf07c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e6.png b/twake/frontend/public/public/emojione/128/1f1e6.png new file mode 100644 index 00000000..f7981b0b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1e6.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1e6.png new file mode 100644 index 00000000..2722f61f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1e7.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1e7.png new file mode 100644 index 00000000..5fcac6c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1e7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1e9.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1e9.png new file mode 100644 index 00000000..693a58e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1ea.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1ea.png new file mode 100644 index 00000000..75439ad3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1eb.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1eb.png new file mode 100644 index 00000000..6b4c7bad Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1ec.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1ec.png new file mode 100644 index 00000000..81cbb9dc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1ed.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1ed.png new file mode 100644 index 00000000..e6ee8f61 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1ee.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1ee.png new file mode 100644 index 00000000..6f2aaeb6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1ef.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1ef.png new file mode 100644 index 00000000..4b54b6c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1f1.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1f1.png new file mode 100644 index 00000000..18880134 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1f2.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1f2.png new file mode 100644 index 00000000..6f9e8279 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1f3.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1f3.png new file mode 100644 index 00000000..44da3b75 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1f4.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1f4.png new file mode 100644 index 00000000..87afa11d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1f6.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1f6.png new file mode 100644 index 00000000..6239b5ef Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1f7.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1f7.png new file mode 100644 index 00000000..53825504 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1f8.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1f8.png new file mode 100644 index 00000000..91550ac5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1f9.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1f9.png new file mode 100644 index 00000000..6d2f1966 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1fb.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1fb.png new file mode 100644 index 00000000..4a79e185 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1fc.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1fc.png new file mode 100644 index 00000000..d1a1af8d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1fe.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1fe.png new file mode 100644 index 00000000..e6f25a85 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7-1f1ff.png b/twake/frontend/public/public/emojione/128/1f1e7-1f1ff.png new file mode 100644 index 00000000..fddf0961 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e7.png b/twake/frontend/public/public/emojione/128/1f1e7.png new file mode 100644 index 00000000..dad48796 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1e6.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1e6.png new file mode 100644 index 00000000..41579c35 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1e8.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1e8.png new file mode 100644 index 00000000..c1f6276e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1e9.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1e9.png new file mode 100644 index 00000000..84c75bab Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1eb.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1eb.png new file mode 100644 index 00000000..5e906ea6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1ec.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1ec.png new file mode 100644 index 00000000..90615008 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1ed.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1ed.png new file mode 100644 index 00000000..48c4ee96 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1ee.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1ee.png new file mode 100644 index 00000000..8ce0bf09 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1f0.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1f0.png new file mode 100644 index 00000000..5e12c930 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1f1.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1f1.png new file mode 100644 index 00000000..4f02ba56 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1f2.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1f2.png new file mode 100644 index 00000000..d5481b3e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1f3.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1f3.png new file mode 100644 index 00000000..5173c8dd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1f4.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1f4.png new file mode 100644 index 00000000..7aeb47c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1f5.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1f5.png new file mode 100644 index 00000000..57178d2a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1f7.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1f7.png new file mode 100644 index 00000000..15443668 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1fa.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1fa.png new file mode 100644 index 00000000..a6951745 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1fb.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1fb.png new file mode 100644 index 00000000..eb7d51c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1fc.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1fc.png new file mode 100644 index 00000000..6251f4c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1fd.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1fd.png new file mode 100644 index 00000000..fc601502 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1fe.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1fe.png new file mode 100644 index 00000000..41d8e930 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8-1f1ff.png b/twake/frontend/public/public/emojione/128/1f1e8-1f1ff.png new file mode 100644 index 00000000..d527ab9c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e8.png b/twake/frontend/public/public/emojione/128/1f1e8.png new file mode 100644 index 00000000..1744dcd0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e9-1f1ea.png b/twake/frontend/public/public/emojione/128/1f1e9-1f1ea.png new file mode 100644 index 00000000..b51784c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e9-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e9-1f1ec.png b/twake/frontend/public/public/emojione/128/1f1e9-1f1ec.png new file mode 100644 index 00000000..d0312246 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e9-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e9-1f1ef.png b/twake/frontend/public/public/emojione/128/1f1e9-1f1ef.png new file mode 100644 index 00000000..caeef2ce Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e9-1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e9-1f1f0.png b/twake/frontend/public/public/emojione/128/1f1e9-1f1f0.png new file mode 100644 index 00000000..c1ae7f49 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e9-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e9-1f1f2.png b/twake/frontend/public/public/emojione/128/1f1e9-1f1f2.png new file mode 100644 index 00000000..ccc691aa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e9-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e9-1f1f4.png b/twake/frontend/public/public/emojione/128/1f1e9-1f1f4.png new file mode 100644 index 00000000..a9e69649 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e9-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e9-1f1ff.png b/twake/frontend/public/public/emojione/128/1f1e9-1f1ff.png new file mode 100644 index 00000000..ccf6c78d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e9-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1e9.png b/twake/frontend/public/public/emojione/128/1f1e9.png new file mode 100644 index 00000000..f9806aee Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ea-1f1e6.png b/twake/frontend/public/public/emojione/128/1f1ea-1f1e6.png new file mode 100644 index 00000000..938e2fa7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ea-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ea-1f1e8.png b/twake/frontend/public/public/emojione/128/1f1ea-1f1e8.png new file mode 100644 index 00000000..38b73ed0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ea-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ea-1f1ea.png b/twake/frontend/public/public/emojione/128/1f1ea-1f1ea.png new file mode 100644 index 00000000..50eb1460 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ea-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ea-1f1ec.png b/twake/frontend/public/public/emojione/128/1f1ea-1f1ec.png new file mode 100644 index 00000000..2200e278 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ea-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ea-1f1ed.png b/twake/frontend/public/public/emojione/128/1f1ea-1f1ed.png new file mode 100644 index 00000000..5e8a815e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ea-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ea-1f1f7.png b/twake/frontend/public/public/emojione/128/1f1ea-1f1f7.png new file mode 100644 index 00000000..91a37e13 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ea-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ea-1f1f8.png b/twake/frontend/public/public/emojione/128/1f1ea-1f1f8.png new file mode 100644 index 00000000..938e2fa7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ea-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ea-1f1f9.png b/twake/frontend/public/public/emojione/128/1f1ea-1f1f9.png new file mode 100644 index 00000000..f57d150f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ea-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ea-1f1fa.png b/twake/frontend/public/public/emojione/128/1f1ea-1f1fa.png new file mode 100644 index 00000000..22ecb188 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ea-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ea.png b/twake/frontend/public/public/emojione/128/1f1ea.png new file mode 100644 index 00000000..44274f9a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1eb-1f1ee.png b/twake/frontend/public/public/emojione/128/1f1eb-1f1ee.png new file mode 100644 index 00000000..0ee2c246 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1eb-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1eb-1f1ef.png b/twake/frontend/public/public/emojione/128/1f1eb-1f1ef.png new file mode 100644 index 00000000..036f5ca6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1eb-1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1eb-1f1f0.png b/twake/frontend/public/public/emojione/128/1f1eb-1f1f0.png new file mode 100644 index 00000000..3a9f73be Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1eb-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1eb-1f1f2.png b/twake/frontend/public/public/emojione/128/1f1eb-1f1f2.png new file mode 100644 index 00000000..8bcb0240 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1eb-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1eb-1f1f4.png b/twake/frontend/public/public/emojione/128/1f1eb-1f1f4.png new file mode 100644 index 00000000..e9fa04bf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1eb-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1eb-1f1f7.png b/twake/frontend/public/public/emojione/128/1f1eb-1f1f7.png new file mode 100644 index 00000000..57178d2a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1eb-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1eb.png b/twake/frontend/public/public/emojione/128/1f1eb.png new file mode 100644 index 00000000..d8ac1c20 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1e6.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1e6.png new file mode 100644 index 00000000..4f822efa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1e7.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1e7.png new file mode 100644 index 00000000..393633ed Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1e7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1e9.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1e9.png new file mode 100644 index 00000000..11ba2142 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1ea.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1ea.png new file mode 100644 index 00000000..0e77c009 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1eb.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1eb.png new file mode 100644 index 00000000..34b47304 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1ec.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1ec.png new file mode 100644 index 00000000..b4b999ed Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1ed.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1ed.png new file mode 100644 index 00000000..e5c0515a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1ee.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1ee.png new file mode 100644 index 00000000..085412e4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1f1.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1f1.png new file mode 100644 index 00000000..56779fd8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1f2.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1f2.png new file mode 100644 index 00000000..a90c51b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1f3.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1f3.png new file mode 100644 index 00000000..d5ed070a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1f5.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1f5.png new file mode 100644 index 00000000..3e246fc5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1f6.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1f6.png new file mode 100644 index 00000000..f9f71ac1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1f7.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1f7.png new file mode 100644 index 00000000..65e08ae1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1f8.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1f8.png new file mode 100644 index 00000000..f4a7d65b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1f9.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1f9.png new file mode 100644 index 00000000..7b3c0d3c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1fa.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1fa.png new file mode 100644 index 00000000..bcd799b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1fc.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1fc.png new file mode 100644 index 00000000..eda80989 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec-1f1fe.png b/twake/frontend/public/public/emojione/128/1f1ec-1f1fe.png new file mode 100644 index 00000000..bd0cbf89 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ec.png b/twake/frontend/public/public/emojione/128/1f1ec.png new file mode 100644 index 00000000..427d3f8e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ed-1f1f0.png b/twake/frontend/public/public/emojione/128/1f1ed-1f1f0.png new file mode 100644 index 00000000..b3ed998f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ed-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ed-1f1f2.png b/twake/frontend/public/public/emojione/128/1f1ed-1f1f2.png new file mode 100644 index 00000000..a608b178 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ed-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ed-1f1f3.png b/twake/frontend/public/public/emojione/128/1f1ed-1f1f3.png new file mode 100644 index 00000000..1fe3dbfa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ed-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ed-1f1f7.png b/twake/frontend/public/public/emojione/128/1f1ed-1f1f7.png new file mode 100644 index 00000000..2800e1a2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ed-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ed-1f1f9.png b/twake/frontend/public/public/emojione/128/1f1ed-1f1f9.png new file mode 100644 index 00000000..42ce7454 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ed-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ed-1f1fa.png b/twake/frontend/public/public/emojione/128/1f1ed-1f1fa.png new file mode 100644 index 00000000..c23b6f9f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ed-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ed.png b/twake/frontend/public/public/emojione/128/1f1ed.png new file mode 100644 index 00000000..cc7ef864 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ee-1f1e8.png b/twake/frontend/public/public/emojione/128/1f1ee-1f1e8.png new file mode 100644 index 00000000..9075a903 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ee-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ee-1f1e9.png b/twake/frontend/public/public/emojione/128/1f1ee-1f1e9.png new file mode 100644 index 00000000..412560c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ee-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ee-1f1ea.png b/twake/frontend/public/public/emojione/128/1f1ee-1f1ea.png new file mode 100644 index 00000000..90235785 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ee-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ee-1f1f1.png b/twake/frontend/public/public/emojione/128/1f1ee-1f1f1.png new file mode 100644 index 00000000..6ed818e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ee-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ee-1f1f2.png b/twake/frontend/public/public/emojione/128/1f1ee-1f1f2.png new file mode 100644 index 00000000..bf921a0f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ee-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ee-1f1f3.png b/twake/frontend/public/public/emojione/128/1f1ee-1f1f3.png new file mode 100644 index 00000000..6995f3d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ee-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ee-1f1f4.png b/twake/frontend/public/public/emojione/128/1f1ee-1f1f4.png new file mode 100644 index 00000000..d0312246 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ee-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ee-1f1f6.png b/twake/frontend/public/public/emojione/128/1f1ee-1f1f6.png new file mode 100644 index 00000000..4b61c990 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ee-1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ee-1f1f7.png b/twake/frontend/public/public/emojione/128/1f1ee-1f1f7.png new file mode 100644 index 00000000..cab0c5a6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ee-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ee-1f1f8.png b/twake/frontend/public/public/emojione/128/1f1ee-1f1f8.png new file mode 100644 index 00000000..61d49e86 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ee-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ee-1f1f9.png b/twake/frontend/public/public/emojione/128/1f1ee-1f1f9.png new file mode 100644 index 00000000..38303497 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ee-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ee.png b/twake/frontend/public/public/emojione/128/1f1ee.png new file mode 100644 index 00000000..3b949ca6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ef-1f1ea.png b/twake/frontend/public/public/emojione/128/1f1ef-1f1ea.png new file mode 100644 index 00000000..ce71e32a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ef-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ef-1f1f2.png b/twake/frontend/public/public/emojione/128/1f1ef-1f1f2.png new file mode 100644 index 00000000..1afa00ca Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ef-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ef-1f1f4.png b/twake/frontend/public/public/emojione/128/1f1ef-1f1f4.png new file mode 100644 index 00000000..333710f9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ef-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ef-1f1f5.png b/twake/frontend/public/public/emojione/128/1f1ef-1f1f5.png new file mode 100644 index 00000000..454154bc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ef-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ef.png b/twake/frontend/public/public/emojione/128/1f1ef.png new file mode 100644 index 00000000..d312b320 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f0-1f1ea.png b/twake/frontend/public/public/emojione/128/1f1f0-1f1ea.png new file mode 100644 index 00000000..e1d98355 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f0-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f0-1f1ec.png b/twake/frontend/public/public/emojione/128/1f1f0-1f1ec.png new file mode 100644 index 00000000..73c382a5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f0-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f0-1f1ed.png b/twake/frontend/public/public/emojione/128/1f1f0-1f1ed.png new file mode 100644 index 00000000..d1d88450 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f0-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f0-1f1ee.png b/twake/frontend/public/public/emojione/128/1f1f0-1f1ee.png new file mode 100644 index 00000000..44d8b053 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f0-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f0-1f1f2.png b/twake/frontend/public/public/emojione/128/1f1f0-1f1f2.png new file mode 100644 index 00000000..d803c7d3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f0-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f0-1f1f3.png b/twake/frontend/public/public/emojione/128/1f1f0-1f1f3.png new file mode 100644 index 00000000..2a355f54 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f0-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f0-1f1f5.png b/twake/frontend/public/public/emojione/128/1f1f0-1f1f5.png new file mode 100644 index 00000000..0c2e5c24 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f0-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f0-1f1f7.png b/twake/frontend/public/public/emojione/128/1f1f0-1f1f7.png new file mode 100644 index 00000000..893136ec Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f0-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f0-1f1fc.png b/twake/frontend/public/public/emojione/128/1f1f0-1f1fc.png new file mode 100644 index 00000000..64c8241d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f0-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f0-1f1fe.png b/twake/frontend/public/public/emojione/128/1f1f0-1f1fe.png new file mode 100644 index 00000000..ed113f60 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f0-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f0-1f1ff.png b/twake/frontend/public/public/emojione/128/1f1f0-1f1ff.png new file mode 100644 index 00000000..30ca58d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f0-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f0.png b/twake/frontend/public/public/emojione/128/1f1f0.png new file mode 100644 index 00000000..a535b39f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f1-1f1e6.png b/twake/frontend/public/public/emojione/128/1f1f1-1f1e6.png new file mode 100644 index 00000000..35d6d261 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f1-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f1-1f1e7.png b/twake/frontend/public/public/emojione/128/1f1f1-1f1e7.png new file mode 100644 index 00000000..cc230ec1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f1-1f1e7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f1-1f1e8.png b/twake/frontend/public/public/emojione/128/1f1f1-1f1e8.png new file mode 100644 index 00000000..014795ed Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f1-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f1-1f1ee.png b/twake/frontend/public/public/emojione/128/1f1f1-1f1ee.png new file mode 100644 index 00000000..32db14a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f1-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f1-1f1f0.png b/twake/frontend/public/public/emojione/128/1f1f1-1f1f0.png new file mode 100644 index 00000000..50c7f2c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f1-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f1-1f1f7.png b/twake/frontend/public/public/emojione/128/1f1f1-1f1f7.png new file mode 100644 index 00000000..6815d0c5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f1-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f1-1f1f8.png b/twake/frontend/public/public/emojione/128/1f1f1-1f1f8.png new file mode 100644 index 00000000..ef2dfa0c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f1-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f1-1f1f9.png b/twake/frontend/public/public/emojione/128/1f1f1-1f1f9.png new file mode 100644 index 00000000..01d04a58 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f1-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f1-1f1fa.png b/twake/frontend/public/public/emojione/128/1f1f1-1f1fa.png new file mode 100644 index 00000000..5e58d936 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f1-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f1-1f1fb.png b/twake/frontend/public/public/emojione/128/1f1f1-1f1fb.png new file mode 100644 index 00000000..d519fd23 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f1-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f1-1f1fe.png b/twake/frontend/public/public/emojione/128/1f1f1-1f1fe.png new file mode 100644 index 00000000..2765de2f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f1-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f1.png b/twake/frontend/public/public/emojione/128/1f1f1.png new file mode 100644 index 00000000..83c7d81a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1e6.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1e6.png new file mode 100644 index 00000000..650dfde4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1e8.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1e8.png new file mode 100644 index 00000000..412560c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1e9.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1e9.png new file mode 100644 index 00000000..09ac142b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1ea.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1ea.png new file mode 100644 index 00000000..6bfc9b81 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1eb.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1eb.png new file mode 100644 index 00000000..57178d2a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1ec.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1ec.png new file mode 100644 index 00000000..ea29d6ee Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1ed.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1ed.png new file mode 100644 index 00000000..dba15199 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1f0.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1f0.png new file mode 100644 index 00000000..a57944c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1f1.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1f1.png new file mode 100644 index 00000000..b76e4dc1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1f2.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1f2.png new file mode 100644 index 00000000..d025d8a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1f3.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1f3.png new file mode 100644 index 00000000..f53165c4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1f4.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1f4.png new file mode 100644 index 00000000..778f2d3d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1f5.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1f5.png new file mode 100644 index 00000000..e4e14b13 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1f6.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1f6.png new file mode 100644 index 00000000..b64de181 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1f7.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1f7.png new file mode 100644 index 00000000..affed96e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1f8.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1f8.png new file mode 100644 index 00000000..a13d7334 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1f9.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1f9.png new file mode 100644 index 00000000..edf078b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1fa.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1fa.png new file mode 100644 index 00000000..056b32ec Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1fb.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1fb.png new file mode 100644 index 00000000..75bd094e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1fc.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1fc.png new file mode 100644 index 00000000..c40b3f24 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1fd.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1fd.png new file mode 100644 index 00000000..7cd01bae Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1fe.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1fe.png new file mode 100644 index 00000000..37a52662 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2-1f1ff.png b/twake/frontend/public/public/emojione/128/1f1f2-1f1ff.png new file mode 100644 index 00000000..626acc35 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f2.png b/twake/frontend/public/public/emojione/128/1f1f2.png new file mode 100644 index 00000000..2cad586e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f3-1f1e6.png b/twake/frontend/public/public/emojione/128/1f1f3-1f1e6.png new file mode 100644 index 00000000..2d7f7b45 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f3-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f3-1f1e8.png b/twake/frontend/public/public/emojione/128/1f1f3-1f1e8.png new file mode 100644 index 00000000..20d99c9e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f3-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f3-1f1ea.png b/twake/frontend/public/public/emojione/128/1f1f3-1f1ea.png new file mode 100644 index 00000000..3c359a60 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f3-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f3-1f1eb.png b/twake/frontend/public/public/emojione/128/1f1f3-1f1eb.png new file mode 100644 index 00000000..709a86cc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f3-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f3-1f1ec.png b/twake/frontend/public/public/emojione/128/1f1f3-1f1ec.png new file mode 100644 index 00000000..93125b43 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f3-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f3-1f1ee.png b/twake/frontend/public/public/emojione/128/1f1f3-1f1ee.png new file mode 100644 index 00000000..13ee5166 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f3-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f3-1f1f1.png b/twake/frontend/public/public/emojione/128/1f1f3-1f1f1.png new file mode 100644 index 00000000..e5b632e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f3-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f3-1f1f4.png b/twake/frontend/public/public/emojione/128/1f1f3-1f1f4.png new file mode 100644 index 00000000..4a79e185 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f3-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f3-1f1f5.png b/twake/frontend/public/public/emojione/128/1f1f3-1f1f5.png new file mode 100644 index 00000000..cddf7062 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f3-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f3-1f1f7.png b/twake/frontend/public/public/emojione/128/1f1f3-1f1f7.png new file mode 100644 index 00000000..eabf449e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f3-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f3-1f1fa.png b/twake/frontend/public/public/emojione/128/1f1f3-1f1fa.png new file mode 100644 index 00000000..418271f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f3-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f3-1f1ff.png b/twake/frontend/public/public/emojione/128/1f1f3-1f1ff.png new file mode 100644 index 00000000..bf3b9551 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f3-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f3.png b/twake/frontend/public/public/emojione/128/1f1f3.png new file mode 100644 index 00000000..7844020c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f4-1f1f2.png b/twake/frontend/public/public/emojione/128/1f1f4-1f1f2.png new file mode 100644 index 00000000..c09dce97 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f4-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f4.png b/twake/frontend/public/public/emojione/128/1f1f4.png new file mode 100644 index 00000000..0b04b25e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f5-1f1e6.png b/twake/frontend/public/public/emojione/128/1f1f5-1f1e6.png new file mode 100644 index 00000000..452d8211 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f5-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f5-1f1ea.png b/twake/frontend/public/public/emojione/128/1f1f5-1f1ea.png new file mode 100644 index 00000000..ef5a89ff Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f5-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f5-1f1eb.png b/twake/frontend/public/public/emojione/128/1f1f5-1f1eb.png new file mode 100644 index 00000000..17fd95de Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f5-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f5-1f1ec.png b/twake/frontend/public/public/emojione/128/1f1f5-1f1ec.png new file mode 100644 index 00000000..8b6d760e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f5-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f5-1f1ed.png b/twake/frontend/public/public/emojione/128/1f1f5-1f1ed.png new file mode 100644 index 00000000..b1c314a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f5-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f5-1f1f0.png b/twake/frontend/public/public/emojione/128/1f1f5-1f1f0.png new file mode 100644 index 00000000..d1a97efd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f5-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f5-1f1f1.png b/twake/frontend/public/public/emojione/128/1f1f5-1f1f1.png new file mode 100644 index 00000000..858bdba9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f5-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f5-1f1f2.png b/twake/frontend/public/public/emojione/128/1f1f5-1f1f2.png new file mode 100644 index 00000000..89284bbf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f5-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f5-1f1f3.png b/twake/frontend/public/public/emojione/128/1f1f5-1f1f3.png new file mode 100644 index 00000000..e9c3e89c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f5-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f5-1f1f7.png b/twake/frontend/public/public/emojione/128/1f1f5-1f1f7.png new file mode 100644 index 00000000..841dd18d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f5-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f5-1f1f8.png b/twake/frontend/public/public/emojione/128/1f1f5-1f1f8.png new file mode 100644 index 00000000..9e70baa2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f5-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f5-1f1f9.png b/twake/frontend/public/public/emojione/128/1f1f5-1f1f9.png new file mode 100644 index 00000000..9497a0cf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f5-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f5-1f1fc.png b/twake/frontend/public/public/emojione/128/1f1f5-1f1fc.png new file mode 100644 index 00000000..6b746c7c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f5-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f5-1f1fe.png b/twake/frontend/public/public/emojione/128/1f1f5-1f1fe.png new file mode 100644 index 00000000..3493e537 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f5-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f5.png b/twake/frontend/public/public/emojione/128/1f1f5.png new file mode 100644 index 00000000..135d1cb2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f6-1f1e6.png b/twake/frontend/public/public/emojione/128/1f1f6-1f1e6.png new file mode 100644 index 00000000..499a2d60 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f6-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f6.png b/twake/frontend/public/public/emojione/128/1f1f6.png new file mode 100644 index 00000000..98422579 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f7-1f1ea.png b/twake/frontend/public/public/emojione/128/1f1f7-1f1ea.png new file mode 100644 index 00000000..0357b00d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f7-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f7-1f1f4.png b/twake/frontend/public/public/emojione/128/1f1f7-1f1f4.png new file mode 100644 index 00000000..12e6b8de Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f7-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f7-1f1f8.png b/twake/frontend/public/public/emojione/128/1f1f7-1f1f8.png new file mode 100644 index 00000000..23314b3b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f7-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f7-1f1fa.png b/twake/frontend/public/public/emojione/128/1f1f7-1f1fa.png new file mode 100644 index 00000000..1b75bad1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f7-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f7-1f1fc.png b/twake/frontend/public/public/emojione/128/1f1f7-1f1fc.png new file mode 100644 index 00000000..c7730b5c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f7-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f7.png b/twake/frontend/public/public/emojione/128/1f1f7.png new file mode 100644 index 00000000..10506007 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1e6.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1e6.png new file mode 100644 index 00000000..387b35a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1e7.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1e7.png new file mode 100644 index 00000000..010e72fe Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1e7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1e8.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1e8.png new file mode 100644 index 00000000..e9ba2e2e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1e9.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1e9.png new file mode 100644 index 00000000..1a1727ab Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1ea.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1ea.png new file mode 100644 index 00000000..64a62e99 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1ec.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1ec.png new file mode 100644 index 00000000..65d2e49f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1ed.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1ed.png new file mode 100644 index 00000000..48a45865 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1ee.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1ee.png new file mode 100644 index 00000000..4fcd0816 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1ef.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1ef.png new file mode 100644 index 00000000..4a79e185 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1f0.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1f0.png new file mode 100644 index 00000000..223ef9e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1f1.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1f1.png new file mode 100644 index 00000000..6cb0a2d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1f2.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1f2.png new file mode 100644 index 00000000..42f71919 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1f3.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1f3.png new file mode 100644 index 00000000..8b6bd5da Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1f4.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1f4.png new file mode 100644 index 00000000..d2c99fa8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1f7.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1f7.png new file mode 100644 index 00000000..f15efb2b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1f8.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1f8.png new file mode 100644 index 00000000..c0f417df Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1f9.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1f9.png new file mode 100644 index 00000000..ef35be3d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1fb.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1fb.png new file mode 100644 index 00000000..bddb66c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1fd.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1fd.png new file mode 100644 index 00000000..7e90ecd8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1fe.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1fe.png new file mode 100644 index 00000000..6c14119e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8-1f1ff.png b/twake/frontend/public/public/emojione/128/1f1f8-1f1ff.png new file mode 100644 index 00000000..8b33e354 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f8.png b/twake/frontend/public/public/emojione/128/1f1f8.png new file mode 100644 index 00000000..03130ee2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9-1f1e6.png b/twake/frontend/public/public/emojione/128/1f1f9-1f1e6.png new file mode 100644 index 00000000..48945bca Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9-1f1e8.png b/twake/frontend/public/public/emojione/128/1f1f9-1f1e8.png new file mode 100644 index 00000000..d7b88dbf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9-1f1e9.png b/twake/frontend/public/public/emojione/128/1f1f9-1f1e9.png new file mode 100644 index 00000000..12e6b8de Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9-1f1eb.png b/twake/frontend/public/public/emojione/128/1f1f9-1f1eb.png new file mode 100644 index 00000000..3775e77d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9-1f1ec.png b/twake/frontend/public/public/emojione/128/1f1f9-1f1ec.png new file mode 100644 index 00000000..13ab443b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9-1f1ed.png b/twake/frontend/public/public/emojione/128/1f1f9-1f1ed.png new file mode 100644 index 00000000..15e392d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9-1f1ef.png b/twake/frontend/public/public/emojione/128/1f1f9-1f1ef.png new file mode 100644 index 00000000..8d37efd2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9-1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9-1f1f0.png b/twake/frontend/public/public/emojione/128/1f1f9-1f1f0.png new file mode 100644 index 00000000..f31dd028 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9-1f1f1.png b/twake/frontend/public/public/emojione/128/1f1f9-1f1f1.png new file mode 100644 index 00000000..00fa9af1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9-1f1f2.png b/twake/frontend/public/public/emojione/128/1f1f9-1f1f2.png new file mode 100644 index 00000000..402171a5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9-1f1f3.png b/twake/frontend/public/public/emojione/128/1f1f9-1f1f3.png new file mode 100644 index 00000000..b538e89b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9-1f1f4.png b/twake/frontend/public/public/emojione/128/1f1f9-1f1f4.png new file mode 100644 index 00000000..8a03ba27 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9-1f1f7.png b/twake/frontend/public/public/emojione/128/1f1f9-1f1f7.png new file mode 100644 index 00000000..2f6c0d5e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9-1f1f9.png b/twake/frontend/public/public/emojione/128/1f1f9-1f1f9.png new file mode 100644 index 00000000..9eb510e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9-1f1fb.png b/twake/frontend/public/public/emojione/128/1f1f9-1f1fb.png new file mode 100644 index 00000000..d7950949 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9-1f1fc.png b/twake/frontend/public/public/emojione/128/1f1f9-1f1fc.png new file mode 100644 index 00000000..07fc77b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9-1f1ff.png b/twake/frontend/public/public/emojione/128/1f1f9-1f1ff.png new file mode 100644 index 00000000..f40774be Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1f9.png b/twake/frontend/public/public/emojione/128/1f1f9.png new file mode 100644 index 00000000..ed1ed1fb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fa-1f1e6.png b/twake/frontend/public/public/emojione/128/1f1fa-1f1e6.png new file mode 100644 index 00000000..aa0aec6a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fa-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fa-1f1ec.png b/twake/frontend/public/public/emojione/128/1f1fa-1f1ec.png new file mode 100644 index 00000000..e6e0ab29 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fa-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fa-1f1f2.png b/twake/frontend/public/public/emojione/128/1f1fa-1f1f2.png new file mode 100644 index 00000000..5e180003 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fa-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fa-1f1f3.png b/twake/frontend/public/public/emojione/128/1f1fa-1f1f3.png new file mode 100644 index 00000000..b7f2739d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fa-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fa-1f1f8.png b/twake/frontend/public/public/emojione/128/1f1fa-1f1f8.png new file mode 100644 index 00000000..5e180003 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fa-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fa-1f1fe.png b/twake/frontend/public/public/emojione/128/1f1fa-1f1fe.png new file mode 100644 index 00000000..01c46455 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fa-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fa-1f1ff.png b/twake/frontend/public/public/emojione/128/1f1fa-1f1ff.png new file mode 100644 index 00000000..5700e261 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fa-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fa.png b/twake/frontend/public/public/emojione/128/1f1fa.png new file mode 100644 index 00000000..f7e2385d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fb-1f1e6.png b/twake/frontend/public/public/emojione/128/1f1fb-1f1e6.png new file mode 100644 index 00000000..33921c31 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fb-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fb-1f1e8.png b/twake/frontend/public/public/emojione/128/1f1fb-1f1e8.png new file mode 100644 index 00000000..8354793e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fb-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fb-1f1ea.png b/twake/frontend/public/public/emojione/128/1f1fb-1f1ea.png new file mode 100644 index 00000000..e93a76b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fb-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fb-1f1ec.png b/twake/frontend/public/public/emojione/128/1f1fb-1f1ec.png new file mode 100644 index 00000000..35a4002e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fb-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fb-1f1ee.png b/twake/frontend/public/public/emojione/128/1f1fb-1f1ee.png new file mode 100644 index 00000000..f8aac0ac Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fb-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fb-1f1f3.png b/twake/frontend/public/public/emojione/128/1f1fb-1f1f3.png new file mode 100644 index 00000000..70952a6b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fb-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fb-1f1fa.png b/twake/frontend/public/public/emojione/128/1f1fb-1f1fa.png new file mode 100644 index 00000000..1154f259 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fb-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fb.png b/twake/frontend/public/public/emojione/128/1f1fb.png new file mode 100644 index 00000000..e5c1ec46 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fc-1f1eb.png b/twake/frontend/public/public/emojione/128/1f1fc-1f1eb.png new file mode 100644 index 00000000..46aa317e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fc-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fc-1f1f8.png b/twake/frontend/public/public/emojione/128/1f1fc-1f1f8.png new file mode 100644 index 00000000..480276ec Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fc-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fc.png b/twake/frontend/public/public/emojione/128/1f1fc.png new file mode 100644 index 00000000..889f4094 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fd-1f1f0.png b/twake/frontend/public/public/emojione/128/1f1fd-1f1f0.png new file mode 100644 index 00000000..8088ea45 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fd-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fd.png b/twake/frontend/public/public/emojione/128/1f1fd.png new file mode 100644 index 00000000..0c30184d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fe-1f1ea.png b/twake/frontend/public/public/emojione/128/1f1fe-1f1ea.png new file mode 100644 index 00000000..6a08d069 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fe-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fe-1f1f9.png b/twake/frontend/public/public/emojione/128/1f1fe-1f1f9.png new file mode 100644 index 00000000..880a2f95 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fe-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1fe.png b/twake/frontend/public/public/emojione/128/1f1fe.png new file mode 100644 index 00000000..158649a4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ff-1f1e6.png b/twake/frontend/public/public/emojione/128/1f1ff-1f1e6.png new file mode 100644 index 00000000..0f8bf09d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ff-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ff-1f1f2.png b/twake/frontend/public/public/emojione/128/1f1ff-1f1f2.png new file mode 100644 index 00000000..73aa11fb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ff-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ff-1f1fc.png b/twake/frontend/public/public/emojione/128/1f1ff-1f1fc.png new file mode 100644 index 00000000..75f99030 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ff-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f1ff.png b/twake/frontend/public/public/emojione/128/1f1ff.png new file mode 100644 index 00000000..49831a6f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f201.png b/twake/frontend/public/public/emojione/128/1f201.png new file mode 100644 index 00000000..55775314 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f201.png differ diff --git a/twake/frontend/public/public/emojione/128/1f202.png b/twake/frontend/public/public/emojione/128/1f202.png new file mode 100644 index 00000000..8c6e13a8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f202.png differ diff --git a/twake/frontend/public/public/emojione/128/1f21a.png b/twake/frontend/public/public/emojione/128/1f21a.png new file mode 100644 index 00000000..01a58f2e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f21a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f22f.png b/twake/frontend/public/public/emojione/128/1f22f.png new file mode 100644 index 00000000..aa6a8814 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f22f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f232.png b/twake/frontend/public/public/emojione/128/1f232.png new file mode 100644 index 00000000..b580a2b6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f232.png differ diff --git a/twake/frontend/public/public/emojione/128/1f233.png b/twake/frontend/public/public/emojione/128/1f233.png new file mode 100644 index 00000000..c6fd9d16 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f233.png differ diff --git a/twake/frontend/public/public/emojione/128/1f234.png b/twake/frontend/public/public/emojione/128/1f234.png new file mode 100644 index 00000000..0d8ef9ad Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f234.png differ diff --git a/twake/frontend/public/public/emojione/128/1f235.png b/twake/frontend/public/public/emojione/128/1f235.png new file mode 100644 index 00000000..7d43af21 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f235.png differ diff --git a/twake/frontend/public/public/emojione/128/1f236.png b/twake/frontend/public/public/emojione/128/1f236.png new file mode 100644 index 00000000..bd0d8f34 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f236.png differ diff --git a/twake/frontend/public/public/emojione/128/1f237.png b/twake/frontend/public/public/emojione/128/1f237.png new file mode 100644 index 00000000..94f77a8b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f237.png differ diff --git a/twake/frontend/public/public/emojione/128/1f238.png b/twake/frontend/public/public/emojione/128/1f238.png new file mode 100644 index 00000000..306c2547 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f238.png differ diff --git a/twake/frontend/public/public/emojione/128/1f239.png b/twake/frontend/public/public/emojione/128/1f239.png new file mode 100644 index 00000000..b35b9ba1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f239.png differ diff --git a/twake/frontend/public/public/emojione/128/1f23a.png b/twake/frontend/public/public/emojione/128/1f23a.png new file mode 100644 index 00000000..22ae4a4b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f23a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f250.png b/twake/frontend/public/public/emojione/128/1f250.png new file mode 100644 index 00000000..843be39a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f250.png differ diff --git a/twake/frontend/public/public/emojione/128/1f251.png b/twake/frontend/public/public/emojione/128/1f251.png new file mode 100644 index 00000000..41725384 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f251.png differ diff --git a/twake/frontend/public/public/emojione/128/1f300.png b/twake/frontend/public/public/emojione/128/1f300.png new file mode 100644 index 00000000..536ed5a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f300.png differ diff --git a/twake/frontend/public/public/emojione/128/1f301.png b/twake/frontend/public/public/emojione/128/1f301.png new file mode 100644 index 00000000..eabb04dd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f301.png differ diff --git a/twake/frontend/public/public/emojione/128/1f302.png b/twake/frontend/public/public/emojione/128/1f302.png new file mode 100644 index 00000000..9e2e44d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f302.png differ diff --git a/twake/frontend/public/public/emojione/128/1f303.png b/twake/frontend/public/public/emojione/128/1f303.png new file mode 100644 index 00000000..79c959fd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f303.png differ diff --git a/twake/frontend/public/public/emojione/128/1f304.png b/twake/frontend/public/public/emojione/128/1f304.png new file mode 100644 index 00000000..fa48dd70 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f304.png differ diff --git a/twake/frontend/public/public/emojione/128/1f305.png b/twake/frontend/public/public/emojione/128/1f305.png new file mode 100644 index 00000000..915a0003 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f305.png differ diff --git a/twake/frontend/public/public/emojione/128/1f306.png b/twake/frontend/public/public/emojione/128/1f306.png new file mode 100644 index 00000000..e06953ae Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f306.png differ diff --git a/twake/frontend/public/public/emojione/128/1f307.png b/twake/frontend/public/public/emojione/128/1f307.png new file mode 100644 index 00000000..08c448df Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f307.png differ diff --git a/twake/frontend/public/public/emojione/128/1f308.png b/twake/frontend/public/public/emojione/128/1f308.png new file mode 100644 index 00000000..5dc133ba Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f308.png differ diff --git a/twake/frontend/public/public/emojione/128/1f309.png b/twake/frontend/public/public/emojione/128/1f309.png new file mode 100644 index 00000000..3824c40d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f309.png differ diff --git a/twake/frontend/public/public/emojione/128/1f30a.png b/twake/frontend/public/public/emojione/128/1f30a.png new file mode 100644 index 00000000..1c2aff81 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f30a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f30b.png b/twake/frontend/public/public/emojione/128/1f30b.png new file mode 100644 index 00000000..36aed7e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f30b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f30c.png b/twake/frontend/public/public/emojione/128/1f30c.png new file mode 100644 index 00000000..c095d8f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f30c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f30d.png b/twake/frontend/public/public/emojione/128/1f30d.png new file mode 100644 index 00000000..af230c1d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f30d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f30e.png b/twake/frontend/public/public/emojione/128/1f30e.png new file mode 100644 index 00000000..7d58faa7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f30e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f30f.png b/twake/frontend/public/public/emojione/128/1f30f.png new file mode 100644 index 00000000..1bc93b02 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f30f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f310.png b/twake/frontend/public/public/emojione/128/1f310.png new file mode 100644 index 00000000..35b878d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f310.png differ diff --git a/twake/frontend/public/public/emojione/128/1f311.png b/twake/frontend/public/public/emojione/128/1f311.png new file mode 100644 index 00000000..ca41a391 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f311.png differ diff --git a/twake/frontend/public/public/emojione/128/1f312.png b/twake/frontend/public/public/emojione/128/1f312.png new file mode 100644 index 00000000..d85ee7f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f312.png differ diff --git a/twake/frontend/public/public/emojione/128/1f313.png b/twake/frontend/public/public/emojione/128/1f313.png new file mode 100644 index 00000000..fa47d7b4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f313.png differ diff --git a/twake/frontend/public/public/emojione/128/1f314.png b/twake/frontend/public/public/emojione/128/1f314.png new file mode 100644 index 00000000..1fba7f00 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f314.png differ diff --git a/twake/frontend/public/public/emojione/128/1f315.png b/twake/frontend/public/public/emojione/128/1f315.png new file mode 100644 index 00000000..2e50dd74 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f315.png differ diff --git a/twake/frontend/public/public/emojione/128/1f316.png b/twake/frontend/public/public/emojione/128/1f316.png new file mode 100644 index 00000000..0e9b69a6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f316.png differ diff --git a/twake/frontend/public/public/emojione/128/1f317.png b/twake/frontend/public/public/emojione/128/1f317.png new file mode 100644 index 00000000..b5391058 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f317.png differ diff --git a/twake/frontend/public/public/emojione/128/1f318.png b/twake/frontend/public/public/emojione/128/1f318.png new file mode 100644 index 00000000..40ddfbae Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f318.png differ diff --git a/twake/frontend/public/public/emojione/128/1f319.png b/twake/frontend/public/public/emojione/128/1f319.png new file mode 100644 index 00000000..b923dfc8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f319.png differ diff --git a/twake/frontend/public/public/emojione/128/1f31a.png b/twake/frontend/public/public/emojione/128/1f31a.png new file mode 100644 index 00000000..9fe67264 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f31a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f31b.png b/twake/frontend/public/public/emojione/128/1f31b.png new file mode 100644 index 00000000..7364833b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f31b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f31c.png b/twake/frontend/public/public/emojione/128/1f31c.png new file mode 100644 index 00000000..ccc209ef Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f31c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f31d.png b/twake/frontend/public/public/emojione/128/1f31d.png new file mode 100644 index 00000000..988d3a7e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f31d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f31e.png b/twake/frontend/public/public/emojione/128/1f31e.png new file mode 100644 index 00000000..0cffa4d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f31e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f31f.png b/twake/frontend/public/public/emojione/128/1f31f.png new file mode 100644 index 00000000..3f184202 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f31f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f320.png b/twake/frontend/public/public/emojione/128/1f320.png new file mode 100644 index 00000000..b4bed635 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f320.png differ diff --git a/twake/frontend/public/public/emojione/128/1f321.png b/twake/frontend/public/public/emojione/128/1f321.png new file mode 100644 index 00000000..dda80911 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f321.png differ diff --git a/twake/frontend/public/public/emojione/128/1f324.png b/twake/frontend/public/public/emojione/128/1f324.png new file mode 100644 index 00000000..58eeff1b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f324.png differ diff --git a/twake/frontend/public/public/emojione/128/1f325.png b/twake/frontend/public/public/emojione/128/1f325.png new file mode 100644 index 00000000..d1cb87ee Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f325.png differ diff --git a/twake/frontend/public/public/emojione/128/1f326.png b/twake/frontend/public/public/emojione/128/1f326.png new file mode 100644 index 00000000..07e5133a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f326.png differ diff --git a/twake/frontend/public/public/emojione/128/1f327.png b/twake/frontend/public/public/emojione/128/1f327.png new file mode 100644 index 00000000..a1976817 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f327.png differ diff --git a/twake/frontend/public/public/emojione/128/1f328.png b/twake/frontend/public/public/emojione/128/1f328.png new file mode 100644 index 00000000..3c61f1cd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f328.png differ diff --git a/twake/frontend/public/public/emojione/128/1f329.png b/twake/frontend/public/public/emojione/128/1f329.png new file mode 100644 index 00000000..2d7ce931 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f329.png differ diff --git a/twake/frontend/public/public/emojione/128/1f32a.png b/twake/frontend/public/public/emojione/128/1f32a.png new file mode 100644 index 00000000..472ef3a2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f32a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f32b.png b/twake/frontend/public/public/emojione/128/1f32b.png new file mode 100644 index 00000000..40dee42c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f32b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f32c.png b/twake/frontend/public/public/emojione/128/1f32c.png new file mode 100644 index 00000000..93e8025b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f32c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f32d.png b/twake/frontend/public/public/emojione/128/1f32d.png new file mode 100644 index 00000000..98831db3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f32d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f32e.png b/twake/frontend/public/public/emojione/128/1f32e.png new file mode 100644 index 00000000..e7692b6c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f32e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f32f.png b/twake/frontend/public/public/emojione/128/1f32f.png new file mode 100644 index 00000000..803084e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f32f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f330.png b/twake/frontend/public/public/emojione/128/1f330.png new file mode 100644 index 00000000..b18e13de Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f330.png differ diff --git a/twake/frontend/public/public/emojione/128/1f331.png b/twake/frontend/public/public/emojione/128/1f331.png new file mode 100644 index 00000000..c4e6294a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f331.png differ diff --git a/twake/frontend/public/public/emojione/128/1f332.png b/twake/frontend/public/public/emojione/128/1f332.png new file mode 100644 index 00000000..e5a5afe6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f332.png differ diff --git a/twake/frontend/public/public/emojione/128/1f333.png b/twake/frontend/public/public/emojione/128/1f333.png new file mode 100644 index 00000000..5c317074 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f333.png differ diff --git a/twake/frontend/public/public/emojione/128/1f334.png b/twake/frontend/public/public/emojione/128/1f334.png new file mode 100644 index 00000000..26310584 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f334.png differ diff --git a/twake/frontend/public/public/emojione/128/1f335.png b/twake/frontend/public/public/emojione/128/1f335.png new file mode 100644 index 00000000..bd425c68 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f335.png differ diff --git a/twake/frontend/public/public/emojione/128/1f336.png b/twake/frontend/public/public/emojione/128/1f336.png new file mode 100644 index 00000000..85ff16ab Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f336.png differ diff --git a/twake/frontend/public/public/emojione/128/1f337.png b/twake/frontend/public/public/emojione/128/1f337.png new file mode 100644 index 00000000..3d3eed23 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f337.png differ diff --git a/twake/frontend/public/public/emojione/128/1f338.png b/twake/frontend/public/public/emojione/128/1f338.png new file mode 100644 index 00000000..1b069e31 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f338.png differ diff --git a/twake/frontend/public/public/emojione/128/1f339.png b/twake/frontend/public/public/emojione/128/1f339.png new file mode 100644 index 00000000..20884394 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f339.png differ diff --git a/twake/frontend/public/public/emojione/128/1f33a.png b/twake/frontend/public/public/emojione/128/1f33a.png new file mode 100644 index 00000000..b5c810f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f33a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f33b.png b/twake/frontend/public/public/emojione/128/1f33b.png new file mode 100644 index 00000000..06d6e683 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f33b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f33c.png b/twake/frontend/public/public/emojione/128/1f33c.png new file mode 100644 index 00000000..bc9c1d68 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f33c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f33d.png b/twake/frontend/public/public/emojione/128/1f33d.png new file mode 100644 index 00000000..2db427f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f33d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f33e.png b/twake/frontend/public/public/emojione/128/1f33e.png new file mode 100644 index 00000000..eda25766 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f33e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f33f.png b/twake/frontend/public/public/emojione/128/1f33f.png new file mode 100644 index 00000000..735118a2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f33f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f340.png b/twake/frontend/public/public/emojione/128/1f340.png new file mode 100644 index 00000000..c51299fe Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f340.png differ diff --git a/twake/frontend/public/public/emojione/128/1f341.png b/twake/frontend/public/public/emojione/128/1f341.png new file mode 100644 index 00000000..1ad18936 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f341.png differ diff --git a/twake/frontend/public/public/emojione/128/1f342.png b/twake/frontend/public/public/emojione/128/1f342.png new file mode 100644 index 00000000..367454e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f342.png differ diff --git a/twake/frontend/public/public/emojione/128/1f343.png b/twake/frontend/public/public/emojione/128/1f343.png new file mode 100644 index 00000000..3f1ad8b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f343.png differ diff --git a/twake/frontend/public/public/emojione/128/1f344.png b/twake/frontend/public/public/emojione/128/1f344.png new file mode 100644 index 00000000..96f01308 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f344.png differ diff --git a/twake/frontend/public/public/emojione/128/1f345.png b/twake/frontend/public/public/emojione/128/1f345.png new file mode 100644 index 00000000..7ab1e8b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f345.png differ diff --git a/twake/frontend/public/public/emojione/128/1f346.png b/twake/frontend/public/public/emojione/128/1f346.png new file mode 100644 index 00000000..ad6f398d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f346.png differ diff --git a/twake/frontend/public/public/emojione/128/1f347.png b/twake/frontend/public/public/emojione/128/1f347.png new file mode 100644 index 00000000..3d66a23b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f347.png differ diff --git a/twake/frontend/public/public/emojione/128/1f348.png b/twake/frontend/public/public/emojione/128/1f348.png new file mode 100644 index 00000000..325443a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f348.png differ diff --git a/twake/frontend/public/public/emojione/128/1f349.png b/twake/frontend/public/public/emojione/128/1f349.png new file mode 100644 index 00000000..a8f8b3da Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f349.png differ diff --git a/twake/frontend/public/public/emojione/128/1f34a.png b/twake/frontend/public/public/emojione/128/1f34a.png new file mode 100644 index 00000000..ef45074d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f34a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f34b.png b/twake/frontend/public/public/emojione/128/1f34b.png new file mode 100644 index 00000000..42b11db9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f34b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f34c.png b/twake/frontend/public/public/emojione/128/1f34c.png new file mode 100644 index 00000000..5d99e83f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f34c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f34d.png b/twake/frontend/public/public/emojione/128/1f34d.png new file mode 100644 index 00000000..7e7e44de Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f34d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f34e.png b/twake/frontend/public/public/emojione/128/1f34e.png new file mode 100644 index 00000000..484619cc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f34e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f34f.png b/twake/frontend/public/public/emojione/128/1f34f.png new file mode 100644 index 00000000..4d23036f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f34f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f350.png b/twake/frontend/public/public/emojione/128/1f350.png new file mode 100644 index 00000000..b4ea9e45 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f350.png differ diff --git a/twake/frontend/public/public/emojione/128/1f351.png b/twake/frontend/public/public/emojione/128/1f351.png new file mode 100644 index 00000000..372c5660 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f351.png differ diff --git a/twake/frontend/public/public/emojione/128/1f352.png b/twake/frontend/public/public/emojione/128/1f352.png new file mode 100644 index 00000000..1ed18a99 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f352.png differ diff --git a/twake/frontend/public/public/emojione/128/1f353.png b/twake/frontend/public/public/emojione/128/1f353.png new file mode 100644 index 00000000..90f9ba6d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f353.png differ diff --git a/twake/frontend/public/public/emojione/128/1f354.png b/twake/frontend/public/public/emojione/128/1f354.png new file mode 100644 index 00000000..6409baa3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f354.png differ diff --git a/twake/frontend/public/public/emojione/128/1f355.png b/twake/frontend/public/public/emojione/128/1f355.png new file mode 100644 index 00000000..31bddf7c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f355.png differ diff --git a/twake/frontend/public/public/emojione/128/1f356.png b/twake/frontend/public/public/emojione/128/1f356.png new file mode 100644 index 00000000..fee2c901 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f356.png differ diff --git a/twake/frontend/public/public/emojione/128/1f357.png b/twake/frontend/public/public/emojione/128/1f357.png new file mode 100644 index 00000000..4c948415 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f357.png differ diff --git a/twake/frontend/public/public/emojione/128/1f358.png b/twake/frontend/public/public/emojione/128/1f358.png new file mode 100644 index 00000000..bac8fc29 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f358.png differ diff --git a/twake/frontend/public/public/emojione/128/1f359.png b/twake/frontend/public/public/emojione/128/1f359.png new file mode 100644 index 00000000..28a94556 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f359.png differ diff --git a/twake/frontend/public/public/emojione/128/1f35a.png b/twake/frontend/public/public/emojione/128/1f35a.png new file mode 100644 index 00000000..7d7ce078 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f35a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f35b.png b/twake/frontend/public/public/emojione/128/1f35b.png new file mode 100644 index 00000000..57cbd652 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f35b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f35c.png b/twake/frontend/public/public/emojione/128/1f35c.png new file mode 100644 index 00000000..1be27010 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f35c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f35d.png b/twake/frontend/public/public/emojione/128/1f35d.png new file mode 100644 index 00000000..0ddaeeac Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f35d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f35e.png b/twake/frontend/public/public/emojione/128/1f35e.png new file mode 100644 index 00000000..f706ae24 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f35e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f35f.png b/twake/frontend/public/public/emojione/128/1f35f.png new file mode 100644 index 00000000..b30feb56 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f35f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f360.png b/twake/frontend/public/public/emojione/128/1f360.png new file mode 100644 index 00000000..0bc91c8b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f360.png differ diff --git a/twake/frontend/public/public/emojione/128/1f361.png b/twake/frontend/public/public/emojione/128/1f361.png new file mode 100644 index 00000000..c8cb7a59 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f361.png differ diff --git a/twake/frontend/public/public/emojione/128/1f362.png b/twake/frontend/public/public/emojione/128/1f362.png new file mode 100644 index 00000000..81167608 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f362.png differ diff --git a/twake/frontend/public/public/emojione/128/1f363.png b/twake/frontend/public/public/emojione/128/1f363.png new file mode 100644 index 00000000..73094b7b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f363.png differ diff --git a/twake/frontend/public/public/emojione/128/1f364.png b/twake/frontend/public/public/emojione/128/1f364.png new file mode 100644 index 00000000..e63f50e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f364.png differ diff --git a/twake/frontend/public/public/emojione/128/1f365.png b/twake/frontend/public/public/emojione/128/1f365.png new file mode 100644 index 00000000..78633781 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f365.png differ diff --git a/twake/frontend/public/public/emojione/128/1f366.png b/twake/frontend/public/public/emojione/128/1f366.png new file mode 100644 index 00000000..62919dd4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f366.png differ diff --git a/twake/frontend/public/public/emojione/128/1f367.png b/twake/frontend/public/public/emojione/128/1f367.png new file mode 100644 index 00000000..708e1d41 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f367.png differ diff --git a/twake/frontend/public/public/emojione/128/1f368.png b/twake/frontend/public/public/emojione/128/1f368.png new file mode 100644 index 00000000..1f824d04 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f368.png differ diff --git a/twake/frontend/public/public/emojione/128/1f369.png b/twake/frontend/public/public/emojione/128/1f369.png new file mode 100644 index 00000000..bfab0b66 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f369.png differ diff --git a/twake/frontend/public/public/emojione/128/1f36a.png b/twake/frontend/public/public/emojione/128/1f36a.png new file mode 100644 index 00000000..4b0fb945 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f36a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f36b.png b/twake/frontend/public/public/emojione/128/1f36b.png new file mode 100644 index 00000000..81b42276 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f36b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f36c.png b/twake/frontend/public/public/emojione/128/1f36c.png new file mode 100644 index 00000000..10959c68 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f36c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f36d.png b/twake/frontend/public/public/emojione/128/1f36d.png new file mode 100644 index 00000000..329add85 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f36d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f36e.png b/twake/frontend/public/public/emojione/128/1f36e.png new file mode 100644 index 00000000..5e544d4d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f36e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f36f.png b/twake/frontend/public/public/emojione/128/1f36f.png new file mode 100644 index 00000000..87bc29cd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f36f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f370.png b/twake/frontend/public/public/emojione/128/1f370.png new file mode 100644 index 00000000..71a912e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f370.png differ diff --git a/twake/frontend/public/public/emojione/128/1f371.png b/twake/frontend/public/public/emojione/128/1f371.png new file mode 100644 index 00000000..8e5a72b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f371.png differ diff --git a/twake/frontend/public/public/emojione/128/1f372.png b/twake/frontend/public/public/emojione/128/1f372.png new file mode 100644 index 00000000..25d1cb4d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f372.png differ diff --git a/twake/frontend/public/public/emojione/128/1f373.png b/twake/frontend/public/public/emojione/128/1f373.png new file mode 100644 index 00000000..a2a67759 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f373.png differ diff --git a/twake/frontend/public/public/emojione/128/1f374.png b/twake/frontend/public/public/emojione/128/1f374.png new file mode 100644 index 00000000..21521c31 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f374.png differ diff --git a/twake/frontend/public/public/emojione/128/1f375.png b/twake/frontend/public/public/emojione/128/1f375.png new file mode 100644 index 00000000..c401b4b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f375.png differ diff --git a/twake/frontend/public/public/emojione/128/1f376.png b/twake/frontend/public/public/emojione/128/1f376.png new file mode 100644 index 00000000..d4aca7de Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f376.png differ diff --git a/twake/frontend/public/public/emojione/128/1f377.png b/twake/frontend/public/public/emojione/128/1f377.png new file mode 100644 index 00000000..b45d4dcc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f377.png differ diff --git a/twake/frontend/public/public/emojione/128/1f378.png b/twake/frontend/public/public/emojione/128/1f378.png new file mode 100644 index 00000000..00b5139a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f378.png differ diff --git a/twake/frontend/public/public/emojione/128/1f379.png b/twake/frontend/public/public/emojione/128/1f379.png new file mode 100644 index 00000000..f136792c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f379.png differ diff --git a/twake/frontend/public/public/emojione/128/1f37a.png b/twake/frontend/public/public/emojione/128/1f37a.png new file mode 100644 index 00000000..1e3ec064 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f37a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f37b.png b/twake/frontend/public/public/emojione/128/1f37b.png new file mode 100644 index 00000000..98725d53 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f37b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f37c.png b/twake/frontend/public/public/emojione/128/1f37c.png new file mode 100644 index 00000000..fa11b427 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f37c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f37d.png b/twake/frontend/public/public/emojione/128/1f37d.png new file mode 100644 index 00000000..3fdbba0e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f37d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f37e.png b/twake/frontend/public/public/emojione/128/1f37e.png new file mode 100644 index 00000000..f883d707 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f37e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f37f.png b/twake/frontend/public/public/emojione/128/1f37f.png new file mode 100644 index 00000000..8449c6df Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f37f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f380.png b/twake/frontend/public/public/emojione/128/1f380.png new file mode 100644 index 00000000..519dd0f9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f380.png differ diff --git a/twake/frontend/public/public/emojione/128/1f381.png b/twake/frontend/public/public/emojione/128/1f381.png new file mode 100644 index 00000000..8e4e1169 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f381.png differ diff --git a/twake/frontend/public/public/emojione/128/1f382.png b/twake/frontend/public/public/emojione/128/1f382.png new file mode 100644 index 00000000..e7a8fd28 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f382.png differ diff --git a/twake/frontend/public/public/emojione/128/1f383.png b/twake/frontend/public/public/emojione/128/1f383.png new file mode 100644 index 00000000..29e15f34 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f383.png differ diff --git a/twake/frontend/public/public/emojione/128/1f384.png b/twake/frontend/public/public/emojione/128/1f384.png new file mode 100644 index 00000000..a268c530 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f384.png differ diff --git a/twake/frontend/public/public/emojione/128/1f385-1f3fb.png b/twake/frontend/public/public/emojione/128/1f385-1f3fb.png new file mode 100644 index 00000000..eeb4c8ea Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f385-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f385-1f3fc.png b/twake/frontend/public/public/emojione/128/1f385-1f3fc.png new file mode 100644 index 00000000..cd87064d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f385-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f385-1f3fd.png b/twake/frontend/public/public/emojione/128/1f385-1f3fd.png new file mode 100644 index 00000000..8440f98e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f385-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f385-1f3fe.png b/twake/frontend/public/public/emojione/128/1f385-1f3fe.png new file mode 100644 index 00000000..f617c8e4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f385-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f385-1f3ff.png b/twake/frontend/public/public/emojione/128/1f385-1f3ff.png new file mode 100644 index 00000000..883d44d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f385-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f385.png b/twake/frontend/public/public/emojione/128/1f385.png new file mode 100644 index 00000000..6185edac Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f385.png differ diff --git a/twake/frontend/public/public/emojione/128/1f386.png b/twake/frontend/public/public/emojione/128/1f386.png new file mode 100644 index 00000000..cb1159f4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f386.png differ diff --git a/twake/frontend/public/public/emojione/128/1f387.png b/twake/frontend/public/public/emojione/128/1f387.png new file mode 100644 index 00000000..805c98ed Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f387.png differ diff --git a/twake/frontend/public/public/emojione/128/1f388.png b/twake/frontend/public/public/emojione/128/1f388.png new file mode 100644 index 00000000..26e0abfc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f388.png differ diff --git a/twake/frontend/public/public/emojione/128/1f389.png b/twake/frontend/public/public/emojione/128/1f389.png new file mode 100644 index 00000000..8ed71e43 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f389.png differ diff --git a/twake/frontend/public/public/emojione/128/1f38a.png b/twake/frontend/public/public/emojione/128/1f38a.png new file mode 100644 index 00000000..303d7c19 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f38a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f38b.png b/twake/frontend/public/public/emojione/128/1f38b.png new file mode 100644 index 00000000..7dabc47f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f38b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f38c.png b/twake/frontend/public/public/emojione/128/1f38c.png new file mode 100644 index 00000000..45558fa0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f38c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f38d.png b/twake/frontend/public/public/emojione/128/1f38d.png new file mode 100644 index 00000000..2d69015c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f38d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f38e.png b/twake/frontend/public/public/emojione/128/1f38e.png new file mode 100644 index 00000000..f8000e8f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f38e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f38f.png b/twake/frontend/public/public/emojione/128/1f38f.png new file mode 100644 index 00000000..7bcd68ac Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f38f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f390.png b/twake/frontend/public/public/emojione/128/1f390.png new file mode 100644 index 00000000..79dc747a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f390.png differ diff --git a/twake/frontend/public/public/emojione/128/1f391.png b/twake/frontend/public/public/emojione/128/1f391.png new file mode 100644 index 00000000..9435e6ce Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f391.png differ diff --git a/twake/frontend/public/public/emojione/128/1f392.png b/twake/frontend/public/public/emojione/128/1f392.png new file mode 100644 index 00000000..de4720b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f392.png differ diff --git a/twake/frontend/public/public/emojione/128/1f393.png b/twake/frontend/public/public/emojione/128/1f393.png new file mode 100644 index 00000000..49c85d53 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f393.png differ diff --git a/twake/frontend/public/public/emojione/128/1f396.png b/twake/frontend/public/public/emojione/128/1f396.png new file mode 100644 index 00000000..5bb989b7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f396.png differ diff --git a/twake/frontend/public/public/emojione/128/1f397.png b/twake/frontend/public/public/emojione/128/1f397.png new file mode 100644 index 00000000..c4a0a1cc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f397.png differ diff --git a/twake/frontend/public/public/emojione/128/1f399.png b/twake/frontend/public/public/emojione/128/1f399.png new file mode 100644 index 00000000..296efef8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f399.png differ diff --git a/twake/frontend/public/public/emojione/128/1f39a.png b/twake/frontend/public/public/emojione/128/1f39a.png new file mode 100644 index 00000000..f2b435ad Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f39a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f39b.png b/twake/frontend/public/public/emojione/128/1f39b.png new file mode 100644 index 00000000..3a2cd2f3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f39b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f39e.png b/twake/frontend/public/public/emojione/128/1f39e.png new file mode 100644 index 00000000..45e2b4ed Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f39e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f39f.png b/twake/frontend/public/public/emojione/128/1f39f.png new file mode 100644 index 00000000..d8e455f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f39f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3a0.png b/twake/frontend/public/public/emojione/128/1f3a0.png new file mode 100644 index 00000000..e8742681 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3a0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3a1.png b/twake/frontend/public/public/emojione/128/1f3a1.png new file mode 100644 index 00000000..375282cc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3a1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3a2.png b/twake/frontend/public/public/emojione/128/1f3a2.png new file mode 100644 index 00000000..8efd5422 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3a2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3a3.png b/twake/frontend/public/public/emojione/128/1f3a3.png new file mode 100644 index 00000000..dccf1a18 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3a3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3a4.png b/twake/frontend/public/public/emojione/128/1f3a4.png new file mode 100644 index 00000000..f7c96b61 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3a5.png b/twake/frontend/public/public/emojione/128/1f3a5.png new file mode 100644 index 00000000..c0c7664f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3a5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3a6.png b/twake/frontend/public/public/emojione/128/1f3a6.png new file mode 100644 index 00000000..0523153e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3a6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3a7.png b/twake/frontend/public/public/emojione/128/1f3a7.png new file mode 100644 index 00000000..bbbbfb73 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3a7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3a8.png b/twake/frontend/public/public/emojione/128/1f3a8.png new file mode 100644 index 00000000..123162ca Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3a9.png b/twake/frontend/public/public/emojione/128/1f3a9.png new file mode 100644 index 00000000..4ea0803a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3a9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3aa.png b/twake/frontend/public/public/emojione/128/1f3aa.png new file mode 100644 index 00000000..a67a4c32 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3aa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ab.png b/twake/frontend/public/public/emojione/128/1f3ab.png new file mode 100644 index 00000000..9ae8733b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ab.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ac.png b/twake/frontend/public/public/emojione/128/1f3ac.png new file mode 100644 index 00000000..9fb6f5c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ac.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ad.png b/twake/frontend/public/public/emojione/128/1f3ad.png new file mode 100644 index 00000000..3f81a50f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ad.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ae.png b/twake/frontend/public/public/emojione/128/1f3ae.png new file mode 100644 index 00000000..8ea8a4cd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ae.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3af.png b/twake/frontend/public/public/emojione/128/1f3af.png new file mode 100644 index 00000000..8f028398 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3af.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3b0.png b/twake/frontend/public/public/emojione/128/1f3b0.png new file mode 100644 index 00000000..425e133f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3b0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3b1.png b/twake/frontend/public/public/emojione/128/1f3b1.png new file mode 100644 index 00000000..0c86f38b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3b1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3b2.png b/twake/frontend/public/public/emojione/128/1f3b2.png new file mode 100644 index 00000000..1a76baf1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3b2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3b3.png b/twake/frontend/public/public/emojione/128/1f3b3.png new file mode 100644 index 00000000..b7282de3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3b3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3b4.png b/twake/frontend/public/public/emojione/128/1f3b4.png new file mode 100644 index 00000000..ed8ee0b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3b4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3b5.png b/twake/frontend/public/public/emojione/128/1f3b5.png new file mode 100644 index 00000000..911fb8d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3b5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3b6.png b/twake/frontend/public/public/emojione/128/1f3b6.png new file mode 100644 index 00000000..c18c4d7c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3b6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3b7.png b/twake/frontend/public/public/emojione/128/1f3b7.png new file mode 100644 index 00000000..8a23bc00 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3b7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3b8.png b/twake/frontend/public/public/emojione/128/1f3b8.png new file mode 100644 index 00000000..02c693ce Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3b8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3b9.png b/twake/frontend/public/public/emojione/128/1f3b9.png new file mode 100644 index 00000000..19d621f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3b9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ba.png b/twake/frontend/public/public/emojione/128/1f3ba.png new file mode 100644 index 00000000..0bd8c760 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ba.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3bb.png b/twake/frontend/public/public/emojione/128/1f3bb.png new file mode 100644 index 00000000..5ea11c04 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3bb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3bc.png b/twake/frontend/public/public/emojione/128/1f3bc.png new file mode 100644 index 00000000..3545693b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3bc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3bd.png b/twake/frontend/public/public/emojione/128/1f3bd.png new file mode 100644 index 00000000..9a5f6c0c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3bd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3be.png b/twake/frontend/public/public/emojione/128/1f3be.png new file mode 100644 index 00000000..917def6a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3be.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3bf.png b/twake/frontend/public/public/emojione/128/1f3bf.png new file mode 100644 index 00000000..6b1ce824 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3bf.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c0.png b/twake/frontend/public/public/emojione/128/1f3c0.png new file mode 100644 index 00000000..65489032 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c1.png b/twake/frontend/public/public/emojione/128/1f3c1.png new file mode 100644 index 00000000..4008cccc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c2-1f3fb.png b/twake/frontend/public/public/emojione/128/1f3c2-1f3fb.png new file mode 100644 index 00000000..4d5f3f67 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c2-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c2-1f3fc.png b/twake/frontend/public/public/emojione/128/1f3c2-1f3fc.png new file mode 100644 index 00000000..89b45520 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c2-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c2-1f3fd.png b/twake/frontend/public/public/emojione/128/1f3c2-1f3fd.png new file mode 100644 index 00000000..187d9385 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c2-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c2-1f3fe.png b/twake/frontend/public/public/emojione/128/1f3c2-1f3fe.png new file mode 100644 index 00000000..10b35418 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c2-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c2-1f3ff.png b/twake/frontend/public/public/emojione/128/1f3c2-1f3ff.png new file mode 100644 index 00000000..b576713c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c2-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c2.png b/twake/frontend/public/public/emojione/128/1f3c2.png new file mode 100644 index 00000000..f1d32972 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f3c3-1f3fb-2640.png new file mode 100644 index 00000000..12c154ee Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f3c3-1f3fb-2642.png new file mode 100644 index 00000000..76309091 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3-1f3fb.png b/twake/frontend/public/public/emojione/128/1f3c3-1f3fb.png new file mode 100644 index 00000000..76309091 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f3c3-1f3fc-2640.png new file mode 100644 index 00000000..dd55099a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f3c3-1f3fc-2642.png new file mode 100644 index 00000000..b0586ab8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3-1f3fc.png b/twake/frontend/public/public/emojione/128/1f3c3-1f3fc.png new file mode 100644 index 00000000..b0586ab8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f3c3-1f3fd-2640.png new file mode 100644 index 00000000..cf944500 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f3c3-1f3fd-2642.png new file mode 100644 index 00000000..693b7549 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3-1f3fd.png b/twake/frontend/public/public/emojione/128/1f3c3-1f3fd.png new file mode 100644 index 00000000..693b7549 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f3c3-1f3fe-2640.png new file mode 100644 index 00000000..96452f29 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f3c3-1f3fe-2642.png new file mode 100644 index 00000000..4cccce3e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3-1f3fe.png b/twake/frontend/public/public/emojione/128/1f3c3-1f3fe.png new file mode 100644 index 00000000..4cccce3e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f3c3-1f3ff-2640.png new file mode 100644 index 00000000..c3695108 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f3c3-1f3ff-2642.png new file mode 100644 index 00000000..0ee6eb1f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3-1f3ff.png b/twake/frontend/public/public/emojione/128/1f3c3-1f3ff.png new file mode 100644 index 00000000..0ee6eb1f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3-2640.png b/twake/frontend/public/public/emojione/128/1f3c3-2640.png new file mode 100644 index 00000000..c301681b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3-2642.png b/twake/frontend/public/public/emojione/128/1f3c3-2642.png new file mode 100644 index 00000000..65cb7bf6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c3.png b/twake/frontend/public/public/emojione/128/1f3c3.png new file mode 100644 index 00000000..65cb7bf6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f3c4-1f3fb-2640.png new file mode 100644 index 00000000..9ec8470e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f3c4-1f3fb-2642.png new file mode 100644 index 00000000..ee150ddc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4-1f3fb.png b/twake/frontend/public/public/emojione/128/1f3c4-1f3fb.png new file mode 100644 index 00000000..ee150ddc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f3c4-1f3fc-2640.png new file mode 100644 index 00000000..65d7920d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f3c4-1f3fc-2642.png new file mode 100644 index 00000000..837b23d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4-1f3fc.png b/twake/frontend/public/public/emojione/128/1f3c4-1f3fc.png new file mode 100644 index 00000000..837b23d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f3c4-1f3fd-2640.png new file mode 100644 index 00000000..b6ecfd7a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f3c4-1f3fd-2642.png new file mode 100644 index 00000000..e2706482 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4-1f3fd.png b/twake/frontend/public/public/emojione/128/1f3c4-1f3fd.png new file mode 100644 index 00000000..e2706482 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f3c4-1f3fe-2640.png new file mode 100644 index 00000000..a118a641 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f3c4-1f3fe-2642.png new file mode 100644 index 00000000..09df8988 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4-1f3fe.png b/twake/frontend/public/public/emojione/128/1f3c4-1f3fe.png new file mode 100644 index 00000000..09df8988 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f3c4-1f3ff-2640.png new file mode 100644 index 00000000..ec16d152 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f3c4-1f3ff-2642.png new file mode 100644 index 00000000..9a698069 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4-1f3ff.png b/twake/frontend/public/public/emojione/128/1f3c4-1f3ff.png new file mode 100644 index 00000000..9a698069 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4-2640.png b/twake/frontend/public/public/emojione/128/1f3c4-2640.png new file mode 100644 index 00000000..a6be765d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4-2642.png b/twake/frontend/public/public/emojione/128/1f3c4-2642.png new file mode 100644 index 00000000..69a483fe Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c4.png b/twake/frontend/public/public/emojione/128/1f3c4.png new file mode 100644 index 00000000..69a483fe Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c5.png b/twake/frontend/public/public/emojione/128/1f3c5.png new file mode 100644 index 00000000..912b535e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c6.png b/twake/frontend/public/public/emojione/128/1f3c6.png new file mode 100644 index 00000000..f012c147 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c7-1f3fb.png b/twake/frontend/public/public/emojione/128/1f3c7-1f3fb.png new file mode 100644 index 00000000..e0591e5e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c7-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c7-1f3fc.png b/twake/frontend/public/public/emojione/128/1f3c7-1f3fc.png new file mode 100644 index 00000000..3c479db5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c7-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c7-1f3fd.png b/twake/frontend/public/public/emojione/128/1f3c7-1f3fd.png new file mode 100644 index 00000000..7a579d84 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c7-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c7-1f3fe.png b/twake/frontend/public/public/emojione/128/1f3c7-1f3fe.png new file mode 100644 index 00000000..3387d09d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c7-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c7-1f3ff.png b/twake/frontend/public/public/emojione/128/1f3c7-1f3ff.png new file mode 100644 index 00000000..71db681a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c7-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c7.png b/twake/frontend/public/public/emojione/128/1f3c7.png new file mode 100644 index 00000000..99d1df15 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c8.png b/twake/frontend/public/public/emojione/128/1f3c8.png new file mode 100644 index 00000000..5389b0fa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3c9.png b/twake/frontend/public/public/emojione/128/1f3c9.png new file mode 100644 index 00000000..fd8976f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3c9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f3ca-1f3fb-2640.png new file mode 100644 index 00000000..364cd053 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f3ca-1f3fb-2642.png new file mode 100644 index 00000000..b8591d19 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca-1f3fb.png b/twake/frontend/public/public/emojione/128/1f3ca-1f3fb.png new file mode 100644 index 00000000..b8591d19 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f3ca-1f3fc-2640.png new file mode 100644 index 00000000..ebae75d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f3ca-1f3fc-2642.png new file mode 100644 index 00000000..9858c73c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca-1f3fc.png b/twake/frontend/public/public/emojione/128/1f3ca-1f3fc.png new file mode 100644 index 00000000..9858c73c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f3ca-1f3fd-2640.png new file mode 100644 index 00000000..34755f9e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f3ca-1f3fd-2642.png new file mode 100644 index 00000000..f53f25a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca-1f3fd.png b/twake/frontend/public/public/emojione/128/1f3ca-1f3fd.png new file mode 100644 index 00000000..f53f25a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f3ca-1f3fe-2640.png new file mode 100644 index 00000000..d54b2098 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f3ca-1f3fe-2642.png new file mode 100644 index 00000000..401b09b7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca-1f3fe.png b/twake/frontend/public/public/emojione/128/1f3ca-1f3fe.png new file mode 100644 index 00000000..401b09b7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f3ca-1f3ff-2640.png new file mode 100644 index 00000000..201de9a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f3ca-1f3ff-2642.png new file mode 100644 index 00000000..3b188403 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca-1f3ff.png b/twake/frontend/public/public/emojione/128/1f3ca-1f3ff.png new file mode 100644 index 00000000..3b188403 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca-2640.png b/twake/frontend/public/public/emojione/128/1f3ca-2640.png new file mode 100644 index 00000000..f8666a46 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca-2642.png b/twake/frontend/public/public/emojione/128/1f3ca-2642.png new file mode 100644 index 00000000..e5c4e4f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ca.png b/twake/frontend/public/public/emojione/128/1f3ca.png new file mode 100644 index 00000000..e5c4e4f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ca.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f3cb-1f3fb-2640.png new file mode 100644 index 00000000..908209d5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f3cb-1f3fb-2642.png new file mode 100644 index 00000000..3389ff87 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb-1f3fb.png b/twake/frontend/public/public/emojione/128/1f3cb-1f3fb.png new file mode 100644 index 00000000..3389ff87 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f3cb-1f3fc-2640.png new file mode 100644 index 00000000..f9654c84 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f3cb-1f3fc-2642.png new file mode 100644 index 00000000..7b74cd4a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb-1f3fc.png b/twake/frontend/public/public/emojione/128/1f3cb-1f3fc.png new file mode 100644 index 00000000..7b74cd4a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f3cb-1f3fd-2640.png new file mode 100644 index 00000000..e5ea44b9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f3cb-1f3fd-2642.png new file mode 100644 index 00000000..7bb87da7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb-1f3fd.png b/twake/frontend/public/public/emojione/128/1f3cb-1f3fd.png new file mode 100644 index 00000000..7bb87da7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f3cb-1f3fe-2640.png new file mode 100644 index 00000000..a2717f04 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f3cb-1f3fe-2642.png new file mode 100644 index 00000000..23ba870c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb-1f3fe.png b/twake/frontend/public/public/emojione/128/1f3cb-1f3fe.png new file mode 100644 index 00000000..23ba870c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f3cb-1f3ff-2640.png new file mode 100644 index 00000000..60828f01 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f3cb-1f3ff-2642.png new file mode 100644 index 00000000..4789fd72 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb-1f3ff.png b/twake/frontend/public/public/emojione/128/1f3cb-1f3ff.png new file mode 100644 index 00000000..4789fd72 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb-2640.png b/twake/frontend/public/public/emojione/128/1f3cb-2640.png new file mode 100644 index 00000000..9948670a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb-2642.png b/twake/frontend/public/public/emojione/128/1f3cb-2642.png new file mode 100644 index 00000000..f6d02aee Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cb.png b/twake/frontend/public/public/emojione/128/1f3cb.png new file mode 100644 index 00000000..f6d02aee Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f3cc-1f3fb-2640.png new file mode 100644 index 00000000..f47f20ba Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f3cc-1f3fb-2642.png new file mode 100644 index 00000000..0de014ba Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc-1f3fb.png b/twake/frontend/public/public/emojione/128/1f3cc-1f3fb.png new file mode 100644 index 00000000..0de014ba Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f3cc-1f3fc-2640.png new file mode 100644 index 00000000..3abe2c92 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f3cc-1f3fc-2642.png new file mode 100644 index 00000000..05874556 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc-1f3fc.png b/twake/frontend/public/public/emojione/128/1f3cc-1f3fc.png new file mode 100644 index 00000000..05874556 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f3cc-1f3fd-2640.png new file mode 100644 index 00000000..66288867 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f3cc-1f3fd-2642.png new file mode 100644 index 00000000..268731d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc-1f3fd.png b/twake/frontend/public/public/emojione/128/1f3cc-1f3fd.png new file mode 100644 index 00000000..268731d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f3cc-1f3fe-2640.png new file mode 100644 index 00000000..ce8e706c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f3cc-1f3fe-2642.png new file mode 100644 index 00000000..960ed3f3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc-1f3fe.png b/twake/frontend/public/public/emojione/128/1f3cc-1f3fe.png new file mode 100644 index 00000000..960ed3f3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f3cc-1f3ff-2640.png new file mode 100644 index 00000000..a5e3b268 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f3cc-1f3ff-2642.png new file mode 100644 index 00000000..0a841557 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc-1f3ff.png b/twake/frontend/public/public/emojione/128/1f3cc-1f3ff.png new file mode 100644 index 00000000..0a841557 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc-2640.png b/twake/frontend/public/public/emojione/128/1f3cc-2640.png new file mode 100644 index 00000000..4630d23a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc-2642.png b/twake/frontend/public/public/emojione/128/1f3cc-2642.png new file mode 100644 index 00000000..be27204c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cc.png b/twake/frontend/public/public/emojione/128/1f3cc.png new file mode 100644 index 00000000..be27204c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cd.png b/twake/frontend/public/public/emojione/128/1f3cd.png new file mode 100644 index 00000000..324fb115 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ce.png b/twake/frontend/public/public/emojione/128/1f3ce.png new file mode 100644 index 00000000..441ee53e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ce.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3cf.png b/twake/frontend/public/public/emojione/128/1f3cf.png new file mode 100644 index 00000000..6ff56b5d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3cf.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3d0.png b/twake/frontend/public/public/emojione/128/1f3d0.png new file mode 100644 index 00000000..3e261e43 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3d0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3d1.png b/twake/frontend/public/public/emojione/128/1f3d1.png new file mode 100644 index 00000000..512283f3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3d1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3d2.png b/twake/frontend/public/public/emojione/128/1f3d2.png new file mode 100644 index 00000000..b08f35fd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3d2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3d3.png b/twake/frontend/public/public/emojione/128/1f3d3.png new file mode 100644 index 00000000..513f4c49 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3d3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3d4.png b/twake/frontend/public/public/emojione/128/1f3d4.png new file mode 100644 index 00000000..fe51bbf4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3d4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3d5.png b/twake/frontend/public/public/emojione/128/1f3d5.png new file mode 100644 index 00000000..80c44d93 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3d5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3d6.png b/twake/frontend/public/public/emojione/128/1f3d6.png new file mode 100644 index 00000000..1d9e16dd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3d6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3d7.png b/twake/frontend/public/public/emojione/128/1f3d7.png new file mode 100644 index 00000000..e079effc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3d7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3d8.png b/twake/frontend/public/public/emojione/128/1f3d8.png new file mode 100644 index 00000000..0ef131f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3d8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3d9.png b/twake/frontend/public/public/emojione/128/1f3d9.png new file mode 100644 index 00000000..6c464081 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3d9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3da.png b/twake/frontend/public/public/emojione/128/1f3da.png new file mode 100644 index 00000000..7b73c1ee Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3da.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3db.png b/twake/frontend/public/public/emojione/128/1f3db.png new file mode 100644 index 00000000..ea47f951 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3db.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3dc.png b/twake/frontend/public/public/emojione/128/1f3dc.png new file mode 100644 index 00000000..1b90f92d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3dc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3dd.png b/twake/frontend/public/public/emojione/128/1f3dd.png new file mode 100644 index 00000000..8f0a25a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3dd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3de.png b/twake/frontend/public/public/emojione/128/1f3de.png new file mode 100644 index 00000000..cd2f4373 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3de.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3df.png b/twake/frontend/public/public/emojione/128/1f3df.png new file mode 100644 index 00000000..66869290 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3df.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3e0.png b/twake/frontend/public/public/emojione/128/1f3e0.png new file mode 100644 index 00000000..7ebbad54 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3e0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3e1.png b/twake/frontend/public/public/emojione/128/1f3e1.png new file mode 100644 index 00000000..db2bb534 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3e1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3e2.png b/twake/frontend/public/public/emojione/128/1f3e2.png new file mode 100644 index 00000000..a378acf1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3e2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3e3.png b/twake/frontend/public/public/emojione/128/1f3e3.png new file mode 100644 index 00000000..39882b4e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3e3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3e4.png b/twake/frontend/public/public/emojione/128/1f3e4.png new file mode 100644 index 00000000..0f5a6729 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3e4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3e5.png b/twake/frontend/public/public/emojione/128/1f3e5.png new file mode 100644 index 00000000..65db23a2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3e5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3e6.png b/twake/frontend/public/public/emojione/128/1f3e6.png new file mode 100644 index 00000000..6d937e01 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3e7.png b/twake/frontend/public/public/emojione/128/1f3e7.png new file mode 100644 index 00000000..b3de541a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3e7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3e8.png b/twake/frontend/public/public/emojione/128/1f3e8.png new file mode 100644 index 00000000..e7a7994b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3e8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3e9.png b/twake/frontend/public/public/emojione/128/1f3e9.png new file mode 100644 index 00000000..22ab7573 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3e9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ea.png b/twake/frontend/public/public/emojione/128/1f3ea.png new file mode 100644 index 00000000..82791133 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3eb.png b/twake/frontend/public/public/emojione/128/1f3eb.png new file mode 100644 index 00000000..b0dfbeae Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ec.png b/twake/frontend/public/public/emojione/128/1f3ec.png new file mode 100644 index 00000000..f4eee148 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ed.png b/twake/frontend/public/public/emojione/128/1f3ed.png new file mode 100644 index 00000000..9daf59a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ee.png b/twake/frontend/public/public/emojione/128/1f3ee.png new file mode 100644 index 00000000..f413c833 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ee.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ef.png b/twake/frontend/public/public/emojione/128/1f3ef.png new file mode 100644 index 00000000..537944aa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ef.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3f0.png b/twake/frontend/public/public/emojione/128/1f3f0.png new file mode 100644 index 00000000..fdab6cbb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3f0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3f3-1f308.png b/twake/frontend/public/public/emojione/128/1f3f3-1f308.png new file mode 100644 index 00000000..5cdb8b01 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3f3-1f308.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3f3.png b/twake/frontend/public/public/emojione/128/1f3f3.png new file mode 100644 index 00000000..e1a4916e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3f4-2620.png b/twake/frontend/public/public/emojione/128/1f3f4-2620.png new file mode 100644 index 00000000..dd3f16b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3f4-2620.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png b/twake/frontend/public/public/emojione/128/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png new file mode 100644 index 00000000..6bc8da74 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png b/twake/frontend/public/public/emojione/128/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png new file mode 100644 index 00000000..45d308b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png b/twake/frontend/public/public/emojione/128/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png new file mode 100644 index 00000000..bb08a0e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3f4.png b/twake/frontend/public/public/emojione/128/1f3f4.png new file mode 100644 index 00000000..4b06369d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3f4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3f5.png b/twake/frontend/public/public/emojione/128/1f3f5.png new file mode 100644 index 00000000..7223c8ed Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3f5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3f7.png b/twake/frontend/public/public/emojione/128/1f3f7.png new file mode 100644 index 00000000..dd36787a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3f8.png b/twake/frontend/public/public/emojione/128/1f3f8.png new file mode 100644 index 00000000..8c4876ff Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3f8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3f9.png b/twake/frontend/public/public/emojione/128/1f3f9.png new file mode 100644 index 00000000..78bc0cad Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3f9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3fa.png b/twake/frontend/public/public/emojione/128/1f3fa.png new file mode 100644 index 00000000..d5799735 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3fa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3fb.png b/twake/frontend/public/public/emojione/128/1f3fb.png new file mode 100644 index 00000000..99e34143 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3fc.png b/twake/frontend/public/public/emojione/128/1f3fc.png new file mode 100644 index 00000000..0fe43887 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3fd.png b/twake/frontend/public/public/emojione/128/1f3fd.png new file mode 100644 index 00000000..5ef41e1b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3fe.png b/twake/frontend/public/public/emojione/128/1f3fe.png new file mode 100644 index 00000000..7f84b81f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f3ff.png b/twake/frontend/public/public/emojione/128/1f3ff.png new file mode 100644 index 00000000..a89d0854 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f400.png b/twake/frontend/public/public/emojione/128/1f400.png new file mode 100644 index 00000000..92a91290 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f400.png differ diff --git a/twake/frontend/public/public/emojione/128/1f401.png b/twake/frontend/public/public/emojione/128/1f401.png new file mode 100644 index 00000000..b5b19eb5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f401.png differ diff --git a/twake/frontend/public/public/emojione/128/1f402.png b/twake/frontend/public/public/emojione/128/1f402.png new file mode 100644 index 00000000..c65186f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f402.png differ diff --git a/twake/frontend/public/public/emojione/128/1f403.png b/twake/frontend/public/public/emojione/128/1f403.png new file mode 100644 index 00000000..98006d90 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f403.png differ diff --git a/twake/frontend/public/public/emojione/128/1f404.png b/twake/frontend/public/public/emojione/128/1f404.png new file mode 100644 index 00000000..25408f4c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f404.png differ diff --git a/twake/frontend/public/public/emojione/128/1f405.png b/twake/frontend/public/public/emojione/128/1f405.png new file mode 100644 index 00000000..c25fbcae Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f405.png differ diff --git a/twake/frontend/public/public/emojione/128/1f406.png b/twake/frontend/public/public/emojione/128/1f406.png new file mode 100644 index 00000000..bf445ae0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f406.png differ diff --git a/twake/frontend/public/public/emojione/128/1f407.png b/twake/frontend/public/public/emojione/128/1f407.png new file mode 100644 index 00000000..abe0e390 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f407.png differ diff --git a/twake/frontend/public/public/emojione/128/1f408.png b/twake/frontend/public/public/emojione/128/1f408.png new file mode 100644 index 00000000..dc413e21 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f408.png differ diff --git a/twake/frontend/public/public/emojione/128/1f409.png b/twake/frontend/public/public/emojione/128/1f409.png new file mode 100644 index 00000000..facfc919 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f409.png differ diff --git a/twake/frontend/public/public/emojione/128/1f40a.png b/twake/frontend/public/public/emojione/128/1f40a.png new file mode 100644 index 00000000..a7fd897d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f40a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f40b.png b/twake/frontend/public/public/emojione/128/1f40b.png new file mode 100644 index 00000000..78c6e18d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f40b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f40c.png b/twake/frontend/public/public/emojione/128/1f40c.png new file mode 100644 index 00000000..bd339c15 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f40c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f40d.png b/twake/frontend/public/public/emojione/128/1f40d.png new file mode 100644 index 00000000..8402368f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f40d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f40e.png b/twake/frontend/public/public/emojione/128/1f40e.png new file mode 100644 index 00000000..9d2507e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f40e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f40f.png b/twake/frontend/public/public/emojione/128/1f40f.png new file mode 100644 index 00000000..f12e8ea0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f40f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f410.png b/twake/frontend/public/public/emojione/128/1f410.png new file mode 100644 index 00000000..fa7e7cdc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f410.png differ diff --git a/twake/frontend/public/public/emojione/128/1f411.png b/twake/frontend/public/public/emojione/128/1f411.png new file mode 100644 index 00000000..4f8a02c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f411.png differ diff --git a/twake/frontend/public/public/emojione/128/1f412.png b/twake/frontend/public/public/emojione/128/1f412.png new file mode 100644 index 00000000..a9bb6621 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f412.png differ diff --git a/twake/frontend/public/public/emojione/128/1f413.png b/twake/frontend/public/public/emojione/128/1f413.png new file mode 100644 index 00000000..a808ff1e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f413.png differ diff --git a/twake/frontend/public/public/emojione/128/1f414.png b/twake/frontend/public/public/emojione/128/1f414.png new file mode 100644 index 00000000..3c3a98c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f414.png differ diff --git a/twake/frontend/public/public/emojione/128/1f415.png b/twake/frontend/public/public/emojione/128/1f415.png new file mode 100644 index 00000000..3743b604 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f415.png differ diff --git a/twake/frontend/public/public/emojione/128/1f416.png b/twake/frontend/public/public/emojione/128/1f416.png new file mode 100644 index 00000000..5752f0ae Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f416.png differ diff --git a/twake/frontend/public/public/emojione/128/1f417.png b/twake/frontend/public/public/emojione/128/1f417.png new file mode 100644 index 00000000..947d81d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f417.png differ diff --git a/twake/frontend/public/public/emojione/128/1f418.png b/twake/frontend/public/public/emojione/128/1f418.png new file mode 100644 index 00000000..8e5613de Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f418.png differ diff --git a/twake/frontend/public/public/emojione/128/1f419.png b/twake/frontend/public/public/emojione/128/1f419.png new file mode 100644 index 00000000..6febb2a5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f419.png differ diff --git a/twake/frontend/public/public/emojione/128/1f41a.png b/twake/frontend/public/public/emojione/128/1f41a.png new file mode 100644 index 00000000..dbfdd5bf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f41a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f41b.png b/twake/frontend/public/public/emojione/128/1f41b.png new file mode 100644 index 00000000..88590c19 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f41b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f41c.png b/twake/frontend/public/public/emojione/128/1f41c.png new file mode 100644 index 00000000..506301d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f41c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f41d.png b/twake/frontend/public/public/emojione/128/1f41d.png new file mode 100644 index 00000000..1938736b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f41d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f41e.png b/twake/frontend/public/public/emojione/128/1f41e.png new file mode 100644 index 00000000..19d4c2ae Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f41e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f41f.png b/twake/frontend/public/public/emojione/128/1f41f.png new file mode 100644 index 00000000..72506d4e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f41f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f420.png b/twake/frontend/public/public/emojione/128/1f420.png new file mode 100644 index 00000000..df75d7b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f420.png differ diff --git a/twake/frontend/public/public/emojione/128/1f421.png b/twake/frontend/public/public/emojione/128/1f421.png new file mode 100644 index 00000000..bbb2289c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f421.png differ diff --git a/twake/frontend/public/public/emojione/128/1f422.png b/twake/frontend/public/public/emojione/128/1f422.png new file mode 100644 index 00000000..a9aa358a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f422.png differ diff --git a/twake/frontend/public/public/emojione/128/1f423.png b/twake/frontend/public/public/emojione/128/1f423.png new file mode 100644 index 00000000..e3792c33 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f423.png differ diff --git a/twake/frontend/public/public/emojione/128/1f424.png b/twake/frontend/public/public/emojione/128/1f424.png new file mode 100644 index 00000000..0ad80508 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f424.png differ diff --git a/twake/frontend/public/public/emojione/128/1f425.png b/twake/frontend/public/public/emojione/128/1f425.png new file mode 100644 index 00000000..806cbb1e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f425.png differ diff --git a/twake/frontend/public/public/emojione/128/1f426.png b/twake/frontend/public/public/emojione/128/1f426.png new file mode 100644 index 00000000..e5f1f5cb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f426.png differ diff --git a/twake/frontend/public/public/emojione/128/1f427.png b/twake/frontend/public/public/emojione/128/1f427.png new file mode 100644 index 00000000..2ea6abeb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f427.png differ diff --git a/twake/frontend/public/public/emojione/128/1f428.png b/twake/frontend/public/public/emojione/128/1f428.png new file mode 100644 index 00000000..db68de62 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f428.png differ diff --git a/twake/frontend/public/public/emojione/128/1f429.png b/twake/frontend/public/public/emojione/128/1f429.png new file mode 100644 index 00000000..5072b90a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f429.png differ diff --git a/twake/frontend/public/public/emojione/128/1f42a.png b/twake/frontend/public/public/emojione/128/1f42a.png new file mode 100644 index 00000000..087773a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f42a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f42b.png b/twake/frontend/public/public/emojione/128/1f42b.png new file mode 100644 index 00000000..3de8fa85 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f42b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f42c.png b/twake/frontend/public/public/emojione/128/1f42c.png new file mode 100644 index 00000000..33292b86 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f42c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f42d.png b/twake/frontend/public/public/emojione/128/1f42d.png new file mode 100644 index 00000000..4c2e13ed Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f42d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f42e.png b/twake/frontend/public/public/emojione/128/1f42e.png new file mode 100644 index 00000000..41762d6f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f42e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f42f.png b/twake/frontend/public/public/emojione/128/1f42f.png new file mode 100644 index 00000000..f7982522 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f42f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f430.png b/twake/frontend/public/public/emojione/128/1f430.png new file mode 100644 index 00000000..5a35fbc9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f430.png differ diff --git a/twake/frontend/public/public/emojione/128/1f431.png b/twake/frontend/public/public/emojione/128/1f431.png new file mode 100644 index 00000000..d4e32246 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f431.png differ diff --git a/twake/frontend/public/public/emojione/128/1f432.png b/twake/frontend/public/public/emojione/128/1f432.png new file mode 100644 index 00000000..6d038392 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f432.png differ diff --git a/twake/frontend/public/public/emojione/128/1f433.png b/twake/frontend/public/public/emojione/128/1f433.png new file mode 100644 index 00000000..ff1063d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f433.png differ diff --git a/twake/frontend/public/public/emojione/128/1f434.png b/twake/frontend/public/public/emojione/128/1f434.png new file mode 100644 index 00000000..c9f6ad01 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f434.png differ diff --git a/twake/frontend/public/public/emojione/128/1f435.png b/twake/frontend/public/public/emojione/128/1f435.png new file mode 100644 index 00000000..71e12d5c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f435.png differ diff --git a/twake/frontend/public/public/emojione/128/1f436.png b/twake/frontend/public/public/emojione/128/1f436.png new file mode 100644 index 00000000..d16b1b2b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f436.png differ diff --git a/twake/frontend/public/public/emojione/128/1f437.png b/twake/frontend/public/public/emojione/128/1f437.png new file mode 100644 index 00000000..96ffa4be Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f437.png differ diff --git a/twake/frontend/public/public/emojione/128/1f438.png b/twake/frontend/public/public/emojione/128/1f438.png new file mode 100644 index 00000000..b74aebbb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f438.png differ diff --git a/twake/frontend/public/public/emojione/128/1f439.png b/twake/frontend/public/public/emojione/128/1f439.png new file mode 100644 index 00000000..ade88f8f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f439.png differ diff --git a/twake/frontend/public/public/emojione/128/1f43a.png b/twake/frontend/public/public/emojione/128/1f43a.png new file mode 100644 index 00000000..5c9437d5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f43a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f43b.png b/twake/frontend/public/public/emojione/128/1f43b.png new file mode 100644 index 00000000..e4c4eb83 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f43b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f43c.png b/twake/frontend/public/public/emojione/128/1f43c.png new file mode 100644 index 00000000..67e625ec Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f43c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f43d.png b/twake/frontend/public/public/emojione/128/1f43d.png new file mode 100644 index 00000000..4356b97a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f43d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f43e.png b/twake/frontend/public/public/emojione/128/1f43e.png new file mode 100644 index 00000000..fc12123e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f43e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f43f.png b/twake/frontend/public/public/emojione/128/1f43f.png new file mode 100644 index 00000000..183aab79 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f43f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f440.png b/twake/frontend/public/public/emojione/128/1f440.png new file mode 100644 index 00000000..ef0bf9b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f440.png differ diff --git a/twake/frontend/public/public/emojione/128/1f441-1f5e8.png b/twake/frontend/public/public/emojione/128/1f441-1f5e8.png new file mode 100644 index 00000000..804dd974 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f441-1f5e8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f441.png b/twake/frontend/public/public/emojione/128/1f441.png new file mode 100644 index 00000000..06066501 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f441.png differ diff --git a/twake/frontend/public/public/emojione/128/1f442-1f3fb.png b/twake/frontend/public/public/emojione/128/1f442-1f3fb.png new file mode 100644 index 00000000..74b88473 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f442-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f442-1f3fc.png b/twake/frontend/public/public/emojione/128/1f442-1f3fc.png new file mode 100644 index 00000000..c484e2d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f442-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f442-1f3fd.png b/twake/frontend/public/public/emojione/128/1f442-1f3fd.png new file mode 100644 index 00000000..ff8767ba Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f442-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f442-1f3fe.png b/twake/frontend/public/public/emojione/128/1f442-1f3fe.png new file mode 100644 index 00000000..c1366ce9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f442-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f442-1f3ff.png b/twake/frontend/public/public/emojione/128/1f442-1f3ff.png new file mode 100644 index 00000000..8c143168 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f442-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f442.png b/twake/frontend/public/public/emojione/128/1f442.png new file mode 100644 index 00000000..14cbdc2b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f442.png differ diff --git a/twake/frontend/public/public/emojione/128/1f443-1f3fb.png b/twake/frontend/public/public/emojione/128/1f443-1f3fb.png new file mode 100644 index 00000000..cf14dfe4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f443-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f443-1f3fc.png b/twake/frontend/public/public/emojione/128/1f443-1f3fc.png new file mode 100644 index 00000000..3625a67b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f443-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f443-1f3fd.png b/twake/frontend/public/public/emojione/128/1f443-1f3fd.png new file mode 100644 index 00000000..d463c384 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f443-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f443-1f3fe.png b/twake/frontend/public/public/emojione/128/1f443-1f3fe.png new file mode 100644 index 00000000..8750c608 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f443-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f443-1f3ff.png b/twake/frontend/public/public/emojione/128/1f443-1f3ff.png new file mode 100644 index 00000000..42612fdd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f443-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f443.png b/twake/frontend/public/public/emojione/128/1f443.png new file mode 100644 index 00000000..5b0dd2bc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f443.png differ diff --git a/twake/frontend/public/public/emojione/128/1f444.png b/twake/frontend/public/public/emojione/128/1f444.png new file mode 100644 index 00000000..4f015142 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f444.png differ diff --git a/twake/frontend/public/public/emojione/128/1f445.png b/twake/frontend/public/public/emojione/128/1f445.png new file mode 100644 index 00000000..495bbe83 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f445.png differ diff --git a/twake/frontend/public/public/emojione/128/1f446-1f3fb.png b/twake/frontend/public/public/emojione/128/1f446-1f3fb.png new file mode 100644 index 00000000..3502c126 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f446-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f446-1f3fc.png b/twake/frontend/public/public/emojione/128/1f446-1f3fc.png new file mode 100644 index 00000000..c6c79595 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f446-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f446-1f3fd.png b/twake/frontend/public/public/emojione/128/1f446-1f3fd.png new file mode 100644 index 00000000..ebd89940 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f446-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f446-1f3fe.png b/twake/frontend/public/public/emojione/128/1f446-1f3fe.png new file mode 100644 index 00000000..39b13a41 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f446-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f446-1f3ff.png b/twake/frontend/public/public/emojione/128/1f446-1f3ff.png new file mode 100644 index 00000000..65f64e23 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f446-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f446.png b/twake/frontend/public/public/emojione/128/1f446.png new file mode 100644 index 00000000..cb9741bd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f446.png differ diff --git a/twake/frontend/public/public/emojione/128/1f447-1f3fb.png b/twake/frontend/public/public/emojione/128/1f447-1f3fb.png new file mode 100644 index 00000000..a529fcb2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f447-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f447-1f3fc.png b/twake/frontend/public/public/emojione/128/1f447-1f3fc.png new file mode 100644 index 00000000..cfeb3f2e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f447-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f447-1f3fd.png b/twake/frontend/public/public/emojione/128/1f447-1f3fd.png new file mode 100644 index 00000000..cd8d632b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f447-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f447-1f3fe.png b/twake/frontend/public/public/emojione/128/1f447-1f3fe.png new file mode 100644 index 00000000..482979f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f447-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f447-1f3ff.png b/twake/frontend/public/public/emojione/128/1f447-1f3ff.png new file mode 100644 index 00000000..40ef67b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f447-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f447.png b/twake/frontend/public/public/emojione/128/1f447.png new file mode 100644 index 00000000..0a86307c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f447.png differ diff --git a/twake/frontend/public/public/emojione/128/1f448-1f3fb.png b/twake/frontend/public/public/emojione/128/1f448-1f3fb.png new file mode 100644 index 00000000..f704b2f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f448-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f448-1f3fc.png b/twake/frontend/public/public/emojione/128/1f448-1f3fc.png new file mode 100644 index 00000000..936166b4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f448-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f448-1f3fd.png b/twake/frontend/public/public/emojione/128/1f448-1f3fd.png new file mode 100644 index 00000000..6be4364a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f448-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f448-1f3fe.png b/twake/frontend/public/public/emojione/128/1f448-1f3fe.png new file mode 100644 index 00000000..33bd6107 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f448-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f448-1f3ff.png b/twake/frontend/public/public/emojione/128/1f448-1f3ff.png new file mode 100644 index 00000000..dac75e46 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f448-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f448.png b/twake/frontend/public/public/emojione/128/1f448.png new file mode 100644 index 00000000..67091a17 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f448.png differ diff --git a/twake/frontend/public/public/emojione/128/1f449-1f3fb.png b/twake/frontend/public/public/emojione/128/1f449-1f3fb.png new file mode 100644 index 00000000..549b324e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f449-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f449-1f3fc.png b/twake/frontend/public/public/emojione/128/1f449-1f3fc.png new file mode 100644 index 00000000..15c5064f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f449-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f449-1f3fd.png b/twake/frontend/public/public/emojione/128/1f449-1f3fd.png new file mode 100644 index 00000000..32aeed2a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f449-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f449-1f3fe.png b/twake/frontend/public/public/emojione/128/1f449-1f3fe.png new file mode 100644 index 00000000..03f532da Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f449-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f449-1f3ff.png b/twake/frontend/public/public/emojione/128/1f449-1f3ff.png new file mode 100644 index 00000000..f87c2c07 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f449-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f449.png b/twake/frontend/public/public/emojione/128/1f449.png new file mode 100644 index 00000000..52809d45 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f449.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44a-1f3fb.png b/twake/frontend/public/public/emojione/128/1f44a-1f3fb.png new file mode 100644 index 00000000..4e5c30c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44a-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44a-1f3fc.png b/twake/frontend/public/public/emojione/128/1f44a-1f3fc.png new file mode 100644 index 00000000..d5824e3c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44a-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44a-1f3fd.png b/twake/frontend/public/public/emojione/128/1f44a-1f3fd.png new file mode 100644 index 00000000..f00c4017 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44a-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44a-1f3fe.png b/twake/frontend/public/public/emojione/128/1f44a-1f3fe.png new file mode 100644 index 00000000..34b25ad7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44a-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44a-1f3ff.png b/twake/frontend/public/public/emojione/128/1f44a-1f3ff.png new file mode 100644 index 00000000..5a496e73 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44a-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44a.png b/twake/frontend/public/public/emojione/128/1f44a.png new file mode 100644 index 00000000..506143d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44b-1f3fb.png b/twake/frontend/public/public/emojione/128/1f44b-1f3fb.png new file mode 100644 index 00000000..262a3e78 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44b-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44b-1f3fc.png b/twake/frontend/public/public/emojione/128/1f44b-1f3fc.png new file mode 100644 index 00000000..ec5300a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44b-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44b-1f3fd.png b/twake/frontend/public/public/emojione/128/1f44b-1f3fd.png new file mode 100644 index 00000000..fd67bfba Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44b-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44b-1f3fe.png b/twake/frontend/public/public/emojione/128/1f44b-1f3fe.png new file mode 100644 index 00000000..b90f9965 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44b-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44b-1f3ff.png b/twake/frontend/public/public/emojione/128/1f44b-1f3ff.png new file mode 100644 index 00000000..7fbb795a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44b-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44b.png b/twake/frontend/public/public/emojione/128/1f44b.png new file mode 100644 index 00000000..bc3fd40e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44c-1f3fb.png b/twake/frontend/public/public/emojione/128/1f44c-1f3fb.png new file mode 100644 index 00000000..ee480e95 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44c-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44c-1f3fc.png b/twake/frontend/public/public/emojione/128/1f44c-1f3fc.png new file mode 100644 index 00000000..46682c97 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44c-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44c-1f3fd.png b/twake/frontend/public/public/emojione/128/1f44c-1f3fd.png new file mode 100644 index 00000000..59f9e9ac Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44c-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44c-1f3fe.png b/twake/frontend/public/public/emojione/128/1f44c-1f3fe.png new file mode 100644 index 00000000..94cb7a74 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44c-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44c-1f3ff.png b/twake/frontend/public/public/emojione/128/1f44c-1f3ff.png new file mode 100644 index 00000000..f350a09c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44c-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44c.png b/twake/frontend/public/public/emojione/128/1f44c.png new file mode 100644 index 00000000..3f1ba797 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44d-1f3fb.png b/twake/frontend/public/public/emojione/128/1f44d-1f3fb.png new file mode 100644 index 00000000..7162fc44 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44d-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44d-1f3fc.png b/twake/frontend/public/public/emojione/128/1f44d-1f3fc.png new file mode 100644 index 00000000..949e1e53 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44d-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44d-1f3fd.png b/twake/frontend/public/public/emojione/128/1f44d-1f3fd.png new file mode 100644 index 00000000..d824b1e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44d-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44d-1f3fe.png b/twake/frontend/public/public/emojione/128/1f44d-1f3fe.png new file mode 100644 index 00000000..b5844a0d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44d-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44d-1f3ff.png b/twake/frontend/public/public/emojione/128/1f44d-1f3ff.png new file mode 100644 index 00000000..20702dd2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44d-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44d.png b/twake/frontend/public/public/emojione/128/1f44d.png new file mode 100644 index 00000000..08e73280 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44e-1f3fb.png b/twake/frontend/public/public/emojione/128/1f44e-1f3fb.png new file mode 100644 index 00000000..7624cf69 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44e-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44e-1f3fc.png b/twake/frontend/public/public/emojione/128/1f44e-1f3fc.png new file mode 100644 index 00000000..110f8926 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44e-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44e-1f3fd.png b/twake/frontend/public/public/emojione/128/1f44e-1f3fd.png new file mode 100644 index 00000000..43c07b43 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44e-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44e-1f3fe.png b/twake/frontend/public/public/emojione/128/1f44e-1f3fe.png new file mode 100644 index 00000000..9e2a091f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44e-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44e-1f3ff.png b/twake/frontend/public/public/emojione/128/1f44e-1f3ff.png new file mode 100644 index 00000000..92cbe57c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44e-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44e.png b/twake/frontend/public/public/emojione/128/1f44e.png new file mode 100644 index 00000000..8da5de57 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44f-1f3fb.png b/twake/frontend/public/public/emojione/128/1f44f-1f3fb.png new file mode 100644 index 00000000..60183f5d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44f-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44f-1f3fc.png b/twake/frontend/public/public/emojione/128/1f44f-1f3fc.png new file mode 100644 index 00000000..83ea5b4c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44f-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44f-1f3fd.png b/twake/frontend/public/public/emojione/128/1f44f-1f3fd.png new file mode 100644 index 00000000..7b1b76a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44f-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44f-1f3fe.png b/twake/frontend/public/public/emojione/128/1f44f-1f3fe.png new file mode 100644 index 00000000..414d3189 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44f-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44f-1f3ff.png b/twake/frontend/public/public/emojione/128/1f44f-1f3ff.png new file mode 100644 index 00000000..a1028b25 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44f-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f44f.png b/twake/frontend/public/public/emojione/128/1f44f.png new file mode 100644 index 00000000..c5166952 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f44f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f450-1f3fb.png b/twake/frontend/public/public/emojione/128/1f450-1f3fb.png new file mode 100644 index 00000000..ccd201d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f450-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f450-1f3fc.png b/twake/frontend/public/public/emojione/128/1f450-1f3fc.png new file mode 100644 index 00000000..62a1018a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f450-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f450-1f3fd.png b/twake/frontend/public/public/emojione/128/1f450-1f3fd.png new file mode 100644 index 00000000..a8dff66d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f450-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f450-1f3fe.png b/twake/frontend/public/public/emojione/128/1f450-1f3fe.png new file mode 100644 index 00000000..ad4d85af Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f450-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f450-1f3ff.png b/twake/frontend/public/public/emojione/128/1f450-1f3ff.png new file mode 100644 index 00000000..73c92bef Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f450-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f450.png b/twake/frontend/public/public/emojione/128/1f450.png new file mode 100644 index 00000000..607f9a17 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f450.png differ diff --git a/twake/frontend/public/public/emojione/128/1f451.png b/twake/frontend/public/public/emojione/128/1f451.png new file mode 100644 index 00000000..e0c4115f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f451.png differ diff --git a/twake/frontend/public/public/emojione/128/1f452.png b/twake/frontend/public/public/emojione/128/1f452.png new file mode 100644 index 00000000..db3daeaf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f452.png differ diff --git a/twake/frontend/public/public/emojione/128/1f453.png b/twake/frontend/public/public/emojione/128/1f453.png new file mode 100644 index 00000000..50aeab91 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f453.png differ diff --git a/twake/frontend/public/public/emojione/128/1f454.png b/twake/frontend/public/public/emojione/128/1f454.png new file mode 100644 index 00000000..1003d1fa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f454.png differ diff --git a/twake/frontend/public/public/emojione/128/1f455.png b/twake/frontend/public/public/emojione/128/1f455.png new file mode 100644 index 00000000..ab3ac9c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f455.png differ diff --git a/twake/frontend/public/public/emojione/128/1f456.png b/twake/frontend/public/public/emojione/128/1f456.png new file mode 100644 index 00000000..5c3f44f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f456.png differ diff --git a/twake/frontend/public/public/emojione/128/1f457.png b/twake/frontend/public/public/emojione/128/1f457.png new file mode 100644 index 00000000..3ce8c6eb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f457.png differ diff --git a/twake/frontend/public/public/emojione/128/1f458.png b/twake/frontend/public/public/emojione/128/1f458.png new file mode 100644 index 00000000..d9393675 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f458.png differ diff --git a/twake/frontend/public/public/emojione/128/1f459.png b/twake/frontend/public/public/emojione/128/1f459.png new file mode 100644 index 00000000..0a5d2f4a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f459.png differ diff --git a/twake/frontend/public/public/emojione/128/1f45a.png b/twake/frontend/public/public/emojione/128/1f45a.png new file mode 100644 index 00000000..d08ac3c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f45a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f45b.png b/twake/frontend/public/public/emojione/128/1f45b.png new file mode 100644 index 00000000..1320b5b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f45b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f45c.png b/twake/frontend/public/public/emojione/128/1f45c.png new file mode 100644 index 00000000..081c6f9d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f45c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f45d.png b/twake/frontend/public/public/emojione/128/1f45d.png new file mode 100644 index 00000000..91496a04 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f45d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f45e.png b/twake/frontend/public/public/emojione/128/1f45e.png new file mode 100644 index 00000000..1d3a3878 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f45e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f45f.png b/twake/frontend/public/public/emojione/128/1f45f.png new file mode 100644 index 00000000..ef0d054e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f45f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f460.png b/twake/frontend/public/public/emojione/128/1f460.png new file mode 100644 index 00000000..d5982a91 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f460.png differ diff --git a/twake/frontend/public/public/emojione/128/1f461.png b/twake/frontend/public/public/emojione/128/1f461.png new file mode 100644 index 00000000..8d269d1c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f461.png differ diff --git a/twake/frontend/public/public/emojione/128/1f462.png b/twake/frontend/public/public/emojione/128/1f462.png new file mode 100644 index 00000000..55e8c63a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f462.png differ diff --git a/twake/frontend/public/public/emojione/128/1f463.png b/twake/frontend/public/public/emojione/128/1f463.png new file mode 100644 index 00000000..53736aec Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f463.png differ diff --git a/twake/frontend/public/public/emojione/128/1f464.png b/twake/frontend/public/public/emojione/128/1f464.png new file mode 100644 index 00000000..46469ab9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f464.png differ diff --git a/twake/frontend/public/public/emojione/128/1f465.png b/twake/frontend/public/public/emojione/128/1f465.png new file mode 100644 index 00000000..3526b737 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f465.png differ diff --git a/twake/frontend/public/public/emojione/128/1f466-1f3fb.png b/twake/frontend/public/public/emojione/128/1f466-1f3fb.png new file mode 100644 index 00000000..4ae1066e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f466-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f466-1f3fc.png b/twake/frontend/public/public/emojione/128/1f466-1f3fc.png new file mode 100644 index 00000000..16ff71b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f466-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f466-1f3fd.png b/twake/frontend/public/public/emojione/128/1f466-1f3fd.png new file mode 100644 index 00000000..dfe2ea91 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f466-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f466-1f3fe.png b/twake/frontend/public/public/emojione/128/1f466-1f3fe.png new file mode 100644 index 00000000..daaf204b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f466-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f466-1f3ff.png b/twake/frontend/public/public/emojione/128/1f466-1f3ff.png new file mode 100644 index 00000000..70ed849e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f466-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f466.png b/twake/frontend/public/public/emojione/128/1f466.png new file mode 100644 index 00000000..3a0e17cb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f466.png differ diff --git a/twake/frontend/public/public/emojione/128/1f467-1f3fb.png b/twake/frontend/public/public/emojione/128/1f467-1f3fb.png new file mode 100644 index 00000000..15fd14d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f467-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f467-1f3fc.png b/twake/frontend/public/public/emojione/128/1f467-1f3fc.png new file mode 100644 index 00000000..164105fd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f467-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f467-1f3fd.png b/twake/frontend/public/public/emojione/128/1f467-1f3fd.png new file mode 100644 index 00000000..7825d010 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f467-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f467-1f3fe.png b/twake/frontend/public/public/emojione/128/1f467-1f3fe.png new file mode 100644 index 00000000..9219d242 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f467-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f467-1f3ff.png b/twake/frontend/public/public/emojione/128/1f467-1f3ff.png new file mode 100644 index 00000000..5ad29820 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f467-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f467.png b/twake/frontend/public/public/emojione/128/1f467.png new file mode 100644 index 00000000..275909dd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f467.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f33e.png b/twake/frontend/public/public/emojione/128/1f468-1f33e.png new file mode 100644 index 00000000..704c2c97 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f373.png b/twake/frontend/public/public/emojione/128/1f468-1f373.png new file mode 100644 index 00000000..8c33fbfa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f373.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f393.png b/twake/frontend/public/public/emojione/128/1f468-1f393.png new file mode 100644 index 00000000..0318b1dc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f393.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3a4.png b/twake/frontend/public/public/emojione/128/1f468-1f3a4.png new file mode 100644 index 00000000..afd9f9b9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3a8.png b/twake/frontend/public/public/emojione/128/1f468-1f3a8.png new file mode 100644 index 00000000..fd69f18a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3eb.png b/twake/frontend/public/public/emojione/128/1f468-1f3eb.png new file mode 100644 index 00000000..8f80b20a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ed.png b/twake/frontend/public/public/emojione/128/1f468-1f3ed.png new file mode 100644 index 00000000..42ac4a82 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f33e.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f33e.png new file mode 100644 index 00000000..e5367c98 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f373.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f373.png new file mode 100644 index 00000000..267565d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f373.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f393.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f393.png new file mode 100644 index 00000000..7d77fc4b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f393.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f3a4.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f3a4.png new file mode 100644 index 00000000..1a8a1345 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f3a8.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f3a8.png new file mode 100644 index 00000000..271560d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f3eb.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f3eb.png new file mode 100644 index 00000000..be6cc779 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f3ed.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f3ed.png new file mode 100644 index 00000000..f3276394 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f4bb.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f4bb.png new file mode 100644 index 00000000..8fb3ecce Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f4bc.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f4bc.png new file mode 100644 index 00000000..f3ab6b9c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f527.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f527.png new file mode 100644 index 00000000..fd41b380 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f527.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f52c.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f52c.png new file mode 100644 index 00000000..8aac8a23 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f680.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f680.png new file mode 100644 index 00000000..1d760383 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f680.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f692.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f692.png new file mode 100644 index 00000000..e2edc770 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f692.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f9b0.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f9b0.png new file mode 100644 index 00000000..9df9597a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f9b1.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f9b1.png new file mode 100644 index 00000000..848b9f79 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f9b2.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f9b2.png new file mode 100644 index 00000000..1c77ffe4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f9b3.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f9b3.png new file mode 100644 index 00000000..7356729e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-2695.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-2695.png new file mode 100644 index 00000000..01e949da Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-2695.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-2696.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-2696.png new file mode 100644 index 00000000..ea4d3b5b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-2696.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb-2708.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb-2708.png new file mode 100644 index 00000000..a0df845c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb-2708.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fb.png b/twake/frontend/public/public/emojione/128/1f468-1f3fb.png new file mode 100644 index 00000000..d58c16b6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f33e.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f33e.png new file mode 100644 index 00000000..f4f6fe24 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f373.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f373.png new file mode 100644 index 00000000..da055cd1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f373.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f393.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f393.png new file mode 100644 index 00000000..e5b1b77b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f393.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f3a4.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f3a4.png new file mode 100644 index 00000000..b8a4082e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f3a8.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f3a8.png new file mode 100644 index 00000000..022c259f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f3eb.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f3eb.png new file mode 100644 index 00000000..06a1b470 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f3ed.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f3ed.png new file mode 100644 index 00000000..4e9d6774 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f4bb.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f4bb.png new file mode 100644 index 00000000..6563e770 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f4bc.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f4bc.png new file mode 100644 index 00000000..be28bfe2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f527.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f527.png new file mode 100644 index 00000000..4c6e4626 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f527.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f52c.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f52c.png new file mode 100644 index 00000000..3a4a7644 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f680.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f680.png new file mode 100644 index 00000000..acd35c0a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f680.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f692.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f692.png new file mode 100644 index 00000000..4542d11e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f692.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f9b0.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f9b0.png new file mode 100644 index 00000000..9da25de5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f9b1.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f9b1.png new file mode 100644 index 00000000..1f2b56f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f9b2.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f9b2.png new file mode 100644 index 00000000..4358a70b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f9b3.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f9b3.png new file mode 100644 index 00000000..cc8047c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-2695.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-2695.png new file mode 100644 index 00000000..3421fe61 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-2695.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-2696.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-2696.png new file mode 100644 index 00000000..1d72ee8f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-2696.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc-2708.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc-2708.png new file mode 100644 index 00000000..4c4bba76 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc-2708.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fc.png b/twake/frontend/public/public/emojione/128/1f468-1f3fc.png new file mode 100644 index 00000000..04f598c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f33e.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f33e.png new file mode 100644 index 00000000..caa76e0b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f373.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f373.png new file mode 100644 index 00000000..1e059ab4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f373.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f393.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f393.png new file mode 100644 index 00000000..fc4a9dcd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f393.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f3a4.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f3a4.png new file mode 100644 index 00000000..bfee14d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f3a8.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f3a8.png new file mode 100644 index 00000000..78b0bb18 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f3eb.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f3eb.png new file mode 100644 index 00000000..50eacd21 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f3ed.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f3ed.png new file mode 100644 index 00000000..01cf732b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f4bb.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f4bb.png new file mode 100644 index 00000000..203db214 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f4bc.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f4bc.png new file mode 100644 index 00000000..56975281 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f527.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f527.png new file mode 100644 index 00000000..5b2ab3ee Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f527.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f52c.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f52c.png new file mode 100644 index 00000000..7bd71741 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f680.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f680.png new file mode 100644 index 00000000..52e43856 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f680.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f692.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f692.png new file mode 100644 index 00000000..b8e8e684 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f692.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f9b0.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f9b0.png new file mode 100644 index 00000000..aa1b38c4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f9b1.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f9b1.png new file mode 100644 index 00000000..a04b20d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f9b2.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f9b2.png new file mode 100644 index 00000000..ebd39ef9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f9b3.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f9b3.png new file mode 100644 index 00000000..33ac0c8e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-2695.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-2695.png new file mode 100644 index 00000000..6fca507b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-2695.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-2696.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-2696.png new file mode 100644 index 00000000..18fda7a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-2696.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd-2708.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd-2708.png new file mode 100644 index 00000000..51935350 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd-2708.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fd.png b/twake/frontend/public/public/emojione/128/1f468-1f3fd.png new file mode 100644 index 00000000..b483dff2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f33e.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f33e.png new file mode 100644 index 00000000..a7c8ec9c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f373.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f373.png new file mode 100644 index 00000000..4725c4b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f373.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f393.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f393.png new file mode 100644 index 00000000..72ef08e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f393.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f3a4.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f3a4.png new file mode 100644 index 00000000..d970756c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f3a8.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f3a8.png new file mode 100644 index 00000000..2d935be1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f3eb.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f3eb.png new file mode 100644 index 00000000..82f5559d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f3ed.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f3ed.png new file mode 100644 index 00000000..e4a6fe51 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f4bb.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f4bb.png new file mode 100644 index 00000000..d1ceef5b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f4bc.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f4bc.png new file mode 100644 index 00000000..65cc7411 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f527.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f527.png new file mode 100644 index 00000000..85208b34 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f527.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f52c.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f52c.png new file mode 100644 index 00000000..b2b2ce87 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f680.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f680.png new file mode 100644 index 00000000..27d742c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f680.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f692.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f692.png new file mode 100644 index 00000000..db3b2bbb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f692.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f9b0.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f9b0.png new file mode 100644 index 00000000..fb705c60 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f9b1.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f9b1.png new file mode 100644 index 00000000..942034b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f9b2.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f9b2.png new file mode 100644 index 00000000..a60d9303 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f9b3.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f9b3.png new file mode 100644 index 00000000..d6359ba1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-2695.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-2695.png new file mode 100644 index 00000000..cacce123 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-2695.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-2696.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-2696.png new file mode 100644 index 00000000..dbe749db Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-2696.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe-2708.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe-2708.png new file mode 100644 index 00000000..0abd1228 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe-2708.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3fe.png b/twake/frontend/public/public/emojione/128/1f468-1f3fe.png new file mode 100644 index 00000000..da4edf82 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f33e.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f33e.png new file mode 100644 index 00000000..dcd12020 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f373.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f373.png new file mode 100644 index 00000000..b24f5be2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f373.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f393.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f393.png new file mode 100644 index 00000000..b14d3a98 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f393.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f3a4.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f3a4.png new file mode 100644 index 00000000..132d4f0f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f3a8.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f3a8.png new file mode 100644 index 00000000..e64623ab Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f3eb.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f3eb.png new file mode 100644 index 00000000..d6d3c944 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f3ed.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f3ed.png new file mode 100644 index 00000000..3ebc574f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f4bb.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f4bb.png new file mode 100644 index 00000000..22b26817 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f4bc.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f4bc.png new file mode 100644 index 00000000..6b6bd14d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f527.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f527.png new file mode 100644 index 00000000..92a0f0fa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f527.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f52c.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f52c.png new file mode 100644 index 00000000..035fba71 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f680.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f680.png new file mode 100644 index 00000000..a2f8811c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f680.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f692.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f692.png new file mode 100644 index 00000000..76c4b963 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f692.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f9b0.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f9b0.png new file mode 100644 index 00000000..0a666a5b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f9b1.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f9b1.png new file mode 100644 index 00000000..4e27d83a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f9b2.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f9b2.png new file mode 100644 index 00000000..87fec90e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f9b3.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f9b3.png new file mode 100644 index 00000000..87e3a419 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-2695.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-2695.png new file mode 100644 index 00000000..1679296d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-2695.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-2696.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-2696.png new file mode 100644 index 00000000..dd139b52 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-2696.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff-2708.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff-2708.png new file mode 100644 index 00000000..69dd64be Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff-2708.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f3ff.png b/twake/frontend/public/public/emojione/128/1f468-1f3ff.png new file mode 100644 index 00000000..611060e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f466-1f466.png b/twake/frontend/public/public/emojione/128/1f468-1f466-1f466.png new file mode 100644 index 00000000..42c15831 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f466-1f466.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f466.png b/twake/frontend/public/public/emojione/128/1f468-1f466.png new file mode 100644 index 00000000..a9ab23b7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f466.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f467-1f466.png b/twake/frontend/public/public/emojione/128/1f468-1f467-1f466.png new file mode 100644 index 00000000..72616dae Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f467-1f466.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f467-1f467.png b/twake/frontend/public/public/emojione/128/1f468-1f467-1f467.png new file mode 100644 index 00000000..480a1ee7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f467-1f467.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f467.png b/twake/frontend/public/public/emojione/128/1f468-1f467.png new file mode 100644 index 00000000..5a028b71 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f467.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f468-1f466-1f466.png b/twake/frontend/public/public/emojione/128/1f468-1f468-1f466-1f466.png new file mode 100644 index 00000000..c17c7c08 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f468-1f466-1f466.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f468-1f466.png b/twake/frontend/public/public/emojione/128/1f468-1f468-1f466.png new file mode 100644 index 00000000..ab6066eb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f468-1f466.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f468-1f467-1f466.png b/twake/frontend/public/public/emojione/128/1f468-1f468-1f467-1f466.png new file mode 100644 index 00000000..ab560f3a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f468-1f467-1f466.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f468-1f467-1f467.png b/twake/frontend/public/public/emojione/128/1f468-1f468-1f467-1f467.png new file mode 100644 index 00000000..d4a52d01 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f468-1f467-1f467.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f468-1f467.png b/twake/frontend/public/public/emojione/128/1f468-1f468-1f467.png new file mode 100644 index 00000000..e82cde30 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f468-1f467.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f469-1f466-1f466.png b/twake/frontend/public/public/emojione/128/1f468-1f469-1f466-1f466.png new file mode 100644 index 00000000..a4a8549f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f469-1f466-1f466.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f469-1f466.png b/twake/frontend/public/public/emojione/128/1f468-1f469-1f466.png new file mode 100644 index 00000000..2bb531bd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f469-1f466.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f469-1f467-1f466.png b/twake/frontend/public/public/emojione/128/1f468-1f469-1f467-1f466.png new file mode 100644 index 00000000..2fc4e63b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f469-1f467-1f466.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f469-1f467-1f467.png b/twake/frontend/public/public/emojione/128/1f468-1f469-1f467-1f467.png new file mode 100644 index 00000000..15a790a2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f469-1f467-1f467.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f469-1f467.png b/twake/frontend/public/public/emojione/128/1f468-1f469-1f467.png new file mode 100644 index 00000000..393dcce3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f469-1f467.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f4bb.png b/twake/frontend/public/public/emojione/128/1f468-1f4bb.png new file mode 100644 index 00000000..3397fa5e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f4bc.png b/twake/frontend/public/public/emojione/128/1f468-1f4bc.png new file mode 100644 index 00000000..837a4d6e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f527.png b/twake/frontend/public/public/emojione/128/1f468-1f527.png new file mode 100644 index 00000000..da906b84 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f527.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f52c.png b/twake/frontend/public/public/emojione/128/1f468-1f52c.png new file mode 100644 index 00000000..0bbb6b18 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f680.png b/twake/frontend/public/public/emojione/128/1f468-1f680.png new file mode 100644 index 00000000..4b8a9d01 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f680.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f692.png b/twake/frontend/public/public/emojione/128/1f468-1f692.png new file mode 100644 index 00000000..cd32a55c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f692.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f9b0.png b/twake/frontend/public/public/emojione/128/1f468-1f9b0.png new file mode 100644 index 00000000..b195c57c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f9b1.png b/twake/frontend/public/public/emojione/128/1f468-1f9b1.png new file mode 100644 index 00000000..d59535bc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f9b2.png b/twake/frontend/public/public/emojione/128/1f468-1f9b2.png new file mode 100644 index 00000000..3b3863bf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-1f9b3.png b/twake/frontend/public/public/emojione/128/1f468-1f9b3.png new file mode 100644 index 00000000..41377ee7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-2695.png b/twake/frontend/public/public/emojione/128/1f468-2695.png new file mode 100644 index 00000000..7984c374 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-2695.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-2696.png b/twake/frontend/public/public/emojione/128/1f468-2696.png new file mode 100644 index 00000000..1c6d81fc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-2696.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-2708.png b/twake/frontend/public/public/emojione/128/1f468-2708.png new file mode 100644 index 00000000..3bb938e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-2708.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-2764-1f468.png b/twake/frontend/public/public/emojione/128/1f468-2764-1f468.png new file mode 100644 index 00000000..1935a692 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-2764-1f468.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468-2764-1f48b-1f468.png b/twake/frontend/public/public/emojione/128/1f468-2764-1f48b-1f468.png new file mode 100644 index 00000000..1338e1b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468-2764-1f48b-1f468.png differ diff --git a/twake/frontend/public/public/emojione/128/1f468.png b/twake/frontend/public/public/emojione/128/1f468.png new file mode 100644 index 00000000..f8cc7828 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f468.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f33e.png b/twake/frontend/public/public/emojione/128/1f469-1f33e.png new file mode 100644 index 00000000..42eb9195 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f373.png b/twake/frontend/public/public/emojione/128/1f469-1f373.png new file mode 100644 index 00000000..68935d0c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f373.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f393.png b/twake/frontend/public/public/emojione/128/1f469-1f393.png new file mode 100644 index 00000000..3ca563af Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f393.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3a4.png b/twake/frontend/public/public/emojione/128/1f469-1f3a4.png new file mode 100644 index 00000000..aac4e69f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3a8.png b/twake/frontend/public/public/emojione/128/1f469-1f3a8.png new file mode 100644 index 00000000..2bee4154 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3eb.png b/twake/frontend/public/public/emojione/128/1f469-1f3eb.png new file mode 100644 index 00000000..7ac3f47d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ed.png b/twake/frontend/public/public/emojione/128/1f469-1f3ed.png new file mode 100644 index 00000000..0266a83d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f33e.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f33e.png new file mode 100644 index 00000000..17c633af Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f373.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f373.png new file mode 100644 index 00000000..04e3758f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f373.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f393.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f393.png new file mode 100644 index 00000000..a514055b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f393.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f3a4.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f3a4.png new file mode 100644 index 00000000..2bfa7b18 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f3a8.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f3a8.png new file mode 100644 index 00000000..b7aa7443 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f3eb.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f3eb.png new file mode 100644 index 00000000..6b5c1e07 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f3ed.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f3ed.png new file mode 100644 index 00000000..6d2e6555 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f4bb.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f4bb.png new file mode 100644 index 00000000..2632488e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f4bc.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f4bc.png new file mode 100644 index 00000000..fc924af3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f527.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f527.png new file mode 100644 index 00000000..b5c74398 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f527.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f52c.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f52c.png new file mode 100644 index 00000000..1b9f2baf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f680.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f680.png new file mode 100644 index 00000000..4c1b5d56 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f680.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f692.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f692.png new file mode 100644 index 00000000..e8d76ee2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f692.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f9b0.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f9b0.png new file mode 100644 index 00000000..6ecf5b06 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f9b1.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f9b1.png new file mode 100644 index 00000000..b2a70c1e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f9b2.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f9b2.png new file mode 100644 index 00000000..f1f3e943 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f9b3.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f9b3.png new file mode 100644 index 00000000..f65e4673 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-2695.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-2695.png new file mode 100644 index 00000000..e22a23ce Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-2695.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-2696.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-2696.png new file mode 100644 index 00000000..4fa97aae Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-2696.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb-2708.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb-2708.png new file mode 100644 index 00000000..43bda9f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb-2708.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fb.png b/twake/frontend/public/public/emojione/128/1f469-1f3fb.png new file mode 100644 index 00000000..16f97e9a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f33e.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f33e.png new file mode 100644 index 00000000..eba920b9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f373.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f373.png new file mode 100644 index 00000000..6d41e297 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f373.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f393.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f393.png new file mode 100644 index 00000000..83bd811f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f393.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f3a4.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f3a4.png new file mode 100644 index 00000000..ba16ec81 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f3a8.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f3a8.png new file mode 100644 index 00000000..64bb2a74 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f3eb.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f3eb.png new file mode 100644 index 00000000..d494e6b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f3ed.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f3ed.png new file mode 100644 index 00000000..d5e9558c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f4bb.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f4bb.png new file mode 100644 index 00000000..8fb082b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f4bc.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f4bc.png new file mode 100644 index 00000000..febc35a6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f527.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f527.png new file mode 100644 index 00000000..4fd5cfce Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f527.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f52c.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f52c.png new file mode 100644 index 00000000..290f31ac Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f680.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f680.png new file mode 100644 index 00000000..253ee95f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f680.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f692.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f692.png new file mode 100644 index 00000000..886bc8c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f692.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f9b0.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f9b0.png new file mode 100644 index 00000000..d6bb57d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f9b1.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f9b1.png new file mode 100644 index 00000000..454f2be9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f9b2.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f9b2.png new file mode 100644 index 00000000..04d4d792 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f9b3.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f9b3.png new file mode 100644 index 00000000..bc3843c4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-2695.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-2695.png new file mode 100644 index 00000000..1986ba28 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-2695.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-2696.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-2696.png new file mode 100644 index 00000000..008a51b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-2696.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc-2708.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc-2708.png new file mode 100644 index 00000000..82dabd95 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc-2708.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fc.png b/twake/frontend/public/public/emojione/128/1f469-1f3fc.png new file mode 100644 index 00000000..db3dddca Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f33e.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f33e.png new file mode 100644 index 00000000..c652c7d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f373.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f373.png new file mode 100644 index 00000000..d325b1ef Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f373.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f393.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f393.png new file mode 100644 index 00000000..85f8d18a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f393.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f3a4.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f3a4.png new file mode 100644 index 00000000..6d161e6e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f3a8.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f3a8.png new file mode 100644 index 00000000..31704ce5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f3eb.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f3eb.png new file mode 100644 index 00000000..13a85cf9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f3ed.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f3ed.png new file mode 100644 index 00000000..e2e75f38 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f4bb.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f4bb.png new file mode 100644 index 00000000..ed51e1c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f4bc.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f4bc.png new file mode 100644 index 00000000..69106e3a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f527.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f527.png new file mode 100644 index 00000000..c8fd3825 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f527.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f52c.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f52c.png new file mode 100644 index 00000000..9276ec31 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f680.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f680.png new file mode 100644 index 00000000..f138c11a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f680.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f692.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f692.png new file mode 100644 index 00000000..448526d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f692.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f9b0.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f9b0.png new file mode 100644 index 00000000..026f760d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f9b1.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f9b1.png new file mode 100644 index 00000000..864045b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f9b2.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f9b2.png new file mode 100644 index 00000000..04fa0636 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f9b3.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f9b3.png new file mode 100644 index 00000000..f75994c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-2695.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-2695.png new file mode 100644 index 00000000..447ec6e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-2695.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-2696.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-2696.png new file mode 100644 index 00000000..fe7553ac Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-2696.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd-2708.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd-2708.png new file mode 100644 index 00000000..aeb646d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd-2708.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fd.png b/twake/frontend/public/public/emojione/128/1f469-1f3fd.png new file mode 100644 index 00000000..82d72d30 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f33e.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f33e.png new file mode 100644 index 00000000..a1a1c34b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f373.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f373.png new file mode 100644 index 00000000..a2b2fa42 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f373.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f393.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f393.png new file mode 100644 index 00000000..7a2dfb1d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f393.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f3a4.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f3a4.png new file mode 100644 index 00000000..082d425e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f3a8.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f3a8.png new file mode 100644 index 00000000..93983cba Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f3eb.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f3eb.png new file mode 100644 index 00000000..4ac43736 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f3ed.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f3ed.png new file mode 100644 index 00000000..8930f496 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f4bb.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f4bb.png new file mode 100644 index 00000000..5feab4dc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f4bc.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f4bc.png new file mode 100644 index 00000000..841eb8fb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f527.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f527.png new file mode 100644 index 00000000..d37382d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f527.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f52c.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f52c.png new file mode 100644 index 00000000..5782e390 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f680.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f680.png new file mode 100644 index 00000000..75d0451f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f680.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f692.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f692.png new file mode 100644 index 00000000..36a96f6b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f692.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f9b0.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f9b0.png new file mode 100644 index 00000000..7ed1adb4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f9b1.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f9b1.png new file mode 100644 index 00000000..df97aa9b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f9b2.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f9b2.png new file mode 100644 index 00000000..61d1fac4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f9b3.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f9b3.png new file mode 100644 index 00000000..e3722616 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-2695.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-2695.png new file mode 100644 index 00000000..251aaa32 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-2695.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-2696.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-2696.png new file mode 100644 index 00000000..10533d35 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-2696.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe-2708.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe-2708.png new file mode 100644 index 00000000..3a867c13 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe-2708.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3fe.png b/twake/frontend/public/public/emojione/128/1f469-1f3fe.png new file mode 100644 index 00000000..ce9b900b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f33e.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f33e.png new file mode 100644 index 00000000..8e1623af Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f373.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f373.png new file mode 100644 index 00000000..d0a1412a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f373.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f393.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f393.png new file mode 100644 index 00000000..75a3bf5b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f393.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f3a4.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f3a4.png new file mode 100644 index 00000000..8f39a491 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f3a8.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f3a8.png new file mode 100644 index 00000000..82c1f89a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f3eb.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f3eb.png new file mode 100644 index 00000000..08cf7d58 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f3ed.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f3ed.png new file mode 100644 index 00000000..b21bfe7c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f4bb.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f4bb.png new file mode 100644 index 00000000..327e3fb9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f4bc.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f4bc.png new file mode 100644 index 00000000..d497d88a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f527.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f527.png new file mode 100644 index 00000000..99d0198d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f527.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f52c.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f52c.png new file mode 100644 index 00000000..c2e1d856 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f680.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f680.png new file mode 100644 index 00000000..2ba12872 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f680.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f692.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f692.png new file mode 100644 index 00000000..f15cad7b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f692.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f9b0.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f9b0.png new file mode 100644 index 00000000..159d0c37 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f9b1.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f9b1.png new file mode 100644 index 00000000..06fdf9da Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f9b2.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f9b2.png new file mode 100644 index 00000000..7a2568ca Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f9b3.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f9b3.png new file mode 100644 index 00000000..e7c4dc9b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-2695.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-2695.png new file mode 100644 index 00000000..86ac6892 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-2695.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-2696.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-2696.png new file mode 100644 index 00000000..ea9685a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-2696.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff-2708.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff-2708.png new file mode 100644 index 00000000..7809cbb2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff-2708.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f3ff.png b/twake/frontend/public/public/emojione/128/1f469-1f3ff.png new file mode 100644 index 00000000..6f8ab069 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f466-1f466.png b/twake/frontend/public/public/emojione/128/1f469-1f466-1f466.png new file mode 100644 index 00000000..d65882df Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f466-1f466.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f466.png b/twake/frontend/public/public/emojione/128/1f469-1f466.png new file mode 100644 index 00000000..bf7ea5fa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f466.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f467-1f466.png b/twake/frontend/public/public/emojione/128/1f469-1f467-1f466.png new file mode 100644 index 00000000..3593afbc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f467-1f466.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f467-1f467.png b/twake/frontend/public/public/emojione/128/1f469-1f467-1f467.png new file mode 100644 index 00000000..e080b539 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f467-1f467.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f467.png b/twake/frontend/public/public/emojione/128/1f469-1f467.png new file mode 100644 index 00000000..91c7f755 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f467.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f469-1f466-1f466.png b/twake/frontend/public/public/emojione/128/1f469-1f469-1f466-1f466.png new file mode 100644 index 00000000..fca87abf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f469-1f466-1f466.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f469-1f466.png b/twake/frontend/public/public/emojione/128/1f469-1f469-1f466.png new file mode 100644 index 00000000..a3365e80 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f469-1f466.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f469-1f467-1f466.png b/twake/frontend/public/public/emojione/128/1f469-1f469-1f467-1f466.png new file mode 100644 index 00000000..9912cce9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f469-1f467-1f466.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f469-1f467-1f467.png b/twake/frontend/public/public/emojione/128/1f469-1f469-1f467-1f467.png new file mode 100644 index 00000000..3f3649c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f469-1f467-1f467.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f469-1f467.png b/twake/frontend/public/public/emojione/128/1f469-1f469-1f467.png new file mode 100644 index 00000000..cc3e3cfd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f469-1f467.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f4bb.png b/twake/frontend/public/public/emojione/128/1f469-1f4bb.png new file mode 100644 index 00000000..b39680f9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f4bc.png b/twake/frontend/public/public/emojione/128/1f469-1f4bc.png new file mode 100644 index 00000000..3739022a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f527.png b/twake/frontend/public/public/emojione/128/1f469-1f527.png new file mode 100644 index 00000000..9ba3ab64 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f527.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f52c.png b/twake/frontend/public/public/emojione/128/1f469-1f52c.png new file mode 100644 index 00000000..5c581a1e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f680.png b/twake/frontend/public/public/emojione/128/1f469-1f680.png new file mode 100644 index 00000000..96848d58 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f680.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f692.png b/twake/frontend/public/public/emojione/128/1f469-1f692.png new file mode 100644 index 00000000..f5be7053 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f692.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f9b0.png b/twake/frontend/public/public/emojione/128/1f469-1f9b0.png new file mode 100644 index 00000000..b2c44d93 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f9b1.png b/twake/frontend/public/public/emojione/128/1f469-1f9b1.png new file mode 100644 index 00000000..6c174719 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f9b2.png b/twake/frontend/public/public/emojione/128/1f469-1f9b2.png new file mode 100644 index 00000000..405f7ee8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-1f9b3.png b/twake/frontend/public/public/emojione/128/1f469-1f9b3.png new file mode 100644 index 00000000..1d224cc1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-2695.png b/twake/frontend/public/public/emojione/128/1f469-2695.png new file mode 100644 index 00000000..1dc2e96a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-2695.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-2696.png b/twake/frontend/public/public/emojione/128/1f469-2696.png new file mode 100644 index 00000000..5f7ae612 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-2696.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-2708.png b/twake/frontend/public/public/emojione/128/1f469-2708.png new file mode 100644 index 00000000..45776d30 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-2708.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-2764-1f468.png b/twake/frontend/public/public/emojione/128/1f469-2764-1f468.png new file mode 100644 index 00000000..44e3f038 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-2764-1f468.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-2764-1f469.png b/twake/frontend/public/public/emojione/128/1f469-2764-1f469.png new file mode 100644 index 00000000..61878e95 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-2764-1f469.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-2764-1f48b-1f468.png b/twake/frontend/public/public/emojione/128/1f469-2764-1f48b-1f468.png new file mode 100644 index 00000000..2b2bffd9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-2764-1f48b-1f468.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469-2764-1f48b-1f469.png b/twake/frontend/public/public/emojione/128/1f469-2764-1f48b-1f469.png new file mode 100644 index 00000000..e787ec78 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469-2764-1f48b-1f469.png differ diff --git a/twake/frontend/public/public/emojione/128/1f469.png b/twake/frontend/public/public/emojione/128/1f469.png new file mode 100644 index 00000000..0c0ccb70 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f469.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46a.png b/twake/frontend/public/public/emojione/128/1f46a.png new file mode 100644 index 00000000..2bb531bd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46b.png b/twake/frontend/public/public/emojione/128/1f46b.png new file mode 100644 index 00000000..cfb59864 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46c.png b/twake/frontend/public/public/emojione/128/1f46c.png new file mode 100644 index 00000000..a1b30b13 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46d.png b/twake/frontend/public/public/emojione/128/1f46d.png new file mode 100644 index 00000000..1cd4bc12 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f46e-1f3fb-2640.png new file mode 100644 index 00000000..ff0a121b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f46e-1f3fb-2642.png new file mode 100644 index 00000000..4a768c48 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e-1f3fb.png b/twake/frontend/public/public/emojione/128/1f46e-1f3fb.png new file mode 100644 index 00000000..4a768c48 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f46e-1f3fc-2640.png new file mode 100644 index 00000000..67691395 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f46e-1f3fc-2642.png new file mode 100644 index 00000000..fcfb5c62 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e-1f3fc.png b/twake/frontend/public/public/emojione/128/1f46e-1f3fc.png new file mode 100644 index 00000000..fcfb5c62 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f46e-1f3fd-2640.png new file mode 100644 index 00000000..1ffeaf94 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f46e-1f3fd-2642.png new file mode 100644 index 00000000..b007196a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e-1f3fd.png b/twake/frontend/public/public/emojione/128/1f46e-1f3fd.png new file mode 100644 index 00000000..b007196a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f46e-1f3fe-2640.png new file mode 100644 index 00000000..aeaebfb0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f46e-1f3fe-2642.png new file mode 100644 index 00000000..a7bf9e16 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e-1f3fe.png b/twake/frontend/public/public/emojione/128/1f46e-1f3fe.png new file mode 100644 index 00000000..a7bf9e16 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f46e-1f3ff-2640.png new file mode 100644 index 00000000..192534e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f46e-1f3ff-2642.png new file mode 100644 index 00000000..636627ea Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e-1f3ff.png b/twake/frontend/public/public/emojione/128/1f46e-1f3ff.png new file mode 100644 index 00000000..636627ea Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e-2640.png b/twake/frontend/public/public/emojione/128/1f46e-2640.png new file mode 100644 index 00000000..c5309794 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e-2642.png b/twake/frontend/public/public/emojione/128/1f46e-2642.png new file mode 100644 index 00000000..41c14ef4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46e.png b/twake/frontend/public/public/emojione/128/1f46e.png new file mode 100644 index 00000000..41c14ef4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46f-2640.png b/twake/frontend/public/public/emojione/128/1f46f-2640.png new file mode 100644 index 00000000..c347878d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46f-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46f-2642.png b/twake/frontend/public/public/emojione/128/1f46f-2642.png new file mode 100644 index 00000000..bea77b81 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46f-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f46f.png b/twake/frontend/public/public/emojione/128/1f46f.png new file mode 100644 index 00000000..cd8801d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f46f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f470-1f3fb.png b/twake/frontend/public/public/emojione/128/1f470-1f3fb.png new file mode 100644 index 00000000..8891b4c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f470-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f470-1f3fc.png b/twake/frontend/public/public/emojione/128/1f470-1f3fc.png new file mode 100644 index 00000000..c06189ae Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f470-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f470-1f3fd.png b/twake/frontend/public/public/emojione/128/1f470-1f3fd.png new file mode 100644 index 00000000..53f991a5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f470-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f470-1f3fe.png b/twake/frontend/public/public/emojione/128/1f470-1f3fe.png new file mode 100644 index 00000000..cd01aec1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f470-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f470-1f3ff.png b/twake/frontend/public/public/emojione/128/1f470-1f3ff.png new file mode 100644 index 00000000..554df4bd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f470-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f470.png b/twake/frontend/public/public/emojione/128/1f470.png new file mode 100644 index 00000000..35c8acc0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f470.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f471-1f3fb-2640.png new file mode 100644 index 00000000..b9fe22a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f471-1f3fb-2642.png new file mode 100644 index 00000000..46cdd0fa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471-1f3fb.png b/twake/frontend/public/public/emojione/128/1f471-1f3fb.png new file mode 100644 index 00000000..1caf66b4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f471-1f3fc-2640.png new file mode 100644 index 00000000..839b3c1b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f471-1f3fc-2642.png new file mode 100644 index 00000000..58e13ade Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471-1f3fc.png b/twake/frontend/public/public/emojione/128/1f471-1f3fc.png new file mode 100644 index 00000000..58e13ade Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f471-1f3fd-2640.png new file mode 100644 index 00000000..fdf88c6b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f471-1f3fd-2642.png new file mode 100644 index 00000000..bc149974 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471-1f3fd.png b/twake/frontend/public/public/emojione/128/1f471-1f3fd.png new file mode 100644 index 00000000..4f38e219 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f471-1f3fe-2640.png new file mode 100644 index 00000000..a4c5e993 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f471-1f3fe-2642.png new file mode 100644 index 00000000..6344b164 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471-1f3fe.png b/twake/frontend/public/public/emojione/128/1f471-1f3fe.png new file mode 100644 index 00000000..755653e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f471-1f3ff-2640.png new file mode 100644 index 00000000..4c8af070 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f471-1f3ff-2642.png new file mode 100644 index 00000000..ab7e14ac Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471-1f3ff.png b/twake/frontend/public/public/emojione/128/1f471-1f3ff.png new file mode 100644 index 00000000..1076317f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471-2640.png b/twake/frontend/public/public/emojione/128/1f471-2640.png new file mode 100644 index 00000000..61e2ae71 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471-2642.png b/twake/frontend/public/public/emojione/128/1f471-2642.png new file mode 100644 index 00000000..6b4aa804 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f471.png b/twake/frontend/public/public/emojione/128/1f471.png new file mode 100644 index 00000000..6b4aa804 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f471.png differ diff --git a/twake/frontend/public/public/emojione/128/1f472-1f3fb.png b/twake/frontend/public/public/emojione/128/1f472-1f3fb.png new file mode 100644 index 00000000..038da8b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f472-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f472-1f3fc.png b/twake/frontend/public/public/emojione/128/1f472-1f3fc.png new file mode 100644 index 00000000..fd9db717 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f472-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f472-1f3fd.png b/twake/frontend/public/public/emojione/128/1f472-1f3fd.png new file mode 100644 index 00000000..ea6e7ff9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f472-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f472-1f3fe.png b/twake/frontend/public/public/emojione/128/1f472-1f3fe.png new file mode 100644 index 00000000..e7067e5a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f472-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f472-1f3ff.png b/twake/frontend/public/public/emojione/128/1f472-1f3ff.png new file mode 100644 index 00000000..991a43f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f472-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f472.png b/twake/frontend/public/public/emojione/128/1f472.png new file mode 100644 index 00000000..55f2a65f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f472.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f473-1f3fb-2640.png new file mode 100644 index 00000000..b750daf2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f473-1f3fb-2642.png new file mode 100644 index 00000000..219e2f70 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473-1f3fb.png b/twake/frontend/public/public/emojione/128/1f473-1f3fb.png new file mode 100644 index 00000000..219e2f70 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f473-1f3fc-2640.png new file mode 100644 index 00000000..00542d91 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f473-1f3fc-2642.png new file mode 100644 index 00000000..efa38010 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473-1f3fc.png b/twake/frontend/public/public/emojione/128/1f473-1f3fc.png new file mode 100644 index 00000000..efa38010 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f473-1f3fd-2640.png new file mode 100644 index 00000000..42b8f728 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f473-1f3fd-2642.png new file mode 100644 index 00000000..f0215d4a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473-1f3fd.png b/twake/frontend/public/public/emojione/128/1f473-1f3fd.png new file mode 100644 index 00000000..f0215d4a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f473-1f3fe-2640.png new file mode 100644 index 00000000..3aaa5053 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f473-1f3fe-2642.png new file mode 100644 index 00000000..10b6ea05 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473-1f3fe.png b/twake/frontend/public/public/emojione/128/1f473-1f3fe.png new file mode 100644 index 00000000..10b6ea05 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f473-1f3ff-2640.png new file mode 100644 index 00000000..27a306d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f473-1f3ff-2642.png new file mode 100644 index 00000000..facbfbbc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473-1f3ff.png b/twake/frontend/public/public/emojione/128/1f473-1f3ff.png new file mode 100644 index 00000000..facbfbbc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473-2640.png b/twake/frontend/public/public/emojione/128/1f473-2640.png new file mode 100644 index 00000000..40ffd5d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473-2642.png b/twake/frontend/public/public/emojione/128/1f473-2642.png new file mode 100644 index 00000000..9f4a1dd9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f473.png b/twake/frontend/public/public/emojione/128/1f473.png new file mode 100644 index 00000000..9f4a1dd9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f473.png differ diff --git a/twake/frontend/public/public/emojione/128/1f474-1f3fb.png b/twake/frontend/public/public/emojione/128/1f474-1f3fb.png new file mode 100644 index 00000000..c5619549 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f474-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f474-1f3fc.png b/twake/frontend/public/public/emojione/128/1f474-1f3fc.png new file mode 100644 index 00000000..c145e164 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f474-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f474-1f3fd.png b/twake/frontend/public/public/emojione/128/1f474-1f3fd.png new file mode 100644 index 00000000..b847f7c5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f474-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f474-1f3fe.png b/twake/frontend/public/public/emojione/128/1f474-1f3fe.png new file mode 100644 index 00000000..d6658074 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f474-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f474-1f3ff.png b/twake/frontend/public/public/emojione/128/1f474-1f3ff.png new file mode 100644 index 00000000..31dce0db Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f474-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f474.png b/twake/frontend/public/public/emojione/128/1f474.png new file mode 100644 index 00000000..5928053a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f474.png differ diff --git a/twake/frontend/public/public/emojione/128/1f475-1f3fb.png b/twake/frontend/public/public/emojione/128/1f475-1f3fb.png new file mode 100644 index 00000000..0c30f724 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f475-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f475-1f3fc.png b/twake/frontend/public/public/emojione/128/1f475-1f3fc.png new file mode 100644 index 00000000..be703e7e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f475-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f475-1f3fd.png b/twake/frontend/public/public/emojione/128/1f475-1f3fd.png new file mode 100644 index 00000000..a4618755 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f475-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f475-1f3fe.png b/twake/frontend/public/public/emojione/128/1f475-1f3fe.png new file mode 100644 index 00000000..d7efcebf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f475-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f475-1f3ff.png b/twake/frontend/public/public/emojione/128/1f475-1f3ff.png new file mode 100644 index 00000000..a9030c79 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f475-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f475.png b/twake/frontend/public/public/emojione/128/1f475.png new file mode 100644 index 00000000..c421baa7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f475.png differ diff --git a/twake/frontend/public/public/emojione/128/1f476-1f3fb.png b/twake/frontend/public/public/emojione/128/1f476-1f3fb.png new file mode 100644 index 00000000..327ec743 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f476-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f476-1f3fc.png b/twake/frontend/public/public/emojione/128/1f476-1f3fc.png new file mode 100644 index 00000000..8d2bdf6d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f476-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f476-1f3fd.png b/twake/frontend/public/public/emojione/128/1f476-1f3fd.png new file mode 100644 index 00000000..97efe337 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f476-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f476-1f3fe.png b/twake/frontend/public/public/emojione/128/1f476-1f3fe.png new file mode 100644 index 00000000..cd646f40 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f476-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f476-1f3ff.png b/twake/frontend/public/public/emojione/128/1f476-1f3ff.png new file mode 100644 index 00000000..e11bb37c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f476-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f476.png b/twake/frontend/public/public/emojione/128/1f476.png new file mode 100644 index 00000000..e420b010 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f476.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f477-1f3fb-2640.png new file mode 100644 index 00000000..323a1d7a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f477-1f3fb-2642.png new file mode 100644 index 00000000..063e55d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477-1f3fb.png b/twake/frontend/public/public/emojione/128/1f477-1f3fb.png new file mode 100644 index 00000000..063e55d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f477-1f3fc-2640.png new file mode 100644 index 00000000..2399961c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f477-1f3fc-2642.png new file mode 100644 index 00000000..f428d407 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477-1f3fc.png b/twake/frontend/public/public/emojione/128/1f477-1f3fc.png new file mode 100644 index 00000000..f428d407 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f477-1f3fd-2640.png new file mode 100644 index 00000000..e014afbc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f477-1f3fd-2642.png new file mode 100644 index 00000000..51b6fc0a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477-1f3fd.png b/twake/frontend/public/public/emojione/128/1f477-1f3fd.png new file mode 100644 index 00000000..51b6fc0a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f477-1f3fe-2640.png new file mode 100644 index 00000000..e8f37ab4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f477-1f3fe-2642.png new file mode 100644 index 00000000..5f677515 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477-1f3fe.png b/twake/frontend/public/public/emojione/128/1f477-1f3fe.png new file mode 100644 index 00000000..5f677515 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f477-1f3ff-2640.png new file mode 100644 index 00000000..e9ff2718 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f477-1f3ff-2642.png new file mode 100644 index 00000000..7d0d057c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477-1f3ff.png b/twake/frontend/public/public/emojione/128/1f477-1f3ff.png new file mode 100644 index 00000000..7d0d057c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477-2640.png b/twake/frontend/public/public/emojione/128/1f477-2640.png new file mode 100644 index 00000000..9a4ef17b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477-2642.png b/twake/frontend/public/public/emojione/128/1f477-2642.png new file mode 100644 index 00000000..125eef5e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f477.png b/twake/frontend/public/public/emojione/128/1f477.png new file mode 100644 index 00000000..125eef5e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f477.png differ diff --git a/twake/frontend/public/public/emojione/128/1f478-1f3fb.png b/twake/frontend/public/public/emojione/128/1f478-1f3fb.png new file mode 100644 index 00000000..1e7524e4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f478-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f478-1f3fc.png b/twake/frontend/public/public/emojione/128/1f478-1f3fc.png new file mode 100644 index 00000000..51f25f17 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f478-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f478-1f3fd.png b/twake/frontend/public/public/emojione/128/1f478-1f3fd.png new file mode 100644 index 00000000..e5449c68 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f478-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f478-1f3fe.png b/twake/frontend/public/public/emojione/128/1f478-1f3fe.png new file mode 100644 index 00000000..36d47761 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f478-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f478-1f3ff.png b/twake/frontend/public/public/emojione/128/1f478-1f3ff.png new file mode 100644 index 00000000..d0613b03 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f478-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f478.png b/twake/frontend/public/public/emojione/128/1f478.png new file mode 100644 index 00000000..0c3d3a08 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f478.png differ diff --git a/twake/frontend/public/public/emojione/128/1f479.png b/twake/frontend/public/public/emojione/128/1f479.png new file mode 100644 index 00000000..84cb3e89 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f479.png differ diff --git a/twake/frontend/public/public/emojione/128/1f47a.png b/twake/frontend/public/public/emojione/128/1f47a.png new file mode 100644 index 00000000..a4e957f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f47a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f47b.png b/twake/frontend/public/public/emojione/128/1f47b.png new file mode 100644 index 00000000..32e6534d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f47b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f47c-1f3fb.png b/twake/frontend/public/public/emojione/128/1f47c-1f3fb.png new file mode 100644 index 00000000..f8a0d11e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f47c-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f47c-1f3fc.png b/twake/frontend/public/public/emojione/128/1f47c-1f3fc.png new file mode 100644 index 00000000..14246c42 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f47c-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f47c-1f3fd.png b/twake/frontend/public/public/emojione/128/1f47c-1f3fd.png new file mode 100644 index 00000000..c23a8add Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f47c-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f47c-1f3fe.png b/twake/frontend/public/public/emojione/128/1f47c-1f3fe.png new file mode 100644 index 00000000..0ef07e95 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f47c-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f47c-1f3ff.png b/twake/frontend/public/public/emojione/128/1f47c-1f3ff.png new file mode 100644 index 00000000..41221755 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f47c-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f47c.png b/twake/frontend/public/public/emojione/128/1f47c.png new file mode 100644 index 00000000..93d78f4f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f47c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f47d.png b/twake/frontend/public/public/emojione/128/1f47d.png new file mode 100644 index 00000000..6ecdca8f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f47d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f47e.png b/twake/frontend/public/public/emojione/128/1f47e.png new file mode 100644 index 00000000..fcd850e4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f47e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f47f.png b/twake/frontend/public/public/emojione/128/1f47f.png new file mode 100644 index 00000000..ea55b6d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f47f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f480.png b/twake/frontend/public/public/emojione/128/1f480.png new file mode 100644 index 00000000..159aec42 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f480.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f481-1f3fb-2640.png new file mode 100644 index 00000000..f5275840 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f481-1f3fb-2642.png new file mode 100644 index 00000000..0ccbf7e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481-1f3fb.png b/twake/frontend/public/public/emojione/128/1f481-1f3fb.png new file mode 100644 index 00000000..c7941e6a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f481-1f3fc-2640.png new file mode 100644 index 00000000..664130ac Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f481-1f3fc-2642.png new file mode 100644 index 00000000..8e8b1df4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481-1f3fc.png b/twake/frontend/public/public/emojione/128/1f481-1f3fc.png new file mode 100644 index 00000000..30d5abea Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f481-1f3fd-2640.png new file mode 100644 index 00000000..eceb079c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f481-1f3fd-2642.png new file mode 100644 index 00000000..70571baf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481-1f3fd.png b/twake/frontend/public/public/emojione/128/1f481-1f3fd.png new file mode 100644 index 00000000..7fb2a500 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f481-1f3fe-2640.png new file mode 100644 index 00000000..3d083e2e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f481-1f3fe-2642.png new file mode 100644 index 00000000..877aedbf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481-1f3fe.png b/twake/frontend/public/public/emojione/128/1f481-1f3fe.png new file mode 100644 index 00000000..ec4f5b52 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f481-1f3ff-2640.png new file mode 100644 index 00000000..e2e9f30a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f481-1f3ff-2642.png new file mode 100644 index 00000000..47b58efe Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481-1f3ff.png b/twake/frontend/public/public/emojione/128/1f481-1f3ff.png new file mode 100644 index 00000000..e8897131 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481-2640.png b/twake/frontend/public/public/emojione/128/1f481-2640.png new file mode 100644 index 00000000..0658626c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481-2642.png b/twake/frontend/public/public/emojione/128/1f481-2642.png new file mode 100644 index 00000000..b7a87b7d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f481.png b/twake/frontend/public/public/emojione/128/1f481.png new file mode 100644 index 00000000..0658626c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f481.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f482-1f3fb-2640.png new file mode 100644 index 00000000..2f5c74c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f482-1f3fb-2642.png new file mode 100644 index 00000000..b9922ae3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482-1f3fb.png b/twake/frontend/public/public/emojione/128/1f482-1f3fb.png new file mode 100644 index 00000000..b9922ae3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f482-1f3fc-2640.png new file mode 100644 index 00000000..6e644676 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f482-1f3fc-2642.png new file mode 100644 index 00000000..ca5a27ac Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482-1f3fc.png b/twake/frontend/public/public/emojione/128/1f482-1f3fc.png new file mode 100644 index 00000000..ca5a27ac Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f482-1f3fd-2640.png new file mode 100644 index 00000000..f81e8f83 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f482-1f3fd-2642.png new file mode 100644 index 00000000..241d9640 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482-1f3fd.png b/twake/frontend/public/public/emojione/128/1f482-1f3fd.png new file mode 100644 index 00000000..241d9640 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f482-1f3fe-2640.png new file mode 100644 index 00000000..575c1a1e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f482-1f3fe-2642.png new file mode 100644 index 00000000..a9bc4bef Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482-1f3fe.png b/twake/frontend/public/public/emojione/128/1f482-1f3fe.png new file mode 100644 index 00000000..a9bc4bef Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f482-1f3ff-2640.png new file mode 100644 index 00000000..fea089b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f482-1f3ff-2642.png new file mode 100644 index 00000000..13b9db26 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482-1f3ff.png b/twake/frontend/public/public/emojione/128/1f482-1f3ff.png new file mode 100644 index 00000000..13b9db26 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482-2640.png b/twake/frontend/public/public/emojione/128/1f482-2640.png new file mode 100644 index 00000000..bc7fe5bf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482-2642.png b/twake/frontend/public/public/emojione/128/1f482-2642.png new file mode 100644 index 00000000..a1ae49a8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f482.png b/twake/frontend/public/public/emojione/128/1f482.png new file mode 100644 index 00000000..a1ae49a8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f482.png differ diff --git a/twake/frontend/public/public/emojione/128/1f483-1f3fb.png b/twake/frontend/public/public/emojione/128/1f483-1f3fb.png new file mode 100644 index 00000000..89759d47 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f483-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f483-1f3fc.png b/twake/frontend/public/public/emojione/128/1f483-1f3fc.png new file mode 100644 index 00000000..541d16bd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f483-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f483-1f3fd.png b/twake/frontend/public/public/emojione/128/1f483-1f3fd.png new file mode 100644 index 00000000..d50c029c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f483-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f483-1f3fe.png b/twake/frontend/public/public/emojione/128/1f483-1f3fe.png new file mode 100644 index 00000000..6a3155f9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f483-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f483-1f3ff.png b/twake/frontend/public/public/emojione/128/1f483-1f3ff.png new file mode 100644 index 00000000..56080e60 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f483-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f483.png b/twake/frontend/public/public/emojione/128/1f483.png new file mode 100644 index 00000000..101ba993 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f483.png differ diff --git a/twake/frontend/public/public/emojione/128/1f484.png b/twake/frontend/public/public/emojione/128/1f484.png new file mode 100644 index 00000000..9b917c8a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f484.png differ diff --git a/twake/frontend/public/public/emojione/128/1f485-1f3fb.png b/twake/frontend/public/public/emojione/128/1f485-1f3fb.png new file mode 100644 index 00000000..debde622 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f485-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f485-1f3fc.png b/twake/frontend/public/public/emojione/128/1f485-1f3fc.png new file mode 100644 index 00000000..55afc505 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f485-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f485-1f3fd.png b/twake/frontend/public/public/emojione/128/1f485-1f3fd.png new file mode 100644 index 00000000..86c4a6f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f485-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f485-1f3fe.png b/twake/frontend/public/public/emojione/128/1f485-1f3fe.png new file mode 100644 index 00000000..7a47c1c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f485-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f485-1f3ff.png b/twake/frontend/public/public/emojione/128/1f485-1f3ff.png new file mode 100644 index 00000000..b38c1176 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f485-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f485.png b/twake/frontend/public/public/emojione/128/1f485.png new file mode 100644 index 00000000..fcd49d58 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f485.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f486-1f3fb-2640.png new file mode 100644 index 00000000..02bc06ad Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f486-1f3fb-2642.png new file mode 100644 index 00000000..ff5b365a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486-1f3fb.png b/twake/frontend/public/public/emojione/128/1f486-1f3fb.png new file mode 100644 index 00000000..104b18fc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f486-1f3fc-2640.png new file mode 100644 index 00000000..ae24f23e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f486-1f3fc-2642.png new file mode 100644 index 00000000..52183943 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486-1f3fc.png b/twake/frontend/public/public/emojione/128/1f486-1f3fc.png new file mode 100644 index 00000000..842aa58c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f486-1f3fd-2640.png new file mode 100644 index 00000000..03a44bf8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f486-1f3fd-2642.png new file mode 100644 index 00000000..73ecdf1d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486-1f3fd.png b/twake/frontend/public/public/emojione/128/1f486-1f3fd.png new file mode 100644 index 00000000..9fa3b44d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f486-1f3fe-2640.png new file mode 100644 index 00000000..adf01f87 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f486-1f3fe-2642.png new file mode 100644 index 00000000..9fafdf54 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486-1f3fe.png b/twake/frontend/public/public/emojione/128/1f486-1f3fe.png new file mode 100644 index 00000000..9ac56a76 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f486-1f3ff-2640.png new file mode 100644 index 00000000..e1cf91d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f486-1f3ff-2642.png new file mode 100644 index 00000000..a4fcc1a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486-1f3ff.png b/twake/frontend/public/public/emojione/128/1f486-1f3ff.png new file mode 100644 index 00000000..1d6b5f71 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486-2640.png b/twake/frontend/public/public/emojione/128/1f486-2640.png new file mode 100644 index 00000000..53d888f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486-2642.png b/twake/frontend/public/public/emojione/128/1f486-2642.png new file mode 100644 index 00000000..664fb912 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f486.png b/twake/frontend/public/public/emojione/128/1f486.png new file mode 100644 index 00000000..53d888f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f486.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f487-1f3fb-2640.png new file mode 100644 index 00000000..9260d88a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f487-1f3fb-2642.png new file mode 100644 index 00000000..fdf5c0ae Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487-1f3fb.png b/twake/frontend/public/public/emojione/128/1f487-1f3fb.png new file mode 100644 index 00000000..2b239774 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f487-1f3fc-2640.png new file mode 100644 index 00000000..811bbe91 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f487-1f3fc-2642.png new file mode 100644 index 00000000..b383f541 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487-1f3fc.png b/twake/frontend/public/public/emojione/128/1f487-1f3fc.png new file mode 100644 index 00000000..4cd0c01c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f487-1f3fd-2640.png new file mode 100644 index 00000000..d380cbc3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f487-1f3fd-2642.png new file mode 100644 index 00000000..88d33a94 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487-1f3fd.png b/twake/frontend/public/public/emojione/128/1f487-1f3fd.png new file mode 100644 index 00000000..0024d018 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f487-1f3fe-2640.png new file mode 100644 index 00000000..7b526675 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f487-1f3fe-2642.png new file mode 100644 index 00000000..9cc9f5c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487-1f3fe.png b/twake/frontend/public/public/emojione/128/1f487-1f3fe.png new file mode 100644 index 00000000..f491a34d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f487-1f3ff-2640.png new file mode 100644 index 00000000..25b9e171 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f487-1f3ff-2642.png new file mode 100644 index 00000000..0fb1d3b4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487-1f3ff.png b/twake/frontend/public/public/emojione/128/1f487-1f3ff.png new file mode 100644 index 00000000..f09f0bad Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487-2640.png b/twake/frontend/public/public/emojione/128/1f487-2640.png new file mode 100644 index 00000000..a0e76f84 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487-2642.png b/twake/frontend/public/public/emojione/128/1f487-2642.png new file mode 100644 index 00000000..08a979cd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f487.png b/twake/frontend/public/public/emojione/128/1f487.png new file mode 100644 index 00000000..a0e76f84 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f487.png differ diff --git a/twake/frontend/public/public/emojione/128/1f488.png b/twake/frontend/public/public/emojione/128/1f488.png new file mode 100644 index 00000000..4f8ea991 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f488.png differ diff --git a/twake/frontend/public/public/emojione/128/1f489.png b/twake/frontend/public/public/emojione/128/1f489.png new file mode 100644 index 00000000..db86eb37 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f489.png differ diff --git a/twake/frontend/public/public/emojione/128/1f48a.png b/twake/frontend/public/public/emojione/128/1f48a.png new file mode 100644 index 00000000..7468a4d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f48a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f48b.png b/twake/frontend/public/public/emojione/128/1f48b.png new file mode 100644 index 00000000..df7827a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f48b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f48c.png b/twake/frontend/public/public/emojione/128/1f48c.png new file mode 100644 index 00000000..13a24890 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f48c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f48d.png b/twake/frontend/public/public/emojione/128/1f48d.png new file mode 100644 index 00000000..c67a00e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f48d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f48e.png b/twake/frontend/public/public/emojione/128/1f48e.png new file mode 100644 index 00000000..95f7d442 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f48e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f48f.png b/twake/frontend/public/public/emojione/128/1f48f.png new file mode 100644 index 00000000..2b2bffd9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f48f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f490.png b/twake/frontend/public/public/emojione/128/1f490.png new file mode 100644 index 00000000..89573400 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f490.png differ diff --git a/twake/frontend/public/public/emojione/128/1f491.png b/twake/frontend/public/public/emojione/128/1f491.png new file mode 100644 index 00000000..44e3f038 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f491.png differ diff --git a/twake/frontend/public/public/emojione/128/1f492.png b/twake/frontend/public/public/emojione/128/1f492.png new file mode 100644 index 00000000..012b3dc6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f492.png differ diff --git a/twake/frontend/public/public/emojione/128/1f493.png b/twake/frontend/public/public/emojione/128/1f493.png new file mode 100644 index 00000000..116da908 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f493.png differ diff --git a/twake/frontend/public/public/emojione/128/1f494.png b/twake/frontend/public/public/emojione/128/1f494.png new file mode 100644 index 00000000..cbd88d2f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f494.png differ diff --git a/twake/frontend/public/public/emojione/128/1f495.png b/twake/frontend/public/public/emojione/128/1f495.png new file mode 100644 index 00000000..0f5243a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f495.png differ diff --git a/twake/frontend/public/public/emojione/128/1f496.png b/twake/frontend/public/public/emojione/128/1f496.png new file mode 100644 index 00000000..13251e2d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f496.png differ diff --git a/twake/frontend/public/public/emojione/128/1f497.png b/twake/frontend/public/public/emojione/128/1f497.png new file mode 100644 index 00000000..5b9f2db7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f497.png differ diff --git a/twake/frontend/public/public/emojione/128/1f498.png b/twake/frontend/public/public/emojione/128/1f498.png new file mode 100644 index 00000000..2e42c896 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f498.png differ diff --git a/twake/frontend/public/public/emojione/128/1f499.png b/twake/frontend/public/public/emojione/128/1f499.png new file mode 100644 index 00000000..739c09a4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f499.png differ diff --git a/twake/frontend/public/public/emojione/128/1f49a.png b/twake/frontend/public/public/emojione/128/1f49a.png new file mode 100644 index 00000000..f4d4fcf9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f49a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f49b.png b/twake/frontend/public/public/emojione/128/1f49b.png new file mode 100644 index 00000000..e3ed8d25 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f49b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f49c.png b/twake/frontend/public/public/emojione/128/1f49c.png new file mode 100644 index 00000000..5ecc6571 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f49c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f49d.png b/twake/frontend/public/public/emojione/128/1f49d.png new file mode 100644 index 00000000..33e74211 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f49d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f49e.png b/twake/frontend/public/public/emojione/128/1f49e.png new file mode 100644 index 00000000..d415b484 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f49e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f49f.png b/twake/frontend/public/public/emojione/128/1f49f.png new file mode 100644 index 00000000..40168ac7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f49f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4a0.png b/twake/frontend/public/public/emojione/128/1f4a0.png new file mode 100644 index 00000000..8aeb4c8c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4a0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4a1.png b/twake/frontend/public/public/emojione/128/1f4a1.png new file mode 100644 index 00000000..87a356cf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4a1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4a2.png b/twake/frontend/public/public/emojione/128/1f4a2.png new file mode 100644 index 00000000..7cadf0b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4a2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4a3.png b/twake/frontend/public/public/emojione/128/1f4a3.png new file mode 100644 index 00000000..ee9da27b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4a3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4a4.png b/twake/frontend/public/public/emojione/128/1f4a4.png new file mode 100644 index 00000000..ed54214f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4a4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4a5.png b/twake/frontend/public/public/emojione/128/1f4a5.png new file mode 100644 index 00000000..6e0e4f6d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4a5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4a6.png b/twake/frontend/public/public/emojione/128/1f4a6.png new file mode 100644 index 00000000..ca21c4fc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4a6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4a7.png b/twake/frontend/public/public/emojione/128/1f4a7.png new file mode 100644 index 00000000..4a5b83d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4a7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4a8.png b/twake/frontend/public/public/emojione/128/1f4a8.png new file mode 100644 index 00000000..c1cf7e71 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4a8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4a9.png b/twake/frontend/public/public/emojione/128/1f4a9.png new file mode 100644 index 00000000..c20d710b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4a9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4aa-1f3fb.png b/twake/frontend/public/public/emojione/128/1f4aa-1f3fb.png new file mode 100644 index 00000000..66dac55d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4aa-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4aa-1f3fc.png b/twake/frontend/public/public/emojione/128/1f4aa-1f3fc.png new file mode 100644 index 00000000..2d992e6c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4aa-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4aa-1f3fd.png b/twake/frontend/public/public/emojione/128/1f4aa-1f3fd.png new file mode 100644 index 00000000..e5301d28 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4aa-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4aa-1f3fe.png b/twake/frontend/public/public/emojione/128/1f4aa-1f3fe.png new file mode 100644 index 00000000..bb4a5beb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4aa-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4aa-1f3ff.png b/twake/frontend/public/public/emojione/128/1f4aa-1f3ff.png new file mode 100644 index 00000000..ca63b322 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4aa-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4aa.png b/twake/frontend/public/public/emojione/128/1f4aa.png new file mode 100644 index 00000000..1b2d3a9c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4aa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4ab.png b/twake/frontend/public/public/emojione/128/1f4ab.png new file mode 100644 index 00000000..cf74a79c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4ab.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4ac.png b/twake/frontend/public/public/emojione/128/1f4ac.png new file mode 100644 index 00000000..a4b4064b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4ac.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4ad.png b/twake/frontend/public/public/emojione/128/1f4ad.png new file mode 100644 index 00000000..0e9990d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4ad.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4ae.png b/twake/frontend/public/public/emojione/128/1f4ae.png new file mode 100644 index 00000000..d79d2449 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4ae.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4af.png b/twake/frontend/public/public/emojione/128/1f4af.png new file mode 100644 index 00000000..cc776d6d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4af.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4b0.png b/twake/frontend/public/public/emojione/128/1f4b0.png new file mode 100644 index 00000000..de2e7d7a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4b0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4b1.png b/twake/frontend/public/public/emojione/128/1f4b1.png new file mode 100644 index 00000000..f5904055 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4b1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4b2.png b/twake/frontend/public/public/emojione/128/1f4b2.png new file mode 100644 index 00000000..2b1d9bd1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4b2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4b3.png b/twake/frontend/public/public/emojione/128/1f4b3.png new file mode 100644 index 00000000..0625c85b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4b3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4b4.png b/twake/frontend/public/public/emojione/128/1f4b4.png new file mode 100644 index 00000000..6851e04a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4b4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4b5.png b/twake/frontend/public/public/emojione/128/1f4b5.png new file mode 100644 index 00000000..7c3e6df0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4b5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4b6.png b/twake/frontend/public/public/emojione/128/1f4b6.png new file mode 100644 index 00000000..fd9a722d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4b6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4b7.png b/twake/frontend/public/public/emojione/128/1f4b7.png new file mode 100644 index 00000000..9e1c2e1e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4b7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4b8.png b/twake/frontend/public/public/emojione/128/1f4b8.png new file mode 100644 index 00000000..68147072 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4b8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4b9.png b/twake/frontend/public/public/emojione/128/1f4b9.png new file mode 100644 index 00000000..f804f9d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4b9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4ba.png b/twake/frontend/public/public/emojione/128/1f4ba.png new file mode 100644 index 00000000..0a11e917 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4ba.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4bb.png b/twake/frontend/public/public/emojione/128/1f4bb.png new file mode 100644 index 00000000..e0e3c891 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4bc.png b/twake/frontend/public/public/emojione/128/1f4bc.png new file mode 100644 index 00000000..7aa6e272 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4bd.png b/twake/frontend/public/public/emojione/128/1f4bd.png new file mode 100644 index 00000000..dea0637b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4bd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4be.png b/twake/frontend/public/public/emojione/128/1f4be.png new file mode 100644 index 00000000..f894bc57 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4be.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4bf.png b/twake/frontend/public/public/emojione/128/1f4bf.png new file mode 100644 index 00000000..3733722b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4bf.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4c0.png b/twake/frontend/public/public/emojione/128/1f4c0.png new file mode 100644 index 00000000..44d42766 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4c0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4c1.png b/twake/frontend/public/public/emojione/128/1f4c1.png new file mode 100644 index 00000000..52b0a320 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4c1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4c2.png b/twake/frontend/public/public/emojione/128/1f4c2.png new file mode 100644 index 00000000..90b9ce6a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4c2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4c3.png b/twake/frontend/public/public/emojione/128/1f4c3.png new file mode 100644 index 00000000..6a81b305 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4c3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4c4.png b/twake/frontend/public/public/emojione/128/1f4c4.png new file mode 100644 index 00000000..e5798b4c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4c4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4c5.png b/twake/frontend/public/public/emojione/128/1f4c5.png new file mode 100644 index 00000000..addcc5e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4c5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4c6.png b/twake/frontend/public/public/emojione/128/1f4c6.png new file mode 100644 index 00000000..b7117cf1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4c6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4c7.png b/twake/frontend/public/public/emojione/128/1f4c7.png new file mode 100644 index 00000000..5afd2ff9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4c7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4c8.png b/twake/frontend/public/public/emojione/128/1f4c8.png new file mode 100644 index 00000000..7ab57ff2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4c8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4c9.png b/twake/frontend/public/public/emojione/128/1f4c9.png new file mode 100644 index 00000000..e45a0008 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4c9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4ca.png b/twake/frontend/public/public/emojione/128/1f4ca.png new file mode 100644 index 00000000..770f2383 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4ca.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4cb.png b/twake/frontend/public/public/emojione/128/1f4cb.png new file mode 100644 index 00000000..75b89959 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4cb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4cc.png b/twake/frontend/public/public/emojione/128/1f4cc.png new file mode 100644 index 00000000..5cd69c28 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4cc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4cd.png b/twake/frontend/public/public/emojione/128/1f4cd.png new file mode 100644 index 00000000..f6f64561 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4cd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4ce.png b/twake/frontend/public/public/emojione/128/1f4ce.png new file mode 100644 index 00000000..80c20b69 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4ce.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4cf.png b/twake/frontend/public/public/emojione/128/1f4cf.png new file mode 100644 index 00000000..5dff590f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4cf.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4d0.png b/twake/frontend/public/public/emojione/128/1f4d0.png new file mode 100644 index 00000000..c966d270 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4d0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4d1.png b/twake/frontend/public/public/emojione/128/1f4d1.png new file mode 100644 index 00000000..08c8885a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4d1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4d2.png b/twake/frontend/public/public/emojione/128/1f4d2.png new file mode 100644 index 00000000..1e0a5e48 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4d2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4d3.png b/twake/frontend/public/public/emojione/128/1f4d3.png new file mode 100644 index 00000000..a0139c63 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4d3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4d4.png b/twake/frontend/public/public/emojione/128/1f4d4.png new file mode 100644 index 00000000..4059d40a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4d4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4d5.png b/twake/frontend/public/public/emojione/128/1f4d5.png new file mode 100644 index 00000000..8d552136 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4d5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4d6.png b/twake/frontend/public/public/emojione/128/1f4d6.png new file mode 100644 index 00000000..d26a5563 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4d6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4d7.png b/twake/frontend/public/public/emojione/128/1f4d7.png new file mode 100644 index 00000000..4e8a28f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4d7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4d8.png b/twake/frontend/public/public/emojione/128/1f4d8.png new file mode 100644 index 00000000..7e37b45b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4d8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4d9.png b/twake/frontend/public/public/emojione/128/1f4d9.png new file mode 100644 index 00000000..9a4da3f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4d9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4da.png b/twake/frontend/public/public/emojione/128/1f4da.png new file mode 100644 index 00000000..327818e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4da.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4db.png b/twake/frontend/public/public/emojione/128/1f4db.png new file mode 100644 index 00000000..83d3507c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4db.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4dc.png b/twake/frontend/public/public/emojione/128/1f4dc.png new file mode 100644 index 00000000..01d1ef98 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4dc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4dd.png b/twake/frontend/public/public/emojione/128/1f4dd.png new file mode 100644 index 00000000..3855c4f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4dd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4de.png b/twake/frontend/public/public/emojione/128/1f4de.png new file mode 100644 index 00000000..54a4f9f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4de.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4df.png b/twake/frontend/public/public/emojione/128/1f4df.png new file mode 100644 index 00000000..3faa7e6b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4df.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4e0.png b/twake/frontend/public/public/emojione/128/1f4e0.png new file mode 100644 index 00000000..6f09246f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4e0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4e1.png b/twake/frontend/public/public/emojione/128/1f4e1.png new file mode 100644 index 00000000..ed167011 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4e1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4e2.png b/twake/frontend/public/public/emojione/128/1f4e2.png new file mode 100644 index 00000000..8128490d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4e2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4e3.png b/twake/frontend/public/public/emojione/128/1f4e3.png new file mode 100644 index 00000000..f77af222 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4e3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4e4.png b/twake/frontend/public/public/emojione/128/1f4e4.png new file mode 100644 index 00000000..babddeb3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4e4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4e5.png b/twake/frontend/public/public/emojione/128/1f4e5.png new file mode 100644 index 00000000..949405d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4e5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4e6.png b/twake/frontend/public/public/emojione/128/1f4e6.png new file mode 100644 index 00000000..2db1aaf1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4e7.png b/twake/frontend/public/public/emojione/128/1f4e7.png new file mode 100644 index 00000000..59a58c55 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4e7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4e8.png b/twake/frontend/public/public/emojione/128/1f4e8.png new file mode 100644 index 00000000..4d816860 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4e8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4e9.png b/twake/frontend/public/public/emojione/128/1f4e9.png new file mode 100644 index 00000000..77f340cc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4e9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4ea.png b/twake/frontend/public/public/emojione/128/1f4ea.png new file mode 100644 index 00000000..20b440cd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4eb.png b/twake/frontend/public/public/emojione/128/1f4eb.png new file mode 100644 index 00000000..fd68734d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4ec.png b/twake/frontend/public/public/emojione/128/1f4ec.png new file mode 100644 index 00000000..c0614126 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4ed.png b/twake/frontend/public/public/emojione/128/1f4ed.png new file mode 100644 index 00000000..e3695fde Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4ee.png b/twake/frontend/public/public/emojione/128/1f4ee.png new file mode 100644 index 00000000..18543cc6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4ee.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4ef.png b/twake/frontend/public/public/emojione/128/1f4ef.png new file mode 100644 index 00000000..57618dcc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4ef.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4f0.png b/twake/frontend/public/public/emojione/128/1f4f0.png new file mode 100644 index 00000000..f425ae00 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4f0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4f1.png b/twake/frontend/public/public/emojione/128/1f4f1.png new file mode 100644 index 00000000..0c444ccf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4f1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4f2.png b/twake/frontend/public/public/emojione/128/1f4f2.png new file mode 100644 index 00000000..15d8e440 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4f3.png b/twake/frontend/public/public/emojione/128/1f4f3.png new file mode 100644 index 00000000..728283bc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4f4.png b/twake/frontend/public/public/emojione/128/1f4f4.png new file mode 100644 index 00000000..ca49582a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4f4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4f5.png b/twake/frontend/public/public/emojione/128/1f4f5.png new file mode 100644 index 00000000..8a8a68d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4f5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4f6.png b/twake/frontend/public/public/emojione/128/1f4f6.png new file mode 100644 index 00000000..c3ad7a76 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4f6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4f7.png b/twake/frontend/public/public/emojione/128/1f4f7.png new file mode 100644 index 00000000..b80f22cc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4f8.png b/twake/frontend/public/public/emojione/128/1f4f8.png new file mode 100644 index 00000000..6a7eee89 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4f8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4f9.png b/twake/frontend/public/public/emojione/128/1f4f9.png new file mode 100644 index 00000000..93a17af1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4f9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4fa.png b/twake/frontend/public/public/emojione/128/1f4fa.png new file mode 100644 index 00000000..f12ba18d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4fa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4fb.png b/twake/frontend/public/public/emojione/128/1f4fb.png new file mode 100644 index 00000000..6fdd2499 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4fc.png b/twake/frontend/public/public/emojione/128/1f4fc.png new file mode 100644 index 00000000..b92ffa9e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4fd.png b/twake/frontend/public/public/emojione/128/1f4fd.png new file mode 100644 index 00000000..5bf5bb59 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f4ff.png b/twake/frontend/public/public/emojione/128/1f4ff.png new file mode 100644 index 00000000..6beae173 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f4ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f500.png b/twake/frontend/public/public/emojione/128/1f500.png new file mode 100644 index 00000000..8f4396d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f500.png differ diff --git a/twake/frontend/public/public/emojione/128/1f501.png b/twake/frontend/public/public/emojione/128/1f501.png new file mode 100644 index 00000000..507aea47 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f501.png differ diff --git a/twake/frontend/public/public/emojione/128/1f502.png b/twake/frontend/public/public/emojione/128/1f502.png new file mode 100644 index 00000000..7542a6f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f502.png differ diff --git a/twake/frontend/public/public/emojione/128/1f503.png b/twake/frontend/public/public/emojione/128/1f503.png new file mode 100644 index 00000000..633f36b7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f503.png differ diff --git a/twake/frontend/public/public/emojione/128/1f504.png b/twake/frontend/public/public/emojione/128/1f504.png new file mode 100644 index 00000000..0e2aae5c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f504.png differ diff --git a/twake/frontend/public/public/emojione/128/1f505.png b/twake/frontend/public/public/emojione/128/1f505.png new file mode 100644 index 00000000..97cb9282 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f505.png differ diff --git a/twake/frontend/public/public/emojione/128/1f506.png b/twake/frontend/public/public/emojione/128/1f506.png new file mode 100644 index 00000000..f7b20a1a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f506.png differ diff --git a/twake/frontend/public/public/emojione/128/1f507.png b/twake/frontend/public/public/emojione/128/1f507.png new file mode 100644 index 00000000..f03a74eb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f507.png differ diff --git a/twake/frontend/public/public/emojione/128/1f508.png b/twake/frontend/public/public/emojione/128/1f508.png new file mode 100644 index 00000000..57f04825 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f508.png differ diff --git a/twake/frontend/public/public/emojione/128/1f509.png b/twake/frontend/public/public/emojione/128/1f509.png new file mode 100644 index 00000000..d120e791 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f509.png differ diff --git a/twake/frontend/public/public/emojione/128/1f50a.png b/twake/frontend/public/public/emojione/128/1f50a.png new file mode 100644 index 00000000..54fc7df2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f50a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f50b.png b/twake/frontend/public/public/emojione/128/1f50b.png new file mode 100644 index 00000000..1bbd0ff3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f50b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f50c.png b/twake/frontend/public/public/emojione/128/1f50c.png new file mode 100644 index 00000000..5ff31d49 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f50c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f50d.png b/twake/frontend/public/public/emojione/128/1f50d.png new file mode 100644 index 00000000..6815b645 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f50d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f50e.png b/twake/frontend/public/public/emojione/128/1f50e.png new file mode 100644 index 00000000..20ffe788 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f50e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f50f.png b/twake/frontend/public/public/emojione/128/1f50f.png new file mode 100644 index 00000000..c3cfa12b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f50f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f510.png b/twake/frontend/public/public/emojione/128/1f510.png new file mode 100644 index 00000000..1ade6429 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f510.png differ diff --git a/twake/frontend/public/public/emojione/128/1f511.png b/twake/frontend/public/public/emojione/128/1f511.png new file mode 100644 index 00000000..1083be98 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f511.png differ diff --git a/twake/frontend/public/public/emojione/128/1f512.png b/twake/frontend/public/public/emojione/128/1f512.png new file mode 100644 index 00000000..95a8eb80 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f512.png differ diff --git a/twake/frontend/public/public/emojione/128/1f513.png b/twake/frontend/public/public/emojione/128/1f513.png new file mode 100644 index 00000000..f3c85d73 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f513.png differ diff --git a/twake/frontend/public/public/emojione/128/1f514.png b/twake/frontend/public/public/emojione/128/1f514.png new file mode 100644 index 00000000..4b26f751 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f514.png differ diff --git a/twake/frontend/public/public/emojione/128/1f515.png b/twake/frontend/public/public/emojione/128/1f515.png new file mode 100644 index 00000000..6cb80805 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f515.png differ diff --git a/twake/frontend/public/public/emojione/128/1f516.png b/twake/frontend/public/public/emojione/128/1f516.png new file mode 100644 index 00000000..48b5dd68 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f516.png differ diff --git a/twake/frontend/public/public/emojione/128/1f517.png b/twake/frontend/public/public/emojione/128/1f517.png new file mode 100644 index 00000000..84a264a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f517.png differ diff --git a/twake/frontend/public/public/emojione/128/1f518.png b/twake/frontend/public/public/emojione/128/1f518.png new file mode 100644 index 00000000..02c460b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f518.png differ diff --git a/twake/frontend/public/public/emojione/128/1f519.png b/twake/frontend/public/public/emojione/128/1f519.png new file mode 100644 index 00000000..fa40e44e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f519.png differ diff --git a/twake/frontend/public/public/emojione/128/1f51a.png b/twake/frontend/public/public/emojione/128/1f51a.png new file mode 100644 index 00000000..958bb967 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f51a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f51b.png b/twake/frontend/public/public/emojione/128/1f51b.png new file mode 100644 index 00000000..18a36138 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f51b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f51c.png b/twake/frontend/public/public/emojione/128/1f51c.png new file mode 100644 index 00000000..eebbb7f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f51c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f51d.png b/twake/frontend/public/public/emojione/128/1f51d.png new file mode 100644 index 00000000..293a4e65 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f51d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f51e.png b/twake/frontend/public/public/emojione/128/1f51e.png new file mode 100644 index 00000000..68f852ad Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f51e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f51f.png b/twake/frontend/public/public/emojione/128/1f51f.png new file mode 100644 index 00000000..d7b61a86 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f51f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f520.png b/twake/frontend/public/public/emojione/128/1f520.png new file mode 100644 index 00000000..d82fac5e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f520.png differ diff --git a/twake/frontend/public/public/emojione/128/1f521.png b/twake/frontend/public/public/emojione/128/1f521.png new file mode 100644 index 00000000..170af0b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f521.png differ diff --git a/twake/frontend/public/public/emojione/128/1f522.png b/twake/frontend/public/public/emojione/128/1f522.png new file mode 100644 index 00000000..def36406 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f522.png differ diff --git a/twake/frontend/public/public/emojione/128/1f523.png b/twake/frontend/public/public/emojione/128/1f523.png new file mode 100644 index 00000000..01c3c0e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f523.png differ diff --git a/twake/frontend/public/public/emojione/128/1f524.png b/twake/frontend/public/public/emojione/128/1f524.png new file mode 100644 index 00000000..67cfc17b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f524.png differ diff --git a/twake/frontend/public/public/emojione/128/1f525.png b/twake/frontend/public/public/emojione/128/1f525.png new file mode 100644 index 00000000..d19a7cef Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f525.png differ diff --git a/twake/frontend/public/public/emojione/128/1f526.png b/twake/frontend/public/public/emojione/128/1f526.png new file mode 100644 index 00000000..e958c6c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f526.png differ diff --git a/twake/frontend/public/public/emojione/128/1f527.png b/twake/frontend/public/public/emojione/128/1f527.png new file mode 100644 index 00000000..2b3e1c19 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f527.png differ diff --git a/twake/frontend/public/public/emojione/128/1f528.png b/twake/frontend/public/public/emojione/128/1f528.png new file mode 100644 index 00000000..57d80ef0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f528.png differ diff --git a/twake/frontend/public/public/emojione/128/1f529.png b/twake/frontend/public/public/emojione/128/1f529.png new file mode 100644 index 00000000..bcba194d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f529.png differ diff --git a/twake/frontend/public/public/emojione/128/1f52a.png b/twake/frontend/public/public/emojione/128/1f52a.png new file mode 100644 index 00000000..dfb49fa4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f52a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f52b.png b/twake/frontend/public/public/emojione/128/1f52b.png new file mode 100644 index 00000000..ba61c65c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f52b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f52c.png b/twake/frontend/public/public/emojione/128/1f52c.png new file mode 100644 index 00000000..0bab170c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f52c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f52d.png b/twake/frontend/public/public/emojione/128/1f52d.png new file mode 100644 index 00000000..4669d7c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f52d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f52e.png b/twake/frontend/public/public/emojione/128/1f52e.png new file mode 100644 index 00000000..47c7db50 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f52e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f52f.png b/twake/frontend/public/public/emojione/128/1f52f.png new file mode 100644 index 00000000..8672eeeb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f52f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f530.png b/twake/frontend/public/public/emojione/128/1f530.png new file mode 100644 index 00000000..3c0aac0e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f530.png differ diff --git a/twake/frontend/public/public/emojione/128/1f531.png b/twake/frontend/public/public/emojione/128/1f531.png new file mode 100644 index 00000000..fe18ad89 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f531.png differ diff --git a/twake/frontend/public/public/emojione/128/1f532.png b/twake/frontend/public/public/emojione/128/1f532.png new file mode 100644 index 00000000..ac30fca9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f532.png differ diff --git a/twake/frontend/public/public/emojione/128/1f533.png b/twake/frontend/public/public/emojione/128/1f533.png new file mode 100644 index 00000000..4ef98d86 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f533.png differ diff --git a/twake/frontend/public/public/emojione/128/1f534.png b/twake/frontend/public/public/emojione/128/1f534.png new file mode 100644 index 00000000..40efa3dd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f534.png differ diff --git a/twake/frontend/public/public/emojione/128/1f535.png b/twake/frontend/public/public/emojione/128/1f535.png new file mode 100644 index 00000000..49892006 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f535.png differ diff --git a/twake/frontend/public/public/emojione/128/1f536.png b/twake/frontend/public/public/emojione/128/1f536.png new file mode 100644 index 00000000..53a611e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f536.png differ diff --git a/twake/frontend/public/public/emojione/128/1f537.png b/twake/frontend/public/public/emojione/128/1f537.png new file mode 100644 index 00000000..8bb94209 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f537.png differ diff --git a/twake/frontend/public/public/emojione/128/1f538.png b/twake/frontend/public/public/emojione/128/1f538.png new file mode 100644 index 00000000..78b08f6e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f538.png differ diff --git a/twake/frontend/public/public/emojione/128/1f539.png b/twake/frontend/public/public/emojione/128/1f539.png new file mode 100644 index 00000000..853b32f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f539.png differ diff --git a/twake/frontend/public/public/emojione/128/1f53a.png b/twake/frontend/public/public/emojione/128/1f53a.png new file mode 100644 index 00000000..d774babc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f53a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f53b.png b/twake/frontend/public/public/emojione/128/1f53b.png new file mode 100644 index 00000000..d930d4a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f53b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f53c.png b/twake/frontend/public/public/emojione/128/1f53c.png new file mode 100644 index 00000000..b3eb2a26 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f53c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f53d.png b/twake/frontend/public/public/emojione/128/1f53d.png new file mode 100644 index 00000000..fe0f4769 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f53d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f549.png b/twake/frontend/public/public/emojione/128/1f549.png new file mode 100644 index 00000000..c66d68b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f549.png differ diff --git a/twake/frontend/public/public/emojione/128/1f54a.png b/twake/frontend/public/public/emojione/128/1f54a.png new file mode 100644 index 00000000..7f10bd6e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f54a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f54b.png b/twake/frontend/public/public/emojione/128/1f54b.png new file mode 100644 index 00000000..28b4c5e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f54b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f54c.png b/twake/frontend/public/public/emojione/128/1f54c.png new file mode 100644 index 00000000..461ac497 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f54c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f54d.png b/twake/frontend/public/public/emojione/128/1f54d.png new file mode 100644 index 00000000..c2b183f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f54d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f54e.png b/twake/frontend/public/public/emojione/128/1f54e.png new file mode 100644 index 00000000..96af96d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f54e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f550.png b/twake/frontend/public/public/emojione/128/1f550.png new file mode 100644 index 00000000..f2ca678f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f550.png differ diff --git a/twake/frontend/public/public/emojione/128/1f551.png b/twake/frontend/public/public/emojione/128/1f551.png new file mode 100644 index 00000000..9ca1476d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f551.png differ diff --git a/twake/frontend/public/public/emojione/128/1f552.png b/twake/frontend/public/public/emojione/128/1f552.png new file mode 100644 index 00000000..e7379e92 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f552.png differ diff --git a/twake/frontend/public/public/emojione/128/1f553.png b/twake/frontend/public/public/emojione/128/1f553.png new file mode 100644 index 00000000..f1a939cb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f553.png differ diff --git a/twake/frontend/public/public/emojione/128/1f554.png b/twake/frontend/public/public/emojione/128/1f554.png new file mode 100644 index 00000000..361dde6e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f554.png differ diff --git a/twake/frontend/public/public/emojione/128/1f555.png b/twake/frontend/public/public/emojione/128/1f555.png new file mode 100644 index 00000000..39c220cc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f555.png differ diff --git a/twake/frontend/public/public/emojione/128/1f556.png b/twake/frontend/public/public/emojione/128/1f556.png new file mode 100644 index 00000000..3e5da429 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f556.png differ diff --git a/twake/frontend/public/public/emojione/128/1f557.png b/twake/frontend/public/public/emojione/128/1f557.png new file mode 100644 index 00000000..d9b4ecb2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f557.png differ diff --git a/twake/frontend/public/public/emojione/128/1f558.png b/twake/frontend/public/public/emojione/128/1f558.png new file mode 100644 index 00000000..834d28bf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f558.png differ diff --git a/twake/frontend/public/public/emojione/128/1f559.png b/twake/frontend/public/public/emojione/128/1f559.png new file mode 100644 index 00000000..1c22883c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f559.png differ diff --git a/twake/frontend/public/public/emojione/128/1f55a.png b/twake/frontend/public/public/emojione/128/1f55a.png new file mode 100644 index 00000000..b1bd8165 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f55a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f55b.png b/twake/frontend/public/public/emojione/128/1f55b.png new file mode 100644 index 00000000..f38e9af7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f55b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f55c.png b/twake/frontend/public/public/emojione/128/1f55c.png new file mode 100644 index 00000000..5f223f0d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f55c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f55d.png b/twake/frontend/public/public/emojione/128/1f55d.png new file mode 100644 index 00000000..6dd395c9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f55d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f55e.png b/twake/frontend/public/public/emojione/128/1f55e.png new file mode 100644 index 00000000..6b440248 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f55e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f55f.png b/twake/frontend/public/public/emojione/128/1f55f.png new file mode 100644 index 00000000..399bbbd0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f55f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f560.png b/twake/frontend/public/public/emojione/128/1f560.png new file mode 100644 index 00000000..afdabe3c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f560.png differ diff --git a/twake/frontend/public/public/emojione/128/1f561.png b/twake/frontend/public/public/emojione/128/1f561.png new file mode 100644 index 00000000..21cee161 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f561.png differ diff --git a/twake/frontend/public/public/emojione/128/1f562.png b/twake/frontend/public/public/emojione/128/1f562.png new file mode 100644 index 00000000..5bd93d5a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f562.png differ diff --git a/twake/frontend/public/public/emojione/128/1f563.png b/twake/frontend/public/public/emojione/128/1f563.png new file mode 100644 index 00000000..1a6713f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f563.png differ diff --git a/twake/frontend/public/public/emojione/128/1f564.png b/twake/frontend/public/public/emojione/128/1f564.png new file mode 100644 index 00000000..a2d947e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f564.png differ diff --git a/twake/frontend/public/public/emojione/128/1f565.png b/twake/frontend/public/public/emojione/128/1f565.png new file mode 100644 index 00000000..cbd63058 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f565.png differ diff --git a/twake/frontend/public/public/emojione/128/1f566.png b/twake/frontend/public/public/emojione/128/1f566.png new file mode 100644 index 00000000..75ffdfaf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f566.png differ diff --git a/twake/frontend/public/public/emojione/128/1f567.png b/twake/frontend/public/public/emojione/128/1f567.png new file mode 100644 index 00000000..9d98b0e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f567.png differ diff --git a/twake/frontend/public/public/emojione/128/1f56f.png b/twake/frontend/public/public/emojione/128/1f56f.png new file mode 100644 index 00000000..d98e9d7e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f56f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f570.png b/twake/frontend/public/public/emojione/128/1f570.png new file mode 100644 index 00000000..e495aeba Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f570.png differ diff --git a/twake/frontend/public/public/emojione/128/1f573.png b/twake/frontend/public/public/emojione/128/1f573.png new file mode 100644 index 00000000..9dcfbcb4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f573.png differ diff --git a/twake/frontend/public/public/emojione/128/1f574-1f3fb.png b/twake/frontend/public/public/emojione/128/1f574-1f3fb.png new file mode 100644 index 00000000..11260b43 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f574-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f574-1f3fc.png b/twake/frontend/public/public/emojione/128/1f574-1f3fc.png new file mode 100644 index 00000000..ba499b95 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f574-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f574-1f3fd.png b/twake/frontend/public/public/emojione/128/1f574-1f3fd.png new file mode 100644 index 00000000..0ea494ca Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f574-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f574-1f3fe.png b/twake/frontend/public/public/emojione/128/1f574-1f3fe.png new file mode 100644 index 00000000..c1889f31 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f574-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f574-1f3ff.png b/twake/frontend/public/public/emojione/128/1f574-1f3ff.png new file mode 100644 index 00000000..86c19cbb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f574-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f574.png b/twake/frontend/public/public/emojione/128/1f574.png new file mode 100644 index 00000000..36f4222e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f574.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f575-1f3fb-2640.png new file mode 100644 index 00000000..1b6b2f77 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f575-1f3fb-2642.png new file mode 100644 index 00000000..fb65f55f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575-1f3fb.png b/twake/frontend/public/public/emojione/128/1f575-1f3fb.png new file mode 100644 index 00000000..fb65f55f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f575-1f3fc-2640.png new file mode 100644 index 00000000..80a80629 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f575-1f3fc-2642.png new file mode 100644 index 00000000..c2cb562d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575-1f3fc.png b/twake/frontend/public/public/emojione/128/1f575-1f3fc.png new file mode 100644 index 00000000..c2cb562d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f575-1f3fd-2640.png new file mode 100644 index 00000000..16ce245e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f575-1f3fd-2642.png new file mode 100644 index 00000000..fd4add6a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575-1f3fd.png b/twake/frontend/public/public/emojione/128/1f575-1f3fd.png new file mode 100644 index 00000000..fd4add6a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f575-1f3fe-2640.png new file mode 100644 index 00000000..c9933088 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f575-1f3fe-2642.png new file mode 100644 index 00000000..6a91ee48 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575-1f3fe.png b/twake/frontend/public/public/emojione/128/1f575-1f3fe.png new file mode 100644 index 00000000..6a91ee48 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f575-1f3ff-2640.png new file mode 100644 index 00000000..c9d10883 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f575-1f3ff-2642.png new file mode 100644 index 00000000..76b064f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575-1f3ff.png b/twake/frontend/public/public/emojione/128/1f575-1f3ff.png new file mode 100644 index 00000000..76b064f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575-2640.png b/twake/frontend/public/public/emojione/128/1f575-2640.png new file mode 100644 index 00000000..c3e8d5ea Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575-2642.png b/twake/frontend/public/public/emojione/128/1f575-2642.png new file mode 100644 index 00000000..28198f5d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f575.png b/twake/frontend/public/public/emojione/128/1f575.png new file mode 100644 index 00000000..28198f5d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f575.png differ diff --git a/twake/frontend/public/public/emojione/128/1f576.png b/twake/frontend/public/public/emojione/128/1f576.png new file mode 100644 index 00000000..31b1bcf9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f576.png differ diff --git a/twake/frontend/public/public/emojione/128/1f577.png b/twake/frontend/public/public/emojione/128/1f577.png new file mode 100644 index 00000000..4964f4b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f577.png differ diff --git a/twake/frontend/public/public/emojione/128/1f578.png b/twake/frontend/public/public/emojione/128/1f578.png new file mode 100644 index 00000000..3bf49386 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f578.png differ diff --git a/twake/frontend/public/public/emojione/128/1f579.png b/twake/frontend/public/public/emojione/128/1f579.png new file mode 100644 index 00000000..4fc00c7b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f579.png differ diff --git a/twake/frontend/public/public/emojione/128/1f57a-1f3fb.png b/twake/frontend/public/public/emojione/128/1f57a-1f3fb.png new file mode 100644 index 00000000..5c9e8a36 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f57a-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f57a-1f3fc.png b/twake/frontend/public/public/emojione/128/1f57a-1f3fc.png new file mode 100644 index 00000000..eecd79e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f57a-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f57a-1f3fd.png b/twake/frontend/public/public/emojione/128/1f57a-1f3fd.png new file mode 100644 index 00000000..2a705122 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f57a-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f57a-1f3fe.png b/twake/frontend/public/public/emojione/128/1f57a-1f3fe.png new file mode 100644 index 00000000..22838d45 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f57a-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f57a-1f3ff.png b/twake/frontend/public/public/emojione/128/1f57a-1f3ff.png new file mode 100644 index 00000000..a5f7b310 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f57a-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f57a.png b/twake/frontend/public/public/emojione/128/1f57a.png new file mode 100644 index 00000000..f4863bf8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f57a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f587.png b/twake/frontend/public/public/emojione/128/1f587.png new file mode 100644 index 00000000..061dc5bd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f587.png differ diff --git a/twake/frontend/public/public/emojione/128/1f58a.png b/twake/frontend/public/public/emojione/128/1f58a.png new file mode 100644 index 00000000..19ce5492 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f58a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f58b.png b/twake/frontend/public/public/emojione/128/1f58b.png new file mode 100644 index 00000000..c66ca448 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f58b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f58c.png b/twake/frontend/public/public/emojione/128/1f58c.png new file mode 100644 index 00000000..730c8c8c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f58c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f58d.png b/twake/frontend/public/public/emojione/128/1f58d.png new file mode 100644 index 00000000..a289880b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f58d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f590-1f3fb.png b/twake/frontend/public/public/emojione/128/1f590-1f3fb.png new file mode 100644 index 00000000..8f61b7c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f590-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f590-1f3fc.png b/twake/frontend/public/public/emojione/128/1f590-1f3fc.png new file mode 100644 index 00000000..a8b1847a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f590-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f590-1f3fd.png b/twake/frontend/public/public/emojione/128/1f590-1f3fd.png new file mode 100644 index 00000000..e9930777 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f590-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f590-1f3fe.png b/twake/frontend/public/public/emojione/128/1f590-1f3fe.png new file mode 100644 index 00000000..7b1913fd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f590-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f590-1f3ff.png b/twake/frontend/public/public/emojione/128/1f590-1f3ff.png new file mode 100644 index 00000000..218181b6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f590-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f590.png b/twake/frontend/public/public/emojione/128/1f590.png new file mode 100644 index 00000000..c14d8f47 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f590.png differ diff --git a/twake/frontend/public/public/emojione/128/1f595-1f3fb.png b/twake/frontend/public/public/emojione/128/1f595-1f3fb.png new file mode 100644 index 00000000..234d21ef Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f595-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f595-1f3fc.png b/twake/frontend/public/public/emojione/128/1f595-1f3fc.png new file mode 100644 index 00000000..9d9f66b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f595-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f595-1f3fd.png b/twake/frontend/public/public/emojione/128/1f595-1f3fd.png new file mode 100644 index 00000000..bc2b3b88 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f595-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f595-1f3fe.png b/twake/frontend/public/public/emojione/128/1f595-1f3fe.png new file mode 100644 index 00000000..7a7a49d3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f595-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f595-1f3ff.png b/twake/frontend/public/public/emojione/128/1f595-1f3ff.png new file mode 100644 index 00000000..148af693 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f595-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f595.png b/twake/frontend/public/public/emojione/128/1f595.png new file mode 100644 index 00000000..c7b42810 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f595.png differ diff --git a/twake/frontend/public/public/emojione/128/1f596-1f3fb.png b/twake/frontend/public/public/emojione/128/1f596-1f3fb.png new file mode 100644 index 00000000..9b38f511 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f596-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f596-1f3fc.png b/twake/frontend/public/public/emojione/128/1f596-1f3fc.png new file mode 100644 index 00000000..82971964 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f596-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f596-1f3fd.png b/twake/frontend/public/public/emojione/128/1f596-1f3fd.png new file mode 100644 index 00000000..bd184984 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f596-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f596-1f3fe.png b/twake/frontend/public/public/emojione/128/1f596-1f3fe.png new file mode 100644 index 00000000..24ca90e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f596-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f596-1f3ff.png b/twake/frontend/public/public/emojione/128/1f596-1f3ff.png new file mode 100644 index 00000000..de3d9e34 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f596-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f596.png b/twake/frontend/public/public/emojione/128/1f596.png new file mode 100644 index 00000000..96675b8f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f596.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5a4.png b/twake/frontend/public/public/emojione/128/1f5a4.png new file mode 100644 index 00000000..a3e41676 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5a4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5a5.png b/twake/frontend/public/public/emojione/128/1f5a5.png new file mode 100644 index 00000000..33c37c59 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5a5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5a8.png b/twake/frontend/public/public/emojione/128/1f5a8.png new file mode 100644 index 00000000..ec0939d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5a8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5b1.png b/twake/frontend/public/public/emojione/128/1f5b1.png new file mode 100644 index 00000000..de3d892a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5b1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5b2.png b/twake/frontend/public/public/emojione/128/1f5b2.png new file mode 100644 index 00000000..a67d0e5c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5b2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5bc.png b/twake/frontend/public/public/emojione/128/1f5bc.png new file mode 100644 index 00000000..b50a340a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5bc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5c2.png b/twake/frontend/public/public/emojione/128/1f5c2.png new file mode 100644 index 00000000..ccbf15b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5c2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5c3.png b/twake/frontend/public/public/emojione/128/1f5c3.png new file mode 100644 index 00000000..28b5ccaf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5c3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5c4.png b/twake/frontend/public/public/emojione/128/1f5c4.png new file mode 100644 index 00000000..bfb41a68 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5c4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5d1.png b/twake/frontend/public/public/emojione/128/1f5d1.png new file mode 100644 index 00000000..eca41d5f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5d1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5d2.png b/twake/frontend/public/public/emojione/128/1f5d2.png new file mode 100644 index 00000000..73049bd5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5d2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5d3.png b/twake/frontend/public/public/emojione/128/1f5d3.png new file mode 100644 index 00000000..7f167ec6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5d3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5dc.png b/twake/frontend/public/public/emojione/128/1f5dc.png new file mode 100644 index 00000000..83192c4a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5dc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5dd.png b/twake/frontend/public/public/emojione/128/1f5dd.png new file mode 100644 index 00000000..f3fe9fda Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5dd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5de.png b/twake/frontend/public/public/emojione/128/1f5de.png new file mode 100644 index 00000000..6d3ca22c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5de.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5e1.png b/twake/frontend/public/public/emojione/128/1f5e1.png new file mode 100644 index 00000000..98fa065e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5e1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5e3.png b/twake/frontend/public/public/emojione/128/1f5e3.png new file mode 100644 index 00000000..984e1d7d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5e3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5e8.png b/twake/frontend/public/public/emojione/128/1f5e8.png new file mode 100644 index 00000000..a162e587 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5e8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5ef.png b/twake/frontend/public/public/emojione/128/1f5ef.png new file mode 100644 index 00000000..80f98d66 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5ef.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5f3.png b/twake/frontend/public/public/emojione/128/1f5f3.png new file mode 100644 index 00000000..edfb15bb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5fa.png b/twake/frontend/public/public/emojione/128/1f5fa.png new file mode 100644 index 00000000..613848ac Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5fa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5fb.png b/twake/frontend/public/public/emojione/128/1f5fb.png new file mode 100644 index 00000000..6914c0b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5fc.png b/twake/frontend/public/public/emojione/128/1f5fc.png new file mode 100644 index 00000000..132d7058 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5fd.png b/twake/frontend/public/public/emojione/128/1f5fd.png new file mode 100644 index 00000000..67dc3a65 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5fe.png b/twake/frontend/public/public/emojione/128/1f5fe.png new file mode 100644 index 00000000..a053ec0d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f5ff.png b/twake/frontend/public/public/emojione/128/1f5ff.png new file mode 100644 index 00000000..6086e26c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f5ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f600.png b/twake/frontend/public/public/emojione/128/1f600.png new file mode 100644 index 00000000..89a2fd45 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f600.png differ diff --git a/twake/frontend/public/public/emojione/128/1f601.png b/twake/frontend/public/public/emojione/128/1f601.png new file mode 100644 index 00000000..7f94d5e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f601.png differ diff --git a/twake/frontend/public/public/emojione/128/1f602.png b/twake/frontend/public/public/emojione/128/1f602.png new file mode 100644 index 00000000..d9a28d2a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f602.png differ diff --git a/twake/frontend/public/public/emojione/128/1f603.png b/twake/frontend/public/public/emojione/128/1f603.png new file mode 100644 index 00000000..389933a6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f603.png differ diff --git a/twake/frontend/public/public/emojione/128/1f604.png b/twake/frontend/public/public/emojione/128/1f604.png new file mode 100644 index 00000000..ceee5228 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f604.png differ diff --git a/twake/frontend/public/public/emojione/128/1f605.png b/twake/frontend/public/public/emojione/128/1f605.png new file mode 100644 index 00000000..612b4a36 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f605.png differ diff --git a/twake/frontend/public/public/emojione/128/1f606.png b/twake/frontend/public/public/emojione/128/1f606.png new file mode 100644 index 00000000..fa3d023a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f606.png differ diff --git a/twake/frontend/public/public/emojione/128/1f607.png b/twake/frontend/public/public/emojione/128/1f607.png new file mode 100644 index 00000000..c07f2d24 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f607.png differ diff --git a/twake/frontend/public/public/emojione/128/1f608.png b/twake/frontend/public/public/emojione/128/1f608.png new file mode 100644 index 00000000..0eb82e43 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f608.png differ diff --git a/twake/frontend/public/public/emojione/128/1f609.png b/twake/frontend/public/public/emojione/128/1f609.png new file mode 100644 index 00000000..1c724624 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f609.png differ diff --git a/twake/frontend/public/public/emojione/128/1f60a.png b/twake/frontend/public/public/emojione/128/1f60a.png new file mode 100644 index 00000000..5cd616f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f60a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f60b.png b/twake/frontend/public/public/emojione/128/1f60b.png new file mode 100644 index 00000000..f2e59529 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f60b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f60c.png b/twake/frontend/public/public/emojione/128/1f60c.png new file mode 100644 index 00000000..a421b25f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f60c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f60d.png b/twake/frontend/public/public/emojione/128/1f60d.png new file mode 100644 index 00000000..3e8bd40f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f60d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f60e.png b/twake/frontend/public/public/emojione/128/1f60e.png new file mode 100644 index 00000000..54efdc42 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f60e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f60f.png b/twake/frontend/public/public/emojione/128/1f60f.png new file mode 100644 index 00000000..0a0d4fcb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f60f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f610.png b/twake/frontend/public/public/emojione/128/1f610.png new file mode 100644 index 00000000..19fe79d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f610.png differ diff --git a/twake/frontend/public/public/emojione/128/1f611.png b/twake/frontend/public/public/emojione/128/1f611.png new file mode 100644 index 00000000..72ff5e85 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f611.png differ diff --git a/twake/frontend/public/public/emojione/128/1f612.png b/twake/frontend/public/public/emojione/128/1f612.png new file mode 100644 index 00000000..2fb1015c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f612.png differ diff --git a/twake/frontend/public/public/emojione/128/1f613.png b/twake/frontend/public/public/emojione/128/1f613.png new file mode 100644 index 00000000..4cd1b3c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f613.png differ diff --git a/twake/frontend/public/public/emojione/128/1f614.png b/twake/frontend/public/public/emojione/128/1f614.png new file mode 100644 index 00000000..52320b46 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f614.png differ diff --git a/twake/frontend/public/public/emojione/128/1f615.png b/twake/frontend/public/public/emojione/128/1f615.png new file mode 100644 index 00000000..18fd6e17 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f615.png differ diff --git a/twake/frontend/public/public/emojione/128/1f616.png b/twake/frontend/public/public/emojione/128/1f616.png new file mode 100644 index 00000000..810b65c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f616.png differ diff --git a/twake/frontend/public/public/emojione/128/1f617.png b/twake/frontend/public/public/emojione/128/1f617.png new file mode 100644 index 00000000..f13bbb62 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f617.png differ diff --git a/twake/frontend/public/public/emojione/128/1f618.png b/twake/frontend/public/public/emojione/128/1f618.png new file mode 100644 index 00000000..03a39934 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f618.png differ diff --git a/twake/frontend/public/public/emojione/128/1f619.png b/twake/frontend/public/public/emojione/128/1f619.png new file mode 100644 index 00000000..fed8e497 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f619.png differ diff --git a/twake/frontend/public/public/emojione/128/1f61a.png b/twake/frontend/public/public/emojione/128/1f61a.png new file mode 100644 index 00000000..7e9ac5d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f61a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f61b.png b/twake/frontend/public/public/emojione/128/1f61b.png new file mode 100644 index 00000000..fc8296dc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f61b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f61c.png b/twake/frontend/public/public/emojione/128/1f61c.png new file mode 100644 index 00000000..e1fed263 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f61c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f61d.png b/twake/frontend/public/public/emojione/128/1f61d.png new file mode 100644 index 00000000..10a5fb4b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f61d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f61e.png b/twake/frontend/public/public/emojione/128/1f61e.png new file mode 100644 index 00000000..c8ce427f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f61e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f61f.png b/twake/frontend/public/public/emojione/128/1f61f.png new file mode 100644 index 00000000..7980701d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f61f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f620.png b/twake/frontend/public/public/emojione/128/1f620.png new file mode 100644 index 00000000..f9a741ec Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f620.png differ diff --git a/twake/frontend/public/public/emojione/128/1f621.png b/twake/frontend/public/public/emojione/128/1f621.png new file mode 100644 index 00000000..c28e2aac Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f621.png differ diff --git a/twake/frontend/public/public/emojione/128/1f622.png b/twake/frontend/public/public/emojione/128/1f622.png new file mode 100644 index 00000000..1eabaf54 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f622.png differ diff --git a/twake/frontend/public/public/emojione/128/1f623.png b/twake/frontend/public/public/emojione/128/1f623.png new file mode 100644 index 00000000..252a84fe Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f623.png differ diff --git a/twake/frontend/public/public/emojione/128/1f624.png b/twake/frontend/public/public/emojione/128/1f624.png new file mode 100644 index 00000000..8005c833 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f624.png differ diff --git a/twake/frontend/public/public/emojione/128/1f625.png b/twake/frontend/public/public/emojione/128/1f625.png new file mode 100644 index 00000000..72d7759a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f625.png differ diff --git a/twake/frontend/public/public/emojione/128/1f626.png b/twake/frontend/public/public/emojione/128/1f626.png new file mode 100644 index 00000000..b499cd22 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f626.png differ diff --git a/twake/frontend/public/public/emojione/128/1f627.png b/twake/frontend/public/public/emojione/128/1f627.png new file mode 100644 index 00000000..a055172b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f627.png differ diff --git a/twake/frontend/public/public/emojione/128/1f628.png b/twake/frontend/public/public/emojione/128/1f628.png new file mode 100644 index 00000000..f77eaa58 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f628.png differ diff --git a/twake/frontend/public/public/emojione/128/1f629.png b/twake/frontend/public/public/emojione/128/1f629.png new file mode 100644 index 00000000..1e15238b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f629.png differ diff --git a/twake/frontend/public/public/emojione/128/1f62a.png b/twake/frontend/public/public/emojione/128/1f62a.png new file mode 100644 index 00000000..80d417fb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f62a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f62b.png b/twake/frontend/public/public/emojione/128/1f62b.png new file mode 100644 index 00000000..376264e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f62b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f62c.png b/twake/frontend/public/public/emojione/128/1f62c.png new file mode 100644 index 00000000..3cb315e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f62c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f62d.png b/twake/frontend/public/public/emojione/128/1f62d.png new file mode 100644 index 00000000..4ad6ea7b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f62d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f62e.png b/twake/frontend/public/public/emojione/128/1f62e.png new file mode 100644 index 00000000..bbe391d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f62e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f62f.png b/twake/frontend/public/public/emojione/128/1f62f.png new file mode 100644 index 00000000..3cab94e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f62f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f630.png b/twake/frontend/public/public/emojione/128/1f630.png new file mode 100644 index 00000000..fee47741 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f630.png differ diff --git a/twake/frontend/public/public/emojione/128/1f631.png b/twake/frontend/public/public/emojione/128/1f631.png new file mode 100644 index 00000000..ce597bcd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f631.png differ diff --git a/twake/frontend/public/public/emojione/128/1f632.png b/twake/frontend/public/public/emojione/128/1f632.png new file mode 100644 index 00000000..d3bdc847 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f632.png differ diff --git a/twake/frontend/public/public/emojione/128/1f633.png b/twake/frontend/public/public/emojione/128/1f633.png new file mode 100644 index 00000000..76782278 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f633.png differ diff --git a/twake/frontend/public/public/emojione/128/1f634.png b/twake/frontend/public/public/emojione/128/1f634.png new file mode 100644 index 00000000..8c00788c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f634.png differ diff --git a/twake/frontend/public/public/emojione/128/1f635.png b/twake/frontend/public/public/emojione/128/1f635.png new file mode 100644 index 00000000..892bd42b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f635.png differ diff --git a/twake/frontend/public/public/emojione/128/1f636.png b/twake/frontend/public/public/emojione/128/1f636.png new file mode 100644 index 00000000..95c5c275 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f636.png differ diff --git a/twake/frontend/public/public/emojione/128/1f637.png b/twake/frontend/public/public/emojione/128/1f637.png new file mode 100644 index 00000000..52947a64 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f637.png differ diff --git a/twake/frontend/public/public/emojione/128/1f638.png b/twake/frontend/public/public/emojione/128/1f638.png new file mode 100644 index 00000000..a2da72ed Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f638.png differ diff --git a/twake/frontend/public/public/emojione/128/1f639.png b/twake/frontend/public/public/emojione/128/1f639.png new file mode 100644 index 00000000..1d396b66 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f639.png differ diff --git a/twake/frontend/public/public/emojione/128/1f63a.png b/twake/frontend/public/public/emojione/128/1f63a.png new file mode 100644 index 00000000..17c1d71a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f63a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f63b.png b/twake/frontend/public/public/emojione/128/1f63b.png new file mode 100644 index 00000000..b6b87b4f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f63b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f63c.png b/twake/frontend/public/public/emojione/128/1f63c.png new file mode 100644 index 00000000..d1dd7d75 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f63c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f63d.png b/twake/frontend/public/public/emojione/128/1f63d.png new file mode 100644 index 00000000..5c319b24 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f63d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f63e.png b/twake/frontend/public/public/emojione/128/1f63e.png new file mode 100644 index 00000000..35e10c38 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f63e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f63f.png b/twake/frontend/public/public/emojione/128/1f63f.png new file mode 100644 index 00000000..dc4aadcc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f63f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f640.png b/twake/frontend/public/public/emojione/128/1f640.png new file mode 100644 index 00000000..7b604965 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f641.png b/twake/frontend/public/public/emojione/128/1f641.png new file mode 100644 index 00000000..b59e0837 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f641.png differ diff --git a/twake/frontend/public/public/emojione/128/1f642.png b/twake/frontend/public/public/emojione/128/1f642.png new file mode 100644 index 00000000..d974d23e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f643.png b/twake/frontend/public/public/emojione/128/1f643.png new file mode 100644 index 00000000..1068f27b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f643.png differ diff --git a/twake/frontend/public/public/emojione/128/1f644.png b/twake/frontend/public/public/emojione/128/1f644.png new file mode 100644 index 00000000..ddad2974 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f644.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f645-1f3fb-2640.png new file mode 100644 index 00000000..b5060b26 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f645-1f3fb-2642.png new file mode 100644 index 00000000..40082abe Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645-1f3fb.png b/twake/frontend/public/public/emojione/128/1f645-1f3fb.png new file mode 100644 index 00000000..e075de11 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f645-1f3fc-2640.png new file mode 100644 index 00000000..83ff7fe8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f645-1f3fc-2642.png new file mode 100644 index 00000000..043a89d5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645-1f3fc.png b/twake/frontend/public/public/emojione/128/1f645-1f3fc.png new file mode 100644 index 00000000..a3ad4848 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f645-1f3fd-2640.png new file mode 100644 index 00000000..178dd42b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f645-1f3fd-2642.png new file mode 100644 index 00000000..82255f40 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645-1f3fd.png b/twake/frontend/public/public/emojione/128/1f645-1f3fd.png new file mode 100644 index 00000000..5d87983d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f645-1f3fe-2640.png new file mode 100644 index 00000000..d1e7c89a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f645-1f3fe-2642.png new file mode 100644 index 00000000..eaf07ef5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645-1f3fe.png b/twake/frontend/public/public/emojione/128/1f645-1f3fe.png new file mode 100644 index 00000000..d5663bad Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f645-1f3ff-2640.png new file mode 100644 index 00000000..d1138718 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f645-1f3ff-2642.png new file mode 100644 index 00000000..0270a0f4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645-1f3ff.png b/twake/frontend/public/public/emojione/128/1f645-1f3ff.png new file mode 100644 index 00000000..fe399136 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645-2640.png b/twake/frontend/public/public/emojione/128/1f645-2640.png new file mode 100644 index 00000000..c2ae56d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645-2642.png b/twake/frontend/public/public/emojione/128/1f645-2642.png new file mode 100644 index 00000000..d526a137 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f645.png b/twake/frontend/public/public/emojione/128/1f645.png new file mode 100644 index 00000000..c2ae56d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f645.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f646-1f3fb-2640.png new file mode 100644 index 00000000..539c3356 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f646-1f3fb-2642.png new file mode 100644 index 00000000..11e017c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646-1f3fb.png b/twake/frontend/public/public/emojione/128/1f646-1f3fb.png new file mode 100644 index 00000000..a5b48949 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f646-1f3fc-2640.png new file mode 100644 index 00000000..4e36a5af Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f646-1f3fc-2642.png new file mode 100644 index 00000000..3d8096f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646-1f3fc.png b/twake/frontend/public/public/emojione/128/1f646-1f3fc.png new file mode 100644 index 00000000..84ef9eee Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f646-1f3fd-2640.png new file mode 100644 index 00000000..fda3d034 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f646-1f3fd-2642.png new file mode 100644 index 00000000..dd626173 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646-1f3fd.png b/twake/frontend/public/public/emojione/128/1f646-1f3fd.png new file mode 100644 index 00000000..6deb8217 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f646-1f3fe-2640.png new file mode 100644 index 00000000..37d439a4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f646-1f3fe-2642.png new file mode 100644 index 00000000..80d7b1b6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646-1f3fe.png b/twake/frontend/public/public/emojione/128/1f646-1f3fe.png new file mode 100644 index 00000000..a1c21840 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f646-1f3ff-2640.png new file mode 100644 index 00000000..eaab1701 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f646-1f3ff-2642.png new file mode 100644 index 00000000..5db1287b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646-1f3ff.png b/twake/frontend/public/public/emojione/128/1f646-1f3ff.png new file mode 100644 index 00000000..eb916c42 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646-2640.png b/twake/frontend/public/public/emojione/128/1f646-2640.png new file mode 100644 index 00000000..ab63d419 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646-2642.png b/twake/frontend/public/public/emojione/128/1f646-2642.png new file mode 100644 index 00000000..67d3cab0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f646.png b/twake/frontend/public/public/emojione/128/1f646.png new file mode 100644 index 00000000..fbe40da9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f646.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f647-1f3fb-2640.png new file mode 100644 index 00000000..9e13363b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f647-1f3fb-2642.png new file mode 100644 index 00000000..547de6c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647-1f3fb.png b/twake/frontend/public/public/emojione/128/1f647-1f3fb.png new file mode 100644 index 00000000..547de6c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f647-1f3fc-2640.png new file mode 100644 index 00000000..04f49db9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f647-1f3fc-2642.png new file mode 100644 index 00000000..d51fa5cf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647-1f3fc.png b/twake/frontend/public/public/emojione/128/1f647-1f3fc.png new file mode 100644 index 00000000..d51fa5cf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f647-1f3fd-2640.png new file mode 100644 index 00000000..296ff73f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f647-1f3fd-2642.png new file mode 100644 index 00000000..e69f9c9e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647-1f3fd.png b/twake/frontend/public/public/emojione/128/1f647-1f3fd.png new file mode 100644 index 00000000..e69f9c9e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f647-1f3fe-2640.png new file mode 100644 index 00000000..854b520a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f647-1f3fe-2642.png new file mode 100644 index 00000000..c665432f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647-1f3fe.png b/twake/frontend/public/public/emojione/128/1f647-1f3fe.png new file mode 100644 index 00000000..c665432f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f647-1f3ff-2640.png new file mode 100644 index 00000000..aab4ba5b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f647-1f3ff-2642.png new file mode 100644 index 00000000..01815ff7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647-1f3ff.png b/twake/frontend/public/public/emojione/128/1f647-1f3ff.png new file mode 100644 index 00000000..01815ff7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647-2640.png b/twake/frontend/public/public/emojione/128/1f647-2640.png new file mode 100644 index 00000000..022d645f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647-2642.png b/twake/frontend/public/public/emojione/128/1f647-2642.png new file mode 100644 index 00000000..4a1045d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f647.png b/twake/frontend/public/public/emojione/128/1f647.png new file mode 100644 index 00000000..4a1045d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f647.png differ diff --git a/twake/frontend/public/public/emojione/128/1f648.png b/twake/frontend/public/public/emojione/128/1f648.png new file mode 100644 index 00000000..12621e9a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f648.png differ diff --git a/twake/frontend/public/public/emojione/128/1f649.png b/twake/frontend/public/public/emojione/128/1f649.png new file mode 100644 index 00000000..00b49912 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f649.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64a.png b/twake/frontend/public/public/emojione/128/1f64a.png new file mode 100644 index 00000000..51af6dab Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f64b-1f3fb-2640.png new file mode 100644 index 00000000..95dab8a1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f64b-1f3fb-2642.png new file mode 100644 index 00000000..d3a8bffa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b-1f3fb.png b/twake/frontend/public/public/emojione/128/1f64b-1f3fb.png new file mode 100644 index 00000000..f28af25e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f64b-1f3fc-2640.png new file mode 100644 index 00000000..52b2baf2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f64b-1f3fc-2642.png new file mode 100644 index 00000000..8a617fb6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b-1f3fc.png b/twake/frontend/public/public/emojione/128/1f64b-1f3fc.png new file mode 100644 index 00000000..1c25a7d3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f64b-1f3fd-2640.png new file mode 100644 index 00000000..fc41e29a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f64b-1f3fd-2642.png new file mode 100644 index 00000000..d8427529 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b-1f3fd.png b/twake/frontend/public/public/emojione/128/1f64b-1f3fd.png new file mode 100644 index 00000000..cead2536 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f64b-1f3fe-2640.png new file mode 100644 index 00000000..9e81706a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f64b-1f3fe-2642.png new file mode 100644 index 00000000..c6cc19ca Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b-1f3fe.png b/twake/frontend/public/public/emojione/128/1f64b-1f3fe.png new file mode 100644 index 00000000..6b412583 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f64b-1f3ff-2640.png new file mode 100644 index 00000000..32a59edb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f64b-1f3ff-2642.png new file mode 100644 index 00000000..d3ac6377 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b-1f3ff.png b/twake/frontend/public/public/emojione/128/1f64b-1f3ff.png new file mode 100644 index 00000000..89016b16 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b-2640.png b/twake/frontend/public/public/emojione/128/1f64b-2640.png new file mode 100644 index 00000000..16f001d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b-2642.png b/twake/frontend/public/public/emojione/128/1f64b-2642.png new file mode 100644 index 00000000..ccdef719 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64b.png b/twake/frontend/public/public/emojione/128/1f64b.png new file mode 100644 index 00000000..16f001d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64c-1f3fb.png b/twake/frontend/public/public/emojione/128/1f64c-1f3fb.png new file mode 100644 index 00000000..9acf2c7a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64c-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64c-1f3fc.png b/twake/frontend/public/public/emojione/128/1f64c-1f3fc.png new file mode 100644 index 00000000..55a6ea84 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64c-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64c-1f3fd.png b/twake/frontend/public/public/emojione/128/1f64c-1f3fd.png new file mode 100644 index 00000000..b38838fc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64c-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64c-1f3fe.png b/twake/frontend/public/public/emojione/128/1f64c-1f3fe.png new file mode 100644 index 00000000..fcd2204d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64c-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64c-1f3ff.png b/twake/frontend/public/public/emojione/128/1f64c-1f3ff.png new file mode 100644 index 00000000..8ee0355d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64c-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64c.png b/twake/frontend/public/public/emojione/128/1f64c.png new file mode 100644 index 00000000..4a54e67f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f64d-1f3fb-2640.png new file mode 100644 index 00000000..df702ef5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f64d-1f3fb-2642.png new file mode 100644 index 00000000..aca8566b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d-1f3fb.png b/twake/frontend/public/public/emojione/128/1f64d-1f3fb.png new file mode 100644 index 00000000..076132c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f64d-1f3fc-2640.png new file mode 100644 index 00000000..3765a414 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f64d-1f3fc-2642.png new file mode 100644 index 00000000..347b1a35 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d-1f3fc.png b/twake/frontend/public/public/emojione/128/1f64d-1f3fc.png new file mode 100644 index 00000000..906444a4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f64d-1f3fd-2640.png new file mode 100644 index 00000000..32aa10b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f64d-1f3fd-2642.png new file mode 100644 index 00000000..90aff298 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d-1f3fd.png b/twake/frontend/public/public/emojione/128/1f64d-1f3fd.png new file mode 100644 index 00000000..86fe4041 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f64d-1f3fe-2640.png new file mode 100644 index 00000000..1bfa22bd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f64d-1f3fe-2642.png new file mode 100644 index 00000000..d23ef3ee Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d-1f3fe.png b/twake/frontend/public/public/emojione/128/1f64d-1f3fe.png new file mode 100644 index 00000000..bc571bd9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f64d-1f3ff-2640.png new file mode 100644 index 00000000..41ab2f19 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f64d-1f3ff-2642.png new file mode 100644 index 00000000..01078d37 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d-1f3ff.png b/twake/frontend/public/public/emojione/128/1f64d-1f3ff.png new file mode 100644 index 00000000..b7dc4d04 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d-2640.png b/twake/frontend/public/public/emojione/128/1f64d-2640.png new file mode 100644 index 00000000..ebc42350 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d-2642.png b/twake/frontend/public/public/emojione/128/1f64d-2642.png new file mode 100644 index 00000000..41581daf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64d.png b/twake/frontend/public/public/emojione/128/1f64d.png new file mode 100644 index 00000000..ebc42350 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f64e-1f3fb-2640.png new file mode 100644 index 00000000..b2447296 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f64e-1f3fb-2642.png new file mode 100644 index 00000000..1c3642f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e-1f3fb.png b/twake/frontend/public/public/emojione/128/1f64e-1f3fb.png new file mode 100644 index 00000000..b2447296 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f64e-1f3fc-2640.png new file mode 100644 index 00000000..318fa4d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f64e-1f3fc-2642.png new file mode 100644 index 00000000..13c7642a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e-1f3fc.png b/twake/frontend/public/public/emojione/128/1f64e-1f3fc.png new file mode 100644 index 00000000..233f5856 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f64e-1f3fd-2640.png new file mode 100644 index 00000000..d7709cda Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f64e-1f3fd-2642.png new file mode 100644 index 00000000..5dd0971f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e-1f3fd.png b/twake/frontend/public/public/emojione/128/1f64e-1f3fd.png new file mode 100644 index 00000000..d7709cda Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f64e-1f3fe-2640.png new file mode 100644 index 00000000..39329506 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f64e-1f3fe-2642.png new file mode 100644 index 00000000..ab2b0fb5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e-1f3fe.png b/twake/frontend/public/public/emojione/128/1f64e-1f3fe.png new file mode 100644 index 00000000..39329506 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f64e-1f3ff-2640.png new file mode 100644 index 00000000..e76d69ef Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f64e-1f3ff-2642.png new file mode 100644 index 00000000..79786ec2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e-1f3ff.png b/twake/frontend/public/public/emojione/128/1f64e-1f3ff.png new file mode 100644 index 00000000..e76d69ef Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e-2640.png b/twake/frontend/public/public/emojione/128/1f64e-2640.png new file mode 100644 index 00000000..c6bee17f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e-2642.png b/twake/frontend/public/public/emojione/128/1f64e-2642.png new file mode 100644 index 00000000..6cf79341 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64e.png b/twake/frontend/public/public/emojione/128/1f64e.png new file mode 100644 index 00000000..c6bee17f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64f-1f3fb.png b/twake/frontend/public/public/emojione/128/1f64f-1f3fb.png new file mode 100644 index 00000000..115a06bb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64f-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64f-1f3fc.png b/twake/frontend/public/public/emojione/128/1f64f-1f3fc.png new file mode 100644 index 00000000..c3052520 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64f-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64f-1f3fd.png b/twake/frontend/public/public/emojione/128/1f64f-1f3fd.png new file mode 100644 index 00000000..c5370bb3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64f-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64f-1f3fe.png b/twake/frontend/public/public/emojione/128/1f64f-1f3fe.png new file mode 100644 index 00000000..f7e06569 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64f-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64f-1f3ff.png b/twake/frontend/public/public/emojione/128/1f64f-1f3ff.png new file mode 100644 index 00000000..742aede3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64f-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f64f.png b/twake/frontend/public/public/emojione/128/1f64f.png new file mode 100644 index 00000000..58ea5c0a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f64f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f680.png b/twake/frontend/public/public/emojione/128/1f680.png new file mode 100644 index 00000000..d6aa70f4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f680.png differ diff --git a/twake/frontend/public/public/emojione/128/1f681.png b/twake/frontend/public/public/emojione/128/1f681.png new file mode 100644 index 00000000..deb4f93b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f681.png differ diff --git a/twake/frontend/public/public/emojione/128/1f682.png b/twake/frontend/public/public/emojione/128/1f682.png new file mode 100644 index 00000000..c0b1c1ee Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f682.png differ diff --git a/twake/frontend/public/public/emojione/128/1f683.png b/twake/frontend/public/public/emojione/128/1f683.png new file mode 100644 index 00000000..84833741 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f683.png differ diff --git a/twake/frontend/public/public/emojione/128/1f684.png b/twake/frontend/public/public/emojione/128/1f684.png new file mode 100644 index 00000000..2e8f02c5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f684.png differ diff --git a/twake/frontend/public/public/emojione/128/1f685.png b/twake/frontend/public/public/emojione/128/1f685.png new file mode 100644 index 00000000..7b46cc5e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f685.png differ diff --git a/twake/frontend/public/public/emojione/128/1f686.png b/twake/frontend/public/public/emojione/128/1f686.png new file mode 100644 index 00000000..91efa7f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f686.png differ diff --git a/twake/frontend/public/public/emojione/128/1f687.png b/twake/frontend/public/public/emojione/128/1f687.png new file mode 100644 index 00000000..a7392bcd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f687.png differ diff --git a/twake/frontend/public/public/emojione/128/1f688.png b/twake/frontend/public/public/emojione/128/1f688.png new file mode 100644 index 00000000..eb344f8e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f688.png differ diff --git a/twake/frontend/public/public/emojione/128/1f689.png b/twake/frontend/public/public/emojione/128/1f689.png new file mode 100644 index 00000000..13de5b40 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f689.png differ diff --git a/twake/frontend/public/public/emojione/128/1f68a.png b/twake/frontend/public/public/emojione/128/1f68a.png new file mode 100644 index 00000000..a4cce3e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f68a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f68b.png b/twake/frontend/public/public/emojione/128/1f68b.png new file mode 100644 index 00000000..0803297f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f68b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f68c.png b/twake/frontend/public/public/emojione/128/1f68c.png new file mode 100644 index 00000000..60ad6760 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f68c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f68d.png b/twake/frontend/public/public/emojione/128/1f68d.png new file mode 100644 index 00000000..cd8de359 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f68d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f68e.png b/twake/frontend/public/public/emojione/128/1f68e.png new file mode 100644 index 00000000..509eb582 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f68e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f68f.png b/twake/frontend/public/public/emojione/128/1f68f.png new file mode 100644 index 00000000..8bca0249 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f68f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f690.png b/twake/frontend/public/public/emojione/128/1f690.png new file mode 100644 index 00000000..16c6fa2b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f690.png differ diff --git a/twake/frontend/public/public/emojione/128/1f691.png b/twake/frontend/public/public/emojione/128/1f691.png new file mode 100644 index 00000000..c3ece90d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f691.png differ diff --git a/twake/frontend/public/public/emojione/128/1f692.png b/twake/frontend/public/public/emojione/128/1f692.png new file mode 100644 index 00000000..3e51e6b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f692.png differ diff --git a/twake/frontend/public/public/emojione/128/1f693.png b/twake/frontend/public/public/emojione/128/1f693.png new file mode 100644 index 00000000..a117a1ef Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f693.png differ diff --git a/twake/frontend/public/public/emojione/128/1f694.png b/twake/frontend/public/public/emojione/128/1f694.png new file mode 100644 index 00000000..13b010a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f694.png differ diff --git a/twake/frontend/public/public/emojione/128/1f695.png b/twake/frontend/public/public/emojione/128/1f695.png new file mode 100644 index 00000000..557116cc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f695.png differ diff --git a/twake/frontend/public/public/emojione/128/1f696.png b/twake/frontend/public/public/emojione/128/1f696.png new file mode 100644 index 00000000..4a74e558 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f696.png differ diff --git a/twake/frontend/public/public/emojione/128/1f697.png b/twake/frontend/public/public/emojione/128/1f697.png new file mode 100644 index 00000000..c5939c60 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f697.png differ diff --git a/twake/frontend/public/public/emojione/128/1f698.png b/twake/frontend/public/public/emojione/128/1f698.png new file mode 100644 index 00000000..1b99135b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f698.png differ diff --git a/twake/frontend/public/public/emojione/128/1f699.png b/twake/frontend/public/public/emojione/128/1f699.png new file mode 100644 index 00000000..179ea0f4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f699.png differ diff --git a/twake/frontend/public/public/emojione/128/1f69a.png b/twake/frontend/public/public/emojione/128/1f69a.png new file mode 100644 index 00000000..ac399db2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f69a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f69b.png b/twake/frontend/public/public/emojione/128/1f69b.png new file mode 100644 index 00000000..d7888208 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f69b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f69c.png b/twake/frontend/public/public/emojione/128/1f69c.png new file mode 100644 index 00000000..6a845f5d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f69c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f69d.png b/twake/frontend/public/public/emojione/128/1f69d.png new file mode 100644 index 00000000..cec16f4d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f69d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f69e.png b/twake/frontend/public/public/emojione/128/1f69e.png new file mode 100644 index 00000000..d7d7ad77 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f69e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f69f.png b/twake/frontend/public/public/emojione/128/1f69f.png new file mode 100644 index 00000000..0664739e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f69f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a0.png b/twake/frontend/public/public/emojione/128/1f6a0.png new file mode 100644 index 00000000..e1a2a8c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a1.png b/twake/frontend/public/public/emojione/128/1f6a1.png new file mode 100644 index 00000000..b3439c42 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a2.png b/twake/frontend/public/public/emojione/128/1f6a2.png new file mode 100644 index 00000000..a6a43514 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f6a3-1f3fb-2640.png new file mode 100644 index 00000000..2c6845d5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f6a3-1f3fb-2642.png new file mode 100644 index 00000000..e0a03f09 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3-1f3fb.png b/twake/frontend/public/public/emojione/128/1f6a3-1f3fb.png new file mode 100644 index 00000000..e0a03f09 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f6a3-1f3fc-2640.png new file mode 100644 index 00000000..641c1b1d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f6a3-1f3fc-2642.png new file mode 100644 index 00000000..7ad98b49 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3-1f3fc.png b/twake/frontend/public/public/emojione/128/1f6a3-1f3fc.png new file mode 100644 index 00000000..7ad98b49 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f6a3-1f3fd-2640.png new file mode 100644 index 00000000..05e6ed74 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f6a3-1f3fd-2642.png new file mode 100644 index 00000000..328c5aa8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3-1f3fd.png b/twake/frontend/public/public/emojione/128/1f6a3-1f3fd.png new file mode 100644 index 00000000..328c5aa8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f6a3-1f3fe-2640.png new file mode 100644 index 00000000..97cc0493 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f6a3-1f3fe-2642.png new file mode 100644 index 00000000..8b4f3c20 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3-1f3fe.png b/twake/frontend/public/public/emojione/128/1f6a3-1f3fe.png new file mode 100644 index 00000000..8b4f3c20 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f6a3-1f3ff-2640.png new file mode 100644 index 00000000..7b2c5e11 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f6a3-1f3ff-2642.png new file mode 100644 index 00000000..c8ec520f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3-1f3ff.png b/twake/frontend/public/public/emojione/128/1f6a3-1f3ff.png new file mode 100644 index 00000000..c8ec520f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3-2640.png b/twake/frontend/public/public/emojione/128/1f6a3-2640.png new file mode 100644 index 00000000..d9d4573d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3-2642.png b/twake/frontend/public/public/emojione/128/1f6a3-2642.png new file mode 100644 index 00000000..cbda6308 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a3.png b/twake/frontend/public/public/emojione/128/1f6a3.png new file mode 100644 index 00000000..cbda6308 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a4.png b/twake/frontend/public/public/emojione/128/1f6a4.png new file mode 100644 index 00000000..4b58400c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a5.png b/twake/frontend/public/public/emojione/128/1f6a5.png new file mode 100644 index 00000000..de9c4c56 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a6.png b/twake/frontend/public/public/emojione/128/1f6a6.png new file mode 100644 index 00000000..17de6716 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a7.png b/twake/frontend/public/public/emojione/128/1f6a7.png new file mode 100644 index 00000000..9eae3409 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a8.png b/twake/frontend/public/public/emojione/128/1f6a8.png new file mode 100644 index 00000000..89efea54 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6a9.png b/twake/frontend/public/public/emojione/128/1f6a9.png new file mode 100644 index 00000000..84329cfc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6a9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6aa.png b/twake/frontend/public/public/emojione/128/1f6aa.png new file mode 100644 index 00000000..54ee6ade Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6aa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6ab.png b/twake/frontend/public/public/emojione/128/1f6ab.png new file mode 100644 index 00000000..3d277f9e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6ab.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6ac.png b/twake/frontend/public/public/emojione/128/1f6ac.png new file mode 100644 index 00000000..44236fd6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6ac.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6ad.png b/twake/frontend/public/public/emojione/128/1f6ad.png new file mode 100644 index 00000000..999c69d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6ad.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6ae.png b/twake/frontend/public/public/emojione/128/1f6ae.png new file mode 100644 index 00000000..e2df2194 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6ae.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6af.png b/twake/frontend/public/public/emojione/128/1f6af.png new file mode 100644 index 00000000..0bffeafe Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6af.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b0.png b/twake/frontend/public/public/emojione/128/1f6b0.png new file mode 100644 index 00000000..475174af Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b1.png b/twake/frontend/public/public/emojione/128/1f6b1.png new file mode 100644 index 00000000..52712410 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b2.png b/twake/frontend/public/public/emojione/128/1f6b2.png new file mode 100644 index 00000000..1e713a73 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b3.png b/twake/frontend/public/public/emojione/128/1f6b3.png new file mode 100644 index 00000000..2d0daa1a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f6b4-1f3fb-2640.png new file mode 100644 index 00000000..850f58c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f6b4-1f3fb-2642.png new file mode 100644 index 00000000..aab7c9c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4-1f3fb.png b/twake/frontend/public/public/emojione/128/1f6b4-1f3fb.png new file mode 100644 index 00000000..aab7c9c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f6b4-1f3fc-2640.png new file mode 100644 index 00000000..e0dbad05 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f6b4-1f3fc-2642.png new file mode 100644 index 00000000..9b3e6a55 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4-1f3fc.png b/twake/frontend/public/public/emojione/128/1f6b4-1f3fc.png new file mode 100644 index 00000000..9b3e6a55 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f6b4-1f3fd-2640.png new file mode 100644 index 00000000..6a875c90 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f6b4-1f3fd-2642.png new file mode 100644 index 00000000..de383a4e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4-1f3fd.png b/twake/frontend/public/public/emojione/128/1f6b4-1f3fd.png new file mode 100644 index 00000000..de383a4e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f6b4-1f3fe-2640.png new file mode 100644 index 00000000..af046d33 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f6b4-1f3fe-2642.png new file mode 100644 index 00000000..af184825 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4-1f3fe.png b/twake/frontend/public/public/emojione/128/1f6b4-1f3fe.png new file mode 100644 index 00000000..af184825 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f6b4-1f3ff-2640.png new file mode 100644 index 00000000..6a5f4707 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f6b4-1f3ff-2642.png new file mode 100644 index 00000000..a9a56136 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4-1f3ff.png b/twake/frontend/public/public/emojione/128/1f6b4-1f3ff.png new file mode 100644 index 00000000..a9a56136 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4-2640.png b/twake/frontend/public/public/emojione/128/1f6b4-2640.png new file mode 100644 index 00000000..87a4a8a8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4-2642.png b/twake/frontend/public/public/emojione/128/1f6b4-2642.png new file mode 100644 index 00000000..deb8d859 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b4.png b/twake/frontend/public/public/emojione/128/1f6b4.png new file mode 100644 index 00000000..deb8d859 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f6b5-1f3fb-2640.png new file mode 100644 index 00000000..a7be9217 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f6b5-1f3fb-2642.png new file mode 100644 index 00000000..09691f33 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5-1f3fb.png b/twake/frontend/public/public/emojione/128/1f6b5-1f3fb.png new file mode 100644 index 00000000..09691f33 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f6b5-1f3fc-2640.png new file mode 100644 index 00000000..8b63b5f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f6b5-1f3fc-2642.png new file mode 100644 index 00000000..ff859d68 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5-1f3fc.png b/twake/frontend/public/public/emojione/128/1f6b5-1f3fc.png new file mode 100644 index 00000000..ff859d68 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f6b5-1f3fd-2640.png new file mode 100644 index 00000000..a55f5164 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f6b5-1f3fd-2642.png new file mode 100644 index 00000000..5033f2e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5-1f3fd.png b/twake/frontend/public/public/emojione/128/1f6b5-1f3fd.png new file mode 100644 index 00000000..5033f2e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f6b5-1f3fe-2640.png new file mode 100644 index 00000000..48d88ee0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f6b5-1f3fe-2642.png new file mode 100644 index 00000000..8dadb91e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5-1f3fe.png b/twake/frontend/public/public/emojione/128/1f6b5-1f3fe.png new file mode 100644 index 00000000..8dadb91e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f6b5-1f3ff-2640.png new file mode 100644 index 00000000..c012ea5a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f6b5-1f3ff-2642.png new file mode 100644 index 00000000..bc3b6d1f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5-1f3ff.png b/twake/frontend/public/public/emojione/128/1f6b5-1f3ff.png new file mode 100644 index 00000000..bc3b6d1f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5-2640.png b/twake/frontend/public/public/emojione/128/1f6b5-2640.png new file mode 100644 index 00000000..73320c29 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5-2642.png b/twake/frontend/public/public/emojione/128/1f6b5-2642.png new file mode 100644 index 00000000..71339d59 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b5.png b/twake/frontend/public/public/emojione/128/1f6b5.png new file mode 100644 index 00000000..71339d59 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f6b6-1f3fb-2640.png new file mode 100644 index 00000000..3bb6f5e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f6b6-1f3fb-2642.png new file mode 100644 index 00000000..aaa35a07 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6-1f3fb.png b/twake/frontend/public/public/emojione/128/1f6b6-1f3fb.png new file mode 100644 index 00000000..aaa35a07 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f6b6-1f3fc-2640.png new file mode 100644 index 00000000..c982dfcc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f6b6-1f3fc-2642.png new file mode 100644 index 00000000..e1a68ac6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6-1f3fc.png b/twake/frontend/public/public/emojione/128/1f6b6-1f3fc.png new file mode 100644 index 00000000..e1a68ac6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f6b6-1f3fd-2640.png new file mode 100644 index 00000000..d10c9329 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f6b6-1f3fd-2642.png new file mode 100644 index 00000000..ed261703 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6-1f3fd.png b/twake/frontend/public/public/emojione/128/1f6b6-1f3fd.png new file mode 100644 index 00000000..ed261703 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f6b6-1f3fe-2640.png new file mode 100644 index 00000000..99e78d17 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f6b6-1f3fe-2642.png new file mode 100644 index 00000000..8063db77 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6-1f3fe.png b/twake/frontend/public/public/emojione/128/1f6b6-1f3fe.png new file mode 100644 index 00000000..8063db77 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f6b6-1f3ff-2640.png new file mode 100644 index 00000000..5d461c67 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f6b6-1f3ff-2642.png new file mode 100644 index 00000000..9cd37a42 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6-1f3ff.png b/twake/frontend/public/public/emojione/128/1f6b6-1f3ff.png new file mode 100644 index 00000000..9cd37a42 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6-2640.png b/twake/frontend/public/public/emojione/128/1f6b6-2640.png new file mode 100644 index 00000000..77b21477 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6-2642.png b/twake/frontend/public/public/emojione/128/1f6b6-2642.png new file mode 100644 index 00000000..0d7b8e4a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b6.png b/twake/frontend/public/public/emojione/128/1f6b6.png new file mode 100644 index 00000000..0d7b8e4a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b7.png b/twake/frontend/public/public/emojione/128/1f6b7.png new file mode 100644 index 00000000..3a63c859 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b8.png b/twake/frontend/public/public/emojione/128/1f6b8.png new file mode 100644 index 00000000..fff811a1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6b9.png b/twake/frontend/public/public/emojione/128/1f6b9.png new file mode 100644 index 00000000..b4fbe0a6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6b9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6ba.png b/twake/frontend/public/public/emojione/128/1f6ba.png new file mode 100644 index 00000000..73f925f3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6ba.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6bb.png b/twake/frontend/public/public/emojione/128/1f6bb.png new file mode 100644 index 00000000..75b4bb8b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6bb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6bc.png b/twake/frontend/public/public/emojione/128/1f6bc.png new file mode 100644 index 00000000..b191bdd9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6bc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6bd.png b/twake/frontend/public/public/emojione/128/1f6bd.png new file mode 100644 index 00000000..2e42536d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6bd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6be.png b/twake/frontend/public/public/emojione/128/1f6be.png new file mode 100644 index 00000000..853e5cbd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6be.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6bf.png b/twake/frontend/public/public/emojione/128/1f6bf.png new file mode 100644 index 00000000..c5293f9a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6bf.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6c0-1f3fb.png b/twake/frontend/public/public/emojione/128/1f6c0-1f3fb.png new file mode 100644 index 00000000..e13d4829 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6c0-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6c0-1f3fc.png b/twake/frontend/public/public/emojione/128/1f6c0-1f3fc.png new file mode 100644 index 00000000..c262ec81 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6c0-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6c0-1f3fd.png b/twake/frontend/public/public/emojione/128/1f6c0-1f3fd.png new file mode 100644 index 00000000..a4ff9256 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6c0-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6c0-1f3fe.png b/twake/frontend/public/public/emojione/128/1f6c0-1f3fe.png new file mode 100644 index 00000000..7471cc06 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6c0-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6c0-1f3ff.png b/twake/frontend/public/public/emojione/128/1f6c0-1f3ff.png new file mode 100644 index 00000000..f19f8fc2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6c0-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6c0.png b/twake/frontend/public/public/emojione/128/1f6c0.png new file mode 100644 index 00000000..83870d20 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6c0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6c1.png b/twake/frontend/public/public/emojione/128/1f6c1.png new file mode 100644 index 00000000..0ef1c333 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6c1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6c2.png b/twake/frontend/public/public/emojione/128/1f6c2.png new file mode 100644 index 00000000..3a09b1d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6c2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6c3.png b/twake/frontend/public/public/emojione/128/1f6c3.png new file mode 100644 index 00000000..e6a36e80 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6c3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6c4.png b/twake/frontend/public/public/emojione/128/1f6c4.png new file mode 100644 index 00000000..c52a96c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6c4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6c5.png b/twake/frontend/public/public/emojione/128/1f6c5.png new file mode 100644 index 00000000..7b73d62a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6c5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6cb.png b/twake/frontend/public/public/emojione/128/1f6cb.png new file mode 100644 index 00000000..f86db9c5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6cb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6cc-1f3fb.png b/twake/frontend/public/public/emojione/128/1f6cc-1f3fb.png new file mode 100644 index 00000000..86060da6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6cc-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6cc-1f3fc.png b/twake/frontend/public/public/emojione/128/1f6cc-1f3fc.png new file mode 100644 index 00000000..9df0a67d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6cc-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6cc-1f3fd.png b/twake/frontend/public/public/emojione/128/1f6cc-1f3fd.png new file mode 100644 index 00000000..e6dd1bae Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6cc-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6cc-1f3fe.png b/twake/frontend/public/public/emojione/128/1f6cc-1f3fe.png new file mode 100644 index 00000000..8ea0d4f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6cc-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6cc-1f3ff.png b/twake/frontend/public/public/emojione/128/1f6cc-1f3ff.png new file mode 100644 index 00000000..46f32d92 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6cc-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6cc.png b/twake/frontend/public/public/emojione/128/1f6cc.png new file mode 100644 index 00000000..ddaa00fe Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6cc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6cd.png b/twake/frontend/public/public/emojione/128/1f6cd.png new file mode 100644 index 00000000..3c726950 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6cd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6ce.png b/twake/frontend/public/public/emojione/128/1f6ce.png new file mode 100644 index 00000000..322552eb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6ce.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6cf.png b/twake/frontend/public/public/emojione/128/1f6cf.png new file mode 100644 index 00000000..57e90fba Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6cf.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6d0.png b/twake/frontend/public/public/emojione/128/1f6d0.png new file mode 100644 index 00000000..fb0303e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6d0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6d1.png b/twake/frontend/public/public/emojione/128/1f6d1.png new file mode 100644 index 00000000..573da552 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6d1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6d2.png b/twake/frontend/public/public/emojione/128/1f6d2.png new file mode 100644 index 00000000..6b87408b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6d2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6e0.png b/twake/frontend/public/public/emojione/128/1f6e0.png new file mode 100644 index 00000000..9fc5ffb6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6e0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6e1.png b/twake/frontend/public/public/emojione/128/1f6e1.png new file mode 100644 index 00000000..6e1b41c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6e1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6e2.png b/twake/frontend/public/public/emojione/128/1f6e2.png new file mode 100644 index 00000000..f74b7593 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6e2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6e3.png b/twake/frontend/public/public/emojione/128/1f6e3.png new file mode 100644 index 00000000..cc53df1d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6e3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6e4.png b/twake/frontend/public/public/emojione/128/1f6e4.png new file mode 100644 index 00000000..e25e7d18 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6e4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6e5.png b/twake/frontend/public/public/emojione/128/1f6e5.png new file mode 100644 index 00000000..7114eb32 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6e5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6e9.png b/twake/frontend/public/public/emojione/128/1f6e9.png new file mode 100644 index 00000000..d664ecd2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6e9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6eb.png b/twake/frontend/public/public/emojione/128/1f6eb.png new file mode 100644 index 00000000..d0d6ea31 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6ec.png b/twake/frontend/public/public/emojione/128/1f6ec.png new file mode 100644 index 00000000..b998c75c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6f0.png b/twake/frontend/public/public/emojione/128/1f6f0.png new file mode 100644 index 00000000..b3e203d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6f0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6f3.png b/twake/frontend/public/public/emojione/128/1f6f3.png new file mode 100644 index 00000000..33630f51 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6f4.png b/twake/frontend/public/public/emojione/128/1f6f4.png new file mode 100644 index 00000000..3e21ab85 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6f4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6f5.png b/twake/frontend/public/public/emojione/128/1f6f5.png new file mode 100644 index 00000000..29409b3c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6f5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6f6.png b/twake/frontend/public/public/emojione/128/1f6f6.png new file mode 100644 index 00000000..484e8148 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6f6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6f7.png b/twake/frontend/public/public/emojione/128/1f6f7.png new file mode 100644 index 00000000..91496dba Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6f8.png b/twake/frontend/public/public/emojione/128/1f6f8.png new file mode 100644 index 00000000..a76304a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6f8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f6f9.png b/twake/frontend/public/public/emojione/128/1f6f9.png new file mode 100644 index 00000000..48b61da0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f6f9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f910.png b/twake/frontend/public/public/emojione/128/1f910.png new file mode 100644 index 00000000..8e857e9c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f910.png differ diff --git a/twake/frontend/public/public/emojione/128/1f911.png b/twake/frontend/public/public/emojione/128/1f911.png new file mode 100644 index 00000000..b6af8f99 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f911.png differ diff --git a/twake/frontend/public/public/emojione/128/1f912.png b/twake/frontend/public/public/emojione/128/1f912.png new file mode 100644 index 00000000..de7dddff Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f912.png differ diff --git a/twake/frontend/public/public/emojione/128/1f913.png b/twake/frontend/public/public/emojione/128/1f913.png new file mode 100644 index 00000000..f92c301b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f913.png differ diff --git a/twake/frontend/public/public/emojione/128/1f914.png b/twake/frontend/public/public/emojione/128/1f914.png new file mode 100644 index 00000000..2501566b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f914.png differ diff --git a/twake/frontend/public/public/emojione/128/1f915.png b/twake/frontend/public/public/emojione/128/1f915.png new file mode 100644 index 00000000..8f729c6f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f915.png differ diff --git a/twake/frontend/public/public/emojione/128/1f916.png b/twake/frontend/public/public/emojione/128/1f916.png new file mode 100644 index 00000000..1d0087dd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f916.png differ diff --git a/twake/frontend/public/public/emojione/128/1f917.png b/twake/frontend/public/public/emojione/128/1f917.png new file mode 100644 index 00000000..32dbb368 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f917.png differ diff --git a/twake/frontend/public/public/emojione/128/1f918-1f3fb.png b/twake/frontend/public/public/emojione/128/1f918-1f3fb.png new file mode 100644 index 00000000..13356522 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f918-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f918-1f3fc.png b/twake/frontend/public/public/emojione/128/1f918-1f3fc.png new file mode 100644 index 00000000..fbc5f781 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f918-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f918-1f3fd.png b/twake/frontend/public/public/emojione/128/1f918-1f3fd.png new file mode 100644 index 00000000..e8f9ecfc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f918-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f918-1f3fe.png b/twake/frontend/public/public/emojione/128/1f918-1f3fe.png new file mode 100644 index 00000000..1ccd91ed Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f918-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f918-1f3ff.png b/twake/frontend/public/public/emojione/128/1f918-1f3ff.png new file mode 100644 index 00000000..d0a4d41b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f918-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f918.png b/twake/frontend/public/public/emojione/128/1f918.png new file mode 100644 index 00000000..464febbe Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f918.png differ diff --git a/twake/frontend/public/public/emojione/128/1f919-1f3fb.png b/twake/frontend/public/public/emojione/128/1f919-1f3fb.png new file mode 100644 index 00000000..f3c52e67 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f919-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f919-1f3fc.png b/twake/frontend/public/public/emojione/128/1f919-1f3fc.png new file mode 100644 index 00000000..910e6c5c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f919-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f919-1f3fd.png b/twake/frontend/public/public/emojione/128/1f919-1f3fd.png new file mode 100644 index 00000000..49fc0df7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f919-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f919-1f3fe.png b/twake/frontend/public/public/emojione/128/1f919-1f3fe.png new file mode 100644 index 00000000..f15d5212 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f919-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f919-1f3ff.png b/twake/frontend/public/public/emojione/128/1f919-1f3ff.png new file mode 100644 index 00000000..27325d83 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f919-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f919.png b/twake/frontend/public/public/emojione/128/1f919.png new file mode 100644 index 00000000..766fec26 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f919.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91a-1f3fb.png b/twake/frontend/public/public/emojione/128/1f91a-1f3fb.png new file mode 100644 index 00000000..19394d6b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91a-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91a-1f3fc.png b/twake/frontend/public/public/emojione/128/1f91a-1f3fc.png new file mode 100644 index 00000000..6c69f1f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91a-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91a-1f3fd.png b/twake/frontend/public/public/emojione/128/1f91a-1f3fd.png new file mode 100644 index 00000000..8b826849 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91a-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91a-1f3fe.png b/twake/frontend/public/public/emojione/128/1f91a-1f3fe.png new file mode 100644 index 00000000..14b1127a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91a-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91a-1f3ff.png b/twake/frontend/public/public/emojione/128/1f91a-1f3ff.png new file mode 100644 index 00000000..663a7098 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91a-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91a.png b/twake/frontend/public/public/emojione/128/1f91a.png new file mode 100644 index 00000000..98333864 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91b-1f3fb.png b/twake/frontend/public/public/emojione/128/1f91b-1f3fb.png new file mode 100644 index 00000000..68fc1f2d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91b-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91b-1f3fc.png b/twake/frontend/public/public/emojione/128/1f91b-1f3fc.png new file mode 100644 index 00000000..3966f893 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91b-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91b-1f3fd.png b/twake/frontend/public/public/emojione/128/1f91b-1f3fd.png new file mode 100644 index 00000000..9d9bffbd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91b-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91b-1f3fe.png b/twake/frontend/public/public/emojione/128/1f91b-1f3fe.png new file mode 100644 index 00000000..920e42ae Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91b-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91b-1f3ff.png b/twake/frontend/public/public/emojione/128/1f91b-1f3ff.png new file mode 100644 index 00000000..8e4360a2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91b-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91b.png b/twake/frontend/public/public/emojione/128/1f91b.png new file mode 100644 index 00000000..f0b89d6a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91c-1f3fb.png b/twake/frontend/public/public/emojione/128/1f91c-1f3fb.png new file mode 100644 index 00000000..7335ada0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91c-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91c-1f3fc.png b/twake/frontend/public/public/emojione/128/1f91c-1f3fc.png new file mode 100644 index 00000000..979b86c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91c-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91c-1f3fd.png b/twake/frontend/public/public/emojione/128/1f91c-1f3fd.png new file mode 100644 index 00000000..d73c98e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91c-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91c-1f3fe.png b/twake/frontend/public/public/emojione/128/1f91c-1f3fe.png new file mode 100644 index 00000000..bc478b94 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91c-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91c-1f3ff.png b/twake/frontend/public/public/emojione/128/1f91c-1f3ff.png new file mode 100644 index 00000000..8003bf19 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91c-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91c.png b/twake/frontend/public/public/emojione/128/1f91c.png new file mode 100644 index 00000000..bec94d55 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91d.png b/twake/frontend/public/public/emojione/128/1f91d.png new file mode 100644 index 00000000..94678637 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91e-1f3fb.png b/twake/frontend/public/public/emojione/128/1f91e-1f3fb.png new file mode 100644 index 00000000..5311bac9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91e-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91e-1f3fc.png b/twake/frontend/public/public/emojione/128/1f91e-1f3fc.png new file mode 100644 index 00000000..b803b23b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91e-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91e-1f3fd.png b/twake/frontend/public/public/emojione/128/1f91e-1f3fd.png new file mode 100644 index 00000000..046ddca4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91e-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91e-1f3fe.png b/twake/frontend/public/public/emojione/128/1f91e-1f3fe.png new file mode 100644 index 00000000..8719a668 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91e-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91e-1f3ff.png b/twake/frontend/public/public/emojione/128/1f91e-1f3ff.png new file mode 100644 index 00000000..787ef07a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91e-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91e.png b/twake/frontend/public/public/emojione/128/1f91e.png new file mode 100644 index 00000000..3c85e690 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91f-1f3fb.png b/twake/frontend/public/public/emojione/128/1f91f-1f3fb.png new file mode 100644 index 00000000..02e5dd3f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91f-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91f-1f3fc.png b/twake/frontend/public/public/emojione/128/1f91f-1f3fc.png new file mode 100644 index 00000000..8630965f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91f-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91f-1f3fd.png b/twake/frontend/public/public/emojione/128/1f91f-1f3fd.png new file mode 100644 index 00000000..7972b543 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91f-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91f-1f3fe.png b/twake/frontend/public/public/emojione/128/1f91f-1f3fe.png new file mode 100644 index 00000000..c555151f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91f-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91f-1f3ff.png b/twake/frontend/public/public/emojione/128/1f91f-1f3ff.png new file mode 100644 index 00000000..8b738804 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91f-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f91f.png b/twake/frontend/public/public/emojione/128/1f91f.png new file mode 100644 index 00000000..02b21346 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f91f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f920.png b/twake/frontend/public/public/emojione/128/1f920.png new file mode 100644 index 00000000..5a38cae7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f920.png differ diff --git a/twake/frontend/public/public/emojione/128/1f921.png b/twake/frontend/public/public/emojione/128/1f921.png new file mode 100644 index 00000000..1f583c73 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f921.png differ diff --git a/twake/frontend/public/public/emojione/128/1f922.png b/twake/frontend/public/public/emojione/128/1f922.png new file mode 100644 index 00000000..a2dbc921 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f922.png differ diff --git a/twake/frontend/public/public/emojione/128/1f923.png b/twake/frontend/public/public/emojione/128/1f923.png new file mode 100644 index 00000000..6b3605f4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f923.png differ diff --git a/twake/frontend/public/public/emojione/128/1f924.png b/twake/frontend/public/public/emojione/128/1f924.png new file mode 100644 index 00000000..a5b84fb5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f924.png differ diff --git a/twake/frontend/public/public/emojione/128/1f925.png b/twake/frontend/public/public/emojione/128/1f925.png new file mode 100644 index 00000000..4e7f1fce Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f925.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f926-1f3fb-2640.png new file mode 100644 index 00000000..79d2eb83 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f926-1f3fb-2642.png new file mode 100644 index 00000000..f76dfe1d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926-1f3fb.png b/twake/frontend/public/public/emojione/128/1f926-1f3fb.png new file mode 100644 index 00000000..b95fec54 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f926-1f3fc-2640.png new file mode 100644 index 00000000..2ac7a562 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f926-1f3fc-2642.png new file mode 100644 index 00000000..aa58b94d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926-1f3fc.png b/twake/frontend/public/public/emojione/128/1f926-1f3fc.png new file mode 100644 index 00000000..2ac7a562 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f926-1f3fd-2640.png new file mode 100644 index 00000000..523b77be Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f926-1f3fd-2642.png new file mode 100644 index 00000000..ace74ebf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926-1f3fd.png b/twake/frontend/public/public/emojione/128/1f926-1f3fd.png new file mode 100644 index 00000000..56d9c318 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f926-1f3fe-2640.png new file mode 100644 index 00000000..c89c801c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f926-1f3fe-2642.png new file mode 100644 index 00000000..54081748 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926-1f3fe.png b/twake/frontend/public/public/emojione/128/1f926-1f3fe.png new file mode 100644 index 00000000..f7f70b0e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f926-1f3ff-2640.png new file mode 100644 index 00000000..07b99f7c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f926-1f3ff-2642.png new file mode 100644 index 00000000..82f32882 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926-1f3ff.png b/twake/frontend/public/public/emojione/128/1f926-1f3ff.png new file mode 100644 index 00000000..d62d720e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926-2640.png b/twake/frontend/public/public/emojione/128/1f926-2640.png new file mode 100644 index 00000000..4cd1733a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926-2642.png b/twake/frontend/public/public/emojione/128/1f926-2642.png new file mode 100644 index 00000000..dc037ef4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f926.png b/twake/frontend/public/public/emojione/128/1f926.png new file mode 100644 index 00000000..4cd1733a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f926.png differ diff --git a/twake/frontend/public/public/emojione/128/1f927.png b/twake/frontend/public/public/emojione/128/1f927.png new file mode 100644 index 00000000..dd91f3ff Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f927.png differ diff --git a/twake/frontend/public/public/emojione/128/1f928.png b/twake/frontend/public/public/emojione/128/1f928.png new file mode 100644 index 00000000..6a73211d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f928.png differ diff --git a/twake/frontend/public/public/emojione/128/1f929.png b/twake/frontend/public/public/emojione/128/1f929.png new file mode 100644 index 00000000..9218a755 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f929.png differ diff --git a/twake/frontend/public/public/emojione/128/1f92a.png b/twake/frontend/public/public/emojione/128/1f92a.png new file mode 100644 index 00000000..fcb0249b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f92a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f92b.png b/twake/frontend/public/public/emojione/128/1f92b.png new file mode 100644 index 00000000..be0a306d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f92b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f92c.png b/twake/frontend/public/public/emojione/128/1f92c.png new file mode 100644 index 00000000..8c58b82b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f92c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f92d.png b/twake/frontend/public/public/emojione/128/1f92d.png new file mode 100644 index 00000000..61bada3e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f92d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f92e.png b/twake/frontend/public/public/emojione/128/1f92e.png new file mode 100644 index 00000000..ef85762b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f92e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f92f.png b/twake/frontend/public/public/emojione/128/1f92f.png new file mode 100644 index 00000000..f066cc23 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f92f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f930-1f3fb.png b/twake/frontend/public/public/emojione/128/1f930-1f3fb.png new file mode 100644 index 00000000..750cdd2f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f930-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f930-1f3fc.png b/twake/frontend/public/public/emojione/128/1f930-1f3fc.png new file mode 100644 index 00000000..930986b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f930-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f930-1f3fd.png b/twake/frontend/public/public/emojione/128/1f930-1f3fd.png new file mode 100644 index 00000000..a335ffb5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f930-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f930-1f3fe.png b/twake/frontend/public/public/emojione/128/1f930-1f3fe.png new file mode 100644 index 00000000..d85f7bb5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f930-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f930-1f3ff.png b/twake/frontend/public/public/emojione/128/1f930-1f3ff.png new file mode 100644 index 00000000..246cb5b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f930-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f930.png b/twake/frontend/public/public/emojione/128/1f930.png new file mode 100644 index 00000000..567ef7e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f930.png differ diff --git a/twake/frontend/public/public/emojione/128/1f931-1f3fb.png b/twake/frontend/public/public/emojione/128/1f931-1f3fb.png new file mode 100644 index 00000000..7e0e5cfe Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f931-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f931-1f3fc.png b/twake/frontend/public/public/emojione/128/1f931-1f3fc.png new file mode 100644 index 00000000..445e2f3b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f931-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f931-1f3fd.png b/twake/frontend/public/public/emojione/128/1f931-1f3fd.png new file mode 100644 index 00000000..0a0e9662 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f931-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f931-1f3fe.png b/twake/frontend/public/public/emojione/128/1f931-1f3fe.png new file mode 100644 index 00000000..fb760c5b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f931-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f931-1f3ff.png b/twake/frontend/public/public/emojione/128/1f931-1f3ff.png new file mode 100644 index 00000000..f04d9b23 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f931-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f931.png b/twake/frontend/public/public/emojione/128/1f931.png new file mode 100644 index 00000000..d6169280 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f931.png differ diff --git a/twake/frontend/public/public/emojione/128/1f932-1f3fb.png b/twake/frontend/public/public/emojione/128/1f932-1f3fb.png new file mode 100644 index 00000000..1e49fd26 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f932-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f932-1f3fc.png b/twake/frontend/public/public/emojione/128/1f932-1f3fc.png new file mode 100644 index 00000000..248cc4ac Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f932-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f932-1f3fd.png b/twake/frontend/public/public/emojione/128/1f932-1f3fd.png new file mode 100644 index 00000000..6ac91d96 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f932-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f932-1f3fe.png b/twake/frontend/public/public/emojione/128/1f932-1f3fe.png new file mode 100644 index 00000000..7eaf246a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f932-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f932-1f3ff.png b/twake/frontend/public/public/emojione/128/1f932-1f3ff.png new file mode 100644 index 00000000..dfcf4aed Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f932-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f932.png b/twake/frontend/public/public/emojione/128/1f932.png new file mode 100644 index 00000000..86830347 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f932.png differ diff --git a/twake/frontend/public/public/emojione/128/1f933-1f3fb.png b/twake/frontend/public/public/emojione/128/1f933-1f3fb.png new file mode 100644 index 00000000..3cdfb7f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f933-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f933-1f3fc.png b/twake/frontend/public/public/emojione/128/1f933-1f3fc.png new file mode 100644 index 00000000..6de96ef1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f933-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f933-1f3fd.png b/twake/frontend/public/public/emojione/128/1f933-1f3fd.png new file mode 100644 index 00000000..00bb1884 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f933-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f933-1f3fe.png b/twake/frontend/public/public/emojione/128/1f933-1f3fe.png new file mode 100644 index 00000000..54078d6b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f933-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f933-1f3ff.png b/twake/frontend/public/public/emojione/128/1f933-1f3ff.png new file mode 100644 index 00000000..1fe70b18 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f933-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f933.png b/twake/frontend/public/public/emojione/128/1f933.png new file mode 100644 index 00000000..f6474710 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f933.png differ diff --git a/twake/frontend/public/public/emojione/128/1f934-1f3fb.png b/twake/frontend/public/public/emojione/128/1f934-1f3fb.png new file mode 100644 index 00000000..a7aefa31 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f934-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f934-1f3fc.png b/twake/frontend/public/public/emojione/128/1f934-1f3fc.png new file mode 100644 index 00000000..e74b2cc2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f934-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f934-1f3fd.png b/twake/frontend/public/public/emojione/128/1f934-1f3fd.png new file mode 100644 index 00000000..2570dc75 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f934-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f934-1f3fe.png b/twake/frontend/public/public/emojione/128/1f934-1f3fe.png new file mode 100644 index 00000000..1acbf9cf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f934-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f934-1f3ff.png b/twake/frontend/public/public/emojione/128/1f934-1f3ff.png new file mode 100644 index 00000000..2e2f87b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f934-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f934.png b/twake/frontend/public/public/emojione/128/1f934.png new file mode 100644 index 00000000..1c2fdfc6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f934.png differ diff --git a/twake/frontend/public/public/emojione/128/1f935-1f3fb.png b/twake/frontend/public/public/emojione/128/1f935-1f3fb.png new file mode 100644 index 00000000..e999992a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f935-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f935-1f3fc.png b/twake/frontend/public/public/emojione/128/1f935-1f3fc.png new file mode 100644 index 00000000..752411e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f935-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f935-1f3fd.png b/twake/frontend/public/public/emojione/128/1f935-1f3fd.png new file mode 100644 index 00000000..f9ebd6cd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f935-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f935-1f3fe.png b/twake/frontend/public/public/emojione/128/1f935-1f3fe.png new file mode 100644 index 00000000..ad5024b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f935-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f935-1f3ff.png b/twake/frontend/public/public/emojione/128/1f935-1f3ff.png new file mode 100644 index 00000000..c4b60d98 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f935-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f935.png b/twake/frontend/public/public/emojione/128/1f935.png new file mode 100644 index 00000000..4d228d43 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f935.png differ diff --git a/twake/frontend/public/public/emojione/128/1f936-1f3fb.png b/twake/frontend/public/public/emojione/128/1f936-1f3fb.png new file mode 100644 index 00000000..59805b85 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f936-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f936-1f3fc.png b/twake/frontend/public/public/emojione/128/1f936-1f3fc.png new file mode 100644 index 00000000..c60d9eed Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f936-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f936-1f3fd.png b/twake/frontend/public/public/emojione/128/1f936-1f3fd.png new file mode 100644 index 00000000..39e1fd50 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f936-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f936-1f3fe.png b/twake/frontend/public/public/emojione/128/1f936-1f3fe.png new file mode 100644 index 00000000..a1600ae3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f936-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f936-1f3ff.png b/twake/frontend/public/public/emojione/128/1f936-1f3ff.png new file mode 100644 index 00000000..20df0246 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f936-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f936.png b/twake/frontend/public/public/emojione/128/1f936.png new file mode 100644 index 00000000..fa9fa8df Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f936.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f937-1f3fb-2640.png new file mode 100644 index 00000000..b121dcad Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f937-1f3fb-2642.png new file mode 100644 index 00000000..86258fc7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937-1f3fb.png b/twake/frontend/public/public/emojione/128/1f937-1f3fb.png new file mode 100644 index 00000000..e5f61193 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f937-1f3fc-2640.png new file mode 100644 index 00000000..8803bd51 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f937-1f3fc-2642.png new file mode 100644 index 00000000..e15020a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937-1f3fc.png b/twake/frontend/public/public/emojione/128/1f937-1f3fc.png new file mode 100644 index 00000000..2b8e6441 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f937-1f3fd-2640.png new file mode 100644 index 00000000..a594abaa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f937-1f3fd-2642.png new file mode 100644 index 00000000..5e6b949c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937-1f3fd.png b/twake/frontend/public/public/emojione/128/1f937-1f3fd.png new file mode 100644 index 00000000..b3231858 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f937-1f3fe-2640.png new file mode 100644 index 00000000..58e4af99 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f937-1f3fe-2642.png new file mode 100644 index 00000000..0d57988e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937-1f3fe.png b/twake/frontend/public/public/emojione/128/1f937-1f3fe.png new file mode 100644 index 00000000..3b40d076 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f937-1f3ff-2640.png new file mode 100644 index 00000000..129da777 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f937-1f3ff-2642.png new file mode 100644 index 00000000..22323ec3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937-1f3ff.png b/twake/frontend/public/public/emojione/128/1f937-1f3ff.png new file mode 100644 index 00000000..d074a5e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937-2640.png b/twake/frontend/public/public/emojione/128/1f937-2640.png new file mode 100644 index 00000000..e13f3107 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937-2642.png b/twake/frontend/public/public/emojione/128/1f937-2642.png new file mode 100644 index 00000000..03281678 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f937.png b/twake/frontend/public/public/emojione/128/1f937.png new file mode 100644 index 00000000..e13f3107 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f937.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f938-1f3fb-2640.png new file mode 100644 index 00000000..b28ae94a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f938-1f3fb-2642.png new file mode 100644 index 00000000..f784456f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938-1f3fb.png b/twake/frontend/public/public/emojione/128/1f938-1f3fb.png new file mode 100644 index 00000000..f784456f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f938-1f3fc-2640.png new file mode 100644 index 00000000..ce929919 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f938-1f3fc-2642.png new file mode 100644 index 00000000..f26e8b4b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938-1f3fc.png b/twake/frontend/public/public/emojione/128/1f938-1f3fc.png new file mode 100644 index 00000000..f26e8b4b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f938-1f3fd-2640.png new file mode 100644 index 00000000..53737b71 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f938-1f3fd-2642.png new file mode 100644 index 00000000..9a042443 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938-1f3fd.png b/twake/frontend/public/public/emojione/128/1f938-1f3fd.png new file mode 100644 index 00000000..9a042443 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f938-1f3fe-2640.png new file mode 100644 index 00000000..50190eea Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f938-1f3fe-2642.png new file mode 100644 index 00000000..9c39e547 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938-1f3fe.png b/twake/frontend/public/public/emojione/128/1f938-1f3fe.png new file mode 100644 index 00000000..9c39e547 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f938-1f3ff-2640.png new file mode 100644 index 00000000..cd702787 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f938-1f3ff-2642.png new file mode 100644 index 00000000..75dd3d24 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938-1f3ff.png b/twake/frontend/public/public/emojione/128/1f938-1f3ff.png new file mode 100644 index 00000000..75dd3d24 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938-2640.png b/twake/frontend/public/public/emojione/128/1f938-2640.png new file mode 100644 index 00000000..212c452c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938-2642.png b/twake/frontend/public/public/emojione/128/1f938-2642.png new file mode 100644 index 00000000..cabceea4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f938.png b/twake/frontend/public/public/emojione/128/1f938.png new file mode 100644 index 00000000..212c452c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f938.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f939-1f3fb-2640.png new file mode 100644 index 00000000..08941f8a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f939-1f3fb-2642.png new file mode 100644 index 00000000..374288d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939-1f3fb.png b/twake/frontend/public/public/emojione/128/1f939-1f3fb.png new file mode 100644 index 00000000..374288d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f939-1f3fc-2640.png new file mode 100644 index 00000000..c84b9366 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f939-1f3fc-2642.png new file mode 100644 index 00000000..339b1f99 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939-1f3fc.png b/twake/frontend/public/public/emojione/128/1f939-1f3fc.png new file mode 100644 index 00000000..339b1f99 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f939-1f3fd-2640.png new file mode 100644 index 00000000..0ed48b19 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f939-1f3fd-2642.png new file mode 100644 index 00000000..6fc2ee10 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939-1f3fd.png b/twake/frontend/public/public/emojione/128/1f939-1f3fd.png new file mode 100644 index 00000000..6fc2ee10 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f939-1f3fe-2640.png new file mode 100644 index 00000000..611dc1b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f939-1f3fe-2642.png new file mode 100644 index 00000000..81baf97f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939-1f3fe.png b/twake/frontend/public/public/emojione/128/1f939-1f3fe.png new file mode 100644 index 00000000..81baf97f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f939-1f3ff-2640.png new file mode 100644 index 00000000..186fb52b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f939-1f3ff-2642.png new file mode 100644 index 00000000..249ad732 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939-1f3ff.png b/twake/frontend/public/public/emojione/128/1f939-1f3ff.png new file mode 100644 index 00000000..249ad732 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939-2640.png b/twake/frontend/public/public/emojione/128/1f939-2640.png new file mode 100644 index 00000000..6502f845 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939-2642.png b/twake/frontend/public/public/emojione/128/1f939-2642.png new file mode 100644 index 00000000..6ca6d929 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f939.png b/twake/frontend/public/public/emojione/128/1f939.png new file mode 100644 index 00000000..6ca6d929 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f939.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93a.png b/twake/frontend/public/public/emojione/128/1f93a.png new file mode 100644 index 00000000..14d40efc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93c-2640.png b/twake/frontend/public/public/emojione/128/1f93c-2640.png new file mode 100644 index 00000000..1208ce46 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93c-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93c-2642.png b/twake/frontend/public/public/emojione/128/1f93c-2642.png new file mode 100644 index 00000000..a9ee9f7b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93c-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93c.png b/twake/frontend/public/public/emojione/128/1f93c.png new file mode 100644 index 00000000..a9ee9f7b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f93d-1f3fb-2640.png new file mode 100644 index 00000000..5e29908c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f93d-1f3fb-2642.png new file mode 100644 index 00000000..1ea49d16 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d-1f3fb.png b/twake/frontend/public/public/emojione/128/1f93d-1f3fb.png new file mode 100644 index 00000000..1ea49d16 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f93d-1f3fc-2640.png new file mode 100644 index 00000000..8cc34859 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f93d-1f3fc-2642.png new file mode 100644 index 00000000..0773437d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d-1f3fc.png b/twake/frontend/public/public/emojione/128/1f93d-1f3fc.png new file mode 100644 index 00000000..0773437d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f93d-1f3fd-2640.png new file mode 100644 index 00000000..54fa56dc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f93d-1f3fd-2642.png new file mode 100644 index 00000000..4ec9a26e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d-1f3fd.png b/twake/frontend/public/public/emojione/128/1f93d-1f3fd.png new file mode 100644 index 00000000..4ec9a26e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f93d-1f3fe-2640.png new file mode 100644 index 00000000..94e230bd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f93d-1f3fe-2642.png new file mode 100644 index 00000000..e8f3f887 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d-1f3fe.png b/twake/frontend/public/public/emojione/128/1f93d-1f3fe.png new file mode 100644 index 00000000..e8f3f887 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f93d-1f3ff-2640.png new file mode 100644 index 00000000..0adc12ff Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f93d-1f3ff-2642.png new file mode 100644 index 00000000..f46f42ca Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d-1f3ff.png b/twake/frontend/public/public/emojione/128/1f93d-1f3ff.png new file mode 100644 index 00000000..f46f42ca Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d-2640.png b/twake/frontend/public/public/emojione/128/1f93d-2640.png new file mode 100644 index 00000000..aacad978 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d-2642.png b/twake/frontend/public/public/emojione/128/1f93d-2642.png new file mode 100644 index 00000000..7f9344f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93d.png b/twake/frontend/public/public/emojione/128/1f93d.png new file mode 100644 index 00000000..7f9344f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f93e-1f3fb-2640.png new file mode 100644 index 00000000..ca666a1e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f93e-1f3fb-2642.png new file mode 100644 index 00000000..99c2643b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e-1f3fb.png b/twake/frontend/public/public/emojione/128/1f93e-1f3fb.png new file mode 100644 index 00000000..99c2643b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f93e-1f3fc-2640.png new file mode 100644 index 00000000..84463410 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f93e-1f3fc-2642.png new file mode 100644 index 00000000..1b3668f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e-1f3fc.png b/twake/frontend/public/public/emojione/128/1f93e-1f3fc.png new file mode 100644 index 00000000..1b3668f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f93e-1f3fd-2640.png new file mode 100644 index 00000000..4b59da42 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f93e-1f3fd-2642.png new file mode 100644 index 00000000..57d71a84 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e-1f3fd.png b/twake/frontend/public/public/emojione/128/1f93e-1f3fd.png new file mode 100644 index 00000000..57d71a84 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f93e-1f3fe-2640.png new file mode 100644 index 00000000..984c134d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f93e-1f3fe-2642.png new file mode 100644 index 00000000..8548b21f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e-1f3fe.png b/twake/frontend/public/public/emojione/128/1f93e-1f3fe.png new file mode 100644 index 00000000..8548b21f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f93e-1f3ff-2640.png new file mode 100644 index 00000000..885b22a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f93e-1f3ff-2642.png new file mode 100644 index 00000000..b70c457c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e-1f3ff.png b/twake/frontend/public/public/emojione/128/1f93e-1f3ff.png new file mode 100644 index 00000000..b70c457c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e-2640.png b/twake/frontend/public/public/emojione/128/1f93e-2640.png new file mode 100644 index 00000000..a1bf753d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e-2642.png b/twake/frontend/public/public/emojione/128/1f93e-2642.png new file mode 100644 index 00000000..641d6d1b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f93e.png b/twake/frontend/public/public/emojione/128/1f93e.png new file mode 100644 index 00000000..641d6d1b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f93e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f940.png b/twake/frontend/public/public/emojione/128/1f940.png new file mode 100644 index 00000000..2b3d2c9e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f940.png differ diff --git a/twake/frontend/public/public/emojione/128/1f941.png b/twake/frontend/public/public/emojione/128/1f941.png new file mode 100644 index 00000000..31d3d586 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f941.png differ diff --git a/twake/frontend/public/public/emojione/128/1f942.png b/twake/frontend/public/public/emojione/128/1f942.png new file mode 100644 index 00000000..45c6e23e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f942.png differ diff --git a/twake/frontend/public/public/emojione/128/1f943.png b/twake/frontend/public/public/emojione/128/1f943.png new file mode 100644 index 00000000..36ca34aa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f943.png differ diff --git a/twake/frontend/public/public/emojione/128/1f944.png b/twake/frontend/public/public/emojione/128/1f944.png new file mode 100644 index 00000000..faf16e3e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f944.png differ diff --git a/twake/frontend/public/public/emojione/128/1f945.png b/twake/frontend/public/public/emojione/128/1f945.png new file mode 100644 index 00000000..c40f2584 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f945.png differ diff --git a/twake/frontend/public/public/emojione/128/1f947.png b/twake/frontend/public/public/emojione/128/1f947.png new file mode 100644 index 00000000..5dfb142b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f947.png differ diff --git a/twake/frontend/public/public/emojione/128/1f948.png b/twake/frontend/public/public/emojione/128/1f948.png new file mode 100644 index 00000000..55b36251 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f948.png differ diff --git a/twake/frontend/public/public/emojione/128/1f949.png b/twake/frontend/public/public/emojione/128/1f949.png new file mode 100644 index 00000000..d38fd6ae Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f949.png differ diff --git a/twake/frontend/public/public/emojione/128/1f94a.png b/twake/frontend/public/public/emojione/128/1f94a.png new file mode 100644 index 00000000..df9b8766 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f94a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f94b.png b/twake/frontend/public/public/emojione/128/1f94b.png new file mode 100644 index 00000000..3197cfb0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f94b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f94c.png b/twake/frontend/public/public/emojione/128/1f94c.png new file mode 100644 index 00000000..cf3d8cab Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f94c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f94d.png b/twake/frontend/public/public/emojione/128/1f94d.png new file mode 100644 index 00000000..a2391e4b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f94d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f94e.png b/twake/frontend/public/public/emojione/128/1f94e.png new file mode 100644 index 00000000..7944570c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f94e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f94f.png b/twake/frontend/public/public/emojione/128/1f94f.png new file mode 100644 index 00000000..8815d778 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f94f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f950.png b/twake/frontend/public/public/emojione/128/1f950.png new file mode 100644 index 00000000..01ce4fa9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f950.png differ diff --git a/twake/frontend/public/public/emojione/128/1f951.png b/twake/frontend/public/public/emojione/128/1f951.png new file mode 100644 index 00000000..999d6dc0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f951.png differ diff --git a/twake/frontend/public/public/emojione/128/1f952.png b/twake/frontend/public/public/emojione/128/1f952.png new file mode 100644 index 00000000..90a83fc6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f952.png differ diff --git a/twake/frontend/public/public/emojione/128/1f953.png b/twake/frontend/public/public/emojione/128/1f953.png new file mode 100644 index 00000000..eef9a758 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f953.png differ diff --git a/twake/frontend/public/public/emojione/128/1f954.png b/twake/frontend/public/public/emojione/128/1f954.png new file mode 100644 index 00000000..41267c7a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f954.png differ diff --git a/twake/frontend/public/public/emojione/128/1f955.png b/twake/frontend/public/public/emojione/128/1f955.png new file mode 100644 index 00000000..2531afab Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f955.png differ diff --git a/twake/frontend/public/public/emojione/128/1f956.png b/twake/frontend/public/public/emojione/128/1f956.png new file mode 100644 index 00000000..5b35c645 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f956.png differ diff --git a/twake/frontend/public/public/emojione/128/1f957.png b/twake/frontend/public/public/emojione/128/1f957.png new file mode 100644 index 00000000..85eefac9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f957.png differ diff --git a/twake/frontend/public/public/emojione/128/1f958.png b/twake/frontend/public/public/emojione/128/1f958.png new file mode 100644 index 00000000..786af6ce Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f958.png differ diff --git a/twake/frontend/public/public/emojione/128/1f959.png b/twake/frontend/public/public/emojione/128/1f959.png new file mode 100644 index 00000000..48498dbf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f959.png differ diff --git a/twake/frontend/public/public/emojione/128/1f95a.png b/twake/frontend/public/public/emojione/128/1f95a.png new file mode 100644 index 00000000..a8a72b55 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f95a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f95b.png b/twake/frontend/public/public/emojione/128/1f95b.png new file mode 100644 index 00000000..9a5eda4c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f95b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f95c.png b/twake/frontend/public/public/emojione/128/1f95c.png new file mode 100644 index 00000000..09a73e61 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f95c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f95d.png b/twake/frontend/public/public/emojione/128/1f95d.png new file mode 100644 index 00000000..2618b91a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f95d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f95e.png b/twake/frontend/public/public/emojione/128/1f95e.png new file mode 100644 index 00000000..9f6e0159 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f95e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f95f.png b/twake/frontend/public/public/emojione/128/1f95f.png new file mode 100644 index 00000000..d9ca068c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f95f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f960.png b/twake/frontend/public/public/emojione/128/1f960.png new file mode 100644 index 00000000..5adc62d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f960.png differ diff --git a/twake/frontend/public/public/emojione/128/1f961.png b/twake/frontend/public/public/emojione/128/1f961.png new file mode 100644 index 00000000..0c68e410 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f961.png differ diff --git a/twake/frontend/public/public/emojione/128/1f962.png b/twake/frontend/public/public/emojione/128/1f962.png new file mode 100644 index 00000000..441b3d14 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f962.png differ diff --git a/twake/frontend/public/public/emojione/128/1f963.png b/twake/frontend/public/public/emojione/128/1f963.png new file mode 100644 index 00000000..06e6310e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f963.png differ diff --git a/twake/frontend/public/public/emojione/128/1f964.png b/twake/frontend/public/public/emojione/128/1f964.png new file mode 100644 index 00000000..94953da2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f964.png differ diff --git a/twake/frontend/public/public/emojione/128/1f965.png b/twake/frontend/public/public/emojione/128/1f965.png new file mode 100644 index 00000000..82fb939a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f965.png differ diff --git a/twake/frontend/public/public/emojione/128/1f966.png b/twake/frontend/public/public/emojione/128/1f966.png new file mode 100644 index 00000000..3470f663 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f966.png differ diff --git a/twake/frontend/public/public/emojione/128/1f967.png b/twake/frontend/public/public/emojione/128/1f967.png new file mode 100644 index 00000000..1966b7cb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f967.png differ diff --git a/twake/frontend/public/public/emojione/128/1f968.png b/twake/frontend/public/public/emojione/128/1f968.png new file mode 100644 index 00000000..707d4a05 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f968.png differ diff --git a/twake/frontend/public/public/emojione/128/1f969.png b/twake/frontend/public/public/emojione/128/1f969.png new file mode 100644 index 00000000..7497bda8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f969.png differ diff --git a/twake/frontend/public/public/emojione/128/1f96a.png b/twake/frontend/public/public/emojione/128/1f96a.png new file mode 100644 index 00000000..32dc7c14 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f96a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f96b.png b/twake/frontend/public/public/emojione/128/1f96b.png new file mode 100644 index 00000000..1cbe5a3d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f96b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f96c.png b/twake/frontend/public/public/emojione/128/1f96c.png new file mode 100644 index 00000000..b89cc1da Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f96c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f96d.png b/twake/frontend/public/public/emojione/128/1f96d.png new file mode 100644 index 00000000..6e6e1101 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f96d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f96e.png b/twake/frontend/public/public/emojione/128/1f96e.png new file mode 100644 index 00000000..9aa95ffb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f96e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f96f.png b/twake/frontend/public/public/emojione/128/1f96f.png new file mode 100644 index 00000000..af974b86 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f96f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f970.png b/twake/frontend/public/public/emojione/128/1f970.png new file mode 100644 index 00000000..abe35af9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f970.png differ diff --git a/twake/frontend/public/public/emojione/128/1f973.png b/twake/frontend/public/public/emojione/128/1f973.png new file mode 100644 index 00000000..196ef9de Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f973.png differ diff --git a/twake/frontend/public/public/emojione/128/1f974.png b/twake/frontend/public/public/emojione/128/1f974.png new file mode 100644 index 00000000..848ad763 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f974.png differ diff --git a/twake/frontend/public/public/emojione/128/1f975.png b/twake/frontend/public/public/emojione/128/1f975.png new file mode 100644 index 00000000..c2183bbf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f975.png differ diff --git a/twake/frontend/public/public/emojione/128/1f976.png b/twake/frontend/public/public/emojione/128/1f976.png new file mode 100644 index 00000000..5a77f827 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f976.png differ diff --git a/twake/frontend/public/public/emojione/128/1f97a.png b/twake/frontend/public/public/emojione/128/1f97a.png new file mode 100644 index 00000000..0fd1024a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f97a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f97c.png b/twake/frontend/public/public/emojione/128/1f97c.png new file mode 100644 index 00000000..b51ce4f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f97c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f97d.png b/twake/frontend/public/public/emojione/128/1f97d.png new file mode 100644 index 00000000..2d471b61 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f97d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f97e.png b/twake/frontend/public/public/emojione/128/1f97e.png new file mode 100644 index 00000000..fbbe0307 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f97e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f97f.png b/twake/frontend/public/public/emojione/128/1f97f.png new file mode 100644 index 00000000..230148db Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f97f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f980.png b/twake/frontend/public/public/emojione/128/1f980.png new file mode 100644 index 00000000..0a1cc33c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f980.png differ diff --git a/twake/frontend/public/public/emojione/128/1f981.png b/twake/frontend/public/public/emojione/128/1f981.png new file mode 100644 index 00000000..854eefcf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f981.png differ diff --git a/twake/frontend/public/public/emojione/128/1f982.png b/twake/frontend/public/public/emojione/128/1f982.png new file mode 100644 index 00000000..0b824652 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f982.png differ diff --git a/twake/frontend/public/public/emojione/128/1f983.png b/twake/frontend/public/public/emojione/128/1f983.png new file mode 100644 index 00000000..85b2f6e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f983.png differ diff --git a/twake/frontend/public/public/emojione/128/1f984.png b/twake/frontend/public/public/emojione/128/1f984.png new file mode 100644 index 00000000..98b86f88 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f984.png differ diff --git a/twake/frontend/public/public/emojione/128/1f985.png b/twake/frontend/public/public/emojione/128/1f985.png new file mode 100644 index 00000000..388b3aa0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f985.png differ diff --git a/twake/frontend/public/public/emojione/128/1f986.png b/twake/frontend/public/public/emojione/128/1f986.png new file mode 100644 index 00000000..a5c38ecd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f986.png differ diff --git a/twake/frontend/public/public/emojione/128/1f987.png b/twake/frontend/public/public/emojione/128/1f987.png new file mode 100644 index 00000000..8358d88f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f987.png differ diff --git a/twake/frontend/public/public/emojione/128/1f988.png b/twake/frontend/public/public/emojione/128/1f988.png new file mode 100644 index 00000000..b4ad8ea1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f988.png differ diff --git a/twake/frontend/public/public/emojione/128/1f989.png b/twake/frontend/public/public/emojione/128/1f989.png new file mode 100644 index 00000000..b8e41212 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f989.png differ diff --git a/twake/frontend/public/public/emojione/128/1f98a.png b/twake/frontend/public/public/emojione/128/1f98a.png new file mode 100644 index 00000000..e37937cf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f98a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f98b.png b/twake/frontend/public/public/emojione/128/1f98b.png new file mode 100644 index 00000000..ee1259b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f98b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f98c.png b/twake/frontend/public/public/emojione/128/1f98c.png new file mode 100644 index 00000000..e3da5437 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f98c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f98d.png b/twake/frontend/public/public/emojione/128/1f98d.png new file mode 100644 index 00000000..1bcefda5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f98d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f98e.png b/twake/frontend/public/public/emojione/128/1f98e.png new file mode 100644 index 00000000..694a581e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f98e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f98f.png b/twake/frontend/public/public/emojione/128/1f98f.png new file mode 100644 index 00000000..6d35bf35 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f98f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f990.png b/twake/frontend/public/public/emojione/128/1f990.png new file mode 100644 index 00000000..d099c8eb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f990.png differ diff --git a/twake/frontend/public/public/emojione/128/1f991.png b/twake/frontend/public/public/emojione/128/1f991.png new file mode 100644 index 00000000..0d0988c9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f991.png differ diff --git a/twake/frontend/public/public/emojione/128/1f992.png b/twake/frontend/public/public/emojione/128/1f992.png new file mode 100644 index 00000000..d4c2b6b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f992.png differ diff --git a/twake/frontend/public/public/emojione/128/1f993.png b/twake/frontend/public/public/emojione/128/1f993.png new file mode 100644 index 00000000..d0af9fa8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f993.png differ diff --git a/twake/frontend/public/public/emojione/128/1f994.png b/twake/frontend/public/public/emojione/128/1f994.png new file mode 100644 index 00000000..d5a2767f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f994.png differ diff --git a/twake/frontend/public/public/emojione/128/1f995.png b/twake/frontend/public/public/emojione/128/1f995.png new file mode 100644 index 00000000..a5a2f129 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f995.png differ diff --git a/twake/frontend/public/public/emojione/128/1f996.png b/twake/frontend/public/public/emojione/128/1f996.png new file mode 100644 index 00000000..ef63c177 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f996.png differ diff --git a/twake/frontend/public/public/emojione/128/1f997.png b/twake/frontend/public/public/emojione/128/1f997.png new file mode 100644 index 00000000..8f69ec85 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f997.png differ diff --git a/twake/frontend/public/public/emojione/128/1f998.png b/twake/frontend/public/public/emojione/128/1f998.png new file mode 100644 index 00000000..3951ca69 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f998.png differ diff --git a/twake/frontend/public/public/emojione/128/1f999.png b/twake/frontend/public/public/emojione/128/1f999.png new file mode 100644 index 00000000..983397aa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f999.png differ diff --git a/twake/frontend/public/public/emojione/128/1f99a.png b/twake/frontend/public/public/emojione/128/1f99a.png new file mode 100644 index 00000000..7b1bcced Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f99a.png differ diff --git a/twake/frontend/public/public/emojione/128/1f99b.png b/twake/frontend/public/public/emojione/128/1f99b.png new file mode 100644 index 00000000..dc26606e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f99b.png differ diff --git a/twake/frontend/public/public/emojione/128/1f99c.png b/twake/frontend/public/public/emojione/128/1f99c.png new file mode 100644 index 00000000..64ae9de8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f99c.png differ diff --git a/twake/frontend/public/public/emojione/128/1f99d.png b/twake/frontend/public/public/emojione/128/1f99d.png new file mode 100644 index 00000000..5d4cd59f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f99d.png differ diff --git a/twake/frontend/public/public/emojione/128/1f99e.png b/twake/frontend/public/public/emojione/128/1f99e.png new file mode 100644 index 00000000..36b33be5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f99e.png differ diff --git a/twake/frontend/public/public/emojione/128/1f99f.png b/twake/frontend/public/public/emojione/128/1f99f.png new file mode 100644 index 00000000..7ddb4c3a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f99f.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9a0.png b/twake/frontend/public/public/emojione/128/1f9a0.png new file mode 100644 index 00000000..1df76ad7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9a0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9a1.png b/twake/frontend/public/public/emojione/128/1f9a1.png new file mode 100644 index 00000000..06d4b4bf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9a1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9a2.png b/twake/frontend/public/public/emojione/128/1f9a2.png new file mode 100644 index 00000000..4f477a8b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9a2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b0.png b/twake/frontend/public/public/emojione/128/1f9b0.png new file mode 100644 index 00000000..a277817f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b1.png b/twake/frontend/public/public/emojione/128/1f9b1.png new file mode 100644 index 00000000..3767ce0d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b2.png b/twake/frontend/public/public/emojione/128/1f9b2.png new file mode 100644 index 00000000..1edff97f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b3.png b/twake/frontend/public/public/emojione/128/1f9b3.png new file mode 100644 index 00000000..86cb4d9c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b4.png b/twake/frontend/public/public/emojione/128/1f9b4.png new file mode 100644 index 00000000..d4b01e8f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b5-1f3fb.png b/twake/frontend/public/public/emojione/128/1f9b5-1f3fb.png new file mode 100644 index 00000000..17aceccf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b5-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b5-1f3fc.png b/twake/frontend/public/public/emojione/128/1f9b5-1f3fc.png new file mode 100644 index 00000000..cb44f576 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b5-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b5-1f3fd.png b/twake/frontend/public/public/emojione/128/1f9b5-1f3fd.png new file mode 100644 index 00000000..aeed811a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b5-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b5-1f3fe.png b/twake/frontend/public/public/emojione/128/1f9b5-1f3fe.png new file mode 100644 index 00000000..1c24d2b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b5-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b5-1f3ff.png b/twake/frontend/public/public/emojione/128/1f9b5-1f3ff.png new file mode 100644 index 00000000..17813758 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b5-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b5.png b/twake/frontend/public/public/emojione/128/1f9b5.png new file mode 100644 index 00000000..e7985977 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b6-1f3fb.png b/twake/frontend/public/public/emojione/128/1f9b6-1f3fb.png new file mode 100644 index 00000000..b72b2798 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b6-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b6-1f3fc.png b/twake/frontend/public/public/emojione/128/1f9b6-1f3fc.png new file mode 100644 index 00000000..7df3a222 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b6-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b6-1f3fd.png b/twake/frontend/public/public/emojione/128/1f9b6-1f3fd.png new file mode 100644 index 00000000..48faf7aa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b6-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b6-1f3fe.png b/twake/frontend/public/public/emojione/128/1f9b6-1f3fe.png new file mode 100644 index 00000000..ea663ca8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b6-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b6-1f3ff.png b/twake/frontend/public/public/emojione/128/1f9b6-1f3ff.png new file mode 100644 index 00000000..ab0f9d85 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b6-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b6.png b/twake/frontend/public/public/emojione/128/1f9b6.png new file mode 100644 index 00000000..7b2b162e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b7.png b/twake/frontend/public/public/emojione/128/1f9b7.png new file mode 100644 index 00000000..b2248c4e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f9b8-1f3fb-2640.png new file mode 100644 index 00000000..f68d276b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f9b8-1f3fb-2642.png new file mode 100644 index 00000000..b7a48b41 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8-1f3fb.png b/twake/frontend/public/public/emojione/128/1f9b8-1f3fb.png new file mode 100644 index 00000000..f68d276b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f9b8-1f3fc-2640.png new file mode 100644 index 00000000..5cb6bc21 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f9b8-1f3fc-2642.png new file mode 100644 index 00000000..1e0eee9e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8-1f3fc.png b/twake/frontend/public/public/emojione/128/1f9b8-1f3fc.png new file mode 100644 index 00000000..5cb6bc21 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f9b8-1f3fd-2640.png new file mode 100644 index 00000000..caf9d936 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f9b8-1f3fd-2642.png new file mode 100644 index 00000000..fe6bcda2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8-1f3fd.png b/twake/frontend/public/public/emojione/128/1f9b8-1f3fd.png new file mode 100644 index 00000000..caf9d936 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f9b8-1f3fe-2640.png new file mode 100644 index 00000000..bdd21be6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f9b8-1f3fe-2642.png new file mode 100644 index 00000000..38b91695 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8-1f3fe.png b/twake/frontend/public/public/emojione/128/1f9b8-1f3fe.png new file mode 100644 index 00000000..bdd21be6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f9b8-1f3ff-2640.png new file mode 100644 index 00000000..e2b44090 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f9b8-1f3ff-2642.png new file mode 100644 index 00000000..07b935fb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8-1f3ff.png b/twake/frontend/public/public/emojione/128/1f9b8-1f3ff.png new file mode 100644 index 00000000..e2b44090 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8-2640.png b/twake/frontend/public/public/emojione/128/1f9b8-2640.png new file mode 100644 index 00000000..11527e89 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8-2642.png b/twake/frontend/public/public/emojione/128/1f9b8-2642.png new file mode 100644 index 00000000..defec594 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b8.png b/twake/frontend/public/public/emojione/128/1f9b8.png new file mode 100644 index 00000000..11527e89 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f9b9-1f3fb-2640.png new file mode 100644 index 00000000..e5d7c6c5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f9b9-1f3fb-2642.png new file mode 100644 index 00000000..c44fd2c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9-1f3fb.png b/twake/frontend/public/public/emojione/128/1f9b9-1f3fb.png new file mode 100644 index 00000000..e5d7c6c5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f9b9-1f3fc-2640.png new file mode 100644 index 00000000..1a2ec084 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f9b9-1f3fc-2642.png new file mode 100644 index 00000000..03c19fad Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9-1f3fc.png b/twake/frontend/public/public/emojione/128/1f9b9-1f3fc.png new file mode 100644 index 00000000..1a2ec084 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f9b9-1f3fd-2640.png new file mode 100644 index 00000000..8f7ae462 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f9b9-1f3fd-2642.png new file mode 100644 index 00000000..cb2529b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9-1f3fd.png b/twake/frontend/public/public/emojione/128/1f9b9-1f3fd.png new file mode 100644 index 00000000..8f7ae462 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f9b9-1f3fe-2640.png new file mode 100644 index 00000000..b3b94cb7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f9b9-1f3fe-2642.png new file mode 100644 index 00000000..44eeffcb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9-1f3fe.png b/twake/frontend/public/public/emojione/128/1f9b9-1f3fe.png new file mode 100644 index 00000000..b3b94cb7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f9b9-1f3ff-2640.png new file mode 100644 index 00000000..673c575d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f9b9-1f3ff-2642.png new file mode 100644 index 00000000..755b1264 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9-1f3ff.png b/twake/frontend/public/public/emojione/128/1f9b9-1f3ff.png new file mode 100644 index 00000000..673c575d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9-2640.png b/twake/frontend/public/public/emojione/128/1f9b9-2640.png new file mode 100644 index 00000000..3919ad85 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9-2642.png b/twake/frontend/public/public/emojione/128/1f9b9-2642.png new file mode 100644 index 00000000..83fa72d5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9b9.png b/twake/frontend/public/public/emojione/128/1f9b9.png new file mode 100644 index 00000000..3919ad85 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9b9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9c0.png b/twake/frontend/public/public/emojione/128/1f9c0.png new file mode 100644 index 00000000..4455642a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9c0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9c1.png b/twake/frontend/public/public/emojione/128/1f9c1.png new file mode 100644 index 00000000..fef59284 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9c1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9c2.png b/twake/frontend/public/public/emojione/128/1f9c2.png new file mode 100644 index 00000000..e00483fd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9c2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d0.png b/twake/frontend/public/public/emojione/128/1f9d0.png new file mode 100644 index 00000000..b1cc4e30 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d1-1f3fb.png b/twake/frontend/public/public/emojione/128/1f9d1-1f3fb.png new file mode 100644 index 00000000..b592618e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d1-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d1-1f3fc.png b/twake/frontend/public/public/emojione/128/1f9d1-1f3fc.png new file mode 100644 index 00000000..3364e1a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d1-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d1-1f3fd.png b/twake/frontend/public/public/emojione/128/1f9d1-1f3fd.png new file mode 100644 index 00000000..52aef0c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d1-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d1-1f3fe.png b/twake/frontend/public/public/emojione/128/1f9d1-1f3fe.png new file mode 100644 index 00000000..a6da441d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d1-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d1-1f3ff.png b/twake/frontend/public/public/emojione/128/1f9d1-1f3ff.png new file mode 100644 index 00000000..37322ec6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d1-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d1.png b/twake/frontend/public/public/emojione/128/1f9d1.png new file mode 100644 index 00000000..3bc3bd74 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d2-1f3fb.png b/twake/frontend/public/public/emojione/128/1f9d2-1f3fb.png new file mode 100644 index 00000000..49a19c4f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d2-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d2-1f3fc.png b/twake/frontend/public/public/emojione/128/1f9d2-1f3fc.png new file mode 100644 index 00000000..b6ac8eb5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d2-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d2-1f3fd.png b/twake/frontend/public/public/emojione/128/1f9d2-1f3fd.png new file mode 100644 index 00000000..bf5d2ea4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d2-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d2-1f3fe.png b/twake/frontend/public/public/emojione/128/1f9d2-1f3fe.png new file mode 100644 index 00000000..ff272d8a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d2-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d2-1f3ff.png b/twake/frontend/public/public/emojione/128/1f9d2-1f3ff.png new file mode 100644 index 00000000..942f863d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d2-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d2.png b/twake/frontend/public/public/emojione/128/1f9d2.png new file mode 100644 index 00000000..bc6d29ad Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d3-1f3fb.png b/twake/frontend/public/public/emojione/128/1f9d3-1f3fb.png new file mode 100644 index 00000000..6f7809db Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d3-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d3-1f3fc.png b/twake/frontend/public/public/emojione/128/1f9d3-1f3fc.png new file mode 100644 index 00000000..35166b57 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d3-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d3-1f3fd.png b/twake/frontend/public/public/emojione/128/1f9d3-1f3fd.png new file mode 100644 index 00000000..62192056 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d3-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d3-1f3fe.png b/twake/frontend/public/public/emojione/128/1f9d3-1f3fe.png new file mode 100644 index 00000000..5b58d0c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d3-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d3-1f3ff.png b/twake/frontend/public/public/emojione/128/1f9d3-1f3ff.png new file mode 100644 index 00000000..c84b33ea Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d3-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d3.png b/twake/frontend/public/public/emojione/128/1f9d3.png new file mode 100644 index 00000000..a2cb1c4f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d4-1f3fb.png b/twake/frontend/public/public/emojione/128/1f9d4-1f3fb.png new file mode 100644 index 00000000..c8817bfb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d4-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d4-1f3fc.png b/twake/frontend/public/public/emojione/128/1f9d4-1f3fc.png new file mode 100644 index 00000000..4360c617 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d4-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d4-1f3fd.png b/twake/frontend/public/public/emojione/128/1f9d4-1f3fd.png new file mode 100644 index 00000000..2b47d4d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d4-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d4-1f3fe.png b/twake/frontend/public/public/emojione/128/1f9d4-1f3fe.png new file mode 100644 index 00000000..68cee454 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d4-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d4-1f3ff.png b/twake/frontend/public/public/emojione/128/1f9d4-1f3ff.png new file mode 100644 index 00000000..e64a793d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d4-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d4.png b/twake/frontend/public/public/emojione/128/1f9d4.png new file mode 100644 index 00000000..1fc34269 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d5-1f3fb.png b/twake/frontend/public/public/emojione/128/1f9d5-1f3fb.png new file mode 100644 index 00000000..1e4c310b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d5-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d5-1f3fc.png b/twake/frontend/public/public/emojione/128/1f9d5-1f3fc.png new file mode 100644 index 00000000..cceffb56 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d5-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d5-1f3fd.png b/twake/frontend/public/public/emojione/128/1f9d5-1f3fd.png new file mode 100644 index 00000000..bb9e8eb8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d5-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d5-1f3fe.png b/twake/frontend/public/public/emojione/128/1f9d5-1f3fe.png new file mode 100644 index 00000000..426381b7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d5-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d5-1f3ff.png b/twake/frontend/public/public/emojione/128/1f9d5-1f3ff.png new file mode 100644 index 00000000..5a635d13 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d5-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d5.png b/twake/frontend/public/public/emojione/128/1f9d5.png new file mode 100644 index 00000000..40de327f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f9d6-1f3fb-2640.png new file mode 100644 index 00000000..75a0f54d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f9d6-1f3fb-2642.png new file mode 100644 index 00000000..2d6b5995 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6-1f3fb.png b/twake/frontend/public/public/emojione/128/1f9d6-1f3fb.png new file mode 100644 index 00000000..75a0f54d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f9d6-1f3fc-2640.png new file mode 100644 index 00000000..ea45aaae Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f9d6-1f3fc-2642.png new file mode 100644 index 00000000..215337ec Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6-1f3fc.png b/twake/frontend/public/public/emojione/128/1f9d6-1f3fc.png new file mode 100644 index 00000000..ea45aaae Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f9d6-1f3fd-2640.png new file mode 100644 index 00000000..89a48586 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f9d6-1f3fd-2642.png new file mode 100644 index 00000000..1ec29c27 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6-1f3fd.png b/twake/frontend/public/public/emojione/128/1f9d6-1f3fd.png new file mode 100644 index 00000000..89a48586 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f9d6-1f3fe-2640.png new file mode 100644 index 00000000..86b884e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f9d6-1f3fe-2642.png new file mode 100644 index 00000000..bcc53fa2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6-1f3fe.png b/twake/frontend/public/public/emojione/128/1f9d6-1f3fe.png new file mode 100644 index 00000000..86b884e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f9d6-1f3ff-2640.png new file mode 100644 index 00000000..3b459a2b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f9d6-1f3ff-2642.png new file mode 100644 index 00000000..240e8257 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6-1f3ff.png b/twake/frontend/public/public/emojione/128/1f9d6-1f3ff.png new file mode 100644 index 00000000..3b459a2b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6-2640.png b/twake/frontend/public/public/emojione/128/1f9d6-2640.png new file mode 100644 index 00000000..00fb1c75 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6-2642.png b/twake/frontend/public/public/emojione/128/1f9d6-2642.png new file mode 100644 index 00000000..4b55b81e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d6.png b/twake/frontend/public/public/emojione/128/1f9d6.png new file mode 100644 index 00000000..00fb1c75 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f9d7-1f3fb-2640.png new file mode 100644 index 00000000..d7ff8d8f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f9d7-1f3fb-2642.png new file mode 100644 index 00000000..0d06badf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7-1f3fb.png b/twake/frontend/public/public/emojione/128/1f9d7-1f3fb.png new file mode 100644 index 00000000..d7ff8d8f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f9d7-1f3fc-2640.png new file mode 100644 index 00000000..211378c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f9d7-1f3fc-2642.png new file mode 100644 index 00000000..0fd2f9af Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7-1f3fc.png b/twake/frontend/public/public/emojione/128/1f9d7-1f3fc.png new file mode 100644 index 00000000..211378c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f9d7-1f3fd-2640.png new file mode 100644 index 00000000..126a38b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f9d7-1f3fd-2642.png new file mode 100644 index 00000000..ff118581 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7-1f3fd.png b/twake/frontend/public/public/emojione/128/1f9d7-1f3fd.png new file mode 100644 index 00000000..126a38b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f9d7-1f3fe-2640.png new file mode 100644 index 00000000..dc691fb0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f9d7-1f3fe-2642.png new file mode 100644 index 00000000..d718c28a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7-1f3fe.png b/twake/frontend/public/public/emojione/128/1f9d7-1f3fe.png new file mode 100644 index 00000000..dc691fb0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f9d7-1f3ff-2640.png new file mode 100644 index 00000000..e9437dca Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f9d7-1f3ff-2642.png new file mode 100644 index 00000000..7547afad Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7-1f3ff.png b/twake/frontend/public/public/emojione/128/1f9d7-1f3ff.png new file mode 100644 index 00000000..e9437dca Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7-2640.png b/twake/frontend/public/public/emojione/128/1f9d7-2640.png new file mode 100644 index 00000000..c10e80cc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7-2642.png b/twake/frontend/public/public/emojione/128/1f9d7-2642.png new file mode 100644 index 00000000..c7dcb861 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d7.png b/twake/frontend/public/public/emojione/128/1f9d7.png new file mode 100644 index 00000000..fea18232 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f9d8-1f3fb-2640.png new file mode 100644 index 00000000..b8d45bec Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f9d8-1f3fb-2642.png new file mode 100644 index 00000000..79363a23 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8-1f3fb.png b/twake/frontend/public/public/emojione/128/1f9d8-1f3fb.png new file mode 100644 index 00000000..b8d45bec Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f9d8-1f3fc-2640.png new file mode 100644 index 00000000..270cdf88 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f9d8-1f3fc-2642.png new file mode 100644 index 00000000..8f5d43fa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8-1f3fc.png b/twake/frontend/public/public/emojione/128/1f9d8-1f3fc.png new file mode 100644 index 00000000..270cdf88 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f9d8-1f3fd-2640.png new file mode 100644 index 00000000..764e1b16 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f9d8-1f3fd-2642.png new file mode 100644 index 00000000..e7d77bb0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8-1f3fd.png b/twake/frontend/public/public/emojione/128/1f9d8-1f3fd.png new file mode 100644 index 00000000..764e1b16 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f9d8-1f3fe-2640.png new file mode 100644 index 00000000..1f634933 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f9d8-1f3fe-2642.png new file mode 100644 index 00000000..1b349efa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8-1f3fe.png b/twake/frontend/public/public/emojione/128/1f9d8-1f3fe.png new file mode 100644 index 00000000..1f634933 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f9d8-1f3ff-2640.png new file mode 100644 index 00000000..bb222f96 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f9d8-1f3ff-2642.png new file mode 100644 index 00000000..7a04c2db Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8-1f3ff.png b/twake/frontend/public/public/emojione/128/1f9d8-1f3ff.png new file mode 100644 index 00000000..bb222f96 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8-2640.png b/twake/frontend/public/public/emojione/128/1f9d8-2640.png new file mode 100644 index 00000000..71cef454 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8-2642.png b/twake/frontend/public/public/emojione/128/1f9d8-2642.png new file mode 100644 index 00000000..d7b8364a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d8.png b/twake/frontend/public/public/emojione/128/1f9d8.png new file mode 100644 index 00000000..71cef454 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f9d9-1f3fb-2640.png new file mode 100644 index 00000000..fd675d09 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f9d9-1f3fb-2642.png new file mode 100644 index 00000000..71e71f2f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9-1f3fb.png b/twake/frontend/public/public/emojione/128/1f9d9-1f3fb.png new file mode 100644 index 00000000..fd675d09 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f9d9-1f3fc-2640.png new file mode 100644 index 00000000..bbcd9b2f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f9d9-1f3fc-2642.png new file mode 100644 index 00000000..854bb9b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9-1f3fc.png b/twake/frontend/public/public/emojione/128/1f9d9-1f3fc.png new file mode 100644 index 00000000..bbcd9b2f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f9d9-1f3fd-2640.png new file mode 100644 index 00000000..f9aabe9e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f9d9-1f3fd-2642.png new file mode 100644 index 00000000..c288fa3a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9-1f3fd.png b/twake/frontend/public/public/emojione/128/1f9d9-1f3fd.png new file mode 100644 index 00000000..f9aabe9e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f9d9-1f3fe-2640.png new file mode 100644 index 00000000..ace34309 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f9d9-1f3fe-2642.png new file mode 100644 index 00000000..1aa075ec Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9-1f3fe.png b/twake/frontend/public/public/emojione/128/1f9d9-1f3fe.png new file mode 100644 index 00000000..ace34309 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f9d9-1f3ff-2640.png new file mode 100644 index 00000000..99a24042 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f9d9-1f3ff-2642.png new file mode 100644 index 00000000..bdee491c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9-1f3ff.png b/twake/frontend/public/public/emojione/128/1f9d9-1f3ff.png new file mode 100644 index 00000000..99a24042 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9-2640.png b/twake/frontend/public/public/emojione/128/1f9d9-2640.png new file mode 100644 index 00000000..2ed0e90e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9-2642.png b/twake/frontend/public/public/emojione/128/1f9d9-2642.png new file mode 100644 index 00000000..84f48093 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9d9.png b/twake/frontend/public/public/emojione/128/1f9d9.png new file mode 100644 index 00000000..2ed0e90e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9d9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f9da-1f3fb-2640.png new file mode 100644 index 00000000..8cc97191 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f9da-1f3fb-2642.png new file mode 100644 index 00000000..840132da Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da-1f3fb.png b/twake/frontend/public/public/emojione/128/1f9da-1f3fb.png new file mode 100644 index 00000000..8cc97191 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f9da-1f3fc-2640.png new file mode 100644 index 00000000..a9633901 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f9da-1f3fc-2642.png new file mode 100644 index 00000000..d70db242 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da-1f3fc.png b/twake/frontend/public/public/emojione/128/1f9da-1f3fc.png new file mode 100644 index 00000000..a9633901 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f9da-1f3fd-2640.png new file mode 100644 index 00000000..cc9da0f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f9da-1f3fd-2642.png new file mode 100644 index 00000000..1fe24ed5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da-1f3fd.png b/twake/frontend/public/public/emojione/128/1f9da-1f3fd.png new file mode 100644 index 00000000..cc9da0f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f9da-1f3fe-2640.png new file mode 100644 index 00000000..3e7801b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f9da-1f3fe-2642.png new file mode 100644 index 00000000..7a8d65b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da-1f3fe.png b/twake/frontend/public/public/emojione/128/1f9da-1f3fe.png new file mode 100644 index 00000000..3e7801b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f9da-1f3ff-2640.png new file mode 100644 index 00000000..1e54c5d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f9da-1f3ff-2642.png new file mode 100644 index 00000000..f51cd38a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da-1f3ff.png b/twake/frontend/public/public/emojione/128/1f9da-1f3ff.png new file mode 100644 index 00000000..1e54c5d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da-2640.png b/twake/frontend/public/public/emojione/128/1f9da-2640.png new file mode 100644 index 00000000..a22a89f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da-2642.png b/twake/frontend/public/public/emojione/128/1f9da-2642.png new file mode 100644 index 00000000..45e5ed2b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9da.png b/twake/frontend/public/public/emojione/128/1f9da.png new file mode 100644 index 00000000..a22a89f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9da.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f9db-1f3fb-2640.png new file mode 100644 index 00000000..9df3ad8a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f9db-1f3fb-2642.png new file mode 100644 index 00000000..22a27330 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db-1f3fb.png b/twake/frontend/public/public/emojione/128/1f9db-1f3fb.png new file mode 100644 index 00000000..9df3ad8a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f9db-1f3fc-2640.png new file mode 100644 index 00000000..112608e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f9db-1f3fc-2642.png new file mode 100644 index 00000000..8ffd31b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db-1f3fc.png b/twake/frontend/public/public/emojione/128/1f9db-1f3fc.png new file mode 100644 index 00000000..112608e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f9db-1f3fd-2640.png new file mode 100644 index 00000000..4c14230d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f9db-1f3fd-2642.png new file mode 100644 index 00000000..0d7ff295 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db-1f3fd.png b/twake/frontend/public/public/emojione/128/1f9db-1f3fd.png new file mode 100644 index 00000000..4c14230d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f9db-1f3fe-2640.png new file mode 100644 index 00000000..434ea512 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f9db-1f3fe-2642.png new file mode 100644 index 00000000..50e97f3b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db-1f3fe.png b/twake/frontend/public/public/emojione/128/1f9db-1f3fe.png new file mode 100644 index 00000000..434ea512 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f9db-1f3ff-2640.png new file mode 100644 index 00000000..31a9aa61 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f9db-1f3ff-2642.png new file mode 100644 index 00000000..fdc6810d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db-1f3ff.png b/twake/frontend/public/public/emojione/128/1f9db-1f3ff.png new file mode 100644 index 00000000..31a9aa61 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db-2640.png b/twake/frontend/public/public/emojione/128/1f9db-2640.png new file mode 100644 index 00000000..73a9cf73 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db-2642.png b/twake/frontend/public/public/emojione/128/1f9db-2642.png new file mode 100644 index 00000000..241e446e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9db.png b/twake/frontend/public/public/emojione/128/1f9db.png new file mode 100644 index 00000000..73a9cf73 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9db.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f9dc-1f3fb-2640.png new file mode 100644 index 00000000..44f9b3be Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f9dc-1f3fb-2642.png new file mode 100644 index 00000000..22cc33c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc-1f3fb.png b/twake/frontend/public/public/emojione/128/1f9dc-1f3fb.png new file mode 100644 index 00000000..44f9b3be Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f9dc-1f3fc-2640.png new file mode 100644 index 00000000..03ee9262 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f9dc-1f3fc-2642.png new file mode 100644 index 00000000..5fd15e2d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc-1f3fc.png b/twake/frontend/public/public/emojione/128/1f9dc-1f3fc.png new file mode 100644 index 00000000..03ee9262 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f9dc-1f3fd-2640.png new file mode 100644 index 00000000..1e6ff8e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f9dc-1f3fd-2642.png new file mode 100644 index 00000000..e1c2a64e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc-1f3fd.png b/twake/frontend/public/public/emojione/128/1f9dc-1f3fd.png new file mode 100644 index 00000000..1e6ff8e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f9dc-1f3fe-2640.png new file mode 100644 index 00000000..ee68ed2f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f9dc-1f3fe-2642.png new file mode 100644 index 00000000..d5225cbb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc-1f3fe.png b/twake/frontend/public/public/emojione/128/1f9dc-1f3fe.png new file mode 100644 index 00000000..ee68ed2f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f9dc-1f3ff-2640.png new file mode 100644 index 00000000..3c3cb3e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f9dc-1f3ff-2642.png new file mode 100644 index 00000000..d975aff9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc-1f3ff.png b/twake/frontend/public/public/emojione/128/1f9dc-1f3ff.png new file mode 100644 index 00000000..3c3cb3e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc-2640.png b/twake/frontend/public/public/emojione/128/1f9dc-2640.png new file mode 100644 index 00000000..4d543d02 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc-2642.png b/twake/frontend/public/public/emojione/128/1f9dc-2642.png new file mode 100644 index 00000000..7da7ba7f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dc.png b/twake/frontend/public/public/emojione/128/1f9dc.png new file mode 100644 index 00000000..2cce551c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/1f9dd-1f3fb-2640.png new file mode 100644 index 00000000..b15c3724 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/1f9dd-1f3fb-2642.png new file mode 100644 index 00000000..9f35367e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd-1f3fb.png b/twake/frontend/public/public/emojione/128/1f9dd-1f3fb.png new file mode 100644 index 00000000..b15c3724 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/1f9dd-1f3fc-2640.png new file mode 100644 index 00000000..b3690057 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/1f9dd-1f3fc-2642.png new file mode 100644 index 00000000..1a198d45 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd-1f3fc.png b/twake/frontend/public/public/emojione/128/1f9dd-1f3fc.png new file mode 100644 index 00000000..b3690057 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/1f9dd-1f3fd-2640.png new file mode 100644 index 00000000..3aec5629 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/1f9dd-1f3fd-2642.png new file mode 100644 index 00000000..3ff7800d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd-1f3fd.png b/twake/frontend/public/public/emojione/128/1f9dd-1f3fd.png new file mode 100644 index 00000000..3aec5629 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/1f9dd-1f3fe-2640.png new file mode 100644 index 00000000..2007da41 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/1f9dd-1f3fe-2642.png new file mode 100644 index 00000000..23af3f2d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd-1f3fe.png b/twake/frontend/public/public/emojione/128/1f9dd-1f3fe.png new file mode 100644 index 00000000..2007da41 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/1f9dd-1f3ff-2640.png new file mode 100644 index 00000000..fb49f606 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/1f9dd-1f3ff-2642.png new file mode 100644 index 00000000..76560c8d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd-1f3ff.png b/twake/frontend/public/public/emojione/128/1f9dd-1f3ff.png new file mode 100644 index 00000000..fb49f606 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd-2640.png b/twake/frontend/public/public/emojione/128/1f9dd-2640.png new file mode 100644 index 00000000..2040400e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd-2642.png b/twake/frontend/public/public/emojione/128/1f9dd-2642.png new file mode 100644 index 00000000..64f24c83 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9dd.png b/twake/frontend/public/public/emojione/128/1f9dd.png new file mode 100644 index 00000000..2040400e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9dd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9de-2640.png b/twake/frontend/public/public/emojione/128/1f9de-2640.png new file mode 100644 index 00000000..52188f6c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9de-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9de-2642.png b/twake/frontend/public/public/emojione/128/1f9de-2642.png new file mode 100644 index 00000000..2bd62d90 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9de-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9de.png b/twake/frontend/public/public/emojione/128/1f9de.png new file mode 100644 index 00000000..52188f6c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9de.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9df-2640.png b/twake/frontend/public/public/emojione/128/1f9df-2640.png new file mode 100644 index 00000000..e58e2557 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9df-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9df-2642.png b/twake/frontend/public/public/emojione/128/1f9df-2642.png new file mode 100644 index 00000000..056c195b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9df-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9df.png b/twake/frontend/public/public/emojione/128/1f9df.png new file mode 100644 index 00000000..e58e2557 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9df.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9e0.png b/twake/frontend/public/public/emojione/128/1f9e0.png new file mode 100644 index 00000000..f3b45ac8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9e0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9e1.png b/twake/frontend/public/public/emojione/128/1f9e1.png new file mode 100644 index 00000000..e5128272 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9e1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9e2.png b/twake/frontend/public/public/emojione/128/1f9e2.png new file mode 100644 index 00000000..521a7aeb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9e2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9e3.png b/twake/frontend/public/public/emojione/128/1f9e3.png new file mode 100644 index 00000000..26e3e008 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9e3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9e4.png b/twake/frontend/public/public/emojione/128/1f9e4.png new file mode 100644 index 00000000..8dca16a1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9e4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9e5.png b/twake/frontend/public/public/emojione/128/1f9e5.png new file mode 100644 index 00000000..3dc322ef Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9e5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9e6.png b/twake/frontend/public/public/emojione/128/1f9e6.png new file mode 100644 index 00000000..8f9badea Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9e6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9e7.png b/twake/frontend/public/public/emojione/128/1f9e7.png new file mode 100644 index 00000000..6b234473 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9e7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9e8.png b/twake/frontend/public/public/emojione/128/1f9e8.png new file mode 100644 index 00000000..ebd2ca71 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9e8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9e9.png b/twake/frontend/public/public/emojione/128/1f9e9.png new file mode 100644 index 00000000..e612d105 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9e9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9ea.png b/twake/frontend/public/public/emojione/128/1f9ea.png new file mode 100644 index 00000000..4f52fcf4 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9ea.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9eb.png b/twake/frontend/public/public/emojione/128/1f9eb.png new file mode 100644 index 00000000..a8286df0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9eb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9ec.png b/twake/frontend/public/public/emojione/128/1f9ec.png new file mode 100644 index 00000000..3e500cbd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9ec.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9ed.png b/twake/frontend/public/public/emojione/128/1f9ed.png new file mode 100644 index 00000000..a5d04a23 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9ed.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9ee.png b/twake/frontend/public/public/emojione/128/1f9ee.png new file mode 100644 index 00000000..0078b38c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9ee.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9ef.png b/twake/frontend/public/public/emojione/128/1f9ef.png new file mode 100644 index 00000000..abf0c605 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9ef.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9f0.png b/twake/frontend/public/public/emojione/128/1f9f0.png new file mode 100644 index 00000000..739e6695 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9f0.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9f1.png b/twake/frontend/public/public/emojione/128/1f9f1.png new file mode 100644 index 00000000..400d8337 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9f1.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9f2.png b/twake/frontend/public/public/emojione/128/1f9f2.png new file mode 100644 index 00000000..63f5e39c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9f2.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9f3.png b/twake/frontend/public/public/emojione/128/1f9f3.png new file mode 100644 index 00000000..b8305818 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9f3.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9f4.png b/twake/frontend/public/public/emojione/128/1f9f4.png new file mode 100644 index 00000000..b4124da3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9f4.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9f5.png b/twake/frontend/public/public/emojione/128/1f9f5.png new file mode 100644 index 00000000..d822d52e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9f5.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9f6.png b/twake/frontend/public/public/emojione/128/1f9f6.png new file mode 100644 index 00000000..28f92f12 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9f6.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9f7.png b/twake/frontend/public/public/emojione/128/1f9f7.png new file mode 100644 index 00000000..a51e994e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9f7.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9f8.png b/twake/frontend/public/public/emojione/128/1f9f8.png new file mode 100644 index 00000000..ba152c61 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9f8.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9f9.png b/twake/frontend/public/public/emojione/128/1f9f9.png new file mode 100644 index 00000000..08fc6104 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9f9.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9fa.png b/twake/frontend/public/public/emojione/128/1f9fa.png new file mode 100644 index 00000000..1d9713a1 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9fa.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9fb.png b/twake/frontend/public/public/emojione/128/1f9fb.png new file mode 100644 index 00000000..4aec7e37 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9fb.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9fc.png b/twake/frontend/public/public/emojione/128/1f9fc.png new file mode 100644 index 00000000..21b9ec33 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9fc.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9fd.png b/twake/frontend/public/public/emojione/128/1f9fd.png new file mode 100644 index 00000000..e17f368b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9fd.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9fe.png b/twake/frontend/public/public/emojione/128/1f9fe.png new file mode 100644 index 00000000..2f7f3102 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9fe.png differ diff --git a/twake/frontend/public/public/emojione/128/1f9ff.png b/twake/frontend/public/public/emojione/128/1f9ff.png new file mode 100644 index 00000000..ddc421b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/1f9ff.png differ diff --git a/twake/frontend/public/public/emojione/128/203c.png b/twake/frontend/public/public/emojione/128/203c.png new file mode 100644 index 00000000..d578ddc7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/203c.png differ diff --git a/twake/frontend/public/public/emojione/128/2049.png b/twake/frontend/public/public/emojione/128/2049.png new file mode 100644 index 00000000..102ede45 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2049.png differ diff --git a/twake/frontend/public/public/emojione/128/2122.png b/twake/frontend/public/public/emojione/128/2122.png new file mode 100644 index 00000000..01e913ea Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2122.png differ diff --git a/twake/frontend/public/public/emojione/128/2139.png b/twake/frontend/public/public/emojione/128/2139.png new file mode 100644 index 00000000..7dfa81e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2139.png differ diff --git a/twake/frontend/public/public/emojione/128/2194.png b/twake/frontend/public/public/emojione/128/2194.png new file mode 100644 index 00000000..2c23d414 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2194.png differ diff --git a/twake/frontend/public/public/emojione/128/2195.png b/twake/frontend/public/public/emojione/128/2195.png new file mode 100644 index 00000000..c90dadd5 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2195.png differ diff --git a/twake/frontend/public/public/emojione/128/2196.png b/twake/frontend/public/public/emojione/128/2196.png new file mode 100644 index 00000000..22ff364a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2196.png differ diff --git a/twake/frontend/public/public/emojione/128/2197.png b/twake/frontend/public/public/emojione/128/2197.png new file mode 100644 index 00000000..9f099207 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2197.png differ diff --git a/twake/frontend/public/public/emojione/128/2198.png b/twake/frontend/public/public/emojione/128/2198.png new file mode 100644 index 00000000..9c5052bd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2198.png differ diff --git a/twake/frontend/public/public/emojione/128/2199.png b/twake/frontend/public/public/emojione/128/2199.png new file mode 100644 index 00000000..467d340a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2199.png differ diff --git a/twake/frontend/public/public/emojione/128/21a9.png b/twake/frontend/public/public/emojione/128/21a9.png new file mode 100644 index 00000000..41704324 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/21a9.png differ diff --git a/twake/frontend/public/public/emojione/128/21aa.png b/twake/frontend/public/public/emojione/128/21aa.png new file mode 100644 index 00000000..dca96e66 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/21aa.png differ diff --git a/twake/frontend/public/public/emojione/128/231a.png b/twake/frontend/public/public/emojione/128/231a.png new file mode 100644 index 00000000..3b4b0992 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/231a.png differ diff --git a/twake/frontend/public/public/emojione/128/231b.png b/twake/frontend/public/public/emojione/128/231b.png new file mode 100644 index 00000000..82b310d3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/231b.png differ diff --git a/twake/frontend/public/public/emojione/128/2328.png b/twake/frontend/public/public/emojione/128/2328.png new file mode 100644 index 00000000..36a58f84 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2328.png differ diff --git a/twake/frontend/public/public/emojione/128/23cf.png b/twake/frontend/public/public/emojione/128/23cf.png new file mode 100644 index 00000000..1d115e5d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/23cf.png differ diff --git a/twake/frontend/public/public/emojione/128/23e9.png b/twake/frontend/public/public/emojione/128/23e9.png new file mode 100644 index 00000000..e1c23d72 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/23e9.png differ diff --git a/twake/frontend/public/public/emojione/128/23ea.png b/twake/frontend/public/public/emojione/128/23ea.png new file mode 100644 index 00000000..adf2c0b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/23ea.png differ diff --git a/twake/frontend/public/public/emojione/128/23eb.png b/twake/frontend/public/public/emojione/128/23eb.png new file mode 100644 index 00000000..cefe3488 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/23eb.png differ diff --git a/twake/frontend/public/public/emojione/128/23ec.png b/twake/frontend/public/public/emojione/128/23ec.png new file mode 100644 index 00000000..92491c53 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/23ec.png differ diff --git a/twake/frontend/public/public/emojione/128/23ed.png b/twake/frontend/public/public/emojione/128/23ed.png new file mode 100644 index 00000000..9c3bf0e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/23ed.png differ diff --git a/twake/frontend/public/public/emojione/128/23ee.png b/twake/frontend/public/public/emojione/128/23ee.png new file mode 100644 index 00000000..2ed3508c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/23ee.png differ diff --git a/twake/frontend/public/public/emojione/128/23ef.png b/twake/frontend/public/public/emojione/128/23ef.png new file mode 100644 index 00000000..bb34ba79 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/23ef.png differ diff --git a/twake/frontend/public/public/emojione/128/23f0.png b/twake/frontend/public/public/emojione/128/23f0.png new file mode 100644 index 00000000..907aa1ce Binary files /dev/null and b/twake/frontend/public/public/emojione/128/23f0.png differ diff --git a/twake/frontend/public/public/emojione/128/23f1.png b/twake/frontend/public/public/emojione/128/23f1.png new file mode 100644 index 00000000..1b76082b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/23f1.png differ diff --git a/twake/frontend/public/public/emojione/128/23f2.png b/twake/frontend/public/public/emojione/128/23f2.png new file mode 100644 index 00000000..9c474d07 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/23f2.png differ diff --git a/twake/frontend/public/public/emojione/128/23f3.png b/twake/frontend/public/public/emojione/128/23f3.png new file mode 100644 index 00000000..b3de8097 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/23f3.png differ diff --git a/twake/frontend/public/public/emojione/128/23f8.png b/twake/frontend/public/public/emojione/128/23f8.png new file mode 100644 index 00000000..fd66a988 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/23f8.png differ diff --git a/twake/frontend/public/public/emojione/128/23f9.png b/twake/frontend/public/public/emojione/128/23f9.png new file mode 100644 index 00000000..0895bf5b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/23f9.png differ diff --git a/twake/frontend/public/public/emojione/128/23fa.png b/twake/frontend/public/public/emojione/128/23fa.png new file mode 100644 index 00000000..a7e96e13 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/23fa.png differ diff --git a/twake/frontend/public/public/emojione/128/24c2.png b/twake/frontend/public/public/emojione/128/24c2.png new file mode 100644 index 00000000..aa9a0a44 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/24c2.png differ diff --git a/twake/frontend/public/public/emojione/128/25aa.png b/twake/frontend/public/public/emojione/128/25aa.png new file mode 100644 index 00000000..e943cb59 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/25aa.png differ diff --git a/twake/frontend/public/public/emojione/128/25ab.png b/twake/frontend/public/public/emojione/128/25ab.png new file mode 100644 index 00000000..a6b062fd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/25ab.png differ diff --git a/twake/frontend/public/public/emojione/128/25b6.png b/twake/frontend/public/public/emojione/128/25b6.png new file mode 100644 index 00000000..544cfc1c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/25b6.png differ diff --git a/twake/frontend/public/public/emojione/128/25c0.png b/twake/frontend/public/public/emojione/128/25c0.png new file mode 100644 index 00000000..edfb518b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/25c0.png differ diff --git a/twake/frontend/public/public/emojione/128/25fb.png b/twake/frontend/public/public/emojione/128/25fb.png new file mode 100644 index 00000000..6df0d13c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/25fb.png differ diff --git a/twake/frontend/public/public/emojione/128/25fc.png b/twake/frontend/public/public/emojione/128/25fc.png new file mode 100644 index 00000000..e7f35ace Binary files /dev/null and b/twake/frontend/public/public/emojione/128/25fc.png differ diff --git a/twake/frontend/public/public/emojione/128/25fd.png b/twake/frontend/public/public/emojione/128/25fd.png new file mode 100644 index 00000000..573f5af6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/25fd.png differ diff --git a/twake/frontend/public/public/emojione/128/25fe.png b/twake/frontend/public/public/emojione/128/25fe.png new file mode 100644 index 00000000..139f51cd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/25fe.png differ diff --git a/twake/frontend/public/public/emojione/128/2600.png b/twake/frontend/public/public/emojione/128/2600.png new file mode 100644 index 00000000..56e890ad Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2600.png differ diff --git a/twake/frontend/public/public/emojione/128/2601.png b/twake/frontend/public/public/emojione/128/2601.png new file mode 100644 index 00000000..9aeaf9f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2601.png differ diff --git a/twake/frontend/public/public/emojione/128/2602.png b/twake/frontend/public/public/emojione/128/2602.png new file mode 100644 index 00000000..babc6185 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2602.png differ diff --git a/twake/frontend/public/public/emojione/128/2603.png b/twake/frontend/public/public/emojione/128/2603.png new file mode 100644 index 00000000..dccc3e76 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2603.png differ diff --git a/twake/frontend/public/public/emojione/128/2604.png b/twake/frontend/public/public/emojione/128/2604.png new file mode 100644 index 00000000..1b38a2cb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2604.png differ diff --git a/twake/frontend/public/public/emojione/128/260e.png b/twake/frontend/public/public/emojione/128/260e.png new file mode 100644 index 00000000..1b81b6ce Binary files /dev/null and b/twake/frontend/public/public/emojione/128/260e.png differ diff --git a/twake/frontend/public/public/emojione/128/2611.png b/twake/frontend/public/public/emojione/128/2611.png new file mode 100644 index 00000000..f66d0f2c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2611.png differ diff --git a/twake/frontend/public/public/emojione/128/2614.png b/twake/frontend/public/public/emojione/128/2614.png new file mode 100644 index 00000000..86687d2a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2614.png differ diff --git a/twake/frontend/public/public/emojione/128/2615.png b/twake/frontend/public/public/emojione/128/2615.png new file mode 100644 index 00000000..7e4e07fc Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2615.png differ diff --git a/twake/frontend/public/public/emojione/128/2618.png b/twake/frontend/public/public/emojione/128/2618.png new file mode 100644 index 00000000..30692edf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2618.png differ diff --git a/twake/frontend/public/public/emojione/128/261d-1f3fb.png b/twake/frontend/public/public/emojione/128/261d-1f3fb.png new file mode 100644 index 00000000..6b11fb1c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/261d-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/261d-1f3fc.png b/twake/frontend/public/public/emojione/128/261d-1f3fc.png new file mode 100644 index 00000000..053ba698 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/261d-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/261d-1f3fd.png b/twake/frontend/public/public/emojione/128/261d-1f3fd.png new file mode 100644 index 00000000..c8e3334a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/261d-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/261d-1f3fe.png b/twake/frontend/public/public/emojione/128/261d-1f3fe.png new file mode 100644 index 00000000..89d06c85 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/261d-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/261d-1f3ff.png b/twake/frontend/public/public/emojione/128/261d-1f3ff.png new file mode 100644 index 00000000..9b8f3d30 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/261d-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/261d.png b/twake/frontend/public/public/emojione/128/261d.png new file mode 100644 index 00000000..35b48a20 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/261d.png differ diff --git a/twake/frontend/public/public/emojione/128/2620.png b/twake/frontend/public/public/emojione/128/2620.png new file mode 100644 index 00000000..f7fc6a4f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2620.png differ diff --git a/twake/frontend/public/public/emojione/128/2622.png b/twake/frontend/public/public/emojione/128/2622.png new file mode 100644 index 00000000..57ff8de7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2622.png differ diff --git a/twake/frontend/public/public/emojione/128/2623.png b/twake/frontend/public/public/emojione/128/2623.png new file mode 100644 index 00000000..f4f86f71 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2623.png differ diff --git a/twake/frontend/public/public/emojione/128/2626.png b/twake/frontend/public/public/emojione/128/2626.png new file mode 100644 index 00000000..82d15a8f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2626.png differ diff --git a/twake/frontend/public/public/emojione/128/262a.png b/twake/frontend/public/public/emojione/128/262a.png new file mode 100644 index 00000000..d72cdf81 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/262a.png differ diff --git a/twake/frontend/public/public/emojione/128/262e.png b/twake/frontend/public/public/emojione/128/262e.png new file mode 100644 index 00000000..fb58692a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/262e.png differ diff --git a/twake/frontend/public/public/emojione/128/262f.png b/twake/frontend/public/public/emojione/128/262f.png new file mode 100644 index 00000000..ac0f349a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/262f.png differ diff --git a/twake/frontend/public/public/emojione/128/2638.png b/twake/frontend/public/public/emojione/128/2638.png new file mode 100644 index 00000000..8121b80b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2638.png differ diff --git a/twake/frontend/public/public/emojione/128/2639.png b/twake/frontend/public/public/emojione/128/2639.png new file mode 100644 index 00000000..a3735fcf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2639.png differ diff --git a/twake/frontend/public/public/emojione/128/263a.png b/twake/frontend/public/public/emojione/128/263a.png new file mode 100644 index 00000000..2178b95b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/263a.png differ diff --git a/twake/frontend/public/public/emojione/128/2640.png b/twake/frontend/public/public/emojione/128/2640.png new file mode 100644 index 00000000..a842b72a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2640.png differ diff --git a/twake/frontend/public/public/emojione/128/2642.png b/twake/frontend/public/public/emojione/128/2642.png new file mode 100644 index 00000000..b1e2f0c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2642.png differ diff --git a/twake/frontend/public/public/emojione/128/2648.png b/twake/frontend/public/public/emojione/128/2648.png new file mode 100644 index 00000000..acfb5122 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2648.png differ diff --git a/twake/frontend/public/public/emojione/128/2649.png b/twake/frontend/public/public/emojione/128/2649.png new file mode 100644 index 00000000..6ba49427 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2649.png differ diff --git a/twake/frontend/public/public/emojione/128/264a.png b/twake/frontend/public/public/emojione/128/264a.png new file mode 100644 index 00000000..41559b79 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/264a.png differ diff --git a/twake/frontend/public/public/emojione/128/264b.png b/twake/frontend/public/public/emojione/128/264b.png new file mode 100644 index 00000000..95e97a86 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/264b.png differ diff --git a/twake/frontend/public/public/emojione/128/264c.png b/twake/frontend/public/public/emojione/128/264c.png new file mode 100644 index 00000000..4f107803 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/264c.png differ diff --git a/twake/frontend/public/public/emojione/128/264d.png b/twake/frontend/public/public/emojione/128/264d.png new file mode 100644 index 00000000..fad8b9f3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/264d.png differ diff --git a/twake/frontend/public/public/emojione/128/264e.png b/twake/frontend/public/public/emojione/128/264e.png new file mode 100644 index 00000000..8c3badfd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/264e.png differ diff --git a/twake/frontend/public/public/emojione/128/264f.png b/twake/frontend/public/public/emojione/128/264f.png new file mode 100644 index 00000000..2c61cbda Binary files /dev/null and b/twake/frontend/public/public/emojione/128/264f.png differ diff --git a/twake/frontend/public/public/emojione/128/2650.png b/twake/frontend/public/public/emojione/128/2650.png new file mode 100644 index 00000000..cf96943f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2650.png differ diff --git a/twake/frontend/public/public/emojione/128/2651.png b/twake/frontend/public/public/emojione/128/2651.png new file mode 100644 index 00000000..6f19c8f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2651.png differ diff --git a/twake/frontend/public/public/emojione/128/2652.png b/twake/frontend/public/public/emojione/128/2652.png new file mode 100644 index 00000000..81733dea Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2652.png differ diff --git a/twake/frontend/public/public/emojione/128/2653.png b/twake/frontend/public/public/emojione/128/2653.png new file mode 100644 index 00000000..25bd7b22 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2653.png differ diff --git a/twake/frontend/public/public/emojione/128/265f.png b/twake/frontend/public/public/emojione/128/265f.png new file mode 100644 index 00000000..be7e949f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/265f.png differ diff --git a/twake/frontend/public/public/emojione/128/2660.png b/twake/frontend/public/public/emojione/128/2660.png new file mode 100644 index 00000000..f682d3d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2660.png differ diff --git a/twake/frontend/public/public/emojione/128/2663.png b/twake/frontend/public/public/emojione/128/2663.png new file mode 100644 index 00000000..da286c10 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2663.png differ diff --git a/twake/frontend/public/public/emojione/128/2665.png b/twake/frontend/public/public/emojione/128/2665.png new file mode 100644 index 00000000..37c084e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2665.png differ diff --git a/twake/frontend/public/public/emojione/128/2666.png b/twake/frontend/public/public/emojione/128/2666.png new file mode 100644 index 00000000..3c50a45e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2666.png differ diff --git a/twake/frontend/public/public/emojione/128/2668.png b/twake/frontend/public/public/emojione/128/2668.png new file mode 100644 index 00000000..306606ea Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2668.png differ diff --git a/twake/frontend/public/public/emojione/128/267b.png b/twake/frontend/public/public/emojione/128/267b.png new file mode 100644 index 00000000..8d0096d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/267b.png differ diff --git a/twake/frontend/public/public/emojione/128/267e.png b/twake/frontend/public/public/emojione/128/267e.png new file mode 100644 index 00000000..05414469 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/267e.png differ diff --git a/twake/frontend/public/public/emojione/128/267f.png b/twake/frontend/public/public/emojione/128/267f.png new file mode 100644 index 00000000..c8b0a17a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/267f.png differ diff --git a/twake/frontend/public/public/emojione/128/2692.png b/twake/frontend/public/public/emojione/128/2692.png new file mode 100644 index 00000000..b6e106bf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2692.png differ diff --git a/twake/frontend/public/public/emojione/128/2693.png b/twake/frontend/public/public/emojione/128/2693.png new file mode 100644 index 00000000..612e044e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2693.png differ diff --git a/twake/frontend/public/public/emojione/128/2694.png b/twake/frontend/public/public/emojione/128/2694.png new file mode 100644 index 00000000..21947918 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2694.png differ diff --git a/twake/frontend/public/public/emojione/128/2695.png b/twake/frontend/public/public/emojione/128/2695.png new file mode 100644 index 00000000..94783ee0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2695.png differ diff --git a/twake/frontend/public/public/emojione/128/2696.png b/twake/frontend/public/public/emojione/128/2696.png new file mode 100644 index 00000000..11e87f2d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2696.png differ diff --git a/twake/frontend/public/public/emojione/128/2697.png b/twake/frontend/public/public/emojione/128/2697.png new file mode 100644 index 00000000..991fa322 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2697.png differ diff --git a/twake/frontend/public/public/emojione/128/2699.png b/twake/frontend/public/public/emojione/128/2699.png new file mode 100644 index 00000000..67c6fd36 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2699.png differ diff --git a/twake/frontend/public/public/emojione/128/269b.png b/twake/frontend/public/public/emojione/128/269b.png new file mode 100644 index 00000000..9994d47d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/269b.png differ diff --git a/twake/frontend/public/public/emojione/128/269c.png b/twake/frontend/public/public/emojione/128/269c.png new file mode 100644 index 00000000..00229c02 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/269c.png differ diff --git a/twake/frontend/public/public/emojione/128/26a0.png b/twake/frontend/public/public/emojione/128/26a0.png new file mode 100644 index 00000000..1665cc58 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26a0.png differ diff --git a/twake/frontend/public/public/emojione/128/26a1.png b/twake/frontend/public/public/emojione/128/26a1.png new file mode 100644 index 00000000..c531aecb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26a1.png differ diff --git a/twake/frontend/public/public/emojione/128/26aa.png b/twake/frontend/public/public/emojione/128/26aa.png new file mode 100644 index 00000000..e41b7f21 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26aa.png differ diff --git a/twake/frontend/public/public/emojione/128/26ab.png b/twake/frontend/public/public/emojione/128/26ab.png new file mode 100644 index 00000000..bf45b9df Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26ab.png differ diff --git a/twake/frontend/public/public/emojione/128/26b0.png b/twake/frontend/public/public/emojione/128/26b0.png new file mode 100644 index 00000000..81b948c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26b0.png differ diff --git a/twake/frontend/public/public/emojione/128/26b1.png b/twake/frontend/public/public/emojione/128/26b1.png new file mode 100644 index 00000000..8083908d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26b1.png differ diff --git a/twake/frontend/public/public/emojione/128/26bd.png b/twake/frontend/public/public/emojione/128/26bd.png new file mode 100644 index 00000000..448fba5d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26bd.png differ diff --git a/twake/frontend/public/public/emojione/128/26be.png b/twake/frontend/public/public/emojione/128/26be.png new file mode 100644 index 00000000..d9c1a86b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26be.png differ diff --git a/twake/frontend/public/public/emojione/128/26c4.png b/twake/frontend/public/public/emojione/128/26c4.png new file mode 100644 index 00000000..f8b51b39 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26c4.png differ diff --git a/twake/frontend/public/public/emojione/128/26c5.png b/twake/frontend/public/public/emojione/128/26c5.png new file mode 100644 index 00000000..ef124c92 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26c5.png differ diff --git a/twake/frontend/public/public/emojione/128/26c8.png b/twake/frontend/public/public/emojione/128/26c8.png new file mode 100644 index 00000000..0dbd527b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26c8.png differ diff --git a/twake/frontend/public/public/emojione/128/26ce.png b/twake/frontend/public/public/emojione/128/26ce.png new file mode 100644 index 00000000..fe8cec94 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26ce.png differ diff --git a/twake/frontend/public/public/emojione/128/26cf.png b/twake/frontend/public/public/emojione/128/26cf.png new file mode 100644 index 00000000..d817db45 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26cf.png differ diff --git a/twake/frontend/public/public/emojione/128/26d1.png b/twake/frontend/public/public/emojione/128/26d1.png new file mode 100644 index 00000000..04969d67 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26d1.png differ diff --git a/twake/frontend/public/public/emojione/128/26d3.png b/twake/frontend/public/public/emojione/128/26d3.png new file mode 100644 index 00000000..b73830e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26d3.png differ diff --git a/twake/frontend/public/public/emojione/128/26d4.png b/twake/frontend/public/public/emojione/128/26d4.png new file mode 100644 index 00000000..1e62e053 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26d4.png differ diff --git a/twake/frontend/public/public/emojione/128/26e9.png b/twake/frontend/public/public/emojione/128/26e9.png new file mode 100644 index 00000000..8d91c169 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26e9.png differ diff --git a/twake/frontend/public/public/emojione/128/26ea.png b/twake/frontend/public/public/emojione/128/26ea.png new file mode 100644 index 00000000..0e21b0ba Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26ea.png differ diff --git a/twake/frontend/public/public/emojione/128/26f0.png b/twake/frontend/public/public/emojione/128/26f0.png new file mode 100644 index 00000000..b71ef608 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f0.png differ diff --git a/twake/frontend/public/public/emojione/128/26f1.png b/twake/frontend/public/public/emojione/128/26f1.png new file mode 100644 index 00000000..0287df85 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f1.png differ diff --git a/twake/frontend/public/public/emojione/128/26f2.png b/twake/frontend/public/public/emojione/128/26f2.png new file mode 100644 index 00000000..70ee647c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f2.png differ diff --git a/twake/frontend/public/public/emojione/128/26f3.png b/twake/frontend/public/public/emojione/128/26f3.png new file mode 100644 index 00000000..d808baa0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f3.png differ diff --git a/twake/frontend/public/public/emojione/128/26f4.png b/twake/frontend/public/public/emojione/128/26f4.png new file mode 100644 index 00000000..419f7002 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f4.png differ diff --git a/twake/frontend/public/public/emojione/128/26f5.png b/twake/frontend/public/public/emojione/128/26f5.png new file mode 100644 index 00000000..3c9f6010 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f5.png differ diff --git a/twake/frontend/public/public/emojione/128/26f7.png b/twake/frontend/public/public/emojione/128/26f7.png new file mode 100644 index 00000000..c141a13f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f7.png differ diff --git a/twake/frontend/public/public/emojione/128/26f8.png b/twake/frontend/public/public/emojione/128/26f8.png new file mode 100644 index 00000000..1282ac4c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f8.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9-1f3fb-2640.png b/twake/frontend/public/public/emojione/128/26f9-1f3fb-2640.png new file mode 100644 index 00000000..0b17ece2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9-1f3fb-2642.png b/twake/frontend/public/public/emojione/128/26f9-1f3fb-2642.png new file mode 100644 index 00000000..16def8f9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9-1f3fb.png b/twake/frontend/public/public/emojione/128/26f9-1f3fb.png new file mode 100644 index 00000000..16def8f9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9-1f3fc-2640.png b/twake/frontend/public/public/emojione/128/26f9-1f3fc-2640.png new file mode 100644 index 00000000..ac31e826 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9-1f3fc-2642.png b/twake/frontend/public/public/emojione/128/26f9-1f3fc-2642.png new file mode 100644 index 00000000..cb752244 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9-1f3fc.png b/twake/frontend/public/public/emojione/128/26f9-1f3fc.png new file mode 100644 index 00000000..cb752244 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9-1f3fd-2640.png b/twake/frontend/public/public/emojione/128/26f9-1f3fd-2640.png new file mode 100644 index 00000000..c3cc5eb9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9-1f3fd-2642.png b/twake/frontend/public/public/emojione/128/26f9-1f3fd-2642.png new file mode 100644 index 00000000..40676ac9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9-1f3fd.png b/twake/frontend/public/public/emojione/128/26f9-1f3fd.png new file mode 100644 index 00000000..40676ac9 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9-1f3fe-2640.png b/twake/frontend/public/public/emojione/128/26f9-1f3fe-2640.png new file mode 100644 index 00000000..42d3ac37 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9-1f3fe-2642.png b/twake/frontend/public/public/emojione/128/26f9-1f3fe-2642.png new file mode 100644 index 00000000..ef119f27 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9-1f3fe.png b/twake/frontend/public/public/emojione/128/26f9-1f3fe.png new file mode 100644 index 00000000..ef119f27 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9-1f3ff-2640.png b/twake/frontend/public/public/emojione/128/26f9-1f3ff-2640.png new file mode 100644 index 00000000..bb193706 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9-1f3ff-2642.png b/twake/frontend/public/public/emojione/128/26f9-1f3ff-2642.png new file mode 100644 index 00000000..17e49b42 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9-1f3ff.png b/twake/frontend/public/public/emojione/128/26f9-1f3ff.png new file mode 100644 index 00000000..17e49b42 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9-2640.png b/twake/frontend/public/public/emojione/128/26f9-2640.png new file mode 100644 index 00000000..1ad83967 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9-2640.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9-2642.png b/twake/frontend/public/public/emojione/128/26f9-2642.png new file mode 100644 index 00000000..7cb4751a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9-2642.png differ diff --git a/twake/frontend/public/public/emojione/128/26f9.png b/twake/frontend/public/public/emojione/128/26f9.png new file mode 100644 index 00000000..7cb4751a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26f9.png differ diff --git a/twake/frontend/public/public/emojione/128/26fa.png b/twake/frontend/public/public/emojione/128/26fa.png new file mode 100644 index 00000000..e62fae22 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26fa.png differ diff --git a/twake/frontend/public/public/emojione/128/26fd.png b/twake/frontend/public/public/emojione/128/26fd.png new file mode 100644 index 00000000..a6a75317 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/26fd.png differ diff --git a/twake/frontend/public/public/emojione/128/2702.png b/twake/frontend/public/public/emojione/128/2702.png new file mode 100644 index 00000000..fe1658bf Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2702.png differ diff --git a/twake/frontend/public/public/emojione/128/2705.png b/twake/frontend/public/public/emojione/128/2705.png new file mode 100644 index 00000000..c75daa64 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2705.png differ diff --git a/twake/frontend/public/public/emojione/128/2708.png b/twake/frontend/public/public/emojione/128/2708.png new file mode 100644 index 00000000..af4c7eeb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2708.png differ diff --git a/twake/frontend/public/public/emojione/128/2709.png b/twake/frontend/public/public/emojione/128/2709.png new file mode 100644 index 00000000..3eb1321a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2709.png differ diff --git a/twake/frontend/public/public/emojione/128/270a-1f3fb.png b/twake/frontend/public/public/emojione/128/270a-1f3fb.png new file mode 100644 index 00000000..1ffeb5ca Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270a-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/270a-1f3fc.png b/twake/frontend/public/public/emojione/128/270a-1f3fc.png new file mode 100644 index 00000000..52bd1608 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270a-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/270a-1f3fd.png b/twake/frontend/public/public/emojione/128/270a-1f3fd.png new file mode 100644 index 00000000..38bf7844 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270a-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/270a-1f3fe.png b/twake/frontend/public/public/emojione/128/270a-1f3fe.png new file mode 100644 index 00000000..e801d002 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270a-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/270a-1f3ff.png b/twake/frontend/public/public/emojione/128/270a-1f3ff.png new file mode 100644 index 00000000..29183b5b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270a-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/270a.png b/twake/frontend/public/public/emojione/128/270a.png new file mode 100644 index 00000000..fbbfab19 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270a.png differ diff --git a/twake/frontend/public/public/emojione/128/270b-1f3fb.png b/twake/frontend/public/public/emojione/128/270b-1f3fb.png new file mode 100644 index 00000000..aaedc2d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270b-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/270b-1f3fc.png b/twake/frontend/public/public/emojione/128/270b-1f3fc.png new file mode 100644 index 00000000..65ff6120 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270b-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/270b-1f3fd.png b/twake/frontend/public/public/emojione/128/270b-1f3fd.png new file mode 100644 index 00000000..fcc42408 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270b-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/270b-1f3fe.png b/twake/frontend/public/public/emojione/128/270b-1f3fe.png new file mode 100644 index 00000000..a3b95477 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270b-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/270b-1f3ff.png b/twake/frontend/public/public/emojione/128/270b-1f3ff.png new file mode 100644 index 00000000..24884d39 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270b-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/270b.png b/twake/frontend/public/public/emojione/128/270b.png new file mode 100644 index 00000000..a70a9c51 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270b.png differ diff --git a/twake/frontend/public/public/emojione/128/270c-1f3fb.png b/twake/frontend/public/public/emojione/128/270c-1f3fb.png new file mode 100644 index 00000000..829c8c8a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270c-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/270c-1f3fc.png b/twake/frontend/public/public/emojione/128/270c-1f3fc.png new file mode 100644 index 00000000..e0f7ce8c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270c-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/270c-1f3fd.png b/twake/frontend/public/public/emojione/128/270c-1f3fd.png new file mode 100644 index 00000000..3cf4b842 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270c-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/270c-1f3fe.png b/twake/frontend/public/public/emojione/128/270c-1f3fe.png new file mode 100644 index 00000000..5c7b3267 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270c-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/270c-1f3ff.png b/twake/frontend/public/public/emojione/128/270c-1f3ff.png new file mode 100644 index 00000000..3e080b35 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270c-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/270c.png b/twake/frontend/public/public/emojione/128/270c.png new file mode 100644 index 00000000..0bbd7f66 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270c.png differ diff --git a/twake/frontend/public/public/emojione/128/270d-1f3fb.png b/twake/frontend/public/public/emojione/128/270d-1f3fb.png new file mode 100644 index 00000000..0bafc702 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270d-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/128/270d-1f3fc.png b/twake/frontend/public/public/emojione/128/270d-1f3fc.png new file mode 100644 index 00000000..b5ce2ee8 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270d-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/128/270d-1f3fd.png b/twake/frontend/public/public/emojione/128/270d-1f3fd.png new file mode 100644 index 00000000..4d46b043 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270d-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/128/270d-1f3fe.png b/twake/frontend/public/public/emojione/128/270d-1f3fe.png new file mode 100644 index 00000000..9541cb6c Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270d-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/128/270d-1f3ff.png b/twake/frontend/public/public/emojione/128/270d-1f3ff.png new file mode 100644 index 00000000..e52701df Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270d-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/128/270d.png b/twake/frontend/public/public/emojione/128/270d.png new file mode 100644 index 00000000..60b3e756 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270d.png differ diff --git a/twake/frontend/public/public/emojione/128/270f.png b/twake/frontend/public/public/emojione/128/270f.png new file mode 100644 index 00000000..847cd45f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/270f.png differ diff --git a/twake/frontend/public/public/emojione/128/2712.png b/twake/frontend/public/public/emojione/128/2712.png new file mode 100644 index 00000000..a4c9393a Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2712.png differ diff --git a/twake/frontend/public/public/emojione/128/2714.png b/twake/frontend/public/public/emojione/128/2714.png new file mode 100644 index 00000000..a35085e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2714.png differ diff --git a/twake/frontend/public/public/emojione/128/2716.png b/twake/frontend/public/public/emojione/128/2716.png new file mode 100644 index 00000000..1a8c1952 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2716.png differ diff --git a/twake/frontend/public/public/emojione/128/271d.png b/twake/frontend/public/public/emojione/128/271d.png new file mode 100644 index 00000000..4c874569 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/271d.png differ diff --git a/twake/frontend/public/public/emojione/128/2721.png b/twake/frontend/public/public/emojione/128/2721.png new file mode 100644 index 00000000..aa089d6f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2721.png differ diff --git a/twake/frontend/public/public/emojione/128/2728.png b/twake/frontend/public/public/emojione/128/2728.png new file mode 100644 index 00000000..1664d309 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2728.png differ diff --git a/twake/frontend/public/public/emojione/128/2733.png b/twake/frontend/public/public/emojione/128/2733.png new file mode 100644 index 00000000..277c2830 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2733.png differ diff --git a/twake/frontend/public/public/emojione/128/2734.png b/twake/frontend/public/public/emojione/128/2734.png new file mode 100644 index 00000000..b9fe8756 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2734.png differ diff --git a/twake/frontend/public/public/emojione/128/2744.png b/twake/frontend/public/public/emojione/128/2744.png new file mode 100644 index 00000000..068d071b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2744.png differ diff --git a/twake/frontend/public/public/emojione/128/2747.png b/twake/frontend/public/public/emojione/128/2747.png new file mode 100644 index 00000000..1800b0da Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2747.png differ diff --git a/twake/frontend/public/public/emojione/128/274c.png b/twake/frontend/public/public/emojione/128/274c.png new file mode 100644 index 00000000..2fec1283 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/274c.png differ diff --git a/twake/frontend/public/public/emojione/128/274e.png b/twake/frontend/public/public/emojione/128/274e.png new file mode 100644 index 00000000..b1ff250e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/274e.png differ diff --git a/twake/frontend/public/public/emojione/128/2753.png b/twake/frontend/public/public/emojione/128/2753.png new file mode 100644 index 00000000..5afcd0ba Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2753.png differ diff --git a/twake/frontend/public/public/emojione/128/2754.png b/twake/frontend/public/public/emojione/128/2754.png new file mode 100644 index 00000000..7dbf8a3d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2754.png differ diff --git a/twake/frontend/public/public/emojione/128/2755.png b/twake/frontend/public/public/emojione/128/2755.png new file mode 100644 index 00000000..942154ab Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2755.png differ diff --git a/twake/frontend/public/public/emojione/128/2757.png b/twake/frontend/public/public/emojione/128/2757.png new file mode 100644 index 00000000..5bfdab2d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2757.png differ diff --git a/twake/frontend/public/public/emojione/128/2763.png b/twake/frontend/public/public/emojione/128/2763.png new file mode 100644 index 00000000..40cda4ff Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2763.png differ diff --git a/twake/frontend/public/public/emojione/128/2764.png b/twake/frontend/public/public/emojione/128/2764.png new file mode 100644 index 00000000..38ddc579 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2764.png differ diff --git a/twake/frontend/public/public/emojione/128/2795.png b/twake/frontend/public/public/emojione/128/2795.png new file mode 100644 index 00000000..5c68949e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2795.png differ diff --git a/twake/frontend/public/public/emojione/128/2796.png b/twake/frontend/public/public/emojione/128/2796.png new file mode 100644 index 00000000..f29c2feb Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2796.png differ diff --git a/twake/frontend/public/public/emojione/128/2797.png b/twake/frontend/public/public/emojione/128/2797.png new file mode 100644 index 00000000..76702c0d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2797.png differ diff --git a/twake/frontend/public/public/emojione/128/27a1.png b/twake/frontend/public/public/emojione/128/27a1.png new file mode 100644 index 00000000..73ab7b68 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/27a1.png differ diff --git a/twake/frontend/public/public/emojione/128/27b0.png b/twake/frontend/public/public/emojione/128/27b0.png new file mode 100644 index 00000000..9e8ec849 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/27b0.png differ diff --git a/twake/frontend/public/public/emojione/128/27bf.png b/twake/frontend/public/public/emojione/128/27bf.png new file mode 100644 index 00000000..babf902e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/27bf.png differ diff --git a/twake/frontend/public/public/emojione/128/2934.png b/twake/frontend/public/public/emojione/128/2934.png new file mode 100644 index 00000000..4f502dcd Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2934.png differ diff --git a/twake/frontend/public/public/emojione/128/2935.png b/twake/frontend/public/public/emojione/128/2935.png new file mode 100644 index 00000000..f7aa71e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2935.png differ diff --git a/twake/frontend/public/public/emojione/128/2b05.png b/twake/frontend/public/public/emojione/128/2b05.png new file mode 100644 index 00000000..2dee2f30 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2b05.png differ diff --git a/twake/frontend/public/public/emojione/128/2b06.png b/twake/frontend/public/public/emojione/128/2b06.png new file mode 100644 index 00000000..a29fc101 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2b06.png differ diff --git a/twake/frontend/public/public/emojione/128/2b07.png b/twake/frontend/public/public/emojione/128/2b07.png new file mode 100644 index 00000000..f9f8aa9f Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2b07.png differ diff --git a/twake/frontend/public/public/emojione/128/2b1b.png b/twake/frontend/public/public/emojione/128/2b1b.png new file mode 100644 index 00000000..70ad9c9d Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2b1b.png differ diff --git a/twake/frontend/public/public/emojione/128/2b1c.png b/twake/frontend/public/public/emojione/128/2b1c.png new file mode 100644 index 00000000..807b2fea Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2b1c.png differ diff --git a/twake/frontend/public/public/emojione/128/2b50.png b/twake/frontend/public/public/emojione/128/2b50.png new file mode 100644 index 00000000..fc6c83fa Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2b50.png differ diff --git a/twake/frontend/public/public/emojione/128/2b55.png b/twake/frontend/public/public/emojione/128/2b55.png new file mode 100644 index 00000000..89d23b8e Binary files /dev/null and b/twake/frontend/public/public/emojione/128/2b55.png differ diff --git a/twake/frontend/public/public/emojione/128/3030.png b/twake/frontend/public/public/emojione/128/3030.png new file mode 100644 index 00000000..31fbfe9b Binary files /dev/null and b/twake/frontend/public/public/emojione/128/3030.png differ diff --git a/twake/frontend/public/public/emojione/128/303d.png b/twake/frontend/public/public/emojione/128/303d.png new file mode 100644 index 00000000..cfb43180 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/303d.png differ diff --git a/twake/frontend/public/public/emojione/128/3297.png b/twake/frontend/public/public/emojione/128/3297.png new file mode 100644 index 00000000..6b4b7a29 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/3297.png differ diff --git a/twake/frontend/public/public/emojione/128/3299.png b/twake/frontend/public/public/emojione/128/3299.png new file mode 100644 index 00000000..f02899d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/3299.png differ diff --git a/twake/frontend/public/public/emojione/128/_alt/1f52b.png b/twake/frontend/public/public/emojione/128/_alt/1f52b.png new file mode 100644 index 00000000..ee013f91 Binary files /dev/null and b/twake/frontend/public/public/emojione/128/_alt/1f52b.png differ diff --git a/twake/frontend/public/public/emojione/32/0023-20e3.png b/twake/frontend/public/public/emojione/32/0023-20e3.png new file mode 100644 index 00000000..a0b70e3e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0023-20e3.png differ diff --git a/twake/frontend/public/public/emojione/32/0023.png b/twake/frontend/public/public/emojione/32/0023.png new file mode 100644 index 00000000..aff41101 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0023.png differ diff --git a/twake/frontend/public/public/emojione/32/002a-20e3.png b/twake/frontend/public/public/emojione/32/002a-20e3.png new file mode 100644 index 00000000..5e2ac8c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/002a-20e3.png differ diff --git a/twake/frontend/public/public/emojione/32/002a.png b/twake/frontend/public/public/emojione/32/002a.png new file mode 100644 index 00000000..24ac5364 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/002a.png differ diff --git a/twake/frontend/public/public/emojione/32/0030-20e3.png b/twake/frontend/public/public/emojione/32/0030-20e3.png new file mode 100644 index 00000000..fc754309 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0030-20e3.png differ diff --git a/twake/frontend/public/public/emojione/32/0030.png b/twake/frontend/public/public/emojione/32/0030.png new file mode 100644 index 00000000..ce8aeabf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0030.png differ diff --git a/twake/frontend/public/public/emojione/32/0031-20e3.png b/twake/frontend/public/public/emojione/32/0031-20e3.png new file mode 100644 index 00000000..ae466982 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0031-20e3.png differ diff --git a/twake/frontend/public/public/emojione/32/0031.png b/twake/frontend/public/public/emojione/32/0031.png new file mode 100644 index 00000000..26935889 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0031.png differ diff --git a/twake/frontend/public/public/emojione/32/0032-20e3.png b/twake/frontend/public/public/emojione/32/0032-20e3.png new file mode 100644 index 00000000..dac1986e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0032-20e3.png differ diff --git a/twake/frontend/public/public/emojione/32/0032.png b/twake/frontend/public/public/emojione/32/0032.png new file mode 100644 index 00000000..39f59088 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0032.png differ diff --git a/twake/frontend/public/public/emojione/32/0033-20e3.png b/twake/frontend/public/public/emojione/32/0033-20e3.png new file mode 100644 index 00000000..eeb8b7b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0033-20e3.png differ diff --git a/twake/frontend/public/public/emojione/32/0033.png b/twake/frontend/public/public/emojione/32/0033.png new file mode 100644 index 00000000..97b06091 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0033.png differ diff --git a/twake/frontend/public/public/emojione/32/0034-20e3.png b/twake/frontend/public/public/emojione/32/0034-20e3.png new file mode 100644 index 00000000..7da7962a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0034-20e3.png differ diff --git a/twake/frontend/public/public/emojione/32/0034.png b/twake/frontend/public/public/emojione/32/0034.png new file mode 100644 index 00000000..b77d6824 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0034.png differ diff --git a/twake/frontend/public/public/emojione/32/0035-20e3.png b/twake/frontend/public/public/emojione/32/0035-20e3.png new file mode 100644 index 00000000..f21908e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0035-20e3.png differ diff --git a/twake/frontend/public/public/emojione/32/0035.png b/twake/frontend/public/public/emojione/32/0035.png new file mode 100644 index 00000000..6598b3b6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0035.png differ diff --git a/twake/frontend/public/public/emojione/32/0036-20e3.png b/twake/frontend/public/public/emojione/32/0036-20e3.png new file mode 100644 index 00000000..d00cd730 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0036-20e3.png differ diff --git a/twake/frontend/public/public/emojione/32/0036.png b/twake/frontend/public/public/emojione/32/0036.png new file mode 100644 index 00000000..8947956f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0036.png differ diff --git a/twake/frontend/public/public/emojione/32/0037-20e3.png b/twake/frontend/public/public/emojione/32/0037-20e3.png new file mode 100644 index 00000000..110c6205 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0037-20e3.png differ diff --git a/twake/frontend/public/public/emojione/32/0037.png b/twake/frontend/public/public/emojione/32/0037.png new file mode 100644 index 00000000..1409c140 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0037.png differ diff --git a/twake/frontend/public/public/emojione/32/0038-20e3.png b/twake/frontend/public/public/emojione/32/0038-20e3.png new file mode 100644 index 00000000..4e439b79 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0038-20e3.png differ diff --git a/twake/frontend/public/public/emojione/32/0038.png b/twake/frontend/public/public/emojione/32/0038.png new file mode 100644 index 00000000..c82f86d5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0038.png differ diff --git a/twake/frontend/public/public/emojione/32/0039-20e3.png b/twake/frontend/public/public/emojione/32/0039-20e3.png new file mode 100644 index 00000000..3e1953ae Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0039-20e3.png differ diff --git a/twake/frontend/public/public/emojione/32/0039.png b/twake/frontend/public/public/emojione/32/0039.png new file mode 100644 index 00000000..ce15ec24 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/0039.png differ diff --git a/twake/frontend/public/public/emojione/32/00a9.png b/twake/frontend/public/public/emojione/32/00a9.png new file mode 100644 index 00000000..5fddee84 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/00a9.png differ diff --git a/twake/frontend/public/public/emojione/32/00ae.png b/twake/frontend/public/public/emojione/32/00ae.png new file mode 100644 index 00000000..9502f69d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/00ae.png differ diff --git a/twake/frontend/public/public/emojione/32/1f004.png b/twake/frontend/public/public/emojione/32/1f004.png new file mode 100644 index 00000000..51b3b7e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f004.png differ diff --git a/twake/frontend/public/public/emojione/32/1f0cf.png b/twake/frontend/public/public/emojione/32/1f0cf.png new file mode 100644 index 00000000..98a59e18 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f0cf.png differ diff --git a/twake/frontend/public/public/emojione/32/1f170.png b/twake/frontend/public/public/emojione/32/1f170.png new file mode 100644 index 00000000..82de8381 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f170.png differ diff --git a/twake/frontend/public/public/emojione/32/1f171.png b/twake/frontend/public/public/emojione/32/1f171.png new file mode 100644 index 00000000..9c8d6577 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f171.png differ diff --git a/twake/frontend/public/public/emojione/32/1f17e.png b/twake/frontend/public/public/emojione/32/1f17e.png new file mode 100644 index 00000000..66c73951 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f17e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f17f.png b/twake/frontend/public/public/emojione/32/1f17f.png new file mode 100644 index 00000000..13c1795b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f17f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f18e.png b/twake/frontend/public/public/emojione/32/1f18e.png new file mode 100644 index 00000000..0ed2ecf6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f18e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f191.png b/twake/frontend/public/public/emojione/32/1f191.png new file mode 100644 index 00000000..c00a242c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f191.png differ diff --git a/twake/frontend/public/public/emojione/32/1f192.png b/twake/frontend/public/public/emojione/32/1f192.png new file mode 100644 index 00000000..bf1a40aa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f192.png differ diff --git a/twake/frontend/public/public/emojione/32/1f193.png b/twake/frontend/public/public/emojione/32/1f193.png new file mode 100644 index 00000000..a754d832 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f193.png differ diff --git a/twake/frontend/public/public/emojione/32/1f194.png b/twake/frontend/public/public/emojione/32/1f194.png new file mode 100644 index 00000000..17f22d9b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f194.png differ diff --git a/twake/frontend/public/public/emojione/32/1f195.png b/twake/frontend/public/public/emojione/32/1f195.png new file mode 100644 index 00000000..4fea4c30 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f195.png differ diff --git a/twake/frontend/public/public/emojione/32/1f196.png b/twake/frontend/public/public/emojione/32/1f196.png new file mode 100644 index 00000000..8a93e5de Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f196.png differ diff --git a/twake/frontend/public/public/emojione/32/1f197.png b/twake/frontend/public/public/emojione/32/1f197.png new file mode 100644 index 00000000..5babe374 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f197.png differ diff --git a/twake/frontend/public/public/emojione/32/1f198.png b/twake/frontend/public/public/emojione/32/1f198.png new file mode 100644 index 00000000..b5777f23 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f198.png differ diff --git a/twake/frontend/public/public/emojione/32/1f199.png b/twake/frontend/public/public/emojione/32/1f199.png new file mode 100644 index 00000000..cb42dc07 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f199.png differ diff --git a/twake/frontend/public/public/emojione/32/1f19a.png b/twake/frontend/public/public/emojione/32/1f19a.png new file mode 100644 index 00000000..763b9cb4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f19a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6-1f1e8.png b/twake/frontend/public/public/emojione/32/1f1e6-1f1e8.png new file mode 100644 index 00000000..43aef882 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6-1f1e9.png b/twake/frontend/public/public/emojione/32/1f1e6-1f1e9.png new file mode 100644 index 00000000..b7e4171f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6-1f1ea.png b/twake/frontend/public/public/emojione/32/1f1e6-1f1ea.png new file mode 100644 index 00000000..2cf4c07b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6-1f1eb.png b/twake/frontend/public/public/emojione/32/1f1e6-1f1eb.png new file mode 100644 index 00000000..440ee15f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6-1f1ec.png b/twake/frontend/public/public/emojione/32/1f1e6-1f1ec.png new file mode 100644 index 00000000..2a76bd2a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6-1f1ee.png b/twake/frontend/public/public/emojione/32/1f1e6-1f1ee.png new file mode 100644 index 00000000..42807e84 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6-1f1f1.png b/twake/frontend/public/public/emojione/32/1f1e6-1f1f1.png new file mode 100644 index 00000000..d40ddc68 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6-1f1f2.png b/twake/frontend/public/public/emojione/32/1f1e6-1f1f2.png new file mode 100644 index 00000000..bc8b2f26 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6-1f1f4.png b/twake/frontend/public/public/emojione/32/1f1e6-1f1f4.png new file mode 100644 index 00000000..e3c3c38c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6-1f1f6.png b/twake/frontend/public/public/emojione/32/1f1e6-1f1f6.png new file mode 100644 index 00000000..d1a8c85d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6-1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6-1f1f7.png b/twake/frontend/public/public/emojione/32/1f1e6-1f1f7.png new file mode 100644 index 00000000..157f835c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6-1f1f8.png b/twake/frontend/public/public/emojione/32/1f1e6-1f1f8.png new file mode 100644 index 00000000..5f5b1cf0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6-1f1f9.png b/twake/frontend/public/public/emojione/32/1f1e6-1f1f9.png new file mode 100644 index 00000000..accce249 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6-1f1fa.png b/twake/frontend/public/public/emojione/32/1f1e6-1f1fa.png new file mode 100644 index 00000000..aeda1f78 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6-1f1fc.png b/twake/frontend/public/public/emojione/32/1f1e6-1f1fc.png new file mode 100644 index 00000000..b4fdd0b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6-1f1fd.png b/twake/frontend/public/public/emojione/32/1f1e6-1f1fd.png new file mode 100644 index 00000000..f3320059 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6-1f1fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6-1f1ff.png b/twake/frontend/public/public/emojione/32/1f1e6-1f1ff.png new file mode 100644 index 00000000..61d055aa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e6.png b/twake/frontend/public/public/emojione/32/1f1e6.png new file mode 100644 index 00000000..4d796f65 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1e6.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1e6.png new file mode 100644 index 00000000..4d0ccbcb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1e7.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1e7.png new file mode 100644 index 00000000..6008865b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1e7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1e9.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1e9.png new file mode 100644 index 00000000..f8da7d32 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1ea.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1ea.png new file mode 100644 index 00000000..db44eb60 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1eb.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1eb.png new file mode 100644 index 00000000..816fb94c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1ec.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1ec.png new file mode 100644 index 00000000..9f22c74f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1ed.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1ed.png new file mode 100644 index 00000000..e2f3322d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1ee.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1ee.png new file mode 100644 index 00000000..604b5ada Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1ef.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1ef.png new file mode 100644 index 00000000..ef8cb579 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1f1.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1f1.png new file mode 100644 index 00000000..00e7eb14 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1f2.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1f2.png new file mode 100644 index 00000000..d62e9e28 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1f3.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1f3.png new file mode 100644 index 00000000..f33a05d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1f4.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1f4.png new file mode 100644 index 00000000..d7435682 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1f6.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1f6.png new file mode 100644 index 00000000..9848d37d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1f7.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1f7.png new file mode 100644 index 00000000..bcf337d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1f8.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1f8.png new file mode 100644 index 00000000..7d93a68a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1f9.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1f9.png new file mode 100644 index 00000000..9b389d12 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1fb.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1fb.png new file mode 100644 index 00000000..e2c1dc40 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1fc.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1fc.png new file mode 100644 index 00000000..cae1dd93 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1fe.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1fe.png new file mode 100644 index 00000000..b0a3a942 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7-1f1ff.png b/twake/frontend/public/public/emojione/32/1f1e7-1f1ff.png new file mode 100644 index 00000000..3d88316c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e7.png b/twake/frontend/public/public/emojione/32/1f1e7.png new file mode 100644 index 00000000..194b975e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1e6.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1e6.png new file mode 100644 index 00000000..4e9b5766 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1e8.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1e8.png new file mode 100644 index 00000000..26d05fec Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1e9.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1e9.png new file mode 100644 index 00000000..f59c7b02 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1eb.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1eb.png new file mode 100644 index 00000000..072146ff Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1ec.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1ec.png new file mode 100644 index 00000000..bc2dca71 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1ed.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1ed.png new file mode 100644 index 00000000..49885531 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1ee.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1ee.png new file mode 100644 index 00000000..5bb1a91c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1f0.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1f0.png new file mode 100644 index 00000000..34063a6d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1f1.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1f1.png new file mode 100644 index 00000000..b704b91c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1f2.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1f2.png new file mode 100644 index 00000000..cf929d20 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1f3.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1f3.png new file mode 100644 index 00000000..d3edcc92 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1f4.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1f4.png new file mode 100644 index 00000000..a3e7ec41 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1f5.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1f5.png new file mode 100644 index 00000000..bd6c7611 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1f7.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1f7.png new file mode 100644 index 00000000..1b8091fb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1fa.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1fa.png new file mode 100644 index 00000000..15459cca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1fb.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1fb.png new file mode 100644 index 00000000..0d1a7d82 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1fc.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1fc.png new file mode 100644 index 00000000..e09a902e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1fd.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1fd.png new file mode 100644 index 00000000..e7530259 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1fe.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1fe.png new file mode 100644 index 00000000..ff164cad Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8-1f1ff.png b/twake/frontend/public/public/emojione/32/1f1e8-1f1ff.png new file mode 100644 index 00000000..b5cff8ec Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e8.png b/twake/frontend/public/public/emojione/32/1f1e8.png new file mode 100644 index 00000000..affad093 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e9-1f1ea.png b/twake/frontend/public/public/emojione/32/1f1e9-1f1ea.png new file mode 100644 index 00000000..d023ef07 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e9-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e9-1f1ec.png b/twake/frontend/public/public/emojione/32/1f1e9-1f1ec.png new file mode 100644 index 00000000..d6a430d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e9-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e9-1f1ef.png b/twake/frontend/public/public/emojione/32/1f1e9-1f1ef.png new file mode 100644 index 00000000..e5e30835 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e9-1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e9-1f1f0.png b/twake/frontend/public/public/emojione/32/1f1e9-1f1f0.png new file mode 100644 index 00000000..eab7590b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e9-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e9-1f1f2.png b/twake/frontend/public/public/emojione/32/1f1e9-1f1f2.png new file mode 100644 index 00000000..09f89447 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e9-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e9-1f1f4.png b/twake/frontend/public/public/emojione/32/1f1e9-1f1f4.png new file mode 100644 index 00000000..e77fc5c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e9-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e9-1f1ff.png b/twake/frontend/public/public/emojione/32/1f1e9-1f1ff.png new file mode 100644 index 00000000..10254d5d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e9-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1e9.png b/twake/frontend/public/public/emojione/32/1f1e9.png new file mode 100644 index 00000000..943064d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ea-1f1e6.png b/twake/frontend/public/public/emojione/32/1f1ea-1f1e6.png new file mode 100644 index 00000000..e312f7b4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ea-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ea-1f1e8.png b/twake/frontend/public/public/emojione/32/1f1ea-1f1e8.png new file mode 100644 index 00000000..c2f60f6d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ea-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ea-1f1ea.png b/twake/frontend/public/public/emojione/32/1f1ea-1f1ea.png new file mode 100644 index 00000000..a8c1ef5f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ea-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ea-1f1ec.png b/twake/frontend/public/public/emojione/32/1f1ea-1f1ec.png new file mode 100644 index 00000000..66e47f00 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ea-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ea-1f1ed.png b/twake/frontend/public/public/emojione/32/1f1ea-1f1ed.png new file mode 100644 index 00000000..997b5d39 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ea-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ea-1f1f7.png b/twake/frontend/public/public/emojione/32/1f1ea-1f1f7.png new file mode 100644 index 00000000..e2434b7b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ea-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ea-1f1f8.png b/twake/frontend/public/public/emojione/32/1f1ea-1f1f8.png new file mode 100644 index 00000000..e312f7b4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ea-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ea-1f1f9.png b/twake/frontend/public/public/emojione/32/1f1ea-1f1f9.png new file mode 100644 index 00000000..b380c7e4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ea-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ea-1f1fa.png b/twake/frontend/public/public/emojione/32/1f1ea-1f1fa.png new file mode 100644 index 00000000..9668104a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ea-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ea.png b/twake/frontend/public/public/emojione/32/1f1ea.png new file mode 100644 index 00000000..d9e56757 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1eb-1f1ee.png b/twake/frontend/public/public/emojione/32/1f1eb-1f1ee.png new file mode 100644 index 00000000..9903cee3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1eb-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1eb-1f1ef.png b/twake/frontend/public/public/emojione/32/1f1eb-1f1ef.png new file mode 100644 index 00000000..0516aaf2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1eb-1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1eb-1f1f0.png b/twake/frontend/public/public/emojione/32/1f1eb-1f1f0.png new file mode 100644 index 00000000..d91932ec Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1eb-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1eb-1f1f2.png b/twake/frontend/public/public/emojione/32/1f1eb-1f1f2.png new file mode 100644 index 00000000..0a6b242f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1eb-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1eb-1f1f4.png b/twake/frontend/public/public/emojione/32/1f1eb-1f1f4.png new file mode 100644 index 00000000..85a5a547 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1eb-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1eb-1f1f7.png b/twake/frontend/public/public/emojione/32/1f1eb-1f1f7.png new file mode 100644 index 00000000..bd6c7611 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1eb-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1eb.png b/twake/frontend/public/public/emojione/32/1f1eb.png new file mode 100644 index 00000000..83a3be62 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1e6.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1e6.png new file mode 100644 index 00000000..c443391a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1e7.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1e7.png new file mode 100644 index 00000000..26d6893e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1e7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1e9.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1e9.png new file mode 100644 index 00000000..3824631f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1ea.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1ea.png new file mode 100644 index 00000000..31f375b7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1eb.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1eb.png new file mode 100644 index 00000000..39af3406 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1ec.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1ec.png new file mode 100644 index 00000000..cc214653 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1ed.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1ed.png new file mode 100644 index 00000000..6f74138e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1ee.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1ee.png new file mode 100644 index 00000000..29f0c0d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1f1.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1f1.png new file mode 100644 index 00000000..bca1f9f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1f2.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1f2.png new file mode 100644 index 00000000..2b274114 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1f3.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1f3.png new file mode 100644 index 00000000..ad5e1146 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1f5.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1f5.png new file mode 100644 index 00000000..9c237f65 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1f6.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1f6.png new file mode 100644 index 00000000..a0753592 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1f7.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1f7.png new file mode 100644 index 00000000..2c4034eb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1f8.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1f8.png new file mode 100644 index 00000000..64dae2e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1f9.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1f9.png new file mode 100644 index 00000000..902cd3ad Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1fa.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1fa.png new file mode 100644 index 00000000..f58e560f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1fc.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1fc.png new file mode 100644 index 00000000..2ecc24f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec-1f1fe.png b/twake/frontend/public/public/emojione/32/1f1ec-1f1fe.png new file mode 100644 index 00000000..534ca811 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ec.png b/twake/frontend/public/public/emojione/32/1f1ec.png new file mode 100644 index 00000000..b400229c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ed-1f1f0.png b/twake/frontend/public/public/emojione/32/1f1ed-1f1f0.png new file mode 100644 index 00000000..7040ba87 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ed-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ed-1f1f2.png b/twake/frontend/public/public/emojione/32/1f1ed-1f1f2.png new file mode 100644 index 00000000..4dcba471 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ed-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ed-1f1f3.png b/twake/frontend/public/public/emojione/32/1f1ed-1f1f3.png new file mode 100644 index 00000000..47f75f99 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ed-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ed-1f1f7.png b/twake/frontend/public/public/emojione/32/1f1ed-1f1f7.png new file mode 100644 index 00000000..0afe6922 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ed-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ed-1f1f9.png b/twake/frontend/public/public/emojione/32/1f1ed-1f1f9.png new file mode 100644 index 00000000..314cf2e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ed-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ed-1f1fa.png b/twake/frontend/public/public/emojione/32/1f1ed-1f1fa.png new file mode 100644 index 00000000..8b2ed205 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ed-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ed.png b/twake/frontend/public/public/emojione/32/1f1ed.png new file mode 100644 index 00000000..d19559b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ee-1f1e8.png b/twake/frontend/public/public/emojione/32/1f1ee-1f1e8.png new file mode 100644 index 00000000..6aa1b680 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ee-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ee-1f1e9.png b/twake/frontend/public/public/emojione/32/1f1ee-1f1e9.png new file mode 100644 index 00000000..1b91cae6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ee-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ee-1f1ea.png b/twake/frontend/public/public/emojione/32/1f1ee-1f1ea.png new file mode 100644 index 00000000..23db31ea Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ee-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ee-1f1f1.png b/twake/frontend/public/public/emojione/32/1f1ee-1f1f1.png new file mode 100644 index 00000000..a66f1f08 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ee-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ee-1f1f2.png b/twake/frontend/public/public/emojione/32/1f1ee-1f1f2.png new file mode 100644 index 00000000..aa401131 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ee-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ee-1f1f3.png b/twake/frontend/public/public/emojione/32/1f1ee-1f1f3.png new file mode 100644 index 00000000..a93b6140 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ee-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ee-1f1f4.png b/twake/frontend/public/public/emojione/32/1f1ee-1f1f4.png new file mode 100644 index 00000000..d6a430d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ee-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ee-1f1f6.png b/twake/frontend/public/public/emojione/32/1f1ee-1f1f6.png new file mode 100644 index 00000000..8aaf6d41 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ee-1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ee-1f1f7.png b/twake/frontend/public/public/emojione/32/1f1ee-1f1f7.png new file mode 100644 index 00000000..e9275c54 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ee-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ee-1f1f8.png b/twake/frontend/public/public/emojione/32/1f1ee-1f1f8.png new file mode 100644 index 00000000..f749dea0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ee-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ee-1f1f9.png b/twake/frontend/public/public/emojione/32/1f1ee-1f1f9.png new file mode 100644 index 00000000..8f1d5ad9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ee-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ee.png b/twake/frontend/public/public/emojione/32/1f1ee.png new file mode 100644 index 00000000..d5846a09 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ef-1f1ea.png b/twake/frontend/public/public/emojione/32/1f1ef-1f1ea.png new file mode 100644 index 00000000..961981ed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ef-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ef-1f1f2.png b/twake/frontend/public/public/emojione/32/1f1ef-1f1f2.png new file mode 100644 index 00000000..1d74da8d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ef-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ef-1f1f4.png b/twake/frontend/public/public/emojione/32/1f1ef-1f1f4.png new file mode 100644 index 00000000..8d5c2202 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ef-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ef-1f1f5.png b/twake/frontend/public/public/emojione/32/1f1ef-1f1f5.png new file mode 100644 index 00000000..851e4fb1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ef-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ef.png b/twake/frontend/public/public/emojione/32/1f1ef.png new file mode 100644 index 00000000..19a42ef1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f0-1f1ea.png b/twake/frontend/public/public/emojione/32/1f1f0-1f1ea.png new file mode 100644 index 00000000..2d446038 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f0-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f0-1f1ec.png b/twake/frontend/public/public/emojione/32/1f1f0-1f1ec.png new file mode 100644 index 00000000..7bfea560 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f0-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f0-1f1ed.png b/twake/frontend/public/public/emojione/32/1f1f0-1f1ed.png new file mode 100644 index 00000000..68340760 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f0-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f0-1f1ee.png b/twake/frontend/public/public/emojione/32/1f1f0-1f1ee.png new file mode 100644 index 00000000..c2267d2f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f0-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f0-1f1f2.png b/twake/frontend/public/public/emojione/32/1f1f0-1f1f2.png new file mode 100644 index 00000000..b5ecafde Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f0-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f0-1f1f3.png b/twake/frontend/public/public/emojione/32/1f1f0-1f1f3.png new file mode 100644 index 00000000..29820296 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f0-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f0-1f1f5.png b/twake/frontend/public/public/emojione/32/1f1f0-1f1f5.png new file mode 100644 index 00000000..a5191691 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f0-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f0-1f1f7.png b/twake/frontend/public/public/emojione/32/1f1f0-1f1f7.png new file mode 100644 index 00000000..8eb4a1c4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f0-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f0-1f1fc.png b/twake/frontend/public/public/emojione/32/1f1f0-1f1fc.png new file mode 100644 index 00000000..7aeba7ea Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f0-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f0-1f1fe.png b/twake/frontend/public/public/emojione/32/1f1f0-1f1fe.png new file mode 100644 index 00000000..ebeda228 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f0-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f0-1f1ff.png b/twake/frontend/public/public/emojione/32/1f1f0-1f1ff.png new file mode 100644 index 00000000..23993b43 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f0-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f0.png b/twake/frontend/public/public/emojione/32/1f1f0.png new file mode 100644 index 00000000..1572c2cc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f1-1f1e6.png b/twake/frontend/public/public/emojione/32/1f1f1-1f1e6.png new file mode 100644 index 00000000..78b8358e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f1-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f1-1f1e7.png b/twake/frontend/public/public/emojione/32/1f1f1-1f1e7.png new file mode 100644 index 00000000..1c31e072 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f1-1f1e7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f1-1f1e8.png b/twake/frontend/public/public/emojione/32/1f1f1-1f1e8.png new file mode 100644 index 00000000..41a6da81 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f1-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f1-1f1ee.png b/twake/frontend/public/public/emojione/32/1f1f1-1f1ee.png new file mode 100644 index 00000000..d3b20be8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f1-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f1-1f1f0.png b/twake/frontend/public/public/emojione/32/1f1f1-1f1f0.png new file mode 100644 index 00000000..bd9a0892 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f1-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f1-1f1f7.png b/twake/frontend/public/public/emojione/32/1f1f1-1f1f7.png new file mode 100644 index 00000000..d9de2776 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f1-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f1-1f1f8.png b/twake/frontend/public/public/emojione/32/1f1f1-1f1f8.png new file mode 100644 index 00000000..5ba903d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f1-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f1-1f1f9.png b/twake/frontend/public/public/emojione/32/1f1f1-1f1f9.png new file mode 100644 index 00000000..f853c6f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f1-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f1-1f1fa.png b/twake/frontend/public/public/emojione/32/1f1f1-1f1fa.png new file mode 100644 index 00000000..91f4940a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f1-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f1-1f1fb.png b/twake/frontend/public/public/emojione/32/1f1f1-1f1fb.png new file mode 100644 index 00000000..019ad23b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f1-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f1-1f1fe.png b/twake/frontend/public/public/emojione/32/1f1f1-1f1fe.png new file mode 100644 index 00000000..301cff71 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f1-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f1.png b/twake/frontend/public/public/emojione/32/1f1f1.png new file mode 100644 index 00000000..d733e481 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1e6.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1e6.png new file mode 100644 index 00000000..4072deb6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1e8.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1e8.png new file mode 100644 index 00000000..1b91cae6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1e9.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1e9.png new file mode 100644 index 00000000..64ce8c78 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1ea.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1ea.png new file mode 100644 index 00000000..0c2acb03 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1eb.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1eb.png new file mode 100644 index 00000000..bd6c7611 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1ec.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1ec.png new file mode 100644 index 00000000..cabf8083 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1ed.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1ed.png new file mode 100644 index 00000000..d71b269d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1f0.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1f0.png new file mode 100644 index 00000000..1a7aa58d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1f1.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1f1.png new file mode 100644 index 00000000..f359efae Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1f2.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1f2.png new file mode 100644 index 00000000..87eda1fc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1f3.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1f3.png new file mode 100644 index 00000000..723bb03c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1f4.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1f4.png new file mode 100644 index 00000000..0d7bdae4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1f5.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1f5.png new file mode 100644 index 00000000..45b9e9d5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1f6.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1f6.png new file mode 100644 index 00000000..55d586cc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1f7.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1f7.png new file mode 100644 index 00000000..764fcfee Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1f8.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1f8.png new file mode 100644 index 00000000..01c3d796 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1f9.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1f9.png new file mode 100644 index 00000000..21b28f3a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1fa.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1fa.png new file mode 100644 index 00000000..d90cfe66 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1fb.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1fb.png new file mode 100644 index 00000000..c67cd421 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1fc.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1fc.png new file mode 100644 index 00000000..9a856cdd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1fd.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1fd.png new file mode 100644 index 00000000..3ed9dbb7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1fe.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1fe.png new file mode 100644 index 00000000..7e1e5acb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2-1f1ff.png b/twake/frontend/public/public/emojione/32/1f1f2-1f1ff.png new file mode 100644 index 00000000..0f63aec0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f2.png b/twake/frontend/public/public/emojione/32/1f1f2.png new file mode 100644 index 00000000..7c86fdb5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f3-1f1e6.png b/twake/frontend/public/public/emojione/32/1f1f3-1f1e6.png new file mode 100644 index 00000000..f9d0fa0d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f3-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f3-1f1e8.png b/twake/frontend/public/public/emojione/32/1f1f3-1f1e8.png new file mode 100644 index 00000000..370de80b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f3-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f3-1f1ea.png b/twake/frontend/public/public/emojione/32/1f1f3-1f1ea.png new file mode 100644 index 00000000..f908894b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f3-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f3-1f1eb.png b/twake/frontend/public/public/emojione/32/1f1f3-1f1eb.png new file mode 100644 index 00000000..084bad82 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f3-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f3-1f1ec.png b/twake/frontend/public/public/emojione/32/1f1f3-1f1ec.png new file mode 100644 index 00000000..3f6fe439 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f3-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f3-1f1ee.png b/twake/frontend/public/public/emojione/32/1f1f3-1f1ee.png new file mode 100644 index 00000000..322532bb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f3-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f3-1f1f1.png b/twake/frontend/public/public/emojione/32/1f1f3-1f1f1.png new file mode 100644 index 00000000..bdd879c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f3-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f3-1f1f4.png b/twake/frontend/public/public/emojione/32/1f1f3-1f1f4.png new file mode 100644 index 00000000..e2c1dc40 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f3-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f3-1f1f5.png b/twake/frontend/public/public/emojione/32/1f1f3-1f1f5.png new file mode 100644 index 00000000..e8e03a42 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f3-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f3-1f1f7.png b/twake/frontend/public/public/emojione/32/1f1f3-1f1f7.png new file mode 100644 index 00000000..c46365f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f3-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f3-1f1fa.png b/twake/frontend/public/public/emojione/32/1f1f3-1f1fa.png new file mode 100644 index 00000000..a8abffac Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f3-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f3-1f1ff.png b/twake/frontend/public/public/emojione/32/1f1f3-1f1ff.png new file mode 100644 index 00000000..89862b94 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f3-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f3.png b/twake/frontend/public/public/emojione/32/1f1f3.png new file mode 100644 index 00000000..8b34e747 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f4-1f1f2.png b/twake/frontend/public/public/emojione/32/1f1f4-1f1f2.png new file mode 100644 index 00000000..cdb2ad81 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f4-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f4.png b/twake/frontend/public/public/emojione/32/1f1f4.png new file mode 100644 index 00000000..bef219c9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f5-1f1e6.png b/twake/frontend/public/public/emojione/32/1f1f5-1f1e6.png new file mode 100644 index 00000000..243effab Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f5-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f5-1f1ea.png b/twake/frontend/public/public/emojione/32/1f1f5-1f1ea.png new file mode 100644 index 00000000..6e4b7dee Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f5-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f5-1f1eb.png b/twake/frontend/public/public/emojione/32/1f1f5-1f1eb.png new file mode 100644 index 00000000..9c08a21e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f5-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f5-1f1ec.png b/twake/frontend/public/public/emojione/32/1f1f5-1f1ec.png new file mode 100644 index 00000000..d847c0cf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f5-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f5-1f1ed.png b/twake/frontend/public/public/emojione/32/1f1f5-1f1ed.png new file mode 100644 index 00000000..95d0cd8d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f5-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f5-1f1f0.png b/twake/frontend/public/public/emojione/32/1f1f5-1f1f0.png new file mode 100644 index 00000000..0aaa86b7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f5-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f5-1f1f1.png b/twake/frontend/public/public/emojione/32/1f1f5-1f1f1.png new file mode 100644 index 00000000..99e81247 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f5-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f5-1f1f2.png b/twake/frontend/public/public/emojione/32/1f1f5-1f1f2.png new file mode 100644 index 00000000..d24b1c71 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f5-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f5-1f1f3.png b/twake/frontend/public/public/emojione/32/1f1f5-1f1f3.png new file mode 100644 index 00000000..03b6344b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f5-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f5-1f1f7.png b/twake/frontend/public/public/emojione/32/1f1f5-1f1f7.png new file mode 100644 index 00000000..8ba2a243 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f5-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f5-1f1f8.png b/twake/frontend/public/public/emojione/32/1f1f5-1f1f8.png new file mode 100644 index 00000000..13138e96 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f5-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f5-1f1f9.png b/twake/frontend/public/public/emojione/32/1f1f5-1f1f9.png new file mode 100644 index 00000000..f7271b2b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f5-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f5-1f1fc.png b/twake/frontend/public/public/emojione/32/1f1f5-1f1fc.png new file mode 100644 index 00000000..d819ea09 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f5-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f5-1f1fe.png b/twake/frontend/public/public/emojione/32/1f1f5-1f1fe.png new file mode 100644 index 00000000..7b7678ba Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f5-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f5.png b/twake/frontend/public/public/emojione/32/1f1f5.png new file mode 100644 index 00000000..18acdcc0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f6-1f1e6.png b/twake/frontend/public/public/emojione/32/1f1f6-1f1e6.png new file mode 100644 index 00000000..568d3195 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f6-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f6.png b/twake/frontend/public/public/emojione/32/1f1f6.png new file mode 100644 index 00000000..9c0e6040 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f7-1f1ea.png b/twake/frontend/public/public/emojione/32/1f1f7-1f1ea.png new file mode 100644 index 00000000..49077ee9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f7-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f7-1f1f4.png b/twake/frontend/public/public/emojione/32/1f1f7-1f1f4.png new file mode 100644 index 00000000..d968ace9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f7-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f7-1f1f8.png b/twake/frontend/public/public/emojione/32/1f1f7-1f1f8.png new file mode 100644 index 00000000..f4933b89 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f7-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f7-1f1fa.png b/twake/frontend/public/public/emojione/32/1f1f7-1f1fa.png new file mode 100644 index 00000000..31c397f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f7-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f7-1f1fc.png b/twake/frontend/public/public/emojione/32/1f1f7-1f1fc.png new file mode 100644 index 00000000..7bf9231a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f7-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f7.png b/twake/frontend/public/public/emojione/32/1f1f7.png new file mode 100644 index 00000000..2230f021 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1e6.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1e6.png new file mode 100644 index 00000000..7a1d54fa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1e7.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1e7.png new file mode 100644 index 00000000..f44b054a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1e7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1e8.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1e8.png new file mode 100644 index 00000000..5a02d902 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1e9.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1e9.png new file mode 100644 index 00000000..7dbfd1ca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1ea.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1ea.png new file mode 100644 index 00000000..9547acaa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1ec.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1ec.png new file mode 100644 index 00000000..f4effe3e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1ed.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1ed.png new file mode 100644 index 00000000..cdd896fa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1ee.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1ee.png new file mode 100644 index 00000000..4445d36e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1ef.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1ef.png new file mode 100644 index 00000000..e2c1dc40 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1f0.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1f0.png new file mode 100644 index 00000000..925112c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1f1.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1f1.png new file mode 100644 index 00000000..be687001 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1f2.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1f2.png new file mode 100644 index 00000000..1f000e2a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1f3.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1f3.png new file mode 100644 index 00000000..e82fa67e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1f4.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1f4.png new file mode 100644 index 00000000..19999c73 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1f7.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1f7.png new file mode 100644 index 00000000..2e001361 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1f8.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1f8.png new file mode 100644 index 00000000..d3954acf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1f9.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1f9.png new file mode 100644 index 00000000..9c399902 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1fb.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1fb.png new file mode 100644 index 00000000..bf6194fb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1fd.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1fd.png new file mode 100644 index 00000000..342da7d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1fe.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1fe.png new file mode 100644 index 00000000..9f44596e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8-1f1ff.png b/twake/frontend/public/public/emojione/32/1f1f8-1f1ff.png new file mode 100644 index 00000000..5158115d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f8.png b/twake/frontend/public/public/emojione/32/1f1f8.png new file mode 100644 index 00000000..ef2b24e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9-1f1e6.png b/twake/frontend/public/public/emojione/32/1f1f9-1f1e6.png new file mode 100644 index 00000000..6b36d31e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9-1f1e8.png b/twake/frontend/public/public/emojione/32/1f1f9-1f1e8.png new file mode 100644 index 00000000..517bdc57 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9-1f1e9.png b/twake/frontend/public/public/emojione/32/1f1f9-1f1e9.png new file mode 100644 index 00000000..d968ace9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9-1f1eb.png b/twake/frontend/public/public/emojione/32/1f1f9-1f1eb.png new file mode 100644 index 00000000..dd1286ac Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9-1f1ec.png b/twake/frontend/public/public/emojione/32/1f1f9-1f1ec.png new file mode 100644 index 00000000..4d84fb64 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9-1f1ed.png b/twake/frontend/public/public/emojione/32/1f1f9-1f1ed.png new file mode 100644 index 00000000..ea835708 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9-1f1ef.png b/twake/frontend/public/public/emojione/32/1f1f9-1f1ef.png new file mode 100644 index 00000000..92bff30f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9-1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9-1f1f0.png b/twake/frontend/public/public/emojione/32/1f1f9-1f1f0.png new file mode 100644 index 00000000..3a2182ca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9-1f1f1.png b/twake/frontend/public/public/emojione/32/1f1f9-1f1f1.png new file mode 100644 index 00000000..de4cacc3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9-1f1f2.png b/twake/frontend/public/public/emojione/32/1f1f9-1f1f2.png new file mode 100644 index 00000000..0e524d15 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9-1f1f3.png b/twake/frontend/public/public/emojione/32/1f1f9-1f1f3.png new file mode 100644 index 00000000..bea75816 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9-1f1f4.png b/twake/frontend/public/public/emojione/32/1f1f9-1f1f4.png new file mode 100644 index 00000000..9f980d08 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9-1f1f7.png b/twake/frontend/public/public/emojione/32/1f1f9-1f1f7.png new file mode 100644 index 00000000..39e95173 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9-1f1f9.png b/twake/frontend/public/public/emojione/32/1f1f9-1f1f9.png new file mode 100644 index 00000000..550d00c5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9-1f1fb.png b/twake/frontend/public/public/emojione/32/1f1f9-1f1fb.png new file mode 100644 index 00000000..d8c3c10d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9-1f1fc.png b/twake/frontend/public/public/emojione/32/1f1f9-1f1fc.png new file mode 100644 index 00000000..c6e5b029 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9-1f1ff.png b/twake/frontend/public/public/emojione/32/1f1f9-1f1ff.png new file mode 100644 index 00000000..4eead8ff Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1f9.png b/twake/frontend/public/public/emojione/32/1f1f9.png new file mode 100644 index 00000000..be7c6310 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fa-1f1e6.png b/twake/frontend/public/public/emojione/32/1f1fa-1f1e6.png new file mode 100644 index 00000000..e9b897e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fa-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fa-1f1ec.png b/twake/frontend/public/public/emojione/32/1f1fa-1f1ec.png new file mode 100644 index 00000000..5af8c09e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fa-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fa-1f1f2.png b/twake/frontend/public/public/emojione/32/1f1fa-1f1f2.png new file mode 100644 index 00000000..241c7ab1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fa-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fa-1f1f3.png b/twake/frontend/public/public/emojione/32/1f1fa-1f1f3.png new file mode 100644 index 00000000..38ba7301 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fa-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fa-1f1f8.png b/twake/frontend/public/public/emojione/32/1f1fa-1f1f8.png new file mode 100644 index 00000000..241c7ab1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fa-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fa-1f1fe.png b/twake/frontend/public/public/emojione/32/1f1fa-1f1fe.png new file mode 100644 index 00000000..86dc2fa9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fa-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fa-1f1ff.png b/twake/frontend/public/public/emojione/32/1f1fa-1f1ff.png new file mode 100644 index 00000000..e36be73c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fa-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fa.png b/twake/frontend/public/public/emojione/32/1f1fa.png new file mode 100644 index 00000000..658e1439 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fb-1f1e6.png b/twake/frontend/public/public/emojione/32/1f1fb-1f1e6.png new file mode 100644 index 00000000..0e248b65 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fb-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fb-1f1e8.png b/twake/frontend/public/public/emojione/32/1f1fb-1f1e8.png new file mode 100644 index 00000000..903808a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fb-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fb-1f1ea.png b/twake/frontend/public/public/emojione/32/1f1fb-1f1ea.png new file mode 100644 index 00000000..1ad01f7f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fb-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fb-1f1ec.png b/twake/frontend/public/public/emojione/32/1f1fb-1f1ec.png new file mode 100644 index 00000000..934b203c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fb-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fb-1f1ee.png b/twake/frontend/public/public/emojione/32/1f1fb-1f1ee.png new file mode 100644 index 00000000..ea6bdf09 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fb-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fb-1f1f3.png b/twake/frontend/public/public/emojione/32/1f1fb-1f1f3.png new file mode 100644 index 00000000..3b7b3f75 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fb-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fb-1f1fa.png b/twake/frontend/public/public/emojione/32/1f1fb-1f1fa.png new file mode 100644 index 00000000..f5d601b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fb-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fb.png b/twake/frontend/public/public/emojione/32/1f1fb.png new file mode 100644 index 00000000..1eb4e217 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fc-1f1eb.png b/twake/frontend/public/public/emojione/32/1f1fc-1f1eb.png new file mode 100644 index 00000000..09d55304 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fc-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fc-1f1f8.png b/twake/frontend/public/public/emojione/32/1f1fc-1f1f8.png new file mode 100644 index 00000000..c1190851 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fc-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fc.png b/twake/frontend/public/public/emojione/32/1f1fc.png new file mode 100644 index 00000000..328399a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fd-1f1f0.png b/twake/frontend/public/public/emojione/32/1f1fd-1f1f0.png new file mode 100644 index 00000000..a40ea319 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fd-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fd.png b/twake/frontend/public/public/emojione/32/1f1fd.png new file mode 100644 index 00000000..7a45bf57 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fe-1f1ea.png b/twake/frontend/public/public/emojione/32/1f1fe-1f1ea.png new file mode 100644 index 00000000..5d50ab22 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fe-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fe-1f1f9.png b/twake/frontend/public/public/emojione/32/1f1fe-1f1f9.png new file mode 100644 index 00000000..6c56666a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fe-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1fe.png b/twake/frontend/public/public/emojione/32/1f1fe.png new file mode 100644 index 00000000..407e1ef8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ff-1f1e6.png b/twake/frontend/public/public/emojione/32/1f1ff-1f1e6.png new file mode 100644 index 00000000..1e74021b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ff-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ff-1f1f2.png b/twake/frontend/public/public/emojione/32/1f1ff-1f1f2.png new file mode 100644 index 00000000..62a6e5a2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ff-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ff-1f1fc.png b/twake/frontend/public/public/emojione/32/1f1ff-1f1fc.png new file mode 100644 index 00000000..cc9da0e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ff-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f1ff.png b/twake/frontend/public/public/emojione/32/1f1ff.png new file mode 100644 index 00000000..2dca7ca1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f201.png b/twake/frontend/public/public/emojione/32/1f201.png new file mode 100644 index 00000000..236f8e51 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f201.png differ diff --git a/twake/frontend/public/public/emojione/32/1f202.png b/twake/frontend/public/public/emojione/32/1f202.png new file mode 100644 index 00000000..eb2f5baa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f202.png differ diff --git a/twake/frontend/public/public/emojione/32/1f21a.png b/twake/frontend/public/public/emojione/32/1f21a.png new file mode 100644 index 00000000..8ce74e3f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f21a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f22f.png b/twake/frontend/public/public/emojione/32/1f22f.png new file mode 100644 index 00000000..ee04c25d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f22f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f232.png b/twake/frontend/public/public/emojione/32/1f232.png new file mode 100644 index 00000000..92f1b2ed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f232.png differ diff --git a/twake/frontend/public/public/emojione/32/1f233.png b/twake/frontend/public/public/emojione/32/1f233.png new file mode 100644 index 00000000..c0056655 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f233.png differ diff --git a/twake/frontend/public/public/emojione/32/1f234.png b/twake/frontend/public/public/emojione/32/1f234.png new file mode 100644 index 00000000..02857a06 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f234.png differ diff --git a/twake/frontend/public/public/emojione/32/1f235.png b/twake/frontend/public/public/emojione/32/1f235.png new file mode 100644 index 00000000..ac6a8096 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f235.png differ diff --git a/twake/frontend/public/public/emojione/32/1f236.png b/twake/frontend/public/public/emojione/32/1f236.png new file mode 100644 index 00000000..3d92e7a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f236.png differ diff --git a/twake/frontend/public/public/emojione/32/1f237.png b/twake/frontend/public/public/emojione/32/1f237.png new file mode 100644 index 00000000..b51cf478 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f237.png differ diff --git a/twake/frontend/public/public/emojione/32/1f238.png b/twake/frontend/public/public/emojione/32/1f238.png new file mode 100644 index 00000000..bf41bd8b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f238.png differ diff --git a/twake/frontend/public/public/emojione/32/1f239.png b/twake/frontend/public/public/emojione/32/1f239.png new file mode 100644 index 00000000..fe9f1cc2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f239.png differ diff --git a/twake/frontend/public/public/emojione/32/1f23a.png b/twake/frontend/public/public/emojione/32/1f23a.png new file mode 100644 index 00000000..37e42554 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f23a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f250.png b/twake/frontend/public/public/emojione/32/1f250.png new file mode 100644 index 00000000..ff44fcfb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f250.png differ diff --git a/twake/frontend/public/public/emojione/32/1f251.png b/twake/frontend/public/public/emojione/32/1f251.png new file mode 100644 index 00000000..0d961938 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f251.png differ diff --git a/twake/frontend/public/public/emojione/32/1f300.png b/twake/frontend/public/public/emojione/32/1f300.png new file mode 100644 index 00000000..d682b595 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f300.png differ diff --git a/twake/frontend/public/public/emojione/32/1f301.png b/twake/frontend/public/public/emojione/32/1f301.png new file mode 100644 index 00000000..fb8fa18a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f301.png differ diff --git a/twake/frontend/public/public/emojione/32/1f302.png b/twake/frontend/public/public/emojione/32/1f302.png new file mode 100644 index 00000000..cf2ea5d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f302.png differ diff --git a/twake/frontend/public/public/emojione/32/1f303.png b/twake/frontend/public/public/emojione/32/1f303.png new file mode 100644 index 00000000..d8e8d3e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f303.png differ diff --git a/twake/frontend/public/public/emojione/32/1f304.png b/twake/frontend/public/public/emojione/32/1f304.png new file mode 100644 index 00000000..9f8ee5d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f304.png differ diff --git a/twake/frontend/public/public/emojione/32/1f305.png b/twake/frontend/public/public/emojione/32/1f305.png new file mode 100644 index 00000000..7d13e09c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f305.png differ diff --git a/twake/frontend/public/public/emojione/32/1f306.png b/twake/frontend/public/public/emojione/32/1f306.png new file mode 100644 index 00000000..0a97c619 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f306.png differ diff --git a/twake/frontend/public/public/emojione/32/1f307.png b/twake/frontend/public/public/emojione/32/1f307.png new file mode 100644 index 00000000..8fa6b7b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f307.png differ diff --git a/twake/frontend/public/public/emojione/32/1f308.png b/twake/frontend/public/public/emojione/32/1f308.png new file mode 100644 index 00000000..d413718f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f308.png differ diff --git a/twake/frontend/public/public/emojione/32/1f309.png b/twake/frontend/public/public/emojione/32/1f309.png new file mode 100644 index 00000000..33f7d644 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f309.png differ diff --git a/twake/frontend/public/public/emojione/32/1f30a.png b/twake/frontend/public/public/emojione/32/1f30a.png new file mode 100644 index 00000000..155b288c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f30a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f30b.png b/twake/frontend/public/public/emojione/32/1f30b.png new file mode 100644 index 00000000..e6a5e340 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f30b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f30c.png b/twake/frontend/public/public/emojione/32/1f30c.png new file mode 100644 index 00000000..2e01c674 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f30c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f30d.png b/twake/frontend/public/public/emojione/32/1f30d.png new file mode 100644 index 00000000..5364456f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f30d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f30e.png b/twake/frontend/public/public/emojione/32/1f30e.png new file mode 100644 index 00000000..74ac4264 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f30e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f30f.png b/twake/frontend/public/public/emojione/32/1f30f.png new file mode 100644 index 00000000..ce470c1a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f30f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f310.png b/twake/frontend/public/public/emojione/32/1f310.png new file mode 100644 index 00000000..7395bdd5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f310.png differ diff --git a/twake/frontend/public/public/emojione/32/1f311.png b/twake/frontend/public/public/emojione/32/1f311.png new file mode 100644 index 00000000..4c7b9530 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f311.png differ diff --git a/twake/frontend/public/public/emojione/32/1f312.png b/twake/frontend/public/public/emojione/32/1f312.png new file mode 100644 index 00000000..8e9350af Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f312.png differ diff --git a/twake/frontend/public/public/emojione/32/1f313.png b/twake/frontend/public/public/emojione/32/1f313.png new file mode 100644 index 00000000..2ac66e2c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f313.png differ diff --git a/twake/frontend/public/public/emojione/32/1f314.png b/twake/frontend/public/public/emojione/32/1f314.png new file mode 100644 index 00000000..de03adc7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f314.png differ diff --git a/twake/frontend/public/public/emojione/32/1f315.png b/twake/frontend/public/public/emojione/32/1f315.png new file mode 100644 index 00000000..b1e53e8b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f315.png differ diff --git a/twake/frontend/public/public/emojione/32/1f316.png b/twake/frontend/public/public/emojione/32/1f316.png new file mode 100644 index 00000000..605dc30d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f316.png differ diff --git a/twake/frontend/public/public/emojione/32/1f317.png b/twake/frontend/public/public/emojione/32/1f317.png new file mode 100644 index 00000000..9ab9b44f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f317.png differ diff --git a/twake/frontend/public/public/emojione/32/1f318.png b/twake/frontend/public/public/emojione/32/1f318.png new file mode 100644 index 00000000..63136f5d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f318.png differ diff --git a/twake/frontend/public/public/emojione/32/1f319.png b/twake/frontend/public/public/emojione/32/1f319.png new file mode 100644 index 00000000..f9d07297 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f319.png differ diff --git a/twake/frontend/public/public/emojione/32/1f31a.png b/twake/frontend/public/public/emojione/32/1f31a.png new file mode 100644 index 00000000..9e53d56e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f31a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f31b.png b/twake/frontend/public/public/emojione/32/1f31b.png new file mode 100644 index 00000000..087f85e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f31b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f31c.png b/twake/frontend/public/public/emojione/32/1f31c.png new file mode 100644 index 00000000..3a435584 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f31c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f31d.png b/twake/frontend/public/public/emojione/32/1f31d.png new file mode 100644 index 00000000..1720c64d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f31d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f31e.png b/twake/frontend/public/public/emojione/32/1f31e.png new file mode 100644 index 00000000..2885b238 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f31e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f31f.png b/twake/frontend/public/public/emojione/32/1f31f.png new file mode 100644 index 00000000..c2cae210 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f31f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f320.png b/twake/frontend/public/public/emojione/32/1f320.png new file mode 100644 index 00000000..dc9a4607 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f320.png differ diff --git a/twake/frontend/public/public/emojione/32/1f321.png b/twake/frontend/public/public/emojione/32/1f321.png new file mode 100644 index 00000000..3d173006 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f321.png differ diff --git a/twake/frontend/public/public/emojione/32/1f324.png b/twake/frontend/public/public/emojione/32/1f324.png new file mode 100644 index 00000000..1979bae3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f324.png differ diff --git a/twake/frontend/public/public/emojione/32/1f325.png b/twake/frontend/public/public/emojione/32/1f325.png new file mode 100644 index 00000000..3a3b0165 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f325.png differ diff --git a/twake/frontend/public/public/emojione/32/1f326.png b/twake/frontend/public/public/emojione/32/1f326.png new file mode 100644 index 00000000..f93abe21 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f326.png differ diff --git a/twake/frontend/public/public/emojione/32/1f327.png b/twake/frontend/public/public/emojione/32/1f327.png new file mode 100644 index 00000000..ec00402e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f327.png differ diff --git a/twake/frontend/public/public/emojione/32/1f328.png b/twake/frontend/public/public/emojione/32/1f328.png new file mode 100644 index 00000000..52ff161f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f328.png differ diff --git a/twake/frontend/public/public/emojione/32/1f329.png b/twake/frontend/public/public/emojione/32/1f329.png new file mode 100644 index 00000000..c03d5789 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f329.png differ diff --git a/twake/frontend/public/public/emojione/32/1f32a.png b/twake/frontend/public/public/emojione/32/1f32a.png new file mode 100644 index 00000000..9dd5e2b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f32a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f32b.png b/twake/frontend/public/public/emojione/32/1f32b.png new file mode 100644 index 00000000..deed961d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f32b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f32c.png b/twake/frontend/public/public/emojione/32/1f32c.png new file mode 100644 index 00000000..829b6e6c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f32c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f32d.png b/twake/frontend/public/public/emojione/32/1f32d.png new file mode 100644 index 00000000..eb952ce2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f32d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f32e.png b/twake/frontend/public/public/emojione/32/1f32e.png new file mode 100644 index 00000000..6ae26cd7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f32e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f32f.png b/twake/frontend/public/public/emojione/32/1f32f.png new file mode 100644 index 00000000..c3617128 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f32f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f330.png b/twake/frontend/public/public/emojione/32/1f330.png new file mode 100644 index 00000000..2a58c9b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f330.png differ diff --git a/twake/frontend/public/public/emojione/32/1f331.png b/twake/frontend/public/public/emojione/32/1f331.png new file mode 100644 index 00000000..dae502b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f331.png differ diff --git a/twake/frontend/public/public/emojione/32/1f332.png b/twake/frontend/public/public/emojione/32/1f332.png new file mode 100644 index 00000000..439e388f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f332.png differ diff --git a/twake/frontend/public/public/emojione/32/1f333.png b/twake/frontend/public/public/emojione/32/1f333.png new file mode 100644 index 00000000..e6cf63d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f333.png differ diff --git a/twake/frontend/public/public/emojione/32/1f334.png b/twake/frontend/public/public/emojione/32/1f334.png new file mode 100644 index 00000000..c525e183 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f334.png differ diff --git a/twake/frontend/public/public/emojione/32/1f335.png b/twake/frontend/public/public/emojione/32/1f335.png new file mode 100644 index 00000000..51d3237f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f335.png differ diff --git a/twake/frontend/public/public/emojione/32/1f336.png b/twake/frontend/public/public/emojione/32/1f336.png new file mode 100644 index 00000000..66abbbc9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f336.png differ diff --git a/twake/frontend/public/public/emojione/32/1f337.png b/twake/frontend/public/public/emojione/32/1f337.png new file mode 100644 index 00000000..f62013e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f337.png differ diff --git a/twake/frontend/public/public/emojione/32/1f338.png b/twake/frontend/public/public/emojione/32/1f338.png new file mode 100644 index 00000000..66a6b2af Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f338.png differ diff --git a/twake/frontend/public/public/emojione/32/1f339.png b/twake/frontend/public/public/emojione/32/1f339.png new file mode 100644 index 00000000..c0c4f8a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f339.png differ diff --git a/twake/frontend/public/public/emojione/32/1f33a.png b/twake/frontend/public/public/emojione/32/1f33a.png new file mode 100644 index 00000000..1163c74e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f33a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f33b.png b/twake/frontend/public/public/emojione/32/1f33b.png new file mode 100644 index 00000000..1e0d3cd4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f33b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f33c.png b/twake/frontend/public/public/emojione/32/1f33c.png new file mode 100644 index 00000000..5f038c43 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f33c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f33d.png b/twake/frontend/public/public/emojione/32/1f33d.png new file mode 100644 index 00000000..7b452f4a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f33d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f33e.png b/twake/frontend/public/public/emojione/32/1f33e.png new file mode 100644 index 00000000..a9b9240a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f33e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f33f.png b/twake/frontend/public/public/emojione/32/1f33f.png new file mode 100644 index 00000000..1e9be99d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f33f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f340.png b/twake/frontend/public/public/emojione/32/1f340.png new file mode 100644 index 00000000..7a7c7cad Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f340.png differ diff --git a/twake/frontend/public/public/emojione/32/1f341.png b/twake/frontend/public/public/emojione/32/1f341.png new file mode 100644 index 00000000..3574f83e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f341.png differ diff --git a/twake/frontend/public/public/emojione/32/1f342.png b/twake/frontend/public/public/emojione/32/1f342.png new file mode 100644 index 00000000..70008ccb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f342.png differ diff --git a/twake/frontend/public/public/emojione/32/1f343.png b/twake/frontend/public/public/emojione/32/1f343.png new file mode 100644 index 00000000..92a09c21 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f343.png differ diff --git a/twake/frontend/public/public/emojione/32/1f344.png b/twake/frontend/public/public/emojione/32/1f344.png new file mode 100644 index 00000000..b0ef3344 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f344.png differ diff --git a/twake/frontend/public/public/emojione/32/1f345.png b/twake/frontend/public/public/emojione/32/1f345.png new file mode 100644 index 00000000..7e1192a4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f345.png differ diff --git a/twake/frontend/public/public/emojione/32/1f346.png b/twake/frontend/public/public/emojione/32/1f346.png new file mode 100644 index 00000000..e0c06bed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f346.png differ diff --git a/twake/frontend/public/public/emojione/32/1f347.png b/twake/frontend/public/public/emojione/32/1f347.png new file mode 100644 index 00000000..3d12403a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f347.png differ diff --git a/twake/frontend/public/public/emojione/32/1f348.png b/twake/frontend/public/public/emojione/32/1f348.png new file mode 100644 index 00000000..9ae8e96c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f348.png differ diff --git a/twake/frontend/public/public/emojione/32/1f349.png b/twake/frontend/public/public/emojione/32/1f349.png new file mode 100644 index 00000000..e0c4043c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f349.png differ diff --git a/twake/frontend/public/public/emojione/32/1f34a.png b/twake/frontend/public/public/emojione/32/1f34a.png new file mode 100644 index 00000000..19b017d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f34a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f34b.png b/twake/frontend/public/public/emojione/32/1f34b.png new file mode 100644 index 00000000..9e226870 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f34b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f34c.png b/twake/frontend/public/public/emojione/32/1f34c.png new file mode 100644 index 00000000..c899469d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f34c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f34d.png b/twake/frontend/public/public/emojione/32/1f34d.png new file mode 100644 index 00000000..0e7c6cb6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f34d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f34e.png b/twake/frontend/public/public/emojione/32/1f34e.png new file mode 100644 index 00000000..8656e3c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f34e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f34f.png b/twake/frontend/public/public/emojione/32/1f34f.png new file mode 100644 index 00000000..49e5dc6f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f34f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f350.png b/twake/frontend/public/public/emojione/32/1f350.png new file mode 100644 index 00000000..0e5f8e64 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f350.png differ diff --git a/twake/frontend/public/public/emojione/32/1f351.png b/twake/frontend/public/public/emojione/32/1f351.png new file mode 100644 index 00000000..73851829 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f351.png differ diff --git a/twake/frontend/public/public/emojione/32/1f352.png b/twake/frontend/public/public/emojione/32/1f352.png new file mode 100644 index 00000000..3d8333e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f352.png differ diff --git a/twake/frontend/public/public/emojione/32/1f353.png b/twake/frontend/public/public/emojione/32/1f353.png new file mode 100644 index 00000000..ef3bc0cf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f353.png differ diff --git a/twake/frontend/public/public/emojione/32/1f354.png b/twake/frontend/public/public/emojione/32/1f354.png new file mode 100644 index 00000000..506fb66b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f354.png differ diff --git a/twake/frontend/public/public/emojione/32/1f355.png b/twake/frontend/public/public/emojione/32/1f355.png new file mode 100644 index 00000000..f7c5b952 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f355.png differ diff --git a/twake/frontend/public/public/emojione/32/1f356.png b/twake/frontend/public/public/emojione/32/1f356.png new file mode 100644 index 00000000..e6a56df8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f356.png differ diff --git a/twake/frontend/public/public/emojione/32/1f357.png b/twake/frontend/public/public/emojione/32/1f357.png new file mode 100644 index 00000000..6731aca6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f357.png differ diff --git a/twake/frontend/public/public/emojione/32/1f358.png b/twake/frontend/public/public/emojione/32/1f358.png new file mode 100644 index 00000000..13d02c92 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f358.png differ diff --git a/twake/frontend/public/public/emojione/32/1f359.png b/twake/frontend/public/public/emojione/32/1f359.png new file mode 100644 index 00000000..c9fa9818 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f359.png differ diff --git a/twake/frontend/public/public/emojione/32/1f35a.png b/twake/frontend/public/public/emojione/32/1f35a.png new file mode 100644 index 00000000..7a5ec72f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f35a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f35b.png b/twake/frontend/public/public/emojione/32/1f35b.png new file mode 100644 index 00000000..71897547 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f35b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f35c.png b/twake/frontend/public/public/emojione/32/1f35c.png new file mode 100644 index 00000000..fc3a5603 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f35c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f35d.png b/twake/frontend/public/public/emojione/32/1f35d.png new file mode 100644 index 00000000..c72c42dd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f35d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f35e.png b/twake/frontend/public/public/emojione/32/1f35e.png new file mode 100644 index 00000000..72f543a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f35e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f35f.png b/twake/frontend/public/public/emojione/32/1f35f.png new file mode 100644 index 00000000..cf9d3715 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f35f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f360.png b/twake/frontend/public/public/emojione/32/1f360.png new file mode 100644 index 00000000..0744d7d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f360.png differ diff --git a/twake/frontend/public/public/emojione/32/1f361.png b/twake/frontend/public/public/emojione/32/1f361.png new file mode 100644 index 00000000..87736621 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f361.png differ diff --git a/twake/frontend/public/public/emojione/32/1f362.png b/twake/frontend/public/public/emojione/32/1f362.png new file mode 100644 index 00000000..f8d0f142 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f362.png differ diff --git a/twake/frontend/public/public/emojione/32/1f363.png b/twake/frontend/public/public/emojione/32/1f363.png new file mode 100644 index 00000000..501240da Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f363.png differ diff --git a/twake/frontend/public/public/emojione/32/1f364.png b/twake/frontend/public/public/emojione/32/1f364.png new file mode 100644 index 00000000..3515a99f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f364.png differ diff --git a/twake/frontend/public/public/emojione/32/1f365.png b/twake/frontend/public/public/emojione/32/1f365.png new file mode 100644 index 00000000..a5098111 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f365.png differ diff --git a/twake/frontend/public/public/emojione/32/1f366.png b/twake/frontend/public/public/emojione/32/1f366.png new file mode 100644 index 00000000..3dc96dbf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f366.png differ diff --git a/twake/frontend/public/public/emojione/32/1f367.png b/twake/frontend/public/public/emojione/32/1f367.png new file mode 100644 index 00000000..d89c4a5a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f367.png differ diff --git a/twake/frontend/public/public/emojione/32/1f368.png b/twake/frontend/public/public/emojione/32/1f368.png new file mode 100644 index 00000000..e15f7941 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f368.png differ diff --git a/twake/frontend/public/public/emojione/32/1f369.png b/twake/frontend/public/public/emojione/32/1f369.png new file mode 100644 index 00000000..49edf70d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f369.png differ diff --git a/twake/frontend/public/public/emojione/32/1f36a.png b/twake/frontend/public/public/emojione/32/1f36a.png new file mode 100644 index 00000000..846df901 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f36a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f36b.png b/twake/frontend/public/public/emojione/32/1f36b.png new file mode 100644 index 00000000..41503b63 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f36b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f36c.png b/twake/frontend/public/public/emojione/32/1f36c.png new file mode 100644 index 00000000..49986277 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f36c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f36d.png b/twake/frontend/public/public/emojione/32/1f36d.png new file mode 100644 index 00000000..9b3b3d30 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f36d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f36e.png b/twake/frontend/public/public/emojione/32/1f36e.png new file mode 100644 index 00000000..6574fc4d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f36e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f36f.png b/twake/frontend/public/public/emojione/32/1f36f.png new file mode 100644 index 00000000..67516d26 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f36f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f370.png b/twake/frontend/public/public/emojione/32/1f370.png new file mode 100644 index 00000000..8c7c908a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f370.png differ diff --git a/twake/frontend/public/public/emojione/32/1f371.png b/twake/frontend/public/public/emojione/32/1f371.png new file mode 100644 index 00000000..904db28d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f371.png differ diff --git a/twake/frontend/public/public/emojione/32/1f372.png b/twake/frontend/public/public/emojione/32/1f372.png new file mode 100644 index 00000000..2cc33d76 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f372.png differ diff --git a/twake/frontend/public/public/emojione/32/1f373.png b/twake/frontend/public/public/emojione/32/1f373.png new file mode 100644 index 00000000..2fe98d6f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f373.png differ diff --git a/twake/frontend/public/public/emojione/32/1f374.png b/twake/frontend/public/public/emojione/32/1f374.png new file mode 100644 index 00000000..4b5f6d69 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f374.png differ diff --git a/twake/frontend/public/public/emojione/32/1f375.png b/twake/frontend/public/public/emojione/32/1f375.png new file mode 100644 index 00000000..a243ce52 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f375.png differ diff --git a/twake/frontend/public/public/emojione/32/1f376.png b/twake/frontend/public/public/emojione/32/1f376.png new file mode 100644 index 00000000..ae79eac6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f376.png differ diff --git a/twake/frontend/public/public/emojione/32/1f377.png b/twake/frontend/public/public/emojione/32/1f377.png new file mode 100644 index 00000000..fa4ad8b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f377.png differ diff --git a/twake/frontend/public/public/emojione/32/1f378.png b/twake/frontend/public/public/emojione/32/1f378.png new file mode 100644 index 00000000..2186719c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f378.png differ diff --git a/twake/frontend/public/public/emojione/32/1f379.png b/twake/frontend/public/public/emojione/32/1f379.png new file mode 100644 index 00000000..d420004c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f379.png differ diff --git a/twake/frontend/public/public/emojione/32/1f37a.png b/twake/frontend/public/public/emojione/32/1f37a.png new file mode 100644 index 00000000..5dfbd551 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f37a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f37b.png b/twake/frontend/public/public/emojione/32/1f37b.png new file mode 100644 index 00000000..cf851ffb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f37b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f37c.png b/twake/frontend/public/public/emojione/32/1f37c.png new file mode 100644 index 00000000..0bd544e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f37c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f37d.png b/twake/frontend/public/public/emojione/32/1f37d.png new file mode 100644 index 00000000..9371d701 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f37d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f37e.png b/twake/frontend/public/public/emojione/32/1f37e.png new file mode 100644 index 00000000..114b14c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f37e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f37f.png b/twake/frontend/public/public/emojione/32/1f37f.png new file mode 100644 index 00000000..7765fb03 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f37f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f380.png b/twake/frontend/public/public/emojione/32/1f380.png new file mode 100644 index 00000000..bfcdab5b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f380.png differ diff --git a/twake/frontend/public/public/emojione/32/1f381.png b/twake/frontend/public/public/emojione/32/1f381.png new file mode 100644 index 00000000..6a6e1527 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f381.png differ diff --git a/twake/frontend/public/public/emojione/32/1f382.png b/twake/frontend/public/public/emojione/32/1f382.png new file mode 100644 index 00000000..dcb38f5c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f382.png differ diff --git a/twake/frontend/public/public/emojione/32/1f383.png b/twake/frontend/public/public/emojione/32/1f383.png new file mode 100644 index 00000000..8d908eca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f383.png differ diff --git a/twake/frontend/public/public/emojione/32/1f384.png b/twake/frontend/public/public/emojione/32/1f384.png new file mode 100644 index 00000000..85aaeb3f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f384.png differ diff --git a/twake/frontend/public/public/emojione/32/1f385-1f3fb.png b/twake/frontend/public/public/emojione/32/1f385-1f3fb.png new file mode 100644 index 00000000..84db692a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f385-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f385-1f3fc.png b/twake/frontend/public/public/emojione/32/1f385-1f3fc.png new file mode 100644 index 00000000..b38638bc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f385-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f385-1f3fd.png b/twake/frontend/public/public/emojione/32/1f385-1f3fd.png new file mode 100644 index 00000000..ca08dfab Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f385-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f385-1f3fe.png b/twake/frontend/public/public/emojione/32/1f385-1f3fe.png new file mode 100644 index 00000000..cb91cef2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f385-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f385-1f3ff.png b/twake/frontend/public/public/emojione/32/1f385-1f3ff.png new file mode 100644 index 00000000..88d53d48 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f385-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f385.png b/twake/frontend/public/public/emojione/32/1f385.png new file mode 100644 index 00000000..bc26d521 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f385.png differ diff --git a/twake/frontend/public/public/emojione/32/1f386.png b/twake/frontend/public/public/emojione/32/1f386.png new file mode 100644 index 00000000..364417a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f386.png differ diff --git a/twake/frontend/public/public/emojione/32/1f387.png b/twake/frontend/public/public/emojione/32/1f387.png new file mode 100644 index 00000000..b7c5a9fb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f387.png differ diff --git a/twake/frontend/public/public/emojione/32/1f388.png b/twake/frontend/public/public/emojione/32/1f388.png new file mode 100644 index 00000000..3f1c9947 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f388.png differ diff --git a/twake/frontend/public/public/emojione/32/1f389.png b/twake/frontend/public/public/emojione/32/1f389.png new file mode 100644 index 00000000..d0fd168d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f389.png differ diff --git a/twake/frontend/public/public/emojione/32/1f38a.png b/twake/frontend/public/public/emojione/32/1f38a.png new file mode 100644 index 00000000..ca5d9094 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f38a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f38b.png b/twake/frontend/public/public/emojione/32/1f38b.png new file mode 100644 index 00000000..be6d2ab9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f38b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f38c.png b/twake/frontend/public/public/emojione/32/1f38c.png new file mode 100644 index 00000000..2a3fc62c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f38c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f38d.png b/twake/frontend/public/public/emojione/32/1f38d.png new file mode 100644 index 00000000..08944185 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f38d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f38e.png b/twake/frontend/public/public/emojione/32/1f38e.png new file mode 100644 index 00000000..0fcc936d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f38e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f38f.png b/twake/frontend/public/public/emojione/32/1f38f.png new file mode 100644 index 00000000..973145af Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f38f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f390.png b/twake/frontend/public/public/emojione/32/1f390.png new file mode 100644 index 00000000..b26db1d3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f390.png differ diff --git a/twake/frontend/public/public/emojione/32/1f391.png b/twake/frontend/public/public/emojione/32/1f391.png new file mode 100644 index 00000000..74631e1e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f391.png differ diff --git a/twake/frontend/public/public/emojione/32/1f392.png b/twake/frontend/public/public/emojione/32/1f392.png new file mode 100644 index 00000000..d7a9b806 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f392.png differ diff --git a/twake/frontend/public/public/emojione/32/1f393.png b/twake/frontend/public/public/emojione/32/1f393.png new file mode 100644 index 00000000..4c2c5edf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f393.png differ diff --git a/twake/frontend/public/public/emojione/32/1f396.png b/twake/frontend/public/public/emojione/32/1f396.png new file mode 100644 index 00000000..d263b010 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f396.png differ diff --git a/twake/frontend/public/public/emojione/32/1f397.png b/twake/frontend/public/public/emojione/32/1f397.png new file mode 100644 index 00000000..8e807363 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f397.png differ diff --git a/twake/frontend/public/public/emojione/32/1f399.png b/twake/frontend/public/public/emojione/32/1f399.png new file mode 100644 index 00000000..77eb1a4a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f399.png differ diff --git a/twake/frontend/public/public/emojione/32/1f39a.png b/twake/frontend/public/public/emojione/32/1f39a.png new file mode 100644 index 00000000..8bca2878 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f39a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f39b.png b/twake/frontend/public/public/emojione/32/1f39b.png new file mode 100644 index 00000000..53922c37 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f39b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f39e.png b/twake/frontend/public/public/emojione/32/1f39e.png new file mode 100644 index 00000000..05ae3d38 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f39e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f39f.png b/twake/frontend/public/public/emojione/32/1f39f.png new file mode 100644 index 00000000..6fa4b2b6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f39f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3a0.png b/twake/frontend/public/public/emojione/32/1f3a0.png new file mode 100644 index 00000000..ffa3b4bf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3a0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3a1.png b/twake/frontend/public/public/emojione/32/1f3a1.png new file mode 100644 index 00000000..23f686f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3a1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3a2.png b/twake/frontend/public/public/emojione/32/1f3a2.png new file mode 100644 index 00000000..86d664e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3a2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3a3.png b/twake/frontend/public/public/emojione/32/1f3a3.png new file mode 100644 index 00000000..9427d149 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3a3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3a4.png b/twake/frontend/public/public/emojione/32/1f3a4.png new file mode 100644 index 00000000..ae1ea7d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3a5.png b/twake/frontend/public/public/emojione/32/1f3a5.png new file mode 100644 index 00000000..a232d3a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3a5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3a6.png b/twake/frontend/public/public/emojione/32/1f3a6.png new file mode 100644 index 00000000..6be638ff Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3a6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3a7.png b/twake/frontend/public/public/emojione/32/1f3a7.png new file mode 100644 index 00000000..263bc09d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3a7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3a8.png b/twake/frontend/public/public/emojione/32/1f3a8.png new file mode 100644 index 00000000..485846f3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3a9.png b/twake/frontend/public/public/emojione/32/1f3a9.png new file mode 100644 index 00000000..059fec43 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3a9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3aa.png b/twake/frontend/public/public/emojione/32/1f3aa.png new file mode 100644 index 00000000..1222b9f4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3aa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ab.png b/twake/frontend/public/public/emojione/32/1f3ab.png new file mode 100644 index 00000000..4fa45442 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ab.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ac.png b/twake/frontend/public/public/emojione/32/1f3ac.png new file mode 100644 index 00000000..cc3ae634 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ac.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ad.png b/twake/frontend/public/public/emojione/32/1f3ad.png new file mode 100644 index 00000000..159b79e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ad.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ae.png b/twake/frontend/public/public/emojione/32/1f3ae.png new file mode 100644 index 00000000..16e1e51d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ae.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3af.png b/twake/frontend/public/public/emojione/32/1f3af.png new file mode 100644 index 00000000..fedae17f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3af.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3b0.png b/twake/frontend/public/public/emojione/32/1f3b0.png new file mode 100644 index 00000000..d01f9bea Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3b0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3b1.png b/twake/frontend/public/public/emojione/32/1f3b1.png new file mode 100644 index 00000000..a20a2955 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3b1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3b2.png b/twake/frontend/public/public/emojione/32/1f3b2.png new file mode 100644 index 00000000..97e8930a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3b2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3b3.png b/twake/frontend/public/public/emojione/32/1f3b3.png new file mode 100644 index 00000000..f88228d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3b3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3b4.png b/twake/frontend/public/public/emojione/32/1f3b4.png new file mode 100644 index 00000000..d41df438 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3b4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3b5.png b/twake/frontend/public/public/emojione/32/1f3b5.png new file mode 100644 index 00000000..ba773474 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3b5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3b6.png b/twake/frontend/public/public/emojione/32/1f3b6.png new file mode 100644 index 00000000..bee758b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3b6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3b7.png b/twake/frontend/public/public/emojione/32/1f3b7.png new file mode 100644 index 00000000..190a7261 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3b7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3b8.png b/twake/frontend/public/public/emojione/32/1f3b8.png new file mode 100644 index 00000000..bc3b54c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3b8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3b9.png b/twake/frontend/public/public/emojione/32/1f3b9.png new file mode 100644 index 00000000..f30fe5a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3b9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ba.png b/twake/frontend/public/public/emojione/32/1f3ba.png new file mode 100644 index 00000000..7c0647a5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ba.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3bb.png b/twake/frontend/public/public/emojione/32/1f3bb.png new file mode 100644 index 00000000..d1f14c61 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3bb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3bc.png b/twake/frontend/public/public/emojione/32/1f3bc.png new file mode 100644 index 00000000..099372db Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3bc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3bd.png b/twake/frontend/public/public/emojione/32/1f3bd.png new file mode 100644 index 00000000..6f923ed2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3bd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3be.png b/twake/frontend/public/public/emojione/32/1f3be.png new file mode 100644 index 00000000..b30eb29a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3be.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3bf.png b/twake/frontend/public/public/emojione/32/1f3bf.png new file mode 100644 index 00000000..4413764a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3bf.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c0.png b/twake/frontend/public/public/emojione/32/1f3c0.png new file mode 100644 index 00000000..b9095f83 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c1.png b/twake/frontend/public/public/emojione/32/1f3c1.png new file mode 100644 index 00000000..7194a2a2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c2-1f3fb.png b/twake/frontend/public/public/emojione/32/1f3c2-1f3fb.png new file mode 100644 index 00000000..854faab9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c2-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c2-1f3fc.png b/twake/frontend/public/public/emojione/32/1f3c2-1f3fc.png new file mode 100644 index 00000000..f4f090a6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c2-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c2-1f3fd.png b/twake/frontend/public/public/emojione/32/1f3c2-1f3fd.png new file mode 100644 index 00000000..22e1fd87 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c2-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c2-1f3fe.png b/twake/frontend/public/public/emojione/32/1f3c2-1f3fe.png new file mode 100644 index 00000000..7b872e4d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c2-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c2-1f3ff.png b/twake/frontend/public/public/emojione/32/1f3c2-1f3ff.png new file mode 100644 index 00000000..ba662471 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c2-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c2.png b/twake/frontend/public/public/emojione/32/1f3c2.png new file mode 100644 index 00000000..58252357 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f3c3-1f3fb-2640.png new file mode 100644 index 00000000..d550c6cf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f3c3-1f3fb-2642.png new file mode 100644 index 00000000..95b7ab23 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3-1f3fb.png b/twake/frontend/public/public/emojione/32/1f3c3-1f3fb.png new file mode 100644 index 00000000..95b7ab23 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f3c3-1f3fc-2640.png new file mode 100644 index 00000000..1377ee7c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f3c3-1f3fc-2642.png new file mode 100644 index 00000000..b3e94b71 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3-1f3fc.png b/twake/frontend/public/public/emojione/32/1f3c3-1f3fc.png new file mode 100644 index 00000000..b3e94b71 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f3c3-1f3fd-2640.png new file mode 100644 index 00000000..6fa90c98 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f3c3-1f3fd-2642.png new file mode 100644 index 00000000..a9440677 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3-1f3fd.png b/twake/frontend/public/public/emojione/32/1f3c3-1f3fd.png new file mode 100644 index 00000000..a9440677 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f3c3-1f3fe-2640.png new file mode 100644 index 00000000..212f56bb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f3c3-1f3fe-2642.png new file mode 100644 index 00000000..d4615ae8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3-1f3fe.png b/twake/frontend/public/public/emojione/32/1f3c3-1f3fe.png new file mode 100644 index 00000000..d4615ae8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f3c3-1f3ff-2640.png new file mode 100644 index 00000000..7b4e29e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f3c3-1f3ff-2642.png new file mode 100644 index 00000000..0b508ae9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3-1f3ff.png b/twake/frontend/public/public/emojione/32/1f3c3-1f3ff.png new file mode 100644 index 00000000..0b508ae9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3-2640.png b/twake/frontend/public/public/emojione/32/1f3c3-2640.png new file mode 100644 index 00000000..a8c2ae7d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3-2642.png b/twake/frontend/public/public/emojione/32/1f3c3-2642.png new file mode 100644 index 00000000..a2c3b9f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c3.png b/twake/frontend/public/public/emojione/32/1f3c3.png new file mode 100644 index 00000000..a2c3b9f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f3c4-1f3fb-2640.png new file mode 100644 index 00000000..50da629a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f3c4-1f3fb-2642.png new file mode 100644 index 00000000..b4bcd6e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4-1f3fb.png b/twake/frontend/public/public/emojione/32/1f3c4-1f3fb.png new file mode 100644 index 00000000..b4bcd6e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f3c4-1f3fc-2640.png new file mode 100644 index 00000000..49dc7404 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f3c4-1f3fc-2642.png new file mode 100644 index 00000000..2ceab008 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4-1f3fc.png b/twake/frontend/public/public/emojione/32/1f3c4-1f3fc.png new file mode 100644 index 00000000..2ceab008 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f3c4-1f3fd-2640.png new file mode 100644 index 00000000..9b0c1691 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f3c4-1f3fd-2642.png new file mode 100644 index 00000000..462e2217 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4-1f3fd.png b/twake/frontend/public/public/emojione/32/1f3c4-1f3fd.png new file mode 100644 index 00000000..462e2217 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f3c4-1f3fe-2640.png new file mode 100644 index 00000000..d6f25532 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f3c4-1f3fe-2642.png new file mode 100644 index 00000000..d17d9f14 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4-1f3fe.png b/twake/frontend/public/public/emojione/32/1f3c4-1f3fe.png new file mode 100644 index 00000000..d17d9f14 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f3c4-1f3ff-2640.png new file mode 100644 index 00000000..b5fb5038 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f3c4-1f3ff-2642.png new file mode 100644 index 00000000..be36143b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4-1f3ff.png b/twake/frontend/public/public/emojione/32/1f3c4-1f3ff.png new file mode 100644 index 00000000..be36143b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4-2640.png b/twake/frontend/public/public/emojione/32/1f3c4-2640.png new file mode 100644 index 00000000..5d0aeb45 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4-2642.png b/twake/frontend/public/public/emojione/32/1f3c4-2642.png new file mode 100644 index 00000000..3cb68f51 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c4.png b/twake/frontend/public/public/emojione/32/1f3c4.png new file mode 100644 index 00000000..3cb68f51 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c5.png b/twake/frontend/public/public/emojione/32/1f3c5.png new file mode 100644 index 00000000..610d27ec Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c6.png b/twake/frontend/public/public/emojione/32/1f3c6.png new file mode 100644 index 00000000..7b33b675 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c7-1f3fb.png b/twake/frontend/public/public/emojione/32/1f3c7-1f3fb.png new file mode 100644 index 00000000..ce39b374 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c7-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c7-1f3fc.png b/twake/frontend/public/public/emojione/32/1f3c7-1f3fc.png new file mode 100644 index 00000000..dd7d4301 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c7-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c7-1f3fd.png b/twake/frontend/public/public/emojione/32/1f3c7-1f3fd.png new file mode 100644 index 00000000..939aabc0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c7-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c7-1f3fe.png b/twake/frontend/public/public/emojione/32/1f3c7-1f3fe.png new file mode 100644 index 00000000..3159b390 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c7-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c7-1f3ff.png b/twake/frontend/public/public/emojione/32/1f3c7-1f3ff.png new file mode 100644 index 00000000..601187cc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c7-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c7.png b/twake/frontend/public/public/emojione/32/1f3c7.png new file mode 100644 index 00000000..aca0c4c9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c8.png b/twake/frontend/public/public/emojione/32/1f3c8.png new file mode 100644 index 00000000..6992ffee Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3c9.png b/twake/frontend/public/public/emojione/32/1f3c9.png new file mode 100644 index 00000000..fdf03d1b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3c9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f3ca-1f3fb-2640.png new file mode 100644 index 00000000..cef882ae Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f3ca-1f3fb-2642.png new file mode 100644 index 00000000..7aa1009c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca-1f3fb.png b/twake/frontend/public/public/emojione/32/1f3ca-1f3fb.png new file mode 100644 index 00000000..7aa1009c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f3ca-1f3fc-2640.png new file mode 100644 index 00000000..63ae0baa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f3ca-1f3fc-2642.png new file mode 100644 index 00000000..1f172809 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca-1f3fc.png b/twake/frontend/public/public/emojione/32/1f3ca-1f3fc.png new file mode 100644 index 00000000..1f172809 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f3ca-1f3fd-2640.png new file mode 100644 index 00000000..492c4696 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f3ca-1f3fd-2642.png new file mode 100644 index 00000000..5981970a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca-1f3fd.png b/twake/frontend/public/public/emojione/32/1f3ca-1f3fd.png new file mode 100644 index 00000000..5981970a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f3ca-1f3fe-2640.png new file mode 100644 index 00000000..afcb9118 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f3ca-1f3fe-2642.png new file mode 100644 index 00000000..e457a8e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca-1f3fe.png b/twake/frontend/public/public/emojione/32/1f3ca-1f3fe.png new file mode 100644 index 00000000..e457a8e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f3ca-1f3ff-2640.png new file mode 100644 index 00000000..273da6ef Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f3ca-1f3ff-2642.png new file mode 100644 index 00000000..dee09d21 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca-1f3ff.png b/twake/frontend/public/public/emojione/32/1f3ca-1f3ff.png new file mode 100644 index 00000000..dee09d21 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca-2640.png b/twake/frontend/public/public/emojione/32/1f3ca-2640.png new file mode 100644 index 00000000..3a6988c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca-2642.png b/twake/frontend/public/public/emojione/32/1f3ca-2642.png new file mode 100644 index 00000000..ec2f307b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ca.png b/twake/frontend/public/public/emojione/32/1f3ca.png new file mode 100644 index 00000000..ec2f307b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ca.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f3cb-1f3fb-2640.png new file mode 100644 index 00000000..74ecb743 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f3cb-1f3fb-2642.png new file mode 100644 index 00000000..92389822 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb-1f3fb.png b/twake/frontend/public/public/emojione/32/1f3cb-1f3fb.png new file mode 100644 index 00000000..92389822 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f3cb-1f3fc-2640.png new file mode 100644 index 00000000..e84818eb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f3cb-1f3fc-2642.png new file mode 100644 index 00000000..d171c9ef Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb-1f3fc.png b/twake/frontend/public/public/emojione/32/1f3cb-1f3fc.png new file mode 100644 index 00000000..d171c9ef Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f3cb-1f3fd-2640.png new file mode 100644 index 00000000..9dbd7eef Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f3cb-1f3fd-2642.png new file mode 100644 index 00000000..5f3382b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb-1f3fd.png b/twake/frontend/public/public/emojione/32/1f3cb-1f3fd.png new file mode 100644 index 00000000..5f3382b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f3cb-1f3fe-2640.png new file mode 100644 index 00000000..1b944e21 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f3cb-1f3fe-2642.png new file mode 100644 index 00000000..7ed965c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb-1f3fe.png b/twake/frontend/public/public/emojione/32/1f3cb-1f3fe.png new file mode 100644 index 00000000..7ed965c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f3cb-1f3ff-2640.png new file mode 100644 index 00000000..2d3c6b68 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f3cb-1f3ff-2642.png new file mode 100644 index 00000000..5e029f45 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb-1f3ff.png b/twake/frontend/public/public/emojione/32/1f3cb-1f3ff.png new file mode 100644 index 00000000..5e029f45 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb-2640.png b/twake/frontend/public/public/emojione/32/1f3cb-2640.png new file mode 100644 index 00000000..4b4df405 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb-2642.png b/twake/frontend/public/public/emojione/32/1f3cb-2642.png new file mode 100644 index 00000000..c010a154 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cb.png b/twake/frontend/public/public/emojione/32/1f3cb.png new file mode 100644 index 00000000..c010a154 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f3cc-1f3fb-2640.png new file mode 100644 index 00000000..ca5b7fe8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f3cc-1f3fb-2642.png new file mode 100644 index 00000000..e5b3e339 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc-1f3fb.png b/twake/frontend/public/public/emojione/32/1f3cc-1f3fb.png new file mode 100644 index 00000000..e5b3e339 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f3cc-1f3fc-2640.png new file mode 100644 index 00000000..efd067e4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f3cc-1f3fc-2642.png new file mode 100644 index 00000000..5d8744ae Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc-1f3fc.png b/twake/frontend/public/public/emojione/32/1f3cc-1f3fc.png new file mode 100644 index 00000000..5d8744ae Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f3cc-1f3fd-2640.png new file mode 100644 index 00000000..c3ad6223 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f3cc-1f3fd-2642.png new file mode 100644 index 00000000..cec58134 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc-1f3fd.png b/twake/frontend/public/public/emojione/32/1f3cc-1f3fd.png new file mode 100644 index 00000000..cec58134 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f3cc-1f3fe-2640.png new file mode 100644 index 00000000..2b833b7e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f3cc-1f3fe-2642.png new file mode 100644 index 00000000..7818aa19 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc-1f3fe.png b/twake/frontend/public/public/emojione/32/1f3cc-1f3fe.png new file mode 100644 index 00000000..7818aa19 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f3cc-1f3ff-2640.png new file mode 100644 index 00000000..e57bd672 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f3cc-1f3ff-2642.png new file mode 100644 index 00000000..3a067ef0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc-1f3ff.png b/twake/frontend/public/public/emojione/32/1f3cc-1f3ff.png new file mode 100644 index 00000000..3a067ef0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc-2640.png b/twake/frontend/public/public/emojione/32/1f3cc-2640.png new file mode 100644 index 00000000..a8b34e65 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc-2642.png b/twake/frontend/public/public/emojione/32/1f3cc-2642.png new file mode 100644 index 00000000..e4529cf5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cc.png b/twake/frontend/public/public/emojione/32/1f3cc.png new file mode 100644 index 00000000..e4529cf5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cd.png b/twake/frontend/public/public/emojione/32/1f3cd.png new file mode 100644 index 00000000..7b2a62fa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ce.png b/twake/frontend/public/public/emojione/32/1f3ce.png new file mode 100644 index 00000000..3f78e8e4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ce.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3cf.png b/twake/frontend/public/public/emojione/32/1f3cf.png new file mode 100644 index 00000000..db1d90e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3cf.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3d0.png b/twake/frontend/public/public/emojione/32/1f3d0.png new file mode 100644 index 00000000..856148eb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3d0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3d1.png b/twake/frontend/public/public/emojione/32/1f3d1.png new file mode 100644 index 00000000..700356a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3d1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3d2.png b/twake/frontend/public/public/emojione/32/1f3d2.png new file mode 100644 index 00000000..8114cfa2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3d2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3d3.png b/twake/frontend/public/public/emojione/32/1f3d3.png new file mode 100644 index 00000000..66d4a103 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3d3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3d4.png b/twake/frontend/public/public/emojione/32/1f3d4.png new file mode 100644 index 00000000..3b671806 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3d4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3d5.png b/twake/frontend/public/public/emojione/32/1f3d5.png new file mode 100644 index 00000000..dca0d266 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3d5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3d6.png b/twake/frontend/public/public/emojione/32/1f3d6.png new file mode 100644 index 00000000..f845098b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3d6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3d7.png b/twake/frontend/public/public/emojione/32/1f3d7.png new file mode 100644 index 00000000..f461ac2e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3d7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3d8.png b/twake/frontend/public/public/emojione/32/1f3d8.png new file mode 100644 index 00000000..e9eb333e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3d8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3d9.png b/twake/frontend/public/public/emojione/32/1f3d9.png new file mode 100644 index 00000000..dec43be7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3d9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3da.png b/twake/frontend/public/public/emojione/32/1f3da.png new file mode 100644 index 00000000..33e636fd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3da.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3db.png b/twake/frontend/public/public/emojione/32/1f3db.png new file mode 100644 index 00000000..8c78b160 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3db.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3dc.png b/twake/frontend/public/public/emojione/32/1f3dc.png new file mode 100644 index 00000000..3a6524d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3dc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3dd.png b/twake/frontend/public/public/emojione/32/1f3dd.png new file mode 100644 index 00000000..63cda5f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3dd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3de.png b/twake/frontend/public/public/emojione/32/1f3de.png new file mode 100644 index 00000000..8739e403 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3de.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3df.png b/twake/frontend/public/public/emojione/32/1f3df.png new file mode 100644 index 00000000..350085fc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3df.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3e0.png b/twake/frontend/public/public/emojione/32/1f3e0.png new file mode 100644 index 00000000..ae9e42d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3e0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3e1.png b/twake/frontend/public/public/emojione/32/1f3e1.png new file mode 100644 index 00000000..990eb06b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3e1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3e2.png b/twake/frontend/public/public/emojione/32/1f3e2.png new file mode 100644 index 00000000..43116005 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3e2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3e3.png b/twake/frontend/public/public/emojione/32/1f3e3.png new file mode 100644 index 00000000..3ca71934 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3e3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3e4.png b/twake/frontend/public/public/emojione/32/1f3e4.png new file mode 100644 index 00000000..40797b5f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3e4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3e5.png b/twake/frontend/public/public/emojione/32/1f3e5.png new file mode 100644 index 00000000..e504d6f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3e5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3e6.png b/twake/frontend/public/public/emojione/32/1f3e6.png new file mode 100644 index 00000000..5dbdcb8f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3e7.png b/twake/frontend/public/public/emojione/32/1f3e7.png new file mode 100644 index 00000000..293f87bf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3e7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3e8.png b/twake/frontend/public/public/emojione/32/1f3e8.png new file mode 100644 index 00000000..47a8ab66 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3e8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3e9.png b/twake/frontend/public/public/emojione/32/1f3e9.png new file mode 100644 index 00000000..b1e12309 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3e9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ea.png b/twake/frontend/public/public/emojione/32/1f3ea.png new file mode 100644 index 00000000..bcf05901 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3eb.png b/twake/frontend/public/public/emojione/32/1f3eb.png new file mode 100644 index 00000000..03e8ece1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ec.png b/twake/frontend/public/public/emojione/32/1f3ec.png new file mode 100644 index 00000000..ff3acd9b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ed.png b/twake/frontend/public/public/emojione/32/1f3ed.png new file mode 100644 index 00000000..50bb9482 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ee.png b/twake/frontend/public/public/emojione/32/1f3ee.png new file mode 100644 index 00000000..2892ad4b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ee.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ef.png b/twake/frontend/public/public/emojione/32/1f3ef.png new file mode 100644 index 00000000..1f150408 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ef.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3f0.png b/twake/frontend/public/public/emojione/32/1f3f0.png new file mode 100644 index 00000000..0d411494 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3f0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3f3-1f308.png b/twake/frontend/public/public/emojione/32/1f3f3-1f308.png new file mode 100644 index 00000000..14accf2a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3f3-1f308.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3f3.png b/twake/frontend/public/public/emojione/32/1f3f3.png new file mode 100644 index 00000000..e94213f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3f4-2620.png b/twake/frontend/public/public/emojione/32/1f3f4-2620.png new file mode 100644 index 00000000..e7edd17e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3f4-2620.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png b/twake/frontend/public/public/emojione/32/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png new file mode 100644 index 00000000..194d3fc2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png b/twake/frontend/public/public/emojione/32/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png new file mode 100644 index 00000000..47cdc54d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png b/twake/frontend/public/public/emojione/32/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png new file mode 100644 index 00000000..5055fbff Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3f4.png b/twake/frontend/public/public/emojione/32/1f3f4.png new file mode 100644 index 00000000..41bf449d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3f4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3f5.png b/twake/frontend/public/public/emojione/32/1f3f5.png new file mode 100644 index 00000000..2b4da066 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3f5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3f7.png b/twake/frontend/public/public/emojione/32/1f3f7.png new file mode 100644 index 00000000..35643640 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3f8.png b/twake/frontend/public/public/emojione/32/1f3f8.png new file mode 100644 index 00000000..de3c35a8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3f8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3f9.png b/twake/frontend/public/public/emojione/32/1f3f9.png new file mode 100644 index 00000000..c45f4547 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3f9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3fa.png b/twake/frontend/public/public/emojione/32/1f3fa.png new file mode 100644 index 00000000..9dc2b7be Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3fa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3fb.png b/twake/frontend/public/public/emojione/32/1f3fb.png new file mode 100644 index 00000000..2b4d0687 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3fc.png b/twake/frontend/public/public/emojione/32/1f3fc.png new file mode 100644 index 00000000..f16e0196 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3fd.png b/twake/frontend/public/public/emojione/32/1f3fd.png new file mode 100644 index 00000000..788b3d9b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3fe.png b/twake/frontend/public/public/emojione/32/1f3fe.png new file mode 100644 index 00000000..801c055f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f3ff.png b/twake/frontend/public/public/emojione/32/1f3ff.png new file mode 100644 index 00000000..a887d45f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f400.png b/twake/frontend/public/public/emojione/32/1f400.png new file mode 100644 index 00000000..a600ab11 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f400.png differ diff --git a/twake/frontend/public/public/emojione/32/1f401.png b/twake/frontend/public/public/emojione/32/1f401.png new file mode 100644 index 00000000..1e5c5b2e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f401.png differ diff --git a/twake/frontend/public/public/emojione/32/1f402.png b/twake/frontend/public/public/emojione/32/1f402.png new file mode 100644 index 00000000..3052d05d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f402.png differ diff --git a/twake/frontend/public/public/emojione/32/1f403.png b/twake/frontend/public/public/emojione/32/1f403.png new file mode 100644 index 00000000..b658d78f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f403.png differ diff --git a/twake/frontend/public/public/emojione/32/1f404.png b/twake/frontend/public/public/emojione/32/1f404.png new file mode 100644 index 00000000..dbcbaf96 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f404.png differ diff --git a/twake/frontend/public/public/emojione/32/1f405.png b/twake/frontend/public/public/emojione/32/1f405.png new file mode 100644 index 00000000..935db459 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f405.png differ diff --git a/twake/frontend/public/public/emojione/32/1f406.png b/twake/frontend/public/public/emojione/32/1f406.png new file mode 100644 index 00000000..a4d77173 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f406.png differ diff --git a/twake/frontend/public/public/emojione/32/1f407.png b/twake/frontend/public/public/emojione/32/1f407.png new file mode 100644 index 00000000..5c9dd0b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f407.png differ diff --git a/twake/frontend/public/public/emojione/32/1f408.png b/twake/frontend/public/public/emojione/32/1f408.png new file mode 100644 index 00000000..ddec64c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f408.png differ diff --git a/twake/frontend/public/public/emojione/32/1f409.png b/twake/frontend/public/public/emojione/32/1f409.png new file mode 100644 index 00000000..e9688328 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f409.png differ diff --git a/twake/frontend/public/public/emojione/32/1f40a.png b/twake/frontend/public/public/emojione/32/1f40a.png new file mode 100644 index 00000000..7819c87d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f40a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f40b.png b/twake/frontend/public/public/emojione/32/1f40b.png new file mode 100644 index 00000000..477c2c69 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f40b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f40c.png b/twake/frontend/public/public/emojione/32/1f40c.png new file mode 100644 index 00000000..fb6768f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f40c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f40d.png b/twake/frontend/public/public/emojione/32/1f40d.png new file mode 100644 index 00000000..c1e3c684 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f40d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f40e.png b/twake/frontend/public/public/emojione/32/1f40e.png new file mode 100644 index 00000000..8479cc0e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f40e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f40f.png b/twake/frontend/public/public/emojione/32/1f40f.png new file mode 100644 index 00000000..18a058c4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f40f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f410.png b/twake/frontend/public/public/emojione/32/1f410.png new file mode 100644 index 00000000..460c481c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f410.png differ diff --git a/twake/frontend/public/public/emojione/32/1f411.png b/twake/frontend/public/public/emojione/32/1f411.png new file mode 100644 index 00000000..f33841b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f411.png differ diff --git a/twake/frontend/public/public/emojione/32/1f412.png b/twake/frontend/public/public/emojione/32/1f412.png new file mode 100644 index 00000000..bd5876f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f412.png differ diff --git a/twake/frontend/public/public/emojione/32/1f413.png b/twake/frontend/public/public/emojione/32/1f413.png new file mode 100644 index 00000000..762637b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f413.png differ diff --git a/twake/frontend/public/public/emojione/32/1f414.png b/twake/frontend/public/public/emojione/32/1f414.png new file mode 100644 index 00000000..d1f465de Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f414.png differ diff --git a/twake/frontend/public/public/emojione/32/1f415.png b/twake/frontend/public/public/emojione/32/1f415.png new file mode 100644 index 00000000..dd70a7a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f415.png differ diff --git a/twake/frontend/public/public/emojione/32/1f416.png b/twake/frontend/public/public/emojione/32/1f416.png new file mode 100644 index 00000000..ff2e2995 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f416.png differ diff --git a/twake/frontend/public/public/emojione/32/1f417.png b/twake/frontend/public/public/emojione/32/1f417.png new file mode 100644 index 00000000..50031a55 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f417.png differ diff --git a/twake/frontend/public/public/emojione/32/1f418.png b/twake/frontend/public/public/emojione/32/1f418.png new file mode 100644 index 00000000..8299f40d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f418.png differ diff --git a/twake/frontend/public/public/emojione/32/1f419.png b/twake/frontend/public/public/emojione/32/1f419.png new file mode 100644 index 00000000..b95a5815 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f419.png differ diff --git a/twake/frontend/public/public/emojione/32/1f41a.png b/twake/frontend/public/public/emojione/32/1f41a.png new file mode 100644 index 00000000..a9474682 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f41a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f41b.png b/twake/frontend/public/public/emojione/32/1f41b.png new file mode 100644 index 00000000..b0423188 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f41b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f41c.png b/twake/frontend/public/public/emojione/32/1f41c.png new file mode 100644 index 00000000..a32ed719 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f41c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f41d.png b/twake/frontend/public/public/emojione/32/1f41d.png new file mode 100644 index 00000000..da3ae7cd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f41d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f41e.png b/twake/frontend/public/public/emojione/32/1f41e.png new file mode 100644 index 00000000..b8230f6a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f41e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f41f.png b/twake/frontend/public/public/emojione/32/1f41f.png new file mode 100644 index 00000000..dd2a1c5b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f41f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f420.png b/twake/frontend/public/public/emojione/32/1f420.png new file mode 100644 index 00000000..5800df26 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f420.png differ diff --git a/twake/frontend/public/public/emojione/32/1f421.png b/twake/frontend/public/public/emojione/32/1f421.png new file mode 100644 index 00000000..50041d1a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f421.png differ diff --git a/twake/frontend/public/public/emojione/32/1f422.png b/twake/frontend/public/public/emojione/32/1f422.png new file mode 100644 index 00000000..9ea8634d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f422.png differ diff --git a/twake/frontend/public/public/emojione/32/1f423.png b/twake/frontend/public/public/emojione/32/1f423.png new file mode 100644 index 00000000..62a78208 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f423.png differ diff --git a/twake/frontend/public/public/emojione/32/1f424.png b/twake/frontend/public/public/emojione/32/1f424.png new file mode 100644 index 00000000..b7898a20 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f424.png differ diff --git a/twake/frontend/public/public/emojione/32/1f425.png b/twake/frontend/public/public/emojione/32/1f425.png new file mode 100644 index 00000000..4b06d453 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f425.png differ diff --git a/twake/frontend/public/public/emojione/32/1f426.png b/twake/frontend/public/public/emojione/32/1f426.png new file mode 100644 index 00000000..dc2b2810 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f426.png differ diff --git a/twake/frontend/public/public/emojione/32/1f427.png b/twake/frontend/public/public/emojione/32/1f427.png new file mode 100644 index 00000000..22437d0a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f427.png differ diff --git a/twake/frontend/public/public/emojione/32/1f428.png b/twake/frontend/public/public/emojione/32/1f428.png new file mode 100644 index 00000000..9b7e6884 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f428.png differ diff --git a/twake/frontend/public/public/emojione/32/1f429.png b/twake/frontend/public/public/emojione/32/1f429.png new file mode 100644 index 00000000..b25ea47a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f429.png differ diff --git a/twake/frontend/public/public/emojione/32/1f42a.png b/twake/frontend/public/public/emojione/32/1f42a.png new file mode 100644 index 00000000..d9c62329 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f42a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f42b.png b/twake/frontend/public/public/emojione/32/1f42b.png new file mode 100644 index 00000000..c532a3c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f42b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f42c.png b/twake/frontend/public/public/emojione/32/1f42c.png new file mode 100644 index 00000000..e199371b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f42c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f42d.png b/twake/frontend/public/public/emojione/32/1f42d.png new file mode 100644 index 00000000..31960519 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f42d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f42e.png b/twake/frontend/public/public/emojione/32/1f42e.png new file mode 100644 index 00000000..81e7ebc6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f42e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f42f.png b/twake/frontend/public/public/emojione/32/1f42f.png new file mode 100644 index 00000000..c0af9519 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f42f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f430.png b/twake/frontend/public/public/emojione/32/1f430.png new file mode 100644 index 00000000..545b3015 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f430.png differ diff --git a/twake/frontend/public/public/emojione/32/1f431.png b/twake/frontend/public/public/emojione/32/1f431.png new file mode 100644 index 00000000..ec08f258 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f431.png differ diff --git a/twake/frontend/public/public/emojione/32/1f432.png b/twake/frontend/public/public/emojione/32/1f432.png new file mode 100644 index 00000000..44904a6a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f432.png differ diff --git a/twake/frontend/public/public/emojione/32/1f433.png b/twake/frontend/public/public/emojione/32/1f433.png new file mode 100644 index 00000000..93a46b1a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f433.png differ diff --git a/twake/frontend/public/public/emojione/32/1f434.png b/twake/frontend/public/public/emojione/32/1f434.png new file mode 100644 index 00000000..7290eaea Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f434.png differ diff --git a/twake/frontend/public/public/emojione/32/1f435.png b/twake/frontend/public/public/emojione/32/1f435.png new file mode 100644 index 00000000..3c6a61fd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f435.png differ diff --git a/twake/frontend/public/public/emojione/32/1f436.png b/twake/frontend/public/public/emojione/32/1f436.png new file mode 100644 index 00000000..e59b7cb5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f436.png differ diff --git a/twake/frontend/public/public/emojione/32/1f437.png b/twake/frontend/public/public/emojione/32/1f437.png new file mode 100644 index 00000000..2f2b6269 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f437.png differ diff --git a/twake/frontend/public/public/emojione/32/1f438.png b/twake/frontend/public/public/emojione/32/1f438.png new file mode 100644 index 00000000..f87e7600 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f438.png differ diff --git a/twake/frontend/public/public/emojione/32/1f439.png b/twake/frontend/public/public/emojione/32/1f439.png new file mode 100644 index 00000000..9ef7664a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f439.png differ diff --git a/twake/frontend/public/public/emojione/32/1f43a.png b/twake/frontend/public/public/emojione/32/1f43a.png new file mode 100644 index 00000000..33b9f107 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f43a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f43b.png b/twake/frontend/public/public/emojione/32/1f43b.png new file mode 100644 index 00000000..03732570 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f43b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f43c.png b/twake/frontend/public/public/emojione/32/1f43c.png new file mode 100644 index 00000000..77c105c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f43c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f43d.png b/twake/frontend/public/public/emojione/32/1f43d.png new file mode 100644 index 00000000..05e3be72 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f43d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f43e.png b/twake/frontend/public/public/emojione/32/1f43e.png new file mode 100644 index 00000000..efa47b6c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f43e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f43f.png b/twake/frontend/public/public/emojione/32/1f43f.png new file mode 100644 index 00000000..437b2039 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f43f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f440.png b/twake/frontend/public/public/emojione/32/1f440.png new file mode 100644 index 00000000..012c6a21 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f440.png differ diff --git a/twake/frontend/public/public/emojione/32/1f441-1f5e8.png b/twake/frontend/public/public/emojione/32/1f441-1f5e8.png new file mode 100644 index 00000000..f2cac155 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f441-1f5e8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f441.png b/twake/frontend/public/public/emojione/32/1f441.png new file mode 100644 index 00000000..1c713c68 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f441.png differ diff --git a/twake/frontend/public/public/emojione/32/1f442-1f3fb.png b/twake/frontend/public/public/emojione/32/1f442-1f3fb.png new file mode 100644 index 00000000..5da6379d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f442-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f442-1f3fc.png b/twake/frontend/public/public/emojione/32/1f442-1f3fc.png new file mode 100644 index 00000000..106614b9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f442-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f442-1f3fd.png b/twake/frontend/public/public/emojione/32/1f442-1f3fd.png new file mode 100644 index 00000000..57351e98 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f442-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f442-1f3fe.png b/twake/frontend/public/public/emojione/32/1f442-1f3fe.png new file mode 100644 index 00000000..a0928e02 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f442-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f442-1f3ff.png b/twake/frontend/public/public/emojione/32/1f442-1f3ff.png new file mode 100644 index 00000000..0197c116 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f442-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f442.png b/twake/frontend/public/public/emojione/32/1f442.png new file mode 100644 index 00000000..4f14bf43 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f442.png differ diff --git a/twake/frontend/public/public/emojione/32/1f443-1f3fb.png b/twake/frontend/public/public/emojione/32/1f443-1f3fb.png new file mode 100644 index 00000000..913bef9f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f443-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f443-1f3fc.png b/twake/frontend/public/public/emojione/32/1f443-1f3fc.png new file mode 100644 index 00000000..ae685617 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f443-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f443-1f3fd.png b/twake/frontend/public/public/emojione/32/1f443-1f3fd.png new file mode 100644 index 00000000..1c7c1e86 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f443-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f443-1f3fe.png b/twake/frontend/public/public/emojione/32/1f443-1f3fe.png new file mode 100644 index 00000000..ce928bcc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f443-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f443-1f3ff.png b/twake/frontend/public/public/emojione/32/1f443-1f3ff.png new file mode 100644 index 00000000..d5b02b00 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f443-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f443.png b/twake/frontend/public/public/emojione/32/1f443.png new file mode 100644 index 00000000..0db6ab32 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f443.png differ diff --git a/twake/frontend/public/public/emojione/32/1f444.png b/twake/frontend/public/public/emojione/32/1f444.png new file mode 100644 index 00000000..a35a2265 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f444.png differ diff --git a/twake/frontend/public/public/emojione/32/1f445.png b/twake/frontend/public/public/emojione/32/1f445.png new file mode 100644 index 00000000..7d75231a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f445.png differ diff --git a/twake/frontend/public/public/emojione/32/1f446-1f3fb.png b/twake/frontend/public/public/emojione/32/1f446-1f3fb.png new file mode 100644 index 00000000..395eb6bb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f446-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f446-1f3fc.png b/twake/frontend/public/public/emojione/32/1f446-1f3fc.png new file mode 100644 index 00000000..895fe760 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f446-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f446-1f3fd.png b/twake/frontend/public/public/emojione/32/1f446-1f3fd.png new file mode 100644 index 00000000..0a10fce7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f446-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f446-1f3fe.png b/twake/frontend/public/public/emojione/32/1f446-1f3fe.png new file mode 100644 index 00000000..c9dbc569 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f446-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f446-1f3ff.png b/twake/frontend/public/public/emojione/32/1f446-1f3ff.png new file mode 100644 index 00000000..94cb4474 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f446-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f446.png b/twake/frontend/public/public/emojione/32/1f446.png new file mode 100644 index 00000000..e39d82ef Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f446.png differ diff --git a/twake/frontend/public/public/emojione/32/1f447-1f3fb.png b/twake/frontend/public/public/emojione/32/1f447-1f3fb.png new file mode 100644 index 00000000..2fb45a14 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f447-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f447-1f3fc.png b/twake/frontend/public/public/emojione/32/1f447-1f3fc.png new file mode 100644 index 00000000..9bf5e027 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f447-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f447-1f3fd.png b/twake/frontend/public/public/emojione/32/1f447-1f3fd.png new file mode 100644 index 00000000..0d48bdc0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f447-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f447-1f3fe.png b/twake/frontend/public/public/emojione/32/1f447-1f3fe.png new file mode 100644 index 00000000..0c0cf2db Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f447-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f447-1f3ff.png b/twake/frontend/public/public/emojione/32/1f447-1f3ff.png new file mode 100644 index 00000000..2e7ab4b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f447-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f447.png b/twake/frontend/public/public/emojione/32/1f447.png new file mode 100644 index 00000000..61d3c26c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f447.png differ diff --git a/twake/frontend/public/public/emojione/32/1f448-1f3fb.png b/twake/frontend/public/public/emojione/32/1f448-1f3fb.png new file mode 100644 index 00000000..89ad3d13 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f448-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f448-1f3fc.png b/twake/frontend/public/public/emojione/32/1f448-1f3fc.png new file mode 100644 index 00000000..a29e0e3e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f448-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f448-1f3fd.png b/twake/frontend/public/public/emojione/32/1f448-1f3fd.png new file mode 100644 index 00000000..589d52bc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f448-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f448-1f3fe.png b/twake/frontend/public/public/emojione/32/1f448-1f3fe.png new file mode 100644 index 00000000..647dc816 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f448-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f448-1f3ff.png b/twake/frontend/public/public/emojione/32/1f448-1f3ff.png new file mode 100644 index 00000000..845a7b07 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f448-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f448.png b/twake/frontend/public/public/emojione/32/1f448.png new file mode 100644 index 00000000..7846595d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f448.png differ diff --git a/twake/frontend/public/public/emojione/32/1f449-1f3fb.png b/twake/frontend/public/public/emojione/32/1f449-1f3fb.png new file mode 100644 index 00000000..48c31399 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f449-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f449-1f3fc.png b/twake/frontend/public/public/emojione/32/1f449-1f3fc.png new file mode 100644 index 00000000..d36bd9f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f449-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f449-1f3fd.png b/twake/frontend/public/public/emojione/32/1f449-1f3fd.png new file mode 100644 index 00000000..397d24d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f449-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f449-1f3fe.png b/twake/frontend/public/public/emojione/32/1f449-1f3fe.png new file mode 100644 index 00000000..7a6ff58d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f449-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f449-1f3ff.png b/twake/frontend/public/public/emojione/32/1f449-1f3ff.png new file mode 100644 index 00000000..7b73a318 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f449-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f449.png b/twake/frontend/public/public/emojione/32/1f449.png new file mode 100644 index 00000000..5f158b39 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f449.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44a-1f3fb.png b/twake/frontend/public/public/emojione/32/1f44a-1f3fb.png new file mode 100644 index 00000000..7a6a1bbb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44a-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44a-1f3fc.png b/twake/frontend/public/public/emojione/32/1f44a-1f3fc.png new file mode 100644 index 00000000..2c20cb73 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44a-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44a-1f3fd.png b/twake/frontend/public/public/emojione/32/1f44a-1f3fd.png new file mode 100644 index 00000000..aff0d521 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44a-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44a-1f3fe.png b/twake/frontend/public/public/emojione/32/1f44a-1f3fe.png new file mode 100644 index 00000000..c4c1ea95 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44a-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44a-1f3ff.png b/twake/frontend/public/public/emojione/32/1f44a-1f3ff.png new file mode 100644 index 00000000..e5cac015 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44a-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44a.png b/twake/frontend/public/public/emojione/32/1f44a.png new file mode 100644 index 00000000..be3f1d5f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44b-1f3fb.png b/twake/frontend/public/public/emojione/32/1f44b-1f3fb.png new file mode 100644 index 00000000..80453d4b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44b-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44b-1f3fc.png b/twake/frontend/public/public/emojione/32/1f44b-1f3fc.png new file mode 100644 index 00000000..c23bb272 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44b-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44b-1f3fd.png b/twake/frontend/public/public/emojione/32/1f44b-1f3fd.png new file mode 100644 index 00000000..01d984d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44b-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44b-1f3fe.png b/twake/frontend/public/public/emojione/32/1f44b-1f3fe.png new file mode 100644 index 00000000..86641f57 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44b-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44b-1f3ff.png b/twake/frontend/public/public/emojione/32/1f44b-1f3ff.png new file mode 100644 index 00000000..1d8e1553 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44b-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44b.png b/twake/frontend/public/public/emojione/32/1f44b.png new file mode 100644 index 00000000..4d7b3458 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44c-1f3fb.png b/twake/frontend/public/public/emojione/32/1f44c-1f3fb.png new file mode 100644 index 00000000..778db2c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44c-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44c-1f3fc.png b/twake/frontend/public/public/emojione/32/1f44c-1f3fc.png new file mode 100644 index 00000000..87564a7e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44c-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44c-1f3fd.png b/twake/frontend/public/public/emojione/32/1f44c-1f3fd.png new file mode 100644 index 00000000..215a3fc0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44c-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44c-1f3fe.png b/twake/frontend/public/public/emojione/32/1f44c-1f3fe.png new file mode 100644 index 00000000..89c3bd63 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44c-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44c-1f3ff.png b/twake/frontend/public/public/emojione/32/1f44c-1f3ff.png new file mode 100644 index 00000000..7fd55e5d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44c-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44c.png b/twake/frontend/public/public/emojione/32/1f44c.png new file mode 100644 index 00000000..049571e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44d-1f3fb.png b/twake/frontend/public/public/emojione/32/1f44d-1f3fb.png new file mode 100644 index 00000000..4b3e9a58 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44d-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44d-1f3fc.png b/twake/frontend/public/public/emojione/32/1f44d-1f3fc.png new file mode 100644 index 00000000..048352ad Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44d-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44d-1f3fd.png b/twake/frontend/public/public/emojione/32/1f44d-1f3fd.png new file mode 100644 index 00000000..d8b975e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44d-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44d-1f3fe.png b/twake/frontend/public/public/emojione/32/1f44d-1f3fe.png new file mode 100644 index 00000000..59454423 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44d-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44d-1f3ff.png b/twake/frontend/public/public/emojione/32/1f44d-1f3ff.png new file mode 100644 index 00000000..80b556e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44d-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44d.png b/twake/frontend/public/public/emojione/32/1f44d.png new file mode 100644 index 00000000..6421052b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44e-1f3fb.png b/twake/frontend/public/public/emojione/32/1f44e-1f3fb.png new file mode 100644 index 00000000..92d3783c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44e-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44e-1f3fc.png b/twake/frontend/public/public/emojione/32/1f44e-1f3fc.png new file mode 100644 index 00000000..4d26fbe7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44e-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44e-1f3fd.png b/twake/frontend/public/public/emojione/32/1f44e-1f3fd.png new file mode 100644 index 00000000..f3b30c98 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44e-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44e-1f3fe.png b/twake/frontend/public/public/emojione/32/1f44e-1f3fe.png new file mode 100644 index 00000000..50cd75fd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44e-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44e-1f3ff.png b/twake/frontend/public/public/emojione/32/1f44e-1f3ff.png new file mode 100644 index 00000000..e0240196 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44e-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44e.png b/twake/frontend/public/public/emojione/32/1f44e.png new file mode 100644 index 00000000..ccd14269 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44f-1f3fb.png b/twake/frontend/public/public/emojione/32/1f44f-1f3fb.png new file mode 100644 index 00000000..d3eeea01 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44f-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44f-1f3fc.png b/twake/frontend/public/public/emojione/32/1f44f-1f3fc.png new file mode 100644 index 00000000..856d0dec Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44f-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44f-1f3fd.png b/twake/frontend/public/public/emojione/32/1f44f-1f3fd.png new file mode 100644 index 00000000..ebd26c9b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44f-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44f-1f3fe.png b/twake/frontend/public/public/emojione/32/1f44f-1f3fe.png new file mode 100644 index 00000000..9e806c2f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44f-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44f-1f3ff.png b/twake/frontend/public/public/emojione/32/1f44f-1f3ff.png new file mode 100644 index 00000000..7684d8af Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44f-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f44f.png b/twake/frontend/public/public/emojione/32/1f44f.png new file mode 100644 index 00000000..7de77b90 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f44f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f450-1f3fb.png b/twake/frontend/public/public/emojione/32/1f450-1f3fb.png new file mode 100644 index 00000000..b513ce79 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f450-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f450-1f3fc.png b/twake/frontend/public/public/emojione/32/1f450-1f3fc.png new file mode 100644 index 00000000..46f49da0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f450-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f450-1f3fd.png b/twake/frontend/public/public/emojione/32/1f450-1f3fd.png new file mode 100644 index 00000000..c1777c4d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f450-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f450-1f3fe.png b/twake/frontend/public/public/emojione/32/1f450-1f3fe.png new file mode 100644 index 00000000..e3785ef8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f450-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f450-1f3ff.png b/twake/frontend/public/public/emojione/32/1f450-1f3ff.png new file mode 100644 index 00000000..083f2e5e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f450-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f450.png b/twake/frontend/public/public/emojione/32/1f450.png new file mode 100644 index 00000000..2d9eca85 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f450.png differ diff --git a/twake/frontend/public/public/emojione/32/1f451.png b/twake/frontend/public/public/emojione/32/1f451.png new file mode 100644 index 00000000..bb58ea1e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f451.png differ diff --git a/twake/frontend/public/public/emojione/32/1f452.png b/twake/frontend/public/public/emojione/32/1f452.png new file mode 100644 index 00000000..cc620f4e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f452.png differ diff --git a/twake/frontend/public/public/emojione/32/1f453.png b/twake/frontend/public/public/emojione/32/1f453.png new file mode 100644 index 00000000..d6dd2fe9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f453.png differ diff --git a/twake/frontend/public/public/emojione/32/1f454.png b/twake/frontend/public/public/emojione/32/1f454.png new file mode 100644 index 00000000..cce80a7c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f454.png differ diff --git a/twake/frontend/public/public/emojione/32/1f455.png b/twake/frontend/public/public/emojione/32/1f455.png new file mode 100644 index 00000000..5e74af4a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f455.png differ diff --git a/twake/frontend/public/public/emojione/32/1f456.png b/twake/frontend/public/public/emojione/32/1f456.png new file mode 100644 index 00000000..49887394 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f456.png differ diff --git a/twake/frontend/public/public/emojione/32/1f457.png b/twake/frontend/public/public/emojione/32/1f457.png new file mode 100644 index 00000000..8a070c44 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f457.png differ diff --git a/twake/frontend/public/public/emojione/32/1f458.png b/twake/frontend/public/public/emojione/32/1f458.png new file mode 100644 index 00000000..2f4ed893 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f458.png differ diff --git a/twake/frontend/public/public/emojione/32/1f459.png b/twake/frontend/public/public/emojione/32/1f459.png new file mode 100644 index 00000000..0a757355 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f459.png differ diff --git a/twake/frontend/public/public/emojione/32/1f45a.png b/twake/frontend/public/public/emojione/32/1f45a.png new file mode 100644 index 00000000..f952d939 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f45a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f45b.png b/twake/frontend/public/public/emojione/32/1f45b.png new file mode 100644 index 00000000..30f9c716 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f45b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f45c.png b/twake/frontend/public/public/emojione/32/1f45c.png new file mode 100644 index 00000000..d2ea4b8d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f45c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f45d.png b/twake/frontend/public/public/emojione/32/1f45d.png new file mode 100644 index 00000000..0ec6edc5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f45d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f45e.png b/twake/frontend/public/public/emojione/32/1f45e.png new file mode 100644 index 00000000..10cc7db6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f45e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f45f.png b/twake/frontend/public/public/emojione/32/1f45f.png new file mode 100644 index 00000000..fb7deb90 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f45f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f460.png b/twake/frontend/public/public/emojione/32/1f460.png new file mode 100644 index 00000000..84a9a79d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f460.png differ diff --git a/twake/frontend/public/public/emojione/32/1f461.png b/twake/frontend/public/public/emojione/32/1f461.png new file mode 100644 index 00000000..56df8907 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f461.png differ diff --git a/twake/frontend/public/public/emojione/32/1f462.png b/twake/frontend/public/public/emojione/32/1f462.png new file mode 100644 index 00000000..7cec47f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f462.png differ diff --git a/twake/frontend/public/public/emojione/32/1f463.png b/twake/frontend/public/public/emojione/32/1f463.png new file mode 100644 index 00000000..b2bf53e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f463.png differ diff --git a/twake/frontend/public/public/emojione/32/1f464.png b/twake/frontend/public/public/emojione/32/1f464.png new file mode 100644 index 00000000..e55889ef Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f464.png differ diff --git a/twake/frontend/public/public/emojione/32/1f465.png b/twake/frontend/public/public/emojione/32/1f465.png new file mode 100644 index 00000000..71199e02 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f465.png differ diff --git a/twake/frontend/public/public/emojione/32/1f466-1f3fb.png b/twake/frontend/public/public/emojione/32/1f466-1f3fb.png new file mode 100644 index 00000000..a5161835 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f466-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f466-1f3fc.png b/twake/frontend/public/public/emojione/32/1f466-1f3fc.png new file mode 100644 index 00000000..161e7144 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f466-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f466-1f3fd.png b/twake/frontend/public/public/emojione/32/1f466-1f3fd.png new file mode 100644 index 00000000..8351a829 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f466-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f466-1f3fe.png b/twake/frontend/public/public/emojione/32/1f466-1f3fe.png new file mode 100644 index 00000000..af8072da Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f466-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f466-1f3ff.png b/twake/frontend/public/public/emojione/32/1f466-1f3ff.png new file mode 100644 index 00000000..2044f81d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f466-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f466.png b/twake/frontend/public/public/emojione/32/1f466.png new file mode 100644 index 00000000..60e36fb0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f466.png differ diff --git a/twake/frontend/public/public/emojione/32/1f467-1f3fb.png b/twake/frontend/public/public/emojione/32/1f467-1f3fb.png new file mode 100644 index 00000000..e35dc785 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f467-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f467-1f3fc.png b/twake/frontend/public/public/emojione/32/1f467-1f3fc.png new file mode 100644 index 00000000..0a7d339d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f467-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f467-1f3fd.png b/twake/frontend/public/public/emojione/32/1f467-1f3fd.png new file mode 100644 index 00000000..95b95e7e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f467-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f467-1f3fe.png b/twake/frontend/public/public/emojione/32/1f467-1f3fe.png new file mode 100644 index 00000000..8a1f7f03 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f467-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f467-1f3ff.png b/twake/frontend/public/public/emojione/32/1f467-1f3ff.png new file mode 100644 index 00000000..3f086fba Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f467-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f467.png b/twake/frontend/public/public/emojione/32/1f467.png new file mode 100644 index 00000000..8f8ff241 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f467.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f33e.png b/twake/frontend/public/public/emojione/32/1f468-1f33e.png new file mode 100644 index 00000000..478042c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f373.png b/twake/frontend/public/public/emojione/32/1f468-1f373.png new file mode 100644 index 00000000..51bc80f3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f373.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f393.png b/twake/frontend/public/public/emojione/32/1f468-1f393.png new file mode 100644 index 00000000..0dd77e15 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f393.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3a4.png b/twake/frontend/public/public/emojione/32/1f468-1f3a4.png new file mode 100644 index 00000000..b326c630 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3a8.png b/twake/frontend/public/public/emojione/32/1f468-1f3a8.png new file mode 100644 index 00000000..e480c096 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3eb.png b/twake/frontend/public/public/emojione/32/1f468-1f3eb.png new file mode 100644 index 00000000..7bceb6cf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ed.png b/twake/frontend/public/public/emojione/32/1f468-1f3ed.png new file mode 100644 index 00000000..c21d1847 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f33e.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f33e.png new file mode 100644 index 00000000..260eac4c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f373.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f373.png new file mode 100644 index 00000000..767cc5e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f373.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f393.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f393.png new file mode 100644 index 00000000..94c533f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f393.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f3a4.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f3a4.png new file mode 100644 index 00000000..9d0bf270 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f3a8.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f3a8.png new file mode 100644 index 00000000..8bb6d87e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f3eb.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f3eb.png new file mode 100644 index 00000000..5a711596 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f3ed.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f3ed.png new file mode 100644 index 00000000..7fd99d02 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f4bb.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f4bb.png new file mode 100644 index 00000000..a6efca60 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f4bc.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f4bc.png new file mode 100644 index 00000000..d41ca87f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f527.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f527.png new file mode 100644 index 00000000..0dea33bf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f527.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f52c.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f52c.png new file mode 100644 index 00000000..b83193f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f680.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f680.png new file mode 100644 index 00000000..abc94d45 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f680.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f692.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f692.png new file mode 100644 index 00000000..b1aa9132 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f692.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f9b0.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f9b0.png new file mode 100644 index 00000000..e0cce394 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f9b1.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f9b1.png new file mode 100644 index 00000000..b1025f91 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f9b2.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f9b2.png new file mode 100644 index 00000000..8848f6d3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f9b3.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f9b3.png new file mode 100644 index 00000000..f83440f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-2695.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-2695.png new file mode 100644 index 00000000..d8dfcdab Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-2695.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-2696.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-2696.png new file mode 100644 index 00000000..66d235d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-2696.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb-2708.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb-2708.png new file mode 100644 index 00000000..edc8c3ad Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb-2708.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fb.png b/twake/frontend/public/public/emojione/32/1f468-1f3fb.png new file mode 100644 index 00000000..577bfac5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f33e.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f33e.png new file mode 100644 index 00000000..ea5511a2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f373.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f373.png new file mode 100644 index 00000000..8e78b16b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f373.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f393.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f393.png new file mode 100644 index 00000000..42c3f3ed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f393.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f3a4.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f3a4.png new file mode 100644 index 00000000..cdc480f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f3a8.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f3a8.png new file mode 100644 index 00000000..29dfa6cd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f3eb.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f3eb.png new file mode 100644 index 00000000..c6a230fc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f3ed.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f3ed.png new file mode 100644 index 00000000..3bbe7138 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f4bb.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f4bb.png new file mode 100644 index 00000000..4952656c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f4bc.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f4bc.png new file mode 100644 index 00000000..a0e3d049 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f527.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f527.png new file mode 100644 index 00000000..d725f773 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f527.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f52c.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f52c.png new file mode 100644 index 00000000..1fa353b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f680.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f680.png new file mode 100644 index 00000000..c8193b7d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f680.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f692.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f692.png new file mode 100644 index 00000000..454f8be9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f692.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f9b0.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f9b0.png new file mode 100644 index 00000000..810758cf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f9b1.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f9b1.png new file mode 100644 index 00000000..34280199 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f9b2.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f9b2.png new file mode 100644 index 00000000..61a33c63 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f9b3.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f9b3.png new file mode 100644 index 00000000..4aac4794 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-2695.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-2695.png new file mode 100644 index 00000000..626f22b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-2695.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-2696.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-2696.png new file mode 100644 index 00000000..4a2ba4b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-2696.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc-2708.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc-2708.png new file mode 100644 index 00000000..42f470ed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc-2708.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fc.png b/twake/frontend/public/public/emojione/32/1f468-1f3fc.png new file mode 100644 index 00000000..d24b13a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f33e.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f33e.png new file mode 100644 index 00000000..3f873695 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f373.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f373.png new file mode 100644 index 00000000..b4432264 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f373.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f393.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f393.png new file mode 100644 index 00000000..732e706d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f393.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f3a4.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f3a4.png new file mode 100644 index 00000000..9ea13e08 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f3a8.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f3a8.png new file mode 100644 index 00000000..2401132b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f3eb.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f3eb.png new file mode 100644 index 00000000..a7f74042 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f3ed.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f3ed.png new file mode 100644 index 00000000..c52e7134 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f4bb.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f4bb.png new file mode 100644 index 00000000..4ec159c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f4bc.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f4bc.png new file mode 100644 index 00000000..94f2fc8b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f527.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f527.png new file mode 100644 index 00000000..86fe7d39 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f527.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f52c.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f52c.png new file mode 100644 index 00000000..5d05270b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f680.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f680.png new file mode 100644 index 00000000..ddc30d56 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f680.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f692.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f692.png new file mode 100644 index 00000000..2b7e6279 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f692.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f9b0.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f9b0.png new file mode 100644 index 00000000..0f47507b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f9b1.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f9b1.png new file mode 100644 index 00000000..77b986a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f9b2.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f9b2.png new file mode 100644 index 00000000..355f22e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f9b3.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f9b3.png new file mode 100644 index 00000000..4aa6a972 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-2695.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-2695.png new file mode 100644 index 00000000..df9e54dc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-2695.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-2696.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-2696.png new file mode 100644 index 00000000..aa23bcdb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-2696.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd-2708.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd-2708.png new file mode 100644 index 00000000..00bde4e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd-2708.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fd.png b/twake/frontend/public/public/emojione/32/1f468-1f3fd.png new file mode 100644 index 00000000..a7252948 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f33e.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f33e.png new file mode 100644 index 00000000..a069a3e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f373.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f373.png new file mode 100644 index 00000000..ea9ac7dd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f373.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f393.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f393.png new file mode 100644 index 00000000..5b6b6d6b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f393.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f3a4.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f3a4.png new file mode 100644 index 00000000..458eca22 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f3a8.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f3a8.png new file mode 100644 index 00000000..435e2889 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f3eb.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f3eb.png new file mode 100644 index 00000000..12db6226 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f3ed.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f3ed.png new file mode 100644 index 00000000..6480bc20 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f4bb.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f4bb.png new file mode 100644 index 00000000..ede36172 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f4bc.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f4bc.png new file mode 100644 index 00000000..273a47ba Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f527.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f527.png new file mode 100644 index 00000000..a585d1a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f527.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f52c.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f52c.png new file mode 100644 index 00000000..64da9a70 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f680.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f680.png new file mode 100644 index 00000000..50967213 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f680.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f692.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f692.png new file mode 100644 index 00000000..eb2eb718 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f692.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f9b0.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f9b0.png new file mode 100644 index 00000000..be64f496 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f9b1.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f9b1.png new file mode 100644 index 00000000..05962e42 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f9b2.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f9b2.png new file mode 100644 index 00000000..88b87b2d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f9b3.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f9b3.png new file mode 100644 index 00000000..492d54bb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-2695.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-2695.png new file mode 100644 index 00000000..7fc15444 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-2695.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-2696.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-2696.png new file mode 100644 index 00000000..01e28443 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-2696.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe-2708.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe-2708.png new file mode 100644 index 00000000..055bfb18 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe-2708.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3fe.png b/twake/frontend/public/public/emojione/32/1f468-1f3fe.png new file mode 100644 index 00000000..319ad3bb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f33e.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f33e.png new file mode 100644 index 00000000..8c909103 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f373.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f373.png new file mode 100644 index 00000000..e609733e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f373.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f393.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f393.png new file mode 100644 index 00000000..560a9f51 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f393.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f3a4.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f3a4.png new file mode 100644 index 00000000..2f05040b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f3a8.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f3a8.png new file mode 100644 index 00000000..408e7688 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f3eb.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f3eb.png new file mode 100644 index 00000000..4a1d40ea Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f3ed.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f3ed.png new file mode 100644 index 00000000..02839fbc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f4bb.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f4bb.png new file mode 100644 index 00000000..cf96607f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f4bc.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f4bc.png new file mode 100644 index 00000000..891c5446 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f527.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f527.png new file mode 100644 index 00000000..f2a55bfd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f527.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f52c.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f52c.png new file mode 100644 index 00000000..8dfe08b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f680.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f680.png new file mode 100644 index 00000000..5c713329 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f680.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f692.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f692.png new file mode 100644 index 00000000..842de94e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f692.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f9b0.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f9b0.png new file mode 100644 index 00000000..8eeb4b44 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f9b1.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f9b1.png new file mode 100644 index 00000000..b66d7bbd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f9b2.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f9b2.png new file mode 100644 index 00000000..1ab28e1f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f9b3.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f9b3.png new file mode 100644 index 00000000..0f784dcd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-2695.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-2695.png new file mode 100644 index 00000000..6b294bad Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-2695.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-2696.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-2696.png new file mode 100644 index 00000000..45a60e1e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-2696.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff-2708.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff-2708.png new file mode 100644 index 00000000..abe87c52 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff-2708.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f3ff.png b/twake/frontend/public/public/emojione/32/1f468-1f3ff.png new file mode 100644 index 00000000..73746d1b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f466-1f466.png b/twake/frontend/public/public/emojione/32/1f468-1f466-1f466.png new file mode 100644 index 00000000..34c8ed80 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f466-1f466.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f466.png b/twake/frontend/public/public/emojione/32/1f468-1f466.png new file mode 100644 index 00000000..33b45988 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f466.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f467-1f466.png b/twake/frontend/public/public/emojione/32/1f468-1f467-1f466.png new file mode 100644 index 00000000..5ee38e33 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f467-1f466.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f467-1f467.png b/twake/frontend/public/public/emojione/32/1f468-1f467-1f467.png new file mode 100644 index 00000000..f249d6f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f467-1f467.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f467.png b/twake/frontend/public/public/emojione/32/1f468-1f467.png new file mode 100644 index 00000000..a16b6ad7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f467.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f468-1f466-1f466.png b/twake/frontend/public/public/emojione/32/1f468-1f468-1f466-1f466.png new file mode 100644 index 00000000..e66eafb3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f468-1f466-1f466.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f468-1f466.png b/twake/frontend/public/public/emojione/32/1f468-1f468-1f466.png new file mode 100644 index 00000000..af986e30 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f468-1f466.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f468-1f467-1f466.png b/twake/frontend/public/public/emojione/32/1f468-1f468-1f467-1f466.png new file mode 100644 index 00000000..fc61e485 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f468-1f467-1f466.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f468-1f467-1f467.png b/twake/frontend/public/public/emojione/32/1f468-1f468-1f467-1f467.png new file mode 100644 index 00000000..a28899c4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f468-1f467-1f467.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f468-1f467.png b/twake/frontend/public/public/emojione/32/1f468-1f468-1f467.png new file mode 100644 index 00000000..63669d85 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f468-1f467.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f469-1f466-1f466.png b/twake/frontend/public/public/emojione/32/1f468-1f469-1f466-1f466.png new file mode 100644 index 00000000..b83ea8ba Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f469-1f466-1f466.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f469-1f466.png b/twake/frontend/public/public/emojione/32/1f468-1f469-1f466.png new file mode 100644 index 00000000..15ee1078 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f469-1f466.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f469-1f467-1f466.png b/twake/frontend/public/public/emojione/32/1f468-1f469-1f467-1f466.png new file mode 100644 index 00000000..34013bf0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f469-1f467-1f466.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f469-1f467-1f467.png b/twake/frontend/public/public/emojione/32/1f468-1f469-1f467-1f467.png new file mode 100644 index 00000000..8d01dc54 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f469-1f467-1f467.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f469-1f467.png b/twake/frontend/public/public/emojione/32/1f468-1f469-1f467.png new file mode 100644 index 00000000..39e45a9e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f469-1f467.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f4bb.png b/twake/frontend/public/public/emojione/32/1f468-1f4bb.png new file mode 100644 index 00000000..14f2620d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f4bc.png b/twake/frontend/public/public/emojione/32/1f468-1f4bc.png new file mode 100644 index 00000000..6e7e4cd3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f527.png b/twake/frontend/public/public/emojione/32/1f468-1f527.png new file mode 100644 index 00000000..4a9f21d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f527.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f52c.png b/twake/frontend/public/public/emojione/32/1f468-1f52c.png new file mode 100644 index 00000000..56ae0cdc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f680.png b/twake/frontend/public/public/emojione/32/1f468-1f680.png new file mode 100644 index 00000000..5b7e9114 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f680.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f692.png b/twake/frontend/public/public/emojione/32/1f468-1f692.png new file mode 100644 index 00000000..bb00a4e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f692.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f9b0.png b/twake/frontend/public/public/emojione/32/1f468-1f9b0.png new file mode 100644 index 00000000..4fb532b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f9b1.png b/twake/frontend/public/public/emojione/32/1f468-1f9b1.png new file mode 100644 index 00000000..18d7686b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f9b2.png b/twake/frontend/public/public/emojione/32/1f468-1f9b2.png new file mode 100644 index 00000000..2888e8d3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-1f9b3.png b/twake/frontend/public/public/emojione/32/1f468-1f9b3.png new file mode 100644 index 00000000..3bba3ec2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-2695.png b/twake/frontend/public/public/emojione/32/1f468-2695.png new file mode 100644 index 00000000..d5f4af3e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-2695.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-2696.png b/twake/frontend/public/public/emojione/32/1f468-2696.png new file mode 100644 index 00000000..c49cd6d3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-2696.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-2708.png b/twake/frontend/public/public/emojione/32/1f468-2708.png new file mode 100644 index 00000000..7ad6023c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-2708.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-2764-1f468.png b/twake/frontend/public/public/emojione/32/1f468-2764-1f468.png new file mode 100644 index 00000000..25aca38a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-2764-1f468.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468-2764-1f48b-1f468.png b/twake/frontend/public/public/emojione/32/1f468-2764-1f48b-1f468.png new file mode 100644 index 00000000..9a265f5e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468-2764-1f48b-1f468.png differ diff --git a/twake/frontend/public/public/emojione/32/1f468.png b/twake/frontend/public/public/emojione/32/1f468.png new file mode 100644 index 00000000..40f25c11 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f468.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f33e.png b/twake/frontend/public/public/emojione/32/1f469-1f33e.png new file mode 100644 index 00000000..f2bf093f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f373.png b/twake/frontend/public/public/emojione/32/1f469-1f373.png new file mode 100644 index 00000000..de1b54f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f373.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f393.png b/twake/frontend/public/public/emojione/32/1f469-1f393.png new file mode 100644 index 00000000..08eb8a72 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f393.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3a4.png b/twake/frontend/public/public/emojione/32/1f469-1f3a4.png new file mode 100644 index 00000000..7f684ae9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3a8.png b/twake/frontend/public/public/emojione/32/1f469-1f3a8.png new file mode 100644 index 00000000..59ad2d97 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3eb.png b/twake/frontend/public/public/emojione/32/1f469-1f3eb.png new file mode 100644 index 00000000..2c9dafed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ed.png b/twake/frontend/public/public/emojione/32/1f469-1f3ed.png new file mode 100644 index 00000000..6e3dbfd6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f33e.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f33e.png new file mode 100644 index 00000000..a057f722 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f373.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f373.png new file mode 100644 index 00000000..73f4323f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f373.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f393.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f393.png new file mode 100644 index 00000000..30c8ab70 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f393.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f3a4.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f3a4.png new file mode 100644 index 00000000..111fa711 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f3a8.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f3a8.png new file mode 100644 index 00000000..f9029554 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f3eb.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f3eb.png new file mode 100644 index 00000000..38391660 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f3ed.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f3ed.png new file mode 100644 index 00000000..05b34ce7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f4bb.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f4bb.png new file mode 100644 index 00000000..f02dbfd5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f4bc.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f4bc.png new file mode 100644 index 00000000..2d6513e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f527.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f527.png new file mode 100644 index 00000000..807e3c35 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f527.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f52c.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f52c.png new file mode 100644 index 00000000..9795ce48 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f680.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f680.png new file mode 100644 index 00000000..14cdf79c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f680.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f692.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f692.png new file mode 100644 index 00000000..b98f6b5e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f692.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f9b0.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f9b0.png new file mode 100644 index 00000000..2c0142f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f9b1.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f9b1.png new file mode 100644 index 00000000..72f8cd19 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f9b2.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f9b2.png new file mode 100644 index 00000000..24bfabf1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f9b3.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f9b3.png new file mode 100644 index 00000000..bb46f4a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-2695.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-2695.png new file mode 100644 index 00000000..7ad69f4f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-2695.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-2696.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-2696.png new file mode 100644 index 00000000..6c260207 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-2696.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb-2708.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb-2708.png new file mode 100644 index 00000000..ec22e65b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb-2708.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fb.png b/twake/frontend/public/public/emojione/32/1f469-1f3fb.png new file mode 100644 index 00000000..6a1c6cfa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f33e.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f33e.png new file mode 100644 index 00000000..2b83ce85 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f373.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f373.png new file mode 100644 index 00000000..e22f3087 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f373.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f393.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f393.png new file mode 100644 index 00000000..7673ffc2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f393.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f3a4.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f3a4.png new file mode 100644 index 00000000..64431026 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f3a8.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f3a8.png new file mode 100644 index 00000000..1f7475aa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f3eb.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f3eb.png new file mode 100644 index 00000000..67baf2c5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f3ed.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f3ed.png new file mode 100644 index 00000000..d9b8d1c4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f4bb.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f4bb.png new file mode 100644 index 00000000..7d9d269a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f4bc.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f4bc.png new file mode 100644 index 00000000..f99b36e4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f527.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f527.png new file mode 100644 index 00000000..c0d20b5a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f527.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f52c.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f52c.png new file mode 100644 index 00000000..2d6917b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f680.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f680.png new file mode 100644 index 00000000..10cb5e44 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f680.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f692.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f692.png new file mode 100644 index 00000000..5d317b1f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f692.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f9b0.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f9b0.png new file mode 100644 index 00000000..8dd0e55d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f9b1.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f9b1.png new file mode 100644 index 00000000..85b767c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f9b2.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f9b2.png new file mode 100644 index 00000000..1d8d4cc7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f9b3.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f9b3.png new file mode 100644 index 00000000..195d524b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-2695.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-2695.png new file mode 100644 index 00000000..19051bca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-2695.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-2696.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-2696.png new file mode 100644 index 00000000..f935e462 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-2696.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc-2708.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc-2708.png new file mode 100644 index 00000000..5d705842 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc-2708.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fc.png b/twake/frontend/public/public/emojione/32/1f469-1f3fc.png new file mode 100644 index 00000000..4691f816 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f33e.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f33e.png new file mode 100644 index 00000000..38fa1a00 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f373.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f373.png new file mode 100644 index 00000000..e0bd5ca1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f373.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f393.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f393.png new file mode 100644 index 00000000..15e496ce Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f393.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f3a4.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f3a4.png new file mode 100644 index 00000000..cb959107 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f3a8.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f3a8.png new file mode 100644 index 00000000..d6f016dd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f3eb.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f3eb.png new file mode 100644 index 00000000..c123c902 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f3ed.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f3ed.png new file mode 100644 index 00000000..f43e1952 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f4bb.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f4bb.png new file mode 100644 index 00000000..bb53b289 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f4bc.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f4bc.png new file mode 100644 index 00000000..f8ee37aa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f527.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f527.png new file mode 100644 index 00000000..b4d155cf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f527.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f52c.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f52c.png new file mode 100644 index 00000000..952b93a6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f680.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f680.png new file mode 100644 index 00000000..a9031096 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f680.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f692.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f692.png new file mode 100644 index 00000000..195507a2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f692.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f9b0.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f9b0.png new file mode 100644 index 00000000..8229e277 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f9b1.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f9b1.png new file mode 100644 index 00000000..af258ebc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f9b2.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f9b2.png new file mode 100644 index 00000000..8844500c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f9b3.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f9b3.png new file mode 100644 index 00000000..7b7c5d0c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-2695.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-2695.png new file mode 100644 index 00000000..a66c3cd0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-2695.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-2696.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-2696.png new file mode 100644 index 00000000..300577b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-2696.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd-2708.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd-2708.png new file mode 100644 index 00000000..81c46951 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd-2708.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fd.png b/twake/frontend/public/public/emojione/32/1f469-1f3fd.png new file mode 100644 index 00000000..8dc01624 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f33e.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f33e.png new file mode 100644 index 00000000..e87aadb5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f373.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f373.png new file mode 100644 index 00000000..ae540088 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f373.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f393.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f393.png new file mode 100644 index 00000000..587b8449 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f393.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f3a4.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f3a4.png new file mode 100644 index 00000000..b8c03542 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f3a8.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f3a8.png new file mode 100644 index 00000000..f627feef Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f3eb.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f3eb.png new file mode 100644 index 00000000..715cff51 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f3ed.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f3ed.png new file mode 100644 index 00000000..deec1f32 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f4bb.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f4bb.png new file mode 100644 index 00000000..783f4191 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f4bc.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f4bc.png new file mode 100644 index 00000000..156975fe Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f527.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f527.png new file mode 100644 index 00000000..424fa2c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f527.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f52c.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f52c.png new file mode 100644 index 00000000..84204061 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f680.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f680.png new file mode 100644 index 00000000..7882a2db Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f680.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f692.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f692.png new file mode 100644 index 00000000..fb27a3f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f692.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f9b0.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f9b0.png new file mode 100644 index 00000000..571585e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f9b1.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f9b1.png new file mode 100644 index 00000000..bb3135b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f9b2.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f9b2.png new file mode 100644 index 00000000..8cb495bc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f9b3.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f9b3.png new file mode 100644 index 00000000..2cc4a694 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-2695.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-2695.png new file mode 100644 index 00000000..fa1d7177 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-2695.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-2696.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-2696.png new file mode 100644 index 00000000..7964862e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-2696.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe-2708.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe-2708.png new file mode 100644 index 00000000..ff2cecbd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe-2708.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3fe.png b/twake/frontend/public/public/emojione/32/1f469-1f3fe.png new file mode 100644 index 00000000..2f27f400 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f33e.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f33e.png new file mode 100644 index 00000000..1bf0322f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f373.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f373.png new file mode 100644 index 00000000..d8ff859b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f373.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f393.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f393.png new file mode 100644 index 00000000..05f6fd01 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f393.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f3a4.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f3a4.png new file mode 100644 index 00000000..678457d5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f3a8.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f3a8.png new file mode 100644 index 00000000..ebf792d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f3eb.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f3eb.png new file mode 100644 index 00000000..a2f68adf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f3ed.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f3ed.png new file mode 100644 index 00000000..4376c59d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f4bb.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f4bb.png new file mode 100644 index 00000000..65c3aa48 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f4bc.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f4bc.png new file mode 100644 index 00000000..9baba7f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f527.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f527.png new file mode 100644 index 00000000..a743f620 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f527.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f52c.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f52c.png new file mode 100644 index 00000000..0c6c6afb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f680.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f680.png new file mode 100644 index 00000000..63413e66 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f680.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f692.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f692.png new file mode 100644 index 00000000..43b083c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f692.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f9b0.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f9b0.png new file mode 100644 index 00000000..01f627a8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f9b1.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f9b1.png new file mode 100644 index 00000000..fd6b3af9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f9b2.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f9b2.png new file mode 100644 index 00000000..3479c1fa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f9b3.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f9b3.png new file mode 100644 index 00000000..9d9a514b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-2695.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-2695.png new file mode 100644 index 00000000..a3a34e8e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-2695.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-2696.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-2696.png new file mode 100644 index 00000000..09cf25d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-2696.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff-2708.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff-2708.png new file mode 100644 index 00000000..35b8b0d5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff-2708.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f3ff.png b/twake/frontend/public/public/emojione/32/1f469-1f3ff.png new file mode 100644 index 00000000..6ea8460c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f466-1f466.png b/twake/frontend/public/public/emojione/32/1f469-1f466-1f466.png new file mode 100644 index 00000000..b080ff74 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f466-1f466.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f466.png b/twake/frontend/public/public/emojione/32/1f469-1f466.png new file mode 100644 index 00000000..db941461 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f466.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f467-1f466.png b/twake/frontend/public/public/emojione/32/1f469-1f467-1f466.png new file mode 100644 index 00000000..031bd5a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f467-1f466.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f467-1f467.png b/twake/frontend/public/public/emojione/32/1f469-1f467-1f467.png new file mode 100644 index 00000000..7c964ec3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f467-1f467.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f467.png b/twake/frontend/public/public/emojione/32/1f469-1f467.png new file mode 100644 index 00000000..b23f7aef Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f467.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f469-1f466-1f466.png b/twake/frontend/public/public/emojione/32/1f469-1f469-1f466-1f466.png new file mode 100644 index 00000000..dba673f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f469-1f466-1f466.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f469-1f466.png b/twake/frontend/public/public/emojione/32/1f469-1f469-1f466.png new file mode 100644 index 00000000..70ea372e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f469-1f466.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f469-1f467-1f466.png b/twake/frontend/public/public/emojione/32/1f469-1f469-1f467-1f466.png new file mode 100644 index 00000000..0d6bd467 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f469-1f467-1f466.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f469-1f467-1f467.png b/twake/frontend/public/public/emojione/32/1f469-1f469-1f467-1f467.png new file mode 100644 index 00000000..223f0c6c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f469-1f467-1f467.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f469-1f467.png b/twake/frontend/public/public/emojione/32/1f469-1f469-1f467.png new file mode 100644 index 00000000..e0440fd4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f469-1f467.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f4bb.png b/twake/frontend/public/public/emojione/32/1f469-1f4bb.png new file mode 100644 index 00000000..9a543970 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f4bc.png b/twake/frontend/public/public/emojione/32/1f469-1f4bc.png new file mode 100644 index 00000000..c9c05377 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f527.png b/twake/frontend/public/public/emojione/32/1f469-1f527.png new file mode 100644 index 00000000..c110b7b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f527.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f52c.png b/twake/frontend/public/public/emojione/32/1f469-1f52c.png new file mode 100644 index 00000000..acc5f117 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f680.png b/twake/frontend/public/public/emojione/32/1f469-1f680.png new file mode 100644 index 00000000..1fb3b8f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f680.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f692.png b/twake/frontend/public/public/emojione/32/1f469-1f692.png new file mode 100644 index 00000000..3dd3ad4e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f692.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f9b0.png b/twake/frontend/public/public/emojione/32/1f469-1f9b0.png new file mode 100644 index 00000000..ccc47fe9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f9b1.png b/twake/frontend/public/public/emojione/32/1f469-1f9b1.png new file mode 100644 index 00000000..dd424cb9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f9b2.png b/twake/frontend/public/public/emojione/32/1f469-1f9b2.png new file mode 100644 index 00000000..7bf80068 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-1f9b3.png b/twake/frontend/public/public/emojione/32/1f469-1f9b3.png new file mode 100644 index 00000000..15adcb4f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-2695.png b/twake/frontend/public/public/emojione/32/1f469-2695.png new file mode 100644 index 00000000..7128d0ae Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-2695.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-2696.png b/twake/frontend/public/public/emojione/32/1f469-2696.png new file mode 100644 index 00000000..b6a0a5da Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-2696.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-2708.png b/twake/frontend/public/public/emojione/32/1f469-2708.png new file mode 100644 index 00000000..88abb19e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-2708.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-2764-1f468.png b/twake/frontend/public/public/emojione/32/1f469-2764-1f468.png new file mode 100644 index 00000000..343322e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-2764-1f468.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-2764-1f469.png b/twake/frontend/public/public/emojione/32/1f469-2764-1f469.png new file mode 100644 index 00000000..0bbf23ac Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-2764-1f469.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-2764-1f48b-1f468.png b/twake/frontend/public/public/emojione/32/1f469-2764-1f48b-1f468.png new file mode 100644 index 00000000..12a952ca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-2764-1f48b-1f468.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469-2764-1f48b-1f469.png b/twake/frontend/public/public/emojione/32/1f469-2764-1f48b-1f469.png new file mode 100644 index 00000000..6ea83d55 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469-2764-1f48b-1f469.png differ diff --git a/twake/frontend/public/public/emojione/32/1f469.png b/twake/frontend/public/public/emojione/32/1f469.png new file mode 100644 index 00000000..59f1681a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f469.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46a.png b/twake/frontend/public/public/emojione/32/1f46a.png new file mode 100644 index 00000000..15ee1078 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46b.png b/twake/frontend/public/public/emojione/32/1f46b.png new file mode 100644 index 00000000..55dc5742 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46c.png b/twake/frontend/public/public/emojione/32/1f46c.png new file mode 100644 index 00000000..9b32145a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46d.png b/twake/frontend/public/public/emojione/32/1f46d.png new file mode 100644 index 00000000..a65576b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f46e-1f3fb-2640.png new file mode 100644 index 00000000..f3c1cf36 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f46e-1f3fb-2642.png new file mode 100644 index 00000000..12e85eff Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e-1f3fb.png b/twake/frontend/public/public/emojione/32/1f46e-1f3fb.png new file mode 100644 index 00000000..12e85eff Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f46e-1f3fc-2640.png new file mode 100644 index 00000000..498daa38 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f46e-1f3fc-2642.png new file mode 100644 index 00000000..f05e832b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e-1f3fc.png b/twake/frontend/public/public/emojione/32/1f46e-1f3fc.png new file mode 100644 index 00000000..f05e832b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f46e-1f3fd-2640.png new file mode 100644 index 00000000..55d43a93 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f46e-1f3fd-2642.png new file mode 100644 index 00000000..ede99bbb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e-1f3fd.png b/twake/frontend/public/public/emojione/32/1f46e-1f3fd.png new file mode 100644 index 00000000..ede99bbb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f46e-1f3fe-2640.png new file mode 100644 index 00000000..8497ab41 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f46e-1f3fe-2642.png new file mode 100644 index 00000000..596f0ea3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e-1f3fe.png b/twake/frontend/public/public/emojione/32/1f46e-1f3fe.png new file mode 100644 index 00000000..596f0ea3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f46e-1f3ff-2640.png new file mode 100644 index 00000000..2fca02d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f46e-1f3ff-2642.png new file mode 100644 index 00000000..9bdc8ad7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e-1f3ff.png b/twake/frontend/public/public/emojione/32/1f46e-1f3ff.png new file mode 100644 index 00000000..9bdc8ad7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e-2640.png b/twake/frontend/public/public/emojione/32/1f46e-2640.png new file mode 100644 index 00000000..3fa664a4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e-2642.png b/twake/frontend/public/public/emojione/32/1f46e-2642.png new file mode 100644 index 00000000..cfa7196e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46e.png b/twake/frontend/public/public/emojione/32/1f46e.png new file mode 100644 index 00000000..cfa7196e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46f-2640.png b/twake/frontend/public/public/emojione/32/1f46f-2640.png new file mode 100644 index 00000000..0194ec19 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46f-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46f-2642.png b/twake/frontend/public/public/emojione/32/1f46f-2642.png new file mode 100644 index 00000000..2d0fa7a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46f-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f46f.png b/twake/frontend/public/public/emojione/32/1f46f.png new file mode 100644 index 00000000..c9f6c623 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f46f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f470-1f3fb.png b/twake/frontend/public/public/emojione/32/1f470-1f3fb.png new file mode 100644 index 00000000..c1989ae4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f470-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f470-1f3fc.png b/twake/frontend/public/public/emojione/32/1f470-1f3fc.png new file mode 100644 index 00000000..393d421b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f470-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f470-1f3fd.png b/twake/frontend/public/public/emojione/32/1f470-1f3fd.png new file mode 100644 index 00000000..ee210576 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f470-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f470-1f3fe.png b/twake/frontend/public/public/emojione/32/1f470-1f3fe.png new file mode 100644 index 00000000..5cec0c69 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f470-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f470-1f3ff.png b/twake/frontend/public/public/emojione/32/1f470-1f3ff.png new file mode 100644 index 00000000..f42a0eed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f470-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f470.png b/twake/frontend/public/public/emojione/32/1f470.png new file mode 100644 index 00000000..81bfefca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f470.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f471-1f3fb-2640.png new file mode 100644 index 00000000..a0121064 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f471-1f3fb-2642.png new file mode 100644 index 00000000..804ee2a1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471-1f3fb.png b/twake/frontend/public/public/emojione/32/1f471-1f3fb.png new file mode 100644 index 00000000..e9ac5b6b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f471-1f3fc-2640.png new file mode 100644 index 00000000..39cc86e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f471-1f3fc-2642.png new file mode 100644 index 00000000..0ee6eca9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471-1f3fc.png b/twake/frontend/public/public/emojione/32/1f471-1f3fc.png new file mode 100644 index 00000000..0ee6eca9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f471-1f3fd-2640.png new file mode 100644 index 00000000..71482116 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f471-1f3fd-2642.png new file mode 100644 index 00000000..61077b8e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471-1f3fd.png b/twake/frontend/public/public/emojione/32/1f471-1f3fd.png new file mode 100644 index 00000000..417658e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f471-1f3fe-2640.png new file mode 100644 index 00000000..0ac8cc62 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f471-1f3fe-2642.png new file mode 100644 index 00000000..da81024a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471-1f3fe.png b/twake/frontend/public/public/emojione/32/1f471-1f3fe.png new file mode 100644 index 00000000..eaaacad8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f471-1f3ff-2640.png new file mode 100644 index 00000000..432896be Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f471-1f3ff-2642.png new file mode 100644 index 00000000..aa5f4f4a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471-1f3ff.png b/twake/frontend/public/public/emojione/32/1f471-1f3ff.png new file mode 100644 index 00000000..12c85171 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471-2640.png b/twake/frontend/public/public/emojione/32/1f471-2640.png new file mode 100644 index 00000000..99eaa6bd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471-2642.png b/twake/frontend/public/public/emojione/32/1f471-2642.png new file mode 100644 index 00000000..17f9a3c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f471.png b/twake/frontend/public/public/emojione/32/1f471.png new file mode 100644 index 00000000..17f9a3c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f471.png differ diff --git a/twake/frontend/public/public/emojione/32/1f472-1f3fb.png b/twake/frontend/public/public/emojione/32/1f472-1f3fb.png new file mode 100644 index 00000000..fba8b4e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f472-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f472-1f3fc.png b/twake/frontend/public/public/emojione/32/1f472-1f3fc.png new file mode 100644 index 00000000..efb1bbb4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f472-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f472-1f3fd.png b/twake/frontend/public/public/emojione/32/1f472-1f3fd.png new file mode 100644 index 00000000..5329d613 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f472-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f472-1f3fe.png b/twake/frontend/public/public/emojione/32/1f472-1f3fe.png new file mode 100644 index 00000000..1963a836 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f472-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f472-1f3ff.png b/twake/frontend/public/public/emojione/32/1f472-1f3ff.png new file mode 100644 index 00000000..38bbbb8c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f472-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f472.png b/twake/frontend/public/public/emojione/32/1f472.png new file mode 100644 index 00000000..c7d688b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f472.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f473-1f3fb-2640.png new file mode 100644 index 00000000..757bab4d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f473-1f3fb-2642.png new file mode 100644 index 00000000..3aa3c428 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473-1f3fb.png b/twake/frontend/public/public/emojione/32/1f473-1f3fb.png new file mode 100644 index 00000000..3aa3c428 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f473-1f3fc-2640.png new file mode 100644 index 00000000..ada28d9e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f473-1f3fc-2642.png new file mode 100644 index 00000000..1c81cf79 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473-1f3fc.png b/twake/frontend/public/public/emojione/32/1f473-1f3fc.png new file mode 100644 index 00000000..1c81cf79 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f473-1f3fd-2640.png new file mode 100644 index 00000000..0987228a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f473-1f3fd-2642.png new file mode 100644 index 00000000..882fc3f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473-1f3fd.png b/twake/frontend/public/public/emojione/32/1f473-1f3fd.png new file mode 100644 index 00000000..882fc3f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f473-1f3fe-2640.png new file mode 100644 index 00000000..86af928b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f473-1f3fe-2642.png new file mode 100644 index 00000000..c470757a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473-1f3fe.png b/twake/frontend/public/public/emojione/32/1f473-1f3fe.png new file mode 100644 index 00000000..c470757a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f473-1f3ff-2640.png new file mode 100644 index 00000000..2dab2eca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f473-1f3ff-2642.png new file mode 100644 index 00000000..b86d35ec Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473-1f3ff.png b/twake/frontend/public/public/emojione/32/1f473-1f3ff.png new file mode 100644 index 00000000..b86d35ec Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473-2640.png b/twake/frontend/public/public/emojione/32/1f473-2640.png new file mode 100644 index 00000000..b03dfb1f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473-2642.png b/twake/frontend/public/public/emojione/32/1f473-2642.png new file mode 100644 index 00000000..98336d21 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f473.png b/twake/frontend/public/public/emojione/32/1f473.png new file mode 100644 index 00000000..98336d21 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f473.png differ diff --git a/twake/frontend/public/public/emojione/32/1f474-1f3fb.png b/twake/frontend/public/public/emojione/32/1f474-1f3fb.png new file mode 100644 index 00000000..a7f8077d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f474-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f474-1f3fc.png b/twake/frontend/public/public/emojione/32/1f474-1f3fc.png new file mode 100644 index 00000000..f25cd959 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f474-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f474-1f3fd.png b/twake/frontend/public/public/emojione/32/1f474-1f3fd.png new file mode 100644 index 00000000..8269c215 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f474-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f474-1f3fe.png b/twake/frontend/public/public/emojione/32/1f474-1f3fe.png new file mode 100644 index 00000000..3d1b1ce9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f474-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f474-1f3ff.png b/twake/frontend/public/public/emojione/32/1f474-1f3ff.png new file mode 100644 index 00000000..4346d9b9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f474-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f474.png b/twake/frontend/public/public/emojione/32/1f474.png new file mode 100644 index 00000000..feee1c2c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f474.png differ diff --git a/twake/frontend/public/public/emojione/32/1f475-1f3fb.png b/twake/frontend/public/public/emojione/32/1f475-1f3fb.png new file mode 100644 index 00000000..b797de2c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f475-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f475-1f3fc.png b/twake/frontend/public/public/emojione/32/1f475-1f3fc.png new file mode 100644 index 00000000..0f759d66 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f475-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f475-1f3fd.png b/twake/frontend/public/public/emojione/32/1f475-1f3fd.png new file mode 100644 index 00000000..68672fb6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f475-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f475-1f3fe.png b/twake/frontend/public/public/emojione/32/1f475-1f3fe.png new file mode 100644 index 00000000..6f62a12e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f475-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f475-1f3ff.png b/twake/frontend/public/public/emojione/32/1f475-1f3ff.png new file mode 100644 index 00000000..53e5c133 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f475-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f475.png b/twake/frontend/public/public/emojione/32/1f475.png new file mode 100644 index 00000000..22b75bba Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f475.png differ diff --git a/twake/frontend/public/public/emojione/32/1f476-1f3fb.png b/twake/frontend/public/public/emojione/32/1f476-1f3fb.png new file mode 100644 index 00000000..cad8619f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f476-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f476-1f3fc.png b/twake/frontend/public/public/emojione/32/1f476-1f3fc.png new file mode 100644 index 00000000..2c690c66 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f476-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f476-1f3fd.png b/twake/frontend/public/public/emojione/32/1f476-1f3fd.png new file mode 100644 index 00000000..11c44f84 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f476-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f476-1f3fe.png b/twake/frontend/public/public/emojione/32/1f476-1f3fe.png new file mode 100644 index 00000000..b30997e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f476-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f476-1f3ff.png b/twake/frontend/public/public/emojione/32/1f476-1f3ff.png new file mode 100644 index 00000000..6ef1ab5b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f476-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f476.png b/twake/frontend/public/public/emojione/32/1f476.png new file mode 100644 index 00000000..5ac64344 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f476.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f477-1f3fb-2640.png new file mode 100644 index 00000000..28c71abb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f477-1f3fb-2642.png new file mode 100644 index 00000000..93e8f9fb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477-1f3fb.png b/twake/frontend/public/public/emojione/32/1f477-1f3fb.png new file mode 100644 index 00000000..93e8f9fb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f477-1f3fc-2640.png new file mode 100644 index 00000000..9c436f0b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f477-1f3fc-2642.png new file mode 100644 index 00000000..38dcdec3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477-1f3fc.png b/twake/frontend/public/public/emojione/32/1f477-1f3fc.png new file mode 100644 index 00000000..38dcdec3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f477-1f3fd-2640.png new file mode 100644 index 00000000..f6dd0db4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f477-1f3fd-2642.png new file mode 100644 index 00000000..b8576dc7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477-1f3fd.png b/twake/frontend/public/public/emojione/32/1f477-1f3fd.png new file mode 100644 index 00000000..b8576dc7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f477-1f3fe-2640.png new file mode 100644 index 00000000..9c2d335e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f477-1f3fe-2642.png new file mode 100644 index 00000000..8f22a425 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477-1f3fe.png b/twake/frontend/public/public/emojione/32/1f477-1f3fe.png new file mode 100644 index 00000000..8f22a425 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f477-1f3ff-2640.png new file mode 100644 index 00000000..f89cbfb1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f477-1f3ff-2642.png new file mode 100644 index 00000000..f63e97be Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477-1f3ff.png b/twake/frontend/public/public/emojione/32/1f477-1f3ff.png new file mode 100644 index 00000000..f63e97be Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477-2640.png b/twake/frontend/public/public/emojione/32/1f477-2640.png new file mode 100644 index 00000000..2ffb1a50 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477-2642.png b/twake/frontend/public/public/emojione/32/1f477-2642.png new file mode 100644 index 00000000..31e15613 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f477.png b/twake/frontend/public/public/emojione/32/1f477.png new file mode 100644 index 00000000..31e15613 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f477.png differ diff --git a/twake/frontend/public/public/emojione/32/1f478-1f3fb.png b/twake/frontend/public/public/emojione/32/1f478-1f3fb.png new file mode 100644 index 00000000..54d78e51 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f478-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f478-1f3fc.png b/twake/frontend/public/public/emojione/32/1f478-1f3fc.png new file mode 100644 index 00000000..a9e74ba5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f478-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f478-1f3fd.png b/twake/frontend/public/public/emojione/32/1f478-1f3fd.png new file mode 100644 index 00000000..b7c8a775 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f478-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f478-1f3fe.png b/twake/frontend/public/public/emojione/32/1f478-1f3fe.png new file mode 100644 index 00000000..a817b8ec Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f478-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f478-1f3ff.png b/twake/frontend/public/public/emojione/32/1f478-1f3ff.png new file mode 100644 index 00000000..0b7a2223 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f478-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f478.png b/twake/frontend/public/public/emojione/32/1f478.png new file mode 100644 index 00000000..67078046 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f478.png differ diff --git a/twake/frontend/public/public/emojione/32/1f479.png b/twake/frontend/public/public/emojione/32/1f479.png new file mode 100644 index 00000000..da036de9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f479.png differ diff --git a/twake/frontend/public/public/emojione/32/1f47a.png b/twake/frontend/public/public/emojione/32/1f47a.png new file mode 100644 index 00000000..0540b064 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f47a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f47b.png b/twake/frontend/public/public/emojione/32/1f47b.png new file mode 100644 index 00000000..230ccf9b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f47b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f47c-1f3fb.png b/twake/frontend/public/public/emojione/32/1f47c-1f3fb.png new file mode 100644 index 00000000..3fe784c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f47c-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f47c-1f3fc.png b/twake/frontend/public/public/emojione/32/1f47c-1f3fc.png new file mode 100644 index 00000000..a451c4d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f47c-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f47c-1f3fd.png b/twake/frontend/public/public/emojione/32/1f47c-1f3fd.png new file mode 100644 index 00000000..72c9c675 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f47c-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f47c-1f3fe.png b/twake/frontend/public/public/emojione/32/1f47c-1f3fe.png new file mode 100644 index 00000000..c40a1f40 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f47c-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f47c-1f3ff.png b/twake/frontend/public/public/emojione/32/1f47c-1f3ff.png new file mode 100644 index 00000000..055a9255 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f47c-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f47c.png b/twake/frontend/public/public/emojione/32/1f47c.png new file mode 100644 index 00000000..97e76a08 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f47c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f47d.png b/twake/frontend/public/public/emojione/32/1f47d.png new file mode 100644 index 00000000..a11e20ed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f47d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f47e.png b/twake/frontend/public/public/emojione/32/1f47e.png new file mode 100644 index 00000000..0dbf9411 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f47e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f47f.png b/twake/frontend/public/public/emojione/32/1f47f.png new file mode 100644 index 00000000..e885c5e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f47f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f480.png b/twake/frontend/public/public/emojione/32/1f480.png new file mode 100644 index 00000000..e7ef4507 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f480.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f481-1f3fb-2640.png new file mode 100644 index 00000000..b8539bc3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f481-1f3fb-2642.png new file mode 100644 index 00000000..4d039c76 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481-1f3fb.png b/twake/frontend/public/public/emojione/32/1f481-1f3fb.png new file mode 100644 index 00000000..7a2419e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f481-1f3fc-2640.png new file mode 100644 index 00000000..a15f339c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f481-1f3fc-2642.png new file mode 100644 index 00000000..57bfb323 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481-1f3fc.png b/twake/frontend/public/public/emojione/32/1f481-1f3fc.png new file mode 100644 index 00000000..35bd8aad Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f481-1f3fd-2640.png new file mode 100644 index 00000000..230d63fa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f481-1f3fd-2642.png new file mode 100644 index 00000000..54958ed6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481-1f3fd.png b/twake/frontend/public/public/emojione/32/1f481-1f3fd.png new file mode 100644 index 00000000..64577243 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f481-1f3fe-2640.png new file mode 100644 index 00000000..4efe9047 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f481-1f3fe-2642.png new file mode 100644 index 00000000..644b5bff Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481-1f3fe.png b/twake/frontend/public/public/emojione/32/1f481-1f3fe.png new file mode 100644 index 00000000..06015c0d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f481-1f3ff-2640.png new file mode 100644 index 00000000..7a267461 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f481-1f3ff-2642.png new file mode 100644 index 00000000..96bd11e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481-1f3ff.png b/twake/frontend/public/public/emojione/32/1f481-1f3ff.png new file mode 100644 index 00000000..e81afce9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481-2640.png b/twake/frontend/public/public/emojione/32/1f481-2640.png new file mode 100644 index 00000000..165034f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481-2642.png b/twake/frontend/public/public/emojione/32/1f481-2642.png new file mode 100644 index 00000000..f01b278d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f481.png b/twake/frontend/public/public/emojione/32/1f481.png new file mode 100644 index 00000000..165034f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f481.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f482-1f3fb-2640.png new file mode 100644 index 00000000..f07c2323 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f482-1f3fb-2642.png new file mode 100644 index 00000000..0cc20605 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482-1f3fb.png b/twake/frontend/public/public/emojione/32/1f482-1f3fb.png new file mode 100644 index 00000000..0cc20605 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f482-1f3fc-2640.png new file mode 100644 index 00000000..4dbbdc74 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f482-1f3fc-2642.png new file mode 100644 index 00000000..945f99b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482-1f3fc.png b/twake/frontend/public/public/emojione/32/1f482-1f3fc.png new file mode 100644 index 00000000..945f99b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f482-1f3fd-2640.png new file mode 100644 index 00000000..750ce2aa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f482-1f3fd-2642.png new file mode 100644 index 00000000..84943ca4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482-1f3fd.png b/twake/frontend/public/public/emojione/32/1f482-1f3fd.png new file mode 100644 index 00000000..84943ca4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f482-1f3fe-2640.png new file mode 100644 index 00000000..9f7c36b9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f482-1f3fe-2642.png new file mode 100644 index 00000000..7d5b510f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482-1f3fe.png b/twake/frontend/public/public/emojione/32/1f482-1f3fe.png new file mode 100644 index 00000000..7d5b510f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f482-1f3ff-2640.png new file mode 100644 index 00000000..fe44c407 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f482-1f3ff-2642.png new file mode 100644 index 00000000..7c420457 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482-1f3ff.png b/twake/frontend/public/public/emojione/32/1f482-1f3ff.png new file mode 100644 index 00000000..7c420457 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482-2640.png b/twake/frontend/public/public/emojione/32/1f482-2640.png new file mode 100644 index 00000000..24ffaed3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482-2642.png b/twake/frontend/public/public/emojione/32/1f482-2642.png new file mode 100644 index 00000000..447f2935 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f482.png b/twake/frontend/public/public/emojione/32/1f482.png new file mode 100644 index 00000000..447f2935 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f482.png differ diff --git a/twake/frontend/public/public/emojione/32/1f483-1f3fb.png b/twake/frontend/public/public/emojione/32/1f483-1f3fb.png new file mode 100644 index 00000000..4cd5835d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f483-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f483-1f3fc.png b/twake/frontend/public/public/emojione/32/1f483-1f3fc.png new file mode 100644 index 00000000..da1879c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f483-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f483-1f3fd.png b/twake/frontend/public/public/emojione/32/1f483-1f3fd.png new file mode 100644 index 00000000..1f1a11b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f483-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f483-1f3fe.png b/twake/frontend/public/public/emojione/32/1f483-1f3fe.png new file mode 100644 index 00000000..863a7444 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f483-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f483-1f3ff.png b/twake/frontend/public/public/emojione/32/1f483-1f3ff.png new file mode 100644 index 00000000..059205d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f483-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f483.png b/twake/frontend/public/public/emojione/32/1f483.png new file mode 100644 index 00000000..eef6b587 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f483.png differ diff --git a/twake/frontend/public/public/emojione/32/1f484.png b/twake/frontend/public/public/emojione/32/1f484.png new file mode 100644 index 00000000..f752b4dd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f484.png differ diff --git a/twake/frontend/public/public/emojione/32/1f485-1f3fb.png b/twake/frontend/public/public/emojione/32/1f485-1f3fb.png new file mode 100644 index 00000000..ef43a71a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f485-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f485-1f3fc.png b/twake/frontend/public/public/emojione/32/1f485-1f3fc.png new file mode 100644 index 00000000..8752aaed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f485-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f485-1f3fd.png b/twake/frontend/public/public/emojione/32/1f485-1f3fd.png new file mode 100644 index 00000000..290401ce Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f485-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f485-1f3fe.png b/twake/frontend/public/public/emojione/32/1f485-1f3fe.png new file mode 100644 index 00000000..e84323a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f485-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f485-1f3ff.png b/twake/frontend/public/public/emojione/32/1f485-1f3ff.png new file mode 100644 index 00000000..84fd6634 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f485-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f485.png b/twake/frontend/public/public/emojione/32/1f485.png new file mode 100644 index 00000000..04ce9234 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f485.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f486-1f3fb-2640.png new file mode 100644 index 00000000..2544a4a2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f486-1f3fb-2642.png new file mode 100644 index 00000000..20ea3144 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486-1f3fb.png b/twake/frontend/public/public/emojione/32/1f486-1f3fb.png new file mode 100644 index 00000000..48414c07 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f486-1f3fc-2640.png new file mode 100644 index 00000000..c7795e80 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f486-1f3fc-2642.png new file mode 100644 index 00000000..a69aeccc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486-1f3fc.png b/twake/frontend/public/public/emojione/32/1f486-1f3fc.png new file mode 100644 index 00000000..99b18af8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f486-1f3fd-2640.png new file mode 100644 index 00000000..1f95a440 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f486-1f3fd-2642.png new file mode 100644 index 00000000..a32b1e21 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486-1f3fd.png b/twake/frontend/public/public/emojione/32/1f486-1f3fd.png new file mode 100644 index 00000000..38e0f40f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f486-1f3fe-2640.png new file mode 100644 index 00000000..3ed98fc4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f486-1f3fe-2642.png new file mode 100644 index 00000000..f3a17471 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486-1f3fe.png b/twake/frontend/public/public/emojione/32/1f486-1f3fe.png new file mode 100644 index 00000000..1096d6bb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f486-1f3ff-2640.png new file mode 100644 index 00000000..7bfdf9fc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f486-1f3ff-2642.png new file mode 100644 index 00000000..8ea60cbc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486-1f3ff.png b/twake/frontend/public/public/emojione/32/1f486-1f3ff.png new file mode 100644 index 00000000..1af67020 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486-2640.png b/twake/frontend/public/public/emojione/32/1f486-2640.png new file mode 100644 index 00000000..7cadb890 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486-2642.png b/twake/frontend/public/public/emojione/32/1f486-2642.png new file mode 100644 index 00000000..85effd36 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f486.png b/twake/frontend/public/public/emojione/32/1f486.png new file mode 100644 index 00000000..7cadb890 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f486.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f487-1f3fb-2640.png new file mode 100644 index 00000000..f7aa44c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f487-1f3fb-2642.png new file mode 100644 index 00000000..68261eca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487-1f3fb.png b/twake/frontend/public/public/emojione/32/1f487-1f3fb.png new file mode 100644 index 00000000..6e275a37 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f487-1f3fc-2640.png new file mode 100644 index 00000000..e2cd3292 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f487-1f3fc-2642.png new file mode 100644 index 00000000..68d6d92f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487-1f3fc.png b/twake/frontend/public/public/emojione/32/1f487-1f3fc.png new file mode 100644 index 00000000..447f71a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f487-1f3fd-2640.png new file mode 100644 index 00000000..615b0ba8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f487-1f3fd-2642.png new file mode 100644 index 00000000..2e31cfb0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487-1f3fd.png b/twake/frontend/public/public/emojione/32/1f487-1f3fd.png new file mode 100644 index 00000000..07223005 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f487-1f3fe-2640.png new file mode 100644 index 00000000..07090c9f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f487-1f3fe-2642.png new file mode 100644 index 00000000..717d4b7b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487-1f3fe.png b/twake/frontend/public/public/emojione/32/1f487-1f3fe.png new file mode 100644 index 00000000..5432074a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f487-1f3ff-2640.png new file mode 100644 index 00000000..2bf015cb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f487-1f3ff-2642.png new file mode 100644 index 00000000..d82ec1be Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487-1f3ff.png b/twake/frontend/public/public/emojione/32/1f487-1f3ff.png new file mode 100644 index 00000000..378bada5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487-2640.png b/twake/frontend/public/public/emojione/32/1f487-2640.png new file mode 100644 index 00000000..c464fc88 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487-2642.png b/twake/frontend/public/public/emojione/32/1f487-2642.png new file mode 100644 index 00000000..9d0b2418 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f487.png b/twake/frontend/public/public/emojione/32/1f487.png new file mode 100644 index 00000000..c464fc88 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f487.png differ diff --git a/twake/frontend/public/public/emojione/32/1f488.png b/twake/frontend/public/public/emojione/32/1f488.png new file mode 100644 index 00000000..ab0c9fc7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f488.png differ diff --git a/twake/frontend/public/public/emojione/32/1f489.png b/twake/frontend/public/public/emojione/32/1f489.png new file mode 100644 index 00000000..d21a1c03 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f489.png differ diff --git a/twake/frontend/public/public/emojione/32/1f48a.png b/twake/frontend/public/public/emojione/32/1f48a.png new file mode 100644 index 00000000..0537da0d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f48a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f48b.png b/twake/frontend/public/public/emojione/32/1f48b.png new file mode 100644 index 00000000..2e3e0d37 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f48b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f48c.png b/twake/frontend/public/public/emojione/32/1f48c.png new file mode 100644 index 00000000..2247cde3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f48c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f48d.png b/twake/frontend/public/public/emojione/32/1f48d.png new file mode 100644 index 00000000..90603f58 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f48d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f48e.png b/twake/frontend/public/public/emojione/32/1f48e.png new file mode 100644 index 00000000..59133e73 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f48e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f48f.png b/twake/frontend/public/public/emojione/32/1f48f.png new file mode 100644 index 00000000..12a952ca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f48f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f490.png b/twake/frontend/public/public/emojione/32/1f490.png new file mode 100644 index 00000000..ce1fa798 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f490.png differ diff --git a/twake/frontend/public/public/emojione/32/1f491.png b/twake/frontend/public/public/emojione/32/1f491.png new file mode 100644 index 00000000..343322e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f491.png differ diff --git a/twake/frontend/public/public/emojione/32/1f492.png b/twake/frontend/public/public/emojione/32/1f492.png new file mode 100644 index 00000000..c7697e43 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f492.png differ diff --git a/twake/frontend/public/public/emojione/32/1f493.png b/twake/frontend/public/public/emojione/32/1f493.png new file mode 100644 index 00000000..4152c640 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f493.png differ diff --git a/twake/frontend/public/public/emojione/32/1f494.png b/twake/frontend/public/public/emojione/32/1f494.png new file mode 100644 index 00000000..b98e3c1d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f494.png differ diff --git a/twake/frontend/public/public/emojione/32/1f495.png b/twake/frontend/public/public/emojione/32/1f495.png new file mode 100644 index 00000000..3a89bc5d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f495.png differ diff --git a/twake/frontend/public/public/emojione/32/1f496.png b/twake/frontend/public/public/emojione/32/1f496.png new file mode 100644 index 00000000..115851f3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f496.png differ diff --git a/twake/frontend/public/public/emojione/32/1f497.png b/twake/frontend/public/public/emojione/32/1f497.png new file mode 100644 index 00000000..6d58fb30 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f497.png differ diff --git a/twake/frontend/public/public/emojione/32/1f498.png b/twake/frontend/public/public/emojione/32/1f498.png new file mode 100644 index 00000000..7685018f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f498.png differ diff --git a/twake/frontend/public/public/emojione/32/1f499.png b/twake/frontend/public/public/emojione/32/1f499.png new file mode 100644 index 00000000..b7b01de3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f499.png differ diff --git a/twake/frontend/public/public/emojione/32/1f49a.png b/twake/frontend/public/public/emojione/32/1f49a.png new file mode 100644 index 00000000..38682de8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f49a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f49b.png b/twake/frontend/public/public/emojione/32/1f49b.png new file mode 100644 index 00000000..df15456a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f49b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f49c.png b/twake/frontend/public/public/emojione/32/1f49c.png new file mode 100644 index 00000000..5bc89dcc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f49c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f49d.png b/twake/frontend/public/public/emojione/32/1f49d.png new file mode 100644 index 00000000..143e851a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f49d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f49e.png b/twake/frontend/public/public/emojione/32/1f49e.png new file mode 100644 index 00000000..e94b6d34 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f49e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f49f.png b/twake/frontend/public/public/emojione/32/1f49f.png new file mode 100644 index 00000000..e87d0346 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f49f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4a0.png b/twake/frontend/public/public/emojione/32/1f4a0.png new file mode 100644 index 00000000..27d65cab Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4a0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4a1.png b/twake/frontend/public/public/emojione/32/1f4a1.png new file mode 100644 index 00000000..d35c53a8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4a1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4a2.png b/twake/frontend/public/public/emojione/32/1f4a2.png new file mode 100644 index 00000000..c88755f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4a2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4a3.png b/twake/frontend/public/public/emojione/32/1f4a3.png new file mode 100644 index 00000000..c11a7991 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4a3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4a4.png b/twake/frontend/public/public/emojione/32/1f4a4.png new file mode 100644 index 00000000..bc538b17 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4a4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4a5.png b/twake/frontend/public/public/emojione/32/1f4a5.png new file mode 100644 index 00000000..a8d4a965 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4a5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4a6.png b/twake/frontend/public/public/emojione/32/1f4a6.png new file mode 100644 index 00000000..05f1b2c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4a6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4a7.png b/twake/frontend/public/public/emojione/32/1f4a7.png new file mode 100644 index 00000000..b6f4e152 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4a7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4a8.png b/twake/frontend/public/public/emojione/32/1f4a8.png new file mode 100644 index 00000000..7095cd1b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4a8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4a9.png b/twake/frontend/public/public/emojione/32/1f4a9.png new file mode 100644 index 00000000..0d32189a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4a9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4aa-1f3fb.png b/twake/frontend/public/public/emojione/32/1f4aa-1f3fb.png new file mode 100644 index 00000000..a4503014 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4aa-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4aa-1f3fc.png b/twake/frontend/public/public/emojione/32/1f4aa-1f3fc.png new file mode 100644 index 00000000..9c99a07d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4aa-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4aa-1f3fd.png b/twake/frontend/public/public/emojione/32/1f4aa-1f3fd.png new file mode 100644 index 00000000..6f55f2cb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4aa-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4aa-1f3fe.png b/twake/frontend/public/public/emojione/32/1f4aa-1f3fe.png new file mode 100644 index 00000000..68e0de35 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4aa-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4aa-1f3ff.png b/twake/frontend/public/public/emojione/32/1f4aa-1f3ff.png new file mode 100644 index 00000000..c2572fe6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4aa-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4aa.png b/twake/frontend/public/public/emojione/32/1f4aa.png new file mode 100644 index 00000000..f20f4bf5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4aa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4ab.png b/twake/frontend/public/public/emojione/32/1f4ab.png new file mode 100644 index 00000000..2108c21d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4ab.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4ac.png b/twake/frontend/public/public/emojione/32/1f4ac.png new file mode 100644 index 00000000..4168918c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4ac.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4ad.png b/twake/frontend/public/public/emojione/32/1f4ad.png new file mode 100644 index 00000000..ceae2227 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4ad.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4ae.png b/twake/frontend/public/public/emojione/32/1f4ae.png new file mode 100644 index 00000000..f0a00963 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4ae.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4af.png b/twake/frontend/public/public/emojione/32/1f4af.png new file mode 100644 index 00000000..b7f789d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4af.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4b0.png b/twake/frontend/public/public/emojione/32/1f4b0.png new file mode 100644 index 00000000..ef91fb1a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4b0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4b1.png b/twake/frontend/public/public/emojione/32/1f4b1.png new file mode 100644 index 00000000..1bc361a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4b1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4b2.png b/twake/frontend/public/public/emojione/32/1f4b2.png new file mode 100644 index 00000000..e9b2237e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4b2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4b3.png b/twake/frontend/public/public/emojione/32/1f4b3.png new file mode 100644 index 00000000..42db78a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4b3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4b4.png b/twake/frontend/public/public/emojione/32/1f4b4.png new file mode 100644 index 00000000..705299ec Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4b4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4b5.png b/twake/frontend/public/public/emojione/32/1f4b5.png new file mode 100644 index 00000000..4f32d259 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4b5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4b6.png b/twake/frontend/public/public/emojione/32/1f4b6.png new file mode 100644 index 00000000..745aca6f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4b6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4b7.png b/twake/frontend/public/public/emojione/32/1f4b7.png new file mode 100644 index 00000000..c077b20d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4b7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4b8.png b/twake/frontend/public/public/emojione/32/1f4b8.png new file mode 100644 index 00000000..b59b3f43 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4b8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4b9.png b/twake/frontend/public/public/emojione/32/1f4b9.png new file mode 100644 index 00000000..43a28160 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4b9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4ba.png b/twake/frontend/public/public/emojione/32/1f4ba.png new file mode 100644 index 00000000..2c2e79c5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4ba.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4bb.png b/twake/frontend/public/public/emojione/32/1f4bb.png new file mode 100644 index 00000000..2da8c3f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4bc.png b/twake/frontend/public/public/emojione/32/1f4bc.png new file mode 100644 index 00000000..e18b49c9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4bd.png b/twake/frontend/public/public/emojione/32/1f4bd.png new file mode 100644 index 00000000..4e09bc21 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4bd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4be.png b/twake/frontend/public/public/emojione/32/1f4be.png new file mode 100644 index 00000000..0a3e7264 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4be.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4bf.png b/twake/frontend/public/public/emojione/32/1f4bf.png new file mode 100644 index 00000000..7e8773e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4bf.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4c0.png b/twake/frontend/public/public/emojione/32/1f4c0.png new file mode 100644 index 00000000..1c8e4453 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4c0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4c1.png b/twake/frontend/public/public/emojione/32/1f4c1.png new file mode 100644 index 00000000..5eb0d46d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4c1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4c2.png b/twake/frontend/public/public/emojione/32/1f4c2.png new file mode 100644 index 00000000..68b381bd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4c2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4c3.png b/twake/frontend/public/public/emojione/32/1f4c3.png new file mode 100644 index 00000000..082ff6f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4c3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4c4.png b/twake/frontend/public/public/emojione/32/1f4c4.png new file mode 100644 index 00000000..7dc5ca05 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4c4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4c5.png b/twake/frontend/public/public/emojione/32/1f4c5.png new file mode 100644 index 00000000..e250b7c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4c5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4c6.png b/twake/frontend/public/public/emojione/32/1f4c6.png new file mode 100644 index 00000000..11f26163 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4c6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4c7.png b/twake/frontend/public/public/emojione/32/1f4c7.png new file mode 100644 index 00000000..ed6b60a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4c7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4c8.png b/twake/frontend/public/public/emojione/32/1f4c8.png new file mode 100644 index 00000000..ca8bade4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4c8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4c9.png b/twake/frontend/public/public/emojione/32/1f4c9.png new file mode 100644 index 00000000..81f4603a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4c9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4ca.png b/twake/frontend/public/public/emojione/32/1f4ca.png new file mode 100644 index 00000000..3532fc65 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4ca.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4cb.png b/twake/frontend/public/public/emojione/32/1f4cb.png new file mode 100644 index 00000000..1c5095b4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4cb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4cc.png b/twake/frontend/public/public/emojione/32/1f4cc.png new file mode 100644 index 00000000..07ac8bd4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4cc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4cd.png b/twake/frontend/public/public/emojione/32/1f4cd.png new file mode 100644 index 00000000..7f9f5f82 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4cd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4ce.png b/twake/frontend/public/public/emojione/32/1f4ce.png new file mode 100644 index 00000000..7ed3cdcc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4ce.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4cf.png b/twake/frontend/public/public/emojione/32/1f4cf.png new file mode 100644 index 00000000..282638fb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4cf.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4d0.png b/twake/frontend/public/public/emojione/32/1f4d0.png new file mode 100644 index 00000000..09689467 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4d0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4d1.png b/twake/frontend/public/public/emojione/32/1f4d1.png new file mode 100644 index 00000000..b8abc608 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4d1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4d2.png b/twake/frontend/public/public/emojione/32/1f4d2.png new file mode 100644 index 00000000..9173b04c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4d2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4d3.png b/twake/frontend/public/public/emojione/32/1f4d3.png new file mode 100644 index 00000000..6f8fe9f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4d3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4d4.png b/twake/frontend/public/public/emojione/32/1f4d4.png new file mode 100644 index 00000000..1950704a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4d4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4d5.png b/twake/frontend/public/public/emojione/32/1f4d5.png new file mode 100644 index 00000000..0160f96b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4d5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4d6.png b/twake/frontend/public/public/emojione/32/1f4d6.png new file mode 100644 index 00000000..47334d6b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4d6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4d7.png b/twake/frontend/public/public/emojione/32/1f4d7.png new file mode 100644 index 00000000..8cf421da Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4d7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4d8.png b/twake/frontend/public/public/emojione/32/1f4d8.png new file mode 100644 index 00000000..3be90f6d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4d8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4d9.png b/twake/frontend/public/public/emojione/32/1f4d9.png new file mode 100644 index 00000000..fe9b31e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4d9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4da.png b/twake/frontend/public/public/emojione/32/1f4da.png new file mode 100644 index 00000000..2769ff2c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4da.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4db.png b/twake/frontend/public/public/emojione/32/1f4db.png new file mode 100644 index 00000000..986e12d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4db.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4dc.png b/twake/frontend/public/public/emojione/32/1f4dc.png new file mode 100644 index 00000000..0270146c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4dc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4dd.png b/twake/frontend/public/public/emojione/32/1f4dd.png new file mode 100644 index 00000000..29e8d014 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4dd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4de.png b/twake/frontend/public/public/emojione/32/1f4de.png new file mode 100644 index 00000000..8e919161 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4de.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4df.png b/twake/frontend/public/public/emojione/32/1f4df.png new file mode 100644 index 00000000..6a81f7f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4df.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4e0.png b/twake/frontend/public/public/emojione/32/1f4e0.png new file mode 100644 index 00000000..5df9577d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4e0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4e1.png b/twake/frontend/public/public/emojione/32/1f4e1.png new file mode 100644 index 00000000..74ac33dc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4e1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4e2.png b/twake/frontend/public/public/emojione/32/1f4e2.png new file mode 100644 index 00000000..6bdcc71e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4e2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4e3.png b/twake/frontend/public/public/emojione/32/1f4e3.png new file mode 100644 index 00000000..783f1d22 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4e3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4e4.png b/twake/frontend/public/public/emojione/32/1f4e4.png new file mode 100644 index 00000000..7879b0e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4e4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4e5.png b/twake/frontend/public/public/emojione/32/1f4e5.png new file mode 100644 index 00000000..5a570332 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4e5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4e6.png b/twake/frontend/public/public/emojione/32/1f4e6.png new file mode 100644 index 00000000..d7ea3766 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4e7.png b/twake/frontend/public/public/emojione/32/1f4e7.png new file mode 100644 index 00000000..b714fb5a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4e7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4e8.png b/twake/frontend/public/public/emojione/32/1f4e8.png new file mode 100644 index 00000000..a3cc55d3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4e8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4e9.png b/twake/frontend/public/public/emojione/32/1f4e9.png new file mode 100644 index 00000000..ec2e64e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4e9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4ea.png b/twake/frontend/public/public/emojione/32/1f4ea.png new file mode 100644 index 00000000..a4b54c00 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4eb.png b/twake/frontend/public/public/emojione/32/1f4eb.png new file mode 100644 index 00000000..7b4daf3c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4ec.png b/twake/frontend/public/public/emojione/32/1f4ec.png new file mode 100644 index 00000000..30745c19 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4ed.png b/twake/frontend/public/public/emojione/32/1f4ed.png new file mode 100644 index 00000000..c66df33d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4ee.png b/twake/frontend/public/public/emojione/32/1f4ee.png new file mode 100644 index 00000000..fd6ee930 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4ee.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4ef.png b/twake/frontend/public/public/emojione/32/1f4ef.png new file mode 100644 index 00000000..dabb4ef5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4ef.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4f0.png b/twake/frontend/public/public/emojione/32/1f4f0.png new file mode 100644 index 00000000..b08ae215 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4f0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4f1.png b/twake/frontend/public/public/emojione/32/1f4f1.png new file mode 100644 index 00000000..73ad6ef2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4f1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4f2.png b/twake/frontend/public/public/emojione/32/1f4f2.png new file mode 100644 index 00000000..468848ab Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4f3.png b/twake/frontend/public/public/emojione/32/1f4f3.png new file mode 100644 index 00000000..c041a891 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4f4.png b/twake/frontend/public/public/emojione/32/1f4f4.png new file mode 100644 index 00000000..fb337522 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4f4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4f5.png b/twake/frontend/public/public/emojione/32/1f4f5.png new file mode 100644 index 00000000..5bbae0b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4f5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4f6.png b/twake/frontend/public/public/emojione/32/1f4f6.png new file mode 100644 index 00000000..978155d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4f6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4f7.png b/twake/frontend/public/public/emojione/32/1f4f7.png new file mode 100644 index 00000000..97e4848d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4f8.png b/twake/frontend/public/public/emojione/32/1f4f8.png new file mode 100644 index 00000000..d41e08e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4f8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4f9.png b/twake/frontend/public/public/emojione/32/1f4f9.png new file mode 100644 index 00000000..85a8cf5f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4f9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4fa.png b/twake/frontend/public/public/emojione/32/1f4fa.png new file mode 100644 index 00000000..10753412 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4fa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4fb.png b/twake/frontend/public/public/emojione/32/1f4fb.png new file mode 100644 index 00000000..98d6f0c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4fc.png b/twake/frontend/public/public/emojione/32/1f4fc.png new file mode 100644 index 00000000..440165fa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4fd.png b/twake/frontend/public/public/emojione/32/1f4fd.png new file mode 100644 index 00000000..b94e4b5c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f4ff.png b/twake/frontend/public/public/emojione/32/1f4ff.png new file mode 100644 index 00000000..f2dd5298 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f4ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f500.png b/twake/frontend/public/public/emojione/32/1f500.png new file mode 100644 index 00000000..bd7fcf06 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f500.png differ diff --git a/twake/frontend/public/public/emojione/32/1f501.png b/twake/frontend/public/public/emojione/32/1f501.png new file mode 100644 index 00000000..7ff93d49 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f501.png differ diff --git a/twake/frontend/public/public/emojione/32/1f502.png b/twake/frontend/public/public/emojione/32/1f502.png new file mode 100644 index 00000000..a8da12f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f502.png differ diff --git a/twake/frontend/public/public/emojione/32/1f503.png b/twake/frontend/public/public/emojione/32/1f503.png new file mode 100644 index 00000000..65444b1f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f503.png differ diff --git a/twake/frontend/public/public/emojione/32/1f504.png b/twake/frontend/public/public/emojione/32/1f504.png new file mode 100644 index 00000000..5d7aa605 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f504.png differ diff --git a/twake/frontend/public/public/emojione/32/1f505.png b/twake/frontend/public/public/emojione/32/1f505.png new file mode 100644 index 00000000..ac4211a8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f505.png differ diff --git a/twake/frontend/public/public/emojione/32/1f506.png b/twake/frontend/public/public/emojione/32/1f506.png new file mode 100644 index 00000000..7ba1aa31 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f506.png differ diff --git a/twake/frontend/public/public/emojione/32/1f507.png b/twake/frontend/public/public/emojione/32/1f507.png new file mode 100644 index 00000000..5d22487a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f507.png differ diff --git a/twake/frontend/public/public/emojione/32/1f508.png b/twake/frontend/public/public/emojione/32/1f508.png new file mode 100644 index 00000000..e8fa908e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f508.png differ diff --git a/twake/frontend/public/public/emojione/32/1f509.png b/twake/frontend/public/public/emojione/32/1f509.png new file mode 100644 index 00000000..942688b7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f509.png differ diff --git a/twake/frontend/public/public/emojione/32/1f50a.png b/twake/frontend/public/public/emojione/32/1f50a.png new file mode 100644 index 00000000..6b70553a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f50a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f50b.png b/twake/frontend/public/public/emojione/32/1f50b.png new file mode 100644 index 00000000..f6b019ab Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f50b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f50c.png b/twake/frontend/public/public/emojione/32/1f50c.png new file mode 100644 index 00000000..f1f26e3f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f50c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f50d.png b/twake/frontend/public/public/emojione/32/1f50d.png new file mode 100644 index 00000000..8dbae49f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f50d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f50e.png b/twake/frontend/public/public/emojione/32/1f50e.png new file mode 100644 index 00000000..f1a4572b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f50e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f50f.png b/twake/frontend/public/public/emojione/32/1f50f.png new file mode 100644 index 00000000..fa69f177 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f50f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f510.png b/twake/frontend/public/public/emojione/32/1f510.png new file mode 100644 index 00000000..2dfcad82 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f510.png differ diff --git a/twake/frontend/public/public/emojione/32/1f511.png b/twake/frontend/public/public/emojione/32/1f511.png new file mode 100644 index 00000000..90ce4d04 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f511.png differ diff --git a/twake/frontend/public/public/emojione/32/1f512.png b/twake/frontend/public/public/emojione/32/1f512.png new file mode 100644 index 00000000..41cf8076 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f512.png differ diff --git a/twake/frontend/public/public/emojione/32/1f513.png b/twake/frontend/public/public/emojione/32/1f513.png new file mode 100644 index 00000000..412117bd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f513.png differ diff --git a/twake/frontend/public/public/emojione/32/1f514.png b/twake/frontend/public/public/emojione/32/1f514.png new file mode 100644 index 00000000..0873c74e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f514.png differ diff --git a/twake/frontend/public/public/emojione/32/1f515.png b/twake/frontend/public/public/emojione/32/1f515.png new file mode 100644 index 00000000..9d1bcacd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f515.png differ diff --git a/twake/frontend/public/public/emojione/32/1f516.png b/twake/frontend/public/public/emojione/32/1f516.png new file mode 100644 index 00000000..b2c60229 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f516.png differ diff --git a/twake/frontend/public/public/emojione/32/1f517.png b/twake/frontend/public/public/emojione/32/1f517.png new file mode 100644 index 00000000..8bae446b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f517.png differ diff --git a/twake/frontend/public/public/emojione/32/1f518.png b/twake/frontend/public/public/emojione/32/1f518.png new file mode 100644 index 00000000..c8687ce4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f518.png differ diff --git a/twake/frontend/public/public/emojione/32/1f519.png b/twake/frontend/public/public/emojione/32/1f519.png new file mode 100644 index 00000000..d5feb9e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f519.png differ diff --git a/twake/frontend/public/public/emojione/32/1f51a.png b/twake/frontend/public/public/emojione/32/1f51a.png new file mode 100644 index 00000000..3910e4d3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f51a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f51b.png b/twake/frontend/public/public/emojione/32/1f51b.png new file mode 100644 index 00000000..0df7dba5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f51b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f51c.png b/twake/frontend/public/public/emojione/32/1f51c.png new file mode 100644 index 00000000..79a94632 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f51c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f51d.png b/twake/frontend/public/public/emojione/32/1f51d.png new file mode 100644 index 00000000..5284cd54 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f51d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f51e.png b/twake/frontend/public/public/emojione/32/1f51e.png new file mode 100644 index 00000000..f4c9d6b7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f51e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f51f.png b/twake/frontend/public/public/emojione/32/1f51f.png new file mode 100644 index 00000000..aa38fbfb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f51f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f520.png b/twake/frontend/public/public/emojione/32/1f520.png new file mode 100644 index 00000000..a8248c80 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f520.png differ diff --git a/twake/frontend/public/public/emojione/32/1f521.png b/twake/frontend/public/public/emojione/32/1f521.png new file mode 100644 index 00000000..243ee014 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f521.png differ diff --git a/twake/frontend/public/public/emojione/32/1f522.png b/twake/frontend/public/public/emojione/32/1f522.png new file mode 100644 index 00000000..49156ce5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f522.png differ diff --git a/twake/frontend/public/public/emojione/32/1f523.png b/twake/frontend/public/public/emojione/32/1f523.png new file mode 100644 index 00000000..08ab2039 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f523.png differ diff --git a/twake/frontend/public/public/emojione/32/1f524.png b/twake/frontend/public/public/emojione/32/1f524.png new file mode 100644 index 00000000..d0b47198 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f524.png differ diff --git a/twake/frontend/public/public/emojione/32/1f525.png b/twake/frontend/public/public/emojione/32/1f525.png new file mode 100644 index 00000000..bee79dc1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f525.png differ diff --git a/twake/frontend/public/public/emojione/32/1f526.png b/twake/frontend/public/public/emojione/32/1f526.png new file mode 100644 index 00000000..00b90d1d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f526.png differ diff --git a/twake/frontend/public/public/emojione/32/1f527.png b/twake/frontend/public/public/emojione/32/1f527.png new file mode 100644 index 00000000..fe6ee924 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f527.png differ diff --git a/twake/frontend/public/public/emojione/32/1f528.png b/twake/frontend/public/public/emojione/32/1f528.png new file mode 100644 index 00000000..cb111243 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f528.png differ diff --git a/twake/frontend/public/public/emojione/32/1f529.png b/twake/frontend/public/public/emojione/32/1f529.png new file mode 100644 index 00000000..19b10544 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f529.png differ diff --git a/twake/frontend/public/public/emojione/32/1f52a.png b/twake/frontend/public/public/emojione/32/1f52a.png new file mode 100644 index 00000000..076453db Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f52a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f52b.png b/twake/frontend/public/public/emojione/32/1f52b.png new file mode 100644 index 00000000..ec643b50 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f52b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f52c.png b/twake/frontend/public/public/emojione/32/1f52c.png new file mode 100644 index 00000000..a062de0f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f52c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f52d.png b/twake/frontend/public/public/emojione/32/1f52d.png new file mode 100644 index 00000000..43ab29e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f52d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f52e.png b/twake/frontend/public/public/emojione/32/1f52e.png new file mode 100644 index 00000000..2dea3494 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f52e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f52f.png b/twake/frontend/public/public/emojione/32/1f52f.png new file mode 100644 index 00000000..0cc89e01 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f52f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f530.png b/twake/frontend/public/public/emojione/32/1f530.png new file mode 100644 index 00000000..c125550c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f530.png differ diff --git a/twake/frontend/public/public/emojione/32/1f531.png b/twake/frontend/public/public/emojione/32/1f531.png new file mode 100644 index 00000000..9609ef34 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f531.png differ diff --git a/twake/frontend/public/public/emojione/32/1f532.png b/twake/frontend/public/public/emojione/32/1f532.png new file mode 100644 index 00000000..50202987 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f532.png differ diff --git a/twake/frontend/public/public/emojione/32/1f533.png b/twake/frontend/public/public/emojione/32/1f533.png new file mode 100644 index 00000000..1f0f7fca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f533.png differ diff --git a/twake/frontend/public/public/emojione/32/1f534.png b/twake/frontend/public/public/emojione/32/1f534.png new file mode 100644 index 00000000..c852dca1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f534.png differ diff --git a/twake/frontend/public/public/emojione/32/1f535.png b/twake/frontend/public/public/emojione/32/1f535.png new file mode 100644 index 00000000..04bd8c65 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f535.png differ diff --git a/twake/frontend/public/public/emojione/32/1f536.png b/twake/frontend/public/public/emojione/32/1f536.png new file mode 100644 index 00000000..d3c30e99 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f536.png differ diff --git a/twake/frontend/public/public/emojione/32/1f537.png b/twake/frontend/public/public/emojione/32/1f537.png new file mode 100644 index 00000000..be9f5fdb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f537.png differ diff --git a/twake/frontend/public/public/emojione/32/1f538.png b/twake/frontend/public/public/emojione/32/1f538.png new file mode 100644 index 00000000..befd9efa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f538.png differ diff --git a/twake/frontend/public/public/emojione/32/1f539.png b/twake/frontend/public/public/emojione/32/1f539.png new file mode 100644 index 00000000..9c4165e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f539.png differ diff --git a/twake/frontend/public/public/emojione/32/1f53a.png b/twake/frontend/public/public/emojione/32/1f53a.png new file mode 100644 index 00000000..7c8ea1b7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f53a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f53b.png b/twake/frontend/public/public/emojione/32/1f53b.png new file mode 100644 index 00000000..49948aad Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f53b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f53c.png b/twake/frontend/public/public/emojione/32/1f53c.png new file mode 100644 index 00000000..aefcf96b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f53c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f53d.png b/twake/frontend/public/public/emojione/32/1f53d.png new file mode 100644 index 00000000..403c5a30 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f53d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f549.png b/twake/frontend/public/public/emojione/32/1f549.png new file mode 100644 index 00000000..fa5c53ea Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f549.png differ diff --git a/twake/frontend/public/public/emojione/32/1f54a.png b/twake/frontend/public/public/emojione/32/1f54a.png new file mode 100644 index 00000000..728df5f9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f54a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f54b.png b/twake/frontend/public/public/emojione/32/1f54b.png new file mode 100644 index 00000000..d6be78ea Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f54b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f54c.png b/twake/frontend/public/public/emojione/32/1f54c.png new file mode 100644 index 00000000..8e4823c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f54c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f54d.png b/twake/frontend/public/public/emojione/32/1f54d.png new file mode 100644 index 00000000..b7bfe748 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f54d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f54e.png b/twake/frontend/public/public/emojione/32/1f54e.png new file mode 100644 index 00000000..1e8f626f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f54e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f550.png b/twake/frontend/public/public/emojione/32/1f550.png new file mode 100644 index 00000000..b5dada99 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f550.png differ diff --git a/twake/frontend/public/public/emojione/32/1f551.png b/twake/frontend/public/public/emojione/32/1f551.png new file mode 100644 index 00000000..e9b6c0bf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f551.png differ diff --git a/twake/frontend/public/public/emojione/32/1f552.png b/twake/frontend/public/public/emojione/32/1f552.png new file mode 100644 index 00000000..3588d89b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f552.png differ diff --git a/twake/frontend/public/public/emojione/32/1f553.png b/twake/frontend/public/public/emojione/32/1f553.png new file mode 100644 index 00000000..17ef24aa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f553.png differ diff --git a/twake/frontend/public/public/emojione/32/1f554.png b/twake/frontend/public/public/emojione/32/1f554.png new file mode 100644 index 00000000..3953be3f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f554.png differ diff --git a/twake/frontend/public/public/emojione/32/1f555.png b/twake/frontend/public/public/emojione/32/1f555.png new file mode 100644 index 00000000..c8d8da17 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f555.png differ diff --git a/twake/frontend/public/public/emojione/32/1f556.png b/twake/frontend/public/public/emojione/32/1f556.png new file mode 100644 index 00000000..a46d63bd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f556.png differ diff --git a/twake/frontend/public/public/emojione/32/1f557.png b/twake/frontend/public/public/emojione/32/1f557.png new file mode 100644 index 00000000..7a35f8ae Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f557.png differ diff --git a/twake/frontend/public/public/emojione/32/1f558.png b/twake/frontend/public/public/emojione/32/1f558.png new file mode 100644 index 00000000..8c372e32 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f558.png differ diff --git a/twake/frontend/public/public/emojione/32/1f559.png b/twake/frontend/public/public/emojione/32/1f559.png new file mode 100644 index 00000000..08eddcda Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f559.png differ diff --git a/twake/frontend/public/public/emojione/32/1f55a.png b/twake/frontend/public/public/emojione/32/1f55a.png new file mode 100644 index 00000000..7c1933e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f55a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f55b.png b/twake/frontend/public/public/emojione/32/1f55b.png new file mode 100644 index 00000000..21c3eff8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f55b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f55c.png b/twake/frontend/public/public/emojione/32/1f55c.png new file mode 100644 index 00000000..e093d2a6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f55c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f55d.png b/twake/frontend/public/public/emojione/32/1f55d.png new file mode 100644 index 00000000..f20d8772 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f55d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f55e.png b/twake/frontend/public/public/emojione/32/1f55e.png new file mode 100644 index 00000000..306c96d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f55e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f55f.png b/twake/frontend/public/public/emojione/32/1f55f.png new file mode 100644 index 00000000..f92dacf3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f55f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f560.png b/twake/frontend/public/public/emojione/32/1f560.png new file mode 100644 index 00000000..94421001 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f560.png differ diff --git a/twake/frontend/public/public/emojione/32/1f561.png b/twake/frontend/public/public/emojione/32/1f561.png new file mode 100644 index 00000000..06169522 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f561.png differ diff --git a/twake/frontend/public/public/emojione/32/1f562.png b/twake/frontend/public/public/emojione/32/1f562.png new file mode 100644 index 00000000..3c94d6ac Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f562.png differ diff --git a/twake/frontend/public/public/emojione/32/1f563.png b/twake/frontend/public/public/emojione/32/1f563.png new file mode 100644 index 00000000..209385f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f563.png differ diff --git a/twake/frontend/public/public/emojione/32/1f564.png b/twake/frontend/public/public/emojione/32/1f564.png new file mode 100644 index 00000000..ec2d8603 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f564.png differ diff --git a/twake/frontend/public/public/emojione/32/1f565.png b/twake/frontend/public/public/emojione/32/1f565.png new file mode 100644 index 00000000..a159d3ce Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f565.png differ diff --git a/twake/frontend/public/public/emojione/32/1f566.png b/twake/frontend/public/public/emojione/32/1f566.png new file mode 100644 index 00000000..4dce77fc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f566.png differ diff --git a/twake/frontend/public/public/emojione/32/1f567.png b/twake/frontend/public/public/emojione/32/1f567.png new file mode 100644 index 00000000..0c3d4204 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f567.png differ diff --git a/twake/frontend/public/public/emojione/32/1f56f.png b/twake/frontend/public/public/emojione/32/1f56f.png new file mode 100644 index 00000000..c3521a5b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f56f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f570.png b/twake/frontend/public/public/emojione/32/1f570.png new file mode 100644 index 00000000..7c732700 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f570.png differ diff --git a/twake/frontend/public/public/emojione/32/1f573.png b/twake/frontend/public/public/emojione/32/1f573.png new file mode 100644 index 00000000..a8d9a1e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f573.png differ diff --git a/twake/frontend/public/public/emojione/32/1f574-1f3fb.png b/twake/frontend/public/public/emojione/32/1f574-1f3fb.png new file mode 100644 index 00000000..829a6be3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f574-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f574-1f3fc.png b/twake/frontend/public/public/emojione/32/1f574-1f3fc.png new file mode 100644 index 00000000..0bacdf98 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f574-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f574-1f3fd.png b/twake/frontend/public/public/emojione/32/1f574-1f3fd.png new file mode 100644 index 00000000..b408cc03 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f574-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f574-1f3fe.png b/twake/frontend/public/public/emojione/32/1f574-1f3fe.png new file mode 100644 index 00000000..3e12b4f3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f574-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f574-1f3ff.png b/twake/frontend/public/public/emojione/32/1f574-1f3ff.png new file mode 100644 index 00000000..c7516455 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f574-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f574.png b/twake/frontend/public/public/emojione/32/1f574.png new file mode 100644 index 00000000..3a5d3ccf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f574.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f575-1f3fb-2640.png new file mode 100644 index 00000000..b1ad9ae6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f575-1f3fb-2642.png new file mode 100644 index 00000000..c3fe2436 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575-1f3fb.png b/twake/frontend/public/public/emojione/32/1f575-1f3fb.png new file mode 100644 index 00000000..c3fe2436 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f575-1f3fc-2640.png new file mode 100644 index 00000000..84182f39 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f575-1f3fc-2642.png new file mode 100644 index 00000000..0a49c62e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575-1f3fc.png b/twake/frontend/public/public/emojione/32/1f575-1f3fc.png new file mode 100644 index 00000000..0a49c62e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f575-1f3fd-2640.png new file mode 100644 index 00000000..ad544ed5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f575-1f3fd-2642.png new file mode 100644 index 00000000..ea7d097e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575-1f3fd.png b/twake/frontend/public/public/emojione/32/1f575-1f3fd.png new file mode 100644 index 00000000..ea7d097e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f575-1f3fe-2640.png new file mode 100644 index 00000000..78fe956b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f575-1f3fe-2642.png new file mode 100644 index 00000000..321dd7ca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575-1f3fe.png b/twake/frontend/public/public/emojione/32/1f575-1f3fe.png new file mode 100644 index 00000000..321dd7ca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f575-1f3ff-2640.png new file mode 100644 index 00000000..a73c2ec6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f575-1f3ff-2642.png new file mode 100644 index 00000000..366f1cec Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575-1f3ff.png b/twake/frontend/public/public/emojione/32/1f575-1f3ff.png new file mode 100644 index 00000000..366f1cec Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575-2640.png b/twake/frontend/public/public/emojione/32/1f575-2640.png new file mode 100644 index 00000000..b2f6fa07 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575-2642.png b/twake/frontend/public/public/emojione/32/1f575-2642.png new file mode 100644 index 00000000..3af91c64 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f575.png b/twake/frontend/public/public/emojione/32/1f575.png new file mode 100644 index 00000000..3af91c64 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f575.png differ diff --git a/twake/frontend/public/public/emojione/32/1f576.png b/twake/frontend/public/public/emojione/32/1f576.png new file mode 100644 index 00000000..d0e52e49 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f576.png differ diff --git a/twake/frontend/public/public/emojione/32/1f577.png b/twake/frontend/public/public/emojione/32/1f577.png new file mode 100644 index 00000000..64d860ea Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f577.png differ diff --git a/twake/frontend/public/public/emojione/32/1f578.png b/twake/frontend/public/public/emojione/32/1f578.png new file mode 100644 index 00000000..4d2a4ae2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f578.png differ diff --git a/twake/frontend/public/public/emojione/32/1f579.png b/twake/frontend/public/public/emojione/32/1f579.png new file mode 100644 index 00000000..e7d1f0ca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f579.png differ diff --git a/twake/frontend/public/public/emojione/32/1f57a-1f3fb.png b/twake/frontend/public/public/emojione/32/1f57a-1f3fb.png new file mode 100644 index 00000000..51bd3ead Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f57a-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f57a-1f3fc.png b/twake/frontend/public/public/emojione/32/1f57a-1f3fc.png new file mode 100644 index 00000000..933588c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f57a-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f57a-1f3fd.png b/twake/frontend/public/public/emojione/32/1f57a-1f3fd.png new file mode 100644 index 00000000..fba914a6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f57a-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f57a-1f3fe.png b/twake/frontend/public/public/emojione/32/1f57a-1f3fe.png new file mode 100644 index 00000000..072734c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f57a-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f57a-1f3ff.png b/twake/frontend/public/public/emojione/32/1f57a-1f3ff.png new file mode 100644 index 00000000..3bcfc4c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f57a-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f57a.png b/twake/frontend/public/public/emojione/32/1f57a.png new file mode 100644 index 00000000..17be005b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f57a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f587.png b/twake/frontend/public/public/emojione/32/1f587.png new file mode 100644 index 00000000..853e6647 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f587.png differ diff --git a/twake/frontend/public/public/emojione/32/1f58a.png b/twake/frontend/public/public/emojione/32/1f58a.png new file mode 100644 index 00000000..79147e0e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f58a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f58b.png b/twake/frontend/public/public/emojione/32/1f58b.png new file mode 100644 index 00000000..d598129a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f58b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f58c.png b/twake/frontend/public/public/emojione/32/1f58c.png new file mode 100644 index 00000000..e1c1d436 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f58c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f58d.png b/twake/frontend/public/public/emojione/32/1f58d.png new file mode 100644 index 00000000..c52ce71d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f58d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f590-1f3fb.png b/twake/frontend/public/public/emojione/32/1f590-1f3fb.png new file mode 100644 index 00000000..caf83097 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f590-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f590-1f3fc.png b/twake/frontend/public/public/emojione/32/1f590-1f3fc.png new file mode 100644 index 00000000..3594e9b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f590-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f590-1f3fd.png b/twake/frontend/public/public/emojione/32/1f590-1f3fd.png new file mode 100644 index 00000000..04d8492e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f590-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f590-1f3fe.png b/twake/frontend/public/public/emojione/32/1f590-1f3fe.png new file mode 100644 index 00000000..a091fc22 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f590-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f590-1f3ff.png b/twake/frontend/public/public/emojione/32/1f590-1f3ff.png new file mode 100644 index 00000000..2281cef5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f590-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f590.png b/twake/frontend/public/public/emojione/32/1f590.png new file mode 100644 index 00000000..8ef30331 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f590.png differ diff --git a/twake/frontend/public/public/emojione/32/1f595-1f3fb.png b/twake/frontend/public/public/emojione/32/1f595-1f3fb.png new file mode 100644 index 00000000..5f8d5621 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f595-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f595-1f3fc.png b/twake/frontend/public/public/emojione/32/1f595-1f3fc.png new file mode 100644 index 00000000..c3885b04 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f595-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f595-1f3fd.png b/twake/frontend/public/public/emojione/32/1f595-1f3fd.png new file mode 100644 index 00000000..4b00e8ba Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f595-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f595-1f3fe.png b/twake/frontend/public/public/emojione/32/1f595-1f3fe.png new file mode 100644 index 00000000..b9408231 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f595-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f595-1f3ff.png b/twake/frontend/public/public/emojione/32/1f595-1f3ff.png new file mode 100644 index 00000000..590c37f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f595-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f595.png b/twake/frontend/public/public/emojione/32/1f595.png new file mode 100644 index 00000000..0acb5d14 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f595.png differ diff --git a/twake/frontend/public/public/emojione/32/1f596-1f3fb.png b/twake/frontend/public/public/emojione/32/1f596-1f3fb.png new file mode 100644 index 00000000..ccf497fd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f596-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f596-1f3fc.png b/twake/frontend/public/public/emojione/32/1f596-1f3fc.png new file mode 100644 index 00000000..aa848cdf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f596-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f596-1f3fd.png b/twake/frontend/public/public/emojione/32/1f596-1f3fd.png new file mode 100644 index 00000000..8d431f2f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f596-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f596-1f3fe.png b/twake/frontend/public/public/emojione/32/1f596-1f3fe.png new file mode 100644 index 00000000..9384892a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f596-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f596-1f3ff.png b/twake/frontend/public/public/emojione/32/1f596-1f3ff.png new file mode 100644 index 00000000..1f0278d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f596-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f596.png b/twake/frontend/public/public/emojione/32/1f596.png new file mode 100644 index 00000000..9bb82908 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f596.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5a4.png b/twake/frontend/public/public/emojione/32/1f5a4.png new file mode 100644 index 00000000..d0119290 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5a4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5a5.png b/twake/frontend/public/public/emojione/32/1f5a5.png new file mode 100644 index 00000000..82af28d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5a5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5a8.png b/twake/frontend/public/public/emojione/32/1f5a8.png new file mode 100644 index 00000000..365b474e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5a8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5b1.png b/twake/frontend/public/public/emojione/32/1f5b1.png new file mode 100644 index 00000000..6c735564 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5b1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5b2.png b/twake/frontend/public/public/emojione/32/1f5b2.png new file mode 100644 index 00000000..359810d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5b2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5bc.png b/twake/frontend/public/public/emojione/32/1f5bc.png new file mode 100644 index 00000000..48057cef Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5bc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5c2.png b/twake/frontend/public/public/emojione/32/1f5c2.png new file mode 100644 index 00000000..2872c7b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5c2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5c3.png b/twake/frontend/public/public/emojione/32/1f5c3.png new file mode 100644 index 00000000..2288599d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5c3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5c4.png b/twake/frontend/public/public/emojione/32/1f5c4.png new file mode 100644 index 00000000..5ccbb846 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5c4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5d1.png b/twake/frontend/public/public/emojione/32/1f5d1.png new file mode 100644 index 00000000..f819fd3a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5d1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5d2.png b/twake/frontend/public/public/emojione/32/1f5d2.png new file mode 100644 index 00000000..f02a7f41 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5d2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5d3.png b/twake/frontend/public/public/emojione/32/1f5d3.png new file mode 100644 index 00000000..24757dee Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5d3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5dc.png b/twake/frontend/public/public/emojione/32/1f5dc.png new file mode 100644 index 00000000..fbf75fb6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5dc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5dd.png b/twake/frontend/public/public/emojione/32/1f5dd.png new file mode 100644 index 00000000..c924f3b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5dd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5de.png b/twake/frontend/public/public/emojione/32/1f5de.png new file mode 100644 index 00000000..55c64875 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5de.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5e1.png b/twake/frontend/public/public/emojione/32/1f5e1.png new file mode 100644 index 00000000..1267d9ef Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5e1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5e3.png b/twake/frontend/public/public/emojione/32/1f5e3.png new file mode 100644 index 00000000..d6dfcf8a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5e3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5e8.png b/twake/frontend/public/public/emojione/32/1f5e8.png new file mode 100644 index 00000000..bd8d0d83 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5e8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5ef.png b/twake/frontend/public/public/emojione/32/1f5ef.png new file mode 100644 index 00000000..73b6acee Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5ef.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5f3.png b/twake/frontend/public/public/emojione/32/1f5f3.png new file mode 100644 index 00000000..72dbfbf4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5fa.png b/twake/frontend/public/public/emojione/32/1f5fa.png new file mode 100644 index 00000000..51894c6b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5fa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5fb.png b/twake/frontend/public/public/emojione/32/1f5fb.png new file mode 100644 index 00000000..051e242e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5fc.png b/twake/frontend/public/public/emojione/32/1f5fc.png new file mode 100644 index 00000000..bdb6786e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5fd.png b/twake/frontend/public/public/emojione/32/1f5fd.png new file mode 100644 index 00000000..ed089ce0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5fe.png b/twake/frontend/public/public/emojione/32/1f5fe.png new file mode 100644 index 00000000..b03a7787 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f5ff.png b/twake/frontend/public/public/emojione/32/1f5ff.png new file mode 100644 index 00000000..3df65c3a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f5ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f600.png b/twake/frontend/public/public/emojione/32/1f600.png new file mode 100644 index 00000000..8a44fc61 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f600.png differ diff --git a/twake/frontend/public/public/emojione/32/1f601.png b/twake/frontend/public/public/emojione/32/1f601.png new file mode 100644 index 00000000..ed346d88 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f601.png differ diff --git a/twake/frontend/public/public/emojione/32/1f602.png b/twake/frontend/public/public/emojione/32/1f602.png new file mode 100644 index 00000000..49ed021b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f602.png differ diff --git a/twake/frontend/public/public/emojione/32/1f603.png b/twake/frontend/public/public/emojione/32/1f603.png new file mode 100644 index 00000000..417a4dcf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f603.png differ diff --git a/twake/frontend/public/public/emojione/32/1f604.png b/twake/frontend/public/public/emojione/32/1f604.png new file mode 100644 index 00000000..8a5130e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f604.png differ diff --git a/twake/frontend/public/public/emojione/32/1f605.png b/twake/frontend/public/public/emojione/32/1f605.png new file mode 100644 index 00000000..7cc1b419 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f605.png differ diff --git a/twake/frontend/public/public/emojione/32/1f606.png b/twake/frontend/public/public/emojione/32/1f606.png new file mode 100644 index 00000000..457ca9e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f606.png differ diff --git a/twake/frontend/public/public/emojione/32/1f607.png b/twake/frontend/public/public/emojione/32/1f607.png new file mode 100644 index 00000000..089d7be7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f607.png differ diff --git a/twake/frontend/public/public/emojione/32/1f608.png b/twake/frontend/public/public/emojione/32/1f608.png new file mode 100644 index 00000000..5b62d1d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f608.png differ diff --git a/twake/frontend/public/public/emojione/32/1f609.png b/twake/frontend/public/public/emojione/32/1f609.png new file mode 100644 index 00000000..12f2ca68 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f609.png differ diff --git a/twake/frontend/public/public/emojione/32/1f60a.png b/twake/frontend/public/public/emojione/32/1f60a.png new file mode 100644 index 00000000..5aad6c75 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f60a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f60b.png b/twake/frontend/public/public/emojione/32/1f60b.png new file mode 100644 index 00000000..f3868fe1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f60b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f60c.png b/twake/frontend/public/public/emojione/32/1f60c.png new file mode 100644 index 00000000..9b727fa1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f60c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f60d.png b/twake/frontend/public/public/emojione/32/1f60d.png new file mode 100644 index 00000000..44377d67 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f60d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f60e.png b/twake/frontend/public/public/emojione/32/1f60e.png new file mode 100644 index 00000000..ff71171c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f60e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f60f.png b/twake/frontend/public/public/emojione/32/1f60f.png new file mode 100644 index 00000000..f326a976 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f60f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f610.png b/twake/frontend/public/public/emojione/32/1f610.png new file mode 100644 index 00000000..2cf59cd3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f610.png differ diff --git a/twake/frontend/public/public/emojione/32/1f611.png b/twake/frontend/public/public/emojione/32/1f611.png new file mode 100644 index 00000000..91f0f504 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f611.png differ diff --git a/twake/frontend/public/public/emojione/32/1f612.png b/twake/frontend/public/public/emojione/32/1f612.png new file mode 100644 index 00000000..ac170f89 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f612.png differ diff --git a/twake/frontend/public/public/emojione/32/1f613.png b/twake/frontend/public/public/emojione/32/1f613.png new file mode 100644 index 00000000..240628be Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f613.png differ diff --git a/twake/frontend/public/public/emojione/32/1f614.png b/twake/frontend/public/public/emojione/32/1f614.png new file mode 100644 index 00000000..8f0271a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f614.png differ diff --git a/twake/frontend/public/public/emojione/32/1f615.png b/twake/frontend/public/public/emojione/32/1f615.png new file mode 100644 index 00000000..e6c02200 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f615.png differ diff --git a/twake/frontend/public/public/emojione/32/1f616.png b/twake/frontend/public/public/emojione/32/1f616.png new file mode 100644 index 00000000..e3c58293 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f616.png differ diff --git a/twake/frontend/public/public/emojione/32/1f617.png b/twake/frontend/public/public/emojione/32/1f617.png new file mode 100644 index 00000000..42c09ba0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f617.png differ diff --git a/twake/frontend/public/public/emojione/32/1f618.png b/twake/frontend/public/public/emojione/32/1f618.png new file mode 100644 index 00000000..f2251c51 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f618.png differ diff --git a/twake/frontend/public/public/emojione/32/1f619.png b/twake/frontend/public/public/emojione/32/1f619.png new file mode 100644 index 00000000..65e7bead Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f619.png differ diff --git a/twake/frontend/public/public/emojione/32/1f61a.png b/twake/frontend/public/public/emojione/32/1f61a.png new file mode 100644 index 00000000..aff0f411 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f61a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f61b.png b/twake/frontend/public/public/emojione/32/1f61b.png new file mode 100644 index 00000000..03ec0596 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f61b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f61c.png b/twake/frontend/public/public/emojione/32/1f61c.png new file mode 100644 index 00000000..a731b6cf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f61c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f61d.png b/twake/frontend/public/public/emojione/32/1f61d.png new file mode 100644 index 00000000..7c419d93 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f61d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f61e.png b/twake/frontend/public/public/emojione/32/1f61e.png new file mode 100644 index 00000000..c889d122 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f61e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f61f.png b/twake/frontend/public/public/emojione/32/1f61f.png new file mode 100644 index 00000000..fb1b6ff9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f61f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f620.png b/twake/frontend/public/public/emojione/32/1f620.png new file mode 100644 index 00000000..8249f1c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f620.png differ diff --git a/twake/frontend/public/public/emojione/32/1f621.png b/twake/frontend/public/public/emojione/32/1f621.png new file mode 100644 index 00000000..72b9d2ef Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f621.png differ diff --git a/twake/frontend/public/public/emojione/32/1f622.png b/twake/frontend/public/public/emojione/32/1f622.png new file mode 100644 index 00000000..ecb040e4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f622.png differ diff --git a/twake/frontend/public/public/emojione/32/1f623.png b/twake/frontend/public/public/emojione/32/1f623.png new file mode 100644 index 00000000..63ed07cd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f623.png differ diff --git a/twake/frontend/public/public/emojione/32/1f624.png b/twake/frontend/public/public/emojione/32/1f624.png new file mode 100644 index 00000000..2b3ddb10 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f624.png differ diff --git a/twake/frontend/public/public/emojione/32/1f625.png b/twake/frontend/public/public/emojione/32/1f625.png new file mode 100644 index 00000000..1c4a9c50 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f625.png differ diff --git a/twake/frontend/public/public/emojione/32/1f626.png b/twake/frontend/public/public/emojione/32/1f626.png new file mode 100644 index 00000000..30816287 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f626.png differ diff --git a/twake/frontend/public/public/emojione/32/1f627.png b/twake/frontend/public/public/emojione/32/1f627.png new file mode 100644 index 00000000..09df5342 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f627.png differ diff --git a/twake/frontend/public/public/emojione/32/1f628.png b/twake/frontend/public/public/emojione/32/1f628.png new file mode 100644 index 00000000..714901b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f628.png differ diff --git a/twake/frontend/public/public/emojione/32/1f629.png b/twake/frontend/public/public/emojione/32/1f629.png new file mode 100644 index 00000000..27abe3ee Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f629.png differ diff --git a/twake/frontend/public/public/emojione/32/1f62a.png b/twake/frontend/public/public/emojione/32/1f62a.png new file mode 100644 index 00000000..dec9c72f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f62a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f62b.png b/twake/frontend/public/public/emojione/32/1f62b.png new file mode 100644 index 00000000..262ad629 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f62b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f62c.png b/twake/frontend/public/public/emojione/32/1f62c.png new file mode 100644 index 00000000..0d79a2be Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f62c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f62d.png b/twake/frontend/public/public/emojione/32/1f62d.png new file mode 100644 index 00000000..315d1e75 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f62d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f62e.png b/twake/frontend/public/public/emojione/32/1f62e.png new file mode 100644 index 00000000..a53e7500 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f62e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f62f.png b/twake/frontend/public/public/emojione/32/1f62f.png new file mode 100644 index 00000000..2aecbb3a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f62f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f630.png b/twake/frontend/public/public/emojione/32/1f630.png new file mode 100644 index 00000000..2d9a8319 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f630.png differ diff --git a/twake/frontend/public/public/emojione/32/1f631.png b/twake/frontend/public/public/emojione/32/1f631.png new file mode 100644 index 00000000..a353ec88 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f631.png differ diff --git a/twake/frontend/public/public/emojione/32/1f632.png b/twake/frontend/public/public/emojione/32/1f632.png new file mode 100644 index 00000000..9d272f3b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f632.png differ diff --git a/twake/frontend/public/public/emojione/32/1f633.png b/twake/frontend/public/public/emojione/32/1f633.png new file mode 100644 index 00000000..2d63f786 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f633.png differ diff --git a/twake/frontend/public/public/emojione/32/1f634.png b/twake/frontend/public/public/emojione/32/1f634.png new file mode 100644 index 00000000..6b227aad Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f634.png differ diff --git a/twake/frontend/public/public/emojione/32/1f635.png b/twake/frontend/public/public/emojione/32/1f635.png new file mode 100644 index 00000000..6b498741 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f635.png differ diff --git a/twake/frontend/public/public/emojione/32/1f636.png b/twake/frontend/public/public/emojione/32/1f636.png new file mode 100644 index 00000000..14f800c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f636.png differ diff --git a/twake/frontend/public/public/emojione/32/1f637.png b/twake/frontend/public/public/emojione/32/1f637.png new file mode 100644 index 00000000..5f9420b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f637.png differ diff --git a/twake/frontend/public/public/emojione/32/1f638.png b/twake/frontend/public/public/emojione/32/1f638.png new file mode 100644 index 00000000..7fe9a594 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f638.png differ diff --git a/twake/frontend/public/public/emojione/32/1f639.png b/twake/frontend/public/public/emojione/32/1f639.png new file mode 100644 index 00000000..4a9d7e86 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f639.png differ diff --git a/twake/frontend/public/public/emojione/32/1f63a.png b/twake/frontend/public/public/emojione/32/1f63a.png new file mode 100644 index 00000000..046b7e0f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f63a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f63b.png b/twake/frontend/public/public/emojione/32/1f63b.png new file mode 100644 index 00000000..3a580c07 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f63b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f63c.png b/twake/frontend/public/public/emojione/32/1f63c.png new file mode 100644 index 00000000..d5ac1d38 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f63c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f63d.png b/twake/frontend/public/public/emojione/32/1f63d.png new file mode 100644 index 00000000..b2de05c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f63d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f63e.png b/twake/frontend/public/public/emojione/32/1f63e.png new file mode 100644 index 00000000..bc6a7e68 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f63e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f63f.png b/twake/frontend/public/public/emojione/32/1f63f.png new file mode 100644 index 00000000..88e678a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f63f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f640.png b/twake/frontend/public/public/emojione/32/1f640.png new file mode 100644 index 00000000..c20a4664 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f641.png b/twake/frontend/public/public/emojione/32/1f641.png new file mode 100644 index 00000000..59249b2f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f641.png differ diff --git a/twake/frontend/public/public/emojione/32/1f642.png b/twake/frontend/public/public/emojione/32/1f642.png new file mode 100644 index 00000000..0f2cd902 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f643.png b/twake/frontend/public/public/emojione/32/1f643.png new file mode 100644 index 00000000..920c0e0a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f643.png differ diff --git a/twake/frontend/public/public/emojione/32/1f644.png b/twake/frontend/public/public/emojione/32/1f644.png new file mode 100644 index 00000000..3814fc09 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f644.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f645-1f3fb-2640.png new file mode 100644 index 00000000..4b6cfbe7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f645-1f3fb-2642.png new file mode 100644 index 00000000..c583e9e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645-1f3fb.png b/twake/frontend/public/public/emojione/32/1f645-1f3fb.png new file mode 100644 index 00000000..d6a9998d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f645-1f3fc-2640.png new file mode 100644 index 00000000..1ceeb672 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f645-1f3fc-2642.png new file mode 100644 index 00000000..bb7901ce Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645-1f3fc.png b/twake/frontend/public/public/emojione/32/1f645-1f3fc.png new file mode 100644 index 00000000..0b6e940d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f645-1f3fd-2640.png new file mode 100644 index 00000000..1db016da Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f645-1f3fd-2642.png new file mode 100644 index 00000000..3add1ff3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645-1f3fd.png b/twake/frontend/public/public/emojione/32/1f645-1f3fd.png new file mode 100644 index 00000000..2195a2bd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f645-1f3fe-2640.png new file mode 100644 index 00000000..06df54b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f645-1f3fe-2642.png new file mode 100644 index 00000000..98d53602 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645-1f3fe.png b/twake/frontend/public/public/emojione/32/1f645-1f3fe.png new file mode 100644 index 00000000..cc3ce273 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f645-1f3ff-2640.png new file mode 100644 index 00000000..a576ea13 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f645-1f3ff-2642.png new file mode 100644 index 00000000..633d634a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645-1f3ff.png b/twake/frontend/public/public/emojione/32/1f645-1f3ff.png new file mode 100644 index 00000000..ce9c885e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645-2640.png b/twake/frontend/public/public/emojione/32/1f645-2640.png new file mode 100644 index 00000000..8455b187 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645-2642.png b/twake/frontend/public/public/emojione/32/1f645-2642.png new file mode 100644 index 00000000..6e3da1ba Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f645.png b/twake/frontend/public/public/emojione/32/1f645.png new file mode 100644 index 00000000..8455b187 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f645.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f646-1f3fb-2640.png new file mode 100644 index 00000000..4086a820 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f646-1f3fb-2642.png new file mode 100644 index 00000000..70a839f3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646-1f3fb.png b/twake/frontend/public/public/emojione/32/1f646-1f3fb.png new file mode 100644 index 00000000..d46ce85c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f646-1f3fc-2640.png new file mode 100644 index 00000000..4caf0ec5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f646-1f3fc-2642.png new file mode 100644 index 00000000..d2137d1d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646-1f3fc.png b/twake/frontend/public/public/emojione/32/1f646-1f3fc.png new file mode 100644 index 00000000..d18681c9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f646-1f3fd-2640.png new file mode 100644 index 00000000..920fa623 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f646-1f3fd-2642.png new file mode 100644 index 00000000..493164ec Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646-1f3fd.png b/twake/frontend/public/public/emojione/32/1f646-1f3fd.png new file mode 100644 index 00000000..ab5ffd41 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f646-1f3fe-2640.png new file mode 100644 index 00000000..dffba577 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f646-1f3fe-2642.png new file mode 100644 index 00000000..c6ccc093 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646-1f3fe.png b/twake/frontend/public/public/emojione/32/1f646-1f3fe.png new file mode 100644 index 00000000..874d169e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f646-1f3ff-2640.png new file mode 100644 index 00000000..b20a5869 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f646-1f3ff-2642.png new file mode 100644 index 00000000..50ae415c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646-1f3ff.png b/twake/frontend/public/public/emojione/32/1f646-1f3ff.png new file mode 100644 index 00000000..8310458a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646-2640.png b/twake/frontend/public/public/emojione/32/1f646-2640.png new file mode 100644 index 00000000..0473ae67 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646-2642.png b/twake/frontend/public/public/emojione/32/1f646-2642.png new file mode 100644 index 00000000..05537627 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f646.png b/twake/frontend/public/public/emojione/32/1f646.png new file mode 100644 index 00000000..7f6656ed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f646.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f647-1f3fb-2640.png new file mode 100644 index 00000000..410514ef Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f647-1f3fb-2642.png new file mode 100644 index 00000000..652ea9de Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647-1f3fb.png b/twake/frontend/public/public/emojione/32/1f647-1f3fb.png new file mode 100644 index 00000000..652ea9de Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f647-1f3fc-2640.png new file mode 100644 index 00000000..fdc0a59e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f647-1f3fc-2642.png new file mode 100644 index 00000000..22baeb44 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647-1f3fc.png b/twake/frontend/public/public/emojione/32/1f647-1f3fc.png new file mode 100644 index 00000000..22baeb44 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f647-1f3fd-2640.png new file mode 100644 index 00000000..e07192ed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f647-1f3fd-2642.png new file mode 100644 index 00000000..1c1f4d3c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647-1f3fd.png b/twake/frontend/public/public/emojione/32/1f647-1f3fd.png new file mode 100644 index 00000000..1c1f4d3c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f647-1f3fe-2640.png new file mode 100644 index 00000000..8ed4808b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f647-1f3fe-2642.png new file mode 100644 index 00000000..58e672c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647-1f3fe.png b/twake/frontend/public/public/emojione/32/1f647-1f3fe.png new file mode 100644 index 00000000..58e672c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f647-1f3ff-2640.png new file mode 100644 index 00000000..6ffe05de Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f647-1f3ff-2642.png new file mode 100644 index 00000000..ab1de2db Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647-1f3ff.png b/twake/frontend/public/public/emojione/32/1f647-1f3ff.png new file mode 100644 index 00000000..ab1de2db Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647-2640.png b/twake/frontend/public/public/emojione/32/1f647-2640.png new file mode 100644 index 00000000..d5c8c344 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647-2642.png b/twake/frontend/public/public/emojione/32/1f647-2642.png new file mode 100644 index 00000000..10f19d5a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f647.png b/twake/frontend/public/public/emojione/32/1f647.png new file mode 100644 index 00000000..10f19d5a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f647.png differ diff --git a/twake/frontend/public/public/emojione/32/1f648.png b/twake/frontend/public/public/emojione/32/1f648.png new file mode 100644 index 00000000..fe5c136b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f648.png differ diff --git a/twake/frontend/public/public/emojione/32/1f649.png b/twake/frontend/public/public/emojione/32/1f649.png new file mode 100644 index 00000000..b591b8ed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f649.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64a.png b/twake/frontend/public/public/emojione/32/1f64a.png new file mode 100644 index 00000000..3f0548a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f64b-1f3fb-2640.png new file mode 100644 index 00000000..34780548 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f64b-1f3fb-2642.png new file mode 100644 index 00000000..4337580a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b-1f3fb.png b/twake/frontend/public/public/emojione/32/1f64b-1f3fb.png new file mode 100644 index 00000000..557c3e0f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f64b-1f3fc-2640.png new file mode 100644 index 00000000..40846d0f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f64b-1f3fc-2642.png new file mode 100644 index 00000000..09bd2d2e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b-1f3fc.png b/twake/frontend/public/public/emojione/32/1f64b-1f3fc.png new file mode 100644 index 00000000..452aaa83 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f64b-1f3fd-2640.png new file mode 100644 index 00000000..c68f5b06 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f64b-1f3fd-2642.png new file mode 100644 index 00000000..444302c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b-1f3fd.png b/twake/frontend/public/public/emojione/32/1f64b-1f3fd.png new file mode 100644 index 00000000..97b8483c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f64b-1f3fe-2640.png new file mode 100644 index 00000000..416be4b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f64b-1f3fe-2642.png new file mode 100644 index 00000000..9ace205a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b-1f3fe.png b/twake/frontend/public/public/emojione/32/1f64b-1f3fe.png new file mode 100644 index 00000000..fd3d5e5a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f64b-1f3ff-2640.png new file mode 100644 index 00000000..2f066fe6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f64b-1f3ff-2642.png new file mode 100644 index 00000000..84580395 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b-1f3ff.png b/twake/frontend/public/public/emojione/32/1f64b-1f3ff.png new file mode 100644 index 00000000..ba6da6b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b-2640.png b/twake/frontend/public/public/emojione/32/1f64b-2640.png new file mode 100644 index 00000000..a55dc01c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b-2642.png b/twake/frontend/public/public/emojione/32/1f64b-2642.png new file mode 100644 index 00000000..97fe6534 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64b.png b/twake/frontend/public/public/emojione/32/1f64b.png new file mode 100644 index 00000000..a55dc01c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64c-1f3fb.png b/twake/frontend/public/public/emojione/32/1f64c-1f3fb.png new file mode 100644 index 00000000..bbc460b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64c-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64c-1f3fc.png b/twake/frontend/public/public/emojione/32/1f64c-1f3fc.png new file mode 100644 index 00000000..39b992b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64c-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64c-1f3fd.png b/twake/frontend/public/public/emojione/32/1f64c-1f3fd.png new file mode 100644 index 00000000..657c52e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64c-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64c-1f3fe.png b/twake/frontend/public/public/emojione/32/1f64c-1f3fe.png new file mode 100644 index 00000000..babce0fb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64c-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64c-1f3ff.png b/twake/frontend/public/public/emojione/32/1f64c-1f3ff.png new file mode 100644 index 00000000..650e3d6a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64c-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64c.png b/twake/frontend/public/public/emojione/32/1f64c.png new file mode 100644 index 00000000..54eabf28 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f64d-1f3fb-2640.png new file mode 100644 index 00000000..b1b496be Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f64d-1f3fb-2642.png new file mode 100644 index 00000000..45a9b382 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d-1f3fb.png b/twake/frontend/public/public/emojione/32/1f64d-1f3fb.png new file mode 100644 index 00000000..083d9b69 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f64d-1f3fc-2640.png new file mode 100644 index 00000000..1c60203f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f64d-1f3fc-2642.png new file mode 100644 index 00000000..82b475c9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d-1f3fc.png b/twake/frontend/public/public/emojione/32/1f64d-1f3fc.png new file mode 100644 index 00000000..7f31ee4c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f64d-1f3fd-2640.png new file mode 100644 index 00000000..78c371bd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f64d-1f3fd-2642.png new file mode 100644 index 00000000..a4d573b7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d-1f3fd.png b/twake/frontend/public/public/emojione/32/1f64d-1f3fd.png new file mode 100644 index 00000000..ebeffbdf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f64d-1f3fe-2640.png new file mode 100644 index 00000000..044bbf73 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f64d-1f3fe-2642.png new file mode 100644 index 00000000..9c67deb6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d-1f3fe.png b/twake/frontend/public/public/emojione/32/1f64d-1f3fe.png new file mode 100644 index 00000000..f39fb374 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f64d-1f3ff-2640.png new file mode 100644 index 00000000..7a06ea74 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f64d-1f3ff-2642.png new file mode 100644 index 00000000..431e8689 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d-1f3ff.png b/twake/frontend/public/public/emojione/32/1f64d-1f3ff.png new file mode 100644 index 00000000..5d84e5f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d-2640.png b/twake/frontend/public/public/emojione/32/1f64d-2640.png new file mode 100644 index 00000000..358f839e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d-2642.png b/twake/frontend/public/public/emojione/32/1f64d-2642.png new file mode 100644 index 00000000..d17aee16 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64d.png b/twake/frontend/public/public/emojione/32/1f64d.png new file mode 100644 index 00000000..358f839e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f64e-1f3fb-2640.png new file mode 100644 index 00000000..fe085fd0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f64e-1f3fb-2642.png new file mode 100644 index 00000000..8b5fd7b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e-1f3fb.png b/twake/frontend/public/public/emojione/32/1f64e-1f3fb.png new file mode 100644 index 00000000..fe085fd0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f64e-1f3fc-2640.png new file mode 100644 index 00000000..efcd522c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f64e-1f3fc-2642.png new file mode 100644 index 00000000..d039d405 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e-1f3fc.png b/twake/frontend/public/public/emojione/32/1f64e-1f3fc.png new file mode 100644 index 00000000..efcd522c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f64e-1f3fd-2640.png new file mode 100644 index 00000000..6e5ce3fd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f64e-1f3fd-2642.png new file mode 100644 index 00000000..dc53f41b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e-1f3fd.png b/twake/frontend/public/public/emojione/32/1f64e-1f3fd.png new file mode 100644 index 00000000..6e5ce3fd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f64e-1f3fe-2640.png new file mode 100644 index 00000000..06b73942 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f64e-1f3fe-2642.png new file mode 100644 index 00000000..6ec2a86d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e-1f3fe.png b/twake/frontend/public/public/emojione/32/1f64e-1f3fe.png new file mode 100644 index 00000000..06b73942 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f64e-1f3ff-2640.png new file mode 100644 index 00000000..0921535f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f64e-1f3ff-2642.png new file mode 100644 index 00000000..01774ef6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e-1f3ff.png b/twake/frontend/public/public/emojione/32/1f64e-1f3ff.png new file mode 100644 index 00000000..0921535f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e-2640.png b/twake/frontend/public/public/emojione/32/1f64e-2640.png new file mode 100644 index 00000000..c2a11a0a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e-2642.png b/twake/frontend/public/public/emojione/32/1f64e-2642.png new file mode 100644 index 00000000..13f1bf62 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64e.png b/twake/frontend/public/public/emojione/32/1f64e.png new file mode 100644 index 00000000..c2a11a0a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64f-1f3fb.png b/twake/frontend/public/public/emojione/32/1f64f-1f3fb.png new file mode 100644 index 00000000..0a98386a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64f-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64f-1f3fc.png b/twake/frontend/public/public/emojione/32/1f64f-1f3fc.png new file mode 100644 index 00000000..0f5ec9a2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64f-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64f-1f3fd.png b/twake/frontend/public/public/emojione/32/1f64f-1f3fd.png new file mode 100644 index 00000000..a2fefcf8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64f-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64f-1f3fe.png b/twake/frontend/public/public/emojione/32/1f64f-1f3fe.png new file mode 100644 index 00000000..7b0827ff Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64f-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64f-1f3ff.png b/twake/frontend/public/public/emojione/32/1f64f-1f3ff.png new file mode 100644 index 00000000..8625eee1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64f-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f64f.png b/twake/frontend/public/public/emojione/32/1f64f.png new file mode 100644 index 00000000..f3ea741a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f64f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f680.png b/twake/frontend/public/public/emojione/32/1f680.png new file mode 100644 index 00000000..4e182ef7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f680.png differ diff --git a/twake/frontend/public/public/emojione/32/1f681.png b/twake/frontend/public/public/emojione/32/1f681.png new file mode 100644 index 00000000..96ae7921 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f681.png differ diff --git a/twake/frontend/public/public/emojione/32/1f682.png b/twake/frontend/public/public/emojione/32/1f682.png new file mode 100644 index 00000000..af845b6b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f682.png differ diff --git a/twake/frontend/public/public/emojione/32/1f683.png b/twake/frontend/public/public/emojione/32/1f683.png new file mode 100644 index 00000000..a8e72f81 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f683.png differ diff --git a/twake/frontend/public/public/emojione/32/1f684.png b/twake/frontend/public/public/emojione/32/1f684.png new file mode 100644 index 00000000..3b7917f3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f684.png differ diff --git a/twake/frontend/public/public/emojione/32/1f685.png b/twake/frontend/public/public/emojione/32/1f685.png new file mode 100644 index 00000000..0ece6de8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f685.png differ diff --git a/twake/frontend/public/public/emojione/32/1f686.png b/twake/frontend/public/public/emojione/32/1f686.png new file mode 100644 index 00000000..31f2b57b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f686.png differ diff --git a/twake/frontend/public/public/emojione/32/1f687.png b/twake/frontend/public/public/emojione/32/1f687.png new file mode 100644 index 00000000..4369e8bf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f687.png differ diff --git a/twake/frontend/public/public/emojione/32/1f688.png b/twake/frontend/public/public/emojione/32/1f688.png new file mode 100644 index 00000000..c79ce89a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f688.png differ diff --git a/twake/frontend/public/public/emojione/32/1f689.png b/twake/frontend/public/public/emojione/32/1f689.png new file mode 100644 index 00000000..03874888 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f689.png differ diff --git a/twake/frontend/public/public/emojione/32/1f68a.png b/twake/frontend/public/public/emojione/32/1f68a.png new file mode 100644 index 00000000..44872af6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f68a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f68b.png b/twake/frontend/public/public/emojione/32/1f68b.png new file mode 100644 index 00000000..20531b55 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f68b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f68c.png b/twake/frontend/public/public/emojione/32/1f68c.png new file mode 100644 index 00000000..42351fff Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f68c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f68d.png b/twake/frontend/public/public/emojione/32/1f68d.png new file mode 100644 index 00000000..f08cc7dd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f68d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f68e.png b/twake/frontend/public/public/emojione/32/1f68e.png new file mode 100644 index 00000000..fc700074 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f68e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f68f.png b/twake/frontend/public/public/emojione/32/1f68f.png new file mode 100644 index 00000000..686e1af3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f68f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f690.png b/twake/frontend/public/public/emojione/32/1f690.png new file mode 100644 index 00000000..a4387ca3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f690.png differ diff --git a/twake/frontend/public/public/emojione/32/1f691.png b/twake/frontend/public/public/emojione/32/1f691.png new file mode 100644 index 00000000..08567ece Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f691.png differ diff --git a/twake/frontend/public/public/emojione/32/1f692.png b/twake/frontend/public/public/emojione/32/1f692.png new file mode 100644 index 00000000..261e838f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f692.png differ diff --git a/twake/frontend/public/public/emojione/32/1f693.png b/twake/frontend/public/public/emojione/32/1f693.png new file mode 100644 index 00000000..1b45c693 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f693.png differ diff --git a/twake/frontend/public/public/emojione/32/1f694.png b/twake/frontend/public/public/emojione/32/1f694.png new file mode 100644 index 00000000..7e442b54 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f694.png differ diff --git a/twake/frontend/public/public/emojione/32/1f695.png b/twake/frontend/public/public/emojione/32/1f695.png new file mode 100644 index 00000000..aabc53d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f695.png differ diff --git a/twake/frontend/public/public/emojione/32/1f696.png b/twake/frontend/public/public/emojione/32/1f696.png new file mode 100644 index 00000000..b13919dc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f696.png differ diff --git a/twake/frontend/public/public/emojione/32/1f697.png b/twake/frontend/public/public/emojione/32/1f697.png new file mode 100644 index 00000000..1620eeef Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f697.png differ diff --git a/twake/frontend/public/public/emojione/32/1f698.png b/twake/frontend/public/public/emojione/32/1f698.png new file mode 100644 index 00000000..9879788c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f698.png differ diff --git a/twake/frontend/public/public/emojione/32/1f699.png b/twake/frontend/public/public/emojione/32/1f699.png new file mode 100644 index 00000000..2e5c839a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f699.png differ diff --git a/twake/frontend/public/public/emojione/32/1f69a.png b/twake/frontend/public/public/emojione/32/1f69a.png new file mode 100644 index 00000000..6ad27749 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f69a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f69b.png b/twake/frontend/public/public/emojione/32/1f69b.png new file mode 100644 index 00000000..f6dd512b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f69b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f69c.png b/twake/frontend/public/public/emojione/32/1f69c.png new file mode 100644 index 00000000..6e6600aa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f69c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f69d.png b/twake/frontend/public/public/emojione/32/1f69d.png new file mode 100644 index 00000000..7f6cf1cd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f69d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f69e.png b/twake/frontend/public/public/emojione/32/1f69e.png new file mode 100644 index 00000000..67873e65 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f69e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f69f.png b/twake/frontend/public/public/emojione/32/1f69f.png new file mode 100644 index 00000000..e663a424 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f69f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a0.png b/twake/frontend/public/public/emojione/32/1f6a0.png new file mode 100644 index 00000000..32fd3792 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a1.png b/twake/frontend/public/public/emojione/32/1f6a1.png new file mode 100644 index 00000000..06599913 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a2.png b/twake/frontend/public/public/emojione/32/1f6a2.png new file mode 100644 index 00000000..ace717b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f6a3-1f3fb-2640.png new file mode 100644 index 00000000..d08796ce Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f6a3-1f3fb-2642.png new file mode 100644 index 00000000..de5ef304 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3-1f3fb.png b/twake/frontend/public/public/emojione/32/1f6a3-1f3fb.png new file mode 100644 index 00000000..de5ef304 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f6a3-1f3fc-2640.png new file mode 100644 index 00000000..8dbaf071 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f6a3-1f3fc-2642.png new file mode 100644 index 00000000..c5b57683 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3-1f3fc.png b/twake/frontend/public/public/emojione/32/1f6a3-1f3fc.png new file mode 100644 index 00000000..c5b57683 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f6a3-1f3fd-2640.png new file mode 100644 index 00000000..054c3e90 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f6a3-1f3fd-2642.png new file mode 100644 index 00000000..3caeffda Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3-1f3fd.png b/twake/frontend/public/public/emojione/32/1f6a3-1f3fd.png new file mode 100644 index 00000000..3caeffda Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f6a3-1f3fe-2640.png new file mode 100644 index 00000000..8706f289 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f6a3-1f3fe-2642.png new file mode 100644 index 00000000..73567ed2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3-1f3fe.png b/twake/frontend/public/public/emojione/32/1f6a3-1f3fe.png new file mode 100644 index 00000000..73567ed2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f6a3-1f3ff-2640.png new file mode 100644 index 00000000..ecb7220a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f6a3-1f3ff-2642.png new file mode 100644 index 00000000..8ce36e93 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3-1f3ff.png b/twake/frontend/public/public/emojione/32/1f6a3-1f3ff.png new file mode 100644 index 00000000..8ce36e93 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3-2640.png b/twake/frontend/public/public/emojione/32/1f6a3-2640.png new file mode 100644 index 00000000..fcb5c99b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3-2642.png b/twake/frontend/public/public/emojione/32/1f6a3-2642.png new file mode 100644 index 00000000..863ff251 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a3.png b/twake/frontend/public/public/emojione/32/1f6a3.png new file mode 100644 index 00000000..863ff251 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a4.png b/twake/frontend/public/public/emojione/32/1f6a4.png new file mode 100644 index 00000000..43aab39f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a5.png b/twake/frontend/public/public/emojione/32/1f6a5.png new file mode 100644 index 00000000..dc5b3c48 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a6.png b/twake/frontend/public/public/emojione/32/1f6a6.png new file mode 100644 index 00000000..cbd21fdc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a7.png b/twake/frontend/public/public/emojione/32/1f6a7.png new file mode 100644 index 00000000..5afaec97 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a8.png b/twake/frontend/public/public/emojione/32/1f6a8.png new file mode 100644 index 00000000..a4012d12 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6a9.png b/twake/frontend/public/public/emojione/32/1f6a9.png new file mode 100644 index 00000000..62b17810 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6a9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6aa.png b/twake/frontend/public/public/emojione/32/1f6aa.png new file mode 100644 index 00000000..3d723297 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6aa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6ab.png b/twake/frontend/public/public/emojione/32/1f6ab.png new file mode 100644 index 00000000..9e1b8275 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6ab.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6ac.png b/twake/frontend/public/public/emojione/32/1f6ac.png new file mode 100644 index 00000000..af107c44 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6ac.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6ad.png b/twake/frontend/public/public/emojione/32/1f6ad.png new file mode 100644 index 00000000..86581847 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6ad.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6ae.png b/twake/frontend/public/public/emojione/32/1f6ae.png new file mode 100644 index 00000000..c2e203db Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6ae.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6af.png b/twake/frontend/public/public/emojione/32/1f6af.png new file mode 100644 index 00000000..33e04e2f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6af.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b0.png b/twake/frontend/public/public/emojione/32/1f6b0.png new file mode 100644 index 00000000..e96ba3b4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b1.png b/twake/frontend/public/public/emojione/32/1f6b1.png new file mode 100644 index 00000000..50e35a05 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b2.png b/twake/frontend/public/public/emojione/32/1f6b2.png new file mode 100644 index 00000000..4abc1c08 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b3.png b/twake/frontend/public/public/emojione/32/1f6b3.png new file mode 100644 index 00000000..14c7e718 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f6b4-1f3fb-2640.png new file mode 100644 index 00000000..cf3ff86e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f6b4-1f3fb-2642.png new file mode 100644 index 00000000..e141fe9e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4-1f3fb.png b/twake/frontend/public/public/emojione/32/1f6b4-1f3fb.png new file mode 100644 index 00000000..e141fe9e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f6b4-1f3fc-2640.png new file mode 100644 index 00000000..46fcd6b9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f6b4-1f3fc-2642.png new file mode 100644 index 00000000..6f4c85fa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4-1f3fc.png b/twake/frontend/public/public/emojione/32/1f6b4-1f3fc.png new file mode 100644 index 00000000..6f4c85fa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f6b4-1f3fd-2640.png new file mode 100644 index 00000000..f6346df4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f6b4-1f3fd-2642.png new file mode 100644 index 00000000..8734ff39 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4-1f3fd.png b/twake/frontend/public/public/emojione/32/1f6b4-1f3fd.png new file mode 100644 index 00000000..8734ff39 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f6b4-1f3fe-2640.png new file mode 100644 index 00000000..2ff13d3c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f6b4-1f3fe-2642.png new file mode 100644 index 00000000..0d864763 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4-1f3fe.png b/twake/frontend/public/public/emojione/32/1f6b4-1f3fe.png new file mode 100644 index 00000000..0d864763 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f6b4-1f3ff-2640.png new file mode 100644 index 00000000..52f34b68 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f6b4-1f3ff-2642.png new file mode 100644 index 00000000..083539e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4-1f3ff.png b/twake/frontend/public/public/emojione/32/1f6b4-1f3ff.png new file mode 100644 index 00000000..083539e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4-2640.png b/twake/frontend/public/public/emojione/32/1f6b4-2640.png new file mode 100644 index 00000000..aaa0679e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4-2642.png b/twake/frontend/public/public/emojione/32/1f6b4-2642.png new file mode 100644 index 00000000..b5332469 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b4.png b/twake/frontend/public/public/emojione/32/1f6b4.png new file mode 100644 index 00000000..b5332469 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f6b5-1f3fb-2640.png new file mode 100644 index 00000000..3c2c2169 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f6b5-1f3fb-2642.png new file mode 100644 index 00000000..44c6a41a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5-1f3fb.png b/twake/frontend/public/public/emojione/32/1f6b5-1f3fb.png new file mode 100644 index 00000000..44c6a41a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f6b5-1f3fc-2640.png new file mode 100644 index 00000000..b794656f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f6b5-1f3fc-2642.png new file mode 100644 index 00000000..304559f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5-1f3fc.png b/twake/frontend/public/public/emojione/32/1f6b5-1f3fc.png new file mode 100644 index 00000000..304559f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f6b5-1f3fd-2640.png new file mode 100644 index 00000000..4018db14 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f6b5-1f3fd-2642.png new file mode 100644 index 00000000..0861737c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5-1f3fd.png b/twake/frontend/public/public/emojione/32/1f6b5-1f3fd.png new file mode 100644 index 00000000..0861737c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f6b5-1f3fe-2640.png new file mode 100644 index 00000000..a6f152ca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f6b5-1f3fe-2642.png new file mode 100644 index 00000000..dfa786f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5-1f3fe.png b/twake/frontend/public/public/emojione/32/1f6b5-1f3fe.png new file mode 100644 index 00000000..dfa786f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f6b5-1f3ff-2640.png new file mode 100644 index 00000000..fecc9a7d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f6b5-1f3ff-2642.png new file mode 100644 index 00000000..61ff6b1f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5-1f3ff.png b/twake/frontend/public/public/emojione/32/1f6b5-1f3ff.png new file mode 100644 index 00000000..61ff6b1f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5-2640.png b/twake/frontend/public/public/emojione/32/1f6b5-2640.png new file mode 100644 index 00000000..6255050f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5-2642.png b/twake/frontend/public/public/emojione/32/1f6b5-2642.png new file mode 100644 index 00000000..6934460b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b5.png b/twake/frontend/public/public/emojione/32/1f6b5.png new file mode 100644 index 00000000..6934460b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f6b6-1f3fb-2640.png new file mode 100644 index 00000000..a0b86dd2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f6b6-1f3fb-2642.png new file mode 100644 index 00000000..8e0ecbf4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6-1f3fb.png b/twake/frontend/public/public/emojione/32/1f6b6-1f3fb.png new file mode 100644 index 00000000..8e0ecbf4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f6b6-1f3fc-2640.png new file mode 100644 index 00000000..38f17a78 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f6b6-1f3fc-2642.png new file mode 100644 index 00000000..1188eed8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6-1f3fc.png b/twake/frontend/public/public/emojione/32/1f6b6-1f3fc.png new file mode 100644 index 00000000..1188eed8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f6b6-1f3fd-2640.png new file mode 100644 index 00000000..56455e5f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f6b6-1f3fd-2642.png new file mode 100644 index 00000000..cd89f495 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6-1f3fd.png b/twake/frontend/public/public/emojione/32/1f6b6-1f3fd.png new file mode 100644 index 00000000..cd89f495 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f6b6-1f3fe-2640.png new file mode 100644 index 00000000..74e00ee0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f6b6-1f3fe-2642.png new file mode 100644 index 00000000..2ae7b480 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6-1f3fe.png b/twake/frontend/public/public/emojione/32/1f6b6-1f3fe.png new file mode 100644 index 00000000..2ae7b480 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f6b6-1f3ff-2640.png new file mode 100644 index 00000000..38f2afe7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f6b6-1f3ff-2642.png new file mode 100644 index 00000000..654da3bb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6-1f3ff.png b/twake/frontend/public/public/emojione/32/1f6b6-1f3ff.png new file mode 100644 index 00000000..654da3bb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6-2640.png b/twake/frontend/public/public/emojione/32/1f6b6-2640.png new file mode 100644 index 00000000..2da8d968 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6-2642.png b/twake/frontend/public/public/emojione/32/1f6b6-2642.png new file mode 100644 index 00000000..dcf890b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b6.png b/twake/frontend/public/public/emojione/32/1f6b6.png new file mode 100644 index 00000000..dcf890b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b7.png b/twake/frontend/public/public/emojione/32/1f6b7.png new file mode 100644 index 00000000..aded0db1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b8.png b/twake/frontend/public/public/emojione/32/1f6b8.png new file mode 100644 index 00000000..36f706d5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6b9.png b/twake/frontend/public/public/emojione/32/1f6b9.png new file mode 100644 index 00000000..84a123e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6b9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6ba.png b/twake/frontend/public/public/emojione/32/1f6ba.png new file mode 100644 index 00000000..18982e3d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6ba.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6bb.png b/twake/frontend/public/public/emojione/32/1f6bb.png new file mode 100644 index 00000000..62f5443f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6bb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6bc.png b/twake/frontend/public/public/emojione/32/1f6bc.png new file mode 100644 index 00000000..eedf4c91 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6bc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6bd.png b/twake/frontend/public/public/emojione/32/1f6bd.png new file mode 100644 index 00000000..ef610626 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6bd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6be.png b/twake/frontend/public/public/emojione/32/1f6be.png new file mode 100644 index 00000000..3d7c79c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6be.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6bf.png b/twake/frontend/public/public/emojione/32/1f6bf.png new file mode 100644 index 00000000..8dcfc690 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6bf.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6c0-1f3fb.png b/twake/frontend/public/public/emojione/32/1f6c0-1f3fb.png new file mode 100644 index 00000000..16f587bf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6c0-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6c0-1f3fc.png b/twake/frontend/public/public/emojione/32/1f6c0-1f3fc.png new file mode 100644 index 00000000..976dc9f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6c0-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6c0-1f3fd.png b/twake/frontend/public/public/emojione/32/1f6c0-1f3fd.png new file mode 100644 index 00000000..f70828f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6c0-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6c0-1f3fe.png b/twake/frontend/public/public/emojione/32/1f6c0-1f3fe.png new file mode 100644 index 00000000..5f45515d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6c0-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6c0-1f3ff.png b/twake/frontend/public/public/emojione/32/1f6c0-1f3ff.png new file mode 100644 index 00000000..0e9c8542 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6c0-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6c0.png b/twake/frontend/public/public/emojione/32/1f6c0.png new file mode 100644 index 00000000..0ab17d7a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6c0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6c1.png b/twake/frontend/public/public/emojione/32/1f6c1.png new file mode 100644 index 00000000..5e28d22e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6c1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6c2.png b/twake/frontend/public/public/emojione/32/1f6c2.png new file mode 100644 index 00000000..7dfab51e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6c2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6c3.png b/twake/frontend/public/public/emojione/32/1f6c3.png new file mode 100644 index 00000000..01dcc9a1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6c3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6c4.png b/twake/frontend/public/public/emojione/32/1f6c4.png new file mode 100644 index 00000000..dbdee6e4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6c4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6c5.png b/twake/frontend/public/public/emojione/32/1f6c5.png new file mode 100644 index 00000000..d4035359 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6c5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6cb.png b/twake/frontend/public/public/emojione/32/1f6cb.png new file mode 100644 index 00000000..4dd6d266 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6cb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6cc-1f3fb.png b/twake/frontend/public/public/emojione/32/1f6cc-1f3fb.png new file mode 100644 index 00000000..8de1c060 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6cc-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6cc-1f3fc.png b/twake/frontend/public/public/emojione/32/1f6cc-1f3fc.png new file mode 100644 index 00000000..98f77dac Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6cc-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6cc-1f3fd.png b/twake/frontend/public/public/emojione/32/1f6cc-1f3fd.png new file mode 100644 index 00000000..3ba8cf6e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6cc-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6cc-1f3fe.png b/twake/frontend/public/public/emojione/32/1f6cc-1f3fe.png new file mode 100644 index 00000000..188d83b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6cc-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6cc-1f3ff.png b/twake/frontend/public/public/emojione/32/1f6cc-1f3ff.png new file mode 100644 index 00000000..ea563927 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6cc-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6cc.png b/twake/frontend/public/public/emojione/32/1f6cc.png new file mode 100644 index 00000000..b3fb4229 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6cc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6cd.png b/twake/frontend/public/public/emojione/32/1f6cd.png new file mode 100644 index 00000000..97d3ad4c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6cd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6ce.png b/twake/frontend/public/public/emojione/32/1f6ce.png new file mode 100644 index 00000000..7dcd7219 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6ce.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6cf.png b/twake/frontend/public/public/emojione/32/1f6cf.png new file mode 100644 index 00000000..d486f75a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6cf.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6d0.png b/twake/frontend/public/public/emojione/32/1f6d0.png new file mode 100644 index 00000000..cc66699e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6d0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6d1.png b/twake/frontend/public/public/emojione/32/1f6d1.png new file mode 100644 index 00000000..48a160e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6d1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6d2.png b/twake/frontend/public/public/emojione/32/1f6d2.png new file mode 100644 index 00000000..80013f5f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6d2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6e0.png b/twake/frontend/public/public/emojione/32/1f6e0.png new file mode 100644 index 00000000..bf73cff0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6e0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6e1.png b/twake/frontend/public/public/emojione/32/1f6e1.png new file mode 100644 index 00000000..646e2ab2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6e1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6e2.png b/twake/frontend/public/public/emojione/32/1f6e2.png new file mode 100644 index 00000000..42502894 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6e2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6e3.png b/twake/frontend/public/public/emojione/32/1f6e3.png new file mode 100644 index 00000000..05536e6e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6e3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6e4.png b/twake/frontend/public/public/emojione/32/1f6e4.png new file mode 100644 index 00000000..ea60bbec Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6e4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6e5.png b/twake/frontend/public/public/emojione/32/1f6e5.png new file mode 100644 index 00000000..42112311 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6e5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6e9.png b/twake/frontend/public/public/emojione/32/1f6e9.png new file mode 100644 index 00000000..8a46b4ed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6e9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6eb.png b/twake/frontend/public/public/emojione/32/1f6eb.png new file mode 100644 index 00000000..647a362b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6ec.png b/twake/frontend/public/public/emojione/32/1f6ec.png new file mode 100644 index 00000000..3f16b0aa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6f0.png b/twake/frontend/public/public/emojione/32/1f6f0.png new file mode 100644 index 00000000..8e48d2e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6f0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6f3.png b/twake/frontend/public/public/emojione/32/1f6f3.png new file mode 100644 index 00000000..09a72164 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6f4.png b/twake/frontend/public/public/emojione/32/1f6f4.png new file mode 100644 index 00000000..d0e3929c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6f4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6f5.png b/twake/frontend/public/public/emojione/32/1f6f5.png new file mode 100644 index 00000000..25d4d829 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6f5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6f6.png b/twake/frontend/public/public/emojione/32/1f6f6.png new file mode 100644 index 00000000..246c67f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6f6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6f7.png b/twake/frontend/public/public/emojione/32/1f6f7.png new file mode 100644 index 00000000..82228a78 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6f8.png b/twake/frontend/public/public/emojione/32/1f6f8.png new file mode 100644 index 00000000..211240cf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6f8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f6f9.png b/twake/frontend/public/public/emojione/32/1f6f9.png new file mode 100644 index 00000000..f8143a07 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f6f9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f910.png b/twake/frontend/public/public/emojione/32/1f910.png new file mode 100644 index 00000000..8bbfa1b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f910.png differ diff --git a/twake/frontend/public/public/emojione/32/1f911.png b/twake/frontend/public/public/emojione/32/1f911.png new file mode 100644 index 00000000..e7e8a091 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f911.png differ diff --git a/twake/frontend/public/public/emojione/32/1f912.png b/twake/frontend/public/public/emojione/32/1f912.png new file mode 100644 index 00000000..ff5c4828 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f912.png differ diff --git a/twake/frontend/public/public/emojione/32/1f913.png b/twake/frontend/public/public/emojione/32/1f913.png new file mode 100644 index 00000000..b04cd190 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f913.png differ diff --git a/twake/frontend/public/public/emojione/32/1f914.png b/twake/frontend/public/public/emojione/32/1f914.png new file mode 100644 index 00000000..38a44e5b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f914.png differ diff --git a/twake/frontend/public/public/emojione/32/1f915.png b/twake/frontend/public/public/emojione/32/1f915.png new file mode 100644 index 00000000..1945956c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f915.png differ diff --git a/twake/frontend/public/public/emojione/32/1f916.png b/twake/frontend/public/public/emojione/32/1f916.png new file mode 100644 index 00000000..364b9a2a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f916.png differ diff --git a/twake/frontend/public/public/emojione/32/1f917.png b/twake/frontend/public/public/emojione/32/1f917.png new file mode 100644 index 00000000..62b6d212 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f917.png differ diff --git a/twake/frontend/public/public/emojione/32/1f918-1f3fb.png b/twake/frontend/public/public/emojione/32/1f918-1f3fb.png new file mode 100644 index 00000000..6515213a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f918-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f918-1f3fc.png b/twake/frontend/public/public/emojione/32/1f918-1f3fc.png new file mode 100644 index 00000000..ecfedc91 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f918-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f918-1f3fd.png b/twake/frontend/public/public/emojione/32/1f918-1f3fd.png new file mode 100644 index 00000000..63c6567f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f918-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f918-1f3fe.png b/twake/frontend/public/public/emojione/32/1f918-1f3fe.png new file mode 100644 index 00000000..1a0fc828 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f918-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f918-1f3ff.png b/twake/frontend/public/public/emojione/32/1f918-1f3ff.png new file mode 100644 index 00000000..e540c5d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f918-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f918.png b/twake/frontend/public/public/emojione/32/1f918.png new file mode 100644 index 00000000..5443e929 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f918.png differ diff --git a/twake/frontend/public/public/emojione/32/1f919-1f3fb.png b/twake/frontend/public/public/emojione/32/1f919-1f3fb.png new file mode 100644 index 00000000..6468cbb4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f919-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f919-1f3fc.png b/twake/frontend/public/public/emojione/32/1f919-1f3fc.png new file mode 100644 index 00000000..93bffd53 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f919-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f919-1f3fd.png b/twake/frontend/public/public/emojione/32/1f919-1f3fd.png new file mode 100644 index 00000000..ea537505 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f919-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f919-1f3fe.png b/twake/frontend/public/public/emojione/32/1f919-1f3fe.png new file mode 100644 index 00000000..657d79b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f919-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f919-1f3ff.png b/twake/frontend/public/public/emojione/32/1f919-1f3ff.png new file mode 100644 index 00000000..7a7a91bc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f919-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f919.png b/twake/frontend/public/public/emojione/32/1f919.png new file mode 100644 index 00000000..b295b36b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f919.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91a-1f3fb.png b/twake/frontend/public/public/emojione/32/1f91a-1f3fb.png new file mode 100644 index 00000000..33be0069 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91a-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91a-1f3fc.png b/twake/frontend/public/public/emojione/32/1f91a-1f3fc.png new file mode 100644 index 00000000..04d8935a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91a-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91a-1f3fd.png b/twake/frontend/public/public/emojione/32/1f91a-1f3fd.png new file mode 100644 index 00000000..b92cba9f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91a-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91a-1f3fe.png b/twake/frontend/public/public/emojione/32/1f91a-1f3fe.png new file mode 100644 index 00000000..f0089c9b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91a-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91a-1f3ff.png b/twake/frontend/public/public/emojione/32/1f91a-1f3ff.png new file mode 100644 index 00000000..cebf1e89 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91a-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91a.png b/twake/frontend/public/public/emojione/32/1f91a.png new file mode 100644 index 00000000..70f4ee05 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91b-1f3fb.png b/twake/frontend/public/public/emojione/32/1f91b-1f3fb.png new file mode 100644 index 00000000..eaa7f1db Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91b-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91b-1f3fc.png b/twake/frontend/public/public/emojione/32/1f91b-1f3fc.png new file mode 100644 index 00000000..661a146a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91b-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91b-1f3fd.png b/twake/frontend/public/public/emojione/32/1f91b-1f3fd.png new file mode 100644 index 00000000..66fe9425 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91b-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91b-1f3fe.png b/twake/frontend/public/public/emojione/32/1f91b-1f3fe.png new file mode 100644 index 00000000..35af8ff6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91b-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91b-1f3ff.png b/twake/frontend/public/public/emojione/32/1f91b-1f3ff.png new file mode 100644 index 00000000..1bf413fa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91b-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91b.png b/twake/frontend/public/public/emojione/32/1f91b.png new file mode 100644 index 00000000..3ab63da4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91c-1f3fb.png b/twake/frontend/public/public/emojione/32/1f91c-1f3fb.png new file mode 100644 index 00000000..a76ddb27 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91c-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91c-1f3fc.png b/twake/frontend/public/public/emojione/32/1f91c-1f3fc.png new file mode 100644 index 00000000..370743d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91c-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91c-1f3fd.png b/twake/frontend/public/public/emojione/32/1f91c-1f3fd.png new file mode 100644 index 00000000..0c9bf4de Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91c-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91c-1f3fe.png b/twake/frontend/public/public/emojione/32/1f91c-1f3fe.png new file mode 100644 index 00000000..b73db5f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91c-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91c-1f3ff.png b/twake/frontend/public/public/emojione/32/1f91c-1f3ff.png new file mode 100644 index 00000000..3ca53571 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91c-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91c.png b/twake/frontend/public/public/emojione/32/1f91c.png new file mode 100644 index 00000000..4003ac9c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91d.png b/twake/frontend/public/public/emojione/32/1f91d.png new file mode 100644 index 00000000..0c358e76 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91e-1f3fb.png b/twake/frontend/public/public/emojione/32/1f91e-1f3fb.png new file mode 100644 index 00000000..b46f95d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91e-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91e-1f3fc.png b/twake/frontend/public/public/emojione/32/1f91e-1f3fc.png new file mode 100644 index 00000000..da78c188 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91e-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91e-1f3fd.png b/twake/frontend/public/public/emojione/32/1f91e-1f3fd.png new file mode 100644 index 00000000..55354527 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91e-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91e-1f3fe.png b/twake/frontend/public/public/emojione/32/1f91e-1f3fe.png new file mode 100644 index 00000000..f684c6e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91e-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91e-1f3ff.png b/twake/frontend/public/public/emojione/32/1f91e-1f3ff.png new file mode 100644 index 00000000..2f58da4a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91e-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91e.png b/twake/frontend/public/public/emojione/32/1f91e.png new file mode 100644 index 00000000..31c0eb4c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91f-1f3fb.png b/twake/frontend/public/public/emojione/32/1f91f-1f3fb.png new file mode 100644 index 00000000..ff64dc88 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91f-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91f-1f3fc.png b/twake/frontend/public/public/emojione/32/1f91f-1f3fc.png new file mode 100644 index 00000000..c122415e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91f-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91f-1f3fd.png b/twake/frontend/public/public/emojione/32/1f91f-1f3fd.png new file mode 100644 index 00000000..04dafb01 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91f-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91f-1f3fe.png b/twake/frontend/public/public/emojione/32/1f91f-1f3fe.png new file mode 100644 index 00000000..31845092 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91f-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91f-1f3ff.png b/twake/frontend/public/public/emojione/32/1f91f-1f3ff.png new file mode 100644 index 00000000..26d418d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91f-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f91f.png b/twake/frontend/public/public/emojione/32/1f91f.png new file mode 100644 index 00000000..2bf463b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f91f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f920.png b/twake/frontend/public/public/emojione/32/1f920.png new file mode 100644 index 00000000..c3939e86 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f920.png differ diff --git a/twake/frontend/public/public/emojione/32/1f921.png b/twake/frontend/public/public/emojione/32/1f921.png new file mode 100644 index 00000000..7447da12 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f921.png differ diff --git a/twake/frontend/public/public/emojione/32/1f922.png b/twake/frontend/public/public/emojione/32/1f922.png new file mode 100644 index 00000000..2a6f889c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f922.png differ diff --git a/twake/frontend/public/public/emojione/32/1f923.png b/twake/frontend/public/public/emojione/32/1f923.png new file mode 100644 index 00000000..32ec9239 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f923.png differ diff --git a/twake/frontend/public/public/emojione/32/1f924.png b/twake/frontend/public/public/emojione/32/1f924.png new file mode 100644 index 00000000..29908f07 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f924.png differ diff --git a/twake/frontend/public/public/emojione/32/1f925.png b/twake/frontend/public/public/emojione/32/1f925.png new file mode 100644 index 00000000..567c1940 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f925.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f926-1f3fb-2640.png new file mode 100644 index 00000000..945fe38d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f926-1f3fb-2642.png new file mode 100644 index 00000000..3f6d4379 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926-1f3fb.png b/twake/frontend/public/public/emojione/32/1f926-1f3fb.png new file mode 100644 index 00000000..3cc1ca44 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f926-1f3fc-2640.png new file mode 100644 index 00000000..c2a380cf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f926-1f3fc-2642.png new file mode 100644 index 00000000..5d8fbcb5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926-1f3fc.png b/twake/frontend/public/public/emojione/32/1f926-1f3fc.png new file mode 100644 index 00000000..c2a380cf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f926-1f3fd-2640.png new file mode 100644 index 00000000..3a378536 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f926-1f3fd-2642.png new file mode 100644 index 00000000..07fddbc9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926-1f3fd.png b/twake/frontend/public/public/emojione/32/1f926-1f3fd.png new file mode 100644 index 00000000..87f2006e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f926-1f3fe-2640.png new file mode 100644 index 00000000..ccb4b698 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f926-1f3fe-2642.png new file mode 100644 index 00000000..d21d6759 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926-1f3fe.png b/twake/frontend/public/public/emojione/32/1f926-1f3fe.png new file mode 100644 index 00000000..f4c0ffb0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f926-1f3ff-2640.png new file mode 100644 index 00000000..f506127a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f926-1f3ff-2642.png new file mode 100644 index 00000000..014065a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926-1f3ff.png b/twake/frontend/public/public/emojione/32/1f926-1f3ff.png new file mode 100644 index 00000000..50f8200e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926-2640.png b/twake/frontend/public/public/emojione/32/1f926-2640.png new file mode 100644 index 00000000..dca31c19 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926-2642.png b/twake/frontend/public/public/emojione/32/1f926-2642.png new file mode 100644 index 00000000..cd648b9e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f926.png b/twake/frontend/public/public/emojione/32/1f926.png new file mode 100644 index 00000000..dca31c19 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f926.png differ diff --git a/twake/frontend/public/public/emojione/32/1f927.png b/twake/frontend/public/public/emojione/32/1f927.png new file mode 100644 index 00000000..391a2e69 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f927.png differ diff --git a/twake/frontend/public/public/emojione/32/1f928.png b/twake/frontend/public/public/emojione/32/1f928.png new file mode 100644 index 00000000..1c2ec421 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f928.png differ diff --git a/twake/frontend/public/public/emojione/32/1f929.png b/twake/frontend/public/public/emojione/32/1f929.png new file mode 100644 index 00000000..2a14b8cd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f929.png differ diff --git a/twake/frontend/public/public/emojione/32/1f92a.png b/twake/frontend/public/public/emojione/32/1f92a.png new file mode 100644 index 00000000..d27375a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f92a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f92b.png b/twake/frontend/public/public/emojione/32/1f92b.png new file mode 100644 index 00000000..dac1bde2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f92b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f92c.png b/twake/frontend/public/public/emojione/32/1f92c.png new file mode 100644 index 00000000..e02a49bd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f92c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f92d.png b/twake/frontend/public/public/emojione/32/1f92d.png new file mode 100644 index 00000000..968fe4df Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f92d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f92e.png b/twake/frontend/public/public/emojione/32/1f92e.png new file mode 100644 index 00000000..3023c9e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f92e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f92f.png b/twake/frontend/public/public/emojione/32/1f92f.png new file mode 100644 index 00000000..91824c03 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f92f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f930-1f3fb.png b/twake/frontend/public/public/emojione/32/1f930-1f3fb.png new file mode 100644 index 00000000..3b38092c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f930-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f930-1f3fc.png b/twake/frontend/public/public/emojione/32/1f930-1f3fc.png new file mode 100644 index 00000000..306ee19b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f930-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f930-1f3fd.png b/twake/frontend/public/public/emojione/32/1f930-1f3fd.png new file mode 100644 index 00000000..6cd347fa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f930-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f930-1f3fe.png b/twake/frontend/public/public/emojione/32/1f930-1f3fe.png new file mode 100644 index 00000000..9e450521 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f930-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f930-1f3ff.png b/twake/frontend/public/public/emojione/32/1f930-1f3ff.png new file mode 100644 index 00000000..3d8f20d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f930-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f930.png b/twake/frontend/public/public/emojione/32/1f930.png new file mode 100644 index 00000000..274b6885 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f930.png differ diff --git a/twake/frontend/public/public/emojione/32/1f931-1f3fb.png b/twake/frontend/public/public/emojione/32/1f931-1f3fb.png new file mode 100644 index 00000000..4dbf8242 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f931-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f931-1f3fc.png b/twake/frontend/public/public/emojione/32/1f931-1f3fc.png new file mode 100644 index 00000000..3ff55e35 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f931-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f931-1f3fd.png b/twake/frontend/public/public/emojione/32/1f931-1f3fd.png new file mode 100644 index 00000000..b0ff3918 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f931-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f931-1f3fe.png b/twake/frontend/public/public/emojione/32/1f931-1f3fe.png new file mode 100644 index 00000000..21cbec45 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f931-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f931-1f3ff.png b/twake/frontend/public/public/emojione/32/1f931-1f3ff.png new file mode 100644 index 00000000..407545f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f931-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f931.png b/twake/frontend/public/public/emojione/32/1f931.png new file mode 100644 index 00000000..a915b413 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f931.png differ diff --git a/twake/frontend/public/public/emojione/32/1f932-1f3fb.png b/twake/frontend/public/public/emojione/32/1f932-1f3fb.png new file mode 100644 index 00000000..134a724f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f932-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f932-1f3fc.png b/twake/frontend/public/public/emojione/32/1f932-1f3fc.png new file mode 100644 index 00000000..b7a0de17 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f932-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f932-1f3fd.png b/twake/frontend/public/public/emojione/32/1f932-1f3fd.png new file mode 100644 index 00000000..d6b59d81 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f932-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f932-1f3fe.png b/twake/frontend/public/public/emojione/32/1f932-1f3fe.png new file mode 100644 index 00000000..845f5344 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f932-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f932-1f3ff.png b/twake/frontend/public/public/emojione/32/1f932-1f3ff.png new file mode 100644 index 00000000..d6e91826 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f932-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f932.png b/twake/frontend/public/public/emojione/32/1f932.png new file mode 100644 index 00000000..b0cc4963 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f932.png differ diff --git a/twake/frontend/public/public/emojione/32/1f933-1f3fb.png b/twake/frontend/public/public/emojione/32/1f933-1f3fb.png new file mode 100644 index 00000000..c0b73c8d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f933-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f933-1f3fc.png b/twake/frontend/public/public/emojione/32/1f933-1f3fc.png new file mode 100644 index 00000000..79654992 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f933-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f933-1f3fd.png b/twake/frontend/public/public/emojione/32/1f933-1f3fd.png new file mode 100644 index 00000000..50152af9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f933-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f933-1f3fe.png b/twake/frontend/public/public/emojione/32/1f933-1f3fe.png new file mode 100644 index 00000000..ad4861bf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f933-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f933-1f3ff.png b/twake/frontend/public/public/emojione/32/1f933-1f3ff.png new file mode 100644 index 00000000..3631322d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f933-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f933.png b/twake/frontend/public/public/emojione/32/1f933.png new file mode 100644 index 00000000..7ad30c08 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f933.png differ diff --git a/twake/frontend/public/public/emojione/32/1f934-1f3fb.png b/twake/frontend/public/public/emojione/32/1f934-1f3fb.png new file mode 100644 index 00000000..41f2e17a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f934-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f934-1f3fc.png b/twake/frontend/public/public/emojione/32/1f934-1f3fc.png new file mode 100644 index 00000000..964470c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f934-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f934-1f3fd.png b/twake/frontend/public/public/emojione/32/1f934-1f3fd.png new file mode 100644 index 00000000..e5b6eaba Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f934-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f934-1f3fe.png b/twake/frontend/public/public/emojione/32/1f934-1f3fe.png new file mode 100644 index 00000000..742b456a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f934-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f934-1f3ff.png b/twake/frontend/public/public/emojione/32/1f934-1f3ff.png new file mode 100644 index 00000000..4a30c533 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f934-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f934.png b/twake/frontend/public/public/emojione/32/1f934.png new file mode 100644 index 00000000..b4429537 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f934.png differ diff --git a/twake/frontend/public/public/emojione/32/1f935-1f3fb.png b/twake/frontend/public/public/emojione/32/1f935-1f3fb.png new file mode 100644 index 00000000..609a8a33 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f935-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f935-1f3fc.png b/twake/frontend/public/public/emojione/32/1f935-1f3fc.png new file mode 100644 index 00000000..e287188b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f935-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f935-1f3fd.png b/twake/frontend/public/public/emojione/32/1f935-1f3fd.png new file mode 100644 index 00000000..40a471cb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f935-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f935-1f3fe.png b/twake/frontend/public/public/emojione/32/1f935-1f3fe.png new file mode 100644 index 00000000..82f02c58 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f935-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f935-1f3ff.png b/twake/frontend/public/public/emojione/32/1f935-1f3ff.png new file mode 100644 index 00000000..b297a7fa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f935-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f935.png b/twake/frontend/public/public/emojione/32/1f935.png new file mode 100644 index 00000000..d01f1f63 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f935.png differ diff --git a/twake/frontend/public/public/emojione/32/1f936-1f3fb.png b/twake/frontend/public/public/emojione/32/1f936-1f3fb.png new file mode 100644 index 00000000..64c6c1e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f936-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f936-1f3fc.png b/twake/frontend/public/public/emojione/32/1f936-1f3fc.png new file mode 100644 index 00000000..1067e9f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f936-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f936-1f3fd.png b/twake/frontend/public/public/emojione/32/1f936-1f3fd.png new file mode 100644 index 00000000..f6710209 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f936-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f936-1f3fe.png b/twake/frontend/public/public/emojione/32/1f936-1f3fe.png new file mode 100644 index 00000000..e7d68409 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f936-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f936-1f3ff.png b/twake/frontend/public/public/emojione/32/1f936-1f3ff.png new file mode 100644 index 00000000..93b656f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f936-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f936.png b/twake/frontend/public/public/emojione/32/1f936.png new file mode 100644 index 00000000..f018f28a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f936.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f937-1f3fb-2640.png new file mode 100644 index 00000000..51fca28e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f937-1f3fb-2642.png new file mode 100644 index 00000000..dc716610 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937-1f3fb.png b/twake/frontend/public/public/emojione/32/1f937-1f3fb.png new file mode 100644 index 00000000..6cc409bf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f937-1f3fc-2640.png new file mode 100644 index 00000000..80139b73 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f937-1f3fc-2642.png new file mode 100644 index 00000000..8c35dbb8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937-1f3fc.png b/twake/frontend/public/public/emojione/32/1f937-1f3fc.png new file mode 100644 index 00000000..5b2ad87d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f937-1f3fd-2640.png new file mode 100644 index 00000000..57829634 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f937-1f3fd-2642.png new file mode 100644 index 00000000..d8b6941d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937-1f3fd.png b/twake/frontend/public/public/emojione/32/1f937-1f3fd.png new file mode 100644 index 00000000..dc09b07e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f937-1f3fe-2640.png new file mode 100644 index 00000000..36eeb857 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f937-1f3fe-2642.png new file mode 100644 index 00000000..aa330aab Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937-1f3fe.png b/twake/frontend/public/public/emojione/32/1f937-1f3fe.png new file mode 100644 index 00000000..363395ca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f937-1f3ff-2640.png new file mode 100644 index 00000000..58c26396 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f937-1f3ff-2642.png new file mode 100644 index 00000000..7fd91856 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937-1f3ff.png b/twake/frontend/public/public/emojione/32/1f937-1f3ff.png new file mode 100644 index 00000000..d4d4ae2f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937-2640.png b/twake/frontend/public/public/emojione/32/1f937-2640.png new file mode 100644 index 00000000..c2bcfd82 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937-2642.png b/twake/frontend/public/public/emojione/32/1f937-2642.png new file mode 100644 index 00000000..6670f184 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f937.png b/twake/frontend/public/public/emojione/32/1f937.png new file mode 100644 index 00000000..c2bcfd82 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f937.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f938-1f3fb-2640.png new file mode 100644 index 00000000..cb482733 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f938-1f3fb-2642.png new file mode 100644 index 00000000..c22f87d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938-1f3fb.png b/twake/frontend/public/public/emojione/32/1f938-1f3fb.png new file mode 100644 index 00000000..c22f87d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f938-1f3fc-2640.png new file mode 100644 index 00000000..3228bb7e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f938-1f3fc-2642.png new file mode 100644 index 00000000..9e606c9c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938-1f3fc.png b/twake/frontend/public/public/emojione/32/1f938-1f3fc.png new file mode 100644 index 00000000..9e606c9c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f938-1f3fd-2640.png new file mode 100644 index 00000000..a269adf3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f938-1f3fd-2642.png new file mode 100644 index 00000000..439cd3f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938-1f3fd.png b/twake/frontend/public/public/emojione/32/1f938-1f3fd.png new file mode 100644 index 00000000..439cd3f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f938-1f3fe-2640.png new file mode 100644 index 00000000..7952cc73 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f938-1f3fe-2642.png new file mode 100644 index 00000000..e1d2876b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938-1f3fe.png b/twake/frontend/public/public/emojione/32/1f938-1f3fe.png new file mode 100644 index 00000000..e1d2876b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f938-1f3ff-2640.png new file mode 100644 index 00000000..34c4849b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f938-1f3ff-2642.png new file mode 100644 index 00000000..c5d83f62 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938-1f3ff.png b/twake/frontend/public/public/emojione/32/1f938-1f3ff.png new file mode 100644 index 00000000..c5d83f62 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938-2640.png b/twake/frontend/public/public/emojione/32/1f938-2640.png new file mode 100644 index 00000000..5bd3b3c4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938-2642.png b/twake/frontend/public/public/emojione/32/1f938-2642.png new file mode 100644 index 00000000..9cc14b8f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f938.png b/twake/frontend/public/public/emojione/32/1f938.png new file mode 100644 index 00000000..5bd3b3c4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f938.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f939-1f3fb-2640.png new file mode 100644 index 00000000..c87e2624 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f939-1f3fb-2642.png new file mode 100644 index 00000000..82e3f81f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939-1f3fb.png b/twake/frontend/public/public/emojione/32/1f939-1f3fb.png new file mode 100644 index 00000000..82e3f81f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f939-1f3fc-2640.png new file mode 100644 index 00000000..885b86a2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f939-1f3fc-2642.png new file mode 100644 index 00000000..d69f3129 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939-1f3fc.png b/twake/frontend/public/public/emojione/32/1f939-1f3fc.png new file mode 100644 index 00000000..d69f3129 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f939-1f3fd-2640.png new file mode 100644 index 00000000..3bea1654 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f939-1f3fd-2642.png new file mode 100644 index 00000000..040f5902 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939-1f3fd.png b/twake/frontend/public/public/emojione/32/1f939-1f3fd.png new file mode 100644 index 00000000..040f5902 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f939-1f3fe-2640.png new file mode 100644 index 00000000..20704b67 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f939-1f3fe-2642.png new file mode 100644 index 00000000..468e467a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939-1f3fe.png b/twake/frontend/public/public/emojione/32/1f939-1f3fe.png new file mode 100644 index 00000000..468e467a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f939-1f3ff-2640.png new file mode 100644 index 00000000..0a4f3212 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f939-1f3ff-2642.png new file mode 100644 index 00000000..ed162461 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939-1f3ff.png b/twake/frontend/public/public/emojione/32/1f939-1f3ff.png new file mode 100644 index 00000000..ed162461 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939-2640.png b/twake/frontend/public/public/emojione/32/1f939-2640.png new file mode 100644 index 00000000..9b6bf41e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939-2642.png b/twake/frontend/public/public/emojione/32/1f939-2642.png new file mode 100644 index 00000000..580072a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f939.png b/twake/frontend/public/public/emojione/32/1f939.png new file mode 100644 index 00000000..580072a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f939.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93a.png b/twake/frontend/public/public/emojione/32/1f93a.png new file mode 100644 index 00000000..eee67455 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93c-2640.png b/twake/frontend/public/public/emojione/32/1f93c-2640.png new file mode 100644 index 00000000..25da40e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93c-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93c-2642.png b/twake/frontend/public/public/emojione/32/1f93c-2642.png new file mode 100644 index 00000000..6e5d3056 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93c-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93c.png b/twake/frontend/public/public/emojione/32/1f93c.png new file mode 100644 index 00000000..6e5d3056 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f93d-1f3fb-2640.png new file mode 100644 index 00000000..d67360d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f93d-1f3fb-2642.png new file mode 100644 index 00000000..84c2e714 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d-1f3fb.png b/twake/frontend/public/public/emojione/32/1f93d-1f3fb.png new file mode 100644 index 00000000..84c2e714 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f93d-1f3fc-2640.png new file mode 100644 index 00000000..663a43b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f93d-1f3fc-2642.png new file mode 100644 index 00000000..56e42694 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d-1f3fc.png b/twake/frontend/public/public/emojione/32/1f93d-1f3fc.png new file mode 100644 index 00000000..56e42694 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f93d-1f3fd-2640.png new file mode 100644 index 00000000..634d894f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f93d-1f3fd-2642.png new file mode 100644 index 00000000..32738cb2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d-1f3fd.png b/twake/frontend/public/public/emojione/32/1f93d-1f3fd.png new file mode 100644 index 00000000..32738cb2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f93d-1f3fe-2640.png new file mode 100644 index 00000000..b7bef1dd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f93d-1f3fe-2642.png new file mode 100644 index 00000000..676deb51 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d-1f3fe.png b/twake/frontend/public/public/emojione/32/1f93d-1f3fe.png new file mode 100644 index 00000000..676deb51 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f93d-1f3ff-2640.png new file mode 100644 index 00000000..950fcb01 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f93d-1f3ff-2642.png new file mode 100644 index 00000000..10ec5331 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d-1f3ff.png b/twake/frontend/public/public/emojione/32/1f93d-1f3ff.png new file mode 100644 index 00000000..10ec5331 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d-2640.png b/twake/frontend/public/public/emojione/32/1f93d-2640.png new file mode 100644 index 00000000..f3db2f33 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d-2642.png b/twake/frontend/public/public/emojione/32/1f93d-2642.png new file mode 100644 index 00000000..05a5432c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93d.png b/twake/frontend/public/public/emojione/32/1f93d.png new file mode 100644 index 00000000..05a5432c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f93e-1f3fb-2640.png new file mode 100644 index 00000000..9a2f5244 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f93e-1f3fb-2642.png new file mode 100644 index 00000000..a7c7c6d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e-1f3fb.png b/twake/frontend/public/public/emojione/32/1f93e-1f3fb.png new file mode 100644 index 00000000..a7c7c6d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f93e-1f3fc-2640.png new file mode 100644 index 00000000..7be8ec57 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f93e-1f3fc-2642.png new file mode 100644 index 00000000..a6d2a2b6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e-1f3fc.png b/twake/frontend/public/public/emojione/32/1f93e-1f3fc.png new file mode 100644 index 00000000..a6d2a2b6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f93e-1f3fd-2640.png new file mode 100644 index 00000000..6ba7431e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f93e-1f3fd-2642.png new file mode 100644 index 00000000..e8075144 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e-1f3fd.png b/twake/frontend/public/public/emojione/32/1f93e-1f3fd.png new file mode 100644 index 00000000..e8075144 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f93e-1f3fe-2640.png new file mode 100644 index 00000000..941bfe3f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f93e-1f3fe-2642.png new file mode 100644 index 00000000..1cbc8184 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e-1f3fe.png b/twake/frontend/public/public/emojione/32/1f93e-1f3fe.png new file mode 100644 index 00000000..1cbc8184 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f93e-1f3ff-2640.png new file mode 100644 index 00000000..b359fc5d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f93e-1f3ff-2642.png new file mode 100644 index 00000000..273eb132 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e-1f3ff.png b/twake/frontend/public/public/emojione/32/1f93e-1f3ff.png new file mode 100644 index 00000000..273eb132 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e-2640.png b/twake/frontend/public/public/emojione/32/1f93e-2640.png new file mode 100644 index 00000000..e68fd93a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e-2642.png b/twake/frontend/public/public/emojione/32/1f93e-2642.png new file mode 100644 index 00000000..a6324cd7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f93e.png b/twake/frontend/public/public/emojione/32/1f93e.png new file mode 100644 index 00000000..a6324cd7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f93e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f940.png b/twake/frontend/public/public/emojione/32/1f940.png new file mode 100644 index 00000000..be720607 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f940.png differ diff --git a/twake/frontend/public/public/emojione/32/1f941.png b/twake/frontend/public/public/emojione/32/1f941.png new file mode 100644 index 00000000..2786e16c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f941.png differ diff --git a/twake/frontend/public/public/emojione/32/1f942.png b/twake/frontend/public/public/emojione/32/1f942.png new file mode 100644 index 00000000..16a45489 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f942.png differ diff --git a/twake/frontend/public/public/emojione/32/1f943.png b/twake/frontend/public/public/emojione/32/1f943.png new file mode 100644 index 00000000..7087a0a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f943.png differ diff --git a/twake/frontend/public/public/emojione/32/1f944.png b/twake/frontend/public/public/emojione/32/1f944.png new file mode 100644 index 00000000..8f4a3df3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f944.png differ diff --git a/twake/frontend/public/public/emojione/32/1f945.png b/twake/frontend/public/public/emojione/32/1f945.png new file mode 100644 index 00000000..a0a8a8be Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f945.png differ diff --git a/twake/frontend/public/public/emojione/32/1f947.png b/twake/frontend/public/public/emojione/32/1f947.png new file mode 100644 index 00000000..89a3421c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f947.png differ diff --git a/twake/frontend/public/public/emojione/32/1f948.png b/twake/frontend/public/public/emojione/32/1f948.png new file mode 100644 index 00000000..43a7f019 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f948.png differ diff --git a/twake/frontend/public/public/emojione/32/1f949.png b/twake/frontend/public/public/emojione/32/1f949.png new file mode 100644 index 00000000..2b57f7be Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f949.png differ diff --git a/twake/frontend/public/public/emojione/32/1f94a.png b/twake/frontend/public/public/emojione/32/1f94a.png new file mode 100644 index 00000000..fb5e004b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f94a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f94b.png b/twake/frontend/public/public/emojione/32/1f94b.png new file mode 100644 index 00000000..9df0ff39 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f94b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f94c.png b/twake/frontend/public/public/emojione/32/1f94c.png new file mode 100644 index 00000000..7077310c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f94c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f94d.png b/twake/frontend/public/public/emojione/32/1f94d.png new file mode 100644 index 00000000..e194aefd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f94d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f94e.png b/twake/frontend/public/public/emojione/32/1f94e.png new file mode 100644 index 00000000..e14a8a26 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f94e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f94f.png b/twake/frontend/public/public/emojione/32/1f94f.png new file mode 100644 index 00000000..4b434877 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f94f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f950.png b/twake/frontend/public/public/emojione/32/1f950.png new file mode 100644 index 00000000..93dd780c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f950.png differ diff --git a/twake/frontend/public/public/emojione/32/1f951.png b/twake/frontend/public/public/emojione/32/1f951.png new file mode 100644 index 00000000..275fa5ab Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f951.png differ diff --git a/twake/frontend/public/public/emojione/32/1f952.png b/twake/frontend/public/public/emojione/32/1f952.png new file mode 100644 index 00000000..e0dd7e50 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f952.png differ diff --git a/twake/frontend/public/public/emojione/32/1f953.png b/twake/frontend/public/public/emojione/32/1f953.png new file mode 100644 index 00000000..37c019c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f953.png differ diff --git a/twake/frontend/public/public/emojione/32/1f954.png b/twake/frontend/public/public/emojione/32/1f954.png new file mode 100644 index 00000000..34d467bd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f954.png differ diff --git a/twake/frontend/public/public/emojione/32/1f955.png b/twake/frontend/public/public/emojione/32/1f955.png new file mode 100644 index 00000000..6b641124 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f955.png differ diff --git a/twake/frontend/public/public/emojione/32/1f956.png b/twake/frontend/public/public/emojione/32/1f956.png new file mode 100644 index 00000000..61bed06c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f956.png differ diff --git a/twake/frontend/public/public/emojione/32/1f957.png b/twake/frontend/public/public/emojione/32/1f957.png new file mode 100644 index 00000000..acc87b48 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f957.png differ diff --git a/twake/frontend/public/public/emojione/32/1f958.png b/twake/frontend/public/public/emojione/32/1f958.png new file mode 100644 index 00000000..f0e44f86 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f958.png differ diff --git a/twake/frontend/public/public/emojione/32/1f959.png b/twake/frontend/public/public/emojione/32/1f959.png new file mode 100644 index 00000000..e6f3071f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f959.png differ diff --git a/twake/frontend/public/public/emojione/32/1f95a.png b/twake/frontend/public/public/emojione/32/1f95a.png new file mode 100644 index 00000000..ca82b15b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f95a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f95b.png b/twake/frontend/public/public/emojione/32/1f95b.png new file mode 100644 index 00000000..1462bcaa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f95b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f95c.png b/twake/frontend/public/public/emojione/32/1f95c.png new file mode 100644 index 00000000..17a00be5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f95c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f95d.png b/twake/frontend/public/public/emojione/32/1f95d.png new file mode 100644 index 00000000..c2120bb6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f95d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f95e.png b/twake/frontend/public/public/emojione/32/1f95e.png new file mode 100644 index 00000000..d39c924d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f95e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f95f.png b/twake/frontend/public/public/emojione/32/1f95f.png new file mode 100644 index 00000000..8b85ab50 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f95f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f960.png b/twake/frontend/public/public/emojione/32/1f960.png new file mode 100644 index 00000000..ab0d52d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f960.png differ diff --git a/twake/frontend/public/public/emojione/32/1f961.png b/twake/frontend/public/public/emojione/32/1f961.png new file mode 100644 index 00000000..b2e054a8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f961.png differ diff --git a/twake/frontend/public/public/emojione/32/1f962.png b/twake/frontend/public/public/emojione/32/1f962.png new file mode 100644 index 00000000..700cf39e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f962.png differ diff --git a/twake/frontend/public/public/emojione/32/1f963.png b/twake/frontend/public/public/emojione/32/1f963.png new file mode 100644 index 00000000..88ca804f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f963.png differ diff --git a/twake/frontend/public/public/emojione/32/1f964.png b/twake/frontend/public/public/emojione/32/1f964.png new file mode 100644 index 00000000..faa6efd1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f964.png differ diff --git a/twake/frontend/public/public/emojione/32/1f965.png b/twake/frontend/public/public/emojione/32/1f965.png new file mode 100644 index 00000000..67dec5b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f965.png differ diff --git a/twake/frontend/public/public/emojione/32/1f966.png b/twake/frontend/public/public/emojione/32/1f966.png new file mode 100644 index 00000000..2a123475 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f966.png differ diff --git a/twake/frontend/public/public/emojione/32/1f967.png b/twake/frontend/public/public/emojione/32/1f967.png new file mode 100644 index 00000000..9da1acc1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f967.png differ diff --git a/twake/frontend/public/public/emojione/32/1f968.png b/twake/frontend/public/public/emojione/32/1f968.png new file mode 100644 index 00000000..2c646011 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f968.png differ diff --git a/twake/frontend/public/public/emojione/32/1f969.png b/twake/frontend/public/public/emojione/32/1f969.png new file mode 100644 index 00000000..57734481 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f969.png differ diff --git a/twake/frontend/public/public/emojione/32/1f96a.png b/twake/frontend/public/public/emojione/32/1f96a.png new file mode 100644 index 00000000..278cc013 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f96a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f96b.png b/twake/frontend/public/public/emojione/32/1f96b.png new file mode 100644 index 00000000..0a503b2e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f96b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f96c.png b/twake/frontend/public/public/emojione/32/1f96c.png new file mode 100644 index 00000000..ca404b43 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f96c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f96d.png b/twake/frontend/public/public/emojione/32/1f96d.png new file mode 100644 index 00000000..58f00179 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f96d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f96e.png b/twake/frontend/public/public/emojione/32/1f96e.png new file mode 100644 index 00000000..f18161c5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f96e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f96f.png b/twake/frontend/public/public/emojione/32/1f96f.png new file mode 100644 index 00000000..f27b1170 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f96f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f970.png b/twake/frontend/public/public/emojione/32/1f970.png new file mode 100644 index 00000000..67c85a2f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f970.png differ diff --git a/twake/frontend/public/public/emojione/32/1f973.png b/twake/frontend/public/public/emojione/32/1f973.png new file mode 100644 index 00000000..d2abaadb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f973.png differ diff --git a/twake/frontend/public/public/emojione/32/1f974.png b/twake/frontend/public/public/emojione/32/1f974.png new file mode 100644 index 00000000..46ac4ba5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f974.png differ diff --git a/twake/frontend/public/public/emojione/32/1f975.png b/twake/frontend/public/public/emojione/32/1f975.png new file mode 100644 index 00000000..e42a43a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f975.png differ diff --git a/twake/frontend/public/public/emojione/32/1f976.png b/twake/frontend/public/public/emojione/32/1f976.png new file mode 100644 index 00000000..79e2c597 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f976.png differ diff --git a/twake/frontend/public/public/emojione/32/1f97a.png b/twake/frontend/public/public/emojione/32/1f97a.png new file mode 100644 index 00000000..fb35800c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f97a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f97c.png b/twake/frontend/public/public/emojione/32/1f97c.png new file mode 100644 index 00000000..6312719c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f97c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f97d.png b/twake/frontend/public/public/emojione/32/1f97d.png new file mode 100644 index 00000000..8b69cc17 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f97d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f97e.png b/twake/frontend/public/public/emojione/32/1f97e.png new file mode 100644 index 00000000..39f23090 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f97e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f97f.png b/twake/frontend/public/public/emojione/32/1f97f.png new file mode 100644 index 00000000..9d8dd21e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f97f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f980.png b/twake/frontend/public/public/emojione/32/1f980.png new file mode 100644 index 00000000..46cf44fa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f980.png differ diff --git a/twake/frontend/public/public/emojione/32/1f981.png b/twake/frontend/public/public/emojione/32/1f981.png new file mode 100644 index 00000000..00c6faa9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f981.png differ diff --git a/twake/frontend/public/public/emojione/32/1f982.png b/twake/frontend/public/public/emojione/32/1f982.png new file mode 100644 index 00000000..14502b5a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f982.png differ diff --git a/twake/frontend/public/public/emojione/32/1f983.png b/twake/frontend/public/public/emojione/32/1f983.png new file mode 100644 index 00000000..a47c2d50 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f983.png differ diff --git a/twake/frontend/public/public/emojione/32/1f984.png b/twake/frontend/public/public/emojione/32/1f984.png new file mode 100644 index 00000000..3249b9d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f984.png differ diff --git a/twake/frontend/public/public/emojione/32/1f985.png b/twake/frontend/public/public/emojione/32/1f985.png new file mode 100644 index 00000000..21bd4594 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f985.png differ diff --git a/twake/frontend/public/public/emojione/32/1f986.png b/twake/frontend/public/public/emojione/32/1f986.png new file mode 100644 index 00000000..38bc625e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f986.png differ diff --git a/twake/frontend/public/public/emojione/32/1f987.png b/twake/frontend/public/public/emojione/32/1f987.png new file mode 100644 index 00000000..577a023c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f987.png differ diff --git a/twake/frontend/public/public/emojione/32/1f988.png b/twake/frontend/public/public/emojione/32/1f988.png new file mode 100644 index 00000000..3865d7b9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f988.png differ diff --git a/twake/frontend/public/public/emojione/32/1f989.png b/twake/frontend/public/public/emojione/32/1f989.png new file mode 100644 index 00000000..2697b2ce Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f989.png differ diff --git a/twake/frontend/public/public/emojione/32/1f98a.png b/twake/frontend/public/public/emojione/32/1f98a.png new file mode 100644 index 00000000..7d03c553 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f98a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f98b.png b/twake/frontend/public/public/emojione/32/1f98b.png new file mode 100644 index 00000000..2d252544 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f98b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f98c.png b/twake/frontend/public/public/emojione/32/1f98c.png new file mode 100644 index 00000000..21ee5c43 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f98c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f98d.png b/twake/frontend/public/public/emojione/32/1f98d.png new file mode 100644 index 00000000..6344e612 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f98d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f98e.png b/twake/frontend/public/public/emojione/32/1f98e.png new file mode 100644 index 00000000..448bbfef Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f98e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f98f.png b/twake/frontend/public/public/emojione/32/1f98f.png new file mode 100644 index 00000000..21e6990f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f98f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f990.png b/twake/frontend/public/public/emojione/32/1f990.png new file mode 100644 index 00000000..75f958ed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f990.png differ diff --git a/twake/frontend/public/public/emojione/32/1f991.png b/twake/frontend/public/public/emojione/32/1f991.png new file mode 100644 index 00000000..2a4b3b7a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f991.png differ diff --git a/twake/frontend/public/public/emojione/32/1f992.png b/twake/frontend/public/public/emojione/32/1f992.png new file mode 100644 index 00000000..979a66de Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f992.png differ diff --git a/twake/frontend/public/public/emojione/32/1f993.png b/twake/frontend/public/public/emojione/32/1f993.png new file mode 100644 index 00000000..0139aafa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f993.png differ diff --git a/twake/frontend/public/public/emojione/32/1f994.png b/twake/frontend/public/public/emojione/32/1f994.png new file mode 100644 index 00000000..36d8a86d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f994.png differ diff --git a/twake/frontend/public/public/emojione/32/1f995.png b/twake/frontend/public/public/emojione/32/1f995.png new file mode 100644 index 00000000..90169372 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f995.png differ diff --git a/twake/frontend/public/public/emojione/32/1f996.png b/twake/frontend/public/public/emojione/32/1f996.png new file mode 100644 index 00000000..9c0e20b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f996.png differ diff --git a/twake/frontend/public/public/emojione/32/1f997.png b/twake/frontend/public/public/emojione/32/1f997.png new file mode 100644 index 00000000..46f17f41 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f997.png differ diff --git a/twake/frontend/public/public/emojione/32/1f998.png b/twake/frontend/public/public/emojione/32/1f998.png new file mode 100644 index 00000000..e5f67877 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f998.png differ diff --git a/twake/frontend/public/public/emojione/32/1f999.png b/twake/frontend/public/public/emojione/32/1f999.png new file mode 100644 index 00000000..552f7e94 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f999.png differ diff --git a/twake/frontend/public/public/emojione/32/1f99a.png b/twake/frontend/public/public/emojione/32/1f99a.png new file mode 100644 index 00000000..308ed641 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f99a.png differ diff --git a/twake/frontend/public/public/emojione/32/1f99b.png b/twake/frontend/public/public/emojione/32/1f99b.png new file mode 100644 index 00000000..52fd152e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f99b.png differ diff --git a/twake/frontend/public/public/emojione/32/1f99c.png b/twake/frontend/public/public/emojione/32/1f99c.png new file mode 100644 index 00000000..22c16aa0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f99c.png differ diff --git a/twake/frontend/public/public/emojione/32/1f99d.png b/twake/frontend/public/public/emojione/32/1f99d.png new file mode 100644 index 00000000..8b90de6d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f99d.png differ diff --git a/twake/frontend/public/public/emojione/32/1f99e.png b/twake/frontend/public/public/emojione/32/1f99e.png new file mode 100644 index 00000000..cbc9b846 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f99e.png differ diff --git a/twake/frontend/public/public/emojione/32/1f99f.png b/twake/frontend/public/public/emojione/32/1f99f.png new file mode 100644 index 00000000..34d1b86e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f99f.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9a0.png b/twake/frontend/public/public/emojione/32/1f9a0.png new file mode 100644 index 00000000..6f82dc24 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9a0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9a1.png b/twake/frontend/public/public/emojione/32/1f9a1.png new file mode 100644 index 00000000..fd59dc92 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9a1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9a2.png b/twake/frontend/public/public/emojione/32/1f9a2.png new file mode 100644 index 00000000..a316bc45 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9a2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b0.png b/twake/frontend/public/public/emojione/32/1f9b0.png new file mode 100644 index 00000000..bdae5729 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b1.png b/twake/frontend/public/public/emojione/32/1f9b1.png new file mode 100644 index 00000000..3edfdb37 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b2.png b/twake/frontend/public/public/emojione/32/1f9b2.png new file mode 100644 index 00000000..91a54a68 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b3.png b/twake/frontend/public/public/emojione/32/1f9b3.png new file mode 100644 index 00000000..62f9a430 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b4.png b/twake/frontend/public/public/emojione/32/1f9b4.png new file mode 100644 index 00000000..6fb3560e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b5-1f3fb.png b/twake/frontend/public/public/emojione/32/1f9b5-1f3fb.png new file mode 100644 index 00000000..61a2b4a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b5-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b5-1f3fc.png b/twake/frontend/public/public/emojione/32/1f9b5-1f3fc.png new file mode 100644 index 00000000..29603e8b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b5-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b5-1f3fd.png b/twake/frontend/public/public/emojione/32/1f9b5-1f3fd.png new file mode 100644 index 00000000..23e3c3f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b5-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b5-1f3fe.png b/twake/frontend/public/public/emojione/32/1f9b5-1f3fe.png new file mode 100644 index 00000000..7c9e63a2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b5-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b5-1f3ff.png b/twake/frontend/public/public/emojione/32/1f9b5-1f3ff.png new file mode 100644 index 00000000..9306e522 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b5-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b5.png b/twake/frontend/public/public/emojione/32/1f9b5.png new file mode 100644 index 00000000..d42f7dc9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b6-1f3fb.png b/twake/frontend/public/public/emojione/32/1f9b6-1f3fb.png new file mode 100644 index 00000000..1842ce9f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b6-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b6-1f3fc.png b/twake/frontend/public/public/emojione/32/1f9b6-1f3fc.png new file mode 100644 index 00000000..de4a829a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b6-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b6-1f3fd.png b/twake/frontend/public/public/emojione/32/1f9b6-1f3fd.png new file mode 100644 index 00000000..87efb2bb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b6-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b6-1f3fe.png b/twake/frontend/public/public/emojione/32/1f9b6-1f3fe.png new file mode 100644 index 00000000..0bde8779 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b6-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b6-1f3ff.png b/twake/frontend/public/public/emojione/32/1f9b6-1f3ff.png new file mode 100644 index 00000000..faebfb2d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b6-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b6.png b/twake/frontend/public/public/emojione/32/1f9b6.png new file mode 100644 index 00000000..3681f446 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b7.png b/twake/frontend/public/public/emojione/32/1f9b7.png new file mode 100644 index 00000000..ec26dfad Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f9b8-1f3fb-2640.png new file mode 100644 index 00000000..dc5a6b91 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f9b8-1f3fb-2642.png new file mode 100644 index 00000000..93c711df Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8-1f3fb.png b/twake/frontend/public/public/emojione/32/1f9b8-1f3fb.png new file mode 100644 index 00000000..dc5a6b91 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f9b8-1f3fc-2640.png new file mode 100644 index 00000000..e392b4ad Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f9b8-1f3fc-2642.png new file mode 100644 index 00000000..e011fa37 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8-1f3fc.png b/twake/frontend/public/public/emojione/32/1f9b8-1f3fc.png new file mode 100644 index 00000000..e392b4ad Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f9b8-1f3fd-2640.png new file mode 100644 index 00000000..6c78221c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f9b8-1f3fd-2642.png new file mode 100644 index 00000000..d82d2282 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8-1f3fd.png b/twake/frontend/public/public/emojione/32/1f9b8-1f3fd.png new file mode 100644 index 00000000..6c78221c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f9b8-1f3fe-2640.png new file mode 100644 index 00000000..b1015d76 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f9b8-1f3fe-2642.png new file mode 100644 index 00000000..4d7fc977 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8-1f3fe.png b/twake/frontend/public/public/emojione/32/1f9b8-1f3fe.png new file mode 100644 index 00000000..b1015d76 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f9b8-1f3ff-2640.png new file mode 100644 index 00000000..e7e33d0a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f9b8-1f3ff-2642.png new file mode 100644 index 00000000..324c059c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8-1f3ff.png b/twake/frontend/public/public/emojione/32/1f9b8-1f3ff.png new file mode 100644 index 00000000..e7e33d0a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8-2640.png b/twake/frontend/public/public/emojione/32/1f9b8-2640.png new file mode 100644 index 00000000..77a40737 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8-2642.png b/twake/frontend/public/public/emojione/32/1f9b8-2642.png new file mode 100644 index 00000000..3d44130e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b8.png b/twake/frontend/public/public/emojione/32/1f9b8.png new file mode 100644 index 00000000..77a40737 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f9b9-1f3fb-2640.png new file mode 100644 index 00000000..46629cb8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f9b9-1f3fb-2642.png new file mode 100644 index 00000000..659907b9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9-1f3fb.png b/twake/frontend/public/public/emojione/32/1f9b9-1f3fb.png new file mode 100644 index 00000000..46629cb8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f9b9-1f3fc-2640.png new file mode 100644 index 00000000..fe062a2a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f9b9-1f3fc-2642.png new file mode 100644 index 00000000..25e1feb8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9-1f3fc.png b/twake/frontend/public/public/emojione/32/1f9b9-1f3fc.png new file mode 100644 index 00000000..fe062a2a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f9b9-1f3fd-2640.png new file mode 100644 index 00000000..d8cf5bfc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f9b9-1f3fd-2642.png new file mode 100644 index 00000000..88477697 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9-1f3fd.png b/twake/frontend/public/public/emojione/32/1f9b9-1f3fd.png new file mode 100644 index 00000000..d8cf5bfc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f9b9-1f3fe-2640.png new file mode 100644 index 00000000..de39e295 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f9b9-1f3fe-2642.png new file mode 100644 index 00000000..9d466b99 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9-1f3fe.png b/twake/frontend/public/public/emojione/32/1f9b9-1f3fe.png new file mode 100644 index 00000000..de39e295 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f9b9-1f3ff-2640.png new file mode 100644 index 00000000..cadeeaad Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f9b9-1f3ff-2642.png new file mode 100644 index 00000000..6a86cdbe Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9-1f3ff.png b/twake/frontend/public/public/emojione/32/1f9b9-1f3ff.png new file mode 100644 index 00000000..cadeeaad Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9-2640.png b/twake/frontend/public/public/emojione/32/1f9b9-2640.png new file mode 100644 index 00000000..86c1079c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9-2642.png b/twake/frontend/public/public/emojione/32/1f9b9-2642.png new file mode 100644 index 00000000..28eea16a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9b9.png b/twake/frontend/public/public/emojione/32/1f9b9.png new file mode 100644 index 00000000..86c1079c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9b9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9c0.png b/twake/frontend/public/public/emojione/32/1f9c0.png new file mode 100644 index 00000000..1efd6a88 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9c0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9c1.png b/twake/frontend/public/public/emojione/32/1f9c1.png new file mode 100644 index 00000000..d336c08e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9c1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9c2.png b/twake/frontend/public/public/emojione/32/1f9c2.png new file mode 100644 index 00000000..7672f2d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9c2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d0.png b/twake/frontend/public/public/emojione/32/1f9d0.png new file mode 100644 index 00000000..eb4a4250 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d1-1f3fb.png b/twake/frontend/public/public/emojione/32/1f9d1-1f3fb.png new file mode 100644 index 00000000..d1740735 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d1-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d1-1f3fc.png b/twake/frontend/public/public/emojione/32/1f9d1-1f3fc.png new file mode 100644 index 00000000..7bd1b6e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d1-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d1-1f3fd.png b/twake/frontend/public/public/emojione/32/1f9d1-1f3fd.png new file mode 100644 index 00000000..ca3d1bd3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d1-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d1-1f3fe.png b/twake/frontend/public/public/emojione/32/1f9d1-1f3fe.png new file mode 100644 index 00000000..d32eee08 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d1-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d1-1f3ff.png b/twake/frontend/public/public/emojione/32/1f9d1-1f3ff.png new file mode 100644 index 00000000..c28db483 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d1-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d1.png b/twake/frontend/public/public/emojione/32/1f9d1.png new file mode 100644 index 00000000..f78ac24a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d2-1f3fb.png b/twake/frontend/public/public/emojione/32/1f9d2-1f3fb.png new file mode 100644 index 00000000..6d17296e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d2-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d2-1f3fc.png b/twake/frontend/public/public/emojione/32/1f9d2-1f3fc.png new file mode 100644 index 00000000..da3aaccc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d2-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d2-1f3fd.png b/twake/frontend/public/public/emojione/32/1f9d2-1f3fd.png new file mode 100644 index 00000000..13255d78 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d2-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d2-1f3fe.png b/twake/frontend/public/public/emojione/32/1f9d2-1f3fe.png new file mode 100644 index 00000000..106590d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d2-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d2-1f3ff.png b/twake/frontend/public/public/emojione/32/1f9d2-1f3ff.png new file mode 100644 index 00000000..9f8d4b95 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d2-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d2.png b/twake/frontend/public/public/emojione/32/1f9d2.png new file mode 100644 index 00000000..55073af5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d3-1f3fb.png b/twake/frontend/public/public/emojione/32/1f9d3-1f3fb.png new file mode 100644 index 00000000..0cd73e5b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d3-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d3-1f3fc.png b/twake/frontend/public/public/emojione/32/1f9d3-1f3fc.png new file mode 100644 index 00000000..edee768a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d3-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d3-1f3fd.png b/twake/frontend/public/public/emojione/32/1f9d3-1f3fd.png new file mode 100644 index 00000000..b2e7ffce Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d3-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d3-1f3fe.png b/twake/frontend/public/public/emojione/32/1f9d3-1f3fe.png new file mode 100644 index 00000000..200707f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d3-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d3-1f3ff.png b/twake/frontend/public/public/emojione/32/1f9d3-1f3ff.png new file mode 100644 index 00000000..4f7ae283 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d3-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d3.png b/twake/frontend/public/public/emojione/32/1f9d3.png new file mode 100644 index 00000000..3d5b059e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d4-1f3fb.png b/twake/frontend/public/public/emojione/32/1f9d4-1f3fb.png new file mode 100644 index 00000000..e2886dd6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d4-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d4-1f3fc.png b/twake/frontend/public/public/emojione/32/1f9d4-1f3fc.png new file mode 100644 index 00000000..91172ad5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d4-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d4-1f3fd.png b/twake/frontend/public/public/emojione/32/1f9d4-1f3fd.png new file mode 100644 index 00000000..339d1dc4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d4-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d4-1f3fe.png b/twake/frontend/public/public/emojione/32/1f9d4-1f3fe.png new file mode 100644 index 00000000..ff6c136f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d4-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d4-1f3ff.png b/twake/frontend/public/public/emojione/32/1f9d4-1f3ff.png new file mode 100644 index 00000000..041f8083 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d4-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d4.png b/twake/frontend/public/public/emojione/32/1f9d4.png new file mode 100644 index 00000000..915f7102 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d5-1f3fb.png b/twake/frontend/public/public/emojione/32/1f9d5-1f3fb.png new file mode 100644 index 00000000..5c10b54b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d5-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d5-1f3fc.png b/twake/frontend/public/public/emojione/32/1f9d5-1f3fc.png new file mode 100644 index 00000000..db44095f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d5-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d5-1f3fd.png b/twake/frontend/public/public/emojione/32/1f9d5-1f3fd.png new file mode 100644 index 00000000..af8c913e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d5-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d5-1f3fe.png b/twake/frontend/public/public/emojione/32/1f9d5-1f3fe.png new file mode 100644 index 00000000..7a5ded4d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d5-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d5-1f3ff.png b/twake/frontend/public/public/emojione/32/1f9d5-1f3ff.png new file mode 100644 index 00000000..534d91d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d5-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d5.png b/twake/frontend/public/public/emojione/32/1f9d5.png new file mode 100644 index 00000000..c05f0ce8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f9d6-1f3fb-2640.png new file mode 100644 index 00000000..5cb3aa40 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f9d6-1f3fb-2642.png new file mode 100644 index 00000000..32386595 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6-1f3fb.png b/twake/frontend/public/public/emojione/32/1f9d6-1f3fb.png new file mode 100644 index 00000000..5cb3aa40 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f9d6-1f3fc-2640.png new file mode 100644 index 00000000..7bbadb35 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f9d6-1f3fc-2642.png new file mode 100644 index 00000000..1a4ebe6f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6-1f3fc.png b/twake/frontend/public/public/emojione/32/1f9d6-1f3fc.png new file mode 100644 index 00000000..7bbadb35 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f9d6-1f3fd-2640.png new file mode 100644 index 00000000..493505b7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f9d6-1f3fd-2642.png new file mode 100644 index 00000000..80f0aeab Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6-1f3fd.png b/twake/frontend/public/public/emojione/32/1f9d6-1f3fd.png new file mode 100644 index 00000000..493505b7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f9d6-1f3fe-2640.png new file mode 100644 index 00000000..48a09606 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f9d6-1f3fe-2642.png new file mode 100644 index 00000000..20f7141f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6-1f3fe.png b/twake/frontend/public/public/emojione/32/1f9d6-1f3fe.png new file mode 100644 index 00000000..48a09606 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f9d6-1f3ff-2640.png new file mode 100644 index 00000000..f164d7a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f9d6-1f3ff-2642.png new file mode 100644 index 00000000..104a3dee Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6-1f3ff.png b/twake/frontend/public/public/emojione/32/1f9d6-1f3ff.png new file mode 100644 index 00000000..f164d7a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6-2640.png b/twake/frontend/public/public/emojione/32/1f9d6-2640.png new file mode 100644 index 00000000..ec721202 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6-2642.png b/twake/frontend/public/public/emojione/32/1f9d6-2642.png new file mode 100644 index 00000000..556e2bd5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d6.png b/twake/frontend/public/public/emojione/32/1f9d6.png new file mode 100644 index 00000000..ec721202 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f9d7-1f3fb-2640.png new file mode 100644 index 00000000..bb97cf05 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f9d7-1f3fb-2642.png new file mode 100644 index 00000000..8c81d8a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7-1f3fb.png b/twake/frontend/public/public/emojione/32/1f9d7-1f3fb.png new file mode 100644 index 00000000..bb97cf05 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f9d7-1f3fc-2640.png new file mode 100644 index 00000000..d622a8ae Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f9d7-1f3fc-2642.png new file mode 100644 index 00000000..9c3aacef Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7-1f3fc.png b/twake/frontend/public/public/emojione/32/1f9d7-1f3fc.png new file mode 100644 index 00000000..d622a8ae Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f9d7-1f3fd-2640.png new file mode 100644 index 00000000..d839646b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f9d7-1f3fd-2642.png new file mode 100644 index 00000000..1aa2a90e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7-1f3fd.png b/twake/frontend/public/public/emojione/32/1f9d7-1f3fd.png new file mode 100644 index 00000000..d839646b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f9d7-1f3fe-2640.png new file mode 100644 index 00000000..c3ca65c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f9d7-1f3fe-2642.png new file mode 100644 index 00000000..4164a80f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7-1f3fe.png b/twake/frontend/public/public/emojione/32/1f9d7-1f3fe.png new file mode 100644 index 00000000..c3ca65c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f9d7-1f3ff-2640.png new file mode 100644 index 00000000..75e6a155 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f9d7-1f3ff-2642.png new file mode 100644 index 00000000..d6dbb892 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7-1f3ff.png b/twake/frontend/public/public/emojione/32/1f9d7-1f3ff.png new file mode 100644 index 00000000..75e6a155 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7-2640.png b/twake/frontend/public/public/emojione/32/1f9d7-2640.png new file mode 100644 index 00000000..981b3431 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7-2642.png b/twake/frontend/public/public/emojione/32/1f9d7-2642.png new file mode 100644 index 00000000..ca76b8f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d7.png b/twake/frontend/public/public/emojione/32/1f9d7.png new file mode 100644 index 00000000..330c6dfa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f9d8-1f3fb-2640.png new file mode 100644 index 00000000..c1a3814b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f9d8-1f3fb-2642.png new file mode 100644 index 00000000..dc00eb81 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8-1f3fb.png b/twake/frontend/public/public/emojione/32/1f9d8-1f3fb.png new file mode 100644 index 00000000..c1a3814b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f9d8-1f3fc-2640.png new file mode 100644 index 00000000..323d9bd9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f9d8-1f3fc-2642.png new file mode 100644 index 00000000..9055b6d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8-1f3fc.png b/twake/frontend/public/public/emojione/32/1f9d8-1f3fc.png new file mode 100644 index 00000000..323d9bd9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f9d8-1f3fd-2640.png new file mode 100644 index 00000000..2cae46c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f9d8-1f3fd-2642.png new file mode 100644 index 00000000..cc1a632e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8-1f3fd.png b/twake/frontend/public/public/emojione/32/1f9d8-1f3fd.png new file mode 100644 index 00000000..2cae46c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f9d8-1f3fe-2640.png new file mode 100644 index 00000000..2d1b0f08 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f9d8-1f3fe-2642.png new file mode 100644 index 00000000..7a26559f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8-1f3fe.png b/twake/frontend/public/public/emojione/32/1f9d8-1f3fe.png new file mode 100644 index 00000000..2d1b0f08 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f9d8-1f3ff-2640.png new file mode 100644 index 00000000..46eac704 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f9d8-1f3ff-2642.png new file mode 100644 index 00000000..a41c95f3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8-1f3ff.png b/twake/frontend/public/public/emojione/32/1f9d8-1f3ff.png new file mode 100644 index 00000000..46eac704 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8-2640.png b/twake/frontend/public/public/emojione/32/1f9d8-2640.png new file mode 100644 index 00000000..728d74f3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8-2642.png b/twake/frontend/public/public/emojione/32/1f9d8-2642.png new file mode 100644 index 00000000..fa61e27d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d8.png b/twake/frontend/public/public/emojione/32/1f9d8.png new file mode 100644 index 00000000..728d74f3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f9d9-1f3fb-2640.png new file mode 100644 index 00000000..d8352d66 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f9d9-1f3fb-2642.png new file mode 100644 index 00000000..d12e5221 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9-1f3fb.png b/twake/frontend/public/public/emojione/32/1f9d9-1f3fb.png new file mode 100644 index 00000000..d8352d66 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f9d9-1f3fc-2640.png new file mode 100644 index 00000000..cb343b26 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f9d9-1f3fc-2642.png new file mode 100644 index 00000000..88a3cf53 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9-1f3fc.png b/twake/frontend/public/public/emojione/32/1f9d9-1f3fc.png new file mode 100644 index 00000000..cb343b26 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f9d9-1f3fd-2640.png new file mode 100644 index 00000000..dc8c174c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f9d9-1f3fd-2642.png new file mode 100644 index 00000000..2e26abc2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9-1f3fd.png b/twake/frontend/public/public/emojione/32/1f9d9-1f3fd.png new file mode 100644 index 00000000..dc8c174c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f9d9-1f3fe-2640.png new file mode 100644 index 00000000..02bbabd6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f9d9-1f3fe-2642.png new file mode 100644 index 00000000..28d010fe Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9-1f3fe.png b/twake/frontend/public/public/emojione/32/1f9d9-1f3fe.png new file mode 100644 index 00000000..02bbabd6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f9d9-1f3ff-2640.png new file mode 100644 index 00000000..23aadc4f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f9d9-1f3ff-2642.png new file mode 100644 index 00000000..eb66bd12 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9-1f3ff.png b/twake/frontend/public/public/emojione/32/1f9d9-1f3ff.png new file mode 100644 index 00000000..23aadc4f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9-2640.png b/twake/frontend/public/public/emojione/32/1f9d9-2640.png new file mode 100644 index 00000000..98fb00fc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9-2642.png b/twake/frontend/public/public/emojione/32/1f9d9-2642.png new file mode 100644 index 00000000..3385d424 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9d9.png b/twake/frontend/public/public/emojione/32/1f9d9.png new file mode 100644 index 00000000..98fb00fc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9d9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f9da-1f3fb-2640.png new file mode 100644 index 00000000..8e664e99 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f9da-1f3fb-2642.png new file mode 100644 index 00000000..131e914e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da-1f3fb.png b/twake/frontend/public/public/emojione/32/1f9da-1f3fb.png new file mode 100644 index 00000000..8e664e99 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f9da-1f3fc-2640.png new file mode 100644 index 00000000..b14ad5c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f9da-1f3fc-2642.png new file mode 100644 index 00000000..eeb4efa8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da-1f3fc.png b/twake/frontend/public/public/emojione/32/1f9da-1f3fc.png new file mode 100644 index 00000000..b14ad5c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f9da-1f3fd-2640.png new file mode 100644 index 00000000..4bf1a595 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f9da-1f3fd-2642.png new file mode 100644 index 00000000..b6c949c4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da-1f3fd.png b/twake/frontend/public/public/emojione/32/1f9da-1f3fd.png new file mode 100644 index 00000000..4bf1a595 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f9da-1f3fe-2640.png new file mode 100644 index 00000000..52e978d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f9da-1f3fe-2642.png new file mode 100644 index 00000000..93f7bf83 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da-1f3fe.png b/twake/frontend/public/public/emojione/32/1f9da-1f3fe.png new file mode 100644 index 00000000..52e978d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f9da-1f3ff-2640.png new file mode 100644 index 00000000..1349243e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f9da-1f3ff-2642.png new file mode 100644 index 00000000..d7bfb6f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da-1f3ff.png b/twake/frontend/public/public/emojione/32/1f9da-1f3ff.png new file mode 100644 index 00000000..1349243e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da-2640.png b/twake/frontend/public/public/emojione/32/1f9da-2640.png new file mode 100644 index 00000000..a87245c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da-2642.png b/twake/frontend/public/public/emojione/32/1f9da-2642.png new file mode 100644 index 00000000..e3822509 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9da.png b/twake/frontend/public/public/emojione/32/1f9da.png new file mode 100644 index 00000000..a87245c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9da.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f9db-1f3fb-2640.png new file mode 100644 index 00000000..93b7ce87 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f9db-1f3fb-2642.png new file mode 100644 index 00000000..3ecd5006 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db-1f3fb.png b/twake/frontend/public/public/emojione/32/1f9db-1f3fb.png new file mode 100644 index 00000000..93b7ce87 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f9db-1f3fc-2640.png new file mode 100644 index 00000000..d1db5609 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f9db-1f3fc-2642.png new file mode 100644 index 00000000..a4372b82 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db-1f3fc.png b/twake/frontend/public/public/emojione/32/1f9db-1f3fc.png new file mode 100644 index 00000000..d1db5609 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f9db-1f3fd-2640.png new file mode 100644 index 00000000..f32263cf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f9db-1f3fd-2642.png new file mode 100644 index 00000000..6a3286db Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db-1f3fd.png b/twake/frontend/public/public/emojione/32/1f9db-1f3fd.png new file mode 100644 index 00000000..f32263cf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f9db-1f3fe-2640.png new file mode 100644 index 00000000..92f588bf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f9db-1f3fe-2642.png new file mode 100644 index 00000000..24382a02 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db-1f3fe.png b/twake/frontend/public/public/emojione/32/1f9db-1f3fe.png new file mode 100644 index 00000000..92f588bf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f9db-1f3ff-2640.png new file mode 100644 index 00000000..7d55205a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f9db-1f3ff-2642.png new file mode 100644 index 00000000..584c53d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db-1f3ff.png b/twake/frontend/public/public/emojione/32/1f9db-1f3ff.png new file mode 100644 index 00000000..7d55205a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db-2640.png b/twake/frontend/public/public/emojione/32/1f9db-2640.png new file mode 100644 index 00000000..48618c62 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db-2642.png b/twake/frontend/public/public/emojione/32/1f9db-2642.png new file mode 100644 index 00000000..abe355fb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9db.png b/twake/frontend/public/public/emojione/32/1f9db.png new file mode 100644 index 00000000..48618c62 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9db.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f9dc-1f3fb-2640.png new file mode 100644 index 00000000..43186148 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f9dc-1f3fb-2642.png new file mode 100644 index 00000000..81af25ed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc-1f3fb.png b/twake/frontend/public/public/emojione/32/1f9dc-1f3fb.png new file mode 100644 index 00000000..43186148 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f9dc-1f3fc-2640.png new file mode 100644 index 00000000..242bdb31 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f9dc-1f3fc-2642.png new file mode 100644 index 00000000..fdc26775 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc-1f3fc.png b/twake/frontend/public/public/emojione/32/1f9dc-1f3fc.png new file mode 100644 index 00000000..242bdb31 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f9dc-1f3fd-2640.png new file mode 100644 index 00000000..86a7c3d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f9dc-1f3fd-2642.png new file mode 100644 index 00000000..a1ef8119 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc-1f3fd.png b/twake/frontend/public/public/emojione/32/1f9dc-1f3fd.png new file mode 100644 index 00000000..86a7c3d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f9dc-1f3fe-2640.png new file mode 100644 index 00000000..e11a2a71 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f9dc-1f3fe-2642.png new file mode 100644 index 00000000..53ba29a6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc-1f3fe.png b/twake/frontend/public/public/emojione/32/1f9dc-1f3fe.png new file mode 100644 index 00000000..e11a2a71 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f9dc-1f3ff-2640.png new file mode 100644 index 00000000..1491ab10 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f9dc-1f3ff-2642.png new file mode 100644 index 00000000..f12260a1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc-1f3ff.png b/twake/frontend/public/public/emojione/32/1f9dc-1f3ff.png new file mode 100644 index 00000000..1491ab10 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc-2640.png b/twake/frontend/public/public/emojione/32/1f9dc-2640.png new file mode 100644 index 00000000..6e86a179 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc-2642.png b/twake/frontend/public/public/emojione/32/1f9dc-2642.png new file mode 100644 index 00000000..ab11b6a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dc.png b/twake/frontend/public/public/emojione/32/1f9dc.png new file mode 100644 index 00000000..1d5d9fe8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/1f9dd-1f3fb-2640.png new file mode 100644 index 00000000..ed5d1f49 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/1f9dd-1f3fb-2642.png new file mode 100644 index 00000000..6f7a3814 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd-1f3fb.png b/twake/frontend/public/public/emojione/32/1f9dd-1f3fb.png new file mode 100644 index 00000000..ed5d1f49 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/1f9dd-1f3fc-2640.png new file mode 100644 index 00000000..3b8b3dc5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/1f9dd-1f3fc-2642.png new file mode 100644 index 00000000..6dddb005 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd-1f3fc.png b/twake/frontend/public/public/emojione/32/1f9dd-1f3fc.png new file mode 100644 index 00000000..3b8b3dc5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/1f9dd-1f3fd-2640.png new file mode 100644 index 00000000..a68b1e25 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/1f9dd-1f3fd-2642.png new file mode 100644 index 00000000..c9ee3e86 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd-1f3fd.png b/twake/frontend/public/public/emojione/32/1f9dd-1f3fd.png new file mode 100644 index 00000000..a68b1e25 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/1f9dd-1f3fe-2640.png new file mode 100644 index 00000000..9a285f21 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/1f9dd-1f3fe-2642.png new file mode 100644 index 00000000..e58015a8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd-1f3fe.png b/twake/frontend/public/public/emojione/32/1f9dd-1f3fe.png new file mode 100644 index 00000000..9a285f21 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/1f9dd-1f3ff-2640.png new file mode 100644 index 00000000..163c5be3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/1f9dd-1f3ff-2642.png new file mode 100644 index 00000000..05bf32d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd-1f3ff.png b/twake/frontend/public/public/emojione/32/1f9dd-1f3ff.png new file mode 100644 index 00000000..163c5be3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd-2640.png b/twake/frontend/public/public/emojione/32/1f9dd-2640.png new file mode 100644 index 00000000..b088c1a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd-2642.png b/twake/frontend/public/public/emojione/32/1f9dd-2642.png new file mode 100644 index 00000000..5eee3ad6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9dd.png b/twake/frontend/public/public/emojione/32/1f9dd.png new file mode 100644 index 00000000..b088c1a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9dd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9de-2640.png b/twake/frontend/public/public/emojione/32/1f9de-2640.png new file mode 100644 index 00000000..4c780297 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9de-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9de-2642.png b/twake/frontend/public/public/emojione/32/1f9de-2642.png new file mode 100644 index 00000000..ee2c802a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9de-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9de.png b/twake/frontend/public/public/emojione/32/1f9de.png new file mode 100644 index 00000000..4c780297 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9de.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9df-2640.png b/twake/frontend/public/public/emojione/32/1f9df-2640.png new file mode 100644 index 00000000..479391a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9df-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9df-2642.png b/twake/frontend/public/public/emojione/32/1f9df-2642.png new file mode 100644 index 00000000..b0b5271e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9df-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9df.png b/twake/frontend/public/public/emojione/32/1f9df.png new file mode 100644 index 00000000..479391a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9df.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9e0.png b/twake/frontend/public/public/emojione/32/1f9e0.png new file mode 100644 index 00000000..a330ff0a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9e0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9e1.png b/twake/frontend/public/public/emojione/32/1f9e1.png new file mode 100644 index 00000000..eac0ec2c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9e1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9e2.png b/twake/frontend/public/public/emojione/32/1f9e2.png new file mode 100644 index 00000000..79ca5315 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9e2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9e3.png b/twake/frontend/public/public/emojione/32/1f9e3.png new file mode 100644 index 00000000..3b23b526 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9e3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9e4.png b/twake/frontend/public/public/emojione/32/1f9e4.png new file mode 100644 index 00000000..89d6b99f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9e4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9e5.png b/twake/frontend/public/public/emojione/32/1f9e5.png new file mode 100644 index 00000000..3fac6b0b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9e5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9e6.png b/twake/frontend/public/public/emojione/32/1f9e6.png new file mode 100644 index 00000000..d8183424 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9e6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9e7.png b/twake/frontend/public/public/emojione/32/1f9e7.png new file mode 100644 index 00000000..0ea159dd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9e7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9e8.png b/twake/frontend/public/public/emojione/32/1f9e8.png new file mode 100644 index 00000000..1b085d81 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9e8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9e9.png b/twake/frontend/public/public/emojione/32/1f9e9.png new file mode 100644 index 00000000..bcf2bb40 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9e9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9ea.png b/twake/frontend/public/public/emojione/32/1f9ea.png new file mode 100644 index 00000000..dd429c6f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9ea.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9eb.png b/twake/frontend/public/public/emojione/32/1f9eb.png new file mode 100644 index 00000000..b315733f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9eb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9ec.png b/twake/frontend/public/public/emojione/32/1f9ec.png new file mode 100644 index 00000000..8f8de81d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9ec.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9ed.png b/twake/frontend/public/public/emojione/32/1f9ed.png new file mode 100644 index 00000000..8868efed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9ed.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9ee.png b/twake/frontend/public/public/emojione/32/1f9ee.png new file mode 100644 index 00000000..34cd3ab7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9ee.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9ef.png b/twake/frontend/public/public/emojione/32/1f9ef.png new file mode 100644 index 00000000..6d5a6e5b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9ef.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9f0.png b/twake/frontend/public/public/emojione/32/1f9f0.png new file mode 100644 index 00000000..f06ffe1a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9f0.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9f1.png b/twake/frontend/public/public/emojione/32/1f9f1.png new file mode 100644 index 00000000..0a37fc54 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9f1.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9f2.png b/twake/frontend/public/public/emojione/32/1f9f2.png new file mode 100644 index 00000000..518e4a14 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9f2.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9f3.png b/twake/frontend/public/public/emojione/32/1f9f3.png new file mode 100644 index 00000000..160f323d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9f3.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9f4.png b/twake/frontend/public/public/emojione/32/1f9f4.png new file mode 100644 index 00000000..be75e561 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9f4.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9f5.png b/twake/frontend/public/public/emojione/32/1f9f5.png new file mode 100644 index 00000000..465b88a6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9f5.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9f6.png b/twake/frontend/public/public/emojione/32/1f9f6.png new file mode 100644 index 00000000..3833451b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9f6.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9f7.png b/twake/frontend/public/public/emojione/32/1f9f7.png new file mode 100644 index 00000000..2170fd79 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9f7.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9f8.png b/twake/frontend/public/public/emojione/32/1f9f8.png new file mode 100644 index 00000000..f011fbbb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9f8.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9f9.png b/twake/frontend/public/public/emojione/32/1f9f9.png new file mode 100644 index 00000000..fcda58a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9f9.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9fa.png b/twake/frontend/public/public/emojione/32/1f9fa.png new file mode 100644 index 00000000..0c89966c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9fa.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9fb.png b/twake/frontend/public/public/emojione/32/1f9fb.png new file mode 100644 index 00000000..56caaceb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9fb.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9fc.png b/twake/frontend/public/public/emojione/32/1f9fc.png new file mode 100644 index 00000000..6bc32981 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9fc.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9fd.png b/twake/frontend/public/public/emojione/32/1f9fd.png new file mode 100644 index 00000000..c38245b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9fd.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9fe.png b/twake/frontend/public/public/emojione/32/1f9fe.png new file mode 100644 index 00000000..20ffb822 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9fe.png differ diff --git a/twake/frontend/public/public/emojione/32/1f9ff.png b/twake/frontend/public/public/emojione/32/1f9ff.png new file mode 100644 index 00000000..671d2330 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/1f9ff.png differ diff --git a/twake/frontend/public/public/emojione/32/203c.png b/twake/frontend/public/public/emojione/32/203c.png new file mode 100644 index 00000000..bf0dce07 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/203c.png differ diff --git a/twake/frontend/public/public/emojione/32/2049.png b/twake/frontend/public/public/emojione/32/2049.png new file mode 100644 index 00000000..af3c9a27 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2049.png differ diff --git a/twake/frontend/public/public/emojione/32/2122.png b/twake/frontend/public/public/emojione/32/2122.png new file mode 100644 index 00000000..03dabe9a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2122.png differ diff --git a/twake/frontend/public/public/emojione/32/2139.png b/twake/frontend/public/public/emojione/32/2139.png new file mode 100644 index 00000000..7e963c53 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2139.png differ diff --git a/twake/frontend/public/public/emojione/32/2194.png b/twake/frontend/public/public/emojione/32/2194.png new file mode 100644 index 00000000..65a7254a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2194.png differ diff --git a/twake/frontend/public/public/emojione/32/2195.png b/twake/frontend/public/public/emojione/32/2195.png new file mode 100644 index 00000000..9c9afeca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2195.png differ diff --git a/twake/frontend/public/public/emojione/32/2196.png b/twake/frontend/public/public/emojione/32/2196.png new file mode 100644 index 00000000..7ea76ff0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2196.png differ diff --git a/twake/frontend/public/public/emojione/32/2197.png b/twake/frontend/public/public/emojione/32/2197.png new file mode 100644 index 00000000..12308078 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2197.png differ diff --git a/twake/frontend/public/public/emojione/32/2198.png b/twake/frontend/public/public/emojione/32/2198.png new file mode 100644 index 00000000..b2b13630 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2198.png differ diff --git a/twake/frontend/public/public/emojione/32/2199.png b/twake/frontend/public/public/emojione/32/2199.png new file mode 100644 index 00000000..043618c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2199.png differ diff --git a/twake/frontend/public/public/emojione/32/21a9.png b/twake/frontend/public/public/emojione/32/21a9.png new file mode 100644 index 00000000..2b9db984 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/21a9.png differ diff --git a/twake/frontend/public/public/emojione/32/21aa.png b/twake/frontend/public/public/emojione/32/21aa.png new file mode 100644 index 00000000..2aee47a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/21aa.png differ diff --git a/twake/frontend/public/public/emojione/32/231a.png b/twake/frontend/public/public/emojione/32/231a.png new file mode 100644 index 00000000..ec79d885 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/231a.png differ diff --git a/twake/frontend/public/public/emojione/32/231b.png b/twake/frontend/public/public/emojione/32/231b.png new file mode 100644 index 00000000..f30bb152 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/231b.png differ diff --git a/twake/frontend/public/public/emojione/32/2328.png b/twake/frontend/public/public/emojione/32/2328.png new file mode 100644 index 00000000..a890066b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2328.png differ diff --git a/twake/frontend/public/public/emojione/32/23cf.png b/twake/frontend/public/public/emojione/32/23cf.png new file mode 100644 index 00000000..e930dd60 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/23cf.png differ diff --git a/twake/frontend/public/public/emojione/32/23e9.png b/twake/frontend/public/public/emojione/32/23e9.png new file mode 100644 index 00000000..bfc40ea2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/23e9.png differ diff --git a/twake/frontend/public/public/emojione/32/23ea.png b/twake/frontend/public/public/emojione/32/23ea.png new file mode 100644 index 00000000..62118fb2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/23ea.png differ diff --git a/twake/frontend/public/public/emojione/32/23eb.png b/twake/frontend/public/public/emojione/32/23eb.png new file mode 100644 index 00000000..dac039fc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/23eb.png differ diff --git a/twake/frontend/public/public/emojione/32/23ec.png b/twake/frontend/public/public/emojione/32/23ec.png new file mode 100644 index 00000000..1a28f967 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/23ec.png differ diff --git a/twake/frontend/public/public/emojione/32/23ed.png b/twake/frontend/public/public/emojione/32/23ed.png new file mode 100644 index 00000000..2573ef04 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/23ed.png differ diff --git a/twake/frontend/public/public/emojione/32/23ee.png b/twake/frontend/public/public/emojione/32/23ee.png new file mode 100644 index 00000000..75ab7685 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/23ee.png differ diff --git a/twake/frontend/public/public/emojione/32/23ef.png b/twake/frontend/public/public/emojione/32/23ef.png new file mode 100644 index 00000000..24229d27 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/23ef.png differ diff --git a/twake/frontend/public/public/emojione/32/23f0.png b/twake/frontend/public/public/emojione/32/23f0.png new file mode 100644 index 00000000..67b55bfa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/23f0.png differ diff --git a/twake/frontend/public/public/emojione/32/23f1.png b/twake/frontend/public/public/emojione/32/23f1.png new file mode 100644 index 00000000..cc5679b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/23f1.png differ diff --git a/twake/frontend/public/public/emojione/32/23f2.png b/twake/frontend/public/public/emojione/32/23f2.png new file mode 100644 index 00000000..f6f2f62c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/23f2.png differ diff --git a/twake/frontend/public/public/emojione/32/23f3.png b/twake/frontend/public/public/emojione/32/23f3.png new file mode 100644 index 00000000..73fea090 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/23f3.png differ diff --git a/twake/frontend/public/public/emojione/32/23f8.png b/twake/frontend/public/public/emojione/32/23f8.png new file mode 100644 index 00000000..0cf983a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/23f8.png differ diff --git a/twake/frontend/public/public/emojione/32/23f9.png b/twake/frontend/public/public/emojione/32/23f9.png new file mode 100644 index 00000000..844b32f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/23f9.png differ diff --git a/twake/frontend/public/public/emojione/32/23fa.png b/twake/frontend/public/public/emojione/32/23fa.png new file mode 100644 index 00000000..8c457291 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/23fa.png differ diff --git a/twake/frontend/public/public/emojione/32/24c2.png b/twake/frontend/public/public/emojione/32/24c2.png new file mode 100644 index 00000000..5a1cc4bb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/24c2.png differ diff --git a/twake/frontend/public/public/emojione/32/25aa.png b/twake/frontend/public/public/emojione/32/25aa.png new file mode 100644 index 00000000..e7f7d989 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/25aa.png differ diff --git a/twake/frontend/public/public/emojione/32/25ab.png b/twake/frontend/public/public/emojione/32/25ab.png new file mode 100644 index 00000000..be937e93 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/25ab.png differ diff --git a/twake/frontend/public/public/emojione/32/25b6.png b/twake/frontend/public/public/emojione/32/25b6.png new file mode 100644 index 00000000..45ebd04d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/25b6.png differ diff --git a/twake/frontend/public/public/emojione/32/25c0.png b/twake/frontend/public/public/emojione/32/25c0.png new file mode 100644 index 00000000..3ac7d5d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/25c0.png differ diff --git a/twake/frontend/public/public/emojione/32/25fb.png b/twake/frontend/public/public/emojione/32/25fb.png new file mode 100644 index 00000000..0e108a82 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/25fb.png differ diff --git a/twake/frontend/public/public/emojione/32/25fc.png b/twake/frontend/public/public/emojione/32/25fc.png new file mode 100644 index 00000000..ce113a8e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/25fc.png differ diff --git a/twake/frontend/public/public/emojione/32/25fd.png b/twake/frontend/public/public/emojione/32/25fd.png new file mode 100644 index 00000000..9fbe434d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/25fd.png differ diff --git a/twake/frontend/public/public/emojione/32/25fe.png b/twake/frontend/public/public/emojione/32/25fe.png new file mode 100644 index 00000000..e23f3e92 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/25fe.png differ diff --git a/twake/frontend/public/public/emojione/32/2600.png b/twake/frontend/public/public/emojione/32/2600.png new file mode 100644 index 00000000..03bc3982 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2600.png differ diff --git a/twake/frontend/public/public/emojione/32/2601.png b/twake/frontend/public/public/emojione/32/2601.png new file mode 100644 index 00000000..5901a1e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2601.png differ diff --git a/twake/frontend/public/public/emojione/32/2602.png b/twake/frontend/public/public/emojione/32/2602.png new file mode 100644 index 00000000..3a38089f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2602.png differ diff --git a/twake/frontend/public/public/emojione/32/2603.png b/twake/frontend/public/public/emojione/32/2603.png new file mode 100644 index 00000000..6d465ee2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2603.png differ diff --git a/twake/frontend/public/public/emojione/32/2604.png b/twake/frontend/public/public/emojione/32/2604.png new file mode 100644 index 00000000..c83fdbce Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2604.png differ diff --git a/twake/frontend/public/public/emojione/32/260e.png b/twake/frontend/public/public/emojione/32/260e.png new file mode 100644 index 00000000..0aec4a37 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/260e.png differ diff --git a/twake/frontend/public/public/emojione/32/2611.png b/twake/frontend/public/public/emojione/32/2611.png new file mode 100644 index 00000000..3639b530 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2611.png differ diff --git a/twake/frontend/public/public/emojione/32/2614.png b/twake/frontend/public/public/emojione/32/2614.png new file mode 100644 index 00000000..1de8bbbe Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2614.png differ diff --git a/twake/frontend/public/public/emojione/32/2615.png b/twake/frontend/public/public/emojione/32/2615.png new file mode 100644 index 00000000..334e6c8e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2615.png differ diff --git a/twake/frontend/public/public/emojione/32/2618.png b/twake/frontend/public/public/emojione/32/2618.png new file mode 100644 index 00000000..836b081d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2618.png differ diff --git a/twake/frontend/public/public/emojione/32/261d-1f3fb.png b/twake/frontend/public/public/emojione/32/261d-1f3fb.png new file mode 100644 index 00000000..4f9f45a5 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/261d-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/261d-1f3fc.png b/twake/frontend/public/public/emojione/32/261d-1f3fc.png new file mode 100644 index 00000000..561d680e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/261d-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/261d-1f3fd.png b/twake/frontend/public/public/emojione/32/261d-1f3fd.png new file mode 100644 index 00000000..1fc6a9c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/261d-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/261d-1f3fe.png b/twake/frontend/public/public/emojione/32/261d-1f3fe.png new file mode 100644 index 00000000..130a67be Binary files /dev/null and b/twake/frontend/public/public/emojione/32/261d-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/261d-1f3ff.png b/twake/frontend/public/public/emojione/32/261d-1f3ff.png new file mode 100644 index 00000000..583b14ef Binary files /dev/null and b/twake/frontend/public/public/emojione/32/261d-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/261d.png b/twake/frontend/public/public/emojione/32/261d.png new file mode 100644 index 00000000..4c223f89 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/261d.png differ diff --git a/twake/frontend/public/public/emojione/32/2620.png b/twake/frontend/public/public/emojione/32/2620.png new file mode 100644 index 00000000..2b100394 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2620.png differ diff --git a/twake/frontend/public/public/emojione/32/2622.png b/twake/frontend/public/public/emojione/32/2622.png new file mode 100644 index 00000000..1eda7a6d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2622.png differ diff --git a/twake/frontend/public/public/emojione/32/2623.png b/twake/frontend/public/public/emojione/32/2623.png new file mode 100644 index 00000000..37e8756d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2623.png differ diff --git a/twake/frontend/public/public/emojione/32/2626.png b/twake/frontend/public/public/emojione/32/2626.png new file mode 100644 index 00000000..67519b57 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2626.png differ diff --git a/twake/frontend/public/public/emojione/32/262a.png b/twake/frontend/public/public/emojione/32/262a.png new file mode 100644 index 00000000..8014b3cd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/262a.png differ diff --git a/twake/frontend/public/public/emojione/32/262e.png b/twake/frontend/public/public/emojione/32/262e.png new file mode 100644 index 00000000..35f97a1f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/262e.png differ diff --git a/twake/frontend/public/public/emojione/32/262f.png b/twake/frontend/public/public/emojione/32/262f.png new file mode 100644 index 00000000..61bc4b4e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/262f.png differ diff --git a/twake/frontend/public/public/emojione/32/2638.png b/twake/frontend/public/public/emojione/32/2638.png new file mode 100644 index 00000000..c20db38d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2638.png differ diff --git a/twake/frontend/public/public/emojione/32/2639.png b/twake/frontend/public/public/emojione/32/2639.png new file mode 100644 index 00000000..da9a76ef Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2639.png differ diff --git a/twake/frontend/public/public/emojione/32/263a.png b/twake/frontend/public/public/emojione/32/263a.png new file mode 100644 index 00000000..11cda432 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/263a.png differ diff --git a/twake/frontend/public/public/emojione/32/2640.png b/twake/frontend/public/public/emojione/32/2640.png new file mode 100644 index 00000000..d377161f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2640.png differ diff --git a/twake/frontend/public/public/emojione/32/2642.png b/twake/frontend/public/public/emojione/32/2642.png new file mode 100644 index 00000000..e8249698 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2642.png differ diff --git a/twake/frontend/public/public/emojione/32/2648.png b/twake/frontend/public/public/emojione/32/2648.png new file mode 100644 index 00000000..ab1c5adf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2648.png differ diff --git a/twake/frontend/public/public/emojione/32/2649.png b/twake/frontend/public/public/emojione/32/2649.png new file mode 100644 index 00000000..6695a212 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2649.png differ diff --git a/twake/frontend/public/public/emojione/32/264a.png b/twake/frontend/public/public/emojione/32/264a.png new file mode 100644 index 00000000..8b1f8367 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/264a.png differ diff --git a/twake/frontend/public/public/emojione/32/264b.png b/twake/frontend/public/public/emojione/32/264b.png new file mode 100644 index 00000000..128bfd25 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/264b.png differ diff --git a/twake/frontend/public/public/emojione/32/264c.png b/twake/frontend/public/public/emojione/32/264c.png new file mode 100644 index 00000000..012fc2d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/264c.png differ diff --git a/twake/frontend/public/public/emojione/32/264d.png b/twake/frontend/public/public/emojione/32/264d.png new file mode 100644 index 00000000..95a52a7b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/264d.png differ diff --git a/twake/frontend/public/public/emojione/32/264e.png b/twake/frontend/public/public/emojione/32/264e.png new file mode 100644 index 00000000..e2395b0b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/264e.png differ diff --git a/twake/frontend/public/public/emojione/32/264f.png b/twake/frontend/public/public/emojione/32/264f.png new file mode 100644 index 00000000..ceb2f89a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/264f.png differ diff --git a/twake/frontend/public/public/emojione/32/2650.png b/twake/frontend/public/public/emojione/32/2650.png new file mode 100644 index 00000000..543177c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2650.png differ diff --git a/twake/frontend/public/public/emojione/32/2651.png b/twake/frontend/public/public/emojione/32/2651.png new file mode 100644 index 00000000..afc226c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2651.png differ diff --git a/twake/frontend/public/public/emojione/32/2652.png b/twake/frontend/public/public/emojione/32/2652.png new file mode 100644 index 00000000..fd440aec Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2652.png differ diff --git a/twake/frontend/public/public/emojione/32/2653.png b/twake/frontend/public/public/emojione/32/2653.png new file mode 100644 index 00000000..98d98ffe Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2653.png differ diff --git a/twake/frontend/public/public/emojione/32/265f.png b/twake/frontend/public/public/emojione/32/265f.png new file mode 100644 index 00000000..00297e78 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/265f.png differ diff --git a/twake/frontend/public/public/emojione/32/2660.png b/twake/frontend/public/public/emojione/32/2660.png new file mode 100644 index 00000000..fe2bf5bf Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2660.png differ diff --git a/twake/frontend/public/public/emojione/32/2663.png b/twake/frontend/public/public/emojione/32/2663.png new file mode 100644 index 00000000..11a73247 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2663.png differ diff --git a/twake/frontend/public/public/emojione/32/2665.png b/twake/frontend/public/public/emojione/32/2665.png new file mode 100644 index 00000000..f22f9a8a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2665.png differ diff --git a/twake/frontend/public/public/emojione/32/2666.png b/twake/frontend/public/public/emojione/32/2666.png new file mode 100644 index 00000000..29bea528 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2666.png differ diff --git a/twake/frontend/public/public/emojione/32/2668.png b/twake/frontend/public/public/emojione/32/2668.png new file mode 100644 index 00000000..eb0e122c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2668.png differ diff --git a/twake/frontend/public/public/emojione/32/267b.png b/twake/frontend/public/public/emojione/32/267b.png new file mode 100644 index 00000000..41178082 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/267b.png differ diff --git a/twake/frontend/public/public/emojione/32/267e.png b/twake/frontend/public/public/emojione/32/267e.png new file mode 100644 index 00000000..d15566e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/267e.png differ diff --git a/twake/frontend/public/public/emojione/32/267f.png b/twake/frontend/public/public/emojione/32/267f.png new file mode 100644 index 00000000..4e69d230 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/267f.png differ diff --git a/twake/frontend/public/public/emojione/32/2692.png b/twake/frontend/public/public/emojione/32/2692.png new file mode 100644 index 00000000..6d40f6e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2692.png differ diff --git a/twake/frontend/public/public/emojione/32/2693.png b/twake/frontend/public/public/emojione/32/2693.png new file mode 100644 index 00000000..3f71a96c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2693.png differ diff --git a/twake/frontend/public/public/emojione/32/2694.png b/twake/frontend/public/public/emojione/32/2694.png new file mode 100644 index 00000000..491c2b35 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2694.png differ diff --git a/twake/frontend/public/public/emojione/32/2695.png b/twake/frontend/public/public/emojione/32/2695.png new file mode 100644 index 00000000..025083cd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2695.png differ diff --git a/twake/frontend/public/public/emojione/32/2696.png b/twake/frontend/public/public/emojione/32/2696.png new file mode 100644 index 00000000..54028dca Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2696.png differ diff --git a/twake/frontend/public/public/emojione/32/2697.png b/twake/frontend/public/public/emojione/32/2697.png new file mode 100644 index 00000000..951b4576 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2697.png differ diff --git a/twake/frontend/public/public/emojione/32/2699.png b/twake/frontend/public/public/emojione/32/2699.png new file mode 100644 index 00000000..a04c8de1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2699.png differ diff --git a/twake/frontend/public/public/emojione/32/269b.png b/twake/frontend/public/public/emojione/32/269b.png new file mode 100644 index 00000000..61461602 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/269b.png differ diff --git a/twake/frontend/public/public/emojione/32/269c.png b/twake/frontend/public/public/emojione/32/269c.png new file mode 100644 index 00000000..f5a93693 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/269c.png differ diff --git a/twake/frontend/public/public/emojione/32/26a0.png b/twake/frontend/public/public/emojione/32/26a0.png new file mode 100644 index 00000000..f3b38ee9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26a0.png differ diff --git a/twake/frontend/public/public/emojione/32/26a1.png b/twake/frontend/public/public/emojione/32/26a1.png new file mode 100644 index 00000000..ba1685c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26a1.png differ diff --git a/twake/frontend/public/public/emojione/32/26aa.png b/twake/frontend/public/public/emojione/32/26aa.png new file mode 100644 index 00000000..0c64d03a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26aa.png differ diff --git a/twake/frontend/public/public/emojione/32/26ab.png b/twake/frontend/public/public/emojione/32/26ab.png new file mode 100644 index 00000000..48d64f2a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26ab.png differ diff --git a/twake/frontend/public/public/emojione/32/26b0.png b/twake/frontend/public/public/emojione/32/26b0.png new file mode 100644 index 00000000..12bdcef9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26b0.png differ diff --git a/twake/frontend/public/public/emojione/32/26b1.png b/twake/frontend/public/public/emojione/32/26b1.png new file mode 100644 index 00000000..013008ae Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26b1.png differ diff --git a/twake/frontend/public/public/emojione/32/26bd.png b/twake/frontend/public/public/emojione/32/26bd.png new file mode 100644 index 00000000..54077c78 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26bd.png differ diff --git a/twake/frontend/public/public/emojione/32/26be.png b/twake/frontend/public/public/emojione/32/26be.png new file mode 100644 index 00000000..82665e1a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26be.png differ diff --git a/twake/frontend/public/public/emojione/32/26c4.png b/twake/frontend/public/public/emojione/32/26c4.png new file mode 100644 index 00000000..f54cad3c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26c4.png differ diff --git a/twake/frontend/public/public/emojione/32/26c5.png b/twake/frontend/public/public/emojione/32/26c5.png new file mode 100644 index 00000000..f43122d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26c5.png differ diff --git a/twake/frontend/public/public/emojione/32/26c8.png b/twake/frontend/public/public/emojione/32/26c8.png new file mode 100644 index 00000000..f0804777 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26c8.png differ diff --git a/twake/frontend/public/public/emojione/32/26ce.png b/twake/frontend/public/public/emojione/32/26ce.png new file mode 100644 index 00000000..311e0bbe Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26ce.png differ diff --git a/twake/frontend/public/public/emojione/32/26cf.png b/twake/frontend/public/public/emojione/32/26cf.png new file mode 100644 index 00000000..72235d47 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26cf.png differ diff --git a/twake/frontend/public/public/emojione/32/26d1.png b/twake/frontend/public/public/emojione/32/26d1.png new file mode 100644 index 00000000..5ed8943d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26d1.png differ diff --git a/twake/frontend/public/public/emojione/32/26d3.png b/twake/frontend/public/public/emojione/32/26d3.png new file mode 100644 index 00000000..dd399963 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26d3.png differ diff --git a/twake/frontend/public/public/emojione/32/26d4.png b/twake/frontend/public/public/emojione/32/26d4.png new file mode 100644 index 00000000..fc5d9b73 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26d4.png differ diff --git a/twake/frontend/public/public/emojione/32/26e9.png b/twake/frontend/public/public/emojione/32/26e9.png new file mode 100644 index 00000000..c1baedff Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26e9.png differ diff --git a/twake/frontend/public/public/emojione/32/26ea.png b/twake/frontend/public/public/emojione/32/26ea.png new file mode 100644 index 00000000..3857cb3d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26ea.png differ diff --git a/twake/frontend/public/public/emojione/32/26f0.png b/twake/frontend/public/public/emojione/32/26f0.png new file mode 100644 index 00000000..0193c5dd Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f0.png differ diff --git a/twake/frontend/public/public/emojione/32/26f1.png b/twake/frontend/public/public/emojione/32/26f1.png new file mode 100644 index 00000000..5ab0c549 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f1.png differ diff --git a/twake/frontend/public/public/emojione/32/26f2.png b/twake/frontend/public/public/emojione/32/26f2.png new file mode 100644 index 00000000..7029f667 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f2.png differ diff --git a/twake/frontend/public/public/emojione/32/26f3.png b/twake/frontend/public/public/emojione/32/26f3.png new file mode 100644 index 00000000..afa1818c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f3.png differ diff --git a/twake/frontend/public/public/emojione/32/26f4.png b/twake/frontend/public/public/emojione/32/26f4.png new file mode 100644 index 00000000..2aac981a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f4.png differ diff --git a/twake/frontend/public/public/emojione/32/26f5.png b/twake/frontend/public/public/emojione/32/26f5.png new file mode 100644 index 00000000..24cbd0fb Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f5.png differ diff --git a/twake/frontend/public/public/emojione/32/26f7.png b/twake/frontend/public/public/emojione/32/26f7.png new file mode 100644 index 00000000..ba2311d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f7.png differ diff --git a/twake/frontend/public/public/emojione/32/26f8.png b/twake/frontend/public/public/emojione/32/26f8.png new file mode 100644 index 00000000..867e1c91 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f8.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9-1f3fb-2640.png b/twake/frontend/public/public/emojione/32/26f9-1f3fb-2640.png new file mode 100644 index 00000000..41dc3467 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9-1f3fb-2642.png b/twake/frontend/public/public/emojione/32/26f9-1f3fb-2642.png new file mode 100644 index 00000000..1a80e937 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9-1f3fb.png b/twake/frontend/public/public/emojione/32/26f9-1f3fb.png new file mode 100644 index 00000000..1a80e937 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9-1f3fc-2640.png b/twake/frontend/public/public/emojione/32/26f9-1f3fc-2640.png new file mode 100644 index 00000000..0f0262ed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9-1f3fc-2642.png b/twake/frontend/public/public/emojione/32/26f9-1f3fc-2642.png new file mode 100644 index 00000000..3d073d07 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9-1f3fc.png b/twake/frontend/public/public/emojione/32/26f9-1f3fc.png new file mode 100644 index 00000000..3d073d07 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9-1f3fd-2640.png b/twake/frontend/public/public/emojione/32/26f9-1f3fd-2640.png new file mode 100644 index 00000000..6964219b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9-1f3fd-2642.png b/twake/frontend/public/public/emojione/32/26f9-1f3fd-2642.png new file mode 100644 index 00000000..a7b7a919 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9-1f3fd.png b/twake/frontend/public/public/emojione/32/26f9-1f3fd.png new file mode 100644 index 00000000..a7b7a919 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9-1f3fe-2640.png b/twake/frontend/public/public/emojione/32/26f9-1f3fe-2640.png new file mode 100644 index 00000000..41933fd0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9-1f3fe-2642.png b/twake/frontend/public/public/emojione/32/26f9-1f3fe-2642.png new file mode 100644 index 00000000..f4334186 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9-1f3fe.png b/twake/frontend/public/public/emojione/32/26f9-1f3fe.png new file mode 100644 index 00000000..f4334186 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9-1f3ff-2640.png b/twake/frontend/public/public/emojione/32/26f9-1f3ff-2640.png new file mode 100644 index 00000000..f31f2c3c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9-1f3ff-2642.png b/twake/frontend/public/public/emojione/32/26f9-1f3ff-2642.png new file mode 100644 index 00000000..f5a6a475 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9-1f3ff.png b/twake/frontend/public/public/emojione/32/26f9-1f3ff.png new file mode 100644 index 00000000..f5a6a475 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9-2640.png b/twake/frontend/public/public/emojione/32/26f9-2640.png new file mode 100644 index 00000000..914d03ed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9-2640.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9-2642.png b/twake/frontend/public/public/emojione/32/26f9-2642.png new file mode 100644 index 00000000..b2644bb9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9-2642.png differ diff --git a/twake/frontend/public/public/emojione/32/26f9.png b/twake/frontend/public/public/emojione/32/26f9.png new file mode 100644 index 00000000..b2644bb9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26f9.png differ diff --git a/twake/frontend/public/public/emojione/32/26fa.png b/twake/frontend/public/public/emojione/32/26fa.png new file mode 100644 index 00000000..6d0d0a0d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26fa.png differ diff --git a/twake/frontend/public/public/emojione/32/26fd.png b/twake/frontend/public/public/emojione/32/26fd.png new file mode 100644 index 00000000..df62c7b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/26fd.png differ diff --git a/twake/frontend/public/public/emojione/32/2702.png b/twake/frontend/public/public/emojione/32/2702.png new file mode 100644 index 00000000..19f0a0ff Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2702.png differ diff --git a/twake/frontend/public/public/emojione/32/2705.png b/twake/frontend/public/public/emojione/32/2705.png new file mode 100644 index 00000000..f0f1465f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2705.png differ diff --git a/twake/frontend/public/public/emojione/32/2708.png b/twake/frontend/public/public/emojione/32/2708.png new file mode 100644 index 00000000..0a390ca3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2708.png differ diff --git a/twake/frontend/public/public/emojione/32/2709.png b/twake/frontend/public/public/emojione/32/2709.png new file mode 100644 index 00000000..59566b02 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2709.png differ diff --git a/twake/frontend/public/public/emojione/32/270a-1f3fb.png b/twake/frontend/public/public/emojione/32/270a-1f3fb.png new file mode 100644 index 00000000..fd256bac Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270a-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/270a-1f3fc.png b/twake/frontend/public/public/emojione/32/270a-1f3fc.png new file mode 100644 index 00000000..1412b82b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270a-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/270a-1f3fd.png b/twake/frontend/public/public/emojione/32/270a-1f3fd.png new file mode 100644 index 00000000..8b8c5f8b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270a-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/270a-1f3fe.png b/twake/frontend/public/public/emojione/32/270a-1f3fe.png new file mode 100644 index 00000000..0c4eed60 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270a-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/270a-1f3ff.png b/twake/frontend/public/public/emojione/32/270a-1f3ff.png new file mode 100644 index 00000000..ad13d75d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270a-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/270a.png b/twake/frontend/public/public/emojione/32/270a.png new file mode 100644 index 00000000..8cea5d5b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270a.png differ diff --git a/twake/frontend/public/public/emojione/32/270b-1f3fb.png b/twake/frontend/public/public/emojione/32/270b-1f3fb.png new file mode 100644 index 00000000..041deb5f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270b-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/270b-1f3fc.png b/twake/frontend/public/public/emojione/32/270b-1f3fc.png new file mode 100644 index 00000000..9433e41c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270b-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/270b-1f3fd.png b/twake/frontend/public/public/emojione/32/270b-1f3fd.png new file mode 100644 index 00000000..c8a10350 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270b-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/270b-1f3fe.png b/twake/frontend/public/public/emojione/32/270b-1f3fe.png new file mode 100644 index 00000000..269e322d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270b-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/270b-1f3ff.png b/twake/frontend/public/public/emojione/32/270b-1f3ff.png new file mode 100644 index 00000000..78425b53 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270b-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/270b.png b/twake/frontend/public/public/emojione/32/270b.png new file mode 100644 index 00000000..bdb0be75 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270b.png differ diff --git a/twake/frontend/public/public/emojione/32/270c-1f3fb.png b/twake/frontend/public/public/emojione/32/270c-1f3fb.png new file mode 100644 index 00000000..666ce796 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270c-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/270c-1f3fc.png b/twake/frontend/public/public/emojione/32/270c-1f3fc.png new file mode 100644 index 00000000..fee01182 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270c-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/270c-1f3fd.png b/twake/frontend/public/public/emojione/32/270c-1f3fd.png new file mode 100644 index 00000000..f3a3640c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270c-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/270c-1f3fe.png b/twake/frontend/public/public/emojione/32/270c-1f3fe.png new file mode 100644 index 00000000..1e6e6ea0 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270c-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/270c-1f3ff.png b/twake/frontend/public/public/emojione/32/270c-1f3ff.png new file mode 100644 index 00000000..b1dc6bc4 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270c-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/270c.png b/twake/frontend/public/public/emojione/32/270c.png new file mode 100644 index 00000000..faff695a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270c.png differ diff --git a/twake/frontend/public/public/emojione/32/270d-1f3fb.png b/twake/frontend/public/public/emojione/32/270d-1f3fb.png new file mode 100644 index 00000000..e63bf0c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270d-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/32/270d-1f3fc.png b/twake/frontend/public/public/emojione/32/270d-1f3fc.png new file mode 100644 index 00000000..fc0bc63a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270d-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/32/270d-1f3fd.png b/twake/frontend/public/public/emojione/32/270d-1f3fd.png new file mode 100644 index 00000000..0dbf7861 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270d-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/32/270d-1f3fe.png b/twake/frontend/public/public/emojione/32/270d-1f3fe.png new file mode 100644 index 00000000..b5306079 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270d-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/32/270d-1f3ff.png b/twake/frontend/public/public/emojione/32/270d-1f3ff.png new file mode 100644 index 00000000..185f665d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270d-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/32/270d.png b/twake/frontend/public/public/emojione/32/270d.png new file mode 100644 index 00000000..fedfe067 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270d.png differ diff --git a/twake/frontend/public/public/emojione/32/270f.png b/twake/frontend/public/public/emojione/32/270f.png new file mode 100644 index 00000000..bb0f01a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/270f.png differ diff --git a/twake/frontend/public/public/emojione/32/2712.png b/twake/frontend/public/public/emojione/32/2712.png new file mode 100644 index 00000000..905f8d7d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2712.png differ diff --git a/twake/frontend/public/public/emojione/32/2714.png b/twake/frontend/public/public/emojione/32/2714.png new file mode 100644 index 00000000..54110a6c Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2714.png differ diff --git a/twake/frontend/public/public/emojione/32/2716.png b/twake/frontend/public/public/emojione/32/2716.png new file mode 100644 index 00000000..00bac80e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2716.png differ diff --git a/twake/frontend/public/public/emojione/32/271d.png b/twake/frontend/public/public/emojione/32/271d.png new file mode 100644 index 00000000..41ed68b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/271d.png differ diff --git a/twake/frontend/public/public/emojione/32/2721.png b/twake/frontend/public/public/emojione/32/2721.png new file mode 100644 index 00000000..0d53326b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2721.png differ diff --git a/twake/frontend/public/public/emojione/32/2728.png b/twake/frontend/public/public/emojione/32/2728.png new file mode 100644 index 00000000..5385b0f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2728.png differ diff --git a/twake/frontend/public/public/emojione/32/2733.png b/twake/frontend/public/public/emojione/32/2733.png new file mode 100644 index 00000000..252451db Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2733.png differ diff --git a/twake/frontend/public/public/emojione/32/2734.png b/twake/frontend/public/public/emojione/32/2734.png new file mode 100644 index 00000000..cf0b420d Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2734.png differ diff --git a/twake/frontend/public/public/emojione/32/2744.png b/twake/frontend/public/public/emojione/32/2744.png new file mode 100644 index 00000000..e6c17500 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2744.png differ diff --git a/twake/frontend/public/public/emojione/32/2747.png b/twake/frontend/public/public/emojione/32/2747.png new file mode 100644 index 00000000..fe7a7ca3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2747.png differ diff --git a/twake/frontend/public/public/emojione/32/274c.png b/twake/frontend/public/public/emojione/32/274c.png new file mode 100644 index 00000000..4057ac8e Binary files /dev/null and b/twake/frontend/public/public/emojione/32/274c.png differ diff --git a/twake/frontend/public/public/emojione/32/274e.png b/twake/frontend/public/public/emojione/32/274e.png new file mode 100644 index 00000000..f0fe0058 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/274e.png differ diff --git a/twake/frontend/public/public/emojione/32/2753.png b/twake/frontend/public/public/emojione/32/2753.png new file mode 100644 index 00000000..c036b015 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2753.png differ diff --git a/twake/frontend/public/public/emojione/32/2754.png b/twake/frontend/public/public/emojione/32/2754.png new file mode 100644 index 00000000..11cea599 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2754.png differ diff --git a/twake/frontend/public/public/emojione/32/2755.png b/twake/frontend/public/public/emojione/32/2755.png new file mode 100644 index 00000000..11886c38 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2755.png differ diff --git a/twake/frontend/public/public/emojione/32/2757.png b/twake/frontend/public/public/emojione/32/2757.png new file mode 100644 index 00000000..dc1d78ed Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2757.png differ diff --git a/twake/frontend/public/public/emojione/32/2763.png b/twake/frontend/public/public/emojione/32/2763.png new file mode 100644 index 00000000..ac3982cc Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2763.png differ diff --git a/twake/frontend/public/public/emojione/32/2764.png b/twake/frontend/public/public/emojione/32/2764.png new file mode 100644 index 00000000..7381df8a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2764.png differ diff --git a/twake/frontend/public/public/emojione/32/2795.png b/twake/frontend/public/public/emojione/32/2795.png new file mode 100644 index 00000000..887a4e40 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2795.png differ diff --git a/twake/frontend/public/public/emojione/32/2796.png b/twake/frontend/public/public/emojione/32/2796.png new file mode 100644 index 00000000..9ceb12c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2796.png differ diff --git a/twake/frontend/public/public/emojione/32/2797.png b/twake/frontend/public/public/emojione/32/2797.png new file mode 100644 index 00000000..c0c2cf0b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2797.png differ diff --git a/twake/frontend/public/public/emojione/32/27a1.png b/twake/frontend/public/public/emojione/32/27a1.png new file mode 100644 index 00000000..167216d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/27a1.png differ diff --git a/twake/frontend/public/public/emojione/32/27b0.png b/twake/frontend/public/public/emojione/32/27b0.png new file mode 100644 index 00000000..4e4f46b9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/27b0.png differ diff --git a/twake/frontend/public/public/emojione/32/27bf.png b/twake/frontend/public/public/emojione/32/27bf.png new file mode 100644 index 00000000..d74217f9 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/27bf.png differ diff --git a/twake/frontend/public/public/emojione/32/2934.png b/twake/frontend/public/public/emojione/32/2934.png new file mode 100644 index 00000000..59e2edaa Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2934.png differ diff --git a/twake/frontend/public/public/emojione/32/2935.png b/twake/frontend/public/public/emojione/32/2935.png new file mode 100644 index 00000000..f0a9166f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2935.png differ diff --git a/twake/frontend/public/public/emojione/32/2b05.png b/twake/frontend/public/public/emojione/32/2b05.png new file mode 100644 index 00000000..d07dc699 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2b05.png differ diff --git a/twake/frontend/public/public/emojione/32/2b06.png b/twake/frontend/public/public/emojione/32/2b06.png new file mode 100644 index 00000000..1e3b1c7a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2b06.png differ diff --git a/twake/frontend/public/public/emojione/32/2b07.png b/twake/frontend/public/public/emojione/32/2b07.png new file mode 100644 index 00000000..03341a40 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2b07.png differ diff --git a/twake/frontend/public/public/emojione/32/2b1b.png b/twake/frontend/public/public/emojione/32/2b1b.png new file mode 100644 index 00000000..887dc40b Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2b1b.png differ diff --git a/twake/frontend/public/public/emojione/32/2b1c.png b/twake/frontend/public/public/emojione/32/2b1c.png new file mode 100644 index 00000000..b2b4e842 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2b1c.png differ diff --git a/twake/frontend/public/public/emojione/32/2b50.png b/twake/frontend/public/public/emojione/32/2b50.png new file mode 100644 index 00000000..9d3623df Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2b50.png differ diff --git a/twake/frontend/public/public/emojione/32/2b55.png b/twake/frontend/public/public/emojione/32/2b55.png new file mode 100644 index 00000000..0788a87f Binary files /dev/null and b/twake/frontend/public/public/emojione/32/2b55.png differ diff --git a/twake/frontend/public/public/emojione/32/3030.png b/twake/frontend/public/public/emojione/32/3030.png new file mode 100644 index 00000000..fb7b6ba3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/3030.png differ diff --git a/twake/frontend/public/public/emojione/32/303d.png b/twake/frontend/public/public/emojione/32/303d.png new file mode 100644 index 00000000..f3ce26b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/303d.png differ diff --git a/twake/frontend/public/public/emojione/32/3297.png b/twake/frontend/public/public/emojione/32/3297.png new file mode 100644 index 00000000..d22bba88 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/3297.png differ diff --git a/twake/frontend/public/public/emojione/32/3299.png b/twake/frontend/public/public/emojione/32/3299.png new file mode 100644 index 00000000..c89e4c93 Binary files /dev/null and b/twake/frontend/public/public/emojione/32/3299.png differ diff --git a/twake/frontend/public/public/emojione/32/_alt/1f52b.png b/twake/frontend/public/public/emojione/32/_alt/1f52b.png new file mode 100644 index 00000000..b677df7a Binary files /dev/null and b/twake/frontend/public/public/emojione/32/_alt/1f52b.png differ diff --git a/twake/frontend/public/public/emojione/64/0023-20e3.png b/twake/frontend/public/public/emojione/64/0023-20e3.png new file mode 100644 index 00000000..237f0b43 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0023-20e3.png differ diff --git a/twake/frontend/public/public/emojione/64/0023.png b/twake/frontend/public/public/emojione/64/0023.png new file mode 100644 index 00000000..8fe73b46 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0023.png differ diff --git a/twake/frontend/public/public/emojione/64/002a-20e3.png b/twake/frontend/public/public/emojione/64/002a-20e3.png new file mode 100644 index 00000000..7560e805 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/002a-20e3.png differ diff --git a/twake/frontend/public/public/emojione/64/002a.png b/twake/frontend/public/public/emojione/64/002a.png new file mode 100644 index 00000000..7ce70c3f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/002a.png differ diff --git a/twake/frontend/public/public/emojione/64/0030-20e3.png b/twake/frontend/public/public/emojione/64/0030-20e3.png new file mode 100644 index 00000000..d42506c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0030-20e3.png differ diff --git a/twake/frontend/public/public/emojione/64/0030.png b/twake/frontend/public/public/emojione/64/0030.png new file mode 100644 index 00000000..229c513d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0030.png differ diff --git a/twake/frontend/public/public/emojione/64/0031-20e3.png b/twake/frontend/public/public/emojione/64/0031-20e3.png new file mode 100644 index 00000000..973dd5ac Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0031-20e3.png differ diff --git a/twake/frontend/public/public/emojione/64/0031.png b/twake/frontend/public/public/emojione/64/0031.png new file mode 100644 index 00000000..e3772c5c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0031.png differ diff --git a/twake/frontend/public/public/emojione/64/0032-20e3.png b/twake/frontend/public/public/emojione/64/0032-20e3.png new file mode 100644 index 00000000..51d1c537 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0032-20e3.png differ diff --git a/twake/frontend/public/public/emojione/64/0032.png b/twake/frontend/public/public/emojione/64/0032.png new file mode 100644 index 00000000..22b84ab2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0032.png differ diff --git a/twake/frontend/public/public/emojione/64/0033-20e3.png b/twake/frontend/public/public/emojione/64/0033-20e3.png new file mode 100644 index 00000000..d4f7d2bb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0033-20e3.png differ diff --git a/twake/frontend/public/public/emojione/64/0033.png b/twake/frontend/public/public/emojione/64/0033.png new file mode 100644 index 00000000..8082e92e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0033.png differ diff --git a/twake/frontend/public/public/emojione/64/0034-20e3.png b/twake/frontend/public/public/emojione/64/0034-20e3.png new file mode 100644 index 00000000..9bfc5800 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0034-20e3.png differ diff --git a/twake/frontend/public/public/emojione/64/0034.png b/twake/frontend/public/public/emojione/64/0034.png new file mode 100644 index 00000000..66a2d983 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0034.png differ diff --git a/twake/frontend/public/public/emojione/64/0035-20e3.png b/twake/frontend/public/public/emojione/64/0035-20e3.png new file mode 100644 index 00000000..3bb9f51c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0035-20e3.png differ diff --git a/twake/frontend/public/public/emojione/64/0035.png b/twake/frontend/public/public/emojione/64/0035.png new file mode 100644 index 00000000..9233fe3b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0035.png differ diff --git a/twake/frontend/public/public/emojione/64/0036-20e3.png b/twake/frontend/public/public/emojione/64/0036-20e3.png new file mode 100644 index 00000000..ca6bbaa3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0036-20e3.png differ diff --git a/twake/frontend/public/public/emojione/64/0036.png b/twake/frontend/public/public/emojione/64/0036.png new file mode 100644 index 00000000..a9b4a0dd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0036.png differ diff --git a/twake/frontend/public/public/emojione/64/0037-20e3.png b/twake/frontend/public/public/emojione/64/0037-20e3.png new file mode 100644 index 00000000..e01a579b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0037-20e3.png differ diff --git a/twake/frontend/public/public/emojione/64/0037.png b/twake/frontend/public/public/emojione/64/0037.png new file mode 100644 index 00000000..cfdb2178 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0037.png differ diff --git a/twake/frontend/public/public/emojione/64/0038-20e3.png b/twake/frontend/public/public/emojione/64/0038-20e3.png new file mode 100644 index 00000000..ba34f1cc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0038-20e3.png differ diff --git a/twake/frontend/public/public/emojione/64/0038.png b/twake/frontend/public/public/emojione/64/0038.png new file mode 100644 index 00000000..1df495e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0038.png differ diff --git a/twake/frontend/public/public/emojione/64/0039-20e3.png b/twake/frontend/public/public/emojione/64/0039-20e3.png new file mode 100644 index 00000000..c3803e7c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0039-20e3.png differ diff --git a/twake/frontend/public/public/emojione/64/0039.png b/twake/frontend/public/public/emojione/64/0039.png new file mode 100644 index 00000000..f656ea7b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/0039.png differ diff --git a/twake/frontend/public/public/emojione/64/00a9.png b/twake/frontend/public/public/emojione/64/00a9.png new file mode 100644 index 00000000..b21d560a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/00a9.png differ diff --git a/twake/frontend/public/public/emojione/64/00ae.png b/twake/frontend/public/public/emojione/64/00ae.png new file mode 100644 index 00000000..1c8259c5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/00ae.png differ diff --git a/twake/frontend/public/public/emojione/64/1f004.png b/twake/frontend/public/public/emojione/64/1f004.png new file mode 100644 index 00000000..5104f0f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f004.png differ diff --git a/twake/frontend/public/public/emojione/64/1f0cf.png b/twake/frontend/public/public/emojione/64/1f0cf.png new file mode 100644 index 00000000..df1af051 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f0cf.png differ diff --git a/twake/frontend/public/public/emojione/64/1f170.png b/twake/frontend/public/public/emojione/64/1f170.png new file mode 100644 index 00000000..8bd6e6a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f170.png differ diff --git a/twake/frontend/public/public/emojione/64/1f171.png b/twake/frontend/public/public/emojione/64/1f171.png new file mode 100644 index 00000000..314933b9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f171.png differ diff --git a/twake/frontend/public/public/emojione/64/1f17e.png b/twake/frontend/public/public/emojione/64/1f17e.png new file mode 100644 index 00000000..290af5d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f17e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f17f.png b/twake/frontend/public/public/emojione/64/1f17f.png new file mode 100644 index 00000000..5d293c3f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f17f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f18e.png b/twake/frontend/public/public/emojione/64/1f18e.png new file mode 100644 index 00000000..2c4d90e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f18e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f191.png b/twake/frontend/public/public/emojione/64/1f191.png new file mode 100644 index 00000000..e09ab541 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f191.png differ diff --git a/twake/frontend/public/public/emojione/64/1f192.png b/twake/frontend/public/public/emojione/64/1f192.png new file mode 100644 index 00000000..beb6f86c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f192.png differ diff --git a/twake/frontend/public/public/emojione/64/1f193.png b/twake/frontend/public/public/emojione/64/1f193.png new file mode 100644 index 00000000..87dff9ab Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f193.png differ diff --git a/twake/frontend/public/public/emojione/64/1f194.png b/twake/frontend/public/public/emojione/64/1f194.png new file mode 100644 index 00000000..87663eee Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f194.png differ diff --git a/twake/frontend/public/public/emojione/64/1f195.png b/twake/frontend/public/public/emojione/64/1f195.png new file mode 100644 index 00000000..f288c367 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f195.png differ diff --git a/twake/frontend/public/public/emojione/64/1f196.png b/twake/frontend/public/public/emojione/64/1f196.png new file mode 100644 index 00000000..64dcfa4b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f196.png differ diff --git a/twake/frontend/public/public/emojione/64/1f197.png b/twake/frontend/public/public/emojione/64/1f197.png new file mode 100644 index 00000000..f0b2cc36 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f197.png differ diff --git a/twake/frontend/public/public/emojione/64/1f198.png b/twake/frontend/public/public/emojione/64/1f198.png new file mode 100644 index 00000000..52c74b1c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f198.png differ diff --git a/twake/frontend/public/public/emojione/64/1f199.png b/twake/frontend/public/public/emojione/64/1f199.png new file mode 100644 index 00000000..801b23f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f199.png differ diff --git a/twake/frontend/public/public/emojione/64/1f19a.png b/twake/frontend/public/public/emojione/64/1f19a.png new file mode 100644 index 00000000..332bf585 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f19a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6-1f1e8.png b/twake/frontend/public/public/emojione/64/1f1e6-1f1e8.png new file mode 100644 index 00000000..ab55c351 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6-1f1e9.png b/twake/frontend/public/public/emojione/64/1f1e6-1f1e9.png new file mode 100644 index 00000000..58d5b180 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6-1f1ea.png b/twake/frontend/public/public/emojione/64/1f1e6-1f1ea.png new file mode 100644 index 00000000..c22a9231 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6-1f1eb.png b/twake/frontend/public/public/emojione/64/1f1e6-1f1eb.png new file mode 100644 index 00000000..6646895a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6-1f1ec.png b/twake/frontend/public/public/emojione/64/1f1e6-1f1ec.png new file mode 100644 index 00000000..b2681c4d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6-1f1ee.png b/twake/frontend/public/public/emojione/64/1f1e6-1f1ee.png new file mode 100644 index 00000000..4c71941a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6-1f1f1.png b/twake/frontend/public/public/emojione/64/1f1e6-1f1f1.png new file mode 100644 index 00000000..3ff9c453 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6-1f1f2.png b/twake/frontend/public/public/emojione/64/1f1e6-1f1f2.png new file mode 100644 index 00000000..921ce514 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6-1f1f4.png b/twake/frontend/public/public/emojione/64/1f1e6-1f1f4.png new file mode 100644 index 00000000..ee9e1d58 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6-1f1f6.png b/twake/frontend/public/public/emojione/64/1f1e6-1f1f6.png new file mode 100644 index 00000000..912c52b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6-1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6-1f1f7.png b/twake/frontend/public/public/emojione/64/1f1e6-1f1f7.png new file mode 100644 index 00000000..75dd8b7d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6-1f1f8.png b/twake/frontend/public/public/emojione/64/1f1e6-1f1f8.png new file mode 100644 index 00000000..32d74819 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6-1f1f9.png b/twake/frontend/public/public/emojione/64/1f1e6-1f1f9.png new file mode 100644 index 00000000..dd1d69e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6-1f1fa.png b/twake/frontend/public/public/emojione/64/1f1e6-1f1fa.png new file mode 100644 index 00000000..64650276 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6-1f1fc.png b/twake/frontend/public/public/emojione/64/1f1e6-1f1fc.png new file mode 100644 index 00000000..8f700a7b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6-1f1fd.png b/twake/frontend/public/public/emojione/64/1f1e6-1f1fd.png new file mode 100644 index 00000000..06fa0abb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6-1f1fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6-1f1ff.png b/twake/frontend/public/public/emojione/64/1f1e6-1f1ff.png new file mode 100644 index 00000000..48f299aa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e6.png b/twake/frontend/public/public/emojione/64/1f1e6.png new file mode 100644 index 00000000..63a74878 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1e6.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1e6.png new file mode 100644 index 00000000..0a209388 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1e7.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1e7.png new file mode 100644 index 00000000..22743081 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1e7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1e9.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1e9.png new file mode 100644 index 00000000..ea6f9594 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1ea.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1ea.png new file mode 100644 index 00000000..bdfde99a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1eb.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1eb.png new file mode 100644 index 00000000..e86f7ebb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1ec.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1ec.png new file mode 100644 index 00000000..6c47bb2f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1ed.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1ed.png new file mode 100644 index 00000000..8e5615e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1ee.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1ee.png new file mode 100644 index 00000000..3d9b0052 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1ef.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1ef.png new file mode 100644 index 00000000..b651b364 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1f1.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1f1.png new file mode 100644 index 00000000..b62b9cbb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1f2.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1f2.png new file mode 100644 index 00000000..5a2b497f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1f3.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1f3.png new file mode 100644 index 00000000..44a8b1b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1f4.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1f4.png new file mode 100644 index 00000000..edd97b4e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1f6.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1f6.png new file mode 100644 index 00000000..5ea10f2b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1f7.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1f7.png new file mode 100644 index 00000000..b9a7ca12 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1f8.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1f8.png new file mode 100644 index 00000000..4659885d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1f9.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1f9.png new file mode 100644 index 00000000..7e6468f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1fb.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1fb.png new file mode 100644 index 00000000..13f5dd2b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1fc.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1fc.png new file mode 100644 index 00000000..1cdc7aea Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1fe.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1fe.png new file mode 100644 index 00000000..58f2bfbd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7-1f1ff.png b/twake/frontend/public/public/emojione/64/1f1e7-1f1ff.png new file mode 100644 index 00000000..d6e31468 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e7.png b/twake/frontend/public/public/emojione/64/1f1e7.png new file mode 100644 index 00000000..6b7cbdcd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1e6.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1e6.png new file mode 100644 index 00000000..b233a9ef Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1e8.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1e8.png new file mode 100644 index 00000000..47cbee0b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1e9.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1e9.png new file mode 100644 index 00000000..283daa68 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1eb.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1eb.png new file mode 100644 index 00000000..753834db Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1ec.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1ec.png new file mode 100644 index 00000000..98486c4f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1ed.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1ed.png new file mode 100644 index 00000000..ad44ac77 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1ee.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1ee.png new file mode 100644 index 00000000..4f2a61a1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1f0.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1f0.png new file mode 100644 index 00000000..45cf5f53 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1f1.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1f1.png new file mode 100644 index 00000000..d60c23aa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1f2.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1f2.png new file mode 100644 index 00000000..f303171e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1f3.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1f3.png new file mode 100644 index 00000000..e9391864 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1f4.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1f4.png new file mode 100644 index 00000000..bd75099d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1f5.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1f5.png new file mode 100644 index 00000000..fb836023 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1f7.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1f7.png new file mode 100644 index 00000000..3e6432ee Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1fa.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1fa.png new file mode 100644 index 00000000..f8cfcc52 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1fb.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1fb.png new file mode 100644 index 00000000..81fc0dbb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1fc.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1fc.png new file mode 100644 index 00000000..2d278b12 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1fd.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1fd.png new file mode 100644 index 00000000..ce88c871 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1fe.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1fe.png new file mode 100644 index 00000000..4ef3306e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8-1f1ff.png b/twake/frontend/public/public/emojione/64/1f1e8-1f1ff.png new file mode 100644 index 00000000..6528d3c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e8.png b/twake/frontend/public/public/emojione/64/1f1e8.png new file mode 100644 index 00000000..be88a984 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e9-1f1ea.png b/twake/frontend/public/public/emojione/64/1f1e9-1f1ea.png new file mode 100644 index 00000000..14b37bcc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e9-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e9-1f1ec.png b/twake/frontend/public/public/emojione/64/1f1e9-1f1ec.png new file mode 100644 index 00000000..d212b20f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e9-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e9-1f1ef.png b/twake/frontend/public/public/emojione/64/1f1e9-1f1ef.png new file mode 100644 index 00000000..fca0e7c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e9-1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e9-1f1f0.png b/twake/frontend/public/public/emojione/64/1f1e9-1f1f0.png new file mode 100644 index 00000000..ddca6807 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e9-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e9-1f1f2.png b/twake/frontend/public/public/emojione/64/1f1e9-1f1f2.png new file mode 100644 index 00000000..adb3a724 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e9-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e9-1f1f4.png b/twake/frontend/public/public/emojione/64/1f1e9-1f1f4.png new file mode 100644 index 00000000..9cfe5d15 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e9-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e9-1f1ff.png b/twake/frontend/public/public/emojione/64/1f1e9-1f1ff.png new file mode 100644 index 00000000..c56ba1cd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e9-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1e9.png b/twake/frontend/public/public/emojione/64/1f1e9.png new file mode 100644 index 00000000..6385f1c5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ea-1f1e6.png b/twake/frontend/public/public/emojione/64/1f1ea-1f1e6.png new file mode 100644 index 00000000..43e054b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ea-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ea-1f1e8.png b/twake/frontend/public/public/emojione/64/1f1ea-1f1e8.png new file mode 100644 index 00000000..84393a08 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ea-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ea-1f1ea.png b/twake/frontend/public/public/emojione/64/1f1ea-1f1ea.png new file mode 100644 index 00000000..3adfea36 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ea-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ea-1f1ec.png b/twake/frontend/public/public/emojione/64/1f1ea-1f1ec.png new file mode 100644 index 00000000..16b4bba0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ea-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ea-1f1ed.png b/twake/frontend/public/public/emojione/64/1f1ea-1f1ed.png new file mode 100644 index 00000000..bb80e6be Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ea-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ea-1f1f7.png b/twake/frontend/public/public/emojione/64/1f1ea-1f1f7.png new file mode 100644 index 00000000..769c1d3d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ea-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ea-1f1f8.png b/twake/frontend/public/public/emojione/64/1f1ea-1f1f8.png new file mode 100644 index 00000000..43e054b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ea-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ea-1f1f9.png b/twake/frontend/public/public/emojione/64/1f1ea-1f1f9.png new file mode 100644 index 00000000..65dc9992 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ea-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ea-1f1fa.png b/twake/frontend/public/public/emojione/64/1f1ea-1f1fa.png new file mode 100644 index 00000000..4a63112a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ea-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ea.png b/twake/frontend/public/public/emojione/64/1f1ea.png new file mode 100644 index 00000000..2f9080b6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1eb-1f1ee.png b/twake/frontend/public/public/emojione/64/1f1eb-1f1ee.png new file mode 100644 index 00000000..2ab803b6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1eb-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1eb-1f1ef.png b/twake/frontend/public/public/emojione/64/1f1eb-1f1ef.png new file mode 100644 index 00000000..439de951 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1eb-1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1eb-1f1f0.png b/twake/frontend/public/public/emojione/64/1f1eb-1f1f0.png new file mode 100644 index 00000000..346bd01d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1eb-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1eb-1f1f2.png b/twake/frontend/public/public/emojione/64/1f1eb-1f1f2.png new file mode 100644 index 00000000..e17e30d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1eb-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1eb-1f1f4.png b/twake/frontend/public/public/emojione/64/1f1eb-1f1f4.png new file mode 100644 index 00000000..37bfcf23 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1eb-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1eb-1f1f7.png b/twake/frontend/public/public/emojione/64/1f1eb-1f1f7.png new file mode 100644 index 00000000..fb836023 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1eb-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1eb.png b/twake/frontend/public/public/emojione/64/1f1eb.png new file mode 100644 index 00000000..73e06feb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1e6.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1e6.png new file mode 100644 index 00000000..80ccacde Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1e7.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1e7.png new file mode 100644 index 00000000..644a7726 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1e7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1e9.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1e9.png new file mode 100644 index 00000000..8b067c1d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1ea.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1ea.png new file mode 100644 index 00000000..558534b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1eb.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1eb.png new file mode 100644 index 00000000..44af1613 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1ec.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1ec.png new file mode 100644 index 00000000..3bb034ff Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1ed.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1ed.png new file mode 100644 index 00000000..8d707e59 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1ee.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1ee.png new file mode 100644 index 00000000..44cdee50 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1f1.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1f1.png new file mode 100644 index 00000000..540fe12b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1f2.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1f2.png new file mode 100644 index 00000000..864e8f5b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1f3.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1f3.png new file mode 100644 index 00000000..25145cce Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1f5.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1f5.png new file mode 100644 index 00000000..e25ce2aa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1f6.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1f6.png new file mode 100644 index 00000000..a61e496d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1f7.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1f7.png new file mode 100644 index 00000000..3506e0e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1f8.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1f8.png new file mode 100644 index 00000000..468a1669 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1f9.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1f9.png new file mode 100644 index 00000000..593e523c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1fa.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1fa.png new file mode 100644 index 00000000..257de5d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1fc.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1fc.png new file mode 100644 index 00000000..fd74abfd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec-1f1fe.png b/twake/frontend/public/public/emojione/64/1f1ec-1f1fe.png new file mode 100644 index 00000000..85f243b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ec.png b/twake/frontend/public/public/emojione/64/1f1ec.png new file mode 100644 index 00000000..c525df86 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ed-1f1f0.png b/twake/frontend/public/public/emojione/64/1f1ed-1f1f0.png new file mode 100644 index 00000000..5bf79604 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ed-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ed-1f1f2.png b/twake/frontend/public/public/emojione/64/1f1ed-1f1f2.png new file mode 100644 index 00000000..72d956af Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ed-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ed-1f1f3.png b/twake/frontend/public/public/emojione/64/1f1ed-1f1f3.png new file mode 100644 index 00000000..462d98c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ed-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ed-1f1f7.png b/twake/frontend/public/public/emojione/64/1f1ed-1f1f7.png new file mode 100644 index 00000000..e3add547 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ed-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ed-1f1f9.png b/twake/frontend/public/public/emojione/64/1f1ed-1f1f9.png new file mode 100644 index 00000000..904e0ba9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ed-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ed-1f1fa.png b/twake/frontend/public/public/emojione/64/1f1ed-1f1fa.png new file mode 100644 index 00000000..c89b0499 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ed-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ed.png b/twake/frontend/public/public/emojione/64/1f1ed.png new file mode 100644 index 00000000..0024911e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ee-1f1e8.png b/twake/frontend/public/public/emojione/64/1f1ee-1f1e8.png new file mode 100644 index 00000000..4fb209d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ee-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ee-1f1e9.png b/twake/frontend/public/public/emojione/64/1f1ee-1f1e9.png new file mode 100644 index 00000000..804bee80 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ee-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ee-1f1ea.png b/twake/frontend/public/public/emojione/64/1f1ee-1f1ea.png new file mode 100644 index 00000000..eef6336c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ee-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ee-1f1f1.png b/twake/frontend/public/public/emojione/64/1f1ee-1f1f1.png new file mode 100644 index 00000000..99748f50 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ee-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ee-1f1f2.png b/twake/frontend/public/public/emojione/64/1f1ee-1f1f2.png new file mode 100644 index 00000000..1b1537de Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ee-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ee-1f1f3.png b/twake/frontend/public/public/emojione/64/1f1ee-1f1f3.png new file mode 100644 index 00000000..9c061c59 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ee-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ee-1f1f4.png b/twake/frontend/public/public/emojione/64/1f1ee-1f1f4.png new file mode 100644 index 00000000..d212b20f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ee-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ee-1f1f6.png b/twake/frontend/public/public/emojione/64/1f1ee-1f1f6.png new file mode 100644 index 00000000..202ed4f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ee-1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ee-1f1f7.png b/twake/frontend/public/public/emojione/64/1f1ee-1f1f7.png new file mode 100644 index 00000000..1a9b4e07 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ee-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ee-1f1f8.png b/twake/frontend/public/public/emojione/64/1f1ee-1f1f8.png new file mode 100644 index 00000000..edbe1718 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ee-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ee-1f1f9.png b/twake/frontend/public/public/emojione/64/1f1ee-1f1f9.png new file mode 100644 index 00000000..5c587f89 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ee-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ee.png b/twake/frontend/public/public/emojione/64/1f1ee.png new file mode 100644 index 00000000..c875f952 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ef-1f1ea.png b/twake/frontend/public/public/emojione/64/1f1ef-1f1ea.png new file mode 100644 index 00000000..13554905 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ef-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ef-1f1f2.png b/twake/frontend/public/public/emojione/64/1f1ef-1f1f2.png new file mode 100644 index 00000000..dc3eba05 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ef-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ef-1f1f4.png b/twake/frontend/public/public/emojione/64/1f1ef-1f1f4.png new file mode 100644 index 00000000..2de381c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ef-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ef-1f1f5.png b/twake/frontend/public/public/emojione/64/1f1ef-1f1f5.png new file mode 100644 index 00000000..95e0b033 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ef-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ef.png b/twake/frontend/public/public/emojione/64/1f1ef.png new file mode 100644 index 00000000..45903495 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f0-1f1ea.png b/twake/frontend/public/public/emojione/64/1f1f0-1f1ea.png new file mode 100644 index 00000000..5c2a70ac Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f0-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f0-1f1ec.png b/twake/frontend/public/public/emojione/64/1f1f0-1f1ec.png new file mode 100644 index 00000000..ab83395a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f0-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f0-1f1ed.png b/twake/frontend/public/public/emojione/64/1f1f0-1f1ed.png new file mode 100644 index 00000000..3633cc1c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f0-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f0-1f1ee.png b/twake/frontend/public/public/emojione/64/1f1f0-1f1ee.png new file mode 100644 index 00000000..21457e37 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f0-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f0-1f1f2.png b/twake/frontend/public/public/emojione/64/1f1f0-1f1f2.png new file mode 100644 index 00000000..b3b71f51 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f0-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f0-1f1f3.png b/twake/frontend/public/public/emojione/64/1f1f0-1f1f3.png new file mode 100644 index 00000000..0ec39571 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f0-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f0-1f1f5.png b/twake/frontend/public/public/emojione/64/1f1f0-1f1f5.png new file mode 100644 index 00000000..4eca1e91 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f0-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f0-1f1f7.png b/twake/frontend/public/public/emojione/64/1f1f0-1f1f7.png new file mode 100644 index 00000000..099dd448 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f0-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f0-1f1fc.png b/twake/frontend/public/public/emojione/64/1f1f0-1f1fc.png new file mode 100644 index 00000000..a285ac5d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f0-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f0-1f1fe.png b/twake/frontend/public/public/emojione/64/1f1f0-1f1fe.png new file mode 100644 index 00000000..ccb9f0ca Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f0-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f0-1f1ff.png b/twake/frontend/public/public/emojione/64/1f1f0-1f1ff.png new file mode 100644 index 00000000..e34dc20d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f0-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f0.png b/twake/frontend/public/public/emojione/64/1f1f0.png new file mode 100644 index 00000000..d0a2dc7e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f1-1f1e6.png b/twake/frontend/public/public/emojione/64/1f1f1-1f1e6.png new file mode 100644 index 00000000..49d5bf45 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f1-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f1-1f1e7.png b/twake/frontend/public/public/emojione/64/1f1f1-1f1e7.png new file mode 100644 index 00000000..d8d3014b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f1-1f1e7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f1-1f1e8.png b/twake/frontend/public/public/emojione/64/1f1f1-1f1e8.png new file mode 100644 index 00000000..8e73978f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f1-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f1-1f1ee.png b/twake/frontend/public/public/emojione/64/1f1f1-1f1ee.png new file mode 100644 index 00000000..732c1888 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f1-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f1-1f1f0.png b/twake/frontend/public/public/emojione/64/1f1f1-1f1f0.png new file mode 100644 index 00000000..26b29dc9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f1-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f1-1f1f7.png b/twake/frontend/public/public/emojione/64/1f1f1-1f1f7.png new file mode 100644 index 00000000..6c34972c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f1-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f1-1f1f8.png b/twake/frontend/public/public/emojione/64/1f1f1-1f1f8.png new file mode 100644 index 00000000..66c021ca Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f1-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f1-1f1f9.png b/twake/frontend/public/public/emojione/64/1f1f1-1f1f9.png new file mode 100644 index 00000000..e32832a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f1-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f1-1f1fa.png b/twake/frontend/public/public/emojione/64/1f1f1-1f1fa.png new file mode 100644 index 00000000..e56c3c97 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f1-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f1-1f1fb.png b/twake/frontend/public/public/emojione/64/1f1f1-1f1fb.png new file mode 100644 index 00000000..55332528 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f1-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f1-1f1fe.png b/twake/frontend/public/public/emojione/64/1f1f1-1f1fe.png new file mode 100644 index 00000000..3681302e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f1-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f1.png b/twake/frontend/public/public/emojione/64/1f1f1.png new file mode 100644 index 00000000..814db955 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1e6.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1e6.png new file mode 100644 index 00000000..46eabd71 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1e8.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1e8.png new file mode 100644 index 00000000..804bee80 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1e9.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1e9.png new file mode 100644 index 00000000..0555aabc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1ea.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1ea.png new file mode 100644 index 00000000..b5f3d392 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1eb.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1eb.png new file mode 100644 index 00000000..fb836023 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1ec.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1ec.png new file mode 100644 index 00000000..61a9458c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1ed.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1ed.png new file mode 100644 index 00000000..f77e3ab8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1f0.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1f0.png new file mode 100644 index 00000000..064dc4d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1f1.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1f1.png new file mode 100644 index 00000000..641b345f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1f2.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1f2.png new file mode 100644 index 00000000..dc536240 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1f3.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1f3.png new file mode 100644 index 00000000..50a649e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1f4.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1f4.png new file mode 100644 index 00000000..25dc8370 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1f5.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1f5.png new file mode 100644 index 00000000..ae85844f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1f6.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1f6.png new file mode 100644 index 00000000..510df136 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1f7.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1f7.png new file mode 100644 index 00000000..6e5d5df2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1f8.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1f8.png new file mode 100644 index 00000000..f0291960 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1f9.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1f9.png new file mode 100644 index 00000000..5c685c67 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1fa.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1fa.png new file mode 100644 index 00000000..a8fb6ae5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1fb.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1fb.png new file mode 100644 index 00000000..fabe6d00 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1fc.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1fc.png new file mode 100644 index 00000000..527a2e57 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1fd.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1fd.png new file mode 100644 index 00000000..1931260c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1fe.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1fe.png new file mode 100644 index 00000000..00fa3401 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2-1f1ff.png b/twake/frontend/public/public/emojione/64/1f1f2-1f1ff.png new file mode 100644 index 00000000..aec24d40 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f2.png b/twake/frontend/public/public/emojione/64/1f1f2.png new file mode 100644 index 00000000..14bf9454 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f3-1f1e6.png b/twake/frontend/public/public/emojione/64/1f1f3-1f1e6.png new file mode 100644 index 00000000..364d761c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f3-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f3-1f1e8.png b/twake/frontend/public/public/emojione/64/1f1f3-1f1e8.png new file mode 100644 index 00000000..8bbcd86e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f3-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f3-1f1ea.png b/twake/frontend/public/public/emojione/64/1f1f3-1f1ea.png new file mode 100644 index 00000000..cea1bf7d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f3-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f3-1f1eb.png b/twake/frontend/public/public/emojione/64/1f1f3-1f1eb.png new file mode 100644 index 00000000..6491fbb0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f3-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f3-1f1ec.png b/twake/frontend/public/public/emojione/64/1f1f3-1f1ec.png new file mode 100644 index 00000000..165c665a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f3-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f3-1f1ee.png b/twake/frontend/public/public/emojione/64/1f1f3-1f1ee.png new file mode 100644 index 00000000..8aedf604 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f3-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f3-1f1f1.png b/twake/frontend/public/public/emojione/64/1f1f3-1f1f1.png new file mode 100644 index 00000000..2165dbc2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f3-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f3-1f1f4.png b/twake/frontend/public/public/emojione/64/1f1f3-1f1f4.png new file mode 100644 index 00000000..13f5dd2b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f3-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f3-1f1f5.png b/twake/frontend/public/public/emojione/64/1f1f3-1f1f5.png new file mode 100644 index 00000000..5285d1ab Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f3-1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f3-1f1f7.png b/twake/frontend/public/public/emojione/64/1f1f3-1f1f7.png new file mode 100644 index 00000000..9e53aa2d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f3-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f3-1f1fa.png b/twake/frontend/public/public/emojione/64/1f1f3-1f1fa.png new file mode 100644 index 00000000..e63a08ad Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f3-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f3-1f1ff.png b/twake/frontend/public/public/emojione/64/1f1f3-1f1ff.png new file mode 100644 index 00000000..90a6a3b6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f3-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f3.png b/twake/frontend/public/public/emojione/64/1f1f3.png new file mode 100644 index 00000000..f57de969 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f4-1f1f2.png b/twake/frontend/public/public/emojione/64/1f1f4-1f1f2.png new file mode 100644 index 00000000..c0c39772 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f4-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f4.png b/twake/frontend/public/public/emojione/64/1f1f4.png new file mode 100644 index 00000000..b0bad009 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f5-1f1e6.png b/twake/frontend/public/public/emojione/64/1f1f5-1f1e6.png new file mode 100644 index 00000000..434e4d30 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f5-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f5-1f1ea.png b/twake/frontend/public/public/emojione/64/1f1f5-1f1ea.png new file mode 100644 index 00000000..92bd1244 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f5-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f5-1f1eb.png b/twake/frontend/public/public/emojione/64/1f1f5-1f1eb.png new file mode 100644 index 00000000..9155609e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f5-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f5-1f1ec.png b/twake/frontend/public/public/emojione/64/1f1f5-1f1ec.png new file mode 100644 index 00000000..49902d8d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f5-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f5-1f1ed.png b/twake/frontend/public/public/emojione/64/1f1f5-1f1ed.png new file mode 100644 index 00000000..a547640e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f5-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f5-1f1f0.png b/twake/frontend/public/public/emojione/64/1f1f5-1f1f0.png new file mode 100644 index 00000000..577b549f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f5-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f5-1f1f1.png b/twake/frontend/public/public/emojione/64/1f1f5-1f1f1.png new file mode 100644 index 00000000..adc07b16 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f5-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f5-1f1f2.png b/twake/frontend/public/public/emojione/64/1f1f5-1f1f2.png new file mode 100644 index 00000000..3198c437 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f5-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f5-1f1f3.png b/twake/frontend/public/public/emojione/64/1f1f5-1f1f3.png new file mode 100644 index 00000000..a1b49963 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f5-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f5-1f1f7.png b/twake/frontend/public/public/emojione/64/1f1f5-1f1f7.png new file mode 100644 index 00000000..8e3b268f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f5-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f5-1f1f8.png b/twake/frontend/public/public/emojione/64/1f1f5-1f1f8.png new file mode 100644 index 00000000..b3ef185a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f5-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f5-1f1f9.png b/twake/frontend/public/public/emojione/64/1f1f5-1f1f9.png new file mode 100644 index 00000000..de7cdc3c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f5-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f5-1f1fc.png b/twake/frontend/public/public/emojione/64/1f1f5-1f1fc.png new file mode 100644 index 00000000..fdd56ad3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f5-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f5-1f1fe.png b/twake/frontend/public/public/emojione/64/1f1f5-1f1fe.png new file mode 100644 index 00000000..a01da56e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f5-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f5.png b/twake/frontend/public/public/emojione/64/1f1f5.png new file mode 100644 index 00000000..0543fefb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f6-1f1e6.png b/twake/frontend/public/public/emojione/64/1f1f6-1f1e6.png new file mode 100644 index 00000000..3efc61f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f6-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f6.png b/twake/frontend/public/public/emojione/64/1f1f6.png new file mode 100644 index 00000000..ea766d85 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f7-1f1ea.png b/twake/frontend/public/public/emojione/64/1f1f7-1f1ea.png new file mode 100644 index 00000000..6a247fe5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f7-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f7-1f1f4.png b/twake/frontend/public/public/emojione/64/1f1f7-1f1f4.png new file mode 100644 index 00000000..05cea8d3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f7-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f7-1f1f8.png b/twake/frontend/public/public/emojione/64/1f1f7-1f1f8.png new file mode 100644 index 00000000..c69c7bc5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f7-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f7-1f1fa.png b/twake/frontend/public/public/emojione/64/1f1f7-1f1fa.png new file mode 100644 index 00000000..9c00e605 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f7-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f7-1f1fc.png b/twake/frontend/public/public/emojione/64/1f1f7-1f1fc.png new file mode 100644 index 00000000..b34ceece Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f7-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f7.png b/twake/frontend/public/public/emojione/64/1f1f7.png new file mode 100644 index 00000000..5e2a7333 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1e6.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1e6.png new file mode 100644 index 00000000..faaa2185 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1e7.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1e7.png new file mode 100644 index 00000000..e1e9c944 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1e7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1e8.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1e8.png new file mode 100644 index 00000000..65feb032 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1e9.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1e9.png new file mode 100644 index 00000000..e44bf0ee Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1ea.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1ea.png new file mode 100644 index 00000000..3438ee25 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1ec.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1ec.png new file mode 100644 index 00000000..aece1fe3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1ed.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1ed.png new file mode 100644 index 00000000..87aa7451 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1ee.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1ee.png new file mode 100644 index 00000000..0be4ad0b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1ef.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1ef.png new file mode 100644 index 00000000..13f5dd2b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1f0.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1f0.png new file mode 100644 index 00000000..cc412390 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1f1.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1f1.png new file mode 100644 index 00000000..4cdaa263 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1f2.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1f2.png new file mode 100644 index 00000000..cdbdfae7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1f3.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1f3.png new file mode 100644 index 00000000..d10ec8dc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1f4.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1f4.png new file mode 100644 index 00000000..dd7615d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1f7.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1f7.png new file mode 100644 index 00000000..2a670483 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1f8.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1f8.png new file mode 100644 index 00000000..bf602ad7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1f9.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1f9.png new file mode 100644 index 00000000..064ae7c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1fb.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1fb.png new file mode 100644 index 00000000..3310da1d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1fd.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1fd.png new file mode 100644 index 00000000..7416690f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1fe.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1fe.png new file mode 100644 index 00000000..61063311 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8-1f1ff.png b/twake/frontend/public/public/emojione/64/1f1f8-1f1ff.png new file mode 100644 index 00000000..dd51200a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f8.png b/twake/frontend/public/public/emojione/64/1f1f8.png new file mode 100644 index 00000000..5f7afe29 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9-1f1e6.png b/twake/frontend/public/public/emojione/64/1f1f9-1f1e6.png new file mode 100644 index 00000000..94523bdc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9-1f1e8.png b/twake/frontend/public/public/emojione/64/1f1f9-1f1e8.png new file mode 100644 index 00000000..9c035c54 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9-1f1e9.png b/twake/frontend/public/public/emojione/64/1f1f9-1f1e9.png new file mode 100644 index 00000000..05cea8d3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9-1f1e9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9-1f1eb.png b/twake/frontend/public/public/emojione/64/1f1f9-1f1eb.png new file mode 100644 index 00000000..7ec705f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9-1f1ec.png b/twake/frontend/public/public/emojione/64/1f1f9-1f1ec.png new file mode 100644 index 00000000..7cd39791 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9-1f1ed.png b/twake/frontend/public/public/emojione/64/1f1f9-1f1ed.png new file mode 100644 index 00000000..9647b5dd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9-1f1ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9-1f1ef.png b/twake/frontend/public/public/emojione/64/1f1f9-1f1ef.png new file mode 100644 index 00000000..cb719cac Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9-1f1ef.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9-1f1f0.png b/twake/frontend/public/public/emojione/64/1f1f9-1f1f0.png new file mode 100644 index 00000000..f353e2f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9-1f1f1.png b/twake/frontend/public/public/emojione/64/1f1f9-1f1f1.png new file mode 100644 index 00000000..77c94fa6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9-1f1f1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9-1f1f2.png b/twake/frontend/public/public/emojione/64/1f1f9-1f1f2.png new file mode 100644 index 00000000..ead0abcb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9-1f1f3.png b/twake/frontend/public/public/emojione/64/1f1f9-1f1f3.png new file mode 100644 index 00000000..5892d6e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9-1f1f4.png b/twake/frontend/public/public/emojione/64/1f1f9-1f1f4.png new file mode 100644 index 00000000..06f88645 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9-1f1f4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9-1f1f7.png b/twake/frontend/public/public/emojione/64/1f1f9-1f1f7.png new file mode 100644 index 00000000..0f9887bb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9-1f1f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9-1f1f9.png b/twake/frontend/public/public/emojione/64/1f1f9-1f1f9.png new file mode 100644 index 00000000..583e9be7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9-1f1fb.png b/twake/frontend/public/public/emojione/64/1f1f9-1f1fb.png new file mode 100644 index 00000000..69ae85b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9-1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9-1f1fc.png b/twake/frontend/public/public/emojione/64/1f1f9-1f1fc.png new file mode 100644 index 00000000..bddf43cf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9-1f1ff.png b/twake/frontend/public/public/emojione/64/1f1f9-1f1ff.png new file mode 100644 index 00000000..4c860910 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1f9.png b/twake/frontend/public/public/emojione/64/1f1f9.png new file mode 100644 index 00000000..6fa61546 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fa-1f1e6.png b/twake/frontend/public/public/emojione/64/1f1fa-1f1e6.png new file mode 100644 index 00000000..0c8aed07 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fa-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fa-1f1ec.png b/twake/frontend/public/public/emojione/64/1f1fa-1f1ec.png new file mode 100644 index 00000000..8a1a5a42 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fa-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fa-1f1f2.png b/twake/frontend/public/public/emojione/64/1f1fa-1f1f2.png new file mode 100644 index 00000000..a1a85b70 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fa-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fa-1f1f3.png b/twake/frontend/public/public/emojione/64/1f1fa-1f1f3.png new file mode 100644 index 00000000..e00edf12 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fa-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fa-1f1f8.png b/twake/frontend/public/public/emojione/64/1f1fa-1f1f8.png new file mode 100644 index 00000000..a1a85b70 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fa-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fa-1f1fe.png b/twake/frontend/public/public/emojione/64/1f1fa-1f1fe.png new file mode 100644 index 00000000..42c9a67a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fa-1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fa-1f1ff.png b/twake/frontend/public/public/emojione/64/1f1fa-1f1ff.png new file mode 100644 index 00000000..91ce3434 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fa-1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fa.png b/twake/frontend/public/public/emojione/64/1f1fa.png new file mode 100644 index 00000000..452a9efc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fb-1f1e6.png b/twake/frontend/public/public/emojione/64/1f1fb-1f1e6.png new file mode 100644 index 00000000..7573ad59 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fb-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fb-1f1e8.png b/twake/frontend/public/public/emojione/64/1f1fb-1f1e8.png new file mode 100644 index 00000000..b84fd7f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fb-1f1e8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fb-1f1ea.png b/twake/frontend/public/public/emojione/64/1f1fb-1f1ea.png new file mode 100644 index 00000000..72f20498 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fb-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fb-1f1ec.png b/twake/frontend/public/public/emojione/64/1f1fb-1f1ec.png new file mode 100644 index 00000000..583f0562 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fb-1f1ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fb-1f1ee.png b/twake/frontend/public/public/emojione/64/1f1fb-1f1ee.png new file mode 100644 index 00000000..e7719ba7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fb-1f1ee.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fb-1f1f3.png b/twake/frontend/public/public/emojione/64/1f1fb-1f1f3.png new file mode 100644 index 00000000..7dc37815 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fb-1f1f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fb-1f1fa.png b/twake/frontend/public/public/emojione/64/1f1fb-1f1fa.png new file mode 100644 index 00000000..22654aac Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fb-1f1fa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fb.png b/twake/frontend/public/public/emojione/64/1f1fb.png new file mode 100644 index 00000000..335046ad Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fc-1f1eb.png b/twake/frontend/public/public/emojione/64/1f1fc-1f1eb.png new file mode 100644 index 00000000..efc41ef1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fc-1f1eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fc-1f1f8.png b/twake/frontend/public/public/emojione/64/1f1fc-1f1f8.png new file mode 100644 index 00000000..3754fb1c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fc-1f1f8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fc.png b/twake/frontend/public/public/emojione/64/1f1fc.png new file mode 100644 index 00000000..3ff4387d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fd-1f1f0.png b/twake/frontend/public/public/emojione/64/1f1fd-1f1f0.png new file mode 100644 index 00000000..35d72cfb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fd-1f1f0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fd.png b/twake/frontend/public/public/emojione/64/1f1fd.png new file mode 100644 index 00000000..970414fd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fe-1f1ea.png b/twake/frontend/public/public/emojione/64/1f1fe-1f1ea.png new file mode 100644 index 00000000..5db46f0e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fe-1f1ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fe-1f1f9.png b/twake/frontend/public/public/emojione/64/1f1fe-1f1f9.png new file mode 100644 index 00000000..ebc1e770 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fe-1f1f9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1fe.png b/twake/frontend/public/public/emojione/64/1f1fe.png new file mode 100644 index 00000000..9a288aae Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ff-1f1e6.png b/twake/frontend/public/public/emojione/64/1f1ff-1f1e6.png new file mode 100644 index 00000000..9062922f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ff-1f1e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ff-1f1f2.png b/twake/frontend/public/public/emojione/64/1f1ff-1f1f2.png new file mode 100644 index 00000000..ac8730a4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ff-1f1f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ff-1f1fc.png b/twake/frontend/public/public/emojione/64/1f1ff-1f1fc.png new file mode 100644 index 00000000..96273454 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ff-1f1fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f1ff.png b/twake/frontend/public/public/emojione/64/1f1ff.png new file mode 100644 index 00000000..cf5c2ae0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f1ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f201.png b/twake/frontend/public/public/emojione/64/1f201.png new file mode 100644 index 00000000..d1ff1684 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f201.png differ diff --git a/twake/frontend/public/public/emojione/64/1f202.png b/twake/frontend/public/public/emojione/64/1f202.png new file mode 100644 index 00000000..e1087e55 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f202.png differ diff --git a/twake/frontend/public/public/emojione/64/1f21a.png b/twake/frontend/public/public/emojione/64/1f21a.png new file mode 100644 index 00000000..be0ad9c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f21a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f22f.png b/twake/frontend/public/public/emojione/64/1f22f.png new file mode 100644 index 00000000..a185f274 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f22f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f232.png b/twake/frontend/public/public/emojione/64/1f232.png new file mode 100644 index 00000000..7cbd3c56 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f232.png differ diff --git a/twake/frontend/public/public/emojione/64/1f233.png b/twake/frontend/public/public/emojione/64/1f233.png new file mode 100644 index 00000000..c40aefa7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f233.png differ diff --git a/twake/frontend/public/public/emojione/64/1f234.png b/twake/frontend/public/public/emojione/64/1f234.png new file mode 100644 index 00000000..a3a799ca Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f234.png differ diff --git a/twake/frontend/public/public/emojione/64/1f235.png b/twake/frontend/public/public/emojione/64/1f235.png new file mode 100644 index 00000000..09c3b00a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f235.png differ diff --git a/twake/frontend/public/public/emojione/64/1f236.png b/twake/frontend/public/public/emojione/64/1f236.png new file mode 100644 index 00000000..02ebbf40 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f236.png differ diff --git a/twake/frontend/public/public/emojione/64/1f237.png b/twake/frontend/public/public/emojione/64/1f237.png new file mode 100644 index 00000000..cc47b980 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f237.png differ diff --git a/twake/frontend/public/public/emojione/64/1f238.png b/twake/frontend/public/public/emojione/64/1f238.png new file mode 100644 index 00000000..4ecc670c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f238.png differ diff --git a/twake/frontend/public/public/emojione/64/1f239.png b/twake/frontend/public/public/emojione/64/1f239.png new file mode 100644 index 00000000..f381d5dc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f239.png differ diff --git a/twake/frontend/public/public/emojione/64/1f23a.png b/twake/frontend/public/public/emojione/64/1f23a.png new file mode 100644 index 00000000..ca68331a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f23a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f250.png b/twake/frontend/public/public/emojione/64/1f250.png new file mode 100644 index 00000000..6815fe85 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f250.png differ diff --git a/twake/frontend/public/public/emojione/64/1f251.png b/twake/frontend/public/public/emojione/64/1f251.png new file mode 100644 index 00000000..87a01d23 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f251.png differ diff --git a/twake/frontend/public/public/emojione/64/1f300.png b/twake/frontend/public/public/emojione/64/1f300.png new file mode 100644 index 00000000..3e64745b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f300.png differ diff --git a/twake/frontend/public/public/emojione/64/1f301.png b/twake/frontend/public/public/emojione/64/1f301.png new file mode 100644 index 00000000..10efaf5b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f301.png differ diff --git a/twake/frontend/public/public/emojione/64/1f302.png b/twake/frontend/public/public/emojione/64/1f302.png new file mode 100644 index 00000000..7a8242a8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f302.png differ diff --git a/twake/frontend/public/public/emojione/64/1f303.png b/twake/frontend/public/public/emojione/64/1f303.png new file mode 100644 index 00000000..17e2900e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f303.png differ diff --git a/twake/frontend/public/public/emojione/64/1f304.png b/twake/frontend/public/public/emojione/64/1f304.png new file mode 100644 index 00000000..90d0838b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f304.png differ diff --git a/twake/frontend/public/public/emojione/64/1f305.png b/twake/frontend/public/public/emojione/64/1f305.png new file mode 100644 index 00000000..d3b5cc14 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f305.png differ diff --git a/twake/frontend/public/public/emojione/64/1f306.png b/twake/frontend/public/public/emojione/64/1f306.png new file mode 100644 index 00000000..4ca36457 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f306.png differ diff --git a/twake/frontend/public/public/emojione/64/1f307.png b/twake/frontend/public/public/emojione/64/1f307.png new file mode 100644 index 00000000..3e4e4716 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f307.png differ diff --git a/twake/frontend/public/public/emojione/64/1f308.png b/twake/frontend/public/public/emojione/64/1f308.png new file mode 100644 index 00000000..5067966a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f308.png differ diff --git a/twake/frontend/public/public/emojione/64/1f309.png b/twake/frontend/public/public/emojione/64/1f309.png new file mode 100644 index 00000000..e0dc7ec5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f309.png differ diff --git a/twake/frontend/public/public/emojione/64/1f30a.png b/twake/frontend/public/public/emojione/64/1f30a.png new file mode 100644 index 00000000..db488577 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f30a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f30b.png b/twake/frontend/public/public/emojione/64/1f30b.png new file mode 100644 index 00000000..29fb3b24 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f30b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f30c.png b/twake/frontend/public/public/emojione/64/1f30c.png new file mode 100644 index 00000000..16865d31 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f30c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f30d.png b/twake/frontend/public/public/emojione/64/1f30d.png new file mode 100644 index 00000000..b414ccc3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f30d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f30e.png b/twake/frontend/public/public/emojione/64/1f30e.png new file mode 100644 index 00000000..be05267c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f30e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f30f.png b/twake/frontend/public/public/emojione/64/1f30f.png new file mode 100644 index 00000000..d37ff56e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f30f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f310.png b/twake/frontend/public/public/emojione/64/1f310.png new file mode 100644 index 00000000..2e303748 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f310.png differ diff --git a/twake/frontend/public/public/emojione/64/1f311.png b/twake/frontend/public/public/emojione/64/1f311.png new file mode 100644 index 00000000..fa648ba5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f311.png differ diff --git a/twake/frontend/public/public/emojione/64/1f312.png b/twake/frontend/public/public/emojione/64/1f312.png new file mode 100644 index 00000000..4c6adabb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f312.png differ diff --git a/twake/frontend/public/public/emojione/64/1f313.png b/twake/frontend/public/public/emojione/64/1f313.png new file mode 100644 index 00000000..590ed629 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f313.png differ diff --git a/twake/frontend/public/public/emojione/64/1f314.png b/twake/frontend/public/public/emojione/64/1f314.png new file mode 100644 index 00000000..45cc3000 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f314.png differ diff --git a/twake/frontend/public/public/emojione/64/1f315.png b/twake/frontend/public/public/emojione/64/1f315.png new file mode 100644 index 00000000..89e6a29f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f315.png differ diff --git a/twake/frontend/public/public/emojione/64/1f316.png b/twake/frontend/public/public/emojione/64/1f316.png new file mode 100644 index 00000000..ac61e2fe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f316.png differ diff --git a/twake/frontend/public/public/emojione/64/1f317.png b/twake/frontend/public/public/emojione/64/1f317.png new file mode 100644 index 00000000..6766c884 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f317.png differ diff --git a/twake/frontend/public/public/emojione/64/1f318.png b/twake/frontend/public/public/emojione/64/1f318.png new file mode 100644 index 00000000..215bc654 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f318.png differ diff --git a/twake/frontend/public/public/emojione/64/1f319.png b/twake/frontend/public/public/emojione/64/1f319.png new file mode 100644 index 00000000..28b0abea Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f319.png differ diff --git a/twake/frontend/public/public/emojione/64/1f31a.png b/twake/frontend/public/public/emojione/64/1f31a.png new file mode 100644 index 00000000..30113c46 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f31a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f31b.png b/twake/frontend/public/public/emojione/64/1f31b.png new file mode 100644 index 00000000..e62c5ca8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f31b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f31c.png b/twake/frontend/public/public/emojione/64/1f31c.png new file mode 100644 index 00000000..e4d25190 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f31c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f31d.png b/twake/frontend/public/public/emojione/64/1f31d.png new file mode 100644 index 00000000..ed221942 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f31d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f31e.png b/twake/frontend/public/public/emojione/64/1f31e.png new file mode 100644 index 00000000..d9568677 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f31e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f31f.png b/twake/frontend/public/public/emojione/64/1f31f.png new file mode 100644 index 00000000..22062726 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f31f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f320.png b/twake/frontend/public/public/emojione/64/1f320.png new file mode 100644 index 00000000..e3040a8f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f320.png differ diff --git a/twake/frontend/public/public/emojione/64/1f321.png b/twake/frontend/public/public/emojione/64/1f321.png new file mode 100644 index 00000000..f2bcfe68 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f321.png differ diff --git a/twake/frontend/public/public/emojione/64/1f324.png b/twake/frontend/public/public/emojione/64/1f324.png new file mode 100644 index 00000000..bd9dcaf1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f324.png differ diff --git a/twake/frontend/public/public/emojione/64/1f325.png b/twake/frontend/public/public/emojione/64/1f325.png new file mode 100644 index 00000000..1c9ba7ea Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f325.png differ diff --git a/twake/frontend/public/public/emojione/64/1f326.png b/twake/frontend/public/public/emojione/64/1f326.png new file mode 100644 index 00000000..be5f5fe7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f326.png differ diff --git a/twake/frontend/public/public/emojione/64/1f327.png b/twake/frontend/public/public/emojione/64/1f327.png new file mode 100644 index 00000000..5c960272 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f327.png differ diff --git a/twake/frontend/public/public/emojione/64/1f328.png b/twake/frontend/public/public/emojione/64/1f328.png new file mode 100644 index 00000000..9a147593 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f328.png differ diff --git a/twake/frontend/public/public/emojione/64/1f329.png b/twake/frontend/public/public/emojione/64/1f329.png new file mode 100644 index 00000000..e8893f59 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f329.png differ diff --git a/twake/frontend/public/public/emojione/64/1f32a.png b/twake/frontend/public/public/emojione/64/1f32a.png new file mode 100644 index 00000000..d836632c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f32a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f32b.png b/twake/frontend/public/public/emojione/64/1f32b.png new file mode 100644 index 00000000..0e903cb2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f32b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f32c.png b/twake/frontend/public/public/emojione/64/1f32c.png new file mode 100644 index 00000000..9a5eee43 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f32c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f32d.png b/twake/frontend/public/public/emojione/64/1f32d.png new file mode 100644 index 00000000..10335335 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f32d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f32e.png b/twake/frontend/public/public/emojione/64/1f32e.png new file mode 100644 index 00000000..853bf845 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f32e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f32f.png b/twake/frontend/public/public/emojione/64/1f32f.png new file mode 100644 index 00000000..4b75980a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f32f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f330.png b/twake/frontend/public/public/emojione/64/1f330.png new file mode 100644 index 00000000..4bb75eb1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f330.png differ diff --git a/twake/frontend/public/public/emojione/64/1f331.png b/twake/frontend/public/public/emojione/64/1f331.png new file mode 100644 index 00000000..ef9cba1b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f331.png differ diff --git a/twake/frontend/public/public/emojione/64/1f332.png b/twake/frontend/public/public/emojione/64/1f332.png new file mode 100644 index 00000000..b5fa22ba Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f332.png differ diff --git a/twake/frontend/public/public/emojione/64/1f333.png b/twake/frontend/public/public/emojione/64/1f333.png new file mode 100644 index 00000000..5f98816e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f333.png differ diff --git a/twake/frontend/public/public/emojione/64/1f334.png b/twake/frontend/public/public/emojione/64/1f334.png new file mode 100644 index 00000000..365859de Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f334.png differ diff --git a/twake/frontend/public/public/emojione/64/1f335.png b/twake/frontend/public/public/emojione/64/1f335.png new file mode 100644 index 00000000..652fd170 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f335.png differ diff --git a/twake/frontend/public/public/emojione/64/1f336.png b/twake/frontend/public/public/emojione/64/1f336.png new file mode 100644 index 00000000..26cdbad6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f336.png differ diff --git a/twake/frontend/public/public/emojione/64/1f337.png b/twake/frontend/public/public/emojione/64/1f337.png new file mode 100644 index 00000000..26890233 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f337.png differ diff --git a/twake/frontend/public/public/emojione/64/1f338.png b/twake/frontend/public/public/emojione/64/1f338.png new file mode 100644 index 00000000..e453c833 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f338.png differ diff --git a/twake/frontend/public/public/emojione/64/1f339.png b/twake/frontend/public/public/emojione/64/1f339.png new file mode 100644 index 00000000..a17cbcf5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f339.png differ diff --git a/twake/frontend/public/public/emojione/64/1f33a.png b/twake/frontend/public/public/emojione/64/1f33a.png new file mode 100644 index 00000000..1a1e9fd9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f33a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f33b.png b/twake/frontend/public/public/emojione/64/1f33b.png new file mode 100644 index 00000000..338d42c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f33b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f33c.png b/twake/frontend/public/public/emojione/64/1f33c.png new file mode 100644 index 00000000..71f076ce Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f33c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f33d.png b/twake/frontend/public/public/emojione/64/1f33d.png new file mode 100644 index 00000000..31a3aa01 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f33d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f33e.png b/twake/frontend/public/public/emojione/64/1f33e.png new file mode 100644 index 00000000..6e524f64 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f33e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f33f.png b/twake/frontend/public/public/emojione/64/1f33f.png new file mode 100644 index 00000000..3248a260 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f33f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f340.png b/twake/frontend/public/public/emojione/64/1f340.png new file mode 100644 index 00000000..c7d2c8a6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f340.png differ diff --git a/twake/frontend/public/public/emojione/64/1f341.png b/twake/frontend/public/public/emojione/64/1f341.png new file mode 100644 index 00000000..f92ec671 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f341.png differ diff --git a/twake/frontend/public/public/emojione/64/1f342.png b/twake/frontend/public/public/emojione/64/1f342.png new file mode 100644 index 00000000..457f5053 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f342.png differ diff --git a/twake/frontend/public/public/emojione/64/1f343.png b/twake/frontend/public/public/emojione/64/1f343.png new file mode 100644 index 00000000..2ce29ec0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f343.png differ diff --git a/twake/frontend/public/public/emojione/64/1f344.png b/twake/frontend/public/public/emojione/64/1f344.png new file mode 100644 index 00000000..07065b40 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f344.png differ diff --git a/twake/frontend/public/public/emojione/64/1f345.png b/twake/frontend/public/public/emojione/64/1f345.png new file mode 100644 index 00000000..24609a5e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f345.png differ diff --git a/twake/frontend/public/public/emojione/64/1f346.png b/twake/frontend/public/public/emojione/64/1f346.png new file mode 100644 index 00000000..bdc8a029 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f346.png differ diff --git a/twake/frontend/public/public/emojione/64/1f347.png b/twake/frontend/public/public/emojione/64/1f347.png new file mode 100644 index 00000000..e1417a22 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f347.png differ diff --git a/twake/frontend/public/public/emojione/64/1f348.png b/twake/frontend/public/public/emojione/64/1f348.png new file mode 100644 index 00000000..02ba1878 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f348.png differ diff --git a/twake/frontend/public/public/emojione/64/1f349.png b/twake/frontend/public/public/emojione/64/1f349.png new file mode 100644 index 00000000..ccdd0356 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f349.png differ diff --git a/twake/frontend/public/public/emojione/64/1f34a.png b/twake/frontend/public/public/emojione/64/1f34a.png new file mode 100644 index 00000000..79ccb98d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f34a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f34b.png b/twake/frontend/public/public/emojione/64/1f34b.png new file mode 100644 index 00000000..095a9bcb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f34b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f34c.png b/twake/frontend/public/public/emojione/64/1f34c.png new file mode 100644 index 00000000..6e5c9cd9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f34c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f34d.png b/twake/frontend/public/public/emojione/64/1f34d.png new file mode 100644 index 00000000..e0d4c78b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f34d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f34e.png b/twake/frontend/public/public/emojione/64/1f34e.png new file mode 100644 index 00000000..c0391e50 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f34e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f34f.png b/twake/frontend/public/public/emojione/64/1f34f.png new file mode 100644 index 00000000..d4254221 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f34f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f350.png b/twake/frontend/public/public/emojione/64/1f350.png new file mode 100644 index 00000000..ed3dcae0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f350.png differ diff --git a/twake/frontend/public/public/emojione/64/1f351.png b/twake/frontend/public/public/emojione/64/1f351.png new file mode 100644 index 00000000..7fe68522 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f351.png differ diff --git a/twake/frontend/public/public/emojione/64/1f352.png b/twake/frontend/public/public/emojione/64/1f352.png new file mode 100644 index 00000000..1e4e3c2f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f352.png differ diff --git a/twake/frontend/public/public/emojione/64/1f353.png b/twake/frontend/public/public/emojione/64/1f353.png new file mode 100644 index 00000000..07ce2350 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f353.png differ diff --git a/twake/frontend/public/public/emojione/64/1f354.png b/twake/frontend/public/public/emojione/64/1f354.png new file mode 100644 index 00000000..5d7e3438 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f354.png differ diff --git a/twake/frontend/public/public/emojione/64/1f355.png b/twake/frontend/public/public/emojione/64/1f355.png new file mode 100644 index 00000000..1f312635 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f355.png differ diff --git a/twake/frontend/public/public/emojione/64/1f356.png b/twake/frontend/public/public/emojione/64/1f356.png new file mode 100644 index 00000000..f4f2c857 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f356.png differ diff --git a/twake/frontend/public/public/emojione/64/1f357.png b/twake/frontend/public/public/emojione/64/1f357.png new file mode 100644 index 00000000..b528a360 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f357.png differ diff --git a/twake/frontend/public/public/emojione/64/1f358.png b/twake/frontend/public/public/emojione/64/1f358.png new file mode 100644 index 00000000..6b9497c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f358.png differ diff --git a/twake/frontend/public/public/emojione/64/1f359.png b/twake/frontend/public/public/emojione/64/1f359.png new file mode 100644 index 00000000..3e882acf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f359.png differ diff --git a/twake/frontend/public/public/emojione/64/1f35a.png b/twake/frontend/public/public/emojione/64/1f35a.png new file mode 100644 index 00000000..316c4922 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f35a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f35b.png b/twake/frontend/public/public/emojione/64/1f35b.png new file mode 100644 index 00000000..e7748559 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f35b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f35c.png b/twake/frontend/public/public/emojione/64/1f35c.png new file mode 100644 index 00000000..24f358ee Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f35c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f35d.png b/twake/frontend/public/public/emojione/64/1f35d.png new file mode 100644 index 00000000..75310de6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f35d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f35e.png b/twake/frontend/public/public/emojione/64/1f35e.png new file mode 100644 index 00000000..b4bf6626 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f35e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f35f.png b/twake/frontend/public/public/emojione/64/1f35f.png new file mode 100644 index 00000000..7d2b6c50 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f35f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f360.png b/twake/frontend/public/public/emojione/64/1f360.png new file mode 100644 index 00000000..9d0e082a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f360.png differ diff --git a/twake/frontend/public/public/emojione/64/1f361.png b/twake/frontend/public/public/emojione/64/1f361.png new file mode 100644 index 00000000..79761395 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f361.png differ diff --git a/twake/frontend/public/public/emojione/64/1f362.png b/twake/frontend/public/public/emojione/64/1f362.png new file mode 100644 index 00000000..af6f6989 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f362.png differ diff --git a/twake/frontend/public/public/emojione/64/1f363.png b/twake/frontend/public/public/emojione/64/1f363.png new file mode 100644 index 00000000..0319ba5f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f363.png differ diff --git a/twake/frontend/public/public/emojione/64/1f364.png b/twake/frontend/public/public/emojione/64/1f364.png new file mode 100644 index 00000000..bb746760 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f364.png differ diff --git a/twake/frontend/public/public/emojione/64/1f365.png b/twake/frontend/public/public/emojione/64/1f365.png new file mode 100644 index 00000000..60c2d8c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f365.png differ diff --git a/twake/frontend/public/public/emojione/64/1f366.png b/twake/frontend/public/public/emojione/64/1f366.png new file mode 100644 index 00000000..a9ae0ca5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f366.png differ diff --git a/twake/frontend/public/public/emojione/64/1f367.png b/twake/frontend/public/public/emojione/64/1f367.png new file mode 100644 index 00000000..c42046ba Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f367.png differ diff --git a/twake/frontend/public/public/emojione/64/1f368.png b/twake/frontend/public/public/emojione/64/1f368.png new file mode 100644 index 00000000..246e6b03 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f368.png differ diff --git a/twake/frontend/public/public/emojione/64/1f369.png b/twake/frontend/public/public/emojione/64/1f369.png new file mode 100644 index 00000000..356421ea Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f369.png differ diff --git a/twake/frontend/public/public/emojione/64/1f36a.png b/twake/frontend/public/public/emojione/64/1f36a.png new file mode 100644 index 00000000..d716cf96 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f36a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f36b.png b/twake/frontend/public/public/emojione/64/1f36b.png new file mode 100644 index 00000000..798fb4fa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f36b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f36c.png b/twake/frontend/public/public/emojione/64/1f36c.png new file mode 100644 index 00000000..37ec42d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f36c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f36d.png b/twake/frontend/public/public/emojione/64/1f36d.png new file mode 100644 index 00000000..b8460d3e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f36d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f36e.png b/twake/frontend/public/public/emojione/64/1f36e.png new file mode 100644 index 00000000..b907c930 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f36e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f36f.png b/twake/frontend/public/public/emojione/64/1f36f.png new file mode 100644 index 00000000..f63f522b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f36f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f370.png b/twake/frontend/public/public/emojione/64/1f370.png new file mode 100644 index 00000000..046b32d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f370.png differ diff --git a/twake/frontend/public/public/emojione/64/1f371.png b/twake/frontend/public/public/emojione/64/1f371.png new file mode 100644 index 00000000..ac60df81 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f371.png differ diff --git a/twake/frontend/public/public/emojione/64/1f372.png b/twake/frontend/public/public/emojione/64/1f372.png new file mode 100644 index 00000000..02b30711 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f372.png differ diff --git a/twake/frontend/public/public/emojione/64/1f373.png b/twake/frontend/public/public/emojione/64/1f373.png new file mode 100644 index 00000000..d2c80da0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f373.png differ diff --git a/twake/frontend/public/public/emojione/64/1f374.png b/twake/frontend/public/public/emojione/64/1f374.png new file mode 100644 index 00000000..73553e42 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f374.png differ diff --git a/twake/frontend/public/public/emojione/64/1f375.png b/twake/frontend/public/public/emojione/64/1f375.png new file mode 100644 index 00000000..c673b423 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f375.png differ diff --git a/twake/frontend/public/public/emojione/64/1f376.png b/twake/frontend/public/public/emojione/64/1f376.png new file mode 100644 index 00000000..ebc90ccf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f376.png differ diff --git a/twake/frontend/public/public/emojione/64/1f377.png b/twake/frontend/public/public/emojione/64/1f377.png new file mode 100644 index 00000000..ce75bc4a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f377.png differ diff --git a/twake/frontend/public/public/emojione/64/1f378.png b/twake/frontend/public/public/emojione/64/1f378.png new file mode 100644 index 00000000..787d61e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f378.png differ diff --git a/twake/frontend/public/public/emojione/64/1f379.png b/twake/frontend/public/public/emojione/64/1f379.png new file mode 100644 index 00000000..5a8b06e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f379.png differ diff --git a/twake/frontend/public/public/emojione/64/1f37a.png b/twake/frontend/public/public/emojione/64/1f37a.png new file mode 100644 index 00000000..60a9e20b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f37a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f37b.png b/twake/frontend/public/public/emojione/64/1f37b.png new file mode 100644 index 00000000..9ce42da8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f37b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f37c.png b/twake/frontend/public/public/emojione/64/1f37c.png new file mode 100644 index 00000000..af3e8a7a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f37c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f37d.png b/twake/frontend/public/public/emojione/64/1f37d.png new file mode 100644 index 00000000..2703d15c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f37d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f37e.png b/twake/frontend/public/public/emojione/64/1f37e.png new file mode 100644 index 00000000..38b69d05 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f37e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f37f.png b/twake/frontend/public/public/emojione/64/1f37f.png new file mode 100644 index 00000000..04e43080 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f37f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f380.png b/twake/frontend/public/public/emojione/64/1f380.png new file mode 100644 index 00000000..f5d182fe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f380.png differ diff --git a/twake/frontend/public/public/emojione/64/1f381.png b/twake/frontend/public/public/emojione/64/1f381.png new file mode 100644 index 00000000..4825f4c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f381.png differ diff --git a/twake/frontend/public/public/emojione/64/1f382.png b/twake/frontend/public/public/emojione/64/1f382.png new file mode 100644 index 00000000..19d96e09 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f382.png differ diff --git a/twake/frontend/public/public/emojione/64/1f383.png b/twake/frontend/public/public/emojione/64/1f383.png new file mode 100644 index 00000000..f72645d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f383.png differ diff --git a/twake/frontend/public/public/emojione/64/1f384.png b/twake/frontend/public/public/emojione/64/1f384.png new file mode 100644 index 00000000..8dcc9296 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f384.png differ diff --git a/twake/frontend/public/public/emojione/64/1f385-1f3fb.png b/twake/frontend/public/public/emojione/64/1f385-1f3fb.png new file mode 100644 index 00000000..d9fd3fc5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f385-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f385-1f3fc.png b/twake/frontend/public/public/emojione/64/1f385-1f3fc.png new file mode 100644 index 00000000..1239ce05 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f385-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f385-1f3fd.png b/twake/frontend/public/public/emojione/64/1f385-1f3fd.png new file mode 100644 index 00000000..2207f810 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f385-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f385-1f3fe.png b/twake/frontend/public/public/emojione/64/1f385-1f3fe.png new file mode 100644 index 00000000..452f7ff8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f385-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f385-1f3ff.png b/twake/frontend/public/public/emojione/64/1f385-1f3ff.png new file mode 100644 index 00000000..faed7436 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f385-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f385.png b/twake/frontend/public/public/emojione/64/1f385.png new file mode 100644 index 00000000..2e45e879 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f385.png differ diff --git a/twake/frontend/public/public/emojione/64/1f386.png b/twake/frontend/public/public/emojione/64/1f386.png new file mode 100644 index 00000000..3f5a50c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f386.png differ diff --git a/twake/frontend/public/public/emojione/64/1f387.png b/twake/frontend/public/public/emojione/64/1f387.png new file mode 100644 index 00000000..285e4ee5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f387.png differ diff --git a/twake/frontend/public/public/emojione/64/1f388.png b/twake/frontend/public/public/emojione/64/1f388.png new file mode 100644 index 00000000..e12eb79a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f388.png differ diff --git a/twake/frontend/public/public/emojione/64/1f389.png b/twake/frontend/public/public/emojione/64/1f389.png new file mode 100644 index 00000000..cdbb6579 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f389.png differ diff --git a/twake/frontend/public/public/emojione/64/1f38a.png b/twake/frontend/public/public/emojione/64/1f38a.png new file mode 100644 index 00000000..62795598 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f38a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f38b.png b/twake/frontend/public/public/emojione/64/1f38b.png new file mode 100644 index 00000000..7b58fcdc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f38b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f38c.png b/twake/frontend/public/public/emojione/64/1f38c.png new file mode 100644 index 00000000..5caf664e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f38c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f38d.png b/twake/frontend/public/public/emojione/64/1f38d.png new file mode 100644 index 00000000..323ab017 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f38d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f38e.png b/twake/frontend/public/public/emojione/64/1f38e.png new file mode 100644 index 00000000..8e985fb7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f38e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f38f.png b/twake/frontend/public/public/emojione/64/1f38f.png new file mode 100644 index 00000000..ca8b54bd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f38f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f390.png b/twake/frontend/public/public/emojione/64/1f390.png new file mode 100644 index 00000000..be92bb86 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f390.png differ diff --git a/twake/frontend/public/public/emojione/64/1f391.png b/twake/frontend/public/public/emojione/64/1f391.png new file mode 100644 index 00000000..d98f8e64 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f391.png differ diff --git a/twake/frontend/public/public/emojione/64/1f392.png b/twake/frontend/public/public/emojione/64/1f392.png new file mode 100644 index 00000000..d9637d75 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f392.png differ diff --git a/twake/frontend/public/public/emojione/64/1f393.png b/twake/frontend/public/public/emojione/64/1f393.png new file mode 100644 index 00000000..bdbf508c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f393.png differ diff --git a/twake/frontend/public/public/emojione/64/1f396.png b/twake/frontend/public/public/emojione/64/1f396.png new file mode 100644 index 00000000..9e550344 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f396.png differ diff --git a/twake/frontend/public/public/emojione/64/1f397.png b/twake/frontend/public/public/emojione/64/1f397.png new file mode 100644 index 00000000..ec867379 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f397.png differ diff --git a/twake/frontend/public/public/emojione/64/1f399.png b/twake/frontend/public/public/emojione/64/1f399.png new file mode 100644 index 00000000..8045c003 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f399.png differ diff --git a/twake/frontend/public/public/emojione/64/1f39a.png b/twake/frontend/public/public/emojione/64/1f39a.png new file mode 100644 index 00000000..74b526f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f39a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f39b.png b/twake/frontend/public/public/emojione/64/1f39b.png new file mode 100644 index 00000000..61cd3ac7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f39b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f39e.png b/twake/frontend/public/public/emojione/64/1f39e.png new file mode 100644 index 00000000..4b0804ce Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f39e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f39f.png b/twake/frontend/public/public/emojione/64/1f39f.png new file mode 100644 index 00000000..71deb8b7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f39f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3a0.png b/twake/frontend/public/public/emojione/64/1f3a0.png new file mode 100644 index 00000000..b2105018 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3a0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3a1.png b/twake/frontend/public/public/emojione/64/1f3a1.png new file mode 100644 index 00000000..bce3dc75 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3a1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3a2.png b/twake/frontend/public/public/emojione/64/1f3a2.png new file mode 100644 index 00000000..c56dbea9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3a2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3a3.png b/twake/frontend/public/public/emojione/64/1f3a3.png new file mode 100644 index 00000000..550df5c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3a3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3a4.png b/twake/frontend/public/public/emojione/64/1f3a4.png new file mode 100644 index 00000000..4221e3db Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3a5.png b/twake/frontend/public/public/emojione/64/1f3a5.png new file mode 100644 index 00000000..57df0726 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3a5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3a6.png b/twake/frontend/public/public/emojione/64/1f3a6.png new file mode 100644 index 00000000..84671c38 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3a6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3a7.png b/twake/frontend/public/public/emojione/64/1f3a7.png new file mode 100644 index 00000000..4028aca0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3a7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3a8.png b/twake/frontend/public/public/emojione/64/1f3a8.png new file mode 100644 index 00000000..0f48b685 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3a9.png b/twake/frontend/public/public/emojione/64/1f3a9.png new file mode 100644 index 00000000..5acb432f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3a9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3aa.png b/twake/frontend/public/public/emojione/64/1f3aa.png new file mode 100644 index 00000000..bcbfd1fc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3aa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ab.png b/twake/frontend/public/public/emojione/64/1f3ab.png new file mode 100644 index 00000000..00205cdd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ab.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ac.png b/twake/frontend/public/public/emojione/64/1f3ac.png new file mode 100644 index 00000000..bb4d1534 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ac.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ad.png b/twake/frontend/public/public/emojione/64/1f3ad.png new file mode 100644 index 00000000..4df95c2b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ad.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ae.png b/twake/frontend/public/public/emojione/64/1f3ae.png new file mode 100644 index 00000000..8bdddaa1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ae.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3af.png b/twake/frontend/public/public/emojione/64/1f3af.png new file mode 100644 index 00000000..7ef9c954 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3af.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3b0.png b/twake/frontend/public/public/emojione/64/1f3b0.png new file mode 100644 index 00000000..92a9dcc6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3b0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3b1.png b/twake/frontend/public/public/emojione/64/1f3b1.png new file mode 100644 index 00000000..52353e0c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3b1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3b2.png b/twake/frontend/public/public/emojione/64/1f3b2.png new file mode 100644 index 00000000..bb7c5b56 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3b2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3b3.png b/twake/frontend/public/public/emojione/64/1f3b3.png new file mode 100644 index 00000000..d9021054 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3b3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3b4.png b/twake/frontend/public/public/emojione/64/1f3b4.png new file mode 100644 index 00000000..d3ffb36b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3b4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3b5.png b/twake/frontend/public/public/emojione/64/1f3b5.png new file mode 100644 index 00000000..a7eff5f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3b5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3b6.png b/twake/frontend/public/public/emojione/64/1f3b6.png new file mode 100644 index 00000000..fa3f4daf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3b6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3b7.png b/twake/frontend/public/public/emojione/64/1f3b7.png new file mode 100644 index 00000000..11d83fdf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3b7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3b8.png b/twake/frontend/public/public/emojione/64/1f3b8.png new file mode 100644 index 00000000..6a0f9d33 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3b8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3b9.png b/twake/frontend/public/public/emojione/64/1f3b9.png new file mode 100644 index 00000000..fbeb6ae8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3b9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ba.png b/twake/frontend/public/public/emojione/64/1f3ba.png new file mode 100644 index 00000000..73128c88 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ba.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3bb.png b/twake/frontend/public/public/emojione/64/1f3bb.png new file mode 100644 index 00000000..72b9af06 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3bb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3bc.png b/twake/frontend/public/public/emojione/64/1f3bc.png new file mode 100644 index 00000000..d20ba250 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3bc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3bd.png b/twake/frontend/public/public/emojione/64/1f3bd.png new file mode 100644 index 00000000..7a3470e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3bd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3be.png b/twake/frontend/public/public/emojione/64/1f3be.png new file mode 100644 index 00000000..f1300d6a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3be.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3bf.png b/twake/frontend/public/public/emojione/64/1f3bf.png new file mode 100644 index 00000000..f60606e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3bf.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c0.png b/twake/frontend/public/public/emojione/64/1f3c0.png new file mode 100644 index 00000000..8c72317d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c1.png b/twake/frontend/public/public/emojione/64/1f3c1.png new file mode 100644 index 00000000..f7bf550e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c2-1f3fb.png b/twake/frontend/public/public/emojione/64/1f3c2-1f3fb.png new file mode 100644 index 00000000..82b2d24d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c2-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c2-1f3fc.png b/twake/frontend/public/public/emojione/64/1f3c2-1f3fc.png new file mode 100644 index 00000000..7a9d9f24 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c2-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c2-1f3fd.png b/twake/frontend/public/public/emojione/64/1f3c2-1f3fd.png new file mode 100644 index 00000000..dd185d85 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c2-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c2-1f3fe.png b/twake/frontend/public/public/emojione/64/1f3c2-1f3fe.png new file mode 100644 index 00000000..fdbe9499 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c2-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c2-1f3ff.png b/twake/frontend/public/public/emojione/64/1f3c2-1f3ff.png new file mode 100644 index 00000000..e2b38584 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c2-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c2.png b/twake/frontend/public/public/emojione/64/1f3c2.png new file mode 100644 index 00000000..cfd26d9e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f3c3-1f3fb-2640.png new file mode 100644 index 00000000..cb1980db Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f3c3-1f3fb-2642.png new file mode 100644 index 00000000..57acd1c9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3-1f3fb.png b/twake/frontend/public/public/emojione/64/1f3c3-1f3fb.png new file mode 100644 index 00000000..57acd1c9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f3c3-1f3fc-2640.png new file mode 100644 index 00000000..04ba9353 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f3c3-1f3fc-2642.png new file mode 100644 index 00000000..0e596188 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3-1f3fc.png b/twake/frontend/public/public/emojione/64/1f3c3-1f3fc.png new file mode 100644 index 00000000..0e596188 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f3c3-1f3fd-2640.png new file mode 100644 index 00000000..fc57df70 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f3c3-1f3fd-2642.png new file mode 100644 index 00000000..9d0bfe74 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3-1f3fd.png b/twake/frontend/public/public/emojione/64/1f3c3-1f3fd.png new file mode 100644 index 00000000..9d0bfe74 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f3c3-1f3fe-2640.png new file mode 100644 index 00000000..2531c2aa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f3c3-1f3fe-2642.png new file mode 100644 index 00000000..393cd396 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3-1f3fe.png b/twake/frontend/public/public/emojione/64/1f3c3-1f3fe.png new file mode 100644 index 00000000..393cd396 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f3c3-1f3ff-2640.png new file mode 100644 index 00000000..60b80203 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f3c3-1f3ff-2642.png new file mode 100644 index 00000000..e810385c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3-1f3ff.png b/twake/frontend/public/public/emojione/64/1f3c3-1f3ff.png new file mode 100644 index 00000000..e810385c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3-2640.png b/twake/frontend/public/public/emojione/64/1f3c3-2640.png new file mode 100644 index 00000000..b1e526f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3-2642.png b/twake/frontend/public/public/emojione/64/1f3c3-2642.png new file mode 100644 index 00000000..6a6a1b72 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c3.png b/twake/frontend/public/public/emojione/64/1f3c3.png new file mode 100644 index 00000000..6a6a1b72 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f3c4-1f3fb-2640.png new file mode 100644 index 00000000..4dda0d38 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f3c4-1f3fb-2642.png new file mode 100644 index 00000000..a781756c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4-1f3fb.png b/twake/frontend/public/public/emojione/64/1f3c4-1f3fb.png new file mode 100644 index 00000000..a781756c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f3c4-1f3fc-2640.png new file mode 100644 index 00000000..26c7c2c4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f3c4-1f3fc-2642.png new file mode 100644 index 00000000..d4fe7e12 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4-1f3fc.png b/twake/frontend/public/public/emojione/64/1f3c4-1f3fc.png new file mode 100644 index 00000000..d4fe7e12 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f3c4-1f3fd-2640.png new file mode 100644 index 00000000..0ba9bed0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f3c4-1f3fd-2642.png new file mode 100644 index 00000000..4019b566 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4-1f3fd.png b/twake/frontend/public/public/emojione/64/1f3c4-1f3fd.png new file mode 100644 index 00000000..4019b566 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f3c4-1f3fe-2640.png new file mode 100644 index 00000000..240bec9a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f3c4-1f3fe-2642.png new file mode 100644 index 00000000..4f703b5c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4-1f3fe.png b/twake/frontend/public/public/emojione/64/1f3c4-1f3fe.png new file mode 100644 index 00000000..4f703b5c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f3c4-1f3ff-2640.png new file mode 100644 index 00000000..151bd7a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f3c4-1f3ff-2642.png new file mode 100644 index 00000000..8ede8c9d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4-1f3ff.png b/twake/frontend/public/public/emojione/64/1f3c4-1f3ff.png new file mode 100644 index 00000000..8ede8c9d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4-2640.png b/twake/frontend/public/public/emojione/64/1f3c4-2640.png new file mode 100644 index 00000000..909a0527 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4-2642.png b/twake/frontend/public/public/emojione/64/1f3c4-2642.png new file mode 100644 index 00000000..aebae34c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c4.png b/twake/frontend/public/public/emojione/64/1f3c4.png new file mode 100644 index 00000000..aebae34c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c5.png b/twake/frontend/public/public/emojione/64/1f3c5.png new file mode 100644 index 00000000..5a72601b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c6.png b/twake/frontend/public/public/emojione/64/1f3c6.png new file mode 100644 index 00000000..81e99fb5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c7-1f3fb.png b/twake/frontend/public/public/emojione/64/1f3c7-1f3fb.png new file mode 100644 index 00000000..5e2efc21 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c7-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c7-1f3fc.png b/twake/frontend/public/public/emojione/64/1f3c7-1f3fc.png new file mode 100644 index 00000000..02dcce60 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c7-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c7-1f3fd.png b/twake/frontend/public/public/emojione/64/1f3c7-1f3fd.png new file mode 100644 index 00000000..645b3156 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c7-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c7-1f3fe.png b/twake/frontend/public/public/emojione/64/1f3c7-1f3fe.png new file mode 100644 index 00000000..5799c445 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c7-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c7-1f3ff.png b/twake/frontend/public/public/emojione/64/1f3c7-1f3ff.png new file mode 100644 index 00000000..5c349516 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c7-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c7.png b/twake/frontend/public/public/emojione/64/1f3c7.png new file mode 100644 index 00000000..b5cf6838 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c8.png b/twake/frontend/public/public/emojione/64/1f3c8.png new file mode 100644 index 00000000..a461a0a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3c9.png b/twake/frontend/public/public/emojione/64/1f3c9.png new file mode 100644 index 00000000..5a846158 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3c9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f3ca-1f3fb-2640.png new file mode 100644 index 00000000..3dd25b40 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f3ca-1f3fb-2642.png new file mode 100644 index 00000000..797e8fd2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca-1f3fb.png b/twake/frontend/public/public/emojione/64/1f3ca-1f3fb.png new file mode 100644 index 00000000..797e8fd2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f3ca-1f3fc-2640.png new file mode 100644 index 00000000..8a01f6d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f3ca-1f3fc-2642.png new file mode 100644 index 00000000..8404c32d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca-1f3fc.png b/twake/frontend/public/public/emojione/64/1f3ca-1f3fc.png new file mode 100644 index 00000000..8404c32d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f3ca-1f3fd-2640.png new file mode 100644 index 00000000..e4c499bd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f3ca-1f3fd-2642.png new file mode 100644 index 00000000..cd9ffd9b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca-1f3fd.png b/twake/frontend/public/public/emojione/64/1f3ca-1f3fd.png new file mode 100644 index 00000000..cd9ffd9b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f3ca-1f3fe-2640.png new file mode 100644 index 00000000..5d779adf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f3ca-1f3fe-2642.png new file mode 100644 index 00000000..5d254ca5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca-1f3fe.png b/twake/frontend/public/public/emojione/64/1f3ca-1f3fe.png new file mode 100644 index 00000000..5d254ca5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f3ca-1f3ff-2640.png new file mode 100644 index 00000000..e30dabd2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f3ca-1f3ff-2642.png new file mode 100644 index 00000000..d896e7c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca-1f3ff.png b/twake/frontend/public/public/emojione/64/1f3ca-1f3ff.png new file mode 100644 index 00000000..d896e7c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca-2640.png b/twake/frontend/public/public/emojione/64/1f3ca-2640.png new file mode 100644 index 00000000..e80fdf6b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca-2642.png b/twake/frontend/public/public/emojione/64/1f3ca-2642.png new file mode 100644 index 00000000..47164a12 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ca.png b/twake/frontend/public/public/emojione/64/1f3ca.png new file mode 100644 index 00000000..47164a12 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ca.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f3cb-1f3fb-2640.png new file mode 100644 index 00000000..a0c46970 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f3cb-1f3fb-2642.png new file mode 100644 index 00000000..d69a2ed2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb-1f3fb.png b/twake/frontend/public/public/emojione/64/1f3cb-1f3fb.png new file mode 100644 index 00000000..d69a2ed2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f3cb-1f3fc-2640.png new file mode 100644 index 00000000..bd18679a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f3cb-1f3fc-2642.png new file mode 100644 index 00000000..3dc2f1c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb-1f3fc.png b/twake/frontend/public/public/emojione/64/1f3cb-1f3fc.png new file mode 100644 index 00000000..3dc2f1c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f3cb-1f3fd-2640.png new file mode 100644 index 00000000..467c61ef Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f3cb-1f3fd-2642.png new file mode 100644 index 00000000..4f338d9b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb-1f3fd.png b/twake/frontend/public/public/emojione/64/1f3cb-1f3fd.png new file mode 100644 index 00000000..4f338d9b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f3cb-1f3fe-2640.png new file mode 100644 index 00000000..3c5be4c9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f3cb-1f3fe-2642.png new file mode 100644 index 00000000..78d7d6ff Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb-1f3fe.png b/twake/frontend/public/public/emojione/64/1f3cb-1f3fe.png new file mode 100644 index 00000000..78d7d6ff Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f3cb-1f3ff-2640.png new file mode 100644 index 00000000..8754ecb7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f3cb-1f3ff-2642.png new file mode 100644 index 00000000..97d95d75 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb-1f3ff.png b/twake/frontend/public/public/emojione/64/1f3cb-1f3ff.png new file mode 100644 index 00000000..97d95d75 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb-2640.png b/twake/frontend/public/public/emojione/64/1f3cb-2640.png new file mode 100644 index 00000000..2661b268 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb-2642.png b/twake/frontend/public/public/emojione/64/1f3cb-2642.png new file mode 100644 index 00000000..1aaf98be Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cb.png b/twake/frontend/public/public/emojione/64/1f3cb.png new file mode 100644 index 00000000..1aaf98be Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f3cc-1f3fb-2640.png new file mode 100644 index 00000000..93fed25c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f3cc-1f3fb-2642.png new file mode 100644 index 00000000..554344d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc-1f3fb.png b/twake/frontend/public/public/emojione/64/1f3cc-1f3fb.png new file mode 100644 index 00000000..554344d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f3cc-1f3fc-2640.png new file mode 100644 index 00000000..1eaeca19 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f3cc-1f3fc-2642.png new file mode 100644 index 00000000..7cf0a332 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc-1f3fc.png b/twake/frontend/public/public/emojione/64/1f3cc-1f3fc.png new file mode 100644 index 00000000..7cf0a332 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f3cc-1f3fd-2640.png new file mode 100644 index 00000000..e084ddb2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f3cc-1f3fd-2642.png new file mode 100644 index 00000000..80a161d3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc-1f3fd.png b/twake/frontend/public/public/emojione/64/1f3cc-1f3fd.png new file mode 100644 index 00000000..80a161d3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f3cc-1f3fe-2640.png new file mode 100644 index 00000000..93d7fe6e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f3cc-1f3fe-2642.png new file mode 100644 index 00000000..957b9c97 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc-1f3fe.png b/twake/frontend/public/public/emojione/64/1f3cc-1f3fe.png new file mode 100644 index 00000000..957b9c97 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f3cc-1f3ff-2640.png new file mode 100644 index 00000000..3172f708 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f3cc-1f3ff-2642.png new file mode 100644 index 00000000..ee72c7ce Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc-1f3ff.png b/twake/frontend/public/public/emojione/64/1f3cc-1f3ff.png new file mode 100644 index 00000000..ee72c7ce Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc-2640.png b/twake/frontend/public/public/emojione/64/1f3cc-2640.png new file mode 100644 index 00000000..a26ac8ec Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc-2642.png b/twake/frontend/public/public/emojione/64/1f3cc-2642.png new file mode 100644 index 00000000..2cb13d3f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cc.png b/twake/frontend/public/public/emojione/64/1f3cc.png new file mode 100644 index 00000000..2cb13d3f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cd.png b/twake/frontend/public/public/emojione/64/1f3cd.png new file mode 100644 index 00000000..731de8bb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ce.png b/twake/frontend/public/public/emojione/64/1f3ce.png new file mode 100644 index 00000000..2b14d47c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ce.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3cf.png b/twake/frontend/public/public/emojione/64/1f3cf.png new file mode 100644 index 00000000..6087d4bd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3cf.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3d0.png b/twake/frontend/public/public/emojione/64/1f3d0.png new file mode 100644 index 00000000..cc022289 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3d0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3d1.png b/twake/frontend/public/public/emojione/64/1f3d1.png new file mode 100644 index 00000000..994a4a80 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3d1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3d2.png b/twake/frontend/public/public/emojione/64/1f3d2.png new file mode 100644 index 00000000..c9c94c42 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3d2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3d3.png b/twake/frontend/public/public/emojione/64/1f3d3.png new file mode 100644 index 00000000..6f8984bf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3d3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3d4.png b/twake/frontend/public/public/emojione/64/1f3d4.png new file mode 100644 index 00000000..54f54bac Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3d4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3d5.png b/twake/frontend/public/public/emojione/64/1f3d5.png new file mode 100644 index 00000000..0672e12e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3d5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3d6.png b/twake/frontend/public/public/emojione/64/1f3d6.png new file mode 100644 index 00000000..0a089d4c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3d6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3d7.png b/twake/frontend/public/public/emojione/64/1f3d7.png new file mode 100644 index 00000000..98d56cd7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3d7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3d8.png b/twake/frontend/public/public/emojione/64/1f3d8.png new file mode 100644 index 00000000..2b3b230f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3d8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3d9.png b/twake/frontend/public/public/emojione/64/1f3d9.png new file mode 100644 index 00000000..0054da78 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3d9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3da.png b/twake/frontend/public/public/emojione/64/1f3da.png new file mode 100644 index 00000000..81e50e34 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3da.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3db.png b/twake/frontend/public/public/emojione/64/1f3db.png new file mode 100644 index 00000000..d954b73b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3db.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3dc.png b/twake/frontend/public/public/emojione/64/1f3dc.png new file mode 100644 index 00000000..60e10786 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3dc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3dd.png b/twake/frontend/public/public/emojione/64/1f3dd.png new file mode 100644 index 00000000..5a1ffdd8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3dd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3de.png b/twake/frontend/public/public/emojione/64/1f3de.png new file mode 100644 index 00000000..2e973353 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3de.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3df.png b/twake/frontend/public/public/emojione/64/1f3df.png new file mode 100644 index 00000000..4ec5827a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3df.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3e0.png b/twake/frontend/public/public/emojione/64/1f3e0.png new file mode 100644 index 00000000..f89ed698 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3e0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3e1.png b/twake/frontend/public/public/emojione/64/1f3e1.png new file mode 100644 index 00000000..b77852ae Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3e1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3e2.png b/twake/frontend/public/public/emojione/64/1f3e2.png new file mode 100644 index 00000000..360e67e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3e2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3e3.png b/twake/frontend/public/public/emojione/64/1f3e3.png new file mode 100644 index 00000000..783e988b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3e3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3e4.png b/twake/frontend/public/public/emojione/64/1f3e4.png new file mode 100644 index 00000000..7b22e63b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3e4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3e5.png b/twake/frontend/public/public/emojione/64/1f3e5.png new file mode 100644 index 00000000..e25cb725 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3e5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3e6.png b/twake/frontend/public/public/emojione/64/1f3e6.png new file mode 100644 index 00000000..6d49868c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3e7.png b/twake/frontend/public/public/emojione/64/1f3e7.png new file mode 100644 index 00000000..b7ec3856 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3e7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3e8.png b/twake/frontend/public/public/emojione/64/1f3e8.png new file mode 100644 index 00000000..0300a157 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3e8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3e9.png b/twake/frontend/public/public/emojione/64/1f3e9.png new file mode 100644 index 00000000..ca88759e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3e9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ea.png b/twake/frontend/public/public/emojione/64/1f3ea.png new file mode 100644 index 00000000..a4419118 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3eb.png b/twake/frontend/public/public/emojione/64/1f3eb.png new file mode 100644 index 00000000..afd09f43 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ec.png b/twake/frontend/public/public/emojione/64/1f3ec.png new file mode 100644 index 00000000..8f24d03b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ed.png b/twake/frontend/public/public/emojione/64/1f3ed.png new file mode 100644 index 00000000..643b0553 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ee.png b/twake/frontend/public/public/emojione/64/1f3ee.png new file mode 100644 index 00000000..b958aed6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ee.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ef.png b/twake/frontend/public/public/emojione/64/1f3ef.png new file mode 100644 index 00000000..6aabedd9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ef.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3f0.png b/twake/frontend/public/public/emojione/64/1f3f0.png new file mode 100644 index 00000000..98d308d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3f0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3f3-1f308.png b/twake/frontend/public/public/emojione/64/1f3f3-1f308.png new file mode 100644 index 00000000..a8d5ffb0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3f3-1f308.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3f3.png b/twake/frontend/public/public/emojione/64/1f3f3.png new file mode 100644 index 00000000..ccc262a6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3f4-2620.png b/twake/frontend/public/public/emojione/64/1f3f4-2620.png new file mode 100644 index 00000000..04241487 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3f4-2620.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png b/twake/frontend/public/public/emojione/64/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png new file mode 100644 index 00000000..538b8726 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png b/twake/frontend/public/public/emojione/64/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png new file mode 100644 index 00000000..5c2ab267 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png b/twake/frontend/public/public/emojione/64/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png new file mode 100644 index 00000000..7e18555f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3f4.png b/twake/frontend/public/public/emojione/64/1f3f4.png new file mode 100644 index 00000000..8ca8515e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3f4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3f5.png b/twake/frontend/public/public/emojione/64/1f3f5.png new file mode 100644 index 00000000..eeffed9d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3f5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3f7.png b/twake/frontend/public/public/emojione/64/1f3f7.png new file mode 100644 index 00000000..23bcfc45 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3f8.png b/twake/frontend/public/public/emojione/64/1f3f8.png new file mode 100644 index 00000000..4a2b63fa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3f8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3f9.png b/twake/frontend/public/public/emojione/64/1f3f9.png new file mode 100644 index 00000000..8796c528 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3f9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3fa.png b/twake/frontend/public/public/emojione/64/1f3fa.png new file mode 100644 index 00000000..67ef3acf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3fa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3fb.png b/twake/frontend/public/public/emojione/64/1f3fb.png new file mode 100644 index 00000000..2cbaed12 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3fc.png b/twake/frontend/public/public/emojione/64/1f3fc.png new file mode 100644 index 00000000..854f24db Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3fd.png b/twake/frontend/public/public/emojione/64/1f3fd.png new file mode 100644 index 00000000..bb14dd1e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3fe.png b/twake/frontend/public/public/emojione/64/1f3fe.png new file mode 100644 index 00000000..a87efe5b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f3ff.png b/twake/frontend/public/public/emojione/64/1f3ff.png new file mode 100644 index 00000000..765eb1ec Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f400.png b/twake/frontend/public/public/emojione/64/1f400.png new file mode 100644 index 00000000..fad632e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f400.png differ diff --git a/twake/frontend/public/public/emojione/64/1f401.png b/twake/frontend/public/public/emojione/64/1f401.png new file mode 100644 index 00000000..3eedbe11 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f401.png differ diff --git a/twake/frontend/public/public/emojione/64/1f402.png b/twake/frontend/public/public/emojione/64/1f402.png new file mode 100644 index 00000000..f6f9ef40 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f402.png differ diff --git a/twake/frontend/public/public/emojione/64/1f403.png b/twake/frontend/public/public/emojione/64/1f403.png new file mode 100644 index 00000000..8a04f817 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f403.png differ diff --git a/twake/frontend/public/public/emojione/64/1f404.png b/twake/frontend/public/public/emojione/64/1f404.png new file mode 100644 index 00000000..10ccce98 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f404.png differ diff --git a/twake/frontend/public/public/emojione/64/1f405.png b/twake/frontend/public/public/emojione/64/1f405.png new file mode 100644 index 00000000..89f7f574 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f405.png differ diff --git a/twake/frontend/public/public/emojione/64/1f406.png b/twake/frontend/public/public/emojione/64/1f406.png new file mode 100644 index 00000000..5a459260 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f406.png differ diff --git a/twake/frontend/public/public/emojione/64/1f407.png b/twake/frontend/public/public/emojione/64/1f407.png new file mode 100644 index 00000000..0d6fe3a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f407.png differ diff --git a/twake/frontend/public/public/emojione/64/1f408.png b/twake/frontend/public/public/emojione/64/1f408.png new file mode 100644 index 00000000..ebf02517 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f408.png differ diff --git a/twake/frontend/public/public/emojione/64/1f409.png b/twake/frontend/public/public/emojione/64/1f409.png new file mode 100644 index 00000000..fa8801f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f409.png differ diff --git a/twake/frontend/public/public/emojione/64/1f40a.png b/twake/frontend/public/public/emojione/64/1f40a.png new file mode 100644 index 00000000..e24d0cbe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f40a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f40b.png b/twake/frontend/public/public/emojione/64/1f40b.png new file mode 100644 index 00000000..e5632def Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f40b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f40c.png b/twake/frontend/public/public/emojione/64/1f40c.png new file mode 100644 index 00000000..d5e4d624 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f40c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f40d.png b/twake/frontend/public/public/emojione/64/1f40d.png new file mode 100644 index 00000000..bb3c6839 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f40d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f40e.png b/twake/frontend/public/public/emojione/64/1f40e.png new file mode 100644 index 00000000..050e79ab Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f40e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f40f.png b/twake/frontend/public/public/emojione/64/1f40f.png new file mode 100644 index 00000000..a255e7be Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f40f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f410.png b/twake/frontend/public/public/emojione/64/1f410.png new file mode 100644 index 00000000..5a33e504 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f410.png differ diff --git a/twake/frontend/public/public/emojione/64/1f411.png b/twake/frontend/public/public/emojione/64/1f411.png new file mode 100644 index 00000000..16ee72c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f411.png differ diff --git a/twake/frontend/public/public/emojione/64/1f412.png b/twake/frontend/public/public/emojione/64/1f412.png new file mode 100644 index 00000000..657f40bd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f412.png differ diff --git a/twake/frontend/public/public/emojione/64/1f413.png b/twake/frontend/public/public/emojione/64/1f413.png new file mode 100644 index 00000000..eee6dd99 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f413.png differ diff --git a/twake/frontend/public/public/emojione/64/1f414.png b/twake/frontend/public/public/emojione/64/1f414.png new file mode 100644 index 00000000..b2bf6460 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f414.png differ diff --git a/twake/frontend/public/public/emojione/64/1f415.png b/twake/frontend/public/public/emojione/64/1f415.png new file mode 100644 index 00000000..3c2cc2e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f415.png differ diff --git a/twake/frontend/public/public/emojione/64/1f416.png b/twake/frontend/public/public/emojione/64/1f416.png new file mode 100644 index 00000000..5247d0c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f416.png differ diff --git a/twake/frontend/public/public/emojione/64/1f417.png b/twake/frontend/public/public/emojione/64/1f417.png new file mode 100644 index 00000000..ba371229 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f417.png differ diff --git a/twake/frontend/public/public/emojione/64/1f418.png b/twake/frontend/public/public/emojione/64/1f418.png new file mode 100644 index 00000000..0e34926d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f418.png differ diff --git a/twake/frontend/public/public/emojione/64/1f419.png b/twake/frontend/public/public/emojione/64/1f419.png new file mode 100644 index 00000000..db9d02be Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f419.png differ diff --git a/twake/frontend/public/public/emojione/64/1f41a.png b/twake/frontend/public/public/emojione/64/1f41a.png new file mode 100644 index 00000000..575a4783 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f41a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f41b.png b/twake/frontend/public/public/emojione/64/1f41b.png new file mode 100644 index 00000000..9bf89a82 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f41b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f41c.png b/twake/frontend/public/public/emojione/64/1f41c.png new file mode 100644 index 00000000..96464448 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f41c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f41d.png b/twake/frontend/public/public/emojione/64/1f41d.png new file mode 100644 index 00000000..905088af Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f41d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f41e.png b/twake/frontend/public/public/emojione/64/1f41e.png new file mode 100644 index 00000000..b3dc599a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f41e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f41f.png b/twake/frontend/public/public/emojione/64/1f41f.png new file mode 100644 index 00000000..dd3016ad Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f41f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f420.png b/twake/frontend/public/public/emojione/64/1f420.png new file mode 100644 index 00000000..2cc866a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f420.png differ diff --git a/twake/frontend/public/public/emojione/64/1f421.png b/twake/frontend/public/public/emojione/64/1f421.png new file mode 100644 index 00000000..708559c4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f421.png differ diff --git a/twake/frontend/public/public/emojione/64/1f422.png b/twake/frontend/public/public/emojione/64/1f422.png new file mode 100644 index 00000000..f25afc87 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f422.png differ diff --git a/twake/frontend/public/public/emojione/64/1f423.png b/twake/frontend/public/public/emojione/64/1f423.png new file mode 100644 index 00000000..e6e67bd1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f423.png differ diff --git a/twake/frontend/public/public/emojione/64/1f424.png b/twake/frontend/public/public/emojione/64/1f424.png new file mode 100644 index 00000000..b5ddacec Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f424.png differ diff --git a/twake/frontend/public/public/emojione/64/1f425.png b/twake/frontend/public/public/emojione/64/1f425.png new file mode 100644 index 00000000..2059ff8c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f425.png differ diff --git a/twake/frontend/public/public/emojione/64/1f426.png b/twake/frontend/public/public/emojione/64/1f426.png new file mode 100644 index 00000000..27f6f7c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f426.png differ diff --git a/twake/frontend/public/public/emojione/64/1f427.png b/twake/frontend/public/public/emojione/64/1f427.png new file mode 100644 index 00000000..1f027dbe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f427.png differ diff --git a/twake/frontend/public/public/emojione/64/1f428.png b/twake/frontend/public/public/emojione/64/1f428.png new file mode 100644 index 00000000..564c3d9f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f428.png differ diff --git a/twake/frontend/public/public/emojione/64/1f429.png b/twake/frontend/public/public/emojione/64/1f429.png new file mode 100644 index 00000000..b3c26fb0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f429.png differ diff --git a/twake/frontend/public/public/emojione/64/1f42a.png b/twake/frontend/public/public/emojione/64/1f42a.png new file mode 100644 index 00000000..f11bdbaa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f42a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f42b.png b/twake/frontend/public/public/emojione/64/1f42b.png new file mode 100644 index 00000000..73057e4a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f42b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f42c.png b/twake/frontend/public/public/emojione/64/1f42c.png new file mode 100644 index 00000000..f8de6958 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f42c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f42d.png b/twake/frontend/public/public/emojione/64/1f42d.png new file mode 100644 index 00000000..f0e51040 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f42d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f42e.png b/twake/frontend/public/public/emojione/64/1f42e.png new file mode 100644 index 00000000..880cf514 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f42e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f42f.png b/twake/frontend/public/public/emojione/64/1f42f.png new file mode 100644 index 00000000..5cabe0ee Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f42f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f430.png b/twake/frontend/public/public/emojione/64/1f430.png new file mode 100644 index 00000000..5f64eb5e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f430.png differ diff --git a/twake/frontend/public/public/emojione/64/1f431.png b/twake/frontend/public/public/emojione/64/1f431.png new file mode 100644 index 00000000..f40a085c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f431.png differ diff --git a/twake/frontend/public/public/emojione/64/1f432.png b/twake/frontend/public/public/emojione/64/1f432.png new file mode 100644 index 00000000..d3aeb667 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f432.png differ diff --git a/twake/frontend/public/public/emojione/64/1f433.png b/twake/frontend/public/public/emojione/64/1f433.png new file mode 100644 index 00000000..05a5e4ac Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f433.png differ diff --git a/twake/frontend/public/public/emojione/64/1f434.png b/twake/frontend/public/public/emojione/64/1f434.png new file mode 100644 index 00000000..feef48ab Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f434.png differ diff --git a/twake/frontend/public/public/emojione/64/1f435.png b/twake/frontend/public/public/emojione/64/1f435.png new file mode 100644 index 00000000..1667fe15 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f435.png differ diff --git a/twake/frontend/public/public/emojione/64/1f436.png b/twake/frontend/public/public/emojione/64/1f436.png new file mode 100644 index 00000000..6184d864 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f436.png differ diff --git a/twake/frontend/public/public/emojione/64/1f437.png b/twake/frontend/public/public/emojione/64/1f437.png new file mode 100644 index 00000000..7f85cfd1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f437.png differ diff --git a/twake/frontend/public/public/emojione/64/1f438.png b/twake/frontend/public/public/emojione/64/1f438.png new file mode 100644 index 00000000..33637971 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f438.png differ diff --git a/twake/frontend/public/public/emojione/64/1f439.png b/twake/frontend/public/public/emojione/64/1f439.png new file mode 100644 index 00000000..6527ad28 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f439.png differ diff --git a/twake/frontend/public/public/emojione/64/1f43a.png b/twake/frontend/public/public/emojione/64/1f43a.png new file mode 100644 index 00000000..fd744d77 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f43a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f43b.png b/twake/frontend/public/public/emojione/64/1f43b.png new file mode 100644 index 00000000..6d737b0e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f43b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f43c.png b/twake/frontend/public/public/emojione/64/1f43c.png new file mode 100644 index 00000000..669020e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f43c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f43d.png b/twake/frontend/public/public/emojione/64/1f43d.png new file mode 100644 index 00000000..608717f4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f43d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f43e.png b/twake/frontend/public/public/emojione/64/1f43e.png new file mode 100644 index 00000000..e3675c6b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f43e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f43f.png b/twake/frontend/public/public/emojione/64/1f43f.png new file mode 100644 index 00000000..f38a9505 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f43f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f440.png b/twake/frontend/public/public/emojione/64/1f440.png new file mode 100644 index 00000000..f8f100c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f440.png differ diff --git a/twake/frontend/public/public/emojione/64/1f441-1f5e8.png b/twake/frontend/public/public/emojione/64/1f441-1f5e8.png new file mode 100644 index 00000000..e3370b6d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f441-1f5e8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f441.png b/twake/frontend/public/public/emojione/64/1f441.png new file mode 100644 index 00000000..4971b999 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f441.png differ diff --git a/twake/frontend/public/public/emojione/64/1f442-1f3fb.png b/twake/frontend/public/public/emojione/64/1f442-1f3fb.png new file mode 100644 index 00000000..44d17689 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f442-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f442-1f3fc.png b/twake/frontend/public/public/emojione/64/1f442-1f3fc.png new file mode 100644 index 00000000..b479c9bb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f442-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f442-1f3fd.png b/twake/frontend/public/public/emojione/64/1f442-1f3fd.png new file mode 100644 index 00000000..07388f79 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f442-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f442-1f3fe.png b/twake/frontend/public/public/emojione/64/1f442-1f3fe.png new file mode 100644 index 00000000..23e6dc53 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f442-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f442-1f3ff.png b/twake/frontend/public/public/emojione/64/1f442-1f3ff.png new file mode 100644 index 00000000..876a4386 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f442-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f442.png b/twake/frontend/public/public/emojione/64/1f442.png new file mode 100644 index 00000000..41494d2c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f442.png differ diff --git a/twake/frontend/public/public/emojione/64/1f443-1f3fb.png b/twake/frontend/public/public/emojione/64/1f443-1f3fb.png new file mode 100644 index 00000000..be650e6f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f443-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f443-1f3fc.png b/twake/frontend/public/public/emojione/64/1f443-1f3fc.png new file mode 100644 index 00000000..025edb0b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f443-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f443-1f3fd.png b/twake/frontend/public/public/emojione/64/1f443-1f3fd.png new file mode 100644 index 00000000..22847208 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f443-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f443-1f3fe.png b/twake/frontend/public/public/emojione/64/1f443-1f3fe.png new file mode 100644 index 00000000..71c42b5f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f443-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f443-1f3ff.png b/twake/frontend/public/public/emojione/64/1f443-1f3ff.png new file mode 100644 index 00000000..498cbf98 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f443-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f443.png b/twake/frontend/public/public/emojione/64/1f443.png new file mode 100644 index 00000000..f3eb4545 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f443.png differ diff --git a/twake/frontend/public/public/emojione/64/1f444.png b/twake/frontend/public/public/emojione/64/1f444.png new file mode 100644 index 00000000..5646c862 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f444.png differ diff --git a/twake/frontend/public/public/emojione/64/1f445.png b/twake/frontend/public/public/emojione/64/1f445.png new file mode 100644 index 00000000..2be8f9d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f445.png differ diff --git a/twake/frontend/public/public/emojione/64/1f446-1f3fb.png b/twake/frontend/public/public/emojione/64/1f446-1f3fb.png new file mode 100644 index 00000000..f24891e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f446-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f446-1f3fc.png b/twake/frontend/public/public/emojione/64/1f446-1f3fc.png new file mode 100644 index 00000000..6cea95bf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f446-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f446-1f3fd.png b/twake/frontend/public/public/emojione/64/1f446-1f3fd.png new file mode 100644 index 00000000..8fcc1952 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f446-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f446-1f3fe.png b/twake/frontend/public/public/emojione/64/1f446-1f3fe.png new file mode 100644 index 00000000..b7d8daab Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f446-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f446-1f3ff.png b/twake/frontend/public/public/emojione/64/1f446-1f3ff.png new file mode 100644 index 00000000..a71420d5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f446-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f446.png b/twake/frontend/public/public/emojione/64/1f446.png new file mode 100644 index 00000000..bb4d3d52 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f446.png differ diff --git a/twake/frontend/public/public/emojione/64/1f447-1f3fb.png b/twake/frontend/public/public/emojione/64/1f447-1f3fb.png new file mode 100644 index 00000000..f25dce54 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f447-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f447-1f3fc.png b/twake/frontend/public/public/emojione/64/1f447-1f3fc.png new file mode 100644 index 00000000..20c70db2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f447-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f447-1f3fd.png b/twake/frontend/public/public/emojione/64/1f447-1f3fd.png new file mode 100644 index 00000000..5e293594 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f447-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f447-1f3fe.png b/twake/frontend/public/public/emojione/64/1f447-1f3fe.png new file mode 100644 index 00000000..2ba1f179 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f447-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f447-1f3ff.png b/twake/frontend/public/public/emojione/64/1f447-1f3ff.png new file mode 100644 index 00000000..acd5336c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f447-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f447.png b/twake/frontend/public/public/emojione/64/1f447.png new file mode 100644 index 00000000..f9b3dbfc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f447.png differ diff --git a/twake/frontend/public/public/emojione/64/1f448-1f3fb.png b/twake/frontend/public/public/emojione/64/1f448-1f3fb.png new file mode 100644 index 00000000..0a6abcbc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f448-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f448-1f3fc.png b/twake/frontend/public/public/emojione/64/1f448-1f3fc.png new file mode 100644 index 00000000..faff4d24 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f448-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f448-1f3fd.png b/twake/frontend/public/public/emojione/64/1f448-1f3fd.png new file mode 100644 index 00000000..baeae833 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f448-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f448-1f3fe.png b/twake/frontend/public/public/emojione/64/1f448-1f3fe.png new file mode 100644 index 00000000..5c8311ea Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f448-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f448-1f3ff.png b/twake/frontend/public/public/emojione/64/1f448-1f3ff.png new file mode 100644 index 00000000..b5ef7c66 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f448-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f448.png b/twake/frontend/public/public/emojione/64/1f448.png new file mode 100644 index 00000000..5c5196a2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f448.png differ diff --git a/twake/frontend/public/public/emojione/64/1f449-1f3fb.png b/twake/frontend/public/public/emojione/64/1f449-1f3fb.png new file mode 100644 index 00000000..7d12a639 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f449-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f449-1f3fc.png b/twake/frontend/public/public/emojione/64/1f449-1f3fc.png new file mode 100644 index 00000000..d101b1d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f449-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f449-1f3fd.png b/twake/frontend/public/public/emojione/64/1f449-1f3fd.png new file mode 100644 index 00000000..32d21353 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f449-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f449-1f3fe.png b/twake/frontend/public/public/emojione/64/1f449-1f3fe.png new file mode 100644 index 00000000..116c3c4f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f449-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f449-1f3ff.png b/twake/frontend/public/public/emojione/64/1f449-1f3ff.png new file mode 100644 index 00000000..bd1932e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f449-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f449.png b/twake/frontend/public/public/emojione/64/1f449.png new file mode 100644 index 00000000..7ce16993 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f449.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44a-1f3fb.png b/twake/frontend/public/public/emojione/64/1f44a-1f3fb.png new file mode 100644 index 00000000..1e4e0340 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44a-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44a-1f3fc.png b/twake/frontend/public/public/emojione/64/1f44a-1f3fc.png new file mode 100644 index 00000000..8cdabca3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44a-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44a-1f3fd.png b/twake/frontend/public/public/emojione/64/1f44a-1f3fd.png new file mode 100644 index 00000000..94c267e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44a-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44a-1f3fe.png b/twake/frontend/public/public/emojione/64/1f44a-1f3fe.png new file mode 100644 index 00000000..5ee5d3e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44a-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44a-1f3ff.png b/twake/frontend/public/public/emojione/64/1f44a-1f3ff.png new file mode 100644 index 00000000..132bd33b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44a-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44a.png b/twake/frontend/public/public/emojione/64/1f44a.png new file mode 100644 index 00000000..4f849656 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44b-1f3fb.png b/twake/frontend/public/public/emojione/64/1f44b-1f3fb.png new file mode 100644 index 00000000..06df1ad7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44b-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44b-1f3fc.png b/twake/frontend/public/public/emojione/64/1f44b-1f3fc.png new file mode 100644 index 00000000..490cb953 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44b-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44b-1f3fd.png b/twake/frontend/public/public/emojione/64/1f44b-1f3fd.png new file mode 100644 index 00000000..9d426780 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44b-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44b-1f3fe.png b/twake/frontend/public/public/emojione/64/1f44b-1f3fe.png new file mode 100644 index 00000000..ed2f80f4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44b-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44b-1f3ff.png b/twake/frontend/public/public/emojione/64/1f44b-1f3ff.png new file mode 100644 index 00000000..bd8a2a00 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44b-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44b.png b/twake/frontend/public/public/emojione/64/1f44b.png new file mode 100644 index 00000000..eb4cd8a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44c-1f3fb.png b/twake/frontend/public/public/emojione/64/1f44c-1f3fb.png new file mode 100644 index 00000000..1f8f32e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44c-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44c-1f3fc.png b/twake/frontend/public/public/emojione/64/1f44c-1f3fc.png new file mode 100644 index 00000000..b2f7b9da Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44c-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44c-1f3fd.png b/twake/frontend/public/public/emojione/64/1f44c-1f3fd.png new file mode 100644 index 00000000..d9044ead Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44c-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44c-1f3fe.png b/twake/frontend/public/public/emojione/64/1f44c-1f3fe.png new file mode 100644 index 00000000..2f3e25e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44c-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44c-1f3ff.png b/twake/frontend/public/public/emojione/64/1f44c-1f3ff.png new file mode 100644 index 00000000..39da56a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44c-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44c.png b/twake/frontend/public/public/emojione/64/1f44c.png new file mode 100644 index 00000000..243bc4f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44d-1f3fb.png b/twake/frontend/public/public/emojione/64/1f44d-1f3fb.png new file mode 100644 index 00000000..b156e00c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44d-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44d-1f3fc.png b/twake/frontend/public/public/emojione/64/1f44d-1f3fc.png new file mode 100644 index 00000000..4b8481d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44d-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44d-1f3fd.png b/twake/frontend/public/public/emojione/64/1f44d-1f3fd.png new file mode 100644 index 00000000..28be85d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44d-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44d-1f3fe.png b/twake/frontend/public/public/emojione/64/1f44d-1f3fe.png new file mode 100644 index 00000000..25d3cb33 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44d-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44d-1f3ff.png b/twake/frontend/public/public/emojione/64/1f44d-1f3ff.png new file mode 100644 index 00000000..55f2ba60 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44d-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44d.png b/twake/frontend/public/public/emojione/64/1f44d.png new file mode 100644 index 00000000..e5b7ba7b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44e-1f3fb.png b/twake/frontend/public/public/emojione/64/1f44e-1f3fb.png new file mode 100644 index 00000000..ccfa226f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44e-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44e-1f3fc.png b/twake/frontend/public/public/emojione/64/1f44e-1f3fc.png new file mode 100644 index 00000000..848eff32 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44e-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44e-1f3fd.png b/twake/frontend/public/public/emojione/64/1f44e-1f3fd.png new file mode 100644 index 00000000..c32a0fa8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44e-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44e-1f3fe.png b/twake/frontend/public/public/emojione/64/1f44e-1f3fe.png new file mode 100644 index 00000000..e9b8ae30 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44e-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44e-1f3ff.png b/twake/frontend/public/public/emojione/64/1f44e-1f3ff.png new file mode 100644 index 00000000..fc2beb9b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44e-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44e.png b/twake/frontend/public/public/emojione/64/1f44e.png new file mode 100644 index 00000000..3660aac6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44f-1f3fb.png b/twake/frontend/public/public/emojione/64/1f44f-1f3fb.png new file mode 100644 index 00000000..af0de621 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44f-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44f-1f3fc.png b/twake/frontend/public/public/emojione/64/1f44f-1f3fc.png new file mode 100644 index 00000000..d1fda24f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44f-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44f-1f3fd.png b/twake/frontend/public/public/emojione/64/1f44f-1f3fd.png new file mode 100644 index 00000000..ef2cb96d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44f-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44f-1f3fe.png b/twake/frontend/public/public/emojione/64/1f44f-1f3fe.png new file mode 100644 index 00000000..cde57a92 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44f-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44f-1f3ff.png b/twake/frontend/public/public/emojione/64/1f44f-1f3ff.png new file mode 100644 index 00000000..f8f1015e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44f-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f44f.png b/twake/frontend/public/public/emojione/64/1f44f.png new file mode 100644 index 00000000..104e5c94 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f44f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f450-1f3fb.png b/twake/frontend/public/public/emojione/64/1f450-1f3fb.png new file mode 100644 index 00000000..1beb79b6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f450-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f450-1f3fc.png b/twake/frontend/public/public/emojione/64/1f450-1f3fc.png new file mode 100644 index 00000000..bcdbd224 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f450-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f450-1f3fd.png b/twake/frontend/public/public/emojione/64/1f450-1f3fd.png new file mode 100644 index 00000000..322f5701 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f450-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f450-1f3fe.png b/twake/frontend/public/public/emojione/64/1f450-1f3fe.png new file mode 100644 index 00000000..630d6e42 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f450-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f450-1f3ff.png b/twake/frontend/public/public/emojione/64/1f450-1f3ff.png new file mode 100644 index 00000000..aaa28695 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f450-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f450.png b/twake/frontend/public/public/emojione/64/1f450.png new file mode 100644 index 00000000..d9b1c481 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f450.png differ diff --git a/twake/frontend/public/public/emojione/64/1f451.png b/twake/frontend/public/public/emojione/64/1f451.png new file mode 100644 index 00000000..4aa1b07e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f451.png differ diff --git a/twake/frontend/public/public/emojione/64/1f452.png b/twake/frontend/public/public/emojione/64/1f452.png new file mode 100644 index 00000000..b063fa0c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f452.png differ diff --git a/twake/frontend/public/public/emojione/64/1f453.png b/twake/frontend/public/public/emojione/64/1f453.png new file mode 100644 index 00000000..51da0469 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f453.png differ diff --git a/twake/frontend/public/public/emojione/64/1f454.png b/twake/frontend/public/public/emojione/64/1f454.png new file mode 100644 index 00000000..4fa7f0c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f454.png differ diff --git a/twake/frontend/public/public/emojione/64/1f455.png b/twake/frontend/public/public/emojione/64/1f455.png new file mode 100644 index 00000000..25b329e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f455.png differ diff --git a/twake/frontend/public/public/emojione/64/1f456.png b/twake/frontend/public/public/emojione/64/1f456.png new file mode 100644 index 00000000..4cc62264 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f456.png differ diff --git a/twake/frontend/public/public/emojione/64/1f457.png b/twake/frontend/public/public/emojione/64/1f457.png new file mode 100644 index 00000000..ad0c1f43 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f457.png differ diff --git a/twake/frontend/public/public/emojione/64/1f458.png b/twake/frontend/public/public/emojione/64/1f458.png new file mode 100644 index 00000000..441341b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f458.png differ diff --git a/twake/frontend/public/public/emojione/64/1f459.png b/twake/frontend/public/public/emojione/64/1f459.png new file mode 100644 index 00000000..7fc3b636 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f459.png differ diff --git a/twake/frontend/public/public/emojione/64/1f45a.png b/twake/frontend/public/public/emojione/64/1f45a.png new file mode 100644 index 00000000..438f119e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f45a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f45b.png b/twake/frontend/public/public/emojione/64/1f45b.png new file mode 100644 index 00000000..bc934a02 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f45b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f45c.png b/twake/frontend/public/public/emojione/64/1f45c.png new file mode 100644 index 00000000..5163275e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f45c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f45d.png b/twake/frontend/public/public/emojione/64/1f45d.png new file mode 100644 index 00000000..5e6dce3e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f45d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f45e.png b/twake/frontend/public/public/emojione/64/1f45e.png new file mode 100644 index 00000000..c5eb9497 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f45e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f45f.png b/twake/frontend/public/public/emojione/64/1f45f.png new file mode 100644 index 00000000..cf8d13e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f45f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f460.png b/twake/frontend/public/public/emojione/64/1f460.png new file mode 100644 index 00000000..b0e38a19 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f460.png differ diff --git a/twake/frontend/public/public/emojione/64/1f461.png b/twake/frontend/public/public/emojione/64/1f461.png new file mode 100644 index 00000000..f0049ae3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f461.png differ diff --git a/twake/frontend/public/public/emojione/64/1f462.png b/twake/frontend/public/public/emojione/64/1f462.png new file mode 100644 index 00000000..80dec231 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f462.png differ diff --git a/twake/frontend/public/public/emojione/64/1f463.png b/twake/frontend/public/public/emojione/64/1f463.png new file mode 100644 index 00000000..13e4bcf4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f463.png differ diff --git a/twake/frontend/public/public/emojione/64/1f464.png b/twake/frontend/public/public/emojione/64/1f464.png new file mode 100644 index 00000000..721feaf2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f464.png differ diff --git a/twake/frontend/public/public/emojione/64/1f465.png b/twake/frontend/public/public/emojione/64/1f465.png new file mode 100644 index 00000000..3ba2e021 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f465.png differ diff --git a/twake/frontend/public/public/emojione/64/1f466-1f3fb.png b/twake/frontend/public/public/emojione/64/1f466-1f3fb.png new file mode 100644 index 00000000..0d422ba9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f466-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f466-1f3fc.png b/twake/frontend/public/public/emojione/64/1f466-1f3fc.png new file mode 100644 index 00000000..09333b78 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f466-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f466-1f3fd.png b/twake/frontend/public/public/emojione/64/1f466-1f3fd.png new file mode 100644 index 00000000..34549782 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f466-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f466-1f3fe.png b/twake/frontend/public/public/emojione/64/1f466-1f3fe.png new file mode 100644 index 00000000..2fe5f767 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f466-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f466-1f3ff.png b/twake/frontend/public/public/emojione/64/1f466-1f3ff.png new file mode 100644 index 00000000..ec083354 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f466-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f466.png b/twake/frontend/public/public/emojione/64/1f466.png new file mode 100644 index 00000000..bea1a4ba Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f466.png differ diff --git a/twake/frontend/public/public/emojione/64/1f467-1f3fb.png b/twake/frontend/public/public/emojione/64/1f467-1f3fb.png new file mode 100644 index 00000000..d5b2d804 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f467-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f467-1f3fc.png b/twake/frontend/public/public/emojione/64/1f467-1f3fc.png new file mode 100644 index 00000000..db85a7ac Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f467-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f467-1f3fd.png b/twake/frontend/public/public/emojione/64/1f467-1f3fd.png new file mode 100644 index 00000000..8f335e99 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f467-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f467-1f3fe.png b/twake/frontend/public/public/emojione/64/1f467-1f3fe.png new file mode 100644 index 00000000..46f28844 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f467-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f467-1f3ff.png b/twake/frontend/public/public/emojione/64/1f467-1f3ff.png new file mode 100644 index 00000000..a5940552 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f467-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f467.png b/twake/frontend/public/public/emojione/64/1f467.png new file mode 100644 index 00000000..d062098f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f467.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f33e.png b/twake/frontend/public/public/emojione/64/1f468-1f33e.png new file mode 100644 index 00000000..d4db37de Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f373.png b/twake/frontend/public/public/emojione/64/1f468-1f373.png new file mode 100644 index 00000000..d7929141 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f373.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f393.png b/twake/frontend/public/public/emojione/64/1f468-1f393.png new file mode 100644 index 00000000..84dd2662 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f393.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3a4.png b/twake/frontend/public/public/emojione/64/1f468-1f3a4.png new file mode 100644 index 00000000..041e0b61 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3a8.png b/twake/frontend/public/public/emojione/64/1f468-1f3a8.png new file mode 100644 index 00000000..7d5f04c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3eb.png b/twake/frontend/public/public/emojione/64/1f468-1f3eb.png new file mode 100644 index 00000000..c554da7f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ed.png b/twake/frontend/public/public/emojione/64/1f468-1f3ed.png new file mode 100644 index 00000000..60685d67 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f33e.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f33e.png new file mode 100644 index 00000000..5f559fb8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f373.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f373.png new file mode 100644 index 00000000..c4dca1b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f373.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f393.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f393.png new file mode 100644 index 00000000..50d7004c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f393.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f3a4.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f3a4.png new file mode 100644 index 00000000..a060d876 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f3a8.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f3a8.png new file mode 100644 index 00000000..79544a00 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f3eb.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f3eb.png new file mode 100644 index 00000000..97c358a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f3ed.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f3ed.png new file mode 100644 index 00000000..1b121694 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f4bb.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f4bb.png new file mode 100644 index 00000000..4291f66f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f4bc.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f4bc.png new file mode 100644 index 00000000..0cd34280 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f527.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f527.png new file mode 100644 index 00000000..0e9b70b4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f527.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f52c.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f52c.png new file mode 100644 index 00000000..d95a7e7b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f680.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f680.png new file mode 100644 index 00000000..074e756e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f680.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f692.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f692.png new file mode 100644 index 00000000..c8943121 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f692.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f9b0.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f9b0.png new file mode 100644 index 00000000..057bdb12 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f9b1.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f9b1.png new file mode 100644 index 00000000..854d76d9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f9b2.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f9b2.png new file mode 100644 index 00000000..2953ee1c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f9b3.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f9b3.png new file mode 100644 index 00000000..e5b83159 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-2695.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-2695.png new file mode 100644 index 00000000..ccf550fb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-2695.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-2696.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-2696.png new file mode 100644 index 00000000..d7c71423 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-2696.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb-2708.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb-2708.png new file mode 100644 index 00000000..c3f76057 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb-2708.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fb.png b/twake/frontend/public/public/emojione/64/1f468-1f3fb.png new file mode 100644 index 00000000..76c8c40d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f33e.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f33e.png new file mode 100644 index 00000000..2ba70d64 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f373.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f373.png new file mode 100644 index 00000000..0c9b8088 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f373.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f393.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f393.png new file mode 100644 index 00000000..c69bea43 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f393.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f3a4.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f3a4.png new file mode 100644 index 00000000..3541325c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f3a8.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f3a8.png new file mode 100644 index 00000000..a5966c36 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f3eb.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f3eb.png new file mode 100644 index 00000000..ce1dd31e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f3ed.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f3ed.png new file mode 100644 index 00000000..ab462aa7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f4bb.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f4bb.png new file mode 100644 index 00000000..fb839e3e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f4bc.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f4bc.png new file mode 100644 index 00000000..4979d897 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f527.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f527.png new file mode 100644 index 00000000..4a47c084 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f527.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f52c.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f52c.png new file mode 100644 index 00000000..aa254ef3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f680.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f680.png new file mode 100644 index 00000000..fce95f50 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f680.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f692.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f692.png new file mode 100644 index 00000000..d7bde548 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f692.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f9b0.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f9b0.png new file mode 100644 index 00000000..3bedd839 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f9b1.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f9b1.png new file mode 100644 index 00000000..4cdb3d87 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f9b2.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f9b2.png new file mode 100644 index 00000000..e328e006 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f9b3.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f9b3.png new file mode 100644 index 00000000..7935c2c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-2695.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-2695.png new file mode 100644 index 00000000..a0bae43f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-2695.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-2696.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-2696.png new file mode 100644 index 00000000..f94340d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-2696.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc-2708.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc-2708.png new file mode 100644 index 00000000..69fe5e71 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc-2708.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fc.png b/twake/frontend/public/public/emojione/64/1f468-1f3fc.png new file mode 100644 index 00000000..53d58ef6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f33e.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f33e.png new file mode 100644 index 00000000..494567d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f373.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f373.png new file mode 100644 index 00000000..7c6159ec Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f373.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f393.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f393.png new file mode 100644 index 00000000..6a1c0976 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f393.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f3a4.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f3a4.png new file mode 100644 index 00000000..8f947e0d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f3a8.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f3a8.png new file mode 100644 index 00000000..c3ac1159 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f3eb.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f3eb.png new file mode 100644 index 00000000..dafa090d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f3ed.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f3ed.png new file mode 100644 index 00000000..4b11cc47 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f4bb.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f4bb.png new file mode 100644 index 00000000..5cad2e92 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f4bc.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f4bc.png new file mode 100644 index 00000000..a2965fa4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f527.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f527.png new file mode 100644 index 00000000..3af687bd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f527.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f52c.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f52c.png new file mode 100644 index 00000000..5f03c227 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f680.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f680.png new file mode 100644 index 00000000..79d65e8c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f680.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f692.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f692.png new file mode 100644 index 00000000..60ad91d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f692.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f9b0.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f9b0.png new file mode 100644 index 00000000..fcd2578c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f9b1.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f9b1.png new file mode 100644 index 00000000..4a27e54e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f9b2.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f9b2.png new file mode 100644 index 00000000..a3eae531 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f9b3.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f9b3.png new file mode 100644 index 00000000..b4245ef0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-2695.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-2695.png new file mode 100644 index 00000000..aded8595 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-2695.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-2696.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-2696.png new file mode 100644 index 00000000..ecd146b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-2696.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd-2708.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd-2708.png new file mode 100644 index 00000000..299b7961 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd-2708.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fd.png b/twake/frontend/public/public/emojione/64/1f468-1f3fd.png new file mode 100644 index 00000000..a51ecb21 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f33e.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f33e.png new file mode 100644 index 00000000..a98528e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f373.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f373.png new file mode 100644 index 00000000..2ccf401e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f373.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f393.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f393.png new file mode 100644 index 00000000..942964a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f393.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f3a4.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f3a4.png new file mode 100644 index 00000000..12e67954 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f3a8.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f3a8.png new file mode 100644 index 00000000..e226368e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f3eb.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f3eb.png new file mode 100644 index 00000000..3f0e6a1f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f3ed.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f3ed.png new file mode 100644 index 00000000..1b5b6be3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f4bb.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f4bb.png new file mode 100644 index 00000000..c97f3f7d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f4bc.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f4bc.png new file mode 100644 index 00000000..37a30a5c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f527.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f527.png new file mode 100644 index 00000000..a9d8f4da Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f527.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f52c.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f52c.png new file mode 100644 index 00000000..3304bfb6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f680.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f680.png new file mode 100644 index 00000000..91375d6e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f680.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f692.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f692.png new file mode 100644 index 00000000..5f92ff9d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f692.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f9b0.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f9b0.png new file mode 100644 index 00000000..473d5600 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f9b1.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f9b1.png new file mode 100644 index 00000000..5f1d0cdf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f9b2.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f9b2.png new file mode 100644 index 00000000..464ff0a5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f9b3.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f9b3.png new file mode 100644 index 00000000..85668934 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-2695.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-2695.png new file mode 100644 index 00000000..11cea1e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-2695.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-2696.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-2696.png new file mode 100644 index 00000000..c1b8fe6d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-2696.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe-2708.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe-2708.png new file mode 100644 index 00000000..1edafe4f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe-2708.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3fe.png b/twake/frontend/public/public/emojione/64/1f468-1f3fe.png new file mode 100644 index 00000000..5c137f34 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f33e.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f33e.png new file mode 100644 index 00000000..5355fe9d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f373.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f373.png new file mode 100644 index 00000000..a019a331 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f373.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f393.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f393.png new file mode 100644 index 00000000..68f89787 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f393.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f3a4.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f3a4.png new file mode 100644 index 00000000..d4a023e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f3a8.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f3a8.png new file mode 100644 index 00000000..8ac02199 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f3eb.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f3eb.png new file mode 100644 index 00000000..124f2649 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f3ed.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f3ed.png new file mode 100644 index 00000000..271545fa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f4bb.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f4bb.png new file mode 100644 index 00000000..a0647bd6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f4bc.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f4bc.png new file mode 100644 index 00000000..594b062e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f527.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f527.png new file mode 100644 index 00000000..c6675754 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f527.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f52c.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f52c.png new file mode 100644 index 00000000..f22ca348 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f680.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f680.png new file mode 100644 index 00000000..6d1c8b7f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f680.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f692.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f692.png new file mode 100644 index 00000000..3deecbff Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f692.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f9b0.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f9b0.png new file mode 100644 index 00000000..93733ce3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f9b1.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f9b1.png new file mode 100644 index 00000000..af487c03 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f9b2.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f9b2.png new file mode 100644 index 00000000..8f3a7358 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f9b3.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f9b3.png new file mode 100644 index 00000000..9391e348 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-2695.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-2695.png new file mode 100644 index 00000000..f7ff74e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-2695.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-2696.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-2696.png new file mode 100644 index 00000000..bc0f64d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-2696.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff-2708.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff-2708.png new file mode 100644 index 00000000..f4b8ca81 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff-2708.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f3ff.png b/twake/frontend/public/public/emojione/64/1f468-1f3ff.png new file mode 100644 index 00000000..4e12eb86 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f466-1f466.png b/twake/frontend/public/public/emojione/64/1f468-1f466-1f466.png new file mode 100644 index 00000000..92f19175 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f466-1f466.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f466.png b/twake/frontend/public/public/emojione/64/1f468-1f466.png new file mode 100644 index 00000000..4f92ca0f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f466.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f467-1f466.png b/twake/frontend/public/public/emojione/64/1f468-1f467-1f466.png new file mode 100644 index 00000000..31db9370 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f467-1f466.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f467-1f467.png b/twake/frontend/public/public/emojione/64/1f468-1f467-1f467.png new file mode 100644 index 00000000..e78c4284 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f467-1f467.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f467.png b/twake/frontend/public/public/emojione/64/1f468-1f467.png new file mode 100644 index 00000000..c5062f90 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f467.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f468-1f466-1f466.png b/twake/frontend/public/public/emojione/64/1f468-1f468-1f466-1f466.png new file mode 100644 index 00000000..5de5a132 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f468-1f466-1f466.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f468-1f466.png b/twake/frontend/public/public/emojione/64/1f468-1f468-1f466.png new file mode 100644 index 00000000..736094d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f468-1f466.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f468-1f467-1f466.png b/twake/frontend/public/public/emojione/64/1f468-1f468-1f467-1f466.png new file mode 100644 index 00000000..13f4f8ef Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f468-1f467-1f466.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f468-1f467-1f467.png b/twake/frontend/public/public/emojione/64/1f468-1f468-1f467-1f467.png new file mode 100644 index 00000000..7df96c56 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f468-1f467-1f467.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f468-1f467.png b/twake/frontend/public/public/emojione/64/1f468-1f468-1f467.png new file mode 100644 index 00000000..38f1cf13 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f468-1f467.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f469-1f466-1f466.png b/twake/frontend/public/public/emojione/64/1f468-1f469-1f466-1f466.png new file mode 100644 index 00000000..385191d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f469-1f466-1f466.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f469-1f466.png b/twake/frontend/public/public/emojione/64/1f468-1f469-1f466.png new file mode 100644 index 00000000..5bb53a29 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f469-1f466.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f469-1f467-1f466.png b/twake/frontend/public/public/emojione/64/1f468-1f469-1f467-1f466.png new file mode 100644 index 00000000..62830a34 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f469-1f467-1f466.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f469-1f467-1f467.png b/twake/frontend/public/public/emojione/64/1f468-1f469-1f467-1f467.png new file mode 100644 index 00000000..0c877885 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f469-1f467-1f467.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f469-1f467.png b/twake/frontend/public/public/emojione/64/1f468-1f469-1f467.png new file mode 100644 index 00000000..ac4b7b52 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f469-1f467.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f4bb.png b/twake/frontend/public/public/emojione/64/1f468-1f4bb.png new file mode 100644 index 00000000..ad29e6b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f4bc.png b/twake/frontend/public/public/emojione/64/1f468-1f4bc.png new file mode 100644 index 00000000..7addc813 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f527.png b/twake/frontend/public/public/emojione/64/1f468-1f527.png new file mode 100644 index 00000000..414e2209 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f527.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f52c.png b/twake/frontend/public/public/emojione/64/1f468-1f52c.png new file mode 100644 index 00000000..43e34632 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f680.png b/twake/frontend/public/public/emojione/64/1f468-1f680.png new file mode 100644 index 00000000..695a8504 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f680.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f692.png b/twake/frontend/public/public/emojione/64/1f468-1f692.png new file mode 100644 index 00000000..d13ac45e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f692.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f9b0.png b/twake/frontend/public/public/emojione/64/1f468-1f9b0.png new file mode 100644 index 00000000..7e656a5c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f9b1.png b/twake/frontend/public/public/emojione/64/1f468-1f9b1.png new file mode 100644 index 00000000..0cfb6f22 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f9b2.png b/twake/frontend/public/public/emojione/64/1f468-1f9b2.png new file mode 100644 index 00000000..46448086 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-1f9b3.png b/twake/frontend/public/public/emojione/64/1f468-1f9b3.png new file mode 100644 index 00000000..54566194 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-2695.png b/twake/frontend/public/public/emojione/64/1f468-2695.png new file mode 100644 index 00000000..e61b4f1f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-2695.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-2696.png b/twake/frontend/public/public/emojione/64/1f468-2696.png new file mode 100644 index 00000000..002a0786 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-2696.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-2708.png b/twake/frontend/public/public/emojione/64/1f468-2708.png new file mode 100644 index 00000000..4b8d83ee Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-2708.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-2764-1f468.png b/twake/frontend/public/public/emojione/64/1f468-2764-1f468.png new file mode 100644 index 00000000..f41ffe29 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-2764-1f468.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468-2764-1f48b-1f468.png b/twake/frontend/public/public/emojione/64/1f468-2764-1f48b-1f468.png new file mode 100644 index 00000000..7902cfcf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468-2764-1f48b-1f468.png differ diff --git a/twake/frontend/public/public/emojione/64/1f468.png b/twake/frontend/public/public/emojione/64/1f468.png new file mode 100644 index 00000000..33f2f501 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f468.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f33e.png b/twake/frontend/public/public/emojione/64/1f469-1f33e.png new file mode 100644 index 00000000..e475c7cd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f373.png b/twake/frontend/public/public/emojione/64/1f469-1f373.png new file mode 100644 index 00000000..f1fe65e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f373.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f393.png b/twake/frontend/public/public/emojione/64/1f469-1f393.png new file mode 100644 index 00000000..e5399b48 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f393.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3a4.png b/twake/frontend/public/public/emojione/64/1f469-1f3a4.png new file mode 100644 index 00000000..afa4ec67 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3a8.png b/twake/frontend/public/public/emojione/64/1f469-1f3a8.png new file mode 100644 index 00000000..4039df5c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3eb.png b/twake/frontend/public/public/emojione/64/1f469-1f3eb.png new file mode 100644 index 00000000..139ece59 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ed.png b/twake/frontend/public/public/emojione/64/1f469-1f3ed.png new file mode 100644 index 00000000..5a48d1f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f33e.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f33e.png new file mode 100644 index 00000000..b3f8cef7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f373.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f373.png new file mode 100644 index 00000000..c80fd223 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f373.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f393.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f393.png new file mode 100644 index 00000000..ae855641 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f393.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f3a4.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f3a4.png new file mode 100644 index 00000000..6937e7f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f3a8.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f3a8.png new file mode 100644 index 00000000..0be1edd3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f3eb.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f3eb.png new file mode 100644 index 00000000..8f11e021 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f3ed.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f3ed.png new file mode 100644 index 00000000..40c0b6b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f4bb.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f4bb.png new file mode 100644 index 00000000..144cd2e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f4bc.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f4bc.png new file mode 100644 index 00000000..d8ffdb30 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f527.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f527.png new file mode 100644 index 00000000..e4c524b6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f527.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f52c.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f52c.png new file mode 100644 index 00000000..aaf53baf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f680.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f680.png new file mode 100644 index 00000000..6f46c06e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f680.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f692.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f692.png new file mode 100644 index 00000000..bba82f55 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f692.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f9b0.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f9b0.png new file mode 100644 index 00000000..f4c7e56f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f9b1.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f9b1.png new file mode 100644 index 00000000..975421e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f9b2.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f9b2.png new file mode 100644 index 00000000..ca3f1fc2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f9b3.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f9b3.png new file mode 100644 index 00000000..dd0e0e0a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-2695.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-2695.png new file mode 100644 index 00000000..41cb5f2a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-2695.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-2696.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-2696.png new file mode 100644 index 00000000..ac393233 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-2696.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb-2708.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb-2708.png new file mode 100644 index 00000000..613d5433 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb-2708.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fb.png b/twake/frontend/public/public/emojione/64/1f469-1f3fb.png new file mode 100644 index 00000000..6d140dca Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f33e.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f33e.png new file mode 100644 index 00000000..66411354 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f373.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f373.png new file mode 100644 index 00000000..e8a1976d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f373.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f393.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f393.png new file mode 100644 index 00000000..62fc96f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f393.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f3a4.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f3a4.png new file mode 100644 index 00000000..1b655dc1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f3a8.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f3a8.png new file mode 100644 index 00000000..3382cd9a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f3eb.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f3eb.png new file mode 100644 index 00000000..e58914e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f3ed.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f3ed.png new file mode 100644 index 00000000..252617da Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f4bb.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f4bb.png new file mode 100644 index 00000000..3258ed4f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f4bc.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f4bc.png new file mode 100644 index 00000000..4ac02eb4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f527.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f527.png new file mode 100644 index 00000000..aa4ad803 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f527.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f52c.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f52c.png new file mode 100644 index 00000000..aefb924a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f680.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f680.png new file mode 100644 index 00000000..2688d7a1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f680.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f692.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f692.png new file mode 100644 index 00000000..2332e6bd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f692.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f9b0.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f9b0.png new file mode 100644 index 00000000..4823c304 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f9b1.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f9b1.png new file mode 100644 index 00000000..46d74d89 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f9b2.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f9b2.png new file mode 100644 index 00000000..78d6ec3e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f9b3.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f9b3.png new file mode 100644 index 00000000..28e4fede Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-2695.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-2695.png new file mode 100644 index 00000000..2d2a6cf8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-2695.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-2696.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-2696.png new file mode 100644 index 00000000..3edaf03d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-2696.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc-2708.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc-2708.png new file mode 100644 index 00000000..61c127f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc-2708.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fc.png b/twake/frontend/public/public/emojione/64/1f469-1f3fc.png new file mode 100644 index 00000000..6122cbe5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f33e.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f33e.png new file mode 100644 index 00000000..1d4978d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f373.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f373.png new file mode 100644 index 00000000..ff35c4a8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f373.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f393.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f393.png new file mode 100644 index 00000000..a4a5bda6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f393.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f3a4.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f3a4.png new file mode 100644 index 00000000..6d673dc0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f3a8.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f3a8.png new file mode 100644 index 00000000..31d1d701 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f3eb.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f3eb.png new file mode 100644 index 00000000..048c23b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f3ed.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f3ed.png new file mode 100644 index 00000000..326c1b54 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f4bb.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f4bb.png new file mode 100644 index 00000000..bf7025f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f4bc.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f4bc.png new file mode 100644 index 00000000..9e61bd08 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f527.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f527.png new file mode 100644 index 00000000..82572ebd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f527.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f52c.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f52c.png new file mode 100644 index 00000000..437acd37 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f680.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f680.png new file mode 100644 index 00000000..a5280974 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f680.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f692.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f692.png new file mode 100644 index 00000000..1f2d7e67 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f692.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f9b0.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f9b0.png new file mode 100644 index 00000000..74ae6da5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f9b1.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f9b1.png new file mode 100644 index 00000000..6341cca3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f9b2.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f9b2.png new file mode 100644 index 00000000..d0d0e097 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f9b3.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f9b3.png new file mode 100644 index 00000000..94bda3a6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-2695.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-2695.png new file mode 100644 index 00000000..b1ad81e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-2695.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-2696.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-2696.png new file mode 100644 index 00000000..bc9d1176 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-2696.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd-2708.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd-2708.png new file mode 100644 index 00000000..292cfd7e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd-2708.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fd.png b/twake/frontend/public/public/emojione/64/1f469-1f3fd.png new file mode 100644 index 00000000..dee1d83e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f33e.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f33e.png new file mode 100644 index 00000000..0d49e154 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f373.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f373.png new file mode 100644 index 00000000..1b243880 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f373.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f393.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f393.png new file mode 100644 index 00000000..0e0b42f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f393.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f3a4.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f3a4.png new file mode 100644 index 00000000..94adb0ee Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f3a8.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f3a8.png new file mode 100644 index 00000000..13949466 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f3eb.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f3eb.png new file mode 100644 index 00000000..4dfd24a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f3ed.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f3ed.png new file mode 100644 index 00000000..376a43ce Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f4bb.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f4bb.png new file mode 100644 index 00000000..e60a3767 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f4bc.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f4bc.png new file mode 100644 index 00000000..7f9f8f6a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f527.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f527.png new file mode 100644 index 00000000..fd60a054 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f527.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f52c.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f52c.png new file mode 100644 index 00000000..9d71c89a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f680.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f680.png new file mode 100644 index 00000000..3e8c160e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f680.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f692.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f692.png new file mode 100644 index 00000000..3bdbce30 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f692.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f9b0.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f9b0.png new file mode 100644 index 00000000..b4fc32ff Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f9b1.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f9b1.png new file mode 100644 index 00000000..40cccaa4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f9b2.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f9b2.png new file mode 100644 index 00000000..3f10a4bb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f9b3.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f9b3.png new file mode 100644 index 00000000..1fd33b66 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-2695.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-2695.png new file mode 100644 index 00000000..d7814655 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-2695.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-2696.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-2696.png new file mode 100644 index 00000000..6424d7b9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-2696.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe-2708.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe-2708.png new file mode 100644 index 00000000..e40634fa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe-2708.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3fe.png b/twake/frontend/public/public/emojione/64/1f469-1f3fe.png new file mode 100644 index 00000000..1449e7fd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f33e.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f33e.png new file mode 100644 index 00000000..54a74977 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f33e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f373.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f373.png new file mode 100644 index 00000000..12572ae4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f373.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f393.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f393.png new file mode 100644 index 00000000..506ba4df Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f393.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f3a4.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f3a4.png new file mode 100644 index 00000000..aeb0bb17 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f3a4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f3a8.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f3a8.png new file mode 100644 index 00000000..ad81f33b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f3a8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f3eb.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f3eb.png new file mode 100644 index 00000000..1e7e4e7a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f3eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f3ed.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f3ed.png new file mode 100644 index 00000000..4261b032 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f3ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f4bb.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f4bb.png new file mode 100644 index 00000000..b8a1ba44 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f4bc.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f4bc.png new file mode 100644 index 00000000..11815d3d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f527.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f527.png new file mode 100644 index 00000000..7e70250e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f527.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f52c.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f52c.png new file mode 100644 index 00000000..bc699a48 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f680.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f680.png new file mode 100644 index 00000000..7f42f972 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f680.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f692.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f692.png new file mode 100644 index 00000000..5a991228 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f692.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f9b0.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f9b0.png new file mode 100644 index 00000000..994dfea9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f9b1.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f9b1.png new file mode 100644 index 00000000..bbd93137 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f9b2.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f9b2.png new file mode 100644 index 00000000..b2572824 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f9b3.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f9b3.png new file mode 100644 index 00000000..ab807cd4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-2695.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-2695.png new file mode 100644 index 00000000..a6e43142 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-2695.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-2696.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-2696.png new file mode 100644 index 00000000..e949bd6f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-2696.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff-2708.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff-2708.png new file mode 100644 index 00000000..a7fb2af5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff-2708.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f3ff.png b/twake/frontend/public/public/emojione/64/1f469-1f3ff.png new file mode 100644 index 00000000..b3bfa9ab Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f466-1f466.png b/twake/frontend/public/public/emojione/64/1f469-1f466-1f466.png new file mode 100644 index 00000000..25ce2687 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f466-1f466.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f466.png b/twake/frontend/public/public/emojione/64/1f469-1f466.png new file mode 100644 index 00000000..b4d7af9b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f466.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f467-1f466.png b/twake/frontend/public/public/emojione/64/1f469-1f467-1f466.png new file mode 100644 index 00000000..919fbf3a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f467-1f466.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f467-1f467.png b/twake/frontend/public/public/emojione/64/1f469-1f467-1f467.png new file mode 100644 index 00000000..0ab6f853 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f467-1f467.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f467.png b/twake/frontend/public/public/emojione/64/1f469-1f467.png new file mode 100644 index 00000000..37d0419c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f467.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f469-1f466-1f466.png b/twake/frontend/public/public/emojione/64/1f469-1f469-1f466-1f466.png new file mode 100644 index 00000000..c2cef3c9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f469-1f466-1f466.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f469-1f466.png b/twake/frontend/public/public/emojione/64/1f469-1f469-1f466.png new file mode 100644 index 00000000..5dafca68 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f469-1f466.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f469-1f467-1f466.png b/twake/frontend/public/public/emojione/64/1f469-1f469-1f467-1f466.png new file mode 100644 index 00000000..388c8546 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f469-1f467-1f466.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f469-1f467-1f467.png b/twake/frontend/public/public/emojione/64/1f469-1f469-1f467-1f467.png new file mode 100644 index 00000000..f31064be Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f469-1f467-1f467.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f469-1f467.png b/twake/frontend/public/public/emojione/64/1f469-1f469-1f467.png new file mode 100644 index 00000000..4b21b6bd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f469-1f467.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f4bb.png b/twake/frontend/public/public/emojione/64/1f469-1f4bb.png new file mode 100644 index 00000000..a612d005 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f4bc.png b/twake/frontend/public/public/emojione/64/1f469-1f4bc.png new file mode 100644 index 00000000..d3bd287c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f527.png b/twake/frontend/public/public/emojione/64/1f469-1f527.png new file mode 100644 index 00000000..2772c841 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f527.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f52c.png b/twake/frontend/public/public/emojione/64/1f469-1f52c.png new file mode 100644 index 00000000..e1642461 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f52c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f680.png b/twake/frontend/public/public/emojione/64/1f469-1f680.png new file mode 100644 index 00000000..96311760 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f680.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f692.png b/twake/frontend/public/public/emojione/64/1f469-1f692.png new file mode 100644 index 00000000..19a7142b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f692.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f9b0.png b/twake/frontend/public/public/emojione/64/1f469-1f9b0.png new file mode 100644 index 00000000..7d7107bb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f9b1.png b/twake/frontend/public/public/emojione/64/1f469-1f9b1.png new file mode 100644 index 00000000..37a1f2d3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f9b2.png b/twake/frontend/public/public/emojione/64/1f469-1f9b2.png new file mode 100644 index 00000000..c6b195ba Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-1f9b3.png b/twake/frontend/public/public/emojione/64/1f469-1f9b3.png new file mode 100644 index 00000000..b8664351 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-2695.png b/twake/frontend/public/public/emojione/64/1f469-2695.png new file mode 100644 index 00000000..229f5791 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-2695.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-2696.png b/twake/frontend/public/public/emojione/64/1f469-2696.png new file mode 100644 index 00000000..26bc4193 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-2696.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-2708.png b/twake/frontend/public/public/emojione/64/1f469-2708.png new file mode 100644 index 00000000..03ee4965 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-2708.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-2764-1f468.png b/twake/frontend/public/public/emojione/64/1f469-2764-1f468.png new file mode 100644 index 00000000..335cf1c4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-2764-1f468.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-2764-1f469.png b/twake/frontend/public/public/emojione/64/1f469-2764-1f469.png new file mode 100644 index 00000000..ba686a8c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-2764-1f469.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-2764-1f48b-1f468.png b/twake/frontend/public/public/emojione/64/1f469-2764-1f48b-1f468.png new file mode 100644 index 00000000..7450553d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-2764-1f48b-1f468.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469-2764-1f48b-1f469.png b/twake/frontend/public/public/emojione/64/1f469-2764-1f48b-1f469.png new file mode 100644 index 00000000..b445df44 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469-2764-1f48b-1f469.png differ diff --git a/twake/frontend/public/public/emojione/64/1f469.png b/twake/frontend/public/public/emojione/64/1f469.png new file mode 100644 index 00000000..1da14b26 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f469.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46a.png b/twake/frontend/public/public/emojione/64/1f46a.png new file mode 100644 index 00000000..5bb53a29 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46b.png b/twake/frontend/public/public/emojione/64/1f46b.png new file mode 100644 index 00000000..3ed4cd8d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46c.png b/twake/frontend/public/public/emojione/64/1f46c.png new file mode 100644 index 00000000..1f3f4c6f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46d.png b/twake/frontend/public/public/emojione/64/1f46d.png new file mode 100644 index 00000000..8ccca9e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f46e-1f3fb-2640.png new file mode 100644 index 00000000..793b928a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f46e-1f3fb-2642.png new file mode 100644 index 00000000..1d45120d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e-1f3fb.png b/twake/frontend/public/public/emojione/64/1f46e-1f3fb.png new file mode 100644 index 00000000..1d45120d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f46e-1f3fc-2640.png new file mode 100644 index 00000000..7ad36efd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f46e-1f3fc-2642.png new file mode 100644 index 00000000..dfbb38d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e-1f3fc.png b/twake/frontend/public/public/emojione/64/1f46e-1f3fc.png new file mode 100644 index 00000000..dfbb38d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f46e-1f3fd-2640.png new file mode 100644 index 00000000..38b91c7a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f46e-1f3fd-2642.png new file mode 100644 index 00000000..a414ce37 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e-1f3fd.png b/twake/frontend/public/public/emojione/64/1f46e-1f3fd.png new file mode 100644 index 00000000..a414ce37 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f46e-1f3fe-2640.png new file mode 100644 index 00000000..7a809956 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f46e-1f3fe-2642.png new file mode 100644 index 00000000..1d2f2023 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e-1f3fe.png b/twake/frontend/public/public/emojione/64/1f46e-1f3fe.png new file mode 100644 index 00000000..1d2f2023 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f46e-1f3ff-2640.png new file mode 100644 index 00000000..50e78b3d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f46e-1f3ff-2642.png new file mode 100644 index 00000000..44861944 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e-1f3ff.png b/twake/frontend/public/public/emojione/64/1f46e-1f3ff.png new file mode 100644 index 00000000..44861944 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e-2640.png b/twake/frontend/public/public/emojione/64/1f46e-2640.png new file mode 100644 index 00000000..1ec97cbb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e-2642.png b/twake/frontend/public/public/emojione/64/1f46e-2642.png new file mode 100644 index 00000000..510f7ff7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46e.png b/twake/frontend/public/public/emojione/64/1f46e.png new file mode 100644 index 00000000..510f7ff7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46f-2640.png b/twake/frontend/public/public/emojione/64/1f46f-2640.png new file mode 100644 index 00000000..d691f2e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46f-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46f-2642.png b/twake/frontend/public/public/emojione/64/1f46f-2642.png new file mode 100644 index 00000000..41dbd6cc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46f-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f46f.png b/twake/frontend/public/public/emojione/64/1f46f.png new file mode 100644 index 00000000..ef30eb35 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f46f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f470-1f3fb.png b/twake/frontend/public/public/emojione/64/1f470-1f3fb.png new file mode 100644 index 00000000..6abd1c37 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f470-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f470-1f3fc.png b/twake/frontend/public/public/emojione/64/1f470-1f3fc.png new file mode 100644 index 00000000..854f4ed3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f470-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f470-1f3fd.png b/twake/frontend/public/public/emojione/64/1f470-1f3fd.png new file mode 100644 index 00000000..feab8518 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f470-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f470-1f3fe.png b/twake/frontend/public/public/emojione/64/1f470-1f3fe.png new file mode 100644 index 00000000..87585032 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f470-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f470-1f3ff.png b/twake/frontend/public/public/emojione/64/1f470-1f3ff.png new file mode 100644 index 00000000..02ce0f55 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f470-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f470.png b/twake/frontend/public/public/emojione/64/1f470.png new file mode 100644 index 00000000..1596e507 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f470.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f471-1f3fb-2640.png new file mode 100644 index 00000000..41faa531 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f471-1f3fb-2642.png new file mode 100644 index 00000000..7cbf8d4b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471-1f3fb.png b/twake/frontend/public/public/emojione/64/1f471-1f3fb.png new file mode 100644 index 00000000..fc680e92 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f471-1f3fc-2640.png new file mode 100644 index 00000000..c672422f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f471-1f3fc-2642.png new file mode 100644 index 00000000..5ebc6b0a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471-1f3fc.png b/twake/frontend/public/public/emojione/64/1f471-1f3fc.png new file mode 100644 index 00000000..5ebc6b0a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f471-1f3fd-2640.png new file mode 100644 index 00000000..2e25fa66 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f471-1f3fd-2642.png new file mode 100644 index 00000000..5d2b996c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471-1f3fd.png b/twake/frontend/public/public/emojione/64/1f471-1f3fd.png new file mode 100644 index 00000000..c7d63e51 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f471-1f3fe-2640.png new file mode 100644 index 00000000..db1b2d47 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f471-1f3fe-2642.png new file mode 100644 index 00000000..ada70074 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471-1f3fe.png b/twake/frontend/public/public/emojione/64/1f471-1f3fe.png new file mode 100644 index 00000000..75569770 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f471-1f3ff-2640.png new file mode 100644 index 00000000..8a5f9eea Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f471-1f3ff-2642.png new file mode 100644 index 00000000..5b5197ab Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471-1f3ff.png b/twake/frontend/public/public/emojione/64/1f471-1f3ff.png new file mode 100644 index 00000000..f941d6d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471-2640.png b/twake/frontend/public/public/emojione/64/1f471-2640.png new file mode 100644 index 00000000..d2d32622 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471-2642.png b/twake/frontend/public/public/emojione/64/1f471-2642.png new file mode 100644 index 00000000..a74d69d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f471.png b/twake/frontend/public/public/emojione/64/1f471.png new file mode 100644 index 00000000..a74d69d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f471.png differ diff --git a/twake/frontend/public/public/emojione/64/1f472-1f3fb.png b/twake/frontend/public/public/emojione/64/1f472-1f3fb.png new file mode 100644 index 00000000..b26e1a8b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f472-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f472-1f3fc.png b/twake/frontend/public/public/emojione/64/1f472-1f3fc.png new file mode 100644 index 00000000..09dfc496 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f472-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f472-1f3fd.png b/twake/frontend/public/public/emojione/64/1f472-1f3fd.png new file mode 100644 index 00000000..907249c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f472-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f472-1f3fe.png b/twake/frontend/public/public/emojione/64/1f472-1f3fe.png new file mode 100644 index 00000000..2e35e88f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f472-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f472-1f3ff.png b/twake/frontend/public/public/emojione/64/1f472-1f3ff.png new file mode 100644 index 00000000..71825125 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f472-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f472.png b/twake/frontend/public/public/emojione/64/1f472.png new file mode 100644 index 00000000..7f4d58f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f472.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f473-1f3fb-2640.png new file mode 100644 index 00000000..d811a92c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f473-1f3fb-2642.png new file mode 100644 index 00000000..0271c889 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473-1f3fb.png b/twake/frontend/public/public/emojione/64/1f473-1f3fb.png new file mode 100644 index 00000000..0271c889 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f473-1f3fc-2640.png new file mode 100644 index 00000000..823f8416 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f473-1f3fc-2642.png new file mode 100644 index 00000000..856ade65 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473-1f3fc.png b/twake/frontend/public/public/emojione/64/1f473-1f3fc.png new file mode 100644 index 00000000..856ade65 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f473-1f3fd-2640.png new file mode 100644 index 00000000..1a14be38 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f473-1f3fd-2642.png new file mode 100644 index 00000000..8585a511 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473-1f3fd.png b/twake/frontend/public/public/emojione/64/1f473-1f3fd.png new file mode 100644 index 00000000..8585a511 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f473-1f3fe-2640.png new file mode 100644 index 00000000..605e2bc2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f473-1f3fe-2642.png new file mode 100644 index 00000000..bdb5efc7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473-1f3fe.png b/twake/frontend/public/public/emojione/64/1f473-1f3fe.png new file mode 100644 index 00000000..bdb5efc7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f473-1f3ff-2640.png new file mode 100644 index 00000000..35316d95 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f473-1f3ff-2642.png new file mode 100644 index 00000000..c29a2e49 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473-1f3ff.png b/twake/frontend/public/public/emojione/64/1f473-1f3ff.png new file mode 100644 index 00000000..c29a2e49 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473-2640.png b/twake/frontend/public/public/emojione/64/1f473-2640.png new file mode 100644 index 00000000..19b1f2b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473-2642.png b/twake/frontend/public/public/emojione/64/1f473-2642.png new file mode 100644 index 00000000..8c8ee24e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f473.png b/twake/frontend/public/public/emojione/64/1f473.png new file mode 100644 index 00000000..8c8ee24e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f473.png differ diff --git a/twake/frontend/public/public/emojione/64/1f474-1f3fb.png b/twake/frontend/public/public/emojione/64/1f474-1f3fb.png new file mode 100644 index 00000000..5e60d925 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f474-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f474-1f3fc.png b/twake/frontend/public/public/emojione/64/1f474-1f3fc.png new file mode 100644 index 00000000..31dda058 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f474-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f474-1f3fd.png b/twake/frontend/public/public/emojione/64/1f474-1f3fd.png new file mode 100644 index 00000000..cb63fc9e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f474-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f474-1f3fe.png b/twake/frontend/public/public/emojione/64/1f474-1f3fe.png new file mode 100644 index 00000000..05c79ddb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f474-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f474-1f3ff.png b/twake/frontend/public/public/emojione/64/1f474-1f3ff.png new file mode 100644 index 00000000..608a9458 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f474-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f474.png b/twake/frontend/public/public/emojione/64/1f474.png new file mode 100644 index 00000000..391fa69c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f474.png differ diff --git a/twake/frontend/public/public/emojione/64/1f475-1f3fb.png b/twake/frontend/public/public/emojione/64/1f475-1f3fb.png new file mode 100644 index 00000000..c5150a26 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f475-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f475-1f3fc.png b/twake/frontend/public/public/emojione/64/1f475-1f3fc.png new file mode 100644 index 00000000..2cda5802 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f475-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f475-1f3fd.png b/twake/frontend/public/public/emojione/64/1f475-1f3fd.png new file mode 100644 index 00000000..c2bb767a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f475-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f475-1f3fe.png b/twake/frontend/public/public/emojione/64/1f475-1f3fe.png new file mode 100644 index 00000000..66f7549c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f475-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f475-1f3ff.png b/twake/frontend/public/public/emojione/64/1f475-1f3ff.png new file mode 100644 index 00000000..678098a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f475-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f475.png b/twake/frontend/public/public/emojione/64/1f475.png new file mode 100644 index 00000000..ad998976 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f475.png differ diff --git a/twake/frontend/public/public/emojione/64/1f476-1f3fb.png b/twake/frontend/public/public/emojione/64/1f476-1f3fb.png new file mode 100644 index 00000000..49a1f96a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f476-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f476-1f3fc.png b/twake/frontend/public/public/emojione/64/1f476-1f3fc.png new file mode 100644 index 00000000..b2f993fd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f476-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f476-1f3fd.png b/twake/frontend/public/public/emojione/64/1f476-1f3fd.png new file mode 100644 index 00000000..68df2621 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f476-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f476-1f3fe.png b/twake/frontend/public/public/emojione/64/1f476-1f3fe.png new file mode 100644 index 00000000..33c70ec4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f476-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f476-1f3ff.png b/twake/frontend/public/public/emojione/64/1f476-1f3ff.png new file mode 100644 index 00000000..b2e1232c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f476-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f476.png b/twake/frontend/public/public/emojione/64/1f476.png new file mode 100644 index 00000000..9134640f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f476.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f477-1f3fb-2640.png new file mode 100644 index 00000000..f0e6a9b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f477-1f3fb-2642.png new file mode 100644 index 00000000..322f1e4f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477-1f3fb.png b/twake/frontend/public/public/emojione/64/1f477-1f3fb.png new file mode 100644 index 00000000..322f1e4f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f477-1f3fc-2640.png new file mode 100644 index 00000000..716a5e8a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f477-1f3fc-2642.png new file mode 100644 index 00000000..af0c4fc8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477-1f3fc.png b/twake/frontend/public/public/emojione/64/1f477-1f3fc.png new file mode 100644 index 00000000..af0c4fc8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f477-1f3fd-2640.png new file mode 100644 index 00000000..566f89da Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f477-1f3fd-2642.png new file mode 100644 index 00000000..b536d97e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477-1f3fd.png b/twake/frontend/public/public/emojione/64/1f477-1f3fd.png new file mode 100644 index 00000000..b536d97e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f477-1f3fe-2640.png new file mode 100644 index 00000000..a1529384 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f477-1f3fe-2642.png new file mode 100644 index 00000000..8df3e4f9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477-1f3fe.png b/twake/frontend/public/public/emojione/64/1f477-1f3fe.png new file mode 100644 index 00000000..8df3e4f9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f477-1f3ff-2640.png new file mode 100644 index 00000000..b1376d21 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f477-1f3ff-2642.png new file mode 100644 index 00000000..70b4be8b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477-1f3ff.png b/twake/frontend/public/public/emojione/64/1f477-1f3ff.png new file mode 100644 index 00000000..70b4be8b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477-2640.png b/twake/frontend/public/public/emojione/64/1f477-2640.png new file mode 100644 index 00000000..2994d041 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477-2642.png b/twake/frontend/public/public/emojione/64/1f477-2642.png new file mode 100644 index 00000000..749f2960 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f477.png b/twake/frontend/public/public/emojione/64/1f477.png new file mode 100644 index 00000000..749f2960 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f477.png differ diff --git a/twake/frontend/public/public/emojione/64/1f478-1f3fb.png b/twake/frontend/public/public/emojione/64/1f478-1f3fb.png new file mode 100644 index 00000000..0a32b06c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f478-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f478-1f3fc.png b/twake/frontend/public/public/emojione/64/1f478-1f3fc.png new file mode 100644 index 00000000..728164fe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f478-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f478-1f3fd.png b/twake/frontend/public/public/emojione/64/1f478-1f3fd.png new file mode 100644 index 00000000..a0b2221f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f478-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f478-1f3fe.png b/twake/frontend/public/public/emojione/64/1f478-1f3fe.png new file mode 100644 index 00000000..0eceb120 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f478-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f478-1f3ff.png b/twake/frontend/public/public/emojione/64/1f478-1f3ff.png new file mode 100644 index 00000000..1c8b9ab3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f478-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f478.png b/twake/frontend/public/public/emojione/64/1f478.png new file mode 100644 index 00000000..70ad85c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f478.png differ diff --git a/twake/frontend/public/public/emojione/64/1f479.png b/twake/frontend/public/public/emojione/64/1f479.png new file mode 100644 index 00000000..4edb2bd3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f479.png differ diff --git a/twake/frontend/public/public/emojione/64/1f47a.png b/twake/frontend/public/public/emojione/64/1f47a.png new file mode 100644 index 00000000..81b21fea Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f47a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f47b.png b/twake/frontend/public/public/emojione/64/1f47b.png new file mode 100644 index 00000000..974e64eb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f47b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f47c-1f3fb.png b/twake/frontend/public/public/emojione/64/1f47c-1f3fb.png new file mode 100644 index 00000000..e50f2b48 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f47c-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f47c-1f3fc.png b/twake/frontend/public/public/emojione/64/1f47c-1f3fc.png new file mode 100644 index 00000000..020c1db1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f47c-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f47c-1f3fd.png b/twake/frontend/public/public/emojione/64/1f47c-1f3fd.png new file mode 100644 index 00000000..637f0e06 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f47c-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f47c-1f3fe.png b/twake/frontend/public/public/emojione/64/1f47c-1f3fe.png new file mode 100644 index 00000000..e2e81d88 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f47c-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f47c-1f3ff.png b/twake/frontend/public/public/emojione/64/1f47c-1f3ff.png new file mode 100644 index 00000000..27c770cd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f47c-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f47c.png b/twake/frontend/public/public/emojione/64/1f47c.png new file mode 100644 index 00000000..68badbe9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f47c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f47d.png b/twake/frontend/public/public/emojione/64/1f47d.png new file mode 100644 index 00000000..cecefe77 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f47d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f47e.png b/twake/frontend/public/public/emojione/64/1f47e.png new file mode 100644 index 00000000..efd9a2d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f47e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f47f.png b/twake/frontend/public/public/emojione/64/1f47f.png new file mode 100644 index 00000000..a5857345 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f47f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f480.png b/twake/frontend/public/public/emojione/64/1f480.png new file mode 100644 index 00000000..3319f80d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f480.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f481-1f3fb-2640.png new file mode 100644 index 00000000..c523d7c5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f481-1f3fb-2642.png new file mode 100644 index 00000000..3994f53f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481-1f3fb.png b/twake/frontend/public/public/emojione/64/1f481-1f3fb.png new file mode 100644 index 00000000..4dbd2d4b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f481-1f3fc-2640.png new file mode 100644 index 00000000..c7d22fc5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f481-1f3fc-2642.png new file mode 100644 index 00000000..970edf44 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481-1f3fc.png b/twake/frontend/public/public/emojione/64/1f481-1f3fc.png new file mode 100644 index 00000000..8df93984 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f481-1f3fd-2640.png new file mode 100644 index 00000000..6a4fc573 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f481-1f3fd-2642.png new file mode 100644 index 00000000..538141b9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481-1f3fd.png b/twake/frontend/public/public/emojione/64/1f481-1f3fd.png new file mode 100644 index 00000000..7336c335 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f481-1f3fe-2640.png new file mode 100644 index 00000000..c55097d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f481-1f3fe-2642.png new file mode 100644 index 00000000..de97a867 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481-1f3fe.png b/twake/frontend/public/public/emojione/64/1f481-1f3fe.png new file mode 100644 index 00000000..56c0df7e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f481-1f3ff-2640.png new file mode 100644 index 00000000..25a4ec69 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f481-1f3ff-2642.png new file mode 100644 index 00000000..94978703 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481-1f3ff.png b/twake/frontend/public/public/emojione/64/1f481-1f3ff.png new file mode 100644 index 00000000..14511ab8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481-2640.png b/twake/frontend/public/public/emojione/64/1f481-2640.png new file mode 100644 index 00000000..529046a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481-2642.png b/twake/frontend/public/public/emojione/64/1f481-2642.png new file mode 100644 index 00000000..7ceed710 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f481.png b/twake/frontend/public/public/emojione/64/1f481.png new file mode 100644 index 00000000..529046a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f481.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f482-1f3fb-2640.png new file mode 100644 index 00000000..a18db6f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f482-1f3fb-2642.png new file mode 100644 index 00000000..e6fe00e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482-1f3fb.png b/twake/frontend/public/public/emojione/64/1f482-1f3fb.png new file mode 100644 index 00000000..e6fe00e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f482-1f3fc-2640.png new file mode 100644 index 00000000..5c96425d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f482-1f3fc-2642.png new file mode 100644 index 00000000..fd296d35 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482-1f3fc.png b/twake/frontend/public/public/emojione/64/1f482-1f3fc.png new file mode 100644 index 00000000..fd296d35 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f482-1f3fd-2640.png new file mode 100644 index 00000000..5814426e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f482-1f3fd-2642.png new file mode 100644 index 00000000..be1d73d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482-1f3fd.png b/twake/frontend/public/public/emojione/64/1f482-1f3fd.png new file mode 100644 index 00000000..be1d73d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f482-1f3fe-2640.png new file mode 100644 index 00000000..6fe7cf89 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f482-1f3fe-2642.png new file mode 100644 index 00000000..66076b06 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482-1f3fe.png b/twake/frontend/public/public/emojione/64/1f482-1f3fe.png new file mode 100644 index 00000000..66076b06 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f482-1f3ff-2640.png new file mode 100644 index 00000000..136f1fbb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f482-1f3ff-2642.png new file mode 100644 index 00000000..bdc26da8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482-1f3ff.png b/twake/frontend/public/public/emojione/64/1f482-1f3ff.png new file mode 100644 index 00000000..bdc26da8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482-2640.png b/twake/frontend/public/public/emojione/64/1f482-2640.png new file mode 100644 index 00000000..1d98ecf7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482-2642.png b/twake/frontend/public/public/emojione/64/1f482-2642.png new file mode 100644 index 00000000..0e85d2d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f482.png b/twake/frontend/public/public/emojione/64/1f482.png new file mode 100644 index 00000000..0e85d2d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f482.png differ diff --git a/twake/frontend/public/public/emojione/64/1f483-1f3fb.png b/twake/frontend/public/public/emojione/64/1f483-1f3fb.png new file mode 100644 index 00000000..900a5469 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f483-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f483-1f3fc.png b/twake/frontend/public/public/emojione/64/1f483-1f3fc.png new file mode 100644 index 00000000..b68d498d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f483-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f483-1f3fd.png b/twake/frontend/public/public/emojione/64/1f483-1f3fd.png new file mode 100644 index 00000000..b4daae84 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f483-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f483-1f3fe.png b/twake/frontend/public/public/emojione/64/1f483-1f3fe.png new file mode 100644 index 00000000..57de130d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f483-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f483-1f3ff.png b/twake/frontend/public/public/emojione/64/1f483-1f3ff.png new file mode 100644 index 00000000..c21ff642 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f483-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f483.png b/twake/frontend/public/public/emojione/64/1f483.png new file mode 100644 index 00000000..15b9f80d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f483.png differ diff --git a/twake/frontend/public/public/emojione/64/1f484.png b/twake/frontend/public/public/emojione/64/1f484.png new file mode 100644 index 00000000..a065a8e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f484.png differ diff --git a/twake/frontend/public/public/emojione/64/1f485-1f3fb.png b/twake/frontend/public/public/emojione/64/1f485-1f3fb.png new file mode 100644 index 00000000..d60c77e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f485-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f485-1f3fc.png b/twake/frontend/public/public/emojione/64/1f485-1f3fc.png new file mode 100644 index 00000000..0c01d4a5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f485-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f485-1f3fd.png b/twake/frontend/public/public/emojione/64/1f485-1f3fd.png new file mode 100644 index 00000000..aea704e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f485-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f485-1f3fe.png b/twake/frontend/public/public/emojione/64/1f485-1f3fe.png new file mode 100644 index 00000000..cdcbbfd9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f485-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f485-1f3ff.png b/twake/frontend/public/public/emojione/64/1f485-1f3ff.png new file mode 100644 index 00000000..9df3cd13 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f485-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f485.png b/twake/frontend/public/public/emojione/64/1f485.png new file mode 100644 index 00000000..31166fce Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f485.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f486-1f3fb-2640.png new file mode 100644 index 00000000..0785b97d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f486-1f3fb-2642.png new file mode 100644 index 00000000..7b82614c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486-1f3fb.png b/twake/frontend/public/public/emojione/64/1f486-1f3fb.png new file mode 100644 index 00000000..106fc1cd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f486-1f3fc-2640.png new file mode 100644 index 00000000..2202237e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f486-1f3fc-2642.png new file mode 100644 index 00000000..183cf2b4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486-1f3fc.png b/twake/frontend/public/public/emojione/64/1f486-1f3fc.png new file mode 100644 index 00000000..91f53f6e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f486-1f3fd-2640.png new file mode 100644 index 00000000..073c6f6d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f486-1f3fd-2642.png new file mode 100644 index 00000000..4ff29c0d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486-1f3fd.png b/twake/frontend/public/public/emojione/64/1f486-1f3fd.png new file mode 100644 index 00000000..0ea2fd84 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f486-1f3fe-2640.png new file mode 100644 index 00000000..afc83e20 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f486-1f3fe-2642.png new file mode 100644 index 00000000..deb65d46 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486-1f3fe.png b/twake/frontend/public/public/emojione/64/1f486-1f3fe.png new file mode 100644 index 00000000..4d4d4406 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f486-1f3ff-2640.png new file mode 100644 index 00000000..2dae147c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f486-1f3ff-2642.png new file mode 100644 index 00000000..c3c28e21 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486-1f3ff.png b/twake/frontend/public/public/emojione/64/1f486-1f3ff.png new file mode 100644 index 00000000..5db61571 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486-2640.png b/twake/frontend/public/public/emojione/64/1f486-2640.png new file mode 100644 index 00000000..8506f37e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486-2642.png b/twake/frontend/public/public/emojione/64/1f486-2642.png new file mode 100644 index 00000000..7bab8722 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f486.png b/twake/frontend/public/public/emojione/64/1f486.png new file mode 100644 index 00000000..8506f37e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f486.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f487-1f3fb-2640.png new file mode 100644 index 00000000..c1318783 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f487-1f3fb-2642.png new file mode 100644 index 00000000..e6a28b03 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487-1f3fb.png b/twake/frontend/public/public/emojione/64/1f487-1f3fb.png new file mode 100644 index 00000000..09d78215 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f487-1f3fc-2640.png new file mode 100644 index 00000000..292545f9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f487-1f3fc-2642.png new file mode 100644 index 00000000..cd4c9939 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487-1f3fc.png b/twake/frontend/public/public/emojione/64/1f487-1f3fc.png new file mode 100644 index 00000000..28097678 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f487-1f3fd-2640.png new file mode 100644 index 00000000..d42d3c5c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f487-1f3fd-2642.png new file mode 100644 index 00000000..9d7e06e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487-1f3fd.png b/twake/frontend/public/public/emojione/64/1f487-1f3fd.png new file mode 100644 index 00000000..8984a972 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f487-1f3fe-2640.png new file mode 100644 index 00000000..4593f6f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f487-1f3fe-2642.png new file mode 100644 index 00000000..a102349f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487-1f3fe.png b/twake/frontend/public/public/emojione/64/1f487-1f3fe.png new file mode 100644 index 00000000..4fa8a97b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f487-1f3ff-2640.png new file mode 100644 index 00000000..3dc9aabc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f487-1f3ff-2642.png new file mode 100644 index 00000000..268c3172 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487-1f3ff.png b/twake/frontend/public/public/emojione/64/1f487-1f3ff.png new file mode 100644 index 00000000..dae00ea9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487-2640.png b/twake/frontend/public/public/emojione/64/1f487-2640.png new file mode 100644 index 00000000..3bcef2eb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487-2642.png b/twake/frontend/public/public/emojione/64/1f487-2642.png new file mode 100644 index 00000000..8f9bf9e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f487.png b/twake/frontend/public/public/emojione/64/1f487.png new file mode 100644 index 00000000..3bcef2eb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f487.png differ diff --git a/twake/frontend/public/public/emojione/64/1f488.png b/twake/frontend/public/public/emojione/64/1f488.png new file mode 100644 index 00000000..6eafc0c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f488.png differ diff --git a/twake/frontend/public/public/emojione/64/1f489.png b/twake/frontend/public/public/emojione/64/1f489.png new file mode 100644 index 00000000..f1386fbe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f489.png differ diff --git a/twake/frontend/public/public/emojione/64/1f48a.png b/twake/frontend/public/public/emojione/64/1f48a.png new file mode 100644 index 00000000..7517cf6b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f48a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f48b.png b/twake/frontend/public/public/emojione/64/1f48b.png new file mode 100644 index 00000000..645bb677 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f48b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f48c.png b/twake/frontend/public/public/emojione/64/1f48c.png new file mode 100644 index 00000000..f151095a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f48c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f48d.png b/twake/frontend/public/public/emojione/64/1f48d.png new file mode 100644 index 00000000..5c911344 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f48d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f48e.png b/twake/frontend/public/public/emojione/64/1f48e.png new file mode 100644 index 00000000..61cf99a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f48e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f48f.png b/twake/frontend/public/public/emojione/64/1f48f.png new file mode 100644 index 00000000..7450553d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f48f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f490.png b/twake/frontend/public/public/emojione/64/1f490.png new file mode 100644 index 00000000..12bce9ff Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f490.png differ diff --git a/twake/frontend/public/public/emojione/64/1f491.png b/twake/frontend/public/public/emojione/64/1f491.png new file mode 100644 index 00000000..335cf1c4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f491.png differ diff --git a/twake/frontend/public/public/emojione/64/1f492.png b/twake/frontend/public/public/emojione/64/1f492.png new file mode 100644 index 00000000..36cf5827 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f492.png differ diff --git a/twake/frontend/public/public/emojione/64/1f493.png b/twake/frontend/public/public/emojione/64/1f493.png new file mode 100644 index 00000000..64c30dca Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f493.png differ diff --git a/twake/frontend/public/public/emojione/64/1f494.png b/twake/frontend/public/public/emojione/64/1f494.png new file mode 100644 index 00000000..41363208 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f494.png differ diff --git a/twake/frontend/public/public/emojione/64/1f495.png b/twake/frontend/public/public/emojione/64/1f495.png new file mode 100644 index 00000000..fe594ad6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f495.png differ diff --git a/twake/frontend/public/public/emojione/64/1f496.png b/twake/frontend/public/public/emojione/64/1f496.png new file mode 100644 index 00000000..c6d9fed6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f496.png differ diff --git a/twake/frontend/public/public/emojione/64/1f497.png b/twake/frontend/public/public/emojione/64/1f497.png new file mode 100644 index 00000000..efc2a0e4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f497.png differ diff --git a/twake/frontend/public/public/emojione/64/1f498.png b/twake/frontend/public/public/emojione/64/1f498.png new file mode 100644 index 00000000..6a0b8c20 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f498.png differ diff --git a/twake/frontend/public/public/emojione/64/1f499.png b/twake/frontend/public/public/emojione/64/1f499.png new file mode 100644 index 00000000..5d133312 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f499.png differ diff --git a/twake/frontend/public/public/emojione/64/1f49a.png b/twake/frontend/public/public/emojione/64/1f49a.png new file mode 100644 index 00000000..dc0d2794 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f49a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f49b.png b/twake/frontend/public/public/emojione/64/1f49b.png new file mode 100644 index 00000000..0af5ff0c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f49b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f49c.png b/twake/frontend/public/public/emojione/64/1f49c.png new file mode 100644 index 00000000..b02c2ae8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f49c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f49d.png b/twake/frontend/public/public/emojione/64/1f49d.png new file mode 100644 index 00000000..e181d59e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f49d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f49e.png b/twake/frontend/public/public/emojione/64/1f49e.png new file mode 100644 index 00000000..cce4eb69 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f49e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f49f.png b/twake/frontend/public/public/emojione/64/1f49f.png new file mode 100644 index 00000000..b058f346 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f49f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4a0.png b/twake/frontend/public/public/emojione/64/1f4a0.png new file mode 100644 index 00000000..82080a19 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4a0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4a1.png b/twake/frontend/public/public/emojione/64/1f4a1.png new file mode 100644 index 00000000..96e8dc3b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4a1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4a2.png b/twake/frontend/public/public/emojione/64/1f4a2.png new file mode 100644 index 00000000..d44275ff Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4a2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4a3.png b/twake/frontend/public/public/emojione/64/1f4a3.png new file mode 100644 index 00000000..42f0d8f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4a3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4a4.png b/twake/frontend/public/public/emojione/64/1f4a4.png new file mode 100644 index 00000000..06064d07 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4a4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4a5.png b/twake/frontend/public/public/emojione/64/1f4a5.png new file mode 100644 index 00000000..b81b002f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4a5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4a6.png b/twake/frontend/public/public/emojione/64/1f4a6.png new file mode 100644 index 00000000..91a604c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4a6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4a7.png b/twake/frontend/public/public/emojione/64/1f4a7.png new file mode 100644 index 00000000..2430d15f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4a7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4a8.png b/twake/frontend/public/public/emojione/64/1f4a8.png new file mode 100644 index 00000000..26cc154e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4a8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4a9.png b/twake/frontend/public/public/emojione/64/1f4a9.png new file mode 100644 index 00000000..a1a53b48 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4a9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4aa-1f3fb.png b/twake/frontend/public/public/emojione/64/1f4aa-1f3fb.png new file mode 100644 index 00000000..898097e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4aa-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4aa-1f3fc.png b/twake/frontend/public/public/emojione/64/1f4aa-1f3fc.png new file mode 100644 index 00000000..ebd06956 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4aa-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4aa-1f3fd.png b/twake/frontend/public/public/emojione/64/1f4aa-1f3fd.png new file mode 100644 index 00000000..fb1fe02b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4aa-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4aa-1f3fe.png b/twake/frontend/public/public/emojione/64/1f4aa-1f3fe.png new file mode 100644 index 00000000..8c8ab6a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4aa-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4aa-1f3ff.png b/twake/frontend/public/public/emojione/64/1f4aa-1f3ff.png new file mode 100644 index 00000000..1a68380b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4aa-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4aa.png b/twake/frontend/public/public/emojione/64/1f4aa.png new file mode 100644 index 00000000..3a37f9e4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4aa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4ab.png b/twake/frontend/public/public/emojione/64/1f4ab.png new file mode 100644 index 00000000..9a92d769 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4ab.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4ac.png b/twake/frontend/public/public/emojione/64/1f4ac.png new file mode 100644 index 00000000..de4f31ee Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4ac.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4ad.png b/twake/frontend/public/public/emojione/64/1f4ad.png new file mode 100644 index 00000000..fd0a926a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4ad.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4ae.png b/twake/frontend/public/public/emojione/64/1f4ae.png new file mode 100644 index 00000000..23b44246 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4ae.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4af.png b/twake/frontend/public/public/emojione/64/1f4af.png new file mode 100644 index 00000000..06f5a9f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4af.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4b0.png b/twake/frontend/public/public/emojione/64/1f4b0.png new file mode 100644 index 00000000..5d7dde2c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4b0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4b1.png b/twake/frontend/public/public/emojione/64/1f4b1.png new file mode 100644 index 00000000..30832cc1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4b1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4b2.png b/twake/frontend/public/public/emojione/64/1f4b2.png new file mode 100644 index 00000000..ec516aae Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4b2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4b3.png b/twake/frontend/public/public/emojione/64/1f4b3.png new file mode 100644 index 00000000..ba08759f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4b3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4b4.png b/twake/frontend/public/public/emojione/64/1f4b4.png new file mode 100644 index 00000000..a02d0193 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4b4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4b5.png b/twake/frontend/public/public/emojione/64/1f4b5.png new file mode 100644 index 00000000..0f2a96d5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4b5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4b6.png b/twake/frontend/public/public/emojione/64/1f4b6.png new file mode 100644 index 00000000..ec464dad Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4b6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4b7.png b/twake/frontend/public/public/emojione/64/1f4b7.png new file mode 100644 index 00000000..c87b95af Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4b7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4b8.png b/twake/frontend/public/public/emojione/64/1f4b8.png new file mode 100644 index 00000000..de35f49f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4b8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4b9.png b/twake/frontend/public/public/emojione/64/1f4b9.png new file mode 100644 index 00000000..693386c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4b9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4ba.png b/twake/frontend/public/public/emojione/64/1f4ba.png new file mode 100644 index 00000000..7207e3a7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4ba.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4bb.png b/twake/frontend/public/public/emojione/64/1f4bb.png new file mode 100644 index 00000000..650267ec Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4bb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4bc.png b/twake/frontend/public/public/emojione/64/1f4bc.png new file mode 100644 index 00000000..ad9fee39 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4bc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4bd.png b/twake/frontend/public/public/emojione/64/1f4bd.png new file mode 100644 index 00000000..b8923bab Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4bd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4be.png b/twake/frontend/public/public/emojione/64/1f4be.png new file mode 100644 index 00000000..0dda8264 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4be.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4bf.png b/twake/frontend/public/public/emojione/64/1f4bf.png new file mode 100644 index 00000000..5e8f1a0d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4bf.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4c0.png b/twake/frontend/public/public/emojione/64/1f4c0.png new file mode 100644 index 00000000..fa981674 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4c0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4c1.png b/twake/frontend/public/public/emojione/64/1f4c1.png new file mode 100644 index 00000000..ea501b3e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4c1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4c2.png b/twake/frontend/public/public/emojione/64/1f4c2.png new file mode 100644 index 00000000..aa9aa083 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4c2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4c3.png b/twake/frontend/public/public/emojione/64/1f4c3.png new file mode 100644 index 00000000..5a19e5ff Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4c3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4c4.png b/twake/frontend/public/public/emojione/64/1f4c4.png new file mode 100644 index 00000000..a338773f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4c4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4c5.png b/twake/frontend/public/public/emojione/64/1f4c5.png new file mode 100644 index 00000000..c86b7b71 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4c5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4c6.png b/twake/frontend/public/public/emojione/64/1f4c6.png new file mode 100644 index 00000000..e1a5dea7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4c6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4c7.png b/twake/frontend/public/public/emojione/64/1f4c7.png new file mode 100644 index 00000000..340a3d97 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4c7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4c8.png b/twake/frontend/public/public/emojione/64/1f4c8.png new file mode 100644 index 00000000..14df9477 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4c8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4c9.png b/twake/frontend/public/public/emojione/64/1f4c9.png new file mode 100644 index 00000000..b510bfdd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4c9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4ca.png b/twake/frontend/public/public/emojione/64/1f4ca.png new file mode 100644 index 00000000..f9fadc80 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4ca.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4cb.png b/twake/frontend/public/public/emojione/64/1f4cb.png new file mode 100644 index 00000000..9f0a7725 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4cb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4cc.png b/twake/frontend/public/public/emojione/64/1f4cc.png new file mode 100644 index 00000000..3cb420a1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4cc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4cd.png b/twake/frontend/public/public/emojione/64/1f4cd.png new file mode 100644 index 00000000..e675a007 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4cd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4ce.png b/twake/frontend/public/public/emojione/64/1f4ce.png new file mode 100644 index 00000000..196ac7e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4ce.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4cf.png b/twake/frontend/public/public/emojione/64/1f4cf.png new file mode 100644 index 00000000..6d03ede9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4cf.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4d0.png b/twake/frontend/public/public/emojione/64/1f4d0.png new file mode 100644 index 00000000..c285a5e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4d0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4d1.png b/twake/frontend/public/public/emojione/64/1f4d1.png new file mode 100644 index 00000000..820758a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4d1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4d2.png b/twake/frontend/public/public/emojione/64/1f4d2.png new file mode 100644 index 00000000..934a87c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4d2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4d3.png b/twake/frontend/public/public/emojione/64/1f4d3.png new file mode 100644 index 00000000..75117d0c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4d3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4d4.png b/twake/frontend/public/public/emojione/64/1f4d4.png new file mode 100644 index 00000000..098e8edf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4d4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4d5.png b/twake/frontend/public/public/emojione/64/1f4d5.png new file mode 100644 index 00000000..08a86a3e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4d5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4d6.png b/twake/frontend/public/public/emojione/64/1f4d6.png new file mode 100644 index 00000000..79a852fc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4d6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4d7.png b/twake/frontend/public/public/emojione/64/1f4d7.png new file mode 100644 index 00000000..e7eb50ce Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4d7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4d8.png b/twake/frontend/public/public/emojione/64/1f4d8.png new file mode 100644 index 00000000..0fd284d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4d8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4d9.png b/twake/frontend/public/public/emojione/64/1f4d9.png new file mode 100644 index 00000000..ed4dc2e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4d9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4da.png b/twake/frontend/public/public/emojione/64/1f4da.png new file mode 100644 index 00000000..547d35bb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4da.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4db.png b/twake/frontend/public/public/emojione/64/1f4db.png new file mode 100644 index 00000000..21276b0e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4db.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4dc.png b/twake/frontend/public/public/emojione/64/1f4dc.png new file mode 100644 index 00000000..d9cc844b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4dc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4dd.png b/twake/frontend/public/public/emojione/64/1f4dd.png new file mode 100644 index 00000000..448f15da Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4dd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4de.png b/twake/frontend/public/public/emojione/64/1f4de.png new file mode 100644 index 00000000..8d4d4e79 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4de.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4df.png b/twake/frontend/public/public/emojione/64/1f4df.png new file mode 100644 index 00000000..59dabedf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4df.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4e0.png b/twake/frontend/public/public/emojione/64/1f4e0.png new file mode 100644 index 00000000..eee1d2cc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4e0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4e1.png b/twake/frontend/public/public/emojione/64/1f4e1.png new file mode 100644 index 00000000..9e8eee7c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4e1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4e2.png b/twake/frontend/public/public/emojione/64/1f4e2.png new file mode 100644 index 00000000..c19703eb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4e2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4e3.png b/twake/frontend/public/public/emojione/64/1f4e3.png new file mode 100644 index 00000000..27309835 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4e3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4e4.png b/twake/frontend/public/public/emojione/64/1f4e4.png new file mode 100644 index 00000000..cd8108c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4e4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4e5.png b/twake/frontend/public/public/emojione/64/1f4e5.png new file mode 100644 index 00000000..efcda975 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4e5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4e6.png b/twake/frontend/public/public/emojione/64/1f4e6.png new file mode 100644 index 00000000..8e6dc6a6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4e7.png b/twake/frontend/public/public/emojione/64/1f4e7.png new file mode 100644 index 00000000..8a071e32 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4e7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4e8.png b/twake/frontend/public/public/emojione/64/1f4e8.png new file mode 100644 index 00000000..1bfe5bdf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4e8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4e9.png b/twake/frontend/public/public/emojione/64/1f4e9.png new file mode 100644 index 00000000..075fc070 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4e9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4ea.png b/twake/frontend/public/public/emojione/64/1f4ea.png new file mode 100644 index 00000000..98f58102 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4eb.png b/twake/frontend/public/public/emojione/64/1f4eb.png new file mode 100644 index 00000000..2e327254 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4ec.png b/twake/frontend/public/public/emojione/64/1f4ec.png new file mode 100644 index 00000000..5f2cbfb0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4ed.png b/twake/frontend/public/public/emojione/64/1f4ed.png new file mode 100644 index 00000000..3070cf3a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4ee.png b/twake/frontend/public/public/emojione/64/1f4ee.png new file mode 100644 index 00000000..12035937 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4ee.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4ef.png b/twake/frontend/public/public/emojione/64/1f4ef.png new file mode 100644 index 00000000..539520aa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4ef.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4f0.png b/twake/frontend/public/public/emojione/64/1f4f0.png new file mode 100644 index 00000000..1f5bac6f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4f0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4f1.png b/twake/frontend/public/public/emojione/64/1f4f1.png new file mode 100644 index 00000000..b641782b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4f1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4f2.png b/twake/frontend/public/public/emojione/64/1f4f2.png new file mode 100644 index 00000000..e72c7b46 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4f3.png b/twake/frontend/public/public/emojione/64/1f4f3.png new file mode 100644 index 00000000..f828f761 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4f4.png b/twake/frontend/public/public/emojione/64/1f4f4.png new file mode 100644 index 00000000..e3e7ac94 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4f4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4f5.png b/twake/frontend/public/public/emojione/64/1f4f5.png new file mode 100644 index 00000000..00b241b9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4f5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4f6.png b/twake/frontend/public/public/emojione/64/1f4f6.png new file mode 100644 index 00000000..c6e75189 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4f6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4f7.png b/twake/frontend/public/public/emojione/64/1f4f7.png new file mode 100644 index 00000000..50a52557 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4f8.png b/twake/frontend/public/public/emojione/64/1f4f8.png new file mode 100644 index 00000000..8aea2e6a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4f8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4f9.png b/twake/frontend/public/public/emojione/64/1f4f9.png new file mode 100644 index 00000000..80d62d2c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4f9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4fa.png b/twake/frontend/public/public/emojione/64/1f4fa.png new file mode 100644 index 00000000..39671de3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4fa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4fb.png b/twake/frontend/public/public/emojione/64/1f4fb.png new file mode 100644 index 00000000..01333fb0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4fc.png b/twake/frontend/public/public/emojione/64/1f4fc.png new file mode 100644 index 00000000..5031ee8d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4fd.png b/twake/frontend/public/public/emojione/64/1f4fd.png new file mode 100644 index 00000000..e00d1c0f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f4ff.png b/twake/frontend/public/public/emojione/64/1f4ff.png new file mode 100644 index 00000000..806d3a5a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f4ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f500.png b/twake/frontend/public/public/emojione/64/1f500.png new file mode 100644 index 00000000..3bb45560 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f500.png differ diff --git a/twake/frontend/public/public/emojione/64/1f501.png b/twake/frontend/public/public/emojione/64/1f501.png new file mode 100644 index 00000000..937515f9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f501.png differ diff --git a/twake/frontend/public/public/emojione/64/1f502.png b/twake/frontend/public/public/emojione/64/1f502.png new file mode 100644 index 00000000..3fc69ef6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f502.png differ diff --git a/twake/frontend/public/public/emojione/64/1f503.png b/twake/frontend/public/public/emojione/64/1f503.png new file mode 100644 index 00000000..99ef1ab9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f503.png differ diff --git a/twake/frontend/public/public/emojione/64/1f504.png b/twake/frontend/public/public/emojione/64/1f504.png new file mode 100644 index 00000000..1724dfe6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f504.png differ diff --git a/twake/frontend/public/public/emojione/64/1f505.png b/twake/frontend/public/public/emojione/64/1f505.png new file mode 100644 index 00000000..651e9b74 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f505.png differ diff --git a/twake/frontend/public/public/emojione/64/1f506.png b/twake/frontend/public/public/emojione/64/1f506.png new file mode 100644 index 00000000..abb7ddf7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f506.png differ diff --git a/twake/frontend/public/public/emojione/64/1f507.png b/twake/frontend/public/public/emojione/64/1f507.png new file mode 100644 index 00000000..60cf9b2f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f507.png differ diff --git a/twake/frontend/public/public/emojione/64/1f508.png b/twake/frontend/public/public/emojione/64/1f508.png new file mode 100644 index 00000000..3a5933c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f508.png differ diff --git a/twake/frontend/public/public/emojione/64/1f509.png b/twake/frontend/public/public/emojione/64/1f509.png new file mode 100644 index 00000000..b7d4bd89 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f509.png differ diff --git a/twake/frontend/public/public/emojione/64/1f50a.png b/twake/frontend/public/public/emojione/64/1f50a.png new file mode 100644 index 00000000..22a27a1a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f50a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f50b.png b/twake/frontend/public/public/emojione/64/1f50b.png new file mode 100644 index 00000000..ee638cfb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f50b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f50c.png b/twake/frontend/public/public/emojione/64/1f50c.png new file mode 100644 index 00000000..a180ec69 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f50c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f50d.png b/twake/frontend/public/public/emojione/64/1f50d.png new file mode 100644 index 00000000..456fd0e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f50d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f50e.png b/twake/frontend/public/public/emojione/64/1f50e.png new file mode 100644 index 00000000..fa1f887a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f50e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f50f.png b/twake/frontend/public/public/emojione/64/1f50f.png new file mode 100644 index 00000000..218812b9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f50f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f510.png b/twake/frontend/public/public/emojione/64/1f510.png new file mode 100644 index 00000000..057e93dd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f510.png differ diff --git a/twake/frontend/public/public/emojione/64/1f511.png b/twake/frontend/public/public/emojione/64/1f511.png new file mode 100644 index 00000000..7945c577 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f511.png differ diff --git a/twake/frontend/public/public/emojione/64/1f512.png b/twake/frontend/public/public/emojione/64/1f512.png new file mode 100644 index 00000000..62d928d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f512.png differ diff --git a/twake/frontend/public/public/emojione/64/1f513.png b/twake/frontend/public/public/emojione/64/1f513.png new file mode 100644 index 00000000..27dc6a5c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f513.png differ diff --git a/twake/frontend/public/public/emojione/64/1f514.png b/twake/frontend/public/public/emojione/64/1f514.png new file mode 100644 index 00000000..e38277f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f514.png differ diff --git a/twake/frontend/public/public/emojione/64/1f515.png b/twake/frontend/public/public/emojione/64/1f515.png new file mode 100644 index 00000000..77e9752d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f515.png differ diff --git a/twake/frontend/public/public/emojione/64/1f516.png b/twake/frontend/public/public/emojione/64/1f516.png new file mode 100644 index 00000000..3bd1af20 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f516.png differ diff --git a/twake/frontend/public/public/emojione/64/1f517.png b/twake/frontend/public/public/emojione/64/1f517.png new file mode 100644 index 00000000..eaec4a8d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f517.png differ diff --git a/twake/frontend/public/public/emojione/64/1f518.png b/twake/frontend/public/public/emojione/64/1f518.png new file mode 100644 index 00000000..cabae4be Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f518.png differ diff --git a/twake/frontend/public/public/emojione/64/1f519.png b/twake/frontend/public/public/emojione/64/1f519.png new file mode 100644 index 00000000..b2dd0224 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f519.png differ diff --git a/twake/frontend/public/public/emojione/64/1f51a.png b/twake/frontend/public/public/emojione/64/1f51a.png new file mode 100644 index 00000000..9410d644 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f51a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f51b.png b/twake/frontend/public/public/emojione/64/1f51b.png new file mode 100644 index 00000000..f866de47 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f51b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f51c.png b/twake/frontend/public/public/emojione/64/1f51c.png new file mode 100644 index 00000000..6899356f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f51c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f51d.png b/twake/frontend/public/public/emojione/64/1f51d.png new file mode 100644 index 00000000..bde89d1d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f51d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f51e.png b/twake/frontend/public/public/emojione/64/1f51e.png new file mode 100644 index 00000000..6e2bd694 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f51e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f51f.png b/twake/frontend/public/public/emojione/64/1f51f.png new file mode 100644 index 00000000..0f7565ca Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f51f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f520.png b/twake/frontend/public/public/emojione/64/1f520.png new file mode 100644 index 00000000..fe106bda Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f520.png differ diff --git a/twake/frontend/public/public/emojione/64/1f521.png b/twake/frontend/public/public/emojione/64/1f521.png new file mode 100644 index 00000000..a3fa93b2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f521.png differ diff --git a/twake/frontend/public/public/emojione/64/1f522.png b/twake/frontend/public/public/emojione/64/1f522.png new file mode 100644 index 00000000..74bf19b3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f522.png differ diff --git a/twake/frontend/public/public/emojione/64/1f523.png b/twake/frontend/public/public/emojione/64/1f523.png new file mode 100644 index 00000000..ed4de7ba Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f523.png differ diff --git a/twake/frontend/public/public/emojione/64/1f524.png b/twake/frontend/public/public/emojione/64/1f524.png new file mode 100644 index 00000000..4074b6c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f524.png differ diff --git a/twake/frontend/public/public/emojione/64/1f525.png b/twake/frontend/public/public/emojione/64/1f525.png new file mode 100644 index 00000000..f63af076 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f525.png differ diff --git a/twake/frontend/public/public/emojione/64/1f526.png b/twake/frontend/public/public/emojione/64/1f526.png new file mode 100644 index 00000000..d99e3b76 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f526.png differ diff --git a/twake/frontend/public/public/emojione/64/1f527.png b/twake/frontend/public/public/emojione/64/1f527.png new file mode 100644 index 00000000..4fea8983 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f527.png differ diff --git a/twake/frontend/public/public/emojione/64/1f528.png b/twake/frontend/public/public/emojione/64/1f528.png new file mode 100644 index 00000000..c3da955a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f528.png differ diff --git a/twake/frontend/public/public/emojione/64/1f529.png b/twake/frontend/public/public/emojione/64/1f529.png new file mode 100644 index 00000000..81bf376a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f529.png differ diff --git a/twake/frontend/public/public/emojione/64/1f52a.png b/twake/frontend/public/public/emojione/64/1f52a.png new file mode 100644 index 00000000..2ed16729 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f52a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f52b.png b/twake/frontend/public/public/emojione/64/1f52b.png new file mode 100644 index 00000000..c906eba0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f52b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f52c.png b/twake/frontend/public/public/emojione/64/1f52c.png new file mode 100644 index 00000000..a072a35f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f52c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f52d.png b/twake/frontend/public/public/emojione/64/1f52d.png new file mode 100644 index 00000000..2cb02057 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f52d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f52e.png b/twake/frontend/public/public/emojione/64/1f52e.png new file mode 100644 index 00000000..16c77aa6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f52e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f52f.png b/twake/frontend/public/public/emojione/64/1f52f.png new file mode 100644 index 00000000..f603b486 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f52f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f530.png b/twake/frontend/public/public/emojione/64/1f530.png new file mode 100644 index 00000000..bd888559 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f530.png differ diff --git a/twake/frontend/public/public/emojione/64/1f531.png b/twake/frontend/public/public/emojione/64/1f531.png new file mode 100644 index 00000000..5faabd71 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f531.png differ diff --git a/twake/frontend/public/public/emojione/64/1f532.png b/twake/frontend/public/public/emojione/64/1f532.png new file mode 100644 index 00000000..cfe1f05a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f532.png differ diff --git a/twake/frontend/public/public/emojione/64/1f533.png b/twake/frontend/public/public/emojione/64/1f533.png new file mode 100644 index 00000000..3342f029 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f533.png differ diff --git a/twake/frontend/public/public/emojione/64/1f534.png b/twake/frontend/public/public/emojione/64/1f534.png new file mode 100644 index 00000000..a85a5d3e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f534.png differ diff --git a/twake/frontend/public/public/emojione/64/1f535.png b/twake/frontend/public/public/emojione/64/1f535.png new file mode 100644 index 00000000..4d2ea6d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f535.png differ diff --git a/twake/frontend/public/public/emojione/64/1f536.png b/twake/frontend/public/public/emojione/64/1f536.png new file mode 100644 index 00000000..a2f62025 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f536.png differ diff --git a/twake/frontend/public/public/emojione/64/1f537.png b/twake/frontend/public/public/emojione/64/1f537.png new file mode 100644 index 00000000..fd71be79 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f537.png differ diff --git a/twake/frontend/public/public/emojione/64/1f538.png b/twake/frontend/public/public/emojione/64/1f538.png new file mode 100644 index 00000000..3b68c3fc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f538.png differ diff --git a/twake/frontend/public/public/emojione/64/1f539.png b/twake/frontend/public/public/emojione/64/1f539.png new file mode 100644 index 00000000..a3a02e59 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f539.png differ diff --git a/twake/frontend/public/public/emojione/64/1f53a.png b/twake/frontend/public/public/emojione/64/1f53a.png new file mode 100644 index 00000000..9a7d6eb0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f53a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f53b.png b/twake/frontend/public/public/emojione/64/1f53b.png new file mode 100644 index 00000000..68e32c12 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f53b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f53c.png b/twake/frontend/public/public/emojione/64/1f53c.png new file mode 100644 index 00000000..23bdcae3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f53c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f53d.png b/twake/frontend/public/public/emojione/64/1f53d.png new file mode 100644 index 00000000..787d390c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f53d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f549.png b/twake/frontend/public/public/emojione/64/1f549.png new file mode 100644 index 00000000..075d5214 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f549.png differ diff --git a/twake/frontend/public/public/emojione/64/1f54a.png b/twake/frontend/public/public/emojione/64/1f54a.png new file mode 100644 index 00000000..280aeb0f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f54a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f54b.png b/twake/frontend/public/public/emojione/64/1f54b.png new file mode 100644 index 00000000..6b16b505 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f54b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f54c.png b/twake/frontend/public/public/emojione/64/1f54c.png new file mode 100644 index 00000000..f6885be6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f54c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f54d.png b/twake/frontend/public/public/emojione/64/1f54d.png new file mode 100644 index 00000000..f37aa942 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f54d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f54e.png b/twake/frontend/public/public/emojione/64/1f54e.png new file mode 100644 index 00000000..c9f0c272 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f54e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f550.png b/twake/frontend/public/public/emojione/64/1f550.png new file mode 100644 index 00000000..c21498d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f550.png differ diff --git a/twake/frontend/public/public/emojione/64/1f551.png b/twake/frontend/public/public/emojione/64/1f551.png new file mode 100644 index 00000000..488f0316 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f551.png differ diff --git a/twake/frontend/public/public/emojione/64/1f552.png b/twake/frontend/public/public/emojione/64/1f552.png new file mode 100644 index 00000000..65bfd93c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f552.png differ diff --git a/twake/frontend/public/public/emojione/64/1f553.png b/twake/frontend/public/public/emojione/64/1f553.png new file mode 100644 index 00000000..e7c3f65f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f553.png differ diff --git a/twake/frontend/public/public/emojione/64/1f554.png b/twake/frontend/public/public/emojione/64/1f554.png new file mode 100644 index 00000000..bb95ed99 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f554.png differ diff --git a/twake/frontend/public/public/emojione/64/1f555.png b/twake/frontend/public/public/emojione/64/1f555.png new file mode 100644 index 00000000..c8637c80 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f555.png differ diff --git a/twake/frontend/public/public/emojione/64/1f556.png b/twake/frontend/public/public/emojione/64/1f556.png new file mode 100644 index 00000000..85eceb6a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f556.png differ diff --git a/twake/frontend/public/public/emojione/64/1f557.png b/twake/frontend/public/public/emojione/64/1f557.png new file mode 100644 index 00000000..395537ef Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f557.png differ diff --git a/twake/frontend/public/public/emojione/64/1f558.png b/twake/frontend/public/public/emojione/64/1f558.png new file mode 100644 index 00000000..83bc1ffc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f558.png differ diff --git a/twake/frontend/public/public/emojione/64/1f559.png b/twake/frontend/public/public/emojione/64/1f559.png new file mode 100644 index 00000000..66d0ae33 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f559.png differ diff --git a/twake/frontend/public/public/emojione/64/1f55a.png b/twake/frontend/public/public/emojione/64/1f55a.png new file mode 100644 index 00000000..11692729 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f55a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f55b.png b/twake/frontend/public/public/emojione/64/1f55b.png new file mode 100644 index 00000000..e93a6486 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f55b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f55c.png b/twake/frontend/public/public/emojione/64/1f55c.png new file mode 100644 index 00000000..83efd595 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f55c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f55d.png b/twake/frontend/public/public/emojione/64/1f55d.png new file mode 100644 index 00000000..9789c934 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f55d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f55e.png b/twake/frontend/public/public/emojione/64/1f55e.png new file mode 100644 index 00000000..65fd95f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f55e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f55f.png b/twake/frontend/public/public/emojione/64/1f55f.png new file mode 100644 index 00000000..3933bb09 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f55f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f560.png b/twake/frontend/public/public/emojione/64/1f560.png new file mode 100644 index 00000000..92cc1c55 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f560.png differ diff --git a/twake/frontend/public/public/emojione/64/1f561.png b/twake/frontend/public/public/emojione/64/1f561.png new file mode 100644 index 00000000..361487bd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f561.png differ diff --git a/twake/frontend/public/public/emojione/64/1f562.png b/twake/frontend/public/public/emojione/64/1f562.png new file mode 100644 index 00000000..9b6f1660 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f562.png differ diff --git a/twake/frontend/public/public/emojione/64/1f563.png b/twake/frontend/public/public/emojione/64/1f563.png new file mode 100644 index 00000000..57e5e192 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f563.png differ diff --git a/twake/frontend/public/public/emojione/64/1f564.png b/twake/frontend/public/public/emojione/64/1f564.png new file mode 100644 index 00000000..138a8fbe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f564.png differ diff --git a/twake/frontend/public/public/emojione/64/1f565.png b/twake/frontend/public/public/emojione/64/1f565.png new file mode 100644 index 00000000..d80d9309 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f565.png differ diff --git a/twake/frontend/public/public/emojione/64/1f566.png b/twake/frontend/public/public/emojione/64/1f566.png new file mode 100644 index 00000000..85c31b09 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f566.png differ diff --git a/twake/frontend/public/public/emojione/64/1f567.png b/twake/frontend/public/public/emojione/64/1f567.png new file mode 100644 index 00000000..d97bdd1a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f567.png differ diff --git a/twake/frontend/public/public/emojione/64/1f56f.png b/twake/frontend/public/public/emojione/64/1f56f.png new file mode 100644 index 00000000..056f03cb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f56f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f570.png b/twake/frontend/public/public/emojione/64/1f570.png new file mode 100644 index 00000000..c086679a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f570.png differ diff --git a/twake/frontend/public/public/emojione/64/1f573.png b/twake/frontend/public/public/emojione/64/1f573.png new file mode 100644 index 00000000..3f0e517e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f573.png differ diff --git a/twake/frontend/public/public/emojione/64/1f574-1f3fb.png b/twake/frontend/public/public/emojione/64/1f574-1f3fb.png new file mode 100644 index 00000000..028b8f00 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f574-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f574-1f3fc.png b/twake/frontend/public/public/emojione/64/1f574-1f3fc.png new file mode 100644 index 00000000..48a95993 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f574-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f574-1f3fd.png b/twake/frontend/public/public/emojione/64/1f574-1f3fd.png new file mode 100644 index 00000000..2eba4db6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f574-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f574-1f3fe.png b/twake/frontend/public/public/emojione/64/1f574-1f3fe.png new file mode 100644 index 00000000..b4ab9f3d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f574-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f574-1f3ff.png b/twake/frontend/public/public/emojione/64/1f574-1f3ff.png new file mode 100644 index 00000000..0c8bb609 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f574-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f574.png b/twake/frontend/public/public/emojione/64/1f574.png new file mode 100644 index 00000000..90a32bac Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f574.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f575-1f3fb-2640.png new file mode 100644 index 00000000..6abb0213 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f575-1f3fb-2642.png new file mode 100644 index 00000000..1b262c3d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575-1f3fb.png b/twake/frontend/public/public/emojione/64/1f575-1f3fb.png new file mode 100644 index 00000000..1b262c3d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f575-1f3fc-2640.png new file mode 100644 index 00000000..90567def Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f575-1f3fc-2642.png new file mode 100644 index 00000000..356eb431 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575-1f3fc.png b/twake/frontend/public/public/emojione/64/1f575-1f3fc.png new file mode 100644 index 00000000..356eb431 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f575-1f3fd-2640.png new file mode 100644 index 00000000..3401135e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f575-1f3fd-2642.png new file mode 100644 index 00000000..cb69cb23 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575-1f3fd.png b/twake/frontend/public/public/emojione/64/1f575-1f3fd.png new file mode 100644 index 00000000..cb69cb23 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f575-1f3fe-2640.png new file mode 100644 index 00000000..b00c5d4e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f575-1f3fe-2642.png new file mode 100644 index 00000000..bae5b815 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575-1f3fe.png b/twake/frontend/public/public/emojione/64/1f575-1f3fe.png new file mode 100644 index 00000000..bae5b815 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f575-1f3ff-2640.png new file mode 100644 index 00000000..80d6588e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f575-1f3ff-2642.png new file mode 100644 index 00000000..501333f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575-1f3ff.png b/twake/frontend/public/public/emojione/64/1f575-1f3ff.png new file mode 100644 index 00000000..501333f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575-2640.png b/twake/frontend/public/public/emojione/64/1f575-2640.png new file mode 100644 index 00000000..e7ce7fc1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575-2642.png b/twake/frontend/public/public/emojione/64/1f575-2642.png new file mode 100644 index 00000000..73feb9b4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f575.png b/twake/frontend/public/public/emojione/64/1f575.png new file mode 100644 index 00000000..73feb9b4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f575.png differ diff --git a/twake/frontend/public/public/emojione/64/1f576.png b/twake/frontend/public/public/emojione/64/1f576.png new file mode 100644 index 00000000..2f352a03 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f576.png differ diff --git a/twake/frontend/public/public/emojione/64/1f577.png b/twake/frontend/public/public/emojione/64/1f577.png new file mode 100644 index 00000000..7f976a76 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f577.png differ diff --git a/twake/frontend/public/public/emojione/64/1f578.png b/twake/frontend/public/public/emojione/64/1f578.png new file mode 100644 index 00000000..cc44abbb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f578.png differ diff --git a/twake/frontend/public/public/emojione/64/1f579.png b/twake/frontend/public/public/emojione/64/1f579.png new file mode 100644 index 00000000..101dbd6a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f579.png differ diff --git a/twake/frontend/public/public/emojione/64/1f57a-1f3fb.png b/twake/frontend/public/public/emojione/64/1f57a-1f3fb.png new file mode 100644 index 00000000..d9252826 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f57a-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f57a-1f3fc.png b/twake/frontend/public/public/emojione/64/1f57a-1f3fc.png new file mode 100644 index 00000000..8dd5e8e8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f57a-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f57a-1f3fd.png b/twake/frontend/public/public/emojione/64/1f57a-1f3fd.png new file mode 100644 index 00000000..1c56347d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f57a-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f57a-1f3fe.png b/twake/frontend/public/public/emojione/64/1f57a-1f3fe.png new file mode 100644 index 00000000..793599f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f57a-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f57a-1f3ff.png b/twake/frontend/public/public/emojione/64/1f57a-1f3ff.png new file mode 100644 index 00000000..61eca435 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f57a-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f57a.png b/twake/frontend/public/public/emojione/64/1f57a.png new file mode 100644 index 00000000..23b343bc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f57a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f587.png b/twake/frontend/public/public/emojione/64/1f587.png new file mode 100644 index 00000000..c69fb2c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f587.png differ diff --git a/twake/frontend/public/public/emojione/64/1f58a.png b/twake/frontend/public/public/emojione/64/1f58a.png new file mode 100644 index 00000000..e0674cf9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f58a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f58b.png b/twake/frontend/public/public/emojione/64/1f58b.png new file mode 100644 index 00000000..83dfd8be Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f58b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f58c.png b/twake/frontend/public/public/emojione/64/1f58c.png new file mode 100644 index 00000000..8a68174d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f58c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f58d.png b/twake/frontend/public/public/emojione/64/1f58d.png new file mode 100644 index 00000000..340f86c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f58d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f590-1f3fb.png b/twake/frontend/public/public/emojione/64/1f590-1f3fb.png new file mode 100644 index 00000000..6beced06 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f590-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f590-1f3fc.png b/twake/frontend/public/public/emojione/64/1f590-1f3fc.png new file mode 100644 index 00000000..83c3b3aa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f590-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f590-1f3fd.png b/twake/frontend/public/public/emojione/64/1f590-1f3fd.png new file mode 100644 index 00000000..96d24099 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f590-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f590-1f3fe.png b/twake/frontend/public/public/emojione/64/1f590-1f3fe.png new file mode 100644 index 00000000..7cffa236 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f590-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f590-1f3ff.png b/twake/frontend/public/public/emojione/64/1f590-1f3ff.png new file mode 100644 index 00000000..43f5f282 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f590-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f590.png b/twake/frontend/public/public/emojione/64/1f590.png new file mode 100644 index 00000000..59d8d91f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f590.png differ diff --git a/twake/frontend/public/public/emojione/64/1f595-1f3fb.png b/twake/frontend/public/public/emojione/64/1f595-1f3fb.png new file mode 100644 index 00000000..b93371af Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f595-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f595-1f3fc.png b/twake/frontend/public/public/emojione/64/1f595-1f3fc.png new file mode 100644 index 00000000..7420991a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f595-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f595-1f3fd.png b/twake/frontend/public/public/emojione/64/1f595-1f3fd.png new file mode 100644 index 00000000..0321db16 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f595-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f595-1f3fe.png b/twake/frontend/public/public/emojione/64/1f595-1f3fe.png new file mode 100644 index 00000000..9d69160d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f595-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f595-1f3ff.png b/twake/frontend/public/public/emojione/64/1f595-1f3ff.png new file mode 100644 index 00000000..f313238e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f595-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f595.png b/twake/frontend/public/public/emojione/64/1f595.png new file mode 100644 index 00000000..018d2015 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f595.png differ diff --git a/twake/frontend/public/public/emojione/64/1f596-1f3fb.png b/twake/frontend/public/public/emojione/64/1f596-1f3fb.png new file mode 100644 index 00000000..ead1f09c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f596-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f596-1f3fc.png b/twake/frontend/public/public/emojione/64/1f596-1f3fc.png new file mode 100644 index 00000000..71ba53b7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f596-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f596-1f3fd.png b/twake/frontend/public/public/emojione/64/1f596-1f3fd.png new file mode 100644 index 00000000..47c020f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f596-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f596-1f3fe.png b/twake/frontend/public/public/emojione/64/1f596-1f3fe.png new file mode 100644 index 00000000..ab754174 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f596-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f596-1f3ff.png b/twake/frontend/public/public/emojione/64/1f596-1f3ff.png new file mode 100644 index 00000000..d03e3f65 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f596-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f596.png b/twake/frontend/public/public/emojione/64/1f596.png new file mode 100644 index 00000000..c793ba53 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f596.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5a4.png b/twake/frontend/public/public/emojione/64/1f5a4.png new file mode 100644 index 00000000..853574a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5a4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5a5.png b/twake/frontend/public/public/emojione/64/1f5a5.png new file mode 100644 index 00000000..f40eb9ab Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5a5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5a8.png b/twake/frontend/public/public/emojione/64/1f5a8.png new file mode 100644 index 00000000..f48b0f53 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5a8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5b1.png b/twake/frontend/public/public/emojione/64/1f5b1.png new file mode 100644 index 00000000..c1696dd7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5b1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5b2.png b/twake/frontend/public/public/emojione/64/1f5b2.png new file mode 100644 index 00000000..d79e1886 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5b2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5bc.png b/twake/frontend/public/public/emojione/64/1f5bc.png new file mode 100644 index 00000000..5a7ce7ac Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5bc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5c2.png b/twake/frontend/public/public/emojione/64/1f5c2.png new file mode 100644 index 00000000..5e0b751d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5c2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5c3.png b/twake/frontend/public/public/emojione/64/1f5c3.png new file mode 100644 index 00000000..7a6ca2a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5c3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5c4.png b/twake/frontend/public/public/emojione/64/1f5c4.png new file mode 100644 index 00000000..66f0e667 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5c4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5d1.png b/twake/frontend/public/public/emojione/64/1f5d1.png new file mode 100644 index 00000000..3cce5927 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5d1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5d2.png b/twake/frontend/public/public/emojione/64/1f5d2.png new file mode 100644 index 00000000..04ef02f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5d2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5d3.png b/twake/frontend/public/public/emojione/64/1f5d3.png new file mode 100644 index 00000000..53ebc985 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5d3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5dc.png b/twake/frontend/public/public/emojione/64/1f5dc.png new file mode 100644 index 00000000..55acc0c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5dc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5dd.png b/twake/frontend/public/public/emojione/64/1f5dd.png new file mode 100644 index 00000000..9181105d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5dd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5de.png b/twake/frontend/public/public/emojione/64/1f5de.png new file mode 100644 index 00000000..acd24aca Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5de.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5e1.png b/twake/frontend/public/public/emojione/64/1f5e1.png new file mode 100644 index 00000000..9206ba58 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5e1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5e3.png b/twake/frontend/public/public/emojione/64/1f5e3.png new file mode 100644 index 00000000..9cfe3362 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5e3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5e8.png b/twake/frontend/public/public/emojione/64/1f5e8.png new file mode 100644 index 00000000..e628c6ed Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5e8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5ef.png b/twake/frontend/public/public/emojione/64/1f5ef.png new file mode 100644 index 00000000..dc8b1e38 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5ef.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5f3.png b/twake/frontend/public/public/emojione/64/1f5f3.png new file mode 100644 index 00000000..184cd63a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5fa.png b/twake/frontend/public/public/emojione/64/1f5fa.png new file mode 100644 index 00000000..6f267d30 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5fa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5fb.png b/twake/frontend/public/public/emojione/64/1f5fb.png new file mode 100644 index 00000000..6c944f32 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5fc.png b/twake/frontend/public/public/emojione/64/1f5fc.png new file mode 100644 index 00000000..afc6344c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5fd.png b/twake/frontend/public/public/emojione/64/1f5fd.png new file mode 100644 index 00000000..13670fcd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5fe.png b/twake/frontend/public/public/emojione/64/1f5fe.png new file mode 100644 index 00000000..37aed379 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f5ff.png b/twake/frontend/public/public/emojione/64/1f5ff.png new file mode 100644 index 00000000..999b9bb5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f5ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f600.png b/twake/frontend/public/public/emojione/64/1f600.png new file mode 100644 index 00000000..26efffaf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f600.png differ diff --git a/twake/frontend/public/public/emojione/64/1f601.png b/twake/frontend/public/public/emojione/64/1f601.png new file mode 100644 index 00000000..95e18f5d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f601.png differ diff --git a/twake/frontend/public/public/emojione/64/1f602.png b/twake/frontend/public/public/emojione/64/1f602.png new file mode 100644 index 00000000..e10f2d3b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f602.png differ diff --git a/twake/frontend/public/public/emojione/64/1f603.png b/twake/frontend/public/public/emojione/64/1f603.png new file mode 100644 index 00000000..d6e2e213 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f603.png differ diff --git a/twake/frontend/public/public/emojione/64/1f604.png b/twake/frontend/public/public/emojione/64/1f604.png new file mode 100644 index 00000000..50c23d30 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f604.png differ diff --git a/twake/frontend/public/public/emojione/64/1f605.png b/twake/frontend/public/public/emojione/64/1f605.png new file mode 100644 index 00000000..dc4d899d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f605.png differ diff --git a/twake/frontend/public/public/emojione/64/1f606.png b/twake/frontend/public/public/emojione/64/1f606.png new file mode 100644 index 00000000..e536961d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f606.png differ diff --git a/twake/frontend/public/public/emojione/64/1f607.png b/twake/frontend/public/public/emojione/64/1f607.png new file mode 100644 index 00000000..cb8cf4e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f607.png differ diff --git a/twake/frontend/public/public/emojione/64/1f608.png b/twake/frontend/public/public/emojione/64/1f608.png new file mode 100644 index 00000000..bdccf585 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f608.png differ diff --git a/twake/frontend/public/public/emojione/64/1f609.png b/twake/frontend/public/public/emojione/64/1f609.png new file mode 100644 index 00000000..7cf0e126 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f609.png differ diff --git a/twake/frontend/public/public/emojione/64/1f60a.png b/twake/frontend/public/public/emojione/64/1f60a.png new file mode 100644 index 00000000..79dde82b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f60a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f60b.png b/twake/frontend/public/public/emojione/64/1f60b.png new file mode 100644 index 00000000..5692ccc1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f60b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f60c.png b/twake/frontend/public/public/emojione/64/1f60c.png new file mode 100644 index 00000000..cafd1cdd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f60c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f60d.png b/twake/frontend/public/public/emojione/64/1f60d.png new file mode 100644 index 00000000..86140ff1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f60d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f60e.png b/twake/frontend/public/public/emojione/64/1f60e.png new file mode 100644 index 00000000..1b583e08 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f60e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f60f.png b/twake/frontend/public/public/emojione/64/1f60f.png new file mode 100644 index 00000000..835958a4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f60f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f610.png b/twake/frontend/public/public/emojione/64/1f610.png new file mode 100644 index 00000000..7c7630ff Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f610.png differ diff --git a/twake/frontend/public/public/emojione/64/1f611.png b/twake/frontend/public/public/emojione/64/1f611.png new file mode 100644 index 00000000..ba3c3a7a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f611.png differ diff --git a/twake/frontend/public/public/emojione/64/1f612.png b/twake/frontend/public/public/emojione/64/1f612.png new file mode 100644 index 00000000..f4eed7aa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f612.png differ diff --git a/twake/frontend/public/public/emojione/64/1f613.png b/twake/frontend/public/public/emojione/64/1f613.png new file mode 100644 index 00000000..4062a4a1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f613.png differ diff --git a/twake/frontend/public/public/emojione/64/1f614.png b/twake/frontend/public/public/emojione/64/1f614.png new file mode 100644 index 00000000..56771ba9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f614.png differ diff --git a/twake/frontend/public/public/emojione/64/1f615.png b/twake/frontend/public/public/emojione/64/1f615.png new file mode 100644 index 00000000..1fb3bc51 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f615.png differ diff --git a/twake/frontend/public/public/emojione/64/1f616.png b/twake/frontend/public/public/emojione/64/1f616.png new file mode 100644 index 00000000..292fca31 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f616.png differ diff --git a/twake/frontend/public/public/emojione/64/1f617.png b/twake/frontend/public/public/emojione/64/1f617.png new file mode 100644 index 00000000..45bfa34b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f617.png differ diff --git a/twake/frontend/public/public/emojione/64/1f618.png b/twake/frontend/public/public/emojione/64/1f618.png new file mode 100644 index 00000000..8dc4cfb1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f618.png differ diff --git a/twake/frontend/public/public/emojione/64/1f619.png b/twake/frontend/public/public/emojione/64/1f619.png new file mode 100644 index 00000000..29c7fd48 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f619.png differ diff --git a/twake/frontend/public/public/emojione/64/1f61a.png b/twake/frontend/public/public/emojione/64/1f61a.png new file mode 100644 index 00000000..2a071127 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f61a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f61b.png b/twake/frontend/public/public/emojione/64/1f61b.png new file mode 100644 index 00000000..f39e8d67 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f61b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f61c.png b/twake/frontend/public/public/emojione/64/1f61c.png new file mode 100644 index 00000000..2fedde5a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f61c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f61d.png b/twake/frontend/public/public/emojione/64/1f61d.png new file mode 100644 index 00000000..8732cecc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f61d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f61e.png b/twake/frontend/public/public/emojione/64/1f61e.png new file mode 100644 index 00000000..fd839bd6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f61e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f61f.png b/twake/frontend/public/public/emojione/64/1f61f.png new file mode 100644 index 00000000..5f9fdecb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f61f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f620.png b/twake/frontend/public/public/emojione/64/1f620.png new file mode 100644 index 00000000..b9a9a57b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f620.png differ diff --git a/twake/frontend/public/public/emojione/64/1f621.png b/twake/frontend/public/public/emojione/64/1f621.png new file mode 100644 index 00000000..5f50850d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f621.png differ diff --git a/twake/frontend/public/public/emojione/64/1f622.png b/twake/frontend/public/public/emojione/64/1f622.png new file mode 100644 index 00000000..dbd45090 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f622.png differ diff --git a/twake/frontend/public/public/emojione/64/1f623.png b/twake/frontend/public/public/emojione/64/1f623.png new file mode 100644 index 00000000..e7f5bb2e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f623.png differ diff --git a/twake/frontend/public/public/emojione/64/1f624.png b/twake/frontend/public/public/emojione/64/1f624.png new file mode 100644 index 00000000..191fbdc2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f624.png differ diff --git a/twake/frontend/public/public/emojione/64/1f625.png b/twake/frontend/public/public/emojione/64/1f625.png new file mode 100644 index 00000000..c6c77c00 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f625.png differ diff --git a/twake/frontend/public/public/emojione/64/1f626.png b/twake/frontend/public/public/emojione/64/1f626.png new file mode 100644 index 00000000..5c2efbb9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f626.png differ diff --git a/twake/frontend/public/public/emojione/64/1f627.png b/twake/frontend/public/public/emojione/64/1f627.png new file mode 100644 index 00000000..d78ec3f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f627.png differ diff --git a/twake/frontend/public/public/emojione/64/1f628.png b/twake/frontend/public/public/emojione/64/1f628.png new file mode 100644 index 00000000..c889f50c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f628.png differ diff --git a/twake/frontend/public/public/emojione/64/1f629.png b/twake/frontend/public/public/emojione/64/1f629.png new file mode 100644 index 00000000..ab616905 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f629.png differ diff --git a/twake/frontend/public/public/emojione/64/1f62a.png b/twake/frontend/public/public/emojione/64/1f62a.png new file mode 100644 index 00000000..bd96828a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f62a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f62b.png b/twake/frontend/public/public/emojione/64/1f62b.png new file mode 100644 index 00000000..5c1b2de5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f62b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f62c.png b/twake/frontend/public/public/emojione/64/1f62c.png new file mode 100644 index 00000000..fedcf297 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f62c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f62d.png b/twake/frontend/public/public/emojione/64/1f62d.png new file mode 100644 index 00000000..6b7a67eb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f62d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f62e.png b/twake/frontend/public/public/emojione/64/1f62e.png new file mode 100644 index 00000000..5f2cffbe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f62e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f62f.png b/twake/frontend/public/public/emojione/64/1f62f.png new file mode 100644 index 00000000..a0449e08 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f62f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f630.png b/twake/frontend/public/public/emojione/64/1f630.png new file mode 100644 index 00000000..8a421da2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f630.png differ diff --git a/twake/frontend/public/public/emojione/64/1f631.png b/twake/frontend/public/public/emojione/64/1f631.png new file mode 100644 index 00000000..eecf031c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f631.png differ diff --git a/twake/frontend/public/public/emojione/64/1f632.png b/twake/frontend/public/public/emojione/64/1f632.png new file mode 100644 index 00000000..bb8765bd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f632.png differ diff --git a/twake/frontend/public/public/emojione/64/1f633.png b/twake/frontend/public/public/emojione/64/1f633.png new file mode 100644 index 00000000..0046f19f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f633.png differ diff --git a/twake/frontend/public/public/emojione/64/1f634.png b/twake/frontend/public/public/emojione/64/1f634.png new file mode 100644 index 00000000..6fb99295 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f634.png differ diff --git a/twake/frontend/public/public/emojione/64/1f635.png b/twake/frontend/public/public/emojione/64/1f635.png new file mode 100644 index 00000000..37bd7ce9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f635.png differ diff --git a/twake/frontend/public/public/emojione/64/1f636.png b/twake/frontend/public/public/emojione/64/1f636.png new file mode 100644 index 00000000..65bca6da Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f636.png differ diff --git a/twake/frontend/public/public/emojione/64/1f637.png b/twake/frontend/public/public/emojione/64/1f637.png new file mode 100644 index 00000000..13be2f28 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f637.png differ diff --git a/twake/frontend/public/public/emojione/64/1f638.png b/twake/frontend/public/public/emojione/64/1f638.png new file mode 100644 index 00000000..5d479d0d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f638.png differ diff --git a/twake/frontend/public/public/emojione/64/1f639.png b/twake/frontend/public/public/emojione/64/1f639.png new file mode 100644 index 00000000..15eec39f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f639.png differ diff --git a/twake/frontend/public/public/emojione/64/1f63a.png b/twake/frontend/public/public/emojione/64/1f63a.png new file mode 100644 index 00000000..fb35f7a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f63a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f63b.png b/twake/frontend/public/public/emojione/64/1f63b.png new file mode 100644 index 00000000..6aa6f5f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f63b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f63c.png b/twake/frontend/public/public/emojione/64/1f63c.png new file mode 100644 index 00000000..fa4121c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f63c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f63d.png b/twake/frontend/public/public/emojione/64/1f63d.png new file mode 100644 index 00000000..5cbfbd3c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f63d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f63e.png b/twake/frontend/public/public/emojione/64/1f63e.png new file mode 100644 index 00000000..a0122feb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f63e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f63f.png b/twake/frontend/public/public/emojione/64/1f63f.png new file mode 100644 index 00000000..9c72a952 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f63f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f640.png b/twake/frontend/public/public/emojione/64/1f640.png new file mode 100644 index 00000000..87c40dbf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f641.png b/twake/frontend/public/public/emojione/64/1f641.png new file mode 100644 index 00000000..d3acab4f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f641.png differ diff --git a/twake/frontend/public/public/emojione/64/1f642.png b/twake/frontend/public/public/emojione/64/1f642.png new file mode 100644 index 00000000..b3efeae8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f643.png b/twake/frontend/public/public/emojione/64/1f643.png new file mode 100644 index 00000000..11d318dd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f643.png differ diff --git a/twake/frontend/public/public/emojione/64/1f644.png b/twake/frontend/public/public/emojione/64/1f644.png new file mode 100644 index 00000000..eb66dbad Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f644.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f645-1f3fb-2640.png new file mode 100644 index 00000000..2e8785d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f645-1f3fb-2642.png new file mode 100644 index 00000000..a80a9fb1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645-1f3fb.png b/twake/frontend/public/public/emojione/64/1f645-1f3fb.png new file mode 100644 index 00000000..4acf85f3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f645-1f3fc-2640.png new file mode 100644 index 00000000..c303f7d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f645-1f3fc-2642.png new file mode 100644 index 00000000..f53fa9af Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645-1f3fc.png b/twake/frontend/public/public/emojione/64/1f645-1f3fc.png new file mode 100644 index 00000000..e62c9781 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f645-1f3fd-2640.png new file mode 100644 index 00000000..3ca117be Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f645-1f3fd-2642.png new file mode 100644 index 00000000..10d3a04c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645-1f3fd.png b/twake/frontend/public/public/emojione/64/1f645-1f3fd.png new file mode 100644 index 00000000..c4b97ba4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f645-1f3fe-2640.png new file mode 100644 index 00000000..d386e07d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f645-1f3fe-2642.png new file mode 100644 index 00000000..f0be4ebd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645-1f3fe.png b/twake/frontend/public/public/emojione/64/1f645-1f3fe.png new file mode 100644 index 00000000..52980a1a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f645-1f3ff-2640.png new file mode 100644 index 00000000..95986841 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f645-1f3ff-2642.png new file mode 100644 index 00000000..273643c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645-1f3ff.png b/twake/frontend/public/public/emojione/64/1f645-1f3ff.png new file mode 100644 index 00000000..3b0f33af Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645-2640.png b/twake/frontend/public/public/emojione/64/1f645-2640.png new file mode 100644 index 00000000..e31321f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645-2642.png b/twake/frontend/public/public/emojione/64/1f645-2642.png new file mode 100644 index 00000000..577fa1db Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f645.png b/twake/frontend/public/public/emojione/64/1f645.png new file mode 100644 index 00000000..e31321f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f645.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f646-1f3fb-2640.png new file mode 100644 index 00000000..81313aa6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f646-1f3fb-2642.png new file mode 100644 index 00000000..e7201392 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646-1f3fb.png b/twake/frontend/public/public/emojione/64/1f646-1f3fb.png new file mode 100644 index 00000000..20d85726 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f646-1f3fc-2640.png new file mode 100644 index 00000000..fee0e4e4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f646-1f3fc-2642.png new file mode 100644 index 00000000..3390e635 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646-1f3fc.png b/twake/frontend/public/public/emojione/64/1f646-1f3fc.png new file mode 100644 index 00000000..a120c69b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f646-1f3fd-2640.png new file mode 100644 index 00000000..c7f266a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f646-1f3fd-2642.png new file mode 100644 index 00000000..eb8367b6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646-1f3fd.png b/twake/frontend/public/public/emojione/64/1f646-1f3fd.png new file mode 100644 index 00000000..807c65fe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f646-1f3fe-2640.png new file mode 100644 index 00000000..ae972f6e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f646-1f3fe-2642.png new file mode 100644 index 00000000..3cf2a585 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646-1f3fe.png b/twake/frontend/public/public/emojione/64/1f646-1f3fe.png new file mode 100644 index 00000000..07d7cde0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f646-1f3ff-2640.png new file mode 100644 index 00000000..b07a8a22 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f646-1f3ff-2642.png new file mode 100644 index 00000000..cd04a3c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646-1f3ff.png b/twake/frontend/public/public/emojione/64/1f646-1f3ff.png new file mode 100644 index 00000000..56868dc2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646-2640.png b/twake/frontend/public/public/emojione/64/1f646-2640.png new file mode 100644 index 00000000..bff0024e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646-2642.png b/twake/frontend/public/public/emojione/64/1f646-2642.png new file mode 100644 index 00000000..d6b45606 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f646.png b/twake/frontend/public/public/emojione/64/1f646.png new file mode 100644 index 00000000..efc11b26 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f646.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f647-1f3fb-2640.png new file mode 100644 index 00000000..e3081f70 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f647-1f3fb-2642.png new file mode 100644 index 00000000..4329bbc1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647-1f3fb.png b/twake/frontend/public/public/emojione/64/1f647-1f3fb.png new file mode 100644 index 00000000..4329bbc1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f647-1f3fc-2640.png new file mode 100644 index 00000000..c971f46f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f647-1f3fc-2642.png new file mode 100644 index 00000000..b78fefc4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647-1f3fc.png b/twake/frontend/public/public/emojione/64/1f647-1f3fc.png new file mode 100644 index 00000000..b78fefc4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f647-1f3fd-2640.png new file mode 100644 index 00000000..1f0068e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f647-1f3fd-2642.png new file mode 100644 index 00000000..5cb6a229 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647-1f3fd.png b/twake/frontend/public/public/emojione/64/1f647-1f3fd.png new file mode 100644 index 00000000..5cb6a229 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f647-1f3fe-2640.png new file mode 100644 index 00000000..5bb8af42 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f647-1f3fe-2642.png new file mode 100644 index 00000000..989b5331 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647-1f3fe.png b/twake/frontend/public/public/emojione/64/1f647-1f3fe.png new file mode 100644 index 00000000..989b5331 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f647-1f3ff-2640.png new file mode 100644 index 00000000..e575b7d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f647-1f3ff-2642.png new file mode 100644 index 00000000..b4fbaace Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647-1f3ff.png b/twake/frontend/public/public/emojione/64/1f647-1f3ff.png new file mode 100644 index 00000000..b4fbaace Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647-2640.png b/twake/frontend/public/public/emojione/64/1f647-2640.png new file mode 100644 index 00000000..2ab68376 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647-2642.png b/twake/frontend/public/public/emojione/64/1f647-2642.png new file mode 100644 index 00000000..bd16c184 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f647.png b/twake/frontend/public/public/emojione/64/1f647.png new file mode 100644 index 00000000..bd16c184 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f647.png differ diff --git a/twake/frontend/public/public/emojione/64/1f648.png b/twake/frontend/public/public/emojione/64/1f648.png new file mode 100644 index 00000000..ea9c5a3f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f648.png differ diff --git a/twake/frontend/public/public/emojione/64/1f649.png b/twake/frontend/public/public/emojione/64/1f649.png new file mode 100644 index 00000000..795d6ca2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f649.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64a.png b/twake/frontend/public/public/emojione/64/1f64a.png new file mode 100644 index 00000000..3d21c2fc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f64b-1f3fb-2640.png new file mode 100644 index 00000000..5f738645 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f64b-1f3fb-2642.png new file mode 100644 index 00000000..3416813c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b-1f3fb.png b/twake/frontend/public/public/emojione/64/1f64b-1f3fb.png new file mode 100644 index 00000000..589c2c2c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f64b-1f3fc-2640.png new file mode 100644 index 00000000..ed6ccce7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f64b-1f3fc-2642.png new file mode 100644 index 00000000..294053aa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b-1f3fc.png b/twake/frontend/public/public/emojione/64/1f64b-1f3fc.png new file mode 100644 index 00000000..b9a7fa5d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f64b-1f3fd-2640.png new file mode 100644 index 00000000..e6973af2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f64b-1f3fd-2642.png new file mode 100644 index 00000000..e9ca5111 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b-1f3fd.png b/twake/frontend/public/public/emojione/64/1f64b-1f3fd.png new file mode 100644 index 00000000..582c3b69 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f64b-1f3fe-2640.png new file mode 100644 index 00000000..d912ba46 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f64b-1f3fe-2642.png new file mode 100644 index 00000000..eeef8a09 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b-1f3fe.png b/twake/frontend/public/public/emojione/64/1f64b-1f3fe.png new file mode 100644 index 00000000..da35bd3e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f64b-1f3ff-2640.png new file mode 100644 index 00000000..c2bc5055 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f64b-1f3ff-2642.png new file mode 100644 index 00000000..59a951cf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b-1f3ff.png b/twake/frontend/public/public/emojione/64/1f64b-1f3ff.png new file mode 100644 index 00000000..c0f07383 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b-2640.png b/twake/frontend/public/public/emojione/64/1f64b-2640.png new file mode 100644 index 00000000..210bb498 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b-2642.png b/twake/frontend/public/public/emojione/64/1f64b-2642.png new file mode 100644 index 00000000..528169ee Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64b.png b/twake/frontend/public/public/emojione/64/1f64b.png new file mode 100644 index 00000000..210bb498 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64c-1f3fb.png b/twake/frontend/public/public/emojione/64/1f64c-1f3fb.png new file mode 100644 index 00000000..25b46121 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64c-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64c-1f3fc.png b/twake/frontend/public/public/emojione/64/1f64c-1f3fc.png new file mode 100644 index 00000000..88c53131 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64c-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64c-1f3fd.png b/twake/frontend/public/public/emojione/64/1f64c-1f3fd.png new file mode 100644 index 00000000..e9d4743e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64c-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64c-1f3fe.png b/twake/frontend/public/public/emojione/64/1f64c-1f3fe.png new file mode 100644 index 00000000..6818efce Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64c-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64c-1f3ff.png b/twake/frontend/public/public/emojione/64/1f64c-1f3ff.png new file mode 100644 index 00000000..1129adeb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64c-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64c.png b/twake/frontend/public/public/emojione/64/1f64c.png new file mode 100644 index 00000000..283563e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f64d-1f3fb-2640.png new file mode 100644 index 00000000..28533f76 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f64d-1f3fb-2642.png new file mode 100644 index 00000000..d71bbb5b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d-1f3fb.png b/twake/frontend/public/public/emojione/64/1f64d-1f3fb.png new file mode 100644 index 00000000..2e62d40b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f64d-1f3fc-2640.png new file mode 100644 index 00000000..34e20c33 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f64d-1f3fc-2642.png new file mode 100644 index 00000000..3cbb8385 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d-1f3fc.png b/twake/frontend/public/public/emojione/64/1f64d-1f3fc.png new file mode 100644 index 00000000..69144204 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f64d-1f3fd-2640.png new file mode 100644 index 00000000..f9eedffd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f64d-1f3fd-2642.png new file mode 100644 index 00000000..ef8192fe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d-1f3fd.png b/twake/frontend/public/public/emojione/64/1f64d-1f3fd.png new file mode 100644 index 00000000..32700cbe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f64d-1f3fe-2640.png new file mode 100644 index 00000000..ae97588a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f64d-1f3fe-2642.png new file mode 100644 index 00000000..488c7f41 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d-1f3fe.png b/twake/frontend/public/public/emojione/64/1f64d-1f3fe.png new file mode 100644 index 00000000..89160239 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f64d-1f3ff-2640.png new file mode 100644 index 00000000..43ec2d93 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f64d-1f3ff-2642.png new file mode 100644 index 00000000..4625ff07 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d-1f3ff.png b/twake/frontend/public/public/emojione/64/1f64d-1f3ff.png new file mode 100644 index 00000000..59cdbfc1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d-2640.png b/twake/frontend/public/public/emojione/64/1f64d-2640.png new file mode 100644 index 00000000..1eefdfb1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d-2642.png b/twake/frontend/public/public/emojione/64/1f64d-2642.png new file mode 100644 index 00000000..d387c362 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64d.png b/twake/frontend/public/public/emojione/64/1f64d.png new file mode 100644 index 00000000..1eefdfb1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f64e-1f3fb-2640.png new file mode 100644 index 00000000..914ec377 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f64e-1f3fb-2642.png new file mode 100644 index 00000000..6fcca99b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e-1f3fb.png b/twake/frontend/public/public/emojione/64/1f64e-1f3fb.png new file mode 100644 index 00000000..914ec377 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f64e-1f3fc-2640.png new file mode 100644 index 00000000..3c3ca4b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f64e-1f3fc-2642.png new file mode 100644 index 00000000..b5fd7e83 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e-1f3fc.png b/twake/frontend/public/public/emojione/64/1f64e-1f3fc.png new file mode 100644 index 00000000..3c3ca4b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f64e-1f3fd-2640.png new file mode 100644 index 00000000..534164bf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f64e-1f3fd-2642.png new file mode 100644 index 00000000..d10fb5fd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e-1f3fd.png b/twake/frontend/public/public/emojione/64/1f64e-1f3fd.png new file mode 100644 index 00000000..534164bf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f64e-1f3fe-2640.png new file mode 100644 index 00000000..063d65e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f64e-1f3fe-2642.png new file mode 100644 index 00000000..5a9353e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e-1f3fe.png b/twake/frontend/public/public/emojione/64/1f64e-1f3fe.png new file mode 100644 index 00000000..063d65e6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f64e-1f3ff-2640.png new file mode 100644 index 00000000..d42179c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f64e-1f3ff-2642.png new file mode 100644 index 00000000..bd271491 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e-1f3ff.png b/twake/frontend/public/public/emojione/64/1f64e-1f3ff.png new file mode 100644 index 00000000..d42179c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e-2640.png b/twake/frontend/public/public/emojione/64/1f64e-2640.png new file mode 100644 index 00000000..8043faf8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e-2642.png b/twake/frontend/public/public/emojione/64/1f64e-2642.png new file mode 100644 index 00000000..6d5bcf69 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64e.png b/twake/frontend/public/public/emojione/64/1f64e.png new file mode 100644 index 00000000..8043faf8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64f-1f3fb.png b/twake/frontend/public/public/emojione/64/1f64f-1f3fb.png new file mode 100644 index 00000000..235c17db Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64f-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64f-1f3fc.png b/twake/frontend/public/public/emojione/64/1f64f-1f3fc.png new file mode 100644 index 00000000..e4b60ca9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64f-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64f-1f3fd.png b/twake/frontend/public/public/emojione/64/1f64f-1f3fd.png new file mode 100644 index 00000000..f0f90655 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64f-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64f-1f3fe.png b/twake/frontend/public/public/emojione/64/1f64f-1f3fe.png new file mode 100644 index 00000000..438f2bad Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64f-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64f-1f3ff.png b/twake/frontend/public/public/emojione/64/1f64f-1f3ff.png new file mode 100644 index 00000000..88db85f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64f-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f64f.png b/twake/frontend/public/public/emojione/64/1f64f.png new file mode 100644 index 00000000..4c59879b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f64f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f680.png b/twake/frontend/public/public/emojione/64/1f680.png new file mode 100644 index 00000000..cc9bc5c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f680.png differ diff --git a/twake/frontend/public/public/emojione/64/1f681.png b/twake/frontend/public/public/emojione/64/1f681.png new file mode 100644 index 00000000..31260650 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f681.png differ diff --git a/twake/frontend/public/public/emojione/64/1f682.png b/twake/frontend/public/public/emojione/64/1f682.png new file mode 100644 index 00000000..01079dae Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f682.png differ diff --git a/twake/frontend/public/public/emojione/64/1f683.png b/twake/frontend/public/public/emojione/64/1f683.png new file mode 100644 index 00000000..c2e92d34 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f683.png differ diff --git a/twake/frontend/public/public/emojione/64/1f684.png b/twake/frontend/public/public/emojione/64/1f684.png new file mode 100644 index 00000000..b972b148 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f684.png differ diff --git a/twake/frontend/public/public/emojione/64/1f685.png b/twake/frontend/public/public/emojione/64/1f685.png new file mode 100644 index 00000000..4e20d1c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f685.png differ diff --git a/twake/frontend/public/public/emojione/64/1f686.png b/twake/frontend/public/public/emojione/64/1f686.png new file mode 100644 index 00000000..1268c612 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f686.png differ diff --git a/twake/frontend/public/public/emojione/64/1f687.png b/twake/frontend/public/public/emojione/64/1f687.png new file mode 100644 index 00000000..a34a0cb8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f687.png differ diff --git a/twake/frontend/public/public/emojione/64/1f688.png b/twake/frontend/public/public/emojione/64/1f688.png new file mode 100644 index 00000000..c00c7295 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f688.png differ diff --git a/twake/frontend/public/public/emojione/64/1f689.png b/twake/frontend/public/public/emojione/64/1f689.png new file mode 100644 index 00000000..cc3b6dd8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f689.png differ diff --git a/twake/frontend/public/public/emojione/64/1f68a.png b/twake/frontend/public/public/emojione/64/1f68a.png new file mode 100644 index 00000000..b6568fe4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f68a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f68b.png b/twake/frontend/public/public/emojione/64/1f68b.png new file mode 100644 index 00000000..cf549898 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f68b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f68c.png b/twake/frontend/public/public/emojione/64/1f68c.png new file mode 100644 index 00000000..e37675f9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f68c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f68d.png b/twake/frontend/public/public/emojione/64/1f68d.png new file mode 100644 index 00000000..7be12ab2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f68d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f68e.png b/twake/frontend/public/public/emojione/64/1f68e.png new file mode 100644 index 00000000..54d723e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f68e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f68f.png b/twake/frontend/public/public/emojione/64/1f68f.png new file mode 100644 index 00000000..86b54bc8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f68f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f690.png b/twake/frontend/public/public/emojione/64/1f690.png new file mode 100644 index 00000000..039170cd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f690.png differ diff --git a/twake/frontend/public/public/emojione/64/1f691.png b/twake/frontend/public/public/emojione/64/1f691.png new file mode 100644 index 00000000..4e9f9665 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f691.png differ diff --git a/twake/frontend/public/public/emojione/64/1f692.png b/twake/frontend/public/public/emojione/64/1f692.png new file mode 100644 index 00000000..0db5e2b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f692.png differ diff --git a/twake/frontend/public/public/emojione/64/1f693.png b/twake/frontend/public/public/emojione/64/1f693.png new file mode 100644 index 00000000..393e5997 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f693.png differ diff --git a/twake/frontend/public/public/emojione/64/1f694.png b/twake/frontend/public/public/emojione/64/1f694.png new file mode 100644 index 00000000..3fefe020 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f694.png differ diff --git a/twake/frontend/public/public/emojione/64/1f695.png b/twake/frontend/public/public/emojione/64/1f695.png new file mode 100644 index 00000000..22b3d7d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f695.png differ diff --git a/twake/frontend/public/public/emojione/64/1f696.png b/twake/frontend/public/public/emojione/64/1f696.png new file mode 100644 index 00000000..7ac434e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f696.png differ diff --git a/twake/frontend/public/public/emojione/64/1f697.png b/twake/frontend/public/public/emojione/64/1f697.png new file mode 100644 index 00000000..6d99d9e4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f697.png differ diff --git a/twake/frontend/public/public/emojione/64/1f698.png b/twake/frontend/public/public/emojione/64/1f698.png new file mode 100644 index 00000000..82e955b9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f698.png differ diff --git a/twake/frontend/public/public/emojione/64/1f699.png b/twake/frontend/public/public/emojione/64/1f699.png new file mode 100644 index 00000000..28459d41 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f699.png differ diff --git a/twake/frontend/public/public/emojione/64/1f69a.png b/twake/frontend/public/public/emojione/64/1f69a.png new file mode 100644 index 00000000..c4a45aa1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f69a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f69b.png b/twake/frontend/public/public/emojione/64/1f69b.png new file mode 100644 index 00000000..86896eb6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f69b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f69c.png b/twake/frontend/public/public/emojione/64/1f69c.png new file mode 100644 index 00000000..788b1272 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f69c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f69d.png b/twake/frontend/public/public/emojione/64/1f69d.png new file mode 100644 index 00000000..69bb6602 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f69d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f69e.png b/twake/frontend/public/public/emojione/64/1f69e.png new file mode 100644 index 00000000..e9035f30 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f69e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f69f.png b/twake/frontend/public/public/emojione/64/1f69f.png new file mode 100644 index 00000000..b8324d50 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f69f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a0.png b/twake/frontend/public/public/emojione/64/1f6a0.png new file mode 100644 index 00000000..eb97f20f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a1.png b/twake/frontend/public/public/emojione/64/1f6a1.png new file mode 100644 index 00000000..bc4b5031 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a2.png b/twake/frontend/public/public/emojione/64/1f6a2.png new file mode 100644 index 00000000..067af1ee Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f6a3-1f3fb-2640.png new file mode 100644 index 00000000..f6021edb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f6a3-1f3fb-2642.png new file mode 100644 index 00000000..b3329ef9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3-1f3fb.png b/twake/frontend/public/public/emojione/64/1f6a3-1f3fb.png new file mode 100644 index 00000000..b3329ef9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f6a3-1f3fc-2640.png new file mode 100644 index 00000000..8ed69c63 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f6a3-1f3fc-2642.png new file mode 100644 index 00000000..fa2dab97 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3-1f3fc.png b/twake/frontend/public/public/emojione/64/1f6a3-1f3fc.png new file mode 100644 index 00000000..fa2dab97 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f6a3-1f3fd-2640.png new file mode 100644 index 00000000..4b2b230d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f6a3-1f3fd-2642.png new file mode 100644 index 00000000..92b70bca Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3-1f3fd.png b/twake/frontend/public/public/emojione/64/1f6a3-1f3fd.png new file mode 100644 index 00000000..92b70bca Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f6a3-1f3fe-2640.png new file mode 100644 index 00000000..18658b48 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f6a3-1f3fe-2642.png new file mode 100644 index 00000000..02f0fd40 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3-1f3fe.png b/twake/frontend/public/public/emojione/64/1f6a3-1f3fe.png new file mode 100644 index 00000000..02f0fd40 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f6a3-1f3ff-2640.png new file mode 100644 index 00000000..41fa1768 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f6a3-1f3ff-2642.png new file mode 100644 index 00000000..f7e7e8fa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3-1f3ff.png b/twake/frontend/public/public/emojione/64/1f6a3-1f3ff.png new file mode 100644 index 00000000..f7e7e8fa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3-2640.png b/twake/frontend/public/public/emojione/64/1f6a3-2640.png new file mode 100644 index 00000000..da180e9e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3-2642.png b/twake/frontend/public/public/emojione/64/1f6a3-2642.png new file mode 100644 index 00000000..ade4c496 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a3.png b/twake/frontend/public/public/emojione/64/1f6a3.png new file mode 100644 index 00000000..ade4c496 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a4.png b/twake/frontend/public/public/emojione/64/1f6a4.png new file mode 100644 index 00000000..d4386f41 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a5.png b/twake/frontend/public/public/emojione/64/1f6a5.png new file mode 100644 index 00000000..081d5067 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a6.png b/twake/frontend/public/public/emojione/64/1f6a6.png new file mode 100644 index 00000000..076b5c8e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a7.png b/twake/frontend/public/public/emojione/64/1f6a7.png new file mode 100644 index 00000000..44fbdec1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a8.png b/twake/frontend/public/public/emojione/64/1f6a8.png new file mode 100644 index 00000000..a952f73e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6a9.png b/twake/frontend/public/public/emojione/64/1f6a9.png new file mode 100644 index 00000000..68319a4a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6a9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6aa.png b/twake/frontend/public/public/emojione/64/1f6aa.png new file mode 100644 index 00000000..fddb1d72 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6aa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6ab.png b/twake/frontend/public/public/emojione/64/1f6ab.png new file mode 100644 index 00000000..6cf01dff Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6ab.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6ac.png b/twake/frontend/public/public/emojione/64/1f6ac.png new file mode 100644 index 00000000..7577c0d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6ac.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6ad.png b/twake/frontend/public/public/emojione/64/1f6ad.png new file mode 100644 index 00000000..b0654eaa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6ad.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6ae.png b/twake/frontend/public/public/emojione/64/1f6ae.png new file mode 100644 index 00000000..dc011d73 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6ae.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6af.png b/twake/frontend/public/public/emojione/64/1f6af.png new file mode 100644 index 00000000..52431cd9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6af.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b0.png b/twake/frontend/public/public/emojione/64/1f6b0.png new file mode 100644 index 00000000..14a5fb76 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b1.png b/twake/frontend/public/public/emojione/64/1f6b1.png new file mode 100644 index 00000000..c21850d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b2.png b/twake/frontend/public/public/emojione/64/1f6b2.png new file mode 100644 index 00000000..6fa0442a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b3.png b/twake/frontend/public/public/emojione/64/1f6b3.png new file mode 100644 index 00000000..ad02656d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f6b4-1f3fb-2640.png new file mode 100644 index 00000000..c56e0a84 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f6b4-1f3fb-2642.png new file mode 100644 index 00000000..640ec2ac Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4-1f3fb.png b/twake/frontend/public/public/emojione/64/1f6b4-1f3fb.png new file mode 100644 index 00000000..640ec2ac Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f6b4-1f3fc-2640.png new file mode 100644 index 00000000..70a677a8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f6b4-1f3fc-2642.png new file mode 100644 index 00000000..024f7601 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4-1f3fc.png b/twake/frontend/public/public/emojione/64/1f6b4-1f3fc.png new file mode 100644 index 00000000..024f7601 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f6b4-1f3fd-2640.png new file mode 100644 index 00000000..3ad1b1d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f6b4-1f3fd-2642.png new file mode 100644 index 00000000..36e02136 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4-1f3fd.png b/twake/frontend/public/public/emojione/64/1f6b4-1f3fd.png new file mode 100644 index 00000000..36e02136 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f6b4-1f3fe-2640.png new file mode 100644 index 00000000..7f49ce91 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f6b4-1f3fe-2642.png new file mode 100644 index 00000000..7c2c276e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4-1f3fe.png b/twake/frontend/public/public/emojione/64/1f6b4-1f3fe.png new file mode 100644 index 00000000..7c2c276e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f6b4-1f3ff-2640.png new file mode 100644 index 00000000..2bf73e94 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f6b4-1f3ff-2642.png new file mode 100644 index 00000000..c8027710 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4-1f3ff.png b/twake/frontend/public/public/emojione/64/1f6b4-1f3ff.png new file mode 100644 index 00000000..c8027710 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4-2640.png b/twake/frontend/public/public/emojione/64/1f6b4-2640.png new file mode 100644 index 00000000..667b0b79 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4-2642.png b/twake/frontend/public/public/emojione/64/1f6b4-2642.png new file mode 100644 index 00000000..3fb3695e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b4.png b/twake/frontend/public/public/emojione/64/1f6b4.png new file mode 100644 index 00000000..3fb3695e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f6b5-1f3fb-2640.png new file mode 100644 index 00000000..d5a9e06d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f6b5-1f3fb-2642.png new file mode 100644 index 00000000..436db6bc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5-1f3fb.png b/twake/frontend/public/public/emojione/64/1f6b5-1f3fb.png new file mode 100644 index 00000000..436db6bc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f6b5-1f3fc-2640.png new file mode 100644 index 00000000..0f70f82e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f6b5-1f3fc-2642.png new file mode 100644 index 00000000..8302f425 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5-1f3fc.png b/twake/frontend/public/public/emojione/64/1f6b5-1f3fc.png new file mode 100644 index 00000000..8302f425 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f6b5-1f3fd-2640.png new file mode 100644 index 00000000..f61f35c2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f6b5-1f3fd-2642.png new file mode 100644 index 00000000..7f83f567 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5-1f3fd.png b/twake/frontend/public/public/emojione/64/1f6b5-1f3fd.png new file mode 100644 index 00000000..7f83f567 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f6b5-1f3fe-2640.png new file mode 100644 index 00000000..8fb08f11 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f6b5-1f3fe-2642.png new file mode 100644 index 00000000..4641beda Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5-1f3fe.png b/twake/frontend/public/public/emojione/64/1f6b5-1f3fe.png new file mode 100644 index 00000000..4641beda Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f6b5-1f3ff-2640.png new file mode 100644 index 00000000..f2e65509 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f6b5-1f3ff-2642.png new file mode 100644 index 00000000..d11dcca8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5-1f3ff.png b/twake/frontend/public/public/emojione/64/1f6b5-1f3ff.png new file mode 100644 index 00000000..d11dcca8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5-2640.png b/twake/frontend/public/public/emojione/64/1f6b5-2640.png new file mode 100644 index 00000000..fb01ea93 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5-2642.png b/twake/frontend/public/public/emojione/64/1f6b5-2642.png new file mode 100644 index 00000000..e5d90d22 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b5.png b/twake/frontend/public/public/emojione/64/1f6b5.png new file mode 100644 index 00000000..e5d90d22 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f6b6-1f3fb-2640.png new file mode 100644 index 00000000..d7f7dc34 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f6b6-1f3fb-2642.png new file mode 100644 index 00000000..216b072e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6-1f3fb.png b/twake/frontend/public/public/emojione/64/1f6b6-1f3fb.png new file mode 100644 index 00000000..216b072e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f6b6-1f3fc-2640.png new file mode 100644 index 00000000..01a712fd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f6b6-1f3fc-2642.png new file mode 100644 index 00000000..22ffd3dc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6-1f3fc.png b/twake/frontend/public/public/emojione/64/1f6b6-1f3fc.png new file mode 100644 index 00000000..22ffd3dc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f6b6-1f3fd-2640.png new file mode 100644 index 00000000..2f010485 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f6b6-1f3fd-2642.png new file mode 100644 index 00000000..c38494ea Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6-1f3fd.png b/twake/frontend/public/public/emojione/64/1f6b6-1f3fd.png new file mode 100644 index 00000000..c38494ea Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f6b6-1f3fe-2640.png new file mode 100644 index 00000000..5085728e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f6b6-1f3fe-2642.png new file mode 100644 index 00000000..4f83224e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6-1f3fe.png b/twake/frontend/public/public/emojione/64/1f6b6-1f3fe.png new file mode 100644 index 00000000..4f83224e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f6b6-1f3ff-2640.png new file mode 100644 index 00000000..033e7938 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f6b6-1f3ff-2642.png new file mode 100644 index 00000000..b855e608 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6-1f3ff.png b/twake/frontend/public/public/emojione/64/1f6b6-1f3ff.png new file mode 100644 index 00000000..b855e608 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6-2640.png b/twake/frontend/public/public/emojione/64/1f6b6-2640.png new file mode 100644 index 00000000..83deac62 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6-2642.png b/twake/frontend/public/public/emojione/64/1f6b6-2642.png new file mode 100644 index 00000000..d730f97d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b6.png b/twake/frontend/public/public/emojione/64/1f6b6.png new file mode 100644 index 00000000..d730f97d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b7.png b/twake/frontend/public/public/emojione/64/1f6b7.png new file mode 100644 index 00000000..33515732 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b8.png b/twake/frontend/public/public/emojione/64/1f6b8.png new file mode 100644 index 00000000..538c1562 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6b9.png b/twake/frontend/public/public/emojione/64/1f6b9.png new file mode 100644 index 00000000..d30c95fc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6b9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6ba.png b/twake/frontend/public/public/emojione/64/1f6ba.png new file mode 100644 index 00000000..c396d709 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6ba.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6bb.png b/twake/frontend/public/public/emojione/64/1f6bb.png new file mode 100644 index 00000000..ce335623 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6bb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6bc.png b/twake/frontend/public/public/emojione/64/1f6bc.png new file mode 100644 index 00000000..af1e96fc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6bc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6bd.png b/twake/frontend/public/public/emojione/64/1f6bd.png new file mode 100644 index 00000000..22196143 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6bd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6be.png b/twake/frontend/public/public/emojione/64/1f6be.png new file mode 100644 index 00000000..6e996dfb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6be.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6bf.png b/twake/frontend/public/public/emojione/64/1f6bf.png new file mode 100644 index 00000000..1afde47a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6bf.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6c0-1f3fb.png b/twake/frontend/public/public/emojione/64/1f6c0-1f3fb.png new file mode 100644 index 00000000..b0c5100f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6c0-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6c0-1f3fc.png b/twake/frontend/public/public/emojione/64/1f6c0-1f3fc.png new file mode 100644 index 00000000..21c713e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6c0-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6c0-1f3fd.png b/twake/frontend/public/public/emojione/64/1f6c0-1f3fd.png new file mode 100644 index 00000000..db6c34b7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6c0-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6c0-1f3fe.png b/twake/frontend/public/public/emojione/64/1f6c0-1f3fe.png new file mode 100644 index 00000000..74417359 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6c0-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6c0-1f3ff.png b/twake/frontend/public/public/emojione/64/1f6c0-1f3ff.png new file mode 100644 index 00000000..7979efff Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6c0-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6c0.png b/twake/frontend/public/public/emojione/64/1f6c0.png new file mode 100644 index 00000000..17162813 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6c0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6c1.png b/twake/frontend/public/public/emojione/64/1f6c1.png new file mode 100644 index 00000000..b973175a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6c1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6c2.png b/twake/frontend/public/public/emojione/64/1f6c2.png new file mode 100644 index 00000000..6a4e59c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6c2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6c3.png b/twake/frontend/public/public/emojione/64/1f6c3.png new file mode 100644 index 00000000..3098e5c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6c3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6c4.png b/twake/frontend/public/public/emojione/64/1f6c4.png new file mode 100644 index 00000000..5163e14a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6c4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6c5.png b/twake/frontend/public/public/emojione/64/1f6c5.png new file mode 100644 index 00000000..83a90563 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6c5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6cb.png b/twake/frontend/public/public/emojione/64/1f6cb.png new file mode 100644 index 00000000..dca7e043 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6cb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6cc-1f3fb.png b/twake/frontend/public/public/emojione/64/1f6cc-1f3fb.png new file mode 100644 index 00000000..07c7f33f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6cc-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6cc-1f3fc.png b/twake/frontend/public/public/emojione/64/1f6cc-1f3fc.png new file mode 100644 index 00000000..95d5f7a1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6cc-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6cc-1f3fd.png b/twake/frontend/public/public/emojione/64/1f6cc-1f3fd.png new file mode 100644 index 00000000..e632fb4d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6cc-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6cc-1f3fe.png b/twake/frontend/public/public/emojione/64/1f6cc-1f3fe.png new file mode 100644 index 00000000..ed26a06d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6cc-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6cc-1f3ff.png b/twake/frontend/public/public/emojione/64/1f6cc-1f3ff.png new file mode 100644 index 00000000..0d66ed8b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6cc-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6cc.png b/twake/frontend/public/public/emojione/64/1f6cc.png new file mode 100644 index 00000000..9cd47414 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6cc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6cd.png b/twake/frontend/public/public/emojione/64/1f6cd.png new file mode 100644 index 00000000..73fa1a9d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6cd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6ce.png b/twake/frontend/public/public/emojione/64/1f6ce.png new file mode 100644 index 00000000..eee69ba9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6ce.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6cf.png b/twake/frontend/public/public/emojione/64/1f6cf.png new file mode 100644 index 00000000..8aa02afe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6cf.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6d0.png b/twake/frontend/public/public/emojione/64/1f6d0.png new file mode 100644 index 00000000..4546353a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6d0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6d1.png b/twake/frontend/public/public/emojione/64/1f6d1.png new file mode 100644 index 00000000..caf33d0a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6d1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6d2.png b/twake/frontend/public/public/emojione/64/1f6d2.png new file mode 100644 index 00000000..5e0819a3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6d2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6e0.png b/twake/frontend/public/public/emojione/64/1f6e0.png new file mode 100644 index 00000000..b0445eef Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6e0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6e1.png b/twake/frontend/public/public/emojione/64/1f6e1.png new file mode 100644 index 00000000..b12e5219 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6e1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6e2.png b/twake/frontend/public/public/emojione/64/1f6e2.png new file mode 100644 index 00000000..278848cf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6e2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6e3.png b/twake/frontend/public/public/emojione/64/1f6e3.png new file mode 100644 index 00000000..62b61e18 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6e3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6e4.png b/twake/frontend/public/public/emojione/64/1f6e4.png new file mode 100644 index 00000000..d2fe938e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6e4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6e5.png b/twake/frontend/public/public/emojione/64/1f6e5.png new file mode 100644 index 00000000..e0ef96e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6e5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6e9.png b/twake/frontend/public/public/emojione/64/1f6e9.png new file mode 100644 index 00000000..1c36a3fa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6e9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6eb.png b/twake/frontend/public/public/emojione/64/1f6eb.png new file mode 100644 index 00000000..5b9868cc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6ec.png b/twake/frontend/public/public/emojione/64/1f6ec.png new file mode 100644 index 00000000..48076767 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6f0.png b/twake/frontend/public/public/emojione/64/1f6f0.png new file mode 100644 index 00000000..5dc4f3b6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6f0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6f3.png b/twake/frontend/public/public/emojione/64/1f6f3.png new file mode 100644 index 00000000..ae17a46a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6f4.png b/twake/frontend/public/public/emojione/64/1f6f4.png new file mode 100644 index 00000000..dfdb8eac Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6f4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6f5.png b/twake/frontend/public/public/emojione/64/1f6f5.png new file mode 100644 index 00000000..82d0b14f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6f5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6f6.png b/twake/frontend/public/public/emojione/64/1f6f6.png new file mode 100644 index 00000000..d7bae3eb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6f6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6f7.png b/twake/frontend/public/public/emojione/64/1f6f7.png new file mode 100644 index 00000000..8e6578cd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6f8.png b/twake/frontend/public/public/emojione/64/1f6f8.png new file mode 100644 index 00000000..78cd73f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6f8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f6f9.png b/twake/frontend/public/public/emojione/64/1f6f9.png new file mode 100644 index 00000000..a860d129 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f6f9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f910.png b/twake/frontend/public/public/emojione/64/1f910.png new file mode 100644 index 00000000..07a1e1ef Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f910.png differ diff --git a/twake/frontend/public/public/emojione/64/1f911.png b/twake/frontend/public/public/emojione/64/1f911.png new file mode 100644 index 00000000..05b1af1c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f911.png differ diff --git a/twake/frontend/public/public/emojione/64/1f912.png b/twake/frontend/public/public/emojione/64/1f912.png new file mode 100644 index 00000000..783fd79d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f912.png differ diff --git a/twake/frontend/public/public/emojione/64/1f913.png b/twake/frontend/public/public/emojione/64/1f913.png new file mode 100644 index 00000000..c59cad2a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f913.png differ diff --git a/twake/frontend/public/public/emojione/64/1f914.png b/twake/frontend/public/public/emojione/64/1f914.png new file mode 100644 index 00000000..a919245a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f914.png differ diff --git a/twake/frontend/public/public/emojione/64/1f915.png b/twake/frontend/public/public/emojione/64/1f915.png new file mode 100644 index 00000000..e90f691a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f915.png differ diff --git a/twake/frontend/public/public/emojione/64/1f916.png b/twake/frontend/public/public/emojione/64/1f916.png new file mode 100644 index 00000000..29ca4078 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f916.png differ diff --git a/twake/frontend/public/public/emojione/64/1f917.png b/twake/frontend/public/public/emojione/64/1f917.png new file mode 100644 index 00000000..e4eb83c9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f917.png differ diff --git a/twake/frontend/public/public/emojione/64/1f918-1f3fb.png b/twake/frontend/public/public/emojione/64/1f918-1f3fb.png new file mode 100644 index 00000000..51a74f72 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f918-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f918-1f3fc.png b/twake/frontend/public/public/emojione/64/1f918-1f3fc.png new file mode 100644 index 00000000..2d438b12 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f918-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f918-1f3fd.png b/twake/frontend/public/public/emojione/64/1f918-1f3fd.png new file mode 100644 index 00000000..62165190 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f918-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f918-1f3fe.png b/twake/frontend/public/public/emojione/64/1f918-1f3fe.png new file mode 100644 index 00000000..35704947 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f918-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f918-1f3ff.png b/twake/frontend/public/public/emojione/64/1f918-1f3ff.png new file mode 100644 index 00000000..585b248a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f918-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f918.png b/twake/frontend/public/public/emojione/64/1f918.png new file mode 100644 index 00000000..b8b70237 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f918.png differ diff --git a/twake/frontend/public/public/emojione/64/1f919-1f3fb.png b/twake/frontend/public/public/emojione/64/1f919-1f3fb.png new file mode 100644 index 00000000..599e8764 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f919-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f919-1f3fc.png b/twake/frontend/public/public/emojione/64/1f919-1f3fc.png new file mode 100644 index 00000000..35111f0a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f919-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f919-1f3fd.png b/twake/frontend/public/public/emojione/64/1f919-1f3fd.png new file mode 100644 index 00000000..37734d8e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f919-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f919-1f3fe.png b/twake/frontend/public/public/emojione/64/1f919-1f3fe.png new file mode 100644 index 00000000..535a67fc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f919-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f919-1f3ff.png b/twake/frontend/public/public/emojione/64/1f919-1f3ff.png new file mode 100644 index 00000000..4498be7a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f919-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f919.png b/twake/frontend/public/public/emojione/64/1f919.png new file mode 100644 index 00000000..780a7329 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f919.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91a-1f3fb.png b/twake/frontend/public/public/emojione/64/1f91a-1f3fb.png new file mode 100644 index 00000000..0697b546 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91a-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91a-1f3fc.png b/twake/frontend/public/public/emojione/64/1f91a-1f3fc.png new file mode 100644 index 00000000..f98e05cb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91a-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91a-1f3fd.png b/twake/frontend/public/public/emojione/64/1f91a-1f3fd.png new file mode 100644 index 00000000..3164019d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91a-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91a-1f3fe.png b/twake/frontend/public/public/emojione/64/1f91a-1f3fe.png new file mode 100644 index 00000000..24684a98 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91a-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91a-1f3ff.png b/twake/frontend/public/public/emojione/64/1f91a-1f3ff.png new file mode 100644 index 00000000..1c915fd7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91a-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91a.png b/twake/frontend/public/public/emojione/64/1f91a.png new file mode 100644 index 00000000..4d4b7e0e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91b-1f3fb.png b/twake/frontend/public/public/emojione/64/1f91b-1f3fb.png new file mode 100644 index 00000000..31ae2c76 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91b-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91b-1f3fc.png b/twake/frontend/public/public/emojione/64/1f91b-1f3fc.png new file mode 100644 index 00000000..9b2fec3a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91b-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91b-1f3fd.png b/twake/frontend/public/public/emojione/64/1f91b-1f3fd.png new file mode 100644 index 00000000..3997ac72 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91b-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91b-1f3fe.png b/twake/frontend/public/public/emojione/64/1f91b-1f3fe.png new file mode 100644 index 00000000..a2b241ee Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91b-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91b-1f3ff.png b/twake/frontend/public/public/emojione/64/1f91b-1f3ff.png new file mode 100644 index 00000000..c8eedb41 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91b-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91b.png b/twake/frontend/public/public/emojione/64/1f91b.png new file mode 100644 index 00000000..846366bd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91c-1f3fb.png b/twake/frontend/public/public/emojione/64/1f91c-1f3fb.png new file mode 100644 index 00000000..7eef92f0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91c-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91c-1f3fc.png b/twake/frontend/public/public/emojione/64/1f91c-1f3fc.png new file mode 100644 index 00000000..0deb86ab Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91c-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91c-1f3fd.png b/twake/frontend/public/public/emojione/64/1f91c-1f3fd.png new file mode 100644 index 00000000..885896c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91c-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91c-1f3fe.png b/twake/frontend/public/public/emojione/64/1f91c-1f3fe.png new file mode 100644 index 00000000..500ce914 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91c-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91c-1f3ff.png b/twake/frontend/public/public/emojione/64/1f91c-1f3ff.png new file mode 100644 index 00000000..f464c9c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91c-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91c.png b/twake/frontend/public/public/emojione/64/1f91c.png new file mode 100644 index 00000000..17d8737e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91d.png b/twake/frontend/public/public/emojione/64/1f91d.png new file mode 100644 index 00000000..633d0907 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91e-1f3fb.png b/twake/frontend/public/public/emojione/64/1f91e-1f3fb.png new file mode 100644 index 00000000..b75f2b49 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91e-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91e-1f3fc.png b/twake/frontend/public/public/emojione/64/1f91e-1f3fc.png new file mode 100644 index 00000000..ef9c5e4b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91e-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91e-1f3fd.png b/twake/frontend/public/public/emojione/64/1f91e-1f3fd.png new file mode 100644 index 00000000..abf77783 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91e-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91e-1f3fe.png b/twake/frontend/public/public/emojione/64/1f91e-1f3fe.png new file mode 100644 index 00000000..a98a36db Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91e-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91e-1f3ff.png b/twake/frontend/public/public/emojione/64/1f91e-1f3ff.png new file mode 100644 index 00000000..d12502fb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91e-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91e.png b/twake/frontend/public/public/emojione/64/1f91e.png new file mode 100644 index 00000000..795aa7e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91f-1f3fb.png b/twake/frontend/public/public/emojione/64/1f91f-1f3fb.png new file mode 100644 index 00000000..afafb749 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91f-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91f-1f3fc.png b/twake/frontend/public/public/emojione/64/1f91f-1f3fc.png new file mode 100644 index 00000000..838111ab Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91f-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91f-1f3fd.png b/twake/frontend/public/public/emojione/64/1f91f-1f3fd.png new file mode 100644 index 00000000..d244037c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91f-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91f-1f3fe.png b/twake/frontend/public/public/emojione/64/1f91f-1f3fe.png new file mode 100644 index 00000000..ae8b7f8b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91f-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91f-1f3ff.png b/twake/frontend/public/public/emojione/64/1f91f-1f3ff.png new file mode 100644 index 00000000..df025bb0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91f-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f91f.png b/twake/frontend/public/public/emojione/64/1f91f.png new file mode 100644 index 00000000..de827790 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f91f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f920.png b/twake/frontend/public/public/emojione/64/1f920.png new file mode 100644 index 00000000..6d9c7b3d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f920.png differ diff --git a/twake/frontend/public/public/emojione/64/1f921.png b/twake/frontend/public/public/emojione/64/1f921.png new file mode 100644 index 00000000..87a984aa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f921.png differ diff --git a/twake/frontend/public/public/emojione/64/1f922.png b/twake/frontend/public/public/emojione/64/1f922.png new file mode 100644 index 00000000..5a7a0cf1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f922.png differ diff --git a/twake/frontend/public/public/emojione/64/1f923.png b/twake/frontend/public/public/emojione/64/1f923.png new file mode 100644 index 00000000..6f7c1bd5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f923.png differ diff --git a/twake/frontend/public/public/emojione/64/1f924.png b/twake/frontend/public/public/emojione/64/1f924.png new file mode 100644 index 00000000..7d501319 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f924.png differ diff --git a/twake/frontend/public/public/emojione/64/1f925.png b/twake/frontend/public/public/emojione/64/1f925.png new file mode 100644 index 00000000..dcb5dde7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f925.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f926-1f3fb-2640.png new file mode 100644 index 00000000..5a8b612b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f926-1f3fb-2642.png new file mode 100644 index 00000000..969a7b2f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926-1f3fb.png b/twake/frontend/public/public/emojione/64/1f926-1f3fb.png new file mode 100644 index 00000000..b87fe852 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f926-1f3fc-2640.png new file mode 100644 index 00000000..ee15c6e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f926-1f3fc-2642.png new file mode 100644 index 00000000..acdf1bf9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926-1f3fc.png b/twake/frontend/public/public/emojione/64/1f926-1f3fc.png new file mode 100644 index 00000000..ee15c6e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f926-1f3fd-2640.png new file mode 100644 index 00000000..97208182 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f926-1f3fd-2642.png new file mode 100644 index 00000000..1ade9d4e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926-1f3fd.png b/twake/frontend/public/public/emojione/64/1f926-1f3fd.png new file mode 100644 index 00000000..75d0bccc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f926-1f3fe-2640.png new file mode 100644 index 00000000..1fd44951 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f926-1f3fe-2642.png new file mode 100644 index 00000000..c0001b11 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926-1f3fe.png b/twake/frontend/public/public/emojione/64/1f926-1f3fe.png new file mode 100644 index 00000000..67886e3e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f926-1f3ff-2640.png new file mode 100644 index 00000000..aba121c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f926-1f3ff-2642.png new file mode 100644 index 00000000..ba8e5c13 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926-1f3ff.png b/twake/frontend/public/public/emojione/64/1f926-1f3ff.png new file mode 100644 index 00000000..bf133003 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926-2640.png b/twake/frontend/public/public/emojione/64/1f926-2640.png new file mode 100644 index 00000000..59359b23 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926-2642.png b/twake/frontend/public/public/emojione/64/1f926-2642.png new file mode 100644 index 00000000..97e3ea43 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f926.png b/twake/frontend/public/public/emojione/64/1f926.png new file mode 100644 index 00000000..59359b23 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f926.png differ diff --git a/twake/frontend/public/public/emojione/64/1f927.png b/twake/frontend/public/public/emojione/64/1f927.png new file mode 100644 index 00000000..0940ac3c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f927.png differ diff --git a/twake/frontend/public/public/emojione/64/1f928.png b/twake/frontend/public/public/emojione/64/1f928.png new file mode 100644 index 00000000..4da4fbf4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f928.png differ diff --git a/twake/frontend/public/public/emojione/64/1f929.png b/twake/frontend/public/public/emojione/64/1f929.png new file mode 100644 index 00000000..d9c5621f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f929.png differ diff --git a/twake/frontend/public/public/emojione/64/1f92a.png b/twake/frontend/public/public/emojione/64/1f92a.png new file mode 100644 index 00000000..37c3c3b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f92a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f92b.png b/twake/frontend/public/public/emojione/64/1f92b.png new file mode 100644 index 00000000..b67e0a75 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f92b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f92c.png b/twake/frontend/public/public/emojione/64/1f92c.png new file mode 100644 index 00000000..27eb56b9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f92c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f92d.png b/twake/frontend/public/public/emojione/64/1f92d.png new file mode 100644 index 00000000..20b7f272 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f92d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f92e.png b/twake/frontend/public/public/emojione/64/1f92e.png new file mode 100644 index 00000000..df33a58b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f92e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f92f.png b/twake/frontend/public/public/emojione/64/1f92f.png new file mode 100644 index 00000000..aede03d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f92f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f930-1f3fb.png b/twake/frontend/public/public/emojione/64/1f930-1f3fb.png new file mode 100644 index 00000000..ffd91e2c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f930-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f930-1f3fc.png b/twake/frontend/public/public/emojione/64/1f930-1f3fc.png new file mode 100644 index 00000000..4374bc58 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f930-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f930-1f3fd.png b/twake/frontend/public/public/emojione/64/1f930-1f3fd.png new file mode 100644 index 00000000..fdb3b414 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f930-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f930-1f3fe.png b/twake/frontend/public/public/emojione/64/1f930-1f3fe.png new file mode 100644 index 00000000..8a28fd62 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f930-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f930-1f3ff.png b/twake/frontend/public/public/emojione/64/1f930-1f3ff.png new file mode 100644 index 00000000..6ae1f70a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f930-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f930.png b/twake/frontend/public/public/emojione/64/1f930.png new file mode 100644 index 00000000..26e171a4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f930.png differ diff --git a/twake/frontend/public/public/emojione/64/1f931-1f3fb.png b/twake/frontend/public/public/emojione/64/1f931-1f3fb.png new file mode 100644 index 00000000..c590366e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f931-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f931-1f3fc.png b/twake/frontend/public/public/emojione/64/1f931-1f3fc.png new file mode 100644 index 00000000..b7153f01 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f931-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f931-1f3fd.png b/twake/frontend/public/public/emojione/64/1f931-1f3fd.png new file mode 100644 index 00000000..6394b7d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f931-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f931-1f3fe.png b/twake/frontend/public/public/emojione/64/1f931-1f3fe.png new file mode 100644 index 00000000..7bbe1a00 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f931-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f931-1f3ff.png b/twake/frontend/public/public/emojione/64/1f931-1f3ff.png new file mode 100644 index 00000000..2945f4f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f931-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f931.png b/twake/frontend/public/public/emojione/64/1f931.png new file mode 100644 index 00000000..8b9eadc8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f931.png differ diff --git a/twake/frontend/public/public/emojione/64/1f932-1f3fb.png b/twake/frontend/public/public/emojione/64/1f932-1f3fb.png new file mode 100644 index 00000000..19fa1332 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f932-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f932-1f3fc.png b/twake/frontend/public/public/emojione/64/1f932-1f3fc.png new file mode 100644 index 00000000..83df4501 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f932-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f932-1f3fd.png b/twake/frontend/public/public/emojione/64/1f932-1f3fd.png new file mode 100644 index 00000000..88b3d8b6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f932-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f932-1f3fe.png b/twake/frontend/public/public/emojione/64/1f932-1f3fe.png new file mode 100644 index 00000000..cbe540da Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f932-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f932-1f3ff.png b/twake/frontend/public/public/emojione/64/1f932-1f3ff.png new file mode 100644 index 00000000..0c7e6413 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f932-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f932.png b/twake/frontend/public/public/emojione/64/1f932.png new file mode 100644 index 00000000..d1b2cdcb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f932.png differ diff --git a/twake/frontend/public/public/emojione/64/1f933-1f3fb.png b/twake/frontend/public/public/emojione/64/1f933-1f3fb.png new file mode 100644 index 00000000..5a0cc3b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f933-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f933-1f3fc.png b/twake/frontend/public/public/emojione/64/1f933-1f3fc.png new file mode 100644 index 00000000..06fa5a9f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f933-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f933-1f3fd.png b/twake/frontend/public/public/emojione/64/1f933-1f3fd.png new file mode 100644 index 00000000..b48110aa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f933-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f933-1f3fe.png b/twake/frontend/public/public/emojione/64/1f933-1f3fe.png new file mode 100644 index 00000000..390c61f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f933-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f933-1f3ff.png b/twake/frontend/public/public/emojione/64/1f933-1f3ff.png new file mode 100644 index 00000000..4ea8cf37 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f933-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f933.png b/twake/frontend/public/public/emojione/64/1f933.png new file mode 100644 index 00000000..16342249 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f933.png differ diff --git a/twake/frontend/public/public/emojione/64/1f934-1f3fb.png b/twake/frontend/public/public/emojione/64/1f934-1f3fb.png new file mode 100644 index 00000000..4c85668c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f934-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f934-1f3fc.png b/twake/frontend/public/public/emojione/64/1f934-1f3fc.png new file mode 100644 index 00000000..1786094e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f934-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f934-1f3fd.png b/twake/frontend/public/public/emojione/64/1f934-1f3fd.png new file mode 100644 index 00000000..96e72818 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f934-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f934-1f3fe.png b/twake/frontend/public/public/emojione/64/1f934-1f3fe.png new file mode 100644 index 00000000..4785191f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f934-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f934-1f3ff.png b/twake/frontend/public/public/emojione/64/1f934-1f3ff.png new file mode 100644 index 00000000..2bba2ee7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f934-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f934.png b/twake/frontend/public/public/emojione/64/1f934.png new file mode 100644 index 00000000..4eb97ac4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f934.png differ diff --git a/twake/frontend/public/public/emojione/64/1f935-1f3fb.png b/twake/frontend/public/public/emojione/64/1f935-1f3fb.png new file mode 100644 index 00000000..3e3cb97b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f935-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f935-1f3fc.png b/twake/frontend/public/public/emojione/64/1f935-1f3fc.png new file mode 100644 index 00000000..b311a202 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f935-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f935-1f3fd.png b/twake/frontend/public/public/emojione/64/1f935-1f3fd.png new file mode 100644 index 00000000..6fda6049 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f935-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f935-1f3fe.png b/twake/frontend/public/public/emojione/64/1f935-1f3fe.png new file mode 100644 index 00000000..93a682ab Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f935-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f935-1f3ff.png b/twake/frontend/public/public/emojione/64/1f935-1f3ff.png new file mode 100644 index 00000000..0af0b33c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f935-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f935.png b/twake/frontend/public/public/emojione/64/1f935.png new file mode 100644 index 00000000..068eac6b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f935.png differ diff --git a/twake/frontend/public/public/emojione/64/1f936-1f3fb.png b/twake/frontend/public/public/emojione/64/1f936-1f3fb.png new file mode 100644 index 00000000..f58a32a2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f936-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f936-1f3fc.png b/twake/frontend/public/public/emojione/64/1f936-1f3fc.png new file mode 100644 index 00000000..fbb82548 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f936-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f936-1f3fd.png b/twake/frontend/public/public/emojione/64/1f936-1f3fd.png new file mode 100644 index 00000000..d9726aaf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f936-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f936-1f3fe.png b/twake/frontend/public/public/emojione/64/1f936-1f3fe.png new file mode 100644 index 00000000..593ba5b6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f936-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f936-1f3ff.png b/twake/frontend/public/public/emojione/64/1f936-1f3ff.png new file mode 100644 index 00000000..c19d003e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f936-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f936.png b/twake/frontend/public/public/emojione/64/1f936.png new file mode 100644 index 00000000..58e744e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f936.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f937-1f3fb-2640.png new file mode 100644 index 00000000..230e4af3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f937-1f3fb-2642.png new file mode 100644 index 00000000..ea41aa33 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937-1f3fb.png b/twake/frontend/public/public/emojione/64/1f937-1f3fb.png new file mode 100644 index 00000000..83c4fba4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f937-1f3fc-2640.png new file mode 100644 index 00000000..042d6528 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f937-1f3fc-2642.png new file mode 100644 index 00000000..baef88d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937-1f3fc.png b/twake/frontend/public/public/emojione/64/1f937-1f3fc.png new file mode 100644 index 00000000..49679e9e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f937-1f3fd-2640.png new file mode 100644 index 00000000..556c0336 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f937-1f3fd-2642.png new file mode 100644 index 00000000..763dd2c9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937-1f3fd.png b/twake/frontend/public/public/emojione/64/1f937-1f3fd.png new file mode 100644 index 00000000..56336c69 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f937-1f3fe-2640.png new file mode 100644 index 00000000..cc629a38 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f937-1f3fe-2642.png new file mode 100644 index 00000000..969d3e84 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937-1f3fe.png b/twake/frontend/public/public/emojione/64/1f937-1f3fe.png new file mode 100644 index 00000000..5400ccfb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f937-1f3ff-2640.png new file mode 100644 index 00000000..e4c35311 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f937-1f3ff-2642.png new file mode 100644 index 00000000..b5c4f891 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937-1f3ff.png b/twake/frontend/public/public/emojione/64/1f937-1f3ff.png new file mode 100644 index 00000000..1a971800 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937-2640.png b/twake/frontend/public/public/emojione/64/1f937-2640.png new file mode 100644 index 00000000..a8137f89 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937-2642.png b/twake/frontend/public/public/emojione/64/1f937-2642.png new file mode 100644 index 00000000..8d9a7a98 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f937.png b/twake/frontend/public/public/emojione/64/1f937.png new file mode 100644 index 00000000..a8137f89 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f937.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f938-1f3fb-2640.png new file mode 100644 index 00000000..7d2865c5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f938-1f3fb-2642.png new file mode 100644 index 00000000..42a23d1e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938-1f3fb.png b/twake/frontend/public/public/emojione/64/1f938-1f3fb.png new file mode 100644 index 00000000..42a23d1e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f938-1f3fc-2640.png new file mode 100644 index 00000000..4b033714 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f938-1f3fc-2642.png new file mode 100644 index 00000000..1e4b358e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938-1f3fc.png b/twake/frontend/public/public/emojione/64/1f938-1f3fc.png new file mode 100644 index 00000000..1e4b358e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f938-1f3fd-2640.png new file mode 100644 index 00000000..a8168c78 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f938-1f3fd-2642.png new file mode 100644 index 00000000..9202163f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938-1f3fd.png b/twake/frontend/public/public/emojione/64/1f938-1f3fd.png new file mode 100644 index 00000000..9202163f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f938-1f3fe-2640.png new file mode 100644 index 00000000..54896ff0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f938-1f3fe-2642.png new file mode 100644 index 00000000..22e5d703 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938-1f3fe.png b/twake/frontend/public/public/emojione/64/1f938-1f3fe.png new file mode 100644 index 00000000..22e5d703 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f938-1f3ff-2640.png new file mode 100644 index 00000000..761dfe8b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f938-1f3ff-2642.png new file mode 100644 index 00000000..5ebce676 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938-1f3ff.png b/twake/frontend/public/public/emojione/64/1f938-1f3ff.png new file mode 100644 index 00000000..5ebce676 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938-2640.png b/twake/frontend/public/public/emojione/64/1f938-2640.png new file mode 100644 index 00000000..b2ca8036 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938-2642.png b/twake/frontend/public/public/emojione/64/1f938-2642.png new file mode 100644 index 00000000..47cc14d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f938.png b/twake/frontend/public/public/emojione/64/1f938.png new file mode 100644 index 00000000..b2ca8036 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f938.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f939-1f3fb-2640.png new file mode 100644 index 00000000..b8bd564a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f939-1f3fb-2642.png new file mode 100644 index 00000000..b92b8bf8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939-1f3fb.png b/twake/frontend/public/public/emojione/64/1f939-1f3fb.png new file mode 100644 index 00000000..b92b8bf8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f939-1f3fc-2640.png new file mode 100644 index 00000000..77925c81 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f939-1f3fc-2642.png new file mode 100644 index 00000000..f784f904 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939-1f3fc.png b/twake/frontend/public/public/emojione/64/1f939-1f3fc.png new file mode 100644 index 00000000..f784f904 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f939-1f3fd-2640.png new file mode 100644 index 00000000..0ddf415c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f939-1f3fd-2642.png new file mode 100644 index 00000000..18a07201 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939-1f3fd.png b/twake/frontend/public/public/emojione/64/1f939-1f3fd.png new file mode 100644 index 00000000..18a07201 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f939-1f3fe-2640.png new file mode 100644 index 00000000..be860533 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f939-1f3fe-2642.png new file mode 100644 index 00000000..c09198e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939-1f3fe.png b/twake/frontend/public/public/emojione/64/1f939-1f3fe.png new file mode 100644 index 00000000..c09198e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f939-1f3ff-2640.png new file mode 100644 index 00000000..6ed4ab91 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f939-1f3ff-2642.png new file mode 100644 index 00000000..eaaabf7b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939-1f3ff.png b/twake/frontend/public/public/emojione/64/1f939-1f3ff.png new file mode 100644 index 00000000..eaaabf7b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939-2640.png b/twake/frontend/public/public/emojione/64/1f939-2640.png new file mode 100644 index 00000000..db43961d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939-2642.png b/twake/frontend/public/public/emojione/64/1f939-2642.png new file mode 100644 index 00000000..5eff353c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f939.png b/twake/frontend/public/public/emojione/64/1f939.png new file mode 100644 index 00000000..5eff353c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f939.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93a.png b/twake/frontend/public/public/emojione/64/1f93a.png new file mode 100644 index 00000000..9a772138 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93c-2640.png b/twake/frontend/public/public/emojione/64/1f93c-2640.png new file mode 100644 index 00000000..ce1ccdec Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93c-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93c-2642.png b/twake/frontend/public/public/emojione/64/1f93c-2642.png new file mode 100644 index 00000000..b3f1379b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93c-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93c.png b/twake/frontend/public/public/emojione/64/1f93c.png new file mode 100644 index 00000000..b3f1379b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f93d-1f3fb-2640.png new file mode 100644 index 00000000..5d7049ce Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f93d-1f3fb-2642.png new file mode 100644 index 00000000..2e6c74da Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d-1f3fb.png b/twake/frontend/public/public/emojione/64/1f93d-1f3fb.png new file mode 100644 index 00000000..2e6c74da Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f93d-1f3fc-2640.png new file mode 100644 index 00000000..34c0e917 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f93d-1f3fc-2642.png new file mode 100644 index 00000000..7a810395 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d-1f3fc.png b/twake/frontend/public/public/emojione/64/1f93d-1f3fc.png new file mode 100644 index 00000000..7a810395 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f93d-1f3fd-2640.png new file mode 100644 index 00000000..14382ed1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f93d-1f3fd-2642.png new file mode 100644 index 00000000..eabe3bdd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d-1f3fd.png b/twake/frontend/public/public/emojione/64/1f93d-1f3fd.png new file mode 100644 index 00000000..eabe3bdd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f93d-1f3fe-2640.png new file mode 100644 index 00000000..d1fb9818 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f93d-1f3fe-2642.png new file mode 100644 index 00000000..425bab6f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d-1f3fe.png b/twake/frontend/public/public/emojione/64/1f93d-1f3fe.png new file mode 100644 index 00000000..425bab6f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f93d-1f3ff-2640.png new file mode 100644 index 00000000..21d0522f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f93d-1f3ff-2642.png new file mode 100644 index 00000000..fcd48d34 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d-1f3ff.png b/twake/frontend/public/public/emojione/64/1f93d-1f3ff.png new file mode 100644 index 00000000..fcd48d34 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d-2640.png b/twake/frontend/public/public/emojione/64/1f93d-2640.png new file mode 100644 index 00000000..f9d8a983 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d-2642.png b/twake/frontend/public/public/emojione/64/1f93d-2642.png new file mode 100644 index 00000000..51f8cf56 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93d.png b/twake/frontend/public/public/emojione/64/1f93d.png new file mode 100644 index 00000000..51f8cf56 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f93e-1f3fb-2640.png new file mode 100644 index 00000000..1af724d2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f93e-1f3fb-2642.png new file mode 100644 index 00000000..8a6ae664 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e-1f3fb.png b/twake/frontend/public/public/emojione/64/1f93e-1f3fb.png new file mode 100644 index 00000000..8a6ae664 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f93e-1f3fc-2640.png new file mode 100644 index 00000000..4567c04f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f93e-1f3fc-2642.png new file mode 100644 index 00000000..eeaee32f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e-1f3fc.png b/twake/frontend/public/public/emojione/64/1f93e-1f3fc.png new file mode 100644 index 00000000..eeaee32f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f93e-1f3fd-2640.png new file mode 100644 index 00000000..6108ef97 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f93e-1f3fd-2642.png new file mode 100644 index 00000000..a71c906b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e-1f3fd.png b/twake/frontend/public/public/emojione/64/1f93e-1f3fd.png new file mode 100644 index 00000000..a71c906b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f93e-1f3fe-2640.png new file mode 100644 index 00000000..d13cd2bf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f93e-1f3fe-2642.png new file mode 100644 index 00000000..73d6426b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e-1f3fe.png b/twake/frontend/public/public/emojione/64/1f93e-1f3fe.png new file mode 100644 index 00000000..73d6426b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f93e-1f3ff-2640.png new file mode 100644 index 00000000..442423f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f93e-1f3ff-2642.png new file mode 100644 index 00000000..06d54677 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e-1f3ff.png b/twake/frontend/public/public/emojione/64/1f93e-1f3ff.png new file mode 100644 index 00000000..06d54677 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e-2640.png b/twake/frontend/public/public/emojione/64/1f93e-2640.png new file mode 100644 index 00000000..23eb99f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e-2642.png b/twake/frontend/public/public/emojione/64/1f93e-2642.png new file mode 100644 index 00000000..2b85289d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f93e.png b/twake/frontend/public/public/emojione/64/1f93e.png new file mode 100644 index 00000000..2b85289d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f93e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f940.png b/twake/frontend/public/public/emojione/64/1f940.png new file mode 100644 index 00000000..416b937f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f940.png differ diff --git a/twake/frontend/public/public/emojione/64/1f941.png b/twake/frontend/public/public/emojione/64/1f941.png new file mode 100644 index 00000000..7da7ae56 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f941.png differ diff --git a/twake/frontend/public/public/emojione/64/1f942.png b/twake/frontend/public/public/emojione/64/1f942.png new file mode 100644 index 00000000..c6328007 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f942.png differ diff --git a/twake/frontend/public/public/emojione/64/1f943.png b/twake/frontend/public/public/emojione/64/1f943.png new file mode 100644 index 00000000..bee8b273 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f943.png differ diff --git a/twake/frontend/public/public/emojione/64/1f944.png b/twake/frontend/public/public/emojione/64/1f944.png new file mode 100644 index 00000000..0c947e0e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f944.png differ diff --git a/twake/frontend/public/public/emojione/64/1f945.png b/twake/frontend/public/public/emojione/64/1f945.png new file mode 100644 index 00000000..5b4344e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f945.png differ diff --git a/twake/frontend/public/public/emojione/64/1f947.png b/twake/frontend/public/public/emojione/64/1f947.png new file mode 100644 index 00000000..5cf55804 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f947.png differ diff --git a/twake/frontend/public/public/emojione/64/1f948.png b/twake/frontend/public/public/emojione/64/1f948.png new file mode 100644 index 00000000..530ba37c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f948.png differ diff --git a/twake/frontend/public/public/emojione/64/1f949.png b/twake/frontend/public/public/emojione/64/1f949.png new file mode 100644 index 00000000..ed955f36 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f949.png differ diff --git a/twake/frontend/public/public/emojione/64/1f94a.png b/twake/frontend/public/public/emojione/64/1f94a.png new file mode 100644 index 00000000..c514a538 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f94a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f94b.png b/twake/frontend/public/public/emojione/64/1f94b.png new file mode 100644 index 00000000..8e2b25b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f94b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f94c.png b/twake/frontend/public/public/emojione/64/1f94c.png new file mode 100644 index 00000000..ade22f37 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f94c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f94d.png b/twake/frontend/public/public/emojione/64/1f94d.png new file mode 100644 index 00000000..700a4402 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f94d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f94e.png b/twake/frontend/public/public/emojione/64/1f94e.png new file mode 100644 index 00000000..d35a398b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f94e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f94f.png b/twake/frontend/public/public/emojione/64/1f94f.png new file mode 100644 index 00000000..770ad768 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f94f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f950.png b/twake/frontend/public/public/emojione/64/1f950.png new file mode 100644 index 00000000..39040317 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f950.png differ diff --git a/twake/frontend/public/public/emojione/64/1f951.png b/twake/frontend/public/public/emojione/64/1f951.png new file mode 100644 index 00000000..a866a19c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f951.png differ diff --git a/twake/frontend/public/public/emojione/64/1f952.png b/twake/frontend/public/public/emojione/64/1f952.png new file mode 100644 index 00000000..c24b355c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f952.png differ diff --git a/twake/frontend/public/public/emojione/64/1f953.png b/twake/frontend/public/public/emojione/64/1f953.png new file mode 100644 index 00000000..ca353133 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f953.png differ diff --git a/twake/frontend/public/public/emojione/64/1f954.png b/twake/frontend/public/public/emojione/64/1f954.png new file mode 100644 index 00000000..ac6bc5a4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f954.png differ diff --git a/twake/frontend/public/public/emojione/64/1f955.png b/twake/frontend/public/public/emojione/64/1f955.png new file mode 100644 index 00000000..09d35a7b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f955.png differ diff --git a/twake/frontend/public/public/emojione/64/1f956.png b/twake/frontend/public/public/emojione/64/1f956.png new file mode 100644 index 00000000..4e0a7696 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f956.png differ diff --git a/twake/frontend/public/public/emojione/64/1f957.png b/twake/frontend/public/public/emojione/64/1f957.png new file mode 100644 index 00000000..27d63060 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f957.png differ diff --git a/twake/frontend/public/public/emojione/64/1f958.png b/twake/frontend/public/public/emojione/64/1f958.png new file mode 100644 index 00000000..6d2cbabc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f958.png differ diff --git a/twake/frontend/public/public/emojione/64/1f959.png b/twake/frontend/public/public/emojione/64/1f959.png new file mode 100644 index 00000000..83cd680d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f959.png differ diff --git a/twake/frontend/public/public/emojione/64/1f95a.png b/twake/frontend/public/public/emojione/64/1f95a.png new file mode 100644 index 00000000..4fc93644 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f95a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f95b.png b/twake/frontend/public/public/emojione/64/1f95b.png new file mode 100644 index 00000000..e341353b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f95b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f95c.png b/twake/frontend/public/public/emojione/64/1f95c.png new file mode 100644 index 00000000..d53fbb8a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f95c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f95d.png b/twake/frontend/public/public/emojione/64/1f95d.png new file mode 100644 index 00000000..656802a8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f95d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f95e.png b/twake/frontend/public/public/emojione/64/1f95e.png new file mode 100644 index 00000000..dfc6a4c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f95e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f95f.png b/twake/frontend/public/public/emojione/64/1f95f.png new file mode 100644 index 00000000..a8abab45 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f95f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f960.png b/twake/frontend/public/public/emojione/64/1f960.png new file mode 100644 index 00000000..0dda2863 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f960.png differ diff --git a/twake/frontend/public/public/emojione/64/1f961.png b/twake/frontend/public/public/emojione/64/1f961.png new file mode 100644 index 00000000..c6870d08 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f961.png differ diff --git a/twake/frontend/public/public/emojione/64/1f962.png b/twake/frontend/public/public/emojione/64/1f962.png new file mode 100644 index 00000000..d1a20acc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f962.png differ diff --git a/twake/frontend/public/public/emojione/64/1f963.png b/twake/frontend/public/public/emojione/64/1f963.png new file mode 100644 index 00000000..5076ec38 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f963.png differ diff --git a/twake/frontend/public/public/emojione/64/1f964.png b/twake/frontend/public/public/emojione/64/1f964.png new file mode 100644 index 00000000..2cb4d78a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f964.png differ diff --git a/twake/frontend/public/public/emojione/64/1f965.png b/twake/frontend/public/public/emojione/64/1f965.png new file mode 100644 index 00000000..c9357248 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f965.png differ diff --git a/twake/frontend/public/public/emojione/64/1f966.png b/twake/frontend/public/public/emojione/64/1f966.png new file mode 100644 index 00000000..3849ee9e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f966.png differ diff --git a/twake/frontend/public/public/emojione/64/1f967.png b/twake/frontend/public/public/emojione/64/1f967.png new file mode 100644 index 00000000..8d73947a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f967.png differ diff --git a/twake/frontend/public/public/emojione/64/1f968.png b/twake/frontend/public/public/emojione/64/1f968.png new file mode 100644 index 00000000..3ca66709 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f968.png differ diff --git a/twake/frontend/public/public/emojione/64/1f969.png b/twake/frontend/public/public/emojione/64/1f969.png new file mode 100644 index 00000000..1abf1556 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f969.png differ diff --git a/twake/frontend/public/public/emojione/64/1f96a.png b/twake/frontend/public/public/emojione/64/1f96a.png new file mode 100644 index 00000000..4a8eac8c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f96a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f96b.png b/twake/frontend/public/public/emojione/64/1f96b.png new file mode 100644 index 00000000..2381ceae Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f96b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f96c.png b/twake/frontend/public/public/emojione/64/1f96c.png new file mode 100644 index 00000000..2b04056e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f96c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f96d.png b/twake/frontend/public/public/emojione/64/1f96d.png new file mode 100644 index 00000000..04305472 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f96d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f96e.png b/twake/frontend/public/public/emojione/64/1f96e.png new file mode 100644 index 00000000..3ae0eb80 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f96e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f96f.png b/twake/frontend/public/public/emojione/64/1f96f.png new file mode 100644 index 00000000..184955d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f96f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f970.png b/twake/frontend/public/public/emojione/64/1f970.png new file mode 100644 index 00000000..2f222712 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f970.png differ diff --git a/twake/frontend/public/public/emojione/64/1f973.png b/twake/frontend/public/public/emojione/64/1f973.png new file mode 100644 index 00000000..9250e500 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f973.png differ diff --git a/twake/frontend/public/public/emojione/64/1f974.png b/twake/frontend/public/public/emojione/64/1f974.png new file mode 100644 index 00000000..2bbe1e77 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f974.png differ diff --git a/twake/frontend/public/public/emojione/64/1f975.png b/twake/frontend/public/public/emojione/64/1f975.png new file mode 100644 index 00000000..3da680fe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f975.png differ diff --git a/twake/frontend/public/public/emojione/64/1f976.png b/twake/frontend/public/public/emojione/64/1f976.png new file mode 100644 index 00000000..5508a30a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f976.png differ diff --git a/twake/frontend/public/public/emojione/64/1f97a.png b/twake/frontend/public/public/emojione/64/1f97a.png new file mode 100644 index 00000000..c74d2b46 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f97a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f97c.png b/twake/frontend/public/public/emojione/64/1f97c.png new file mode 100644 index 00000000..61a6d627 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f97c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f97d.png b/twake/frontend/public/public/emojione/64/1f97d.png new file mode 100644 index 00000000..65b20055 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f97d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f97e.png b/twake/frontend/public/public/emojione/64/1f97e.png new file mode 100644 index 00000000..561d947a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f97e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f97f.png b/twake/frontend/public/public/emojione/64/1f97f.png new file mode 100644 index 00000000..2fafee1d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f97f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f980.png b/twake/frontend/public/public/emojione/64/1f980.png new file mode 100644 index 00000000..0a96b016 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f980.png differ diff --git a/twake/frontend/public/public/emojione/64/1f981.png b/twake/frontend/public/public/emojione/64/1f981.png new file mode 100644 index 00000000..fb960f77 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f981.png differ diff --git a/twake/frontend/public/public/emojione/64/1f982.png b/twake/frontend/public/public/emojione/64/1f982.png new file mode 100644 index 00000000..8da9e0e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f982.png differ diff --git a/twake/frontend/public/public/emojione/64/1f983.png b/twake/frontend/public/public/emojione/64/1f983.png new file mode 100644 index 00000000..d268a3c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f983.png differ diff --git a/twake/frontend/public/public/emojione/64/1f984.png b/twake/frontend/public/public/emojione/64/1f984.png new file mode 100644 index 00000000..bdd7a99e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f984.png differ diff --git a/twake/frontend/public/public/emojione/64/1f985.png b/twake/frontend/public/public/emojione/64/1f985.png new file mode 100644 index 00000000..33abdefa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f985.png differ diff --git a/twake/frontend/public/public/emojione/64/1f986.png b/twake/frontend/public/public/emojione/64/1f986.png new file mode 100644 index 00000000..ace5b237 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f986.png differ diff --git a/twake/frontend/public/public/emojione/64/1f987.png b/twake/frontend/public/public/emojione/64/1f987.png new file mode 100644 index 00000000..950826e9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f987.png differ diff --git a/twake/frontend/public/public/emojione/64/1f988.png b/twake/frontend/public/public/emojione/64/1f988.png new file mode 100644 index 00000000..0e543fae Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f988.png differ diff --git a/twake/frontend/public/public/emojione/64/1f989.png b/twake/frontend/public/public/emojione/64/1f989.png new file mode 100644 index 00000000..ebb96b28 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f989.png differ diff --git a/twake/frontend/public/public/emojione/64/1f98a.png b/twake/frontend/public/public/emojione/64/1f98a.png new file mode 100644 index 00000000..38736c78 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f98a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f98b.png b/twake/frontend/public/public/emojione/64/1f98b.png new file mode 100644 index 00000000..0823fb6f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f98b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f98c.png b/twake/frontend/public/public/emojione/64/1f98c.png new file mode 100644 index 00000000..0c5dc9ba Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f98c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f98d.png b/twake/frontend/public/public/emojione/64/1f98d.png new file mode 100644 index 00000000..7caa7efd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f98d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f98e.png b/twake/frontend/public/public/emojione/64/1f98e.png new file mode 100644 index 00000000..f0e8cec0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f98e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f98f.png b/twake/frontend/public/public/emojione/64/1f98f.png new file mode 100644 index 00000000..68dc8ede Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f98f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f990.png b/twake/frontend/public/public/emojione/64/1f990.png new file mode 100644 index 00000000..9ec57c39 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f990.png differ diff --git a/twake/frontend/public/public/emojione/64/1f991.png b/twake/frontend/public/public/emojione/64/1f991.png new file mode 100644 index 00000000..7b8420cd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f991.png differ diff --git a/twake/frontend/public/public/emojione/64/1f992.png b/twake/frontend/public/public/emojione/64/1f992.png new file mode 100644 index 00000000..f18462f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f992.png differ diff --git a/twake/frontend/public/public/emojione/64/1f993.png b/twake/frontend/public/public/emojione/64/1f993.png new file mode 100644 index 00000000..fcbad8f9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f993.png differ diff --git a/twake/frontend/public/public/emojione/64/1f994.png b/twake/frontend/public/public/emojione/64/1f994.png new file mode 100644 index 00000000..c3ba5ece Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f994.png differ diff --git a/twake/frontend/public/public/emojione/64/1f995.png b/twake/frontend/public/public/emojione/64/1f995.png new file mode 100644 index 00000000..3e64e037 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f995.png differ diff --git a/twake/frontend/public/public/emojione/64/1f996.png b/twake/frontend/public/public/emojione/64/1f996.png new file mode 100644 index 00000000..d540300c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f996.png differ diff --git a/twake/frontend/public/public/emojione/64/1f997.png b/twake/frontend/public/public/emojione/64/1f997.png new file mode 100644 index 00000000..4ff16c68 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f997.png differ diff --git a/twake/frontend/public/public/emojione/64/1f998.png b/twake/frontend/public/public/emojione/64/1f998.png new file mode 100644 index 00000000..ec58f7ad Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f998.png differ diff --git a/twake/frontend/public/public/emojione/64/1f999.png b/twake/frontend/public/public/emojione/64/1f999.png new file mode 100644 index 00000000..32c0b244 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f999.png differ diff --git a/twake/frontend/public/public/emojione/64/1f99a.png b/twake/frontend/public/public/emojione/64/1f99a.png new file mode 100644 index 00000000..a7f4a307 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f99a.png differ diff --git a/twake/frontend/public/public/emojione/64/1f99b.png b/twake/frontend/public/public/emojione/64/1f99b.png new file mode 100644 index 00000000..cad82a0b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f99b.png differ diff --git a/twake/frontend/public/public/emojione/64/1f99c.png b/twake/frontend/public/public/emojione/64/1f99c.png new file mode 100644 index 00000000..df761f82 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f99c.png differ diff --git a/twake/frontend/public/public/emojione/64/1f99d.png b/twake/frontend/public/public/emojione/64/1f99d.png new file mode 100644 index 00000000..d571d21c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f99d.png differ diff --git a/twake/frontend/public/public/emojione/64/1f99e.png b/twake/frontend/public/public/emojione/64/1f99e.png new file mode 100644 index 00000000..a0eaaa1e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f99e.png differ diff --git a/twake/frontend/public/public/emojione/64/1f99f.png b/twake/frontend/public/public/emojione/64/1f99f.png new file mode 100644 index 00000000..3beead57 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f99f.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9a0.png b/twake/frontend/public/public/emojione/64/1f9a0.png new file mode 100644 index 00000000..c4564e73 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9a0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9a1.png b/twake/frontend/public/public/emojione/64/1f9a1.png new file mode 100644 index 00000000..09898fdc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9a1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9a2.png b/twake/frontend/public/public/emojione/64/1f9a2.png new file mode 100644 index 00000000..0a76ab0c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9a2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b0.png b/twake/frontend/public/public/emojione/64/1f9b0.png new file mode 100644 index 00000000..038464cc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b1.png b/twake/frontend/public/public/emojione/64/1f9b1.png new file mode 100644 index 00000000..50a0af3c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b2.png b/twake/frontend/public/public/emojione/64/1f9b2.png new file mode 100644 index 00000000..3bf2d0d7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b3.png b/twake/frontend/public/public/emojione/64/1f9b3.png new file mode 100644 index 00000000..b0eb1336 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b4.png b/twake/frontend/public/public/emojione/64/1f9b4.png new file mode 100644 index 00000000..9ce66fd9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b5-1f3fb.png b/twake/frontend/public/public/emojione/64/1f9b5-1f3fb.png new file mode 100644 index 00000000..7c6162c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b5-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b5-1f3fc.png b/twake/frontend/public/public/emojione/64/1f9b5-1f3fc.png new file mode 100644 index 00000000..90109ca7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b5-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b5-1f3fd.png b/twake/frontend/public/public/emojione/64/1f9b5-1f3fd.png new file mode 100644 index 00000000..425226dd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b5-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b5-1f3fe.png b/twake/frontend/public/public/emojione/64/1f9b5-1f3fe.png new file mode 100644 index 00000000..d07c55a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b5-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b5-1f3ff.png b/twake/frontend/public/public/emojione/64/1f9b5-1f3ff.png new file mode 100644 index 00000000..3c35861a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b5-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b5.png b/twake/frontend/public/public/emojione/64/1f9b5.png new file mode 100644 index 00000000..a60e415f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b6-1f3fb.png b/twake/frontend/public/public/emojione/64/1f9b6-1f3fb.png new file mode 100644 index 00000000..07de3512 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b6-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b6-1f3fc.png b/twake/frontend/public/public/emojione/64/1f9b6-1f3fc.png new file mode 100644 index 00000000..913bfa43 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b6-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b6-1f3fd.png b/twake/frontend/public/public/emojione/64/1f9b6-1f3fd.png new file mode 100644 index 00000000..bdb975f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b6-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b6-1f3fe.png b/twake/frontend/public/public/emojione/64/1f9b6-1f3fe.png new file mode 100644 index 00000000..4496363f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b6-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b6-1f3ff.png b/twake/frontend/public/public/emojione/64/1f9b6-1f3ff.png new file mode 100644 index 00000000..998a4397 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b6-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b6.png b/twake/frontend/public/public/emojione/64/1f9b6.png new file mode 100644 index 00000000..0b5ef5de Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b7.png b/twake/frontend/public/public/emojione/64/1f9b7.png new file mode 100644 index 00000000..779bccba Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f9b8-1f3fb-2640.png new file mode 100644 index 00000000..76149166 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f9b8-1f3fb-2642.png new file mode 100644 index 00000000..f5d54da6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8-1f3fb.png b/twake/frontend/public/public/emojione/64/1f9b8-1f3fb.png new file mode 100644 index 00000000..76149166 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f9b8-1f3fc-2640.png new file mode 100644 index 00000000..2706fa01 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f9b8-1f3fc-2642.png new file mode 100644 index 00000000..ea3749c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8-1f3fc.png b/twake/frontend/public/public/emojione/64/1f9b8-1f3fc.png new file mode 100644 index 00000000..2706fa01 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f9b8-1f3fd-2640.png new file mode 100644 index 00000000..61f01456 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f9b8-1f3fd-2642.png new file mode 100644 index 00000000..b6732e3e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8-1f3fd.png b/twake/frontend/public/public/emojione/64/1f9b8-1f3fd.png new file mode 100644 index 00000000..61f01456 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f9b8-1f3fe-2640.png new file mode 100644 index 00000000..8dc04e72 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f9b8-1f3fe-2642.png new file mode 100644 index 00000000..f66a6678 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8-1f3fe.png b/twake/frontend/public/public/emojione/64/1f9b8-1f3fe.png new file mode 100644 index 00000000..8dc04e72 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f9b8-1f3ff-2640.png new file mode 100644 index 00000000..ba1a039c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f9b8-1f3ff-2642.png new file mode 100644 index 00000000..88f57d42 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8-1f3ff.png b/twake/frontend/public/public/emojione/64/1f9b8-1f3ff.png new file mode 100644 index 00000000..ba1a039c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8-2640.png b/twake/frontend/public/public/emojione/64/1f9b8-2640.png new file mode 100644 index 00000000..38081e3b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8-2642.png b/twake/frontend/public/public/emojione/64/1f9b8-2642.png new file mode 100644 index 00000000..970d2283 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b8.png b/twake/frontend/public/public/emojione/64/1f9b8.png new file mode 100644 index 00000000..38081e3b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f9b9-1f3fb-2640.png new file mode 100644 index 00000000..f6cc2e1a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f9b9-1f3fb-2642.png new file mode 100644 index 00000000..c2bf67c4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9-1f3fb.png b/twake/frontend/public/public/emojione/64/1f9b9-1f3fb.png new file mode 100644 index 00000000..f6cc2e1a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f9b9-1f3fc-2640.png new file mode 100644 index 00000000..d19b93c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f9b9-1f3fc-2642.png new file mode 100644 index 00000000..e938c4cc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9-1f3fc.png b/twake/frontend/public/public/emojione/64/1f9b9-1f3fc.png new file mode 100644 index 00000000..d19b93c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f9b9-1f3fd-2640.png new file mode 100644 index 00000000..70a4d0d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f9b9-1f3fd-2642.png new file mode 100644 index 00000000..98f914b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9-1f3fd.png b/twake/frontend/public/public/emojione/64/1f9b9-1f3fd.png new file mode 100644 index 00000000..70a4d0d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f9b9-1f3fe-2640.png new file mode 100644 index 00000000..318cf100 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f9b9-1f3fe-2642.png new file mode 100644 index 00000000..038a117d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9-1f3fe.png b/twake/frontend/public/public/emojione/64/1f9b9-1f3fe.png new file mode 100644 index 00000000..318cf100 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f9b9-1f3ff-2640.png new file mode 100644 index 00000000..1f610b85 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f9b9-1f3ff-2642.png new file mode 100644 index 00000000..15bb1d5c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9-1f3ff.png b/twake/frontend/public/public/emojione/64/1f9b9-1f3ff.png new file mode 100644 index 00000000..1f610b85 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9-2640.png b/twake/frontend/public/public/emojione/64/1f9b9-2640.png new file mode 100644 index 00000000..c908f80b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9-2642.png b/twake/frontend/public/public/emojione/64/1f9b9-2642.png new file mode 100644 index 00000000..049b094a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9b9.png b/twake/frontend/public/public/emojione/64/1f9b9.png new file mode 100644 index 00000000..c908f80b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9b9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9c0.png b/twake/frontend/public/public/emojione/64/1f9c0.png new file mode 100644 index 00000000..2d62bfbe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9c0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9c1.png b/twake/frontend/public/public/emojione/64/1f9c1.png new file mode 100644 index 00000000..0920c3c3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9c1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9c2.png b/twake/frontend/public/public/emojione/64/1f9c2.png new file mode 100644 index 00000000..b82b252c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9c2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d0.png b/twake/frontend/public/public/emojione/64/1f9d0.png new file mode 100644 index 00000000..c01b53fb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d1-1f3fb.png b/twake/frontend/public/public/emojione/64/1f9d1-1f3fb.png new file mode 100644 index 00000000..da46a3df Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d1-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d1-1f3fc.png b/twake/frontend/public/public/emojione/64/1f9d1-1f3fc.png new file mode 100644 index 00000000..9627c82a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d1-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d1-1f3fd.png b/twake/frontend/public/public/emojione/64/1f9d1-1f3fd.png new file mode 100644 index 00000000..322286ff Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d1-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d1-1f3fe.png b/twake/frontend/public/public/emojione/64/1f9d1-1f3fe.png new file mode 100644 index 00000000..5365f71f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d1-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d1-1f3ff.png b/twake/frontend/public/public/emojione/64/1f9d1-1f3ff.png new file mode 100644 index 00000000..5d851a37 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d1-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d1.png b/twake/frontend/public/public/emojione/64/1f9d1.png new file mode 100644 index 00000000..8b9f9a8a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d2-1f3fb.png b/twake/frontend/public/public/emojione/64/1f9d2-1f3fb.png new file mode 100644 index 00000000..e23470a5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d2-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d2-1f3fc.png b/twake/frontend/public/public/emojione/64/1f9d2-1f3fc.png new file mode 100644 index 00000000..60451e84 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d2-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d2-1f3fd.png b/twake/frontend/public/public/emojione/64/1f9d2-1f3fd.png new file mode 100644 index 00000000..25ad39e3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d2-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d2-1f3fe.png b/twake/frontend/public/public/emojione/64/1f9d2-1f3fe.png new file mode 100644 index 00000000..d80947b0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d2-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d2-1f3ff.png b/twake/frontend/public/public/emojione/64/1f9d2-1f3ff.png new file mode 100644 index 00000000..f2d3f1cb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d2-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d2.png b/twake/frontend/public/public/emojione/64/1f9d2.png new file mode 100644 index 00000000..97f7d7d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d3-1f3fb.png b/twake/frontend/public/public/emojione/64/1f9d3-1f3fb.png new file mode 100644 index 00000000..ba22c924 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d3-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d3-1f3fc.png b/twake/frontend/public/public/emojione/64/1f9d3-1f3fc.png new file mode 100644 index 00000000..59abb0c5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d3-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d3-1f3fd.png b/twake/frontend/public/public/emojione/64/1f9d3-1f3fd.png new file mode 100644 index 00000000..a8c48e6d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d3-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d3-1f3fe.png b/twake/frontend/public/public/emojione/64/1f9d3-1f3fe.png new file mode 100644 index 00000000..86526529 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d3-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d3-1f3ff.png b/twake/frontend/public/public/emojione/64/1f9d3-1f3ff.png new file mode 100644 index 00000000..e164d5f3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d3-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d3.png b/twake/frontend/public/public/emojione/64/1f9d3.png new file mode 100644 index 00000000..93ad965b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d4-1f3fb.png b/twake/frontend/public/public/emojione/64/1f9d4-1f3fb.png new file mode 100644 index 00000000..6f07514d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d4-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d4-1f3fc.png b/twake/frontend/public/public/emojione/64/1f9d4-1f3fc.png new file mode 100644 index 00000000..91b4c4b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d4-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d4-1f3fd.png b/twake/frontend/public/public/emojione/64/1f9d4-1f3fd.png new file mode 100644 index 00000000..c38867e4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d4-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d4-1f3fe.png b/twake/frontend/public/public/emojione/64/1f9d4-1f3fe.png new file mode 100644 index 00000000..0986e0f8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d4-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d4-1f3ff.png b/twake/frontend/public/public/emojione/64/1f9d4-1f3ff.png new file mode 100644 index 00000000..e8391728 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d4-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d4.png b/twake/frontend/public/public/emojione/64/1f9d4.png new file mode 100644 index 00000000..8e97f05d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d5-1f3fb.png b/twake/frontend/public/public/emojione/64/1f9d5-1f3fb.png new file mode 100644 index 00000000..a33c4c33 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d5-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d5-1f3fc.png b/twake/frontend/public/public/emojione/64/1f9d5-1f3fc.png new file mode 100644 index 00000000..08199c13 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d5-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d5-1f3fd.png b/twake/frontend/public/public/emojione/64/1f9d5-1f3fd.png new file mode 100644 index 00000000..aea390d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d5-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d5-1f3fe.png b/twake/frontend/public/public/emojione/64/1f9d5-1f3fe.png new file mode 100644 index 00000000..bc8e6742 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d5-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d5-1f3ff.png b/twake/frontend/public/public/emojione/64/1f9d5-1f3ff.png new file mode 100644 index 00000000..60dab8ed Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d5-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d5.png b/twake/frontend/public/public/emojione/64/1f9d5.png new file mode 100644 index 00000000..84f43834 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f9d6-1f3fb-2640.png new file mode 100644 index 00000000..f424f277 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f9d6-1f3fb-2642.png new file mode 100644 index 00000000..81053f49 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6-1f3fb.png b/twake/frontend/public/public/emojione/64/1f9d6-1f3fb.png new file mode 100644 index 00000000..f424f277 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f9d6-1f3fc-2640.png new file mode 100644 index 00000000..633ffa29 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f9d6-1f3fc-2642.png new file mode 100644 index 00000000..17fc0d13 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6-1f3fc.png b/twake/frontend/public/public/emojione/64/1f9d6-1f3fc.png new file mode 100644 index 00000000..633ffa29 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f9d6-1f3fd-2640.png new file mode 100644 index 00000000..a06bf4bc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f9d6-1f3fd-2642.png new file mode 100644 index 00000000..b81b0112 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6-1f3fd.png b/twake/frontend/public/public/emojione/64/1f9d6-1f3fd.png new file mode 100644 index 00000000..a06bf4bc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f9d6-1f3fe-2640.png new file mode 100644 index 00000000..0cc773b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f9d6-1f3fe-2642.png new file mode 100644 index 00000000..33e79fea Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6-1f3fe.png b/twake/frontend/public/public/emojione/64/1f9d6-1f3fe.png new file mode 100644 index 00000000..0cc773b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f9d6-1f3ff-2640.png new file mode 100644 index 00000000..25825e9d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f9d6-1f3ff-2642.png new file mode 100644 index 00000000..9a9e36bc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6-1f3ff.png b/twake/frontend/public/public/emojione/64/1f9d6-1f3ff.png new file mode 100644 index 00000000..25825e9d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6-2640.png b/twake/frontend/public/public/emojione/64/1f9d6-2640.png new file mode 100644 index 00000000..635fc35b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6-2642.png b/twake/frontend/public/public/emojione/64/1f9d6-2642.png new file mode 100644 index 00000000..f71abb9a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d6.png b/twake/frontend/public/public/emojione/64/1f9d6.png new file mode 100644 index 00000000..635fc35b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f9d7-1f3fb-2640.png new file mode 100644 index 00000000..5167c0f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f9d7-1f3fb-2642.png new file mode 100644 index 00000000..c71f9a76 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7-1f3fb.png b/twake/frontend/public/public/emojione/64/1f9d7-1f3fb.png new file mode 100644 index 00000000..5167c0f5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f9d7-1f3fc-2640.png new file mode 100644 index 00000000..73e99641 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f9d7-1f3fc-2642.png new file mode 100644 index 00000000..12641488 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7-1f3fc.png b/twake/frontend/public/public/emojione/64/1f9d7-1f3fc.png new file mode 100644 index 00000000..73e99641 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f9d7-1f3fd-2640.png new file mode 100644 index 00000000..ee66c991 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f9d7-1f3fd-2642.png new file mode 100644 index 00000000..f48e486d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7-1f3fd.png b/twake/frontend/public/public/emojione/64/1f9d7-1f3fd.png new file mode 100644 index 00000000..ee66c991 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f9d7-1f3fe-2640.png new file mode 100644 index 00000000..7dce3d48 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f9d7-1f3fe-2642.png new file mode 100644 index 00000000..79eb1319 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7-1f3fe.png b/twake/frontend/public/public/emojione/64/1f9d7-1f3fe.png new file mode 100644 index 00000000..7dce3d48 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f9d7-1f3ff-2640.png new file mode 100644 index 00000000..fcdbdf48 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f9d7-1f3ff-2642.png new file mode 100644 index 00000000..5e7acb8d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7-1f3ff.png b/twake/frontend/public/public/emojione/64/1f9d7-1f3ff.png new file mode 100644 index 00000000..fcdbdf48 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7-2640.png b/twake/frontend/public/public/emojione/64/1f9d7-2640.png new file mode 100644 index 00000000..45c8cff3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7-2642.png b/twake/frontend/public/public/emojione/64/1f9d7-2642.png new file mode 100644 index 00000000..66efa33c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d7.png b/twake/frontend/public/public/emojione/64/1f9d7.png new file mode 100644 index 00000000..6f733766 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f9d8-1f3fb-2640.png new file mode 100644 index 00000000..c4dacf6a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f9d8-1f3fb-2642.png new file mode 100644 index 00000000..674cb616 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8-1f3fb.png b/twake/frontend/public/public/emojione/64/1f9d8-1f3fb.png new file mode 100644 index 00000000..c4dacf6a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f9d8-1f3fc-2640.png new file mode 100644 index 00000000..69d39974 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f9d8-1f3fc-2642.png new file mode 100644 index 00000000..aa35f9a8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8-1f3fc.png b/twake/frontend/public/public/emojione/64/1f9d8-1f3fc.png new file mode 100644 index 00000000..69d39974 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f9d8-1f3fd-2640.png new file mode 100644 index 00000000..71413a5e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f9d8-1f3fd-2642.png new file mode 100644 index 00000000..090b4efc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8-1f3fd.png b/twake/frontend/public/public/emojione/64/1f9d8-1f3fd.png new file mode 100644 index 00000000..71413a5e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f9d8-1f3fe-2640.png new file mode 100644 index 00000000..23127efe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f9d8-1f3fe-2642.png new file mode 100644 index 00000000..b103d9b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8-1f3fe.png b/twake/frontend/public/public/emojione/64/1f9d8-1f3fe.png new file mode 100644 index 00000000..23127efe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f9d8-1f3ff-2640.png new file mode 100644 index 00000000..21f5890c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f9d8-1f3ff-2642.png new file mode 100644 index 00000000..9918b96e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8-1f3ff.png b/twake/frontend/public/public/emojione/64/1f9d8-1f3ff.png new file mode 100644 index 00000000..21f5890c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8-2640.png b/twake/frontend/public/public/emojione/64/1f9d8-2640.png new file mode 100644 index 00000000..62cf06ff Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8-2642.png b/twake/frontend/public/public/emojione/64/1f9d8-2642.png new file mode 100644 index 00000000..803791eb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d8.png b/twake/frontend/public/public/emojione/64/1f9d8.png new file mode 100644 index 00000000..62cf06ff Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f9d9-1f3fb-2640.png new file mode 100644 index 00000000..b04932e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f9d9-1f3fb-2642.png new file mode 100644 index 00000000..5069f2d3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9-1f3fb.png b/twake/frontend/public/public/emojione/64/1f9d9-1f3fb.png new file mode 100644 index 00000000..b04932e1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f9d9-1f3fc-2640.png new file mode 100644 index 00000000..e31b5fa3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f9d9-1f3fc-2642.png new file mode 100644 index 00000000..86bce35c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9-1f3fc.png b/twake/frontend/public/public/emojione/64/1f9d9-1f3fc.png new file mode 100644 index 00000000..e31b5fa3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f9d9-1f3fd-2640.png new file mode 100644 index 00000000..42e390f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f9d9-1f3fd-2642.png new file mode 100644 index 00000000..a2234f02 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9-1f3fd.png b/twake/frontend/public/public/emojione/64/1f9d9-1f3fd.png new file mode 100644 index 00000000..42e390f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f9d9-1f3fe-2640.png new file mode 100644 index 00000000..d21c5827 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f9d9-1f3fe-2642.png new file mode 100644 index 00000000..b87300c1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9-1f3fe.png b/twake/frontend/public/public/emojione/64/1f9d9-1f3fe.png new file mode 100644 index 00000000..d21c5827 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f9d9-1f3ff-2640.png new file mode 100644 index 00000000..9fef6b5a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f9d9-1f3ff-2642.png new file mode 100644 index 00000000..8c259801 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9-1f3ff.png b/twake/frontend/public/public/emojione/64/1f9d9-1f3ff.png new file mode 100644 index 00000000..9fef6b5a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9-2640.png b/twake/frontend/public/public/emojione/64/1f9d9-2640.png new file mode 100644 index 00000000..852865b4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9-2642.png b/twake/frontend/public/public/emojione/64/1f9d9-2642.png new file mode 100644 index 00000000..7232afe4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9d9.png b/twake/frontend/public/public/emojione/64/1f9d9.png new file mode 100644 index 00000000..852865b4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9d9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f9da-1f3fb-2640.png new file mode 100644 index 00000000..44cdde0b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f9da-1f3fb-2642.png new file mode 100644 index 00000000..b0c69c2d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da-1f3fb.png b/twake/frontend/public/public/emojione/64/1f9da-1f3fb.png new file mode 100644 index 00000000..44cdde0b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f9da-1f3fc-2640.png new file mode 100644 index 00000000..796ba30e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f9da-1f3fc-2642.png new file mode 100644 index 00000000..a7c73ac1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da-1f3fc.png b/twake/frontend/public/public/emojione/64/1f9da-1f3fc.png new file mode 100644 index 00000000..796ba30e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f9da-1f3fd-2640.png new file mode 100644 index 00000000..51a53be6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f9da-1f3fd-2642.png new file mode 100644 index 00000000..32e7e2e7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da-1f3fd.png b/twake/frontend/public/public/emojione/64/1f9da-1f3fd.png new file mode 100644 index 00000000..51a53be6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f9da-1f3fe-2640.png new file mode 100644 index 00000000..89dc8cdb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f9da-1f3fe-2642.png new file mode 100644 index 00000000..da82cc0b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da-1f3fe.png b/twake/frontend/public/public/emojione/64/1f9da-1f3fe.png new file mode 100644 index 00000000..89dc8cdb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f9da-1f3ff-2640.png new file mode 100644 index 00000000..ea4cfb84 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f9da-1f3ff-2642.png new file mode 100644 index 00000000..a3121646 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da-1f3ff.png b/twake/frontend/public/public/emojione/64/1f9da-1f3ff.png new file mode 100644 index 00000000..ea4cfb84 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da-2640.png b/twake/frontend/public/public/emojione/64/1f9da-2640.png new file mode 100644 index 00000000..3eb34011 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da-2642.png b/twake/frontend/public/public/emojione/64/1f9da-2642.png new file mode 100644 index 00000000..d0b52119 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9da.png b/twake/frontend/public/public/emojione/64/1f9da.png new file mode 100644 index 00000000..3eb34011 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9da.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f9db-1f3fb-2640.png new file mode 100644 index 00000000..764d9d13 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f9db-1f3fb-2642.png new file mode 100644 index 00000000..02452456 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db-1f3fb.png b/twake/frontend/public/public/emojione/64/1f9db-1f3fb.png new file mode 100644 index 00000000..764d9d13 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f9db-1f3fc-2640.png new file mode 100644 index 00000000..8c7de857 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f9db-1f3fc-2642.png new file mode 100644 index 00000000..1520ddd8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db-1f3fc.png b/twake/frontend/public/public/emojione/64/1f9db-1f3fc.png new file mode 100644 index 00000000..8c7de857 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f9db-1f3fd-2640.png new file mode 100644 index 00000000..ed8c85cb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f9db-1f3fd-2642.png new file mode 100644 index 00000000..b469026a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db-1f3fd.png b/twake/frontend/public/public/emojione/64/1f9db-1f3fd.png new file mode 100644 index 00000000..ed8c85cb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f9db-1f3fe-2640.png new file mode 100644 index 00000000..f2b865ad Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f9db-1f3fe-2642.png new file mode 100644 index 00000000..cab46b91 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db-1f3fe.png b/twake/frontend/public/public/emojione/64/1f9db-1f3fe.png new file mode 100644 index 00000000..f2b865ad Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f9db-1f3ff-2640.png new file mode 100644 index 00000000..e6dd178a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f9db-1f3ff-2642.png new file mode 100644 index 00000000..ec4ada56 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db-1f3ff.png b/twake/frontend/public/public/emojione/64/1f9db-1f3ff.png new file mode 100644 index 00000000..e6dd178a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db-2640.png b/twake/frontend/public/public/emojione/64/1f9db-2640.png new file mode 100644 index 00000000..220c109a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db-2642.png b/twake/frontend/public/public/emojione/64/1f9db-2642.png new file mode 100644 index 00000000..e93fa6cd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9db.png b/twake/frontend/public/public/emojione/64/1f9db.png new file mode 100644 index 00000000..220c109a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9db.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f9dc-1f3fb-2640.png new file mode 100644 index 00000000..7137a646 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f9dc-1f3fb-2642.png new file mode 100644 index 00000000..ea8c6d00 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc-1f3fb.png b/twake/frontend/public/public/emojione/64/1f9dc-1f3fb.png new file mode 100644 index 00000000..7137a646 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f9dc-1f3fc-2640.png new file mode 100644 index 00000000..1a873d70 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f9dc-1f3fc-2642.png new file mode 100644 index 00000000..34e8117a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc-1f3fc.png b/twake/frontend/public/public/emojione/64/1f9dc-1f3fc.png new file mode 100644 index 00000000..1a873d70 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f9dc-1f3fd-2640.png new file mode 100644 index 00000000..e6f98604 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f9dc-1f3fd-2642.png new file mode 100644 index 00000000..bb408c30 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc-1f3fd.png b/twake/frontend/public/public/emojione/64/1f9dc-1f3fd.png new file mode 100644 index 00000000..e6f98604 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f9dc-1f3fe-2640.png new file mode 100644 index 00000000..b47ff836 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f9dc-1f3fe-2642.png new file mode 100644 index 00000000..6b0c3426 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc-1f3fe.png b/twake/frontend/public/public/emojione/64/1f9dc-1f3fe.png new file mode 100644 index 00000000..b47ff836 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f9dc-1f3ff-2640.png new file mode 100644 index 00000000..0fdcf2e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f9dc-1f3ff-2642.png new file mode 100644 index 00000000..4878b8a0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc-1f3ff.png b/twake/frontend/public/public/emojione/64/1f9dc-1f3ff.png new file mode 100644 index 00000000..0fdcf2e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc-2640.png b/twake/frontend/public/public/emojione/64/1f9dc-2640.png new file mode 100644 index 00000000..b4061006 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc-2642.png b/twake/frontend/public/public/emojione/64/1f9dc-2642.png new file mode 100644 index 00000000..d0379c7c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dc.png b/twake/frontend/public/public/emojione/64/1f9dc.png new file mode 100644 index 00000000..420acb45 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/1f9dd-1f3fb-2640.png new file mode 100644 index 00000000..6936c659 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/1f9dd-1f3fb-2642.png new file mode 100644 index 00000000..612a60d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd-1f3fb.png b/twake/frontend/public/public/emojione/64/1f9dd-1f3fb.png new file mode 100644 index 00000000..6936c659 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/1f9dd-1f3fc-2640.png new file mode 100644 index 00000000..c82f4caa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/1f9dd-1f3fc-2642.png new file mode 100644 index 00000000..fd41ecf7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd-1f3fc.png b/twake/frontend/public/public/emojione/64/1f9dd-1f3fc.png new file mode 100644 index 00000000..c82f4caa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/1f9dd-1f3fd-2640.png new file mode 100644 index 00000000..2e799ab6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/1f9dd-1f3fd-2642.png new file mode 100644 index 00000000..f9ef5e5b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd-1f3fd.png b/twake/frontend/public/public/emojione/64/1f9dd-1f3fd.png new file mode 100644 index 00000000..2e799ab6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/1f9dd-1f3fe-2640.png new file mode 100644 index 00000000..f7498ef1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/1f9dd-1f3fe-2642.png new file mode 100644 index 00000000..5dba0eb6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd-1f3fe.png b/twake/frontend/public/public/emojione/64/1f9dd-1f3fe.png new file mode 100644 index 00000000..f7498ef1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/1f9dd-1f3ff-2640.png new file mode 100644 index 00000000..30152585 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/1f9dd-1f3ff-2642.png new file mode 100644 index 00000000..6bb32830 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd-1f3ff.png b/twake/frontend/public/public/emojione/64/1f9dd-1f3ff.png new file mode 100644 index 00000000..30152585 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd-2640.png b/twake/frontend/public/public/emojione/64/1f9dd-2640.png new file mode 100644 index 00000000..0d8c3eb2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd-2642.png b/twake/frontend/public/public/emojione/64/1f9dd-2642.png new file mode 100644 index 00000000..af5f1145 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9dd.png b/twake/frontend/public/public/emojione/64/1f9dd.png new file mode 100644 index 00000000..0d8c3eb2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9dd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9de-2640.png b/twake/frontend/public/public/emojione/64/1f9de-2640.png new file mode 100644 index 00000000..a31c0b1a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9de-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9de-2642.png b/twake/frontend/public/public/emojione/64/1f9de-2642.png new file mode 100644 index 00000000..2494fe02 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9de-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9de.png b/twake/frontend/public/public/emojione/64/1f9de.png new file mode 100644 index 00000000..a31c0b1a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9de.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9df-2640.png b/twake/frontend/public/public/emojione/64/1f9df-2640.png new file mode 100644 index 00000000..d5003135 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9df-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9df-2642.png b/twake/frontend/public/public/emojione/64/1f9df-2642.png new file mode 100644 index 00000000..11174e53 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9df-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9df.png b/twake/frontend/public/public/emojione/64/1f9df.png new file mode 100644 index 00000000..d5003135 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9df.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9e0.png b/twake/frontend/public/public/emojione/64/1f9e0.png new file mode 100644 index 00000000..fbf05d33 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9e0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9e1.png b/twake/frontend/public/public/emojione/64/1f9e1.png new file mode 100644 index 00000000..38d4c946 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9e1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9e2.png b/twake/frontend/public/public/emojione/64/1f9e2.png new file mode 100644 index 00000000..8a098fb7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9e2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9e3.png b/twake/frontend/public/public/emojione/64/1f9e3.png new file mode 100644 index 00000000..f623d691 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9e3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9e4.png b/twake/frontend/public/public/emojione/64/1f9e4.png new file mode 100644 index 00000000..98f59698 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9e4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9e5.png b/twake/frontend/public/public/emojione/64/1f9e5.png new file mode 100644 index 00000000..1f6b7b90 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9e5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9e6.png b/twake/frontend/public/public/emojione/64/1f9e6.png new file mode 100644 index 00000000..52c7750c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9e6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9e7.png b/twake/frontend/public/public/emojione/64/1f9e7.png new file mode 100644 index 00000000..3a0b79d4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9e7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9e8.png b/twake/frontend/public/public/emojione/64/1f9e8.png new file mode 100644 index 00000000..799c8739 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9e8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9e9.png b/twake/frontend/public/public/emojione/64/1f9e9.png new file mode 100644 index 00000000..90acb260 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9e9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9ea.png b/twake/frontend/public/public/emojione/64/1f9ea.png new file mode 100644 index 00000000..aabfa0cf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9ea.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9eb.png b/twake/frontend/public/public/emojione/64/1f9eb.png new file mode 100644 index 00000000..d473fee2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9eb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9ec.png b/twake/frontend/public/public/emojione/64/1f9ec.png new file mode 100644 index 00000000..6764507c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9ec.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9ed.png b/twake/frontend/public/public/emojione/64/1f9ed.png new file mode 100644 index 00000000..b0241686 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9ed.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9ee.png b/twake/frontend/public/public/emojione/64/1f9ee.png new file mode 100644 index 00000000..7d9f90ba Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9ee.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9ef.png b/twake/frontend/public/public/emojione/64/1f9ef.png new file mode 100644 index 00000000..ea537b90 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9ef.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9f0.png b/twake/frontend/public/public/emojione/64/1f9f0.png new file mode 100644 index 00000000..a5cb9325 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9f0.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9f1.png b/twake/frontend/public/public/emojione/64/1f9f1.png new file mode 100644 index 00000000..8c2642f2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9f1.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9f2.png b/twake/frontend/public/public/emojione/64/1f9f2.png new file mode 100644 index 00000000..3d49d6ee Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9f2.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9f3.png b/twake/frontend/public/public/emojione/64/1f9f3.png new file mode 100644 index 00000000..f8a760b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9f3.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9f4.png b/twake/frontend/public/public/emojione/64/1f9f4.png new file mode 100644 index 00000000..094c2be8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9f4.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9f5.png b/twake/frontend/public/public/emojione/64/1f9f5.png new file mode 100644 index 00000000..5b988414 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9f5.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9f6.png b/twake/frontend/public/public/emojione/64/1f9f6.png new file mode 100644 index 00000000..9758fc10 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9f6.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9f7.png b/twake/frontend/public/public/emojione/64/1f9f7.png new file mode 100644 index 00000000..2f77df31 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9f7.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9f8.png b/twake/frontend/public/public/emojione/64/1f9f8.png new file mode 100644 index 00000000..3dc81176 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9f8.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9f9.png b/twake/frontend/public/public/emojione/64/1f9f9.png new file mode 100644 index 00000000..2f082a98 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9f9.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9fa.png b/twake/frontend/public/public/emojione/64/1f9fa.png new file mode 100644 index 00000000..fd74a1ee Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9fa.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9fb.png b/twake/frontend/public/public/emojione/64/1f9fb.png new file mode 100644 index 00000000..7363a979 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9fb.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9fc.png b/twake/frontend/public/public/emojione/64/1f9fc.png new file mode 100644 index 00000000..e3bea0dc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9fc.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9fd.png b/twake/frontend/public/public/emojione/64/1f9fd.png new file mode 100644 index 00000000..859e1e44 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9fd.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9fe.png b/twake/frontend/public/public/emojione/64/1f9fe.png new file mode 100644 index 00000000..fca84739 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9fe.png differ diff --git a/twake/frontend/public/public/emojione/64/1f9ff.png b/twake/frontend/public/public/emojione/64/1f9ff.png new file mode 100644 index 00000000..f2f3b20e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/1f9ff.png differ diff --git a/twake/frontend/public/public/emojione/64/203c.png b/twake/frontend/public/public/emojione/64/203c.png new file mode 100644 index 00000000..89221a2a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/203c.png differ diff --git a/twake/frontend/public/public/emojione/64/2049.png b/twake/frontend/public/public/emojione/64/2049.png new file mode 100644 index 00000000..2fb523f9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2049.png differ diff --git a/twake/frontend/public/public/emojione/64/2122.png b/twake/frontend/public/public/emojione/64/2122.png new file mode 100644 index 00000000..eabe7937 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2122.png differ diff --git a/twake/frontend/public/public/emojione/64/2139.png b/twake/frontend/public/public/emojione/64/2139.png new file mode 100644 index 00000000..515631bd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2139.png differ diff --git a/twake/frontend/public/public/emojione/64/2194.png b/twake/frontend/public/public/emojione/64/2194.png new file mode 100644 index 00000000..60ff3c2b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2194.png differ diff --git a/twake/frontend/public/public/emojione/64/2195.png b/twake/frontend/public/public/emojione/64/2195.png new file mode 100644 index 00000000..64da1e8d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2195.png differ diff --git a/twake/frontend/public/public/emojione/64/2196.png b/twake/frontend/public/public/emojione/64/2196.png new file mode 100644 index 00000000..f3a24177 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2196.png differ diff --git a/twake/frontend/public/public/emojione/64/2197.png b/twake/frontend/public/public/emojione/64/2197.png new file mode 100644 index 00000000..e7694aa7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2197.png differ diff --git a/twake/frontend/public/public/emojione/64/2198.png b/twake/frontend/public/public/emojione/64/2198.png new file mode 100644 index 00000000..d96cd270 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2198.png differ diff --git a/twake/frontend/public/public/emojione/64/2199.png b/twake/frontend/public/public/emojione/64/2199.png new file mode 100644 index 00000000..182b877f Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2199.png differ diff --git a/twake/frontend/public/public/emojione/64/21a9.png b/twake/frontend/public/public/emojione/64/21a9.png new file mode 100644 index 00000000..7310cccd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/21a9.png differ diff --git a/twake/frontend/public/public/emojione/64/21aa.png b/twake/frontend/public/public/emojione/64/21aa.png new file mode 100644 index 00000000..823e6ff5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/21aa.png differ diff --git a/twake/frontend/public/public/emojione/64/231a.png b/twake/frontend/public/public/emojione/64/231a.png new file mode 100644 index 00000000..396c6162 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/231a.png differ diff --git a/twake/frontend/public/public/emojione/64/231b.png b/twake/frontend/public/public/emojione/64/231b.png new file mode 100644 index 00000000..d20f7cd0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/231b.png differ diff --git a/twake/frontend/public/public/emojione/64/2328.png b/twake/frontend/public/public/emojione/64/2328.png new file mode 100644 index 00000000..fb66294e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2328.png differ diff --git a/twake/frontend/public/public/emojione/64/23cf.png b/twake/frontend/public/public/emojione/64/23cf.png new file mode 100644 index 00000000..00024ea9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/23cf.png differ diff --git a/twake/frontend/public/public/emojione/64/23e9.png b/twake/frontend/public/public/emojione/64/23e9.png new file mode 100644 index 00000000..debb83b1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/23e9.png differ diff --git a/twake/frontend/public/public/emojione/64/23ea.png b/twake/frontend/public/public/emojione/64/23ea.png new file mode 100644 index 00000000..542b8432 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/23ea.png differ diff --git a/twake/frontend/public/public/emojione/64/23eb.png b/twake/frontend/public/public/emojione/64/23eb.png new file mode 100644 index 00000000..0874d1e2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/23eb.png differ diff --git a/twake/frontend/public/public/emojione/64/23ec.png b/twake/frontend/public/public/emojione/64/23ec.png new file mode 100644 index 00000000..94a0c4af Binary files /dev/null and b/twake/frontend/public/public/emojione/64/23ec.png differ diff --git a/twake/frontend/public/public/emojione/64/23ed.png b/twake/frontend/public/public/emojione/64/23ed.png new file mode 100644 index 00000000..f661c6ae Binary files /dev/null and b/twake/frontend/public/public/emojione/64/23ed.png differ diff --git a/twake/frontend/public/public/emojione/64/23ee.png b/twake/frontend/public/public/emojione/64/23ee.png new file mode 100644 index 00000000..f04b6a06 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/23ee.png differ diff --git a/twake/frontend/public/public/emojione/64/23ef.png b/twake/frontend/public/public/emojione/64/23ef.png new file mode 100644 index 00000000..3b1e8fb5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/23ef.png differ diff --git a/twake/frontend/public/public/emojione/64/23f0.png b/twake/frontend/public/public/emojione/64/23f0.png new file mode 100644 index 00000000..ff4498e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/23f0.png differ diff --git a/twake/frontend/public/public/emojione/64/23f1.png b/twake/frontend/public/public/emojione/64/23f1.png new file mode 100644 index 00000000..5b576b26 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/23f1.png differ diff --git a/twake/frontend/public/public/emojione/64/23f2.png b/twake/frontend/public/public/emojione/64/23f2.png new file mode 100644 index 00000000..8688afb9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/23f2.png differ diff --git a/twake/frontend/public/public/emojione/64/23f3.png b/twake/frontend/public/public/emojione/64/23f3.png new file mode 100644 index 00000000..e429b225 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/23f3.png differ diff --git a/twake/frontend/public/public/emojione/64/23f8.png b/twake/frontend/public/public/emojione/64/23f8.png new file mode 100644 index 00000000..8df98fa0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/23f8.png differ diff --git a/twake/frontend/public/public/emojione/64/23f9.png b/twake/frontend/public/public/emojione/64/23f9.png new file mode 100644 index 00000000..8ef83099 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/23f9.png differ diff --git a/twake/frontend/public/public/emojione/64/23fa.png b/twake/frontend/public/public/emojione/64/23fa.png new file mode 100644 index 00000000..1f801a4c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/23fa.png differ diff --git a/twake/frontend/public/public/emojione/64/24c2.png b/twake/frontend/public/public/emojione/64/24c2.png new file mode 100644 index 00000000..d33c682c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/24c2.png differ diff --git a/twake/frontend/public/public/emojione/64/25aa.png b/twake/frontend/public/public/emojione/64/25aa.png new file mode 100644 index 00000000..91395f1a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/25aa.png differ diff --git a/twake/frontend/public/public/emojione/64/25ab.png b/twake/frontend/public/public/emojione/64/25ab.png new file mode 100644 index 00000000..42fdf07e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/25ab.png differ diff --git a/twake/frontend/public/public/emojione/64/25b6.png b/twake/frontend/public/public/emojione/64/25b6.png new file mode 100644 index 00000000..bc1a1cda Binary files /dev/null and b/twake/frontend/public/public/emojione/64/25b6.png differ diff --git a/twake/frontend/public/public/emojione/64/25c0.png b/twake/frontend/public/public/emojione/64/25c0.png new file mode 100644 index 00000000..6e044161 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/25c0.png differ diff --git a/twake/frontend/public/public/emojione/64/25fb.png b/twake/frontend/public/public/emojione/64/25fb.png new file mode 100644 index 00000000..18b7ca42 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/25fb.png differ diff --git a/twake/frontend/public/public/emojione/64/25fc.png b/twake/frontend/public/public/emojione/64/25fc.png new file mode 100644 index 00000000..f51d474c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/25fc.png differ diff --git a/twake/frontend/public/public/emojione/64/25fd.png b/twake/frontend/public/public/emojione/64/25fd.png new file mode 100644 index 00000000..af52976b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/25fd.png differ diff --git a/twake/frontend/public/public/emojione/64/25fe.png b/twake/frontend/public/public/emojione/64/25fe.png new file mode 100644 index 00000000..b1acb249 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/25fe.png differ diff --git a/twake/frontend/public/public/emojione/64/2600.png b/twake/frontend/public/public/emojione/64/2600.png new file mode 100644 index 00000000..d6e0ebaf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2600.png differ diff --git a/twake/frontend/public/public/emojione/64/2601.png b/twake/frontend/public/public/emojione/64/2601.png new file mode 100644 index 00000000..841e32d1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2601.png differ diff --git a/twake/frontend/public/public/emojione/64/2602.png b/twake/frontend/public/public/emojione/64/2602.png new file mode 100644 index 00000000..eb465c61 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2602.png differ diff --git a/twake/frontend/public/public/emojione/64/2603.png b/twake/frontend/public/public/emojione/64/2603.png new file mode 100644 index 00000000..3c466df2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2603.png differ diff --git a/twake/frontend/public/public/emojione/64/2604.png b/twake/frontend/public/public/emojione/64/2604.png new file mode 100644 index 00000000..5485c7aa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2604.png differ diff --git a/twake/frontend/public/public/emojione/64/260e.png b/twake/frontend/public/public/emojione/64/260e.png new file mode 100644 index 00000000..c2fb25cb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/260e.png differ diff --git a/twake/frontend/public/public/emojione/64/2611.png b/twake/frontend/public/public/emojione/64/2611.png new file mode 100644 index 00000000..13e61b39 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2611.png differ diff --git a/twake/frontend/public/public/emojione/64/2614.png b/twake/frontend/public/public/emojione/64/2614.png new file mode 100644 index 00000000..7d6c5ba3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2614.png differ diff --git a/twake/frontend/public/public/emojione/64/2615.png b/twake/frontend/public/public/emojione/64/2615.png new file mode 100644 index 00000000..7de032f1 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2615.png differ diff --git a/twake/frontend/public/public/emojione/64/2618.png b/twake/frontend/public/public/emojione/64/2618.png new file mode 100644 index 00000000..3938c504 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2618.png differ diff --git a/twake/frontend/public/public/emojione/64/261d-1f3fb.png b/twake/frontend/public/public/emojione/64/261d-1f3fb.png new file mode 100644 index 00000000..a238e87b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/261d-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/261d-1f3fc.png b/twake/frontend/public/public/emojione/64/261d-1f3fc.png new file mode 100644 index 00000000..0d3abf70 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/261d-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/261d-1f3fd.png b/twake/frontend/public/public/emojione/64/261d-1f3fd.png new file mode 100644 index 00000000..64dbbc17 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/261d-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/261d-1f3fe.png b/twake/frontend/public/public/emojione/64/261d-1f3fe.png new file mode 100644 index 00000000..fc8ff442 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/261d-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/261d-1f3ff.png b/twake/frontend/public/public/emojione/64/261d-1f3ff.png new file mode 100644 index 00000000..b811bbf3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/261d-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/261d.png b/twake/frontend/public/public/emojione/64/261d.png new file mode 100644 index 00000000..a9079048 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/261d.png differ diff --git a/twake/frontend/public/public/emojione/64/2620.png b/twake/frontend/public/public/emojione/64/2620.png new file mode 100644 index 00000000..9e9ba044 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2620.png differ diff --git a/twake/frontend/public/public/emojione/64/2622.png b/twake/frontend/public/public/emojione/64/2622.png new file mode 100644 index 00000000..c410f786 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2622.png differ diff --git a/twake/frontend/public/public/emojione/64/2623.png b/twake/frontend/public/public/emojione/64/2623.png new file mode 100644 index 00000000..45c8a64d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2623.png differ diff --git a/twake/frontend/public/public/emojione/64/2626.png b/twake/frontend/public/public/emojione/64/2626.png new file mode 100644 index 00000000..c29c45bc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2626.png differ diff --git a/twake/frontend/public/public/emojione/64/262a.png b/twake/frontend/public/public/emojione/64/262a.png new file mode 100644 index 00000000..d2a48c18 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/262a.png differ diff --git a/twake/frontend/public/public/emojione/64/262e.png b/twake/frontend/public/public/emojione/64/262e.png new file mode 100644 index 00000000..43711beb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/262e.png differ diff --git a/twake/frontend/public/public/emojione/64/262f.png b/twake/frontend/public/public/emojione/64/262f.png new file mode 100644 index 00000000..e07c743a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/262f.png differ diff --git a/twake/frontend/public/public/emojione/64/2638.png b/twake/frontend/public/public/emojione/64/2638.png new file mode 100644 index 00000000..61fc5e1e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2638.png differ diff --git a/twake/frontend/public/public/emojione/64/2639.png b/twake/frontend/public/public/emojione/64/2639.png new file mode 100644 index 00000000..453a3537 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2639.png differ diff --git a/twake/frontend/public/public/emojione/64/263a.png b/twake/frontend/public/public/emojione/64/263a.png new file mode 100644 index 00000000..9ef404bc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/263a.png differ diff --git a/twake/frontend/public/public/emojione/64/2640.png b/twake/frontend/public/public/emojione/64/2640.png new file mode 100644 index 00000000..04b8ff6e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2640.png differ diff --git a/twake/frontend/public/public/emojione/64/2642.png b/twake/frontend/public/public/emojione/64/2642.png new file mode 100644 index 00000000..1b981088 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2642.png differ diff --git a/twake/frontend/public/public/emojione/64/2648.png b/twake/frontend/public/public/emojione/64/2648.png new file mode 100644 index 00000000..8ea764a2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2648.png differ diff --git a/twake/frontend/public/public/emojione/64/2649.png b/twake/frontend/public/public/emojione/64/2649.png new file mode 100644 index 00000000..56b15ce7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2649.png differ diff --git a/twake/frontend/public/public/emojione/64/264a.png b/twake/frontend/public/public/emojione/64/264a.png new file mode 100644 index 00000000..111d41ad Binary files /dev/null and b/twake/frontend/public/public/emojione/64/264a.png differ diff --git a/twake/frontend/public/public/emojione/64/264b.png b/twake/frontend/public/public/emojione/64/264b.png new file mode 100644 index 00000000..752a3184 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/264b.png differ diff --git a/twake/frontend/public/public/emojione/64/264c.png b/twake/frontend/public/public/emojione/64/264c.png new file mode 100644 index 00000000..1bfff517 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/264c.png differ diff --git a/twake/frontend/public/public/emojione/64/264d.png b/twake/frontend/public/public/emojione/64/264d.png new file mode 100644 index 00000000..fdd21b73 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/264d.png differ diff --git a/twake/frontend/public/public/emojione/64/264e.png b/twake/frontend/public/public/emojione/64/264e.png new file mode 100644 index 00000000..54399549 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/264e.png differ diff --git a/twake/frontend/public/public/emojione/64/264f.png b/twake/frontend/public/public/emojione/64/264f.png new file mode 100644 index 00000000..f8ddf240 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/264f.png differ diff --git a/twake/frontend/public/public/emojione/64/2650.png b/twake/frontend/public/public/emojione/64/2650.png new file mode 100644 index 00000000..a417a772 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2650.png differ diff --git a/twake/frontend/public/public/emojione/64/2651.png b/twake/frontend/public/public/emojione/64/2651.png new file mode 100644 index 00000000..50cc4f10 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2651.png differ diff --git a/twake/frontend/public/public/emojione/64/2652.png b/twake/frontend/public/public/emojione/64/2652.png new file mode 100644 index 00000000..44108152 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2652.png differ diff --git a/twake/frontend/public/public/emojione/64/2653.png b/twake/frontend/public/public/emojione/64/2653.png new file mode 100644 index 00000000..80919eaf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2653.png differ diff --git a/twake/frontend/public/public/emojione/64/265f.png b/twake/frontend/public/public/emojione/64/265f.png new file mode 100644 index 00000000..62ea9d27 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/265f.png differ diff --git a/twake/frontend/public/public/emojione/64/2660.png b/twake/frontend/public/public/emojione/64/2660.png new file mode 100644 index 00000000..4dc6ad1a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2660.png differ diff --git a/twake/frontend/public/public/emojione/64/2663.png b/twake/frontend/public/public/emojione/64/2663.png new file mode 100644 index 00000000..682de2cc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2663.png differ diff --git a/twake/frontend/public/public/emojione/64/2665.png b/twake/frontend/public/public/emojione/64/2665.png new file mode 100644 index 00000000..86ce7200 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2665.png differ diff --git a/twake/frontend/public/public/emojione/64/2666.png b/twake/frontend/public/public/emojione/64/2666.png new file mode 100644 index 00000000..d2fe603c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2666.png differ diff --git a/twake/frontend/public/public/emojione/64/2668.png b/twake/frontend/public/public/emojione/64/2668.png new file mode 100644 index 00000000..53f5a3f9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2668.png differ diff --git a/twake/frontend/public/public/emojione/64/267b.png b/twake/frontend/public/public/emojione/64/267b.png new file mode 100644 index 00000000..573fc749 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/267b.png differ diff --git a/twake/frontend/public/public/emojione/64/267e.png b/twake/frontend/public/public/emojione/64/267e.png new file mode 100644 index 00000000..292dc513 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/267e.png differ diff --git a/twake/frontend/public/public/emojione/64/267f.png b/twake/frontend/public/public/emojione/64/267f.png new file mode 100644 index 00000000..4f37bc6c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/267f.png differ diff --git a/twake/frontend/public/public/emojione/64/2692.png b/twake/frontend/public/public/emojione/64/2692.png new file mode 100644 index 00000000..0feaa6e0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2692.png differ diff --git a/twake/frontend/public/public/emojione/64/2693.png b/twake/frontend/public/public/emojione/64/2693.png new file mode 100644 index 00000000..282c304c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2693.png differ diff --git a/twake/frontend/public/public/emojione/64/2694.png b/twake/frontend/public/public/emojione/64/2694.png new file mode 100644 index 00000000..84b978ed Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2694.png differ diff --git a/twake/frontend/public/public/emojione/64/2695.png b/twake/frontend/public/public/emojione/64/2695.png new file mode 100644 index 00000000..95850b82 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2695.png differ diff --git a/twake/frontend/public/public/emojione/64/2696.png b/twake/frontend/public/public/emojione/64/2696.png new file mode 100644 index 00000000..2615907a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2696.png differ diff --git a/twake/frontend/public/public/emojione/64/2697.png b/twake/frontend/public/public/emojione/64/2697.png new file mode 100644 index 00000000..61ad3918 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2697.png differ diff --git a/twake/frontend/public/public/emojione/64/2699.png b/twake/frontend/public/public/emojione/64/2699.png new file mode 100644 index 00000000..1b57c384 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2699.png differ diff --git a/twake/frontend/public/public/emojione/64/269b.png b/twake/frontend/public/public/emojione/64/269b.png new file mode 100644 index 00000000..fbee0e6a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/269b.png differ diff --git a/twake/frontend/public/public/emojione/64/269c.png b/twake/frontend/public/public/emojione/64/269c.png new file mode 100644 index 00000000..8db0d3df Binary files /dev/null and b/twake/frontend/public/public/emojione/64/269c.png differ diff --git a/twake/frontend/public/public/emojione/64/26a0.png b/twake/frontend/public/public/emojione/64/26a0.png new file mode 100644 index 00000000..a84c0e92 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26a0.png differ diff --git a/twake/frontend/public/public/emojione/64/26a1.png b/twake/frontend/public/public/emojione/64/26a1.png new file mode 100644 index 00000000..89cbbe45 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26a1.png differ diff --git a/twake/frontend/public/public/emojione/64/26aa.png b/twake/frontend/public/public/emojione/64/26aa.png new file mode 100644 index 00000000..bc8a9492 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26aa.png differ diff --git a/twake/frontend/public/public/emojione/64/26ab.png b/twake/frontend/public/public/emojione/64/26ab.png new file mode 100644 index 00000000..c1568080 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26ab.png differ diff --git a/twake/frontend/public/public/emojione/64/26b0.png b/twake/frontend/public/public/emojione/64/26b0.png new file mode 100644 index 00000000..a335c665 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26b0.png differ diff --git a/twake/frontend/public/public/emojione/64/26b1.png b/twake/frontend/public/public/emojione/64/26b1.png new file mode 100644 index 00000000..494920c7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26b1.png differ diff --git a/twake/frontend/public/public/emojione/64/26bd.png b/twake/frontend/public/public/emojione/64/26bd.png new file mode 100644 index 00000000..1bb5cb48 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26bd.png differ diff --git a/twake/frontend/public/public/emojione/64/26be.png b/twake/frontend/public/public/emojione/64/26be.png new file mode 100644 index 00000000..2359e0b5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26be.png differ diff --git a/twake/frontend/public/public/emojione/64/26c4.png b/twake/frontend/public/public/emojione/64/26c4.png new file mode 100644 index 00000000..a6f084c8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26c4.png differ diff --git a/twake/frontend/public/public/emojione/64/26c5.png b/twake/frontend/public/public/emojione/64/26c5.png new file mode 100644 index 00000000..3132a219 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26c5.png differ diff --git a/twake/frontend/public/public/emojione/64/26c8.png b/twake/frontend/public/public/emojione/64/26c8.png new file mode 100644 index 00000000..90d2b092 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26c8.png differ diff --git a/twake/frontend/public/public/emojione/64/26ce.png b/twake/frontend/public/public/emojione/64/26ce.png new file mode 100644 index 00000000..036aaf8c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26ce.png differ diff --git a/twake/frontend/public/public/emojione/64/26cf.png b/twake/frontend/public/public/emojione/64/26cf.png new file mode 100644 index 00000000..acf7a6c6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26cf.png differ diff --git a/twake/frontend/public/public/emojione/64/26d1.png b/twake/frontend/public/public/emojione/64/26d1.png new file mode 100644 index 00000000..b1493816 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26d1.png differ diff --git a/twake/frontend/public/public/emojione/64/26d3.png b/twake/frontend/public/public/emojione/64/26d3.png new file mode 100644 index 00000000..5bdec7ca Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26d3.png differ diff --git a/twake/frontend/public/public/emojione/64/26d4.png b/twake/frontend/public/public/emojione/64/26d4.png new file mode 100644 index 00000000..1f1de6eb Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26d4.png differ diff --git a/twake/frontend/public/public/emojione/64/26e9.png b/twake/frontend/public/public/emojione/64/26e9.png new file mode 100644 index 00000000..97f29013 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26e9.png differ diff --git a/twake/frontend/public/public/emojione/64/26ea.png b/twake/frontend/public/public/emojione/64/26ea.png new file mode 100644 index 00000000..8303dfd7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26ea.png differ diff --git a/twake/frontend/public/public/emojione/64/26f0.png b/twake/frontend/public/public/emojione/64/26f0.png new file mode 100644 index 00000000..f76d4304 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f0.png differ diff --git a/twake/frontend/public/public/emojione/64/26f1.png b/twake/frontend/public/public/emojione/64/26f1.png new file mode 100644 index 00000000..8c2472fa Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f1.png differ diff --git a/twake/frontend/public/public/emojione/64/26f2.png b/twake/frontend/public/public/emojione/64/26f2.png new file mode 100644 index 00000000..6307d8b8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f2.png differ diff --git a/twake/frontend/public/public/emojione/64/26f3.png b/twake/frontend/public/public/emojione/64/26f3.png new file mode 100644 index 00000000..506d99f4 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f3.png differ diff --git a/twake/frontend/public/public/emojione/64/26f4.png b/twake/frontend/public/public/emojione/64/26f4.png new file mode 100644 index 00000000..27158b56 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f4.png differ diff --git a/twake/frontend/public/public/emojione/64/26f5.png b/twake/frontend/public/public/emojione/64/26f5.png new file mode 100644 index 00000000..0c54281e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f5.png differ diff --git a/twake/frontend/public/public/emojione/64/26f7.png b/twake/frontend/public/public/emojione/64/26f7.png new file mode 100644 index 00000000..7ff786fe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f7.png differ diff --git a/twake/frontend/public/public/emojione/64/26f8.png b/twake/frontend/public/public/emojione/64/26f8.png new file mode 100644 index 00000000..0b85771e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f8.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9-1f3fb-2640.png b/twake/frontend/public/public/emojione/64/26f9-1f3fb-2640.png new file mode 100644 index 00000000..dbfe9521 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9-1f3fb-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9-1f3fb-2642.png b/twake/frontend/public/public/emojione/64/26f9-1f3fb-2642.png new file mode 100644 index 00000000..92d865fe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9-1f3fb-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9-1f3fb.png b/twake/frontend/public/public/emojione/64/26f9-1f3fb.png new file mode 100644 index 00000000..92d865fe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9-1f3fc-2640.png b/twake/frontend/public/public/emojione/64/26f9-1f3fc-2640.png new file mode 100644 index 00000000..bd824d59 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9-1f3fc-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9-1f3fc-2642.png b/twake/frontend/public/public/emojione/64/26f9-1f3fc-2642.png new file mode 100644 index 00000000..b0cc6b17 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9-1f3fc-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9-1f3fc.png b/twake/frontend/public/public/emojione/64/26f9-1f3fc.png new file mode 100644 index 00000000..b0cc6b17 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9-1f3fd-2640.png b/twake/frontend/public/public/emojione/64/26f9-1f3fd-2640.png new file mode 100644 index 00000000..8fbd25d6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9-1f3fd-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9-1f3fd-2642.png b/twake/frontend/public/public/emojione/64/26f9-1f3fd-2642.png new file mode 100644 index 00000000..5ae85776 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9-1f3fd-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9-1f3fd.png b/twake/frontend/public/public/emojione/64/26f9-1f3fd.png new file mode 100644 index 00000000..5ae85776 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9-1f3fe-2640.png b/twake/frontend/public/public/emojione/64/26f9-1f3fe-2640.png new file mode 100644 index 00000000..b4ecf4d0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9-1f3fe-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9-1f3fe-2642.png b/twake/frontend/public/public/emojione/64/26f9-1f3fe-2642.png new file mode 100644 index 00000000..0ca3f3fc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9-1f3fe-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9-1f3fe.png b/twake/frontend/public/public/emojione/64/26f9-1f3fe.png new file mode 100644 index 00000000..0ca3f3fc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9-1f3ff-2640.png b/twake/frontend/public/public/emojione/64/26f9-1f3ff-2640.png new file mode 100644 index 00000000..daeaf169 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9-1f3ff-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9-1f3ff-2642.png b/twake/frontend/public/public/emojione/64/26f9-1f3ff-2642.png new file mode 100644 index 00000000..59d5346b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9-1f3ff-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9-1f3ff.png b/twake/frontend/public/public/emojione/64/26f9-1f3ff.png new file mode 100644 index 00000000..59d5346b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9-2640.png b/twake/frontend/public/public/emojione/64/26f9-2640.png new file mode 100644 index 00000000..23f55ddc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9-2640.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9-2642.png b/twake/frontend/public/public/emojione/64/26f9-2642.png new file mode 100644 index 00000000..897394bc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9-2642.png differ diff --git a/twake/frontend/public/public/emojione/64/26f9.png b/twake/frontend/public/public/emojione/64/26f9.png new file mode 100644 index 00000000..897394bc Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26f9.png differ diff --git a/twake/frontend/public/public/emojione/64/26fa.png b/twake/frontend/public/public/emojione/64/26fa.png new file mode 100644 index 00000000..3b6d7c5b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26fa.png differ diff --git a/twake/frontend/public/public/emojione/64/26fd.png b/twake/frontend/public/public/emojione/64/26fd.png new file mode 100644 index 00000000..97f47b0d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/26fd.png differ diff --git a/twake/frontend/public/public/emojione/64/2702.png b/twake/frontend/public/public/emojione/64/2702.png new file mode 100644 index 00000000..6ba49157 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2702.png differ diff --git a/twake/frontend/public/public/emojione/64/2705.png b/twake/frontend/public/public/emojione/64/2705.png new file mode 100644 index 00000000..dd33a069 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2705.png differ diff --git a/twake/frontend/public/public/emojione/64/2708.png b/twake/frontend/public/public/emojione/64/2708.png new file mode 100644 index 00000000..be64cd4e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2708.png differ diff --git a/twake/frontend/public/public/emojione/64/2709.png b/twake/frontend/public/public/emojione/64/2709.png new file mode 100644 index 00000000..054e2ed3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2709.png differ diff --git a/twake/frontend/public/public/emojione/64/270a-1f3fb.png b/twake/frontend/public/public/emojione/64/270a-1f3fb.png new file mode 100644 index 00000000..e30aa126 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270a-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/270a-1f3fc.png b/twake/frontend/public/public/emojione/64/270a-1f3fc.png new file mode 100644 index 00000000..e8dfdb11 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270a-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/270a-1f3fd.png b/twake/frontend/public/public/emojione/64/270a-1f3fd.png new file mode 100644 index 00000000..127cfdb6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270a-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/270a-1f3fe.png b/twake/frontend/public/public/emojione/64/270a-1f3fe.png new file mode 100644 index 00000000..36b6505d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270a-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/270a-1f3ff.png b/twake/frontend/public/public/emojione/64/270a-1f3ff.png new file mode 100644 index 00000000..40a8bd47 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270a-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/270a.png b/twake/frontend/public/public/emojione/64/270a.png new file mode 100644 index 00000000..e3bd9d1c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270a.png differ diff --git a/twake/frontend/public/public/emojione/64/270b-1f3fb.png b/twake/frontend/public/public/emojione/64/270b-1f3fb.png new file mode 100644 index 00000000..3e3b8e64 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270b-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/270b-1f3fc.png b/twake/frontend/public/public/emojione/64/270b-1f3fc.png new file mode 100644 index 00000000..629d1a82 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270b-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/270b-1f3fd.png b/twake/frontend/public/public/emojione/64/270b-1f3fd.png new file mode 100644 index 00000000..97cd61dd Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270b-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/270b-1f3fe.png b/twake/frontend/public/public/emojione/64/270b-1f3fe.png new file mode 100644 index 00000000..16f52f91 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270b-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/270b-1f3ff.png b/twake/frontend/public/public/emojione/64/270b-1f3ff.png new file mode 100644 index 00000000..59198a64 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270b-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/270b.png b/twake/frontend/public/public/emojione/64/270b.png new file mode 100644 index 00000000..41c75c8c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270b.png differ diff --git a/twake/frontend/public/public/emojione/64/270c-1f3fb.png b/twake/frontend/public/public/emojione/64/270c-1f3fb.png new file mode 100644 index 00000000..49d20567 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270c-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/270c-1f3fc.png b/twake/frontend/public/public/emojione/64/270c-1f3fc.png new file mode 100644 index 00000000..6209dab0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270c-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/270c-1f3fd.png b/twake/frontend/public/public/emojione/64/270c-1f3fd.png new file mode 100644 index 00000000..f899c5f7 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270c-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/270c-1f3fe.png b/twake/frontend/public/public/emojione/64/270c-1f3fe.png new file mode 100644 index 00000000..1d7ddc7e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270c-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/270c-1f3ff.png b/twake/frontend/public/public/emojione/64/270c-1f3ff.png new file mode 100644 index 00000000..80eedcd3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270c-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/270c.png b/twake/frontend/public/public/emojione/64/270c.png new file mode 100644 index 00000000..37e4d8da Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270c.png differ diff --git a/twake/frontend/public/public/emojione/64/270d-1f3fb.png b/twake/frontend/public/public/emojione/64/270d-1f3fb.png new file mode 100644 index 00000000..13fbf724 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270d-1f3fb.png differ diff --git a/twake/frontend/public/public/emojione/64/270d-1f3fc.png b/twake/frontend/public/public/emojione/64/270d-1f3fc.png new file mode 100644 index 00000000..32268648 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270d-1f3fc.png differ diff --git a/twake/frontend/public/public/emojione/64/270d-1f3fd.png b/twake/frontend/public/public/emojione/64/270d-1f3fd.png new file mode 100644 index 00000000..7302e455 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270d-1f3fd.png differ diff --git a/twake/frontend/public/public/emojione/64/270d-1f3fe.png b/twake/frontend/public/public/emojione/64/270d-1f3fe.png new file mode 100644 index 00000000..8ed579be Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270d-1f3fe.png differ diff --git a/twake/frontend/public/public/emojione/64/270d-1f3ff.png b/twake/frontend/public/public/emojione/64/270d-1f3ff.png new file mode 100644 index 00000000..7da5b27d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270d-1f3ff.png differ diff --git a/twake/frontend/public/public/emojione/64/270d.png b/twake/frontend/public/public/emojione/64/270d.png new file mode 100644 index 00000000..f6d29ed3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270d.png differ diff --git a/twake/frontend/public/public/emojione/64/270f.png b/twake/frontend/public/public/emojione/64/270f.png new file mode 100644 index 00000000..7d8ac2c0 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/270f.png differ diff --git a/twake/frontend/public/public/emojione/64/2712.png b/twake/frontend/public/public/emojione/64/2712.png new file mode 100644 index 00000000..bddb2484 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2712.png differ diff --git a/twake/frontend/public/public/emojione/64/2714.png b/twake/frontend/public/public/emojione/64/2714.png new file mode 100644 index 00000000..2cbdf07a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2714.png differ diff --git a/twake/frontend/public/public/emojione/64/2716.png b/twake/frontend/public/public/emojione/64/2716.png new file mode 100644 index 00000000..79c6a765 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2716.png differ diff --git a/twake/frontend/public/public/emojione/64/271d.png b/twake/frontend/public/public/emojione/64/271d.png new file mode 100644 index 00000000..dc927726 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/271d.png differ diff --git a/twake/frontend/public/public/emojione/64/2721.png b/twake/frontend/public/public/emojione/64/2721.png new file mode 100644 index 00000000..c83a53ce Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2721.png differ diff --git a/twake/frontend/public/public/emojione/64/2728.png b/twake/frontend/public/public/emojione/64/2728.png new file mode 100644 index 00000000..72855990 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2728.png differ diff --git a/twake/frontend/public/public/emojione/64/2733.png b/twake/frontend/public/public/emojione/64/2733.png new file mode 100644 index 00000000..bb7a404a Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2733.png differ diff --git a/twake/frontend/public/public/emojione/64/2734.png b/twake/frontend/public/public/emojione/64/2734.png new file mode 100644 index 00000000..1216224d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2734.png differ diff --git a/twake/frontend/public/public/emojione/64/2744.png b/twake/frontend/public/public/emojione/64/2744.png new file mode 100644 index 00000000..f7ee93e5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2744.png differ diff --git a/twake/frontend/public/public/emojione/64/2747.png b/twake/frontend/public/public/emojione/64/2747.png new file mode 100644 index 00000000..ad23ebc3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2747.png differ diff --git a/twake/frontend/public/public/emojione/64/274c.png b/twake/frontend/public/public/emojione/64/274c.png new file mode 100644 index 00000000..71b103d5 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/274c.png differ diff --git a/twake/frontend/public/public/emojione/64/274e.png b/twake/frontend/public/public/emojione/64/274e.png new file mode 100644 index 00000000..f8238969 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/274e.png differ diff --git a/twake/frontend/public/public/emojione/64/2753.png b/twake/frontend/public/public/emojione/64/2753.png new file mode 100644 index 00000000..b76c90f6 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2753.png differ diff --git a/twake/frontend/public/public/emojione/64/2754.png b/twake/frontend/public/public/emojione/64/2754.png new file mode 100644 index 00000000..5fc04cf3 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2754.png differ diff --git a/twake/frontend/public/public/emojione/64/2755.png b/twake/frontend/public/public/emojione/64/2755.png new file mode 100644 index 00000000..4a4f0dd2 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2755.png differ diff --git a/twake/frontend/public/public/emojione/64/2757.png b/twake/frontend/public/public/emojione/64/2757.png new file mode 100644 index 00000000..2c8f709c Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2757.png differ diff --git a/twake/frontend/public/public/emojione/64/2763.png b/twake/frontend/public/public/emojione/64/2763.png new file mode 100644 index 00000000..891838ac Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2763.png differ diff --git a/twake/frontend/public/public/emojione/64/2764.png b/twake/frontend/public/public/emojione/64/2764.png new file mode 100644 index 00000000..2157cf2b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2764.png differ diff --git a/twake/frontend/public/public/emojione/64/2795.png b/twake/frontend/public/public/emojione/64/2795.png new file mode 100644 index 00000000..4b6009cf Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2795.png differ diff --git a/twake/frontend/public/public/emojione/64/2796.png b/twake/frontend/public/public/emojione/64/2796.png new file mode 100644 index 00000000..b5674442 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2796.png differ diff --git a/twake/frontend/public/public/emojione/64/2797.png b/twake/frontend/public/public/emojione/64/2797.png new file mode 100644 index 00000000..eabb4a83 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2797.png differ diff --git a/twake/frontend/public/public/emojione/64/27a1.png b/twake/frontend/public/public/emojione/64/27a1.png new file mode 100644 index 00000000..a3394f4e Binary files /dev/null and b/twake/frontend/public/public/emojione/64/27a1.png differ diff --git a/twake/frontend/public/public/emojione/64/27b0.png b/twake/frontend/public/public/emojione/64/27b0.png new file mode 100644 index 00000000..ef3a9e60 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/27b0.png differ diff --git a/twake/frontend/public/public/emojione/64/27bf.png b/twake/frontend/public/public/emojione/64/27bf.png new file mode 100644 index 00000000..19d487ad Binary files /dev/null and b/twake/frontend/public/public/emojione/64/27bf.png differ diff --git a/twake/frontend/public/public/emojione/64/2934.png b/twake/frontend/public/public/emojione/64/2934.png new file mode 100644 index 00000000..146e86a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2934.png differ diff --git a/twake/frontend/public/public/emojione/64/2935.png b/twake/frontend/public/public/emojione/64/2935.png new file mode 100644 index 00000000..e432b5fe Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2935.png differ diff --git a/twake/frontend/public/public/emojione/64/2b05.png b/twake/frontend/public/public/emojione/64/2b05.png new file mode 100644 index 00000000..5114c67b Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2b05.png differ diff --git a/twake/frontend/public/public/emojione/64/2b06.png b/twake/frontend/public/public/emojione/64/2b06.png new file mode 100644 index 00000000..e0074612 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2b06.png differ diff --git a/twake/frontend/public/public/emojione/64/2b07.png b/twake/frontend/public/public/emojione/64/2b07.png new file mode 100644 index 00000000..400ac6a8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2b07.png differ diff --git a/twake/frontend/public/public/emojione/64/2b1b.png b/twake/frontend/public/public/emojione/64/2b1b.png new file mode 100644 index 00000000..cad5a9ba Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2b1b.png differ diff --git a/twake/frontend/public/public/emojione/64/2b1c.png b/twake/frontend/public/public/emojione/64/2b1c.png new file mode 100644 index 00000000..6d95e48d Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2b1c.png differ diff --git a/twake/frontend/public/public/emojione/64/2b50.png b/twake/frontend/public/public/emojione/64/2b50.png new file mode 100644 index 00000000..72ac58ee Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2b50.png differ diff --git a/twake/frontend/public/public/emojione/64/2b55.png b/twake/frontend/public/public/emojione/64/2b55.png new file mode 100644 index 00000000..fdacf182 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/2b55.png differ diff --git a/twake/frontend/public/public/emojione/64/3030.png b/twake/frontend/public/public/emojione/64/3030.png new file mode 100644 index 00000000..7ac0d5a9 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/3030.png differ diff --git a/twake/frontend/public/public/emojione/64/303d.png b/twake/frontend/public/public/emojione/64/303d.png new file mode 100644 index 00000000..ed33eb25 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/303d.png differ diff --git a/twake/frontend/public/public/emojione/64/3297.png b/twake/frontend/public/public/emojione/64/3297.png new file mode 100644 index 00000000..ff485a87 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/3297.png differ diff --git a/twake/frontend/public/public/emojione/64/3299.png b/twake/frontend/public/public/emojione/64/3299.png new file mode 100644 index 00000000..feefe7d8 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/3299.png differ diff --git a/twake/frontend/public/public/emojione/64/_alt/1f52b.png b/twake/frontend/public/public/emojione/64/_alt/1f52b.png new file mode 100644 index 00000000..d5cb0281 Binary files /dev/null and b/twake/frontend/public/public/emojione/64/_alt/1f52b.png differ diff --git a/twake/frontend/public/public/emojione/categories/activity.svg b/twake/frontend/public/public/emojione/categories/activity.svg new file mode 100644 index 00000000..623e59c8 --- /dev/null +++ b/twake/frontend/public/public/emojione/categories/activity.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/twake/frontend/public/public/emojione/categories/diversity.svg b/twake/frontend/public/public/emojione/categories/diversity.svg new file mode 100644 index 00000000..2498950f --- /dev/null +++ b/twake/frontend/public/public/emojione/categories/diversity.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/twake/frontend/public/public/emojione/categories/flags.svg b/twake/frontend/public/public/emojione/categories/flags.svg new file mode 100644 index 00000000..f3ee7a4d --- /dev/null +++ b/twake/frontend/public/public/emojione/categories/flags.svg @@ -0,0 +1,11 @@ + + + + + diff --git a/twake/frontend/public/public/emojione/categories/food.svg b/twake/frontend/public/public/emojione/categories/food.svg new file mode 100644 index 00000000..22bb48c4 --- /dev/null +++ b/twake/frontend/public/public/emojione/categories/food.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + diff --git a/twake/frontend/public/public/emojione/categories/nature.svg b/twake/frontend/public/public/emojione/categories/nature.svg new file mode 100644 index 00000000..0be17020 --- /dev/null +++ b/twake/frontend/public/public/emojione/categories/nature.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + diff --git a/twake/frontend/public/public/emojione/categories/objects.svg b/twake/frontend/public/public/emojione/categories/objects.svg new file mode 100644 index 00000000..ae0b893f --- /dev/null +++ b/twake/frontend/public/public/emojione/categories/objects.svg @@ -0,0 +1,30 @@ + + + + + diff --git a/twake/frontend/public/public/emojione/categories/people.svg b/twake/frontend/public/public/emojione/categories/people.svg new file mode 100644 index 00000000..70d0487d --- /dev/null +++ b/twake/frontend/public/public/emojione/categories/people.svg @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/twake/frontend/public/public/emojione/categories/recent.svg b/twake/frontend/public/public/emojione/categories/recent.svg new file mode 100644 index 00000000..e79b2ebc --- /dev/null +++ b/twake/frontend/public/public/emojione/categories/recent.svg @@ -0,0 +1,29 @@ + +image/svg+xml \ No newline at end of file diff --git a/twake/frontend/public/public/emojione/categories/symbols.svg b/twake/frontend/public/public/emojione/categories/symbols.svg new file mode 100644 index 00000000..2e4ea009 --- /dev/null +++ b/twake/frontend/public/public/emojione/categories/symbols.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + diff --git a/twake/frontend/public/public/emojione/categories/travel.svg b/twake/frontend/public/public/emojione/categories/travel.svg new file mode 100644 index 00000000..248c2420 --- /dev/null +++ b/twake/frontend/public/public/emojione/categories/travel.svg @@ -0,0 +1,33 @@ + + + + + + + + + diff --git a/twake/frontend/public/public/font/fontastic.css b/twake/frontend/public/public/font/fontastic.css new file mode 100755 index 00000000..a73c9744 --- /dev/null +++ b/twake/frontend/public/public/font/fontastic.css @@ -0,0 +1,255 @@ +@charset "UTF-8"; + +@font-face { + font-family: 'twake-fontastic'; + src: url('fontastic/twake-fontastic.eot'); + src: url('fontastic/twake-fontastic.eot?#iefix') format('embedded-opentype'), + url('fontastic/twake-fontastic.woff') format('woff'), + url('fontastic/twake-fontastic.ttf') format('truetype'), + url('fontastic/twake-fontastic.svg#twake-fontastic') format('svg'); + font-weight: normal; + font-style: normal; +} + +[data-icon]:before { + font-family: 'twake-fontastic' !important; + content: attr(data-icon); + font-style: normal !important; + font-weight: normal !important; + font-variant: normal !important; + text-transform: none !important; + speak: none; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +[class^='icon-']:before, +[class*=' icon-']:before { + font-family: 'twake-fontastic' !important; + font-style: normal !important; + font-weight: normal !important; + font-variant: normal !important; + text-transform: none !important; + speak: none; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-add-circle:before { + content: '\61'; +} +.icon-camera:before { + content: '\62'; +} +.icon-check-circle:before { + content: '\63'; +} +.icon-chevron-bottom:before { + content: '\64'; +} +.icon-chevron-left:before { + content: '\65'; +} +.icon-chevron-right:before { + content: '\66'; +} +.icon-clock:before { + content: '\67'; +} +.icon-close:before { + content: '\68'; +} +.icon-close-circle:before { + content: '\69'; +} +.icon-comment:before { + content: '\6a'; +} +.icon-danger-circle:before { + content: '\6b'; +} +.icon-directory:before { + content: '\6c'; +} +.icon-directory-open:before { + content: '\6d'; +} +.icon-down:before { + content: '\6e'; +} +.icon-down-circle:before { + content: '\6f'; +} +.icon-download:before { + content: '\70'; +} +.icon-exchange:before { + content: '\71'; +} +.icon-exit:before { + content: '\72'; +} +.icon-expand:before { + content: '\73'; +} +.icon-export:before { + content: '\74'; +} +.icon-eye:before { + content: '\75'; +} +.icon-file:before { + content: '\76'; +} +.icon-gear:before { + content: '\77'; +} +.icon-grid:before { + content: '\78'; +} +.icon-heart:before { + content: '\79'; +} +.icon-home:before { + content: '\7a'; +} +.icon-inbox:before { + content: '\41'; +} +.icon-info-circle:before { + content: '\42'; +} +.icon-label:before { + content: '\43'; +} +.icon-left-circle:before { + content: '\44'; +} +.icon-left-line:before { + content: '\45'; +} +.icon-left-right:before { + content: '\46'; +} +.icon-link:before { + content: '\47'; +} +.icon-list:before { + content: '\48'; +} +.icon-location:before { + content: '\49'; +} +.icon-locked:before { + content: '\4a'; +} +.icon-mail:before { + content: '\4b'; +} +.icon-minus-circle:before { + content: '\4c'; +} +.icon-monitor:before { + content: '\4d'; +} +.icon-paper-clip:before { + content: '\4e'; +} +.icon-pause-circle:before { + content: '\4f'; +} +.icon-phone:before { + content: '\50'; +} +.icon-pin:before { + content: '\51'; +} +.icon-plus:before { + content: '\52'; +} +.icon-plus-circle:before { + content: '\53'; +} +.icon-power-circle:before { + content: '\54'; +} +.icon-qrcode:before { + content: '\55'; +} +.icon-question-circle:before { + content: '\56'; +} +.icon-reload:before { + content: '\57'; +} +.icon-respond:before { + content: '\58'; +} +.icon-right-line:before { + content: '\59'; +} +.icon-save:before { + content: '\5a'; +} +.icon-search:before { + content: '\30'; +} +.icon-send:before { + content: '\31'; +} +.icon-share:before { + content: '\32'; +} +.icon-shrink:before { + content: '\33'; +} +.icon-smiley:before { + content: '\34'; +} +.icon-smiley-neutral:before { + content: '\35'; +} +.icon-smiley-sad:before { + content: '\36'; +} +.icon-smileys:before { + content: '\37'; +} +.icon-star:before { + content: '\38'; +} +.icon-thumbs-down:before { + content: '\39'; +} +.icon-thumbs-up:before { + content: '\21'; +} +.icon-trash:before { + content: '\22'; +} +.icon-type-image:before { + content: '\23'; +} +.icon-unlocked:before { + content: '\24'; +} +.icon-up:before { + content: '\25'; +} +.icon-up-circle:before { + content: '\26'; +} +.icon-upload:before { + content: '\27'; +} +.icon-user:before { + content: '\28'; +} +.icon-write:before { + content: '\29'; +} +.icon-bell:before { + content: '\2a'; +} diff --git a/twake/frontend/public/public/font/fontastic/twake-fontastic.eot b/twake/frontend/public/public/font/fontastic/twake-fontastic.eot new file mode 100755 index 00000000..ce59a204 Binary files /dev/null and b/twake/frontend/public/public/font/fontastic/twake-fontastic.eot differ diff --git a/twake/frontend/public/public/font/fontastic/twake-fontastic.svg b/twake/frontend/public/public/font/fontastic/twake-fontastic.svg new file mode 100755 index 00000000..b19b4162 --- /dev/null +++ b/twake/frontend/public/public/font/fontastic/twake-fontastic.svg @@ -0,0 +1,82 @@ + + + +Generated by Fontastic.me + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/twake/frontend/public/public/font/fontastic/twake-fontastic.ttf b/twake/frontend/public/public/font/fontastic/twake-fontastic.ttf new file mode 100755 index 00000000..a0381707 Binary files /dev/null and b/twake/frontend/public/public/font/fontastic/twake-fontastic.ttf differ diff --git a/twake/frontend/public/public/font/fontastic/twake-fontastic.woff b/twake/frontend/public/public/font/fontastic/twake-fontastic.woff new file mode 100755 index 00000000..7988645f Binary files /dev/null and b/twake/frontend/public/public/font/fontastic/twake-fontastic.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueBlackCondensed.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueBlackCondensed.eot new file mode 100644 index 00000000..9e85640c Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueBlackCondensed.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueBlackCondensed.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueBlackCondensed.ttf new file mode 100644 index 00000000..0bb8f49d Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueBlackCondensed.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueBlackCondensed.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueBlackCondensed.woff new file mode 100644 index 00000000..3b6fe1b9 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueBlackCondensed.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueBlackCondensed.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueBlackCondensed.woff2 new file mode 100644 index 00000000..540e93af Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueBlackCondensed.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueBoldCondensed.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueBoldCondensed.eot new file mode 100644 index 00000000..9c23a359 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueBoldCondensed.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueBoldCondensed.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueBoldCondensed.ttf new file mode 100644 index 00000000..f27aca7f Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueBoldCondensed.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueBoldCondensed.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueBoldCondensed.woff new file mode 100644 index 00000000..2eb281c3 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueBoldCondensed.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueBoldCondensed.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueBoldCondensed.woff2 new file mode 100644 index 00000000..8ed4218e Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueBoldCondensed.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Black.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Black.eot new file mode 100644 index 00000000..192a2fe4 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Black.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Black.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Black.ttf new file mode 100644 index 00000000..ee17c2d5 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Black.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Black.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Black.woff new file mode 100644 index 00000000..ae67a0db Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Black.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Black.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Black.woff2 new file mode 100644 index 00000000..3c87f889 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Black.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BlackItalic.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BlackItalic.eot new file mode 100644 index 00000000..6b13bdd6 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BlackItalic.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BlackItalic.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BlackItalic.ttf new file mode 100644 index 00000000..3ee26aad Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BlackItalic.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BlackItalic.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BlackItalic.woff new file mode 100644 index 00000000..5c8cdeb5 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BlackItalic.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BlackItalic.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BlackItalic.woff2 new file mode 100644 index 00000000..fa8598d3 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BlackItalic.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Bold.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Bold.eot new file mode 100644 index 00000000..5e2eec07 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Bold.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Bold.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Bold.ttf new file mode 100644 index 00000000..ceb575a5 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Bold.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Bold.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Bold.woff new file mode 100644 index 00000000..c3ae53d2 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Bold.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Bold.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Bold.woff2 new file mode 100644 index 00000000..2268496f Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Bold.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BoldItalic.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BoldItalic.eot new file mode 100644 index 00000000..99c89719 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BoldItalic.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BoldItalic.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BoldItalic.ttf new file mode 100644 index 00000000..f6a54eff Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BoldItalic.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BoldItalic.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BoldItalic.woff new file mode 100644 index 00000000..fe3f72a3 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BoldItalic.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BoldItalic.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BoldItalic.woff2 new file mode 100644 index 00000000..618738d8 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-BoldItalic.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Heavy.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Heavy.eot new file mode 100644 index 00000000..79de797c Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Heavy.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Heavy.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Heavy.ttf new file mode 100644 index 00000000..8ae830b0 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Heavy.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Heavy.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Heavy.woff new file mode 100644 index 00000000..d8a9613f Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Heavy.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Heavy.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Heavy.woff2 new file mode 100644 index 00000000..fe2cf4ff Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Heavy.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-HeavyItalic.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-HeavyItalic.eot new file mode 100644 index 00000000..ecf0b9b5 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-HeavyItalic.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-HeavyItalic.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-HeavyItalic.ttf new file mode 100644 index 00000000..951cc548 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-HeavyItalic.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-HeavyItalic.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-HeavyItalic.woff new file mode 100644 index 00000000..38c99a9d Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-HeavyItalic.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-HeavyItalic.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-HeavyItalic.woff2 new file mode 100644 index 00000000..89632e58 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-HeavyItalic.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Italic.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Italic.eot new file mode 100644 index 00000000..a4d5e6ea Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Italic.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Italic.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Italic.ttf new file mode 100644 index 00000000..223fcf37 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Italic.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Italic.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Italic.woff new file mode 100644 index 00000000..df541397 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Italic.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Italic.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Italic.woff2 new file mode 100644 index 00000000..dc80c89e Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Italic.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Light.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Light.eot new file mode 100644 index 00000000..483be51f Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Light.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Light.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Light.ttf new file mode 100644 index 00000000..9f8077b2 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Light.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Light.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Light.woff new file mode 100644 index 00000000..2dcf96ff Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Light.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Light.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Light.woff2 new file mode 100644 index 00000000..5dbe24e3 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Light.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-LightItalic.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-LightItalic.eot new file mode 100644 index 00000000..39d54363 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-LightItalic.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-LightItalic.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-LightItalic.ttf new file mode 100644 index 00000000..ba410e4b Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-LightItalic.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-LightItalic.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-LightItalic.woff new file mode 100644 index 00000000..29425af8 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-LightItalic.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-LightItalic.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-LightItalic.woff2 new file mode 100644 index 00000000..12e2f87c Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-LightItalic.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Medium.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Medium.eot new file mode 100644 index 00000000..c94ceb97 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Medium.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Medium.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Medium.ttf new file mode 100644 index 00000000..39bf3260 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Medium.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Medium.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Medium.woff new file mode 100644 index 00000000..1dd4457e Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Medium.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Medium.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Medium.woff2 new file mode 100644 index 00000000..e8799b1e Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Medium.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-MediumItalic.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-MediumItalic.eot new file mode 100644 index 00000000..500d53fb Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-MediumItalic.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-MediumItalic.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-MediumItalic.ttf new file mode 100644 index 00000000..e0e4aa37 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-MediumItalic.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-MediumItalic.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-MediumItalic.woff new file mode 100644 index 00000000..cb60bc48 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-MediumItalic.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-MediumItalic.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-MediumItalic.woff2 new file mode 100644 index 00000000..b8df051d Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-MediumItalic.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Roman.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Roman.eot new file mode 100644 index 00000000..e7f78ab2 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Roman.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Roman.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Roman.ttf new file mode 100644 index 00000000..b0c6ae51 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Roman.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Roman.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Roman.woff new file mode 100644 index 00000000..8538e298 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Roman.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Roman.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Roman.woff2 new file mode 100644 index 00000000..256cb760 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Roman.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Thin.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Thin.eot new file mode 100644 index 00000000..c3c8e436 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Thin.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Thin.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Thin.ttf new file mode 100644 index 00000000..4658191e Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Thin.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Thin.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Thin.woff new file mode 100644 index 00000000..7a29f3fc Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Thin.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Thin.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Thin.woff2 new file mode 100644 index 00000000..b53fba0d Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-Thin.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-ThinItalic.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-ThinItalic.eot new file mode 100644 index 00000000..96483732 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-ThinItalic.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-ThinItalic.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-ThinItalic.ttf new file mode 100644 index 00000000..4a5fade1 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-ThinItalic.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-ThinItalic.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-ThinItalic.woff new file mode 100644 index 00000000..42938f47 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-ThinItalic.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-ThinItalic.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-ThinItalic.woff2 new file mode 100644 index 00000000..3faf6f52 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-ThinItalic.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLight.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLight.eot new file mode 100644 index 00000000..d2fdf6fb Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLight.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLight.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLight.ttf new file mode 100644 index 00000000..9a77f230 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLight.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLight.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLight.woff new file mode 100644 index 00000000..2a0cac31 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLight.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLight.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLight.woff2 new file mode 100644 index 00000000..2ba52147 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLight.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLightItalic.eot b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLightItalic.eot new file mode 100644 index 00000000..f744c14c Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLightItalic.eot differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLightItalic.ttf b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLightItalic.ttf new file mode 100644 index 00000000..33f8ada9 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLightItalic.ttf differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLightItalic.woff b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLightItalic.woff new file mode 100644 index 00000000..897bd21c Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLightItalic.woff differ diff --git a/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLightItalic.woff2 b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLightItalic.woff2 new file mode 100644 index 00000000..89bd1359 Binary files /dev/null and b/twake/frontend/public/public/font/helvetica/HelveticaNeueCyr-UltraLightItalic.woff2 differ diff --git a/twake/frontend/public/public/font/helvetica/stylesheet.css b/twake/frontend/public/public/font/helvetica/stylesheet.css new file mode 100644 index 00000000..2dad0bac --- /dev/null +++ b/twake/frontend/public/public/font/helvetica/stylesheet.css @@ -0,0 +1,215 @@ +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueBoldCondensed.eot'); + src: local('Helvetica Neue Condensed Bold'), local('HelveticaNeueBoldCondensed'), + url('HelveticaNeueBoldCondensed.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueBoldCondensed.woff2') format('woff2'), + url('HelveticaNeueBoldCondensed.woff') format('woff'), + url('HelveticaNeueBoldCondensed.ttf') format('truetype'); + font-weight: bold; + font-style: normal; +} + +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueBlackCondensed.eot'); + src: local('Helvetica Neue Condensed Black'), local('HelveticaNeueBlackCondensed'), + url('HelveticaNeueBlackCondensed.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueBlackCondensed.woff2') format('woff2'), + url('HelveticaNeueBlackCondensed.woff') format('woff'), + url('HelveticaNeueBlackCondensed.ttf') format('truetype'); + font-weight: 900; + font-style: normal; +} + +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueCyr-Bold.eot'); + src: local('HelveticaNeueCyr-Bold'), + url('HelveticaNeueCyr-Bold.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueCyr-Bold.woff2') format('woff2'), + url('HelveticaNeueCyr-Bold.woff') format('woff'), + url('HelveticaNeueCyr-Bold.ttf') format('truetype'); + font-weight: bold; + font-style: normal; +} + +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueCyr-Light.eot'); + src: local('HelveticaNeueCyr-Light'), + url('HelveticaNeueCyr-Light.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueCyr-Light.woff2') format('woff2'), + url('HelveticaNeueCyr-Light.woff') format('woff'), + url('HelveticaNeueCyr-Light.ttf') format('truetype'); + font-weight: 300; + font-style: normal; +} + +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueCyr-Medium.eot'); + src: local('HelveticaNeueCyr-Medium'), + url('HelveticaNeueCyr-Medium.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueCyr-Medium.woff2') format('woff2'), + url('HelveticaNeueCyr-Medium.woff') format('woff'), + url('HelveticaNeueCyr-Medium.ttf') format('truetype'); + font-weight: 500; + font-style: normal; +} + +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueCyr-MediumItalic.eot'); + src: local('HelveticaNeueCyr-MediumItalic'), + url('HelveticaNeueCyr-MediumItalic.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueCyr-MediumItalic.woff2') format('woff2'), + url('HelveticaNeueCyr-MediumItalic.woff') format('woff'), + url('HelveticaNeueCyr-MediumItalic.ttf') format('truetype'); + font-weight: 500; + font-style: italic; +} + +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueCyr-LightItalic.eot'); + src: local('HelveticaNeueCyr-LightItalic'), + url('HelveticaNeueCyr-LightItalic.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueCyr-LightItalic.woff2') format('woff2'), + url('HelveticaNeueCyr-LightItalic.woff') format('woff'), + url('HelveticaNeueCyr-LightItalic.ttf') format('truetype'); + font-weight: 300; + font-style: italic; +} + +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueCyr-HeavyItalic.eot'); + src: local('HelveticaNeueCyr-HeavyItalic'), + url('HelveticaNeueCyr-HeavyItalic.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueCyr-HeavyItalic.woff2') format('woff2'), + url('HelveticaNeueCyr-HeavyItalic.woff') format('woff'), + url('HelveticaNeueCyr-HeavyItalic.ttf') format('truetype'); + font-weight: 900; + font-style: italic; +} + +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueCyr-Black.eot'); + src: local('HelveticaNeueCyr-Black'), + url('HelveticaNeueCyr-Black.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueCyr-Black.woff2') format('woff2'), + url('HelveticaNeueCyr-Black.woff') format('woff'), + url('HelveticaNeueCyr-Black.ttf') format('truetype'); + font-weight: 900; + font-style: normal; +} + +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueCyr-Heavy.eot'); + src: local('HelveticaNeueCyr-Heavy'), + url('HelveticaNeueCyr-Heavy.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueCyr-Heavy.woff2') format('woff2'), + url('HelveticaNeueCyr-Heavy.woff') format('woff'), + url('HelveticaNeueCyr-Heavy.ttf') format('truetype'); + font-weight: 900; + font-style: normal; +} + +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueCyr-Italic.eot'); + src: local('HelveticaNeueCyr-Italic'), + url('HelveticaNeueCyr-Italic.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueCyr-Italic.woff2') format('woff2'), + url('HelveticaNeueCyr-Italic.woff') format('woff'), + url('HelveticaNeueCyr-Italic.ttf') format('truetype'); + font-weight: 500; + font-style: italic; +} + +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueCyr-Roman.eot'); + src: local('HelveticaNeueCyr-Roman'), + url('HelveticaNeueCyr-Roman.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueCyr-Roman.woff2') format('woff2'), + url('HelveticaNeueCyr-Roman.woff') format('woff'), + url('HelveticaNeueCyr-Roman.ttf') format('truetype'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueCyr-BlackItalic.eot'); + src: local('HelveticaNeueCyr-BlackItalic'), + url('HelveticaNeueCyr-BlackItalic.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueCyr-BlackItalic.woff2') format('woff2'), + url('HelveticaNeueCyr-BlackItalic.woff') format('woff'), + url('HelveticaNeueCyr-BlackItalic.ttf') format('truetype'); + font-weight: 900; + font-style: italic; +} + +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueCyr-UltraLightItalic.eot'); + src: local('HelveticaNeueCyr-UltraLightItalic'), + url('HelveticaNeueCyr-UltraLightItalic.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueCyr-UltraLightItalic.woff2') format('woff2'), + url('HelveticaNeueCyr-UltraLightItalic.woff') format('woff'), + url('HelveticaNeueCyr-UltraLightItalic.ttf') format('truetype'); + font-weight: 200; + font-style: italic; +} + +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueCyr-BoldItalic.eot'); + src: local('HelveticaNeueCyr-BoldItalic'), + url('HelveticaNeueCyr-BoldItalic.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueCyr-BoldItalic.woff2') format('woff2'), + url('HelveticaNeueCyr-BoldItalic.woff') format('woff'), + url('HelveticaNeueCyr-BoldItalic.ttf') format('truetype'); + font-weight: bold; + font-style: italic; +} + +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueCyr-ThinItalic.eot'); + src: local('HelveticaNeueCyr-ThinItalic'), + url('HelveticaNeueCyr-ThinItalic.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueCyr-ThinItalic.woff2') format('woff2'), + url('HelveticaNeueCyr-ThinItalic.woff') format('woff'), + url('HelveticaNeueCyr-ThinItalic.ttf') format('truetype'); + font-weight: 100; + font-style: italic; +} + +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueCyr-UltraLight.eot'); + src: local('HelveticaNeueCyr-UltraLight'), + url('HelveticaNeueCyr-UltraLight.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueCyr-UltraLight.woff2') format('woff2'), + url('HelveticaNeueCyr-UltraLight.woff') format('woff'), + url('HelveticaNeueCyr-UltraLight.ttf') format('truetype'); + font-weight: 200; + font-style: normal; +} + +@font-face { + font-family: 'Helvetica Neue'; + src: url('HelveticaNeueCyr-Thin.eot'); + src: local('HelveticaNeueCyr-Thin'), + url('HelveticaNeueCyr-Thin.eot?#iefix') format('embedded-opentype'), + url('HelveticaNeueCyr-Thin.woff2') format('woff2'), + url('HelveticaNeueCyr-Thin.woff') format('woff'), + url('HelveticaNeueCyr-Thin.ttf') format('truetype'); + font-weight: 100; + font-style: normal; +} diff --git a/twake/frontend/public/public/font/inter/Inter-Black.woff b/twake/frontend/public/public/font/inter/Inter-Black.woff new file mode 100644 index 00000000..a18593a0 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-Black.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-Black.woff2 b/twake/frontend/public/public/font/inter/Inter-Black.woff2 new file mode 100644 index 00000000..68f64c9e Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-Black.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-BlackItalic.woff b/twake/frontend/public/public/font/inter/Inter-BlackItalic.woff new file mode 100644 index 00000000..b6b01943 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-BlackItalic.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-BlackItalic.woff2 b/twake/frontend/public/public/font/inter/Inter-BlackItalic.woff2 new file mode 100644 index 00000000..1c9c7ca8 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-BlackItalic.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-Bold.woff b/twake/frontend/public/public/font/inter/Inter-Bold.woff new file mode 100644 index 00000000..eaf3d4bf Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-Bold.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-Bold.woff2 b/twake/frontend/public/public/font/inter/Inter-Bold.woff2 new file mode 100644 index 00000000..2846f29c Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-Bold.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-BoldItalic.woff b/twake/frontend/public/public/font/inter/Inter-BoldItalic.woff new file mode 100644 index 00000000..32750761 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-BoldItalic.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-BoldItalic.woff2 b/twake/frontend/public/public/font/inter/Inter-BoldItalic.woff2 new file mode 100644 index 00000000..0b1fe8e1 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-BoldItalic.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-ExtraBold.woff b/twake/frontend/public/public/font/inter/Inter-ExtraBold.woff new file mode 100644 index 00000000..c2c17ede Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-ExtraBold.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-ExtraBold.woff2 b/twake/frontend/public/public/font/inter/Inter-ExtraBold.woff2 new file mode 100644 index 00000000..c24c2bdc Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-ExtraBold.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-ExtraBoldItalic.woff b/twake/frontend/public/public/font/inter/Inter-ExtraBoldItalic.woff new file mode 100644 index 00000000..c42f7052 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-ExtraBoldItalic.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-ExtraBoldItalic.woff2 b/twake/frontend/public/public/font/inter/Inter-ExtraBoldItalic.woff2 new file mode 100644 index 00000000..4a81dc79 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-ExtraBoldItalic.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-ExtraLight.woff b/twake/frontend/public/public/font/inter/Inter-ExtraLight.woff new file mode 100644 index 00000000..d0de5f39 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-ExtraLight.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-ExtraLight.woff2 b/twake/frontend/public/public/font/inter/Inter-ExtraLight.woff2 new file mode 100644 index 00000000..f2ea706f Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-ExtraLight.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-ExtraLightItalic.woff b/twake/frontend/public/public/font/inter/Inter-ExtraLightItalic.woff new file mode 100644 index 00000000..81f1a28e Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-ExtraLightItalic.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-ExtraLightItalic.woff2 b/twake/frontend/public/public/font/inter/Inter-ExtraLightItalic.woff2 new file mode 100644 index 00000000..9af717ba Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-ExtraLightItalic.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-Italic.woff b/twake/frontend/public/public/font/inter/Inter-Italic.woff new file mode 100644 index 00000000..a806b382 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-Italic.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-Italic.woff2 b/twake/frontend/public/public/font/inter/Inter-Italic.woff2 new file mode 100644 index 00000000..a619fc54 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-Italic.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-Light.woff b/twake/frontend/public/public/font/inter/Inter-Light.woff new file mode 100644 index 00000000..c496464d Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-Light.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-Light.woff2 b/twake/frontend/public/public/font/inter/Inter-Light.woff2 new file mode 100644 index 00000000..bc4be665 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-Light.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-LightItalic.woff b/twake/frontend/public/public/font/inter/Inter-LightItalic.woff new file mode 100644 index 00000000..f84a9de3 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-LightItalic.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-LightItalic.woff2 b/twake/frontend/public/public/font/inter/Inter-LightItalic.woff2 new file mode 100644 index 00000000..842b2dfc Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-LightItalic.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-Medium.woff b/twake/frontend/public/public/font/inter/Inter-Medium.woff new file mode 100644 index 00000000..d546843f Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-Medium.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-Medium.woff2 b/twake/frontend/public/public/font/inter/Inter-Medium.woff2 new file mode 100644 index 00000000..f92498a2 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-Medium.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-MediumItalic.woff b/twake/frontend/public/public/font/inter/Inter-MediumItalic.woff new file mode 100644 index 00000000..459a6568 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-MediumItalic.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-MediumItalic.woff2 b/twake/frontend/public/public/font/inter/Inter-MediumItalic.woff2 new file mode 100644 index 00000000..0e3019f4 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-MediumItalic.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-Regular.woff b/twake/frontend/public/public/font/inter/Inter-Regular.woff new file mode 100644 index 00000000..62d3a618 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-Regular.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-Regular.woff2 b/twake/frontend/public/public/font/inter/Inter-Regular.woff2 new file mode 100644 index 00000000..6c2b6893 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-Regular.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-SemiBold.woff b/twake/frontend/public/public/font/inter/Inter-SemiBold.woff new file mode 100644 index 00000000..a815f43a Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-SemiBold.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-SemiBold.woff2 b/twake/frontend/public/public/font/inter/Inter-SemiBold.woff2 new file mode 100644 index 00000000..611e90c9 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-SemiBold.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-SemiBoldItalic.woff b/twake/frontend/public/public/font/inter/Inter-SemiBoldItalic.woff new file mode 100644 index 00000000..909e43a9 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-SemiBoldItalic.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-SemiBoldItalic.woff2 b/twake/frontend/public/public/font/inter/Inter-SemiBoldItalic.woff2 new file mode 100644 index 00000000..545685bd Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-SemiBoldItalic.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-Thin.woff b/twake/frontend/public/public/font/inter/Inter-Thin.woff new file mode 100644 index 00000000..62bc58cd Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-Thin.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-Thin.woff2 b/twake/frontend/public/public/font/inter/Inter-Thin.woff2 new file mode 100644 index 00000000..abbc3a5c Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-Thin.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-ThinItalic.woff b/twake/frontend/public/public/font/inter/Inter-ThinItalic.woff new file mode 100644 index 00000000..700a7f06 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-ThinItalic.woff differ diff --git a/twake/frontend/public/public/font/inter/Inter-ThinItalic.woff2 b/twake/frontend/public/public/font/inter/Inter-ThinItalic.woff2 new file mode 100644 index 00000000..ab0b2002 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-ThinItalic.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-italic.var.woff2 b/twake/frontend/public/public/font/inter/Inter-italic.var.woff2 new file mode 100644 index 00000000..b826d5af Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-italic.var.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter-roman.var.woff2 b/twake/frontend/public/public/font/inter/Inter-roman.var.woff2 new file mode 100644 index 00000000..6a256a06 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter-roman.var.woff2 differ diff --git a/twake/frontend/public/public/font/inter/Inter.var.woff2 b/twake/frontend/public/public/font/inter/Inter.var.woff2 new file mode 100644 index 00000000..365eedc5 Binary files /dev/null and b/twake/frontend/public/public/font/inter/Inter.var.woff2 differ diff --git a/twake/frontend/public/public/font/inter/inter.css b/twake/frontend/public/public/font/inter/inter.css new file mode 100644 index 00000000..f4500101 --- /dev/null +++ b/twake/frontend/public/public/font/inter/inter.css @@ -0,0 +1,200 @@ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100; + font-display: swap; + src: url("Inter-Thin.woff2?v=3.19") format("woff2"), + url("Inter-Thin.woff?v=3.19") format("woff"); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 100; + font-display: swap; + src: url("Inter-ThinItalic.woff2?v=3.19") format("woff2"), + url("Inter-ThinItalic.woff?v=3.19") format("woff"); +} + +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 200; + font-display: swap; + src: url("Inter-ExtraLight.woff2?v=3.19") format("woff2"), + url("Inter-ExtraLight.woff?v=3.19") format("woff"); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 200; + font-display: swap; + src: url("Inter-ExtraLightItalic.woff2?v=3.19") format("woff2"), + url("Inter-ExtraLightItalic.woff?v=3.19") format("woff"); +} + +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url("Inter-Light.woff2?v=3.19") format("woff2"), + url("Inter-Light.woff?v=3.19") format("woff"); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 300; + font-display: swap; + src: url("Inter-LightItalic.woff2?v=3.19") format("woff2"), + url("Inter-LightItalic.woff?v=3.19") format("woff"); +} + +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("Inter-Regular.woff2?v=3.19") format("woff2"), + url("Inter-Regular.woff?v=3.19") format("woff"); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url("Inter-Italic.woff2?v=3.19") format("woff2"), + url("Inter-Italic.woff?v=3.19") format("woff"); +} + +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url("Inter-Medium.woff2?v=3.19") format("woff2"), + url("Inter-Medium.woff?v=3.19") format("woff"); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url("Inter-MediumItalic.woff2?v=3.19") format("woff2"), + url("Inter-MediumItalic.woff?v=3.19") format("woff"); +} + +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url("Inter-SemiBold.woff2?v=3.19") format("woff2"), + url("Inter-SemiBold.woff?v=3.19") format("woff"); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 600; + font-display: swap; + src: url("Inter-SemiBoldItalic.woff2?v=3.19") format("woff2"), + url("Inter-SemiBoldItalic.woff?v=3.19") format("woff"); +} + +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url("Inter-Bold.woff2?v=3.19") format("woff2"), + url("Inter-Bold.woff?v=3.19") format("woff"); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 700; + font-display: swap; + src: url("Inter-BoldItalic.woff2?v=3.19") format("woff2"), + url("Inter-BoldItalic.woff?v=3.19") format("woff"); +} + +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 800; + font-display: swap; + src: url("Inter-ExtraBold.woff2?v=3.19") format("woff2"), + url("Inter-ExtraBold.woff?v=3.19") format("woff"); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 800; + font-display: swap; + src: url("Inter-ExtraBoldItalic.woff2?v=3.19") format("woff2"), + url("Inter-ExtraBoldItalic.woff?v=3.19") format("woff"); +} + +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 900; + font-display: swap; + src: url("Inter-Black.woff2?v=3.19") format("woff2"), + url("Inter-Black.woff?v=3.19") format("woff"); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 900; + font-display: swap; + src: url("Inter-BlackItalic.woff2?v=3.19") format("woff2"), + url("Inter-BlackItalic.woff?v=3.19") format("woff"); +} + +/* ------------------------------------------------------- +Variable font. +Usage: + + html { font-family: 'Inter', sans-serif; } + @supports (font-variation-settings: normal) { + html { font-family: 'Inter var', sans-serif; } + } +*/ +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: normal; + font-named-instance: 'Regular'; + src: url("Inter-roman.var.woff2?v=3.19") format("woff2"); +} +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: italic; + font-named-instance: 'Italic'; + src: url("Inter-italic.var.woff2?v=3.19") format("woff2"); +} + + +/* -------------------------------------------------------------------------- +[EXPERIMENTAL] Multi-axis, single variable font. + +Slant axis is not yet widely supported (as of February 2019) and thus this +multi-axis single variable font is opt-in rather than the default. + +When using this, you will probably need to set font-variation-settings +explicitly, e.g. + + * { font-variation-settings: "slnt" 0deg } + .italic { font-variation-settings: "slnt" 10deg } + +*/ +@font-face { + font-family: 'Inter var experimental'; + font-weight: 100 900; + font-display: swap; + font-style: oblique 0deg 10deg; + src: url("Inter.var.woff2?v=3.19") format("woff2"); +} diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Black.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Black.eot new file mode 100644 index 00000000..60ae189f Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Black.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Black.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Black.ttf new file mode 100644 index 00000000..ec41d1f0 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Black.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Black.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Black.woff new file mode 100644 index 00000000..b9394bc9 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Black.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Black.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Black.woff2 new file mode 100644 index 00000000..e7110955 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Black.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-BlackItalic.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-BlackItalic.eot new file mode 100644 index 00000000..68952dd8 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-BlackItalic.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-BlackItalic.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-BlackItalic.ttf new file mode 100644 index 00000000..3deb3f09 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-BlackItalic.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-BlackItalic.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-BlackItalic.woff new file mode 100644 index 00000000..fee9046f Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-BlackItalic.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-BlackItalic.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-BlackItalic.woff2 new file mode 100644 index 00000000..2a884a43 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-BlackItalic.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Bold.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Bold.eot new file mode 100644 index 00000000..02f65973 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Bold.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Bold.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Bold.ttf new file mode 100644 index 00000000..1c0313ef Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Bold.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Bold.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Bold.woff new file mode 100644 index 00000000..cbf38697 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Bold.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Bold.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Bold.woff2 new file mode 100644 index 00000000..27fdde37 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Bold.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-BoldItalic.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-BoldItalic.eot new file mode 100644 index 00000000..1cf32771 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-BoldItalic.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-BoldItalic.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-BoldItalic.ttf new file mode 100644 index 00000000..4b48a835 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-BoldItalic.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-BoldItalic.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-BoldItalic.woff new file mode 100644 index 00000000..5e19e0df Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-BoldItalic.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-BoldItalic.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-BoldItalic.woff2 new file mode 100644 index 00000000..8e001ac5 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-BoldItalic.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlack.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlack.eot new file mode 100644 index 00000000..93789e4e Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlack.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlack.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlack.ttf new file mode 100644 index 00000000..976ff0b3 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlack.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlack.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlack.woff new file mode 100644 index 00000000..9e35aaf7 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlack.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlack.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlack.woff2 new file mode 100644 index 00000000..1bdb015c Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlack.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlackItalic.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlackItalic.eot new file mode 100644 index 00000000..46296157 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlackItalic.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlackItalic.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlackItalic.ttf new file mode 100644 index 00000000..e79cddcf Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlackItalic.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlackItalic.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlackItalic.woff new file mode 100644 index 00000000..c1d3992b Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlackItalic.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlackItalic.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlackItalic.woff2 new file mode 100644 index 00000000..053051b3 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBlackItalic.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBold.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBold.eot new file mode 100644 index 00000000..5f5c876d Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBold.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBold.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBold.ttf new file mode 100644 index 00000000..cfa757e9 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBold.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBold.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBold.woff new file mode 100644 index 00000000..bd3d7518 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBold.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBold.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBold.woff2 new file mode 100644 index 00000000..e761c453 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBold.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBoldItalic.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBoldItalic.eot new file mode 100644 index 00000000..1e45cc4c Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBoldItalic.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBoldItalic.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBoldItalic.ttf new file mode 100644 index 00000000..8517b4be Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBoldItalic.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBoldItalic.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBoldItalic.woff new file mode 100644 index 00000000..64677f98 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBoldItalic.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBoldItalic.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBoldItalic.woff2 new file mode 100644 index 00000000..a679f17a Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraBoldItalic.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLight.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLight.eot new file mode 100644 index 00000000..8e1016f0 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLight.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLight.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLight.ttf new file mode 100644 index 00000000..2ba31662 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLight.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLight.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLight.woff new file mode 100644 index 00000000..6f9c59d7 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLight.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLight.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLight.woff2 new file mode 100644 index 00000000..21353f2a Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLight.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLightItalic.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLightItalic.eot new file mode 100644 index 00000000..ac95471e Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLightItalic.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLightItalic.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLightItalic.ttf new file mode 100644 index 00000000..1446c33f Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLightItalic.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLightItalic.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLightItalic.woff new file mode 100644 index 00000000..d6da6d41 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLightItalic.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLightItalic.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLightItalic.woff2 new file mode 100644 index 00000000..ac981cc2 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ExtraLightItalic.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Italic.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Italic.eot new file mode 100644 index 00000000..4d30d4bb Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Italic.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Italic.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Italic.ttf new file mode 100644 index 00000000..0c89334d Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Italic.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Italic.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Italic.woff new file mode 100644 index 00000000..064d0880 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Italic.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Italic.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Italic.woff2 new file mode 100644 index 00000000..6cc6ee9c Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Italic.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Light.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Light.eot new file mode 100644 index 00000000..a4652042 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Light.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Light.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Light.ttf new file mode 100644 index 00000000..ef8aa697 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Light.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Light.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Light.woff new file mode 100644 index 00000000..b4ee151b Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Light.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Light.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Light.woff2 new file mode 100644 index 00000000..e50fca85 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Light.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-LightItalic.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-LightItalic.eot new file mode 100644 index 00000000..3a750f6f Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-LightItalic.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-LightItalic.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-LightItalic.ttf new file mode 100644 index 00000000..91898add Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-LightItalic.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-LightItalic.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-LightItalic.woff new file mode 100644 index 00000000..65544618 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-LightItalic.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-LightItalic.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-LightItalic.woff2 new file mode 100644 index 00000000..b13cd6d9 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-LightItalic.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Medium.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Medium.eot new file mode 100644 index 00000000..50622e62 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Medium.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Medium.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Medium.ttf new file mode 100644 index 00000000..04159c49 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Medium.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Medium.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Medium.woff new file mode 100644 index 00000000..a472244c Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Medium.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Medium.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Medium.woff2 new file mode 100644 index 00000000..23a1570e Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Medium.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-MediumItalic.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-MediumItalic.eot new file mode 100644 index 00000000..e0e0f512 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-MediumItalic.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-MediumItalic.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-MediumItalic.ttf new file mode 100644 index 00000000..a1015fb0 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-MediumItalic.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-MediumItalic.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-MediumItalic.woff new file mode 100644 index 00000000..deb1b7d6 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-MediumItalic.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-MediumItalic.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-MediumItalic.woff2 new file mode 100644 index 00000000..903976ce Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-MediumItalic.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Regular.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Regular.eot new file mode 100644 index 00000000..771257cf Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Regular.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Regular.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Regular.ttf new file mode 100644 index 00000000..9163f52b Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Regular.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Regular.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Regular.woff new file mode 100644 index 00000000..5e1c2a1a Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Regular.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Regular.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Regular.woff2 new file mode 100644 index 00000000..e181f465 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Regular.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Thin.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Thin.eot new file mode 100644 index 00000000..f0506930 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Thin.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Thin.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Thin.ttf new file mode 100644 index 00000000..434e4e91 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Thin.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Thin.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Thin.woff new file mode 100644 index 00000000..726323d8 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Thin.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-Thin.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Thin.woff2 new file mode 100644 index 00000000..1a259b00 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-Thin.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ThinItalic.eot b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ThinItalic.eot new file mode 100644 index 00000000..559b471e Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ThinItalic.eot differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ThinItalic.ttf b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ThinItalic.ttf new file mode 100644 index 00000000..77f70669 Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ThinItalic.ttf differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ThinItalic.woff b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ThinItalic.woff new file mode 100644 index 00000000..a08388fb Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ThinItalic.woff differ diff --git a/twake/frontend/public/public/font/tt_norms/TTNormsPro-ThinItalic.woff2 b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ThinItalic.woff2 new file mode 100644 index 00000000..c98be2dc Binary files /dev/null and b/twake/frontend/public/public/font/tt_norms/TTNormsPro-ThinItalic.woff2 differ diff --git a/twake/frontend/public/public/font/tt_norms/stylesheet.css b/twake/frontend/public/public/font/tt_norms/stylesheet.css new file mode 100644 index 00000000..1979b0e5 --- /dev/null +++ b/twake/frontend/public/public/font/tt_norms/stylesheet.css @@ -0,0 +1,208 @@ +@font-face { + font-family: 'TT Norms Pro'; + src: url('TTNormsPro-Bold.eot'); + src: local('TT Norms Pro Bold'), local('TTNormsPro-Bold'), + url('TTNormsPro-Bold.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-Bold.woff2') format('woff2'), url('TTNormsPro-Bold.woff') format('woff'), + url('TTNormsPro-Bold.ttf') format('truetype'); + font-weight: bold; + font-style: normal; +} + +@font-face { + font-family: 'TT Norms Pro'; + src: url('TTNormsPro-ExtraBoldItalic.eot'); + src: local('TT Norms Pro ExtraBold Italic'), local('TTNormsPro-ExtraBoldItalic'), + url('TTNormsPro-ExtraBoldItalic.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-ExtraBoldItalic.woff2') format('woff2'), + url('TTNormsPro-ExtraBoldItalic.woff') format('woff'), + url('TTNormsPro-ExtraBoldItalic.ttf') format('truetype'); + font-weight: 800; + font-style: italic; +} + +@font-face { + font-family: 'TT Norms Pro'; + src: url('TTNormsPro-ExtraLightItalic.eot'); + src: local('TT Norms Pro ExtraLight Italic'), local('TTNormsPro-ExtraLightItalic'), + url('TTNormsPro-ExtraLightItalic.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-ExtraLightItalic.woff2') format('woff2'), + url('TTNormsPro-ExtraLightItalic.woff') format('woff'), + url('TTNormsPro-ExtraLightItalic.ttf') format('truetype'); + font-weight: 200; + font-style: italic; +} + +@font-face { + font-family: 'TT Norms Pro'; + src: url('TTNormsPro-Thin.eot'); + src: local('TT Norms Pro Thin'), local('TTNormsPro-Thin'), + url('TTNormsPro-Thin.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-Thin.woff2') format('woff2'), url('TTNormsPro-Thin.woff') format('woff'), + url('TTNormsPro-Thin.ttf') format('truetype'); + font-weight: 100; + font-style: normal; +} + +@font-face { + font-family: 'TT Norms Pro'; + src: url('TTNormsPro-ExtraBold.eot'); + src: local('TT Norms Pro ExtraBold'), local('TTNormsPro-ExtraBold'), + url('TTNormsPro-ExtraBold.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-ExtraBold.woff2') format('woff2'), + url('TTNormsPro-ExtraBold.woff') format('woff'), + url('TTNormsPro-ExtraBold.ttf') format('truetype'); + font-weight: 800; + font-style: normal; +} + +@font-face { + font-family: 'TT Norms Pro'; + src: url('TTNormsPro-Regular.eot'); + src: local('TT Norms Pro Regular'), local('TTNormsPro-Regular'), + url('TTNormsPro-Regular.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-Regular.woff2') format('woff2'), url('TTNormsPro-Regular.woff') format('woff'), + url('TTNormsPro-Regular.ttf') format('truetype'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'TT Norms Pro'; + src: url('TTNormsPro-ThinItalic.eot'); + src: local('TT Norms Pro Thin Italic'), local('TTNormsPro-ThinItalic'), + url('TTNormsPro-ThinItalic.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-ThinItalic.woff2') format('woff2'), + url('TTNormsPro-ThinItalic.woff') format('woff'), + url('TTNormsPro-ThinItalic.ttf') format('truetype'); + font-weight: 100; + font-style: italic; +} + +@font-face { + font-family: 'TT Norms Pro'; + src: url('TTNormsPro-Light.eot'); + src: local('TT Norms Pro Light'), local('TTNormsPro-Light'), + url('TTNormsPro-Light.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-Light.woff2') format('woff2'), url('TTNormsPro-Light.woff') format('woff'), + url('TTNormsPro-Light.ttf') format('truetype'); + font-weight: 300; + font-style: normal; +} + +@font-face { + font-family: 'TT Norms Pro'; + src: url('TTNormsPro-MediumItalic.eot'); + src: local('TT Norms Pro Medium Italic'), local('TTNormsPro-MediumItalic'), + url('TTNormsPro-MediumItalic.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-MediumItalic.woff2') format('woff2'), + url('TTNormsPro-MediumItalic.woff') format('woff'), + url('TTNormsPro-MediumItalic.ttf') format('truetype'); + font-weight: 400; + font-style: italic; +} + +@font-face { + font-family: 'TT Norms Pro ExtraBlack'; + src: url('TTNormsPro-ExtraBlackItalic.eot'); + src: local('TT Norms Pro ExtraBlack Italic'), local('TTNormsPro-ExtraBlackItalic'), + url('TTNormsPro-ExtraBlackItalic.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-ExtraBlackItalic.woff2') format('woff2'), + url('TTNormsPro-ExtraBlackItalic.woff') format('woff'), + url('TTNormsPro-ExtraBlackItalic.ttf') format('truetype'); + font-weight: 900; + font-style: italic; +} + +@font-face { + font-family: 'TT Norms Pro'; + src: url('TTNormsPro-ExtraLight.eot'); + src: local('TT Norms Pro ExtraLight'), local('TTNormsPro-ExtraLight'), + url('TTNormsPro-ExtraLight.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-ExtraLight.woff2') format('woff2'), + url('TTNormsPro-ExtraLight.woff') format('woff'), + url('TTNormsPro-ExtraLight.ttf') format('truetype'); + font-weight: 200; + font-style: normal; +} + +@font-face { + font-family: 'TT Norms Pro'; + src: url('TTNormsPro-LightItalic.eot'); + src: local('TT Norms Pro Light Italic'), local('TTNormsPro-LightItalic'), + url('TTNormsPro-LightItalic.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-LightItalic.woff2') format('woff2'), + url('TTNormsPro-LightItalic.woff') format('woff'), + url('TTNormsPro-LightItalic.ttf') format('truetype'); + font-weight: 300; + font-style: italic; +} + +@font-face { + font-family: 'TT Norms Pro'; + src: url('TTNormsPro-Medium.eot'); + src: local('TT Norms Pro Medium'), local('TTNormsPro-Medium'), + url('TTNormsPro-Medium.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-Medium.woff2') format('woff2'), url('TTNormsPro-Medium.woff') format('woff'), + url('TTNormsPro-Medium.ttf') format('truetype'); + font-weight: 400; + font-style: normal; +} + +@font-face { + font-family: 'TT Norms Pro ExtraBlack'; + src: url('TTNormsPro-ExtraBlack.eot'); + src: local('TT Norms Pro ExtraBlack'), local('TTNormsPro-ExtraBlack'), + url('TTNormsPro-ExtraBlack.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-ExtraBlack.woff2') format('woff2'), + url('TTNormsPro-ExtraBlack.woff') format('woff'), + url('TTNormsPro-ExtraBlack.ttf') format('truetype'); + font-weight: 900; + font-style: normal; +} + +@font-face { + font-family: 'TT Norms Pro'; + src: url('TTNormsPro-BoldItalic.eot'); + src: local('TT Norms Pro Bold Italic'), local('TTNormsPro-BoldItalic'), + url('TTNormsPro-BoldItalic.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-BoldItalic.woff2') format('woff2'), + url('TTNormsPro-BoldItalic.woff') format('woff'), + url('TTNormsPro-BoldItalic.ttf') format('truetype'); + font-weight: bold; + font-style: italic; +} + +@font-face { + font-family: 'TT Norms Pro'; + src: url('TTNormsPro-BlackItalic.eot'); + src: local('TT Norms Pro Black Italic'), local('TTNormsPro-BlackItalic'), + url('TTNormsPro-BlackItalic.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-BlackItalic.woff2') format('woff2'), + url('TTNormsPro-BlackItalic.woff') format('woff'), + url('TTNormsPro-BlackItalic.ttf') format('truetype'); + font-weight: 900; + font-style: italic; +} + +@font-face { + font-family: 'TT Norms Pro'; + src: url('TTNormsPro-Black.eot'); + src: local('TT Norms Pro Black'), local('TTNormsPro-Black'), + url('TTNormsPro-Black.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-Black.woff2') format('woff2'), url('TTNormsPro-Black.woff') format('woff'), + url('TTNormsPro-Black.ttf') format('truetype'); + font-weight: 900; + font-style: normal; +} + +@font-face { + font-family: 'TT Norms Pro'; + src: url('TTNormsPro-Italic.eot'); + src: local('TT Norms Pro Italic'), local('TTNormsPro-Italic'), + url('TTNormsPro-Italic.eot?#iefix') format('embedded-opentype'), + url('TTNormsPro-Italic.woff2') format('woff2'), url('TTNormsPro-Italic.woff') format('woff'), + url('TTNormsPro-Italic.ttf') format('truetype'); + font-weight: normal; + font-style: italic; +} diff --git a/twake/frontend/public/public/identicon/0.png b/twake/frontend/public/public/identicon/0.png new file mode 100644 index 00000000..c460151a Binary files /dev/null and b/twake/frontend/public/public/identicon/0.png differ diff --git a/twake/frontend/public/public/identicon/1.png b/twake/frontend/public/public/identicon/1.png new file mode 100644 index 00000000..8ada9829 Binary files /dev/null and b/twake/frontend/public/public/identicon/1.png differ diff --git a/twake/frontend/public/public/identicon/10.png b/twake/frontend/public/public/identicon/10.png new file mode 100644 index 00000000..75340bff Binary files /dev/null and b/twake/frontend/public/public/identicon/10.png differ diff --git a/twake/frontend/public/public/identicon/100.png b/twake/frontend/public/public/identicon/100.png new file mode 100644 index 00000000..9c885e61 Binary files /dev/null and b/twake/frontend/public/public/identicon/100.png differ diff --git a/twake/frontend/public/public/identicon/11.png b/twake/frontend/public/public/identicon/11.png new file mode 100644 index 00000000..a73160dc Binary files /dev/null and b/twake/frontend/public/public/identicon/11.png differ diff --git a/twake/frontend/public/public/identicon/12.png b/twake/frontend/public/public/identicon/12.png new file mode 100644 index 00000000..26c1154d Binary files /dev/null and b/twake/frontend/public/public/identicon/12.png differ diff --git a/twake/frontend/public/public/identicon/13.png b/twake/frontend/public/public/identicon/13.png new file mode 100644 index 00000000..3f22358b Binary files /dev/null and b/twake/frontend/public/public/identicon/13.png differ diff --git a/twake/frontend/public/public/identicon/14.png b/twake/frontend/public/public/identicon/14.png new file mode 100644 index 00000000..fe9ce9f0 Binary files /dev/null and b/twake/frontend/public/public/identicon/14.png differ diff --git a/twake/frontend/public/public/identicon/15.png b/twake/frontend/public/public/identicon/15.png new file mode 100644 index 00000000..116af24e Binary files /dev/null and b/twake/frontend/public/public/identicon/15.png differ diff --git a/twake/frontend/public/public/identicon/16.png b/twake/frontend/public/public/identicon/16.png new file mode 100644 index 00000000..db2ed918 Binary files /dev/null and b/twake/frontend/public/public/identicon/16.png differ diff --git a/twake/frontend/public/public/identicon/17.png b/twake/frontend/public/public/identicon/17.png new file mode 100644 index 00000000..c6d5b0f8 Binary files /dev/null and b/twake/frontend/public/public/identicon/17.png differ diff --git a/twake/frontend/public/public/identicon/18.png b/twake/frontend/public/public/identicon/18.png new file mode 100644 index 00000000..c938d5d9 Binary files /dev/null and b/twake/frontend/public/public/identicon/18.png differ diff --git a/twake/frontend/public/public/identicon/19.png b/twake/frontend/public/public/identicon/19.png new file mode 100644 index 00000000..d8fb2c8c Binary files /dev/null and b/twake/frontend/public/public/identicon/19.png differ diff --git a/twake/frontend/public/public/identicon/2.png b/twake/frontend/public/public/identicon/2.png new file mode 100644 index 00000000..974c96ca Binary files /dev/null and b/twake/frontend/public/public/identicon/2.png differ diff --git a/twake/frontend/public/public/identicon/20.png b/twake/frontend/public/public/identicon/20.png new file mode 100644 index 00000000..6d2c5e59 Binary files /dev/null and b/twake/frontend/public/public/identicon/20.png differ diff --git a/twake/frontend/public/public/identicon/21.png b/twake/frontend/public/public/identicon/21.png new file mode 100644 index 00000000..db381467 Binary files /dev/null and b/twake/frontend/public/public/identicon/21.png differ diff --git a/twake/frontend/public/public/identicon/22.png b/twake/frontend/public/public/identicon/22.png new file mode 100644 index 00000000..35493464 Binary files /dev/null and b/twake/frontend/public/public/identicon/22.png differ diff --git a/twake/frontend/public/public/identicon/23.png b/twake/frontend/public/public/identicon/23.png new file mode 100644 index 00000000..f38f7677 Binary files /dev/null and b/twake/frontend/public/public/identicon/23.png differ diff --git a/twake/frontend/public/public/identicon/24.png b/twake/frontend/public/public/identicon/24.png new file mode 100644 index 00000000..327fab7d Binary files /dev/null and b/twake/frontend/public/public/identicon/24.png differ diff --git a/twake/frontend/public/public/identicon/25.png b/twake/frontend/public/public/identicon/25.png new file mode 100644 index 00000000..9578dab5 Binary files /dev/null and b/twake/frontend/public/public/identicon/25.png differ diff --git a/twake/frontend/public/public/identicon/26.png b/twake/frontend/public/public/identicon/26.png new file mode 100644 index 00000000..f5a562a8 Binary files /dev/null and b/twake/frontend/public/public/identicon/26.png differ diff --git a/twake/frontend/public/public/identicon/27.png b/twake/frontend/public/public/identicon/27.png new file mode 100644 index 00000000..75aa2401 Binary files /dev/null and b/twake/frontend/public/public/identicon/27.png differ diff --git a/twake/frontend/public/public/identicon/28.png b/twake/frontend/public/public/identicon/28.png new file mode 100644 index 00000000..36774a8f Binary files /dev/null and b/twake/frontend/public/public/identicon/28.png differ diff --git a/twake/frontend/public/public/identicon/29.png b/twake/frontend/public/public/identicon/29.png new file mode 100644 index 00000000..a75f9253 Binary files /dev/null and b/twake/frontend/public/public/identicon/29.png differ diff --git a/twake/frontend/public/public/identicon/3.png b/twake/frontend/public/public/identicon/3.png new file mode 100644 index 00000000..4502b858 Binary files /dev/null and b/twake/frontend/public/public/identicon/3.png differ diff --git a/twake/frontend/public/public/identicon/30.png b/twake/frontend/public/public/identicon/30.png new file mode 100644 index 00000000..755fe088 Binary files /dev/null and b/twake/frontend/public/public/identicon/30.png differ diff --git a/twake/frontend/public/public/identicon/31.png b/twake/frontend/public/public/identicon/31.png new file mode 100644 index 00000000..26f64ca0 Binary files /dev/null and b/twake/frontend/public/public/identicon/31.png differ diff --git a/twake/frontend/public/public/identicon/32.png b/twake/frontend/public/public/identicon/32.png new file mode 100644 index 00000000..b749c6ef Binary files /dev/null and b/twake/frontend/public/public/identicon/32.png differ diff --git a/twake/frontend/public/public/identicon/33.png b/twake/frontend/public/public/identicon/33.png new file mode 100644 index 00000000..df770111 Binary files /dev/null and b/twake/frontend/public/public/identicon/33.png differ diff --git a/twake/frontend/public/public/identicon/34.png b/twake/frontend/public/public/identicon/34.png new file mode 100644 index 00000000..1df5b92c Binary files /dev/null and b/twake/frontend/public/public/identicon/34.png differ diff --git a/twake/frontend/public/public/identicon/35.png b/twake/frontend/public/public/identicon/35.png new file mode 100644 index 00000000..523c657f Binary files /dev/null and b/twake/frontend/public/public/identicon/35.png differ diff --git a/twake/frontend/public/public/identicon/36.png b/twake/frontend/public/public/identicon/36.png new file mode 100644 index 00000000..8082b8db Binary files /dev/null and b/twake/frontend/public/public/identicon/36.png differ diff --git a/twake/frontend/public/public/identicon/37.png b/twake/frontend/public/public/identicon/37.png new file mode 100644 index 00000000..b72f4766 Binary files /dev/null and b/twake/frontend/public/public/identicon/37.png differ diff --git a/twake/frontend/public/public/identicon/38.png b/twake/frontend/public/public/identicon/38.png new file mode 100644 index 00000000..777d41a9 Binary files /dev/null and b/twake/frontend/public/public/identicon/38.png differ diff --git a/twake/frontend/public/public/identicon/39.png b/twake/frontend/public/public/identicon/39.png new file mode 100644 index 00000000..56ecccba Binary files /dev/null and b/twake/frontend/public/public/identicon/39.png differ diff --git a/twake/frontend/public/public/identicon/4.png b/twake/frontend/public/public/identicon/4.png new file mode 100644 index 00000000..c460151a Binary files /dev/null and b/twake/frontend/public/public/identicon/4.png differ diff --git a/twake/frontend/public/public/identicon/40.png b/twake/frontend/public/public/identicon/40.png new file mode 100644 index 00000000..4a65e984 Binary files /dev/null and b/twake/frontend/public/public/identicon/40.png differ diff --git a/twake/frontend/public/public/identicon/41.png b/twake/frontend/public/public/identicon/41.png new file mode 100644 index 00000000..99ef2dc6 Binary files /dev/null and b/twake/frontend/public/public/identicon/41.png differ diff --git a/twake/frontend/public/public/identicon/42.png b/twake/frontend/public/public/identicon/42.png new file mode 100644 index 00000000..c9be6fb0 Binary files /dev/null and b/twake/frontend/public/public/identicon/42.png differ diff --git a/twake/frontend/public/public/identicon/43.png b/twake/frontend/public/public/identicon/43.png new file mode 100644 index 00000000..0c76009f Binary files /dev/null and b/twake/frontend/public/public/identicon/43.png differ diff --git a/twake/frontend/public/public/identicon/44.png b/twake/frontend/public/public/identicon/44.png new file mode 100644 index 00000000..b7a175c4 Binary files /dev/null and b/twake/frontend/public/public/identicon/44.png differ diff --git a/twake/frontend/public/public/identicon/45.png b/twake/frontend/public/public/identicon/45.png new file mode 100644 index 00000000..e8ad7d83 Binary files /dev/null and b/twake/frontend/public/public/identicon/45.png differ diff --git a/twake/frontend/public/public/identicon/46.png b/twake/frontend/public/public/identicon/46.png new file mode 100644 index 00000000..b5be9a1d Binary files /dev/null and b/twake/frontend/public/public/identicon/46.png differ diff --git a/twake/frontend/public/public/identicon/47.png b/twake/frontend/public/public/identicon/47.png new file mode 100644 index 00000000..5a1eca82 Binary files /dev/null and b/twake/frontend/public/public/identicon/47.png differ diff --git a/twake/frontend/public/public/identicon/48.png b/twake/frontend/public/public/identicon/48.png new file mode 100644 index 00000000..0037550a Binary files /dev/null and b/twake/frontend/public/public/identicon/48.png differ diff --git a/twake/frontend/public/public/identicon/49.png b/twake/frontend/public/public/identicon/49.png new file mode 100644 index 00000000..f1e5fe44 Binary files /dev/null and b/twake/frontend/public/public/identicon/49.png differ diff --git a/twake/frontend/public/public/identicon/5.png b/twake/frontend/public/public/identicon/5.png new file mode 100644 index 00000000..582ea53c Binary files /dev/null and b/twake/frontend/public/public/identicon/5.png differ diff --git a/twake/frontend/public/public/identicon/50.png b/twake/frontend/public/public/identicon/50.png new file mode 100644 index 00000000..efcdad3e Binary files /dev/null and b/twake/frontend/public/public/identicon/50.png differ diff --git a/twake/frontend/public/public/identicon/51.png b/twake/frontend/public/public/identicon/51.png new file mode 100644 index 00000000..72d713b9 Binary files /dev/null and b/twake/frontend/public/public/identicon/51.png differ diff --git a/twake/frontend/public/public/identicon/52.png b/twake/frontend/public/public/identicon/52.png new file mode 100644 index 00000000..c0d4664b Binary files /dev/null and b/twake/frontend/public/public/identicon/52.png differ diff --git a/twake/frontend/public/public/identicon/53.png b/twake/frontend/public/public/identicon/53.png new file mode 100644 index 00000000..0792b38e Binary files /dev/null and b/twake/frontend/public/public/identicon/53.png differ diff --git a/twake/frontend/public/public/identicon/54.png b/twake/frontend/public/public/identicon/54.png new file mode 100644 index 00000000..3db757ff Binary files /dev/null and b/twake/frontend/public/public/identicon/54.png differ diff --git a/twake/frontend/public/public/identicon/55.png b/twake/frontend/public/public/identicon/55.png new file mode 100644 index 00000000..3fa0ab2a Binary files /dev/null and b/twake/frontend/public/public/identicon/55.png differ diff --git a/twake/frontend/public/public/identicon/56.png b/twake/frontend/public/public/identicon/56.png new file mode 100644 index 00000000..d1f5cbcb Binary files /dev/null and b/twake/frontend/public/public/identicon/56.png differ diff --git a/twake/frontend/public/public/identicon/57.png b/twake/frontend/public/public/identicon/57.png new file mode 100644 index 00000000..f1db56f3 Binary files /dev/null and b/twake/frontend/public/public/identicon/57.png differ diff --git a/twake/frontend/public/public/identicon/58.png b/twake/frontend/public/public/identicon/58.png new file mode 100644 index 00000000..c646e976 Binary files /dev/null and b/twake/frontend/public/public/identicon/58.png differ diff --git a/twake/frontend/public/public/identicon/59.png b/twake/frontend/public/public/identicon/59.png new file mode 100644 index 00000000..b85e3c28 Binary files /dev/null and b/twake/frontend/public/public/identicon/59.png differ diff --git a/twake/frontend/public/public/identicon/6.png b/twake/frontend/public/public/identicon/6.png new file mode 100644 index 00000000..bcabb747 Binary files /dev/null and b/twake/frontend/public/public/identicon/6.png differ diff --git a/twake/frontend/public/public/identicon/60.png b/twake/frontend/public/public/identicon/60.png new file mode 100644 index 00000000..b916a9a9 Binary files /dev/null and b/twake/frontend/public/public/identicon/60.png differ diff --git a/twake/frontend/public/public/identicon/61.png b/twake/frontend/public/public/identicon/61.png new file mode 100644 index 00000000..1346fb5d Binary files /dev/null and b/twake/frontend/public/public/identicon/61.png differ diff --git a/twake/frontend/public/public/identicon/62.png b/twake/frontend/public/public/identicon/62.png new file mode 100644 index 00000000..0767254c Binary files /dev/null and b/twake/frontend/public/public/identicon/62.png differ diff --git a/twake/frontend/public/public/identicon/63.png b/twake/frontend/public/public/identicon/63.png new file mode 100644 index 00000000..8e89e916 Binary files /dev/null and b/twake/frontend/public/public/identicon/63.png differ diff --git a/twake/frontend/public/public/identicon/64.png b/twake/frontend/public/public/identicon/64.png new file mode 100644 index 00000000..3c968efb Binary files /dev/null and b/twake/frontend/public/public/identicon/64.png differ diff --git a/twake/frontend/public/public/identicon/65.png b/twake/frontend/public/public/identicon/65.png new file mode 100644 index 00000000..c3957bb9 Binary files /dev/null and b/twake/frontend/public/public/identicon/65.png differ diff --git a/twake/frontend/public/public/identicon/66.png b/twake/frontend/public/public/identicon/66.png new file mode 100644 index 00000000..b4eb0bfb Binary files /dev/null and b/twake/frontend/public/public/identicon/66.png differ diff --git a/twake/frontend/public/public/identicon/67.png b/twake/frontend/public/public/identicon/67.png new file mode 100644 index 00000000..cb682b24 Binary files /dev/null and b/twake/frontend/public/public/identicon/67.png differ diff --git a/twake/frontend/public/public/identicon/68.png b/twake/frontend/public/public/identicon/68.png new file mode 100644 index 00000000..9acb571f Binary files /dev/null and b/twake/frontend/public/public/identicon/68.png differ diff --git a/twake/frontend/public/public/identicon/69.png b/twake/frontend/public/public/identicon/69.png new file mode 100644 index 00000000..ba38d1dd Binary files /dev/null and b/twake/frontend/public/public/identicon/69.png differ diff --git a/twake/frontend/public/public/identicon/7.png b/twake/frontend/public/public/identicon/7.png new file mode 100644 index 00000000..6452ff99 Binary files /dev/null and b/twake/frontend/public/public/identicon/7.png differ diff --git a/twake/frontend/public/public/identicon/70.png b/twake/frontend/public/public/identicon/70.png new file mode 100644 index 00000000..817d23a4 Binary files /dev/null and b/twake/frontend/public/public/identicon/70.png differ diff --git a/twake/frontend/public/public/identicon/71.png b/twake/frontend/public/public/identicon/71.png new file mode 100644 index 00000000..7d0d7715 Binary files /dev/null and b/twake/frontend/public/public/identicon/71.png differ diff --git a/twake/frontend/public/public/identicon/72.png b/twake/frontend/public/public/identicon/72.png new file mode 100644 index 00000000..4765a55c Binary files /dev/null and b/twake/frontend/public/public/identicon/72.png differ diff --git a/twake/frontend/public/public/identicon/73.png b/twake/frontend/public/public/identicon/73.png new file mode 100644 index 00000000..52534011 Binary files /dev/null and b/twake/frontend/public/public/identicon/73.png differ diff --git a/twake/frontend/public/public/identicon/74.png b/twake/frontend/public/public/identicon/74.png new file mode 100644 index 00000000..71b71dae Binary files /dev/null and b/twake/frontend/public/public/identicon/74.png differ diff --git a/twake/frontend/public/public/identicon/75.png b/twake/frontend/public/public/identicon/75.png new file mode 100644 index 00000000..71cb9a02 Binary files /dev/null and b/twake/frontend/public/public/identicon/75.png differ diff --git a/twake/frontend/public/public/identicon/76.png b/twake/frontend/public/public/identicon/76.png new file mode 100644 index 00000000..4bf615ce Binary files /dev/null and b/twake/frontend/public/public/identicon/76.png differ diff --git a/twake/frontend/public/public/identicon/77.png b/twake/frontend/public/public/identicon/77.png new file mode 100644 index 00000000..d27d3c2d Binary files /dev/null and b/twake/frontend/public/public/identicon/77.png differ diff --git a/twake/frontend/public/public/identicon/78.png b/twake/frontend/public/public/identicon/78.png new file mode 100644 index 00000000..12012977 Binary files /dev/null and b/twake/frontend/public/public/identicon/78.png differ diff --git a/twake/frontend/public/public/identicon/79.png b/twake/frontend/public/public/identicon/79.png new file mode 100644 index 00000000..d16f2a10 Binary files /dev/null and b/twake/frontend/public/public/identicon/79.png differ diff --git a/twake/frontend/public/public/identicon/8.png b/twake/frontend/public/public/identicon/8.png new file mode 100644 index 00000000..76237485 Binary files /dev/null and b/twake/frontend/public/public/identicon/8.png differ diff --git a/twake/frontend/public/public/identicon/80.png b/twake/frontend/public/public/identicon/80.png new file mode 100644 index 00000000..362830ed Binary files /dev/null and b/twake/frontend/public/public/identicon/80.png differ diff --git a/twake/frontend/public/public/identicon/81.png b/twake/frontend/public/public/identicon/81.png new file mode 100644 index 00000000..fabb9023 Binary files /dev/null and b/twake/frontend/public/public/identicon/81.png differ diff --git a/twake/frontend/public/public/identicon/82.png b/twake/frontend/public/public/identicon/82.png new file mode 100644 index 00000000..0f387567 Binary files /dev/null and b/twake/frontend/public/public/identicon/82.png differ diff --git a/twake/frontend/public/public/identicon/83.png b/twake/frontend/public/public/identicon/83.png new file mode 100644 index 00000000..93f0f11c Binary files /dev/null and b/twake/frontend/public/public/identicon/83.png differ diff --git a/twake/frontend/public/public/identicon/84.png b/twake/frontend/public/public/identicon/84.png new file mode 100644 index 00000000..b29cc05c Binary files /dev/null and b/twake/frontend/public/public/identicon/84.png differ diff --git a/twake/frontend/public/public/identicon/85.png b/twake/frontend/public/public/identicon/85.png new file mode 100644 index 00000000..483b3894 Binary files /dev/null and b/twake/frontend/public/public/identicon/85.png differ diff --git a/twake/frontend/public/public/identicon/86.png b/twake/frontend/public/public/identicon/86.png new file mode 100644 index 00000000..67a3bb38 Binary files /dev/null and b/twake/frontend/public/public/identicon/86.png differ diff --git a/twake/frontend/public/public/identicon/87.png b/twake/frontend/public/public/identicon/87.png new file mode 100644 index 00000000..65c00df1 Binary files /dev/null and b/twake/frontend/public/public/identicon/87.png differ diff --git a/twake/frontend/public/public/identicon/88.png b/twake/frontend/public/public/identicon/88.png new file mode 100644 index 00000000..3d186d9f Binary files /dev/null and b/twake/frontend/public/public/identicon/88.png differ diff --git a/twake/frontend/public/public/identicon/89.png b/twake/frontend/public/public/identicon/89.png new file mode 100644 index 00000000..9f9990be Binary files /dev/null and b/twake/frontend/public/public/identicon/89.png differ diff --git a/twake/frontend/public/public/identicon/9.png b/twake/frontend/public/public/identicon/9.png new file mode 100644 index 00000000..76237485 Binary files /dev/null and b/twake/frontend/public/public/identicon/9.png differ diff --git a/twake/frontend/public/public/identicon/90.png b/twake/frontend/public/public/identicon/90.png new file mode 100644 index 00000000..a478881a Binary files /dev/null and b/twake/frontend/public/public/identicon/90.png differ diff --git a/twake/frontend/public/public/identicon/91.png b/twake/frontend/public/public/identicon/91.png new file mode 100644 index 00000000..20fc8cc0 Binary files /dev/null and b/twake/frontend/public/public/identicon/91.png differ diff --git a/twake/frontend/public/public/identicon/92.png b/twake/frontend/public/public/identicon/92.png new file mode 100644 index 00000000..0d85f306 Binary files /dev/null and b/twake/frontend/public/public/identicon/92.png differ diff --git a/twake/frontend/public/public/identicon/93.png b/twake/frontend/public/public/identicon/93.png new file mode 100644 index 00000000..62543a72 Binary files /dev/null and b/twake/frontend/public/public/identicon/93.png differ diff --git a/twake/frontend/public/public/identicon/94.png b/twake/frontend/public/public/identicon/94.png new file mode 100644 index 00000000..1e0a6082 Binary files /dev/null and b/twake/frontend/public/public/identicon/94.png differ diff --git a/twake/frontend/public/public/identicon/95.png b/twake/frontend/public/public/identicon/95.png new file mode 100644 index 00000000..e6daf999 Binary files /dev/null and b/twake/frontend/public/public/identicon/95.png differ diff --git a/twake/frontend/public/public/identicon/96.png b/twake/frontend/public/public/identicon/96.png new file mode 100644 index 00000000..1024e853 Binary files /dev/null and b/twake/frontend/public/public/identicon/96.png differ diff --git a/twake/frontend/public/public/identicon/97.png b/twake/frontend/public/public/identicon/97.png new file mode 100644 index 00000000..bf8f7743 Binary files /dev/null and b/twake/frontend/public/public/identicon/97.png differ diff --git a/twake/frontend/public/public/identicon/98.png b/twake/frontend/public/public/identicon/98.png new file mode 100644 index 00000000..e4cfbff0 Binary files /dev/null and b/twake/frontend/public/public/identicon/98.png differ diff --git a/twake/frontend/public/public/identicon/99.png b/twake/frontend/public/public/identicon/99.png new file mode 100644 index 00000000..45d22e01 Binary files /dev/null and b/twake/frontend/public/public/identicon/99.png differ diff --git a/twake/frontend/public/public/img/appstore.png b/twake/frontend/public/public/img/appstore.png new file mode 100755 index 00000000..bbe57aec Binary files /dev/null and b/twake/frontend/public/public/img/appstore.png differ diff --git a/twake/frontend/public/public/img/beta.png b/twake/frontend/public/public/img/beta.png new file mode 100644 index 00000000..cd5b209d Binary files /dev/null and b/twake/frontend/public/public/img/beta.png differ diff --git a/twake/frontend/public/public/img/canary.png b/twake/frontend/public/public/img/canary.png new file mode 100644 index 00000000..10737ac2 Binary files /dev/null and b/twake/frontend/public/public/img/canary.png differ diff --git a/twake/frontend/public/public/img/googleplay.png b/twake/frontend/public/public/img/googleplay.png new file mode 100755 index 00000000..2751fd22 Binary files /dev/null and b/twake/frontend/public/public/img/googleplay.png differ diff --git a/twake/frontend/public/public/img/hexagon.png b/twake/frontend/public/public/img/hexagon.png new file mode 100644 index 00000000..354acbb0 Binary files /dev/null and b/twake/frontend/public/public/img/hexagon.png differ diff --git a/twake/frontend/public/public/img/logo/128x128.png b/twake/frontend/public/public/img/logo/128x128.png new file mode 100644 index 00000000..b6bffc97 Binary files /dev/null and b/twake/frontend/public/public/img/logo/128x128.png differ diff --git a/twake/frontend/public/public/img/logo/16x16.png b/twake/frontend/public/public/img/logo/16x16.png new file mode 100644 index 00000000..820b375e Binary files /dev/null and b/twake/frontend/public/public/img/logo/16x16.png differ diff --git a/twake/frontend/public/public/img/logo/256x256.png b/twake/frontend/public/public/img/logo/256x256.png new file mode 100644 index 00000000..caf50a8f Binary files /dev/null and b/twake/frontend/public/public/img/logo/256x256.png differ diff --git a/twake/frontend/public/public/img/logo/32x32.png b/twake/frontend/public/public/img/logo/32x32.png new file mode 100644 index 00000000..e28beb27 Binary files /dev/null and b/twake/frontend/public/public/img/logo/32x32.png differ diff --git a/twake/frontend/public/public/img/logo/64x64.png b/twake/frontend/public/public/img/logo/64x64.png new file mode 100644 index 00000000..6bfdf13b Binary files /dev/null and b/twake/frontend/public/public/img/logo/64x64.png differ diff --git a/twake/frontend/public/public/img/twake-emoji/twake-calendar.png b/twake/frontend/public/public/img/twake-emoji/twake-calendar.png new file mode 100644 index 00000000..429c3157 Binary files /dev/null and b/twake/frontend/public/public/img/twake-emoji/twake-calendar.png differ diff --git a/twake/frontend/public/public/img/twake-emoji/twake-calendar.svg b/twake/frontend/public/public/img/twake-emoji/twake-calendar.svg new file mode 100644 index 00000000..6c7fd870 --- /dev/null +++ b/twake/frontend/public/public/img/twake-emoji/twake-calendar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/twake/frontend/public/public/img/twake-emoji/twake-drive.png b/twake/frontend/public/public/img/twake-emoji/twake-drive.png new file mode 100644 index 00000000..c3a04ebf Binary files /dev/null and b/twake/frontend/public/public/img/twake-emoji/twake-drive.png differ diff --git a/twake/frontend/public/public/img/twake-emoji/twake-drive.svg b/twake/frontend/public/public/img/twake-emoji/twake-drive.svg new file mode 100644 index 00000000..134458b9 --- /dev/null +++ b/twake/frontend/public/public/img/twake-emoji/twake-drive.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/twake/frontend/public/public/img/twake-emoji/twake-task.svg b/twake/frontend/public/public/img/twake-emoji/twake-task.svg new file mode 100644 index 00000000..72ab7a80 --- /dev/null +++ b/twake/frontend/public/public/img/twake-emoji/twake-task.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/twake/frontend/public/public/img/twake-emoji/twake-tasks.png b/twake/frontend/public/public/img/twake-emoji/twake-tasks.png new file mode 100644 index 00000000..d7f321ec Binary files /dev/null and b/twake/frontend/public/public/img/twake-emoji/twake-tasks.png differ diff --git a/twake/frontend/public/public/sounds/belligerent.wav b/twake/frontend/public/public/sounds/belligerent.wav new file mode 100644 index 00000000..5790c2a4 Binary files /dev/null and b/twake/frontend/public/public/sounds/belligerent.wav differ diff --git a/twake/frontend/public/public/sounds/boot.wav b/twake/frontend/public/public/sounds/boot.wav new file mode 100755 index 00000000..1a6f4f53 Binary files /dev/null and b/twake/frontend/public/public/sounds/boot.wav differ diff --git a/twake/frontend/public/public/sounds/chord.wav b/twake/frontend/public/public/sounds/chord.wav new file mode 100644 index 00000000..92097843 Binary files /dev/null and b/twake/frontend/public/public/sounds/chord.wav differ diff --git a/twake/frontend/public/public/sounds/exitcall.wav b/twake/frontend/public/public/sounds/exitcall.wav new file mode 100755 index 00000000..2db5f901 Binary files /dev/null and b/twake/frontend/public/public/sounds/exitcall.wav differ diff --git a/twake/frontend/public/public/sounds/iexitcall.wav b/twake/frontend/public/public/sounds/iexitcall.wav new file mode 100755 index 00000000..b78ce6d9 Binary files /dev/null and b/twake/frontend/public/public/sounds/iexitcall.wav differ diff --git a/twake/frontend/public/public/sounds/joincall.wav b/twake/frontend/public/public/sounds/joincall.wav new file mode 100755 index 00000000..e485e97c Binary files /dev/null and b/twake/frontend/public/public/sounds/joincall.wav differ diff --git a/twake/frontend/public/public/sounds/newmessage.wav b/twake/frontend/public/public/sounds/newmessage.wav new file mode 100755 index 00000000..37b90f37 Binary files /dev/null and b/twake/frontend/public/public/sounds/newmessage.wav differ diff --git a/twake/frontend/public/public/sounds/newnotification.wav b/twake/frontend/public/public/sounds/newnotification.wav new file mode 100644 index 00000000..97e443dd Binary files /dev/null and b/twake/frontend/public/public/sounds/newnotification.wav differ diff --git a/twake/frontend/public/public/sounds/polite.wav b/twake/frontend/public/public/sounds/polite.wav new file mode 100644 index 00000000..198dcbb6 Binary files /dev/null and b/twake/frontend/public/public/sounds/polite.wav differ diff --git a/twake/frontend/public/public/viewer/AudioViewer/viewer.html b/twake/frontend/public/public/viewer/AudioViewer/viewer.html new file mode 100755 index 00000000..31e95c53 --- /dev/null +++ b/twake/frontend/public/public/viewer/AudioViewer/viewer.html @@ -0,0 +1,38 @@ + + + + + + + + + + diff --git a/twake/frontend/public/public/viewer/CodeViewer/ace.min.js b/twake/frontend/public/public/viewer/CodeViewer/ace.min.js new file mode 100644 index 00000000..d6a7f155 --- /dev/null +++ b/twake/frontend/public/public/viewer/CodeViewer/ace.min.js @@ -0,0 +1 @@ +(function(){var o,r,l,a,h,e,t,i=function(){return this}();i||"undefined"==typeof window||(i=window),"undefined"==typeof requirejs&&((o=function(e,t,i){"string"==typeof e?(2==arguments.length&&(i=t),o.modules[e]||(o.payloads[e]=i,o.modules[e]=null)):o.original?o.original.apply(this,arguments):(console.error("dropping module because define wasn't a string."),console.trace())}).modules={},o.payloads={},r=function(e,t,i){if("string"==typeof t){var n=h(e,t);if(null!=n)return i&&i(),n}else if("[object Array]"===Object.prototype.toString.call(t)){for(var s=[],o=0,r=t.length;o ["+this.end.row+"/"+this.end.column+"]"},this.contains=function(e,t){return 0==this.compare(e,t)},this.compareRange=function(e){var t=e.end,i=e.start,n=this.compare(t.row,t.column);return 1==n?1==(n=this.compare(i.row,i.column))?2:0==n?1:0:-1==n?-2:-1==(n=this.compare(i.row,i.column))?-1:1==n?42:0},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return 0==this.comparePoint(e.start)&&0==this.comparePoint(e.end)},this.intersects=function(e){var t=this.compareRange(e);return-1==t||0==t||1==t},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){"object"==typeof e?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){"object"==typeof e?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return 0==this.compare(e,t)&&(!this.isEnd(e,t)&&!this.isStart(e,t))},this.insideStart=function(e,t){return 0==this.compare(e,t)&&!this.isEnd(e,t)},this.insideEnd=function(e,t){return 0==this.compare(e,t)&&!this.isStart(e,t)},this.compare=function(e,t){return this.isMultiLine()||e!==this.start.row?ethis.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row!==e||t<=this.end.column?0:1:tthis.end.column?1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){var i,n;return this.end.row>t?i={row:t+1,column:0}:this.end.rowt?n={row:t+1,column:0}:this.start.row>=1)&&(e+=e);return i};var n=/^\s\s*/,s=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(n,"")},t.stringTrimRight=function(e){return e.replace(s,"")},t.copyObject=function(e){var t={};for(var i in e)t[i]=e[i];return t},t.copyArray=function(e){for(var t=[],i=0,n=e.length;iDate.now()-50)||(n=!1)},cancel:function(){n=Date.now()}}}),define("ace/keyboard/textinput",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/lib/dom","ace/lib/lang","ace/clipboard","ace/lib/keys"],function(e,t,i){"use strict";var D=e("../lib/event"),B=e("../lib/useragent"),H=e("../lib/dom"),P=e("../lib/lang"),N=e("../clipboard"),z=B.isChrome<18,V=B.isIE,U=63i+1?s.length:r,r+=a.length+1,a=a+"\n"+s):Y&&0v-1&&w[w.length-h]==e[e.length-h];)h++,o--;a-=h-1,l-=h-1;var c=r.length-h+1;if(c<0&&(s=-c,c=0),r=r.slice(0,c),!(t||r||a||s||o||l))return"";var u=!(m=!0);return B.isAndroid&&". "==r&&(r=" ",u=!0),r&&!s&&!o&&!a&&!l||p?d.onTextInput(r):d.onTextInput(r,{extendLeft:s,extendRight:o,restoreStart:a,restoreEnd:l}),m=!1,w=e,v=i,$=n,b=l,u?"\n":r}function o(e){if(h)return L();if(e&&e.inputType){if("historyUndo"==e.inputType)return d.execCommand("undo");if("historyRedo"==e.inputType)return d.execCommand("redo")}var t=g.value,i=s(t,!0);(500=w.length&&t.value===w&&w&&t.selectionEnd!==$?(d.selectAll(),y()):Y&&g.selectionStart!=v&&y())},d),D.addListener(g,"input",o,d),D.addListener(g,"cut",C,d),D.addListener(g,"copy",S,d),D.addListener(g,"paste",x,d),"oncut"in g&&"oncopy"in g&&"onpaste"in g||D.addListener(e,"keydown",function(e){if((!B.isMac||e.metaKey)&&e.ctrlKey)switch(e.keyCode){case 67:S(e);break;case 86:x(e);break;case 88:C(e)}},d);var L=function(){var e;if(h&&d.onCompositionUpdate&&!d.$readOnly)return p?i():void(h.useTextareaForIME?d.onCompositionUpdate(g.value):(e=g.value,s(e),h.markerRange&&(h.context&&(h.markerRange.start.column=h.selectionStart=h.context.compositionStartOffset),h.markerRange.end.column=h.markerRange.start.column+$-h.selectionStart+b)))},R=function(e){d.onCompositionEnd&&!d.$readOnly&&(h=!1,d.onCompositionEnd(),d.off("mousedown",i),e&&o())},M=P.delayedCall(L,50).schedule.bind(null,null);D.addListener(g,"compositionstart",function(e){var t;h||!d.onCompositionStart||d.$readOnly||(h={},p||(e.data&&(h.useTextareaForIME=!1),setTimeout(L,0),d._signal("compositionStart"),d.on("mousedown",i),(t=d.getSelectionRange()).end.row=t.start.row,t.end.column=t.start.column,h.markerRange=t,h.selectionStart=v,d.onCompositionStart(h),h.useTextareaForIME?(w=g.value="",$=v=0):(g.msGetInputContext&&(h.context=g.msGetInputContext()),g.getInputContext&&(h.context=g.getInputContext()))))},d),D.addListener(g,"compositionupdate",L,d),D.addListener(g,"keyup",function(e){27==e.keyCode&&g.value.lengththis.$focusTimeout)&&this.startSelect(this.mousedownEvent.getDocumentPosition())},this.onDoubleClick=function(e){var t=e.getDocumentPosition(),i=this.editor,n=i.session.getBracketRange(t);n?(n.isEmpty()&&(n.start.column--,n.end.column++),this.setState("select")):(n=i.selection.getWordRange(t.row,t.column),this.setState("selectByWords")),this.$clickSelection=n,this.select()},this.onTripleClick=function(e){var t=e.getDocumentPosition(),i=this.editor;this.setState("selectByLines");var n=i.getSelectionRange();n.isMultiLine()&&n.contains(t.row,t.column)?(this.$clickSelection=i.selection.getLineRange(n.start.row),this.$clickSelection.end=i.selection.getLineRange(n.end.row).end):this.$clickSelection=i.selection.getLineRange(t.row),this.select()},this.onQuadClick=function(e){var t=this.editor;t.selectAll(),this.$clickSelection=t.getSelectionRange(),this.setState("selectAll")},this.onMouseWheel=function(e){if(!e.getAccelKey()){e.getShiftKey()&&e.wheelY&&!e.wheelX&&(e.wheelX=e.wheelY,e.wheelY=0);var t=this.editor;this.$lastScroll||(this.$lastScroll={t:0,vx:0,vy:0,allowed:0});var i=this.$lastScroll,n=e.domEvent.timeStamp,s=n-i.t,o=s?e.wheelX/s:i.vx,r=s?e.wheelY/s:i.vy;s<550&&(o=(o+i.vx)/2,r=(r+i.vy)/2);var a=Math.abs(o/r),l=!1;return 1<=a&&t.renderer.isScrollableBy(e.wheelX*e.speed,0)&&(l=!0),a<=1&&t.renderer.isScrollableBy(0,e.wheelY*e.speed)&&(l=!0),l?i.allowed=n:n-i.allowed<550&&(Math.abs(o)<=1.5*Math.abs(i.vx)&&Math.abs(r)<=1.5*Math.abs(i.vy)?(l=!0,i.allowed=n):i.allowed=0),i.t=n,i.vx=o,i.vy=r,l?(t.renderer.scrollBy(e.wheelX*e.speed,e.wheelY*e.speed),e.stop()):void 0}}}).call(n.prototype),t.DefaultHandlers=n}),define("ace/tooltip",["require","exports","module","ace/lib/oop","ace/lib/dom"],function(e,t,i){"use strict";function n(e){this.isOpen=!1,this.$element=null,this.$parentNode=e}e("./lib/oop");var s=e("./lib/dom");(function(){this.$init=function(){return this.$element=s.createElement("div"),this.$element.className="ace_tooltip",this.$element.style.display="none",this.$parentNode.appendChild(this.$element),this.$element},this.getElement=function(){return this.$element||this.$init()},this.setText=function(e){this.getElement().textContent=e},this.setHtml=function(e){this.getElement().innerHTML=e},this.setPosition=function(e,t){this.getElement().style.left=e+"px",this.getElement().style.top=t+"px"},this.setClassName=function(e){s.addCssClass(this.getElement(),e)},this.show=function(e,t,i){null!=e&&this.setText(e),null!=t&&null!=i&&this.setPosition(t,i),this.isOpen||(this.getElement().style.display="block",this.isOpen=!0)},this.hide=function(){this.isOpen&&(this.getElement().style.display="none",this.isOpen=!1)},this.getHeight=function(){return this.getElement().offsetHeight},this.getWidth=function(){return this.getElement().offsetWidth},this.destroy=function(){this.isOpen=!1,this.$element&&this.$element.parentNode&&this.$element.parentNode.removeChild(this.$element)}}).call(n.prototype),t.Tooltip=n}),define("ace/mouse/default_gutter_handler",["require","exports","module","ace/lib/dom","ace/lib/oop","ace/lib/event","ace/tooltip"],function(e,t,i){"use strict";function n(e){r.call(this,e)}var s=e("../lib/dom"),o=e("../lib/oop"),f=e("../lib/event"),r=e("../tooltip").Tooltip;o.inherits(n,r),function(){this.setPosition=function(e,t){var i=window.innerWidth||document.documentElement.clientWidth,n=window.innerHeight||document.documentElement.clientHeight,s=this.getWidth(),o=this.getHeight();i<(e+=15)+s&&(e-=e+s-i),n<(t+=15)+o&&(t-=20+o),r.prototype.setPosition.call(this,e,t)}}.call(n.prototype),t.GutterHandler=function(r){function a(){i=i&&clearTimeout(i),c&&(g.hide(),c=null,u._signal("hideGutterTooltip",g),u.off("mousewheel",a))}function l(e){g.setPosition(e.x,e.y)}var i,h,c,u=r.editor,d=u.renderer.$gutterLayer,g=new n(u.container);r.editor.setDefaultHandler("guttermousedown",function(e){if(u.isFocused()&&0==e.getButton()&&"foldWidgets"!=d.getRegion(e)){var t=e.getDocumentPosition().row,i=u.session.selection;if(e.getShiftKey())i.selectTo(t,0);else{if(2==e.domEvent.detail)return u.selectAll(),e.preventDefault();r.$clickSelection=u.selection.getLineRange(t)}return r.setState("selectByLines"),r.captureMouse(e),e.preventDefault()}}),r.editor.setDefaultHandler("guttermousemove",function(e){var t=e.domEvent.target||e.domEvent.srcElement;if(s.hasCssClass(t,"ace_fold-widget"))return a();c&&r.$tooltipFollowsMouse&&l(e),h=e,i=i||setTimeout(function(){i=null,(h&&!r.isMousePressed?function(){var e,t,i=h.getDocumentPosition().row,n=d.$annotations[i];if(!n)return a();if(i==u.session.getLength()){var s=u.renderer.pixelToScreenCoordinates(0,h.y).row,o=h.$pos;if(s>u.session.documentToScreenRow(o.row,o.column))return a()}c!=n&&(c=n.text.join("
"),g.setHtml(c),g.show(),u._signal("showGutterTooltip",g),u.on("mousewheel",a),r.$tooltipFollowsMouse?l(h):(e=h.domEvent.target.getBoundingClientRect(),(t=g.getElement().style).left=e.right+"px",t.top=e.bottom+"px"))}:a)()},50)}),f.addListener(u.renderer.$gutter,"mouseout",function(e){h=null,c&&!i&&(i=setTimeout(function(){i=null,a()},50))},u),u.on("changeSession",a)}}),define("ace/mouse/mouse_event",["require","exports","module","ace/lib/event","ace/lib/useragent"],function(e,t,i){"use strict";var n=e("../lib/event"),s=e("../lib/useragent"),o=t.MouseEvent=function(e,t){this.domEvent=e,this.editor=t,this.x=this.clientX=e.clientX,this.y=this.clientY=e.clientY,this.$pos=null,this.$inSelection=null,this.propagationStopped=!1,this.defaultPrevented=!1};(function(){this.stopPropagation=function(){n.stopPropagation(this.domEvent),this.propagationStopped=!0},this.preventDefault=function(){n.preventDefault(this.domEvent),this.defaultPrevented=!0},this.stop=function(){this.stopPropagation(),this.preventDefault()},this.getDocumentPosition=function(){return this.$pos||(this.$pos=this.editor.renderer.screenToTextCoordinates(this.clientX,this.clientY)),this.$pos},this.inSelection=function(){if(null!==this.$inSelection)return this.$inSelection;var e,t=this.editor.getSelectionRange();return t.isEmpty()?this.$inSelection=!1:(e=this.getDocumentPosition(),this.$inSelection=t.contains(e.row,e.column)),this.$inSelection},this.getButton=function(){return n.getButton(this.domEvent)},this.getShiftKey=function(){return this.domEvent.shiftKey},this.getAccelKey=s.isMac?function(){return this.domEvent.metaKey}:function(){return this.domEvent.ctrlKey}}).call(o.prototype)}),define("ace/mouse/dragdrop_handler",["require","exports","module","ace/lib/dom","ace/lib/event","ace/lib/useragent"],function(e,t,i){"use strict";function n(t){function e(){var e,t,i,n,s,o=u;u=g.renderer.screenToTextCoordinates(f,m),e=u,t=o,i=Date.now(),n=!t||e.row!=t.row,s=!t||e.column!=t.column,!v||n||s?(g.moveCursorToPosition(e),v=i,$={x:f,y:m}):5this.editor.getDragDelay()&&this.startDrag()},this.dragWaitEnd=function(){this.editor.container.draggable=!1,this.startSelect(this.mousedownEvent.getDocumentPosition()),this.selectEnd()},this.dragReadyEnd=function(e){this.editor.$resetCursorStyle(),this.editor.unsetStyle("ace_dragging"),this.editor.renderer.setCursorStyle(""),this.dragWaitEnd()},this.startDrag=function(){this.cancelDrag=!1;var e=this.editor;e.container.draggable=!0,e.renderer.$cursorLayer.setBlinking(!1),e.setStyle("ace_dragging");var t=A.isWin?"default":"move";e.renderer.setCursorStyle(t),this.setState("dragReady")},this.onMouseDrag=function(e){var t=this.editor.container;A.isIE&&"dragReady"==this.state&&3i&&(S=-1),y=e.clientX=r,C=e.clientY=a,T=_=0;var l=new F(e,$);if(A=l.getDocumentPosition(),s-S<500&&1==t.length&&!M)E++,e.preventDefault(),e.button=0,function(){k=null,clearTimeout(k),$.selection.moveToPosition(A);var e=2<=E?$.selection.getLineRange(A.row):$.session.getBracketRange(A);e&&!e.isEmpty()?$.selection.setRange(e):$.selection.selectWord(),R="wait"}();else{E=0;var h=$.selection.cursor,c=$.selection.isEmpty()?h:$.selection.anchor,u=$.renderer.$cursorLayer.getPixelPosition(h,!0),d=$.renderer.$cursorLayer.getPixelPosition(c,!0),g=$.renderer.scroller.getBoundingClientRect(),f=$.renderer.layerConfig.offset,m=$.renderer.scrollLeft,p=function(e,t){return(e/=n)*e+(t=t/i-.75)*t};if(e.clientX=e){for(n=l+1;n=e;)n++;for(s=l,o=n-1;s=t.length||(c=i[n-1])!=g&&c!=f||(s=t[n+1])!=g&&s!=f?x:($&&(s=f),s==c?s:x);case E:return(c=0>8;return 0==i?191L&&t[a]t.row||e.row==t.row&&e.column>t.column},this.getRange=function(){var e=this.anchor,t=this.lead;return this.$isEmpty?a.fromPoints(t,t):this.isBackwards()?a.fromPoints(t,e):a.fromPoints(e,t)},this.clearSelection=function(){this.$isEmpty||(this.$isEmpty=!0,this._emit("changeSelection"))},this.selectAll=function(){this.$setSelection(0,0,Number.MAX_VALUE,Number.MAX_VALUE)},this.setRange=this.setSelectionRange=function(e,t){var i=t?e.end:e.start,n=t?e.start:e.end;this.$setSelection(i.row,i.column,n.row,n.column)},this.$setSelection=function(e,t,i,n){var s,o;this.$silent||(s=this.$isEmpty,o=this.inMultiSelectMode,this.$silent=!0,this.$cursorChanged=this.$anchorChanged=!1,this.anchor.setPosition(e,t),this.cursor.setPosition(i,n),this.$isEmpty=!a.comparePoints(this.anchor,this.cursor),this.$silent=!1,this.$cursorChanged&&this._emit("changeCursor"),(this.$cursorChanged||this.$anchorChanged||s!=this.$isEmpty||o)&&this._emit("changeSelection"))},this.$moveSelection=function(e){var t=this.lead;this.$isEmpty&&this.setSelectionAnchor(t.row,t.column),e.call(this)},this.selectTo=function(e,t){this.$moveSelection(function(){this.moveCursorTo(e,t)})},this.selectToPosition=function(e){this.$moveSelection(function(){this.moveCursorToPosition(e)})},this.moveTo=function(e,t){this.clearSelection(),this.moveCursorTo(e,t)},this.moveToPosition=function(e){this.clearSelection(),this.moveCursorToPosition(e)},this.selectUp=function(){this.$moveSelection(this.moveCursorUp)},this.selectDown=function(){this.$moveSelection(this.moveCursorDown)},this.selectRight=function(){this.$moveSelection(this.moveCursorRight)},this.selectLeft=function(){this.$moveSelection(this.moveCursorLeft)},this.selectLineStart=function(){this.$moveSelection(this.moveCursorLineStart)},this.selectLineEnd=function(){this.$moveSelection(this.moveCursorLineEnd)},this.selectFileEnd=function(){this.$moveSelection(this.moveCursorFileEnd)},this.selectFileStart=function(){this.$moveSelection(this.moveCursorFileStart)},this.selectWordRight=function(){this.$moveSelection(this.moveCursorWordRight)},this.selectWordLeft=function(){this.$moveSelection(this.moveCursorWordLeft)},this.getWordRange=function(e,t){var i;return void 0===t&&(e=(i=e||this.lead).row,t=i.column),this.session.getWordRange(e,t)},this.selectWord=function(){this.setSelectionRange(this.getWordRange())},this.selectAWord=function(){var e=this.getCursor(),t=this.session.getAWordRange(e.row,e.column);this.setSelectionRange(t)},this.getLineRange=function(e,t){var i="number"==typeof e?e:this.lead.row,n=this.session.getFoldLine(i),s=n?(i=n.start.row,n.end.row):i;return!0===t?new a(i,0,s,this.session.getLine(s).length):new a(i,0,s+1,0)},this.selectLine=function(){this.setSelectionRange(this.getLineRange())},this.moveCursorUp=function(){this.moveCursorBy(-1,0)},this.moveCursorDown=function(){this.moveCursorBy(1,0)},this.wouldMoveIntoSoftTab=function(e,t,i){var n=e.column,s=e.column+t;return i<0&&(n=e.column-t,s=e.column),this.session.isTabStop(e)&&this.doc.getLine(e.row).slice(n,s).split(" ").length-1==t},this.moveCursorLeft=function(){var e,t,i=this.lead.getPosition();(e=this.session.getFoldAt(i.row,i.column,-1))?this.moveCursorTo(e.start.row,e.start.column):0===i.column?0=i.length)return this.moveCursorTo(e,i.length),this.moveCursorRight(),void(eh&&(d=e.substring(h,p-m.length),u.type==g?u.value+=d:(u.type&&l.push(u),u={type:g,value:d}));for(var w=0;wv){for(c>2*e.length&&this.reportError("infinite loop with in ace tokenizer",{startState:t,line:e});h=this.$rowTokens.length;){if(this.$row+=1,e=e||this.$session.getLength(),this.$row>=e)return this.$row=e-1,null;this.$rowTokens=this.$session.getTokens(this.$row),this.$tokenIndex=0}return this.$rowTokens[this.$tokenIndex]},this.getCurrentToken=function(){return this.$rowTokens[this.$tokenIndex]},this.getCurrentTokenRow=function(){return this.$row},this.getCurrentTokenColumn=function(){var e=this.$rowTokens,t=this.$tokenIndex,i=e[t].start;if(void 0!==i)return i;for(i=0;0e.length&&(b=e.length)}),l==1/0&&(l=b,a=r=!1),c&&l%h!=0&&(l=Math.floor(l/h)*h),t(a?u:g)},this.toggleBlockComment=function(e,t,i,n){var s=this.blockComment;if(s){!s.start&&s[0]&&(s=s[0]);var o,r,a=(d=new m(t,n.row,n.column)).getCurrentToken(),l=(t.selection,t.selection.toOrientedRange());if(a&&/comment/.test(a.type)){for(;a&&/comment/.test(a.type);){if(-1!=(g=a.value.indexOf(s.start))){var h=d.getCurrentTokenRow(),c=d.getCurrentTokenColumn()+g,u=new p(h,c,h,c+s.start.length);break}a=d.stepBackward()}for(var d,g,a=(d=new m(t,n.row,n.column)).getCurrentToken();a&&/comment/.test(a.type);){if(-1!=(g=a.value.indexOf(s.end))){var h=d.getCurrentTokenRow(),c=d.getCurrentTokenColumn()+g,f=new p(h,c,h,c+s.end.length);break}a=d.stepForward()}f&&t.remove(f),u&&(t.remove(u),o=u.start.row,r=-s.start.length)}else r=s.start.length,o=i.start.row,t.insert(i.end,s.end),t.insert(i.start,s.start);l.start.row==o&&(l.start.column+=r),l.end.row==o&&(l.end.column+=r),t.selection.fromOrientedRange(l)}},this.getNextLineIndent=function(e,t,i){return this.$getIndent(t)},this.checkOutdent=function(e,t,i){return!1},this.autoOutdent=function(e,t,i){},this.$getIndent=function(e){return e.match(/^\s*/)[0]},this.createWorker=function(e){return null},this.createModeDelegates=function(e){for(var n in this.$embeds=[],this.$modes={},e){var t,i,s;e[n]&&(i=(t=e[n]).prototype.$id,(s=r.$modes[i])||(r.$modes[i]=s=new t),r.$modes[n]||(r.$modes[n]=s),this.$embeds.push(n),this.$modes[n]=s)}for(var o=["toggleBlockComment","toggleCommentLines","getNextLineIndent","checkOutdent","autoOutdent","transformAction","getCompletions"],n=0;nthis.row||(i=e,n={row:this.row,column:this.column},s=this.$insertRight,o="insert"==i.action,r=(o?1:-1)*(i.end.row-i.start.row),a=(o?1:-1)*(i.end.column-i.start.column),l=i.start,h=o?l:i.end,t=c(n,l,s)?{row:n.row,column:n.column}:c(h,n,!s)?{row:n.row+r,column:n.column+(n.row==h.row?a:0)}:{row:l.row,column:l.column},this.setPosition(t.row,t.column,!0))},this.setPosition=function(e,t,i){var n,s=i?{row:e,column:t}:this.$clipPositionToDocument(e,t);this.row==s.row&&this.column==s.column||(n={row:this.row,column:this.column},this.row=s.row,this.column=s.column,this._signal("change",{old:n,value:s}))},this.detach=function(){this.document.off("change",this.$onChange)},this.attach=function(e){this.document=e||this.document,this.document.on("change",this.$onChange)},this.$clipPositionToDocument=function(e,t){var i={};return e>=this.document.getLength()?(i.row=Math.max(0,this.document.getLength()-1),i.column=this.document.getLine(i.row).length):e<0?(i.row=0,i.column=0):(i.row=e,i.column=Math.min(this.document.getLine(i.row).length,Math.max(0,t))),t<0&&(i.column=0),i}}).call(o.prototype)}),define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"],function(e,t,i){"use strict";function n(e){this.$lines=[""],0===e.length?this.$lines=[""]:Array.isArray(e)?this.insertMergedLines({row:0,column:0},e):this.insert({row:0,column:0},e)}var s=e("./lib/oop"),o=e("./apply_delta").applyDelta,r=e("./lib/event_emitter").EventEmitter,c=e("./range").Range,a=e("./anchor").Anchor;(function(){s.implement(this,r),this.setValue=function(e){var t=this.getLength()-1;this.remove(new c(0,0,t,this.getLine(t).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new a(this,e,t)},0==="aaa".split(/a/).length?this.$split=function(e){return e.replace(/\r\n|\r/g,"\n").split("\n")}:this.$split=function(e){return e.split(/\r\n|\r|\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r\n|\r|\n)/m);this.$autoNewLine=t?t[1]:"\n",this._signal("changeNewLineMode")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case"windows":return"\r\n";case"unix":return"\n";default:return this.$autoNewLine||"\n"}},this.$autoNewLine="",this.$newLineMode="auto",this.setNewLineMode=function(e){this.$newLineMode!==e&&(this.$newLineMode=e,this._signal("changeNewLineMode"))},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return"\r\n"==e||"\r"==e||"\n"==e},this.getLine=function(e){return this.$lines[e]||""},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){return this.getLinesForRange(e).join(this.getNewLineCharacter())},this.getLinesForRange=function(e){var t,i;return e.start.row===e.end.row?t=[this.getLine(e.start.row).substring(e.start.column,e.end.column)]:((t=this.getLines(e.start.row,e.end.row))[0]=(t[0]||"").substring(e.start.column),i=t.length-1,e.end.row-e.start.row==i&&(t[i]=t[i].substring(0,e.end.column))),t},this.insertLines=function(e,t){return console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."),this.insertFullLines(e,t)},this.removeLines=function(e,t){return console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."),this.removeFullLines(e,t)},this.insertNewLine=function(e){return console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."),this.insertMergedLines(e,["",""])},this.insert=function(e,t){return this.getLength()<=1&&this.$detectNewLine(t),this.insertMergedLines(e,this.$split(t))},this.insertInLine=function(e,t){var i=this.clippedPos(e.row,e.column),n=this.pos(e.row,e.column+t.length);return this.applyDelta({start:i,end:n,action:"insert",lines:[t]},!0),this.clonePos(n)},this.clippedPos=function(e,t){var i=this.getLength();void 0===e?e=i:e<0?e=0:i<=e&&(e=i-1,t=void 0);var n=this.getLine(e);return null==t&&(t=n.length),{row:e,column:t=Math.min(Math.max(t,0),n.length)}},this.clonePos=function(e){return{row:e.row,column:e.column}},this.pos=function(e,t){return{row:e,column:t}},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t?(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length):(e.row=Math.max(0,e.row),e.column=Math.min(Math.max(e.column,0),this.getLine(e.row).length)),e},this.insertFullLines=function(e,t){var i=0,i=(e=Math.min(Math.max(e,0),this.getLength()))e+1&&(this.currentLine=e+1)):this.currentLine==e&&(this.currentLine=e+1),this.lines[e]=n.tokens}}).call(n.prototype),t.BackgroundTokenizer=n}),define("ace/search_highlight",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"],function(e,t,i){"use strict";function n(e,t,i){this.setRegexp(e),this.clazz=t,this.type=i||"text"}var h=e("./lib/lang"),c=(e("./lib/oop"),e("./range").Range);(function(){this.MAX_RANGES=500,this.setRegexp=function(e){this.regExp+""!=e+""&&(this.regExp=e,this.cache=[])},this.update=function(e,t,i,n){if(this.regExp)for(var s=n.firstRow,o=n.lastRow,r=s;r<=o;r++){var a=this.cache[r];null==a&&((a=h.getMatchOffsets(i.getLine(r),this.regExp)).length>this.MAX_RANGES&&(a=a.slice(0,this.MAX_RANGES)),a=a.map(function(e){return new c(r,e.offset,r,e.offset+e.length)}),this.cache[r]=a.length?a:"");for(var l=a.length;l--;)t.drawSingleLineMarker(e,a[l].toScreenRange(i),this.clazz,n)}}}).call(n.prototype),t.SearchHighlight=n}),define("ace/edit_session/fold_line",["require","exports","module","ace/range"],function(e,t,i){"use strict";function h(e,t){this.foldData=e,Array.isArray(t)?this.folds=t:t=this.folds=[t];var i=t[t.length-1];this.range=new n(t[0].start.row,t[0].start.column,i.end.row,i.end.column),this.start=this.range.start,this.end=this.range.end,this.folds.forEach(function(e){e.setFoldLine(this)},this)}var n=e("../range").Range;(function(){this.shiftRow=function(t){this.start.row+=t,this.end.row+=t,this.folds.forEach(function(e){e.start.row+=t,e.end.row+=t})},this.addFold=function(e){if(e.sameRow){if(e.start.rowthis.endRow)throw new Error("Can't add a fold to this FoldLine as it has no connection");this.folds.push(e),this.folds.sort(function(e,t){return-e.range.compareEnd(t.start.row,t.start.column)}),0=this.start.row&&e<=this.end.row},this.walk=function(e,t,i){var n,s,o=0,r=this.folds,a=!0;null==t&&(t=this.end.row,i=this.end.column);for(var l=0;lt||i[i.length-1].start.row=n)break}if("insert"==e.action)for(var l=s-n,h=-t.column+i.column;rn)break;if(c.start.row==n&&c.start.column>=t.column&&(c.start.column==t.column&&this.$bias<=0||(c.start.column+=h,c.start.row+=l)),c.end.row==n&&c.end.column>=t.column){if(c.end.column==t.column&&this.$bias<0)continue;c.end.column==t.column&&0c.start.column&&c.end.column==o[r+1].start.column&&(c.end.column-=h),c.end.column+=h,c.end.row+=l}}else for(var c,l=n-s,h=t.column-i.column;rs)break;c.end.rowt.column)&&(c.end.column=t.column,c.end.row=t.row):(c.end.column+=h,c.end.row+=l):c.end.row>s&&(c.end.row+=l),c.start.rowt.column)&&(c.start.column=t.column,c.start.row=t.row):(c.start.column+=h,c.start.row+=l):c.start.row>s&&(c.start.row+=l)}if(0!=l&&r=e)return s;if(s.end.row>e)return null}return null},this.getNextFoldLine=function(e,t){var i=this.$foldData,n=0;for(t&&(n=i.indexOf(t)),-1==n&&(n=0);n=e)return s}return null},this.getFoldedRowCount=function(e,t){for(var i=this.$foldData,n=t-e+1,s=0;sl)break}while(s&&r.test(s.type));s=n.stepBackward()}else s=n.getCurrentToken();return a.end.row=n.getCurrentTokenRow(),a.end.column=n.getCurrentTokenColumn()+s.value.length-2,a}},this.foldAll=function(e,t,i,n){null==i&&(i=1e5);var s=this.foldWidgets;if(s){t=t||this.getLength();for(var o,r=e=e||0;r=e&&(r=o.end.row,o.collapseChildren=i,this.addFold("...",o)))}}},this.foldToLevel=function(e){for(this.foldAll();0=e)break}n--}return{range:-1!==n&&o,firstRange:r}},this.onFoldWidgetClick=function(e,t){var i,n={children:(t=t.domEvent).shiftKey,all:t.ctrlKey||t.metaKey,siblings:t.altKey};this.$toggleFoldWidget(e,n)||(i=t.target||t.srcElement)&&/ace_fold-widget/.test(i.className)&&(i.className+=" ace_invalid")},this.$toggleFoldWidget=function(e,t){if(this.getFoldWidget){var i=this.getFoldWidget(e),n=this.getLine(e),s="end"===i?-1:1,o=this.getFoldAt(e,-1==s?0:n.length,s);if(o)return t.children||t.all?this.removeFold(o):this.expandFold(o),o;var r,a,l,h=this.getFoldWidgetRange(e,!0);return h&&!h.isMultiLine()&&(o=this.getFoldAt(h.start.row,h.start.column,1))&&h.isEqual(o.range)?(this.removeFold(o),o):(t.siblings?((r=this.getParentFoldRangeData(e)).range&&(a=r.range.start.row+1,l=r.range.end.row),this.foldAll(a,l,t.all?1e4:0)):t.children?(l=h?h.end.row:this.getLength(),this.foldAll(e+1,l,t.all?1e4:0)):h&&(t.all&&(h.collapseChildren=1e4),this.addFold("...",h)),h)}},this.toggleFoldWidget=function(e){var t,i,n=this.selection.getCursor().row,n=this.getRowFoldStart(n),s=this.$toggleFoldWidget(n,{});s||(s=(t=this.getParentFoldRangeData(n,!0)).range||t.firstRange)&&(n=s.start.row,(i=this.getFoldAt(n,this.getLine(n).length,1))?this.removeFold(i):this.addFold("...",s))},this.updateFoldWidgets=function(e){var t,i=e.start.row,n=e.end.row-i;0==n?this.foldWidgets[i]=null:"remove"==e.action?this.foldWidgets.splice(i,1+n,null):((t=Array(1+n)).unshift(i,1),this.foldWidgets.splice.apply(this.foldWidgets,t))},this.tokenizerUpdateFoldWidgets=function(e){var t=e.data;t.first!=t.last&&this.foldWidgets.length>t.first&&this.foldWidgets.splice(t.first,this.foldWidgets.length)}}}),define("ace/edit_session/bracket_match",["require","exports","module","ace/token_iterator","ace/range"],function(e,t,i){"use strict";var u=e("../token_iterator").TokenIterator,a=e("../range").Range;t.BracketMatch=function(){this.findMatchingBracket=function(e,t){if(0==e.column)return null;var i=t||this.getLine(e.row).charAt(e.column-1);if(""==i)return null;var n=i.match(/([\(\[\{])|([\)\]\}])/);return n?n[1]?this.$findClosingBracket(n[1],e):this.$findOpeningBracket(n[2],e):null},this.getBracketRange=function(e){var t,i,n=this.getLine(e.row),s=!0,o=n.charAt(e.column-1),r=o&&o.match(/([\(\[\{])|([\)\]\}])/);if(r||(o=n.charAt(e.column),e={row:e.row,column:e.column+1},r=o&&o.match(/([\(\[\{])|([\)\]\}])/),s=!1),!r)return null;if(r[1]){if(!(i=this.$findClosingBracket(r[1],e)))return null;t=a.fromPoints(e,i),s||(t.end.column++,t.start.column--),t.cursor=t.end}else{if(!(i=this.$findOpeningBracket(r[2],e)))return null;t=a.fromPoints(i,e),s||(t.start.column++,t.end.column--),t.cursor=t.start}return t},this.getMatchingBracketRanges=function(e){var t=this.getLine(e.row),i=t.charAt(e.column-1),n=i&&i.match(/([\(\[\{])|([\)\]\}])/);if(n||(i=t.charAt(e.column),e={row:e.row,column:e.column+1},n=i&&i.match(/([\(\[\{])|([\)\]\}])/)),!n)return null;var s=new a(e.row,e.column-1,e.row,e.column),o=n[1]?this.$findClosingBracket(n[1],e):this.$findOpeningBracket(n[2],e);return o?[s,new a(o.row,o.column,o.row,o.column+1)]:[s]},this.$brackets={")":"(","(":")","]":"[","[":"]","{":"}","}":"{","<":">",">":"<"},this.$findOpeningBracket=function(e,t,i){var n=this.$brackets[e],s=1,o=new u(this,t.row,t.column),r=o.getCurrentToken();if(r=r||o.stepForward()){i=i||new RegExp("(\\.?"+r.type.replace(".","\\.").replace("rparen",".paren").replace(/\b(?:end)\b/,"(?:start|begin|end)")+")+");for(var a=t.column-o.getCurrentTokenColumn()-2,l=r.value;;){for(;0<=a;){var h=l.charAt(a);if(h==n){if(0==--s)return{row:o.getCurrentTokenRow(),column:a+o.getCurrentTokenColumn()}}else h==e&&(s+=1);--a}for(;(r=o.stepBackward())&&!i.test(r.type););if(null==r)break;a=(l=r.value).length-1}return null}},this.$findClosingBracket=function(e,t,i){var n=this.$brackets[e],s=1,o=new u(this,t.row,t.column),r=o.getCurrentToken();if(r=r||o.stepForward()){i=i||new RegExp("(\\.?"+r.type.replace(".","\\.").replace("lparen",".paren").replace(/\b(?:start|begin)\b/,"(?:start|begin|end)")+")+");for(var a=t.column-o.getCurrentTokenColumn();;){for(var l=r.value,h=l.length;a>1,o=e[s];if(ot&&(t=e.screenWidth)}),this.lineWidgetWidth=t},this.$computeWidth=function(e){if(this.$modified||e){if(this.$modified=!1,this.$useWrapMode)return this.screenWidth=this.$wrapLimit;for(var t=this.doc.getAllLines(),i=this.$rowLengthCache,n=0,s=0,o=this.$foldData[s],r=o?o.start.row:1/0,a=t.length,l=0;ln&&(n=i[l])}this.screenWidth=n}},this.getLine=function(e){return this.doc.getLine(e)},this.getLines=function(e,t){return this.doc.getLines(e,t)},this.getLength=function(){return this.doc.getLength()},this.getTextRange=function(e){return this.doc.getTextRange(e||this.selection.getRange())},this.insert=function(e,t){return this.doc.insert(e,t)},this.remove=function(e){return this.doc.remove(e)},this.removeFullLines=function(e,t){return this.doc.removeFullLines(e,t)},this.undoChanges=function(e,t){if(e.length){this.$fromUndo=!0;for(var i=e.length-1;-1!=i;i--){var n=e[i];"insert"==n.action||"remove"==n.action?this.doc.revertDelta(n):n.folds&&this.addFolds(n.folds)}!t&&this.$undoSelect&&(e.selectionBefore?this.selection.fromJSON(e.selectionBefore):this.selection.setRange(this.$getUndoSelection(e,!0))),this.$fromUndo=!1}},this.redoChanges=function(e,t){if(e.length){this.$fromUndo=!0;for(var i=0;ie.end.column&&(h.start.column+=r),h.end.row==e.end.row&&h.end.column>e.end.column&&(h.end.column+=r)),o&&h.start.row>=e.end.row&&(h.start.row+=o,h.end.row+=o)),h.end=this.insert(h.start,a),l.length&&(n=e.start,s=h.start,o=s.row-n.row,r=s.column-n.column,this.addFolds(l.map(function(e){return(e=e.clone()).start.row==n.row&&(e.start.column+=r),e.end.row==n.row&&(e.end.column+=r),e.start.row+=o,e.end.row+=o,e}))),h},this.indentRows=function(e,t,i){i=i.replace(/\t/g,this.getTabString());for(var n=e;n<=t;n++)this.doc.insertInLine({row:n,column:0},i)},this.outdentRows=function(e){for(var t=e.collapseRows(),i=new c(0,0,0,0),n=this.getTabSize(),s=t.start.row;s<=t.end.row;++s){var o=this.getLine(s);i.start.row=s,i.end.row=s;for(var r=0;rthis.doc.getLength()-1)return 0;n=s-t}else{e=this.$clipRowToDocument(e);n=(t=this.$clipRowToDocument(t))-e+1}var o=new c(e,0,t,Number.MAX_VALUE),r=this.getFoldsInRange(o).map(function(e){return(e=e.clone()).start.row+=n,e.end.row+=n,e}),a=0==i?this.doc.getLines(e,t):this.doc.removeFullLines(e,t);return this.doc.insertFullLines(e+n,a),r.length&&this.addFolds(r),n},this.moveLinesUp=function(e,t){return this.$moveLines(e,t,-1)},this.moveLinesDown=function(e,t){return this.$moveLines(e,t,1)},this.duplicateLines=function(e,t){return this.$moveLines(e,t,0)},this.$clipRowToDocument=function(e){return Math.max(0,Math.min(e,this.doc.getLength()-1))},this.$clipColumnToRow=function(e,t){return t<0?0:Math.min(this.doc.getLine(e).length,t)},this.$clipPositionToDocument=function(e,t){var i;return t=Math.max(0,t),t=e<0?e=0:(i=this.doc.getLength())<=e?(e=i-1,this.doc.getLine(i-1).length):Math.min(this.doc.getLine(e).length,t),{row:e,column:t}},this.$clipRangeToDocument=function(e){e.start.row<0?(e.start.row=0,e.start.column=0):e.start.column=this.$clipColumnToRow(e.start.row,e.start.column);var t=this.doc.getLength()-1;return e.end.row>t?(e.end.row=t,e.end.column=this.doc.getLine(t).length):e.end.column=this.$clipColumnToRow(e.end.row,e.end.column),e},this.$wrapLimit=80,this.$useWrapMode=!1,this.$wrapLimitRange={min:null,max:null},this.setUseWrapMode=function(e){var t;e!=this.$useWrapMode&&(this.$useWrapMode=e,this.$modified=!0,this.$resetRowCache(0),e&&(t=this.getLength(),this.$wrapData=Array(t),this.$updateWrapData(0,t-1)),this._signal("changeWrapMode"))},this.getUseWrapMode=function(){return this.$useWrapMode},this.setWrapLimitRange=function(e,t){this.$wrapLimitRange.min===e&&this.$wrapLimitRange.max===t||(this.$wrapLimitRange={min:e,max:t},this.$modified=!0,this.$bidiHandler.markAsDirty(),this.$useWrapMode&&this._signal("changeWrapMode"))},this.adjustWrapLimit=function(e,t){var i=this.$wrapLimitRange;i.max<0&&(i={min:t,max:t});var n=this.$constrainWrapLimit(e,i.min,i.max);return n!=this.$wrapLimit&&1=s.row&&m.shiftRow(-a)}r=o}else{var d=Array(a);d.unshift(o,0);var g=t?this.$wrapData:this.$rowLengthCache;g.splice.apply(g,d);var f,h=this.$foldData,u=0;for((m=this.getFoldLine(o))&&(0==(f=m.range.compareInside(n.row,n.column))?(m=m.split(n.row,n.column))&&(m.shiftRow(a),m.addRemoveChars(r,0,s.column-n.column)):-1==f&&(m.addRemoveChars(o,0,s.column-n.column),m.shiftRow(a)),u=h.indexOf(m)+1);u=o&&m.shiftRow(a)}}else{var m,a=Math.abs(e.start.column-e.end.column);"remove"===i&&(l=this.getFoldsInRange(e),this.removeFolds(l),a=-a),(m=this.getFoldLine(o))&&m.addRemoveChars(o,n.column,a)}return t&&this.$wrapData.length!=this.doc.getLength()&&console.error("doc.getLength() and $wrapData.length have to be the same!"),this.$updating=!1,t?this.$updateWrapData(o,r):this.$updateRowLengthCache(o,r),l},this.$updateRowLengthCache=function(e,t,i){this.$rowLengthCache[e]=null,this.$rowLengthCache[t]=null},this.$updateWrapData=function(e,t){var r,i,a=this.doc.getAllLines(),n=this.getTabSize(),s=this.$wrapData,o=this.$wrapLimit,l=e;for(t=Math.min(t,a.length-1);l<=t;)(i=this.getFoldLine(l,i))?(r=[],i.walk(function(e,t,i,n){var s;if(null!=e){(s=this.$getDisplayTokens(e,r.length))[0]=f;for(var o=1;o>2)),a-1);gc[d-1]):!d;for(var g=this.getLength()-1,f=this.getNextFoldLine(r),m=f?f.start.row:1/0;l<=e&&!(eh[u-1]):!u;for(var d=this.getNextFoldLine(l),g=d?d.start.row:1/0;l=p[w];)s++,w++;f=f.substring(p[w-1]||0,f.length),m=0g||(s.push(r=new y(h,g,h+a-1,f)),2$&&s[c].end.row==i.end.row;)c--;for(s=s.slice(m,c+1),m=0,c=s.length;m=s.length)break;u.lastIndex=r+=1}if(n.index+a>t)break;o.push(n.index,a)}for(var l=o.length-1;0<=l;l-=2){var h=o[l-1];if(i(e,h,e,h+(a=o[l])))return!0}}:function(e,t,i){var n,s=c.getLine(e);for(u.lastIndex=t;n=u.exec(s);){var o,r=n[0].length;if(i(e,o=n.index,e,o+r))return!0;if(!r&&(u.lastIndex=o+=1,o>=s.length))return!1}},{forEach:s}}}).call(n.prototype),t.Search=n}),define("ace/keyboard/hash_handler",["require","exports","module","ace/lib/keys","ace/lib/useragent"],function(e,t,i){"use strict";function n(e,t){this.platform=t||(o.isMac?"mac":"win"),this.commands={},this.commandKeyBinding={},this.addCommands(e),this.$singleCommand=!0}function s(e,t){n.call(this,e,t),this.$singleCommand=!1}var a=e("../lib/keys"),o=e("../lib/useragent"),l=a.KEY_MODS;s.prototype=n.prototype,function(){function r(e){return"object"==typeof e&&e.bindKey&&e.bindKey.position||(e.isDefault?-100:0)}this.addCommand=function(e){this.commands[e.name]&&this.removeCommand(e),(this.commands[e.name]=e).bindKey&&this._buildKeyHash(e)},this.removeCommand=function(e,t){var i=e&&("string"==typeof e?e:e.name);e=this.commands[i],t||delete this.commands[i];var n=this.commandKeyBinding;for(var s in n){var o,r=n[s];r==e?delete n[s]:!Array.isArray(r)||-1!=(o=r.indexOf(e))&&(r.splice(o,1),1==r.length&&(n[s]=r[0]))}},this.bindKey=function(e,o,r){if("object"==typeof e&&e&&(null==r&&(r=e.position),e=e[this.platform]),e)return"function"==typeof o?this.addCommand({exec:o,bindKey:e,name:o.name||e}):void e.split("|").forEach(function(e){var t,n="";-1!=e.indexOf(" ")&&(e=(t=e.split(/\s+/)).pop(),t.forEach(function(e){var t=this.parseKeys(e),i=l[t.hashId]+t.key;n+=(n?" ":"")+i,this._addCommandToBinding(n,"chainKeys")},this),n+=" ");var i=this.parseKeys(e),s=l[i.hashId]+i.key;this._addCommandToBinding(n+s,o,r)},this)},this._addCommandToBinding=function(e,t,i){var n=this.commandKeyBinding;if(t)if(!n[e]||this.$singleCommand)n[e]=t;else{Array.isArray(n[e])?-1!=(o=n[e].indexOf(t))&&n[e].splice(o,1):n[e]=[n[e]],"number"!=typeof i&&(i=r(t));for(var s=n[e],o=0;os?s+1:s,e.selection.moveCursorTo(i.row,s))},multiSelectAction:"forEach",readOnly:!0},{name:"invertSelection",description:"Invert selection",bindKey:n(null,null),exec:function(e){var t=e.session.doc.getLength()-1,i=e.session.doc.getLine(t).length,n=e.selection.rangeList.ranges,s=[];n.length<1&&(n=[e.selection.getRange()]);for(var o=0;o=s.lastRow||n.end.row<=s.firstRow)&&this.renderer.scrollSelectionIntoView(this.selection.anchor,this.selection.lead)}"animate"==i&&this.renderer.animateScrolling(this.curOp.scrollTop)}var o=this.selection.toJSON();this.curOp.selectionAfter=o,this.$lastSel=this.selection.toJSON(),this.session.getUndoManager().addSelection(o),this.prevOp=this.curOp,this.curOp=null}},this.$mergeableCommands=["backspace","del","insertstring"],this.$historyTracker=function(e){var t,i,n,s;this.$mergeUndoDeltas&&(t=this.prevOp,i=this.$mergeableCommands,n=t.command&&e.command.name==t.command.name,"insertstring"==e.command.name?(s=e.args,void 0===this.mergeNextCommand&&(this.mergeNextCommand=!0),n=n&&this.mergeNextCommand&&(!/\s/.test(s)||/\s/.test(t.args)),this.mergeNextCommand=!0):n=n&&-1!==i.indexOf(e.command.name),"always"!=this.$mergeUndoDeltas&&2e3"===n.value&&r--),n&&0<=r;);else{do{if(n=a,a=i.stepBackward(),n)if(-1!==n.type.indexOf("tag-name"))s===n.value&&("<"===a.value?r++:""===n.value){for(var l=0,h=a;h;){if(-1!==h.type.indexOf("tag-name")&&h.value===s){r--;break}if("<"===h.value)break;h=i.stepBackward(),l++}for(var c=0;cu.search(/\S|$/)&&(s=u.substr(a.column).search(/\S|$/),o.doc.removeInLine(a.row,a.column,a.column+s))),this.clearSelection();var l,h=a.column,c=o.getState(a.row),u=o.getLine(a.row),d=r.checkOutdent(c,u,e);o.insert(a,e),i&&i.selection&&(2==i.selection.length?this.selection.setSelectionRange(new w(a.row,h+i.selection[0],a.row,h+i.selection[1])):this.selection.setSelectionRange(new w(a.row+i.selection[0],i.selection[1],a.row+i.selection[2],i.selection[3]))),this.$enableAutoIndent&&(o.getDocument().isNewLine(e)&&(l=r.getNextLineIndent(c,u.slice(0,a.column),o.getTabString()),o.insert({row:a.row+1,column:0},l)),d&&r.autoOutdent(c,o,a.row))},this.autoIndent=function(){var e,t,i,n=this.session,s=n.getMode();i=this.selection.isEmpty()?(t=0,n.doc.getLength()-1):(t=(e=this.getSelectionRange()).start.row,e.end.row);for(var o,r,a,l="",h="",c="",u=n.getTabString(),d=t;d<=i;d++)0t.toLowerCase()?1:0});for(var s=new w(0,0,0,0),n=e.first;n<=e.last;n++){var o=t.getLine(n);s.start.row=n,s.end.row=n,s.end.column=o.length,t.replace(s,i[n-e.first])}},this.toggleCommentLines=function(){var e=this.session.getState(this.getCursorPosition().row),t=this.$getSelectedRows();this.session.getMode().toggleCommentLines(e,this.session,t.first,t.last)},this.toggleBlockComment=function(){var e=this.getCursorPosition(),t=this.session.getState(e.row),i=this.getSelectionRange();this.session.getMode().toggleBlockComment(t,this.session,i,e)},this.getNumberAt=function(e,t){var i=/[\-]?[0-9]+(?:\.[0-9]+)?/g;i.lastIndex=0;for(var n=this.session.getLine(e);i.lastIndex=t)return{value:s[0],start:s.index,end:s.index+s[0].length}}return null},this.modifyNumber=function(e){var t,i,n,s,o,r,a=this.selection.getCursor().row,l=this.selection.getCursor().column,h=new w(a,l-1,a,l),c=this.session.getTextRange(h);!isNaN(parseFloat(c))&&isFinite(c)?(t=this.getNumberAt(a,l))&&(i=0<=t.value.indexOf(".")?t.start+t.value.indexOf(".")+1:t.end,n=t.start+t.value.length-i,s=parseFloat(t.value),s*=Math.pow(10,n),i!==t.end&&lg+1)break;g=f.last}for(c--,a=this.session.$moveLines(d,g,t?0:e),t&&-1==e&&(u=c+1);u<=c;)r[u].moveBy(a,0),u++;t||(a=0),l+=a}i.fromOrientedRange(i.ranges[0]),i.rangeList.attach(this.session),this.inVirtualSelectionMode=!1}},this.$getSelectedRows=function(e){return e=(e||this.getSelectionRange()).collapseRows(),{first:this.session.getRowFoldStart(e.start.row),last:this.session.getRowFoldEnd(e.end.row)}},this.onCompositionStart=function(e){this.renderer.showComposition(e)},this.onCompositionUpdate=function(e){this.renderer.setCompositionText(e)},this.onCompositionEnd=function(){this.renderer.hideComposition()},this.getFirstVisibleRow=function(){return this.renderer.getFirstVisibleRow()},this.getLastVisibleRow=function(){return this.renderer.getLastVisibleRow()},this.isRowVisible=function(e){return e>=this.getFirstVisibleRow()&&e<=this.getLastVisibleRow()},this.isRowFullyVisible=function(e){return e>=this.renderer.getFirstFullyVisibleRow()&&e<=this.renderer.getLastFullyVisibleRow()},this.$getVisibleRowCount=function(){return this.renderer.getScrollBottomRow()-this.renderer.getScrollTopRow()+1},this.$moveByPage=function(e,t){var i=this.renderer,n=this.renderer.layerConfig,s=e*Math.floor(n.height/n.lineHeight);!0===t?this.selection.$moveSelection(function(){this.moveCursorBy(s,0)}):!1===t&&(this.selection.moveCursorBy(s,0),this.selection.clearSelection());var o=i.scrollTop;i.scrollBy(0,s*n.lineHeight),null!=t&&i.scrollCursorIntoView(null,.5),i.animateScrolling(o)},this.selectPageDown=function(){this.$moveByPage(1,!0)},this.selectPageUp=function(){this.$moveByPage(-1,!0)},this.gotoPageDown=function(){this.$moveByPage(1,!1)},this.gotoPageUp=function(){this.$moveByPage(-1,!1)},this.scrollPageDown=function(){this.$moveByPage(1)},this.scrollPageUp=function(){this.$moveByPage(-1)},this.scrollToRow=function(e){this.renderer.scrollToRow(e)},this.scrollToLine=function(e,t,i,n){this.renderer.scrollToLine(e,t,i,n)},this.centerSelection=function(){var e=this.getSelectionRange(),t={row:Math.floor(e.start.row+(e.end.row-e.start.row)/2),column:Math.floor(e.start.column+(e.end.column-e.start.column)/2)};this.renderer.alignCursor(t,.5)},this.getCursorPosition=function(){return this.selection.getCursor()},this.getCursorPositionScreen=function(){return this.session.documentToScreenPosition(this.getCursorPosition())},this.getSelectionRange=function(){return this.selection.getRange()},this.selectAll=function(){this.selection.selectAll()},this.clearSelection=function(){this.selection.clearSelection()},this.moveCursorTo=function(e,t){this.selection.moveCursorTo(e,t)},this.moveCursorToPosition=function(e){this.selection.moveCursorToPosition(e)},this.jumpToMatching=function(e,t){var i=this.getCursorPosition(),n=new v(this.session,i.row,i.column),s=n.getCurrentToken(),o=s||n.stepForward();if(o){var r,a,l,h=!1,c={},u=i.column-o.start,d={")":"(","(":"(","]":"[","[":"[","{":"{","}":"{"};do{if(o.value.match(/[{}()\[\]]/g)){for(;uwindow.innerHeight)&&null)&&(a.style.top=n+"px",a.style.left=t.left+"px",a.style.height=i.lineHeight+"px",a.scrollIntoView(r)),r=s=null)}),this.setAutoScrollEditorIntoView=function(e){e||(delete this.setAutoScrollEditorIntoView,this.off("changeSelection",t),this.renderer.off("afterRender",n),this.renderer.off("beforeRender",i))})},this.$resetCursorStyle=function(){var e=this.$cursorStyle||"ace",t=this.renderer.$cursorLayer;t&&(t.setSmoothBlinking(/smooth/.test(e)),t.isBlinking=!this.$readOnly&&"wide"!=e,n.setCssClass(t.element,"ace_slim-cursors",/slim/.test(e)))},this.prompt=function(t,i,n){var s=this;m.loadModule("./ext/prompt",function(e){e.prompt(s,t,i,n)})}}.call(b.prototype),m.defineOptions(b.prototype,"editor",{selectionStyle:{set:function(e){this.onSelectionChange(),this._signal("changeSelectionStyle",{data:e})},initialValue:"line"},highlightActiveLine:{set:function(){this.$updateHighlightActiveLine()},initialValue:!0},highlightSelectedWord:{set:function(e){this.$onSelectionChange()},initialValue:!0},readOnly:{set:function(e){this.textInput.setReadOnly(e),this.$resetCursorStyle()},initialValue:!1},copyWithEmptySelection:{set:function(e){this.textInput.setCopyWithEmptySelection(e)},initialValue:!1},cursorStyle:{set:function(e){this.$resetCursorStyle()},values:["ace","slim","smooth","wide"],initialValue:"ace"},mergeUndoDeltas:{values:[!1,!0,"always"],initialValue:!0},behavioursEnabled:{initialValue:!0},wrapBehavioursEnabled:{initialValue:!0},enableAutoIndent:{initialValue:!0},autoScrollEditorIntoView:{set:function(e){this.setAutoScrollEditorIntoView(e)}},keyboardHandler:{set:function(e){this.setKeyboardHandler(e)},get:function(){return this.$keybindingId},handlesSet:!0},value:{set:function(e){this.session.setValue(e)},get:function(){return this.getValue()},handlesSet:!0,hidden:!0},session:{set:function(e){this.setSession(e)},get:function(){return this.session},handlesSet:!0,hidden:!0},showLineNumbers:{set:function(e){this.renderer.$gutterLayer.setShowLineNumbers(e),this.renderer.$loop.schedule(this.renderer.CHANGE_GUTTER),e&&this.$relativeLineNumbers?y.attach(this):y.detach(this)},initialValue:!0},relativeLineNumbers:{set:function(e){this.$showLineNumbers&&e?y.attach(this):y.detach(this)}},placeholder:{set:function(e){this.$updatePlaceholder||(this.$updatePlaceholder=function(){var e,t=this.session&&(this.renderer.$composition||this.getValue());t&&this.renderer.placeholderNode?(this.renderer.off("afterRender",this.$updatePlaceholder),n.removeCssClass(this.container,"ace_hasPlaceholder"),this.renderer.placeholderNode.remove(),this.renderer.placeholderNode=null):t||this.renderer.placeholderNode?!t&&this.renderer.placeholderNode&&(this.renderer.placeholderNode.textContent=this.$placeholder||""):(this.renderer.on("afterRender",this.$updatePlaceholder),n.addCssClass(this.container,"ace_hasPlaceholder"),(e=n.createElement("div")).className="ace_placeholder",e.textContent=this.$placeholder||"",this.renderer.placeholderNode=e,this.renderer.content.appendChild(this.renderer.placeholderNode))}.bind(this),this.on("input",this.$updatePlaceholder)),this.$updatePlaceholder()}},hScrollBarAlwaysVisible:"renderer",vScrollBarAlwaysVisible:"renderer",highlightGutterLine:"renderer",animatedScroll:"renderer",showInvisibles:"renderer",showPrintMargin:"renderer",printMarginColumn:"renderer",printMargin:"renderer",fadeFoldWidgets:"renderer",showFoldWidgets:"renderer",displayIndentGuides:"renderer",showGutter:"renderer",fontSize:"renderer",fontFamily:"renderer",maxLines:"renderer",minLines:"renderer",scrollPastEnd:"renderer",fixedWidthGutter:"renderer",theme:"renderer",hasCssTransforms:"renderer",maxPixelHeight:"renderer",useTextareaForIME:"renderer",scrollSpeed:"$mouseHandler",dragDelay:"$mouseHandler",dragEnabled:"$mouseHandler",focusTimeout:"$mouseHandler",tooltipFollowsMouse:"$mouseHandler",firstLineNumber:"session",overwrite:"session",newLineMode:"session",useWorker:"session",useSoftTabs:"session",navigateWithinSoftTabs:"session",tabSize:"session",wrap:"session",indentedSoftWrap:"session",foldStyle:"session",mode:"session"});var y={getText:function(e,t){return(Math.abs(e.selection.lead.row-t)||t+1+(t<9?"Β·":""))+""},getWidth:function(e,t,i){return Math.max(t.toString().length,(i.lastRow+1).toString().length,2)*i.characterWidth},update:function(e,t){t.renderer.$loop.schedule(t.renderer.CHANGE_GUTTER)},attach:function(e){e.renderer.$gutterLayer.$renderer=this,e.on("changeSelection",this.update),this.update(null,e)},detach:function(e){e.renderer.$gutterLayer.$renderer==this&&(e.renderer.$gutterLayer.$renderer=null),e.off("changeSelection",this.update),this.update(null,e)}};t.Editor=b}),define("ace/undomanager",["require","exports","module","ace/range"],function(e,t,i){"use strict";function a(e){return{row:e.row,column:e.column}}function n(e){if(e=e||this,Array.isArray(e))return e.map(n).join("\n");var t="";return e.action?(t="insert"==e.action?"+":"-",t+="["+e.lines+"]"):e.value&&(t=Array.isArray(e.value)?e.value.map(s).join("\n"):s(e.value)),e.start&&(t+=s(e)),(e.id||e.rev)&&(t+="\t("+(e.id||e.rev)+")"),t}function s(e){return e.start.row+":"+e.start.column+"=>"+e.end.row+":"+e.end.column}function o(e,t){var i="insert"==e.action,n="insert"==t.action;if(i&&n)if(0<=m(t.start,e.end))h(t,e,-1);else{if(!(m(t.start,e.start)<=0))return;h(e,t,1)}else if(i&&!n)if(0<=m(t.start,e.end))h(t,e,-1);else{if(!(m(t.end,e.start)<=0))return;h(e,t,-1)}else if(!i&&n)if(0<=m(t.start,e.start))h(t,e,1);else{if(!(m(t.start,e.start)<=0))return;h(e,t,1)}else if(!i&&!n)if(0<=m(t.start,e.start))h(t,e,1);else{if(!(m(t.end,e.start)<=0))return;h(e,t,-1)}return 1}function r(e,t){for(var i=e.length;i--;)for(var n=0;na+1;)this.$lines.pop();break}(r=this.$lines.get(++a))?r.row=l:(r=this.$lines.createCell(l,e,this.session,h),this.$lines.push(r)),this.$renderCell(r,e,s,l),l++}this._signal("afterRender"),this.$updateGutterWidth(e)},this.$updateGutterWidth=function(e){var t=this.session,i=t.gutterRenderer||this.$renderer,n=t.$firstLineNumber,s=this.$lines.last()?this.$lines.last().text:"";(this.$fixedWidth||t.$useWrapMode)&&(s=t.getLength()+n-1);var o=i?i.getWidth(t,s,e):s.toString().length*e.characterWidth,r=this.$padding||this.$computePadding();(o+=r.left+r.right)===this.gutterWidth||isNaN(o)||(this.gutterWidth=o,this.element.parentNode.style.width=this.element.style.width=Math.ceil(this.gutterWidth)+"px",this._signal("changeGutterWidth",o))},this.$updateCursorRow=function(){var e;this.$highlightGutterLine&&(e=this.session.selection.getCursor(),this.$cursorRow!==e.row&&(this.$cursorRow=e.row))},this.updateLineHighlight=function(){if(this.$highlightGutterLine){var e=this.session.selection.cursor.row;if(this.$cursorRow=e,!this.$cursorCell||this.$cursorCell.row!=e){this.$cursorCell&&(this.$cursorCell.element.className=this.$cursorCell.element.className.replace("ace_gutter-active-line ",""));var t=this.$lines.cells;this.$cursorCell=null;for(var i=0;i=this.$cursorRow){if(n.row>this.$cursorRow){var s=this.session.getFoldLine(this.$cursorRow);if(!(0i.right-t.right?"foldWidgets":void 0}}).call(n.prototype),t.Gutter=n}),define("ace/layer/marker",["require","exports","module","ace/range","ace/lib/dom"],function(e,t,i){"use strict";function n(e){this.element=s.createElement("div"),this.element.className="ace_layer ace_marker-layer",e.appendChild(this.element)}var g=e("../range").Range,s=e("../lib/dom");(function(){this.$padding=0,this.setPadding=function(e){this.$padding=e},this.setSession=function(e){this.session=e},this.setMarkers=function(e){this.markers=e},this.elt=function(e,t){var i=-1!=this.i&&this.element.childNodes[this.i];i?this.i++:(i=document.createElement("div"),this.element.appendChild(i),this.i=-1),i.style.cssText=t,i.className=e},this.update=function(e){if(e){var t;for(var i in this.config=e,this.i=0,this.markers){var n,s,o,r=this.markers[i];r.range?(o=r.range.clipRows(e.firstRow,e.lastRow)).isEmpty()||(o=o.toScreenRange(this.session),r.renderer?(n=this.$getTop(o.start.row,e),s=this.$padding+o.start.column*e.characterWidth,r.renderer(t,o,s,n,e)):"fullLine"==r.type?this.drawFullLineMarker(t,o,r.clazz,e):"screenLine"==r.type?this.drawScreenLineMarker(t,o,r.clazz,e):o.isMultiLine()?"text"==r.type?this.drawTextMarker(t,o,r.clazz,e):this.drawMultiLineMarker(t,o,r.clazz,e):this.drawSingleLineMarker(t,o,r.clazz+" ace_start ace_br15",e)):r.update(t,this,this.session,e)}if(-1!=this.i)for(;this.ie.lastRow)for(s=this.session.getFoldedRowCount(e.lastRow+1,t.lastRow);0t.lastRow&&this.$lines.push(this.$renderLinesFragment(e,t.lastRow+1,e.lastRow))},this.$renderLinesFragment=function(e,t,i){for(var n=[],s=t,o=this.session.getNextFoldLine(s),r=o?o.start.row:1/0;r=o;)r=this.$renderToken(a,r,h,c.substring(0,o-n)),c=c.substring(o-n),n=o,a=this.$createLineElement(),e.appendChild(a),a.appendChild(this.dom.createTextNode(v.stringRepeat("Β ",i.indent),this.element)),r=0,o=i[++s]||Number.MAX_VALUE;0!=c.length&&(n+=c.length,r=this.$renderToken(a,r,h,c))}}i[i.length-1]>this.MAX_LINE_LENGTH&&this.$renderOverflowMessage(a,r,null,"",!0)},this.$renderSimpleLine=function(e,t){var i=0,n=t[0],s=n.value;this.displayIndentGuides&&(s=this.renderIndentGuide(e,s)),s&&(i=this.$renderToken(e,i,n,s));for(var o=1;othis.MAX_LINE_LENGTH)return this.$renderOverflowMessage(e,i,n,s);i=this.$renderToken(e,i,n,s)}},this.$renderOverflowMessage=function(e,t,i,n,s){i&&this.$renderToken(e,t,i,n.slice(0,this.MAX_LINE_LENGTH-t));var o=this.dom.createElement("span");o.className="ace_inline_button ace_keyword ace_toggle_wrap",o.textContent=s?"":"",e.appendChild(o)},this.$renderLine=function(e,t,i){var n;i||0==i||(i=this.session.getFoldLine(t));var s,o,r=e;(n=i?this.$getFoldLineTokens(t,i):this.session.getTokens(t)).length?(s=this.session.getRowSplitData(t))&&s.length?(this.$renderWrappedLine(e,n,s),r=e.lastChild):(r=e,this.$useLineGroups()&&(r=this.$createLineElement(),e.appendChild(r)),this.$renderSimpleLine(r,n)):this.$useLineGroups()&&(r=this.$createLineElement(),e.appendChild(r)),this.showEOL&&r&&(i&&(t=i.end.row),(o=this.dom.createElement("span")).className="ace_invisible ace_invisible_eol",o.textContent=t==this.session.getLength()-1?this.EOF_CHAR:this.EOL_CHAR,r.appendChild(o))},this.$getFoldLineTokens=function(e,t){var o=this.session,r=[],a=o.getTokens(e);return t.walk(function(e,t,i,n,s){null!=e?r.push({type:"fold",value:e}):(s&&(a=o.getTokens(t)),a.length&&function(e,t,i){for(var n,s=0,o=0;o+e[s].value.lengthi-t&&(n=n.substring(0,i-t)),r.push({type:e[s].type,value:n}),o=t+n.length,s+=1);oi?r.push({type:e[s].type,value:n.substring(0,i-o)}):r.push(e[s]),o+=n.length,s+=1}}(a,n,i))},t.end.row,this.session.getLine(t.end.row).length),r},this.$useLineGroups=function(){return this.session.getUseWrapMode()},this.destroy=function(){}}).call(n.prototype),t.Text=n}),define("ace/layer/cursor",["require","exports","module","ace/lib/dom"],function(e,t,i){"use strict";function n(e){this.element=h.createElement("div"),this.element.className="ace_layer ace_cursor-layer",e.appendChild(this.element),this.isVisible=!1,this.isBlinking=!0,this.blinkInterval=1e3,this.smoothBlinking=!1,this.cursors=[],this.cursor=this.addCursor(),h.addCssClass(this.element,"ace_hidden-cursors"),this.$updateCursors=this.$updateOpacity.bind(this)}var h=e("../lib/dom");(function(){this.$updateOpacity=function(e){for(var t=this.cursors,i=t.length;i--;)h.setStyle(t[i].style,"opacity",e?"":"0")},this.$startCssAnimation=function(){for(var e=this.cursors,t=e.length;t--;)e[t].style.animationDuration=this.blinkInterval+"ms";setTimeout(function(){h.addCssClass(this.element,"ace_animate-blinking")}.bind(this))},this.$stopCssAnimation=function(){h.removeCssClass(this.element,"ace_animate-blinking")},this.$padding=0,this.setPadding=function(e){this.$padding=e},this.setSession=function(e){this.session=e},this.setBlinking=function(e){e!=this.isBlinking&&(this.isBlinking=e,this.restartTimer())},this.setBlinkInterval=function(e){e!=this.blinkInterval&&(this.blinkInterval=e,this.restartTimer())},this.setSmoothBlinking=function(e){e!=this.smoothBlinking&&(this.smoothBlinking=e,h.setCssClass(this.element,"ace_smooth-blinking",e),this.$updateCursors(!0),this.restartTimer())},this.addCursor=function(){var e=h.createElement("div");return e.className="ace_cursor",this.element.appendChild(e),this.cursors.push(e),e},this.removeCursor=function(){if(1e.height+e.offset||a.top<0)&&1n;)this.removeCursor();var l=this.session.getOverwrite();this.$setOverwrite(l),this.$pixelPos=a,this.restartTimer()},this.drawCursor=null,this.$setOverwrite=function(e){e!=this.overwrite&&((this.overwrite=e)?h.addCssClass(this.element,"ace_overwrite-cursors"):h.removeCssClass(this.element,"ace_overwrite-cursors"))},this.destroy=function(){clearInterval(this.intervalId),clearTimeout(this.timeoutId)}}).call(n.prototype),t.Cursor=n}),define("ace/scrollbar",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/event","ace/lib/event_emitter"],function(e,t,i){"use strict";function n(e){this.element=o.createElement("div"),this.element.className="ace_scrollbar ace_scrollbar"+this.classSuffix,this.inner=o.createElement("div"),this.inner.className="ace_scrollbar-inner",this.inner.textContent="Β ",this.element.appendChild(this.inner),e.appendChild(this.element),this.setVisible(!1),this.skipEvent=!1,r.addListener(this.element,"scroll",this.onScroll.bind(this)),r.addListener(this.element,"mousedown",r.preventDefault)}var s=e("./lib/oop"),o=e("./lib/dom"),r=e("./lib/event"),a=e("./lib/event_emitter").EventEmitter;(function(){s.implement(this,a),this.setVisible=function(e){this.element.style.display=e?"":"none",this.isVisible=e,this.coeff=1}}).call(n.prototype);function l(e,t){n.call(this,e),this.scrollTop=0,this.scrollHeight=0,t.$scrollbarWidth=this.width=o.scrollbarWidth(e.ownerDocument),this.inner.style.width=this.element.style.width=(this.width||15)+5+"px",this.$minWidth=0}s.inherits(l,n),function(){this.classSuffix="-v",this.onScroll=function(){var e;this.skipEvent||(this.scrollTop=this.element.scrollTop,1!=this.coeff&&(e=this.element.clientHeight/this.scrollHeight,this.scrollTop=this.scrollTop*(1-e)/(this.coeff-e)),this._emit("scroll",{data:this.scrollTop})),this.skipEvent=!1},this.getWidth=function(){return Math.max(this.isVisible?this.width:0,this.$minWidth||0)},this.setHeight=function(e){this.element.style.height=e+"px"},this.setInnerHeight=this.setScrollHeight=function(e){32768<(this.scrollHeight=e)?(this.coeff=32768/e,e=32768):1!=this.coeff&&(this.coeff=1),this.inner.style.height=e+"px"},this.setScrollTop=function(e){this.scrollTop!=e&&(this.skipEvent=!0,this.scrollTop=e,this.element.scrollTop=e*this.coeff)}}.call(l.prototype);function h(e,t){n.call(this,e),this.scrollLeft=0,this.height=t.$scrollbarWidth,this.inner.style.height=this.element.style.height=(this.height||15)+5+"px"}s.inherits(h,n),function(){this.classSuffix="-h",this.onScroll=function(){this.skipEvent||(this.scrollLeft=this.element.scrollLeft,this._emit("scroll",{data:this.scrollLeft})),this.skipEvent=!1},this.getHeight=function(){return this.isVisible?this.height:0},this.setWidth=function(e){this.element.style.width=e+"px"},this.setInnerWidth=function(e){this.inner.style.width=e+"px"},this.setScrollWidth=function(e){this.inner.style.width=e+"px"},this.setScrollLeft=function(e){this.scrollLeft!=e&&(this.skipEvent=!0,this.scrollLeft=this.element.scrollLeft=e)}}.call(h.prototype),t.ScrollBar=l,t.ScrollBarV=l,t.ScrollBarH=h,t.VScrollBar=l,t.HScrollBar=h}),define("ace/renderloop",["require","exports","module","ace/lib/event"],function(e,t,i){"use strict";function n(e,t){this.onRender=e,this.pending=!1,this.changes=0,this.$recursionLimit=2,this.window=t||window;var i=this;this._flush=function(e){i.pending=!1;var t=i.changes;if(t&&(s.blockIdle(100),i.changes=0,i.onRender(t)),i.changes){if(i.$recursionLimit--<0)return;i.schedule()}else i.$recursionLimit=2}}var s=e("./lib/event");(function(){this.schedule=function(e){this.changes=this.changes|e,this.changes&&!this.pending&&(s.nextFrame(this._flush),this.pending=!0)},this.clear=function(e){var t=this.changes;return this.changes=0,t}}).call(n.prototype),t.RenderLoop=n}),define("ace/layer/font_metrics",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/event","ace/lib/useragent","ace/lib/event_emitter"],function(e,t,i){var n=e("../lib/oop"),s=e("../lib/dom"),o=e("../lib/lang"),r=e("../lib/event"),a=e("../lib/useragent"),l=e("../lib/event_emitter").EventEmitter,h="function"==typeof ResizeObserver,c=t.FontMetrics=function(e){this.el=s.createElement("div"),this.$setMeasureNodeStyles(this.el.style,!0),this.$main=s.createElement("div"),this.$setMeasureNodeStyles(this.$main.style),this.$measureNode=s.createElement("div"),this.$setMeasureNodeStyles(this.$measureNode.style),this.el.appendChild(this.$main),this.el.appendChild(this.$measureNode),e.appendChild(this.el),this.$measureNode.textContent=o.stringRepeat("X",256),this.$characterSize={width:0,height:0},h?this.$addObserver():this.checkForSizeChanges()};(function(){n.implement(this,l),this.$characterSize={width:0,height:0},this.$setMeasureNodeStyles=function(e,t){e.width=e.height="auto",e.left=e.top="0px",e.visibility="hidden",e.position="absolute",e.whiteSpace="pre",a.isIE<8?e["font-family"]="inherit":e.font="inherit",e.overflow=t?"hidden":"visible"},this.checkForSizeChanges=function(e){var t;void 0===e&&(e=this.$measureSizes()),!e||this.$characterSize.width===e.width&&this.$characterSize.height===e.height||(this.$measureNode.style.fontWeight="bold",t=this.$measureSizes(),this.$measureNode.style.fontWeight="",this.$characterSize=e,this.charSizes=Object.create(null),this.allowBoldFonts=t&&t.width===e.width&&t.height===e.height,this._emit("changeCharacterSize",{data:e}))},this.$addObserver=function(){var t=this;this.$observer=new window.ResizeObserver(function(e){t.checkForSizeChanges()}),this.$observer.observe(this.$measureNode)},this.$pollSizeChanges=function(){if(this.$pollSizeChangesTimer||this.$observer)return this.$pollSizeChangesTimer;var t=this;return this.$pollSizeChangesTimer=r.onIdle(function e(){t.checkForSizeChanges(),r.onIdle(e,500)},500)},this.setPolling=function(e){e?this.$pollSizeChanges():this.$pollSizeChangesTimer&&(clearInterval(this.$pollSizeChangesTimer),this.$pollSizeChangesTimer=0)},this.$measureSizes=function(e){var t={height:(e||this.$measureNode).clientHeight,width:(e||this.$measureNode).clientWidth/256};return 0===t.width||0===t.height?null:t},this.$measureCharWidth=function(e){return this.$main.textContent=o.stringRepeat(e,256),this.$main.getBoundingClientRect().width/256},this.getCharacterWidth=function(e){var t=this.charSizes[e];return void 0===t&&(t=this.charSizes[e]=this.$measureCharWidth(e)/this.$characterSize.width),t},this.destroy=function(){clearInterval(this.$pollSizeChangesTimer),this.$observer&&this.$observer.disconnect(),this.el&&this.el.parentNode&&this.el.parentNode.removeChild(this.el)},this.$getZoom=function e(t){return t&&t.parentElement?(window.getComputedStyle(t).zoom||1)*e(t.parentElement):1},this.$initTransformMeasureNodes=function(){function e(e,t){return["div",{style:"position: absolute;top:"+e+"px;left:"+t+"px;"}]}this.els=s.buildDom([e(0,0),e(200,0),e(0,200),e(200,200)],this.el)},this.transformCoordinates=function(e,t){function i(e,t,i){var n=e[1]*t[0]-e[0]*t[1];return[(-t[1]*i[0]+t[0]*i[1])/n,(e[1]*i[0]-e[0]*i[1])/n]}function n(e,t){return[e[0]-t[0],e[1]-t[1]]}function s(e,t){return[e[0]+t[0],e[1]+t[1]]}function o(e,t){return[e*t[0],e*t[1]]}function r(e){var t=e.getBoundingClientRect();return[t.left,t.top]}e=e&&o(1/this.$getZoom(this.el),e),this.els||this.$initTransformMeasureNodes();var a=r(this.els[0]),l=r(this.els[1]),h=r(this.els[2]),c=r(this.els[3]),u=i(n(c,l),n(c,h),n(s(l,h),s(c,a))),d=o(1+u[0],n(l,a)),g=o(1+u[1],n(h,a));if(t){var f=u[0]*t[0]/200+u[1]*t[1]/200+1,m=s(o(t[0],d),o(t[1],g));return s(o(1/f/200,m),a)}var p=n(e,a),w=i(n(d,o(u[0],p)),n(g,o(u[1],p)),p);return o(200,w)}}).call(c.prototype)}),define("ace/virtual_renderer",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/config","ace/layer/gutter","ace/layer/marker","ace/layer/text","ace/layer/cursor","ace/scrollbar","ace/scrollbar","ace/renderloop","ace/layer/font_metrics","ace/lib/event_emitter","ace/lib/useragent"],function(e,t,i){"use strict";var n=e("./lib/oop"),c=e("./lib/dom"),o=e("./config"),s=e("./layer/gutter").Gutter,r=e("./layer/marker").Marker,a=e("./layer/text").Text,l=e("./layer/cursor").Cursor,h=e("./scrollbar").HScrollBar,u=e("./scrollbar").VScrollBar,d=e("./renderloop").RenderLoop,g=e("./layer/font_metrics").FontMetrics,f=e("./lib/event_emitter").EventEmitter,m='.ace_br1 {border-top-left-radius : 3px;}.ace_br2 {border-top-right-radius : 3px;}.ace_br3 {border-top-left-radius : 3px; border-top-right-radius: 3px;}.ace_br4 {border-bottom-right-radius: 3px;}.ace_br5 {border-top-left-radius : 3px; border-bottom-right-radius: 3px;}.ace_br6 {border-top-right-radius : 3px; border-bottom-right-radius: 3px;}.ace_br7 {border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px;}.ace_br8 {border-bottom-left-radius : 3px;}.ace_br9 {border-top-left-radius : 3px; border-bottom-left-radius: 3px;}.ace_br10{border-top-right-radius : 3px; border-bottom-left-radius: 3px;}.ace_br11{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br12{border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br13{border-top-left-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br14{border-top-right-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br15{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_editor {position: relative;overflow: hidden;padding: 0;font: 12px/normal \'Monaco\', \'Menlo\', \'Ubuntu Mono\', \'Consolas\', \'source-code-pro\', monospace;direction: ltr;text-align: left;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}.ace_scroller {position: absolute;overflow: hidden;top: 0;bottom: 0;background-color: inherit;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;cursor: text;}.ace_content {position: absolute;box-sizing: border-box;min-width: 100%;contain: style size layout;font-variant-ligatures: no-common-ligatures;}.ace_dragging .ace_scroller:before{position: absolute;top: 0;left: 0;right: 0;bottom: 0;content: \'\';background: rgba(250, 250, 250, 0.01);z-index: 1000;}.ace_dragging.ace_dark .ace_scroller:before{background: rgba(0, 0, 0, 0.01);}.ace_selecting, .ace_selecting * {cursor: text !important;}.ace_gutter {position: absolute;overflow : hidden;width: auto;top: 0;bottom: 0;left: 0;cursor: default;z-index: 4;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;contain: style size layout;}.ace_gutter-active-line {position: absolute;left: 0;right: 0;}.ace_scroller.ace_scroll-left {box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;}.ace_gutter-cell {position: absolute;top: 0;left: 0;right: 0;padding-left: 19px;padding-right: 6px;background-repeat: no-repeat;}.ace_gutter-cell.ace_error {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg==");background-repeat: no-repeat;background-position: 2px center;}.ace_gutter-cell.ace_warning {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ4p3h2hTf4t3k3ucyrN1K5+Xaks52Sfs9CXgrAAAAjklEQVR42o3PbQ+CIBQFYEwboPhSYgoYunIqqLn6/z8uYdH8Vmdnu9vz4WwXgN/xTPRD2+sgOcZjsge/whXZgUaYYvT8QnuJaUrjrHUQreGczuEafQCO/SJTufTbroWsPgsllVhq3wJEk2jUSzX3CUEDJC84707djRc5MTAQxoLgupWRwW6UB5fS++NV8AbOZgnsC7BpEAAAAABJRU5ErkJggg==");background-position: 2px center;}.ace_gutter-cell.ace_info {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAJ0Uk5TAAB2k804AAAAPklEQVQY02NgIB68QuO3tiLznjAwpKTgNyDbMegwisCHZUETUZV0ZqOquBpXj2rtnpSJT1AEnnRmL2OgGgAAIKkRQap2htgAAAAASUVORK5CYII=");background-position: 2px center;}.ace_dark .ace_gutter-cell.ace_info {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC");}.ace_scrollbar {contain: strict;position: absolute;right: 0;bottom: 0;z-index: 6;}.ace_scrollbar-inner {position: absolute;cursor: text;left: 0;top: 0;}.ace_scrollbar-v{overflow-x: hidden;overflow-y: scroll;top: 0;}.ace_scrollbar-h {overflow-x: scroll;overflow-y: hidden;left: 0;}.ace_print-margin {position: absolute;height: 100%;}.ace_text-input {position: absolute;z-index: 0;width: 0.5em;height: 1em;opacity: 0;background: transparent;-moz-appearance: none;appearance: none;border: none;resize: none;outline: none;overflow: hidden;font: inherit;padding: 0 1px;margin: 0 -1px;contain: strict;-ms-user-select: text;-moz-user-select: text;-webkit-user-select: text;user-select: text;white-space: pre!important;}.ace_text-input.ace_composition {background: transparent;color: inherit;z-index: 1000;opacity: 1;}.ace_composition_placeholder { color: transparent }.ace_composition_marker { border-bottom: 1px solid;position: absolute;border-radius: 0;margin-top: 1px;}[ace_nocontext=true] {transform: none!important;filter: none!important;clip-path: none!important;mask : none!important;contain: none!important;perspective: none!important;mix-blend-mode: initial!important;z-index: auto;}.ace_layer {z-index: 1;position: absolute;overflow: hidden;word-wrap: normal;white-space: pre;height: 100%;width: 100%;box-sizing: border-box;pointer-events: none;}.ace_gutter-layer {position: relative;width: auto;text-align: right;pointer-events: auto;height: 1000000px;contain: style size layout;}.ace_text-layer {font: inherit !important;position: absolute;height: 1000000px;width: 1000000px;contain: style size layout;}.ace_text-layer > .ace_line, .ace_text-layer > .ace_line_group {contain: style size layout;position: absolute;top: 0;left: 0;right: 0;}.ace_hidpi .ace_text-layer,.ace_hidpi .ace_gutter-layer,.ace_hidpi .ace_content,.ace_hidpi .ace_gutter {contain: strict;will-change: transform;}.ace_hidpi .ace_text-layer > .ace_line, .ace_hidpi .ace_text-layer > .ace_line_group {contain: strict;}.ace_cjk {display: inline-block;text-align: center;}.ace_cursor-layer {z-index: 4;}.ace_cursor {z-index: 4;position: absolute;box-sizing: border-box;border-left: 2px solid;transform: translatez(0);}.ace_multiselect .ace_cursor {border-left-width: 1px;}.ace_slim-cursors .ace_cursor {border-left-width: 1px;}.ace_overwrite-cursors .ace_cursor {border-left-width: 0;border-bottom: 1px solid;}.ace_hidden-cursors .ace_cursor {opacity: 0.2;}.ace_hasPlaceholder .ace_hidden-cursors .ace_cursor {opacity: 0;}.ace_smooth-blinking .ace_cursor {transition: opacity 0.18s;}.ace_animate-blinking .ace_cursor {animation-duration: 1000ms;animation-timing-function: step-end;animation-name: blink-ace-animate;animation-iteration-count: infinite;}.ace_animate-blinking.ace_smooth-blinking .ace_cursor {animation-duration: 1000ms;animation-timing-function: ease-in-out;animation-name: blink-ace-animate-smooth;}@keyframes blink-ace-animate {from, to { opacity: 1; }60% { opacity: 0; }}@keyframes blink-ace-animate-smooth {from, to { opacity: 1; }45% { opacity: 1; }60% { opacity: 0; }85% { opacity: 0; }}.ace_marker-layer .ace_step, .ace_marker-layer .ace_stack {position: absolute;z-index: 3;}.ace_marker-layer .ace_selection {position: absolute;z-index: 5;}.ace_marker-layer .ace_bracket {position: absolute;z-index: 6;}.ace_marker-layer .ace_error_bracket {position: absolute;border-bottom: 1px solid #DE5555;border-radius: 0;}.ace_marker-layer .ace_active-line {position: absolute;z-index: 2;}.ace_marker-layer .ace_selected-word {position: absolute;z-index: 4;box-sizing: border-box;}.ace_line .ace_fold {box-sizing: border-box;display: inline-block;height: 11px;margin-top: -2px;vertical-align: middle;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="),url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi+P//fxgTAwPDBxDxD078RSX+YeEyDFMCIMAAI3INmXiwf2YAAAAASUVORK5CYII=");background-repeat: no-repeat, repeat-x;background-position: center center, top left;color: transparent;border: 1px solid black;border-radius: 2px;cursor: pointer;pointer-events: auto;}.ace_dark .ace_fold {}.ace_fold:hover{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="),url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACBJREFUeNpi+P//fz4TAwPDZxDxD5X4i5fLMEwJgAADAEPVDbjNw87ZAAAAAElFTkSuQmCC");}.ace_tooltip {background-color: #FFF;background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.1));border: 1px solid gray;border-radius: 1px;box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);color: black;max-width: 100%;padding: 3px 4px;position: fixed;z-index: 999999;box-sizing: border-box;cursor: default;white-space: pre;word-wrap: break-word;line-height: normal;font-style: normal;font-weight: normal;letter-spacing: normal;pointer-events: none;}.ace_folding-enabled > .ace_gutter-cell {padding-right: 13px;}.ace_fold-widget {box-sizing: border-box;margin: 0 -12px 0 1px;display: none;width: 11px;vertical-align: top;background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg==");background-repeat: no-repeat;background-position: center;border-radius: 3px;border: 1px solid transparent;cursor: pointer;}.ace_folding-enabled .ace_fold-widget {display: inline-block; }.ace_fold-widget.ace_end {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42m3HwQkAMAhD0YzsRchFKI7sAikeWkrxwScEB0nh5e7KTPWimZki4tYfVbX+MNl4pyZXejUO1QAAAABJRU5ErkJggg==");}.ace_fold-widget.ace_closed {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAGCAYAAAAG5SQMAAAAOUlEQVR42jXKwQkAMAgDwKwqKD4EwQ26sSOkVWjgIIHAzPiCgaqiqnJHZnKICBERHN194O5b9vbLuAVRL+l0YWnZAAAAAElFTkSuQmCCXA==");}.ace_fold-widget:hover {border: 1px solid rgba(0, 0, 0, 0.3);background-color: rgba(255, 255, 255, 0.2);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);}.ace_fold-widget:active {border: 1px solid rgba(0, 0, 0, 0.4);background-color: rgba(0, 0, 0, 0.05);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);}.ace_dark .ace_fold-widget {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC");}.ace_dark .ace_fold-widget.ace_end {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==");}.ace_dark .ace_fold-widget.ace_closed {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg==");}.ace_dark .ace_fold-widget:hover {box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);background-color: rgba(255, 255, 255, 0.1);}.ace_dark .ace_fold-widget:active {box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);}.ace_inline_button {border: 1px solid lightgray;display: inline-block;margin: -1px 8px;padding: 0 5px;pointer-events: auto;cursor: pointer;}.ace_inline_button:hover {border-color: gray;background: rgba(200,200,200,0.2);display: inline-block;pointer-events: auto;}.ace_fold-widget.ace_invalid {background-color: #FFB4B4;border-color: #DE5555;}.ace_fade-fold-widgets .ace_fold-widget {transition: opacity 0.4s ease 0.05s;opacity: 0;}.ace_fade-fold-widgets:hover .ace_fold-widget {transition: opacity 0.05s ease 0.05s;opacity:1;}.ace_underline {text-decoration: underline;}.ace_bold {font-weight: bold;}.ace_nobold .ace_bold {font-weight: normal;}.ace_italic {font-style: italic;}.ace_error-marker {background-color: rgba(255, 0, 0,0.2);position: absolute;z-index: 9;}.ace_highlight-marker {background-color: rgba(255, 255, 0,0.2);position: absolute;z-index: 8;}.ace_mobile-menu {position: absolute;line-height: 1.5;border-radius: 4px;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;background: white;box-shadow: 1px 3px 2px grey;border: 1px solid #dcdcdc;color: black;}.ace_dark > .ace_mobile-menu {background: #333;color: #ccc;box-shadow: 1px 3px 2px grey;border: 1px solid #444;}.ace_mobile-button {padding: 2px;cursor: pointer;overflow: hidden;}.ace_mobile-button:hover {background-color: #eee;opacity:1;}.ace_mobile-button:active {background-color: #ddd;}.ace_placeholder {font-family: arial;transform: scale(0.9);transform-origin: left;white-space: pre;opacity: 0.7;margin: 0 10px;}',p=e("./lib/useragent"),w=p.isIE;c.importCssString(m,"ace_editor.css");function v(e,t){var i=this;this.container=e||c.createElement("div"),c.addCssClass(this.container,"ace_editor"),c.HI_DPI&&c.addCssClass(this.container,"ace_hidpi"),this.setTheme(t),this.$gutter=c.createElement("div"),this.$gutter.className="ace_gutter",this.container.appendChild(this.$gutter),this.$gutter.setAttribute("aria-hidden",!0),this.scroller=c.createElement("div"),this.scroller.className="ace_scroller",this.container.appendChild(this.scroller),this.content=c.createElement("div"),this.content.className="ace_content",this.scroller.appendChild(this.content),this.$gutterLayer=new s(this.$gutter),this.$gutterLayer.on("changeGutterWidth",this.onGutterResize.bind(this)),this.$markerBack=new r(this.content);var n=this.$textLayer=new a(this.content);this.canvas=n.element,this.$markerFront=new r(this.content),this.$cursorLayer=new l(this.content),this.$horizScroll=!1,this.$vScroll=!1,this.scrollBar=this.scrollBarV=new u(this.container,this),this.scrollBarH=new h(this.container,this),this.scrollBarV.on("scroll",function(e){i.$scrollAnimation||i.session.setScrollTop(e.data-i.scrollMargin.top)}),this.scrollBarH.on("scroll",function(e){i.$scrollAnimation||i.session.setScrollLeft(e.data-i.scrollMargin.left)}),this.scrollTop=0,this.scrollLeft=0,this.cursorPos={row:0,column:0},this.$fontMetrics=new g(this.container),this.$textLayer.$setFontMetrics(this.$fontMetrics),this.$textLayer.on("changeCharacterSize",function(e){i.updateCharacterSize(),i.onResize(!0,i.gutterWidth,i.$size.width,i.$size.height),i._signal("changeCharacterSize",e)}),this.$size={width:0,height:0,scrollerHeight:0,scrollerWidth:0,$dirty:!0},this.layerConfig={width:1,padding:0,firstRow:0,firstRowScreen:0,lastRow:0,lineHeight:0,characterWidth:0,minHeight:1,maxHeight:1,offset:0,height:1,gutterOffset:1},this.scrollMargin={left:0,right:0,top:0,bottom:0,v:0,h:0},this.margin={left:0,right:0,top:0,bottom:0,v:0,h:0},this.$keepTextAreaAtCursor=!p.isIOS,this.$loop=new d(this.$renderChanges.bind(this),this.container.ownerDocument.defaultView),this.$loop.schedule(this.CHANGE_FULL),this.updateCharacterSize(),this.setPadding(4),o.resetOptions(this),o._signal("renderer",this)}(function(){this.CHANGE_CURSOR=1,this.CHANGE_MARKER=2,this.CHANGE_GUTTER=4,this.CHANGE_SCROLL=8,this.CHANGE_LINES=16,this.CHANGE_TEXT=32,this.CHANGE_SIZE=64,this.CHANGE_MARKER_BACK=128,this.CHANGE_MARKER_FRONT=256,this.CHANGE_FULL=512,this.CHANGE_H_SCROLL=1024,n.implement(this,f),this.updateCharacterSize=function(){this.$textLayer.allowBoldFonts!=this.$allowBoldFonts&&(this.$allowBoldFonts=this.$textLayer.allowBoldFonts,this.setStyle("ace_nobold",!this.$allowBoldFonts)),this.layerConfig.characterWidth=this.characterWidth=this.$textLayer.getCharacterWidth(),this.layerConfig.lineHeight=this.lineHeight=this.$textLayer.getLineHeight(),this.$updatePrintMargin(),c.setStyle(this.scroller.style,"line-height",this.lineHeight+"px")},this.setSession=function(e){this.session&&this.session.doc.off("changeNewLineMode",this.onChangeNewLineMode),(this.session=e)&&this.scrollMargin.top&&e.getScrollTop()<=0&&e.setScrollTop(-this.scrollMargin.top),this.$cursorLayer.setSession(e),this.$markerBack.setSession(e),this.$markerFront.setSession(e),this.$gutterLayer.setSession(e),this.$textLayer.setSession(e),e&&(this.$loop.schedule(this.CHANGE_FULL),this.session.$setFontMetrics(this.$fontMetrics),this.scrollBarH.scrollLeft=this.scrollBarV.scrollTop=null,this.onChangeNewLineMode=this.onChangeNewLineMode.bind(this),this.onChangeNewLineMode(),this.session.doc.on("changeNewLineMode",this.onChangeNewLineMode))},this.updateLines=function(e,t,i){if(void 0===t&&(t=1/0),this.$changedLines?(this.$changedLines.firstRow>e&&(this.$changedLines.firstRow=e),this.$changedLines.lastRowthis.layerConfig.lastRow||this.$loop.schedule(this.CHANGE_LINES)},this.onChangeNewLineMode=function(){this.$loop.schedule(this.CHANGE_TEXT),this.$textLayer.$updateEolChar(),this.session.$bidiHandler.setEolChar(this.$textLayer.EOL_CHAR)},this.onChangeTabSize=function(){this.$loop.schedule(this.CHANGE_TEXT|this.CHANGE_MARKER),this.$textLayer.onChangeTabSize()},this.updateText=function(){this.$loop.schedule(this.CHANGE_TEXT)},this.updateFull=function(e){e?this.$renderChanges(this.CHANGE_FULL,!0):this.$loop.schedule(this.CHANGE_FULL)},this.updateFontSize=function(){this.$textLayer.checkForSizeChanges()},this.$changes=0,this.$updateSizeAsync=function(){this.$loop.pending?this.$size.$dirty=!0:this.onResize()},this.onResize=function(e,t,i,n){if(!(2n.height-r?c.translate(this.textarea,0,0):(h=1,a=this.$size.height-r,t?t.useTextareaForIME?(l=this.textarea.value,h=this.characterWidth*this.session.$getStringScreenWidth(l)[0]):s+=this.lineHeight+2:s+=this.lineHeight,(o-=this.scrollLeft)>this.$size.scrollerWidth-h&&(o=this.$size.scrollerWidth-h),o+=this.gutterWidth+this.margin.left,c.setStyle(e,"height",r+"px"),c.setStyle(e,"width",h+"px"),c.translate(this.textarea,Math.min(o,this.$size.scrollerWidth-h),Math.min(s,a)))):c.translate(this.textarea,-100,0))},this.getFirstVisibleRow=function(){return this.layerConfig.firstRow},this.getFirstFullyVisibleRow=function(){return this.layerConfig.firstRow+(0===this.layerConfig.offset?0:1)},this.getLastFullyVisibleRow=function(){var e=this.layerConfig,t=e.lastRow;return this.session.documentToScreenRow(t,0)*e.lineHeight-this.session.getScrollTop()>e.height-e.lineHeight?t-1:t},this.getLastVisibleRow=function(){return this.layerConfig.lastRow},this.$padding=null,this.setPadding=function(e){this.$padding=e,this.$textLayer.setPadding(e),this.$cursorLayer.setPadding(e),this.$markerFront.setPadding(e),this.$markerBack.setPadding(e),this.$loop.schedule(this.CHANGE_FULL),this.$updatePrintMargin()},this.setScrollMargin=function(e,t,i,n){var s=this.scrollMargin;s.top=0|e,s.bottom=0|t,s.right=0|n,s.left=0|i,s.v=s.top+s.bottom,s.h=s.left+s.right,s.top&&this.scrollTop<=0&&this.session&&this.session.setScrollTop(-s.top),this.updateFull()},this.setMargin=function(e,t,i,n){var s=this.margin;s.top=0|e,s.bottom=0|t,s.right=0|n,s.left=0|i,s.v=s.top+s.bottom,s.h=s.left+s.right,this.$updateCachedSize(!0,this.gutterWidth,this.$size.width,this.$size.height),this.updateFull()},this.getHScrollBarAlwaysVisible=function(){return this.$hScrollBarAlwaysVisible},this.setHScrollBarAlwaysVisible=function(e){this.setOption("hScrollBarAlwaysVisible",e)},this.getVScrollBarAlwaysVisible=function(){return this.$vScrollBarAlwaysVisible},this.setVScrollBarAlwaysVisible=function(e){this.setOption("vScrollBarAlwaysVisible",e)},this.$updateScrollBarV=function(){var e=this.layerConfig.maxHeight,t=this.$size.scrollerHeight;!this.$maxLines&&this.$scrollPastEnd&&(e-=(t-this.lineHeight)*this.$scrollPastEnd,this.scrollTop>e-t&&(e=this.scrollTop+t,this.scrollBarV.scrollTop=null)),this.scrollBarV.setScrollHeight(e+this.scrollMargin.v),this.scrollBarV.setScrollTop(this.scrollTop+this.scrollMargin.top)},this.$updateScrollBarH=function(){this.scrollBarH.setScrollWidth(this.layerConfig.width+2*this.$padding+this.scrollMargin.h),this.scrollBarH.setScrollLeft(this.scrollLeft+this.scrollMargin.left)},this.$frozen=!1,this.freeze=function(){this.$frozen=!0},this.unfreeze=function(){this.$frozen=!1},this.$renderChanges=function(e,t){if(this.$changes&&(e|=this.$changes,this.$changes=0),this.session&&this.container.offsetWidth&&!this.$frozen&&(e||t)){if(this.$size.$dirty)return this.$changes|=e,this.onResize(!0);this.lineHeight||this.$textLayer.checkForSizeChanges(),this._signal("beforeRender",e),this.session&&this.session.$bidiHandler&&this.session.$bidiHandler.updateCharacterWidths(this.$fontMetrics);var i,n,s,o=this.layerConfig;return(e&this.CHANGE_FULL||e&this.CHANGE_SIZE||e&this.CHANGE_TEXT||e&this.CHANGE_LINES||e&this.CHANGE_SCROLL||e&this.CHANGE_H_SCROLL)&&(e|=this.$computeLayerConfig()|this.$loop.clear(),o.firstRow==this.layerConfig.firstRow||o.firstRowScreen!=this.layerConfig.firstRowScreen||0<(i=this.scrollTop+(o.firstRow-this.layerConfig.firstRow)*this.lineHeight)&&(this.scrollTop=i,e|=this.CHANGE_SCROLL,e|=this.$computeLayerConfig()|this.$loop.clear()),o=this.layerConfig,this.$updateScrollBarV(),e&this.CHANGE_H_SCROLL&&this.$updateScrollBarH(),c.translate(this.content,-this.scrollLeft,-o.offset),n=o.width+2*this.$padding+"px",s=o.minHeight+"px",c.setStyle(this.content.style,"width",n),c.setStyle(this.content.style,"height",s)),e&this.CHANGE_H_SCROLL&&(c.translate(this.content,-this.scrollLeft,-o.offset),this.scroller.className=this.scrollLeft<=0?"ace_scroller":"ace_scroller ace_scroll-left"),e&this.CHANGE_FULL?(this.$changedLines=null,this.$textLayer.update(o),this.$showGutter&&this.$gutterLayer.update(o),this.$markerBack.update(o),this.$markerFront.update(o),this.$cursorLayer.update(o),this.$moveTextAreaToCursor()):e&this.CHANGE_SCROLL?(this.$changedLines=null,e&this.CHANGE_TEXT||e&this.CHANGE_LINES?this.$textLayer.update(o):this.$textLayer.scrollLines(o),this.$showGutter&&(e&this.CHANGE_GUTTER||e&this.CHANGE_LINES?this.$gutterLayer.update(o):this.$gutterLayer.scrollLines(o)),this.$markerBack.update(o),this.$markerFront.update(o),this.$cursorLayer.update(o),this.$moveTextAreaToCursor()):(e&this.CHANGE_TEXT?(this.$changedLines=null,this.$textLayer.update(o),this.$showGutter&&this.$gutterLayer.update(o)):e&this.CHANGE_LINES?(this.$updateLines()||e&this.CHANGE_GUTTER&&this.$showGutter)&&this.$gutterLayer.update(o):e&this.CHANGE_TEXT||e&this.CHANGE_GUTTER?this.$showGutter&&this.$gutterLayer.update(o):e&this.CHANGE_CURSOR&&this.$highlightGutterLine&&this.$gutterLayer.updateLineHighlight(o),e&this.CHANGE_CURSOR&&(this.$cursorLayer.update(o),this.$moveTextAreaToCursor()),e&(this.CHANGE_MARKER|this.CHANGE_MARKER_FRONT)&&this.$markerFront.update(o),e&(this.CHANGE_MARKER|this.CHANGE_MARKER_BACK)&&this.$markerBack.update(o)),void this._signal("afterRender",e)}this.$changes|=e},this.$autosize=function(){var e=this.session.getScreenLength()*this.lineHeight,t=this.$maxLines*this.lineHeight,i=Math.min(t,Math.max((this.$minLines||1)*this.lineHeight,e))+this.scrollMargin.v+(this.$extraHeight||0);this.$horizScroll&&(i+=this.scrollBarH.getHeight()),this.$maxPixelHeight&&i>this.$maxPixelHeight&&(i=this.$maxPixelHeight);var n,s=!(i<=2*this.lineHeight)&&tc.top),d=a!==u;d&&(this.$vScroll=u,this.scrollBarV.setVisible(u));var g,f,m=this.scrollTop%this.lineHeight,p=Math.ceil(l/this.lineHeight)-1,w=($=Math.max(0,Math.round((this.scrollTop-m)/this.lineHeight)))+p,v=this.lineHeight,$=e.screenToDocumentRow($,0),b=e.getFoldLine($);b&&($=b.start.row),g=e.documentToScreenRow($,0),f=e.getRowLength($)*v,w=Math.min(e.screenToDocumentRow(w,0),e.getLength()-1),l=t.scrollerHeight+e.getRowLength(w)*v+f,m=this.scrollTop-g*v;var y=0;return this.layerConfig.width==s&&!r||(y=this.CHANGE_H_SCROLL),(r||d)&&(y|=this.$updateCachedSize(!0,this.gutterWidth,t.width,t.height),this._signal("scrollbarVisibilityChanged"),d&&(s=this.$getLongestLine())),this.layerConfig={width:s,padding:this.$padding,firstRow:$,firstRowScreen:g,lastRow:w,lineHeight:v,characterWidth:this.characterWidth,minHeight:l,maxHeight:n,offset:m,gutterOffset:v?Math.max(0,Math.ceil((m+t.height-t.scrollerHeight)/v)):0,height:this.$size.scrollerHeight},this.session.$bidiHandler&&this.session.$bidiHandler.setContentWidth(s-this.$padding),y},this.$updateLines=function(){if(this.$changedLines){var e=this.$changedLines.firstRow,t=this.$changedLines.lastRow;this.$changedLines=null;var i=this.layerConfig;if(!(e>i.lastRow+1||tthis.$textLayer.MAX_LINE_LENGTH&&(e=this.$textLayer.MAX_LINE_LENGTH+30),Math.max(this.$size.scrollerWidth-2*this.$padding,Math.round(e*this.characterWidth))},this.updateFrontMarkers=function(){this.$markerFront.setMarkers(this.session.getMarkers(!0)),this.$loop.schedule(this.CHANGE_MARKER_FRONT)},this.updateBackMarkers=function(){this.$markerBack.setMarkers(this.session.getMarkers()),this.$loop.schedule(this.CHANGE_MARKER_BACK)},this.addGutterDecoration=function(e,t){this.$gutterLayer.addGutterDecoration(e,t)},this.removeGutterDecoration=function(e,t){this.$gutterLayer.removeGutterDecoration(e,t)},this.updateBreakpoints=function(e){this.$loop.schedule(this.CHANGE_GUTTER)},this.setAnnotations=function(e){this.$gutterLayer.setAnnotations(e),this.$loop.schedule(this.CHANGE_GUTTER)},this.updateCursor=function(){this.$loop.schedule(this.CHANGE_CURSOR)},this.hideCursor=function(){this.$cursorLayer.hideCursor()},this.showCursor=function(){this.$cursorLayer.showCursor()},this.scrollSelectionIntoView=function(e,t,i){this.scrollCursorIntoView(e,i),this.scrollCursorIntoView(t,i)},this.scrollCursorIntoView=function(e,t,i){var n,s,o,r,a,l,h;0!==this.$size.scrollerHeight&&(s=(n=this.$cursorLayer.getPixelPosition(e)).left,o=n.top,r=i&&i.top||0,a=i&&i.bottom||0,o<(l=this.$scrollAnimation?this.session.getScrollTop():this.scrollTop)+r?(t&&l+r>o+this.lineHeight&&(o-=t*this.$size.scrollerHeight),0===o&&(o=-this.scrollMargin.top),this.session.setScrollTop(o)):l+this.$size.scrollerHeight-a=1-this.scrollMargin.top||(0=1-this.scrollMargin.left||(0this.$doc.getLength()>>1?this.call("setValue",[this.$doc.getValue()]):this.emit("change",{data:e}))}}).call(h.prototype);e.UIWorkerClient=function(e,t,i){var n=null,s=!1,o=Object.create(c),r=[],a=new h({messageBuffer:r,terminate:function(){},postMessage:function(e){r.push(e),n&&(s?setTimeout(l):l())}});a.setEmitSync=function(e){s=e};var l=function(){var e=r.shift();e.command?n[e.command].apply(n,e.args):e.event&&o._signal(e.event,e.data)};return o.postMessage=function(e){a.onMessage({data:e})},o.callback=function(e,t){this.postMessage({type:"call",id:t,data:e})},o.emit=function(e,t){this.postMessage({type:"event",name:e,data:t})},u.loadModule(["worker",t],function(e){for(n=new e[i](o);r.length;)l()}),a},e.WorkerClient=h,e.createWorker=l}),define("ace/placeholder",["require","exports","module","ace/range","ace/lib/event_emitter","ace/lib/oop"],function(e,t,i){"use strict";function n(e,t,i,n,s,o){var r=this;this.length=t,this.session=e,this.doc=e.getDocument(),this.mainClass=s,this.othersClass=o,this.$onUpdate=this.onUpdate.bind(this),this.doc.on("change",this.$onUpdate),this.$others=n,this.$onCursorChange=function(){setTimeout(function(){r.onCursorChange()})},this.$pos=i;var a=e.getUndoManager().$undoStack||e.getUndoManager().$undostack||{length:-1};this.$undoStackDepth=a.length,this.setup(),e.selection.on("changeCursor",this.$onCursorChange)}var l=e("./range").Range,s=e("./lib/event_emitter").EventEmitter,o=e("./lib/oop");(function(){o.implement(this,s),this.setup=function(){var i=this,n=this.doc,e=this.session;this.selectionBefore=e.selection.toJSON(),e.selection.inMultiSelectMode&&e.selection.toSingleRange(),this.pos=n.createAnchor(this.$pos.row,this.$pos.column);var t=this.pos;t.$insertRight=!0,t.detach(),t.markerId=e.addMarker(new l(t.row,t.column,t.row,t.column+this.length),this.mainClass,null,!1),this.others=[],this.$others.forEach(function(e){var t=n.createAnchor(e.row,e.column);t.$insertRight=!0,t.detach(),i.others.push(t)}),e.setUndoSelect(!1)},this.showOtherMarkers=function(){var t,i;this.othersActive||(t=this.session,(i=this).othersActive=!0,this.others.forEach(function(e){e.markerId=t.addMarker(new l(e.row,e.column,e.row,e.column+i.length),i.othersClass,null,!1)}))},this.hideOtherMarkers=function(){if(this.othersActive){this.othersActive=!1;for(var e=0;e=this.pos.column&&t.start.column<=this.pos.column+this.length+1,s=t.start.column-this.pos.column;if(this.updateAnchors(e),n&&(this.length+=i),n&&!this.session.$fromUndo)if("insert"===e.action)for(var o=this.others.length-1;0<=o;o--){var r={row:(a=this.others[o]).row,column:a.column+s};this.doc.insertMergedLines(r,e.lines)}else if("remove"===e.action)for(o=this.others.length-1;0<=o;o--){var a,r={row:(a=this.others[o]).row,column:a.column+s};this.doc.remove(new l(r.row,r.column,r.row,r.column-i))}this.$updating=!1,this.updateMarkers()}},this.updateAnchors=function(e){this.pos.onChange(e);for(var t=this.others.length;t--;)this.others[t].onChange(e);this.updateMarkers()},this.updateMarkers=function(){if(!this.$updating){var i=this,n=this.session,e=function(e,t){n.removeMarker(e.markerId),e.markerId=n.addMarker(new l(e.row,e.column,e.row,e.column+i.length),t,null,!1)};e(this.pos,this.mainClass);for(var t=this.others.length;t--;)e(this.others[t],this.othersClass)}},this.onCursorChange=function(e){var t;!this.$updating&&this.session&&((t=this.session.selection.getCursor()).row===this.pos.row&&t.column>=this.pos.column&&t.column<=this.pos.column+this.length?(this.showOtherMarkers(),this._emit("cursorEnter",e)):(this.hideOtherMarkers(),this._emit("cursorLeave",e)))},this.detach=function(){this.session.removeMarker(this.pos&&this.pos.markerId),this.hideOtherMarkers(),this.doc.off("change",this.$onUpdate),this.session.selection.off("changeCursor",this.$onCursorChange),this.session.setUndoSelect(!0),this.session=null},this.cancel=function(){if(-1!==this.$undoStackDepth){for(var e=this.session.getUndoManager(),t=(e.$undoStack||e.$undostack).length-this.$undoStackDepth,i=0;ir&&(r=t.column),it[1].length&&(s=t[1].length),ot[3].length&&(r=t[3].length)),t):[e]}).map(t?n:a?l?function(e){return e[2]?i(s+o-e[2].length)+e[2]+i(r)+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}:n:function(e){return e[2]?i(s)+e[2]+i(r)+e[4].replace(/^([=:])\s+/,"$1 "):e[0]})}}).call(h.prototype),t.onSessionChange=function(e){var t=e.session;t&&!t.multiSelect&&(t.$selectionMarkers=[],t.selection.$initRangeList(),t.multiSelect=t.selection),this.multiSelect=t&&t.multiSelect;var i=e.oldSession;i&&(i.multiSelect.off("addRange",this.$onAddRange),i.multiSelect.off("removeRange",this.$onRemoveRange),i.multiSelect.off("multiSelect",this.$onMultiSelect),i.multiSelect.off("singleSelect",this.$onSingleSelect),i.multiSelect.lead.off("change",this.$checkMultiselectChange),i.multiSelect.anchor.off("change",this.$checkMultiselectChange)),t&&(t.multiSelect.on("addRange",this.$onAddRange),t.multiSelect.on("removeRange",this.$onRemoveRange),t.multiSelect.on("multiSelect",this.$onMultiSelect),t.multiSelect.on("singleSelect",this.$onSingleSelect),t.multiSelect.lead.on("change",this.$checkMultiselectChange),t.multiSelect.anchor.on("change",this.$checkMultiselectChange)),t&&this.inMultiSelectMode!=t.selection.inMultiSelectMode&&(t.selection.inMultiSelectMode?this.$onMultiSelect():this.$onSingleSelect())},t.MultiSelect=n,e("./config").defineOptions(h.prototype,"editor",{enableMultiselect:{set:function(e){n(this),e?(this.on("changeSession",this.$multiselectOnSessionChange),this.on("mousedown",o)):(this.off("changeSession",this.$multiselectOnSessionChange),this.off("mousedown",o))},value:!0},enableBlockSelect:{set:function(e){this.$blockSelectEnabled=e},value:!0}})}),define("ace/mode/folding/fold_mode",["require","exports","module","ace/range"],function(e,t,i){"use strict";var g=e("../../range").Range,n=t.FoldMode=function(){};(function(){this.foldingStartMarker=null,this.foldingStopMarker=null,this.getFoldWidget=function(e,t,i){var n=e.getLine(i);return this.foldingStartMarker.test(n)?"start":"markbeginend"==t&&this.foldingStopMarker&&this.foldingStopMarker.test(n)?"end":""},this.getFoldWidgetRange=function(e,t,i){return null},this.indentationBlock=function(e,t,i){var n=/\S/,s=e.getLine(t),o=s.search(n);if(-1!=o){for(var r=i||s.length,a=e.getLength(),l=t,h=t;++to.row&&(r.row--,r.column=e.getLine(r.row).length),g.fromPoints(o,r)}},this.closingBracketBlock=function(e,t,i,n,s){var o={row:i,column:n},r=e.$findOpeningBracket(t,o);if(r)return r.column++,o.column--,g.fromPoints(r,o)}}).call(n.prototype)}),define("ace/theme/textmate",["require","exports","module","ace/lib/dom"],function(e,t,i){"use strict";t.isDark=!1,t.cssClass="ace-tm",t.cssText='.ace-tm .ace_gutter {background: #f0f0f0;color: #333;}.ace-tm .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-tm .ace_fold {background-color: #6B72E6;}.ace-tm {background-color: #FFFFFF;color: black;}.ace-tm .ace_cursor {color: black;}.ace-tm .ace_invisible {color: rgb(191, 191, 191);}.ace-tm .ace_storage,.ace-tm .ace_keyword {color: blue;}.ace-tm .ace_constant {color: rgb(197, 6, 11);}.ace-tm .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-tm .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-tm .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-tm .ace_invalid {background-color: rgba(255, 0, 0, 0.1);color: red;}.ace-tm .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-tm .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-tm .ace_support.ace_type,.ace-tm .ace_support.ace_class {color: rgb(109, 121, 222);}.ace-tm .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-tm .ace_string {color: rgb(3, 106, 7);}.ace-tm .ace_comment {color: rgb(76, 136, 107);}.ace-tm .ace_comment.ace_doc {color: rgb(0, 102, 255);}.ace-tm .ace_comment.ace_doc.ace_tag {color: rgb(128, 159, 191);}.ace-tm .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-tm .ace_variable {color: rgb(49, 132, 149);}.ace-tm .ace_xml-pe {color: rgb(104, 104, 91);}.ace-tm .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-tm .ace_heading {color: rgb(12, 7, 255);}.ace-tm .ace_list {color:rgb(185, 6, 144);}.ace-tm .ace_meta.ace_tag {color:rgb(0, 22, 142);}.ace-tm .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-tm .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-tm.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px white;}.ace-tm .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-tm .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-tm .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-tm .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-tm .ace_gutter-active-line {background-color : #dcdcdc;}.ace-tm .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-tm .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}',t.$id="ace/theme/textmate",e("../lib/dom").importCssString(t.cssText,t.cssClass)}),define("ace/line_widgets",["require","exports","module","ace/lib/dom"],function(e,t,i){"use strict";function n(e){this.session=e,(this.session.widgetManager=this).session.getRowLength=this.getRowLength,this.session.$getWidgetScreenLength=this.$getWidgetScreenLength,this.updateOnChange=this.updateOnChange.bind(this),this.renderWidgets=this.renderWidgets.bind(this),this.measureWidgets=this.measureWidgets.bind(this),this.session._changedWidgets=[],this.$onChangeEditor=this.$onChangeEditor.bind(this),this.session.on("change",this.updateOnChange),this.session.on("changeFold",this.updateOnFold),this.session.on("changeEditor",this.$onChangeEditor)}var s=e("./lib/dom");(function(){this.getRowLength=function(e){var t=this.lineWidgets&&this.lineWidgets[e]&&this.lineWidgets[e].rowCount||0;return this.$useWrapMode&&this.$wrapData[e]?this.$wrapData[e].length+1+t:1+t},this.$getWidgetScreenLength=function(){var t=0;return this.lineWidgets.forEach(function(e){e&&e.rowCount&&!e.hidden&&(t+=e.rowCount)}),t},this.$onChangeEditor=function(e){this.attach(e.editor)},this.attach=function(e){e&&e.widgetManager&&e.widgetManager!=this&&e.widgetManager.detach(),this.editor!=e&&(this.detach(),(this.editor=e)&&(e.widgetManager=this,e.renderer.on("beforeRender",this.measureWidgets),e.renderer.on("afterRender",this.renderWidgets)))},this.detach=function(e){var t,i=this.editor;i&&(this.editor=null,i.widgetManager=null,i.renderer.off("beforeRender",this.measureWidgets),i.renderer.off("afterRender",this.renderWidgets),(t=this.session.lineWidgets)&&t.forEach(function(e){e&&e.el&&e.el.parentNode&&(e._inDocument=!1,e.el.parentNode.removeChild(e.el))}))},this.updateOnFold=function(e,t){var i=t.lineWidgets;if(i&&e.action){for(var n=e.data,s=n.start.row,o=n.end.row,r="add"==e.action,a=s+1;ao[t].column&&t++,s.unshift(t,0),o.splice.apply(o,s)),this.$updateRows()))},this.$updateRows=function(){var i,e=this.session.lineWidgets;e&&(i=!0,e.forEach(function(e,t){if(e)for(i=!1,e.row=t;e.$oldWidget;)e.$oldWidget.row=t,e=e.$oldWidget}),i&&(this.session.lineWidgets=null))},this.$registerLineWidget=function(e){this.session.lineWidgets||(this.session.lineWidgets=new Array(this.session.getLength()));var t=this.session.lineWidgets[e.row];return t&&((e.$oldWidget=t).el&&t.el.parentNode&&(t.el.parentNode.removeChild(t.el),t._inDocument=!1)),this.session.lineWidgets[e.row]=e},this.addLineWidget=function(e){if(this.$registerLineWidget(e),e.session=this.session,!this.editor)return e;var t=this.editor.renderer;e.html&&!e.el&&(e.el=s.createElement("div"),e.el.innerHTML=e.html),e.el&&(s.addCssClass(e.el,"ace_lineWidgetContainer"),e.el.style.position="absolute",e.el.style.zIndex=5,t.container.appendChild(e.el),e._inDocument=!0,e.coverGutter||(e.el.style.zIndex=3),null==e.pixelHeight&&(e.pixelHeight=e.el.offsetHeight)),null==e.rowCount&&(e.rowCount=e.pixelHeight/t.layerConfig.lineHeight);var i,n=this.session.getFoldAt(e.row,0);return(e.$fold=n)&&(i=this.session.lineWidgets,e.row!=n.end.row||i[n.start.row]?e.hidden=!0:i[n.start.row]=e),this.session._emit("changeFold",{data:{start:{row:e.row}}}),this.$updateRows(),this.renderWidgets(null,t),this.onWidgetChanged(e),e},this.removeLineWidget=function(e){if(e._inDocument=!1,e.session=null,e.el&&e.el.parentNode&&e.el.parentNode.removeChild(e.el),e.editor&&e.editor.destroy)try{e.editor.destroy()}catch(e){}if(this.session.lineWidgets){var t=this.session.lineWidgets[e.row];if(t==e)this.session.lineWidgets[e.row]=e.$oldWidget,e.$oldWidget&&this.onWidgetChanged(e.$oldWidget);else for(;t;){if(t.$oldWidget==e){t.$oldWidget=e.$oldWidget;break}t=t.$oldWidget}}this.session._emit("changeFold",{data:{start:{row:e.row}}}),this.$updateRows()},this.getWidgetsAtRow=function(e){for(var t=this.session.lineWidgets,i=t&&t[e],n=[];i;)n.push(i),i=i.$oldWidget;return n},this.onWidgetChanged=function(e){this.session._changedWidgets.push(e),this.editor&&this.editor.renderer.updateFull()},this.measureWidgets=function(e,t){var i=this.session._changedWidgets,n=t.layerConfig;if(i&&i.length){for(var s=1/0,o=0;o>1,r=i(t,e[o]);if(0=n.length?s=0"),c.appendChild(p.createElement("div"));function g(e,t,i){if(0===t&&("esc"===i||"return"===i))return h.destroy(),{command:"null"}}h.destroy=function(){e.$mouseHandler.isMousePressed||(e.keyBinding.removeKeyboardHandler(g),i.widgetManager.removeLineWidget(h),e.off("changeSelection",h.destroy),e.off("changeSession",h.destroy),e.off("mouseup",h.destroy),e.off("change",h.destroy))},e.keyBinding.addKeyboardHandler(g),e.on("changeSelection",h.destroy),e.on("changeSession",h.destroy),e.on("mouseup",h.destroy),e.on("change",h.destroy),e.session.widgetManager.addLineWidget(h),h.el.onmousedown=e.focus.bind(e),e.renderer.scrollCursorIntoView(null,.5,{bottom:h.el.offsetHeight})},p.importCssString(" .error_widget_wrapper { background: inherit; color: inherit; border:none } .error_widget { border-top: solid 2px; border-bottom: solid 2px; margin: 5px 0; padding: 10px 40px; white-space: pre-wrap; } .error_widget.ace_error, .error_widget_arrow.ace_error{ border-color: #ff5a5a } .error_widget.ace_warning, .error_widget_arrow.ace_warning{ border-color: #F1D817 } .error_widget.ace_info, .error_widget_arrow.ace_info{ border-color: #5a5a5a } .error_widget.ace_ok, .error_widget_arrow.ace_ok{ border-color: #5aaa5a } .error_widget_arrow { position: absolute; border: solid 5px; border-top-color: transparent!important; border-right-color: transparent!important; border-left-color: transparent!important; top: -5px; }","")}),define("ace/ace",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/dom","ace/lib/event","ace/range","ace/editor","ace/edit_session","ace/undomanager","ace/virtual_renderer","ace/worker/worker_client","ace/keyboard/hash_handler","ace/placeholder","ace/multi_select","ace/mode/folding/fold_mode","ace/theme/textmate","ace/ext/error_marker","ace/config"],function(e,l,t){"use strict";e("./lib/fixoldbrowsers");var h=e("./lib/dom"),c=e("./lib/event"),i=e("./range").Range,u=e("./editor").Editor,n=e("./edit_session").EditSession,s=e("./undomanager").UndoManager,d=e("./virtual_renderer").VirtualRenderer;e("./worker/worker_client"),e("./keyboard/hash_handler"),e("./placeholder"),e("./multi_select"),e("./mode/folding/fold_mode"),e("./theme/textmate"),e("./ext/error_marker"),l.config=e("./config"),l.require=e,"function"==typeof define&&(l.define=define),l.edit=function(e,t){if("string"==typeof e){var i=e;if(!(e=document.getElementById(i)))throw new Error("ace.edit can't find div #"+i)}if(e&&e.env&&e.env.editor instanceof u)return e.env.editor;var n,s="";e&&/input|textarea/i.test(e.tagName)?(s=(n=e).value,e=h.createElement("pre"),n.parentNode.replaceChild(e,n)):e&&(s=e.textContent,e.innerHTML="");var o=l.createEditSession(s),r=new u(new d(e),o,t),a={document:o,editor:r,onResize:r.resize.bind(r,null)};return n&&(a.textarea=n),c.addListener(window,"resize",a.onResize),r.on("destroy",function(){c.removeListener(window,"resize",a.onResize),a.editor.container.env=null}),r.container.env=r.env=a,r},l.createEditSession=function(e,t){var i=new n(e,t);return i.setUndoManager(new s),i},l.Range=i,l.Editor=u,l.EditSession=n,l.UndoManager=s,l.VirtualRenderer=d,l.version=l.config.version}),window.require(["ace/ace"],function(e){for(var t in e&&(e.config.init(!0),e.define=window.define),window.ace||(window.ace=e),e)e.hasOwnProperty(t)&&(window.ace[t]=e[t]);window.ace.default=window.ace,"object"==typeof module&&"object"==typeof exports&&module&&(module.exports=window.ace)}); \ No newline at end of file diff --git a/twake/frontend/public/public/viewer/CodeViewer/ext-modelist.js b/twake/frontend/public/public/viewer/CodeViewer/ext-modelist.js new file mode 100644 index 00000000..ae001fef --- /dev/null +++ b/twake/frontend/public/public/viewer/CodeViewer/ext-modelist.js @@ -0,0 +1,226 @@ +ace.define('ace/ext/modelist', ['require', 'exports', 'module'], function (e, t, n) { + 'use strict'; + function i(e) { + var t = a.text, + n = e.split(/[\/\\]/).pop(); + for (var i = 0; i < r.length; i++) + if (r[i].supportsFile(n)) { + t = r[i]; + break; + } + return t; + } + var r = [], + s = function (e, t, n) { + (this.name = e), (this.caption = t), (this.mode = 'ace/mode/' + e), (this.extensions = n); + var r; + /\^/.test(n) + ? (r = + n.replace(/\|(\^)?/g, function (e, t) { + return '$|' + (t ? '^' : '^.*\\.'); + }) + '$') + : (r = '^.*\\.(' + n + ')$'), + (this.extRe = new RegExp(r, 'gi')); + }; + s.prototype.supportsFile = function (e) { + return e.match(this.extRe); + }; + var o = { + ABAP: ['abap'], + ABC: ['abc'], + ActionScript: ['as'], + ADA: ['ada|adb'], + Alda: ['alda'], + Apache_Conf: ['^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd'], + Apex: ['apex|cls|trigger|tgr'], + AQL: ['aql'], + AsciiDoc: ['asciidoc|adoc'], + ASL: ['dsl|asl'], + Assembly_x86: ['asm|a'], + AutoHotKey: ['ahk'], + BatchFile: ['bat|cmd'], + C_Cpp: ['cpp|c|cc|cxx|h|hh|hpp|ino'], + C9Search: ['c9search_results'], + Cirru: ['cirru|cr'], + Clojure: ['clj|cljs'], + Cobol: ['CBL|COB'], + coffee: ['coffee|cf|cson|^Cakefile'], + ColdFusion: ['cfm'], + Crystal: ['cr'], + CSharp: ['cs'], + Csound_Document: ['csd'], + Csound_Orchestra: ['orc'], + Csound_Score: ['sco'], + CSS: ['css'], + Curly: ['curly'], + D: ['d|di'], + Dart: ['dart'], + Diff: ['diff|patch'], + Dockerfile: ['^Dockerfile'], + Dot: ['dot'], + Drools: ['drl'], + Edifact: ['edi'], + Eiffel: ['e|ge'], + EJS: ['ejs'], + Elixir: ['ex|exs'], + Elm: ['elm'], + Erlang: ['erl|hrl'], + Forth: ['frt|fs|ldr|fth|4th'], + Fortran: ['f|f90'], + FSharp: ['fsi|fs|ml|mli|fsx|fsscript'], + FSL: ['fsl'], + FTL: ['ftl'], + Gcode: ['gcode'], + Gherkin: ['feature'], + Gitignore: ['^.gitignore'], + Glsl: ['glsl|frag|vert'], + Gobstones: ['gbs'], + golang: ['go'], + GraphQLSchema: ['gql'], + Groovy: ['groovy'], + HAML: ['haml'], + Handlebars: ['hbs|handlebars|tpl|mustache'], + Haskell: ['hs'], + Haskell_Cabal: ['cabal'], + haXe: ['hx'], + Hjson: ['hjson'], + HTML: ['html|htm|xhtml|vue|we|wpy'], + HTML_Elixir: ['eex|html.eex'], + HTML_Ruby: ['erb|rhtml|html.erb'], + INI: ['ini|conf|cfg|prefs'], + Io: ['io'], + Jack: ['jack'], + Jade: ['jade|pug'], + Java: ['java'], + JavaScript: ['js|jsm|jsx'], + JSON: ['json'], + JSON5: ['json5'], + JSONiq: ['jq'], + JSP: ['jsp'], + JSSM: ['jssm|jssm_state'], + JSX: ['jsx'], + Julia: ['jl'], + Kotlin: ['kt|kts'], + LaTeX: ['tex|latex|ltx|bib'], + LESS: ['less'], + Liquid: ['liquid'], + Lisp: ['lisp'], + LiveScript: ['ls'], + LogiQL: ['logic|lql'], + LSL: ['lsl'], + Lua: ['lua'], + LuaPage: ['lp'], + Lucene: ['lucene'], + Makefile: ['^Makefile|^GNUmakefile|^makefile|^OCamlMakefile|make'], + Markdown: ['md|markdown'], + Mask: ['mask'], + MATLAB: ['matlab'], + Maze: ['mz'], + MediaWiki: ['wiki|mediawiki'], + MEL: ['mel'], + MIXAL: ['mixal'], + MUSHCode: ['mc|mush'], + MySQL: ['mysql'], + Nginx: ['nginx|conf'], + Nim: ['nim'], + Nix: ['nix'], + NSIS: ['nsi|nsh'], + Nunjucks: ['nunjucks|nunjs|nj|njk'], + ObjectiveC: ['m|mm'], + OCaml: ['ml|mli'], + Pascal: ['pas|p'], + Perl: ['pl|pm'], + Perl6: ['p6|pl6|pm6'], + pgSQL: ['pgsql'], + PHP: ['php|inc|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module'], + PHP_Laravel_blade: ['blade.php'], + Pig: ['pig'], + Powershell: ['ps1'], + Praat: ['praat|praatscript|psc|proc'], + Prisma: ['prisma'], + Prolog: ['plg|prolog'], + Properties: ['properties'], + Protobuf: ['proto'], + Puppet: ['epp|pp'], + Python: ['py'], + QML: ['qml'], + R: ['r'], + Razor: ['cshtml|asp'], + RDoc: ['Rd'], + Red: ['red|reds'], + RHTML: ['Rhtml'], + RST: ['rst'], + Ruby: ['rb|ru|gemspec|rake|^Guardfile|^Rakefile|^Gemfile'], + Rust: ['rs'], + SASS: ['sass'], + SCAD: ['scad'], + Scala: ['scala|sbt'], + Scheme: ['scm|sm|rkt|oak|scheme'], + SCSS: ['scss'], + SH: ['sh|bash|^.bashrc'], + SJS: ['sjs'], + Slim: ['slim|skim'], + Smarty: ['smarty|tpl'], + snippets: ['snippets'], + Soy_Template: ['soy'], + Space: ['space'], + SQL: ['sql'], + SQLServer: ['sqlserver'], + Stylus: ['styl|stylus'], + SVG: ['svg'], + Swift: ['swift'], + Tcl: ['tcl'], + Terraform: ['tf', 'tfvars', 'terragrunt'], + Tex: ['tex'], + Text: ['txt'], + Textile: ['textile'], + Toml: ['toml'], + TSX: ['tsx'], + Twig: ['latte|twig|swig'], + Typescript: ['ts|typescript|str'], + Vala: ['vala'], + VBScript: ['vbs|vb'], + Velocity: ['vm'], + Verilog: ['v|vh|sv|svh'], + VHDL: ['vhd|vhdl'], + Visualforce: ['vfp|component|page'], + Wollok: ['wlk|wpgm|wtest'], + XML: ['xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl|xaml'], + XQuery: ['xq'], + YAML: ['yaml|yml'], + Zeek: ['zeek|bro'], + Django: ['html'], + }, + u = { + ObjectiveC: 'Objective-C', + CSharp: 'C#', + golang: 'Go', + C_Cpp: 'C and C++', + Csound_Document: 'Csound Document', + Csound_Orchestra: 'Csound', + Csound_Score: 'Csound Score', + coffee: 'CoffeeScript', + HTML_Ruby: 'HTML (Ruby)', + HTML_Elixir: 'HTML (Elixir)', + FTL: 'FreeMarker', + PHP_Laravel_blade: 'PHP (Blade Template)', + Perl6: 'Perl 6', + AutoHotKey: 'AutoHotkey / AutoIt', + }, + a = {}; + for (var f in o) { + var l = o[f], + c = (u[f] || f).replace(/_/g, ' '), + h = f.toLowerCase(), + p = new s(h, c, l[0]); + (a[h] = p), r.push(p); + } + n.exports = { getModeForPath: i, modes: r, modesByName: a }; +}); +(function () { + ace.require(['ace/ext/modelist'], function (m) { + if (typeof module == 'object' && typeof exports == 'object' && module) { + module.exports = m; + } + }); +})(); diff --git a/twake/frontend/public/public/viewer/CodeViewer/showdown.min.js b/twake/frontend/public/public/viewer/CodeViewer/showdown.min.js new file mode 100644 index 00000000..9bf51426 --- /dev/null +++ b/twake/frontend/public/public/viewer/CodeViewer/showdown.min.js @@ -0,0 +1,3 @@ +/*! showdown v 1.9.1 - 02-11-2019 */ +(function(){function e(e){"use strict";var r={omitExtraWLInCodeBlocks:{defaultValue:!1,describe:"Omit the default extra whiteline added to code blocks",type:"boolean"},noHeaderId:{defaultValue:!1,describe:"Turn on/off generated header id",type:"boolean"},prefixHeaderId:{defaultValue:!1,describe:"Add a prefix to the generated header ids. Passing a string will prefix that string to the header id. Setting to true will add a generic 'section-' prefix",type:"string"},rawPrefixHeaderId:{defaultValue:!1,describe:'Setting this option to true will prevent showdown from modifying the prefix. This might result in malformed IDs (if, for instance, the " char is used in the prefix)',type:"boolean"},ghCompatibleHeaderId:{defaultValue:!1,describe:"Generate header ids compatible with github style (spaces are replaced with dashes, a bunch of non alphanumeric chars are removed)",type:"boolean"},rawHeaderId:{defaultValue:!1,describe:"Remove only spaces, ' and \" from generated header ids (including prefixes), replacing them with dashes (-). WARNING: This might result in malformed ids",type:"boolean"},headerLevelStart:{defaultValue:!1,describe:"The header blocks level start",type:"integer"},parseImgDimensions:{defaultValue:!1,describe:"Turn on/off image dimension parsing",type:"boolean"},simplifiedAutoLink:{defaultValue:!1,describe:"Turn on/off GFM autolink style",type:"boolean"},excludeTrailingPunctuationFromURLs:{defaultValue:!1,describe:"Excludes trailing punctuation from links generated with autoLinking",type:"boolean"},literalMidWordUnderscores:{defaultValue:!1,describe:"Parse midword underscores as literal underscores",type:"boolean"},literalMidWordAsterisks:{defaultValue:!1,describe:"Parse midword asterisks as literal asterisks",type:"boolean"},strikethrough:{defaultValue:!1,describe:"Turn on/off strikethrough support",type:"boolean"},tables:{defaultValue:!1,describe:"Turn on/off tables support",type:"boolean"},tablesHeaderId:{defaultValue:!1,describe:"Add an id to table headers",type:"boolean"},ghCodeBlocks:{defaultValue:!0,describe:"Turn on/off GFM fenced code blocks support",type:"boolean"},tasklists:{defaultValue:!1,describe:"Turn on/off GFM tasklist support",type:"boolean"},smoothLivePreview:{defaultValue:!1,describe:"Prevents weird effects in live previews due to incomplete input",type:"boolean"},smartIndentationFix:{defaultValue:!1,description:"Tries to smartly fix indentation in es6 strings",type:"boolean"},disableForced4SpacesIndentedSublists:{defaultValue:!1,description:"Disables the requirement of indenting nested sublists by 4 spaces",type:"boolean"},simpleLineBreaks:{defaultValue:!1,description:"Parses simple line breaks as
(GFM Style)",type:"boolean"},requireSpaceBeforeHeadingText:{defaultValue:!1,description:"Makes adding a space between `#` and the header text mandatory (GFM Style)",type:"boolean"},ghMentions:{defaultValue:!1,description:"Enables github @mentions",type:"boolean"},ghMentionsLink:{defaultValue:"https://github.com/{u}",description:"Changes the link generated by @mentions. Only applies if ghMentions option is enabled.",type:"string"},encodeEmails:{defaultValue:!0,description:"Encode e-mail addresses through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities",type:"boolean"},openLinksInNewWindow:{defaultValue:!1,description:"Open all links in new windows",type:"boolean"},backslashEscapesHTMLTags:{defaultValue:!1,description:"Support for HTML Tag escaping. ex:
foo
",type:"boolean"},emoji:{defaultValue:!1,description:"Enable emoji support. Ex: `this is a :smile: emoji`",type:"boolean"},underline:{defaultValue:!1,description:"Enable support for underline. Syntax is double or triple underscores: `__underline word__`. With this option enabled, underscores no longer parses into `` and ``",type:"boolean"},completeHTMLDocument:{defaultValue:!1,description:"Outputs a complete html document, including ``, `` and `` tags",type:"boolean"},metadata:{defaultValue:!1,description:"Enable support for document metadata (defined at the top of the document between `«««` and `»»»` or between `---` and `---`).",type:"boolean"},splitAdjacentBlockquotes:{defaultValue:!1,description:"Split adjacent blockquote blocks",type:"boolean"}};if(!1===e)return JSON.parse(JSON.stringify(r));var t={};for(var a in r)r.hasOwnProperty(a)&&(t[a]=r[a].defaultValue);return t}function r(e,r){"use strict";var t=r?"Error in "+r+" extension->":"Error in unnamed extension",n={valid:!0,error:""};a.helper.isArray(e)||(e=[e]);for(var s=0;s").replace(/&/g,"&")};var c=function(e,r,t,a){"use strict";var n,s,o,i,l,c=a||"",u=c.indexOf("g")>-1,d=new RegExp(r+"|"+t,"g"+c.replace(/g/g,"")),p=new RegExp(r,c.replace(/g/g,"")),h=[];do{for(n=0;o=d.exec(e);)if(p.test(o[0]))n++||(i=(s=d.lastIndex)-o[0].length);else if(n&&!--n){l=o.index+o[0].length;var _={left:{start:i,end:s},match:{start:s,end:o.index},right:{start:o.index,end:l},wholeMatch:{start:i,end:l}};if(h.push(_),!u)return h}}while(n&&(d.lastIndex=s));return h};a.helper.matchRecursiveRegExp=function(e,r,t,a){"use strict";for(var n=c(e,r,t,a),s=[],o=0;o0){var d=[];0!==i[0].wholeMatch.start&&d.push(e.slice(0,i[0].wholeMatch.start));for(var p=0;p=0?n+(t||0):n},a.helper.splitAtIndex=function(e,r){"use strict";if(!a.helper.isString(e))throw"InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string";return[e.substring(0,r),e.substring(r)]},a.helper.encodeEmailAddress=function(e){"use strict";var r=[function(e){return"&#"+e.charCodeAt(0)+";"},function(e){return"&#x"+e.charCodeAt(0).toString(16)+";"},function(e){return e}];return e=e.replace(/./g,function(e){if("@"===e)e=r[Math.floor(2*Math.random())](e);else{var t=Math.random();e=t>.9?r[2](e):t>.45?r[1](e):r[0](e)}return e})},a.helper.padEnd=function(e,r,t){"use strict";return r>>=0,t=String(t||" "),e.length>r?String(e):((r-=e.length)>t.length&&(t+=t.repeat(r/t.length)),String(e)+t.slice(0,r))},"undefined"==typeof console&&(console={warn:function(e){"use strict";alert(e)},log:function(e){"use strict";alert(e)},error:function(e){"use strict";throw e}}),a.helper.regexes={asteriskDashAndColon:/([*_:~])/g},a.helper.emojis={"+1":"πŸ‘","-1":"πŸ‘Ž",100:"πŸ’―",1234:"πŸ”’","1st_place_medal":"πŸ₯‡","2nd_place_medal":"πŸ₯ˆ","3rd_place_medal":"πŸ₯‰","8ball":"🎱",a:"πŸ…°οΈ",ab:"πŸ†Ž",abc:"πŸ”€",abcd:"πŸ”‘",accept:"πŸ‰‘",aerial_tramway:"🚑",airplane:"✈️",alarm_clock:"⏰",alembic:"βš—οΈ",alien:"πŸ‘½",ambulance:"πŸš‘",amphora:"🏺",anchor:"βš“οΈ",angel:"πŸ‘Ό",anger:"πŸ’’",angry:"😠",anguished:"😧",ant:"🐜",apple:"🍎",aquarius:"♒️",aries:"β™ˆοΈ",arrow_backward:"◀️",arrow_double_down:"⏬",arrow_double_up:"⏫",arrow_down:"⬇️",arrow_down_small:"πŸ”½",arrow_forward:"▢️",arrow_heading_down:"‡️",arrow_heading_up:"‴️",arrow_left:"⬅️",arrow_lower_left:"↙️",arrow_lower_right:"β†˜οΈ",arrow_right:"➑️",arrow_right_hook:"β†ͺ️",arrow_up:"⬆️",arrow_up_down:"↕️",arrow_up_small:"πŸ”Ό",arrow_upper_left:"↖️",arrow_upper_right:"↗️",arrows_clockwise:"πŸ”ƒ",arrows_counterclockwise:"πŸ”„",art:"🎨",articulated_lorry:"πŸš›",artificial_satellite:"πŸ›°",astonished:"😲",athletic_shoe:"πŸ‘Ÿ",atm:"🏧",atom_symbol:"βš›οΈ",avocado:"πŸ₯‘",b:"πŸ…±οΈ",baby:"πŸ‘Ά",baby_bottle:"🍼",baby_chick:"🐀",baby_symbol:"🚼",back:"πŸ”™",bacon:"πŸ₯“",badminton:"🏸",baggage_claim:"πŸ›„",baguette_bread:"πŸ₯–",balance_scale:"βš–οΈ",balloon:"🎈",ballot_box:"πŸ—³",ballot_box_with_check:"β˜‘οΈ",bamboo:"🎍",banana:"🍌",bangbang:"‼️",bank:"🏦",bar_chart:"πŸ“Š",barber:"πŸ’ˆ",baseball:"⚾️",basketball:"πŸ€",basketball_man:"⛹️",basketball_woman:"⛹️‍♀️",bat:"πŸ¦‡",bath:"πŸ›€",bathtub:"πŸ›",battery:"πŸ”‹",beach_umbrella:"πŸ–",bear:"🐻",bed:"πŸ›",bee:"🐝",beer:"🍺",beers:"🍻",beetle:"🐞",beginner:"πŸ”°",bell:"πŸ””",bellhop_bell:"πŸ›Ž",bento:"🍱",biking_man:"🚴",bike:"🚲",biking_woman:"🚴‍♀️",bikini:"πŸ‘™",biohazard:"☣️",bird:"🐦",birthday:"πŸŽ‚",black_circle:"⚫️",black_flag:"🏴",black_heart:"πŸ–€",black_joker:"πŸƒ",black_large_square:"⬛️",black_medium_small_square:"◾️",black_medium_square:"◼️",black_nib:"βœ’οΈ",black_small_square:"β–ͺ️",black_square_button:"πŸ”²",blonde_man:"πŸ‘±",blonde_woman:"πŸ‘±‍♀️",blossom:"🌼",blowfish:"🐑",blue_book:"πŸ“˜",blue_car:"πŸš™",blue_heart:"πŸ’™",blush:"😊",boar:"πŸ—",boat:"⛡️",bomb:"πŸ’£",book:"πŸ“–",bookmark:"πŸ”–",bookmark_tabs:"πŸ“‘",books:"πŸ“š",boom:"πŸ’₯",boot:"πŸ‘’",bouquet:"πŸ’",bowing_man:"πŸ™‡",bow_and_arrow:"🏹",bowing_woman:"πŸ™‡‍♀️",bowling:"🎳",boxing_glove:"πŸ₯Š",boy:"πŸ‘¦",bread:"🍞",bride_with_veil:"πŸ‘°",bridge_at_night:"πŸŒ‰",briefcase:"πŸ’Ό",broken_heart:"πŸ’”",bug:"πŸ›",building_construction:"πŸ—",bulb:"πŸ’‘",bullettrain_front:"πŸš…",bullettrain_side:"πŸš„",burrito:"🌯",bus:"🚌",business_suit_levitating:"πŸ•΄",busstop:"🚏",bust_in_silhouette:"πŸ‘€",busts_in_silhouette:"πŸ‘₯",butterfly:"πŸ¦‹",cactus:"🌡",cake:"🍰",calendar:"πŸ“†",call_me_hand:"πŸ€™",calling:"πŸ“²",camel:"🐫",camera:"πŸ“·",camera_flash:"πŸ“Έ",camping:"πŸ•",cancer:"♋️",candle:"πŸ•―",candy:"🍬",canoe:"πŸ›Ά",capital_abcd:"πŸ” ",capricorn:"♑️",car:"πŸš—",card_file_box:"πŸ—ƒ",card_index:"πŸ“‡",card_index_dividers:"πŸ—‚",carousel_horse:"🎠",carrot:"πŸ₯•",cat:"🐱",cat2:"🐈",cd:"πŸ’Ώ",chains:"β›“",champagne:"🍾",chart:"πŸ’Ή",chart_with_downwards_trend:"πŸ“‰",chart_with_upwards_trend:"πŸ“ˆ",checkered_flag:"🏁",cheese:"πŸ§€",cherries:"πŸ’",cherry_blossom:"🌸",chestnut:"🌰",chicken:"πŸ”",children_crossing:"🚸",chipmunk:"🐿",chocolate_bar:"🍫",christmas_tree:"πŸŽ„",church:"β›ͺ️",cinema:"🎦",circus_tent:"πŸŽͺ",city_sunrise:"πŸŒ‡",city_sunset:"πŸŒ†",cityscape:"πŸ™",cl:"πŸ†‘",clamp:"πŸ—œ",clap:"πŸ‘",clapper:"🎬",classical_building:"πŸ›",clinking_glasses:"πŸ₯‚",clipboard:"πŸ“‹",clock1:"πŸ•",clock10:"πŸ•™",clock1030:"πŸ•₯",clock11:"πŸ•š",clock1130:"πŸ•¦",clock12:"πŸ•›",clock1230:"πŸ•§",clock130:"πŸ•œ",clock2:"πŸ•‘",clock230:"πŸ•",clock3:"πŸ•’",clock330:"πŸ•ž",clock4:"πŸ•“",clock430:"πŸ•Ÿ",clock5:"πŸ•”",clock530:"πŸ• ",clock6:"πŸ••",clock630:"πŸ•‘",clock7:"πŸ•–",clock730:"πŸ•’",clock8:"πŸ•—",clock830:"πŸ•£",clock9:"πŸ•˜",clock930:"πŸ•€",closed_book:"πŸ“•",closed_lock_with_key:"πŸ”",closed_umbrella:"πŸŒ‚",cloud:"☁️",cloud_with_lightning:"🌩",cloud_with_lightning_and_rain:"β›ˆ",cloud_with_rain:"🌧",cloud_with_snow:"🌨",clown_face:"🀑",clubs:"♣️",cocktail:"🍸",coffee:"β˜•οΈ",coffin:"⚰️",cold_sweat:"😰",comet:"β˜„οΈ",computer:"πŸ’»",computer_mouse:"πŸ–±",confetti_ball:"🎊",confounded:"πŸ˜–",confused:"πŸ˜•",congratulations:"γŠ—οΈ",construction:"🚧",construction_worker_man:"πŸ‘·",construction_worker_woman:"πŸ‘·‍♀️",control_knobs:"πŸŽ›",convenience_store:"πŸͺ",cookie:"πŸͺ",cool:"πŸ†’",policeman:"πŸ‘",copyright:"©️",corn:"🌽",couch_and_lamp:"πŸ›‹",couple:"πŸ‘«",couple_with_heart_woman_man:"πŸ’‘",couple_with_heart_man_man:"πŸ‘¨‍❀️‍πŸ‘¨",couple_with_heart_woman_woman:"πŸ‘©‍❀️‍πŸ‘©",couplekiss_man_man:"πŸ‘¨‍❀️‍πŸ’‹‍πŸ‘¨",couplekiss_man_woman:"πŸ’",couplekiss_woman_woman:"πŸ‘©‍❀️‍πŸ’‹‍πŸ‘©",cow:"πŸ",cow2:"πŸ„",cowboy_hat_face:"🀠",crab:"πŸ¦€",crayon:"πŸ–",credit_card:"πŸ’³",crescent_moon:"πŸŒ™",cricket:"🏏",crocodile:"🐊",croissant:"πŸ₯",crossed_fingers:"🀞",crossed_flags:"🎌",crossed_swords:"βš”οΈ",crown:"πŸ‘‘",cry:"😒",crying_cat_face:"😿",crystal_ball:"πŸ”",cucumber:"πŸ₯’",cupid:"πŸ’˜",curly_loop:"➰",currency_exchange:"πŸ’±",curry:"πŸ›",custard:"πŸ",customs:"πŸ›ƒ",cyclone:"πŸŒ€",dagger:"πŸ—‘",dancer:"πŸ’ƒ",dancing_women:"πŸ‘―",dancing_men:"πŸ‘―‍♂️",dango:"🍑",dark_sunglasses:"πŸ•Ά",dart:"🎯",dash:"πŸ’¨",date:"πŸ“…",deciduous_tree:"🌳",deer:"🦌",department_store:"🏬",derelict_house:"🏚",desert:"🏜",desert_island:"🏝",desktop_computer:"πŸ–₯",male_detective:"πŸ•΅οΈ",diamond_shape_with_a_dot_inside:"πŸ’ ",diamonds:"♦️",disappointed:"😞",disappointed_relieved:"πŸ˜₯",dizzy:"πŸ’«",dizzy_face:"😡",do_not_litter:"🚯",dog:"🐢",dog2:"πŸ•",dollar:"πŸ’΅",dolls:"🎎",dolphin:"🐬",door:"πŸšͺ",doughnut:"🍩",dove:"πŸ•Š",dragon:"πŸ‰",dragon_face:"🐲",dress:"πŸ‘—",dromedary_camel:"πŸͺ",drooling_face:"🀀",droplet:"πŸ’§",drum:"πŸ₯",duck:"πŸ¦†",dvd:"πŸ“€","e-mail":"πŸ“§",eagle:"πŸ¦…",ear:"πŸ‘‚",ear_of_rice:"🌾",earth_africa:"🌍",earth_americas:"🌎",earth_asia:"🌏",egg:"πŸ₯š",eggplant:"πŸ†",eight_pointed_black_star:"✴️",eight_spoked_asterisk:"✳️",electric_plug:"πŸ”Œ",elephant:"🐘",email:"βœ‰οΈ",end:"πŸ”š",envelope_with_arrow:"πŸ“©",euro:"πŸ’Ά",european_castle:"🏰",european_post_office:"🏀",evergreen_tree:"🌲",exclamation:"❗️",expressionless:"πŸ˜‘",eye:"πŸ‘",eye_speech_bubble:"πŸ‘‍πŸ—¨",eyeglasses:"πŸ‘“",eyes:"πŸ‘€",face_with_head_bandage:"πŸ€•",face_with_thermometer:"πŸ€’",fist_oncoming:"πŸ‘Š",factory:"🏭",fallen_leaf:"πŸ‚",family_man_woman_boy:"πŸ‘ͺ",family_man_boy:"πŸ‘¨‍πŸ‘¦",family_man_boy_boy:"πŸ‘¨‍πŸ‘¦‍πŸ‘¦",family_man_girl:"πŸ‘¨‍πŸ‘§",family_man_girl_boy:"πŸ‘¨‍πŸ‘§‍πŸ‘¦",family_man_girl_girl:"πŸ‘¨‍πŸ‘§‍πŸ‘§",family_man_man_boy:"πŸ‘¨‍πŸ‘¨‍πŸ‘¦",family_man_man_boy_boy:"πŸ‘¨‍πŸ‘¨‍πŸ‘¦‍πŸ‘¦",family_man_man_girl:"πŸ‘¨‍πŸ‘¨‍πŸ‘§",family_man_man_girl_boy:"πŸ‘¨‍πŸ‘¨‍πŸ‘§‍πŸ‘¦",family_man_man_girl_girl:"πŸ‘¨‍πŸ‘¨‍πŸ‘§‍πŸ‘§",family_man_woman_boy_boy:"πŸ‘¨‍πŸ‘©‍πŸ‘¦‍πŸ‘¦",family_man_woman_girl:"πŸ‘¨‍πŸ‘©‍πŸ‘§",family_man_woman_girl_boy:"πŸ‘¨‍πŸ‘©‍πŸ‘§‍πŸ‘¦",family_man_woman_girl_girl:"πŸ‘¨‍πŸ‘©‍πŸ‘§‍πŸ‘§",family_woman_boy:"πŸ‘©‍πŸ‘¦",family_woman_boy_boy:"πŸ‘©‍πŸ‘¦‍πŸ‘¦",family_woman_girl:"πŸ‘©‍πŸ‘§",family_woman_girl_boy:"πŸ‘©‍πŸ‘§‍πŸ‘¦",family_woman_girl_girl:"πŸ‘©‍πŸ‘§‍πŸ‘§",family_woman_woman_boy:"πŸ‘©‍πŸ‘©‍πŸ‘¦",family_woman_woman_boy_boy:"πŸ‘©‍πŸ‘©‍πŸ‘¦‍πŸ‘¦",family_woman_woman_girl:"πŸ‘©‍πŸ‘©‍πŸ‘§",family_woman_woman_girl_boy:"πŸ‘©‍πŸ‘©‍πŸ‘§‍πŸ‘¦",family_woman_woman_girl_girl:"πŸ‘©‍πŸ‘©‍πŸ‘§‍πŸ‘§",fast_forward:"⏩",fax:"πŸ“ ",fearful:"😨",feet:"🐾",female_detective:"πŸ•΅οΈ‍♀️",ferris_wheel:"🎑",ferry:"β›΄",field_hockey:"πŸ‘",file_cabinet:"πŸ—„",file_folder:"πŸ“",film_projector:"πŸ“½",film_strip:"🎞",fire:"πŸ”₯",fire_engine:"πŸš’",fireworks:"πŸŽ†",first_quarter_moon:"πŸŒ“",first_quarter_moon_with_face:"πŸŒ›",fish:"🐟",fish_cake:"πŸ₯",fishing_pole_and_fish:"🎣",fist_raised:"✊",fist_left:"πŸ€›",fist_right:"🀜",flags:"🎏",flashlight:"πŸ”¦",fleur_de_lis:"⚜️",flight_arrival:"πŸ›¬",flight_departure:"πŸ›«",floppy_disk:"πŸ’Ύ",flower_playing_cards:"🎴",flushed:"😳",fog:"🌫",foggy:"🌁",football:"🏈",footprints:"πŸ‘£",fork_and_knife:"🍴",fountain:"⛲️",fountain_pen:"πŸ–‹",four_leaf_clover:"πŸ€",fox_face:"🦊",framed_picture:"πŸ–Ό",free:"πŸ†“",fried_egg:"🍳",fried_shrimp:"🍀",fries:"🍟",frog:"🐸",frowning:"😦",frowning_face:"☹️",frowning_man:"πŸ™‍♂️",frowning_woman:"πŸ™",middle_finger:"πŸ–•",fuelpump:"⛽️",full_moon:"πŸŒ•",full_moon_with_face:"🌝",funeral_urn:"⚱️",game_die:"🎲",gear:"βš™οΈ",gem:"πŸ’Ž",gemini:"β™ŠοΈ",ghost:"πŸ‘»",gift:"🎁",gift_heart:"πŸ’",girl:"πŸ‘§",globe_with_meridians:"🌐",goal_net:"πŸ₯…",goat:"🐐",golf:"⛳️",golfing_man:"🏌️",golfing_woman:"🏌️‍♀️",gorilla:"🦍",grapes:"πŸ‡",green_apple:"🍏",green_book:"πŸ“—",green_heart:"πŸ’š",green_salad:"πŸ₯—",grey_exclamation:"❕",grey_question:"❔",grimacing:"😬",grin:"😁",grinning:"πŸ˜€",guardsman:"πŸ’‚",guardswoman:"πŸ’‚‍♀️",guitar:"🎸",gun:"πŸ”«",haircut_woman:"πŸ’‡",haircut_man:"πŸ’‡‍♂️",hamburger:"πŸ”",hammer:"πŸ”¨",hammer_and_pick:"βš’",hammer_and_wrench:"πŸ› ",hamster:"🐹",hand:"βœ‹",handbag:"πŸ‘œ",handshake:"🀝",hankey:"πŸ’©",hatched_chick:"πŸ₯",hatching_chick:"🐣",headphones:"🎧",hear_no_evil:"πŸ™‰",heart:"❀️",heart_decoration:"πŸ’Ÿ",heart_eyes:"😍",heart_eyes_cat:"😻",heartbeat:"πŸ’“",heartpulse:"πŸ’—",hearts:"β™₯️",heavy_check_mark:"βœ”οΈ",heavy_division_sign:"βž—",heavy_dollar_sign:"πŸ’²",heavy_heart_exclamation:"❣️",heavy_minus_sign:"βž–",heavy_multiplication_x:"βœ–οΈ",heavy_plus_sign:"βž•",helicopter:"🚁",herb:"🌿",hibiscus:"🌺",high_brightness:"πŸ”†",high_heel:"πŸ‘ ",hocho:"πŸ”ͺ",hole:"πŸ•³",honey_pot:"🍯",horse:"🐴",horse_racing:"πŸ‡",hospital:"πŸ₯",hot_pepper:"🌢",hotdog:"🌭",hotel:"🏨",hotsprings:"♨️",hourglass:"βŒ›οΈ",hourglass_flowing_sand:"⏳",house:"🏠",house_with_garden:"🏑",houses:"🏘",hugs:"πŸ€—",hushed:"😯",ice_cream:"🍨",ice_hockey:"πŸ’",ice_skate:"β›Έ",icecream:"🍦",id:"πŸ†”",ideograph_advantage:"πŸ‰",imp:"πŸ‘Ώ",inbox_tray:"πŸ“₯",incoming_envelope:"πŸ“¨",tipping_hand_woman:"πŸ’",information_source:"ℹ️",innocent:"πŸ˜‡",interrobang:"⁉️",iphone:"πŸ“±",izakaya_lantern:"πŸ",jack_o_lantern:"πŸŽƒ",japan:"πŸ—Ύ",japanese_castle:"🏯",japanese_goblin:"πŸ‘Ί",japanese_ogre:"πŸ‘Ή",jeans:"πŸ‘–",joy:"πŸ˜‚",joy_cat:"😹",joystick:"πŸ•Ή",kaaba:"πŸ•‹",key:"πŸ”‘",keyboard:"⌨️",keycap_ten:"πŸ”Ÿ",kick_scooter:"πŸ›΄",kimono:"πŸ‘˜",kiss:"πŸ’‹",kissing:"πŸ˜—",kissing_cat:"😽",kissing_closed_eyes:"😚",kissing_heart:"😘",kissing_smiling_eyes:"πŸ˜™",kiwi_fruit:"πŸ₯",koala:"🐨",koko:"🈁",label:"🏷",large_blue_circle:"πŸ”΅",large_blue_diamond:"πŸ”·",large_orange_diamond:"πŸ”Ά",last_quarter_moon:"πŸŒ—",last_quarter_moon_with_face:"🌜",latin_cross:"✝️",laughing:"πŸ˜†",leaves:"πŸƒ",ledger:"πŸ“’",left_luggage:"πŸ›…",left_right_arrow:"↔️",leftwards_arrow_with_hook:"↩️",lemon:"πŸ‹",leo:"β™ŒοΈ",leopard:"πŸ†",level_slider:"🎚",libra:"β™ŽοΈ",light_rail:"🚈",link:"πŸ”—",lion:"🦁",lips:"πŸ‘„",lipstick:"πŸ’„",lizard:"🦎",lock:"πŸ”’",lock_with_ink_pen:"πŸ”",lollipop:"🍭",loop:"➿",loud_sound:"πŸ”Š",loudspeaker:"πŸ“’",love_hotel:"🏩",love_letter:"πŸ’Œ",low_brightness:"πŸ”…",lying_face:"πŸ€₯",m:"Ⓜ️",mag:"πŸ”",mag_right:"πŸ”Ž",mahjong:"πŸ€„οΈ",mailbox:"πŸ“«",mailbox_closed:"πŸ“ͺ",mailbox_with_mail:"πŸ“¬",mailbox_with_no_mail:"πŸ“­",man:"πŸ‘¨",man_artist:"πŸ‘¨‍🎨",man_astronaut:"πŸ‘¨‍πŸš€",man_cartwheeling:"🀸‍♂️",man_cook:"πŸ‘¨‍🍳",man_dancing:"πŸ•Ί",man_facepalming:"🀦‍♂️",man_factory_worker:"πŸ‘¨‍🏭",man_farmer:"πŸ‘¨‍🌾",man_firefighter:"πŸ‘¨‍πŸš’",man_health_worker:"πŸ‘¨‍βš•οΈ",man_in_tuxedo:"🀡",man_judge:"πŸ‘¨‍βš–οΈ",man_juggling:"🀹‍♂️",man_mechanic:"πŸ‘¨‍πŸ”§",man_office_worker:"πŸ‘¨‍πŸ’Ό",man_pilot:"πŸ‘¨‍✈️",man_playing_handball:"🀾‍♂️",man_playing_water_polo:"🀽‍♂️",man_scientist:"πŸ‘¨‍πŸ”¬",man_shrugging:"🀷‍♂️",man_singer:"πŸ‘¨‍🎀",man_student:"πŸ‘¨‍πŸŽ“",man_teacher:"πŸ‘¨‍🏫",man_technologist:"πŸ‘¨‍πŸ’»",man_with_gua_pi_mao:"πŸ‘²",man_with_turban:"πŸ‘³",tangerine:"🍊",mans_shoe:"πŸ‘ž",mantelpiece_clock:"πŸ•°",maple_leaf:"🍁",martial_arts_uniform:"πŸ₯‹",mask:"😷",massage_woman:"πŸ’†",massage_man:"πŸ’†‍♂️",meat_on_bone:"πŸ–",medal_military:"πŸŽ–",medal_sports:"πŸ…",mega:"πŸ“£",melon:"🍈",memo:"πŸ“",men_wrestling:"🀼‍♂️",menorah:"πŸ•Ž",mens:"🚹",metal:"🀘",metro:"πŸš‡",microphone:"🎀",microscope:"πŸ”¬",milk_glass:"πŸ₯›",milky_way:"🌌",minibus:"🚐",minidisc:"πŸ’½",mobile_phone_off:"πŸ“΄",money_mouth_face:"πŸ€‘",money_with_wings:"πŸ’Έ",moneybag:"πŸ’°",monkey:"πŸ’",monkey_face:"🐡",monorail:"🚝",moon:"πŸŒ”",mortar_board:"πŸŽ“",mosque:"πŸ•Œ",motor_boat:"πŸ›₯",motor_scooter:"πŸ›΅",motorcycle:"🏍",motorway:"πŸ›£",mount_fuji:"πŸ—»",mountain:"β›°",mountain_biking_man:"🚡",mountain_biking_woman:"🚡‍♀️",mountain_cableway:"🚠",mountain_railway:"🚞",mountain_snow:"πŸ”",mouse:"🐭",mouse2:"🐁",movie_camera:"πŸŽ₯",moyai:"πŸ—Ώ",mrs_claus:"🀢",muscle:"πŸ’ͺ",mushroom:"πŸ„",musical_keyboard:"🎹",musical_note:"🎡",musical_score:"🎼",mute:"πŸ”‡",nail_care:"πŸ’…",name_badge:"πŸ“›",national_park:"🏞",nauseated_face:"🀒",necktie:"πŸ‘”",negative_squared_cross_mark:"❎",nerd_face:"πŸ€“",neutral_face:"😐",new:"πŸ†•",new_moon:"πŸŒ‘",new_moon_with_face:"🌚",newspaper:"πŸ“°",newspaper_roll:"πŸ—ž",next_track_button:"⏭",ng:"πŸ†–",no_good_man:"πŸ™…‍♂️",no_good_woman:"πŸ™…",night_with_stars:"πŸŒƒ",no_bell:"πŸ”•",no_bicycles:"🚳",no_entry:"⛔️",no_entry_sign:"🚫",no_mobile_phones:"πŸ“΅",no_mouth:"😢",no_pedestrians:"🚷",no_smoking:"🚭","non-potable_water":"🚱",nose:"πŸ‘ƒ",notebook:"πŸ““",notebook_with_decorative_cover:"πŸ“”",notes:"🎢",nut_and_bolt:"πŸ”©",o:"⭕️",o2:"πŸ…ΎοΈ",ocean:"🌊",octopus:"πŸ™",oden:"🍒",office:"🏒",oil_drum:"πŸ›’",ok:"πŸ†—",ok_hand:"πŸ‘Œ",ok_man:"πŸ™†‍♂️",ok_woman:"πŸ™†",old_key:"πŸ—",older_man:"πŸ‘΄",older_woman:"πŸ‘΅",om:"πŸ•‰",on:"πŸ”›",oncoming_automobile:"🚘",oncoming_bus:"🚍",oncoming_police_car:"πŸš”",oncoming_taxi:"πŸš–",open_file_folder:"πŸ“‚",open_hands:"πŸ‘",open_mouth:"πŸ˜",open_umbrella:"β˜‚οΈ",ophiuchus:"β›Ž",orange_book:"πŸ“™",orthodox_cross:"☦️",outbox_tray:"πŸ“€",owl:"πŸ¦‰",ox:"πŸ‚",package:"πŸ“¦",page_facing_up:"πŸ“„",page_with_curl:"πŸ“ƒ",pager:"πŸ“Ÿ",paintbrush:"πŸ–Œ",palm_tree:"🌴",pancakes:"πŸ₯ž",panda_face:"🐼",paperclip:"πŸ“Ž",paperclips:"πŸ–‡",parasol_on_ground:"β›±",parking:"πŸ…ΏοΈ",part_alternation_mark:"〽️",partly_sunny:"⛅️",passenger_ship:"πŸ›³",passport_control:"πŸ›‚",pause_button:"⏸",peace_symbol:"β˜οΈ",peach:"πŸ‘",peanuts:"πŸ₯œ",pear:"🍐",pen:"πŸ–Š",pencil2:"✏️",penguin:"🐧",pensive:"πŸ˜”",performing_arts:"🎭",persevere:"😣",person_fencing:"🀺",pouting_woman:"πŸ™Ž",phone:"☎️",pick:"⛏",pig:"🐷",pig2:"πŸ–",pig_nose:"🐽",pill:"πŸ’Š",pineapple:"🍍",ping_pong:"πŸ“",pisces:"♓️",pizza:"πŸ•",place_of_worship:"πŸ›",plate_with_cutlery:"🍽",play_or_pause_button:"⏯",point_down:"πŸ‘‡",point_left:"πŸ‘ˆ",point_right:"πŸ‘‰",point_up:"☝️",point_up_2:"πŸ‘†",police_car:"πŸš“",policewoman:"πŸ‘‍♀️",poodle:"🐩",popcorn:"🍿",post_office:"🏣",postal_horn:"πŸ“―",postbox:"πŸ“",potable_water:"🚰",potato:"πŸ₯”",pouch:"πŸ‘",poultry_leg:"πŸ—",pound:"πŸ’·",rage:"😑",pouting_cat:"😾",pouting_man:"πŸ™Ž‍♂️",pray:"πŸ™",prayer_beads:"πŸ“Ώ",pregnant_woman:"🀰",previous_track_button:"β",prince:"🀴",princess:"πŸ‘Έ",printer:"πŸ–¨",purple_heart:"πŸ’œ",purse:"πŸ‘›",pushpin:"πŸ“Œ",put_litter_in_its_place:"πŸš",question:"❓",rabbit:"🐰",rabbit2:"πŸ‡",racehorse:"🐎",racing_car:"🏎",radio:"πŸ“»",radio_button:"πŸ”˜",radioactive:"☒️",railway_car:"πŸšƒ",railway_track:"πŸ›€",rainbow:"🌈",rainbow_flag:"🏳️‍🌈",raised_back_of_hand:"🀚",raised_hand_with_fingers_splayed:"πŸ–",raised_hands:"πŸ™Œ",raising_hand_woman:"πŸ™‹",raising_hand_man:"πŸ™‹‍♂️",ram:"🐏",ramen:"🍜",rat:"πŸ€",record_button:"⏺",recycle:"♻️",red_circle:"πŸ”΄",registered:"Β️",relaxed:"☺️",relieved:"😌",reminder_ribbon:"πŸŽ—",repeat:"πŸ”",repeat_one:"πŸ”‚",rescue_worker_helmet:"β›‘",restroom:"🚻",revolving_hearts:"πŸ’ž",rewind:"βͺ",rhinoceros:"🦏",ribbon:"πŸŽ€",rice:"🍚",rice_ball:"πŸ™",rice_cracker:"🍘",rice_scene:"πŸŽ‘",right_anger_bubble:"πŸ—―",ring:"πŸ’",robot:"πŸ€–",rocket:"πŸš€",rofl:"🀣",roll_eyes:"πŸ™„",roller_coaster:"🎒",rooster:"πŸ“",rose:"🌹",rosette:"🏡",rotating_light:"🚨",round_pushpin:"πŸ“",rowing_man:"🚣",rowing_woman:"🚣‍♀️",rugby_football:"πŸ‰",running_man:"πŸƒ",running_shirt_with_sash:"🎽",running_woman:"πŸƒ‍♀️",sa:"πŸˆ‚οΈ",sagittarius:"♐️",sake:"🍢",sandal:"πŸ‘‘",santa:"πŸŽ…",satellite:"πŸ“‘",saxophone:"🎷",school:"🏫",school_satchel:"πŸŽ’",scissors:"βœ‚οΈ",scorpion:"πŸ¦‚",scorpius:"♏️",scream:"😱",scream_cat:"πŸ™€",scroll:"πŸ“œ",seat:"πŸ’Ί",secret:"γŠ™οΈ",see_no_evil:"πŸ™ˆ",seedling:"🌱",selfie:"🀳",shallow_pan_of_food:"πŸ₯˜",shamrock:"☘️",shark:"🦈",shaved_ice:"🍧",sheep:"πŸ‘",shell:"🐚",shield:"πŸ›‘",shinto_shrine:"β›©",ship:"🚒",shirt:"πŸ‘•",shopping:"πŸ›",shopping_cart:"πŸ›’",shower:"🚿",shrimp:"🦐",signal_strength:"πŸ“Ά",six_pointed_star:"πŸ”―",ski:"🎿",skier:"β›·",skull:"πŸ’€",skull_and_crossbones:"☠️",sleeping:"😴",sleeping_bed:"πŸ›Œ",sleepy:"πŸ˜ͺ",slightly_frowning_face:"πŸ™",slightly_smiling_face:"πŸ™‚",slot_machine:"🎰",small_airplane:"πŸ›©",small_blue_diamond:"πŸ”Ή",small_orange_diamond:"πŸ”Έ",small_red_triangle:"πŸ”Ί",small_red_triangle_down:"πŸ”»",smile:"πŸ˜„",smile_cat:"😸",smiley:"πŸ˜ƒ",smiley_cat:"😺",smiling_imp:"😈",smirk:"😏",smirk_cat:"😼",smoking:"🚬",snail:"🐌",snake:"🐍",sneezing_face:"🀧",snowboarder:"πŸ‚",snowflake:"❄️",snowman:"⛄️",snowman_with_snow:"β˜ƒοΈ",sob:"😭",soccer:"⚽️",soon:"πŸ”œ",sos:"πŸ†˜",sound:"πŸ”‰",space_invader:"πŸ‘Ύ",spades:"♠️",spaghetti:"🍝",sparkle:"❇️",sparkler:"πŸŽ‡",sparkles:"✨",sparkling_heart:"πŸ’–",speak_no_evil:"πŸ™Š",speaker:"πŸ”ˆ",speaking_head:"πŸ—£",speech_balloon:"πŸ’¬",speedboat:"🚀",spider:"πŸ•·",spider_web:"πŸ•Έ",spiral_calendar:"πŸ—“",spiral_notepad:"πŸ—’",spoon:"πŸ₯„",squid:"πŸ¦‘",stadium:"🏟",star:"⭐️",star2:"🌟",star_and_crescent:"β˜ͺ️",star_of_david:"✑️",stars:"🌠",station:"πŸš‰",statue_of_liberty:"πŸ—½",steam_locomotive:"πŸš‚",stew:"🍲",stop_button:"⏹",stop_sign:"πŸ›‘",stopwatch:"⏱",straight_ruler:"πŸ“",strawberry:"πŸ“",stuck_out_tongue:"πŸ˜›",stuck_out_tongue_closed_eyes:"😝",stuck_out_tongue_winking_eye:"😜",studio_microphone:"πŸŽ™",stuffed_flatbread:"πŸ₯™",sun_behind_large_cloud:"πŸŒ₯",sun_behind_rain_cloud:"🌦",sun_behind_small_cloud:"🌀",sun_with_face:"🌞",sunflower:"🌻",sunglasses:"😎",sunny:"β˜€οΈ",sunrise:"πŸŒ…",sunrise_over_mountains:"πŸŒ„",surfing_man:"πŸ„",surfing_woman:"πŸ„‍♀️",sushi:"🍣",suspension_railway:"🚟",sweat:"πŸ˜“",sweat_drops:"πŸ’¦",sweat_smile:"πŸ˜…",sweet_potato:"🍠",swimming_man:"🏊",swimming_woman:"🏊‍♀️",symbols:"πŸ”£",synagogue:"πŸ•",syringe:"πŸ’‰",taco:"πŸŒ",tada:"πŸŽ‰",tanabata_tree:"πŸŽ‹",taurus:"♉️",taxi:"πŸš•",tea:"🍡",telephone_receiver:"πŸ“ž",telescope:"πŸ”­",tennis:"🎾",tent:"⛺️",thermometer:"🌑",thinking:"πŸ€”",thought_balloon:"πŸ’­",ticket:"🎫",tickets:"🎟",tiger:"🐯",tiger2:"πŸ…",timer_clock:"⏲",tipping_hand_man:"πŸ’‍♂️",tired_face:"😫",tm:"ℒ️",toilet:"🚽",tokyo_tower:"πŸ—Ό",tomato:"πŸ…",tongue:"πŸ‘…",top:"πŸ”",tophat:"🎩",tornado:"πŸŒͺ",trackball:"πŸ–²",tractor:"🚜",traffic_light:"πŸš₯",train:"πŸš‹",train2:"πŸš†",tram:"🚊",triangular_flag_on_post:"🚩",triangular_ruler:"πŸ“",trident:"πŸ”±",triumph:"😀",trolleybus:"🚎",trophy:"πŸ†",tropical_drink:"🍹",tropical_fish:"🐠",truck:"🚚",trumpet:"🎺",tulip:"🌷",tumbler_glass:"πŸ₯ƒ",turkey:"πŸ¦ƒ",turtle:"🐒",tv:"πŸ“Ί",twisted_rightwards_arrows:"πŸ”€",two_hearts:"πŸ’•",two_men_holding_hands:"πŸ‘¬",two_women_holding_hands:"πŸ‘­",u5272:"🈹",u5408:"🈴",u55b6:"🈺",u6307:"🈯️",u6708:"🈷️",u6709:"🈢",u6e80:"🈡",u7121:"🈚️",u7533:"🈸",u7981:"🈲",u7a7a:"🈳",umbrella:"β˜”οΈ",unamused:"πŸ˜’",underage:"πŸ”ž",unicorn:"πŸ¦„",unlock:"πŸ”“",up:"πŸ†™",upside_down_face:"πŸ™ƒ",v:"✌️",vertical_traffic_light:"🚦",vhs:"πŸ“Ό",vibration_mode:"πŸ“³",video_camera:"πŸ“Ή",video_game:"πŸŽ",violin:"🎻",virgo:"♍️",volcano:"πŸŒ‹",volleyball:"🏐",vs:"πŸ†š",vulcan_salute:"πŸ––",walking_man:"🚢",walking_woman:"🚢‍♀️",waning_crescent_moon:"🌘",waning_gibbous_moon:"πŸŒ–",warning:"⚠️",wastebasket:"πŸ—‘",watch:"⌚️",water_buffalo:"πŸƒ",watermelon:"πŸ‰",wave:"πŸ‘‹",wavy_dash:"〰️",waxing_crescent_moon:"πŸŒ’",wc:"🚾",weary:"😩",wedding:"πŸ’’",weight_lifting_man:"πŸ‹οΈ",weight_lifting_woman:"πŸ‹οΈ‍♀️",whale:"🐳",whale2:"πŸ‹",wheel_of_dharma:"☸️",wheelchair:"♿️",white_check_mark:"βœ…",white_circle:"βšͺ️",white_flag:"🏳️",white_flower:"πŸ’",white_large_square:"⬜️",white_medium_small_square:"◽️",white_medium_square:"◻️",white_small_square:"▫️",white_square_button:"πŸ”³",wilted_flower:"πŸ₯€",wind_chime:"🎐",wind_face:"🌬",wine_glass:"🍷",wink:"πŸ˜‰",wolf:"🐺",woman:"πŸ‘©",woman_artist:"πŸ‘©‍🎨",woman_astronaut:"πŸ‘©‍πŸš€",woman_cartwheeling:"🀸‍♀️",woman_cook:"πŸ‘©‍🍳",woman_facepalming:"🀦‍♀️",woman_factory_worker:"πŸ‘©‍🏭",woman_farmer:"πŸ‘©‍🌾",woman_firefighter:"πŸ‘©‍πŸš’",woman_health_worker:"πŸ‘©‍βš•οΈ",woman_judge:"πŸ‘©‍βš–οΈ",woman_juggling:"🀹‍♀️",woman_mechanic:"πŸ‘©‍πŸ”§",woman_office_worker:"πŸ‘©‍πŸ’Ό",woman_pilot:"πŸ‘©‍✈️",woman_playing_handball:"🀾‍♀️",woman_playing_water_polo:"🀽‍♀️",woman_scientist:"πŸ‘©‍πŸ”¬",woman_shrugging:"🀷‍♀️",woman_singer:"πŸ‘©‍🎀",woman_student:"πŸ‘©‍πŸŽ“",woman_teacher:"πŸ‘©‍🏫",woman_technologist:"πŸ‘©‍πŸ’»",woman_with_turban:"πŸ‘³‍♀️",womans_clothes:"πŸ‘š",womans_hat:"πŸ‘’",women_wrestling:"🀼‍♀️",womens:"🚺",world_map:"πŸ—Ί",worried:"😟",wrench:"πŸ”§",writing_hand:"✍️",x:"❌",yellow_heart:"πŸ’›",yen:"πŸ’΄",yin_yang:"☯️",yum:"πŸ˜‹",zap:"⚑️",zipper_mouth_face:"🀐",zzz:"πŸ’€",octocat:':octocat:',showdown:"S"},a.Converter=function(e){"use strict";function t(e,t){if(t=t||null,a.helper.isString(e)){if(e=a.helper.stdExtName(e),t=e,a.extensions[e])return console.warn("DEPRECATION WARNING: "+e+" is an old extension that uses a deprecated loading method.Please inform the developer that the extension should be updated!"),void function(e,t){"function"==typeof e&&(e=e(new a.Converter));a.helper.isArray(e)||(e=[e]);var n=r(e,t);if(!n.valid)throw Error(n.error);for(var s=0;s[ \t]+Β¨NBSP;<"),!r){if(!window||!window.document)throw new Error("HTMLParser is undefined. If in a webworker or nodejs environment, you need to provide a WHATWG DOM and HTML such as JSDOM");r=window.document}var n=r.createElement("div");n.innerHTML=e;var s={preList:function(e){for(var r=e.querySelectorAll("pre"),t=[],n=0;n'}else t.push(r[n].innerHTML),r[n].innerHTML="",r[n].setAttribute("prenum",n.toString());return t}(n)};t(n);for(var o=n.childNodes,i="",l=0;l? ?(['"].*['"])?\)$/m)>-1)o="";else if(!o){if(s||(s=n.toLowerCase().replace(/ ?\n/g," ")),o="#"+s,a.helper.isUndefined(t.gUrls[s]))return e;o=t.gUrls[s],a.helper.isUndefined(t.gTitles[s])||(c=t.gTitles[s])}var u='"};return e=(e=t.converter._dispatch("anchors.before",e,r,t)).replace(/\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g,n),e=e.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,n),e=e.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]??(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,n),e=e.replace(/\[([^\[\]]+)]()()()()()/g,n),r.ghMentions&&(e=e.replace(/(^|\s)(\\)?(@([a-z\d]+(?:[a-z\d.-]+?[a-z\d]+)*))/gim,function(e,t,n,s,o){if("\\"===n)return t+s;if(!a.helper.isString(r.ghMentionsLink))throw new Error("ghMentionsLink option must be a string");var i=r.ghMentionsLink.replace(/\{u}/g,o),l="";return r.openLinksInNewWindow&&(l=' rel="noopener noreferrer" target="Β¨E95Eblank"'),t+'"+s+""})),e=t.converter._dispatch("anchors.after",e,r,t)});var u=/([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+?\.[^'">\s]+?)()(\1)?(?=\s|$)(?!["<>])/gi,d=/([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+?)([.!?,()\[\]])?(\1)?(?=\s|$)(?!["<>])/gi,p=/()<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)()>()/gi,h=/(^|\s)(?:mailto:)?([A-Za-z0-9!#$%&'*+-/=?^_`{|}~.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?=$|\s)/gim,_=/<()(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,g=function(e){"use strict";return function(r,t,n,s,o,i,l){var c=n=n.replace(a.helper.regexes.asteriskDashAndColon,a.helper.escapeCharactersCallback),u="",d="",p=t||"",h=l||"";return/^www\./i.test(n)&&(n=n.replace(/^www\./i,"http://www.")),e.excludeTrailingPunctuationFromURLs&&i&&(u=i),e.openLinksInNewWindow&&(d=' rel="noopener noreferrer" target="Β¨E95Eblank"'),p+'"+c+""+u+h}},m=function(e,r){"use strict";return function(t,n,s){var o="mailto:";return n=n||"",s=a.subParser("unescapeSpecialChars")(s,e,r),e.encodeEmails?(o=a.helper.encodeEmailAddress(o+s),s=a.helper.encodeEmailAddress(s)):o+=s,n+''+s+""}};a.subParser("autoLinks",function(e,r,t){"use strict";return e=t.converter._dispatch("autoLinks.before",e,r,t),e=e.replace(p,g(r)),e=e.replace(_,m(r,t)),e=t.converter._dispatch("autoLinks.after",e,r,t)}),a.subParser("simplifiedAutoLinks",function(e,r,t){"use strict";return r.simplifiedAutoLink?(e=t.converter._dispatch("simplifiedAutoLinks.before",e,r,t),e=r.excludeTrailingPunctuationFromURLs?e.replace(d,g(r)):e.replace(u,g(r)),e=e.replace(h,m(r,t)),e=t.converter._dispatch("simplifiedAutoLinks.after",e,r,t)):e}),a.subParser("blockGamut",function(e,r,t){"use strict";return e=t.converter._dispatch("blockGamut.before",e,r,t),e=a.subParser("blockQuotes")(e,r,t),e=a.subParser("headers")(e,r,t),e=a.subParser("horizontalRule")(e,r,t),e=a.subParser("lists")(e,r,t),e=a.subParser("codeBlocks")(e,r,t),e=a.subParser("tables")(e,r,t),e=a.subParser("hashHTMLBlocks")(e,r,t),e=a.subParser("paragraphs")(e,r,t),e=t.converter._dispatch("blockGamut.after",e,r,t)}),a.subParser("blockQuotes",function(e,r,t){"use strict";e=t.converter._dispatch("blockQuotes.before",e,r,t),e+="\n\n";var n=/(^ {0,3}>[ \t]?.+\n(.+\n)*\n*)+/gm;return r.splitAdjacentBlockquotes&&(n=/^ {0,3}>[\s\S]*?(?:\n\n)/gm),e=e.replace(n,function(e){return e=e.replace(/^[ \t]*>[ \t]?/gm,""),e=e.replace(/Β¨0/g,""),e=e.replace(/^[ \t]+$/gm,""),e=a.subParser("githubCodeBlocks")(e,r,t),e=a.subParser("blockGamut")(e,r,t),e=e.replace(/(^|\n)/g,"$1 "),e=e.replace(/(\s*
[^\r]+?<\/pre>)/gm,function(e,r){var t=r;return t=t.replace(/^  /gm,"Β¨0"),t=t.replace(/Β¨0/g,"")}),a.subParser("hashBlock")("
\n"+e+"\n
",r,t)}),e=t.converter._dispatch("blockQuotes.after",e,r,t)}),a.subParser("codeBlocks",function(e,r,t){"use strict";e=t.converter._dispatch("codeBlocks.before",e,r,t);return e=(e+="Β¨0").replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=Β¨0))/g,function(e,n,s){var o=n,i=s,l="\n";return o=a.subParser("outdent")(o,r,t),o=a.subParser("encodeCode")(o,r,t),o=a.subParser("detab")(o,r,t),o=o.replace(/^\n+/g,""),o=o.replace(/\n+$/g,""),r.omitExtraWLInCodeBlocks&&(l=""),o="
"+o+l+"
",a.subParser("hashBlock")(o,r,t)+i}),e=e.replace(/¨0/,""),e=t.converter._dispatch("codeBlocks.after",e,r,t)}),a.subParser("codeSpans",function(e,r,t){"use strict";return void 0===(e=t.converter._dispatch("codeSpans.before",e,r,t))&&(e=""),e=e.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(e,n,s,o){var i=o;return i=i.replace(/^([ \t]*)/g,""),i=i.replace(/[ \t]*$/g,""),i=a.subParser("encodeCode")(i,r,t),i=n+""+i+"",i=a.subParser("hashHTMLSpans")(i,r,t)}),e=t.converter._dispatch("codeSpans.after",e,r,t)}),a.subParser("completeHTMLDocument",function(e,r,t){"use strict";if(!r.completeHTMLDocument)return e;e=t.converter._dispatch("completeHTMLDocument.before",e,r,t);var a="html",n="\n",s="",o='\n',i="",l="";void 0!==t.metadata.parsed.doctype&&(n="\n","html"!==(a=t.metadata.parsed.doctype.toString().toLowerCase())&&"html5"!==a||(o=''));for(var c in t.metadata.parsed)if(t.metadata.parsed.hasOwnProperty(c))switch(c.toLowerCase()){case"doctype":break;case"title":s=""+t.metadata.parsed.title+"\n";break;case"charset":o="html"===a||"html5"===a?'\n':'\n';break;case"language":case"lang":i=' lang="'+t.metadata.parsed[c]+'"',l+='\n';break;default:l+='\n'}return e=n+"\n\n"+s+o+l+"\n\n"+e.trim()+"\n\n",e=t.converter._dispatch("completeHTMLDocument.after",e,r,t)}),a.subParser("detab",function(e,r,t){"use strict";return e=t.converter._dispatch("detab.before",e,r,t),e=e.replace(/\t(?=\t)/g," "),e=e.replace(/\t/g,"¨A¨B"),e=e.replace(/¨B(.+?)¨A/g,function(e,r){for(var t=r,a=4-t.length%4,n=0;n/g,">"),e=t.converter._dispatch("encodeAmpsAndAngles.after",e,r,t)}),a.subParser("encodeBackslashEscapes",function(e,r,t){"use strict";return e=t.converter._dispatch("encodeBackslashEscapes.before",e,r,t),e=e.replace(/\\(\\)/g,a.helper.escapeCharactersCallback),e=e.replace(/\\([`*_{}\[\]()>#+.!~=|-])/g,a.helper.escapeCharactersCallback),e=t.converter._dispatch("encodeBackslashEscapes.after",e,r,t)}),a.subParser("encodeCode",function(e,r,t){"use strict";return e=t.converter._dispatch("encodeCode.before",e,r,t),e=e.replace(/&/g,"&").replace(//g,">").replace(/([*_{}\[\]\\=~-])/g,a.helper.escapeCharactersCallback),e=t.converter._dispatch("encodeCode.after",e,r,t)}),a.subParser("escapeSpecialCharsWithinTagAttributes",function(e,r,t){"use strict";return e=(e=t.converter._dispatch("escapeSpecialCharsWithinTagAttributes.before",e,r,t)).replace(/<\/?[a-z\d_:-]+(?:[\s]+[\s\S]+?)?>/gi,function(e){return e.replace(/(.)<\/?code>(?=.)/g,"$1`").replace(/([\\`*_~=|])/g,a.helper.escapeCharactersCallback)}),e=e.replace(/-]|-[^>])(?:[^-]|-[^-])*)--)>/gi,function(e){return e.replace(/([\\`*_~=|])/g,a.helper.escapeCharactersCallback)}),e=t.converter._dispatch("escapeSpecialCharsWithinTagAttributes.after",e,r,t)}),a.subParser("githubCodeBlocks",function(e,r,t){"use strict";return r.ghCodeBlocks?(e=t.converter._dispatch("githubCodeBlocks.before",e,r,t),e+="¨0",e=e.replace(/(?:^|\n)(?: {0,3})(```+|~~~+)(?: *)([^\s`~]*)\n([\s\S]*?)\n(?: {0,3})\1/g,function(e,n,s,o){var i=r.omitExtraWLInCodeBlocks?"":"\n";return o=a.subParser("encodeCode")(o,r,t),o=a.subParser("detab")(o,r,t),o=o.replace(/^\n+/g,""),o=o.replace(/\n+$/g,""),o="
"+o+i+"
",o=a.subParser("hashBlock")(o,r,t),"\n\n¨G"+(t.ghCodeBlocks.push({text:e,codeblock:o})-1)+"G\n\n"}),e=e.replace(/¨0/,""),t.converter._dispatch("githubCodeBlocks.after",e,r,t)):e}),a.subParser("hashBlock",function(e,r,t){"use strict";return e=t.converter._dispatch("hashBlock.before",e,r,t),e=e.replace(/(^\n+|\n+$)/g,""),e="\n\n¨K"+(t.gHtmlBlocks.push(e)-1)+"K\n\n",e=t.converter._dispatch("hashBlock.after",e,r,t)}),a.subParser("hashCodeTags",function(e,r,t){"use strict";e=t.converter._dispatch("hashCodeTags.before",e,r,t);return e=a.helper.replaceRecursiveRegExp(e,function(e,n,s,o){var i=s+a.subParser("encodeCode")(n,r,t)+o;return"¨C"+(t.gHtmlSpans.push(i)-1)+"C"},"]*>","","gim"),e=t.converter._dispatch("hashCodeTags.after",e,r,t)}),a.subParser("hashElement",function(e,r,t){"use strict";return function(e,r){var a=r;return a=a.replace(/\n\n/g,"\n"),a=a.replace(/^\n/,""),a=a.replace(/\n+$/g,""),a="\n\n¨K"+(t.gHtmlBlocks.push(a)-1)+"K\n\n"}}),a.subParser("hashHTMLBlocks",function(e,r,t){"use strict";e=t.converter._dispatch("hashHTMLBlocks.before",e,r,t);var n=["pre","div","h1","h2","h3","h4","h5","h6","blockquote","table","dl","ol","ul","script","noscript","form","fieldset","iframe","math","style","section","header","footer","nav","article","aside","address","audio","canvas","figure","hgroup","output","video","p"],s=function(e,r,a,n){var s=e;return-1!==a.search(/\bmarkdown\b/)&&(s=a+t.converter.makeHtml(r)+n),"\n\n¨K"+(t.gHtmlBlocks.push(s)-1)+"K\n\n"};r.backslashEscapesHTMLTags&&(e=e.replace(/\\<(\/?[^>]+?)>/g,function(e,r){return"<"+r+">"}));for(var o=0;o]*>)","im"),c="<"+n[o]+"\\b[^>]*>",u="";-1!==(i=a.helper.regexIndexOf(e,l));){var d=a.helper.splitAtIndex(e,i),p=a.helper.replaceRecursiveRegExp(d[1],s,c,u,"im");if(p===d[1])break;e=d[0].concat(p)}return e=e.replace(/(\n {0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,a.subParser("hashElement")(e,r,t)),e=a.helper.replaceRecursiveRegExp(e,function(e){return"\n\n¨K"+(t.gHtmlBlocks.push(e)-1)+"K\n\n"},"^ {0,3}\x3c!--","--\x3e","gm"),e=e.replace(/(?:\n\n)( {0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,a.subParser("hashElement")(e,r,t)),e=t.converter._dispatch("hashHTMLBlocks.after",e,r,t)}),a.subParser("hashHTMLSpans",function(e,r,t){"use strict";function a(e){return"¨C"+(t.gHtmlSpans.push(e)-1)+"C"}return e=t.converter._dispatch("hashHTMLSpans.before",e,r,t),e=e.replace(/<[^>]+?\/>/gi,function(e){return a(e)}),e=e.replace(/<([^>]+?)>[\s\S]*?<\/\1>/g,function(e){return a(e)}),e=e.replace(/<([^>]+?)\s[^>]+?>[\s\S]*?<\/\1>/g,function(e){return a(e)}),e=e.replace(/<[^>]+?>/gi,function(e){return a(e)}),e=t.converter._dispatch("hashHTMLSpans.after",e,r,t)}),a.subParser("unhashHTMLSpans",function(e,r,t){"use strict";e=t.converter._dispatch("unhashHTMLSpans.before",e,r,t);for(var a=0;a]*>\\s*]*>","^ {0,3}\\s*
","gim"),e=t.converter._dispatch("hashPreCodeTags.after",e,r,t)}),a.subParser("headers",function(e,r,t){"use strict";function n(e){var n,s;if(r.customizedHeaderId){var o=e.match(/\{([^{]+?)}\s*$/);o&&o[1]&&(e=o[1])}return n=e,s=a.helper.isString(r.prefixHeaderId)?r.prefixHeaderId:!0===r.prefixHeaderId?"section-":"",r.rawPrefixHeaderId||(n=s+n),n=r.ghCompatibleHeaderId?n.replace(/ /g,"-").replace(/&/g,"").replace(/Β¨T/g,"").replace(/Β¨D/g,"").replace(/[&+$,\/:;=?@"#{}|^Β¨~\[\]`\\*)(%.!'<>]/g,"").toLowerCase():r.rawHeaderId?n.replace(/ /g,"-").replace(/&/g,"&").replace(/Β¨T/g,"Β¨").replace(/Β¨D/g,"$").replace(/["']/g,"-").toLowerCase():n.replace(/[^\w]/g,"").toLowerCase(),r.rawPrefixHeaderId&&(n=s+n),t.hashLinkCounts[n]?n=n+"-"+t.hashLinkCounts[n]++:t.hashLinkCounts[n]=1,n}e=t.converter._dispatch("headers.before",e,r,t);var s=isNaN(parseInt(r.headerLevelStart))?1:parseInt(r.headerLevelStart),o=r.smoothLivePreview?/^(.+)[ \t]*\n={2,}[ \t]*\n+/gm:/^(.+)[ \t]*\n=+[ \t]*\n+/gm,i=r.smoothLivePreview?/^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm:/^(.+)[ \t]*\n-+[ \t]*\n+/gm;e=(e=e.replace(o,function(e,o){var i=a.subParser("spanGamut")(o,r,t),l=r.noHeaderId?"":' id="'+n(o)+'"',c=""+i+"";return a.subParser("hashBlock")(c,r,t)})).replace(i,function(e,o){var i=a.subParser("spanGamut")(o,r,t),l=r.noHeaderId?"":' id="'+n(o)+'"',c=s+1,u=""+i+"";return a.subParser("hashBlock")(u,r,t)});var l=r.requireSpaceBeforeHeadingText?/^(#{1,6})[ \t]+(.+?)[ \t]*#*\n+/gm:/^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm;return e=e.replace(l,function(e,o,i){var l=i;r.customizedHeaderId&&(l=i.replace(/\s?\{([^{]+?)}\s*$/,""));var c=a.subParser("spanGamut")(l,r,t),u=r.noHeaderId?"":' id="'+n(i)+'"',d=s-1+o.length,p=""+c+"";return a.subParser("hashBlock")(p,r,t)}),e=t.converter._dispatch("headers.after",e,r,t)}),a.subParser("horizontalRule",function(e,r,t){"use strict";e=t.converter._dispatch("horizontalRule.before",e,r,t);var n=a.subParser("hashBlock")("
",r,t);return e=e.replace(/^ {0,2}( ?-){3,}[ \t]*$/gm,n),e=e.replace(/^ {0,2}( ?\*){3,}[ \t]*$/gm,n),e=e.replace(/^ {0,2}( ?_){3,}[ \t]*$/gm,n),e=t.converter._dispatch("horizontalRule.after",e,r,t)}),a.subParser("images",function(e,r,t){"use strict";function n(e,r,n,s,o,i,l,c){var u=t.gUrls,d=t.gTitles,p=t.gDimensions;if(n=n.toLowerCase(),c||(c=""),e.search(/\(? ?(['"].*['"])?\)$/m)>-1)s="";else if(""===s||null===s){if(""!==n&&null!==n||(n=r.toLowerCase().replace(/ ?\n/g," ")),s="#"+n,a.helper.isUndefined(u[n]))return e;s=u[n],a.helper.isUndefined(d[n])||(c=d[n]),a.helper.isUndefined(p[n])||(o=p[n].width,i=p[n].height)}r=r.replace(/"/g,""").replace(a.helper.regexes.asteriskDashAndColon,a.helper.escapeCharactersCallback);var h=''+r+'"}return e=(e=t.converter._dispatch("images.before",e,r,t)).replace(/!\[([^\]]*?)] ?(?:\n *)?\[([\s\S]*?)]()()()()()/g,n),e=e.replace(/!\[([^\]]*?)][ \t]*()\([ \t]??(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,function(e,r,t,a,s,o,i,l){return a=a.replace(/\s/g,""),n(e,r,t,a,s,o,0,l)}),e=e.replace(/!\[([^\]]*?)][ \t]*()\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(?:(["'])([^"]*?)\6))?[ \t]?\)/g,n),e=e.replace(/!\[([^\]]*?)][ \t]*()\([ \t]??(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,n),e=e.replace(/!\[([^\[\]]+)]()()()()()/g,n),e=t.converter._dispatch("images.after",e,r,t)}),a.subParser("italicsAndBold",function(e,r,t){"use strict";function a(e,r,t){return r+e+t}return e=t.converter._dispatch("italicsAndBold.before",e,r,t),e=r.literalMidWordUnderscores?(e=(e=e.replace(/\b___(\S[\s\S]*?)___\b/g,function(e,r){return a(r,"","")})).replace(/\b__(\S[\s\S]*?)__\b/g,function(e,r){return a(r,"","")})).replace(/\b_(\S[\s\S]*?)_\b/g,function(e,r){return a(r,"","")}):(e=(e=e.replace(/___(\S[\s\S]*?)___/g,function(e,r){return/\S$/.test(r)?a(r,"",""):e})).replace(/__(\S[\s\S]*?)__/g,function(e,r){return/\S$/.test(r)?a(r,"",""):e})).replace(/_([^\s_][\s\S]*?)_/g,function(e,r){return/\S$/.test(r)?a(r,"",""):e}),e=r.literalMidWordAsterisks?(e=(e=e.replace(/([^*]|^)\B\*\*\*(\S[\s\S]*?)\*\*\*\B(?!\*)/g,function(e,r,t){return a(t,r+"","")})).replace(/([^*]|^)\B\*\*(\S[\s\S]*?)\*\*\B(?!\*)/g,function(e,r,t){return a(t,r+"","")})).replace(/([^*]|^)\B\*(\S[\s\S]*?)\*\B(?!\*)/g,function(e,r,t){return a(t,r+"","")}):(e=(e=e.replace(/\*\*\*(\S[\s\S]*?)\*\*\*/g,function(e,r){return/\S$/.test(r)?a(r,"",""):e})).replace(/\*\*(\S[\s\S]*?)\*\*/g,function(e,r){return/\S$/.test(r)?a(r,"",""):e})).replace(/\*([^\s*][\s\S]*?)\*/g,function(e,r){return/\S$/.test(r)?a(r,"",""):e}),e=t.converter._dispatch("italicsAndBold.after",e,r,t)}),a.subParser("lists",function(e,r,t){"use strict";function n(e,n){t.gListLevel++,e=e.replace(/\n{2,}$/,"\n");var s=/(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0| {0,3}([*+-]|\d+[.])[ \t]+))/gm,o=/\n[ \t]*\n(?!¨0)/.test(e+="¨0");return r.disableForced4SpacesIndentedSublists&&(s=/(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0|\2([*+-]|\d+[.])[ \t]+))/gm),e=e.replace(s,function(e,n,s,i,l,c,u){u=u&&""!==u.trim();var d=a.subParser("outdent")(l,r,t),p="";return c&&r.tasklists&&(p=' class="task-list-item" style="list-style-type: none;"',d=d.replace(/^[ \t]*\[(x|X| )?]/m,function(){var e='-1?(d=a.subParser("githubCodeBlocks")(d,r,t),d=a.subParser("blockGamut")(d,r,t)):(d=(d=a.subParser("lists")(d,r,t)).replace(/\n$/,""),d=(d=a.subParser("hashHTMLBlocks")(d,r,t)).replace(/\n\n+/g,"\n\n"),d=o?a.subParser("paragraphs")(d,r,t):a.subParser("spanGamut")(d,r,t)),d=d.replace("¨A",""),d=""+d+"\n"}),e=e.replace(/¨0/g,""),t.gListLevel--,n&&(e=e.replace(/\s+$/,"")),e}function s(e,r){if("ol"===r){var t=e.match(/^ *(\d+)\./);if(t&&"1"!==t[1])return' start="'+t[1]+'"'}return""}function o(e,t,a){var o=r.disableForced4SpacesIndentedSublists?/^ ?\d+\.[ \t]/gm:/^ {0,3}\d+\.[ \t]/gm,i=r.disableForced4SpacesIndentedSublists?/^ ?[*+-][ \t]/gm:/^ {0,3}[*+-][ \t]/gm,l="ul"===t?o:i,c="";if(-1!==e.search(l))!function r(u){var d=u.search(l),p=s(e,t);-1!==d?(c+="\n\n<"+t+p+">\n"+n(u.slice(0,d),!!a)+"\n",l="ul"===(t="ul"===t?"ol":"ul")?o:i,r(u.slice(d))):c+="\n\n<"+t+p+">\n"+n(u,!!a)+"\n"}(e);else{var u=s(e,t);c="\n\n<"+t+u+">\n"+n(e,!!a)+"\n"}return c}return e=t.converter._dispatch("lists.before",e,r,t),e+="¨0",e=t.gListLevel?e.replace(/^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,function(e,r,t){return o(r,t.search(/[*+-]/g)>-1?"ul":"ol",!0)}):e.replace(/(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,function(e,r,t,a){return o(t,a.search(/[*+-]/g)>-1?"ul":"ol",!1)}),e=e.replace(/¨0/,""),e=t.converter._dispatch("lists.after",e,r,t)}),a.subParser("metadata",function(e,r,t){"use strict";function a(e){t.metadata.raw=e,(e=(e=e.replace(/&/g,"&").replace(/"/g,""")).replace(/\n {4}/g," ")).replace(/^([\S ]+): +([\s\S]+?)$/gm,function(e,r,a){return t.metadata.parsed[r]=a,""})}return r.metadata?(e=t.converter._dispatch("metadata.before",e,r,t),e=e.replace(/^\s*«««+(\S*?)\n([\s\S]+?)\n»»»+\n/,function(e,r,t){return a(t),"¨M"}),e=e.replace(/^\s*---+(\S*?)\n([\s\S]+?)\n---+\n/,function(e,r,n){return r&&(t.metadata.format=r),a(n),"¨M"}),e=e.replace(/¨M/g,""),e=t.converter._dispatch("metadata.after",e,r,t)):e}),a.subParser("outdent",function(e,r,t){"use strict";return e=t.converter._dispatch("outdent.before",e,r,t),e=e.replace(/^(\t|[ ]{1,4})/gm,"¨0"),e=e.replace(/¨0/g,""),e=t.converter._dispatch("outdent.after",e,r,t)}),a.subParser("paragraphs",function(e,r,t){"use strict";for(var n=(e=(e=(e=t.converter._dispatch("paragraphs.before",e,r,t)).replace(/^\n+/g,"")).replace(/\n+$/g,"")).split(/\n{2,}/g),s=[],o=n.length,i=0;i=0?s.push(l):l.search(/\S/)>=0&&(l=(l=a.subParser("spanGamut")(l,r,t)).replace(/^([ \t]*)/g,"

"),l+="

",s.push(l))}for(o=s.length,i=0;i]*>\s*]*>/.test(u)&&(d=!0)}s[i]=u}return e=s.join("\n"),e=e.replace(/^\n+/g,""),e=e.replace(/\n+$/g,""),t.converter._dispatch("paragraphs.after",e,r,t)}),a.subParser("runExtension",function(e,r,t,a){"use strict";if(e.filter)r=e.filter(r,a.converter,t);else if(e.regex){var n=e.regex;n instanceof RegExp||(n=new RegExp(n,"g")),r=r.replace(n,e.replace)}return r}),a.subParser("spanGamut",function(e,r,t){"use strict";return e=t.converter._dispatch("spanGamut.before",e,r,t),e=a.subParser("codeSpans")(e,r,t),e=a.subParser("escapeSpecialCharsWithinTagAttributes")(e,r,t),e=a.subParser("encodeBackslashEscapes")(e,r,t),e=a.subParser("images")(e,r,t),e=a.subParser("anchors")(e,r,t),e=a.subParser("autoLinks")(e,r,t),e=a.subParser("simplifiedAutoLinks")(e,r,t),e=a.subParser("emoji")(e,r,t),e=a.subParser("underline")(e,r,t),e=a.subParser("italicsAndBold")(e,r,t),e=a.subParser("strikethrough")(e,r,t),e=a.subParser("ellipsis")(e,r,t),e=a.subParser("hashHTMLSpans")(e,r,t),e=a.subParser("encodeAmpsAndAngles")(e,r,t),r.simpleLineBreaks?/\n\n¨K/.test(e)||(e=e.replace(/\n+/g,"
\n")):e=e.replace(/ +\n/g,"
\n"),e=t.converter._dispatch("spanGamut.after",e,r,t)}),a.subParser("strikethrough",function(e,r,t){"use strict";return r.strikethrough&&(e=(e=t.converter._dispatch("strikethrough.before",e,r,t)).replace(/(?:~){2}([\s\S]+?)(?:~){2}/g,function(e,n){return function(e){return r.simplifiedAutoLink&&(e=a.subParser("simplifiedAutoLinks")(e,r,t)),""+e+""}(n)}),e=t.converter._dispatch("strikethrough.after",e,r,t)),e}),a.subParser("stripLinkDefinitions",function(e,r,t){"use strict";var n=function(e,n,s,o,i,l,c){return n=n.toLowerCase(),s.match(/^data:.+?\/.+?;base64,/)?t.gUrls[n]=s.replace(/\s/g,""):t.gUrls[n]=a.subParser("encodeAmpsAndAngles")(s,r,t),l?l+c:(c&&(t.gTitles[n]=c.replace(/"|'/g,""")),r.parseImgDimensions&&o&&i&&(t.gDimensions[n]={width:o,height:i}),"")};return e=(e+="Β¨0").replace(/^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n\n|(?=Β¨0)|(?=\n\[))/gm,n),e=e.replace(/^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*\s]+)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=Β¨0))/gm,n),e=e.replace(/Β¨0/,"")}),a.subParser("tables",function(e,r,t){"use strict";function n(e){return/^:[ \t]*--*$/.test(e)?' style="text-align:left;"':/^--*[ \t]*:[ \t]*$/.test(e)?' style="text-align:right;"':/^:[ \t]*--*[ \t]*:$/.test(e)?' style="text-align:center;"':""}function s(e,n){var s="";return e=e.trim(),(r.tablesHeaderId||r.tableHeaderId)&&(s=' id="'+e.replace(/ /g,"_").toLowerCase()+'"'),e=a.subParser("spanGamut")(e,r,t),""+e+"\n"}function o(e,n){return""+a.subParser("spanGamut")(e,r,t)+"\n"}function i(e){var i,l=e.split("\n");for(i=0;i\n\n\n",n=0;n\n";for(var s=0;s\n"}return t+="\n\n"}(p,_)}if(!r.tables)return e;return e=t.converter._dispatch("tables.before",e,r,t),e=e.replace(/\\(\|)/g,a.helper.escapeCharactersCallback),e=e.replace(/^ {0,3}\|?.+\|.+\n {0,3}\|?[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:[-=]){2,}[\s\S]+?(?:\n\n|Β¨0)/gm,i),e=e.replace(/^ {0,3}\|.+\|[ \t]*\n {0,3}\|[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*\n( {0,3}\|.+\|[ \t]*\n)*(?:\n|Β¨0)/gm,i),e=t.converter._dispatch("tables.after",e,r,t)}),a.subParser("underline",function(e,r,t){"use strict";return r.underline?(e=t.converter._dispatch("underline.before",e,r,t),e=r.literalMidWordUnderscores?(e=e.replace(/\b___(\S[\s\S]*?)___\b/g,function(e,r){return""+r+""})).replace(/\b__(\S[\s\S]*?)__\b/g,function(e,r){return""+r+""}):(e=e.replace(/___(\S[\s\S]*?)___/g,function(e,r){return/\S$/.test(r)?""+r+"":e})).replace(/__(\S[\s\S]*?)__/g,function(e,r){return/\S$/.test(r)?""+r+"":e}),e=e.replace(/(_)/g,a.helper.escapeCharactersCallback),e=t.converter._dispatch("underline.after",e,r,t)):e}),a.subParser("unescapeSpecialChars",function(e,r,t){"use strict";return e=t.converter._dispatch("unescapeSpecialChars.before",e,r,t),e=e.replace(/Β¨E(\d+)E/g,function(e,r){var t=parseInt(r);return String.fromCharCode(t)}),e=t.converter._dispatch("unescapeSpecialChars.after",e,r,t)}),a.subParser("makeMarkdown.blockquote",function(e,r){"use strict";var t="";if(e.hasChildNodes())for(var n=e.childNodes,s=n.length,o=0;o "+t.split("\n").join("\n> ")}),a.subParser("makeMarkdown.codeBlock",function(e,r){"use strict";var t=e.getAttribute("language"),a=e.getAttribute("precodenum");return"```"+t+"\n"+r.preList[a]+"\n```"}),a.subParser("makeMarkdown.codeSpan",function(e){"use strict";return"`"+e.innerHTML+"`"}),a.subParser("makeMarkdown.emphasis",function(e,r){"use strict";var t="";if(e.hasChildNodes()){t+="*";for(var n=e.childNodes,s=n.length,o=0;o",e.hasAttribute("width")&&e.hasAttribute("height")&&(r+=" ="+e.getAttribute("width")+"x"+e.getAttribute("height")),e.hasAttribute("title")&&(r+=' "'+e.getAttribute("title")+'"'),r+=")"),r}),a.subParser("makeMarkdown.links",function(e,r){"use strict";var t="";if(e.hasChildNodes()&&e.hasAttribute("href")){var n=e.childNodes,s=n.length;t="[";for(var o=0;o",e.hasAttribute("title")&&(t+=' "'+e.getAttribute("title")+'"'),t+=")"}return t}),a.subParser("makeMarkdown.list",function(e,r,t){"use strict";var n="";if(!e.hasChildNodes())return"";for(var s=e.childNodes,o=s.length,i=e.getAttribute("start")||1,l=0;l"+r.preList[t]+""}),a.subParser("makeMarkdown.strikethrough",function(e,r){"use strict";var t="";if(e.hasChildNodes()){t+="~~";for(var n=e.childNodes,s=n.length,o=0;otr>th"),l=e.querySelectorAll("tbody>tr");for(t=0;t_&&(_=g)}for(t=0;t/g,"\\$1>"),r=r.replace(/^#/gm,"\\#"),r=r.replace(/^(\s*)([-=]{3,})(\s*)$/,"$1\\$2$3"),r=r.replace(/^( {0,3}\d+)\./gm,"$1\\."),r=r.replace(/^( {0,3})([+-])/gm,"$1\\$2"),r=r.replace(/]([\s]*)\(/g,"\\]$1\\("),r=r.replace(/^ {0,3}\[([\S \t]*?)]:/gm,"\\[$1]:")});"function"==typeof define&&define.amd?define(function(){"use strict";return a}):"undefined"!=typeof module&&module.exports?module.exports=a:this.showdown=a}).call(this); +//# sourceMappingURL=showdown.min.js.map diff --git a/twake/frontend/public/public/viewer/CodeViewer/theme-dracula.js b/twake/frontend/public/public/viewer/CodeViewer/theme-dracula.js new file mode 100644 index 00000000..870392d5 --- /dev/null +++ b/twake/frontend/public/public/viewer/CodeViewer/theme-dracula.js @@ -0,0 +1,20 @@ +ace.define( + 'ace/theme/dracula', + ['require', 'exports', 'module', 'ace/lib/dom'], + function (e, t, n) { + (t.isDark = !0), + (t.cssClass = 'ace-dracula'), + (t.cssText = + '.ace-dracula .ace_gutter {background: #282a36;color: rgb(144,145,148)}.ace-dracula .ace_print-margin {width: 1px;background: #44475a}.ace-dracula {background-color: #282a36;color: #f8f8f2}.ace-dracula .ace_cursor {color: #f8f8f0}.ace-dracula .ace_marker-layer .ace_selection {background: #44475a}.ace-dracula.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px #282a36;border-radius: 2px}.ace-dracula .ace_marker-layer .ace_step {background: rgb(198, 219, 174)}.ace-dracula .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid #a29709}.ace-dracula .ace_marker-layer .ace_active-line {background: #44475a}.ace-dracula .ace_gutter-active-line {background-color: #44475a}.ace-dracula .ace_marker-layer .ace_selected-word {box-shadow: 0px 0px 0px 1px #a29709;border-radius: 3px;}.ace-dracula .ace_fold {background-color: #50fa7b;border-color: #f8f8f2}.ace-dracula .ace_keyword {color: #ff79c6}.ace-dracula .ace_constant.ace_language {color: #bd93f9}.ace-dracula .ace_constant.ace_numeric {color: #bd93f9}.ace-dracula .ace_constant.ace_character {color: #bd93f9}.ace-dracula .ace_constant.ace_character.ace_escape {color: #ff79c6}.ace-dracula .ace_constant.ace_other {color: #bd93f9}.ace-dracula .ace_support.ace_function {color: #8be9fd}.ace-dracula .ace_support.ace_constant {color: #6be5fd}.ace-dracula .ace_support.ace_class {font-style: italic;color: #66d9ef}.ace-dracula .ace_support.ace_type {font-style: italic;color: #66d9ef}.ace-dracula .ace_storage {color: #ff79c6}.ace-dracula .ace_storage.ace_type {font-style: italic;color: #8be9fd}.ace-dracula .ace_invalid {color: #F8F8F0;background-color: #ff79c6}.ace-dracula .ace_invalid.ace_deprecated {color: #F8F8F0;background-color: #bd93f9}.ace-dracula .ace_string {color: #f1fa8c}.ace-dracula .ace_comment {color: #6272a4}.ace-dracula .ace_variable {color: #50fa7b}.ace-dracula .ace_variable.ace_parameter {font-style: italic;color: #ffb86c}.ace-dracula .ace_entity.ace_other.ace_attribute-name {color: #50fa7b}.ace-dracula .ace_entity.ace_name.ace_function {color: #50fa7b}.ace-dracula .ace_entity.ace_name.ace_tag {color: #ff79c6}.ace-dracula .ace_invisible {color: #626680;}.ace-dracula .ace_indent-guide {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYHB3d/8PAAOIAdULw8qMAAAAAElFTkSuQmCC) right repeat-y}'), + (t.$selectionColorConflict = !0); + var r = e('../lib/dom'); + r.importCssString(t.cssText, t.cssClass); + }, +); +(function () { + ace.require(['ace/theme/dracula'], function (m) { + if (typeof module == 'object' && typeof exports == 'object' && module) { + module.exports = m; + } + }); +})(); diff --git a/twake/frontend/public/public/viewer/CodeViewer/viewer.html b/twake/frontend/public/public/viewer/CodeViewer/viewer.html new file mode 100755 index 00000000..6705c65d --- /dev/null +++ b/twake/frontend/public/public/viewer/CodeViewer/viewer.html @@ -0,0 +1,79 @@ + + + + + + +
+
+ + + + + + + + diff --git a/twake/frontend/public/public/viewer/ImageViewer/iv-viewer.css b/twake/frontend/public/public/viewer/ImageViewer/iv-viewer.css new file mode 100755 index 00000000..b2b19efa --- /dev/null +++ b/twake/frontend/public/public/viewer/ImageViewer/iv-viewer.css @@ -0,0 +1,184 @@ +.iv { + /***** snap view css *****/ + /*** zoom slider ***/ + /**** snap view css end *****/ +} +.iv-container { + overflow: hidden; + position: relative; +} +.iv-fullscreen { + position: fixed; + background: #0d0d0d; + width: 100%; + height: 100%; + top: 0; + left: 0; + display: none; + z-index: 1000; +} +.iv-fullscreen-container { + position: relative; + height: 100%; + width: 100%; +} +.iv-container { + overflow: hidden; + position: relative; +} +.iv-image-mode { + display: inline-block; +} +.iv-fullscreen-close { + position: absolute; + width: 24px; + height: 24px; + right: 10px; + top: 10px; + padding: 10px; + cursor: pointer; + text-align: center; + overflow: hidden; + text-shadow: 0px 0px 3px #6d6d6d; + transition: all ease 200ms; +} +.iv-fullscreen-close:after, .iv-fullscreen-close:before { + content: ""; + height: 4px; + width: 24px; + background: #FFF; + position: absolute; + left: 0; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} +.iv-fullscreen-close:before { + transform: translate(-50%, -50%) rotate(45deg); +} +.iv-fullscreen-close:after { + transform: translate(-50%, -50%) rotate(-45deg); +} +.iv-fullscreen-close:hover { + transform: rotate(90deg); + transform-origin: 50% 50%; +} +.iv-snap-view { + width: 150px; + height: 150px; + position: absolute; + top: 20px; + left: 20px; + border: 1px solid #aaa; + background: black; + z-index: 100; + box-sizing: content-box; + transition: opacity ease 400ms; + opacity: 0; +} +.iv-snap-image-wrap { + display: inline-block; + position: absolute; + max-width: 150px; + max-height: 150px; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + overflow: hidden; +} +.iv-snap-image { + position: relative; + -ms-touch-action: none; + touch-action: none; +} +.iv-snap-handle { + box-sizing: border-box; + position: absolute; + border: 1px solid white; + transform: translate3d(0, 0, 0); + box-shadow: 0px 0px 0px 200px rgba(0, 0, 0, 0.5); + cursor: pointer; + cursor: grab; +} +.iv-snap-handle:active { + cursor: grabbing; +} +.iv-zoom-slider { + width: 100%; + box-sizing: content-box; + border: 1px solid #aaa; + border-top: 0; + background: rgba(0, 0, 0, 0.3); + height: 15px; + position: absolute; + top: 150px; + left: -1px; +} +.iv-zoom-handle { + width: 20px; + height: 15px; + background: white; + position: absolute; + cursor: pointer; + cursor: grab; +} +.iv-zoom-handle:active { + cursor: grabbing; +} +.iv-image-view { + position: absolute; + height: 100%; + width: 100%; + top: 0; + left: 0; +} +.iv-image-wrap { + display: inline-block; +} +.iv-image-wrap:active { + cursor: move; +} +.iv-image { + max-width: 100%; + max-height: 100%; + position: absolute; + -ms-touch-action: none; + touch-action: none; + transform: translate3d(0, 0, 0); +} +.iv-loader { + top: 50%; + left: 50%; + border-radius: 50%; + width: 32px; + height: 32px; + z-index: 100; + margin-top: -16px; + margin-left: -16px; + font-size: 5px; + position: absolute; + text-indent: -9999em; + border: 1.1em solid rgba(255, 255, 255, 0.2); + border-left: 1.1em solid #ffffff; + transform: translateZ(0); + animation: loading-icon 1.1s infinite linear; +} +.iv-loader:after { + width: 10em; + height: 10em; + border-radius: 50%; +} +@keyframes loading-icon { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} +@media screen and (max-width: 767px) { + .iv-snap-view { + z-index: -1; + visibility: hidden; + } +} \ No newline at end of file diff --git a/twake/frontend/public/public/viewer/ImageViewer/iv-viewer.js b/twake/frontend/public/public/viewer/ImageViewer/iv-viewer.js new file mode 100755 index 00000000..f118d888 --- /dev/null +++ b/twake/frontend/public/public/viewer/ImageViewer/iv-viewer.js @@ -0,0 +1,1409 @@ +/** + * iv-viewer - 2.0.0 + * Author : Sudhanshu Yadav + * Copyright (c) 2019 to Sudhanshu Yadav, released under the MIT license. + * git+https://github.com/s-yadav/iv-viewer.git + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = global || self, global.ImageViewer = factory()); +}(this, function () { 'use strict'; + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + return Constructor; + } + + function _defineProperty(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + + return obj; + } + + function _objectSpread(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i] != null ? arguments[i] : {}; + var ownKeys = Object.keys(source); + + if (typeof Object.getOwnPropertySymbols === 'function') { + ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { + return Object.getOwnPropertyDescriptor(source, sym).enumerable; + })); + } + + ownKeys.forEach(function (key) { + _defineProperty(target, key, source[key]); + }); + } + + return target; + } + + function _inherits(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function"); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + writable: true, + configurable: true + } + }); + if (superClass) _setPrototypeOf(subClass, superClass); + } + + function _getPrototypeOf(o) { + _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { + return o.__proto__ || Object.getPrototypeOf(o); + }; + return _getPrototypeOf(o); + } + + function _setPrototypeOf(o, p) { + _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { + o.__proto__ = p; + return o; + }; + + return _setPrototypeOf(o, p); + } + + function _assertThisInitialized(self) { + if (self === void 0) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + + return self; + } + + function _possibleConstructorReturn(self, call) { + if (call && (typeof call === "object" || typeof call === "function")) { + return call; + } + + return _assertThisInitialized(self); + } + + function _superPropBase(object, property) { + while (!Object.prototype.hasOwnProperty.call(object, property)) { + object = _getPrototypeOf(object); + if (object === null) break; + } + + return object; + } + + function _get(target, property, receiver) { + if (typeof Reflect !== "undefined" && Reflect.get) { + _get = Reflect.get; + } else { + _get = function _get(target, property, receiver) { + var base = _superPropBase(target, property); + + if (!base) return; + var desc = Object.getOwnPropertyDescriptor(base, property); + + if (desc.get) { + return desc.get.call(receiver); + } + + return desc.value; + }; + } + + return _get(target, property, receiver || target); + } + + function _slicedToArray(arr, i) { + return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); + } + + function _arrayWithHoles(arr) { + if (Array.isArray(arr)) return arr; + } + + function _iterableToArrayLimit(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"] != null) _i["return"](); + } finally { + if (_d) throw _e; + } + } + + return _arr; + } + + function _nonIterableRest() { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + + // constants + var ZOOM_CONSTANT = 15; // increase or decrease value for zoom on mouse wheel + + var MOUSE_WHEEL_COUNT = 5; // A mouse delta after which it should stop preventing default behaviour of mouse wheel + + function noop() {} // ease out method + + /* + t : current time, + b : intial value, + c : changed value, + d : duration + */ + + function easeOutQuart(t, b, c, d) { + t /= d; + t -= 1; + return -c * (t * t * t * t - 1) + b; + } + function createElement(options) { + var elem = document.createElement(options.tagName); + if (options.id) elem.id = options.id; + if (options.html) elem.innerHTML = options.html; + if (options.className) elem.className = options.className; + if (options.src) elem.src = options.src; + if (options.style) elem.style.cssText = options.style; + if (options.child) elem.appendChild(options.child); // Insert before + + if (options.insertBefore) { + options.parent.insertBefore(elem, options.insertBefore); // Standard append + } else { + options.parent.appendChild(elem); + } + + return elem; + } // method to add class + + function addClass(el, className) { + var classNameAry = className.split(' '); + + if (classNameAry.length > 1) { + classNameAry.forEach(function (classItem) { + return addClass(el, classItem); + }); + } else if (el.classList) { + el.classList.add(className); + } else { + el.className += " ".concat(className); // eslint-disable-line no-param-reassign + } + } // method to remove class + + function removeClass(el, className) { + var classNameAry = className.split(' '); + + if (classNameAry.length > 1) { + classNameAry.forEach(function (classItem) { + return removeClass(el, classItem); + }); + } else if (el.classList) { + el.classList.remove(className); + } else { + el.className = el.className.replace(new RegExp("(^|\\b)".concat(className.split(' ').join('|'), "(\\b|$)"), 'gi'), ' '); // eslint-disable-line no-param-reassign + } + } // function to check if image is loaded + + function imageLoaded(img) { + return img.complete && (typeof img.naturalWidth === 'undefined' || img.naturalWidth !== 0); + } + function toArray(list) { + if (!(list instanceof NodeList || list instanceof HTMLCollection)) return [list]; + return Array.prototype.slice.call(list); + } + function css(elements, properties) { + var elmArray = toArray(elements); + + if (typeof properties === 'string') { + return window.getComputedStyle(elmArray[0])[properties]; + } + + elmArray.forEach(function (element) { + Object.keys(properties).forEach(function (key) { + var value = properties[key]; + element.style[key] = value; // eslint-disable-line no-param-reassign + }); + }); + return undefined; + } + function removeCss(element, property) { + element.style.removeProperty(property); + } + function wrap(element, _ref) { + var _ref$tag = _ref.tag, + tag = _ref$tag === void 0 ? 'div' : _ref$tag, + className = _ref.className, + id = _ref.id, + style = _ref.style; + var wrapper = document.createElement(tag); + if (className) wrapper.className = className; + if (id) wrapper.id = id; + if (style) wrapper.style = style; + element.parentNode.insertBefore(wrapper, element); + element.parentNode.removeChild(element); + wrapper.appendChild(element); + return wrapper; + } + function unwrap(element) { + var parent = element.parentNode; + + if (parent !== document.body) { + parent.parentNode.insertBefore(element, parent); + parent.parentNode.removeChild(parent); + } + } + function remove(elements) { + var elmArray = toArray(elements); + elmArray.forEach(function (element) { + element.parentNode.removeChild(element); + }); + } + function clamp(num, min, max) { + return Math.min(Math.max(num, min), max); + } + function assignEvent(element, events, handler) { + if (typeof events === 'string') events = [events]; + events.forEach(function (event) { + element.addEventListener(event, handler); + }); + return function () { + events.forEach(function (event) { + element.removeEventListener(event, handler); + }); + }; + } + function getTouchPointsDistance(touches) { + var touch0 = touches[0]; + var touch1 = touches[1]; + return Math.sqrt(Math.pow(touch1.pageX - touch0.pageX, 2) + Math.pow(touch1.pageY - touch0.pageY, 2)); + } + + var Slider = + /*#__PURE__*/ + function () { + function Slider(container, _ref) { + var _this = this; + + var _onStart = _ref.onStart, + _onMove = _ref.onMove, + onEnd = _ref.onEnd, + isSliderEnabled = _ref.isSliderEnabled; + + _classCallCheck(this, Slider); + + _defineProperty(this, "startHandler", function (eStart) { + if (!_this.isSliderEnabled()) return; + + _this.removeListeners(); + + eStart.preventDefault(); + var moveHandler = _this.moveHandler, + endHandler = _this.endHandler, + onStart = _this.onStart; + var isTouchEvent = eStart.type === 'touchstart'; + _this.touchMoveEvent = isTouchEvent ? 'touchmove' : 'mousemove'; + _this.touchEndEvent = isTouchEvent ? 'touchend' : 'mouseup'; + _this.sx = isTouchEvent ? eStart.touches[0].clientX : eStart.clientX; + _this.sy = isTouchEvent ? eStart.touches[0].clientY : eStart.clientY; + onStart(eStart, { + x: _this.sx, + y: _this.sy + }); // add listeners + + document.addEventListener(_this.touchMoveEvent, moveHandler); + document.addEventListener(_this.touchEndEvent, endHandler); + /* + add end handler in context menu as well. + As mouseup event is not trigger on context menu open + https://bugs.chromium.org/p/chromium/issues/detail?id=506801 + */ + + document.addEventListener('contextmenu', endHandler); + }); + + _defineProperty(this, "moveHandler", function (eMove) { + if (!_this.isSliderEnabled()) return; + eMove.preventDefault(); + var sx = _this.sx, + sy = _this.sy, + onMove = _this.onMove; + var isTouchEvent = _this.touchMoveEvent === 'touchmove'; // get the coordinates + + var mx = isTouchEvent ? eMove.touches[0].clientX : eMove.clientX; + var my = isTouchEvent ? eMove.touches[0].clientY : eMove.clientY; + onMove(eMove, { + dx: mx - sx, + dy: my - sy, + mx: mx, + my: my + }); + }); + + _defineProperty(this, "endHandler", function () { + if (!_this.isSliderEnabled()) return; + + _this.removeListeners(); + + _this.onEnd(); + }); + + this.container = container; + this.isSliderEnabled = isSliderEnabled; + this.onStart = _onStart || noop; + this.onMove = _onMove || noop; + this.onEnd = onEnd || noop; + } + + _createClass(Slider, [{ + key: "removeListeners", + // remove previous events if its not removed + // - Case when while sliding mouse moved out of document and released there + value: function removeListeners() { + if (!this.touchMoveEvent) return; + document.removeEventListener(this.touchMoveEvent, this.moveHandler); + document.removeEventListener(this.touchEndEvent, this.endHandler); + document.removeEventListener('contextmenu', this.endHandler); + } + }, { + key: "init", + value: function init() { + var _this2 = this; + + ['touchstart', 'mousedown'].forEach(function (evt) { + _this2.container.addEventListener(evt, _this2.startHandler); + }); + } + }, { + key: "destroy", + value: function destroy() { + var _this3 = this; + + ['touchstart', 'mousedown'].forEach(function (evt) { + _this3.container.removeEventListener(evt, _this3.startHandler); + }); + this.removeListeners(); + } + }]); + + return Slider; + }(); + + var imageViewHtml = "\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n"; + + var ImageViewer = + /*#__PURE__*/ + function () { + function ImageViewer(element) { + var _this = this; + + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + _classCallCheck(this, ImageViewer); + + _defineProperty(this, "zoom", function (perc, point) { + var _options = _this._options, + _elements = _this._elements, + _state = _this._state; + var curPerc = _state.zoomValue, + imageDim = _state.imageDim, + containerDim = _state.containerDim, + zoomSliderLength = _state.zoomSliderLength; + var image = _elements.image, + zoomHandle = _elements.zoomHandle; + var maxZoom = _options.maxZoom; + perc = Math.round(Math.max(100, perc)); + perc = Math.min(maxZoom, perc); + point = point || { + x: containerDim.w / 2, + y: containerDim.h / 2 + }; + var curLeft = parseFloat(css(image, 'left')); + var curTop = parseFloat(css(image, 'top')); // clear any panning frames + + _this._clearFrames(); + + var step = 0; + var baseLeft = (containerDim.w - imageDim.w) / 2; + var baseTop = (containerDim.h - imageDim.h) / 2; + var baseRight = containerDim.w - baseLeft; + var baseBottom = containerDim.h - baseTop; + + var zoom = function zoom() { + step++; + + if (step < 16) { + _this._frames.zoomFrame = requestAnimationFrame(zoom); + } + + var tickZoom = easeOutQuart(step, curPerc, perc - curPerc, 16); + var ratio = tickZoom / curPerc; + var imgWidth = imageDim.w * tickZoom / 100; + var imgHeight = imageDim.h * tickZoom / 100; + var newLeft = -((point.x - curLeft) * ratio - point.x); + var newTop = -((point.y - curTop) * ratio - point.y); // fix for left and top + + newLeft = Math.min(newLeft, baseLeft); + newTop = Math.min(newTop, baseTop); // fix for right and bottom + + if (newLeft + imgWidth < baseRight) { + newLeft = baseRight - imgWidth; // newLeft - (newLeft + imgWidth - baseRight) + } + + if (newTop + imgHeight < baseBottom) { + newTop = baseBottom - imgHeight; // newTop + (newTop + imgHeight - baseBottom) + } + + css(image, { + height: "".concat(imgHeight, "px"), + width: "".concat(imgWidth, "px"), + left: "".concat(newLeft, "px"), + top: "".concat(newTop, "px") + }); + _this._state.zoomValue = tickZoom; + + _this._resizeSnapHandle(imgWidth, imgHeight, newLeft, newTop); // update zoom handle position + + + css(zoomHandle, { + left: "".concat((tickZoom - 100) * zoomSliderLength / (maxZoom - 100), "px") + }); + }; + + zoom(); + }); + + _defineProperty(this, "_clearFrames", function () { + var _this$_frames = _this._frames, + slideMomentumCheck = _this$_frames.slideMomentumCheck, + sliderMomentumFrame = _this$_frames.sliderMomentumFrame, + zoomFrame = _this$_frames.zoomFrame; + clearInterval(slideMomentumCheck); + cancelAnimationFrame(sliderMomentumFrame); + cancelAnimationFrame(zoomFrame); + }); + + _defineProperty(this, "_resizeSnapHandle", function (imgWidth, imgHeight, imgLeft, imgTop) { + var _elements = _this._elements, + _state = _this._state; + var snapHandle = _elements.snapHandle, + image = _elements.image; + var imageDim = _state.imageDim, + containerDim = _state.containerDim, + zoomValue = _state.zoomValue, + snapImageDim = _state.snapImageDim; + var imageWidth = imgWidth || imageDim.w * zoomValue / 100; + var imageHeight = imgHeight || imageDim.h * zoomValue / 100; + var imageLeft = imgLeft || parseFloat(css(image, 'left')); + var imageTop = imgTop || parseFloat(css(image, 'top')); + var left = -imageLeft * snapImageDim.w / imageWidth; + var top = -imageTop * snapImageDim.h / imageHeight; + var handleWidth = containerDim.w * snapImageDim.w / imageWidth; + var handleHeight = containerDim.h * snapImageDim.h / imageHeight; + css(snapHandle, { + top: "".concat(top, "px"), + left: "".concat(left, "px"), + width: "".concat(handleWidth, "px"), + height: "".concat(handleHeight, "px") + }); + _this._state.snapHandleDim = { + w: handleWidth, + h: handleHeight + }; + }); + + _defineProperty(this, "showSnapView", function (noTimeout) { + var _this$_state = _this._state, + snapViewVisible = _this$_state.snapViewVisible, + zoomValue = _this$_state.zoomValue, + loaded = _this$_state.loaded; + var snapView = _this._elements.snapView; + if (!_this._options.snapView) return; + if (snapViewVisible || zoomValue <= 100 || !loaded) return; + clearTimeout(_this._frames.snapViewTimeout); + _this._state.snapViewVisible = true; + css(snapView, { + opacity: 1, + pointerEvents: 'inherit' + }); + + if (!noTimeout) { + _this._frames.snapViewTimeout = setTimeout(_this.hideSnapView, 1500); + } + }); + + _defineProperty(this, "hideSnapView", function () { + var snapView = _this._elements.snapView; + css(snapView, { + opacity: 0, + pointerEvents: 'none' + }); + _this._state.snapViewVisible = false; + }); + + _defineProperty(this, "refresh", function () { + _this._calculateDimensions(); + + _this.resetZoom(); + }); + + var _this$_findContainerA = this._findContainerAndImageSrc(element, options), + container = _this$_findContainerA.container, + domElement = _this$_findContainerA.domElement, + imageSrc = _this$_findContainerA.imageSrc, + hiResImageSrc = _this$_findContainerA.hiResImageSrc; // containers for elements + + + this._elements = { + container: container, + domElement: domElement + }; + this._options = _objectSpread({}, ImageViewer.defaults, options); // container for all events + + this._events = {}; // container for all timeout and frames + + this._frames = {}; // container for all sliders + + this._sliders = {}; // maintain current state + + this._state = { + zoomValue: this._options.zoomValue + }; + this._images = { + imageSrc: imageSrc, + hiResImageSrc: hiResImageSrc + }; + + this._init(); + + if (imageSrc) { + this._loadImages(); + } // store reference of imageViewer in domElement + + + domElement._imageViewer = this; + } + + _createClass(ImageViewer, [{ + key: "_findContainerAndImageSrc", + value: function _findContainerAndImageSrc(element) { + var domElement = element; + var imageSrc, hiResImageSrc; + + if (typeof element === 'string') { + domElement = document.querySelector(element); + } // throw error if imageViewer is already assigned + + + if (domElement._imageViewer) { + throw new Error('An image viewer is already being initiated on the element.'); + } + + var container = element; + + if (domElement.tagName === 'IMG') { + imageSrc = domElement.src; + hiResImageSrc = domElement.getAttribute('high-res-src') || domElement.getAttribute('data-high-res-src'); // wrap the image with iv-container div + + container = wrap(domElement, { + className: 'iv-container iv-image-mode', + style: { + display: 'inline-block', + overflow: 'hidden' + } + }); // hide the image and add iv-original-img class + + css(domElement, { + opacity: 0, + position: 'relative', + zIndex: -1 + }); + } else { + imageSrc = domElement.getAttribute('src') || domElement.getAttribute('data-src'); + hiResImageSrc = domElement.getAttribute('high-res-src') || domElement.getAttribute('data-high-res-src'); + } + + return { + container: container, + domElement: domElement, + imageSrc: imageSrc, + hiResImageSrc: hiResImageSrc + }; + } + }, { + key: "_init", + value: function _init() { + // initialize the dom elements + this._initDom(); // initialize slider + + + this._initImageSlider(); + + this._initSnapSlider(); + + this._initZoomSlider(); // enable pinch and zoom feature for touch screens + + + this._pinchAndZoom(); // enable scroll zoom interaction + + + this._scrollZoom(); // enable double tap to zoom interaction + + + this._doubleTapToZoom(); // initialize events + + + this._initEvents(); + } + }, { + key: "_initDom", + value: function _initDom() { + var container = this._elements.container; // add image-viewer layout elements + + createElement({ + tagName: 'div', + className: 'iv-wrap', + html: imageViewHtml, + parent: container + }); // add container class on the container + + addClass(container, 'iv-container'); // if the element is static position, position it relatively + + if (css(container, 'position') === 'static') { + css(container, { + position: 'relative' + }); + } // save references for later use + + + this._elements = _objectSpread({}, this._elements, { + snapView: container.querySelector('.iv-snap-view'), + snapImageWrap: container.querySelector('.iv-snap-image-wrap'), + imageWrap: container.querySelector('.iv-image-wrap'), + snapHandle: container.querySelector('.iv-snap-handle'), + zoomHandle: container.querySelector('.iv-zoom-handle') + }); + } + }, { + key: "_initImageSlider", + value: function _initImageSlider() { + var _this2 = this; + + var _elements = this._elements; + var imageWrap = _elements.imageWrap; + var positions, currentPos; + /* Add slide interaction to image */ + + var imageSlider = new Slider(imageWrap, { + isSliderEnabled: function isSliderEnabled() { + var _this2$_state = _this2._state, + loaded = _this2$_state.loaded, + zooming = _this2$_state.zooming, + zoomValue = _this2$_state.zoomValue; + return loaded && !zooming && zoomValue > 100; + }, + onStart: function onStart(e, position) { + var snapSlider = _this2._sliders.snapSlider; // clear all animation frame and interval + + _this2._clearFrames(); + + snapSlider.onStart(); // reset positions + + positions = [position, position]; + currentPos = undefined; + _this2._frames.slideMomentumCheck = setInterval(function () { + if (!currentPos) return; + positions.shift(); + positions.push({ + x: currentPos.mx, + y: currentPos.my + }); + }, 50); + }, + onMove: function onMove(e, position) { + var snapImageDim = _this2._state.snapImageDim; + var snapSlider = _this2._sliders.snapSlider; + + var imageCurrentDim = _this2._getImageCurrentDim(); + + currentPos = position; + snapSlider.onMove(e, { + dx: -position.dx * snapImageDim.w / imageCurrentDim.w, + dy: -position.dy * snapImageDim.h / imageCurrentDim.h + }); + }, + onEnd: function onEnd() { + var snapImageDim = _this2._state.snapImageDim; + var snapSlider = _this2._sliders.snapSlider; + + var imageCurrentDim = _this2._getImageCurrentDim(); // clear all animation frame and interval + + + _this2._clearFrames(); + + var step, positionX, positionY; + var xDiff = positions[1].x - positions[0].x; + var yDiff = positions[1].y - positions[0].y; + + var momentum = function momentum() { + if (step <= 60) { + _this2._frames.sliderMomentumFrame = requestAnimationFrame(momentum); + } + + positionX += easeOutQuart(step, xDiff / 3, -xDiff / 3, 60); + positionY += easeOutQuart(step, yDiff / 3, -yDiff / 3, 60); + snapSlider.onMove(null, { + dx: -(positionX * snapImageDim.w / imageCurrentDim.w), + dy: -(positionY * snapImageDim.h / imageCurrentDim.h) + }); + step++; + }; + + if (Math.abs(xDiff) > 30 || Math.abs(yDiff) > 30) { + step = 1; + positionX = currentPos.dx; + positionY = currentPos.dy; + momentum(); + } + } + }); + imageSlider.init(); + this._sliders.imageSlider = imageSlider; + } + }, { + key: "_initSnapSlider", + value: function _initSnapSlider() { + var _this3 = this; + + var snapHandle = this._elements.snapHandle; + var startHandleTop, startHandleLeft; + var snapSlider = new Slider(snapHandle, { + isSliderEnabled: function isSliderEnabled() { + return _this3._state.loaded; + }, + onStart: function onStart() { + var _this3$_frames = _this3._frames, + slideMomentumCheck = _this3$_frames.slideMomentumCheck, + sliderMomentumFrame = _this3$_frames.sliderMomentumFrame; + startHandleTop = parseFloat(css(snapHandle, 'top')); + startHandleLeft = parseFloat(css(snapHandle, 'left')); // stop momentum on image + + clearInterval(slideMomentumCheck); + cancelAnimationFrame(sliderMomentumFrame); + }, + onMove: function onMove(e, position) { + var _this3$_state = _this3._state, + snapHandleDim = _this3$_state.snapHandleDim, + snapImageDim = _this3$_state.snapImageDim; + var image = _this3._elements.image; + + var imageCurrentDim = _this3._getImageCurrentDim(); // find handle left and top and make sure they lay between the snap image + + + var maxLeft = Math.max(snapImageDim.w - snapHandleDim.w, startHandleLeft); + var maxTop = Math.max(snapImageDim.h - snapHandleDim.h, startHandleTop); + var minLeft = Math.min(0, startHandleLeft); + var minTop = Math.min(0, startHandleTop); + var left = clamp(startHandleLeft + position.dx, minLeft, maxLeft); + var top = clamp(startHandleTop + position.dy, minTop, maxTop); + var imgLeft = -left * imageCurrentDim.w / snapImageDim.w; + var imgTop = -top * imageCurrentDim.h / snapImageDim.h; + css(snapHandle, { + left: "".concat(left, "px"), + top: "".concat(top, "px") + }); + css(image, { + left: "".concat(imgLeft, "px"), + top: "".concat(imgTop, "px") + }); + } + }); + snapSlider.init(); + this._sliders.snapSlider = snapSlider; + } + }, { + key: "_initZoomSlider", + value: function _initZoomSlider() { + var _this4 = this; + + var _this$_elements = this._elements, + snapView = _this$_elements.snapView, + zoomHandle = _this$_elements.zoomHandle; // zoom in zoom out using zoom handle + + var sliderElm = snapView.querySelector('.iv-zoom-slider'); + var leftOffset, handleWidth; // on zoom slider we have to follow the mouse and set the handle to its position. + + var zoomSlider = new Slider(sliderElm, { + isSliderEnabled: function isSliderEnabled() { + return _this4._state.loaded; + }, + onStart: function onStart(eStart) { + var slider = _this4._sliders.zoomSlider; + leftOffset = sliderElm.getBoundingClientRect().left + document.body.scrollLeft; + handleWidth = parseInt(css(zoomHandle, 'width'), 10); // move the handle to current mouse position + + slider.onMove(eStart); + }, + onMove: function onMove(e) { + var maxZoom = _this4._options.maxZoom; + var zoomSliderLength = _this4._state.zoomSliderLength; + var pageX = e.pageX !== undefined ? e.pageX : e.touches[0].pageX; + var newLeft = clamp(pageX - leftOffset - handleWidth / 2, 0, zoomSliderLength); + var zoomValue = 100 + (maxZoom - 100) * newLeft / zoomSliderLength; + + _this4.zoom(zoomValue); + } + }); + zoomSlider.init(); + this._sliders.zoomSlider = zoomSlider; + } + }, { + key: "_initEvents", + value: function _initEvents() { + this._snapViewEvents(); // handle window resize + + + if (this._options.refreshOnResize) { + this._events.onWindowResize = assignEvent(window, 'resize', this.refresh); + } + } + }, { + key: "_snapViewEvents", + value: function _snapViewEvents() { + var _this5 = this; + + var _this$_elements2 = this._elements, + imageWrap = _this$_elements2.imageWrap, + snapView = _this$_elements2.snapView; // show snapView on mouse move + + this._events.snapViewOnMouseMove = assignEvent(imageWrap, ['touchmove', 'mousemove'], function () { + _this5.showSnapView(); + }); // keep showing snapView if on hover over it without any timeout + + this._events.mouseEnterSnapView = assignEvent(snapView, ['mouseenter', 'touchstart'], function () { + _this5._state.snapViewVisible = false; + + _this5.showSnapView(true); + }); // on mouse leave set timeout to hide snapView + + this._events.mouseLeaveSnapView = assignEvent(snapView, ['mouseleave', 'touchend'], function () { + _this5._state.snapViewVisible = false; + + _this5.showSnapView(); + }); + } + }, { + key: "_pinchAndZoom", + value: function _pinchAndZoom() { + var _this6 = this; + + var _this$_elements3 = this._elements, + imageWrap = _this$_elements3.imageWrap, + container = _this$_elements3.container; // apply pinch and zoom feature + + var onPinchStart = function onPinchStart(eStart) { + var _this6$_state = _this6._state, + loaded = _this6$_state.loaded, + startZoomValue = _this6$_state.zoomValue; + var events = _this6._events; + if (!loaded) return; + var touch0 = eStart.touches[0]; + var touch1 = eStart.touches[1]; + + if (!(touch0 && touch1)) { + return; + } + + _this6._state.zooming = true; + var contOffset = container.getBoundingClientRect(); // find distance between two touch points + + var startDist = getTouchPointsDistance(eStart.touches); // find the center for the zoom + + var center = { + x: (touch1.pageX + touch0.pageX) / 2 - (contOffset.left + document.body.scrollLeft), + y: (touch1.pageY + touch0.pageY) / 2 - (contOffset.top + document.body.scrollTop) + }; + + var moveListener = function moveListener(eMove) { + // eMove.preventDefault(); + var newDist = getTouchPointsDistance(eMove.touches); + var zoomValue = startZoomValue + (newDist - startDist) / 2; + + _this6.zoom(zoomValue, center); + }; + + var endListener = function endListener() { + // unbind events + events.pinchMove(); + events.pinchEnd(); + _this6._state.zooming = false; + }; // remove events if already assigned + + + if (events.pinchMove) events.pinchMove(); + if (events.pinchEnd) events.pinchEnd(); // assign events + + events.pinchMove = assignEvent(document, 'touchmove', moveListener); + events.pinchEnd = assignEvent(document, 'touchend', endListener); + }; + + this._events.pinchStart = assignEvent(imageWrap, 'touchstart', onPinchStart); + } + }, { + key: "_scrollZoom", + value: function _scrollZoom() { + var _this7 = this; + + /* Add zoom interaction in mouse wheel */ + var _options = this._options; + var _this$_elements4 = this._elements, + container = _this$_elements4.container, + imageWrap = _this$_elements4.imageWrap; + var changedDelta = 0; + + var onMouseWheel = function onMouseWheel(e) { + var _this7$_state = _this7._state, + loaded = _this7$_state.loaded, + zoomValue = _this7$_state.zoomValue; + if (!_options.zoomOnMouseWheel || !loaded) return; // clear all animation frame and interval + + _this7._clearFrames(); // cross-browser wheel delta + + + var delta = Math.max(-1, Math.min(1, e.wheelDelta || -e.detail || -e.deltaY)); + var newZoomValue = zoomValue * (100 + delta * ZOOM_CONSTANT) / 100; + + if (!(newZoomValue >= 100 && newZoomValue <= _options.maxZoom)) { + changedDelta += Math.abs(delta); + } else { + changedDelta = 0; + } + + e.preventDefault(); + if (changedDelta > MOUSE_WHEEL_COUNT) return; + var contOffset = container.getBoundingClientRect(); + var x = (e.pageX || e.pageX) - (contOffset.left + document.body.scrollLeft); + var y = (e.pageY || e.pageY) - (contOffset.top + document.body.scrollTop); + + _this7.zoom(newZoomValue, { + x: x, + y: y + }); // show the snap viewer + + + _this7.showSnapView(); + }; + + this._ev = assignEvent(imageWrap, 'wheel', onMouseWheel); + } + }, { + key: "_doubleTapToZoom", + value: function _doubleTapToZoom() { + var _this8 = this; + + var imageWrap = this._elements.imageWrap; // handle double tap for zoom in and zoom out + + var touchTime = 0; + var point; + + var onDoubleTap = function onDoubleTap(e) { + if (touchTime === 0) { + touchTime = Date.now(); + point = { + x: e.pageX, + y: e.pageY + }; + } else if (Date.now() - touchTime < 500 && Math.abs(e.pageX - point.x) < 50 && Math.abs(e.pageY - point.y) < 50) { + if (_this8._state.zoomValue === _this8._options.zoomValue) { + _this8.zoom(200); + } else { + _this8.resetZoom(); + } + + touchTime = 0; + } else { + touchTime = 0; + } + }; + + assignEvent(imageWrap, 'click', onDoubleTap); + } + }, { + key: "_getImageCurrentDim", + value: function _getImageCurrentDim() { + var _this$_state2 = this._state, + zoomValue = _this$_state2.zoomValue, + imageDim = _this$_state2.imageDim; + return { + w: imageDim.w * (zoomValue / 100), + h: imageDim.h * (zoomValue / 100) + }; + } + }, { + key: "_loadImages", + value: function _loadImages() { + var _this9 = this; + + var _images = this._images, + _elements = this._elements; + var imageSrc = _images.imageSrc, + hiResImageSrc = _images.hiResImageSrc; + var container = _elements.container, + snapImageWrap = _elements.snapImageWrap, + imageWrap = _elements.imageWrap; + var ivLoader = container.querySelector('.iv-loader'); // remove old images + + remove(container.querySelectorAll('.iv-snap-image, .iv-image')); // add snapView image + + var snapImage = createElement({ + tagName: 'img', + className: 'iv-snap-image', + src: imageSrc, + insertBefore: snapImageWrap.firstChild, + parent: snapImageWrap + }); // add image + + var image = createElement({ + tagName: 'img', + className: 'iv-image iv-small-image', + src: imageSrc, + parent: imageWrap + }); + this._state.loaded = false; // store image reference in _elements + + this._elements.image = image; + this._elements.snapImage = snapImage; + css(ivLoader, { + display: 'block' + }); // keep visibility hidden until image is loaded + + css(image, { + visibility: 'hidden' + }); // hide snap view if open + + this.hideSnapView(); + + var onImageLoad = function onImageLoad() { + // hide the iv loader + css(ivLoader, { + display: 'none' + }); // show the image + + css(image, { + visibility: 'visible' + }); // load high resolution image if provided + + if (hiResImageSrc) { + _this9._loadHighResImage(hiResImageSrc); + } // set loaded flag to true + + + _this9._state.loaded = true; // calculate the dimension + + _this9._calculateDimensions(); // reset the zoom + + + _this9.resetZoom(); + }; + + if (imageLoaded(image)) { + onImageLoad(); + } else { + this._events.imageLoad = assignEvent(image, 'load', onImageLoad); + } + } + }, { + key: "_loadHighResImage", + value: function _loadHighResImage(hiResImageSrc) { + var _this10 = this; + + var _this$_elements5 = this._elements, + imageWrap = _this$_elements5.imageWrap, + container = _this$_elements5.container; + var lowResImg = this._elements.image; + var hiResImage = createElement({ + tagName: 'img', + className: 'iv-image iv-large-image', + src: hiResImageSrc, + parent: imageWrap, + style: lowResImg.style.cssText + }); // add all the style attributes from lowResImg to highResImg + + hiResImage.style.cssText = lowResImg.style.cssText; + this._elements.image = container.querySelectorAll('.iv-image'); + + var onHighResImageLoad = function onHighResImageLoad() { + // remove the low size image and set this image as default image + remove(lowResImg); + _this10._elements.image = hiResImage; // this._calculateDimensions(); + }; + + if (imageLoaded(hiResImage)) { + onHighResImageLoad(); + } else { + this._events.hiResImageLoad = assignEvent(hiResImage, 'load', onHighResImageLoad); + } + } + }, { + key: "_calculateDimensions", + value: function _calculateDimensions() { + var _this$_elements6 = this._elements, + image = _this$_elements6.image, + container = _this$_elements6.container, + snapView = _this$_elements6.snapView, + snapImage = _this$_elements6.snapImage, + zoomHandle = _this$_elements6.zoomHandle; // calculate content width of image and snap image + + var imageWidth = parseInt(css(image, 'width'), 10); + var imageHeight = parseInt(css(image, 'height'), 10); + var contWidth = parseInt(css(container, 'width'), 10); + var contHeight = parseInt(css(container, 'height'), 10); + var snapViewWidth = snapView.clientWidth; + var snapViewHeight = snapView.clientHeight; // set the container dimension + + this._state.containerDim = { + w: contWidth, + h: contHeight + }; // set the image dimension + + var imgWidth; + var imgHeight; + var ratio = imageWidth / imageHeight; + imgWidth = imageWidth > imageHeight && contHeight >= contWidth || ratio * contHeight > contWidth ? contWidth : ratio * contHeight; + imgWidth = Math.min(imgWidth, imageWidth); + imgHeight = imgWidth / ratio; + this._state.imageDim = { + w: imgWidth, + h: imgHeight + }; // reset image position and zoom + + css(image, { + width: "".concat(imgWidth, "px"), + height: "".concat(imgHeight, "px"), + left: "".concat((contWidth - imgWidth) / 2, "px"), + top: "".concat((contHeight - imgHeight) / 2, "px"), + maxWidth: 'none', + maxHeight: 'none' + }); // set the snap Image dimension + + var snapWidth = imgWidth > imgHeight ? snapViewWidth : imgWidth * snapViewHeight / imgHeight; + var snapHeight = imgHeight > imgWidth ? snapViewHeight : imgHeight * snapViewWidth / imgWidth; + this._state.snapImageDim = { + w: snapWidth, + h: snapHeight + }; + css(snapImage, { + width: "".concat(snapWidth, "px"), + height: "".concat(snapHeight, "px") + }); // calculate zoom slider area + + this._state.zoomSliderLength = snapViewWidth - zoomHandle.offsetWidth; + } + }, { + key: "resetZoom", + value: function resetZoom() { + var animate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + var zoomValue = this._options.zoomValue; + + if (!animate) { + this._state.zoomValue = zoomValue; + } + + this.zoom(zoomValue); + } + }, { + key: "load", + value: function load(imageSrc, hiResImageSrc) { + this._images = { + imageSrc: imageSrc, + hiResImageSrc: hiResImageSrc + }; + + this._loadImages(); + } + }, { + key: "destroy", + value: function destroy() { + var _this$_elements7 = this._elements, + container = _this$_elements7.container, + domElement = _this$_elements7.domElement; // destroy all the sliders + + Object.entries(this._sliders).forEach(function (_ref) { + var _ref2 = _slicedToArray(_ref, 2), + key = _ref2[0], + slider = _ref2[1]; + + slider.destroy(); + }); // unbind all events + + Object.entries(this._events).forEach(function (_ref3) { + var _ref4 = _slicedToArray(_ref3, 2), + key = _ref4[0], + unbindEvent = _ref4[1]; + + unbindEvent(); + }); // clear all the frames + + this._clearFrames(); // remove html from the container + + + remove(container.querySelector('.iv-wrap')); // remove iv-container class from container + + removeClass(container, 'iv-container'); // remove added style from container + + removeCss(document.querySelector('html'), 'relative'); // if container has original image, unwrap the image and remove the class + // which will happen when domElement is not the container + + if (domElement !== container) { + unwrap(domElement); + } // remove imageViewer reference from dom element + + + domElement._imageViewer = null; + } + }]); + + return ImageViewer; + }(); + + ImageViewer.defaults = { + zoomValue: 100, + snapView: true, + maxZoom: 500, + refreshOnResize: true, + zoomOnMouseWheel: true + }; + + var fullScreenHtml = "\n
\n
\n"; + + var FullScreenViewer = + /*#__PURE__*/ + function (_ImageViewer) { + _inherits(FullScreenViewer, _ImageViewer); + + function FullScreenViewer() { + var _this; + + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + _classCallCheck(this, FullScreenViewer); + + var fullScreenElem = createElement({ + tagName: 'div', + className: 'iv-fullscreen', + html: fullScreenHtml, + parent: document.body + }); + var container = fullScreenElem.querySelector('.iv-fullscreen-container'); // call the ImageViewer constructor + + _this = _possibleConstructorReturn(this, _getPrototypeOf(FullScreenViewer).call(this, container, _objectSpread({}, options, { + refreshOnResize: false + }))); // add fullScreenElem on element list + + _defineProperty(_assertThisInitialized(_this), "hide", function () { + // hide the fullscreen + css(_this._elements.fullScreen, { + display: 'none' + }); // enable scroll + + removeCss(document.querySelector('html'), 'overflow'); // remove window event + + _this._events.onWindowResize(); + }); + + _this._elements.fullScreen = fullScreenElem; + + _this._initFullScreenEvents(); + + return _this; + } + + _createClass(FullScreenViewer, [{ + key: "_initFullScreenEvents", + value: function _initFullScreenEvents() { + var fullScreen = this._elements.fullScreen; + var closeBtn = fullScreen.querySelector('.iv-fullscreen-close'); // add close button event + + this._events.onCloseBtnClick = assignEvent(closeBtn, 'click', this.hide); + } + }, { + key: "show", + value: function show(imageSrc, hiResImageSrc) { + // show the element + css(this._elements.fullScreen, { + display: 'block' + }); // if image source is provide load image source + + if (imageSrc) { + this.load(imageSrc, hiResImageSrc); + } // handle window resize + + + this._events.onWindowResize = assignEvent(window, 'resize', this.refresh); // disable scroll on html + + css(document.querySelector('html'), { + overflow: 'hidden' + }); + } + }, { + key: "destroy", + value: function destroy() { + var fullScreen = this._elements.fullScreen; // destroy image viewer + + _get(_getPrototypeOf(FullScreenViewer.prototype), "destroy", this).call(this); // remove the element + + + remove(fullScreen); + } + }]); + + return FullScreenViewer; + }(ImageViewer); + + ImageViewer.FullScreenViewer = FullScreenViewer; + + return ImageViewer; + +})); diff --git a/twake/frontend/public/public/viewer/ImageViewer/viewer.html b/twake/frontend/public/public/viewer/ImageViewer/viewer.html new file mode 100755 index 00000000..350178b0 --- /dev/null +++ b/twake/frontend/public/public/viewer/ImageViewer/viewer.html @@ -0,0 +1,295 @@ + + + + + + + + +
Loading...
+ + + + diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-EUC-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-EUC-H.bcmap new file mode 100755 index 00000000..2655fc70 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-EUC-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-EUC-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-EUC-V.bcmap new file mode 100755 index 00000000..f1ed8538 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-EUC-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-H.bcmap new file mode 100755 index 00000000..39e89d33 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-RKSJ-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-RKSJ-H.bcmap new file mode 100755 index 00000000..e4167cb5 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-RKSJ-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-RKSJ-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-RKSJ-V.bcmap new file mode 100755 index 00000000..50b1646e Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-RKSJ-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-V.bcmap new file mode 100755 index 00000000..d7af99b5 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/78-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/78ms-RKSJ-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/78ms-RKSJ-H.bcmap new file mode 100755 index 00000000..37077d01 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/78ms-RKSJ-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/78ms-RKSJ-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/78ms-RKSJ-V.bcmap new file mode 100755 index 00000000..acf23231 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/78ms-RKSJ-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/83pv-RKSJ-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/83pv-RKSJ-H.bcmap new file mode 100755 index 00000000..2359bc52 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/83pv-RKSJ-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/90ms-RKSJ-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/90ms-RKSJ-H.bcmap new file mode 100755 index 00000000..af829382 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/90ms-RKSJ-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/90ms-RKSJ-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/90ms-RKSJ-V.bcmap new file mode 100755 index 00000000..780549de Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/90ms-RKSJ-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/90msp-RKSJ-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/90msp-RKSJ-H.bcmap new file mode 100755 index 00000000..bfd3119c Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/90msp-RKSJ-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/90msp-RKSJ-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/90msp-RKSJ-V.bcmap new file mode 100755 index 00000000..25ef14ab Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/90msp-RKSJ-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/90pv-RKSJ-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/90pv-RKSJ-H.bcmap new file mode 100755 index 00000000..02f713bb Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/90pv-RKSJ-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/90pv-RKSJ-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/90pv-RKSJ-V.bcmap new file mode 100755 index 00000000..d08e0cc5 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/90pv-RKSJ-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Add-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Add-H.bcmap new file mode 100755 index 00000000..59442aca Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Add-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Add-RKSJ-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Add-RKSJ-H.bcmap new file mode 100755 index 00000000..a3065e44 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Add-RKSJ-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Add-RKSJ-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Add-RKSJ-V.bcmap new file mode 100755 index 00000000..040014cf Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Add-RKSJ-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Add-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Add-V.bcmap new file mode 100755 index 00000000..2f816d32 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Add-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-0.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-0.bcmap new file mode 100755 index 00000000..88ec04af Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-0.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-1.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-1.bcmap new file mode 100755 index 00000000..03a50147 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-1.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-2.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-2.bcmap new file mode 100755 index 00000000..2aa95141 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-2.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-3.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-3.bcmap new file mode 100755 index 00000000..86d8b8c7 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-3.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-4.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-4.bcmap new file mode 100755 index 00000000..f50fc6c1 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-4.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-5.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-5.bcmap new file mode 100755 index 00000000..6caf4a83 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-5.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-6.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-6.bcmap new file mode 100755 index 00000000..b77fb070 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-6.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-UCS2.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-UCS2.bcmap new file mode 100755 index 00000000..69d79a2c Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-CNS1-UCS2.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-0.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-0.bcmap new file mode 100755 index 00000000..36101083 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-0.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-1.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-1.bcmap new file mode 100755 index 00000000..707bb106 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-1.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-2.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-2.bcmap new file mode 100755 index 00000000..f7648cc3 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-2.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-3.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-3.bcmap new file mode 100755 index 00000000..85214589 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-3.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-4.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-4.bcmap new file mode 100755 index 00000000..e40c63ab Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-4.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-5.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-5.bcmap new file mode 100755 index 00000000..d7623b50 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-5.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-UCS2.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-UCS2.bcmap new file mode 100755 index 00000000..75865259 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-GB1-UCS2.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-0.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-0.bcmap new file mode 100755 index 00000000..f0e94ec1 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-0.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-1.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-1.bcmap new file mode 100755 index 00000000..dad42c5a Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-1.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-2.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-2.bcmap new file mode 100755 index 00000000..090819a0 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-2.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-3.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-3.bcmap new file mode 100755 index 00000000..087dfc15 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-3.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-4.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-4.bcmap new file mode 100755 index 00000000..46aa9bff Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-4.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-5.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-5.bcmap new file mode 100755 index 00000000..5b4b65cc Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-5.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-6.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-6.bcmap new file mode 100755 index 00000000..e77d699a Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-6.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-UCS2.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-UCS2.bcmap new file mode 100755 index 00000000..128a1410 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Japan1-UCS2.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Korea1-0.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Korea1-0.bcmap new file mode 100755 index 00000000..cef1a998 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Korea1-0.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Korea1-1.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Korea1-1.bcmap new file mode 100755 index 00000000..11ffa36d Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Korea1-1.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Korea1-2.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Korea1-2.bcmap new file mode 100755 index 00000000..3172308c Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Korea1-2.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Korea1-UCS2.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Korea1-UCS2.bcmap new file mode 100755 index 00000000..f3371c0c Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Adobe-Korea1-UCS2.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/B5-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/B5-H.bcmap new file mode 100755 index 00000000..beb4d228 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/B5-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/B5-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/B5-V.bcmap new file mode 100755 index 00000000..2d4f87d5 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/B5-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/B5pc-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/B5pc-H.bcmap new file mode 100755 index 00000000..ce001316 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/B5pc-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/B5pc-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/B5pc-V.bcmap new file mode 100755 index 00000000..73b99ff2 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/B5pc-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS-EUC-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS-EUC-H.bcmap new file mode 100755 index 00000000..61d1d0cb Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS-EUC-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS-EUC-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS-EUC-V.bcmap new file mode 100755 index 00000000..1a393a51 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS-EUC-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS1-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS1-H.bcmap new file mode 100755 index 00000000..f738e218 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS1-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS1-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS1-V.bcmap new file mode 100755 index 00000000..9c3169f0 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS1-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS2-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS2-H.bcmap new file mode 100755 index 00000000..c89b3527 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS2-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS2-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS2-V.bcmap new file mode 100755 index 00000000..7588cec8 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/cmaps/CNS2-V.bcmap @@ -0,0 +1,3 @@ +ΰRCopyright 1990-2009 Adobe Systems Incorporated. +All rights reserved. +See ./LICENSEαCNS2-H \ No newline at end of file diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETHK-B5-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETHK-B5-H.bcmap new file mode 100755 index 00000000..cb29415d Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETHK-B5-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETHK-B5-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETHK-B5-V.bcmap new file mode 100755 index 00000000..f09aec63 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETHK-B5-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETen-B5-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETen-B5-H.bcmap new file mode 100755 index 00000000..c2d77462 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETen-B5-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETen-B5-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETen-B5-V.bcmap new file mode 100755 index 00000000..89bff159 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETen-B5-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETenms-B5-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETenms-B5-H.bcmap new file mode 100755 index 00000000..a7d69db5 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETenms-B5-H.bcmap @@ -0,0 +1,3 @@ +ΰRCopyright 1990-2009 Adobe Systems Incorporated. +All rights reserved. +See ./LICENSEα ETen-B5-H` ^ \ No newline at end of file diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETenms-B5-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETenms-B5-V.bcmap new file mode 100755 index 00000000..adc5d618 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/ETenms-B5-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/EUC-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/EUC-H.bcmap new file mode 100755 index 00000000..e92ea5b3 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/EUC-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/EUC-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/EUC-V.bcmap new file mode 100755 index 00000000..7a7c1832 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/EUC-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Ext-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Ext-H.bcmap new file mode 100755 index 00000000..3b5cde44 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Ext-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Ext-RKSJ-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Ext-RKSJ-H.bcmap new file mode 100755 index 00000000..ea4d2d97 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Ext-RKSJ-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Ext-RKSJ-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Ext-RKSJ-V.bcmap new file mode 100755 index 00000000..3457c277 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Ext-RKSJ-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Ext-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Ext-V.bcmap new file mode 100755 index 00000000..4999ca40 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Ext-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GB-EUC-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GB-EUC-H.bcmap new file mode 100755 index 00000000..e39908b9 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GB-EUC-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GB-EUC-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GB-EUC-V.bcmap new file mode 100755 index 00000000..d5be5446 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GB-EUC-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GB-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GB-H.bcmap new file mode 100755 index 00000000..39189c54 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GB-H.bcmap @@ -0,0 +1,4 @@ +ΰRCopyright 1990-2009 Adobe Systems Incorporated. +All rights reserved. +See ./LICENSE!!Ί]aX!!]`21> p z$]‚"R‚d-Uƒ7*„ 4„%+ „Z „{/…%…<9K…b1]†."‡ ‰`]‡,"]ˆ +"]ˆh"]‰F"]Š$"]‹"]‹`"]Œ>"]"]z"]ŽX"]6"]"]r"]‘P"]’."]“ "]“j"]”H"]•&"]–"]–b"]—@"]˜"]˜|"]™Z"]š8"]›"]›t"]œR"]0"]ž"]žl"]ŸJ"] ("]‘"]‘d"]’B"]£ "X£~']€W"]₯5"]¦"]¦q"]§O"]¨-"]© "]©i"]ͺG"]«%"]¬"]¬a"]­?"]"]{"]―Y"]°7"]±"]±s"]²Q"]³/"]΄ "]΄k"]΅I"]Ά'"]·"]·c"]ΈA"]Ή"]Ή}"]Ί["]»9 \ No newline at end of file diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GB-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GB-V.bcmap new file mode 100755 index 00000000..31083451 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GB-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBK-EUC-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBK-EUC-H.bcmap new file mode 100755 index 00000000..05fff7e8 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBK-EUC-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBK-EUC-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBK-EUC-V.bcmap new file mode 100755 index 00000000..0cdf6bed Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBK-EUC-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBK2K-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBK2K-H.bcmap new file mode 100755 index 00000000..46f6ba59 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBK2K-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBK2K-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBK2K-V.bcmap new file mode 100755 index 00000000..d9a94798 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBK2K-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBKp-EUC-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBKp-EUC-H.bcmap new file mode 100755 index 00000000..5cb0af68 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBKp-EUC-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBKp-EUC-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBKp-EUC-V.bcmap new file mode 100755 index 00000000..bca93b8e Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBKp-EUC-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBT-EUC-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBT-EUC-H.bcmap new file mode 100755 index 00000000..4b4e2d32 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBT-EUC-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBT-EUC-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBT-EUC-V.bcmap new file mode 100755 index 00000000..38f70669 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBT-EUC-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBT-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBT-H.bcmap new file mode 100755 index 00000000..8437ac33 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBT-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBT-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBT-V.bcmap new file mode 100755 index 00000000..697ab4a8 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBT-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBTpc-EUC-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBTpc-EUC-H.bcmap new file mode 100755 index 00000000..f6e50e89 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBTpc-EUC-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBTpc-EUC-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBTpc-EUC-V.bcmap new file mode 100755 index 00000000..6c0d71a2 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBTpc-EUC-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBpc-EUC-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBpc-EUC-H.bcmap new file mode 100755 index 00000000..c9edf67c Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBpc-EUC-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBpc-EUC-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBpc-EUC-V.bcmap new file mode 100755 index 00000000..31450c97 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/GBpc-EUC-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/H.bcmap new file mode 100755 index 00000000..7b24ea46 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKdla-B5-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKdla-B5-H.bcmap new file mode 100755 index 00000000..7d30c050 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKdla-B5-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKdla-B5-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKdla-B5-V.bcmap new file mode 100755 index 00000000..78946940 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKdla-B5-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKdlb-B5-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKdlb-B5-H.bcmap new file mode 100755 index 00000000..d829a231 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKdlb-B5-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKdlb-B5-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKdlb-B5-V.bcmap new file mode 100755 index 00000000..2b572b50 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKdlb-B5-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKgccs-B5-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKgccs-B5-H.bcmap new file mode 100755 index 00000000..971a4f23 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKgccs-B5-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKgccs-B5-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKgccs-B5-V.bcmap new file mode 100755 index 00000000..d353ca25 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKgccs-B5-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKm314-B5-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKm314-B5-H.bcmap new file mode 100755 index 00000000..576dc011 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKm314-B5-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKm314-B5-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKm314-B5-V.bcmap new file mode 100755 index 00000000..0e96d0e2 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKm314-B5-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKm471-B5-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKm471-B5-H.bcmap new file mode 100755 index 00000000..11d170c7 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKm471-B5-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKm471-B5-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKm471-B5-V.bcmap new file mode 100755 index 00000000..54959bf9 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKm471-B5-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKscs-B5-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKscs-B5-H.bcmap new file mode 100755 index 00000000..6ef7857a Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKscs-B5-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKscs-B5-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKscs-B5-V.bcmap new file mode 100755 index 00000000..1fb2fa2a Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/HKscs-B5-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Hankaku.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Hankaku.bcmap new file mode 100755 index 00000000..4b8ec7fc Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Hankaku.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Hiragana.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Hiragana.bcmap new file mode 100755 index 00000000..17e983e7 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Hiragana.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-EUC-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-EUC-H.bcmap new file mode 100755 index 00000000..a45c65f0 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-EUC-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-EUC-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-EUC-V.bcmap new file mode 100755 index 00000000..0e7b21f0 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-EUC-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-H.bcmap new file mode 100755 index 00000000..b9b22b67 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-Johab-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-Johab-H.bcmap new file mode 100755 index 00000000..2531ffcf Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-Johab-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-Johab-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-Johab-V.bcmap new file mode 100755 index 00000000..367ceb22 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-Johab-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-V.bcmap new file mode 100755 index 00000000..6ae2f0b6 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSC-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCms-UHC-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCms-UHC-H.bcmap new file mode 100755 index 00000000..a8d4240e Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCms-UHC-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCms-UHC-HW-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCms-UHC-HW-H.bcmap new file mode 100755 index 00000000..8b4ae18f Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCms-UHC-HW-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCms-UHC-HW-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCms-UHC-HW-V.bcmap new file mode 100755 index 00000000..b655dbcf Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCms-UHC-HW-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCms-UHC-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCms-UHC-V.bcmap new file mode 100755 index 00000000..21f97f65 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCms-UHC-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCpc-EUC-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCpc-EUC-H.bcmap new file mode 100755 index 00000000..e06f361e Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCpc-EUC-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCpc-EUC-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCpc-EUC-V.bcmap new file mode 100755 index 00000000..f3c9113f Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/KSCpc-EUC-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Katakana.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Katakana.bcmap new file mode 100755 index 00000000..524303c4 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Katakana.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/LICENSE b/twake/frontend/public/public/viewer/PDFViewer/cmaps/LICENSE new file mode 100755 index 00000000..b1ad168a --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/cmaps/LICENSE @@ -0,0 +1,36 @@ +%%Copyright: ----------------------------------------------------------- +%%Copyright: Copyright 1990-2009 Adobe Systems Incorporated. +%%Copyright: All rights reserved. +%%Copyright: +%%Copyright: Redistribution and use in source and binary forms, with or +%%Copyright: without modification, are permitted provided that the +%%Copyright: following conditions are met: +%%Copyright: +%%Copyright: Redistributions of source code must retain the above +%%Copyright: copyright notice, this list of conditions and the following +%%Copyright: disclaimer. +%%Copyright: +%%Copyright: Redistributions in binary form must reproduce the above +%%Copyright: copyright notice, this list of conditions and the following +%%Copyright: disclaimer in the documentation and/or other materials +%%Copyright: provided with the distribution. +%%Copyright: +%%Copyright: Neither the name of Adobe Systems Incorporated nor the names +%%Copyright: of its contributors may be used to endorse or promote +%%Copyright: products derived from this software without specific prior +%%Copyright: written permission. +%%Copyright: +%%Copyright: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +%%Copyright: CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +%%Copyright: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +%%Copyright: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +%%Copyright: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +%%Copyright: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +%%Copyright: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +%%Copyright: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +%%Copyright: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +%%Copyright: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +%%Copyright: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +%%Copyright: OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +%%Copyright: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +%%Copyright: ----------------------------------------------------------- diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/NWP-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/NWP-H.bcmap new file mode 100755 index 00000000..afc5e4b0 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/NWP-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/NWP-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/NWP-V.bcmap new file mode 100755 index 00000000..bb5785e3 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/NWP-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/RKSJ-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/RKSJ-H.bcmap new file mode 100755 index 00000000..fb8d298e Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/RKSJ-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/RKSJ-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/RKSJ-V.bcmap new file mode 100755 index 00000000..a2555a6c Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/RKSJ-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/Roman.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Roman.bcmap new file mode 100755 index 00000000..f896dcf1 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/Roman.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UCS2-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UCS2-H.bcmap new file mode 100755 index 00000000..d5db27c5 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UCS2-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UCS2-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UCS2-V.bcmap new file mode 100755 index 00000000..1dc9b7a2 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UCS2-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF16-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF16-H.bcmap new file mode 100755 index 00000000..961afefb Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF16-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF16-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF16-V.bcmap new file mode 100755 index 00000000..df0cffe8 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF16-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF32-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF32-H.bcmap new file mode 100755 index 00000000..1ab18a14 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF32-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF32-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF32-V.bcmap new file mode 100755 index 00000000..ad14662e Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF32-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF8-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF8-H.bcmap new file mode 100755 index 00000000..83c6bd7c Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF8-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF8-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF8-V.bcmap new file mode 100755 index 00000000..22a27e4d Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniCNS-UTF8-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UCS2-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UCS2-H.bcmap new file mode 100755 index 00000000..5bd6228c Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UCS2-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UCS2-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UCS2-V.bcmap new file mode 100755 index 00000000..53c534b7 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UCS2-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF16-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF16-H.bcmap new file mode 100755 index 00000000..b95045b4 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF16-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF16-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF16-V.bcmap new file mode 100755 index 00000000..51f023e0 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF16-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF32-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF32-H.bcmap new file mode 100755 index 00000000..f0dbd14f Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF32-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF32-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF32-V.bcmap new file mode 100755 index 00000000..ce9c30a9 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF32-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF8-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF8-H.bcmap new file mode 100755 index 00000000..982ca462 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF8-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF8-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF8-V.bcmap new file mode 100755 index 00000000..f78020dd Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniGB-UTF8-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UCS2-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UCS2-H.bcmap new file mode 100755 index 00000000..7daf56af Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UCS2-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UCS2-HW-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UCS2-HW-H.bcmap new file mode 100755 index 00000000..ac9975c5 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UCS2-HW-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UCS2-HW-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UCS2-HW-V.bcmap new file mode 100755 index 00000000..3da0a1c6 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UCS2-HW-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UCS2-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UCS2-V.bcmap new file mode 100755 index 00000000..c50b9ddf Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UCS2-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF16-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF16-H.bcmap new file mode 100755 index 00000000..67613446 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF16-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF16-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF16-V.bcmap new file mode 100755 index 00000000..70bf90c0 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF16-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF32-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF32-H.bcmap new file mode 100755 index 00000000..7a83d53a Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF32-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF32-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF32-V.bcmap new file mode 100755 index 00000000..7a871353 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF32-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF8-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF8-H.bcmap new file mode 100755 index 00000000..9f0334ca Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF8-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF8-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF8-V.bcmap new file mode 100755 index 00000000..808a94f0 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS-UTF8-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF16-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF16-H.bcmap new file mode 100755 index 00000000..d768bf81 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF16-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF16-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF16-V.bcmap new file mode 100755 index 00000000..3d5bf6fb Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF16-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF32-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF32-H.bcmap new file mode 100755 index 00000000..09eee10d Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF32-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF32-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF32-V.bcmap new file mode 100755 index 00000000..6c546001 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF32-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF8-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF8-H.bcmap new file mode 100755 index 00000000..1b1a64f5 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF8-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF8-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF8-V.bcmap new file mode 100755 index 00000000..994aa9ef Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJIS2004-UTF8-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISPro-UCS2-HW-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISPro-UCS2-HW-V.bcmap new file mode 100755 index 00000000..643f921b Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISPro-UCS2-HW-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISPro-UCS2-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISPro-UCS2-V.bcmap new file mode 100755 index 00000000..c148f67f Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISPro-UCS2-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISPro-UTF8-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISPro-UTF8-V.bcmap new file mode 100755 index 00000000..1849d809 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISPro-UTF8-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISX0213-UTF32-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISX0213-UTF32-H.bcmap new file mode 100755 index 00000000..a83a677c Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISX0213-UTF32-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISX0213-UTF32-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISX0213-UTF32-V.bcmap new file mode 100755 index 00000000..f527248a Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISX0213-UTF32-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISX02132004-UTF32-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISX02132004-UTF32-H.bcmap new file mode 100755 index 00000000..e1a988dc Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISX02132004-UTF32-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISX02132004-UTF32-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISX02132004-UTF32-V.bcmap new file mode 100755 index 00000000..47e054a9 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniJISX02132004-UTF32-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UCS2-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UCS2-H.bcmap new file mode 100755 index 00000000..b5b94852 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UCS2-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UCS2-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UCS2-V.bcmap new file mode 100755 index 00000000..026adcaa Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UCS2-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF16-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF16-H.bcmap new file mode 100755 index 00000000..fd4e66e8 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF16-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF16-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF16-V.bcmap new file mode 100755 index 00000000..075efb70 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF16-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF32-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF32-H.bcmap new file mode 100755 index 00000000..769d2142 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF32-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF32-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF32-V.bcmap new file mode 100755 index 00000000..bdab208b Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF32-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF8-H.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF8-H.bcmap new file mode 100755 index 00000000..6ff8674a Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF8-H.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF8-V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF8-V.bcmap new file mode 100755 index 00000000..8dfa76a5 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/UniKS-UTF8-V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/V.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/V.bcmap new file mode 100755 index 00000000..fdec9906 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/V.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/cmaps/WP-Symbol.bcmap b/twake/frontend/public/public/viewer/PDFViewer/cmaps/WP-Symbol.bcmap new file mode 100755 index 00000000..46729bbf Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/cmaps/WP-Symbol.bcmap differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/debugger.js b/twake/frontend/public/public/viewer/PDFViewer/debugger.js new file mode 100755 index 00000000..38738d8b --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/debugger.js @@ -0,0 +1,635 @@ +/* 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. + */ + +'use strict'; + +var FontInspector = (function FontInspectorClosure() { + var fonts; + var active = false; + var fontAttribute = 'data-font-name'; + + function removeSelection() { + var divs = document.querySelectorAll('div[' + fontAttribute + ']'); + for (var i = 0, ii = divs.length; i < ii; ++i) { + var div = divs[i]; + div.className = ''; + } + } + + function resetSelection() { + var divs = document.querySelectorAll('div[' + fontAttribute + ']'); + for (var i = 0, ii = divs.length; i < ii; ++i) { + var div = divs[i]; + div.className = 'debuggerHideText'; + } + } + + function selectFont(fontName, show) { + var divs = document.querySelectorAll('div[' + fontAttribute + '=' + + fontName + ']'); + for (var i = 0, ii = divs.length; i < ii; ++i) { + var div = divs[i]; + div.className = show ? 'debuggerShowText' : 'debuggerHideText'; + } + } + + function textLayerClick(e) { + if (!e.target.dataset.fontName || + e.target.tagName.toUpperCase() !== 'DIV') { + return; + } + var fontName = e.target.dataset.fontName; + var selects = document.getElementsByTagName('input'); + for (var i = 0; i < selects.length; ++i) { + var select = selects[i]; + if (select.dataset.fontName !== fontName) { + continue; + } + select.checked = !select.checked; + selectFont(fontName, select.checked); + select.scrollIntoView(); + } + } + + return { + // Properties/functions needed by PDFBug. + id: 'FontInspector', + name: 'Font Inspector', + panel: null, + manager: null, + init: function init(pdfjsLib) { + var panel = this.panel; + panel.setAttribute('style', 'padding: 5px;'); + var tmp = document.createElement('button'); + tmp.addEventListener('click', resetSelection); + tmp.textContent = 'Refresh'; + panel.appendChild(tmp); + + fonts = document.createElement('div'); + panel.appendChild(fonts); + }, + cleanup: function cleanup() { + fonts.textContent = ''; + }, + enabled: false, + get active() { + return active; + }, + set active(value) { + active = value; + if (active) { + document.body.addEventListener('click', textLayerClick, true); + resetSelection(); + } else { + document.body.removeEventListener('click', textLayerClick, true); + removeSelection(); + } + }, + // FontInspector specific functions. + fontAdded: function fontAdded(fontObj, url) { + function properties(obj, list) { + var moreInfo = document.createElement('table'); + for (var i = 0; i < list.length; i++) { + var tr = document.createElement('tr'); + var td1 = document.createElement('td'); + td1.textContent = list[i]; + tr.appendChild(td1); + var td2 = document.createElement('td'); + td2.textContent = obj[list[i]].toString(); + tr.appendChild(td2); + moreInfo.appendChild(tr); + } + return moreInfo; + } + + var moreInfo = properties(fontObj, ['name', 'type']); + var fontName = fontObj.loadedName; + var font = document.createElement('div'); + var name = document.createElement('span'); + name.textContent = fontName; + var download = document.createElement('a'); + if (url) { + url = /url\(['"]?([^\)"']+)/.exec(url); + download.href = url[1]; + } else if (fontObj.data) { + url = URL.createObjectURL(new Blob([fontObj.data], { + type: fontObj.mimeType, + })); + download.href = url; + } + download.textContent = 'Download'; + var logIt = document.createElement('a'); + logIt.href = ''; + logIt.textContent = 'Log'; + logIt.addEventListener('click', function (event) { + event.preventDefault(); + console.log(fontObj); + }); + var select = document.createElement('input'); + select.setAttribute('type', 'checkbox'); + select.dataset.fontName = fontName; + select.addEventListener('click', (function (select, fontName) { + return (function () { + selectFont(fontName, select.checked); + }); + })(select, fontName)); + font.appendChild(select); + font.appendChild(name); + font.appendChild(document.createTextNode(' ')); + font.appendChild(download); + font.appendChild(document.createTextNode(' ')); + font.appendChild(logIt); + font.appendChild(moreInfo); + fonts.appendChild(font); + // Somewhat of a hack, should probably add a hook for when the text layer + // is done rendering. + setTimeout(() = > { + if(this.active + ) + { + resetSelection(); + } + }, + 2000 + ) + ; + }, + }; +})(); + +var opMap; + +// Manages all the page steppers. +var StepperManager = (function StepperManagerClosure() { + var steppers = []; + var stepperDiv = null; + var stepperControls = null; + var stepperChooser = null; + var breakPoints = Object.create(null); + return { + // Properties/functions needed by PDFBug. + id: 'Stepper', + name: 'Stepper', + panel: null, + manager: null, + init: function init(pdfjsLib) { + var self = this; + this.panel.setAttribute('style', 'padding: 5px;'); + stepperControls = document.createElement('div'); + stepperChooser = document.createElement('select'); + stepperChooser.addEventListener('change', function (event) { + self.selectStepper(this.value); + }); + stepperControls.appendChild(stepperChooser); + stepperDiv = document.createElement('div'); + this.panel.appendChild(stepperControls); + this.panel.appendChild(stepperDiv); + if (sessionStorage.getItem('pdfjsBreakPoints')) { + breakPoints = JSON.parse(sessionStorage.getItem('pdfjsBreakPoints')); + } + + opMap = Object.create(null); + for (var key in pdfjsLib.OPS) { + opMap[pdfjsLib.OPS[key]] = key; + } + }, + cleanup: function cleanup() { + stepperChooser.textContent = ''; + stepperDiv.textContent = ''; + steppers = []; + }, + enabled: false, + active: false, + // Stepper specific functions. + create: function create(pageIndex) { + var debug = document.createElement('div'); + debug.id = 'stepper' + pageIndex; + debug.setAttribute('hidden', true); + debug.className = 'stepper'; + stepperDiv.appendChild(debug); + var b = document.createElement('option'); + b.textContent = 'Page ' + (pageIndex + 1); + b.value = pageIndex; + stepperChooser.appendChild(b); + var initBreakPoints = breakPoints[pageIndex] || []; + var stepper = new Stepper(debug, pageIndex, initBreakPoints); + steppers.push(stepper); + if (steppers.length === 1) { + this.selectStepper(pageIndex, false); + } + return stepper; + }, + selectStepper: function selectStepper(pageIndex, selectPanel) { + var i; + pageIndex = pageIndex | 0; + if (selectPanel) { + this.manager.selectPanel(this); + } + for (i = 0; i < steppers.length; ++i) { + var stepper = steppers[i]; + if (stepper.pageIndex === pageIndex) { + stepper.panel.removeAttribute('hidden'); + } else { + stepper.panel.setAttribute('hidden', true); + } + } + var options = stepperChooser.options; + for (i = 0; i < options.length; ++i) { + var option = options[i]; + option.selected = (option.value | 0) === pageIndex; + } + }, + saveBreakPoints: function saveBreakPoints(pageIndex, bps) { + breakPoints[pageIndex] = bps; + sessionStorage.setItem('pdfjsBreakPoints', JSON.stringify(breakPoints)); + }, + }; +})(); + +// The stepper for each page's IRQueue. +var Stepper = (function StepperClosure() { + // Shorter way to create element and optionally set textContent. + function c(tag, textContent) { + var d = document.createElement(tag); + if (textContent) { + d.textContent = textContent; + } + return d; + } + + function simplifyArgs(args) { + if (typeof args === 'string') { + var MAX_STRING_LENGTH = 75; + return args.length <= MAX_STRING_LENGTH ? args : + args.substr(0, MAX_STRING_LENGTH) + '...'; + } + if (typeof args !== 'object' || args === null) { + return args; + } + if ('length' in args) { // array + var simpleArgs = [], i, ii; + var MAX_ITEMS = 10; + for (i = 0, ii = Math.min(MAX_ITEMS, args.length); i < ii; i++) { + simpleArgs.push(simplifyArgs(args[i])); + } + if (i < args.length) { + simpleArgs.push('...'); + } + return simpleArgs; + } + var simpleObj = {}; + for (var key in args) { + simpleObj[key] = simplifyArgs(args[key]); + } + return simpleObj; + } + + function Stepper(panel, pageIndex, initialBreakPoints) { + this.panel = panel; + this.breakPoint = 0; + this.nextBreakPoint = null; + this.pageIndex = pageIndex; + this.breakPoints = initialBreakPoints; + this.currentIdx = -1; + this.operatorListIdx = 0; + } + + Stepper.prototype = { + init: function init(operatorList) { + var panel = this.panel; + var content = c('div', 'c=continue, s=step'); + var table = c('table'); + content.appendChild(table); + table.cellSpacing = 0; + var headerRow = c('tr'); + table.appendChild(headerRow); + headerRow.appendChild(c('th', 'Break')); + headerRow.appendChild(c('th', 'Idx')); + headerRow.appendChild(c('th', 'fn')); + headerRow.appendChild(c('th', 'args')); + panel.appendChild(content); + this.table = table; + this.updateOperatorList(operatorList); + }, + updateOperatorList: function updateOperatorList(operatorList) { + var self = this; + + function cboxOnClick() { + var x = +this.dataset.idx; + if (this.checked) { + self.breakPoints.push(x); + } else { + self.breakPoints.splice(self.breakPoints.indexOf(x), 1); + } + StepperManager.saveBreakPoints(self.pageIndex, self.breakPoints); + } + + var MAX_OPERATORS_COUNT = 15000; + if (this.operatorListIdx > MAX_OPERATORS_COUNT) { + return; + } + + var chunk = document.createDocumentFragment(); + var operatorsToDisplay = Math.min(MAX_OPERATORS_COUNT, + operatorList.fnArray.length); + for (var i = this.operatorListIdx; i < operatorsToDisplay; i++) { + var line = c('tr'); + line.className = 'line'; + line.dataset.idx = i; + chunk.appendChild(line); + var checked = this.breakPoints.indexOf(i) !== -1; + var args = operatorList.argsArray[i] || []; + + var breakCell = c('td'); + var cbox = c('input'); + cbox.type = 'checkbox'; + cbox.className = 'points'; + cbox.checked = checked; + cbox.dataset.idx = i; + cbox.onclick = cboxOnClick; + + breakCell.appendChild(cbox); + line.appendChild(breakCell); + line.appendChild(c('td', i.toString())); + var fn = opMap[operatorList.fnArray[i]]; + var decArgs = args; + if (fn === 'showText') { + var glyphs = args[0]; + var newArgs = []; + var str = []; + for (var j = 0; j < glyphs.length; j++) { + var glyph = glyphs[j]; + if (typeof glyph === 'object' && glyph !== null) { + str.push(glyph.fontChar); + } else { + if (str.length > 0) { + newArgs.push(str.join('')); + str = []; + } + newArgs.push(glyph); // null or number + } + } + if (str.length > 0) { + newArgs.push(str.join('')); + } + decArgs = [newArgs]; + } + line.appendChild(c('td', fn)); + line.appendChild(c('td', JSON.stringify(simplifyArgs(decArgs)))); + } + if (operatorsToDisplay < operatorList.fnArray.length) { + line = c('tr'); + var lastCell = c('td', '...'); + lastCell.colspan = 4; + chunk.appendChild(lastCell); + } + this.operatorListIdx = operatorList.fnArray.length; + this.table.appendChild(chunk); + }, + getNextBreakPoint: function getNextBreakPoint() { + this.breakPoints.sort(function (a, b) { + return a - b; + }); + for (var i = 0; i < this.breakPoints.length; i++) { + if (this.breakPoints[i] > this.currentIdx) { + return this.breakPoints[i]; + } + } + return null; + }, + breakIt: function breakIt(idx, callback) { + StepperManager.selectStepper(this.pageIndex, true); + var self = this; + var dom = document; + self.currentIdx = idx; + var listener = function (e) { + switch (e.keyCode) { + case 83: // step + dom.removeEventListener('keydown', listener); + self.nextBreakPoint = self.currentIdx + 1; + self.goTo(-1); + callback(); + break; + case 67: // continue + dom.removeEventListener('keydown', listener); + var breakPoint = self.getNextBreakPoint(); + self.nextBreakPoint = breakPoint; + self.goTo(-1); + callback(); + break; + } + }; + dom.addEventListener('keydown', listener); + self.goTo(idx); + }, + goTo: function goTo(idx) { + var allRows = this.panel.getElementsByClassName('line'); + for (var x = 0, xx = allRows.length; x < xx; ++x) { + var row = allRows[x]; + if ((row.dataset.idx | 0) === idx) { + row.style.backgroundColor = 'rgb(251,250,207)'; + row.scrollIntoView(); + } else { + row.style.backgroundColor = null; + } + } + }, + }; + return Stepper; +})(); + +var Stats = (function Stats() { + var stats = []; + + function clear(node) { + while (node.hasChildNodes()) { + node.removeChild(node.lastChild); + } + } + + function getStatIndex(pageNumber) { + for (var i = 0, ii = stats.length; i < ii; ++i) { + if (stats[i].pageNumber === pageNumber) { + return i; + } + } + return false; + } + + return { + // Properties/functions needed by PDFBug. + id: 'Stats', + name: 'Stats', + panel: null, + manager: null, + init(pdfjsLib) { + this.panel.setAttribute('style', 'padding: 5px;'); + pdfjsLib.PDFJS.enableStats = true; + }, + enabled: false, + active: false, + // Stats specific functions. + add(pageNumber, stat) { + if (!stat) { + return; + } + var statsIndex = getStatIndex(pageNumber); + if (statsIndex !== false) { + var b = stats[statsIndex]; + this.panel.removeChild(b.div); + stats.splice(statsIndex, 1); + } + var wrapper = document.createElement('div'); + wrapper.className = 'stats'; + var title = document.createElement('div'); + title.className = 'title'; + title.textContent = 'Page: ' + pageNumber; + var statsDiv = document.createElement('div'); + statsDiv.textContent = stat.toString(); + wrapper.appendChild(title); + wrapper.appendChild(statsDiv); + stats.push({pageNumber, div: wrapper,}); + stats.sort(function (a, b) { + return a.pageNumber - b.pageNumber; + }); + clear(this.panel); + for (var i = 0, ii = stats.length; i < ii; ++i) { + this.panel.appendChild(stats[i].div); + } + }, + cleanup() { + stats = []; + clear(this.panel); + }, + }; +})(); + +// Manages all the debugging tools. +window.PDFBug = (function PDFBugClosure() { + var panelWidth = 300; + var buttons = []; + var activePanel = null; + + return { + tools: [ + FontInspector, + StepperManager, + Stats + ], + enable(ids) { + var all = false, tools = this.tools; + if (ids.length === 1 && ids[0] === 'all') { + all = true; + } + for (var i = 0; i < tools.length; ++i) { + var tool = tools[i]; + if (all || ids.indexOf(tool.id) !== -1) { + tool.enabled = true; + } + } + if (!all) { + // Sort the tools by the order they are enabled. + tools.sort(function (a, b) { + var indexA = ids.indexOf(a.id); + indexA = indexA < 0 ? tools.length : indexA; + var indexB = ids.indexOf(b.id); + indexB = indexB < 0 ? tools.length : indexB; + return indexA - indexB; + }); + } + }, + init(pdfjsLib, container) { + /* + * Basic Layout: + * PDFBug + * Controls + * Panels + * Panel + * Panel + * ... + */ + var ui = document.createElement('div'); + ui.id = 'PDFBug'; + + var controls = document.createElement('div'); + controls.setAttribute('class', 'controls'); + ui.appendChild(controls); + + var panels = document.createElement('div'); + panels.setAttribute('class', 'panels'); + ui.appendChild(panels); + + container.appendChild(ui); + container.style.right = panelWidth + 'px'; + + // Initialize all the debugging tools. + var tools = this.tools; + var self = this; + for (var i = 0; i < tools.length; ++i) { + var tool = tools[i]; + var panel = document.createElement('div'); + var panelButton = document.createElement('button'); + panelButton.textContent = tool.name; + panelButton.addEventListener('click', (function (selected) { + return function (event) { + event.preventDefault(); + self.selectPanel(selected); + }; + })(i)); + controls.appendChild(panelButton); + panels.appendChild(panel); + tool.panel = panel; + tool.manager = this; + if (tool.enabled) { + tool.init(pdfjsLib); + } else { + panel.textContent = tool.name + ' is disabled. To enable add ' + + ' "' + tool.id + '" to the pdfBug parameter ' + + 'and refresh (separate multiple by commas).'; + } + buttons.push(panelButton); + } + this.selectPanel(0); + }, + cleanup() { + for (var i = 0, ii = this.tools.length; i < ii; i++) { + if (this.tools[i].enabled) { + this.tools[i].cleanup(); + } + } + }, + selectPanel(index) { + if (typeof index !== 'number') { + index = this.tools.indexOf(index); + } + if (index === activePanel) { + return; + } + activePanel = index; + var tools = this.tools; + for (var j = 0; j < tools.length; ++j) { + if (j === index) { + buttons[j].setAttribute('class', 'active'); + tools[j].active = true; + tools[j].panel.removeAttribute('hidden'); + } else { + buttons[j].setAttribute('class', ''); + tools[j].active = false; + tools[j].panel.setAttribute('hidden', 'true'); + } + } + }, + }; +})(); diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/annotation-check.svg b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-check.svg new file mode 100755 index 00000000..ec42b0c8 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-check.svg @@ -0,0 +1,11 @@ + + + + diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/annotation-comment.svg b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-comment.svg new file mode 100755 index 00000000..115037e0 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-comment.svg @@ -0,0 +1,16 @@ + + + + + diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/annotation-help.svg b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-help.svg new file mode 100755 index 00000000..cce51bc6 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-help.svg @@ -0,0 +1,26 @@ + + + + + + + + + + diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/annotation-insert.svg b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-insert.svg new file mode 100755 index 00000000..b36eb132 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-insert.svg @@ -0,0 +1,10 @@ + + + + diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/annotation-key.svg b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-key.svg new file mode 100755 index 00000000..848598a9 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-key.svg @@ -0,0 +1,11 @@ + + + + diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/annotation-newparagraph.svg b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-newparagraph.svg new file mode 100755 index 00000000..1e36e719 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-newparagraph.svg @@ -0,0 +1,11 @@ + + + + diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/annotation-noicon.svg b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-noicon.svg new file mode 100755 index 00000000..205feb07 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-noicon.svg @@ -0,0 +1,7 @@ + + + diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/annotation-note.svg b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-note.svg new file mode 100755 index 00000000..20cdb817 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-note.svg @@ -0,0 +1,42 @@ + + + + + + + + diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/annotation-paragraph.svg b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-paragraph.svg new file mode 100755 index 00000000..abf0f3a6 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/images/annotation-paragraph.svg @@ -0,0 +1,16 @@ + + + + + diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-next-rtl.png b/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-next-rtl.png new file mode 100755 index 00000000..bef02743 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-next-rtl.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-next-rtl@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-next-rtl@2x.png new file mode 100755 index 00000000..1da6dc94 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-next-rtl@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-next.png b/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-next.png new file mode 100755 index 00000000..de1d0fc9 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-next.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-next@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-next@2x.png new file mode 100755 index 00000000..0250307c Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-next@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-previous-rtl.png b/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-previous-rtl.png new file mode 100755 index 00000000..de1d0fc9 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-previous-rtl.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-previous-rtl@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-previous-rtl@2x.png new file mode 100755 index 00000000..0250307c Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-previous-rtl@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-previous.png b/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-previous.png new file mode 100755 index 00000000..bef02743 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-previous.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-previous@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-previous@2x.png new file mode 100755 index 00000000..1da6dc94 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/findbarButton-previous@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/grab.cur b/twake/frontend/public/public/viewer/PDFViewer/images/grab.cur new file mode 100755 index 00000000..db7ad5ae Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/grab.cur differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/grabbing.cur b/twake/frontend/public/public/viewer/PDFViewer/images/grabbing.cur new file mode 100755 index 00000000..e0dfd04e Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/grabbing.cur differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/loading-icon.gif b/twake/frontend/public/public/viewer/PDFViewer/images/loading-icon.gif new file mode 100755 index 00000000..1c72ebb5 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/loading-icon.gif differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/loading-small.png b/twake/frontend/public/public/viewer/PDFViewer/images/loading-small.png new file mode 100755 index 00000000..8831a805 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/loading-small.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/loading-small@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/loading-small@2x.png new file mode 100755 index 00000000..b25b4452 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/loading-small@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-documentProperties.png b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-documentProperties.png new file mode 100755 index 00000000..40925e25 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-documentProperties.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-documentProperties@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-documentProperties@2x.png new file mode 100755 index 00000000..adb240ea Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-documentProperties@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-firstPage.png b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-firstPage.png new file mode 100755 index 00000000..e68846aa Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-firstPage.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-firstPage@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-firstPage@2x.png new file mode 100755 index 00000000..3ad8af51 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-firstPage@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-handTool.png b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-handTool.png new file mode 100755 index 00000000..cb85a841 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-handTool.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-handTool@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-handTool@2x.png new file mode 100755 index 00000000..5c13f77f Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-handTool@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-lastPage.png b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-lastPage.png new file mode 100755 index 00000000..be763e0c Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-lastPage.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-lastPage@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-lastPage@2x.png new file mode 100755 index 00000000..8570984f Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-lastPage@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-rotateCcw.png b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-rotateCcw.png new file mode 100755 index 00000000..675d6da2 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-rotateCcw.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-rotateCcw@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-rotateCcw@2x.png new file mode 100755 index 00000000..b9e74312 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-rotateCcw@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-rotateCw.png b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-rotateCw.png new file mode 100755 index 00000000..e1c75988 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-rotateCw.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-rotateCw@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-rotateCw@2x.png new file mode 100755 index 00000000..cb257b41 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-rotateCw@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-selectTool.png b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-selectTool.png new file mode 100755 index 00000000..25520a6f Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-selectTool.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-selectTool@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-selectTool@2x.png new file mode 100755 index 00000000..a58aaef4 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/secondaryToolbarButton-selectTool@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/shadow.png b/twake/frontend/public/public/viewer/PDFViewer/images/shadow.png new file mode 100755 index 00000000..31d3bdb1 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/shadow.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/texture.png b/twake/frontend/public/public/viewer/PDFViewer/images/texture.png new file mode 100755 index 00000000..12bae83a Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/texture.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-bookmark.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-bookmark.png new file mode 100755 index 00000000..a187be6c Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-bookmark.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-bookmark@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-bookmark@2x.png new file mode 100755 index 00000000..4efbaa67 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-bookmark@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-download.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-download.png new file mode 100755 index 00000000..eaab35f0 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-download.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-download@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-download@2x.png new file mode 100755 index 00000000..896face4 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-download@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-menuArrows.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-menuArrows.png new file mode 100755 index 00000000..e50ca4ee Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-menuArrows.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-menuArrows@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-menuArrows@2x.png new file mode 100755 index 00000000..f7570bc0 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-menuArrows@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-openFile.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-openFile.png new file mode 100755 index 00000000..b5cf1bd0 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-openFile.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-openFile@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-openFile@2x.png new file mode 100755 index 00000000..91ab7659 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-openFile@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageDown-rtl.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageDown-rtl.png new file mode 100755 index 00000000..1957f79a Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageDown-rtl.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageDown-rtl@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageDown-rtl@2x.png new file mode 100755 index 00000000..16ebcb8e Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageDown-rtl@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageDown.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageDown.png new file mode 100755 index 00000000..8219ecf8 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageDown.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageDown@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageDown@2x.png new file mode 100755 index 00000000..758c01d8 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageDown@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageUp-rtl.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageUp-rtl.png new file mode 100755 index 00000000..98e7ce48 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageUp-rtl.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageUp-rtl@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageUp-rtl@2x.png new file mode 100755 index 00000000..a01b0238 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageUp-rtl@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageUp.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageUp.png new file mode 100755 index 00000000..fb9daa33 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageUp.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageUp@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageUp@2x.png new file mode 100755 index 00000000..a5cfd755 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-pageUp@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-presentationMode.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-presentationMode.png new file mode 100755 index 00000000..3ac21244 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-presentationMode.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-presentationMode@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-presentationMode@2x.png new file mode 100755 index 00000000..cada9e79 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-presentationMode@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-print.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-print.png new file mode 100755 index 00000000..51275e54 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-print.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-print@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-print@2x.png new file mode 100755 index 00000000..53d18daf Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-print@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-search.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-search.png new file mode 100755 index 00000000..f9b75579 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-search.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-search@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-search@2x.png new file mode 100755 index 00000000..456b1332 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-search@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-secondaryToolbarToggle-rtl.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-secondaryToolbarToggle-rtl.png new file mode 100755 index 00000000..84370952 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-secondaryToolbarToggle-rtl.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-secondaryToolbarToggle-rtl@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-secondaryToolbarToggle-rtl@2x.png new file mode 100755 index 00000000..9d9bfa4f Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-secondaryToolbarToggle-rtl@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-secondaryToolbarToggle.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-secondaryToolbarToggle.png new file mode 100755 index 00000000..1f90f83d Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-secondaryToolbarToggle.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-secondaryToolbarToggle@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-secondaryToolbarToggle@2x.png new file mode 100755 index 00000000..b066fe5c Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-secondaryToolbarToggle@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-sidebarToggle-rtl.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-sidebarToggle-rtl.png new file mode 100755 index 00000000..6f85ec06 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-sidebarToggle-rtl.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-sidebarToggle-rtl@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-sidebarToggle-rtl@2x.png new file mode 100755 index 00000000..291e0067 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-sidebarToggle-rtl@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-sidebarToggle.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-sidebarToggle.png new file mode 100755 index 00000000..025dc904 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-sidebarToggle.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-sidebarToggle@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-sidebarToggle@2x.png new file mode 100755 index 00000000..7f834df9 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-sidebarToggle@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewAttachments.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewAttachments.png new file mode 100755 index 00000000..fcd0b268 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewAttachments.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewAttachments@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewAttachments@2x.png new file mode 100755 index 00000000..4a5e2b8a Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewAttachments@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewOutline-rtl.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewOutline-rtl.png new file mode 100755 index 00000000..aaa94302 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewOutline-rtl.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewOutline-rtl@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewOutline-rtl@2x.png new file mode 100755 index 00000000..3410f70d Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewOutline-rtl@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewOutline.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewOutline.png new file mode 100755 index 00000000..976365a5 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewOutline.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewOutline@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewOutline@2x.png new file mode 100755 index 00000000..b6a197fd Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewOutline@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewThumbnail.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewThumbnail.png new file mode 100755 index 00000000..584ba558 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewThumbnail.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewThumbnail@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewThumbnail@2x.png new file mode 100755 index 00000000..a0208b41 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-viewThumbnail@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-zoomIn.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-zoomIn.png new file mode 100755 index 00000000..513d081b Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-zoomIn.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-zoomIn@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-zoomIn@2x.png new file mode 100755 index 00000000..d5d49d5f Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-zoomIn@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-zoomOut.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-zoomOut.png new file mode 100755 index 00000000..156c26b9 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-zoomOut.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-zoomOut@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-zoomOut@2x.png new file mode 100755 index 00000000..959e1919 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/toolbarButton-zoomOut@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-collapsed-rtl.png b/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-collapsed-rtl.png new file mode 100755 index 00000000..0496b357 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-collapsed-rtl.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-collapsed-rtl@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-collapsed-rtl@2x.png new file mode 100755 index 00000000..6ad9ebcd Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-collapsed-rtl@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-collapsed.png b/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-collapsed.png new file mode 100755 index 00000000..06d4d376 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-collapsed.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-collapsed@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-collapsed@2x.png new file mode 100755 index 00000000..eec1e58c Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-collapsed@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-expanded.png b/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-expanded.png new file mode 100755 index 00000000..c8d55735 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-expanded.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-expanded@2x.png b/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-expanded@2x.png new file mode 100755 index 00000000..3b3b6103 Binary files /dev/null and b/twake/frontend/public/public/viewer/PDFViewer/images/treeitem-expanded@2x.png differ diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ach/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ach/viewer.properties new file mode 100755 index 00000000..fd5c1d00 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ach/viewer.properties @@ -0,0 +1,179 @@ +# 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=Pot buk mukato +previous_label=Mukato +next.title=Pot buk malubo +next_label=Malubo + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Pot buk +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=pi {{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}} me {{pagesCount}}) + +zoom_out.title=Jwik Matidi +zoom_out_label=Jwik Matidi +zoom_in.title=Kwot Madit +zoom_in_label=Kwot Madit +zoom.title=Kwoti +presentation_mode.title=Lokke i kit me tyer +presentation_mode_label=Kit me tyer +open_file.title=Yab Pwail +open_file_label=Yab +print.title=Go +print_label=Go +download.title=Gam +download_label=Gam +bookmark.title=Neno ma kombedi (lok onyo yab i dirica manyen) +bookmark_label=Neno ma kombedi + +# Secondary toolbar and context menu +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_hand_tool.title=Cak gitic me cing + +# Document properties dialog box +document_properties.title=Jami me gin acoya… +document_properties_label=Jami me gin acoya… +document_properties_file_name=Nying pwail: +document_properties_file_size=Dit pa pwail: +# 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=Wiye: +document_properties_author=Ngat mucoyo: +document_properties_subject=Subjek: +document_properties_keywords=Lok mapire tek: +document_properties_creation_date=Nino dwe me cwec: +document_properties_modification_date=Nino dwe me yub: +# 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=Lacwec: +document_properties_producer=Layub PDF: +document_properties_version=Kit PDF: +document_properties_page_count=Kwan me pot buk: +document_properties_close=Lor + +print_progress_message=Yubo coc me agoya… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Juki + +# 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=Lok gintic ma inget +toggle_sidebar_label=Lok gintic ma inget +document_outline_label=Pek pa gin acoya +attachments.title=Nyut twec +attachments_label=Twec +thumbs.title=Nyut cal +thumbs_label=Cal +findbar.title=Nong iye gin acoya +findbar_label=Nong + +# 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=Pot buk {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Cal me pot buk {{page}} + +# Find panel button title and messages +find_input.title=Nong +find_input.placeholder=Nong i dokumen… +find_previous.title=Nong timme pa lok mukato +find_previous_label=Mukato +find_next.title=Nong timme pa lok malubo +find_next_label=Malubo +find_highlight=Wer weng +find_match_case_label=Lok marwate +find_reached_top=Oo iwi gin acoya, omede ki i tere +find_reached_bottom=Oo i agiki me gin acoya, omede ki iwiye +find_not_found=Lok pe ononge + +# Error panel labels +error_more_info=Ngec Mukene +error_less_info=Ngec Manok +error_close=Lor +# 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=Kwena: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Can kikore {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Pwail: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Rek: {{line}} +rendering_error=Bal otime i kare me nyuto pot buk. + +# Predefined zoom values +page_scale_width=Lac me iye pot buk +page_scale_fit=Porre me pot buk +page_scale_auto=Kwot pire kene +page_scale_actual=Dite kikome +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# 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. +unexpected_response_error=Lagam mape kigeno pa lapok tic. + +# 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}} Lok angea manok] +password_label=Ket mung me donyo me yabo pwail me PDF man. +password_invalid=Mung me donyo pe atir. Tim ber i tem doki. +password_ok=OK +password_cancel=Juki + +printing_not_supported=Ciko: Layeny ma pe teno goyo liweng. +printing_not_ready=Ciko: PDF pe ocane weng me agoya. +web_fonts_disabled=Kijuko dit pa coc me kakube woko: pe romo tic ki dit pa coc me PDF ma kiketo i kine. +document_colors_not_allowed=Pe ki yee ki gin acoya me PDF me tic ki rangi gi kengi: Kijuko woko β€œYee pot buk me yero rangi mamegi kengi” ki i layeny. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/af/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/af/viewer.properties new file mode 100755 index 00000000..8cf08808 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/af/viewer.properties @@ -0,0 +1,184 @@ +# 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=Vorige bladsy +previous_label=Vorige +next.title=Volgende bladsy +next_label=Volgende + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Bladsy +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=van {{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}} van {{pagesCount}}) + +zoom_out.title=Zoem uit +zoom_out_label=Zoem uit +zoom_in.title=Zoem in +zoom_in_label=Zoem in +zoom.title=Zoem +presentation_mode.title=Wissel na voorleggingsmodus +presentation_mode_label=Voorleggingsmodus +open_file.title=Open lΓͺer +open_file_label=Open +print.title=Druk +print_label=Druk +download.title=Laai af +download_label=Laai af +bookmark.title=Huidige aansig (kopieer of open in nuwe venster) +bookmark_label=Huidige aansig + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=Teksmerkgereedskap +cursor_hand_tool.title=Aktiveer handjie +cursor_hand_tool_label=Handjie + +# Document properties dialog box +document_properties.title=Dokumenteienskappe… +document_properties_label=Dokumenteienskappe… +document_properties_file_name=LΓͺernaam: +document_properties_file_size=LΓͺergrootte: +# 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}} kG ({{size_b}} grepe) +# 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}} MG ({{size_b}} grepe) +document_properties_title=Titel: +document_properties_author=Outeur: +document_properties_subject=Onderwerp: +document_properties_keywords=Sleutelwoorde: +document_properties_creation_date=Skeppingsdatum: +document_properties_modification_date=Wysigingsdatum: +# 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=Skepper: +document_properties_producer=PDF-vervaardiger: +document_properties_version=PDF-weergawe: +document_properties_page_count=Aantal bladsye: +document_properties_close=Sluit + +print_progress_message=Berei tans dokument voor om te druk… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Kanselleer + +# 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=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 +attachments.title=Wys aanhegsels +attachments_label=Aanhegsels +thumbs.title=Wys duimnaels +thumbs_label=Duimnaels +findbar.title=Soek in dokument +findbar_label=Vind + +# 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=Bladsy {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Duimnael van bladsy {{page}} + +# Find panel button title and messages +find_input.title=Vind +find_input.placeholder=Soek in dokument… +find_previous.title=Vind die vorige voorkoms van die frase +find_previous_label=Vorige +find_next.title=Vind die volgende voorkoms van die frase +find_next_label=Volgende +find_highlight=Verlig almal +find_match_case_label=Kassensitief +find_reached_top=Bokant van dokument is bereik; gaan voort van onder af +find_reached_bottom=Einde van dokument is bereik; gaan voort van bo af +find_not_found=Frase nie gevind nie + +# Error panel labels +error_more_info=Meer inligting +error_less_info=Minder inligting +error_close=Sluit +# 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}} (ID: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Boodskap: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Stapel: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=LΓͺer: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Lyn: {{line}} +rendering_error='n Fout het voorgekom toe die bladsy weergegee is. + +# Predefined zoom values +page_scale_width=Bladsywydte +page_scale_fit=Pas bladsy +page_scale_auto=Outomatiese zoem +page_scale_actual=Werklike grootte +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# 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. +unexpected_response_error=Onverwagse antwoord van bediener. + +# 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}}-annotasie] +password_label=Gee die wagwoord om diΓ© PDF-lΓͺer mee te open. +password_invalid=Ongeldige wagwoord. Probeer gerus weer. +password_ok=OK +password_cancel=Kanselleer + +printing_not_supported=Waarskuwing: DiΓ© blaaier ondersteun nie drukwerk ten volle nie. +printing_not_ready=Waarskuwing: Die PDF is nog nie volledig gelaai vir drukwerk nie. +web_fonts_disabled=Webfonte is gedeaktiveer: kan nie PDF-fonte wat ingebed is, gebruik nie. +document_colors_not_allowed=PDF-dokumente word nie toegelaat om hul eie kleure te gebruik nie: β€œLaat bladsye toe om hul eie kleure te kies” is gedeaktiveer in die blaaier. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ak/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ak/viewer.properties new file mode 100755 index 00000000..25dc62e3 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ak/viewer.properties @@ -0,0 +1,130 @@ +# 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=Krataafa baako a etwa mu +previous_label=Ekyiri-baako +next.title=Krataafa a edi so baako +next_label=Dea-Ι›-di-so-baako + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +zoom_out.title=Zuum pue +zoom_out_label=Zuum ba abΙ”nten +zoom_in.title=Zuum kΙ” mu +zoom_in_label=Zuum kΙ” mu +zoom.title=Zuum +presentation_mode.title=Sesa kΙ” YΙ›kyerΙ› Tebea mu +presentation_mode_label=YΙ›kyerΙ› Tebea +open_file.title=Bue Fael +open_file_label=Bue +print.title=Prente +print_label=Prente +download.title=Twe +download_label=Twe +bookmark.title=Seisei nhwΙ› (fa anaaso bue wΙ” tokuro foforo mu) +bookmark_label=Seisei nhwΙ› + +# Secondary toolbar and context menu + + +# Document properties dialog box +# LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" +# will be replaced by the PDF file size in kilobytes, respectively in 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_title=Ti asΙ›m: +# LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" +# will be replaced by the creation/modification date, and time, of the PDF file. + +# 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) +toggle_sidebar.title=SΙ” anaaso dum saedbaa +toggle_sidebar_label=SΙ” anaaso dum saedbaa +document_outline_label=DΙ”komΙ›nt bΙ”bea +thumbs.title=KyerΙ› mfoniwaa +thumbs_label=Mfoniwaa +findbar.title=Hu wΙ” dΙ”komΙ›nt no mu + +# 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=Krataafa {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Krataafa ne mfoniwaa {{page}} + +# Find panel button title and messages +find_previous.title=San hu fres wΙ” ekyiri baako +find_previous_label=Ekyiri baako +find_next.title=San hu fres no wΙ” enim baako +find_next_label=Ndiso +find_highlight=HyΙ› bibiara nso +find_match_case_label=Fa susu kaase +find_reached_top=Edu krataafa ne soro, atoa so efiri ase +find_reached_bottom=Edu krataafa n'ewiei, atoa so efiri soro +find_not_found=Ennhu fres + +# Error panel labels +error_more_info=InfΙ”mehyΙ›n bio a wΙ”ka ho +error_less_info=Te infΙ”mehyΙ›n bio a wΙ”ka ho so +# 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{{vΙ›Ι›hyen}} (nsi: {{si}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Nkrato: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Staake: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Fael: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Laen: {{line}} +rendering_error=Mfomso bae wΙ” bere a wΙ” rekyerΙ› krataafa no. + +# Predefined zoom values +page_scale_width=Krataafa tΙ›trΙ›tΙ› +page_scale_fit=Krataafa ehimtwa +page_scale_auto=Zuum otomatik +page_scale_actual=KΙ›seyΙ› ankasa +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. + +# Loading indicator messages +loading_error_indicator=Mfomso +loading_error=Mfomso bae wΙ” bere a wΙ”reloode PDF no. +invalid_file_error=PDF fael no nndi mu anaaso ho atΙ” kyima. +missing_file_error=PDF fael no ayera. + +# 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}} TΙ›kst-nyiano] +password_ok=OK + +printing_not_supported=KΙ”kΙ”bΙ”: Brawsa yi nnhyΙ› daa mma prent ho kwan. +printing_not_ready=KΙ”kΙ”bΙ”: WΙ”nntwee PDF fael no nyinara mmbaee ama wo Ι› tumi aprente. +web_fonts_disabled=Ζ†edum wΙ›b-mfΙ”nt: nntumi mmfa PDF mfΙ”nt a wΙ”hyΙ› mu nndi dwuma. +document_colors_not_allowed=WΙ”mma ho kwan sΙ› PDF adΙ”komΙ›nt de wΙ”n ara wΙ”n ahosu bΙ›di dwuma: wΙ” adum 'Ma ho kwan ma nkrataafa mpaw wΙ”n ara wΙ”n ahosu' wΙ” brawsa yi mu. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/an/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/an/viewer.properties new file mode 100755 index 00000000..e42a22ae --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/an/viewer.properties @@ -0,0 +1,180 @@ +# 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=Pachina anterior +previous_label=Anterior +next.title=Pachina siguient +next_label=Siguient + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Pachina +# 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=Achiquir +zoom_out_label=Achiquir +zoom_in.title=Agrandir +zoom_in_label=Agrandir +zoom.title=Grandaria +presentation_mode.title=Cambear t'o modo de presentaciΓ³n +presentation_mode_label=Modo de presentaciΓ³n +open_file.title=Ubrir o fichero +open_file_label=Ubrir +print.title=Imprentar +print_label=Imprentar +download.title=Descargar +download_label=Descargar +bookmark.title=Vista actual (copiar u ubrir en una nueva finestra) +bookmark_label=Anvista 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 + + +# Document properties dialog box +document_properties.title=Propiedatz d'o documento... +document_properties_label=Propiedatz d'o documento... +document_properties_file_name=Nombre de fichero: +document_properties_file_size=Grandaria d'o fichero: +# 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=Titol: +document_properties_author=Autor: +document_properties_subject=Afer: +document_properties_keywords=Parolas clau: +document_properties_creation_date=Calendata de creyaciΓ³n: +document_properties_modification_date=Calendata 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=Creyador: +document_properties_producer=Creyador de PDF: +document_properties_version=VersiΓ³n de PDF: +document_properties_page_count=Numero de pachinas: +document_properties_close=Zarrar + +print_progress_message=Se ye preparando la documentaciΓ³n pa imprentar… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +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=Amostrar u amagar a barra lateral +toggle_sidebar_notification.title=Cambiar barra lateral (lo documento contiene esquema/adchuntos) +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 +thumbs.title=Amostrar as miniaturas +thumbs_label=Miniaturas +findbar.title=Trobar en o documento +findbar_label=Trobar + +# 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=Pachina {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Miniatura d'a pachina {{page}} + +# Find panel button title and messages +find_input.title=Trobar +find_input.placeholder=Trobar en o documento… +find_previous.title=Trobar l'anterior coincidencia d'a frase +find_previous_label=Anterior +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_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 +find_not_found=No s'ha trobau a frase + +# Error panel labels +error_more_info=Mas 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}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Mensache: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Pila: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Fichero: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Linia: {{line}} +rendering_error=Ha ocurriu una error en renderizar a pachina. + +# Predefined zoom values +page_scale_width=Amplaria d'a pachina +page_scale_fit=Achuste d'a pachina +page_scale_auto=Grandaria automatica +page_scale_actual=Grandaria 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=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 (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=Introduzca a clau ta ubrir iste fichero PDF. +password_invalid=Clau invalida. Torna a intentar-lo. +password_ok=Acceptar +password_cancel=Cancelar + +printing_not_supported=Pare cuenta: Iste navegador no maneya totalment as impresions. +printing_not_ready=Aviso: Encara no se ha cargau completament o PDF ta imprentar-lo. +web_fonts_disabled=As fuents web son desactivadas: no se puet incrustar fichers PDF. +document_colors_not_allowed=Los documentos PDF no pueden fer servir las suyas propias colors: 'Permitir que as pachinas triguen as suyas propias colors' ye desactivau en o navegador. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ar/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ar/viewer.properties new file mode 100755 index 00000000..93dbc9b7 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ar/viewer.properties @@ -0,0 +1,184 @@ +# 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=Ψ§Ψ°Ω‡Ψ¨ Ψ₯Ω„Ω‰ الءفحة Ψ§Ω„Ψ£ΩˆΩ„Ω‰ +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_label=Ψ£Ψ―Ψ§Ψ© Ψ§ΨΨͺيار Ψ§Ω„Ω†Ψ΅ +cursor_hand_tool.title=فعّل Ψ£Ψ―Ψ§Ψ© Ψ§Ω„ΩŠΨ― +cursor_hand_tool_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_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_notification.title=Ψ¨Ψ―Ω‘Ω„ ΨΈΩ‡ΩˆΨ± Ψ§Ω„Ψ΄Ψ±ΩŠΨ· Ψ§Ω„Ψ¬Ψ§Ω†Ψ¨ΩŠ (يحΨͺوي Ψ§Ω„Ω…Ψ³ΨͺΩ†Ψ― ΨΉΩ„Ω‰ Ω…ΨΨ·Ψ· أو مرفقاΨͺ) +toggle_sidebar_label=Ψ¨Ψ―Ω‘Ω„ ΨΈΩ‡ΩˆΨ± Ψ§Ω„Ψ΄Ψ±ΩŠΨ· Ψ§Ω„Ψ¬Ψ§Ω†Ψ¨ΩŠ +document_outline.title=Ψ§ΨΉΨ±ΨΆ فهرس Ψ§Ω„Ω…Ψ³ΨͺΩ†Ψ― (Ω†Ω‚Ψ± Ω…Ψ²Ψ―ΩˆΨ¬ Ω„ΨͺΩ…Ψ―ΩŠΨ― أو ΨͺΩ‚Ω„ΩŠΨ΅ ΩƒΩ„ Ψ§Ω„ΨΉΩ†Ψ§Ψ΅Ψ±) +document_outline_label=Ω…ΨΨ·Ψ· Ψ§Ω„Ω…Ψ³ΨͺΩ†Ψ― +attachments.title=Ψ§ΨΉΨ±ΨΆ المرفقاΨͺ +attachments_label=المُرفقاΨͺ +thumbs.title=Ψ§ΨΉΨ±ΨΆ مُءغراΨͺ +thumbs_label=مُءغّراΨͺ +findbar.title=Ψ§Ψ¨Ψ­Ψ« في Ψ§Ω„Ω…Ψ³ΨͺΩ†Ψ― +findbar_label=Ψ§Ψ¨Ψ­Ψ« + +# 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_reached_top=ΨͺΨ§Ψ¨ΨΉΨͺ Ω…Ω† الأسفل Ψ¨ΨΉΨ―Ω…Ψ§ ΩˆΨ΅Ω„Ψͺ Ψ₯Ω„Ω‰ بداية Ψ§Ω„Ω…Ψ³ΨͺΩ†Ψ― +find_reached_bottom=ΨͺΨ§Ψ¨ΨΉΨͺ Ω…Ω† Ψ§Ω„Ψ£ΨΉΩ„Ω‰ Ψ¨ΨΉΨ―Ω…Ψ§ ΩˆΨ΅Ω„Ψͺ Ψ₯Ω„Ω‰ Ω†Ω‡Ψ§ΩŠΨ© Ψ§Ω„Ω…Ψ³ΨͺΩ†Ψ― +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 Ω†{{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_error_indicator=ΨΉΨ·Ω„ +loading_error=Ψ­Ψ―Ψ« ΨΉΨ·Ω„ Ψ£Ψ«Ω†Ψ§Ψ‘ ΨͺΨ­Ω…ΩŠΩ„ ملف PDF. +invalid_file_error=ملف PDF Ψͺالف أو غير ءحيح. +missing_file_error=ملف PDF غير Ω…ΩˆΨ¬ΩˆΨ―. +unexpected_response_error=Ψ§Ψ³ΨͺΨ¬Ψ§Ψ¨Ψ© ΨΨ§Ψ―ΩˆΩ… غير Ω…ΨͺΩˆΩ‚ΨΉΨ©. + +# 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=Ψ£Ψ―ΨΩ„ Ω„ΩƒΩ„Ω…Ψ© Ψ§Ω„Ψ³Ψ± لفΨͺΨ­ Ω‡Ψ°Ψ§ الملف. +password_invalid=ΩƒΩ„Ω…Ψ© Ψ³Ψ± ΨΨ·Ψ£. Ω…Ω† فآلك Ψ£ΨΉΨ― Ψ§Ω„Ω…Ψ­Ψ§ΩˆΩ„Ψ©. +password_ok=Ψ­Ψ³Ω†Ψ§ +password_cancel=ألغِ + +printing_not_supported=Ψͺحذير: Ω„Ψ§ ΩŠΨ―ΨΉΩ… Ω‡Ψ°Ψ§ Ψ§Ω„Ω…Ψͺءفح Ψ§Ω„Ψ·Ψ¨Ψ§ΨΉΨ© Ψ¨Ψ΄ΩƒΩ„ ΩƒΨ§Ω…Ω„. +printing_not_ready=Ψͺحذير: ملف PDF Ω„Ω… ΩŠΩΨ­Ω…Ω‘Ω„ ΩƒΨ§Ω…Ω„Ω‹Ψ§ Ω„Ω„Ψ·Ψ¨Ψ§ΨΉΨ©. +web_fonts_disabled=Ψطوط Ψ§Ω„ΩˆΨ¨ مُعطّلة: ΨͺΨΉΨ°Ω‘Ψ± Ψ§Ψ³ΨͺΨΨ―Ψ§Ω… Ψطوط PDF المُآمّنة. +document_colors_not_allowed=Ω„ΩŠΨ³ Ω…Ψ³Ω…ΩˆΨ­Ω‹Ψ§ لملفاΨͺ PDF Ψ¨Ψ§Ψ³ΨͺΨΨ―Ψ§Ω… Ψ£Ω„ΩˆΨ§Ω†Ω‡Ψ§ Ψ§Ω„ΨΨ§Ψ΅Ψ©: Ψيار ”اسمح للءفحاΨͺ Ψ¨Ψ§ΨΨͺيار Ψ£Ω„ΩˆΨ§Ω†Ω‡Ψ§ Ψ§Ω„ΨΨ§Ψ΅Ψ©β€œ Ω„ΩŠΨ³ مُفعّلًا في Ψ§Ω„Ω…Ψͺءفح. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/as/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/as/viewer.properties new file mode 100755 index 00000000..ea3ecc79 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/as/viewer.properties @@ -0,0 +1,167 @@ +# 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. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +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=ΰ¦ͺ্ৰΰ¦₯ΰ¦ ΰ¦ͺৃষ্ঠাঀ যাওক +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=ΰ¦˜ΰ§œΰ§€ΰ§° ΰ¦“ΰ¦²ΰ§‹ΰ¦Ÿΰ¦Ύ দিঢঀ ΰ¦˜ΰ§ΰ§°ΰ¦Ύΰ¦“ΰ¦• + + +# 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}} 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=ঢীৰ্ষক: +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_close=বন্ধ কৰক + +# 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) +toggle_sidebar.title=কাষবাৰ ΰ¦Ÿΰ¦—ΰ¦² কৰক +toggle_sidebar_label=কাষবাৰ ΰ¦Ÿΰ¦—ΰ¦² কৰক +document_outline_label=ΰ¦¦ΰ¦Έΰ§ΰ¦€ΰ¦Ύΰ¦¬ΰ§‡ΰ¦œ ΰ¦†ΰ¦‰ΰ¦Ÿΰ¦²ΰ¦Ύΰ¦‡ΰ¦¨ +attachments.title=এটাচΰ¦ΰ§‡ΰ¦¨ΰ§ΰ¦Ÿΰ¦Έΰ¦ΰ§‚ΰ¦Ή দেখুৱাওক +attachments_label=এটাচΰ¦ΰ§‡ΰ¦¨ΰ§ΰ¦Ÿΰ¦Έΰ¦ΰ§‚ΰ¦Ή +thumbs.title=ΰ¦₯ΰ¦Ύΰ¦ΰ§ΰ¦¬ΰ¦¨ΰ§‡ΰ¦‡ΰ¦²ΰ¦Έΰ¦ΰ§‚ΰ¦Ή দেখুৱাওক +thumbs_label=ΰ¦₯ΰ¦Ύΰ¦ΰ§ΰ¦¬ΰ¦¨ΰ§‡ΰ¦‡ΰ¦²ΰ¦Έΰ¦ΰ§‚ΰ¦Ή +findbar.title=ΰ¦¦ΰ¦Έΰ§ΰ¦€ΰ¦Ύΰ¦¬ΰ§‡ΰ¦œΰ¦€ সন্ধান কৰক + +# 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_previous_label=ΰ¦ͺূৰ্বৱৰ্ঀী +find_next.title=বাক্যাংঢৰ ΰ¦ͺৰৱৰ্ঀী উΰ¦ͺস্ΰ¦₯িঀি সন্ধান কৰক +find_next_label=ΰ¦ͺৰৱৰ্ঀী +find_highlight=সকলো ΰ¦‰ΰ¦œΰ§ΰ¦œΰ§ΰ¦¬ΰ¦² কৰক +find_match_case_label=ফলা ΰ¦ΰ¦Ώΰ¦²ΰ¦Ύΰ¦“ক +find_reached_top=ঀলৰ ΰ¦ͺΰ§°ΰ¦Ύ আৰΰ¦ΰ§ΰ¦­ কৰি, ΰ¦¦ΰ¦Έΰ§ΰ¦€ΰ¦Ύΰ¦¬ΰ§‡ΰ¦œΰ§° ওΰ¦ͺৰলৈ ΰ¦…ΰ¦Ήΰ¦Ύ ΰ¦Ήΰ§ˆΰ¦›ΰ§‡ +find_reached_bottom=ওΰ¦ͺΰ§°ΰ§° ΰ¦ͺΰ§°ΰ¦Ύ আৰΰ¦ΰ§ΰ¦­ কৰি, ΰ¦¦ΰ¦Έΰ§ΰ¦€ΰ¦Ύΰ¦¬ΰ§‡ΰ¦œΰ§° ঀললৈ ΰ¦…ΰ¦Ήΰ¦Ύ ΰ¦Ήΰ§ˆΰ¦›ΰ§‡ +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. + +# Loading indicator messages +loading_error_indicator=ঀ্ৰুটি +loading_error=PDF ল'঑ কৰোঀে এটা ঀ্ৰুটি দেখা দিলেΰ₯€ +invalid_file_error=ΰ¦…ΰ¦¬ΰ§ˆΰ¦§ ΰ¦…ΰ¦₯বা ক্ষঀিগ্ৰস্ΰ¦₯ PDF fileΰ₯€ +missing_file_error=সন্ধানহিন PDF ফাইলΰ₯€ +unexpected_response_error=ΰ¦…ΰ¦ͺ্ৰঀ্যাঢিঀ চাৰ্ভাৰ ΰ¦ͺΰ§ΰ§°ΰ¦€ΰ¦Ώΰ¦•ΰ§ΰ§°ΰ¦Ώΰ§Ÿΰ¦Ύΰ₯€ + +# 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 ফন্টসΰ¦ΰ§‚ΰ¦Ή ব্যৱহাৰ কৰিবলে অক্ষΰ¦ΰ₯€ +document_colors_not_allowed=PDF ΰ¦¦ΰ¦Έΰ§ΰ¦€ΰ¦Ύΰ¦¬ΰ§‡ΰ¦œΰ¦Έΰ¦ΰ§‚ΰ¦Ήΰ§° সিহঀৰ নিজস্ব ৰঙ ব্যৱহাৰ কৰাৰ অনুΰ¦ΰ¦€ΰ¦Ώ নাই: ব্ৰাউছাৰঀ 'ΰ¦ͺৃষ্ঠাসΰ¦ΰ§‚হক সিহঀৰ নিজস্ব ৰঙ নিৰ্বাচন কৰাৰ অনুΰ¦ΰ¦€ΰ¦Ώ ΰ¦¦ΰ¦Ώΰ§Ÿΰ¦•' ΰ¦…ΰ¦Έΰ¦Ύΰ¦ΰ§°ΰ§ΰ¦₯বান কৰা আছেΰ₯€ diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ast/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ast/viewer.properties new file mode 100755 index 00000000..e57fc4a0 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ast/viewer.properties @@ -0,0 +1,177 @@ +# 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Γ‘xina anterior +previous_label=Anterior +next.title=PΓ‘xina siguiente +next_label=Siguiente + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=PΓ‘xina +# 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=Reducir +zoom_out_label=Reducir +zoom_in.title=Aumentar +zoom_in_label=Aumentar +zoom.title=TamaΓ±u +presentation_mode.title= +presentation_mode_label= +open_file.title=Abrir ficheru +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) +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= +page_rotate_cw_label=Xirar en sen horariu +page_rotate_ccw.title=Xirar en sen antihorariu +page_rotate_ccw.label= +page_rotate_ccw_label=Xirar en sen antihorariu + + +# 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: +# 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=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_page_count=NΓΊmberu de pΓ‘xines: +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}}% +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 +attachments_label=Axuntos +thumbs.title=Amosar miniatures +thumbs_label=Miniatures +findbar.title=Guetar nel documentu +findbar_label=Guetar + +# 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_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_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_not_found=Frase non atopada + +# 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}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Mensaxe: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Pila: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +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 +# 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. + +# 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_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. +document_colors_not_allowed=Los documentos PDF nun tienen permisu pa usar les sos colores: Β«Permitir que les pΓ‘xines escueyan les sos coloresΒ» ta desactivao nel restolador. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/az/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/az/viewer.properties new file mode 100755 index 00000000..be878d39 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/az/viewer.properties @@ -0,0 +1,184 @@ +# 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=ƏvvΙ™lki sΙ™hifΙ™ +previous_label=ƏvvΙ™lkini tap +next.title=NΓΆvbΙ™ti sΙ™hifΙ™ +next_label=Δ°rΙ™li + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=SΙ™hifΙ™ +# 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=Uzaqlaş +zoom_out_label=Uzaqlaş +zoom_in.title=YaxΔ±nlaş +zoom_in_label=YaxΔ±nlaş +zoom.title=YaxΔ±nlaşdΔ±rma +presentation_mode.title=TΙ™qdimat RejiminΙ™ KeΓ§ +presentation_mode_label=TΙ™qdimat Rejimi +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Ι™ +bookmark.title=HazΔ±rkΔ± gΓΆrΓΌnüş (kΓΆΓ§ΓΌr vΙ™ ya yeni pΙ™ncΙ™rΙ™dΙ™ aΓ§) +bookmark_label=HazΔ±rki gΓΆrΓΌnüş + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=YazΔ± seΓ§mΙ™ alΙ™ti +cursor_hand_tool.title=Əl alΙ™tini aktivlΙ™ΕŸdir +cursor_hand_tool_label=Əl alΙ™ti + +# Document properties dialog box +document_properties.title=SΙ™nΙ™d xΓΌsusiyyΙ™tlΙ™ri… +document_properties_label=SΙ™nΙ™d xΓΌsusiyyΙ™tlΙ™ri… +document_properties_file_name=Fayl adΔ±: +document_properties_file_size=Fayl ΓΆlΓ§ΓΌsΓΌ: +# 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}} bayt) +# 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}} bayt) +document_properties_title=BaşlΔ±k: +document_properties_author=MΓΌΙ™llif: +document_properties_subject=MΓΆvzu: +document_properties_keywords=AΓ§ar sΓΆzlΙ™r: +document_properties_creation_date=YaradΔ±lış Tarixi : +document_properties_modification_date=DΙ™yişdirilmΙ™ Tarixi : +# 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=Yaradan: +document_properties_producer=PDF yaradΔ±cΔ±sΔ±: +document_properties_version=PDF versiyasΔ±: +document_properties_page_count=SΙ™hifΙ™ sayΔ±: +document_properties_close=Qapat + +print_progress_message=SΙ™nΙ™d Γ§ap ΓΌΓ§ΓΌn hazΔ±rlanΔ±r… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=LΙ™ΔŸv et + +# 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=Yan Paneli AΓ§/Bağla +toggle_sidebar_notification.title=Yan paneli Γ§evir (sΙ™nΙ™ddΙ™ icmal/bağlama var) +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 +thumbs.title=KiΓ§ik ΕŸΙ™killΙ™ri gΓΆstΙ™r +thumbs_label=KiΓ§ik ΕŸΙ™killΙ™r +findbar.title=SΙ™nΙ™ddΙ™ Tap +findbar_label=Tap + +# 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=SΙ™hifΙ™{{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas={{page}} sΙ™hifΙ™sinin kiΓ§ik vΙ™ziyyΙ™ti + +# Find panel button title and messages +find_input.title=Tap +find_input.placeholder=SΙ™nΙ™ddΙ™ tap… +find_previous.title=Bir ΓΆncΙ™ki uyğun gΙ™lΙ™n sΓΆzΓΌ tapΔ±r +find_previous_label=Geri +find_next.title=Bir sonrakΔ± uyğun gΙ™lΙ™n sΓΆzΓΌ tapΔ±r +find_next_label=Δ°rΙ™li +find_highlight=İşarΙ™lΙ™ +find_match_case_label=BΓΆyΓΌk/kiΓ§ik hΙ™rfΙ™ hΙ™ssaslΔ±q +find_reached_top=SΙ™nΙ™din yuxarΔ±sΔ±na Γ§atdΔ±, aşağıdan davam edir +find_reached_bottom=SΙ™nΙ™din sonuna Γ§atdΔ±, yuxarΔ±dan davam edir +find_not_found=Uyğunlaşma tapΔ±lmadΔ± + +# Error panel labels +error_more_info=Daha Γ§ox mΙ™lumati +error_less_info=Daha az mΙ™lumat +error_close=Qapat +# 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}} (yığma: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Δ°smarΔ±c: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Stek: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Fayl: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=SΙ™tir: {{line}} +rendering_error=SΙ™hifΙ™ gΓΆstΙ™rilΙ™rkΙ™n sΙ™hv yarandΔ±. + +# Predefined zoom values +page_scale_width=SΙ™hifΙ™ genişliyi +page_scale_fit=SΙ™hifΙ™ni sığdΔ±r +page_scale_auto=Avtomatik yaxΔ±nlaşdΔ±r +page_scale_actual=HazΔ±rki HΙ™cm +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# 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. +unexpected_response_error=GΓΆzlΙ™nilmΙ™z server cavabΔ±. + +# 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}} AnnotasiyasΔ±] +password_label=Bu PDF faylΔ± aΓ§maq ΓΌΓ§ΓΌn şifrΙ™ni daxil edin. +password_invalid=ŞifrΙ™ yanlışdΔ±r. Bir daha sΔ±nayΔ±n. +password_ok=Tamam +password_cancel=LΙ™ΔŸv et + +printing_not_supported=XΙ™bΙ™rdarlΔ±q: Γ‡ap bu sΙ™yyah tΙ™rΙ™findΙ™n tam olaraq dΙ™stΙ™klΙ™nmir. +printing_not_ready=XΙ™bΙ™rdarlΔ±q: PDF Γ§ap ΓΌΓ§ΓΌn tam yΓΌklΙ™nmΙ™yib. +web_fonts_disabled=Web ŞriftlΙ™r sΓΆndΓΌrΓΌlΓΌb: yerlΙ™ΕŸdirilmiş PDF şriftlΙ™rini istifadΙ™ etmΙ™k mΓΌmkΓΌn deyil. +document_colors_not_allowed=PDF sΙ™nΙ™dlΙ™rΙ™ ΓΆz rΙ™nglΙ™rini işlΙ™tmΙ™yΙ™ icazΙ™ verilmir: β€œSΙ™hifΙ™lΙ™rΙ™ ΓΆz rΙ™nglΙ™rini istifadΙ™ etmΙ™yΙ™ icazΙ™ ver”mΙ™ sΙ™yyahda sΓΆndΓΌrΓΌlΓΌb. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/be/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/be/viewer.properties new file mode 100755 index 00000000..f0e3fa27 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/be/viewer.properties @@ -0,0 +1,184 @@ +# 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=ΠŸΠ΅Ρ€Π°ΠΉΡΡ†Ρ– Π½Π° ΠΏΠ΅Ρ€ΡˆΡƒΡŽ старонку +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_label=ΠŸΡ€Ρ‹Π»Π°Π΄Π° Π²Ρ‹Π±Π°Ρ€Ρƒ тэксту +cursor_hand_tool.title=Π£ΠΊΠ»ΡŽΡ‡Ρ‹Ρ†ΡŒ Ρ€ΡƒΡ‡Π½ΡƒΡŽ ΠΏΡ€Ρ‹Π»Π°Π΄Ρƒ +cursor_hand_tool_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_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_notification.title=ΠŸΠ°ΠΊΠ°Π·Π°Ρ†ΡŒ/ΡΡ…Π°Π²Π°Ρ†ΡŒ Π±Π°ΠΊΠ°Π²ΡƒΡŽ панэль (Π΄Π°ΠΊΡƒΠΌΠ΅Π½Ρ‚ ΠΌΠ°Π΅ змСст/ΡƒΠΊΠ»Π°Π΄Π°Π½Π½Ρ–) +toggle_sidebar_label=ΠŸΠ°ΠΊΠ°Π·Π°Ρ†ΡŒ/ΡΡ…Π°Π²Π°Ρ†ΡŒ Π±Π°ΠΊΠ°Π²ΡƒΡŽ панэль +document_outline.title=ΠŸΠ°ΠΊΠ°Π·Π°Ρ†ΡŒ структуру Π΄Π°ΠΊΡƒΠΌΠ΅Π½Ρ‚Π° (двайная пстрычка, ΠΊΠ°Π± Ρ€Π°Π·Π³Π°Ρ€Π½ΡƒΡ†ΡŒ /Π·Π³Π°Ρ€Π½ΡƒΡ†ΡŒ усС элСмСнты) +document_outline_label=Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π° Π΄Π°ΠΊΡƒΠΌΠ΅Π½Ρ‚Π° +attachments.title=ΠŸΠ°ΠΊΠ°Π·Π°Ρ†ΡŒ далучэнні +attachments_label=Далучэнні +thumbs.title=Паказ ΠΌΡ–Π½Ρ–ΡΡ†ΡŽΡ€ +thumbs_label=ΠœΡ–Π½Ρ–ΡΡ†ΡŽΡ€Ρ‹ +findbar.title=ΠŸΠΎΡˆΡƒΠΊ Ρƒ Π΄Π°ΠΊΡƒΠΌΠ΅Π½Ρ†Π΅ +findbar_label=Знайсці + +# 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_reached_top=Дасягнуты ΠΏΠ°Ρ‡Π°Ρ‚Π°ΠΊ Π΄Π°ΠΊΡƒΠΌΠ΅Π½Ρ‚Π°, працяг Π· ΠΊΠ°Π½Ρ†Π° +find_reached_bottom=Дасягнуты ΠΊΠ°Π½Π΅Ρ† Π΄Π°ΠΊΡƒΠΌΠ΅Π½Ρ‚Π°, працяг Π· ΠΏΠ°Ρ‡Π°Ρ‚ΠΊΡƒ +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 Π²{{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_error_indicator=ΠŸΠ°ΠΌΡ‹Π»ΠΊΠ° +loading_error=Здарылася ΠΏΠ°ΠΌΡ‹Π»ΠΊΠ° падчас Π·Π°Π³Ρ€ΡƒΠ·ΠΊΡ– PDF. +invalid_file_error=ΠΡΡΠΏΡ€Π°ΡžΠ½Ρ‹ Π°Π±ΠΎ ΠΏΠ°ΡˆΠΊΠΎΠ΄ΠΆΠ°Π½Ρ‹ Ρ„Π°ΠΉΠ» PDF. +missing_file_error=Адсутны Ρ„Π°ΠΉΠ» PDF. +unexpected_response_error=НСчаканы Π°Π΄ΠΊΠ°Π· сСрвСра. + +# 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=УвядзіцС ΠΏΠ°Ρ€ΠΎΠ»ΡŒ, ΠΊΠ°Π± Π°Π΄ΠΊΡ€Ρ‹Ρ†ΡŒ гэты Ρ„Π°ΠΉΠ» PDF. +password_invalid=НядзСйсны ΠΏΠ°Ρ€ΠΎΠ»ΡŒ. ΠŸΠ°ΡΠΏΡ€Π°Π±ΡƒΠΉΡ†Π΅ зноў. +password_ok=Π”ΠΎΠ±Ρ€Π° +password_cancel=Π‘ΠΊΠ°ΡΠ°Π²Π°Ρ†ΡŒ + +printing_not_supported=ΠŸΠ°ΠΏΡΡ€ΡΠ΄ΠΆΠ°Π½Π½Π΅: Π΄Ρ€ΡƒΠΊ Π½Π΅ ΠΏΠ°Π΄Ρ‚Ρ€Ρ‹ΠΌΠ»Ρ–Π²Π°Π΅Ρ†Ρ†Π° Ρ†Π°Π»ΠΊΠ°ΠΌ гэтым Π±Ρ€Π°ΡžΠ·Π΅Ρ€Π°ΠΌ. +printing_not_ready=Π£Π²Π°Π³Π°: PDF Π½Π΅ сцягнуты Ρ†Π°Π»ΠΊΠ°ΠΌ для друкавання. +web_fonts_disabled=Π¨Ρ€Ρ‹Ρ„Ρ‚Ρ‹ Π‘Π΅Ρ†Ρ–Π²Π° Π·Π°Π±Π°Ρ€ΠΎΠ½Π΅Π½Ρ‹: Π½Π΅ΠΌΠ°Π³Ρ‡Ρ‹ΠΌΠ° ΡžΠΆΡ‹Π²Π°Ρ†ΡŒ укладзСныя ΡˆΡ€Ρ‹Ρ„Ρ‚Ρ‹ PDF. +document_colors_not_allowed=PDF-Π΄Π°ΠΊΡƒΠΌΠ΅Π½Ρ‚Π°ΠΌ Π½Π΅ Π΄Π°Π·Π²ΠΎΠ»Π΅Π½Π° Π²Ρ‹ΠΊΠ°Ρ€Ρ‹ΡΡ‚ΠΎΡžΠ²Π°Ρ†ΡŒ сваС ΠΊΠΎΠ»Π΅Ρ€Ρ‹: Ρƒ Π±Ρ€Π°ΡžΠ·Π΅Ρ€Ρ‹ Π°Π΄ΠΊΠ»ΡŽΡ‡Π°Π½Ρ‹ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ "Π”Π°Π·Π²ΠΎΠ»Ρ–Ρ†ΡŒ вэб-сайтам Π²Ρ‹ΠΊΠ°Ρ€Ρ‹ΡΡ‚ΠΎΡžΠ²Π°Ρ†ΡŒ сваС ΠΊΠΎΠ»Π΅Ρ€Ρ‹". diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/bg/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/bg/viewer.properties new file mode 100755 index 00000000..a6928a8e --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/bg/viewer.properties @@ -0,0 +1,184 @@ +# 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=Към ΠΏΡŠΡ€Π²Π°Ρ‚Π° страница +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_label=Π˜Π½ΡΡ‚Ρ€ΡƒΠΌΠ΅Π½Ρ‚ Π·Π° ΠΈΠ·Π±ΠΎΡ€ Π½Π° тСкст +cursor_hand_tool.title=Π’ΠΊΠ»ΡŽΡ‡Π²Π°Π½Π΅ Π½Π° инструмСнта Ρ€ΡŠΠΊΠ° +cursor_hand_tool_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_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_notification.title=ΠŸΡ€Π΅Π²ΠΊΠ»ΡŽΡ‡Π²Π°Π½Π΅ Π½Π° страничната Π»Π΅Π½Ρ‚Π° (Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΈ със структура/ΠΏΡ€ΠΈΠΊΠ°Ρ‡Π΅Π½ΠΈ Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅) +toggle_sidebar_label=ΠŸΡ€Π΅Π²ΠΊΠ»ΡŽΡ‡Π²Π°Π½Π΅ Π½Π° страничната Π»Π΅Π½Ρ‚Π° +document_outline.title=ПоказванС Π½Π° структурата Π½Π° Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π° (Π΄Π²ΡƒΠΊΡ€Π°Ρ‚Π½ΠΎ Ρ‰Ρ€Π°ΠΊΠ²Π°Π½Π΅ Π·Π° свиванС/Ρ€Π°Π·Π³ΡŠΠ²Π°Π½Π΅ Π½Π° всичко) +document_outline_label=Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π° Π½Π° Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π° +attachments.title=ПоказванС Π½Π° ΠΏΡ€ΠΈΡ‚ΡƒΡ€ΠΊΠΈΡ‚Π΅ +attachments_label=ΠŸΡ€ΠΈΡ‚ΡƒΡ€ΠΊΠΈ +thumbs.title=ПоказванС Π½Π° ΠΌΠΈΠ½ΠΈΠ°Ρ‚ΡŽΡ€ΠΈΡ‚Π΅ +thumbs_label=ΠœΠΈΠ½ΠΈΠ°Ρ‚ΡŽΡ€ΠΈ +findbar.title=НамиранС Π² Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π° +findbar_label=Π’ΡŠΡ€ΡΠ΅Π½Π΅ + +# 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_reached_top=Достигнато Π΅ Π½Π°Ρ‡Π°Π»ΠΎΡ‚ΠΎ Π½Π° Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°, ΠΏΡ€ΠΎΠ΄ΡŠΠ»ΠΆΠ°Π²Π°Π½Π΅ ΠΎΡ‚ края +find_reached_bottom=Достигнат Π΅ краят Π½Π° Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°, ΠΏΡ€ΠΎΠ΄ΡŠΠ»ΠΆΠ°Π²Π°Π½Π΅ ΠΎΡ‚ Π½Π°Ρ‡Π°Π»ΠΎΡ‚ΠΎ +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 вСрсия {{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_indicator=Π“Ρ€Π΅ΡˆΠΊΠ° +loading_error=ΠŸΠΎΠ»ΡƒΡ‡ΠΈ сС Π³Ρ€Π΅ΡˆΠΊΠ° ΠΏΡ€ΠΈ Π·Π°Ρ€Π΅ΠΆΠ΄Π°Π½Π΅ Π½Π° PDF-Π°. +invalid_file_error=НСвалидСн ΠΈΠ»ΠΈ ΠΏΠΎΠ²Ρ€Π΅Π΄Π΅Π½ PDF Ρ„Π°ΠΉΠ». +missing_file_error=Липсващ PDF Ρ„Π°ΠΉΠ». +unexpected_response_error=НСочакван ΠΎΡ‚Π³ΠΎΠ²ΠΎΡ€ ΠΎΡ‚ ΡΡŠΡ€Π²ΡŠΡ€Π°. + +# 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 ΡˆΡ€ΠΈΡ„Ρ‚ΠΎΠ²Π΅. +document_colors_not_allowed=На PDF-Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΈΡ‚Π΅ Π½Π΅ Π΅ Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΎ Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ‚ собствСни Ρ†Π²Π΅Ρ‚ΠΎΠ²Π΅: β€žΠ Π°Π·Ρ€Π΅ΡˆΠ°Π²Π°Π½Π΅ Π½Π° страницитС Π΄Π° ΠΈΠ·Π±ΠΈΡ€Π°Ρ‚ собствСни Ρ†Π²Π΅Ρ‚ΠΎΠ²Π΅β€œ Π΅ ΠΈΠ·ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΎ Π² Π±Ρ€Π°ΡƒΠ·ΡŠΡ€Π°. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/bn-BD/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/bn-BD/viewer.properties new file mode 100755 index 00000000..53e3c1e7 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/bn-BD/viewer.properties @@ -0,0 +1,181 @@ +# 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=({{pagesCount}} এর {{pageNumber}}) + +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=ΰ¦ͺ্রΰ¦₯ΰ¦ ΰ¦ͺাঀায় যাও +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.title=হ্যান্঑ টুল সক্রিয় করুন + +# 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=ΰ¦ͺি঑িএফ ΰ¦ͺ্রস্ঀুঀকারক: +document_properties_version=ΰ¦ͺি঑িএফ সংষ্করণ: +document_properties_page_count=ΰ¦ΰ§‹ΰ¦Ÿ ΰ¦ͺাঀা: +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_notification.title=সাই঑বার ΰ¦Ÿΰ¦—ΰ¦² (নΰ¦₯িঀে ΰ¦†ΰ¦‰ΰ¦Ÿΰ¦²ΰ¦Ύΰ¦‡ΰ¦¨/এটাচΰ¦ΰ§‡ΰ¦¨ΰ§ΰ¦Ÿ রয়েছে) +toggle_sidebar_label=সাই঑বার ΰ¦Ÿΰ¦—ΰ¦² করুন +document_outline.title=নΰ¦₯ΰ¦Ώΰ¦° ΰ¦†ΰ¦‰ΰ¦Ÿΰ¦²ΰ¦Ύΰ¦‡ΰ¦¨ দেখাও (সব ΰ¦†ΰ¦‡ΰ¦Ÿΰ§‡ΰ¦ ΰ¦ͺ্রসারিঀ/ΰ¦Έΰ¦™ΰ§ΰ¦•ΰ§ΰ¦šΰ¦Ώΰ¦€ করঀে ঑বল ক্লিক করুন) +document_outline_label=নΰ¦₯ΰ¦Ώΰ¦° ΰ¦°ΰ§‚ΰ¦ͺরেখা +attachments.title=সংযুক্ঀি দেখাও +attachments_label=সংযুক্ঀি +thumbs.title=ΰ¦₯ΰ¦Ύΰ¦ΰ§ΰ¦¬ΰ¦¨ΰ§‡ΰ¦‡ΰ¦² ΰ¦Έΰ¦ΰ§‚ΰ¦Ή ΰ¦ͺ্রদর্ঢন করুন +thumbs_label=ΰ¦₯ΰ¦Ύΰ¦ΰ§ΰ¦¬ΰ¦¨ΰ§‡ΰ¦‡ΰ¦² ΰ¦Έΰ¦ΰ§‚ΰ¦Ή +findbar.title=নΰ¦₯ΰ¦Ώΰ¦° ΰ¦ΰ¦§ΰ§ΰ¦―ে ΰ¦–ΰ§ΰ¦ΰ¦œΰ§ΰ¦¨ +findbar_label=ΰ¦–ΰ§ΰ¦ΰ¦œΰ§ΰ¦¨ + +# 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_reached_top=ΰ¦ͺৃষ্ঠার ঢুরুঀে ΰ¦ͺΰ§Œΰ¦›ΰ§‡ গেছে, ΰ¦¨ΰ§€ΰ¦š ΰ¦₯েকে আরΰ¦ΰ§ΰ¦­ করা ΰ¦Ήΰ§Ÿΰ§‡ΰ¦›ΰ§‡ +find_reached_bottom=ΰ¦ͺৃষ্ঠার ঢেষে ΰ¦ͺΰ§Œΰ¦›ΰ§‡ গেছে, উΰ¦ͺΰ¦° ΰ¦₯েকে আরΰ¦ΰ§ΰ¦­ করা ΰ¦Ήΰ§Ÿΰ§‡ΰ¦›ΰ§‡ +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: {{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_indicator=ঀ্রুটি +loading_error=ΰ¦ͺি঑িএফ লো঑ করার ΰ¦Έΰ¦ΰ§Ÿ ঀ্রুটি দেখা ΰ¦¦ΰ¦Ώΰ§Ÿΰ§‡ΰ¦›ΰ§‡ΰ₯€ +invalid_file_error=অকার্যকর ΰ¦…ΰ¦₯বা ক্ষঀিগ্রস্ঀ ΰ¦ͺি঑িএফ ফাইলΰ₯€ +missing_file_error=ΰ¦¨ΰ¦Ώΰ¦–ΰ§‹ΰ¦ΰ¦œ PDF ফাইলΰ₯€ +unexpected_response_error=ΰ¦…ΰ¦ͺ্রঀ্যাঢীঀ সার্ভার ΰ¦ͺΰ§ΰ¦°ΰ¦€ΰ¦Ώΰ¦•ΰ§ΰ¦°ΰ¦Ώΰ§Ÿΰ¦Ύΰ₯€ + +# 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=ΰ¦ͺি঑িএফ ΰ¦«ΰ¦Ύΰ¦‡ΰ¦²ΰ¦Ÿΰ¦Ώ ওΰ¦ͺেন করঀে ΰ¦ͺΰ¦Ύΰ¦Έΰ¦“ΰ§Ÿΰ¦Ύΰ¦°ΰ§ΰ¦‘ দিনΰ₯€ +password_invalid=ভুল ΰ¦ͺΰ¦Ύΰ¦Έΰ¦“ΰ§Ÿΰ¦Ύΰ¦°ΰ§ΰ¦‘ΰ₯€ অনুগ্রহ করে আবার ΰ¦šΰ§‡ΰ¦·ΰ§ΰ¦Ÿΰ¦Ύ করুনΰ₯€ +password_ok=ঠিক আছে +password_cancel=বাঀিল + +printing_not_supported=সঀর্কঀা: এই ΰ¦¬ΰ§ΰ¦°ΰ¦Ύΰ¦‰ΰ¦œΰ¦Ύΰ¦°ΰ§‡ ΰ¦ΰ§ΰ¦¦ΰ§ΰ¦°ΰ¦£ ΰ¦Έΰ¦ΰ§ΰ¦ͺূর্ণভাবে ΰ¦Έΰ¦ΰ¦°ΰ§ΰ¦₯িঀ নয়ΰ₯€ +printing_not_ready=সঀর্কীকরণ: ΰ¦ͺি঑িএফটি ΰ¦ΰ§ΰ¦¦ΰ§ΰ¦°ΰ¦£ΰ§‡ΰ¦° জন্য ΰ¦Έΰ¦ΰ§ΰ¦ͺূর্ণ লো঑ হয়নিΰ₯€ +web_fonts_disabled=ΰ¦“ΰ§Ÿΰ§‡ΰ¦¬ ফন্ট ΰ¦¨ΰ¦Ώΰ¦·ΰ§ΰ¦•ΰ§ΰ¦°ΰ¦Ώΰ§Ÿ: সংযুক্ঀ ΰ¦ͺি঑িএফ ফন্ট ব্যবহার করা ΰ¦―ΰ¦Ύΰ¦šΰ§ΰ¦›ΰ§‡ নাΰ₯€ +document_colors_not_allowed=ΰ¦ͺি঑িএফ ঑কুΰ¦ΰ§‡ΰ¦¨ΰ§ΰ¦Ÿΰ¦•ে ঀাদের নিজস্ব রঙ ব্যবহারে অনুΰ¦ΰ¦€ΰ¦Ώ নেই: 'ΰ¦ͺাঀা ঀাদের ΰ¦¨ΰ¦Ώΰ¦œΰ§‡ΰ¦Έΰ§ΰ¦¬ রঙ নির্বাচন করঀে অনুΰ¦ΰ¦€ΰ¦Ώ দিন' এই ΰ¦¬ΰ§ΰ¦°ΰ¦Ύΰ¦‰ΰ¦œΰ¦Ύΰ¦°ΰ§‡ ΰ¦¨ΰ¦Ώΰ¦·ΰ§ΰ¦•ΰ§ΰ¦°ΰ¦Ώΰ§Ÿ ΰ¦°ΰ§Ÿΰ§‡ΰ¦›ΰ§‡ΰ₯€ diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/bn-IN/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/bn-IN/viewer.properties new file mode 100755 index 00000000..4e229239 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/bn-IN/viewer.properties @@ -0,0 +1,177 @@ +# 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=({{pagesCount}} এর {{pageNumber}}) + +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=ΰ¦ͺ্রΰ¦₯ΰ¦ ΰ¦ͺΰ§ƒΰ¦·ΰ§ΰ¦ ΰ¦Ύΰ§Ÿ চলুন +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=বাঁদিকে ΰ¦˜ΰ§‹ΰ¦°ΰ¦Ύΰ¦¨ΰ§‹ হবে + + +# 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}} 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}} ΰ¦ΰ§‡ΰ¦—ΰ¦Ύΰ¦¬ΰ¦Ύΰ¦‡ΰ¦Ÿ ({{size_b}} bytes) +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_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.title=঑কুΰ¦ΰ§‡ΰ¦¨ΰ§ΰ¦Ÿ ΰ¦†ΰ¦‰ΰ¦Ÿΰ¦²ΰ¦Ύΰ¦‡ΰ¦¨ দেখান (দুবার ক্লিক করুন ΰ¦¬ΰ¦Ύΰ§œΰ¦Ύΰ¦€ΰ§‡//collapse ΰ¦Έΰ¦ΰ¦Έΰ§ΰ¦€ ΰ¦†ΰ¦‡ΰ¦Ÿΰ§‡ΰ¦) +document_outline_label=঑কুΰ¦ΰ§‡ΰ¦¨ΰ§ΰ¦Ÿ ΰ¦†ΰ¦‰ΰ¦Ÿΰ¦²ΰ¦Ύΰ¦‡ΰ¦¨ +attachments.title=সংযুক্ঀিসΰ¦ΰ§‚ΰ¦Ή দেখান +attachments_label=সংযুক্ঀ বস্ঀু +thumbs.title=ΰ¦₯ΰ¦Ύΰ¦ΰ§ΰ¦¬-নেইল ΰ¦ͺ্রদর্ঢন +thumbs_label=ΰ¦₯ΰ¦Ύΰ¦ΰ§ΰ¦¬-নেইল ΰ¦ͺ্রদর্ঢন +findbar.title=নΰ¦₯িঀে ΰ¦–ΰ§ΰ¦ΰ¦œΰ§ΰ¦¨ +findbar_label=অনুসন্ধান করুন + +# 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_previous_label=ΰ¦ͺূর্ববর্ঀী +find_next.title=চিহ্নিঀ ΰ¦ͺংক্ঀির ΰ¦ͺরবর্ঀী উΰ¦ͺস্ΰ¦₯িঀি অনুসন্ধান করুন +find_next_label=ΰ¦ͺরবর্ঀী +find_highlight=ΰ¦Έΰ¦ΰ¦—্র ΰ¦‰ΰ¦œΰ§ΰ¦œΰ§ΰ¦¬ΰ¦² করুন +find_match_case_label=হরফের ছাঁদ ΰ¦ΰ§‡ΰ¦²ΰ¦Ύΰ¦¨ΰ§‹ হবে +find_reached_top=ΰ¦ͺৃষ্ঠার ΰ¦ͺ্রারΰ¦ΰ§ΰ¦­ΰ§‡ ΰ¦ͺΰ§Œΰ¦›ΰ§‡ গেছে, ΰ¦¨ΰ§€ΰ¦šΰ§‡ΰ¦° অংঢ ΰ¦₯েকে আরΰ¦ΰ§ΰ¦­ করা হবে +find_reached_bottom=ΰ¦ͺৃষ্ঠার অন্ঀিঠΰ¦ͺ্রান্ঀে ΰ¦ͺΰ§Œΰ¦›ΰ§‡ গেছে, ΰ¦ͺ্রΰ¦₯ঠঅংঢ ΰ¦₯েকে আরΰ¦ΰ§ΰ¦­ করা হবে +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: {{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=ΰ¦ͺৃষ্ঠা ΰ¦ͺ্রদর্ঢনকালে ΰ¦ΰ¦•ΰ¦Ÿΰ¦Ώ ΰ¦Έΰ¦ΰ¦Έΰ§ΰ¦―ΰ¦Ύ দেখা ΰ¦¦ΰ¦Ώΰ§Ÿΰ§‡ΰ¦›ΰ§‡ΰ₯€ + +# 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_indicator=ঀ্রুটি +loading_error=PDF লো঑ করার ΰ¦Έΰ¦ΰ§Ÿ ΰ¦Έΰ¦ΰ¦Έΰ§ΰ¦―ΰ¦Ύ দেখা ΰ¦¦ΰ¦Ώΰ§Ÿΰ§‡ΰ¦›ΰ§‡ΰ₯€ +invalid_file_error=ΰ¦…ΰ¦¬ΰ§ˆΰ¦§ বা ক্ষঀিগ্রস্ঀ ΰ¦ͺি঑িএফ ফাইলΰ₯€ +missing_file_error=অনুΰ¦ͺস্ΰ¦₯িঀ PDF ফাইল +unexpected_response_error=সার্ভার ΰ¦₯েকে ΰ¦…ΰ¦ͺ্রঀ্যাঢিঀ সাড়া ΰ¦ͺΰ¦Ύΰ¦“ΰ§Ÿΰ¦Ύ গেছেΰ₯€ + +# 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=এই PDF ফাইল খোলার জন্য ΰ¦ͺাসওয়ার্঑ দিনΰ₯€ +password_invalid=ΰ¦ͺΰ¦Ύΰ¦Έΰ¦“ΰ§Ÿΰ¦Ύΰ¦°ΰ§ΰ¦‘ সঠিক নয়ΰ₯€ অনুগ্রহ করে ΰ¦ͺুনরায় ΰ¦ͺΰ§ΰ¦°ΰ¦šΰ§‡ΰ¦·ΰ§ΰ¦Ÿΰ¦Ύ করুনΰ₯€ +password_ok=OK +password_cancel=বাঀিল করুন + +printing_not_supported=সঀর্কবার্ঀা: এই ΰ¦¬ΰ§ΰ¦°ΰ¦Ύΰ¦‰ΰ¦œΰ¦Ύΰ¦° দ্বারা ΰ¦ͺ্রিন্ট ব্যবস্ΰ¦₯ΰ¦Ύ ΰ¦Έΰ¦ΰ§ΰ¦ͺূর্ণরূΰ¦ͺে ΰ¦Έΰ¦ΰ¦°ΰ§ΰ¦₯িঀ নয়ΰ₯€ +printing_not_ready=সঀর্কবাণী: ΰ¦ͺি঑িএফ ΰ¦Έΰ¦ΰ§ΰ¦ͺূর্ণরূΰ¦ͺে ΰ¦ΰ§ΰ¦¦ΰ§ΰ¦°ΰ¦£ΰ§‡ΰ¦° জন্য লো঑ করা ΰ¦Ήΰ¦―ΰ¦Ό না. +web_fonts_disabled=ওয়েব ফন্ট নিষ্ক্রিয় করা হয়েছে: এΰ¦ΰ¦¬ΰ§‡ΰ¦‘ে঑ ΰ¦ͺি঑িএফ ফন্ট ব্যবহার করঀে অক্ষΰ¦. +document_colors_not_allowed=ΰ¦ͺি঑িএফ নΰ¦₯ΰ¦Ώ ঀাদের নিজস্ব রং ব্যবহার করার জন্য অনুΰ¦ΰ¦€ΰ¦Ώΰ¦ͺ্রাΰ¦ͺ্ঀ নয়: ΰ¦¬ΰ§ΰ¦°ΰ¦Ύΰ¦‰ΰ¦œΰ¦Ύΰ¦°ΰ§‡ নিষ্ক্রিয় করা হয়েছে ΰ§Ÿΰ§‡ΰ¦¨ 'ΰ¦ͺΰ§‡ΰ¦œ ঀাদের নিজস্ব রং নির্বাচন করার অনুΰ¦ΰ¦€ΰ¦Ώ ΰ¦ͺ্রদান করা য়ায়ΰ₯€' diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/br/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/br/viewer.properties new file mode 100755 index 00000000..94dac29a --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/br/viewer.properties @@ -0,0 +1,180 @@ +# 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=Pajenn a-raok +previous_label=A-raok +next.title=Pajenn war-lerc'h +next_label=War-lerc'h + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Pajenn +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=eus {{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}} war {{pagesCount}}) + +zoom_out.title=Zoum bihanaat +zoom_out_label=Zoum bihanaat +zoom_in.title=Zoum brasaat +zoom_in_label=Zoum brasaat +zoom.title=Zoum +presentation_mode.title=Trec'haoliΓ± etrezek ar mod kinnigadenn +presentation_mode_label=Mod kinnigadenn +open_file.title=DigeriΓ± ur restr +open_file_label=DigeriΓ± ur restr +print.title=MoullaΓ± +print_label=MoullaΓ± +download.title=PellgargaΓ± +download_label=PellgargaΓ± +bookmark.title=Gwel bremanel (eilaΓ± pe zigeriΓ± e-barzh ur prenestr nevez) +bookmark_label=Gwel bremanel + +# Secondary toolbar and context menu +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 + + +# 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 : +# 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Γ± : +# 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_close=SerriΓ± + +print_progress_message=O prientiΓ± an teul evit moullaΓ±... +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=NullaΓ± + +# 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=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_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ΓΉ +thumbs.title=Diskouez ar melvennoΓΉ +thumbs_label=MelvennoΓΉ +findbar.title=Klask e-barzh an teuliad +findbar_label=Klask + +# 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=Pajenn {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Melvenn ar bajenn {{page}} + +# Find panel button title and messages +find_input.title=Klask +find_input.placeholder=Klask e-barzh an teuliad +find_previous.title=Kavout an tamm frazenn kent o klotaΓ± ganti +find_previous_label=Kent +find_next.title=Kavout an tamm frazenn war-lerc'h o klotaΓ± ganti +find_next_label=War-lerc'h +find_highlight=UsskediΓ± pep tra +find_match_case_label=Teurel evezh ouzh ar pennlizherennoΓΉ +find_reached_top=Tizhet eo bet derou ar bajenn, kenderc'hel diouzh an diaz +find_reached_bottom=Tizhet eo bet dibenn ar bajenn, kenderc'hel diouzh ar c'hrec'h +find_not_found=N'haller ket kavout ar frazenn + +# Error panel labels +error_more_info=Muioc'h a ditouroΓΉ +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}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Kemennadenn : {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Torn : {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Restr : {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Linenn : {{line}} +rendering_error=Degouezhet ez eus bet ur fazi e-pad skrammaΓ± ar bajennad. + +# Predefined zoom values +page_scale_width=Led ar bajenn +page_scale_fit=Pajenn a-bezh +page_scale_auto=Zoum emgefreek +page_scale_actual=Ment wir +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Fazi +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. +unexpected_response_error=Respont dic'hortoz a-berzh an dafariad + +# 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}} NotennaΓ±] +password_label=Enankit ar ger-tremen evit digeriΓ± ar restr PDF-maΓ±. +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. +document_colors_not_allowed=N'eo ket aotreet an teuliadoΓΉ PDF da arveraΓ± o livioΓΉ dezho : diweredekaet eo β€œAotren ar pajennoΓΉ da zibab o livioΓΉ dezho” e-barzh ar merdeer. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/bs/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/bs/viewer.properties new file mode 100755 index 00000000..64735bef --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/bs/viewer.properties @@ -0,0 +1,180 @@ +# 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=Prethodna strana +previous_label=Prethodna +next.title=SljedeΔ‡a strna +next_label=SljedeΔ‡a + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Strana +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=od {{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}} od {{pagesCount}}) + +zoom_out.title=Umanji +zoom_out_label=Umanji +zoom_in.title=UveΔ‡aj +zoom_in_label=UveΔ‡aj +zoom.title=UveΔ‡anje +presentation_mode.title=Prebaci se u prezentacijski reΕΎim +presentation_mode_label=Prezentacijski reΕΎim +open_file.title=Otvori fajl +open_file_label=Otvori +print.title=Ε tampaj +print_label=Ε tampaj +download.title=Preuzmi +download_label=Preuzmi +bookmark.title=Trenutni prikaz (kopiraj ili otvori u novom prozoru) +bookmark_label=Trenutni prikaz + +# Secondary toolbar and context menu +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 + + +# Document properties dialog box +document_properties.title=Svojstva dokumenta... +document_properties_label=Svojstva dokumenta... +document_properties_file_name=Naziv fajla: +document_properties_file_size=Veličina fajla: +# 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}} bajta) +# 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}} bajta) +document_properties_title=Naslov: +document_properties_author=Autor: +document_properties_subject=Predmet: +document_properties_keywords=Ključne riječi: +document_properties_creation_date=Datum kreiranja: +document_properties_modification_date=Datum promjene: +# 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=Kreator: +document_properties_producer=PDF stvaratelj: +document_properties_version=PDF verzija: +document_properties_page_count=Broj stranica: +document_properties_close=Zatvori + +print_progress_message=Pripremam dokument za Ε‘tampu… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=OtkaΕΎi + +# 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=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 +attachments.title=PrikaΕΎi priloge +attachments_label=Prilozi +thumbs.title=PrikaΕΎi thumbnailove +thumbs_label=Thumbnailovi +findbar.title=PronaΔ‘i u dokumentu +findbar_label=PronaΔ‘i + +# 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=Strana {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Thumbnail strane {{page}} + +# Find panel button title and messages +find_input.title=PronaΔ‘i +find_input.placeholder=PronaΔ‘i u dokumentu… +find_previous.title=PronaΔ‘i prethodno pojavljivanje fraze +find_previous_label=Prethodno +find_next.title=PronaΔ‘i sljedeΔ‡e pojavljivanje fraze +find_next_label=SljedeΔ‡e +find_highlight=Označi sve +find_match_case_label=Osjetljivost na karaktere +find_reached_top=Dostigao sam vrh dokumenta, nastavljam sa dna +find_reached_bottom=Dostigao sam kraj dokumenta, nastavljam sa vrha +find_not_found=Fraza nije pronaΔ‘ena + +# Error panel labels +error_more_info=ViΕ‘e informacija +error_less_info=Manje informacija +error_close=Zatvori +# 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=Poruka: {{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=Fajl: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Linija: {{line}} +rendering_error=DoΕ‘lo je do greΕ‘ke prilikom renderiranja strane. + +# Predefined zoom values +page_scale_width=Ε irina strane +page_scale_fit=Uklopi stranu +page_scale_auto=Automatsko uveΔ‡anje +page_scale_actual=Stvarna veličina +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# 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. +unexpected_response_error=Neočekivani odgovor servera. + +# 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}} pribiljeΕ‘ka] +password_label=UpiΕ‘ite lozinku da biste otvorili ovaj PDF fajl. +password_invalid=PogreΕ‘na lozinka. PokuΕ‘ajte ponovo. +password_ok=OK +password_cancel=OtkaΕΎi + +printing_not_supported=Upozorenje: Ε tampanje nije u potpunosti podrΕΎano u ovom browseru. +printing_not_ready=Upozorenje: PDF nije u potpunosti učitan za Ε‘tampanje. +web_fonts_disabled=Web fontovi su onemoguΔ‡eni: nemoguΔ‡e koristiti ubačene PDF fontove. +document_colors_not_allowed=PDF dokumentima nije dozvoljeno da koriste vlastite boje: 'Dozvoli stranicama da izaberu vlastite boje' je deaktivirano u browseru. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ca/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ca/viewer.properties new file mode 100755 index 00000000..2bc7ffad --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ca/viewer.properties @@ -0,0 +1,184 @@ +# 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 anterior +previous_label=Anterior +next.title=PΓ gina segΓΌent +next_label=SegΓΌent + +# 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=Allunya +zoom_out_label=Allunya +zoom_in.title=Apropa +zoom_in_label=Apropa +zoom.title=Escala +presentation_mode.title=Canvia al mode de presentaciΓ³ +presentation_mode_label=Mode de presentaciΓ³ +open_file.title=Obre el fitxer +open_file_label=Obre +print.title=Imprimeix +print_label=Imprimeix +download.title=Baixa +download_label=Baixa +bookmark.title=Vista actual (copia o obre en una finestra nova) +bookmark_label=Vista actual + +# Secondary toolbar and context menu +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 +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Γ  + +# Document properties dialog box +document_properties.title=Propietats del document… +document_properties_label=Propietats del document… +document_properties_file_name=Nom del fitxer: +document_properties_file_size=Mida del fitxer: +# 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Γ­tol: +document_properties_author=Autor: +document_properties_subject=Assumpte: +document_properties_keywords=Paraules clau: +document_properties_creation_date=Data de creaciΓ³: +document_properties_modification_date=Data de modificaciΓ³: +# 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=Generador de PDF: +document_properties_version=VersiΓ³ de PDF: +document_properties_page_count=Nombre de pΓ gines: +document_properties_close=Tanca + +print_progress_message=S'estΓ  preparant la impressiΓ³ del document… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=CancelΒ·la + +# 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=Mostra/amaga la barra lateral +toggle_sidebar_notification.title=Mostra/amaga la barra lateral (el document contΓ© un esquema o adjuncions) +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 +attachments.title=Mostra les adjuncions +attachments_label=Adjuncions +thumbs.title=Mostra les miniatures +thumbs_label=Miniatures +findbar.title=Cerca al document +findbar_label=Cerca + +# 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 la pΓ gina {{page}} + +# Find panel button title and messages +find_input.title=Cerca +find_input.placeholder=Cerca al document… +find_previous.title=Cerca l'anterior coincidΓ¨ncia de l'expressiΓ³ +find_previous_label=Anterior +find_next.title=Cerca la segΓΌent coincidΓ¨ncia de l'expressiΓ³ +find_next_label=SegΓΌent +find_highlight=Ressalta-ho tot +find_match_case_label=Distingeix entre majΓΊscules i minΓΊscules +find_reached_top=S'ha arribat al principi del document, es continua pel final +find_reached_bottom=S'ha arribat al final del document, es continua pel principi +find_not_found=No s'ha trobat l'expressiΓ³ + +# Error panel labels +error_more_info=MΓ©s informaciΓ³ +error_less_info=Menys informaciΓ³ +error_close=Tanca +# 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}} (muntatge: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Missatge: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Pila: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Fitxer: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +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_fit=Ajusta la pΓ gina +page_scale_auto=Zoom automΓ tic +page_scale_actual=Mida 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_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. +unexpected_response_error=Resposta inesperada del servidor. + +# 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Γ³ {{type}}] +password_label=IntroduΓ―u la contrasenya per obrir aquest fitxer PDF. +password_invalid=La contrasenya no Γ©s vΓ lida. Torneu-ho a provar. +password_ok=D'acord +password_cancel=CancelΒ·la + +printing_not_supported=AvΓ­s: la impressiΓ³ no Γ©s plenament funcional en aquest navegador. +printing_not_ready=AtenciΓ³: el PDF no s'ha acabat de carregar per imprimir-lo. +web_fonts_disabled=Els tipus de lletra web estan desactivats: no es poden utilitzar els tipus de lletra incrustats al PDF. +document_colors_not_allowed=Els documents PDF no poden usar els seus colors propis: Β«Permet a les pΓ gines triar els colors propisΒ» es troba desactivat al navegador. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/cs/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/cs/viewer.properties new file mode 100755 index 00000000..13b36fc9 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/cs/viewer.properties @@ -0,0 +1,184 @@ +# 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Ε™ejde na pΕ™edchozΓ­ strΓ‘nku +previous_label=PΕ™edchozΓ­ +next.title=PΕ™ejde na nΓ‘sledujΓ­cΓ­ strΓ‘nku +next_label=DalΕ‘Γ­ + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=StrΓ‘nka +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=z {{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}} z {{pagesCount}}) + +zoom_out.title=ZmenΕ‘Γ­ velikost +zoom_out_label=ZmenΕ‘it +zoom_in.title=ZvΔ›tΕ‘Γ­ velikost +zoom_in_label=ZvΔ›tΕ‘it +zoom.title=NastavΓ­ velikost +presentation_mode.title=PΕ™epne do reΕΎimu prezentace +presentation_mode_label=ReΕΎim prezentace +open_file.title=OtevΕ™e soubor +open_file_label=OtevΕ™Γ­t +print.title=Vytiskne dokument +print_label=Tisk +download.title=StΓ‘hne dokument +download_label=StΓ‘hnout +bookmark.title=SoučasnΓ½ pohled (kopΓ­rovat nebo otevΕ™Γ­t v novΓ©m oknΔ›) +bookmark_label=SoučasnΓ½ pohled + +# Secondary toolbar and context menu +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 +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 + +# Document properties dialog box +document_properties.title=Vlastnosti dokumentu… +document_properties_label=Vlastnosti dokumentu… +document_properties_file_name=NΓ‘zev souboru: +document_properties_file_size=Velikost souboru: +# 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}} bajtΕ―) +# 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}} bajtΕ―) +document_properties_title=Nadpis: +document_properties_author=Autor: +document_properties_subject=PΕ™edmΔ›t: +document_properties_keywords=KlíčovΓ‘ slova: +document_properties_creation_date=Datum vytvoΕ™enΓ­: +document_properties_modification_date=Datum ΓΊpravy: +# 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=VytvoΕ™il: +document_properties_producer=TvΕ―rce PDF: +document_properties_version=Verze PDF: +document_properties_page_count=Počet strΓ‘nek: +document_properties_close=ZavΕ™Γ­t + +print_progress_message=PΕ™Γ­prava dokumentu pro tisk… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}} % +print_progress_close=ZruΕ‘it + +# 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=PostrannΓ­ liΕ‘ta +toggle_sidebar_notification.title=PΕ™epne postrannΓ­ liΕ‘tu (dokument obsahuje osnovu/pΕ™Γ­lohy) +toggle_sidebar_label=PostrannΓ­ liΕ‘ta +document_outline.title=ZobrazΓ­ osnovu dokumentu (dvojitΓ© klepnutΓ­ rozbalΓ­/sbalΓ­ vΕ‘echny poloΕΎky) +document_outline_label=Osnova dokumentu +attachments.title=ZobrazΓ­ pΕ™Γ­lohy +attachments_label=PΕ™Γ­lohy +thumbs.title=ZobrazΓ­ nΓ‘hledy +thumbs_label=NΓ‘hledy +findbar.title=Najde v dokumentu +findbar_label=NajΓ­t + +# 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=Strana {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=NΓ‘hled strany {{page}} + +# Find panel button title and messages +find_input.title=NajΓ­t +find_input.placeholder=NajΓ­t v dokumentu… +find_previous.title=Najde pΕ™edchozΓ­ vΓ½skyt hledanΓ©ho textu +find_previous_label=PΕ™edchozΓ­ +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_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 +find_not_found=HledanΓ½ text nenalezen + +# Error panel labels +error_more_info=VΓ­ce informacΓ­ +error_less_info=MΓ©nΔ› informacΓ­ +error_close=ZavΕ™Γ­t +# 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}} (sestavenΓ­: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=ZprΓ‘va: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=ZΓ‘sobnΓ­k: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Soubor: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=ŘÑdek: {{line}} +rendering_error=PΕ™i vykreslovΓ‘nΓ­ strΓ‘nky nastala chyba. + +# Predefined zoom values +page_scale_width=Podle Ε‘Γ­Ε™ky +page_scale_fit=Podle vΓ½Ε‘ky +page_scale_auto=AutomatickΓ‘ velikost +page_scale_actual=SkutečnΓ‘ velikost +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Chyba +loading_error=PΕ™i nahrΓ‘vΓ‘nΓ­ PDF nastala chyba. +invalid_file_error=NeplatnΓ½ nebo chybnΓ½ soubor PDF. +missing_file_error=ChybΓ­ soubor PDF. +unexpected_response_error=NeočekΓ‘vanΓ‘ odpověď serveru. + +# 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=[Anotace typu {{type}}] +password_label=Pro otevΕ™enΓ­ PDF souboru vloΕΎte heslo. +password_invalid=NeplatnΓ© heslo. Zkuste to znovu. +password_ok=OK +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. +document_colors_not_allowed=PDF dokumenty nemajΓ­ povoleno pouΕΎΓ­vat vlastnΓ­ barvy: volba 'Povolit strΓ‘nkΓ‘m pouΕΎΓ­vat vlastnΓ­ barvy' je v prohlΓ­ΕΎeči deaktivovΓ‘na. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/csb/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/csb/viewer.properties new file mode 100755 index 00000000..293a353c --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/csb/viewer.properties @@ -0,0 +1,134 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Main toolbar buttons (tooltips and alt text for images) +previous.title=PΓ²przΓ©dnΓ΄ strona +previous_label=PΓ²przΓ©dnΓ΄ +next.title=NΓ΄slΓ©dnΓ΄ strona +next_label=NΓ΄slΓ©dnΓ΄ + +# LOCALIZATION NOTE (page_label, page_of): +# These strings are concatenated to form the "Page: X of Y" string. +# Do not translate "{{pageCount}}", it will be substituted with a number +# representing the total number of pages. +page_label=Strona: +page_of=z {{pageCount}} + +zoom_out.title=ZmniΓ©szΓ« +zoom_out_label=ZmniΓ©szΓ« +zoom_in.title=ZwikszΓ« +zoom_in_label=WiΓ΄lgΓ²sc +zoom.title=WiΓ΄lgΓ²sc +print.title=DrΓ«kΓΉjΓ« +print_label=DrΓ«kΓΉjΓ« +presentation_mode.title=PrzΓ©Ε„dzΓ« w trib prezentacje +presentation_mode_label=Trib prezentacje +open_file.title=Γ’temkni lopk +open_file_label=Γ’temkni +download.title=ZladΓ«nk +download_label=ZladΓ«nk +bookmark.title=SpamiΓ£tΓ΄j wΓ«zdrzatk (kΓ²pΓ©rΓ«je, abΓ² Γ²temkni w nowim Γ²knnie) +bookmark_label=Aktualny wΓ«zdrzatk + +find_label=SzΓ«kΓ΄j: +find_previous.title=BiΓ©j do pΓ²przΓ©dnΓ©gΓ² wΓ«nikΓΉ szΓ«kbΓ« +find_previous_label=PΓ²przΓ©dny +find_next.title=BiΓ©j do nΓ΄slΓ©dnΓ©gΓ² wΓ«nikΓΉ szΓ«kbΓ« +find_next_label=NΓ΄slΓ©dny +find_highlight=PΓ²dszkrzΓ«ni wszΓ«tczΓ© +find_match_case_label=RozeznΓ΄wΓ΄j miarΓ£ lΓ«terΓ³w +find_not_found=Nie nalΓ΄zΕ‚ tekstu +find_reached_bottom=DoszedΕ‚ do kΓΉΕ„ca dokΓΉmentu, zaczinajΔ…cΓ« Γ²d gΓ³rΓ« +find_reached_top=DoszedΕ‚ do pΓ²czΔ…tkΓΉ dokΓΉmentu, zaczinajΔ…cΓ« Γ²d doΕ‚ΓΉ + +toggle_sidebar.title=PΓ²suwk wΓ«biΓ©rkΓΉ +toggle_sidebar_label=PΓ²suwk wΓ«biΓ©rkΓΉ + +outline.title=WΓ«skrzΓ«ni Γ²bcΓ©ch dokΓΉmentu +outline_label=Γ’bcΓ©ch dokΓΉmentu +thumbs.title=WΓ«skrzΓ«ni miniaturΓ« +thumbs_label=MiniaturΓ« +findbar.title=PrzeszΓ«kΓ΄j dokΓΉment +findbar_label=NalezΓ« +tools_label=NΓ΄rzΓ£dΕ‚a +first_page.title=BiΓ©j do pierszi stronΓ« +first_page.label=BiΓ©j do pierszi stronΓ« +last_page.label=BiΓ©j do Γ²statny stronΓ« +invalid_file_error=LΓ«chi Γ΄rt, abΓ² pΓ²psΓ«ti lopk PDF. + + + +# 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=Strona {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Miniatura stronΓ« {{page}} + +# Error panel labels +error_more_info=Wicy infΓ²rmacje +error_less_info=Mni infΓ²rmacje +error_close=Close +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: {{wiadΕ‚o}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Stack: {{stΓ³g}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=File: {{lopk}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Line: {{line}} +rendering_error=PΓ²kΓ΄za sΓ£ fela przΓ« renderowanim stronΓ«. + +# Predefined zoom values +page_scale_width=SzΓ©rzawa stronΓ« +page_scale_fit=DopasΓ«je stronΓ£ +page_scale_auto=AΓΉtomatnΓ΄ wiΓ΄lgΓ²sc +page_scale_actual=NaturalnΓ΄ wiΓ΄lgΓ²sc + +# Loading indicator messages +# LOCALIZATION NOTE (error_line): "{{[percent}}" will be replaced with a percentage +loading_error_indicator=Fela +loading_error=PΓ²kΓ΄za sΓ£ fela przΓ« wczΓ«tiwanim PDFΓΉ. + +# LOCALIZATION NOTE (text_annotation_type): 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" + +request_password=PDF je zabezpieczony parolΔ…: +printing_not_supported = Γ’strzΓ©ga: przezΓ©rnik nie je do kΓΉΕ„ca wspierΓ³ny przez drΓ«kΓ΄rze + +# Context menu +page_rotate_cw.label=Γ’bkrΓ£cΓ« w prawΓ² +page_rotate_ccw.label=Γ’bkrΓ£cΓ« w lewΓ² + + +last_page.title=BiΓ©j do pΓ²przΓ©dny stronΓ« +last_page_label=BiΓ©j do pΓ²przΓ©dny stronΓ« +page_rotate_cw.title=Γ’bkrΓ£cΓ« w prawΓ² +page_rotate_cw_label=Γ’bkrΓ£cΓ« w prawΓ² +page_rotate_ccw.title=Γ’bkrΓ£cΓ« w lewΓ² +page_rotate_ccw_label=Γ’bkrΓ£cΓ« w lewΓ² + + +web_fonts_disabled=SΓ©cowΓ© czconczi sΔ… wΓ«Ε‚Δ…czonΓ©: wΕ‚Δ…czΓ« je, bΓ« mΓ³c ΓΉΕΌiwac Γ²sadzonΓ«ch czconkΓ³w w lopkach PDF. + + +missing_file_error=FelΓ«je lopka PDF. +printing_not_ready = Γ’strzΓ©ga: lopk mΓΉszi sΓ£ do kΓΉΕ„ca wczΓ«tac zanim gΓ² mΓ²ΕΌe drΓ«kΓ²wac + +document_colors_disabled=DokΓΉmentΓ« PDF nie mΓ²gΔ… ΓΉ swΓ²jich farwΓ³w: \'PΓ²zwΓ²lΓ« stronΓ³m wΓ«bierac swΓ²je farwΓ«\' je wΓ«Ε‚Δ…czonΓ© w przezΓ©rnikΓΉ. +invalid_password=LΓ«chΓ΄ parola. +text_annotation_type.alt=[AdnotacjΓ΄ {{type}}] + +tools.title=Tools +first_page_label=Go to First Page + + diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/cy/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/cy/viewer.properties new file mode 100755 index 00000000..193768bc --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/cy/viewer.properties @@ -0,0 +1,184 @@ +# 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=Tudalen Flaenorol +previous_label=Blaenorol +next.title=Tudalen Nesaf +next_label=Nesaf + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Tudalen +# 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=Chwyddo Allan +zoom_out_label=Chwyddo Allan +zoom_in.title=Chwyddo Mewn +zoom_in_label=Chwyddo Mewn +zoom.title=Chwyddo +presentation_mode.title=Newid i'r Modd Cyflwyno +presentation_mode_label=Modd Cyflwyno +open_file.title=Agor Ffeil +open_file_label=Agor +print.title=Argraffu +print_label=Argraffu +download.title=Llwyth +download_label=Llwytho i Lawr +bookmark.title=Golwg cyfredol (copΓ―o neu agor ffenestr newydd) +bookmark_label=Golwg Gyfredol + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=Offeryn Dewis Testun +cursor_hand_tool.title=Galluogi Offeryn Llaw +cursor_hand_tool_label=Offeryn Llaw + +# Document properties dialog box +document_properties.title=Priodweddau Dogfen… +document_properties_label=Priodweddau Dogfen… +document_properties_file_name=Enw ffeil: +document_properties_file_size=Maint ffeil: +# 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}} beit) +# 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}} beit) +document_properties_title=Teitl: +document_properties_author=Awdur: +document_properties_subject=Pwnc: +document_properties_keywords=Allweddair: +document_properties_creation_date=Dyddiad Creu: +document_properties_modification_date=Dyddiad Addasu: +# 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=Crewr: +document_properties_producer=Cynhyrchydd PDF: +document_properties_version=Fersiwn PDF: +document_properties_page_count=Cyfrif Tudalen: +document_properties_close=Cau + +print_progress_message=Paratoi dogfen ar gyfer ei hargraffu… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Diddymu + +# 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=Toglo'r Bar Ochr +toggle_sidebar_notification.title=Toglo'r Bar Ochr (mae'r ddogfen yn cynnwys outline/attachments) +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 +thumbs.title=Dangos Lluniau Bach +thumbs_label=Lluniau Bach +findbar.title=Canfod yn y Ddogfen +findbar_label=Canfod + +# 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=Tudalen {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Llun Bach Tudalen {{page}} + +# Find panel button title and messages +find_input.title=Canfod +find_input.placeholder=Canfod yn y ddogfen… +find_previous.title=Canfod enghraifft flaenorol o'r ymadrodd +find_previous_label=Blaenorol +find_next.title=Canfod enghraifft nesaf yr ymadrodd +find_next_label=Nesaf +find_highlight=Amlygu popeth +find_match_case_label=Cydweddu maint +find_reached_top=Wedi cyrraedd brig y dudalen, parhau o'r gwaelod +find_reached_bottom=Wedi cyrraedd diwedd y dudalen, parhau o'r brig +find_not_found=Heb ganfod ymadrodd + +# Error panel labels +error_more_info=Rhagor o Wybodaeth +error_less_info=Llai o wybodaeth +error_close=Cau +# 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=Neges: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Stac: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Ffeil: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Llinell: {{line}} +rendering_error=Digwyddodd gwall wrth adeiladu'r dudalen. + +# Predefined zoom values +page_scale_width=Lled Tudalen +page_scale_fit=Ffit Tudalen +page_scale_auto=Chwyddo Awtomatig +page_scale_actual=Maint Gwirioneddol +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Gwall +loading_error=Digwyddodd gwall wrth lwytho'r PDF. +invalid_file_error=Ffeil PDF annilys neu llwgr. +missing_file_error=Ffeil PDF coll. +unexpected_response_error=Ymateb annisgwyl gan y gweinydd. + +# 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=[Anodiad {{type}} ] +password_label=Rhowch gyfrinair i agor y PDF. +password_invalid=Cyfrinair annilys. Ceisiwch eto. +password_ok=Iawn +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. +document_colors_not_allowed=Nid oes caniatΓ’d i ddogfennau PDF i ddefnyddio eu lliwiau eu hunain: Mae β€œCaniatΓ‘u i dudalennau ddefnyddio eu lliwiau eu hunain” wedi ei atal yn y porwr. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/da/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/da/viewer.properties new file mode 100755 index 00000000..765d6a76 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/da/viewer.properties @@ -0,0 +1,184 @@ +# 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=Forrige side +previous_label=Forrige +next.title=NΓ¦ste side +next_label=NΓ¦ste + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +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=af {{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}} af {{pagesCount}}) + +zoom_out.title=Zoom ud +zoom_out_label=Zoom ud +zoom_in.title=Zoom ind +zoom_in_label=Zoom ind +zoom.title=Zoom +print.title=Udskriv +print_label=Udskriv +presentation_mode.title=Skift til fuldskΓ¦rmsvisning +presentation_mode_label=FuldskΓ¦rmsvisning +open_file.title=Γ…bn fil +open_file_label=Γ…bn +download.title=Hent +download_label=Hent +bookmark.title=Aktuel visning (kopier eller Γ₯bn i et nyt vindue) +bookmark_label=Aktuel visning + +# Secondary toolbar and context menu +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 +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 + +# Document properties dialog box +document_properties.title=Dokumentegenskaber… +document_properties_label=Dokumentegenskaber… +document_properties_file_name=Filnavn: +document_properties_file_size=FilstΓΈrrelse: +# 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=Titel: +document_properties_author=Forfatter: +document_properties_subject=Emne: +document_properties_keywords=NΓΈgleord: +document_properties_creation_date=Oprettet: +document_properties_modification_date=Redigeret: +# 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=Program: +document_properties_producer=PDF-producent: +document_properties_version=PDF-version: +document_properties_page_count=Antal sider: +document_properties_close=Luk + +print_progress_message=Forbereder dokument til udskrivning… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Annuller + +# 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=SlΓ₯ sidepanel til eller fra +toggle_sidebar_notification.title=SlΓ₯ sidepanel til eller fra (dokumentet indeholder disposition/vedhΓ¦ftede filer) +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 +thumbs.title=Vis miniaturer +thumbs_label=Miniaturer +findbar.title=Find i dokument +findbar_label=Find + +# 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=Side {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Miniature af side {{page}} + +# Find panel button title and messages +find_input.title=Find +find_input.placeholder=Find i dokument… +find_previous.title=Find den forrige forekomst +find_previous_label=Forrige +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_reached_top=Toppen af siden blev nΓ₯et, fortsatte fra bunden +find_reached_bottom=Bunden af siden blev nΓ₯et, fortsatte fra toppen +find_not_found=Der blev ikke fundet noget + +# Error panel labels +error_more_info=Mere information +error_less_info=Mindre information +error_close=Luk +# 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=Fejlmeddelelse: {{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=Fil: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Linje: {{line}} +rendering_error=Der opstod en fejl ved generering af siden. + +# Predefined zoom values +page_scale_width=Sidebredde +page_scale_fit=Tilpas til side +page_scale_auto=Automatisk zoom +page_scale_actual=Faktisk stΓΈrrelse +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Fejl +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. +unexpected_response_error=Uventet svar fra serveren. + +# 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}}kommentar] +password_label=Angiv adgangskode til at Γ₯bne denne PDF-fil. +password_invalid=Ugyldig adgangskode. PrΓΈv igen. +password_ok=OK +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. +document_colors_not_allowed=PDF-dokumenter mΓ₯ ikke bruge deres egne farver: 'Tillad sider at vΓ¦lge deres egne farver' er deaktiveret i browseren. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/de/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/de/viewer.properties new file mode 100755 index 00000000..3f5a4e23 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/de/viewer.properties @@ -0,0 +1,184 @@ +# 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=Eine Seite zurΓΌck +previous_label=ZurΓΌck +next.title=Eine Seite vor +next_label=Vor + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Seite +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=von {{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}} von {{pagesCount}}) + +zoom_out.title=Verkleinern +zoom_out_label=Verkleinern +zoom_in.title=Vergrâßern +zoom_in_label=Vergrâßern +zoom.title=Zoom +print.title=Drucken +print_label=Drucken +presentation_mode.title=In PrΓ€sentationsmodus wechseln +presentation_mode_label=PrΓ€sentationsmodus +open_file.title=Datei ΓΆffnen +open_file_label=Γ–ffnen +download.title=Dokument speichern +download_label=Speichern +bookmark.title=Aktuelle Ansicht (zum Kopieren oder Γ–ffnen in einem neuen Fenster) +bookmark_label=Aktuelle Ansicht + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=Textauswahl-Werkzeug +cursor_hand_tool.title=Hand-Werkzeug aktivieren +cursor_hand_tool_label=Hand-Werkzeug + +# Document properties dialog box +document_properties.title=Dokumenteigenschaften +document_properties_label=Dokumenteigenschaften… +document_properties_file_name=Dateiname: +document_properties_file_size=Dateigrâße: +# 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=Titel: +document_properties_author=Autor: +document_properties_subject=Thema: +document_properties_keywords=StichwΓΆrter: +document_properties_creation_date=Erstelldatum: +document_properties_modification_date=Bearbeitungsdatum: +# 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=Anwendung: +document_properties_producer=PDF erstellt mit: +document_properties_version=PDF-Version: +document_properties_page_count=Seitenzahl: +document_properties_close=Schließen + +print_progress_message=Dokument wird fΓΌr Drucken vorbereitet… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Abbrechen + +# 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=Sidebar umschalten +toggle_sidebar_notification.title=Sidebar umschalten (Dokument enthΓ€lt Dokumentstruktur/AnhΓ€nge) +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 +thumbs.title=Miniaturansichten anzeigen +thumbs_label=Miniaturansichten +findbar.title=Dokument durchsuchen +findbar_label=Suchen + +# 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=Seite {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Miniaturansicht von Seite {{page}} + +# Find panel button title and messages +find_input.title=Suchen +find_input.placeholder=Im Dokument suchen… +find_previous.title=Vorheriges Vorkommen des Suchbegriffs finden +find_previous_label=ZurΓΌck +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_reached_top=Anfang des Dokuments erreicht, fahre am Ende fort +find_reached_bottom=Ende des Dokuments erreicht, fahre am Anfang fort +find_not_found=Suchbegriff nicht gefunden + +# Error panel labels +error_more_info=Mehr Informationen +error_less_info=Weniger Informationen +error_close=Schließen +# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be +# replaced by the PDF.JS version and build ID. +error_version_info=PDF.js Version {{version}} (build: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Nachricht: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Aufrufliste: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Datei: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Zeile: {{line}} +rendering_error=Beim Darstellen der Seite trat ein Fehler auf. + +# Predefined zoom values +page_scale_width=Seitenbreite +page_scale_fit=Seitengrâße +page_scale_auto=Automatischer Zoom +page_scale_actual=Originalgrâße +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Fehler +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 +unexpected_response_error=Unerwartete Antwort des Servers + +# 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=[Anlage: {{type}}] +password_label=Geben Sie zum Γ–ffnen der PDF-Datei deren Passwort ein. +password_invalid=Falsches Passwort. Bitte versuchen Sie es erneut. +password_ok=OK +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. +document_colors_not_allowed=PDF-Dokumenten ist es nicht erlaubt, ihre eigenen Farben zu verwenden: 'Seiten das Verwenden von eigenen Farben erlauben' ist im Browser deaktiviert. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/el/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/el/viewer.properties new file mode 100755 index 00000000..5e3f6eee --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/el/viewer.properties @@ -0,0 +1,184 @@ +# 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=ΞœΞ΅Ο„Ξ¬Ξ²Ξ±ΟƒΞ· στην Ο€ΟΟŽΟ„Ξ· σΡλίδα +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_label=ΕργαλΡίο ΡπιλογΞΟ‚ κΡιμένου +cursor_hand_tool.title=ΕνΡργοποίηση ΡργαλΡίου χΡριού +cursor_hand_tool_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}} 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=΀ίτλος: +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_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_notification.title=(Απ)ΡνΡργοποίηση πλΡυρικΞΟ‚ στΞλης (το έγγραφο πΡριέχΡι πΡρίγραμμα/συνημμένα) +toggle_sidebar_label=(Απ)ΡνΡργοποίηση πλΡυρικΞΟ‚ στΞλης +document_outline.title=Εμφάνιση διάρθρωσης Ργγράφου (Ξ΄ΞΉΟ€Ξ»ΟŒ κλικ Ξ³ΞΉΞ± ανάπτυξη/σύμπτυξη ΟŒΞ»Ο‰Ξ½ των στοιχΡίων) +document_outline_label=Διάρθρωση Ργγράφου +attachments.title=ΠροβολΠσυνημμένων +attachments_label=Συνημμένα +thumbs.title=Ξ ΟΞΏΞ²ΞΏΞ»Ξ ΞΌΞΉΞΊΟΞΏΞ³ΟΞ±Ο†ΞΉΟŽΞ½ +thumbs_label=ΞœΞΉΞΊΟΞΏΞ³ΟΞ±Ο†Ξ―Ξ΅Ο‚ +findbar.title=ΕύρΡση στο έγγραφο +findbar_label=ΕύρΡση + +# 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_reached_top=ΞˆΞ»Ξ΅Ο…ΟƒΞ· στην αρχΠτου Ργγράφου, συνέχΡια Ξ±Ο€ΟŒ το τέλος +find_reached_bottom=ΞˆΞ»Ξ΅Ο…ΟƒΞ· στο τέλος του Ργγράφου, συνέχΡια Ξ±Ο€ΟŒ την αρχΠ+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_indicator=Σφάλμα +loading_error=Ξ ΟΞΏΞ­ΞΊΟ…ΟˆΞ΅ Ξ­Ξ½Ξ± σφάλμα κατά τη Ο†ΟŒΟΟ„Ο‰ΟƒΞ· του PDF. +invalid_file_error=Μη έγκυρο ΠκατΡστραμμένο αρχΡίο PDF. +missing_file_error=ΛΡίπΡι αρχΡίο PDF. +unexpected_response_error=Μη αναμΡνόμΡνη Ξ±Ο€ΟŒΞΊΟΞΉΟƒΞ· Ξ±Ο€ΟŒ το διακομιστΞ. + +# 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=Οι γραμματοσΡιρές Web απΡνΡργοποιημένΡς: αδυναμία χρΞσης των Ρνσωματωμένων Ξ³ΟΞ±ΞΌΞΌΞ±Ο„ΞΏΟƒΞ΅ΞΉΟΟŽΞ½ PDF. +document_colors_not_allowed=Στα PDF έγγραφα δΡν ΡπιτρέπΡται Ξ½Ξ± χρησιμοποιούν τα δικά τους Ο‡ΟΟŽΞΌΞ±Ο„Ξ±: ΀ο β€œΞΞ± ΡπιτρέπΡται στις σΡλίδΡς Ξ½Ξ± Ρπιλέγουν τα δικά τους Ο‡ΟΟŽΞΌΞ±Ο„Ξ±β€ Ρίναι απΡνΡργοποιημένο στον πΡριηγητΞ. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/en-GB/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/en-GB/viewer.properties new file mode 100755 index 00000000..a3e0bab2 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/en-GB/viewer.properties @@ -0,0 +1,184 @@ +# 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 Page +previous_label=Previous +next.title=Next Page +next_label=Next + +# 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=of {{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}} of {{pagesCount}}) + +zoom_out.title=Zoom Out +zoom_out_label=Zoom Out +zoom_in.title=Zoom In +zoom_in_label=Zoom In +zoom.title=Zoom +presentation_mode.title=Switch to Presentation Mode +presentation_mode_label=Presentation Mode +open_file.title=Open File +open_file_label=Open +print.title=Print +print_label=Print +download.title=Download +download_label=Download +bookmark.title=Current view (copy or open in new window) +bookmark_label=Current View + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=Text Selection Tool +cursor_hand_tool.title=Enable Hand Tool +cursor_hand_tool_label=Hand Tool + +# Document properties dialog box +document_properties.title=Document Properties… +document_properties_label=Document Properties… +document_properties_file_name=File name: +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=Subject: +document_properties_keywords=Keywords: +document_properties_creation_date=Creation Date: +document_properties_modification_date=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=Creator: +document_properties_producer=PDF Producer: +document_properties_version=PDF Version: +document_properties_page_count=Page Count: +document_properties_close=Close + +print_progress_message=Preparing document for printing… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Cancel + +# 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=Show Thumbnails +thumbs_label=Thumbnails +findbar.title=Find in Document +findbar_label=Find + +# 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 of Page {{page}} + +# Find panel button title and messages +find_input.title=Find +find_input.placeholder=Find in document… +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_reached_top=Reached top of document, continued from bottom +find_reached_bottom=Reached end of document, continued from top +find_not_found=Phrase not found + +# Error panel labels +error_more_info=More Information +error_less_info=Less Information +error_close=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: {{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=An error occurred while rendering 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_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. +unexpected_response_error=Unexpected server response. + +# 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=Enter the password to open this PDF file. +password_invalid=Invalid password. Please try again. +password_ok=OK +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. +document_colors_not_allowed=PDF documents are not allowed to use their own colours: β€œAllow pages to choose their own colours” is deactivated in the browser. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/en-US/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/en-US/viewer.properties new file mode 100755 index 00000000..f1c50547 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/en-US/viewer.properties @@ -0,0 +1,184 @@ +# 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 Page +previous_label=Previous +next.title=Next Page +next_label=Next + +# 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=of {{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}} of {{pagesCount}}) + +zoom_out.title=Zoom Out +zoom_out_label=Zoom Out +zoom_in.title=Zoom In +zoom_in_label=Zoom In +zoom.title=Zoom +presentation_mode.title=Switch to Presentation Mode +presentation_mode_label=Presentation Mode +open_file.title=Open File +open_file_label=Open +print.title=Print +print_label=Print +download.title=Download +download_label=Download +bookmark.title=Current view (copy or open in new window) +bookmark_label=Current View + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=Text Selection Tool +cursor_hand_tool.title=Enable Hand Tool +cursor_hand_tool_label=Hand Tool + +# Document properties dialog box +document_properties.title=Document Properties… +document_properties_label=Document Properties… +document_properties_file_name=File name: +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=Subject: +document_properties_keywords=Keywords: +document_properties_creation_date=Creation Date: +document_properties_modification_date=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=Creator: +document_properties_producer=PDF Producer: +document_properties_version=PDF Version: +document_properties_page_count=Page Count: +document_properties_close=Close + +print_progress_message=Preparing document for printing… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Cancel + +# 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=Show Thumbnails +thumbs_label=Thumbnails +findbar.title=Find in Document +findbar_label=Find + +# 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 of Page {{page}} + +# Find panel button title and messages +find_input.title=Find +find_input.placeholder=Find in document… +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_reached_top=Reached top of document, continued from bottom +find_reached_bottom=Reached end of document, continued from top +find_not_found=Phrase not found + +# Error panel labels +error_more_info=More Information +error_less_info=Less Information +error_close=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: {{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=An error occurred while rendering 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_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. +unexpected_response_error=Unexpected server response. + +# 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=Enter the password to open this PDF file. +password_invalid=Invalid password. Please try again. +password_ok=OK +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. +document_colors_not_allowed=PDF documents are not allowed to use their own colors: β€œAllow pages to choose their own colors” is deactivated in the browser. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/en-ZA/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/en-ZA/viewer.properties new file mode 100755 index 00000000..832d5586 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/en-ZA/viewer.properties @@ -0,0 +1,170 @@ +# 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 Page +previous_label=Previous +next.title=Next Page +next_label=Next + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=of {{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. + +zoom_out.title=Zoom Out +zoom_out_label=Zoom Out +zoom_in.title=Zoom In +zoom_in_label=Zoom In +zoom.title=Zoom +presentation_mode.title=Switch to Presentation Mode +presentation_mode_label=Presentation Mode +open_file.title=Open File +open_file_label=Open +print.title=Print +print_label=Print +download.title=Download +download_label=Download +bookmark.title=Current view (copy or open in new window) +bookmark_label=Current View + +# Secondary toolbar and context menu +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 + + +# Document properties dialog box +document_properties.title=Document Properties… +document_properties_label=Document Properties… +document_properties_file_name=File name: +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=Subject: +document_properties_keywords=Keywords: +document_properties_creation_date=Creation Date: +document_properties_modification_date=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=Creator: +document_properties_producer=PDF Producer: +document_properties_version=PDF Version: +document_properties_page_count=Page Count: +document_properties_close=Close + +# 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) +toggle_sidebar.title=Toggle Sidebar +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=Show Thumbnails +thumbs_label=Thumbnails +findbar.title=Find in Document + +# 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 of Page {{page}} + +# Find panel button title and messages +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_reached_top=Reached top of document, continued from bottom +find_reached_bottom=Reached end of document, continued from top +find_not_found=Phrase not found + +# Error panel labels +error_more_info=More Information +error_less_info=Less Information +error_close=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: {{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=An error occurred while rendering 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_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. +unexpected_response_error=Unexpected server response. + +# 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=Enter the password to open this PDF file. +password_invalid=Invalid password. Please try again. +password_ok=OK + +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. +document_colors_not_allowed=PDF documents are not allowed to use their own colours: β€œAllow pages to choose their own colours” is deactivated in the browser. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/eo/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/eo/viewer.properties new file mode 100755 index 00000000..d4bbd7a7 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/eo/viewer.properties @@ -0,0 +1,184 @@ +# 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=AntaΕ­a paĝo +previous_label=MalantaΕ­en +next.title=Venonta paĝo +next_label=AntaΕ­en + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Paĝo +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=el {{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}} el {{pagesCount}}) + +zoom_out.title=Malpligrandigi +zoom_out_label=Malpligrandigi +zoom_in.title=Pligrandigi +zoom_in_label=Pligrandigi +zoom.title=Pligrandigilo +presentation_mode.title=Iri al prezenta reĝimo +presentation_mode_label=Prezenta reĝimo +open_file.title=Malfermi dosieron +open_file_label=Malfermi +print.title=Presi +print_label=Presi +download.title=Elŝuti +download_label=Elŝuti +bookmark.title=Nuna vido (kopii aΕ­ malfermi en nova fenestro) +bookmark_label=Nuna vido + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=Teksta elektilo +cursor_hand_tool.title=Aktivigi ilon de mano +cursor_hand_tool_label=Ilo de mano + +# Document properties dialog box +document_properties.title=Atributoj de dokumento… +document_properties_label=Atributoj de dokumento… +document_properties_file_name=Nomo de dosiero: +document_properties_file_size=Grado de dosiero: +# 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}} KO ({{size_b}} oktetoj) +# 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}} MO ({{size_b}} oktetoj) +document_properties_title=Titolo: +document_properties_author=AΕ­toro: +document_properties_subject=Temo: +document_properties_keywords=Ŝlosilvorto: +document_properties_creation_date=Dato de kreado: +document_properties_modification_date=Dato de modifo: +# 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=Kreinto: +document_properties_producer=Produktinto de PDF: +document_properties_version=Versio de PDF: +document_properties_page_count=Nombro de paĝoj: +document_properties_close=Fermi + +print_progress_message=Preparo de dokumento por presi ĝin … +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Nuligi + +# 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=Montri/kaŝi flankan strion +toggle_sidebar_notification.title=Montri/kaŝi flankan strion (la dokumento enhavas konturon/aneksaΔ΅ojn) +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 +thumbs.title=Montri miniaturojn +thumbs_label=Miniaturoj +findbar.title=SerΔ‰i en dokumento +findbar_label=SerΔ‰i + +# 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=Paĝo {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Miniaturo de paĝo {{page}} + +# Find panel button title and messages +find_input.title=SerΔ‰i +find_input.placeholder=SerΔ‰i en dokumento… +find_previous.title=SerΔ‰i la antaΕ­an aperon de la frazo +find_previous_label=MalantaΕ­en +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_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 +find_not_found=Frazo ne trovita + +# Error panel labels +error_more_info=Pli da informo +error_less_info=Mapli da informo +error_close=Fermi +# 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=Mesaĝo: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Stako: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Dosiero: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Linio: {{line}} +rendering_error=Okazis eraro dum la montrado de la paĝo. + +# Predefined zoom values +page_scale_width=Larĝo de paĝo +page_scale_fit=Adapti paĝon +page_scale_auto=AΕ­tomata skalo +page_scale_actual=Reala gandeco +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Eraro +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. +unexpected_response_error=Neatendita respondo de servilo. + +# 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=[Prinoto: {{type}}] +password_label=Tajpu pasvorton por malfermi tiun Δ‰i dosieron PDF. +password_invalid=Nevalida pasvorto. Bonvolu provi denove. +password_ok=Akcepti +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. +document_colors_not_allowed=PDF dokumentoj ne rajtas uzi siajn proprajn kolorojn: 'Permesi al paĝoj uzi siajn proprajn kolorojn' ne estas aktiva en la retumilo. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/es-AR/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/es-AR/viewer.properties new file mode 100755 index 00000000..970de09f --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/es-AR/viewer.properties @@ -0,0 +1,184 @@ +# 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 anterior +previous_label=Anterior +next.title=PΓ‘gina siguiente +next_label=Siguiente + +# 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=Alejar +zoom_out_label=Alejar +zoom_in.title=Acercar +zoom_in_label=Acercar +zoom.title=Zoom +presentation_mode.title=Cambiar a modo presentaciΓ³n +presentation_mode_label=Modo presentaciΓ³n +open_file.title=Abrir archivo +open_file_label=Abrir +print.title=Imprimir +print_label=Imprimir +download.title=Descargar +download_label=Descargar +bookmark.title=Vista actual (copiar o abrir en nueva ventana) +bookmark_label=Vista actual + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=Herramienta de selecciΓ³n de texto +cursor_hand_tool.title=Habilitar herramienta mano +cursor_hand_tool_label=Herramienta mano + +# Document properties dialog box +document_properties.title=Propiedades del documento… +document_properties_label=Propiedades del documento… +document_properties_file_name=Nombre de archivo: +document_properties_file_size=TamaΓ±o de archovo: +# 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Γ­tulo: +document_properties_author=Autor: +document_properties_subject=Asunto: +document_properties_keywords=Palabras clave: +document_properties_creation_date=Fecha de creaciΓ³n: +document_properties_modification_date=Fecha 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=PDF Productor: +document_properties_version=VersiΓ³n de PDF: +document_properties_page_count=Cantidad de pΓ‘ginas: +document_properties_close=Cerrar + +print_progress_message=Preparando documento para imprimir… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +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 barra lateral +toggle_sidebar_notification.title=Intercambiar barra lateral (el documento contiene esquema/adjuntos) +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 +thumbs.title=Mostrar miniaturas +thumbs_label=Miniaturas +findbar.title=Buscar en documento +findbar_label=Buscar + +# 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 pΓ‘gina {{page}} + +# Find panel button title and messages +find_input.title=Buscar +find_input.placeholder=Buscar en documento… +find_previous.title=Buscar la apariciΓ³n anterior de la frase +find_previous_label=Anterior +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_reached_top=Inicio de documento alcanzado, continuando desde abajo +find_reached_bottom=Fin de documento alcanzando, continuando desde arriba +find_not_found=Frase no encontrada + +# Error panel labels +error_more_info=MΓ‘s informaciΓ³n +error_less_info=Menos informaciΓ³n +error_close=Cerrar +# 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=Mensaje: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Pila: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Archivo: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=LΓ­nea: {{line}} +rendering_error=OcurriΓ³ un error al dibujar la pΓ‘gina. + +# Predefined zoom values +page_scale_width=Ancho de pΓ‘gina +page_scale_fit=Ajustar pΓ‘gina +page_scale_auto=Zoom automΓ‘tico +page_scale_actual=TamaΓ±o 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_error=OcurriΓ³ un error al cargar el PDF. +invalid_file_error=Archivo PDF no vΓ‘lido o cocrrupto. +missing_file_error=Archivo PDF faltante. +unexpected_response_error=Respuesta del servidor inesperada. + +# 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}} AnotaciΓ³n] +password_label=Ingrese la contraseΓ±a para abrir este archivo PDF +password_invalid=ContraseΓ±a invΓ‘lida. Intente nuevamente. +password_ok=Aceptar +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. +document_colors_not_allowed=Los documentos PDF no tienen permitido usar sus propios colores: 'Permitir a las pΓ‘ginas elegir sus propios colores' estΓ‘ desactivado en el navegador. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/es-CL/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/es-CL/viewer.properties new file mode 100755 index 00000000..3bafb7fd --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/es-CL/viewer.properties @@ -0,0 +1,184 @@ +# 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 anterior +previous_label=Anterior +next.title=PΓ‘gina siguiente +next_label=Siguiente + +# 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=Alejar +zoom_out_label=Alejar +zoom_in.title=Acercar +zoom_in_label=Acercar +zoom.title=AmpliaciΓ³n +presentation_mode.title=Cambiar al modo de presentaciΓ³n +presentation_mode_label=Modo de presentaciΓ³n +open_file.title=Abrir archivo +open_file_label=Abrir +print.title=Imprimir +print_label=Imprimir +download.title=Descargar +download_label=Descargar +bookmark.title=Vista actual (copiar o abrir en nueva ventana) +bookmark_label=Vista actual + +# Secondary toolbar and context menu +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 +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 + +# Document properties dialog box +document_properties.title=Propiedades del documento… +document_properties_label=Propiedades del documento… +document_properties_file_name=Nombre de archivo: +document_properties_file_size=TamaΓ±o del archivo: +# 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Γ­tulo: +document_properties_author=Autor: +document_properties_subject=Asunto: +document_properties_keywords=Palabras clave: +document_properties_creation_date=Fecha de creaciΓ³n: +document_properties_modification_date=Fecha 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 del PDF: +document_properties_version=VersiΓ³n de PDF: +document_properties_page_count=Cantidad de pΓ‘ginas: +document_properties_close=Cerrar + +print_progress_message=Preparando documento para impresiΓ³n… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +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=Barra lateral +toggle_sidebar_notification.title=Cambiar barra lateral (Γ­ndice de contenidos del documento/adjuntos) +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 +thumbs.title=Mostrar miniaturas +thumbs_label=Miniaturas +findbar.title=Buscar en el documento +findbar_label=Buscar + +# 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 la pΓ‘gina {{page}} + +# Find panel button title and messages +find_input.title=Encontrar +find_input.placeholder=Encontrar en el documento… +find_previous.title=Buscar la apariciΓ³n anterior de la frase +find_previous_label=Previo +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_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 +find_not_found=Frase no encontrada + +# Error panel labels +error_more_info=MΓ‘s informaciΓ³n +error_less_info=Menos informaciΓ³n +error_close=Cerrar +# 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}} (compilaciΓ³n: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Mensaje: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Pila: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Archivo: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=LΓ­nea: {{line}} +rendering_error=Ha ocurrido un error al renderizar la pΓ‘gina. + +# Predefined zoom values +page_scale_width=Ancho de pΓ‘gina +page_scale_fit=Ajuste de pΓ‘gina +page_scale_auto=Aumento automΓ‘tico +page_scale_actual=TamaΓ±o 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=Error +loading_error=Ha ocurrido un error al cargar el PDF. +invalid_file_error=Archivo PDF invΓ‘lido o corrupto. +missing_file_error=Falta el archivo PDF. +unexpected_response_error=Respuesta del servidor inesperada. + +# 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}} AnotaciΓ³n] +password_label=Ingrese la contraseΓ±a para abrir este archivo PDF. +password_invalid=ContraseΓ±a invΓ‘lida. Por favor, vuelve a intentarlo. +password_ok=Aceptar +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. +document_colors_not_allowed=Los documentos PDF no tienen permitido usar sus propios colores: 'Permitir a las pΓ‘ginas elegir sus propios colores' estΓ‘ desactivado en el navegador. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/es-ES/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/es-ES/viewer.properties new file mode 100755 index 00000000..9505b3af --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/es-ES/viewer.properties @@ -0,0 +1,117 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +previous.title = PΓ‘gina anterior +previous_label = Anterior +next.title = PΓ‘gina siguiente +next_label = Siguiente +page.title = PΓ‘gina +of_pages = de {{pagesCount}} +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Γ±o +presentation_mode.title = Cambiar al modo presentaciΓ³n +presentation_mode_label = Modo presentaciΓ³n +open_file.title = Abrir archivo +open_file_label = Abrir +print.title = Imprimir +print_label = Imprimir +download.title = Descargar +download_label = Descargar +bookmark.title = Vista actual (copiar o abrir en una nueva ventana) +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 +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 +document_properties.title = Propiedades del documento… +document_properties_label = Propiedades del documento… +document_properties_file_name = Nombre de archivo: +document_properties_file_size = TamaΓ±o de archivo: +document_properties_kb = {{size_kb}} KB ({{size_b}} bytes) +document_properties_mb = {{size_mb}} MB ({{size_b}} bytes) +document_properties_title = TΓ­tulo: +document_properties_author = Autor: +document_properties_subject = Asunto: +document_properties_keywords = Palabras clave: +document_properties_creation_date = Fecha de creaciΓ³n: +document_properties_modification_date = Fecha de modificaciΓ³n: +document_properties_date_string = {{date}}, {{time}} +document_properties_creator = Creador: +document_properties_producer = Productor PDF: +document_properties_version = VersiΓ³n PDF: +document_properties_page_count = NΓΊmero de pΓ‘ginas: +document_properties_close = Cerrar +print_progress_message = Preparando documento para impresiΓ³n… +print_progress_percent = {{progress}}% +print_progress_close = Cancelar +toggle_sidebar.title = Cambiar barra lateral +toggle_sidebar_notification.title = Alternar panel lateral (el documento contiene un esquema o adjuntos) +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 +thumbs.title = Mostrar miniaturas +thumbs_label = Miniaturas +findbar.title = Buscar en el documento +findbar_label = Buscar +thumb_page_title = PΓ‘gina {{page}} +thumb_page_canvas = Miniatura de la pΓ‘gina {{page}} +find_input.title = Buscar +find_input.placeholder = Buscar en el documento… +find_previous.title = Encontrar la anterior apariciΓ³n de la frase +find_previous_label = Anterior +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_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 +find_not_found = Frase no encontrada +error_more_info = MΓ‘s informaciΓ³n +error_less_info = Menos informaciΓ³n +error_close = Cerrar +error_version_info = PDF.js v{{version}} (build: {{build}}) +error_message = Mensaje: {{message}} +error_stack = Pila: {{stack}} +error_file = Archivo: {{file}} +error_line = LΓ­nea: {{line}} +rendering_error = OcurriΓ³ un error al renderizar la pΓ‘gina. +page_scale_width = Anchura de la pΓ‘gina +page_scale_fit = Ajuste de la pΓ‘gina +page_scale_auto = TamaΓ±o automΓ‘tico +page_scale_actual = TamaΓ±o real +page_scale_percent = {{scale}}% +loading_error_indicator = Error +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. +unexpected_response_error = Respuesta inesperada del servidor. +text_annotation_type.alt = [AnotaciΓ³n {{type}}] +password_label = Introduzca la contraseΓ±a para abrir este archivo PDF. +password_invalid = ContraseΓ±a no vΓ‘lida. Vuelva a intentarlo. +password_ok = Aceptar +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. +document_colors_not_allowed = Los documentos PDF no tienen permitido usar sus propios colores: 'Permitir a las pΓ‘ginas elegir sus propios colores' estΓ‘ desactivado en el navegador. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/es-MX/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/es-MX/viewer.properties new file mode 100755 index 00000000..6d36e926 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/es-MX/viewer.properties @@ -0,0 +1,184 @@ +# 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 anterior +previous_label=Anterior +next.title=PΓ‘gina siguiente +next_label=Siguiente + +# 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=Reducir +zoom_out_label=Reducir +zoom_in.title=Aumentar +zoom_in_label=Aumentar +zoom.title=Zoom +presentation_mode.title=Cambiar al modo presentaciΓ³n +presentation_mode_label=Modo presentaciΓ³n +open_file.title=Abrir archivo +open_file_label=Abrir +print.title=Imprimir +print_label=Imprimir +download.title=Descargar +download_label=Descargar +bookmark.title=Vista actual (copiar o abrir en una nueva ventana) +bookmark_label=Vista actual + +# Secondary toolbar and context menu +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 +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 + +# Document properties dialog box +document_properties.title=Propiedades del documento… +document_properties_label=Propiedades del documento… +document_properties_file_name=Nombre del archivo: +document_properties_file_size=TamaΓ±o del archivo: +# 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Γ­tulo: +document_properties_author=Autor: +document_properties_subject=Asunto: +document_properties_keywords=Palabras claves: +document_properties_creation_date=Fecha de creaciΓ³n: +document_properties_modification_date=Fecha 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_page_count=NΓΊmero de pΓ‘ginas: +document_properties_close=Cerrar + +print_progress_message=Preparando documento para impresiΓ³n… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +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=Cambiar barra lateral +toggle_sidebar_notification.title=Cambiar barra lateral (Γ­ndice de contenidos del documento/adjuntos) +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 +thumbs.title=Mostrar miniaturas +thumbs_label=Miniaturas +findbar.title=Buscar en el documento +findbar_label=Buscar + +# 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 la pΓ‘gina {{page}} + +# Find panel button title and messages +find_input.title=Buscar +find_input.placeholder=Buscar en el documento… +find_previous.title=Ir a la anterior frase encontrada +find_previous_label=Anterior +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_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 +find_not_found=No se encontrΓ³ la frase + +# Error panel labels +error_more_info=MΓ‘s informaciΓ³n +error_less_info=Menos informaciΓ³n +error_close=Cerrar +# 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=Mensaje: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Pila: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Archivo: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=LΓ­nea: {{line}} +rendering_error=Un error ocurriΓ³ al renderizar la pΓ‘gina. + +# Predefined zoom values +page_scale_width=Ancho de pΓ‘gina +page_scale_fit=Ajustar pΓ‘gina +page_scale_auto=Zoom automΓ‘tico +page_scale_actual=TamaΓ±o 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_error=Un error ocurriΓ³ al cargar el PDF. +invalid_file_error=Archivo PDF invalido o daΓ±ado. +missing_file_error=Archivo PDF no encontrado. +unexpected_response_error=Respuesta inesperada del servidor. + +# 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}} anotaciΓ³n] +password_label=Ingresa la contraseΓ±a para abrir este archivo PDF. +password_invalid=ContraseΓ±a invΓ‘lida. Por favor intenta de nuevo. +password_ok=Aceptar +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. +document_colors_not_allowed=Los documentos PDF no tienen permiso de usar sus propios colores: 'Permitir que las pΓ‘ginas elijan sus propios colores' esta desactivada en el navegador. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/et/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/et/viewer.properties new file mode 100755 index 00000000..46017845 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/et/viewer.properties @@ -0,0 +1,180 @@ +# 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=Eelmine lehekΓΌlg +previous_label=Eelmine +next.title=JΓ€rgmine lehekΓΌlg +next_label=JΓ€rgmine + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Leht +# 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=VΓ€henda +zoom_out_label=VΓ€henda +zoom_in.title=Suurenda +zoom_in_label=Suurenda +zoom.title=Suurendamine +presentation_mode.title=LΓΌlitu esitlusreΕΎiimi +presentation_mode_label=EsitlusreΕΎiim +open_file.title=Ava fail +open_file_label=Ava +print.title=Prindi +print_label=Prindi +download.title=Laadi alla +download_label=Laadi alla +bookmark.title=Praegune vaade (kopeeri vΓ΅i ava uues aknas) +bookmark_label=Praegune vaade + +# Secondary toolbar and context menu +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 + + +# Document properties dialog box +document_properties.title=Dokumendi omadused… +document_properties_label=Dokumendi omadused… +document_properties_file_name=Faili nimi: +document_properties_file_size=Faili suurus: +# 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}} KiB ({{size_b}} baiti) +# 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}} MiB ({{size_b}} baiti) +document_properties_title=Pealkiri: +document_properties_author=Autor: +document_properties_subject=Teema: +document_properties_keywords=MΓ€rksΓ΅nad: +document_properties_creation_date=Loodud: +document_properties_modification_date=Muudetud: +# 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=Looja: +document_properties_producer=Generaator: +document_properties_version=Generaatori versioon: +document_properties_page_count=LehekΓΌlgi: +document_properties_close=Sulge + +print_progress_message=Dokumendi ettevalmistamine printimiseks… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Loobu + +# 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=NΓ€ita kΓΌlgriba +toggle_sidebar_notification.title=NΓ€ita kΓΌlgriba (dokument sisaldab sisukorda/manuseid) +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 +thumbs.title=NΓ€ita pisipilte +thumbs_label=Pisipildid +findbar.title=Otsi dokumendist +findbar_label=Otsi + +# 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}}. lehekΓΌlg +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas={{page}}. lehekΓΌlje pisipilt + +# Find panel button title and messages +find_input.title=Otsi +find_input.placeholder=Otsi dokumendist… +find_previous.title=Otsi fraasi eelmine esinemiskoht +find_previous_label=Eelmine +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_reached_top=JΓ΅uti dokumendi algusesse, jΓ€tkati lΓ΅pust +find_reached_bottom=JΓ΅uti dokumendi lΓ΅ppu, jΓ€tkati algusest +find_not_found=Fraasi ei leitud + +# Error panel labels +error_more_info=Rohkem teavet +error_less_info=VΓ€hem teavet +error_close=Sulge +# 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=Teade: {{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=Fail: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Rida: {{line}} +rendering_error=Lehe renderdamisel esines viga. + +# Predefined zoom values +page_scale_width=Mahuta laiusele +page_scale_fit=Mahuta lehekΓΌljele +page_scale_auto=Automaatne suurendamine +page_scale_actual=Tegelik suurus +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Viga +loading_error=PDFi laadimisel esines viga. +invalid_file_error=Vigane vΓ΅i rikutud PDF-fail. +missing_file_error=PDF-fail puudub. +unexpected_response_error=Ootamatu vastus serverilt. + +# 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=PDF-faili avamiseks sisesta parool. +password_invalid=Vigane parool. Palun proovi uuesti. +password_ok=Sobib +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. +document_colors_not_allowed=PDF-dokumentidel pole oma vΓ€rvide kasutamine lubatud: β€œVeebilehtedel on lubatud kasutada oma vΓ€rve” on brauseris deaktiveeritud. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/eu/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/eu/viewer.properties new file mode 100755 index 00000000..ac1216f0 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/eu/viewer.properties @@ -0,0 +1,184 @@ +# 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=Aurreko orria +previous_label=Aurrekoa +next.title=Hurrengo orria +next_label=Hurrengoa + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Orria +# 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={{pagesCount}}/{{pageNumber}} + +zoom_out.title=Urrundu zooma +zoom_out_label=Urrundu zooma +zoom_in.title=Gerturatu zooma +zoom_in_label=Gerturatu zooma +zoom.title=Zooma +presentation_mode.title=Aldatu aurkezpen modura +presentation_mode_label=Arkezpen modua +open_file.title=Ireki fitxategia +open_file_label=Ireki +print.title=Inprimatu +print_label=Inprimatu +download.title=Deskargatu +download_label=Deskargatu +bookmark.title=Uneko ikuspegia (kopiatu edo ireki leiho berrian) +bookmark_label=Uneko ikuspegia + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=Testuaren hautapen tresna +cursor_hand_tool.title=Gaitu eskuaren tresna +cursor_hand_tool_label=Eskuaren tresna + +# Document properties dialog box +document_properties.title=Dokumentuaren propietateak… +document_properties_label=Dokumentuaren propietateak… +document_properties_file_name=Fitxategi-izena: +document_properties_file_size=Fitxategiaren tamaina: +# 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}} byte) +# 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}} byte) +document_properties_title=Izenburua: +document_properties_author=Egilea: +document_properties_subject=Gaia: +document_properties_keywords=Gako-hitzak: +document_properties_creation_date=Sortze-data: +document_properties_modification_date=Aldatze-data: +# 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=Sortzailea: +document_properties_producer=PDFaren ekoizlea: +document_properties_version=PDF bertsioa: +document_properties_page_count=Orrialde kopurua: +document_properties_close=Itxi + +print_progress_message=Dokumentua inprimatzeko prestatzen… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent=%{{progress}} +print_progress_close=Utzi + +# 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=Txandakatu alboko barra +toggle_sidebar_notification.title=Txandakatu alboko barra (dokumentuak eskema/eranskinak 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 +thumbs.title=Erakutsi koadro txikiak +thumbs_label=Koadro txikiak +findbar.title=Bilatu dokumentuan +findbar_label=Bilatu + +# 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}}. orria +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas={{page}}. orriaren koadro txikia + +# Find panel button title and messages +find_input.title=Bilatu +find_input.placeholder=Bilatu dokumentuan… +find_previous.title=Bilatu esaldiaren aurreko parekatzea +find_previous_label=Aurrekoa +find_next.title=Bilatu esaldiaren hurrengo parekatzea +find_next_label=Hurrengoa +find_highlight=Nabarmendu guztia +find_match_case_label=Bat etorri maiuskulekin/minuskulekin +find_reached_top=Dokumentuaren hasierara heldu da, bukaeratik jarraitzen +find_reached_bottom=Dokumentuaren bukaerara heldu da, hasieratik jarraitzen +find_not_found=Esaldia ez da aurkitu + +# Error panel labels +error_more_info=Informazio gehiago +error_less_info=Informazio gutxiago +error_close=Itxi +# 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}} (eraikuntza: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Mezua: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Pila: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Fitxategia: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Lerroa: {{line}} +rendering_error=Errorea gertatu da orria errendatzean. + +# Predefined zoom values +page_scale_width=Orriaren zabalera +page_scale_fit=Doitu orrira +page_scale_auto=Zoom automatikoa +page_scale_actual=Benetako tamaina +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent=%{{scale}} + +# Loading indicator messages +loading_error_indicator=Errorea +loading_error=Errorea gertatu da PDFa kargatzean. +invalid_file_error=PDF fitxategi baliogabe edo hondatua. +missing_file_error=PDF fitxategia falta da. +unexpected_response_error=Espero gabeko zerbitzariaren erantzuna. + +# 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}} ohartarazpena] +password_label=Idatzi PDF fitxategi hau irekitzeko pasahitza. +password_invalid=Pasahitz baliogabea. Saiatu berriro mesedez. +password_ok=Ados +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. +document_colors_not_allowed=PDF dokumentuek ez dute beraien koloreak erabiltzeko baimenik: 'Baimendu orriak beraien letra-tipoak aukeratzea' desaktibatuta dago nabigatzailean. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/fa/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/fa/viewer.properties new file mode 100755 index 00000000..577a4e14 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/fa/viewer.properties @@ -0,0 +1,184 @@ +# 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=برو ΫŒΩ‡ Ψ§ΩˆΩ„ΫŒΩ† ءفحه +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_label=ابزارِ Ψ§Ω†ΨͺΨابِ Ω…ΨͺΩ† +cursor_hand_tool.title=فعال Ϊ©Ψ±Ψ―Ω† ابزارِ Ψ―Ψ³Ψͺ +cursor_hand_tool_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_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_notification.title=Ψͺغییر وآعیΨͺ Ω†ΩˆΨ§Ψ± Ϊ©Ω†Ψ§Ψ±ΫŒ (Ψ³Ω†Ψ― حاوی Ψ·Ψ±Ψ­/پیوسΨͺ Ψ§Ψ³Ψͺ) +toggle_sidebar_label=ΨͺΨΊΫŒΫŒΨ±Ψ­Ψ§Ω„Ψͺ Ω†ΩˆΨ§Ψ±Ϊ©Ω†Ψ§Ψ±ΫŒ +document_outline.title=Ω†Ω…Ψ§ΫŒΨ΄ رئوس Ω…Ψ·Ψ§Ω„Ψ¨ Ω…Ψ―Ψ§Ψ±Ϊ©(برای Ψ¨Ψ§Ψ²Ψ΄Ψ―Ω†/Ψ¬Ω…ΨΉ Ψ΄Ψ―Ω† Ω‡Ω…Ω‡ Ω…ΩˆΨ§Ψ±Ψ― دوبار Ϊ©Ω„ΫŒΪ© Ϊ©Ω†ΫŒΨ―) +document_outline_label=Ψ·Ψ±Ψ­ Ω†ΩˆΨ΄ΨͺΨ§Ψ± +attachments.title=Ω†Ω…Ψ§ΫŒΨ΄ پیوسΨͺβ€ŒΩ‡Ψ§ +attachments_label=پیوسΨͺβ€ŒΩ‡Ψ§ +thumbs.title=Ω†Ω…Ψ§ΫŒΨ΄ Ψͺءاویر Ψ¨Ω†Ψ―Ψ§Ω†Ϊ―Ψ΄Ψͺی +thumbs_label=Ψͺءاویر Ψ¨Ω†Ψ―Ψ§Ω†Ϊ―Ψ΄Ψͺی +findbar.title=Ψ¬Ψ³Ψͺجو Ψ―Ψ± Ψ³Ω†Ψ― +findbar_label=پیدا Ϊ©Ψ±Ψ―Ω† + +# 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_reached_top=Ψ¨Ω‡ Ψ¨Ψ§Ω„Ψ§ΫŒ ءفحه Ψ±Ψ³ΫŒΨ―ΫŒΩ…ΨŒ Ψ§Ψ² ΩΎΨ§ΫŒΫŒΩ† Ψ§Ψ―Ψ§Ω…Ω‡ Ω…ΫŒβ€ŒΨ―Ω‡ΫŒΩ… +find_reached_bottom=Ψ¨Ω‡ Ψ’ΨΨ± ءفحه Ψ±Ψ³ΫŒΨ―ΫŒΩ…ΨŒ Ψ§Ψ² Ψ¨Ψ§Ω„Ψ§ Ψ§Ψ―Ψ§Ω…Ω‡ Ω…ΫŒβ€ŒΨ―Ω‡ΫŒΩ… +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 ΩˆΨ±Ϊ˜Ω†{{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_error_indicator=ΨΨ·Ψ§ +loading_error=Ω‡Ω†Ϊ―Ψ§Ω… بارگیری ΩΎΨ±ΩˆΩ†Ψ―Ω‡ PDF Ψطایی Ψ±Ψ Ψ―Ψ§Ψ―. +invalid_file_error=ΩΎΨ±ΩˆΩ†Ψ―Ω‡ PDF Ω†Ψ§Ω…ΨΉΨͺΨ¨Ψ± ΫŒΨ§Ω…ΨΉΫŒΩˆΨ¨ Ω…ΫŒβ€ŒΨ¨Ψ§Ψ΄Ψ―. +missing_file_error=ΩΎΨ±ΩˆΩ†Ψ―Ω‡ PDF یافΨͺ Ω†Ψ΄Ψ―. +unexpected_response_error=ΩΎΨ§Ψ³Ψ ΩΎΫŒΨ΄ Ψ¨ΫŒΩ†ΫŒ Ω†Ψ΄Ψ―Ω‡ سرور + +# 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=Ψ¬Ω‡Ψͺ Ψ¨Ψ§Ψ² Ϊ©Ψ±Ψ―Ω† ΩΎΨ±ΩˆΩ†Ψ―Ω‡ PDF Ϊ―Ψ°Ψ±ΩˆΨ§Ϊ˜Ω‡ Ψ±Ψ§ وارد Ω†Ω…Ψ§Ψ¦ΫŒΨ―. +password_invalid=Ϊ―Ψ°Ψ±ΩˆΨ§Ϊ˜Ω‡ Ω†Ψ§Ω…ΨΉΨͺΨ¨Ψ±. لطفا Ω…Ψ¬Ψ―Ψ―Ψ§ ΨͺΩ„Ψ§Ψ΄ Ϊ©Ω†ΫŒΨ―. +password_ok=Ψͺأیید +password_cancel=Ω„ΨΊΩˆ + +printing_not_supported=Ω‡Ψ΄Ψ―Ψ§Ψ±: Ω‚Ψ§Ψ¨Ω„ΫŒΨͺ Ϊ†Ψ§ΩΎ Ψ¨Ω‡β€ŒΨ·ΩˆΨ± Ϊ©Ψ§Ω…Ω„ Ψ―Ψ± Ψ§ΫŒΩ† Ω…Ψ±ΩˆΨ±Ϊ―Ψ± ΩΎΨ΄ΨͺΫŒΨ¨Ψ§Ω†ΫŒ Ω†Ω…ΫŒβ€ŒΨ΄ΩˆΨ―. +printing_not_ready=Ψ§ΨΨ·Ψ§Ψ±: ΩΎΨ±ΩˆΩ†Ψ―Ω‡ PDF بطور Ϊ©Ψ§Ω…Ω„ بارگیری Ω†Ψ΄Ψ―Ω‡ و Ψ§Ω…Ϊ©Ψ§Ω† Ϊ†Ψ§ΩΎ وجود Ω†Ψ―Ψ§Ψ±Ψ―. +web_fonts_disabled=ΩΩˆΩ†Ψͺ Ω‡Ψ§ΫŒ ΨͺΨ­Ψͺ وب غیر فعال Ψ΄Ψ―Ω‡ Ψ§Ω†Ψ―: Ψ§Ω…Ϊ©Ψ§Ω† Ψ§Ψ³Ψͺفاده Ψ§Ψ² Ω†Ω…Ψ§ΫŒΨ΄ Ψ―Ω‡Ω†Ψ―Ω‡ Ψ―Ψ§ΨΩ„ΫŒ PDF وجود Ω†Ψ―Ψ§Ψ±Ψ―. +document_colors_not_allowed=ΩΨ§ΫŒΩ„Ω‡Ψ§ΫŒ PDF Ψ§Ψ¬Ψ§Ψ²Ω‡ Ω†Ψ―Ψ§Ψ±Ω†Ψ― ΨͺΨ§ Ψ§Ψ² Ψ±Ω†Ϊ―β€ŒΩ‡Ψ§ΫŒ Ψود Ψ§Ψ³Ψͺفاده Ϊ©Ω†Ω†Ψ―: Ϊ―Ψ²ΫŒΩ†Ω‡ Β«Ψ¨Ω‡ ءفحاΨͺ Ψ§Ψ¬Ψ§Ψ²Ω‡ Ψ¨Ψ―Ω‡ ΨͺΨ§ Ψ§Ψ² Ψ±Ω†Ϊ―β€ŒΩ‡Ψ§ΫŒ Ψود Ψ§Ψ³Ψͺفاده Ϊ©Ω†Ω†Ψ―Β» Ψ―Ψ± Ω…Ψ±ΩˆΨ±Ϊ―Ψ± غیر فعال Ψ§Ψ³Ψͺ. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ff/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ff/viewer.properties new file mode 100755 index 00000000..23d3b493 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ff/viewer.properties @@ -0,0 +1,184 @@ +# 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=Hello Ɓennungo +previous_label=ƁennuΙ—o +next.title=Hello faango +next_label=Yeeso + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Hello +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=e nder {{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}} of {{pagesCount}}) + +zoom_out.title=Lonngo WoΙ—Ι—a +zoom_out_label=Lonngo WoΙ—Ι—a +zoom_in.title=Lonngo Ara +zoom_in_label=Lonngo Ara +zoom.title=Lonngo +presentation_mode.title=Faytu to Presentation Mode +presentation_mode_label=Presentation Mode +open_file.title=Uddit Fiilde +open_file_label=Uddit +print.title=Winndito +print_label=Winndito +download.title=Aawto +download_label=Aawto +bookmark.title=Jiytol gonangol (natto walla uddit e henorde) +bookmark_label=Jiytol Gonangol + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=KaΙ“irgel cuΙ“irgel binndi +cursor_hand_tool.title=Hurmin kuutorgal junngo +cursor_hand_tool_label=KaΙ“irgel junngo + +# Document properties dialog box +document_properties.title=KeeroraaΙ—i Winndannde… +document_properties_label=KeeroraaΙ—i Winndannde… +document_properties_file_name=Innde fiilde: +document_properties_file_size=Ɓetol fiilde: +# 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}} bite) +# 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}} bite) +document_properties_title=Tiitoonde: +document_properties_author=BinnduΙ—o: +document_properties_subject=ToΙ“Ι“ere: +document_properties_keywords=Kelmekele jiytirΙ—e: +document_properties_creation_date=Γ‘alnde Sosaa: +document_properties_modification_date=Γ‘alnde Waylaa: +# 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=CosΙ—o: +document_properties_producer=PaggiiΙ—o PDF: +document_properties_version=Yamre PDF: +document_properties_page_count=Limoore Kelle: +document_properties_close=Uddu + +print_progress_message=Nana heboo winnditaade fiilannde… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Haaytu + +# 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=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 +attachments.title=Hollu ƊisanΙ—e +attachments_label=ƊisanΙ—e +thumbs.title=Hollu DooΙ“e +thumbs_label=DooΙ“e +findbar.title=Yiylo e fiilannde +findbar_label=Yiytu + +# 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=Hello {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=DooΙ“re Hello {{page}} + +# Find panel button title and messages +find_input.title=Yiytu +find_input.placeholder=Yiylo nder dokimaa +find_previous.title=Yiylo cilol Ι“ennugol konngol ngol +find_previous_label=ƁennuΙ—o +find_next.title=Yiylo cilol garowol konngol ngol +find_next_label=Yeeso +find_highlight=Jalbin fof +find_match_case_label=JaaΙ“nu darnde +find_reached_top=HeΙ“ii fuΙ—Ι—orde fiilannde, jokku faya les +find_reached_bottom=HeΙ“ii hoore fiilannde, jokku faya les +find_not_found=Konngi njiyataa + +# Error panel labels +error_more_info=Ɓeydu Humpito +error_less_info=Ustu Humpito +error_close=Uddu +# 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=Ɓatakuure: {{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=Fiilde: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Gorol: {{line}} +rendering_error=Juumre waΙ—ii tuma nde yoΕ‹kittoo hello. + +# Predefined zoom values +page_scale_width=Njaajeendi Hello +page_scale_fit=KeΖ΄eendi Hello +page_scale_auto=Loongorde Jaajol +page_scale_actual=Ɓetol Jaati +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# 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. +unexpected_response_error=Jaabtol sarworde tijjinooka. + +# 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}} Siiftannde] +password_label=Naatu finnde ngam uddite ndee fiilde PDF. +password_invalid=Finnde moΖ΄Ζ΄aani. TiiΙ—no eto kadi. +password_ok=OK +password_cancel=Haaytu + +printing_not_supported=Reentino: Winnditagol tammbitaaka no feewi e ndee wanngorde. +printing_not_ready=Reentino: PDF oo loowaaki haa timmi ngam winnditagol. +web_fonts_disabled=Ponte geese ko daaΖ΄aaΙ—e: horiima huutoraade ponte PDF coomtoraaΙ—e. +document_colors_not_allowed=PiilanΙ—e PDF njamiraaka yoo kuutoro goobuuji mum'en keeriiΙ—i: 'Yamir kello yoo kuutoro goobuuki keeriiΙ—i' koko daaΖ΄aa e wanngorde ndee. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/fi/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/fi/viewer.properties new file mode 100755 index 00000000..241d5afa --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/fi/viewer.properties @@ -0,0 +1,184 @@ +# 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=Edellinen sivu +previous_label=Edellinen +next.title=Seuraava sivu +next_label=Seuraava + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Sivu +# 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=Loitonna +zoom_out_label=Loitonna +zoom_in.title=LΓ€hennΓ€ +zoom_in_label=LΓ€hennΓ€ +zoom.title=Suurennus +presentation_mode.title=Siirry esitystilaan +presentation_mode_label=Esitystila +open_file.title=Avaa tiedosto +open_file_label=Avaa +print.title=Tulosta +print_label=Tulosta +download.title=Lataa +download_label=Lataa +bookmark.title=Avoin ikkuna (kopioi tai avaa uuteen ikkunaan) +bookmark_label=Avoin ikkuna + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=TekstinvalintatyΓΆkalu +cursor_hand_tool.title=KΓ€ytΓ€ kΓ€sityΓΆkalua +cursor_hand_tool_label=KΓ€sityΓΆkalu + +# Document properties dialog box +document_properties.title=Dokumentin ominaisuudet… +document_properties_label=Dokumentin ominaisuudet… +document_properties_file_name=Tiedostonimi: +document_properties_file_size=Tiedoston koko: +# 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}} kt ({{size_b}} tavua) +# 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}} Mt ({{size_b}} tavua) +document_properties_title=Otsikko: +document_properties_author=TekijΓ€: +document_properties_subject=Aihe: +document_properties_keywords=Avainsanat: +document_properties_creation_date=LuomispΓ€ivΓ€mÀÀrΓ€: +document_properties_modification_date=MuokkauspΓ€ivΓ€mÀÀrΓ€: +# 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=Luoja: +document_properties_producer=PDF-tuottaja: +document_properties_version=PDF-versio: +document_properties_page_count=Sivujen mÀÀrΓ€: +document_properties_close=Sulje + +print_progress_message=Valmistellaan dokumenttia tulostamista varten… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}Β % +print_progress_close=Peruuta + +# 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=NΓ€ytΓ€/piilota sivupaneeli +toggle_sidebar_notification.title=NΓ€ytΓ€/piilota sivupaneeli (dokumentissa on sisΓ€llys tai liitteitΓ€) +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 +thumbs.title=NΓ€ytΓ€ pienoiskuvat +thumbs_label=Pienoiskuvat +findbar.title=Etsi dokumentista +findbar_label=Etsi + +# 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=Sivu {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Pienoiskuva sivusta {{page}} + +# Find panel button title and messages +find_input.title=Etsi +find_input.placeholder=Etsi dokumentista… +find_previous.title=Etsi hakusanan edellinen osuma +find_previous_label=Edellinen +find_next.title=Etsi hakusanan seuraava osuma +find_next_label=Seuraava +find_highlight=Korosta kaikki +find_match_case_label=Huomioi kirjainkoko +find_reached_top=PÀÀstiin dokumentin alkuun, jatketaan lopusta +find_reached_bottom=PÀÀstiin dokumentin loppuun, continued from top +find_not_found=Hakusanaa ei lΓΆytynyt + +# Error panel labels +error_more_info=LisΓ€tietoja +error_less_info=LisΓ€tietoja +error_close=Sulje +# 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}} (kooste: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Virheilmoitus: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Pino: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Tiedosto: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Rivi: {{line}} +rendering_error=Tapahtui virhe piirrettΓ€essΓ€ sivua. + +# Predefined zoom values +page_scale_width=Sivun leveys +page_scale_fit=Koko sivu +page_scale_auto=Automaattinen suurennus +page_scale_actual=Todellinen koko +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}} % + +# Loading indicator messages +loading_error_indicator=Virhe +loading_error=Tapahtui virhe ladattaessa PDF-tiedostoa. +invalid_file_error=Virheellinen tai vioittunut PDF-tiedosto. +missing_file_error=Puuttuva PDF-tiedosto. +unexpected_response_error=Odottamaton vastaus palvelimelta. + +# 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=Kirjoita PDF-tiedoston salasana. +password_invalid=Virheellinen salasana. YritΓ€ uudestaan. +password_ok=OK +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. +document_colors_not_allowed=PDF-dokumenttien ei ole sallittua kΓ€yttÀÀ omia vΓ€rejÀÀn: Asetusta ”Sivut saavat kΓ€yttÀÀ omia vΓ€rejÀÀn oletusten sijaan” ei ole valittu selaimen asetuksissa. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/fr/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/fr/viewer.properties new file mode 100755 index 00000000..2c0f0ff8 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/fr/viewer.properties @@ -0,0 +1,184 @@ +# 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 prΓ©cΓ©dente +previous_label=PrΓ©cΓ©dent +next.title=Page suivante +next_label=Suivant + +# 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=sur {{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}} sur {{pagesCount}}) + +zoom_out.title=Zoom arriΓ¨re +zoom_out_label=Zoom arriΓ¨re +zoom_in.title=Zoom avant +zoom_in_label=Zoom avant +zoom.title=Zoom +presentation_mode.title=Basculer en mode prΓ©sentation +presentation_mode_label=Mode prΓ©sentation +open_file.title=Ouvrir le fichier +open_file_label=Ouvrir le fichier +print.title=Imprimer +print_label=Imprimer +download.title=TΓ©lΓ©charger +download_label=TΓ©lΓ©charger +bookmark.title=Affichage courant (copier ou ouvrir dans une nouvelle fenΓͺtre) +bookmark_label=Affichage actuel + +# Secondary toolbar and context menu +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 anti-horaire +page_rotate_ccw.label=Rotation anti-horaire +page_rotate_ccw_label=Rotation anti-horaire + +cursor_text_select_tool.title=Activer l’outil de sΓ©lection de texte +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 + +# Document properties dialog box +document_properties.title=PropriΓ©tΓ©s du document… +document_properties_label=PropriΓ©tΓ©s du document… +document_properties_file_name=Nom du fichierΒ : +document_properties_file_size=Taille du fichierΒ : +# 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}}Β Ko ({{size_b}} octets) +# 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}}Β Mo ({{size_b}} octets) +document_properties_title=TitreΒ : +document_properties_author=AuteurΒ : +document_properties_subject=SujetΒ : +document_properties_keywords=Mots-clΓ©sΒ : +document_properties_creation_date=Date de crΓ©ationΒ : +document_properties_modification_date=ModifiΓ© leΒ : +# 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=Créé parΒ : +document_properties_producer=Outil de conversion PDFΒ : +document_properties_version=Version PDFΒ : +document_properties_page_count=Nombre de pagesΒ : +document_properties_close=Fermer + +print_progress_message=PrΓ©paration du document pour l’impression… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}Β % +print_progress_close=Annuler + +# 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=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_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 +thumbs.title=Afficher les vignettes +thumbs_label=Vignettes +findbar.title=Rechercher dans le document +findbar_label=Rechercher + +# 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=Vignette de la page {{page}} + +# Find panel button title and messages +find_input.title=Rechercher +find_input.placeholder=Rechercher dans le document… +find_previous.title=Trouver l’occurrence prΓ©cΓ©dente de la phrase +find_previous_label=PrΓ©cΓ©dent +find_next.title=Trouver la prochaine occurrence de la phrase +find_next_label=Suivant +find_highlight=Tout surligner +find_match_case_label=Respecter la casse +find_reached_top=Haut de la page atteint, poursuite depuis la fin +find_reached_bottom=Bas de la page atteint, poursuite au dΓ©but +find_not_found=Phrase introuvable + +# Error panel labels +error_more_info=Plus d’informations +error_less_info=Moins d’informations +error_close=Fermer +# 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}} (identifiant de compilationΒ : {{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=PileΒ : {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=FichierΒ : {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=LigneΒ : {{line}} +rendering_error=Une erreur s’est produite lors de l’affichage de la page. + +# Predefined zoom values +page_scale_width=Pleine largeur +page_scale_fit=Page entiΓ¨re +page_scale_auto=Zoom automatique +page_scale_actual=Taille rΓ©elle +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}Β % + +# Loading indicator messages +loading_error_indicator=Erreur +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. +unexpected_response_error=RΓ©ponse inattendue du serveur. + +# 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=[Annotation {{type}}] +password_label=Veuillez saisir le mot de passe pour ouvrir ce fichier PDF. +password_invalid=Mot de passe incorrect. Veuillez rΓ©essayer. +password_ok=OK +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. +document_colors_not_allowed=Les documents PDF ne peuvent pas utiliser leurs propres couleursΒ : « Autoriser les pages web Γ  utiliser leurs propres couleursΒ Β» est dΓ©sactivΓ© dans le navigateur. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/fy-NL/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/fy-NL/viewer.properties new file mode 100755 index 00000000..5f041444 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/fy-NL/viewer.properties @@ -0,0 +1,184 @@ +# 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=Foarige side +previous_label=Foarige +next.title=Folgjende side +next_label=Folgjende + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +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}} +# 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}} fan {{pagesCount}}) + +zoom_out.title=Utzoome +zoom_out_label=Utzoome +zoom_in.title=Ynzoome +zoom_in_label=Ynzoome +zoom.title=Zoome +presentation_mode.title=Wikselje nei presintaasjemodus +presentation_mode_label=Presintaasjemodus +open_file.title=BestΓ’n iepenje +open_file_label=Iepenje +print.title=Ofdrukke +print_label=Ofdrukke +download.title=Downloade +download_label=Downloade +bookmark.title=Aktuele finster (kopiearje of iepenje yn nij finster) +bookmark_label=Aktuele finster + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=Tekstseleksjehelpmiddel +cursor_hand_tool.title=HΓ’nhelpmiddel ynskeakelje +cursor_hand_tool_label=HΓ’nhelpmiddel + +# Document properties dialog box +document_properties.title=Dokuminteigenskippen… +document_properties_label=Dokuminteigenskippen… +document_properties_file_name=BestΓ’nsnamme: +document_properties_file_size=BestΓ’nsgrutte: +# 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=Titel: +document_properties_author=Auteur: +document_properties_subject=Underwerp: +document_properties_keywords=Kaaiwurden: +document_properties_creation_date=Oanmaakdatum: +document_properties_modification_date=Bewurkingsdatum: +# 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-makker: +document_properties_version=PDF-ferzje: +document_properties_page_count=Siden: +document_properties_close=Slute + +print_progress_message=Dokumint tariede oar Γ΄fdrukken… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Annulearje + +# 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=Sidebalke yn-/ΓΊtskeakelje +toggle_sidebar_notification.title=Sidebalke yn-/ΓΊtskeakelje (dokumint befettet outline/bylagen) +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 +thumbs.title=Foarbylden toane +thumbs_label=Foarbylden +findbar.title=Sykje yn dokumint +findbar_label=Sykje + +# 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=Side {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Foarbyld fan side {{page}} + +# Find panel button title and messages +find_input.title=Sykje +find_input.placeholder=Sykje yn dokumint… +find_previous.title=It foarige foarkommen fan de tekst sykje +find_previous_label=Foarige +find_next.title=It folgjende foarkommen fan de tekst sykje +find_next_label=Folgjende +find_highlight=Alles markearje +find_match_case_label=Haadlettergefoelich +find_reached_top=Boppekant fan dokumint berikt, trochgien fan Γ»nder Γ΄f +find_reached_bottom=Ein fan dokumint berikt, trochgien fan boppe Γ΄f +find_not_found=Tekst net fΓ»n + +# Error panel labels +error_more_info=Mear ynformaasje +error_less_info=Minder ynformaasje +error_close=Slute +# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be +# replaced by the PDF.JS version and build ID. +error_version_info=PDF.js f{{version}} (build: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Berjocht: {{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=BestΓ’n: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Rigel: {{line}} +rendering_error=Der is in flater bard by it renderjen fan de side. + +# Predefined zoom values +page_scale_width=Sidebreedte +page_scale_fit=Hiele side +page_scale_auto=Automatysk zoome +page_scale_actual=Werklike grutte +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Flater +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. +unexpected_response_error=Unferwacht serverantwurd. + +# 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}}-annotaasje] +password_label=Jou it wachtwurd om dit PDF-bestΓ’n te iepenjen. +password_invalid=Ferkeard wachtwurd. Probearje opnij. +password_ok=OK +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. +document_colors_not_allowed=PDF-dokuminten meie harren eigen kleuren net brΓ»ke: β€˜Siden tastean om harren eigen kleuren te kiezen’ is ΓΊtskeakele yn de browser. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ga-IE/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ga-IE/viewer.properties new file mode 100755 index 00000000..62f1a551 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ga-IE/viewer.properties @@ -0,0 +1,184 @@ +# 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=An Leathanach Roimhe Seo +previous_label=Roimhe Seo +next.title=An ChΓ©ad Leathanach Eile +next_label=Ar Aghaidh + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Leathanach +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=as {{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}} as {{pagesCount}}) + +zoom_out.title=SΓΊmΓ‘il Amach +zoom_out_label=SΓΊmΓ‘il Amach +zoom_in.title=SΓΊmΓ‘il Isteach +zoom_in_label=SΓΊmΓ‘il Isteach +zoom.title=SΓΊmΓ‘il +presentation_mode.title=ÚsΓ‘id an MΓ³d LΓ‘ithreoireachta +presentation_mode_label=MΓ³d LΓ‘ithreoireachta +open_file.title=Oscail Comhad +open_file_label=Oscail +print.title=PriontΓ‘il +print_label=PriontΓ‘il +download.title=ÍoslΓ³dΓ‘il +download_label=ÍoslΓ³dΓ‘il +bookmark.title=An t-amharc reatha (cΓ³ipeΓ‘il nΓ³ oscail i bhfuinneog nua) +bookmark_label=An tAmharc Reatha + +# Secondary toolbar and context menu +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 +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… +document_properties_file_name=Ainm an chomhaid: +document_properties_file_size=MΓ©id an chomhaid: +# 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}} beart) +# 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}} beart) +document_properties_title=Teideal: +document_properties_author=Údar: +document_properties_subject=Ábhar: +document_properties_keywords=Eochairfhocail: +document_properties_creation_date=DΓ‘ta Cruthaithe: +document_properties_modification_date=DΓ‘ta Athraithe: +# 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=Cruthaitheoir: +document_properties_producer=Cruthaitheoir an PDF: +document_properties_version=Leagan PDF: +document_properties_page_count=LΓ­on Leathanach: +document_properties_close=DΓΊn + +print_progress_message=CΓ‘ipΓ©is Γ‘ hullmhΓΊ le priontΓ‘il… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Cealaigh + +# 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=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 +attachments.title=TaispeΓ‘in IatΓ‘in +attachments_label=IatΓ‘in +thumbs.title=TaispeΓ‘in Mionsamhlacha +thumbs_label=Mionsamhlacha +findbar.title=Aimsigh sa ChΓ‘ipΓ©is +findbar_label=Aimsigh + +# 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=Leathanach {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Mionsamhail Leathanaigh {{page}} + +# Find panel button title and messages +find_input.title=Aimsigh +find_input.placeholder=Aimsigh sa chΓ‘ipΓ©is… +find_previous.title=Aimsigh an sampla roimhe seo den nath seo +find_previous_label=Roimhe seo +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_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 +find_not_found=FrΓ‘sa gan aimsiΓΊ + +# Error panel labels +error_more_info=Tuilleadh Eolais +error_less_info=NΓ­os LΓΊ Eolais +error_close=DΓΊn +# 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=Teachtaireacht: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Cruach: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Comhad: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=LΓ­ne: {{line}} +rendering_error=Tharla earrΓ‘id agus an leathanach Γ‘ leagan amach. + +# Predefined zoom values +page_scale_width=Leithead Leathanaigh +page_scale_fit=Laghdaigh go dtΓ­ an Leathanach +page_scale_auto=SΓΊmΓ‘il UathoibrΓ­och +page_scale_actual=FΓ­ormhΓ©id +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +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 (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=[AnΓ³tΓ‘il {{type}}] +password_label=Cuir an focal faire isteach chun an comhad PDF seo a oscailt. +password_invalid=Focal faire mΓ­cheart. DΓ©an iarracht eile. +password_ok=OK +password_cancel=Cealaigh + +printing_not_supported=Rabhadh: NΓ­ thacaΓ­onn an brabhsΓ‘laΓ­ le priontΓ‘il go hiomlΓ‘n. +printing_not_ready=Rabhadh: NΓ­ fΓ©idir an PDF a phriontΓ‘il go dtΓ­ go mbeidh an chΓ‘ipΓ©is iomlΓ‘n lΓ³dΓ‘ilte. +web_fonts_disabled=TΓ‘ clΓ³fhoirne GrΓ©asΓ‘in dΓ­chumasaithe: nΓ­ fΓ©idir clΓ³fhoirne leabaithe PDF a ΓΊsΓ‘id. +document_colors_not_allowed=NΓ­l cead ag cΓ‘ipΓ©isΓ­ PDF a ndathanna fΓ©in a roghnΓΊ: tΓ‘ β€œTabhair cead do leathanaigh a ndathanna fΓ©in a roghnú” dΓ­chumasaithe sa mbrabhsΓ‘laΓ­. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/gd/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/gd/viewer.properties new file mode 100755 index 00000000..ad752b88 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/gd/viewer.properties @@ -0,0 +1,184 @@ +# 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=An duilleag roimhe +previous_label=Air ais +next.title=An ath-dhuilleag +next_label=Air adhart + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Duilleag +# 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=SΓΉm a-mach +zoom_out_label=SΓΉm a-mach +zoom_in.title=SΓΉm a-steach +zoom_in_label=SΓΉm a-steach +zoom.title=SΓΉm +presentation_mode.title=Gearr leum dhan mhodh taisbeanaidh +presentation_mode_label=Am modh taisbeanaidh +open_file.title=Fosgail faidhle +open_file_label=Fosgail +print.title=ClΓ²-bhuail +print_label=ClΓ²-bhuail +download.title=Luchdaich a-nuas +download_label=Luchdaich a-nuas +bookmark.title=An sealladh lΓ ithreach (dΓ¨an lethbhreac no fosgail e ann an uinneag ΓΉr) +bookmark_label=An sealladh lΓ ithreach + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=Inneal taghadh an teacsa +cursor_hand_tool.title=Cuir inneal na lΓ imhe an comas +cursor_hand_tool_label=Inneal na lΓ imhe + +# Document properties dialog box +document_properties.title=Roghainnean na sgrΓ¬obhainne… +document_properties_label=Roghainnean na sgrΓ¬obhainne… +document_properties_file_name=Ainm an fhaidhle: +document_properties_file_size=Meud an fhaidhle: +# 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=Tiotal: +document_properties_author=Γ™ghdar: +document_properties_subject=Cuspair: +document_properties_keywords=Faclan-luirg: +document_properties_creation_date=Latha a chruthachaidh: +document_properties_modification_date=Latha atharrachaidh: +# 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=Cruthadair: +document_properties_producer=Saothraiche a' PDF: +document_properties_version=Tionndadh a' PDF: +document_properties_page_count=Γ€ireamh de dhuilleagan: +document_properties_close=DΓΉin + +print_progress_message=Ag ullachadh na sgrΓ¬obhainn airson clΓ²-bhualadh… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Sguir dheth + +# 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=Toglaich am bΓ r-taoibh +toggle_sidebar_notification.title=Toglaich am bΓ r-taoibh (tha oir-loidhne/ceanglachain 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 +thumbs.title=Seall na dealbhagan +thumbs_label=Dealbhagan +findbar.title=Lorg san sgrΓ¬obhainn +findbar_label=Lorg + +# 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=Duilleag a {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Dealbhag duilleag a {{page}} + +# Find panel button title and messages +find_input.title=Lorg +find_input.placeholder=Lorg san sgrΓ¬obhainn... +find_previous.title=Lorg lΓ thair roimhe na h-abairt seo +find_previous_label=Air ais +find_next.title=Lorg ath-lΓ thair na h-abairt seo +find_next_label=Air adhart +find_highlight=Soillsich a h-uile +find_match_case_label=Aire do litrichean mΓ²ra is beaga +find_reached_top=RΓ inig sinn barr na duilleige, a' leantainn air adhart o bhonn na duilleige +find_reached_bottom=RΓ inig sinn bonn na duilleige, a' leantainn air adhart o bharr na duilleige +find_not_found=Cha deach an abairt a lorg + +# Error panel labels +error_more_info=Barrachd fiosrachaidh +error_less_info=Nas lugha de dh'fhiosrachadh +error_close=DΓΉin +# 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=Teachdaireachd: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Stac: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Faidhle: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Loidhne: {{line}} +rendering_error=Thachair mearachd rΓ¨ reandaradh na duilleige. + +# Predefined zoom values +page_scale_width=Leud na duilleige +page_scale_fit=Freagair ri meud na duilleige +page_scale_auto=SΓΉm fΓ¨in-obrachail +page_scale_actual=Am fΓ¬or-mheud +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Mearachd +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 (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=[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_cancel=Sguir dheth + +printing_not_supported=Rabhadh: Chan eil am brabhsair seo a' cur lΓ n-taic ri clΓ²-bhualadh. +printing_not_ready=Rabhadh: Cha deach am PDF a luchdadh gu tur airson clΓ²-bhualadh. +web_fonts_disabled=Tha cruthan-clΓ² lΓ¬n Γ  comas: Chan urrainn dhuinn cruthan-clΓ² PDF leabaichte a chleachdadh. +document_colors_not_allowed=Chan fhaod sgrΓ¬obhainnean PDF na dathan aca fhΓ¨in a chleachdadh: Tha β€œLeig le duilleagan na dathan aca fhΓ¨in a chleachdadh” Γ  comas sa bhrabhsair. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/gl/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/gl/viewer.properties new file mode 100755 index 00000000..f393fcad --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/gl/viewer.properties @@ -0,0 +1,168 @@ +# 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Γ‘xina anterior +previous_label=Anterior +next.title=Seguinte pΓ‘xina +next_label=Seguinte + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +zoom_out.title=Reducir +zoom_out_label=Reducir +zoom_in.title=Ampliar +zoom_in_label=Ampliar +zoom.title=Zoom +presentation_mode.title=Cambiar ao modo presentaciΓ³n +presentation_mode_label=Modo presentaciΓ³n +open_file.title=Abrir ficheiro +open_file_label=Abrir +print.title=Imprimir +print_label=Imprimir +download.title=Descargar +download_label=Descargar +bookmark.title=Vista actual (copiar ou abrir nunha nova xanela) +bookmark_label=Vista actual + +# Secondary toolbar and context menu +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 + + +# Document properties dialog box +document_properties.title=Propiedades do documento… +document_properties_label=Propiedades do documento… +document_properties_file_name=Nome do ficheiro: +document_properties_file_size=TamaΓ±o do ficheiro: +# 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Γ­tulo: +document_properties_author=Autor: +document_properties_subject=Asunto: +document_properties_keywords=Palabras 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=Creado por: +document_properties_producer=Xenerador do PDF: +document_properties_version=VersiΓ³n de PDF: +document_properties_page_count=NΓΊmero de pΓ‘xinas: +document_properties_close=Pechar + +# 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) +toggle_sidebar.title=Amosar/agochar a barra lateral +toggle_sidebar_label=Amosar/agochar a barra lateral +attachments.title=Amosar anexos +attachments_label=Anexos +thumbs.title=Amosar miniaturas +thumbs_label=Miniaturas +findbar.title=Atopar no documento +findbar_label=Atopar + +# 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 da pΓ‘xina {{page}} + +# Find panel button title and messages +find_previous.title=Atopar a anterior apariciΓ³n da frase +find_previous_label=Anterior +find_next.title=Atopar a seguinte apariciΓ³n da frase +find_next_label=Seguinte +find_highlight=Realzar todo +find_match_case_label=Diferenciar maiΓΊsculas de minΓΊsculas +find_reached_top=Chegouse ao inicio do documento, continuar desde o final +find_reached_bottom=Chegouse ao final do documento, continuar desde o inicio +find_not_found=Non se atopou a frase + +# Error panel labels +error_more_info=MΓ‘is informaciΓ³n +error_less_info=Menos informaciΓ³n +error_close=Pechar +# 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}} (Identificador da compilaciΓ³n: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Mensaxe: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Pila: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Ficheiro: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=LiΓ±a: {{line}} +rendering_error=Produciuse un erro ao representar a pΓ‘xina. + +# Predefined zoom values +page_scale_width=Largura da pΓ‘xina +page_scale_fit=Axuste de pΓ‘xina +page_scale_auto=Zoom automΓ‘tico +page_scale_actual=TamaΓ±o 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=Erro +loading_error=Produciuse un erro ao cargar o PDF. +invalid_file_error=Ficheiro PDF danado ou incorrecto. +missing_file_error=Falta o ficheiro PDF. +unexpected_response_error=Resposta inesperada do servidor. + +# 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=Escriba o contrasinal para abrir este ficheiro PDF. +password_invalid=Contrasinal incorrecto. Tente de novo. +password_ok=Aceptar +password_cancel=Cancelar + +printing_not_supported=Aviso: A impresiΓ³n non Γ© compatΓ­bel de todo con este navegador. +printing_not_ready=Aviso: O PDF non se cargou completamente para imprimirse. +web_fonts_disabled=DesactivΓ‘ronse as fontes web: foi imposΓ­bel usar as fontes incrustadas no PDF. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/gu-IN/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/gu-IN/viewer.properties new file mode 100755 index 00000000..433cabfa --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/gu-IN/viewer.properties @@ -0,0 +1,163 @@ +# 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. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +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.label=ΰͺͺΰͺΉΰ«‡ΰͺ²ΰͺΎΰͺ‚ ΰͺͺΰͺΎΰͺ¨ΰͺΎΰͺΰͺΎΰͺ‚ ΰͺœΰͺΎΰͺ΅ +first_page_label=ΰͺͺ્ΰͺ°ΰͺ₯ΰͺ ΰͺͺΰͺΎΰͺ¨ΰͺΎΰͺ‚ ΰͺͺΰͺ° ΰͺœΰͺΎΰͺ΅ +last_page.label=ΰͺ›ΰ«‡ΰͺ²ΰ«ΰͺ²ΰͺΎ ΰͺͺΰͺΎΰͺ¨ΰͺΎΰͺΰͺΎΰͺ‚ ΰͺœΰͺΎΰͺ΅ +last_page_label=ΰͺ›ΰ«‡ΰͺ²ΰ«ΰͺ²ΰͺΎ ΰͺͺΰͺΎΰͺ¨ΰͺΎΰͺ‚ ΰͺͺΰͺ° ΰͺœΰͺΎΰͺ΅ +page_rotate_cw.label=ΰͺ˜ΰͺ‘ΰͺΏΰͺ―ΰͺΎΰͺ³ΰͺ¨ΰͺΎΰͺ‚ ΰͺ•ΰͺΎΰͺ‚ΰͺŸΰͺΎΰͺ¨ΰ«€ ΰͺœΰ«‡ΰͺ ΰͺ«ΰ«‡ΰͺ°ΰͺ΅ΰ«‹ +page_rotate_cw_label=ΰͺ˜ΰͺ‘ΰͺΏΰͺ―ΰͺΎΰͺ³ΰͺ¨ΰͺΎΰͺ‚ ΰͺ•ΰͺΎΰͺ‚ΰͺŸΰͺΎ ΰͺ€ΰͺ°ΰͺ« ΰͺ«ΰ«‡ΰͺ°ΰͺ΅ΰ«‹ +page_rotate_ccw.label=ΰͺ˜ΰͺ‘ΰͺΏΰͺ―ΰͺΎΰͺ³ΰͺ¨ΰͺΎΰͺ‚ ΰͺ•ΰͺΎΰͺ‚ΰͺŸΰͺΎΰͺ¨ΰ«€ ΰͺ‰ΰͺ²ΰͺŸΰ«€ ΰͺ¦ΰͺΏΰͺΆΰͺΎΰͺΰͺΎΰͺ‚ ΰͺ«ΰ«‡ΰͺ°ΰͺ΅ΰ«‹ +page_rotate_ccw_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}} 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_close=ΰͺ¬ΰͺ‚ΰͺ§ ΰͺ•ΰͺ°ΰ«‹ + +# 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) +toggle_sidebar.title=ΰͺŸΰ«‰ΰͺ—ΰͺ² ΰͺ¬ΰͺΎΰͺœΰ«ΰͺͺΰͺŸΰ«ΰͺŸΰ«€ +toggle_sidebar_label=ΰͺŸΰ«‰ΰͺ—ΰͺ² ΰͺ¬ΰͺΎΰͺœΰ«ΰͺͺΰͺŸΰ«ΰͺŸΰ«€ +document_outline_label=ΰͺ¦ΰͺΈΰ«ΰͺ€ΰͺΎΰͺ΅ΰ«‡ΰͺœ ΰͺ°ΰ«‚ΰͺͺΰͺ°ΰ«‡ΰͺ–ΰͺΎ +attachments.title=ΰͺœΰ«‹ΰͺ‘ΰͺΎΰͺ£ΰ«‹ΰͺ¨ΰ«‡ ΰͺ¬ΰͺ€ΰͺΎΰͺ΅ΰ«‹ +attachments_label=ΰͺœΰ«‹ΰͺ‘ΰͺΎΰͺ£ΰ«‹ +thumbs.title=ΰͺ₯ΰͺ‚ΰͺ¬ΰͺ¨ΰ«‡ΰͺ²ΰ«ΰͺΈ ΰͺ¬ΰͺ€ΰͺΎΰͺ΅ΰ«‹ +thumbs_label=ΰͺ₯ΰͺ‚ΰͺ¬ΰͺ¨ΰ«‡ΰͺ²ΰ«ΰͺΈ +findbar.title=ΰͺ¦ΰͺΈΰ«ΰͺ€ΰͺΎΰͺ΅ΰ«‡ΰͺœΰͺΰͺΎΰͺ‚ ΰͺΆΰ«‹ΰͺ§ΰ«‹ +findbar_label=ΰͺΆΰ«‹ΰͺ§ΰ«‹ + +# 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_previous_label=ΰͺͺΰͺΉΰ«‡ΰͺ²ΰͺΎΰͺ‚ΰͺ¨ΰ« +find_next.title=ΰͺΆΰͺ¬ΰ«ΰͺ¦ΰͺΈΰͺΰ«‚ΰͺΉΰͺ¨ΰ«€ ΰͺ†ΰͺ—ΰͺ³ΰͺ¨ΰ«€ ΰͺ˜ΰͺŸΰͺ¨ΰͺΎΰͺ¨ΰ«‡ ΰͺΆΰ«‹ΰͺ§ΰ«‹ +find_next_label=ΰͺ†ΰͺ—ΰͺ³ΰͺ¨ΰ«ΰͺ‚ +find_highlight=ΰͺ¬ΰͺ§ΰ« ΰͺͺ્ΰͺ°ΰͺ•ΰͺΎΰͺΆΰͺΏΰͺ€ ΰͺ•ΰͺ°ΰ«‹ +find_match_case_label=ΰͺ•ેΰͺΈ ΰͺ¬ΰͺ‚ΰͺ§ΰͺ¬ΰ«‡ΰͺΈΰͺΎΰͺ‘ΰ«‹ +find_reached_top=ΰͺ¦ΰͺΈΰ«ΰͺ€ΰͺΎΰͺ΅ΰ«‡ΰͺœΰͺ¨ΰͺΎΰͺ‚ ΰͺŸΰ«‹ΰͺšΰ«‡ ΰͺͺΰͺΉΰ«‹ΰͺ‚ΰͺšΰ«€ ΰͺ—ΰͺ―ΰͺΎ, ΰͺ€ΰͺ³ΰͺΏΰͺ―ેΰͺ₯ΰ«€ ΰͺšΰͺΎΰͺ²ΰ« ΰͺ•ΰͺ°ΰ«‡ΰͺ² ΰͺΉΰͺ€ΰ« +find_reached_bottom=ΰͺ¦ΰͺΈΰ«ΰͺ€ΰͺΎΰͺ΅ΰ«‡ΰͺœΰͺ¨ΰͺΎΰͺ‚ ΰͺ…ΰͺ‚ΰͺ€ΰ«‡ ΰͺͺΰͺΉΰ«‹ΰͺ‚ΰͺšΰ«€ ΰͺ—ΰͺ―ΰͺΎ, ΰͺ‰ΰͺͺΰͺ°ΰͺ₯ΰ«€ ΰͺšΰͺΎΰͺ²ΰ« ΰͺ•ΰͺ°ΰ«‡ΰͺ² ΰͺΉΰͺ€ΰ« +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. + +# Loading indicator messages +loading_error_indicator=ΰͺ­ΰ«‚ΰͺ² +loading_error=ΰͺ­ΰ«‚ΰͺ² ΰͺ‰ΰͺ¦ΰ«ΰͺ­ΰͺ΅ΰ«€ ΰͺœΰ«ΰͺ―ΰͺΎΰͺ°ΰ«‡ PDF ΰͺ¨ΰ«‡ ΰͺ²ΰͺΎΰͺ΅ΰ«€ ΰͺ°ΰͺΉΰ«ΰͺ―ΰͺΎ ΰͺΉΰ«‹ΰͺ―. +invalid_file_error=ΰͺ…ΰͺ―ΰ«‹ΰͺ—્ΰͺ― ΰͺ…ΰͺ₯ΰͺ΅ΰͺΎ ΰͺ­ΰͺΎΰͺ‚ΰͺ—ેΰͺ² PDF ΰͺ«ΰͺΎΰͺ‡ΰͺ². +missing_file_error=ΰͺ—ુΰͺ ΰͺ₯ΰͺ―ેΰͺ² PDF ΰͺ«ΰͺΎΰͺ‡ΰͺ². + +# 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=ΰͺ† PDF ΰͺ«ΰͺΎΰͺ‡ΰͺ²ΰͺ¨ΰ«‡ ΰͺ–ΰ«‹ΰͺ²ΰͺ΅ΰͺΎ ΰͺͺΰͺΎΰͺΈΰͺ΅ΰͺ°ΰ«ΰͺ‘ΰͺ¨ΰ«‡ ΰͺ¦ΰͺΎΰͺ–ΰͺ² ΰͺ•ΰͺ°ΰ«‹. +password_invalid=ΰͺ…ΰͺ―ΰ«‹ΰͺ—્ΰͺ― ΰͺͺΰͺΎΰͺΈΰͺ΅ΰͺ°ΰ«ΰͺ‘. ΰͺΰͺΉΰ«‡ΰͺ°ΰͺ¬ΰͺΎΰͺ¨ΰ«€ ΰͺ•ΰͺ°ΰ«€ΰͺ¨ΰ«‡ ΰͺ«ΰͺ°ΰ«€ ΰͺͺ્ΰͺ°ΰͺ―ΰͺ€ΰ«ΰͺ¨ ΰͺ•ΰͺ°ΰ«‹. +password_ok=ΰͺ¬ΰͺ°ΰͺΎΰͺ¬ΰͺ° + +printing_not_supported=ΰͺšΰ«‡ΰͺ€ΰͺ΅ΰͺ£ΰ«€: ΰͺ›ΰͺΎΰͺͺΰͺ΅ΰͺΎΰͺ¨ΰ«ΰͺ‚ ΰͺ† ΰͺ¬ΰ«ΰͺ°ΰͺΎΰͺ‰ΰͺΰͺ° ΰͺ¦ΰ«ΰͺ¦ΰͺΎΰͺ°ΰͺΎ ΰͺΈΰͺ‚ΰͺͺΰ«‚ΰͺ°ΰ«ΰͺ£ΰͺͺΰͺ£ΰ«‡ ΰͺ†ΰͺ§ΰͺΎΰͺ°ΰͺ­ΰ«‚ΰͺ€ ΰͺ¨ΰͺ₯ΰ«€. +printing_not_ready=Warning: PDF ΰͺ ΰͺ›ΰͺΎΰͺͺΰͺ΅ΰͺΎ ΰͺΰͺΎΰͺŸΰ«‡ ΰͺΈΰͺ‚ΰͺͺΰ«‚ΰͺ°ΰ«ΰͺ£ΰͺͺΰͺ£ΰ«‡ ΰͺ²ΰͺΎΰͺ΅ΰ«‡ΰͺ² ΰͺ›ΰ«‡. +web_fonts_disabled=ΰͺ΅ΰ«‡ΰͺ¬ ΰͺ«ΰ«‹ΰͺ¨ΰ«ΰͺŸ ΰͺ¨ΰͺΏΰͺ·ΰ«ΰͺ•્ΰͺ°ΰͺΏΰͺ― ΰͺ₯ΰͺ―ેΰͺ² ΰͺ›ΰ«‡: ΰͺΰͺ્ΰͺ¬ΰ«‡ΰͺ‘ ΰͺ₯ΰͺ―ેΰͺ² PDF ΰͺ«ΰ«‹ΰͺ¨ΰ«ΰͺŸΰͺ¨ΰ«‡ ΰͺ΅ΰͺΎΰͺͺΰͺ°ΰͺ΅ΰͺΎΰͺ¨ΰ«ΰͺ‚ ΰͺ…ΰͺΈΰͺΰͺ°ΰ«ΰͺ₯. +document_colors_not_allowed=PDF ΰͺ¦ΰͺΈΰ«ΰͺ€ΰͺΎΰͺ΅ΰ«‡ΰͺœΰ«‹ ΰͺ€ΰ«‡ΰͺ¨ΰͺΎΰͺ‚ ΰͺͺΰ«‹ΰͺ€ΰͺΎΰͺ¨ΰͺΎ ΰͺ°ΰͺ‚ΰͺ—ΰ«‹ΰͺ¨ΰ«‡ ΰͺ΅ΰͺΎΰͺͺΰͺ°ΰͺ΅ΰͺΎ ΰͺͺΰͺ°ΰͺ΅ΰͺΎΰͺ¨ΰͺ—ΰ«€ ΰͺ†ΰͺͺΰͺ€ΰͺΎ ΰͺ¨ΰͺ₯ΰ«€: 'ΰͺ€ΰ«‡ΰͺ¨ΰͺΎΰͺ‚ ΰͺͺΰ«‹ΰͺ€ΰͺΎΰͺ¨ΰͺΎΰͺ‚ ΰͺ°ΰͺ‚ΰͺ—ΰ«‹ΰͺ¨ΰ«‡ ΰͺͺΰͺΈΰͺ‚ΰͺ¦ ΰͺ•ΰͺ°ΰͺ΅ΰͺΎ ΰͺΰͺΎΰͺŸΰ«‡ ΰͺͺΰͺΎΰͺ¨ΰͺΎΰͺ‚ΰͺ¨ΰ«‡ ΰͺͺΰͺ°ΰͺ΅ΰͺΎΰͺ¨ΰͺ—ΰ«€ ΰͺ†ΰͺͺΰ«‹' ΰͺ¬ΰ«ΰͺ°ΰͺΎΰͺ‰ΰͺΰͺ°ΰͺΰͺΎΰͺ‚ ΰͺ¨ΰͺΏΰͺ·ΰ«ΰͺ•્ΰͺ°ΰͺΏΰͺ― ΰͺ₯ΰͺ―ેΰͺ² ΰͺ›ΰ«‡. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/he/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/he/viewer.properties new file mode 100755 index 00000000..070bbdef --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/he/viewer.properties @@ -0,0 +1,184 @@ +# 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=ΧžΧ’Χ‘Χ¨ ΧœΧ’ΧžΧ•Χ“ Χ”Χ¨ΧΧ©Χ•ΧŸ +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_label=Χ›ΧœΧ™ Χ‘Χ—Χ™Χ¨Χͺ טקבט +cursor_hand_tool.title=Χ”Χ€Χ’ΧœΧͺ Χ›ΧœΧ™ Χ”Χ™Χ“ +cursor_hand_tool_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_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_notification.title=Χ”Χ—ΧœΧ€Χͺ ΧͺΧ¦Χ•Χ’Χͺ Χ‘Χ¨Χ’Χœ Χ¦Χ“ (מבמך Χ©ΧžΧ›Χ™Χœ מΧͺאר/Χ¦Χ¨Χ•Χ€Χ•Χͺ) +toggle_sidebar_label=Χ”Χ¦Χ’Χ”/Χ”Χ‘ΧͺΧ¨Χ” של Χ‘Χ¨Χ’Χœ Χ”Χ¦Χ“ +document_outline.title=Χ”Χ¦Χ’Χͺ מΧͺאר מבמך (ΧœΧ—Χ™Χ¦Χ” Χ›Χ€Χ•ΧœΧ” Χ›Χ“Χ™ ΧœΧ”Χ¨Χ—Χ™Χ‘ או לצמצם אΧͺ Χ›Χœ Χ”Χ€Χ¨Χ™Χ˜Χ™Χ) +document_outline_label=מΧͺאר מבמך +attachments.title=Χ”Χ¦Χ’Χͺ Χ¦Χ¨Χ•Χ€Χ•Χͺ +attachments_label=Χ¦Χ¨Χ•Χ€Χ•Χͺ +thumbs.title=Χ”Χ¦Χ’Χͺ ΧͺΧ¦Χ•Χ’Χ” ΧžΧ§Χ“Χ™ΧžΧ” +thumbs_label=ΧͺΧ¦Χ•Χ’Χ” ΧžΧ§Χ“Χ™ΧžΧ” +findbar.title=Χ—Χ™Χ€Χ•Χ© Χ‘ΧžΧ‘ΧžΧš +findbar_label=Χ—Χ™Χ€Χ•Χ© + +# 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_reached_top=Χ”Χ’Χ™Χ’ לראש Χ”Χ“Χ£, ΧžΧžΧ©Χ™Χš ΧžΧœΧžΧ˜Χ” +find_reached_bottom=Χ”Χ’Χ™Χ’ ΧœΧ‘Χ•Χ£ Χ”Χ“Χ£, ΧžΧžΧ©Χ™Χš ΧžΧœΧžΧ’ΧœΧ” +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 Χ’Χ¨Χ‘Χ” {{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_error_indicator=שגיאה +loading_error=אירגה שגיאה Χ‘Χ’Χͺ Χ˜Χ’Χ™Χ Χͺ Χ”ΦΎPDF. +invalid_file_error=Χ§Χ•Χ‘Χ₯ PDF ׀גום או לא ΧͺΧ§Χ™ΧŸ. +missing_file_error=Χ§Χ•Χ‘Χ₯ PDF Χ—Χ‘Χ¨. +unexpected_response_error=ΧͺΧ’Χ•Χ‘Χͺ Χ©Χ¨Χͺ לא Χ¦Χ€Χ•Χ™Χ”. + +# 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 ΧžΧ•Χ˜Χ‘Χ’Χ™Χ. +document_colors_not_allowed=ΧžΧ‘ΧžΧ›Χ™ PDF אינם ΧžΧ•Χ¨Χ©Χ™Χ ΧœΧ”Χ©Χͺמש בצבגים ΧžΧ©ΧœΧ”Χ: הא׀שרוΧͺ β€žΧΧ€Χ©Χ¨ ΧœΧ’ΧžΧ•Χ“Χ™Χ ΧœΧ‘Χ—Χ•Χ¨ צבגים ΧžΧ©ΧœΧ”Χβ€ אינה Χ€Χ’Χ™ΧœΧ” Χ‘Χ“Χ€Χ“Χ€ΧŸ. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/hi-IN/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/hi-IN/viewer.properties new file mode 100755 index 00000000..3280c9b7 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/hi-IN/viewer.properties @@ -0,0 +1,176 @@ +# 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}} of {{pagesCount}}) + +zoom_out.title=\u0020ΰ€›ΰ₯‹ΰ€Ÿΰ€Ύ ΰ€•ΰ€°ΰ₯‡ΰ€‚ +zoom_out_label=\u0020ΰ€›ΰ₯‹ΰ€Ÿΰ€Ύ ΰ€•ΰ€°ΰ₯‡ΰ€‚ +zoom_in.title=ΰ€¬ΰ€‘ΰ€Όΰ€Ύ ΰ€•ΰ€°ΰ₯‡ΰ€‚ +zoom_in_label=ΰ€¬ΰ€‘ΰ€Όΰ€Ύ ΰ€•ΰ€°ΰ₯‡ΰ€‚ +zoom.title=ΰ€¬ΰ€‘ΰ€Όΰ€Ύ-ΰ€›ΰ₯‹ΰ€Ÿΰ€Ύ ΰ€•ΰ€°ΰ₯‡ΰ€‚ +presentation_mode.title=ΰ€ͺΰ₯ΰ€°ΰ€Έΰ₯ΰ€€ΰ₯ΰ€€ΰ€Ώ ΰ€…ΰ€΅ΰ€Έΰ₯ΰ€₯ΰ€Ύ ΰ€ΰ₯‡ΰ€‚ ΰ€œΰ€Ύΰ€ΰ€ +presentation_mode_label=\u0020ΰ€ͺΰ₯ΰ€°ΰ€Έΰ₯ΰ€€ΰ₯ΰ€€ΰ€Ώ ΰ€…ΰ€΅ΰ€Έΰ₯ΰ€₯ΰ€Ύ +open_file.title=ΰ€«ΰ€Όΰ€Ύΰ€‡ΰ€² ΰ€–ΰ₯‹ΰ€²ΰ₯‡ΰ€‚ +open_file_label=\u0020ΰ€–ΰ₯‹ΰ€²ΰ₯‡ΰ€‚ +print.title=ΰ€›ΰ€Ύΰ€ͺΰ₯‡ΰ€‚ +print_label=\u0020ΰ€›ΰ€Ύΰ€ͺΰ₯‡ΰ€‚ +download.title=ΰ€‘ΰ€Ύΰ€‰ΰ€¨ΰ€²ΰ₯‹ΰ€‘ +download_label=ΰ€‘ΰ€Ύΰ€‰ΰ€¨ΰ€²ΰ₯‹ΰ€‘ +bookmark.title=ΰ€ΰ₯Œΰ€œΰ₯‚ΰ€¦ΰ€Ύ ΰ€¦ΰ₯ƒΰ€Άΰ₯ΰ€― (ΰ€¨ΰ€ ΰ€΅ΰ€Ώΰ€‚ΰ€‘ΰ₯‹ ΰ€ΰ₯‡ΰ€‚ ΰ€¨ΰ€•ΰ€Όΰ€² ΰ€²ΰ₯‡ΰ€‚ ΰ€―ΰ€Ύ ΰ€–ΰ₯‹ΰ€²ΰ₯‡ΰ€‚) +bookmark_label=\u0020ΰ€ΰ₯Œΰ€œΰ₯‚ΰ€¦ΰ€Ύ ΰ€¦ΰ₯ƒΰ€Άΰ₯ΰ€― + +# Secondary toolbar and context menu +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ΰ€˜ΰ€‘ΰ€Όΰ₯€ ΰ€•ΰ₯€ ΰ€¦ΰ€Ώΰ€Άΰ€Ύ ΰ€Έΰ₯‡ ΰ€‰ΰ€²ΰ₯ΰ€Ÿΰ€Ύ ΰ€˜ΰ₯ΰ€ΰ€Ύΰ€ΰ€ + + +# 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}} 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=ΰ€Άΰ₯€ΰ€°ΰ₯ΰ€·ΰ€•: +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_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=\u0020ΰ€Έΰ₯ΰ€²ΰ€Ύΰ€‡ΰ€‘ΰ€° ΰ€Ÿΰ₯‰ΰ€—ΰ€² ΰ€•ΰ€°ΰ₯‡ΰ€‚ +toggle_sidebar_label=ΰ€Έΰ₯ΰ€²ΰ€Ύΰ€‡ΰ€‘ΰ€° ΰ€Ÿΰ₯‰ΰ€—ΰ€² ΰ€•ΰ€°ΰ₯‡ΰ€‚ +document_outline.title=ΰ€¦ΰ€Έΰ₯ΰ€€ΰ€Ύΰ€΅ΰ₯‡ΰ€œΰ€Ό ΰ€•ΰ₯€ ΰ€°ΰ₯‚ΰ€ͺΰ€°ΰ₯‡ΰ€–ΰ€Ύ ΰ€¦ΰ€Ώΰ€–ΰ€Ύΰ€‡ΰ€ (ΰ€Έΰ€Ύΰ€°ΰ₯€ ΰ€΅ΰ€Έΰ₯ΰ€€ΰ₯ΰ€“ΰ€‚ ΰ€•ΰ₯‹ ΰ€«ΰ€²ΰ€¨ΰ₯‡ ΰ€…ΰ€₯ΰ€΅ΰ€Ύ ΰ€Έΰ€ΰ₯‡ΰ€Ÿΰ€¨ΰ₯‡ ΰ€•ΰ₯‡ ΰ€²ΰ€Ώΰ€ ΰ€¦ΰ₯‹ ΰ€¬ΰ€Ύΰ€° ΰ€•ΰ₯ΰ€²ΰ€Ώΰ€• ΰ€•ΰ€°ΰ₯‡ΰ€‚) +document_outline_label=ΰ€¦ΰ€Έΰ₯ΰ€€ΰ€Ύΰ€΅ΰ₯‡ΰ€œΰ€Ό ΰ€†ΰ€‰ΰ€Ÿΰ€²ΰ€Ύΰ€‡ΰ€¨ +attachments.title=ΰ€Έΰ€‚ΰ€²ΰ€—ΰ₯ΰ€¨ΰ€• ΰ€¦ΰ€Ώΰ€–ΰ€Ύΰ€―ΰ₯‡ΰ€‚ +attachments_label=ΰ€Έΰ€‚ΰ€²ΰ€—ΰ₯ΰ€¨ΰ€• +thumbs.title=ΰ€²ΰ€˜ΰ₯ΰ€›ΰ€΅ΰ€Ώΰ€―ΰ€Ύΰ€ ΰ€¦ΰ€Ώΰ€–ΰ€Ύΰ€ΰ€ +thumbs_label=ΰ€²ΰ€˜ΰ₯ ΰ€›ΰ€΅ΰ€Ώ +findbar.title=\u0020ΰ€¦ΰ€Έΰ₯ΰ€€ΰ€Ύΰ€΅ΰ₯‡ΰ€œΰ€Ό ΰ€ΰ₯‡ΰ€‚ ΰ€’ΰ₯‚ΰ€ΰ€’ΰ€Όΰ₯‡ΰ€‚ + +# 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_previous_label=ΰ€ͺΰ€Ώΰ€›ΰ€²ΰ€Ύ +find_next.title=ΰ€΅ΰ€Ύΰ€•ΰ₯ΰ€―ΰ€Ύΰ€‚ΰ€Ά ΰ€•ΰ₯€ ΰ€…ΰ€—ΰ€²ΰ₯€ ΰ€‰ΰ€ͺΰ€Έΰ₯ΰ€₯ΰ€Ώΰ€€ΰ€Ώ ΰ€’ΰ₯‚ΰ€ΰ€’ΰ€Όΰ₯‡ΰ€‚ +find_next_label=ΰ€†ΰ€—ΰ₯‡ +find_highlight=\u0020ΰ€Έΰ€­ΰ₯€ ΰ€†ΰ€²ΰ₯‹ΰ€•ΰ€Ώΰ€€ ΰ€•ΰ€°ΰ₯‡ΰ€‚ +find_match_case_label=ΰ€ΰ€Ώΰ€²ΰ€Ύΰ€¨ ΰ€Έΰ₯ΰ€₯ΰ€Ώΰ€€ΰ€Ώ +find_reached_top=ΰ€ͺΰ₯ƒΰ€·ΰ₯ΰ€  ΰ€•ΰ₯‡ ΰ€Šΰ€ͺΰ€° ΰ€ͺΰ€Ήΰ₯ΰ€‚ΰ€š ΰ€—ΰ€―ΰ€Ύ, ΰ€¨ΰ₯€ΰ€šΰ₯‡ ΰ€Έΰ₯‡ ΰ€œΰ€Ύΰ€°ΰ₯€ ΰ€°ΰ€–ΰ₯‡ΰ€‚ +find_reached_bottom=ΰ€ͺΰ₯ƒΰ€·ΰ₯ΰ€  ΰ€•ΰ₯‡ ΰ€¨ΰ₯€ΰ€šΰ₯‡ ΰ€ΰ₯‡ΰ€‚ ΰ€œΰ€Ύ ΰ€ͺΰ€Ήΰ₯ΰ€ΰ€šΰ€Ύ, ΰ€Šΰ€ͺΰ€° ΰ€Έΰ₯‡ ΰ€œΰ€Ύΰ€°ΰ₯€ +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=\u0020ΰ€Έΰ€‚ΰ€¦ΰ₯‡ΰ€Ά: {{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=\u0020ΰ€ͺΰ₯ƒΰ€·ΰ₯ΰ€  ΰ€šΰ₯Œΰ€‘ΰ€Όΰ€Ύΰ€ˆ +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_error=PDF ΰ€²ΰ₯‹ΰ€‘ ΰ€•ΰ€°ΰ€€ΰ₯‡ ΰ€Έΰ€ΰ€― ΰ€ΰ€• ΰ€€ΰ₯ΰ€°ΰ₯ΰ€Ÿΰ€Ώ ΰ€Ήΰ₯ΰ€ˆ. +invalid_file_error=ΰ€…ΰ€ΰ€Ύΰ€¨ΰ₯ΰ€― ΰ€―ΰ€Ύ ΰ€­ΰ₯ΰ€°ΰ€·ΰ₯ΰ€Ÿ PDF ΰ€«ΰ€Όΰ€Ύΰ€‡ΰ€². +missing_file_error=\u0020ΰ€…ΰ€¨ΰ₯ΰ€ͺΰ€Έΰ₯ΰ€₯ΰ€Ώΰ€€ PDF ΰ€«ΰ€Όΰ€Ύΰ€‡ΰ€². +unexpected_response_error=ΰ€…ΰ€ͺΰ₯ΰ€°ΰ€€ΰ₯ΰ€―ΰ€Ύΰ€Άΰ€Ώΰ€€ ΰ€Έΰ€°ΰ₯ΰ€΅ΰ€° ΰ€ͺΰ₯ΰ€°ΰ€€ΰ€Ώΰ€•ΰ₯ΰ€°ΰ€Ώΰ€―ΰ€Ύ. + +# 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=\u0020[{{type}} Annotation] +password_label=ΰ€‡ΰ€Έ PDF ΰ€«ΰ€Όΰ€Ύΰ€‡ΰ€² ΰ€•ΰ₯‹ ΰ€–ΰ₯‹ΰ€²ΰ€¨ΰ₯‡ ΰ€•ΰ₯‡ ΰ€²ΰ€Ώΰ€ ΰ€•ΰ₯ƒΰ€ͺΰ€―ΰ€Ύ ΰ€•ΰ₯‚ΰ€Ÿΰ€Άΰ€¬ΰ₯ΰ€¦ ΰ€­ΰ€°ΰ₯‡ΰ€‚. +password_invalid=ΰ€…ΰ€΅ΰ₯ˆΰ€§ ΰ€•ΰ₯‚ΰ€Ÿΰ€Άΰ€¬ΰ₯ΰ€¦, ΰ€•ΰ₯ƒΰ€ͺΰ€―ΰ€Ύ ΰ€«ΰ€Ώΰ€° ΰ€•ΰ₯‹ΰ€Άΰ€Ώΰ€Ά ΰ€•ΰ€°ΰ₯‡ΰ€‚. +password_ok=OK +password_cancel=ΰ€°ΰ€¦ΰ₯ΰ€¦ ΰ€•ΰ€°ΰ₯‡ΰ€‚ + +printing_not_supported=ΰ€šΰ₯‡ΰ€€ΰ€Ύΰ€΅ΰ€¨ΰ₯€: ΰ€‡ΰ€Έ ΰ€¬ΰ₯ΰ€°ΰ€Ύΰ€‰ΰ€œΰ€Όΰ€° ΰ€ͺΰ€° ΰ€›ΰ€ͺΰ€Ύΰ€ˆ ΰ€ͺΰ₯‚ΰ€°ΰ₯€ ΰ€€ΰ€°ΰ€Ή ΰ€Έΰ₯‡ ΰ€Έΰ€ΰ€°ΰ₯ΰ€₯ΰ€Ώΰ€€ ΰ€¨ΰ€Ήΰ₯€ΰ€‚ ΰ€Ήΰ₯ˆ. +printing_not_ready=ΰ€šΰ₯‡ΰ€€ΰ€Ύΰ€΅ΰ€¨ΰ₯€: PDF ΰ€›ΰ€ͺΰ€Ύΰ€ˆ ΰ€•ΰ₯‡ ΰ€²ΰ€Ώΰ€ ΰ€ͺΰ₯‚ΰ€°ΰ₯€ ΰ€€ΰ€°ΰ€Ή ΰ€Έΰ₯‡ ΰ€²ΰ₯‹ΰ€‘ ΰ€¨ΰ€Ήΰ₯€ΰ€‚ ΰ€Ήΰ₯ˆ. +web_fonts_disabled=ΰ€΅ΰ₯‡ΰ€¬ ΰ€«ΰ₯‰ΰ€¨ΰ₯ΰ€Ÿΰ₯ΰ€Έ ΰ€¨ΰ€Ώΰ€·ΰ₯ΰ€•ΰ₯ΰ€°ΰ€Ώΰ€― ΰ€Ήΰ₯ˆΰ€‚: ΰ€…ΰ€‚ΰ€€ΰ€ƒΰ€Έΰ₯ΰ€₯ΰ€Ύΰ€ͺΰ€Ώΰ€€ PDF ΰ€«ΰ₯‰ΰ€¨ΰ₯ΰ€Ÿΰ€Έ ΰ€•ΰ₯‡ ΰ€‰ΰ€ͺΰ€―ΰ₯‹ΰ€— ΰ€ΰ₯‡ΰ€‚ ΰ€…ΰ€Έΰ€ΰ€°ΰ₯ΰ€₯. +document_colors_not_allowed=PDF ΰ€¦ΰ€Έΰ₯ΰ€€ΰ€Ύΰ€΅ΰ₯‡ΰ€œΰ€Ό ΰ€‰ΰ€¨ΰ€•ΰ₯‡ ΰ€…ΰ€ͺΰ€¨ΰ₯‡ ΰ€°ΰ€‚ΰ€— ΰ€•ΰ₯‹ ΰ€‰ΰ€ͺΰ€―ΰ₯‹ΰ€— ΰ€•ΰ€°ΰ€¨ΰ₯‡ ΰ€•ΰ₯‡ ΰ€²ΰ€Ώΰ€ ΰ€…ΰ€¨ΰ₯ΰ€ΰ€€ΰ€Ώ ΰ€ͺΰ₯ΰ€°ΰ€Ύΰ€ͺΰ₯ΰ€€ ΰ€¨ΰ€Ήΰ₯€ΰ€‚ ΰ€Ήΰ₯ˆ: "ΰ€ͺΰ₯ƒΰ€·ΰ₯ΰ€ ΰ₯‹ΰ€‚ ΰ€•ΰ₯‹ ΰ€‰ΰ€¨ΰ€•ΰ₯‡ ΰ€…ΰ€ͺΰ€¨ΰ₯‡ ΰ€°ΰ€‚ΰ€— ΰ€•ΰ₯‹ ΰ€šΰ₯ΰ€¨ΰ€¨ΰ₯‡ ΰ€•ΰ₯‡ ΰ€²ΰ€Ώΰ€ ΰ€Έΰ₯ΰ€΅ΰ₯€ΰ€•ΰ₯ƒΰ€€ΰ€Ώ ΰ€¦ΰ₯‡ΰ€‚" ΰ€•ΰ€Ώ ΰ€΅ΰ€Ή ΰ€‰ΰ€Έ ΰ€¬ΰ₯ΰ€°ΰ€Ύΰ€‰ΰ€œΰ€Όΰ€° ΰ€ΰ₯‡ΰ€‚ ΰ€¨ΰ€Ώΰ€·ΰ₯ΰ€•ΰ₯ΰ€°ΰ€Ώΰ€― ΰ€Ήΰ₯ˆ. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/hr/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/hr/viewer.properties new file mode 100755 index 00000000..ca39552c --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/hr/viewer.properties @@ -0,0 +1,184 @@ +# 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=Prethodna stranica +previous_label=Prethodna +next.title=SljedeΔ‡a stranica +next_label=SljedeΔ‡a + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Stranica +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=od {{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}} od {{pagesCount}}) + +zoom_out.title=UveΔ‡aj +zoom_out_label=Smanji +zoom_in.title=UveΔ‡aj +zoom_in_label=Smanji +zoom.title=UveΔ‡anje +presentation_mode.title=Prebaci u prezentacijski način rada +presentation_mode_label=Prezentacijski način rada +open_file.title=Otvori datoteku +open_file_label=Otvori +print.title=Ispis +print_label=Ispis +download.title=Preuzmi +download_label=Preuzmi +bookmark.title=Trenutni prikaz (kopiraj ili otvori u novom prozoru) +bookmark_label=Trenutni prikaz + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=Alat za označavanje teksta +cursor_hand_tool.title=OmoguΔ‡i ručni alat +cursor_hand_tool_label=Ručni alat + +# Document properties dialog box +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}}" +# will be replaced by the PDF file size in kilobytes, respectively in bytes. +document_properties_kb={{size_kb}} KB ({{size_b}} bajtova) +# 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}} bajtova) +document_properties_title=Naslov: +document_properties_author=Autor: +document_properties_subject=Predmet: +document_properties_keywords=Ključne riječi: +document_properties_creation_date=Datum stvaranja: +document_properties_modification_date=Datum promjene: +# 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=Stvaratelj: +document_properties_producer=PDF stvaratelj: +document_properties_version=PDF inačica: +document_properties_page_count=Broj stranica: +document_properties_close=Zatvori + +print_progress_message=Pripremanje dokumenta za ispis… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Odustani + +# 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=PrikaΕΎi/sakrij bočnu traku +toggle_sidebar_notification.title=Prikazivanje i sklanjanje bočne trake (dokument sadrΕΎi konturu/privitke) +toggle_sidebar_label=PrikaΕΎi/sakrij bočnu traku +document_outline.title=PrikaΕΎi obris dokumenta (dvostruki klik za proΕ‘irivanje/skupljanje svih stavki) +document_outline_label=Obris dokumenta +attachments.title=PrikaΕΎi privitke +attachments_label=Privitci +thumbs.title=PrikaΕΎi sličice +thumbs_label=Sličice +findbar.title=TraΕΎi u dokumentu +findbar_label=TraΕΎi + +# 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=Stranica {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Sličica stranice {{page}} + +# Find panel button title and messages +find_input.title=TraΕΎi +find_input.placeholder=TraΕΎi u dokumentu… +find_previous.title=PronaΔ‘i prethodno javljanje ovog izraza +find_previous_label=Prethodno +find_next.title=PronaΔ‘i iduΔ‡e javljanje ovog izraza +find_next_label=SljedeΔ‡e +find_highlight=Istankni sve +find_match_case_label=Slučaj podudaranja +find_reached_top=Dosegnut vrh dokumenta, nastavak od dna +find_reached_bottom=Dosegnut vrh dokumenta, nastavak od vrha +find_not_found=Izraz nije pronaΔ‘en + +# Error panel labels +error_more_info=ViΕ‘e informacija +error_less_info=Manje informacija +error_close=Zatvori +# 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=Poruka: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Stog: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Datoteka: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Redak: {{line}} +rendering_error=DoΕ‘lo je do greΕ‘ke prilikom iscrtavanja stranice. + +# Predefined zoom values +page_scale_width=Ε irina stranice +page_scale_fit=Pristajanje stranici +page_scale_auto=Automatsko uveΔ‡anje +page_scale_actual=Prava veličina +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=GreΕ‘ka +loading_error=DoΕ‘lo je do greΕ‘ke pri učitavanju PDF-a. +invalid_file_error=Kriva ili oΕ‘teΔ‡ena PDF datoteka. +missing_file_error=Nedostaje PDF datoteka. +unexpected_response_error=Neočekivani odgovor posluΕΎitelja. + +# 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}} BiljeΕ‘ka] +password_label=UpiΕ‘ite lozinku da biste otvorili ovu PDF datoteku. +password_invalid=Neispravna lozinka. PokuΕ‘ajte ponovo. +password_ok=U redu +password_cancel=Odustani + +printing_not_supported=Upozorenje: Ispisivanje nije potpuno podrΕΎano u ovom pregledniku. +printing_not_ready=Upozorenje: PDF nije u potpunosti učitan za ispis. +web_fonts_disabled=Web fontovi su onemoguΔ‡eni: nije moguΔ‡e koristiti umetnute PDF fontove. +document_colors_not_allowed=PDF dokumenti nemaju dopuΕ‘tene koristiti vlastite boje: opcija 'Dopusti stranicama da koriste vlastite boje' je deaktivirana. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/hu/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/hu/viewer.properties new file mode 100755 index 00000000..03990afa --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/hu/viewer.properties @@ -0,0 +1,184 @@ +# 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=ElΕ‘zΕ‘ oldal +previous_label=ElΕ‘zΕ‘ +next.title=KΓΆvetkezΕ‘ oldal +next_label=TovΓ‘bb + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Oldal +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=ΓΆsszesen: {{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=KicsinyΓ­tΓ©s +zoom_out_label=KicsinyΓ­tΓ©s +zoom_in.title=NagyΓ­tΓ‘s +zoom_in_label=NagyΓ­tΓ‘s +zoom.title=NagyΓ­tΓ‘s +presentation_mode.title=VΓ‘ltΓ‘s bemutatΓ³ mΓ³dba +presentation_mode_label=BemutatΓ³ mΓ³d +open_file.title=FΓ‘jl megnyitΓ‘sa +open_file_label=MegnyitΓ‘s +print.title=NyomtatΓ‘s +print_label=NyomtatΓ‘s +download.title=LetΓΆltΓ©s +download_label=LetΓΆltΓ©s +bookmark.title=Jelenlegi nΓ©zet (mΓ‘solΓ‘s vagy megnyitΓ‘s ΓΊj ablakban) +bookmark_label=AktuΓ‘lis nΓ©zet + +# Secondary toolbar and context menu +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 +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 + +# Document properties dialog box +document_properties.title=Dokumentum tulajdonsΓ‘gai… +document_properties_label=Dokumentum tulajdonsΓ‘gai… +document_properties_file_name=FΓ‘jlnΓ©v: +document_properties_file_size=FΓ‘jlmΓ©ret: +# 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}} bΓ‘jt) +# 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}} bΓ‘jt) +document_properties_title=CΓ­m: +document_properties_author=SzerzΕ‘: +document_properties_subject=TΓ‘rgy: +document_properties_keywords=Kulcsszavak: +document_properties_creation_date=LΓ©trehozΓ‘s dΓ‘tuma: +document_properties_modification_date=MΓ³dosΓ­tΓ‘s dΓ‘tuma: +# 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=LΓ©trehozta: +document_properties_producer=PDF elΕ‘Γ‘llΓ­tΓ³: +document_properties_version=PDF verziΓ³: +document_properties_page_count=OldalszΓ‘m: +document_properties_close=BezΓ‘rΓ‘s + +print_progress_message=Dokumentum elΕ‘kΓ©szΓ­tΓ©se nyomtatΓ‘shoz… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=MΓ©gse + +# 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=OldalsΓ‘v be/ki +toggle_sidebar_notification.title=OldalsΓ‘v be/ki (a dokumentum vΓ‘zlatot/mellΓ©kleteket 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 +thumbs.title=BΓ©lyegkΓ©pek megjelenΓ­tΓ©se +thumbs_label=BΓ©lyegkΓ©pek +findbar.title=KeresΓ©s a dokumentumban +findbar_label=KeresΓ©s + +# 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}}. oldal +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas={{page}}. oldal bΓ©lyegkΓ©pe + +# Find panel button title and messages +find_input.title=KeresΓ©s +find_input.placeholder=KeresΓ©s a dokumentumban… +find_previous.title=A kifejezΓ©s elΕ‘zΕ‘ elΕ‘fordulΓ‘sΓ‘nak keresΓ©se +find_previous_label=ElΕ‘zΕ‘ +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_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 +find_not_found=A kifejezΓ©s nem talΓ‘lhatΓ³ + +# Error panel labels +error_more_info=TovΓ‘bbi tudnivalΓ³k +error_less_info=Kevesebb informΓ‘ciΓ³ +error_close=BezΓ‘rΓ‘s +# 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=Üzenet: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=NyomkΓΆvetΓ©s: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=FΓ‘jl: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Sor: {{line}} +rendering_error=Hiba tΓΆrtΓ©nt az oldal feldolgozΓ‘sa kΓΆzben. + +# Predefined zoom values +page_scale_width=OldalszΓ©lessΓ©g +page_scale_fit=Teljes oldal +page_scale_auto=Automatikus nagyΓ­tΓ‘s +page_scale_actual=ValΓ³di mΓ©ret +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Hiba +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. +unexpected_response_error=VΓ‘ratlan kiszolgΓ‘lΓ³vΓ‘lasz. + +# 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}} megjegyzΓ©s] +password_label=Adja meg a jelszΓ³t a PDF fΓ‘jl megnyitΓ‘sΓ‘hoz. +password_invalid=Helytelen jelszΓ³. PrΓ³bΓ‘lja ΓΊjra. +password_ok=OK +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. +document_colors_not_allowed=A PDF dokumentumok nem hasznΓ‘lhatjΓ‘k sajΓ‘t szΓ­neiket: β€žAz oldalak a sajΓ‘t maguk Γ‘ltal kivΓ‘lasztott szΓ­neket hasznΓ‘lhatjΓ‘k” beΓ‘llΓ­tΓ‘s ki van kapcsolva a bΓΆngΓ©szΕ‘ben. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/hy-AM/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/hy-AM/viewer.properties new file mode 100755 index 00000000..5542d8de --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/hy-AM/viewer.properties @@ -0,0 +1,180 @@ +# 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}}-ից\u0020 +# 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=Υ„Υ‘Υ½Υ·ΥΏΥ‘Υ’Υ¨\u0020 +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=ԱբցբΥ₯Υ¬ Υ‘ΥΌΥ‘Υ»Υ«ΥΆ Υ§Υ»Υ«ΥΆ +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=ՊտտΥ₯Υ¬ Υ°Υ‘Υ―Υ‘ΥΌΥ‘Υ― ΥͺՑմՑցուացի Υ½Υ¬Υ‘Φ„Υ« + + +# 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_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_notification.title=Υ“ΥΈΥ­Υ‘ΥΆΥ»Υ‘ΥΏΥ₯Υ¬ ΤΏΥΈΥ²Υ‘Υ΅Υ«ΥΆ Υ£ΥΈΥΏΥ«ΥΆ (ΦƒΥ‘Υ½ΥΏΥ‘Υ©ΥΈΦ‚Υ²Υ©Υ¨ ΥΊΥ‘Φ€ΥΈΦ‚ΥΆΥ‘Υ―ΥΈΦ‚Υ΄ Υ§ ΥΈΦ‚Φ€ΥΎΥ‘Υ£Υ«Υ/կցորՀ) +toggle_sidebar_label=ԲՑցΥ₯Υ¬/Υ“Υ‘Υ―Υ₯Υ¬ ΤΏΥΈΥ²Υ‘Υ΅Υ«ΥΆ ΥΎΥ‘Υ°Υ‘ΥΆΥ‘Υ―Υ¨ +document_outline.title=ՑուցՑՀրΥ₯Υ¬ ΦƒΥ‘Υ½ΥΏΥ‘Υ©Υ²Υ©Υ« ΥΈΦ‚Φ€ΥΎΥ‘Υ£Υ«ΥΥ¨ (Υ―Φ€Υ―ΥΆΥ‘Υ―Υ« Υ½Υ₯Υ²Υ΄Υ₯ք՝ Υ΄Υ«ΥΈΦ‚Υ΅Υ©ΥΆΥ₯Φ€Υ¨ Υ¨ΥΆΥ€Υ‘Φ€Υ±Υ‘Υ―Υ₯Υ¬ΥΈΦ‚/Υ―ΥΈΥΥ―Υ₯Υ¬ΥΈΦ‚ Υ°Υ‘Υ΄Υ‘Φ€) +document_outline_label=Υ“Υ‘Υ½ΥΏΥ‘Υ©Υ²Υ©Υ« Υ’ΥΈΥΎΥ‘ΥΆΥ€Υ‘Υ―ΥΈΦ‚Υ©Υ΅ΥΈΦ‚ΥΆΥ¨ +attachments.title=ՑուցՑՀրΥ₯Υ¬ կցորՀբΥ₯Φ€Υ¨ +attachments_label=ԿցորՀբΥ₯Φ€ +thumbs.title=ՑուցՑՀրΥ₯Υ¬ Υ„Υ‘ΥΆΦ€Υ‘ΥΊΥ‘ΥΏΥ―Υ₯Φ€Υ¨ +thumbs_label=Υ„Υ‘ΥΆΦ€Υ‘ΥΊΥ‘ΥΏΥ―Υ₯Φ€Υ¨ +findbar.title=Τ³ΥΏΥΆΥ₯Υ¬ ΦƒΥ‘Υ½ΥΏΥ‘Υ©Υ²Υ©ΥΈΦ‚Υ΄ +findbar_label=ΥˆΦ€ΥΈΥΆΥΈΦ‚Υ΄ + +# 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_reached_top=Υ€Υ‘Υ½Υ₯Υ¬ Υ₯Φ„ ΦƒΥ‘Υ½ΥΏΥ‘Υ©Υ²Υ©Υ« ΥΎΥ₯Φ€Φ‡Υ«ΥΆ, Υ―Υ·Υ‘Φ€ΥΈΦ‚ΥΆΥ‘Υ―ΥΎΥ« ΥΆΥ₯րքևից +find_reached_bottom=Υ€Υ‘Υ½Υ₯Υ¬ Υ₯Φ„ ΦƒΥ‘Υ½ΥΏΥ‘Υ©Υ²Υ©Υ« ΥΎΥ₯Φ€Υ»Υ«ΥΆ, Υ―Υ·Υ‘Φ€ΥΈΦ‚ΥΆΥ‘Υ―ΥΎΥ« ΥΎΥ₯րևից +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_error_indicator=ՍխՑլ +loading_error=ՍխՑլ՝ PDF Φ†Υ‘Υ΅Υ¬Υ¨ ՒՑցΥ₯Υ¬Υ«Υ½Φ‰ +invalid_file_error=ՍխՑլ Υ―Υ‘Υ΄ Υ’ΥΆΥ‘Υ½ΥΎΥ‘Υ PDF Φ†Υ‘Υ΅Υ¬: +missing_file_error=PDF Φ†Υ‘Υ΅Υ¬Υ¨ ՒՑցՑկՑաում Υ§: +unexpected_response_error=ՍպՑսՑրկիչի Υ‘ΥΆΥ½ΥΊΥ‘Υ½Υ₯Υ¬Υ« ΥΊΥ‘ΥΏΥ‘Υ½Υ­Υ‘ΥΆ: + +# 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 ΥΏΥ‘ΥΌΥ‘ΥΏΥ₯Υ½Υ‘Υ―ΥΆΥ₯Φ€Υ¨: +document_colors_not_allowed=PDF ΦƒΥ‘Υ½ΥΏΥ‘Υ©Υ²Υ©Υ₯Φ€Υ«ΥΆ Υ©ΥΈΦ‚Υ΅Υ¬Υ‘ΥΏΦ€ΥΎΥ‘Υ ΥΉΥ§ Φ…Υ£ΥΏΥ‘Υ£ΥΈΦ€ΥΥ₯Υ¬ Υ«Φ€Υ₯բց Υ½Υ₯ΦƒΥ‘Υ―Υ‘ΥΆ Υ£ΥΈΦ‚Υ΅ΥΆΥ₯Φ€Υ¨: β€œΤΉΥΈΦ‚Υ΅Υ¬Υ‘ΥΏΦ€Υ₯Υ¬ Υ§Υ»Υ₯Φ€Υ«ΥΆ Υ¨ΥΆΥΏΦ€Υ₯Υ¬ Υ«Φ€Υ₯բց Υ½Υ₯ΦƒΥ‘Υ―Υ‘ΥΆ Υ£ΥΈΦ‚Υ΅ΥΆΥ₯Φ€Υ¨β€œ Υ¨ΥΆΥΏΦ€Υ‘ΥΆΦ„Υ¨ Υ‘ΥΆΥ»Υ‘ΥΏΥΎΥ‘Υ Υ§ Υ€Υ«ΥΏΥ‘Φ€Υ―Υ«ΥΉΥΈΦ‚Υ΄: diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/id/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/id/viewer.properties new file mode 100755 index 00000000..fa847e25 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/id/viewer.properties @@ -0,0 +1,184 @@ +# 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=Laman Sebelumnya +previous_label=Sebelumnya +next.title=Laman Selanjutnya +next_label=Selanjutnya + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Halaman +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=dari {{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}} dari {{pagesCount}}) + +zoom_out.title=Perkecil +zoom_out_label=Perkecil +zoom_in.title=Perbesar +zoom_in_label=Perbesar +zoom.title=Perbesaran +presentation_mode.title=Ganti ke Mode Presentasi +presentation_mode_label=Mode Presentasi +open_file.title=Buka Berkas +open_file_label=Buka +print.title=Cetak +print_label=Cetak +download.title=Unduh +download_label=Unduh +bookmark.title=Tampilan Sekarang (salin atau buka di jendela baru) +bookmark_label=Tampilan Sekarang + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=Alat Seleksi Teks +cursor_hand_tool.title=Aktifkan Alat Tangan +cursor_hand_tool_label=Alat Tangan + +# Document properties dialog box +document_properties.title=Properti Dokumen… +document_properties_label=Properti Dokumen… +document_properties_file_name=Nama berkas: +document_properties_file_size=Ukuran berkas: +# 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}} byte) +# 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}} byte) +document_properties_title=Judul: +document_properties_author=Penyusun: +document_properties_subject=Subjek: +document_properties_keywords=Kata Kunci: +document_properties_creation_date=Tanggal Dibuat: +document_properties_modification_date=Tanggal Dimodifikasi: +# 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=Pembuat: +document_properties_producer=Pemroduksi PDF: +document_properties_version=Versi PDF: +document_properties_page_count=Jumlah Halaman: +document_properties_close=Tutup + +print_progress_message=Menyiapkan dokumen untuk pencetakan… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Batalkan + +# 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=Aktif/Nonaktifkan Bilah Samping +toggle_sidebar_notification.title=Aktif/Nonaktifkan Bilah Samping (dokumen berisi kerangka/lampiran) +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 +thumbs.title=Tampilkan Miniatur +thumbs_label=Miniatur +findbar.title=Temukan di Dokumen +findbar_label=Temukan + +# 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=Laman {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Miniatur Laman {{page}} + +# Find panel button title and messages +find_input.title=Temukan +find_input.placeholder=Temukan di dokumen… +find_previous.title=Temukan kata sebelumnya +find_previous_label=Sebelumnya +find_next.title=Temukan lebih lanjut +find_next_label=Selanjutnya +find_highlight=Sorot semuanya +find_match_case_label=Cocokkan BESAR/kecil +find_reached_top=Sampai di awal dokumen, dilanjutkan dari bawah +find_reached_bottom=Sampai di akhir dokumen, dilanjutkan dari atas +find_not_found=Frasa tidak ditemukan + +# Error panel labels +error_more_info=Lebih Banyak Informasi +error_less_info=Lebih Sedikit Informasi +error_close=Tutup +# 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=Pesan: {{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=Berkas: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Baris: {{line}} +rendering_error=Galat terjadi saat merender laman. + +# Predefined zoom values +page_scale_width=Lebar Laman +page_scale_fit=Muat Laman +page_scale_auto=Perbesaran Otomatis +page_scale_actual=Ukuran Asli +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Galat +loading_error=Galat terjadi saat memuat PDF. +invalid_file_error=Berkas PDF tidak valid atau rusak. +missing_file_error=Berkas PDF tidak ada. +unexpected_response_error=Balasan server yang tidak diharapkan. + +# 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=[Anotasi {{type}}] +password_label=Masukkan sandi untuk membuka berkas PDF ini. +password_invalid=Sandi tidak valid. Silakan coba lagi. +password_ok=Oke +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. +document_colors_not_allowed=Dokumen PDF tidak diizinkan untuk menggunakan warnanya sendiri karena setelan 'Izinkan laman memilih warna sendiri' dinonaktifkan pada pengaturan. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/is/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/is/viewer.properties new file mode 100755 index 00000000..2cfd266f --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/is/viewer.properties @@ -0,0 +1,184 @@ +# 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=Fyrri sΓ­Γ°a +previous_label=Fyrri +next.title=NΓ¦sta sΓ­Γ°a +next_label=NΓ¦sti + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=SΓ­Γ°a +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=af {{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}} af {{pagesCount}}) + +zoom_out.title=Minnka +zoom_out_label=Minnka +zoom_in.title=StΓ¦kka +zoom_in_label=StΓ¦kka +zoom.title=AΓ°drΓ‘ttur +presentation_mode.title=Skipta yfir Γ‘ kynningarham +presentation_mode_label=Kynningarhamur +open_file.title=Opna skrΓ‘ +open_file_label=Opna +print.title=Prenta +print_label=Prenta +download.title=Hala niΓ°ur +download_label=Hala niΓ°ur +bookmark.title=NΓΊverandi sΓ½n (afritaΓ°u eΓ°a opnaΓ°u Γ­ nΓ½jum glugga) +bookmark_label=NΓΊverandi sΓ½n + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=TextavalsΓ‘hald +cursor_hand_tool.title=Virkja handarverkfΓ¦ri +cursor_hand_tool_label=HandarverkfΓ¦ri + +# Document properties dialog box +document_properties.title=Eiginleikar skjals… +document_properties_label=Eiginleikar skjals… +document_properties_file_name=SkrΓ‘arnafn: +document_properties_file_size=SkrΓ‘rstΓ¦rΓ°: +# 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=Titill: +document_properties_author=HΓΆnnuΓ°ur: +document_properties_subject=Efni: +document_properties_keywords=StikkorΓ°: +document_properties_creation_date=BΓΊiΓ° til: +document_properties_modification_date=Dags breytingar: +# 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=HΓΆfundur: +document_properties_producer=PDF framleiΓ°andi: +document_properties_version=PDF ΓΊtgΓ‘fa: +document_properties_page_count=BlaΓ°sΓ­Γ°ufjΓΆldi: +document_properties_close=Loka + +print_progress_message=UndirbΓ½ skjal fyrir prentun… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +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Γ‘ +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 +thumbs.title=SΓ½na smΓ‘myndir +thumbs_label=SmΓ‘myndir +findbar.title=Leita Γ­ skjali +findbar_label=Leita + +# 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=SΓ­Γ°a {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=SmΓ‘mynd af sΓ­Γ°u {{page}} + +# Find panel button title and messages +find_input.title=Leita +find_input.placeholder=Leita Γ­ skjali… +find_previous.title=Leita aΓ° fyrra tilfelli ΓΎessara orΓ°a +find_previous_label=Fyrri +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_reached_top=NÑði efst Γ­ skjal, held Γ‘fram neΓ°st +find_reached_bottom=NÑði enda skjals, held Γ‘fram efst +find_not_found=Fann ekki orΓ°iΓ° + +# Error panel labels +error_more_info=Meiri upplΓ½singar +error_less_info=Minni upplΓ½singar +error_close=Loka +# 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=SkilaboΓ°: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Stafli: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=SkrΓ‘: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=LΓ­na: {{line}} +rendering_error=Upp kom villa viΓ° aΓ° birta sΓ­Γ°una. + +# Predefined zoom values +page_scale_width=SΓ­Γ°ubreidd +page_scale_fit=Passa Γ‘ sΓ­Γ°u +page_scale_auto=SjΓ‘lfvirkur aΓ°drΓ‘ttur +page_scale_actual=RaunstΓ¦rΓ° +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Villa +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 (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}} SkΓ½ring] +password_label=SlÑðu inn lykilorΓ° til aΓ° opna ΓΎessa PDF skrΓ‘. +password_invalid=Γ“gilt lykilorΓ°. Reyndu aftur. +password_ok=Í lagi +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. +document_colors_not_allowed=PDF skjΓΆl hafa ekki leyfi til aΓ° nota sΓ­na eigin liti: β€œLeyfa sΓ­Γ°um aΓ° velja eigin liti” er Γ³virkt Γ­ vafranum. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/it/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/it/viewer.properties new file mode 100755 index 00000000..f385aa89 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/it/viewer.properties @@ -0,0 +1,117 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +previous.title = Pagina precedente +previous_label = Precedente +next.title = Pagina successiva +next_label = Successiva +page.title = Pagina +of_pages = di {{pagesCount}} +page_of_pages = ({{pageNumber}} di {{pagesCount}}) +zoom_out.title = Riduci zoom +zoom_out_label = Riduci zoom +zoom_in.title = Aumenta zoom +zoom_in_label = Aumenta zoom +zoom.title = Zoom +presentation_mode.title = Passa alla modalitΓ  presentazione +presentation_mode_label = ModalitΓ  presentazione +open_file.title = Apri file +open_file_label = Apri +print.title = Stampa +print_label = Stampa +download.title = Scarica questo documento +download_label = Download +bookmark.title = Visualizzazione corrente (copia o apri in una nuova finestra) +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 +cursor_text_select_tool_label = Strumento di selezione testo +cursor_hand_tool.title = Attiva strumento mano +cursor_hand_tool_label = Strumento mano +document_properties.title = ProprietΓ  del documento… +document_properties_label = ProprietΓ  del documento… +document_properties_file_name = Nome file: +document_properties_file_size = Dimensione file: +document_properties_kb = {{size_kb}} kB ({{size_b}} byte) +document_properties_mb = {{size_mb}} MB ({{size_b}} byte) +document_properties_title = Titolo: +document_properties_author = Autore: +document_properties_subject = Oggetto: +document_properties_keywords = Parole chiave: +document_properties_creation_date = Data creazione: +document_properties_modification_date = Data modifica: +document_properties_date_string = {{date}}, {{time}} +document_properties_creator = Autore originale: +document_properties_producer = Produttore PDF: +document_properties_version = Versione PDF: +document_properties_page_count = Conteggio pagine: +document_properties_close = Chiudi +print_progress_message = Preparazione documento per la stampa… +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_label = Attiva/disattiva barra laterale +document_outline.title = Visualizza la struttura del documento (doppio clic per visualizzare/nascondere tutti gli elementi) +document_outline_label = Struttura documento +attachments.title = Visualizza allegati +attachments_label = Allegati +thumbs.title = Mostra le miniature +thumbs_label = Miniature +findbar.title = Trova nel documento +findbar_label = Trova +thumb_page_title = Pagina {{page}} +thumb_page_canvas = Miniatura della pagina {{page}} +find_input.title = Trova +find_input.placeholder = Trova nel documento… +find_previous.title = Trova l’occorrenza precedente del testo da cercare +find_previous_label = Precedente +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_reached_top = Raggiunto l’inizio della pagina, continua dalla fine +find_reached_bottom = Raggiunta la fine della pagina, continua dall’inizio +find_not_found = Testo non trovato +error_more_info = Ulteriori informazioni +error_less_info = Nascondi dettagli +error_close = Chiudi +error_version_info = PDF.js v{{version}} (build: {{build}}) +error_message = Messaggio: {{message}} +error_stack = Stack: {{stack}} +error_file = File: {{file}} +error_line = Riga: {{line}} +rendering_error = Si Γ¨ verificato un errore durante il rendering della pagina. +page_scale_width = Larghezza pagina +page_scale_fit = Adatta a una pagina +page_scale_auto = Zoom automatico +page_scale_actual = Dimensioni effettive +page_scale_percent = {{scale}}% +loading_error_indicator = Errore +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. +unexpected_response_error = Risposta imprevista del server +text_annotation_type.alt = [Annotazione: {{type}}] +password_label = Inserire la password per aprire questo file PDF. +password_invalid = Password non corretta. Riprovare. +password_ok = OK +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 inclusi nel PDF. +document_colors_not_allowed = Non Γ¨ possibile visualizzare i colori originali definiti nel file PDF: l’opzione del browser β€œConsenti alle pagine di scegliere i propri colori invece di quelli impostati” Γ¨ disattivata. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ja/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ja/viewer.properties new file mode 100755 index 00000000..4149d9ed --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ja/viewer.properties @@ -0,0 +1,184 @@ +# 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=現在γγƒ“γƒ₯ーだURL です (γ‚³γƒ”γƒΌγΎγŸγ―ζ–°γ—γ„γ‚¦γ‚£γƒ³γƒ‰γ‚¦γ«ι–‹γ) +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=γƒ†γ‚­γ‚ΉγƒˆιΈζŠžγƒ„γƒΌγƒ«γ‚’ζœ‰εŠΉγ«γ™γ‚‹ +cursor_text_select_tool_label=γƒ†γ‚­γ‚ΉγƒˆιΈζŠžγƒ„γƒΌγƒ« +cursor_hand_tool.title=手γγ²γ‚‰γƒ„γƒΌγƒ«γ‚’ζœ‰εŠΉγ«γ™γ‚‹ +cursor_hand_tool_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}} 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=γ‚Ώγ‚€γƒˆγƒ«: +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_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_notification.title=γ‚΅γ‚€γƒ‰γƒγƒΌθ‘¨η€Ίγ‚’εˆ‡γ‚Šζ›ΏγˆγΎγ™ (ζ–‡ζ›Έγ«ε«γΎγ‚Œγ‚‹γ‚’γ‚¦γƒˆγƒ©γ‚€γƒ³ / 添付) +toggle_sidebar_label=ァむドバーγεˆ‡γ‚Šζ›Ώγˆ +document_outline.title=ζ–‡ζ›Έγη›ζ¬‘を葨瀺します (ダブルクγƒͺックで項η›γ‚’開閉します) +document_outline_label=ζ–‡ζ›Έγη›ζ¬‘ +attachments.title=ζ·»δ»˜γƒ•γ‚‘γ‚€γƒ«γ‚’θ‘¨η€Ίγ—γΎγ™ +attachments_label=ζ·»δ»˜γƒ•γ‚‘γ‚€γƒ« +thumbs.title=ηΈε°η‰ˆγ‚’葨瀺します +thumbs_label=ηΈε°η‰ˆ +findbar.title=ζ–‡ζ›Έε†…γ‚’ζ€œη΄’γ—γΎγ™ +findbar_label=怜紒 + +# 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_reached_top=ζ–‡ζ›Έε…ˆι ­γ«εˆ°ι”γ—γŸγγ§ζœ«ε°Ύγ‹γ‚‰ηΆšγ‘γ¦ζ€œη΄’します +find_reached_bottom=ζ–‡ζ›Έζœ«ε°Ύγ«εˆ°ι”γ—γŸγγ§ε…ˆι ­γ‹γ‚‰ηΆšγ‘γ¦ζ€œη΄’します +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_error_indicator=エラー +loading_error=PDF γθͺ­γΏθΎΌγΏδΈ­γ«γ‚¨γƒ©γƒΌγŒη™Ίη”Ÿγ—γΎγ—γŸγ€‚ +invalid_file_error=η„‘εŠΉγΎγŸγ―η ΄ζγ—γŸ PDF フゑむル。 +missing_file_error=PDF γƒ•γ‚‘γ‚€γƒ«γŒθ¦‹γ€γ‹γ‚ŠγΎγ›γ‚“γ€‚ +unexpected_response_error=γ‚΅γƒΌγƒγƒΌγ‹γ‚‰δΊˆζœŸγ›γ¬εΏœη­”γŒγ‚γ‚ŠγΎγ—γŸγ€‚ + +# 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=OK +password_cancel=キャンセル + +printing_not_supported=θ­¦ε‘Š: こγγƒ–ラウアーでは印刷がεŒε…¨γ«γ‚΅γƒγƒΌγƒˆγ•γ‚Œγ¦γ„γΎγ›γ‚“γ€‚ +printing_not_ready=θ­¦ε‘Š: PDF γ‚’ε°εˆ·γ™γ‚‹γŸγ‚γθͺ­γΏθΎΌγΏγŒη΅‚了していません。 +web_fonts_disabled=γ‚¦γ‚§γƒ–γƒ•γ‚©γƒ³γƒˆγŒη„‘εŠΉγ«γͺっています: εŸ‹γ‚θΎΌγΎγ‚ŒγŸ PDF γγƒ•γ‚©γƒ³γƒˆγ‚’δ½Ώη”¨γ§γγΎγ›γ‚“γ€‚ +document_colors_not_allowed=PDF ζ–‡ζ›Έγ―γ€γ‚¦γ‚§γƒ–γƒšγƒΌγ‚ΈγŒζŒ‡εšγ—γŸι…θ‰²γ‚’δ½Ώη”¨γ™γ‚‹γ“γ¨γŒγ§γγΎγ›γ‚“: 'γ‚¦γ‚§γƒ–γƒšγƒΌγ‚ΈγŒζŒ‡εšγ—γŸι…θ‰²' γ―γƒ–γƒ©γ‚¦γ‚ΆγƒΌγ§η„‘εŠΉγ«γͺっています。 diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ka/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ka/viewer.properties new file mode 100755 index 00000000..ac033c22 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ka/viewer.properties @@ -0,0 +1,184 @@ +# 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=αƒžαƒ˜αƒ αƒ•αƒ”αƒš გვერდზე αƒ’αƒαƒ“αƒαƒ‘αƒ•αƒšαƒ +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_label=αƒ›αƒαƒ‘αƒαƒœαƒ˜αƒ¨αƒœαƒ˜ αƒ™αƒ£αƒ αƒ‘αƒαƒ αƒ˜ +cursor_hand_tool.title=αƒ’αƒαƒ“αƒαƒ‘αƒαƒαƒ“αƒ’αƒ˜αƒšαƒ”αƒ‘αƒ”αƒšαƒ˜ αƒ™αƒ£αƒ αƒ‘αƒαƒ αƒ˜αƒ‘ ჩართვა +cursor_hand_tool_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_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_notification.title=αƒ’αƒ•αƒ”αƒ αƒ“αƒ˜αƒ—αƒ αƒ–αƒαƒšαƒ˜αƒ‘ ჩართვა/გამორთვა (αƒ“αƒαƒ™αƒ£αƒ›αƒ”αƒœαƒ’αƒ˜ αƒ¨αƒ”αƒ˜αƒͺავბ მოαƒαƒαƒ–αƒ£αƒšαƒαƒ‘αƒ/αƒ“αƒαƒœαƒαƒ αƒ—αƒ‘) +toggle_sidebar_label=αƒ’αƒ•αƒ”αƒ αƒ“αƒ˜αƒ—αƒ αƒ–αƒαƒšαƒ˜αƒ‘ αƒ’αƒαƒ›αƒαƒ©αƒ”αƒœαƒ +document_outline.title=αƒ“αƒαƒ™αƒ£αƒ›αƒ”αƒœαƒ’αƒ˜αƒ‘ მოαƒαƒαƒ–αƒ£αƒšαƒαƒ‘αƒ˜αƒ‘ αƒ©αƒ•αƒ”αƒœαƒ”αƒ‘αƒ (ორჯერ αƒ“αƒαƒ¬αƒ™αƒαƒžαƒ”αƒ‘αƒ˜αƒ— αƒ§αƒ•αƒ”αƒšαƒ αƒ”αƒšαƒ”αƒ›αƒ”αƒœαƒ’αƒ˜αƒ‘ αƒ’αƒαƒ¨αƒšαƒ/აკეαƒͺვა) +document_outline_label=αƒ“αƒαƒ™αƒ£αƒ›αƒ”αƒœαƒ’αƒ˜αƒ‘ მოαƒαƒαƒ–αƒ£αƒšαƒαƒ‘αƒ +attachments.title=αƒ“αƒαƒœαƒαƒ αƒ—αƒ”αƒ‘αƒ˜αƒ‘ αƒ©αƒ•αƒ”αƒœαƒ”αƒ‘αƒ +attachments_label=αƒ“αƒαƒœαƒαƒ αƒ—αƒ”αƒ‘αƒ˜ +thumbs.title=αƒ”αƒ‘αƒ™αƒ˜αƒ–αƒ”αƒ‘αƒ˜αƒ‘ αƒ©αƒ•αƒ”αƒœαƒ”αƒ‘αƒ +thumbs_label=αƒ”αƒ‘αƒ™αƒ˜αƒ–αƒ”αƒ‘αƒ˜ +findbar.title=αƒ«αƒ˜αƒ”αƒ‘αƒ αƒ“αƒαƒ™αƒ£αƒ›αƒ”αƒœαƒ’αƒ¨αƒ˜ +findbar_label=αƒ«αƒ˜αƒ”αƒ‘αƒ + +# 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_reached_top=αƒ›αƒ˜αƒ¦αƒ¬αƒ”αƒ£αƒšαƒ˜αƒ αƒ“αƒαƒ™αƒ£αƒ›αƒ”αƒœαƒ’αƒ˜αƒ‘ ზედა αƒ¬αƒ”αƒ αƒ’αƒ˜αƒšαƒαƒ›αƒ“αƒ”, αƒ’αƒ αƒ«αƒ”αƒšαƒ“αƒ”αƒ‘αƒ αƒ₯αƒ•αƒ”αƒ›αƒαƒ“αƒαƒœ +find_reached_bottom=αƒ›αƒ˜αƒ¦αƒ¬αƒ”αƒ£αƒšαƒ˜αƒ αƒ“αƒαƒ™αƒ£αƒ›αƒ”αƒœαƒ’αƒ˜αƒ‘ αƒ‘αƒαƒšαƒ αƒ¬αƒ”αƒ αƒ’αƒ˜αƒšαƒαƒ›αƒ“αƒ”, αƒ’αƒ αƒ«αƒ”αƒšαƒ“αƒ”αƒ‘αƒ αƒ–αƒ”αƒ›αƒαƒ“αƒαƒœ +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_indicator=შეαƒͺდომა +loading_error=PDF-αƒ˜αƒ‘ αƒ©αƒαƒ’αƒ•αƒ˜αƒ αƒ—αƒ•αƒ˜αƒ‘αƒαƒ‘ αƒ“αƒαƒ€αƒ˜αƒ₯αƒ‘αƒ˜αƒ αƒ“αƒ შეαƒͺდომა. +invalid_file_error=αƒαƒ αƒαƒ›αƒαƒ αƒ—αƒ”αƒ‘αƒ£αƒšαƒ˜ αƒαƒœ αƒ“αƒαƒ–αƒ˜αƒαƒœαƒ”αƒ‘αƒ£αƒšαƒ˜ PDF αƒ€αƒαƒ˜αƒšαƒ˜. +missing_file_error=αƒœαƒαƒ™αƒšαƒ£αƒšαƒ˜ PDF αƒ€αƒαƒ˜αƒšαƒ˜. +unexpected_response_error=αƒ‘αƒ”αƒ αƒ•αƒ”αƒ αƒ˜αƒ‘ αƒ›αƒαƒ£αƒšαƒαƒ“αƒœαƒ”αƒšαƒ˜ αƒžαƒαƒ‘αƒ£αƒαƒ˜. + +# 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 αƒ¨αƒ αƒ˜αƒ€αƒ’αƒ”αƒ‘αƒ˜αƒ‘ αƒ’αƒαƒ›αƒαƒ§αƒ”αƒœαƒ”αƒ‘αƒ ვერ αƒαƒ”αƒ αƒαƒ“ება. +document_colors_not_allowed=PDF αƒ“αƒαƒ™αƒ£αƒ›αƒ”αƒœαƒ’αƒ”αƒ‘αƒ‘ არ აαƒ₯ვთ αƒ‘αƒαƒ™αƒ£αƒ—αƒαƒ αƒ˜ αƒ€αƒ”αƒ αƒ”αƒ‘αƒ˜αƒ‘ αƒ’αƒαƒ›αƒαƒ§αƒ”αƒœαƒ”αƒ‘αƒ˜αƒ‘ αƒ£αƒ€αƒšαƒ”αƒ‘αƒ: αƒ‘αƒ αƒαƒ£αƒ–αƒ”αƒ αƒ¨αƒ˜ αƒ’αƒαƒ›αƒαƒ αƒ—αƒ£αƒšαƒ˜αƒ "αƒ’αƒ•αƒ”αƒ αƒ“αƒ”αƒ‘αƒ˜αƒ‘αƒ—αƒ•αƒ˜αƒ‘ αƒ‘αƒαƒ™αƒ£αƒ—αƒαƒ αƒ˜ αƒ€αƒ”αƒ αƒ”αƒ‘αƒ˜αƒ‘ αƒ’αƒαƒ›αƒαƒ§αƒ”αƒœαƒ”αƒ‘αƒ˜αƒ‘ αƒ£αƒ€αƒšαƒ”αƒ‘αƒ". diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/kk/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/kk/viewer.properties new file mode 100755 index 00000000..a4011081 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/kk/viewer.properties @@ -0,0 +1,184 @@ +# 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=Ал“Π°Ρˆ›Ρ‹ ΠΏΠ°Ρ€Π°››Π° Σ©Ρ‚Ρƒ +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_label=ΠœΣ™Ρ‚Ρ–Π½Π΄Ρ– Ρ‚Π°£Π΄Π°Ρƒ сайманы +cursor_hand_tool.title=šΠΎΠ» сайманын іскС ›ΠΎΡΡƒ +cursor_hand_tool_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_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_notification.title=Π‘―ΠΉΡ–Ρ€ ΠΏΠ°Π½Π΅Π»Ρ–Π½ көрсСту/Тасыру (›±ΠΆΠ°Ρ‚Ρ‚Π° ›±Ρ€Ρ‹Π»Ρ‹ΠΌΡ‹/салынымдар Π±Π°Ρ€) +toggle_sidebar_label=Π‘―ΠΉΡ–Ρ€ ΠΏΠ°Π½Π΅Π»Ρ–Π½ көрсСту/Тасыру +document_outline.title=š±ΠΆΠ°Ρ‚ ›±Ρ€Ρ‹Π»Ρ‹ΠΌΡ‹Π½ көрсСту (Π±Π°Ρ€Π»Ρ‹› нәрсСлСрді ΠΆΠ°Π·Ρ‹› ›Ρ‹Π»Ρƒ/ΠΆΠΈΠ½Π°Ρƒ ―ΡˆΡ–Π½ ›ΠΎΡ ΡˆΠ΅Ρ€Ρ‚Ρƒ ΠΊΠ΅Ρ€Π΅ΠΊ) +document_outline_label=š±ΠΆΠ°Ρ‚ ›±Ρ€Π°ΠΌΠ°ΡΡ‹ +attachments.title=Π‘Π°Π»Ρ‹Π½Ρ‹ΠΌΠ΄Π°Ρ€Π΄Ρ‹ көрсСту +attachments_label=Π‘Π°Π»Ρ‹Π½Ρ‹ΠΌΠ΄Π°Ρ€ +thumbs.title=ΠšΡ–ΡˆΡ– көріністСрді көрсСту +thumbs_label=ΠšΡ–ΡˆΡ– көріністСр +findbar.title=š±ΠΆΠ°Ρ‚Ρ‚Π°Π½ Ρ‚Π°Π±Ρƒ +findbar_label=Π’Π°Π±Ρƒ + +# 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_reached_top=š±ΠΆΠ°Ρ‚Ρ‚Ρ‹£ басына ΠΆΠ΅Ρ‚Ρ‚Ρ–ΠΊ, со£Ρ‹Π½Π°Π½ бастап ΠΆΠ°Π»“астырамыз +find_reached_bottom=š±ΠΆΠ°Ρ‚Ρ‚Ρ‹£ со£Ρ‹Π½Π° ΠΆΠ΅Ρ‚Ρ‚Ρ–ΠΊ, басынан бастап ΠΆΠ°Π»“астырамыз +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_error_indicator=šΠ°Ρ‚Π΅ +loading_error=PDF ΠΆ―ΠΊΡ‚Π΅Ρƒ ΠΊΠ΅Π·Ρ–Π½Π΄Π΅ ›Π°Ρ‚Π΅ ΠΊΠ΅Ρ‚Ρ‚Ρ–. +invalid_file_error=Π—Π°›Ρ‹ΠΌΠ΄Π°Π»“Π°Π½ нСмСсС ›Π°Ρ‚Π΅ PDF Ρ„Π°ΠΉΠ». +missing_file_error=PDF Ρ„Π°ΠΉΠ»Ρ‹ ΠΆΠΎ›. +unexpected_response_error=Π‘Π΅Ρ€Π²Π΅Ρ€Π΄Ρ–£ ΠΊ―Ρ‚ΠΏΠ΅Π³Π΅Π½ ΠΆΠ°ΡƒΠ°Π±Ρ‹. + +# 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 ›Π°Ρ€Ρ–ΠΏΡ‚Π΅Ρ€Ρ–Π½ ›ΠΎΠ»Π΄Π°Π½Ρƒ ΠΌ―ΠΌΠΊΡ–Π½ СмСс. +document_colors_not_allowed=PDF ›±ΠΆΠ°Ρ‚Ρ‚Π°Ρ€Ρ‹Π½Π° Σ©Π·Π΄Ρ–ΠΊ Ρ‚―стСрді ›ΠΎΠ»Π΄Π°Π½Ρƒ Ρ€±›ΡΠ°Ρ‚ Π΅Ρ‚Ρ–Π»ΠΌΠ΅Π³Π΅Π½: Π±±Π» Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΄Π΅ 'Π’Π΅Π±-сайттар“Π° Σ©Π·Π΄Π΅Ρ€Ρ–Π½Ρ–£ Ρ‚―стСрін ›ΠΎΠ»Π΄Π°Π½Ρƒ“Π° Ρ€±›ΡΠ°Ρ‚ Π±Π΅Ρ€Ρƒ' ΠΌ―ΠΌΠΊΡ–Π½Π΄Ρ–Π³Ρ– сөндірулі Ρ‚±Ρ€. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/km/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/km/viewer.properties new file mode 100755 index 00000000..e5403cc1 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/km/viewer.properties @@ -0,0 +1,184 @@ +# 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=αž‘αŸ…αž€αžΆαž“αŸ‹β€‹αž‘αŸ†αž–αŸαžšβ€‹αžŠαŸ†αž”αžΌαž„β€‹ +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_label=αž§αž”αž€αžšαžŽαŸβ€‹αž‡αŸ’αžšαžΎαžŸβ€‹αž’αžαŸ’αžαž”αž‘ +cursor_hand_tool.title=αž”αžΎαž€β€‹αž§αž”αž€αžšαžŽαŸβ€‹αžŠαŸƒ +cursor_hand_tool_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}} 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_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_notification.title=αž”αž·αž‘/αž”αžΎαž€β€‹αžšαž”αžΆαžšβ€‹αž…αŸ†αž αŸ€αž„ (αž―αž€αžŸαžΆαžšβ€‹αž˜αžΆαž“β€‹αž˜αžΆαžαž·αž€αžΆβ€‹αž“αŸ…β€‹αž€αŸ’αžšαŸ…/attachments) +toggle_sidebar_label=αž”αž·αž‘/αž”αžΎαž€β€‹αž‚αŸ’αžšαžΆαž”αŸ‹β€‹αžšαŸ†αž€αž·αž› +document_outline.title=αž”αž„αŸ’αž αžΆαž‰β€‹αž‚αŸ’αžšαŸ„αž„β€‹αž―αž€αžŸαžΆαžš (αž…αž»αž…β€‹αž‘αŸ’αžœαŸβ€‹αžŠαž„β€‹αžŠαžΎαž˜αŸ’αž”αžΈβ€‹αž–αž„αŸ’αžšαžΈαž€/αž”αž„αŸ’αžšαž½αž˜β€‹αž’αžΆαžαž»β€‹αž‘αžΆαŸ†αž„αž’αžŸαŸ‹) +document_outline_label=αž‚αŸ’αžšαŸ„αž„β€‹αž―αž€αžŸαžΆαžš +attachments.title=αž”αž„αŸ’αž αžΆαž‰β€‹αž―αž€αžŸαžΆαžšβ€‹αž—αŸ’αž‡αžΆαž”αŸ‹ +attachments_label=αž―αž€αžŸαžΆαžšβ€‹αž—αŸ’αž‡αžΆαž”αŸ‹ +thumbs.title=αž”αž„αŸ’αž αžΆαž‰β€‹αžšαžΌαž”αž—αžΆαž–β€‹αžαžΌαž…αŸ— +thumbs_label=αžšαž½αž”αž—αžΆαž–β€‹αžαžΌαž…αŸ— +findbar.title=αžšαž€β€‹αž“αŸ…β€‹αž€αŸ’αž“αž»αž„β€‹αž―αž€αžŸαžΆαžš +findbar_label=αžšαž€ + +# 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_reached_top=αž”αžΆαž“β€‹αž”αž“αŸ’αžβ€‹αž–αžΈβ€‹αžαžΆαž„β€‹αž€αŸ’αžšαŸ„αž˜ αž‘αŸ…β€‹αžŠαž›αŸ‹β€‹αžαžΆαž„β€‹β€‹αž›αžΎβ€‹αž“αŸƒβ€‹αž―αž€αžŸαžΆαžš +find_reached_bottom=αž”αžΆαž“β€‹αž”αž“αŸ’αžβ€‹αž–αžΈβ€‹αžαžΆαž„αž›αžΎ αž‘αŸ…αžŠαž›αŸ‹β€‹αž…αž»αž„β€‹β€‹αž“αŸƒβ€‹αž―αž€αžŸαžΆαžš +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_indicator=αž€αŸ†αž αž»αžŸ +loading_error=αž˜αžΆαž“β€‹αž€αŸ†αž αž»αžŸβ€‹αž”αžΆαž“β€‹αž€αžΎαžαž‘αžΎαž„β€‹αž–αŸαž›β€‹αž€αŸ†αž–αž»αž„β€‹αž•αŸ’αž‘αž»αž€ PDFΒ αŸ” +invalid_file_error=αž―αž€αžŸαžΆαžš PDF αžαžΌαž… αž¬β€‹αž˜αž·αž“β€‹αžαŸ’αžšαžΉαž˜αžαŸ’αžšαžΌαžœΒ αŸ” +missing_file_error=αž”αžΆαžαŸ‹β€‹αž―αž€αžŸαžΆαžš PDF +unexpected_response_error=αž€αžΆαžšβ€‹αž†αŸ’αž›αžΎαž™β€‹αžαž˜β€‹αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“β€‹αž˜αŸβ€‹αžŠαŸ‚αž›β€‹αž˜αž·αž“β€‹αž”αžΆαž“β€‹αžšαŸ†αž–αžΉαž„αŸ” + +# 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 αžŠαŸ‚αž›β€‹αž”αžΆαž“β€‹αž”αž„αŸ’αž€αž”αŸ‹β€‹αž”αžΆαž“β€‹αž‘αŸΒ αŸ” +document_colors_not_allowed=αž―αž€αžŸαžΆαžš PDF αž˜αž·αž“β€‹αžαŸ’αžšαžΌαžœβ€‹αž”αžΆαž“β€‹αž’αž“αž»αž‰αŸ’αž‰αžΆαžβ€‹αž²αŸ’αž™β€‹αž”αŸ’αžšαžΎβ€‹αž–αžŽαŸŒβ€‹αž•αŸ’αž‘αžΆαž›αŸ‹β€‹αžšαž”αžŸαŸ‹β€‹αžœαžΆβ€‹αž‘αŸαŸ– 'αž’αž“αž»αž‰αŸ’αž‰αžΆαžβ€‹β€‹αž²αŸ’αž™β€‹αž‘αŸ†αž–αŸαžšβ€‹αž‡αŸ’αžšαžΎαžŸβ€‹αž–αžŽαŸŒβ€‹αž•αŸ’αž‘αžΆαž›αŸ‹β€‹αžαŸ’αž›αž½αž“' αžαŸ’αžšαžΌαžœβ€‹αž”αžΆαž“β€‹αž’αŸ’αžœαžΎβ€‹αž²αŸ’αž™β€‹αž’αžŸαž€αž˜αŸ’αž˜β€‹αž€αŸ’αž“αž»αž„β€‹β€‹αž€αž˜αŸ’αž˜αžœαž·αž’αžΈβ€‹αžšαž»αž€αžšαž€αŸ” diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/kn/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/kn/viewer.properties new file mode 100755 index 00000000..7b2dc170 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/kn/viewer.properties @@ -0,0 +1,169 @@ +# 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. +# 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. + +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=ΰ²ΰ³Šΰ²¦ΰ²² ΰ²ͺΰ³ΰ²Ÿΰ²•ΰ³ΰ²•ΰ³† ಀೆರಳು +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=ΰ²…ΰ²ͺ್ರದಕ್ಷಿಣೆಯಲ್ಲಿ ಀಿರುಗಿಸು + + +# 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}} 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_close=ΰ²ΰ³ΰ²šΰ³ΰ²šΰ³ + +# 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) +toggle_sidebar.title=ಬದಿΰ²ͺಟ್ಟಿಯನ್ನು ಹೊರಳಿಸು +toggle_sidebar_label=ಬದಿΰ²ͺಟ್ಟಿಯನ್ನು ಹೊರಳಿಸು +document_outline_label=ΰ²¦ΰ²Έΰ³ΰ²€ΰ²Ύΰ²΅ΰ³‡ΰ²œΰ²Ώΰ²¨ ΰ²Ήΰ³Šΰ²°ΰ²°ΰ³‡ΰ²–ΰ³† +attachments.title=ಲಗಀ್ಀುಗಳನ್ನು ಀೋರಿಸು +attachments_label=ಲಗಀ್ಀುಗಳು +thumbs.title=ΰ²šΰ²Ώΰ²•ΰ³ΰ²•ΰ²šΰ²Ώΰ²€ΰ³ΰ²°ΰ²¦ΰ²‚ΰ²€ΰ³† ಀೋರಿಸು +thumbs_label=ΰ²šΰ²Ώΰ²•ΰ³ΰ²•ΰ²šΰ²Ώΰ²€ΰ³ΰ²°ΰ²—ΰ²³ΰ³ +findbar.title=ΰ²¦ΰ²Έΰ³ΰ²€ΰ²Ύΰ²΅ΰ³‡ΰ²œΰ²Ώΰ²¨ΰ²²ΰ³ΰ²²ΰ²Ώ ಹು಑ುಕು + +# 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_previous_label=ಹಿಂದಿನ +find_next.title=ಡಾಕ್ಯದ ΰ²ΰ³ΰ²‚ದಿನ ಇರುಡಿಕೆಯನ್ನು ಹು಑ುಕು +find_next_label=ΰ²ΰ³ΰ²‚ದಿನ +find_highlight=ಎಲ್ಲಡನ್ನು ಹೈಲೈಟ್ ΰ²ΰ²Ύΰ²‘ು +find_match_case_label=ಕೇಸನ್ನು ΰ²Ήΰ³Šΰ²‚ΰ²¦ΰ²Ώΰ²Έΰ³ +find_reached_top=ΰ²¦ΰ²Έΰ³ΰ²€ΰ²Ύΰ²΅ΰ³‡ΰ²œΰ²Ώΰ²¨ ΰ²ΰ³‡ΰ²²ΰ³ΰ²­ΰ²Ύΰ²—ಡನ್ನು ಀಲುΰ²ͺಿದೆ, ಕೆಳಗಿನಿಂದ ಆರಂಭಿಸು +find_reached_bottom=ΰ²¦ΰ²Έΰ³ΰ²€ΰ²Ύΰ²΅ΰ³‡ΰ²œΰ²Ώΰ²¨ ΰ²•ΰ³Šΰ²¨ΰ³†ΰ²―ΰ²¨ΰ³ΰ²¨ΰ³ ಀಲುΰ²ͺಿದೆ, ΰ²ΰ³‡ΰ²²ΰ²Ώΰ²¨ΰ²Ώΰ²‚ದ ಆರಂಭಿಸು +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_indicator=ದೋಷ +loading_error=PDF ಅನ್ನು ಲೋ಑್ ΰ²ΰ²Ύΰ²‘ುಡಾಗ ಒಂದು ದೋಷ ΰ²Žΰ²¦ΰ³ΰ²°ΰ²Ύΰ²—ΰ²Ώΰ²¦ΰ³†. +invalid_file_error=ΰ²…ΰ²ΰ²Ύΰ²¨ΰ³ΰ²―ಡಾದ ΰ²…ΰ²₯ಡ ಹಾಳಾದ PDF ಕ಑ಀ. +missing_file_error=PDF ಕ಑ಀ ಇಲ್ಲ. +unexpected_response_error=ಅನಿರೀಕ್ಷಿಀಡಾದ ΰ²ͺΰ³‚ΰ²°ΰ³ˆΰ²•ΰ³†ΰ²—ΰ²£ΰ²•ΰ²¦ ΰ²ͺ್ರಀಿಕ್ರಿಯೆ. + +# 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=OK + +printing_not_supported=ΰ²Žΰ²šΰ³ΰ²šΰ²°ΰ²Ώΰ²•ΰ³†: ಈ ΰ²œΰ²Ύΰ²²ΰ²΅ΰ³€ΰ²•ΰ³ΰ²·ΰ²•ΰ²¦ΰ²²ΰ³ΰ²²ΰ²Ώ ΰ²ΰ³ΰ²¦ΰ³ΰ²°ΰ²£ΰ²•್ಕೆ ಸಂΰ²ͺೂರ್ಣ ಬೆಂಬಲಡಿಲ್ಲ. +printing_not_ready=ΰ²Žΰ²šΰ³ΰ²šΰ²°ΰ²Ώΰ²•ΰ³†: PDF ಕ಑ಀಡು ΰ²ΰ³ΰ²¦ΰ³ΰ²°ΰ²Ώΰ²Έΰ²²ΰ³ ಸಂΰ²ͺೂರ್ಣಡಾಗಿ ಲೋ಑್ ಆಗಿಲ್ಲ. +web_fonts_disabled=ಜಾಲ ΰ²…ΰ²•ΰ³ΰ²·ΰ²°ΰ²Άΰ³ˆΰ²²ΰ²Ώΰ²―ΰ²¨ΰ³ΰ²¨ΰ³ ΰ²¨ΰ²Ώΰ²·ΰ³ΰ²•ΰ³ΰ²°ΰ²Ώΰ²―ΰ²—ΰ³Šΰ²³ΰ²Ώΰ²Έΰ²²ΰ²Ύΰ²—ΰ²Ώΰ²¦ΰ³†: ΰ²…ΰ²‘ΰ²•ΰ²—ΰ³Šΰ²³ΰ²Ώΰ²Έΰ²Ώΰ²¦ PDF ΰ²…ΰ²•ΰ³ΰ²·ΰ²°ΰ²Άΰ³ˆΰ²²ΰ²Ώΰ²—ΰ²³ΰ²¨ΰ³ΰ²¨ΰ³ ಬಳಸಲು ಸಾಧ್ಯಡಾಗಿಲ್ಲ. +document_colors_not_allowed=PDF ΰ²¦ΰ²Έΰ³ΰ²€ΰ²Ύΰ²΅ΰ³‡ΰ²œΰ³ΰ²—ΰ²³ΰ³ ΰ²€ΰ²ΰ³ΰ²ΰ²¦ΰ³† ಆದ ಬಣ್ಣಗಳನ್ನು ಬಳಸಲು ಅನುΰ²ΰ²€ΰ²Ώ ಇರುಡುದಿಲ್ಲ: 'ΰ²ͺΰ³ΰ²Ÿΰ²—ΰ²³ΰ³ ΰ²€ΰ²ΰ³ΰ²ΰ²¦ΰ³† ಆದ ಬಣ್ಣಡನ್ನು ಆಯ್ಕೆ ΰ²ΰ²Ύΰ²‘ಲು ಅನುΰ²ΰ²€ΰ²Ώΰ²Έΰ³' ಅನ್ನು ΰ²œΰ²Ύΰ²²ΰ²΅ΰ³€ΰ²•ΰ³ΰ²·ΰ²•ΰ²¦ΰ²²ΰ³ΰ²²ΰ²Ώ ΰ²¨ΰ²Ώΰ²·ΰ³ΰ²•ΰ³ΰ²°ΰ²Ώΰ²―ΰ²—ΰ³Šΰ²³ΰ²Ώΰ²Έΰ²²ΰ²Ύΰ²—ΰ²Ώΰ²°ΰ³ΰ²€ΰ³ΰ²€ΰ²¦ΰ³†. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ko/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ko/viewer.properties new file mode 100755 index 00000000..ea3732b7 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ko/viewer.properties @@ -0,0 +1,184 @@ +# 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=({{pagesCount}} 쀑 {{pageNumber}}) + +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=첫 νŽ˜μ΄μ§€λ‘œ 이동 +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_label=ν…μŠ€νŠΈ 선택 도ꡬ +cursor_hand_tool.title=손 도ꡬ ν™œμ„±ν™” +cursor_hand_tool_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}} 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_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_notification.title=탐색창 μ—΄κ³  λ‹«κΈ° (λ¬Έμ„œμ— μ•„μ›ƒλΌμΈμ΄λ‚˜ μ²¨λΆ€νŒŒμΌμ΄ λ“€μ–΄μžˆμŒ) +toggle_sidebar_label=탐색창 μ—΄κ³  λ‹«κΈ° +document_outline.title=λ¬Έμ„œ 아웃라인 보기(더블 ν΄λ¦­ν•΄μ„œ λͺ¨λ“  ν•­λͺ© μ—΄κ³  λ‹«κΈ°) +document_outline_label=λ¬Έμ„œ 아웃라인 +attachments.title=μ²¨λΆ€νŒŒμΌ 보기 +attachments_label=μ²¨λΆ€νŒŒμΌ +thumbs.title=미리보기 +thumbs_label=미리보기 +findbar.title=검색 +findbar_label=검색 + +# 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=μ§€μ • λ¬Έμžμ—΄μ— μΌμΉ˜ν•˜λŠ” 1개 뢀뢄을 검색 +find_previous_label=이전 +find_next.title=μ§€μ • λ¬Έμžμ—΄μ— μΌμΉ˜ν•˜λŠ” λ‹€μŒ 뢀뢄을 검색 +find_next_label=λ‹€μŒ +find_highlight=λͺ¨λ‘ κ°•μ‘° ν‘œμ‹œ +find_match_case_label=λŒ€λ¬Έμž/μ†Œλ¬Έμž ꡬ별 +find_reached_top=λ¬Έμ„œ μ²˜μŒκΉŒμ§€ κ²€μƒ‰ν•˜κ³  끝으둜 λŒμ•„μ™€ κ²€μƒ‰ν–ˆμŠ΅λ‹ˆλ‹€. +find_reached_bottom=λ¬Έμ„œ λκΉŒμ§€ κ²€μƒ‰ν•˜κ³  μ•žμœΌλ‘œ λŒμ•„μ™€ κ²€μƒ‰ν–ˆμŠ΅λ‹ˆλ‹€. +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_error_indicator=였λ₯˜ +loading_error=PDFλ₯Ό μ½λŠ” 쀑 였λ₯˜κ°€ μƒκ²ΌμŠ΅λ‹ˆλ‹€. +invalid_file_error=μœ νš¨ν•˜μ§€ μ•Šκ±°λ‚˜ νŒŒμ†λœ PDF 파일 +missing_file_error=PDF 파일이 μ—†μŠ΅λ‹ˆλ‹€. +unexpected_response_error=μ•Œ 수 μ—†λŠ” μ„œλ²„ μ‘λ‹΅μž…λ‹ˆλ‹€. + +# 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 글꼴을 μ“Έ 수 μ—†μŠ΅λ‹ˆλ‹€. +document_colors_not_allowed=PDF λ¬Έμ„œμ˜ 색상을 μ“°μ§€ λͺ»ν•˜κ²Œ λ˜μ–΄ 있음: 'μ›Ή νŽ˜μ΄μ§€ 자체 색상 μ‚¬μš© ν—ˆμš©'이 λΈŒλΌμš°μ €μ—μ„œ κΊΌμ Έ μžˆμŠ΅λ‹ˆλ‹€. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ku/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ku/viewer.properties new file mode 100755 index 00000000..c3462f67 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ku/viewer.properties @@ -0,0 +1,146 @@ +# 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=RΓ»pela berΓͺ +previous_label=Paşve +next.title=RΓ»pela pΓͺş +next_label=PΓͺş + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +zoom_out.title=DΓ»r bike +zoom_out_label=DΓ»r bike +zoom_in.title=NΓͺzΓk bike +zoom_in_label=NΓͺzΓk bike +zoom.title=NΓͺzΓk Bike +presentation_mode.title=DerbasΓ mΓ»da pΓͺşkΓͺşkariyΓͺ bibe +presentation_mode_label=Moda PΓͺşkΓͺşkariyΓͺ +open_file.title=PelΓ veke +open_file_label=Veke +print.title=Γ‡ap bike +print_label=Γ‡ap bike +download.title=JΓͺbar bike +download_label=JΓͺbar bike +bookmark.title=Xuyakirina niha (kopΓ yan jΓ di pencereyeke nΓ» de veke) +bookmark_label=Xuyakirina niha + +# Secondary toolbar and context menu +tools.title=AmΓ»r +tools_label=AmΓ»r +first_page.title=Here rΓ»pela yekemΓn +first_page.label=Here rΓ»pela yekemΓn +first_page_label=Here rΓ»pela yekemΓn +last_page.title=Here rΓ»pela dawΓn +last_page.label=Here rΓ»pela dawΓn +last_page_label=Here rΓ»pela dawΓn +page_rotate_cw.title=Bi aliyΓͺ saetΓͺ ve bizivirΓne +page_rotate_cw.label=Bi aliyΓͺ saetΓͺ ve bizivirΓne +page_rotate_cw_label=Bi aliyΓͺ saetΓͺ ve bizivirΓne +page_rotate_ccw.title=BerevajΓ aliyΓͺ saetΓͺ ve bizivirΓne +page_rotate_ccw.label=BerevajΓ aliyΓͺ saetΓͺ ve bizivirΓne +page_rotate_ccw_label=BerevajΓ aliyΓͺ saetΓͺ ve bizivirΓne + + +# Document properties dialog box +# LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" +# will be replaced by the PDF file size in kilobytes, respectively in 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_title=Sernav: +# LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" +# will be replaced by the creation/modification date, and time, of the PDF file. + +# 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) +toggle_sidebar.title=DarikΓͺ kΓͺlekΓͺ veke/bigire +toggle_sidebar_label=DarikΓͺ kΓͺlekΓͺ veke/bigire +document_outline_label=Şemaya belgeyΓͺ +thumbs.title=WΓͺnekokan nΓşan bide +thumbs_label=WΓͺnekok +findbar.title=Di belgeyΓͺ de bibΓne + +# 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=RΓ»pel {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=WΓͺnekoka rΓ»pelΓͺ {{page}} + +# Find panel button title and messages +find_previous.title=Peyva berΓͺ bibΓne +find_previous_label=Paşve +find_next.title=Peyya pΓͺş bibΓne +find_next_label=PΓͺşve +find_highlight=TevΓ beloq bike +find_match_case_label=Ji bo tΓpΓͺn hΓ»rdek-girdek bihΓstyar +find_reached_top=GihΓşt serΓͺ rΓ»pelΓͺ, ji dawiya rΓ»pelΓͺ bidomΓne +find_reached_bottom=GihΓşt dawiya rΓ»pelΓͺ, ji serΓͺ rΓ»pelΓͺ bidomΓne +find_not_found=Peyv nehat dΓtin + +# Error panel labels +error_more_info=ZΓͺdetir agahΓ +error_less_info=ZΓͺdetir agahΓ +# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be +# replaced by the PDF.JS version and build ID. +error_version_info=PDF.js versiyon {{version}} (avanΓ: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Peyam: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Komik: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Pel: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=RΓͺzik: {{line}} +rendering_error=Di vehΓ»randina rΓ»pelΓͺ de Γ§ewtΓ Γ§ΓͺbΓ». + +# Predefined zoom values +page_scale_width=Firehiya rΓ»pelΓͺ +page_scale_fit=Di rΓ»pelΓͺ de bicΓ bike +page_scale_auto=Xweber nΓͺzΓk bike +page_scale_actual=Mezinahiya rastΓn +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. + +# Loading indicator messages +loading_error_indicator=XeletΓ +loading_error=Dema ku PDF dihat barkirin Γ§ewtiyek Γ§ΓͺbΓ». +invalid_file_error=PelΓͺ PDFΓͺ nederbasdar yan jΓ xirabe ye. +missing_file_error=PelΓͺ PDFΓͺ kΓͺm e. + +# 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=[NΓşaneya {{type}}Γͺ] +password_label=Ji bo PDFΓͺ vekà şΓfreyΓͺ binivΓse. +password_invalid=ŞΓfre Γ§ewt e. Tika ye dΓsa biceribΓne. +password_ok=Temam + +printing_not_supported=HişyarΓ: Γ‡apkirin ji hΓͺla vΓͺ gerokΓͺ ve bi temamΓ nayΓͺ destekirin. +printing_not_ready=HişyarΓ: PDF bi temamΓ nehat barkirin Γ» ji bo Γ§apΓͺ ne amade ye. +web_fonts_disabled=FontΓͺn WebΓͺ neΓ§alak in: FontΓͺn PDFΓͺ yΓͺn veşartΓ nayΓͺn bikaranΓn. +document_colors_not_allowed=DestΓ»r tune ye ku belgeyΓͺn PDFΓͺ rengΓͺn xwe bi kar bΓnin: Di gerokΓͺ de 'destΓ»rΓͺ bide rΓ»pelan ku rengΓͺn xwe bi kar bΓnin' nehatiye Γ§alakirin. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/lg/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/lg/viewer.properties new file mode 100755 index 00000000..5658d544 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/lg/viewer.properties @@ -0,0 +1,112 @@ +# 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=Omuko Ogubadewo +next.title=Omuko Oguddako + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=ku {{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. + +zoom_out.title=Zimbulukusa +zoom_out_label=Zimbulukusa +zoom_in.title=Funza Munda +zoom_in_label=Funza Munda +zoom.title=Gezzamu +open_file.title=Bikula Fayiro +open_file_label=Ggulawo +print.title=Fulumya +print_label=Fulumya +download.title=Tikula +download_label=Tikula +bookmark.title=Endabika eriwo (koppa oba gulawo mu diriisa epya) +bookmark_label=Endabika Eriwo + +# Secondary toolbar and context menu + + +# Document properties dialog box +# LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" +# will be replaced by the PDF file size in kilobytes, respectively in bytes. +# LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" +# will be replaced by the PDF file size in megabytes, respectively in bytes. +# LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" +# will be replaced by the creation/modification date, and time, of the PDF file. + +# 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=Ensalo ze Ekiwandiko +thumbs.title=Laga Ekifanyi Mubufunze +thumbs_label=Ekifanyi Mubufunze + +# 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=Omuko {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Ekifananyi kyo Omuko Mubufunze {{page}} + +# Find panel button title and messages +find_previous.title=Zuula awayise mukweddamu mumiteddera +find_next.title=Zuula ekidako mukweddamu mumiteddera +find_highlight=Londa byonna +find_not_found=Emiteddera tezuuliddwa + +# Error panel labels +error_more_info=Ebisingawo +error_less_info=Mubumpimpi +# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be +# replaced by the PDF.JS version and build ID. +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Obubaaka: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Ebipangiddwa: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Fayiro {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Layini: {{line}} +rendering_error=Wabadewo ensobi muku tekawo omuko. + +# Predefined zoom values +page_scale_width=Obugazi bwo Omuko +page_scale_fit=Okutuka kwo Omuko +page_scale_auto=Okwefunza no Kwegeza +page_scale_actual=Obunene Obutufu +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. + +# Loading indicator messages +loading_error_indicator=Ensobi +loading_error=Wabadewo ensobi mukutika PDF. + +# 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}} Enyonyola] +password_ok=OK + +printing_not_supported=Okulaabula: Okulumya empapula tekuwagirwa enonyeso enno. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/lij/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/lij/viewer.properties new file mode 100755 index 00000000..06bdfd04 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/lij/viewer.properties @@ -0,0 +1,180 @@ +# 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=Pagina primma +previous_label=Precedente +next.title=Pagina dΓ²ppo +next_label=PrΓ²scima + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Pagina +# 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=Diminoisci zoom +zoom_out_label=Diminoisci zoom +zoom_in.title=Aomenta zoom +zoom_in_label=Aomenta zoom +zoom.title=Zoom +presentation_mode.title=Vanni into mΓ²ddo de prezentaΓ§ion +presentation_mode_label=MΓ²ddo de prezentaΓ§ion +open_file.title=Arvi file +open_file_label=Arvi +print.title=Stanpa +print_label=Stanpa +download.title=Descaregamento +download_label=Descaregamento +bookmark.title=Vixon corente (cΓ²pia Γ² arvi inte 'n neuvo barcon) +bookmark_label=Vixon corente + +# Secondary toolbar and context menu +tools.title=Strumenti +tools_label=Strumenti +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 + + +# Document properties dialog box +document_properties.title=PropietΓ¦ do documento… +document_properties_label=PropietΓ¦ do documento… +document_properties_file_name=Nomme file: +document_properties_file_size=Dimenscion file: +# 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}} byte) +# 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_kb}} MB ({{size_b}} byte) +document_properties_title=Titolo: +document_properties_author=Aoto: +document_properties_subject=Ogetto: +document_properties_keywords=ParΓ²lle ciave: +document_properties_creation_date=DΓ¦ta creaΓ§ion: +document_properties_modification_date=DΓ¦ta cangiamento: +# 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=AotΓ΄ originale: +document_properties_producer=ProdutΓ΄ PDF: +document_properties_version=Verscion PDF: +document_properties_page_count=Contezzo pagine: +document_properties_close=SΓ¦ra + +print_progress_message=Praparo o documento pe-a stanpa… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Anulla + +# 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/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 +attachments.title=Fanni vedde alegΓ¦ +attachments_label=AlegΓ¦ +thumbs.title=Mostra miniatue +thumbs_label=Miniatue +findbar.title=Treuva into documento +findbar_label=Treuva + +# 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=Pagina {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Miniatua da pagina {{page}} + +# Find panel button title and messages +find_input.title=Treuva +find_input.placeholder=Treuva into documento… +find_previous.title=Treuva a ripetiΓ§ion precedente do testo da Γ§ercΓ’ +find_previous_label=Precedente +find_next.title=Treuva a ripetiΓ§ion dΓ²ppo do testo da Γ§ercΓ’ +find_next_label=Segoente +find_highlight=EvidenΓ§ia +find_match_case_label=Maioscole/minoscole +find_reached_top=Razonto a fin da pagina, continoa da l'iniΓ§io +find_reached_bottom=Razonto l'iniΓ§io da pagina, continoa da-a fin +find_not_found=Testo no trovou + +# Error panel labels +error_more_info=CiΓΉ informaΓ§ioin +error_less_info=Meno informaΓ§ioin +error_close=SΓ¦ra +# 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=Mesaggio: {{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=Linia: {{line}} +rendering_error=Gh'Γ© stΓ¦to 'n'erΓ΄ itno rendering da pagina. + +# Predefined zoom values +page_scale_width=Larghessa pagina +page_scale_fit=Adatta a una pagina +page_scale_auto=Zoom aotomatico +page_scale_actual=Dimenscioin efetive +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# 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 file PDF o l'Γ© no valido Γ² aroinou. +missing_file_error=O file PDF o no gh'Γ©. +unexpected_response_error=Risposta inprevista do-u server + +# 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=[AnotaΓ§ion: {{type}}] +password_label=Dimme a parΓ²lla segreta pe arvΓ sto file PDF. +password_invalid=ParΓ²lla segreta sbalia. Preuva torna. +password_ok=Va ben +password_cancel=Anulla + +printing_not_supported=AtenΓ§ion: a stanpa a no l'Γ© conpletamente soportΓ’ da sto navegatΓ΄. +printing_not_ready=AtenΓ§ion: o PDF o no l'Γ© ancon caregou conpletamente pe-a stanpa. +web_fonts_disabled=I font do web en dizativΓ¦: inposcibile adeuviΓ’ i carateri do PDF. +document_colors_not_allowed=No l'Γ© poscibile adeuviΓ’ i prΓ²pi coΓ pe-i documenti PDF: l'opΓ§ion do navegatΓ΄ β€œPermetti a-e pagine de Γ§erne i prΓ²pi coΓ in cangio de quelli inpostæ” a l'Γ© dizativΓ’. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/locale.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/locale.properties new file mode 100755 index 00000000..9aded1b5 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/locale.properties @@ -0,0 +1,312 @@ +[ach] +@import url(ach/viewer.properties) + +[af] +@import url(af/viewer.properties) + +[ak] +@import url(ak/viewer.properties) + +[an] +@import url(an/viewer.properties) + +[ar] +@import url(ar/viewer.properties) + +[as] +@import url(as/viewer.properties) + +[ast] +@import url(ast/viewer.properties) + +[az] +@import url(az/viewer.properties) + +[be] +@import url(be/viewer.properties) + +[bg] +@import url(bg/viewer.properties) + +[bn-BD] +@import url(bn-BD/viewer.properties) + +[bn-IN] +@import url(bn-IN/viewer.properties) + +[br] +@import url(br/viewer.properties) + +[bs] +@import url(bs/viewer.properties) + +[ca] +@import url(ca/viewer.properties) + +[cs] +@import url(cs/viewer.properties) + +[csb] +@import url(csb/viewer.properties) + +[cy] +@import url(cy/viewer.properties) + +[da] +@import url(da/viewer.properties) + +[de] +@import url(de/viewer.properties) + +[el] +@import url(el/viewer.properties) + +[en-GB] +@import url(en-GB/viewer.properties) + +[en-US] +@import url(en-US/viewer.properties) + +[en-ZA] +@import url(en-ZA/viewer.properties) + +[eo] +@import url(eo/viewer.properties) + +[es-AR] +@import url(es-AR/viewer.properties) + +[es-CL] +@import url(es-CL/viewer.properties) + +[es-ES] +@import url(es-ES/viewer.properties) + +[es-MX] +@import url(es-MX/viewer.properties) + +[et] +@import url(et/viewer.properties) + +[eu] +@import url(eu/viewer.properties) + +[fa] +@import url(fa/viewer.properties) + +[ff] +@import url(ff/viewer.properties) + +[fi] +@import url(fi/viewer.properties) + +[fr] +@import url(fr/viewer.properties) + +[fy-NL] +@import url(fy-NL/viewer.properties) + +[ga-IE] +@import url(ga-IE/viewer.properties) + +[gd] +@import url(gd/viewer.properties) + +[gl] +@import url(gl/viewer.properties) + +[gu-IN] +@import url(gu-IN/viewer.properties) + +[he] +@import url(he/viewer.properties) + +[hi-IN] +@import url(hi-IN/viewer.properties) + +[hr] +@import url(hr/viewer.properties) + +[hu] +@import url(hu/viewer.properties) + +[hy-AM] +@import url(hy-AM/viewer.properties) + +[id] +@import url(id/viewer.properties) + +[is] +@import url(is/viewer.properties) + +[it] +@import url(it/viewer.properties) + +[ja] +@import url(ja/viewer.properties) + +[ka] +@import url(ka/viewer.properties) + +[kk] +@import url(kk/viewer.properties) + +[km] +@import url(km/viewer.properties) + +[kn] +@import url(kn/viewer.properties) + +[ko] +@import url(ko/viewer.properties) + +[ku] +@import url(ku/viewer.properties) + +[lg] +@import url(lg/viewer.properties) + +[lij] +@import url(lij/viewer.properties) + +[lt] +@import url(lt/viewer.properties) + +[lv] +@import url(lv/viewer.properties) + +[mai] +@import url(mai/viewer.properties) + +[mk] +@import url(mk/viewer.properties) + +[ml] +@import url(ml/viewer.properties) + +[mn] +@import url(mn/viewer.properties) + +[mr] +@import url(mr/viewer.properties) + +[ms] +@import url(ms/viewer.properties) + +[my] +@import url(my/viewer.properties) + +[nb-NO] +@import url(nb-NO/viewer.properties) + +[nl] +@import url(nl/viewer.properties) + +[nn-NO] +@import url(nn-NO/viewer.properties) + +[nso] +@import url(nso/viewer.properties) + +[oc] +@import url(oc/viewer.properties) + +[or] +@import url(or/viewer.properties) + +[pa-IN] +@import url(pa-IN/viewer.properties) + +[pl] +@import url(pl/viewer.properties) + +[pt-BR] +@import url(pt-BR/viewer.properties) + +[pt-PT] +@import url(pt-PT/viewer.properties) + +[rm] +@import url(rm/viewer.properties) + +[ro] +@import url(ro/viewer.properties) + +[ru] +@import url(ru/viewer.properties) + +[rw] +@import url(rw/viewer.properties) + +[sah] +@import url(sah/viewer.properties) + +[si] +@import url(si/viewer.properties) + +[sk] +@import url(sk/viewer.properties) + +[sl] +@import url(sl/viewer.properties) + +[son] +@import url(son/viewer.properties) + +[sq] +@import url(sq/viewer.properties) + +[sr] +@import url(sr/viewer.properties) + +[sv-SE] +@import url(sv-SE/viewer.properties) + +[sw] +@import url(sw/viewer.properties) + +[ta] +@import url(ta/viewer.properties) + +[ta-LK] +@import url(ta-LK/viewer.properties) + +[te] +@import url(te/viewer.properties) + +[th] +@import url(th/viewer.properties) + +[tl] +@import url(tl/viewer.properties) + +[tn] +@import url(tn/viewer.properties) + +[tr] +@import url(tr/viewer.properties) + +[uk] +@import url(uk/viewer.properties) + +[ur] +@import url(ur/viewer.properties) + +[vi] +@import url(vi/viewer.properties) + +[wo] +@import url(wo/viewer.properties) + +[xh] +@import url(xh/viewer.properties) + +[zh-CN] +@import url(zh-CN/viewer.properties) + +[zh-TW] +@import url(zh-TW/viewer.properties) + +[zu] +@import url(zu/viewer.properties) + diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/lt/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/lt/viewer.properties new file mode 100755 index 00000000..e2ad07bc --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/lt/viewer.properties @@ -0,0 +1,184 @@ +# 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=Ankstesnis puslapis +previous_label=Ankstesnis +next.title=Kitas puslapis +next_label=Kitas + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Puslapis +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=iΕ‘ {{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}} iΕ‘ {{pagesCount}}) + +zoom_out.title=SumaΕΎinti +zoom_out_label=SumaΕΎinti +zoom_in.title=Padidinti +zoom_in_label=Padidinti +zoom.title=Mastelis +presentation_mode.title=Pereiti Δ― pateikties veiksenΔ… +presentation_mode_label=Pateikties veiksena +open_file.title=Atverti failΔ… +open_file_label=Atverti +print.title=Spausdinti +print_label=Spausdinti +download.title=ParsiΕ³sti +download_label=ParsiΕ³sti +bookmark.title=Esamojo rodinio saitas (kopijavimui ar atvΔ—rimui kitame lange) +bookmark_label=Esamasis rodinys + +# Secondary toolbar and context menu +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Δ― +cursor_text_select_tool_label=Teksto ΕΎymΔ—jimo Δ―rankis +cursor_hand_tool.title=Δjungti vilkimo Δ―rankΔ― +cursor_hand_tool_label=Vilkimo Δ―rankis + +# Document properties dialog box +document_properties.title=Dokumento savybΔ—s… +document_properties_label=Dokumento savybΔ—s… +document_properties_file_name=Failo vardas: +document_properties_file_size=Failo dydis: +# 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}} 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}} B) +document_properties_title=AntraΕ‘tΔ—: +document_properties_author=Autorius: +document_properties_subject=Tema: +document_properties_keywords=ReikΕ‘miniai ΕΎodΕΎiai: +document_properties_creation_date=SukΕ«rimo data: +document_properties_modification_date=Modifikavimo data: +# 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=KΕ«rΔ—jas: +document_properties_producer=PDF generatorius: +document_properties_version=PDF versija: +document_properties_page_count=PuslapiΕ³ skaičius: +document_properties_close=UΕΎverti + +print_progress_message=Dokumentas ruoΕ‘iamas spausdinimui… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Atsisakyti + +# 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=Rodyti / slΔ—pti Ε‘oninΔ― polangΔ― +toggle_sidebar_notification.title=ParankinΔ— (dokumentas turi struktΕ«rΔ… / priedΕ³) +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 +thumbs.title=Rodyti puslapiΕ³ miniatiΕ«ras +thumbs_label=MiniatiΕ«ros +findbar.title=IeΕ‘koti dokumente +findbar_label=Rasti + +# 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}} puslapis +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas={{page}} puslapio miniatiΕ«ra + +# Find panel button title and messages +find_input.title=Rasti +find_input.placeholder=Rasti dokumente… +find_previous.title=IeΕ‘koti ankstesnio frazΔ—s egzemplioriaus +find_previous_label=Ankstesnis +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_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 +find_not_found=IeΕ‘koma frazΔ— nerasta + +# Error panel labels +error_more_info=IΕ‘samiau +error_less_info=Glausčiau +error_close=UΕΎverti +# 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}} (darinys: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=PraneΕ‘imas: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=DΔ—klas: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Failas: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=EilutΔ—: {{line}} +rendering_error=Atvaizduojant puslapΔ― Δ―vyko klaida. + +# Predefined zoom values +page_scale_width=Priderinti prie lapo pločio +page_scale_fit=Pritaikyti prie lapo dydΕΎio +page_scale_auto=Automatinis mastelis +page_scale_actual=Tikras dydis +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Klaida +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. +unexpected_response_error=NetikΔ—tas serverio atsakas. + +# 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}}β€œ tipo anotacija] +password_label=Δveskite slaptaΕΎodΔ― Ε‘iam PDF failui atverti. +password_invalid=SlaptaΕΎodis neteisingas. Bandykite dar kartΔ…. +password_ok=Gerai +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. +document_colors_not_allowed=PDF dokumentams neleidΕΎiama nurodyti savo spalvΕ³, nes iΕ‘jungta narΕ‘yklΔ—s nuostata β€žLeisti tinklalapiams nurodyti spalvasβ€œ. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/lv/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/lv/viewer.properties new file mode 100755 index 00000000..9d7ae41c --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/lv/viewer.properties @@ -0,0 +1,180 @@ +# 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=IepriekΕ‘Δ“jā lapa +previous_label=IepriekΕ‘Δ“jā +next.title=Nākamā lapa +next_label=Nākamā + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Lapa +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=no {{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}} no {{pagesCount}}) + +zoom_out.title=Attālināt\u0020 +zoom_out_label=Attālināt +zoom_in.title=Pietuvināt +zoom_in_label=Pietuvināt +zoom.title=Palielinājums +presentation_mode.title=PārslΔ“gties uz Prezentācijas reΕΎΔ«mu +presentation_mode_label=Prezentācijas reΕΎΔ«ms +open_file.title=AtvΔ“rt failu +open_file_label=AtvΔ“rt +print.title=Drukāőana +print_label=Drukāt +download.title=Lejupielāde +download_label=LejupielādΔ“t +bookmark.title=PaΕ‘reizΔ“jais skats (kopΔ“t vai atvΔ“rt jaunā logā) +bookmark_label=PaΕ‘reizΔ“jais skats + +# Secondary toolbar and context menu +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 + + +# Document properties dialog box +document_properties.title=Dokumenta iestatΔ«jumi… +document_properties_label=Dokumenta iestatΔ«jumi… +document_properties_file_name=Faila nosaukums: +document_properties_file_size=Faila izmΔ“rs: +# 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}} biti) +# 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}} biti) +document_properties_title=Nosaukums: +document_properties_author=Autors: +document_properties_subject=TΔ“ma: +document_properties_keywords=AtslΔ“gas vārdi: +document_properties_creation_date=Izveides datums: +document_properties_modification_date=LAboΕ‘anas datums: +# 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=RadΔ«tājs: +document_properties_producer=PDF producents: +document_properties_version=PDF versija: +document_properties_page_count=Lapu skaits: +document_properties_close=AizvΔ“rt + +print_progress_message=Gatavo dokumentu drukāőanai... +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Atcelt + +# 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=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 +attachments.title=RādΔ«t pielikumus +attachments_label=Pielikumi +thumbs.title=ParādΔ«t sΔ«ktΔ“lus +thumbs_label=SΔ«ktΔ“li +findbar.title=MeklΔ“t dokumentā +findbar_label=MeklΔ“t + +# 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=Lapa {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Lapas {{page}} sΔ«ktΔ“ls + +# Find panel button title and messages +find_input.title=MeklΔ“t +find_input.placeholder=MeklΔ“t dokumentā… +find_previous.title=Atrast iepriekΕ‘Δ“jo +find_previous_label=IepriekΕ‘Δ“jā +find_next.title=Atrast nākamo +find_next_label=Nākamā +find_highlight=Iekrāsot visas +find_match_case_label=Lielo, mazo burtu jutΔ«gs +find_reached_top=Sasniegts dokumenta sākums, turpinām no beigām +find_reached_bottom=Sasniegtas dokumenta beigas, turpinām no sākuma +find_not_found=Frāze nav atrasta + +# Error panel labels +error_more_info=Vairāk informācijas +error_less_info=MAzāk informācijas +error_close=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=ZiΕ†ojums: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Steks: {{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=RindiΕ†a: {{line}} +rendering_error=AttΔ“lojot lapu radās kΔΌΕ«da + +# Predefined zoom values +page_scale_width=Lapas platumā +page_scale_fit=Ietilpinot lapu +page_scale_auto=Automātiskais izmΔ“rs +page_scale_actual=Patiesais izmΔ“rs +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# 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. +unexpected_response_error=NegaidΔ«a servera atbilde. + +# 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}} anotācija] +password_label=Ievadiet paroli, lai atvΔ“rtu PDF failu. +password_invalid=Nepareiza parole, mΔ“Δ£iniet vΔ“lreiz. +password_ok=Labi +password_cancel=Atcelt + +printing_not_supported=UzmanΔ«bu: Drukāőana no Ε‘Δ« pārlΕ«ka darbojas tikai daΔΌΔ“ji. +printing_not_ready=UzmanΔ«bu: PDF nav pilnΔ«bā ielādΔ“ts drukāőanai. +web_fonts_disabled=TΔ«mekΔΌa fonti nav aktivizΔ“ti: Nevar iegult PDF fontus. +document_colors_not_allowed=PDF dokumentiem nav atΔΌauts izmantot paΕ‘iem savas krāsas: β€žAtΔΌaut lapām izvΔ“lΔ“ties paőām savas krāsasβ€œ ir deaktivΔ“ts pārlΕ«kā. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/mai/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/mai/viewer.properties new file mode 100755 index 00000000..356223fe --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/mai/viewer.properties @@ -0,0 +1,168 @@ +# 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. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +zoom_out.title=ΰ€›ΰ₯‹ΰ€Ÿ ΰ€•ΰ€°ΰ₯‚ +zoom_out_label=ΰ€›ΰ₯‹ΰ€Ÿ ΰ€•ΰ€°ΰ₯‚ +zoom_in.title=ΰ€ͺΰ₯ˆΰ€˜ ΰ€•ΰ€°ΰ₯‚ +zoom_in_label=ΰ€œΰ₯‚ΰ€ ΰ€‡ΰ€¨ +zoom.title=ΰ€›ΰ₯‹ΰ€Ÿ-ΰ€ͺΰ₯ˆΰ€˜ ΰ€•ΰ€°ΰ₯‚\u0020 +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=ΰ€ͺΰ₯ΰ€°ΰ€₯ΰ€ ΰ€ͺΰ₯ƒΰ€·ΰ₯ΰ€  ΰ€ͺΰ€° ΰ€œΰ€Ύΰ€‰ +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=ΰ€˜ΰ€‘ΰ€Όΰ₯€ΰ€• ΰ€¦ΰ€Ώΰ€Άΰ€Ύ ΰ€Έΰ€ ΰ€‰ΰ€¨ΰ€Ÿΰ€Ύ ΰ€˜ΰ₯ΰ€ΰ€Ύΰ€‰ + + +# 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}} 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_close=ΰ€¬ΰ€¨ΰ₯ΰ€¨ ΰ€•ΰ€°ΰ₯‚ + +# 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) +toggle_sidebar.title=ΰ€Έΰ₯ΰ€²ΰ€Ύΰ€‡ΰ€‘ΰ€° ΰ€Ÿΰ€Ύΰ€—ΰ€² +toggle_sidebar_label=ΰ€Έΰ₯ΰ€²ΰ€Ύΰ€‡ΰ€‘ΰ€° ΰ€Ÿΰ€Ύΰ€—ΰ€² +document_outline_label=ΰ€¦ΰ€Έΰ₯ΰ€€ΰ€Ύΰ€΅ΰ₯‡ΰ€œ ΰ€–ΰ€Ύΰ€•ΰ€Ύ +attachments.title=ΰ€Έΰ€‚ΰ€²ΰ€—ΰ₯ΰ€¨ΰ€• ΰ€¦ΰ₯‡ΰ€–ΰ€Ύΰ€¬ΰ₯‚ +attachments_label=ΰ€Έΰ€‚ΰ€²ΰ€—ΰ₯ΰ€¨ΰ€• +thumbs.title=ΰ€²ΰ€˜ΰ₯-ΰ€›ΰ€΅ΰ€Ώ ΰ€¦ΰ₯‡ΰ€–ΰ€Ύΰ€‰ +thumbs_label=ΰ€²ΰ€˜ΰ₯ ΰ€›ΰ€΅ΰ€Ώ +findbar.title=ΰ€¦ΰ€Έΰ₯ΰ€€ΰ€Ύΰ€΅ΰ₯‡ΰ€œΰ€ΰ₯‡ ΰ€’ΰ₯‚ΰ€ΰ€’ΰ₯‚ + +# 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_previous_label=ΰ€ͺΰ€›ΰ€Ώΰ€²ΰ€Ύ +find_next.title=ΰ€–ΰ₯‹ΰ€œΰ€• ΰ€…ΰ€—ΰ€Ώΰ€²ΰ€Ύ ΰ€‰ΰ€ͺΰ€Έΰ₯ΰ€₯ΰ€Ώΰ€€ΰ€Ώ ΰ€€ΰ€Ύΰ€•ΰ₯‚ +find_next_label=ΰ€†ΰ€—ΰ€Ύΰ€ +find_highlight=ΰ€Έΰ€­ΰ€Ÿΰ€Ύ ΰ€†ΰ€²ΰ₯‹ΰ€•ΰ€Ώΰ€€ ΰ€•ΰ€°ΰ₯‚ +find_match_case_label=ΰ€ΰ€Ώΰ€²ΰ€Ύΰ€¨ ΰ€Έΰ₯ΰ€₯ΰ€Ώΰ€€ΰ€Ώ +find_reached_top=ΰ€ͺΰ₯ƒΰ€·ΰ₯ΰ€ ΰ€• ΰ€Άΰ₯€ΰ€°ΰ₯ΰ€· ΰ€œΰ€Ύΰ€ ΰ€ͺΰ€Ήΰ₯ΰ€ΰ€šΰ€², ΰ€€ΰ€² ΰ€Έΰ€ ΰ€œΰ€Ύΰ€°ΰ₯€ +find_reached_bottom=ΰ€ͺΰ₯ƒΰ€·ΰ₯ΰ€ ΰ€• ΰ€€ΰ€² ΰ€ΰ₯‡ ΰ€œΰ€Ύΰ€ ΰ€ͺΰ€Ήΰ₯ΰ€ΰ€šΰ€², ΰ€Άΰ₯€ΰ€°ΰ₯ΰ€· ΰ€Έΰ€ ΰ€œΰ€Ύΰ€°ΰ₯€ +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_indicator=ΰ€€ΰ₯ΰ€°ΰ₯ΰ€Ÿΰ€Ώ +loading_error=ΰ€ͺΰ₯€ΰ€‘ΰ₯€ΰ€ΰ€« ΰ€²ΰ₯‹ΰ€‘ ΰ€•ΰ€°ΰ₯ˆΰ€€ ΰ€Έΰ€ΰ€― ΰ€ΰ€•ΰ€Ÿΰ€Ύ ΰ€€ΰ₯ΰ€°ΰ₯ΰ€Ÿΰ€Ώ ΰ€­ΰ₯‡ΰ€². +invalid_file_error=ΰ€…ΰ€ΰ€Ύΰ€¨ΰ₯ΰ€― ΰ€…ΰ€₯ΰ€΅ΰ€Ύ ΰ€­ΰ₯ΰ€°ΰ€·ΰ₯ΰ€Ÿ PDF ΰ€«ΰ€Ύΰ€‡ΰ€². +missing_file_error=ΰ€…ΰ€¨ΰ₯ΰ€ͺΰ€Έΰ₯ΰ€₯ΰ€Ώΰ€€ PDF ΰ€«ΰ€Ύΰ€‡ΰ€². +unexpected_response_error=ΰ€Έΰ€°ΰ₯ΰ€΅ΰ€° ΰ€Έΰ€ ΰ€…ΰ€ͺΰ₯ΰ€°ΰ€€ΰ₯ΰ€―ΰ€Ύΰ€Άΰ€Ώΰ€€ ΰ€ͺΰ₯ΰ€°ΰ€€ΰ€Ώΰ€•ΰ₯ΰ€°ΰ€Ώΰ€―ΰ€Ύ. + +# 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=ΰ€ΰ€Ήΰ€Ώ ΰ€ͺΰ₯€ΰ€‘ΰ₯€ΰ€ΰ€« ΰ€«ΰ€Όΰ€Ύΰ€‡ΰ€² ΰ€•ΰ₯‡ΰ€ ΰ€–ΰ₯‹ΰ€²ΰ€¬ΰ€Ύΰ€• ΰ€²ΰ₯‡ΰ€² ΰ€•ΰ₯ƒΰ€ͺΰ€―ΰ€Ύ ΰ€•ΰ₯‚ΰ€Ÿΰ€Άΰ€¬ΰ₯ΰ€¦ ΰ€­ΰ€°ΰ₯‚. +password_invalid=ΰ€…ΰ€΅ΰ₯ˆΰ€§ ΰ€•ΰ₯‚ΰ€Ÿΰ€Άΰ€¬ΰ₯ΰ€¦, ΰ€•ΰ₯ƒΰ€ͺΰ€―ΰ€Ύ ΰ€«ΰ€Ώΰ€¨ΰ₯ ΰ€•ΰ₯‹ΰ€Άΰ€Ώΰ€Ά ΰ€•ΰ€°ΰ₯‚. +password_ok=ΰ€¬ΰ₯‡ΰ€Έ + +printing_not_supported=ΰ€šΰ₯‡ΰ€€ΰ€Ύΰ€΅ΰ€¨ΰ₯€: ΰ€ˆ ΰ€¬ΰ₯ΰ€°ΰ€Ύΰ€‰ΰ€œΰ€° ΰ€ͺΰ€° ΰ€›ΰ€ͺΰ€Ύΰ€‡ ΰ€ͺΰ₯‚ΰ€°ΰ₯ΰ€£ ΰ€€ΰ€°ΰ€Ή ΰ€Έΰ€ ΰ€Έΰ€ΰ€°ΰ₯ΰ€₯ΰ€Ώΰ€€ ΰ€¨ΰ€Ήΰ€Ώ ΰ€…ΰ€›ΰ€Ώ. +printing_not_ready=ΰ€šΰ₯‡ΰ€€ΰ€Ύΰ€΅ΰ€¨ΰ₯€: ΰ€ͺΰ₯€ΰ€‘ΰ₯€ΰ€ΰ€« ΰ€›ΰ€ͺΰ€Ύΰ€‡ΰ€• ΰ€²ΰ₯‡ΰ€² ΰ€ͺΰ₯‚ΰ€°ΰ₯ΰ€£ ΰ€€ΰ€°ΰ€Ή ΰ€Έΰ€ ΰ€²ΰ₯‹ΰ€‘ ΰ€¨ΰ€Ήΰ€Ώ ΰ€…ΰ€›ΰ€Ώ. +web_fonts_disabled=ΰ€΅ΰ₯‡ΰ€¬ ΰ€«ΰ₯‰ΰ€¨ΰ₯ΰ€Ÿΰ₯ΰ€Έ ΰ€¨ΰ€Ώΰ€·ΰ₯ΰ€•ΰ₯ΰ€°ΰ€Ώΰ€― ΰ€…ΰ€›ΰ€Ώ: ΰ€…ΰ€‚ΰ€€ΰ€ƒΰ€Έΰ₯ΰ€₯ΰ€Ύΰ€ͺΰ€Ώΰ€€ PDF ΰ€«ΰ€Ύΰ€¨ΰ₯ΰ€Ÿΰ€Έΰ€• ΰ€‰ΰ€ͺΰ€―ΰ₯‹ΰ€—ΰ€ΰ₯‡ ΰ€…ΰ€Έΰ€ΰ€°ΰ₯ΰ€₯. +document_colors_not_allowed=PDF ΰ€¦ΰ€Έΰ₯ΰ€€ΰ€Ύΰ€΅ΰ₯‡ΰ€œΰ€Ό ΰ€Ήΰ₯ΰ€•ΰ€° ΰ€…ΰ€ͺΰ€¨ ΰ€°ΰ€‚ΰ€— ΰ€•ΰ₯‡ΰ€ ΰ€‰ΰ€ͺΰ€―ΰ₯‹ΰ€— ΰ€•ΰ€°ΰ€¬ΰ€Ύΰ€• ΰ€²ΰ₯‡ΰ€² ΰ€…ΰ€¨ΰ₯ΰ€ΰ€€ΰ€Ώ ΰ€ͺΰ₯ΰ€°ΰ€Ύΰ€ͺΰ₯ΰ€€ ΰ€¨ΰ€Ήΰ€Ώ ΰ€…ΰ€›ΰ€Ώ: 'ΰ€ͺΰ₯ƒΰ€·ΰ₯ΰ€  ΰ€•ΰ₯‡ΰ€ ΰ€Ήΰ₯ΰ€•ΰ€° ΰ€…ΰ€ͺΰ€¨ ΰ€°ΰ€‚ΰ€— ΰ€•ΰ₯‡ΰ€ ΰ€šΰ₯ΰ€¨ΰ€¬ΰ€Ύΰ€• ΰ€²ΰ₯‡ΰ€² ΰ€Έΰ₯ΰ€΅ΰ₯€ΰ€•ΰ₯ƒΰ€€ΰ€Ώ ΰ€¦ΰ€Ώΰ€… ΰ€œΰ₯‡ ΰ€“ ΰ€“ΰ€Ήΰ€Ώ ΰ€¬ΰ₯ΰ€°ΰ€Ύΰ€‰ΰ€œΰ€Όΰ€° ΰ€ΰ₯‡ ΰ€¨ΰ€Ώΰ€·ΰ₯ΰ€•ΰ₯ΰ€°ΰ€Ώΰ€― ΰ€…ΰ€›ΰ€Ώ. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/mk/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/mk/viewer.properties new file mode 100755 index 00000000..094ef766 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/mk/viewer.properties @@ -0,0 +1,133 @@ +# 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. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +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=Алатки +first_page.label=Оди Π΄ΠΎ ΠΏΡ€Π²Π°Ρ‚Π° страница +last_page.label=Оди Π΄ΠΎ послСдната страница +page_rotate_cw.label=Π ΠΎΡ‚ΠΈΡ€Π°Ρ˜ ΠΏΠΎ стрСлкитС Π½Π° часовникот +page_rotate_ccw.label=Π ΠΎΡ‚ΠΈΡ€Π°Ρ˜ спротивно ΠΎΠ΄ стрСлкитС Π½Π° часовникот + + +# Document properties dialog box +# LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" +# will be replaced by the PDF file size in kilobytes, respectively in bytes. +# LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" +# will be replaced by the PDF file size in megabytes, respectively in bytes. +# LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" +# will be replaced by the creation/modification date, and time, of the PDF file. + +# 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) +toggle_sidebar.title=Π’ΠΊΠ»ΡƒΡ‡ΠΈ странична Π»Π΅Π½Ρ‚Π° +toggle_sidebar_label=Π’ΠΊΠ»ΡƒΡ‡ΠΈ странична Π»Π΅Π½Ρ‚Π° +thumbs.title=ΠŸΡ€ΠΈΠΊΠ°ΠΆΡƒΠ²Π°ΡšΠ΅ Π½Π° ΠΈΠΊΠΎΠ½ΠΈ +thumbs_label=Икони +findbar.title=Најди Π²ΠΎ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΎΡ‚ +findbar_label=Најди + +# 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_previous_label=ΠŸΡ€Π΅Ρ‚Ρ…ΠΎΠ΄Π½ΠΎ +find_next.title=Најди ја слСдната појава Π½Π° Ρ„Ρ€Π°Π·Π°Ρ‚Π° +find_next_label=Π‘Π»Π΅Π΄Π½ΠΎ +find_highlight=ΠžΠ·Π½Π°Ρ‡ΠΈ сѐ +find_match_case_label=Π’ΠΎΠΊΠΌΡƒ Ρ‚Π°ΠΊΠ° +find_reached_top=Π‘Π°Ρ€Π°ΡšΠ΅Ρ‚ΠΎ стигна Π΄ΠΎ ΠΏΠΎΡ‡Π΅Ρ‚ΠΎΠΊΠΎΡ‚ Π½Π° Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΎΡ‚ ΠΈ ΠΏΠΎΡ‡Π½ΡƒΠ²Π° ΠΎΠ΄ ΠΊΡ€Π°Ρ˜ΠΎΡ‚ +find_reached_bottom=Π‘Π°Ρ€Π°ΡšΠ΅Ρ‚ΠΎ стигна Π΄ΠΎ ΠΊΡ€Π°Ρ˜ΠΎΡ‚ Π½Π° Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΎΡ‚ ΠΈ ΠΏΠΎΡ‡Π½ΡƒΠ²Π° ΠΎΠ΄ ΠΏΠΎΡ‡Π΅Ρ‚ΠΎΠΊ +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: {{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_indicator=Π“Ρ€Π΅ΡˆΠΊΠ° +loading_error=Настана Π³Ρ€Π΅ΡˆΠΊΠ° ΠΏΡ€ΠΈ Π²Ρ‡ΠΈΡ‚ΡƒΠ²Π°ΡšΠ΅Ρ‚ΠΎ Π½Π° PDF-ΠΎΡ‚. +invalid_file_error=НСвалидна ΠΈΠ»ΠΈ ΠΊΠΎΡ€ΡƒΠΌΠΏΠΈΡ€Π°Π½Π° PDF Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ°. +missing_file_error=НСдостасува PDF Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚. + +# 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" + +printing_not_supported=ΠŸΡ€Π΅Π΄ΡƒΠΏΡ€Π΅Π΄ΡƒΠ²Π°ΡšΠ΅: ΠŸΠ΅Ρ‡Π°Ρ‚Π΅ΡšΠ΅Ρ‚ΠΎ Π½Π΅ Π΅ цСлосно ΠΏΠΎΠ΄Π΄Ρ€ΠΆΠ°Π½ΠΎ Π²ΠΎ овој прСлистувач. +printing_not_ready=ΠŸΡ€Π΅Π΄ΡƒΠΏΡ€Π΅Π΄ΡƒΠ²Π°ΡšΠ΅: PDF Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΎΡ‚ Π½Π΅ Π΅ цСлосно Π²Ρ‡ΠΈΡ‚Π°Π½ Π·Π° ΠΏΠ΅Ρ‡Π°Ρ‚Π΅ΡšΠ΅. +web_fonts_disabled=Π˜Π½Ρ‚Π΅Ρ€Π½Π΅Ρ‚ Ρ„ΠΎΠ½Ρ‚ΠΎΠ²ΠΈΡ‚Π΅ сС ΠΎΠ½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ΅Π½ΠΈ: Π½Π΅ ΠΌΠΎΠΆΠ΅ Π΄Π° сС користат Π²Π³Ρ€Π°Π΄Π΅Π½ΠΈΡ‚Π΅ PDF Ρ„ΠΎΠ½Ρ‚ΠΎΠ²ΠΈ. +document_colors_not_allowed=PDF-Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΈΡ‚Π΅ Π½Π΅ΠΌΠ°Π°Ρ‚ Π΄ΠΎΠ·Π²ΠΎΠ»Π° Π΄Π° користат сопствСни Π±ΠΎΠΈ: ΠŸΠΎΡΡ‚Π°Π²ΠΊΠ°Ρ‚Π° β€žΠ”ΠΎΠ·Π²ΠΎΠ»ΠΈ страницитС сами Π΄Π° Π³ΠΈ ΠΈΠ·Π±ΠΈΡ€Π°Π°Ρ‚ своитС Π±ΠΎΠΈβ€œ Π΅ Π΄Π΅Π°ΠΊΡ‚ΠΈΠ²ΠΈΡ€Π°Π½Π° ΠΎΠ΄ прСлистувачот. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ml/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ml/viewer.properties new file mode 100755 index 00000000..20c124dc --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ml/viewer.properties @@ -0,0 +1,168 @@ +# 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. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +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=ആദࡍയഀࡍഀࡆ ഀാളിലࡇയࡍകࡍകࡁࡍ ΰ΄ͺࡋകࡁക +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=ΰ΄˜ΰ΄Ÿΰ΄Ώΰ΄•ΰ΄Ύΰ΄° ദിഢയࡍകࡍകࡁࡍ ΰ΄΅ΰ΄Ώΰ΄ͺΰ΄°ΰ΅€ΰ΄€ΰ΄ΰ΄Ύΰ΄―ΰ΄Ώ കറകࡍകࡁക + + +# 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=ΰ΄€ΰ΄²ΰ΄•ΰ΅ΰ΄•ΰ΅†ΰ΄Ÿΰ΅ΰ΄Ÿΰ΅β€Œ\u0020 +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=ΰ΄ͺി഑ിഎഫࡍ ΰ΄ͺΰ΅ΰ΄°ΰ΅Šΰ΄‘ΰ΅ΰ΄―ΰ΅‚ΰ΄Έΰ΄°ΰ΅β€: +document_properties_version=ΰ΄ͺി഑ിഎഫࡍ ΰ΄ͺΰ΄€ΰ΄Ώΰ΄ͺࡍΰ΄ͺࡍ: +document_properties_page_count=ഀാളിനࡍറࡆ ΰ΄Žΰ΄£ΰ΅ΰ΄£ΰ΄‚: +document_properties_close=ΰ΄…ΰ΄Ÿΰ΄―ΰ΅ΰ΄•ΰ΅ΰ΄•ΰ΅ΰ΄• + +# 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) +toggle_sidebar.title=സࡈ഑ࡍ ബാറിലࡇകࡍകࡁࡍ ΰ΄ΰ΄Ύΰ΄±ΰ΅ΰ΄±ΰ΅ΰ΄• +toggle_sidebar_label=സࡈ഑ࡍ ബാറിലࡇകࡍകࡁࡍ ΰ΄ΰ΄Ύΰ΄±ΰ΅ΰ΄±ΰ΅ΰ΄• +document_outline_label=ΰ΄°ΰ΅‡ΰ΄–ΰ΄―ΰ΅ΰ΄Ÿΰ΅† ΰ΄”ΰ΄Ÿΰ΅ΰ΄Ÿΰ΅ΰ΄²ΰ΅ˆΰ΄¨ΰ΅β€ +attachments.title=ΰ΄…ΰ΄±ΰ΅ΰ΄±ΰ΄Ύΰ΄šΰ΅ΰ΄ΰ΅†ΰ΄¨ΰ΅ΰ΄±ΰ΅ΰ΄•ളࡍ‍ കാണിയࡍകࡍകࡁക +attachments_label=ΰ΄…ΰ΄±ΰ΅ΰ΄±ΰ΄Ύΰ΄šΰ΅ΰ΄ΰ΅†ΰ΄¨ΰ΅ΰ΄±ΰ΅ΰ΄•ളࡍ‍ +thumbs.title=ഀംബࡍനࡆയിലࡁകളࡍ‍ കാണിയࡍകࡍകࡁക +thumbs_label=ഀംബࡍനࡆയിലࡁകളࡍ‍ +findbar.title=രࡇഖയിലࡍ‍ ΰ΄•ΰ΄£ΰ΅ΰ΄Ÿΰ΅ΰ΄ͺΰ΄Ώΰ΄Ÿΰ΄Ώΰ΄―ΰ΅ΰ΄•ΰ΅ΰ΄•ΰ΅ΰ΄• + +# 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=ΰ΄΅ΰ΄Ύΰ΄šΰ΄•ΰ΄‚ ഇഀിനࡁ ΰ΄ΰ΅ΰ΄¨ΰ΅β€ΰ΄ͺΰ΅β€Œ ΰ΄†ΰ΄΅ΰ΄°ΰ΅β€ΰ΄€ΰ΅ΰ΄€ΰ΄Ώΰ΄šΰ΅ΰ΄šΰ΄€ΰ΅β€Œ ΰ΄•ΰ΄£ΰ΅ΰ΄Ÿΰ΅†ΰ΄€ΰ΅ΰ΄€ΰ΅ΰ΄•\u0020 +find_previous_label=ΰ΄ΰ΅ΰ΄ΰ΅ΰ΄ͺࡁࡍ +find_next.title=ΰ΄΅ΰ΄Ύΰ΄šΰ΄•ΰ΄‚ ΰ΄΅ΰ΅€ΰ΄£ΰ΅ΰ΄Ÿΰ΅ΰ΄‚ ΰ΄†ΰ΄΅ΰ΄°ΰ΅β€ΰ΄€ΰ΅ΰ΄€ΰ΄Ώΰ΄•ΰ΅ΰ΄•ΰ΅ΰ΄¨ΰ΅ΰ΄¨ΰ΄€ΰ΅β€Œ ΰ΄•ΰ΄£ΰ΅ΰ΄Ÿΰ΅†ΰ΄€ΰ΅ΰ΄€ΰ΅ΰ΄•\u0020 +find_next_label=ΰ΄…ΰ΄Ÿΰ΅ΰ΄€ΰ΅ΰ΄€ΰ΄€ΰ΅ΰ΅ +find_highlight=ΰ΄Žΰ΄²ΰ΅ΰ΄²ΰ΄Ύΰ΄‚ ΰ΄Žΰ΄Ÿΰ΅ΰ΄€ΰ΅ΰ΄€ΰ΅ΰ΄•ΰ΄Ύΰ΄£ΰ΄Ώΰ΄―ΰ΅ΰ΄•ΰ΅ΰ΄•ΰ΅ΰ΄• +find_match_case_label=അകࡍഷരങࡍങളࡍ‍ ഒഀࡍഀࡁനࡋകࡍകࡁക +find_reached_top=ΰ΄°ΰ΅‡ΰ΄–ΰ΄―ΰ΅ΰ΄Ÿΰ΅† ΰ΄ΰ΅ΰ΄•ളിലࡍ‍ ΰ΄Žΰ΄€ΰ΅ΰ΄€ΰ΄Ώΰ΄―ΰ΄Ώΰ΄°ΰ΄Ώΰ΄•ΰ΅ΰ΄•ΰ΅ΰ΄¨ΰ΅ΰ΄¨ΰ΅, ഀാഴࡆ നിനࡍനࡁം ഀࡁടരࡁനࡍനࡁ +find_reached_bottom=ΰ΄°ΰ΅‡ΰ΄–ΰ΄―ΰ΅ΰ΄Ÿΰ΅† അഡസാനം ഡരࡆ ΰ΄Žΰ΄€ΰ΅ΰ΄€ΰ΄Ώΰ΄―ΰ΄Ώΰ΄°ΰ΄Ώΰ΄•ΰ΅ΰ΄•ΰ΅ΰ΄¨ΰ΅ΰ΄¨ΰ΅, ΰ΄ΰ΅ΰ΄•ളിലࡍ‍ നിനࡍനࡁം ഀࡁടരࡁനࡍനࡁ\u0020 +find_not_found=ΰ΄΅ΰ΄Ύΰ΄šΰ΄•ΰ΄‚ ΰ΄•ΰ΄£ΰ΅ΰ΄Ÿΰ΅†ΰ΄€ΰ΅ΰ΄€ΰ΄Ύΰ΄¨ΰ΄Ύΰ΄―ΰ΄Ώΰ΄²ΰ΅ΰ΄²\u0020 + +# 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_indicator=ΰ΄ͺിഢകࡍ +loading_error=ΰ΄ͺി഑ിഎഫࡍ ലഭࡍയΰ΄ΰ΄Ύΰ΄•ࡍകࡁΰ΄ΰ΅ΰ΄ͺࡋളࡍ‍ ΰ΄ͺിഢകࡍ ΰ΄‰ΰ΄£ΰ΅ΰ΄Ÿΰ΄Ύΰ΄―ΰ΄Ώΰ΄°ΰ΄Ώΰ΄―ΰ΅ΰ΄•ΰ΅ΰ΄•ΰ΅ΰ΄¨ΰ΅ΰ΄¨ΰ΅. +invalid_file_error=ഀࡆറࡍറായ അലࡍലࡆങࡍകിലࡍ‍ ഀകരാറࡁളࡍള ΰ΄ͺി഑ിഎഫࡍ ഫയലࡍ‍. +missing_file_error=ΰ΄ͺി഑ിഎഫࡍ ഫയലࡍ‍ ലഭࡍയΰ΄ΰ΄²ΰ΅ΰ΄². +unexpected_response_error=ΰ΄ͺࡍരഀࡀകࡍഷികࡍകാഀࡍഀ സࡆരࡍ‍ഡരࡍ‍ ΰ΄ΰ΄±ΰ΅ΰ΄ͺടി. + +# 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=ഈ ΰ΄ͺി഑ിഎഫࡍ ഫയലࡍ‍ ഀࡁറകࡍകࡁനࡍനഀിനࡁࡍ രഹസࡍയഡാകࡍകࡍ നലࡍ‍കࡁക. +password_invalid=ഀࡆറࡍറായ രഹസࡍയഡാകࡍകࡍ, ദയഡായി ΰ΄΅ΰ΅€ΰ΄£ΰ΅ΰ΄Ÿΰ΅ΰ΄‚ ഢࡍരΰ΄ΰ΄Ώΰ΄―ࡍകࡍകࡁക. +password_ok=ΰ΄Άΰ΄°ΰ΄Ώ + +printing_not_supported=ΰ΄ΰ΅ΰ΄¨ΰ΅ΰ΄¨ΰ΄±ΰ΄Ώΰ΄―ΰ΄Ώΰ΄ͺࡍΰ΄ͺࡁࡍ: ഈ ΰ΄¬ΰ΅ΰ΄°ΰ΅Œΰ΄Έΰ΄°ΰ΅β€ ΰ΄ͺࡂരࡍ‍ണࡍണΰ΄ΰ΄Ύΰ΄―ΰ΄Ώ ΰ΄ͺࡍരിനࡍറിങࡍ ΰ΄ͺിനࡍഀࡁണയࡍകࡍകࡁനࡍനിലࡍല. +printing_not_ready=ΰ΄ΰ΅ΰ΄¨ΰ΅ΰ΄¨ΰ΄±ΰ΄Ώΰ΄―ΰ΄Ώΰ΄ͺࡍΰ΄ͺࡁࡍ: ΰ΄ͺࡍരിനࡍറࡍ ΰ΄šΰ΅†ΰ΄―ΰ΅ΰ΄―ΰ΅ΰ΄¨ΰ΅ΰ΄¨ΰ΄€ΰ΄Ώΰ΄¨ΰ΅ΰ΅ ΰ΄ͺി഑ിഎഫࡍ ΰ΄ͺࡂരࡍ‍ണࡍണΰ΄ΰ΄Ύΰ΄―ΰ΄Ώ ലഭࡍയΰ΄ΰ΄²ΰ΅ΰ΄². +web_fonts_disabled=ഡࡆബിനࡁളࡍള ΰ΄…ΰ΄•ΰ΅ΰ΄·ΰ΄°ΰ΄Έΰ΄žΰ΅ΰ΄šΰ΄―ΰ΄™ΰ΅ΰ΄™ΰ΄³ΰ΅β€ ΰ΄ͺࡍരഡരࡍ‍ഀࡍഀന ΰ΄°ΰ΄Ήΰ΄Ώΰ΄€ΰ΄‚: ΰ΄Žΰ΄‚ΰ΄¬ΰ΄‘ΰ΅ΰ΄‘ΰ΅ ΰ΄šΰ΅†ΰ΄―ΰ΅ΰ΄€ ΰ΄ͺി഑ിഎഫࡍ ΰ΄…ΰ΄•ΰ΅ΰ΄·ΰ΄°ΰ΄Έΰ΄žΰ΅ΰ΄šΰ΄―ΰ΄™ΰ΅ΰ΄™ΰ΄³ΰ΅β€ ഉΰ΄ͺയࡋഗിയࡍകࡍകࡁഡാനࡍ‍ സാധࡍയΰ΄ΰ΄²ΰ΅ΰ΄². +document_colors_not_allowed=സࡍഡനࡍഀം നിറങࡍങളࡍ‍ ഉΰ΄ͺയࡋഗിയࡍകࡍകࡁഡാനࡍ‍ ΰ΄ͺി഑ിഎഫࡍ രࡇഖകളࡍ‍കࡍകࡁࡍ അനࡁഡാദΰ΄ΰ΄Ώΰ΄²ΰ΅ΰ΄²: 'സࡍഡനࡍഀം നിറങࡍങളࡍ‍ ഉΰ΄ͺയࡋഗിയࡍകࡍകࡁഡാനࡍ‍ ഀാളࡁകളࡆ അനࡁഡദിയࡍകࡍകࡁക' എനࡍനഀࡁࡍ ΰ΄¬ΰ΅ΰ΄°ΰ΅Œΰ΄Έΰ΄±ΰ΄Ώΰ΄²ΰ΅β€ ΰ΄¨ΰ΄Ώΰ΄°ΰ΅β€ΰ΄œΰ΅€ΰ΄΅ΰ΄ΰ΄Ύΰ΄£ΰ΅ΰ΅. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/mn/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/mn/viewer.properties new file mode 100755 index 00000000..39edeb2b --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/mn/viewer.properties @@ -0,0 +1,82 @@ +# 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) + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +zoom.title=Вэлэлт +open_file.title=Π€Π°ΠΉΠ» нээ +open_file_label=Нээ + +# Secondary toolbar and context menu + + +# Document properties dialog box +document_properties_file_name=Π€Π°ΠΉΠ»Ρ‹Π½ нэр: +# LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" +# will be replaced by the PDF file size in kilobytes, respectively in 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_title=Π“Π°Ρ€Ρ‡ΠΈΠ³: +# LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" +# will be replaced by the creation/modification date, and time, of the PDF file. + +# 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) + +# Thumbnails panel item (tooltip and alt text for images) +# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page +# number. +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. + +# Find panel button title and messages +find_previous.title=Π₯Π°ΠΉΠ»Ρ‚Ρ‹Π½ Σ©ΠΌΠ½Σ©Ρ… ΠΎΠ»Π΄Ρ†Ρ‹Π³ Ρ…Π°Ρ€ΡƒΡƒΠ»Π½Π° +find_next.title=Π₯Π°ΠΉΠ»Ρ‚Ρ‹Π½ Π΄Π°Ρ€Π°Π°Π³ΠΈΠΉΠ½ ΠΎΠ»Π΄Ρ†Ρ‹Π³ Ρ…Π°Ρ€ΡƒΡƒΠ»Π½Π° +find_not_found=Олдсонг―ΠΉ + +# Error panel labels +error_more_info=Нэмэлт мэдээлэл +# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be +# replaced by the PDF.JS version and build ID. +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number + +# Predefined zoom values +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. + +# Loading indicator messages +loading_error_indicator=Алдаа + +# 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_ok=OK + diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/mr/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/mr/viewer.properties new file mode 100755 index 00000000..38d35652 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/mr/viewer.properties @@ -0,0 +1,184 @@ +# 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={{pageCount}}ΰ€ͺΰ₯ˆΰ€•ΰ₯€ +# 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=({{pagesCount}} ΰ€ͺΰ₯ˆΰ€•ΰ₯€ {{pageNumber}}) + +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=ΰ€ͺΰ€Ήΰ€Ώΰ€²ΰ₯ΰ€―ΰ€Ύ ΰ€ͺΰ₯ƒΰ€·ΰ₯ΰ€ ΰ€Ύΰ€΅ΰ€° ΰ€œΰ€Ύ +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_label=ΰ€ΰ€œΰ€•ΰ₯‚ΰ€° ΰ€¨ΰ€Ώΰ€΅ΰ€‘ ΰ€Έΰ€Ύΰ€§ΰ€¨ +cursor_hand_tool.title=ΰ€Ήΰ€Ύΰ€€ ΰ€Έΰ€Ύΰ€§ΰ€¨ ΰ€•ΰ€Ύΰ€°ΰ₯ΰ€―ΰ€Ύΰ€¨ΰ₯ΰ€΅ΰ€Ώΰ€€ ΰ€•ΰ€°ΰ€Ύ +cursor_hand_tool_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}} 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_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_notification.title=ΰ€¬ΰ€Ύΰ€œΰ₯‚ΰ€šΰ₯€ ΰ€ͺΰ€Ÿΰ₯ΰ€Ÿΰ₯€ ΰ€Ÿΰ₯‰ΰ€—ΰ€² ΰ€•ΰ€°ΰ€Ύ (ΰ€¦ΰ€Έΰ₯ΰ€€ΰ€ΰ€΅ΰ€œΰ€Ύΰ€ΰ€§ΰ₯ΰ€―ΰ₯‡ ΰ€°ΰ₯ΰ€ͺΰ€°ΰ₯‡ΰ€·ΰ€Ύ/ΰ€œΰ₯‹ΰ€‘ΰ€£ΰ₯ΰ€―ΰ€Ύ ΰ€†ΰ€Ήΰ₯‡ΰ€€) +toggle_sidebar_label=ΰ€¬ΰ€Ύΰ€œΰ₯‚ΰ€šΰ₯€ΰ€ͺΰ€Ÿΰ₯ΰ€Ÿΰ₯€ ΰ€Ÿΰ₯‰ΰ€—ΰ€² ΰ€•ΰ€°ΰ€Ύ +document_outline.title=ΰ€¦ΰ€Έΰ₯ΰ€€ΰ€ΰ€΅ΰ€œ ΰ€¬ΰ€Ύΰ€Ήΰ₯ΰ€―ΰ€°ΰ₯‡ΰ€–ΰ€Ύ ΰ€¦ΰ€°ΰ₯ΰ€Άΰ€΅ΰ€Ύ (ΰ€΅ΰ€Ώΰ€Έΰ₯ΰ€€ΰ₯ƒΰ€€ ΰ€•ΰ€°ΰ€£ΰ₯ΰ€―ΰ€Ύΰ€Έΰ€Ύΰ€ ΰ₯€ ΰ€¦ΰ₯‹ΰ€¨ΰ€΅ΰ₯‡ΰ€³ΰ€Ύ ΰ€•ΰ₯ΰ€²ΰ€Ώΰ€• ΰ€•ΰ€°ΰ€Ύ /ΰ€Έΰ€°ΰ₯ΰ€΅ ΰ€˜ΰ€Ÿΰ€• ΰ€¦ΰ€Ύΰ€–ΰ€΅ΰ€Ύ) +document_outline_label=ΰ€¦ΰ€Έΰ₯ΰ€€ΰ€ΰ€΅ΰ€œ ΰ€°ΰ₯‚ΰ€ͺΰ€°ΰ₯‡ΰ€·ΰ€Ύ +attachments.title=ΰ€œΰ₯‹ΰ€‘ΰ€ͺΰ€€ΰ₯ΰ€° ΰ€¦ΰ€Ύΰ€–ΰ€΅ΰ€Ύ +attachments_label=ΰ€œΰ₯‹ΰ€‘ΰ€ͺΰ€€ΰ₯ΰ€° +thumbs.title=ΰ€₯ΰ€‚ΰ€¬ΰ€¨ΰ₯‡ΰ€²ΰ₯ΰ€Έΰ₯ ΰ€¦ΰ€Ύΰ€–ΰ€΅ΰ€Ύ +thumbs_label=ΰ€₯ΰ€‚ΰ€¬ΰ€¨ΰ₯‡ΰ€²ΰ₯ΰ€Έΰ₯ +findbar.title=ΰ€¦ΰ€Έΰ₯ΰ€€ΰ€ΰ€΅ΰ€œΰ€Ύΰ€€ ΰ€Άΰ₯‹ΰ€§ΰ€Ύ +findbar_label=ΰ€Άΰ₯‹ΰ€§ΰ€Ύ + +# 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_reached_top=ΰ€¦ΰ€Έΰ₯ΰ€€ΰ€ΰ€΅ΰ€œΰ€Ύΰ€šΰ₯ΰ€―ΰ€Ύ ΰ€Άΰ₯€ΰ€°ΰ₯ΰ€·ΰ€•ΰ€Ύΰ€Έ ΰ€ͺΰ₯‹ΰ€Ήΰ€šΰ€²ΰ₯‡, ΰ€€ΰ€³ΰ€ͺΰ€Ύΰ€Έΰ₯‚ΰ€¨ ΰ€ͺΰ₯ΰ€’ΰ₯‡ +find_reached_bottom=ΰ€¦ΰ€Έΰ₯ΰ€€ΰ€ΰ€΅ΰ€œΰ€Ύΰ€šΰ₯ΰ€―ΰ€Ύ ΰ€€ΰ€³ΰ€Ύΰ€²ΰ€Ύ ΰ€ͺΰ₯‹ΰ€Ήΰ€šΰ€²ΰ₯‡, ΰ€Άΰ₯€ΰ€°ΰ₯ΰ€·ΰ€•ΰ€Ύΰ€ͺΰ€Ύΰ€Έΰ₯‚ΰ€¨ ΰ€ͺΰ₯ΰ€’ΰ₯‡ +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_indicator=ΰ€€ΰ₯ΰ€°ΰ₯ΰ€Ÿΰ₯€ +loading_error=PDF ΰ€²ΰ₯‹ΰ€‘ ΰ€•ΰ€°ΰ€€ΰ₯‡ΰ€΅ΰ₯‡ΰ€³ΰ₯€ ΰ€€ΰ₯ΰ€°ΰ₯ΰ€Ÿΰ₯€ ΰ€†ΰ€’ΰ€³ΰ€²ΰ₯€. +invalid_file_error=ΰ€…ΰ€΅ΰ₯ˆΰ€§ ΰ€•ΰ€Ώΰ€‚ΰ€΅ΰ€Ύ ΰ€¦ΰ₯‹ΰ€·ΰ₯€ΰ€€ PDF ΰ€«ΰ€Ύΰ€‡ΰ€². +missing_file_error=ΰ€¨ ΰ€†ΰ€’ΰ€³ΰ€£ΰ€Ύΰ€°ΰ₯€ PDF ΰ€«ΰ€Ύΰ€‡ΰ€². +unexpected_response_error=ΰ€…ΰ€¨ΰ€ͺΰ₯‡ΰ€•ΰ₯ΰ€·ΰ€Ώΰ€€ ΰ€Έΰ€°ΰ₯ΰ€΅ΰ₯ΰ€Ήΰ€° ΰ€ͺΰ₯ΰ€°ΰ€€ΰ€Ώΰ€Έΰ€Ύΰ€¦. + +# 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 ΰ€Ÿΰ€‚ΰ€• ΰ€΅ΰ€Ύΰ€ͺΰ€° ΰ€…ΰ€Άΰ€•ΰ₯ΰ€―. +document_colors_not_allowed=PDF ΰ€¦ΰ€Έΰ₯ΰ€€ΰ€ΰ€΅ΰ€œΰ€Ύΰ€‚ΰ€¨ΰ€Ύ ΰ€€ΰ₯ΰ€―ΰ€Ύΰ€‚ΰ€šΰ₯‡ ΰ€°ΰ€‚ΰ€— ΰ€΅ΰ€Ύΰ€ͺΰ€°ΰ€£ΰ₯ΰ€―ΰ€Ύΰ€Έ ΰ€…ΰ€¨ΰ₯ΰ€ΰ€€ΰ₯€ ΰ€¨ΰ€Ύΰ€Ήΰ₯€: ΰ€¬ΰ₯ΰ€°ΰ€Ύΰ€‰ΰ€ΰ€°ΰ€ΰ€§ΰ₯ΰ€―ΰ₯‡ ' ΰ€ͺΰ₯ƒΰ€·ΰ₯ΰ€ ΰ€Ύΰ€‚ΰ€¨ΰ€Ύ ΰ€€ΰ₯ΰ€―ΰ€Ύΰ€‚ΰ€šΰ₯‡ ΰ€°ΰ€‚ΰ€— ΰ€¨ΰ€Ώΰ€΅ΰ€‘ΰ€£ΰ₯ΰ€―ΰ€Ύΰ€Έ ΰ€…ΰ€¨ΰ₯ΰ€ΰ€€ΰ₯€ ΰ€¦ΰ₯ΰ€―ΰ€Ύ' ΰ€¬ΰ€‚ΰ€¦ ΰ€•ΰ₯‡ΰ€²ΰ₯‡ ΰ€†ΰ€Ήΰ₯‡. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ms/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ms/viewer.properties new file mode 100755 index 00000000..62f1d3e0 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ms/viewer.properties @@ -0,0 +1,184 @@ +# 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=Halaman Sebelum +previous_label=Terdahulu +next.title=Halaman Seterusnya +next_label=Berikut + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Halaman +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=daripada {{pageCount}} +# 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}} daripada {{pagesCount}}) + +zoom_out.title=Zum Keluar +zoom_out_label=Zum Keluar +zoom_in.title=Zum Masuk +zoom_in_label=Zum Masuk +zoom.title=Zum +presentation_mode.title=Tukar ke Mod Persembahan +presentation_mode_label=Mod Persembahan +open_file.title=Buka Fail +open_file_label=Buka +print.title=Cetak +print_label=Cetak +download.title=Muat turun +download_label=Muat turun +bookmark.title=Paparan semasa (salin atau buka dalam tetingkap baru) +bookmark_label=Paparan Semasa + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=Alatan Pilihan Teks +cursor_hand_tool.title=Dayakan Alatan Tangan +cursor_hand_tool_label=Alatan Tangan + +# Document properties dialog box +document_properties.title=Sifat Dokumen… +document_properties_label=Sifat Dokumen… +document_properties_file_name=Nama fail: +document_properties_file_size=Saiz fail: +# 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}} bait) +# 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}} bait) +document_properties_title=Tajuk: +document_properties_author=Pengarang: +document_properties_subject=Subjek: +document_properties_keywords=Kata kunci: +document_properties_creation_date=Masa Dicipta: +document_properties_modification_date=Tarikh Ubahsuai: +# 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=Pencipta: +document_properties_producer=Pengeluar PDF: +document_properties_version=Versi PDF: +document_properties_page_count=Kiraan Laman: +document_properties_close=Tutup + +print_progress_message=Menyediakan dokumen untuk dicetak… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Batal + +# 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=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 +attachments.title=Papar Lampiran +attachments_label=Lampiran +thumbs.title=Papar Thumbnails +thumbs_label=Imej kecil +findbar.title=Cari didalam Dokumen +findbar_label=Cari + +# 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=Halaman {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Halaman Imej kecil {{page}} + +# Find panel button title and messages +find_input.title=Cari +find_input.placeholder=Cari dalam dokumen… +find_previous.title=Cari teks frasa berkenaan yang terdahulu +find_previous_label=Sebelumnya +find_next.title=Cari teks frasa berkenaan yang berikut +find_next_label=Berikut +find_highlight=Serlahkan semua +find_match_case_label=Kes Sepadan +find_reached_top=Mencapai teratas daripada dokumen, sambungan daripada bawah +find_reached_bottom=Mencapai terakhir daripada dokumen, sambungan daripada atas +find_not_found=Frasa tidak ditemui + +# Error panel labels +error_more_info=Maklumat lanjut +error_less_info=Kurang Informasi +error_close=Tutup +# 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=Mesej: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Timbun: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Fail: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Garis: {{line}} +rendering_error=Ralat berlaku ketika memberikan halaman. + +# Predefined zoom values +page_scale_width=Lebar Halaman +page_scale_fit=Muat Halaman +page_scale_auto=Zoom Automatik +page_scale_actual=Saiz Sebenar +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# 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. +unexpected_response_error=Respon pelayan yang tidak dijangka. + +# 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}} Anotasi] +password_label=Masukan kata kunci untuk membuka fail PDF ini. +password_invalid=Kata laluan salah. Cuba lagi. +password_ok=OK +password_cancel=Batal + +printing_not_supported=Amaran: Cetakan ini tidak sepenuhnya disokong oleh pelayar ini. +printing_not_ready=Amaran: PDF tidak sepenuhnya dimuatkan untuk dicetak. +web_fonts_disabled=Fon web dinyahdayakan: tidak dapat menggunakan fon terbenam PDF. +document_colors_not_allowed=Dokumen PDF tidak dibenarkan untuk menggunakan warna sendiri: β€œIzinkan halaman untuk memilih warna sendiri” telah dinyahaktifkan dalam pelayar. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/my/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/my/viewer.properties new file mode 100755 index 00000000..ff9f5e29 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/my/viewer.properties @@ -0,0 +1,180 @@ +# 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=({{pagesCount}} ၏ {{pageNumber}}) + +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=ပထမ α€…α€¬α€™α€»α€€α€Ία€”α€Ύα€¬α€žα€­α€―α€· +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=နာရα€α€œα€€α€Ία€α€Ά ပြောင်းပြန် + + +# 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_kb}}α€˜α€­α€―α€α€Ί) +# 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=α€α€±α€«α€„α€Ία€Έα€…α€‰α€Ίβ€Œ - +document_properties_author=α€›α€±α€Έα€žα€¬α€Έα€žα€°: +document_properties_subject=ထကြောင်းထရာ:\u0020 +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_close=ပိတ် + +print_progress_message=Preparing document for printing… +# 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_notification.title=α€˜α€±α€Έα€˜α€¬α€Έα€α€”α€Ία€Έα€€α€­α€― ထဖွင့်/ထပိတ် α€œα€―α€•α€Ία€›α€”α€Ί (စာတမ်းတွင် outline/attachments α€•α€«α€α€„α€Ία€”α€­α€―α€„α€Ία€žα€Šα€Ί) +toggle_sidebar_label=ဖွင့်ပိတ် α€†α€œα€­α€―α€€α€Ία€’α€« +document_outline.title=စာတမ်းထကျဉ်းချုပ်ကို ပြပါ (α€…α€¬α€›α€„α€Ία€Έα€‘α€¬α€Έα€œα€―α€Άα€Έα€€α€­α€― ချုဢ့/ချဲ့ရန် α€€α€œα€…α€Ία€”α€Ύα€…α€Ία€α€»α€€α€Ία€”α€Ύα€­α€•α€Ία€•α€«) +document_outline_label=စာတမ်းထကျဉ်းချုပ် +attachments.title=တွဲချက်များ ပြပါ +attachments_label=တွဲထားချက်များ +thumbs.title=α€•α€―α€Άα€›α€­α€•α€Ία€„α€šα€Ία€™α€»α€¬α€Έα€€α€­α€― ပြပါ +thumbs_label=α€•α€―α€Άα€›α€­α€•α€Ία€„α€šα€Ία€™α€»α€¬α€Έ +findbar.title=Find in Document +findbar_label=ရှာဖွေပါ + +# 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_reached_top=စာမျက်နှာထိပ် ရောက်နေပြα€αŠ ထဆုဢးကနေ ပြန်စပါ +find_reached_bottom=စာမျက်နှာထဆုဢး ရောက်နေပြα€αŠ ထိပ်ကနေ ပြန်စပါ +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_indicator=ထမှား +loading_error=PDF ဖိုင် ကိုဆွဲတင်နေချိန်မှာ α€‘α€™α€Ύα€¬α€Έα€α€…α€Ία€α€―α€α€½α€±α€·α€›α€•α€«α€α€šα€Ία‹ +invalid_file_error=α€™α€›α€žα€±α€¬ α€žα€­α€―α€· α€•α€»α€€α€Ία€”α€±α€žα€±α€¬ PDF ဖိုင် +missing_file_error=PDF ပျောက်ဆုဢး +unexpected_response_error=α€™α€™α€»α€Ύα€±α€¬α€Ία€œα€„α€Ία€·α€‘α€¬α€Έα€žα€±α€¬ ဆာဗာမှ ပြန်ကြားချက် + +# 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=OK +password_cancel=α€•α€šα€Ίβ€‹α€–α€»α€€α€Ία€•α€« + +printing_not_supported=α€žα€α€­α€•α€±α€Έα€α€»α€€α€ΊαŠα€•α€›α€„α€·α€Ία€‘α€―α€α€Ία€α€Όα€„α€Ία€Έα€€α€­α€―α€€α€˜α€šα€±α€¬α€€α€Ία€†α€¬α€žα€Šα€Ί α€•α€Όα€Šα€·α€Ία€α€…α€½α€¬α€‘α€±α€¬α€€α€Ία€•α€Άα€·α€™α€‘α€¬α€Έα€•α€« ။ +printing_not_ready=α€žα€α€­α€•α€±α€Έα€α€»α€€α€Ί: α€šα€α€― PDF α€–α€­α€―α€„α€Ία€žα€Šα€Ί ပုဢနှိပ်ရန် α€™α€•α€Όα€Šα€·α€Ία€…α€―α€Άα€•α€« +web_fonts_disabled=Web fonts are disabled: unable to use embedded PDF fonts. +document_colors_not_allowed=PDF ဖိုင်ထား αŽα€„α€Ία€Έα€€ α€€α€­α€―α€šα€Ία€•α€­α€―α€„α€Ία€‘α€›α€±α€¬α€„α€Ία€™α€»α€¬α€Έα€€α€­α€― α€‘α€žα€―α€Άα€Έα€•α€Όα€―α€α€½α€„α€Ία€·α€™α€•α€±α€Έα€‘α€¬α€Έα€•α€« ။ 'α€…α€¬α€™α€»α€€α€Ία€”α€Ύα€¬α€‘α€¬α€Έα€œα€―α€Άα€Έα€‘α€¬α€Έα€‘α€›α€±α€¬α€„α€Ία€›α€½α€±α€Έα€α€»α€šα€Ία€α€½α€„α€Ία€·' ထား α€šα€α€― α€˜α€šα€±α€¬α€€α€Ία€†α€¬α€α€½α€„α€Ί ပိတ်ထားခြင်းကြောင့်ဖြစ် α€žα€Ύα€Ί diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/nb-NO/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/nb-NO/viewer.properties new file mode 100755 index 00000000..a04a57a4 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/nb-NO/viewer.properties @@ -0,0 +1,184 @@ +# 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=Forrige side +previous_label=Forrige +next.title=Neste side +next_label=Neste + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +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=av {{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}} av {{pagesCount}}) + +zoom_out.title=Zoom ut +zoom_out_label=Zoom ut +zoom_in.title=Zoom inn +zoom_in_label=Zoom inn +zoom.title=Zoom +presentation_mode.title=Bytt til presentasjonsmodus +presentation_mode_label=Presentasjonsmodus +open_file.title=Γ…pne fil +open_file_label=Γ…pne +print.title=Skriv ut +print_label=Skriv ut +download.title=Last ned +download_label=Last ned +bookmark.title=NΓ₯vΓ¦rende visning (kopier eller Γ₯pne i et nytt vindu) +bookmark_label=NΓ₯vΓ¦rende visning + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=TekstmarkeringsverktΓΈy +cursor_hand_tool.title=Aktiver handverktΓΈy +cursor_hand_tool_label=HandverktΓΈy + +# Document properties dialog box +document_properties.title=Dokumentegenskaper … +document_properties_label=Dokumentegenskaper … +document_properties_file_name=Filnavn: +document_properties_file_size=FilstΓΈrrelse: +# 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=Dokumentegenskaper … +document_properties_author=Forfatter: +document_properties_subject=Emne: +document_properties_keywords=NΓΈkkelord: +document_properties_creation_date=Opprettet dato: +document_properties_modification_date=Endret dato: +# 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=Opprettet av: +document_properties_producer=PDF-verktΓΈy: +document_properties_version=PDF-versjon: +document_properties_page_count=Sideantall: +document_properties_close=Lukk + +print_progress_message=Forbereder dokument for utskrift … +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Avbryt + +# 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=SlΓ₯ av/pΓ₯ sidestolpe +toggle_sidebar_notification.title=Vis/gjem sidestolpe (dokumentet inneholder oversikt/vedlegg) +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 +thumbs.title=Vis miniatyrbilde +thumbs_label=Miniatyrbilde +findbar.title=Finn i dokumentet +findbar_label=Finn + +# 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=Side {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Miniatyrbilde av side {{page}} + +# Find panel button title and messages +find_input.title=SΓΈk +find_input.placeholder=SΓΈk i dokument… +find_previous.title=Finn forrige forekomst av frasen +find_previous_label=Forrige +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_reached_top=NΓ₯dde toppen av dokumentet, fortsetter fra bunnen +find_reached_bottom=NΓ₯dde bunnen av dokumentet, fortsetter fra toppen +find_not_found=Fant ikke teksten + +# Error panel labels +error_more_info=Mer info +error_less_info=Mindre info +error_close=Lukk +# 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}} (bygg: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Melding: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Stakk: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Fil: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Linje: {{line}} +rendering_error=En feil oppstod ved opptegning av siden. + +# Predefined zoom values +page_scale_width=Sidebredde +page_scale_fit=Tilpass til siden +page_scale_auto=Automatisk zoom +page_scale_actual=Virkelig stΓΈrrelse +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}} % + +# Loading indicator messages +loading_error_indicator=Feil +loading_error=En feil oppstod ved lasting av PDF. +invalid_file_error=Ugyldig eller skadet PDF-fil. +missing_file_error=Manglende PDF-fil. +unexpected_response_error=Uventet serverrespons. + +# 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}} annotasjon] +password_label=Skriv inn passordet for Γ₯ Γ₯pne denne PDF-filen. +password_invalid=Ugyldig passord. PrΓΈv igjen. +password_ok=OK +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. +document_colors_not_allowed=PDF-dokumenter tillates ikke Γ₯ bruke deres egne farger: "Tillat sider Γ₯ velge egne farger" er deaktivert i nettleseren. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/nl/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/nl/viewer.properties new file mode 100755 index 00000000..c66d0350 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/nl/viewer.properties @@ -0,0 +1,184 @@ +# 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=Vorige pagina +previous_label=Vorige +next.title=Volgende pagina +next_label=Volgende + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Pagina +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=van {{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}} van {{pagesCount}}) + +zoom_out.title=Uitzoomen +zoom_out_label=Uitzoomen +zoom_in.title=Inzoomen +zoom_in_label=Inzoomen +zoom.title=Zoomen +presentation_mode.title=Wisselen naar presentatiemodus +presentation_mode_label=Presentatiemodus +open_file.title=Bestand openen +open_file_label=Openen +print.title=Afdrukken +print_label=Afdrukken +download.title=Downloaden +download_label=Downloaden +bookmark.title=Huidige weergave (kopiΓ«ren of openen in nieuw venster) +bookmark_label=Huidige weergave + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=Tekstselectiehulpmiddel +cursor_hand_tool.title=Handhulpmiddel inschakelen +cursor_hand_tool_label=Handhulpmiddel + +# Document properties dialog box +document_properties.title=Documenteigenschappen… +document_properties_label=Documenteigenschappen… +document_properties_file_name=Bestandsnaam: +document_properties_file_size=Bestandsgrootte: +# 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=Titel: +document_properties_author=Auteur: +document_properties_subject=Onderwerp: +document_properties_keywords=Trefwoorden: +document_properties_creation_date=Aanmaakdatum: +document_properties_modification_date=Wijzigingsdatum: +# 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=Auteur: +document_properties_producer=PDF-producent: +document_properties_version=PDF-versie: +document_properties_page_count=Aantal pagina’s: +document_properties_close=Sluiten + +print_progress_message=Document voorbereiden voor afdrukken… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Annuleren + +# 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=Zijbalk in-/uitschakelen +toggle_sidebar_notification.title=Zijbalk in-/uitschakelen (document bevat overzicht/bijlagen) +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 +thumbs.title=Miniaturen tonen +thumbs_label=Miniaturen +findbar.title=Zoeken in document +findbar_label=Zoeken + +# 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=Pagina {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Miniatuur van pagina {{page}} + +# Find panel button title and messages +find_input.title=Zoeken +find_input.placeholder=Zoeken in document… +find_previous.title=De vorige overeenkomst van de tekst zoeken +find_previous_label=Vorige +find_next.title=De volgende overeenkomst van de tekst zoeken +find_next_label=Volgende +find_highlight=Alles markeren +find_match_case_label=Hoofdlettergevoelig +find_reached_top=Bovenkant van document bereikt, doorgegaan vanaf onderkant +find_reached_bottom=Onderkant van document bereikt, doorgegaan vanaf bovenkant +find_not_found=Tekst niet gevonden + +# Error panel labels +error_more_info=Meer informatie +error_less_info=Minder informatie +error_close=Sluiten +# 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=Bericht: {{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=Bestand: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Regel: {{line}} +rendering_error=Er is een fout opgetreden bij het weergeven van de pagina. + +# Predefined zoom values +page_scale_width=Paginabreedte +page_scale_fit=Hele pagina +page_scale_auto=Automatisch zoomen +page_scale_actual=Werkelijke grootte +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Fout +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. +unexpected_response_error=Onverwacht serverantwoord. + +# 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}}-aantekening] +password_label=Voer het wachtwoord in om dit PDF-bestand te openen. +password_invalid=Ongeldig wachtwoord. Probeer het opnieuw. +password_ok=OK +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. +document_colors_not_allowed=PDF-documenten mogen hun eigen kleuren niet gebruiken: β€˜Pagina’s toestaan om hun eigen kleuren te kiezen’ is uitgeschakeld in de browser. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/nn-NO/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/nn-NO/viewer.properties new file mode 100755 index 00000000..82473da8 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/nn-NO/viewer.properties @@ -0,0 +1,184 @@ +# 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=FΓΈregΓ₯ande side +previous_label=FΓΈregΓ₯ande +next.title=Neste side +next_label=Neste + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +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=av {{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}} av {{pagesCount}}) + +zoom_out.title=Zoom ut +zoom_out_label=Zoom ut +zoom_in.title=Zoom inn +zoom_in_label=Zoom inn +zoom.title=Zoom +presentation_mode.title=Byt til presentasjonsmodus +presentation_mode_label=Presentasjonsmodus +open_file.title=Opne fil +open_file_label=Opne +print.title=Skriv ut +print_label=Skriv ut +download.title=Last ned +download_label=Last ned +bookmark.title=Gjeldande vising (kopier eller opne i nytt vindauge) +bookmark_label=Gjeldande vising + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=TekstmarkeringsverktΓΈy +cursor_hand_tool.title=Aktiver handverktΓΈy +cursor_hand_tool_label=HandverktΓΈy + +# Document properties dialog box +document_properties.title=Dokumenteigenskapar… +document_properties_label=Dokumenteigenskapar… +document_properties_file_name=Filnamn: +document_properties_file_size=Filstorleik: +# 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=Tittel: +document_properties_author=Forfattar: +document_properties_subject=Emne: +document_properties_keywords=Stikkord: +document_properties_creation_date=Dato oppretta: +document_properties_modification_date=Dato endra: +# 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=Oppretta av: +document_properties_producer=PDF-verktΓΈy: +document_properties_version=PDF-versjon: +document_properties_page_count=Sidetal: +document_properties_close=Lukk + +print_progress_message=FΓΈrebur dokumentet for utskrift… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Avbryt + +# 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=SlΓ₯ av/pΓ₯ sidestolpe +toggle_sidebar_notification.title=Vis/gΓΈym sidestolpen (dokumentet inneheld oversikt/vedlegg) +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 +thumbs.title=Vis miniatyrbilde +thumbs_label=Miniatyrbilde +findbar.title=Finn i dokumentet +findbar_label=Finn + +# 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=Side {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Miniatyrbilde av side {{page}} + +# Find panel button title and messages +find_input.title=SΓΈk +find_input.placeholder=SΓΈk i dokument… +find_previous.title=Finn fΓΈrre fΓΈrekomst av frasen +find_previous_label=FΓΈrre +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_reached_top=NΓ₯dde toppen av dokumentet, fortset frΓ₯ botnen +find_reached_bottom=NΓ₯dde botnen av dokumentet, fortset frΓ₯ toppen +find_not_found=Fann ikkje teksten + +# Error panel labels +error_more_info=Meir info +error_less_info=Mindre info +error_close=Lukk +# 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}} (bygg: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Melding: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Stakk: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Fil: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Linje: {{line}} +rendering_error=Ein feil oppstod under vising av sida. + +# Predefined zoom values +page_scale_width=Sidebreidde +page_scale_fit=Tilpass til sida +page_scale_auto=Automatisk skalering +page_scale_actual=Verkeleg storleik +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Feil +loading_error=Ein feil oppstod ved lasting av PDF. +invalid_file_error=Ugyldig eller korrupt PDF-fil. +missing_file_error=Manglande PDF-fil. +unexpected_response_error=Uventa tenarrespons. + +# 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}} annotasjon] +password_label=Skriv inn passordet for Γ₯ opne denne PDF-fila. +password_invalid=Ugyldig passord. PrΓΈv igjen. +password_ok=OK +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. +document_colors_not_allowed=PDF-dokument kan ikkje bruke eigne fargar: Β«Tillat sider Γ₯ velje eigne fargarΒ» er deaktivert i nettlesaren. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/nso/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/nso/viewer.properties new file mode 100755 index 00000000..d95406c9 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/nso/viewer.properties @@ -0,0 +1,130 @@ +# 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=Letlakala le fetilego +previous_label=Fetilego +next.title=Letlakala le latelago +next_label=Latelago + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +zoom_out.title=BuΕ‘etΕ‘a ka gare +zoom_out_label=BuΕ‘etΕ‘a ka gare +zoom_in.title=GodiΕ‘etΕ‘a ka ntle +zoom_in_label=GodiΕ‘etΕ‘a ka ntle +zoom.title=GodiΕ‘a +presentation_mode.title=Fetogela go mokgwa wa tlhagiΕ‘o +presentation_mode_label=Mokgwa wa tlhagiΕ‘o +open_file.title=Bula faele +open_file_label=Bula +print.title=GatiΕ‘a +print_label=GatiΕ‘a +download.title=Laolla +download_label=Laolla +bookmark.title=Pono ya bjale (kopiΕ‘a le go bula lefasetereng le leswa) +bookmark_label=Tebelelo ya gona bjale + +# Secondary toolbar and context menu + + +# Document properties dialog box +document_properties_file_name=Leina la faele: +# LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" +# will be replaced by the PDF file size in kilobytes, respectively in 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_title=Thaetlele: +# LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" +# will be replaced by the creation/modification date, and time, of the PDF file. + +# 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) +toggle_sidebar.title=Ε ielanya para ya ka thoko +toggle_sidebar_label=Ε ielanya para ya ka thoko +document_outline_label=KakaretΕ‘o ya tokumente +thumbs.title=LaetΕ‘a dikhutΕ‘ofatΕ‘o +thumbs_label=DikhutΕ‘ofatΕ‘o +findbar.title=HwetΕ‘a go tokumente + +# 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=Letlakala {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=KhutΕ‘ofatΕ‘o ya letlakala {{page}} + +# Find panel button title and messages +find_previous.title=HwetΕ‘a tiragalo e fetilego ya sekafoko +find_previous_label=Fetilego +find_next.title=HwetΕ‘a tiragalo e latelago ya sekafoko +find_next_label=Latelago +find_highlight=BonagatΕ‘a tΕ‘ohle +find_match_case_label=SwantΕ‘ha kheisi +find_reached_top=Fihlile godimo ga tokumente, go tΕ‘wetΕ‘we pele go tloga tlase +find_reached_bottom=Fihlile mafelelong a tokumente, go tΕ‘wetΕ‘we pele go tloga godimo +find_not_found=Sekafoko ga sa hwetΕ‘wa + +# Error panel labels +error_more_info=TshedimoΕ‘o e oketΕ‘egilego +error_less_info=TshedimoΕ‘o ya tlasana +# 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=MolaetΕ‘a: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Mokgobo: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Faele: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Mothaladi: {{line}} +rendering_error=Go diregile phoΕ‘o ge go be go gafelwa letlakala. + +# Predefined zoom values +page_scale_width=Bophara bja letlakala +page_scale_fit=Go lekana ga letlakala +page_scale_auto=KgodiΕ‘o ya maitiriΕ‘o +page_scale_actual=Bogolo bja kgonthe +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. + +# Loading indicator messages +loading_error_indicator=PhoΕ‘o +loading_error=Go diregile phoΕ‘o ge go hlahlelwa PDF. +invalid_file_error=Faele ye e sa Ε‘omego goba e senyegilego ya PDF. +missing_file_error=Faele yeo e sego gona ya PDF. + +# 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}} Tlhaloso] +password_ok=LOKILE + +printing_not_supported=TemoΕ‘o: Go gatiΕ‘a ga go thekgwe ke praosara ye ka botlalo. +printing_not_ready=TemoΕ‘o: PDF ga ya hlahlelwa ka botlalo bakeng sa go gatiΕ‘wa. +web_fonts_disabled=Difonte tΕ‘a wepe di Ε‘itiΕ‘itΕ‘we: ga e kgone go diriΕ‘a difonte tΕ‘a PDF tΕ‘e khutiΕ‘itΕ‘wego. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/oc/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/oc/viewer.properties new file mode 100755 index 00000000..fbea2670 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/oc/viewer.properties @@ -0,0 +1,174 @@ +# 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=Pagina precedenta +previous_label=Precedent +next.title=Pagina seguenta +next_label=Seguent + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Pagina +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +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. + +zoom_out.title=Zoom arriΓ¨r +zoom_out_label=Zoom arriΓ¨r +zoom_in.title=Zoom avant +zoom_in_label=Zoom avant +zoom.title=Zoom +presentation_mode.title=Bascular en mΓ²de presentacion +presentation_mode_label=MΓ²de Presentacion +open_file.title=Dobrir lo fichiΓ¨r +open_file_label=Dobrir +print.title=Imprimir +print_label=Imprimir +download.title=Telecargar +download_label=Telecargar +bookmark.title=Afichatge corrent (copiar o dobrir dins una fenΓ¨stra novΓ¨la) +bookmark_label=Afichatge actual + +# Secondary toolbar and context menu +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 + +hand_tool_enable.title=Activar l'aisina man +hand_tool_enable_label=Activar l'aisina man +hand_tool_disable.title=Desactivar l'aisina man +hand_tool_disable_label=Desactivar l'aisina man + +# Document properties dialog box +document_properties.title=Proprietats del document... +document_properties_label=Proprietats del document... +document_properties_file_name=Nom del fichiΓ¨rΒ : +document_properties_file_size=Talha del fichiΓ¨r : +# 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}} Ko ({{size_b}} octets) +# 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}} Mo ({{size_b}} octets) +document_properties_title=TΓ­tolΒ : +document_properties_author=Autor : +document_properties_subject=SubjΓ¨cte : +document_properties_keywords=Mots clausΒ : +document_properties_creation_date=Data de creacion : +document_properties_modification_date=Data de modificacion : +# 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_producer=Aisina de conversion PDF : +document_properties_version=Version PDF : +document_properties_page_count=Nombre de paginas : +document_properties_close=Tampar + +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_close=Anullar + +# 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=Afichar/amagar lo panΓ¨l lateral +toggle_sidebar_label=Afichar/amagar lo panΓ¨l lateral +document_outline_label=Marcapaginas del document +attachments.title=Visualizar las pèças juntas +attachments_label=Pèças juntas +thumbs.title=Afichar las vinhetas +thumbs_label=Vinhetas +findbar.title=Trobar dins lo document + +# 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=Pagina {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Vinheta de la pagina {{page}} + +# Find panel button title and messages +find_previous.title=TrΓ²ba l'ocurrΓ©ncia precedenta de la frasa +find_previous_label=Precedent +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_reached_top=Naut de la pagina atench, perseguida dempuΓ¨i lo bas +find_reached_bottom=Bas de la pagina atench, perseguida al comenΓ§ament +find_not_found=Frasa pas trobada + +# Error panel labels +error_more_info=Mai de detalhs +error_less_info=Mens d'informacions +error_close=Tampar +# 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}} (identificant de compilacionΒ : {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=MessatgeΒ : {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=PilaΒ : {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +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. + +# Predefined zoom values +page_scale_width=Largor plena +page_scale_fit=Pagina entiΓ¨ra +page_scale_auto=Zoom automatic +page_scale_actual=Talha vertadiΓ¨ra +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. + +# Loading indicator messages +loading_error_indicator=Error +loading_error=Una error s'es produita pendent lo cargament del fichiΓ¨r PDF. +invalid_file_error=FichiΓ¨r PDF invalid o corromput. +missing_file_error=FichiΓ¨r PDF mancant. + +# 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=[Anotacion {{type}}] +password_label=Picatz lo senhal per dobrir aqueste fichiΓ¨r PDF. +password_invalid=Senhal incorrΓ¨cte. Tornatz ensajar. +password_ok=D'acΓ²rdi +password_cancel=Anullar + +printing_not_supported=Atencion : l'impression es pas completament gerit per aqueste navigador. +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. +document_colors_not_allowed=Los documents PDF pΓ²don pas utilizar lors prΓ²prias colors : Β« Autorizar las paginas web d'utilizar lors prΓ²prias colors Β» es desactivat dins lo navigador. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/or/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/or/viewer.properties new file mode 100755 index 00000000..831eacee --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/or/viewer.properties @@ -0,0 +1,167 @@ +# 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. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +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=ΰ¬ͺ୍ରΰ¬₯ΰ¬ ΰ¬ͺୃଷ୍ଠାକୁ ଯାଆନ୍଀ୁ +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=ବାΰ¬ΰ¬Ύΰ¬¬ΰ¬°ΰ­ΰ¬€ΰ­ΰ¬€ΰ­€ ଘୁରାନ୍଀ୁ + + +# 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}} 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=ଢୀର୍ଷକ: +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_close=ବନ୍ଦ କରନ୍଀ୁ + +# 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) +toggle_sidebar.title=ΰ¬ͺାର୍ଢ୍ୱΰ¬ͺΰ¬Ÿΰ¬Ώΰ¬•ΰ­ ଆଗΰ¬ͺଛ କରନ୍଀ୁ +toggle_sidebar_label=ΰ¬ͺାର୍ଢ୍ୱΰ¬ͺΰ¬Ÿΰ¬Ώΰ¬•ΰ­ ଆଗΰ¬ͺଛ କରନ୍଀ୁ +document_outline_label=ଦଲିଲ ସାରାଂଢ +attachments.title=ସଂଲଗ୍ନକଗୁ଑଼ିକୁ ଦର୍ଢାନ୍଀ୁ +attachments_label=ସଲଗ୍ନକଗୁ଑ିକ +thumbs.title=ସଂକ୍ଷିΰ¬ͺ୍଀ ବିବରଣୀ ଦର୍ଢାନ୍଀ୁ +thumbs_label=ସଂକ୍ଷିΰ¬ͺ୍଀ ବିବରଣୀ +findbar.title=ଦଲିଲରେ ΰ¬–ΰ­‹ΰ¬œΰ¬¨ΰ­ΰ¬€ΰ­ + +# 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_previous_label=ΰ¬ͺୂର୍ବବର୍଀୍଀ୀ +find_next.title=ଏହି ΰ¬¬ΰ¬Ύΰ¬•ΰ­ΰ­Ÿΰ¬Ύΰ¬‚ΰ¬Άΰ¬° ΰ¬ͺରବର୍଀୍଀ୀ ଉΰ¬ͺସ୍ΰ¬₯ି଀ିକୁ ΰ¬–ΰ­‹ΰ¬œΰ¬¨ΰ­ΰ¬€ΰ­ +find_next_label=ΰ¬ͺରବର୍଀୍଀ୀ\u0020 +find_highlight=ΰ¬Έΰ¬ΰ¬Έΰ­ΰ¬€ΰ¬™ΰ­ΰ¬•ୁ ଆଲୋକି଀ କରନ୍଀ୁ +find_match_case_label=ଅକ୍ଷର ΰ¬ΰ­‡ΰ¬³ΰ¬Ύΰ¬¨ΰ­ΰ¬€ΰ­ +find_reached_top=଀ଳୁ ଉΰ¬ͺରକୁ ଗ଀ି କରି ଦଲିଲର ଉΰ¬ͺΰ¬° ΰ¬­ΰ¬Ύΰ¬—ΰ¬°ΰ­‡ ΰ¬ͺହଞ୍ଚି ଯାଇଛି +find_reached_bottom=ଉΰ¬ͺରୁ ଀ଳକୁ ଗ଀ି କରି ଦଲିଲର ΰ¬Άΰ­‡ΰ¬· ΰ¬­ΰ¬Ύΰ¬—ΰ¬°ΰ­‡ ΰ¬ͺହଞ୍ଚି ଯାଇଛି +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. + +# Loading indicator messages +loading_error_indicator=଀୍ରୁଟି +loading_error=PDF ଧାରଣ କରିବା ΰ¬Έΰ¬ΰ­Ÿΰ¬°ΰ­‡ ଏକ ଀୍ରୁଟି ଘଟିଲାΰ₯€ +invalid_file_error=ΰ¬…ΰ¬¬ΰ­ˆΰ¬§ କିΰ¬ΰ­ΰ¬¬ΰ¬Ύ ΰ¬€ΰ­ΰ¬°ΰ­ΰ¬Ÿΰ¬Ώΰ¬―ΰ­ΰ¬•ΰ­ΰ¬€ PDF ଫାଇଲΰ₯€ +missing_file_error=ΰ¬Ήΰ¬œΰ¬Ώΰ¬―ΰ¬Ύΰ¬‡ΰ¬₯ିବା PDF ଫାଇଲΰ₯€ +unexpected_response_error=ΰ¬…ΰ¬ͺ୍ର଀୍ୟାଢି଀ ସର୍ଭର ଉ଀୍଀ରΰ₯€ + +# 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=ଏହି PDF ଫାଇଲକୁ ଖୋଲିବା ΰ¬ͺାଇଁ ΰ¬ͺ୍ରବେଢ ସଂକେ଀ ଭରଣ କରନ୍଀ୁΰ₯€ +password_invalid=ଭୁଲ ΰ¬ͺ୍ରବେଢ ସଂକେ଀ΰ₯€ ΰ¬¦ΰ­Ÿΰ¬Ύΰ¬•ΰ¬°ΰ¬Ώ ΰ¬ͺୁଣି ΰ¬šΰ­‡ΰ¬·ΰ­ΰ¬Ÿΰ¬Ύ କରନ୍଀ୁΰ₯€ +password_ok=ଠିକ ଅଛି + +printing_not_supported=ΰ¬šΰ­‡ΰ¬€ΰ¬Ύΰ¬¬ΰ¬¨ΰ­€: ଏହି ΰ¬¬ΰ­ΰ¬°ΰ¬Ύΰ¬‰ΰ¬œΰ¬° ଦ୍ୱାରା ΰ¬ΰ­ΰ¬¦ΰ­ΰ¬°ΰ¬£ ΰ¬•ΰ­ΰ¬°ΰ¬Ώΰ­Ÿΰ¬Ύ ΰ¬Έΰ¬ΰ­ΰ¬ͺୂର୍ଣ୍ଣ ଭାବରେ ସହାୟ଀ା ΰ¬ͺ୍ରାΰ¬ͺ୍଀ ନୁହଁΰ₯€ +printing_not_ready=ΰ¬šΰ­‡ΰ¬€ΰ¬Ύΰ¬¬ΰ¬¨ΰ­€: PDF ଟି ΰ¬ΰ­ΰ¬¦ΰ­ΰ¬°ΰ¬£ ΰ¬ͺାଇଁ ΰ¬Έΰ¬ΰ­ΰ¬ͺୂର୍ଣ୍ଣ ଭାବରେ ଧାରଣ ହୋଇ ନାହିଁΰ₯€ +web_fonts_disabled=ୱେବ ଅକ୍ଷରରୂΰ¬ͺଗୁ଑଼ିକୁ ΰ¬¨ΰ¬Ώΰ¬·ΰ­ΰ¬•ΰ­ΰ¬°ΰ¬Ώΰ­Ÿ କରାଯାଇଛି: ସନ୍ନିହି଀ PDF ଅକ୍ଷରରୂΰ¬ͺଗୁ଑଼ିକୁ ବ୍ୟବହାର କରିବାରେ ΰ¬…ΰ¬Έΰ¬ΰ¬°ΰ­ΰ¬₯ΰ₯€ +document_colors_not_allowed=PDF ଦଲିଲଗୁ଑଼ିକ ΰ¬Έΰ­‡ΰ¬ΰ¬Ύΰ¬¨ΰ¬™ΰ­ΰ¬•ΰ¬° ନିଜର ରଙ୍ଗ ବ୍ୟବହାର କରିବା ΰ¬ͺାଇଁ ଅନୁΰ¬ΰ¬€ΰ¬Ώ ΰ¬ͺ୍ରାΰ¬ͺ୍଀ ନୁହଁ: 'ΰ¬Έΰ­‡ΰ¬ΰ¬Ύΰ¬¨ΰ¬™ΰ­ΰ¬•ΰ¬° ନିଜ ରଙ୍ଗ ବାଛିବା ΰ¬ͺାଇଁ ΰ¬ͺୃଷ୍ଠାଗୁ଑଼ିକୁ ଅନୁΰ¬ΰ¬€ΰ¬Ώ ଦିଅନ୍଀ୁ' କୁ ΰ¬¬ΰ­ΰ¬°ΰ¬Ύΰ¬‰ΰ¬œΰ¬°ΰ¬°ΰ­‡ ΰ¬¨ΰ¬Ώΰ¬·ΰ­ΰ¬•ΰ­ΰ¬°ΰ¬Ώΰ­Ÿ କରାଯାଇଛିΰ₯€ diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/pa-IN/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/pa-IN/viewer.properties new file mode 100755 index 00000000..dc202da5 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/pa-IN/viewer.properties @@ -0,0 +1,178 @@ +# 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=Page +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=of {{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}} of {{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=ΰ¨ͺਹਿਲੇ ΰ¨Έΰ©žΰ©‡ ਉੱ਀ੇ ΰ¨œΰ¨Ύΰ¨“ +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=ਖੱਬੇ ਦਾਅ ਘੁੰΰ¨ΰ¨Ύΰ¨“ + + +# 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}} 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_close=ਬੰਦ ਕਰੋ + +print_progress_message=Preparing document for printing… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Cancel + +# 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 (document contains outline/attachments) +toggle_sidebar_label=ਬਾਹੀ ਬਦਲੋ +document_outline.title=Show Document Outline (double-click to expand/collapse all items) +document_outline_label=Document Outline +attachments.title=ΰ¨…ΰ¨Ÿΰ©ˆΰ¨šΰ¨ΰ©ˆΰ¨‚ΰ¨Ÿ ਨੂੰ ਡੇਖਾਓ +attachments_label=ΰ¨…ΰ¨Ÿΰ©ˆΰ¨šΰ¨ΰ©ˆΰ¨‚ΰ¨Ÿ +thumbs.title=ΰ¨₯ΰ©°ΰ¨ΰ¨¨ΰ©‡ΰ¨² ਨੂੰ ਡੇਖਾਓ +thumbs_label=ΰ¨₯ΰ©°ΰ¨ΰ¨¨ΰ©‡ΰ¨² +findbar.title=ਦਸ਀ਾਡੇਜ਼ ਡਿੱਚ ਲੱਭੋ +findbar_label=ਲੱਭੋ + +# 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_previous_label=ΰ¨ͺਿੱਛੇ +find_next.title=ਡਾਕ ਦੀ ਅਗਲੀ ΰ¨ΰ©Œΰ¨œΰ©‚ਦਗੀ ਲੱਭੋ +find_next_label=ਅੱਗੇ +find_highlight=ΰ¨Έΰ¨­ ਉਭਾਰੋ +find_match_case_label=ΰ¨…ΰ©±ΰ¨–ΰ¨° ਆਕਾਰ ਨੂੰ ΰ¨ΰ¨Ώΰ¨²ΰ¨Ύΰ¨‰ +find_reached_top=ਦਸ਀ਾਡੇਜ਼ ਦੇ ਉੱ਀ੇ ਆ ਗਏ ਹਾਂ, ΰ¨₯ੱਲੇ ਀ੋਂ ΰ¨œΰ¨Ύΰ¨°ΰ©€ ਰੱਖਿਆ ਹੈ +find_reached_bottom=ਦਸ਀ਾਡੇਜ਼ ਦੇ ਅੰ਀ ਉੱ਀ੇ ਆ ਗਏ ਹਾਂ, ਉੱ਀ੇ ਀ੋਂ ΰ¨œΰ¨Ύΰ¨°ΰ©€ ਰੱਖਿਆ ਹੈ +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_error_indicator=ਗਲ਀ੀ +loading_error=PDF ਲੋ਑ ਕਰਨ ਦੇ ਦੌਰਾਨ ਗਲ਀ੀ ΰ¨†ΰ¨ˆ ਹੈΰ₯€ +invalid_file_error=ਗਲ਀ ΰ¨œΰ¨Ύΰ¨‚ ਨਿਕਾਰਾ PDF ਫਾਈਲ ਹੈΰ₯€ +missing_file_error=ਨਾ-ΰ¨ΰ©Œΰ¨œΰ©‚ਦ PDF ਫਾਈਲΰ₯€ +unexpected_response_error=ΰ¨…ΰ¨£ΰ¨œΰ¨Ύΰ¨£ ਸਰਡਰ ਜਡਾਬΰ₯€ + +# 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 ΰ¨«ΰ©‹ΰ¨‚ΰ¨Ÿ ਨੂੰ ਡਰ਀ਣ ਲਈ ΰ¨…ΰ¨Έΰ¨ΰ¨°ΰ©±ΰ¨₯ ਹੈΰ₯€ +document_colors_not_allowed=PDF ਦਸ਀ਾਡੇਜ਼ਾਂ ਨੂੰ ਆΰ¨ͺਣੇ ΰ¨°ΰ©°ΰ¨— ਡਰ਀ਣ ਦੀ ਇਜ਼ਾਜ਼਀ ਨਹੀਂ ਹੈΰ₯€: ΰ¨¬ΰ¨°ΰ¨Ύΰ¨Šΰ©›ΰ¨° ਡਿੱਚ β€œΰ¨Έΰ©žΰ¨Ώΰ¨†ΰ¨‚ ਨੂੰ ਆΰ¨ͺਣੇ ΰ¨°ΰ©°ΰ¨— ਚੁਣਨ ਦੀ ਇਜ਼ਾਜ਼਀ ਦਿਓ” ਨਾ-ΰ¨Έΰ¨°ΰ¨—ΰ¨°ΰ¨ ΰ¨Ήΰ©ˆΰ₯€ diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/pl/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/pl/viewer.properties new file mode 100755 index 00000000..fc26be8c --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/pl/viewer.properties @@ -0,0 +1,131 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +previous.title=Poprzednia strona +previous_label=Poprzednia +next.title=NastΔ™pna strona +next_label=NastΔ™pna + +page.title==Strona: +of_pages=zΒ {{pagesCount}} +page_of_pages=({{pageNumber}}Β zΒ {{pagesCount}}) + +zoom_out.title=Pomniejszenie +zoom_out_label=Pomniejsz +zoom_in.title=PowiΔ™kszenie +zoom_in_label=PowiΔ™ksz +zoom.title=Skala +presentation_mode.title=PrzeΕ‚Δ…cz na tryb prezentacji +presentation_mode_label=Tryb prezentacji +open_file.title=Otwieranie pliku +open_file_label=OtwΓ³rz +print.title=Drukowanie +print_label=Drukuj +download.title=Pobieranie +download_label=Pobierz +bookmark.title=BieΕΌΔ…ca pozycja (skopiuj lub otwΓ³rz jako odnoΕ›nik wΒ nowym oknie) +bookmark_label=BieΕΌΔ…ca pozycja + +tools.title=NarzΔ™dzia +tools_label=NarzΔ™dzia +first_page.title=Przechodzenie do pierwszej strony +first_page.label=PrzejdΕΊ do pierwszej strony +first_page_label=PrzejdΕΊ do pierwszej strony +last_page.title=Przechodzenie do ostatniej strony +last_page.label=PrzejdΕΊ do ostatniej strony +last_page_label=PrzejdΕΊ do ostatniej strony +page_rotate_cw.title=Obracanie 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=Obracanie 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Ε‚Δ…cza narzΔ™dzie zaznaczania tekstu +cursor_text_select_tool_label=NarzΔ™dzie zaznaczania tekstu +cursor_hand_tool.title=WΕ‚Δ…cza narzΔ™dzie rΔ…czka +cursor_hand_tool_label=NarzΔ™dzie rΔ…czka + +document_properties.title=WΕ‚aΕ›ciwoΕ›ci dokumentu… +document_properties_label=WΕ‚aΕ›ciwoΕ›ci dokumentu… +document_properties_file_name=Nazwa pliku: +document_properties_file_size=Rozmiar pliku: +document_properties_kb={{size_kb}} KB ({{size_b}} b) +document_properties_mb={{size_mb}} MB ({{size_b}} b) +document_properties_title=TytuΕ‚: +document_properties_author=Autor: +document_properties_subject=Temat: +document_properties_keywords=SΕ‚owa kluczowe: +document_properties_creation_date=Data utworzenia: +document_properties_modification_date=Data modyfikacji: +document_properties_date_string={{date}}, {{time}} +document_properties_creator=Utworzony przez: +document_properties_producer=PDF wyprodukowany przez: +document_properties_version=Wersja PDF: +document_properties_page_count=Liczba stron: +document_properties_close=Zamknij + +print_progress_message=Przygotowywanie dokumentu do druku… +print_progress_percent={{progress}}% +print_progress_close=Anuluj + +toggle_sidebar.title=PrzeΕ‚Δ…czanie panelu bocznego +toggle_sidebar_notification.title=PrzeΕ‚Δ…czanie panelu bocznego (dokument zawiera konspekt/zaΕ‚Δ…czniki) +toggle_sidebar_label=PrzeΕ‚Δ…cz panel boczny +document_outline.title=WyΕ›wietlanie zarysu dokumentu (podwΓ³jne klikniΔ™cie rozwija lub zwija wszystkie pozycje) +document_outline_label=Zarys dokumentu +attachments.title=WyΕ›wietlanie zaΕ‚Δ…cznikΓ³w +attachments_label=ZaΕ‚Δ…czniki +thumbs.title=WyΕ›wietlanie miniaturek +thumbs_label=Miniaturki +findbar.title=ZnajdΕΊ wΒ dokumencie +findbar_label=ZnajdΕΊ + +thumb_page_title=Strona {{page}} +thumb_page_canvas=Miniaturka strony {{page}} + +find_input.title=Wyszukiwanie +find_input.placeholder=Szukaj wΒ dokumencie… +find_previous.title=ZnajdΕΊ poprzednie wystΔ…pienie tekstu +find_previous_label=Poprzednie +find_next.title=ZnajdΕΊ nastΔ™pne wystΔ…pienie tekstu +find_next_label=NastΔ™pne +find_highlight=PodΕ›wietl wszystkie +find_match_case_label=RozrΓ³ΕΌniaj wielkoΕ›Δ‡ znakΓ³w +find_reached_top=OsiΔ…gniΔ™to poczΔ…tek dokumentu, kontynuacja od koΕ„ca +find_reached_bottom=OsiΔ…gniΔ™to koniec dokumentu, kontynuacja od poczΔ…tku +find_not_found=Tekst nieznaleziony + +error_more_info=WiΔ™cej informacji +error_less_info=Mniej informacji +error_close=Zamknij +error_version_info=PDF.js v{{version}} (kompilacja: {{build}}) +error_message=WiadomoΕ›Δ‡: {{message}} +error_stack=Stos: {{stack}} +error_file=Plik: {{file}} +error_line=Wiersz: {{line}} +rendering_error=Podczas renderowania strony wystΔ…piΕ‚ bΕ‚Δ…d. + +page_scale_width=SzerokoΕ›Δ‡ strony +page_scale_fit=Dopasowanie strony +page_scale_auto=Skala automatyczna +page_scale_actual=Rozmiar rzeczywisty +page_scale_percent={{scale}}% + +loading_error_indicator=BΕ‚Δ…d +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. +unexpected_response_error=Nieoczekiwana odpowiedΕΊ serwera. + +text_annotation_type.alt=[Adnotacja: {{type}}] +password_label=WprowadΕΊ hasΕ‚o, aby otworzyΔ‡ ten dokument PDF. +password_invalid=NieprawidΕ‚owe hasΕ‚o. ProszΔ™ sprΓ³bowaΔ‡ ponownie. +password_ok=OK +password_cancel=Anuluj + +printing_not_supported=OstrzeΕΌenie: Drukowanie nie jest wΒ peΕ‚ni obsΕ‚ugiwane przez 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. +document_colors_not_allowed=Dokumenty PDF nie mogΔ… uΕΌywaΔ‡ wΕ‚asnych kolorΓ³w: Opcja β€žPozwalaj stronom stosowaΔ‡ inne kolory” wΒ przeglΔ…darce jest nieaktywna. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/pt-BR/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/pt-BR/viewer.properties new file mode 100755 index 00000000..c2371c4d --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/pt-BR/viewer.properties @@ -0,0 +1,184 @@ +# 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 anterior +previous_label=Anterior +next.title=PrΓ³xima pΓ‘gina +next_label=PrΓ³xima + +# 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=Reduzir +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_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 +bookmark.title=VisualizaΓ§Γ£o atual (copiar ou abrir em uma nova janela) +bookmark_label=VisualizaΓ§Γ£o atual + +# Secondary toolbar and context menu +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=Habilitar a ferramenta de seleΓ§Γ£o de texto +cursor_text_select_tool_label=Ferramenta de seleΓ§Γ£o de texto +cursor_hand_tool.title=Habilitar ferramenta de mΓ£o +cursor_hand_tool_label=Ferramenta de mΓ£o + +# Document properties dialog box +document_properties.title=Propriedades do documento… +document_properties_label=Propriedades do documento… +document_properties_file_name=Nome do arquivo: +document_properties_file_size=Tamanho do arquivo: +# 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Γ­tulo: +document_properties_author=Autor: +document_properties_subject=Assunto: +document_properties_keywords=Palavras-chave: +document_properties_creation_date=Data da criaΓ§Γ£o: +document_properties_modification_date=Data da modificaΓ§Γ£o: +# 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=CriaΓ§Γ£o: +document_properties_producer=Criador do PDF: +document_properties_version=VersΓ£o do PDF: +document_properties_page_count=NΓΊmero de pΓ‘ginas: +document_properties_close=Fechar + +print_progress_message=Preparando documento para impressΓ£o… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}} % +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) +document_outline_label=Estrutura do documento +attachments.title=Mostrar anexos +attachments_label=Anexos +thumbs.title=Mostrar miniaturas +thumbs_label=Miniaturas +findbar.title=Localizar no documento +findbar_label=Localizar + +# 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 da pΓ‘gina {{page}} + +# Find panel button title and messages +find_input.title=Localizar +find_input.placeholder=Localizar no documento… +find_previous.title=Localizar a ocorrΓͺncia anterior da frase +find_previous_label=Anterior +find_next.title=Localizar a prΓ³xima ocorrΓͺncia da frase +find_next_label=PrΓ³xima +find_highlight=RealΓ§ar tudo +find_match_case_label=Diferenciar maiΓΊsculas/minΓΊsculas +find_reached_top=InΓ­cio do documento alcanΓ§ado, continuando do fim +find_reached_bottom=Fim do documento alcanΓ§ado, continuando do inΓ­cio +find_not_found=Frase nΓ£o encontrada + +# Error panel labels +error_more_info=Mais informaΓ§Γ΅es +error_less_info=Menos informaΓ§Γ΅es +error_close=Fechar +# 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}} (compilaΓ§Γ£o: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Mensagem: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Pilha: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Arquivo: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Linha: {{line}} +rendering_error=Ocorreu um erro ao renderizar a pΓ‘gina. + +# Predefined zoom values +page_scale_width=Largura da pΓ‘gina +page_scale_fit=Ajustar Γ  janela +page_scale_auto=Zoom automΓ‘tico +page_scale_actual=Tamanho 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=Erro +loading_error=Ocorreu um erro ao carregar o PDF. +invalid_file_error=Arquivo PDF corrompido ou invΓ‘lido. +missing_file_error=Arquivo PDF ausente. +unexpected_response_error=Resposta inesperada do servidor. + +# 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=[AnotaΓ§Γ£o {{type}}] +password_label=ForneΓ§a a senha para abrir este arquivo PDF. +password_invalid=Senha invΓ‘lida. Por favor, tentar de novo. +password_ok=OK +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 desabilitadas: nΓ£o foi possΓ­vel usar fontes incorporadas do PDF. +document_colors_not_allowed=Os documentos em PDF nΓ£o estΓ£o autorizados a usar suas prΓ³prias cores: β€œPermitir que as pΓ‘ginas escolham suas prΓ³prias cores” estΓ‘ desabilitado no navegador. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/pt-PT/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/pt-PT/viewer.properties new file mode 100755 index 00000000..6ae8bead --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/pt-PT/viewer.properties @@ -0,0 +1,184 @@ +# 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 anterior +previous_label=Anterior +next.title=PΓ‘gina seguinte +next_label=Seguinte + +# 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=Reduzir +zoom_out_label=Reduzir +zoom_in.title=Ampliar +zoom_in_label=Ampliar +zoom.title=Zoom +presentation_mode.title=Trocar para o modo de apresentaΓ§Γ£o +presentation_mode_label=Modo de apresentaΓ§Γ£o +open_file.title=Abrir ficheiro +open_file_label=Abrir +print.title=Imprimir +print_label=Imprimir +download.title=Descarregar +download_label=Descarregar +bookmark.title=VisΓ£o atual (copiar ou abrir em nova janela) +bookmark_label=VisΓ£o atual + +# Secondary toolbar and context menu +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 +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 + +# Document properties dialog box +document_properties.title=Propriedades do documento… +document_properties_label=Propriedades do documento… +document_properties_file_name=Nome do ficheiro: +document_properties_file_size=Tamanho do ficheiro: +# 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Γ­tulo: +document_properties_author=Autor: +document_properties_subject=Assunto: +document_properties_keywords=Palavras-chave: +document_properties_creation_date=Data de criaΓ§Γ£o: +document_properties_modification_date=Data de modificaΓ§Γ£o: +# 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=Criador: +document_properties_producer=Produtor de PDF: +document_properties_version=VersΓ£o do PDF: +document_properties_page_count=N.ΒΊ de pΓ‘ginas: +document_properties_close=Fechar + +print_progress_message=A preparar o documento para impressΓ£o… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +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 barra lateral +toggle_sidebar_notification.title=Alternar barra lateral (documento contΓ©m contorno/anexos) +toggle_sidebar_label=Alternar barra lateral +document_outline.title=Mostrar esquema do documento (duplo clique para expandir/colapsar todos os itens) +document_outline_label=Estrutura do documento +attachments.title=Mostrar anexos +attachments_label=Anexos +thumbs.title=Mostrar miniaturas +thumbs_label=Miniaturas +findbar.title=Localizar no documento +findbar_label=Localizar + +# 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 da pΓ‘gina {{page}} + +# Find panel button title and messages +find_input.title=Localizar +find_input.placeholder=Localizar no documento… +find_previous.title=Localizar ocorrΓͺncia anterior da frase +find_previous_label=Anterior +find_next.title=Localizar ocorrΓͺncia seguinte da frase +find_next_label=Seguinte +find_highlight=Destacar tudo +find_match_case_label=CorrespondΓͺncia +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 +find_not_found=Frase nΓ£o encontrada + +# Error panel labels +error_more_info=Mais informaΓ§Γ£o +error_less_info=Menos informaΓ§Γ£o +error_close=Fechar +# 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}} (compilaΓ§Γ£o: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Mensagem: {{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=Ficheiro: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Linha: {{line}} +rendering_error=Ocorreu um erro ao processar a pΓ‘gina. + +# Predefined zoom values +page_scale_width=Ajustar Γ  largura +page_scale_fit=Ajustar Γ  pΓ‘gina +page_scale_auto=Zoom automΓ‘tico +page_scale_actual=Tamanho 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=Erro +loading_error=Ocorreu um erro ao carregar o PDF. +invalid_file_error=Ficheiro PDF invΓ‘lido ou danificado. +missing_file_error=Ficheiro PDF inexistente. +unexpected_response_error=Resposta inesperada do servidor. + +# 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=[AnotaΓ§Γ£o {{type}}] +password_label=Digite a palavra-passe para abrir este ficheiro PDF. +password_invalid=Palavra-passe invΓ‘lida. Por favor, tente novamente. +password_ok=OK +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 incorporados. +document_colors_not_allowed=Os documentos PDF nΓ£o permitem a utilizaΓ§Γ£o das suas prΓ³prias cores: β€œPermitir Γ s pΓ‘ginas escolher as suas prΓ³prias cores” estΓ‘ desativado no navegador. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/rm/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/rm/viewer.properties new file mode 100755 index 00000000..d9eb5240 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/rm/viewer.properties @@ -0,0 +1,184 @@ +# 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=Pagina precedenta +previous_label=Enavos +next.title=Proxima pagina +next_label=Enavant + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Pagina +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=da {{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}} da {{pagesCount}}) + +zoom_out.title=Empitschnir +zoom_out_label=Empitschnir +zoom_in.title=Engrondir +zoom_in_label=Engrondir +zoom.title=Zoom +presentation_mode.title=Midar en il modus da preschentaziun +presentation_mode_label=Modus da preschentaziun +open_file.title=Avrir datoteca +open_file_label=Avrir +print.title=Stampar +print_label=Stampar +download.title=Telechargiar +download_label=Telechargiar +bookmark.title=Vista actuala (copiar u avrir en ina nova fanestra) +bookmark_label=Vista actuala + +# Secondary toolbar and context menu +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 +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 + +# Document properties dialog box +document_properties.title=Caracteristicas dal document… +document_properties_label=Caracteristicas dal document… +document_properties_file_name=Num da la datoteca: +document_properties_file_size=Grondezza da la datoteca: +# 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=Titel: +document_properties_author=Autur: +document_properties_subject=Tema: +document_properties_keywords=Chavazzins: +document_properties_creation_date=Data da creaziun: +document_properties_modification_date=Data da modificaziun: +# 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=CreΓ  da: +document_properties_producer=CreΓ  il PDF cun: +document_properties_version=Versiun da PDF: +document_properties_page_count=Dumber da paginas: +document_properties_close=Serrar + +print_progress_message=Preparar il document per stampar… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Interrumper + +# 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=Activar/deactivar la trav laterala +toggle_sidebar_notification.title=Activar/deactivar la trav laterala (structura dal document/agiuntas) +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 +thumbs.title=Mussar las miniaturas +thumbs_label=Miniaturas +findbar.title=Tschertgar en il document +findbar_label=Tschertgar + +# 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=Pagina {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Miniatura da la pagina {{page}} + +# Find panel button title and messages +find_input.title=Tschertgar +find_input.placeholder=Tschertgar en il document… +find_previous.title=Tschertgar la posiziun precedenta da l'expressiun +find_previous_label=Enavos +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_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 +find_not_found=Impussibel da chattar l'expressiun + +# Error panel labels +error_more_info=Dapli infurmaziuns +error_less_info=Damain infurmaziuns +error_close=Serrar +# 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=Messadi: {{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=Datoteca: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Lingia: {{line}} +rendering_error=Ina errur Γ¨ cumparida cun visualisar questa pagina. + +# Predefined zoom values +page_scale_width=Ladezza da la pagina +page_scale_fit=Entira pagina +page_scale_auto=Zoom automatic +page_scale_actual=Grondezza actuala +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Errur +loading_error=Ina errur Γ¨ cumparida cun chargiar il PDF. +invalid_file_error=Datoteca PDF nunvalida u donnegiada. +missing_file_error=Datoteca PDF manconta. +unexpected_response_error=Resposta nunspetgada dal server. + +# 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=[Annotaziun da {{type}}] +password_label=Endatescha il pled-clav per avrir questa datoteca da PDF. +password_invalid=Pled-clav nunvalid. Emprova anc ina giada. +password_ok=OK +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. +document_colors_not_allowed=Documents da PDF na dastgan betg duvrar las atgnas colurs: 'Permetter a paginas da tscherner lur atgna colur' Γ¨ deactivΓ  en il navigatur. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ro/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ro/viewer.properties new file mode 100755 index 00000000..c987c7b7 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ro/viewer.properties @@ -0,0 +1,177 @@ +# 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=Pagina precedentΔƒ +previous_label=Înapoi +next.title=Pagina urmΔƒtoare +next_label=Înainte + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Pagina +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=din {{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}} din {{pagesCount}}) + +zoom_out.title=MicΘ™oreazΔƒ +zoom_out_label=MicΘ™oreazΔƒ +zoom_in.title=MΔƒreΘ™te +zoom_in_label=MΔƒreΘ™te +zoom.title=Zoom +presentation_mode.title=SchimbΔƒ la modul de prezentare +presentation_mode_label=Mod de prezentare +open_file.title=Deschide un fiΘ™ier +open_file_label=Deschide +print.title=TipΔƒreΘ™te +print_label=TipΔƒreΘ™te +download.title=DescarcΔƒ +download_label=DescarcΔƒ +bookmark.title=Vizualizare actualΔƒ (copiaΘ›i sau deschideΘ›i Γntr-o fereastrΔƒ nouΔƒ) +bookmark_label=Vizualizare actualΔƒ + +# Secondary toolbar and context menu +tools.title=Unelte +tools_label=Unelte +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 ceasornic +page_rotate_cw.label=RoteΘ™te Γn sensul acelor de ceasornic +page_rotate_cw_label=RoteΘ™te Γn sensul acelor de ceasornic +page_rotate_ccw.title=RoteΘ™te Γn sens invers al acelor de ceasornic +page_rotate_ccw.label=RoteΘ™te Γn sens invers al acelor de ceasornic +page_rotate_ccw_label=RoteΘ™te Γn sens invers al acelor de ceasornic + + +# Document properties dialog box +document_properties.title=ProprietΔƒΘ›ile documentului… +document_properties_label=ProprietΔƒΘ›ile documentului… +document_properties_file_name=Numele fiΘ™ierului: +document_properties_file_size=Dimensiunea fiΘ™ierului: +# 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}} byΘ›i) +# 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}} byΘ›i) +document_properties_title=Titlu: +document_properties_author=Autor: +document_properties_subject=Subiect: +document_properties_keywords=Cuvinte cheie: +document_properties_creation_date=Data creΔƒrii: +document_properties_modification_date=Data modificΔƒrii: +# 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=Autor: +document_properties_producer=ProducΔƒtor PDF: +document_properties_version=Versiune PDF: +document_properties_page_count=NumΔƒr de pagini: +document_properties_close=Închide + +print_progress_message=Se pregΔƒteΘ™te documentul pentru imprimare… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=RenunΘ›Δƒ + +# 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=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=AratΔƒ schiΘ›a documentului (dublu-clic pentru a expanda/colapsa toate elementele +document_outline_label=SchiΘ›Δƒ document +attachments.title=AfiΘ™eazΔƒ ataΘ™amentele +attachments_label=AtaΘ™amente +thumbs.title=AratΔƒ miniaturi +thumbs_label=Miniaturi +findbar.title=GΔƒseΘ™te Γn document + +# 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=Pagina {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Miniatura paginii {{page}} + +# Find panel button title and messages +find_previous.title=GΔƒseΘ™te instanΘ›a anterioarΔƒ Γn frazΔƒ +find_previous_label=Anterior +find_next.title=GΔƒseΘ™te instanΘ›a urmΔƒtoare Γn frazΔƒ +find_next_label=UrmΔƒtor +find_highlight=EvidenΘ›iazΔƒ apariΘ›iile +find_match_case_label=PotriveΘ™te literele mari Θ™i mici +find_reached_top=Am ajuns la Γnceputul documentului, continuΔƒ de la sfΓ’rΘ™it +find_reached_bottom=Am ajuns la sfΓ’rΘ™itul documentului, continuΔƒ de la Γnceput +find_not_found=Nu s-a gΔƒsit textul + +# Error panel labels +error_more_info=Mai multe informaΘ›ii +error_less_info=Mai puΘ›ine informaΘ›ii +error_close=Închide +# 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}} (varianta: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Mesaj: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=StivΔƒ: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=FiΘ™ier: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Linie: {{line}} +rendering_error=A intervenit o eroare la afiΘ™area paginii. + +# Predefined zoom values +page_scale_width=LΔƒΘ›ime paginΔƒ +page_scale_fit=Potrivire la paginΔƒ +page_scale_auto=Zoom automat +page_scale_actual=Dimensiune 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=Eroare +loading_error=A intervenit o eroare la ΓncΔƒrcarea fiΘ™ierului PDF. +invalid_file_error=FiΘ™ier PDF invalid sau deteriorat. +missing_file_error=FiΘ™ier PDF lipsΔƒ. +unexpected_response_error=RΔƒspuns neaΘ™teptat de la server. + +# 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}} Adnotare] +password_label=IntroduceΘ›i parola pentru a deschide acest fiΘ™ier PDF. +password_invalid=ParolΔƒ greΘ™itΔƒ. VΔƒ rugΔƒm sΔƒ ΓncercaΘ›i din nou. +password_ok=Ok +password_cancel=RenunΘ›Δƒ + +printing_not_supported=Avertisment: TipΔƒrirea nu este suportatΔƒ Γn totalitate de acest browser. +printing_not_ready=Avertisment: FiΘ™ierul PDF nu este ΓncΔƒrcat complet pentru tipΔƒrire. +web_fonts_disabled=Fonturile web sunt dezactivate: nu pot utiliza fonturile PDF Γncorporate. +document_colors_not_allowed=Documentele PDF nu sunt autorizate sΔƒ foloseascΔƒ propriile culori: 'Permite paginilor sΔƒ aleagΔƒ propriile culori' este dezactivatΔƒ Γn browser. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ru/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ru/viewer.properties new file mode 100755 index 00000000..47a322bd --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ru/viewer.properties @@ -0,0 +1,184 @@ +# 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=ΠŸΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ Π½Π° ΠΏΠ΅Ρ€Π²ΡƒΡŽ страницу +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_label=Π˜Π½ΡΡ‚Ρ€ΡƒΠΌΠ΅Π½Ρ‚ Β«Π’Ρ‹Π΄Π΅Π»Π΅Π½ΠΈΠ΅ тСкста» +cursor_hand_tool.title=Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Π˜Π½ΡΡ‚Ρ€ΡƒΠΌΠ΅Π½Ρ‚ Β«Π ΡƒΠΊΠ°Β» +cursor_hand_tool_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_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_notification.title=ΠŸΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ/ΡΠΊΡ€Ρ‹Ρ‚ΡŒ Π±ΠΎΠΊΠΎΠ²ΡƒΡŽ панСль (Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ ΠΈΠΌΠ΅Π΅Ρ‚ содСрТаниС/влоТСния) +toggle_sidebar_label=ΠŸΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ/ΡΠΊΡ€Ρ‹Ρ‚ΡŒ Π±ΠΎΠΊΠΎΠ²ΡƒΡŽ панСль +document_outline.title=ΠŸΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ содСрТаниС Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π° (Π΄Π²ΠΎΠΉΠ½ΠΎΠΉ Ρ‰Π΅Π»Ρ‡ΠΎΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Ρ€Π°Π·Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ/ΡΠ²Π΅Ρ€Π½ΡƒΡ‚ΡŒ всС элСмСнты) +document_outline_label=Π‘ΠΎΠ΄Π΅Ρ€ΠΆΠ°Π½ΠΈΠ΅ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π° +attachments.title=ΠŸΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ влоТСния +attachments_label=ВлоТСния +thumbs.title=ΠŸΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΌΠΈΠ½ΠΈΠ°Ρ‚ΡŽΡ€Ρ‹ +thumbs_label=ΠœΠΈΠ½ΠΈΠ°Ρ‚ΡŽΡ€Ρ‹ +findbar.title=Найти Π² Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π΅ +findbar_label=Найти + +# 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_reached_top=Достигнут Π²Π΅Ρ€Ρ… Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°, ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ΅Π½ΠΎ снизу +find_reached_bottom=Достигнут ΠΊΠΎΠ½Π΅Ρ† Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°, ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ΅Π½ΠΎ свСрху +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=Π‘Ρ‚eΠΊ: {{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_indicator=Ошибка +loading_error=ΠŸΡ€ΠΈ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ΅ PDF ΠΏΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка. +invalid_file_error=НСкоррСктный ΠΈΠ»ΠΈ ΠΏΠΎΠ²Ρ€Π΅ΠΆΠ΄Ρ‘Π½Π½Ρ‹ΠΉ PDF-Ρ„Π°ΠΉΠ». +missing_file_error=PDF-Ρ„Π°ΠΉΠ» отсутствуСт. +unexpected_response_error=НСоТиданный ΠΎΡ‚Π²Π΅Ρ‚ сСрвСра. + +# 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=OK +password_cancel=ΠžΡ‚ΠΌΠ΅Π½Π° + +printing_not_supported=ΠŸΡ€Π΅Π΄ΡƒΠΏΡ€Π΅ΠΆΠ΄Π΅Π½ΠΈΠ΅: Π’ этом Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅ Π½Π΅ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ поддСрТиваСтся ΠΏΠ΅Ρ‡Π°Ρ‚ΡŒ. +printing_not_ready=ΠŸΡ€Π΅Π΄ΡƒΠΏΡ€Π΅ΠΆΠ΄Π΅Π½ΠΈΠ΅: PDF Π½Π΅ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½ для ΠΏΠ΅Ρ‡Π°Ρ‚ΠΈ. +web_fonts_disabled=Π’Π΅Π±-ΡˆΡ€ΠΈΡ„Ρ‚Ρ‹ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½Ρ‹: Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ встроСнныС PDF-ΡˆΡ€ΠΈΡ„Ρ‚Ρ‹. +document_colors_not_allowed=PDF-Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°ΠΌ Π½Π΅ Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ свои Ρ†Π²Π΅Ρ‚Π°: Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Ρ‘Π½ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ Β«Π Π°Π·Ρ€Π΅ΡˆΠΈΡ‚ΡŒ Π²Π΅Π±-сайтам ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ свои Ρ†Π²Π΅Ρ‚Π°Β». diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/rw/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/rw/viewer.properties new file mode 100755 index 00000000..68a893d3 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/rw/viewer.properties @@ -0,0 +1,81 @@ +# 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) + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +zoom.title=Ihindurangano +open_file.title=Gufungura Dosiye +open_file_label=Gufungura + +# Secondary toolbar and context menu + + +# Document properties dialog box +# LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" +# will be replaced by the PDF file size in kilobytes, respectively in 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_title=Umutwe: +# LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" +# will be replaced by the creation/modification date, and time, of the PDF file. + +# 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) + +# Thumbnails panel item (tooltip and alt text for images) +# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page +# number. +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. + +# Find panel button title and messages +find_previous.title=Gushaka aho uyu murongo ugaruka mbere y'aha +find_next.title=Gushaka aho uyu murongo wongera kugaruka +find_not_found=Umurongo ntubonetse + +# Error panel labels +# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be +# replaced by the PDF.JS version and build ID. +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number + +# Predefined zoom values +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. + +# Loading indicator messages +loading_error_indicator=Ikosa + +# 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_invalid=Ijambo ry'ibanga ridahari. Wakongera ukagerageza +password_ok=YEGO + diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/sah/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/sah/viewer.properties new file mode 100755 index 00000000..1786c40d --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/sah/viewer.properties @@ -0,0 +1,166 @@ +# 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. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +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=Бастакы сирэйгэ көс +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=Π§Π°»Ρ‹ ΡƒΡ‚Π°Ρ€Ρ‹ эргит + + +# Document properties dialog box +document_properties.title=Π”ΠΎΠΊΡƒΠΌΡƒΠΎΠ½ Ρ‚ΡƒΡ€ΡƒΠΎΡ€ΡƒΡƒΠ»Π°Ρ€Π°... +document_properties_label=Π”ΠΎΠΊΡƒΠΌΡƒΠΎΠ½ Ρ‚ΡƒΡ€ΡƒΠΎΡ€ΡƒΡƒΠ»Π°Ρ€Π°...\u0020 +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_producer=PDF ΠΎ₯ΠΎΡ€ΠΎΠΎΡ‡Ρ‡Ρƒ: +document_properties_version=PDF Π±Π°Ρ€Ρ‹Π»Π°: +document_properties_page_count=Бирэй ахсаана: +document_properties_close=Π‘Π°ΠΏ + +# 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) +toggle_sidebar.title=Ойо•ос Ρ…Π°ΠΏΡ‚Π°Π»Ρ‹ Π°Ρ€Ρ‹ΠΉ/сап +toggle_sidebar_label=Ойо•ос Ρ…Π°ΠΏΡ‚Π°Π»Ρ‹ Π°Ρ€Ρ‹ΠΉ/сап +document_outline_label=Π”Σ©ΠΊ―ΠΌ―Σ©Π½ ΠΈ»ΠΈΠ½ΡΡ•итэ +attachments.title=ΠšΡ‹Π±Ρ‹Ρ‚Ρ‹ΠΊΡ‚Π°Ρ€Ρ‹ ΠΊΣ©Ρ€Π΄Σ©Ρ€ +attachments_label=ΠšΡ‹Π±Ρ‹Ρ‚Ρ‹ΠΊ +thumbs.title=ΠžΠΉΡƒΡƒΡ‡Π°Π°Π½Π½Π°Ρ€Ρ‹ ΠΊΣ©Ρ€Π΄Σ©Ρ€ +thumbs_label=ΠžΠΉΡƒΡƒΡ‡Π°Π°Π½Π½Π°Ρ€ +findbar.title=Π”Σ©ΠΊ―ΠΌ―өнтэн Π±ΡƒΠ» + +# 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_previous_label=Иннинээ•ΠΈ +find_next.title=Π­Ρ‚ΠΈΠΈ тиэкискэ Π±Ρƒ кэннинээ•ΠΈ ΠΊΠΈΠΈΡ€ΠΈΠΈΡ‚ΠΈΠ½ Π±ΡƒΠ» +find_next_label=Аныгыскы +find_highlight=Π‘Π°Ρ€Ρ‹Ρ‚Ρ‹Π½ сырдатан ΠΊΣ©Ρ€Π΄Σ©Ρ€ +find_match_case_label=Π‘ΡƒΡƒΠΊΡƒΠ±Π° ΡƒΠ»Π°Ρ…Π°Π½Ρ‹Π½-ΠΊΡ‹Ρ€Π°Ρ‚Ρ‹Π½ Π°Ρ€Π°Π°Ρ€ +find_reached_top=Бирэй ―Ρ€Π΄―гэр Ρ‚ΠΈΠΈΠΉΠ΄ΠΈ₯, салгыыта Π°Π»Π»Π°Ρ€Π° +find_reached_bottom=Бирэй Π±―ттэ, ―Σ©»Ρ сал•Π°Π½Π½Π° +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=Π‘Ρ‚eΠΊ: {{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_indicator=Ал•ас +loading_error=PDF-билэни Ρ…Π°Ρ‡Π°ΠΉΠ΄Ρ‹Ρ‹Ρ€Π³Π° Π°Π»•ас Ρ‚Π°•ыста. +invalid_file_error=Π’ΡƒΠΎΡ… эрэ Π°Π»•астаах эбэтэр Π°Π»Π΄ΡŒΠ°ΠΌΠΌΡ‹Ρ‚ PDF-билэ. +missing_file_error=PDF-билэ суох. +unexpected_response_error=Биэрбэр Ρ…ΠΎΡ€ΡƒΠΉΠ΄Π°Π°Π±Π°Ρ‚. + +# 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 бичиктэрэ ΠΊΡ‹Π°ΠΉΠ°Π½ көст―бэттэр. +document_colors_not_allowed=PDF-Π΄Σ©ΠΊ―ΠΌ―Σ©―ннэргэ бэйэлэрин Σ©₯Π½Σ©Ρ€―Π½ Ρ‚ΡƒΡ‚Ρ‚Π°Ρ€ ΠΊΣ©₯―ллэммэтэ: "Π‘ΠΈΡ‚ΠΈΠΌ-сирдэр бэйэлэрин Σ©₯Π½Σ©Ρ€―Π½ Ρ‚ΡƒΡ‚Ρ‚Π°Π»Π»Π°Ρ€Ρ‹Π½ ΠΊΣ©₯―Π»Π»――ргэ" диэн Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π³Π° арахса ΡΡ‹Π»Π΄ΡŒΠ°Ρ€ эбит. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/si/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/si/viewer.properties new file mode 100755 index 00000000..4137ec1c --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/si/viewer.properties @@ -0,0 +1,171 @@ +# 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. +# 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. + +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=ΰΆΈΰ·”ΰΆ½ΰ·Š ΰΆ΄ΰ·’ΰΆ§ΰ·”ΰ·€ΰΆ§ ࢺࢱ්ࢱ +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=ΰ·€ΰ·ΰΆΈΰ·ΰ·€ΰΆ»ΰ·ŠΰΆ­ΰ·€ ΰΆ·ΰ·Šβ€ΰΆ»ΰΆΈΰΆ«ΰΆΊ + + +# 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}} 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_close=ΰ·€ΰ·ƒΰΆ±ΰ·ŠΰΆ± + +print_progress_message=ΰΆ½ΰ·šΰΆ›ΰΆ±ΰΆΊ ΰΆΈΰ·”ΰΆ―ΰ·Šβ€ΰΆ»ΰΆ«ΰΆΊ සࢳහා ΰ·ƒΰ·–ΰΆ―ΰ·ΰΆ±ΰΆΈΰ·Š ΰΆšΰΆ»ΰΆΈΰ·’ΰΆ±ΰ·Šβ€¦ +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +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=ࢴැࢭි ΰΆ­ΰ·“ΰΆ»ΰ·”ΰ·€ΰΆ§ ΰΆΈΰ·ΰΆ»ΰ·”ΰ·€ΰΆ±ΰ·ŠΰΆ± +attachments.title=ΰΆ‡ΰΆΈΰ·’ΰΆ«ΰ·”ΰΆΈΰ·Š ΰΆ΄ΰ·™ΰΆ±ΰ·Šΰ·€ΰΆ±ΰ·ŠΰΆ± +attachments_label=ΰΆ‡ΰΆΈΰ·’ΰΆ«ΰ·”ΰΆΈΰ·Š +thumbs.title=ΰ·ƒΰ·’ΰΆŸΰ·’ΰΆ­ΰ·’ ΰΆ»ΰ·– ΰΆ΄ΰ·™ΰΆ±ΰ·Šΰ·€ΰΆ±ΰ·ŠΰΆ± +thumbs_label=ΰ·ƒΰ·’ΰΆŸΰ·’ΰΆ­ΰ·’ ΰΆ»ΰ·– +findbar.title=ΰΆ½ΰ·šΰΆ›ΰΆ±ΰΆΊ ΰΆ­ΰ·”ΰ·… ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ± +findbar_label=ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ± + +# 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_previous_label=ΰΆ΄ΰ·™ΰΆ»: +find_next.title=ࢸේ ΰ·€ΰ·ΰΆšΰ·Šβ€ΰΆΊ ΰΆ›ΰΆ«ΰ·ŠΰΆ©ΰΆΊ ΰΆΈΰ·“ΰ·…ΰΆŸΰΆ§ ΰΆΊΰ·™ΰΆ―ΰ·™ΰΆ± ΰ·ƒΰ·ŠΰΆΰ·ΰΆ±ΰΆΊ ΰ·ƒΰ·œΰΆΊΰΆ±ΰ·ŠΰΆ± +find_next_label=ΰΆΈΰ·“ΰ·…ΰΆŸ +find_highlight=ΰ·ƒΰ·’ΰΆΊΰΆ½ΰ·ŠΰΆ½ ΰΆ‹ΰΆ―ΰ·ŠΰΆ―ΰ·“ΰΆ΄ΰΆ±ΰΆΊ +find_match_case_label=ΰΆ…ΰΆšΰ·”ΰΆ»ΰ·” ΰΆœΰ·…ΰΆ΄ΰΆ±ΰ·ŠΰΆ± +find_reached_top=ΰΆ΄ΰ·’ΰΆ§ΰ·”ΰ·€ΰ·š ΰΆ‰ΰ·„ΰ·… ΰΆšΰ·™ΰ·…ΰ·€ΰΆ»ΰΆ§ ΰΆ½ΰΆœΰ·ΰ·€ΰ·’ΰΆΊ, ΰΆ΄ΰ·„ΰ·… ΰ·ƒΰ·’ΰΆ§ ΰΆ‰ΰΆ―ΰ·’ΰΆ»ΰ·’ΰΆΊΰΆ§ ΰΆΊΰΆΈΰ·’ΰΆ±ΰ·Š +find_reached_bottom=ΰΆ΄ΰ·’ΰΆ§ΰ·”ΰ·€ΰ·š ΰΆ΄ΰ·„ΰ·… ΰΆšΰ·™ΰ·…ΰ·€ΰΆ»ΰΆ§ ΰΆ½ΰΆœΰ·ΰ·€ΰ·’ΰΆΊ, ΰΆ‰ΰ·„ΰ·… ΰ·ƒΰ·’ΰΆ§ ΰΆ‰ΰΆ―ΰ·’ΰΆ»ΰ·’ΰΆΊΰΆ§ ΰΆΊΰΆΈΰ·’ΰΆ±ΰ·Š +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: {{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_indicator=ࢯෝෂࢺ +loading_error=PDF ΰΆ΄ΰ·–ΰΆ»ΰΆ«ΰΆΊ ΰ·€ΰ·’ΰΆΈΰ·šΰΆ―ΰ·’ ΰΆ―ΰ·ΰ·‚ΰΆΊΰΆšΰ·Š ΰ·„ΰΆ§ ΰΆœΰ·ΰΆ±ΰ·”ΰΆ«ΰ·’. +invalid_file_error=ࢯූශිࢭ හෝ ΰ·ƒΰ·ΰ·€ΰΆ―ΰ·Šβ€ΰΆΊ PDF ΰΆœΰ·œΰΆ±ΰ·”ΰ·€. +missing_file_error=ࢱැࢭිවූ PDF ΰΆœΰ·œΰΆ±ΰ·”ΰ·€. +unexpected_response_error=ΰΆΆΰΆ½ΰ·ΰΆ΄ΰ·œΰΆ»ΰ·œΰΆ­ΰ·ŠΰΆ­ΰ·” ΰΆ±ΰ·œΰ·€ΰ·– ΰ·ƒΰ·šΰ·€ΰ·ΰΆ―ΰ·ΰΆΊΰΆš ΰΆ΄ΰ·Šβ€ΰΆ»ΰΆ­ΰ·’ΰΆ ΰ·ΰΆ»ΰΆΊ. + +# 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/twake/frontend/public/public/viewer/PDFViewer/locale/sk/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/sk/viewer.properties new file mode 100755 index 00000000..57a621dd --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/sk/viewer.properties @@ -0,0 +1,184 @@ +# 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=PredchΓ‘dzajΓΊca strana +previous_label=PredchΓ‘dzajΓΊca +next.title=NasledujΓΊca strana +next_label=NasledujΓΊca + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Strana +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=z {{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}} z {{pagesCount}}) + +zoom_out.title=VzdialiΕ₯ +zoom_out_label=VzdialiΕ₯ +zoom_in.title=PriblΓ­ΕΎiΕ₯ +zoom_in_label=PriblΓ­ΕΎiΕ₯ +zoom.title=Lupa +presentation_mode.title=PrepnΓΊΕ₯ na reΕΎim PrezentΓ‘cia +presentation_mode_label=ReΕΎim PrezentΓ‘cia +open_file.title=OtvoriΕ₯ sΓΊbor +open_file_label=OtvoriΕ₯ +print.title=TlačiΕ₯ +print_label=TlačiΕ₯ +download.title=PrevziaΕ₯ +download_label=PrevziaΕ₯ +bookmark.title=AktuΓ‘lne zobrazenie (kopΓ­rovaΕ₯ alebo otvoriΕ₯ v novom okne) +bookmark_label=AktuΓ‘lne zobrazenie + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=VΓ½ber textu +cursor_hand_tool.title=PovoliΕ₯ nΓ‘stroj ruka +cursor_hand_tool_label=NΓ‘stroj ruka + +# Document properties dialog box +document_properties.title=Vlastnosti dokumentu… +document_properties_label=Vlastnosti dokumentu… +document_properties_file_name=NΓ‘zov sΓΊboru: +document_properties_file_size=VeΔΎkosΕ₯ sΓΊboru: +# 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}} bajtov) +# 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}} bajtov) +document_properties_title=NΓ‘zov: +document_properties_author=Autor: +document_properties_subject=Predmet: +document_properties_keywords=KľúčovΓ© slovΓ‘: +document_properties_creation_date=DΓ‘tum vytvorenia: +document_properties_modification_date=DΓ‘tum ΓΊpravy: +# 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=Vytvoril: +document_properties_producer=Tvorca PDF: +document_properties_version=Verzia PDF: +document_properties_page_count=Počet strΓ‘n: +document_properties_close=ZavrieΕ₯ + +print_progress_message=PrΓ­prava dokumentu na tlač… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=ZruΕ‘iΕ₯ + +# 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=PrepnΓΊΕ₯ bočnΓ½ panel +toggle_sidebar_notification.title=PrepnΓΊΕ₯ bočnΓ½ panel (dokument obsahuje osnovu/prΓ­lohy) +toggle_sidebar_label=PrepnΓΊΕ₯ bočnΓ½ panel +document_outline.title=ZobraziΕ₯ prehΔΎad dokumentu (dvojitΓ½m kliknutΓ­m rozbalΓ­te/zbalΓ­te vΕ‘etky poloΕΎky) +document_outline_label=PrehΔΎad dokumentu +attachments.title=ZobraziΕ₯ prΓ­lohy +attachments_label=PrΓ­lohy +thumbs.title=ZobraziΕ₯ miniatΓΊry +thumbs_label=MiniatΓΊry +findbar.title=HΔΎadaΕ₯ v dokumente +findbar_label=HΔΎadaΕ₯ + +# 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=Strana {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=MiniatΓΊra strany {{page}} + +# Find panel button title and messages +find_input.title=HΔΎadaΕ₯ +find_input.placeholder=HΔΎadaΕ₯ v dokumente… +find_previous.title=VyhΔΎadaΕ₯ predchΓ‘dzajΓΊci vΓ½skyt reΕ₯azca +find_previous_label=PredchΓ‘dzajΓΊce +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Ε₯ malΓ©/veΔΎkΓ© pΓ­smenΓ‘ +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 +find_not_found=VΓ½raz nebol nΓ‘jdenΓ½ + +# Error panel labels +error_more_info=Viac informΓ‘ciΓ­ +error_less_info=Menej informΓ‘ciΓ­ +error_close=ZavrieΕ₯ +# 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}} (zostavenie: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=SprΓ‘va: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=ZΓ‘sobnΓ­k: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=SΓΊbor: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Riadok: {{line}} +rendering_error=Pri vykresΔΎovanΓ­ strΓ‘nky sa vyskytla chyba. + +# Predefined zoom values +page_scale_width=Na Ε‘Γ­rku strany +page_scale_fit=Na veΔΎkosΕ₯ strany +page_scale_auto=AutomatickΓ‘ veΔΎkosΕ₯ +page_scale_actual=SkutočnΓ‘ veΔΎkosΕ₯ +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Chyba +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. +unexpected_response_error=NeočakΓ‘vanΓ‘ odpoveď zo servera. + +# 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=[AnotΓ‘cia typu {{type}}] +password_label=Ak chcete otvoriΕ₯ tento sΓΊbor PDF, zadajte jeho heslo. +password_invalid=Heslo nie je platnΓ©. SkΓΊste to znova. +password_ok=OK +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. +document_colors_not_allowed=Dokumenty PDF nemajΓΊ povolenΓ© pouΕΎΓ­vaΕ₯ vlastnΓ© farby, pretoΕΎe voΔΎba "PovoliΕ₯ strΓ‘nkam pouΕΎΓ­vaΕ₯ vlastnΓ© farby" je v nastaveniach prehliadača vypnutΓ‘. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/sl/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/sl/viewer.properties new file mode 100755 index 00000000..0000a9b7 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/sl/viewer.properties @@ -0,0 +1,184 @@ +# 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=PrejΕ‘nja stran +previous_label=Nazaj +next.title=Naslednja stran +next_label=Naprej + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Stran +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=od {{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}} od {{pagesCount}}) + +zoom_out.title=PomanjΕ‘aj +zoom_out_label=PomanjΕ‘aj +zoom_in.title=Povečaj +zoom_in_label=Povečaj +zoom.title=Povečava +presentation_mode.title=Preklopi v način predstavitve +presentation_mode_label=Način predstavitve +open_file.title=Odpri datoteko +open_file_label=Odpri +print.title=Natisni +print_label=Natisni +download.title=Prenesi +download_label=Prenesi +bookmark.title=Trenutni pogled (kopiraj ali odpri v novem oknu) +bookmark_label=Trenutni pogled + +# Secondary toolbar and context menu +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 urninega kazalca +page_rotate_cw.label=Zavrti v smeri urninega kazalca +page_rotate_cw_label=Zavrti v smeri urninega kazalca +page_rotate_ccw.title=Zavrti v nasprotni smeri urninega kazalca +page_rotate_ccw.label=Zavrti v nasprotni smeri urninega kazalca +page_rotate_ccw_label=Zavrti v nasprotni smeri urninega kazalca + +cursor_text_select_tool.title=Omogoči orodje za izbor besedila +cursor_text_select_tool_label=Orodje za izbor besedila +cursor_hand_tool.title=Omogoči roko +cursor_hand_tool_label=Roka + +# Document properties dialog box +document_properties.title=Lastnosti dokumenta … +document_properties_label=Lastnosti dokumenta … +document_properties_file_name=Ime datoteke: +document_properties_file_size=Velikost datoteke: +# 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}} bajtov) +# 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}} bajtov) +document_properties_title=Ime: +document_properties_author=Avtor: +document_properties_subject=Tema: +document_properties_keywords=Ključne besede: +document_properties_creation_date=Datum nastanka: +document_properties_modification_date=Datum spremembe: +# 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=Ustvaril: +document_properties_producer=Izdelovalec PDF: +document_properties_version=Različica PDF: +document_properties_page_count=Ε tevilo strani: +document_properties_close=Zapri + +print_progress_message=Priprava dokumenta na tiskanje … +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}} % +print_progress_close=Prekliči + +# 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=Preklopi stransko vrstico +toggle_sidebar_notification.title=Preklopi stransko vrstico (dokument vsebuje oris/priponke) +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 +thumbs.title=PrikaΕΎi sličice +thumbs_label=Sličice +findbar.title=Iskanje po dokumentu +findbar_label=Najdi + +# 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=Stran {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Sličica strani {{page}} + +# Find panel button title and messages +find_input.title=Najdi +find_input.placeholder=Najdi v dokumentu … +find_previous.title=Najdi prejΕ‘njo ponovitev iskanega +find_previous_label=Najdi nazaj +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_reached_top=DoseΕΎen začetek dokumenta iz smeri konca +find_reached_bottom=DoseΕΎeno konec dokumenta iz smeri začetka +find_not_found=Iskanega ni mogoče najti + +# Error panel labels +error_more_info=Več informacij +error_less_info=Manj informacij +error_close=Zapri +# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be +# replaced by the PDF.JS version and build ID. +error_version_info=PDF.js r{{version}} (graditev: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Sporočilo: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Sklad: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Datoteka: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Vrstica: {{line}} +rendering_error=Med pripravljanjem strani je priΕ‘lo do napake! + +# Predefined zoom values +page_scale_width=Ε irina strani +page_scale_fit=Prilagodi stran +page_scale_auto=Samodejno +page_scale_actual=Dejanska velikost +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}} % + +# Loading indicator messages +loading_error_indicator=Napaka +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. +unexpected_response_error=Nepričakovan odgovor streΕΎnika. + +# 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=[Opomba vrste {{type}}] +password_label=Vnesite geslo za odpiranje te datoteke PDF. +password_invalid=Neveljavno geslo. Poskusite znova. +password_ok=V redu +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. +document_colors_not_allowed=Dokumenti PDF ne smejo uporabljati svojih lastnih barv: moΕΎnost 'Dovoli stranem uporabo lastnih barv' je v brskalniku onemogočena. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/son/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/son/viewer.properties new file mode 100755 index 00000000..f5c1b46f --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/son/viewer.properties @@ -0,0 +1,180 @@ +# 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=Moo bisante +previous_label=Bisante +next.title=Jinehere moo +next_label=Jine + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Moo +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages={{pagesCount}} ra +# 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}} ka hun {{pagesCount}}) ra + +zoom_out.title=Nakasandi +zoom_out_label=Nakasandi +zoom_in.title=Bebbeerandi +zoom_in_label=Bebbeerandi +zoom.title=Bebbeerandi +presentation_mode.title=Bere cebeyan alhaali +presentation_mode_label=Cebeyan alhaali +open_file.title=Tuku feeri +open_file_label=Feeri +print.title=Kar +print_label=Kar +download.title=Zumandi +download_label=Zumandi +bookmark.title=SohΓ΅ gunarro (bere wala feeri zanfun taaga ra) +bookmark_label=SohΓ΅ gunaroo + +# Secondary toolbar and context menu +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 + + +# Document properties dialog box +document_properties.title=Takadda mayrawey… +document_properties_label=Takadda mayrawey… +document_properties_file_name=Tuku maa: +document_properties_file_size=Tuku adadu: +# 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=KB {{size_kb}} (cebsu-ize {{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=MB {{size_mb}} (cebsu-ize {{size_b}}) +document_properties_title=Tiiramaa: +document_properties_author=Hantumkaw: +document_properties_subject=Dalil: +document_properties_keywords=Kufalkalimawey: +document_properties_creation_date=Teeyan han: +document_properties_modification_date=Barmayan han: +# 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=Teekaw: +document_properties_producer=PDF berandikaw: +document_properties_version=PDF dumi: +document_properties_page_count=Moo hinna: +document_properties_close=Daabu + +print_progress_message=Goo ma takaddaa soolu k'a kar se… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=NaΕ‹ + +# 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=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Ε‹ +attachments.title=Hangarey cebe +attachments_label=Hangarey +thumbs.title=Kabeboy biyey cebe +thumbs_label=Kabeboy biyey +findbar.title=Ceeci takaddaa ra +findbar_label=Ceeci + +# 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}} moo +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Kabeboy bii {{page}} moo Ε‘e + +# Find panel button title and messages +find_input.title=Ceeci +find_input.placeholder=Ceeci takaddaa ra… +find_previous.title=KalimaΙ²aΕ‹oo bangayri bisantaa ceeci +find_previous_label=Bisante +find_next.title=KalimaΙ²aΕ‹oo hiino bangayroo ceeci +find_next_label=Jine +find_highlight=Ikul Ε‘ilbay +find_match_case_label=Harfu-beeriyan hawgay +find_reached_top=A too moΕ‹oo boΕ‹oo, koy jine ka Ε‘initin nda cewoo +find_reached_bottom=A too moΙ²oo cewoo, koy jine Ε‘intioo ga +find_not_found=KalimaΙ²aa mana duwandi + +# Error panel labels +error_more_info=Alhabar tontoni +error_less_info=Alhabar tontoni +error_close=Daabu +# 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=Alhabar: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Dekeri: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Tuku: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Ε½eeri: {{line}} +rendering_error=Firka bangay kaΕ‹ moΙ²oo goo ma willandi. + +# Predefined zoom values +page_scale_width=Mooo hayyan +page_scale_fit=Moo sawayan +page_scale_auto=BoΕ‹Ε‘e azzaati barmayyan +page_scale_actual=Adadu cimi +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# 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. +unexpected_response_error=Manti ferΕ‘ikaw tuuruyan maatante. + +# 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}} maasa-caw] +password_label=Ε ennikufal dam ka PDF tukoo woo feeri. +password_invalid=Ε ennikufal laalo. Ceeci koyne taare. +password_ok=Ayyo +password_cancel=NaΕ‹ + +printing_not_supported=Yaamar: Karyan Ε‘i tee ka timme nda ceecikaa woo. +printing_not_ready=Yaamar: PDF Ε‘i zunbu ka timme karyan Ε‘e. +web_fonts_disabled=Interneti Ε‘igirawey kay: Ε‘i hin ka goy nda PDF Ε‘igira hurantey. +document_colors_not_allowed=PDF takaddawey Ε‘i duu fondo ka ngey boΕ‹ noonawey zaa: β€œNaΕ‹ moΙ²ey ma ngey boΕ‹ noonawey suuba” Ε‘i dira ceecikaa ga. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/sq/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/sq/viewer.properties new file mode 100755 index 00000000..8f5dcbfa --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/sq/viewer.properties @@ -0,0 +1,180 @@ +# 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=Faqja e MΓ«parshme +previous_label=E mΓ«parshmja +next.title=Faqja Pasuese +next_label=Pasuesja + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Faqe +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=nga {{pagesCount}} gjithsej +# 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}} nga {{pagesCount}}) + +zoom_out.title=Zmadhim +zoom_out_label=Zmadhoji +zoom_in.title=ZvogΓ«lim +zoom_in_label=ZvogΓ«loji +zoom.title=Zoom +presentation_mode.title=Kalo te MΓ«nyra Paraqitje +presentation_mode_label=MΓ«nyra Paraqitje +open_file.title=Hapni KartelΓ« +open_file_label=Hape +print.title=Shtypje +print_label=Shtype +download.title=Shkarkim +download_label=Shkarkoje +bookmark.title=Pamja e tanishme (kopjojeni ose hapeni nΓ« dritare tΓ« re) +bookmark_label=Pamja e Tanishme + +# Secondary toolbar and context menu +tools.title=Mjete +tools_label=Mjete +first_page.title=Kaloni te Faqja e ParΓ« +first_page.label=Kalo te Faqja e ParΓ« +first_page_label=Kalo te Faqja e ParΓ« +last_page.title=Kaloni te Faqja e Fundit +last_page.label=Kalo te Faqja e Fundit +last_page_label=Kalo 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 + + +# Document properties dialog box +document_properties.title=Veti Dokumenti… +document_properties_label=Veti Dokumenti… +document_properties_file_name=EmΓ«r kartele: +document_properties_file_size=MadhΓ«si kartele: +# 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}} bajte) +# 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}} bajte) +document_properties_title=Titull: +document_properties_author=Autor: +document_properties_subject=Subjekt: +document_properties_keywords=FjalΓ«kyΓ§e: +document_properties_creation_date=DatΓ« Krijimi: +document_properties_modification_date=DatΓ« Ndryshimi: +# 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=Krijues: +document_properties_producer=Prodhues PDF-je: +document_properties_version=Version PDF-je: +document_properties_page_count=NumΓ«r Faqesh: +document_properties_close=Mbylle + +print_progress_message=Po pΓ«rgatitet dokumenti pΓ«r shtypje… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Anuloje + +# 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=Shfaqni/Fshihni AnΓ«shtyllΓ«n +toggle_sidebar_notification.title=Shfaqni AnΓ«shtyllΓ«n (dokumenti pΓ«rmban pΓ«rvijim/bashkΓ«ngjitje) +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 +thumbs.title=Shfaqni Miniatura +thumbs_label=Miniatura +findbar.title=Gjeni nΓ« Dokument +findbar_label=Gjej + +# 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=Faqja {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=MiniaturΓ« e Faqes {{page}} + +# Find panel button title and messages +find_input.title=Gjeje +find_input.placeholder=Gjeni nΓ« dokument… +find_previous.title=Gjeni hasjen e mΓ«parshme tΓ« togfjalΓ«shit +find_previous_label=E mΓ«parshmja +find_next.title=Gjeni hasjen pasuese tΓ« togfjalΓ«shit +find_next_label=Pasuesja +find_highlight=Theksoji tΓ« tΓ«ra +find_match_case_label=SiΓ§ Γ«shtΓ« shkruar +find_reached_top=U mbΓ«rrit nΓ« krye tΓ« dokumentit, vazhduar prej fundit +find_reached_bottom=U mbΓ«rrit nΓ« fund tΓ« dokumentit, vazhduar prej kreut +find_not_found=TogfjalΓ«sh qΓ« s’gjendet + +# Error panel labels +error_more_info=MΓ« TepΓ«r tΓ« DhΓ«na +error_less_info=MΓ« Pak tΓ« DhΓ«na +error_close=Mbylle +# 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=Mesazh: {{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=KartelΓ«: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Rresht: {{line}} +rendering_error=Ndodhi njΓ« gabim gjatΓ« riprodhimit tΓ« faqes. + +# Predefined zoom values +page_scale_width=GjerΓ«si Faqeje +page_scale_fit=Sa NxΓ« Faqja +page_scale_auto=Zoom i VetvetishΓ«m +page_scale_actual=MadhΓ«sia Faktike +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Gabim +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. +unexpected_response_error=PΓ«rgjigje shΓ«rbyesi e papritur. + +# 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=[NΓ«nvizim {{type}}] +password_label=Jepni fjalΓ«kalimin qΓ« tΓ« hapet kjo kartelΓ« PDF. +password_invalid=FjalΓ«kalim i pavlefshΓ«m. Ju lutemi, riprovoni. +password_ok=OK +password_cancel=Anuloje + +printing_not_supported=Kujdes: Shtypja s’mbulohet plotΓ«sisht nga ky shfletues. +printing_not_ready=Kujdes: PDF-ja s’ështΓ« ngarkuar plotΓ«sisht qΓ« ta shtypni. +web_fonts_disabled=Shkronjat Web janΓ« tΓ« Γ§aktivizuara: s’arrihet tΓ« pΓ«rdoren shkronja tΓ« trupΓ«zuara nΓ« PDF. +document_colors_not_allowed=Dokumenteve PDF s’u lejohet tΓ« pΓ«rdorin ngjyrat e tyre: 'Lejoji faqet t’i zgjedhin vetΓ« ngjyrat' Γ«shtΓ« e Γ§aktivizuar te shfletuesi. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/sr/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/sr/viewer.properties new file mode 100755 index 00000000..754d9c49 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/sr/viewer.properties @@ -0,0 +1,184 @@ +# 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=Иди Π½Π° ΠΏΡ€Π²Ρƒ страницу +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_label=Алат Π·Π° ΡΠ΅Π»Π΅ΠΊΡ‚ΠΎΠ²Π°ΡšΠ΅ тСкста +cursor_hand_tool.title=ΠžΠΌΠΎΠ³ΡƒΡ›ΠΈ Π°Π»Π°Ρ‚ Π·Π° ΠΏΠΎΠΌΠ΅Ρ€Π°ΡšΠ΅ +cursor_hand_tool_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}} KB ({{size_b}} 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}} 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_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_notification.title=ΠŸΡ€ΠΈΠΊΠ°ΠΆΠΈ Π΄ΠΎΠ΄Π°Ρ‚Π½Ρƒ Ρ‚Ρ€Π°ΠΊΡƒ (Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Π°Ρ‚ садрТи ΠΎΠΊΠ²ΠΈΡ€Π΅/ΠΏΡ€ΠΈΠ»ΠΎΠ³Π΅) +toggle_sidebar_label=ΠŸΡ€ΠΈΠΊΠ°ΠΆΠΈ Π΄ΠΎΠ΄Π°Ρ‚Π½Ρƒ ΠΏΠ°Π»Π΅Ρ‚Ρƒ +document_outline.title=ΠŸΡ€ΠΈΠΊΠ°ΠΆΠΈ ΠΊΠΎΠ½Ρ‚ΡƒΡ€Ρƒ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π° (Π΄ΡƒΠΏΠ»ΠΈ ΠΊΠ»ΠΈΠΊ Π·Π° ΠΏΡ€ΠΎΡˆΠΈΡ€Π΅ΡšΠ΅/ΡΠΊΡƒΠΏΡ™Π°ΡšΠ΅ Π΅Π»Π΅ΠΌΠ΅Π½Π°Ρ‚Π°) +document_outline_label=ΠšΠΎΠ½Ρ‚ΡƒΡ€Π° Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π° +attachments.title=ΠŸΡ€ΠΈΠΊΠ°ΠΆΠΈ ΠΏΡ€ΠΈΠ»ΠΎΠ³Π΅ +attachments_label=ΠŸΡ€ΠΈΠ»ΠΎΠ·ΠΈ +thumbs.title=ΠŸΡ€ΠΈΠΊΠ°ΠΆΠΈ сличицС +thumbs_label=Π‘Π»ΠΈΡ‡ΠΈΡ†Π΅ +findbar.title=ΠŸΡ€ΠΎΠ½Π°Ρ’ΠΈ Ρƒ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Ρƒ +findbar_label=ΠŸΡ€ΠΎΠ½Π°Ρ’ΠΈ + +# 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_reached_top=Достигнут Π²Ρ€Ρ… Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°, наставио са Π΄Π½Π° +find_reached_bottom=Достигнуто Π΄Π½ΠΎ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°, наставио са Π²Ρ€Ρ…Π° +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_indicator=Π“Ρ€Π΅ΡˆΠΊΠ° +loading_error=Π”ΠΎΡˆΠ»ΠΎ јС Π΄ΠΎ Π³Ρ€Π΅ΡˆΠΊΠ΅ ΠΏΡ€ΠΈΠ»ΠΈΠΊΠΎΠΌ ΡƒΡ‡ΠΈΡ‚Π°Π²Π°ΡšΠ° PDF-Π°. +invalid_file_error=PDF Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ° јС ΠΎΡˆΡ‚Π΅Ρ›Π΅Π½Π° ΠΈΠ»ΠΈ јС нСисправна. +missing_file_error=PDF Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ° нијС ΠΏΡ€ΠΎΠ½Π°Ρ’Π΅Π½Π°. +unexpected_response_error=НСочСкиван ΠΎΠ΄Π³ΠΎΠ²ΠΎΡ€ ΠΎΠ΄ сСрвСра. + +# 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 Ρ„ΠΎΠ½Ρ‚ΠΎΠ²Π΅. +document_colors_not_allowed=PDF Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΈ Π½Π΅ ΠΌΠΎΠ³Ρƒ Π΄Π° користС сопствСнС бојС: β€œΠ”ΠΎΠ·Π²ΠΎΠ»ΠΈ страницама Π΄Π° ΠΈΠ·Π°Π±Π΅Ρ€Ρƒ својС Π±ΠΎΡ˜Π΅β€ јС Π΄Π΅Π°ΠΊΡ‚ΠΈΠ²ΠΈΡ€Π°Π½ΠΎ Ρƒ ΠΏΡ€Π΅Π³Π»Π΅Π΄Π°Ρ‡Ρƒ. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/sv-SE/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/sv-SE/viewer.properties new file mode 100755 index 00000000..412b7652 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/sv-SE/viewer.properties @@ -0,0 +1,184 @@ +# 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=FΓΆregΓ₯ende sida +previous_label=FΓΆregΓ₯ende +next.title=NΓ€sta sida +next_label=NΓ€sta + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Sida +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=av {{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}} av {{pagesCount}}) + +zoom_out.title=Zooma ut +zoom_out_label=Zooma ut +zoom_in.title=Zooma in +zoom_in_label=Zooma in +zoom.title=Zoom +presentation_mode.title=Byt till presentationslΓ€ge +presentation_mode_label=PresentationslΓ€ge +open_file.title=Γ–ppna fil +open_file_label=Γ–ppna +print.title=Skriv ut +print_label=Skriv ut +download.title=HΓ€mta +download_label=HΓ€mta +bookmark.title=Aktuell vy (kopiera eller ΓΆppna i nytt fΓΆnster) +bookmark_label=Aktuell vy + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=Textmarkeringsverktyg +cursor_hand_tool.title=Aktivera handverktyg +cursor_hand_tool_label=Handverktyg + +# Document properties dialog box +document_properties.title=Dokumentegenskaper… +document_properties_label=Dokumentegenskaper… +document_properties_file_name=Filnamn: +document_properties_file_size=Filstorlek: +# 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}} byte) +# 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}} byte) +document_properties_title=Titel: +document_properties_author=FΓΆrfattare: +document_properties_subject=Γ„mne: +document_properties_keywords=Nyckelord: +document_properties_creation_date=Skapades: +document_properties_modification_date=Γ„ndrades: +# 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=Skapare: +document_properties_producer=PDF-producent: +document_properties_version=PDF-version: +document_properties_page_count=Sidantal: +document_properties_close=StΓ€ng + +print_progress_message=FΓΆrbereder sidor fΓΆr utskrift… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Avbryt + +# 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=Visa/dΓΆlj sidofΓ€lt +toggle_sidebar_notification.title=Visa/dΓΆlj sidofΓ€lt (dokument innehΓ₯ller ΓΆversikt/bilagor) +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 +thumbs.title=Visa miniatyrer +thumbs_label=Miniatyrer +findbar.title=SΓΆk i dokument +findbar_label=SΓΆk + +# 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=Sida {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Miniatyr av sida {{page}} + +# Find panel button title and messages +find_input.title=SΓΆk +find_input.placeholder=SΓΆk i dokument… +find_previous.title=Hitta fΓΆregΓ₯ende fΓΆrekomst av frasen +find_previous_label=FΓΆregΓ₯ende +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_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 +find_not_found=Frasen hittades inte + +# Error panel labels +error_more_info=Mer information +error_less_info=Mindre information +error_close=StΓ€ng +# 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=Meddelande: {{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=Fil: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Rad: {{line}} +rendering_error=Ett fel uppstod vid visning av sidan. + +# Predefined zoom values +page_scale_width=Sidbredd +page_scale_fit=Anpassa sida +page_scale_auto=Automatisk zoom +page_scale_actual=Verklig storlek +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Fel +loading_error=Ett fel uppstod vid laddning av PDF-filen. +invalid_file_error=Ogiltig eller korrupt PDF-fil. +missing_file_error=Saknad PDF-fil. +unexpected_response_error=OvΓ€ntat svar frΓ₯n servern. + +# 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}}-annotering] +password_label=Skriv in lΓΆsenordet fΓΆr att ΓΆppna PDF-filen. +password_invalid=Ogiltigt lΓΆsenord. FΓΆrsΓΆk igen. +password_ok=OK +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. +document_colors_not_allowed=PDF-dokument tillΓ₯ts inte anvΓ€nda egna fΓ€rger: β€œLΓ₯t sidor anvΓ€nda egna fΓ€rger” Γ€r inaktiverat i webblΓ€saren. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/sw/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/sw/viewer.properties new file mode 100755 index 00000000..9ec4e216 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/sw/viewer.properties @@ -0,0 +1,128 @@ +# 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=Ukurasa Uliotangulia +previous_label=Iliyotangulia +next.title=Ukurasa Ufuatao +next_label=Ifuatayo + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +zoom_out.title=Kuza Nje +zoom_out_label=Kuza Nje +zoom_in.title=Kuza Ndani +zoom_in_label=Kuza Ndani +zoom.title=Kuza +presentation_mode.title=Badili kwa Hali ya Uwasilishaji +presentation_mode_label=Hali ya Uwasilishaji +open_file.title=Fungua Faili +open_file_label=Fungua +print.title=Chapisha +print_label=Chapisha +download.title=Pakua +download_label=Pakua +bookmark.title=Mwonekano wa sasa (nakili au ufungue katika dirisha mpya) +bookmark_label=Mwonekano wa Sasa + +# Secondary toolbar and context menu + + +# Document properties dialog box +# LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" +# will be replaced by the PDF file size in kilobytes, respectively in 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_title=Kichwa: +# LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" +# will be replaced by the creation/modification date, and time, of the PDF file. + +# 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) +toggle_sidebar.title=Kibiano cha Upau wa Kando +toggle_sidebar_label=Kibiano cha Upau wa Kando +document_outline_label=Ufupisho wa Waraka +thumbs.title=Onyesha Kijipicha +thumbs_label=Vijipicha +findbar.title=Pata katika Waraka + +# 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=Ukurasa {{ukurasa}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Kijipicha cha ukurasa {{ukurasa}} + +# Find panel button title and messages +find_previous.title=Tafuta tukio kabla ya msemo huu +find_previous_label=Iliyotangulia +find_next.title=Tafuta tukio linalofuata la msemo +find_next_label=Ifuatayo +find_highlight=Angazia yote +find_match_case_label=Linganisha herufi +find_reached_top=Imefika juu ya waraka, imeendelea kutoka chini +find_reached_bottom=Imefika mwisho wa waraka, imeendelea kutoka juu +find_not_found=Msemo hukupatikana + +# Error panel labels +error_more_info=Maelezo Zaidi +error_less_info=Maelezo Kidogo +# 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}} (jenga: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Ujumbe: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Panganya: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Faili: {{faili}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Laini: {{laini}} +rendering_error=Hitilafu lilitokea wajati wa kutoa ukurasa + +# Predefined zoom values +page_scale_width=Upana wa Ukurasa +page_scale_fit=Usawa wa Ukurasa +page_scale_auto=Ukuzaji wa Kiotomatiki +page_scale_actual=Ukubwa Halisi +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. + +# Loading indicator messages +loading_error_indicator=Hitilafu +loading_error=Hitilafu lilitokea wakati wa kupakia PDF. +invalid_file_error=Faili ya PDF isiyohalali au potofu. +missing_file_error=Faili ya PDF isiyopo. + +# 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}} Ufafanuzi] +password_ok=SAWA + +printing_not_supported=Onyo: Uchapishaji hauauniwi kabisa kwa kivinjari hiki. +web_fonts_disabled=Fonti za tovuti zimelemazwa: haziwezi kutumia fonti za PDF zilizopachikwa. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ta-LK/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ta-LK/viewer.properties new file mode 100755 index 00000000..f0b1f43e --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ta-LK/viewer.properties @@ -0,0 +1,77 @@ +# 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) + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +zoom.title=ΰ…ΰ³ΰ΅ΰ― +open_file.title=ΰ•ΰ―‹ΰͺ்ΰͺΰΏΰ©ΰ―ˆΰ€ΰ― ΰ€ΰΏΰ±ΰ•ΰ―ΰ• +open_file_label=ΰ€ΰΏΰ±ΰ•ΰ―ΰ• + +# Secondary toolbar and context menu + + +# Document properties dialog box +# LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" +# will be replaced by the PDF file size in kilobytes, respectively in bytes. +# LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" +# will be replaced by the PDF file size in megabytes, respectively in bytes. +# LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" +# will be replaced by the creation/modification date, and time, of the PDF file. + +# 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) + +# Thumbnails panel item (tooltip and alt text for images) +# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page +# number. +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. + +# Find panel button title and messages +find_previous.title=ΰ‡ΰ¨ΰ―ΰ€ ΰšΰ―Šΰ±ΰ―ΰ±ΰ―ŠΰŸΰ°ΰΏΰ©ΰ― ΰுΰ©ΰ―ΰ©ΰ―ˆΰ― ΰ¨ΰΏΰ•ΰ΄ΰ―ΰ΅ΰ―ˆ ΰ€ΰ―‡ΰŸΰ― +find_next.title=ΰ‡ΰ¨ΰ―ΰ€ ΰšΰ―Šΰ±ΰ―ΰ±ΰ―ŠΰŸΰ°ΰΏΰ©ΰ― ΰ…ΰŸΰ―ΰ€ΰ―ΰ€ ΰ¨ΰΏΰ•ΰ΄ΰ―ΰ΅ΰ―ˆΰ€ΰ― ΰ€ΰ―‡ΰŸΰ― + +# Error panel labels +# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be +# replaced by the PDF.JS version and build ID. +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number + +# Predefined zoom values +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. + +# Loading indicator messages + +# 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_ok=ΰ†ΰ் + diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ta/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ta/viewer.properties new file mode 100755 index 00000000..2e216ea0 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ta/viewer.properties @@ -0,0 +1,184 @@ +# 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={{pagesCount}}) ΰ‡ΰ²ΰ― ({{pageNumber}} + +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=ΰுΰ€ΰ²ΰ― ΰͺΰ•்ΰ•ΰ€ΰ―ΰ€ΰΏΰ±ΰ―ΰ•ு ΰšΰ―†ΰ²ΰ―ΰ²ΰ΅ΰ―ΰ் +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_label=ΰ‰ΰ°ΰ―ˆΰ€ΰ― ΰ€ΰ―†ΰ°ΰΏΰ΅ΰ― ΰ•ΰ°ΰ―ΰ΅ΰΏ +cursor_hand_tool.title=ΰ•ΰ―ˆΰ•் ΰ•ΰ°ΰ―ΰ΅ΰΏΰ•்ΰšΰ― ΰšΰ―†ΰ―ΰ±ΰ―ΰͺΰŸΰ―ΰ€ΰ―ΰ€ΰ― +cursor_hand_tool_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=ΰͺΰΏΰŸΰΏΰŽΰƒΰͺ் ΰ€ΰ―ΰΎΰ°ΰΏΰͺ்ΰͺΰΎΰ³ΰ°ΰ―: +document_properties_version=PDF ΰͺΰ€ΰΏΰͺ்ΰͺு: +document_properties_page_count=ΰͺΰ•ΰ―ΰ• ΰŽΰ£ΰ―ΰ£ΰΏΰ•்ΰ•ΰ―ˆ: +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_notification.title=ΰͺΰ•்ΰ•ΰͺ்ΰͺΰŸΰ―ΰŸΰ―ˆΰ―ை ΰ¨ΰΏΰ²ΰ―ˆΰΰΎΰ±ΰ―ΰ±ΰ― (ΰ΅ΰ―†ΰ³ΰΏΰ•்ΰ•ΰ―‹ΰŸΰ―/ΰ‡ΰ£ΰ―ˆΰͺ்ΰͺுΰ•ΰ³ΰ―ˆ ΰ†ΰ΅ΰ£ΰ் ΰ•ΰ―Šΰ£ΰ―ΰŸΰ―ΰ³ΰ―ΰ³ΰ€ΰ―) +toggle_sidebar_label=ΰͺΰ•்ΰ•ΰͺ் ΰͺΰŸΰ―ΰŸΰΏΰ―ை ΰ¨ΰΏΰ²ΰ―ˆΰΰΎΰ±ΰ―ΰ±ΰ― +document_outline.title=ΰ†ΰ΅ΰ£ ΰ…ΰŸΰ•்ΰ•ΰ€ΰ―ΰ€ΰ―ˆΰ•் ΰ•ΰΎΰŸΰ―ΰŸΰ― (ΰ‡ΰ°ΰ―ΰுΰ±ΰ―ˆΰšΰ― ΰšΰ―ŠΰŸΰ―ΰ•்ΰ•ΰΏ ΰ…ΰ©ΰ―ˆΰ€ΰ―ΰ€ΰ― ΰ‰ΰ±ΰ―ΰͺ்ΰͺΰΏΰŸΰΏΰ•ΰ³ΰ―ˆΰ―ுΰ் ΰ΅ΰΏΰ°ΰΏ/ΰšΰ―‡ΰ°ΰ―) +document_outline_label=ΰ†ΰ΅ΰ£ ΰ΅ΰ―†ΰ³ΰΏΰ΅ΰ°ΰ―ˆ +attachments.title=ΰ‡ΰ£ΰ―ˆΰͺ்ΰͺுΰ•ΰ³ΰ―ˆ ΰ•ΰΎΰ£ΰ―ΰͺΰΏ +attachments_label=ΰ‡ΰ£ΰ―ˆΰͺ்ΰͺுΰ•ΰ³ΰ― +thumbs.title=ΰšΰΏΰ±ΰ―ΰͺΰŸΰ™ΰ―ΰ•ΰ³ΰ―ˆΰ•் ΰ•ΰΎΰ£ΰ―ΰͺΰΏ +thumbs_label=ΰšΰΏΰ±ΰ―ΰͺΰŸΰ™ΰ―ΰ•ΰ³ΰ― +findbar.title=ΰ†ΰ΅ΰ£ΰ€ΰ―ΰ€ΰΏΰ²ΰ― ΰ•ΰ£ΰ―ΰŸΰ±ΰΏ +findbar_label=ΰ€ΰ―‡ΰŸΰ― + +# 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_reached_top=ΰ†ΰ΅ΰ£ΰ€ΰ―ΰ€ΰΏΰ©ΰ― ΰΰ―‡ΰ²ΰ― ΰͺΰ•ுΰ€ΰΏΰ―ை ΰ…ΰŸΰ―ˆΰ¨ΰ―ΰ€ΰ€ΰ―, ΰ…ΰŸΰΏΰͺ்ΰͺΰ•்ΰ•ΰ€ΰ―ΰ€ΰΏΰ²ΰΏΰ°ΰ―ΰ¨ΰ―ΰ€ΰ― ΰ€ΰ―ŠΰŸΰ°ΰ―ΰ¨ΰ―ΰ€ΰ€ΰ― +find_reached_bottom=ΰ†ΰ΅ΰ£ΰ€ΰ―ΰ€ΰΏΰ©ΰ― ΰுΰŸΰΏΰ΅ΰ―ˆ ΰ…ΰŸΰ―ˆΰ¨ΰ―ΰ€ΰ€ΰ―, ΰΰ―‡ΰ²ΰΏΰ°ΰ―ΰ¨ΰ―ΰ€ΰ― ΰ€ΰ―ŠΰŸΰ°ΰ―ΰ¨ΰ―ΰ€ΰ€ΰ― +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_indicator=ΰͺΰΏΰ΄ΰ―ˆ +loading_error=PDF ΰ ΰΰ±ΰ―ΰ±ΰ―ΰ் ΰͺΰ―‹ΰ€ΰ― ΰ’ΰ°ΰ― ΰͺΰΏΰ΄ΰ―ˆ ΰΰ±ΰ―ΰͺΰŸΰ―ΰŸΰ€ΰ―. +invalid_file_error=ΰšΰ―†ΰ²ΰ―ΰ²ΰ―ΰͺΰŸΰΏΰ―ΰΎΰ•ΰΎΰ€ ΰ…ΰ²ΰ―ΰ²ΰ€ΰ― ΰšΰΏΰ€ΰ―ˆΰ¨ΰ―ΰ€ PDF ΰ•ΰ―‹ΰͺ்ΰͺு. +missing_file_error=PDF ΰ•ΰ―‹ΰͺ்ΰͺு ΰ•ΰΎΰ£ΰ΅ΰΏΰ²ΰ―ΰ²ΰ―ˆ. +unexpected_response_error=ΰšΰ―‡ΰ΅ΰ•ΰ©ΰ― ΰͺΰ€ΰΏΰ²ΰ― ΰŽΰ€ΰΏΰ°ΰ―ΰͺΰΎΰ°ΰ€ΰ€ΰ―. + +# 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 ΰŽΰ΄ΰ―ΰ€ΰ―ΰ€ΰ―ΰ°ΰ―ΰ•்ΰ•ΰ³ΰ―ˆΰͺ் ΰͺΰ―ΰ©ΰ―ΰͺΰŸΰ―ΰ€ΰ―ΰ€ ΰுΰŸΰΏΰ―ΰ΅ΰΏΰ²ΰ―ΰ²ΰ―ˆ. +document_colors_not_allowed=PDF ΰ†ΰ΅ΰ£ΰ™ΰ―ΰ•ΰ³ΰ―ΰ•்ΰ•ுΰšΰ― ΰšΰ―Šΰ¨ΰ―ΰ€ ΰ¨ΰΏΰ±ΰ™ΰ―ΰ•ΰ³ΰ―ˆΰͺ் ΰͺΰ―ΰ©ΰ―ΰͺΰŸΰ―ΰ€ΰ―ΰ€ ΰ…ΰ©ΰ―ΰΰ€ΰΏΰ―ΰΏΰ²ΰ―ΰ²ΰ―ˆ: ΰ‰ΰ²ΰΎΰ΅ΰΏΰ―ΰΏΰ²ΰ― "ΰͺΰ•்ΰ•ΰ™ΰ―ΰ•ΰ³ΰ― ΰ€ΰ™ΰ―ΰ•ΰ³ΰ― ΰšΰ―Šΰ¨ΰ―ΰ€ ΰ¨ΰΏΰ±ΰ™ΰ―ΰ•ΰ³ΰ―ˆΰ€ΰ― ΰ€ΰ―‡ΰ°ΰ―ΰ΅ΰ― ΰšΰ―†ΰ―்ΰ€ΰ―ΰ•ΰ―Šΰ³ΰ―ΰ³ ΰ…ΰ©ΰ―ΰΰ€ΰΏ" ΰŽΰ©ΰ―ΰ©ΰ―ΰ் ΰ΅ΰΏΰ°ΰ―ΰͺ்ΰͺΰ் ΰுΰŸΰ•்ΰ•ΰͺ்ΰͺΰŸΰ―ΰŸΰ―ΰ³ΰ―ΰ³ΰ€ΰ―. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/te/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/te/viewer.properties new file mode 100755 index 00000000..10d8fa88 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/te/viewer.properties @@ -0,0 +1,183 @@ +# 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=ΰ°ΰ±Šΰ°€ΰ±ΰ°€ΰ°‚ {{pageCount}} లో +# 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=(ΰ°ΰ±Šΰ°€ΰ±ΰ°€ΰ°‚ {{pagesCount}} లో {{pageNumber}}ΰ°΅ΰ°¦ΰ°Ώ) + +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=ΰ°ΰ±Šΰ°¦ΰ°Ÿΰ°Ώ ΰ°ͺΰ±‡ΰ°œΰ±€ΰ°•ΰ°Ώ డెళ్ళు +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_label=ΰ°Ÿΰ±†ΰ°•ΰ±ΰ°Έΰ±ΰ°Ÿΰ± ΰ°Žΰ°‚ΰ°ͺΰ°Ώΰ°• ΰ°Έΰ°Ύΰ°§ΰ°¨ΰ°‚ +cursor_hand_tool.title=ΰ°šΰ±‡ΰ°€ΰ°Ώ ΰ°Έΰ°Ύΰ°§ΰ°¨ΰ°‚ ΰ°šΰ±‡ΰ°€ΰ°¨ΰ°Ώΰ°‚ΰ°šΰ± +cursor_hand_tool_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}} 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=ఢీర్షిక: +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_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.title=ΰ°ͺఀ్రΰ°ΰ± రూΰ°ͺΰ°ΰ± ΰ°šΰ±‚ΰ°ͺΰ°Ώΰ°‚ΰ°šΰ± (఑బుల్ క్లిక్ ΰ°šΰ±‡ΰ°Έΰ°Ώ అన్ని అంఢాలను ΰ°΅ΰ°Ώΰ°Έΰ±ΰ°€ΰ°°ΰ°Ώΰ°‚ΰ°šΰ±/ΰ°•ΰ±‚ΰ°²ΰ±ΰ°šΰ±) +document_outline_label=ΰ°ͺఀ్రΰ°ΰ± ΰ°…ΰ°΅ΰ±ΰ°Ÿΰ±β€Œΰ°²ΰ±ˆΰ°¨ΰ± +attachments.title=అనుబంధాలు ΰ°šΰ±‚ΰ°ͺు +attachments_label=అనుబంధాలు +thumbs.title=ΰ°₯ΰ°‚ΰ°¬ΰ±β€Œΰ°¨ΰ±ˆΰ°²ΰ±ΰ°Έΰ± ΰ°šΰ±‚ΰ°ͺు +thumbs_label=ΰ°₯ΰ°‚ΰ°¬ΰ±β€Œΰ°¨ΰ±ˆΰ°²ΰ±ΰ°Έΰ± +findbar.title=ΰ°ͺఀ్రΰ°ΰ±ΰ°²ΰ±‹ ΰ°•ΰ°¨ΰ±ΰ°—ΰ±Šΰ°¨ΰ±ΰ°ΰ± +findbar_label=ΰ°•ΰ°¨ΰ±ΰ°—ΰ±Šΰ°¨ΰ± + +# 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_reached_top=ΰ°ͺΰ±‡ΰ°œΰ±€ ΰ°ͺΰ±ˆΰ°•ΰ°Ώ ΰ°šΰ±‡ΰ°°ΰ±ΰ°•ΰ±ΰ°¨ΰ±ΰ°¨ΰ°¦ΰ°Ώ, క్రింది నుం఑ి ΰ°•ΰ±Šΰ°¨ΰ°Έΰ°Ύΰ°—ΰ°Ώΰ°‚ΰ°šΰ°‚ΰ°‘ΰ°Ώ +find_reached_bottom=ΰ°ͺΰ±‡ΰ°œΰ±€ ΰ°šΰ°Ώΰ°΅ΰ°°ΰ°•ΰ± ΰ°šΰ±‡ΰ°°ΰ±ΰ°•ΰ±ΰ°¨ΰ±ΰ°¨ΰ°¦ΰ°Ώ, ΰ°ͺΰ±ˆΰ°¨ΰ±ΰ°‚ΰ°‘ΰ°Ώ ΰ°•ΰ±Šΰ°¨ΰ°Έΰ°Ύΰ°—ΰ°Ώΰ°‚ΰ°šΰ°‚ΰ°‘ΰ°Ώ +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_indicator=దోషం +loading_error=PDF ΰ°²ΰ±‹ΰ°‘ΰ°΅ΰ±ΰ°šΰ±ΰ°¨ΰ±ΰ°¨ΰ°ͺ్ΰ°ͺు఑ు ΰ°’ΰ°• దోషం ΰ°Žΰ°¦ΰ±ΰ°°ΰ±ˆΰ°‚ΰ°¦ΰ°Ώ. +invalid_file_error=ΰ°šΰ±†ΰ°²ΰ±ΰ°²ΰ°¨ΰ°Ώ లేదా ΰ°ͺా఑ైన PDF ఫైలు. +missing_file_error=ΰ°¦ΰ±Šΰ°°ΰ°•ΰ°¨ΰ°Ώ PDF ఫైలు. +unexpected_response_error=అనుకోని సర్డర్ స్ΰ°ͺΰ°‚ΰ°¦ΰ°¨. + +# 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 ΰ°«ΰ°Ύΰ°‚ΰ°Ÿΰ±ΰ°²ΰ± ΰ°‰ΰ°ͺΰ°―ΰ±‹ΰ°—ΰ°Ώΰ°‚ΰ°šΰ°²ΰ±‡ΰ°• ΰ°ͺోయింది. +document_colors_not_allowed=PDF ΰ°ͺఀ్రాలు డాటి స్డంఀ రంగులను ΰ°‰ΰ°ͺΰ°―ΰ±‹ΰ°—ΰ°Ώΰ°‚ΰ°šΰ±ΰ°•ΰ±Šΰ°¨ΰ±ΰ°Ÿΰ°•ΰ± అనుΰ°ΰ°€ΰ°Ώΰ°‚ΰ°šΰ°¬ΰ°‘డు: ΰ°΅ΰ°Ώΰ°Ήΰ°°ΰ°£ΰ°Ώ నందు β€œΰ°ͺΰ±‡ΰ°œΰ±€ΰ°²ΰ°¨ΰ± డాటి స్డంఀ రంగులను ΰ°Žΰ°‚ΰ°šΰ±ΰ°•ΰ±Šΰ°¨ΰ±ΰ°Ÿΰ°•ΰ± అనుΰ°ΰ°€ΰ°Ώΰ°‚ΰ°šΰ±β€ ΰ°…ΰ°šΰ±‡ΰ°€ΰ°¨ΰ°‚ ΰ°šΰ±‡ΰ°―ΰ°¬ΰ°‘ΰ°Ώΰ°΅ΰ±ΰ°‚ΰ°¦ΰ°Ώ. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/th/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/th/viewer.properties new file mode 100755 index 00000000..f1fd5450 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/th/viewer.properties @@ -0,0 +1,180 @@ +# 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=ไปฒังหน้าแรก +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=หฑุนทวนเข็ฑนาฬิกา + + +# 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_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_notification.title=ΰΉ€ΰΈ›ΰΈ΄ΰΈ”/ΰΈ›ΰΈ΄ΰΈ”ΰΉΰΈ–ΰΈšΰΈ‚ΰΉ‰ΰΈ²ΰΈ‡ (เอกΰΈͺΰΈ²ΰΈ£ΰΈ‘ΰΈ΅ΰΉ€ΰΈ„ΰΉ‰ΰΈ²ΰΈ£ΰΉˆΰΈ²ΰΈ‡/ΰΉ„ΰΈŸΰΈ₯ΰΉŒΰΉΰΈ™ΰΈš) +toggle_sidebar_label=ΰΉ€ΰΈ›ΰΈ΄ΰΈ”/ΰΈ›ΰΈ΄ΰΈ”ΰΉΰΈ–ΰΈšΰΈ‚ΰΉ‰ΰΈ²ΰΈ‡ +document_outline.title=แΰΈͺΰΈ”ΰΈ‡ΰΉ€ΰΈ„ΰΉ‰ΰΈ²ΰΈ£ΰΉˆΰΈ²ΰΈ‡ΰΉ€ΰΈ­ΰΈΰΈͺΰΈ²ΰΈ£ (ΰΈ„ΰΈ₯ิกΰΈͺΰΈ­ΰΈ‡ΰΈ„ΰΈ£ΰΈ±ΰΉ‰ΰΈ‡ΰΉ€ΰΈžΰΈ·ΰΉˆΰΈ­ΰΈ‚ΰΈ’ΰΈ²ΰΈ’/ΰΈ’ΰΈΈΰΈšΰΈ£ΰΈ²ΰΈ’ΰΈΰΈ²ΰΈ£ΰΈ—ΰΈ±ΰΉ‰ΰΈ‡ΰΈ«ΰΈ‘ΰΈ”) +document_outline_label=ΰΉ€ΰΈ„ΰΉ‰ΰΈ²ΰΈ£ΰΉˆΰΈ²ΰΈ‡ΰΉ€ΰΈ­ΰΈΰΈͺΰΈ²ΰΈ£ +attachments.title=แΰΈͺΰΈ”ΰΈ‡ΰΉ„ΰΈŸΰΈ₯ΰΉŒΰΉΰΈ™ΰΈš +attachments_label=ΰΉ„ΰΈŸΰΈ₯ΰΉŒΰΉΰΈ™ΰΈš +thumbs.title=แΰΈͺΰΈ”ΰΈ‡ΰΈ ΰΈ²ΰΈžΰΈ‚ΰΈ™ΰΈ²ΰΈ”ΰΈ’ΰΉˆΰΈ­ +thumbs_label=ΰΈ ΰΈ²ΰΈžΰΈ‚ΰΈ™ΰΈ²ΰΈ”ΰΈ’ΰΉˆΰΈ­ +findbar.title=ค้นหาในเอกΰΈͺΰΈ²ΰΈ£ +findbar_label=ΰΈ„ΰΉ‰ΰΈ™ΰΈ«ΰΈ² + +# 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_reached_top=ΰΈ„ΰΉ‰ΰΈ™ΰΈ«ΰΈ²ΰΈ–ΰΈΆΰΈ‡ΰΈˆΰΈΈΰΈ”ΰΉ€ΰΈ£ΰΈ΄ΰΉˆΰΈ‘ΰΈ•ΰΉ‰ΰΈ™ΰΈ‚ΰΈ­ΰΈ‡ΰΈ«ΰΈ™ΰΉ‰ΰΈ² ΰΉ€ΰΈ£ΰΈ΄ΰΉˆΰΈ‘ΰΈ„ΰΉ‰ΰΈ™ΰΈ•ΰΉˆΰΈ­ΰΈˆΰΈ²ΰΈΰΈ”ΰΉ‰ΰΈ²ΰΈ™ΰΈ₯ΰΉˆΰΈ²ΰΈ‡ +find_reached_bottom=ΰΈ„ΰΉ‰ΰΈ™ΰΈ«ΰΈ²ΰΈ–ΰΈΆΰΈ‡ΰΈˆΰΈΈΰΈ”ΰΈͺΰΈ΄ΰΉ‰ΰΈ™ΰΈͺΰΈΈΰΈ”ΰΈ«ΰΈ™ΰΉ‰ΰΈ² ΰΉ€ΰΈ£ΰΈ΄ΰΉˆΰΈ‘ΰΈ„ΰΉ‰ΰΈ™ΰΈ•ΰΉˆΰΈ­ΰΈˆΰΈ²ΰΈΰΈ”ΰΉ‰ΰΈ²ΰΈ™ΰΈšΰΈ™ +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_indicator=ΰΈ‚ΰΉ‰ΰΈ­ΰΈœΰΈ΄ΰΈ”ΰΈžΰΈ₯ΰΈ²ΰΈ” +loading_error=ΰΉ€ΰΈΰΈ΄ΰΈ”ΰΈ‚ΰΉ‰ΰΈ­ΰΈœΰΈ΄ΰΈ”ΰΈžΰΈ₯าดขณะกำΰΈ₯ΰΈ±ΰΈ‡ΰΉ‚ΰΈ«ΰΈ₯ΰΈ” PDF +invalid_file_error=ΰΉ„ΰΈŸΰΈ₯์ PDF ΰΉ„ΰΈ‘ΰΉˆΰΈ–ΰΈΉΰΈΰΈ•ΰΉ‰ΰΈ­ΰΈ‡ΰΈ«ΰΈ£ΰΈ·ΰΈ­ΰΉ€ΰΈͺΰΈ΅ΰΈ’ΰΈ«ΰΈ²ΰΈ’ +missing_file_error=ΰΉ„ΰΈŸΰΈ₯์ PDF ΰΈ‚ΰΈ²ΰΈ”ΰΈ«ΰΈ²ΰΈ’ +unexpected_response_error=ΰΈΰΈ²ΰΈ£ΰΈ•ΰΈ­ΰΈšΰΈͺΰΈ™ΰΈ­ΰΈ‡ΰΈ‚ΰΈ­ΰΈ‡ΰΉ€ΰΈ‹ΰΈ΄ΰΈ£ΰΉŒΰΈŸΰΉ€ΰΈ§ΰΈ­ΰΈ£ΰΉŒΰΈ—ΰΈ΅ΰΉˆΰΉ„ΰΈ‘ΰΉˆΰΈ„ΰΈ²ΰΈ”ΰΈ„ΰΈ΄ΰΈ” + +# 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 ฝังตัว +document_colors_not_allowed=เอกΰΈͺΰΈ²ΰΈ£ PDF ΰΉ„ΰΈ‘ΰΉˆΰΉ„ΰΈ”ΰΉ‰ΰΈ£ΰΈ±ΰΈšΰΈ­ΰΈ™ΰΈΈΰΈΰΈ²ΰΈ•ΰΉƒΰΈ«ΰΉ‰ΰΉƒΰΈŠΰΉ‰ΰΈͺΰΈ΅ΰΈ‚ΰΈ­ΰΈ‡ΰΈ•ΰΈ±ΰΈ§ΰΉ€ΰΈ­ΰΈ‡: "อนุญาตให้หน้าเอกΰΈͺΰΈ²ΰΈ£ΰΈͺΰΈ²ΰΈ‘ΰΈ²ΰΈ£ΰΈ–ΰΉ€ΰΈ₯ือกΰΈͺΰΈ΅ΰΈ‚ΰΈ­ΰΈ‡ΰΈ•ΰΈ±ΰΈ§ΰΉ€ΰΈ­ΰΈ‡" ΰΈ–ΰΈΉΰΈΰΈ›ΰΈ΄ΰΈ”ΰΉƒΰΈŠΰΉ‰ΰΈ‡ΰΈ²ΰΈ™ΰΉƒΰΈ™ΰΉ€ΰΈšΰΈ£ΰΈ²ΰΈ§ΰΉŒΰΉ€ΰΈ‹ΰΈ­ΰΈ£ΰΉŒ diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/tl/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/tl/viewer.properties new file mode 100755 index 00000000..de4d1bf6 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/tl/viewer.properties @@ -0,0 +1,97 @@ +# 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=Naunang Pahina +next.title=Sunod na Pahina + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +open_file.title=Magbukas ng file +open_file_label=Buksan +bookmark.title=Kasalukuyang tingin (kopyahin o buksan sa bagong window) +bookmark_label=Kasalukuyang tingin + +# Secondary toolbar and context menu +tools.title=Mga Tool +tools_label=Mga Tool + + +# Document properties dialog box +# LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" +# will be replaced by the PDF file size in kilobytes, respectively in 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_title=Pamagat: +# LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" +# will be replaced by the creation/modification date, and time, of the PDF file. + +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +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) +thumbs.title=Ipakita ang mga Thumbnails +findbar_label=Hanapin + +# 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=Pahina {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Thumbnail ng Pahina {{page}} + +# Find panel button title and messages +find_highlight=I-highlight lahat + +# Error panel labels +error_more_info=Maraming Inpormasyon +error_less_info=Maikling Inpormasyon +# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be +# replaced by the PDF.JS version and build ID. +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Mensahe: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +# 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. + +# Predefined zoom values +page_scale_width=Haba ng Pahina +page_scale_fit=ang pahina ay angkop +page_scale_auto=awtomatikong pag-imbulog +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. + +# Loading indicator messages +loading_error=May maling nangyari habang kinakarga ang PDF. + +# 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_ok=OK +password_cancel=Kanselahin + diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/tn/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/tn/viewer.properties new file mode 100755 index 00000000..eda077c3 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/tn/viewer.properties @@ -0,0 +1,83 @@ +# 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) + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +zoom.title=Zuma/gogela +open_file.title=Bula Faele +open_file_label=Bula + +# Secondary toolbar and context menu + + +# Document properties dialog box +document_properties_file_name=Leina la faele: +# LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" +# will be replaced by the PDF file size in kilobytes, respectively in 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_title=Leina: +# LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" +# will be replaced by the creation/modification date, and time, of the PDF file. + +# 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) + +# Thumbnails panel item (tooltip and alt text for images) +# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page +# number. +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. + +# Find panel button title and messages +find_previous.title=Batla tiragalo e e fetileng ya setlhopha sa mafoko +find_next.title=Batla tiragalo e e latelang ya setlhopha sa mafoko +find_not_found=Setlhopha sa mafoko ga se a bonwa + +# Error panel labels +error_more_info=Tshedimosetso e Nngwe +# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be +# replaced by the PDF.JS version and build ID. +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number + +# Predefined zoom values +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. + +# Loading indicator messages +loading_error_indicator=Phoso + +# 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_ok=Siame + +web_fonts_disabled=Mefutatlhaka ya Webo ga e dire: ga e kgone go dirisa mofutatlhaka wa PDF o tsentsweng. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/tr/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/tr/viewer.properties new file mode 100755 index 00000000..2c60df20 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/tr/viewer.properties @@ -0,0 +1,184 @@ +# 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=Γ–nceki sayfa +previous_label=Γ–nceki +next.title=Sonraki sayfa +next_label=Sonraki + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Sayfa +# 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=UzaklaştΔ±r +zoom_out_label=UzaklaştΔ±r +zoom_in.title=YaklaştΔ±r +zoom_in_label=YaklaştΔ±r +zoom.title=YakΔ±nlaştΔ±rma +presentation_mode.title=Sunum moduna geΓ§ +presentation_mode_label=Sunum Modu +open_file.title=Dosya aΓ§ +open_file_label=AΓ§ +print.title=YazdΔ±r +print_label=YazdΔ±r +download.title=Δ°ndir +download_label=Δ°ndir +bookmark.title=GeΓ§erli gΓΆrΓΌnΓΌm (kopyala veya yeni pencerede aΓ§) +bookmark_label=GeΓ§erli gΓΆrΓΌnΓΌm + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=Metin seΓ§me aracΔ± +cursor_hand_tool.title=El aracΔ±nΔ± etkinleştir +cursor_hand_tool_label=El aracΔ± + +# Document properties dialog box +document_properties.title=Belge ΓΆzellikleri… +document_properties_label=Belge ΓΆzellikleri… +document_properties_file_name=Dosya adΔ±: +document_properties_file_size=Dosya boyutu: +# 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}} bayt) +# 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}} bayt) +document_properties_title=BaşlΔ±k: +document_properties_author=Yazar: +document_properties_subject=Konu: +document_properties_keywords=Anahtar kelimeler: +document_properties_creation_date=Oluturma tarihi: +document_properties_modification_date=Değiştirme tarihi: +# 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=Oluşturan: +document_properties_producer=PDF ΓΌreticisi: +document_properties_version=PDF sΓΌrΓΌmΓΌ: +document_properties_page_count=Sayfa sayΔ±sΔ±: +document_properties_close=Kapat + +print_progress_message=Belge yazdΔ±rΔ±lmaya hazΔ±rlanΔ±yor… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent=%{{progress}} +print_progress_close=Δ°ptal + +# 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=Kenar Γ§ubuğunu aΓ§/kapat +toggle_sidebar_notification.title=Kenar Γ§ubuğunu aΓ§/kapay (Belge anahat/ekler iΓ§eriyor) +toggle_sidebar_label=Kenar Γ§ubuğunu aΓ§/kapat +document_outline.title=Belge şemasΔ±nΔ± gΓΆster (TΓΌm âğeleri genişletmek/daraltmak iΓ§in Γ§ift tΔ±klayΔ±n) +document_outline_label=Belge şemasΔ± +attachments.title=Ekleri gΓΆster +attachments_label=Ekler +thumbs.title=KΓΌΓ§ΓΌk resimleri gΓΆster +thumbs_label=KΓΌΓ§ΓΌk resimler +findbar.title=Belgede bul +findbar_label=Bul + +# 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=Sayfa {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas={{page}}. sayfanΔ±n kΓΌΓ§ΓΌk hΓ’li + +# Find panel button title and messages +find_input.title=Bul +find_input.placeholder=Belgede bul… +find_previous.title=Γ–nceki eşleşmeyi bul +find_previous_label=Γ–nceki +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_reached_top=Belgenin başına ulaşıldΔ±, sonundan devam edildi +find_reached_bottom=Belgenin sonuna ulaşıldΔ±, başından devam edildi +find_not_found=Eşleşme bulunamadΔ± + +# Error panel labels +error_more_info=Daha fazla bilgi al +error_less_info=Daha az bilgi +error_close=Kapat +# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be +# replaced by the PDF.JS version and build ID. +error_version_info=PDF.js sΓΌrΓΌm {{version}} (yapΔ±: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Δ°leti: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Yığın: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Dosya: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=SatΔ±r: {{line}} +rendering_error=Sayfa yorumlanΔ±rken bir hata oluştu. + +# Predefined zoom values +page_scale_width=Sayfa genişliği +page_scale_fit=SayfayΔ± sığdΔ±r +page_scale_auto=Otomatik yakΔ±nlaştΔ±r +page_scale_actual=GerΓ§ek boyut +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent=%{{scale}} + +# Loading indicator messages +loading_error_indicator=Hata +loading_error=PDF yΓΌklenirken bir hata oluştu. +invalid_file_error=GeΓ§ersiz veya bozulmuş PDF dosyasΔ±. +missing_file_error=PDF dosyasΔ± eksik. +unexpected_response_error=Beklenmeyen sunucu yanΔ±tΔ±. + +# 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}} işareti] +password_label=Bu PDF dosyasΔ±nΔ± aΓ§mak iΓ§in parolasΔ±nΔ± yazΔ±n. +password_invalid=GeΓ§ersiz parola. LΓΌtfen tekrar deneyin. +password_ok=Tamam +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. +document_colors_not_allowed=PDF belgelerinin kendi renklerini kullanmasΔ± iΓ§in izin verilmiyor: β€œSayfalara kendi renklerini seΓ§mesi iΓ§in izin ver” tarayΔ±cΔ±da etkinleştirilmemiş. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/uk/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/uk/viewer.properties new file mode 100755 index 00000000..b2eda938 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/uk/viewer.properties @@ -0,0 +1,184 @@ +# 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=На ΠΏΠ΅Ρ€ΡˆΡƒ сторінку +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_label=ІнструмСнт Π²ΠΈΠ±ΠΎΡ€Ρƒ тСксту +cursor_hand_tool.title=Π£Π²Ρ–ΠΌΠΊΠ½ΡƒΡ‚ΠΈ інструмСнт Β«Π ΡƒΠΊΠ°Β» +cursor_hand_tool_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}} 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}} ΠœΠ‘ ({{size_b}} bytes) +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_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_notification.title=ΠŸΠ΅Ρ€Π΅ΠΌΠΊΠ½ΡƒΡ‚ΠΈ Π±Ρ–Ρ‡Π½Ρƒ панСль (Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ ΠΌΠ°Ρ” вміст/вкладСння) +toggle_sidebar_label=ΠŸΠ΅Ρ€Π΅ΠΌΠΊΠ½ΡƒΡ‚ΠΈ Π±Ρ–Ρ‡Π½Ρƒ панСль +document_outline.title=ΠŸΠΎΠΊΠ°Π·Π°Ρ‚ΠΈ схСму Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Ρƒ (ΠΏΠΎΠ΄Π²Ρ–ΠΉΠ½ΠΈΠΉ ΠΊΠ»Ρ–ΠΊ для розгортання/згортання Π΅Π»Π΅ΠΌΠ΅Π½Ρ‚Ρ–Π²) +document_outline_label=Π‘Ρ…Π΅ΠΌΠ° Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π° +attachments.title=ΠŸΠΎΠΊΠ°Π·Π°Ρ‚ΠΈ прикріплСння +attachments_label=ΠŸΡ€ΠΈΠΊΡ€Ρ–ΠΏΠ»Π΅Π½Π½Ρ +thumbs.title=ΠŸΠΎΠΊΠ°Π·ΡƒΠ²Π°Ρ‚ΠΈ Сскізи +thumbs_label=Ескізи +findbar.title=Π—Π½Π°ΠΉΡ‚ΠΈ Π² Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Ρ– +findbar_label=ΠŸΠΎΡˆΡƒΠΊ + +# 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_reached_top=Досягнуто ΠΏΠΎΡ‡Π°Ρ‚ΠΊΡƒ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Ρƒ, ΠΏΡ€ΠΎΠ΄ΠΎΠ²ΠΆΠ΅Π½ΠΎ Π· кінця +find_reached_bottom=Досягнуто кінця Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Ρƒ, ΠΏΡ€ΠΎΠ΄ΠΎΠ²ΠΆΠ΅Π½ΠΎ Π· ΠΏΠΎΡ‡Π°Ρ‚ΠΊΡƒ +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_indicator=Помилка +loading_error=ΠŸΡ–Π΄ час завантаТСння PDF сталася ΠΏΠΎΠΌΠΈΠ»ΠΊΠ°. +invalid_file_error=НСдійсний Π°Π±ΠΎ пошкодТСний PDF-Ρ„Π°ΠΉΠ». +missing_file_error=Відсутній PDF-Ρ„Π°ΠΉΠ». +unexpected_response_error=НСочікувана Π²Ρ–Π΄ΠΏΠΎΠ²Ρ–Π΄ΡŒ сСрвСра. + +# 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 ΡˆΡ€ΠΈΡ„Ρ‚ΠΈ. +document_colors_not_allowed=PDF-Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°ΠΌ Π½Π΅ Π΄ΠΎΠ·Π²ΠΎΠ»Π΅Π½ΠΎ використовувати власні ΠΊΠΎΠ»ΡŒΠΎΡ€ΠΈ: Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Ρ– Π²ΠΈΠΌΠΊΠ½Π΅Π½ΠΎ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ Β«Π”ΠΎΠ·Π²ΠΎΠ»ΠΈΡ‚ΠΈ сторінкам використовувати власні ΠΊΠΎΠ»ΡŒΠΎΡ€ΠΈΒ». diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/ur/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/ur/viewer.properties new file mode 100755 index 00000000..35a44583 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/ur/viewer.properties @@ -0,0 +1,176 @@ +# 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=پہلے ءفحہ ΩΎΨ± جائیں +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=ΨΆΨ― Ϊ―ΪΎΪ‘ΫŒ وار Ϊ―ΪΎΩ…Ψ§Ψ¦ΫŒΪΊ + + +# Document properties dialog box +document_properties.title=Ψ―Ψ³Ψͺاویز ΨΩˆΨ§Ψ΅β€¦ +document_properties_label=Ψ―Ψ³Ψͺاویز ΨΩˆΨ§Ψ΅β€¦\u0020 +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) +# 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=ΨΉΩ†ΩˆΨ§Ω†: +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_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.title=Ψ―Ψ³Ψͺاویز کی Ψ³Ψ±Ψیاں دکھایں (ΨͺΩ…Ψ§Ω… اشیاؑ وسیع / ΨΊΨ§Ψ¦Ψ¨ Ϊ©Ψ±Ω†Ϋ’ Ϊ©Ϋ’ Ω„ΫŒΫ’ ΪˆΨ¨Ω„ Ϊ©Ω„Ϊ© کریں) +document_outline_label=Ψ―Ψ³Ψͺاویز Ψ’Ψ€ΩΉ Ω„Ψ§Ψ¦Ω† +attachments.title=Ω…Ω†Ψ³Ω„Ϊ©Ψ§Ψͺ دکھائیں +attachments_label=Ω…Ω†Ψ³Ω„Ϊ©Ψ§Ψͺ +thumbs.title=ΨͺΪΎΩ…Ψ¨Ω†ΫŒΩ„ دکھائیں +thumbs_label=Ω…Ψ¬Ω…Ω„ +findbar.title=Ψ―Ψ³Ψͺاویز Ω…ΫŒΪΊ ΪˆΪΎΩˆΩ†ΪˆΫŒΪΊ + +# 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_previous_label=ΩΎΪ†ΪΎΩ„Ψ§ +find_next.title=فقرے Ϊ©Ψ§ اگلہ ΩˆΩ‚ΩˆΨΉ ΪˆΪΎΩˆΩ†ΪˆΫŒΪΊ +find_next_label=Ψ’Ϊ―Ϋ’ +find_highlight=ΨͺΩ…Ψ§Ω… Ω†Ω…Ψ§ΫŒΨ§ΪΊ کریں +find_match_case_label=حروف مشابہ کریں +find_reached_top=ءفحہ Ϊ©Ϋ’ شروع ΩΎΨ± پہنچ گیا، Ω†ΫŒΪ†Ϋ’ Ψ³Ϋ’ جاری کیا +find_reached_bottom=ءفحہ Ϊ©Ϋ’ Ψ§ΨΨͺΨͺΨ§Ω… ΩΎΨ± پہنچ گیا، اوپر Ψ³Ϋ’ جاری کیا +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_indicator=Ω†Ω‚Ψ΅ +loading_error=PDF Ω„ΩˆΪˆ Ϊ©Ψ±ΨͺΫ’ ΩˆΩ‚Ψͺ Ω†Ω‚Ψ΅ Ψ’ Ϊ―ΫŒΨ§Ϋ” +invalid_file_error=Ω†Ψ§Ψ¬Ψ§Ψ¦Ψ² یا ΨΨ±Ψ§Ψ¨ PDF Ω…Ψ³Ω„ +missing_file_error=PDF Ω…Ψ³Ω„ ΨΊΨ§Ψ¦Ψ¨ ہے۔ +unexpected_response_error=ΨΊΫŒΨ±Ω…ΨͺΩˆΩ‚ΨΉ پیش Ϊ©Ψ§Ψ± جواب + +# 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 فانٹ Ψ§Ψ³ΨͺΨΉΩ…Ψ§Ω„ Ϊ©Ψ±Ω†Ϋ’ Ω…ΫŒΪΊ Ω†Ψ§Ϊ©Ψ§Ω…Ϋ” +document_colors_not_allowed=PDF Ψ―Ψ³ΨͺاویزاΨͺ کو Ψ§ΩΎΩ†Ϋ’ Ψ±Ω†Ϊ― Ψ§Ψ³ΨͺΨΉΩ…Ψ§Ω„ Ϊ©Ψ±Ω†Ϋ’ کی Ψ§Ψ¬Ψ§Ψ²Ψͺ Ω†ΫΫŒΪΊ: 'ءفحاΨͺ کو Ψ§ΩΎΩ†Ϋ’ Ψ±Ω†Ϊ― Ϊ†Ω†ΫŒΪΊ' کی اِجازΨͺ Ψ¨Ψ±Ψ§Ψ€Ψ²Ψ± Ω…ΫŒΪΊ Ψ¨Ϋ’ ΨΉΩ…Ω„ ہے۔ diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/vi/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/vi/viewer.properties new file mode 100755 index 00000000..3623b653 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/vi/viewer.properties @@ -0,0 +1,173 @@ +# 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=Trang TrΖ°α»›c +previous_label=TrΖ°α»›c +next.title=Trang Sau +next_label=TiαΊΏp + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=trΓͺn {{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}} trΓͺn {{pagesCount}}) + +zoom_out.title=Thu nhỏ +zoom_out_label=Thu nhỏ +zoom_in.title=PhΓ³ng to +zoom_in_label=PhΓ³ng to +zoom.title=Chỉnh kΓ­ch thΖ°α»›c +presentation_mode.title=Chuyển sang chαΊΏ Δ‘α»™ trΓ¬nh chiαΊΏu +presentation_mode_label=ChαΊΏ Δ‘α»™ trΓ¬nh chiαΊΏu +open_file.title=Mở tαΊ­p tin +open_file_label=Mở tαΊ­p tin +print.title=In +print_label=In +download.title=TαΊ£i xuα»‘ng +download_label=TαΊ£i xuα»‘ng +bookmark.title=GΓ³c nhΓ¬n hiện tαΊ‘i (copy hoαΊ·c mở trong cα»­a sα»• mα»›i) +bookmark_label=ChαΊΏ Δ‘α»™ xem hiện tαΊ‘i + +# Secondary toolbar and context menu +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α»“ + + +# Document properties dialog box +document_properties.title=Thuα»™c tΓ­nh cα»§a tΓ i liệu… +document_properties_label=Thuα»™c tΓ­nh cα»§a tΓ i liệu… +document_properties_file_name=TΓͺn tαΊ­p tin: +document_properties_file_size=KΓ­ch thΖ°α»›c: +# 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}} byte) +# 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}} byte) +document_properties_title=TiΓͺu đề: +document_properties_author=TΓ‘c giαΊ£: +document_properties_subject=Chα»§ đề: +document_properties_keywords=Tα»« khΓ³a: +document_properties_creation_date=NgΓ y tαΊ‘o: +document_properties_modification_date=NgΓ y sα»­a Δ‘α»•i: +# 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=Người tαΊ‘o: +document_properties_producer=PhαΊ§n mềm tαΊ‘o PDF: +document_properties_version=PhiΓͺn bαΊ£n PDF: +document_properties_page_count=Tα»•ng sα»‘ trang: +document_properties_close=Ðóng + +print_progress_message=ChuαΊ©n bα»‹ trang để in… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% + +# 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=BαΊ­t/TαΊ―t thanh lề +toggle_sidebar_label=BαΊ­t/TαΊ―t thanh lề +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 +thumbs.title=Hiển thα»‹ αΊ£nh thu nhỏ +thumbs_label=αΊ’nh thu nhỏ +findbar.title=TΓ¬m trong tΓ i liệu +findbar_label=TΓ¬m + +# 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=Trang {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=αΊ’nh thu nhỏ cα»§a trang {{page}} + +# Find panel button title and messages +find_previous.title=TΓ¬m cα»₯m tα»« ở phαΊ§n trΖ°α»›c +find_previous_label=TrΖ°α»›c +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_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 +find_not_found=KhΓ΄ng tΓ¬m thαΊ₯y cα»₯m tα»« nΓ y + +# Error panel labels +error_more_info=ThΓ΄ng tin thΓͺm +error_less_info=Hiển thα»‹ Γ­t thΓ΄ng tin hΖ‘n +error_close=Đóng +# 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=ThΓ΄ng Δ‘iệp: {{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=TαΊ­p tin: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=DΓ²ng: {{line}} +rendering_error=Lα»—i khi hiển thα»‹ trang. + +# Predefined zoom values +page_scale_width=Vα»«a chiều rα»™ng +page_scale_fit=Vα»«a chiều cao +page_scale_auto=Tα»± Δ‘α»™ng chọn kΓ­ch thΖ°α»›c +page_scale_actual=KΓ­ch thΖ°α»›c thα»±c +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. +page_scale_percent={{scale}}% + +# Loading indicator messages +loading_error_indicator=Lα»—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. +unexpected_response_error=MΓ‘y chα»§ cΓ³ phαΊ£n hα»“i lαΊ‘. + +# 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}} ChΓΊ thΓ­ch] +password_label=NhαΊ­p mαΊ­t khαΊ©u để mở tαΊ­p tin PDF nΓ y. +password_invalid=MαΊ­t khαΊ©u khΓ΄ng Δ‘ΓΊng. Vui lΓ²ng thα»­ lαΊ‘i. +password_ok=OK + +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. +document_colors_not_allowed=TΓ i liệu PDF khΓ΄ng được cho phΓ©p dΓΉng mΓ u riΓͺng: 'Cho phΓ©p trang chọn mΓ u riΓͺng' Δ‘Γ£ bα»‹ tαΊ―t trΓͺn trΓ¬nh duyệt. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/wo/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/wo/viewer.properties new file mode 100755 index 00000000..8c999ad0 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/wo/viewer.properties @@ -0,0 +1,124 @@ +# 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=XΓ«t wi jiitu +previous_label=Bi jiitu +next.title=XΓ«t wi ci topp +next_label=Bi ci topp + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +zoom_out.title=WΓ Γ±Γ±i +zoom_out_label=WΓ Γ±Γ±i +zoom_in.title=Yaatal +zoom_in_label=Yaatal +zoom.title=YambalaΕ‹ +presentation_mode.title=WaΓ±arΓ±il ci anamu wone +presentation_mode_label=Anamu Wone +open_file.title=Ubbi benn dencukaay +open_file_label=Ubbi +print.title=MΓ³ol +print_label=MΓ³ol +download.title=Yeb yi +download_label=Yeb yi +bookmark.title=Wone bi taxaw (duppi walla ubbi palanteer bu bees) +bookmark_label=Wone bi feeΓ± + +# Secondary toolbar and context menu + + +# Document properties dialog box +# LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" +# will be replaced by the PDF file size in kilobytes, respectively in 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_title=Bopp: +# LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" +# will be replaced by the creation/modification date, and time, of the PDF file. + +# 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) +thumbs.title=Wone nataal yu ndaw yi +thumbs_label=Nataal yu ndaw yi +findbar.title=Gis ci biir jukki bi +findbar_label=Wut + +# 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=XΓ«t {{xΓ«t}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=WiΓ±et bu xΓ«t{{xΓ«t}} + +# Find panel button title and messages +find_previous.title=Seet beneen kaddu bu ni mel te jiitu +find_previous_label=Bi jiitu +find_next.title=Seet beneen kaddu bu ni mel +find_next_label=Bi ci topp +find_highlight=Melaxal lΓ©pp +find_match_case_label=SΓ mm jΓ«mmalin wi +find_reached_top=Jot naΓ±u ndorteel xΓ«t wi, kontine dale ko ci suuf +find_reached_bottom=Jot naΓ±u jeexitalu xΓ«t wi, kontine ci ndorte +find_not_found=GisiΓ±u kaddu gi + +# Error panel labels +error_more_info=Xibaar yu gΓ«n bari +error_less_info=Xibaar yu gΓ«n bari +# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be +# replaced by the PDF.JS version and build ID. +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Bataaxal: {{bataaxal}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Juug: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Dencukaay: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=RΓ«ddΒ : {{line}} +rendering_error=Am njumte bu am bi xΓ«t bi di wonewu. + +# Predefined zoom values +page_scale_width=Yaatuwaay bu mΓ«t +page_scale_fit=XΓ«t lΓ«mm +page_scale_auto=YambalaΕ‹ ci saa si +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. + +# 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=[Karmat {{type}}] +password_ok=OK +password_cancel=Neenal + +printing_not_supported=Artu: Joowkat bii nanguwul lool mool. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/xh/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/xh/viewer.properties new file mode 100755 index 00000000..1fa394bb --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/xh/viewer.properties @@ -0,0 +1,184 @@ +# 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=Iphepha langaphambili +previous_label=Okwangaphambili +next.title=Iphepha elilandelayo +next_label=Okulandelayo + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +page.title=Iphepha +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +of_pages=kwali- {{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}} kwali {{pagesCount}}) + +zoom_out.title=Bhekelisela Kudana +zoom_out_label=Bhekelisela Kudana +zoom_in.title=Sondeza Kufuphi +zoom_in_label=Sondeza Kufuphi +zoom.title=Yandisa / Nciphisa +presentation_mode.title=Tshintshela kwimo yonikezelo +presentation_mode_label=Imo yonikezelo +open_file.title=Vula Ifayile +open_file_label=Vula +print.title=Printa +print_label=Printa +download.title=Khuphela +download_label=Khuphela +bookmark.title=Imbonakalo ekhoyo (kopa okanye vula kwifestile entsha) +bookmark_label=Imbonakalo ekhoyo + +# Secondary toolbar and context menu +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 +cursor_text_select_tool_label=ISixhobo sokuKhetha iTeksti +cursor_hand_tool.title=Yenza iSixhobo seSandla siSebenze +cursor_hand_tool_label=ISixhobo seSandla + +# Document properties dialog box +document_properties.title=Iipropati zoxwebhu… +document_properties_label=Iipropati zoxwebhu… +document_properties_file_name=Igama lefayile: +document_properties_file_size=Isayizi yefayile: +# 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 (iibhayiti{{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 (iibhayithi{{size_b}}) +document_properties_title=Umxholo: +document_properties_author=Umbhali: +document_properties_subject=Umbandela: +document_properties_keywords=Amagama aphambili: +document_properties_creation_date=Umhla wokwenziwa kwayo: +document_properties_modification_date=Umhla wokulungiswa kwayo: +# 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=Umntu oyenzileyo: +document_properties_producer=Umvelisi we-PDF: +document_properties_version=Uhlelo lwe-PDF: +document_properties_page_count=Inani lamaphepha: +document_properties_close=Vala + +print_progress_message=Ilungisa uxwebhu ukuze iprinte… +# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by +# a numerical per cent value. +print_progress_percent={{progress}}% +print_progress_close=Rhoxisa + +# 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=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 +attachments.title=Bonisa iziqhotyoshelwa +attachments_label=Iziqhoboshelo +thumbs.title=Bonisa ukrobiso kumfanekiso +thumbs_label=Ukrobiso kumfanekiso +findbar.title=Fumana kuXwebhu +findbar_label=Fumana + +# 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=Iphepha {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Ukrobiso kumfanekiso wephepha {{page}} + +# Find panel button title and messages +find_input.title=Fumana +find_input.placeholder=Fumana kuXwebhu… +find_previous.title=Fumanisa isenzeko sangaphambili sebinzana lamagama +find_previous_label=Okwangaphambili +find_next.title=Fumanisa isenzeko esilandelayo sebinzana lamagama +find_next_label=Okulandelayo +find_highlight=Qaqambisa konke +find_match_case_label=Tshatisa ngobukhulu bukanobumba +find_reached_top=Ufike ngaphezulu ephepheni, kusukwa ngezantsi +find_reached_bottom=Ufike ekupheleni kwephepha, kusukwa ngaphezulu +find_not_found=Ibinzana alifunyenwanga + +# Error panel labels +error_more_info=Inkcazelo Engakumbi +error_less_info=Inkcazelo Encinane +error_close=Vala +# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be +# replaced by the PDF.JS version and build ID. +error_version_info=I-PDF.js v{{version}} (yakha: {{build}}) +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an +# english string describing the error. +error_message=Umyalezo: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Imfumba: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Ifayile: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Umgca: {{line}} +rendering_error=Imposiso yenzekile xa bekunikezelwa iphepha. + +# Predefined zoom values +page_scale_width=Ububanzi bephepha +page_scale_fit=Ukulinganiswa kwephepha +page_scale_auto=Ukwandisa/Ukunciphisa Ngokwayo +page_scale_actual=Ubungakanani bokwenene +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# 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. +unexpected_response_error=Impendulo yeseva engalindelekanga. + +# 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}} Ubhalo-nqaku] +password_label=Faka ipasiwedi ukuze uvule le fayile yePDF. +password_invalid=Ipasiwedi ayisebenzi. Nceda uzame kwakhona. +password_ok=KULUNGILE +password_cancel=Rhoxisa + +printing_not_supported=Isilumkiso: Ukuprinta akuxhaswa ngokupheleleyo yile bhrawuza. +printing_not_ready=Isilumkiso: IPDF ayihlohlwanga ngokupheleleyo ukwenzela ukuprinta. +web_fonts_disabled=Iifonti zewebhu ziqhwalelisiwe: ayikwazi ukusebenzisa iifonti ze-PDF ezincanyathelisiweyo. +document_colors_not_allowed=Amaxwebhu ePDF akavumelekanga ukuba asebenzise imibala yawo: 'Ukuvumela amaphepha ukuba asebenzise eyawo imibala' kuvaliwe ukuba kungasebenzi kwibhrawuza. diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/zh-CN/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/zh-CN/viewer.properties new file mode 100755 index 00000000..5140824c --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/zh-CN/viewer.properties @@ -0,0 +1,184 @@ +# 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=θ½¬εˆ°η¬¬δΈ€ι‘΅ +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_label=ζ–‡ζœ¬ι€‰ζ‹©ε·₯ε…· +cursor_hand_tool.title=启用手归ε·₯ε…· +cursor_hand_tool_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}} 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_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_notification.title=εˆ‡ζ’δΎ§ζ οΌˆζ–‡ζ‘£ζ‰€ε«ηš„ε€§ηΊ²/ι™„δ»ΆοΌ‰ +toggle_sidebar_label=εˆ‡ζ’δΎ§ζ  +document_outline.title=ζ˜Ύη€Ίζ–‡ζ‘£ε€§ηΊ²οΌˆεŒε‡»ε±•εΌ€/ζŠ˜ε ζ‰€ζœ‰ι‘ΉοΌ‰ +document_outline_label=ζ–‡ζ‘£ε€§ηΊ² +attachments.title=ζ˜Ύη€Ίι™„δ»Ά +attachments_label=ι™„δ»Ά +thumbs.title=显瀺缩η•₯ε›Ύ +thumbs_label=ηΌ©η•₯ε›Ύ +findbar.title=εœ¨ζ–‡ζ‘£δΈ­ζŸ₯ζ‰Ύ +findbar_label=ζŸ₯ζ‰Ύ + +# 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_reached_top=εˆ°θΎΎζ–‡ζ‘£εΌ€ε€΄οΌŒδ»Žζœ«ε°Ύη»§η»­ +find_reached_bottom=εˆ°θΎΎζ–‡ζ‘£ζœ«ε°ΎοΌŒδ»ŽεΌ€ε€΄η»§η»­ +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_indicator=ι”™θ―― +loading_error=θ½½ε…₯PDFζ—Άε‘η”Ÿι”™θ――γ€‚ +invalid_file_error=ζ— ζ•ˆζˆ–ζŸεηš„PDF文仢。 +missing_file_error=ηΌΊε°‘PDF文仢。 +unexpected_response_error=ζ„ε€–ηš„ζœεŠ‘ε™¨ε“εΊ”γ€‚ + +# 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=Web ε­—δ½“ε·²θ’«η¦η”¨οΌšζ— ζ³•δ½Ώη”¨ε΅Œε…₯ηš„PDF字体。 +document_colors_not_allowed=δΈε…θΈ PDF 文摣使用θ‡ͺε·±ηš„ι’œθ‰²οΌšζ΅θ§ˆε™¨δΈ­β€œε…θΈι‘΅ι’选择θ‡ͺε·±ηš„ι’œθ‰²β€ηš„ι€‰ι‘Ήε·²εœη”¨γ€‚ diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/zh-TW/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/zh-TW/viewer.properties new file mode 100755 index 00000000..67f64250 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/zh-TW/viewer.properties @@ -0,0 +1,184 @@ +# 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=θ·³εˆ°η¬¬δΈ€ι  +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_label=文字選擇ε·₯ε…· +cursor_hand_tool.title=ι–‹ε•Ÿι ι’η§»ε‹•ε·₯ε…· +cursor_hand_tool_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}} 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_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_notification.title=εˆ‡ζ›ε΄ι‚Šζ””οΌˆζ–‡δ»ΆεŒ…ε«ε€§ηΆ±ζˆ–ι™„δ»ΆοΌ‰ +toggle_sidebar_label=εˆ‡ζ›ε΄ι‚Šζ¬„ +document_outline.title=ι‘―η€Ίζ–‡δ»Άε€§ηΆ±οΌˆι›™ζ“Šε±•ι–‹/ζ‘Ίη–Šζ‰€ζœ‰ι …η›οΌ‰ +document_outline_label=ζ–‡δ»Άε€§ηΆ± +attachments.title=ι‘―η€Ίι™„δ»Ά +attachments_label=ι™„δ»Ά +thumbs.title=ι‘―η€ΊηΈεœ– +thumbs_label=ηΈεœ– +findbar.title=εœ¨ζ–‡δ»ΆδΈ­ε°‹ζ‰Ύ +findbar_label=ε°‹ζ‰Ύ + +# 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_reached_top=ε·²ζœε°‹θ‡³ζ–‡δ»Άι ‚η«―οΌŒθ‡ͺεΊ•η«―ηΉΌηΊŒζœε°‹ +find_reached_bottom=ε·²ζœε°‹θ‡³ζ–‡δ»ΆεΊ•η«―οΌŒθ‡ͺι ‚η«―ηΉΌηΊŒζœε°‹ +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_indicator=錯θͺ€ +loading_error=θΌ‰ε…₯ PDF ζ™‚η™Όη”ŸιŒ―θͺ€γ€‚ +invalid_file_error=η„‘ζ•ˆζˆ–ζ―€ζηš„ PDF ζͺ”ζ‘ˆγ€‚ +missing_file_error=ζ‰ΎδΈεˆ° PDF ζͺ”ζ‘ˆγ€‚ +unexpected_response_error=δΌΊζœε™¨ε›žζ‡‰ζœͺι ζœŸηš„ε…§εΉγ€‚ + +# 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=ε·²εœη”¨ηΆ²θ·―ε­—εž‹ (Web fonts): 焑法使用 PDF ε…§ε΅Œε­—εž‹γ€‚ +document_colors_not_allowed=η€θ¦½ε™¨ηš„γ€Œε„ͺε…ˆδ½Ώη”¨ηΆ²ι ζŒ‡εšηš„色彩」ζœͺθ’«ε‹ΎιΈοΌŒPDF 文仢焑法使用θ‡ͺε·±ηš„θ‰²ε½©γ€‚ diff --git a/twake/frontend/public/public/viewer/PDFViewer/locale/zu/viewer.properties b/twake/frontend/public/public/viewer/PDFViewer/locale/zu/viewer.properties new file mode 100755 index 00000000..8fc77f28 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/locale/zu/viewer.properties @@ -0,0 +1,131 @@ +# 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=Ikhasi eledlule +previous_label=Okudlule +next.title=Ikhasi elilandelayo +next_label=Okulandelayo + +# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. +# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number +# representing the total number of pages in the document. +# 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. + +zoom_out.title=Hlehlisela emuva +zoom_out_label=Hlehlisela emuva +zoom_in.title=Sondeza eduze +zoom_in_label=Sondeza eduze +zoom.title=Lwiza +presentation_mode.title=Guqulela kwindlela yesethulo +presentation_mode_label=Indlelo yesethulo +open_file.title=Vula ifayela +open_file_label=Vula +print.title=Phrinta +print_label=Phrinta +download.title=Landa +download_label=Landa +bookmark.title=Ukubuka kwamanje (kopisha noma vula kwifasitela elisha) +bookmark_label=Ukubuka kwamanje + +# Secondary toolbar and context menu + + +# Document properties dialog box +document_properties_file_name=Igama lefayela: +# LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" +# will be replaced by the PDF file size in kilobytes, respectively in 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_title=Isihloko: +# LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" +# will be replaced by the creation/modification date, and time, of the PDF file. + +# 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) +toggle_sidebar.title=I-toggle yebha yaseceleni +toggle_sidebar_label=i-toggle yebha yaseceleni +document_outline_label=Umugqa waseceleni wedokhumenti +thumbs.title=Bonisa izithombe ezincane +thumbs_label=Izithonjana +findbar.title=Thola kwidokhumenti + +# 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=Ikhasi {{page}} +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page +# number. +thumb_page_canvas=Isithonjana sekhasi {{page}} + +# Find panel button title and messages +find_previous.title=Thola indawo eyandulelayo okuvela kuyo lomshwana +find_previous_label=Okudlulile +find_next.title=Thola enye indawo okuvela kuyo lomshwana +find_next_label=Okulandelayo +find_highlight=Gqamisa konke +find_match_case_label=Fanisa ikheyisi +find_reached_top=Finyelele phezulu kwidokhumenti, qhubeka kusukaphansi +find_reached_bottom=Ifinyelele ekupheleni kwedokhumenti, qhubeka kusukaphezulu +find_not_found=Umshwana awutholakali + +# Error panel labels +error_more_info=Ukwaziswa Okwengeziwe +error_less_info=Ukwazi okuncane +# 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=Umlayezo: {{message}} +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack +# trace. +error_stack=Isitaki: {{stack}} +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename +error_file=Ifayela: {{file}} +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number +error_line=Umugqa: {{line}} +rendering_error=Iphutha lenzekile uma kunikwa ikhasi. + +# Predefined zoom values +page_scale_width=Ububanzi bekhasi +page_scale_fit=Ukulingana kwekhasi +page_scale_auto=Ukulwiza okuzenzekalelayo +page_scale_actual=Usayizi Wangempela +# LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a +# numerical scale value. + +# Loading indicator messages +loading_error_indicator=Iphutha +loading_error=Kwenzeke iphutha uma kulayishwa i-PDF. +invalid_file_error=Ifayela le-PDF elingavumelekile noma elonakele. +missing_file_error=Ifayela le-PDF elilahlekile. + +# 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=[Amazwibela e-{{type}}] +password_ok=Kulungile + +printing_not_supported=Isixwayiso: Ukuphrinta akuxhasiwe yilesisiphequluli ngokugcwele. +printing_not_ready=Isixwayiso: I-PDF ayikalayishwa ngokuphelele yiPhrinta. +web_fonts_disabled=Amafonti e-webhu akutshaziwe: ayikwazi ukusebenzisa amafonti abekiwe e-PDF.\u0020 +document_colors_not_allowed=Amadokhumenti we-PDF awavumelekile ukusebenzisa imibalo yayo: 'Vumela amakhasi ukukhetha imibala yayo' ayisebenzi kusiphequluli. diff --git a/twake/frontend/public/public/viewer/PDFViewer/pdf.js b/twake/frontend/public/public/viewer/PDFViewer/pdf.js new file mode 100755 index 00000000..f9b9f821 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/pdf.js @@ -0,0 +1,14498 @@ +/* Copyright 2017 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. + */ + +(function webpackUniversalModuleDefinition(root, factory) { + if (typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if (typeof define === 'function' && define.amd) + define("pdfjs-dist/build/pdf", [], factory); + else if (typeof exports === 'object') + exports["pdfjs-dist/build/pdf"] = factory(); + else + root["pdfjs-dist/build/pdf"] = root.pdfjsDistBuildPdf = 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; + /******/ + /******/ // identity function for calling harmony imports with the correct context + /******/ + __w_pdfjs_require__.i = function (value) { + return value; + }; + /******/ + /******/ // 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, { + /******/ configurable: false, + /******/ enumerable: true, + /******/ get: getter + /******/ + }); + /******/ + } + /******/ + }; + /******/ + /******/ // 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 = 15); + /******/ + }) + /************************************************************************/ + /******/([ + /* 0 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.loadJpegStream = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isNodeJS = exports.isSpace = exports.isString = exports.isNum = exports.isInt = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.isArray = exports.info = exports.globalScope = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.createBlob = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.StatTimer = exports.PasswordResponses = exports.PasswordException = exports.PageViewport = exports.NotImplementedException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.MessageHandler = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VERBOSITY_LEVELS = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined; + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + __w_pdfjs_require__(16); + + var _streams_polyfill = __w_pdfjs_require__(17); + + var globalScope = typeof window !== 'undefined' && window.Math === Math ? window : typeof global !== 'undefined' && global.Math === Math ? global : typeof self !== 'undefined' && self.Math === Math ? self : undefined; + var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0]; + var NativeImageDecoding = { + NONE: 'none', + DECODE: 'decode', + DISPLAY: 'display' + }; + var TextRenderingMode = { + FILL: 0, + STROKE: 1, + FILL_STROKE: 2, + INVISIBLE: 3, + FILL_ADD_TO_PATH: 4, + STROKE_ADD_TO_PATH: 5, + FILL_STROKE_ADD_TO_PATH: 6, + ADD_TO_PATH: 7, + FILL_STROKE_MASK: 3, + ADD_TO_PATH_FLAG: 4 + }; + var ImageKind = { + GRAYSCALE_1BPP: 1, + RGB_24BPP: 2, + RGBA_32BPP: 3 + }; + var AnnotationType = { + TEXT: 1, + LINK: 2, + FREETEXT: 3, + LINE: 4, + SQUARE: 5, + CIRCLE: 6, + POLYGON: 7, + POLYLINE: 8, + HIGHLIGHT: 9, + UNDERLINE: 10, + SQUIGGLY: 11, + STRIKEOUT: 12, + STAMP: 13, + CARET: 14, + INK: 15, + POPUP: 16, + FILEATTACHMENT: 17, + SOUND: 18, + MOVIE: 19, + WIDGET: 20, + SCREEN: 21, + PRINTERMARK: 22, + TRAPNET: 23, + WATERMARK: 24, + THREED: 25, + REDACT: 26 + }; + var AnnotationFlag = { + INVISIBLE: 0x01, + HIDDEN: 0x02, + PRINT: 0x04, + NOZOOM: 0x08, + NOROTATE: 0x10, + NOVIEW: 0x20, + READONLY: 0x40, + LOCKED: 0x80, + TOGGLENOVIEW: 0x100, + LOCKEDCONTENTS: 0x200 + }; + var AnnotationFieldFlag = { + READONLY: 0x0000001, + REQUIRED: 0x0000002, + NOEXPORT: 0x0000004, + MULTILINE: 0x0001000, + PASSWORD: 0x0002000, + NOTOGGLETOOFF: 0x0004000, + RADIO: 0x0008000, + PUSHBUTTON: 0x0010000, + COMBO: 0x0020000, + EDIT: 0x0040000, + SORT: 0x0080000, + FILESELECT: 0x0100000, + MULTISELECT: 0x0200000, + DONOTSPELLCHECK: 0x0400000, + DONOTSCROLL: 0x0800000, + COMB: 0x1000000, + RICHTEXT: 0x2000000, + RADIOSINUNISON: 0x2000000, + COMMITONSELCHANGE: 0x4000000 + }; + var AnnotationBorderStyleType = { + SOLID: 1, + DASHED: 2, + BEVELED: 3, + INSET: 4, + UNDERLINE: 5 + }; + var StreamType = { + UNKNOWN: 0, + FLATE: 1, + LZW: 2, + DCT: 3, + JPX: 4, + JBIG: 5, + A85: 6, + AHX: 7, + CCF: 8, + RL: 9 + }; + var FontType = { + UNKNOWN: 0, + TYPE1: 1, + TYPE1C: 2, + CIDFONTTYPE0: 3, + CIDFONTTYPE0C: 4, + TRUETYPE: 5, + CIDFONTTYPE2: 6, + TYPE3: 7, + OPENTYPE: 8, + TYPE0: 9, + MMTYPE1: 10 + }; + var VERBOSITY_LEVELS = { + errors: 0, + warnings: 1, + infos: 5 + }; + var CMapCompressionType = { + NONE: 0, + BINARY: 1, + STREAM: 2 + }; + var OPS = { + dependency: 1, + setLineWidth: 2, + setLineCap: 3, + setLineJoin: 4, + setMiterLimit: 5, + setDash: 6, + setRenderingIntent: 7, + setFlatness: 8, + setGState: 9, + save: 10, + restore: 11, + transform: 12, + moveTo: 13, + lineTo: 14, + curveTo: 15, + curveTo2: 16, + curveTo3: 17, + closePath: 18, + rectangle: 19, + stroke: 20, + closeStroke: 21, + fill: 22, + eoFill: 23, + fillStroke: 24, + eoFillStroke: 25, + closeFillStroke: 26, + closeEOFillStroke: 27, + endPath: 28, + clip: 29, + eoClip: 30, + beginText: 31, + endText: 32, + setCharSpacing: 33, + setWordSpacing: 34, + setHScale: 35, + setLeading: 36, + setFont: 37, + setTextRenderingMode: 38, + setTextRise: 39, + moveText: 40, + setLeadingMoveText: 41, + setTextMatrix: 42, + nextLine: 43, + showText: 44, + showSpacedText: 45, + nextLineShowText: 46, + nextLineSetSpacingShowText: 47, + setCharWidth: 48, + setCharWidthAndBounds: 49, + setStrokeColorSpace: 50, + setFillColorSpace: 51, + setStrokeColor: 52, + setStrokeColorN: 53, + setFillColor: 54, + setFillColorN: 55, + setStrokeGray: 56, + setFillGray: 57, + setStrokeRGBColor: 58, + setFillRGBColor: 59, + setStrokeCMYKColor: 60, + setFillCMYKColor: 61, + shadingFill: 62, + beginInlineImage: 63, + beginImageData: 64, + endInlineImage: 65, + paintXObject: 66, + markPoint: 67, + markPointProps: 68, + beginMarkedContent: 69, + beginMarkedContentProps: 70, + endMarkedContent: 71, + beginCompat: 72, + endCompat: 73, + paintFormXObjectBegin: 74, + paintFormXObjectEnd: 75, + beginGroup: 76, + endGroup: 77, + beginAnnotations: 78, + endAnnotations: 79, + beginAnnotation: 80, + endAnnotation: 81, + paintJpegXObject: 82, + paintImageMaskXObject: 83, + paintImageMaskXObjectGroup: 84, + paintImageXObject: 85, + paintInlineImageXObject: 86, + paintInlineImageXObjectGroup: 87, + paintImageXObjectRepeat: 88, + paintImageMaskXObjectRepeat: 89, + paintSolidColorImageMask: 90, + constructPath: 91 + }; + var verbosity = VERBOSITY_LEVELS.warnings; + + function setVerbosityLevel(level) { + verbosity = level; + } + + function getVerbosityLevel() { + return verbosity; + } + + function info(msg) { + if (verbosity >= VERBOSITY_LEVELS.infos) { + console.log('Info: ' + msg); + } + } + + function warn(msg) { + if (verbosity >= VERBOSITY_LEVELS.warnings) { + console.log('Warning: ' + msg); + } + } + + function deprecated(details) { + console.log('Deprecated API usage: ' + details); + } + + function unreachable(msg) { + throw new Error(msg); + } + + function assert(cond, msg) { + if (!cond) { + unreachable(msg); + } + } + + var UNSUPPORTED_FEATURES = { + unknown: 'unknown', + forms: 'forms', + javaScript: 'javaScript', + smask: 'smask', + shadingPattern: 'shadingPattern', + font: 'font' + }; + + function isSameOrigin(baseUrl, otherUrl) { + try { + var base = new URL(baseUrl); + if (!base.origin || base.origin === 'null') { + return false; + } + } catch (e) { + return false; + } + var other = new URL(otherUrl, base); + return base.origin === other.origin; + } + + function isValidProtocol(url) { + if (!url) { + return false; + } + switch (url.protocol) { + case 'http:': + case 'https:': + case 'ftp:': + case 'mailto:': + case 'tel:': + return true; + default: + return false; + } + } + + function createValidAbsoluteUrl(url, baseUrl) { + if (!url) { + return null; + } + try { + var absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url); + if (isValidProtocol(absoluteUrl)) { + return absoluteUrl; + } + } catch (ex) { + } + return null; + } + + function shadow(obj, prop, value) { + Object.defineProperty(obj, prop, { + value: value, + enumerable: true, + configurable: true, + writable: false + }); + return value; + } + + function getLookupTableFactory(initializer) { + var lookup; + return function () { + if (initializer) { + lookup = Object.create(null); + initializer(lookup); + initializer = null; + } + return lookup; + }; + } + + var PasswordResponses = { + NEED_PASSWORD: 1, + INCORRECT_PASSWORD: 2 + }; + var PasswordException = function PasswordExceptionClosure() { + function PasswordException(msg, code) { + this.name = 'PasswordException'; + this.message = msg; + this.code = code; + } + + PasswordException.prototype = new Error(); + PasswordException.constructor = PasswordException; + return PasswordException; + }(); + var UnknownErrorException = function UnknownErrorExceptionClosure() { + function UnknownErrorException(msg, details) { + this.name = 'UnknownErrorException'; + this.message = msg; + this.details = details; + } + + UnknownErrorException.prototype = new Error(); + UnknownErrorException.constructor = UnknownErrorException; + return UnknownErrorException; + }(); + var InvalidPDFException = function InvalidPDFExceptionClosure() { + function InvalidPDFException(msg) { + this.name = 'InvalidPDFException'; + this.message = msg; + } + + InvalidPDFException.prototype = new Error(); + InvalidPDFException.constructor = InvalidPDFException; + return InvalidPDFException; + }(); + var MissingPDFException = function MissingPDFExceptionClosure() { + function MissingPDFException(msg) { + this.name = 'MissingPDFException'; + this.message = msg; + } + + MissingPDFException.prototype = new Error(); + MissingPDFException.constructor = MissingPDFException; + return MissingPDFException; + }(); + var UnexpectedResponseException = function UnexpectedResponseExceptionClosure() { + function UnexpectedResponseException(msg, status) { + this.name = 'UnexpectedResponseException'; + this.message = msg; + this.status = status; + } + + UnexpectedResponseException.prototype = new Error(); + UnexpectedResponseException.constructor = UnexpectedResponseException; + return UnexpectedResponseException; + }(); + var NotImplementedException = function NotImplementedExceptionClosure() { + function NotImplementedException(msg) { + this.message = msg; + } + + NotImplementedException.prototype = new Error(); + NotImplementedException.prototype.name = 'NotImplementedException'; + NotImplementedException.constructor = NotImplementedException; + return NotImplementedException; + }(); + var MissingDataException = function MissingDataExceptionClosure() { + function MissingDataException(begin, end) { + this.begin = begin; + this.end = end; + this.message = 'Missing data [' + begin + ', ' + end + ')'; + } + + MissingDataException.prototype = new Error(); + MissingDataException.prototype.name = 'MissingDataException'; + MissingDataException.constructor = MissingDataException; + return MissingDataException; + }(); + var XRefParseException = function XRefParseExceptionClosure() { + function XRefParseException(msg) { + this.message = msg; + } + + XRefParseException.prototype = new Error(); + XRefParseException.prototype.name = 'XRefParseException'; + XRefParseException.constructor = XRefParseException; + return XRefParseException; + }(); + var FormatError = function FormatErrorClosure() { + function FormatError(msg) { + this.message = msg; + } + + FormatError.prototype = new Error(); + FormatError.prototype.name = 'FormatError'; + FormatError.constructor = FormatError; + return FormatError; + }(); + var AbortException = function AbortExceptionClosure() { + function AbortException(msg) { + this.name = 'AbortException'; + this.message = msg; + } + + AbortException.prototype = new Error(); + AbortException.constructor = AbortException; + return AbortException; + }(); + var NullCharactersRegExp = /\x00/g; + + function removeNullCharacters(str) { + if (typeof str !== 'string') { + warn('The argument for removeNullCharacters must be a string.'); + return str; + } + return str.replace(NullCharactersRegExp, ''); + } + + function bytesToString(bytes) { + assert(bytes !== null && (typeof bytes === 'undefined' ? 'undefined' : _typeof(bytes)) === 'object' && bytes.length !== undefined, 'Invalid argument for bytesToString'); + var length = bytes.length; + var MAX_ARGUMENT_COUNT = 8192; + if (length < MAX_ARGUMENT_COUNT) { + return String.fromCharCode.apply(null, bytes); + } + var strBuf = []; + for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) { + var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length); + var chunk = bytes.subarray(i, chunkEnd); + strBuf.push(String.fromCharCode.apply(null, chunk)); + } + return strBuf.join(''); + } + + function stringToBytes(str) { + assert(typeof str === 'string', 'Invalid argument for stringToBytes'); + var length = str.length; + var bytes = new Uint8Array(length); + for (var i = 0; i < length; ++i) { + bytes[i] = str.charCodeAt(i) & 0xFF; + } + return bytes; + } + + function arrayByteLength(arr) { + if (arr.length !== undefined) { + return arr.length; + } + assert(arr.byteLength !== undefined); + return arr.byteLength; + } + + function arraysToBytes(arr) { + if (arr.length === 1 && arr[0] instanceof Uint8Array) { + return arr[0]; + } + var resultLength = 0; + var i, + ii = arr.length; + var item, itemLength; + for (i = 0; i < ii; i++) { + item = arr[i]; + itemLength = arrayByteLength(item); + resultLength += itemLength; + } + var pos = 0; + var data = new Uint8Array(resultLength); + for (i = 0; i < ii; i++) { + item = arr[i]; + if (!(item instanceof Uint8Array)) { + if (typeof item === 'string') { + item = stringToBytes(item); + } else { + item = new Uint8Array(item); + } + } + itemLength = item.byteLength; + data.set(item, pos); + pos += itemLength; + } + return data; + } + + function string32(value) { + return String.fromCharCode(value >> 24 & 0xff, value >> 16 & 0xff, value >> 8 & 0xff, value & 0xff); + } + + function log2(x) { + var n = 1, + i = 0; + while (x > n) { + n <<= 1; + i++; + } + return i; + } + + function readInt8(data, start) { + return data[start] << 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 isLittleEndian() { + var buffer8 = new Uint8Array(4); + buffer8[0] = 1; + var view32 = new Uint32Array(buffer8.buffer, 0, 1); + return view32[0] === 1; + } + + function isEvalSupported() { + try { + new Function(''); + return true; + } catch (e) { + return false; + } + } + + var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0]; + var Util = function UtilClosure() { + function Util() { + } + + var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')']; + Util.makeCssRgb = function Util_makeCssRgb(r, g, b) { + rgbBuf[1] = r; + rgbBuf[3] = g; + rgbBuf[5] = b; + return rgbBuf.join(''); + }; + Util.transform = function Util_transform(m1, m2) { + return [m1[0] * m2[0] + m1[2] * m2[1], m1[1] * m2[0] + m1[3] * m2[1], m1[0] * m2[2] + m1[2] * m2[3], m1[1] * m2[2] + m1[3] * m2[3], m1[0] * m2[4] + m1[2] * m2[5] + m1[4], m1[1] * m2[4] + m1[3] * m2[5] + m1[5]]; + }; + Util.applyTransform = function Util_applyTransform(p, m) { + var xt = p[0] * m[0] + p[1] * m[2] + m[4]; + var yt = p[0] * m[1] + p[1] * m[3] + m[5]; + return [xt, yt]; + }; + Util.applyInverseTransform = function Util_applyInverseTransform(p, m) { + var d = m[0] * m[3] - m[1] * m[2]; + var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d; + var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d; + return [xt, yt]; + }; + Util.getAxialAlignedBoundingBox = function Util_getAxialAlignedBoundingBox(r, m) { + var p1 = Util.applyTransform(r, m); + var p2 = Util.applyTransform(r.slice(2, 4), m); + var p3 = Util.applyTransform([r[0], r[3]], m); + var p4 = Util.applyTransform([r[2], r[1]], m); + return [Math.min(p1[0], p2[0], p3[0], p4[0]), Math.min(p1[1], p2[1], p3[1], p4[1]), Math.max(p1[0], p2[0], p3[0], p4[0]), Math.max(p1[1], p2[1], p3[1], p4[1])]; + }; + Util.inverseTransform = function Util_inverseTransform(m) { + var d = m[0] * m[3] - m[1] * m[2]; + return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d, (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d]; + }; + Util.apply3dTransform = function Util_apply3dTransform(m, v) { + return [m[0] * v[0] + m[1] * v[1] + m[2] * v[2], m[3] * v[0] + m[4] * v[1] + m[5] * v[2], m[6] * v[0] + m[7] * v[1] + m[8] * v[2]]; + }; + Util.singularValueDecompose2dScale = function Util_singularValueDecompose2dScale(m) { + var transpose = [m[0], m[2], m[1], m[3]]; + var a = m[0] * transpose[0] + m[1] * transpose[2]; + var b = m[0] * transpose[1] + m[1] * transpose[3]; + var c = m[2] * transpose[0] + m[3] * transpose[2]; + var d = m[2] * transpose[1] + m[3] * transpose[3]; + var first = (a + d) / 2; + var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2; + var sx = first + second || 1; + var sy = first - second || 1; + return [Math.sqrt(sx), Math.sqrt(sy)]; + }; + Util.normalizeRect = function Util_normalizeRect(rect) { + var r = rect.slice(0); + if (rect[0] > rect[2]) { + r[0] = rect[2]; + r[2] = rect[0]; + } + if (rect[1] > rect[3]) { + r[1] = rect[3]; + r[3] = rect[1]; + } + return r; + }; + Util.intersect = function Util_intersect(rect1, rect2) { + function compare(a, b) { + return a - b; + } + + var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare), + orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare), + 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 { + return false; + } + 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 { + return false; + } + return result; + }; + Util.sign = function Util_sign(num) { + return num < 0 ? -1 : 1; + }; + var 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']; + Util.toRoman = function Util_toRoman(number, lowerCase) { + assert(isInt(number) && number > 0, 'The number should be a positive integer.'); + var pos, + romanBuf = []; + 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]); + var romanStr = romanBuf.join(''); + return lowerCase ? romanStr.toLowerCase() : romanStr; + }; + Util.appendToArray = function Util_appendToArray(arr1, arr2) { + Array.prototype.push.apply(arr1, arr2); + }; + Util.prependToArray = function Util_prependToArray(arr1, arr2) { + Array.prototype.unshift.apply(arr1, arr2); + }; + Util.extendObj = function extendObj(obj1, obj2) { + for (var key in obj2) { + obj1[key] = obj2[key]; + } + }; + Util.getInheritableProperty = function Util_getInheritableProperty(dict, name, getArray) { + while (dict && !dict.has(name)) { + dict = dict.get('Parent'); + } + if (!dict) { + return null; + } + return getArray ? dict.getArray(name) : dict.get(name); + }; + Util.inherit = function Util_inherit(sub, base, prototype) { + sub.prototype = Object.create(base.prototype); + sub.prototype.constructor = sub; + for (var prop in prototype) { + sub.prototype[prop] = prototype[prop]; + } + }; + Util.loadScript = function Util_loadScript(src, callback) { + var script = document.createElement('script'); + var loaded = false; + script.setAttribute('src', src); + if (callback) { + script.onload = function () { + if (!loaded) { + callback(); + } + loaded = true; + }; + } + document.getElementsByTagName('head')[0].appendChild(script); + }; + return Util; + }(); + var PageViewport = function PageViewportClosure() { + function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) { + this.viewBox = viewBox; + this.scale = scale; + this.rotation = rotation; + this.offsetX = offsetX; + this.offsetY = offsetY; + var centerX = (viewBox[2] + viewBox[0]) / 2; + var centerY = (viewBox[3] + viewBox[1]) / 2; + var 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; + default: + rotateA = 1; + rotateB = 0; + rotateC = 0; + rotateD = -1; + break; + } + if (dontFlip) { + rotateC = -rotateC; + rotateD = -rotateD; + } + var offsetCanvasX, offsetCanvasY; + var 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; + this.fontScale = scale; + } + + PageViewport.prototype = { + clone: function PageViewPort_clone(args) { + args = args || {}; + var scale = 'scale' in args ? args.scale : this.scale; + var rotation = 'rotation' in args ? args.rotation : this.rotation; + return new PageViewport(this.viewBox.slice(), scale, rotation, this.offsetX, this.offsetY, args.dontFlip); + }, + convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) { + return Util.applyTransform([x, y], this.transform); + }, + convertToViewportRectangle: function PageViewport_convertToViewportRectangle(rect) { + var tl = Util.applyTransform([rect[0], rect[1]], this.transform); + var br = Util.applyTransform([rect[2], rect[3]], this.transform); + return [tl[0], tl[1], br[0], br[1]]; + }, + convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) { + return Util.applyInverseTransform([x, y], this.transform); + } + }; + return PageViewport; + }(); + var 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) { + var i, + n = str.length, + strBuf = []; + if (str[0] === '\xFE' && str[1] === '\xFF') { + for (i = 2; i < n; i += 2) { + strBuf.push(String.fromCharCode(str.charCodeAt(i) << 8 | str.charCodeAt(i + 1))); + } + } else { + for (i = 0; i < n; ++i) { + var code = PDFStringTranslateTable[str.charCodeAt(i)]; + strBuf.push(code ? String.fromCharCode(code) : str.charAt(i)); + } + } + return strBuf.join(''); + } + + function stringToUTF8String(str) { + return decodeURIComponent(escape(str)); + } + + function utf8StringToString(str) { + return unescape(encodeURIComponent(str)); + } + + function isEmptyObj(obj) { + for (var key in obj) { + return false; + } + return true; + } + + function isBool(v) { + return typeof v === 'boolean'; + } + + function isInt(v) { + return typeof v === 'number' && (v | 0) === v; + } + + function isNum(v) { + return typeof v === 'number'; + } + + function isString(v) { + return typeof v === 'string'; + } + + function isArray(v) { + return v instanceof Array; + } + + function isArrayBuffer(v) { + return (typeof v === 'undefined' ? 'undefined' : _typeof(v)) === 'object' && v !== null && v.byteLength !== undefined; + } + + function isSpace(ch) { + return ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A; + } + + function isNodeJS() { + return (typeof process === 'undefined' ? 'undefined' : _typeof(process)) === 'object' && process + '' === '[object process]'; + } + + function createPromiseCapability() { + var capability = {}; + capability.promise = new Promise(function (resolve, reject) { + capability.resolve = resolve; + capability.reject = reject; + }); + return capability; + } + + var StatTimer = function StatTimerClosure() { + function rpad(str, pad, length) { + while (str.length < length) { + str += pad; + } + return str; + } + + function StatTimer() { + this.started = Object.create(null); + this.times = []; + this.enabled = true; + } + + StatTimer.prototype = { + time: function StatTimer_time(name) { + if (!this.enabled) { + return; + } + if (name in this.started) { + warn('Timer is already running for ' + name); + } + this.started[name] = Date.now(); + }, + timeEnd: function StatTimer_timeEnd(name) { + if (!this.enabled) { + return; + } + if (!(name in this.started)) { + warn('Timer has not been started for ' + name); + } + this.times.push({ + 'name': name, + 'start': this.started[name], + 'end': Date.now() + }); + delete this.started[name]; + }, + toString: function StatTimer_toString() { + var i, ii; + var times = this.times; + var out = ''; + var longest = 0; + for (i = 0, ii = times.length; i < ii; ++i) { + var name = times[i]['name']; + if (name.length > longest) { + longest = name.length; + } + } + for (i = 0, ii = times.length; i < ii; ++i) { + var span = times[i]; + var duration = span.end - span.start; + out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n'; + } + return out; + } + }; + return StatTimer; + }(); + var createBlob = function createBlob(data, contentType) { + if (typeof Blob !== 'undefined') { + return new Blob([data], {type: contentType}); + } + throw new Error('The "Blob" constructor is not supported.'); + }; + var createObjectURL = function createObjectURLClosure() { + var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + return function createObjectURL(data, contentType) { + var forceDataSchema = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + + if (!forceDataSchema && URL.createObjectURL) { + var blob = createBlob(data, contentType); + return URL.createObjectURL(blob); + } + var buffer = 'data:' + contentType + ';base64,'; + for (var i = 0, ii = data.length; i < ii; i += 3) { + var b1 = data[i] & 0xFF; + var b2 = data[i + 1] & 0xFF; + var b3 = data[i + 2] & 0xFF; + var d1 = b1 >> 2, + d2 = (b1 & 3) << 4 | b2 >> 4; + var d3 = i + 1 < ii ? (b2 & 0xF) << 2 | b3 >> 6 : 64; + var d4 = i + 2 < ii ? b3 & 0x3F : 64; + buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4]; + } + return buffer; + }; + }(); + + function resolveCall(fn, args) { + var thisArg = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + + if (!fn) { + return Promise.resolve(undefined); + } + return new Promise(function (resolve, reject) { + resolve(fn.apply(thisArg, args)); + }); + } + + function wrapReason(reason) { + if ((typeof reason === 'undefined' ? 'undefined' : _typeof(reason)) !== 'object') { + return reason; + } + switch (reason.name) { + case 'AbortException': + return new AbortException(reason.message); + case 'MissingPDFException': + return new MissingPDFException(reason.message); + case 'UnexpectedResponseException': + return new UnexpectedResponseException(reason.message, reason.status); + default: + return new UnknownErrorException(reason.message, reason.details); + } + } + + function resolveOrReject(capability, success, reason) { + if (success) { + capability.resolve(); + } else { + capability.reject(reason); + } + } + + function finalize(promise) { + return Promise.resolve(promise).catch(function () { + }); + } + + function MessageHandler(sourceName, targetName, comObj) { + var _this = this; + + this.sourceName = sourceName; + this.targetName = targetName; + this.comObj = comObj; + this.callbackId = 1; + this.streamId = 1; + this.postMessageTransfers = true; + this.streamSinks = Object.create(null); + this.streamControllers = Object.create(null); + var callbacksCapabilities = this.callbacksCapabilities = Object.create(null); + var ah = this.actionHandler = Object.create(null); + this._onComObjOnMessage = function (event) { + var data = event.data; + if (data.targetName !== _this.sourceName) { + return; + } + if (data.stream) { + _this._processStreamMessage(data); + } else if (data.isReply) { + var callbackId = data.callbackId; + if (data.callbackId in callbacksCapabilities) { + var callback = callbacksCapabilities[callbackId]; + delete callbacksCapabilities[callbackId]; + if ('error' in data) { + callback.reject(wrapReason(data.error)); + } else { + callback.resolve(data.data); + } + } else { + throw new Error('Cannot resolve callback ' + callbackId); + } + } else if (data.action in ah) { + var action = ah[data.action]; + if (data.callbackId) { + var _sourceName = _this.sourceName; + var _targetName = data.sourceName; + Promise.resolve().then(function () { + return action[0].call(action[1], data.data); + }).then(function (result) { + comObj.postMessage({ + sourceName: _sourceName, + targetName: _targetName, + isReply: true, + callbackId: data.callbackId, + data: result + }); + }, function (reason) { + if (reason instanceof Error) { + reason = reason + ''; + } + comObj.postMessage({ + sourceName: _sourceName, + targetName: _targetName, + isReply: true, + callbackId: data.callbackId, + error: reason + }); + }); + } else if (data.streamId) { + _this._createStreamSink(data); + } else { + action[0].call(action[1], data.data); + } + } else { + throw new Error('Unknown action from worker: ' + data.action); + } + }; + comObj.addEventListener('message', this._onComObjOnMessage); + } + + MessageHandler.prototype = { + on: function on(actionName, handler, scope) { + var ah = this.actionHandler; + if (ah[actionName]) { + throw new Error('There is already an actionName called "' + actionName + '"'); + } + ah[actionName] = [handler, scope]; + }, + send: function send(actionName, data, transfers) { + var message = { + sourceName: this.sourceName, + targetName: this.targetName, + action: actionName, + data: data + }; + this.postMessage(message, transfers); + }, + sendWithPromise: function sendWithPromise(actionName, data, transfers) { + var callbackId = this.callbackId++; + var message = { + sourceName: this.sourceName, + targetName: this.targetName, + action: actionName, + data: data, + callbackId: callbackId + }; + var capability = createPromiseCapability(); + this.callbacksCapabilities[callbackId] = capability; + try { + this.postMessage(message, transfers); + } catch (e) { + capability.reject(e); + } + return capability.promise; + }, + sendWithStream: function sendWithStream(actionName, data, queueingStrategy, transfers) { + var _this2 = this; + + var streamId = this.streamId++; + var sourceName = this.sourceName; + var targetName = this.targetName; + return new _streams_polyfill.ReadableStream({ + start: function start(controller) { + var startCapability = createPromiseCapability(); + _this2.streamControllers[streamId] = { + controller: controller, + startCall: startCapability, + isClosed: false + }; + _this2.postMessage({ + sourceName: sourceName, + targetName: targetName, + action: actionName, + streamId: streamId, + data: data, + desiredSize: controller.desiredSize + }); + return startCapability.promise; + }, + pull: function pull(controller) { + var pullCapability = createPromiseCapability(); + _this2.streamControllers[streamId].pullCall = pullCapability; + _this2.postMessage({ + sourceName: sourceName, + targetName: targetName, + stream: 'pull', + streamId: streamId, + desiredSize: controller.desiredSize + }); + return pullCapability.promise; + }, + cancel: function cancel(reason) { + var cancelCapability = createPromiseCapability(); + _this2.streamControllers[streamId].cancelCall = cancelCapability; + _this2.streamControllers[streamId].isClosed = true; + _this2.postMessage({ + sourceName: sourceName, + targetName: targetName, + stream: 'cancel', + reason: reason, + streamId: streamId + }); + return cancelCapability.promise; + } + }, queueingStrategy); + }, + _createStreamSink: function _createStreamSink(data) { + var _this3 = this; + + var self = this; + var action = this.actionHandler[data.action]; + var streamId = data.streamId; + var desiredSize = data.desiredSize; + var sourceName = this.sourceName; + var targetName = data.sourceName; + var capability = createPromiseCapability(); + var sendStreamRequest = function sendStreamRequest(_ref) { + var stream = _ref.stream, + chunk = _ref.chunk, + transfers = _ref.transfers, + success = _ref.success, + reason = _ref.reason; + + _this3.postMessage({ + sourceName: sourceName, + targetName: targetName, + stream: stream, + streamId: streamId, + chunk: chunk, + success: success, + reason: reason + }, transfers); + }; + var streamSink = { + enqueue: function enqueue(chunk) { + var size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; + var transfers = arguments[2]; + + if (this.isCancelled) { + return; + } + var lastDesiredSize = this.desiredSize; + this.desiredSize -= size; + if (lastDesiredSize > 0 && this.desiredSize <= 0) { + this.sinkCapability = createPromiseCapability(); + this.ready = this.sinkCapability.promise; + } + sendStreamRequest({ + stream: 'enqueue', + chunk: chunk, + transfers: transfers + }); + }, + close: function close() { + if (this.isCancelled) { + return; + } + sendStreamRequest({stream: 'close'}); + delete self.streamSinks[streamId]; + }, + error: function error(reason) { + if (this.isCancelled) { + return; + } + this.isCancelled = true; + sendStreamRequest({ + stream: 'error', + reason: reason + }); + }, + + sinkCapability: capability, + onPull: null, + onCancel: null, + isCancelled: false, + desiredSize: desiredSize, + ready: null + }; + streamSink.sinkCapability.resolve(); + streamSink.ready = streamSink.sinkCapability.promise; + this.streamSinks[streamId] = streamSink; + resolveCall(action[0], [data.data, streamSink], action[1]).then(function () { + sendStreamRequest({ + stream: 'start_complete', + success: true + }); + }, function (reason) { + sendStreamRequest({ + stream: 'start_complete', + success: false, + reason: reason + }); + }); + }, + _processStreamMessage: function _processStreamMessage(data) { + var _this4 = this; + + var sourceName = this.sourceName; + var targetName = data.sourceName; + var streamId = data.streamId; + var sendStreamResponse = function sendStreamResponse(_ref2) { + var stream = _ref2.stream, + success = _ref2.success, + reason = _ref2.reason; + + _this4.comObj.postMessage({ + sourceName: sourceName, + targetName: targetName, + stream: stream, + success: success, + streamId: streamId, + reason: reason + }); + }; + var deleteStreamController = function deleteStreamController() { + Promise.all([_this4.streamControllers[data.streamId].startCall, _this4.streamControllers[data.streamId].pullCall, _this4.streamControllers[data.streamId].cancelCall].map(function (capability) { + return capability && finalize(capability.promise); + })).then(function () { + delete _this4.streamControllers[data.streamId]; + }); + }; + switch (data.stream) { + case 'start_complete': + resolveOrReject(this.streamControllers[data.streamId].startCall, data.success, wrapReason(data.reason)); + break; + case 'pull_complete': + resolveOrReject(this.streamControllers[data.streamId].pullCall, data.success, wrapReason(data.reason)); + break; + case 'pull': + if (!this.streamSinks[data.streamId]) { + sendStreamResponse({ + stream: 'pull_complete', + success: true + }); + break; + } + if (this.streamSinks[data.streamId].desiredSize <= 0 && data.desiredSize > 0) { + this.streamSinks[data.streamId].sinkCapability.resolve(); + } + this.streamSinks[data.streamId].desiredSize = data.desiredSize; + resolveCall(this.streamSinks[data.streamId].onPull).then(function () { + sendStreamResponse({ + stream: 'pull_complete', + success: true + }); + }, function (reason) { + sendStreamResponse({ + stream: 'pull_complete', + success: false, + reason: reason + }); + }); + break; + case 'enqueue': + assert(this.streamControllers[data.streamId], 'enqueue should have stream controller'); + if (!this.streamControllers[data.streamId].isClosed) { + this.streamControllers[data.streamId].controller.enqueue(data.chunk); + } + break; + case 'close': + assert(this.streamControllers[data.streamId], 'close should have stream controller'); + if (this.streamControllers[data.streamId].isClosed) { + break; + } + this.streamControllers[data.streamId].isClosed = true; + this.streamControllers[data.streamId].controller.close(); + deleteStreamController(); + break; + case 'error': + assert(this.streamControllers[data.streamId], 'error should have stream controller'); + this.streamControllers[data.streamId].controller.error(wrapReason(data.reason)); + deleteStreamController(); + break; + case 'cancel_complete': + resolveOrReject(this.streamControllers[data.streamId].cancelCall, data.success, wrapReason(data.reason)); + deleteStreamController(); + break; + case 'cancel': + if (!this.streamSinks[data.streamId]) { + break; + } + resolveCall(this.streamSinks[data.streamId].onCancel, [wrapReason(data.reason)]).then(function () { + sendStreamResponse({ + stream: 'cancel_complete', + success: true + }); + }, function (reason) { + sendStreamResponse({ + stream: 'cancel_complete', + success: false, + reason: reason + }); + }); + this.streamSinks[data.streamId].sinkCapability.reject(wrapReason(data.reason)); + this.streamSinks[data.streamId].isCancelled = true; + delete this.streamSinks[data.streamId]; + break; + default: + throw new Error('Unexpected stream case'); + } + }, + postMessage: function postMessage(message, transfers) { + if (transfers && this.postMessageTransfers) { + this.comObj.postMessage(message, transfers); + } else { + this.comObj.postMessage(message); + } + }, + destroy: function destroy() { + this.comObj.removeEventListener('message', this._onComObjOnMessage); + } + }; + + function loadJpegStream(id, imageUrl, objs) { + var img = new Image(); + img.onload = function loadJpegStream_onloadClosure() { + objs.resolve(id, img); + }; + img.onerror = function loadJpegStream_onerrorClosure() { + objs.resolve(id, null); + warn('Error during JPEG image loading'); + }; + img.src = imageUrl; + } + + exports.FONT_IDENTITY_MATRIX = FONT_IDENTITY_MATRIX; + exports.IDENTITY_MATRIX = IDENTITY_MATRIX; + exports.OPS = OPS; + exports.VERBOSITY_LEVELS = VERBOSITY_LEVELS; + exports.UNSUPPORTED_FEATURES = UNSUPPORTED_FEATURES; + exports.AnnotationBorderStyleType = AnnotationBorderStyleType; + exports.AnnotationFieldFlag = AnnotationFieldFlag; + exports.AnnotationFlag = AnnotationFlag; + exports.AnnotationType = AnnotationType; + exports.FontType = FontType; + exports.ImageKind = ImageKind; + exports.CMapCompressionType = CMapCompressionType; + exports.AbortException = AbortException; + exports.InvalidPDFException = InvalidPDFException; + exports.MessageHandler = MessageHandler; + exports.MissingDataException = MissingDataException; + exports.MissingPDFException = MissingPDFException; + exports.NativeImageDecoding = NativeImageDecoding; + exports.NotImplementedException = NotImplementedException; + exports.PageViewport = PageViewport; + exports.PasswordException = PasswordException; + exports.PasswordResponses = PasswordResponses; + exports.StatTimer = StatTimer; + exports.StreamType = StreamType; + exports.TextRenderingMode = TextRenderingMode; + exports.UnexpectedResponseException = UnexpectedResponseException; + exports.UnknownErrorException = UnknownErrorException; + exports.Util = Util; + exports.XRefParseException = XRefParseException; + exports.FormatError = FormatError; + exports.arrayByteLength = arrayByteLength; + exports.arraysToBytes = arraysToBytes; + exports.assert = assert; + exports.bytesToString = bytesToString; + exports.createBlob = createBlob; + exports.createPromiseCapability = createPromiseCapability; + exports.createObjectURL = createObjectURL; + exports.deprecated = deprecated; + exports.getLookupTableFactory = getLookupTableFactory; + exports.getVerbosityLevel = getVerbosityLevel; + exports.globalScope = globalScope; + exports.info = info; + exports.isArray = isArray; + exports.isArrayBuffer = isArrayBuffer; + exports.isBool = isBool; + exports.isEmptyObj = isEmptyObj; + exports.isInt = isInt; + exports.isNum = isNum; + exports.isString = isString; + exports.isSpace = isSpace; + exports.isNodeJS = isNodeJS; + exports.isSameOrigin = isSameOrigin; + exports.createValidAbsoluteUrl = createValidAbsoluteUrl; + exports.isLittleEndian = isLittleEndian; + exports.isEvalSupported = isEvalSupported; + exports.loadJpegStream = loadJpegStream; + exports.log2 = log2; + exports.readInt8 = readInt8; + exports.readUint16 = readUint16; + exports.readUint32 = readUint32; + exports.removeNullCharacters = removeNullCharacters; + exports.ReadableStream = _streams_polyfill.ReadableStream; + exports.setVerbosityLevel = setVerbosityLevel; + exports.shadow = shadow; + exports.string32 = string32; + exports.stringToBytes = stringToBytes; + exports.stringToPDFString = stringToPDFString; + exports.stringToUTF8String = stringToUTF8String; + exports.utf8StringToString = utf8StringToString; + exports.warn = warn; + exports.unreachable = unreachable; + + /***/ + }), + /* 1 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.DOMCMapReaderFactory = exports.DOMCanvasFactory = exports.DEFAULT_LINK_REL = exports.getDefaultSetting = exports.LinkTarget = exports.getFilenameFromUrl = exports.isValidUrl = exports.isExternalLinkTargetSet = exports.addLinkAttributes = exports.RenderingCancelledException = exports.CustomStyle = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _util = __w_pdfjs_require__(0); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var DEFAULT_LINK_REL = 'noopener noreferrer nofollow'; + + var DOMCanvasFactory = function () { + function DOMCanvasFactory() { + _classCallCheck(this, DOMCanvasFactory); + } + + _createClass(DOMCanvasFactory, [{ + key: 'create', + value: function create(width, height) { + if (width <= 0 || height <= 0) { + throw new Error('invalid canvas size'); + } + var canvas = document.createElement('canvas'); + var context = canvas.getContext('2d'); + canvas.width = width; + canvas.height = height; + return { + canvas: canvas, + context: context + }; + } + }, { + key: 'reset', + value: function 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; + } + }, { + key: 'destroy', + value: function 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; + } + }]); + + return DOMCanvasFactory; + }(); + + var DOMCMapReaderFactory = function () { + function DOMCMapReaderFactory(_ref) { + var _ref$baseUrl = _ref.baseUrl, + baseUrl = _ref$baseUrl === undefined ? null : _ref$baseUrl, + _ref$isCompressed = _ref.isCompressed, + isCompressed = _ref$isCompressed === undefined ? false : _ref$isCompressed; + + _classCallCheck(this, DOMCMapReaderFactory); + + this.baseUrl = baseUrl; + this.isCompressed = isCompressed; + } + + _createClass(DOMCMapReaderFactory, [{ + key: 'fetch', + value: function fetch(_ref2) { + var _this = this; + + var name = _ref2.name; + + if (!name) { + return Promise.reject(new Error('CMap name must be specified.')); + } + return new Promise(function (resolve, reject) { + var url = _this.baseUrl + name + (_this.isCompressed ? '.bcmap' : ''); + var request = new XMLHttpRequest(); + request.open('GET', url, true); + if (_this.isCompressed) { + request.responseType = 'arraybuffer'; + } + request.onreadystatechange = function () { + if (request.readyState !== XMLHttpRequest.DONE) { + return; + } + if (request.status === 200 || request.status === 0) { + var data = void 0; + if (_this.isCompressed && request.response) { + data = new Uint8Array(request.response); + } else if (!_this.isCompressed && request.responseText) { + data = (0, _util.stringToBytes)(request.responseText); + } + if (data) { + resolve({ + cMapData: data, + compressionType: _this.isCompressed ? _util.CMapCompressionType.BINARY : _util.CMapCompressionType.NONE + }); + return; + } + } + reject(new Error('Unable to load ' + (_this.isCompressed ? 'binary ' : '') + 'CMap at: ' + url)); + }; + request.send(null); + }); + } + }]); + + return DOMCMapReaderFactory; + }(); + + var CustomStyle = function CustomStyleClosure() { + var prefixes = ['ms', 'Moz', 'Webkit', 'O']; + var _cache = Object.create(null); + + function CustomStyle() { + } + + CustomStyle.getProp = function get(propName, element) { + if (arguments.length === 1 && typeof _cache[propName] === 'string') { + return _cache[propName]; + } + element = element || document.documentElement; + var style = element.style, + prefixed, + uPropName; + if (typeof style[propName] === 'string') { + return _cache[propName] = propName; + } + uPropName = propName.charAt(0).toUpperCase() + propName.slice(1); + for (var i = 0, l = prefixes.length; i < l; i++) { + prefixed = prefixes[i] + uPropName; + if (typeof style[prefixed] === 'string') { + return _cache[propName] = prefixed; + } + } + return _cache[propName] = 'undefined'; + }; + CustomStyle.setProp = function set(propName, element, str) { + var prop = this.getProp(propName); + if (prop !== 'undefined') { + element.style[prop] = str; + } + }; + return CustomStyle; + }(); + var RenderingCancelledException = function RenderingCancelledException() { + function RenderingCancelledException(msg, type) { + this.message = msg; + this.type = type; + } + + RenderingCancelledException.prototype = new Error(); + RenderingCancelledException.prototype.name = 'RenderingCancelledException'; + RenderingCancelledException.constructor = RenderingCancelledException; + return RenderingCancelledException; + }(); + var LinkTarget = { + NONE: 0, + SELF: 1, + BLANK: 2, + PARENT: 3, + TOP: 4 + }; + var LinkTargetStringMap = ['', '_self', '_blank', '_parent', '_top']; + + function addLinkAttributes(link, params) { + var url = params && params.url; + link.href = link.title = url ? (0, _util.removeNullCharacters)(url) : ''; + if (url) { + var target = params.target; + if (typeof target === 'undefined') { + target = getDefaultSetting('externalLinkTarget'); + } + link.target = LinkTargetStringMap[target]; + var rel = params.rel; + if (typeof rel === 'undefined') { + rel = getDefaultSetting('externalLinkRel'); + } + link.rel = rel; + } + } + + function getFilenameFromUrl(url) { + var anchor = url.indexOf('#'); + var query = url.indexOf('?'); + var end = Math.min(anchor > 0 ? anchor : url.length, query > 0 ? query : url.length); + return url.substring(url.lastIndexOf('/', end) + 1, end); + } + + function getDefaultSetting(id) { + var globalSettings = _util.globalScope.PDFJS; + switch (id) { + case 'pdfBug': + return globalSettings ? globalSettings.pdfBug : false; + case 'disableAutoFetch': + return globalSettings ? globalSettings.disableAutoFetch : false; + case 'disableStream': + return globalSettings ? globalSettings.disableStream : false; + case 'disableRange': + return globalSettings ? globalSettings.disableRange : false; + case 'disableFontFace': + return globalSettings ? globalSettings.disableFontFace : false; + case 'disableCreateObjectURL': + return globalSettings ? globalSettings.disableCreateObjectURL : false; + case 'disableWebGL': + return globalSettings ? globalSettings.disableWebGL : true; + case 'cMapUrl': + return globalSettings ? globalSettings.cMapUrl : null; + case 'cMapPacked': + return globalSettings ? globalSettings.cMapPacked : false; + case 'postMessageTransfers': + return globalSettings ? globalSettings.postMessageTransfers : true; + case 'workerPort': + return globalSettings ? globalSettings.workerPort : null; + case 'workerSrc': + return globalSettings ? globalSettings.workerSrc : null; + case 'disableWorker': + return globalSettings ? globalSettings.disableWorker : false; + case 'maxImageSize': + return globalSettings ? globalSettings.maxImageSize : -1; + case 'imageResourcesPath': + return globalSettings ? globalSettings.imageResourcesPath : ''; + case 'isEvalSupported': + return globalSettings ? globalSettings.isEvalSupported : true; + case 'externalLinkTarget': + if (!globalSettings) { + return LinkTarget.NONE; + } + switch (globalSettings.externalLinkTarget) { + case LinkTarget.NONE: + case LinkTarget.SELF: + case LinkTarget.BLANK: + case LinkTarget.PARENT: + case LinkTarget.TOP: + return globalSettings.externalLinkTarget; + } + (0, _util.warn)('PDFJS.externalLinkTarget is invalid: ' + globalSettings.externalLinkTarget); + globalSettings.externalLinkTarget = LinkTarget.NONE; + return LinkTarget.NONE; + case 'externalLinkRel': + return globalSettings ? globalSettings.externalLinkRel : DEFAULT_LINK_REL; + case 'enableStats': + return !!(globalSettings && globalSettings.enableStats); + case 'pdfjsNext': + return !!(globalSettings && globalSettings.pdfjsNext); + default: + throw new Error('Unknown default setting: ' + id); + } + } + + function isExternalLinkTargetSet() { + var externalLinkTarget = getDefaultSetting('externalLinkTarget'); + switch (externalLinkTarget) { + case LinkTarget.NONE: + return false; + case LinkTarget.SELF: + case LinkTarget.BLANK: + case LinkTarget.PARENT: + case LinkTarget.TOP: + return true; + } + } + + function isValidUrl(url, allowRelative) { + (0, _util.deprecated)('isValidUrl(), please use createValidAbsoluteUrl() instead.'); + var baseUrl = allowRelative ? 'http://example.com' : null; + return (0, _util.createValidAbsoluteUrl)(url, baseUrl) !== null; + } + + exports.CustomStyle = CustomStyle; + exports.RenderingCancelledException = RenderingCancelledException; + exports.addLinkAttributes = addLinkAttributes; + exports.isExternalLinkTargetSet = isExternalLinkTargetSet; + exports.isValidUrl = isValidUrl; + exports.getFilenameFromUrl = getFilenameFromUrl; + exports.LinkTarget = LinkTarget; + exports.getDefaultSetting = getDefaultSetting; + exports.DEFAULT_LINK_REL = DEFAULT_LINK_REL; + exports.DOMCanvasFactory = DOMCanvasFactory; + exports.DOMCMapReaderFactory = DOMCMapReaderFactory; + + /***/ + }), + /* 2 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.build = exports.version = exports._UnsupportedManager = exports.setPDFNetworkStreamClass = exports.PDFPageProxy = exports.PDFDocumentProxy = exports.PDFWorker = exports.PDFDataRangeTransport = exports.LoopbackPort = exports.getDocument = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + var _util = __w_pdfjs_require__(0); + + var _dom_utils = __w_pdfjs_require__(1); + + var _font_loader = __w_pdfjs_require__(12); + + var _canvas = __w_pdfjs_require__(11); + + var _metadata = __w_pdfjs_require__(6); + + var _transport_stream = __w_pdfjs_require__(14); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var DEFAULT_RANGE_CHUNK_SIZE = 65536; + var isWorkerDisabled = false; + var workerSrc; + var isPostMessageTransfersDisabled = false; + var pdfjsFilePath = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : null; + var fakeWorkerFilesLoader = null; + var useRequireEnsure = false; + { + if (typeof window === 'undefined') { + isWorkerDisabled = true; + if (typeof require.ensure === 'undefined') { + require.ensure = require('node-ensure'); + } + useRequireEnsure = true; + } else if (typeof require !== 'undefined' && typeof require.ensure === 'function') { + useRequireEnsure = true; + } + if (typeof requirejs !== 'undefined' && requirejs.toUrl) { + workerSrc = requirejs.toUrl('pdfjs-dist/build/pdf.worker.js'); + } + var dynamicLoaderSupported = typeof requirejs !== 'undefined' && requirejs.load; + fakeWorkerFilesLoader = useRequireEnsure ? function (callback) { + require.ensure([], function () { + var worker; + worker = require('./pdf.worker.js'); + callback(worker.WorkerMessageHandler); + }); + } : dynamicLoaderSupported ? function (callback) { + requirejs(['pdfjs-dist/build/pdf.worker'], function (worker) { + callback(worker.WorkerMessageHandler); + }); + } : null; + } + var PDFNetworkStream; + + function setPDFNetworkStreamClass(cls) { + PDFNetworkStream = cls; + } + + function getDocument(src, pdfDataRangeTransport, passwordCallback, progressCallback) { + var task = new PDFDocumentLoadingTask(); + if (arguments.length > 1) { + (0, _util.deprecated)('getDocument is called with pdfDataRangeTransport, ' + 'passwordCallback or progressCallback argument'); + } + if (pdfDataRangeTransport) { + if (!(pdfDataRangeTransport instanceof PDFDataRangeTransport)) { + pdfDataRangeTransport = Object.create(pdfDataRangeTransport); + pdfDataRangeTransport.length = src.length; + pdfDataRangeTransport.initialData = src.initialData; + if (!pdfDataRangeTransport.abort) { + pdfDataRangeTransport.abort = function () { + }; + } + } + src = Object.create(src); + src.range = pdfDataRangeTransport; + } + task.onPassword = passwordCallback || null; + task.onProgress = progressCallback || null; + var source; + if (typeof src === 'string') { + source = {url: src}; + } else if ((0, _util.isArrayBuffer)(src)) { + source = {data: src}; + } else if (src instanceof PDFDataRangeTransport) { + source = {range: src}; + } else { + if ((typeof src === 'undefined' ? 'undefined' : _typeof(src)) !== 'object') { + throw new Error('Invalid parameter in getDocument, ' + 'need either Uint8Array, string or a parameter object'); + } + if (!src.url && !src.data && !src.range) { + throw new Error('Invalid parameter object: need either .data, .range or .url'); + } + source = src; + } + var params = {}; + var rangeTransport = null; + var worker = null; + var CMapReaderFactory = _dom_utils.DOMCMapReaderFactory; + for (var 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)) { + var pdfBytes = source[key]; + if (typeof pdfBytes === 'string') { + params[key] = (0, _util.stringToBytes)(pdfBytes); + } else if ((typeof pdfBytes === 'undefined' ? 'undefined' : _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.'); + } + continue; + } else if (key === 'CMapReaderFactory') { + CMapReaderFactory = source[key]; + continue; + } + params[key] = source[key]; + } + params.rangeChunkSize = params.rangeChunkSize || DEFAULT_RANGE_CHUNK_SIZE; + params.ignoreErrors = params.stopAtErrors !== true; + if (params.disableNativeImageDecoder !== undefined) { + (0, _util.deprecated)('parameter disableNativeImageDecoder, ' + 'use nativeImageDecoderSupport instead'); + } + params.nativeImageDecoderSupport = params.nativeImageDecoderSupport || (params.disableNativeImageDecoder === true ? _util.NativeImageDecoding.NONE : _util.NativeImageDecoding.DECODE); + if (params.nativeImageDecoderSupport !== _util.NativeImageDecoding.DECODE && params.nativeImageDecoderSupport !== _util.NativeImageDecoding.NONE && params.nativeImageDecoderSupport !== _util.NativeImageDecoding.DISPLAY) { + (0, _util.warn)('Invalid parameter nativeImageDecoderSupport: ' + 'need a state of enum {NativeImageDecoding}'); + params.nativeImageDecoderSupport = _util.NativeImageDecoding.DECODE; + } + if (!worker) { + var workerPort = (0, _dom_utils.getDefaultSetting)('workerPort'); + worker = workerPort ? PDFWorker.fromPort(workerPort) : new PDFWorker(); + task._worker = worker; + } + var docId = task.docId; + worker.promise.then(function () { + if (task.destroyed) { + throw new Error('Loading aborted'); + } + return _fetchDocument(worker, params, rangeTransport, docId).then(function (workerId) { + if (task.destroyed) { + throw new Error('Loading aborted'); + } + var networkStream = void 0; + if (rangeTransport) { + networkStream = new _transport_stream.PDFDataTransportStream(params, rangeTransport); + } else if (!params.data) { + networkStream = new PDFNetworkStream({ + source: params, + disableRange: (0, _dom_utils.getDefaultSetting)('disableRange') + }); + } + var messageHandler = new _util.MessageHandler(docId, workerId, worker.port); + messageHandler.postMessageTransfers = worker.postMessageTransfers; + var transport = new WorkerTransport(messageHandler, task, networkStream, CMapReaderFactory); + task._transport = transport; + messageHandler.send('Ready', null); + }); + }).catch(task._capability.reject); + return task; + } + + function _fetchDocument(worker, source, pdfDataRangeTransport, docId) { + if (worker.destroyed) { + return Promise.reject(new Error('Worker was destroyed')); + } + source.disableAutoFetch = (0, _dom_utils.getDefaultSetting)('disableAutoFetch'); + source.disableStream = (0, _dom_utils.getDefaultSetting)('disableStream'); + source.chunkedViewerLoading = !!pdfDataRangeTransport; + if (pdfDataRangeTransport) { + source.length = pdfDataRangeTransport.length; + source.initialData = pdfDataRangeTransport.initialData; + } + return worker.messageHandler.sendWithPromise('GetDocRequest', { + docId: docId, + source: { + data: source.data, + url: source.url, + password: source.password, + disableAutoFetch: source.disableAutoFetch, + rangeChunkSize: source.rangeChunkSize, + length: source.length + }, + maxImageSize: (0, _dom_utils.getDefaultSetting)('maxImageSize'), + disableFontFace: (0, _dom_utils.getDefaultSetting)('disableFontFace'), + disableCreateObjectURL: (0, _dom_utils.getDefaultSetting)('disableCreateObjectURL'), + postMessageTransfers: (0, _dom_utils.getDefaultSetting)('postMessageTransfers') && !isPostMessageTransfersDisabled, + docBaseUrl: source.docBaseUrl, + nativeImageDecoderSupport: source.nativeImageDecoderSupport, + ignoreErrors: source.ignoreErrors + }).then(function (workerId) { + if (worker.destroyed) { + throw new Error('Worker was destroyed'); + } + return workerId; + }); + } + + var PDFDocumentLoadingTask = function PDFDocumentLoadingTaskClosure() { + var nextDocumentId = 0; + + function PDFDocumentLoadingTask() { + 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; + } + + PDFDocumentLoadingTask.prototype = { + get promise() { + return this._capability.promise; + }, + destroy: function destroy() { + var _this = this; + + this.destroyed = true; + var transportDestroyed = !this._transport ? Promise.resolve() : this._transport.destroy(); + return transportDestroyed.then(function () { + _this._transport = null; + if (_this._worker) { + _this._worker.destroy(); + _this._worker = null; + } + }); + }, + + then: function PDFDocumentLoadingTask_then(onFulfilled, onRejected) { + return this.promise.then.apply(this.promise, arguments); + } + }; + return PDFDocumentLoadingTask; + }(); + var PDFDataRangeTransport = function pdfDataRangeTransportClosure() { + function PDFDataRangeTransport(length, initialData) { + this.length = length; + this.initialData = initialData; + this._rangeListeners = []; + this._progressListeners = []; + this._progressiveReadListeners = []; + this._readyCapability = (0, _util.createPromiseCapability)(); + } + + PDFDataRangeTransport.prototype = { + addRangeListener: function PDFDataRangeTransport_addRangeListener(listener) { + this._rangeListeners.push(listener); + }, + addProgressListener: function PDFDataRangeTransport_addProgressListener(listener) { + this._progressListeners.push(listener); + }, + addProgressiveReadListener: function PDFDataRangeTransport_addProgressiveReadListener(listener) { + this._progressiveReadListeners.push(listener); + }, + onDataRange: function PDFDataRangeTransport_onDataRange(begin, chunk) { + var listeners = this._rangeListeners; + for (var i = 0, n = listeners.length; i < n; ++i) { + listeners[i](begin, chunk); + } + }, + onDataProgress: function PDFDataRangeTransport_onDataProgress(loaded) { + var _this2 = this; + + this._readyCapability.promise.then(function () { + var listeners = _this2._progressListeners; + for (var i = 0, n = listeners.length; i < n; ++i) { + listeners[i](loaded); + } + }); + }, + onDataProgressiveRead: function PDFDataRangeTransport_onDataProgress(chunk) { + var _this3 = this; + + this._readyCapability.promise.then(function () { + var listeners = _this3._progressiveReadListeners; + for (var i = 0, n = listeners.length; i < n; ++i) { + listeners[i](chunk); + } + }); + }, + transportReady: function PDFDataRangeTransport_transportReady() { + this._readyCapability.resolve(); + }, + requestDataRange: function PDFDataRangeTransport_requestDataRange(begin, end) { + throw new Error('Abstract method PDFDataRangeTransport.requestDataRange'); + }, + abort: function PDFDataRangeTransport_abort() { + } + }; + return PDFDataRangeTransport; + }(); + var PDFDocumentProxy = function PDFDocumentProxyClosure() { + function PDFDocumentProxy(pdfInfo, transport, loadingTask) { + this.pdfInfo = pdfInfo; + this.transport = transport; + this.loadingTask = loadingTask; + } + + PDFDocumentProxy.prototype = { + get numPages() { + return this.pdfInfo.numPages; + }, + get fingerprint() { + return this.pdfInfo.fingerprint; + }, + getPage: function PDFDocumentProxy_getPage(pageNumber) { + return this.transport.getPage(pageNumber); + }, + getPageIndex: function PDFDocumentProxy_getPageIndex(ref) { + return this.transport.getPageIndex(ref); + }, + getDestinations: function PDFDocumentProxy_getDestinations() { + return this.transport.getDestinations(); + }, + getDestination: function PDFDocumentProxy_getDestination(id) { + return this.transport.getDestination(id); + }, + getPageLabels: function PDFDocumentProxy_getPageLabels() { + return this.transport.getPageLabels(); + }, + getPageMode: function getPageMode() { + return this.transport.getPageMode(); + }, + + getAttachments: function PDFDocumentProxy_getAttachments() { + return this.transport.getAttachments(); + }, + getJavaScript: function PDFDocumentProxy_getJavaScript() { + return this.transport.getJavaScript(); + }, + getOutline: function PDFDocumentProxy_getOutline() { + return this.transport.getOutline(); + }, + getMetadata: function PDFDocumentProxy_getMetadata() { + return this.transport.getMetadata(); + }, + getData: function PDFDocumentProxy_getData() { + return this.transport.getData(); + }, + getDownloadInfo: function PDFDocumentProxy_getDownloadInfo() { + return this.transport.downloadInfoCapability.promise; + }, + getStats: function PDFDocumentProxy_getStats() { + return this.transport.getStats(); + }, + cleanup: function PDFDocumentProxy_cleanup() { + this.transport.startCleanup(); + }, + destroy: function PDFDocumentProxy_destroy() { + return this.loadingTask.destroy(); + } + }; + return PDFDocumentProxy; + }(); + var PDFPageProxy = function PDFPageProxyClosure() { + function PDFPageProxy(pageIndex, pageInfo, transport) { + this.pageIndex = pageIndex; + this.pageInfo = pageInfo; + this.transport = transport; + this.stats = new _util.StatTimer(); + this.stats.enabled = (0, _dom_utils.getDefaultSetting)('enableStats'); + this.commonObjs = transport.commonObjs; + this.objs = new PDFObjects(); + this.cleanupAfterRender = false; + this.pendingCleanup = false; + this.intentStates = Object.create(null); + this.destroyed = false; + } + + PDFPageProxy.prototype = { + get pageNumber() { + return this.pageIndex + 1; + }, + get rotate() { + return this.pageInfo.rotate; + }, + get ref() { + return this.pageInfo.ref; + }, + get userUnit() { + return this.pageInfo.userUnit; + }, + get view() { + return this.pageInfo.view; + }, + getViewport: function PDFPageProxy_getViewport(scale, rotate) { + if (arguments.length < 2) { + rotate = this.rotate; + } + return new _util.PageViewport(this.view, scale, rotate, 0, 0); + }, + getAnnotations: function PDFPageProxy_getAnnotations(params) { + var intent = params && params.intent || null; + if (!this.annotationsPromise || this.annotationsIntent !== intent) { + this.annotationsPromise = this.transport.getAnnotations(this.pageIndex, intent); + this.annotationsIntent = intent; + } + return this.annotationsPromise; + }, + render: function PDFPageProxy_render(params) { + var _this4 = this; + + var stats = this.stats; + stats.time('Overall'); + this.pendingCleanup = false; + var renderingIntent = params.intent === 'print' ? 'print' : 'display'; + var canvasFactory = params.canvasFactory || new _dom_utils.DOMCanvasFactory(); + if (!this.intentStates[renderingIntent]) { + this.intentStates[renderingIntent] = Object.create(null); + } + var intentState = this.intentStates[renderingIntent]; + if (!intentState.displayReadyCapability) { + intentState.receivingOperatorList = true; + intentState.displayReadyCapability = (0, _util.createPromiseCapability)(); + intentState.operatorList = { + fnArray: [], + argsArray: [], + lastChunk: false + }; + this.stats.time('Page Request'); + this.transport.messageHandler.send('RenderPageRequest', { + pageIndex: this.pageNumber - 1, + intent: renderingIntent, + renderInteractiveForms: params.renderInteractiveForms === true + }); + } + var complete = function complete(error) { + var i = intentState.renderTasks.indexOf(internalRenderTask); + if (i >= 0) { + intentState.renderTasks.splice(i, 1); + } + if (_this4.cleanupAfterRender) { + _this4.pendingCleanup = true; + } + _this4._tryCleanup(); + if (error) { + internalRenderTask.capability.reject(error); + } else { + internalRenderTask.capability.resolve(); + } + stats.timeEnd('Rendering'); + stats.timeEnd('Overall'); + }; + var internalRenderTask = new InternalRenderTask(complete, params, this.objs, this.commonObjs, intentState.operatorList, this.pageNumber, canvasFactory); + internalRenderTask.useRequestAnimationFrame = renderingIntent !== 'print'; + if (!intentState.renderTasks) { + intentState.renderTasks = []; + } + intentState.renderTasks.push(internalRenderTask); + var renderTask = internalRenderTask.task; + if (params.continueCallback) { + (0, _util.deprecated)('render is used with continueCallback parameter'); + renderTask.onContinue = params.continueCallback; + } + intentState.displayReadyCapability.promise.then(function (transparency) { + if (_this4.pendingCleanup) { + complete(); + return; + } + stats.time('Rendering'); + internalRenderTask.initializeGraphics(transparency); + internalRenderTask.operatorListChanged(); + }).catch(complete); + return renderTask; + }, + getOperatorList: function PDFPageProxy_getOperatorList() { + function operatorListChanged() { + if (intentState.operatorList.lastChunk) { + intentState.opListReadCapability.resolve(intentState.operatorList); + var i = intentState.renderTasks.indexOf(opListTask); + if (i >= 0) { + intentState.renderTasks.splice(i, 1); + } + } + } + + var renderingIntent = 'oplist'; + if (!this.intentStates[renderingIntent]) { + this.intentStates[renderingIntent] = Object.create(null); + } + var intentState = this.intentStates[renderingIntent]; + var opListTask; + if (!intentState.opListReadCapability) { + opListTask = {}; + opListTask.operatorListChanged = operatorListChanged; + intentState.receivingOperatorList = true; + intentState.opListReadCapability = (0, _util.createPromiseCapability)(); + intentState.renderTasks = []; + intentState.renderTasks.push(opListTask); + intentState.operatorList = { + fnArray: [], + argsArray: [], + lastChunk: false + }; + this.transport.messageHandler.send('RenderPageRequest', { + pageIndex: this.pageIndex, + intent: renderingIntent + }); + } + return intentState.opListReadCapability.promise; + }, + streamTextContent: function streamTextContent() { + var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + var TEXT_CONTENT_CHUNK_SIZE = 100; + return this.transport.messageHandler.sendWithStream('GetTextContent', { + pageIndex: this.pageNumber - 1, + normalizeWhitespace: params.normalizeWhitespace === true, + combineTextItems: params.disableCombineTextItems !== true + }, { + highWaterMark: TEXT_CONTENT_CHUNK_SIZE, + size: function size(textContent) { + return textContent.items.length; + } + }); + }, + + getTextContent: function PDFPageProxy_getTextContent(params) { + params = params || {}; + var readableStream = this.streamTextContent(params); + return new Promise(function (resolve, reject) { + function pump() { + reader.read().then(function (_ref) { + var value = _ref.value, + done = _ref.done; + + if (done) { + resolve(textContent); + return; + } + _util.Util.extendObj(textContent.styles, value.styles); + _util.Util.appendToArray(textContent.items, value.items); + pump(); + }, reject); + } + + var reader = readableStream.getReader(); + var textContent = { + items: [], + styles: Object.create(null) + }; + pump(); + }); + }, + _destroy: function PDFPageProxy_destroy() { + this.destroyed = true; + this.transport.pageCache[this.pageIndex] = null; + var waitOn = []; + Object.keys(this.intentStates).forEach(function (intent) { + if (intent === 'oplist') { + return; + } + var intentState = this.intentStates[intent]; + intentState.renderTasks.forEach(function (renderTask) { + var renderCompleted = renderTask.capability.promise.catch(function () { + }); + waitOn.push(renderCompleted); + renderTask.cancel(); + }); + }, this); + this.objs.clear(); + this.annotationsPromise = null; + this.pendingCleanup = false; + return Promise.all(waitOn); + }, + destroy: function destroy() { + (0, _util.deprecated)('page destroy method, use cleanup() instead'); + this.cleanup(); + }, + + cleanup: function PDFPageProxy_cleanup() { + this.pendingCleanup = true; + this._tryCleanup(); + }, + _tryCleanup: function PDFPageProxy_tryCleanup() { + if (!this.pendingCleanup || Object.keys(this.intentStates).some(function (intent) { + var intentState = this.intentStates[intent]; + return intentState.renderTasks.length !== 0 || intentState.receivingOperatorList; + }, this)) { + return; + } + Object.keys(this.intentStates).forEach(function (intent) { + delete this.intentStates[intent]; + }, this); + this.objs.clear(); + this.annotationsPromise = null; + this.pendingCleanup = false; + }, + _startRenderPage: function PDFPageProxy_startRenderPage(transparency, intent) { + var intentState = this.intentStates[intent]; + if (intentState.displayReadyCapability) { + intentState.displayReadyCapability.resolve(transparency); + } + }, + _renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk, intent) { + var intentState = this.intentStates[intent]; + var i, ii; + for (i = 0, ii = operatorListChunk.length; i < ii; i++) { + intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]); + intentState.operatorList.argsArray.push(operatorListChunk.argsArray[i]); + } + intentState.operatorList.lastChunk = operatorListChunk.lastChunk; + for (i = 0; i < intentState.renderTasks.length; i++) { + intentState.renderTasks[i].operatorListChanged(); + } + if (operatorListChunk.lastChunk) { + intentState.receivingOperatorList = false; + this._tryCleanup(); + } + } + }; + return PDFPageProxy; + }(); + + var LoopbackPort = function () { + function LoopbackPort(defer) { + _classCallCheck(this, LoopbackPort); + + this._listeners = []; + this._defer = defer; + this._deferred = Promise.resolve(undefined); + } + + _createClass(LoopbackPort, [{ + key: 'postMessage', + value: function postMessage(obj, transfers) { + var _this5 = this; + + function cloneValue(value) { + if ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) !== 'object' || value === null) { + return value; + } + if (cloned.has(value)) { + return cloned.get(value); + } + var result; + var buffer; + if ((buffer = value.buffer) && (0, _util.isArrayBuffer)(buffer)) { + var transferable = transfers && transfers.indexOf(buffer) >= 0; + if (value === buffer) { + result = value; + } else if (transferable) { + result = new value.constructor(buffer, value.byteOffset, value.byteLength); + } else { + result = new value.constructor(value); + } + cloned.set(value, result); + return result; + } + result = (0, _util.isArray)(value) ? [] : {}; + cloned.set(value, result); + for (var i in value) { + var desc, + p = value; + while (!(desc = Object.getOwnPropertyDescriptor(p, i))) { + p = Object.getPrototypeOf(p); + } + if (typeof desc.value === 'undefined' || typeof desc.value === 'function') { + continue; + } + result[i] = cloneValue(desc.value); + } + return result; + } + + if (!this._defer) { + this._listeners.forEach(function (listener) { + listener.call(this, {data: obj}); + }, this); + return; + } + var cloned = new WeakMap(); + var e = {data: cloneValue(obj)}; + this._deferred.then(function () { + _this5._listeners.forEach(function (listener) { + listener.call(this, e); + }, _this5); + }); + } + }, { + key: 'addEventListener', + value: function addEventListener(name, listener) { + this._listeners.push(listener); + } + }, { + key: 'removeEventListener', + value: function removeEventListener(name, listener) { + var i = this._listeners.indexOf(listener); + this._listeners.splice(i, 1); + } + }, { + key: 'terminate', + value: function terminate() { + this._listeners = []; + } + }]); + + return LoopbackPort; + }(); + + var PDFWorker = function PDFWorkerClosure() { + var nextFakeWorkerId = 0; + + function getWorkerSrc() { + if (typeof workerSrc !== 'undefined') { + return workerSrc; + } + if ((0, _dom_utils.getDefaultSetting)('workerSrc')) { + return (0, _dom_utils.getDefaultSetting)('workerSrc'); + } + if (pdfjsFilePath) { + return pdfjsFilePath.replace(/(\.(?:min\.)?js)(\?.*)?$/i, '.worker$1$2'); + } + throw new Error('No PDFJS.workerSrc specified'); + } + + var fakeWorkerFilesLoadedCapability = void 0; + + function setupFakeWorkerGlobal() { + var WorkerMessageHandler; + if (fakeWorkerFilesLoadedCapability) { + return fakeWorkerFilesLoadedCapability.promise; + } + fakeWorkerFilesLoadedCapability = (0, _util.createPromiseCapability)(); + var loader = fakeWorkerFilesLoader || function (callback) { + _util.Util.loadScript(getWorkerSrc(), function () { + callback(window.pdfjsDistBuildPdfWorker.WorkerMessageHandler); + }); + }; + loader(fakeWorkerFilesLoadedCapability.resolve); + return fakeWorkerFilesLoadedCapability.promise; + } + + function createCDNWrapper(url) { + var wrapper = 'importScripts(\'' + url + '\');'; + return URL.createObjectURL(new Blob([wrapper])); + } + + var pdfWorkerPorts = new WeakMap(); + + function PDFWorker(name, port) { + 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._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(); + } + + PDFWorker.prototype = { + get promise() { + return this._readyCapability.promise; + }, + get port() { + return this._port; + }, + get messageHandler() { + return this._messageHandler; + }, + _initializeFromPort: function PDFWorker_initializeFromPort(port) { + this._port = port; + this._messageHandler = new _util.MessageHandler('main', 'worker', port); + this._messageHandler.on('ready', function () { + }); + this._readyCapability.resolve(); + }, + _initialize: function PDFWorker_initialize() { + var _this6 = this; + + if (!isWorkerDisabled && !(0, _dom_utils.getDefaultSetting)('disableWorker') && typeof Worker !== 'undefined') { + var workerSrc = getWorkerSrc(); + try { + if (!(0, _util.isSameOrigin)(window.location.href, workerSrc)) { + workerSrc = createCDNWrapper(new URL(workerSrc, window.location).href); + } + var worker = new Worker(workerSrc); + var messageHandler = new _util.MessageHandler('main', 'worker', worker); + var terminateEarly = function terminateEarly() { + worker.removeEventListener('error', onWorkerError); + messageHandler.destroy(); + worker.terminate(); + if (_this6.destroyed) { + _this6._readyCapability.reject(new Error('Worker was destroyed')); + } else { + _this6._setupFakeWorker(); + } + }; + var onWorkerError = function onWorkerError() { + if (!_this6._webWorker) { + terminateEarly(); + } + }; + worker.addEventListener('error', onWorkerError); + messageHandler.on('test', function (data) { + worker.removeEventListener('error', onWorkerError); + if (_this6.destroyed) { + terminateEarly(); + return; + } + var supportTypedArray = data && data.supportTypedArray; + if (supportTypedArray) { + _this6._messageHandler = messageHandler; + _this6._port = worker; + _this6._webWorker = worker; + if (!data.supportTransfers) { + _this6.postMessageTransfers = false; + isPostMessageTransfersDisabled = true; + } + _this6._readyCapability.resolve(); + messageHandler.send('configure', {verbosity: (0, _util.getVerbosityLevel)()}); + } else { + _this6._setupFakeWorker(); + messageHandler.destroy(); + worker.terminate(); + } + }); + messageHandler.on('console_log', function (data) { + console.log.apply(console, data); + }); + messageHandler.on('console_error', function (data) { + console.error.apply(console, data); + }); + messageHandler.on('ready', function (data) { + worker.removeEventListener('error', onWorkerError); + if (_this6.destroyed) { + terminateEarly(); + return; + } + try { + sendTest(); + } catch (e) { + _this6._setupFakeWorker(); + } + }); + var sendTest = function sendTest() { + var postMessageTransfers = (0, _dom_utils.getDefaultSetting)('postMessageTransfers') && !isPostMessageTransfersDisabled; + var testObj = new Uint8Array([postMessageTransfers ? 255 : 0]); + try { + messageHandler.send('test', testObj, [testObj.buffer]); + } catch (ex) { + (0, _util.info)('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: function PDFWorker_setupFakeWorker() { + var _this7 = this; + + if (!isWorkerDisabled && !(0, _dom_utils.getDefaultSetting)('disableWorker')) { + (0, _util.warn)('Setting up fake worker.'); + isWorkerDisabled = true; + } + setupFakeWorkerGlobal().then(function (WorkerMessageHandler) { + if (_this7.destroyed) { + _this7._readyCapability.reject(new Error('Worker was destroyed')); + return; + } + var isTypedArraysPresent = Uint8Array !== Float32Array; + var port = new LoopbackPort(isTypedArraysPresent); + _this7._port = port; + var id = 'fake' + nextFakeWorkerId++; + var workerHandler = new _util.MessageHandler(id + '_worker', id, port); + WorkerMessageHandler.setup(workerHandler, port); + var messageHandler = new _util.MessageHandler(id, id + '_worker', port); + _this7._messageHandler = messageHandler; + _this7._readyCapability.resolve(); + }); + }, + destroy: function PDFWorker_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; + } + } + }; + PDFWorker.fromPort = function (port) { + if (pdfWorkerPorts.has(port)) { + return pdfWorkerPorts.get(port); + } + return new PDFWorker(null, port); + }; + return PDFWorker; + }(); + var WorkerTransport = function WorkerTransportClosure() { + function WorkerTransport(messageHandler, loadingTask, networkStream, CMapReaderFactory) { + this.messageHandler = messageHandler; + this.loadingTask = loadingTask; + this.commonObjs = new PDFObjects(); + this.fontLoader = new _font_loader.FontLoader(loadingTask.docId); + this.CMapReaderFactory = new CMapReaderFactory({ + baseUrl: (0, _dom_utils.getDefaultSetting)('cMapUrl'), + isCompressed: (0, _dom_utils.getDefaultSetting)('cMapPacked') + }); + 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(); + } + + WorkerTransport.prototype = { + destroy: function WorkerTransport_destroy() { + var _this8 = this; + + if (this.destroyCapability) { + return this.destroyCapability.promise; + } + this.destroyed = true; + this.destroyCapability = (0, _util.createPromiseCapability)(); + if (this._passwordCapability) { + this._passwordCapability.reject(new Error('Worker was destroyed during onPassword callback')); + } + var waitOn = []; + this.pageCache.forEach(function (page) { + if (page) { + waitOn.push(page._destroy()); + } + }); + this.pageCache = []; + this.pagePromises = []; + var terminated = this.messageHandler.sendWithPromise('Terminate', null); + waitOn.push(terminated); + Promise.all(waitOn).then(function () { + _this8.fontLoader.clear(); + if (_this8._networkStream) { + _this8._networkStream.cancelAllRequests(); + } + if (_this8.messageHandler) { + _this8.messageHandler.destroy(); + _this8.messageHandler = null; + } + _this8.destroyCapability.resolve(); + }, this.destroyCapability.reject); + return this.destroyCapability.promise; + }, + setupMessageHandler: function WorkerTransport_setupMessageHandler() { + var messageHandler = this.messageHandler; + var loadingTask = this.loadingTask; + messageHandler.on('GetReader', function (data, sink) { + var _this9 = this; + + (0, _util.assert)(this._networkStream); + this._fullReader = this._networkStream.getFullReader(); + this._fullReader.onProgress = function (evt) { + _this9._lastProgress = { + loaded: evt.loaded, + total: evt.total + }; + }; + sink.onPull = function () { + _this9._fullReader.read().then(function (_ref2) { + var value = _ref2.value, + done = _ref2.done; + + if (done) { + sink.close(); + return; + } + (0, _util.assert)((0, _util.isArrayBuffer)(value)); + sink.enqueue(new Uint8Array(value), 1, [value]); + }).catch(function (reason) { + sink.error(reason); + }); + }; + sink.onCancel = function (reason) { + _this9._fullReader.cancel(reason); + }; + }, this); + messageHandler.on('ReaderHeadersReady', function (data) { + var _this10 = this; + + var headersCapability = (0, _util.createPromiseCapability)(); + var fullReader = this._fullReader; + fullReader.headersReady.then(function () { + if (!fullReader.isStreamingSupported || !fullReader.isRangeSupported) { + if (_this10._lastProgress) { + var _loadingTask = _this10.loadingTask; + if (_loadingTask.onProgress) { + _loadingTask.onProgress(_this10._lastProgress); + } + } + fullReader.onProgress = function (evt) { + var loadingTask = _this10.loadingTask; + if (loadingTask.onProgress) { + loadingTask.onProgress({ + loaded: evt.loaded, + total: evt.total + }); + } + }; + } + headersCapability.resolve({ + isStreamingSupported: fullReader.isStreamingSupported, + isRangeSupported: fullReader.isRangeSupported, + contentLength: fullReader.contentLength + }); + }, headersCapability.reject); + return headersCapability.promise; + }, this); + messageHandler.on('GetRangeReader', function (data, sink) { + (0, _util.assert)(this._networkStream); + var _rangeReader = this._networkStream.getRangeReader(data.begin, data.end); + sink.onPull = function () { + _rangeReader.read().then(function (_ref3) { + var value = _ref3.value, + done = _ref3.done; + + if (done) { + sink.close(); + return; + } + (0, _util.assert)((0, _util.isArrayBuffer)(value)); + sink.enqueue(new Uint8Array(value), 1, [value]); + }).catch(function (reason) { + sink.error(reason); + }); + }; + sink.onCancel = function (reason) { + _rangeReader.cancel(reason); + }; + }, this); + messageHandler.on('GetDoc', function transportDoc(data) { + var pdfInfo = data.pdfInfo; + this.numPages = data.pdfInfo.numPages; + var loadingTask = this.loadingTask; + var pdfDocument = new PDFDocumentProxy(pdfInfo, this, loadingTask); + this.pdfDocument = pdfDocument; + loadingTask._capability.resolve(pdfDocument); + }, this); + messageHandler.on('PasswordRequest', function transportPasswordRequest(exception) { + var _this11 = this; + + this._passwordCapability = (0, _util.createPromiseCapability)(); + if (loadingTask.onPassword) { + var updatePassword = function updatePassword(password) { + _this11._passwordCapability.resolve({password: password}); + }; + loadingTask.onPassword(updatePassword, exception.code); + } else { + this._passwordCapability.reject(new _util.PasswordException(exception.message, exception.code)); + } + return this._passwordCapability.promise; + }, this); + messageHandler.on('PasswordException', function transportPasswordException(exception) { + loadingTask._capability.reject(new _util.PasswordException(exception.message, exception.code)); + }, this); + messageHandler.on('InvalidPDF', function transportInvalidPDF(exception) { + this.loadingTask._capability.reject(new _util.InvalidPDFException(exception.message)); + }, this); + messageHandler.on('MissingPDF', function transportMissingPDF(exception) { + this.loadingTask._capability.reject(new _util.MissingPDFException(exception.message)); + }, this); + messageHandler.on('UnexpectedResponse', function transportUnexpectedResponse(exception) { + this.loadingTask._capability.reject(new _util.UnexpectedResponseException(exception.message, exception.status)); + }, this); + messageHandler.on('UnknownError', function transportUnknownError(exception) { + this.loadingTask._capability.reject(new _util.UnknownErrorException(exception.message, exception.details)); + }, this); + messageHandler.on('DataLoaded', function transportPage(data) { + this.downloadInfoCapability.resolve(data); + }, this); + messageHandler.on('PDFManagerReady', function transportPage(data) { + }, this); + messageHandler.on('StartRenderPage', function transportRender(data) { + if (this.destroyed) { + return; + } + var page = this.pageCache[data.pageIndex]; + page.stats.timeEnd('Page Request'); + page._startRenderPage(data.transparency, data.intent); + }, this); + messageHandler.on('RenderPageChunk', function transportRender(data) { + if (this.destroyed) { + return; + } + var page = this.pageCache[data.pageIndex]; + page._renderPageChunk(data.operatorList, data.intent); + }, this); + messageHandler.on('commonobj', function transportObj(data) { + var _this12 = this; + + if (this.destroyed) { + return; + } + var id = data[0]; + var type = data[1]; + if (this.commonObjs.hasData(id)) { + return; + } + switch (type) { + case 'Font': + var exportedData = data[2]; + if ('error' in exportedData) { + var exportedError = exportedData.error; + (0, _util.warn)('Error during font loading: ' + exportedError); + this.commonObjs.resolve(id, exportedError); + break; + } + var fontRegistry = null; + if ((0, _dom_utils.getDefaultSetting)('pdfBug') && _util.globalScope.FontInspector && _util.globalScope['FontInspector'].enabled) { + fontRegistry = { + registerFont: function registerFont(font, url) { + _util.globalScope['FontInspector'].fontAdded(font, url); + } + }; + } + var font = new _font_loader.FontFaceObject(exportedData, { + isEvalSuported: (0, _dom_utils.getDefaultSetting)('isEvalSupported'), + disableFontFace: (0, _dom_utils.getDefaultSetting)('disableFontFace'), + fontRegistry: fontRegistry + }); + var fontReady = function fontReady(fontObjs) { + _this12.commonObjs.resolve(id, font); + }; + this.fontLoader.bind([font], fontReady); + break; + case 'FontPath': + this.commonObjs.resolve(id, data[2]); + break; + default: + throw new Error('Got unknown common object type ' + type); + } + }, this); + messageHandler.on('obj', function transportObj(data) { + if (this.destroyed) { + return; + } + var id = data[0]; + var pageIndex = data[1]; + var type = data[2]; + var pageProxy = this.pageCache[pageIndex]; + var imageData; + if (pageProxy.objs.hasData(id)) { + return; + } + switch (type) { + case 'JpegStream': + imageData = data[3]; + (0, _util.loadJpegStream)(id, imageData, pageProxy.objs); + break; + case 'Image': + imageData = data[3]; + pageProxy.objs.resolve(id, imageData); + var MAX_IMAGE_SIZE_TO_STORE = 8000000; + if (imageData && 'data' in imageData && imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) { + pageProxy.cleanupAfterRender = true; + } + break; + default: + throw new Error('Got unknown object type ' + type); + } + }, this); + messageHandler.on('DocProgress', function transportDocProgress(data) { + if (this.destroyed) { + return; + } + var loadingTask = this.loadingTask; + if (loadingTask.onProgress) { + loadingTask.onProgress({ + loaded: data.loaded, + total: data.total + }); + } + }, this); + messageHandler.on('PageError', function transportError(data) { + if (this.destroyed) { + return; + } + var page = this.pageCache[data.pageNum - 1]; + var intentState = page.intentStates[data.intent]; + if (intentState.displayReadyCapability) { + intentState.displayReadyCapability.reject(data.error); + } else { + throw new Error(data.error); + } + if (intentState.operatorList) { + intentState.operatorList.lastChunk = true; + for (var i = 0; i < intentState.renderTasks.length; i++) { + intentState.renderTasks[i].operatorListChanged(); + } + } + }, this); + messageHandler.on('UnsupportedFeature', function transportUnsupportedFeature(data) { + if (this.destroyed) { + return; + } + var featureId = data.featureId; + var loadingTask = this.loadingTask; + if (loadingTask.onUnsupportedFeature) { + loadingTask.onUnsupportedFeature(featureId); + } + _UnsupportedManager.notify(featureId); + }, this); + messageHandler.on('JpegDecode', function (data) { + if (this.destroyed) { + return Promise.reject(new Error('Worker was destroyed')); + } + if (typeof document === 'undefined') { + return Promise.reject(new Error('"document" is not defined.')); + } + var imageUrl = data[0]; + var components = data[1]; + if (components !== 3 && components !== 1) { + return Promise.reject(new Error('Only 3 components or 1 component can be returned')); + } + return new Promise(function (resolve, reject) { + var img = new Image(); + img.onload = function () { + var width = img.width; + var height = img.height; + var size = width * height; + var rgbaLength = size * 4; + var buf = new Uint8Array(size * components); + var tmpCanvas = document.createElement('canvas'); + tmpCanvas.width = width; + tmpCanvas.height = height; + var tmpCtx = tmpCanvas.getContext('2d'); + tmpCtx.drawImage(img, 0, 0); + var data = tmpCtx.getImageData(0, 0, width, height).data; + var i, j; + if (components === 3) { + for (i = 0, j = 0; i < rgbaLength; i += 4, j += 3) { + buf[j] = data[i]; + buf[j + 1] = data[i + 1]; + buf[j + 2] = data[i + 2]; + } + } else if (components === 1) { + for (i = 0, j = 0; i < rgbaLength; i += 4, j++) { + buf[j] = data[i]; + } + } + resolve({ + data: buf, + width: width, + height: height + }); + }; + img.onerror = function () { + reject(new Error('JpegDecode failed to load image')); + }; + img.src = imageUrl; + }); + }, this); + messageHandler.on('FetchBuiltInCMap', function (data) { + if (this.destroyed) { + return Promise.reject(new Error('Worker was destroyed')); + } + return this.CMapReaderFactory.fetch({name: data.name}); + }, this); + }, + getData: function WorkerTransport_getData() { + return this.messageHandler.sendWithPromise('GetData', null); + }, + getPage: function WorkerTransport_getPage(pageNumber, capability) { + var _this13 = this; + + if (!(0, _util.isInt)(pageNumber) || pageNumber <= 0 || pageNumber > this.numPages) { + return Promise.reject(new Error('Invalid page request')); + } + var pageIndex = pageNumber - 1; + if (pageIndex in this.pagePromises) { + return this.pagePromises[pageIndex]; + } + var promise = this.messageHandler.sendWithPromise('GetPage', {pageIndex: pageIndex}).then(function (pageInfo) { + if (_this13.destroyed) { + throw new Error('Transport destroyed'); + } + var page = new PDFPageProxy(pageIndex, pageInfo, _this13); + _this13.pageCache[pageIndex] = page; + return page; + }); + this.pagePromises[pageIndex] = promise; + return promise; + }, + getPageIndex: function WorkerTransport_getPageIndexByRef(ref) { + return this.messageHandler.sendWithPromise('GetPageIndex', {ref: ref}).catch(function (reason) { + return Promise.reject(new Error(reason)); + }); + }, + getAnnotations: function WorkerTransport_getAnnotations(pageIndex, intent) { + return this.messageHandler.sendWithPromise('GetAnnotations', { + pageIndex: pageIndex, + intent: intent + }); + }, + getDestinations: function WorkerTransport_getDestinations() { + return this.messageHandler.sendWithPromise('GetDestinations', null); + }, + getDestination: function WorkerTransport_getDestination(id) { + return this.messageHandler.sendWithPromise('GetDestination', {id: id}); + }, + getPageLabels: function WorkerTransport_getPageLabels() { + return this.messageHandler.sendWithPromise('GetPageLabels', null); + }, + getPageMode: function getPageMode() { + return this.messageHandler.sendWithPromise('GetPageMode', null); + }, + + getAttachments: function WorkerTransport_getAttachments() { + return this.messageHandler.sendWithPromise('GetAttachments', null); + }, + getJavaScript: function WorkerTransport_getJavaScript() { + return this.messageHandler.sendWithPromise('GetJavaScript', null); + }, + getOutline: function WorkerTransport_getOutline() { + return this.messageHandler.sendWithPromise('GetOutline', null); + }, + getMetadata: function WorkerTransport_getMetadata() { + return this.messageHandler.sendWithPromise('GetMetadata', null).then(function transportMetadata(results) { + return { + info: results[0], + metadata: results[1] ? new _metadata.Metadata(results[1]) : null + }; + }); + }, + getStats: function WorkerTransport_getStats() { + return this.messageHandler.sendWithPromise('GetStats', null); + }, + startCleanup: function WorkerTransport_startCleanup() { + var _this14 = this; + + this.messageHandler.sendWithPromise('Cleanup', null).then(function () { + for (var i = 0, ii = _this14.pageCache.length; i < ii; i++) { + var page = _this14.pageCache[i]; + if (page) { + page.cleanup(); + } + } + _this14.commonObjs.clear(); + _this14.fontLoader.clear(); + }); + } + }; + return WorkerTransport; + }(); + var PDFObjects = function PDFObjectsClosure() { + function PDFObjects() { + this.objs = Object.create(null); + } + + PDFObjects.prototype = { + ensureObj: function PDFObjects_ensureObj(objId) { + if (this.objs[objId]) { + return this.objs[objId]; + } + var obj = { + capability: (0, _util.createPromiseCapability)(), + data: null, + resolved: false + }; + this.objs[objId] = obj; + return obj; + }, + get: function PDFObjects_get(objId, callback) { + if (callback) { + this.ensureObj(objId).capability.promise.then(callback); + return null; + } + var obj = this.objs[objId]; + if (!obj || !obj.resolved) { + throw new Error('Requesting object that isn\'t resolved yet ' + objId); + } + return obj.data; + }, + resolve: function PDFObjects_resolve(objId, data) { + var obj = this.ensureObj(objId); + obj.resolved = true; + obj.data = data; + obj.capability.resolve(data); + }, + isResolved: function PDFObjects_isResolved(objId) { + var objs = this.objs; + if (!objs[objId]) { + return false; + } + return objs[objId].resolved; + }, + hasData: function PDFObjects_hasData(objId) { + return this.isResolved(objId); + }, + getData: function PDFObjects_getData(objId) { + var objs = this.objs; + if (!objs[objId] || !objs[objId].resolved) { + return null; + } + return objs[objId].data; + }, + clear: function PDFObjects_clear() { + this.objs = Object.create(null); + } + }; + return PDFObjects; + }(); + var RenderTask = function RenderTaskClosure() { + function RenderTask(internalRenderTask) { + this._internalRenderTask = internalRenderTask; + this.onContinue = null; + } + + RenderTask.prototype = { + get promise() { + return this._internalRenderTask.capability.promise; + }, + cancel: function RenderTask_cancel() { + this._internalRenderTask.cancel(); + }, + then: function RenderTask_then(onFulfilled, onRejected) { + return this.promise.then.apply(this.promise, arguments); + } + }; + return RenderTask; + }(); + var InternalRenderTask = function InternalRenderTaskClosure() { + var canvasInRendering = new WeakMap(); + + function InternalRenderTask(callback, params, objs, commonObjs, operatorList, pageNumber, canvasFactory) { + this.callback = callback; + this.params = params; + this.objs = objs; + this.commonObjs = commonObjs; + this.operatorListIdx = null; + this.operatorList = operatorList; + this.pageNumber = pageNumber; + this.canvasFactory = canvasFactory; + this.running = false; + this.graphicsReadyCallback = null; + this.graphicsReady = false; + this.useRequestAnimationFrame = false; + 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; + } + + InternalRenderTask.prototype = { + initializeGraphics: function InternalRenderTask_initializeGraphics(transparency) { + 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.set(this._canvas, this); + } + if (this.cancelled) { + return; + } + if ((0, _dom_utils.getDefaultSetting)('pdfBug') && _util.globalScope.StepperManager && _util.globalScope.StepperManager.enabled) { + this.stepper = _util.globalScope.StepperManager.create(this.pageNumber - 1); + this.stepper.init(this.operatorList); + this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint(); + } + var params = this.params; + this.gfx = new _canvas.CanvasGraphics(params.canvasContext, this.commonObjs, this.objs, this.canvasFactory, params.imageLayer); + this.gfx.beginDrawing({ + transform: params.transform, + viewport: params.viewport, + transparency: transparency, + background: params.background + }); + this.operatorListIdx = 0; + this.graphicsReady = true; + if (this.graphicsReadyCallback) { + this.graphicsReadyCallback(); + } + }, + cancel: function InternalRenderTask_cancel() { + this.running = false; + this.cancelled = true; + if (this._canvas) { + canvasInRendering.delete(this._canvas); + } + if ((0, _dom_utils.getDefaultSetting)('pdfjsNext')) { + this.callback(new _dom_utils.RenderingCancelledException('Rendering cancelled, page ' + this.pageNumber, 'canvas')); + } else { + this.callback('cancelled'); + } + }, + operatorListChanged: function InternalRenderTask_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: function InternalRenderTask__continue() { + this.running = true; + if (this.cancelled) { + return; + } + if (this.task.onContinue) { + this.task.onContinue(this._scheduleNextBound); + } else { + this._scheduleNext(); + } + }, + _scheduleNext: function InternalRenderTask__scheduleNext() { + if (this.useRequestAnimationFrame && typeof window !== 'undefined') { + window.requestAnimationFrame(this._nextBound); + } else { + Promise.resolve(undefined).then(this._nextBound); + } + }, + _next: function InternalRenderTask__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(); + } + } + } + }; + return InternalRenderTask; + }(); + var _UnsupportedManager = function UnsupportedManagerClosure() { + var listeners = []; + return { + listen: function listen(cb) { + (0, _util.deprecated)('Global UnsupportedManager.listen is used: ' + ' use PDFDocumentLoadingTask.onUnsupportedFeature instead'); + listeners.push(cb); + }, + notify: function notify(featureId) { + for (var i = 0, ii = listeners.length; i < ii; i++) { + listeners[i](featureId); + } + } + }; + }(); + var version, build; + { + exports.version = version = '1.9.426'; + exports.build = build = '2558a58d'; + } + exports.getDocument = getDocument; + exports.LoopbackPort = LoopbackPort; + exports.PDFDataRangeTransport = PDFDataRangeTransport; + exports.PDFWorker = PDFWorker; + exports.PDFDocumentProxy = PDFDocumentProxy; + exports.PDFPageProxy = PDFPageProxy; + exports.setPDFNetworkStreamClass = setPDFNetworkStreamClass; + exports._UnsupportedManager = _UnsupportedManager; + exports.version = version; + exports.build = build; + + /***/ + }), + /* 3 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.AnnotationLayer = undefined; + + var _dom_utils = __w_pdfjs_require__(1); + + var _util = __w_pdfjs_require__(0); + + function AnnotationElementFactory() { + } + + AnnotationElementFactory.prototype = { + create: function AnnotationElementFactory_create(parameters) { + var subtype = parameters.data.annotationType; + switch (subtype) { + case _util.AnnotationType.LINK: + return new LinkAnnotationElement(parameters); + case _util.AnnotationType.TEXT: + return new TextAnnotationElement(parameters); + case _util.AnnotationType.WIDGET: + var fieldType = parameters.data.fieldType; + switch (fieldType) { + case 'Tx': + return new TextWidgetAnnotationElement(parameters); + case 'Btn': + if (parameters.data.radioButton) { + return new RadioButtonWidgetAnnotationElement(parameters); + } else if (parameters.data.checkBox) { + return new CheckboxWidgetAnnotationElement(parameters); + } + (0, _util.warn)('Unimplemented button widget annotation: pushbutton'); + break; + case 'Ch': + return new ChoiceWidgetAnnotationElement(parameters); + } + return new WidgetAnnotationElement(parameters); + case _util.AnnotationType.POPUP: + return new PopupAnnotationElement(parameters); + case _util.AnnotationType.LINE: + return new LineAnnotationElement(parameters); + case _util.AnnotationType.HIGHLIGHT: + return new HighlightAnnotationElement(parameters); + case _util.AnnotationType.UNDERLINE: + return new UnderlineAnnotationElement(parameters); + case _util.AnnotationType.SQUIGGLY: + return new SquigglyAnnotationElement(parameters); + case _util.AnnotationType.STRIKEOUT: + return new StrikeOutAnnotationElement(parameters); + case _util.AnnotationType.FILEATTACHMENT: + return new FileAttachmentAnnotationElement(parameters); + default: + return new AnnotationElement(parameters); + } + } + }; + var AnnotationElement = function AnnotationElementClosure() { + function AnnotationElement(parameters, isRenderable, ignoreBorder) { + this.isRenderable = isRenderable || false; + this.data = parameters.data; + this.layer = parameters.layer; + this.page = parameters.page; + this.viewport = parameters.viewport; + this.linkService = parameters.linkService; + this.downloadManager = parameters.downloadManager; + this.imageResourcesPath = parameters.imageResourcesPath; + this.renderInteractiveForms = parameters.renderInteractiveForms; + if (isRenderable) { + this.container = this._createContainer(ignoreBorder); + } + } + + AnnotationElement.prototype = { + _createContainer: function AnnotationElement_createContainer(ignoreBorder) { + var data = this.data, + page = this.page, + viewport = this.viewport; + var container = document.createElement('section'); + var width = data.rect[2] - data.rect[0]; + var height = data.rect[3] - data.rect[1]; + container.setAttribute('data-annotation-id', data.id); + var 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]]); + _dom_utils.CustomStyle.setProp('transform', container, 'matrix(' + viewport.transform.join(',') + ')'); + _dom_utils.CustomStyle.setProp('transformOrigin', container, -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; + } + var horizontalRadius = data.borderStyle.horizontalCornerRadius; + var verticalRadius = data.borderStyle.verticalCornerRadius; + if (horizontalRadius > 0 || verticalRadius > 0) { + var radius = horizontalRadius + 'px / ' + verticalRadius + 'px'; + _dom_utils.CustomStyle.setProp('borderRadius', container, radius); + } + switch (data.borderStyle.style) { + case _util.AnnotationBorderStyleType.SOLID: + container.style.borderStyle = 'solid'; + break; + case _util.AnnotationBorderStyleType.DASHED: + container.style.borderStyle = 'dashed'; + break; + case _util.AnnotationBorderStyleType.BEVELED: + (0, _util.warn)('Unimplemented border style: beveled'); + break; + case _util.AnnotationBorderStyleType.INSET: + (0, _util.warn)('Unimplemented border style: inset'); + break; + case _util.AnnotationBorderStyleType.UNDERLINE: + container.style.borderBottomStyle = 'solid'; + break; + default: + break; + } + if (data.color) { + container.style.borderColor = _util.Util.makeCssRgb(data.color[0] | 0, data.color[1] | 0, data.color[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'; + return container; + }, + _createPopup: function AnnotationElement_createPopup(container, trigger, data) { + if (!trigger) { + trigger = document.createElement('div'); + trigger.style.height = container.style.height; + trigger.style.width = container.style.width; + container.appendChild(trigger); + } + var popupElement = new PopupElement({ + container: container, + trigger: trigger, + color: data.color, + title: data.title, + contents: data.contents, + hideWrapper: true + }); + var popup = popupElement.render(); + popup.style.left = container.style.width; + container.appendChild(popup); + }, + render: function AnnotationElement_render() { + throw new Error('Abstract method AnnotationElement.render called'); + } + }; + return AnnotationElement; + }(); + var LinkAnnotationElement = function LinkAnnotationElementClosure() { + function LinkAnnotationElement(parameters) { + AnnotationElement.call(this, parameters, true); + } + + _util.Util.inherit(LinkAnnotationElement, AnnotationElement, { + render: function LinkAnnotationElement_render() { + this.container.className = 'linkAnnotation'; + var link = document.createElement('a'); + (0, _dom_utils.addLinkAttributes)(link, { + url: this.data.url, + target: this.data.newWindow ? _dom_utils.LinkTarget.BLANK : undefined + }); + if (!this.data.url) { + if (this.data.action) { + this._bindNamedAction(link, this.data.action); + } else { + this._bindLink(link, this.data.dest); + } + } + this.container.appendChild(link); + return this.container; + }, + _bindLink: function _bindLink(link, destination) { + var _this = this; + + link.href = this.linkService.getDestinationHash(destination); + link.onclick = function () { + if (destination) { + _this.linkService.navigateTo(destination); + } + return false; + }; + if (destination) { + link.className = 'internalLink'; + } + }, + _bindNamedAction: function _bindNamedAction(link, action) { + var _this2 = this; + + link.href = this.linkService.getAnchorUrl(''); + link.onclick = function () { + _this2.linkService.executeNamedAction(action); + return false; + }; + link.className = 'internalLink'; + } + }); + return LinkAnnotationElement; + }(); + var TextAnnotationElement = function TextAnnotationElementClosure() { + function TextAnnotationElement(parameters) { + var isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); + AnnotationElement.call(this, parameters, isRenderable); + } + + _util.Util.inherit(TextAnnotationElement, AnnotationElement, { + render: function TextAnnotationElement_render() { + this.container.className = 'textAnnotation'; + var 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'; + image.dataset.l10nArgs = JSON.stringify({type: this.data.name}); + if (!this.data.hasPopup) { + this._createPopup(this.container, image, this.data); + } + this.container.appendChild(image); + return this.container; + } + }); + return TextAnnotationElement; + }(); + var WidgetAnnotationElement = function WidgetAnnotationElementClosure() { + function WidgetAnnotationElement(parameters, isRenderable) { + AnnotationElement.call(this, parameters, isRenderable); + } + + _util.Util.inherit(WidgetAnnotationElement, AnnotationElement, { + render: function WidgetAnnotationElement_render() { + return this.container; + } + }); + return WidgetAnnotationElement; + }(); + var TextWidgetAnnotationElement = function TextWidgetAnnotationElementClosure() { + var TEXT_ALIGNMENT = ['left', 'center', 'right']; + + function TextWidgetAnnotationElement(parameters) { + var isRenderable = parameters.renderInteractiveForms || !parameters.data.hasAppearance && !!parameters.data.fieldValue; + WidgetAnnotationElement.call(this, parameters, isRenderable); + } + + _util.Util.inherit(TextWidgetAnnotationElement, WidgetAnnotationElement, { + render: function TextWidgetAnnotationElement_render() { + this.container.className = 'textWidgetAnnotation'; + var element = null; + if (this.renderInteractiveForms) { + if (this.data.multiLine) { + element = document.createElement('textarea'); + element.textContent = this.data.fieldValue; + } else { + element = document.createElement('input'); + element.type = 'text'; + element.setAttribute('value', this.data.fieldValue); + } + element.disabled = this.data.readOnly; + if (this.data.maxLen !== null) { + element.maxLength = this.data.maxLen; + } + if (this.data.comb) { + var fieldWidth = this.data.rect[2] - this.data.rect[0]; + var combWidth = fieldWidth / this.data.maxLen; + element.classList.add('comb'); + element.style.letterSpacing = 'calc(' + combWidth + 'px - 1ch)'; + } + } else { + element = document.createElement('div'); + element.textContent = this.data.fieldValue; + element.style.verticalAlign = 'middle'; + element.style.display = 'table-cell'; + var font = null; + if (this.data.fontRefName) { + font = this.page.commonObjs.getData(this.data.fontRefName); + } + this._setTextStyle(element, font); + } + if (this.data.textAlignment !== null) { + element.style.textAlign = TEXT_ALIGNMENT[this.data.textAlignment]; + } + this.container.appendChild(element); + return this.container; + }, + _setTextStyle: function TextWidgetAnnotationElement_setTextStyle(element, font) { + var style = element.style; + style.fontSize = this.data.fontSize + 'px'; + style.direction = this.data.fontDirection < 0 ? 'rtl' : 'ltr'; + if (!font) { + return; + } + style.fontWeight = font.black ? font.bold ? '900' : 'bold' : font.bold ? 'bold' : 'normal'; + style.fontStyle = font.italic ? 'italic' : 'normal'; + var fontFamily = font.loadedName ? '"' + font.loadedName + '", ' : ''; + var fallbackName = font.fallbackName || 'Helvetica, sans-serif'; + style.fontFamily = fontFamily + fallbackName; + } + }); + return TextWidgetAnnotationElement; + }(); + var CheckboxWidgetAnnotationElement = function CheckboxWidgetAnnotationElementClosure() { + function CheckboxWidgetAnnotationElement(parameters) { + WidgetAnnotationElement.call(this, parameters, parameters.renderInteractiveForms); + } + + _util.Util.inherit(CheckboxWidgetAnnotationElement, WidgetAnnotationElement, { + render: function CheckboxWidgetAnnotationElement_render() { + this.container.className = 'buttonWidgetAnnotation checkBox'; + var element = document.createElement('input'); + element.disabled = this.data.readOnly; + element.type = 'checkbox'; + if (this.data.fieldValue && this.data.fieldValue !== 'Off') { + element.setAttribute('checked', true); + } + this.container.appendChild(element); + return this.container; + } + }); + return CheckboxWidgetAnnotationElement; + }(); + var RadioButtonWidgetAnnotationElement = function RadioButtonWidgetAnnotationElementClosure() { + function RadioButtonWidgetAnnotationElement(parameters) { + WidgetAnnotationElement.call(this, parameters, parameters.renderInteractiveForms); + } + + _util.Util.inherit(RadioButtonWidgetAnnotationElement, WidgetAnnotationElement, { + render: function RadioButtonWidgetAnnotationElement_render() { + this.container.className = 'buttonWidgetAnnotation radioButton'; + var element = document.createElement('input'); + element.disabled = this.data.readOnly; + element.type = 'radio'; + element.name = this.data.fieldName; + if (this.data.fieldValue === this.data.buttonValue) { + element.setAttribute('checked', true); + } + this.container.appendChild(element); + return this.container; + } + }); + return RadioButtonWidgetAnnotationElement; + }(); + var ChoiceWidgetAnnotationElement = function ChoiceWidgetAnnotationElementClosure() { + function ChoiceWidgetAnnotationElement(parameters) { + WidgetAnnotationElement.call(this, parameters, parameters.renderInteractiveForms); + } + + _util.Util.inherit(ChoiceWidgetAnnotationElement, WidgetAnnotationElement, { + render: function ChoiceWidgetAnnotationElement_render() { + this.container.className = 'choiceWidgetAnnotation'; + var selectElement = document.createElement('select'); + selectElement.disabled = this.data.readOnly; + if (!this.data.combo) { + selectElement.size = this.data.options.length; + if (this.data.multiSelect) { + selectElement.multiple = true; + } + } + for (var i = 0, ii = this.data.options.length; i < ii; i++) { + var option = this.data.options[i]; + var optionElement = document.createElement('option'); + optionElement.textContent = option.displayValue; + optionElement.value = option.exportValue; + if (this.data.fieldValue.indexOf(option.displayValue) >= 0) { + optionElement.setAttribute('selected', true); + } + selectElement.appendChild(optionElement); + } + this.container.appendChild(selectElement); + return this.container; + } + }); + return ChoiceWidgetAnnotationElement; + }(); + var PopupAnnotationElement = function PopupAnnotationElementClosure() { + var IGNORE_TYPES = ['Line']; + + function PopupAnnotationElement(parameters) { + var isRenderable = !!(parameters.data.title || parameters.data.contents); + AnnotationElement.call(this, parameters, isRenderable); + } + + _util.Util.inherit(PopupAnnotationElement, AnnotationElement, { + render: function PopupAnnotationElement_render() { + this.container.className = 'popupAnnotation'; + if (IGNORE_TYPES.indexOf(this.data.parentType) >= 0) { + return this.container; + } + var selector = '[data-annotation-id="' + this.data.parentId + '"]'; + var parentElement = this.layer.querySelector(selector); + if (!parentElement) { + return this.container; + } + var popup = new PopupElement({ + container: this.container, + trigger: parentElement, + color: this.data.color, + title: this.data.title, + contents: this.data.contents + }); + var parentLeft = parseFloat(parentElement.style.left); + var parentWidth = parseFloat(parentElement.style.width); + _dom_utils.CustomStyle.setProp('transformOrigin', this.container, -(parentLeft + parentWidth) + 'px -' + parentElement.style.top); + this.container.style.left = parentLeft + parentWidth + 'px'; + this.container.appendChild(popup.render()); + return this.container; + } + }); + return PopupAnnotationElement; + }(); + var PopupElement = function PopupElementClosure() { + var BACKGROUND_ENLIGHT = 0.7; + + function PopupElement(parameters) { + this.container = parameters.container; + this.trigger = parameters.trigger; + this.color = parameters.color; + this.title = parameters.title; + this.contents = parameters.contents; + this.hideWrapper = parameters.hideWrapper || false; + this.pinned = false; + } + + PopupElement.prototype = { + render: function PopupElement_render() { + var wrapper = document.createElement('div'); + wrapper.className = 'popupWrapper'; + this.hideElement = this.hideWrapper ? wrapper : this.container; + this.hideElement.setAttribute('hidden', true); + var popup = document.createElement('div'); + popup.className = 'popup'; + var color = this.color; + if (color) { + var r = BACKGROUND_ENLIGHT * (255 - color[0]) + color[0]; + var g = BACKGROUND_ENLIGHT * (255 - color[1]) + color[1]; + var b = BACKGROUND_ENLIGHT * (255 - color[2]) + color[2]; + popup.style.backgroundColor = _util.Util.makeCssRgb(r | 0, g | 0, b | 0); + } + var contents = this._formatContents(this.contents); + var title = document.createElement('h1'); + title.textContent = this.title; + 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)); + popup.appendChild(title); + popup.appendChild(contents); + wrapper.appendChild(popup); + return wrapper; + }, + _formatContents: function PopupElement_formatContents(contents) { + var p = document.createElement('p'); + var lines = contents.split(/(?:\r\n?|\n)/); + for (var i = 0, ii = lines.length; i < ii; ++i) { + var line = lines[i]; + p.appendChild(document.createTextNode(line)); + if (i < ii - 1) { + p.appendChild(document.createElement('br')); + } + } + return p; + }, + _toggle: function PopupElement_toggle() { + if (this.pinned) { + this._hide(true); + } else { + this._show(true); + } + }, + _show: function PopupElement_show(pin) { + if (pin) { + this.pinned = true; + } + if (this.hideElement.hasAttribute('hidden')) { + this.hideElement.removeAttribute('hidden'); + this.container.style.zIndex += 1; + } + }, + _hide: function PopupElement_hide(unpin) { + if (unpin) { + this.pinned = false; + } + if (!this.hideElement.hasAttribute('hidden') && !this.pinned) { + this.hideElement.setAttribute('hidden', true); + this.container.style.zIndex -= 1; + } + } + }; + return PopupElement; + }(); + var LineAnnotationElement = function LineAnnotationElementClosure() { + var SVG_NS = 'http://www.w3.org/2000/svg'; + + function LineAnnotationElement(parameters) { + var isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); + AnnotationElement.call(this, parameters, isRenderable, true); + } + + _util.Util.inherit(LineAnnotationElement, AnnotationElement, { + render: function LineAnnotationElement_render() { + this.container.className = 'lineAnnotation'; + var data = this.data; + var width = data.rect[2] - data.rect[0]; + var height = data.rect[3] - data.rect[1]; + var svg = document.createElementNS(SVG_NS, 'svg:svg'); + svg.setAttributeNS(null, 'version', '1.1'); + svg.setAttributeNS(null, 'width', width + 'px'); + svg.setAttributeNS(null, 'height', height + 'px'); + svg.setAttributeNS(null, 'preserveAspectRatio', 'none'); + svg.setAttributeNS(null, 'viewBox', '0 0 ' + width + ' ' + height); + var line = document.createElementNS(SVG_NS, 'svg:line'); + line.setAttributeNS(null, 'x1', data.rect[2] - data.lineCoordinates[0]); + line.setAttributeNS(null, 'y1', data.rect[3] - data.lineCoordinates[1]); + line.setAttributeNS(null, 'x2', data.rect[2] - data.lineCoordinates[2]); + line.setAttributeNS(null, 'y2', data.rect[3] - data.lineCoordinates[3]); + line.setAttributeNS(null, 'stroke-width', data.borderStyle.width); + line.setAttributeNS(null, 'stroke', 'transparent'); + svg.appendChild(line); + this.container.append(svg); + this._createPopup(this.container, line, this.data); + return this.container; + } + }); + return LineAnnotationElement; + }(); + var HighlightAnnotationElement = function HighlightAnnotationElementClosure() { + function HighlightAnnotationElement(parameters) { + var isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); + AnnotationElement.call(this, parameters, isRenderable, true); + } + + _util.Util.inherit(HighlightAnnotationElement, AnnotationElement, { + render: function HighlightAnnotationElement_render() { + this.container.className = 'highlightAnnotation'; + if (!this.data.hasPopup) { + this._createPopup(this.container, null, this.data); + } + return this.container; + } + }); + return HighlightAnnotationElement; + }(); + var UnderlineAnnotationElement = function UnderlineAnnotationElementClosure() { + function UnderlineAnnotationElement(parameters) { + var isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); + AnnotationElement.call(this, parameters, isRenderable, true); + } + + _util.Util.inherit(UnderlineAnnotationElement, AnnotationElement, { + render: function UnderlineAnnotationElement_render() { + this.container.className = 'underlineAnnotation'; + if (!this.data.hasPopup) { + this._createPopup(this.container, null, this.data); + } + return this.container; + } + }); + return UnderlineAnnotationElement; + }(); + var SquigglyAnnotationElement = function SquigglyAnnotationElementClosure() { + function SquigglyAnnotationElement(parameters) { + var isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); + AnnotationElement.call(this, parameters, isRenderable, true); + } + + _util.Util.inherit(SquigglyAnnotationElement, AnnotationElement, { + render: function SquigglyAnnotationElement_render() { + this.container.className = 'squigglyAnnotation'; + if (!this.data.hasPopup) { + this._createPopup(this.container, null, this.data); + } + return this.container; + } + }); + return SquigglyAnnotationElement; + }(); + var StrikeOutAnnotationElement = function StrikeOutAnnotationElementClosure() { + function StrikeOutAnnotationElement(parameters) { + var isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); + AnnotationElement.call(this, parameters, isRenderable, true); + } + + _util.Util.inherit(StrikeOutAnnotationElement, AnnotationElement, { + render: function StrikeOutAnnotationElement_render() { + this.container.className = 'strikeoutAnnotation'; + if (!this.data.hasPopup) { + this._createPopup(this.container, null, this.data); + } + return this.container; + } + }); + return StrikeOutAnnotationElement; + }(); + var FileAttachmentAnnotationElement = function FileAttachmentAnnotationElementClosure() { + function FileAttachmentAnnotationElement(parameters) { + AnnotationElement.call(this, parameters, true); + var file = this.data.file; + this.filename = (0, _dom_utils.getFilenameFromUrl)(file.filename); + this.content = file.content; + this.linkService.onFileAttachmentAnnotation({ + id: (0, _util.stringToPDFString)(file.filename), + filename: file.filename, + content: file.content + }); + } + + _util.Util.inherit(FileAttachmentAnnotationElement, AnnotationElement, { + render: function FileAttachmentAnnotationElement_render() { + this.container.className = 'fileAttachmentAnnotation'; + var trigger = document.createElement('div'); + trigger.style.height = this.container.style.height; + trigger.style.width = this.container.style.width; + trigger.addEventListener('dblclick', this._download.bind(this)); + if (!this.data.hasPopup && (this.data.title || this.data.contents)) { + this._createPopup(this.container, trigger, this.data); + } + this.container.appendChild(trigger); + return this.container; + }, + _download: function FileAttachmentAnnotationElement_download() { + if (!this.downloadManager) { + (0, _util.warn)('Download cannot be started due to unavailable download manager'); + return; + } + this.downloadManager.downloadData(this.content, this.filename, ''); + } + }); + return FileAttachmentAnnotationElement; + }(); + var AnnotationLayer = function AnnotationLayerClosure() { + return { + render: function AnnotationLayer_render(parameters) { + var annotationElementFactory = new AnnotationElementFactory(); + for (var i = 0, ii = parameters.annotations.length; i < ii; i++) { + var data = parameters.annotations[i]; + if (!data) { + continue; + } + var element = annotationElementFactory.create({ + data: data, + layer: parameters.div, + page: parameters.page, + viewport: parameters.viewport, + linkService: parameters.linkService, + downloadManager: parameters.downloadManager, + imageResourcesPath: parameters.imageResourcesPath || (0, _dom_utils.getDefaultSetting)('imageResourcesPath'), + renderInteractiveForms: parameters.renderInteractiveForms || false + }); + if (element.isRenderable) { + parameters.div.appendChild(element.render()); + } + } + }, + update: function AnnotationLayer_update(parameters) { + for (var i = 0, ii = parameters.annotations.length; i < ii; i++) { + var data = parameters.annotations[i]; + var element = parameters.div.querySelector('[data-annotation-id="' + data.id + '"]'); + if (element) { + _dom_utils.CustomStyle.setProp('transform', element, 'matrix(' + parameters.viewport.transform.join(',') + ')'); + } + } + parameters.div.removeAttribute('hidden'); + } + }; + }(); + exports.AnnotationLayer = AnnotationLayer; + + /***/ + }), + /* 4 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.SVGGraphics = undefined; + + var _util = __w_pdfjs_require__(0); + + var SVGGraphics = function SVGGraphics() { + throw new Error('Not implemented: SVGGraphics'); + }; + { + var SVG_DEFAULTS = { + fontStyle: 'normal', + fontWeight: 'normal', + fillColor: '#000000' + }; + var convertImgDataToPng = function convertImgDataToPngClosure() { + var PNG_HEADER = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]); + var CHUNK_WRAPPER_SIZE = 12; + var crcTable = new Int32Array(256); + for (var i = 0; i < 256; i++) { + var c = i; + for (var h = 0; h < 8; h++) { + if (c & 1) { + c = 0xedB88320 ^ c >> 1 & 0x7fffffff; + } else { + c = c >> 1 & 0x7fffffff; + } + } + crcTable[i] = c; + } + + function crc32(data, start, end) { + var crc = -1; + for (var i = start; i < end; i++) { + var a = (crc ^ data[i]) & 0xff; + var b = crcTable[a]; + crc = crc >>> 8 ^ b; + } + return crc ^ -1; + } + + function writePngChunk(type, body, data, offset) { + var p = offset; + var len = body.length; + data[p] = len >> 24 & 0xff; + data[p + 1] = len >> 16 & 0xff; + data[p + 2] = len >> 8 & 0xff; + data[p + 3] = len & 0xff; + p += 4; + data[p] = type.charCodeAt(0) & 0xff; + data[p + 1] = type.charCodeAt(1) & 0xff; + data[p + 2] = type.charCodeAt(2) & 0xff; + data[p + 3] = type.charCodeAt(3) & 0xff; + p += 4; + data.set(body, p); + p += body.length; + var crc = crc32(data, offset + 4, p); + data[p] = crc >> 24 & 0xff; + data[p + 1] = crc >> 16 & 0xff; + data[p + 2] = crc >> 8 & 0xff; + data[p + 3] = crc & 0xff; + } + + function adler32(data, start, end) { + var a = 1; + var b = 0; + for (var i = start; i < end; ++i) { + a = (a + (data[i] & 0xff)) % 65521; + b = (b + a) % 65521; + } + return b << 16 | a; + } + + function deflateSync(literals) { + if (!(0, _util.isNodeJS)()) { + return deflateSyncUncompressed(literals); + } + try { + var input; + if (parseInt(process.versions.node) >= 8) { + input = literals; + } else { + input = new Buffer(literals); + } + var output = require('zlib').deflateSync(input, {level: 9}); + return output instanceof Uint8Array ? output : new Uint8Array(output); + } catch (e) { + (0, _util.warn)('Not compressing PNG because zlib.deflateSync is unavailable: ' + e); + } + return deflateSyncUncompressed(literals); + } + + function deflateSyncUncompressed(literals) { + var len = literals.length; + var maxBlockLength = 0xFFFF; + var deflateBlocks = Math.ceil(len / maxBlockLength); + var idat = new Uint8Array(2 + len + deflateBlocks * 5 + 4); + var pi = 0; + idat[pi++] = 0x78; + idat[pi++] = 0x9c; + var pos = 0; + while (len > maxBlockLength) { + idat[pi++] = 0x00; + idat[pi++] = 0xff; + idat[pi++] = 0xff; + idat[pi++] = 0x00; + idat[pi++] = 0x00; + idat.set(literals.subarray(pos, pos + maxBlockLength), pi); + pi += maxBlockLength; + pos += maxBlockLength; + len -= maxBlockLength; + } + idat[pi++] = 0x01; + idat[pi++] = len & 0xff; + idat[pi++] = len >> 8 & 0xff; + idat[pi++] = ~len & 0xffff & 0xff; + idat[pi++] = (~len & 0xffff) >> 8 & 0xff; + idat.set(literals.subarray(pos), pi); + pi += literals.length - pos; + var adler = adler32(literals, 0, literals.length); + idat[pi++] = adler >> 24 & 0xff; + idat[pi++] = adler >> 16 & 0xff; + idat[pi++] = adler >> 8 & 0xff; + idat[pi++] = adler & 0xff; + return idat; + } + + function encode(imgData, kind, forceDataSchema) { + var width = imgData.width; + var height = imgData.height; + var bitDepth, colorType, lineSize; + var bytes = imgData.data; + switch (kind) { + case _util.ImageKind.GRAYSCALE_1BPP: + colorType = 0; + bitDepth = 1; + lineSize = width + 7 >> 3; + break; + case _util.ImageKind.RGB_24BPP: + colorType = 2; + bitDepth = 8; + lineSize = width * 3; + break; + case _util.ImageKind.RGBA_32BPP: + colorType = 6; + bitDepth = 8; + lineSize = width * 4; + break; + default: + throw new Error('invalid format'); + } + var literals = new Uint8Array((1 + lineSize) * height); + var offsetLiterals = 0, + offsetBytes = 0; + var y, i; + for (y = 0; y < height; ++y) { + literals[offsetLiterals++] = 0; + literals.set(bytes.subarray(offsetBytes, offsetBytes + lineSize), offsetLiterals); + offsetBytes += lineSize; + offsetLiterals += lineSize; + } + if (kind === _util.ImageKind.GRAYSCALE_1BPP) { + offsetLiterals = 0; + for (y = 0; y < height; y++) { + offsetLiterals++; + for (i = 0; i < lineSize; i++) { + literals[offsetLiterals++] ^= 0xFF; + } + } + } + var ihdr = new Uint8Array([width >> 24 & 0xff, width >> 16 & 0xff, width >> 8 & 0xff, width & 0xff, height >> 24 & 0xff, height >> 16 & 0xff, height >> 8 & 0xff, height & 0xff, bitDepth, colorType, 0x00, 0x00, 0x00]); + var idat = deflateSync(literals); + var pngLength = PNG_HEADER.length + CHUNK_WRAPPER_SIZE * 3 + ihdr.length + idat.length; + var data = new Uint8Array(pngLength); + var offset = 0; + data.set(PNG_HEADER, offset); + offset += PNG_HEADER.length; + writePngChunk('IHDR', ihdr, data, offset); + offset += CHUNK_WRAPPER_SIZE + ihdr.length; + 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 function convertImgDataToPng(imgData, forceDataSchema) { + var kind = imgData.kind === undefined ? _util.ImageKind.GRAYSCALE_1BPP : imgData.kind; + return encode(imgData, kind, forceDataSchema); + }; + }(); + var SVGExtraState = function SVGExtraStateClosure() { + function SVGExtraState() { + this.fontSizeScale = 1; + this.fontWeight = SVG_DEFAULTS.fontWeight; + this.fontSize = 0; + this.textMatrix = _util.IDENTITY_MATRIX; + this.fontMatrix = _util.FONT_IDENTITY_MATRIX; + this.leading = 0; + this.x = 0; + this.y = 0; + this.lineX = 0; + this.lineY = 0; + this.charSpacing = 0; + this.wordSpacing = 0; + this.textHScale = 1; + this.textRise = 0; + this.fillColor = SVG_DEFAULTS.fillColor; + this.strokeColor = '#000000'; + this.fillAlpha = 1; + this.strokeAlpha = 1; + this.lineWidth = 1; + this.lineJoin = ''; + this.lineCap = ''; + this.miterLimit = 0; + this.dashArray = []; + this.dashPhase = 0; + this.dependencies = []; + this.activeClipUrl = null; + this.clipGroup = null; + this.maskId = ''; + } + + SVGExtraState.prototype = { + clone: function SVGExtraState_clone() { + return Object.create(this); + }, + setCurrentPoint: function SVGExtraState_setCurrentPoint(x, y) { + this.x = x; + this.y = y; + } + }; + return SVGExtraState; + }(); + exports.SVGGraphics = SVGGraphics = function SVGGraphicsClosure() { + function opListToTree(opList) { + var opTree = []; + var tmp = []; + var opListLen = opList.length; + for (var x = 0; x < opListLen; x++) { + if (opList[x].fn === 'save') { + opTree.push({ + 'fnId': 92, + 'fn': 'group', + 'items': [] + }); + tmp.push(opTree); + opTree = opTree[opTree.length - 1].items; + continue; + } + if (opList[x].fn === 'restore') { + opTree = tmp.pop(); + } else { + opTree.push(opList[x]); + } + } + return opTree; + } + + function pf(value) { + if (value === (value | 0)) { + return value.toString(); + } + var s = value.toFixed(10); + var i = s.length - 1; + if (s[i] !== '0') { + return s; + } + do { + i--; + } while (s[i] === '0'); + return s.substr(0, s[i] === '.' ? i : i + 1); + } + + function pm(m) { + if (m[4] === 0 && m[5] === 0) { + if (m[1] === 0 && m[2] === 0) { + if (m[0] === 1 && m[3] === 1) { + return ''; + } + return 'scale(' + pf(m[0]) + ' ' + pf(m[3]) + ')'; + } + if (m[0] === m[3] && m[1] === -m[2]) { + var a = Math.acos(m[0]) * 180 / Math.PI; + return 'rotate(' + pf(a) + ')'; + } + } else { + if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1) { + return 'translate(' + pf(m[4]) + ' ' + pf(m[5]) + ')'; + } + } + return 'matrix(' + pf(m[0]) + ' ' + pf(m[1]) + ' ' + pf(m[2]) + ' ' + pf(m[3]) + ' ' + pf(m[4]) + ' ' + pf(m[5]) + ')'; + } + + function SVGGraphics(commonObjs, objs, forceDataSchema) { + this.current = new SVGExtraState(); + this.transformMatrix = _util.IDENTITY_MATRIX; + this.transformStack = []; + this.extraStack = []; + this.commonObjs = commonObjs; + this.objs = objs; + this.pendingClip = null; + this.pendingEOFill = false; + this.embedFonts = false; + this.embeddedFonts = Object.create(null); + this.cssStyle = null; + this.forceDataSchema = !!forceDataSchema; + } + + var NS = 'http://www.w3.org/2000/svg'; + var XML_NS = 'http://www.w3.org/XML/1998/namespace'; + var XLINK_NS = 'http://www.w3.org/1999/xlink'; + var LINE_CAP_STYLES = ['butt', 'round', 'square']; + var LINE_JOIN_STYLES = ['miter', 'round', 'bevel']; + var clipCount = 0; + var maskCount = 0; + SVGGraphics.prototype = { + save: function SVGGraphics_save() { + this.transformStack.push(this.transformMatrix); + var old = this.current; + this.extraStack.push(old); + this.current = old.clone(); + }, + restore: function SVGGraphics_restore() { + this.transformMatrix = this.transformStack.pop(); + this.current = this.extraStack.pop(); + this.pendingClip = null; + this.tgrp = null; + }, + group: function SVGGraphics_group(items) { + this.save(); + this.executeOpTree(items); + this.restore(); + }, + loadDependencies: function SVGGraphics_loadDependencies(operatorList) { + var _this = this; + + var fnArray = operatorList.fnArray; + var fnArrayLen = fnArray.length; + var argsArray = operatorList.argsArray; + for (var i = 0; i < fnArrayLen; i++) { + if (_util.OPS.dependency === fnArray[i]) { + var deps = argsArray[i]; + for (var n = 0, nn = deps.length; n < nn; n++) { + var obj = deps[n]; + var common = obj.substring(0, 2) === 'g_'; + var promise; + if (common) { + promise = new Promise(function (resolve) { + _this.commonObjs.get(obj, resolve); + }); + } else { + promise = new Promise(function (resolve) { + _this.objs.get(obj, resolve); + }); + } + this.current.dependencies.push(promise); + } + } + } + return Promise.all(this.current.dependencies); + }, + transform: function SVGGraphics_transform(a, b, c, d, e, f) { + var transformMatrix = [a, b, c, d, e, f]; + this.transformMatrix = _util.Util.transform(this.transformMatrix, transformMatrix); + this.tgrp = null; + }, + getSVG: function SVGGraphics_getSVG(operatorList, viewport) { + var _this2 = this; + + this.viewport = viewport; + var svgElement = this._initialize(viewport); + return this.loadDependencies(operatorList).then(function () { + _this2.transformMatrix = _util.IDENTITY_MATRIX; + var opTree = _this2.convertOpList(operatorList); + _this2.executeOpTree(opTree); + return svgElement; + }); + }, + convertOpList: function SVGGraphics_convertOpList(operatorList) { + var argsArray = operatorList.argsArray; + var fnArray = operatorList.fnArray; + var fnArrayLen = fnArray.length; + var REVOPS = []; + var opList = []; + for (var op in _util.OPS) { + REVOPS[_util.OPS[op]] = op; + } + for (var x = 0; x < fnArrayLen; x++) { + var fnId = fnArray[x]; + opList.push({ + 'fnId': fnId, + 'fn': REVOPS[fnId], + 'args': argsArray[x] + }); + } + return opListToTree(opList); + }, + executeOpTree: function SVGGraphics_executeOpTree(opTree) { + var opTreeLen = opTree.length; + for (var x = 0; x < opTreeLen; x++) { + var fn = opTree[x].fn; + var fnId = opTree[x].fnId; + var args = opTree[x].args; + switch (fnId | 0) { + case _util.OPS.beginText: + this.beginText(); + break; + case _util.OPS.setLeading: + this.setLeading(args); + break; + case _util.OPS.setLeadingMoveText: + this.setLeadingMoveText(args[0], args[1]); + break; + case _util.OPS.setFont: + this.setFont(args); + break; + case _util.OPS.showText: + this.showText(args[0]); + break; + case _util.OPS.showSpacedText: + this.showText(args[0]); + break; + case _util.OPS.endText: + this.endText(); + break; + case _util.OPS.moveText: + this.moveText(args[0], args[1]); + break; + case _util.OPS.setCharSpacing: + this.setCharSpacing(args[0]); + break; + case _util.OPS.setWordSpacing: + this.setWordSpacing(args[0]); + break; + case _util.OPS.setHScale: + this.setHScale(args[0]); + break; + case _util.OPS.setTextMatrix: + this.setTextMatrix(args[0], args[1], args[2], args[3], args[4], args[5]); + break; + case _util.OPS.setLineWidth: + this.setLineWidth(args[0]); + break; + case _util.OPS.setLineJoin: + this.setLineJoin(args[0]); + break; + case _util.OPS.setLineCap: + this.setLineCap(args[0]); + break; + case _util.OPS.setMiterLimit: + this.setMiterLimit(args[0]); + break; + case _util.OPS.setFillRGBColor: + this.setFillRGBColor(args[0], args[1], args[2]); + break; + case _util.OPS.setStrokeRGBColor: + this.setStrokeRGBColor(args[0], args[1], args[2]); + break; + case _util.OPS.setDash: + this.setDash(args[0], args[1]); + break; + case _util.OPS.setGState: + this.setGState(args[0]); + break; + case _util.OPS.fill: + this.fill(); + break; + case _util.OPS.eoFill: + this.eoFill(); + break; + case _util.OPS.stroke: + this.stroke(); + break; + case _util.OPS.fillStroke: + this.fillStroke(); + break; + case _util.OPS.eoFillStroke: + this.eoFillStroke(); + break; + case _util.OPS.clip: + this.clip('nonzero'); + break; + case _util.OPS.eoClip: + this.clip('evenodd'); + break; + case _util.OPS.paintSolidColorImageMask: + this.paintSolidColorImageMask(); + break; + case _util.OPS.paintJpegXObject: + this.paintJpegXObject(args[0], args[1], args[2]); + break; + case _util.OPS.paintImageXObject: + this.paintImageXObject(args[0]); + break; + case _util.OPS.paintInlineImageXObject: + this.paintInlineImageXObject(args[0]); + break; + case _util.OPS.paintImageMaskXObject: + this.paintImageMaskXObject(args[0]); + break; + case _util.OPS.paintFormXObjectBegin: + this.paintFormXObjectBegin(args[0], args[1]); + break; + case _util.OPS.paintFormXObjectEnd: + this.paintFormXObjectEnd(); + break; + case _util.OPS.closePath: + this.closePath(); + break; + case _util.OPS.closeStroke: + this.closeStroke(); + break; + case _util.OPS.closeFillStroke: + this.closeFillStroke(); + break; + case _util.OPS.nextLine: + this.nextLine(); + break; + case _util.OPS.transform: + this.transform(args[0], args[1], args[2], args[3], args[4], args[5]); + break; + case _util.OPS.constructPath: + this.constructPath(args[0], args[1]); + break; + case _util.OPS.endPath: + this.endPath(); + break; + case 92: + this.group(opTree[x].items); + break; + default: + (0, _util.warn)('Unimplemented operator ' + fn); + break; + } + } + }, + setWordSpacing: function SVGGraphics_setWordSpacing(wordSpacing) { + this.current.wordSpacing = wordSpacing; + }, + setCharSpacing: function SVGGraphics_setCharSpacing(charSpacing) { + this.current.charSpacing = charSpacing; + }, + nextLine: function SVGGraphics_nextLine() { + this.moveText(0, this.current.leading); + }, + setTextMatrix: function SVGGraphics_setTextMatrix(a, b, c, d, e, f) { + var current = this.current; + this.current.textMatrix = this.current.lineMatrix = [a, b, c, d, e, f]; + this.current.x = this.current.lineX = 0; + this.current.y = this.current.lineY = 0; + current.xcoords = []; + current.tspan = document.createElementNS(NS, 'svg:tspan'); + current.tspan.setAttributeNS(null, 'font-family', current.fontFamily); + current.tspan.setAttributeNS(null, 'font-size', pf(current.fontSize) + 'px'); + current.tspan.setAttributeNS(null, 'y', pf(-current.y)); + current.txtElement = document.createElementNS(NS, 'svg:text'); + current.txtElement.appendChild(current.tspan); + }, + beginText: function SVGGraphics_beginText() { + this.current.x = this.current.lineX = 0; + this.current.y = this.current.lineY = 0; + this.current.textMatrix = _util.IDENTITY_MATRIX; + this.current.lineMatrix = _util.IDENTITY_MATRIX; + this.current.tspan = document.createElementNS(NS, 'svg:tspan'); + this.current.txtElement = document.createElementNS(NS, 'svg:text'); + this.current.txtgrp = document.createElementNS(NS, 'svg:g'); + this.current.xcoords = []; + }, + moveText: function SVGGraphics_moveText(x, y) { + var current = this.current; + this.current.x = this.current.lineX += x; + this.current.y = this.current.lineY += y; + current.xcoords = []; + current.tspan = document.createElementNS(NS, 'svg:tspan'); + current.tspan.setAttributeNS(null, 'font-family', current.fontFamily); + current.tspan.setAttributeNS(null, 'font-size', pf(current.fontSize) + 'px'); + current.tspan.setAttributeNS(null, 'y', pf(-current.y)); + }, + showText: function SVGGraphics_showText(glyphs) { + var current = this.current; + var font = current.font; + var fontSize = current.fontSize; + if (fontSize === 0) { + return; + } + 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 widthAdvanceScale = fontSize * current.fontMatrix[0]; + var x = 0, + i; + for (i = 0; i < glyphsLength; ++i) { + var glyph = glyphs[i]; + if (glyph === null) { + x += fontDirection * wordSpacing; + continue; + } else if ((0, _util.isNum)(glyph)) { + x += -glyph * fontSize * 0.001; + continue; + } + current.xcoords.push(current.x + x * textHScale); + var width = glyph.width; + var character = glyph.fontChar; + var spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing; + var charWidth = width * widthAdvanceScale + spacing * fontDirection; + x += charWidth; + current.tspan.textContent += character; + } + if (vertical) { + current.y -= x * textHScale; + } else { + current.x += x * textHScale; + } + current.tspan.setAttributeNS(null, 'x', current.xcoords.map(pf).join(' ')); + current.tspan.setAttributeNS(null, 'y', pf(-current.y)); + current.tspan.setAttributeNS(null, 'font-family', current.fontFamily); + current.tspan.setAttributeNS(null, 'font-size', pf(current.fontSize) + 'px'); + if (current.fontStyle !== SVG_DEFAULTS.fontStyle) { + current.tspan.setAttributeNS(null, 'font-style', current.fontStyle); + } + if (current.fontWeight !== SVG_DEFAULTS.fontWeight) { + current.tspan.setAttributeNS(null, 'font-weight', current.fontWeight); + } + if (current.fillColor !== SVG_DEFAULTS.fillColor) { + current.tspan.setAttributeNS(null, 'fill', current.fillColor); + } + current.txtElement.setAttributeNS(null, 'transform', pm(current.textMatrix) + ' scale(1, -1)'); + current.txtElement.setAttributeNS(XML_NS, 'xml:space', 'preserve'); + current.txtElement.appendChild(current.tspan); + current.txtgrp.appendChild(current.txtElement); + this._ensureTransformGroup().appendChild(current.txtElement); + }, + setLeadingMoveText: function SVGGraphics_setLeadingMoveText(x, y) { + this.setLeading(-y); + this.moveText(x, y); + }, + addFontStyle: function SVGGraphics_addFontStyle(fontObj) { + if (!this.cssStyle) { + this.cssStyle = document.createElementNS(NS, 'svg:style'); + this.cssStyle.setAttributeNS(null, 'type', 'text/css'); + this.defs.appendChild(this.cssStyle); + } + var url = (0, _util.createObjectURL)(fontObj.data, fontObj.mimetype, this.forceDataSchema); + this.cssStyle.textContent += '@font-face { font-family: "' + fontObj.loadedName + '";' + ' src: url(' + url + '); }\n'; + }, + setFont: function SVGGraphics_setFont(details) { + var current = this.current; + var fontObj = this.commonObjs.get(details[0]); + var size = details[1]; + this.current.font = fontObj; + if (this.embedFonts && fontObj.data && !this.embeddedFonts[fontObj.loadedName]) { + this.addFontStyle(fontObj); + this.embeddedFonts[fontObj.loadedName] = fontObj; + } + current.fontMatrix = fontObj.fontMatrix ? fontObj.fontMatrix : _util.FONT_IDENTITY_MATRIX; + var bold = fontObj.black ? fontObj.bold ? 'bolder' : 'bold' : fontObj.bold ? 'bold' : 'normal'; + var italic = fontObj.italic ? 'italic' : 'normal'; + if (size < 0) { + size = -size; + current.fontDirection = -1; + } else { + current.fontDirection = 1; + } + current.fontSize = size; + current.fontFamily = fontObj.loadedName; + current.fontWeight = bold; + current.fontStyle = italic; + current.tspan = document.createElementNS(NS, 'svg:tspan'); + current.tspan.setAttributeNS(null, 'y', pf(-current.y)); + current.xcoords = []; + }, + endText: function SVGGraphics_endText() { + }, + setLineWidth: function SVGGraphics_setLineWidth(width) { + this.current.lineWidth = width; + }, + setLineCap: function SVGGraphics_setLineCap(style) { + this.current.lineCap = LINE_CAP_STYLES[style]; + }, + setLineJoin: function SVGGraphics_setLineJoin(style) { + this.current.lineJoin = LINE_JOIN_STYLES[style]; + }, + setMiterLimit: function SVGGraphics_setMiterLimit(limit) { + this.current.miterLimit = limit; + }, + setStrokeAlpha: function SVGGraphics_setStrokeAlpha(strokeAlpha) { + this.current.strokeAlpha = strokeAlpha; + }, + setStrokeRGBColor: function SVGGraphics_setStrokeRGBColor(r, g, b) { + var color = _util.Util.makeCssRgb(r, g, b); + this.current.strokeColor = color; + }, + setFillAlpha: function SVGGraphics_setFillAlpha(fillAlpha) { + this.current.fillAlpha = fillAlpha; + }, + setFillRGBColor: function SVGGraphics_setFillRGBColor(r, g, b) { + var color = _util.Util.makeCssRgb(r, g, b); + this.current.fillColor = color; + this.current.tspan = document.createElementNS(NS, 'svg:tspan'); + this.current.xcoords = []; + }, + setDash: function SVGGraphics_setDash(dashArray, dashPhase) { + this.current.dashArray = dashArray; + this.current.dashPhase = dashPhase; + }, + constructPath: function SVGGraphics_constructPath(ops, args) { + var current = this.current; + var x = current.x, + y = current.y; + current.path = document.createElementNS(NS, 'svg:path'); + var d = []; + var opLength = ops.length; + for (var i = 0, j = 0; i < opLength; i++) { + switch (ops[i] | 0) { + case _util.OPS.rectangle: + x = args[j++]; + y = args[j++]; + var width = args[j++]; + var height = args[j++]; + var xw = x + width; + var yh = y + height; + d.push('M', pf(x), pf(y), 'L', pf(xw), pf(y), 'L', pf(xw), pf(yh), 'L', pf(x), pf(yh), 'Z'); + break; + case _util.OPS.moveTo: + x = args[j++]; + y = args[j++]; + d.push('M', pf(x), pf(y)); + break; + case _util.OPS.lineTo: + x = args[j++]; + y = args[j++]; + d.push('L', pf(x), pf(y)); + break; + case _util.OPS.curveTo: + x = args[j + 4]; + y = args[j + 5]; + d.push('C', pf(args[j]), pf(args[j + 1]), pf(args[j + 2]), pf(args[j + 3]), pf(x), pf(y)); + j += 6; + break; + case _util.OPS.curveTo2: + x = args[j + 2]; + y = args[j + 3]; + d.push('C', pf(x), pf(y), pf(args[j]), pf(args[j + 1]), pf(args[j + 2]), pf(args[j + 3])); + j += 4; + break; + case _util.OPS.curveTo3: + x = args[j + 2]; + y = args[j + 3]; + d.push('C', pf(args[j]), pf(args[j + 1]), pf(x), pf(y), pf(x), pf(y)); + j += 4; + break; + case _util.OPS.closePath: + d.push('Z'); + break; + } + } + current.path.setAttributeNS(null, 'd', d.join(' ')); + current.path.setAttributeNS(null, 'fill', 'none'); + this._ensureTransformGroup().appendChild(current.path); + current.element = current.path; + current.setCurrentPoint(x, y); + }, + endPath: function SVGGraphics_endPath() { + if (!this.pendingClip) { + return; + } + var current = this.current; + var clipId = 'clippath' + clipCount; + clipCount++; + var clipPath = document.createElementNS(NS, 'svg:clipPath'); + clipPath.setAttributeNS(null, 'id', clipId); + clipPath.setAttributeNS(null, 'transform', pm(this.transformMatrix)); + var clipElement = current.element.cloneNode(); + if (this.pendingClip === 'evenodd') { + clipElement.setAttributeNS(null, 'clip-rule', 'evenodd'); + } else { + clipElement.setAttributeNS(null, 'clip-rule', 'nonzero'); + } + this.pendingClip = null; + clipPath.appendChild(clipElement); + this.defs.appendChild(clipPath); + if (current.activeClipUrl) { + current.clipGroup = null; + this.extraStack.forEach(function (prev) { + prev.clipGroup = null; + }); + } + current.activeClipUrl = 'url(#' + clipId + ')'; + this.tgrp = null; + }, + clip: function SVGGraphics_clip(type) { + this.pendingClip = type; + }, + closePath: function SVGGraphics_closePath() { + var current = this.current; + var d = current.path.getAttributeNS(null, 'd'); + d += 'Z'; + current.path.setAttributeNS(null, 'd', d); + }, + setLeading: function SVGGraphics_setLeading(leading) { + this.current.leading = -leading; + }, + setTextRise: function SVGGraphics_setTextRise(textRise) { + this.current.textRise = textRise; + }, + setHScale: function SVGGraphics_setHScale(scale) { + this.current.textHScale = scale / 100; + }, + setGState: function SVGGraphics_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 'Font': + this.setFont(value); + break; + case 'CA': + this.setStrokeAlpha(value); + break; + case 'ca': + this.setFillAlpha(value); + break; + default: + (0, _util.warn)('Unimplemented graphic state ' + key); + break; + } + } + }, + fill: function SVGGraphics_fill() { + var current = this.current; + current.element.setAttributeNS(null, 'fill', current.fillColor); + current.element.setAttributeNS(null, 'fill-opacity', current.fillAlpha); + }, + stroke: function SVGGraphics_stroke() { + var current = this.current; + current.element.setAttributeNS(null, 'stroke', current.strokeColor); + current.element.setAttributeNS(null, 'stroke-opacity', current.strokeAlpha); + current.element.setAttributeNS(null, 'stroke-miterlimit', pf(current.miterLimit)); + current.element.setAttributeNS(null, 'stroke-linecap', current.lineCap); + current.element.setAttributeNS(null, 'stroke-linejoin', current.lineJoin); + current.element.setAttributeNS(null, 'stroke-width', pf(current.lineWidth) + 'px'); + current.element.setAttributeNS(null, 'stroke-dasharray', current.dashArray.map(pf).join(' ')); + current.element.setAttributeNS(null, 'stroke-dashoffset', pf(current.dashPhase) + 'px'); + current.element.setAttributeNS(null, 'fill', 'none'); + }, + eoFill: function SVGGraphics_eoFill() { + this.current.element.setAttributeNS(null, 'fill-rule', 'evenodd'); + this.fill(); + }, + fillStroke: function SVGGraphics_fillStroke() { + this.stroke(); + this.fill(); + }, + eoFillStroke: function SVGGraphics_eoFillStroke() { + this.current.element.setAttributeNS(null, 'fill-rule', 'evenodd'); + this.fillStroke(); + }, + closeStroke: function SVGGraphics_closeStroke() { + this.closePath(); + this.stroke(); + }, + closeFillStroke: function SVGGraphics_closeFillStroke() { + this.closePath(); + this.fillStroke(); + }, + paintSolidColorImageMask: function SVGGraphics_paintSolidColorImageMask() { + var current = this.current; + var rect = document.createElementNS(NS, 'svg:rect'); + rect.setAttributeNS(null, 'x', '0'); + rect.setAttributeNS(null, 'y', '0'); + rect.setAttributeNS(null, 'width', '1px'); + rect.setAttributeNS(null, 'height', '1px'); + rect.setAttributeNS(null, 'fill', current.fillColor); + this._ensureTransformGroup().appendChild(rect); + }, + paintJpegXObject: function SVGGraphics_paintJpegXObject(objId, w, h) { + var imgObj = this.objs.get(objId); + var imgEl = document.createElementNS(NS, 'svg:image'); + imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgObj.src); + imgEl.setAttributeNS(null, 'width', pf(w)); + imgEl.setAttributeNS(null, 'height', pf(h)); + imgEl.setAttributeNS(null, 'x', '0'); + imgEl.setAttributeNS(null, 'y', pf(-h)); + imgEl.setAttributeNS(null, 'transform', 'scale(' + pf(1 / w) + ' ' + pf(-1 / h) + ')'); + this._ensureTransformGroup().appendChild(imgEl); + }, + paintImageXObject: function SVGGraphics_paintImageXObject(objId) { + var imgData = this.objs.get(objId); + if (!imgData) { + (0, _util.warn)('Dependent image isn\'t ready yet'); + return; + } + this.paintInlineImageXObject(imgData); + }, + paintInlineImageXObject: function SVGGraphics_paintInlineImageXObject(imgData, mask) { + var width = imgData.width; + var height = imgData.height; + var imgSrc = convertImgDataToPng(imgData, this.forceDataSchema); + var cliprect = document.createElementNS(NS, 'svg:rect'); + cliprect.setAttributeNS(null, 'x', '0'); + cliprect.setAttributeNS(null, 'y', '0'); + cliprect.setAttributeNS(null, 'width', pf(width)); + cliprect.setAttributeNS(null, 'height', pf(height)); + this.current.element = cliprect; + this.clip('nonzero'); + var imgEl = document.createElementNS(NS, 'svg:image'); + imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgSrc); + imgEl.setAttributeNS(null, 'x', '0'); + imgEl.setAttributeNS(null, 'y', pf(-height)); + imgEl.setAttributeNS(null, 'width', pf(width) + 'px'); + imgEl.setAttributeNS(null, 'height', pf(height) + 'px'); + imgEl.setAttributeNS(null, 'transform', 'scale(' + pf(1 / width) + ' ' + pf(-1 / height) + ')'); + if (mask) { + mask.appendChild(imgEl); + } else { + this._ensureTransformGroup().appendChild(imgEl); + } + }, + paintImageMaskXObject: function SVGGraphics_paintImageMaskXObject(imgData) { + var current = this.current; + var width = imgData.width; + var height = imgData.height; + var fillColor = current.fillColor; + current.maskId = 'mask' + maskCount++; + var mask = document.createElementNS(NS, 'svg:mask'); + mask.setAttributeNS(null, 'id', current.maskId); + var rect = document.createElementNS(NS, 'svg:rect'); + rect.setAttributeNS(null, 'x', '0'); + rect.setAttributeNS(null, 'y', '0'); + rect.setAttributeNS(null, 'width', pf(width)); + rect.setAttributeNS(null, 'height', pf(height)); + rect.setAttributeNS(null, 'fill', fillColor); + rect.setAttributeNS(null, 'mask', 'url(#' + current.maskId + ')'); + this.defs.appendChild(mask); + this._ensureTransformGroup().appendChild(rect); + this.paintInlineImageXObject(imgData, mask); + }, + paintFormXObjectBegin: function SVGGraphics_paintFormXObjectBegin(matrix, bbox) { + if ((0, _util.isArray)(matrix) && matrix.length === 6) { + this.transform(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); + } + if ((0, _util.isArray)(bbox) && bbox.length === 4) { + var width = bbox[2] - bbox[0]; + var height = bbox[3] - bbox[1]; + var cliprect = document.createElementNS(NS, 'svg:rect'); + cliprect.setAttributeNS(null, 'x', bbox[0]); + cliprect.setAttributeNS(null, 'y', bbox[1]); + cliprect.setAttributeNS(null, 'width', pf(width)); + cliprect.setAttributeNS(null, 'height', pf(height)); + this.current.element = cliprect; + this.clip('nonzero'); + this.endPath(); + } + }, + paintFormXObjectEnd: function SVGGraphics_paintFormXObjectEnd() { + }, + _initialize: function SVGGraphics_initialize(viewport) { + var svg = document.createElementNS(NS, 'svg:svg'); + svg.setAttributeNS(null, 'version', '1.1'); + svg.setAttributeNS(null, 'width', viewport.width + 'px'); + svg.setAttributeNS(null, 'height', viewport.height + 'px'); + svg.setAttributeNS(null, 'preserveAspectRatio', 'none'); + svg.setAttributeNS(null, 'viewBox', '0 0 ' + viewport.width + ' ' + viewport.height); + var definitions = document.createElementNS(NS, 'svg:defs'); + svg.appendChild(definitions); + this.defs = definitions; + var rootGroup = document.createElementNS(NS, 'svg:g'); + rootGroup.setAttributeNS(null, 'transform', pm(viewport.transform)); + svg.appendChild(rootGroup); + this.svg = rootGroup; + return svg; + }, + _ensureClipGroup: function SVGGraphics_ensureClipGroup() { + if (!this.current.clipGroup) { + var clipGroup = document.createElementNS(NS, 'svg:g'); + clipGroup.setAttributeNS(null, 'clip-path', this.current.activeClipUrl); + this.svg.appendChild(clipGroup); + this.current.clipGroup = clipGroup; + } + return this.current.clipGroup; + }, + _ensureTransformGroup: function SVGGraphics_ensureTransformGroup() { + if (!this.tgrp) { + this.tgrp = document.createElementNS(NS, 'svg:g'); + this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix)); + if (this.current.activeClipUrl) { + this._ensureClipGroup().appendChild(this.tgrp); + } else { + this.svg.appendChild(this.tgrp); + } + } + return this.tgrp; + } + }; + return SVGGraphics; + }(); + } + exports.SVGGraphics = SVGGraphics; + + /***/ + }), + /* 5 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.renderTextLayer = undefined; + + var _util = __w_pdfjs_require__(0); + + var _dom_utils = __w_pdfjs_require__(1); + + var renderTextLayer = function renderTextLayerClosure() { + var MAX_TEXT_DIVS_TO_RENDER = 100000; + var NonWhitespaceRegexp = /\S/; + + function isAllWhitespace(str) { + return !NonWhitespaceRegexp.test(str); + } + + var styleBuf = ['left: ', 0, 'px; top: ', 0, 'px; font-size: ', 0, 'px; font-family: ', '', ';']; + + function appendText(task, geom, styles) { + var textDiv = document.createElement('div'); + var textDivProperties = { + style: null, + angle: 0, + canvasWidth: 0, + isWhitespace: false, + originalTransform: null, + paddingBottom: 0, + paddingLeft: 0, + paddingRight: 0, + paddingTop: 0, + scale: 1 + }; + task._textDivs.push(textDiv); + if (isAllWhitespace(geom.str)) { + textDivProperties.isWhitespace = true; + task._textDivProperties.set(textDiv, textDivProperties); + return; + } + var tx = _util.Util.transform(task._viewport.transform, geom.transform); + var angle = Math.atan2(tx[1], tx[0]); + var style = styles[geom.fontName]; + if (style.vertical) { + angle += Math.PI / 2; + } + var fontHeight = Math.sqrt(tx[2] * tx[2] + tx[3] * tx[3]); + var fontAscent = fontHeight; + if (style.ascent) { + fontAscent = style.ascent * fontAscent; + } else if (style.descent) { + fontAscent = (1 + style.descent) * fontAscent; + } + var left; + var 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); + } + styleBuf[1] = left; + styleBuf[3] = top; + styleBuf[5] = fontHeight; + styleBuf[7] = style.fontFamily; + textDivProperties.style = styleBuf.join(''); + textDiv.setAttribute('style', textDivProperties.style); + textDiv.textContent = geom.str; + if ((0, _dom_utils.getDefaultSetting)('pdfBug')) { + textDiv.dataset.fontName = geom.fontName; + } + if (angle !== 0) { + textDivProperties.angle = angle * (180 / Math.PI); + } + if (geom.str.length > 1) { + 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) { + var angleCos = 1, + angleSin = 0; + if (angle !== 0) { + angleCos = Math.cos(angle); + angleSin = Math.sin(angle); + } + var divWidth = (style.vertical ? geom.height : geom.width) * task._viewport.scale; + var divHeight = fontHeight; + var 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: m + }); + } + } + + function render(task) { + if (task._canceled) { + return; + } + 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 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); + 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, i) { + var t = _util.Util.applyTransform(p, m); + ts[i + 0] = c && (e.left - t[0]) / c; + ts[i + 4] = s && (e.top - t[1]) / s; + ts[i + 8] = c && (e.right - t[0]) / c; + ts[i + 12] = s && (e.bottom - t[1]) / s; + ts[i + 16] = s && (e.left - t[0]) / -s; + ts[i + 20] = c && (e.top - t[1]) / c; + ts[i + 24] = s && (e.right - t[0]) / -s; + ts[i + 28] = c && (e.bottom - t[1]) / c; + ts[i + 32] = c && (e.left - t[0]) / -c; + ts[i + 36] = s && (e.top - t[1]) / -s; + ts[i + 40] = c && (e.right - t[0]) / -c; + ts[i + 44] = s && (e.bottom - t[1]) / -s; + ts[i + 48] = s && (e.left - t[0]) / s; + ts[i + 52] = c && (e.top - t[1]) / -c; + ts[i + 56] = s && (e.right - t[0]) / s; + ts[i + 60] = c && (e.bottom - t[1]) / -c; + }); + var findPositiveMin = function findPositiveMin(ts, offset, count) { + var result = 0; + for (var i = 0; i < count; i++) { + var t = ts[offset++]; + if (t > 0) { + result = result ? Math.min(t, result) : t; + } + } + return result; + }; + 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; + task._textDivProperties.set(div, divProperties); + } + } + + 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; + } + + function expandBoundsLTR(width, bounds) { + bounds.sort(function (a, b) { + return a.x1 - b.x1 || a.index - b.index; + }); + var fakeBoundary = { + x1: -Infinity, + y1: -Infinity, + x2: 0, + y2: Infinity, + index: -1, + x1New: 0, + x2New: 0 + }; + var horizon = [{ + start: -Infinity, + end: Infinity, + boundary: fakeBoundary + }]; + bounds.forEach(function (boundary) { + var i = 0; + while (i < horizon.length && horizon[i].end <= boundary.y1) { + i++; + } + var j = horizon.length - 1; + while (j >= 0 && horizon[j].start >= boundary.y2) { + j--; + } + var horizonPart, affectedBoundary; + var q, + k, + maxXNew = -Infinity; + 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; + if (affectedBoundary.x2New === undefined) { + affectedBoundary.x2New = Math.max(width, affectedBoundary.x2); + } + }); + } + + function TextLayerRenderTask(_ref) { + var textContent = _ref.textContent, + textContentStream = _ref.textContentStream, + container = _ref.container, + viewport = _ref.viewport, + textDivs = _ref.textDivs, + textContentItemsStr = _ref.textContentItemsStr, + enhanceTextSelection = _ref.enhanceTextSelection; + + this._textContent = textContent; + this._textContentStream = textContentStream; + this._container = container; + this._viewport = viewport; + this._textDivs = textDivs || []; + this._textContentItemsStr = textContentItemsStr || []; + this._enhanceTextSelection = !!enhanceTextSelection; + this._reader = null; + this._layoutTextLastFontSize = null; + this._layoutTextLastFontFamily = null; + this._layoutTextCtx = null; + this._textDivProperties = new WeakMap(); + this._renderingDone = false; + this._canceled = false; + this._capability = (0, _util.createPromiseCapability)(); + this._renderTimer = null; + this._bounds = []; + } + + TextLayerRenderTask.prototype = { + get promise() { + return this._capability.promise; + }, + cancel: function TextLayer_cancel() { + if (this._reader) { + this._reader.cancel(new _util.AbortException('text layer task cancelled')); + this._reader = null; + } + this._canceled = true; + if (this._renderTimer !== null) { + clearTimeout(this._renderTimer); + this._renderTimer = null; + } + this._capability.reject('canceled'); + }, + _processItems: function _processItems(items, styleCache) { + for (var i = 0, len = items.length; i < len; i++) { + this._textContentItemsStr.push(items[i].str); + appendText(this, items[i], styleCache); + } + }, + _layoutText: function _layoutText(textDiv) { + var textLayerFrag = this._container; + var textDivProperties = this._textDivProperties.get(textDiv); + if (textDivProperties.isWhitespace) { + return; + } + var fontSize = textDiv.style.fontSize; + var fontFamily = textDiv.style.fontFamily; + if (fontSize !== this._layoutTextLastFontSize || fontFamily !== this._layoutTextLastFontFamily) { + this._layoutTextCtx.font = fontSize + ' ' + fontFamily; + this._lastFontSize = fontSize; + this._lastFontFamily = fontFamily; + } + var width = this._layoutTextCtx.measureText(textDiv.textContent).width; + var transform = ''; + if (textDivProperties.canvasWidth !== 0 && width > 0) { + textDivProperties.scale = textDivProperties.canvasWidth / width; + transform = 'scaleX(' + textDivProperties.scale + ')'; + } + if (textDivProperties.angle !== 0) { + transform = 'rotate(' + textDivProperties.angle + 'deg) ' + transform; + } + if (transform !== '') { + textDivProperties.originalTransform = transform; + _dom_utils.CustomStyle.setProp('transform', textDiv, transform); + } + this._textDivProperties.set(textDiv, textDivProperties); + textLayerFrag.appendChild(textDiv); + }, + + _render: function TextLayer_render(timeout) { + var _this = this; + + var capability = (0, _util.createPromiseCapability)(); + var styleCache = Object.create(null); + var canvas = document.createElement('canvas'); + canvas.mozOpaque = true; + this._layoutTextCtx = canvas.getContext('2d', {alpha: false}); + if (this._textContent) { + var textItems = this._textContent.items; + var textStyles = this._textContent.styles; + this._processItems(textItems, textStyles); + capability.resolve(); + } else if (this._textContentStream) { + var pump = function pump() { + _this._reader.read().then(function (_ref2) { + var value = _ref2.value, + done = _ref2.done; + + if (done) { + capability.resolve(); + return; + } + _util.Util.extendObj(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(function () { + styleCache = null; + if (!timeout) { + render(_this); + } else { + _this._renderTimer = setTimeout(function () { + 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; + } + for (var i = 0, ii = this._textDivs.length; i < ii; i++) { + var div = this._textDivs[i]; + var divProperties = this._textDivProperties.get(div); + if (divProperties.isWhitespace) { + continue; + } + if (expandDivs) { + var transform = '', + padding = ''; + if (divProperties.scale !== 1) { + transform = 'scaleX(' + divProperties.scale + ')'; + } + if (divProperties.angle !== 0) { + transform = 'rotate(' + divProperties.angle + 'deg) ' + transform; + } + if (divProperties.paddingLeft !== 0) { + padding += ' padding-left: ' + divProperties.paddingLeft / divProperties.scale + 'px;'; + transform += ' translateX(' + -divProperties.paddingLeft / divProperties.scale + 'px)'; + } + if (divProperties.paddingTop !== 0) { + padding += ' padding-top: ' + divProperties.paddingTop + 'px;'; + transform += ' translateY(' + -divProperties.paddingTop + 'px)'; + } + if (divProperties.paddingRight !== 0) { + padding += ' padding-right: ' + divProperties.paddingRight / divProperties.scale + 'px;'; + } + if (divProperties.paddingBottom !== 0) { + padding += ' padding-bottom: ' + divProperties.paddingBottom + 'px;'; + } + if (padding !== '') { + div.setAttribute('style', divProperties.style + padding); + } + if (transform !== '') { + _dom_utils.CustomStyle.setProp('transform', div, transform); + } + } else { + div.style.padding = 0; + _dom_utils.CustomStyle.setProp('transform', div, divProperties.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; + } + + return renderTextLayer; + }(); + exports.renderTextLayer = renderTextLayer; + + /***/ + }), + /* 6 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + + function fixMetadata(meta) { + return meta.replace(/>\\376\\377([^<]+)/g, function (all, codes) { + var bytes = codes.replace(/\\([0-3])([0-7])([0-7])/g, function (code, d1, d2, d3) { + return String.fromCharCode(d1 * 64 + d2 * 8 + d3 * 1); + }); + var chars = ''; + for (var i = 0; i < bytes.length; i += 2) { + var code = bytes.charCodeAt(i) * 256 + bytes.charCodeAt(i + 1); + chars += code >= 32 && code < 127 && code !== 60 && code !== 62 && code !== 38 ? String.fromCharCode(code) : '&#x' + (0x10000 + code).toString(16).substring(1) + ';'; + } + return '>' + chars; + }); + } + + function Metadata(meta) { + if (typeof meta === 'string') { + meta = fixMetadata(meta); + var parser = new DOMParser(); + meta = parser.parseFromString(meta, 'application/xml'); + } else if (!(meta instanceof Document)) { + throw new Error('Metadata: Invalid metadata object'); + } + this.metaDocument = meta; + this.metadata = Object.create(null); + this.parse(); + } + + Metadata.prototype = { + parse: function Metadata_parse() { + var doc = this.metaDocument; + var rdf = doc.documentElement; + if (rdf.nodeName.toLowerCase() !== 'rdf:rdf') { + rdf = rdf.firstChild; + while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf') { + rdf = rdf.nextSibling; + } + } + var nodeName = rdf ? rdf.nodeName.toLowerCase() : null; + if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes()) { + return; + } + var children = rdf.childNodes, + desc, + entry, + name, + i, + ii, + length, + iLength; + for (i = 0, length = children.length; i < length; i++) { + desc = children[i]; + if (desc.nodeName.toLowerCase() !== 'rdf:description') { + continue; + } + for (ii = 0, iLength = desc.childNodes.length; ii < iLength; ii++) { + if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text') { + entry = desc.childNodes[ii]; + name = entry.nodeName.toLowerCase(); + this.metadata[name] = entry.textContent.trim(); + } + } + } + }, + get: function Metadata_get(name) { + return this.metadata[name] || null; + }, + has: function Metadata_has(name) { + return typeof this.metadata[name] !== 'undefined'; + } + }; + exports.Metadata = Metadata; + + /***/ + }), + /* 7 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.WebGLUtils = undefined; + + var _dom_utils = __w_pdfjs_require__(1); + + var _util = __w_pdfjs_require__(0); + + 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); + if (!compiled) { + var errorMsg = gl.getShaderInfoLog(shader); + throw new Error('Error during shader compilation: ' + errorMsg); + } + return shader; + } + + function createVertexShader(gl, code) { + return loadShader(gl, code, gl.VERTEX_SHADER); + } + + function createFragmentShader(gl, code) { + return loadShader(gl, code, gl.FRAGMENT_SHADER); + } + + 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}); + } + + 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; + } + + 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; + } + + function 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; + } + + return { + get isEnabled() { + if ((0, _dom_utils.getDefaultSetting)('disableWebGL')) { + return false; + } + var enabled = false; + try { + generateGL(); + enabled = !!currentGL; + } catch (e) { + } + return (0, _util.shadow)(this, 'isEnabled', enabled); + }, + composeSMask: composeSMask, + drawFigures: drawFigures, + clear: cleanup + }; + }(); + exports.WebGLUtils = WebGLUtils; + + /***/ + }), + /* 8 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFJS = exports.isWorker = exports.globalScope = undefined; + + var _api = __w_pdfjs_require__(2); + + var _dom_utils = __w_pdfjs_require__(1); + + var _util = __w_pdfjs_require__(0); + + var _annotation_layer = __w_pdfjs_require__(3); + + var _metadata = __w_pdfjs_require__(6); + + var _text_layer = __w_pdfjs_require__(5); + + var _svg = __w_pdfjs_require__(4); + + var isWorker = typeof window === 'undefined'; + if (!_util.globalScope.PDFJS) { + _util.globalScope.PDFJS = {}; + } + var PDFJS = _util.globalScope.PDFJS; + { + PDFJS.version = '1.9.426'; + PDFJS.build = '2558a58d'; + } + PDFJS.pdfBug = false; + if (PDFJS.verbosity !== undefined) { + (0, _util.setVerbosityLevel)(PDFJS.verbosity); + } + delete PDFJS.verbosity; + Object.defineProperty(PDFJS, 'verbosity', { + get: function get() { + return (0, _util.getVerbosityLevel)(); + }, + set: function set(level) { + (0, _util.setVerbosityLevel)(level); + }, + + enumerable: true, + configurable: true + }); + PDFJS.VERBOSITY_LEVELS = _util.VERBOSITY_LEVELS; + PDFJS.OPS = _util.OPS; + PDFJS.UNSUPPORTED_FEATURES = _util.UNSUPPORTED_FEATURES; + PDFJS.isValidUrl = _dom_utils.isValidUrl; + PDFJS.shadow = _util.shadow; + PDFJS.createBlob = _util.createBlob; + PDFJS.createObjectURL = function PDFJS_createObjectURL(data, contentType) { + return (0, _util.createObjectURL)(data, contentType, PDFJS.disableCreateObjectURL); + }; + Object.defineProperty(PDFJS, 'isLittleEndian', { + configurable: true, + get: function PDFJS_isLittleEndian() { + return (0, _util.shadow)(PDFJS, 'isLittleEndian', (0, _util.isLittleEndian)()); + } + }); + PDFJS.removeNullCharacters = _util.removeNullCharacters; + PDFJS.PasswordResponses = _util.PasswordResponses; + PDFJS.PasswordException = _util.PasswordException; + PDFJS.UnknownErrorException = _util.UnknownErrorException; + PDFJS.InvalidPDFException = _util.InvalidPDFException; + PDFJS.MissingPDFException = _util.MissingPDFException; + PDFJS.UnexpectedResponseException = _util.UnexpectedResponseException; + PDFJS.Util = _util.Util; + PDFJS.PageViewport = _util.PageViewport; + PDFJS.createPromiseCapability = _util.createPromiseCapability; + PDFJS.maxImageSize = PDFJS.maxImageSize === undefined ? -1 : PDFJS.maxImageSize; + PDFJS.cMapUrl = PDFJS.cMapUrl === undefined ? null : PDFJS.cMapUrl; + PDFJS.cMapPacked = PDFJS.cMapPacked === undefined ? false : PDFJS.cMapPacked; + PDFJS.disableFontFace = PDFJS.disableFontFace === undefined ? false : PDFJS.disableFontFace; + PDFJS.imageResourcesPath = PDFJS.imageResourcesPath === undefined ? '' : PDFJS.imageResourcesPath; + PDFJS.disableWorker = PDFJS.disableWorker === undefined ? false : PDFJS.disableWorker; + PDFJS.workerSrc = PDFJS.workerSrc === undefined ? null : PDFJS.workerSrc; + PDFJS.workerPort = PDFJS.workerPort === undefined ? null : PDFJS.workerPort; + PDFJS.disableRange = PDFJS.disableRange === undefined ? false : PDFJS.disableRange; + PDFJS.disableStream = PDFJS.disableStream === undefined ? false : PDFJS.disableStream; + PDFJS.disableAutoFetch = PDFJS.disableAutoFetch === undefined ? false : PDFJS.disableAutoFetch; + PDFJS.pdfBug = PDFJS.pdfBug === undefined ? false : PDFJS.pdfBug; + PDFJS.postMessageTransfers = PDFJS.postMessageTransfers === undefined ? true : PDFJS.postMessageTransfers; + PDFJS.disableCreateObjectURL = PDFJS.disableCreateObjectURL === undefined ? false : PDFJS.disableCreateObjectURL; + PDFJS.disableWebGL = PDFJS.disableWebGL === undefined ? true : PDFJS.disableWebGL; + PDFJS.externalLinkTarget = PDFJS.externalLinkTarget === undefined ? _dom_utils.LinkTarget.NONE : PDFJS.externalLinkTarget; + PDFJS.externalLinkRel = PDFJS.externalLinkRel === undefined ? _dom_utils.DEFAULT_LINK_REL : PDFJS.externalLinkRel; + PDFJS.isEvalSupported = PDFJS.isEvalSupported === undefined ? true : PDFJS.isEvalSupported; + PDFJS.pdfjsNext = PDFJS.pdfjsNext === undefined ? false : PDFJS.pdfjsNext; + { + var savedOpenExternalLinksInNewWindow = PDFJS.openExternalLinksInNewWindow; + delete PDFJS.openExternalLinksInNewWindow; + Object.defineProperty(PDFJS, 'openExternalLinksInNewWindow', { + get: function get() { + return PDFJS.externalLinkTarget === _dom_utils.LinkTarget.BLANK; + }, + set: function set(value) { + if (value) { + (0, _util.deprecated)('PDFJS.openExternalLinksInNewWindow, please use ' + '"PDFJS.externalLinkTarget = PDFJS.LinkTarget.BLANK" instead.'); + } + if (PDFJS.externalLinkTarget !== _dom_utils.LinkTarget.NONE) { + (0, _util.warn)('PDFJS.externalLinkTarget is already initialized'); + return; + } + PDFJS.externalLinkTarget = value ? _dom_utils.LinkTarget.BLANK : _dom_utils.LinkTarget.NONE; + }, + + enumerable: true, + configurable: true + }); + if (savedOpenExternalLinksInNewWindow) { + PDFJS.openExternalLinksInNewWindow = savedOpenExternalLinksInNewWindow; + } + } + PDFJS.getDocument = _api.getDocument; + PDFJS.LoopbackPort = _api.LoopbackPort; + PDFJS.PDFDataRangeTransport = _api.PDFDataRangeTransport; + PDFJS.PDFWorker = _api.PDFWorker; + PDFJS.hasCanvasTypedArrays = true; + PDFJS.CustomStyle = _dom_utils.CustomStyle; + PDFJS.LinkTarget = _dom_utils.LinkTarget; + PDFJS.addLinkAttributes = _dom_utils.addLinkAttributes; + PDFJS.getFilenameFromUrl = _dom_utils.getFilenameFromUrl; + PDFJS.isExternalLinkTargetSet = _dom_utils.isExternalLinkTargetSet; + PDFJS.AnnotationLayer = _annotation_layer.AnnotationLayer; + PDFJS.renderTextLayer = _text_layer.renderTextLayer; + PDFJS.Metadata = _metadata.Metadata; + PDFJS.SVGGraphics = _svg.SVGGraphics; + PDFJS.UnsupportedManager = _api._UnsupportedManager; + exports.globalScope = _util.globalScope; + exports.isWorker = isWorker; + exports.PDFJS = PDFJS; + + /***/ + }), + /* 9 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.NetworkManager = exports.PDFNetworkStream = undefined; + + var _util = __w_pdfjs_require__(0); + + var _api = __w_pdfjs_require__(2); + + ; + var OK_RESPONSE = 200; + var PARTIAL_CONTENT_RESPONSE = 206; + + function NetworkManager(url, args) { + this.url = url; + args = args || {}; + this.isHttp = /^https?:/i.test(url); + this.httpHeaders = this.isHttp && args.httpHeaders || {}; + this.withCredentials = args.withCredentials || false; + this.getXhr = args.getXhr || function NetworkManager_getXhr() { + return new XMLHttpRequest(); + }; + this.currXhrId = 0; + this.pendingRequests = Object.create(null); + this.loadedRequests = Object.create(null); + } + + function getArrayBuffer(xhr) { + var data = xhr.response; + if (typeof data !== 'string') { + return data; + } + var length = data.length; + var array = new Uint8Array(length); + for (var i = 0; i < length; i++) { + array[i] = data.charCodeAt(i) & 0xFF; + } + return array.buffer; + } + + var supportsMozChunked = function supportsMozChunkedClosure() { + try { + var x = new XMLHttpRequest(); + x.open('GET', _util.globalScope.location.href); + x.responseType = 'moz-chunked-arraybuffer'; + return x.responseType === 'moz-chunked-arraybuffer'; + } catch (e) { + return false; + } + }(); + NetworkManager.prototype = { + requestRange: function NetworkManager_requestRange(begin, end, listeners) { + var args = { + begin: begin, + end: end + }; + for (var prop in listeners) { + args[prop] = listeners[prop]; + } + return this.request(args); + }, + requestFull: function NetworkManager_requestFull(listeners) { + return this.request(listeners); + }, + request: function NetworkManager_request(args) { + var xhr = this.getXhr(); + var xhrId = this.currXhrId++; + var pendingRequest = this.pendingRequests[xhrId] = {xhr: xhr}; + xhr.open('GET', this.url); + xhr.withCredentials = this.withCredentials; + for (var property in this.httpHeaders) { + var value = this.httpHeaders[property]; + if (typeof value === 'undefined') { + continue; + } + xhr.setRequestHeader(property, value); + } + if (this.isHttp && 'begin' in args && 'end' in args) { + var rangeStr = args.begin + '-' + (args.end - 1); + xhr.setRequestHeader('Range', 'bytes=' + rangeStr); + pendingRequest.expectedStatus = 206; + } else { + pendingRequest.expectedStatus = 200; + } + var useMozChunkedLoading = supportsMozChunked && !!args.onProgressiveData; + if (useMozChunkedLoading) { + xhr.responseType = 'moz-chunked-arraybuffer'; + pendingRequest.onProgressiveData = args.onProgressiveData; + pendingRequest.mozChunked = true; + } else { + xhr.responseType = 'arraybuffer'; + } + if (args.onError) { + xhr.onerror = function (evt) { + args.onError(xhr.status); + }; + } + xhr.onreadystatechange = this.onStateChange.bind(this, xhrId); + xhr.onprogress = this.onProgress.bind(this, xhrId); + pendingRequest.onHeadersReceived = args.onHeadersReceived; + pendingRequest.onDone = args.onDone; + pendingRequest.onError = args.onError; + pendingRequest.onProgress = args.onProgress; + xhr.send(null); + return xhrId; + }, + onProgress: function NetworkManager_onProgress(xhrId, evt) { + var pendingRequest = this.pendingRequests[xhrId]; + if (!pendingRequest) { + return; + } + if (pendingRequest.mozChunked) { + var chunk = getArrayBuffer(pendingRequest.xhr); + pendingRequest.onProgressiveData(chunk); + } + var onProgress = pendingRequest.onProgress; + if (onProgress) { + onProgress(evt); + } + }, + onStateChange: function NetworkManager_onStateChange(xhrId, evt) { + var pendingRequest = this.pendingRequests[xhrId]; + if (!pendingRequest) { + return; + } + var xhr = pendingRequest.xhr; + if (xhr.readyState >= 2 && pendingRequest.onHeadersReceived) { + pendingRequest.onHeadersReceived(); + delete pendingRequest.onHeadersReceived; + } + if (xhr.readyState !== 4) { + return; + } + if (!(xhrId in this.pendingRequests)) { + return; + } + delete this.pendingRequests[xhrId]; + if (xhr.status === 0 && this.isHttp) { + if (pendingRequest.onError) { + pendingRequest.onError(xhr.status); + } + return; + } + var xhrStatus = xhr.status || OK_RESPONSE; + var 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); + } + return; + } + this.loadedRequests[xhrId] = true; + var chunk = getArrayBuffer(xhr); + if (xhrStatus === PARTIAL_CONTENT_RESPONSE) { + var rangeHeader = xhr.getResponseHeader('Content-Range'); + var matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader); + var begin = parseInt(matches[1], 10); + pendingRequest.onDone({ + begin: begin, + chunk: chunk + }); + } else if (pendingRequest.onProgressiveData) { + pendingRequest.onDone(null); + } else if (chunk) { + pendingRequest.onDone({ + begin: 0, + chunk: chunk + }); + } else if (pendingRequest.onError) { + pendingRequest.onError(xhr.status); + } + }, + hasPendingRequests: function NetworkManager_hasPendingRequests() { + for (var xhrId in this.pendingRequests) { + return true; + } + return false; + }, + getRequestXhr: function NetworkManager_getXhr(xhrId) { + return this.pendingRequests[xhrId].xhr; + }, + isStreamingRequest: function NetworkManager_isStreamingRequest(xhrId) { + return !!this.pendingRequests[xhrId].onProgressiveData; + }, + isPendingRequest: function NetworkManager_isPendingRequest(xhrId) { + return xhrId in this.pendingRequests; + }, + isLoadedRequest: function NetworkManager_isLoadedRequest(xhrId) { + return xhrId in this.loadedRequests; + }, + abortAllRequests: function NetworkManager_abortAllRequests() { + for (var xhrId in this.pendingRequests) { + this.abortRequest(xhrId | 0); + } + }, + abortRequest: function NetworkManager_abortRequest(xhrId) { + var xhr = this.pendingRequests[xhrId].xhr; + delete this.pendingRequests[xhrId]; + xhr.abort(); + } + }; + + function PDFNetworkStream(options) { + this._options = options; + var source = options.source; + this._manager = new NetworkManager(source.url, { + httpHeaders: source.httpHeaders, + withCredentials: source.withCredentials + }); + this._rangeChunkSize = source.rangeChunkSize; + this._fullRequestReader = null; + this._rangeRequestReaders = []; + } + + PDFNetworkStream.prototype = { + _onRangeRequestReaderClosed: function PDFNetworkStream_onRangeRequestReaderClosed(reader) { + var i = this._rangeRequestReaders.indexOf(reader); + if (i >= 0) { + this._rangeRequestReaders.splice(i, 1); + } + }, + getFullReader: function PDFNetworkStream_getFullReader() { + (0, _util.assert)(!this._fullRequestReader); + this._fullRequestReader = new PDFNetworkStreamFullRequestReader(this._manager, this._options); + return this._fullRequestReader; + }, + getRangeReader: function PDFNetworkStream_getRangeReader(begin, end) { + var reader = new PDFNetworkStreamRangeRequestReader(this._manager, begin, end); + reader.onClosed = this._onRangeRequestReaderClosed.bind(this); + this._rangeRequestReaders.push(reader); + return reader; + }, + cancelAllRequests: function PDFNetworkStream_cancelAllRequests(reason) { + if (this._fullRequestReader) { + this._fullRequestReader.cancel(reason); + } + var readers = this._rangeRequestReaders.slice(0); + readers.forEach(function (reader) { + reader.cancel(reason); + }); + } + }; + + function PDFNetworkStreamFullRequestReader(manager, options) { + this._manager = manager; + var source = options.source; + var args = { + onHeadersReceived: this._onHeadersReceived.bind(this), + onProgressiveData: source.disableStream ? null : this._onProgressiveData.bind(this), + onDone: this._onDone.bind(this), + onError: this._onError.bind(this), + onProgress: this._onProgress.bind(this) + }; + this._url = source.url; + this._fullRequestId = manager.requestFull(args); + this._headersReceivedCapability = (0, _util.createPromiseCapability)(); + this._disableRange = options.disableRange || false; + this._contentLength = source.length; + this._rangeChunkSize = source.rangeChunkSize; + if (!this._rangeChunkSize && !this._disableRange) { + this._disableRange = true; + } + this._isStreamingSupported = false; + this._isRangeSupported = false; + this._cachedChunks = []; + this._requests = []; + this._done = false; + this._storedError = undefined; + this.onProgress = null; + } + + PDFNetworkStreamFullRequestReader.prototype = { + _validateRangeRequestCapabilities: function PDFNetworkStreamFullRequestReader_validateRangeRequestCapabilities() { + if (this._disableRange) { + return false; + } + var networkManager = this._manager; + if (!networkManager.isHttp) { + return false; + } + var fullRequestXhrId = this._fullRequestId; + var fullRequestXhr = networkManager.getRequestXhr(fullRequestXhrId); + if (fullRequestXhr.getResponseHeader('Accept-Ranges') !== 'bytes') { + return false; + } + var contentEncoding = fullRequestXhr.getResponseHeader('Content-Encoding') || 'identity'; + if (contentEncoding !== 'identity') { + return false; + } + var length = fullRequestXhr.getResponseHeader('Content-Length'); + length = parseInt(length, 10); + if (!(0, _util.isInt)(length)) { + return false; + } + this._contentLength = length; + if (length <= 2 * this._rangeChunkSize) { + return false; + } + return true; + }, + _onHeadersReceived: function PDFNetworkStreamFullRequestReader_onHeadersReceived() { + if (this._validateRangeRequestCapabilities()) { + this._isRangeSupported = true; + } + var networkManager = this._manager; + var fullRequestXhrId = this._fullRequestId; + if (networkManager.isStreamingRequest(fullRequestXhrId)) { + this._isStreamingSupported = true; + } else if (this._isRangeSupported) { + networkManager.abortRequest(fullRequestXhrId); + } + this._headersReceivedCapability.resolve(); + }, + _onProgressiveData: function PDFNetworkStreamFullRequestReader_onProgressiveData(chunk) { + if (this._requests.length > 0) { + var requestCapability = this._requests.shift(); + requestCapability.resolve({ + value: chunk, + done: false + }); + } else { + this._cachedChunks.push(chunk); + } + }, + _onDone: function PDFNetworkStreamFullRequestReader_onDone(args) { + if (args) { + this._onProgressiveData(args.chunk); + } + this._done = true; + if (this._cachedChunks.length > 0) { + return; + } + this._requests.forEach(function (requestCapability) { + requestCapability.resolve({ + value: undefined, + done: true + }); + }); + this._requests = []; + }, + _onError: function PDFNetworkStreamFullRequestReader_onError(status) { + var url = this._url; + var exception; + if (status === 404 || status === 0 && /^file:/.test(url)) { + exception = new _util.MissingPDFException('Missing PDF "' + url + '".'); + } else { + exception = new _util.UnexpectedResponseException('Unexpected server response (' + status + ') while retrieving PDF "' + url + '".', status); + } + this._storedError = exception; + this._headersReceivedCapability.reject(exception); + this._requests.forEach(function (requestCapability) { + requestCapability.reject(exception); + }); + this._requests = []; + this._cachedChunks = []; + }, + _onProgress: function PDFNetworkStreamFullRequestReader_onProgress(data) { + if (this.onProgress) { + this.onProgress({ + loaded: data.loaded, + total: data.lengthComputable ? data.total : this._contentLength + }); + } + }, + get isRangeSupported() { + return this._isRangeSupported; + }, + get isStreamingSupported() { + return this._isStreamingSupported; + }, + get contentLength() { + return this._contentLength; + }, + get headersReady() { + return this._headersReceivedCapability.promise; + }, + read: function PDFNetworkStreamFullRequestReader_read() { + if (this._storedError) { + return Promise.reject(this._storedError); + } + if (this._cachedChunks.length > 0) { + var chunk = this._cachedChunks.shift(); + return Promise.resolve({ + value: chunk, + done: false + }); + } + if (this._done) { + return Promise.resolve({ + value: undefined, + done: true + }); + } + var requestCapability = (0, _util.createPromiseCapability)(); + this._requests.push(requestCapability); + return requestCapability.promise; + }, + cancel: function PDFNetworkStreamFullRequestReader_cancel(reason) { + this._done = true; + this._headersReceivedCapability.reject(reason); + this._requests.forEach(function (requestCapability) { + requestCapability.resolve({ + value: undefined, + done: true + }); + }); + this._requests = []; + if (this._manager.isPendingRequest(this._fullRequestId)) { + this._manager.abortRequest(this._fullRequestId); + } + this._fullRequestReader = null; + } + }; + + function PDFNetworkStreamRangeRequestReader(manager, begin, end) { + this._manager = manager; + var args = { + onDone: this._onDone.bind(this), + onProgress: this._onProgress.bind(this) + }; + this._requestId = manager.requestRange(begin, end, args); + this._requests = []; + this._queuedChunk = null; + this._done = false; + this.onProgress = null; + this.onClosed = null; + } + + PDFNetworkStreamRangeRequestReader.prototype = { + _close: function PDFNetworkStreamRangeRequestReader_close() { + if (this.onClosed) { + this.onClosed(this); + } + }, + _onDone: function PDFNetworkStreamRangeRequestReader_onDone(data) { + var chunk = data.chunk; + if (this._requests.length > 0) { + var requestCapability = this._requests.shift(); + requestCapability.resolve({ + value: chunk, + done: false + }); + } else { + this._queuedChunk = chunk; + } + this._done = true; + this._requests.forEach(function (requestCapability) { + requestCapability.resolve({ + value: undefined, + done: true + }); + }); + this._requests = []; + this._close(); + }, + _onProgress: function PDFNetworkStreamRangeRequestReader_onProgress(evt) { + if (!this.isStreamingSupported && this.onProgress) { + this.onProgress({loaded: evt.loaded}); + } + }, + get isStreamingSupported() { + return false; + }, + read: function PDFNetworkStreamRangeRequestReader_read() { + if (this._queuedChunk !== null) { + var chunk = this._queuedChunk; + this._queuedChunk = null; + return Promise.resolve({ + value: chunk, + done: false + }); + } + if (this._done) { + return Promise.resolve({ + value: undefined, + done: true + }); + } + var requestCapability = (0, _util.createPromiseCapability)(); + this._requests.push(requestCapability); + return requestCapability.promise; + }, + cancel: function PDFNetworkStreamRangeRequestReader_cancel(reason) { + this._done = true; + this._requests.forEach(function (requestCapability) { + requestCapability.resolve({ + value: undefined, + done: true + }); + }); + this._requests = []; + if (this._manager.isPendingRequest(this._requestId)) { + this._manager.abortRequest(this._requestId); + } + this._close(); + } + }; + (0, _api.setPDFNetworkStreamClass)(PDFNetworkStream); + exports.PDFNetworkStream = PDFNetworkStream; + exports.NetworkManager = NetworkManager; + + /***/ + }), + /* 10 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + var _typeof2 = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + (function (e, a) { + for (var i in a) { + e[i] = a[i]; + } + })(exports, function (modules) { + var installedModules = {}; + + function __w_pdfjs_require__(moduleId) { + if (installedModules[moduleId]) return installedModules[moduleId].exports; + var module = installedModules[moduleId] = { + i: moduleId, + l: false, + exports: {} + }; + modules[moduleId].call(module.exports, module, module.exports, __w_pdfjs_require__); + module.l = true; + return module.exports; + } + + __w_pdfjs_require__.m = modules; + __w_pdfjs_require__.c = installedModules; + __w_pdfjs_require__.i = function (value) { + return value; + }; + __w_pdfjs_require__.d = function (exports, name, getter) { + if (!__w_pdfjs_require__.o(exports, name)) { + Object.defineProperty(exports, name, { + configurable: false, + enumerable: true, + get: getter + }); + } + }; + __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; + }; + __w_pdfjs_require__.o = function (object, property) { + return Object.prototype.hasOwnProperty.call(object, property); + }; + __w_pdfjs_require__.p = ""; + return __w_pdfjs_require__(__w_pdfjs_require__.s = 7); + }([function (module, exports, __w_pdfjs_require__) { + "use strict"; + + var _typeof = typeof Symbol === "function" && _typeof2(Symbol.iterator) === "symbol" ? function (obj) { + return typeof obj === 'undefined' ? 'undefined' : _typeof2(obj); + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj === 'undefined' ? 'undefined' : _typeof2(obj); + }; + var _require = __w_pdfjs_require__(1), + assert = _require.assert; + + function IsPropertyKey(argument) { + return typeof argument === 'string' || (typeof argument === 'undefined' ? 'undefined' : _typeof(argument)) === 'symbol'; + } + + exports.typeIsObject = function (x) { + return (typeof x === 'undefined' ? 'undefined' : _typeof(x)) === 'object' && x !== null || typeof x === 'function'; + }; + exports.createDataProperty = function (o, p, v) { + assert(exports.typeIsObject(o)); + Object.defineProperty(o, p, { + value: v, + writable: true, + enumerable: true, + configurable: true + }); + }; + exports.createArrayFromList = function (elements) { + return elements.slice(); + }; + exports.ArrayBufferCopy = function (dest, destOffset, src, srcOffset, n) { + new Uint8Array(dest).set(new Uint8Array(src, srcOffset, n), destOffset); + }; + exports.CreateIterResultObject = function (value, done) { + assert(typeof done === 'boolean'); + var obj = {}; + Object.defineProperty(obj, 'value', { + value: value, + enumerable: true, + writable: true, + configurable: true + }); + Object.defineProperty(obj, 'done', { + value: done, + enumerable: true, + writable: true, + configurable: true + }); + return obj; + }; + exports.IsFiniteNonNegativeNumber = function (v) { + if (Number.isNaN(v)) { + return false; + } + if (v === Infinity) { + return false; + } + if (v < 0) { + return false; + } + return true; + }; + + function Call(F, V, args) { + if (typeof F !== 'function') { + throw new TypeError('Argument is not a function'); + } + return Function.prototype.apply.call(F, V, args); + } + + exports.InvokeOrNoop = function (O, P, args) { + assert(O !== undefined); + assert(IsPropertyKey(P)); + assert(Array.isArray(args)); + var method = O[P]; + if (method === undefined) { + return undefined; + } + return Call(method, O, args); + }; + exports.PromiseInvokeOrNoop = function (O, P, args) { + assert(O !== undefined); + assert(IsPropertyKey(P)); + assert(Array.isArray(args)); + try { + return Promise.resolve(exports.InvokeOrNoop(O, P, args)); + } catch (returnValueE) { + return Promise.reject(returnValueE); + } + }; + exports.PromiseInvokeOrPerformFallback = function (O, P, args, F, argsF) { + assert(O !== undefined); + assert(IsPropertyKey(P)); + assert(Array.isArray(args)); + assert(Array.isArray(argsF)); + var method = void 0; + try { + method = O[P]; + } catch (methodE) { + return Promise.reject(methodE); + } + if (method === undefined) { + return F.apply(null, argsF); + } + try { + return Promise.resolve(Call(method, O, args)); + } catch (e) { + return Promise.reject(e); + } + }; + exports.TransferArrayBuffer = function (O) { + return O.slice(); + }; + exports.ValidateAndNormalizeHighWaterMark = function (highWaterMark) { + highWaterMark = Number(highWaterMark); + if (Number.isNaN(highWaterMark) || highWaterMark < 0) { + throw new RangeError('highWaterMark property of a queuing strategy must be non-negative and non-NaN'); + } + return highWaterMark; + }; + exports.ValidateAndNormalizeQueuingStrategy = function (size, highWaterMark) { + if (size !== undefined && typeof size !== 'function') { + throw new TypeError('size property of a queuing strategy must be a function'); + } + highWaterMark = exports.ValidateAndNormalizeHighWaterMark(highWaterMark); + return { + size: size, + highWaterMark: highWaterMark + }; + }; + }, function (module, exports, __w_pdfjs_require__) { + "use strict"; + + function rethrowAssertionErrorRejection(e) { + if (e && e.constructor === AssertionError) { + setTimeout(function () { + throw e; + }, 0); + } + } + + function AssertionError(message) { + this.name = 'AssertionError'; + this.message = message || ''; + this.stack = new Error().stack; + } + + AssertionError.prototype = Object.create(Error.prototype); + AssertionError.prototype.constructor = AssertionError; + + function assert(value, message) { + if (!value) { + throw new AssertionError(message); + } + } + + module.exports = { + rethrowAssertionErrorRejection: rethrowAssertionErrorRejection, + AssertionError: AssertionError, + assert: assert + }; + }, function (module, exports, __w_pdfjs_require__) { + "use strict"; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var _require = __w_pdfjs_require__(0), + InvokeOrNoop = _require.InvokeOrNoop, + PromiseInvokeOrNoop = _require.PromiseInvokeOrNoop, + ValidateAndNormalizeQueuingStrategy = _require.ValidateAndNormalizeQueuingStrategy, + typeIsObject = _require.typeIsObject; + var _require2 = __w_pdfjs_require__(1), + assert = _require2.assert, + rethrowAssertionErrorRejection = _require2.rethrowAssertionErrorRejection; + var _require3 = __w_pdfjs_require__(3), + DequeueValue = _require3.DequeueValue, + EnqueueValueWithSize = _require3.EnqueueValueWithSize, + PeekQueueValue = _require3.PeekQueueValue, + ResetQueue = _require3.ResetQueue; + var WritableStream = function () { + function WritableStream() { + var underlyingSink = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, + size = _ref.size, + _ref$highWaterMark = _ref.highWaterMark, + highWaterMark = _ref$highWaterMark === undefined ? 1 : _ref$highWaterMark; + _classCallCheck(this, WritableStream); + this._state = 'writable'; + this._storedError = undefined; + this._writer = undefined; + this._writableStreamController = undefined; + this._writeRequests = []; + this._inFlightWriteRequest = undefined; + this._closeRequest = undefined; + this._inFlightCloseRequest = undefined; + this._pendingAbortRequest = undefined; + this._backpressure = false; + var type = underlyingSink.type; + if (type !== undefined) { + throw new RangeError('Invalid type is specified'); + } + this._writableStreamController = new WritableStreamDefaultController(this, underlyingSink, size, highWaterMark); + this._writableStreamController.__startSteps(); + } + + _createClass(WritableStream, [{ + key: 'abort', + value: function abort(reason) { + if (IsWritableStream(this) === false) { + return Promise.reject(streamBrandCheckException('abort')); + } + if (IsWritableStreamLocked(this) === true) { + return Promise.reject(new TypeError('Cannot abort a stream that already has a writer')); + } + return WritableStreamAbort(this, reason); + } + }, { + key: 'getWriter', + value: function getWriter() { + if (IsWritableStream(this) === false) { + throw streamBrandCheckException('getWriter'); + } + return AcquireWritableStreamDefaultWriter(this); + } + }, { + key: 'locked', + get: function get() { + if (IsWritableStream(this) === false) { + throw streamBrandCheckException('locked'); + } + return IsWritableStreamLocked(this); + } + }]); + return WritableStream; + }(); + module.exports = { + AcquireWritableStreamDefaultWriter: AcquireWritableStreamDefaultWriter, + IsWritableStream: IsWritableStream, + IsWritableStreamLocked: IsWritableStreamLocked, + WritableStream: WritableStream, + WritableStreamAbort: WritableStreamAbort, + WritableStreamDefaultControllerError: WritableStreamDefaultControllerError, + WritableStreamDefaultWriterCloseWithErrorPropagation: WritableStreamDefaultWriterCloseWithErrorPropagation, + WritableStreamDefaultWriterRelease: WritableStreamDefaultWriterRelease, + WritableStreamDefaultWriterWrite: WritableStreamDefaultWriterWrite, + WritableStreamCloseQueuedOrInFlight: WritableStreamCloseQueuedOrInFlight + }; + + function AcquireWritableStreamDefaultWriter(stream) { + return new WritableStreamDefaultWriter(stream); + } + + function IsWritableStream(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_writableStreamController')) { + return false; + } + return true; + } + + function IsWritableStreamLocked(stream) { + assert(IsWritableStream(stream) === true, 'IsWritableStreamLocked should only be used on known writable streams'); + if (stream._writer === undefined) { + return false; + } + return true; + } + + function WritableStreamAbort(stream, reason) { + var state = stream._state; + if (state === 'closed') { + return Promise.resolve(undefined); + } + if (state === 'errored') { + return Promise.reject(stream._storedError); + } + var error = new TypeError('Requested to abort'); + if (stream._pendingAbortRequest !== undefined) { + return Promise.reject(error); + } + assert(state === 'writable' || state === 'erroring', 'state must be writable or erroring'); + var wasAlreadyErroring = false; + if (state === 'erroring') { + wasAlreadyErroring = true; + reason = undefined; + } + var promise = new Promise(function (resolve, reject) { + stream._pendingAbortRequest = { + _resolve: resolve, + _reject: reject, + _reason: reason, + _wasAlreadyErroring: wasAlreadyErroring + }; + }); + if (wasAlreadyErroring === false) { + WritableStreamStartErroring(stream, error); + } + return promise; + } + + function WritableStreamAddWriteRequest(stream) { + assert(IsWritableStreamLocked(stream) === true); + assert(stream._state === 'writable'); + var promise = new Promise(function (resolve, reject) { + var writeRequest = { + _resolve: resolve, + _reject: reject + }; + stream._writeRequests.push(writeRequest); + }); + return promise; + } + + function WritableStreamDealWithRejection(stream, error) { + var state = stream._state; + if (state === 'writable') { + WritableStreamStartErroring(stream, error); + return; + } + assert(state === 'erroring'); + WritableStreamFinishErroring(stream); + } + + function WritableStreamStartErroring(stream, reason) { + assert(stream._storedError === undefined, 'stream._storedError === undefined'); + assert(stream._state === 'writable', 'state must be writable'); + var controller = stream._writableStreamController; + assert(controller !== undefined, 'controller must not be undefined'); + stream._state = 'erroring'; + stream._storedError = reason; + var writer = stream._writer; + if (writer !== undefined) { + WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason); + } + if (WritableStreamHasOperationMarkedInFlight(stream) === false && controller._started === true) { + WritableStreamFinishErroring(stream); + } + } + + function WritableStreamFinishErroring(stream) { + assert(stream._state === 'erroring', 'stream._state === erroring'); + assert(WritableStreamHasOperationMarkedInFlight(stream) === false, 'WritableStreamHasOperationMarkedInFlight(stream) === false'); + stream._state = 'errored'; + stream._writableStreamController.__errorSteps(); + var storedError = stream._storedError; + for (var i = 0; i < stream._writeRequests.length; i++) { + var writeRequest = stream._writeRequests[i]; + writeRequest._reject(storedError); + } + stream._writeRequests = []; + if (stream._pendingAbortRequest === undefined) { + WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); + return; + } + var abortRequest = stream._pendingAbortRequest; + stream._pendingAbortRequest = undefined; + if (abortRequest._wasAlreadyErroring === true) { + abortRequest._reject(storedError); + WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); + return; + } + var promise = stream._writableStreamController.__abortSteps(abortRequest._reason); + promise.then(function () { + abortRequest._resolve(); + WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); + }, function (reason) { + abortRequest._reject(reason); + WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); + }); + } + + function WritableStreamFinishInFlightWrite(stream) { + assert(stream._inFlightWriteRequest !== undefined); + stream._inFlightWriteRequest._resolve(undefined); + stream._inFlightWriteRequest = undefined; + } + + function WritableStreamFinishInFlightWriteWithError(stream, error) { + assert(stream._inFlightWriteRequest !== undefined); + stream._inFlightWriteRequest._reject(error); + stream._inFlightWriteRequest = undefined; + assert(stream._state === 'writable' || stream._state === 'erroring'); + WritableStreamDealWithRejection(stream, error); + } + + function WritableStreamFinishInFlightClose(stream) { + assert(stream._inFlightCloseRequest !== undefined); + stream._inFlightCloseRequest._resolve(undefined); + stream._inFlightCloseRequest = undefined; + var state = stream._state; + assert(state === 'writable' || state === 'erroring'); + if (state === 'erroring') { + stream._storedError = undefined; + if (stream._pendingAbortRequest !== undefined) { + stream._pendingAbortRequest._resolve(); + stream._pendingAbortRequest = undefined; + } + } + stream._state = 'closed'; + var writer = stream._writer; + if (writer !== undefined) { + defaultWriterClosedPromiseResolve(writer); + } + assert(stream._pendingAbortRequest === undefined, 'stream._pendingAbortRequest === undefined'); + assert(stream._storedError === undefined, 'stream._storedError === undefined'); + } + + function WritableStreamFinishInFlightCloseWithError(stream, error) { + assert(stream._inFlightCloseRequest !== undefined); + stream._inFlightCloseRequest._reject(error); + stream._inFlightCloseRequest = undefined; + assert(stream._state === 'writable' || stream._state === 'erroring'); + if (stream._pendingAbortRequest !== undefined) { + stream._pendingAbortRequest._reject(error); + stream._pendingAbortRequest = undefined; + } + WritableStreamDealWithRejection(stream, error); + } + + function WritableStreamCloseQueuedOrInFlight(stream) { + if (stream._closeRequest === undefined && stream._inFlightCloseRequest === undefined) { + return false; + } + return true; + } + + function WritableStreamHasOperationMarkedInFlight(stream) { + if (stream._inFlightWriteRequest === undefined && stream._inFlightCloseRequest === undefined) { + return false; + } + return true; + } + + function WritableStreamMarkCloseRequestInFlight(stream) { + assert(stream._inFlightCloseRequest === undefined); + assert(stream._closeRequest !== undefined); + stream._inFlightCloseRequest = stream._closeRequest; + stream._closeRequest = undefined; + } + + function WritableStreamMarkFirstWriteRequestInFlight(stream) { + assert(stream._inFlightWriteRequest === undefined, 'there must be no pending write request'); + assert(stream._writeRequests.length !== 0, 'writeRequests must not be empty'); + stream._inFlightWriteRequest = stream._writeRequests.shift(); + } + + function WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream) { + assert(stream._state === 'errored', '_stream_.[[state]] is `"errored"`'); + if (stream._closeRequest !== undefined) { + assert(stream._inFlightCloseRequest === undefined); + stream._closeRequest._reject(stream._storedError); + stream._closeRequest = undefined; + } + var writer = stream._writer; + if (writer !== undefined) { + defaultWriterClosedPromiseReject(writer, stream._storedError); + writer._closedPromise.catch(function () { + }); + } + } + + function WritableStreamUpdateBackpressure(stream, backpressure) { + assert(stream._state === 'writable'); + assert(WritableStreamCloseQueuedOrInFlight(stream) === false); + var writer = stream._writer; + if (writer !== undefined && backpressure !== stream._backpressure) { + if (backpressure === true) { + defaultWriterReadyPromiseReset(writer); + } else { + assert(backpressure === false); + defaultWriterReadyPromiseResolve(writer); + } + } + stream._backpressure = backpressure; + } + + var WritableStreamDefaultWriter = function () { + function WritableStreamDefaultWriter(stream) { + _classCallCheck(this, WritableStreamDefaultWriter); + if (IsWritableStream(stream) === false) { + throw new TypeError('WritableStreamDefaultWriter can only be constructed with a WritableStream instance'); + } + if (IsWritableStreamLocked(stream) === true) { + throw new TypeError('This stream has already been locked for exclusive writing by another writer'); + } + this._ownerWritableStream = stream; + stream._writer = this; + var state = stream._state; + if (state === 'writable') { + if (WritableStreamCloseQueuedOrInFlight(stream) === false && stream._backpressure === true) { + defaultWriterReadyPromiseInitialize(this); + } else { + defaultWriterReadyPromiseInitializeAsResolved(this); + } + defaultWriterClosedPromiseInitialize(this); + } else if (state === 'erroring') { + defaultWriterReadyPromiseInitializeAsRejected(this, stream._storedError); + this._readyPromise.catch(function () { + }); + defaultWriterClosedPromiseInitialize(this); + } else if (state === 'closed') { + defaultWriterReadyPromiseInitializeAsResolved(this); + defaultWriterClosedPromiseInitializeAsResolved(this); + } else { + assert(state === 'errored', 'state must be errored'); + var storedError = stream._storedError; + defaultWriterReadyPromiseInitializeAsRejected(this, storedError); + this._readyPromise.catch(function () { + }); + defaultWriterClosedPromiseInitializeAsRejected(this, storedError); + this._closedPromise.catch(function () { + }); + } + } + + _createClass(WritableStreamDefaultWriter, [{ + key: 'abort', + value: function abort(reason) { + if (IsWritableStreamDefaultWriter(this) === false) { + return Promise.reject(defaultWriterBrandCheckException('abort')); + } + if (this._ownerWritableStream === undefined) { + return Promise.reject(defaultWriterLockException('abort')); + } + return WritableStreamDefaultWriterAbort(this, reason); + } + }, { + key: 'close', + value: function close() { + if (IsWritableStreamDefaultWriter(this) === false) { + return Promise.reject(defaultWriterBrandCheckException('close')); + } + var stream = this._ownerWritableStream; + if (stream === undefined) { + return Promise.reject(defaultWriterLockException('close')); + } + if (WritableStreamCloseQueuedOrInFlight(stream) === true) { + return Promise.reject(new TypeError('cannot close an already-closing stream')); + } + return WritableStreamDefaultWriterClose(this); + } + }, { + key: 'releaseLock', + value: function releaseLock() { + if (IsWritableStreamDefaultWriter(this) === false) { + throw defaultWriterBrandCheckException('releaseLock'); + } + var stream = this._ownerWritableStream; + if (stream === undefined) { + return; + } + assert(stream._writer !== undefined); + WritableStreamDefaultWriterRelease(this); + } + }, { + key: 'write', + value: function write(chunk) { + if (IsWritableStreamDefaultWriter(this) === false) { + return Promise.reject(defaultWriterBrandCheckException('write')); + } + if (this._ownerWritableStream === undefined) { + return Promise.reject(defaultWriterLockException('write to')); + } + return WritableStreamDefaultWriterWrite(this, chunk); + } + }, { + key: 'closed', + get: function get() { + if (IsWritableStreamDefaultWriter(this) === false) { + return Promise.reject(defaultWriterBrandCheckException('closed')); + } + return this._closedPromise; + } + }, { + key: 'desiredSize', + get: function get() { + if (IsWritableStreamDefaultWriter(this) === false) { + throw defaultWriterBrandCheckException('desiredSize'); + } + if (this._ownerWritableStream === undefined) { + throw defaultWriterLockException('desiredSize'); + } + return WritableStreamDefaultWriterGetDesiredSize(this); + } + }, { + key: 'ready', + get: function get() { + if (IsWritableStreamDefaultWriter(this) === false) { + return Promise.reject(defaultWriterBrandCheckException('ready')); + } + return this._readyPromise; + } + }]); + return WritableStreamDefaultWriter; + }(); + + function IsWritableStreamDefaultWriter(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_ownerWritableStream')) { + return false; + } + return true; + } + + function WritableStreamDefaultWriterAbort(writer, reason) { + var stream = writer._ownerWritableStream; + assert(stream !== undefined); + return WritableStreamAbort(stream, reason); + } + + function WritableStreamDefaultWriterClose(writer) { + var stream = writer._ownerWritableStream; + assert(stream !== undefined); + var state = stream._state; + if (state === 'closed' || state === 'errored') { + return Promise.reject(new TypeError('The stream (in ' + state + ' state) is not in the writable state and cannot be closed')); + } + assert(state === 'writable' || state === 'erroring'); + assert(WritableStreamCloseQueuedOrInFlight(stream) === false); + var promise = new Promise(function (resolve, reject) { + var closeRequest = { + _resolve: resolve, + _reject: reject + }; + stream._closeRequest = closeRequest; + }); + if (stream._backpressure === true && state === 'writable') { + defaultWriterReadyPromiseResolve(writer); + } + WritableStreamDefaultControllerClose(stream._writableStreamController); + return promise; + } + + function WritableStreamDefaultWriterCloseWithErrorPropagation(writer) { + var stream = writer._ownerWritableStream; + assert(stream !== undefined); + var state = stream._state; + if (WritableStreamCloseQueuedOrInFlight(stream) === true || state === 'closed') { + return Promise.resolve(); + } + if (state === 'errored') { + return Promise.reject(stream._storedError); + } + assert(state === 'writable' || state === 'erroring'); + return WritableStreamDefaultWriterClose(writer); + } + + function WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, error) { + if (writer._closedPromiseState === 'pending') { + defaultWriterClosedPromiseReject(writer, error); + } else { + defaultWriterClosedPromiseResetToRejected(writer, error); + } + writer._closedPromise.catch(function () { + }); + } + + function WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, error) { + if (writer._readyPromiseState === 'pending') { + defaultWriterReadyPromiseReject(writer, error); + } else { + defaultWriterReadyPromiseResetToRejected(writer, error); + } + writer._readyPromise.catch(function () { + }); + } + + function WritableStreamDefaultWriterGetDesiredSize(writer) { + var stream = writer._ownerWritableStream; + var state = stream._state; + if (state === 'errored' || state === 'erroring') { + return null; + } + if (state === 'closed') { + return 0; + } + return WritableStreamDefaultControllerGetDesiredSize(stream._writableStreamController); + } + + function WritableStreamDefaultWriterRelease(writer) { + var stream = writer._ownerWritableStream; + assert(stream !== undefined); + assert(stream._writer === writer); + var releasedError = new TypeError('Writer was released and can no longer be used to monitor the stream\'s closedness'); + WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, releasedError); + WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, releasedError); + stream._writer = undefined; + writer._ownerWritableStream = undefined; + } + + function WritableStreamDefaultWriterWrite(writer, chunk) { + var stream = writer._ownerWritableStream; + assert(stream !== undefined); + var controller = stream._writableStreamController; + var chunkSize = WritableStreamDefaultControllerGetChunkSize(controller, chunk); + if (stream !== writer._ownerWritableStream) { + return Promise.reject(defaultWriterLockException('write to')); + } + var state = stream._state; + if (state === 'errored') { + return Promise.reject(stream._storedError); + } + if (WritableStreamCloseQueuedOrInFlight(stream) === true || state === 'closed') { + return Promise.reject(new TypeError('The stream is closing or closed and cannot be written to')); + } + if (state === 'erroring') { + return Promise.reject(stream._storedError); + } + assert(state === 'writable'); + var promise = WritableStreamAddWriteRequest(stream); + WritableStreamDefaultControllerWrite(controller, chunk, chunkSize); + return promise; + } + + var WritableStreamDefaultController = function () { + function WritableStreamDefaultController(stream, underlyingSink, size, highWaterMark) { + _classCallCheck(this, WritableStreamDefaultController); + if (IsWritableStream(stream) === false) { + throw new TypeError('WritableStreamDefaultController can only be constructed with a WritableStream instance'); + } + if (stream._writableStreamController !== undefined) { + throw new TypeError('WritableStreamDefaultController instances can only be created by the WritableStream constructor'); + } + this._controlledWritableStream = stream; + this._underlyingSink = underlyingSink; + this._queue = undefined; + this._queueTotalSize = undefined; + ResetQueue(this); + this._started = false; + var normalizedStrategy = ValidateAndNormalizeQueuingStrategy(size, highWaterMark); + this._strategySize = normalizedStrategy.size; + this._strategyHWM = normalizedStrategy.highWaterMark; + var backpressure = WritableStreamDefaultControllerGetBackpressure(this); + WritableStreamUpdateBackpressure(stream, backpressure); + } + + _createClass(WritableStreamDefaultController, [{ + key: 'error', + value: function error(e) { + if (IsWritableStreamDefaultController(this) === false) { + throw new TypeError('WritableStreamDefaultController.prototype.error can only be used on a WritableStreamDefaultController'); + } + var state = this._controlledWritableStream._state; + if (state !== 'writable') { + return; + } + WritableStreamDefaultControllerError(this, e); + } + }, { + key: '__abortSteps', + value: function __abortSteps(reason) { + return PromiseInvokeOrNoop(this._underlyingSink, 'abort', [reason]); + } + }, { + key: '__errorSteps', + value: function __errorSteps() { + ResetQueue(this); + } + }, { + key: '__startSteps', + value: function __startSteps() { + var _this = this; + var startResult = InvokeOrNoop(this._underlyingSink, 'start', [this]); + var stream = this._controlledWritableStream; + Promise.resolve(startResult).then(function () { + assert(stream._state === 'writable' || stream._state === 'erroring'); + _this._started = true; + WritableStreamDefaultControllerAdvanceQueueIfNeeded(_this); + }, function (r) { + assert(stream._state === 'writable' || stream._state === 'erroring'); + _this._started = true; + WritableStreamDealWithRejection(stream, r); + }).catch(rethrowAssertionErrorRejection); + } + }]); + return WritableStreamDefaultController; + }(); + + function WritableStreamDefaultControllerClose(controller) { + EnqueueValueWithSize(controller, 'close', 0); + WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); + } + + function WritableStreamDefaultControllerGetChunkSize(controller, chunk) { + var strategySize = controller._strategySize; + if (strategySize === undefined) { + return 1; + } + try { + return strategySize(chunk); + } catch (chunkSizeE) { + WritableStreamDefaultControllerErrorIfNeeded(controller, chunkSizeE); + return 1; + } + } + + function WritableStreamDefaultControllerGetDesiredSize(controller) { + return controller._strategyHWM - controller._queueTotalSize; + } + + function WritableStreamDefaultControllerWrite(controller, chunk, chunkSize) { + var writeRecord = {chunk: chunk}; + try { + EnqueueValueWithSize(controller, writeRecord, chunkSize); + } catch (enqueueE) { + WritableStreamDefaultControllerErrorIfNeeded(controller, enqueueE); + return; + } + var stream = controller._controlledWritableStream; + if (WritableStreamCloseQueuedOrInFlight(stream) === false && stream._state === 'writable') { + var backpressure = WritableStreamDefaultControllerGetBackpressure(controller); + WritableStreamUpdateBackpressure(stream, backpressure); + } + WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); + } + + function IsWritableStreamDefaultController(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_underlyingSink')) { + return false; + } + return true; + } + + function WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller) { + var stream = controller._controlledWritableStream; + if (controller._started === false) { + return; + } + if (stream._inFlightWriteRequest !== undefined) { + return; + } + var state = stream._state; + if (state === 'closed' || state === 'errored') { + return; + } + if (state === 'erroring') { + WritableStreamFinishErroring(stream); + return; + } + if (controller._queue.length === 0) { + return; + } + var writeRecord = PeekQueueValue(controller); + if (writeRecord === 'close') { + WritableStreamDefaultControllerProcessClose(controller); + } else { + WritableStreamDefaultControllerProcessWrite(controller, writeRecord.chunk); + } + } + + function WritableStreamDefaultControllerErrorIfNeeded(controller, error) { + if (controller._controlledWritableStream._state === 'writable') { + WritableStreamDefaultControllerError(controller, error); + } + } + + function WritableStreamDefaultControllerProcessClose(controller) { + var stream = controller._controlledWritableStream; + WritableStreamMarkCloseRequestInFlight(stream); + DequeueValue(controller); + assert(controller._queue.length === 0, 'queue must be empty once the final write record is dequeued'); + var sinkClosePromise = PromiseInvokeOrNoop(controller._underlyingSink, 'close', []); + sinkClosePromise.then(function () { + WritableStreamFinishInFlightClose(stream); + }, function (reason) { + WritableStreamFinishInFlightCloseWithError(stream, reason); + }).catch(rethrowAssertionErrorRejection); + } + + function WritableStreamDefaultControllerProcessWrite(controller, chunk) { + var stream = controller._controlledWritableStream; + WritableStreamMarkFirstWriteRequestInFlight(stream); + var sinkWritePromise = PromiseInvokeOrNoop(controller._underlyingSink, 'write', [chunk, controller]); + sinkWritePromise.then(function () { + WritableStreamFinishInFlightWrite(stream); + var state = stream._state; + assert(state === 'writable' || state === 'erroring'); + DequeueValue(controller); + if (WritableStreamCloseQueuedOrInFlight(stream) === false && state === 'writable') { + var backpressure = WritableStreamDefaultControllerGetBackpressure(controller); + WritableStreamUpdateBackpressure(stream, backpressure); + } + WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); + }, function (reason) { + WritableStreamFinishInFlightWriteWithError(stream, reason); + }).catch(rethrowAssertionErrorRejection); + } + + function WritableStreamDefaultControllerGetBackpressure(controller) { + var desiredSize = WritableStreamDefaultControllerGetDesiredSize(controller); + return desiredSize <= 0; + } + + function WritableStreamDefaultControllerError(controller, error) { + var stream = controller._controlledWritableStream; + assert(stream._state === 'writable'); + WritableStreamStartErroring(stream, error); + } + + function streamBrandCheckException(name) { + return new TypeError('WritableStream.prototype.' + name + ' can only be used on a WritableStream'); + } + + function defaultWriterBrandCheckException(name) { + return new TypeError('WritableStreamDefaultWriter.prototype.' + name + ' can only be used on a WritableStreamDefaultWriter'); + } + + function defaultWriterLockException(name) { + return new TypeError('Cannot ' + name + ' a stream using a released writer'); + } + + function defaultWriterClosedPromiseInitialize(writer) { + writer._closedPromise = new Promise(function (resolve, reject) { + writer._closedPromise_resolve = resolve; + writer._closedPromise_reject = reject; + writer._closedPromiseState = 'pending'; + }); + } + + function defaultWriterClosedPromiseInitializeAsRejected(writer, reason) { + writer._closedPromise = Promise.reject(reason); + writer._closedPromise_resolve = undefined; + writer._closedPromise_reject = undefined; + writer._closedPromiseState = 'rejected'; + } + + function defaultWriterClosedPromiseInitializeAsResolved(writer) { + writer._closedPromise = Promise.resolve(undefined); + writer._closedPromise_resolve = undefined; + writer._closedPromise_reject = undefined; + writer._closedPromiseState = 'resolved'; + } + + function defaultWriterClosedPromiseReject(writer, reason) { + assert(writer._closedPromise_resolve !== undefined, 'writer._closedPromise_resolve !== undefined'); + assert(writer._closedPromise_reject !== undefined, 'writer._closedPromise_reject !== undefined'); + assert(writer._closedPromiseState === 'pending', 'writer._closedPromiseState is pending'); + writer._closedPromise_reject(reason); + writer._closedPromise_resolve = undefined; + writer._closedPromise_reject = undefined; + writer._closedPromiseState = 'rejected'; + } + + function defaultWriterClosedPromiseResetToRejected(writer, reason) { + assert(writer._closedPromise_resolve === undefined, 'writer._closedPromise_resolve === undefined'); + assert(writer._closedPromise_reject === undefined, 'writer._closedPromise_reject === undefined'); + assert(writer._closedPromiseState !== 'pending', 'writer._closedPromiseState is not pending'); + writer._closedPromise = Promise.reject(reason); + writer._closedPromiseState = 'rejected'; + } + + function defaultWriterClosedPromiseResolve(writer) { + assert(writer._closedPromise_resolve !== undefined, 'writer._closedPromise_resolve !== undefined'); + assert(writer._closedPromise_reject !== undefined, 'writer._closedPromise_reject !== undefined'); + assert(writer._closedPromiseState === 'pending', 'writer._closedPromiseState is pending'); + writer._closedPromise_resolve(undefined); + writer._closedPromise_resolve = undefined; + writer._closedPromise_reject = undefined; + writer._closedPromiseState = 'resolved'; + } + + function defaultWriterReadyPromiseInitialize(writer) { + writer._readyPromise = new Promise(function (resolve, reject) { + writer._readyPromise_resolve = resolve; + writer._readyPromise_reject = reject; + }); + writer._readyPromiseState = 'pending'; + } + + function defaultWriterReadyPromiseInitializeAsRejected(writer, reason) { + writer._readyPromise = Promise.reject(reason); + writer._readyPromise_resolve = undefined; + writer._readyPromise_reject = undefined; + writer._readyPromiseState = 'rejected'; + } + + function defaultWriterReadyPromiseInitializeAsResolved(writer) { + writer._readyPromise = Promise.resolve(undefined); + writer._readyPromise_resolve = undefined; + writer._readyPromise_reject = undefined; + writer._readyPromiseState = 'fulfilled'; + } + + function defaultWriterReadyPromiseReject(writer, reason) { + assert(writer._readyPromise_resolve !== undefined, 'writer._readyPromise_resolve !== undefined'); + assert(writer._readyPromise_reject !== undefined, 'writer._readyPromise_reject !== undefined'); + writer._readyPromise_reject(reason); + writer._readyPromise_resolve = undefined; + writer._readyPromise_reject = undefined; + writer._readyPromiseState = 'rejected'; + } + + function defaultWriterReadyPromiseReset(writer) { + assert(writer._readyPromise_resolve === undefined, 'writer._readyPromise_resolve === undefined'); + assert(writer._readyPromise_reject === undefined, 'writer._readyPromise_reject === undefined'); + writer._readyPromise = new Promise(function (resolve, reject) { + writer._readyPromise_resolve = resolve; + writer._readyPromise_reject = reject; + }); + writer._readyPromiseState = 'pending'; + } + + function defaultWriterReadyPromiseResetToRejected(writer, reason) { + assert(writer._readyPromise_resolve === undefined, 'writer._readyPromise_resolve === undefined'); + assert(writer._readyPromise_reject === undefined, 'writer._readyPromise_reject === undefined'); + writer._readyPromise = Promise.reject(reason); + writer._readyPromiseState = 'rejected'; + } + + function defaultWriterReadyPromiseResolve(writer) { + assert(writer._readyPromise_resolve !== undefined, 'writer._readyPromise_resolve !== undefined'); + assert(writer._readyPromise_reject !== undefined, 'writer._readyPromise_reject !== undefined'); + writer._readyPromise_resolve(undefined); + writer._readyPromise_resolve = undefined; + writer._readyPromise_reject = undefined; + writer._readyPromiseState = 'fulfilled'; + } + }, function (module, exports, __w_pdfjs_require__) { + "use strict"; + + var _require = __w_pdfjs_require__(0), + IsFiniteNonNegativeNumber = _require.IsFiniteNonNegativeNumber; + var _require2 = __w_pdfjs_require__(1), + assert = _require2.assert; + exports.DequeueValue = function (container) { + assert('_queue' in container && '_queueTotalSize' in container, 'Spec-level failure: DequeueValue should only be used on containers with [[queue]] and [[queueTotalSize]].'); + assert(container._queue.length > 0, 'Spec-level failure: should never dequeue from an empty queue.'); + var pair = container._queue.shift(); + container._queueTotalSize -= pair.size; + if (container._queueTotalSize < 0) { + container._queueTotalSize = 0; + } + return pair.value; + }; + exports.EnqueueValueWithSize = function (container, value, size) { + assert('_queue' in container && '_queueTotalSize' in container, 'Spec-level failure: EnqueueValueWithSize should only be used on containers with [[queue]] and ' + '[[queueTotalSize]].'); + size = Number(size); + if (!IsFiniteNonNegativeNumber(size)) { + throw new RangeError('Size must be a finite, non-NaN, non-negative number.'); + } + container._queue.push({ + value: value, + size: size + }); + container._queueTotalSize += size; + }; + exports.PeekQueueValue = function (container) { + assert('_queue' in container && '_queueTotalSize' in container, 'Spec-level failure: PeekQueueValue should only be used on containers with [[queue]] and [[queueTotalSize]].'); + assert(container._queue.length > 0, 'Spec-level failure: should never peek at an empty queue.'); + var pair = container._queue[0]; + return pair.value; + }; + exports.ResetQueue = function (container) { + assert('_queue' in container && '_queueTotalSize' in container, 'Spec-level failure: ResetQueue should only be used on containers with [[queue]] and [[queueTotalSize]].'); + container._queue = []; + container._queueTotalSize = 0; + }; + }, function (module, exports, __w_pdfjs_require__) { + "use strict"; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var _require = __w_pdfjs_require__(0), + ArrayBufferCopy = _require.ArrayBufferCopy, + CreateIterResultObject = _require.CreateIterResultObject, + IsFiniteNonNegativeNumber = _require.IsFiniteNonNegativeNumber, + InvokeOrNoop = _require.InvokeOrNoop, + PromiseInvokeOrNoop = _require.PromiseInvokeOrNoop, + TransferArrayBuffer = _require.TransferArrayBuffer, + ValidateAndNormalizeQueuingStrategy = _require.ValidateAndNormalizeQueuingStrategy, + ValidateAndNormalizeHighWaterMark = _require.ValidateAndNormalizeHighWaterMark; + var _require2 = __w_pdfjs_require__(0), + createArrayFromList = _require2.createArrayFromList, + createDataProperty = _require2.createDataProperty, + typeIsObject = _require2.typeIsObject; + var _require3 = __w_pdfjs_require__(1), + assert = _require3.assert, + rethrowAssertionErrorRejection = _require3.rethrowAssertionErrorRejection; + var _require4 = __w_pdfjs_require__(3), + DequeueValue = _require4.DequeueValue, + EnqueueValueWithSize = _require4.EnqueueValueWithSize, + ResetQueue = _require4.ResetQueue; + var _require5 = __w_pdfjs_require__(2), + AcquireWritableStreamDefaultWriter = _require5.AcquireWritableStreamDefaultWriter, + IsWritableStream = _require5.IsWritableStream, + IsWritableStreamLocked = _require5.IsWritableStreamLocked, + WritableStreamAbort = _require5.WritableStreamAbort, + WritableStreamDefaultWriterCloseWithErrorPropagation = _require5.WritableStreamDefaultWriterCloseWithErrorPropagation, + WritableStreamDefaultWriterRelease = _require5.WritableStreamDefaultWriterRelease, + WritableStreamDefaultWriterWrite = _require5.WritableStreamDefaultWriterWrite, + WritableStreamCloseQueuedOrInFlight = _require5.WritableStreamCloseQueuedOrInFlight; + var ReadableStream = function () { + function ReadableStream() { + var underlyingSource = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, + size = _ref.size, + highWaterMark = _ref.highWaterMark; + _classCallCheck(this, ReadableStream); + this._state = 'readable'; + this._reader = undefined; + this._storedError = undefined; + this._disturbed = false; + this._readableStreamController = undefined; + var type = underlyingSource.type; + var typeString = String(type); + if (typeString === 'bytes') { + if (highWaterMark === undefined) { + highWaterMark = 0; + } + this._readableStreamController = new ReadableByteStreamController(this, underlyingSource, highWaterMark); + } else if (type === undefined) { + if (highWaterMark === undefined) { + highWaterMark = 1; + } + this._readableStreamController = new ReadableStreamDefaultController(this, underlyingSource, size, highWaterMark); + } else { + throw new RangeError('Invalid type is specified'); + } + } + + _createClass(ReadableStream, [{ + key: 'cancel', + value: function cancel(reason) { + if (IsReadableStream(this) === false) { + return Promise.reject(streamBrandCheckException('cancel')); + } + if (IsReadableStreamLocked(this) === true) { + return Promise.reject(new TypeError('Cannot cancel a stream that already has a reader')); + } + return ReadableStreamCancel(this, reason); + } + }, { + key: 'getReader', + value: function getReader() { + var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, + mode = _ref2.mode; + if (IsReadableStream(this) === false) { + throw streamBrandCheckException('getReader'); + } + if (mode === undefined) { + return AcquireReadableStreamDefaultReader(this); + } + mode = String(mode); + if (mode === 'byob') { + return AcquireReadableStreamBYOBReader(this); + } + throw new RangeError('Invalid mode is specified'); + } + }, { + key: 'pipeThrough', + value: function pipeThrough(_ref3, options) { + var writable = _ref3.writable, + readable = _ref3.readable; + var promise = this.pipeTo(writable, options); + ifIsObjectAndHasAPromiseIsHandledInternalSlotSetPromiseIsHandledToTrue(promise); + return readable; + } + }, { + key: 'pipeTo', + value: function pipeTo(dest) { + var _this = this; + var _ref4 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, + preventClose = _ref4.preventClose, + preventAbort = _ref4.preventAbort, + preventCancel = _ref4.preventCancel; + if (IsReadableStream(this) === false) { + return Promise.reject(streamBrandCheckException('pipeTo')); + } + if (IsWritableStream(dest) === false) { + return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo\'s first argument must be a WritableStream')); + } + preventClose = Boolean(preventClose); + preventAbort = Boolean(preventAbort); + preventCancel = Boolean(preventCancel); + if (IsReadableStreamLocked(this) === true) { + return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo cannot be used on a locked ReadableStream')); + } + if (IsWritableStreamLocked(dest) === true) { + return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo cannot be used on a locked WritableStream')); + } + var reader = AcquireReadableStreamDefaultReader(this); + var writer = AcquireWritableStreamDefaultWriter(dest); + var shuttingDown = false; + var currentWrite = Promise.resolve(); + return new Promise(function (resolve, reject) { + function pipeLoop() { + currentWrite = Promise.resolve(); + if (shuttingDown === true) { + return Promise.resolve(); + } + return writer._readyPromise.then(function () { + return ReadableStreamDefaultReaderRead(reader).then(function (_ref5) { + var value = _ref5.value, + done = _ref5.done; + if (done === true) { + return; + } + currentWrite = WritableStreamDefaultWriterWrite(writer, value).catch(function () { + }); + }); + }).then(pipeLoop); + } + + isOrBecomesErrored(_this, reader._closedPromise, function (storedError) { + if (preventAbort === false) { + shutdownWithAction(function () { + return WritableStreamAbort(dest, storedError); + }, true, storedError); + } else { + shutdown(true, storedError); + } + }); + isOrBecomesErrored(dest, writer._closedPromise, function (storedError) { + if (preventCancel === false) { + shutdownWithAction(function () { + return ReadableStreamCancel(_this, storedError); + }, true, storedError); + } else { + shutdown(true, storedError); + } + }); + isOrBecomesClosed(_this, reader._closedPromise, function () { + if (preventClose === false) { + shutdownWithAction(function () { + return WritableStreamDefaultWriterCloseWithErrorPropagation(writer); + }); + } else { + shutdown(); + } + }); + if (WritableStreamCloseQueuedOrInFlight(dest) === true || dest._state === 'closed') { + var destClosed = new TypeError('the destination writable stream closed before all data could be piped to it'); + if (preventCancel === false) { + shutdownWithAction(function () { + return ReadableStreamCancel(_this, destClosed); + }, true, destClosed); + } else { + shutdown(true, destClosed); + } + } + pipeLoop().catch(function (err) { + currentWrite = Promise.resolve(); + rethrowAssertionErrorRejection(err); + }); + + function waitForWritesToFinish() { + var oldCurrentWrite = currentWrite; + return currentWrite.then(function () { + return oldCurrentWrite !== currentWrite ? waitForWritesToFinish() : undefined; + }); + } + + function isOrBecomesErrored(stream, promise, action) { + if (stream._state === 'errored') { + action(stream._storedError); + } else { + promise.catch(action).catch(rethrowAssertionErrorRejection); + } + } + + function isOrBecomesClosed(stream, promise, action) { + if (stream._state === 'closed') { + action(); + } else { + promise.then(action).catch(rethrowAssertionErrorRejection); + } + } + + function shutdownWithAction(action, originalIsError, originalError) { + if (shuttingDown === true) { + return; + } + shuttingDown = true; + if (dest._state === 'writable' && WritableStreamCloseQueuedOrInFlight(dest) === false) { + waitForWritesToFinish().then(doTheRest); + } else { + doTheRest(); + } + + function doTheRest() { + action().then(function () { + return finalize(originalIsError, originalError); + }, function (newError) { + return finalize(true, newError); + }).catch(rethrowAssertionErrorRejection); + } + } + + function shutdown(isError, error) { + if (shuttingDown === true) { + return; + } + shuttingDown = true; + if (dest._state === 'writable' && WritableStreamCloseQueuedOrInFlight(dest) === false) { + waitForWritesToFinish().then(function () { + return finalize(isError, error); + }).catch(rethrowAssertionErrorRejection); + } else { + finalize(isError, error); + } + } + + function finalize(isError, error) { + WritableStreamDefaultWriterRelease(writer); + ReadableStreamReaderGenericRelease(reader); + if (isError) { + reject(error); + } else { + resolve(undefined); + } + } + }); + } + }, { + key: 'tee', + value: function tee() { + if (IsReadableStream(this) === false) { + throw streamBrandCheckException('tee'); + } + var branches = ReadableStreamTee(this, false); + return createArrayFromList(branches); + } + }, { + key: 'locked', + get: function get() { + if (IsReadableStream(this) === false) { + throw streamBrandCheckException('locked'); + } + return IsReadableStreamLocked(this); + } + }]); + return ReadableStream; + }(); + module.exports = { + ReadableStream: ReadableStream, + IsReadableStreamDisturbed: IsReadableStreamDisturbed, + ReadableStreamDefaultControllerClose: ReadableStreamDefaultControllerClose, + ReadableStreamDefaultControllerEnqueue: ReadableStreamDefaultControllerEnqueue, + ReadableStreamDefaultControllerError: ReadableStreamDefaultControllerError, + ReadableStreamDefaultControllerGetDesiredSize: ReadableStreamDefaultControllerGetDesiredSize + }; + + function AcquireReadableStreamBYOBReader(stream) { + return new ReadableStreamBYOBReader(stream); + } + + function AcquireReadableStreamDefaultReader(stream) { + return new ReadableStreamDefaultReader(stream); + } + + function IsReadableStream(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_readableStreamController')) { + return false; + } + return true; + } + + function IsReadableStreamDisturbed(stream) { + assert(IsReadableStream(stream) === true, 'IsReadableStreamDisturbed should only be used on known readable streams'); + return stream._disturbed; + } + + function IsReadableStreamLocked(stream) { + assert(IsReadableStream(stream) === true, 'IsReadableStreamLocked should only be used on known readable streams'); + if (stream._reader === undefined) { + return false; + } + return true; + } + + function ReadableStreamTee(stream, cloneForBranch2) { + assert(IsReadableStream(stream) === true); + assert(typeof cloneForBranch2 === 'boolean'); + var reader = AcquireReadableStreamDefaultReader(stream); + var teeState = { + closedOrErrored: false, + canceled1: false, + canceled2: false, + reason1: undefined, + reason2: undefined + }; + teeState.promise = new Promise(function (resolve) { + teeState._resolve = resolve; + }); + var pull = create_ReadableStreamTeePullFunction(); + pull._reader = reader; + pull._teeState = teeState; + pull._cloneForBranch2 = cloneForBranch2; + var cancel1 = create_ReadableStreamTeeBranch1CancelFunction(); + cancel1._stream = stream; + cancel1._teeState = teeState; + var cancel2 = create_ReadableStreamTeeBranch2CancelFunction(); + cancel2._stream = stream; + cancel2._teeState = teeState; + var underlyingSource1 = Object.create(Object.prototype); + createDataProperty(underlyingSource1, 'pull', pull); + createDataProperty(underlyingSource1, 'cancel', cancel1); + var branch1Stream = new ReadableStream(underlyingSource1); + var underlyingSource2 = Object.create(Object.prototype); + createDataProperty(underlyingSource2, 'pull', pull); + createDataProperty(underlyingSource2, 'cancel', cancel2); + var branch2Stream = new ReadableStream(underlyingSource2); + pull._branch1 = branch1Stream._readableStreamController; + pull._branch2 = branch2Stream._readableStreamController; + reader._closedPromise.catch(function (r) { + if (teeState.closedOrErrored === true) { + return; + } + ReadableStreamDefaultControllerError(pull._branch1, r); + ReadableStreamDefaultControllerError(pull._branch2, r); + teeState.closedOrErrored = true; + }); + return [branch1Stream, branch2Stream]; + } + + function create_ReadableStreamTeePullFunction() { + function f() { + var reader = f._reader, + branch1 = f._branch1, + branch2 = f._branch2, + teeState = f._teeState; + return ReadableStreamDefaultReaderRead(reader).then(function (result) { + assert(typeIsObject(result)); + var value = result.value; + var done = result.done; + assert(typeof done === 'boolean'); + if (done === true && teeState.closedOrErrored === false) { + if (teeState.canceled1 === false) { + ReadableStreamDefaultControllerClose(branch1); + } + if (teeState.canceled2 === false) { + ReadableStreamDefaultControllerClose(branch2); + } + teeState.closedOrErrored = true; + } + if (teeState.closedOrErrored === true) { + return; + } + var value1 = value; + var value2 = value; + if (teeState.canceled1 === false) { + ReadableStreamDefaultControllerEnqueue(branch1, value1); + } + if (teeState.canceled2 === false) { + ReadableStreamDefaultControllerEnqueue(branch2, value2); + } + }); + } + + return f; + } + + function create_ReadableStreamTeeBranch1CancelFunction() { + function f(reason) { + var stream = f._stream, + teeState = f._teeState; + teeState.canceled1 = true; + teeState.reason1 = reason; + if (teeState.canceled2 === true) { + var compositeReason = createArrayFromList([teeState.reason1, teeState.reason2]); + var cancelResult = ReadableStreamCancel(stream, compositeReason); + teeState._resolve(cancelResult); + } + return teeState.promise; + } + + return f; + } + + function create_ReadableStreamTeeBranch2CancelFunction() { + function f(reason) { + var stream = f._stream, + teeState = f._teeState; + teeState.canceled2 = true; + teeState.reason2 = reason; + if (teeState.canceled1 === true) { + var compositeReason = createArrayFromList([teeState.reason1, teeState.reason2]); + var cancelResult = ReadableStreamCancel(stream, compositeReason); + teeState._resolve(cancelResult); + } + return teeState.promise; + } + + return f; + } + + function ReadableStreamAddReadIntoRequest(stream) { + assert(IsReadableStreamBYOBReader(stream._reader) === true); + assert(stream._state === 'readable' || stream._state === 'closed'); + var promise = new Promise(function (resolve, reject) { + var readIntoRequest = { + _resolve: resolve, + _reject: reject + }; + stream._reader._readIntoRequests.push(readIntoRequest); + }); + return promise; + } + + function ReadableStreamAddReadRequest(stream) { + assert(IsReadableStreamDefaultReader(stream._reader) === true); + assert(stream._state === 'readable'); + var promise = new Promise(function (resolve, reject) { + var readRequest = { + _resolve: resolve, + _reject: reject + }; + stream._reader._readRequests.push(readRequest); + }); + return promise; + } + + function ReadableStreamCancel(stream, reason) { + stream._disturbed = true; + if (stream._state === 'closed') { + return Promise.resolve(undefined); + } + if (stream._state === 'errored') { + return Promise.reject(stream._storedError); + } + ReadableStreamClose(stream); + var sourceCancelPromise = stream._readableStreamController.__cancelSteps(reason); + return sourceCancelPromise.then(function () { + return undefined; + }); + } + + function ReadableStreamClose(stream) { + assert(stream._state === 'readable'); + stream._state = 'closed'; + var reader = stream._reader; + if (reader === undefined) { + return undefined; + } + if (IsReadableStreamDefaultReader(reader) === true) { + for (var i = 0; i < reader._readRequests.length; i++) { + var _resolve = reader._readRequests[i]._resolve; + _resolve(CreateIterResultObject(undefined, true)); + } + reader._readRequests = []; + } + defaultReaderClosedPromiseResolve(reader); + return undefined; + } + + function ReadableStreamError(stream, e) { + assert(IsReadableStream(stream) === true, 'stream must be ReadableStream'); + assert(stream._state === 'readable', 'state must be readable'); + stream._state = 'errored'; + stream._storedError = e; + var reader = stream._reader; + if (reader === undefined) { + return undefined; + } + if (IsReadableStreamDefaultReader(reader) === true) { + for (var i = 0; i < reader._readRequests.length; i++) { + var readRequest = reader._readRequests[i]; + readRequest._reject(e); + } + reader._readRequests = []; + } else { + assert(IsReadableStreamBYOBReader(reader), 'reader must be ReadableStreamBYOBReader'); + for (var _i = 0; _i < reader._readIntoRequests.length; _i++) { + var readIntoRequest = reader._readIntoRequests[_i]; + readIntoRequest._reject(e); + } + reader._readIntoRequests = []; + } + defaultReaderClosedPromiseReject(reader, e); + reader._closedPromise.catch(function () { + }); + } + + function ReadableStreamFulfillReadIntoRequest(stream, chunk, done) { + var reader = stream._reader; + assert(reader._readIntoRequests.length > 0); + var readIntoRequest = reader._readIntoRequests.shift(); + readIntoRequest._resolve(CreateIterResultObject(chunk, done)); + } + + function ReadableStreamFulfillReadRequest(stream, chunk, done) { + var reader = stream._reader; + assert(reader._readRequests.length > 0); + var readRequest = reader._readRequests.shift(); + readRequest._resolve(CreateIterResultObject(chunk, done)); + } + + function ReadableStreamGetNumReadIntoRequests(stream) { + return stream._reader._readIntoRequests.length; + } + + function ReadableStreamGetNumReadRequests(stream) { + return stream._reader._readRequests.length; + } + + function ReadableStreamHasBYOBReader(stream) { + var reader = stream._reader; + if (reader === undefined) { + return false; + } + if (IsReadableStreamBYOBReader(reader) === false) { + return false; + } + return true; + } + + function ReadableStreamHasDefaultReader(stream) { + var reader = stream._reader; + if (reader === undefined) { + return false; + } + if (IsReadableStreamDefaultReader(reader) === false) { + return false; + } + return true; + } + + var ReadableStreamDefaultReader = function () { + function ReadableStreamDefaultReader(stream) { + _classCallCheck(this, ReadableStreamDefaultReader); + if (IsReadableStream(stream) === false) { + throw new TypeError('ReadableStreamDefaultReader can only be constructed with a ReadableStream instance'); + } + if (IsReadableStreamLocked(stream) === true) { + throw new TypeError('This stream has already been locked for exclusive reading by another reader'); + } + ReadableStreamReaderGenericInitialize(this, stream); + this._readRequests = []; + } + + _createClass(ReadableStreamDefaultReader, [{ + key: 'cancel', + value: function cancel(reason) { + if (IsReadableStreamDefaultReader(this) === false) { + return Promise.reject(defaultReaderBrandCheckException('cancel')); + } + if (this._ownerReadableStream === undefined) { + return Promise.reject(readerLockException('cancel')); + } + return ReadableStreamReaderGenericCancel(this, reason); + } + }, { + key: 'read', + value: function read() { + if (IsReadableStreamDefaultReader(this) === false) { + return Promise.reject(defaultReaderBrandCheckException('read')); + } + if (this._ownerReadableStream === undefined) { + return Promise.reject(readerLockException('read from')); + } + return ReadableStreamDefaultReaderRead(this); + } + }, { + key: 'releaseLock', + value: function releaseLock() { + if (IsReadableStreamDefaultReader(this) === false) { + throw defaultReaderBrandCheckException('releaseLock'); + } + if (this._ownerReadableStream === undefined) { + return; + } + if (this._readRequests.length > 0) { + throw new TypeError('Tried to release a reader lock when that reader has pending read() calls un-settled'); + } + ReadableStreamReaderGenericRelease(this); + } + }, { + key: 'closed', + get: function get() { + if (IsReadableStreamDefaultReader(this) === false) { + return Promise.reject(defaultReaderBrandCheckException('closed')); + } + return this._closedPromise; + } + }]); + return ReadableStreamDefaultReader; + }(); + var ReadableStreamBYOBReader = function () { + function ReadableStreamBYOBReader(stream) { + _classCallCheck(this, ReadableStreamBYOBReader); + if (!IsReadableStream(stream)) { + throw new TypeError('ReadableStreamBYOBReader can only be constructed with a ReadableStream instance given a ' + 'byte source'); + } + if (IsReadableByteStreamController(stream._readableStreamController) === false) { + throw new TypeError('Cannot construct a ReadableStreamBYOBReader for a stream not constructed with a byte ' + 'source'); + } + if (IsReadableStreamLocked(stream)) { + throw new TypeError('This stream has already been locked for exclusive reading by another reader'); + } + ReadableStreamReaderGenericInitialize(this, stream); + this._readIntoRequests = []; + } + + _createClass(ReadableStreamBYOBReader, [{ + key: 'cancel', + value: function cancel(reason) { + if (!IsReadableStreamBYOBReader(this)) { + return Promise.reject(byobReaderBrandCheckException('cancel')); + } + if (this._ownerReadableStream === undefined) { + return Promise.reject(readerLockException('cancel')); + } + return ReadableStreamReaderGenericCancel(this, reason); + } + }, { + key: 'read', + value: function read(view) { + if (!IsReadableStreamBYOBReader(this)) { + return Promise.reject(byobReaderBrandCheckException('read')); + } + if (this._ownerReadableStream === undefined) { + return Promise.reject(readerLockException('read from')); + } + if (!ArrayBuffer.isView(view)) { + return Promise.reject(new TypeError('view must be an array buffer view')); + } + if (view.byteLength === 0) { + return Promise.reject(new TypeError('view must have non-zero byteLength')); + } + return ReadableStreamBYOBReaderRead(this, view); + } + }, { + key: 'releaseLock', + value: function releaseLock() { + if (!IsReadableStreamBYOBReader(this)) { + throw byobReaderBrandCheckException('releaseLock'); + } + if (this._ownerReadableStream === undefined) { + return; + } + if (this._readIntoRequests.length > 0) { + throw new TypeError('Tried to release a reader lock when that reader has pending read() calls un-settled'); + } + ReadableStreamReaderGenericRelease(this); + } + }, { + key: 'closed', + get: function get() { + if (!IsReadableStreamBYOBReader(this)) { + return Promise.reject(byobReaderBrandCheckException('closed')); + } + return this._closedPromise; + } + }]); + return ReadableStreamBYOBReader; + }(); + + function IsReadableStreamBYOBReader(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_readIntoRequests')) { + return false; + } + return true; + } + + function IsReadableStreamDefaultReader(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_readRequests')) { + return false; + } + return true; + } + + function ReadableStreamReaderGenericInitialize(reader, stream) { + reader._ownerReadableStream = stream; + stream._reader = reader; + if (stream._state === 'readable') { + defaultReaderClosedPromiseInitialize(reader); + } else if (stream._state === 'closed') { + defaultReaderClosedPromiseInitializeAsResolved(reader); + } else { + assert(stream._state === 'errored', 'state must be errored'); + defaultReaderClosedPromiseInitializeAsRejected(reader, stream._storedError); + reader._closedPromise.catch(function () { + }); + } + } + + function ReadableStreamReaderGenericCancel(reader, reason) { + var stream = reader._ownerReadableStream; + assert(stream !== undefined); + return ReadableStreamCancel(stream, reason); + } + + function ReadableStreamReaderGenericRelease(reader) { + assert(reader._ownerReadableStream !== undefined); + assert(reader._ownerReadableStream._reader === reader); + if (reader._ownerReadableStream._state === 'readable') { + defaultReaderClosedPromiseReject(reader, new TypeError('Reader was released and can no longer be used to monitor the stream\'s closedness')); + } else { + defaultReaderClosedPromiseResetToRejected(reader, new TypeError('Reader was released and can no longer be used to monitor the stream\'s closedness')); + } + reader._closedPromise.catch(function () { + }); + reader._ownerReadableStream._reader = undefined; + reader._ownerReadableStream = undefined; + } + + function ReadableStreamBYOBReaderRead(reader, view) { + var stream = reader._ownerReadableStream; + assert(stream !== undefined); + stream._disturbed = true; + if (stream._state === 'errored') { + return Promise.reject(stream._storedError); + } + return ReadableByteStreamControllerPullInto(stream._readableStreamController, view); + } + + function ReadableStreamDefaultReaderRead(reader) { + var stream = reader._ownerReadableStream; + assert(stream !== undefined); + stream._disturbed = true; + if (stream._state === 'closed') { + return Promise.resolve(CreateIterResultObject(undefined, true)); + } + if (stream._state === 'errored') { + return Promise.reject(stream._storedError); + } + assert(stream._state === 'readable'); + return stream._readableStreamController.__pullSteps(); + } + + var ReadableStreamDefaultController = function () { + function ReadableStreamDefaultController(stream, underlyingSource, size, highWaterMark) { + _classCallCheck(this, ReadableStreamDefaultController); + if (IsReadableStream(stream) === false) { + throw new TypeError('ReadableStreamDefaultController can only be constructed with a ReadableStream instance'); + } + if (stream._readableStreamController !== undefined) { + throw new TypeError('ReadableStreamDefaultController instances can only be created by the ReadableStream constructor'); + } + this._controlledReadableStream = stream; + this._underlyingSource = underlyingSource; + this._queue = undefined; + this._queueTotalSize = undefined; + ResetQueue(this); + this._started = false; + this._closeRequested = false; + this._pullAgain = false; + this._pulling = false; + var normalizedStrategy = ValidateAndNormalizeQueuingStrategy(size, highWaterMark); + this._strategySize = normalizedStrategy.size; + this._strategyHWM = normalizedStrategy.highWaterMark; + var controller = this; + var startResult = InvokeOrNoop(underlyingSource, 'start', [this]); + Promise.resolve(startResult).then(function () { + controller._started = true; + assert(controller._pulling === false); + assert(controller._pullAgain === false); + ReadableStreamDefaultControllerCallPullIfNeeded(controller); + }, function (r) { + ReadableStreamDefaultControllerErrorIfNeeded(controller, r); + }).catch(rethrowAssertionErrorRejection); + } + + _createClass(ReadableStreamDefaultController, [{ + key: 'close', + value: function close() { + if (IsReadableStreamDefaultController(this) === false) { + throw defaultControllerBrandCheckException('close'); + } + if (this._closeRequested === true) { + throw new TypeError('The stream has already been closed; do not close it again!'); + } + var state = this._controlledReadableStream._state; + if (state !== 'readable') { + throw new TypeError('The stream (in ' + state + ' state) is not in the readable state and cannot be closed'); + } + ReadableStreamDefaultControllerClose(this); + } + }, { + key: 'enqueue', + value: function enqueue(chunk) { + if (IsReadableStreamDefaultController(this) === false) { + throw defaultControllerBrandCheckException('enqueue'); + } + if (this._closeRequested === true) { + throw new TypeError('stream is closed or draining'); + } + var state = this._controlledReadableStream._state; + if (state !== 'readable') { + throw new TypeError('The stream (in ' + state + ' state) is not in the readable state and cannot be enqueued to'); + } + return ReadableStreamDefaultControllerEnqueue(this, chunk); + } + }, { + key: 'error', + value: function error(e) { + if (IsReadableStreamDefaultController(this) === false) { + throw defaultControllerBrandCheckException('error'); + } + var stream = this._controlledReadableStream; + if (stream._state !== 'readable') { + throw new TypeError('The stream is ' + stream._state + ' and so cannot be errored'); + } + ReadableStreamDefaultControllerError(this, e); + } + }, { + key: '__cancelSteps', + value: function __cancelSteps(reason) { + ResetQueue(this); + return PromiseInvokeOrNoop(this._underlyingSource, 'cancel', [reason]); + } + }, { + key: '__pullSteps', + value: function __pullSteps() { + var stream = this._controlledReadableStream; + if (this._queue.length > 0) { + var chunk = DequeueValue(this); + if (this._closeRequested === true && this._queue.length === 0) { + ReadableStreamClose(stream); + } else { + ReadableStreamDefaultControllerCallPullIfNeeded(this); + } + return Promise.resolve(CreateIterResultObject(chunk, false)); + } + var pendingPromise = ReadableStreamAddReadRequest(stream); + ReadableStreamDefaultControllerCallPullIfNeeded(this); + return pendingPromise; + } + }, { + key: 'desiredSize', + get: function get() { + if (IsReadableStreamDefaultController(this) === false) { + throw defaultControllerBrandCheckException('desiredSize'); + } + return ReadableStreamDefaultControllerGetDesiredSize(this); + } + }]); + return ReadableStreamDefaultController; + }(); + + function IsReadableStreamDefaultController(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_underlyingSource')) { + return false; + } + return true; + } + + function ReadableStreamDefaultControllerCallPullIfNeeded(controller) { + var shouldPull = ReadableStreamDefaultControllerShouldCallPull(controller); + if (shouldPull === false) { + return undefined; + } + if (controller._pulling === true) { + controller._pullAgain = true; + return undefined; + } + assert(controller._pullAgain === false); + controller._pulling = true; + var pullPromise = PromiseInvokeOrNoop(controller._underlyingSource, 'pull', [controller]); + pullPromise.then(function () { + controller._pulling = false; + if (controller._pullAgain === true) { + controller._pullAgain = false; + return ReadableStreamDefaultControllerCallPullIfNeeded(controller); + } + return undefined; + }, function (e) { + ReadableStreamDefaultControllerErrorIfNeeded(controller, e); + }).catch(rethrowAssertionErrorRejection); + return undefined; + } + + function ReadableStreamDefaultControllerShouldCallPull(controller) { + var stream = controller._controlledReadableStream; + if (stream._state === 'closed' || stream._state === 'errored') { + return false; + } + if (controller._closeRequested === true) { + return false; + } + if (controller._started === false) { + return false; + } + if (IsReadableStreamLocked(stream) === true && ReadableStreamGetNumReadRequests(stream) > 0) { + return true; + } + var desiredSize = ReadableStreamDefaultControllerGetDesiredSize(controller); + if (desiredSize > 0) { + return true; + } + return false; + } + + function ReadableStreamDefaultControllerClose(controller) { + var stream = controller._controlledReadableStream; + assert(controller._closeRequested === false); + assert(stream._state === 'readable'); + controller._closeRequested = true; + if (controller._queue.length === 0) { + ReadableStreamClose(stream); + } + } + + function ReadableStreamDefaultControllerEnqueue(controller, chunk) { + var stream = controller._controlledReadableStream; + assert(controller._closeRequested === false); + assert(stream._state === 'readable'); + if (IsReadableStreamLocked(stream) === true && ReadableStreamGetNumReadRequests(stream) > 0) { + ReadableStreamFulfillReadRequest(stream, chunk, false); + } else { + var chunkSize = 1; + if (controller._strategySize !== undefined) { + var strategySize = controller._strategySize; + try { + chunkSize = strategySize(chunk); + } catch (chunkSizeE) { + ReadableStreamDefaultControllerErrorIfNeeded(controller, chunkSizeE); + throw chunkSizeE; + } + } + try { + EnqueueValueWithSize(controller, chunk, chunkSize); + } catch (enqueueE) { + ReadableStreamDefaultControllerErrorIfNeeded(controller, enqueueE); + throw enqueueE; + } + } + ReadableStreamDefaultControllerCallPullIfNeeded(controller); + return undefined; + } + + function ReadableStreamDefaultControllerError(controller, e) { + var stream = controller._controlledReadableStream; + assert(stream._state === 'readable'); + ResetQueue(controller); + ReadableStreamError(stream, e); + } + + function ReadableStreamDefaultControllerErrorIfNeeded(controller, e) { + if (controller._controlledReadableStream._state === 'readable') { + ReadableStreamDefaultControllerError(controller, e); + } + } + + function ReadableStreamDefaultControllerGetDesiredSize(controller) { + var stream = controller._controlledReadableStream; + var state = stream._state; + if (state === 'errored') { + return null; + } + if (state === 'closed') { + return 0; + } + return controller._strategyHWM - controller._queueTotalSize; + } + + var ReadableStreamBYOBRequest = function () { + function ReadableStreamBYOBRequest(controller, view) { + _classCallCheck(this, ReadableStreamBYOBRequest); + this._associatedReadableByteStreamController = controller; + this._view = view; + } + + _createClass(ReadableStreamBYOBRequest, [{ + key: 'respond', + value: function respond(bytesWritten) { + if (IsReadableStreamBYOBRequest(this) === false) { + throw byobRequestBrandCheckException('respond'); + } + if (this._associatedReadableByteStreamController === undefined) { + throw new TypeError('This BYOB request has been invalidated'); + } + ReadableByteStreamControllerRespond(this._associatedReadableByteStreamController, bytesWritten); + } + }, { + key: 'respondWithNewView', + value: function respondWithNewView(view) { + if (IsReadableStreamBYOBRequest(this) === false) { + throw byobRequestBrandCheckException('respond'); + } + if (this._associatedReadableByteStreamController === undefined) { + throw new TypeError('This BYOB request has been invalidated'); + } + if (!ArrayBuffer.isView(view)) { + throw new TypeError('You can only respond with array buffer views'); + } + ReadableByteStreamControllerRespondWithNewView(this._associatedReadableByteStreamController, view); + } + }, { + key: 'view', + get: function get() { + return this._view; + } + }]); + return ReadableStreamBYOBRequest; + }(); + var ReadableByteStreamController = function () { + function ReadableByteStreamController(stream, underlyingByteSource, highWaterMark) { + _classCallCheck(this, ReadableByteStreamController); + if (IsReadableStream(stream) === false) { + throw new TypeError('ReadableByteStreamController can only be constructed with a ReadableStream instance given ' + 'a byte source'); + } + if (stream._readableStreamController !== undefined) { + throw new TypeError('ReadableByteStreamController instances can only be created by the ReadableStream constructor given a byte ' + 'source'); + } + this._controlledReadableStream = stream; + this._underlyingByteSource = underlyingByteSource; + this._pullAgain = false; + this._pulling = false; + ReadableByteStreamControllerClearPendingPullIntos(this); + this._queue = this._queueTotalSize = undefined; + ResetQueue(this); + this._closeRequested = false; + this._started = false; + this._strategyHWM = ValidateAndNormalizeHighWaterMark(highWaterMark); + var autoAllocateChunkSize = underlyingByteSource.autoAllocateChunkSize; + if (autoAllocateChunkSize !== undefined) { + if (Number.isInteger(autoAllocateChunkSize) === false || autoAllocateChunkSize <= 0) { + throw new RangeError('autoAllocateChunkSize must be a positive integer'); + } + } + this._autoAllocateChunkSize = autoAllocateChunkSize; + this._pendingPullIntos = []; + var controller = this; + var startResult = InvokeOrNoop(underlyingByteSource, 'start', [this]); + Promise.resolve(startResult).then(function () { + controller._started = true; + assert(controller._pulling === false); + assert(controller._pullAgain === false); + ReadableByteStreamControllerCallPullIfNeeded(controller); + }, function (r) { + if (stream._state === 'readable') { + ReadableByteStreamControllerError(controller, r); + } + }).catch(rethrowAssertionErrorRejection); + } + + _createClass(ReadableByteStreamController, [{ + key: 'close', + value: function close() { + if (IsReadableByteStreamController(this) === false) { + throw byteStreamControllerBrandCheckException('close'); + } + if (this._closeRequested === true) { + throw new TypeError('The stream has already been closed; do not close it again!'); + } + var state = this._controlledReadableStream._state; + if (state !== 'readable') { + throw new TypeError('The stream (in ' + state + ' state) is not in the readable state and cannot be closed'); + } + ReadableByteStreamControllerClose(this); + } + }, { + key: 'enqueue', + value: function enqueue(chunk) { + if (IsReadableByteStreamController(this) === false) { + throw byteStreamControllerBrandCheckException('enqueue'); + } + if (this._closeRequested === true) { + throw new TypeError('stream is closed or draining'); + } + var state = this._controlledReadableStream._state; + if (state !== 'readable') { + throw new TypeError('The stream (in ' + state + ' state) is not in the readable state and cannot be enqueued to'); + } + if (!ArrayBuffer.isView(chunk)) { + throw new TypeError('You can only enqueue array buffer views when using a ReadableByteStreamController'); + } + ReadableByteStreamControllerEnqueue(this, chunk); + } + }, { + key: 'error', + value: function error(e) { + if (IsReadableByteStreamController(this) === false) { + throw byteStreamControllerBrandCheckException('error'); + } + var stream = this._controlledReadableStream; + if (stream._state !== 'readable') { + throw new TypeError('The stream is ' + stream._state + ' and so cannot be errored'); + } + ReadableByteStreamControllerError(this, e); + } + }, { + key: '__cancelSteps', + value: function __cancelSteps(reason) { + if (this._pendingPullIntos.length > 0) { + var firstDescriptor = this._pendingPullIntos[0]; + firstDescriptor.bytesFilled = 0; + } + ResetQueue(this); + return PromiseInvokeOrNoop(this._underlyingByteSource, 'cancel', [reason]); + } + }, { + key: '__pullSteps', + value: function __pullSteps() { + var stream = this._controlledReadableStream; + assert(ReadableStreamHasDefaultReader(stream) === true); + if (this._queueTotalSize > 0) { + assert(ReadableStreamGetNumReadRequests(stream) === 0); + var entry = this._queue.shift(); + this._queueTotalSize -= entry.byteLength; + ReadableByteStreamControllerHandleQueueDrain(this); + var view = void 0; + try { + view = new Uint8Array(entry.buffer, entry.byteOffset, entry.byteLength); + } catch (viewE) { + return Promise.reject(viewE); + } + return Promise.resolve(CreateIterResultObject(view, false)); + } + var autoAllocateChunkSize = this._autoAllocateChunkSize; + if (autoAllocateChunkSize !== undefined) { + var buffer = void 0; + try { + buffer = new ArrayBuffer(autoAllocateChunkSize); + } catch (bufferE) { + return Promise.reject(bufferE); + } + var pullIntoDescriptor = { + buffer: buffer, + byteOffset: 0, + byteLength: autoAllocateChunkSize, + bytesFilled: 0, + elementSize: 1, + ctor: Uint8Array, + readerType: 'default' + }; + this._pendingPullIntos.push(pullIntoDescriptor); + } + var promise = ReadableStreamAddReadRequest(stream); + ReadableByteStreamControllerCallPullIfNeeded(this); + return promise; + } + }, { + key: 'byobRequest', + get: function get() { + if (IsReadableByteStreamController(this) === false) { + throw byteStreamControllerBrandCheckException('byobRequest'); + } + if (this._byobRequest === undefined && this._pendingPullIntos.length > 0) { + var firstDescriptor = this._pendingPullIntos[0]; + var view = new Uint8Array(firstDescriptor.buffer, firstDescriptor.byteOffset + firstDescriptor.bytesFilled, firstDescriptor.byteLength - firstDescriptor.bytesFilled); + this._byobRequest = new ReadableStreamBYOBRequest(this, view); + } + return this._byobRequest; + } + }, { + key: 'desiredSize', + get: function get() { + if (IsReadableByteStreamController(this) === false) { + throw byteStreamControllerBrandCheckException('desiredSize'); + } + return ReadableByteStreamControllerGetDesiredSize(this); + } + }]); + return ReadableByteStreamController; + }(); + + function IsReadableByteStreamController(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_underlyingByteSource')) { + return false; + } + return true; + } + + function IsReadableStreamBYOBRequest(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_associatedReadableByteStreamController')) { + return false; + } + return true; + } + + function ReadableByteStreamControllerCallPullIfNeeded(controller) { + var shouldPull = ReadableByteStreamControllerShouldCallPull(controller); + if (shouldPull === false) { + return undefined; + } + if (controller._pulling === true) { + controller._pullAgain = true; + return undefined; + } + assert(controller._pullAgain === false); + controller._pulling = true; + var pullPromise = PromiseInvokeOrNoop(controller._underlyingByteSource, 'pull', [controller]); + pullPromise.then(function () { + controller._pulling = false; + if (controller._pullAgain === true) { + controller._pullAgain = false; + ReadableByteStreamControllerCallPullIfNeeded(controller); + } + }, function (e) { + if (controller._controlledReadableStream._state === 'readable') { + ReadableByteStreamControllerError(controller, e); + } + }).catch(rethrowAssertionErrorRejection); + return undefined; + } + + function ReadableByteStreamControllerClearPendingPullIntos(controller) { + ReadableByteStreamControllerInvalidateBYOBRequest(controller); + controller._pendingPullIntos = []; + } + + function ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor) { + assert(stream._state !== 'errored', 'state must not be errored'); + var done = false; + if (stream._state === 'closed') { + assert(pullIntoDescriptor.bytesFilled === 0); + done = true; + } + var filledView = ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor); + if (pullIntoDescriptor.readerType === 'default') { + ReadableStreamFulfillReadRequest(stream, filledView, done); + } else { + assert(pullIntoDescriptor.readerType === 'byob'); + ReadableStreamFulfillReadIntoRequest(stream, filledView, done); + } + } + + function ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor) { + var bytesFilled = pullIntoDescriptor.bytesFilled; + var elementSize = pullIntoDescriptor.elementSize; + assert(bytesFilled <= pullIntoDescriptor.byteLength); + assert(bytesFilled % elementSize === 0); + return new pullIntoDescriptor.ctor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, bytesFilled / elementSize); + } + + function ReadableByteStreamControllerEnqueueChunkToQueue(controller, buffer, byteOffset, byteLength) { + controller._queue.push({ + buffer: buffer, + byteOffset: byteOffset, + byteLength: byteLength + }); + controller._queueTotalSize += byteLength; + } + + function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) { + var elementSize = pullIntoDescriptor.elementSize; + var currentAlignedBytes = pullIntoDescriptor.bytesFilled - pullIntoDescriptor.bytesFilled % elementSize; + var maxBytesToCopy = Math.min(controller._queueTotalSize, pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled); + var maxBytesFilled = pullIntoDescriptor.bytesFilled + maxBytesToCopy; + var maxAlignedBytes = maxBytesFilled - maxBytesFilled % elementSize; + var totalBytesToCopyRemaining = maxBytesToCopy; + var ready = false; + if (maxAlignedBytes > currentAlignedBytes) { + totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled; + ready = true; + } + var queue = controller._queue; + while (totalBytesToCopyRemaining > 0) { + var headOfQueue = queue[0]; + var bytesToCopy = Math.min(totalBytesToCopyRemaining, headOfQueue.byteLength); + var destStart = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled; + ArrayBufferCopy(pullIntoDescriptor.buffer, destStart, headOfQueue.buffer, headOfQueue.byteOffset, bytesToCopy); + if (headOfQueue.byteLength === bytesToCopy) { + queue.shift(); + } else { + headOfQueue.byteOffset += bytesToCopy; + headOfQueue.byteLength -= bytesToCopy; + } + controller._queueTotalSize -= bytesToCopy; + ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesToCopy, pullIntoDescriptor); + totalBytesToCopyRemaining -= bytesToCopy; + } + if (ready === false) { + assert(controller._queueTotalSize === 0, 'queue must be empty'); + assert(pullIntoDescriptor.bytesFilled > 0); + assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize); + } + return ready; + } + + function ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, size, pullIntoDescriptor) { + assert(controller._pendingPullIntos.length === 0 || controller._pendingPullIntos[0] === pullIntoDescriptor); + ReadableByteStreamControllerInvalidateBYOBRequest(controller); + pullIntoDescriptor.bytesFilled += size; + } + + function ReadableByteStreamControllerHandleQueueDrain(controller) { + assert(controller._controlledReadableStream._state === 'readable'); + if (controller._queueTotalSize === 0 && controller._closeRequested === true) { + ReadableStreamClose(controller._controlledReadableStream); + } else { + ReadableByteStreamControllerCallPullIfNeeded(controller); + } + } + + function ReadableByteStreamControllerInvalidateBYOBRequest(controller) { + if (controller._byobRequest === undefined) { + return; + } + controller._byobRequest._associatedReadableByteStreamController = undefined; + controller._byobRequest._view = undefined; + controller._byobRequest = undefined; + } + + function ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller) { + assert(controller._closeRequested === false); + while (controller._pendingPullIntos.length > 0) { + if (controller._queueTotalSize === 0) { + return; + } + var pullIntoDescriptor = controller._pendingPullIntos[0]; + if (ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) === true) { + ReadableByteStreamControllerShiftPendingPullInto(controller); + ReadableByteStreamControllerCommitPullIntoDescriptor(controller._controlledReadableStream, pullIntoDescriptor); + } + } + } + + function ReadableByteStreamControllerPullInto(controller, view) { + var stream = controller._controlledReadableStream; + var elementSize = 1; + if (view.constructor !== DataView) { + elementSize = view.constructor.BYTES_PER_ELEMENT; + } + var ctor = view.constructor; + var pullIntoDescriptor = { + buffer: view.buffer, + byteOffset: view.byteOffset, + byteLength: view.byteLength, + bytesFilled: 0, + elementSize: elementSize, + ctor: ctor, + readerType: 'byob' + }; + if (controller._pendingPullIntos.length > 0) { + pullIntoDescriptor.buffer = TransferArrayBuffer(pullIntoDescriptor.buffer); + controller._pendingPullIntos.push(pullIntoDescriptor); + return ReadableStreamAddReadIntoRequest(stream); + } + if (stream._state === 'closed') { + var emptyView = new view.constructor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, 0); + return Promise.resolve(CreateIterResultObject(emptyView, true)); + } + if (controller._queueTotalSize > 0) { + if (ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) === true) { + var filledView = ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor); + ReadableByteStreamControllerHandleQueueDrain(controller); + return Promise.resolve(CreateIterResultObject(filledView, false)); + } + if (controller._closeRequested === true) { + var e = new TypeError('Insufficient bytes to fill elements in the given buffer'); + ReadableByteStreamControllerError(controller, e); + return Promise.reject(e); + } + } + pullIntoDescriptor.buffer = TransferArrayBuffer(pullIntoDescriptor.buffer); + controller._pendingPullIntos.push(pullIntoDescriptor); + var promise = ReadableStreamAddReadIntoRequest(stream); + ReadableByteStreamControllerCallPullIfNeeded(controller); + return promise; + } + + function ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor) { + firstDescriptor.buffer = TransferArrayBuffer(firstDescriptor.buffer); + assert(firstDescriptor.bytesFilled === 0, 'bytesFilled must be 0'); + var stream = controller._controlledReadableStream; + if (ReadableStreamHasBYOBReader(stream) === true) { + while (ReadableStreamGetNumReadIntoRequests(stream) > 0) { + var pullIntoDescriptor = ReadableByteStreamControllerShiftPendingPullInto(controller); + ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor); + } + } + } + + function ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, pullIntoDescriptor) { + if (pullIntoDescriptor.bytesFilled + bytesWritten > pullIntoDescriptor.byteLength) { + throw new RangeError('bytesWritten out of range'); + } + ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesWritten, pullIntoDescriptor); + if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize) { + return; + } + ReadableByteStreamControllerShiftPendingPullInto(controller); + var remainderSize = pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize; + if (remainderSize > 0) { + var end = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled; + var remainder = pullIntoDescriptor.buffer.slice(end - remainderSize, end); + ReadableByteStreamControllerEnqueueChunkToQueue(controller, remainder, 0, remainder.byteLength); + } + pullIntoDescriptor.buffer = TransferArrayBuffer(pullIntoDescriptor.buffer); + pullIntoDescriptor.bytesFilled -= remainderSize; + ReadableByteStreamControllerCommitPullIntoDescriptor(controller._controlledReadableStream, pullIntoDescriptor); + ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller); + } + + function ReadableByteStreamControllerRespondInternal(controller, bytesWritten) { + var firstDescriptor = controller._pendingPullIntos[0]; + var stream = controller._controlledReadableStream; + if (stream._state === 'closed') { + if (bytesWritten !== 0) { + throw new TypeError('bytesWritten must be 0 when calling respond() on a closed stream'); + } + ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor); + } else { + assert(stream._state === 'readable'); + ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, firstDescriptor); + } + } + + function ReadableByteStreamControllerShiftPendingPullInto(controller) { + var descriptor = controller._pendingPullIntos.shift(); + ReadableByteStreamControllerInvalidateBYOBRequest(controller); + return descriptor; + } + + function ReadableByteStreamControllerShouldCallPull(controller) { + var stream = controller._controlledReadableStream; + if (stream._state !== 'readable') { + return false; + } + if (controller._closeRequested === true) { + return false; + } + if (controller._started === false) { + return false; + } + if (ReadableStreamHasDefaultReader(stream) === true && ReadableStreamGetNumReadRequests(stream) > 0) { + return true; + } + if (ReadableStreamHasBYOBReader(stream) === true && ReadableStreamGetNumReadIntoRequests(stream) > 0) { + return true; + } + if (ReadableByteStreamControllerGetDesiredSize(controller) > 0) { + return true; + } + return false; + } + + function ReadableByteStreamControllerClose(controller) { + var stream = controller._controlledReadableStream; + assert(controller._closeRequested === false); + assert(stream._state === 'readable'); + if (controller._queueTotalSize > 0) { + controller._closeRequested = true; + return; + } + if (controller._pendingPullIntos.length > 0) { + var firstPendingPullInto = controller._pendingPullIntos[0]; + if (firstPendingPullInto.bytesFilled > 0) { + var e = new TypeError('Insufficient bytes to fill elements in the given buffer'); + ReadableByteStreamControllerError(controller, e); + throw e; + } + } + ReadableStreamClose(stream); + } + + function ReadableByteStreamControllerEnqueue(controller, chunk) { + var stream = controller._controlledReadableStream; + assert(controller._closeRequested === false); + assert(stream._state === 'readable'); + var buffer = chunk.buffer; + var byteOffset = chunk.byteOffset; + var byteLength = chunk.byteLength; + var transferredBuffer = TransferArrayBuffer(buffer); + if (ReadableStreamHasDefaultReader(stream) === true) { + if (ReadableStreamGetNumReadRequests(stream) === 0) { + ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength); + } else { + assert(controller._queue.length === 0); + var transferredView = new Uint8Array(transferredBuffer, byteOffset, byteLength); + ReadableStreamFulfillReadRequest(stream, transferredView, false); + } + } else if (ReadableStreamHasBYOBReader(stream) === true) { + ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength); + ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller); + } else { + assert(IsReadableStreamLocked(stream) === false, 'stream must not be locked'); + ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength); + } + } + + function ReadableByteStreamControllerError(controller, e) { + var stream = controller._controlledReadableStream; + assert(stream._state === 'readable'); + ReadableByteStreamControllerClearPendingPullIntos(controller); + ResetQueue(controller); + ReadableStreamError(stream, e); + } + + function ReadableByteStreamControllerGetDesiredSize(controller) { + var stream = controller._controlledReadableStream; + var state = stream._state; + if (state === 'errored') { + return null; + } + if (state === 'closed') { + return 0; + } + return controller._strategyHWM - controller._queueTotalSize; + } + + function ReadableByteStreamControllerRespond(controller, bytesWritten) { + bytesWritten = Number(bytesWritten); + if (IsFiniteNonNegativeNumber(bytesWritten) === false) { + throw new RangeError('bytesWritten must be a finite'); + } + assert(controller._pendingPullIntos.length > 0); + ReadableByteStreamControllerRespondInternal(controller, bytesWritten); + } + + function ReadableByteStreamControllerRespondWithNewView(controller, view) { + assert(controller._pendingPullIntos.length > 0); + var firstDescriptor = controller._pendingPullIntos[0]; + if (firstDescriptor.byteOffset + firstDescriptor.bytesFilled !== view.byteOffset) { + throw new RangeError('The region specified by view does not match byobRequest'); + } + if (firstDescriptor.byteLength !== view.byteLength) { + throw new RangeError('The buffer of view has different capacity than byobRequest'); + } + firstDescriptor.buffer = view.buffer; + ReadableByteStreamControllerRespondInternal(controller, view.byteLength); + } + + function streamBrandCheckException(name) { + return new TypeError('ReadableStream.prototype.' + name + ' can only be used on a ReadableStream'); + } + + function readerLockException(name) { + return new TypeError('Cannot ' + name + ' a stream using a released reader'); + } + + function defaultReaderBrandCheckException(name) { + return new TypeError('ReadableStreamDefaultReader.prototype.' + name + ' can only be used on a ReadableStreamDefaultReader'); + } + + function defaultReaderClosedPromiseInitialize(reader) { + reader._closedPromise = new Promise(function (resolve, reject) { + reader._closedPromise_resolve = resolve; + reader._closedPromise_reject = reject; + }); + } + + function defaultReaderClosedPromiseInitializeAsRejected(reader, reason) { + reader._closedPromise = Promise.reject(reason); + reader._closedPromise_resolve = undefined; + reader._closedPromise_reject = undefined; + } + + function defaultReaderClosedPromiseInitializeAsResolved(reader) { + reader._closedPromise = Promise.resolve(undefined); + reader._closedPromise_resolve = undefined; + reader._closedPromise_reject = undefined; + } + + function defaultReaderClosedPromiseReject(reader, reason) { + assert(reader._closedPromise_resolve !== undefined); + assert(reader._closedPromise_reject !== undefined); + reader._closedPromise_reject(reason); + reader._closedPromise_resolve = undefined; + reader._closedPromise_reject = undefined; + } + + function defaultReaderClosedPromiseResetToRejected(reader, reason) { + assert(reader._closedPromise_resolve === undefined); + assert(reader._closedPromise_reject === undefined); + reader._closedPromise = Promise.reject(reason); + } + + function defaultReaderClosedPromiseResolve(reader) { + assert(reader._closedPromise_resolve !== undefined); + assert(reader._closedPromise_reject !== undefined); + reader._closedPromise_resolve(undefined); + reader._closedPromise_resolve = undefined; + reader._closedPromise_reject = undefined; + } + + function byobReaderBrandCheckException(name) { + return new TypeError('ReadableStreamBYOBReader.prototype.' + name + ' can only be used on a ReadableStreamBYOBReader'); + } + + function defaultControllerBrandCheckException(name) { + return new TypeError('ReadableStreamDefaultController.prototype.' + name + ' can only be used on a ReadableStreamDefaultController'); + } + + function byobRequestBrandCheckException(name) { + return new TypeError('ReadableStreamBYOBRequest.prototype.' + name + ' can only be used on a ReadableStreamBYOBRequest'); + } + + function byteStreamControllerBrandCheckException(name) { + return new TypeError('ReadableByteStreamController.prototype.' + name + ' can only be used on a ReadableByteStreamController'); + } + + function ifIsObjectAndHasAPromiseIsHandledInternalSlotSetPromiseIsHandledToTrue(promise) { + try { + Promise.prototype.then.call(promise, undefined, function () { + }); + } catch (e) { + } + } + }, function (module, exports, __w_pdfjs_require__) { + "use strict"; + + var transformStream = __w_pdfjs_require__(6); + var readableStream = __w_pdfjs_require__(4); + var writableStream = __w_pdfjs_require__(2); + exports.TransformStream = transformStream.TransformStream; + exports.ReadableStream = readableStream.ReadableStream; + exports.IsReadableStreamDisturbed = readableStream.IsReadableStreamDisturbed; + exports.ReadableStreamDefaultControllerClose = readableStream.ReadableStreamDefaultControllerClose; + exports.ReadableStreamDefaultControllerEnqueue = readableStream.ReadableStreamDefaultControllerEnqueue; + exports.ReadableStreamDefaultControllerError = readableStream.ReadableStreamDefaultControllerError; + exports.ReadableStreamDefaultControllerGetDesiredSize = readableStream.ReadableStreamDefaultControllerGetDesiredSize; + exports.AcquireWritableStreamDefaultWriter = writableStream.AcquireWritableStreamDefaultWriter; + exports.IsWritableStream = writableStream.IsWritableStream; + exports.IsWritableStreamLocked = writableStream.IsWritableStreamLocked; + exports.WritableStream = writableStream.WritableStream; + exports.WritableStreamAbort = writableStream.WritableStreamAbort; + exports.WritableStreamDefaultControllerError = writableStream.WritableStreamDefaultControllerError; + exports.WritableStreamDefaultWriterCloseWithErrorPropagation = writableStream.WritableStreamDefaultWriterCloseWithErrorPropagation; + exports.WritableStreamDefaultWriterRelease = writableStream.WritableStreamDefaultWriterRelease; + exports.WritableStreamDefaultWriterWrite = writableStream.WritableStreamDefaultWriterWrite; + }, function (module, exports, __w_pdfjs_require__) { + "use strict"; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var _require = __w_pdfjs_require__(1), + assert = _require.assert; + var _require2 = __w_pdfjs_require__(0), + InvokeOrNoop = _require2.InvokeOrNoop, + PromiseInvokeOrPerformFallback = _require2.PromiseInvokeOrPerformFallback, + PromiseInvokeOrNoop = _require2.PromiseInvokeOrNoop, + typeIsObject = _require2.typeIsObject; + var _require3 = __w_pdfjs_require__(4), + ReadableStream = _require3.ReadableStream, + ReadableStreamDefaultControllerClose = _require3.ReadableStreamDefaultControllerClose, + ReadableStreamDefaultControllerEnqueue = _require3.ReadableStreamDefaultControllerEnqueue, + ReadableStreamDefaultControllerError = _require3.ReadableStreamDefaultControllerError, + ReadableStreamDefaultControllerGetDesiredSize = _require3.ReadableStreamDefaultControllerGetDesiredSize; + var _require4 = __w_pdfjs_require__(2), + WritableStream = _require4.WritableStream, + WritableStreamDefaultControllerError = _require4.WritableStreamDefaultControllerError; + + function TransformStreamCloseReadable(transformStream) { + if (transformStream._errored === true) { + throw new TypeError('TransformStream is already errored'); + } + if (transformStream._readableClosed === true) { + throw new TypeError('Readable side is already closed'); + } + TransformStreamCloseReadableInternal(transformStream); + } + + function TransformStreamEnqueueToReadable(transformStream, chunk) { + if (transformStream._errored === true) { + throw new TypeError('TransformStream is already errored'); + } + if (transformStream._readableClosed === true) { + throw new TypeError('Readable side is already closed'); + } + var controller = transformStream._readableController; + try { + ReadableStreamDefaultControllerEnqueue(controller, chunk); + } catch (e) { + transformStream._readableClosed = true; + TransformStreamErrorIfNeeded(transformStream, e); + throw transformStream._storedError; + } + var desiredSize = ReadableStreamDefaultControllerGetDesiredSize(controller); + var maybeBackpressure = desiredSize <= 0; + if (maybeBackpressure === true && transformStream._backpressure === false) { + TransformStreamSetBackpressure(transformStream, true); + } + } + + function TransformStreamError(transformStream, e) { + if (transformStream._errored === true) { + throw new TypeError('TransformStream is already errored'); + } + TransformStreamErrorInternal(transformStream, e); + } + + function TransformStreamCloseReadableInternal(transformStream) { + assert(transformStream._errored === false); + assert(transformStream._readableClosed === false); + try { + ReadableStreamDefaultControllerClose(transformStream._readableController); + } catch (e) { + assert(false); + } + transformStream._readableClosed = true; + } + + function TransformStreamErrorIfNeeded(transformStream, e) { + if (transformStream._errored === false) { + TransformStreamErrorInternal(transformStream, e); + } + } + + function TransformStreamErrorInternal(transformStream, e) { + assert(transformStream._errored === false); + transformStream._errored = true; + transformStream._storedError = e; + if (transformStream._writableDone === false) { + WritableStreamDefaultControllerError(transformStream._writableController, e); + } + if (transformStream._readableClosed === false) { + ReadableStreamDefaultControllerError(transformStream._readableController, e); + } + } + + function TransformStreamReadableReadyPromise(transformStream) { + assert(transformStream._backpressureChangePromise !== undefined, '_backpressureChangePromise should have been initialized'); + if (transformStream._backpressure === false) { + return Promise.resolve(); + } + assert(transformStream._backpressure === true, '_backpressure should have been initialized'); + return transformStream._backpressureChangePromise; + } + + function TransformStreamSetBackpressure(transformStream, backpressure) { + assert(transformStream._backpressure !== backpressure, 'TransformStreamSetBackpressure() should be called only when backpressure is changed'); + if (transformStream._backpressureChangePromise !== undefined) { + transformStream._backpressureChangePromise_resolve(backpressure); + } + transformStream._backpressureChangePromise = new Promise(function (resolve) { + transformStream._backpressureChangePromise_resolve = resolve; + }); + transformStream._backpressureChangePromise.then(function (resolution) { + assert(resolution !== backpressure, '_backpressureChangePromise should be fulfilled only when backpressure is changed'); + }); + transformStream._backpressure = backpressure; + } + + function TransformStreamDefaultTransform(chunk, transformStreamController) { + var transformStream = transformStreamController._controlledTransformStream; + TransformStreamEnqueueToReadable(transformStream, chunk); + return Promise.resolve(); + } + + function TransformStreamTransform(transformStream, chunk) { + assert(transformStream._errored === false); + assert(transformStream._transforming === false); + assert(transformStream._backpressure === false); + transformStream._transforming = true; + var transformer = transformStream._transformer; + var controller = transformStream._transformStreamController; + var transformPromise = PromiseInvokeOrPerformFallback(transformer, 'transform', [chunk, controller], TransformStreamDefaultTransform, [chunk, controller]); + return transformPromise.then(function () { + transformStream._transforming = false; + return TransformStreamReadableReadyPromise(transformStream); + }, function (e) { + TransformStreamErrorIfNeeded(transformStream, e); + return Promise.reject(e); + }); + } + + function IsTransformStreamDefaultController(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_controlledTransformStream')) { + return false; + } + return true; + } + + function IsTransformStream(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_transformStreamController')) { + return false; + } + return true; + } + + var TransformStreamSink = function () { + function TransformStreamSink(transformStream, startPromise) { + _classCallCheck(this, TransformStreamSink); + this._transformStream = transformStream; + this._startPromise = startPromise; + } + + _createClass(TransformStreamSink, [{ + key: 'start', + value: function start(c) { + var transformStream = this._transformStream; + transformStream._writableController = c; + return this._startPromise.then(function () { + return TransformStreamReadableReadyPromise(transformStream); + }); + } + }, { + key: 'write', + value: function write(chunk) { + var transformStream = this._transformStream; + return TransformStreamTransform(transformStream, chunk); + } + }, { + key: 'abort', + value: function abort() { + var transformStream = this._transformStream; + transformStream._writableDone = true; + TransformStreamErrorInternal(transformStream, new TypeError('Writable side aborted')); + } + }, { + key: 'close', + value: function close() { + var transformStream = this._transformStream; + assert(transformStream._transforming === false); + transformStream._writableDone = true; + var flushPromise = PromiseInvokeOrNoop(transformStream._transformer, 'flush', [transformStream._transformStreamController]); + return flushPromise.then(function () { + if (transformStream._errored === true) { + return Promise.reject(transformStream._storedError); + } + if (transformStream._readableClosed === false) { + TransformStreamCloseReadableInternal(transformStream); + } + return Promise.resolve(); + }).catch(function (r) { + TransformStreamErrorIfNeeded(transformStream, r); + return Promise.reject(transformStream._storedError); + }); + } + }]); + return TransformStreamSink; + }(); + var TransformStreamSource = function () { + function TransformStreamSource(transformStream, startPromise) { + _classCallCheck(this, TransformStreamSource); + this._transformStream = transformStream; + this._startPromise = startPromise; + } + + _createClass(TransformStreamSource, [{ + key: 'start', + value: function start(c) { + var transformStream = this._transformStream; + transformStream._readableController = c; + return this._startPromise.then(function () { + assert(transformStream._backpressureChangePromise !== undefined, '_backpressureChangePromise should have been initialized'); + if (transformStream._backpressure === true) { + return Promise.resolve(); + } + assert(transformStream._backpressure === false, '_backpressure should have been initialized'); + return transformStream._backpressureChangePromise; + }); + } + }, { + key: 'pull', + value: function pull() { + var transformStream = this._transformStream; + assert(transformStream._backpressure === true, 'pull() should be never called while _backpressure is false'); + assert(transformStream._backpressureChangePromise !== undefined, '_backpressureChangePromise should have been initialized'); + TransformStreamSetBackpressure(transformStream, false); + return transformStream._backpressureChangePromise; + } + }, { + key: 'cancel', + value: function cancel() { + var transformStream = this._transformStream; + transformStream._readableClosed = true; + TransformStreamErrorInternal(transformStream, new TypeError('Readable side canceled')); + } + }]); + return TransformStreamSource; + }(); + var TransformStreamDefaultController = function () { + function TransformStreamDefaultController(transformStream) { + _classCallCheck(this, TransformStreamDefaultController); + if (IsTransformStream(transformStream) === false) { + throw new TypeError('TransformStreamDefaultController can only be ' + 'constructed with a TransformStream instance'); + } + if (transformStream._transformStreamController !== undefined) { + throw new TypeError('TransformStreamDefaultController instances can ' + 'only be created by the TransformStream constructor'); + } + this._controlledTransformStream = transformStream; + } + + _createClass(TransformStreamDefaultController, [{ + key: 'enqueue', + value: function enqueue(chunk) { + if (IsTransformStreamDefaultController(this) === false) { + throw defaultControllerBrandCheckException('enqueue'); + } + TransformStreamEnqueueToReadable(this._controlledTransformStream, chunk); + } + }, { + key: 'close', + value: function close() { + if (IsTransformStreamDefaultController(this) === false) { + throw defaultControllerBrandCheckException('close'); + } + TransformStreamCloseReadable(this._controlledTransformStream); + } + }, { + key: 'error', + value: function error(reason) { + if (IsTransformStreamDefaultController(this) === false) { + throw defaultControllerBrandCheckException('error'); + } + TransformStreamError(this._controlledTransformStream, reason); + } + }, { + key: 'desiredSize', + get: function get() { + if (IsTransformStreamDefaultController(this) === false) { + throw defaultControllerBrandCheckException('desiredSize'); + } + var transformStream = this._controlledTransformStream; + var readableController = transformStream._readableController; + return ReadableStreamDefaultControllerGetDesiredSize(readableController); + } + }]); + return TransformStreamDefaultController; + }(); + var TransformStream = function () { + function TransformStream() { + var transformer = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + _classCallCheck(this, TransformStream); + this._transformer = transformer; + var readableStrategy = transformer.readableStrategy, + writableStrategy = transformer.writableStrategy; + this._transforming = false; + this._errored = false; + this._storedError = undefined; + this._writableController = undefined; + this._readableController = undefined; + this._transformStreamController = undefined; + this._writableDone = false; + this._readableClosed = false; + this._backpressure = undefined; + this._backpressureChangePromise = undefined; + this._backpressureChangePromise_resolve = undefined; + this._transformStreamController = new TransformStreamDefaultController(this); + var startPromise_resolve = void 0; + var startPromise = new Promise(function (resolve) { + startPromise_resolve = resolve; + }); + var source = new TransformStreamSource(this, startPromise); + this._readable = new ReadableStream(source, readableStrategy); + var sink = new TransformStreamSink(this, startPromise); + this._writable = new WritableStream(sink, writableStrategy); + assert(this._writableController !== undefined); + assert(this._readableController !== undefined); + var desiredSize = ReadableStreamDefaultControllerGetDesiredSize(this._readableController); + TransformStreamSetBackpressure(this, desiredSize <= 0); + var transformStream = this; + var startResult = InvokeOrNoop(transformer, 'start', [transformStream._transformStreamController]); + startPromise_resolve(startResult); + startPromise.catch(function (e) { + if (transformStream._errored === false) { + transformStream._errored = true; + transformStream._storedError = e; + } + }); + } + + _createClass(TransformStream, [{ + key: 'readable', + get: function get() { + if (IsTransformStream(this) === false) { + throw streamBrandCheckException('readable'); + } + return this._readable; + } + }, { + key: 'writable', + get: function get() { + if (IsTransformStream(this) === false) { + throw streamBrandCheckException('writable'); + } + return this._writable; + } + }]); + return TransformStream; + }(); + module.exports = {TransformStream: TransformStream}; + + function defaultControllerBrandCheckException(name) { + return new TypeError('TransformStreamDefaultController.prototype.' + name + ' can only be used on a TransformStreamDefaultController'); + } + + function streamBrandCheckException(name) { + return new TypeError('TransformStream.prototype.' + name + ' can only be used on a TransformStream'); + } + }, function (module, exports, __w_pdfjs_require__) { + module.exports = __w_pdfjs_require__(5); + }])); + + /***/ + }), + /* 11 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.CanvasGraphics = undefined; + + var _util = __w_pdfjs_require__(0); + + var _pattern_helper = __w_pdfjs_require__(13); + + var _webgl = __w_pdfjs_require__(7); + + 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 IsLittleEndianCached = { + get value() { + return (0, _util.shadow)(IsLittleEndianCached, 'value', (0, _util.isLittleEndian)()); + } + }; + + 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]; + } + }); + ctx.save = function ctxSave() { + var old = this._transformMatrix; + this._transformStack.push(old); + 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); + }; + } + } + + var CachedCanvases = function CachedCanvasesClosure() { + function CachedCanvases(canvasFactory) { + this.canvasFactory = canvasFactory; + this.cache = Object.create(null); + } + + CachedCanvases.prototype = { + getCanvas: function CachedCanvases_getCanvas(id, width, height, trackTransform) { + var 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: function clear() { + for (var id in this.cache) { + var canvasEntry = this.cache[id]; + this.canvasFactory.destroy(canvasEntry); + delete this.cache[id]; + } + } + }; + return CachedCanvases; + }(); + + 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; + for (i = 0, ii = data0.length; i < ii; i++) { + var mask = 128, + elem = data0[i]; + while (mask > 0) { + data[pos++] = elem & mask ? 0 : 255; + mask >>= 1; + } + } + var count = 0; + pos = 0; + if (data[pos] !== 0) { + points[0] = 1; + ++count; + } + for (j = 1; j < width; j++) { + if (data[pos] !== data[pos + 1]) { + points[j] = data[pos] ? 2 : 1; + ++count; + } + pos++; + } + if (data[pos] !== 0) { + points[j] = 2; + ++count; + } + for (i = 1; i < height; i++) { + pos = i * lineSize; + j0 = i * width1; + if (data[pos - lineSize] !== data[pos]) { + points[j0] = data[pos] ? 1 : 8; + ++count; + } + var 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); + if (POINT_TYPES[sum]) { + points[j0 + j] = POINT_TYPES[sum]; + ++count; + } + pos++; + } + if (data[pos - lineSize] !== data[pos]) { + points[j0 + j] = data[pos] ? 2 : 4; + ++count; + } + if (count > POINT_TO_PROCESS_LIMIT) { + return null; + } + } + pos = lineSize * (height - 1); + j0 = i * width1; + if (data[pos] !== 0) { + points[j0] = 8; + ++count; + } + for (j = 1; j < width; j++) { + if (data[pos] !== data[pos + 1]) { + points[j0 + j] = data[pos] ? 4 : 8; + ++count; + } + pos++; + } + if (data[pos] !== 0) { + points[j0 + j] = 4; + ++count; + } + if (count > POINT_TO_PROCESS_LIMIT) { + return null; + } + var steps = new Int32Array([0, width1, -1, 0, -width1, 0, 0, 0, 1]); + var outlines = []; + for (i = 0; count && i <= height; i++) { + var p = i * width1; + var end = p + width; + while (p < end && !points[p]) { + p++; + } + if (p === end) { + continue; + } + var coords = [p % width1, i]; + var type = points[p], + p0 = p, + pp; + do { + var step = steps[type]; + do { + p += step; + } while (!points[p]); + pp = points[p]; + if (pp !== 5 && pp !== 10) { + type = pp; + points[p] = 0; + } else { + type = pp & 0x33 * type >> 4; + points[p] &= type >> 2 | type << 2; + } + coords.push(p % width1); + coords.push(p / width1 | 0); + --count; + } while (p0 !== p); + outlines.push(coords); + --i; + } + var drawOutline = function drawOutline(c) { + c.save(); + c.scale(1 / width, -1 / height); + c.translate(0, -height); + c.beginPath(); + for (var i = 0, ii = outlines.length; i < ii; i++) { + var o = outlines[i]; + c.moveTo(o[0], o[1]); + for (var j = 2, jj = o.length; j < jj; j += 2) { + c.lineTo(o[j], o[j + 1]); + } + } + c.fill(); + c.beginPath(); + c.restore(); + }; + return drawOutline; + } + + var CanvasExtraState = function CanvasExtraStateClosure() { + function CanvasExtraState() { + this.alphaIsShape = false; + this.fontSize = 0; + this.fontSizeScale = 1; + this.textMatrix = _util.IDENTITY_MATRIX; + this.textMatrixScale = 1; + this.fontMatrix = _util.FONT_IDENTITY_MATRIX; + this.leading = 0; + this.x = 0; + this.y = 0; + this.lineX = 0; + this.lineY = 0; + this.charSpacing = 0; + this.wordSpacing = 0; + this.textHScale = 1; + this.textRenderingMode = _util.TextRenderingMode.FILL; + this.textRise = 0; + this.fillColor = '#000000'; + this.strokeColor = '#000000'; + this.patternFill = false; + this.fillAlpha = 1; + this.strokeAlpha = 1; + this.lineWidth = 1; + this.activeSMask = null; + this.resumeSMaskCtx = null; + } + + CanvasExtraState.prototype = { + clone: function CanvasExtraState_clone() { + return Object.create(this); + }, + setCurrentPoint: function CanvasExtraState_setCurrentPoint(x, y) { + this.x = x; + this.y = y; + } + }; + return CanvasExtraState; + }(); + var CanvasGraphics = function CanvasGraphicsClosure() { + var EXECUTION_TIME = 15; + var EXECUTION_STEPS = 10; + + function CanvasGraphics(canvasCtx, commonObjs, objs, canvasFactory, imageLayer) { + this.ctx = canvasCtx; + this.current = new CanvasExtraState(); + this.stateStack = []; + this.pendingClip = null; + this.pendingEOFill = false; + this.res = null; + this.xobjs = null; + this.commonObjs = commonObjs; + this.objs = objs; + this.canvasFactory = canvasFactory; + this.imageLayer = imageLayer; + this.groupStack = []; + this.processingType3 = null; + this.baseTransform = null; + this.baseTransformStack = []; + this.groupLevel = 0; + this.smaskStack = []; + this.smaskCounter = 0; + this.tempSMask = null; + this.cachedCanvases = new CachedCanvases(this.canvasFactory); + if (canvasCtx) { + addContextCurrentTransform(canvasCtx); + } + this.cachedGetSinglePixelWidth = null; + } + + function putBinaryImageData(ctx, imgData) { + if (typeof ImageData !== 'undefined' && imgData instanceof ImageData) { + ctx.putImageData(imgData, 0, 0); + return; + } + 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; + 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 = IsLittleEndianCached.value ? 0xFF000000 : 0x000000FF; + 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; + var 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) { + j = 0; + elemsInThisChunk = width * FULL_CHUNK_HEIGHT * 4; + for (i = 0; i < fullChunks; i++) { + dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk)); + srcPos += elemsInThisChunk; + ctx.putImageData(chunkImgData, 0, j); + j += FULL_CHUNK_HEIGHT; + } + if (i < totalChunks) { + elemsInThisChunk = width * partialChunkHeight * 4; + dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk)); + ctx.putImageData(chunkImgData, 0, j); + } + } else if (imgData.kind === _util.ImageKind.RGB_24BPP) { + 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; + } + 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) { + 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 && _webgl.WebGLUtils.isEnabled) { + var composed = _webgl.WebGLUtils.composeSMask(layerCtx.canvas, mask, { + subtype: smask.subtype, + backdrop: 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: function beginDrawing(_ref) { + var transform = _ref.transform, + viewport = _ref.viewport, + transparency = _ref.transparency, + _ref$background = _ref.background, + background = _ref$background === undefined ? null : _ref$background; + + var width = this.ctx.canvas.width; + var height = this.ctx.canvas.height; + this.ctx.save(); + this.ctx.fillStyle = background || 'rgb(255, 255, 255)'; + this.ctx.fillRect(0, 0, width, height); + this.ctx.restore(); + 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); + if (transform) { + this.ctx.transform.apply(this.ctx, transform); + } + this.ctx.transform.apply(this.ctx, viewport.transform); + this.baseTransform = this.ctx.mozCurrentTransform.slice(); + if (this.imageLayer) { + this.imageLayer.beginLayout(); + } + }, + + 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; + } + 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; + while (true) { + if (stepper !== undefined && i === stepper.nextBreakPoint) { + stepper.breakIt(i, continueCallback); + return i; + } + fnId = fnArray[i]; + if (fnId !== _util.OPS.dependency) { + this[fnId].apply(this, argsArray[i]); + } else { + var deps = argsArray[i]; + for (var n = 0, nn = deps.length; n < nn; n++) { + var depObjId = deps[n]; + var common = depObjId[0] === 'g' && depObjId[1] === '_'; + var objsPool = common ? commonObjs : objs; + if (!objsPool.isResolved(depObjId)) { + objsPool.get(depObjId, continueCallback); + return i; + } + } + } + i++; + if (i === argsArrayLen) { + return i; + } + if (chunkOperations && ++steps > EXECUTION_STEPS) { + if (Date.now() > endTime) { + continueCallback(); + return i; + } + steps = 0; + } + } + }, + endDrawing: function CanvasGraphics_endDrawing() { + if (this.current.activeSMask !== null) { + this.endSMaskGroup(); + } + 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; + } + this.cachedCanvases.clear(); + _webgl.WebGLUtils.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: function CanvasGraphics_setRenderingIntent(intent) { + }, + setFlatness: function CanvasGraphics_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; + } + } + }, + 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.ctx.restore(); + this.ctx.save(); + copyCtxState(groupCtx, this.ctx); + this.current.resumeSMaskCtx = groupCtx; + var deltaTransform = _util.Util.transform(this.current.activeSMask.startTransformInverse, groupCtx.mozCurrentTransform); + 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.ctx.restore(); + copyCtxState(groupCtx, this.ctx); + var deltaTransform = _util.Util.transform(this.current.activeSMask.startTransformInverse, groupCtx.mozCurrentTransform); + 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(); + } + if (this.current.activeSMask !== null && (this.stateStack.length === 0 || this.stateStack[this.stateStack.length - 1].activeSMask !== this.current.activeSMask)) { + this.endSMaskGroup(); + } + if (this.stateStack.length !== 0) { + this.current = this.stateStack.pop(); + 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.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++]; + if (width === 0) { + width = this.getSinglePixelWidth(); + } + if (height === 0) { + height = this.getSinglePixelWidth(); + } + var xw = x + width; + var yh = y + height; + this.ctx.moveTo(x, y); + this.ctx.lineTo(xw, y); + this.ctx.lineTo(xw, yh); + this.ctx.lineTo(x, yh); + this.ctx.lineTo(x, y); + this.ctx.closePath(); + break; + case _util.OPS.moveTo: + x = args[j++]; + y = args[j++]; + ctx.moveTo(x, y); + break; + case _util.OPS.lineTo: + x = args[j++]; + y = args[j++]; + ctx.lineTo(x, y); + 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.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; + 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; + 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.lineWidth = Math.max(this.getSinglePixelWidth() * MIN_WIDTH_FACTOR, this.current.lineWidth); + ctx.globalAlpha = this.current.strokeAlpha; + if (strokeColor && strokeColor.hasOwnProperty('type') && strokeColor.type === 'Pattern') { + ctx.save(); + ctx.strokeStyle = strokeColor.getPattern(ctx, this); + ctx.stroke(); + ctx.restore(); + } else { + ctx.stroke(); + } + 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) { + ctx.save(); + if (this.baseTransform) { + ctx.setTransform.apply(ctx, this.baseTransform); + } + ctx.fillStyle = fillColor.getPattern(ctx, this); + needRestore = true; + } + if (this.pendingEOFill) { + ctx.fill('evenodd'); + this.pendingEOFill = false; + } else { + ctx.fill(); + } + if (needRestore) { + ctx.restore(); + } + 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 (paths === undefined) { + ctx.beginPath(); + return; + } + ctx.save(); + ctx.beginPath(); + 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); + } + 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); + } + 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 (size < 0) { + size = -size; + current.fontDirection = -1; + } else { + current.fontDirection = 1; + } + this.current.font = fontObj; + this.current.fontSize = size; + if (fontObj.isType3Font) { + return; + } + var name = fontObj.loadedName || 'sans-serif'; + var bold = fontObj.black ? '900' : fontObj.bold ? 'bold' : 'normal'; + var italic = fontObj.italic ? 'italic' : 'normal'; + var typeface = '"' + name + '", ' + fontObj.fallbackName; + var browserFontSize = size < MIN_FONT_SIZE ? MIN_FONT_SIZE : size > MAX_FONT_SIZE ? MAX_FONT_SIZE : size; + this.current.fontSizeScale = size / browserFontSize; + var rule = italic + ' ' + bold + ' ' + browserFontSize + 'px ' + typeface; + this.ctx.font = rule; + }, + 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); + }, + paintChar: function CanvasGraphics_paintChar(character, x, y) { + 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); + var addToPath; + if (font.disableFontFace || isAddToPathSet) { + addToPath = font.getPathGenerator(this.commonObjs, character); + } + if (font.disableFontFace) { + ctx.save(); + ctx.translate(x, y); + ctx.beginPath(); + addToPath(ctx, fontSize); + 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: x, + y: y, + fontSize: fontSize, + addToPath: addToPath + }); + } + }, + get isFontSubpixelAAEnabled() { + var ctx = this.canvasFactory.create(10, 10).context; + 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; + } + 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; + ctx.save(); + ctx.transform.apply(ctx, current.textMatrix); + ctx.translate(current.x, current.y + current.textRise); + if (current.patternFill) { + ctx.fillStyle = current.fillColor.getPattern(ctx, this); + } + 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 (glyph.isInFont || font.missingFile) { + if (simpleFillText && !accent) { + ctx.fillText(character, scaledX, scaledY); + } else { + this.paintChar(character, scaledX, scaledY); + if (accent) { + scaledAccentX = scaledX + accent.offset.x / fontSizeScale; + scaledAccentY = scaledY - accent.offset.y / fontSizeScale; + this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY); + } + } + } + var charWidth = width * widthAdvanceScale + spacing * fontDirection; + x += charWidth; + if (restoreNeeded) { + ctx.restore(); + } + } + if (vertical) { + current.y -= x * textHScale; + } else { + current.x += x * textHScale; + } + 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 (isTextInvisible || fontSize === 0) { + return; + } + this.cachedGetSinglePixelWidth = null; + ctx.save(); + ctx.transform.apply(ctx, current.textMatrix); + ctx.translate(current.x, current.y); + ctx.scale(textHScale, fontDirection); + 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; + } + 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; + } + 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); + this.clip(); + this.endPath(); + }, + getColorN_Pattern: function CanvasGraphics_getColorN_Pattern(IR) { + var _this = this; + + var pattern; + if (IR[0] === 'TilingPattern') { + var color = IR[1]; + var baseTransform = this.baseTransform || this.ctx.mozCurrentTransform.slice(); + var canvasGraphicsFactory = { + createCanvasGraphics: function 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 = (0, _pattern_helper.getShadingPatternFromIR)(IR); + } + 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.ctx.strokeStyle = color; + this.current.strokeColor = color; + }, + setFillRGBColor: function CanvasGraphics_setFillRGBColor(r, g, b) { + var color = _util.Util.makeCssRgb(r, g, b); + this.ctx.fillStyle = color; + this.current.fillColor = color; + this.current.patternFill = false; + }, + shadingFill: function CanvasGraphics_shadingFill(patternIR) { + 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() { + throw new Error('Should not call beginInlineImage'); + }, + beginImageData: function CanvasGraphics_beginImageData() { + throw new Error('Should not call beginImageData'); + }, + paintFormXObjectBegin: function CanvasGraphics_paintFormXObjectBegin(matrix, bbox) { + this.save(); + this.baseTransformStack.push(this.baseTransform); + if ((0, _util.isArray)(matrix) && matrix.length === 6) { + this.transform.apply(this, matrix); + } + this.baseTransform = this.ctx.mozCurrentTransform; + if ((0, _util.isArray)(bbox) && bbox.length === 4) { + 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() { + this.restore(); + this.baseTransform = this.baseTransformStack.pop(); + }, + beginGroup: function CanvasGraphics_beginGroup(group) { + 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: offsetX, + offsetY: offsetY, + scaleX: scaleX, + scaleY: 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++; + this.current.activeSMask = null; + }, + endGroup: function CanvasGraphics_endGroup(group) { + this.groupLevel--; + var groupCtx = this.ctx; + this.ctx = this.groupStack.pop(); + if (this.ctx.imageSmoothingEnabled !== undefined) { + this.ctx.imageSmoothingEnabled = false; + } else { + this.ctx.mozImageSmoothingEnabled = false; + } + if (group.smask) { + this.tempSMask = this.smaskStack.pop(); + } else { + this.ctx.drawImage(groupCtx.canvas, 0, 0); + } + this.restore(); + }, + beginAnnotations: function CanvasGraphics_beginAnnotations() { + this.save(); + if (this.baseTransform) { + this.ctx.setTransform.apply(this.ctx, this.baseTransform); + } + }, + endAnnotations: function CanvasGraphics_endAnnotations() { + this.restore(); + }, + beginAnnotation: function CanvasGraphics_beginAnnotation(rect, transform, matrix) { + this.save(); + resetCtxToDefault(this.ctx); + this.current = new CanvasExtraState(); + if ((0, _util.isArray)(rect) && rect.length === 4) { + var width = rect[2] - rect[0]; + var height = rect[3] - rect[1]; + this.ctx.rect(rect[0], rect[1], width, height); + this.clip(); + this.endPath(); + } + this.transform.apply(this, transform); + this.transform.apply(this, matrix); + }, + endAnnotation: function CanvasGraphics_endAnnotation() { + this.restore(); + }, + paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) { + var domImage = this.objs.get(objId); + if (!domImage) { + (0, _util.warn)('Dependent image isn\'t ready yet'); + return; + } + this.save(); + var ctx = this.ctx; + ctx.scale(1 / w, -1 / h); + ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height, 0, -h, w, h); + if (this.imageLayer) { + var currentTransform = ctx.mozCurrentTransformInverse; + var position = this.getCanvasPosition(0, 0); + this.imageLayer.appendImage({ + objId: objId, + left: position[0], + top: position[1], + width: w / currentTransform[0], + height: h / currentTransform[3] + }); + } + this.restore(); + }, + paintImageMaskXObject: function CanvasGraphics_paintImageMaskXObject(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: width, + height: height + }); + } else { + glyph.compiled = null; + } + } + if (glyph && glyph.compiled) { + glyph.compiled(ctx); + return; + } + var maskCanvas = this.cachedCanvases.getCanvas('maskCanvas', width, height); + var maskCtx = maskCanvas.context; + maskCtx.save(); + putBinaryImageMask(maskCtx, img); + maskCtx.globalCompositeOperation = 'source-in'; + maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this) : fillColor; + maskCtx.fillRect(0, 0, width, height); + maskCtx.restore(); + this.paintInlineImageXObject(maskCanvas.canvas); + }, + paintImageMaskXObjectRepeat: function CanvasGraphics_paintImageMaskXObjectRepeat(imgData, scaleX, scaleY, positions) { + 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; + for (var i = 0, ii = positions.length; i < ii; i += 2) { + ctx.save(); + ctx.transform(scaleX, 0, 0, scaleY, positions[i], positions[i + 1]); + ctx.scale(1, -1); + ctx.drawImage(maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1); + ctx.restore(); + } + }, + paintImageMaskXObjectGroup: function CanvasGraphics_paintImageMaskXObjectGroup(images) { + var ctx = this.ctx; + var fillColor = this.current.fillColor; + var isPatternFill = this.current.patternFill; + 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) { + var imgData = this.objs.get(objId); + if (!imgData) { + (0, _util.warn)('Dependent image isn\'t ready yet'); + return; + } + this.paintInlineImageXObject(imgData); + }, + paintImageXObjectRepeat: function CanvasGraphics_paintImageXObjectRepeat(objId, scaleX, scaleY, positions) { + var imgData = this.objs.get(objId); + if (!imgData) { + (0, _util.warn)('Dependent image isn\'t ready yet'); + return; + } + var width = imgData.width; + var height = imgData.height; + var map = []; + 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 + }); + } + this.paintInlineImageXObjectGroup(imgData, map); + }, + paintInlineImageXObject: function CanvasGraphics_paintInlineImageXObject(imgData) { + 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; + if (imgData instanceof HTMLElement || !imgData.data) { + imgToPaint = imgData; + } else { + tmpCanvas = this.cachedCanvases.getCanvas('inlineImage', width, height); + var tmpCtx = tmpCanvas.context; + putBinaryImageData(tmpCtx, imgData); + imgToPaint = tmpCanvas.canvas; + } + var paintWidth = width, + paintHeight = height; + var tmpCanvasId = 'prescale1'; + while (widthScale > 2 && paintWidth > 1 || heightScale > 2 && paintHeight > 1) { + var newWidth = paintWidth, + newHeight = paintHeight; + if (widthScale > 2 && paintWidth > 1) { + newWidth = Math.ceil(paintWidth / 2); + widthScale /= paintWidth / newWidth; + } + if (heightScale > 2 && paintHeight > 1) { + newHeight = Math.ceil(paintHeight / 2); + heightScale /= paintHeight / newHeight; + } + 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'; + } + ctx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight, 0, -height, width, height); + if (this.imageLayer) { + var position = this.getCanvasPosition(0, -height); + this.imageLayer.appendImage({ + imgData: imgData, + left: position[0], + top: position[1], + width: width / currentTransform[0], + height: height / currentTransform[3] + }); + } + this.restore(); + }, + paintInlineImageXObjectGroup: function CanvasGraphics_paintInlineImageXObjectGroup(imgData, map) { + 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); + 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); + if (this.imageLayer) { + var position = this.getCanvasPosition(entry.x, entry.y); + this.imageLayer.appendImage({ + imgData: imgData, + left: position[0], + top: position[1], + width: w, + height: h + }); + } + ctx.restore(); + } + }, + paintSolidColorImageMask: function CanvasGraphics_paintSolidColorImageMask() { + this.ctx.fillRect(0, 0, 1, 1); + }, + paintXObject: function CanvasGraphics_paintXObject() { + (0, _util.warn)('Unsupported \'paintXObject\' command.'); + }, + markPoint: function CanvasGraphics_markPoint(tag) { + }, + markPointProps: function CanvasGraphics_markPointProps(tag, properties) { + }, + beginMarkedContent: function CanvasGraphics_beginMarkedContent(tag) { + }, + beginMarkedContentProps: function CanvasGraphics_beginMarkedContentProps(tag, properties) { + }, + endMarkedContent: function CanvasGraphics_endMarkedContent() { + }, + beginCompat: function CanvasGraphics_beginCompat() { + }, + endCompat: function CanvasGraphics_endCompat() { + }, + consumePath: function CanvasGraphics_consumePath() { + var ctx = this.ctx; + if (this.pendingClip) { + if (this.pendingClip === EO_CLIP) { + ctx.clip('evenodd'); + } else { + ctx.clip(); + } + this.pendingClip = null; + } + ctx.beginPath(); + }, + getSinglePixelWidth: function CanvasGraphics_getSinglePixelWidth(scale) { + if (this.cachedGetSinglePixelWidth === null) { + this.ctx.save(); + var inverse = this.ctx.mozCurrentTransformInverse; + this.ctx.restore(); + this.cachedGetSinglePixelWidth = Math.sqrt(Math.max(inverse[0] * inverse[0] + inverse[1] * inverse[1], inverse[2] * inverse[2] + inverse[3] * inverse[3])); + } + 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]]; + } + }; + for (var op in _util.OPS) { + CanvasGraphics.prototype[_util.OPS[op]] = CanvasGraphics.prototype[op]; + } + return CanvasGraphics; + }(); + exports.CanvasGraphics = CanvasGraphics; + + /***/ + }), + /* 12 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.FontLoader = exports.FontFaceObject = undefined; + + var _util = __w_pdfjs_require__(0); + + function FontLoader(docId) { + this.docId = docId; + this.styleElement = null; + this.nativeFontFaces = []; + this.loadTestFontId = 0; + this.loadingContext = { + requests: [], + nextRequestId: 0 + }; + } + + FontLoader.prototype = { + insertRule: function fontLoaderInsertRule(rule) { + var styleElement = this.styleElement; + if (!styleElement) { + styleElement = this.styleElement = document.createElement('style'); + styleElement.id = 'PDFJS_FONT_STYLE_TAG_' + this.docId; + document.documentElement.getElementsByTagName('head')[0].appendChild(styleElement); + } + var styleSheet = styleElement.sheet; + styleSheet.insertRule(rule, styleSheet.cssRules.length); + }, + clear: function fontLoaderClear() { + if (this.styleElement) { + this.styleElement.remove(); + this.styleElement = null; + } + this.nativeFontFaces.forEach(function (nativeFontFace) { + document.fonts.delete(nativeFontFace); + }); + this.nativeFontFaces.length = 0; + } + }; + { + var getLoadTestFont = function getLoadTestFont() { + return atob('T1RUTwALAIAAAwAwQ0ZGIDHtZg4AAAOYAAAAgUZGVE1lkzZwAAAEHAAAABxHREVGABQAFQ' + 'AABDgAAAAeT1MvMlYNYwkAAAEgAAAAYGNtYXABDQLUAAACNAAAAUJoZWFk/xVFDQAAALwA' + 'AAA2aGhlYQdkA+oAAAD0AAAAJGhtdHgD6AAAAAAEWAAAAAZtYXhwAAJQAAAAARgAAAAGbm' + 'FtZVjmdH4AAAGAAAAAsXBvc3T/hgAzAAADeAAAACAAAQAAAAEAALZRFsRfDzz1AAsD6AAA' + 'AADOBOTLAAAAAM4KHDwAAAAAA+gDIQAAAAgAAgAAAAAAAAABAAADIQAAAFoD6AAAAAAD6A' + 'ABAAAAAAAAAAAAAAAAAAAAAQAAUAAAAgAAAAQD6AH0AAUAAAKKArwAAACMAooCvAAAAeAA' + 'MQECAAACAAYJAAAAAAAAAAAAAQAAAAAAAAAAAAAAAFBmRWQAwAAuAC4DIP84AFoDIQAAAA' + 'AAAQAAAAAAAAAAACAAIAABAAAADgCuAAEAAAAAAAAAAQAAAAEAAAAAAAEAAQAAAAEAAAAA' + 'AAIAAQAAAAEAAAAAAAMAAQAAAAEAAAAAAAQAAQAAAAEAAAAAAAUAAQAAAAEAAAAAAAYAAQ' + 'AAAAMAAQQJAAAAAgABAAMAAQQJAAEAAgABAAMAAQQJAAIAAgABAAMAAQQJAAMAAgABAAMA' + 'AQQJAAQAAgABAAMAAQQJAAUAAgABAAMAAQQJAAYAAgABWABYAAAAAAAAAwAAAAMAAAAcAA' + 'EAAAAAADwAAwABAAAAHAAEACAAAAAEAAQAAQAAAC7//wAAAC7////TAAEAAAAAAAABBgAA' + 'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAA' + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAA' + 'AAAAD/gwAyAAAAAQAAAAAAAAAAAAAAAAAAAAABAAQEAAEBAQJYAAEBASH4DwD4GwHEAvgc' + 'A/gXBIwMAYuL+nz5tQXkD5j3CBLnEQACAQEBIVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWF' + 'hYWFhYWFhYAAABAQAADwACAQEEE/t3Dov6fAH6fAT+fPp8+nwHDosMCvm1Cvm1DAz6fBQA' + 'AAAAAAABAAAAAMmJbzEAAAAAzgTjFQAAAADOBOQpAAEAAAAAAAAADAAUAAQAAAABAAAAAg' + 'ABAAAAAAAAAAAD6AAAAAAAAA=='); + }; + Object.defineProperty(FontLoader.prototype, 'loadTestFont', { + get: function get() { + return (0, _util.shadow)(this, 'loadTestFont', getLoadTestFont()); + }, + + configurable: true + }); + FontLoader.prototype.addNativeFontFace = function fontLoader_addNativeFontFace(nativeFontFace) { + this.nativeFontFaces.push(nativeFontFace); + document.fonts.add(nativeFontFace); + }; + FontLoader.prototype.bind = function fontLoaderBind(fonts, callback) { + var rules = []; + var fontsToLoad = []; + var fontLoadPromises = []; + var getNativeFontPromise = function getNativeFontPromise(nativeFontFace) { + return nativeFontFace.loaded.catch(function (e) { + (0, _util.warn)('Failed to load font "' + nativeFontFace.family + '": ' + e); + }); + }; + var isFontLoadingAPISupported = FontLoader.isFontLoadingAPISupported && !FontLoader.isSyncFontLoadingSupported; + for (var i = 0, ii = fonts.length; i < ii; i++) { + var font = fonts[i]; + if (font.attached || font.loading === false) { + continue; + } + font.attached = true; + if (isFontLoadingAPISupported) { + var nativeFontFace = font.createNativeFontFace(); + if (nativeFontFace) { + this.addNativeFontFace(nativeFontFace); + fontLoadPromises.push(getNativeFontPromise(nativeFontFace)); + } + } else { + var rule = font.createFontFaceRule(); + if (rule) { + this.insertRule(rule); + rules.push(rule); + fontsToLoad.push(font); + } + } + } + var request = this.queueLoadingCallback(callback); + if (isFontLoadingAPISupported) { + Promise.all(fontLoadPromises).then(function () { + request.complete(); + }); + } else if (rules.length > 0 && !FontLoader.isSyncFontLoadingSupported) { + this.prepareFontLoadEvent(rules, fontsToLoad, request); + } else { + request.complete(); + } + }; + FontLoader.prototype.queueLoadingCallback = function FontLoader_queueLoadingCallback(callback) { + function LoadLoader_completeRequest() { + (0, _util.assert)(!request.end, 'completeRequest() cannot be called twice'); + request.end = Date.now(); + while (context.requests.length > 0 && context.requests[0].end) { + var otherRequest = context.requests.shift(); + setTimeout(otherRequest.callback, 0); + } + } + + var context = this.loadingContext; + var requestId = 'pdfjs-font-loading-' + context.nextRequestId++; + var request = { + id: requestId, + complete: LoadLoader_completeRequest, + callback: callback, + started: Date.now() + }; + context.requests.push(request); + return request; + }; + FontLoader.prototype.prepareFontLoadEvent = function fontLoaderPrepareFontLoadEvent(rules, fonts, request) { + function int32(data, offset) { + return data.charCodeAt(offset) << 24 | data.charCodeAt(offset + 1) << 16 | data.charCodeAt(offset + 2) << 8 | data.charCodeAt(offset + 3) & 0xff; + } + + function spliceString(s, offset, remove, insert) { + var chunk1 = s.substr(0, offset); + var chunk2 = s.substr(offset + remove); + return chunk1 + insert + chunk2; + } + + var i, ii; + var canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + var ctx = canvas.getContext('2d'); + var called = 0; + + function isFontReady(name, callback) { + called++; + if (called > 30) { + (0, _util.warn)('Load test font never loaded.'); + callback(); + return; + } + ctx.font = '30px ' + name; + ctx.fillText('.', 0, 20); + var imageData = ctx.getImageData(0, 0, 1, 1); + if (imageData.data[3] > 0) { + callback(); + return; + } + setTimeout(isFontReady.bind(null, name, callback)); + } + + var loadTestFontId = 'lt' + Date.now() + this.loadTestFontId++; + var data = this.loadTestFont; + var COMMENT_OFFSET = 976; + data = spliceString(data, COMMENT_OFFSET, loadTestFontId.length, loadTestFontId); + var CFF_CHECKSUM_OFFSET = 16; + var XXXX_VALUE = 0x58585858; + var checksum = int32(data, CFF_CHECKSUM_OFFSET); + for (i = 0, ii = loadTestFontId.length - 3; i < ii; i += 4) { + checksum = checksum - XXXX_VALUE + int32(loadTestFontId, i) | 0; + } + if (i < loadTestFontId.length) { + checksum = checksum - XXXX_VALUE + int32(loadTestFontId + 'XXX', i) | 0; + } + data = spliceString(data, CFF_CHECKSUM_OFFSET, 4, (0, _util.string32)(checksum)); + var url = 'url(data:font/opentype;base64,' + btoa(data) + ');'; + var rule = '@font-face { font-family:"' + loadTestFontId + '";src:' + url + '}'; + this.insertRule(rule); + var names = []; + for (i = 0, ii = fonts.length; i < ii; i++) { + names.push(fonts[i].loadedName); + } + names.push(loadTestFontId); + var div = document.createElement('div'); + div.setAttribute('style', 'visibility: hidden;' + 'width: 10px; height: 10px;' + 'position: absolute; top: 0px; left: 0px;'); + for (i = 0, ii = names.length; i < ii; ++i) { + var span = document.createElement('span'); + span.textContent = 'Hi'; + span.style.fontFamily = names[i]; + div.appendChild(span); + } + document.body.appendChild(div); + isFontReady(loadTestFontId, function () { + document.body.removeChild(div); + request.complete(); + }); + }; + } + { + FontLoader.isFontLoadingAPISupported = typeof document !== 'undefined' && !!document.fonts; + } + { + var isSyncFontLoadingSupported = function isSyncFontLoadingSupported() { + if (typeof navigator === 'undefined') { + return true; + } + var supported = false; + var m = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(navigator.userAgent); + if (m && m[1] >= 14) { + supported = true; + } + return supported; + }; + Object.defineProperty(FontLoader, 'isSyncFontLoadingSupported', { + get: function get() { + return (0, _util.shadow)(FontLoader, 'isSyncFontLoadingSupported', isSyncFontLoadingSupported()); + }, + + enumerable: true, + configurable: true + }); + } + var IsEvalSupportedCached = { + get value() { + return (0, _util.shadow)(this, 'value', (0, _util.isEvalSupported)()); + } + }; + var FontFaceObject = function FontFaceObjectClosure() { + function FontFaceObject(translatedData, options) { + this.compiledGlyphs = Object.create(null); + for (var i in translatedData) { + this[i] = translatedData[i]; + } + this.options = options; + } + + FontFaceObject.prototype = { + createNativeFontFace: function FontFaceObject_createNativeFontFace() { + if (!this.data) { + return null; + } + if (this.options.disableFontFace) { + this.disableFontFace = true; + return null; + } + var nativeFontFace = new FontFace(this.loadedName, this.data, {}); + if (this.options.fontRegistry) { + this.options.fontRegistry.registerFont(this); + } + return nativeFontFace; + }, + createFontFaceRule: function FontFaceObject_createFontFaceRule() { + if (!this.data) { + return null; + } + if (this.options.disableFontFace) { + this.disableFontFace = true; + return null; + } + var data = (0, _util.bytesToString)(new Uint8Array(this.data)); + var fontName = this.loadedName; + var url = 'url(data:' + this.mimetype + ';base64,' + btoa(data) + ');'; + var rule = '@font-face { font-family:"' + fontName + '";src:' + url + '}'; + if (this.options.fontRegistry) { + this.options.fontRegistry.registerFont(this, url); + } + return rule; + }, + getPathGenerator: function FontFaceObject_getPathGenerator(objs, character) { + if (!(character in this.compiledGlyphs)) { + var cmds = objs.get(this.loadedName + '_path_' + character); + var current, i, len; + if (this.options.isEvalSupported && IsEvalSupportedCached.value) { + var args, + js = ''; + for (i = 0, len = cmds.length; i < len; i++) { + current = cmds[i]; + if (current.args !== undefined) { + args = current.args.join(','); + } else { + args = ''; + } + js += 'c.' + current.cmd + '(' + args + ');\n'; + } + this.compiledGlyphs[character] = new Function('c', 'size', js); + } else { + this.compiledGlyphs[character] = function (c, size) { + for (i = 0, len = cmds.length; i < len; i++) { + current = cmds[i]; + if (current.cmd === 'scale') { + current.args = [size, -size]; + } + c[current.cmd].apply(c, current.args); + } + }; + } + } + return this.compiledGlyphs[character]; + } + }; + return FontFaceObject; + }(); + exports.FontFaceObject = FontFaceObject; + exports.FontLoader = FontLoader; + + /***/ + }), + /* 13 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.TilingPattern = exports.getShadingPatternFromIR = undefined; + + var _util = __w_pdfjs_require__(0); + + var _webgl = __w_pdfjs_require__(7); + + var ShadingIRs = {}; + ShadingIRs.RadialAxial = { + fromIR: function RadialAxial_fromIR(raw) { + var type = raw[1]; + var colorStops = raw[2]; + var p0 = raw[3]; + var p1 = raw[4]; + var r0 = raw[5]; + var r1 = raw[6]; + return { + type: 'Pattern', + getPattern: function RadialAxial_getPattern(ctx) { + 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; + } + }; + } + }; + var createMeshCanvas = function createMeshCanvasClosure() { + function drawTriangle(data, context, p1, p2, p3, c1, c2, c3) { + var coords = context.coords, + colors = context.colors; + var bytes = data.data, + rowSize = data.width * 4; + var 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[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; + if (y1 >= y3) { + return; + } + var c1r = colors[c1], + c1g = colors[c1 + 1], + c1b = colors[c1 + 2]; + var c2r = colors[c2], + c2g = colors[c2 + 1], + c2b = colors[c2 + 2]; + var c3r = colors[c3], + c3g = colors[c3 + 1], + c3b = colors[c3 + 2]; + var minY = Math.round(y1), + maxY = Math.round(y3); + var xa, car, cag, cab; + var xb, cbr, cbg, cbb; + var k; + for (var y = minY; y <= maxY; y++) { + if (y < y2) { + k = y < y1 ? 0 : y1 === y2 ? 1 : (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 { + k = y > y3 ? 1 : y2 === y3 ? 0 : (y2 - y) / (y2 - y3); + xa = x2 - (x2 - x3) * k; + car = c2r - (c2r - c3r) * k; + cag = c2g - (c2g - c3g) * k; + cab = c2b - (c2b - c3b) * k; + } + k = y < y1 ? 0 : y > y3 ? 1 : (y1 - y) / (y1 - y3); + 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; + for (var x = x1_; x <= x2_; x++) { + k = (xa - x) / (xa - xb); + k = k < 0 ? 0 : k > 1 ? 1 : k; + 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; + switch (figure.type) { + case 'lattice': + var verticesPerRow = figure.verticesPerRow; + var rows = Math.floor(ps.length / verticesPerRow) - 1; + var cols = verticesPerRow - 1; + for (i = 0; i < rows; i++) { + var 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]); + } + } + 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]); + } + break; + default: + throw new Error('illegal figure'); + } + } + + function createMeshCanvas(bounds, combinesScale, coords, colors, figures, backgroundColor, cachedCanvases) { + 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: coords, + colors: 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; + if (_webgl.WebGLUtils.isEnabled) { + canvas = _webgl.WebGLUtils.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) { + 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 (i = 0; i < figures.length; i++) { + drawFigure(data, figures[i], context); + } + tmpCtx.putImageData(data, BORDER_SIZE, BORDER_SIZE); + canvas = tmpCanvas.canvas; + } + return { + canvas: canvas, + offsetX: offsetX - BORDER_SIZE * scaleX, + offsetY: offsetY - BORDER_SIZE * scaleY, + scaleX: scaleX, + scaleY: scaleY + }; + } + + return createMeshCanvas; + }(); + 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 background = raw[8]; + return { + type: 'Pattern', + getPattern: function Mesh_getPattern(ctx, owner, shadingFill) { + var scale; + if (shadingFill) { + scale = _util.Util.singularValueDecompose2dScale(ctx.mozCurrentTransform); + } else { + scale = _util.Util.singularValueDecompose2dScale(owner.baseTransform); + 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); + 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'); + } + }; + } + }; + ShadingIRs.Dummy = { + fromIR: function Dummy_fromIR() { + return { + type: 'Pattern', + getPattern: function Dummy_fromIR_getPattern() { + return 'hotpink'; + } + }; + } + }; + + function getShadingPatternFromIR(raw) { + var shadingIR = ShadingIRs[raw[0]]; + if (!shadingIR) { + throw new Error('Unknown IR type: ' + raw[0]); + } + return shadingIR.fromIR(raw); + } + + var TilingPattern = function TilingPatternClosure() { + var PaintType = { + COLORED: 1, + UNCOLORED: 2 + }; + var MAX_PATTERN_SIZE = 3000; + + function TilingPattern(IR, color, ctx, canvasGraphicsFactory, baseTransform) { + this.operatorList = IR[2]; + this.matrix = IR[3] || [1, 0, 0, 1, 0, 0]; + this.bbox = IR[4]; + this.xstep = IR[5]; + this.ystep = IR[6]; + this.paintType = IR[7]; + this.tilingType = IR[8]; + this.color = color; + 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], + y0 = bbox[1], + x1 = bbox[2], + y1 = bbox[3]; + var topLeft = [x0, y0]; + var botRight = [x0 + xstep, y0 + ystep]; + var width = botRight[0] - topLeft[0]; + var height = botRight[1] - topLeft[1]; + var matrixScale = _util.Util.singularValueDecompose2dScale(this.matrix); + var curMatrixScale = _util.Util.singularValueDecompose2dScale(this.baseTransform); + var combinedScale = [matrixScale[0] * curMatrixScale[0], matrixScale[1] * curMatrixScale[1]]; + width = Math.min(Math.ceil(Math.abs(width * combinedScale[0])), MAX_PATTERN_SIZE); + height = Math.min(Math.ceil(Math.abs(height * combinedScale[1])), MAX_PATTERN_SIZE); + var tmpCanvas = owner.cachedCanvases.getCanvas('pattern', width, height, true); + var tmpCtx = tmpCanvas.context; + var graphics = canvasGraphicsFactory.createCanvasGraphics(tmpCtx); + graphics.groupLevel = owner.groupLevel; + this.setFillAndStrokeStyleToContext(tmpCtx, paintType, color); + this.setScale(width, height, xstep, ystep); + this.transformToScale(graphics); + var tmpTranslate = [1, 0, 0, 1, -topLeft[0], -topLeft[1]]; + graphics.transform.apply(graphics, tmpTranslate); + this.clipBbox(graphics, bbox, x0, y0, x1, y1); + graphics.executeOperatorList(operatorList); + return tmpCanvas.canvas; + }, + setScale: function TilingPattern_setScale(width, height, xstep, ystep) { + this.scale = [width / xstep, height / ystep]; + }, + transformToScale: function TilingPattern_transformToScale(graphics) { + var scale = this.scale; + var tmpScale = [scale[0], 0, 0, scale[1], 0, 0]; + graphics.transform.apply(graphics, tmpScale); + }, + scaleToContext: function TilingPattern_scaleToContext() { + var scale = this.scale; + this.ctx.scale(1 / scale[0], 1 / scale[1]); + }, + clipBbox: function clipBbox(graphics, bbox, x0, y0, x1, y1) { + if ((0, _util.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(context, paintType, color) { + switch (paintType) { + case PaintType.COLORED: + var ctx = this.ctx; + context.fillStyle = ctx.fillStyle; + context.strokeStyle = ctx.strokeStyle; + break; + case PaintType.UNCOLORED: + var cssColor = _util.Util.makeCssRgb(color[0], color[1], color[2]); + context.fillStyle = cssColor; + context.strokeStyle = cssColor; + break; + default: + throw new _util.FormatError('Unsupported paint type: ' + paintType); + } + }, + getPattern: function TilingPattern_getPattern(ctx, owner) { + var temporaryPatternCanvas = this.createPatternCanvas(owner); + ctx = this.ctx; + ctx.setTransform.apply(ctx, this.baseTransform); + ctx.transform.apply(ctx, this.matrix); + this.scaleToContext(); + return ctx.createPattern(temporaryPatternCanvas, 'repeat'); + } + }; + return TilingPattern; + }(); + exports.getShadingPatternFromIR = getShadingPatternFromIR; + exports.TilingPattern = TilingPattern; + + /***/ + }), + /* 14 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFDataTransportStream = undefined; + + var _util = __w_pdfjs_require__(0); + + var PDFDataTransportStream = function PDFDataTransportStreamClosure() { + function PDFDataTransportStream(params, pdfDataRangeTransport) { + var _this = this; + + (0, _util.assert)(pdfDataRangeTransport); + this._queuedChunks = []; + var initialData = params.initialData; + if (initialData && initialData.length > 0) { + var buffer = new Uint8Array(initialData).buffer; + this._queuedChunks.push(buffer); + } + this._pdfDataRangeTransport = pdfDataRangeTransport; + this._isRangeSupported = !params.disableRange; + this._isStreamingSupported = !params.disableStream; + this._contentLength = params.length; + this._fullRequestReader = null; + this._rangeReaders = []; + this._pdfDataRangeTransport.addRangeListener(function (begin, chunk) { + _this._onReceiveData({ + begin: begin, + chunk: chunk + }); + }); + this._pdfDataRangeTransport.addProgressListener(function (loaded) { + _this._onProgress({loaded: loaded}); + }); + this._pdfDataRangeTransport.addProgressiveReadListener(function (chunk) { + _this._onReceiveData({chunk: chunk}); + }); + this._pdfDataRangeTransport.transportReady(); + } + + PDFDataTransportStream.prototype = { + _onReceiveData: function PDFDataTransportStream_onReceiveData(args) { + var buffer = new Uint8Array(args.chunk).buffer; + if (args.begin === undefined) { + if (this._fullRequestReader) { + this._fullRequestReader._enqueue(buffer); + } else { + this._queuedChunks.push(buffer); + } + } else { + var found = this._rangeReaders.some(function (rangeReader) { + if (rangeReader._begin !== args.begin) { + return false; + } + rangeReader._enqueue(buffer); + return true; + }); + (0, _util.assert)(found); + } + }, + _onProgress: function PDFDataTransportStream_onDataProgress(evt) { + if (this._rangeReaders.length > 0) { + var firstReader = this._rangeReaders[0]; + if (firstReader.onProgress) { + firstReader.onProgress({loaded: evt.loaded}); + } + } + }, + _removeRangeReader: function PDFDataTransportStream_removeRangeReader(reader) { + var i = this._rangeReaders.indexOf(reader); + if (i >= 0) { + this._rangeReaders.splice(i, 1); + } + }, + getFullReader: function PDFDataTransportStream_getFullReader() { + (0, _util.assert)(!this._fullRequestReader); + var queuedChunks = this._queuedChunks; + this._queuedChunks = null; + return new PDFDataTransportStreamReader(this, queuedChunks); + }, + getRangeReader: function PDFDataTransportStream_getRangeReader(begin, end) { + var reader = new PDFDataTransportStreamRangeReader(this, begin, end); + this._pdfDataRangeTransport.requestDataRange(begin, end); + this._rangeReaders.push(reader); + return reader; + }, + cancelAllRequests: function PDFDataTransportStream_cancelAllRequests(reason) { + if (this._fullRequestReader) { + this._fullRequestReader.cancel(reason); + } + var readers = this._rangeReaders.slice(0); + readers.forEach(function (rangeReader) { + rangeReader.cancel(reason); + }); + this._pdfDataRangeTransport.abort(); + } + }; + + function PDFDataTransportStreamReader(stream, queuedChunks) { + this._stream = stream; + this._done = false; + this._queuedChunks = queuedChunks || []; + this._requests = []; + this._headersReady = Promise.resolve(); + stream._fullRequestReader = this; + this.onProgress = null; + } + + PDFDataTransportStreamReader.prototype = { + _enqueue: function PDFDataTransportStreamReader_enqueue(chunk) { + if (this._done) { + return; + } + if (this._requests.length > 0) { + var requestCapability = this._requests.shift(); + requestCapability.resolve({ + value: chunk, + done: false + }); + return; + } + this._queuedChunks.push(chunk); + }, + get headersReady() { + return this._headersReady; + }, + get isRangeSupported() { + return this._stream._isRangeSupported; + }, + get isStreamingSupported() { + return this._stream._isStreamingSupported; + }, + get contentLength() { + return this._stream._contentLength; + }, + read: function PDFDataTransportStreamReader_read() { + if (this._queuedChunks.length > 0) { + var chunk = this._queuedChunks.shift(); + return Promise.resolve({ + value: chunk, + done: false + }); + } + if (this._done) { + return Promise.resolve({ + value: undefined, + done: true + }); + } + var requestCapability = (0, _util.createPromiseCapability)(); + this._requests.push(requestCapability); + return requestCapability.promise; + }, + cancel: function PDFDataTransportStreamReader_cancel(reason) { + this._done = true; + this._requests.forEach(function (requestCapability) { + requestCapability.resolve({ + value: undefined, + done: true + }); + }); + this._requests = []; + } + }; + + function PDFDataTransportStreamRangeReader(stream, begin, end) { + this._stream = stream; + this._begin = begin; + this._end = end; + this._queuedChunk = null; + this._requests = []; + this._done = false; + this.onProgress = null; + } + + PDFDataTransportStreamRangeReader.prototype = { + _enqueue: function PDFDataTransportStreamRangeReader_enqueue(chunk) { + if (this._done) { + return; + } + if (this._requests.length === 0) { + this._queuedChunk = chunk; + } else { + var requestsCapability = this._requests.shift(); + requestsCapability.resolve({ + value: chunk, + done: false + }); + this._requests.forEach(function (requestCapability) { + requestCapability.resolve({ + value: undefined, + done: true + }); + }); + this._requests = []; + } + this._done = true; + this._stream._removeRangeReader(this); + }, + get isStreamingSupported() { + return false; + }, + read: function PDFDataTransportStreamRangeReader_read() { + if (this._queuedChunk) { + var chunk = this._queuedChunk; + this._queuedChunk = null; + return Promise.resolve({ + value: chunk, + done: false + }); + } + if (this._done) { + return Promise.resolve({ + value: undefined, + done: true + }); + } + var requestCapability = (0, _util.createPromiseCapability)(); + this._requests.push(requestCapability); + return requestCapability.promise; + }, + cancel: function PDFDataTransportStreamRangeReader_cancel(reason) { + this._done = true; + this._requests.forEach(function (requestCapability) { + requestCapability.resolve({ + value: undefined, + done: true + }); + }); + this._requests = []; + this._stream._removeRangeReader(this); + } + }; + return PDFDataTransportStream; + }(); + exports.PDFDataTransportStream = PDFDataTransportStream; + + /***/ + }), + /* 15 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + var pdfjsVersion = '1.9.426'; + var pdfjsBuild = '2558a58d'; + var pdfjsSharedUtil = __w_pdfjs_require__(0); + var pdfjsDisplayGlobal = __w_pdfjs_require__(8); + var pdfjsDisplayAPI = __w_pdfjs_require__(2); + var pdfjsDisplayTextLayer = __w_pdfjs_require__(5); + var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(3); + var pdfjsDisplayDOMUtils = __w_pdfjs_require__(1); + var pdfjsDisplaySVG = __w_pdfjs_require__(4); + { + __w_pdfjs_require__(9); + } + exports.PDFJS = pdfjsDisplayGlobal.PDFJS; + exports.build = pdfjsDisplayAPI.build; + exports.version = pdfjsDisplayAPI.version; + exports.getDocument = pdfjsDisplayAPI.getDocument; + exports.LoopbackPort = pdfjsDisplayAPI.LoopbackPort; + exports.PDFDataRangeTransport = pdfjsDisplayAPI.PDFDataRangeTransport; + exports.PDFWorker = pdfjsDisplayAPI.PDFWorker; + exports.renderTextLayer = pdfjsDisplayTextLayer.renderTextLayer; + exports.AnnotationLayer = pdfjsDisplayAnnotationLayer.AnnotationLayer; + exports.CustomStyle = pdfjsDisplayDOMUtils.CustomStyle; + exports.createPromiseCapability = pdfjsSharedUtil.createPromiseCapability; + exports.PasswordResponses = pdfjsSharedUtil.PasswordResponses; + exports.InvalidPDFException = pdfjsSharedUtil.InvalidPDFException; + exports.MissingPDFException = pdfjsSharedUtil.MissingPDFException; + exports.SVGGraphics = pdfjsDisplaySVG.SVGGraphics; + exports.NativeImageDecoding = pdfjsSharedUtil.NativeImageDecoding; + exports.UnexpectedResponseException = pdfjsSharedUtil.UnexpectedResponseException; + exports.OPS = pdfjsSharedUtil.OPS; + exports.UNSUPPORTED_FEATURES = pdfjsSharedUtil.UNSUPPORTED_FEATURES; + exports.isValidUrl = pdfjsDisplayDOMUtils.isValidUrl; + exports.createValidAbsoluteUrl = pdfjsSharedUtil.createValidAbsoluteUrl; + exports.createObjectURL = pdfjsSharedUtil.createObjectURL; + exports.removeNullCharacters = pdfjsSharedUtil.removeNullCharacters; + exports.shadow = pdfjsSharedUtil.shadow; + exports.createBlob = pdfjsSharedUtil.createBlob; + exports.RenderingCancelledException = pdfjsDisplayDOMUtils.RenderingCancelledException; + exports.getFilenameFromUrl = pdfjsDisplayDOMUtils.getFilenameFromUrl; + exports.addLinkAttributes = pdfjsDisplayDOMUtils.addLinkAttributes; + exports.StatTimer = pdfjsSharedUtil.StatTimer; + + /***/ + }), + /* 16 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + if (typeof PDFJS === 'undefined' || !PDFJS.compatibilityChecked) { + var globalScope = typeof window !== 'undefined' && window.Math === Math ? window : typeof global !== 'undefined' && global.Math === Math ? global : typeof self !== 'undefined' && self.Math === Math ? self : false ? undefined : {}; + var userAgent = typeof navigator !== 'undefined' && navigator.userAgent || ''; + var isAndroid = /Android/.test(userAgent); + var isAndroidPre3 = /Android\s[0-2][^\d]/.test(userAgent); + var isAndroidPre5 = /Android\s[0-4][^\d]/.test(userAgent); + var isChrome = userAgent.indexOf('Chrom') >= 0; + var isChromeWithRangeBug = /Chrome\/(39|40)\./.test(userAgent); + var isIOSChrome = userAgent.indexOf('CriOS') >= 0; + var isIE = userAgent.indexOf('Trident') >= 0; + var isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent); + var isOpera = userAgent.indexOf('Opera') >= 0; + var isSafari = /Safari\//.test(userAgent) && !/(Chrome\/|Android\s)/.test(userAgent); + var hasDOM = (typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && (typeof document === 'undefined' ? 'undefined' : _typeof(document)) === 'object'; + if (typeof PDFJS === 'undefined') { + globalScope.PDFJS = {}; + } + PDFJS.compatibilityChecked = true; + (function checkTypedArrayCompatibility() { + if (typeof Uint8Array !== 'undefined') { + if (typeof Uint8Array.prototype.subarray === 'undefined') { + Uint8Array.prototype.subarray = function subarray(start, end) { + return new Uint8Array(this.slice(start, end)); + }; + Float32Array.prototype.subarray = function subarray(start, end) { + return new Float32Array(this.slice(start, end)); + }; + } + if (typeof Float64Array === 'undefined') { + globalScope.Float64Array = Float32Array; + } + return; + } + + function subarray(start, end) { + return new TypedArray(this.slice(start, end)); + } + + function setArrayOffset(array, offset) { + if (arguments.length < 2) { + offset = 0; + } + for (var i = 0, n = array.length; i < n; ++i, ++offset) { + this[offset] = array[i] & 0xFF; + } + } + + function Uint32ArrayView(buffer, length) { + this.buffer = buffer; + this.byteLength = buffer.length; + this.length = length; + ensureUint32ArrayViewProps(this.length); + } + + Uint32ArrayView.prototype = Object.create(null); + var uint32ArrayViewSetters = 0; + + function createUint32ArrayProp(index) { + return { + get: function get() { + var buffer = this.buffer, + offset = index << 2; + return (buffer[offset] | buffer[offset + 1] << 8 | buffer[offset + 2] << 16 | buffer[offset + 3] << 24) >>> 0; + }, + set: function set(value) { + var buffer = this.buffer, + offset = index << 2; + buffer[offset] = value & 255; + buffer[offset + 1] = value >> 8 & 255; + buffer[offset + 2] = value >> 16 & 255; + buffer[offset + 3] = value >>> 24 & 255; + } + }; + } + + function ensureUint32ArrayViewProps(length) { + while (uint32ArrayViewSetters < length) { + Object.defineProperty(Uint32ArrayView.prototype, uint32ArrayViewSetters, createUint32ArrayProp(uint32ArrayViewSetters)); + uint32ArrayViewSetters++; + } + } + + function TypedArray(arg1) { + var result, i, n; + if (typeof arg1 === 'number') { + result = []; + for (i = 0; i < arg1; ++i) { + result[i] = 0; + } + } else if ('slice' in arg1) { + result = arg1.slice(0); + } else { + result = []; + for (i = 0, n = arg1.length; i < n; ++i) { + result[i] = arg1[i]; + } + } + result.subarray = subarray; + result.buffer = result; + result.byteLength = result.length; + result.set = setArrayOffset; + if ((typeof arg1 === 'undefined' ? 'undefined' : _typeof(arg1)) === 'object' && arg1.buffer) { + result.buffer = arg1.buffer; + } + return result; + } + + globalScope.Uint8Array = TypedArray; + globalScope.Int8Array = TypedArray; + globalScope.Int32Array = TypedArray; + globalScope.Uint16Array = TypedArray; + globalScope.Float32Array = TypedArray; + globalScope.Float64Array = TypedArray; + globalScope.Uint32Array = function () { + if (arguments.length === 3) { + if (arguments[1] !== 0) { + throw new Error('offset !== 0 is not supported'); + } + return new Uint32ArrayView(arguments[0], arguments[2]); + } + return TypedArray.apply(this, arguments); + }; + })(); + (function canvasPixelArrayBuffer() { + if (!hasDOM || !window.CanvasPixelArray) { + return; + } + var cpaProto = window.CanvasPixelArray.prototype; + if ('buffer' in cpaProto) { + return; + } + Object.defineProperty(cpaProto, 'buffer', { + get: function get() { + return this; + }, + + enumerable: false, + configurable: true + }); + Object.defineProperty(cpaProto, 'byteLength', { + get: function get() { + return this.length; + }, + + enumerable: false, + configurable: true + }); + })(); + (function normalizeURLObject() { + if (!globalScope.URL) { + globalScope.URL = globalScope.webkitURL; + } + })(); + (function checkObjectDefinePropertyCompatibility() { + if (typeof Object.defineProperty !== 'undefined') { + var definePropertyPossible = true; + try { + if (hasDOM) { + Object.defineProperty(new Image(), 'id', {value: 'test'}); + } + var Test = function Test() { + }; + Test.prototype = { + get id() { + } + }; + Object.defineProperty(new Test(), 'id', { + value: '', + configurable: true, + enumerable: true, + writable: false + }); + } catch (e) { + definePropertyPossible = false; + } + if (definePropertyPossible) { + return; + } + } + Object.defineProperty = function objectDefineProperty(obj, name, def) { + delete obj[name]; + if ('get' in def) { + obj.__defineGetter__(name, def['get']); + } + if ('set' in def) { + obj.__defineSetter__(name, def['set']); + } + if ('value' in def) { + obj.__defineSetter__(name, function objectDefinePropertySetter(value) { + this.__defineGetter__(name, function objectDefinePropertyGetter() { + return value; + }); + return value; + }); + obj[name] = def.value; + } + }; + })(); + (function checkXMLHttpRequestResponseCompatibility() { + if (typeof XMLHttpRequest === 'undefined') { + return; + } + var xhrPrototype = XMLHttpRequest.prototype; + var xhr = new XMLHttpRequest(); + if (!('overrideMimeType' in xhr)) { + Object.defineProperty(xhrPrototype, 'overrideMimeType', { + value: function xmlHttpRequestOverrideMimeType(mimeType) { + } + }); + } + if ('responseType' in xhr) { + return; + } + Object.defineProperty(xhrPrototype, 'responseType', { + get: function xmlHttpRequestGetResponseType() { + return this._responseType || 'text'; + }, + set: function xmlHttpRequestSetResponseType(value) { + if (value === 'text' || value === 'arraybuffer') { + this._responseType = value; + if (value === 'arraybuffer' && typeof this.overrideMimeType === 'function') { + this.overrideMimeType('text/plain; charset=x-user-defined'); + } + } + } + }); + if (typeof VBArray !== 'undefined') { + Object.defineProperty(xhrPrototype, 'response', { + get: function xmlHttpRequestResponseGet() { + if (this.responseType === 'arraybuffer') { + return new Uint8Array(new VBArray(this.responseBody).toArray()); + } + return this.responseText; + } + }); + return; + } + Object.defineProperty(xhrPrototype, 'response', { + get: function xmlHttpRequestResponseGet() { + if (this.responseType !== 'arraybuffer') { + return this.responseText; + } + var text = this.responseText; + var i, + n = text.length; + var result = new Uint8Array(n); + for (i = 0; i < n; ++i) { + result[i] = text.charCodeAt(i) & 0xFF; + } + return result.buffer; + } + }); + })(); + (function checkWindowBtoaCompatibility() { + if ('btoa' in globalScope) { + return; + } + var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + globalScope.btoa = function (chars) { + var buffer = ''; + var i, n; + for (i = 0, n = chars.length; i < n; i += 3) { + var b1 = chars.charCodeAt(i) & 0xFF; + var b2 = chars.charCodeAt(i + 1) & 0xFF; + var b3 = chars.charCodeAt(i + 2) & 0xFF; + var d1 = b1 >> 2, + d2 = (b1 & 3) << 4 | b2 >> 4; + var d3 = i + 1 < n ? (b2 & 0xF) << 2 | b3 >> 6 : 64; + var d4 = i + 2 < n ? b3 & 0x3F : 64; + buffer += digits.charAt(d1) + digits.charAt(d2) + digits.charAt(d3) + digits.charAt(d4); + } + return buffer; + }; + })(); + (function checkWindowAtobCompatibility() { + if ('atob' in globalScope) { + return; + } + var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + globalScope.atob = function (input) { + input = input.replace(/=+$/, ''); + if (input.length % 4 === 1) { + throw new Error('bad atob input'); + } + for (var bc = 0, bs, buffer, idx = 0, output = ''; buffer = input.charAt(idx++); ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer, bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0) { + buffer = digits.indexOf(buffer); + } + return output; + }; + })(); + (function checkFunctionPrototypeBindCompatibility() { + if (typeof Function.prototype.bind !== 'undefined') { + return; + } + Function.prototype.bind = function functionPrototypeBind(obj) { + var fn = this, + headArgs = Array.prototype.slice.call(arguments, 1); + var bound = function functionPrototypeBindBound() { + var args = headArgs.concat(Array.prototype.slice.call(arguments)); + return fn.apply(obj, args); + }; + return bound; + }; + })(); + (function checkDatasetProperty() { + if (!hasDOM) { + return; + } + var div = document.createElement('div'); + if ('dataset' in div) { + return; + } + Object.defineProperty(HTMLElement.prototype, 'dataset', { + get: function get() { + if (this._dataset) { + return this._dataset; + } + var dataset = {}; + for (var j = 0, jj = this.attributes.length; j < jj; j++) { + var attribute = this.attributes[j]; + if (attribute.name.substring(0, 5) !== 'data-') { + continue; + } + var key = attribute.name.substring(5).replace(/\-([a-z])/g, function (all, ch) { + return ch.toUpperCase(); + }); + dataset[key] = attribute.value; + } + Object.defineProperty(this, '_dataset', { + value: dataset, + writable: false, + enumerable: false + }); + return dataset; + }, + + enumerable: true + }); + })(); + (function checkClassListProperty() { + function changeList(element, itemName, add, remove) { + var s = element.className || ''; + var list = s.split(/\s+/g); + if (list[0] === '') { + list.shift(); + } + var index = list.indexOf(itemName); + if (index < 0 && add) { + list.push(itemName); + } + if (index >= 0 && remove) { + list.splice(index, 1); + } + element.className = list.join(' '); + return index >= 0; + } + + if (!hasDOM) { + return; + } + var div = document.createElement('div'); + if ('classList' in div) { + return; + } + var classListPrototype = { + add: function add(name) { + changeList(this.element, name, true, false); + }, + contains: function contains(name) { + return changeList(this.element, name, false, false); + }, + remove: function remove(name) { + changeList(this.element, name, false, true); + }, + toggle: function toggle(name) { + changeList(this.element, name, true, true); + } + }; + Object.defineProperty(HTMLElement.prototype, 'classList', { + get: function get() { + if (this._classList) { + return this._classList; + } + var classList = Object.create(classListPrototype, { + element: { + value: this, + writable: false, + enumerable: true + } + }); + Object.defineProperty(this, '_classList', { + value: classList, + writable: false, + enumerable: false + }); + return classList; + }, + + enumerable: true + }); + })(); + (function checkWorkerConsoleCompatibility() { + if (typeof importScripts === 'undefined' || 'console' in globalScope) { + return; + } + var consoleTimer = {}; + var workerConsole = { + log: function log() { + var args = Array.prototype.slice.call(arguments); + globalScope.postMessage({ + targetName: 'main', + action: 'console_log', + data: args + }); + }, + error: function error() { + var args = Array.prototype.slice.call(arguments); + globalScope.postMessage({ + targetName: 'main', + action: 'console_error', + data: args + }); + }, + time: function time(name) { + consoleTimer[name] = Date.now(); + }, + timeEnd: function timeEnd(name) { + var time = consoleTimer[name]; + if (!time) { + throw new Error('Unknown timer name ' + name); + } + this.log('Timer:', name, Date.now() - time); + } + }; + globalScope.console = workerConsole; + })(); + (function checkConsoleCompatibility() { + if (!hasDOM) { + return; + } + if (!('console' in window)) { + window.console = { + log: function log() { + }, + error: function error() { + }, + warn: function warn() { + } + }; + return; + } + if (!('bind' in console.log)) { + console.log = function (fn) { + return function (msg) { + return fn(msg); + }; + }(console.log); + console.error = function (fn) { + return function (msg) { + return fn(msg); + }; + }(console.error); + console.warn = function (fn) { + return function (msg) { + return fn(msg); + }; + }(console.warn); + return; + } + })(); + (function checkOnClickCompatibility() { + function ignoreIfTargetDisabled(event) { + if (isDisabled(event.target)) { + event.stopPropagation(); + } + } + + function isDisabled(node) { + return node.disabled || node.parentNode && isDisabled(node.parentNode); + } + + if (isOpera) { + document.addEventListener('click', ignoreIfTargetDisabled, true); + } + })(); + (function checkOnBlobSupport() { + if (isIE || isIOSChrome) { + PDFJS.disableCreateObjectURL = true; + } + })(); + (function checkNavigatorLanguage() { + if (typeof navigator === 'undefined') { + return; + } + if ('language' in navigator) { + return; + } + PDFJS.locale = navigator.userLanguage || 'en-US'; + })(); + (function checkRangeRequests() { + if (isSafari || isAndroidPre3 || isChromeWithRangeBug || isIOS) { + PDFJS.disableRange = true; + PDFJS.disableStream = true; + } + })(); + (function checkHistoryManipulation() { + if (!hasDOM) { + return; + } + if (!history.pushState || isAndroidPre3) { + PDFJS.disableHistory = true; + } + })(); + (function checkSetPresenceInImageData() { + if (!hasDOM) { + return; + } + if (window.CanvasPixelArray) { + if (typeof window.CanvasPixelArray.prototype.set !== 'function') { + window.CanvasPixelArray.prototype.set = function (arr) { + for (var i = 0, ii = this.length; i < ii; i++) { + this[i] = arr[i]; + } + }; + } + } else { + var polyfill = false, + versionMatch; + if (isChrome) { + versionMatch = userAgent.match(/Chrom(e|ium)\/([0-9]+)\./); + polyfill = versionMatch && parseInt(versionMatch[2]) < 21; + } else if (isAndroid) { + polyfill = isAndroidPre5; + } else if (isSafari) { + versionMatch = userAgent.match(/Version\/([0-9]+)\.([0-9]+)\.([0-9]+) Safari\//); + polyfill = versionMatch && parseInt(versionMatch[1]) < 6; + } + if (polyfill) { + var contextPrototype = window.CanvasRenderingContext2D.prototype; + var createImageData = contextPrototype.createImageData; + contextPrototype.createImageData = function (w, h) { + var imageData = createImageData.call(this, w, h); + imageData.data.set = function (arr) { + for (var i = 0, ii = this.length; i < ii; i++) { + this[i] = arr[i]; + } + }; + return imageData; + }; + contextPrototype = null; + } + } + })(); + (function checkRequestAnimationFrame() { + function installFakeAnimationFrameFunctions() { + window.requestAnimationFrame = function (callback) { + return window.setTimeout(callback, 20); + }; + window.cancelAnimationFrame = function (timeoutID) { + window.clearTimeout(timeoutID); + }; + } + + if (!hasDOM) { + return; + } + if (isIOS) { + installFakeAnimationFrameFunctions(); + return; + } + if ('requestAnimationFrame' in window) { + return; + } + window.requestAnimationFrame = window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame; + if (window.requestAnimationFrame) { + return; + } + installFakeAnimationFrameFunctions(); + })(); + (function checkCanvasSizeLimitation() { + if (isIOS || isAndroid) { + PDFJS.maxCanvasPixels = 5242880; + } + })(); + (function checkFullscreenSupport() { + if (!hasDOM) { + return; + } + if (isIE && window.parent !== window) { + PDFJS.disableFullscreen = true; + } + })(); + (function checkCurrentScript() { + if (!hasDOM) { + return; + } + if ('currentScript' in document) { + return; + } + Object.defineProperty(document, 'currentScript', { + get: function get() { + var scripts = document.getElementsByTagName('script'); + return scripts[scripts.length - 1]; + }, + + enumerable: true, + configurable: true + }); + })(); + (function checkInputTypeNumberAssign() { + if (!hasDOM) { + return; + } + var el = document.createElement('input'); + try { + el.type = 'number'; + } catch (ex) { + var inputProto = el.constructor.prototype; + var typeProperty = Object.getOwnPropertyDescriptor(inputProto, 'type'); + Object.defineProperty(inputProto, 'type', { + get: function get() { + return typeProperty.get.call(this); + }, + set: function set(value) { + typeProperty.set.call(this, value === 'number' ? 'text' : value); + }, + + enumerable: true, + configurable: true + }); + } + })(); + (function checkDocumentReadyState() { + if (!hasDOM) { + return; + } + if (!document.attachEvent) { + return; + } + var documentProto = document.constructor.prototype; + var readyStateProto = Object.getOwnPropertyDescriptor(documentProto, 'readyState'); + Object.defineProperty(documentProto, 'readyState', { + get: function get() { + var value = readyStateProto.get.call(this); + return value === 'interactive' ? 'loading' : value; + }, + set: function set(value) { + readyStateProto.set.call(this, value); + }, + + enumerable: true, + configurable: true + }); + })(); + (function checkChildNodeRemove() { + if (!hasDOM) { + return; + } + if (typeof Element.prototype.remove !== 'undefined') { + return; + } + Element.prototype.remove = function () { + if (this.parentNode) { + this.parentNode.removeChild(this); + } + }; + })(); + (function checkNumberIsNaN() { + if (Number.isNaN) { + return; + } + Number.isNaN = function (value) { + return typeof value === 'number' && isNaN(value); + }; + })(); + (function checkNumberIsInteger() { + if (Number.isInteger) { + return; + } + Number.isInteger = function (value) { + return typeof value === 'number' && isFinite(value) && Math.floor(value) === value; + }; + })(); + (function checkPromise() { + if (globalScope.Promise) { + if (typeof globalScope.Promise.all !== 'function') { + globalScope.Promise.all = function (iterable) { + var count = 0, + results = [], + resolve, + reject; + var promise = new globalScope.Promise(function (resolve_, reject_) { + resolve = resolve_; + reject = reject_; + }); + iterable.forEach(function (p, i) { + count++; + p.then(function (result) { + results[i] = result; + count--; + if (count === 0) { + resolve(results); + } + }, reject); + }); + if (count === 0) { + resolve(results); + } + return promise; + }; + } + if (typeof globalScope.Promise.resolve !== 'function') { + globalScope.Promise.resolve = function (value) { + return new globalScope.Promise(function (resolve) { + resolve(value); + }); + }; + } + if (typeof globalScope.Promise.reject !== 'function') { + globalScope.Promise.reject = function (reason) { + return new globalScope.Promise(function (resolve, reject) { + reject(reason); + }); + }; + } + if (typeof globalScope.Promise.prototype.catch !== 'function') { + globalScope.Promise.prototype.catch = function (onReject) { + return globalScope.Promise.prototype.then(undefined, onReject); + }; + } + return; + } + var STATUS_PENDING = 0; + var STATUS_RESOLVED = 1; + var STATUS_REJECTED = 2; + var REJECTION_TIMEOUT = 500; + var HandlerManager = { + handlers: [], + running: false, + unhandledRejections: [], + pendingRejectionCheck: false, + scheduleHandlers: function scheduleHandlers(promise) { + if (promise._status === STATUS_PENDING) { + return; + } + this.handlers = this.handlers.concat(promise._handlers); + promise._handlers = []; + if (this.running) { + return; + } + this.running = true; + setTimeout(this.runHandlers.bind(this), 0); + }, + runHandlers: function runHandlers() { + var RUN_TIMEOUT = 1; + var timeoutAt = Date.now() + RUN_TIMEOUT; + while (this.handlers.length > 0) { + var handler = this.handlers.shift(); + var nextStatus = handler.thisPromise._status; + var nextValue = handler.thisPromise._value; + try { + if (nextStatus === STATUS_RESOLVED) { + if (typeof handler.onResolve === 'function') { + nextValue = handler.onResolve(nextValue); + } + } else if (typeof handler.onReject === 'function') { + nextValue = handler.onReject(nextValue); + nextStatus = STATUS_RESOLVED; + if (handler.thisPromise._unhandledRejection) { + this.removeUnhandeledRejection(handler.thisPromise); + } + } + } catch (ex) { + nextStatus = STATUS_REJECTED; + nextValue = ex; + } + handler.nextPromise._updateStatus(nextStatus, nextValue); + if (Date.now() >= timeoutAt) { + break; + } + } + if (this.handlers.length > 0) { + setTimeout(this.runHandlers.bind(this), 0); + return; + } + this.running = false; + }, + addUnhandledRejection: function addUnhandledRejection(promise) { + this.unhandledRejections.push({ + promise: promise, + time: Date.now() + }); + this.scheduleRejectionCheck(); + }, + removeUnhandeledRejection: function removeUnhandeledRejection(promise) { + promise._unhandledRejection = false; + for (var i = 0; i < this.unhandledRejections.length; i++) { + if (this.unhandledRejections[i].promise === promise) { + this.unhandledRejections.splice(i); + i--; + } + } + }, + scheduleRejectionCheck: function scheduleRejectionCheck() { + var _this = this; + + if (this.pendingRejectionCheck) { + return; + } + this.pendingRejectionCheck = true; + setTimeout(function () { + _this.pendingRejectionCheck = false; + var now = Date.now(); + for (var i = 0; i < _this.unhandledRejections.length; i++) { + if (now - _this.unhandledRejections[i].time > REJECTION_TIMEOUT) { + var unhandled = _this.unhandledRejections[i].promise._value; + var msg = 'Unhandled rejection: ' + unhandled; + if (unhandled.stack) { + msg += '\n' + unhandled.stack; + } + try { + throw new Error(msg); + } catch (_) { + console.warn(msg); + } + _this.unhandledRejections.splice(i); + i--; + } + } + if (_this.unhandledRejections.length) { + _this.scheduleRejectionCheck(); + } + }, REJECTION_TIMEOUT); + } + }; + var Promise = function Promise(resolver) { + this._status = STATUS_PENDING; + this._handlers = []; + try { + resolver.call(this, this._resolve.bind(this), this._reject.bind(this)); + } catch (e) { + this._reject(e); + } + }; + Promise.all = function Promise_all(promises) { + var resolveAll, rejectAll; + var deferred = new Promise(function (resolve, reject) { + resolveAll = resolve; + rejectAll = reject; + }); + var unresolved = promises.length; + var results = []; + if (unresolved === 0) { + resolveAll(results); + return deferred; + } + + function reject(reason) { + if (deferred._status === STATUS_REJECTED) { + return; + } + results = []; + rejectAll(reason); + } + + for (var i = 0, ii = promises.length; i < ii; ++i) { + var promise = promises[i]; + var resolve = function (i) { + return function (value) { + if (deferred._status === STATUS_REJECTED) { + return; + } + results[i] = value; + unresolved--; + if (unresolved === 0) { + resolveAll(results); + } + }; + }(i); + if (Promise.isPromise(promise)) { + promise.then(resolve, reject); + } else { + resolve(promise); + } + } + return deferred; + }; + Promise.isPromise = function Promise_isPromise(value) { + return value && typeof value.then === 'function'; + }; + Promise.resolve = function Promise_resolve(value) { + return new Promise(function (resolve) { + resolve(value); + }); + }; + Promise.reject = function Promise_reject(reason) { + return new Promise(function (resolve, reject) { + reject(reason); + }); + }; + Promise.prototype = { + _status: null, + _value: null, + _handlers: null, + _unhandledRejection: null, + _updateStatus: function Promise__updateStatus(status, value) { + if (this._status === STATUS_RESOLVED || this._status === STATUS_REJECTED) { + return; + } + if (status === STATUS_RESOLVED && Promise.isPromise(value)) { + value.then(this._updateStatus.bind(this, STATUS_RESOLVED), this._updateStatus.bind(this, STATUS_REJECTED)); + return; + } + this._status = status; + this._value = value; + if (status === STATUS_REJECTED && this._handlers.length === 0) { + this._unhandledRejection = true; + HandlerManager.addUnhandledRejection(this); + } + HandlerManager.scheduleHandlers(this); + }, + _resolve: function Promise_resolve(value) { + this._updateStatus(STATUS_RESOLVED, value); + }, + _reject: function Promise_reject(reason) { + this._updateStatus(STATUS_REJECTED, reason); + }, + then: function Promise_then(onResolve, onReject) { + var nextPromise = new Promise(function (resolve, reject) { + this.resolve = resolve; + this.reject = reject; + }); + this._handlers.push({ + thisPromise: this, + onResolve: onResolve, + onReject: onReject, + nextPromise: nextPromise + }); + HandlerManager.scheduleHandlers(this); + return nextPromise; + }, + catch: function Promise_catch(onReject) { + return this.then(undefined, onReject); + } + }; + globalScope.Promise = Promise; + })(); + (function checkWeakMap() { + if (globalScope.WeakMap) { + return; + } + var id = 0; + + function WeakMap() { + this.id = '$weakmap' + id++; + } + + WeakMap.prototype = { + has: function has(obj) { + if ((typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) !== 'object' && typeof obj !== 'function' || obj === null) { + return false; + } + return !!Object.getOwnPropertyDescriptor(obj, this.id); + }, + get: function get(obj) { + return this.has(obj) ? obj[this.id] : undefined; + }, + set: function set(obj, value) { + Object.defineProperty(obj, this.id, { + value: value, + enumerable: false, + configurable: true + }); + }, + delete: function _delete(obj) { + delete obj[this.id]; + } + }; + globalScope.WeakMap = WeakMap; + })(); + (function checkURLConstructor() { + var hasWorkingUrl = false; + try { + if (typeof URL === 'function' && _typeof(URL.prototype) === 'object' && 'origin' in URL.prototype) { + var u = new URL('b', 'http://a'); + u.pathname = 'c%20d'; + hasWorkingUrl = u.href === 'http://a/c%20d'; + } + } catch (e) { + } + if (hasWorkingUrl) { + return; + } + var relative = Object.create(null); + relative['ftp'] = 21; + relative['file'] = 0; + relative['gopher'] = 70; + relative['http'] = 80; + relative['https'] = 443; + relative['ws'] = 80; + relative['wss'] = 443; + var relativePathDotMapping = Object.create(null); + relativePathDotMapping['%2e'] = '.'; + relativePathDotMapping['.%2e'] = '..'; + relativePathDotMapping['%2e.'] = '..'; + relativePathDotMapping['%2e%2e'] = '..'; + + function isRelativeScheme(scheme) { + return relative[scheme] !== undefined; + } + + function invalid() { + clear.call(this); + this._isInvalid = true; + } + + function IDNAToASCII(h) { + if (h === '') { + invalid.call(this); + } + return h.toLowerCase(); + } + + function percentEscape(c) { + var unicode = c.charCodeAt(0); + if (unicode > 0x20 && unicode < 0x7F && [0x22, 0x23, 0x3C, 0x3E, 0x3F, 0x60].indexOf(unicode) === -1) { + return c; + } + return encodeURIComponent(c); + } + + function percentEscapeQuery(c) { + var unicode = c.charCodeAt(0); + if (unicode > 0x20 && unicode < 0x7F && [0x22, 0x23, 0x3C, 0x3E, 0x60].indexOf(unicode) === -1) { + return c; + } + return encodeURIComponent(c); + } + + var EOF, + ALPHA = /[a-zA-Z]/, + ALPHANUMERIC = /[a-zA-Z0-9\+\-\.]/; + + function parse(input, stateOverride, base) { + function err(message) { + errors.push(message); + } + + var state = stateOverride || 'scheme start', + cursor = 0, + buffer = '', + seenAt = false, + seenBracket = false, + errors = []; + loop: while ((input[cursor - 1] !== EOF || cursor === 0) && !this._isInvalid) { + var c = input[cursor]; + switch (state) { + case 'scheme start': + if (c && ALPHA.test(c)) { + buffer += c.toLowerCase(); + state = 'scheme'; + } else if (!stateOverride) { + buffer = ''; + state = 'no scheme'; + continue; + } else { + err('Invalid scheme.'); + break loop; + } + break; + case 'scheme': + if (c && ALPHANUMERIC.test(c)) { + buffer += c.toLowerCase(); + } else if (c === ':') { + this._scheme = buffer; + buffer = ''; + if (stateOverride) { + break loop; + } + if (isRelativeScheme(this._scheme)) { + this._isRelative = true; + } + if (this._scheme === 'file') { + state = 'relative'; + } else if (this._isRelative && base && base._scheme === this._scheme) { + state = 'relative or authority'; + } else if (this._isRelative) { + state = 'authority first slash'; + } else { + state = 'scheme data'; + } + } else if (!stateOverride) { + buffer = ''; + cursor = 0; + state = 'no scheme'; + continue; + } else if (c === EOF) { + break loop; + } else { + err('Code point not allowed in scheme: ' + c); + break loop; + } + break; + case 'scheme data': + if (c === '?') { + this._query = '?'; + state = 'query'; + } else if (c === '#') { + this._fragment = '#'; + state = 'fragment'; + } else { + if (c !== EOF && c !== '\t' && c !== '\n' && c !== '\r') { + this._schemeData += percentEscape(c); + } + } + break; + case 'no scheme': + if (!base || !isRelativeScheme(base._scheme)) { + err('Missing scheme.'); + invalid.call(this); + } else { + state = 'relative'; + continue; + } + break; + case 'relative or authority': + if (c === '/' && input[cursor + 1] === '/') { + state = 'authority ignore slashes'; + } else { + err('Expected /, got: ' + c); + state = 'relative'; + continue; + } + break; + case 'relative': + this._isRelative = true; + if (this._scheme !== 'file') { + this._scheme = base._scheme; + } + if (c === EOF) { + this._host = base._host; + this._port = base._port; + this._path = base._path.slice(); + this._query = base._query; + this._username = base._username; + this._password = base._password; + break loop; + } else if (c === '/' || c === '\\') { + if (c === '\\') { + err('\\ is an invalid code point.'); + } + state = 'relative slash'; + } else if (c === '?') { + this._host = base._host; + this._port = base._port; + this._path = base._path.slice(); + this._query = '?'; + this._username = base._username; + this._password = base._password; + state = 'query'; + } else if (c === '#') { + this._host = base._host; + this._port = base._port; + this._path = base._path.slice(); + this._query = base._query; + this._fragment = '#'; + this._username = base._username; + this._password = base._password; + state = 'fragment'; + } else { + var nextC = input[cursor + 1]; + var nextNextC = input[cursor + 2]; + if (this._scheme !== 'file' || !ALPHA.test(c) || nextC !== ':' && nextC !== '|' || nextNextC !== EOF && nextNextC !== '/' && nextNextC !== '\\' && nextNextC !== '?' && nextNextC !== '#') { + this._host = base._host; + this._port = base._port; + this._username = base._username; + this._password = base._password; + this._path = base._path.slice(); + this._path.pop(); + } + state = 'relative path'; + continue; + } + break; + case 'relative slash': + if (c === '/' || c === '\\') { + if (c === '\\') { + err('\\ is an invalid code point.'); + } + if (this._scheme === 'file') { + state = 'file host'; + } else { + state = 'authority ignore slashes'; + } + } else { + if (this._scheme !== 'file') { + this._host = base._host; + this._port = base._port; + this._username = base._username; + this._password = base._password; + } + state = 'relative path'; + continue; + } + break; + case 'authority first slash': + if (c === '/') { + state = 'authority second slash'; + } else { + err('Expected \'/\', got: ' + c); + state = 'authority ignore slashes'; + continue; + } + break; + case 'authority second slash': + state = 'authority ignore slashes'; + if (c !== '/') { + err('Expected \'/\', got: ' + c); + continue; + } + break; + case 'authority ignore slashes': + if (c !== '/' && c !== '\\') { + state = 'authority'; + continue; + } else { + err('Expected authority, got: ' + c); + } + break; + case 'authority': + if (c === '@') { + if (seenAt) { + err('@ already seen.'); + buffer += '%40'; + } + seenAt = true; + for (var i = 0; i < buffer.length; i++) { + var cp = buffer[i]; + if (cp === '\t' || cp === '\n' || cp === '\r') { + err('Invalid whitespace in authority.'); + continue; + } + if (cp === ':' && this._password === null) { + this._password = ''; + continue; + } + var tempC = percentEscape(cp); + if (this._password !== null) { + this._password += tempC; + } else { + this._username += tempC; + } + } + buffer = ''; + } else if (c === EOF || c === '/' || c === '\\' || c === '?' || c === '#') { + cursor -= buffer.length; + buffer = ''; + state = 'host'; + continue; + } else { + buffer += c; + } + break; + case 'file host': + if (c === EOF || c === '/' || c === '\\' || c === '?' || c === '#') { + if (buffer.length === 2 && ALPHA.test(buffer[0]) && (buffer[1] === ':' || buffer[1] === '|')) { + state = 'relative path'; + } else if (buffer.length === 0) { + state = 'relative path start'; + } else { + this._host = IDNAToASCII.call(this, buffer); + buffer = ''; + state = 'relative path start'; + } + continue; + } else if (c === '\t' || c === '\n' || c === '\r') { + err('Invalid whitespace in file host.'); + } else { + buffer += c; + } + break; + case 'host': + case 'hostname': + if (c === ':' && !seenBracket) { + this._host = IDNAToASCII.call(this, buffer); + buffer = ''; + state = 'port'; + if (stateOverride === 'hostname') { + break loop; + } + } else if (c === EOF || c === '/' || c === '\\' || c === '?' || c === '#') { + this._host = IDNAToASCII.call(this, buffer); + buffer = ''; + state = 'relative path start'; + if (stateOverride) { + break loop; + } + continue; + } else if (c !== '\t' && c !== '\n' && c !== '\r') { + if (c === '[') { + seenBracket = true; + } else if (c === ']') { + seenBracket = false; + } + buffer += c; + } else { + err('Invalid code point in host/hostname: ' + c); + } + break; + case 'port': + if (/[0-9]/.test(c)) { + buffer += c; + } else if (c === EOF || c === '/' || c === '\\' || c === '?' || c === '#' || stateOverride) { + if (buffer !== '') { + var temp = parseInt(buffer, 10); + if (temp !== relative[this._scheme]) { + this._port = temp + ''; + } + buffer = ''; + } + if (stateOverride) { + break loop; + } + state = 'relative path start'; + continue; + } else if (c === '\t' || c === '\n' || c === '\r') { + err('Invalid code point in port: ' + c); + } else { + invalid.call(this); + } + break; + case 'relative path start': + if (c === '\\') { + err('\'\\\' not allowed in path.'); + } + state = 'relative path'; + if (c !== '/' && c !== '\\') { + continue; + } + break; + case 'relative path': + if (c === EOF || c === '/' || c === '\\' || !stateOverride && (c === '?' || c === '#')) { + if (c === '\\') { + err('\\ not allowed in relative path.'); + } + var tmp; + if (tmp = relativePathDotMapping[buffer.toLowerCase()]) { + buffer = tmp; + } + if (buffer === '..') { + this._path.pop(); + if (c !== '/' && c !== '\\') { + this._path.push(''); + } + } else if (buffer === '.' && c !== '/' && c !== '\\') { + this._path.push(''); + } else if (buffer !== '.') { + if (this._scheme === 'file' && this._path.length === 0 && buffer.length === 2 && ALPHA.test(buffer[0]) && buffer[1] === '|') { + buffer = buffer[0] + ':'; + } + this._path.push(buffer); + } + buffer = ''; + if (c === '?') { + this._query = '?'; + state = 'query'; + } else if (c === '#') { + this._fragment = '#'; + state = 'fragment'; + } + } else if (c !== '\t' && c !== '\n' && c !== '\r') { + buffer += percentEscape(c); + } + break; + case 'query': + if (!stateOverride && c === '#') { + this._fragment = '#'; + state = 'fragment'; + } else if (c !== EOF && c !== '\t' && c !== '\n' && c !== '\r') { + this._query += percentEscapeQuery(c); + } + break; + case 'fragment': + if (c !== EOF && c !== '\t' && c !== '\n' && c !== '\r') { + this._fragment += c; + } + break; + } + cursor++; + } + } + + function clear() { + this._scheme = ''; + this._schemeData = ''; + this._username = ''; + this._password = null; + this._host = ''; + this._port = ''; + this._path = []; + this._query = ''; + this._fragment = ''; + this._isInvalid = false; + this._isRelative = false; + } + + function JURL(url, base) { + if (base !== undefined && !(base instanceof JURL)) { + base = new JURL(String(base)); + } + this._url = url; + clear.call(this); + var input = url.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g, ''); + parse.call(this, input, null, base); + } + + JURL.prototype = { + toString: function toString() { + return this.href; + }, + + get href() { + if (this._isInvalid) { + return this._url; + } + var authority = ''; + if (this._username !== '' || this._password !== null) { + authority = this._username + (this._password !== null ? ':' + this._password : '') + '@'; + } + return this.protocol + (this._isRelative ? '//' + authority + this.host : '') + this.pathname + this._query + this._fragment; + }, + set href(value) { + clear.call(this); + parse.call(this, value); + }, + get protocol() { + return this._scheme + ':'; + }, + set protocol(value) { + if (this._isInvalid) { + return; + } + parse.call(this, value + ':', 'scheme start'); + }, + get host() { + return this._isInvalid ? '' : this._port ? this._host + ':' + this._port : this._host; + }, + set host(value) { + if (this._isInvalid || !this._isRelative) { + return; + } + parse.call(this, value, 'host'); + }, + get hostname() { + return this._host; + }, + set hostname(value) { + if (this._isInvalid || !this._isRelative) { + return; + } + parse.call(this, value, 'hostname'); + }, + get port() { + return this._port; + }, + set port(value) { + if (this._isInvalid || !this._isRelative) { + return; + } + parse.call(this, value, 'port'); + }, + get pathname() { + return this._isInvalid ? '' : this._isRelative ? '/' + this._path.join('/') : this._schemeData; + }, + set pathname(value) { + if (this._isInvalid || !this._isRelative) { + return; + } + this._path = []; + parse.call(this, value, 'relative path start'); + }, + get search() { + return this._isInvalid || !this._query || this._query === '?' ? '' : this._query; + }, + set search(value) { + if (this._isInvalid || !this._isRelative) { + return; + } + this._query = '?'; + if (value[0] === '?') { + value = value.slice(1); + } + parse.call(this, value, 'query'); + }, + get hash() { + return this._isInvalid || !this._fragment || this._fragment === '#' ? '' : this._fragment; + }, + set hash(value) { + if (this._isInvalid) { + return; + } + this._fragment = '#'; + if (value[0] === '#') { + value = value.slice(1); + } + parse.call(this, value, 'fragment'); + }, + get origin() { + var host; + if (this._isInvalid || !this._scheme) { + return ''; + } + switch (this._scheme) { + case 'data': + case 'file': + case 'javascript': + case 'mailto': + return 'null'; + case 'blob': + try { + return new JURL(this._schemeData).origin || 'null'; + } catch (_) { + } + return 'null'; + } + host = this.host; + if (!host) { + return ''; + } + return this._scheme + '://' + host; + } + }; + var OriginalURL = globalScope.URL; + if (OriginalURL) { + JURL.createObjectURL = function (blob) { + return OriginalURL.createObjectURL.apply(OriginalURL, arguments); + }; + JURL.revokeObjectURL = function (url) { + OriginalURL.revokeObjectURL(url); + }; + } + globalScope.URL = JURL; + })(); + } + + /***/ + }), + /* 17 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + var isReadableStreamSupported = false; + if (typeof ReadableStream !== 'undefined') { + try { + new ReadableStream({ + start: function start(controller) { + controller.close(); + } + }); + isReadableStreamSupported = true; + } catch (e) { + } + } + if (isReadableStreamSupported) { + exports.ReadableStream = ReadableStream; + } else { + exports.ReadableStream = __w_pdfjs_require__(10).ReadableStream; + } + + /***/ + }) + /******/]); +}); +//# sourceMappingURL=pdf.js.map diff --git a/twake/frontend/public/public/viewer/PDFViewer/pdf.js.map b/twake/frontend/public/public/viewer/PDFViewer/pdf.js.map new file mode 100755 index 00000000..8bc23204 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/pdf.js.map @@ -0,0 +1,51 @@ +{ + "version": 3, + "sources": [ + "webpack:///webpack/universalModuleDefinition", + "webpack:///webpack/bootstrap b5fe8ab6eb949fc98816", + "webpack:///src/shared/util.js", + "webpack:///src/display/dom_utils.js", + "webpack:///src/display/api.js", + "webpack:///src/display/annotation_layer.js", + "webpack:///src/display/svg.js", + "webpack:///src/display/text_layer.js", + "webpack:///src/display/metadata.js", + "webpack:///src/display/webgl.js", + "webpack:///src/display/global.js", + "webpack:///src/display/network.js", + "webpack:///external/streams/streams-lib.js", + "webpack:///src/display/canvas.js", + "webpack:///src/display/font_loader.js", + "webpack:///src/display/pattern_helper.js", + "webpack:///src/display/transport_stream.js", + "webpack:///src/pdf.js", + "webpack:///src/shared/compatibility.js", + "webpack:///src/shared/streams_polyfill.js" + ], + "names": [], + "mappings": ";;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,O;ACVA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA,mDAA2C,cAAc;;AAEzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;;;;;;;;;;ACjDO;;AACwB;;AAE/B,IAAI,cACD,OAAO,WAAW,eAAe,OAAO,SAAS,OAAQ,SAEzD,OAAO,WAAW,eAAe,OAAO,SAAS,OAAQ,SACzD,OAAO,SAAS,eAAe,KAAK,SAAS,OAAe;AAE/D,IAAI,uBAAuB,CAAC,OAAO,GAAG,GAAG,OAAO,GAAG;AAEnD,IAAM;AACJ,QAAM;AACN,UAAQ;AACR,WAAS;AAHiB;AAM5B,IAAI;AACF,QAAM;AACN,UAAQ;AACR,eAAa;AACb,aAAW;AACX,oBAAkB;AAClB,sBAAoB;AACpB,2BAAyB;AACzB,eAAa;AACb,oBAAkB;AAClB,oBAAkB;AAVI;AAaxB,IAAI;AACF,kBAAgB;AAChB,aAAW;AACX,cAAY;AAHE;AAMhB,IAAI;AACF,QAAM;AACN,QAAM;AACN,YAAU;AACV,QAAM;AACN,UAAQ;AACR,UAAQ;AACR,WAAS;AACT,YAAU;AACV,aAAW;AACX,aAAW;AACX,YAAU;AACV,aAAW;AACX,SAAO;AACP,SAAO;AACP,OAAK;AACL,SAAO;AACP,kBAAgB;AAChB,SAAO;AACP,SAAO;AACP,UAAQ;AACR,UAAQ;AACR,eAAa;AACb,WAAS;AACT,aAAW;AACX,UAAQ;AACR,UAAQ;AA1BW;AA6BrB,IAAI;AACF,aAAW;AACX,UAAQ;AACR,SAAO;AACP,UAAQ;AACR,YAAU;AACV,UAAQ;AACR,YAAU;AACV,UAAQ;AACR,gBAAc;AACd,kBAAgB;AAVG;AAarB,IAAI;AACF,YAAU;AACV,YAAU;AACV,YAAU;AACV,aAAW;AACX,YAAU;AACV,iBAAe;AACf,SAAO;AACP,cAAY;AACZ,SAAO;AACP,QAAM;AACN,QAAM;AACN,cAAY;AACZ,eAAa;AACb,mBAAiB;AACjB,eAAa;AACb,QAAM;AACN,YAAU;AACV,kBAAgB;AAChB,qBAAmB;AAnBK;AAsB1B,IAAI;AACF,SAAO;AACP,UAAQ;AACR,WAAS;AACT,SAAO;AACP,aAAW;AALmB;AAQhC,IAAI;AACF,WAAS;AACT,SAAO;AACP,OAAK;AACL,OAAK;AACL,OAAK;AACL,QAAM;AACN,OAAK;AACL,OAAK;AACL,OAAK;AACL,MAAI;AAVW;AAajB,IAAI;AACF,WAAS;AACT,SAAO;AACP,UAAQ;AACR,gBAAc;AACd,iBAAe;AACf,YAAU;AACV,gBAAc;AACd,SAAO;AACP,YAAU;AACV,SAAO;AACP,WAAS;AAXI;AAcf,IAAI;AACF,UAAQ;AACR,YAAU;AACV,SAAO;AAHc;AAMvB,IAAI;AACF,QAAM;AACN,UAAQ;AACR,UAAQ;AAHgB;AAO1B,IAAI;AAGF,cAAY;AACZ,gBAAc;AACd,cAAY;AACZ,eAAa;AACb,iBAAe;AACf,WAAS;AACT,sBAAoB;AACpB,eAAa;AACb,aAAW;AACX,QAAM;AACN,WAAS;AACT,aAAW;AACX,UAAQ;AACR,UAAQ;AACR,WAAS;AACT,YAAU;AACV,YAAU;AACV,aAAW;AACX,aAAW;AACX,UAAQ;AACR,eAAa;AACb,QAAM;AACN,UAAQ;AACR,cAAY;AACZ,gBAAc;AACd,mBAAiB;AACjB,qBAAmB;AACnB,WAAS;AACT,QAAM;AACN,UAAQ;AACR,aAAW;AACX,WAAS;AACT,kBAAgB;AAChB,kBAAgB;AAChB,aAAW;AACX,cAAY;AACZ,WAAS;AACT,wBAAsB;AACtB,eAAa;AACb,YAAU;AACV,sBAAoB;AACpB,iBAAe;AACf,YAAU;AACV,YAAU;AACV,kBAAgB;AAChB,oBAAkB;AAClB,8BAA4B;AAC5B,gBAAc;AACd,yBAAuB;AACvB,uBAAqB;AACrB,qBAAmB;AACnB,kBAAgB;AAChB,mBAAiB;AACjB,gBAAc;AACd,iBAAe;AACf,iBAAe;AACf,eAAa;AACb,qBAAmB;AACnB,mBAAiB;AACjB,sBAAoB;AACpB,oBAAkB;AAClB,eAAa;AACb,oBAAkB;AAClB,kBAAgB;AAChB,kBAAgB;AAChB,gBAAc;AACd,aAAW;AACX,kBAAgB;AAChB,sBAAoB;AACpB,2BAAyB;AACzB,oBAAkB;AAClB,eAAa;AACb,aAAW;AACX,yBAAuB;AACvB,uBAAqB;AACrB,cAAY;AACZ,YAAU;AACV,oBAAkB;AAClB,kBAAgB;AAChB,mBAAiB;AACjB,iBAAe;AACf,oBAAkB;AAClB,yBAAuB;AACvB,8BAA4B;AAC5B,qBAAmB;AACnB,2BAAyB;AACzB,gCAA8B;AAC9B,2BAAyB;AACzB,+BAA6B;AAC7B,4BAA0B;AAC1B,iBAAe;AA7FP;AAgGV,IAAI,YAAY,iBAAiB;AAEjC,SAAS,kBAAkB,OAAO;AAChC,cAAY;AAtQd;AAyQA,SAAS,oBAAoB;AAC3B,SAAO;AA1QT;AAgRA,SAAS,KAAK,KAAK;AACjB,MAAI,aAAa,iBAAiB,OAAO;AACvC,YAAQ,IAAI,WAAW;AAFR;AAhRnB;AAuRA,SAAS,KAAK,KAAK;AACjB,MAAI,aAAa,iBAAiB,UAAU;AAC1C,YAAQ,IAAI,cAAc;AAFX;AAvRnB;AA8RA,SAAS,WAAW,SAAS;AAC3B,UAAQ,IAAI,2BAA2B;AA/RzC;AAkSA,SAAS,YAAY,KAAK;AACxB,QAAM,IAAI,MAAM;AAnSlB;AAsSA,SAAS,OAAO,MAAM,KAAK;AACzB,MAAI,CAAC,MAAM;AACT,gBAAY;AAFW;AAtS3B;AA4SA,IAAI;AACF,WAAS;AACT,SAAO;AACP,cAAY;AACZ,SAAO;AACP,kBAAgB;AAChB,QAAM;AANmB;AAU3B,SAAS,aAAa,SAAS,UAAU;AACvC,MAAI;AACF,QAAI,OAAO,IAAI,IAAI;AACnB,QAAI,CAAC,KAAK,UAAU,KAAK,WAAW,QAAQ;AAC1C,aAAO;AAHP;AAAJ,IAKE,OAAO,GAAG;AACV,WAAO;AAP8B;AAUvC,MAAI,QAAQ,IAAI,IAAI,UAAU;AAC9B,SAAO,KAAK,WAAW,MAAM;AAjU/B;AAqUA,SAAS,gBAAgB,KAAK;AAC5B,MAAI,CAAC,KAAK;AACR,WAAO;AAFmB;AAI5B,UAAQ,IAAI;AACV,SAAK;AACL,SAAK;AACL,SAAK;AACL,SAAK;AACL,SAAK;AACH,aAAO;AACT;AACE,aAAO;;AAjVb;AA2VA,SAAS,uBAAuB,KAAK,SAAS;AAC5C,MAAI,CAAC,KAAK;AACR,WAAO;AAFmC;AAI5C,MAAI;AACF,QAAI,cAAc,UAAU,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI;AAC5D,QAAI,gBAAgB,cAAc;AAChC,aAAO;AAHP;AAAJ,IAKE,OAAO,IAAI,CAT+B;AAU5C,SAAO;AArWT;AAwWA,SAAS,OAAO,KAAK,MAAM,OAAO;AAChC,SAAO,eAAe,KAAK;AAAQ;AACA,gBAAY;AACZ,kBAAc;AACd,cAAU;AAHZ;AAIjC,SAAO;AA7WT;AAgXA,SAAS,sBAAsB,aAAa;AAC1C,MAAI;AACJ,SAAO,YAAY;AACjB,QAAI,aAAa;AACf,eAAS,OAAO,OAAO;AACvB,kBAAY;AACZ,oBAAc;AAJC;AAMjB,WAAO;AANT;AAlXF;AA4XA,IAAI;AACF,iBAAe;AACf,sBAAoB;AAFE;AAKxB,IAAI,6BAA8B,2BAA2B;AAC3D,WAAS,kBAAkB,KAAK,MAAM;AACpC,SAAK,OAAO;AACZ,SAAK,UAAU;AACf,SAAK,OAAO;AAJ6C;AAO3D,oBAAkB,YAAY,IAAI;AAClC,oBAAkB,cAAc;AAEhC,SAAO;AAVe,CAAC;AAazB,IAAI,iCAAkC,+BAA+B;AACnE,WAAS,sBAAsB,KAAK,SAAS;AAC3C,SAAK,OAAO;AACZ,SAAK,UAAU;AACf,SAAK,UAAU;AAJkD;AAOnE,wBAAsB,YAAY,IAAI;AACtC,wBAAsB,cAAc;AAEpC,SAAO;AAVmB,CAAC;AAa7B,IAAI,+BAAgC,6BAA6B;AAC/D,WAAS,oBAAoB,KAAK;AAChC,SAAK,OAAO;AACZ,SAAK,UAAU;AAH8C;AAM/D,sBAAoB,YAAY,IAAI;AACpC,sBAAoB,cAAc;AAElC,SAAO;AATiB,CAAC;AAY3B,IAAI,+BAAgC,6BAA6B;AAC/D,WAAS,oBAAoB,KAAK;AAChC,SAAK,OAAO;AACZ,SAAK,UAAU;AAH8C;AAM/D,sBAAoB,YAAY,IAAI;AACpC,sBAAoB,cAAc;AAElC,SAAO;AATiB,CAAC;AAY3B,IAAI,uCACU,qCAAqC;AACjD,WAAS,4BAA4B,KAAK,QAAQ;AAChD,SAAK,OAAO;AACZ,SAAK,UAAU;AACf,SAAK,SAAS;AAJiC;AAOjD,8BAA4B,YAAY,IAAI;AAC5C,8BAA4B,cAAc;AAE1C,SAAO;AAVL,CAAC;AAaL,IAAI,mCAAoC,iCAAiC;AACvE,WAAS,wBAAwB,KAAK;AACpC,SAAK,UAAU;AAFsD;AAKvE,0BAAwB,YAAY,IAAI;AACxC,0BAAwB,UAAU,OAAO;AACzC,0BAAwB,cAAc;AAEtC,SAAO;AATqB,CAAC;AAY/B,IAAI,gCAAiC,8BAA8B;AACjE,WAAS,qBAAqB,OAAO,KAAK;AACxC,SAAK,QAAQ;AACb,SAAK,MAAM;AACX,SAAK,UAAU,mBAAmB,QAAQ,OAAO,MAAM;AAJQ;AAOjE,uBAAqB,YAAY,IAAI;AACrC,uBAAqB,UAAU,OAAO;AACtC,uBAAqB,cAAc;AAEnC,SAAO;AAXkB,CAAC;AAc5B,IAAI,8BAA+B,4BAA4B;AAC7D,WAAS,mBAAmB,KAAK;AAC/B,SAAK,UAAU;AAF4C;AAK7D,qBAAmB,YAAY,IAAI;AACnC,qBAAmB,UAAU,OAAO;AACpC,qBAAmB,cAAc;AAEjC,SAAO;AATgB,CAAC;AAe1B,IAAI,uBAAwB,qBAAqB;AAC/C,WAAS,YAAY,KAAK;AACxB,SAAK,UAAU;AAF8B;AAK/C,cAAY,YAAY,IAAI;AAC5B,cAAY,UAAU,OAAO;AAC7B,cAAY,cAAc;AAE1B,SAAO;AATS,CAAC;AAenB,IAAI,0BAA2B,wBAAwB;AACrD,WAAS,eAAe,KAAK;AAC3B,SAAK,OAAO;AACZ,SAAK,UAAU;AAHoC;AAMrD,iBAAe,YAAY,IAAI;AAC/B,iBAAe,cAAc;AAE7B,SAAO;AATY,CAAC;AAYtB,IAAI,uBAAuB;AAE3B,SAAS,qBAAqB,KAAK;AACjC,MAAI,OAAO,QAAQ,UAAU;AAC3B,SAAK;AACL,WAAO;AAHwB;AAKjC,SAAO,IAAI,QAAQ,sBAAsB;AA5gB3C;AA+gBA,SAAS,cAAc,OAAO;AAC5B,SAAO,UAAU,QAAQ,QAAO,0DAAU,YACnC,MAAM,WAAW,WAAW;AACnC,MAAI,SAAS,MAAM;AACnB,MAAI,qBAAqB;AACzB,MAAI,SAAS,oBAAoB;AAC/B,WAAO,OAAO,aAAa,MAAM,MAAM;AANb;AAQ5B,MAAI,SAAS;AACb,OAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK,oBAAoB;AACnD,QAAI,WAAW,KAAK,IAAI,IAAI,oBAAoB;AAChD,QAAI,QAAQ,MAAM,SAAS,GAAG;AAC9B,WAAO,KAAK,OAAO,aAAa,MAAM,MAAM;AAZlB;AAc5B,SAAO,OAAO,KAAK;AA7hBrB;AAgiBA,SAAS,cAAc,KAAK;AAC1B,SAAO,OAAO,QAAQ,UAAU;AAChC,MAAI,SAAS,IAAI;AACjB,MAAI,QAAQ,IAAI,WAAW;AAC3B,OAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,EAAE,GAAG;AAC/B,UAAM,KAAK,IAAI,WAAW,KAAK;AALP;AAO1B,SAAO;AAviBT;AA+iBA,SAAS,gBAAgB,KAAK;AAC5B,MAAI,IAAI,WAAW,WAAW;AAC5B,WAAO,IAAI;AAFe;AAI5B,SAAO,IAAI,eAAe;AAC1B,SAAO,IAAI;AApjBb;AA4jBA,SAAS,cAAc,KAAK;AAE1B,MAAI,IAAI,WAAW,KAAM,IAAI,cAAc,YAAa;AACtD,WAAO,IAAI;AAHa;AAK1B,MAAI,eAAe;AACnB,MAAI;MAAG,KAAK,IAAI;AAChB,MAAI,MAAM;AACV,OAAK,IAAI,GAAG,IAAI,IAAI,KAAK;AACvB,WAAO,IAAI;AACX,iBAAa,gBAAgB;AAC7B,oBAAgB;AAXQ;AAa1B,MAAI,MAAM;AACV,MAAI,OAAO,IAAI,WAAW;AAC1B,OAAK,IAAI,GAAG,IAAI,IAAI,KAAK;AACvB,WAAO,IAAI;AACX,QAAM,kBAAgB,aAAa;AACjC,UAAI,OAAO,SAAS,UAAU;AAC5B,eAAO,cAAc;AADvB,aAEO;AACL,eAAO,IAAI,WAAW;AAJS;AAFZ;AASvB,iBAAa,KAAK;AAClB,SAAK,IAAI,MAAM;AACf,WAAO;AA1BiB;AA4B1B,SAAO;AAxlBT;AA2lBA,SAAS,SAAS,OAAO;AACvB,SAAO,OAAO,aAAc,SAAS,KAAM,MAAO,SAAS,KAAM,MACrC,SAAS,IAAK,MAAM,QAAQ;AA7lB1D;AAgmBA,SAAS,KAAK,GAAG;AACf,MAAI,IAAI;MAAG,IAAI;AACf,SAAO,IAAI,GAAG;AACZ,UAAM;AACN;AAJa;AAMf,SAAO;AAtmBT;AAymBA,SAAS,SAAS,MAAM,OAAO;AAC7B,SAAQ,KAAK,UAAU,MAAO;AA1mBhC;AA6mBA,SAAS,WAAW,MAAM,QAAQ;AAChC,SAAQ,KAAK,WAAW,IAAK,KAAK,SAAS;AA9mB7C;AAinBA,SAAS,WAAW,MAAM,QAAQ;AAChC,SAAQ,CAAC,KAAK,WAAW,KAAO,KAAK,SAAS,MAAM,KAC5C,KAAK,SAAS,MAAM,IAAK,KAAK,SAAS,QAAQ;AAnnBzD;AAwnBA,SAAS,iBAAiB;AACxB,MAAI,UAAU,IAAI,WAAW;AAC7B,UAAQ,KAAK;AACb,MAAI,SAAS,IAAI,YAAY,QAAQ,QAAQ,GAAG;AAChD,SAAQ,OAAO,OAAO;AA5nBxB;AAgoBA,SAAS,kBAAkB;AACzB,MAAI;AACF,QAAI,SAAS;AACb,WAAO;AAFT,IAGE,OAAO,GAAG;AACV,WAAO;AALgB;AAhoB3B;AAyoBA,IAAI,kBAAkB,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG;AAEtC,IAAI,gBAAiB,cAAc;AACjC,WAAS,OAAO,CADiB;AAGjC,MAAI,SAAS,CAAC,QAAQ,GAAG,KAAK,GAAG,KAAK,GAAG;AAIzC,OAAK,aAAa,SAAS,gBAAgB,GAAG,GAAG,GAAG;AAClD,WAAO,KAAK;AACZ,WAAO,KAAK;AACZ,WAAO,KAAK;AACZ,WAAO,OAAO,KAAK;AAJrB;AAQA,OAAK,YAAY,SAAS,eAAe,IAAI,IAAI;AAC/C,WAAO,CACL,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,IAC3B,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,IAC3B,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,IAC3B,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,IAC3B,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,IACnC,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG;AAPvC;AAYA,OAAK,iBAAiB,SAAS,oBAAoB,GAAG,GAAG;AACvD,QAAI,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;AACvC,QAAI,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;AACvC,WAAO,CAAC,IAAI;AAHd;AAMA,OAAK,wBAAwB,SAAS,2BAA2B,GAAG,GAAG;AACrE,QAAI,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;AAC/B,QAAI,KAAM,GAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM;AACnE,QAAI,KAAM,EAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM;AACpE,WAAO,CAAC,IAAI;AAJd;AASA,OAAK,6BACH,SAAS,gCAAgC,GAAG,GAAG;AAE/C,QAAI,KAAK,KAAK,eAAe,GAAG;AAChC,QAAI,KAAK,KAAK,eAAe,EAAE,MAAM,GAAG,IAAI;AAC5C,QAAI,KAAK,KAAK,eAAe,CAAC,EAAE,IAAI,EAAE,KAAK;AAC3C,QAAI,KAAK,KAAK,eAAe,CAAC,EAAE,IAAI,EAAE,KAAK;AAC3C,WAAO,CACL,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KACjC,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KACjC,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KACjC,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AAXrC;AAeA,OAAK,mBAAmB,SAAS,sBAAsB,GAAG;AACxD,QAAI,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;AAC/B,WAAO,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,EAAE,KAAK,GAC5C,GAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,GAAI,GAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM;AAHnE;AAYA,OAAK,mBAAmB,SAAS,sBAAsB,GAAG,GAAG;AAC3D,WAAO,CACL,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IACrC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IACrC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;AAJzC;AAWA,OAAK,gCACH,SAAS,mCAAmC,GAAG;AAE/C,QAAI,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;AAGrC,QAAI,IAAI,EAAE,KAAK,UAAU,KAAK,EAAE,KAAK,UAAU;AAC/C,QAAI,IAAI,EAAE,KAAK,UAAU,KAAK,EAAE,KAAK,UAAU;AAC/C,QAAI,IAAI,EAAE,KAAK,UAAU,KAAK,EAAE,KAAK,UAAU;AAC/C,QAAI,IAAI,EAAE,KAAK,UAAU,KAAK,EAAE,KAAK,UAAU;AAG/C,QAAI,QAAS,KAAI,KAAK;AACtB,QAAI,SAAS,KAAK,KAAM,KAAU,UAAI,KAAU,SAAI,IAAI,IAAI,MAAM;AAClE,QAAI,KAAK,QAAQ,UAAU;AAC3B,QAAI,KAAK,QAAQ,UAAU;AAG3B,WAAO,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK;AAlBnC;AAyBA,OAAK,gBAAgB,SAAS,mBAAmB,MAAM;AACrD,QAAI,IAAI,KAAK,MAAM;AACnB,QAAI,KAAK,KAAK,KAAK,IAAI;AACrB,QAAE,KAAK,KAAK;AACZ,QAAE,KAAK,KAAK;AAJuC;AAMrD,QAAI,KAAK,KAAK,KAAK,IAAI;AACrB,QAAE,KAAK,KAAK;AACZ,QAAE,KAAK,KAAK;AARuC;AAUrD,WAAO;AAVT;AAgBA,OAAK,YAAY,SAAS,eAAe,OAAO,OAAO;AACrD,aAAS,QAAQ,GAAG,GAAG;AACrB,aAAO,IAAI;AAFwC;AAMrD,QAAI,WAAW,CAAC,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,KAAK;QACzD,WAAW,CAAC,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,KAAK;QACzD,SAAS;AAEb,YAAQ,KAAK,cAAc;AAC3B,YAAQ,KAAK,cAAc;AAG3B,QAAK,SAAS,OAAO,MAAM,MAAM,SAAS,OAAO,MAAM,MAClD,SAAS,OAAO,MAAM,MAAM,SAAS,OAAO,MAAM,IAAK;AAE1D,aAAO,KAAK,SAAS;AACrB,aAAO,KAAK,SAAS;AAJvB,WAKO;AACL,aAAO;AApB4C;AAwBrD,QAAK,SAAS,OAAO,MAAM,MAAM,SAAS,OAAO,MAAM,MAClD,SAAS,OAAO,MAAM,MAAM,SAAS,OAAO,MAAM,IAAK;AAE1D,aAAO,KAAK,SAAS;AACrB,aAAO,KAAK,SAAS;AAJvB,WAKO;AACL,aAAO;AA9B4C;AAiCrD,WAAO;AAjCT;AAoCA,OAAK,OAAO,SAAS,UAAU,KAAK;AAClC,WAAO,MAAM,IAAI,CAAC,IAAI;AADxB;AAIA,MAAI,mBAAmB,CACrB,IAAI,KAAK,MAAM,OAAO,MAAM,KAAK,MAAM,OAAO,QAAQ,MACtD,IAAI,KAAK,MAAM,OAAO,MAAM,KAAK,MAAM,OAAO,QAAQ,MACtD,IAAI,KAAK,MAAM,OAAO,MAAM,KAAK,MAAM,OAAO,QAAQ;AASxD,OAAK,UAAU,SAAS,aAAa,QAAQ,WAAW;AACtD,WAAO,MAAM,WAAW,SAAS,GAC1B;AACP,QAAI;QAAK,WAAW;AAEpB,WAAO,UAAU,MAAM;AACrB,gBAAU;AACV,eAAS,KAAK;AAPsC;AAUtD,UAAO,SAAS,MAAO;AACvB,cAAU;AACV,aAAS,KAAK,iBAAiB;AAE/B,UAAO,SAAS,KAAM;AACtB,cAAU;AACV,aAAS,KAAK,iBAAiB,KAAK;AAEpC,aAAS,KAAK,iBAAiB,KAAK;AAEpC,QAAI,WAAW,SAAS,KAAK;AAC7B,WAAQ,YAAY,SAAS,gBAAgB;AArB/C;AAwBA,OAAK,gBAAgB,SAAS,mBAAmB,MAAM,MAAM;AAC3D,UAAM,UAAU,KAAK,MAAM,MAAM;AADnC;AAIA,OAAK,iBAAiB,SAAS,oBAAoB,MAAM,MAAM;AAC7D,UAAM,UAAU,QAAQ,MAAM,MAAM;AADtC;AAIA,OAAK,YAAY,SAAS,UAAU,MAAM,MAAM;AAC9C,aAAS,OAAO,MAAM;AACpB,WAAK,OAAO,KAAK;AAF2B;AAAhD;AAMA,OAAK,yBACD,SAAS,4BAA4B,MAAM,MAAM,UAAU;AAC7D,WAAO,QAAQ,CAAC,KAAK,IAAI,OAAO;AAC9B,aAAO,KAAK,IAAI;AAF2C;AAI7D,QAAI,CAAC,MAAM;AACT,aAAO;AALoD;AAO7D,WAAO,WAAW,KAAK,SAAS,QAAQ,KAAK,IAAI;AARnD;AAWA,OAAK,UAAU,SAAS,aAAa,KAAK,MAAM,WAAW;AACzD,QAAI,YAAY,OAAO,OAAO,KAAK;AACnC,QAAI,UAAU,cAAc;AAC5B,aAAS,QAAQ,WAAW;AAC1B,UAAI,UAAU,QAAQ,UAAU;AAJuB;AAA3D;AAQA,OAAK,aAAa,SAAS,gBAAgB,KAAK,UAAU;AACxD,QAAI,SAAS,SAAS,cAAc;AACpC,QAAI,SAAS;AACb,WAAO,aAAa,OAAO;AAC3B,QAAI,UAAU;AACZ,aAAO,SAAS,YAAW;AACzB,YAAI,CAAC,QAAQ;AACX;AAFuB;AAIzB,iBAAS;AAJX;AALsD;AAYxD,aAAS,qBAAqB,QAAQ,GAAG,YAAY;AAZvD;AAeA,SAAO;AArPE,CAAC;AA6PZ,IAAI,wBAAyB,sBAAsB;AAWjD,WAAS,aAAa,SAAS,OAAO,UAAU,SAAS,SAAS,UAAU;AAC1E,SAAK,UAAU;AACf,SAAK,QAAQ;AACb,SAAK,WAAW;AAChB,SAAK,UAAU;AACf,SAAK,UAAU;AAIf,QAAI,UAAW,SAAQ,KAAK,QAAQ,MAAM;AAC1C,QAAI,UAAW,SAAQ,KAAK,QAAQ,MAAM;AAC1C,QAAI,SAAS,SAAS,SAAS;AAC/B,eAAW,WAAW;AACtB,eAAW,WAAW,IAAI,WAAW,MAAM;AAC3C,YAAQ;AACN,WAAK;AACH,kBAAU,CAAC;AAAG,kBAAU;AAAG,kBAAU;AAAG,kBAAU;AAClD;AACF,WAAK;AACH,kBAAU;AAAG,kBAAU;AAAG,kBAAU;AAAG,kBAAU;AACjD;AACF,WAAK;AACH,kBAAU;AAAG,kBAAU,CAAC;AAAG,kBAAU,CAAC;AAAG,kBAAU;AACnD;AAEF;AACE,kBAAU;AAAG,kBAAU;AAAG,kBAAU;AAAG,kBAAU,CAAC;AAClD;;AAGJ,QAAI,UAAU;AACZ,gBAAU,CAAC;AAAS,gBAAU,CAAC;AA/ByC;AAkC1E,QAAI,eAAe;AACnB,QAAI,OAAO;AACX,QAAI,YAAY,GAAG;AACjB,sBAAgB,KAAK,IAAI,UAAU,QAAQ,MAAM,QAAQ;AACzD,sBAAgB,KAAK,IAAI,UAAU,QAAQ,MAAM,QAAQ;AACzD,cAAQ,KAAK,IAAI,QAAQ,KAAK,QAAQ,MAAM;AAC5C,eAAS,KAAK,IAAI,QAAQ,KAAK,QAAQ,MAAM;AAJ/C,WAKO;AACL,sBAAgB,KAAK,IAAI,UAAU,QAAQ,MAAM,QAAQ;AACzD,sBAAgB,KAAK,IAAI,UAAU,QAAQ,MAAM,QAAQ;AACzD,cAAQ,KAAK,IAAI,QAAQ,KAAK,QAAQ,MAAM;AAC5C,eAAS,KAAK,IAAI,QAAQ,KAAK,QAAQ,MAAM;AA7C2B;AAkD1E,SAAK,YAAY,CACf,UAAU,OACV,UAAU,OACV,UAAU,OACV,UAAU,OACV,gBAAgB,UAAU,QAAQ,UAAU,UAAU,QAAQ,SAC9D,gBAAgB,UAAU,QAAQ,UAAU,UAAU,QAAQ;AAGhE,SAAK,QAAQ;AACb,SAAK,SAAS;AACd,SAAK,YAAY;AAxE8B;AA0EjD,eAAa;AAQX,WAAO,SAAS,mBAAmB,MAAM;AACvC,aAAO,QAAQ;AACf,UAAI,QAAQ,WAAW,OAAO,KAAK,QAAQ,KAAK;AAChD,UAAI,WAAW,cAAc,OAAO,KAAK,WAAW,KAAK;AACzD,aAAO,IAAI,aAAa,KAAK,QAAQ,SAAS,OAAO,UAC7B,KAAK,SAAS,KAAK,SAAS,KAAK;AAbC;AAyB5D,4BAAwB,SAAS,oCAAoC,GAAG,GAAG;AACzE,aAAO,KAAK,eAAe,CAAC,GAAG,IAAI,KAAK;AA1BkB;AAmC5D,gCACE,SAAS,wCAAwC,MAAM;AACvD,UAAI,KAAK,KAAK,eAAe,CAAC,KAAK,IAAI,KAAK,KAAK,KAAK;AACtD,UAAI,KAAK,KAAK,eAAe,CAAC,KAAK,IAAI,KAAK,KAAK,KAAK;AACtD,aAAO,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AAvC0B;AAkD5D,uBAAmB,SAAS,+BAA+B,GAAG,GAAG;AAC/D,aAAO,KAAK,sBAAsB,CAAC,GAAG,IAAI,KAAK;AAnDW;AAAA;AAsD9D,SAAO;AAhIU,CAAC;AAmIpB,IAAI,0BAA0B,CAC5B,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GACrE,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAC1E,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAC3E,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAC3E,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAC3E,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,QAAQ,QAAQ,QAAQ,QAAQ,QACjE,QAAQ,OAAO,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,QAC/D,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,OAAO,OAAO,OACtE,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,GAAG;AAGtD,SAAS,kBAAkB,KAAK;AAC9B,MAAI;MAAG,IAAI,IAAI;MAAQ,SAAS;AAChC,MAAI,IAAI,OAAO,UAAU,IAAI,OAAO,QAAQ;AAE1C,SAAK,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG;AACzB,aAAO,KAAK,OAAO,aAChB,IAAI,WAAW,MAAM,IAAK,IAAI,WAAW,IAAI;AAJR;AAA5C,SAMO;AACL,SAAK,IAAI,GAAG,IAAI,GAAG,EAAE,GAAG;AACtB,UAAI,OAAO,wBAAwB,IAAI,WAAW;AAClD,aAAO,KAAK,OAAO,OAAO,aAAa,QAAQ,IAAI,OAAO;AAHvD;AARuB;AAc9B,SAAO,OAAO,KAAK;AAriCrB;AAwiCA,SAAS,mBAAmB,KAAK;AAC/B,SAAO,mBAAmB,OAAO;AAziCnC;AA4iCA,SAAS,mBAAmB,KAAK;AAC/B,SAAO,SAAS,mBAAmB;AA7iCrC;AAgjCA,SAAS,WAAW,KAAK;AACvB,WAAS,OAAO,KAAK;AACnB,WAAO;AAFc;AAIvB,SAAO;AApjCT;AAujCA,SAAS,OAAO,GAAG;AACjB,SAAO,OAAO,MAAM;AAxjCtB;AA2jCA,SAAS,MAAM,GAAG;AAChB,SAAO,OAAO,MAAM,YAAc,KAAI,OAAO;AA5jC/C;AA+jCA,SAAS,MAAM,GAAG;AAChB,SAAO,OAAO,MAAM;AAhkCtB;AAmkCA,SAAS,SAAS,GAAG;AACnB,SAAO,OAAO,MAAM;AApkCtB;AAukCA,SAAS,QAAQ,GAAG;AAClB,SAAO,aAAa;AAxkCtB;AA2kCA,SAAS,cAAc,GAAG;AACxB,SAAO,QAAO,kDAAM,YAAY,MAAM,QAAQ,EAAE,eAAe;AA5kCjE;AAglCA,SAAS,QAAQ,IAAI;AACnB,SAAQ,OAAO,QAAQ,OAAO,QAAQ,OAAO,QAAQ,OAAO;AAjlC9D;AAolCA,SAAS,WAAW;AAElB,SAAO,QAAO,8DAAY,YAAY,UAAU,OAAO;AAtlCzD;AAymCA,SAAS,0BAA0B;AACjC,MAAI,aAAa;AACjB,aAAW,cAAc,QAAQ,UAAU,SAAS,QAAQ;AAC1D,eAAW,UAAU;AACrB,eAAW,SAAS;AAFD;AAIrB,SAAO;AA/mCT;AAknCA,IAAI,qBAAsB,mBAAmB;AAC3C,WAAS,KAAK,KAAK,KAAK,QAAQ;AAC9B,WAAO,IAAI,SAAS,QAAQ;AAC1B,aAAO;AAFqB;AAI9B,WAAO;AALkC;AAO3C,WAAS,YAAY;AACnB,SAAK,UAAU,OAAO,OAAO;AAC7B,SAAK,QAAQ;AACb,SAAK,UAAU;AAV0B;AAY3C,YAAU;AACR,UAAM,SAAS,eAAe,MAAM;AAClC,UAAI,CAAC,KAAK,SAAS;AACjB;AAFgC;AAIlC,UAAI,QAAQ,KAAK,SAAS;AACxB,aAAK,kCAAkC;AALP;AAOlC,WAAK,QAAQ,QAAQ,KAAK;AARR;AAUpB,aAAS,SAAS,kBAAkB,MAAM;AACxC,UAAI,CAAC,KAAK,SAAS;AACjB;AAFsC;AAIxC,UAAM,UAAQ,KAAK,UAAU;AAC3B,aAAK,oCAAoC;AALH;AAOxC,WAAK,MAAM;AACT,gBAAQ;AACR,iBAAS,KAAK,QAAQ;AACtB,eAAO,KAAK;AAHE;AAMhB,aAAO,KAAK,QAAQ;AAvBF;AAyBpB,cAAU,SAAS,qBAAqB;AACtC,UAAI,GAAG;AACP,UAAI,QAAQ,KAAK;AACjB,UAAI,MAAM;AAEV,UAAI,UAAU;AACd,WAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,IAAI,IAAI,EAAE,GAAG;AAC1C,YAAI,OAAO,MAAM,GAAG;AACpB,YAAI,KAAK,SAAS,SAAS;AACzB,oBAAU,KAAK;AAHyB;AANN;AAYtC,WAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,IAAI,IAAI,EAAE,GAAG;AAC1C,YAAI,OAAO,MAAM;AACjB,YAAI,WAAW,KAAK,MAAM,KAAK;AAC/B,eAAO,KAAK,KAAK,SAAS,KAAK,WAAW,MAAM,WAAW;AAfvB;AAiBtC,aAAO;AA1CW;AAAA;AA6CtB,SAAO;AAzDO,CAAC;AA4DjB,IAAI,aAAa,SAAS,WAAW,MAAM,aAAa;AACtD,MAAI,OAAO,SAAS,aAAa;AAC/B,WAAO,IAAI,KAAK,CAAC,OAAO,EAAE,MAAM;AAFoB;AAItD,QAAM,IAAI,MAAM;AAJlB;AAOA,IAAI,2BAA4B,yBAAyB;AAEvD,MAAI,SACF;AAEF,SAAO,SAAS,gBAAgB,MAAM;AAAsC,QAAzB,sFAAkB;;AACnE,QAAI,CAAC,mBAAmB,IAAI,iBAAiB;AAC3C,UAAI,OAAO,WAAW,MAAM;AAC5B,aAAO,IAAI,gBAAgB;AAH6C;AAM1E,QAAI,SAAS,UAAU,cAAc;AACrC,SAAK,IAAI,IAAI,GAAG,KAAK,KAAK,QAAQ,IAAI,IAAI,KAAK,GAAG;AAChD,UAAI,KAAK,KAAK,KAAK;AACnB,UAAI,KAAK,KAAK,IAAI,KAAK;AACvB,UAAI,KAAK,KAAK,IAAI,KAAK;AACvB,UAAI,KAAK,MAAM;UAAG,KAAO,MAAK,MAAM,IAAM,MAAM;AAChD,UAAI,KAAK,IAAI,IAAI,KAAO,MAAK,QAAQ,IAAM,MAAM,IAAK;AACtD,UAAI,KAAK,IAAI,IAAI,KAAM,KAAK,OAAQ;AACpC,gBAAU,OAAO,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO;AAdgB;AAgB1E,WAAO;AAhBT;AALoB,CAAC;AAyBvB,SAAS,YAAY,IAAI;AAAsB,MAAhB,8EAAU;;AACvC,MAAI,CAAC,IAAI;AACP,WAAO,QAAQ,QAAQ;AAFoB;AAI7C,aAAW,QAAQ,UAAC,SAAS,QAAW;AACtC,YAAQ,GAAG,MAAM,SAAS;AADrB;AAltCT;AAutCA,SAAS,WAAW,QAAQ;AAC1B,MAAI,QAAO,4DAAW,UAAU;AAC9B,WAAO;AAFiB;AAI1B,UAAQ,OAAO;AACb,SAAK;AACH,aAAO,IAAI,eAAe,OAAO;AACnC,SAAK;AACH,aAAO,IAAI,oBAAoB,OAAO;AACxC,SAAK;AACH,aAAO,IAAI,4BAA4B,OAAO,SAAS,OAAO;AAChE;AACE,aAAO,IAAI,sBAAsB,OAAO,SAAS,OAAO;;AAnuC9D;AAuuCA,SAAS,gBAAgB,YAAY,SAAS,QAAQ;AACpD,MAAI,SAAS;AACX,eAAW;AADb,SAEO;AACL,eAAW,OAAO;AAJgC;AAvuCtD;AA+uCA,SAAS,SAAS,SAAS;AACzB,SAAO,QAAQ,QAAQ,SAAS,MAAM,YAAM,CAArC;AAhvCT;AAmvCA,SAAS,eAAe,YAAY,YAAY;AAAQ;;AACtD,OAAK,aAAa;AAClB,OAAK,aAAa;AAClB,OAAK,SAAS;AACd,OAAK,aAAa;AAClB,OAAK,WAAW;AAChB,OAAK,uBAAuB;AAC5B,OAAK,cAAc,OAAO,OAAO;AACjC,OAAK,oBAAoB,OAAO,OAAO;AACvC,MAAI,wBAAwB,KAAK,wBAAwB,OAAO,OAAO;AACvE,MAAI,KAAK,KAAK,gBAAgB,OAAO,OAAO;AAE5C,OAAK,qBAAsB,iBAAU;AACnC,QAAI,OAAO,MAAM;AACjB,QAAI,KAAK,eAAe,MAAK,YAAY;AACvC;AAHiC;AAKnC,QAAI,KAAK,QAAQ;AACf,YAAK,sBAAsB;AAD7B,eAEW,KAAK,SAAS;AACvB,UAAI,aAAa,KAAK;AACtB,UAAI,KAAK,cAAc,uBAAuB;AAC5C,YAAI,WAAW,sBAAsB;AACrC,eAAO,sBAAsB;AAC7B,YAAI,WAAW,MAAM;AACnB,mBAAS,OAAO,WAAW,KAAK;AADlC,eAEO;AACL,mBAAS,QAAQ,KAAK;AANoB;AAA9C,aAQO;AACL,cAAM,IAAW,mCAA0B;AAXtB;AAAlB,eAaI,KAAK,UAAU,IAAI;AAC5B,UAAI,SAAS,GAAG,KAAK;AACrB,UAAI,KAAK,YAAY;AACnB,YAAI,cAAa,MAAK;AACtB,YAAI,cAAa,KAAK;AACtB,gBAAQ,UAAU,KAAK,YAAY;AACjC,iBAAO,OAAO,GAAG,KAAK,OAAO,IAAI,KAAK;AADxC,WAEG,KAAM,kBAAW;AAClB,iBAAO;AACL;AACA;AACA,qBAAS;AACT,wBAAY,KAAK;AACjB,kBAAM;AALW;AAHrB,WAUI,kBAAW;AACb,cAAI,kBAAkB,OAAO;AAE3B,qBAAS,SAAS;AAHP;AAKb,iBAAO;AACL;AACA;AACA,qBAAS;AACT,wBAAY,KAAK;AACjB,mBAAO;AALU;AAfrB;AAHF,iBA0BW,KAAK,UAAU;AACxB,cAAK,kBAAkB;AADlB,aAEA;AACL,eAAO,GAAG,KAAK,OAAO,IAAI,KAAK;AA/BL;AAAvB,WAiCA;AACL,YAAM,IAAW,uCAA8B,KAAK;AAtDnB;AAArC;AAyDA,SAAO,iBAAiB,WAAW,KAAK;AAxzC1C;AA2zCA,eAAe;AACb,kBAAG,YAAY,SAAS,OAAO;AAC7B,QAAI,KAAK,KAAK;AACd,QAAI,GAAG,aAAa;AAClB,YAAM,IAAW,kDAAoD;AAH1C;AAK7B,OAAG,cAAc,CAAC,SAAS;AANJ;AAczB,sBAAK,YAAY,MAAM,WAAW;AAChC,QAAI;AACF,kBAAY,KAAK;AACjB,kBAAY,KAAK;AACjB,cAAQ;AACR;AAJY;AAMd,SAAK,YAAY,SAAS;AArBH;AA+BzB,4CAAgB,YAAY,MAAM,WAAW;AAC3C,QAAI,aAAa,KAAK;AACtB,QAAI;AACF,kBAAY,KAAK;AACjB,kBAAY,KAAK;AACjB,cAAQ;AACR;AACA;AALY;AAOd,QAAI,aAAa;AACjB,SAAK,sBAAsB,cAAc;AACzC,QAAI;AACF,WAAK,YAAY,SAAS;AAD5B,MAEE,OAAO,GAAG;AACV,iBAAW,OAAO;AAduB;AAgB3C,WAAO,WAAW;AA/CK;AA2DzB,0CAAe,YAAY,MAAM,kBAAkB;AAAW;;AAC5D,QAAI,WAAW,KAAK;AACpB,QAAI,aAAa,KAAK;AACtB,QAAI,aAAa,KAAK;AAEtB;AACE,aAAQ,2BAAe;AACrB,YAAI,kBAAkB;AACtB,eAAK,kBAAkB;AACrB;AACA,qBAAW;AACX,oBAAU;AAHuB;AAKnC,eAAK;AACH;AACA;AACA,kBAAQ;AACR;AACA;AACA,uBAAa,WAAW;AANT;AASjB,eAAO,gBAAgB;AAjBD;AAoBxB,YAAO,0BAAe;AACpB,YAAI,iBAAiB;AACrB,eAAK,kBAAkB,UAAU,WAAW;AAC5C,eAAK;AACH;AACA;AACA,kBAAQ;AACR;AACA,uBAAa,WAAW;AALT;AASjB,eAAO,eAAe;AAhCA;AAmCxB,cAAS,wBAAW;AAClB,YAAI,mBAAmB;AACvB,eAAK,kBAAkB,UAAU,aAAa;AAC9C,eAAK,kBAAkB,UAAU,WAAW;AAC5C,eAAK;AACH;AACA;AACA,kBAAQ;AACR;AACA;AALe;AAQjB,eAAO,iBAAiB;AA/CF;AAAA,KAAf,EAiDR;AAjHoB;AAoHzB,gDAAkB;AAAM;;AACtB,QAAI,OAAO;AACX,QAAI,SAAS,KAAK,cAAc,KAAK;AACrC,QAAI,WAAW,KAAK;AACpB,QAAI,cAAc,KAAK;AACvB,QAAI,aAAa,KAAK;AACtB,QAAI,aAAa,KAAK;AACtB,QAAI,aAAa;AAEjB,QAAI,oBAAqB;AACyB,UADvB;UAAQ;UAAO;UACf;UAAS;;AAClC,aAAK;AAAc;AAAY;AAAY;AAAQ;AAChC;AAAO;AAAS;AADlB,SAC6B;AAHhD;AAMA,QAAI;AACF,gCAAQ;AAA4B,YAArB,2EAAO;YAAG;;AACvB,YAAI,KAAK,aAAa;AACpB;AAFgC;AAIlC,YAAI,kBAAkB,KAAK;AAC3B,aAAK,eAAe;AAIpB,YAAI,kBAAkB,KAAK,KAAK,eAAe,GAAG;AAChD,eAAK,iBAAiB;AACtB,eAAK,QAAQ,KAAK,eAAe;AAXD;AAalC;AAAoB,kBAAQ;AAAW;AAAO;AAA5B;AAdL;AAiBf,8BAAQ;AACN,YAAI,KAAK,aAAa;AACpB;AAFI;AAIN,0BAAkB,EAAE,QAAQ;AAC5B,eAAO,KAAK,YAAY;AAtBX;AAyBf,4BAAM,QAAQ;AACZ,YAAI,KAAK,aAAa;AACpB;AAFU;AAIZ,aAAK,cAAc;AACnB;AAAoB,kBAAQ;AAAS;AAAnB;AA9BL;;AAiCf,sBAAgB;AAChB,cAAQ;AACR,gBAAU;AACV,mBAAa;AACb;AACA,aAAO;AAtCQ;AAyCjB,eAAW,eAAe;AAC1B,eAAW,QAAQ,WAAW,eAAe;AAC7C,SAAK,YAAY,YAAY;AAC7B,gBAAY,OAAO,IAAI,CAAC,KAAK,MAAM,aAAa,OAAO,IAAI,KAAK,YAAM;AACpE;AAAoB,gBAAQ;AAAkB,iBAAS;AAArC;AADpB,OAEI,kBAAW;AACb;AAAoB,gBAAQ;AAAkB,iBAAS;AAAO;AAA5C;AAHpB;AA/KuB;AAsLzB,wDAAsB;AAAM;;AAC1B,QAAI,aAAa,KAAK;AACtB,QAAI,aAAa,KAAK;AACtB,QAAI,WAAW,KAAK;AAEpB,QAAI,qBAAsB;AAAiC,UAA/B;UAAQ;UAAS;;AAC3C,aAAK,OAAO;AAAc;AAAY;AAAY;AACxB;AAAS;AAAU;AADrB;AAD1B;AAKA,QAAI,yBAAyB,kCAAM;AAGjC,cAAQ,KACN,OAAK,kBAAkB,KAAK,UAAU,WACtC,OAAK,kBAAkB,KAAK,UAAU,UACtC,OAAK,kBAAkB,KAAK,UAAU,YACtC,IAAI,UAAS,YAAY;AACzB,eAAO,cAAc,SAAS,WAAW;AAL/B,UAMR,KAAK,YAAM;AACb,eAAO,OAAK,kBAAkB,KAAK;AAPrC;AAHF;AAcA,YAAQ,KAAK;AACX,WAAK;AACH,wBAAgB,KAAK,kBAAkB,KAAK,UAAU,WACtC,KAAK,SAAS,WAAW,KAAK;AAC9C;AACF,WAAK;AACH,wBAAgB,KAAK,kBAAkB,KAAK,UAAU,UACtC,KAAK,SAAS,WAAW,KAAK;AAC9C;AACF,WAAK;AAEH,YAAI,CAAC,KAAK,YAAY,KAAK,WAAW;AACpC;AAAqB,oBAAQ;AAAiB,qBAAS;AAApC;AACnB;AAJJ;AASE,YAAI,KAAK,YAAY,KAAK,UAAU,eAAe,KAC/C,KAAK,cAAc,GAAG;AACxB,eAAK,YAAY,KAAK,UAAU,eAAe;AAXnD;AAcE,aAAK,YAAY,KAAK,UAAU,cAAc,KAAK;AACnD,oBAAY,KAAK,YAAY,KAAK,UAAU,QAAQ,KAAK,YAAM;AAC7D;AAAqB,oBAAQ;AAAiB,qBAAS;AAApC;AADrB,WAEI,kBAAW;AACb;AAAqB,oBAAQ;AACR,qBAAS;AAAO;AADlB;AAHrB;AAMA;AACF,WAAK;AACH,eAAO,KAAK,kBAAkB,KAAK,WAC5B;AACP,YAAI,CAAC,KAAK,kBAAkB,KAAK,UAAU,UAAU;AACnD,eAAK,kBAAkB,KAAK,UAAU,WAAW,QAAQ,KAAK;AAJlE;AAME;AACF,WAAK;AACH,eAAO,KAAK,kBAAkB,KAAK,WAC5B;AACP,YAAI,KAAK,kBAAkB,KAAK,UAAU,UAAU;AAClD;AAJJ;AAME,aAAK,kBAAkB,KAAK,UAAU,WAAW;AACjD,aAAK,kBAAkB,KAAK,UAAU,WAAW;AACjD;AACA;AACF,WAAK;AACH,eAAO,KAAK,kBAAkB,KAAK,WAC5B;AACP,aAAK,kBAAkB,KAAK,UAAU,WACpC,MAAM,WAAW,KAAK;AACxB;AACA;AACF,WAAK;AACH,wBAAgB,KAAK,kBAAkB,KAAK,UAAU,YACtC,KAAK,SAAS,WAAW,KAAK;AAC9C;AACA;AACF,WAAK;AACH,YAAI,CAAC,KAAK,YAAY,KAAK,WAAW;AACpC;AAFJ;AAIE,oBAAY,KAAK,YAAY,KAAK,UAAU,UAChC,CAAC,WAAW,KAAK,UAAU,KAAK,YAAM;AAChD;AAAqB,oBAAQ;AAAmB,qBAAS;AAAtC;AAFrB,WAGI,kBAAW;AACb;AAAqB,oBAAQ;AACR,qBAAS;AAAO;AADlB;AAJrB;AAOA,aAAK,YAAY,KAAK,UAAU,eAC9B,OAAO,WAAW,KAAK;AACzB,aAAK,YAAY,KAAK,UAAU,cAAc;AAC9C,eAAO,KAAK,YAAY,KAAK;AAC7B;AACF;AACE,cAAM,IAAI,MAAM;;AA3RG;AAqSzB,oCAAY,SAAS,WAAW;AAC9B,QAAI,aAAa,KAAK,sBAAsB;AAC1C,WAAK,OAAO,YAAY,SAAS;AADnC,WAEO;AACL,WAAK,OAAO,YAAY;AAJI;AArSP;AA6SzB,8BAAU;AACR,SAAK,OAAO,oBAAoB,WAAW,KAAK;AA9SzB;AAAA;AAkT3B,SAAS,eAAe,IAAI,UAAU,MAAM;AAC1C,MAAI,MAAM,IAAI;AACd,MAAI,SAAU,SAAS,+BAA+B;AACpD,SAAK,QAAQ,IAAI;AADnB;AAGA,MAAI,UAAW,SAAS,gCAAgC;AACtD,SAAK,QAAQ,IAAI;AACjB,SAAK;AAFP;AAIA,MAAI,MAAM;AAGZ;QACE;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,0B;;;;;;;;;;;;;;;;AC9qDK;;;;AAEP,IAAI,mBAEJ;;IACE;;;;;;;2BAAO,OAAO,QAAQ;AACpB,UAAI,SAAS,KAAK,UAAU,GAAG;AAC7B,cAAM,IAAI,MAAM;AAFE;AAIpB,UAAI,SAAS,SAAS,cAAc;AACpC,UAAI,UAAU,OAAO,WAAW;AAChC,aAAO,QAAQ;AACf,aAAO,SAAS;AAChB;AACE;AACA;AAFK;AAMT;;;0BAAM,kBAAkB,OAAO,QAAQ;AACrC,UAAI,CAAC,iBAAiB,QAAQ;AAC5B,cAAM,IAAI,MAAM;AAFmB;AAIrC,UAAI,SAAS,KAAK,UAAU,GAAG;AAC7B,cAAM,IAAI,MAAM;AALmB;AAOrC,uBAAiB,OAAO,QAAQ;AAChC,uBAAiB,OAAO,SAAS;AAGnC;;;4BAAQ,kBAAkB;AACxB,UAAI,CAAC,iBAAiB,QAAQ;AAC5B,cAAM,IAAI,MAAM;AAFM;AAMxB,uBAAiB,OAAO,QAAQ;AAChC,uBAAiB,OAAO,SAAS;AACjC,uBAAiB,SAAS;AAC1B,uBAAiB,UAAU;AAI/B;;;;;;IAA2B;AACb;AAA2C;QAAzC,uCAAU;;QAAM,iDAAe;;;;AAC3C,SAAK,UAAU;AACf,SAAK,eAAe;AAGhB;;;;;AAAW;;UAAT;;AACN,UAAI,CAAC,MAAM;AACT,eAAO,QAAQ,OAAO,IAAI,MAAM;AAFnB;AAIf,iBAAW,QAAQ,UAAC,SAAS,QAAW;AACtC,YAAI,MAAM,MAAK,UAAkB,cAAK,eAAe,WAAW;AAEhE,YAAI,UAAU,IAAI;AAClB,gBAAQ,KAAK,OAAO,KAAK;AAEzB,YAAI,MAAK,cAAc;AACrB,kBAAQ,eAAe;AAPa;AAStC,gBAAQ,qBAAqB,YAAM;AACjC,cAAI,QAAQ,eAAe,eAAe,MAAM;AAC9C;AAF+B;AAIjC,cAAI,QAAQ,WAAW,OAAO,QAAQ,WAAW,GAAG;AAClD,gBAAI;AACJ,gBAAI,MAAK,gBAAgB,QAAQ,UAAU;AACzC,qBAAO,IAAI,WAAW,QAAQ;AADhC,mBAEO,IAAI,CAAC,MAAK,gBAAgB,QAAQ,cAAc;AACrD,qBAAO,yBAAc,QAAQ;AALmB;AAOlD,gBAAI,MAAM;AACR;AACE,0BAAU;AACV,iCAAiB,MAAK,eACpB,0BAAoB,SAAS,0BAAoB;AAH7C;AAKR;AAbgD;AAJnB;AAoBjC,iBAAO,IAAI,MACO,2BAAK,eAAe,YAAY,MACjC,cAAc;AAtBjC;AAyBA,gBAAQ,KAAK;AAlCR;AAVgB;;;;;;AAqD3B,IAAI,uBAAwB,qBAAqB;AAM/C,MAAI,WAAW,CAAC,MAAM,OAAO,UAAU;AACvC,MAAI,SAAS,OAAO,OAAO;AAE3B,WAAS,cAAc,CATwB;AAW/C,cAAY,UAAU,SAAS,IAAI,UAAU,SAAS;AAEpD,QAAI,UAAU,WAAW,KAAK,OAAO,OAAO,cAAc,UAAU;AAClE,aAAO,OAAO;AAHoC;AAMpD,cAAU,WAAW,SAAS;AAC9B,QAAI,QAAQ,QAAQ;QAAO;QAAU;AAGrC,QAAI,OAAO,MAAM,cAAc,UAAU;AACvC,aAAQ,OAAO,YAAY;AAXuB;AAepD,gBAAY,SAAS,OAAO,GAAG,gBAAgB,SAAS,MAAM;AAG9D,SAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,IAAI,GAAG,KAAK;AAC/C,iBAAW,SAAS,KAAK;AACzB,UAAI,OAAO,MAAM,cAAc,UAAU;AACvC,eAAQ,OAAO,YAAY;AAHkB;AAlBG;AA0BpD,WAAQ,OAAO,YAAY;AA1B7B;AA6BA,cAAY,UAAU,SAAS,IAAI,UAAU,SAAS,KAAK;AACzD,QAAI,OAAO,KAAK,QAAQ;AACxB,QAAI,SAAS,aAAa;AACxB,cAAQ,MAAM,QAAQ;AAHiC;AAA3D;AAOA,SAAO;AA/CS,CAAC;AAkDnB,IAAI,uCAAwC,8BAA8B;AACxE,WAAS,4BAA4B,KAAK,MAAM;AAC9C,SAAK,UAAU;AACf,SAAK,OAAO;AAH0D;AAMxE,8BAA4B,YAAY,IAAI;AAC5C,8BAA4B,UAAU,OAAO;AAC7C,8BAA4B,cAAc;AAE1C,SAAO;AAVyB,CAAC;AAanC,IAAI;AACF,QAAM;AACN,QAAM;AACN,SAAO;AACP,UAAQ;AACR,OAAK;AALU;AAQjB,IAAI,sBAAsB,CACxB,IACA,SACA,UACA,WACA;AAgBF,SAAS,kBAAkB,MAAM,QAAQ;AACvC,MAAI,MAAM,UAAU,OAAO;AAC3B,OAAK,OAAO,KAAK,QAAS,MAAM,gCAAqB,OAAO;AAE5D,MAAI,KAAK;AACP,QAAI,SAAS,OAAO;AACpB,QAAI,OAAO,WAAW,aAAa;AACjC,eAAS,kBAAkB;AAHtB;AAKP,SAAK,SAAS,oBAAoB;AAElC,QAAI,MAAM,OAAO;AACjB,QAAI,OAAO,QAAQ,aAAa;AAC9B,YAAM,kBAAkB;AATnB;AAWP,SAAK,MAAM;AAf0B;AA9MzC;AAkOA,SAAS,mBAAmB,KAAK;AAC/B,MAAI,SAAS,IAAI,QAAQ;AACzB,MAAI,QAAQ,IAAI,QAAQ;AACxB,MAAI,MAAM,KAAK,IACb,SAAS,IAAI,SAAS,IAAI,QAC1B,QAAQ,IAAI,QAAQ,IAAI;AAC1B,SAAO,IAAI,UAAU,IAAI,YAAY,KAAK,OAAO,GAAG;AAxOtD;AA2OA,SAAS,kBAAkB,IAAI;AAG7B,MAAI,iBAAiB,kBAAY;AACjC,UAAQ;AACN,SAAK;AACH,aAAO,iBAAiB,eAAe,SAAS;AAClD,SAAK;AACH,aAAO,iBAAiB,eAAe,mBAAmB;AAC5D,SAAK;AACH,aAAO,iBAAiB,eAAe,gBAAgB;AACzD,SAAK;AACH,aAAO,iBAAiB,eAAe,eAAe;AACxD,SAAK;AACH,aAAO,iBAAiB,eAAe,kBAAkB;AAC3D,SAAK;AACH,aAAO,iBAAiB,eAAe,yBAAyB;AAClE,SAAK;AACH,aAAO,iBAAiB,eAAe,eAAe;AACxD,SAAK;AACH,aAAO,iBAAiB,eAAe,UAAU;AACnD,SAAK;AACH,aAAO,iBAAiB,eAAe,aAAa;AACtD,SAAK;AACH,aAAO,iBAAiB,eAAe,uBAAuB;AAChE,SAAK;AACH,aAAO,iBAAiB,eAAe,aAAa;AACtD,SAAK;AACH,aAAO,iBAAiB,eAAe,YAAY;AACrD,SAAK;AACH,aAAO,iBAAiB,eAAe,gBAAgB;AACzD,SAAK;AACH,aAAO,iBAAiB,eAAe,eAAe,CAAC;AACzD,SAAK;AACH,aAAO,iBAAiB,eAAe,qBAAqB;AAC9D,SAAK;AACH,aAAO,iBAAiB,eAAe,kBAAkB;AAC3D,SAAK;AACH,UAAI,CAAC,gBAAgB;AACnB,eAAO,WAAW;AAFtB;AAIE,cAAQ,eAAe;AACrB,aAAK,WAAW;AAChB,aAAK,WAAW;AAChB,aAAK,WAAW;AAChB,aAAK,WAAW;AAChB,aAAK,WAAW;AACd,iBAAO,eAAe;;AAE1B,sBAAK,0CACA,eAAe;AAEpB,qBAAe,qBAAqB,WAAW;AAC/C,aAAO,WAAW;AACpB,SAAK;AACH,aAAO,iBAAiB,eAAe,kBAAkB;AAC3D,SAAK;AACH,aAAO,CAAG,oBAAkB,eAAe;AAC7C,SAAK;AACH,aAAO,CAAG,oBAAkB,eAAe;AAC7C;AACE,YAAM,IAAI,MAAM,8BAA8B;;AAxSpD;AA4SA,SAAS,0BAA0B;AACjC,MAAI,qBAAqB,kBAAkB;AAC3C,UAAQ;AACN,SAAK,WAAW;AACd,aAAO;AACT,SAAK,WAAW;AAChB,SAAK,WAAW;AAChB,SAAK,WAAW;AAChB,SAAK,WAAW;AACd,aAAO;;AArTb;AAyTA,SAAS,WAAW,KAAK,eAAe;AACtC,wBAAW;AACX,MAAI,UAAU,gBAAgB,uBAAuB;AACrD,SAAO,kCAAuB,KAAK,aAAa;AAGlD;QACE;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,4C;;;;;;;;;;;;;;;;;;ACpTK;;AAIA;;AACoC;;AACZ;;AACN;;AACc;;;;AAEvC,IAAI,2BAA2B;AAE/B,IAAI,mBAAmB;AACvB,IAAI;AACJ,IAAI,iCAAiC;AAErC,IAAI,gBAGF,OAAO,aAAa,eAAe,SAAS,gBAC1C,SAAS,cAAc,MAAM;AAEjC,IAAI,wBAAwB;AAC5B,IAAI,mBAAmB;AAEuB;AAG5C,MAAI,OAAO,WAAW,aAAa;AAEjC,uBAAmB;AACnB,QAAI,OAAO,QAAwB,WAAW,aAAa;AACzD,cAAwB,SAAS,QAAwB;AAJ1B;AAMjC,uBAAmB;AANrB,SAOO,IAAI,OAAO,YAA4B,eACnC,OAAO,QAAwB,WAAW,YAAY;AAC/D,uBAAmB;AAZuB;AAc5C,MAAI,OAAO,cAAc,eAAe,UAAU,OAAO;AACvD,gBAAY,UAAU,MAAM;AAfc;AAiB5C,MAAI,yBACF,OAAO,cAAc,eAAe,UAAU;AAChD,6CAA4C,UAAU,UAAU;AAC9D,YAAwB,OAAO,IAAI,YAAY;AAC7C,UAAI;AAIF,eAAS,QAAwB;AAEnC,eAAS,OAAO;AAPlB;AADsB,+BAUO,UAAU,UAAU;AACjD,cAAU,CAAC,gCAAgC,UAAU,QAAQ;AAC3D,eAAS,OAAO;AADlB;AADG,MAIA;AAhFP;AAoFA,IAAI;AAMJ,SAAS,yBAAyB,KAAK;AACrC,qBAAmB;AA3FrB;AAgLA,SAAS,YAAY,KAAK,uBACL,kBAAkB,kBAAkB;AACvD,MAAI,OAAO,IAAI;AAGf,MAAI,UAAU,SAAS,GAAG;AACxB,0BAAW,uDACA;AAN0C;AAQvD,MAAI,uBAAuB;AACzB,QAAM,mCAAiC,wBAAwB;AAE7D,8BAAwB,OAAO,OAAO;AACtC,4BAAsB,SAAS,IAAI;AACnC,4BAAsB,cAAc,IAAI;AACxC,UAAI,CAAC,sBAAsB,OAAO;AAChC,8BAAsB,QAAQ,YAAY,CAA1C;AAN2D;AADtC;AAUzB,UAAM,OAAO,OAAO;AACpB,QAAI,QAAQ;AAnByC;AAqBvD,OAAK,aAAa,oBAAoB;AACtC,OAAK,aAAa,oBAAoB;AAEtC,MAAI;AACJ,MAAI,OAAO,QAAQ,UAAU;AAC3B,aAAS,EAAE,KAAK;AADlB,aAEW,yBAAc,MAAM;AAC7B,aAAS,EAAE,MAAM;AADZ,aAEI,eAAe,uBAAuB;AAC/C,aAAS,EAAE,OAAO;AADb,SAEA;AACL,QAAI,QAAO,sDAAQ,UAAU;AAC3B,YAAM,IAAI,MAAM,uCACA;AAHb;AAKL,QAAI,CAAC,IAAI,OAAO,CAAC,IAAI,QAAQ,CAAC,IAAI,OAAO;AACvC,YAAM,IAAI,MACR;AAPC;AAUL,aAAS;AAzC4C;AA4CvD,MAAI,SAAS;AACb,MAAI,iBAAiB;AACrB,MAAI,SAAS;AACb,MAAwB;AAExB,WAAS,OAAO,QAAQ;AACtB,QAAI,QAAQ,SAAS,OAAO,WAAW,aAAa;AAElD,aAAO,OAAO,IAAI,IAAI,OAAO,MAAM,OAAO,UAAU;AACpD;AAHF,eAIW,QAAQ,SAAS;AAC1B,uBAAiB,OAAO;AACxB;AAFK,eAGI,QAAQ,UAAU;AAC3B,eAAS,OAAO;AAChB;AAFK,eAGI,QAAQ,UAAY,SAAO,gBAAgB,aAAa;AAEjE,UAAI,WAAW,OAAO;AACtB,UAAI,OAAO,aAAa,UAAU;AAChC,eAAO,OAAO,yBAAc;AAD9B,iBAEW,QAAO,gEAAa,YAAY,aAAa,QAC7C,CAAC,MAAM,SAAS,SAAS;AAClC,eAAO,OAAO,IAAI,WAAW;AAFxB,iBAGI,yBAAc,WAAW;AAClC,eAAO,OAAO,IAAI,WAAW;AADxB,aAEA;AACL,cAAM,IAAI,MAAM,kDACA,oDACA;AAb+C;AAejE;AAfK,WAgBA,IAAI,QAAQ,qBAAqB;AACtC,0BAAoB,OAAO;AAC3B;AA7BoB;AA+BtB,WAAO,OAAO,OAAO;AAhFgC;AAmFvD,SAAO,iBAAiB,OAAO,kBAAkB;AACjD,SAAO,eAAe,OAAO,iBAAiB;AAE9C,MAAI,OAAO,8BAA8B,WAAW;AAClD,0BAAW,0CACT;AAxFmD;AA0FvD,SAAO,4BAA4B,OAChC,qCAAO,8BAA8B,OAAO,0BAAoB,OAC/D,0BAAoB;AACxB,MAAI,OAAO,8BAA8B,0BAAoB,UACzD,OAAO,8BAA8B,0BAAoB,QACzD,OAAO,8BAA8B,0BAAoB,SAAS;AACpE,oBAAK,kDACH;AACF,WAAO,4BAA4B,0BAAoB;AAlGF;AAqGvD,MAAI,CAAC,QAAQ;AAGX,QAAI,aAAa,kCAAkB;AACnC,aAAS,aAAa,UAAU,SAAS,cAAc,IAAI;AAC3D,SAAK,UAAU;AA1GsC;AA4GvD,MAAI,QAAQ,KAAK;AACjB,SAAO,QAAQ,KAAK,YAAY;AAC9B,QAAI,KAAK,WAAW;AAClB,YAAM,IAAI,MAAM;AAFY;AAI9B,0BAAsB,QAAQ,QAAQ,gBAAgB,OAAO,KACzD,UAAU,UAAU;AACtB,UAAI,KAAK,WAAW;AAClB,cAAM,IAAI,MAAM;AAFI;AAKtB,UAAI;AACJ,UAAI,gBAAgB;AAClB,wBAAoB,6CAAuB,QAAQ;AADrD,aAEO,IAAI,CAAC,OAAO,MAAM;AACvB,4BAAoB;AAClB,kBAAQ;AACR,wBAAc,kCAAkB;AAFG,SAArB;AATI;AAetB,UAAI,iBAAqB,yBAAe,OAAO,UAAU,OAAO;AAChE,qBAAe,uBAAuB,OAAO;AAC7C,UAAI,YAAY,IAAI,gBAAgB,gBAAgB,MAAM,eACtB;AACpC,WAAK,aAAa;AAClB,qBAAe,KAAK,SAAS;AArBxB;AAJT,KA2BG,MAAM,KAAK,YAAY;AAE1B,SAAO;AA3TT;AAwUA,SAAS,eAAe,QAAQ,QAAQ,uBAAuB,OAAO;AACpE,MAAI,OAAO,WAAW;AACpB,WAAO,QAAQ,OAAO,IAAI,MAAM;AAFkC;AAKpE,SAAO,mBAAmB,kCAAkB;AAC5C,SAAO,gBAAgB,kCAAkB;AACzC,SAAO,uBAAuB,CAAC,CAAC;AAChC,MAAI,uBAAuB;AACzB,WAAO,SAAS,sBAAsB;AACtC,WAAO,cAAc,sBAAsB;AAVuB;AAYpE,gBAAc,eAAe,gBAAgB;AAC3C;AACA;AACE,YAAM,OAAO;AACb,WAAK,OAAO;AACZ,gBAAU,OAAO;AACjB,wBAAkB,OAAO;AACzB,sBAAgB,OAAO;AACvB,cAAQ,OAAO;AANT;AAQR,kBAAc,kCAAkB;AAChC,qBAAiB,kCAAkB;AACnC,4BAAwB,kCAAkB;AAC1C,0BAAsB,kCAAkB,2BAClB,CAAC;AACvB,gBAAY,OAAO;AACnB,+BAA2B,OAAO;AAClC,kBAAc,OAAO;AAjBuC,GAAvD,EAkBJ,KAAK,UAAU,UAAU;AAC1B,QAAI,OAAO,WAAW;AACpB,YAAM,IAAI,MAAM;AAFQ;AAI1B,WAAO;AAtBF;AApVT;AAmXA,IAAI,kCAAmC,gCAAgC;AACrE,MAAI,iBAAiB;AAGrB,WAAS,yBAAyB;AAChC,SAAK,cAAc;AACnB,SAAK,aAAa;AAClB,SAAK,UAAU;AAMf,SAAK,QAAQ,MAAO;AAMpB,SAAK,YAAY;AAOjB,SAAK,aAAa;AAOlB,SAAK,aAAa;AAMlB,SAAK,uBAAuB;AAvCuC;AA0CrE,yBAAuB;AAKrB,QAAI,UAAU;AACZ,aAAO,KAAK,YAAY;AALuB;AAajD;AAAU;;AACR,WAAK,YAAY;AAEjB,UAAI,qBAAqB,CAAC,KAAK,aAAa,QAAQ,YAClD,KAAK,WAAW;AAClB,gCAA0B,KAAK,YAAM;AACnC,cAAK,aAAa;AAClB,YAAI,MAAK,SAAS;AAChB,gBAAK,QAAQ;AACb,gBAAK,UAAU;AAJkB;AAA9B;AAlBwC;;AAmCjD,UAAM,SAAS,4BAA4B,aAAa,YAAY;AAClE,aAAO,KAAK,QAAQ,KAAK,MAAM,KAAK,SAAS;AApCE;AAAA;AAwCnD,SAAO;AAnFoB,CAAC;AA6F9B,IAAI,iCAAkC,+BAA+B;AACnE,WAAS,sBAAsB,QAAQ,aAAa;AAClD,SAAK,SAAS;AACd,SAAK,cAAc;AAEnB,SAAK,kBAAkB;AACvB,SAAK,qBAAqB;AAC1B,SAAK,4BAA4B;AACjC,SAAK,mBAAmB;AARyC;AAUnE,wBAAsB;AAEpB,sBACI,SAAS,uCAAuC,UAAU;AAC5D,WAAK,gBAAgB,KAAK;AAHoB;AAMhD,yBACI,SAAS,0CAA0C,UAAU;AAC/D,WAAK,mBAAmB,KAAK;AARiB;AAWhD,gCACI,SAAS,iDAAiD,UAAU;AACtE,WAAK,0BAA0B,KAAK;AAbU;AAgBhD,iBAAa,SAAS,kCAAkC,OAAO,OAAO;AACpE,UAAI,YAAY,KAAK;AACrB,WAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,IAAI,GAAG,EAAE,GAAG;AAChD,kBAAU,GAAG,OAAO;AAH8C;AAhBtB;AAuBhD,oBAAgB,SAAS,qCAAqC;AAAQ;;AACpE,WAAK,iBAAiB,QAAQ,KAAK,YAAM;AACvC,YAAI,YAAY,OAAK;AACrB,aAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,IAAI,GAAG,EAAE,GAAG;AAChD,oBAAU,GAAG;AAHwB;AAAzC;AAxB8C;AAgChD,2BACI,SAAS,qCAAqC;AAAO;;AACvD,WAAK,iBAAiB,QAAQ,KAAK,YAAM;AACvC,YAAI,YAAY,OAAK;AACrB,aAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,IAAI,GAAG,EAAE,GAAG;AAChD,oBAAU,GAAG;AAHwB;AAAzC;AAlC8C;AA0ChD,oBAAgB,SAAS,uCAAuC;AAC9D,WAAK,iBAAiB;AA3CwB;AA8ChD,sBACI,SAAS,uCAAuC,OAAO,KAAK;AAC9D,YAAM,IAAI,MAAM;AAhD8B;AAmDhD,WAAO,SAAS,8BAA8B,CAnDE;AAAA;AAsDlD,SAAO;AAjEmB,CAAC;AA0E7B,IAAI,4BAA6B,0BAA0B;AACzD,WAAS,iBAAiB,SAAS,WAAW,aAAa;AACzD,SAAK,UAAU;AACf,SAAK,YAAY;AACjB,SAAK,cAAc;AAJoC;AAMzD,mBAAiB;AAIf,QAAI,WAAW;AACb,aAAO,KAAK,QAAQ;AAL8C;AAWpE,QAAI,cAAc;AAChB,aAAO,KAAK,QAAQ;AAZ8C;AAmBpE,aAAS,SAAS,yBAAyB,YAAY;AACrD,aAAO,KAAK,UAAU,QAAQ;AApBoC;AA4BpE,kBAAc,SAAS,8BAA8B,KAAK;AACxD,aAAO,KAAK,UAAU,aAAa;AA7B+B;AAqCpE,qBAAiB,SAAS,mCAAmC;AAC3D,aAAO,KAAK,UAAU;AAtC4C;AA6CpE,oBAAgB,SAAS,gCAAgC,IAAI;AAC3D,aAAO,KAAK,UAAU,eAAe;AA9C6B;AAqDpE,mBAAe,SAAS,iCAAiC;AACvD,aAAO,KAAK,UAAU;AAtD4C;AA4DpE,wCAAc;AACZ,aAAO,KAAK,UAAU;AA7D4C;;AAmEpE,oBAAgB,SAAS,kCAAkC;AACzD,aAAO,KAAK,UAAU;AApE4C;AA0EpE,mBAAe,SAAS,iCAAiC;AACvD,aAAO,KAAK,UAAU;AA3E4C;AA6FpE,gBAAY,SAAS,8BAA8B;AACjD,aAAO,KAAK,UAAU;AA9F4C;AAsGpE,iBAAa,SAAS,+BAA+B;AACnD,aAAO,KAAK,UAAU;AAvG4C;AA6GpE,aAAS,SAAS,2BAA2B;AAC3C,aAAO,KAAK,UAAU;AA9G4C;AAqHpE,qBAAiB,SAAS,mCAAmC;AAC3D,aAAO,KAAK,UAAU,uBAAuB;AAtHqB;AA4HpE,cAAU,SAAS,4BAA4B;AAC7C,aAAO,KAAK,UAAU;AA7H4C;AAkIpE,aAAS,SAAS,2BAA2B;AAC3C,WAAK,UAAU;AAnImD;AAwIpE,aAAS,SAAS,2BAA2B;AAC3C,aAAO,KAAK,YAAY;AAzI0C;AAAA;AA4ItE,SAAO;AAlJc,CAAC;AAmPxB,IAAI,wBAAyB,sBAAsB;AACjD,WAAS,aAAa,WAAW,UAAU,WAAW;AACpD,SAAK,YAAY;AACjB,SAAK,WAAW;AAChB,SAAK,YAAY;AACjB,SAAK,QAAY;AACjB,SAAK,MAAM,UAAU,kCAAkB;AACvC,SAAK,aAAa,UAAU;AAC5B,SAAK,OAAO,IAAI;AAChB,SAAK,qBAAqB;AAC1B,SAAK,iBAAiB;AACtB,SAAK,eAAe,OAAO,OAAO;AAClC,SAAK,YAAY;AAZ8B;AAcjD,eAAa;AAIX,QAAI,aAAa;AACf,aAAO,KAAK,YAAY;AALkC;AAU5D,QAAI,SAAS;AACX,aAAO,KAAK,SAAS;AAXqC;AAiB5D,QAAI,MAAM;AACR,aAAO,KAAK,SAAS;AAlBqC;AAuB5D,QAAI,WAAW;AACb,aAAO,KAAK,SAAS;AAxBqC;AA8B5D,QAAI,OAAO;AACT,aAAO,KAAK,SAAS;AA/BqC;AAwC5D,iBAAa,SAAS,yBAAyB,OAAO,QAAQ;AAC5D,UAAI,UAAU,SAAS,GAAG;AACxB,iBAAS,KAAK;AAF4C;AAI5D,aAAW,uBAAa,KAAK,MAAM,OAAO,QAAQ,GAAG;AA5CK;AAmD5D,oBAAgB,SAAS,4BAA4B,QAAQ;AAC3D,UAAI,SAAU,UAAU,OAAO,UAAW;AAE1C,UAAI,CAAC,KAAK,sBAAsB,KAAK,sBAAsB,QAAQ;AACjE,aAAK,qBAAqB,KAAK,UAAU,eAAe,KAAK,WACL;AACxD,aAAK,oBAAoB;AANgC;AAQ3D,aAAO,KAAK;AA3D8C;AAmE5D,YAAQ,SAAS,oBAAoB;AAAQ;;AAC3C,UAAI,QAAQ,KAAK;AACjB,YAAM,KAAK;AAIX,WAAK,iBAAiB;AAEtB,UAAI,kBAAmB,OAAO,WAAW,UAAU,UAAU;AAC7D,UAAI,gBAAgB,OAAO,iBAAqB;AAEhD,UAAI,CAAC,KAAK,aAAa,kBAAkB;AACvC,aAAK,aAAa,mBAAmB,OAAO,OAAO;AAZV;AAc3C,UAAI,cAAc,KAAK,aAAa;AAIpC,UAAI,CAAC,YAAY,wBAAwB;AACvC,oBAAY,wBAAwB;AACpC,oBAAY,yBAAyB;AACrC,oBAAY;AACV,mBAAS;AACT,qBAAW;AACX,qBAAW;AAHc;AAM3B,aAAK,MAAM,KAAK;AAChB,aAAK,UAAU,eAAe,KAAK;AACjC,qBAAW,KAAK,aAAa;AAC7B,kBAAQ;AACR,kCAAyB,OAAO,2BAA2B;AAHL;AA5Bf;AAmC3C,UAAI,WAAY,yBAAU;AACxB,YAAI,IAAI,YAAY,YAAY,QAAQ;AACxC,YAAI,KAAK,GAAG;AACV,sBAAY,YAAY,OAAO,GAAG;AAHZ;AAMxB,YAAI,OAAK,oBAAoB;AAC3B,iBAAK,iBAAiB;AAPA;AASxB,eAAK;AAEL,YAAI,OAAO;AACT,6BAAmB,WAAW,OAAO;AADvC,eAEO;AACL,6BAAmB,WAAW;AAdR;AAgBxB,cAAM,QAAQ;AACd,cAAM,QAAQ;AAjBhB;AAoBA,UAAI,qBAAqB,IAAI,mBAAmB,UAAU,QACV,KAAK,MACL,KAAK,YACL,YAAY,cACZ,KAAK,YACL;AAChD,yBAAmB,2BAA2B,oBAAoB;AAClE,UAAI,CAAC,YAAY,aAAa;AAC5B,oBAAY,cAAc;AA/De;AAiE3C,kBAAY,YAAY,KAAK;AAC7B,UAAI,aAAa,mBAAmB;AAGpC,UAAI,OAAO,kBAAkB;AAC3B,8BAAW;AACX,mBAAW,aAAa,OAAO;AAvEU;AA0E3C,kBAAY,uBAAuB,QAAQ,KAAM,wBAAiB;AAChE,YAAI,OAAK,gBAAgB;AACvB;AACA;AAH8D;AAKhE,cAAM,KAAK;AACX,2BAAmB,mBAAmB;AACtC,2BAAmB;AAPrB,SAQG,MAAM;AAET,aAAO;AAvJmD;AA8J5D,qBAAiB,SAAS,+BAA+B;AACvD,eAAS,sBAAsB;AAC7B,YAAI,YAAY,aAAa,WAAW;AACtC,sBAAY,qBAAqB,QAAQ,YAAY;AAErD,cAAI,IAAI,YAAY,YAAY,QAAQ;AACxC,cAAI,KAAK,GAAG;AACV,wBAAY,YAAY,OAAO,GAAG;AALE;AADX;AADwB;AAYvD,UAAI,kBAAkB;AACtB,UAAI,CAAC,KAAK,aAAa,kBAAkB;AACvC,aAAK,aAAa,mBAAmB,OAAO,OAAO;AAdE;AAgBvD,UAAI,cAAc,KAAK,aAAa;AACpC,UAAI;AAEJ,UAAI,CAAC,YAAY,sBAAsB;AACrC,qBAAa;AACb,mBAAW,sBAAsB;AACjC,oBAAY,wBAAwB;AACpC,oBAAY,uBAAuB;AACnC,oBAAY,cAAc;AAC1B,oBAAY,YAAY,KAAK;AAC7B,oBAAY;AACV,mBAAS;AACT,qBAAW;AACX,qBAAW;AAHc;AAM3B,aAAK,UAAU,eAAe,KAAK;AACjC,qBAAW,KAAK;AAChB,kBAAQ;AAF8C;AAhCH;AAqCvD,aAAO,YAAY,qBAAqB;AAnMkB;AA0M5D;AAA+B,UAAb,6EAAS;;AACzB,UAAM,0BAA0B;AAChC,kBAAY,UAAU,eAAe,eAAe;AAClD,mBAAW,KAAK,aAAa;AAC7B,6BAAsB,OAAO,wBAAwB;AACrD,0BAAmB,OAAO,4BAA4B;AAHc,OAA/D;AAKL,uBAAe;AACf,4BAAK,aAAa;AAChB,iBAAO,YAAY,MAAM;AAH1B;AAAA;AAhNuD;;AA6N5D,oBAAgB,SAAS,4BAA4B,QAAQ;AAC3D,eAAS,UAAU;AACnB,UAAI,iBAAiB,KAAK,kBAAkB;AAE5C,iBAAW,QAAQ,UAAS,SAAS,QAAQ;AAC3C,iBAAS,OAAO;AACd,iBAAO,OAAO,KAAc;AAAkB,gBAAhB;gBAAO;;AACnC,gBAAI,MAAM;AACR,sBAAQ;AACR;AAH0C;AAK5C,uBAAK,UAAU,YAAY,QAAQ,MAAM;AACzC,uBAAK,cAAc,YAAY,OAAO,MAAM;AAC5C;AAPF,aAQG;AAVsC;AAa3C,YAAI,SAAS,eAAe;AAC5B,YAAI;AACF,iBAAO;AACP,kBAAQ,OAAO,OAAO;AAFN;AAKlB;AAnBK;AAjOmD;AA2P5D,cAAU,SAAS,uBAAuB;AACxC,WAAK,YAAY;AACjB,WAAK,UAAU,UAAU,KAAK,aAAa;AAE3C,UAAI,SAAS;AACb,aAAO,KAAK,KAAK,cAAc,QAAQ,UAAS,QAAQ;AACtD,YAAI,WAAW,UAAU;AAEvB;AAHoD;AAKtD,YAAI,cAAc,KAAK,aAAa;AACpC,oBAAY,YAAY,QAAQ,UAAS,YAAY;AACnD,cAAI,kBAAkB,WAAW,WAAW,QAC1C,MAAM,YAAY,CADE;AAEtB,iBAAO,KAAK;AACZ,qBAAW;AAJb;AANF,SAYG;AACH,WAAK,KAAK;AACV,WAAK,qBAAqB;AAC1B,WAAK,iBAAiB;AACtB,aAAO,QAAQ,IAAI;AAhRuC;AAsR5D,gCAAU;AACR,4BAAW;AACX,WAAK;AAxRqD;;AA8R5D,aAAS,SAAS,uBAAuB;AACvC,WAAK,iBAAiB;AACtB,WAAK;AAhSqD;AAuS5D,iBAAa,SAAS,0BAA0B;AAC9C,UAAI,CAAC,KAAK,yBACC,KAAK,KAAK,cAAc,KAAK,UAAS,QAAQ;AACnD,YAAI,cAAc,KAAK,aAAa;AACpC,eAAQ,YAAY,YAAY,WAAW,KACnC,YAAY;AAHtB,SAIG,OAAO;AACZ;AAP4C;AAU9C,aAAO,KAAK,KAAK,cAAc,QAAQ,UAAS,QAAQ;AACtD,eAAO,KAAK,aAAa;AAD3B,SAEG;AACH,WAAK,KAAK;AACV,WAAK,qBAAqB;AAC1B,WAAK,iBAAiB;AAtToC;AA4T5D,sBAAkB,SAAS,6BAA6B,cACA,QAAQ;AAC9D,UAAI,cAAc,KAAK,aAAa;AAGpC,UAAI,YAAY,wBAAwB;AACtC,oBAAY,uBAAuB,QAAQ;AALiB;AA7TJ;AAyU5D,sBAAkB,SAAS,6BAA6B,mBACA,QAAQ;AAC9D,UAAI,cAAc,KAAK,aAAa;AACpC,UAAI,GAAG;AAEP,WAAK,IAAI,GAAG,KAAK,kBAAkB,QAAQ,IAAI,IAAI,KAAK;AACtD,oBAAY,aAAa,QAAQ,KAAK,kBAAkB,QAAQ;AAChE,oBAAY,aAAa,UAAU,KACjC,kBAAkB,UAAU;AAP8B;AAS9D,kBAAY,aAAa,YAAY,kBAAkB;AAGvD,WAAK,IAAI,GAAG,IAAI,YAAY,YAAY,QAAQ,KAAK;AACnD,oBAAY,YAAY,GAAG;AAbiC;AAgB9D,UAAI,kBAAkB,WAAW;AAC/B,oBAAY,wBAAwB;AACpC,aAAK;AAlBuD;AA1UJ;AAAA;AAgW9D,SAAO;AAGT,CAjXoB;;IAiXD;AACjB,wBAAY;AAAO;;AACjB,SAAK,aAAa;AAClB,SAAK,SAAS;AACd,SAAK,YAAY,QAAQ,QAAQ;AAGnC;;;;gCAAY,KAAK;AAAW;;AAC1B,eAAS,WAAW,OAAO;AAGzB,YAAI,QAAO,0DAAU,YAAY,UAAU,MAAM;AAC/C,iBAAO;AAJgB;AAMzB,YAAI,OAAO,IAAI,QAAQ;AACrB,iBAAO,OAAO,IAAI;AAPK;AASzB,YAAI;AACJ,YAAI;AACJ,YAAK,UAAS,MAAM,WAAW,yBAAc,SAAS;AAEpD,cAAI,eAAe,aAAa,UAAU,QAAQ,WAAW;AAC7D,cAAI,UAAU,QAAQ;AAEpB,qBAAS;AAFX,qBAGW,cAAc;AACvB,qBAAS,IAAI,MAAM,YAAY,QAAQ,MAAM,YACd,MAAM;AAFhC,iBAGA;AACL,qBAAS,IAAI,MAAM,YAAY;AAVmB;AAYpD,iBAAO,IAAI,OAAO;AAClB,iBAAO;AAxBgB;AA0BzB,iBAAS,mBAAQ,SAAS,KAAK;AAC/B,eAAO,IAAI,OAAO;AAGlB,iBAAS,KAAK,OAAO;AACnB,cAAI;cAAM,IAAI;AACd,iBAAS,SAAO,OAAO,yBAAyB,GAAG,KAAK;AACtD,gBAAI,OAAO,eAAe;AAHT;AAKnB,cAAI,OAAO,KAAK,UAAU,eACtB,OAAO,KAAK,UAAU,YAAY;AACpC;AAPiB;AASnB,iBAAO,KAAK,WAAW,KAAK;AAvCL;AAyCzB,eAAO;AA1CiB;AA6C1B,UAAI,CAAC,KAAK,QAAQ;AAChB,aAAK,WAAW,QAAQ,UAAU,UAAU;AAC1C,mBAAS,KAAK,MAAM,EAAE,MAAM;AAD9B,WAEG;AACH;AAjDwB;AAoD1B,UAAI,SAAS,IAAI;AACjB,UAAI,IAAI,EAAE,MAAM,WAAW;AAC3B,WAAK,UAAU,KAAK,YAAM;AACxB,eAAK,WAAW,QAAQ,UAAU,UAAU;AAC1C,mBAAS,KAAK,MAAM;AACnB;AAHL;AAOF;;;qCAAiB,MAAM,UAAU;AAC/B,WAAK,WAAW,KAAK;AAGvB;;;wCAAoB,MAAM,UAAU;AAClC,UAAI,IAAI,KAAK,WAAW,QAAQ;AAChC,WAAK,WAAW,OAAO,GAAG;AAG5B;;;gCAAY;AACV,WAAK,aAAa;AA9EH;;;;;;AAwFnB,IAAI,qBAAsB,mBAAmB;AAC3C,MAAI,mBAAmB;AAEvB,WAAS,eAAe;AACtB,QAAI,OAAO,cAAc,aAAa;AACpC,aAAO;AAFa;AAItB,QAAI,kCAAkB,cAAc;AAClC,aAAO,kCAAkB;AALL;AAOtB,QAEI,eAAe;AACjB,aAAO,cAAc,QAAQ,6BAA6B;AAVtC;AAYtB,UAAM,IAAI,MAAM;AAfyB;AAkB3C,MAAI;AAGJ,WAAS,wBAAwB;AAC/B,QAAI;AACJ,QAAI,iCAAiC;AACnC,aAAO,gCAAgC;AAHV;AAK/B,sCAAkC;AAuBhC,QAAI,SAAS,yBAAyB,UAAU,UAAU;AACxD,iBAAK,WAAW,gBAAgB,YAAY;AAC1C,iBAAS,OAAO,wBAAwB;AAD1C;AADF;AAKA,WAAO,gCAAgC;AAEzC,WAAO,gCAAgC;AAxDE;AA2D3C,WAAS,iBAAiB,KAAK;AAI7B,QAAI,UAAU,qBAAqB,MAAM;AACzC,WAAO,IAAI,gBAAgB,IAAI,KAAK,CAAC;AAhEI;AAmE3C,MAAI,iBAAiB,IAAI;AAEzB,WAAS,UAAU,MAAM,MAAM;AAC7B,QAAI,QAAQ,eAAe,IAAI,OAAO;AACpC,YAAM,IAAI,MAAM;AAFW;AAK7B,SAAK,OAAO;AACZ,SAAK,YAAY;AACjB,SAAK,uBAAuB;AAE5B,SAAK,mBAAmB;AACxB,SAAK,QAAQ;AACb,SAAK,aAAa;AAClB,SAAK,kBAAkB;AAEvB,QAAI,MAAM;AACR,qBAAe,IAAI,MAAM;AACzB,WAAK,oBAAoB;AACzB;AAjB2B;AAoB7B,SAAK;AAzFoC;AA4F3C,YAAU;AACR,QAAI,UAAU;AACZ,aAAO,KAAK,iBAAiB;AAFuB;AAKtD,QAAI,OAAO;AACT,aAAO,KAAK;AANwC;AAStD,QAAI,iBAAiB;AACnB,aAAO,KAAK;AAVwC;AAatD,yBAAqB,SAAS,6BAA6B,MAAM;AAC/D,WAAK,QAAQ;AACb,WAAK,kBAAsB,yBAAe,QAAQ,UAAU;AAC5D,WAAK,gBAAgB,GAAG,SAAS,YAAY,CAA7C;AAIA,WAAK,iBAAiB;AApB8B;AAuBtD,iBAAa,SAAS;AAAuB;;AAM3C,UACI,CAAC,oBAAoB,CAAC,kCAAkB,oBACxC,OAAO,WAAW,aAAa;AACjC,YAAI,YAAY;AAEhB,YAAI;AAGF,cACI,CAAC,wBAAa,OAAO,SAAS,MAAM,YAAY;AAClD,wBAAY,iBACV,IAAI,IAAI,WAAW,OAAO,UAAU;AANtC;AAWF,cAAI,SAAS,IAAI,OAAO;AACxB,cAAI,iBAAqB,yBAAe,QAAQ,UAAU;AAC1D,cAAI,iBAAiB,0BAAM;AACzB,mBAAO,oBAAoB,SAAS;AACpC,2BAAe;AACf,mBAAO;AACP,gBAAI,OAAK,WAAW;AAClB,qBAAK,iBAAiB,OAAO,IAAI,MAAM;AADzC,mBAEO;AAGL,qBAAK;AATkB;AAA3B;AAaA,cAAI,gBAAgB,yBAAM;AACxB,gBAAI,CAAC,OAAK,YAAY;AAGpB;AAJsB;AAA1B;AAOA,iBAAO,iBAAiB,SAAS;AAEjC,yBAAe,GAAG,QAAS,gBAAS;AAClC,mBAAO,oBAAoB,SAAS;AACpC,gBAAI,OAAK,WAAW;AAClB;AACA;AAJgC;AAMlC,gBAAI,oBAAoB,QAAQ,KAAK;AACrC,gBAAI,mBAAmB;AACrB,qBAAK,kBAAkB;AACvB,qBAAK,QAAQ;AACb,qBAAK,aAAa;AAClB,kBAAI,CAAC,KAAK,kBAAkB;AAC1B,uBAAK,uBAAuB;AAC5B,iDAAiC;AANd;AAQrB,qBAAK,iBAAiB;AAEtB,6BAAe,KAAK,aAAa,EAC/B,WAAW;AAXf,mBAaO;AACL,qBAAK;AACL,6BAAe;AACf,qBAAO;AAvByB;AAApC;AA2BA,yBAAe,GAAG,eAAe,UAAU,MAAM;AAC/C,oBAAQ,IAAI,MAAM,SAAS;AAD7B;AAGA,yBAAe,GAAG,iBAAiB,UAAU,MAAM;AACjD,oBAAQ,MAAM,MAAM,SAAS;AAD/B;AAIA,yBAAe,GAAG,SAAU,gBAAS;AACnC,mBAAO,oBAAoB,SAAS;AACpC,gBAAI,OAAK,WAAW;AAClB;AACA;AAJiC;AAMnC,gBAAI;AACF;AADF,cAEE,OAAO,GAAG;AAEV,qBAAK;AAV4B;AAArC;AAcA,cAAI,WAAW,oBAAY;AACzB,gBAAI,uBACF,kCAAkB,2BAClB,CAAC;AACH,gBAAI,UAAU,IAAI,WAAW,CAAC,uBAAuB,MAAM;AAG3D,gBAAI;AACF,6BAAe,KAAK,QAAQ,SAAS,CAAC,QAAQ;AADhD,cAEE,OAAO,IAAI;AACX,8BAAK;AACL,sBAAQ,KAAK;AACb,6BAAe,KAAK,QAAQ;AAZL;AAA3B;AAoBA;AACA;AAxGF,UAyGE,OAAO,GAAG;AACV,0BAAK;AA7G0B;AARQ;AA0H3C,WAAK;AAjJ+C;AAoJtD,sBAAkB,SAAS;AAA4B;;AACrD,UAAI,CAAC,oBAAoB,CAAC,kCAAkB,kBAAkB;AAC5D,wBAAK;AACL,2BAAmB;AAHgC;AAMrD,8BAAwB,KAAM,gCAAyB;AACrD,YAAI,OAAK,WAAW;AAClB,iBAAK,iBAAiB,OAAO,IAAI,MAAM;AACvC;AAHmD;AASrD,YAAI,uBAAuB,eAAe;AAC1C,YAAI,OAAO,IAAI,aAAa;AAC5B,eAAK,QAAQ;AAGb,YAAI,KAAK,SAAU;AAInB,YAAI,gBAAoB,yBAAe,KAAK,WAAW,IAAI;AAC3D,6BAAqB,MAAM,eAAe;AAE1C,YAAI,iBAAqB,yBAAe,IAAI,KAAK,WAAW;AAC5D,eAAK,kBAAkB;AACvB,eAAK,iBAAiB;AAvBxB;AA1JoD;AAwLtD,aAAS,SAAS,oBAAoB;AACpC,WAAK,YAAY;AACjB,UAAI,KAAK,YAAY;AAEnB,aAAK,WAAW;AAChB,aAAK,aAAa;AALgB;AAOpC,qBAAe,OAAO,KAAK;AAC3B,WAAK,QAAQ;AACb,UAAI,KAAK,iBAAiB;AACxB,aAAK,gBAAgB;AACrB,aAAK,kBAAkB;AAXW;AAxLgB;AAAA;AAwMxD,YAAU,WAAW,UAAU,MAAM;AACnC,QAAI,eAAe,IAAI,OAAO;AAC5B,aAAO,eAAe,IAAI;AAFO;AAInC,WAAO,IAAI,UAAU,MAAM;AAJ7B;AAOA,SAAO;AA3SO,CAAC;AAkTjB,IAAI,2BAA4B,yBAAyB;AACvD,WAAS,gBAAgB,gBAAgB,aAAa,eAC7B,mBAAmB;AAC1C,SAAK,iBAAiB;AACtB,SAAK,cAAc;AACnB,SAAK,aAAa,IAAI;AACtB,SAAK,aAAiB,4BAAW,YAAY;AAC7C,SAAK,wBAAwB;AAC3B,eAAS,kCAAkB;AAC3B,oBAAc,kCAAkB;AAFa,KAAtB;AAKzB,SAAK,YAAY;AACjB,SAAK,oBAAoB;AACzB,SAAK,sBAAsB;AAE3B,SAAK,iBAAiB;AACtB,SAAK,cAAc;AACnB,SAAK,gBAAgB;AAErB,SAAK,YAAY;AACjB,SAAK,eAAe;AACpB,SAAK,yBAAyB;AAE9B,SAAK;AAxBgD;AA0BvD,kBAAgB;AACd,aAAS,SAAS;AAA0B;;AAC1C,UAAI,KAAK,mBAAmB;AAC1B,eAAO,KAAK,kBAAkB;AAFU;AAK1C,WAAK,YAAY;AACjB,WAAK,oBAAoB;AAEzB,UAAI,KAAK,qBAAqB;AAC5B,aAAK,oBAAoB,OACvB,IAAI,MAAM;AAV4B;AAa1C,UAAI,SAAS;AAGb,WAAK,UAAU,QAAQ,UAAU,MAAM;AACrC,YAAI,MAAM;AACR,iBAAO,KAAK,KAAK;AAFkB;AAAvC;AAKA,WAAK,YAAY;AACjB,WAAK,eAAe;AAEpB,UAAI,aAAa,KAAK,eAAe,gBAAgB,aAAa;AAClE,aAAO,KAAK;AACZ,cAAQ,IAAI,QAAQ,KAAK,YAAM;AAC7B,eAAK,WAAW;AAChB,YAAI,OAAK,gBAAgB;AACvB,iBAAK,eAAe;AAHO;AAM7B,YAAI,OAAK,gBAAgB;AACvB,iBAAK,eAAe;AACpB,iBAAK,iBAAiB;AARK;AAU7B,eAAK,kBAAkB;AAVzB,SAWG,KAAK,kBAAkB;AAC1B,aAAO,KAAK,kBAAkB;AAvCN;AA0C1B,yBAAqB,SAAS,sCAAsC;AAClE,UAAI,iBAAiB,KAAK;AAC1B,UAAI,cAAc,KAAK;AAEvB,qBAAe,GAAG,aAAa,UAAS,MAAM;AAAM;;AAClD,0BAAO,KAAK;AACZ,aAAK,cAAc,KAAK,eAAe;AACvC,aAAK,YAAY,aAAc,eAAQ;AACrC,iBAAK;AACH,oBAAQ,IAAI;AACZ,mBAAO,IAAI;AAFQ;AADvB;AAMA,aAAK,SAAS,YAAM;AAClB,iBAAK,YAAY,OAAO,KAAc;AAAkB,gBAAhB;gBAAO;;AAC7C,gBAAI,MAAM;AACR,mBAAK;AACL;AAHoD;AAKtD,8BAAO,yBAAc;AAGrB,iBAAK,QAAQ,IAAI,WAAW,QAAQ,GAAG,CAAC;AAR1C,aASG,MAAO,kBAAW;AACnB,iBAAK,MAAM;AAVb;AADF;AAeA,aAAK,WAAY,kBAAW;AAC1B,iBAAK,YAAY,OAAO;AAD1B;AAxBF,SA2BG;AAEH,qBAAe,GAAG,sBAAsB,UAAS;AAAM;;AACrD,YAAI,oBAAoB;AACxB,YAAI,aAAa,KAAK;AACtB,mBAAW,aAAa,KAAK,YAAM;AAGjC,cAAI,CAAC,WAAW,wBACZ,CAAC,WAAW,kBAAkB;AAChC,gBAAI,QAAK,eAAe;AACtB,kBAAI,eAAc,QAAK;AACvB,kBAAI,aAAY,YAAY;AAC1B,6BAAY,WAAW,QAAK;AAHR;AADQ;AAOhC,uBAAW,aAAc,eAAQ;AAC/B,kBAAI,cAAc,QAAK;AACvB,kBAAI,YAAY,YAAY;AAC1B,4BAAY;AACV,0BAAQ,IAAI;AACZ,yBAAO,IAAI;AAFU;AAHM;AAAjC;AAX+B;AAsBjC,4BAAkB;AAChB,kCAAsB,WAAW;AACjC,8BAAkB,WAAW;AAC7B,2BAAe,WAAW;AAHF;AAtB5B,WA2BG,kBAAkB;AAErB,eAAO,kBAAkB;AAhC3B,SAiCG;AAEH,qBAAe,GAAG,kBAAkB,UAAS,MAAM,MAAM;AACvD,0BAAO,KAAK;AACZ,YAAI,eACF,KAAK,eAAe,eAAe,KAAK,OAAO,KAAK;AAEtD,aAAK,SAAS,YAAM;AAClB,uBAAa,OAAO,KAAc;AAAkB,gBAAhB;gBAAO;;AACzC,gBAAI,MAAM;AACR,mBAAK;AACL;AAHgD;AAKlD,8BAAO,yBAAc;AACrB,iBAAK,QAAQ,IAAI,WAAW,QAAQ,GAAG,CAAC;AAN1C,aAOG,MAAO,kBAAW;AACnB,iBAAK,MAAM;AARb;AADF;AAaA,aAAK,WAAY,kBAAW;AAC1B,uBAAa,OAAO;AADtB;AAlBF,SAqBG;AAEH,qBAAe,GAAG,UAAU,SAAS,aAAa,MAAM;AACtD,YAAI,UAAU,KAAK;AACnB,aAAK,WAAW,KAAK,QAAQ;AAC7B,YAAI,cAAc,KAAK;AACvB,YAAI,cAAc,IAAI,iBAAiB,SAAS,MAAM;AACtD,aAAK,cAAc;AACnB,oBAAY,YAAY,QAAQ;AANlC,SAOG;AAEH,qBAAe,GAAG,mBACA,SAAS,yBAAyB;AAAW;;AAC7D,aAAK,sBAAsB;AAE3B,YAAI,YAAY,YAAY;AAC1B,cAAI,iBAAkB,kCAAa;AACjC,oBAAK,oBAAoB,QAAQ,EAC/B;AAFJ;AAKA,sBAAY,WAAW,gBAAgB,UAAU;AANnD,eAOO;AACL,eAAK,oBAAoB,OACnB,4BAAkB,UAAU,SAAS,UAAU;AAZM;AAc7D,eAAO,KAAK,oBAAoB;AAflC,SAgBG;AAEH,qBAAe,GAAG,qBACA,SAAS,2BAA2B,WAAW;AAC/D,oBAAY,YAAY,OAClB,4BAAkB,UAAU,SAAS,UAAU;AAHvD,SAIG;AAEH,qBAAe,GAAG,cAAc,SAAS,oBAAoB,WAAW;AACtE,aAAK,YAAY,YAAY,OACvB,8BAAoB,UAAU;AAFtC,SAGG;AAEH,qBAAe,GAAG,cAAc,SAAS,oBAAoB,WAAW;AACtE,aAAK,YAAY,YAAY,OACvB,8BAAoB,UAAU;AAFtC,SAGG;AAEH,qBAAe,GAAG,sBACA,SAAS,4BAA4B,WAAW;AAChE,aAAK,YAAY,YAAY,OACvB,sCAA4B,UAAU,SAAS,UAAU;AAHjE,SAIG;AAEH,qBAAe,GAAG,gBACA,SAAS,sBAAsB,WAAW;AAC1D,aAAK,YAAY,YAAY,OACvB,gCAAsB,UAAU,SAAS,UAAU;AAH3D,SAIG;AAEH,qBAAe,GAAG,cAAc,SAAS,cAAc,MAAM;AAC3D,aAAK,uBAAuB,QAAQ;AADtC,SAEG;AAEH,qBAAe,GAAG,mBAAmB,SAAS,cAAc,MAAM,CAAlE,GACG;AAEH,qBAAe,GAAG,mBAAmB,SAAS,gBAAgB,MAAM;AAClE,YAAI,KAAK,WAAW;AAClB;AAFgE;AAIlE,YAAI,OAAO,KAAK,UAAU,KAAK;AAE/B,aAAK,MAAM,QAAQ;AACnB,aAAK,iBAAiB,KAAK,cAAc,KAAK;AAPhD,SAQG;AAEH,qBAAe,GAAG,mBAAmB,SAAS,gBAAgB,MAAM;AAClE,YAAI,KAAK,WAAW;AAClB;AAFgE;AAIlE,YAAI,OAAO,KAAK,UAAU,KAAK;AAE/B,aAAK,iBAAiB,KAAK,cAAc,KAAK;AANhD,SAOG;AAEH,qBAAe,GAAG,aAAa,SAAS,aAAa;AAAM;;AACzD,YAAI,KAAK,WAAW;AAClB;AAFuD;AAKzD,YAAI,KAAK,KAAK;AACd,YAAI,OAAO,KAAK;AAChB,YAAI,KAAK,WAAW,QAAQ,KAAK;AAC/B;AARuD;AAWzD,gBAAQ;AACN,eAAK;AACH,gBAAI,eAAe,KAAK;AAExB,gBAAI,WAAW,cAAc;AAC3B,kBAAI,gBAAgB,aAAa;AACjC,8BAAK,gCAAgC;AACrC,mBAAK,WAAW,QAAQ,IAAI;AAC5B;AAPJ;AASE,gBAAI,eAAe;AACnB,gBAAI,kCAAkB,aAAa,kBAAY,iBAC3C,kBAAY,iBAAiB,SAAS;AACxC;AACE,oDAAa,MAAM,KAAK;AACtB,oCAAY,iBAAiB,UAAU,MAAM;AAFlC;AAAA;AAZnB;AAkBE,gBAAI,uCAA0B;AAC5B,8BAAgB,kCAAkB;AAClC,+BAAiB,kCAAkB;AACnC;AAH0C,aAA7B;AAKf,gBAAI,YAAa,6BAAa;AAC5B,sBAAK,WAAW,QAAQ,IAAI;AAD9B;AAIA,iBAAK,WAAW,KAAK,CAAC,OAAO;AAC7B;AACF,eAAK;AACH,iBAAK,WAAW,QAAQ,IAAI,KAAK;AACjC;AACF;AACE,kBAAM,IAAW,0CAAiC;;AA7CxD,SA+CG;AAEH,qBAAe,GAAG,OAAO,SAAS,aAAa,MAAM;AACnD,YAAI,KAAK,WAAW;AAClB;AAFiD;AAKnD,YAAI,KAAK,KAAK;AACd,YAAI,YAAY,KAAK;AACrB,YAAI,OAAO,KAAK;AAChB,YAAI,YAAY,KAAK,UAAU;AAC/B,YAAI;AACJ,YAAI,UAAU,KAAK,QAAQ,KAAK;AAC9B;AAXiD;AAcnD,gBAAQ;AACN,eAAK;AACH,wBAAY,KAAK;AACjB,sCAAe,IAAI,WAAW,UAAU;AACxC;AACF,eAAK;AACH,wBAAY,KAAK;AACjB,sBAAU,KAAK,QAAQ,IAAI;AAG3B,gBAAI,0BAA0B;AAC9B,gBAAI,aAAa,UAAU,aACvB,UAAU,KAAK,SAAS,yBAAyB;AACnD,wBAAU,qBAAqB;AARnC;AAUE;AACF;AACE,kBAAM,IAAW,mCAA0B;;AA/BjD,SAiCG;AAEH,qBAAe,GAAG,eAAe,SAAS,qBAAqB,MAAM;AACnE,YAAI,KAAK,WAAW;AAClB;AAFiE;AAKnE,YAAI,cAAc,KAAK;AACvB,YAAI,YAAY,YAAY;AAC1B,sBAAY;AACV,oBAAQ,KAAK;AACb,mBAAO,KAAK;AAFS;AAP0C;AAArE,SAYG;AAEH,qBAAe,GAAG,aAAa,SAAS,eAAe,MAAM;AAC3D,YAAI,KAAK,WAAW;AAClB;AAFyD;AAK3D,YAAI,OAAO,KAAK,UAAU,KAAK,UAAU;AACzC,YAAI,cAAc,KAAK,aAAa,KAAK;AAEzC,YAAI,YAAY,wBAAwB;AACtC,sBAAY,uBAAuB,OAAO,KAAK;AADjD,eAEO;AACL,gBAAM,IAAI,MAAM,KAAK;AAXoC;AAc3D,YAAI,YAAY,cAAc;AAE5B,sBAAY,aAAa,YAAY;AACrC,eAAK,IAAI,IAAI,GAAG,IAAI,YAAY,YAAY,QAAQ,KAAK;AACvD,wBAAY,YAAY,GAAG;AAJD;AAd6B;AAA7D,SAqBG;AAEH,qBAAe,GAAG,sBACd,SAAS,4BAA4B,MAAM;AAC7C,YAAI,KAAK,WAAW;AAClB;AAF2C;AAI7C,YAAI,YAAY,KAAK;AACrB,YAAI,cAAc,KAAK;AACvB,YAAI,YAAY,sBAAsB;AACpC,sBAAY,qBAAqB;AAPU;AAS7C,4BAAoB,OAAO;AAV7B,SAWG;AAEH,qBAAe,GAAG,cAAc,UAAS,MAAM;AAC7C,YAAI,KAAK,WAAW;AAClB,iBAAO,QAAQ,OAAO,IAAI,MAAM;AAFW;AAK7C,YAAI,OAAO,aAAa,aAAa;AAGnC,iBAAO,QAAQ,OAAO,IAAI,MAAM;AARW;AAW7C,YAAI,WAAW,KAAK;AACpB,YAAI,aAAa,KAAK;AACtB,YAAI,eAAe,KAAK,eAAe,GAAG;AACxC,iBAAO,QAAQ,OACb,IAAI,MAAM;AAf+B;AAkB7C,mBAAW,QAAQ,UAAU,SAAS,QAAQ;AAC5C,cAAI,MAAM,IAAI;AACd,cAAI,SAAS,YAAY;AACvB,gBAAI,QAAQ,IAAI;AAChB,gBAAI,SAAS,IAAI;AACjB,gBAAI,OAAO,QAAQ;AACnB,gBAAI,aAAa,OAAO;AACxB,gBAAI,MAAM,IAAI,WAAW,OAAO;AAChC,gBAAI,YAAY,SAAS,cAAc;AACvC,sBAAU,QAAQ;AAClB,sBAAU,SAAS;AACnB,gBAAI,SAAS,UAAU,WAAW;AAClC,mBAAO,UAAU,KAAK,GAAG;AACzB,gBAAI,OAAO,OAAO,aAAa,GAAG,GAAG,OAAO,QAAQ;AACpD,gBAAI,GAAG;AAEP,gBAAI,eAAe,GAAG;AACpB,mBAAK,IAAI,GAAG,IAAI,GAAG,IAAI,YAAY,KAAK,GAAG,KAAK,GAAG;AACjD,oBAAI,KAAK,KAAK;AACd,oBAAI,IAAI,KAAK,KAAK,IAAI;AACtB,oBAAI,IAAI,KAAK,KAAK,IAAI;AAJJ;AAAtB,mBAMO,IAAI,eAAe,GAAG;AAC3B,mBAAK,IAAI,GAAG,IAAI,GAAG,IAAI,YAAY,KAAK,GAAG,KAAK;AAC9C,oBAAI,KAAK,KAAK;AAFW;AApBN;AAyBvB;AAAU,oBAAM;AAAK;AAAO;AAApB;AAzBV;AA2BA,cAAI,UAAU,YAAY;AACxB,mBAAO,IAAI,MAAM;AADnB;AAGA,cAAI,MAAM;AAhCL;AAlBT,SAoDG;AAEH,qBAAe,GAAG,oBAAoB,UAAU,MAAM;AACpD,YAAI,KAAK,WAAW;AAClB,iBAAO,QAAQ,OAAO,IAAI,MAAM;AAFkB;AAIpD,eAAO,KAAK,kBAAkB,MAAM,EAClC,MAAM,KAAK;AALf,SAOG;AAzZqB;AA4Z1B,aAAS,SAAS,0BAA0B;AAC1C,aAAO,KAAK,eAAe,gBAAgB,WAAW;AA7Z9B;AAga1B,aAAS,SAAS,wBAAwB,YAAY;AAAY;;AAChE,UAAI,CAAC,iBAAM,eAAe,cAAc,KAAK,aAAa,KAAK,UAAU;AACvE,eAAO,QAAQ,OAAO,IAAI,MAAM;AAF8B;AAKhE,UAAI,YAAY,aAAa;AAC7B,UAAI,aAAa,KAAK,cAAc;AAClC,eAAO,KAAK,aAAa;AAPqC;AAShE,UAAI,eAAe,eAAe,gBAAgB,WAAW,EAC3D,wBACC,KAAM,oBAAa;AACpB,YAAI,QAAK,WAAW;AAClB,gBAAM,IAAI,MAAM;AAFE;AAIpB,YAAI,OAAO,IAAI,aAAa,WAAqB;AACjD,gBAAK,UAAU,aAAa;AAC5B,eAAO;AARK;AAUd,WAAK,aAAa,aAAa;AAC/B,aAAO;AApbiB;AAub1B,kBAAc,SAAS,kCAAkC,KAAK;AAC5D,kBAAY,eAAe,gBAAgB,gBAAgB,EACzD,YACC,MAAM,UAAU,QAAQ;AACzB,eAAO,QAAQ,OAAO,IAAI,MAAM;AAH3B;AAxbiB;AA+b1B,oBAAgB,SAAS,+BAA+B,WAAW,QAAQ;AACzE,kBAAY,eAAe,gBAAgB;AACzC;AACA;AAF2D,OAAtD;AAhciB;AAsc1B,qBAAiB,SAAS,kCAAkC;AAC1D,aAAO,KAAK,eAAe,gBAAgB,mBAAmB;AAvctC;AA0c1B,oBAAgB,SAAS,+BAA+B,IAAI;AAC1D,aAAO,KAAK,eAAe,gBAAgB,kBAAkB,EAC3D;AA5csB;AAgd1B,mBAAe,SAAS,gCAAgC;AACtD,aAAO,KAAK,eAAe,gBAAgB,iBAAiB;AAjdpC;AAod1B,wCAAc;AACZ,aAAO,KAAK,eAAe,gBAAgB,eAAe;AArdlC;;AAwd1B,oBAAgB,SAAS,iCAAiC;AACxD,aAAO,KAAK,eAAe,gBAAgB,kBAAkB;AAzdrC;AA4d1B,mBAAe,SAAS,gCAAgC;AACtD,aAAO,KAAK,eAAe,gBAAgB,iBAAiB;AA7dpC;AAge1B,gBAAY,SAAS,6BAA6B;AAChD,aAAO,KAAK,eAAe,gBAAgB,cAAc;AAjejC;AAoe1B,iBAAa,SAAS,8BAA8B;AAClD,kBAAY,eAAe,gBAAgB,eAAe,MACxD,KAAK,SAAS,kBAAkB,SAAS;AACzC;AACE,gBAAM,QAAQ;AACd,oBAAW,QAAQ,KAAS,uBAAS,QAAQ,MAAM;AAF9C;AAFF;AAreiB;AA8e1B,cAAU,SAAS,2BAA2B;AAC5C,aAAO,KAAK,eAAe,gBAAgB,YAAY;AA/e/B;AAkf1B,kBAAc,SAAS;AAA+B;;AACpD,WAAK,eAAe,gBAAgB,WAAW,MAAM,KAAK,YAAM;AAC9D,aAAK,IAAI,IAAI,GAAG,KAAK,QAAK,UAAU,QAAQ,IAAI,IAAI,KAAK;AACvD,cAAI,OAAO,QAAK,UAAU;AAC1B,cAAI,MAAM;AACR,iBAAK;AAHgD;AADK;AAO9D,gBAAK,WAAW;AAChB,gBAAK,WAAW;AARlB;AAnfwB;AAAA;AA+f5B,SAAO;AAzhBa,CAAC;AAoiBvB,IAAI,sBAAuB,oBAAoB;AAC7C,WAAS,aAAa;AACpB,SAAK,OAAO,OAAO,OAAO;AAFiB;AAK7C,aAAW;AAKT,eAAW,SAAS,qBAAqB,OAAO;AAC9C,UAAI,KAAK,KAAK,QAAQ;AACpB,eAAO,KAAK,KAAK;AAF2B;AAK9C,UAAI;AACF,oBAAY;AACZ,cAAM;AACN,kBAAU;AAHF;AAKV,WAAK,KAAK,SAAS;AAEnB,aAAO;AAjBY;AA6BrB,SAAK,SAAS,eAAe,OAAO,UAAU;AAG5C,UAAI,UAAU;AACZ,aAAK,UAAU,OAAO,WAAW,QAAQ,KAAK;AAC9C,eAAO;AALmC;AAU5C,UAAI,MAAM,KAAK,KAAK;AAIpB,UAAI,CAAC,OAAO,CAAC,IAAI,UAAU;AACzB,cAAM,IAAW,sDAA4C;AAfnB;AAkB5C,aAAO,IAAI;AA/CQ;AAqDrB,aAAS,SAAS,mBAAmB,OAAO,MAAM;AAChD,UAAI,MAAM,KAAK,UAAU;AAEzB,UAAI,WAAW;AACf,UAAI,OAAO;AACX,UAAI,WAAW,QAAQ;AA1DJ;AA6DrB,gBAAY,SAAS,sBAAsB,OAAO;AAChD,UAAI,OAAO,KAAK;AAEhB,UAAI,CAAC,KAAK,QAAQ;AAChB,eAAO;AAJuC;AAMhD,aAAO,KAAK,OAAO;AAnEA;AAsErB,aAAS,SAAS,mBAAmB,OAAO;AAC1C,aAAO,KAAK,WAAW;AAvEJ;AA6ErB,aAAS,SAAS,mBAAmB,OAAO;AAC1C,UAAI,OAAO,KAAK;AAChB,UAAI,CAAC,KAAK,UAAU,CAAC,KAAK,OAAO,UAAU;AACzC,eAAO;AAHiC;AAK1C,aAAO,KAAK,OAAO;AAlFA;AAqFrB,WAAO,SAAS,mBAAmB;AACjC,WAAK,OAAO,OAAO,OAAO;AAtFP;AAAA;AAyFvB,SAAO;AA9FQ,CAAC;AAsGlB,IAAI,sBAAuB,oBAAoB;AAC7C,WAAS,WAAW,oBAAoB;AACtC,SAAK,sBAAsB;AAQ3B,SAAK,aAAa;AAVyB;AAa7C,aAAW;AAKT,QAAI,UAAU;AACZ,aAAO,KAAK,oBAAoB,WAAW;AANW;AAcxD,YAAQ,SAAS,oBAAoB;AACnC,WAAK,oBAAoB;AAf6B;AA0BxD,UAAM,SAAS,gBAAgB,aAAa,YAAY;AACtD,aAAO,KAAK,QAAQ,KAAK,MAAM,KAAK,SAAS;AA3BS;AAAA;AA+B1D,SAAO;AA5CQ,CAAC;AAmDlB,IAAI,8BAA+B,4BAA4B;AAC7D,MAAI,oBAAoB,IAAI;AAE5B,WAAS,mBAAmB,UAAU,QAAQ,MAAM,YAAY,cACpC,YAAY,eAAe;AACrD,SAAK,WAAW;AAChB,SAAK,SAAS;AACd,SAAK,OAAO;AACZ,SAAK,aAAa;AAClB,SAAK,kBAAkB;AACvB,SAAK,eAAe;AACpB,SAAK,aAAa;AAClB,SAAK,gBAAgB;AACrB,SAAK,UAAU;AACf,SAAK,wBAAwB;AAC7B,SAAK,gBAAgB;AACrB,SAAK,2BAA2B;AAChC,SAAK,YAAY;AACjB,SAAK,aAAa;AAClB,SAAK,OAAO,IAAI,WAAW;AAE3B,SAAK,iBAAiB,KAAK,UAAU,KAAK;AAC1C,SAAK,qBAAqB,KAAK,cAAc,KAAK;AAClD,SAAK,aAAa,KAAK,MAAM,KAAK;AAClC,SAAK,UAAU,OAAO,cAAc;AAxBuB;AA2B7D,qBAAmB;AAEjB,wBACI,SAAS,sCAAsC,cAAc;AAE/D,UAAI,KAAK,SAAS;AAChB,YAAI,kBAAkB,IAAI,KAAK,UAAU;AACvC,gBAAM,IAAI,MACR,qEACA,6DACA;AALY;AAOhB,0BAAkB,IAAI,KAAK,SAAS;AATyB;AAY/D,UAAI,KAAK,WAAW;AAClB;AAb6D;AAe/D,UAAI,kCAAkB,aAAa,kBAAY,kBAC3C,kBAAY,eAAe,SAAS;AACtC,aAAK,UAAU,kBAAY,eAAe,OAAO,KAAK,aAAa;AACnE,aAAK,QAAQ,KAAK,KAAK;AACvB,aAAK,QAAQ,iBAAiB,KAAK,QAAQ;AAnBkB;AAsB/D,UAAI,SAAS,KAAK;AAClB,WAAK,MAAU,2BAAe,OAAO,eAAe,KAAK,YAC3B,KAAK,MAAM,KAAK,eAChB,OAAO;AAErC,WAAK,IAAI;AACP,mBAAW,OAAO;AAClB,kBAAU,OAAO;AACjB;AACA,oBAAY,OAAO;AAJC;AAMtB,WAAK,kBAAkB;AACvB,WAAK,gBAAgB;AACrB,UAAI,KAAK,uBAAuB;AAC9B,aAAK;AApCwD;AAHpC;AA2C7B,YAAQ,SAAS,4BAA4B;AAC3C,WAAK,UAAU;AACf,WAAK,YAAY;AACjB,UAAI,KAAK,SAAS;AAChB,0BAAkB,OAAO,KAAK;AAJW;AAO3C,UACI,kCAAkB,cAAc;AAClC,aAAK,SAAa,2CAChB,+BAA+B,KAAK,YAAY;AAHpD,aAIO;AACL,aAAK,SAAS;AAZ2B;AA3ChB;AA2D7B,yBAAqB,SAAS,yCAAyC;AACrE,UAAI,CAAC,KAAK,eAAe;AACvB,YAAI,CAAC,KAAK,uBAAuB;AAC/B,eAAK,wBAAwB,KAAK;AAFb;AAIvB;AALmE;AAQrE,UAAI,KAAK,SAAS;AAChB,aAAK,QAAQ,mBAAmB,KAAK;AAT8B;AAYrE,UAAI,KAAK,SAAS;AAChB;AAbmE;AAerE,WAAK;AA1EsB;AA6E7B,eAAW,SAAS,+BAA+B;AACjD,WAAK,UAAU;AACf,UAAI,KAAK,WAAW;AAClB;AAH+C;AAKjD,UAAI,KAAK,KAAK,YAAY;AACxB,aAAK,KAAK,WAAW,KAAK;AAD5B,aAEO;AACL,aAAK;AAR0C;AA7EtB;AAyF7B,mBAAe,SAAS,mCAAmC;AACzD,UAAI,KAAK,4BAA4B,OAAO,WAAW,aAAa;AAClE,eAAO,sBAAsB,KAAK;AADpC,aAEO;AACL,gBAAQ,QAAQ,WAAW,KAAK,KAAK;AAJkB;AAzF9B;AAiG7B,WAAO,SAAS,2BAA2B;AACzC,UAAI,KAAK,WAAW;AAClB;AAFuC;AAIzC,WAAK,kBAAkB,KAAK,IAAI,oBAAoB,KAAK,cACvB,KAAK,iBACL,KAAK,gBACL,KAAK;AACvC,UAAI,KAAK,oBAAoB,KAAK,aAAa,UAAU,QAAQ;AAC/D,aAAK,UAAU;AACf,YAAI,KAAK,aAAa,WAAW;AAC/B,eAAK,IAAI;AACT,cAAI,KAAK,SAAS;AAChB,8BAAkB,OAAO,KAAK;AAHD;AAK/B,eAAK;AAPwD;AARxB;AAjGd;AAAA;AAuH/B,SAAO;AAlJgB,CAAC;AAyJ1B,IAAI,+BAAgC,4BAA4B;AAC9D,MAAI,YAAY;AAChB;AACE,4BAAO,IAAI;AACT,4BAAW,+CACA;AACX,gBAAU,KAAK;AAJZ;AAML,4BAAO,WAAW;AAChB,WAAK,IAAI,IAAI,GAAG,KAAK,UAAU,QAAQ,IAAI,IAAI,KAAK;AAClD,kBAAU,GAAG;AAFC;AANb;AAAA;AAFiB,CAAC;AAgB3B,IAAI,SAAS;AACwB;AACnC,8BAAU;AACV,0BAAQ;AAGV;QACE;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,c;;;;;;;;;;;;;;AC52EK;;AAGA;;AAkBP,SAAS,2BAA2B,CAvCpC;AAwCA,yBAAyB;AAMvB,UAAQ,SAAS,gCAAgC,YAAY;AAC3D,QAAI,UAAU,WAAW,KAAK;AAE9B,YAAQ;AACN,WAAK,qBAAe;AAClB,eAAO,IAAI,sBAAsB;AAEnC,WAAK,qBAAe;AAClB,eAAO,IAAI,sBAAsB;AAEnC,WAAK,qBAAe;AAClB,YAAI,YAAY,WAAW,KAAK;AAEhC,gBAAQ;AACN,eAAK;AACH,mBAAO,IAAI,4BAA4B;AACzC,eAAK;AACH,gBAAI,WAAW,KAAK,aAAa;AAC/B,qBAAO,IAAI,mCAAmC;AADhD,mBAEO,IAAI,WAAW,KAAK,UAAU;AACnC,qBAAO,IAAI,gCAAgC;AAJ/C;AAME,4BAAK;AACL;AACF,eAAK;AACH,mBAAO,IAAI,8BAA8B;;AAE7C,eAAO,IAAI,wBAAwB;AAErC,WAAK,qBAAe;AAClB,eAAO,IAAI,uBAAuB;AAEpC,WAAK,qBAAe;AAClB,eAAO,IAAI,sBAAsB;AAEnC,WAAK,qBAAe;AAClB,eAAO,IAAI,2BAA2B;AAExC,WAAK,qBAAe;AAClB,eAAO,IAAI,2BAA2B;AAExC,WAAK,qBAAe;AAClB,eAAO,IAAI,0BAA0B;AAEvC,WAAK,qBAAe;AAClB,eAAO,IAAI,2BAA2B;AAExC,WAAK,qBAAe;AAClB,eAAO,IAAI,gCAAgC;AAE7C;AACE,eAAO,IAAI,kBAAkB;;AAxDgB;AAAA;AAiErD,IAAI,6BAA8B,2BAA2B;AAC3D,WAAS,kBAAkB,YAAY,cAAc,cAAc;AACjE,SAAK,eAAe,gBAAgB;AACpC,SAAK,OAAO,WAAW;AACvB,SAAK,QAAQ,WAAW;AACxB,SAAK,OAAO,WAAW;AACvB,SAAK,WAAW,WAAW;AAC3B,SAAK,cAAc,WAAW;AAC9B,SAAK,kBAAkB,WAAW;AAClC,SAAK,qBAAqB,WAAW;AACrC,SAAK,yBAAyB,WAAW;AAEzC,QAAI,cAAc;AAChB,WAAK,YAAY,KAAK,iBAAiB;AAZwB;AADR;AAiB3D,oBAAkB;AAShB,sBACI,SAAS,kCAAkC,cAAc;AAC3D,UAAI,OAAO,KAAK;UAAM,OAAO,KAAK;UAAM,WAAW,KAAK;AACxD,UAAI,YAAY,SAAS,cAAc;AACvC,UAAI,QAAQ,KAAK,KAAK,KAAK,KAAK,KAAK;AACrC,UAAI,SAAS,KAAK,KAAK,KAAK,KAAK,KAAK;AAEtC,gBAAU,aAAa,sBAAsB,KAAK;AAIlD,UAAI,OAAO,WAAK,cAAc,CAC5B,KAAK,KAAK,IACV,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,IACxC,KAAK,KAAK,IACV,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK;AAG1C,6BAAY,QAAQ,aAAa,WACb,YAAY,SAAS,UAAU,KAAK,OAAO;AAC/D,6BAAY,QAAQ,mBAAmB,WACnB,CAAC,KAAK,KAAK,QAAQ,CAAC,KAAK,KAAK;AAElD,UAAI,CAAC,gBAAgB,KAAK,YAAY,QAAQ,GAAG;AAC/C,kBAAU,MAAM,cAAc,KAAK,YAAY,QAAQ;AACvD,YAAI,KAAK,YAAY,UAAU,gCAA0B,WAAW;AAIlE,kBAAQ,QAAQ,IAAI,KAAK,YAAY;AACrC,mBAAS,SAAS,IAAI,KAAK,YAAY;AAPM;AAU/C,YAAI,mBAAmB,KAAK,YAAY;AACxC,YAAI,iBAAiB,KAAK,YAAY;AACtC,YAAI,mBAAmB,KAAK,iBAAiB,GAAG;AAC9C,cAAI,SAAS,mBAAmB,UAAU,iBAAiB;AAC3D,iCAAY,QAAQ,gBAAgB,WAAW;AAdF;AAiB/C,gBAAQ,KAAK,YAAY;AACvB,eAAK,gCAA0B;AAC7B,sBAAU,MAAM,cAAc;AAC9B;AAEF,eAAK,gCAA0B;AAC7B,sBAAU,MAAM,cAAc;AAC9B;AAEF,eAAK,gCAA0B;AAC7B,4BAAK;AACL;AAEF,eAAK,gCAA0B;AAC7B,4BAAK;AACL;AAEF,eAAK,gCAA0B;AAC7B,sBAAU,MAAM,oBAAoB;AACpC;AAEF;AACE;;AAGJ,YAAI,KAAK,OAAO;AACd,oBAAU,MAAM,cACd,WAAK,WAAW,KAAK,MAAM,KAAK,GAChB,KAAK,MAAM,KAAK,GAChB,KAAK,MAAM,KAAK;AAJpC,eAKO;AAEL,oBAAU,MAAM,cAAc;AAjDe;AAtBU;AA2E3D,gBAAU,MAAM,OAAO,KAAK,KAAK;AACjC,gBAAU,MAAM,MAAM,KAAK,KAAK;AAEhC,gBAAU,MAAM,QAAQ,QAAQ;AAChC,gBAAU,MAAM,SAAS,SAAS;AAElC,aAAO;AA3F6D;AAyGtE,kBACI,SAAS,8BAA8B,WAAW,SAAS,MAAM;AAEnE,UAAI,CAAC,SAAS;AACZ,kBAAU,SAAS,cAAc;AACjC,gBAAQ,MAAM,SAAS,UAAU,MAAM;AACvC,gBAAQ,MAAM,QAAQ,UAAU,MAAM;AACtC,kBAAU,YAAY;AAN2C;AASnE,UAAI,mBAAmB;AACrB;AACA;AACA,eAAO,KAAK;AACZ,eAAO,KAAK;AACZ,kBAAU,KAAK;AACf,qBAAa;AANqB,OAAjB;AAQnB,UAAI,QAAQ,aAAa;AAGzB,YAAM,MAAM,OAAO,UAAU,MAAM;AAEnC,gBAAU,YAAY;AAhI8C;AAyItE,YAAQ,SAAS,2BAA2B;AAC1C,YAAM,IAAI,MAAM;AA1IoD;AAAA;AA8IxE,SAAO;AA/Je,CAAC;AAsKzB,IAAI,iCAAkC,+BAA+B;AACnE,WAAS,sBAAsB,YAAY;AACzC,sBAAkB,KAAK,MAAM,YAAY;AAFwB;AAKnE,aAAK,QAAQ,uBAAuB;AAQlC,YAAQ,SAAS,+BAA+B;AAC9C,WAAK,UAAU,YAAY;AAE3B,UAAI,OAAO,SAAS,cAAc;AAClC,wCAAkB;AAChB,aAAK,KAAK,KAAK;AACf,gBAAS,KAAK,KAAK,YAAY,sBAAW,QAAQ;AAF5B;AAKxB,UAAI,CAAC,KAAK,KAAK,KAAK;AAClB,YAAI,KAAK,KAAK,QAAQ;AACpB,eAAK,iBAAiB,MAAM,KAAK,KAAK;AADxC,eAEO;AACL,eAAK,UAAU,MAAM,KAAK,KAAK;AAJf;AAT0B;AAiB9C,WAAK,UAAU,YAAY;AAC3B,aAAO,KAAK;AA1BuC;AAqCrD,kCAAU,MAAM;AAAa;;AAC3B,WAAK,OAAO,KAAK,YAAY,mBAAmB;AAChD,WAAK,UAAU,YAAM;AACnB,YAAI,aAAa;AACf,gBAAK,YAAY,WAAW;AAFX;AAInB,eAAO;AAJT;AAMA,UAAI,aAAa;AACf,aAAK,YAAY;AATQ;AArCwB;AA0DrD,gDAAiB,MAAM;AAAQ;;AAC7B,WAAK,OAAO,KAAK,YAAY,aAAa;AAC1C,WAAK,UAAU,YAAM;AACnB,eAAK,YAAY,mBAAmB;AACpC,eAAO;AAFT;AAIA,WAAK,YAAY;AAhEkC;AAAA;AAoEvD,SAAO;AAzEmB,CAAC;AAgF7B,IAAI,iCAAkC,+BAA+B;AACnE,WAAS,sBAAsB,YAAY;AACzC,QAAI,eAAe,CAAG,aAAW,KAAK,YAChB,WAAW,KAAK,SAAS,WAAW,KAAK;AAC/D,sBAAkB,KAAK,MAAM,YAAY;AAJwB;AAOnE,aAAK,QAAQ,uBAAuB;AAQlC,YAAQ,SAAS,+BAA+B;AAC9C,WAAK,UAAU,YAAY;AAE3B,UAAI,QAAQ,SAAS,cAAc;AACnC,YAAM,MAAM,SAAS,KAAK,UAAU,MAAM;AAC1C,YAAM,MAAM,QAAQ,KAAK,UAAU,MAAM;AACzC,YAAM,MAAM,KAAK,qBAAqB,gBACpC,KAAK,KAAK,KAAK,gBAAgB;AACjC,YAAM,MAAM;AACZ,YAAM,QAAQ,SAAS;AACvB,YAAM,QAAQ,WAAW,KAAK,UAAU,EAAE,MAAM,KAAK,KAAK;AAE1D,UAAI,CAAC,KAAK,KAAK,UAAU;AACvB,aAAK,aAAa,KAAK,WAAW,OAAO,KAAK;AAbF;AAgB9C,WAAK,UAAU,YAAY;AAC3B,aAAO,KAAK;AAzBuC;AAAA;AA6BvD,SAAO;AApCmB,CAAC;AA2C7B,IAAI,mCAAoC,iCAAiC;AACvE,WAAS,wBAAwB,YAAY,cAAc;AACzD,sBAAkB,KAAK,MAAM,YAAY;AAF4B;AAKvE,aAAK,QAAQ,yBAAyB;AAQpC,YAAQ,SAAS,iCAAiC;AAEhD,aAAO,KAAK;AAVyC;AAAA;AAczD,SAAO;AAnBqB,CAAC;AA0B/B,IAAI,uCACS,qCAAqC;AAChD,MAAI,iBAAiB,CAAC,QAAQ,UAAU;AAExC,WAAS,4BAA4B,YAAY;AAC/C,QAAI,eAAe,WAAW,0BAC3B,CAAC,WAAW,KAAK,iBAAiB,CAAC,CAAC,WAAW,KAAK;AACvD,4BAAwB,KAAK,MAAM,YAAY;AAND;AAShD,aAAK,QAAQ,6BAA6B;AAQxC,YAAQ,SAAS,qCAAqC;AACpD,WAAK,UAAU,YAAY;AAE3B,UAAI,UAAU;AACd,UAAI,KAAK,wBAAwB;AAI/B,YAAI,KAAK,KAAK,WAAW;AACvB,oBAAU,SAAS,cAAc;AACjC,kBAAQ,cAAc,KAAK,KAAK;AAFlC,eAGO;AACL,oBAAU,SAAS,cAAc;AACjC,kBAAQ,OAAO;AACf,kBAAQ,aAAa,SAAS,KAAK,KAAK;AAVX;AAa/B,gBAAQ,WAAW,KAAK,KAAK;AAE7B,YAAI,KAAK,KAAK,WAAW,MAAM;AAC7B,kBAAQ,YAAY,KAAK,KAAK;AAhBD;AAmB/B,YAAI,KAAK,KAAK,MAAM;AAClB,cAAI,aAAa,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK;AACpD,cAAI,YAAY,aAAa,KAAK,KAAK;AAEvC,kBAAQ,UAAU,IAAI;AACtB,kBAAQ,MAAM,gBAAgB,UAAU,YAAY;AAxBvB;AAAjC,aA0BO;AACL,kBAAU,SAAS,cAAc;AACjC,gBAAQ,cAAc,KAAK,KAAK;AAChC,gBAAQ,MAAM,gBAAgB;AAC9B,gBAAQ,MAAM,UAAU;AAExB,YAAI,OAAO;AACX,YAAI,KAAK,KAAK,aAAa;AACzB,iBAAO,KAAK,KAAK,WAAW,QAAQ,KAAK,KAAK;AAR3C;AAUL,aAAK,cAAc,SAAS;AAxCsB;AA2CpD,UAAI,KAAK,KAAK,kBAAkB,MAAM;AACpC,gBAAQ,MAAM,YAAY,eAAe,KAAK,KAAK;AA5CD;AA+CpD,WAAK,UAAU,YAAY;AAC3B,aAAO,KAAK;AAxDmD;AAmEjE,mBACI,SAAS,yCAAyC,SAAS,MAAM;AAEnE,UAAI,QAAQ,QAAQ;AACpB,YAAM,WAAW,KAAK,KAAK,WAAW;AACtC,YAAM,YAAa,KAAK,KAAK,gBAAgB,IAAI,QAAQ;AAEzD,UAAI,CAAC,MAAM;AACT;AAPiE;AAUnE,YAAM,aAAc,KAAK,QACtB,KAAK,OAAO,QAAQ,SACpB,KAAK,OAAO,SAAS;AACxB,YAAM,YAAa,KAAK,SAAS,WAAW;AAG5C,UAAI,aAAa,KAAK,aAAa,MAAM,KAAK,aAAa,QAAQ;AACnE,UAAI,eAAe,KAAK,gBAAgB;AACxC,YAAM,aAAa,aAAa;AAtF+B;AAAA;AA0FnE,SAAO;AApGyB,CAC9B;AA0GJ,IAAI,2CACU,yCAAyC;AACrD,WAAS,gCAAgC,YAAY;AACnD,4BAAwB,KAAK,MAAM,YACN,WAAW;AAHW;AAMrD,aAAK,QAAQ,iCAAiC;AAS5C,YAAQ,SAAS,yCAAyC;AACxD,WAAK,UAAU,YAAY;AAE3B,UAAI,UAAU,SAAS,cAAc;AACrC,cAAQ,WAAW,KAAK,KAAK;AAC7B,cAAQ,OAAO;AACf,UAAI,KAAK,KAAK,cAAc,KAAK,KAAK,eAAe,OAAO;AAC1D,gBAAQ,aAAa,WAAW;AAPsB;AAUxD,WAAK,UAAU,YAAY;AAC3B,aAAO,KAAK;AApBuD;AAAA;AAwBvE,SAAO;AA9BL,CAAC;AAqCL,IAAI,8CACU,4CAA4C;AACxD,WAAS,mCAAmC,YAAY;AACtD,4BAAwB,KAAK,MAAM,YACN,WAAW;AAHc;AAMxD,aAAK,QAAQ,oCAAoC;AAS/C,YAAQ,SAAS,4CAA4C;AAC3D,WAAK,UAAU,YAAY;AAE3B,UAAI,UAAU,SAAS,cAAc;AACrC,cAAQ,WAAW,KAAK,KAAK;AAC7B,cAAQ,OAAO;AACf,cAAQ,OAAO,KAAK,KAAK;AACzB,UAAI,KAAK,KAAK,eAAe,KAAK,KAAK,aAAa;AAClD,gBAAQ,aAAa,WAAW;AARyB;AAW3D,WAAK,UAAU,YAAY;AAC3B,aAAO,KAAK;AArB0D;AAAA;AAyB1E,SAAO;AA/BL,CAAC;AAsCL,IAAI,yCACS,uCAAuC;AAClD,WAAS,8BAA8B,YAAY;AACjD,4BAAwB,KAAK,MAAM,YACN,WAAW;AAHQ;AAMlD,aAAK,QAAQ,+BAA+B;AAS1C,YAAQ,SAAS,uCAAuC;AACtD,WAAK,UAAU,YAAY;AAE3B,UAAI,gBAAgB,SAAS,cAAc;AAC3C,oBAAc,WAAW,KAAK,KAAK;AAEnC,UAAI,CAAC,KAAK,KAAK,OAAO;AAEpB,sBAAc,OAAO,KAAK,KAAK,QAAQ;AAEvC,YAAI,KAAK,KAAK,aAAa;AACzB,wBAAc,WAAW;AALP;AANgC;AAgBtD,WAAK,IAAI,IAAI,GAAG,KAAK,KAAK,KAAK,QAAQ,QAAQ,IAAI,IAAI,KAAK;AAC1D,YAAI,SAAS,KAAK,KAAK,QAAQ;AAE/B,YAAI,gBAAgB,SAAS,cAAc;AAC3C,sBAAc,cAAc,OAAO;AACnC,sBAAc,QAAQ,OAAO;AAE7B,YAAI,KAAK,KAAK,WAAW,QAAQ,OAAO,iBAAiB,GAAG;AAC1D,wBAAc,aAAa,YAAY;AARiB;AAW1D,sBAAc,YAAY;AA3B0B;AA8BtD,WAAK,UAAU,YAAY;AAC3B,aAAO,KAAK;AAxCqD;AAAA;AA4CrE,SAAO;AAnD2B,CAChC;AAyDJ,IAAI,kCAAmC,gCAAgC;AAGrE,MAAI,eAAe,CAAC;AAEpB,WAAS,uBAAuB,YAAY;AAC1C,QAAI,eAAe,CAAG,aAAW,KAAK,SAAS,WAAW,KAAK;AAC/D,sBAAkB,KAAK,MAAM,YAAY;AAP0B;AAUrE,aAAK,QAAQ,wBAAwB;AAQnC,YAAQ,SAAS,gCAAgC;AAC/C,WAAK,UAAU,YAAY;AAE3B,UAAI,aAAa,QAAQ,KAAK,KAAK,eAAe,GAAG;AACnD,eAAO,KAAK;AAJiC;AAO/C,UAAI,WAAW,0BAA0B,KAAK,KAAK,WAAW;AAC9D,UAAI,gBAAgB,KAAK,MAAM,cAAc;AAC7C,UAAI,CAAC,eAAe;AAClB,eAAO,KAAK;AAViC;AAa/C,UAAI,YAAY;AACd,mBAAW,KAAK;AAChB,iBAAS;AACT,eAAO,KAAK,KAAK;AACjB,eAAO,KAAK,KAAK;AACjB,kBAAU,KAAK,KAAK;AALO,OAAjB;AAUZ,UAAI,aAAa,WAAW,cAAc,MAAM;AAChD,UAAI,cAAc,WAAW,cAAc,MAAM;AACjD,6BAAY,QAAQ,mBAAmB,KAAK,WACtB,eAAa,eAAe,SAC9B,cAAc,MAAM;AACxC,WAAK,UAAU,MAAM,OAAQ,aAAa,cAAe;AAEzD,WAAK,UAAU,YAAY,MAAM;AACjC,aAAO,KAAK;AAvCwC;AAAA;AA2CxD,SAAO;AArDoB,CAAC;AA4D9B,IAAI,wBAAyB,sBAAsB;AACjD,MAAI,qBAAqB;AAEzB,WAAS,aAAa,YAAY;AAChC,SAAK,YAAY,WAAW;AAC5B,SAAK,UAAU,WAAW;AAC1B,SAAK,QAAQ,WAAW;AACxB,SAAK,QAAQ,WAAW;AACxB,SAAK,WAAW,WAAW;AAC3B,SAAK,cAAc,WAAW,eAAe;AAE7C,SAAK,SAAS;AAXiC;AAcjD,eAAa;AAQX,YAAQ,SAAS,sBAAsB;AACrC,UAAI,UAAU,SAAS,cAAc;AACrC,cAAQ,YAAY;AAMpB,WAAK,cAAe,KAAK,cAAc,UAAU,KAAK;AACtD,WAAK,YAAY,aAAa,UAAU;AAExC,UAAI,QAAQ,SAAS,cAAc;AACnC,YAAM,YAAY;AAElB,UAAI,QAAQ,KAAK;AACjB,UAAI,OAAO;AAET,YAAI,IAA0B,4BAAM,MAAM,MAAM,MAAM;AACtD,YAAI,IAA0B,4BAAM,MAAM,MAAM,MAAM;AACtD,YAAI,IAA0B,4BAAM,MAAM,MAAM,MAAM;AACtD,cAAM,MAAM,kBAAkB,WAAK,WAAW,IAAI,GAAG,IAAI,GAAG,IAAI;AApB7B;AAuBrC,UAAI,WAAW,KAAK,gBAAgB,KAAK;AACzC,UAAI,QAAQ,SAAS,cAAc;AACnC,YAAM,cAAc,KAAK;AAGzB,WAAK,QAAQ,iBAAiB,SAAS,KAAK,QAAQ,KAAK;AACzD,WAAK,QAAQ,iBAAiB,aAAa,KAAK,MAAM,KAAK,MAAM;AACjE,WAAK,QAAQ,iBAAiB,YAAY,KAAK,MAAM,KAAK,MAAM;AAChE,YAAM,iBAAiB,SAAS,KAAK,MAAM,KAAK,MAAM;AAEtD,YAAM,YAAY;AAClB,YAAM,YAAY;AAClB,cAAQ,YAAY;AACpB,aAAO;AA5CmD;AAuD5D,qBAAiB,SAAS,4BAA4B,UAAU;AAC9D,UAAI,IAAI,SAAS,cAAc;AAC/B,UAAI,QAAQ,SAAS,MAAM;AAC3B,WAAK,IAAI,IAAI,GAAG,KAAK,MAAM,QAAQ,IAAI,IAAI,EAAE,GAAG;AAC9C,YAAI,OAAO,MAAM;AACjB,UAAE,YAAY,SAAS,eAAe;AACtC,YAAI,IAAK,KAAK,GAAI;AAChB,YAAE,YAAY,SAAS,cAAc;AAJO;AAHc;AAU9D,aAAO;AAjEmD;AA0E5D,aAAS,SAAS,sBAAsB;AACtC,UAAI,KAAK,QAAQ;AACf,aAAK,MAAM;AADb,aAEO;AACL,aAAK,MAAM;AAJyB;AA1EoB;AAyF5D,WAAO,SAAS,kBAAkB,KAAK;AACrC,UAAI,KAAK;AACP,aAAK,SAAS;AAFqB;AAIrC,UAAI,KAAK,YAAY,aAAa,WAAW;AAC3C,aAAK,YAAY,gBAAgB;AACjC,aAAK,UAAU,MAAM,UAAU;AANI;AAzFqB;AA0G5D,WAAO,SAAS,kBAAkB,OAAO;AACvC,UAAI,OAAO;AACT,aAAK,SAAS;AAFuB;AAIvC,UAAI,CAAC,KAAK,YAAY,aAAa,aAAa,CAAC,KAAK,QAAQ;AAC5D,aAAK,YAAY,aAAa,UAAU;AACxC,aAAK,UAAU,MAAM,UAAU;AANM;AA1GmB;AAAA;AAqH9D,SAAO;AAnIU,CAAC;AA0IpB,IAAI,iCAAkC,+BAA+B;AACnE,MAAI,SAAS;AAEb,WAAS,sBAAsB,YAAY;AACzC,QAAI,eAAe,CAAG,aAAW,KAAK,YAChB,WAAW,KAAK,SAAS,WAAW,KAAK;AAC/D,sBAAkB,KAAK,MAAM,YAAY,cACG;AAPqB;AAUnE,aAAK,QAAQ,uBAAuB;AAQlC,YAAQ,SAAS,+BAA+B;AAC9C,WAAK,UAAU,YAAY;AAK3B,UAAI,OAAO,KAAK;AAChB,UAAI,QAAQ,KAAK,KAAK,KAAK,KAAK,KAAK;AACrC,UAAI,SAAS,KAAK,KAAK,KAAK,KAAK,KAAK;AAEtC,UAAI,MAAM,SAAS,gBAAgB,QAAQ;AAC3C,UAAI,eAAe,MAAM,WAAW;AACpC,UAAI,eAAe,MAAM,SAAS,QAAQ;AAC1C,UAAI,eAAe,MAAM,UAAU,SAAS;AAC5C,UAAI,eAAe,MAAM,uBAAuB;AAChD,UAAI,eAAe,MAAM,WAAW,SAAS,QAAQ,MAAM;AAI3D,UAAI,OAAO,SAAS,gBAAgB,QAAQ;AAC5C,WAAK,eAAe,MAAM,MAAM,KAAK,KAAK,KAAK,KAAK,gBAAgB;AACpE,WAAK,eAAe,MAAM,MAAM,KAAK,KAAK,KAAK,KAAK,gBAAgB;AACpE,WAAK,eAAe,MAAM,MAAM,KAAK,KAAK,KAAK,KAAK,gBAAgB;AACpE,WAAK,eAAe,MAAM,MAAM,KAAK,KAAK,KAAK,KAAK,gBAAgB;AACpE,WAAK,eAAe,MAAM,gBAAgB,KAAK,YAAY;AAC3D,WAAK,eAAe,MAAM,UAAU;AAEpC,UAAI,YAAY;AAChB,WAAK,UAAU,OAAO;AAItB,WAAK,aAAa,KAAK,WAAW,MAAM,KAAK;AAE7C,aAAO,KAAK;AA1CuC;AAAA;AA8CvD,SAAO;AAxDmB,CAAC;AA+D7B,IAAI,sCACS,oCAAoC;AAC/C,WAAS,2BAA2B,YAAY;AAC9C,QAAI,eAAe,CAAG,aAAW,KAAK,YAChB,WAAW,KAAK,SAAS,WAAW,KAAK;AAC/D,sBAAkB,KAAK,MAAM,YAAY,cACG;AALC;AAQ/C,aAAK,QAAQ,4BAA4B;AAQvC,YAAQ,SAAS,oCAAoC;AACnD,WAAK,UAAU,YAAY;AAE3B,UAAI,CAAC,KAAK,KAAK,UAAU;AACvB,aAAK,aAAa,KAAK,WAAW,MAAM,KAAK;AAJI;AAMnD,aAAO,KAAK;AAd4C;AAAA;AAkB5D,SAAO;AA3BwB,CAC7B;AAiCJ,IAAI,sCACS,oCAAoC;AAC/C,WAAS,2BAA2B,YAAY;AAC9C,QAAI,eAAe,CAAG,aAAW,KAAK,YAChB,WAAW,KAAK,SAAS,WAAW,KAAK;AAC/D,sBAAkB,KAAK,MAAM,YAAY,cACG;AALC;AAQ/C,aAAK,QAAQ,4BAA4B;AAQvC,YAAQ,SAAS,oCAAoC;AACnD,WAAK,UAAU,YAAY;AAE3B,UAAI,CAAC,KAAK,KAAK,UAAU;AACvB,aAAK,aAAa,KAAK,WAAW,MAAM,KAAK;AAJI;AAMnD,aAAO,KAAK;AAd4C;AAAA;AAkB5D,SAAO;AA3BwB,CAC7B;AAiCJ,IAAI,qCAAsC,mCAAmC;AAC3E,WAAS,0BAA0B,YAAY;AAC7C,QAAI,eAAe,CAAG,aAAW,KAAK,YAChB,WAAW,KAAK,SAAS,WAAW,KAAK;AAC/D,sBAAkB,KAAK,MAAM,YAAY,cACG;AAL6B;AAQ3E,aAAK,QAAQ,2BAA2B;AAQtC,YAAQ,SAAS,mCAAmC;AAClD,WAAK,UAAU,YAAY;AAE3B,UAAI,CAAC,KAAK,KAAK,UAAU;AACvB,aAAK,aAAa,KAAK,WAAW,MAAM,KAAK;AAJG;AAMlD,aAAO,KAAK;AAd2C;AAAA;AAkB3D,SAAO;AA1BuB,CAAC;AAiCjC,IAAI,sCACS,oCAAoC;AAC/C,WAAS,2BAA2B,YAAY;AAC9C,QAAI,eAAe,CAAG,aAAW,KAAK,YAChB,WAAW,KAAK,SAAS,WAAW,KAAK;AAC/D,sBAAkB,KAAK,MAAM,YAAY,cACG;AALC;AAQ/C,aAAK,QAAQ,4BAA4B;AAQvC,YAAQ,SAAS,oCAAoC;AACnD,WAAK,UAAU,YAAY;AAE3B,UAAI,CAAC,KAAK,KAAK,UAAU;AACvB,aAAK,aAAa,KAAK,WAAW,MAAM,KAAK;AAJI;AAMnD,aAAO,KAAK;AAd4C;AAAA;AAkB5D,SAAO;AA3BwB,CAC7B;AAiCJ,IAAI,2CACS,yCAAyC;AACpD,WAAS,gCAAgC,YAAY;AACnD,sBAAkB,KAAK,MAAM,YAAY;AAEzC,QAAI,OAAO,KAAK,KAAK;AACrB,SAAK,WAAW,mCAAmB,KAAK;AACxC,SAAK,UAAU,KAAK;AAEpB,SAAK,YAAY;AACf,UAAI,6BAAkB,KAAK;AAC3B,gBAAU,KAAK;AACf,eAAS,KAAK;AAH4B;AARM;AAepD,aAAK,QAAQ,iCAAiC;AAS5C,YAAQ,SAAS,yCAAyC;AACxD,WAAK,UAAU,YAAY;AAE3B,UAAI,UAAU,SAAS,cAAc;AACrC,cAAQ,MAAM,SAAS,KAAK,UAAU,MAAM;AAC5C,cAAQ,MAAM,QAAQ,KAAK,UAAU,MAAM;AAC3C,cAAQ,iBAAiB,YAAY,KAAK,UAAU,KAAK;AAEzD,UAAI,CAAC,KAAK,KAAkB,kBAAK,KAAK,SAAS,KAAK,KAAK,WAAW;AAClE,aAAK,aAAa,KAAK,WAAW,SAAS,KAAK;AATM;AAYxD,WAAK,UAAU,YAAY;AAC3B,aAAO,KAAK;AAtBiD;AA+B/D,eAAW,SAAS,2CAA2C;AAC7D,UAAI,CAAC,KAAK,iBAAiB;AACzB,wBAAK;AACL;AAH2D;AAK7D,WAAK,gBAAgB,aAAa,KAAK,SAAS,KAAK,UAAU;AApCF;AAAA;AAwCjE,SAAO;AAxD6B,CAClC;AAyEJ,IAAI,2BAA4B,yBAAyB;AACvD;AAQE,YAAQ,SAAS,uBAAuB,YAAY;AAClD,UAAI,2BAA2B,IAAI;AAEnC,WAAK,IAAI,IAAI,GAAG,KAAK,WAAW,YAAY,QAAQ,IAAI,IAAI,KAAK;AAC/D,YAAI,OAAO,WAAW,YAAY;AAClC,YAAI,CAAC,MAAM;AACT;AAH6D;AAK/D,YAAI,mCAAmC;AACrC;AACA,iBAAO,WAAW;AAClB,gBAAM,WAAW;AACjB,oBAAU,WAAW;AACrB,uBAAa,WAAW;AACxB,2BAAiB,WAAW;AAC5B,8BAAoB,WAAW,sBACX,kCAAkB;AACtC,kCAAwB,WAAW,0BAA0B;AATjB,SAAhC;AAWd,YAAI,QAAQ,cAAc;AACxB,qBAAW,IAAI,YAAY,QAAQ;AAjB0B;AAHf;AAR/C;AAwCL,YAAQ,SAAS,uBAAuB,YAAY;AAClD,WAAK,IAAI,IAAI,GAAG,KAAK,WAAW,YAAY,QAAQ,IAAI,IAAI,KAAK;AAC/D,YAAI,OAAO,WAAW,YAAY;AAClC,YAAI,UAAU,WAAW,IAAI,cAC3B,0BAA0B,KAAK,KAAK;AACtC,YAAI,SAAS;AACX,iCAAY,QAAQ,aAAa,SAC/B,YAAY,WAAW,SAAS,UAAU,KAAK,OAAO;AANK;AADf;AAUlD,iBAAW,IAAI,gBAAgB;AAlD5B;AAAA;AAuDT,CAxDuB;QAyDrB,kC;;;;;;;;;;;;;;ACnpCK;;AAEP,IAAI,cAAc,uBAAW;AAC3B,QAAM,IAAI,MAAM;AADlB;AAK6C;AAE7C,MAAI;AACF,eAAW;AACX,gBAAY;AACZ,eAAW;AAHM;AAMnB,MAAI,+BAAgC,6BAA6B;AAC/D,QAAI,aACF,IAAI,WAAW,CAAC,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM;AAE5D,QAAI,qBAAqB;AAEzB,QAAI,WAAW,IAAI,WAAW;AAC9B,SAAK,IAAI,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,UAAI,IAAI;AACR,WAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,YAAI,IAAI,GAAG;AACT,cAAI,aAAe,KAAK,IAAK;AAD/B,eAEO;AACL,cAAK,KAAK,IAAK;AAJS;AAFA;AAS5B,eAAS,KAAK;AAhB+C;AAmB/D,aAAS,MAAM,MAAM,OAAO,KAAK;AAC/B,UAAI,MAAM,CAAC;AACX,WAAK,IAAI,IAAI,OAAO,IAAI,KAAK,KAAK;AAChC,YAAI,IAAK,OAAM,KAAK,MAAM;AAC1B,YAAI,IAAI,SAAS;AACjB,cAAO,QAAQ,IAAK;AALS;AAO/B,aAAO,MAAM,CAAC;AA1B+C;AA6B/D,aAAS,cAAc,MAAM,MAAM,MAAM,QAAQ;AAC/C,UAAI,IAAI;AACR,UAAI,MAAM,KAAK;AAEf,WAAK,KAAK,OAAO,KAAK;AACtB,WAAK,IAAI,KAAK,OAAO,KAAK;AAC1B,WAAK,IAAI,KAAK,OAAO,IAAI;AACzB,WAAK,IAAI,KAAK,MAAM;AACpB,WAAK;AAEL,WAAK,KAAK,KAAK,WAAW,KAAK;AAC/B,WAAK,IAAI,KAAK,KAAK,WAAW,KAAK;AACnC,WAAK,IAAI,KAAK,KAAK,WAAW,KAAK;AACnC,WAAK,IAAI,KAAK,KAAK,WAAW,KAAK;AACnC,WAAK;AAEL,WAAK,IAAI,MAAM;AACf,WAAK,KAAK;AAEV,UAAI,MAAM,MAAM,MAAM,SAAS,GAAG;AAElC,WAAK,KAAK,OAAO,KAAK;AACtB,WAAK,IAAI,KAAK,OAAO,KAAK;AAC1B,WAAK,IAAI,KAAK,OAAO,IAAI;AACzB,WAAK,IAAI,KAAK,MAAM;AArDyC;AAwD/D,aAAS,QAAQ,MAAM,OAAO,KAAK;AACjC,UAAI,IAAI;AACR,UAAI,IAAI;AACR,WAAK,IAAI,IAAI,OAAO,IAAI,KAAK,EAAE,GAAG;AAChC,YAAK,CAAK,UAAK,KAAK,SAAS;AAC7B,YAAK,KAAI,KAAK;AALiB;AAOjC,aAAQ,KAAK,KAAM;AA/D0C;AAwE/D,aAAS,YAAY,UAAU;AAC7B,UAAI,CAAC,uBAAY;AAIf,eAAO,wBAAwB;AALJ;AAO7B,UAAI;AAUF,YAAI;AAEJ,YAAI,SAAS,QAAQ,SAAS,SAAS,GAAG;AACxC,kBAAQ;AADV,eAEO;AAEL,kBAAQ,IAAI,OAAO;AAhBnB;AAkBF,YAAI,SAAS,QAAwB,QAClC,YAAY,OAAO,EAAE,OAAO;AAC/B,eAAO,kBAAkB,aAAa,SAAS,IAAI,WAAW;AApBhE,QAqBE,OAAO,GAAG;AACV,wBAAK,kEAAkE;AA7B5C;AAgC7B,aAAO,wBAAwB;AAxG8B;AA4G/D,aAAS,wBAAwB,UAAU;AACzC,UAAI,MAAM,SAAS;AACnB,UAAI,iBAAiB;AAErB,UAAI,gBAAgB,KAAK,KAAK,MAAM;AACpC,UAAI,OAAO,IAAI,WAAW,IAAI,MAAM,gBAAgB,IAAI;AACxD,UAAI,KAAK;AACT,WAAK,QAAQ;AACb,WAAK,QAAQ;AAEb,UAAI,MAAM;AACV,aAAO,MAAM,gBAAgB;AAE3B,aAAK,QAAQ;AACb,aAAK,QAAQ;AACb,aAAK,QAAQ;AACb,aAAK,QAAQ;AACb,aAAK,QAAQ;AACb,aAAK,IAAI,SAAS,SAAS,KAAK,MAAM,iBAAiB;AACvD,cAAM;AACN,eAAO;AACP,eAAO;AArBgC;AAyBzC,WAAK,QAAQ;AACb,WAAK,QAAQ,MAAM;AACnB,WAAK,QAAQ,OAAO,IAAI;AACxB,WAAK,QAAS,CAAC,MAAM,SAAU;AAC/B,WAAK,QAAS,EAAC,MAAM,WAAW,IAAI;AACpC,WAAK,IAAI,SAAS,SAAS,MAAM;AACjC,YAAM,SAAS,SAAS;AAExB,UAAI,QAAQ,QAAQ,UAAU,GAAG,SAAS;AAC1C,WAAK,QAAQ,SAAS,KAAK;AAC3B,WAAK,QAAQ,SAAS,KAAK;AAC3B,WAAK,QAAQ,SAAS,IAAI;AAC1B,WAAK,QAAQ,QAAQ;AACrB,aAAO;AAlJsD;AAqJ/D,aAAS,OAAO,SAAS,MAAM,iBAAiB;AAC9C,UAAI,QAAQ,QAAQ;AACpB,UAAI,SAAS,QAAQ;AACrB,UAAI,UAAU,WAAW;AACzB,UAAI,QAAQ,QAAQ;AAEpB,cAAQ;AACN,aAAK,gBAAU;AACb,sBAAY;AACZ,qBAAW;AACX,qBAAY,QAAQ,KAAM;AAC1B;AACF,aAAK,gBAAU;AACb,sBAAY;AACZ,qBAAW;AACX,qBAAW,QAAQ;AACnB;AACF,aAAK,gBAAU;AACb,sBAAY;AACZ,qBAAW;AACX,qBAAW,QAAQ;AACnB;AACF;AACE,gBAAM,IAAI,MAAM;;AAIpB,UAAI,WAAW,IAAI,WAAY,KAAI,YAAY;AAC/C,UAAI,iBAAiB;UAAG,cAAc;AACtC,UAAI,GAAG;AACP,WAAK,IAAI,GAAG,IAAI,QAAQ,EAAE,GAAG;AAC3B,iBAAS,oBAAoB;AAC7B,iBAAS,IAAI,MAAM,SAAS,aAAa,cAAc,WAC1C;AACb,uBAAe;AACf,0BAAkB;AAnC0B;AAsC9C,UAAI,SAAS,gBAAU,gBAAgB;AAErC,yBAAiB;AACjB,aAAK,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC3B;AACA,eAAK,IAAI,GAAG,IAAI,UAAU,KAAK;AAC7B,qBAAS,qBAAqB;AAHL;AAHQ;AAtCO;AAiD9C,UAAI,OAAO,IAAI,WAAW,CACxB,SAAS,KAAK,MACd,SAAS,KAAK,MACd,SAAS,IAAI,MACb,QAAQ,MACR,UAAU,KAAK,MACf,UAAU,KAAK,MACf,UAAU,IAAI,MACd,SAAS,MACT,UACA,WACA,MACA,MACA;AAGF,UAAI,OAAO,YAAY;AAGvB,UAAI,YAAY,WAAW,SAAU,qBAAqB,IAC1C,KAAK,SAAS,KAAK;AACnC,UAAI,OAAO,IAAI,WAAW;AAC1B,UAAI,SAAS;AACb,WAAK,IAAI,YAAY;AACrB,gBAAU,WAAW;AACrB,oBAAc,QAAQ,MAAM,MAAM;AAClC,gBAAU,qBAAqB,KAAK;AACpC,oBAAc,SAAS,MAAM,MAAM;AACnC,gBAAU,qBAAqB,KAAK;AACpC,oBAAc,QAAQ,IAAI,WAAW,IAAI,MAAM;AAE/C,aAAO,2BAAgB,MAAM,aAAa;AArOmB;AAwO/D,WAAO,SAAS,oBAAoB,SAAS,iBAAiB;AAC5D,UAAI,OAAQ,QAAQ,SAAS,YACjB,gBAAU,iBAAiB,QAAQ;AAC/C,aAAO,OAAO,SAAS,MAAM;AAH/B;AAxOwB,GAAC;AA+O3B,MAAI,yBAA0B,uBAAuB;AACnD,aAAS,gBAAgB;AACvB,WAAK,gBAAgB;AACrB,WAAK,aAAa,aAAa;AAC/B,WAAK,WAAW;AAEhB,WAAkB;AAClB,WAAkB;AAClB,WAAK,UAAU;AAGf,WAAK,IAAI;AACT,WAAK,IAAI;AAGT,WAAK,QAAQ;AACb,WAAK,QAAQ;AAGb,WAAK,cAAc;AACnB,WAAK,cAAc;AACnB,WAAK,aAAa;AAClB,WAAK,WAAW;AAGhB,WAAK,YAAY,aAAa;AAC9B,WAAK,cAAc;AAEnB,WAAK,YAAY;AACjB,WAAK,cAAc;AACnB,WAAK,YAAY;AACjB,WAAK,WAAW;AAChB,WAAK,UAAU;AACf,WAAK,aAAa;AAElB,WAAK,YAAY;AACjB,WAAK,YAAY;AAEjB,WAAK,eAAe;AAGpB,WAAK,gBAAgB;AACrB,WAAK,YAAY;AAEjB,WAAK,SAAS;AA5CmC;AA+CnD,kBAAc;AACZ,aAAO,SAAS,sBAAsB;AACpC,eAAO,OAAO,OAAO;AAFC;AAIxB,uBAAiB,SAAS,8BAA8B,GAAG,GAAG;AAC5D,aAAK,IAAI;AACT,aAAK,IAAI;AANa;AAAA;AAS1B,WAAO;AAxDW,GAAC;AA2DrB,+CAAwB,qBAAqB;AAC3C,aAAS,aAAa,QAAQ;AAC5B,UAAI,SAAS;AACb,UAAI,MAAM;AACV,UAAI,YAAY,OAAO;AAEvB,WAAK,IAAI,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,YAAI,OAAO,GAAG,OAAO,QAAQ;AAC3B,iBAAO;AAAO,oBAAQ;AAAI,kBAAM;AAAS,qBAAS;AAAtC;AACZ,cAAI,KAAK;AACT,mBAAS,OAAO,OAAO,SAAS,GAAG;AACnC;AALgC;AAQlC,YAAI,OAAO,GAAG,OAAO,WAAW;AAC9B,mBAAS,IAAI;AADf,eAEO;AACL,iBAAO,KAAK,OAAO;AAXa;AALR;AAmB5B,aAAO;AApBkC;AA4B3C,aAAS,GAAG,OAAO;AACjB,UAAe,mBAAQ,IAAI;AACzB,eAAO,MAAM;AAFE;AAIjB,UAAI,IAAI,MAAM,QAAQ;AACtB,UAAI,IAAI,EAAE,SAAS;AACnB,UAAI,EAAE,OAAO,KAAK;AAChB,eAAO;AAPQ;AAUjB,SAAG;AACD;AADF,eAES,EAAE,OAAO;AAClB,aAAO,EAAE,OAAO,GAAG,EAAE,OAAO,MAAM,IAAI,IAAI;AAzCD;AAmD3C,aAAS,GAAG,GAAG;AACb,UAAI,EAAE,OAAO,KAAK,EAAE,OAAO,GAAG;AAC5B,YAAI,EAAE,OAAO,KAAK,EAAE,OAAO,GAAG;AAC5B,cAAI,EAAE,OAAO,KAAK,EAAE,OAAO,GAAG;AAC5B,mBAAO;AAFmB;AAI5B,iBAAO,WAAW,GAAG,EAAE,MAAM,MAAM,GAAG,EAAE,MAAM;AALpB;AAO5B,YAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI;AACnC,cAAI,IAAI,KAAK,KAAK,EAAE,MAAM,MAAM,KAAK;AACrC,iBAAO,YAAY,GAAG,KAAK;AATD;AAA9B,aAWO;AACL,YAAI,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK,EAAE,OAAO,GAAG;AACxD,iBAAO,eAAe,GAAG,EAAE,MAAM,MAAM,GAAG,EAAE,MAAM;AAF/C;AAZM;AAiBb,aAAO,YAAY,GAAG,EAAE,MAAM,MAAM,GAAG,EAAE,MAAM,MAAM,GAAG,EAAE,MAAM,MAC9D,GAAG,EAAE,MAAM,MAAM,GAAG,EAAE,MAAM,MAAM,GAAG,EAAE,MAAM;AArEN;AAwE3C,aAAS,YAAY,YAAY,MAAM,iBAAiB;AACtD,WAAK,UAAU,IAAI;AACnB,WAAuB;AACvB,WAAK,iBAAiB;AACtB,WAAK,aAAa;AAClB,WAAK,aAAa;AAClB,WAAK,OAAO;AACZ,WAAK,cAAc;AACnB,WAAK,gBAAgB;AAErB,WAAK,aAAa;AAClB,WAAK,gBAAgB,OAAO,OAAO;AACnC,WAAK,WAAW;AAChB,WAAK,kBAAkB,CAAC,CAAC;AArFgB;AAwF3C,QAAI,KAAK;AACT,QAAI,SAAS;AACb,QAAI,WAAW;AACf,QAAI,kBAAkB,CAAC,QAAQ,SAAS;AACxC,QAAI,mBAAmB,CAAC,SAAS,SAAS;AAC1C,QAAI,YAAY;AAChB,QAAI,YAAY;AAEhB,gBAAY;AACV,YAAM,SAAS,mBAAmB;AAChC,aAAK,eAAe,KAAK,KAAK;AAC9B,YAAI,MAAM,KAAK;AACf,aAAK,WAAW,KAAK;AACrB,aAAK,UAAU,IAAI;AALC;AAQtB,eAAS,SAAS,sBAAsB;AACtC,aAAK,kBAAkB,KAAK,eAAe;AAC3C,aAAK,UAAU,KAAK,WAAW;AAE/B,aAAK,cAAc;AACnB,aAAK,OAAO;AAbQ;AAgBtB,aAAO,SAAS,kBAAkB,OAAO;AACvC,aAAK;AACL,aAAK,cAAc;AACnB,aAAK;AAnBe;AAsBtB,wBAAkB,SAAS,6BAA6B;AAAc;;AACpE,YAAI,UAAU,aAAa;AAC3B,YAAI,aAAa,QAAQ;AACzB,YAAI,YAAY,aAAa;AAE7B,aAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAAK;AACnC,cAAI,UAAI,eAAe,QAAQ,IAAI;AACjC,gBAAI,OAAO,UAAU;AACrB,iBAAK,IAAI,IAAI,GAAG,KAAK,KAAK,QAAQ,IAAI,IAAI,KAAK;AAC7C,kBAAI,MAAM,KAAK;AACf,kBAAI,SAAS,IAAI,UAAU,GAAG,OAAO;AACrC,kBAAI;AACJ,kBAAI,QAAQ;AACV,8BAAc,QAAS,mBAAY;AACjC,wBAAK,WAAW,IAAI,KAAK;AADjB;AADZ,qBAIO;AACL,8BAAc,QAAS,mBAAY;AACjC,wBAAK,KAAK,IAAI,KAAK;AADX;AATiC;AAa7C,mBAAK,QAAQ,aAAa,KAAK;AAfA;AADA;AAL+B;AAyBpE,eAAO,QAAQ,IAAI,KAAK,QAAQ;AA/CZ;AAkDtB,iBAAW,SAAS,sBAAsB,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG;AAC1D,YAAI,kBAAkB,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG;AACtC,aAAK,kBAAkB,WAAK,UAAU,KAAK,iBACL;AACtC,aAAK,OAAO;AAtDQ;AAyDtB,cAAQ,SAAS,mBAAmB,cAAc;AAAU;;AAC1D,aAAK,WAAW;AAEhB,YAAI,aAAa,KAAK,YAAY;AAClC,oBAAY,iBAAiB,cAAc,KAAK,YAAM;AACpD,iBAAuB;AACvB,cAAI,SAAS,OAAK,cAAc;AAChC,iBAAK,cAAc;AACnB,iBAAO;AAJF;AA7Da;AAqEtB,qBAAe,SAAS,0BAA0B,cAAc;AAC9D,YAAI,YAAY,aAAa;AAC7B,YAAI,UAAU,aAAa;AAC3B,YAAI,aAAa,QAAQ;AACzB,YAAI,SAAS;AACb,YAAI,SAAS;AAEb,iBAAe,iBAAK;AAClB,iBAAO,UAAI,OAAO;AAR0C;AAW9D,aAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAAK;AACnC,cAAI,OAAO,QAAQ;AACnB,iBAAO;AACL,oBAAQ;AACR,kBAAM,OAAO;AACb,oBAAQ,UAAU;AAHR;AAbgD;AAmB9D,eAAO,aAAa;AAxFA;AA2FtB,qBAAe,SAAS,0BAA0B,QAAQ;AACxD,YAAI,YAAY,OAAO;AACvB,aAAK,IAAI,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,cAAI,KAAK,OAAO,GAAG;AACnB,cAAI,OAAO,OAAO,GAAG;AACrB,cAAI,OAAO,OAAO,GAAG;AAErB,kBAAQ,OAAO;AACb,iBAAK,UAAI;AACP,mBAAK;AACL;AACF,iBAAK,UAAI;AACP,mBAAK,WAAW;AAChB;AACF,iBAAK,UAAI;AACP,mBAAK,mBAAmB,KAAK,IAAI,KAAK;AACtC;AACF,iBAAK,UAAI;AACP,mBAAK,QAAQ;AACb;AACF,iBAAK,UAAI;AACP,mBAAK,SAAS,KAAK;AACnB;AACF,iBAAK,UAAI;AACP,mBAAK,SAAS,KAAK;AACnB;AACF,iBAAK,UAAI;AACP,mBAAK;AACL;AACF,iBAAK,UAAI;AACP,mBAAK,SAAS,KAAK,IAAI,KAAK;AAC5B;AACF,iBAAK,UAAI;AACP,mBAAK,eAAe,KAAK;AACzB;AACF,iBAAK,UAAI;AACP,mBAAK,eAAe,KAAK;AACzB;AACF,iBAAK,UAAI;AACP,mBAAK,UAAU,KAAK;AACpB;AACF,iBAAK,UAAI;AACP,mBAAK,cAAc,KAAK,IAAI,KAAK,IAAI,KAAK,IACvB,KAAK,IAAI,KAAK,IAAI,KAAK;AAC1C;AACF,iBAAK,UAAI;AACP,mBAAK,aAAa,KAAK;AACvB;AACF,iBAAK,UAAI;AACP,mBAAK,YAAY,KAAK;AACtB;AACF,iBAAK,UAAI;AACP,mBAAK,WAAW,KAAK;AACrB;AACF,iBAAK,UAAI;AACP,mBAAK,cAAc,KAAK;AACxB;AACF,iBAAK,UAAI;AACP,mBAAK,gBAAgB,KAAK,IAAI,KAAK,IAAI,KAAK;AAC5C;AACF,iBAAK,UAAI;AACP,mBAAK,kBAAkB,KAAK,IAAI,KAAK,IAAI,KAAK;AAC9C;AACF,iBAAK,UAAI;AACP,mBAAK,QAAQ,KAAK,IAAI,KAAK;AAC3B;AACF,iBAAK,UAAI;AACP,mBAAK,UAAU,KAAK;AACpB;AACF,iBAAK,UAAI;AACP,mBAAK;AACL;AACF,iBAAK,UAAI;AACP,mBAAK;AACL;AACF,iBAAK,UAAI;AACP,mBAAK;AACL;AACF,iBAAK,UAAI;AACP,mBAAK;AACL;AACF,iBAAK,UAAI;AACP,mBAAK;AACL;AACF,iBAAK,UAAI;AACP,mBAAK,KAAK;AACV;AACF,iBAAK,UAAI;AACP,mBAAK,KAAK;AACV;AACF,iBAAK,UAAI;AACP,mBAAK;AACL;AACF,iBAAK,UAAI;AACP,mBAAK,iBAAiB,KAAK,IAAI,KAAK,IAAI,KAAK;AAC7C;AACF,iBAAK,UAAI;AACP,mBAAK,kBAAkB,KAAK;AAC5B;AACF,iBAAK,UAAI;AACP,mBAAK,wBAAwB,KAAK;AAClC;AACF,iBAAK,UAAI;AACP,mBAAK,sBAAsB,KAAK;AAChC;AACF,iBAAK,UAAI;AACP,mBAAK,sBAAsB,KAAK,IAAI,KAAK;AACzC;AACF,iBAAK,UAAI;AACP,mBAAK;AACL;AACF,iBAAK,UAAI;AACP,mBAAK;AACL;AACF,iBAAK,UAAI;AACP,mBAAK;AACL;AACF,iBAAK,UAAI;AACP,mBAAK;AACL;AACF,iBAAK,UAAI;AACP,mBAAK;AACL;AACF,iBAAK,UAAI;AACP,mBAAK,UAAU,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAChC,KAAK,IAAI,KAAK;AAC7B;AACF,iBAAK,UAAI;AACP,mBAAK,cAAc,KAAK,IAAI,KAAK;AACjC;AACF,iBAAK,UAAI;AACP,mBAAK;AACL;AACF,iBAAK;AACH,mBAAK,MAAM,OAAO,GAAG;AACrB;AACF;AACE,8BAAK,4BAA4B;AACjC;;AA1IkD;AA3FpC;AA0OtB,sBAAgB,SAAS,2BAA2B,aAAa;AAC/D,aAAK,QAAQ,cAAc;AA3OP;AA8OtB,sBAAgB,SAAS,2BAA2B,aAAa;AAC/D,aAAK,QAAQ,cAAc;AA/OP;AAkPtB,gBAAU,SAAS,uBAAuB;AACxC,aAAK,SAAS,GAAG,KAAK,QAAQ;AAnPV;AAsPtB,qBAAe,SAAS,0BAA0B,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG;AAClE,YAAI,UAAU,KAAK;AACnB,aAAK,QAAQ,aAAa,KAAK,QAAQ,aAAa,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG;AAEpE,aAAK,QAAQ,IAAI,KAAK,QAAQ,QAAQ;AACtC,aAAK,QAAQ,IAAI,KAAK,QAAQ,QAAQ;AAEtC,gBAAQ,UAAU;AAClB,gBAAQ,QAAQ,SAAS,gBAAgB,IAAI;AAC7C,gBAAQ,MAAM,eAAe,MAAM,eAAe,QAAQ;AAC1D,gBAAQ,MAAM,eAAe,MAAM,aACN,GAAG,QAAQ,YAAY;AACpD,gBAAQ,MAAM,eAAe,MAAM,KAAK,GAAG,CAAC,QAAQ;AAEpD,gBAAQ,aAAa,SAAS,gBAAgB,IAAI;AAClD,gBAAQ,WAAW,YAAY,QAAQ;AArQnB;AAwQtB,iBAAW,SAAS,wBAAwB;AAC1C,aAAK,QAAQ,IAAI,KAAK,QAAQ,QAAQ;AACtC,aAAK,QAAQ,IAAI,KAAK,QAAQ,QAAQ;AACtC,aAAK,QAAqB;AAC1B,aAAK,QAAqB;AAC1B,aAAK,QAAQ,QAAQ,SAAS,gBAAgB,IAAI;AAClD,aAAK,QAAQ,aAAa,SAAS,gBAAgB,IAAI;AACvD,aAAK,QAAQ,SAAS,SAAS,gBAAgB,IAAI;AACnD,aAAK,QAAQ,UAAU;AAhRH;AAmRtB,gBAAU,SAAS,qBAAqB,GAAG,GAAG;AAC5C,YAAI,UAAU,KAAK;AACnB,aAAK,QAAQ,IAAI,KAAK,QAAQ,SAAS;AACvC,aAAK,QAAQ,IAAI,KAAK,QAAQ,SAAS;AAEvC,gBAAQ,UAAU;AAClB,gBAAQ,QAAQ,SAAS,gBAAgB,IAAI;AAC7C,gBAAQ,MAAM,eAAe,MAAM,eAAe,QAAQ;AAC1D,gBAAQ,MAAM,eAAe,MAAM,aACN,GAAG,QAAQ,YAAY;AACpD,gBAAQ,MAAM,eAAe,MAAM,KAAK,GAAG,CAAC,QAAQ;AA7RhC;AAgStB,gBAAU,SAAS,qBAAqB,QAAQ;AAC9C,YAAI,UAAU,KAAK;AACnB,YAAI,OAAO,QAAQ;AACnB,YAAI,WAAW,QAAQ;AAEvB,YAAI,aAAa,GAAG;AAClB;AAN4C;AAS9C,YAAI,cAAc,QAAQ;AAC1B,YAAI,cAAc,QAAQ;AAC1B,YAAI,gBAAgB,QAAQ;AAC5B,YAAI,aAAa,QAAQ,aAAa;AACtC,YAAI,eAAe,OAAO;AAC1B,YAAI,WAAW,KAAK;AACpB,YAAI,oBAAoB,WAAW,QAAQ,WAAW;AAEtD,YAAI,IAAI;YAAG;AACX,aAAK,IAAI,GAAG,IAAI,cAAc,EAAE,GAAG;AACjC,cAAI,QAAQ,OAAO;AACnB,cAAI,UAAU,MAAM;AAElB,iBAAK,gBAAgB;AACrB;AAHF,iBAIO,IAAI,iBAAM,QAAQ;AACvB,iBAAK,CAAC,QAAQ,WAAW;AACzB;AAR+B;AAUjC,kBAAQ,QAAQ,KAAK,QAAQ,IAAI,IAAI;AAErC,cAAI,QAAQ,MAAM;AAClB,cAAI,YAAY,MAAM;AACtB,cAAI,UAAW,OAAM,UAAU,cAAc,KAAK;AAClD,cAAI,YAAY,QAAQ,oBAAoB,UAAU;AACtD,eAAK;AAEL,kBAAQ,MAAM,eAAe;AApCe;AAsC9C,YAAI,UAAU;AACZ,kBAAQ,KAAK,IAAI;AADnB,eAEO;AACL,kBAAQ,KAAK,IAAI;AAzC2B;AA4C9C,gBAAQ,MAAM,eAAe,MAAM,KACN,QAAQ,QAAQ,IAAI,IAAI,KAAK;AAC1D,gBAAQ,MAAM,eAAe,MAAM,KAAK,GAAG,CAAC,QAAQ;AACpD,gBAAQ,MAAM,eAAe,MAAM,eAAe,QAAQ;AAC1D,gBAAQ,MAAM,eAAe,MAAM,aACN,GAAG,QAAQ,YAAY;AACpD,YAAI,QAAQ,cAAc,aAAa,WAAW;AAChD,kBAAQ,MAAM,eAAe,MAAM,cAAc,QAAQ;AAnDb;AAqD9C,YAAI,QAAQ,eAAe,aAAa,YAAY;AAClD,kBAAQ,MAAM,eAAe,MAAM,eAAe,QAAQ;AAtDd;AAwD9C,YAAI,QAAQ,cAAc,aAAa,WAAW;AAChD,kBAAQ,MAAM,eAAe,MAAM,QAAQ,QAAQ;AAzDP;AA4D9C,gBAAQ,WAAW,eAAe,MAAM,aACN,GAAG,QAAQ,cACX;AAClC,gBAAQ,WAAW,eAAe,QAAQ,aAAa;AACvD,gBAAQ,WAAW,YAAY,QAAQ;AACvC,gBAAQ,OAAO,YAAY,QAAQ;AAEnC,aAAK,wBAAwB,YAAY,QAAQ;AAnW7B;AAsWtB,0BAAoB,SAAS,+BAA+B,GAAG,GAAG;AAChE,aAAK,WAAW,CAAC;AACjB,aAAK,SAAS,GAAG;AAxWG;AA2WtB,oBAAc,SAAS,yBAAyB,SAAS;AACvD,YAAI,CAAC,KAAK,UAAU;AAClB,eAAK,WAAW,SAAS,gBAAgB,IAAI;AAC7C,eAAK,SAAS,eAAe,MAAM,QAAQ;AAC3C,eAAK,KAAK,YAAY,KAAK;AAJ0B;AAOvD,YAAI,MAAM,2BAAgB,QAAQ,MAAM,QAAQ,UACtB,KAAK;AAC/B,aAAK,SAAS,eACZ,gCAAgC,QAAQ,aAAa,OACrD,eAAe,MAAM;AAtXH;AAyXtB,eAAS,SAAS,oBAAoB,SAAS;AAC7C,YAAI,UAAU,KAAK;AACnB,YAAI,UAAU,KAAK,WAAW,IAAI,QAAQ;AAC1C,YAAI,OAAO,QAAQ;AACnB,aAAK,QAAQ,OAAO;AAEpB,YAAI,KAAK,cAAc,QAAQ,QAC3B,CAAC,KAAK,cAAc,QAAQ,aAAa;AAC3C,eAAK,aAAa;AAClB,eAAK,cAAc,QAAQ,cAAc;AATE;AAY7C,gBAAQ,aAAc,QAAQ,aACR,QAAqB;AAE3C,YAAI,OAAO,QAAQ,QAAS,QAAQ,OAAO,WAAW,SAC1B,QAAQ,OAAO,SAAS;AACpD,YAAI,SAAS,QAAQ,SAAS,WAAW;AAEzC,YAAI,OAAO,GAAG;AACZ,iBAAO,CAAC;AACR,kBAAQ,gBAAgB,CAAC;AAF3B,eAGO;AACL,kBAAQ,gBAAgB;AAvBmB;AAyB7C,gBAAQ,WAAW;AACnB,gBAAQ,aAAa,QAAQ;AAC7B,gBAAQ,aAAa;AACrB,gBAAQ,YAAY;AAEpB,gBAAQ,QAAQ,SAAS,gBAAgB,IAAI;AAC7C,gBAAQ,MAAM,eAAe,MAAM,KAAK,GAAG,CAAC,QAAQ;AACpD,gBAAQ,UAAU;AAzZE;AA4ZtB,eAAS,SAAS,sBAAsB,CA5ZlB;AA+ZtB,oBAAc,SAAS,yBAAyB,OAAO;AACrD,aAAK,QAAQ,YAAY;AAhaL;AAkatB,kBAAY,SAAS,uBAAuB,OAAO;AACjD,aAAK,QAAQ,UAAU,gBAAgB;AAnanB;AAqatB,mBAAa,SAAS,wBAAwB,OAAO;AACnD,aAAK,QAAQ,WAAW,iBAAiB;AAtarB;AAwatB,qBAAe,SAAS,0BAA0B,OAAO;AACvD,aAAK,QAAQ,aAAa;AAzaN;AA2atB,sBAAgB,SAAS,2BAA2B,aAAa;AAC/D,aAAK,QAAQ,cAAc;AA5aP;AA8atB,yBAAmB,SAAS,8BAA8B,GAAG,GAAG,GAAG;AACjE,YAAI,QAAQ,WAAK,WAAW,GAAG,GAAG;AAClC,aAAK,QAAQ,cAAc;AAhbP;AAkbtB,oBAAc,SAAS,yBAAyB,WAAW;AACzD,aAAK,QAAQ,YAAY;AAnbL;AAqbtB,uBAAiB,SAAS,4BAA4B,GAAG,GAAG,GAAG;AAC7D,YAAI,QAAQ,WAAK,WAAW,GAAG,GAAG;AAClC,aAAK,QAAQ,YAAY;AACzB,aAAK,QAAQ,QAAQ,SAAS,gBAAgB,IAAI;AAClD,aAAK,QAAQ,UAAU;AAzbH;AA2btB,eAAS,SAAS,oBAAoB,WAAW,WAAW;AAC1D,aAAK,QAAQ,YAAY;AACzB,aAAK,QAAQ,YAAY;AA7bL;AAgctB,qBAAe,SAAS,0BAA0B,KAAK,MAAM;AAC3D,YAAI,UAAU,KAAK;AACnB,YAAI,IAAI,QAAQ;YAAG,IAAI,QAAQ;AAC/B,gBAAQ,OAAO,SAAS,gBAAgB,IAAI;AAC5C,YAAI,IAAI;AACR,YAAI,WAAW,IAAI;AAEnB,aAAK,IAAI,IAAI,GAAG,IAAI,GAAG,IAAI,UAAU,KAAK;AACxC,kBAAQ,IAAI,KAAK;AACf,iBAAK,UAAI;AACP,kBAAI,KAAK;AACT,kBAAI,KAAK;AACT,kBAAI,QAAQ,KAAK;AACjB,kBAAI,SAAS,KAAK;AAClB,kBAAI,KAAK,IAAI;AACb,kBAAI,KAAK,IAAI;AACb,gBAAE,KAAK,KAAK,GAAG,IAAI,GAAG,IAAI,KAAK,GAAG,KAAK,GAAG,IAAI,KAAK,GAAG,KAAK,GAAG,KACvD,KAAK,GAAG,IAAI,GAAG,KAAK;AAC3B;AACF,iBAAK,UAAI;AACP,kBAAI,KAAK;AACT,kBAAI,KAAK;AACT,gBAAE,KAAK,KAAK,GAAG,IAAI,GAAG;AACtB;AACF,iBAAK,UAAI;AACP,kBAAI,KAAK;AACT,kBAAI,KAAK;AACT,gBAAE,KAAK,KAAK,GAAG,IAAI,GAAG;AACtB;AACF,iBAAK,UAAI;AACP,kBAAI,KAAK,IAAI;AACb,kBAAI,KAAK,IAAI;AACb,gBAAE,KAAK,KAAK,GAAG,KAAK,KAAK,GAAG,KAAK,IAAI,KAAK,GAAG,KAAK,IAAI,KAC/C,GAAG,KAAK,IAAI,KAAK,GAAG,IAAI,GAAG;AAClC,mBAAK;AACL;AACF,iBAAK,UAAI;AACP,kBAAI,KAAK,IAAI;AACb,kBAAI,KAAK,IAAI;AACb,gBAAE,KAAK,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,KAAK,GAAG,KAAK,IAAI,KAC5C,GAAG,KAAK,IAAI,KAAK,GAAG,KAAK,IAAI;AACpC,mBAAK;AACL;AACF,iBAAK,UAAI;AACP,kBAAI,KAAK,IAAI;AACb,kBAAI,KAAK,IAAI;AACb,gBAAE,KAAK,KAAK,GAAG,KAAK,KAAK,GAAG,KAAK,IAAI,KAAK,GAAG,IAAI,GAAG,IAC7C,GAAG,IAAI,GAAG;AACjB,mBAAK;AACL;AACF,iBAAK,UAAI;AACP,gBAAE,KAAK;AACP;;AApDqD;AAuD3D,gBAAQ,KAAK,eAAe,MAAM,KAAK,EAAE,KAAK;AAC9C,gBAAQ,KAAK,eAAe,MAAM,QAAQ;AAE1C,aAAK,wBAAwB,YAAY,QAAQ;AAIjD,gBAAQ,UAAU,QAAQ;AAC1B,gBAAQ,gBAAgB,GAAG;AA/fP;AAkgBtB,eAAS,SAAS,sBAAsB;AACtC,YAAI,CAAC,KAAK,aAAa;AACrB;AAFoC;AAItC,YAAI,UAAU,KAAK;AAEnB,YAAI,SAAS,aAAa;AAC1B;AACA,YAAI,WAAW,SAAS,gBAAgB,IAAI;AAC5C,iBAAS,eAAe,MAAM,MAAM;AACpC,iBAAS,eAAe,MAAM,aAAa,GAAG,KAAK;AACnD,YAAI,cAAc,QAAQ,QAAQ;AAClC,YAAI,KAAK,gBAAgB,WAAW;AAClC,sBAAY,eAAe,MAAM,aAAa;AADhD,eAEO;AACL,sBAAY,eAAe,MAAM,aAAa;AAfV;AAiBtC,aAAK,cAAc;AACnB,iBAAS,YAAY;AACrB,aAAK,KAAK,YAAY;AAEtB,YAAI,QAAQ,eAAe;AAGzB,kBAAQ,YAAY;AACpB,eAAK,WAAW,QAAQ,UAAU,MAAM;AACtC,iBAAK,YAAY;AADnB;AAzBoC;AA6BtC,gBAAQ,gBAAgB,UAAU,SAAS;AAE3C,aAAK,OAAO;AAjiBQ;AAoiBtB,YAAM,SAAS,iBAAiB,MAAM;AACpC,aAAK,cAAc;AAriBC;AAwiBtB,iBAAW,SAAS,wBAAwB;AAC1C,YAAI,UAAU,KAAK;AACnB,YAAI,IAAI,QAAQ,KAAK,eAAe,MAAM;AAC1C,aAAK;AACL,gBAAQ,KAAK,eAAe,MAAM,KAAK;AA5iBnB;AA+iBtB,kBAAY,SAAS,uBAAuB,SAAS;AACnD,aAAK,QAAQ,UAAU,CAAC;AAhjBJ;AAmjBtB,mBAAa,SAAS,wBAAwB,UAAU;AACtD,aAAK,QAAQ,WAAW;AApjBJ;AAujBtB,iBAAW,SAAS,sBAAsB,OAAO;AAC/C,aAAK,QAAQ,aAAa,QAAQ;AAxjBd;AA2jBtB,iBAAW,SAAS,sBAAsB,QAAQ;AAChD,aAAK,IAAI,IAAI,GAAG,KAAK,OAAO,QAAQ,IAAI,IAAI,KAAK;AAC/C,cAAI,QAAQ,OAAO;AACnB,cAAI,MAAM,MAAM;AAChB,cAAI,QAAQ,MAAM;AAElB,kBAAQ;AACN,iBAAK;AACH,mBAAK,aAAa;AAClB;AACF,iBAAK;AACH,mBAAK,WAAW;AAChB;AACF,iBAAK;AACH,mBAAK,YAAY;AACjB;AACF,iBAAK;AACH,mBAAK,cAAc;AACnB;AACF,iBAAK;AACH,mBAAK,QAAQ,MAAM,IAAI,MAAM;AAC7B;AACF,iBAAK;AACH,mBAAK,QAAQ;AACb;AACF,iBAAK;AACH,mBAAK,eAAe;AACpB;AACF,iBAAK;AACH,mBAAK,aAAa;AAClB;AACF;AACE,8BAAK,iCAAiC;AACtC;;AAjC0C;AA3jB5B;AAimBtB,YAAM,SAAS,mBAAmB;AAChC,YAAI,UAAU,KAAK;AACnB,gBAAQ,QAAQ,eAAe,MAAM,QAAQ,QAAQ;AACrD,gBAAQ,QAAQ,eAAe,MAAM,gBAAgB,QAAQ;AApmBzC;AAumBtB,cAAQ,SAAS,qBAAqB;AACpC,YAAI,UAAU,KAAK;AAEnB,gBAAQ,QAAQ,eAAe,MAAM,UAAU,QAAQ;AACvD,gBAAQ,QAAQ,eAAe,MAAM,kBACN,QAAQ;AACvC,gBAAQ,QAAQ,eAAe,MAAM,qBACN,GAAG,QAAQ;AAC1C,gBAAQ,QAAQ,eAAe,MAAM,kBAAkB,QAAQ;AAC/D,gBAAQ,QAAQ,eAAe,MAAM,mBAAmB,QAAQ;AAChE,gBAAQ,QAAQ,eAAe,MAAM,gBACN,GAAG,QAAQ,aAAa;AACvD,gBAAQ,QAAQ,eAAe,MAAM,oBACN,QAAQ,UAAU,IAAI,IAAI,KAAK;AAC9D,gBAAQ,QAAQ,eAAe,MAAM,qBACN,GAAG,QAAQ,aAAa;AAEvD,gBAAQ,QAAQ,eAAe,MAAM,QAAQ;AAxnBzB;AA2nBtB,cAAQ,SAAS,qBAAqB;AACpC,aAAK,QAAQ,QAAQ,eAAe,MAAM,aAAa;AACvD,aAAK;AA7nBe;AAgoBtB,kBAAY,SAAS,yBAAyB;AAG5C,aAAK;AACL,aAAK;AApoBe;AAuoBtB,oBAAc,SAAS,2BAA2B;AAChD,aAAK,QAAQ,QAAQ,eAAe,MAAM,aAAa;AACvD,aAAK;AAzoBe;AA4oBtB,mBAAa,SAAS,0BAA0B;AAC9C,aAAK;AACL,aAAK;AA9oBe;AAipBtB,uBAAiB,SAAS,8BAA8B;AACtD,aAAK;AACL,aAAK;AAnpBe;AAspBtB,gCACI,SAAS,uCAAuC;AAClD,YAAI,UAAU,KAAK;AACnB,YAAI,OAAO,SAAS,gBAAgB,IAAI;AACxC,aAAK,eAAe,MAAM,KAAK;AAC/B,aAAK,eAAe,MAAM,KAAK;AAC/B,aAAK,eAAe,MAAM,SAAS;AACnC,aAAK,eAAe,MAAM,UAAU;AACpC,aAAK,eAAe,MAAM,QAAQ,QAAQ;AAE1C,aAAK,wBAAwB,YAAY;AAhqBrB;AAmqBtB,wBAAkB,SAAS,6BAA6B,OAAO,GAAG,GAAG;AACnE,YAAI,SAAS,KAAK,KAAK,IAAI;AAC3B,YAAI,QAAQ,SAAS,gBAAgB,IAAI;AACzC,cAAM,eAAe,UAAU,cAAc,OAAO;AACpD,cAAM,eAAe,MAAM,SAAS,GAAG;AACvC,cAAM,eAAe,MAAM,UAAU,GAAG;AACxC,cAAM,eAAe,MAAM,KAAK;AAChC,cAAM,eAAe,MAAM,KAAK,GAAG,CAAC;AACpC,cAAM,eAAe,MAAM,aACN,WAAW,GAAG,IAAI,KAAK,MAAM,GAAG,CAAC,IAAI,KAAK;AAE/D,aAAK,wBAAwB,YAAY;AA9qBrB;AAirBtB,yBAAmB,SAAS,8BAA8B,OAAO;AAC/D,YAAI,UAAU,KAAK,KAAK,IAAI;AAC5B,YAAI,CAAC,SAAS;AACZ,0BAAK;AACL;AAJ6D;AAM/D,aAAK,wBAAwB;AAvrBT;AA0rBtB,+BACI,SAAS,oCAAoC,SAAS,MAAM;AAC9D,YAAI,QAAQ,QAAQ;AACpB,YAAI,SAAS,QAAQ;AAErB,YAAI,SAAS,oBAAoB,SAAS,KAAK;AAC/C,YAAI,WAAW,SAAS,gBAAgB,IAAI;AAC5C,iBAAS,eAAe,MAAM,KAAK;AACnC,iBAAS,eAAe,MAAM,KAAK;AACnC,iBAAS,eAAe,MAAM,SAAS,GAAG;AAC1C,iBAAS,eAAe,MAAM,UAAU,GAAG;AAC3C,aAAK,QAAQ,UAAU;AACvB,aAAK,KAAK;AACV,YAAI,QAAQ,SAAS,gBAAgB,IAAI;AACzC,cAAM,eAAe,UAAU,cAAc;AAC7C,cAAM,eAAe,MAAM,KAAK;AAChC,cAAM,eAAe,MAAM,KAAK,GAAG,CAAC;AACpC,cAAM,eAAe,MAAM,SAAS,GAAG,SAAS;AAChD,cAAM,eAAe,MAAM,UAAU,GAAG,UAAU;AAClD,cAAM,eAAe,MAAM,aACN,WAAW,GAAG,IAAI,SAAS,MAC3B,GAAG,CAAC,IAAI,UAAU;AACvC,YAAI,MAAM;AACR,eAAK,YAAY;AADnB,eAEO;AACL,eAAK,wBAAwB,YAAY;AAxBmB;AA3rB1C;AAutBtB,6BACI,SAAS,kCAAkC,SAAS;AACtD,YAAI,UAAU,KAAK;AACnB,YAAI,QAAQ,QAAQ;AACpB,YAAI,SAAS,QAAQ;AACrB,YAAI,YAAY,QAAQ;AAExB,gBAAQ,SAAS,SAAS;AAC1B,YAAI,OAAO,SAAS,gBAAgB,IAAI;AACxC,aAAK,eAAe,MAAM,MAAM,QAAQ;AAExC,YAAI,OAAO,SAAS,gBAAgB,IAAI;AACxC,aAAK,eAAe,MAAM,KAAK;AAC/B,aAAK,eAAe,MAAM,KAAK;AAC/B,aAAK,eAAe,MAAM,SAAS,GAAG;AACtC,aAAK,eAAe,MAAM,UAAU,GAAG;AACvC,aAAK,eAAe,MAAM,QAAQ;AAClC,aAAK,eAAe,MAAM,QAAQ,UAAU,QAAQ,SAAS;AAC7D,aAAK,KAAK,YAAY;AAEtB,aAAK,wBAAwB,YAAY;AAEzC,aAAK,wBAAwB,SAAS;AA7uBlB;AAgvBtB,6BACI,SAAS,kCAAkC,QAAQ,MAAM;AAC3D,YAAI,mBAAQ,WAAW,OAAO,WAAW,GAAG;AAC1C,eAAK,UAAU,OAAO,IAAI,OAAO,IAAI,OAAO,IAC7B,OAAO,IAAI,OAAO,IAAI,OAAO;AAHa;AAM3D,YAAI,mBAAQ,SAAS,KAAK,WAAW,GAAG;AACtC,cAAI,QAAQ,KAAK,KAAK,KAAK;AAC3B,cAAI,SAAS,KAAK,KAAK,KAAK;AAE5B,cAAI,WAAW,SAAS,gBAAgB,IAAI;AAC5C,mBAAS,eAAe,MAAM,KAAK,KAAK;AACxC,mBAAS,eAAe,MAAM,KAAK,KAAK;AACxC,mBAAS,eAAe,MAAM,SAAS,GAAG;AAC1C,mBAAS,eAAe,MAAM,UAAU,GAAG;AAC3C,eAAK,QAAQ,UAAU;AACvB,eAAK,KAAK;AACV,eAAK;AAjBoD;AAjvBvC;AAswBtB,2BACI,SAAS,kCAAkC,CAvwBzB;AA4wBtB,mBAAa,SAAS,uBAAuB,UAAU;AAErD,YAAI,MAAM,SAAS,gBAAgB,IAAI;AACvC,YAAI,eAAe,MAAM,WAAW;AACpC,YAAI,eAAe,MAAM,SAAS,SAAS,QAAQ;AACnD,YAAI,eAAe,MAAM,UAAU,SAAS,SAAS;AACrD,YAAI,eAAe,MAAM,uBAAuB;AAChD,YAAI,eAAe,MAAM,WAAW,SAAS,SAAS,QAClB,MAAM,SAAS;AAGnD,YAAI,cAAc,SAAS,gBAAgB,IAAI;AAC/C,YAAI,YAAY;AAChB,aAAK,OAAO;AAIZ,YAAI,YAAY,SAAS,gBAAgB,IAAI;AAC7C,kBAAU,eAAe,MAAM,aAAa,GAAG,SAAS;AACxD,YAAI,YAAY;AAKhB,aAAK,MAAM;AAEX,eAAO;AAtyBa;AA4yBtB,wBAAkB,SAAS,8BAA8B;AACvD,YAAI,CAAC,KAAK,QAAQ,WAAW;AAC3B,cAAI,YAAY,SAAS,gBAAgB,IAAI;AAC7C,oBAAU,eAAe,MAAM,aACN,KAAK,QAAQ;AACtC,eAAK,IAAI,YAAY;AACrB,eAAK,QAAQ,YAAY;AAN4B;AAQvD,eAAO,KAAK,QAAQ;AApzBA;AA0zBtB,6BAAuB,SAAS,mCAAmC;AACjE,YAAI,CAAC,KAAK,MAAM;AACd,eAAK,OAAO,SAAS,gBAAgB,IAAI;AACzC,eAAK,KAAK,eAAe,MAAM,aAAa,GAAG,KAAK;AACpD,cAAI,KAAK,QAAQ,eAAe;AAC9B,iBAAK,mBAAmB,YAAY,KAAK;AAD3C,iBAEO;AACL,iBAAK,IAAI,YAAY,KAAK;AANd;AADiD;AAUjE,eAAO,KAAK;AAp0BQ;AAAA;AAu0BxB,WAAO;AAv6BK,GAAC;AA46Bf;QACE,0B;;;;;;;;;;;;;;AC1uC4D;;AACf;;AAyB/C,IAAI,2BAA4B,yBAAyB;AACvD,MAAI,0BAA0B;AAE9B,MAAI,sBAAsB;AAE1B,WAAS,gBAAgB,KAAK;AAC5B,WAAO,CAAC,oBAAoB,KAAK;AANoB;AAWvD,MAAI,WAAW,CAAC,UAAU,GAAG,aAAa,GAAG,mBAAmB,GAChD,qBAAqB,IAAI;AAEzC,WAAS,WAAW,MAAM,MAAM,QAAQ;AAEtC,QAAI,UAAU,SAAS,cAAc;AACrC,QAAI;AACF,aAAO;AACP,aAAO;AACP,mBAAa;AACb,oBAAc;AACd,yBAAmB;AACnB,qBAAe;AACf,mBAAa;AACb,oBAAc;AACd,kBAAY;AACZ,aAAO;AAVe;AAaxB,SAAK,UAAU,KAAK;AACpB,QAAI,gBAAgB,KAAK,MAAM;AAC7B,wBAAkB,eAAe;AACjC,WAAK,mBAAmB,IAAI,SAAS;AACrC;AApBoC;AAuBtC,QAAI,KAAK,WAAK,UAAU,KAAK,UAAU,WAAW,KAAK;AACvD,QAAI,QAAQ,KAAK,MAAM,GAAG,IAAI,GAAG;AACjC,QAAI,QAAQ,OAAO,KAAK;AACxB,QAAI,MAAM,UAAU;AAClB,eAAS,KAAK,KAAK;AA3BiB;AA6BtC,QAAI,aAAa,KAAK,KAAM,GAAG,KAAK,GAAG,KAAO,GAAG,KAAK,GAAG;AACzD,QAAI,aAAa;AACjB,QAAI,MAAM,QAAQ;AAChB,mBAAa,MAAM,SAAS;AAD9B,WAEO,IAAI,MAAM,SAAS;AACxB,mBAAc,KAAI,MAAM,WAAW;AAlCC;AAqCtC,QAAI;AACJ,QAAI;AACJ,QAAI,UAAU,GAAG;AACf,aAAO,GAAG;AACV,YAAM,GAAG,KAAK;AAFhB,WAGO;AACL,aAAO,GAAG,KAAM,aAAa,KAAK,IAAI;AACtC,YAAM,GAAG,KAAM,aAAa,KAAK,IAAI;AA5CD;AA8CtC,aAAS,KAAK;AACd,aAAS,KAAK;AACd,aAAS,KAAK;AACd,aAAS,KAAK,MAAM;AACpB,sBAAkB,QAAQ,SAAS,KAAK;AACxC,YAAQ,aAAa,SAAS,kBAAkB;AAEhD,YAAQ,cAAc,KAAK;AAK3B,QAAI,kCAAkB,WAAW;AAC/B,cAAQ,QAAQ,WAAW,KAAK;AA3DI;AA6DtC,QAAI,UAAU,GAAG;AACf,wBAAkB,QAAiB,eAAM,KAAK;AA9DV;AAmEtC,QAAI,KAAK,IAAI,SAAS,GAAG;AACvB,UAAI,MAAM,UAAU;AAClB,0BAAkB,cAAc,KAAK,SAAS,KAAK,UAAU;AAD/D,aAEO;AACL,0BAAkB,cAAc,KAAK,QAAQ,KAAK,UAAU;AAJvC;AAnEa;AA0EtC,SAAK,mBAAmB,IAAI,SAAS;AACrC,QAAI,KAAK,oBAAoB;AAC3B,WAAK,YAAY;AA5EmB;AA+EtC,QAAI,KAAK,uBAAuB;AAC9B,UAAI,WAAW;UAAG,WAAW;AAC7B,UAAI,UAAU,GAAG;AACf,mBAAW,KAAK,IAAI;AACpB,mBAAW,KAAK,IAAI;AAJQ;AAM9B,UAAI,WAAY,OAAM,WAAW,KAAK,SAAS,KAAK,SACrC,KAAK,UAAU;AAC9B,UAAI,YAAY;AAEhB,UAAI,GAAG;AACP,UAAI,UAAU,GAAG;AACf,YAAI,CAAC,UAAU,UAAU,CAAC,UAAU,UAAU,MAAM;AACpD,YAAI,WAAK,2BAA2B,CAAC,GAAG,GAAG,UAAU,YAAY;AAFnE,aAGO;AACL,YAAI,CAAC,MAAM,KAAK,OAAO,UAAU,MAAM;AAfX;AAkB9B,WAAK,QAAQ;AACX,cAAM,EAAE;AACR,aAAK,EAAE;AACP,eAAO,EAAE;AACT,gBAAQ,EAAE;AACV,aAAK;AACL,cAAM,CAAC,UAAU;AACjB;AAPgB;AAjGkB;AAde;AA2HvD,WAAS,OAAO,MAAM;AACpB,QAAI,KAAK,WAAW;AAClB;AAFkB;AAIpB,QAAI,WAAW,KAAK;AACpB,QAAI,aAAa,KAAK;AACtB,QAAI,iBAAiB,SAAS;AAI9B,QAAI,iBAAiB,yBAAyB;AAC5C,WAAK,iBAAiB;AACtB,iBAAW;AACX;AAbkB;AAgBpB,QAAI,CAAC,KAAK,oBAAoB;AAC5B,WAAK,IAAI,IAAI,GAAG,IAAI,gBAAgB,KAAK;AACvC,aAAK,YAAY,SAAS;AAFA;AAhBV;AAsBpB,SAAK,iBAAiB;AACtB,eAAW;AAlJ0C;AAqJvD,WAAS,OAAO,MAAM;AACpB,QAAI,SAAS,KAAK;AAClB,QAAI,WAAW,KAAK;AAEpB,QAAI,WAAW,aAAa,SAAS,OAAO,SAAS,QAAQ;AAC7D,SAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,UAAI,MAAM,OAAO,GAAG;AACpB,UAAI,gBAAgB,KAAK,mBAAmB,IAAI;AAChD,UAAI,cAAc,UAAU,GAAG;AAC7B,sBAAc,cAAc,OAAO,GAAG,OAAO,SAAS,GAAG;AACzD,sBAAc,aAAa,OAAO,GAAG,MAAM,SAAS,GAAG;AACvD,sBAAc,eAAe,SAAS,GAAG,QAAQ,OAAO,GAAG;AAC3D,sBAAc,gBAAgB,SAAS,GAAG,SAAS,OAAO,GAAG;AAC7D,aAAK,mBAAmB,IAAI,KAAK;AACjC;AATsC;AAaxC,UAAI,IAAI,SAAS;UAAI,IAAI,OAAO;AAChC,UAAI,IAAI,EAAE;UAAG,IAAI,EAAE;UAAI,IAAI,EAAE;AAE7B,UAAI,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,KAAK,CAAC,EAAE,KAAK,IAAI,IAAI,EAAE;AACxD,UAAI,KAAK,IAAI,aAAa;AAC1B,aAAO,QAAQ,UAAU,GAAG,GAAG;AAC7B,YAAI,IAAI,WAAK,eAAe,GAAG;AAC/B,WAAG,IAAI,KAAK,KAAM,GAAE,OAAO,EAAE,MAAM;AACnC,WAAG,IAAI,KAAK,KAAM,GAAE,MAAM,EAAE,MAAM;AAClC,WAAG,IAAI,KAAK,KAAM,GAAE,QAAQ,EAAE,MAAM;AACpC,WAAG,IAAI,MAAM,KAAM,GAAE,SAAS,EAAE,MAAM;AAEtC,WAAG,IAAI,MAAM,KAAM,GAAE,OAAO,EAAE,MAAM,CAAC;AACrC,WAAG,IAAI,MAAM,KAAM,GAAE,MAAM,EAAE,MAAM;AACnC,WAAG,IAAI,MAAM,KAAM,GAAE,QAAQ,EAAE,MAAM,CAAC;AACtC,WAAG,IAAI,MAAM,KAAM,GAAE,SAAS,EAAE,MAAM;AAEtC,WAAG,IAAI,MAAM,KAAM,GAAE,OAAO,EAAE,MAAM,CAAC;AACrC,WAAG,IAAI,MAAM,KAAM,GAAE,MAAM,EAAE,MAAM,CAAC;AACpC,WAAG,IAAI,MAAM,KAAM,GAAE,QAAQ,EAAE,MAAM,CAAC;AACtC,WAAG,IAAI,MAAM,KAAM,GAAE,SAAS,EAAE,MAAM,CAAC;AAEvC,WAAG,IAAI,MAAM,KAAM,GAAE,OAAO,EAAE,MAAM;AACpC,WAAG,IAAI,MAAM,KAAM,GAAE,MAAM,EAAE,MAAM,CAAC;AACpC,WAAG,IAAI,MAAM,KAAM,GAAE,QAAQ,EAAE,MAAM;AACrC,WAAG,IAAI,MAAM,KAAM,GAAE,SAAS,EAAE,MAAM,CAAC;AApBzC;AAsBA,UAAI,kBAAkB,yBAAU,IAAI,QAAQ,OAAO;AACjD,YAAI,SAAS;AACb,aAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,cAAI,IAAI,GAAG;AACX,cAAI,IAAI,GAAG;AACT,qBAAS,SAAS,KAAK,IAAI,GAAG,UAAU;AAHZ;AAFiB;AAQjD,eAAO;AART;AAYA,UAAI,WAAW,IAAI,KAAK,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI;AAClD,oBAAc,cAAc,gBAAgB,IAAI,IAAI,MAAM;AAC1D,oBAAc,aAAa,gBAAgB,IAAI,IAAI,MAAM;AACzD,oBAAc,eAAe,gBAAgB,IAAI,GAAG,MAAM;AAC1D,oBAAc,gBAAgB,gBAAgB,IAAI,IAAI,MAAM;AAC5D,WAAK,mBAAmB,IAAI,KAAK;AA9Df;AArJiC;AAuNvD,WAAS,aAAa,OAAO,QAAQ,OAAO;AAC1C,QAAI,eAAe,IAAI,UAAU,KAAK,GAAG;AACvC;AACE,YAAI,IAAI;AACR,YAAI,IAAI;AACR,YAAI,IAAI;AACR,YAAI,IAAI;AACR,eAAO;AACP,eAAO;AACP,eAAO;AAPF;AADI;AAWb,oBAAgB,OAAO;AACvB,QAAI,WAAW,IAAI,MAAM,MAAM;AAC/B,WAAO,QAAQ,UAAU,GAAG;AAC1B,UAAI,IAAI,EAAE;AACV,eAAS;AACP,cAAM,EAAE;AACR,aAAK;AACL,eAAO,EAAE;AACT,gBAAQ;AAJI;AAFhB;AAYA,UAAM,IAAI,UAAU,KAAK,GAAG;AAC1B,UAAI,IAAI,SAAS;UAAI,IAAI,OAAO;AAChC,QAAE,KAAK,IAAI;AACX,QAAE,KAAK,QAAQ,EAAE;AACjB,QAAE,KAAK,IAAI;AACX,QAAE,KAAK,QAAQ,EAAE;AACjB,QAAE,QAAQ;AACV,QAAE,QAAQ;AACV,QAAE,QAAQ;AARZ;AAUA,oBAAgB,QAAQ;AAExB,WAAO,QAAQ,UAAU,GAAG;AAC1B,UAAI,IAAI,EAAE;AACV,eAAS,GAAG,MAAM,EAAE;AACpB,eAAS,GAAG,SAAS,EAAE;AAHzB;AAKA,WAAO;AAlQ8C;AAqQvD,WAAS,gBAAgB,OAAO,QAAQ;AAEtC,WAAO,KAAK,UAAU,GAAG,GAAG;AAC1B,aAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE;AADpC;AAKA,QAAI;AACF,UAAI,CAAC;AACL,UAAI,CAAC;AACL,UAAI;AACJ,UAAI;AACJ,aAAO,CAAC;AACR,aAAO;AACP,aAAO;AAPU;AASnB,QAAI;AACF,aAAO,CAAC;AACR,WAAK;AACL,gBAAU;AAHG,KAAD;AAMd,WAAO,QAAQ,UAAU,UAAU;AAGjC,UAAI,IAAI;AACR,aAAO,IAAI,QAAQ,UAAU,QAAQ,GAAG,OAAO,SAAS,IAAI;AAC1D;AAL+B;AAOjC,UAAI,IAAI,QAAQ,SAAS;AACzB,aAAO,KAAK,KAAK,QAAQ,GAAG,SAAS,SAAS,IAAI;AAChD;AAT+B;AAYjC,UAAI,aAAa;AACjB,UAAI;UAAG;UAAG,UAAU,CAAC;AACrB,WAAK,IAAI,GAAG,KAAK,GAAG,KAAK;AACvB,sBAAc,QAAQ;AACtB,2BAAmB,YAAY;AAC/B,YAAI;AACJ,YAAI,iBAAiB,KAAK,SAAS,IAAI;AAIrC,iBAAO,iBAAiB,QAAQ,SAAS,QACvC,iBAAiB,QAAQ,SAAS;AALtC,mBAMW,iBAAiB,UAAU,WAAW;AAG/C,iBAAQ,kBAAiB,KAAK,SAAS,MAAM;AAHxC,eAIA;AAEL,iBAAO,iBAAiB;AAhBH;AAkBvB,YAAI,OAAO,SAAS;AAClB,oBAAU;AAnBW;AAdQ;AAsCjC,eAAS,QAAQ;AAGjB,WAAK,IAAI,GAAG,KAAK,GAAG,KAAK;AACvB,sBAAc,QAAQ;AACtB,2BAAmB,YAAY;AAC/B,YAAI,iBAAiB,UAAU,WAAW;AAExC,cAAI,iBAAiB,KAAK,SAAS,IAAI;AAGrC,gBAAI,iBAAiB,QAAQ,SAAS,OAAO;AAC3C,+BAAiB,QAAQ,iBAAiB;AAJP;AAAvC,iBAMO;AACL,6BAAiB,QAAQ;AATa;AAA1C,eAWO,IAAI,iBAAiB,QAAQ,SAAS;AAE3C,2BAAiB,QAAQ,KAAK,IAAI,SAAS,iBAAiB;AAhBvC;AAzCQ;AA8DjC,UAAI,iBAAiB;UAAI,eAAe;AACxC,WAAK,IAAI,GAAG,KAAK,GAAG,KAAK;AACvB,sBAAc,QAAQ;AACtB,2BAAmB,YAAY;AAE/B,YAAI,cAAc,iBAAiB,KAAK,SAAS,KAC/C,mBAAmB;AACrB,YAAI,iBAAiB,aAAa;AAEhC,yBAAe,eAAe,SAAS,GAAG,MAAM,YAAY;AAF9D,eAGO;AACL,yBAAe;AACb,mBAAO,YAAY;AACnB,iBAAK,YAAY;AACjB,sBAAU;AAHQ;AAKpB,yBAAe;AAfM;AA/DQ;AAiFjC,UAAI,QAAQ,GAAG,QAAQ,SAAS,IAAI;AAClC,uBAAe,GAAG,QAAQ,SAAS;AACnC,uBAAe;AACb,iBAAO,QAAQ,GAAG;AAClB,eAAK,SAAS;AACd,oBAAU,QAAQ,GAAG;AAHA;AAnFQ;AAyFjC,UAAI,SAAS,KAAK,QAAQ,GAAG,KAAK;AAChC,uBAAe,eAAe,SAAS,GAAG,MAAM,SAAS;AACzD,uBAAe;AACb,iBAAO,SAAS;AAChB,eAAK,QAAQ,GAAG;AAChB,oBAAU,QAAQ,GAAG;AAHH;AA3FW;AAqGjC,WAAK,IAAI,GAAG,KAAK,GAAG,KAAK;AACvB,sBAAc,QAAQ;AACtB,2BAAmB,YAAY;AAC/B,YAAI,iBAAiB,UAAU,WAAW;AACxC;AAJqB;AAMvB,YAAI,OAAO;AACX,aAAK,IAAI,IAAI,GAAG,CAAC,QAAQ,KAAK,KAC9B,QAAQ,GAAG,SAAS,iBAAiB,IAAI,KAAK;AAC5C,iBAAO,QAAQ,GAAG,aAAa;AATV;AAWvB,aAAK,IAAI,IAAI,GAAG,CAAC,QAAQ,IAAI,QAAQ,UACrC,QAAQ,GAAG,OAAO,iBAAiB,IAAI,KAAK;AAC1C,iBAAO,QAAQ,GAAG,aAAa;AAbV;AAevB,aAAK,IAAI,GAAG,CAAC,QAAQ,IAAI,eAAe,QAAQ,KAAK;AACnD,iBAAO,eAAe,GAAG,aAAa;AAhBjB;AAkBvB,YAAI,CAAC,MAAM;AACT,2BAAiB,QAAQ;AAnBJ;AArGQ;AA4HjC,YAAM,UAAU,OAAO,MAAM,SAC3B,CAAC,GAAG,IAAI,IAAI,GAAG,OAAO;AA7H1B;AAiIA,YAAQ,QAAQ,UAAU,aAAa;AACrC,UAAI,mBAAmB,YAAY;AACnC,UAAI,iBAAiB,UAAU,WAAW;AACxC,yBAAiB,QAAQ,KAAK,IAAI,OAAO,iBAAiB;AAHvB;AAAvC;AA5ZqD;AA8avD,WAA6B;AAE2B,QAFzB;QAAa;QAAmB;QAChC;QAAU;QAAU;QACpB;;AAC7B,SAAK,eAAe;AACpB,SAAK,qBAAqB;AAC1B,SAAK,aAAa;AAClB,SAAK,YAAY;AACjB,SAAK,YAAY,YAAY;AAC7B,SAAK,uBAAuB,uBAAuB;AACnD,SAAK,wBAAwB,CAAC,CAAC;AAE/B,SAAK,UAAU;AACf,SAAK,0BAA0B;AAC/B,SAAK,4BAA4B;AACjC,SAAK,iBAAiB;AACtB,SAAK,qBAAqB,IAAI;AAC9B,SAAK,iBAAiB;AACtB,SAAK,YAAY;AACjB,SAAK,cAAc;AACnB,SAAK,eAAe;AACpB,SAAK,UAAU;AAlcsC;AAocvD,sBAAoB;AAClB,QAAI,UAAU;AACZ,aAAO,KAAK,YAAY;AAFI;AAK9B,YAAQ,SAAS,mBAAmB;AAClC,UAAI,KAAK,SAAS;AAChB,aAAK,QAAQ,OAAW,yBAAe;AACvC,aAAK,UAAU;AAHiB;AAKlC,WAAK,YAAY;AACjB,UAAI,KAAK,iBAAiB,MAAM;AAC9B,qBAAa,KAAK;AAClB,aAAK,eAAe;AARY;AAUlC,WAAK,YAAY,OAAO;AAfI;AAkB9B,0CAAc,OAAO,YAAY;AAC/B,WAAK,IAAI,IAAI,GAAG,MAAM,MAAM,QAAQ,IAAI,KAAK,KAAK;AAChD,aAAK,qBAAqB,KAAK,MAAM,GAAG;AACxC,mBAAW,MAAM,MAAM,IAAI;AAHE;AAlBH;AAyB9B,sCAAY,SAAS;AACnB,UAAI,gBAAgB,KAAK;AAEzB,UAAI,oBAAoB,KAAK,mBAAmB,IAAI;AACpD,UAAI,kBAAkB,cAAc;AAClC;AALiB;AAQnB,UAAI,WAAW,QAAQ,MAAM;AAC7B,UAAI,aAAa,QAAQ,MAAM;AAG/B,UAAI,aAAa,KAAK,2BAClB,eAAe,KAAK,2BAA2B;AACjD,aAAK,eAAe,OAAO,WAAW,MAAM;AAC5C,aAAK,gBAAgB;AACrB,aAAK,kBAAkB;AAhBN;AAmBnB,UAAI,QAAQ,KAAK,eAAe,YAAY,QAAQ,aAAa;AAEjE,UAAI,YAAY;AAChB,UAAI,kBAAkB,gBAAgB,KAAK,QAAQ,GAAG;AACpD,0BAAkB,QAAQ,kBAAkB,cAAc;AAC1D,oBAAY,YAAY,kBAAkB,QAAQ;AAxBjC;AA0BnB,UAAI,kBAAkB,UAAU,GAAG;AACjC,oBAAY,YAAY,kBAAkB,QAAQ,UAAU;AA3B3C;AA6BnB,UAAI,cAAc,IAAI;AACpB,0BAAkB,oBAAoB;AACtC,+BAAY,QAAQ,aAAa,SAAS;AA/BzB;AAiCnB,WAAK,mBAAmB,IAAI,SAAS;AACrC,oBAAc,YAAY;AA3DE;;AA8D9B,aAAS,SAAS,iBAAiB;AAAS;;AAC1C,UAAI,aAAa;AACjB,UAAI,aAAa,OAAO,OAAO;AAG/B,UAAI,SAAS,SAAS,cAAc;AAGjC,aAAO,YAAY;AAEtB,WAAK,iBAAiB,OAAO,WAAW,MAAM,EAAE,OAAO;AAEvD,UAAI,KAAK,cAAc;AACrB,YAAI,YAAY,KAAK,aAAa;AAClC,YAAI,aAAa,KAAK,aAAa;AACnC,aAAK,cAAc,WAAW;AAC9B,mBAAW;AAJb,iBAKW,KAAK,oBAAoB;AAClC,YAAI,OAAO,gBAAM;AACf,gBAAK,QAAQ,OAAO,KAAM;AAAqB,gBAAnB;gBAAO;;AACjC,gBAAI,MAAM;AACR,yBAAW;AACX;AAH2C;AAM7C,uBAAK,UAAU,YAAY,MAAM;AACjC,kBAAK,cAAc,MAAM,OAAO;AAChC;AARF,aAUG,WAAW;AAXhB;AAcA,aAAK,UAAU,KAAK,mBAAmB;AACvC;AAhBK,aAiBA;AACL,cAAM,IAAI,MAAM,kDACd;AApCsC;AAuC1C,iBAAW,QAAQ,KAAK,YAAM;AAC5B,qBAAa;AACb,YAAI,CAAC,SAAS;AACL;AADT,eAEO;AACL,gBAAK,0BAA0B,YAAM;AAC5B;AACP,kBAAK,eAAe;AAFF,aAGjB;AARuB;AAA9B,SAUG,KAAK,YAAY;AA/GQ;AAkH9B,oBAAgB,SAAS,yBAAyB,YAAY;AAC5D,UAAI,CAAC,KAAK,yBAAyB,CAAC,KAAK,gBAAgB;AACvD;AAF0D;AAI5D,UAAI,KAAK,YAAY,MAAM;AACzB,eAAO;AACP,aAAK,UAAU;AAN2C;AAS5D,WAAK,IAAI,IAAI,GAAG,KAAK,KAAK,UAAU,QAAQ,IAAI,IAAI,KAAK;AACvD,YAAI,MAAM,KAAK,UAAU;AACzB,YAAI,gBAAgB,KAAK,mBAAmB,IAAI;AAEhD,YAAI,cAAc,cAAc;AAC9B;AALqD;AAOvD,YAAI,YAAY;AACd,cAAI,YAAY;cAAI,UAAU;AAE9B,cAAI,cAAc,UAAU,GAAG;AAC7B,wBAAY,YAAY,cAAc,QAAQ;AAJlC;AAMd,cAAI,cAAc,UAAU,GAAG;AAC7B,wBAAY,YAAY,cAAc,QAAQ,UAAU;AAP5C;AASd,cAAI,cAAc,gBAAgB,GAAG;AACnC,uBAAW,oBACR,cAAc,cAAc,cAAc,QAAS;AACtD,yBAAa,iBACV,CAAC,cAAc,cAAc,cAAc,QAAS;AAb3C;AAed,cAAI,cAAc,eAAe,GAAG;AAClC,uBAAW,mBAAmB,cAAc,aAAa;AACzD,yBAAa,iBAAkB,CAAC,cAAc,aAAc;AAjBhD;AAmBd,cAAI,cAAc,iBAAiB,GAAG;AACpC,uBAAW,qBACR,cAAc,eAAe,cAAc,QAAS;AArB3C;AAuBd,cAAI,cAAc,kBAAkB,GAAG;AACrC,uBAAW,sBACT,cAAc,gBAAgB;AAzBpB;AA4Bd,cAAI,YAAY,IAAI;AAClB,gBAAI,aAAa,SAAS,cAAc,QAAQ;AA7BpC;AA+Bd,cAAI,cAAc,IAAI;AACpB,mCAAY,QAAQ,aAAa,KAAK;AAhC1B;AAAhB,eAkCO;AACL,cAAI,MAAM,UAAU;AACpB,iCAAY,QAAQ,aAAa,KACb,cAAc,qBAAqB;AA5CF;AATG;AAlHhC;AAAA;AAmLhC,WAAS,gBAAgB,kBAAkB;AACzC,QAAI,WAAW;AACb,mBAAa,iBAAiB;AAC9B,yBAAmB,iBAAiB;AACpC,iBAAW,iBAAiB;AAC5B,gBAAU,iBAAiB;AAC3B,gBAAU,iBAAiB;AAC3B,2BAAqB,iBAAiB;AACtC,4BAAsB,iBAAiB;AAPN,KAAxB;AASX,SAAK,QAAQ,iBAAiB;AAC9B,WAAO;AAloB8C;AAqoBvD,SAAO;AAGT,CAxoBuB;QAyoBrB,kC;;;;;;;;;;;;ACnqBF,SAAS,YAAY,MAAM;AACzB,cAAY,QAAQ,uBAAuB,UAAS,KAAK,OAAO;AAC9D,QAAI,cAAc,QAAQ,4BACA,UAAS,MAAM,IAAI,IAAI,IAAI;AACnD,aAAO,OAAO,aAAa,KAAK,KAAK,KAAK,IAAI,KAAK;AAFzC;AAIZ,QAAI,QAAQ;AACZ,SAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG;AACxC,UAAI,OAAO,MAAM,WAAW,KAAK,MAAM,MAAM,WAAW,IAAI;AAC5D,eAAU,QAAQ,MAAM,OAAO,OAAO,SAAS,MAAM,SAAS,MAC5D,SAAS,KAAM,OAAO,aAAa,QACnC,QAAS,WAAU,MAAM,SAAS,IAAI,UAAU,KAAK;AAVK;AAY9D,WAAO,MAAM;AAZR;AAhBT;AAgCA,SAAS,SAAS,MAAM;AACtB,MAAI,OAAO,SAAS,UAAU;AAE5B,WAAO,YAAY;AAEnB,QAAI,SAAS,IAAI;AACjB,WAAO,OAAO,gBAAgB,MAAM;AALtC,SAMO,IAAM,kBAAgB,WAAW;AACtC,UAAM,IAAI,MAAM;AARI;AAWtB,OAAK,eAAe;AACpB,OAAK,WAAW,OAAO,OAAO;AAC9B,OAAK;AA7CP;AAgDA,SAAS;AACP,SAAO,SAAS,iBAAiB;AAC/B,QAAI,MAAM,KAAK;AACf,QAAI,MAAM,IAAI;AAEd,QAAI,IAAI,SAAS,kBAAkB,WAAW;AAC5C,YAAM,IAAI;AACV,aAAO,OAAO,IAAI,SAAS,kBAAkB,WAAW;AACtD,cAAM,IAAI;AAHgC;AAJf;AAW/B,QAAI,WAAY,MAAO,IAAI,SAAS,gBAAgB;AACpD,QAAI,CAAC,OAAO,aAAa,aAAa,CAAC,IAAI,iBAAiB;AAC1D;AAb6B;AAgB/B,QAAI,WAAW,IAAI;QAAY;QAAM;QAAO;QAAM;QAAG;QAAI;QAAQ;AACjE,SAAK,IAAI,GAAG,SAAS,SAAS,QAAQ,IAAI,QAAQ,KAAK;AACrD,aAAO,SAAS;AAChB,UAAI,KAAK,SAAS,kBAAkB,mBAAmB;AACrD;AAHmD;AAMrD,WAAK,KAAK,GAAG,UAAU,KAAK,WAAW,QAAQ,KAAK,SAAS,MAAM;AACjE,YAAI,KAAK,WAAW,IAAI,SAAS,kBAAkB,SAAS;AAC1D,kBAAQ,KAAK,WAAW;AACxB,iBAAO,MAAM,SAAS;AACtB,eAAK,SAAS,QAAQ,MAAM,YAAY;AAJuB;AANd;AAjBxB;AADd;AAkCnB,OAAK,SAAS,aAAa,MAAM;AAC/B,WAAO,KAAK,SAAS,SAAS;AAnCb;AAsCnB,OAAK,SAAS,aAAa,MAAM;AAC/B,WAAO,OAAO,KAAK,SAAS,UAAU;AAI1C;AA3CqB;QA4CnB,oB;;;;;;;;;;;;;;AC5EgC;;AACX;;AAEvB,IAAI,sBAAuB,oBAAoB;AAC7C,WAAS,WAAW,IAAI,MAAM,YAAY;AACxC,QAAI,SAAS,GAAG,aAAa;AAC7B,OAAG,aAAa,QAAQ;AACxB,OAAG,cAAc;AACjB,QAAI,WAAW,GAAG,mBAAmB,QAAQ,GAAG;AAChD,QAAI,CAAC,UAAU;AACb,UAAI,WAAW,GAAG,iBAAiB;AACnC,YAAM,IAAI,MAAM,sCAAsC;AAPhB;AASxC,WAAO;AAVoC;AAY7C,WAAS,mBAAmB,IAAI,MAAM;AACpC,WAAO,WAAW,IAAI,MAAM,GAAG;AAbY;AAe7C,WAAS,qBAAqB,IAAI,MAAM;AACtC,WAAO,WAAW,IAAI,MAAM,GAAG;AAhBY;AAkB7C,WAAS,cAAc,IAAI,SAAS;AAClC,QAAI,UAAU,GAAG;AACjB,SAAK,IAAI,IAAI,GAAG,KAAK,QAAQ,QAAQ,IAAI,IAAI,EAAE,GAAG;AAChD,SAAG,aAAa,SAAS,QAAQ;AAHD;AAKlC,OAAG,YAAY;AACf,QAAI,SAAS,GAAG,oBAAoB,SAAS,GAAG;AAChD,QAAI,CAAC,QAAQ;AACX,UAAI,WAAW,GAAG,kBAAkB;AACpC,YAAM,IAAI,MAAM,mCAAmC;AATnB;AAWlC,WAAO;AA7BoC;AA+B7C,WAAS,cAAc,IAAI,OAAO,WAAW;AAC3C,OAAG,cAAc;AACjB,QAAI,UAAU,GAAG;AACjB,OAAG,YAAY,GAAG,YAAY;AAG9B,OAAG,cAAc,GAAG,YAAY,GAAG,gBAAgB,GAAG;AACtD,OAAG,cAAc,GAAG,YAAY,GAAG,gBAAgB,GAAG;AACtD,OAAG,cAAc,GAAG,YAAY,GAAG,oBAAoB,GAAG;AAC1D,OAAG,cAAc,GAAG,YAAY,GAAG,oBAAoB,GAAG;AAG1D,OAAG,WAAW,GAAG,YAAY,GAAG,GAAG,MAAM,GAAG,MAAM,GAAG,eAAe;AACpE,WAAO;AA5CoC;AA+C7C,MAAI,WAAW;AACf,WAAS,aAAa;AACpB,QAAI,WAAW;AACb;AAFkB;AAMpB,oBAAgB,SAAS,cAAc;AACvC,gBAAY,cAAc,WAAW,SACnC,EAAE,oBAAoB;AAxDmB;AA2D7C,MAAI,wBAAwB;;;;;;;;;;;;;;AAe5B,MAAI,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6B9B,MAAI,aAAa;AAEjB,WAAS,cAAc;AACrB,QAAI,QAAQ;AAEZ;AACA,aAAS;AACT,oBAAgB;AAChB,SAAK;AACL,gBAAY;AAGZ,QAAI,eAAe,mBAAmB,IAAI;AAC1C,QAAI,iBAAiB,qBAAqB,IAAI;AAC9C,QAAI,UAAU,cAAc,IAAI,CAAC,cAAc;AAC/C,OAAG,WAAW;AAEd,QAAI,QAAQ;AACZ,UAAM,KAAK;AACX,UAAM,SAAS;AACf,UAAM,qBAAqB,GAAG,mBAAmB,SAAS;AAC1D,UAAM,mBAAmB,GAAG,kBAAkB,SAAS;AACvD,UAAM,mBAAmB,GAAG,mBAAmB,SAAS;AACxD,UAAM,kBAAkB,GAAG,mBAAmB,SAAS;AAEvD,QAAI,mBAAmB,GAAG,kBAAkB,SAAS;AACrD,QAAI,mBAAmB,GAAG,mBAAmB,SAAS;AACtD,QAAI,kBAAkB,GAAG,mBAAmB,SAAS;AAGrD,QAAI,iBAAiB,GAAG;AACxB,OAAG,WAAW,GAAG,cAAc;AAC/B,OAAG,WAAW,GAAG,cAAc,IAAI,aAAa,CAC9C,KAAK,KACL,KAAK,KACL,KAAK,KACL,KAAK,KACL,KAAK,KACL,KAAK,OAAO,GAAG;AACjB,OAAG,wBAAwB;AAC3B,OAAG,oBAAoB,kBAAkB,GAAG,GAAG,OAAO,OAAO,GAAG;AAEhE,OAAG,UAAU,kBAAkB;AAC/B,OAAG,UAAU,iBAAiB;AAE9B,iBAAa;AApJ8B;AAuJ7C,WAAS,aAAa,OAAO,MAAM,YAAY;AAC7C,QAAI,QAAQ,MAAM;QAAO,SAAS,MAAM;AAExC,QAAI,CAAC,YAAY;AACf;AAJ2C;AAM7C,QAAI,QAAQ;QAAY,SAAS,MAAM;QAAQ,KAAK,MAAM;AAC1D,WAAO,QAAQ;AACf,WAAO,SAAS;AAChB,OAAG,SAAS,GAAG,GAAG,GAAG,oBAAoB,GAAG;AAC5C,OAAG,UAAU,MAAM,oBAAoB,OAAO;AAE9C,QAAI,WAAW,UAAU;AACvB,SAAG,UAAU,MAAM,oBAAoB,WAAW,SAAS,IAC9C,WAAW,SAAS,IAAI,WAAW,SAAS,IAAI;AAF/D,WAGO;AACL,SAAG,UAAU,MAAM,oBAAoB,GAAG,GAAG,GAAG;AAhBL;AAkB7C,OAAG,UAAU,MAAM,iBACN,WAAW,YAAY,eAAe,IAAI;AAGvD,QAAI,UAAU,cAAc,IAAI,OAAO,GAAG;AAC1C,QAAI,cAAc,cAAc,IAAI,MAAM,GAAG;AAK7C,QAAI,SAAS,GAAG;AAChB,OAAG,WAAW,GAAG,cAAc;AAC/B,OAAG,WAAW,GAAG,cAAc,IAAI,aAAa,CAC9C,GAAG,GACH,OAAO,GACP,GAAG,QACH,GAAG,QACH,OAAO,GACP,OAAO,UAAU,GAAG;AACtB,OAAG,wBAAwB,MAAM;AACjC,OAAG,oBAAoB,MAAM,kBAAkB,GAAG,GAAG,OAAO,OAAO,GAAG;AAGtE,OAAG,WAAW,GAAG,GAAG,GAAG;AACvB,OAAG,OAAO,GAAG;AACb,OAAG,UAAU,GAAG,KAAK,GAAG;AACxB,OAAG,MAAM,GAAG;AAEZ,OAAG,WAAW,GAAG,WAAW,GAAG;AAE/B,OAAG;AAEH,OAAG,cAAc;AACjB,OAAG,cAAc;AACjB,OAAG,aAAa;AAEhB,WAAO;AA7MoC;AAgN7C,MAAI,0BAA0B;;;;;;;;;;;;;;;;;AAkB9B,MAAI,4BAA4B;;;;;;;;AAShC,MAAI,eAAe;AAEnB,WAAS,gBAAgB;AACvB,QAAI,QAAQ;AAEZ;AACA,aAAS;AACT,oBAAgB;AAChB,SAAK;AACL,gBAAY;AAGZ,QAAI,eAAe,mBAAmB,IAAI;AAC1C,QAAI,iBAAiB,qBAAqB,IAAI;AAC9C,QAAI,UAAU,cAAc,IAAI,CAAC,cAAc;AAC/C,OAAG,WAAW;AAEd,QAAI,QAAQ;AACZ,UAAM,KAAK;AACX,UAAM,SAAS;AACf,UAAM,qBAAqB,GAAG,mBAAmB,SAAS;AAC1D,UAAM,gBAAgB,GAAG,mBAAmB,SAAS;AACrD,UAAM,iBAAiB,GAAG,mBAAmB,SAAS;AACtD,UAAM,mBAAmB,GAAG,kBAAkB,SAAS;AACvD,UAAM,gBAAgB,GAAG,kBAAkB,SAAS;AAEpD,mBAAe;AArQ4B;AAwQ7C,WAAS,YAAY,OAAO,QAAQ,iBAAiB,SAAS,SAAS;AACrE,QAAI,CAAC,cAAc;AACjB;AAFmE;AAIrE,QAAI,QAAQ;QAAc,SAAS,MAAM;QAAQ,KAAK,MAAM;AAE5D,WAAO,QAAQ;AACf,WAAO,SAAS;AAChB,OAAG,SAAS,GAAG,GAAG,GAAG,oBAAoB,GAAG;AAC5C,OAAG,UAAU,MAAM,oBAAoB,OAAO;AAG9C,QAAI,QAAQ;AACZ,QAAI,GAAG,IAAI;AACX,SAAK,IAAI,GAAG,KAAK,QAAQ,QAAQ,IAAI,IAAI,KAAK;AAC5C,cAAQ,QAAQ,GAAG;AACjB,aAAK;AACH,iBAAQ,QAAQ,GAAG,OAAO,SAAS,QAAQ,GAAG,iBAAkB;AAChE,mBAAU,QAAa,cAAQ,GAAG,iBAAiB,KAAK;AACxD;AACF,aAAK;AACH,mBAAS,QAAQ,GAAG,OAAO;AAC3B;;AAtB+D;AA0BrE,QAAI,SAAS,IAAI,aAAa,QAAQ;AACtC,QAAI,SAAS,IAAI,WAAW,QAAQ;AACpC,QAAI,YAAY,QAAQ;QAAQ,YAAY,QAAQ;AACpD,QAAI,SAAS;QAAG,SAAS;AACzB,SAAK,IAAI,GAAG,KAAK,QAAQ,QAAQ,IAAI,IAAI,KAAK;AAC5C,UAAI,SAAS,QAAQ;UAAI,KAAK,OAAO;UAAQ,KAAK,OAAO;AACzD,cAAQ,OAAO;AACb,aAAK;AACH,cAAI,OAAO,OAAO;AAClB,iBAAQ,GAAG,SAAS,OAAQ;AAC5B,eAAK,IAAI,MAAM,GAAG,MAAM,MAAM,OAAO;AACnC,gBAAI,SAAS,MAAM,OAAO;AAC1B,iBAAK,IAAI,MAAM,GAAG,MAAM,MAAM,OAAO,UAAU;AAC7C,qBAAO,UAAU,UAAU,GAAG,SAAS,OAAO;AAC9C,qBAAO,SAAS,KAAK,UAAU,GAAG,SAAS,OAAO,KAAK;AACvD,qBAAO,SAAS,KAAK,UAAU,GAAG,SAAS;AAC3C,qBAAO,SAAS,KAAK,UAAU,GAAG,SAAS,QAAQ;AACnD,qBAAO,SAAS,KAAK,UAAU,GAAG,SAAS;AAC3C,qBAAO,SAAS,KAAK,UAAU,GAAG,SAAS,KAAK;AAChD,qBAAO,UAAU,UAAU,GAAG,SAAS,OAAO;AAC9C,qBAAO,SAAS,KAAK,UAAU,GAAG,SAAS,OAAO,KAAK;AACvD,qBAAO,SAAS,KAAK,UAAU,GAAG,SAAS,OAAO,KAAK;AACvD,qBAAO,SAAS,KAAK,UAAU,GAAG,SAAS;AAC3C,qBAAO,SAAS,KAAK,UAAU,GAAG,SAAS,QAAQ;AACnD,qBAAO,SAAS,KAAK,UAAU,GAAG,SAAS,QAAQ;AACnD,qBAAO,SAAS,KAAK,UAAU,GAAG,SAAS;AAC3C,qBAAO,SAAS,KAAK,UAAU,GAAG,SAAS,KAAK;AAChD,qBAAO,SAAS,KAAK,UAAU,GAAG,SAAS,KAAK;AAEhD,qBAAO,SAAS,KAAK,OAAO,SAAS;AACrC,qBAAO,SAAS,KAAK,OAAO,SAAS;AACrC,qBAAO,SAAS,KAAK,OAAO,SAAS;AACrC,qBAAO,SAAS,KAAK,OAAO,SAAS;AACrC,qBAAO,SAAS,MAAM,UAAU,GAAG;AACnC,qBAAO,SAAS,MAAM,UAAU,GAAG,UAAU;AAC7C,qBAAO,SAAS,KAAK,OAAO,SAAS;AACrC,qBAAO,SAAS,MAAM,OAAO,SAAS;AACtC,qBAAO,SAAS,MAAM,OAAO,SAAS;AACtC,qBAAO,SAAS,MAAM,OAAO,SAAS;AACtC,qBAAO,SAAS,MAAM,OAAO,SAAS;AACtC,qBAAO,SAAS,MAAM,OAAO,SAAS;AACtC,qBAAO,SAAS,MAAM,UAAU,GAAG;AACnC,qBAAO,SAAS,MAAM,UAAU,GAAG,UAAU;AAC7C,qBAAO,SAAS,MAAM,UAAU,GAAG,UAAU;AAC7C,wBAAU;AACV,wBAAU;AAnCuB;AAHvC;AAyCE;AACF,aAAK;AACH,eAAK,IAAI,IAAI,GAAG,KAAK,GAAG,QAAQ,IAAI,IAAI,KAAK;AAC3C,mBAAO,UAAU,UAAU,GAAG;AAC9B,mBAAO,SAAS,KAAK,UAAU,GAAG,KAAK;AACvC,mBAAO,UAAU,UAAU,GAAG;AAC9B,mBAAO,SAAS,KAAK,UAAU,GAAG,KAAK;AACvC,mBAAO,SAAS,KAAK,UAAU,GAAG,KAAK;AACvC,sBAAU;AACV,sBAAU;AARd;AAUE;;AArF+D;AA0FrE,QAAI,iBAAiB;AACnB,SAAG,WAAW,gBAAgB,KAAK,KAAK,gBAAgB,KAAK,KAC/C,gBAAgB,KAAK,KAAK;AAF1C,WAGO;AACL,SAAG,WAAW,GAAG,GAAG,GAAG;AA9F4C;AAgGrE,OAAG,MAAM,GAAG;AAEZ,QAAI,eAAe,GAAG;AACtB,OAAG,WAAW,GAAG,cAAc;AAC/B,OAAG,WAAW,GAAG,cAAc,QAAQ,GAAG;AAC1C,OAAG,wBAAwB,MAAM;AACjC,OAAG,oBAAoB,MAAM,kBAAkB,GAAG,GAAG,OAAO,OAAO,GAAG;AAEtE,QAAI,eAAe,GAAG;AACtB,OAAG,WAAW,GAAG,cAAc;AAC/B,OAAG,WAAW,GAAG,cAAc,QAAQ,GAAG;AAC1C,OAAG,wBAAwB,MAAM;AACjC,OAAG,oBAAoB,MAAM,eAAe,GAAG,GAAG,eAAe,OAC1C,GAAG;AAE1B,OAAG,UAAU,MAAM,eAAe,QAAQ,QAAQ,QAAQ;AAC1D,OAAG,UAAU,MAAM,gBAAgB,QAAQ,SAAS,QAAQ;AAE5D,OAAG,WAAW,GAAG,WAAW,GAAG;AAE/B,OAAG;AAEH,OAAG,aAAa;AAChB,OAAG,aAAa;AAEhB,WAAO;AAjYoC;AAoY7C,WAAS,UAAU;AACjB,QAAI,cAAc,WAAW,QAAQ;AACnC,iBAAW,OAAO,QAAQ;AAC1B,iBAAW,OAAO,SAAS;AAHZ;AAKjB,QAAI,gBAAgB,aAAa,QAAQ;AACvC,mBAAa,OAAO,QAAQ;AAC5B,mBAAa,OAAO,SAAS;AAPd;AASjB,iBAAa;AACb,mBAAe;AA9Y4B;AAiZ7C;AACE,QAAI,YAAY;AACd,UAAI,kCAAkB,iBAAiB;AACrC,eAAO;AAFK;AAId,UAAI,UAAU;AACd,UAAI;AACF;AACA,kBAAU,CAAC,CAAC;AAFd,QAGE,OAAO,GAAG,CARE;AASd,aAAO,kBAAO,MAAM,aAAa;AAV9B;AAYL;AACA;AACA,WAAO;AAdF;AAkBT,CAnakB;QAoahB,wB;;;;;;;;;;;;;;ACraK;;AAIA;;AAOA;;AACyB;;AACP;;AACO;;AACJ;;AAE5B,IAAI,WAAY,OAAO,WAAW;AAMlC,IAAI,CAAC,kBAAY,OAAO;AACtB,oBAAY,QAAQ;AA1CtB;AA4CA,IAAI,QAAQ,kBAAY;AAEa;AACnC,QAAM,UAAU;AAChB,QAAM,QAAQ;AAhDhB;AAmDA,MAAM,SAAS;AAEf,IAAI,MAAM,cAAc,WAAW;AACjC,+BAAkB,MAAM;AAtD1B;AAwDA,OAAO,MAAM;AACb,OAAO,eAAe,OAAO;AAC3B,sBAAM;AACJ,WAAO;AAF+B;AAIxC,oBAAI,OAAO;AACT,iCAAkB;AALoB;;AAOxC,cAAY;AACZ,gBAAc;AAR0B;AAW1C,MAAyB;AACzB,MAAY;AACZ,MAA6B;AAC7B,MAAmB;AACnB,MAAe;AACf,MAAmB;AACnB,MAAM,kBAAkB,SAAS,sBAAsB,MAAM,aAAa;AACxE,SAAO,2BAAgB,MAAM,aAAa,MAAM;AADlD;AAGA,OAAO,eAAe,OAAO;AAC3B,gBAAc;AACd,OAAK,SAAS,uBAAuB;AACnC,WAAO,kBAAO,OAAO,kBAAkB;AAHI;AAAA;AAM/C,MAA6B;AAC7B,MAA0B;AAC1B,MAA0B;AAC1B,MAA8B;AAC9B,MAA4B;AAC5B,MAA4B;AAC5B,MAAoC;AACpC,MAAa;AACb,MAAqB;AACrB,MAAgC;AAOhC,MAAM,eAAgB,MAAM,iBAAiB,YACvB,CAAC,IAAI,MAAM;AAOjC,MAAM,UAAW,MAAM,YAAY,YAAY,OAAO,MAAM;AAM5D,MAAM,aAAa,MAAM,eAAe,YAAY,QAAQ,MAAM;AAQlE,MAAM,kBAAmB,MAAM,oBAAoB,YAC1B,QAAQ,MAAM;AAOvC,MAAM,qBAAsB,MAAM,uBAAuB,YAC7B,KAAK,MAAM;AAQvC,MAAM,gBAAiB,MAAM,kBAAkB,YACxB,QAAQ,MAAM;AAUrC,MAAM,YAAa,MAAM,cAAc,YAAY,OAAO,MAAM;AAMhE,MAAM,aAAc,MAAM,eAAe,YAAY,OAAO,MAAM;AAQlE,MAAM,eAAgB,MAAM,iBAAiB,YACvB,QAAQ,MAAM;AAOpC,MAAM,gBAAiB,MAAM,kBAAkB,YACxB,QAAQ,MAAM;AAWrC,MAAM,mBAAoB,MAAM,qBAAqB,YAC3B,QAAQ,MAAM;AAMxC,MAAM,SAAU,MAAM,WAAW,YAAY,QAAQ,MAAM;AAM3D,MAAM,uBAAwB,MAAM,yBAAyB,YAC/B,OAAO,MAAM;AAM3C,MAAM,yBAA0B,MAAM,2BAA2B,YACjC,QAAQ,MAAM;AAM9C,MAAM,eAAgB,MAAM,iBAAiB,YACvB,OAAO,MAAM;AAYnC,MAAM,qBAAsB,MAAM,uBAAuB,YAC7B,sBAAW,OAAO,MAAM;AAOpD,MAAM,kBAAmB,MAAM,oBACN,0CAAmB,MAAM;AAOlD,MAAM,kBAAmB,MAAM,oBAAoB,YAC1B,OAAO,MAAM;AAOtC,MAAM,YAAa,MAAM,cAAc,YAAa,QAAQ,MAAM;AAEG;AACnE,MAAI,oCAAoC,MAAM;AAC9C,SAAO,MAAM;AACb,SAAO,eAAe,OAAO;AAC3B,wBAAM;AACJ,aAAO,MAAM,uBAAuB,sBAAW;AAFU;AAI3D,sBAAI,OAAO;AACT,UAAI,OAAO;AACT,8BAAW,oDACT;AAHK;AAKT,UAAI,MAAM,uBAAuB,sBAAW,MAAM;AAChD,wBAAK;AACL;AAPO;AAST,YAAM,qBAAqB,QAAQ,sBAAW,QAAQ,sBAAW;AAbR;;AAe3D,gBAAY;AACZ,kBAAc;AAhB6C;AAkB7D,MAAI,mCAAmC;AASrC,UAAM,+BAA+B;AA9B4B;AAzPrE;AA2RA,MAAoB;AACpB,MAAqB;AACrB,MAA8B;AAC9B,MAAkB;AAElB,MAAM,uBAAuB;AAC7B,MAAoB;AACpB,MAAmB;AACnB,MAA0B;AAC1B,MAA2B;AAC3B,MAAgC;AAEhC,MAAwB;AAExB,MAAwB;AAExB,MAAiB;AAEjB,MAAoB;AAEpB,MAEA;QACE;QACA;QACA,c;;;;;;;;;;;;;;AClSK;;AACkC;;AAEzC;AAKA,IAAI,cAAc;AAClB,IAAI,2BAA2B;AAE/B,SAAS,eAAe,KAAK,MAAM;AACjC,OAAK,MAAM;AACX,SAAO,QAAQ;AACf,OAAK,SAAS,YAAY,KAAK;AAC/B,OAAK,cAAe,KAAK,UAAU,KAAK,eAAgB;AACxD,OAAK,kBAAkB,KAAK,mBAAmB;AAC/C,OAAK,SAAS,KAAK,UACjB,SAAS,wBAAwB;AAC/B,WAAO,IAAI;AAFf;AAKA,OAAK,YAAY;AACjB,OAAK,kBAAkB,OAAO,OAAO;AACrC,OAAK,iBAAiB,OAAO,OAAO;AA1CtC;AA6CA,SAAS,eAAe,KAAK;AAC3B,MAAI,OAAO,IAAI;AACf,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO;AAHkB;AAK3B,MAAI,SAAS,KAAK;AAClB,MAAI,QAAQ,IAAI,WAAW;AAC3B,OAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,UAAM,KAAK,KAAK,WAAW,KAAK;AARP;AAU3B,SAAO,MAAM;AAvDf;AA0DA,IAAI,8BAEU,4BAA4B;AACxC,MAAI;AACF,QAAI,IAAI,IAAI;AAOZ,MAAE,KAAK,OAAO,kBAAY,SAAS;AACnC,MAAE,eAAe;AACjB,WAAO,EAAE,iBAAiB;AAV5B,IAWE,OAAO,GAAG;AACV,WAAO;AAb+B;AAAtC,CAAC;AAiBL,eAAe;AACb,gBAAc,SAAS,4BAA4B,OAAO,KAAK,WAAW;AACxE,QAAI;AACF;AACA;AAFS;AAIX,aAAS,QAAQ,WAAW;AAC1B,WAAK,QAAQ,UAAU;AAN+C;AAQxE,WAAO,KAAK,QAAQ;AATG;AAYzB,eAAa,SAAS,2BAA2B,WAAW;AAC1D,WAAO,KAAK,QAAQ;AAbG;AAgBzB,WAAS,SAAS,uBAAuB,MAAM;AAC7C,QAAI,MAAM,KAAK;AACf,QAAI,QAAQ,KAAK;AACjB,QAAI,iBAAiB,KAAK,gBAAgB,SAAS,EACjD;AAGF,QAAI,KAAK,OAAO,KAAK;AACrB,QAAI,kBAAkB,KAAK;AAC3B,aAAS,YAAY,KAAK,aAAa;AACrC,UAAI,QAAQ,KAAK,YAAY;AAC7B,UAAI,OAAO,UAAU,aAAa;AAChC;AAHmC;AAKrC,UAAI,iBAAiB,UAAU;AAdY;AAgB7C,QAAI,KAAK,UAAU,WAAW,QAAQ,SAAS,MAAM;AACnD,UAAI,WAAW,KAAK,QAAe,YAAK,MAAM;AAC9C,UAAI,iBAAiB,SAAS,WAAW;AACzC,qBAAe,iBAAiB;AAHlC,WAIO;AACL,qBAAe,iBAAiB;AArBW;AAwB7C,QAAI,uBAAuB,sBAAsB,CAAC,CAAC,KAAK;AACxD,QAAI,sBAAsB;AACxB,UAAI,eAAe;AACnB,qBAAe,oBAAoB,KAAK;AACxC,qBAAe,aAAa;AAH9B,WAIO;AACL,UAAI,eAAe;AA9BwB;AAiC7C,QAAI,KAAK,SAAS;AAChB,UAAI,UAAU,UAAS,KAAK;AAC1B,aAAK,QAAQ,IAAI;AADnB;AAlC2C;AAsC7C,QAAI,qBAAqB,KAAK,cAAc,KAAK,MAAM;AACvD,QAAI,aAAa,KAAK,WAAW,KAAK,MAAM;AAE5C,mBAAe,oBAAoB,KAAK;AACxC,mBAAe,SAAS,KAAK;AAC7B,mBAAe,UAAU,KAAK;AAC9B,mBAAe,aAAa,KAAK;AAEjC,QAAI,KAAK;AAET,WAAO;AAhEgB;AAmEzB,cAAY,SAAS,0BAA0B,OAAO,KAAK;AACzD,QAAI,iBAAiB,KAAK,gBAAgB;AAC1C,QAAI,CAAC,gBAAgB;AAEnB;AAJuD;AAOzD,QAAI,eAAe,YAAY;AAC7B,UAAI,QAAQ,eAAe,eAAe;AAC1C,qBAAe,kBAAkB;AATsB;AAYzD,QAAI,aAAa,eAAe;AAChC,QAAI,YAAY;AACd,iBAAW;AAd4C;AAnElC;AAqFzB,iBAAe,SAAS,6BAA6B,OAAO,KAAK;AAC/D,QAAI,iBAAiB,KAAK,gBAAgB;AAC1C,QAAI,CAAC,gBAAgB;AAEnB;AAJ6D;AAO/D,QAAI,MAAM,eAAe;AACzB,QAAI,IAAI,cAAc,KAAK,eAAe,mBAAmB;AAC3D,qBAAe;AACf,aAAO,eAAe;AAVuC;AAa/D,QAAI,IAAI,eAAe,GAAG;AACxB;AAd6D;AAiB/D,QAAM,WAAS,KAAK,kBAAkB;AAGpC;AApB6D;AAuB/D,WAAO,KAAK,gBAAgB;AAG5B,QAAI,IAAI,WAAW,KAAK,KAAK,QAAQ;AACnC,UAAI,eAAe,SAAS;AAC1B,uBAAe,QAAQ,IAAI;AAFM;AAInC;AA9B6D;AAgC/D,QAAI,YAAY,IAAI,UAAU;AAK9B,QAAI,+BACA,cAAc,eACd,eAAe,mBAAmB;AAEtC,QAAI,CAAC,gCACD,cAAc,eAAe,gBAAgB;AAC/C,UAAI,eAAe,SAAS;AAC1B,uBAAe,QAAQ,IAAI;AAFkB;AAI/C;AA9C6D;AAiD/D,SAAK,eAAe,SAAS;AAE7B,QAAI,QAAQ,eAAe;AAC3B,QAAI,cAAc,0BAA0B;AAC1C,UAAI,cAAc,IAAI,kBAAkB;AACxC,UAAI,UAAU,2BAA2B,KAAK;AAC9C,UAAI,QAAQ,SAAS,QAAQ,IAAI;AACjC,qBAAe;AACb;AACA;AAFoB;AAJxB,eAQW,eAAe,mBAAmB;AAC3C,qBAAe,OAAO;AADjB,eAEI,OAAO;AAChB,qBAAe;AACb,eAAO;AACP;AAFoB;AADjB,WAKA,IAAI,eAAe,SAAS;AACjC,qBAAe,QAAQ,IAAI;AApEkC;AArFxC;AA6JzB,sBAAoB,SAAS,oCAAoC;AAC/D,aAAS,SAAS,KAAK,iBAAiB;AACtC,aAAO;AAFsD;AAI/D,WAAO;AAjKgB;AAoKzB,iBAAe,SAAS,sBAAsB,OAAO;AACnD,WAAO,KAAK,gBAAgB,OAAO;AArKZ;AAwKzB,sBAAoB,SAAS,kCAAkC,OAAO;AACpE,WAAO,CAAC,CAAE,KAAK,gBAAgB,OAAO;AAzKf;AA4KzB,oBAAkB,SAAS,gCAAgC,OAAO;AAChE,WAAO,SAAS,KAAK;AA7KE;AAgLzB,mBAAiB,SAAS,+BAA+B,OAAO;AAC9D,WAAO,SAAS,KAAK;AAjLE;AAoLzB,oBAAkB,SAAS,kCAAkC;AAC3D,aAAS,SAAS,KAAK,iBAAiB;AACtC,WAAK,aAAa,QAAQ;AAF+B;AApLpC;AA0LzB,gBAAc,SAAS,4BAA4B,OAAO;AACxD,QAAI,MAAM,KAAK,gBAAgB,OAAO;AACtC,WAAO,KAAK,gBAAgB;AAC5B,QAAI;AA7LmB;AAAA;AAkM3B,SAAS,iBAAiB,SAAS;AACjC,OAAK,WAAW;AAChB,MAAI,SAAS,QAAQ;AACrB,OAAK,eAAe,eAAe,OAAO;AACxC,iBAAa,OAAO;AACpB,qBAAiB,OAAO;AAFqB,GAA/B;AAIhB,OAAK,kBAAkB,OAAO;AAC9B,OAAK,qBAAqB;AAC1B,OAAK,uBAAuB;AAxR9B;AA2RA,iBAAiB;AACf,+BACI,SAAS,4CAA4C,QAAQ;AAC/D,QAAI,IAAI,KAAK,qBAAqB,QAAQ;AAC1C,QAAI,KAAK,GAAG;AACV,WAAK,qBAAqB,OAAO,GAAG;AAHyB;AAFtC;AAS3B,iBAAe,SAAS,iCAAiC;AACvD,sBAAO,CAAC,KAAK;AACb,SAAK,qBACH,IAAI,kCAAkC,KAAK,UAAU,KAAK;AAC5D,WAAO,KAAK;AAba;AAgB3B,kBAAgB,SAAS,gCAAgC,OAAO,KAAK;AACnE,QAAI,SAAS,IAAI,mCAAmC,KAAK,UACL,OAAO;AAC3D,WAAO,WAAW,KAAK,4BAA4B,KAAK;AACxD,SAAK,qBAAqB,KAAK;AAC/B,WAAO;AArBkB;AAwB3B,qBAAmB,SAAS,mCAAmC,QAAQ;AACrE,QAAI,KAAK,oBAAoB;AAC3B,WAAK,mBAAmB,OAAO;AAFoC;AAIrE,QAAI,UAAU,KAAK,qBAAqB,MAAM;AAC9C,YAAQ,QAAQ,UAAU,QAAQ;AAChC,aAAO,OAAO;AADhB;AA7ByB;AAAA;AAoC7B,SAAS,kCAAkC,SAAS,SAAS;AAC3D,OAAK,WAAW;AAEhB,MAAI,SAAS,QAAQ;AACrB,MAAI;AACF,uBAAmB,KAAK,mBAAmB,KAAK;AAChD,uBAAmB,OAAO,gBAAgB,OACvB,KAAK,mBAAmB,KAAK;AAChD,YAAQ,KAAK,QAAQ,KAAK;AAC1B,aAAS,KAAK,SAAS,KAAK;AAC5B,gBAAY,KAAK,YAAY,KAAK;AANzB;AAQX,OAAK,OAAO,OAAO;AACnB,OAAK,iBAAiB,QAAQ,YAAY;AAC1C,OAAK,6BAA6B;AAClC,OAAK,gBAAgB,QAAQ,gBAAgB;AAC7C,OAAK,iBAAiB,OAAO;AAC7B,OAAK,kBAAkB,OAAO;AAC9B,MAAI,CAAC,KAAK,mBAAmB,CAAC,KAAK,eAAe;AAChD,SAAK,gBAAgB;AAnBoC;AAsB3D,OAAK,wBAAwB;AAC7B,OAAK,oBAAoB;AAEzB,OAAK,gBAAgB;AACrB,OAAK,YAAY;AACjB,OAAK,QAAQ;AACb,OAAK,eAAe;AAEpB,OAAK,aAAa;AA7VpB;AAgWA,kCAAkC;AAChC,qCAAmC,SAC/B,qEAAqE;AAEvE,QAAI,KAAK,eAAe;AACtB,aAAO;AAH8D;AAMvE,QAAI,iBAAiB,KAAK;AAC1B,QAAI,CAAC,eAAe,QAAQ;AAC1B,aAAO;AAR8D;AAUvE,QAAI,mBAAmB,KAAK;AAC5B,QAAI,iBAAiB,eAAe,cAAc;AAClD,QAAI,eAAe,kBAAkB,qBAAqB,SAAS;AACjE,aAAO;AAb8D;AAgBvE,QAAI,kBACF,eAAe,kBAAkB,uBAAuB;AAC1D,QAAI,oBAAoB,YAAY;AAClC,aAAO;AAnB8D;AAsBvE,QAAI,SAAS,eAAe,kBAAkB;AAC9C,aAAS,SAAS,QAAQ;AAC1B,QAAI,CAAC,iBAAM,SAAS;AAClB,aAAO;AAzB8D;AA4BvE,SAAK,iBAAiB;AAEtB,QAAI,UAAU,IAAI,KAAK,iBAAiB;AAItC,aAAO;AAlC8D;AAqCvE,WAAO;AAvCmC;AA0C5C,sBACI,SAAS,sDAAsD;AAEjE,QAAI,KAAK,qCAAqC;AAC5C,WAAK,oBAAoB;AAHsC;AAMjE,QAAI,iBAAiB,KAAK;AAC1B,QAAI,mBAAmB,KAAK;AAC5B,QAAI,eAAe,mBAAmB,mBAAmB;AAGvD,WAAK,wBAAwB;AAH/B,WAIO,IAAI,KAAK,mBAAmB;AAMjC,qBAAe,aAAa;AAlBmC;AAqBjE,SAAK,2BAA2B;AAhEU;AAmE5C,sBACI,SAAS,oDAAoD,OAAO;AACtE,QAAI,KAAK,UAAU,SAAS,GAAG;AAC7B,UAAI,oBAAoB,KAAK,UAAU;AACvC,wBAAkB;AAAU,eAAO;AAAO,cAAM;AAAtB;AAF5B,WAGO;AACL,WAAK,cAAc,KAAK;AAL4C;AApE5B;AA6E5C,WAAS,SAAS,yCAAyC,MAAM;AAC/D,QAAI,MAAM;AACR,WAAK,mBAAmB,KAAK;AAFgC;AAI/D,SAAK,QAAQ;AACb,QAAI,KAAK,cAAc,SAAS,GAAG;AACjC;AAN6D;AAQ/D,SAAK,UAAU,QAAQ,UAAU,mBAAmB;AAClD,wBAAkB;AAAU,eAAO;AAAW,cAAM;AAA1B;AAD5B;AAGA,SAAK,YAAY;AAxFyB;AA2F5C,YAAU,SAAS,0CAA0C,QAAQ;AACnE,QAAI,MAAM,KAAK;AACf,QAAI;AACJ,QAAI,WAAW,OAAO,WAAW,KAAK,SAAS,KAAK,MAAM;AACxD,kBAAgB,8BAAoB,kBAAkB,MAAM;AAD9D,WAEO;AACL,kBAAgB,sCACd,iCAAiC,SACjC,6BAA6B,MAAM,MAAM;AARsB;AAUnE,SAAK,eAAe;AACpB,SAAK,2BAA2B,OAAO;AACvC,SAAK,UAAU,QAAQ,UAAU,mBAAmB;AAClD,wBAAkB,OAAO;AAD3B;AAGA,SAAK,YAAY;AACjB,SAAK,gBAAgB;AA3GqB;AA8G5C,eAAa,SAAS,6CAA6C,MAAM;AACvE,QAAI,KAAK,YAAY;AACnB,WAAK;AACH,gBAAQ,KAAK;AACb,eAAO,KAAK,mBAAmB,KAAK,QAAQ,KAAK;AAFnC;AAFqD;AA9G7B;AAuH5C,MAAI,mBAAmB;AACrB,WAAO,KAAK;AAxH8B;AA2H5C,MAAI,uBAAuB;AACzB,WAAO,KAAK;AA5H8B;AA+H5C,MAAI,gBAAgB;AAClB,WAAO,KAAK;AAhI8B;AAmI5C,MAAI,eAAe;AACjB,WAAO,KAAK,2BAA2B;AApIG;AAuI5C,QAAM,SAAS,yCAAyC;AACtD,QAAI,KAAK,cAAc;AACrB,aAAO,QAAQ,OAAO,KAAK;AAFyB;AAItD,QAAI,KAAK,cAAc,SAAS,GAAG;AACjC,UAAI,QAAQ,KAAK,cAAc;AAC/B,qBAAe;AAAU,eAAO;AAAO,cAAM;AAAtB,OAAhB;AAN6C;AAQtD,QAAI,KAAK,OAAO;AACd,qBAAe;AAAU,eAAO;AAAW,cAAM;AAA1B,OAAhB;AAT6C;AAWtD,QAAI,oBAAoB;AACxB,SAAK,UAAU,KAAK;AACpB,WAAO,kBAAkB;AApJiB;AAuJ5C,UAAQ,SAAS,yCAAyC,QAAQ;AAChE,SAAK,QAAQ;AACb,SAAK,2BAA2B,OAAO;AACvC,SAAK,UAAU,QAAQ,UAAU,mBAAmB;AAClD,wBAAkB;AAAU,eAAO;AAAW,cAAM;AAA1B;AAD5B;AAGA,SAAK,YAAY;AACjB,QAAI,KAAK,SAAS,iBAAiB,KAAK,iBAAiB;AACvD,WAAK,SAAS,aAAa,KAAK;AAR8B;AAUhE,SAAK,qBAAqB;AAjKgB;AAAA;AAsK9C,SAAS,mCAAmC,SAAS,OAAO,KAAK;AAC/D,OAAK,WAAW;AAChB,MAAI;AACF,YAAQ,KAAK,QAAQ,KAAK;AAC1B,gBAAY,KAAK,YAAY,KAAK;AAFzB;AAIX,OAAK,aAAa,QAAQ,aAAa,OAAO,KAAK;AACnD,OAAK,YAAY;AACjB,OAAK,eAAe;AACpB,OAAK,QAAQ;AAEb,OAAK,aAAa;AAClB,OAAK,WAAW;AAlhBlB;AAqhBA,mCAAmC;AACjC,UAAQ,SAAS,2CAA2C;AAC1D,QAAI,KAAK,UAAU;AACjB,WAAK,SAAS;AAF0C;AADf;AAO7C,WAAS,SAAS,0CAA0C,MAAM;AAChE,QAAI,QAAQ,KAAK;AACjB,QAAI,KAAK,UAAU,SAAS,GAAG;AAC7B,UAAI,oBAAoB,KAAK,UAAU;AACvC,wBAAkB;AAAU,eAAO;AAAO,cAAM;AAAtB;AAF5B,WAGO;AACL,WAAK,eAAe;AAN0C;AAQhE,SAAK,QAAQ;AACb,SAAK,UAAU,QAAQ,UAAU,mBAAmB;AAClD,wBAAkB;AAAU,eAAO;AAAW,cAAM;AAA1B;AAD5B;AAGA,SAAK,YAAY;AACjB,SAAK;AApBsC;AAuB7C,eAAa,SAAS,8CAA8C,KAAK;AACvE,QAAI,CAAC,KAAK,wBAAwB,KAAK,YAAY;AACjD,WAAK,WAAW,EACd,QAAQ,IAAI;AAHuD;AAvB5B;AA+B7C,MAAI,uBAAuB;AACzB,WAAO;AAhCoC;AAmC7C,QAAM,SAAS,0CAA0C;AACvD,QAAI,KAAK,iBAAiB,MAAM;AAC9B,UAAI,QAAQ,KAAK;AACjB,WAAK,eAAe;AACpB,qBAAe;AAAU,eAAO;AAAO,cAAM;AAAtB,OAAhB;AAJ8C;AAMvD,QAAI,KAAK,OAAO;AACd,qBAAe;AAAU,eAAO;AAAW,cAAM;AAA1B,OAAhB;AAP8C;AASvD,QAAI,oBAAoB;AACxB,SAAK,UAAU,KAAK;AACpB,WAAO,kBAAkB;AA9CkB;AAiD7C,UAAQ,SAAS,0CAA0C,QAAQ;AACjE,SAAK,QAAQ;AACb,SAAK,UAAU,QAAQ,UAAU,mBAAmB;AAClD,wBAAkB;AAAU,eAAO;AAAW,cAAM;AAA1B;AAD5B;AAGA,SAAK,YAAY;AACjB,QAAI,KAAK,SAAS,iBAAiB,KAAK,aAAa;AACnD,WAAK,SAAS,aAAa,KAAK;AAP+B;AASjE,SAAK;AA1DsC;AAAA;AA8D/C,mCAEA;QACE;QACA,gC;;;;;;;;;;;AC9kBD,WAAS,GAAG,GAAG;AAAE,WAAQ,KAAK;AAAG,MAAE,KAAK,EAAE;;AAA1C,GAAgD,mBAA4B,SAAS;AAE5E,MAAI,mBAAmB;AAGvB,WAAS,oBAAoB,UAAU;AAGrC,QAAG,iBAAiB,WAClB,OAAO,iBAAiB,UAAU;AAGpC,QAAI,SAAS,iBAAiB;AAC5B,SAAG;AACH,SAAG;AACH,eAAS;AAH+B;AAO1C,YAAQ,UAAU,KAAK,OAAO,SAAS,QAAQ,OAAO,SAAS;AAG/D,WAAO,IAAI;AAGX,WAAO,OAAO;AAzB4D;AA8B5E,sBAAoB,IAAI;AAGxB,sBAAoB,IAAI;AAGxB,sBAAoB,IAAI,UAAS,OAAO;AAAE,WAAO;AAAjD;AAGA,sBAAoB,IAAI,UAAS,SAAS,MAAM,QAAQ;AACtD,QAAG,CAAC,oBAAoB,EAAE,SAAS,OAAO;AACxC,aAAO,eAAe,SAAS;AAC7B,sBAAc;AACd,oBAAY;AACZ,aAAK;AAH8B;AAFe;AAAxD;AAWA,sBAAoB,IAAI,UAAS,QAAQ;AACvC,QAAI,mBAAmB,OAAO,aAC5B,SAAS,aAAa;AAAE,aAAO,OAAO;AAD3B,QAEX,SAAS,mBAAmB;AAAE,aAAO;AAFvC;AAGA,wBAAoB,EAAE,QAAQ,KAAK;AACnC,WAAO;AALT;AASA,sBAAoB,IAAI,UAAS,QAAQ,UAAU;AAAE,WAAO,OAAO,UAAU,eAAe,KAAK,QAAQ;AAAzG;AAGA,sBAAoB,IAAI;AAGxB,SAAO,oBAAoB,oBAAoB,IAAI;AAjEM,CAAC,EAsE7D,UAAS,QAAQ,SAAS,qBAAqB;AAEtD;;AAGA,MAAI,iBAAiB,WAAW,cAAc,SAAO,OAAO,cAAa,WAAW,UAAU,KAAK;AAAS,kBAAO;AAArG,MAA8G,UAAU,KAAK;AAAE,WAAO,OAAO,OAAO,WAAW,cAAc,IAAI,gBAAgB,UAAU,QAAQ,OAAO,YAAuB,kBAAO;AAAtQ;AAEA,MAAI,WAAW,oBAAoB;MAC/B,SAAS,SAAS;AAEtB,WAAS,cAAc,UAAU;AAC/B,WAAO,OAAO,aAAa,YAAa,QAAO,aAAa,cAAc,cAAc,QAAQ,eAAe;AAX3D;AActD,UAAQ,eAAe,UAAU,GAAG;AAClC,WAAQ,QAAO,MAAM,cAAc,cAAc,QAAQ,QAAQ,YAAY,MAAM,QAAQ,OAAO,MAAM;AAD1G;AAIA,UAAQ,qBAAqB,UAAU,GAAG,GAAG,GAAG;AAC9C,WAAO,QAAQ,aAAa;AAC5B,WAAO,eAAe,GAAG;AAAK,aAAO;AAAG,gBAAU;AAAM,kBAAY;AAAM,oBAAc;AAA5D;AAF9B;AAKA,UAAQ,sBAAsB,UAAU,UAAU;AAGhD,WAAO,SAAS;AAHlB;AAMA,UAAQ,kBAAkB,UAAU,MAAM,YAAY,KAAK,WAAW,GAAG;AACvE,QAAI,WAAW,MAAM,IAAI,IAAI,WAAW,KAAK,WAAW,IAAI;AAD9D;AAIA,UAAQ,yBAAyB,UAAU,OAAO,MAAM;AACtD,WAAO,OAAO,SAAS;AACvB,QAAI,MAAM;AACV,WAAO,eAAe,KAAK;AAAW,aAAO;AAAO,kBAAY;AAAM,gBAAU;AAAM,oBAAc;AAAhE;AACpC,WAAO,eAAe,KAAK;AAAU,aAAO;AAAM,kBAAY;AAAM,gBAAU;AAAM,oBAAc;AAA/D;AACnC,WAAO;AALT;AAQA,UAAQ,4BAA4B,UAAU,GAAG;AAC/C,QAAI,OAAO,MAAM,IAAI;AACnB,aAAO;AAFsC;AAI/C,QAAI,MAAM,UAAU;AAClB,aAAO;AALsC;AAO/C,QAAI,IAAI,GAAG;AACT,aAAO;AARsC;AAW/C,WAAO;AAXT;AAcA,WAAS,KAAK,GAAG,GAAG,MAAM;AACxB,QAAI,OAAO,MAAM,YAAY;AAC3B,YAAM,IAAI,UAAU;AAFE;AAKxB,WAAO,SAAS,UAAU,MAAM,KAAK,GAAG,GAAG;AA5DS;AA+DtD,UAAQ,eAAe,UAAU,GAAG,GAAG,MAAM;AAC3C,WAAO,MAAM;AACb,WAAO,cAAc;AACrB,WAAO,MAAM,QAAQ;AAErB,QAAI,SAAS,EAAE;AACf,QAAI,WAAW,WAAW;AACxB,aAAO;AAPkC;AAU3C,WAAO,KAAK,QAAQ,GAAG;AAVzB;AAaA,UAAQ,sBAAsB,UAAU,GAAG,GAAG,MAAM;AAClD,WAAO,MAAM;AACb,WAAO,cAAc;AACrB,WAAO,MAAM,QAAQ;AACrB,QAAI;AACF,aAAO,QAAQ,QAAQ,QAAQ,aAAa,GAAG,GAAG;AADpD,MAEE,OAAO,cAAc;AACrB,aAAO,QAAQ,OAAO;AAP0B;AAApD;AAWA,UAAQ,iCAAiC,UAAU,GAAG,GAAG,MAAM,GAAG,OAAO;AACvE,WAAO,MAAM;AACb,WAAO,cAAc;AACrB,WAAO,MAAM,QAAQ;AACrB,WAAO,MAAM,QAAQ;AAErB,QAAI,SAAS,KAAK;AAClB,QAAI;AACF,eAAS,EAAE;AADb,MAEE,OAAO,SAAS;AAChB,aAAO,QAAQ,OAAO;AAV+C;AAavE,QAAI,WAAW,WAAW;AACxB,aAAO,EAAE,MAAM,MAAM;AAdgD;AAiBvE,QAAI;AACF,aAAO,QAAQ,QAAQ,KAAK,QAAQ,GAAG;AADzC,MAEE,OAAO,GAAG;AACV,aAAO,QAAQ,OAAO;AApB+C;AAAzE;AAyBA,UAAQ,sBAAsB,UAAU,GAAG;AACzC,WAAO,EAAE;AADX;AAIA,UAAQ,oCAAoC,UAAU,eAAe;AACnE,oBAAgB,OAAO;AACvB,QAAI,OAAO,MAAM,kBAAkB,gBAAgB,GAAG;AACpD,YAAM,IAAI,WAAW;AAH4C;AAMnE,WAAO;AANT;AASA,UAAQ,sCAAsC,UAAU,MAAM,eAAe;AAC3E,QAAI,SAAS,aAAa,OAAO,SAAS,YAAY;AACpD,YAAM,IAAI,UAAU;AAFqD;AAK3E,oBAAgB,QAAQ,kCAAkC;AAE1D;AAAS,YAAM;AAAM,qBAAe;AAA7B;AAPT;AA/HU,GA2IH,UAAS,QAAQ,SAAS,qBAAqB;AAEtD;;AAGA,WAAS,+BAA+B,GAAG;AAIzC,QAAI,KAAK,EAAE,gBAAgB,gBAAgB;AACzC,iBAAW,YAAY;AACrB,cAAM;AADR,SAEG;AAPoC;AALW;AAgBtD,WAAS,eAAe,SAAS;AAC/B,SAAK,OAAO;AACZ,SAAK,UAAU,WAAW;AAC1B,SAAK,QAAQ,IAAI,QAAQ;AAnB2B;AAqBtD,iBAAe,YAAY,OAAO,OAAO,MAAM;AAC/C,iBAAe,UAAU,cAAc;AAEvC,WAAS,OAAO,OAAO,SAAS;AAC9B,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,eAAe;AAFG;AAxBsB;AA8BtD,SAAO;AACL,oCAAgC;AAChC,oBAAgB;AAChB,YAAQ;AAHO;AAzKP,GAiLH,UAAS,QAAQ,SAAS,qBAAqB;AAEtD;;AAGA,MAAI,2BAA2B;AAAE,aAAS,iBAAiB,QAAQ,OAAO;AAAE,WAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AAAE,YAAI,aAAa,MAAM;AAAI,mBAAW,aAAa,WAAW,cAAc;AAAO,mBAAW,eAAe;AAAM,YAAI,WAAW,YAAY,WAAW,WAAW;AAAM,eAAO,eAAe,QAAQ,WAAW,KAAK;AAAnQ;AAA3C;AAA+T,WAAO,UAAU,aAAa,YAAY,aAAa;AAAE,UAAI,YAAY,iBAAiB,YAAY,WAAW;AAAa,UAAI,aAAa,iBAAiB,aAAa;AAAc,aAAO;AAAlM;AAA3U;AAEnB,WAAS,gBAAgB,UAAU,aAAa;AAAE,QAAM,sBAAoB,cAAc;AAAE,YAAM,IAAI,UAAU;AAAhE;AAPM;AAStD,MAAI,WAAW,oBAAoB;MAC/B,eAAe,SAAS;MACxB,sBAAsB,SAAS;MAC/B,sCAAsC,SAAS;MAC/C,eAAe,SAAS;AAE5B,MAAI,YAAY,oBAAoB;MAChC,SAAS,UAAU;MACnB,iCAAiC,UAAU;AAE/C,MAAI,YAAY,oBAAoB;MAChC,eAAe,UAAU;MACzB,uBAAuB,UAAU;MACjC,iBAAiB,UAAU;MAC3B,aAAa,UAAU;AAE3B,MAAI,6BAA6B;AAC/B,aAAS,iBAAiB;AACxB,UAAI,iBAAiB,UAAU,SAAS,KAAK,UAAU,OAAO,YAAY,UAAU,KAAK;AAEzF,UAAI,OAAO,UAAU,SAAS,KAAK,UAAU,OAAO,YAAY,UAAU,KAAK;UAC3E,OAAO,KAAK;UACZ,qBAAqB,KAAK;UAC1B,gBAAgB,uBAAuB,YAAY,IAAI;AAE3D,sBAAgB,MAAM;AAEtB,WAAK,SAAS;AAId,WAAK,eAAe;AAEpB,WAAK,UAAU;AAIf,WAAK,4BAA4B;AAIjC,WAAK,iBAAiB;AAItB,WAAK,wBAAwB;AAI7B,WAAK,gBAAgB;AAIrB,WAAK,wBAAwB;AAG7B,WAAK,uBAAuB;AAG5B,WAAK,gBAAgB;AAErB,UAAI,OAAO,eAAe;AAE1B,UAAI,SAAS,WAAW;AACtB,cAAM,IAAI,WAAW;AA/CC;AAkDxB,WAAK,4BAA4B,IAAI,gCAAgC,MAAM,gBAAgB,MAAM;AACjG,WAAK,0BAA0B;AApDF;AAuD/B,iBAAa;AACX,WAAK;AACL,aAAO,SAAS,MAAM,QAAQ;AAC5B,YAAI,iBAAiB,UAAU,OAAO;AACpC,iBAAO,QAAQ,OAAO,0BAA0B;AAFtB;AAK5B,YAAI,uBAAuB,UAAU,MAAM;AACzC,iBAAO,QAAQ,OAAO,IAAI,UAAU;AANV;AAS5B,eAAO,oBAAoB,MAAM;AAXP;AAAA,KAAD;AAc3B,WAAK;AACL,aAAO,SAAS,YAAY;AAC1B,YAAI,iBAAiB,UAAU,OAAO;AACpC,gBAAM,0BAA0B;AAFR;AAK1B,eAAO,mCAAmC;AAP3C;AAAA;AAUD,WAAK;AACL,WAAK,SAAS,MAAM;AAClB,YAAI,iBAAiB,UAAU,OAAO;AACpC,gBAAM,0BAA0B;AAFhB;AAKlB,eAAO,uBAAuB;AAP/B;AAAA;AAWH,WAAO;AAxFY;AA2FrB,SAAO;AACL,wCAAoC;AACpC,sBAAkB;AAClB,4BAAwB;AACxB,oBAAgB;AAChB,yBAAqB;AACrB,0CAAsC;AACtC,0DAAsD;AACtD,wCAAoC;AACpC,sCAAkC;AAClC,yCAAqC;AAVtB;AAejB,WAAS,mCAAmC,QAAQ;AAClD,WAAO,IAAI,4BAA4B;AApIa;AAuItD,WAAS,iBAAiB,GAAG;AAC3B,QAAI,CAAC,aAAa,IAAI;AACpB,aAAO;AAFkB;AAK3B,QAAI,CAAC,OAAO,UAAU,eAAe,KAAK,GAAG,8BAA8B;AACzE,aAAO;AANkB;AAS3B,WAAO;AAhJ6C;AAmJtD,WAAS,uBAAuB,QAAQ;AACtC,WAAO,iBAAiB,YAAY,MAAM;AAE1C,QAAI,OAAO,YAAY,WAAW;AAChC,aAAO;AAJ6B;AAOtC,WAAO;AA1J6C;AA6JtD,WAAS,oBAAoB,QAAQ,QAAQ;AAC3C,QAAI,QAAQ,OAAO;AACnB,QAAI,UAAU,UAAU;AACtB,aAAO,QAAQ,QAAQ;AAHkB;AAK3C,QAAI,UAAU,WAAW;AACvB,aAAO,QAAQ,OAAO,OAAO;AANY;AAQ3C,QAAI,QAAQ,IAAI,UAAU;AAC1B,QAAI,OAAO,yBAAyB,WAAW;AAC7C,aAAO,QAAQ,OAAO;AAVmB;AAa3C,WAAO,UAAU,cAAc,UAAU,YAAY;AAErD,QAAI,qBAAqB;AACzB,QAAI,UAAU,YAAY;AACxB,2BAAqB;AAErB,eAAS;AAnBgC;AAsB3C,QAAI,cAAc,QAAQ,UAAU,SAAS,QAAQ;AACnD,aAAO;AACL,kBAAU;AACV,iBAAS;AACT,iBAAS;AACT,6BAAqB;AAJO;AADlB;AASd,QAAI,uBAAuB,OAAO;AAChC,kCAA4B,QAAQ;AAhCK;AAmC3C,WAAO;AAhM6C;AAqMtD,WAAS,8BAA8B,QAAQ;AAC7C,WAAO,uBAAuB,YAAY;AAC1C,WAAO,OAAO,WAAW;AAEzB,QAAI,cAAc,QAAQ,UAAU,SAAS,QAAQ;AACnD,UAAI;AACF,kBAAU;AACV,iBAAS;AAFQ;AAKnB,aAAO,eAAe,KAAK;AANf;AASd,WAAO;AAlN6C;AAqNtD,WAAS,gCAAgC,QAAQ,OAAO;AACtD,QAAI,QAAQ,OAAO;AAEnB,QAAI,UAAU,YAAY;AACxB,kCAA4B,QAAQ;AACpC;AALoD;AAQtD,WAAO,UAAU;AACjB,iCAA6B;AA9NuB;AAiOtD,WAAS,4BAA4B,QAAQ,QAAQ;AACnD,WAAO,OAAO,iBAAiB,WAAW;AAC1C,WAAO,OAAO,WAAW,YAAY;AAErC,QAAI,aAAa,OAAO;AACxB,WAAO,eAAe,WAAW;AAEjC,WAAO,SAAS;AAChB,WAAO,eAAe;AACtB,QAAI,SAAS,OAAO;AACpB,QAAI,WAAW,WAAW;AACxB,4DAAsD,QAAQ;AAXb;AAcnD,QAAI,yCAAyC,YAAY,SAAS,WAAW,aAAa,MAAM;AAC9F,mCAA6B;AAfoB;AAjOC;AAoPtD,WAAS,6BAA6B,QAAQ;AAC5C,WAAO,OAAO,WAAW,YAAY;AACrC,WAAO,yCAAyC,YAAY,OAAO;AACnE,WAAO,SAAS;AAChB,WAAO,0BAA0B;AAEjC,QAAI,cAAc,OAAO;AACzB,SAAK,IAAI,IAAI,GAAG,IAAI,OAAO,eAAe,QAAQ,KAAK;AACrD,UAAI,eAAe,OAAO,eAAe;AACzC,mBAAa,QAAQ;AATqB;AAW5C,WAAO,iBAAiB;AAExB,QAAI,OAAO,yBAAyB,WAAW;AAC7C,wDAAkD;AAClD;AAf0C;AAkB5C,QAAI,eAAe,OAAO;AAC1B,WAAO,uBAAuB;AAE9B,QAAI,aAAa,wBAAwB,MAAM;AAC7C,mBAAa,QAAQ;AACrB,wDAAkD;AAClD;AAxB0C;AA2B5C,QAAI,UAAU,OAAO,0BAA0B,aAAa,aAAa;AACzE,YAAQ,KAAK,YAAY;AACvB,mBAAa;AACb,wDAAkD;AAFpD,OAGG,UAAU,QAAQ;AACnB,mBAAa,QAAQ;AACrB,wDAAkD;AALpD;AAhRoD;AAyRtD,WAAS,kCAAkC,QAAQ;AACjD,WAAO,OAAO,0BAA0B;AACxC,WAAO,sBAAsB,SAAS;AACtC,WAAO,wBAAwB;AA5RqB;AA+RtD,WAAS,2CAA2C,QAAQ,OAAO;AACjE,WAAO,OAAO,0BAA0B;AACxC,WAAO,sBAAsB,QAAQ;AACrC,WAAO,wBAAwB;AAE/B,WAAO,OAAO,WAAW,cAAc,OAAO,WAAW;AAEzD,oCAAgC,QAAQ;AAtSY;AAyStD,WAAS,kCAAkC,QAAQ;AACjD,WAAO,OAAO,0BAA0B;AACxC,WAAO,sBAAsB,SAAS;AACtC,WAAO,wBAAwB;AAE/B,QAAI,QAAQ,OAAO;AAEnB,WAAO,UAAU,cAAc,UAAU;AAEzC,QAAI,UAAU,YAAY;AAExB,aAAO,eAAe;AACtB,UAAI,OAAO,yBAAyB,WAAW;AAC7C,eAAO,qBAAqB;AAC5B,eAAO,uBAAuB;AALR;AATuB;AAkBjD,WAAO,SAAS;AAEhB,QAAI,SAAS,OAAO;AACpB,QAAI,WAAW,WAAW;AACxB,wCAAkC;AAtBa;AAyBjD,WAAO,OAAO,yBAAyB,WAAW;AAClD,WAAO,OAAO,iBAAiB,WAAW;AAnUU;AAsUtD,WAAS,2CAA2C,QAAQ,OAAO;AACjE,WAAO,OAAO,0BAA0B;AACxC,WAAO,sBAAsB,QAAQ;AACrC,WAAO,wBAAwB;AAE/B,WAAO,OAAO,WAAW,cAAc,OAAO,WAAW;AAGzD,QAAI,OAAO,yBAAyB,WAAW;AAC7C,aAAO,qBAAqB,QAAQ;AACpC,aAAO,uBAAuB;AAViC;AAYjE,oCAAgC,QAAQ;AAlVY;AAsVtD,WAAS,oCAAoC,QAAQ;AACnD,QAAI,OAAO,kBAAkB,aAAa,OAAO,0BAA0B,WAAW;AACpF,aAAO;AAF0C;AAKnD,WAAO;AA3V6C;AA8VtD,WAAS,yCAAyC,QAAQ;AACxD,QAAI,OAAO,0BAA0B,aAAa,OAAO,0BAA0B,WAAW;AAC5F,aAAO;AAF+C;AAKxD,WAAO;AAnW6C;AAsWtD,WAAS,uCAAuC,QAAQ;AACtD,WAAO,OAAO,0BAA0B;AACxC,WAAO,OAAO,kBAAkB;AAChC,WAAO,wBAAwB,OAAO;AACtC,WAAO,gBAAgB;AA1W6B;AA6WtD,WAAS,4CAA4C,QAAQ;AAC3D,WAAO,OAAO,0BAA0B,WAAW;AACnD,WAAO,OAAO,eAAe,WAAW,GAAG;AAC3C,WAAO,wBAAwB,OAAO,eAAe;AAhXD;AAmXtD,WAAS,kDAAkD,QAAQ;AACjE,WAAO,OAAO,WAAW,WAAW;AACpC,QAAI,OAAO,kBAAkB,WAAW;AACtC,aAAO,OAAO,0BAA0B;AAExC,aAAO,cAAc,QAAQ,OAAO;AACpC,aAAO,gBAAgB;AANwC;AAQjE,QAAI,SAAS,OAAO;AACpB,QAAI,WAAW,WAAW;AACxB,uCAAiC,QAAQ,OAAO;AAChD,aAAO,eAAe,MAAM,YAAY,CAAxC;AAX+D;AAnXb;AAkYtD,WAAS,iCAAiC,QAAQ,cAAc;AAC9D,WAAO,OAAO,WAAW;AACzB,WAAO,oCAAoC,YAAY;AAEvD,QAAI,SAAS,OAAO;AACpB,QAAI,WAAW,aAAa,iBAAiB,OAAO,eAAe;AACjE,UAAI,iBAAiB,MAAM;AACzB,uCAA+B;AADjC,aAEO;AACL,eAAO,iBAAiB;AAExB,yCAAiC;AAN8B;AALL;AAe9D,WAAO,gBAAgB;AAjZ6B;AAoZtD,MAAI,0CAA0C;AAC5C,aAAS,4BAA4B,QAAQ;AAC3C,sBAAgB,MAAM;AAEtB,UAAI,iBAAiB,YAAY,OAAO;AACtC,cAAM,IAAI,UAAU;AAJqB;AAM3C,UAAI,uBAAuB,YAAY,MAAM;AAC3C,cAAM,IAAI,UAAU;AAPqB;AAU3C,WAAK,uBAAuB;AAC5B,aAAO,UAAU;AAEjB,UAAI,QAAQ,OAAO;AAEnB,UAAI,UAAU,YAAY;AACxB,YAAI,oCAAoC,YAAY,SAAS,OAAO,kBAAkB,MAAM;AAC1F,8CAAoC;AADtC,eAEO;AACL,wDAA8C;AAJxB;AAOxB,6CAAqC;AAPvC,iBAQW,UAAU,YAAY;AAC/B,sDAA8C,MAAM,OAAO;AAC3D,aAAK,cAAc,MAAM,YAAY,CAArC;AACA,6CAAqC;AAHhC,iBAII,UAAU,UAAU;AAC7B,sDAA8C;AAC9C,uDAA+C;AAF1C,aAGA;AACL,eAAO,UAAU,WAAW;AAE5B,YAAI,cAAc,OAAO;AACzB,sDAA8C,MAAM;AACpD,aAAK,cAAc,MAAM,YAAY,CAArC;AACA,uDAA+C,MAAM;AACrD,aAAK,eAAe,MAAM,YAAY,CAAtC;AArCyC;AADD;AA0C5C,iBAAa;AACX,WAAK;AACL,aAAO,SAAS,MAAM,QAAQ;AAC5B,YAAI,8BAA8B,UAAU,OAAO;AACjD,iBAAO,QAAQ,OAAO,iCAAiC;AAF7B;AAK5B,YAAI,KAAK,yBAAyB,WAAW;AAC3C,iBAAO,QAAQ,OAAO,2BAA2B;AANvB;AAS5B,eAAO,iCAAiC,MAAM;AAXP;AAAA,KAAD;AAcxC,WAAK;AACL,aAAO,SAAS,QAAQ;AACtB,YAAI,8BAA8B,UAAU,OAAO;AACjD,iBAAO,QAAQ,OAAO,iCAAiC;AAFnC;AAKtB,YAAI,SAAS,KAAK;AAElB,YAAI,WAAW,WAAW;AACxB,iBAAO,QAAQ,OAAO,2BAA2B;AAR7B;AAWtB,YAAI,oCAAoC,YAAY,MAAM;AACxD,iBAAO,QAAQ,OAAO,IAAI,UAAU;AAZhB;AAetB,eAAO,iCAAiC;AAjBzC;AAAA;AAoBD,WAAK;AACL,aAAO,SAAS,cAAc;AAC5B,YAAI,8BAA8B,UAAU,OAAO;AACjD,gBAAM,iCAAiC;AAFb;AAK5B,YAAI,SAAS,KAAK;AAElB,YAAI,WAAW,WAAW;AACxB;AAR0B;AAW5B,eAAO,OAAO,YAAY;AAE1B,2CAAmC;AAfpC;AAAA;AAkBD,WAAK;AACL,aAAO,SAAS,MAAM,OAAO;AAC3B,YAAI,8BAA8B,UAAU,OAAO;AACjD,iBAAO,QAAQ,OAAO,iCAAiC;AAF9B;AAK3B,YAAI,KAAK,yBAAyB,WAAW;AAC3C,iBAAO,QAAQ,OAAO,2BAA2B;AANxB;AAS3B,eAAO,iCAAiC,MAAM;AAX/C;AAAA;AAcD,WAAK;AACL,WAAK,SAAS,MAAM;AAClB,YAAI,8BAA8B,UAAU,OAAO;AACjD,iBAAO,QAAQ,OAAO,iCAAiC;AAFvC;AAKlB,eAAO,KAAK;AAPb;AAAA;AAUD,WAAK;AACL,WAAK,SAAS,MAAM;AAClB,YAAI,8BAA8B,UAAU,OAAO;AACjD,gBAAM,iCAAiC;AAFvB;AAKlB,YAAI,KAAK,yBAAyB,WAAW;AAC3C,gBAAM,2BAA2B;AANjB;AASlB,eAAO,0CAA0C;AAXlD;AAAA;AAcD,WAAK;AACL,WAAK,SAAS,MAAM;AAClB,YAAI,8BAA8B,UAAU,OAAO;AACjD,iBAAO,QAAQ,OAAO,iCAAiC;AAFvC;AAKlB,eAAO,KAAK;AAPb;AAAA;AAWH,WAAO;AAzIyB;AA8IlC,WAAS,8BAA8B,GAAG;AACxC,QAAI,CAAC,aAAa,IAAI;AACpB,aAAO;AAF+B;AAKxC,QAAI,CAAC,OAAO,UAAU,eAAe,KAAK,GAAG,yBAAyB;AACpE,aAAO;AAN+B;AASxC,WAAO;AA3iB6C;AAgjBtD,WAAS,iCAAiC,QAAQ,QAAQ;AACxD,QAAI,SAAS,OAAO;AAEpB,WAAO,WAAW;AAElB,WAAO,oBAAoB,QAAQ;AArjBiB;AAwjBtD,WAAS,iCAAiC,QAAQ;AAChD,QAAI,SAAS,OAAO;AAEpB,WAAO,WAAW;AAElB,QAAI,QAAQ,OAAO;AACnB,QAAI,UAAU,YAAY,UAAU,WAAW;AAC7C,aAAO,QAAQ,OAAO,IAAI,UAAU,oBAAoB,QAAQ;AAPlB;AAUhD,WAAO,UAAU,cAAc,UAAU;AACzC,WAAO,oCAAoC,YAAY;AAEvD,QAAI,cAAc,QAAQ,UAAU,SAAS,QAAQ;AACnD,UAAI;AACF,kBAAU;AACV,iBAAS;AAFQ;AAKnB,aAAO,gBAAgB;AANX;AASd,QAAI,OAAO,kBAAkB,QAAQ,UAAU,YAAY;AACzD,uCAAiC;AAvBa;AA0BhD,yCAAqC,OAAO;AAE5C,WAAO;AAplB6C;AAulBtD,WAAS,qDAAqD,QAAQ;AACpE,QAAI,SAAS,OAAO;AAEpB,WAAO,WAAW;AAElB,QAAI,QAAQ,OAAO;AACnB,QAAI,oCAAoC,YAAY,QAAQ,UAAU,UAAU;AAC9E,aAAO,QAAQ;AAPmD;AAUpE,QAAI,UAAU,WAAW;AACvB,aAAO,QAAQ,OAAO,OAAO;AAXqC;AAcpE,WAAO,UAAU,cAAc,UAAU;AAEzC,WAAO,iCAAiC;AAvmBY;AA0mBtD,WAAS,uDAAuD,QAAQ,OAAO;AAC7E,QAAI,OAAO,wBAAwB,WAAW;AAC5C,uCAAiC,QAAQ;AAD3C,WAEO;AACL,gDAA0C,QAAQ;AAJyB;AAM7E,WAAO,eAAe,MAAM,YAAY,CAAxC;AAhnBoD;AAmnBtD,WAAS,sDAAsD,QAAQ,OAAO;AAC5E,QAAI,OAAO,uBAAuB,WAAW;AAC3C,sCAAgC,QAAQ;AAD1C,WAEO;AACL,+CAAyC,QAAQ;AAJyB;AAM5E,WAAO,cAAc,MAAM,YAAY,CAAvC;AAznBoD;AA4nBtD,WAAS,0CAA0C,QAAQ;AACzD,QAAI,SAAS,OAAO;AACpB,QAAI,QAAQ,OAAO;AAEnB,QAAI,UAAU,aAAa,UAAU,YAAY;AAC/C,aAAO;AALgD;AAQzD,QAAI,UAAU,UAAU;AACtB,aAAO;AATgD;AAYzD,WAAO,8CAA8C,OAAO;AAxoBR;AA2oBtD,WAAS,mCAAmC,QAAQ;AAClD,QAAI,SAAS,OAAO;AACpB,WAAO,WAAW;AAClB,WAAO,OAAO,YAAY;AAE1B,QAAI,gBAAgB,IAAI,UAAU;AAElC,0DAAsD,QAAQ;AAI9D,2DAAuD,QAAQ;AAE/D,WAAO,UAAU;AACjB,WAAO,uBAAuB;AAzpBsB;AA4pBtD,WAAS,iCAAiC,QAAQ,OAAO;AACvD,QAAI,SAAS,OAAO;AAEpB,WAAO,WAAW;AAElB,QAAI,aAAa,OAAO;AAExB,QAAI,YAAY,4CAA4C,YAAY;AAExE,QAAI,WAAW,OAAO,sBAAsB;AAC1C,aAAO,QAAQ,OAAO,2BAA2B;AAVI;AAavD,QAAI,QAAQ,OAAO;AACnB,QAAI,UAAU,WAAW;AACvB,aAAO,QAAQ,OAAO,OAAO;AAfwB;AAiBvD,QAAI,oCAAoC,YAAY,QAAQ,UAAU,UAAU;AAC9E,aAAO,QAAQ,OAAO,IAAI,UAAU;AAlBiB;AAoBvD,QAAI,UAAU,YAAY;AACxB,aAAO,QAAQ,OAAO,OAAO;AArBwB;AAwBvD,WAAO,UAAU;AAEjB,QAAI,UAAU,8BAA8B;AAE5C,yCAAqC,YAAY,OAAO;AAExD,WAAO;AA1rB6C;AA6rBtD,MAAI,8CAA8C;AAChD,aAAS,gCAAgC,QAAQ,gBAAgB,MAAM,eAAe;AACpF,sBAAgB,MAAM;AAEtB,UAAI,iBAAiB,YAAY,OAAO;AACtC,cAAM,IAAI,UAAU;AAJ8D;AAOpF,UAAI,OAAO,8BAA8B,WAAW;AAClD,cAAM,IAAI,UAAU;AAR8D;AAWpF,WAAK,4BAA4B;AAEjC,WAAK,kBAAkB;AAGvB,WAAK,SAAS;AACd,WAAK,kBAAkB;AACvB,iBAAW;AAEX,WAAK,WAAW;AAEhB,UAAI,qBAAqB,oCAAoC,MAAM;AACnE,WAAK,gBAAgB,mBAAmB;AACxC,WAAK,eAAe,mBAAmB;AAEvC,UAAI,eAAe,+CAA+C;AAClE,uCAAiC,QAAQ;AA5BK;AA+BhD,iBAAa;AACX,WAAK;AACL,aAAO,SAAS,MAAM,GAAG;AACvB,YAAI,kCAAkC,UAAU,OAAO;AACrD,gBAAM,IAAI,UAAU;AAFC;AAIvB,YAAI,QAAQ,KAAK,0BAA0B;AAC3C,YAAI,UAAU,YAAY;AAGxB;AARqB;AAWvB,6CAAqC,MAAM;AAbA;AAAA,KAAD;AAgB5C,WAAK;AACL,aAAO,SAAS,aAAa,QAAQ;AACnC,eAAO,oBAAoB,KAAK,iBAAiB,SAAS,CAAC;AAH5D;AAAA;AAMD,WAAK;AACL,aAAO,SAAS,eAAe;AAC7B,mBAAW;AAHZ;AAAA;AAMD,WAAK;AACL,aAAO,SAAS,eAAe;AAC7B,YAAI,QAAQ;AAEZ,YAAI,cAAc,aAAa,KAAK,iBAAiB,SAAS,CAAC;AAC/D,YAAI,SAAS,KAAK;AAElB,gBAAQ,QAAQ,aAAa,KAAK,YAAY;AAC5C,iBAAO,OAAO,WAAW,cAAc,OAAO,WAAW;AACzD,gBAAM,WAAW;AACjB,8DAAoD;AAHtD,WAIG,UAAU,GAAG;AACd,iBAAO,OAAO,WAAW,cAAc,OAAO,WAAW;AACzD,gBAAM,WAAW;AACjB,0CAAgC,QAAQ;AAP1C,WAQG,MAAM;AAhBV;AAAA;AAoBH,WAAO;AA5E6B;AAiFtC,WAAS,qCAAqC,YAAY;AACxD,yBAAqB,YAAY,SAAS;AAC1C,wDAAoD;AAhxBA;AAmxBtD,WAAS,4CAA4C,YAAY,OAAO;AACtE,QAAI,eAAe,WAAW;AAE9B,QAAI,iBAAiB,WAAW;AAC9B,aAAO;AAJ6D;AAOtE,QAAI;AACF,aAAO,aAAa;AADtB,MAEE,OAAO,YAAY;AACnB,mDAA6C,YAAY;AACzD,aAAO;AAX6D;AAnxBlB;AAkyBtD,WAAS,8CAA8C,YAAY;AACjE,WAAO,WAAW,eAAe,WAAW;AAnyBQ;AAsyBtD,WAAS,qCAAqC,YAAY,OAAO,WAAW;AAC1E,QAAI,cAAc,EAAE,OAAO;AAE3B,QAAI;AACF,2BAAqB,YAAY,aAAa;AADhD,MAEE,OAAO,UAAU;AACjB,mDAA6C,YAAY;AACzD;AAPwE;AAU1E,QAAI,SAAS,WAAW;AACxB,QAAI,oCAAoC,YAAY,SAAS,OAAO,WAAW,YAAY;AACzF,UAAI,eAAe,+CAA+C;AAClE,uCAAiC,QAAQ;AAb+B;AAgB1E,wDAAoD;AAtzBA;AA2zBtD,WAAS,kCAAkC,GAAG;AAC5C,QAAI,CAAC,aAAa,IAAI;AACpB,aAAO;AAFmC;AAK5C,QAAI,CAAC,OAAO,UAAU,eAAe,KAAK,GAAG,oBAAoB;AAC/D,aAAO;AANmC;AAS5C,WAAO;AAp0B6C;AAu0BtD,WAAS,oDAAoD,YAAY;AACvE,QAAI,SAAS,WAAW;AAExB,QAAI,WAAW,aAAa,OAAO;AACjC;AAJqE;AAOvE,QAAI,OAAO,0BAA0B,WAAW;AAC9C;AARqE;AAWvE,QAAI,QAAQ,OAAO;AACnB,QAAI,UAAU,YAAY,UAAU,WAAW;AAC7C;AAbqE;AAevE,QAAI,UAAU,YAAY;AACxB,mCAA6B;AAC7B;AAjBqE;AAoBvE,QAAI,WAAW,OAAO,WAAW,GAAG;AAClC;AArBqE;AAwBvE,QAAI,cAAc,eAAe;AACjC,QAAI,gBAAgB,SAAS;AAC3B,kDAA4C;AAD9C,WAEO;AACL,kDAA4C,YAAY,YAAY;AA5BC;AAv0BnB;AAu2BtD,WAAS,6CAA6C,YAAY,OAAO;AACvE,QAAI,WAAW,0BAA0B,WAAW,YAAY;AAC9D,2CAAqC,YAAY;AAFoB;AAv2BnB;AA62BtD,WAAS,4CAA4C,YAAY;AAC/D,QAAI,SAAS,WAAW;AAExB,2CAAuC;AAEvC,iBAAa;AACb,WAAO,WAAW,OAAO,WAAW,GAAG;AAEvC,QAAI,mBAAmB,oBAAoB,WAAW,iBAAiB,SAAS;AAChF,qBAAiB,KAAK,YAAY;AAChC,wCAAkC;AADpC,OAEG,UAAU,QAAQ;AACnB,iDAA2C,QAAQ;AAHrD,OAIG,MAAM;AA13B2C;AA63BtD,WAAS,4CAA4C,YAAY,OAAO;AACtE,QAAI,SAAS,WAAW;AAExB,gDAA4C;AAE5C,QAAI,mBAAmB,oBAAoB,WAAW,iBAAiB,SAAS,CAAC,OAAO;AACxF,qBAAiB,KAAK,YAAY;AAChC,wCAAkC;AAElC,UAAI,QAAQ,OAAO;AACnB,aAAO,UAAU,cAAc,UAAU;AAEzC,mBAAa;AAEb,UAAI,oCAAoC,YAAY,SAAS,UAAU,YAAY;AACjF,YAAI,eAAe,+CAA+C;AAClE,yCAAiC,QAAQ;AAVX;AAahC,0DAAoD;AAbtD,OAcG,UAAU,QAAQ;AACnB,iDAA2C,QAAQ;AAfrD,OAgBG,MAAM;AAn5B2C;AAs5BtD,WAAS,+CAA+C,YAAY;AAClE,QAAI,cAAc,8CAA8C;AAChE,WAAO,eAAe;AAx5B8B;AA65BtD,WAAS,qCAAqC,YAAY,OAAO;AAC/D,QAAI,SAAS,WAAW;AAExB,WAAO,OAAO,WAAW;AAEzB,gCAA4B,QAAQ;AAl6BgB;AAu6BtD,WAAS,0BAA0B,MAAM;AACvC,WAAO,IAAI,UAAU,8BAA8B,OAAO;AAx6BN;AA66BtD,WAAS,iCAAiC,MAAM;AAC9C,WAAO,IAAI,UAAU,2CAA2C,OAAO;AA96BnB;AAi7BtD,WAAS,2BAA2B,MAAM;AACxC,WAAO,IAAI,UAAU,YAAY,OAAO;AAl7BY;AAq7BtD,WAAS,qCAAqC,QAAQ;AACpD,WAAO,qBAAqB,QAAQ,UAAU,SAAS,QAAQ;AAC7D,aAAO,yBAAyB;AAChC,aAAO,wBAAwB;AAC/B,aAAO,sBAAsB;AAHP;AAt7B4B;AA67BtD,WAAS,+CAA+C,QAAQ,QAAQ;AACtE,WAAO,iBAAiB,QAAQ,OAAO;AACvC,WAAO,yBAAyB;AAChC,WAAO,wBAAwB;AAC/B,WAAO,sBAAsB;AAj8BuB;AAo8BtD,WAAS,+CAA+C,QAAQ;AAC9D,WAAO,iBAAiB,QAAQ,QAAQ;AACxC,WAAO,yBAAyB;AAChC,WAAO,wBAAwB;AAC/B,WAAO,sBAAsB;AAx8BuB;AA28BtD,WAAS,iCAAiC,QAAQ,QAAQ;AACxD,WAAO,OAAO,2BAA2B,WAAW;AACpD,WAAO,OAAO,0BAA0B,WAAW;AACnD,WAAO,OAAO,wBAAwB,WAAW;AAEjD,WAAO,sBAAsB;AAC7B,WAAO,yBAAyB;AAChC,WAAO,wBAAwB;AAC/B,WAAO,sBAAsB;AAn9BuB;AAs9BtD,WAAS,0CAA0C,QAAQ,QAAQ;AACjE,WAAO,OAAO,2BAA2B,WAAW;AACpD,WAAO,OAAO,0BAA0B,WAAW;AACnD,WAAO,OAAO,wBAAwB,WAAW;AAEjD,WAAO,iBAAiB,QAAQ,OAAO;AACvC,WAAO,sBAAsB;AA59BuB;AA+9BtD,WAAS,kCAAkC,QAAQ;AACjD,WAAO,OAAO,2BAA2B,WAAW;AACpD,WAAO,OAAO,0BAA0B,WAAW;AACnD,WAAO,OAAO,wBAAwB,WAAW;AAEjD,WAAO,uBAAuB;AAC9B,WAAO,yBAAyB;AAChC,WAAO,wBAAwB;AAC/B,WAAO,sBAAsB;AAv+BuB;AA0+BtD,WAAS,oCAAoC,QAAQ;AACnD,WAAO,oBAAoB,QAAQ,UAAU,SAAS,QAAQ;AAC5D,aAAO,wBAAwB;AAC/B,aAAO,uBAAuB;AAFT;AAIvB,WAAO,qBAAqB;AA/+BwB;AAk/BtD,WAAS,8CAA8C,QAAQ,QAAQ;AACrE,WAAO,gBAAgB,QAAQ,OAAO;AACtC,WAAO,wBAAwB;AAC/B,WAAO,uBAAuB;AAC9B,WAAO,qBAAqB;AAt/BwB;AAy/BtD,WAAS,8CAA8C,QAAQ;AAC7D,WAAO,gBAAgB,QAAQ,QAAQ;AACvC,WAAO,wBAAwB;AAC/B,WAAO,uBAAuB;AAC9B,WAAO,qBAAqB;AA7/BwB;AAggCtD,WAAS,gCAAgC,QAAQ,QAAQ;AACvD,WAAO,OAAO,0BAA0B,WAAW;AACnD,WAAO,OAAO,yBAAyB,WAAW;AAElD,WAAO,qBAAqB;AAC5B,WAAO,wBAAwB;AAC/B,WAAO,uBAAuB;AAC9B,WAAO,qBAAqB;AAvgCwB;AA0gCtD,WAAS,+BAA+B,QAAQ;AAC9C,WAAO,OAAO,0BAA0B,WAAW;AACnD,WAAO,OAAO,yBAAyB,WAAW;AAElD,WAAO,oBAAoB,QAAQ,UAAU,SAAS,QAAQ;AAC5D,aAAO,wBAAwB;AAC/B,aAAO,uBAAuB;AAFT;AAIvB,WAAO,qBAAqB;AAlhCwB;AAqhCtD,WAAS,yCAAyC,QAAQ,QAAQ;AAChE,WAAO,OAAO,0BAA0B,WAAW;AACnD,WAAO,OAAO,yBAAyB,WAAW;AAElD,WAAO,gBAAgB,QAAQ,OAAO;AACtC,WAAO,qBAAqB;AA1hCwB;AA6hCtD,WAAS,iCAAiC,QAAQ;AAChD,WAAO,OAAO,0BAA0B,WAAW;AACnD,WAAO,OAAO,yBAAyB,WAAW;AAElD,WAAO,sBAAsB;AAC7B,WAAO,wBAAwB;AAC/B,WAAO,uBAAuB;AAC9B,WAAO,qBAAqB;AApiCwB;AAjL5C,GA0tCH,UAAS,QAAQ,SAAS,qBAAqB;AAEtD;;AAGA,MAAI,WAAW,oBAAoB;MAC/B,4BAA4B,SAAS;AAEzC,MAAI,YAAY,oBAAoB;MAChC,SAAS,UAAU;AAEvB,UAAQ,eAAe,UAAU,WAAW;AAC1C,WAAO,YAAY,aAAa,qBAAqB,WAAW;AAChE,WAAO,UAAU,OAAO,SAAS,GAAG;AAEpC,QAAI,OAAO,UAAU,OAAO;AAC5B,cAAU,mBAAmB,KAAK;AAClC,QAAI,UAAU,kBAAkB,GAAG;AACjC,gBAAU,kBAAkB;AAPY;AAU1C,WAAO,KAAK;AAVd;AAaA,UAAQ,uBAAuB,UAAU,WAAW,OAAO,MAAM;AAC/D,WAAO,YAAY,aAAa,qBAAqB,WAAW,mGAAmG;AAEnK,WAAO,OAAO;AACd,QAAI,CAAC,0BAA0B,OAAO;AACpC,YAAM,IAAI,WAAW;AALwC;AAQ/D,cAAU,OAAO;AAAO,aAAO;AAAO,YAAM;AAAtB;AACtB,cAAU,mBAAmB;AAT/B;AAYA,UAAQ,iBAAiB,UAAU,WAAW;AAC5C,WAAO,YAAY,aAAa,qBAAqB,WAAW;AAChE,WAAO,UAAU,OAAO,SAAS,GAAG;AAEpC,QAAI,OAAO,UAAU,OAAO;AAC5B,WAAO,KAAK;AALd;AAQA,UAAQ,aAAa,UAAU,WAAW;AACxC,WAAO,YAAY,aAAa,qBAAqB,WAAW;AAEhE,cAAU,SAAS;AACnB,cAAU,kBAAkB;AAJ9B;AAtwCU,GA+wCH,UAAS,QAAQ,SAAS,qBAAqB;AAEtD;;AAGA,MAAI,2BAA2B;AAAE,aAAS,iBAAiB,QAAQ,OAAO;AAAE,WAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AAAE,YAAI,aAAa,MAAM;AAAI,mBAAW,aAAa,WAAW,cAAc;AAAO,mBAAW,eAAe;AAAM,YAAI,WAAW,YAAY,WAAW,WAAW;AAAM,eAAO,eAAe,QAAQ,WAAW,KAAK;AAAnQ;AAA3C;AAA+T,WAAO,UAAU,aAAa,YAAY,aAAa;AAAE,UAAI,YAAY,iBAAiB,YAAY,WAAW;AAAa,UAAI,aAAa,iBAAiB,aAAa;AAAc,aAAO;AAAlM;AAA3U;AAEnB,WAAS,gBAAgB,UAAU,aAAa;AAAE,QAAM,sBAAoB,cAAc;AAAE,YAAM,IAAI,UAAU;AAAhE;AAPM;AAStD,MAAI,WAAW,oBAAoB;MAC/B,kBAAkB,SAAS;MAC3B,yBAAyB,SAAS;MAClC,4BAA4B,SAAS;MACrC,eAAe,SAAS;MACxB,sBAAsB,SAAS;MAC/B,sBAAsB,SAAS;MAC/B,sCAAsC,SAAS;MAC/C,oCAAoC,SAAS;AAEjD,MAAI,YAAY,oBAAoB;MAChC,sBAAsB,UAAU;MAChC,qBAAqB,UAAU;MAC/B,eAAe,UAAU;AAE7B,MAAI,YAAY,oBAAoB;MAChC,SAAS,UAAU;MACnB,iCAAiC,UAAU;AAE/C,MAAI,YAAY,oBAAoB;MAChC,eAAe,UAAU;MACzB,uBAAuB,UAAU;MACjC,aAAa,UAAU;AAE3B,MAAI,YAAY,oBAAoB;MAChC,qCAAqC,UAAU;MAC/C,mBAAmB,UAAU;MAC7B,yBAAyB,UAAU;MACnC,sBAAsB,UAAU;MAChC,uDAAuD,UAAU;MACjE,qCAAqC,UAAU;MAC/C,mCAAmC,UAAU;MAC7C,sCAAsC,UAAU;AAEpD,MAAI,6BAA6B;AAC/B,aAAS,iBAAiB;AACxB,UAAI,mBAAmB,UAAU,SAAS,KAAK,UAAU,OAAO,YAAY,UAAU,KAAK;AAE3F,UAAI,OAAO,UAAU,SAAS,KAAK,UAAU,OAAO,YAAY,UAAU,KAAK;UAC3E,OAAO,KAAK;UACZ,gBAAgB,KAAK;AAEzB,sBAAgB,MAAM;AAGtB,WAAK,SAAS;AAEd,WAAK,UAAU;AACf,WAAK,eAAe;AAEpB,WAAK,aAAa;AAIlB,WAAK,4BAA4B;AACjC,UAAI,OAAO,iBAAiB;AAC5B,UAAI,aAAa,OAAO;AACxB,UAAI,eAAe,SAAS;AAC1B,YAAI,kBAAkB,WAAW;AAC/B,0BAAgB;AAFQ;AAI1B,aAAK,4BAA4B,IAAI,6BAA6B,MAAM,kBAAkB;AAJ5F,iBAKW,SAAS,WAAW;AAC7B,YAAI,kBAAkB,WAAW;AAC/B,0BAAgB;AAFW;AAI7B,aAAK,4BAA4B,IAAI,gCAAgC,MAAM,kBAAkB,MAAM;AAJ9F,aAKA;AACL,cAAM,IAAI,WAAW;AAjCC;AADK;AAsC/B,iBAAa;AACX,WAAK;AACL,aAAO,SAAS,OAAO,QAAQ;AAC7B,YAAI,iBAAiB,UAAU,OAAO;AACpC,iBAAO,QAAQ,OAAO,0BAA0B;AAFrB;AAK7B,YAAI,uBAAuB,UAAU,MAAM;AACzC,iBAAO,QAAQ,OAAO,IAAI,UAAU;AANT;AAS7B,eAAO,qBAAqB,MAAM;AAXR;AAAA,KAAD;AAc3B,WAAK;AACL,aAAO,SAAS,YAAY;AAC1B,YAAI,QAAQ,UAAU,SAAS,KAAK,UAAU,OAAO,YAAY,UAAU,KAAK;YAC5E,OAAO,MAAM;AAEjB,YAAI,iBAAiB,UAAU,OAAO;AACpC,gBAAM,0BAA0B;AALR;AAQ1B,YAAI,SAAS,WAAW;AACtB,iBAAO,mCAAmC;AATlB;AAY1B,eAAO,OAAO;AAEd,YAAI,SAAS,QAAQ;AACnB,iBAAO,gCAAgC;AAff;AAkB1B,cAAM,IAAI,WAAW;AApBtB;AAAA;AAuBD,WAAK;AACL,aAAO,SAAS,YAAY,OAAO,SAAS;AAC1C,YAAI,WAAW,MAAM;YACjB,WAAW,MAAM;AAErB,YAAI,UAAU,KAAK,OAAO,UAAU;AAEpC,+EAAuE;AAEvE,eAAO;AAVR;AAAA;AAaD,WAAK;AACL,aAAO,SAAS,OAAO,MAAM;AAC3B,YAAI,QAAQ;AAEZ,YAAI,QAAQ,UAAU,SAAS,KAAK,UAAU,OAAO,YAAY,UAAU,KAAK;YAC5E,eAAe,MAAM;YACrB,eAAe,MAAM;YACrB,gBAAgB,MAAM;AAE1B,YAAI,iBAAiB,UAAU,OAAO;AACpC,iBAAO,QAAQ,OAAO,0BAA0B;AATvB;AAW3B,YAAI,iBAAiB,UAAU,OAAO;AACpC,iBAAO,QAAQ,OAAO,IAAI,UAAU;AAZX;AAe3B,uBAAe,QAAQ;AACvB,uBAAe,QAAQ;AACvB,wBAAgB,QAAQ;AAExB,YAAI,uBAAuB,UAAU,MAAM;AACzC,iBAAO,QAAQ,OAAO,IAAI,UAAU;AApBX;AAsB3B,YAAI,uBAAuB,UAAU,MAAM;AACzC,iBAAO,QAAQ,OAAO,IAAI,UAAU;AAvBX;AA0B3B,YAAI,SAAS,mCAAmC;AAChD,YAAI,SAAS,mCAAmC;AAEhD,YAAI,eAAe;AAGnB,YAAI,eAAe,QAAQ;AAE3B,mBAAW,QAAQ,UAAU,SAAS,QAAQ;AAI5C,mBAAS,WAAW;AAClB,2BAAe,QAAQ;AAEvB,gBAAI,iBAAiB,MAAM;AACzB,qBAAO,QAAQ;AAJC;AAOlB,0BAAc,cAAc,KAAK,YAAY;AAC3C,qDAAuC,QAAQ,KAAK,UAAU,OAAO;AACnE,oBAAI,QAAQ,MAAM;oBACd,OAAO,MAAM;AAEjB,oBAAI,SAAS,MAAM;AACjB;AALiE;AAQnE,+BAAe,iCAAiC,QAAQ,OAAO,MAAM,YAAY,CAAlE;AARV;AADF,eAWJ,KAAK;AAtBkC;AA0B5C,6BAAmB,OAAO,OAAO,gBAAgB,UAAU,aAAa;AACtE,gBAAI,iBAAiB,OAAO;AAC1B,iCAAmB,YAAY;AAC7B,uBAAO,oBAAoB,MAAM;AADnC,iBAEG,MAAM;AAHX,mBAIO;AACL,uBAAS,MAAM;AANqD;AAAxE;AAWA,6BAAmB,MAAM,OAAO,gBAAgB,UAAU,aAAa;AACrE,gBAAI,kBAAkB,OAAO;AAC3B,iCAAmB,YAAY;AAC7B,uBAAO,qBAAqB,OAAO;AADrC,iBAEG,MAAM;AAHX,mBAIO;AACL,uBAAS,MAAM;AANoD;AAAvE;AAWA,4BAAkB,OAAO,OAAO,gBAAgB,YAAY;AAC1D,gBAAI,iBAAiB,OAAO;AAC1B,iCAAmB,YAAY;AAC7B,uBAAO,qDAAqD;AAD9D;AADF,mBAIO;AACL;AANwD;AAA5D;AAWA,cAAI,oCAAoC,UAAU,QAAQ,KAAK,WAAW,UAAU;AAClF,gBAAI,aAAa,IAAI,UAAU;AAE/B,gBAAI,kBAAkB,OAAO;AAC3B,iCAAmB,YAAY;AAC7B,uBAAO,qBAAqB,OAAO;AADrC,iBAEG,MAAM;AAHX,mBAIO;AACL,uBAAS,MAAM;AARiE;AA3DxC;AAuE5C,qBAAW,MAAM,UAAU,KAAK;AAC9B,2BAAe,QAAQ;AACvB,2CAA+B;AAFjC;AAKA,mBAAS,wBAAwB;AAG/B,gBAAI,kBAAkB;AACtB,gCAAoB,KAAK,YAAY;AACnC,qBAAO,oBAAoB,eAAe,0BAA0B;AAD/D;AAhFmC;AAqF5C,mBAAS,mBAAmB,QAAQ,SAAS,QAAQ;AACnD,gBAAI,OAAO,WAAW,WAAW;AAC/B,qBAAO,OAAO;AADhB,mBAEO;AACL,sBAAQ,MAAM,QAAQ,MAAM;AAJqB;AArFT;AA6F5C,mBAAS,kBAAkB,QAAQ,SAAS,QAAQ;AAClD,gBAAI,OAAO,WAAW,UAAU;AAC9B;AADF,mBAEO;AACL,sBAAQ,KAAK,QAAQ,MAAM;AAJqB;AA7FR;AAqG5C,mBAAS,mBAAmB,QAAQ,iBAAiB,eAAe;AAClE,gBAAI,iBAAiB,MAAM;AACzB;AAFgE;AAIlE,2BAAe;AAEf,gBAAI,KAAK,WAAW,cAAc,oCAAoC,UAAU,OAAO;AACrF,sCAAwB,KAAK;AAD/B,mBAEO;AACL;AATgE;AAYlE,qBAAS,YAAY;AACnB,uBAAS,KAAK,YAAY;AACxB,uBAAO,SAAS,iBAAiB;AADnC,iBAEG,UAAU,UAAU;AACrB,uBAAO,SAAS,MAAM;AAHxB,iBAIG,MAAM;AAjBuD;AArGxB;AA0H5C,mBAAS,SAAS,SAAS,OAAO;AAChC,gBAAI,iBAAiB,MAAM;AACzB;AAF8B;AAIhC,2BAAe;AAEf,gBAAI,KAAK,WAAW,cAAc,oCAAoC,UAAU,OAAO;AACrF,sCAAwB,KAAK,YAAY;AACvC,uBAAO,SAAS,SAAS;AAD3B,iBAEG,MAAM;AAHX,mBAIO;AACL,uBAAS,SAAS;AAXY;AA1HU;AAyI5C,mBAAS,SAAS,SAAS,OAAO;AAChC,+CAAmC;AACnC,+CAAmC;AAEnC,gBAAI,SAAS;AACX,qBAAO;AADT,mBAEO;AACL,sBAAQ;AAPsB;AAzIU;AAAvC;AApCR;AAAA;AA0LD,WAAK;AACL,aAAO,SAAS,MAAM;AACpB,YAAI,iBAAiB,UAAU,OAAO;AACpC,gBAAM,0BAA0B;AAFd;AAKpB,YAAI,WAAW,kBAAkB,MAAM;AACvC,eAAO,oBAAoB;AAR5B;AAAA;AAWD,WAAK;AACL,WAAK,SAAS,MAAM;AAClB,YAAI,iBAAiB,UAAU,OAAO;AACpC,gBAAM,0BAA0B;AAFhB;AAKlB,eAAO,uBAAuB;AAP/B;AAAA;AAWH,WAAO;AAnSY;AAsSrB,SAAO;AACL,oBAAgB;AAChB,+BAA2B;AAC3B,0CAAsC;AACtC,4CAAwC;AACxC,0CAAsC;AACtC,mDAA+C;AANhC;AAWjB,WAAS,gCAAgC,QAAQ;AAC/C,WAAO,IAAI,yBAAyB;AA7VgB;AAgWtD,WAAS,mCAAmC,QAAQ;AAClD,WAAO,IAAI,4BAA4B;AAjWa;AAoWtD,WAAS,iBAAiB,GAAG;AAC3B,QAAI,CAAC,aAAa,IAAI;AACpB,aAAO;AAFkB;AAK3B,QAAI,CAAC,OAAO,UAAU,eAAe,KAAK,GAAG,8BAA8B;AACzE,aAAO;AANkB;AAS3B,WAAO;AA7W6C;AAgXtD,WAAS,0BAA0B,QAAQ;AACzC,WAAO,iBAAiB,YAAY,MAAM;AAE1C,WAAO,OAAO;AAnXsC;AAsXtD,WAAS,uBAAuB,QAAQ;AACtC,WAAO,iBAAiB,YAAY,MAAM;AAE1C,QAAI,OAAO,YAAY,WAAW;AAChC,aAAO;AAJ6B;AAOtC,WAAO;AA7X6C;AAgYtD,WAAS,kBAAkB,QAAQ,iBAAiB;AAClD,WAAO,iBAAiB,YAAY;AACpC,WAAO,OAAO,oBAAoB;AAElC,QAAI,SAAS,mCAAmC;AAEhD,QAAI;AACF,uBAAiB;AACjB,iBAAW;AACX,iBAAW;AACX,eAAS;AACT,eAAS;AALI;AAOf,aAAS,cAAc,QAAQ,UAAU,SAAS;AAChD,eAAS,WAAW;AADH;AAInB,QAAI,OAAO;AACX,SAAK,UAAU;AACf,SAAK,YAAY;AACjB,SAAK,mBAAmB;AAExB,QAAI,UAAU;AACd,YAAQ,UAAU;AAClB,YAAQ,YAAY;AAEpB,QAAI,UAAU;AACd,YAAQ,UAAU;AAClB,YAAQ,YAAY;AAEpB,QAAI,oBAAoB,OAAO,OAAO,OAAO;AAC7C,uBAAmB,mBAAmB,QAAQ;AAC9C,uBAAmB,mBAAmB,UAAU;AAChD,QAAI,gBAAgB,IAAI,eAAe;AAEvC,QAAI,oBAAoB,OAAO,OAAO,OAAO;AAC7C,uBAAmB,mBAAmB,QAAQ;AAC9C,uBAAmB,mBAAmB,UAAU;AAChD,QAAI,gBAAgB,IAAI,eAAe;AAEvC,SAAK,WAAW,cAAc;AAC9B,SAAK,WAAW,cAAc;AAE9B,WAAO,eAAe,MAAM,UAAU,GAAG;AACvC,UAAI,SAAS,oBAAoB,MAAM;AACrC;AAFqC;AAKvC,2CAAqC,KAAK,UAAU;AACpD,2CAAqC,KAAK,UAAU;AACpD,eAAS,kBAAkB;AAP7B;AAUA,WAAO,CAAC,eAAe;AArb6B;AAwbtD,WAAS,uCAAuC;AAC9C,aAAS,IAAI;AACX,UAAI,SAAS,EAAE;UACX,UAAU,EAAE;UACZ,UAAU,EAAE;UACZ,WAAW,EAAE;AAGjB,6CAAuC,QAAQ,KAAK,UAAU,QAAQ;AACpE,eAAO,aAAa;AACpB,YAAI,QAAQ,OAAO;AACnB,YAAI,OAAO,OAAO;AAClB,eAAO,OAAO,SAAS;AAEvB,YAAI,SAAS,QAAQ,SAAS,oBAAoB,OAAO;AACvD,cAAI,SAAS,cAAc,OAAO;AAChC,iDAAqC;AAFgB;AAIvD,cAAI,SAAS,cAAc,OAAO;AAChC,iDAAqC;AALgB;AAOvD,mBAAS,kBAAkB;AAbuC;AAgBpE,YAAI,SAAS,oBAAoB,MAAM;AACrC;AAjBkE;AAoBpE,YAAI,SAAS;AACb,YAAI,SAAS;AAQb,YAAI,SAAS,cAAc,OAAO;AAChC,iDAAuC,SAAS;AA9BkB;AAiCpE,YAAI,SAAS,cAAc,OAAO;AAChC,iDAAuC,SAAS;AAlCkB;AAA/D;AARqC;AA8C9C,WAAO;AAte6C;AAyetD,WAAS,gDAAgD;AACvD,aAAS,EAAE,QAAQ;AACjB,UAAI,SAAS,EAAE;UACX,WAAW,EAAE;AAGjB,eAAS,YAAY;AACrB,eAAS,UAAU;AACnB,UAAI,SAAS,cAAc,MAAM;AAC/B,YAAI,kBAAkB,oBAAoB,CAAC,SAAS,SAAS,SAAS;AACtE,YAAI,eAAe,qBAAqB,QAAQ;AAChD,iBAAS,SAAS;AAVH;AAYjB,aAAO,SAAS;AAbqC;AAevD,WAAO;AAxf6C;AA2ftD,WAAS,gDAAgD;AACvD,aAAS,EAAE,QAAQ;AACjB,UAAI,SAAS,EAAE;UACX,WAAW,EAAE;AAGjB,eAAS,YAAY;AACrB,eAAS,UAAU;AACnB,UAAI,SAAS,cAAc,MAAM;AAC/B,YAAI,kBAAkB,oBAAoB,CAAC,SAAS,SAAS,SAAS;AACtE,YAAI,eAAe,qBAAqB,QAAQ;AAChD,iBAAS,SAAS;AAVH;AAYjB,aAAO,SAAS;AAbqC;AAevD,WAAO;AA1gB6C;AA+gBtD,WAAS,iCAAiC,QAAQ;AAChD,WAAO,2BAA2B,OAAO,aAAa;AACtD,WAAO,OAAO,WAAW,cAAc,OAAO,WAAW;AAEzD,QAAI,cAAc,QAAQ,UAAU,SAAS,QAAQ;AACnD,UAAI;AACF,kBAAU;AACV,iBAAS;AAFW;AAKtB,aAAO,QAAQ,kBAAkB,KAAK;AAN1B;AASd,WAAO;AA5hB6C;AA+hBtD,WAAS,6BAA6B,QAAQ;AAC5C,WAAO,8BAA8B,OAAO,aAAa;AACzD,WAAO,OAAO,WAAW;AAEzB,QAAI,cAAc,QAAQ,UAAU,SAAS,QAAQ;AACnD,UAAI;AACF,kBAAU;AACV,iBAAS;AAFO;AAKlB,aAAO,QAAQ,cAAc,KAAK;AANtB;AASd,WAAO;AA5iB6C;AA+iBtD,WAAS,qBAAqB,QAAQ,QAAQ;AAC5C,WAAO,aAAa;AAEpB,QAAI,OAAO,WAAW,UAAU;AAC9B,aAAO,QAAQ,QAAQ;AAJmB;AAM5C,QAAI,OAAO,WAAW,WAAW;AAC/B,aAAO,QAAQ,OAAO,OAAO;AAPa;AAU5C,wBAAoB;AAEpB,QAAI,sBAAsB,OAAO,0BAA0B,cAAc;AACzE,+BAA2B,KAAK,YAAY;AAC1C,aAAO;AADF;AA5jB6C;AAikBtD,WAAS,oBAAoB,QAAQ;AACnC,WAAO,OAAO,WAAW;AAEzB,WAAO,SAAS;AAEhB,QAAI,SAAS,OAAO;AAEpB,QAAI,WAAW,WAAW;AACxB,aAAO;AAR0B;AAWnC,QAAI,8BAA8B,YAAY,MAAM;AAClD,WAAK,IAAI,IAAI,GAAG,IAAI,OAAO,cAAc,QAAQ,KAAK;AACpD,YAAI,WAAW,OAAO,cAAc,GAAG;AAEvC,iBAAS,uBAAuB,WAAW;AAJK;AAMlD,aAAO,gBAAgB;AAjBU;AAoBnC,sCAAkC;AAElC,WAAO;AAvlB6C;AA0lBtD,WAAS,oBAAoB,QAAQ,GAAG;AACtC,WAAO,iBAAiB,YAAY,MAAM;AAC1C,WAAO,OAAO,WAAW,YAAY;AAErC,WAAO,SAAS;AAChB,WAAO,eAAe;AAEtB,QAAI,SAAS,OAAO;AAEpB,QAAI,WAAW,WAAW;AACxB,aAAO;AAV6B;AAatC,QAAI,8BAA8B,YAAY,MAAM;AAClD,WAAK,IAAI,IAAI,GAAG,IAAI,OAAO,cAAc,QAAQ,KAAK;AACpD,YAAI,cAAc,OAAO,cAAc;AACvC,oBAAY,QAAQ;AAH4B;AAMlD,aAAO,gBAAgB;AANzB,WAOO;AACL,aAAO,2BAA2B,SAAS;AAE3C,WAAK,IAAI,KAAK,GAAG,KAAK,OAAO,kBAAkB,QAAQ,MAAM;AAC3D,YAAI,kBAAkB,OAAO,kBAAkB;AAC/C,wBAAgB,QAAQ;AALrB;AAQL,aAAO,oBAAoB;AA5BS;AA+BtC,qCAAiC,QAAQ;AACzC,WAAO,eAAe,MAAM,YAAY,CAAxC;AA1nBoD;AA6nBtD,WAAS,qCAAqC,QAAQ,OAAO,MAAM;AACjE,QAAI,SAAS,OAAO;AAEpB,WAAO,OAAO,kBAAkB,SAAS;AAEzC,QAAI,kBAAkB,OAAO,kBAAkB;AAC/C,oBAAgB,SAAS,uBAAuB,OAAO;AAnoBH;AAsoBtD,WAAS,iCAAiC,QAAQ,OAAO,MAAM;AAC7D,QAAI,SAAS,OAAO;AAEpB,WAAO,OAAO,cAAc,SAAS;AAErC,QAAI,cAAc,OAAO,cAAc;AACvC,gBAAY,SAAS,uBAAuB,OAAO;AA5oBC;AA+oBtD,WAAS,qCAAqC,QAAQ;AACpD,WAAO,OAAO,QAAQ,kBAAkB;AAhpBY;AAmpBtD,WAAS,iCAAiC,QAAQ;AAChD,WAAO,OAAO,QAAQ,cAAc;AAppBgB;AAupBtD,WAAS,4BAA4B,QAAQ;AAC3C,QAAI,SAAS,OAAO;AAEpB,QAAI,WAAW,WAAW;AACxB,aAAO;AAJkC;AAO3C,QAAI,2BAA2B,YAAY,OAAO;AAChD,aAAO;AARkC;AAW3C,WAAO;AAlqB6C;AAqqBtD,WAAS,+BAA+B,QAAQ;AAC9C,QAAI,SAAS,OAAO;AAEpB,QAAI,WAAW,WAAW;AACxB,aAAO;AAJqC;AAO9C,QAAI,8BAA8B,YAAY,OAAO;AACnD,aAAO;AARqC;AAW9C,WAAO;AAhrB6C;AAqrBtD,MAAI,0CAA0C;AAC5C,aAAS,4BAA4B,QAAQ;AAC3C,sBAAgB,MAAM;AAEtB,UAAI,iBAAiB,YAAY,OAAO;AACtC,cAAM,IAAI,UAAU;AAJqB;AAM3C,UAAI,uBAAuB,YAAY,MAAM;AAC3C,cAAM,IAAI,UAAU;AAPqB;AAU3C,4CAAsC,MAAM;AAE5C,WAAK,gBAAgB;AAbqB;AAgB5C,iBAAa;AACX,WAAK;AACL,aAAO,SAAS,OAAO,QAAQ;AAC7B,YAAI,8BAA8B,UAAU,OAAO;AACjD,iBAAO,QAAQ,OAAO,iCAAiC;AAF5B;AAK7B,YAAI,KAAK,yBAAyB,WAAW;AAC3C,iBAAO,QAAQ,OAAO,oBAAoB;AANf;AAS7B,eAAO,kCAAkC,MAAM;AAXR;AAAA,KAAD;AAcxC,WAAK;AACL,aAAO,SAAS,OAAO;AACrB,YAAI,8BAA8B,UAAU,OAAO;AACjD,iBAAO,QAAQ,OAAO,iCAAiC;AAFpC;AAKrB,YAAI,KAAK,yBAAyB,WAAW;AAC3C,iBAAO,QAAQ,OAAO,oBAAoB;AANvB;AASrB,eAAO,gCAAgC;AAXxC;AAAA;AAcD,WAAK;AACL,aAAO,SAAS,cAAc;AAC5B,YAAI,8BAA8B,UAAU,OAAO;AACjD,gBAAM,iCAAiC;AAFb;AAK5B,YAAI,KAAK,yBAAyB,WAAW;AAC3C;AAN0B;AAS5B,YAAI,KAAK,cAAc,SAAS,GAAG;AACjC,gBAAM,IAAI,UAAU;AAVM;AAa5B,2CAAmC;AAfpC;AAAA;AAkBD,WAAK;AACL,WAAK,SAAS,MAAM;AAClB,YAAI,8BAA8B,UAAU,OAAO;AACjD,iBAAO,QAAQ,OAAO,iCAAiC;AAFvC;AAKlB,eAAO,KAAK;AAPb;AAAA;AAWH,WAAO;AAtEyB;AAyElC,MAAI,uCAAuC;AACzC,aAAS,yBAAyB,QAAQ;AACxC,sBAAgB,MAAM;AAEtB,UAAI,CAAC,iBAAiB,SAAS;AAC7B,cAAM,IAAI,UAAU,6FAA6F;AAJ3E;AAMxC,UAAI,+BAA+B,OAAO,+BAA+B,OAAO;AAC9E,cAAM,IAAI,UAAU,0FAA0F;AAPxE;AASxC,UAAI,uBAAuB,SAAS;AAClC,cAAM,IAAI,UAAU;AAVkB;AAaxC,4CAAsC,MAAM;AAE5C,WAAK,oBAAoB;AAhBc;AAmBzC,iBAAa;AACX,WAAK;AACL,aAAO,SAAS,OAAO,QAAQ;AAC7B,YAAI,CAAC,2BAA2B,OAAO;AACrC,iBAAO,QAAQ,OAAO,8BAA8B;AAFzB;AAK7B,YAAI,KAAK,yBAAyB,WAAW;AAC3C,iBAAO,QAAQ,OAAO,oBAAoB;AANf;AAS7B,eAAO,kCAAkC,MAAM;AAXX;AAAA,KAAD;AAcrC,WAAK;AACL,aAAO,SAAS,KAAK,MAAM;AACzB,YAAI,CAAC,2BAA2B,OAAO;AACrC,iBAAO,QAAQ,OAAO,8BAA8B;AAF7B;AAKzB,YAAI,KAAK,yBAAyB,WAAW;AAC3C,iBAAO,QAAQ,OAAO,oBAAoB;AANnB;AASzB,YAAI,CAAC,YAAY,OAAO,OAAO;AAC7B,iBAAO,QAAQ,OAAO,IAAI,UAAU;AAVb;AAazB,YAAI,KAAK,eAAe,GAAG;AACzB,iBAAO,QAAQ,OAAO,IAAI,UAAU;AAdb;AAiBzB,eAAO,6BAA6B,MAAM;AAnB3C;AAAA;AAsBD,WAAK;AACL,aAAO,SAAS,cAAc;AAC5B,YAAI,CAAC,2BAA2B,OAAO;AACrC,gBAAM,8BAA8B;AAFV;AAK5B,YAAI,KAAK,yBAAyB,WAAW;AAC3C;AAN0B;AAS5B,YAAI,KAAK,kBAAkB,SAAS,GAAG;AACrC,gBAAM,IAAI,UAAU;AAVM;AAa5B,2CAAmC;AAfpC;AAAA;AAkBD,WAAK;AACL,WAAK,SAAS,MAAM;AAClB,YAAI,CAAC,2BAA2B,OAAO;AACrC,iBAAO,QAAQ,OAAO,8BAA8B;AAFpC;AAKlB,eAAO,KAAK;AAPb;AAAA;AAWH,WAAO;AAjFsB;AAsF/B,WAAS,2BAA2B,GAAG;AACrC,QAAI,CAAC,aAAa,IAAI;AACpB,aAAO;AAF4B;AAKrC,QAAI,CAAC,OAAO,UAAU,eAAe,KAAK,GAAG,sBAAsB;AACjE,aAAO;AAN4B;AASrC,WAAO;AA71B6C;AAg2BtD,WAAS,8BAA8B,GAAG;AACxC,QAAI,CAAC,aAAa,IAAI;AACpB,aAAO;AAF+B;AAKxC,QAAI,CAAC,OAAO,UAAU,eAAe,KAAK,GAAG,kBAAkB;AAC7D,aAAO;AAN+B;AASxC,WAAO;AAz2B6C;AA42BtD,WAAS,sCAAsC,QAAQ,QAAQ;AAC7D,WAAO,uBAAuB;AAC9B,WAAO,UAAU;AAEjB,QAAI,OAAO,WAAW,YAAY;AAChC,2CAAqC;AADvC,eAEW,OAAO,WAAW,UAAU;AACrC,qDAA+C;AAD1C,WAEA;AACL,aAAO,OAAO,WAAW,WAAW;AAEpC,qDAA+C,QAAQ,OAAO;AAC9D,aAAO,eAAe,MAAM,YAAY,CAAxC;AAZ2D;AA52BT;AA+3BtD,WAAS,kCAAkC,QAAQ,QAAQ;AACzD,QAAI,SAAS,OAAO;AACpB,WAAO,WAAW;AAClB,WAAO,qBAAqB,QAAQ;AAl4BgB;AAq4BtD,WAAS,mCAAmC,QAAQ;AAClD,WAAO,OAAO,yBAAyB;AACvC,WAAO,OAAO,qBAAqB,YAAY;AAE/C,QAAI,OAAO,qBAAqB,WAAW,YAAY;AACrD,uCAAiC,QAAQ,IAAI,UAAU;AADzD,WAEO;AACL,gDAA0C,QAAQ,IAAI,UAAU;AAPhB;AASlD,WAAO,eAAe,MAAM,YAAY,CAAxC;AAEA,WAAO,qBAAqB,UAAU;AACtC,WAAO,uBAAuB;AAj5BsB;AAo5BtD,WAAS,6BAA6B,QAAQ,MAAM;AAClD,QAAI,SAAS,OAAO;AAEpB,WAAO,WAAW;AAElB,WAAO,aAAa;AAEpB,QAAI,OAAO,WAAW,WAAW;AAC/B,aAAO,QAAQ,OAAO,OAAO;AARmB;AAYlD,WAAO,qCAAqC,OAAO,2BAA2B;AAh6B1B;AAm6BtD,WAAS,gCAAgC,QAAQ;AAC/C,QAAI,SAAS,OAAO;AAEpB,WAAO,WAAW;AAElB,WAAO,aAAa;AAEpB,QAAI,OAAO,WAAW,UAAU;AAC9B,aAAO,QAAQ,QAAQ,uBAAuB,WAAW;AARZ;AAW/C,QAAI,OAAO,WAAW,WAAW;AAC/B,aAAO,QAAQ,OAAO,OAAO;AAZgB;AAe/C,WAAO,OAAO,WAAW;AAEzB,WAAO,OAAO,0BAA0B;AAp7BY;AAy7BtD,MAAI,8CAA8C;AAChD,aAAS,gCAAgC,QAAQ,kBAAkB,MAAM,eAAe;AACtF,sBAAgB,MAAM;AAEtB,UAAI,iBAAiB,YAAY,OAAO;AACtC,cAAM,IAAI,UAAU;AAJgE;AAOtF,UAAI,OAAO,8BAA8B,WAAW;AAClD,cAAM,IAAI,UAAU;AARgE;AAWtF,WAAK,4BAA4B;AAEjC,WAAK,oBAAoB;AAGzB,WAAK,SAAS;AACd,WAAK,kBAAkB;AACvB,iBAAW;AAEX,WAAK,WAAW;AAChB,WAAK,kBAAkB;AACvB,WAAK,aAAa;AAClB,WAAK,WAAW;AAEhB,UAAI,qBAAqB,oCAAoC,MAAM;AACnE,WAAK,gBAAgB,mBAAmB;AACxC,WAAK,eAAe,mBAAmB;AAEvC,UAAI,aAAa;AAEjB,UAAI,cAAc,aAAa,kBAAkB,SAAS,CAAC;AAC3D,cAAQ,QAAQ,aAAa,KAAK,YAAY;AAC5C,mBAAW,WAAW;AAEtB,eAAO,WAAW,aAAa;AAC/B,eAAO,WAAW,eAAe;AAEjC,wDAAgD;AANlD,SAOG,UAAU,GAAG;AACd,qDAA6C,YAAY;AAR3D,SASG,MAAM;AA1CqC;AA6ChD,iBAAa;AACX,WAAK;AACL,aAAO,SAAS,QAAQ;AACtB,YAAI,kCAAkC,UAAU,OAAO;AACrD,gBAAM,qCAAqC;AAFvB;AAKtB,YAAI,KAAK,oBAAoB,MAAM;AACjC,gBAAM,IAAI,UAAU;AANA;AAStB,YAAI,QAAQ,KAAK,0BAA0B;AAC3C,YAAI,UAAU,YAAY;AACxB,gBAAM,IAAI,UAAU,oBAAoB,QAAQ;AAX5B;AActB,6CAAqC;AAhBM;AAAA,KAAD;AAmB5C,WAAK;AACL,aAAO,SAAS,QAAQ,OAAO;AAC7B,YAAI,kCAAkC,UAAU,OAAO;AACrD,gBAAM,qCAAqC;AAFhB;AAK7B,YAAI,KAAK,oBAAoB,MAAM;AACjC,gBAAM,IAAI,UAAU;AANO;AAS7B,YAAI,QAAQ,KAAK,0BAA0B;AAC3C,YAAI,UAAU,YAAY;AACxB,gBAAM,IAAI,UAAU,oBAAoB,QAAQ;AAXrB;AAc7B,eAAO,uCAAuC,MAAM;AAhBrD;AAAA;AAmBD,WAAK;AACL,aAAO,SAAS,MAAM,GAAG;AACvB,YAAI,kCAAkC,UAAU,OAAO;AACrD,gBAAM,qCAAqC;AAFtB;AAKvB,YAAI,SAAS,KAAK;AAClB,YAAI,OAAO,WAAW,YAAY;AAChC,gBAAM,IAAI,UAAU,mBAAmB,OAAO,SAAS;AAPlC;AAUvB,6CAAqC,MAAM;AAZ5C;AAAA;AAeD,WAAK;AACL,aAAO,SAAS,cAAc,QAAQ;AACpC,mBAAW;AACX,eAAO,oBAAoB,KAAK,mBAAmB,UAAU,CAAC;AAJ/D;AAAA;AAOD,WAAK;AACL,aAAO,SAAS,cAAc;AAC5B,YAAI,SAAS,KAAK;AAElB,YAAI,KAAK,OAAO,SAAS,GAAG;AAC1B,cAAI,QAAQ,aAAa;AAEzB,cAAI,KAAK,oBAAoB,QAAQ,KAAK,OAAO,WAAW,GAAG;AAC7D,gCAAoB;AADtB,iBAEO;AACL,4DAAgD;AANxB;AAS1B,iBAAO,QAAQ,QAAQ,uBAAuB,OAAO;AAZ3B;AAe5B,YAAI,iBAAiB,6BAA6B;AAClD,wDAAgD;AAChD,eAAO;AAnBR;AAAA;AAsBD,WAAK;AACL,WAAK,SAAS,MAAM;AAClB,YAAI,kCAAkC,UAAU,OAAO;AACrD,gBAAM,qCAAqC;AAF3B;AAKlB,eAAO,8CAA8C;AAPtD;AAAA;AAWH,WAAO;AArI6B;AA0ItC,WAAS,kCAAkC,GAAG;AAC5C,QAAI,CAAC,aAAa,IAAI;AACpB,aAAO;AAFmC;AAK5C,QAAI,CAAC,OAAO,UAAU,eAAe,KAAK,GAAG,sBAAsB;AACjE,aAAO;AANmC;AAS5C,WAAO;AA5kC6C;AA+kCtD,WAAS,gDAAgD,YAAY;AACnE,QAAI,aAAa,8CAA8C;AAC/D,QAAI,eAAe,OAAO;AACxB,aAAO;AAH0D;AAMnE,QAAI,WAAW,aAAa,MAAM;AAChC,iBAAW,aAAa;AACxB,aAAO;AAR0D;AAWnE,WAAO,WAAW,eAAe;AAEjC,eAAW,WAAW;AAEtB,QAAI,cAAc,oBAAoB,WAAW,mBAAmB,QAAQ,CAAC;AAC7E,gBAAY,KAAK,YAAY;AAC3B,iBAAW,WAAW;AAEtB,UAAI,WAAW,eAAe,MAAM;AAClC,mBAAW,aAAa;AACxB,eAAO,gDAAgD;AAL9B;AAO3B,aAAO;AAPT,OAQG,UAAU,GAAG;AACd,mDAA6C,YAAY;AAT3D,OAUG,MAAM;AAET,WAAO;AA3mC6C;AA8mCtD,WAAS,8CAA8C,YAAY;AACjE,QAAI,SAAS,WAAW;AAExB,QAAI,OAAO,WAAW,YAAY,OAAO,WAAW,WAAW;AAC7D,aAAO;AAJwD;AAOjE,QAAI,WAAW,oBAAoB,MAAM;AACvC,aAAO;AARwD;AAWjE,QAAI,WAAW,aAAa,OAAO;AACjC,aAAO;AAZwD;AAejE,QAAI,uBAAuB,YAAY,QAAQ,iCAAiC,UAAU,GAAG;AAC3F,aAAO;AAhBwD;AAmBjE,QAAI,cAAc,8CAA8C;AAChE,QAAI,cAAc,GAAG;AACnB,aAAO;AArBwD;AAwBjE,WAAO;AAtoC6C;AA2oCtD,WAAS,qCAAqC,YAAY;AACxD,QAAI,SAAS,WAAW;AAExB,WAAO,WAAW,oBAAoB;AACtC,WAAO,OAAO,WAAW;AAEzB,eAAW,kBAAkB;AAE7B,QAAI,WAAW,OAAO,WAAW,GAAG;AAClC,0BAAoB;AATkC;AA3oCJ;AAwpCtD,WAAS,uCAAuC,YAAY,OAAO;AACjE,QAAI,SAAS,WAAW;AAExB,WAAO,WAAW,oBAAoB;AACtC,WAAO,OAAO,WAAW;AAEzB,QAAI,uBAAuB,YAAY,QAAQ,iCAAiC,UAAU,GAAG;AAC3F,uCAAiC,QAAQ,OAAO;AADlD,WAEO;AACL,UAAI,YAAY;AAEhB,UAAI,WAAW,kBAAkB,WAAW;AAC1C,YAAI,eAAe,WAAW;AAC9B,YAAI;AACF,sBAAY,aAAa;AAD3B,UAEE,OAAO,YAAY;AACnB,uDAA6C,YAAY;AACzD,gBAAM;AANkC;AAHvC;AAaL,UAAI;AACF,6BAAqB,YAAY,OAAO;AAD1C,QAEE,OAAO,UAAU;AACjB,qDAA6C,YAAY;AACzD,cAAM;AAjBH;AAR0D;AA6BjE,oDAAgD;AAEhD,WAAO;AAvrC6C;AA0rCtD,WAAS,qCAAqC,YAAY,GAAG;AAC3D,QAAI,SAAS,WAAW;AAExB,WAAO,OAAO,WAAW;AAEzB,eAAW;AAEX,wBAAoB,QAAQ;AAjsCwB;AAosCtD,WAAS,6CAA6C,YAAY,GAAG;AACnE,QAAI,WAAW,0BAA0B,WAAW,YAAY;AAC9D,2CAAqC,YAAY;AAFgB;AApsCf;AA0sCtD,WAAS,8CAA8C,YAAY;AACjE,QAAI,SAAS,WAAW;AACxB,QAAI,QAAQ,OAAO;AAEnB,QAAI,UAAU,WAAW;AACvB,aAAO;AALwD;AAOjE,QAAI,UAAU,UAAU;AACtB,aAAO;AARwD;AAWjE,WAAO,WAAW,eAAe,WAAW;AArtCQ;AAwtCtD,MAAI,wCAAwC;AAC1C,aAAS,0BAA0B,YAAY,MAAM;AACnD,sBAAgB,MAAM;AAEtB,WAAK,0CAA0C;AAC/C,WAAK,QAAQ;AAL2B;AAQ1C,iBAAa;AACX,WAAK;AACL,aAAO,SAAS,QAAQ,cAAc;AACpC,YAAI,4BAA4B,UAAU,OAAO;AAC/C,gBAAM,+BAA+B;AAFH;AAKpC,YAAI,KAAK,4CAA4C,WAAW;AAC9D,gBAAM,IAAI,UAAU;AANc;AASpC,4CAAoC,KAAK,yCAAyC;AAX7C;AAAA,KAAD;AActC,WAAK;AACL,aAAO,SAAS,mBAAmB,MAAM;AACvC,YAAI,4BAA4B,UAAU,OAAO;AAC/C,gBAAM,+BAA+B;AAFA;AAKvC,YAAI,KAAK,4CAA4C,WAAW;AAC9D,gBAAM,IAAI,UAAU;AANiB;AASvC,YAAI,CAAC,YAAY,OAAO,OAAO;AAC7B,gBAAM,IAAI,UAAU;AAViB;AAavC,uDAA+C,KAAK,yCAAyC;AAf9F;AAAA;AAkBD,WAAK;AACL,WAAK,SAAS,MAAM;AAClB,eAAO,KAAK;AAHb;AAAA;AAOH,WAAO;AA7CuB;AAgDhC,MAAI,2CAA2C;AAC7C,aAAS,6BAA6B,QAAQ,sBAAsB,eAAe;AACjF,sBAAgB,MAAM;AAEtB,UAAI,iBAAiB,YAAY,OAAO;AACtC,cAAM,IAAI,UAAU,+FAA+F;AAJpC;AAOjF,UAAI,OAAO,8BAA8B,WAAW;AAClD,cAAM,IAAI,UAAU,+GAA+G;AARpD;AAWjF,WAAK,4BAA4B;AAEjC,WAAK,wBAAwB;AAE7B,WAAK,aAAa;AAClB,WAAK,WAAW;AAEhB,wDAAkD;AAGlD,WAAK,SAAS,KAAK,kBAAkB;AACrC,iBAAW;AAEX,WAAK,kBAAkB;AACvB,WAAK,WAAW;AAEhB,WAAK,eAAe,kCAAkC;AAEtD,UAAI,wBAAwB,qBAAqB;AACjD,UAAI,0BAA0B,WAAW;AACvC,YAAI,OAAO,UAAU,2BAA2B,SAAS,yBAAyB,GAAG;AACnF,gBAAM,IAAI,WAAW;AAFgB;AA9BwC;AAmCjF,WAAK,yBAAyB;AAE9B,WAAK,oBAAoB;AAEzB,UAAI,aAAa;AAEjB,UAAI,cAAc,aAAa,sBAAsB,SAAS,CAAC;AAC/D,cAAQ,QAAQ,aAAa,KAAK,YAAY;AAC5C,mBAAW,WAAW;AAEtB,eAAO,WAAW,aAAa;AAC/B,eAAO,WAAW,eAAe;AAEjC,qDAA6C;AAN/C,SAOG,UAAU,GAAG;AACd,YAAI,OAAO,WAAW,YAAY;AAChC,4CAAkC,YAAY;AAFlC;AAPhB,SAWG,MAAM;AAtDkC;AAyD7C,iBAAa;AACX,WAAK;AACL,aAAO,SAAS,QAAQ;AACtB,YAAI,+BAA+B,UAAU,OAAO;AAClD,gBAAM,wCAAwC;AAF1B;AAKtB,YAAI,KAAK,oBAAoB,MAAM;AACjC,gBAAM,IAAI,UAAU;AANA;AAStB,YAAI,QAAQ,KAAK,0BAA0B;AAC3C,YAAI,UAAU,YAAY;AACxB,gBAAM,IAAI,UAAU,oBAAoB,QAAQ;AAX5B;AActB,0CAAkC;AAhBM;AAAA,KAAD;AAmBzC,WAAK;AACL,aAAO,SAAS,QAAQ,OAAO;AAC7B,YAAI,+BAA+B,UAAU,OAAO;AAClD,gBAAM,wCAAwC;AAFnB;AAK7B,YAAI,KAAK,oBAAoB,MAAM;AACjC,gBAAM,IAAI,UAAU;AANO;AAS7B,YAAI,QAAQ,KAAK,0BAA0B;AAC3C,YAAI,UAAU,YAAY;AACxB,gBAAM,IAAI,UAAU,oBAAoB,QAAQ;AAXrB;AAc7B,YAAI,CAAC,YAAY,OAAO,QAAQ;AAC9B,gBAAM,IAAI,UAAU;AAfO;AAkB7B,4CAAoC,MAAM;AApB3C;AAAA;AAuBD,WAAK;AACL,aAAO,SAAS,MAAM,GAAG;AACvB,YAAI,+BAA+B,UAAU,OAAO;AAClD,gBAAM,wCAAwC;AAFzB;AAKvB,YAAI,SAAS,KAAK;AAClB,YAAI,OAAO,WAAW,YAAY;AAChC,gBAAM,IAAI,UAAU,mBAAmB,OAAO,SAAS;AAPlC;AAUvB,0CAAkC,MAAM;AAZzC;AAAA;AAeD,WAAK;AACL,aAAO,SAAS,cAAc,QAAQ;AACpC,YAAI,KAAK,kBAAkB,SAAS,GAAG;AACrC,cAAI,kBAAkB,KAAK,kBAAkB;AAC7C,0BAAgB,cAAc;AAHI;AAMpC,mBAAW;AAEX,eAAO,oBAAoB,KAAK,uBAAuB,UAAU,CAAC;AAVnE;AAAA;AAaD,WAAK;AACL,aAAO,SAAS,cAAc;AAC5B,YAAI,SAAS,KAAK;AAClB,eAAO,+BAA+B,YAAY;AAElD,YAAI,KAAK,kBAAkB,GAAG;AAC5B,iBAAO,iCAAiC,YAAY;AAEpD,cAAI,QAAQ,KAAK,OAAO;AACxB,eAAK,mBAAmB,MAAM;AAE9B,uDAA6C;AAE7C,cAAI,OAAO,KAAK;AAChB,cAAI;AACF,mBAAO,IAAI,WAAW,MAAM,QAAQ,MAAM,YAAY,MAAM;AAD9D,YAEE,OAAO,OAAO;AACd,mBAAO,QAAQ,OAAO;AAZI;AAe5B,iBAAO,QAAQ,QAAQ,uBAAuB,MAAM;AAnB1B;AAsB5B,YAAI,wBAAwB,KAAK;AACjC,YAAI,0BAA0B,WAAW;AACvC,cAAI,SAAS,KAAK;AAClB,cAAI;AACF,qBAAS,IAAI,YAAY;AAD3B,YAEE,OAAO,SAAS;AAChB,mBAAO,QAAQ,OAAO;AALe;AAQvC,cAAI;AACF,oBAAQ;AACR,wBAAY;AACZ,wBAAY;AACZ,yBAAa;AACb,yBAAa;AACb,kBAAM;AACN,wBAAY;AAPW;AAUzB,eAAK,kBAAkB,KAAK;AAzCF;AA4C5B,YAAI,UAAU,6BAA6B;AAE3C,qDAA6C;AAE7C,eAAO;AAlDR;AAAA;AAqDD,WAAK;AACL,WAAK,SAAS,MAAM;AAClB,YAAI,+BAA+B,UAAU,OAAO;AAClD,gBAAM,wCAAwC;AAF9B;AAKlB,YAAI,KAAK,iBAAiB,aAAa,KAAK,kBAAkB,SAAS,GAAG;AACxE,cAAI,kBAAkB,KAAK,kBAAkB;AAC7C,cAAI,OAAO,IAAI,WAAW,gBAAgB,QAAQ,gBAAgB,aAAa,gBAAgB,aAAa,gBAAgB,aAAa,gBAAgB;AAEzJ,eAAK,eAAe,IAAI,0BAA0B,MAAM;AATxC;AAYlB,eAAO,KAAK;AAdb;AAAA;AAiBD,WAAK;AACL,WAAK,SAAS,MAAM;AAClB,YAAI,+BAA+B,UAAU,OAAO;AAClD,gBAAM,wCAAwC;AAF9B;AAKlB,eAAO,2CAA2C;AAPnD;AAAA;AAWH,WAAO;AA1M0B;AA+MnC,WAAS,+BAA+B,GAAG;AACzC,QAAI,CAAC,aAAa,IAAI;AACpB,aAAO;AAFgC;AAKzC,QAAI,CAAC,OAAO,UAAU,eAAe,KAAK,GAAG,0BAA0B;AACrE,aAAO;AANgC;AASzC,WAAO;AAh+C6C;AAm+CtD,WAAS,4BAA4B,GAAG;AACtC,QAAI,CAAC,aAAa,IAAI;AACpB,aAAO;AAF6B;AAKtC,QAAI,CAAC,OAAO,UAAU,eAAe,KAAK,GAAG,4CAA4C;AACvF,aAAO;AAN6B;AAStC,WAAO;AA5+C6C;AA++CtD,WAAS,6CAA6C,YAAY;AAChE,QAAI,aAAa,2CAA2C;AAC5D,QAAI,eAAe,OAAO;AACxB,aAAO;AAHuD;AAMhE,QAAI,WAAW,aAAa,MAAM;AAChC,iBAAW,aAAa;AACxB,aAAO;AARuD;AAWhE,WAAO,WAAW,eAAe;AAEjC,eAAW,WAAW;AAGtB,QAAI,cAAc,oBAAoB,WAAW,uBAAuB,QAAQ,CAAC;AACjF,gBAAY,KAAK,YAAY;AAC3B,iBAAW,WAAW;AAEtB,UAAI,WAAW,eAAe,MAAM;AAClC,mBAAW,aAAa;AACxB,qDAA6C;AALpB;AAA7B,OAOG,UAAU,GAAG;AACd,UAAI,WAAW,0BAA0B,WAAW,YAAY;AAC9D,0CAAkC,YAAY;AAFlC;AAPhB,OAWG,MAAM;AAET,WAAO;AA7gD6C;AAghDtD,WAAS,kDAAkD,YAAY;AACrE,sDAAkD;AAClD,eAAW,oBAAoB;AAlhDqB;AAqhDtD,WAAS,qDAAqD,QAAQ,oBAAoB;AACxF,WAAO,OAAO,WAAW,WAAW;AAEpC,QAAI,OAAO;AACX,QAAI,OAAO,WAAW,UAAU;AAC9B,aAAO,mBAAmB,gBAAgB;AAC1C,aAAO;AAN+E;AASxF,QAAI,aAAa,sDAAsD;AACvE,QAAI,mBAAmB,eAAe,WAAW;AAC/C,uCAAiC,QAAQ,YAAY;AADvD,WAEO;AACL,aAAO,mBAAmB,eAAe;AACzC,2CAAqC,QAAQ,YAAY;AAd6B;AArhDpC;AAuiDtD,WAAS,sDAAsD,oBAAoB;AACjF,QAAI,cAAc,mBAAmB;AACrC,QAAI,cAAc,mBAAmB;AAErC,WAAO,eAAe,mBAAmB;AACzC,WAAO,cAAc,gBAAgB;AAErC,WAAO,IAAI,mBAAmB,KAAK,mBAAmB,QAAQ,mBAAmB,YAAY,cAAc;AA9iDvD;AAijDtD,WAAS,gDAAgD,YAAY,QAAQ,YAAY,YAAY;AACnG,eAAW,OAAO;AAAO,cAAQ;AAAQ,kBAAY;AAAY,kBAAY;AAAtD;AACvB,eAAW,mBAAmB;AAnjDsB;AAsjDtD,WAAS,4DAA4D,YAAY,oBAAoB;AACnG,QAAI,cAAc,mBAAmB;AAErC,QAAI,sBAAsB,mBAAmB,cAAc,mBAAmB,cAAc;AAE5F,QAAI,iBAAiB,KAAK,IAAI,WAAW,iBAAiB,mBAAmB,aAAa,mBAAmB;AAC7G,QAAI,iBAAiB,mBAAmB,cAAc;AACtD,QAAI,kBAAkB,iBAAiB,iBAAiB;AAExD,QAAI,4BAA4B;AAChC,QAAI,QAAQ;AACZ,QAAI,kBAAkB,qBAAqB;AACzC,kCAA4B,kBAAkB,mBAAmB;AACjE,cAAQ;AAbyF;AAgBnG,QAAI,QAAQ,WAAW;AAEvB,WAAO,4BAA4B,GAAG;AACpC,UAAI,cAAc,MAAM;AAExB,UAAI,cAAc,KAAK,IAAI,2BAA2B,YAAY;AAElE,UAAI,YAAY,mBAAmB,aAAa,mBAAmB;AACnE,sBAAgB,mBAAmB,QAAQ,WAAW,YAAY,QAAQ,YAAY,YAAY;AAElG,UAAI,YAAY,eAAe,aAAa;AAC1C,cAAM;AADR,aAEO;AACL,oBAAY,cAAc;AAC1B,oBAAY,cAAc;AAZQ;AAcpC,iBAAW,mBAAmB;AAE9B,6DAAuD,YAAY,aAAa;AAEhF,mCAA6B;AApCoE;AAuCnG,QAAI,UAAU,OAAO;AACnB,aAAO,WAAW,oBAAoB,GAAG;AACzC,aAAO,mBAAmB,cAAc;AACxC,aAAO,mBAAmB,cAAc,mBAAmB;AA1CsC;AA6CnG,WAAO;AAnmD6C;AAsmDtD,WAAS,uDAAuD,YAAY,MAAM,oBAAoB;AACpG,WAAO,WAAW,kBAAkB,WAAW,KAAK,WAAW,kBAAkB,OAAO;AAExF,sDAAkD;AAClD,uBAAmB,eAAe;AA1mDkB;AA6mDtD,WAAS,6CAA6C,YAAY;AAChE,WAAO,WAAW,0BAA0B,WAAW;AAEvD,QAAI,WAAW,oBAAoB,KAAK,WAAW,oBAAoB,MAAM;AAC3E,0BAAoB,WAAW;AADjC,WAEO;AACL,mDAA6C;AANiB;AA7mDZ;AAunDtD,WAAS,kDAAkD,YAAY;AACrE,QAAI,WAAW,iBAAiB,WAAW;AACzC;AAFmE;AAKrE,eAAW,aAAa,0CAA0C;AAClE,eAAW,aAAa,QAAQ;AAChC,eAAW,eAAe;AA9nD0B;AAioDtD,WAAS,iEAAiE,YAAY;AACpF,WAAO,WAAW,oBAAoB;AAEtC,WAAO,WAAW,kBAAkB,SAAS,GAAG;AAC9C,UAAI,WAAW,oBAAoB,GAAG;AACpC;AAF4C;AAK9C,UAAI,qBAAqB,WAAW,kBAAkB;AAEtD,UAAI,4DAA4D,YAAY,wBAAwB,MAAM;AACxG,yDAAiD;AAEjD,6DAAqD,WAAW,2BAA2B;AAV/C;AAHoC;AAjoDhC;AAmpDtD,WAAS,qCAAqC,YAAY,MAAM;AAC9D,QAAI,SAAS,WAAW;AAExB,QAAI,cAAc;AAClB,QAAI,KAAK,gBAAgB,UAAU;AACjC,oBAAc,KAAK,YAAY;AAL6B;AAQ9D,QAAI,OAAO,KAAK;AAEhB,QAAI;AACF,cAAQ,KAAK;AACb,kBAAY,KAAK;AACjB,kBAAY,KAAK;AACjB,mBAAa;AACb,mBAAa;AACb,YAAM;AACN,kBAAY;AAPW;AAUzB,QAAI,WAAW,kBAAkB,SAAS,GAAG;AAC3C,yBAAmB,SAAS,oBAAoB,mBAAmB;AACnE,iBAAW,kBAAkB,KAAK;AAMlC,aAAO,iCAAiC;AA5BoB;AA+B9D,QAAI,OAAO,WAAW,UAAU;AAC9B,UAAI,YAAY,IAAI,KAAK,YAAY,mBAAmB,QAAQ,mBAAmB,YAAY;AAC/F,aAAO,QAAQ,QAAQ,uBAAuB,WAAW;AAjCG;AAoC9D,QAAI,WAAW,kBAAkB,GAAG;AAClC,UAAI,4DAA4D,YAAY,wBAAwB,MAAM;AACxG,YAAI,aAAa,sDAAsD;AAEvE,qDAA6C;AAE7C,eAAO,QAAQ,QAAQ,uBAAuB,YAAY;AAN1B;AASlC,UAAI,WAAW,oBAAoB,MAAM;AACvC,YAAI,IAAI,IAAI,UAAU;AACtB,0CAAkC,YAAY;AAE9C,eAAO,QAAQ,OAAO;AAbU;AApC0B;AAqD9D,uBAAmB,SAAS,oBAAoB,mBAAmB;AACnE,eAAW,kBAAkB,KAAK;AAElC,QAAI,UAAU,iCAAiC;AAE/C,iDAA6C;AAE7C,WAAO;AA/sD6C;AAktDtD,WAAS,iDAAiD,YAAY,iBAAiB;AACrF,oBAAgB,SAAS,oBAAoB,gBAAgB;AAE7D,WAAO,gBAAgB,gBAAgB,GAAG;AAE1C,QAAI,SAAS,WAAW;AACxB,QAAI,4BAA4B,YAAY,MAAM;AAChD,aAAO,qCAAqC,UAAU,GAAG;AACvD,YAAI,qBAAqB,iDAAiD;AAC1E,6DAAqD,QAAQ;AAHf;AANmC;AAltDjC;AAguDtD,WAAS,mDAAmD,YAAY,cAAc,oBAAoB;AACxG,QAAI,mBAAmB,cAAc,eAAe,mBAAmB,YAAY;AACjF,YAAM,IAAI,WAAW;AAFiF;AAKxG,2DAAuD,YAAY,cAAc;AAEjF,QAAI,mBAAmB,cAAc,mBAAmB,aAAa;AAEnE;AATsG;AAYxG,qDAAiD;AAEjD,QAAI,gBAAgB,mBAAmB,cAAc,mBAAmB;AACxE,QAAI,gBAAgB,GAAG;AACrB,UAAI,MAAM,mBAAmB,aAAa,mBAAmB;AAC7D,UAAI,YAAY,mBAAmB,OAAO,MAAM,MAAM,eAAe;AACrE,sDAAgD,YAAY,WAAW,GAAG,UAAU;AAlBkB;AAqBxG,uBAAmB,SAAS,oBAAoB,mBAAmB;AACnE,uBAAmB,eAAe;AAClC,yDAAqD,WAAW,2BAA2B;AAE3F,qEAAiE;AAzvDb;AA4vDtD,WAAS,4CAA4C,YAAY,cAAc;AAC7E,QAAI,kBAAkB,WAAW,kBAAkB;AAEnD,QAAI,SAAS,WAAW;AAExB,QAAI,OAAO,WAAW,UAAU;AAC9B,UAAI,iBAAiB,GAAG;AACtB,cAAM,IAAI,UAAU;AAFQ;AAK9B,uDAAiD,YAAY;AAL/D,WAMO;AACL,aAAO,OAAO,WAAW;AAEzB,yDAAmD,YAAY,cAAc;AAdF;AA5vDzB;AA8wDtD,WAAS,iDAAiD,YAAY;AACpE,QAAI,aAAa,WAAW,kBAAkB;AAC9C,sDAAkD;AAClD,WAAO;AAjxD6C;AAoxDtD,WAAS,2CAA2C,YAAY;AAC9D,QAAI,SAAS,WAAW;AAExB,QAAI,OAAO,WAAW,YAAY;AAChC,aAAO;AAJqD;AAO9D,QAAI,WAAW,oBAAoB,MAAM;AACvC,aAAO;AARqD;AAW9D,QAAI,WAAW,aAAa,OAAO;AACjC,aAAO;AAZqD;AAe9D,QAAI,+BAA+B,YAAY,QAAQ,iCAAiC,UAAU,GAAG;AACnG,aAAO;AAhBqD;AAmB9D,QAAI,4BAA4B,YAAY,QAAQ,qCAAqC,UAAU,GAAG;AACpG,aAAO;AApBqD;AAuB9D,QAAI,2CAA2C,cAAc,GAAG;AAC9D,aAAO;AAxBqD;AA2B9D,WAAO;AA/yD6C;AAozDtD,WAAS,kCAAkC,YAAY;AACrD,QAAI,SAAS,WAAW;AAExB,WAAO,WAAW,oBAAoB;AACtC,WAAO,OAAO,WAAW;AAEzB,QAAI,WAAW,kBAAkB,GAAG;AAClC,iBAAW,kBAAkB;AAE7B;AATmD;AAYrD,QAAI,WAAW,kBAAkB,SAAS,GAAG;AAC3C,UAAI,uBAAuB,WAAW,kBAAkB;AACxD,UAAI,qBAAqB,cAAc,GAAG;AACxC,YAAI,IAAI,IAAI,UAAU;AACtB,0CAAkC,YAAY;AAE9C,cAAM;AANmC;AAZQ;AAsBrD,wBAAoB;AA10DgC;AA60DtD,WAAS,oCAAoC,YAAY,OAAO;AAC9D,QAAI,SAAS,WAAW;AAExB,WAAO,WAAW,oBAAoB;AACtC,WAAO,OAAO,WAAW;AAEzB,QAAI,SAAS,MAAM;AACnB,QAAI,aAAa,MAAM;AACvB,QAAI,aAAa,MAAM;AACvB,QAAI,oBAAoB,oBAAoB;AAE5C,QAAI,+BAA+B,YAAY,MAAM;AACnD,UAAI,iCAAiC,YAAY,GAAG;AAClD,wDAAgD,YAAY,mBAAmB,YAAY;AAD7F,aAEO;AACL,eAAO,WAAW,OAAO,WAAW;AAEpC,YAAI,kBAAkB,IAAI,WAAW,mBAAmB,YAAY;AACpE,yCAAiC,QAAQ,iBAAiB;AAPT;AAArD,eASW,4BAA4B,YAAY,MAAM;AAEvD,sDAAgD,YAAY,mBAAmB,YAAY;AAC3F,uEAAiE;AAH5D,WAIA;AACL,aAAO,uBAAuB,YAAY,OAAO;AACjD,sDAAgD,YAAY,mBAAmB,YAAY;AA1B/B;AA70DV;AA22DtD,WAAS,kCAAkC,YAAY,GAAG;AACxD,QAAI,SAAS,WAAW;AAExB,WAAO,OAAO,WAAW;AAEzB,sDAAkD;AAElD,eAAW;AACX,wBAAoB,QAAQ;AAn3DwB;AAs3DtD,WAAS,2CAA2C,YAAY;AAC9D,QAAI,SAAS,WAAW;AACxB,QAAI,QAAQ,OAAO;AAEnB,QAAI,UAAU,WAAW;AACvB,aAAO;AALqD;AAO9D,QAAI,UAAU,UAAU;AACtB,aAAO;AARqD;AAW9D,WAAO,WAAW,eAAe,WAAW;AAj4DQ;AAo4DtD,WAAS,oCAAoC,YAAY,cAAc;AACrE,mBAAe,OAAO;AACtB,QAAI,0BAA0B,kBAAkB,OAAO;AACrD,YAAM,IAAI,WAAW;AAH8C;AAMrE,WAAO,WAAW,kBAAkB,SAAS;AAE7C,gDAA4C,YAAY;AA54DJ;AA+4DtD,WAAS,+CAA+C,YAAY,MAAM;AACxE,WAAO,WAAW,kBAAkB,SAAS;AAE7C,QAAI,kBAAkB,WAAW,kBAAkB;AAEnD,QAAI,gBAAgB,aAAa,gBAAgB,gBAAgB,KAAK,YAAY;AAChF,YAAM,IAAI,WAAW;AANiD;AAQxE,QAAI,gBAAgB,eAAe,KAAK,YAAY;AAClD,YAAM,IAAI,WAAW;AATiD;AAYxE,oBAAgB,SAAS,KAAK;AAE9B,gDAA4C,YAAY,KAAK;AA75DT;AAk6DtD,WAAS,0BAA0B,MAAM;AACvC,WAAO,IAAI,UAAU,8BAA8B,OAAO;AAn6DN;AAw6DtD,WAAS,oBAAoB,MAAM;AACjC,WAAO,IAAI,UAAU,YAAY,OAAO;AAz6DY;AA86DtD,WAAS,iCAAiC,MAAM;AAC9C,WAAO,IAAI,UAAU,2CAA2C,OAAO;AA/6DnB;AAk7DtD,WAAS,qCAAqC,QAAQ;AACpD,WAAO,qBAAqB,QAAQ,UAAU,SAAS,QAAQ;AAC7D,aAAO,yBAAyB;AAChC,aAAO,wBAAwB;AAFT;AAn7D4B;AAy7DtD,WAAS,+CAA+C,QAAQ,QAAQ;AACtE,WAAO,iBAAiB,QAAQ,OAAO;AACvC,WAAO,yBAAyB;AAChC,WAAO,wBAAwB;AA57DqB;AA+7DtD,WAAS,+CAA+C,QAAQ;AAC9D,WAAO,iBAAiB,QAAQ,QAAQ;AACxC,WAAO,yBAAyB;AAChC,WAAO,wBAAwB;AAl8DqB;AAq8DtD,WAAS,iCAAiC,QAAQ,QAAQ;AACxD,WAAO,OAAO,2BAA2B;AACzC,WAAO,OAAO,0BAA0B;AAExC,WAAO,sBAAsB;AAC7B,WAAO,yBAAyB;AAChC,WAAO,wBAAwB;AA38DqB;AA88DtD,WAAS,0CAA0C,QAAQ,QAAQ;AACjE,WAAO,OAAO,2BAA2B;AACzC,WAAO,OAAO,0BAA0B;AAExC,WAAO,iBAAiB,QAAQ,OAAO;AAl9Da;AAq9DtD,WAAS,kCAAkC,QAAQ;AACjD,WAAO,OAAO,2BAA2B;AACzC,WAAO,OAAO,0BAA0B;AAExC,WAAO,uBAAuB;AAC9B,WAAO,yBAAyB;AAChC,WAAO,wBAAwB;AA39DqB;AAg+DtD,WAAS,8BAA8B,MAAM;AAC3C,WAAO,IAAI,UAAU,wCAAwC,OAAO;AAj+DhB;AAs+DtD,WAAS,qCAAqC,MAAM;AAClD,WAAO,IAAI,UAAU,+CAA+C,OAAO;AAv+DvB;AA4+DtD,WAAS,+BAA+B,MAAM;AAC5C,WAAO,IAAI,UAAU,yCAAyC,OAAO;AA7+DjB;AAk/DtD,WAAS,wCAAwC,MAAM;AACrD,WAAO,IAAI,UAAU,4CAA4C,OAAO;AAn/DpB;AAw/DtD,WAAS,uEAAuE,SAAS;AACvF,QAAI;AAGF,cAAQ,UAAU,KAAK,KAAK,SAAS,WAAW,YAAY,CAA5D;AAHF,MAIE,OAAO,GAAG,CAL2E;AAx/DnC;AA/wC5C,GAmxGH,UAAS,QAAQ,SAAS,qBAAqB;AAEtD;;AAGA,MAAI,kBAAkB,oBAAoB;AAC1C,MAAI,iBAAiB,oBAAoB;AACzC,MAAI,iBAAiB,oBAAoB;AAEzC,UAAQ,kBAAkB,gBAAgB;AAC1C,UAAQ,iBAAiB,eAAe;AACxC,UAAQ,4BAA4B,eAAe;AACnD,UAAQ,uCAAuC,eAAe;AAC9D,UAAQ,yCAAyC,eAAe;AAChE,UAAQ,uCAAuC,eAAe;AAC9D,UAAQ,gDAAgD,eAAe;AACvE,UAAQ,qCAAqC,eAAe;AAC5D,UAAQ,mBAAmB,eAAe;AAC1C,UAAQ,yBAAyB,eAAe;AAChD,UAAQ,iBAAiB,eAAe;AACxC,UAAQ,sBAAsB,eAAe;AAC7C,UAAQ,uCAAuC,eAAe;AAC9D,UAAQ,uDAAuD,eAAe;AAC9E,UAAQ,qCAAqC,eAAe;AAC5D,UAAQ,mCAAmC,eAAe;AA3yGhD,GA+yGH,UAAS,QAAQ,SAAS,qBAAqB;AAEtD;;AAGA,MAAI,2BAA2B;AAAE,aAAS,iBAAiB,QAAQ,OAAO;AAAE,WAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AAAE,YAAI,aAAa,MAAM;AAAI,mBAAW,aAAa,WAAW,cAAc;AAAO,mBAAW,eAAe;AAAM,YAAI,WAAW,YAAY,WAAW,WAAW;AAAM,eAAO,eAAe,QAAQ,WAAW,KAAK;AAAnQ;AAA3C;AAA+T,WAAO,UAAU,aAAa,YAAY,aAAa;AAAE,UAAI,YAAY,iBAAiB,YAAY,WAAW;AAAa,UAAI,aAAa,iBAAiB,aAAa;AAAc,aAAO;AAAlM;AAA3U;AAEnB,WAAS,gBAAgB,UAAU,aAAa;AAAE,QAAM,sBAAoB,cAAc;AAAE,YAAM,IAAI,UAAU;AAAhE;AAPM;AAStD,MAAI,WAAW,oBAAoB;MAC/B,SAAS,SAAS;AAEtB,MAAI,YAAY,oBAAoB;MAChC,eAAe,UAAU;MACzB,iCAAiC,UAAU;MAC3C,sBAAsB,UAAU;MAChC,eAAe,UAAU;AAE7B,MAAI,YAAY,oBAAoB;MAChC,iBAAiB,UAAU;MAC3B,uCAAuC,UAAU;MACjD,yCAAyC,UAAU;MACnD,uCAAuC,UAAU;MACjD,gDAAgD,UAAU;AAE9D,MAAI,YAAY,oBAAoB;MAChC,iBAAiB,UAAU;MAC3B,uCAAuC,UAAU;AAIrD,WAAS,6BAA6B,iBAAiB;AAGrD,QAAI,gBAAgB,aAAa,MAAM;AACrC,YAAM,IAAI,UAAU;AAJ+B;AAOrD,QAAI,gBAAgB,oBAAoB,MAAM;AAC5C,YAAM,IAAI,UAAU;AAR+B;AAWrD,yCAAqC;AA1Ce;AA6CtD,WAAS,iCAAiC,iBAAiB,OAAO;AAGhE,QAAI,gBAAgB,aAAa,MAAM;AACrC,YAAM,IAAI,UAAU;AAJ0C;AAOhE,QAAI,gBAAgB,oBAAoB,MAAM;AAC5C,YAAM,IAAI,UAAU;AAR0C;AAchE,QAAI,aAAa,gBAAgB;AAEjC,QAAI;AACF,6CAAuC,YAAY;AADrD,MAEE,OAAO,GAAG;AAGV,sBAAgB,kBAAkB;AAClC,mCAA6B,iBAAiB;AAE9C,YAAM,gBAAgB;AAxBwC;AA2BhE,QAAI,cAAc,8CAA8C;AAChE,QAAI,oBAAoB,eAAe;AAEvC,QAAI,sBAAsB,QAAQ,gBAAgB,kBAAkB,OAAO;AAMzE,qCAA+B,iBAAiB;AApCc;AA7CZ;AAqFtD,WAAS,qBAAqB,iBAAiB,GAAG;AAChD,QAAI,gBAAgB,aAAa,MAAM;AACrC,YAAM,IAAI,UAAU;AAF0B;AAKhD,iCAA6B,iBAAiB;AA1FM;AA+FtD,WAAS,qCAAqC,iBAAiB;AAC7D,WAAO,gBAAgB,aAAa;AACpC,WAAO,gBAAgB,oBAAoB;AAE3C,QAAI;AACF,2CAAqC,gBAAgB;AADvD,MAEE,OAAO,GAAG;AACV,aAAO;AAPoD;AAU7D,oBAAgB,kBAAkB;AAzGkB;AA4GtD,WAAS,6BAA6B,iBAAiB,GAAG;AACxD,QAAI,gBAAgB,aAAa,OAAO;AACtC,mCAA6B,iBAAiB;AAFQ;AA5GJ;AAkHtD,WAAS,6BAA6B,iBAAiB,GAAG;AAGxD,WAAO,gBAAgB,aAAa;AAEpC,oBAAgB,WAAW;AAC3B,oBAAgB,eAAe;AAE/B,QAAI,gBAAgB,kBAAkB,OAAO;AAC3C,2CAAqC,gBAAgB,qBAAqB;AATpB;AAWxD,QAAI,gBAAgB,oBAAoB,OAAO;AAC7C,2CAAqC,gBAAgB,qBAAqB;AAZpB;AAlHJ;AAoItD,WAAS,oCAAoC,iBAAiB;AAC5D,WAAO,gBAAgB,+BAA+B,WAAW;AAEjE,QAAI,gBAAgB,kBAAkB,OAAO;AAC3C,aAAO,QAAQ;AAJ2C;AAO5D,WAAO,gBAAgB,kBAAkB,MAAM;AAE/C,WAAO,gBAAgB;AA7I6B;AAgJtD,WAAS,+BAA+B,iBAAiB,cAAc;AAIrE,WAAO,gBAAgB,kBAAkB,cAAc;AAEvD,QAAI,gBAAgB,+BAA+B,WAAW;AAE5D,sBAAgB,mCAAmC;AARgB;AAWrE,oBAAgB,iCAAiC,QAAQ,UAAU,SAAS;AAC1E,sBAAgB,qCAAqC;AADV;AAI7C,oBAAgB,2BAA2B,KAAK,UAAU,YAAY;AACpE,aAAO,eAAe,cAAc;AADtC;AAIA,oBAAgB,gBAAgB;AAnKoB;AAsKtD,WAAS,gCAAgC,OAAO,2BAA2B;AACzE,QAAI,kBAAkB,0BAA0B;AAChD,qCAAiC,iBAAiB;AAClD,WAAO,QAAQ;AAzKqC;AA4KtD,WAAS,yBAAyB,iBAAiB,OAAO;AAGxD,WAAO,gBAAgB,aAAa;AACpC,WAAO,gBAAgB,kBAAkB;AACzC,WAAO,gBAAgB,kBAAkB;AAEzC,oBAAgB,gBAAgB;AAEhC,QAAI,cAAc,gBAAgB;AAClC,QAAI,aAAa,gBAAgB;AAEjC,QAAI,mBAAmB,+BAA+B,aAAa,aAAa,CAAC,OAAO,aAAa,iCAAiC,CAAC,OAAO;AAE9I,4BAAwB,KAAK,YAAY;AACvC,sBAAgB,gBAAgB;AAEhC,aAAO,oCAAoC;AAHtC,OAIJ,UAAU,GAAG;AACd,mCAA6B,iBAAiB;AAC9C,aAAO,QAAQ,OAAO;AANjB;AA1L6C;AAoMtD,WAAS,mCAAmC,GAAG;AAC7C,QAAI,CAAC,aAAa,IAAI;AACpB,aAAO;AAFoC;AAK7C,QAAI,CAAC,OAAO,UAAU,eAAe,KAAK,GAAG,+BAA+B;AAC1E,aAAO;AANoC;AAS7C,WAAO;AA7M6C;AAgNtD,WAAS,kBAAkB,GAAG;AAC5B,QAAI,CAAC,aAAa,IAAI;AACpB,aAAO;AAFmB;AAK5B,QAAI,CAAC,OAAO,UAAU,eAAe,KAAK,GAAG,+BAA+B;AAC1E,aAAO;AANmB;AAS5B,WAAO;AAzN6C;AA4NtD,MAAI,kCAAkC;AACpC,aAAS,oBAAoB,iBAAiB,cAAc;AAC1D,sBAAgB,MAAM;AAEtB,WAAK,mBAAmB;AACxB,WAAK,gBAAgB;AALa;AAQpC,iBAAa;AACX,WAAK;AACL,aAAO,SAAS,MAAM,GAAG;AACvB,YAAI,kBAAkB,KAAK;AAE3B,wBAAgB,sBAAsB;AAEtC,oBAAY,cAAc,KAAK,YAAY;AACzC,iBAAO,oCAAoC;AADtC;AAPwB;AAAA,KAAD;AAYhC,WAAK;AACL,aAAO,SAAS,MAAM,OAAO;AAG3B,YAAI,kBAAkB,KAAK;AAE3B,eAAO,yBAAyB,iBAAiB;AAPlD;AAAA;AAUD,WAAK;AACL,aAAO,SAAS,QAAQ;AACtB,YAAI,kBAAkB,KAAK;AAC3B,wBAAgB,gBAAgB;AAChC,qCAA6B,iBAAiB,IAAI,UAAU;AAL7D;AAAA;AAQD,WAAK;AACL,aAAO,SAAS,QAAQ;AAGtB,YAAI,kBAAkB,KAAK;AAE3B,eAAO,gBAAgB,kBAAkB;AAEzC,wBAAgB,gBAAgB;AAEhC,YAAI,eAAe,oBAAoB,gBAAgB,cAAc,SAAS,CAAC,gBAAgB;AAE/F,4BAAoB,KAAK,YAAY;AACnC,cAAI,gBAAgB,aAAa,MAAM;AACrC,mBAAO,QAAQ,OAAO,gBAAgB;AAFL;AAInC,cAAI,gBAAgB,oBAAoB,OAAO;AAC7C,iDAAqC;AALJ;AAOnC,iBAAO,QAAQ;AAPV,WAQJ,MAAM,UAAU,GAAG;AACpB,uCAA6B,iBAAiB;AAC9C,iBAAO,QAAQ,OAAO,gBAAgB;AAVjC;AAbR;AAAA;AA4BH,WAAO;AA/DiB;AAkE1B,MAAI,oCAAoC;AACtC,aAAS,sBAAsB,iBAAiB,cAAc;AAC5D,sBAAgB,MAAM;AAEtB,WAAK,mBAAmB;AACxB,WAAK,gBAAgB;AALe;AAQtC,iBAAa;AACX,WAAK;AACL,aAAO,SAAS,MAAM,GAAG;AACvB,YAAI,kBAAkB,KAAK;AAE3B,wBAAgB,sBAAsB;AAEtC,oBAAY,cAAc,KAAK,YAAY;AAGzC,iBAAO,gBAAgB,+BAA+B,WAAW;AAEjE,cAAI,gBAAgB,kBAAkB,MAAM;AAC1C,mBAAO,QAAQ;AANwB;AASzC,iBAAO,gBAAgB,kBAAkB,OAAO;AAEhD,iBAAO,gBAAgB;AAXlB;AAP0B;AAAA,KAAD;AAsBlC,WAAK;AACL,aAAO,SAAS,OAAO;AAGrB,YAAI,kBAAkB,KAAK;AAG3B,eAAO,gBAAgB,kBAAkB,MAAM;AAE/C,eAAO,gBAAgB,+BAA+B,WAAW;AAEjE,uCAA+B,iBAAiB;AAGhD,eAAO,gBAAgB;AAfxB;AAAA;AAkBD,WAAK;AACL,aAAO,SAAS,SAAS;AACvB,YAAI,kBAAkB,KAAK;AAC3B,wBAAgB,kBAAkB;AAClC,qCAA6B,iBAAiB,IAAI,UAAU;AAL7D;AAAA;AASH,WAAO;AAvDmB;AA0D5B,MAAI,+CAA+C;AACjD,aAAS,iCAAiC,iBAAiB;AACzD,sBAAgB,MAAM;AAEtB,UAAI,kBAAkB,qBAAqB,OAAO;AAChD,cAAM,IAAI,UAAU,kDAAkD;AAJf;AAOzD,UAAI,gBAAgB,+BAA+B,WAAW;AAC5D,cAAM,IAAI,UAAU,oDAAoD;AARjB;AAWzD,WAAK,6BAA6B;AAZa;AAejD,iBAAa;AACX,WAAK;AACL,aAAO,SAAS,QAAQ,OAAO;AAC7B,YAAI,mCAAmC,UAAU,OAAO;AACtD,gBAAM,qCAAqC;AAFhB;AAK7B,yCAAiC,KAAK,4BAA4B;AAPtB;AAAA,KAAD;AAU7C,WAAK;AACL,aAAO,SAAS,QAAQ;AACtB,YAAI,mCAAmC,UAAU,OAAO;AACtD,gBAAM,qCAAqC;AAFvB;AAKtB,qCAA6B,KAAK;AAPnC;AAAA;AAUD,WAAK;AACL,aAAO,SAAS,MAAM,QAAQ;AAC5B,YAAI,mCAAmC,UAAU,OAAO;AACtD,gBAAM,qCAAqC;AAFjB;AAK5B,6BAAqB,KAAK,4BAA4B;AAPvD;AAAA;AAUD,WAAK;AACL,WAAK,SAAS,MAAM;AAClB,YAAI,mCAAmC,UAAU,OAAO;AACtD,gBAAM,qCAAqC;AAF3B;AAKlB,YAAI,kBAAkB,KAAK;AAC3B,YAAI,qBAAqB,gBAAgB;AAEzC,eAAO,8CAA8C;AAVtD;AAAA;AAcH,WAAO;AAxD8B;AA2DvC,MAAI,8BAA8B;AAChC,aAAS,kBAAkB;AACzB,UAAI,cAAc,UAAU,SAAS,KAAK,UAAU,OAAO,YAAY,UAAU,KAAK;AAEtF,sBAAgB,MAAM;AAEtB,WAAK,eAAe;AACpB,UAAI,mBAAmB,YAAY;UAC/B,mBAAmB,YAAY;AAGnC,WAAK,gBAAgB;AACrB,WAAK,WAAW;AAChB,WAAK,eAAe;AAEpB,WAAK,sBAAsB;AAC3B,WAAK,sBAAsB;AAC3B,WAAK,6BAA6B;AAElC,WAAK,gBAAgB;AACrB,WAAK,kBAAkB;AAEvB,WAAK,gBAAgB;AACrB,WAAK,6BAA6B;AAClC,WAAK,qCAAqC;AAE1C,WAAK,6BAA6B,IAAI,iCAAiC;AAEvE,UAAI,uBAAuB,KAAK;AAChC,UAAI,mBAAmB,QAAQ,UAAU,SAAS;AAChD,+BAAuB;AADN;AAInB,UAAI,SAAS,IAAI,sBAAsB,MAAM;AAE7C,WAAK,YAAY,IAAI,eAAe,QAAQ;AAE5C,UAAI,OAAO,IAAI,oBAAoB,MAAM;AAEzC,WAAK,YAAY,IAAI,eAAe,MAAM;AAE1C,aAAO,KAAK,wBAAwB;AACpC,aAAO,KAAK,wBAAwB;AAEpC,UAAI,cAAc,8CAA8C,KAAK;AAGrE,qCAA+B,MAAM,eAAe;AAEpD,UAAI,kBAAkB;AACtB,UAAI,cAAc,aAAa,aAAa,SAAS,CAAC,gBAAgB;AACtE,2BAAqB;AACrB,mBAAa,MAAM,UAAU,GAAG;AAE9B,YAAI,gBAAgB,aAAa,OAAO;AACtC,0BAAgB,WAAW;AAC3B,0BAAgB,eAAe;AAJH;AAAhC;AApD8B;AA6DhC,iBAAa;AACX,WAAK;AACL,WAAK,SAAS,MAAM;AAClB,YAAI,kBAAkB,UAAU,OAAO;AACrC,gBAAM,0BAA0B;AAFhB;AAKlB,eAAO,KAAK;AAPe;AAAA,KAAD;AAU5B,WAAK;AACL,WAAK,SAAS,MAAM;AAClB,YAAI,kBAAkB,UAAU,OAAO;AACrC,gBAAM,0BAA0B;AAFhB;AAKlB,eAAO,KAAK;AAPb;AAAA;AAWH,WAAO;AAjFa;AAoFtB,SAAO,UAAU,EAAE,iBAAiB;AAIpC,WAAS,qCAAqC,MAAM;AAClD,WAAO,IAAI,UAAU,gDAAgD,OAAO;AA5exB;AAiftD,WAAS,0BAA0B,MAAM;AACvC,WAAO,IAAI,UAAU,+BAA+B,OAAO;AAlfP;AA/yG5C,GAsyHH,UAAS,QAAQ,SAAS,qBAAqB;AAEtD,SAAO,UAAU,oBAAoB;AAxyH3B,IApEV,C;;;;;;;;;;;;;;ACSO;;AACgD;;AAC5B;;AAM3B,IAAI,gBAAgB;AAEpB,IAAI,gBAAgB;AACpB,IAAI,iBAAiB;AAGrB,IAAI,mBAAmB;AAEvB,IAAI,uBAAuB;AAC3B,IAAI,sBAAsB;AAE1B,IAAI,oBAAoB;AAExB,IAAI;AACF,MAAI,QAAQ;AACV,WAAO,kBAAO,sBAAsB,SAAS;AAFtB;AAAA;AAM3B,SAAS,2BAA2B,KAAK;AAEvC,MAAI,CAAC,IAAI,qBAAqB;AAC5B,QAAI,gBAAgB,IAAI;AACxB,QAAI,mBAAmB,IAAI;AAC3B,QAAI,kBAAkB,IAAI;AAC1B,QAAI,iBAAiB,IAAI;AACzB,QAAI,qBAAqB,IAAI;AAC7B,QAAI,qBAAqB,IAAI;AAC7B,QAAI,wBAAwB,IAAI;AAEhC,QAAI,mBAAmB,IAAI,oBAAoB,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG;AAC/D,QAAI,kBAAkB;AAEtB,WAAO,eAAe,KAAK;AACzB,WAAK,SAAS,sBAAsB;AAClC,eAAO,KAAK;AAFkC;AAAA;AAMlD,WAAO,eAAe,KAAK;AACzB,WAAK,SAAS,6BAA6B;AAKzC,YAAI,IAAI,KAAK;AACb,YAAI,IAAI,EAAE;YAAI,IAAI,EAAE;YAAI,IAAI,EAAE;YAAI,IAAI,EAAE;YAAI,IAAI,EAAE;YAAI,IAAI,EAAE;AAE5D,YAAI,QAAQ,IAAI,IAAI,IAAI;AACxB,YAAI,QAAQ,IAAI,IAAI,IAAI;AAExB,eAAO,CACL,IAAI,OACJ,IAAI,OACJ,IAAI,OACJ,IAAI,OACH,KAAI,IAAI,IAAI,KAAK,OACjB,KAAI,IAAI,IAAI,KAAK;AAlBiC;AAAA;AAuBzD,QAAI,OAAO,SAAS,UAAU;AAC5B,UAAI,MAAM,KAAK;AACf,WAAK,gBAAgB,KAAK;AAC1B,WAAK,mBAAmB,IAAI,MAAM,GAAG;AAErC,WAAK;AALP;AAQA,QAAI,UAAU,SAAS,aAAa;AAClC,UAAI,OAAO,KAAK,gBAAgB;AAChC,UAAI,MAAM;AACR,aAAK,mBAAmB;AACxB,aAAK;AAJ2B;AAApC;AAQA,QAAI,YAAY,SAAS,aAAa,GAAG,GAAG;AAC1C,UAAI,IAAI,KAAK;AACb,QAAE,KAAK,EAAE,KAAK,IAAI,EAAE,KAAK,IAAI,EAAE;AAC/B,QAAE,KAAK,EAAE,KAAK,IAAI,EAAE,KAAK,IAAI,EAAE;AAE/B,WAAK,mBAAmB,GAAG;AAL7B;AAQA,QAAI,QAAQ,SAAS,SAAS,GAAG,GAAG;AAClC,UAAI,IAAI,KAAK;AACb,QAAE,KAAK,EAAE,KAAK;AACd,QAAE,KAAK,EAAE,KAAK;AACd,QAAE,KAAK,EAAE,KAAK;AACd,QAAE,KAAK,EAAE,KAAK;AAEd,WAAK,eAAe,GAAG;AAPzB;AAUA,QAAI,YAAY,SAAS,aAAa,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG;AACtD,UAAI,IAAI,KAAK;AACb,WAAK,mBAAmB,CACtB,EAAE,KAAK,IAAI,EAAE,KAAK,GAClB,EAAE,KAAK,IAAI,EAAE,KAAK,GAClB,EAAE,KAAK,IAAI,EAAE,KAAK,GAClB,EAAE,KAAK,IAAI,EAAE,KAAK,GAClB,EAAE,KAAK,IAAI,EAAE,KAAK,IAAI,EAAE,IACxB,EAAE,KAAK,IAAI,EAAE,KAAK,IAAI,EAAE;AAG1B,UAAI,mBAAmB,GAAG,GAAG,GAAG,GAAG,GAAG;AAXxC;AAcA,QAAI,eAAe,SAAS,gBAAgB,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG;AAC5D,WAAK,mBAAmB,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG;AAExC,UAAI,sBAAsB,GAAG,GAAG,GAAG,GAAG,GAAG;AAH3C;AAMA,QAAI,SAAS,SAAS,UAAU,OAAO;AACrC,UAAI,WAAW,KAAK,IAAI;AACxB,UAAI,WAAW,KAAK,IAAI;AAExB,UAAI,IAAI,KAAK;AACb,WAAK,mBAAmB,CACtB,EAAE,KAAK,WAAW,EAAE,KAAK,UACzB,EAAE,KAAK,WAAW,EAAE,KAAK,UACzB,EAAE,KAAM,CAAC,WAAY,EAAE,KAAK,UAC5B,EAAE,KAAM,CAAC,WAAY,EAAE,KAAK,UAC5B,EAAE,IACF,EAAE;AAGJ,WAAK,gBAAgB;AAdvB;AAjGqC;AA7CzC;AAiKA,IAAI,0BAA2B,wBAAwB;AACrD,WAAS,eAAe,eAAe;AACrC,SAAK,gBAAgB;AACrB,SAAK,QAAQ,OAAO,OAAO;AAHwB;AAKrD,iBAAe;AACb,eAAW,SAAS,yBAAyB,IAAI,OAAO,QACX,gBAAgB;AAC3D,UAAI;AACJ,UAAI,KAAK,MAAM,QAAQ,WAAW;AAChC,sBAAc,KAAK,MAAM;AACzB,aAAK,cAAc,MAAM,aAAa,OAAO;AAE7C,oBAAY,QAAQ,aAAa,GAAG,GAAG,GAAG,GAAG,GAAG;AAJlD,aAKO;AACL,sBAAc,KAAK,cAAc,OAAO,OAAO;AAC/C,aAAK,MAAM,MAAM;AATwC;AAW3D,UAAI,gBAAgB;AAClB,mCAA2B,YAAY;AAZkB;AAc3D,aAAO;AAhBgB;AAkBzB,4BAAQ;AACN,eAAS,MAAM,KAAK,OAAO;AACzB,YAAI,cAAc,KAAK,MAAM;AAC7B,aAAK,cAAc,QAAQ;AAC3B,eAAO,KAAK,MAAM;AAJd;AAlBiB;AAAA;AA0B3B,SAAO;AA/BY,CAAC;AAkCtB,SAAS,kBAAkB,SAAS;AAClC,MAAI,yBAAyB;AAE7B,MAAI,QAAQ,QAAQ;MAAO,SAAS,QAAQ;AAC5C,MAAI;MAAG;MAAG;MAAI,SAAS,QAAQ;AAC/B,MAAI,SAAS,IAAI,WAAqB,mBAAS;AAC/C,MAAI,cACA,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG;AAGlE,MAAI,WAAY,QAAQ,IAAK,CAAC;MAAG,QAAQ,QAAQ;AACjD,MAAI,OAAO,IAAI,WAAW,WAAW;MAAS,MAAM;MAAG;AACvD,OAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,IAAI,IAAI,KAAK;AAC1C,QAAI,OAAO;QAAK,OAAO,MAAM;AAC7B,WAAO,OAAO,GAAG;AACf,WAAK,SAAU,OAAO,OAAQ,IAAI;AAClC,eAAS;AAJ+B;AAZV;AA8BlC,MAAI,QAAQ;AACZ,QAAM;AACN,MAAI,KAAK,SAAS,GAAG;AACnB,WAAO,KAAK;AACZ,MAAE;AAlC8B;AAoClC,OAAK,IAAI,GAAG,IAAI,OAAO,KAAK;AAC1B,QAAI,KAAK,SAAS,KAAK,MAAM,IAAI;AAC/B,aAAO,KAAK,KAAK,OAAO,IAAI;AAC5B,QAAE;AAHsB;AAK1B;AAzCgC;AA2ClC,MAAI,KAAK,SAAS,GAAG;AACnB,WAAO,KAAK;AACZ,MAAE;AA7C8B;AA+ClC,OAAK,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC3B,UAAM,IAAI;AACV,SAAK,IAAI;AACT,QAAI,KAAK,MAAM,cAAc,KAAK,MAAM;AACtC,aAAO,MAAM,KAAK,OAAO,IAAI;AAC7B,QAAE;AALuB;AAS3B,QAAI,MAAO,MAAK,OAAO,IAAU,WAAK,MAAM,YAAY,IAAI;AAC5D,SAAK,IAAI,GAAG,IAAI,OAAO,KAAK;AAC1B,YAAO,QAAa,WAAK,MAAM,KAAK,IAC7B,WAAK,MAAM,WAAW,KAAK,IAAI;AACtC,UAAI,YAAY,MAAM;AACpB,eAAO,KAAK,KAAK,YAAY;AAC7B,UAAE;AALsB;AAO1B;AAjByB;AAmB3B,QAAI,KAAK,MAAM,cAAc,KAAK,MAAM;AACtC,aAAO,KAAK,KAAK,KAAK,OAAO,IAAI;AACjC,QAAE;AArBuB;AAwB3B,QAAI,QAAQ,wBAAwB;AAClC,aAAO;AAzBkB;AA/CK;AA4ElC,QAAkB,qBAAS;AAC3B,OAAK,IAAI;AACT,MAAI,KAAK,SAAS,GAAG;AACnB,WAAO,MAAM;AACb,MAAE;AAhF8B;AAkFlC,OAAK,IAAI,GAAG,IAAI,OAAO,KAAK;AAC1B,QAAI,KAAK,SAAS,KAAK,MAAM,IAAI;AAC/B,aAAO,KAAK,KAAK,KAAK,OAAO,IAAI;AACjC,QAAE;AAHsB;AAK1B;AAvFgC;AAyFlC,MAAI,KAAK,SAAS,GAAG;AACnB,WAAO,KAAK,KAAK;AACjB,MAAE;AA3F8B;AA6FlC,MAAI,QAAQ,wBAAwB;AAClC,WAAO;AA9FyB;AAkGlC,MAAI,QAAQ,IAAI,WAAW,CAAC,GAAG,QAAQ,CAAC,GAAG,GAAG,CAAC,QAAQ,GAAG,GAAG,GAAG;AAChE,MAAI,WAAW;AACf,OAAK,IAAI,GAAG,SAAS,KAAK,QAAQ,KAAK;AACrC,QAAI,IAAI,IAAI;AACZ,QAAI,MAAM,IAAI;AACd,WAAO,IAAI,OAAO,CAAC,OAAO,IAAI;AAC5B;AAJmC;AAMrC,QAAI,MAAM,KAAK;AACb;AAPmC;AASrC,QAAI,SAAS,CAAC,IAAI,QAAQ;AAE1B,QAAI,OAAO,OAAO;QAAI,KAAK;QAAG;AAC9B,OAAG;AACD,UAAI,OAAO,MAAM;AACjB,SAAG;AACD,aAAK;AADP,eAES,CAAC,OAAO;AAEjB,WAAK,OAAO;AACZ,UAAI,OAAO,KAAK,OAAO,IAAI;AAEzB,eAAO;AAEP,eAAO,KAAK;AAJd,aAKO;AAEL,eAAO,KAAO,OAAO,QAAS;AAE9B,eAAO,MAAO,QAAQ,IAAI,QAAQ;AAhBnC;AAmBD,aAAO,KAAK,IAAI;AAChB,aAAO,KAAM,IAAI,SAAU;AAC3B,QAAE;AArBJ,aAsBS,OAAO;AAChB,aAAS,KAAK;AACd,MAAE;AAxI8B;AA2IlC,MAAI,cAAc,qBAAS,GAAG;AAC5B,MAAE;AAEF,MAAE,MAAM,IAAI,OAAO,CAAC,IAAI;AACxB,MAAE,UAAU,GAAG,CAAC;AAChB,MAAE;AACF,SAAK,IAAI,IAAI,GAAG,KAAK,SAAS,QAAQ,IAAI,IAAI,KAAK;AACjD,UAAI,IAAI,SAAS;AACjB,QAAE,OAAO,EAAE,IAAI,EAAE;AACjB,WAAK,IAAI,IAAI,GAAG,KAAK,EAAE,QAAQ,IAAI,IAAI,KAAK,GAAG;AAC7C,UAAE,OAAO,EAAE,IAAI,EAAE,IAAI;AAJ0B;AANvB;AAa5B,MAAE;AACF,MAAE;AACF,MAAE;AAfJ;AAkBA,SAAO;AAhWT;AAmWA,IAAI,4BAA6B,0BAA0B;AACzD,WAAS,mBAAmB;AAE1B,SAAK,eAAe;AACpB,SAAK,WAAW;AAChB,SAAK,gBAAgB;AACrB,SAAkB;AAClB,SAAK,kBAAkB;AACvB,SAAkB;AAClB,SAAK,UAAU;AAEf,SAAK,IAAI;AACT,SAAK,IAAI;AAET,SAAK,QAAQ;AACb,SAAK,QAAQ;AAEb,SAAK,cAAc;AACnB,SAAK,cAAc;AACnB,SAAK,aAAa;AAClB,SAAK,oBAAoB,wBAAkB;AAC3C,SAAK,WAAW;AAEhB,SAAK,YAAY;AACjB,SAAK,cAAc;AACnB,SAAK,cAAc;AAEnB,SAAK,YAAY;AACjB,SAAK,cAAc;AACnB,SAAK,YAAY;AACjB,SAAK,cAAc;AACnB,SAAK,iBAAiB;AA/BiC;AAkCzD,mBAAiB;AACf,WAAO,SAAS,yBAAyB;AACvC,aAAO,OAAO,OAAO;AAFI;AAI3B,qBAAiB,SAAS,iCAAiC,GAAG,GAAG;AAC/D,WAAK,IAAI;AACT,WAAK,IAAI;AANgB;AAAA;AAS7B,SAAO;AA3Cc,CAAC;AA8CxB,IAAI,0BAA2B,wBAAwB;AAGrD,MAAI,iBAAiB;AAErB,MAAI,kBAAkB;AAEtB,WAAS,eAAe,WAAW,YAAY,MAAM,eAC7B,YAAY;AAClC,SAAK,MAAM;AACX,SAAK,UAAU,IAAI;AACnB,SAAK,aAAa;AAClB,SAAK,cAAc;AACnB,SAAK,gBAAgB;AACrB,SAAK,MAAM;AACX,SAAK,QAAQ;AACb,SAAK,aAAa;AAClB,SAAK,OAAO;AACZ,SAAK,gBAAgB;AACrB,SAAK,aAAa;AAClB,SAAK,aAAa;AAClB,SAAK,kBAAkB;AAGvB,SAAK,gBAAgB;AACrB,SAAK,qBAAqB;AAC1B,SAAK,aAAa;AAClB,SAAK,aAAa;AAClB,SAAK,eAAe;AACpB,SAAK,YAAY;AACjB,SAAK,iBAAiB,IAAI,eAAe,KAAK;AAC9C,QAAI,WAAW;AAGb,iCAA2B;AA1BK;AA4BlC,SAAK,4BAA4B;AApCkB;AAuCrD,WAAS,mBAAmB,KAAK,SAAS;AACxC,QAAI,OAAO,cAAc,eAAe,mBAAmB,WAAW;AACpE,UAAI,aAAa,SAAS,GAAG;AAC7B;AAHsC;AAiBxC,QAAI,SAAS,QAAQ;QAAQ,QAAQ,QAAQ;AAC7C,QAAI,qBAAqB,SAAS;AAClC,QAAI,aAAc,UAAS,sBAAsB;AACjD,QAAI,cAAc,uBAAuB,IAAI,aAAa,aAAa;AAEvE,QAAI,eAAe,IAAI,gBAAgB,OAAO;AAC9C,QAAI,SAAS;QAAG;AAChB,QAAI,MAAM,QAAQ;AAClB,QAAI,OAAO,aAAa;AACxB,QAAI,GAAG,GAAG,iBAAiB;AAI3B,QAAI,QAAQ,SAAS,gBAAU,gBAAgB;AAE7C,UAAI,YAAY,IAAI;AACpB,UAAI,SAAS,IAAI,YAAY,KAAK,QAAQ,GAAG,KAAK,cAAc;AAChE,UAAI,mBAAmB,OAAO;AAC9B,UAAI,cAAe,QAAQ,KAAM;AACjC,UAAI,QAAQ;AACZ,UAAI,QAAQ,qBAAqB,QAAQ,aAAa;AACtD,WAAK,IAAI,GAAG,IAAI,aAAa,KAAK;AAChC,0BACG,IAAI,aAAc,oBAAoB;AACzC,kBAAU;AACV,aAAK,IAAI,GAAG,IAAI,iBAAiB,KAAK;AACpC,cAAI,UAAU,YAAY;AAC1B,cAAI,IAAI;AACR,cAAI,OAAQ,UAAU,cAAe,QAAQ,UAAU,IAAI;AAC3D,cAAI,eAAe,OAAO,CAAC;AAC3B,cAAI,OAAO;AACX,cAAI,UAAU;AACd,iBAAO,IAAI,cAAc,KAAK,GAAG;AAC/B,sBAAU,IAAI;AACd,mBAAO,aAAc,UAAU,MAAO,QAAQ;AAC9C,mBAAO,aAAc,UAAU,KAAM,QAAQ;AAC7C,mBAAO,aAAc,UAAU,KAAM,QAAQ;AAC7C,mBAAO,aAAc,UAAU,KAAM,QAAQ;AAC7C,mBAAO,aAAc,UAAU,IAAK,QAAQ;AAC5C,mBAAO,aAAc,UAAU,IAAK,QAAQ;AAC5C,mBAAO,aAAc,UAAU,IAAK,QAAQ;AAC5C,mBAAO,aAAc,UAAU,IAAK,QAAQ;AAhBV;AAkBpC,iBAAO,IAAI,MAAM,KAAK;AACnB,gBAAI,SAAS,GAAG;AACd,wBAAU,IAAI;AACd,qBAAO;AAHU;AAMpB,mBAAO,aAAc,UAAU,OAAQ,QAAQ;AAC/C,qBAAS;AAzByB;AAJN;AAiChC,eAAO,UAAU,kBAAkB;AACjC,iBAAO,aAAa;AAlCU;AAqChC,YAAI,aAAa,cAAc,GAAG,IAAI;AA7CK;AAA/C,eA+CW,QAAQ,SAAS,gBAAU,YAAY;AAGhD,UAAI;AACJ,yBAAmB,QAAQ,oBAAoB;AAC/C,WAAK,IAAI,GAAG,IAAI,YAAY,KAAK;AAC/B,aAAK,IAAI,IAAI,SAAS,QAAQ,SAAS;AACvC,kBAAU;AAEV,YAAI,aAAa,cAAc,GAAG;AAClC,aAAK;AAVyC;AAYhD,UAAI,IAAI,aAAa;AACnB,2BAAmB,QAAQ,qBAAqB;AAChD,aAAK,IAAI,IAAI,SAAS,QAAQ,SAAS;AACvC,YAAI,aAAa,cAAc,GAAG;AAfY;AAA3C,eAkBI,QAAQ,SAAS,gBAAU,WAAW;AAE/C,wBAAkB;AAClB,yBAAmB,QAAQ;AAC3B,WAAK,IAAI,GAAG,IAAI,aAAa,KAAK;AAChC,YAAI,KAAK,YAAY;AACnB,4BAAkB;AAClB,6BAAmB,QAAQ;AAHG;AAMhC,kBAAU;AACV,aAAK,IAAI,kBAAkB,MAAM;AAC/B,eAAK,aAAa,IAAI;AACtB,eAAK,aAAa,IAAI;AACtB,eAAK,aAAa,IAAI;AACtB,eAAK,aAAa;AAXY;AAahC,YAAI,aAAa,cAAc,GAAG,IAAI;AAjBO;AAA1C,WAmBA;AACL,YAAM,IAAW,2BAAkB,QAAQ;AAnHL;AAvCW;AA8JrD,WAAS,mBAAmB,KAAK,SAAS;AACxC,QAAI,SAAS,QAAQ;QAAQ,QAAQ,QAAQ;AAC7C,QAAI,qBAAqB,SAAS;AAClC,QAAI,aAAc,UAAS,sBAAsB;AACjD,QAAI,cAAc,uBAAuB,IAAI,aAAa,aAAa;AAEvE,QAAI,eAAe,IAAI,gBAAgB,OAAO;AAC9C,QAAI,SAAS;AACb,QAAI,MAAM,QAAQ;AAClB,QAAI,OAAO,aAAa;AAExB,SAAK,IAAI,IAAI,GAAG,IAAI,aAAa,KAAK;AACpC,UAAI,kBACD,IAAI,aAAc,oBAAoB;AAIzC,UAAI,UAAU;AACd,WAAK,IAAI,IAAI,GAAG,IAAI,iBAAiB,KAAK;AACxC,YAAI,OAAO;AACX,aAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,cAAI,CAAC,MAAM;AACT,gBAAI,OAAO,IAAI;AACf,mBAAO;AAHqB;AAK9B,eAAK,WAAY,OAAO,OAAQ,IAAI;AACpC,qBAAW;AACX,mBAAS;AAT6B;AAPN;AAmBpC,UAAI,aAAa,cAAc,GAAG,IAAI;AA9BA;AA9JW;AAgMrD,WAAS,aAAa,WAAW,SAAS;AACxC,QAAI,aAAa,CAAC,eAAe,aAAa,YAAY,eACxC,aAAa,WAAW,YAAY,cACpC,4BAA4B;AAC9C,SAAK,IAAI,IAAI,GAAG,KAAK,WAAW,QAAQ,IAAI,IAAI,KAAK;AACnD,UAAI,WAAW,WAAW;AAC1B,UAAI,UAAU,cAAc,WAAW;AACrC,gBAAQ,YAAY,UAAU;AAHmB;AAJb;AAUxC,QAAI,UAAU,gBAAgB,WAAW;AACvC,cAAQ,YAAY,UAAU;AAC9B,cAAQ,iBAAiB,UAAU;AAZG;AAhMW;AAgNrD,WAAS,kBAAkB,KAAK;AAC9B,QAAI,cAAc;AAClB,QAAI,YAAY;AAChB,QAAI,WAAW;AACf,QAAI,cAAc;AAClB,QAAI,YAAY;AAChB,QAAI,UAAU;AACd,QAAI,WAAW;AACf,QAAI,aAAa;AACjB,QAAI,2BAA2B;AAC/B,QAAI,OAAO;AACX,QAAI,IAAI,gBAAgB,WAAW;AACjC,UAAI,YAAY;AAChB,UAAI,iBAAiB;AAbO;AAhNqB;AAiOrD,WAAS,qBAAqB,OAAO,IAAI,IAAI,IAAI;AAC/C,QAAI,SAAS,MAAM;AACnB,SAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK,GAAG;AAClC,UAAI,QAAQ,MAAM;AAClB,UAAI,UAAU,GAAG;AACf,cAAM,IAAI,KAAK;AACf,cAAM,IAAI,KAAK;AACf,cAAM,IAAI,KAAK;AAHjB,aAIO,IAAI,QAAQ,KAAK;AACtB,YAAI,SAAS,MAAM;AACnB,cAAM,IAAI,KAAM,MAAM,IAAI,KAAK,QAAQ,KAAK,UAAW;AACvD,cAAM,IAAI,KAAM,MAAM,IAAI,KAAK,QAAQ,KAAK,UAAW;AACvD,cAAM,IAAI,KAAM,MAAM,IAAI,KAAK,QAAQ,KAAK,UAAW;AAVvB;AAFW;AAjOI;AAkPrD,WAAS,kBAAkB,UAAU,WAAW,aAAa;AAC3D,QAAI,SAAS,SAAS;AACtB,QAAI,QAAQ,IAAI;AAChB,SAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK,GAAG;AAClC,UAAI,QAAQ,cAAc,YAAY,SAAS,MAAM,SAAS;AAC9D,gBAAU,KAAM,UAAU,KAAK,QAAQ,QAAS;AALS;AAlPR;AA2PrD,WAAS,uBAAuB,UAAU,WAAW,aAAa;AAChE,QAAI,SAAS,SAAS;AACtB,SAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK,GAAG;AAClC,UAAI,IAAK,SAAS,IAAI,KAAK,KAClB,SAAS,IAAI,KAAK,MAClB,SAAS,IAAI,KAAK;AAC3B,gBAAU,KAAK,cACZ,UAAU,KAAK,YAAY,KAAK,MAAO,IACvC,UAAU,KAAK,KAAM;AARsC;AA3Pb;AAuQrD,WAAS,oBAAoB,SAAS,UAAU,OAAO,QAC1B,SAAS,UAAU,aAAa;AAC3D,QAAI,cAAc,CAAC,CAAC;AACpB,QAAI,KAAK,cAAc,SAAS,KAAK;AACrC,QAAI,KAAK,cAAc,SAAS,KAAK;AACrC,QAAI,KAAK,cAAc,SAAS,KAAK;AAErC,QAAI;AACJ,QAAI,YAAY,cAAc;AAC5B,kBAAY;AADd,WAEO;AACL,kBAAY;AAV6C;AAc3D,QAAI,oBAAoB;AACxB,QAAI,YAAY,KAAK,IAAI,QAAQ,KAAK,KAAK,oBAAoB;AAC/D,SAAK,IAAI,MAAM,GAAG,MAAM,QAAQ,OAAO,WAAW;AAChD,UAAI,cAAc,KAAK,IAAI,WAAW,SAAS;AAC/C,UAAI,WAAW,QAAQ,aAAa,GAAG,KAAK,OAAO;AACnD,UAAI,YAAY,SAAS,aAAa,GAAG,KAAK,OAAO;AAErD,UAAI,aAAa;AACf,6BAAqB,SAAS,MAAM,IAAI,IAAI;AANE;AAQhD,gBAAU,SAAS,MAAM,UAAU,MAAM;AAEzC,cAAQ,aAAa,WAAW,GAAG;AA1BsB;AAxQR;AAsSrD,WAAS,aAAa,KAAK,OAAO,UAAU;AAC1C,QAAI,OAAO,MAAM;AACjB,QAAI,UAAU,MAAM;AAEpB,QAAI,aAAa,MAAM,QAAQ,GAAG,GAAG,MAAM,QAC1B,MAAM,SAAS,MAAM;AAEtC,QAAI,WAAW,MAAM,YAAY;AACjC,QAAI,CAAC,MAAM,eAAe,kBAAW,WAAW;AAC9C,UAAI,6BAAsB,aAAa,SAAS,QAAQ;AACpD,iBAAS,MAAM;AAAS;AAA1B,OADa;AAEf,UAAI,aAAa,GAAG,GAAG,GAAG,GAAG,GAAG;AAChC,UAAI,UAAU,UAAU,MAAM,SAAS,MAAM;AAC7C;AAbwC;AAe1C,wBAAoB,SAAS,UAAU,KAAK,OAAO,KAAK,QACpC,MAAM,SAAS,UAAU,MAAM;AACnD,QAAI,UAAU,MAAM,GAAG;AAvT4B;AA0TrD,MAAI,kBAAkB,CAAC,QAAQ,SAAS;AACxC,MAAI,mBAAmB,CAAC,SAAS,SAAS;AAC1C,MAAI,cAAc;AAClB,MAAI,UAAU;AAEd,iBAAe;AAEA;AACwB,UADtB;UAAW;UAAU;;UACrB,6CAAa;;AAM1B,UAAI,QAAQ,KAAK,IAAI,OAAO;AAC5B,UAAI,SAAS,KAAK,IAAI,OAAO;AAE7B,WAAK,IAAI;AACT,WAAK,IAAI,YAAY,cAAc;AACnC,WAAK,IAAI,SAAS,GAAG,GAAG,OAAO;AAC/B,WAAK,IAAI;AAET,UAAI,cAAc;AAChB,YAAI,oBAAoB,KAAK,eAAe,UAC1C,eAAe,OAAO,QAAQ;AAChC,aAAK,eAAe,KAAK;AACzB,aAAK,oBAAoB,kBAAkB;AAC3C,aAAK,MAAM,kBAAkB;AAC7B,aAAK,IAAI;AAGT,aAAK,IAAI,UAAU,MAAM,KAAK,KACL,KAAK,aAAa;AAxBV;AA2BnC,WAAK,IAAI;AACT,wBAAkB,KAAK;AACvB,UAAI,WAAW;AACb,aAAK,IAAI,UAAU,MAAM,KAAK,KAAK;AA9BF;AAgCnC,WAAK,IAAI,UAAU,MAAM,KAAK,KAAK,SAAS;AAE5C,WAAK,gBAAgB,KAAK,IAAI,oBAAoB;AAElD,UAAI,KAAK,YAAY;AACnB,aAAK,WAAW;AArCiB;AAHZ;;AA4CzB,yBAAqB,SAAS,mCACE,cACA,mBAAmB,kBACnB,SAAS;AACvC,UAAI,YAAY,aAAa;AAC7B,UAAI,UAAU,aAAa;AAC3B,UAAI,IAAI,qBAAqB;AAC7B,UAAI,eAAe,UAAU;AAG7B,UAAI,iBAAiB,GAAG;AACtB,eAAO;AAR8B;AAWvC,UAAI,kBAAmB,eAAe,IAAI,mBACnB,OAAO,qBAAqB;AACnD,UAAI,UAAU,kBAAkB,KAAK,QAAQ,iBAAiB;AAC9D,UAAI,QAAQ;AAEZ,UAAI,aAAa,KAAK;AACtB,UAAI,OAAO,KAAK;AAChB,UAAI;AAEJ,aAAO,MAAM;AACX,YAAI,YAAY,aAAa,MAAM,QAAQ,gBAAgB;AACzD,kBAAQ,QAAQ,GAAG;AACnB,iBAAO;AAHE;AAMX,eAAO,QAAQ;AAEf,YAAI,SAAS,UAAI,YAAY;AAC3B,eAAK,MAAM,MAAM,MAAM,UAAU;AADnC,eAEO;AACL,cAAI,OAAO,UAAU;AACrB,eAAK,IAAI,IAAI,GAAG,KAAK,KAAK,QAAQ,IAAI,IAAI,KAAK;AAC7C,gBAAI,WAAW,KAAK;AACpB,gBAAI,SAAS,SAAS,OAAO,OAAO,SAAS,OAAO;AACpD,gBAAI,WAAW,SAAS,aAAa;AAIrC,gBAAI,CAAC,SAAS,WAAW,WAAW;AAClC,uBAAS,IAAI,UAAU;AACvB,qBAAO;AAToC;AAF1C;AAVI;AA0BX;AAGA,YAAI,MAAM,cAAc;AACtB,iBAAO;AA9BE;AAmCX,YAAI,mBAAmB,EAAE,QAAQ,iBAAiB;AAChD,cAAI,KAAK,QAAQ,SAAS;AACxB;AACA,mBAAO;AAHuC;AAKhD,kBAAQ;AAxCC;AApB0B;AA/ChB;AAmHzB,gBAAY,SAAS,4BAA4B;AAE/C,UAAI,KAAK,QAAQ,gBAAgB,MAAM;AACrC,aAAK;AAHwC;AAM/C,WAAK,IAAI;AAET,UAAI,KAAK,mBAAmB;AAC1B,aAAK,MAAM,KAAK;AAChB,aAAK,IAAI;AACT,aAAK,IAAI,aAAa,GAAG,GAAG,GAAG,GAAG,GAAG;AACrC,aAAK,IAAI,UAAU,KAAK,mBAAmB,GAAG;AAC9C,aAAK,IAAI;AACT,aAAK,oBAAoB;AAdoB;AAiB/C,WAAK,eAAe;AACpB,wBAAW;AAEX,UAAI,KAAK,YAAY;AACnB,aAAK,WAAW;AArB6B;AAnHxB;AA6IzB,kBAAc,SAAS,4BAA4B,OAAO;AACxD,WAAK,QAAQ,YAAY;AACzB,WAAK,IAAI,YAAY;AA/IE;AAiJzB,gBAAY,SAAS,0BAA0B,OAAO;AACpD,WAAK,IAAI,UAAU,gBAAgB;AAlJZ;AAoJzB,iBAAa,SAAS,2BAA2B,OAAO;AACtD,WAAK,IAAI,WAAW,iBAAiB;AArJd;AAuJzB,mBAAe,SAAS,6BAA6B,OAAO;AAC1D,WAAK,IAAI,aAAa;AAxJC;AA0JzB,aAAS,SAAS,uBAAuB,WAAW,WAAW;AAC7D,UAAI,MAAM,KAAK;AACf,UAAI,IAAI,gBAAgB,WAAW;AACjC,YAAI,YAAY;AAChB,YAAI,iBAAiB;AAJsC;AA1JtC;AAiKzB,wBAAoB,SAAS,kCAAkC,QAAQ,CAjK9C;AAsKzB,iBAAa,SAAS,2BAA2B,UAAU,CAtKlC;AA0KzB,eAAW,SAAS,yBAAyB,QAAQ;AACnD,WAAK,IAAI,IAAI,GAAG,KAAK,OAAO,QAAQ,IAAI,IAAI,KAAK;AAC/C,YAAI,QAAQ,OAAO;AACnB,YAAI,MAAM,MAAM;AAChB,YAAI,QAAQ,MAAM;AAElB,gBAAQ;AACN,eAAK;AACH,iBAAK,aAAa;AAClB;AACF,eAAK;AACH,iBAAK,WAAW;AAChB;AACF,eAAK;AACH,iBAAK,YAAY;AACjB;AACF,eAAK;AACH,iBAAK,cAAc;AACnB;AACF,eAAK;AACH,iBAAK,QAAQ,MAAM,IAAI,MAAM;AAC7B;AACF,eAAK;AACH,iBAAK,mBAAmB;AACxB;AACF,eAAK;AACH,iBAAK,YAAY;AACjB;AACF,eAAK;AACH,iBAAK,QAAQ,MAAM,IAAI,MAAM;AAC7B;AACF,eAAK;AACH,iBAAK,QAAQ,cAAc,MAAM;AACjC;AACF,eAAK;AACH,iBAAK,QAAQ,YAAY,MAAM;AAC/B,iBAAK,IAAI,cAAc,MAAM;AAC7B;AACF,eAAK;AACH,iBAAK,IAAI,2BAA2B;AACpC;AACF,eAAK;AACH,gBAAI,KAAK,QAAQ,aAAa;AAI5B,kBAAI,KAAK,WAAW,SAAS,KACxB,KAAK,WAAW,KAAK,WAAW,SAAS,GAAG,gBAC5C,KAAK,QAAQ,aAAc;AAC9B,qBAAK;AAHP,qBAIO;AACL,qBAAK;AATqB;AADhC;AAaE,iBAAK,QAAQ,cAAc,QAAQ,KAAK,YAAY;AACpD,gBAAI,KAAK,QAAQ,aAAa;AAC5B,mBAAK;AAfT;AAiBE,iBAAK,YAAY;AACjB;;AA3D6C;AA1K5B;AAyOzB,qBAAiB,SAAS,iCAAiC;AAEzD,UAAI,cAAc,KAAK,QAAQ;AAC/B,UAAI,aAAa,YAAY,OAAO;AACpC,UAAI,cAAc,YAAY,OAAO;AACrC,UAAI,UAAU,iBAAiB,KAAK;AACpC,UAAI,gBAAgB,KAAK,eAAe,UACtC,SAAS,YAAY,aAAa;AAEpC,UAAI,aAAa,KAAK;AACtB,UAAI,mBAAmB,WAAW;AAClC,WAAK,IAAI;AAET,UAAI,WAAW,cAAc;AAC7B,eAAS,MAAM,IAAI,YAAY,QAAQ,IAAI,YAAY;AACvD,eAAS,UAAU,CAAC,YAAY,SAAS,CAAC,YAAY;AACtD,eAAS,UAAU,MAAM,UAAU;AAEnC,kBAAY,wBAAwB,SAAS;AAE7C,mBAAa,YAAY;AACzB,WAAK,MAAM;AACX,WAAK,UAAU,CACb,CAAC,MAAM,gBACP,CAAC,MAAM,IACP,CAAC,MAAM;AAET,WAAK,WAAW,KAAK;AACrB,WAAK;AArQkB;AAuQzB,uBAAmB,SAAS,+BAA+B;AAGzD,UAAI,WAAW,KAAK;AACpB,WAAK;AACL,WAAK,MAAM,KAAK,WAAW;AAE3B,mBAAa,KAAK,KAAK,KAAK,QAAQ,aAAa;AACjD,WAAK,IAAI;AACT,WAAK,IAAI;AACT,mBAAa,UAAU,KAAK;AAG5B,WAAK,QAAQ,iBAAiB;AAG9B,UAAI,iBAAiB,WAAK,UACxB,KAAK,QAAQ,YAAY,uBACzB,SAAS;AACX,WAAK,IAAI,UAAU,MAAM,KAAK,KAAK;AAGnC,eAAS;AACT,eAAS,aAAa,GAAG,GAAG,GAAG,GAAG,GAAG;AACrC,eAAS,UAAU,GAAG,GAAG,SAAS,OAAO,OAAO,SAAS,OAAO;AAChE,eAAS;AAhSc;AAkSzB,sBAAkB,SAAS,+BAA+B;AAIxD,UAAI,WAAW,KAAK,QAAQ;AAC5B,UAAI,aAAa,KAAK;AACtB,WAAK,MAAM;AACX,WAAK,WAAW,KAAK;AACrB,WAAK;AA1SkB;AA4SzB,mBAAe,SAAS,+BAA+B;AACrD,UAAI,WAAW,KAAK;AACpB,WAAK;AACL,WAAK,MAAM,KAAK,WAAW;AAE3B,mBAAa,KAAK,KAAK,KAAK,QAAQ,aAAa;AACjD,WAAK,IAAI;AACT,mBAAa,UAAU,KAAK;AAG5B,UAAI,iBAAiB,WAAK,UACxB,KAAK,QAAQ,YAAY,uBACzB,SAAS;AACX,WAAK,IAAI,UAAU,MAAM,KAAK,KAAK;AAzTZ;AA2TzB,UAAM,SAAS,sBAAsB;AACnC,WAAK,IAAI;AACT,UAAI,MAAM,KAAK;AACf,WAAK,WAAW,KAAK;AACrB,WAAK,UAAU,IAAI;AACnB,WAAK,QAAQ,iBAAiB;AAhUP;AAkUzB,aAAS,SAAS,yBAAyB;AAEzC,UAAI,KAAK,QAAQ,gBAAgB;AAC/B,aAAK;AAHkC;AAOzC,UAAI,KAAK,QAAQ,gBAAyB,cAAK,WAAW,WAAW,KACjE,KAAK,WAAW,KAAK,WAAW,SAAS,GAAG,gBAC5C,KAAK,QAAQ,cAAc;AAC7B,aAAK;AAVkC;AAazC,UAAI,KAAK,WAAW,WAAW,GAAG;AAChC,aAAK,UAAU,KAAK,WAAW;AAC/B,aAAK,IAAI;AAGT,aAAK,cAAc;AAEnB,aAAK,4BAA4B;AApBM;AAlUlB;AAyVzB,eAAW,SAAS,yBAAyB,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG;AAC7D,WAAK,IAAI,UAAU,GAAG,GAAG,GAAG,GAAG,GAAG;AAElC,WAAK,4BAA4B;AA5VV;AAgWzB,mBAAe,SAAS,6BAA6B,KAAK,MAAM;AAC9D,UAAI,MAAM,KAAK;AACf,UAAI,UAAU,KAAK;AACnB,UAAI,IAAI,QAAQ;UAAG,IAAI,QAAQ;AAC/B,WAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK,IAAI,QAAQ,IAAI,IAAI,KAAK;AACnD,gBAAQ,IAAI,KAAK;AACf,eAAK,UAAI;AACP,gBAAI,KAAK;AACT,gBAAI,KAAK;AACT,gBAAI,QAAQ,KAAK;AACjB,gBAAI,SAAS,KAAK;AAClB,gBAAI,UAAU,GAAG;AACf,sBAAQ,KAAK;AANjB;AAQE,gBAAI,WAAW,GAAG;AAChB,uBAAS,KAAK;AATlB;AAWE,gBAAI,KAAK,IAAI;AACb,gBAAI,KAAK,IAAI;AACb,iBAAK,IAAI,OAAO,GAAG;AACnB,iBAAK,IAAI,OAAO,IAAI;AACpB,iBAAK,IAAI,OAAO,IAAI;AACpB,iBAAK,IAAI,OAAO,GAAG;AACnB,iBAAK,IAAI,OAAO,GAAG;AACnB,iBAAK,IAAI;AACT;AACF,eAAK,UAAI;AACP,gBAAI,KAAK;AACT,gBAAI,KAAK;AACT,gBAAI,OAAO,GAAG;AACd;AACF,eAAK,UAAI;AACP,gBAAI,KAAK;AACT,gBAAI,KAAK;AACT,gBAAI,OAAO,GAAG;AACd;AACF,eAAK,UAAI;AACP,gBAAI,KAAK,IAAI;AACb,gBAAI,KAAK,IAAI;AACb,gBAAI,cAAc,KAAK,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI,IAC5C,GAAG;AACrB,iBAAK;AACL;AACF,eAAK,UAAI;AACP,gBAAI,cAAc,GAAG,GAAG,KAAK,IAAI,KAAK,IAAI,IACxB,KAAK,IAAI,IAAI,KAAK,IAAI;AACxC,gBAAI,KAAK,IAAI;AACb,gBAAI,KAAK,IAAI;AACb,iBAAK;AACL;AACF,eAAK,UAAI;AACP,gBAAI,KAAK,IAAI;AACb,gBAAI,KAAK,IAAI;AACb,gBAAI,cAAc,KAAK,IAAI,KAAK,IAAI,IAAI,GAAG,GAAG,GAAG;AACjD,iBAAK;AACL;AACF,eAAK,UAAI;AACP,gBAAI;AACJ;;AA1DwD;AA6D9D,cAAQ,gBAAgB,GAAG;AA7ZJ;AA+ZzB,eAAW,SAAS,2BAA2B;AAC7C,WAAK,IAAI;AAhac;AAkazB,YAAQ,SAAS,sBAAsB,aAAa;AAClD,oBAAc,OAAO,gBAAgB,cAAc,cAAc;AACjE,UAAI,MAAM,KAAK;AACf,UAAI,cAAc,KAAK,QAAQ;AAE/B,UAAI,YAAY,KAAK,IAAI,KAAK,wBAAwB,kBAC7B,KAAK,QAAQ;AAGtC,UAAI,cAAc,KAAK,QAAQ;AAC/B,UAAI,eAAe,YAAY,eAAe,WAC1C,YAAY,SAAS,WAAW;AAGlC,YAAI;AACJ,YAAI,cAAc,YAAY,WAAW,KAAK;AAC9C,YAAI;AACJ,YAAI;AAPN,aAQO;AACL,YAAI;AAnB4C;AAqBlD,UAAI,aAAa;AACf,aAAK;AAtB2C;AAyBlD,UAAI,cAAc,KAAK,QAAQ;AA3bR;AA6bzB,iBAAa,SAAS,6BAA6B;AACjD,WAAK;AACL,WAAK;AA/bkB;AAiczB,UAAM,SAAS,oBAAoB,aAAa;AAC9C,oBAAc,OAAO,gBAAgB,cAAc,cAAc;AACjE,UAAI,MAAM,KAAK;AACf,UAAI,YAAY,KAAK,QAAQ;AAC7B,UAAI,gBAAgB,KAAK,QAAQ;AACjC,UAAI,cAAc;AAElB,UAAI,eAAe;AACjB,YAAI;AACJ,YAAI,KAAK,eAAe;AACtB,cAAI,aAAa,MAAM,KAAK,KAAK;AAHlB;AAKjB,YAAI,YAAY,UAAU,WAAW,KAAK;AAC1C,sBAAc;AAb8B;AAgB9C,UAAI,KAAK,eAAe;AACtB,YAAI,KAAK;AACT,aAAK,gBAAgB;AAFvB,aAGO;AACL,YAAI;AApBwC;AAuB9C,UAAI,aAAa;AACf,YAAI;AAxBwC;AA0B9C,UAAI,aAAa;AACf,aAAK;AA3BuC;AAjcvB;AA+dzB,YAAQ,SAAS,wBAAwB;AACvC,WAAK,gBAAgB;AACrB,WAAK;AAjekB;AAmezB,gBAAY,SAAS,4BAA4B;AAC/C,WAAK,KAAK;AACV,WAAK,OAAO;AAEZ,WAAK;AAvekB;AAyezB,kBAAc,SAAS,8BAA8B;AACnD,WAAK,gBAAgB;AACrB,WAAK;AA3ekB;AA6ezB,qBAAiB,SAAS,iCAAiC;AACzD,WAAK;AACL,WAAK;AA/ekB;AAifzB,uBAAmB,SAAS,mCAAmC;AAC7D,WAAK,gBAAgB;AACrB,WAAK;AACL,WAAK;AApfkB;AAsfzB,aAAS,SAAS,yBAAyB;AACzC,WAAK;AAvfkB;AA2fzB,UAAM,SAAS,sBAAsB;AACnC,WAAK,cAAc;AA5fI;AA8fzB,YAAQ,SAAS,wBAAwB;AACvC,WAAK,cAAc;AA/fI;AAmgBzB,eAAW,SAAS,2BAA2B;AAC7C,WAAK,QAAqB;AAC1B,WAAK,QAAQ,kBAAkB;AAC/B,WAAK,QAAQ,IAAI,KAAK,QAAQ,QAAQ;AACtC,WAAK,QAAQ,IAAI,KAAK,QAAQ,QAAQ;AAvgBf;AAygBzB,aAAS,SAAS,yBAAyB;AACzC,UAAI,QAAQ,KAAK;AACjB,UAAI,MAAM,KAAK;AACf,UAAI,UAAU,WAAW;AACvB,YAAI;AACJ;AALuC;AAQzC,UAAI;AACJ,UAAI;AACJ,WAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,YAAI,OAAO,MAAM;AACjB,YAAI,aAAa,MAAM,KAAK,KAAK;AACjC,YAAI,UAAU,KAAK,GAAG,KAAK;AAC3B,aAAK,UAAU,KAAK,KAAK;AAdc;AAgBzC,UAAI;AACJ,UAAI;AACJ,UAAI;AACJ,aAAO,KAAK;AA5hBW;AA8hBzB,oBAAgB,SAAS,8BAA8B,SAAS;AAC9D,WAAK,QAAQ,cAAc;AA/hBJ;AAiiBzB,oBAAgB,SAAS,8BAA8B,SAAS;AAC9D,WAAK,QAAQ,cAAc;AAliBJ;AAoiBzB,eAAW,SAAS,yBAAyB,OAAO;AAClD,WAAK,QAAQ,aAAa,QAAQ;AAriBX;AAuiBzB,gBAAY,SAAS,0BAA0B,SAAS;AACtD,WAAK,QAAQ,UAAU,CAAC;AAxiBD;AA0iBzB,aAAS,SAAS,uBAAuB,aAAa,MAAM;AAC1D,UAAI,UAAU,KAAK,WAAW,IAAI;AAClC,UAAI,UAAU,KAAK;AAEnB,UAAI,CAAC,SAAS;AACZ,cAAM,IAAW,gCAAsB;AALiB;AAQ1D,cAAQ,aAAc,QAAQ,aACR,QAAqB;AAI3C,UAAI,QAAQ,WAAW,OAAO,KAC1B,QAAQ,WAAW,OAAO,GAAG;AAC/B,wBAAK,kCAAkC;AAfiB;AAoB1D,UAAI,OAAO,GAAG;AACZ,eAAO,CAAC;AACR,gBAAQ,gBAAgB,CAAC;AAF3B,aAGO;AACL,gBAAQ,gBAAgB;AAxBgC;AA2B1D,WAAK,QAAQ,OAAO;AACpB,WAAK,QAAQ,WAAW;AAExB,UAAI,QAAQ,aAAa;AACvB;AA/BwD;AAkC1D,UAAI,OAAO,QAAQ,cAAc;AACjC,UAAI,OAAO,QAAQ,QAAQ,QAAS,QAAQ,OAAO,SAAS;AAC5D,UAAI,SAAS,QAAQ,SAAS,WAAW;AACzC,UAAI,WAAW,MAAM,OAAO,QAAQ,QAAQ;AAM5C,UAAI,kBAAkB,OAAO,gBAAgB,gBACvB,OAAO,gBAAgB,gBAAgB;AAC7D,WAAK,QAAQ,gBAAgB,OAAO;AAEpC,UAAI,OAAO,SAAS,MAAM,OAAO,MAAM,kBAAkB,QAAQ;AACjE,WAAK,IAAI,OAAO;AA1lBO;AA4lBzB,0BAAsB,SAAS,oCAAoC,MAAM;AACvE,WAAK,QAAQ,oBAAoB;AA7lBV;AA+lBzB,iBAAa,SAAS,2BAA2B,MAAM;AACrD,WAAK,QAAQ,WAAW;AAhmBD;AAkmBzB,cAAU,SAAS,wBAAwB,GAAG,GAAG;AAC/C,WAAK,QAAQ,IAAI,KAAK,QAAQ,SAAS;AACvC,WAAK,QAAQ,IAAI,KAAK,QAAQ,SAAS;AApmBhB;AAsmBzB,wBAAoB,SAAS,kCAAkC,GAAG,GAAG;AACnE,WAAK,WAAW,CAAC;AACjB,WAAK,SAAS,GAAG;AAxmBM;AA0mBzB,mBAAe,SAAS,6BAA6B,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG;AACrE,WAAK,QAAQ,aAAa,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG;AAC1C,WAAK,QAAQ,kBAAkB,KAAK,KAAK,IAAI,IAAI,IAAI;AAErD,WAAK,QAAQ,IAAI,KAAK,QAAQ,QAAQ;AACtC,WAAK,QAAQ,IAAI,KAAK,QAAQ,QAAQ;AA/mBf;AAinBzB,cAAU,SAAS,0BAA0B;AAC3C,WAAK,SAAS,GAAG,KAAK,QAAQ;AAlnBP;AAqnBzB,eAAW,SAAS,yBAAyB,WAAW,GAAG,GAAG;AAC5D,UAAI,MAAM,KAAK;AACf,UAAI,UAAU,KAAK;AACnB,UAAI,OAAO,QAAQ;AACnB,UAAI,oBAAoB,QAAQ;AAChC,UAAI,WAAW,QAAQ,WAAW,QAAQ;AAC1C,UAAI,iBAAiB,oBACnB,wBAAkB;AACpB,UAAI,iBAAiB,CAAG,sBACtB,wBAAkB;AAEpB,UAAI;AACJ,UAAI,KAAK,mBAAmB,gBAAgB;AAC1C,oBAAY,KAAK,iBAAiB,KAAK,YAAY;AAbO;AAgB5D,UAAI,KAAK,iBAAiB;AACxB,YAAI;AACJ,YAAI,UAAU,GAAG;AACjB,YAAI;AACJ,kBAAU,KAAK;AACf,YAAI,mBAAmB,wBAAkB,QACrC,mBAAmB,wBAAkB,aAAa;AACpD,cAAI;AAPkB;AASxB,YAAI,mBAAmB,wBAAkB,UACrC,mBAAmB,wBAAkB,aAAa;AACpD,cAAI;AAXkB;AAaxB,YAAI;AAbN,aAcO;AACL,YAAI,mBAAmB,wBAAkB,QACrC,mBAAmB,wBAAkB,aAAa;AACpD,cAAI,SAAS,WAAW,GAAG;AAHxB;AAKL,YAAI,mBAAmB,wBAAkB,UACrC,mBAAmB,wBAAkB,aAAa;AACpD,cAAI,WAAW,WAAW,GAAG;AAP1B;AA9BqD;AAyC5D,UAAI,gBAAgB;AAClB,YAAI,QAAQ,KAA0B,0BAAK,mBAAmB;AAC9D,cAAM;AACJ,qBAAW,IAAI;AACf;AACA;AACA;AACA;AALS;AA3C+C;AArnBrC;AA0qBzB,QAAI,0BAA0B;AAG5B,UAAI,MAAM,KAAK,cAAc,OAAO,IAAI,IAAI;AAC5C,UAAI,MAAM,KAAK;AACf,UAAI,SAAS,KAAK,GAAG;AACrB,UAAI,OAAO,IAAI,aAAa,GAAG,GAAG,IAAI,IAAI;AAC1C,UAAI,UAAU;AACd,WAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;AACvC,YAAI,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK;AAChC,oBAAU;AACV;AAHqC;AARb;AAc5B,aAAO,kBAAO,MAAM,2BAA2B;AAxrBxB;AA2rBzB,cAAU,SAAS,wBAAwB,QAAQ;AACjD,UAAI,UAAU,KAAK;AACnB,UAAI,OAAO,QAAQ;AACnB,UAAI,KAAK,aAAa;AACpB,eAAO,KAAK,cAAc;AAJqB;AAOjD,UAAI,WAAW,QAAQ;AACvB,UAAI,aAAa,GAAG;AAClB;AAT+C;AAYjD,UAAI,MAAM,KAAK;AACf,UAAI,gBAAgB,QAAQ;AAC5B,UAAI,cAAc,QAAQ;AAC1B,UAAI,cAAc,QAAQ;AAC1B,UAAI,gBAAgB,QAAQ;AAC5B,UAAI,aAAa,QAAQ,aAAa;AACtC,UAAI,eAAe,OAAO;AAC1B,UAAI,WAAW,KAAK;AACpB,UAAI,aAAa,WAAW,IAAI,CAAC;AACjC,UAAI,kBAAkB,KAAK;AAC3B,UAAI,oBAAoB,WAAW,QAAQ,WAAW;AAEtD,UAAI,iBACF,QAAQ,sBAAsB,wBAAkB,QAChD,CAAC,KAAK;AAER,UAAI;AACJ,UAAI,UAAU,MAAM,KAAK,QAAQ;AACjC,UAAI,UAAU,QAAQ,GAAG,QAAQ,IAAI,QAAQ;AAE7C,UAAI,QAAQ,aAAa;AAGvB,YAAI,YAAY,QAAQ,UAAU,WAAW,KAAK;AAnCH;AAsCjD,UAAI,gBAAgB,GAAG;AACrB,YAAI,MAAM,YAAY,CAAC;AADzB,aAEO;AACL,YAAI,MAAM,YAAY;AAzCyB;AA4CjD,UAAI,YAAY,QAAQ;AACxB,UAAI,QAAQ,QAAQ;AACpB,UAAI,UAAU,KAAK,cAAc,GAAG;AAClC,YAAI,iBAAiB,QAAQ,oBAC3B,wBAAkB;AACpB,YAAI,mBAAmB,wBAAkB,UACrC,mBAAmB,wBAAkB,aAAa;AACpD,eAAK,4BAA4B;AACjC,sBAAY,KAAK,wBAAwB;AANT;AAApC,aAQO;AACL,qBAAa;AAvDkC;AA0DjD,UAAI,kBAAkB,KAAK;AACzB,YAAI,MAAM,eAAe;AACzB,qBAAa;AA5DkC;AA+DjD,UAAI,YAAY;AAEhB,UAAI,IAAI;UAAG;AACX,WAAK,IAAI,GAAG,IAAI,cAAc,EAAE,GAAG;AACjC,YAAI,QAAQ,OAAO;AACnB,YAAI,iBAAM,QAAQ;AAChB,eAAK,aAAa,QAAQ,WAAW;AACrC;AAJ+B;AAOjC,YAAI,gBAAgB;AACpB,YAAI,UAAW,OAAM,UAAU,cAAc,KAAK;AAClD,YAAI,YAAY,MAAM;AACtB,YAAI,SAAS,MAAM;AACnB,YAAI,SAAS,SAAS,eAAe;AACrC,YAAI,QAAQ,MAAM;AAClB,YAAI,UAAU;AACZ,cAAI,SAAS,IAAI;AACjB,oBAAU,MAAM,WAAW;AAC3B,eAAK,MAAM,UAAU,QAAQ,KAAK,QAAQ;AAC1C,eAAK,CAAC,KAAK;AACX,eAAK,QAAQ,KAAK;AAElB,kBAAQ,UAAU,CAAC,QAAQ,KAAK;AAChC,oBAAU,KAAK;AACf,oBAAW,KAAI,MAAM;AATvB,eAUO;AACL,oBAAU,IAAI;AACd,oBAAU;AAzBqB;AA4BjC,YAAI,KAAK,aAAa,QAAQ,GAAG;AAI/B,cAAI,gBAAgB,IAAI,YAAY,WAAW,QAAQ,OACrD,WAAW;AACb,cAAI,QAAQ,iBAAiB,KAAK,yBAAyB;AACzD,gBAAI,kBAAkB,QAAQ;AAC9B,4BAAgB;AAChB,gBAAI;AACJ,gBAAI,MAAM,iBAAiB;AAC3B,uBAAW;AALb,iBAMO,IAAI,UAAU,eAAe;AAClC,uBAAY,SAAQ,iBAAiB,OACnC,WAAW;AAdgB;AA5BA;AAgDjC,YAAI,MAAM,YAAY,KAAK,aAAa;AACtC,cAAI,kBAAkB,CAAC,QAAQ;AAE7B,gBAAI,SAAS,WAAW,SAAS;AAFnC,iBAGO;AACL,iBAAK,UAAU,WAAW,SAAS;AACnC,gBAAI,QAAQ;AACV,8BAAgB,UAAU,OAAO,OAAO,IAAI;AAC5C,8BAAgB,UAAU,OAAO,OAAO,IAAI;AAC5C,mBAAK,UAAU,OAAO,UAAU,eAAe;AAL5C;AAJ+B;AAhDP;AA8DjC,YAAI,YAAY,QAAQ,oBAAoB,UAAU;AACtD,aAAK;AAEL,YAAI,eAAe;AACjB,cAAI;AAlE2B;AAlEc;AAuIjD,UAAI,UAAU;AACZ,gBAAQ,KAAK,IAAI;AADnB,aAEO;AACL,gBAAQ,KAAK,IAAI;AA1I8B;AA4IjD,UAAI;AAv0BmB;AA00BzB,mBAAe,SAAS,6BAA6B,QAAQ;AAE3D,UAAI,MAAM,KAAK;AACf,UAAI,UAAU,KAAK;AACnB,UAAI,OAAO,QAAQ;AACnB,UAAI,WAAW,QAAQ;AACvB,UAAI,gBAAgB,QAAQ;AAC5B,UAAI,aAAa,KAAK,WAAW,IAAI,CAAC;AACtC,UAAI,cAAc,QAAQ;AAC1B,UAAI,cAAc,QAAQ;AAC1B,UAAI,aAAa,QAAQ,aAAa;AACtC,UAAI,aAAa,QAAsB;AACvC,UAAI,eAAe,OAAO;AAC1B,UAAI,kBACF,QAAQ,sBAAsB,wBAAkB;AAClD,UAAI,GAAG,OAAO,OAAO;AAErB,UAAI,mBAAmB,aAAa,GAAG;AACrC;AAlByD;AAoB3D,WAAK,4BAA4B;AAEjC,UAAI;AACJ,UAAI,UAAU,MAAM,KAAK,QAAQ;AACjC,UAAI,UAAU,QAAQ,GAAG,QAAQ;AAEjC,UAAI,MAAM,YAAY;AAEtB,WAAK,IAAI,GAAG,IAAI,cAAc,EAAE,GAAG;AACjC,gBAAQ,OAAO;AACf,YAAI,iBAAM,QAAQ;AAChB,0BAAgB,aAAa,QAAQ,WAAW;AAChD,eAAK,IAAI,UAAU,eAAe;AAClC,kBAAQ,KAAK,gBAAgB;AAC7B;AAN+B;AASjC,YAAI,UAAW,OAAM,UAAU,cAAc,KAAK;AAClD,YAAI,eAAe,KAAK,qBAAqB,MAAM;AACnD,YAAI,CAAC,cAAc;AACX,gDAAmB,MAAqB;AAC9C;AAb+B;AAejC,aAAK,kBAAkB;AACvB,aAAK;AACL,YAAI,MAAM,UAAU;AACpB,YAAI,UAAU,MAAM,KAAK;AACzB,aAAK,oBAAoB;AACzB,aAAK;AAEL,YAAI,cAAc,WAAK,eAAe,CAAC,MAAM,OAAO,IAAI;AACxD,gBAAQ,YAAY,KAAK,WAAW;AAEpC,YAAI,UAAU,OAAO;AACrB,gBAAQ,KAAK,QAAQ;AAtDoC;AAwD3D,UAAI;AACJ,WAAK,kBAAkB;AAn4BA;AAu4BzB,kBAAc,SAAS,4BAA4B,QAAQ,QAAQ,CAv4B1C;AA24BzB,2BAAuB,SAAS,qCAAqC,QACD,QACA,KACA,KACA,KACA,KAAK;AAGvE,WAAK,IAAI,KAAK,KAAK,KAAK,MAAM,KAAK,MAAM;AACzC,WAAK;AACL,WAAK;AAr5BkB;AAy5BzB,uBAAmB,SAAS,iCAAiC;AAAI;;AAC/D,UAAI;AACJ,UAAI,GAAG,OAAO,iBAAiB;AAC7B,YAAI,QAAQ,GAAG;AACf,YAAI,gBAAgB,KAAK,iBACL,KAAK,IAAI,oBAAoB;AACjD,YAAI;AACF,gCAAuB,mCAAQ;AAC7B,mBAAO,IAAI,eAAe,KAAK,MAAK,YAAY,MAAK,MAC3B,MAAK;AAHP;AAAA;AAM5B,kBAAc,kCAAc,IAAI,OAAO,KAAK,KAAK,uBACrB;AAX9B,aAYO;AACL,kBAAU,6CAAwB;AAf2B;AAiB/D,aAAO;AA16BgB;AA46BzB,qBAAiB,SAAS,iCAAiC;AACzD,WAAK,QAAQ,cAAc,KAAK,kBAAkB;AA76B3B;AA+6BzB,mBAAe,SAAS,+BAA+B;AACrD,WAAK,QAAQ,YAAY,KAAK,kBAAkB;AAChD,WAAK,QAAQ,cAAc;AAj7BJ;AAm7BzB,uBAAmB,SAAS,iCAAiC,GAAG,GAAG,GAAG;AACpE,UAAI,QAAQ,WAAK,WAAW,GAAG,GAAG;AAClC,WAAK,IAAI,cAAc;AACvB,WAAK,QAAQ,cAAc;AAt7BJ;AAw7BzB,qBAAiB,SAAS,+BAA+B,GAAG,GAAG,GAAG;AAChE,UAAI,QAAQ,WAAK,WAAW,GAAG,GAAG;AAClC,WAAK,IAAI,YAAY;AACrB,WAAK,QAAQ,YAAY;AACzB,WAAK,QAAQ,cAAc;AA57BJ;AA+7BzB,iBAAa,SAAS,2BAA2B,WAAW;AAC1D,UAAI,MAAM,KAAK;AAEf,WAAK;AACL,UAAI,UAAU,6CAAwB;AACtC,UAAI,YAAY,QAAQ,WAAW,KAAK,MAAM;AAE9C,UAAI,MAAM,IAAI;AACd,UAAI,KAAK;AACP,YAAI,SAAS,IAAI;AACjB,YAAI,QAAQ,OAAO;AACnB,YAAI,SAAS,OAAO;AAEpB,YAAI,KAAK,WAAK,eAAe,CAAC,GAAG,IAAI;AACrC,YAAI,KAAK,WAAK,eAAe,CAAC,GAAG,SAAS;AAC1C,YAAI,KAAK,WAAK,eAAe,CAAC,OAAO,IAAI;AACzC,YAAI,KAAK,WAAK,eAAe,CAAC,OAAO,SAAS;AAE9C,YAAI,KAAK,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AAC1C,YAAI,KAAK,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AAC1C,YAAI,KAAK,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AAC1C,YAAI,KAAK,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AAE1C,aAAK,IAAI,SAAS,IAAI,IAAI,KAAK,IAAI,KAAK;AAf1C,aAgBO;AAOL,aAAK,IAAI,SAAS,CAAC,MAAM,CAAC,MAAM,MAAM;AA/BkB;AAkC1D,WAAK;AAj+BkB;AAq+BzB,sBAAkB,SAAS,kCAAkC;AAC3D,YAAM,IAAI,MAAM;AAt+BO;AAw+BzB,oBAAgB,SAAS,gCAAgC;AACvD,YAAM,IAAI,MAAM;AAz+BO;AA4+BzB,2BAAuB,SAAS,qCAAqC,QACD,MAAM;AACxE,WAAK;AACL,WAAK,mBAAmB,KAAK,KAAK;AAElC,UAAI,mBAAQ,WAAW,OAAO,WAAW,GAAG;AAC1C,aAAK,UAAU,MAAM,MAAM;AAL2C;AAQxE,WAAK,gBAAgB,KAAK,IAAI;AAE9B,UAAI,mBAAQ,SAAS,KAAK,WAAW,GAAG;AACtC,YAAI,QAAQ,KAAK,KAAK,KAAK;AAC3B,YAAI,SAAS,KAAK,KAAK,KAAK;AAC5B,aAAK,IAAI,KAAK,KAAK,IAAI,KAAK,IAAI,OAAO;AACvC,aAAK;AACL,aAAK;AAfiE;AA7+BjD;AAggCzB,yBAAqB,SAAS,qCAAqC;AACjE,WAAK;AACL,WAAK,gBAAgB,KAAK,mBAAmB;AAlgCtB;AAqgCzB,gBAAY,SAAS,0BAA0B,OAAO;AACpD,WAAK;AACL,UAAI,aAAa,KAAK;AActB,UAAI,CAAC,MAAM,UAAU;AACnB,wBAAK;AAjB6C;AAsBpD,UAAI,MAAM,UAAU;AAClB,wBAAK;AAvB6C;AA0BpD,UAAI,mBAAmB,WAAW;AAClC,UAAI,MAAM,QAAQ;AAChB,mBAAW,UAAU,MAAM,YAAY,MAAM;AA5BK;AA8BpD,UAAI,CAAC,MAAM,MAAM;AACf,cAAM,IAAI,MAAM;AA/BkC;AAoCpD,UAAI,SAAS,WAAK,2BACJ,MAAM,MACN,WAAW;AAEzB,UAAI,eAAe,CAAC,GACA,GACA,WAAW,OAAO,OAClB,WAAW,OAAO;AACtC,eAAS,WAAK,UAAU,QAAQ,iBAAiB,CAAC,GAAG,GAAG,GAAG;AAG3D,UAAI,UAAU,KAAK,MAAM,OAAO;AAChC,UAAI,UAAU,KAAK,MAAM,OAAO;AAChC,UAAI,aAAa,KAAK,IAAI,KAAK,KAAK,OAAO,MAAM,SAAS;AAC1D,UAAI,cAAc,KAAK,IAAI,KAAK,KAAK,OAAO,MAAM,SAAS;AAC3D,UAAI,SAAS;UAAG,SAAS;AACzB,UAAI,aAAa,gBAAgB;AAC/B,iBAAS,aAAa;AACtB,qBAAa;AAtDqC;AAwDpD,UAAI,cAAc,gBAAgB;AAChC,iBAAS,cAAc;AACvB,sBAAc;AA1DoC;AA6DpD,UAAI,UAAU,YAAY,KAAK;AAC/B,UAAI,MAAM,OAAO;AAEf,mBAAW,YAAc,KAAK,iBAAkB;AAhEE;AAkEpD,UAAI,gBAAgB,KAAK,eAAe,UACtC,SAAS,YAAY,aAAa;AACpC,UAAI,WAAW,cAAc;AAI7B,eAAS,MAAM,IAAI,QAAQ,IAAI;AAC/B,eAAS,UAAU,CAAC,SAAS,CAAC;AAC9B,eAAS,UAAU,MAAM,UAAU;AAEnC,UAAI,MAAM,OAAO;AAEf,aAAK,WAAW;AACd,kBAAQ,cAAc;AACtB,mBAAS;AACT;AACA;AACA;AACA;AACA,mBAAS,MAAM,MAAM;AACrB,oBAAU,MAAM,MAAM;AACtB,uBAAa,MAAM,MAAM,eAAe;AACxC,iCAAuB;AAVJ;AAFvB,aAcO;AAGL,mBAAW,aAAa,GAAG,GAAG,GAAG,GAAG,GAAG;AACvC,mBAAW,UAAU,SAAS;AAC9B,mBAAW,MAAM,QAAQ;AA/FyB;AAmGpD,mBAAa,YAAY;AACzB,WAAK,MAAM;AACX,WAAK,UAAU,CACb,CAAC,MAAM,gBACP,CAAC,MAAM,IACP,CAAC,MAAM;AAET,WAAK,WAAW,KAAK;AACrB,WAAK;AAGL,WAAK,QAAQ,cAAc;AAnnCJ;AAsnCzB,cAAU,SAAS,wBAAwB,OAAO;AAChD,WAAK;AACL,UAAI,WAAW,KAAK;AACpB,WAAK,MAAM,KAAK,WAAW;AAG3B,UAAI,KAAK,IAAI,0BAA0B,WAAW;AAChD,aAAK,IAAI,wBAAwB;AADnC,aAEO;AACL,aAAK,IAAI,2BAA2B;AATU;AAWhD,UAAI,MAAM,OAAO;AACf,aAAK,YAAY,KAAK,WAAW;AADnC,aAEO;AACL,aAAK,IAAI,UAAU,SAAS,QAAQ,GAAG;AAdO;AAgBhD,WAAK;AAtoCkB;AAyoCzB,sBAAkB,SAAS,kCAAkC;AAC3D,WAAK;AACL,UAAI,KAAK,eAAe;AACtB,aAAK,IAAI,aAAa,MAAM,KAAK,KAAK,KAAK;AAHc;AAzoCpC;AAgpCzB,oBAAgB,SAAS,gCAAgC;AACvD,WAAK;AAjpCkB;AAopCzB,qBAAiB,SAAS,+BAA+B,MAAM,WACN,QAAQ;AAC/D,WAAK;AACL,wBAAkB,KAAK;AACvB,WAAK,UAAU,IAAI;AAEnB,UAAI,mBAAQ,SAAS,KAAK,WAAW,GAAG;AACtC,YAAI,QAAQ,KAAK,KAAK,KAAK;AAC3B,YAAI,SAAS,KAAK,KAAK,KAAK;AAC5B,aAAK,IAAI,KAAK,KAAK,IAAI,KAAK,IAAI,OAAO;AACvC,aAAK;AACL,aAAK;AAVwD;AAa/D,WAAK,UAAU,MAAM,MAAM;AAC3B,WAAK,UAAU,MAAM,MAAM;AAnqCJ;AAsqCzB,mBAAe,SAAS,+BAA+B;AACrD,WAAK;AAvqCkB;AA0qCzB,sBAAkB,SAAS,gCAAgC,OAAO,GAAG,GAAG;AACtE,UAAI,WAAW,KAAK,KAAK,IAAI;AAC7B,UAAI,CAAC,UAAU;AACb,wBAAK;AACL;AAJoE;AAOtE,WAAK;AAEL,UAAI,MAAM,KAAK;AAEf,UAAI,MAAM,IAAI,GAAG,CAAC,IAAI;AAEtB,UAAI,UAAU,UAAU,GAAG,GAAG,SAAS,OAAO,SAAS,QACzC,GAAG,CAAC,GAAG,GAAG;AACxB,UAAI,KAAK,YAAY;AACnB,YAAI,mBAAmB,IAAI;AAC3B,YAAI,WAAW,KAAK,kBAAkB,GAAG;AACzC,aAAK,WAAW;AACd;AACA,gBAAM,SAAS;AACf,eAAK,SAAS;AACd,iBAAO,IAAI,iBAAiB;AAC5B,kBAAQ,IAAI,iBAAiB;AALH;AAlBwC;AA0BtE,WAAK;AApsCkB;AAusCzB,2BAAuB,SAAS,qCAAqC,KAAK;AACxE,UAAI,MAAM,KAAK;AACf,UAAI,QAAQ,IAAI;UAAO,SAAS,IAAI;AACpC,UAAI,YAAY,KAAK,QAAQ;AAC7B,UAAI,gBAAgB,KAAK,QAAQ;AAEjC,UAAI,QAAQ,KAAK;AAEjB,UAAI,wBAAwB,SAAS,MAAM,aAAa,WAAW;AACjE,YAAI,SAAS,uBAAuB,UAAU,qBAAqB;AACjE,gBAAM;AACgB,kBAAM,IAAI;AAAM;AAAO;AAAzB,WAAlB;AAFJ,eAGO;AACL,gBAAM,WAAW;AAL8C;AARK;AAiBxE,UAAI,SAAS,MAAM,UAAU;AAC3B,cAAM,SAAS;AACf;AAnBsE;AAsBxE,UAAI,aAAa,KAAK,eAAe,UAAU,cACA,OAAO;AACtD,UAAI,UAAU,WAAW;AACzB,cAAQ;AAER,yBAAmB,SAAS;AAE5B,cAAQ,2BAA2B;AAEnC,cAAQ,YAAY,gBACA,UAAU,WAAW,SAAS,QAAQ;AAC1D,cAAQ,SAAS,GAAG,GAAG,OAAO;AAE9B,cAAQ;AAER,WAAK,wBAAwB,WAAW;AA5uCjB;AA+uCzB,iCACE,SAAS,2CAA2C,SAAS,QACT,QAAQ,WAAW;AACvE,UAAI,QAAQ,QAAQ;AACpB,UAAI,SAAS,QAAQ;AACrB,UAAI,YAAY,KAAK,QAAQ;AAC7B,UAAI,gBAAgB,KAAK,QAAQ;AAEjC,UAAI,aAAa,KAAK,eAAe,UAAU,cACA,OAAO;AACtD,UAAI,UAAU,WAAW;AACzB,cAAQ;AAER,yBAAmB,SAAS;AAE5B,cAAQ,2BAA2B;AAEnC,cAAQ,YAAY,gBACA,UAAU,WAAW,SAAS,QAAQ;AAC1D,cAAQ,SAAS,GAAG,GAAG,OAAO;AAE9B,cAAQ;AAER,UAAI,MAAM,KAAK;AACf,WAAK,IAAI,IAAI,GAAG,KAAK,UAAU,QAAQ,IAAI,IAAI,KAAK,GAAG;AACrD,YAAI;AACJ,YAAI,UAAU,QAAQ,GAAG,GAAG,QAAQ,UAAU,IAAI,UAAU,IAAI;AAChE,YAAI,MAAM,GAAG,CAAC;AACd,YAAI,UAAU,WAAW,QAAQ,GAAG,GAAG,OAAO,QAC5C,GAAG,CAAC,GAAG,GAAG;AACZ,YAAI;AA5BiE;AAjvChD;AAixCzB,gCACE,SAAS,0CAA0C,QAAQ;AAC3D,UAAI,MAAM,KAAK;AAEf,UAAI,YAAY,KAAK,QAAQ;AAC7B,UAAI,gBAAgB,KAAK,QAAQ;AACjC,WAAK,IAAI,IAAI,GAAG,KAAK,OAAO,QAAQ,IAAI,IAAI,KAAK;AAC/C,YAAI,QAAQ,OAAO;AACnB,YAAI,QAAQ,MAAM;YAAO,SAAS,MAAM;AAExC,YAAI,aAAa,KAAK,eAAe,UAAU,cACA,OAAO;AACtD,YAAI,UAAU,WAAW;AACzB,gBAAQ;AAER,2BAAmB,SAAS;AAE5B,gBAAQ,2BAA2B;AAEnC,gBAAQ,YAAY,gBACA,UAAU,WAAW,SAAS,QAAQ;AAC1D,gBAAQ,SAAS,GAAG,GAAG,OAAO;AAE9B,gBAAQ;AAER,YAAI;AACJ,YAAI,UAAU,MAAM,KAAK,MAAM;AAC/B,YAAI,MAAM,GAAG,CAAC;AACd,YAAI,UAAU,WAAW,QAAQ,GAAG,GAAG,OAAO,QAChC,GAAG,CAAC,GAAG,GAAG;AACxB,YAAI;AA7BqD;AAlxCpC;AAmzCzB,uBAAmB,SAAS,iCAAiC,OAAO;AAClE,UAAI,UAAU,KAAK,KAAK,IAAI;AAC5B,UAAI,CAAC,SAAS;AACZ,wBAAK;AACL;AAJgE;AAOlE,WAAK,wBAAwB;AA1zCN;AA6zCzB,6BACE,SAAS,uCAAuC,OAAO,QAAQ,QACX,WAAW;AAC/D,UAAI,UAAU,KAAK,KAAK,IAAI;AAC5B,UAAI,CAAC,SAAS;AACZ,wBAAK;AACL;AAJ6D;AAO/D,UAAI,QAAQ,QAAQ;AACpB,UAAI,SAAS,QAAQ;AACrB,UAAI,MAAM;AACV,WAAK,IAAI,IAAI,GAAG,KAAK,UAAU,QAAQ,IAAI,IAAI,KAAK,GAAG;AACrD,YAAI;AAAO,qBAAW,CAAC,QAAQ,GAAG,GAAG,QAAQ,UAAU,IAC5C,UAAU,IAAI;AAAK,aAAG;AAAG,aAAG;AAAG,aAAG;AAAO,aAAG;AAD9C;AAXoD;AAc/D,WAAK,6BAA6B,SAAS;AA70CpB;AAg1CzB,6BACE,SAAS,uCAAuC,SAAS;AACzD,UAAI,QAAQ,QAAQ;AACpB,UAAI,SAAS,QAAQ;AACrB,UAAI,MAAM,KAAK;AAEf,WAAK;AAEL,UAAI,MAAM,IAAI,OAAO,CAAC,IAAI;AAE1B,UAAI,mBAAmB,IAAI;AAC3B,UAAI,IAAI,iBAAiB;UAAI,IAAI,iBAAiB;AAClD,UAAI,aAAa,KAAK,IAAI,KAAK,KAAK,IAAI,IAAI,IAAI,IAAI;AACpD,UAAI,IAAI,iBAAiB;UAAI,IAAI,iBAAiB;AAClD,UAAI,cAAc,KAAK,IAAI,KAAK,KAAK,IAAI,IAAI,IAAI,IAAI;AAErD,UAAI,YAAY;AAEhB,UAAI,mBAAmB,eAAe,CAAC,QAAQ,MAAM;AACnD,qBAAa;AADf,aAEO;AACL,oBAAY,KAAK,eAAe,UAAU,eACA,OAAO;AACjD,YAAI,SAAS,UAAU;AACvB,2BAAmB,QAAQ;AAC3B,qBAAa,UAAU;AAxBgC;AA2BzD,UAAI,aAAa;UAAO,cAAc;AACtC,UAAI,cAAc;AAIlB,aAAQ,aAAa,KAAK,aAAa,KAC/B,cAAc,KAAK,cAAc,GAAI;AAC3C,YAAI,WAAW;YAAY,YAAY;AACvC,YAAI,aAAa,KAAK,aAAa,GAAG;AACpC,qBAAW,KAAK,KAAK,aAAa;AAClC,wBAAc,aAAa;AAJc;AAM3C,YAAI,cAAc,KAAK,cAAc,GAAG;AACtC,sBAAY,KAAK,KAAK,cAAc;AACpC,yBAAe,cAAc;AARY;AAU3C,oBAAY,KAAK,eAAe,UAAU,aACA,UAAU;AACpD,iBAAS,UAAU;AACnB,eAAO,UAAU,GAAG,GAAG,UAAU;AACjC,eAAO,UAAU,YAAY,GAAG,GAAG,YAAY,aAClB,GAAG,GAAG,UAAU;AAC7C,qBAAa,UAAU;AACvB,qBAAa;AACb,sBAAc;AACd,sBAAc,gBAAgB,cAAc,cAAc;AApDH;AAsDzD,UAAI,UAAU,YAAY,GAAG,GAAG,YAAY,aAClB,GAAG,CAAC,QAAQ,OAAO;AAE7C,UAAI,KAAK,YAAY;AACnB,YAAI,WAAW,KAAK,kBAAkB,GAAG,CAAC;AAC1C,aAAK,WAAW;AACd;AACA,gBAAM,SAAS;AACf,eAAK,SAAS;AACd,iBAAO,QAAQ,iBAAiB;AAChC,kBAAQ,SAAS,iBAAiB;AALR;AA3D2B;AAmEzD,WAAK;AAp5CkB;AAu5CzB,kCACE,SAAS,4CAA4C,SAAS,KAAK;AACnE,UAAI,MAAM,KAAK;AACf,UAAI,IAAI,QAAQ;AAChB,UAAI,IAAI,QAAQ;AAEhB,UAAI,YAAY,KAAK,eAAe,UAAU,eAAe,GAAG;AAChE,UAAI,SAAS,UAAU;AACvB,yBAAmB,QAAQ;AAE3B,WAAK,IAAI,IAAI,GAAG,KAAK,IAAI,QAAQ,IAAI,IAAI,KAAK;AAC5C,YAAI,QAAQ,IAAI;AAChB,YAAI;AACJ,YAAI,UAAU,MAAM,KAAK,MAAM;AAC/B,YAAI,MAAM,GAAG,CAAC;AACd,YAAI,UAAU,UAAU,QAAQ,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GACnD,GAAG,CAAC,GAAG,GAAG;AACxB,YAAI,KAAK,YAAY;AACnB,cAAI,WAAW,KAAK,kBAAkB,MAAM,GAAG,MAAM;AACrD,eAAK,WAAW;AACd;AACA,kBAAM,SAAS;AACf,iBAAK,SAAS;AACd,mBAAO;AACP,oBAAQ;AALkB;AATc;AAiB5C,YAAI;AA1B6D;AAx5C5C;AAs7CzB,8BACE,SAAS,0CAA0C;AACjD,WAAK,IAAI,SAAS,GAAG,GAAG,GAAG;AAx7CN;AA27CzB,kBAAc,SAAS,8BAA8B;AACnD,sBAAK;AA57CkB;AAi8CzB,eAAW,SAAS,yBAAyB,KAAK,CAj8CzB;AAo8CzB,oBAAgB,SAAS,8BAA8B,KAAK,YAAY,CAp8C/C;AAu8CzB,wBAAoB,SAAS,kCAAkC,KAAK,CAv8C3C;AA08CzB,6BAAyB,SAAS,uCACE,KAAK,YAAY,CA38C5B;AA88CzB,sBAAkB,SAAS,kCAAkC,CA98CpC;AAo9CzB,iBAAa,SAAS,6BAA6B,CAp9C1B;AAu9CzB,eAAW,SAAS,2BAA2B,CAv9CtB;AA69CzB,iBAAa,SAAS,6BAA6B;AACjD,UAAI,MAAM,KAAK;AACf,UAAI,KAAK,aAAa;AACpB,YAAI,KAAK,gBAAgB,SAAS;AAChC,cAAI,KAAK;AADX,eAEO;AACL,cAAI;AAJc;AAMpB,aAAK,cAAc;AAR4B;AAUjD,UAAI;AAv+CmB;AAy+CzB,yBAAqB,SAAS,mCAAmC,OAAO;AACtE,UAAI,KAAK,8BAA8B,MAAM;AAK3C,aAAK,IAAI;AACT,YAAI,UAAU,KAAK,IAAI;AACvB,aAAK,IAAI;AAET,aAAK,4BAA4B,KAAK,KAAK,KAAK,IAC7C,QAAQ,KAAK,QAAQ,KAAK,QAAQ,KAAK,QAAQ,IAC/C,QAAQ,KAAK,QAAQ,KAAK,QAAQ,KAAK,QAAQ;AAZkB;AActE,aAAO,KAAK;AAv/CW;AAy/CzB,uBAAmB,SAAS,iCAAiC,GAAG,GAAG;AACjE,UAAI,YAAY,KAAK,IAAI;AACzB,aAAO,CACL,UAAU,KAAK,IAAI,UAAU,KAAK,IAAI,UAAU,IAChD,UAAU,KAAK,IAAI,UAAU,KAAK,IAAI,UAAU;AA7/C3B;AAAA;AAkgD3B,WAAe,iBAAK;AAClB,mBAAe,UAAU,UAAI,OAAO,eAAe,UAAU;AAl0DV;AAq0DrD,SAAO;AAGT,CAx0DsB;QAy0DpB,gC;;;;;;;;;;;;;;ACzsEK;;AAEP,SAAS,WAAW,OAAO;AACzB,OAAK,QAAQ;AACb,OAAK,eAAe;AAElB,OAAK,kBAAkB;AACvB,OAAK,iBAAiB;AACtB,OAAK;AACH,cAAU;AACV,mBAAe;AAFK;AAzB1B;AA+BA,WAAW;AACT,cAAY,SAAS,qBAAqB,MAAM;AAC9C,QAAI,eAAe,KAAK;AACxB,QAAI,CAAC,cAAc;AACjB,qBAAe,KAAK,eAAe,SAAS,cAAc;AAC1D,mBAAa,KAAK,0BAA0B,KAAK;AACjD,eAAS,gBAAgB,qBAAqB,QAAQ,GAAG,YACvD;AAN0C;AAS9C,QAAI,aAAa,aAAa;AAC9B,eAAW,WAAW,MAAM,WAAW,SAAS;AAX7B;AAcrB,SAAO,SAAS,kBAAkB;AAChC,QAAI,KAAK,cAAc;AAErB,WAAK,aAAa;AAClB,WAAK,eAAe;AAJU;AAO9B,SAAK,gBAAgB,QAAQ,UAAS,gBAAgB;AACpD,eAAS,MAAM,OAAO;AADxB;AAGA,SAAK,gBAAgB,SAAS;AAxBb;AAAA;AA6B8C;AACnE,MAAI,kBAAkB,2BAAY;AAGhC,WAAO,KACL,2EACA,2EACA,2EACA,2EACA,2EACA,2EACA,2EACA,2EACA,2EACA,2EACA,2EACA,2EACA,2EACA,2EACA,2EACA,2EACA,2EACA,2EACA,2EACA,2EACA,2EACA;AAzBJ;AA2BA,SAAO,eAAe,WAAW,WAAW;AAC1C,wBAAM;AACJ,aAAO,kBAAO,MAAM,gBAAgB;AAFoB;;AAI1D,kBAAc;AAJ4C;AAO5D,aAAW,UAAU,oBACjB,SAAS,6BAA6B,gBAAgB;AACxD,SAAK,gBAAgB,KAAK;AAC1B,aAAS,MAAM,IAAI;AAHrB;AAMA,aAAW,UAAU,OAAO,SAAS,eAAe,OAAO,UAAU;AACnE,QAAI,QAAQ;AACZ,QAAI,cAAc;AAClB,QAAI,mBAAmB;AACvB,QAAI,uBAAuB,8BAAS,gBAAgB;AAGlD,4BAAsB,OAAO,MAAM,UAAS,GAAG;AAC7C,wBAAK,0BAA0B,eAAe,SAAS,QAAQ;AAD1D;AAHT;AASA,QAAI,4BAA4B,WAAW,6BACX,CAAC,WAAW;AAC5C,SAAK,IAAI,IAAI,GAAG,KAAK,MAAM,QAAQ,IAAI,IAAI,KAAK;AAC9C,UAAI,OAAO,MAAM;AAIjB,UAAI,KAAK,YAAY,KAAK,YAAY,OAAO;AAC3C;AAN4C;AAQ9C,WAAK,WAAW;AAEhB,UAAI,2BAA2B;AAC7B,YAAI,iBAAiB,KAAK;AAC1B,YAAI,gBAAgB;AAClB,eAAK,kBAAkB;AACvB,2BAAiB,KAAK,qBAAqB;AAJhB;AAA/B,aAMO;AACL,YAAI,OAAO,KAAK;AAChB,YAAI,MAAM;AACR,eAAK,WAAW;AAChB,gBAAM,KAAK;AACX,sBAAY,KAAK;AALd;AAhBuC;AAfmB;AAyCnE,QAAI,UAAU,KAAK,qBAAqB;AACxC,QAAI,2BAA2B;AAC7B,cAAQ,IAAI,kBAAkB,KAAK,YAAW;AAC5C,gBAAQ;AADV;AADF,eAIW,MAAM,SAAS,KAAK,CAAC,WAAW,4BAA4B;AACrE,WAAK,qBAAqB,OAAO,aAAa;AADzC,WAEA;AACL,cAAQ;AAjDyD;AAArE;AAqDA,aAAW,UAAU,uBACjB,SAAS,gCAAgC,UAAU;AACrD,aAAS,6BAA6B;AACpC,wBAAO,CAAC,QAAQ,KAAK;AACrB,cAAQ,MAAM,KAAK;AAGnB,aAAO,QAAQ,SAAS,SAAS,KAAK,QAAQ,SAAS,GAAG,KAAK;AAC7D,YAAI,eAAe,QAAQ,SAAS;AACpC,mBAAW,aAAa,UAAU;AAPA;AADe;AAYrD,QAAI,UAAU,KAAK;AACnB,QAAI,YAAY,wBAAyB,QAAQ;AACjD,QAAI;AACF,UAAI;AACJ,gBAAU;AACV;AACA,eAAS,KAAK;AAJF;AAMd,YAAQ,SAAS,KAAK;AACtB,WAAO;AAtBT;AAyBA,aAAW,UAAU,uBACf,SAAS,+BAA+B,OAAO,OAAO,SAAS;AAQjE,aAAS,MAAM,MAAM,QAAQ;AAC3B,aAAQ,KAAK,WAAW,WAAW,KAC3B,KAAK,WAAW,SAAS,MAAM,KAC/B,KAAK,WAAW,SAAS,MAAM,IAC/B,KAAK,WAAW,SAAS,KAAK;AAZyB;AAejE,aAAS,aAAa,GAAG,QAAQ,QAAQ,QAAQ;AAC/C,UAAI,SAAS,EAAE,OAAO,GAAG;AACzB,UAAI,SAAS,EAAE,OAAO,SAAS;AAC/B,aAAO,SAAS,SAAS;AAlBsC;AAqBjE,QAAI,GAAG;AAGP,QAAI,SAAS,SAAS,cAAc;AACpC,WAAO,QAAQ;AACf,WAAO,SAAS;AAChB,QAAI,MAAM,OAAO,WAAW;AAE5B,QAAI,SAAS;AACb,aAAS,YAAY,MAAM,UAAU;AACnC;AAEA,UAAI,SAAS,IAAI;AACf,wBAAK;AACL;AACA;AANiC;AAQnC,UAAI,OAAO,UAAU;AACrB,UAAI,SAAS,KAAK,GAAG;AACrB,UAAI,YAAY,IAAI,aAAa,GAAG,GAAG,GAAG;AAC1C,UAAI,UAAU,KAAK,KAAK,GAAG;AACzB;AACA;AAbiC;AAenC,iBAAW,YAAY,KAAK,MAAM,MAAM;AA7CuB;AAgDjE,QAAI,iBAAiB,OAAO,KAAK,QAAQ,KAAK;AAM9C,QAAI,OAAO,KAAK;AAChB,QAAI,iBAAiB;AACrB,WAAO,aAAa,MAAM,gBAAgB,eAAe,QACrC;AAEpB,QAAI,sBAAsB;AAC1B,QAAI,aAAa;AACjB,QAAI,WAAW,MAAM,MAAM;AAC3B,SAAK,IAAI,GAAG,KAAK,eAAe,SAAS,GAAG,IAAI,IAAI,KAAK,GAAG;AAC1D,iBAAY,WAAW,aAAa,MAAM,gBAAgB,KAAM;AA/DD;AAiEjE,QAAI,IAAI,eAAe,QAAQ;AAC7B,iBAAY,WAAW,aACX,MAAM,iBAAiB,OAAO,KAAM;AAnEe;AAqEjE,WAAO,aAAa,MAAM,qBAAqB,GAAG,oBAAS;AAE3D,QAAI,MAAM,mCAAmC,KAAK,QAAQ;AAC1D,QAAI,OAAO,+BAA+B,iBAAiB,WAChD,MAAM;AACjB,SAAK,WAAW;AAEhB,QAAI,QAAQ;AACZ,SAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,IAAI,IAAI,KAAK;AAC1C,YAAM,KAAK,MAAM,GAAG;AA9E2C;AAgFjE,UAAM,KAAK;AAEX,QAAI,MAAM,SAAS,cAAc;AACjC,QAAI,aAAa,SACA,wBACA,+BACA;AACjB,SAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,IAAI,IAAI,EAAE,GAAG;AAC1C,UAAI,OAAO,SAAS,cAAc;AAClC,WAAK,cAAc;AACnB,WAAK,MAAM,aAAa,MAAM;AAC9B,UAAI,YAAY;AA3F+C;AA6FjE,aAAS,KAAK,YAAY;AAE1B,gBAAY,gBAAgB,YAAW;AACrC,eAAS,KAAK,YAAY;AAC1B,cAAQ;AAFV;AAhGJ;AAnLF;AA2SqE;AACnE,aAAW,4BAA4B,OAAO,aAAa,eACpB,CAAC,CAAC,SAAS;AA7SpD;AA+S+E;AAC7E,MAAI,6BAA6B,SAAS,6BAA6B;AACrE,QAAI,OAAO,cAAc,aAAa;AAEpC,aAAO;AAH4D;AAMrE,QAAI,YAAY;AAIhB,QAAI,IAAI,mCAAmC,KAAK,UAAU;AAC1D,QAAI,KAAK,EAAE,MAAM,IAAI;AACnB,kBAAY;AAZuD;AAerE,WAAO;AAfT;AAiBA,SAAO,eAAe,YAAY;AAChC,wBAAM;AACJ,aAAO,kBAAO,YAAY,8BACZ;AAH8C;;AAK9D,gBAAY;AACZ,kBAAc;AANgD;AAjUlE;AA2UA,IAAI;AACF,MAAI,QAAQ;AACV,WAAO,kBAAO,MAAM,SAAS;AAFL;AAAA;AAM5B,IAAI,0BAA2B,wBAAwB;AACrD,WAAS,eAAe,gBAAgB,SAAS;AAC/C,SAAK,iBAAiB,OAAO,OAAO;AAEpC,aAAS,KAAK,gBAAgB;AAC5B,WAAK,KAAK,eAAe;AAJoB;AAM/C,SAAK,UAAU;AAPoC;AASrD,iBAAe;AACb,0BAAsB,SAAS,sCAAsC;AAKnE,UAAI,CAAC,KAAK,MAAM;AACd,eAAO;AAN0D;AASnE,UAAI,KAAK,QAAQ,iBAAiB;AAChC,aAAK,kBAAkB;AACvB,eAAO;AAX0D;AAcnE,UAAI,iBAAiB,IAAI,SAAS,KAAK,YAAY,KAAK,MAAM;AAE9D,UAAI,KAAK,QAAQ,cAAc;AAC7B,aAAK,QAAQ,aAAa,aAAa;AAjB0B;AAmBnE,aAAO;AApBgB;AAuBzB,wBAAoB,SAAS,oCAAoC;AAC/D,UAAI,CAAC,KAAK,MAAM;AACd,eAAO;AAFsD;AAK/D,UAAI,KAAK,QAAQ,iBAAiB;AAChC,aAAK,kBAAkB;AACvB,eAAO;AAPsD;AAU/D,UAAI,OAAO,yBAAc,IAAI,WAAW,KAAK;AAC7C,UAAI,WAAW,KAAK;AAGpB,UAAI,MAAO,cAAc,KAAK,WAAW,aAAa,KAAK,QAAQ;AACnE,UAAI,OAAO,+BAA+B,WAAW,WAAW,MAAM;AAEtE,UAAI,KAAK,QAAQ,cAAc;AAC7B,aAAK,QAAQ,aAAa,aAAa,MAAM;AAlBgB;AAqB/D,aAAO;AA5CgB;AA+CzB,sBACI,SAAS,gCAAgC,MAAM,WAAW;AAC5D,UAAM,eAAa,KAAK,iBAAiB;AACvC,YAAI,OAAO,KAAK,IAAI,KAAK,aAAa,WAAW;AACjD,YAAI,SAAS,GAAG;AAGhB,YAAI,KAAK,QAAQ,mBAAmB,sBAAsB,OAAO;AAC/D,cAAI;cAAM,KAAK;AACf,eAAK,IAAI,GAAG,MAAM,KAAK,QAAQ,IAAI,KAAK,KAAK;AAC3C,sBAAU,KAAK;AAEf,gBAAI,QAAQ,SAAS,WAAW;AAC9B,qBAAO,QAAQ,KAAK,KAAK;AAD3B,mBAEO;AACL,qBAAO;AANkC;AAS3C,kBAAM,OAAO,QAAQ,MAAM,MAAM,OAAO;AAXqB;AAc/D,eAAK,eAAe,aAAa,IAAI,SAAS,KAAK,QAAQ;AAd7D,eAeO;AAGL,eAAK,eAAe,aAAa,UAAS,GAAG,MAAM;AACjD,iBAAK,IAAI,GAAG,MAAM,KAAK,QAAQ,IAAI,KAAK,KAAK;AAC3C,wBAAU,KAAK;AAEf,kBAAI,QAAQ,QAAQ,SAAS;AAC3B,wBAAQ,OAAO,CAAC,MAAM,CAAC;AAJkB;AAO3C,gBAAE,QAAQ,KAAK,MAAM,GAAG,QAAQ;AARe;AAAnD;AAvBqC;AADmB;AAqC5D,aAAO,KAAK,eAAe;AArFJ;AAAA;AAyF3B,SAAO;AAGT,CArGsB;QAsGpB;QACA,wB;;;;;;;;;;;;;;ACza+C;;AACtB;;AAE3B,IAAI,aAAa;AAEjB,WAAW;AACT,UAAQ,SAAS,mBAAmB,KAAK;AACvC,QAAI,OAAO,IAAI;AACf,QAAI,aAAa,IAAI;AACrB,QAAI,KAAK,IAAI;AACb,QAAI,KAAK,IAAI;AACb,QAAI,KAAK,IAAI;AACb,QAAI,KAAK,IAAI;AACb;AACE,YAAM;AACN,kBAAY,SAAS,uBAAuB,KAAK;AAC/C,YAAI;AACJ,YAAI,SAAS,SAAS;AACpB,iBAAO,IAAI,qBAAqB,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;AAD1D,eAEO,IAAI,SAAS,UAAU;AAC5B,iBAAO,IAAI,qBAAqB,GAAG,IAAI,GAAG,IAAI,IAAI,GAAG,IAAI,GAAG,IAAI;AALnB;AAQ/C,aAAK,IAAI,IAAI,GAAG,KAAK,WAAW,QAAQ,IAAI,IAAI,EAAE,GAAG;AACnD,cAAI,IAAI,WAAW;AACnB,eAAK,aAAa,EAAE,IAAI,EAAE;AAVmB;AAY/C,eAAO;AAdJ;AAAA;AARc;AAAA;AA4BzB,IAAI,4BAA6B,0BAA0B;AACzD,WAAS,aAAa,MAAM,SAAS,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;AAE3D,QAAI,SAAS,QAAQ;QAAQ,SAAS,QAAQ;AAC9C,QAAI,QAAQ,KAAK;QAAM,UAAU,KAAK,QAAQ;AAC9C,QAAI;AACJ,QAAI,OAAO,KAAK,KAAK,OAAO,KAAK,IAAI;AACnC,YAAM;AAAI,WAAK;AAAI,WAAK;AAAK,YAAM;AAAI,WAAK;AAAI,WAAK;AANI;AAQ3D,QAAI,OAAO,KAAK,KAAK,OAAO,KAAK,IAAI;AACnC,YAAM;AAAI,WAAK;AAAI,WAAK;AAAK,YAAM;AAAI,WAAK;AAAI,WAAK;AATI;AAW3D,QAAI,OAAO,KAAK,KAAK,OAAO,KAAK,IAAI;AACnC,YAAM;AAAI,WAAK;AAAI,WAAK;AAAK,YAAM;AAAI,WAAK;AAAI,WAAK;AAZI;AAc3D,QAAI,KAAM,QAAO,MAAM,QAAQ,WAAW,QAAQ;AAClD,QAAI,KAAM,QAAO,KAAK,KAAK,QAAQ,WAAW,QAAQ;AACtD,QAAI,KAAM,QAAO,MAAM,QAAQ,WAAW,QAAQ;AAClD,QAAI,KAAM,QAAO,KAAK,KAAK,QAAQ,WAAW,QAAQ;AACtD,QAAI,KAAM,QAAO,MAAM,QAAQ,WAAW,QAAQ;AAClD,QAAI,KAAM,QAAO,KAAK,KAAK,QAAQ,WAAW,QAAQ;AACtD,QAAI,MAAM,IAAI;AACZ;AArByD;AAuB3D,QAAI,MAAM,OAAO;QAAK,MAAM,OAAO,KAAK;QAAI,MAAM,OAAO,KAAK;AAC9D,QAAI,MAAM,OAAO;QAAK,MAAM,OAAO,KAAK;QAAI,MAAM,OAAO,KAAK;AAC9D,QAAI,MAAM,OAAO;QAAK,MAAM,OAAO,KAAK;QAAI,MAAM,OAAO,KAAK;AAE9D,QAAI,OAAO,KAAK,MAAM;QAAK,OAAO,KAAK,MAAM;AAC7C,QAAI,IAAI,KAAK,KAAK;AAClB,QAAI,IAAI,KAAK,KAAK;AAClB,QAAI;AACJ,SAAK,IAAI,IAAI,MAAM,KAAK,MAAM,KAAK;AACjC,UAAI,IAAI,IAAI;AACV,YAAI,IAAI,KAAK,IAAI,OAAO,KAAK,IAAK,MAAW,WAAK;AAClD,aAAK,KAAM,MAAK,MAAM;AACtB,cAAM,MAAO,OAAM,OAAO;AAC1B,cAAM,MAAO,OAAM,OAAO;AAC1B,cAAM,MAAO,OAAM,OAAO;AAL5B,aAMO;AACL,YAAI,IAAI,KAAK,IAAI,OAAO,KAAK,IAAK,MAAW,WAAK;AAClD,aAAK,KAAM,MAAK,MAAM;AACtB,cAAM,MAAO,OAAM,OAAO;AAC1B,cAAM,MAAO,OAAM,OAAO;AAC1B,cAAM,MAAO,OAAM,OAAO;AAZK;AAcjC,UAAI,IAAI,KAAK,IAAI,IAAI,KAAK,IAAK,MAAW,WAAK;AAC/C,WAAK,KAAM,MAAK,MAAM;AACtB,YAAM,MAAO,OAAM,OAAO;AAC1B,YAAM,MAAO,OAAM,OAAO;AAC1B,YAAM,MAAO,OAAM,OAAO;AAC1B,UAAI,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI;AAClC,UAAI,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI;AAClC,UAAI,IAAI,UAAU,IAAI,MAAM;AAC5B,WAAK,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK;AAC/B,YAAK,MAAW,WAAK;AACrB,YAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;AAC5B,cAAM,OAAQ,MAAO,OAAM,OAAO,IAAK;AACvC,cAAM,OAAQ,MAAO,OAAM,OAAO,IAAK;AACvC,cAAM,OAAQ,MAAO,OAAM,OAAO,IAAK;AACvC,cAAM,OAAO;AA5BkB;AA/BwB;AADJ;AAiEzD,WAAS,WAAW,MAAM,QAAQ,SAAS;AACzC,QAAI,KAAK,OAAO;AAChB,QAAI,KAAK,OAAO;AAChB,QAAI,GAAG;AACP,YAAQ,OAAO;AACb,WAAK;AACH,YAAI,iBAAiB,OAAO;AAC5B,YAAI,OAAO,KAAK,MAAM,GAAG,SAAS,kBAAkB;AACpD,YAAI,OAAO,iBAAiB;AAC5B,aAAK,IAAI,GAAG,IAAI,MAAM,KAAK;AACzB,cAAI,IAAI,IAAI;AACZ,eAAK,IAAI,IAAI,GAAG,IAAI,MAAM,KAAK,KAAK;AAClC,yBAAa,MAAM,SACjB,GAAG,IAAI,GAAG,IAAI,IAAI,GAAG,IAAI,iBACzB,GAAG,IAAI,GAAG,IAAI,IAAI,GAAG,IAAI;AAC3B,yBAAa,MAAM,SACjB,GAAG,IAAI,iBAAiB,IAAI,GAAG,IAAI,IAAI,GAAG,IAAI,iBAC9C,GAAG,IAAI,iBAAiB,IAAI,GAAG,IAAI,IAAI,GAAG,IAAI;AARzB;AAJ7B;AAeE;AACF,WAAK;AACH,aAAK,IAAI,GAAG,KAAK,GAAG,QAAQ,IAAI,IAAI,KAAK,GAAG;AAC1C,uBAAa,MAAM,SACjB,GAAG,IAAI,GAAG,IAAI,IAAI,GAAG,IAAI,IACzB,GAAG,IAAI,GAAG,IAAI,IAAI,GAAG,IAAI;AAJ/B;AAME;AACF;AACE,cAAM,IAAI,MAAM;;AA9FmC;AAkGzD,WAAS,iBAAiB,QAAQ,eAAe,QAAQ,QAAQ,SACvC,iBAAiB,gBAAgB;AAGzD,QAAI,iBAAiB;AAErB,QAAI,mBAAmB;AAGvB,QAAI,cAAc;AAElB,QAAI,UAAU,KAAK,MAAM,OAAO;AAChC,QAAI,UAAU,KAAK,MAAM,OAAO;AAChC,QAAI,cAAc,KAAK,KAAK,OAAO,MAAM;AACzC,QAAI,eAAe,KAAK,KAAK,OAAO,MAAM;AAE1C,QAAI,QAAQ,KAAK,IAAI,KAAK,KAAK,KAAK,IAAI,cAAc,cAAc,KAClE,kBAAkB;AACpB,QAAI,SAAS,KAAK,IAAI,KAAK,KAAK,KAAK,IAAI,eAAe,cAAc,KACpE,kBAAkB;AACpB,QAAI,SAAS,cAAc;AAC3B,QAAI,SAAS,eAAe;AAE5B,QAAI;AACF;AACA;AACA,eAAS,CAAC;AACV,eAAS,CAAC;AACV,cAAQ,IAAI;AACZ,cAAQ,IAAI;AANA;AASd,QAAI,cAAc,QAAQ,cAAc;AACxC,QAAI,eAAe,SAAS,cAAc;AAE1C,QAAI,QAAQ,WAAW,GAAG;AAC1B,QAAI,kBAAW,WAAW;AACxB,eAAS,kBAAW,YAAY,OAAO,QAAQ,iBACf,SAAS;AAGzC,kBAAY,eAAe,UAAU,QAAQ,aAAa,cACrB;AACrC,gBAAU,QAAQ,UAAU,QAAQ,aAAa;AACjD,eAAS,UAAU;AARrB,WASO;AACL,kBAAY,eAAe,UAAU,QAAQ,aAAa,cACrB;AACrC,UAAI,SAAS,UAAU;AAEvB,UAAI,OAAO,OAAO,gBAAgB,OAAO;AACzC,UAAI,iBAAiB;AACnB,YAAI,QAAQ,KAAK;AACjB,aAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,IAAI,IAAI,KAAK,GAAG;AAC7C,gBAAM,KAAK,gBAAgB;AAC3B,gBAAM,IAAI,KAAK,gBAAgB;AAC/B,gBAAM,IAAI,KAAK,gBAAgB;AAC/B,gBAAM,IAAI,KAAK;AANE;AANhB;AAeL,WAAK,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACnC,mBAAW,MAAM,QAAQ,IAAI;AAhB1B;AAkBL,aAAO,aAAa,MAAM,aAAa;AACvC,eAAS,UAAU;AA/DoC;AAkEzD;AACE;AACA,eAAS,UAAU,cAAc;AACjC,eAAS,UAAU,cAAc;AACjC;AACA;AALK;AArKgD;AA6KzD,SAAO;AA7Kc,CAAC;AAgLxB,WAAW;AACT,UAAQ,SAAS,YAAY,KAAK;AAEhC,QAAI,SAAS,IAAI;AACjB,QAAI,SAAS,IAAI;AACjB,QAAI,UAAU,IAAI;AAClB,QAAI,SAAS,IAAI;AACjB,QAAI,SAAS,IAAI;AAEjB,QAAI,aAAa,IAAI;AACrB;AACE,YAAM;AACN,kBAAY,SAAS,gBAAgB,KAAK,OAAO,aAAa;AAC5D,YAAI;AACJ,YAAI,aAAa;AACf,kBAAQ,WAAK,8BAA8B,IAAI;AADjD,eAEO;AAEL,kBAAQ,WAAK,8BAA8B,MAAM;AACjD,cAAI,QAAQ;AACV,gBAAI,cAAc,WAAK,8BAA8B;AACrD,oBAAQ,CAAC,MAAM,KAAK,YAAY,IACvB,MAAM,KAAK,YAAY;AAN7B;AAJqD;AAiB5D,YAAI,yBAAyB,iBAAiB,QAAQ,OAAO,QAC3D,QAAQ,SAAS,cAAc,OAAO,YACtC,MAAM;AAER,YAAI,CAAC,aAAa;AAChB,cAAI,aAAa,MAAM,KAAK,MAAM;AAClC,cAAI,QAAQ;AACV,gBAAI,UAAU,MAAM,KAAK;AAHX;AArB0C;AA4B5D,YAAI,UAAU,uBAAuB,SACvB,uBAAuB;AACrC,YAAI,MAAM,uBAAuB,QACvB,uBAAuB;AAEjC,eAAO,IAAI,cAAc,uBAAuB,QAAQ;AAnCrD;AAAA;AAVO;AAAA;AAmDlB,WAAW;AACT,UAAQ,SAAS,eAAe;AAC9B;AACE,YAAM;AACN,kBAAY,SAAS,0BAA0B;AAC7C,eAAO;AAHJ;AAAA;AAFQ;AAAA;AAWnB,SAAS,wBAAwB,KAAK;AACpC,MAAI,YAAY,WAAW,IAAI;AAC/B,MAAI,CAAC,WAAW;AACd,UAAM,IAAW,4BAAmB,IAAI;AAHN;AAKpC,SAAO,UAAU,OAAO;AAnS1B;AAsSA,IAAI,yBAA0B,uBAAuB;AACnD,MAAI;AACF,aAAS;AACT,eAAW;AAFG;AAKhB,MAAI,mBAAmB;AAEvB,WAAS,cAAc,IAAI,OAAO,KAAK,uBAAuB,eAAe;AAC3E,SAAK,eAAe,GAAG;AACvB,SAAK,SAAS,GAAG,MAAM,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG;AACvC,SAAK,OAAO,GAAG;AACf,SAAK,QAAQ,GAAG;AAChB,SAAK,QAAQ,GAAG;AAChB,SAAK,YAAY,GAAG;AACpB,SAAK,aAAa,GAAG;AACrB,SAAK,QAAQ;AACb,SAAK,wBAAwB;AAC7B,SAAK,gBAAgB;AACrB,SAAK,OAAO;AACZ,SAAK,MAAM;AApBsC;AAuBnD,gBAAc;AACZ,yBAAqB,SAAS,iCAAiC,OAAO;AACpE,UAAI,eAAe,KAAK;AACxB,UAAI,OAAO,KAAK;AAChB,UAAI,QAAQ,KAAK;AACjB,UAAI,QAAQ,KAAK;AACjB,UAAI,YAAY,KAAK;AACrB,UAAI,aAAa,KAAK;AACtB,UAAI,QAAQ,KAAK;AACjB,UAAI,wBAAwB,KAAK;AAEjC,sBAAK,iBAAiB;AAEtB,UAAI,KAAK,KAAK;UAAI,KAAK,KAAK;UAAI,KAAK,KAAK;UAAI,KAAK,KAAK;AAExD,UAAI,UAAU,CAAC,IAAI;AAEnB,UAAI,WAAW,CAAC,KAAK,OAAO,KAAK;AAEjC,UAAI,QAAQ,SAAS,KAAK,QAAQ;AAClC,UAAI,SAAS,SAAS,KAAK,QAAQ;AAGnC,UAAI,cAAc,WAAK,8BAA8B,KAAK;AAC1D,UAAI,iBAAiB,WAAK,8BACxB,KAAK;AACP,UAAI,gBAAgB,CAAC,YAAY,KAAK,eAAe,IACnD,YAAY,KAAK,eAAe;AAMlC,cAAQ,KAAK,IAAI,KAAK,KAAK,KAAK,IAAI,QAAQ,cAAc,MACxD;AAEF,eAAS,KAAK,IAAI,KAAK,KAAK,KAAK,IAAI,SAAS,cAAc,MAC1D;AAEF,UAAI,YAAY,MAAM,eAAe,UAAU,WAC7C,OAAO,QAAQ;AACjB,UAAI,SAAS,UAAU;AACvB,UAAI,WAAW,sBAAsB,qBAAqB;AAC1D,eAAS,aAAa,MAAM;AAE5B,WAAK,+BAA+B,QAAQ,WAAW;AAEvD,WAAK,SAAS,OAAO,QAAQ,OAAO;AACpC,WAAK,iBAAiB;AAGtB,UAAI,eAAe,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,QAAQ,IAAI,CAAC,QAAQ;AACtD,eAAS,UAAU,MAAM,UAAU;AAEnC,WAAK,SAAS,UAAU,MAAM,IAAI,IAAI,IAAI;AAE1C,eAAS,oBAAoB;AAC7B,aAAO,UAAU;AAzDK;AA4DxB,cAAU,SAAS,uBAAuB,OAAO,QAAQ,OAAO,OAAO;AACrE,WAAK,QAAQ,CAAC,QAAQ,OAAO,SAAS;AA7DhB;AAgExB,sBAAkB,SAAS,+BAA+B,UAAU;AAClE,UAAI,QAAQ,KAAK;AACjB,UAAI,WAAW,CAAC,MAAM,IAAI,GAAG,GAAG,MAAM,IAAI,GAAG;AAC7C,eAAS,UAAU,MAAM,UAAU;AAnEb;AAsExB,oBAAgB,SAAS,+BAA+B;AACtD,UAAI,QAAQ,KAAK;AACjB,WAAK,IAAI,MAAM,IAAI,MAAM,IAAI,IAAI,MAAM;AAxEjB;AA2ExB,cAAU,SAAS,SAAS,UAAU,MAAM,IAAI,IAAI,IAAI,IAAI;AAC1D,UAAI,mBAAQ,SAAS,KAAK,WAAW,GAAG;AACtC,YAAI,YAAY,KAAK;AACrB,YAAI,aAAa,KAAK;AACtB,iBAAS,IAAI,KAAK,IAAI,IAAI,WAAW;AACrC,iBAAS;AACT,iBAAS;AAN+C;AA3EpC;AAqFxB,oCACE,SAAS,+BAA+B,SAAS,WAAW,OAAO;AACjE,cAAQ;AACN,aAAK,UAAU;AACb,cAAI,MAAM,KAAK;AACf,kBAAQ,YAAY,IAAI;AACxB,kBAAQ,cAAc,IAAI;AAC1B;AACF,aAAK,UAAU;AACb,cAAI,WAAW,WAAK,WAAW,MAAM,IAAI,MAAM,IAAI,MAAM;AACzD,kBAAQ,YAAY;AACpB,kBAAQ,cAAc;AACtB;AACF;AACE,gBAAuB,mDAA0B;;AAnGjC;AAuGxB,gBAAY,SAAS,yBAAyB,KAAK,OAAO;AACxD,UAAI,yBAAyB,KAAK,oBAAoB;AAEtD,YAAM,KAAK;AACX,UAAI,aAAa,MAAM,KAAK,KAAK;AACjC,UAAI,UAAU,MAAM,KAAK,KAAK;AAC9B,WAAK;AAEL,aAAO,IAAI,cAAc,wBAAwB;AA/G3B;AAAA;AAmH1B,SAAO;AAGT,CA7IqB;QA8InB;QACA,8B;;;;;;;;;;;;;;ACta8C;;AAGhD,IAAI,kCAAmC,gCAAgC;AACrE,WAAS,uBAAuB,QAAQ;AAAuB;;AAC7D,sBAAO;AAEP,SAAK,gBAAgB;AACrB,QAAI,cAAc,OAAO;AACzB,QAAI,eAAe,YAAY,SAAS,GAAG;AACzC,UAAI,SAAS,IAAI,WAAW,aAAa;AACzC,WAAK,cAAc,KAAK;AAPmC;AAU7D,SAAK,yBAAyB;AAC9B,SAAK,oBAAoB,CAAE,OAAO;AAClC,SAAK,wBAAwB,CAAE,OAAO;AACtC,SAAK,iBAAiB,OAAO;AAE7B,SAAK,qBAAqB;AAC1B,SAAK,gBAAgB;AAErB,SAAK,uBAAuB,iBAAiB,UAAC,OAAO,OAAU;AAC7D,YAAK;AAAiB;AAAO;AAAT;AADtB;AAIA,SAAK,uBAAuB,oBAAqB,kBAAW;AAC1D,YAAK,YAAY,EAAE;AADrB;AAIA,SAAK,uBAAuB,2BAA4B,iBAAU;AAChE,YAAK,eAAe,EAAE;AADxB;AAIA,SAAK,uBAAuB;AA/BuC;AAiCrE,yBAAuB;AACrB,oBAAgB,SAAS,qCAAqC,MAAM;AACjE,UAAI,SAAS,IAAI,WAAW,KAAK,OAAO;AACxC,UAAI,KAAK,UAAU,WAAW;AAC5B,YAAI,KAAK,oBAAoB;AAC3B,eAAK,mBAAmB,SAAS;AADnC,eAEO;AACL,eAAK,cAAc,KAAK;AAJE;AAA9B,aAMO;AACL,YAAI,aAAa,cAAc,KAAK,UAAU,aAAa;AACzD,cAAI,YAAY,WAAW,KAAK,OAAO;AACrC,mBAAO;AAFgD;AAIzD,sBAAY,SAAS;AACrB,iBAAO;AALG;AAOZ,0BAAO;AAhBwD;AADnC;AAqBjC,iBAAa,SAAS,sCAAsC,KAAK;AAC9D,UAAI,KAAK,cAAc,SAAS,GAAG;AAEjC,YAAI,cAAc,KAAK,cAAc;AACrC,YAAI,YAAY,YAAY;AAC1B,sBAAY,WAAW,EAAE,QAAQ,IAAI;AAJN;AAD2B;AArBhC;AA+BjC,wBACI,SAAS,yCAAyC,QAAQ;AAC5D,UAAI,IAAI,KAAK,cAAc,QAAQ;AACnC,UAAI,KAAK,GAAG;AACV,aAAK,cAAc,OAAO,GAAG;AAH6B;AAhC7B;AAuCjC,mBAAe,SAAS,uCAAuC;AAC7D,wBAAO,CAAC,KAAK;AACb,UAAI,eAAe,KAAK;AACxB,WAAK,gBAAgB;AACrB,aAAO,IAAI,6BAA6B,MAAM;AA3Cf;AA8CjC,oBAAgB,SAAS,sCAAsC,OAAO,KAAK;AACzE,UAAI,SAAS,IAAI,kCAAkC,MAAM,OAAO;AAChE,WAAK,uBAAuB,iBAAiB,OAAO;AACpD,WAAK,cAAc,KAAK;AACxB,aAAO;AAlDwB;AAqDjC,uBACI,SAAS,yCAAyC,QAAQ;AAC5D,UAAI,KAAK,oBAAoB;AAC3B,aAAK,mBAAmB,OAAO;AAF2B;AAI5D,UAAI,UAAU,KAAK,cAAc,MAAM;AACvC,cAAQ,QAAQ,UAAU,aAAa;AACrC,oBAAY,OAAO;AADrB;AAGA,WAAK,uBAAuB;AA9DG;AAAA;AAmEnC,WAAS,6BAA6B,QAAQ,cAAc;AAC1D,SAAK,UAAU;AACf,SAAK,QAAQ;AACb,SAAK,gBAAgB,gBAAgB;AACrC,SAAK,YAAY;AACjB,SAAK,gBAAgB,QAAQ;AAC7B,WAAO,qBAAqB;AAE5B,SAAK,aAAa;AA5GiD;AA8GrE,+BAA6B;AAC3B,cAAU,SAAS,qCAAqC,OAAO;AAC7D,UAAI,KAAK,OAAO;AACd;AAF2D;AAI7D,UAAI,KAAK,UAAU,SAAS,GAAG;AAC7B,YAAI,oBAAoB,KAAK,UAAU;AACvC,0BAAkB;AAAU,iBAAO;AAAO,gBAAM;AAAtB;AAC1B;AAP2D;AAS7D,WAAK,cAAc,KAAK;AAVa;AAavC,QAAI,eAAe;AACjB,aAAO,KAAK;AAdyB;AAiBvC,QAAI,mBAAmB;AACrB,aAAO,KAAK,QAAQ;AAlBiB;AAqBvC,QAAI,uBAAuB;AACzB,aAAO,KAAK,QAAQ;AAtBiB;AAyBvC,QAAI,gBAAgB;AAClB,aAAO,KAAK,QAAQ;AA1BiB;AA6BvC,UAAM,SAAS,oCAAoC;AACjD,UAAI,KAAK,cAAc,SAAS,GAAG;AACjC,YAAI,QAAQ,KAAK,cAAc;AAC/B,uBAAe;AAAU,iBAAO;AAAO,gBAAM;AAAtB,SAAhB;AAHwC;AAKjD,UAAI,KAAK,OAAO;AACd,uBAAe;AAAU,iBAAO;AAAW,gBAAM;AAA1B,SAAhB;AANwC;AAQjD,UAAI,oBAAoB;AACxB,WAAK,UAAU,KAAK;AACpB,aAAO,kBAAkB;AAvCY;AA0CvC,YAAQ,SAAS,oCAAoC,QAAQ;AAC3D,WAAK,QAAQ;AACb,WAAK,UAAU,QAAQ,UAAU,mBAAmB;AAClD,0BAAkB;AAAU,iBAAO;AAAW,gBAAM;AAA1B;AAD5B;AAGA,WAAK,YAAY;AA/CoB;AAAA;AAoDzC,WAAS,kCAAkC,QAAQ,OAAO,KAAK;AAC7D,SAAK,UAAU;AACf,SAAK,SAAS;AACd,SAAK,OAAO;AACZ,SAAK,eAAe;AACpB,SAAK,YAAY;AACjB,SAAK,QAAQ;AAEb,SAAK,aAAa;AA1KiD;AA4KrE,oCAAkC;AAChC,cAAU,SAAS,0CAA0C,OAAO;AAClE,UAAI,KAAK,OAAO;AACd;AAFgE;AAIlE,UAAI,KAAK,UAAU,WAAW,GAAG;AAC/B,aAAK,eAAe;AADtB,aAEO;AACL,YAAI,qBAAqB,KAAK,UAAU;AACxC,2BAAmB;AAAU,iBAAO;AAAO,gBAAM;AAAtB;AAC3B,aAAK,UAAU,QAAQ,UAAU,mBAAmB;AAClD,4BAAkB;AAAU,mBAAO;AAAW,kBAAM;AAA1B;AAD5B;AAGA,aAAK,YAAY;AAZ+C;AAclE,WAAK,QAAQ;AACb,WAAK,QAAQ,mBAAmB;AAhBU;AAmB5C,QAAI,uBAAuB;AACzB,aAAO;AApBmC;AAuB5C,UAAM,SAAS,yCAAyC;AACtD,UAAI,KAAK,cAAc;AACrB,YAAI,QAAQ,KAAK;AACjB,aAAK,eAAe;AACpB,uBAAe;AAAU,iBAAO;AAAO,gBAAM;AAAtB,SAAhB;AAJ6C;AAMtD,UAAI,KAAK,OAAO;AACd,uBAAe;AAAU,iBAAO;AAAW,gBAAM;AAA1B,SAAhB;AAP6C;AAStD,UAAI,oBAAoB;AACxB,WAAK,UAAU,KAAK;AACpB,aAAO,kBAAkB;AAlCiB;AAqC5C,YAAQ,SAAS,yCAAyC,QAAQ;AAChE,WAAK,QAAQ;AACb,WAAK,UAAU,QAAQ,UAAU,mBAAmB;AAClD,0BAAkB;AAAU,iBAAO;AAAW,gBAAM;AAA1B;AAD5B;AAGA,WAAK,YAAY;AACjB,WAAK,QAAQ,mBAAmB;AA3CU;AAAA;AA+C9C,SAAO;AAGT,CA9N8B;QA+N5B,gD;;;;;;;ACjOF;;AAEA,IAAI,eACgC;AACpC,IAAI,aACgC;AAEpC,IAAI,kBAAkB,oBAAQ;AAC9B,IAAI,qBAAqB,oBAAQ;AACjC,IAAI,kBAAkB,oBAAQ;AAC9B,IAAI,wBAAwB,oBAAQ;AACpC,IAAI,8BAA8B,oBAAQ;AAC1C,IAAI,uBAAuB,oBAAQ;AACnC,IAAI,kBAAkB,oBAAQ;AAGe;AAC3C,sBAAQ;AAjCV;AAoCA,QAAQ,QAAQ,mBAAmB;AACnC,QAAQ,QAAQ,gBAAgB;AAChC,QAAQ,UAAU,gBAAgB;AAClC,QAAQ,cAAc,gBAAgB;AACtC,QAAQ,eAAe,gBAAgB;AACvC,QAAQ,wBAAwB,gBAAgB;AAChD,QAAQ,YAAY,gBAAgB;AACpC,QAAQ,kBAAkB,sBAAsB;AAChD,QAAQ,kBAAkB,4BAA4B;AACtD,QAAQ,cAAc,qBAAqB;AAC3C,QAAQ,0BAA0B,gBAAgB;AAClD,QAAQ,oBAAoB,gBAAgB;AAC5C,QAAQ,sBAAsB,gBAAgB;AAC9C,QAAQ,sBAAsB,gBAAgB;AAC9C,QAAQ,cAAc,gBAAgB;AACtC,QAAQ,sBAAsB,gBAAgB;AAC9C,QAAQ,8BACN,gBAAgB;AAClB,QAAQ,MAAM,gBAAgB;AAC9B,QAAQ,uBAAuB,gBAAgB;AAC/C,QAAQ,aAAa,qBAAqB;AAC1C,QAAQ,yBAAyB,gBAAgB;AACjD,QAAQ,kBAAkB,gBAAgB;AAC1C,QAAQ,uBAAuB,gBAAgB;AAC/C,QAAQ,SAAS,gBAAgB;AACjC,QAAQ,aAAa,gBAAgB;AACrC,QAAQ,8BACN,qBAAqB;AACvB,QAAQ,qBAAqB,qBAAqB;AAClD,QAAQ,oBAAoB,qBAAqB;AACjD,QAAQ,YAAY,gBAAgB,U;;;;;;;;;;;AC/CpC,IAEK,OAAO,UAAU,eAAe,CAAC,MAAM,sBAAuB;AAEnE,MAAI,cACD,OAAO,WAAW,eAAe,OAAO,SAAS,OAAQ,SACzD,OAAO,WAAW,eAAe,OAAO,SAAS,OAAQ,SACzD,OAAO,SAAS,eAAe,KAAK,SAAS,OAAQ,OAC9C,MAA8C,eAAO;AAE/D,MAAI,YAAa,OAAO,cAAc,eAAe,UAAU,aAAc;AAC7E,MAAI,YAAY,UAAU,KAAK;AAC/B,MAAI,gBAAgB,sBAAsB,KAAK;AAC/C,MAAI,gBAAgB,sBAAsB,KAAK;AAC/C,MAAI,WAAW,UAAU,QAAQ,YAAY;AAC7C,MAAI,uBAAuB,oBAAoB,KAAK;AACpD,MAAI,cAAc,UAAU,QAAQ,YAAY;AAChD,MAAI,OAAO,UAAU,QAAQ,cAAc;AAC3C,MAAI,QAAQ,4BAA4B,KAAK;AAC7C,MAAI,UAAU,UAAU,QAAQ,YAAY;AAC5C,MAAI,WAAW,WAAW,KAAK,cAChB,CAAC,uBAAuB,KAAK;AAE5C,MAAI,SAAS,QAAO,4DAAW,YAAY,QAAO,gEAAa;AAI/D,MAAI,OAAO,UAAU,aAAa;AAChC,gBAAY,QAAQ;AA1B6C;AA6BnE,QAAM,uBAAuB;AAI5B,YAAS,+BAA+B;AACvC,QAAI,OAAO,eAAe,aAAa;AAErC,UAAI,OAAO,WAAW,UAAU,aAAa,aAAa;AACxD,mBAAW,UAAU,WAAW,SAAS,SAAS,OAAO,KAAK;AAC5D,iBAAO,IAAI,WAAW,KAAK,MAAM,OAAO;AAD1C;AAGA,qBAAa,UAAU,WAAW,SAAS,SAAS,OAAO,KAAK;AAC9D,iBAAO,IAAI,aAAa,KAAK,MAAM,OAAO;AAD5C;AANmC;AAYrC,UAAI,OAAO,iBAAiB,aAAa;AACvC,oBAAY,eAAe;AAbQ;AAerC;AAhBqC;AAmBvC,aAAS,SAAS,OAAO,KAAK;AAC5B,aAAO,IAAI,WAAW,KAAK,MAAM,OAAO;AApBH;AAuBvC,aAAS,eAAe,OAAO,QAAQ;AACrC,UAAI,UAAU,SAAS,GAAG;AACxB,iBAAS;AAF0B;AAIrC,WAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAI,GAAG,EAAE,GAAG,EAAE,QAAQ;AACtD,aAAK,UAAU,MAAM,KAAK;AALS;AAvBA;AAgCvC,aAAS,gBAAgB,QAAQ,QAAQ;AACvC,WAAK,SAAS;AACd,WAAK,aAAa,OAAO;AACzB,WAAK,SAAS;AACd,iCAA2B,KAAK;AApCK;AAsCvC,oBAAgB,YAAY,OAAO,OAAO;AAE1C,QAAI,yBAAyB;AAC7B,aAAS,sBAAsB,OAAO;AACpC;AACE,4BAAM;AACJ,cAAI,SAAS,KAAK;cAAQ,SAAS,SAAS;AAC5C,iBAAQ,QAAO,UAAW,OAAO,SAAS,MAAM,IAC7C,OAAO,SAAS,MAAM,KAAO,OAAO,SAAS,MAAM,QAAS;AAJ5D;AAML,0BAAI,OAAO;AACT,cAAI,SAAS,KAAK;cAAQ,SAAS,SAAS;AAC5C,iBAAO,UAAU,QAAQ;AACzB,iBAAO,SAAS,KAAM,SAAS,IAAK;AACpC,iBAAO,SAAS,KAAM,SAAS,KAAM;AACrC,iBAAO,SAAS,KAAM,UAAU,KAAM;AAXnC;AAAA;AA1C8B;AA0DvC,aAAS,2BAA2B,QAAQ;AAC1C,aAAO,yBAAyB,QAAQ;AACtC,eAAO,eAAe,gBAAgB,WACpC,wBACA,sBAAsB;AACxB;AALwC;AA1DL;AAmEvC,aAAS,WAAW,MAAM;AACxB,UAAI,QAAQ,GAAG;AACf,UAAI,OAAO,SAAS,UAAU;AAC5B,iBAAS;AACT,aAAK,IAAI,GAAG,IAAI,MAAM,EAAE,GAAG;AACzB,iBAAO,KAAK;AAHc;AAA9B,iBAKW,WAAW,MAAM;AAC1B,iBAAS,KAAK,MAAM;AADf,aAEA;AACL,iBAAS;AACT,aAAK,IAAI,GAAG,IAAI,KAAK,QAAQ,IAAI,GAAG,EAAE,GAAG;AACvC,iBAAO,KAAK,KAAK;AAHd;AATiB;AAgBxB,aAAO,WAAW;AAClB,aAAO,SAAS;AAChB,aAAO,aAAa,OAAO;AAC3B,aAAO,MAAM;AAEb,UAAI,QAAO,wDAAS,YAAY,KAAK,QAAQ;AAC3C,eAAO,SAAS,KAAK;AAtBC;AAwBxB,aAAO;AA3F8B;AA8FvC,gBAAY,aAAa;AACzB,gBAAY,YAAY;AAIxB,gBAAY,aAAa;AACzB,gBAAY,cAAc;AAC1B,gBAAY,eAAe;AAC3B,gBAAY,eAAe;AAE3B,gBAAY,cAAc,YAAY;AACpC,UAAI,UAAU,WAAW,GAAG;AAE1B,YAAI,UAAU,OAAO,GAAG;AACtB,gBAAM,IAAI,MAAM;AAHQ;AAK1B,eAAO,IAAI,gBAAgB,UAAU,IAAI,UAAU;AANjB;AAQpC,aAAO,WAAW,MAAM,MAAM;AARhC;AAxGF;AAsHC,YAAS,yBAAyB;AACjC,QAAI,CAAC,UAAU,CAAC,OAAO,kBAAkB;AACvC;AAF+B;AAIjC,QAAI,WAAW,OAAO,iBAAiB;AACvC,QAAI,YAAY,UAAU;AACxB;AAN+B;AASjC,WAAO,eAAe,UAAU;AAC9B,0BAAM;AACJ,eAAO;AAF+B;;AAIxC,kBAAY;AACZ,oBAAc;AAL0B;AAO1C,WAAO,eAAe,UAAU;AAC9B,0BAAM;AACJ,eAAO,KAAK;AAF8B;;AAI5C,kBAAY;AACZ,oBAAc;AAL8B;AAhBhD;AA2BC,YAAS,qBAAqB;AAC7B,QAAI,CAAC,YAAY,KAAK;AACpB,kBAAY,MAAM,YAAY;AAFH;AAA/B;AAQC,YAAS,yCAAyC;AACjD,QAAI,OAAO,OAAO,mBAAmB,aAAa;AAChD,UAAI,yBAAyB;AAC7B,UAAI;AACF,YAAI,QAAQ;AAGV,iBAAO,eAAe,IAAI,SAAS,MAAM,EAAE,OAAO;AAJlD;AAOF,YAAI,OAAO,SAAS,OAAO,CAA3B;AACA,aAAK;AAAc,cAAI,KAAK,CAAX;AAAA;AACjB,eAAO,eAAe,IAAI,QAAQ;AAC9B,iBAAO;AAAI,wBAAc;AAAM,sBAAY;AAAM,oBAAU;AAA7D;AAVJ,QAWE,OAAO,GAAG;AACV,iCAAyB;AAdqB;AAgBhD,UAAI,wBAAwB;AAC1B;AAjB8C;AADD;AAsBjD,WAAO,iBAAiB,SAAS,qBAAqB,KAAK,MAAM,KAAK;AACpE,aAAO,IAAI;AACX,UAAI,SAAS,KAAK;AAChB,YAAI,iBAAiB,MAAM,IAAI;AAHmC;AAKpE,UAAI,SAAS,KAAK;AAChB,YAAI,iBAAiB,MAAM,IAAI;AANmC;AAQpE,UAAI,WAAW,KAAK;AAClB,YAAI,iBAAiB,MAAM,SAAS,2BAA2B,OAAO;AACpE,eAAK,iBAAiB,MAAM,SAAS,6BAA6B;AAChE,mBAAO;AADT;AAGA,iBAAO;AAJT;AAMA,YAAI,QAAQ,IAAI;AAfkD;AAAtE;AAtBF;AA6CC,YAAS,2CAA2C;AACnD,QAAI,OAAO,mBAAmB,aAAa;AACzC;AAFiD;AAInD,QAAI,eAAe,eAAe;AAClC,QAAI,MAAM,IAAI;AACd,QAAM,wBAAsB,MAAM;AAGhC,aAAO,eAAe,cAAc;AAClC,eAAO,SAAS,+BAA+B,UAAU,CADH;AAAA;AATP;AAanD,QAAI,kBAAkB,KAAK;AACzB;AAdiD;AAiBnD,WAAO,eAAe,cAAc;AAClC,WAAK,SAAS,gCAAgC;AAC5C,eAAO,KAAK,iBAAiB;AAFmB;AAIlD,WAAK,SAAS,8BAA8B,OAAO;AACjD,YAAI,UAAU,UAAU,UAAU,eAAe;AAC/C,eAAK,gBAAgB;AACrB,cAAI,UAAU,iBACV,OAAO,KAAK,qBAAqB,YAAY;AAC/C,iBAAK,iBAAiB;AAJuB;AADA;AAJD;AAAA;AAgBpD,QAAI,OAAO,YAAY,aAAa;AAClC,aAAO,eAAe,cAAc;AAClC,aAAK,SAAS,4BAA4B;AACxC,cAAI,KAAK,iBAAiB,eAAe;AACvC,mBAAO,IAAI,WAAW,IAAI,QAAQ,KAAK,cAAc;AAFf;AAIxC,iBAAO,KAAK;AALgC;AAAA;AAQhD;AA1CiD;AA6CnD,WAAO,eAAe,cAAc;AAClC,WAAK,SAAS,4BAA4B;AACxC,YAAI,KAAK,iBAAiB,eAAe;AACvC,iBAAO,KAAK;AAF0B;AAIxC,YAAI,OAAO,KAAK;AAChB,YAAI;YAAG,IAAI,KAAK;AAChB,YAAI,SAAS,IAAI,WAAW;AAC5B,aAAK,IAAI,GAAG,IAAI,GAAG,EAAE,GAAG;AACtB,iBAAO,KAAK,KAAK,WAAW,KAAK;AARK;AAUxC,eAAO,OAAO;AAX8B;AAAA;AA7ClD;AA+DC,YAAS,+BAA+B;AACvC,QAAI,UAAU,aAAa;AACzB;AAFqC;AAKvC,QAAI,SACF;AAEF,gBAAY,OAAO,UAAU,OAAO;AAClC,UAAI,SAAS;AACb,UAAI,GAAG;AACP,WAAK,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAI,GAAG,KAAK,GAAG;AAC3C,YAAI,KAAK,MAAM,WAAW,KAAK;AAC/B,YAAI,KAAK,MAAM,WAAW,IAAI,KAAK;AACnC,YAAI,KAAK,MAAM,WAAW,IAAI,KAAK;AACnC,YAAI,KAAK,MAAM;YAAG,KAAO,MAAK,MAAM,IAAM,MAAM;AAChD,YAAI,KAAK,IAAI,IAAI,IAAM,MAAK,QAAQ,IAAM,MAAM,IAAK;AACrD,YAAI,KAAK,IAAI,IAAI,IAAK,KAAK,OAAQ;AACnC,kBAAW,OAAO,OAAO,MAAM,OAAO,OAAO,MAClC,OAAO,OAAO,MAAM,OAAO,OAAO;AAXb;AAalC,aAAO;AAbT;AARF;AA2BC,YAAS,+BAA+B;AACvC,QAAI,UAAU,aAAa;AACzB;AAFqC;AAMvC,QAAI,SACF;AACF,gBAAY,OAAO,UAAU,OAAO;AAClC,cAAQ,MAAM,QAAQ,OAAO;AAC7B,UAAI,MAAM,SAAS,MAAM,GAAG;AAC1B,cAAM,IAAI,MAAM;AAHgB;AAKlC,WAEE,IAAI,KAAK,GAAG,IAAI,QAAQ,MAAM,GAAG,SAAS,IAEzC,SAAS,MAAM,OAAO,QAGvB,CAAY,gBAAK,KAAK,IAAI,KAAK,KAAK,SAAS,QAG3C,OAAO,KAAK,UAAU,OAAO,aAAa,MAAa,QAAC,IAAI,KAAK,MAAM,GACzE;AAEA,iBAAS,OAAO,QAAQ;AAlBQ;AAoBlC,aAAO;AApBT;AARF;AAkCC,YAAS,0CAA0C;AAClD,QAAI,OAAO,SAAS,UAAU,SAAS,aAAa;AAClD;AAFgD;AAKlD,aAAS,UAAU,OAAO,SAAS,sBAAsB,KAAK;AAC5D,UAAI,KAAK;UAAM,WAAW,MAAM,UAAU,MAAM,KAAK,WAAW;AAChE,UAAI,QAAQ,SAAS,6BAA6B;AAChD,YAAI,OAAO,SAAS,OAAO,MAAM,UAAU,MAAM,KAAK;AACtD,eAAO,GAAG,MAAM,KAAK;AAFvB;AAIA,aAAO;AANT;AALF;AAiBC,YAAS,uBAAuB;AAC/B,QAAI,CAAC,QAAQ;AACX;AAF6B;AAI/B,QAAI,MAAM,SAAS,cAAc;AACjC,QAAI,aAAa,KAAK;AACpB;AAN6B;AAS/B,WAAO,eAAe,YAAY,WAAW;AAC3C,0BAAM;AACJ,YAAI,KAAK,UAAU;AACjB,iBAAO,KAAK;AAFV;AAKJ,YAAI,UAAU;AACd,aAAK,IAAI,IAAI,GAAG,KAAK,KAAK,WAAW,QAAQ,IAAI,IAAI,KAAK;AACxD,cAAI,YAAY,KAAK,WAAW;AAChC,cAAI,UAAU,KAAK,UAAU,GAAG,OAAO,SAAS;AAC9C;AAHsD;AAKxD,cAAI,gBAAgB,KAAK,UAAU,GAAG,QAAQ,cAC5C,UAAS,KAAK,IAAI;AAChB,mBAAO,GAAG;AAFJ;AAIV,kBAAQ,OAAO,UAAU;AAfvB;AAkBJ,eAAO,eAAe,MAAM;AAC1B,iBAAO;AACP,oBAAU;AACV,sBAAY;AAH0B;AAKxC,eAAO;AAxB6C;;AA0BtD,kBAAY;AA1B0C;AAT1D;AAyCC,YAAS,yBAAyB;AACjC,aAAS,WAAW,SAAS,UAAU,KAAK,QAAQ;AAClD,UAAI,IAAI,QAAQ,aAAa;AAC7B,UAAI,OAAO,EAAE,MAAM;AACnB,UAAI,KAAK,OAAO,IAAI;AAClB,aAAK;AAJ2C;AAMlD,UAAI,QAAQ,KAAK,QAAQ;AACzB,UAAI,QAAQ,KAAK,KAAK;AACpB,aAAK,KAAK;AARsC;AAUlD,UAAI,SAAS,KAAK,QAAQ;AACxB,aAAK,OAAO,OAAO;AAX6B;AAalD,cAAQ,YAAY,KAAK,KAAK;AAC9B,aAAQ,SAAS;AAfc;AAkBjC,QAAI,CAAC,QAAQ;AACX;AAnB+B;AAsBjC,QAAI,MAAM,SAAS,cAAc;AACjC,QAAI,eAAe,KAAK;AACtB;AAxB+B;AA2BjC,QAAI;AACF,wBAAI,MAAM;AACR,mBAAW,KAAK,SAAS,MAAM,MAAM;AAFhB;AAIvB,kCAAS,MAAM;AACb,eAAO,WAAW,KAAK,SAAS,MAAM,OAAO;AALxB;AAOvB,8BAAO,MAAM;AACX,mBAAW,KAAK,SAAS,MAAM,OAAO;AARjB;AAUvB,8BAAO,MAAM;AACX,mBAAW,KAAK,SAAS,MAAM,MAAM;AAXhB;AAAA;AAezB,WAAO,eAAe,YAAY,WAAW;AAC3C,0BAAM;AACJ,YAAI,KAAK,YAAY;AACnB,iBAAO,KAAK;AAFV;AAKJ,YAAI,mBAAmB,OAAO;AAC5B;AACE,mBAAO;AACP,sBAAU;AACV,wBAAY;AAHL;AADuC,SAAlC;AAOhB,eAAO,eAAe,MAAM;AAC1B,iBAAO;AACP,oBAAU;AACV,sBAAY;AAH4B;AAK1C,eAAO;AAlB+C;;AAoBxD,kBAAY;AApB4C;AA1C5D;AAoEC,YAAS,kCAAkC;AAC1C,QAAI,OAAO,kBAAkB,eAAe,aAAa,aAAa;AACpE;AAFwC;AAK1C,QAAI,eAAe;AAEnB,QAAI;AACF,WAAK,SAAS,MAAM;AAClB,YAAI,OAAO,MAAM,UAAU,MAAM,KAAK;AACtC,oBAAY;AACV,sBAAY;AACZ,kBAAQ;AACR,gBAAM;AAHgB;AAHR;AAUlB,aAAO,SAAS,QAAQ;AACtB,YAAI,OAAO,MAAM,UAAU,MAAM,KAAK;AACtC,oBAAY;AACV,sBAAY;AACZ,kBAAQ;AACR,gBAAM;AAHgB;AAZR;AAmBlB,YAAM,SAAS,KAAK,MAAM;AACxB,qBAAa,QAAQ,KAAK;AApBV;AAuBlB,eAAS,SAAS,QAAQ,MAAM;AAC9B,YAAI,OAAO,aAAa;AACxB,YAAI,CAAC,MAAM;AACT,gBAAM,IAAI,MAAM,wBAAwB;AAHZ;AAK9B,aAAK,IAAI,UAAU,MAAM,KAAK,QAAQ;AA5BtB;AAAA;AAgCpB,gBAAY,UAAU;AAvCxB;AA8CC,YAAS,4BAA4B;AACpC,QAAI,CAAC,QAAQ;AACX;AAFkC;AAIpC,QAAM,eAAa,SAAS;AAC1B,aAAO;AACL,4BAAM,CADS;AAEf,gCAAQ,CAFO;AAGf,8BAAO,CAHQ;AAAA;AAKjB;AAVkC;AAYpC,QAAM,YAAU,QAAQ,MAAM;AAE5B,cAAQ,gBAAgB,IAAI;AAC1B,eAAO,UAAS,KAAK;AACnB,iBAAO,GAAG;AADZ;AADY,OAAC,CAIZ,QAAQ;AACX,cAAQ,kBAAkB,IAAI;AAC5B,eAAO,UAAS,KAAK;AACnB,iBAAO,GAAG;AADZ;AADc,OAAC,CAId,QAAQ;AACX,cAAQ,iBAAiB,IAAI;AAC3B,eAAO,UAAS,KAAK;AACnB,iBAAO,GAAG;AADZ;AADa,OAAC,CAIb,QAAQ;AACX;AA7BkC;AAAtC;AAmCC,YAAS,4BAA4B;AAGpC,aAAS,uBAAuB,OAAO;AACrC,UAAI,WAAW,MAAM,SAAS;AAC5B,cAAM;AAF6B;AAHH;AAQpC,aAAS,WAAW,MAAM;AACxB,aAAO,KAAK,YAAa,KAAK,cAAc,WAAW,KAAK;AAT1B;AAWpC,QAAI,SAAS;AAEX,eAAS,iBAAiB,SAAS,wBAAwB;AAbzB;AAAtC;AAmBC,YAAS,qBAAqB;AAG7B,QAAI,QAAQ,aAAa;AACvB,YAAM,yBAAyB;AAJJ;AAA/B;AASC,YAAS,yBAAyB;AACjC,QAAI,OAAO,cAAc,aAAa;AACpC;AAF+B;AAIjC,QAAI,cAAc,WAAW;AAC3B;AAL+B;AAOjC,UAAM,SAAS,UAAU,gBAAgB;AAP3C;AAWC,YAAS,qBAAqB;AAW7B,QAAI,YAAY,iBAAiB,wBAAwB,OAAO;AAC9D,YAAM,eAAe;AACrB,YAAM,gBAAgB;AAbK;AAA/B;AAmBC,YAAS,2BAA2B;AACnC,QAAI,CAAC,QAAQ;AACX;AAFiC;AAOnC,QAAI,CAAC,QAAQ,aAAa,eAAe;AACvC,YAAM,iBAAiB;AARU;AAArC;AAaC,YAAS,8BAA8B;AACtC,QAAI,CAAC,QAAQ;AACX;AAFoC;AAKtC,QAAI,OAAO,kBAAkB;AAC3B,UAAI,OAAO,OAAO,iBAAiB,UAAU,QAAQ,YAAY;AAC/D,eAAO,iBAAiB,UAAU,MAAM,UAAS,KAAK;AACpD,eAAK,IAAI,IAAI,GAAG,KAAK,KAAK,QAAQ,IAAI,IAAI,KAAK;AAC7C,iBAAK,KAAK,IAAI;AAFoC;AAAtD;AAFyB;AAA7B,WAQO;AAGL,UAAI,WAAW;UAAO;AACtB,UAAI,UAAU;AACZ,uBAAe,UAAU,MAAM;AAE/B,mBAAW,gBAAgB,SAAS,aAAa,MAAM;AAHzD,iBAIW,WAAW;AAIpB,mBAAW;AAJN,aAKA,IAAI,UAAU;AACnB,uBAAe,UACb,MAAM;AAER,mBAAW,gBAAgB,SAAS,aAAa,MAAM;AAjBpD;AAoBL,UAAI,UAAU;AACZ,YAAI,mBAAmB,OAAO,yBAAyB;AACvD,YAAI,kBAAkB,iBAAiB;AACvC,yBAAiB,kBAAkB,UAAS,GAAG,GAAG;AAChD,cAAI,YAAY,gBAAgB,KAAK,MAAM,GAAG;AAC9C,oBAAU,KAAK,MAAM,UAAS,KAAK;AACjC,iBAAK,IAAI,IAAI,GAAG,KAAK,KAAK,QAAQ,IAAI,IAAI,KAAK;AAC7C,mBAAK,KAAK,IAAI;AAFiB;AAAnC;AAKA,iBAAO;AAPT;AAUA,2BAAmB;AAjChB;AAb+B;AAAxC;AAoDC,YAAS,6BAA6B;AACrC,aAAS,qCAAqC;AAC5C,aAAO,wBAAwB,UAAU,UAAU;AACjD,eAAO,OAAO,WAAW,UAAU;AADrC;AAGA,aAAO,uBAAuB,UAAU,WAAW;AACjD,eAAO,aAAa;AADtB;AALmC;AAUrC,QAAI,CAAC,QAAQ;AACX;AAXmC;AAarC,QAAI,OAAO;AAET;AACA;AAhBmC;AAkBrC,QAAI,2BAA2B,QAAQ;AACrC;AAnBmC;AAqBrC,WAAO,wBAAwB,OAAO,4BACP,OAAO;AACtC,QAAI,OAAO,uBAAuB;AAChC;AAxBmC;AA0BrC;AA1BF;AA8BC,YAAS,4BAA4B;AACpC,QAAI,SAAS,WAAW;AAEtB,YAAM,kBAAkB;AAHU;AAAtC;AASC,YAAS,yBAAyB;AACjC,QAAI,CAAC,QAAQ;AACX;AAF+B;AAIjC,QAAI,QAAQ,OAAO,WAAW,QAAQ;AACpC,YAAM,oBAAoB;AALK;AAAnC;AAWC,YAAS,qBAAqB;AAC7B,QAAI,CAAC,QAAQ;AACX;AAF2B;AAI7B,QAAI,mBAAmB,UAAU;AAC/B;AAL2B;AAO7B,WAAO,eAAe,UAAU;AAC9B,0BAAM;AACJ,YAAI,UAAU,SAAS,qBAAqB;AAC5C,eAAO,QAAQ,QAAQ,SAAS;AAHa;;AAK/C,kBAAY;AACZ,oBAAc;AANiC;AAPnD;AAmBC,YAAS,6BAA6B;AACrC,QAAI,CAAC,QAAQ;AACX;AAFmC;AAIrC,QAAI,KAAK,SAAS,cAAc;AAChC,QAAI;AACF,SAAG,OAAO;AADZ,MAEE,OAAO,IAAI;AACX,UAAI,aAAa,GAAG,YAAY;AAChC,UAAI,eAAe,OAAO,yBAAyB,YAAY;AAC/D,aAAO,eAAe,YAAY;AAChC,4BAAM;AACJ,iBAAO,aAAa,IAAI,KAAK;AAFS;AAIxC,0BAAI,OAAO;AACT,uBAAa,IAAI,KAAK,MAAM,UAAU,WAAW,SAAS;AALpB;;AAOxC,oBAAY;AACZ,sBAAc;AAR0B;AAVP;AAAvC;AAyBC,YAAS,0BAA0B;AAClC,QAAI,CAAC,QAAQ;AACX;AAFgC;AAIlC,QAAI,CAAC,SAAS,aAAa;AACzB;AALgC;AAOlC,QAAI,gBAAgB,SAAS,YAAY;AACzC,QAAI,kBAAkB,OAAO,yBAAyB,eACA;AACtD,WAAO,eAAe,eAAe;AACnC,0BAAM;AACJ,YAAI,QAAQ,gBAAgB,IAAI,KAAK;AACrC,eAAO,UAAU,gBAAgB,YAAY;AAHE;AAKjD,wBAAI,OAAO;AACT,wBAAgB,IAAI,KAAK,MAAM;AANgB;;AAQjD,kBAAY;AACZ,oBAAc;AATmC;AAVrD;AAyBC,YAAS,uBAAuB;AAC/B,QAAI,CAAC,QAAQ;AACX;AAF6B;AAI/B,QAAI,OAAO,QAAQ,UAAU,WAAW,aAAa;AACnD;AAL6B;AAO/B,YAAQ,UAAU,SAAS,YAAY;AACrC,UAAI,KAAK,YAAY;AACnB,aAAK,WAAW,YAAY;AAFO;AAAvC;AAPF;AAgBC,YAAS,mBAAmB;AAC3B,QAAI,OAAO,OAAO;AAChB;AAFyB;AAI3B,WAAO,QAAQ,UAAS,OAAO;AAC7B,aAAO,OAAO,UAAU,YAAY,MAAM;AAD5C;AAJF;AAWC,YAAS,uBAAuB;AAC/B,QAAI,OAAO,WAAW;AACpB;AAF6B;AAI/B,WAAO,YAAY,UAAS,OAAO;AACjC,aAAO,OAAO,UAAU,YAAY,SAAS,UACtC,KAAK,MAAM,WAAW;AAF/B;AAJF;AAoBC,YAAS,eAAe;AACvB,QAAI,YAAY,SAAS;AAEvB,UAAI,OAAO,YAAY,QAAQ,QAAQ,YAAY;AACjD,oBAAY,QAAQ,MAAM,UAAU,UAAU;AAC5C,cAAI,QAAQ;cAAG,UAAU;cAAI;cAAS;AACtC,cAAI,cAAc,YAAY,QAAQ,UAAU,UAAU,SAAS;AACjE,sBAAU;AACV,qBAAS;AAFG;AAId,mBAAS,QAAQ,UAAU,GAAG,GAAG;AAC/B;AACA,cAAE,KAAK,UAAU,QAAQ;AACvB,sBAAQ,KAAK;AACb;AACA,kBAAI,UAAU,GAAG;AACf,wBAAQ;AAJa;AAAzB,eAMG;AARL;AAUA,cAAI,UAAU,GAAG;AACf,oBAAQ;AAjBkC;AAmB5C,iBAAO;AAnBT;AAHqB;AAyBvB,UAAI,OAAO,YAAY,QAAQ,YAAY,YAAY;AACrD,oBAAY,QAAQ,UAAU,UAAU,OAAO;AAC7C,qBAAW,YAAY,QAAQ,UAAU,SAAS;AAChD,oBAAQ;AADH;AADT;AA1BqB;AAgCvB,UAAI,OAAO,YAAY,QAAQ,WAAW,YAAY;AACpD,oBAAY,QAAQ,SAAS,UAAU,QAAQ;AAC7C,qBAAW,YAAY,QAAQ,UAAU,SAAS,QAAQ;AACxD,mBAAO;AADF;AADT;AAjCqB;AAuCvB,UAAI,OAAO,YAAY,QAAQ,UAAU,UAAU,YAAY;AAC7D,oBAAY,QAAQ,UAAU,QAAQ,UAAU,UAAU;AACxD,iBAAO,YAAY,QAAQ,UAAU,KAAK,WAAW;AADvD;AAxCqB;AA4CvB;AA7CqB;AAgDvB,QAAI,iBAAiB;AACrB,QAAI,kBAAkB;AACtB,QAAI,kBAAkB;AAKtB,QAAI,oBAAoB;AAExB,QAAI;AACF,gBAAU;AACV,eAAS;AACT,2BAAqB;AACrB,6BAAuB;AAEvB,wBAAkB,SAAS,iBAAiB,SAAS;AACnD,YAAI,QAAQ,YAAY,gBAAgB;AACtC;AAFiD;AAKnD,aAAK,WAAW,KAAK,SAAS,OAAO,QAAQ;AAC7C,gBAAQ,YAAY;AAEpB,YAAI,KAAK,SAAS;AAChB;AATiD;AAWnD,aAAK,UAAU;AAEf,mBAAW,KAAK,YAAY,KAAK,OAAO;AAnBvB;AAsBnB,mBAAa,SAAS,cAAc;AAClC,YAAI,cAAc;AAClB,YAAI,YAAY,KAAK,QAAQ;AAC7B,eAAO,KAAK,SAAS,SAAS,GAAG;AAC/B,cAAI,UAAU,KAAK,SAAS;AAE5B,cAAI,aAAa,QAAQ,YAAY;AACrC,cAAI,YAAY,QAAQ,YAAY;AAEpC,cAAI;AACF,gBAAI,eAAe,iBAAiB;AAClC,kBAAI,OAAO,QAAQ,cAAc,YAAY;AAC3C,4BAAY,QAAQ,UAAU;AAFE;AAApC,mBAIO,IAAI,OAAO,QAAQ,aAAa,YAAY;AAC/C,0BAAY,QAAQ,SAAS;AAC7B,2BAAa;AAEb,kBAAI,QAAQ,YAAY,qBAAqB;AAC3C,qBAAK,0BAA0B,QAAQ;AALM;AALjD;AAAJ,YAaE,OAAO,IAAI;AACX,yBAAa;AACb,wBAAY;AArBiB;AAwB/B,kBAAQ,YAAY,cAAc,YAAY;AAC9C,cAAI,KAAK,SAAS,WAAW;AAC3B;AA1B6B;AAHC;AAiClC,YAAI,KAAK,SAAS,SAAS,GAAG;AAC5B,qBAAW,KAAK,YAAY,KAAK,OAAO;AACxC;AAnCgC;AAsClC,aAAK,UAAU;AA5DE;AA+DnB,6BAAuB,SAAS,sBAAsB,SAAS;AAC7D,aAAK,oBAAoB;AACvB;AACA,gBAAM,KAAK;AAFiB;AAI9B,aAAK;AApEY;AAuEnB,iCAA2B,SAAS,0BAA0B,SAAS;AACrE,gBAAQ,sBAAsB;AAC9B,aAAK,IAAI,IAAI,GAAG,IAAI,KAAK,oBAAoB,QAAQ,KAAK;AACxD,cAAI,KAAK,oBAAoB,GAAG,YAAY,SAAS;AACnD,iBAAK,oBAAoB,OAAO;AAChC;AAHsD;AAFW;AAvEpD;AAiFnB,8BAAwB,SAAS;AAAyB;;AACxD,YAAI,KAAK,uBAAuB;AAC9B;AAFsD;AAIxD,aAAK,wBAAwB;AAC7B,mBAAW,YAAM;AACf,gBAAK,wBAAwB;AAC7B,cAAI,MAAM,KAAK;AACf,eAAK,IAAI,IAAI,GAAG,IAAI,MAAK,oBAAoB,QAAQ,KAAK;AACxD,gBAAI,MAAM,MAAK,oBAAoB,GAAG,OAAO,mBAAmB;AAC9D,kBAAI,YAAY,MAAK,oBAAoB,GAAG,QAAQ;AACpD,kBAAI,MAAM,0BAA0B;AACpC,kBAAI,UAAU,OAAO;AACnB,uBAAO,OAAO,UAAU;AAJoC;AAO9D,kBAAI;AACF,sBAAM,IAAI,MAAM;AADlB,gBAEE,OAAO,GAAG;AACV,wBAAQ,KAAK;AAV+C;AAY9D,oBAAK,oBAAoB,OAAO;AAChC;AAdsD;AAH3C;AAoBf,cAAI,MAAK,oBAAoB,QAAQ;AACnC,kBAAK;AArBQ;AAAjB,WAuBG;AA7Gc;AAAA;AAiHrB,QAAI,UAAU,SAAS,QAAQ,UAAU;AACvC,WAAK,UAAU;AACf,WAAK,YAAY;AACjB,UAAI;AACF,iBAAS,KAAK,MAAM,KAAK,SAAS,KAAK,OAAO,KAAK,QAAQ,KAAK;AADlE,QAEE,OAAO,GAAG;AACV,aAAK,QAAQ;AANwB;AAAzC;AAgBA,YAAQ,MAAM,SAAS,YAAY,UAAU;AAC3C,UAAI,YAAY;AAChB,UAAI,eAAe,QAAQ,UAAU,SAAS,QAAQ;AACpD,qBAAa;AACb,oBAAY;AAFC;AAIf,UAAI,aAAa,SAAS;AAC1B,UAAI,UAAU;AACd,UAAI,eAAe,GAAG;AACpB,mBAAW;AACX,eAAO;AAVkC;AAY3C,eAAS,OAAO,QAAQ;AACtB,YAAI,SAAS,YAAY,iBAAiB;AACxC;AAFoB;AAItB,kBAAU;AACV,kBAAU;AAjB+B;AAmB3C,WAAK,IAAI,IAAI,GAAG,KAAK,SAAS,QAAQ,IAAI,IAAI,EAAE,GAAG;AACjD,YAAI,UAAU,SAAS;AACvB,YAAI,oBAAoB,GAAG;AACzB,iBAAO,UAAS,OAAO;AACrB,gBAAI,SAAS,YAAY,iBAAiB;AACxC;AAFmB;AAIrB,oBAAQ,KAAK;AACb;AACA,gBAAI,eAAe,GAAG;AACpB,yBAAW;AAPQ;AAAvB;AADY,SAAC,CAWZ;AACH,YAAI,QAAQ,UAAU,UAAU;AAC9B,kBAAQ,KAAK,SAAS;AADxB,eAEO;AACL,kBAAQ;AAjBuC;AAnBR;AAuC3C,aAAO;AAvCT;AA8CA,YAAQ,YAAY,SAAS,kBAAkB,OAAO;AACpD,aAAO,SAAS,OAAO,MAAM,SAAS;AADxC;AASA,YAAQ,UAAU,SAAS,gBAAgB,OAAO;AAChD,iBAAW,QAAQ,UAAU,SAAS;AACpC,gBAAQ;AADH;AADT;AAWA,YAAQ,SAAS,SAAS,eAAe,QAAQ;AAC/C,iBAAW,QAAQ,UAAU,SAAS,QAAQ;AAC5C,eAAO;AADF;AADT;AAMA,YAAQ;AACN,eAAS;AACT,cAAQ;AACR,iBAAW;AACX,2BAAqB;AAErB,qBAAe,SAAS,sBAAsB,QAAQ,OAAO;AAC3D,YAAI,KAAK,YAAY,mBACjB,KAAK,YAAY,iBAAiB;AACpC;AAHyD;AAM3D,YAAI,WAAW,mBACX,QAAQ,UAAU,QAAQ;AAC5B,gBAAM,KAAK,KAAK,cAAc,KAAK,MAAM,kBAC9B,KAAK,cAAc,KAAK,MAAM;AACzC;AAVyD;AAa3D,aAAK,UAAU;AACf,aAAK,SAAS;AAEd,YAAI,WAAW,mBAAmB,KAAK,UAAU,WAAW,GAAG;AAC7D,eAAK,sBAAsB;AAC3B,yBAAe,sBAAsB;AAlBoB;AAqB3D,uBAAe,iBAAiB;AA3BhB;AA8BlB,gBAAU,SAAS,gBAAgB,OAAO;AACxC,aAAK,cAAc,iBAAiB;AA/BpB;AAkClB,eAAS,SAAS,eAAe,QAAQ;AACvC,aAAK,cAAc,iBAAiB;AAnCpB;AAsClB,YAAM,SAAS,aAAa,WAAW,UAAU;AAC/C,YAAI,kBAAkB,QAAQ,UAAU,SAAS,QAAQ;AACvD,eAAK,UAAU;AACf,eAAK,SAAS;AAFE;AAIlB,aAAK,UAAU;AACb,uBAAa;AACb;AACA;AACA;AAJkB;AAMpB,uBAAe,iBAAiB;AAChC,eAAO;AAlDS;AAqDlB,aAAO,SAAS,cAAc,UAAU;AACtC,eAAO,KAAK,KAAK,WAAW;AAtDZ;AAAA;AA0DpB,gBAAY,UAAU;AA5TxB;AA+TC,YAAS,eAAe;AACvB,QAAI,YAAY,SAAS;AACvB;AAFqB;AAKvB,QAAI,KAAK;AACT,aAAS,UAAU;AACjB,WAAK,KAAK,aAAc;AAPH;AASvB,YAAQ;AACN,wBAAI,KAAK;AACP,YAAK,QAAO,sDAAQ,YAAY,OAAO,QAAQ,cAC3C,QAAQ,MAAM;AAChB,iBAAO;AAHF;AAKP,eAAO,CAAC,CAAC,OAAO,yBAAyB,KAAK,KAAK;AANnC;AAQlB,wBAAI,KAAK;AACP,eAAO,KAAK,IAAI,OAAO,IAAI,KAAK,MAAM;AATtB;AAWlB,wBAAI,KAAK,OAAO;AACd,eAAO,eAAe,KAAK,KAAK;AAC9B;AACA,sBAAY;AACZ,wBAAc;AAHoB;AAZpB;AAkBlB,+BAAO,KAAK;AACV,eAAO,IAAI,KAAK;AAnBA;AAAA;AAuBpB,gBAAY,UAAU;AAhCxB;AAsCC,YAAS,sBAAsB;AAE9B,QAAI,gBAAgB;AACpB,QAAI;AACF,UAAI,OAAO,QAAQ,cACf,QAAO,IAAI,eAAc,YACxB,YAAY,IAAI,WAAY;AAC/B,YAAI,IAAI,IAAI,IAAI,KAAK;AACrB,UAAE,WAAW;AACb,wBAAgB,EAAE,SAAS;AAN3B;AAAJ,MAQE,OAAO,GAAG,CAXkB;AAa9B,QAAI,eAAe;AACjB;AAd4B;AAiB9B,QAAI,WAAW,OAAO,OAAO;AAC7B,aAAS,SAAS;AAClB,aAAS,UAAU;AACnB,aAAS,YAAY;AACrB,aAAS,UAAU;AACnB,aAAS,WAAW;AACpB,aAAS,QAAQ;AACjB,aAAS,SAAS;AAElB,QAAI,yBAAyB,OAAO,OAAO;AAC3C,2BAAuB,SAAS;AAChC,2BAAuB,UAAU;AACjC,2BAAuB,UAAU;AACjC,2BAAuB,YAAY;AAEnC,aAAS,iBAAiB,QAAQ;AAChC,aAAO,SAAS,YAAY;AAjCA;AAoC9B,aAAS,UAAU;AACjB,YAAM,KAAK;AACX,WAAK,aAAa;AAtCU;AAyC9B,aAAS,YAAY,GAAG;AACtB,UAAI,MAAM,IAAI;AACZ,gBAAQ,KAAK;AAFO;AAKtB,aAAO,EAAE;AA9CmB;AAiD9B,aAAS,cAAc,GAAG;AACxB,UAAI,UAAU,EAAE,WAAW;AAC3B,UAAI,UAAU,QACX,UAAU,QAEV,CAAC,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,QAAQ,aAAa,CAAC,GAC1D;AACF,eAAO;AAPe;AASxB,aAAO,mBAAmB;AA1DE;AA6D9B,aAAS,mBAAmB,GAAG;AAI7B,UAAI,UAAU,EAAE,WAAW;AAC3B,UAAI,UAAU,QACX,UAAU,QAEV,CAAC,MAAM,MAAM,MAAM,MAAM,MAAM,QAAQ,aAAa,CAAC,GACpD;AACF,eAAO;AAVoB;AAY7B,aAAO,mBAAmB;AAzEE;AA4E9B,QAAI;QAAK,QAAQ;QACb,eAAe;AAEnB,aAAS,MAAM,OAAO,eAAe,MAAM;AACzC,eAAS,IAAI,SAAS;AACpB,eAAO,KAAK;AAF2B;AAKzC,UAAI,QAAQ,iBAAiB;UACzB,SAAS;UACT,SAAS;UACT,SAAS;UACT,cAAc;UACd,SAAS;AAEb,YAAM,OAAQ,OAAM,SAAS,OAAO,OAAO,WAAW,MACzC,CAAC,KAAK,YAAY;AAC7B,YAAI,IAAI,MAAM;AACd,gBAAQ;AACN,eAAK;AACH,gBAAI,KAAK,MAAM,KAAK,IAAI;AACtB,wBAAU,EAAE;AACZ,sBAAQ;AAFV,uBAGW,CAAC,eAAe;AACzB,uBAAS;AACT,sBAAQ;AACR;AAHK,mBAIA;AACL,kBAAI;AACJ,oBAFK;AART;AAYE;AAEF,eAAK;AACH,gBAAI,KAAK,aAAa,KAAK,IAAI;AAC7B,wBAAU,EAAE;AADd,uBAEW,MAAM,KAAK;AACpB,mBAAK,UAAU;AACf,uBAAS;AACT,kBAAI,eAAe;AACjB,sBADiB;AAHC;AAMpB,kBAAI,iBAAiB,KAAK,UAAU;AAClC,qBAAK,cAAc;AAPD;AASpB,kBAAI,KAAK,YAAY,QAAQ;AAC3B,wBAAQ;AADV,yBAEW,KAAK,eAAe,QACpB,KAAK,YAAY,KAAK,SAAS;AACxC,wBAAQ;AAFH,yBAGI,KAAK,aAAa;AAC3B,wBAAQ;AADH,qBAEA;AACL,wBAAQ;AAjBU;AAAf,uBAmBI,CAAC,eAAe;AACzB,uBAAS;AACT,uBAAS;AACT,sBAAQ;AACR;AAJK,uBAKI,MAAM,KAAK;AACpB,oBADoB;AAAf,mBAEA;AACL,kBAAI,uCAAuC;AAC3C,oBAFK;AA7BT;AAiCE;AAEF,eAAK;AACH,gBAAI,MAAM,KAAK;AACb,mBAAK,SAAS;AACd,sBAAQ;AAFV,uBAGW,MAAM,KAAK;AACpB,mBAAK,YAAY;AACjB,sBAAQ;AAFH,mBAGA;AAEL,kBAAI,MAAM,OAAO,MAAM,QAAQ,MAAM,QAAQ,MAAM,MAAM;AACvD,qBAAK,eAAe,cAAc;AAH/B;AAPT;AAaE;AAEF,eAAK;AACH,gBAAI,CAAC,QAAQ,CAAE,iBAAiB,KAAK,UAAW;AAC9C,kBAAI;AACJ,sBAAQ,KAAK;AAFf,mBAGO;AACL,sBAAQ;AACR;AANJ;AAQE;AAEF,eAAK;AACH,gBAAI,MAAM,OAAO,MAAM,SAAS,OAAO,KAAK;AAC1C,sBAAQ;AADV,mBAEO;AACL,kBAAI,sBAAsB;AAC1B,sBAAQ;AACR;AANJ;AAQE;AAEF,eAAK;AACH,iBAAK,cAAc;AACnB,gBAAI,KAAK,YAAY,QAAQ;AAC3B,mBAAK,UAAU,KAAK;AAHxB;AAKE,gBAAI,MAAM,KAAK;AACb,mBAAK,QAAQ,KAAK;AAClB,mBAAK,QAAQ,KAAK;AAClB,mBAAK,QAAQ,KAAK,MAAM;AACxB,mBAAK,SAAS,KAAK;AACnB,mBAAK,YAAY,KAAK;AACtB,mBAAK,YAAY,KAAK;AACtB,oBAPa;AAAf,uBAQW,MAAM,OAAO,MAAM,MAAM;AAClC,kBAAI,MAAM,MAAM;AACd,oBAAI;AAF4B;AAIlC,sBAAQ;AAJH,uBAKI,MAAM,KAAK;AACpB,mBAAK,QAAQ,KAAK;AAClB,mBAAK,QAAQ,KAAK;AAClB,mBAAK,QAAQ,KAAK,MAAM;AACxB,mBAAK,SAAS;AACd,mBAAK,YAAY,KAAK;AACtB,mBAAK,YAAY,KAAK;AACtB,sBAAQ;AAPH,uBAQI,MAAM,KAAK;AACpB,mBAAK,QAAQ,KAAK;AAClB,mBAAK,QAAQ,KAAK;AAClB,mBAAK,QAAQ,KAAK,MAAM;AACxB,mBAAK,SAAS,KAAK;AACnB,mBAAK,YAAY;AACjB,mBAAK,YAAY,KAAK;AACtB,mBAAK,YAAY,KAAK;AACtB,sBAAQ;AARH,mBASA;AACL,kBAAI,QAAQ,MAAM,SAAS;AAC3B,kBAAI,YAAY,MAAM,SAAS;AAC/B,kBAAI,KAAK,YAAY,UAAU,CAAC,MAAM,KAAK,MACtC,UAAU,OAAO,UAAU,OAC3B,cAAc,OAAO,cAAc,OAAO,cAAc,QACxD,cAAc,OAAO,cAAc,KAAM;AAC5C,qBAAK,QAAQ,KAAK;AAClB,qBAAK,QAAQ,KAAK;AAClB,qBAAK,YAAY,KAAK;AACtB,qBAAK,YAAY,KAAK;AACtB,qBAAK,QAAQ,KAAK,MAAM;AACxB,qBAAK,MAAM;AAZR;AAcL,sBAAQ;AACR;AAlDJ;AAoDE;AAEF,eAAK;AACH,gBAAI,MAAM,OAAO,MAAM,MAAM;AAC3B,kBAAI,MAAM,MAAM;AACd,oBAAI;AAFqB;AAI3B,kBAAI,KAAK,YAAY,QAAQ;AAC3B,wBAAQ;AADV,qBAEO;AACL,wBAAQ;AAPiB;AAA7B,mBASO;AACL,kBAAI,KAAK,YAAY,QAAQ;AAC3B,qBAAK,QAAQ,KAAK;AAClB,qBAAK,QAAQ,KAAK;AAClB,qBAAK,YAAY,KAAK;AACtB,qBAAK,YAAY,KAAK;AALnB;AAOL,sBAAQ;AACR;AAlBJ;AAoBE;AAEF,eAAK;AACH,gBAAI,MAAM,KAAK;AACb,sBAAQ;AADV,mBAEO;AACL,kBAAI,0BAA0B;AAC9B,sBAAQ;AACR;AANJ;AAQE;AAEF,eAAK;AACH,oBAAQ;AACR,gBAAI,MAAM,KAAK;AACb,kBAAI,0BAA0B;AAC9B;AAJJ;AAME;AAEF,eAAK;AACH,gBAAI,MAAM,OAAO,MAAM,MAAM;AAC3B,sBAAQ;AACR;AAFF,mBAGO;AACL,kBAAI,8BAA8B;AALtC;AAOE;AAEF,eAAK;AACH,gBAAI,MAAM,KAAK;AACb,kBAAI,QAAQ;AACV,oBAAI;AACJ,0BAAU;AAHC;AAKb,uBAAS;AACT,mBAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,oBAAI,KAAK,OAAO;AAChB,oBAAI,OAAO,QAAQ,OAAO,QAAQ,OAAO,MAAM;AAC7C,sBAAI;AACJ;AAJoC;AAOtC,oBAAI,OAAO,OAAO,KAAK,cAAc,MAAM;AACzC,uBAAK,YAAY;AACjB;AAToC;AAWtC,oBAAI,QAAQ,cAAc;AAC1B,oBAAI,KAAK,cAAc,MAAM;AAC3B,uBAAK,aAAa;AADpB,uBAEO;AACL,uBAAK,aAAa;AAfkB;AAN3B;AAwBb,uBAAS;AAxBX,uBAyBW,MAAM,OAAO,MAAM,OAAO,MAAM,QAChC,MAAM,OAAO,MAAM,KAAK;AACjC,wBAAU,OAAO;AACjB,uBAAS;AACT,sBAAQ;AACR;AALK,mBAMA;AACL,wBAAU;AAjCd;AAmCE;AAEF,eAAK;AACH,gBAAI,MAAM,OAAO,MAAM,OAAO,MAAM,QAAQ,MAAM,OAAO,MAAM,KAAK;AAClE,kBAAI,OAAO,WAAW,KAAK,MAAM,KAAK,OACjC,eAAO,OAAO,OAAO,OAAO,OAAO,MAAM;AAC5C,wBAAQ;AAFV,yBAGW,OAAO,WAAW,GAAG;AAC9B,wBAAQ;AADH,qBAEA;AACL,qBAAK,QAAQ,YAAY,KAAK,MAAM;AACpC,yBAAS;AACT,wBAAQ;AATwD;AAWlE;AAXF,uBAYW,MAAM,QAAQ,MAAM,QAAQ,MAAM,MAAM;AACjD,kBAAI;AADC,mBAEA;AACL,wBAAU;AAhBd;AAkBE;AAEF,eAAK;AACL,eAAK;AACH,gBAAI,MAAM,OAAO,CAAC,aAAa;AAE7B,mBAAK,QAAQ,YAAY,KAAK,MAAM;AACpC,uBAAS;AACT,sBAAQ;AACR,kBAAI,kBAAkB,YAAY;AAChC,sBADgC;AALL;AAA/B,uBAQW,MAAM,OAAO,MAAM,OACnB,MAAM,QAAQ,MAAM,OAAO,MAAM,KAAK;AAC/C,mBAAK,QAAQ,YAAY,KAAK,MAAM;AACpC,uBAAS;AACT,sBAAQ;AACR,kBAAI,eAAe;AACjB,sBADiB;AAJ4B;AAO/C;AARK,uBASI,MAAM,QAAQ,MAAM,QAAQ,MAAM,MAAM;AACjD,kBAAI,MAAM,KAAK;AACb,8BAAc;AADhB,qBAEO,IAAI,MAAM,KAAK;AACpB,8BAAc;AAJiC;AAMjD,wBAAU;AANL,mBAOA;AACL,kBAAI,0CAA0C;AA1BlD;AA4BE;AAEF,eAAK;AACH,gBAAI,QAAQ,KAAK,IAAI;AACnB,wBAAU;AADZ,uBAEW,MAAM,OAAO,MAAM,OAAO,MAAM,QAChC,MAAM,OAAO,MAAM,OAAO,eAAe;AAClD,kBAAI,WAAW,IAAI;AACjB,oBAAI,OAAO,SAAS,QAAQ;AAC5B,oBAAI,SAAS,SAAS,KAAK,UAAU;AACnC,uBAAK,QAAQ,OAAO;AAHL;AAKjB,yBAAS;AANuC;AAQlD,kBAAI,eAAe;AACjB,sBADiB;AAR+B;AAWlD,sBAAQ;AACR;AAbK,uBAcI,MAAM,QAAQ,MAAM,QAAQ,MAAM,MAAM;AACjD,kBAAI,iCAAiC;AADhC,mBAEA;AACL,sBAAQ,KAAK;AApBjB;AAsBE;AAEF,eAAK;AACH,gBAAI,MAAM,MAAM;AACd,kBAAI;AAFR;AAIE,oBAAQ;AACR,gBAAI,MAAM,OAAO,MAAM,MAAM;AAC3B;AANJ;AAQE;AAEF,eAAK;AACH,gBAAI,MAAM,OAAO,MAAM,OAAO,MAAM,QAC/B,CAAmB,wBAAM,OAAO,MAAM,MAAO;AAChD,kBAAI,MAAM,MAAM;AACd,oBAAI;AAF0C;AAIhD,kBAAI;AACJ,kBAAK,MAAM,uBAAuB,OAAO,gBAAiB;AACxD,yBAAS;AANqC;AAQhD,kBAAI,WAAW,MAAM;AACnB,qBAAK,MAAM;AACX,oBAAI,MAAM,OAAO,MAAM,MAAM;AAC3B,uBAAK,MAAM,KAAK;AAHC;AAArB,yBAKW,WAAW,OAAO,MAAM,OAAO,MAAM,MAAM;AACpD,qBAAK,MAAM,KAAK;AADX,qBAEA,IAAI,WAAW,KAAK;AACzB,oBAAI,KAAK,YAAY,UAAU,KAAK,MAAM,WAAW,KACjD,OAAO,WAAW,KAAK,MAAM,KAAK,OAAO,OACzC,OAAO,OAAO,KAAK;AACrB,2BAAS,OAAO,KAAK;AAJE;AAMzB,qBAAK,MAAM,KAAK;AArB8B;AAuBhD,uBAAS;AACT,kBAAI,MAAM,KAAK;AACb,qBAAK,SAAS;AACd,wBAAQ;AAFV,qBAGO,IAAI,MAAM,KAAK;AACpB,qBAAK,YAAY;AACjB,wBAAQ;AA7BsC;AADlD,mBAgCO,IAAI,MAAM,QAAQ,MAAM,QAAQ,MAAM,MAAM;AACjD,wBAAU,cAAc;AAlC5B;AAoCE;AAEF,eAAK;AACH,gBAAI,CAAC,iBAAiB,MAAM,KAAK;AAC/B,mBAAK,YAAY;AACjB,sBAAQ;AAFV,mBAGO,IAAI,MAAM,OAAO,MAAM,QAAQ,MAAM,QAAQ,MAAM,MAAM;AAC9D,mBAAK,UAAU,mBAAmB;AALtC;AAOE;AAEF,eAAK;AACH,gBAAI,MAAM,OAAO,MAAM,QAAQ,MAAM,QAAQ,MAAM,MAAM;AACvD,mBAAK,aAAa;AAFtB;AAIE;;AAGJ;AA3XuC;AA/Eb;AA8c9B,aAAS,QAAQ;AACf,WAAK,UAAU;AACf,WAAK,cAAc;AACnB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,QAAQ;AACb,WAAK,QAAQ;AACb,WAAK,QAAQ;AACb,WAAK,SAAS;AACd,WAAK,YAAY;AACjB,WAAK,aAAa;AAClB,WAAK,cAAc;AAzdS;AA8d9B,aAAS,KAAK,KAAK,MAAuB;AACxC,UAAI,SAAS,aAAe,kBAAgB,OAAO;AACjD,eAAO,IAAI,KAAK,OAAO;AAFe;AAKxC,WAAK,OAAO;AACZ,YAAM,KAAK;AAEX,UAAI,QAAQ,IAAI,QAAQ,gCAAgC;AAGxD,YAAM,KAAK,MAAM,OAAO,MAAM;AAzeF;AA4e9B,SAAK;AACH,oCAAW;AACT,eAAO,KAAK;AAFC;;AAIf,UAAI,OAAO;AACT,YAAI,KAAK,YAAY;AACnB,iBAAO,KAAK;AAFL;AAIT,YAAI,YAAY;AAChB,YAAI,KAAK,cAAc,MAAM,KAAK,cAAc,MAAM;AACpD,sBAAY,KACT,kBAAK,cAAc,OAAO,MAAM,KAAK,YAAY,MAAM;AAPnD;AAUT,eAAO,KACF,iBAAK,cAAc,OAAO,YAAY,KAAK,OAAO,MACnD,KAAK,WAAW,KAAK,SAAS,KAAK;AAhB1B;AAoBf,UAAI,KAAK,OAAO;AACd,cAAM,KAAK;AACX,cAAM,KAAK,MAAM;AAtBJ;AAyBf,UAAI,WAAW;AACb,eAAO,KAAK,UAAU;AA1BT;AA4Bf,UAAI,SAAS,OAAO;AAClB,YAAI,KAAK,YAAY;AACnB;AAFgB;AAIlB,cAAM,KAAK,MAAM,QAAQ,KAAK;AAhCjB;AAmCf,UAAI,OAAO;AACT,eAAO,KAAK,aAAa,KAAK,KAAK,QAC/B,KAAK,QAAQ,MAAM,KAAK,QAAQ,KAAK;AArC5B;AAuCf,UAAI,KAAK,OAAO;AACd,YAAI,KAAK,cAAc,CAAC,KAAK,aAAa;AACxC;AAFY;AAId,cAAM,KAAK,MAAM,OAAO;AA3CX;AA8Cf,UAAI,WAAW;AACb,eAAO,KAAK;AA/CC;AAiDf,UAAI,SAAS,OAAO;AAClB,YAAI,KAAK,cAAc,CAAC,KAAK,aAAa;AACxC;AAFgB;AAIlB,cAAM,KAAK,MAAM,OAAO;AArDX;AAwDf,UAAI,OAAO;AACT,eAAO,KAAK;AAzDC;AA2Df,UAAI,KAAK,OAAO;AACd,YAAI,KAAK,cAAc,CAAC,KAAK,aAAa;AACxC;AAFY;AAId,cAAM,KAAK,MAAM,OAAO;AA/DX;AAkEf,UAAI,WAAW;AACb,eAAO,KAAK,aAAa,KAAK,KAAK,cAC/B,MAAM,KAAK,MAAM,KAAK,OAAO,KAAK;AApEzB;AAsEf,UAAI,SAAS,OAAO;AAClB,YAAI,KAAK,cAAc,CAAC,KAAK,aAAa;AACxC;AAFgB;AAIlB,aAAK,QAAQ;AACb,cAAM,KAAK,MAAM,OAAO;AA3EX;AA8Ef,UAAI,SAAS;AACX,eAAO,KAAK,cAAc,CAAC,KAAK,UAAU,KAAK,WAAW,MACtD,KAAK,KAAK;AAhFD;AAkFf,UAAI,OAAO,OAAO;AAChB,YAAI,KAAK,cAAc,CAAC,KAAK,aAAa;AACxC;AAFc;AAIhB,aAAK,SAAS;AACd,YAAI,MAAM,OAAO,KAAK;AACpB,kBAAQ,MAAM,MAAM;AANN;AAQhB,cAAM,KAAK,MAAM,OAAO;AA1FX;AA6Ff,UAAI,OAAO;AACT,eAAO,KAAK,cAAc,CAAC,KAAK,aAAa,KAAK,cAAc,MAC5D,KAAK,KAAK;AA/FD;AAiGf,UAAI,KAAK,OAAO;AACd,YAAI,KAAK,YAAY;AACnB;AAFY;AAId,aAAK,YAAY;AACjB,YAAI,MAAM,OAAO,KAAK;AACpB,kBAAQ,MAAM,MAAM;AANR;AAQd,cAAM,KAAK,MAAM,OAAO;AAzGX;AA4Gf,UAAI,SAAS;AACX,YAAI;AACJ,YAAI,KAAK,cAAc,CAAC,KAAK,SAAS;AACpC,iBAAO;AAHE;AAUX,gBAAQ,KAAK;AACX,eAAK;AACL,eAAK;AACL,eAAK;AACL,eAAK;AACH,mBAAO;AACT,eAAK;AAEH,gBAAI;AACF,qBAAO,IAAI,KAAK,KAAK,aAAa,UAAU;AAD9C,cAEE,OAAO,GAAG,CAJd;AAOE,mBAAO;;AAEX,eAAO,KAAK;AACZ,YAAI,CAAC,MAAM;AACT,iBAAO;AA3BE;AA6BX,eAAO,KAAK,UAAU,QAAQ;AAzIjB;AAAA;AA8IjB,QAAI,cAAc,YAAY;AAC9B,QAAI,aAAa;AACf,WAAK,kBAAkB,UAAS,MAAM;AAGpC,eAAO,YAAY,gBAAgB,MAAM,aAAa;AAHxD;AAKA,WAAK,kBAAkB,UAAS,KAAK;AACnC,oBAAY,gBAAgB;AAD9B;AAjoB4B;AAsoB9B,gBAAY,MAAM;AAtoBpB;;;;;;;;;;AC9rCA,IAAI,4BAA4B;AAChC,IAAI,OAAO,mBAAmB,aAAa;AAEzC,MAAI;AAEF,QAAI;AACF,4BAAM,YAAY;AAChB,mBAAW;AAFI;AAAA;AAKnB,gCAA4B;AAP9B,IAQE,OAAO,GAAG,CAV6B;AAhB3C;AA8BA,IAAI,2BAA2B;AAC7B,UAAQ,iBAAiB;AAD3B,OAEO;AAIL,UAAQ,iBACN,oBAAQ,IAAsC", + "file": "pdf.js", + "sourcesContent": [ + "(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"pdfjs-dist/build/pdf\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"pdfjs-dist/build/pdf\"] = factory();\n\telse\n\t\troot[\"pdfjs-dist/build/pdf\"] = factory();\n})(this, function() {\nreturn \n\n\n// WEBPACK FOOTER //\n// webpack/universalModuleDefinition", + " \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __w_pdfjs_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __w_pdfjs_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__w_pdfjs_require__.m = modules;\n\n \t// expose the module cache\n \t__w_pdfjs_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__w_pdfjs_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__w_pdfjs_require__.d = function(exports, name, getter) {\n \t\tif(!__w_pdfjs_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__w_pdfjs_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__w_pdfjs_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__w_pdfjs_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__w_pdfjs_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __w_pdfjs_require__(__w_pdfjs_require__.s = 15);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap b5fe8ab6eb949fc98816", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport './compatibility';\nimport { ReadableStream } from './streams_polyfill';\n\nvar globalScope =\n (typeof window !== 'undefined' && window.Math === Math) ? window :\n // eslint-disable-next-line no-undef\n (typeof global !== 'undefined' && global.Math === Math) ? global :\n (typeof self !== 'undefined' && self.Math === Math) ? self : this;\n\nvar FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];\n\nconst NativeImageDecoding = {\n NONE: 'none',\n DECODE: 'decode',\n DISPLAY: 'display',\n};\n\nvar TextRenderingMode = {\n FILL: 0,\n STROKE: 1,\n FILL_STROKE: 2,\n INVISIBLE: 3,\n FILL_ADD_TO_PATH: 4,\n STROKE_ADD_TO_PATH: 5,\n FILL_STROKE_ADD_TO_PATH: 6,\n ADD_TO_PATH: 7,\n FILL_STROKE_MASK: 3,\n ADD_TO_PATH_FLAG: 4,\n};\n\nvar ImageKind = {\n GRAYSCALE_1BPP: 1,\n RGB_24BPP: 2,\n RGBA_32BPP: 3,\n};\n\nvar AnnotationType = {\n TEXT: 1,\n LINK: 2,\n FREETEXT: 3,\n LINE: 4,\n SQUARE: 5,\n CIRCLE: 6,\n POLYGON: 7,\n POLYLINE: 8,\n HIGHLIGHT: 9,\n UNDERLINE: 10,\n SQUIGGLY: 11,\n STRIKEOUT: 12,\n STAMP: 13,\n CARET: 14,\n INK: 15,\n POPUP: 16,\n FILEATTACHMENT: 17,\n SOUND: 18,\n MOVIE: 19,\n WIDGET: 20,\n SCREEN: 21,\n PRINTERMARK: 22,\n TRAPNET: 23,\n WATERMARK: 24,\n THREED: 25,\n REDACT: 26,\n};\n\nvar AnnotationFlag = {\n INVISIBLE: 0x01,\n HIDDEN: 0x02,\n PRINT: 0x04,\n NOZOOM: 0x08,\n NOROTATE: 0x10,\n NOVIEW: 0x20,\n READONLY: 0x40,\n LOCKED: 0x80,\n TOGGLENOVIEW: 0x100,\n LOCKEDCONTENTS: 0x200,\n};\n\nvar AnnotationFieldFlag = {\n READONLY: 0x0000001,\n REQUIRED: 0x0000002,\n NOEXPORT: 0x0000004,\n MULTILINE: 0x0001000,\n PASSWORD: 0x0002000,\n NOTOGGLETOOFF: 0x0004000,\n RADIO: 0x0008000,\n PUSHBUTTON: 0x0010000,\n COMBO: 0x0020000,\n EDIT: 0x0040000,\n SORT: 0x0080000,\n FILESELECT: 0x0100000,\n MULTISELECT: 0x0200000,\n DONOTSPELLCHECK: 0x0400000,\n DONOTSCROLL: 0x0800000,\n COMB: 0x1000000,\n RICHTEXT: 0x2000000,\n RADIOSINUNISON: 0x2000000,\n COMMITONSELCHANGE: 0x4000000,\n};\n\nvar AnnotationBorderStyleType = {\n SOLID: 1,\n DASHED: 2,\n BEVELED: 3,\n INSET: 4,\n UNDERLINE: 5,\n};\n\nvar StreamType = {\n UNKNOWN: 0,\n FLATE: 1,\n LZW: 2,\n DCT: 3,\n JPX: 4,\n JBIG: 5,\n A85: 6,\n AHX: 7,\n CCF: 8,\n RL: 9,\n};\n\nvar FontType = {\n UNKNOWN: 0,\n TYPE1: 1,\n TYPE1C: 2,\n CIDFONTTYPE0: 3,\n CIDFONTTYPE0C: 4,\n TRUETYPE: 5,\n CIDFONTTYPE2: 6,\n TYPE3: 7,\n OPENTYPE: 8,\n TYPE0: 9,\n MMTYPE1: 10,\n};\n\nvar VERBOSITY_LEVELS = {\n errors: 0,\n warnings: 1,\n infos: 5,\n};\n\nvar CMapCompressionType = {\n NONE: 0,\n BINARY: 1,\n STREAM: 2,\n};\n\n// All the possible operations for an operator list.\nvar OPS = {\n // Intentionally start from 1 so it is easy to spot bad operators that will be\n // 0's.\n dependency: 1,\n setLineWidth: 2,\n setLineCap: 3,\n setLineJoin: 4,\n setMiterLimit: 5,\n setDash: 6,\n setRenderingIntent: 7,\n setFlatness: 8,\n setGState: 9,\n save: 10,\n restore: 11,\n transform: 12,\n moveTo: 13,\n lineTo: 14,\n curveTo: 15,\n curveTo2: 16,\n curveTo3: 17,\n closePath: 18,\n rectangle: 19,\n stroke: 20,\n closeStroke: 21,\n fill: 22,\n eoFill: 23,\n fillStroke: 24,\n eoFillStroke: 25,\n closeFillStroke: 26,\n closeEOFillStroke: 27,\n endPath: 28,\n clip: 29,\n eoClip: 30,\n beginText: 31,\n endText: 32,\n setCharSpacing: 33,\n setWordSpacing: 34,\n setHScale: 35,\n setLeading: 36,\n setFont: 37,\n setTextRenderingMode: 38,\n setTextRise: 39,\n moveText: 40,\n setLeadingMoveText: 41,\n setTextMatrix: 42,\n nextLine: 43,\n showText: 44,\n showSpacedText: 45,\n nextLineShowText: 46,\n nextLineSetSpacingShowText: 47,\n setCharWidth: 48,\n setCharWidthAndBounds: 49,\n setStrokeColorSpace: 50,\n setFillColorSpace: 51,\n setStrokeColor: 52,\n setStrokeColorN: 53,\n setFillColor: 54,\n setFillColorN: 55,\n setStrokeGray: 56,\n setFillGray: 57,\n setStrokeRGBColor: 58,\n setFillRGBColor: 59,\n setStrokeCMYKColor: 60,\n setFillCMYKColor: 61,\n shadingFill: 62,\n beginInlineImage: 63,\n beginImageData: 64,\n endInlineImage: 65,\n paintXObject: 66,\n markPoint: 67,\n markPointProps: 68,\n beginMarkedContent: 69,\n beginMarkedContentProps: 70,\n endMarkedContent: 71,\n beginCompat: 72,\n endCompat: 73,\n paintFormXObjectBegin: 74,\n paintFormXObjectEnd: 75,\n beginGroup: 76,\n endGroup: 77,\n beginAnnotations: 78,\n endAnnotations: 79,\n beginAnnotation: 80,\n endAnnotation: 81,\n paintJpegXObject: 82,\n paintImageMaskXObject: 83,\n paintImageMaskXObjectGroup: 84,\n paintImageXObject: 85,\n paintInlineImageXObject: 86,\n paintInlineImageXObjectGroup: 87,\n paintImageXObjectRepeat: 88,\n paintImageMaskXObjectRepeat: 89,\n paintSolidColorImageMask: 90,\n constructPath: 91,\n};\n\nvar verbosity = VERBOSITY_LEVELS.warnings;\n\nfunction setVerbosityLevel(level) {\n verbosity = level;\n}\n\nfunction getVerbosityLevel() {\n return verbosity;\n}\n\n// A notice for devs. These are good for things that are helpful to devs, such\n// as warning that Workers were disabled, which is important to devs but not\n// end users.\nfunction info(msg) {\n if (verbosity >= VERBOSITY_LEVELS.infos) {\n console.log('Info: ' + msg);\n }\n}\n\n// Non-fatal warnings.\nfunction warn(msg) {\n if (verbosity >= VERBOSITY_LEVELS.warnings) {\n console.log('Warning: ' + msg);\n }\n}\n\n// Deprecated API function -- display regardless of the PDFJS.verbosity setting.\nfunction deprecated(details) {\n console.log('Deprecated API usage: ' + details);\n}\n\nfunction unreachable(msg) {\n throw new Error(msg);\n}\n\nfunction assert(cond, msg) {\n if (!cond) {\n unreachable(msg);\n }\n}\n\nvar UNSUPPORTED_FEATURES = {\n unknown: 'unknown',\n forms: 'forms',\n javaScript: 'javaScript',\n smask: 'smask',\n shadingPattern: 'shadingPattern',\n font: 'font',\n};\n\n// Checks if URLs have the same origin. For non-HTTP based URLs, returns false.\nfunction isSameOrigin(baseUrl, otherUrl) {\n try {\n var base = new URL(baseUrl);\n if (!base.origin || base.origin === 'null') {\n return false; // non-HTTP url\n }\n } catch (e) {\n return false;\n }\n\n var other = new URL(otherUrl, base);\n return base.origin === other.origin;\n}\n\n// Checks if URLs use one of the whitelisted protocols, e.g. to avoid XSS.\nfunction isValidProtocol(url) {\n if (!url) {\n return false;\n }\n switch (url.protocol) {\n case 'http:':\n case 'https:':\n case 'ftp:':\n case 'mailto:':\n case 'tel:':\n return true;\n default:\n return false;\n }\n}\n\n/**\n * Attempts to create a valid absolute URL (utilizing `isValidProtocol`).\n * @param {URL|string} url - An absolute, or relative, URL.\n * @param {URL|string} baseUrl - An absolute URL.\n * @returns Either a valid {URL}, or `null` otherwise.\n */\nfunction createValidAbsoluteUrl(url, baseUrl) {\n if (!url) {\n return null;\n }\n try {\n var absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url);\n if (isValidProtocol(absoluteUrl)) {\n return absoluteUrl;\n }\n } catch (ex) { /* `new URL()` will throw on incorrect data. */ }\n return null;\n}\n\nfunction shadow(obj, prop, value) {\n Object.defineProperty(obj, prop, { value,\n enumerable: true,\n configurable: true,\n writable: false, });\n return value;\n}\n\nfunction getLookupTableFactory(initializer) {\n var lookup;\n return function () {\n if (initializer) {\n lookup = Object.create(null);\n initializer(lookup);\n initializer = null;\n }\n return lookup;\n };\n}\n\nvar PasswordResponses = {\n NEED_PASSWORD: 1,\n INCORRECT_PASSWORD: 2,\n};\n\nvar PasswordException = (function PasswordExceptionClosure() {\n function PasswordException(msg, code) {\n this.name = 'PasswordException';\n this.message = msg;\n this.code = code;\n }\n\n PasswordException.prototype = new Error();\n PasswordException.constructor = PasswordException;\n\n return PasswordException;\n})();\n\nvar UnknownErrorException = (function UnknownErrorExceptionClosure() {\n function UnknownErrorException(msg, details) {\n this.name = 'UnknownErrorException';\n this.message = msg;\n this.details = details;\n }\n\n UnknownErrorException.prototype = new Error();\n UnknownErrorException.constructor = UnknownErrorException;\n\n return UnknownErrorException;\n})();\n\nvar InvalidPDFException = (function InvalidPDFExceptionClosure() {\n function InvalidPDFException(msg) {\n this.name = 'InvalidPDFException';\n this.message = msg;\n }\n\n InvalidPDFException.prototype = new Error();\n InvalidPDFException.constructor = InvalidPDFException;\n\n return InvalidPDFException;\n})();\n\nvar MissingPDFException = (function MissingPDFExceptionClosure() {\n function MissingPDFException(msg) {\n this.name = 'MissingPDFException';\n this.message = msg;\n }\n\n MissingPDFException.prototype = new Error();\n MissingPDFException.constructor = MissingPDFException;\n\n return MissingPDFException;\n})();\n\nvar UnexpectedResponseException =\n (function UnexpectedResponseExceptionClosure() {\n function UnexpectedResponseException(msg, status) {\n this.name = 'UnexpectedResponseException';\n this.message = msg;\n this.status = status;\n }\n\n UnexpectedResponseException.prototype = new Error();\n UnexpectedResponseException.constructor = UnexpectedResponseException;\n\n return UnexpectedResponseException;\n})();\n\nvar NotImplementedException = (function NotImplementedExceptionClosure() {\n function NotImplementedException(msg) {\n this.message = msg;\n }\n\n NotImplementedException.prototype = new Error();\n NotImplementedException.prototype.name = 'NotImplementedException';\n NotImplementedException.constructor = NotImplementedException;\n\n return NotImplementedException;\n})();\n\nvar MissingDataException = (function MissingDataExceptionClosure() {\n function MissingDataException(begin, end) {\n this.begin = begin;\n this.end = end;\n this.message = 'Missing data [' + begin + ', ' + end + ')';\n }\n\n MissingDataException.prototype = new Error();\n MissingDataException.prototype.name = 'MissingDataException';\n MissingDataException.constructor = MissingDataException;\n\n return MissingDataException;\n})();\n\nvar XRefParseException = (function XRefParseExceptionClosure() {\n function XRefParseException(msg) {\n this.message = msg;\n }\n\n XRefParseException.prototype = new Error();\n XRefParseException.prototype.name = 'XRefParseException';\n XRefParseException.constructor = XRefParseException;\n\n return XRefParseException;\n})();\n\n/**\n * Error caused during parsing PDF data.\n */\nlet FormatError = (function FormatErrorClosure() {\n function FormatError(msg) {\n this.message = msg;\n }\n\n FormatError.prototype = new Error();\n FormatError.prototype.name = 'FormatError';\n FormatError.constructor = FormatError;\n\n return FormatError;\n})();\n\n/**\n * Error used to indicate task cancellation.\n */\nlet AbortException = (function AbortExceptionClosure() {\n function AbortException(msg) {\n this.name = 'AbortException';\n this.message = msg;\n }\n\n AbortException.prototype = new Error();\n AbortException.constructor = AbortException;\n\n return AbortException;\n})();\n\nvar NullCharactersRegExp = /\\x00/g;\n\nfunction removeNullCharacters(str) {\n if (typeof str !== 'string') {\n warn('The argument for removeNullCharacters must be a string.');\n return str;\n }\n return str.replace(NullCharactersRegExp, '');\n}\n\nfunction bytesToString(bytes) {\n assert(bytes !== null && typeof bytes === 'object' &&\n bytes.length !== undefined, 'Invalid argument for bytesToString');\n var length = bytes.length;\n var MAX_ARGUMENT_COUNT = 8192;\n if (length < MAX_ARGUMENT_COUNT) {\n return String.fromCharCode.apply(null, bytes);\n }\n var strBuf = [];\n for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) {\n var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length);\n var chunk = bytes.subarray(i, chunkEnd);\n strBuf.push(String.fromCharCode.apply(null, chunk));\n }\n return strBuf.join('');\n}\n\nfunction stringToBytes(str) {\n assert(typeof str === 'string', 'Invalid argument for stringToBytes');\n var length = str.length;\n var bytes = new Uint8Array(length);\n for (var i = 0; i < length; ++i) {\n bytes[i] = str.charCodeAt(i) & 0xFF;\n }\n return bytes;\n}\n\n/**\n * Gets length of the array (Array, Uint8Array, or string) in bytes.\n * @param {Array|Uint8Array|string} arr\n * @returns {number}\n */\nfunction arrayByteLength(arr) {\n if (arr.length !== undefined) {\n return arr.length;\n }\n assert(arr.byteLength !== undefined);\n return arr.byteLength;\n}\n\n/**\n * Combines array items (arrays) into single Uint8Array object.\n * @param {Array} arr - the array of the arrays (Array, Uint8Array, or string).\n * @returns {Uint8Array}\n */\nfunction arraysToBytes(arr) {\n // Shortcut: if first and only item is Uint8Array, return it.\n if (arr.length === 1 && (arr[0] instanceof Uint8Array)) {\n return arr[0];\n }\n var resultLength = 0;\n var i, ii = arr.length;\n var item, itemLength;\n for (i = 0; i < ii; i++) {\n item = arr[i];\n itemLength = arrayByteLength(item);\n resultLength += itemLength;\n }\n var pos = 0;\n var data = new Uint8Array(resultLength);\n for (i = 0; i < ii; i++) {\n item = arr[i];\n if (!(item instanceof Uint8Array)) {\n if (typeof item === 'string') {\n item = stringToBytes(item);\n } else {\n item = new Uint8Array(item);\n }\n }\n itemLength = item.byteLength;\n data.set(item, pos);\n pos += itemLength;\n }\n return data;\n}\n\nfunction string32(value) {\n return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff,\n (value >> 8) & 0xff, value & 0xff);\n}\n\nfunction log2(x) {\n var n = 1, i = 0;\n while (x > n) {\n n <<= 1;\n i++;\n }\n return i;\n}\n\nfunction readInt8(data, start) {\n return (data[start] << 24) >> 24;\n}\n\nfunction readUint16(data, offset) {\n return (data[offset] << 8) | data[offset + 1];\n}\n\nfunction readUint32(data, offset) {\n return ((data[offset] << 24) | (data[offset + 1] << 16) |\n (data[offset + 2] << 8) | data[offset + 3]) >>> 0;\n}\n\n// Lazy test the endianness of the platform\n// NOTE: This will be 'true' for simulated TypedArrays\nfunction isLittleEndian() {\n var buffer8 = new Uint8Array(4);\n buffer8[0] = 1;\n var view32 = new Uint32Array(buffer8.buffer, 0, 1);\n return (view32[0] === 1);\n}\n\n// Checks if it's possible to eval JS expressions.\nfunction isEvalSupported() {\n try {\n new Function(''); // eslint-disable-line no-new, no-new-func\n return true;\n } catch (e) {\n return false;\n }\n}\n\nvar IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];\n\nvar Util = (function UtilClosure() {\n function Util() {}\n\n var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')'];\n\n // makeCssRgb() can be called thousands of times. Using |rgbBuf| avoids\n // creating many intermediate strings.\n Util.makeCssRgb = function Util_makeCssRgb(r, g, b) {\n rgbBuf[1] = r;\n rgbBuf[3] = g;\n rgbBuf[5] = b;\n return rgbBuf.join('');\n };\n\n // Concatenates two transformation matrices together and returns the result.\n Util.transform = function Util_transform(m1, m2) {\n return [\n m1[0] * m2[0] + m1[2] * m2[1],\n m1[1] * m2[0] + m1[3] * m2[1],\n m1[0] * m2[2] + m1[2] * m2[3],\n m1[1] * m2[2] + m1[3] * m2[3],\n m1[0] * m2[4] + m1[2] * m2[5] + m1[4],\n m1[1] * m2[4] + m1[3] * m2[5] + m1[5]\n ];\n };\n\n // For 2d affine transforms\n Util.applyTransform = function Util_applyTransform(p, m) {\n var xt = p[0] * m[0] + p[1] * m[2] + m[4];\n var yt = p[0] * m[1] + p[1] * m[3] + m[5];\n return [xt, yt];\n };\n\n Util.applyInverseTransform = function Util_applyInverseTransform(p, m) {\n var d = m[0] * m[3] - m[1] * m[2];\n var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;\n var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;\n return [xt, yt];\n };\n\n // Applies the transform to the rectangle and finds the minimum axially\n // aligned bounding box.\n Util.getAxialAlignedBoundingBox =\n function Util_getAxialAlignedBoundingBox(r, m) {\n\n var p1 = Util.applyTransform(r, m);\n var p2 = Util.applyTransform(r.slice(2, 4), m);\n var p3 = Util.applyTransform([r[0], r[3]], m);\n var p4 = Util.applyTransform([r[2], r[1]], m);\n return [\n Math.min(p1[0], p2[0], p3[0], p4[0]),\n Math.min(p1[1], p2[1], p3[1], p4[1]),\n Math.max(p1[0], p2[0], p3[0], p4[0]),\n Math.max(p1[1], p2[1], p3[1], p4[1])\n ];\n };\n\n Util.inverseTransform = function Util_inverseTransform(m) {\n var d = m[0] * m[3] - m[1] * m[2];\n return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d,\n (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d];\n };\n\n // Apply a generic 3d matrix M on a 3-vector v:\n // | a b c | | X |\n // | d e f | x | Y |\n // | g h i | | Z |\n // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i],\n // with v as [X,Y,Z]\n Util.apply3dTransform = function Util_apply3dTransform(m, v) {\n return [\n m[0] * v[0] + m[1] * v[1] + m[2] * v[2],\n m[3] * v[0] + m[4] * v[1] + m[5] * v[2],\n m[6] * v[0] + m[7] * v[1] + m[8] * v[2]\n ];\n };\n\n // This calculation uses Singular Value Decomposition.\n // The SVD can be represented with formula A = USV. We are interested in the\n // matrix S here because it represents the scale values.\n Util.singularValueDecompose2dScale =\n function Util_singularValueDecompose2dScale(m) {\n\n var transpose = [m[0], m[2], m[1], m[3]];\n\n // Multiply matrix m with its transpose.\n var a = m[0] * transpose[0] + m[1] * transpose[2];\n var b = m[0] * transpose[1] + m[1] * transpose[3];\n var c = m[2] * transpose[0] + m[3] * transpose[2];\n var d = m[2] * transpose[1] + m[3] * transpose[3];\n\n // Solve the second degree polynomial to get roots.\n var first = (a + d) / 2;\n var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2;\n var sx = first + second || 1;\n var sy = first - second || 1;\n\n // Scale values are the square roots of the eigenvalues.\n return [Math.sqrt(sx), Math.sqrt(sy)];\n };\n\n // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)\n // For coordinate systems whose origin lies in the bottom-left, this\n // means normalization to (BL,TR) ordering. For systems with origin in the\n // top-left, this means (TL,BR) ordering.\n Util.normalizeRect = function Util_normalizeRect(rect) {\n var r = rect.slice(0); // clone rect\n if (rect[0] > rect[2]) {\n r[0] = rect[2];\n r[2] = rect[0];\n }\n if (rect[1] > rect[3]) {\n r[1] = rect[3];\n r[3] = rect[1];\n }\n return r;\n };\n\n // Returns a rectangle [x1, y1, x2, y2] corresponding to the\n // intersection of rect1 and rect2. If no intersection, returns 'false'\n // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2]\n Util.intersect = function Util_intersect(rect1, rect2) {\n function compare(a, b) {\n return a - b;\n }\n\n // Order points along the axes\n var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare),\n orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare),\n result = [];\n\n rect1 = Util.normalizeRect(rect1);\n rect2 = Util.normalizeRect(rect2);\n\n // X: first and second points belong to different rectangles?\n if ((orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) ||\n (orderedX[0] === rect2[0] && orderedX[1] === rect1[0])) {\n // Intersection must be between second and third points\n result[0] = orderedX[1];\n result[2] = orderedX[2];\n } else {\n return false;\n }\n\n // Y: first and second points belong to different rectangles?\n if ((orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) ||\n (orderedY[0] === rect2[1] && orderedY[1] === rect1[1])) {\n // Intersection must be between second and third points\n result[1] = orderedY[1];\n result[3] = orderedY[2];\n } else {\n return false;\n }\n\n return result;\n };\n\n Util.sign = function Util_sign(num) {\n return num < 0 ? -1 : 1;\n };\n\n var ROMAN_NUMBER_MAP = [\n '', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM',\n '', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC',\n '', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'\n ];\n /**\n * Converts positive integers to (upper case) Roman numerals.\n * @param {integer} number - The number that should be converted.\n * @param {boolean} lowerCase - Indicates if the result should be converted\n * to lower case letters. The default is false.\n * @return {string} The resulting Roman number.\n */\n Util.toRoman = function Util_toRoman(number, lowerCase) {\n assert(isInt(number) && number > 0,\n 'The number should be a positive integer.');\n var pos, romanBuf = [];\n // Thousands\n while (number >= 1000) {\n number -= 1000;\n romanBuf.push('M');\n }\n // Hundreds\n pos = (number / 100) | 0;\n number %= 100;\n romanBuf.push(ROMAN_NUMBER_MAP[pos]);\n // Tens\n pos = (number / 10) | 0;\n number %= 10;\n romanBuf.push(ROMAN_NUMBER_MAP[10 + pos]);\n // Ones\n romanBuf.push(ROMAN_NUMBER_MAP[20 + number]);\n\n var romanStr = romanBuf.join('');\n return (lowerCase ? romanStr.toLowerCase() : romanStr);\n };\n\n Util.appendToArray = function Util_appendToArray(arr1, arr2) {\n Array.prototype.push.apply(arr1, arr2);\n };\n\n Util.prependToArray = function Util_prependToArray(arr1, arr2) {\n Array.prototype.unshift.apply(arr1, arr2);\n };\n\n Util.extendObj = function extendObj(obj1, obj2) {\n for (var key in obj2) {\n obj1[key] = obj2[key];\n }\n };\n\n Util.getInheritableProperty =\n function Util_getInheritableProperty(dict, name, getArray) {\n while (dict && !dict.has(name)) {\n dict = dict.get('Parent');\n }\n if (!dict) {\n return null;\n }\n return getArray ? dict.getArray(name) : dict.get(name);\n };\n\n Util.inherit = function Util_inherit(sub, base, prototype) {\n sub.prototype = Object.create(base.prototype);\n sub.prototype.constructor = sub;\n for (var prop in prototype) {\n sub.prototype[prop] = prototype[prop];\n }\n };\n\n Util.loadScript = function Util_loadScript(src, callback) {\n var script = document.createElement('script');\n var loaded = false;\n script.setAttribute('src', src);\n if (callback) {\n script.onload = function() {\n if (!loaded) {\n callback();\n }\n loaded = true;\n };\n }\n document.getElementsByTagName('head')[0].appendChild(script);\n };\n\n return Util;\n})();\n\n/**\n * PDF page viewport created based on scale, rotation and offset.\n * @class\n * @alias PageViewport\n */\nvar PageViewport = (function PageViewportClosure() {\n /**\n * @constructor\n * @private\n * @param viewBox {Array} xMin, yMin, xMax and yMax coordinates.\n * @param scale {number} scale of the viewport.\n * @param rotation {number} rotations of the viewport in degrees.\n * @param offsetX {number} offset X\n * @param offsetY {number} offset Y\n * @param dontFlip {boolean} if true, axis Y will not be flipped.\n */\n function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {\n this.viewBox = viewBox;\n this.scale = scale;\n this.rotation = rotation;\n this.offsetX = offsetX;\n this.offsetY = offsetY;\n\n // creating transform to convert pdf coordinate system to the normal\n // canvas like coordinates taking in account scale and rotation\n var centerX = (viewBox[2] + viewBox[0]) / 2;\n var centerY = (viewBox[3] + viewBox[1]) / 2;\n var rotateA, rotateB, rotateC, rotateD;\n rotation = rotation % 360;\n rotation = rotation < 0 ? rotation + 360 : rotation;\n switch (rotation) {\n case 180:\n rotateA = -1; rotateB = 0; rotateC = 0; rotateD = 1;\n break;\n case 90:\n rotateA = 0; rotateB = 1; rotateC = 1; rotateD = 0;\n break;\n case 270:\n rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0;\n break;\n // case 0:\n default:\n rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1;\n break;\n }\n\n if (dontFlip) {\n rotateC = -rotateC; rotateD = -rotateD;\n }\n\n var offsetCanvasX, offsetCanvasY;\n var width, height;\n if (rotateA === 0) {\n offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX;\n offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY;\n width = Math.abs(viewBox[3] - viewBox[1]) * scale;\n height = Math.abs(viewBox[2] - viewBox[0]) * scale;\n } else {\n offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX;\n offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY;\n width = Math.abs(viewBox[2] - viewBox[0]) * scale;\n height = Math.abs(viewBox[3] - viewBox[1]) * scale;\n }\n // creating transform for the following operations:\n // translate(-centerX, -centerY), rotate and flip vertically,\n // scale, and translate(offsetCanvasX, offsetCanvasY)\n this.transform = [\n rotateA * scale,\n rotateB * scale,\n rotateC * scale,\n rotateD * scale,\n offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY,\n offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY\n ];\n\n this.width = width;\n this.height = height;\n this.fontScale = scale;\n }\n PageViewport.prototype = /** @lends PageViewport.prototype */ {\n /**\n * Clones viewport with additional properties.\n * @param args {Object} (optional) If specified, may contain the 'scale' or\n * 'rotation' properties to override the corresponding properties in\n * the cloned viewport.\n * @returns {PageViewport} Cloned viewport.\n */\n clone: function PageViewPort_clone(args) {\n args = args || {};\n var scale = 'scale' in args ? args.scale : this.scale;\n var rotation = 'rotation' in args ? args.rotation : this.rotation;\n return new PageViewport(this.viewBox.slice(), scale, rotation,\n this.offsetX, this.offsetY, args.dontFlip);\n },\n /**\n * Converts PDF point to the viewport coordinates. For examples, useful for\n * converting PDF location into canvas pixel coordinates.\n * @param x {number} X coordinate.\n * @param y {number} Y coordinate.\n * @returns {Object} Object that contains 'x' and 'y' properties of the\n * point in the viewport coordinate space.\n * @see {@link convertToPdfPoint}\n * @see {@link convertToViewportRectangle}\n */\n convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {\n return Util.applyTransform([x, y], this.transform);\n },\n /**\n * Converts PDF rectangle to the viewport coordinates.\n * @param rect {Array} xMin, yMin, xMax and yMax coordinates.\n * @returns {Array} Contains corresponding coordinates of the rectangle\n * in the viewport coordinate space.\n * @see {@link convertToViewportPoint}\n */\n convertToViewportRectangle:\n function PageViewport_convertToViewportRectangle(rect) {\n var tl = Util.applyTransform([rect[0], rect[1]], this.transform);\n var br = Util.applyTransform([rect[2], rect[3]], this.transform);\n return [tl[0], tl[1], br[0], br[1]];\n },\n /**\n * Converts viewport coordinates to the PDF location. For examples, useful\n * for converting canvas pixel location into PDF one.\n * @param x {number} X coordinate.\n * @param y {number} Y coordinate.\n * @returns {Object} Object that contains 'x' and 'y' properties of the\n * point in the PDF coordinate space.\n * @see {@link convertToViewportPoint}\n */\n convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) {\n return Util.applyInverseTransform([x, y], this.transform);\n },\n };\n return PageViewport;\n})();\n\nvar PDFStringTranslateTable = [\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014,\n 0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C,\n 0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160,\n 0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC\n];\n\nfunction stringToPDFString(str) {\n var i, n = str.length, strBuf = [];\n if (str[0] === '\\xFE' && str[1] === '\\xFF') {\n // UTF16BE BOM\n for (i = 2; i < n; i += 2) {\n strBuf.push(String.fromCharCode(\n (str.charCodeAt(i) << 8) | str.charCodeAt(i + 1)));\n }\n } else {\n for (i = 0; i < n; ++i) {\n var code = PDFStringTranslateTable[str.charCodeAt(i)];\n strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));\n }\n }\n return strBuf.join('');\n}\n\nfunction stringToUTF8String(str) {\n return decodeURIComponent(escape(str));\n}\n\nfunction utf8StringToString(str) {\n return unescape(encodeURIComponent(str));\n}\n\nfunction isEmptyObj(obj) {\n for (var key in obj) {\n return false;\n }\n return true;\n}\n\nfunction isBool(v) {\n return typeof v === 'boolean';\n}\n\nfunction isInt(v) {\n return typeof v === 'number' && ((v | 0) === v);\n}\n\nfunction isNum(v) {\n return typeof v === 'number';\n}\n\nfunction isString(v) {\n return typeof v === 'string';\n}\n\nfunction isArray(v) {\n return v instanceof Array;\n}\n\nfunction isArrayBuffer(v) {\n return typeof v === 'object' && v !== null && v.byteLength !== undefined;\n}\n\n// Checks if ch is one of the following characters: SPACE, TAB, CR or LF.\nfunction isSpace(ch) {\n return (ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A);\n}\n\nfunction isNodeJS() {\n // eslint-disable-next-line no-undef\n return typeof process === 'object' && process + '' === '[object process]';\n}\n\n/**\n * Promise Capability object.\n *\n * @typedef {Object} PromiseCapability\n * @property {Promise} promise - A promise object.\n * @property {function} resolve - Fulfills the promise.\n * @property {function} reject - Rejects the promise.\n */\n\n/**\n * Creates a promise capability object.\n * @alias createPromiseCapability\n *\n * @return {PromiseCapability} A capability object contains:\n * - a Promise, resolve and reject methods.\n */\nfunction createPromiseCapability() {\n var capability = {};\n capability.promise = new Promise(function (resolve, reject) {\n capability.resolve = resolve;\n capability.reject = reject;\n });\n return capability;\n}\n\nvar StatTimer = (function StatTimerClosure() {\n function rpad(str, pad, length) {\n while (str.length < length) {\n str += pad;\n }\n return str;\n }\n function StatTimer() {\n this.started = Object.create(null);\n this.times = [];\n this.enabled = true;\n }\n StatTimer.prototype = {\n time: function StatTimer_time(name) {\n if (!this.enabled) {\n return;\n }\n if (name in this.started) {\n warn('Timer is already running for ' + name);\n }\n this.started[name] = Date.now();\n },\n timeEnd: function StatTimer_timeEnd(name) {\n if (!this.enabled) {\n return;\n }\n if (!(name in this.started)) {\n warn('Timer has not been started for ' + name);\n }\n this.times.push({\n 'name': name,\n 'start': this.started[name],\n 'end': Date.now(),\n });\n // Remove timer from started so it can be called again.\n delete this.started[name];\n },\n toString: function StatTimer_toString() {\n var i, ii;\n var times = this.times;\n var out = '';\n // Find the longest name for padding purposes.\n var longest = 0;\n for (i = 0, ii = times.length; i < ii; ++i) {\n var name = times[i]['name'];\n if (name.length > longest) {\n longest = name.length;\n }\n }\n for (i = 0, ii = times.length; i < ii; ++i) {\n var span = times[i];\n var duration = span.end - span.start;\n out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\\n';\n }\n return out;\n },\n };\n return StatTimer;\n})();\n\nvar createBlob = function createBlob(data, contentType) {\n if (typeof Blob !== 'undefined') {\n return new Blob([data], { type: contentType, });\n }\n throw new Error('The \"Blob\" constructor is not supported.');\n};\n\nvar createObjectURL = (function createObjectURLClosure() {\n // Blob/createObjectURL is not available, falling back to data schema.\n var digits =\n 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';\n\n return function createObjectURL(data, contentType, forceDataSchema = false) {\n if (!forceDataSchema && URL.createObjectURL) {\n var blob = createBlob(data, contentType);\n return URL.createObjectURL(blob);\n }\n\n var buffer = 'data:' + contentType + ';base64,';\n for (var i = 0, ii = data.length; i < ii; i += 3) {\n var b1 = data[i] & 0xFF;\n var b2 = data[i + 1] & 0xFF;\n var b3 = data[i + 2] & 0xFF;\n var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);\n var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;\n var d4 = i + 2 < ii ? (b3 & 0x3F) : 64;\n buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];\n }\n return buffer;\n };\n})();\n\nfunction resolveCall(fn, args, thisArg = null) {\n if (!fn) {\n return Promise.resolve(undefined);\n }\n return new Promise((resolve, reject) => {\n resolve(fn.apply(thisArg, args));\n });\n}\n\nfunction wrapReason(reason) {\n if (typeof reason !== 'object') {\n return reason;\n }\n switch (reason.name) {\n case 'AbortException':\n return new AbortException(reason.message);\n case 'MissingPDFException':\n return new MissingPDFException(reason.message);\n case 'UnexpectedResponseException':\n return new UnexpectedResponseException(reason.message, reason.status);\n default:\n return new UnknownErrorException(reason.message, reason.details);\n }\n}\n\nfunction resolveOrReject(capability, success, reason) {\n if (success) {\n capability.resolve();\n } else {\n capability.reject(reason);\n }\n}\n\nfunction finalize(promise) {\n return Promise.resolve(promise).catch(() => {});\n}\n\nfunction MessageHandler(sourceName, targetName, comObj) {\n this.sourceName = sourceName;\n this.targetName = targetName;\n this.comObj = comObj;\n this.callbackId = 1;\n this.streamId = 1;\n this.postMessageTransfers = true;\n this.streamSinks = Object.create(null);\n this.streamControllers = Object.create(null);\n let callbacksCapabilities = this.callbacksCapabilities = Object.create(null);\n let ah = this.actionHandler = Object.create(null);\n\n this._onComObjOnMessage = (event) => {\n let data = event.data;\n if (data.targetName !== this.sourceName) {\n return;\n }\n if (data.stream) {\n this._processStreamMessage(data);\n } else if (data.isReply) {\n let callbackId = data.callbackId;\n if (data.callbackId in callbacksCapabilities) {\n let callback = callbacksCapabilities[callbackId];\n delete callbacksCapabilities[callbackId];\n if ('error' in data) {\n callback.reject(wrapReason(data.error));\n } else {\n callback.resolve(data.data);\n }\n } else {\n throw new Error(`Cannot resolve callback ${callbackId}`);\n }\n } else if (data.action in ah) {\n let action = ah[data.action];\n if (data.callbackId) {\n let sourceName = this.sourceName;\n let targetName = data.sourceName;\n Promise.resolve().then(function () {\n return action[0].call(action[1], data.data);\n }).then((result) => {\n comObj.postMessage({\n sourceName,\n targetName,\n isReply: true,\n callbackId: data.callbackId,\n data: result,\n });\n }, (reason) => {\n if (reason instanceof Error) {\n // Serialize error to avoid \"DataCloneError\"\n reason = reason + '';\n }\n comObj.postMessage({\n sourceName,\n targetName,\n isReply: true,\n callbackId: data.callbackId,\n error: reason,\n });\n });\n } else if (data.streamId) {\n this._createStreamSink(data);\n } else {\n action[0].call(action[1], data.data);\n }\n } else {\n throw new Error(`Unknown action from worker: ${data.action}`);\n }\n };\n comObj.addEventListener('message', this._onComObjOnMessage);\n}\n\nMessageHandler.prototype = {\n on(actionName, handler, scope) {\n var ah = this.actionHandler;\n if (ah[actionName]) {\n throw new Error(`There is already an actionName called \"${actionName}\"`);\n }\n ah[actionName] = [handler, scope];\n },\n /**\n * Sends a message to the comObj to invoke the action with the supplied data.\n * @param {String} actionName - Action to call.\n * @param {JSON} data - JSON data to send.\n * @param {Array} [transfers] - Optional list of transfers/ArrayBuffers\n */\n send(actionName, data, transfers) {\n var message = {\n sourceName: this.sourceName,\n targetName: this.targetName,\n action: actionName,\n data,\n };\n this.postMessage(message, transfers);\n },\n /**\n * Sends a message to the comObj to invoke the action with the supplied data.\n * Expects that the other side will callback with the response.\n * @param {String} actionName - Action to call.\n * @param {JSON} data - JSON data to send.\n * @param {Array} [transfers] - Optional list of transfers/ArrayBuffers.\n * @returns {Promise} Promise to be resolved with response data.\n */\n sendWithPromise(actionName, data, transfers) {\n var callbackId = this.callbackId++;\n var message = {\n sourceName: this.sourceName,\n targetName: this.targetName,\n action: actionName,\n data,\n callbackId,\n };\n var capability = createPromiseCapability();\n this.callbacksCapabilities[callbackId] = capability;\n try {\n this.postMessage(message, transfers);\n } catch (e) {\n capability.reject(e);\n }\n return capability.promise;\n },\n /**\n * Sends a message to the comObj to invoke the action with the supplied data.\n * Expect that the other side will callback to signal 'start_complete'.\n * @param {String} actionName - Action to call.\n * @param {JSON} data - JSON data to send.\n * @param {Object} queueingStrategy - strategy to signal backpressure based on\n * internal queue.\n * @param {Array} [transfers] - Optional list of transfers/ArrayBuffers.\n * @return {ReadableStream} ReadableStream to read data in chunks.\n */\n sendWithStream(actionName, data, queueingStrategy, transfers) {\n let streamId = this.streamId++;\n let sourceName = this.sourceName;\n let targetName = this.targetName;\n\n return new ReadableStream({\n start: (controller) => {\n let startCapability = createPromiseCapability();\n this.streamControllers[streamId] = {\n controller,\n startCall: startCapability,\n isClosed: false,\n };\n this.postMessage({\n sourceName,\n targetName,\n action: actionName,\n streamId,\n data,\n desiredSize: controller.desiredSize,\n });\n // Return Promise for Async process, to signal success/failure.\n return startCapability.promise;\n },\n\n pull: (controller) => {\n let pullCapability = createPromiseCapability();\n this.streamControllers[streamId].pullCall = pullCapability;\n this.postMessage({\n sourceName,\n targetName,\n stream: 'pull',\n streamId,\n desiredSize: controller.desiredSize,\n });\n // Returning Promise will not call \"pull\"\n // again until current pull is resolved.\n return pullCapability.promise;\n },\n\n cancel: (reason) => {\n let cancelCapability = createPromiseCapability();\n this.streamControllers[streamId].cancelCall = cancelCapability;\n this.streamControllers[streamId].isClosed = true;\n this.postMessage({\n sourceName,\n targetName,\n stream: 'cancel',\n reason,\n streamId,\n });\n // Return Promise to signal success or failure.\n return cancelCapability.promise;\n },\n }, queueingStrategy);\n },\n\n _createStreamSink(data) {\n let self = this;\n let action = this.actionHandler[data.action];\n let streamId = data.streamId;\n let desiredSize = data.desiredSize;\n let sourceName = this.sourceName;\n let targetName = data.sourceName;\n let capability = createPromiseCapability();\n\n let sendStreamRequest = ({ stream, chunk, transfers,\n success, reason, }) => {\n this.postMessage({ sourceName, targetName, stream, streamId,\n chunk, success, reason, }, transfers);\n };\n\n let streamSink = {\n enqueue(chunk, size = 1, transfers) {\n if (this.isCancelled) {\n return;\n }\n let lastDesiredSize = this.desiredSize;\n this.desiredSize -= size;\n // Enqueue decreases the desiredSize property of sink,\n // so when it changes from positive to negative,\n // set ready as unresolved promise.\n if (lastDesiredSize > 0 && this.desiredSize <= 0) {\n this.sinkCapability = createPromiseCapability();\n this.ready = this.sinkCapability.promise;\n }\n sendStreamRequest({ stream: 'enqueue', chunk, transfers, });\n },\n\n close() {\n if (this.isCancelled) {\n return;\n }\n sendStreamRequest({ stream: 'close', });\n delete self.streamSinks[streamId];\n },\n\n error(reason) {\n if (this.isCancelled) {\n return;\n }\n this.isCancelled = true;\n sendStreamRequest({ stream: 'error', reason, });\n },\n\n sinkCapability: capability,\n onPull: null,\n onCancel: null,\n isCancelled: false,\n desiredSize,\n ready: null,\n };\n\n streamSink.sinkCapability.resolve();\n streamSink.ready = streamSink.sinkCapability.promise;\n this.streamSinks[streamId] = streamSink;\n resolveCall(action[0], [data.data, streamSink], action[1]).then(() => {\n sendStreamRequest({ stream: 'start_complete', success: true, });\n }, (reason) => {\n sendStreamRequest({ stream: 'start_complete', success: false, reason, });\n });\n },\n\n _processStreamMessage(data) {\n let sourceName = this.sourceName;\n let targetName = data.sourceName;\n let streamId = data.streamId;\n\n let sendStreamResponse = ({ stream, success, reason, }) => {\n this.comObj.postMessage({ sourceName, targetName, stream,\n success, streamId, reason, });\n };\n\n let deleteStreamController = () => {\n // Delete streamController only when start, pull and\n // cancel callbacks are resolved, to avoid \"TypeError\".\n Promise.all([\n this.streamControllers[data.streamId].startCall,\n this.streamControllers[data.streamId].pullCall,\n this.streamControllers[data.streamId].cancelCall\n ].map(function(capability) {\n return capability && finalize(capability.promise);\n })).then(() => {\n delete this.streamControllers[data.streamId];\n });\n };\n\n switch (data.stream) {\n case 'start_complete':\n resolveOrReject(this.streamControllers[data.streamId].startCall,\n data.success, wrapReason(data.reason));\n break;\n case 'pull_complete':\n resolveOrReject(this.streamControllers[data.streamId].pullCall,\n data.success, wrapReason(data.reason));\n break;\n case 'pull':\n // Ignore any pull after close is called.\n if (!this.streamSinks[data.streamId]) {\n sendStreamResponse({ stream: 'pull_complete', success: true, });\n break;\n }\n // Pull increases the desiredSize property of sink,\n // so when it changes from negative to positive,\n // set ready property as resolved promise.\n if (this.streamSinks[data.streamId].desiredSize <= 0 &&\n data.desiredSize > 0) {\n this.streamSinks[data.streamId].sinkCapability.resolve();\n }\n // Reset desiredSize property of sink on every pull.\n this.streamSinks[data.streamId].desiredSize = data.desiredSize;\n resolveCall(this.streamSinks[data.streamId].onPull).then(() => {\n sendStreamResponse({ stream: 'pull_complete', success: true, });\n }, (reason) => {\n sendStreamResponse({ stream: 'pull_complete',\n success: false, reason, });\n });\n break;\n case 'enqueue':\n assert(this.streamControllers[data.streamId],\n 'enqueue should have stream controller');\n if (!this.streamControllers[data.streamId].isClosed) {\n this.streamControllers[data.streamId].controller.enqueue(data.chunk);\n }\n break;\n case 'close':\n assert(this.streamControllers[data.streamId],\n 'close should have stream controller');\n if (this.streamControllers[data.streamId].isClosed) {\n break;\n }\n this.streamControllers[data.streamId].isClosed = true;\n this.streamControllers[data.streamId].controller.close();\n deleteStreamController();\n break;\n case 'error':\n assert(this.streamControllers[data.streamId],\n 'error should have stream controller');\n this.streamControllers[data.streamId].controller.\n error(wrapReason(data.reason));\n deleteStreamController();\n break;\n case 'cancel_complete':\n resolveOrReject(this.streamControllers[data.streamId].cancelCall,\n data.success, wrapReason(data.reason));\n deleteStreamController();\n break;\n case 'cancel':\n if (!this.streamSinks[data.streamId]) {\n break;\n }\n resolveCall(this.streamSinks[data.streamId].onCancel,\n [wrapReason(data.reason)]).then(() => {\n sendStreamResponse({ stream: 'cancel_complete', success: true, });\n }, (reason) => {\n sendStreamResponse({ stream: 'cancel_complete',\n success: false, reason, });\n });\n this.streamSinks[data.streamId].sinkCapability.\n reject(wrapReason(data.reason));\n this.streamSinks[data.streamId].isCancelled = true;\n delete this.streamSinks[data.streamId];\n break;\n default:\n throw new Error('Unexpected stream case');\n }\n },\n\n /**\n * Sends raw message to the comObj.\n * @private\n * @param {Object} message - Raw message.\n * @param transfers List of transfers/ArrayBuffers, or undefined.\n */\n postMessage(message, transfers) {\n if (transfers && this.postMessageTransfers) {\n this.comObj.postMessage(message, transfers);\n } else {\n this.comObj.postMessage(message);\n }\n },\n\n destroy() {\n this.comObj.removeEventListener('message', this._onComObjOnMessage);\n },\n};\n\nfunction loadJpegStream(id, imageUrl, objs) {\n var img = new Image();\n img.onload = (function loadJpegStream_onloadClosure() {\n objs.resolve(id, img);\n });\n img.onerror = (function loadJpegStream_onerrorClosure() {\n objs.resolve(id, null);\n warn('Error during JPEG image loading');\n });\n img.src = imageUrl;\n}\n\nexport {\n FONT_IDENTITY_MATRIX,\n IDENTITY_MATRIX,\n OPS,\n VERBOSITY_LEVELS,\n UNSUPPORTED_FEATURES,\n AnnotationBorderStyleType,\n AnnotationFieldFlag,\n AnnotationFlag,\n AnnotationType,\n FontType,\n ImageKind,\n CMapCompressionType,\n AbortException,\n InvalidPDFException,\n MessageHandler,\n MissingDataException,\n MissingPDFException,\n NativeImageDecoding,\n NotImplementedException,\n PageViewport,\n PasswordException,\n PasswordResponses,\n StatTimer,\n StreamType,\n TextRenderingMode,\n UnexpectedResponseException,\n UnknownErrorException,\n Util,\n XRefParseException,\n FormatError,\n arrayByteLength,\n arraysToBytes,\n assert,\n bytesToString,\n createBlob,\n createPromiseCapability,\n createObjectURL,\n deprecated,\n getLookupTableFactory,\n getVerbosityLevel,\n globalScope,\n info,\n isArray,\n isArrayBuffer,\n isBool,\n isEmptyObj,\n isInt,\n isNum,\n isString,\n isSpace,\n isNodeJS,\n isSameOrigin,\n createValidAbsoluteUrl,\n isLittleEndian,\n isEvalSupported,\n loadJpegStream,\n log2,\n readInt8,\n readUint16,\n readUint32,\n removeNullCharacters,\n ReadableStream,\n setVerbosityLevel,\n shadow,\n string32,\n stringToBytes,\n stringToPDFString,\n stringToUTF8String,\n utf8StringToString,\n warn,\n unreachable,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/shared/util.js", + "/* Copyright 2015 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n CMapCompressionType, createValidAbsoluteUrl, deprecated, globalScope,\n removeNullCharacters, stringToBytes, warn\n} from '../shared/util';\n\nvar DEFAULT_LINK_REL = 'noopener noreferrer nofollow';\n\nclass DOMCanvasFactory {\n create(width, height) {\n if (width <= 0 || height <= 0) {\n throw new Error('invalid canvas size');\n }\n let canvas = document.createElement('canvas');\n let context = canvas.getContext('2d');\n canvas.width = width;\n canvas.height = height;\n return {\n canvas,\n context,\n };\n }\n\n reset(canvasAndContext, width, height) {\n if (!canvasAndContext.canvas) {\n throw new Error('canvas is not specified');\n }\n if (width <= 0 || height <= 0) {\n throw new Error('invalid canvas size');\n }\n canvasAndContext.canvas.width = width;\n canvasAndContext.canvas.height = height;\n }\n\n destroy(canvasAndContext) {\n if (!canvasAndContext.canvas) {\n throw new Error('canvas is not specified');\n }\n // Zeroing the width and height cause Firefox to release graphics\n // resources immediately, which can greatly reduce memory consumption.\n canvasAndContext.canvas.width = 0;\n canvasAndContext.canvas.height = 0;\n canvasAndContext.canvas = null;\n canvasAndContext.context = null;\n }\n}\n\nclass DOMCMapReaderFactory {\n constructor({ baseUrl = null, isCompressed = false, }) {\n this.baseUrl = baseUrl;\n this.isCompressed = isCompressed;\n }\n\n fetch({ name, }) {\n if (!name) {\n return Promise.reject(new Error('CMap name must be specified.'));\n }\n return new Promise((resolve, reject) => {\n let url = this.baseUrl + name + (this.isCompressed ? '.bcmap' : '');\n\n let request = new XMLHttpRequest();\n request.open('GET', url, true);\n\n if (this.isCompressed) {\n request.responseType = 'arraybuffer';\n }\n request.onreadystatechange = () => {\n if (request.readyState !== XMLHttpRequest.DONE) {\n return;\n }\n if (request.status === 200 || request.status === 0) {\n let data;\n if (this.isCompressed && request.response) {\n data = new Uint8Array(request.response);\n } else if (!this.isCompressed && request.responseText) {\n data = stringToBytes(request.responseText);\n }\n if (data) {\n resolve({\n cMapData: data,\n compressionType: this.isCompressed ?\n CMapCompressionType.BINARY : CMapCompressionType.NONE,\n });\n return;\n }\n }\n reject(new Error('Unable to load ' +\n (this.isCompressed ? 'binary ' : '') +\n 'CMap at: ' + url));\n };\n\n request.send(null);\n });\n }\n}\n\n/**\n * Optimised CSS custom property getter/setter.\n * @class\n */\nvar CustomStyle = (function CustomStyleClosure() {\n\n // As noted on: http://www.zachstronaut.com/posts/2009/02/17/\n // animate-css-transforms-firefox-webkit.html\n // in some versions of IE9 it is critical that ms appear in this list\n // before Moz\n var prefixes = ['ms', 'Moz', 'Webkit', 'O'];\n var _cache = Object.create(null);\n\n function CustomStyle() {}\n\n CustomStyle.getProp = function get(propName, element) {\n // check cache only when no element is given\n if (arguments.length === 1 && typeof _cache[propName] === 'string') {\n return _cache[propName];\n }\n\n element = element || document.documentElement;\n var style = element.style, prefixed, uPropName;\n\n // test standard property first\n if (typeof style[propName] === 'string') {\n return (_cache[propName] = propName);\n }\n\n // capitalize\n uPropName = propName.charAt(0).toUpperCase() + propName.slice(1);\n\n // test vendor specific properties\n for (var i = 0, l = prefixes.length; i < l; i++) {\n prefixed = prefixes[i] + uPropName;\n if (typeof style[prefixed] === 'string') {\n return (_cache[propName] = prefixed);\n }\n }\n\n // If all fails then set to undefined.\n return (_cache[propName] = 'undefined');\n };\n\n CustomStyle.setProp = function set(propName, element, str) {\n var prop = this.getProp(propName);\n if (prop !== 'undefined') {\n element.style[prop] = str;\n }\n };\n\n return CustomStyle;\n})();\n\nvar RenderingCancelledException = (function RenderingCancelledException() {\n function RenderingCancelledException(msg, type) {\n this.message = msg;\n this.type = type;\n }\n\n RenderingCancelledException.prototype = new Error();\n RenderingCancelledException.prototype.name = 'RenderingCancelledException';\n RenderingCancelledException.constructor = RenderingCancelledException;\n\n return RenderingCancelledException;\n})();\n\nvar LinkTarget = {\n NONE: 0, // Default value.\n SELF: 1,\n BLANK: 2,\n PARENT: 3,\n TOP: 4,\n};\n\nvar LinkTargetStringMap = [\n '',\n '_self',\n '_blank',\n '_parent',\n '_top'\n];\n\n/**\n * @typedef ExternalLinkParameters\n * @typedef {Object} ExternalLinkParameters\n * @property {string} url - An absolute URL.\n * @property {LinkTarget} target - The link target.\n * @property {string} rel - The link relationship.\n */\n\n/**\n * Adds various attributes (href, title, target, rel) to hyperlinks.\n * @param {HTMLLinkElement} link - The link element.\n * @param {ExternalLinkParameters} params\n */\nfunction addLinkAttributes(link, params) {\n var url = params && params.url;\n link.href = link.title = (url ? removeNullCharacters(url) : '');\n\n if (url) {\n var target = params.target;\n if (typeof target === 'undefined') {\n target = getDefaultSetting('externalLinkTarget');\n }\n link.target = LinkTargetStringMap[target];\n\n var rel = params.rel;\n if (typeof rel === 'undefined') {\n rel = getDefaultSetting('externalLinkRel');\n }\n link.rel = rel;\n }\n}\n\n// Gets the file name from a given URL.\nfunction getFilenameFromUrl(url) {\n var anchor = url.indexOf('#');\n var query = url.indexOf('?');\n var end = Math.min(\n anchor > 0 ? anchor : url.length,\n query > 0 ? query : url.length);\n return url.substring(url.lastIndexOf('/', end) + 1, end);\n}\n\nfunction getDefaultSetting(id) {\n // The list of the settings and their default is maintained for backward\n // compatibility and shall not be extended or modified. See also global.js.\n var globalSettings = globalScope.PDFJS;\n switch (id) {\n case 'pdfBug':\n return globalSettings ? globalSettings.pdfBug : false;\n case 'disableAutoFetch':\n return globalSettings ? globalSettings.disableAutoFetch : false;\n case 'disableStream':\n return globalSettings ? globalSettings.disableStream : false;\n case 'disableRange':\n return globalSettings ? globalSettings.disableRange : false;\n case 'disableFontFace':\n return globalSettings ? globalSettings.disableFontFace : false;\n case 'disableCreateObjectURL':\n return globalSettings ? globalSettings.disableCreateObjectURL : false;\n case 'disableWebGL':\n return globalSettings ? globalSettings.disableWebGL : true;\n case 'cMapUrl':\n return globalSettings ? globalSettings.cMapUrl : null;\n case 'cMapPacked':\n return globalSettings ? globalSettings.cMapPacked : false;\n case 'postMessageTransfers':\n return globalSettings ? globalSettings.postMessageTransfers : true;\n case 'workerPort':\n return globalSettings ? globalSettings.workerPort : null;\n case 'workerSrc':\n return globalSettings ? globalSettings.workerSrc : null;\n case 'disableWorker':\n return globalSettings ? globalSettings.disableWorker : false;\n case 'maxImageSize':\n return globalSettings ? globalSettings.maxImageSize : -1;\n case 'imageResourcesPath':\n return globalSettings ? globalSettings.imageResourcesPath : '';\n case 'isEvalSupported':\n return globalSettings ? globalSettings.isEvalSupported : true;\n case 'externalLinkTarget':\n if (!globalSettings) {\n return LinkTarget.NONE;\n }\n switch (globalSettings.externalLinkTarget) {\n case LinkTarget.NONE:\n case LinkTarget.SELF:\n case LinkTarget.BLANK:\n case LinkTarget.PARENT:\n case LinkTarget.TOP:\n return globalSettings.externalLinkTarget;\n }\n warn('PDFJS.externalLinkTarget is invalid: ' +\n globalSettings.externalLinkTarget);\n // Reset the external link target, to suppress further warnings.\n globalSettings.externalLinkTarget = LinkTarget.NONE;\n return LinkTarget.NONE;\n case 'externalLinkRel':\n return globalSettings ? globalSettings.externalLinkRel : DEFAULT_LINK_REL;\n case 'enableStats':\n return !!(globalSettings && globalSettings.enableStats);\n case 'pdfjsNext':\n return !!(globalSettings && globalSettings.pdfjsNext);\n default:\n throw new Error('Unknown default setting: ' + id);\n }\n}\n\nfunction isExternalLinkTargetSet() {\n var externalLinkTarget = getDefaultSetting('externalLinkTarget');\n switch (externalLinkTarget) {\n case LinkTarget.NONE:\n return false;\n case LinkTarget.SELF:\n case LinkTarget.BLANK:\n case LinkTarget.PARENT:\n case LinkTarget.TOP:\n return true;\n }\n}\n\nfunction isValidUrl(url, allowRelative) {\n deprecated('isValidUrl(), please use createValidAbsoluteUrl() instead.');\n var baseUrl = allowRelative ? 'http://example.com' : null;\n return createValidAbsoluteUrl(url, baseUrl) !== null;\n}\n\nexport {\n CustomStyle,\n RenderingCancelledException,\n addLinkAttributes,\n isExternalLinkTargetSet,\n isValidUrl,\n getFilenameFromUrl,\n LinkTarget,\n getDefaultSetting,\n DEFAULT_LINK_REL,\n DOMCanvasFactory,\n DOMCMapReaderFactory,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/display/dom_utils.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* globals requirejs, __non_webpack_require__ */\n\nimport {\n assert, createPromiseCapability, deprecated, getVerbosityLevel, globalScope,\n info, InvalidPDFException, isArray, isArrayBuffer, isInt, isSameOrigin,\n loadJpegStream, MessageHandler, MissingPDFException, NativeImageDecoding,\n PageViewport, PasswordException, StatTimer, stringToBytes,\n UnexpectedResponseException, UnknownErrorException, Util, warn\n} from '../shared/util';\nimport {\n DOMCanvasFactory, DOMCMapReaderFactory, getDefaultSetting,\n RenderingCancelledException\n} from './dom_utils';\nimport { FontFaceObject, FontLoader } from './font_loader';\nimport { CanvasGraphics } from './canvas';\nimport { Metadata } from './metadata';\nimport { PDFDataTransportStream } from './transport_stream';\n\nvar DEFAULT_RANGE_CHUNK_SIZE = 65536; // 2^16 = 65536\n\nvar isWorkerDisabled = false;\nvar workerSrc;\nvar isPostMessageTransfersDisabled = false;\n\nvar pdfjsFilePath =\n typeof PDFJSDev !== 'undefined' &&\n PDFJSDev.test('PRODUCTION && !(MOZCENTRAL || FIREFOX)') &&\n typeof document !== 'undefined' && document.currentScript ?\n document.currentScript.src : null;\n\nvar fakeWorkerFilesLoader = null;\nvar useRequireEnsure = false;\nif (typeof PDFJSDev !== 'undefined' &&\n PDFJSDev.test('GENERIC && !SINGLE_FILE')) {\n // For GENERIC build we need add support of different fake file loaders\n // for different frameworks.\n if (typeof window === 'undefined') {\n // node.js - disable worker and set require.ensure.\n isWorkerDisabled = true;\n if (typeof __non_webpack_require__.ensure === 'undefined') {\n __non_webpack_require__.ensure = __non_webpack_require__('node-ensure');\n }\n useRequireEnsure = true;\n } else if (typeof __non_webpack_require__ !== 'undefined' &&\n typeof __non_webpack_require__.ensure === 'function') {\n useRequireEnsure = true;\n }\n if (typeof requirejs !== 'undefined' && requirejs.toUrl) {\n workerSrc = requirejs.toUrl('pdfjs-dist/build/pdf.worker.js');\n }\n var dynamicLoaderSupported =\n typeof requirejs !== 'undefined' && requirejs.load;\n fakeWorkerFilesLoader = useRequireEnsure ? (function (callback) {\n __non_webpack_require__.ensure([], function () {\n var worker;\n if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('LIB')) {\n worker = __non_webpack_require__('../pdf.worker.js');\n } else {\n worker = __non_webpack_require__('./pdf.worker.js');\n }\n callback(worker.WorkerMessageHandler);\n });\n }) : dynamicLoaderSupported ? (function (callback) {\n requirejs(['pdfjs-dist/build/pdf.worker'], function (worker) {\n callback(worker.WorkerMessageHandler);\n });\n }) : null;\n}\n\n/** @type IPDFStream */\nvar PDFNetworkStream;\n\n/**\n * Sets PDFNetworkStream class to be used as alternative PDF data transport.\n * @param {IPDFStream} cls - the PDF data transport.\n */\nfunction setPDFNetworkStreamClass(cls) {\n PDFNetworkStream = cls;\n}\n\n/**\n * Document initialization / loading parameters object.\n *\n * @typedef {Object} DocumentInitParameters\n * @property {string} url - The URL of the PDF.\n * @property {TypedArray|Array|string} data - Binary PDF data. Use typed arrays\n * (Uint8Array) to improve the memory usage. If PDF data is BASE64-encoded,\n * use atob() to convert it to a binary string first.\n * @property {Object} httpHeaders - Basic authentication headers.\n * @property {boolean} withCredentials - Indicates whether or not cross-site\n * Access-Control requests should be made using credentials such as cookies\n * or authorization headers. The default is false.\n * @property {string} password - For decrypting password-protected PDFs.\n * @property {TypedArray} initialData - A typed array with the first portion or\n * all of the pdf data. Used by the extension since some data is already\n * loaded before the switch to range requests.\n * @property {number} length - The PDF file length. It's used for progress\n * reports and range requests operations.\n * @property {PDFDataRangeTransport} range\n * @property {number} rangeChunkSize - Optional parameter to specify\n * maximum number of bytes fetched per range request. The default value is\n * 2^16 = 65536.\n * @property {PDFWorker} worker - The worker that will be used for the loading\n * and parsing of the PDF data.\n * @property {string} docBaseUrl - (optional) The base URL of the document,\n * used when attempting to recover valid absolute URLs for annotations, and\n * outline items, that (incorrectly) only specify relative URLs.\n * @property {boolean} disableNativeImageDecoder - (deprecated) Disable decoding\n * of certain (simple) JPEG images in the browser. This is useful for\n * environments without DOM image support, such as e.g. Node.js.\n * The default value is `false`.\n * @property {string} nativeImageDecoderSupport - (optional) Strategy for\n * decoding certain (simple) JPEG images in the browser. This is useful for\n * environments without DOM image and canvas support, such as e.g. Node.js.\n * Valid values are 'decode', 'display' or 'none'; where 'decode' is intended\n * for browsers with full image/canvas support, 'display' for environments\n * with limited image support through stubs (useful for SVG conversion),\n * and 'none' where JPEG images will be decoded entirely by PDF.js.\n * The default value is 'decode'.\n * @property {Object} CMapReaderFactory - (optional) The factory that will be\n * used when reading built-in CMap files. Providing a custom factory is useful\n * for environments without `XMLHttpRequest` support, such as e.g. Node.js.\n * The default value is {DOMCMapReaderFactory}.\n * @property {boolean} stopAtErrors - (optional) Reject certain promises, e.g.\n * `getOperatorList`, `getTextContent`, and `RenderTask`, when the associated\n * PDF data cannot be successfully parsed, instead of attempting to recover\n * whatever possible of the data. The default value is `false`.\n */\n\n/**\n * @typedef {Object} PDFDocumentStats\n * @property {Array} streamTypes - Used stream types in the document (an item\n * is set to true if specific stream ID was used in the document).\n * @property {Array} fontTypes - Used font type in the document (an item is set\n * to true if specific font ID was used in the document).\n */\n\n/**\n * This is the main entry point for loading a PDF and interacting with it.\n * NOTE: If a URL is used to fetch the PDF data a standard XMLHttpRequest(XHR)\n * is used, which means it must follow the same origin rules that any XHR does\n * e.g. No cross domain requests without CORS.\n *\n * @param {string|TypedArray|DocumentInitParameters|PDFDataRangeTransport} src\n * Can be a url to where a PDF is located, a typed array (Uint8Array)\n * already populated with data or parameter object.\n *\n * @param {PDFDataRangeTransport} pdfDataRangeTransport (deprecated) It is used\n * if you want to manually serve range requests for data in the PDF.\n *\n * @param {function} passwordCallback (deprecated) It is used to request a\n * password if wrong or no password was provided. The callback receives two\n * parameters: function that needs to be called with new password and reason\n * (see {PasswordResponses}).\n *\n * @param {function} progressCallback (deprecated) It is used to be able to\n * monitor the loading progress of the PDF file (necessary to implement e.g.\n * a loading bar). The callback receives an {Object} with the properties:\n * {number} loaded and {number} total.\n *\n * @return {PDFDocumentLoadingTask}\n */\nfunction getDocument(src, pdfDataRangeTransport,\n passwordCallback, progressCallback) {\n var task = new PDFDocumentLoadingTask();\n\n // Support of the obsolete arguments (for compatibility with API v1.0)\n if (arguments.length > 1) {\n deprecated('getDocument is called with pdfDataRangeTransport, ' +\n 'passwordCallback or progressCallback argument');\n }\n if (pdfDataRangeTransport) {\n if (!(pdfDataRangeTransport instanceof PDFDataRangeTransport)) {\n // Not a PDFDataRangeTransport instance, trying to add missing properties.\n pdfDataRangeTransport = Object.create(pdfDataRangeTransport);\n pdfDataRangeTransport.length = src.length;\n pdfDataRangeTransport.initialData = src.initialData;\n if (!pdfDataRangeTransport.abort) {\n pdfDataRangeTransport.abort = function () {};\n }\n }\n src = Object.create(src);\n src.range = pdfDataRangeTransport;\n }\n task.onPassword = passwordCallback || null;\n task.onProgress = progressCallback || null;\n\n var source;\n if (typeof src === 'string') {\n source = { url: src, };\n } else if (isArrayBuffer(src)) {\n source = { data: src, };\n } else if (src instanceof PDFDataRangeTransport) {\n source = { range: src, };\n } else {\n if (typeof src !== 'object') {\n throw new Error('Invalid parameter in getDocument, ' +\n 'need either Uint8Array, string or a parameter object');\n }\n if (!src.url && !src.data && !src.range) {\n throw new Error(\n 'Invalid parameter object: need either .data, .range or .url');\n }\n\n source = src;\n }\n\n var params = {};\n var rangeTransport = null;\n var worker = null;\n var CMapReaderFactory = DOMCMapReaderFactory;\n\n for (var key in source) {\n if (key === 'url' && typeof window !== 'undefined') {\n // The full path is required in the 'url' field.\n params[key] = new URL(source[key], window.location).href;\n continue;\n } else if (key === 'range') {\n rangeTransport = source[key];\n continue;\n } else if (key === 'worker') {\n worker = source[key];\n continue;\n } else if (key === 'data' && !(source[key] instanceof Uint8Array)) {\n // Converting string or array-like data to Uint8Array.\n var pdfBytes = source[key];\n if (typeof pdfBytes === 'string') {\n params[key] = stringToBytes(pdfBytes);\n } else if (typeof pdfBytes === 'object' && pdfBytes !== null &&\n !isNaN(pdfBytes.length)) {\n params[key] = new Uint8Array(pdfBytes);\n } else if (isArrayBuffer(pdfBytes)) {\n params[key] = new Uint8Array(pdfBytes);\n } else {\n throw new Error('Invalid PDF binary data: either typed array, ' +\n 'string or array-like object is expected in the ' +\n 'data property.');\n }\n continue;\n } else if (key === 'CMapReaderFactory') {\n CMapReaderFactory = source[key];\n continue;\n }\n params[key] = source[key];\n }\n\n params.rangeChunkSize = params.rangeChunkSize || DEFAULT_RANGE_CHUNK_SIZE;\n params.ignoreErrors = params.stopAtErrors !== true;\n\n if (params.disableNativeImageDecoder !== undefined) {\n deprecated('parameter disableNativeImageDecoder, ' +\n 'use nativeImageDecoderSupport instead');\n }\n params.nativeImageDecoderSupport = params.nativeImageDecoderSupport ||\n (params.disableNativeImageDecoder === true ? NativeImageDecoding.NONE :\n NativeImageDecoding.DECODE);\n if (params.nativeImageDecoderSupport !== NativeImageDecoding.DECODE &&\n params.nativeImageDecoderSupport !== NativeImageDecoding.NONE &&\n params.nativeImageDecoderSupport !== NativeImageDecoding.DISPLAY) {\n warn('Invalid parameter nativeImageDecoderSupport: ' +\n 'need a state of enum {NativeImageDecoding}');\n params.nativeImageDecoderSupport = NativeImageDecoding.DECODE;\n }\n\n if (!worker) {\n // Worker was not provided -- creating and owning our own. If message port\n // is specified in global settings, using it.\n var workerPort = getDefaultSetting('workerPort');\n worker = workerPort ? PDFWorker.fromPort(workerPort) : new PDFWorker();\n task._worker = worker;\n }\n var docId = task.docId;\n worker.promise.then(function () {\n if (task.destroyed) {\n throw new Error('Loading aborted');\n }\n return _fetchDocument(worker, params, rangeTransport, docId).then(\n function (workerId) {\n if (task.destroyed) {\n throw new Error('Loading aborted');\n }\n\n let networkStream;\n if (rangeTransport) {\n networkStream = new PDFDataTransportStream(params, rangeTransport);\n } else if (!params.data) {\n networkStream = new PDFNetworkStream({\n source: params,\n disableRange: getDefaultSetting('disableRange'),\n });\n }\n\n var messageHandler = new MessageHandler(docId, workerId, worker.port);\n messageHandler.postMessageTransfers = worker.postMessageTransfers;\n var transport = new WorkerTransport(messageHandler, task, networkStream,\n CMapReaderFactory);\n task._transport = transport;\n messageHandler.send('Ready', null);\n });\n }).catch(task._capability.reject);\n\n return task;\n}\n\n/**\n * Starts fetching of specified PDF document/data.\n * @param {PDFWorker} worker\n * @param {Object} source\n * @param {PDFDataRangeTransport} pdfDataRangeTransport\n * @param {string} docId Unique document id, used as MessageHandler id.\n * @returns {Promise} The promise, which is resolved when worker id of\n * MessageHandler is known.\n * @private\n */\nfunction _fetchDocument(worker, source, pdfDataRangeTransport, docId) {\n if (worker.destroyed) {\n return Promise.reject(new Error('Worker was destroyed'));\n }\n\n source.disableAutoFetch = getDefaultSetting('disableAutoFetch');\n source.disableStream = getDefaultSetting('disableStream');\n source.chunkedViewerLoading = !!pdfDataRangeTransport;\n if (pdfDataRangeTransport) {\n source.length = pdfDataRangeTransport.length;\n source.initialData = pdfDataRangeTransport.initialData;\n }\n return worker.messageHandler.sendWithPromise('GetDocRequest', {\n docId,\n source: {\n data: source.data,\n url: source.url,\n password: source.password,\n disableAutoFetch: source.disableAutoFetch,\n rangeChunkSize: source.rangeChunkSize,\n length: source.length,\n },\n maxImageSize: getDefaultSetting('maxImageSize'),\n disableFontFace: getDefaultSetting('disableFontFace'),\n disableCreateObjectURL: getDefaultSetting('disableCreateObjectURL'),\n postMessageTransfers: getDefaultSetting('postMessageTransfers') &&\n !isPostMessageTransfersDisabled,\n docBaseUrl: source.docBaseUrl,\n nativeImageDecoderSupport: source.nativeImageDecoderSupport,\n ignoreErrors: source.ignoreErrors,\n }).then(function (workerId) {\n if (worker.destroyed) {\n throw new Error('Worker was destroyed');\n }\n return workerId;\n });\n}\n\n/**\n * PDF document loading operation.\n * @class\n * @alias PDFDocumentLoadingTask\n */\nvar PDFDocumentLoadingTask = (function PDFDocumentLoadingTaskClosure() {\n var nextDocumentId = 0;\n\n /** @constructs PDFDocumentLoadingTask */\n function PDFDocumentLoadingTask() {\n this._capability = createPromiseCapability();\n this._transport = null;\n this._worker = null;\n\n /**\n * Unique document loading task id -- used in MessageHandlers.\n * @type {string}\n */\n this.docId = 'd' + (nextDocumentId++);\n\n /**\n * Shows if loading task is destroyed.\n * @type {boolean}\n */\n this.destroyed = false;\n\n /**\n * Callback to request a password if wrong or no password was provided.\n * The callback receives two parameters: function that needs to be called\n * with new password and reason (see {PasswordResponses}).\n */\n this.onPassword = null;\n\n /**\n * Callback to be able to monitor the loading progress of the PDF file\n * (necessary to implement e.g. a loading bar). The callback receives\n * an {Object} with the properties: {number} loaded and {number} total.\n */\n this.onProgress = null;\n\n /**\n * Callback to when unsupported feature is used. The callback receives\n * an {UNSUPPORTED_FEATURES} argument.\n */\n this.onUnsupportedFeature = null;\n }\n\n PDFDocumentLoadingTask.prototype =\n /** @lends PDFDocumentLoadingTask.prototype */ {\n /**\n * @return {Promise}\n */\n get promise() {\n return this._capability.promise;\n },\n\n /**\n * Aborts all network requests and destroys worker.\n * @return {Promise} A promise that is resolved after destruction activity\n * is completed.\n */\n destroy() {\n this.destroyed = true;\n\n var transportDestroyed = !this._transport ? Promise.resolve() :\n this._transport.destroy();\n return transportDestroyed.then(() => {\n this._transport = null;\n if (this._worker) {\n this._worker.destroy();\n this._worker = null;\n }\n });\n },\n\n /**\n * Registers callbacks to indicate the document loading completion.\n *\n * @param {function} onFulfilled The callback for the loading completion.\n * @param {function} onRejected The callback for the loading failure.\n * @return {Promise} A promise that is resolved after the onFulfilled or\n * onRejected callback.\n */\n then: function PDFDocumentLoadingTask_then(onFulfilled, onRejected) {\n return this.promise.then.apply(this.promise, arguments);\n },\n };\n\n return PDFDocumentLoadingTask;\n})();\n\n/**\n * Abstract class to support range requests file loading.\n * @class\n * @alias PDFDataRangeTransport\n * @param {number} length\n * @param {Uint8Array} initialData\n */\nvar PDFDataRangeTransport = (function pdfDataRangeTransportClosure() {\n function PDFDataRangeTransport(length, initialData) {\n this.length = length;\n this.initialData = initialData;\n\n this._rangeListeners = [];\n this._progressListeners = [];\n this._progressiveReadListeners = [];\n this._readyCapability = createPromiseCapability();\n }\n PDFDataRangeTransport.prototype =\n /** @lends PDFDataRangeTransport.prototype */ {\n addRangeListener:\n function PDFDataRangeTransport_addRangeListener(listener) {\n this._rangeListeners.push(listener);\n },\n\n addProgressListener:\n function PDFDataRangeTransport_addProgressListener(listener) {\n this._progressListeners.push(listener);\n },\n\n addProgressiveReadListener:\n function PDFDataRangeTransport_addProgressiveReadListener(listener) {\n this._progressiveReadListeners.push(listener);\n },\n\n onDataRange: function PDFDataRangeTransport_onDataRange(begin, chunk) {\n var listeners = this._rangeListeners;\n for (var i = 0, n = listeners.length; i < n; ++i) {\n listeners[i](begin, chunk);\n }\n },\n\n onDataProgress: function PDFDataRangeTransport_onDataProgress(loaded) {\n this._readyCapability.promise.then(() => {\n var listeners = this._progressListeners;\n for (var i = 0, n = listeners.length; i < n; ++i) {\n listeners[i](loaded);\n }\n });\n },\n\n onDataProgressiveRead:\n function PDFDataRangeTransport_onDataProgress(chunk) {\n this._readyCapability.promise.then(() => {\n var listeners = this._progressiveReadListeners;\n for (var i = 0, n = listeners.length; i < n; ++i) {\n listeners[i](chunk);\n }\n });\n },\n\n transportReady: function PDFDataRangeTransport_transportReady() {\n this._readyCapability.resolve();\n },\n\n requestDataRange:\n function PDFDataRangeTransport_requestDataRange(begin, end) {\n throw new Error('Abstract method PDFDataRangeTransport.requestDataRange');\n },\n\n abort: function PDFDataRangeTransport_abort() {\n },\n };\n return PDFDataRangeTransport;\n})();\n\n/**\n * Proxy to a PDFDocument in the worker thread. Also, contains commonly used\n * properties that can be read synchronously.\n * @class\n * @alias PDFDocumentProxy\n */\nvar PDFDocumentProxy = (function PDFDocumentProxyClosure() {\n function PDFDocumentProxy(pdfInfo, transport, loadingTask) {\n this.pdfInfo = pdfInfo;\n this.transport = transport;\n this.loadingTask = loadingTask;\n }\n PDFDocumentProxy.prototype = /** @lends PDFDocumentProxy.prototype */ {\n /**\n * @return {number} Total number of pages the PDF contains.\n */\n get numPages() {\n return this.pdfInfo.numPages;\n },\n /**\n * @return {string} A unique ID to identify a PDF. Not guaranteed to be\n * unique.\n */\n get fingerprint() {\n return this.pdfInfo.fingerprint;\n },\n /**\n * @param {number} pageNumber The page number to get. The first page is 1.\n * @return {Promise} A promise that is resolved with a {@link PDFPageProxy}\n * object.\n */\n getPage: function PDFDocumentProxy_getPage(pageNumber) {\n return this.transport.getPage(pageNumber);\n },\n /**\n * @param {{num: number, gen: number}} ref The page reference. Must have\n * the 'num' and 'gen' properties.\n * @return {Promise} A promise that is resolved with the page index that is\n * associated with the reference.\n */\n getPageIndex: function PDFDocumentProxy_getPageIndex(ref) {\n return this.transport.getPageIndex(ref);\n },\n /**\n * @return {Promise} A promise that is resolved with a lookup table for\n * mapping named destinations to reference numbers.\n *\n * This can be slow for large documents: use getDestination instead\n */\n getDestinations: function PDFDocumentProxy_getDestinations() {\n return this.transport.getDestinations();\n },\n /**\n * @param {string} id The named destination to get.\n * @return {Promise} A promise that is resolved with all information\n * of the given named destination.\n */\n getDestination: function PDFDocumentProxy_getDestination(id) {\n return this.transport.getDestination(id);\n },\n /**\n * @return {Promise} A promise that is resolved with:\n * an Array containing the pageLabels that correspond to the pageIndexes,\n * or `null` when no pageLabels are present in the PDF file.\n */\n getPageLabels: function PDFDocumentProxy_getPageLabels() {\n return this.transport.getPageLabels();\n },\n /**\n * @return {Promise} A promise that is resolved with a {string} containing\n * the PageMode name.\n */\n getPageMode() {\n return this.transport.getPageMode();\n },\n /**\n * @return {Promise} A promise that is resolved with a lookup table for\n * mapping named attachments to their content.\n */\n getAttachments: function PDFDocumentProxy_getAttachments() {\n return this.transport.getAttachments();\n },\n /**\n * @return {Promise} A promise that is resolved with an array of all the\n * JavaScript strings in the name tree.\n */\n getJavaScript: function PDFDocumentProxy_getJavaScript() {\n return this.transport.getJavaScript();\n },\n /**\n * @return {Promise} A promise that is resolved with an {Array} that is a\n * tree outline (if it has one) of the PDF. The tree is in the format of:\n * [\n * {\n * title: string,\n * bold: boolean,\n * italic: boolean,\n * color: rgb Uint8Array,\n * dest: dest obj,\n * url: string,\n * items: array of more items like this\n * },\n * ...\n * ].\n */\n getOutline: function PDFDocumentProxy_getOutline() {\n return this.transport.getOutline();\n },\n /**\n * @return {Promise} A promise that is resolved with an {Object} that has\n * info and metadata properties. Info is an {Object} filled with anything\n * available in the information dictionary and similarly metadata is a\n * {Metadata} object with information from the metadata section of the PDF.\n */\n getMetadata: function PDFDocumentProxy_getMetadata() {\n return this.transport.getMetadata();\n },\n /**\n * @return {Promise} A promise that is resolved with a TypedArray that has\n * the raw data from the PDF.\n */\n getData: function PDFDocumentProxy_getData() {\n return this.transport.getData();\n },\n /**\n * @return {Promise} A promise that is resolved when the document's data\n * is loaded. It is resolved with an {Object} that contains the length\n * property that indicates size of the PDF data in bytes.\n */\n getDownloadInfo: function PDFDocumentProxy_getDownloadInfo() {\n return this.transport.downloadInfoCapability.promise;\n },\n /**\n * @return {Promise} A promise this is resolved with current stats about\n * document structures (see {@link PDFDocumentStats}).\n */\n getStats: function PDFDocumentProxy_getStats() {\n return this.transport.getStats();\n },\n /**\n * Cleans up resources allocated by the document, e.g. created @font-face.\n */\n cleanup: function PDFDocumentProxy_cleanup() {\n this.transport.startCleanup();\n },\n /**\n * Destroys current document instance and terminates worker.\n */\n destroy: function PDFDocumentProxy_destroy() {\n return this.loadingTask.destroy();\n },\n };\n return PDFDocumentProxy;\n})();\n\n/**\n * Page getTextContent parameters.\n *\n * @typedef {Object} getTextContentParameters\n * @property {boolean} normalizeWhitespace - replaces all occurrences of\n * whitespace with standard spaces (0x20). The default value is `false`.\n * @property {boolean} disableCombineTextItems - do not attempt to combine\n * same line {@link TextItem}'s. The default value is `false`.\n */\n\n/**\n * Page text content.\n *\n * @typedef {Object} TextContent\n * @property {array} items - array of {@link TextItem}\n * @property {Object} styles - {@link TextStyles} objects, indexed by font name.\n */\n\n/**\n * Page text content part.\n *\n * @typedef {Object} TextItem\n * @property {string} str - text content.\n * @property {string} dir - text direction: 'ttb', 'ltr' or 'rtl'.\n * @property {array} transform - transformation matrix.\n * @property {number} width - width in device space.\n * @property {number} height - height in device space.\n * @property {string} fontName - font name used by pdf.js for converted font.\n */\n\n/**\n * Text style.\n *\n * @typedef {Object} TextStyle\n * @property {number} ascent - font ascent.\n * @property {number} descent - font descent.\n * @property {boolean} vertical - text is in vertical mode.\n * @property {string} fontFamily - possible font family\n */\n\n/**\n * Page annotation parameters.\n *\n * @typedef {Object} GetAnnotationsParameters\n * @property {string} intent - Determines the annotations that will be fetched,\n * can be either 'display' (viewable annotations) or 'print'\n * (printable annotations).\n * If the parameter is omitted, all annotations are fetched.\n */\n\n/**\n * Page render parameters.\n *\n * @typedef {Object} RenderParameters\n * @property {Object} canvasContext - A 2D context of a DOM Canvas object.\n * @property {PageViewport} viewport - Rendering viewport obtained by\n * calling of PDFPage.getViewport method.\n * @property {string} intent - Rendering intent, can be 'display' or 'print'\n * (default value is 'display').\n * @property {boolean} renderInteractiveForms - (optional) Whether or not\n * interactive form elements are rendered in the display\n * layer. If so, we do not render them on canvas as well.\n * @property {Array} transform - (optional) Additional transform, applied\n * just before viewport transform.\n * @property {Object} imageLayer - (optional) An object that has beginLayout,\n * endLayout and appendImage functions.\n * @property {function} continueCallback - (deprecated) A function that will be\n * called each time the rendering is paused. To continue\n * rendering call the function that is the first argument\n * to the callback.\n * @property {Object} canvasFactory - (optional) The factory that will be used\n * when creating canvases. The default value is\n * {DOMCanvasFactory}.\n * @property {Object} background - (optional) Background to use for the canvas.\n * Can use any valid canvas.fillStyle: A DOMString parsed as\n * CSS value, a CanvasGradient object (a linear or\n * radial gradient) or a CanvasPattern object (a repetitive\n * image). The default value is 'rgb(255,255,255)'.\n */\n\n/**\n * PDF page operator list.\n *\n * @typedef {Object} PDFOperatorList\n * @property {Array} fnArray - Array containing the operator functions.\n * @property {Array} argsArray - Array containing the arguments of the\n * functions.\n */\n\n/**\n * Proxy to a PDFPage in the worker thread.\n * @class\n * @alias PDFPageProxy\n */\nvar PDFPageProxy = (function PDFPageProxyClosure() {\n function PDFPageProxy(pageIndex, pageInfo, transport) {\n this.pageIndex = pageIndex;\n this.pageInfo = pageInfo;\n this.transport = transport;\n this.stats = new StatTimer();\n this.stats.enabled = getDefaultSetting('enableStats');\n this.commonObjs = transport.commonObjs;\n this.objs = new PDFObjects();\n this.cleanupAfterRender = false;\n this.pendingCleanup = false;\n this.intentStates = Object.create(null);\n this.destroyed = false;\n }\n PDFPageProxy.prototype = /** @lends PDFPageProxy.prototype */ {\n /**\n * @return {number} Page number of the page. First page is 1.\n */\n get pageNumber() {\n return this.pageIndex + 1;\n },\n /**\n * @return {number} The number of degrees the page is rotated clockwise.\n */\n get rotate() {\n return this.pageInfo.rotate;\n },\n /**\n * @return {Object} The reference that points to this page. It has 'num' and\n * 'gen' properties.\n */\n get ref() {\n return this.pageInfo.ref;\n },\n /**\n * @return {number} The default size of units in 1/72nds of an inch.\n */\n get userUnit() {\n return this.pageInfo.userUnit;\n },\n /**\n * @return {Array} An array of the visible portion of the PDF page in the\n * user space units - [x1, y1, x2, y2].\n */\n get view() {\n return this.pageInfo.view;\n },\n /**\n * @param {number} scale The desired scale of the viewport.\n * @param {number} rotate Degrees to rotate the viewport. If omitted this\n * defaults to the page rotation.\n * @return {PageViewport} Contains 'width' and 'height' properties\n * along with transforms required for rendering.\n */\n getViewport: function PDFPageProxy_getViewport(scale, rotate) {\n if (arguments.length < 2) {\n rotate = this.rotate;\n }\n return new PageViewport(this.view, scale, rotate, 0, 0);\n },\n /**\n * @param {GetAnnotationsParameters} params - Annotation parameters.\n * @return {Promise} A promise that is resolved with an {Array} of the\n * annotation objects.\n */\n getAnnotations: function PDFPageProxy_getAnnotations(params) {\n var intent = (params && params.intent) || null;\n\n if (!this.annotationsPromise || this.annotationsIntent !== intent) {\n this.annotationsPromise = this.transport.getAnnotations(this.pageIndex,\n intent);\n this.annotationsIntent = intent;\n }\n return this.annotationsPromise;\n },\n /**\n * Begins the process of rendering a page to the desired context.\n * @param {RenderParameters} params Page render parameters.\n * @return {RenderTask} An object that contains the promise, which\n * is resolved when the page finishes rendering.\n */\n render: function PDFPageProxy_render(params) {\n var stats = this.stats;\n stats.time('Overall');\n\n // If there was a pending destroy cancel it so no cleanup happens during\n // this call to render.\n this.pendingCleanup = false;\n\n var renderingIntent = (params.intent === 'print' ? 'print' : 'display');\n var canvasFactory = params.canvasFactory || new DOMCanvasFactory();\n\n if (!this.intentStates[renderingIntent]) {\n this.intentStates[renderingIntent] = Object.create(null);\n }\n var intentState = this.intentStates[renderingIntent];\n\n // If there's no displayReadyCapability yet, then the operatorList\n // was never requested before. Make the request and create the promise.\n if (!intentState.displayReadyCapability) {\n intentState.receivingOperatorList = true;\n intentState.displayReadyCapability = createPromiseCapability();\n intentState.operatorList = {\n fnArray: [],\n argsArray: [],\n lastChunk: false,\n };\n\n this.stats.time('Page Request');\n this.transport.messageHandler.send('RenderPageRequest', {\n pageIndex: this.pageNumber - 1,\n intent: renderingIntent,\n renderInteractiveForms: (params.renderInteractiveForms === true),\n });\n }\n\n var complete = (error) => {\n var i = intentState.renderTasks.indexOf(internalRenderTask);\n if (i >= 0) {\n intentState.renderTasks.splice(i, 1);\n }\n\n if (this.cleanupAfterRender) {\n this.pendingCleanup = true;\n }\n this._tryCleanup();\n\n if (error) {\n internalRenderTask.capability.reject(error);\n } else {\n internalRenderTask.capability.resolve();\n }\n stats.timeEnd('Rendering');\n stats.timeEnd('Overall');\n };\n\n var internalRenderTask = new InternalRenderTask(complete, params,\n this.objs,\n this.commonObjs,\n intentState.operatorList,\n this.pageNumber,\n canvasFactory);\n internalRenderTask.useRequestAnimationFrame = renderingIntent !== 'print';\n if (!intentState.renderTasks) {\n intentState.renderTasks = [];\n }\n intentState.renderTasks.push(internalRenderTask);\n var renderTask = internalRenderTask.task;\n\n // Obsolete parameter support\n if (params.continueCallback) {\n deprecated('render is used with continueCallback parameter');\n renderTask.onContinue = params.continueCallback;\n }\n\n intentState.displayReadyCapability.promise.then((transparency) => {\n if (this.pendingCleanup) {\n complete();\n return;\n }\n stats.time('Rendering');\n internalRenderTask.initializeGraphics(transparency);\n internalRenderTask.operatorListChanged();\n }).catch(complete);\n\n return renderTask;\n },\n\n /**\n * @return {Promise} A promise resolved with an {@link PDFOperatorList}\n * object that represents page's operator list.\n */\n getOperatorList: function PDFPageProxy_getOperatorList() {\n function operatorListChanged() {\n if (intentState.operatorList.lastChunk) {\n intentState.opListReadCapability.resolve(intentState.operatorList);\n\n var i = intentState.renderTasks.indexOf(opListTask);\n if (i >= 0) {\n intentState.renderTasks.splice(i, 1);\n }\n }\n }\n\n var renderingIntent = 'oplist';\n if (!this.intentStates[renderingIntent]) {\n this.intentStates[renderingIntent] = Object.create(null);\n }\n var intentState = this.intentStates[renderingIntent];\n var opListTask;\n\n if (!intentState.opListReadCapability) {\n opListTask = {};\n opListTask.operatorListChanged = operatorListChanged;\n intentState.receivingOperatorList = true;\n intentState.opListReadCapability = createPromiseCapability();\n intentState.renderTasks = [];\n intentState.renderTasks.push(opListTask);\n intentState.operatorList = {\n fnArray: [],\n argsArray: [],\n lastChunk: false,\n };\n\n this.transport.messageHandler.send('RenderPageRequest', {\n pageIndex: this.pageIndex,\n intent: renderingIntent,\n });\n }\n return intentState.opListReadCapability.promise;\n },\n\n /**\n * @param {getTextContentParameters} params - getTextContent parameters.\n * @return {ReadableStream} ReadableStream to read textContent chunks.\n */\n streamTextContent(params = {}) {\n const TEXT_CONTENT_CHUNK_SIZE = 100;\n return this.transport.messageHandler.sendWithStream('GetTextContent', {\n pageIndex: this.pageNumber - 1,\n normalizeWhitespace: (params.normalizeWhitespace === true),\n combineTextItems: (params.disableCombineTextItems !== true),\n }, {\n highWaterMark: TEXT_CONTENT_CHUNK_SIZE,\n size(textContent) {\n return textContent.items.length;\n },\n });\n },\n\n /**\n * @param {getTextContentParameters} params - getTextContent parameters.\n * @return {Promise} That is resolved a {@link TextContent}\n * object that represent the page text content.\n */\n getTextContent: function PDFPageProxy_getTextContent(params) {\n params = params || {};\n let readableStream = this.streamTextContent(params);\n\n return new Promise(function(resolve, reject) {\n function pump() {\n reader.read().then(function({ value, done, }) {\n if (done) {\n resolve(textContent);\n return;\n }\n Util.extendObj(textContent.styles, value.styles);\n Util.appendToArray(textContent.items, value.items);\n pump();\n }, reject);\n }\n\n let reader = readableStream.getReader();\n let textContent = {\n items: [],\n styles: Object.create(null),\n };\n\n pump();\n });\n },\n\n /**\n * Destroys page object.\n */\n _destroy: function PDFPageProxy_destroy() {\n this.destroyed = true;\n this.transport.pageCache[this.pageIndex] = null;\n\n var waitOn = [];\n Object.keys(this.intentStates).forEach(function(intent) {\n if (intent === 'oplist') {\n // Avoid errors below, since the renderTasks are just stubs.\n return;\n }\n var intentState = this.intentStates[intent];\n intentState.renderTasks.forEach(function(renderTask) {\n var renderCompleted = renderTask.capability.promise.\n catch(function () {}); // ignoring failures\n waitOn.push(renderCompleted);\n renderTask.cancel();\n });\n }, this);\n this.objs.clear();\n this.annotationsPromise = null;\n this.pendingCleanup = false;\n return Promise.all(waitOn);\n },\n\n /**\n * Cleans up resources allocated by the page. (deprecated)\n */\n destroy() {\n deprecated('page destroy method, use cleanup() instead');\n this.cleanup();\n },\n\n /**\n * Cleans up resources allocated by the page.\n */\n cleanup: function PDFPageProxy_cleanup() {\n this.pendingCleanup = true;\n this._tryCleanup();\n },\n /**\n * For internal use only. Attempts to clean up if rendering is in a state\n * where that's possible.\n * @ignore\n */\n _tryCleanup: function PDFPageProxy_tryCleanup() {\n if (!this.pendingCleanup ||\n Object.keys(this.intentStates).some(function(intent) {\n var intentState = this.intentStates[intent];\n return (intentState.renderTasks.length !== 0 ||\n intentState.receivingOperatorList);\n }, this)) {\n return;\n }\n\n Object.keys(this.intentStates).forEach(function(intent) {\n delete this.intentStates[intent];\n }, this);\n this.objs.clear();\n this.annotationsPromise = null;\n this.pendingCleanup = false;\n },\n /**\n * For internal use only.\n * @ignore\n */\n _startRenderPage: function PDFPageProxy_startRenderPage(transparency,\n intent) {\n var intentState = this.intentStates[intent];\n // TODO Refactor RenderPageRequest to separate rendering\n // and operator list logic\n if (intentState.displayReadyCapability) {\n intentState.displayReadyCapability.resolve(transparency);\n }\n },\n /**\n * For internal use only.\n * @ignore\n */\n _renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk,\n intent) {\n var intentState = this.intentStates[intent];\n var i, ii;\n // Add the new chunk to the current operator list.\n for (i = 0, ii = operatorListChunk.length; i < ii; i++) {\n intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);\n intentState.operatorList.argsArray.push(\n operatorListChunk.argsArray[i]);\n }\n intentState.operatorList.lastChunk = operatorListChunk.lastChunk;\n\n // Notify all the rendering tasks there are more operators to be consumed.\n for (i = 0; i < intentState.renderTasks.length; i++) {\n intentState.renderTasks[i].operatorListChanged();\n }\n\n if (operatorListChunk.lastChunk) {\n intentState.receivingOperatorList = false;\n this._tryCleanup();\n }\n },\n };\n return PDFPageProxy;\n})();\n\nclass LoopbackPort {\n constructor(defer) {\n this._listeners = [];\n this._defer = defer;\n this._deferred = Promise.resolve(undefined);\n }\n\n postMessage(obj, transfers) {\n function cloneValue(value) {\n // Trying to perform a structured clone close to the spec, including\n // transfers.\n if (typeof value !== 'object' || value === null) {\n return value;\n }\n if (cloned.has(value)) { // already cloned the object\n return cloned.get(value);\n }\n var result;\n var buffer;\n if ((buffer = value.buffer) && isArrayBuffer(buffer)) {\n // We found object with ArrayBuffer (typed array).\n var transferable = transfers && transfers.indexOf(buffer) >= 0;\n if (value === buffer) {\n // Special case when we are faking typed arrays in compatibility.js.\n result = value;\n } else if (transferable) {\n result = new value.constructor(buffer, value.byteOffset,\n value.byteLength);\n } else {\n result = new value.constructor(value);\n }\n cloned.set(value, result);\n return result;\n }\n result = isArray(value) ? [] : {};\n cloned.set(value, result); // adding to cache now for cyclic references\n // Cloning all value and object properties, however ignoring properties\n // defined via getter.\n for (var i in value) {\n var desc, p = value;\n while (!(desc = Object.getOwnPropertyDescriptor(p, i))) {\n p = Object.getPrototypeOf(p);\n }\n if (typeof desc.value === 'undefined' ||\n typeof desc.value === 'function') {\n continue;\n }\n result[i] = cloneValue(desc.value);\n }\n return result;\n }\n\n if (!this._defer) {\n this._listeners.forEach(function (listener) {\n listener.call(this, { data: obj, });\n }, this);\n return;\n }\n\n var cloned = new WeakMap();\n var e = { data: cloneValue(obj), };\n this._deferred.then(() => {\n this._listeners.forEach(function (listener) {\n listener.call(this, e);\n }, this);\n });\n }\n\n addEventListener(name, listener) {\n this._listeners.push(listener);\n }\n\n removeEventListener(name, listener) {\n var i = this._listeners.indexOf(listener);\n this._listeners.splice(i, 1);\n }\n\n terminate() {\n this._listeners = [];\n }\n}\n\n/**\n * PDF.js web worker abstraction, it controls instantiation of PDF documents and\n * WorkerTransport for them. If creation of a web worker is not possible,\n * a \"fake\" worker will be used instead.\n * @class\n */\nvar PDFWorker = (function PDFWorkerClosure() {\n let nextFakeWorkerId = 0;\n\n function getWorkerSrc() {\n if (typeof workerSrc !== 'undefined') {\n return workerSrc;\n }\n if (getDefaultSetting('workerSrc')) {\n return getDefaultSetting('workerSrc');\n }\n if (typeof PDFJSDev !== 'undefined' &&\n PDFJSDev.test('PRODUCTION && !(MOZCENTRAL || FIREFOX)') &&\n pdfjsFilePath) {\n return pdfjsFilePath.replace(/(\\.(?:min\\.)?js)(\\?.*)?$/i, '.worker$1$2');\n }\n throw new Error('No PDFJS.workerSrc specified');\n }\n\n let fakeWorkerFilesLoadedCapability;\n\n // Loads worker code into main thread.\n function setupFakeWorkerGlobal() {\n var WorkerMessageHandler;\n if (fakeWorkerFilesLoadedCapability) {\n return fakeWorkerFilesLoadedCapability.promise;\n }\n fakeWorkerFilesLoadedCapability = createPromiseCapability();\n // In the developer build load worker_loader which in turn loads all the\n // other files and resolves the promise. In production only the\n // pdf.worker.js file is needed.\n if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('PRODUCTION')) {\n if (typeof SystemJS === 'object') {\n SystemJS.import('pdfjs/core/worker').then((worker) => {\n WorkerMessageHandler = worker.WorkerMessageHandler;\n fakeWorkerFilesLoadedCapability.resolve(WorkerMessageHandler);\n });\n } else if (typeof require === 'function') {\n var worker = require('../core/worker.js');\n WorkerMessageHandler = worker.WorkerMessageHandler;\n fakeWorkerFilesLoadedCapability.resolve(WorkerMessageHandler);\n } else {\n throw new Error(\n 'SystemJS or CommonJS must be used to load fake worker.');\n }\n } else if (PDFJSDev.test('SINGLE_FILE')) {\n var pdfjsCoreWorker = require('../core/worker.js');\n WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;\n fakeWorkerFilesLoadedCapability.resolve(WorkerMessageHandler);\n } else {\n var loader = fakeWorkerFilesLoader || function (callback) {\n Util.loadScript(getWorkerSrc(), function () {\n callback(window.pdfjsDistBuildPdfWorker.WorkerMessageHandler);\n });\n };\n loader(fakeWorkerFilesLoadedCapability.resolve);\n }\n return fakeWorkerFilesLoadedCapability.promise;\n }\n\n function createCDNWrapper(url) {\n // We will rely on blob URL's property to specify origin.\n // We want this function to fail in case if createObjectURL or Blob do not\n // exist or fail for some reason -- our Worker creation will fail anyway.\n var wrapper = 'importScripts(\\'' + url + '\\');';\n return URL.createObjectURL(new Blob([wrapper]));\n }\n\n let pdfWorkerPorts = new WeakMap();\n\n function PDFWorker(name, port) {\n if (port && pdfWorkerPorts.has(port)) {\n throw new Error('Cannot use more than one PDFWorker per port');\n }\n\n this.name = name;\n this.destroyed = false;\n this.postMessageTransfers = true;\n\n this._readyCapability = createPromiseCapability();\n this._port = null;\n this._webWorker = null;\n this._messageHandler = null;\n\n if (port) {\n pdfWorkerPorts.set(port, this);\n this._initializeFromPort(port);\n return;\n }\n\n this._initialize();\n }\n\n PDFWorker.prototype = /** @lends PDFWorker.prototype */ {\n get promise() {\n return this._readyCapability.promise;\n },\n\n get port() {\n return this._port;\n },\n\n get messageHandler() {\n return this._messageHandler;\n },\n\n _initializeFromPort: function PDFWorker_initializeFromPort(port) {\n this._port = port;\n this._messageHandler = new MessageHandler('main', 'worker', port);\n this._messageHandler.on('ready', function () {\n // Ignoring 'ready' event -- MessageHandler shall be already initialized\n // and ready to accept the messages.\n });\n this._readyCapability.resolve();\n },\n\n _initialize: function PDFWorker_initialize() {\n // If worker support isn't disabled explicit and the browser has worker\n // support, create a new web worker and test if it/the browser fulfills\n // all requirements to run parts of pdf.js in a web worker.\n // Right now, the requirement is, that an Uint8Array is still an\n // Uint8Array as it arrives on the worker. (Chrome added this with v.15.)\n if ((typeof PDFJSDev === 'undefined' || !PDFJSDev.test('SINGLE_FILE')) &&\n !isWorkerDisabled && !getDefaultSetting('disableWorker') &&\n typeof Worker !== 'undefined') {\n var workerSrc = getWorkerSrc();\n\n try {\n // Wraps workerSrc path into blob URL, if the former does not belong\n // to the same origin.\n if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('GENERIC') &&\n !isSameOrigin(window.location.href, workerSrc)) {\n workerSrc = createCDNWrapper(\n new URL(workerSrc, window.location).href);\n }\n\n // Some versions of FF can't create a worker on localhost, see:\n // https://bugzilla.mozilla.org/show_bug.cgi?id=683280\n var worker = new Worker(workerSrc);\n var messageHandler = new MessageHandler('main', 'worker', worker);\n var terminateEarly = () => {\n worker.removeEventListener('error', onWorkerError);\n messageHandler.destroy();\n worker.terminate();\n if (this.destroyed) {\n this._readyCapability.reject(new Error('Worker was destroyed'));\n } else {\n // Fall back to fake worker if the termination is caused by an\n // error (e.g. NetworkError / SecurityError).\n this._setupFakeWorker();\n }\n };\n\n var onWorkerError = () => {\n if (!this._webWorker) {\n // Worker failed to initialize due to an error. Clean up and fall\n // back to the fake worker.\n terminateEarly();\n }\n };\n worker.addEventListener('error', onWorkerError);\n\n messageHandler.on('test', (data) => {\n worker.removeEventListener('error', onWorkerError);\n if (this.destroyed) {\n terminateEarly();\n return; // worker was destroyed\n }\n var supportTypedArray = data && data.supportTypedArray;\n if (supportTypedArray) {\n this._messageHandler = messageHandler;\n this._port = worker;\n this._webWorker = worker;\n if (!data.supportTransfers) {\n this.postMessageTransfers = false;\n isPostMessageTransfersDisabled = true;\n }\n this._readyCapability.resolve();\n // Send global setting, e.g. verbosity level.\n messageHandler.send('configure', {\n verbosity: getVerbosityLevel(),\n });\n } else {\n this._setupFakeWorker();\n messageHandler.destroy();\n worker.terminate();\n }\n });\n\n messageHandler.on('console_log', function (data) {\n console.log.apply(console, data);\n });\n messageHandler.on('console_error', function (data) {\n console.error.apply(console, data);\n });\n\n messageHandler.on('ready', (data) => {\n worker.removeEventListener('error', onWorkerError);\n if (this.destroyed) {\n terminateEarly();\n return; // worker was destroyed\n }\n try {\n sendTest();\n } catch (e) {\n // We need fallback to a faked worker.\n this._setupFakeWorker();\n }\n });\n\n var sendTest = function () {\n var postMessageTransfers =\n getDefaultSetting('postMessageTransfers') &&\n !isPostMessageTransfersDisabled;\n var testObj = new Uint8Array([postMessageTransfers ? 255 : 0]);\n // Some versions of Opera throw a DATA_CLONE_ERR on serializing the\n // typed array. Also, checking if we can use transfers.\n try {\n messageHandler.send('test', testObj, [testObj.buffer]);\n } catch (ex) {\n info('Cannot use postMessage transfers');\n testObj[0] = 0;\n messageHandler.send('test', testObj);\n }\n };\n\n // It might take time for worker to initialize (especially when AMD\n // loader is used). We will try to send test immediately, and then\n // when 'ready' message will arrive. The worker shall process only\n // first received 'test'.\n sendTest();\n return;\n } catch (e) {\n info('The worker has been disabled.');\n }\n }\n // Either workers are disabled, not supported or have thrown an exception.\n // Thus, we fallback to a faked worker.\n this._setupFakeWorker();\n },\n\n _setupFakeWorker: function PDFWorker_setupFakeWorker() {\n if (!isWorkerDisabled && !getDefaultSetting('disableWorker')) {\n warn('Setting up fake worker.');\n isWorkerDisabled = true;\n }\n\n setupFakeWorkerGlobal().then((WorkerMessageHandler) => {\n if (this.destroyed) {\n this._readyCapability.reject(new Error('Worker was destroyed'));\n return;\n }\n\n // We cannot turn on proper fake port simulation (this includes\n // structured cloning) when typed arrays are not supported. Relying\n // on a chance that messages will be sent in proper order.\n var isTypedArraysPresent = Uint8Array !== Float32Array;\n var port = new LoopbackPort(isTypedArraysPresent);\n this._port = port;\n\n // All fake workers use the same port, making id unique.\n var id = 'fake' + (nextFakeWorkerId++);\n\n // If the main thread is our worker, setup the handling for the\n // messages -- the main thread sends to it self.\n var workerHandler = new MessageHandler(id + '_worker', id, port);\n WorkerMessageHandler.setup(workerHandler, port);\n\n var messageHandler = new MessageHandler(id, id + '_worker', port);\n this._messageHandler = messageHandler;\n this._readyCapability.resolve();\n });\n },\n\n /**\n * Destroys the worker instance.\n */\n destroy: function PDFWorker_destroy() {\n this.destroyed = true;\n if (this._webWorker) {\n // We need to terminate only web worker created resource.\n this._webWorker.terminate();\n this._webWorker = null;\n }\n pdfWorkerPorts.delete(this._port);\n this._port = null;\n if (this._messageHandler) {\n this._messageHandler.destroy();\n this._messageHandler = null;\n }\n },\n };\n\n PDFWorker.fromPort = function (port) {\n if (pdfWorkerPorts.has(port)) {\n return pdfWorkerPorts.get(port);\n }\n return new PDFWorker(null, port);\n };\n\n return PDFWorker;\n})();\n\n/**\n * For internal use only.\n * @ignore\n */\nvar WorkerTransport = (function WorkerTransportClosure() {\n function WorkerTransport(messageHandler, loadingTask, networkStream,\n CMapReaderFactory) {\n this.messageHandler = messageHandler;\n this.loadingTask = loadingTask;\n this.commonObjs = new PDFObjects();\n this.fontLoader = new FontLoader(loadingTask.docId);\n this.CMapReaderFactory = new CMapReaderFactory({\n baseUrl: getDefaultSetting('cMapUrl'),\n isCompressed: getDefaultSetting('cMapPacked'),\n });\n\n this.destroyed = false;\n this.destroyCapability = null;\n this._passwordCapability = null;\n\n this._networkStream = networkStream;\n this._fullReader = null;\n this._lastProgress = null;\n\n this.pageCache = [];\n this.pagePromises = [];\n this.downloadInfoCapability = createPromiseCapability();\n\n this.setupMessageHandler();\n }\n WorkerTransport.prototype = {\n destroy: function WorkerTransport_destroy() {\n if (this.destroyCapability) {\n return this.destroyCapability.promise;\n }\n\n this.destroyed = true;\n this.destroyCapability = createPromiseCapability();\n\n if (this._passwordCapability) {\n this._passwordCapability.reject(\n new Error('Worker was destroyed during onPassword callback'));\n }\n\n var waitOn = [];\n // We need to wait for all renderings to be completed, e.g.\n // timeout/rAF can take a long time.\n this.pageCache.forEach(function (page) {\n if (page) {\n waitOn.push(page._destroy());\n }\n });\n this.pageCache = [];\n this.pagePromises = [];\n // We also need to wait for the worker to finish its long running tasks.\n var terminated = this.messageHandler.sendWithPromise('Terminate', null);\n waitOn.push(terminated);\n Promise.all(waitOn).then(() => {\n this.fontLoader.clear();\n if (this._networkStream) {\n this._networkStream.cancelAllRequests();\n }\n\n if (this.messageHandler) {\n this.messageHandler.destroy();\n this.messageHandler = null;\n }\n this.destroyCapability.resolve();\n }, this.destroyCapability.reject);\n return this.destroyCapability.promise;\n },\n\n setupMessageHandler: function WorkerTransport_setupMessageHandler() {\n var messageHandler = this.messageHandler;\n var loadingTask = this.loadingTask;\n\n messageHandler.on('GetReader', function(data, sink) {\n assert(this._networkStream);\n this._fullReader = this._networkStream.getFullReader();\n this._fullReader.onProgress = (evt) => {\n this._lastProgress = {\n loaded: evt.loaded,\n total: evt.total,\n };\n };\n sink.onPull = () => {\n this._fullReader.read().then(function({ value, done, }) {\n if (done) {\n sink.close();\n return;\n }\n assert(isArrayBuffer(value));\n // Enqueue data chunk into sink, and transfer it\n // to other side as `Transferable` object.\n sink.enqueue(new Uint8Array(value), 1, [value]);\n }).catch((reason) => {\n sink.error(reason);\n });\n };\n\n sink.onCancel = (reason) => {\n this._fullReader.cancel(reason);\n };\n }, this);\n\n messageHandler.on('ReaderHeadersReady', function(data) {\n let headersCapability = createPromiseCapability();\n let fullReader = this._fullReader;\n fullReader.headersReady.then(() => {\n // If stream or range are disabled, it's our only way to report\n // loading progress.\n if (!fullReader.isStreamingSupported ||\n !fullReader.isRangeSupported) {\n if (this._lastProgress) {\n let loadingTask = this.loadingTask;\n if (loadingTask.onProgress) {\n loadingTask.onProgress(this._lastProgress);\n }\n }\n fullReader.onProgress = (evt) => {\n let loadingTask = this.loadingTask;\n if (loadingTask.onProgress) {\n loadingTask.onProgress({\n loaded: evt.loaded,\n total: evt.total,\n });\n }\n };\n }\n\n headersCapability.resolve({\n isStreamingSupported: fullReader.isStreamingSupported,\n isRangeSupported: fullReader.isRangeSupported,\n contentLength: fullReader.contentLength,\n });\n }, headersCapability.reject);\n\n return headersCapability.promise;\n }, this);\n\n messageHandler.on('GetRangeReader', function(data, sink) {\n assert(this._networkStream);\n let _rangeReader =\n this._networkStream.getRangeReader(data.begin, data.end);\n\n sink.onPull = () => {\n _rangeReader.read().then(function({ value, done, }) {\n if (done) {\n sink.close();\n return;\n }\n assert(isArrayBuffer(value));\n sink.enqueue(new Uint8Array(value), 1, [value]);\n }).catch((reason) => {\n sink.error(reason);\n });\n };\n\n sink.onCancel = (reason) => {\n _rangeReader.cancel(reason);\n };\n }, this);\n\n messageHandler.on('GetDoc', function transportDoc(data) {\n var pdfInfo = data.pdfInfo;\n this.numPages = data.pdfInfo.numPages;\n var loadingTask = this.loadingTask;\n var pdfDocument = new PDFDocumentProxy(pdfInfo, this, loadingTask);\n this.pdfDocument = pdfDocument;\n loadingTask._capability.resolve(pdfDocument);\n }, this);\n\n messageHandler.on('PasswordRequest',\n function transportPasswordRequest(exception) {\n this._passwordCapability = createPromiseCapability();\n\n if (loadingTask.onPassword) {\n var updatePassword = (password) => {\n this._passwordCapability.resolve({\n password,\n });\n };\n loadingTask.onPassword(updatePassword, exception.code);\n } else {\n this._passwordCapability.reject(\n new PasswordException(exception.message, exception.code));\n }\n return this._passwordCapability.promise;\n }, this);\n\n messageHandler.on('PasswordException',\n function transportPasswordException(exception) {\n loadingTask._capability.reject(\n new PasswordException(exception.message, exception.code));\n }, this);\n\n messageHandler.on('InvalidPDF', function transportInvalidPDF(exception) {\n this.loadingTask._capability.reject(\n new InvalidPDFException(exception.message));\n }, this);\n\n messageHandler.on('MissingPDF', function transportMissingPDF(exception) {\n this.loadingTask._capability.reject(\n new MissingPDFException(exception.message));\n }, this);\n\n messageHandler.on('UnexpectedResponse',\n function transportUnexpectedResponse(exception) {\n this.loadingTask._capability.reject(\n new UnexpectedResponseException(exception.message, exception.status));\n }, this);\n\n messageHandler.on('UnknownError',\n function transportUnknownError(exception) {\n this.loadingTask._capability.reject(\n new UnknownErrorException(exception.message, exception.details));\n }, this);\n\n messageHandler.on('DataLoaded', function transportPage(data) {\n this.downloadInfoCapability.resolve(data);\n }, this);\n\n messageHandler.on('PDFManagerReady', function transportPage(data) {\n }, this);\n\n messageHandler.on('StartRenderPage', function transportRender(data) {\n if (this.destroyed) {\n return; // Ignore any pending requests if the worker was terminated.\n }\n var page = this.pageCache[data.pageIndex];\n\n page.stats.timeEnd('Page Request');\n page._startRenderPage(data.transparency, data.intent);\n }, this);\n\n messageHandler.on('RenderPageChunk', function transportRender(data) {\n if (this.destroyed) {\n return; // Ignore any pending requests if the worker was terminated.\n }\n var page = this.pageCache[data.pageIndex];\n\n page._renderPageChunk(data.operatorList, data.intent);\n }, this);\n\n messageHandler.on('commonobj', function transportObj(data) {\n if (this.destroyed) {\n return; // Ignore any pending requests if the worker was terminated.\n }\n\n var id = data[0];\n var type = data[1];\n if (this.commonObjs.hasData(id)) {\n return;\n }\n\n switch (type) {\n case 'Font':\n var exportedData = data[2];\n\n if ('error' in exportedData) {\n var exportedError = exportedData.error;\n warn('Error during font loading: ' + exportedError);\n this.commonObjs.resolve(id, exportedError);\n break;\n }\n var fontRegistry = null;\n if (getDefaultSetting('pdfBug') && globalScope.FontInspector &&\n globalScope['FontInspector'].enabled) {\n fontRegistry = {\n registerFont(font, url) {\n globalScope['FontInspector'].fontAdded(font, url);\n },\n };\n }\n var font = new FontFaceObject(exportedData, {\n isEvalSuported: getDefaultSetting('isEvalSupported'),\n disableFontFace: getDefaultSetting('disableFontFace'),\n fontRegistry,\n });\n var fontReady = (fontObjs) => {\n this.commonObjs.resolve(id, font);\n };\n\n this.fontLoader.bind([font], fontReady);\n break;\n case 'FontPath':\n this.commonObjs.resolve(id, data[2]);\n break;\n default:\n throw new Error(`Got unknown common object type ${type}`);\n }\n }, this);\n\n messageHandler.on('obj', function transportObj(data) {\n if (this.destroyed) {\n return; // Ignore any pending requests if the worker was terminated.\n }\n\n var id = data[0];\n var pageIndex = data[1];\n var type = data[2];\n var pageProxy = this.pageCache[pageIndex];\n var imageData;\n if (pageProxy.objs.hasData(id)) {\n return;\n }\n\n switch (type) {\n case 'JpegStream':\n imageData = data[3];\n loadJpegStream(id, imageData, pageProxy.objs);\n break;\n case 'Image':\n imageData = data[3];\n pageProxy.objs.resolve(id, imageData);\n\n // heuristics that will allow not to store large data\n var MAX_IMAGE_SIZE_TO_STORE = 8000000;\n if (imageData && 'data' in imageData &&\n imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) {\n pageProxy.cleanupAfterRender = true;\n }\n break;\n default:\n throw new Error(`Got unknown object type ${type}`);\n }\n }, this);\n\n messageHandler.on('DocProgress', function transportDocProgress(data) {\n if (this.destroyed) {\n return; // Ignore any pending requests if the worker was terminated.\n }\n\n var loadingTask = this.loadingTask;\n if (loadingTask.onProgress) {\n loadingTask.onProgress({\n loaded: data.loaded,\n total: data.total,\n });\n }\n }, this);\n\n messageHandler.on('PageError', function transportError(data) {\n if (this.destroyed) {\n return; // Ignore any pending requests if the worker was terminated.\n }\n\n var page = this.pageCache[data.pageNum - 1];\n var intentState = page.intentStates[data.intent];\n\n if (intentState.displayReadyCapability) {\n intentState.displayReadyCapability.reject(data.error);\n } else {\n throw new Error(data.error);\n }\n\n if (intentState.operatorList) {\n // Mark operator list as complete.\n intentState.operatorList.lastChunk = true;\n for (var i = 0; i < intentState.renderTasks.length; i++) {\n intentState.renderTasks[i].operatorListChanged();\n }\n }\n }, this);\n\n messageHandler.on('UnsupportedFeature',\n function transportUnsupportedFeature(data) {\n if (this.destroyed) {\n return; // Ignore any pending requests if the worker was terminated.\n }\n var featureId = data.featureId;\n var loadingTask = this.loadingTask;\n if (loadingTask.onUnsupportedFeature) {\n loadingTask.onUnsupportedFeature(featureId);\n }\n _UnsupportedManager.notify(featureId);\n }, this);\n\n messageHandler.on('JpegDecode', function(data) {\n if (this.destroyed) {\n return Promise.reject(new Error('Worker was destroyed'));\n }\n\n if (typeof document === 'undefined') {\n // Make sure that this code is not executing in node.js, as\n // it's using DOM image, and there is no library to support that.\n return Promise.reject(new Error('\"document\" is not defined.'));\n }\n\n var imageUrl = data[0];\n var components = data[1];\n if (components !== 3 && components !== 1) {\n return Promise.reject(\n new Error('Only 3 components or 1 component can be returned'));\n }\n\n return new Promise(function (resolve, reject) {\n var img = new Image();\n img.onload = function () {\n var width = img.width;\n var height = img.height;\n var size = width * height;\n var rgbaLength = size * 4;\n var buf = new Uint8Array(size * components);\n var tmpCanvas = document.createElement('canvas');\n tmpCanvas.width = width;\n tmpCanvas.height = height;\n var tmpCtx = tmpCanvas.getContext('2d');\n tmpCtx.drawImage(img, 0, 0);\n var data = tmpCtx.getImageData(0, 0, width, height).data;\n var i, j;\n\n if (components === 3) {\n for (i = 0, j = 0; i < rgbaLength; i += 4, j += 3) {\n buf[j] = data[i];\n buf[j + 1] = data[i + 1];\n buf[j + 2] = data[i + 2];\n }\n } else if (components === 1) {\n for (i = 0, j = 0; i < rgbaLength; i += 4, j++) {\n buf[j] = data[i];\n }\n }\n resolve({ data: buf, width, height, });\n };\n img.onerror = function () {\n reject(new Error('JpegDecode failed to load image'));\n };\n img.src = imageUrl;\n });\n }, this);\n\n messageHandler.on('FetchBuiltInCMap', function (data) {\n if (this.destroyed) {\n return Promise.reject(new Error('Worker was destroyed'));\n }\n return this.CMapReaderFactory.fetch({\n name: data.name,\n });\n }, this);\n },\n\n getData: function WorkerTransport_getData() {\n return this.messageHandler.sendWithPromise('GetData', null);\n },\n\n getPage: function WorkerTransport_getPage(pageNumber, capability) {\n if (!isInt(pageNumber) || pageNumber <= 0 || pageNumber > this.numPages) {\n return Promise.reject(new Error('Invalid page request'));\n }\n\n var pageIndex = pageNumber - 1;\n if (pageIndex in this.pagePromises) {\n return this.pagePromises[pageIndex];\n }\n var promise = this.messageHandler.sendWithPromise('GetPage', {\n pageIndex,\n }).then((pageInfo) => {\n if (this.destroyed) {\n throw new Error('Transport destroyed');\n }\n var page = new PDFPageProxy(pageIndex, pageInfo, this);\n this.pageCache[pageIndex] = page;\n return page;\n });\n this.pagePromises[pageIndex] = promise;\n return promise;\n },\n\n getPageIndex: function WorkerTransport_getPageIndexByRef(ref) {\n return this.messageHandler.sendWithPromise('GetPageIndex', {\n ref,\n }).catch(function (reason) {\n return Promise.reject(new Error(reason));\n });\n },\n\n getAnnotations: function WorkerTransport_getAnnotations(pageIndex, intent) {\n return this.messageHandler.sendWithPromise('GetAnnotations', {\n pageIndex,\n intent,\n });\n },\n\n getDestinations: function WorkerTransport_getDestinations() {\n return this.messageHandler.sendWithPromise('GetDestinations', null);\n },\n\n getDestination: function WorkerTransport_getDestination(id) {\n return this.messageHandler.sendWithPromise('GetDestination', {\n id,\n });\n },\n\n getPageLabels: function WorkerTransport_getPageLabels() {\n return this.messageHandler.sendWithPromise('GetPageLabels', null);\n },\n\n getPageMode() {\n return this.messageHandler.sendWithPromise('GetPageMode', null);\n },\n\n getAttachments: function WorkerTransport_getAttachments() {\n return this.messageHandler.sendWithPromise('GetAttachments', null);\n },\n\n getJavaScript: function WorkerTransport_getJavaScript() {\n return this.messageHandler.sendWithPromise('GetJavaScript', null);\n },\n\n getOutline: function WorkerTransport_getOutline() {\n return this.messageHandler.sendWithPromise('GetOutline', null);\n },\n\n getMetadata: function WorkerTransport_getMetadata() {\n return this.messageHandler.sendWithPromise('GetMetadata', null).\n then(function transportMetadata(results) {\n return {\n info: results[0],\n metadata: (results[1] ? new Metadata(results[1]) : null),\n };\n });\n },\n\n getStats: function WorkerTransport_getStats() {\n return this.messageHandler.sendWithPromise('GetStats', null);\n },\n\n startCleanup: function WorkerTransport_startCleanup() {\n this.messageHandler.sendWithPromise('Cleanup', null).then(() => {\n for (var i = 0, ii = this.pageCache.length; i < ii; i++) {\n var page = this.pageCache[i];\n if (page) {\n page.cleanup();\n }\n }\n this.commonObjs.clear();\n this.fontLoader.clear();\n });\n },\n };\n return WorkerTransport;\n\n})();\n\n/**\n * A PDF document and page is built of many objects. E.g. there are objects\n * for fonts, images, rendering code and such. These objects might get processed\n * inside of a worker. The `PDFObjects` implements some basic functions to\n * manage these objects.\n * @ignore\n */\nvar PDFObjects = (function PDFObjectsClosure() {\n function PDFObjects() {\n this.objs = Object.create(null);\n }\n\n PDFObjects.prototype = {\n /**\n * Internal function.\n * Ensures there is an object defined for `objId`.\n */\n ensureObj: function PDFObjects_ensureObj(objId) {\n if (this.objs[objId]) {\n return this.objs[objId];\n }\n\n var obj = {\n capability: createPromiseCapability(),\n data: null,\n resolved: false,\n };\n this.objs[objId] = obj;\n\n return obj;\n },\n\n /**\n * If called *without* callback, this returns the data of `objId` but the\n * object needs to be resolved. If it isn't, this function throws.\n *\n * If called *with* a callback, the callback is called with the data of the\n * object once the object is resolved. That means, if you call this\n * function and the object is already resolved, the callback gets called\n * right away.\n */\n get: function PDFObjects_get(objId, callback) {\n // If there is a callback, then the get can be async and the object is\n // not required to be resolved right now\n if (callback) {\n this.ensureObj(objId).capability.promise.then(callback);\n return null;\n }\n\n // If there isn't a callback, the user expects to get the resolved data\n // directly.\n var obj = this.objs[objId];\n\n // If there isn't an object yet or the object isn't resolved, then the\n // data isn't ready yet!\n if (!obj || !obj.resolved) {\n throw new Error(`Requesting object that isn't resolved yet ${objId}`);\n }\n\n return obj.data;\n },\n\n /**\n * Resolves the object `objId` with optional `data`.\n */\n resolve: function PDFObjects_resolve(objId, data) {\n var obj = this.ensureObj(objId);\n\n obj.resolved = true;\n obj.data = data;\n obj.capability.resolve(data);\n },\n\n isResolved: function PDFObjects_isResolved(objId) {\n var objs = this.objs;\n\n if (!objs[objId]) {\n return false;\n }\n return objs[objId].resolved;\n },\n\n hasData: function PDFObjects_hasData(objId) {\n return this.isResolved(objId);\n },\n\n /**\n * Returns the data of `objId` if object exists, null otherwise.\n */\n getData: function PDFObjects_getData(objId) {\n var objs = this.objs;\n if (!objs[objId] || !objs[objId].resolved) {\n return null;\n }\n return objs[objId].data;\n },\n\n clear: function PDFObjects_clear() {\n this.objs = Object.create(null);\n },\n };\n return PDFObjects;\n})();\n\n/**\n * Allows controlling of the rendering tasks.\n * @class\n * @alias RenderTask\n */\nvar RenderTask = (function RenderTaskClosure() {\n function RenderTask(internalRenderTask) {\n this._internalRenderTask = internalRenderTask;\n\n /**\n * Callback for incremental rendering -- a function that will be called\n * each time the rendering is paused. To continue rendering call the\n * function that is the first argument to the callback.\n * @type {function}\n */\n this.onContinue = null;\n }\n\n RenderTask.prototype = /** @lends RenderTask.prototype */ {\n /**\n * Promise for rendering task completion.\n * @return {Promise}\n */\n get promise() {\n return this._internalRenderTask.capability.promise;\n },\n\n /**\n * Cancels the rendering task. If the task is currently rendering it will\n * not be cancelled until graphics pauses with a timeout. The promise that\n * this object extends will be rejected when cancelled.\n */\n cancel: function RenderTask_cancel() {\n this._internalRenderTask.cancel();\n },\n\n /**\n * Registers callbacks to indicate the rendering task completion.\n *\n * @param {function} onFulfilled The callback for the rendering completion.\n * @param {function} onRejected The callback for the rendering failure.\n * @return {Promise} A promise that is resolved after the onFulfilled or\n * onRejected callback.\n */\n then: function RenderTask_then(onFulfilled, onRejected) {\n return this.promise.then.apply(this.promise, arguments);\n },\n };\n\n return RenderTask;\n})();\n\n/**\n * For internal use only.\n * @ignore\n */\nvar InternalRenderTask = (function InternalRenderTaskClosure() {\n let canvasInRendering = new WeakMap();\n\n function InternalRenderTask(callback, params, objs, commonObjs, operatorList,\n pageNumber, canvasFactory) {\n this.callback = callback;\n this.params = params;\n this.objs = objs;\n this.commonObjs = commonObjs;\n this.operatorListIdx = null;\n this.operatorList = operatorList;\n this.pageNumber = pageNumber;\n this.canvasFactory = canvasFactory;\n this.running = false;\n this.graphicsReadyCallback = null;\n this.graphicsReady = false;\n this.useRequestAnimationFrame = false;\n this.cancelled = false;\n this.capability = createPromiseCapability();\n this.task = new RenderTask(this);\n // caching this-bound methods\n this._continueBound = this._continue.bind(this);\n this._scheduleNextBound = this._scheduleNext.bind(this);\n this._nextBound = this._next.bind(this);\n this._canvas = params.canvasContext.canvas;\n }\n\n InternalRenderTask.prototype = {\n\n initializeGraphics:\n function InternalRenderTask_initializeGraphics(transparency) {\n\n if (this._canvas) {\n if (canvasInRendering.has(this._canvas)) {\n throw new Error(\n 'Cannot use the same canvas during multiple render() operations. ' +\n 'Use different canvas or ensure previous operations were ' +\n 'cancelled or completed.');\n }\n canvasInRendering.set(this._canvas, this);\n }\n\n if (this.cancelled) {\n return;\n }\n if (getDefaultSetting('pdfBug') && globalScope.StepperManager &&\n globalScope.StepperManager.enabled) {\n this.stepper = globalScope.StepperManager.create(this.pageNumber - 1);\n this.stepper.init(this.operatorList);\n this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint();\n }\n\n var params = this.params;\n this.gfx = new CanvasGraphics(params.canvasContext, this.commonObjs,\n this.objs, this.canvasFactory,\n params.imageLayer);\n\n this.gfx.beginDrawing({\n transform: params.transform,\n viewport: params.viewport,\n transparency,\n background: params.background,\n });\n this.operatorListIdx = 0;\n this.graphicsReady = true;\n if (this.graphicsReadyCallback) {\n this.graphicsReadyCallback();\n }\n },\n\n cancel: function InternalRenderTask_cancel() {\n this.running = false;\n this.cancelled = true;\n if (this._canvas) {\n canvasInRendering.delete(this._canvas);\n }\n\n if ((typeof PDFJSDev !== 'undefined' && PDFJSDev.test('PDFJS_NEXT')) ||\n getDefaultSetting('pdfjsNext')) {\n this.callback(new RenderingCancelledException(\n 'Rendering cancelled, page ' + this.pageNumber, 'canvas'));\n } else {\n this.callback('cancelled');\n }\n },\n\n operatorListChanged: function InternalRenderTask_operatorListChanged() {\n if (!this.graphicsReady) {\n if (!this.graphicsReadyCallback) {\n this.graphicsReadyCallback = this._continueBound;\n }\n return;\n }\n\n if (this.stepper) {\n this.stepper.updateOperatorList(this.operatorList);\n }\n\n if (this.running) {\n return;\n }\n this._continue();\n },\n\n _continue: function InternalRenderTask__continue() {\n this.running = true;\n if (this.cancelled) {\n return;\n }\n if (this.task.onContinue) {\n this.task.onContinue(this._scheduleNextBound);\n } else {\n this._scheduleNext();\n }\n },\n\n _scheduleNext: function InternalRenderTask__scheduleNext() {\n if (this.useRequestAnimationFrame && typeof window !== 'undefined') {\n window.requestAnimationFrame(this._nextBound);\n } else {\n Promise.resolve(undefined).then(this._nextBound);\n }\n },\n\n _next: function InternalRenderTask__next() {\n if (this.cancelled) {\n return;\n }\n this.operatorListIdx = this.gfx.executeOperatorList(this.operatorList,\n this.operatorListIdx,\n this._continueBound,\n this.stepper);\n if (this.operatorListIdx === this.operatorList.argsArray.length) {\n this.running = false;\n if (this.operatorList.lastChunk) {\n this.gfx.endDrawing();\n if (this._canvas) {\n canvasInRendering.delete(this._canvas);\n }\n this.callback();\n }\n }\n },\n\n };\n\n return InternalRenderTask;\n})();\n\n/**\n * (Deprecated) Global observer of unsupported feature usages. Use\n * onUnsupportedFeature callback of the {PDFDocumentLoadingTask} instance.\n */\nvar _UnsupportedManager = (function UnsupportedManagerClosure() {\n var listeners = [];\n return {\n listen(cb) {\n deprecated('Global UnsupportedManager.listen is used: ' +\n ' use PDFDocumentLoadingTask.onUnsupportedFeature instead');\n listeners.push(cb);\n },\n notify(featureId) {\n for (var i = 0, ii = listeners.length; i < ii; i++) {\n listeners[i](featureId);\n }\n },\n };\n})();\n\nvar version, build;\nif (typeof PDFJSDev !== 'undefined') {\n version = PDFJSDev.eval('BUNDLE_VERSION');\n build = PDFJSDev.eval('BUNDLE_BUILD');\n}\n\nexport {\n getDocument,\n LoopbackPort,\n PDFDataRangeTransport,\n PDFWorker,\n PDFDocumentProxy,\n PDFPageProxy,\n setPDFNetworkStreamClass,\n _UnsupportedManager,\n version,\n build,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/display/api.js", + "/* Copyright 2014 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n addLinkAttributes, CustomStyle, getDefaultSetting, getFilenameFromUrl,\n LinkTarget\n} from './dom_utils';\nimport {\n AnnotationBorderStyleType, AnnotationType, stringToPDFString, Util, warn\n} from '../shared/util';\n\n/**\n * @typedef {Object} AnnotationElementParameters\n * @property {Object} data\n * @property {HTMLDivElement} layer\n * @property {PDFPage} page\n * @property {PageViewport} viewport\n * @property {IPDFLinkService} linkService\n * @property {DownloadManager} downloadManager\n * @property {string} imageResourcesPath\n * @property {boolean} renderInteractiveForms\n */\n\n/**\n * @class\n * @alias AnnotationElementFactory\n */\nfunction AnnotationElementFactory() {}\nAnnotationElementFactory.prototype =\n /** @lends AnnotationElementFactory.prototype */ {\n /**\n * @param {AnnotationElementParameters} parameters\n * @returns {AnnotationElement}\n */\n create: function AnnotationElementFactory_create(parameters) {\n var subtype = parameters.data.annotationType;\n\n switch (subtype) {\n case AnnotationType.LINK:\n return new LinkAnnotationElement(parameters);\n\n case AnnotationType.TEXT:\n return new TextAnnotationElement(parameters);\n\n case AnnotationType.WIDGET:\n var fieldType = parameters.data.fieldType;\n\n switch (fieldType) {\n case 'Tx':\n return new TextWidgetAnnotationElement(parameters);\n case 'Btn':\n if (parameters.data.radioButton) {\n return new RadioButtonWidgetAnnotationElement(parameters);\n } else if (parameters.data.checkBox) {\n return new CheckboxWidgetAnnotationElement(parameters);\n }\n warn('Unimplemented button widget annotation: pushbutton');\n break;\n case 'Ch':\n return new ChoiceWidgetAnnotationElement(parameters);\n }\n return new WidgetAnnotationElement(parameters);\n\n case AnnotationType.POPUP:\n return new PopupAnnotationElement(parameters);\n\n case AnnotationType.LINE:\n return new LineAnnotationElement(parameters);\n\n case AnnotationType.HIGHLIGHT:\n return new HighlightAnnotationElement(parameters);\n\n case AnnotationType.UNDERLINE:\n return new UnderlineAnnotationElement(parameters);\n\n case AnnotationType.SQUIGGLY:\n return new SquigglyAnnotationElement(parameters);\n\n case AnnotationType.STRIKEOUT:\n return new StrikeOutAnnotationElement(parameters);\n\n case AnnotationType.FILEATTACHMENT:\n return new FileAttachmentAnnotationElement(parameters);\n\n default:\n return new AnnotationElement(parameters);\n }\n },\n};\n\n/**\n * @class\n * @alias AnnotationElement\n */\nvar AnnotationElement = (function AnnotationElementClosure() {\n function AnnotationElement(parameters, isRenderable, ignoreBorder) {\n this.isRenderable = isRenderable || false;\n this.data = parameters.data;\n this.layer = parameters.layer;\n this.page = parameters.page;\n this.viewport = parameters.viewport;\n this.linkService = parameters.linkService;\n this.downloadManager = parameters.downloadManager;\n this.imageResourcesPath = parameters.imageResourcesPath;\n this.renderInteractiveForms = parameters.renderInteractiveForms;\n\n if (isRenderable) {\n this.container = this._createContainer(ignoreBorder);\n }\n }\n\n AnnotationElement.prototype = /** @lends AnnotationElement.prototype */ {\n /**\n * Create an empty container for the annotation's HTML element.\n *\n * @private\n * @param {boolean} ignoreBorder\n * @memberof AnnotationElement\n * @returns {HTMLSectionElement}\n */\n _createContainer:\n function AnnotationElement_createContainer(ignoreBorder) {\n var data = this.data, page = this.page, viewport = this.viewport;\n var container = document.createElement('section');\n var width = data.rect[2] - data.rect[0];\n var height = data.rect[3] - data.rect[1];\n\n container.setAttribute('data-annotation-id', data.id);\n\n // Do *not* modify `data.rect`, since that will corrupt the annotation\n // position on subsequent calls to `_createContainer` (see issue 6804).\n var rect = Util.normalizeRect([\n data.rect[0],\n page.view[3] - data.rect[1] + page.view[1],\n data.rect[2],\n page.view[3] - data.rect[3] + page.view[1]\n ]);\n\n CustomStyle.setProp('transform', container,\n 'matrix(' + viewport.transform.join(',') + ')');\n CustomStyle.setProp('transformOrigin', container,\n -rect[0] + 'px ' + -rect[1] + 'px');\n\n if (!ignoreBorder && data.borderStyle.width > 0) {\n container.style.borderWidth = data.borderStyle.width + 'px';\n if (data.borderStyle.style !== AnnotationBorderStyleType.UNDERLINE) {\n // Underline styles only have a bottom border, so we do not need\n // to adjust for all borders. This yields a similar result as\n // Adobe Acrobat/Reader.\n width = width - 2 * data.borderStyle.width;\n height = height - 2 * data.borderStyle.width;\n }\n\n var horizontalRadius = data.borderStyle.horizontalCornerRadius;\n var verticalRadius = data.borderStyle.verticalCornerRadius;\n if (horizontalRadius > 0 || verticalRadius > 0) {\n var radius = horizontalRadius + 'px / ' + verticalRadius + 'px';\n CustomStyle.setProp('borderRadius', container, radius);\n }\n\n switch (data.borderStyle.style) {\n case AnnotationBorderStyleType.SOLID:\n container.style.borderStyle = 'solid';\n break;\n\n case AnnotationBorderStyleType.DASHED:\n container.style.borderStyle = 'dashed';\n break;\n\n case AnnotationBorderStyleType.BEVELED:\n warn('Unimplemented border style: beveled');\n break;\n\n case AnnotationBorderStyleType.INSET:\n warn('Unimplemented border style: inset');\n break;\n\n case AnnotationBorderStyleType.UNDERLINE:\n container.style.borderBottomStyle = 'solid';\n break;\n\n default:\n break;\n }\n\n if (data.color) {\n container.style.borderColor =\n Util.makeCssRgb(data.color[0] | 0,\n data.color[1] | 0,\n data.color[2] | 0);\n } else {\n // Transparent (invisible) border, so do not draw it at all.\n container.style.borderWidth = 0;\n }\n }\n\n container.style.left = rect[0] + 'px';\n container.style.top = rect[1] + 'px';\n\n container.style.width = width + 'px';\n container.style.height = height + 'px';\n\n return container;\n },\n\n /**\n * Create a popup for the annotation's HTML element. This is used for\n * annotations that do not have a Popup entry in the dictionary, but\n * are of a type that works with popups (such as Highlight annotations).\n *\n * @private\n * @param {HTMLSectionElement} container\n * @param {HTMLDivElement|HTMLImageElement|null} trigger\n * @param {Object} data\n * @memberof AnnotationElement\n */\n _createPopup:\n function AnnotationElement_createPopup(container, trigger, data) {\n // If no trigger element is specified, create it.\n if (!trigger) {\n trigger = document.createElement('div');\n trigger.style.height = container.style.height;\n trigger.style.width = container.style.width;\n container.appendChild(trigger);\n }\n\n var popupElement = new PopupElement({\n container,\n trigger,\n color: data.color,\n title: data.title,\n contents: data.contents,\n hideWrapper: true,\n });\n var popup = popupElement.render();\n\n // Position the popup next to the annotation's container.\n popup.style.left = container.style.width;\n\n container.appendChild(popup);\n },\n\n /**\n * Render the annotation's HTML element in the empty container.\n *\n * @public\n * @memberof AnnotationElement\n */\n render: function AnnotationElement_render() {\n throw new Error('Abstract method AnnotationElement.render called');\n },\n };\n\n return AnnotationElement;\n})();\n\n/**\n * @class\n * @alias LinkAnnotationElement\n */\nvar LinkAnnotationElement = (function LinkAnnotationElementClosure() {\n function LinkAnnotationElement(parameters) {\n AnnotationElement.call(this, parameters, true);\n }\n\n Util.inherit(LinkAnnotationElement, AnnotationElement, {\n /**\n * Render the link annotation's HTML element in the empty container.\n *\n * @public\n * @memberof LinkAnnotationElement\n * @returns {HTMLSectionElement}\n */\n render: function LinkAnnotationElement_render() {\n this.container.className = 'linkAnnotation';\n\n var link = document.createElement('a');\n addLinkAttributes(link, {\n url: this.data.url,\n target: (this.data.newWindow ? LinkTarget.BLANK : undefined),\n });\n\n if (!this.data.url) {\n if (this.data.action) {\n this._bindNamedAction(link, this.data.action);\n } else {\n this._bindLink(link, this.data.dest);\n }\n }\n\n this.container.appendChild(link);\n return this.container;\n },\n\n /**\n * Bind internal links to the link element.\n *\n * @private\n * @param {Object} link\n * @param {Object} destination\n * @memberof LinkAnnotationElement\n */\n _bindLink(link, destination) {\n link.href = this.linkService.getDestinationHash(destination);\n link.onclick = () => {\n if (destination) {\n this.linkService.navigateTo(destination);\n }\n return false;\n };\n if (destination) {\n link.className = 'internalLink';\n }\n },\n\n /**\n * Bind named actions to the link element.\n *\n * @private\n * @param {Object} link\n * @param {Object} action\n * @memberof LinkAnnotationElement\n */\n _bindNamedAction(link, action) {\n link.href = this.linkService.getAnchorUrl('');\n link.onclick = () => {\n this.linkService.executeNamedAction(action);\n return false;\n };\n link.className = 'internalLink';\n },\n });\n\n return LinkAnnotationElement;\n})();\n\n/**\n * @class\n * @alias TextAnnotationElement\n */\nvar TextAnnotationElement = (function TextAnnotationElementClosure() {\n function TextAnnotationElement(parameters) {\n var isRenderable = !!(parameters.data.hasPopup ||\n parameters.data.title || parameters.data.contents);\n AnnotationElement.call(this, parameters, isRenderable);\n }\n\n Util.inherit(TextAnnotationElement, AnnotationElement, {\n /**\n * Render the text annotation's HTML element in the empty container.\n *\n * @public\n * @memberof TextAnnotationElement\n * @returns {HTMLSectionElement}\n */\n render: function TextAnnotationElement_render() {\n this.container.className = 'textAnnotation';\n\n var image = document.createElement('img');\n image.style.height = this.container.style.height;\n image.style.width = this.container.style.width;\n image.src = this.imageResourcesPath + 'annotation-' +\n this.data.name.toLowerCase() + '.svg';\n image.alt = '[{{type}} Annotation]';\n image.dataset.l10nId = 'text_annotation_type';\n image.dataset.l10nArgs = JSON.stringify({ type: this.data.name, });\n\n if (!this.data.hasPopup) {\n this._createPopup(this.container, image, this.data);\n }\n\n this.container.appendChild(image);\n return this.container;\n },\n });\n\n return TextAnnotationElement;\n})();\n\n/**\n * @class\n * @alias WidgetAnnotationElement\n */\nvar WidgetAnnotationElement = (function WidgetAnnotationElementClosure() {\n function WidgetAnnotationElement(parameters, isRenderable) {\n AnnotationElement.call(this, parameters, isRenderable);\n }\n\n Util.inherit(WidgetAnnotationElement, AnnotationElement, {\n /**\n * Render the widget annotation's HTML element in the empty container.\n *\n * @public\n * @memberof WidgetAnnotationElement\n * @returns {HTMLSectionElement}\n */\n render: function WidgetAnnotationElement_render() {\n // Show only the container for unsupported field types.\n return this.container;\n },\n });\n\n return WidgetAnnotationElement;\n})();\n\n/**\n * @class\n * @alias TextWidgetAnnotationElement\n */\nvar TextWidgetAnnotationElement = (\n function TextWidgetAnnotationElementClosure() {\n var TEXT_ALIGNMENT = ['left', 'center', 'right'];\n\n function TextWidgetAnnotationElement(parameters) {\n var isRenderable = parameters.renderInteractiveForms ||\n (!parameters.data.hasAppearance && !!parameters.data.fieldValue);\n WidgetAnnotationElement.call(this, parameters, isRenderable);\n }\n\n Util.inherit(TextWidgetAnnotationElement, WidgetAnnotationElement, {\n /**\n * Render the text widget annotation's HTML element in the empty container.\n *\n * @public\n * @memberof TextWidgetAnnotationElement\n * @returns {HTMLSectionElement}\n */\n render: function TextWidgetAnnotationElement_render() {\n this.container.className = 'textWidgetAnnotation';\n\n var element = null;\n if (this.renderInteractiveForms) {\n // NOTE: We cannot set the values using `element.value` below, since it\n // prevents the AnnotationLayer rasterizer in `test/driver.js`\n // from parsing the elements correctly for the reference tests.\n if (this.data.multiLine) {\n element = document.createElement('textarea');\n element.textContent = this.data.fieldValue;\n } else {\n element = document.createElement('input');\n element.type = 'text';\n element.setAttribute('value', this.data.fieldValue);\n }\n\n element.disabled = this.data.readOnly;\n\n if (this.data.maxLen !== null) {\n element.maxLength = this.data.maxLen;\n }\n\n if (this.data.comb) {\n var fieldWidth = this.data.rect[2] - this.data.rect[0];\n var combWidth = fieldWidth / this.data.maxLen;\n\n element.classList.add('comb');\n element.style.letterSpacing = 'calc(' + combWidth + 'px - 1ch)';\n }\n } else {\n element = document.createElement('div');\n element.textContent = this.data.fieldValue;\n element.style.verticalAlign = 'middle';\n element.style.display = 'table-cell';\n\n var font = null;\n if (this.data.fontRefName) {\n font = this.page.commonObjs.getData(this.data.fontRefName);\n }\n this._setTextStyle(element, font);\n }\n\n if (this.data.textAlignment !== null) {\n element.style.textAlign = TEXT_ALIGNMENT[this.data.textAlignment];\n }\n\n this.container.appendChild(element);\n return this.container;\n },\n\n /**\n * Apply text styles to the text in the element.\n *\n * @private\n * @param {HTMLDivElement} element\n * @param {Object} font\n * @memberof TextWidgetAnnotationElement\n */\n _setTextStyle:\n function TextWidgetAnnotationElement_setTextStyle(element, font) {\n // TODO: This duplicates some of the logic in CanvasGraphics.setFont().\n var style = element.style;\n style.fontSize = this.data.fontSize + 'px';\n style.direction = (this.data.fontDirection < 0 ? 'rtl' : 'ltr');\n\n if (!font) {\n return;\n }\n\n style.fontWeight = (font.black ?\n (font.bold ? '900' : 'bold') :\n (font.bold ? 'bold' : 'normal'));\n style.fontStyle = (font.italic ? 'italic' : 'normal');\n\n // Use a reasonable default font if the font doesn't specify a fallback.\n var fontFamily = font.loadedName ? '\"' + font.loadedName + '\", ' : '';\n var fallbackName = font.fallbackName || 'Helvetica, sans-serif';\n style.fontFamily = fontFamily + fallbackName;\n },\n });\n\n return TextWidgetAnnotationElement;\n})();\n\n/**\n * @class\n * @alias CheckboxWidgetAnnotationElement\n */\nvar CheckboxWidgetAnnotationElement =\n (function CheckboxWidgetAnnotationElementClosure() {\n function CheckboxWidgetAnnotationElement(parameters) {\n WidgetAnnotationElement.call(this, parameters,\n parameters.renderInteractiveForms);\n }\n\n Util.inherit(CheckboxWidgetAnnotationElement, WidgetAnnotationElement, {\n /**\n * Render the checkbox widget annotation's HTML element\n * in the empty container.\n *\n * @public\n * @memberof CheckboxWidgetAnnotationElement\n * @returns {HTMLSectionElement}\n */\n render: function CheckboxWidgetAnnotationElement_render() {\n this.container.className = 'buttonWidgetAnnotation checkBox';\n\n var element = document.createElement('input');\n element.disabled = this.data.readOnly;\n element.type = 'checkbox';\n if (this.data.fieldValue && this.data.fieldValue !== 'Off') {\n element.setAttribute('checked', true);\n }\n\n this.container.appendChild(element);\n return this.container;\n },\n });\n\n return CheckboxWidgetAnnotationElement;\n})();\n\n/**\n * @class\n * @alias RadioButtonWidgetAnnotationElement\n */\nvar RadioButtonWidgetAnnotationElement =\n (function RadioButtonWidgetAnnotationElementClosure() {\n function RadioButtonWidgetAnnotationElement(parameters) {\n WidgetAnnotationElement.call(this, parameters,\n parameters.renderInteractiveForms);\n }\n\n Util.inherit(RadioButtonWidgetAnnotationElement, WidgetAnnotationElement, {\n /**\n * Render the radio button widget annotation's HTML element\n * in the empty container.\n *\n * @public\n * @memberof RadioButtonWidgetAnnotationElement\n * @returns {HTMLSectionElement}\n */\n render: function RadioButtonWidgetAnnotationElement_render() {\n this.container.className = 'buttonWidgetAnnotation radioButton';\n\n var element = document.createElement('input');\n element.disabled = this.data.readOnly;\n element.type = 'radio';\n element.name = this.data.fieldName;\n if (this.data.fieldValue === this.data.buttonValue) {\n element.setAttribute('checked', true);\n }\n\n this.container.appendChild(element);\n return this.container;\n },\n });\n\n return RadioButtonWidgetAnnotationElement;\n})();\n\n /**\n * @class\n * @alias ChoiceWidgetAnnotationElement\n */\nvar ChoiceWidgetAnnotationElement = (\n function ChoiceWidgetAnnotationElementClosure() {\n function ChoiceWidgetAnnotationElement(parameters) {\n WidgetAnnotationElement.call(this, parameters,\n parameters.renderInteractiveForms);\n }\n\n Util.inherit(ChoiceWidgetAnnotationElement, WidgetAnnotationElement, {\n /**\n * Render the choice widget annotation's HTML element in the empty\n * container.\n *\n * @public\n * @memberof ChoiceWidgetAnnotationElement\n * @returns {HTMLSectionElement}\n */\n render: function ChoiceWidgetAnnotationElement_render() {\n this.container.className = 'choiceWidgetAnnotation';\n\n var selectElement = document.createElement('select');\n selectElement.disabled = this.data.readOnly;\n\n if (!this.data.combo) {\n // List boxes have a size and (optionally) multiple selection.\n selectElement.size = this.data.options.length;\n\n if (this.data.multiSelect) {\n selectElement.multiple = true;\n }\n }\n\n // Insert the options into the choice field.\n for (var i = 0, ii = this.data.options.length; i < ii; i++) {\n var option = this.data.options[i];\n\n var optionElement = document.createElement('option');\n optionElement.textContent = option.displayValue;\n optionElement.value = option.exportValue;\n\n if (this.data.fieldValue.indexOf(option.displayValue) >= 0) {\n optionElement.setAttribute('selected', true);\n }\n\n selectElement.appendChild(optionElement);\n }\n\n this.container.appendChild(selectElement);\n return this.container;\n },\n });\n\n return ChoiceWidgetAnnotationElement;\n})();\n\n/**\n * @class\n * @alias PopupAnnotationElement\n */\nvar PopupAnnotationElement = (function PopupAnnotationElementClosure() {\n // Do not render popup annotations for parent elements with these types as\n // they create the popups themselves (because of custom trigger divs).\n var IGNORE_TYPES = ['Line'];\n\n function PopupAnnotationElement(parameters) {\n var isRenderable = !!(parameters.data.title || parameters.data.contents);\n AnnotationElement.call(this, parameters, isRenderable);\n }\n\n Util.inherit(PopupAnnotationElement, AnnotationElement, {\n /**\n * Render the popup annotation's HTML element in the empty container.\n *\n * @public\n * @memberof PopupAnnotationElement\n * @returns {HTMLSectionElement}\n */\n render: function PopupAnnotationElement_render() {\n this.container.className = 'popupAnnotation';\n\n if (IGNORE_TYPES.indexOf(this.data.parentType) >= 0) {\n return this.container;\n }\n\n var selector = '[data-annotation-id=\"' + this.data.parentId + '\"]';\n var parentElement = this.layer.querySelector(selector);\n if (!parentElement) {\n return this.container;\n }\n\n var popup = new PopupElement({\n container: this.container,\n trigger: parentElement,\n color: this.data.color,\n title: this.data.title,\n contents: this.data.contents,\n });\n\n // Position the popup next to the parent annotation's container.\n // PDF viewers ignore a popup annotation's rectangle.\n var parentLeft = parseFloat(parentElement.style.left);\n var parentWidth = parseFloat(parentElement.style.width);\n CustomStyle.setProp('transformOrigin', this.container,\n -(parentLeft + parentWidth) + 'px -' +\n parentElement.style.top);\n this.container.style.left = (parentLeft + parentWidth) + 'px';\n\n this.container.appendChild(popup.render());\n return this.container;\n },\n });\n\n return PopupAnnotationElement;\n})();\n\n/**\n * @class\n * @alias PopupElement\n */\nvar PopupElement = (function PopupElementClosure() {\n var BACKGROUND_ENLIGHT = 0.7;\n\n function PopupElement(parameters) {\n this.container = parameters.container;\n this.trigger = parameters.trigger;\n this.color = parameters.color;\n this.title = parameters.title;\n this.contents = parameters.contents;\n this.hideWrapper = parameters.hideWrapper || false;\n\n this.pinned = false;\n }\n\n PopupElement.prototype = /** @lends PopupElement.prototype */ {\n /**\n * Render the popup's HTML element.\n *\n * @public\n * @memberof PopupElement\n * @returns {HTMLSectionElement}\n */\n render: function PopupElement_render() {\n var wrapper = document.createElement('div');\n wrapper.className = 'popupWrapper';\n\n // For Popup annotations we hide the entire section because it contains\n // only the popup. However, for Text annotations without a separate Popup\n // annotation, we cannot hide the entire container as the image would\n // disappear too. In that special case, hiding the wrapper suffices.\n this.hideElement = (this.hideWrapper ? wrapper : this.container);\n this.hideElement.setAttribute('hidden', true);\n\n var popup = document.createElement('div');\n popup.className = 'popup';\n\n var color = this.color;\n if (color) {\n // Enlighten the color.\n var r = BACKGROUND_ENLIGHT * (255 - color[0]) + color[0];\n var g = BACKGROUND_ENLIGHT * (255 - color[1]) + color[1];\n var b = BACKGROUND_ENLIGHT * (255 - color[2]) + color[2];\n popup.style.backgroundColor = Util.makeCssRgb(r | 0, g | 0, b | 0);\n }\n\n var contents = this._formatContents(this.contents);\n var title = document.createElement('h1');\n title.textContent = this.title;\n\n // Attach the event listeners to the trigger element.\n this.trigger.addEventListener('click', this._toggle.bind(this));\n this.trigger.addEventListener('mouseover', this._show.bind(this, false));\n this.trigger.addEventListener('mouseout', this._hide.bind(this, false));\n popup.addEventListener('click', this._hide.bind(this, true));\n\n popup.appendChild(title);\n popup.appendChild(contents);\n wrapper.appendChild(popup);\n return wrapper;\n },\n\n /**\n * Format the contents of the popup by adding newlines where necessary.\n *\n * @private\n * @param {string} contents\n * @memberof PopupElement\n * @returns {HTMLParagraphElement}\n */\n _formatContents: function PopupElement_formatContents(contents) {\n var p = document.createElement('p');\n var lines = contents.split(/(?:\\r\\n?|\\n)/);\n for (var i = 0, ii = lines.length; i < ii; ++i) {\n var line = lines[i];\n p.appendChild(document.createTextNode(line));\n if (i < (ii - 1)) {\n p.appendChild(document.createElement('br'));\n }\n }\n return p;\n },\n\n /**\n * Toggle the visibility of the popup.\n *\n * @private\n * @memberof PopupElement\n */\n _toggle: function PopupElement_toggle() {\n if (this.pinned) {\n this._hide(true);\n } else {\n this._show(true);\n }\n },\n\n /**\n * Show the popup.\n *\n * @private\n * @param {boolean} pin\n * @memberof PopupElement\n */\n _show: function PopupElement_show(pin) {\n if (pin) {\n this.pinned = true;\n }\n if (this.hideElement.hasAttribute('hidden')) {\n this.hideElement.removeAttribute('hidden');\n this.container.style.zIndex += 1;\n }\n },\n\n /**\n * Hide the popup.\n *\n * @private\n * @param {boolean} unpin\n * @memberof PopupElement\n */\n _hide: function PopupElement_hide(unpin) {\n if (unpin) {\n this.pinned = false;\n }\n if (!this.hideElement.hasAttribute('hidden') && !this.pinned) {\n this.hideElement.setAttribute('hidden', true);\n this.container.style.zIndex -= 1;\n }\n },\n };\n\n return PopupElement;\n})();\n\n/**\n * @class\n * @alias LineAnnotationElement\n */\nvar LineAnnotationElement = (function LineAnnotationElementClosure() {\n var SVG_NS = 'http://www.w3.org/2000/svg';\n\n function LineAnnotationElement(parameters) {\n var isRenderable = !!(parameters.data.hasPopup ||\n parameters.data.title || parameters.data.contents);\n AnnotationElement.call(this, parameters, isRenderable,\n /* ignoreBorder = */ true);\n }\n\n Util.inherit(LineAnnotationElement, AnnotationElement, {\n /**\n * Render the line annotation's HTML element in the empty container.\n *\n * @public\n * @memberof LineAnnotationElement\n * @returns {HTMLSectionElement}\n */\n render: function LineAnnotationElement_render() {\n this.container.className = 'lineAnnotation';\n\n // Create an invisible line with the same starting and ending coordinates\n // that acts as the trigger for the popup. Only the line itself should\n // trigger the popup, not the entire container.\n var data = this.data;\n var width = data.rect[2] - data.rect[0];\n var height = data.rect[3] - data.rect[1];\n\n var svg = document.createElementNS(SVG_NS, 'svg:svg');\n svg.setAttributeNS(null, 'version', '1.1');\n svg.setAttributeNS(null, 'width', width + 'px');\n svg.setAttributeNS(null, 'height', height + 'px');\n svg.setAttributeNS(null, 'preserveAspectRatio', 'none');\n svg.setAttributeNS(null, 'viewBox', '0 0 ' + width + ' ' + height);\n\n // PDF coordinates are calculated from a bottom left origin, so transform\n // the line coordinates to a top left origin for the SVG element.\n var line = document.createElementNS(SVG_NS, 'svg:line');\n line.setAttributeNS(null, 'x1', data.rect[2] - data.lineCoordinates[0]);\n line.setAttributeNS(null, 'y1', data.rect[3] - data.lineCoordinates[1]);\n line.setAttributeNS(null, 'x2', data.rect[2] - data.lineCoordinates[2]);\n line.setAttributeNS(null, 'y2', data.rect[3] - data.lineCoordinates[3]);\n line.setAttributeNS(null, 'stroke-width', data.borderStyle.width);\n line.setAttributeNS(null, 'stroke', 'transparent');\n\n svg.appendChild(line);\n this.container.append(svg);\n\n // Create the popup ourselves so that we can bind it to the line instead\n // of to the entire container (which is the default).\n this._createPopup(this.container, line, this.data);\n\n return this.container;\n },\n });\n\n return LineAnnotationElement;\n})();\n\n/**\n * @class\n * @alias HighlightAnnotationElement\n */\nvar HighlightAnnotationElement = (\n function HighlightAnnotationElementClosure() {\n function HighlightAnnotationElement(parameters) {\n var isRenderable = !!(parameters.data.hasPopup ||\n parameters.data.title || parameters.data.contents);\n AnnotationElement.call(this, parameters, isRenderable,\n /* ignoreBorder = */ true);\n }\n\n Util.inherit(HighlightAnnotationElement, AnnotationElement, {\n /**\n * Render the highlight annotation's HTML element in the empty container.\n *\n * @public\n * @memberof HighlightAnnotationElement\n * @returns {HTMLSectionElement}\n */\n render: function HighlightAnnotationElement_render() {\n this.container.className = 'highlightAnnotation';\n\n if (!this.data.hasPopup) {\n this._createPopup(this.container, null, this.data);\n }\n return this.container;\n },\n });\n\n return HighlightAnnotationElement;\n})();\n\n/**\n * @class\n * @alias UnderlineAnnotationElement\n */\nvar UnderlineAnnotationElement = (\n function UnderlineAnnotationElementClosure() {\n function UnderlineAnnotationElement(parameters) {\n var isRenderable = !!(parameters.data.hasPopup ||\n parameters.data.title || parameters.data.contents);\n AnnotationElement.call(this, parameters, isRenderable,\n /* ignoreBorder = */ true);\n }\n\n Util.inherit(UnderlineAnnotationElement, AnnotationElement, {\n /**\n * Render the underline annotation's HTML element in the empty container.\n *\n * @public\n * @memberof UnderlineAnnotationElement\n * @returns {HTMLSectionElement}\n */\n render: function UnderlineAnnotationElement_render() {\n this.container.className = 'underlineAnnotation';\n\n if (!this.data.hasPopup) {\n this._createPopup(this.container, null, this.data);\n }\n return this.container;\n },\n });\n\n return UnderlineAnnotationElement;\n})();\n\n/**\n * @class\n * @alias SquigglyAnnotationElement\n */\nvar SquigglyAnnotationElement = (function SquigglyAnnotationElementClosure() {\n function SquigglyAnnotationElement(parameters) {\n var isRenderable = !!(parameters.data.hasPopup ||\n parameters.data.title || parameters.data.contents);\n AnnotationElement.call(this, parameters, isRenderable,\n /* ignoreBorder = */ true);\n }\n\n Util.inherit(SquigglyAnnotationElement, AnnotationElement, {\n /**\n * Render the squiggly annotation's HTML element in the empty container.\n *\n * @public\n * @memberof SquigglyAnnotationElement\n * @returns {HTMLSectionElement}\n */\n render: function SquigglyAnnotationElement_render() {\n this.container.className = 'squigglyAnnotation';\n\n if (!this.data.hasPopup) {\n this._createPopup(this.container, null, this.data);\n }\n return this.container;\n },\n });\n\n return SquigglyAnnotationElement;\n})();\n\n/**\n * @class\n * @alias StrikeOutAnnotationElement\n */\nvar StrikeOutAnnotationElement = (\n function StrikeOutAnnotationElementClosure() {\n function StrikeOutAnnotationElement(parameters) {\n var isRenderable = !!(parameters.data.hasPopup ||\n parameters.data.title || parameters.data.contents);\n AnnotationElement.call(this, parameters, isRenderable,\n /* ignoreBorder = */ true);\n }\n\n Util.inherit(StrikeOutAnnotationElement, AnnotationElement, {\n /**\n * Render the strikeout annotation's HTML element in the empty container.\n *\n * @public\n * @memberof StrikeOutAnnotationElement\n * @returns {HTMLSectionElement}\n */\n render: function StrikeOutAnnotationElement_render() {\n this.container.className = 'strikeoutAnnotation';\n\n if (!this.data.hasPopup) {\n this._createPopup(this.container, null, this.data);\n }\n return this.container;\n },\n });\n\n return StrikeOutAnnotationElement;\n})();\n\n/**\n * @class\n * @alias FileAttachmentAnnotationElement\n */\nvar FileAttachmentAnnotationElement = (\n function FileAttachmentAnnotationElementClosure() {\n function FileAttachmentAnnotationElement(parameters) {\n AnnotationElement.call(this, parameters, true);\n\n var file = this.data.file;\n this.filename = getFilenameFromUrl(file.filename);\n this.content = file.content;\n\n this.linkService.onFileAttachmentAnnotation({\n id: stringToPDFString(file.filename),\n filename: file.filename,\n content: file.content,\n });\n }\n\n Util.inherit(FileAttachmentAnnotationElement, AnnotationElement, {\n /**\n * Render the file attachment annotation's HTML element in the empty\n * container.\n *\n * @public\n * @memberof FileAttachmentAnnotationElement\n * @returns {HTMLSectionElement}\n */\n render: function FileAttachmentAnnotationElement_render() {\n this.container.className = 'fileAttachmentAnnotation';\n\n var trigger = document.createElement('div');\n trigger.style.height = this.container.style.height;\n trigger.style.width = this.container.style.width;\n trigger.addEventListener('dblclick', this._download.bind(this));\n\n if (!this.data.hasPopup && (this.data.title || this.data.contents)) {\n this._createPopup(this.container, trigger, this.data);\n }\n\n this.container.appendChild(trigger);\n return this.container;\n },\n\n /**\n * Download the file attachment associated with this annotation.\n *\n * @private\n * @memberof FileAttachmentAnnotationElement\n */\n _download: function FileAttachmentAnnotationElement_download() {\n if (!this.downloadManager) {\n warn('Download cannot be started due to unavailable download manager');\n return;\n }\n this.downloadManager.downloadData(this.content, this.filename, '');\n },\n });\n\n return FileAttachmentAnnotationElement;\n})();\n\n/**\n * @typedef {Object} AnnotationLayerParameters\n * @property {PageViewport} viewport\n * @property {HTMLDivElement} div\n * @property {Array} annotations\n * @property {PDFPage} page\n * @property {IPDFLinkService} linkService\n * @property {string} imageResourcesPath\n * @property {boolean} renderInteractiveForms\n */\n\n/**\n * @class\n * @alias AnnotationLayer\n */\nvar AnnotationLayer = (function AnnotationLayerClosure() {\n return {\n /**\n * Render a new annotation layer with all annotation elements.\n *\n * @public\n * @param {AnnotationLayerParameters} parameters\n * @memberof AnnotationLayer\n */\n render: function AnnotationLayer_render(parameters) {\n var annotationElementFactory = new AnnotationElementFactory();\n\n for (var i = 0, ii = parameters.annotations.length; i < ii; i++) {\n var data = parameters.annotations[i];\n if (!data) {\n continue;\n }\n var element = annotationElementFactory.create({\n data,\n layer: parameters.div,\n page: parameters.page,\n viewport: parameters.viewport,\n linkService: parameters.linkService,\n downloadManager: parameters.downloadManager,\n imageResourcesPath: parameters.imageResourcesPath ||\n getDefaultSetting('imageResourcesPath'),\n renderInteractiveForms: parameters.renderInteractiveForms || false,\n });\n if (element.isRenderable) {\n parameters.div.appendChild(element.render());\n }\n }\n },\n\n /**\n * Update the annotation elements on existing annotation layer.\n *\n * @public\n * @param {AnnotationLayerParameters} parameters\n * @memberof AnnotationLayer\n */\n update: function AnnotationLayer_update(parameters) {\n for (var i = 0, ii = parameters.annotations.length; i < ii; i++) {\n var data = parameters.annotations[i];\n var element = parameters.div.querySelector(\n '[data-annotation-id=\"' + data.id + '\"]');\n if (element) {\n CustomStyle.setProp('transform', element,\n 'matrix(' + parameters.viewport.transform.join(',') + ')');\n }\n }\n parameters.div.removeAttribute('hidden');\n },\n };\n})();\n\nexport {\n AnnotationLayer,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/display/annotation_layer.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* globals __non_webpack_require__ */\n\nimport {\n createObjectURL, FONT_IDENTITY_MATRIX, IDENTITY_MATRIX, ImageKind, isArray,\n isNodeJS, isNum, OPS, Util, warn\n} from '../shared/util';\n\nvar SVGGraphics = function() {\n throw new Error('Not implemented: SVGGraphics');\n};\n\nif (typeof PDFJSDev === 'undefined' ||\n PDFJSDev.test('GENERIC || SINGLE_FILE')) {\n\nvar SVG_DEFAULTS = {\n fontStyle: 'normal',\n fontWeight: 'normal',\n fillColor: '#000000',\n};\n\nvar convertImgDataToPng = (function convertImgDataToPngClosure() {\n var PNG_HEADER =\n new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);\n\n var CHUNK_WRAPPER_SIZE = 12;\n\n var crcTable = new Int32Array(256);\n for (var i = 0; i < 256; i++) {\n var c = i;\n for (var h = 0; h < 8; h++) {\n if (c & 1) {\n c = 0xedB88320 ^ ((c >> 1) & 0x7fffffff);\n } else {\n c = (c >> 1) & 0x7fffffff;\n }\n }\n crcTable[i] = c;\n }\n\n function crc32(data, start, end) {\n var crc = -1;\n for (var i = start; i < end; i++) {\n var a = (crc ^ data[i]) & 0xff;\n var b = crcTable[a];\n crc = (crc >>> 8) ^ b;\n }\n return crc ^ -1;\n }\n\n function writePngChunk(type, body, data, offset) {\n var p = offset;\n var len = body.length;\n\n data[p] = len >> 24 & 0xff;\n data[p + 1] = len >> 16 & 0xff;\n data[p + 2] = len >> 8 & 0xff;\n data[p + 3] = len & 0xff;\n p += 4;\n\n data[p] = type.charCodeAt(0) & 0xff;\n data[p + 1] = type.charCodeAt(1) & 0xff;\n data[p + 2] = type.charCodeAt(2) & 0xff;\n data[p + 3] = type.charCodeAt(3) & 0xff;\n p += 4;\n\n data.set(body, p);\n p += body.length;\n\n var crc = crc32(data, offset + 4, p);\n\n data[p] = crc >> 24 & 0xff;\n data[p + 1] = crc >> 16 & 0xff;\n data[p + 2] = crc >> 8 & 0xff;\n data[p + 3] = crc & 0xff;\n }\n\n function adler32(data, start, end) {\n var a = 1;\n var b = 0;\n for (var i = start; i < end; ++i) {\n a = (a + (data[i] & 0xff)) % 65521;\n b = (b + a) % 65521;\n }\n return (b << 16) | a;\n }\n\n /**\n * @param {Uint8Array} literals The input data.\n * @returns {Uint8Array} The DEFLATE-compressed data stream in zlib format.\n * This is the required format for compressed streams in the PNG format:\n * http://www.libpng.org/pub/png/spec/1.2/PNG-Compression.html\n */\n function deflateSync(literals) {\n if (!isNodeJS()) {\n // zlib is certainly not available outside of Node.js. We can either use\n // the pako library for client-side DEFLATE compression, or use the canvas\n // API of the browser to obtain a more optimal PNG file.\n return deflateSyncUncompressed(literals);\n }\n try {\n // NOTE: This implementation is far from perfect, but already way better\n // than not applying any compression.\n //\n // A better algorithm will try to choose a good predictor/filter and\n // then choose a suitable zlib compression strategy (e.g. 3,Z_RLE).\n //\n // Node v0.11.12 zlib.deflateSync is introduced (and returns a Buffer).\n // Node v3.0.0 Buffer inherits from Uint8Array.\n // Node v8.0.0 zlib.deflateSync accepts Uint8Array as input.\n var input;\n // eslint-disable-next-line no-undef\n if (parseInt(process.versions.node) >= 8) {\n input = literals;\n } else {\n // eslint-disable-next-line no-undef\n input = new Buffer(literals);\n }\n var output = __non_webpack_require__('zlib')\n .deflateSync(input, { level: 9, });\n return output instanceof Uint8Array ? output : new Uint8Array(output);\n } catch (e) {\n warn('Not compressing PNG because zlib.deflateSync is unavailable: ' + e);\n }\n\n return deflateSyncUncompressed(literals);\n }\n\n // An implementation of DEFLATE with compression level 0 (Z_NO_COMPRESSION).\n function deflateSyncUncompressed(literals) {\n var len = literals.length;\n var maxBlockLength = 0xFFFF;\n\n var deflateBlocks = Math.ceil(len / maxBlockLength);\n var idat = new Uint8Array(2 + len + deflateBlocks * 5 + 4);\n var pi = 0;\n idat[pi++] = 0x78; // compression method and flags\n idat[pi++] = 0x9c; // flags\n\n var pos = 0;\n while (len > maxBlockLength) {\n // writing non-final DEFLATE blocks type 0 and length of 65535\n idat[pi++] = 0x00;\n idat[pi++] = 0xff;\n idat[pi++] = 0xff;\n idat[pi++] = 0x00;\n idat[pi++] = 0x00;\n idat.set(literals.subarray(pos, pos + maxBlockLength), pi);\n pi += maxBlockLength;\n pos += maxBlockLength;\n len -= maxBlockLength;\n }\n\n // writing non-final DEFLATE blocks type 0\n idat[pi++] = 0x01;\n idat[pi++] = len & 0xff;\n idat[pi++] = len >> 8 & 0xff;\n idat[pi++] = (~len & 0xffff) & 0xff;\n idat[pi++] = (~len & 0xffff) >> 8 & 0xff;\n idat.set(literals.subarray(pos), pi);\n pi += literals.length - pos;\n\n var adler = adler32(literals, 0, literals.length); // checksum\n idat[pi++] = adler >> 24 & 0xff;\n idat[pi++] = adler >> 16 & 0xff;\n idat[pi++] = adler >> 8 & 0xff;\n idat[pi++] = adler & 0xff;\n return idat;\n }\n\n function encode(imgData, kind, forceDataSchema) {\n var width = imgData.width;\n var height = imgData.height;\n var bitDepth, colorType, lineSize;\n var bytes = imgData.data;\n\n switch (kind) {\n case ImageKind.GRAYSCALE_1BPP:\n colorType = 0;\n bitDepth = 1;\n lineSize = (width + 7) >> 3;\n break;\n case ImageKind.RGB_24BPP:\n colorType = 2;\n bitDepth = 8;\n lineSize = width * 3;\n break;\n case ImageKind.RGBA_32BPP:\n colorType = 6;\n bitDepth = 8;\n lineSize = width * 4;\n break;\n default:\n throw new Error('invalid format');\n }\n\n // prefix every row with predictor 0\n var literals = new Uint8Array((1 + lineSize) * height);\n var offsetLiterals = 0, offsetBytes = 0;\n var y, i;\n for (y = 0; y < height; ++y) {\n literals[offsetLiterals++] = 0; // no prediction\n literals.set(bytes.subarray(offsetBytes, offsetBytes + lineSize),\n offsetLiterals);\n offsetBytes += lineSize;\n offsetLiterals += lineSize;\n }\n\n if (kind === ImageKind.GRAYSCALE_1BPP) {\n // inverting for B/W\n offsetLiterals = 0;\n for (y = 0; y < height; y++) {\n offsetLiterals++; // skipping predictor\n for (i = 0; i < lineSize; i++) {\n literals[offsetLiterals++] ^= 0xFF;\n }\n }\n }\n\n var ihdr = new Uint8Array([\n width >> 24 & 0xff,\n width >> 16 & 0xff,\n width >> 8 & 0xff,\n width & 0xff,\n height >> 24 & 0xff,\n height >> 16 & 0xff,\n height >> 8 & 0xff,\n height & 0xff,\n bitDepth, // bit depth\n colorType, // color type\n 0x00, // compression method\n 0x00, // filter method\n 0x00 // interlace method\n ]);\n\n var idat = deflateSync(literals);\n\n // PNG will consists: header, IHDR+data, IDAT+data, and IEND.\n var pngLength = PNG_HEADER.length + (CHUNK_WRAPPER_SIZE * 3) +\n ihdr.length + idat.length;\n var data = new Uint8Array(pngLength);\n var offset = 0;\n data.set(PNG_HEADER, offset);\n offset += PNG_HEADER.length;\n writePngChunk('IHDR', ihdr, data, offset);\n offset += CHUNK_WRAPPER_SIZE + ihdr.length;\n writePngChunk('IDATA', idat, data, offset);\n offset += CHUNK_WRAPPER_SIZE + idat.length;\n writePngChunk('IEND', new Uint8Array(0), data, offset);\n\n return createObjectURL(data, 'image/png', forceDataSchema);\n }\n\n return function convertImgDataToPng(imgData, forceDataSchema) {\n var kind = (imgData.kind === undefined ?\n ImageKind.GRAYSCALE_1BPP : imgData.kind);\n return encode(imgData, kind, forceDataSchema);\n };\n})();\n\nvar SVGExtraState = (function SVGExtraStateClosure() {\n function SVGExtraState() {\n this.fontSizeScale = 1;\n this.fontWeight = SVG_DEFAULTS.fontWeight;\n this.fontSize = 0;\n\n this.textMatrix = IDENTITY_MATRIX;\n this.fontMatrix = FONT_IDENTITY_MATRIX;\n this.leading = 0;\n\n // Current point (in user coordinates)\n this.x = 0;\n this.y = 0;\n\n // Start of text line (in text coordinates)\n this.lineX = 0;\n this.lineY = 0;\n\n // Character and word spacing\n this.charSpacing = 0;\n this.wordSpacing = 0;\n this.textHScale = 1;\n this.textRise = 0;\n\n // Default foreground and background colors\n this.fillColor = SVG_DEFAULTS.fillColor;\n this.strokeColor = '#000000';\n\n this.fillAlpha = 1;\n this.strokeAlpha = 1;\n this.lineWidth = 1;\n this.lineJoin = '';\n this.lineCap = '';\n this.miterLimit = 0;\n\n this.dashArray = [];\n this.dashPhase = 0;\n\n this.dependencies = [];\n\n // Clipping\n this.activeClipUrl = null;\n this.clipGroup = null;\n\n this.maskId = '';\n }\n\n SVGExtraState.prototype = {\n clone: function SVGExtraState_clone() {\n return Object.create(this);\n },\n setCurrentPoint: function SVGExtraState_setCurrentPoint(x, y) {\n this.x = x;\n this.y = y;\n },\n };\n return SVGExtraState;\n})();\n\nSVGGraphics = (function SVGGraphicsClosure() {\n function opListToTree(opList) {\n var opTree = [];\n var tmp = [];\n var opListLen = opList.length;\n\n for (var x = 0; x < opListLen; x++) {\n if (opList[x].fn === 'save') {\n opTree.push({ 'fnId': 92, 'fn': 'group', 'items': [], });\n tmp.push(opTree);\n opTree = opTree[opTree.length - 1].items;\n continue;\n }\n\n if (opList[x].fn === 'restore') {\n opTree = tmp.pop();\n } else {\n opTree.push(opList[x]);\n }\n }\n return opTree;\n }\n\n /**\n * Formats float number.\n * @param value {number} number to format.\n * @returns {string}\n */\n function pf(value) {\n if (value === (value | 0)) { // integer number\n return value.toString();\n }\n var s = value.toFixed(10);\n var i = s.length - 1;\n if (s[i] !== '0') {\n return s;\n }\n // removing trailing zeros\n do {\n i--;\n } while (s[i] === '0');\n return s.substr(0, s[i] === '.' ? i : i + 1);\n }\n\n /**\n * Formats transform matrix. The standard rotation, scale and translate\n * matrices are replaced by their shorter forms, and for identity matrix\n * returns empty string to save the memory.\n * @param m {Array} matrix to format.\n * @returns {string}\n */\n function pm(m) {\n if (m[4] === 0 && m[5] === 0) {\n if (m[1] === 0 && m[2] === 0) {\n if (m[0] === 1 && m[3] === 1) {\n return '';\n }\n return 'scale(' + pf(m[0]) + ' ' + pf(m[3]) + ')';\n }\n if (m[0] === m[3] && m[1] === -m[2]) {\n var a = Math.acos(m[0]) * 180 / Math.PI;\n return 'rotate(' + pf(a) + ')';\n }\n } else {\n if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1) {\n return 'translate(' + pf(m[4]) + ' ' + pf(m[5]) + ')';\n }\n }\n return 'matrix(' + pf(m[0]) + ' ' + pf(m[1]) + ' ' + pf(m[2]) + ' ' +\n pf(m[3]) + ' ' + pf(m[4]) + ' ' + pf(m[5]) + ')';\n }\n\n function SVGGraphics(commonObjs, objs, forceDataSchema) {\n this.current = new SVGExtraState();\n this.transformMatrix = IDENTITY_MATRIX; // Graphics state matrix\n this.transformStack = [];\n this.extraStack = [];\n this.commonObjs = commonObjs;\n this.objs = objs;\n this.pendingClip = null;\n this.pendingEOFill = false;\n\n this.embedFonts = false;\n this.embeddedFonts = Object.create(null);\n this.cssStyle = null;\n this.forceDataSchema = !!forceDataSchema;\n }\n\n var NS = 'http://www.w3.org/2000/svg';\n var XML_NS = 'http://www.w3.org/XML/1998/namespace';\n var XLINK_NS = 'http://www.w3.org/1999/xlink';\n var LINE_CAP_STYLES = ['butt', 'round', 'square'];\n var LINE_JOIN_STYLES = ['miter', 'round', 'bevel'];\n var clipCount = 0;\n var maskCount = 0;\n\n SVGGraphics.prototype = {\n save: function SVGGraphics_save() {\n this.transformStack.push(this.transformMatrix);\n var old = this.current;\n this.extraStack.push(old);\n this.current = old.clone();\n },\n\n restore: function SVGGraphics_restore() {\n this.transformMatrix = this.transformStack.pop();\n this.current = this.extraStack.pop();\n\n this.pendingClip = null;\n this.tgrp = null;\n },\n\n group: function SVGGraphics_group(items) {\n this.save();\n this.executeOpTree(items);\n this.restore();\n },\n\n loadDependencies: function SVGGraphics_loadDependencies(operatorList) {\n var fnArray = operatorList.fnArray;\n var fnArrayLen = fnArray.length;\n var argsArray = operatorList.argsArray;\n\n for (var i = 0; i < fnArrayLen; i++) {\n if (OPS.dependency === fnArray[i]) {\n var deps = argsArray[i];\n for (var n = 0, nn = deps.length; n < nn; n++) {\n var obj = deps[n];\n var common = obj.substring(0, 2) === 'g_';\n var promise;\n if (common) {\n promise = new Promise((resolve) => {\n this.commonObjs.get(obj, resolve);\n });\n } else {\n promise = new Promise((resolve) => {\n this.objs.get(obj, resolve);\n });\n }\n this.current.dependencies.push(promise);\n }\n }\n }\n return Promise.all(this.current.dependencies);\n },\n\n transform: function SVGGraphics_transform(a, b, c, d, e, f) {\n var transformMatrix = [a, b, c, d, e, f];\n this.transformMatrix = Util.transform(this.transformMatrix,\n transformMatrix);\n this.tgrp = null;\n },\n\n getSVG: function SVGGraphics_getSVG(operatorList, viewport) {\n this.viewport = viewport;\n\n var svgElement = this._initialize(viewport);\n return this.loadDependencies(operatorList).then(() => {\n this.transformMatrix = IDENTITY_MATRIX;\n var opTree = this.convertOpList(operatorList);\n this.executeOpTree(opTree);\n return svgElement;\n });\n },\n\n convertOpList: function SVGGraphics_convertOpList(operatorList) {\n var argsArray = operatorList.argsArray;\n var fnArray = operatorList.fnArray;\n var fnArrayLen = fnArray.length;\n var REVOPS = [];\n var opList = [];\n\n for (var op in OPS) {\n REVOPS[OPS[op]] = op;\n }\n\n for (var x = 0; x < fnArrayLen; x++) {\n var fnId = fnArray[x];\n opList.push({\n 'fnId': fnId,\n 'fn': REVOPS[fnId],\n 'args': argsArray[x],\n });\n }\n return opListToTree(opList);\n },\n\n executeOpTree: function SVGGraphics_executeOpTree(opTree) {\n var opTreeLen = opTree.length;\n for (var x = 0; x < opTreeLen; x++) {\n var fn = opTree[x].fn;\n var fnId = opTree[x].fnId;\n var args = opTree[x].args;\n\n switch (fnId | 0) {\n case OPS.beginText:\n this.beginText();\n break;\n case OPS.setLeading:\n this.setLeading(args);\n break;\n case OPS.setLeadingMoveText:\n this.setLeadingMoveText(args[0], args[1]);\n break;\n case OPS.setFont:\n this.setFont(args);\n break;\n case OPS.showText:\n this.showText(args[0]);\n break;\n case OPS.showSpacedText:\n this.showText(args[0]);\n break;\n case OPS.endText:\n this.endText();\n break;\n case OPS.moveText:\n this.moveText(args[0], args[1]);\n break;\n case OPS.setCharSpacing:\n this.setCharSpacing(args[0]);\n break;\n case OPS.setWordSpacing:\n this.setWordSpacing(args[0]);\n break;\n case OPS.setHScale:\n this.setHScale(args[0]);\n break;\n case OPS.setTextMatrix:\n this.setTextMatrix(args[0], args[1], args[2],\n args[3], args[4], args[5]);\n break;\n case OPS.setLineWidth:\n this.setLineWidth(args[0]);\n break;\n case OPS.setLineJoin:\n this.setLineJoin(args[0]);\n break;\n case OPS.setLineCap:\n this.setLineCap(args[0]);\n break;\n case OPS.setMiterLimit:\n this.setMiterLimit(args[0]);\n break;\n case OPS.setFillRGBColor:\n this.setFillRGBColor(args[0], args[1], args[2]);\n break;\n case OPS.setStrokeRGBColor:\n this.setStrokeRGBColor(args[0], args[1], args[2]);\n break;\n case OPS.setDash:\n this.setDash(args[0], args[1]);\n break;\n case OPS.setGState:\n this.setGState(args[0]);\n break;\n case OPS.fill:\n this.fill();\n break;\n case OPS.eoFill:\n this.eoFill();\n break;\n case OPS.stroke:\n this.stroke();\n break;\n case OPS.fillStroke:\n this.fillStroke();\n break;\n case OPS.eoFillStroke:\n this.eoFillStroke();\n break;\n case OPS.clip:\n this.clip('nonzero');\n break;\n case OPS.eoClip:\n this.clip('evenodd');\n break;\n case OPS.paintSolidColorImageMask:\n this.paintSolidColorImageMask();\n break;\n case OPS.paintJpegXObject:\n this.paintJpegXObject(args[0], args[1], args[2]);\n break;\n case OPS.paintImageXObject:\n this.paintImageXObject(args[0]);\n break;\n case OPS.paintInlineImageXObject:\n this.paintInlineImageXObject(args[0]);\n break;\n case OPS.paintImageMaskXObject:\n this.paintImageMaskXObject(args[0]);\n break;\n case OPS.paintFormXObjectBegin:\n this.paintFormXObjectBegin(args[0], args[1]);\n break;\n case OPS.paintFormXObjectEnd:\n this.paintFormXObjectEnd();\n break;\n case OPS.closePath:\n this.closePath();\n break;\n case OPS.closeStroke:\n this.closeStroke();\n break;\n case OPS.closeFillStroke:\n this.closeFillStroke();\n break;\n case OPS.nextLine:\n this.nextLine();\n break;\n case OPS.transform:\n this.transform(args[0], args[1], args[2], args[3],\n args[4], args[5]);\n break;\n case OPS.constructPath:\n this.constructPath(args[0], args[1]);\n break;\n case OPS.endPath:\n this.endPath();\n break;\n case 92:\n this.group(opTree[x].items);\n break;\n default:\n warn('Unimplemented operator ' + fn);\n break;\n }\n }\n },\n\n setWordSpacing: function SVGGraphics_setWordSpacing(wordSpacing) {\n this.current.wordSpacing = wordSpacing;\n },\n\n setCharSpacing: function SVGGraphics_setCharSpacing(charSpacing) {\n this.current.charSpacing = charSpacing;\n },\n\n nextLine: function SVGGraphics_nextLine() {\n this.moveText(0, this.current.leading);\n },\n\n setTextMatrix: function SVGGraphics_setTextMatrix(a, b, c, d, e, f) {\n var current = this.current;\n this.current.textMatrix = this.current.lineMatrix = [a, b, c, d, e, f];\n\n this.current.x = this.current.lineX = 0;\n this.current.y = this.current.lineY = 0;\n\n current.xcoords = [];\n current.tspan = document.createElementNS(NS, 'svg:tspan');\n current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);\n current.tspan.setAttributeNS(null, 'font-size',\n pf(current.fontSize) + 'px');\n current.tspan.setAttributeNS(null, 'y', pf(-current.y));\n\n current.txtElement = document.createElementNS(NS, 'svg:text');\n current.txtElement.appendChild(current.tspan);\n },\n\n beginText: function SVGGraphics_beginText() {\n this.current.x = this.current.lineX = 0;\n this.current.y = this.current.lineY = 0;\n this.current.textMatrix = IDENTITY_MATRIX;\n this.current.lineMatrix = IDENTITY_MATRIX;\n this.current.tspan = document.createElementNS(NS, 'svg:tspan');\n this.current.txtElement = document.createElementNS(NS, 'svg:text');\n this.current.txtgrp = document.createElementNS(NS, 'svg:g');\n this.current.xcoords = [];\n },\n\n moveText: function SVGGraphics_moveText(x, y) {\n var current = this.current;\n this.current.x = this.current.lineX += x;\n this.current.y = this.current.lineY += y;\n\n current.xcoords = [];\n current.tspan = document.createElementNS(NS, 'svg:tspan');\n current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);\n current.tspan.setAttributeNS(null, 'font-size',\n pf(current.fontSize) + 'px');\n current.tspan.setAttributeNS(null, 'y', pf(-current.y));\n },\n\n showText: function SVGGraphics_showText(glyphs) {\n var current = this.current;\n var font = current.font;\n var fontSize = current.fontSize;\n\n if (fontSize === 0) {\n return;\n }\n\n var charSpacing = current.charSpacing;\n var wordSpacing = current.wordSpacing;\n var fontDirection = current.fontDirection;\n var textHScale = current.textHScale * fontDirection;\n var glyphsLength = glyphs.length;\n var vertical = font.vertical;\n var widthAdvanceScale = fontSize * current.fontMatrix[0];\n\n var x = 0, i;\n for (i = 0; i < glyphsLength; ++i) {\n var glyph = glyphs[i];\n if (glyph === null) {\n // word break\n x += fontDirection * wordSpacing;\n continue;\n } else if (isNum(glyph)) {\n x += -glyph * fontSize * 0.001;\n continue;\n }\n current.xcoords.push(current.x + x * textHScale);\n\n var width = glyph.width;\n var character = glyph.fontChar;\n var spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;\n var charWidth = width * widthAdvanceScale + spacing * fontDirection;\n x += charWidth;\n\n current.tspan.textContent += character;\n }\n if (vertical) {\n current.y -= x * textHScale;\n } else {\n current.x += x * textHScale;\n }\n\n current.tspan.setAttributeNS(null, 'x',\n current.xcoords.map(pf).join(' '));\n current.tspan.setAttributeNS(null, 'y', pf(-current.y));\n current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);\n current.tspan.setAttributeNS(null, 'font-size',\n pf(current.fontSize) + 'px');\n if (current.fontStyle !== SVG_DEFAULTS.fontStyle) {\n current.tspan.setAttributeNS(null, 'font-style', current.fontStyle);\n }\n if (current.fontWeight !== SVG_DEFAULTS.fontWeight) {\n current.tspan.setAttributeNS(null, 'font-weight', current.fontWeight);\n }\n if (current.fillColor !== SVG_DEFAULTS.fillColor) {\n current.tspan.setAttributeNS(null, 'fill', current.fillColor);\n }\n\n current.txtElement.setAttributeNS(null, 'transform',\n pm(current.textMatrix) +\n ' scale(1, -1)');\n current.txtElement.setAttributeNS(XML_NS, 'xml:space', 'preserve');\n current.txtElement.appendChild(current.tspan);\n current.txtgrp.appendChild(current.txtElement);\n\n this._ensureTransformGroup().appendChild(current.txtElement);\n },\n\n setLeadingMoveText: function SVGGraphics_setLeadingMoveText(x, y) {\n this.setLeading(-y);\n this.moveText(x, y);\n },\n\n addFontStyle: function SVGGraphics_addFontStyle(fontObj) {\n if (!this.cssStyle) {\n this.cssStyle = document.createElementNS(NS, 'svg:style');\n this.cssStyle.setAttributeNS(null, 'type', 'text/css');\n this.defs.appendChild(this.cssStyle);\n }\n\n var url = createObjectURL(fontObj.data, fontObj.mimetype,\n this.forceDataSchema);\n this.cssStyle.textContent +=\n '@font-face { font-family: \"' + fontObj.loadedName + '\";' +\n ' src: url(' + url + '); }\\n';\n },\n\n setFont: function SVGGraphics_setFont(details) {\n var current = this.current;\n var fontObj = this.commonObjs.get(details[0]);\n var size = details[1];\n this.current.font = fontObj;\n\n if (this.embedFonts && fontObj.data &&\n !this.embeddedFonts[fontObj.loadedName]) {\n this.addFontStyle(fontObj);\n this.embeddedFonts[fontObj.loadedName] = fontObj;\n }\n\n current.fontMatrix = (fontObj.fontMatrix ?\n fontObj.fontMatrix : FONT_IDENTITY_MATRIX);\n\n var bold = fontObj.black ? (fontObj.bold ? 'bolder' : 'bold') :\n (fontObj.bold ? 'bold' : 'normal');\n var italic = fontObj.italic ? 'italic' : 'normal';\n\n if (size < 0) {\n size = -size;\n current.fontDirection = -1;\n } else {\n current.fontDirection = 1;\n }\n current.fontSize = size;\n current.fontFamily = fontObj.loadedName;\n current.fontWeight = bold;\n current.fontStyle = italic;\n\n current.tspan = document.createElementNS(NS, 'svg:tspan');\n current.tspan.setAttributeNS(null, 'y', pf(-current.y));\n current.xcoords = [];\n },\n\n endText: function SVGGraphics_endText() {},\n\n // Path properties\n setLineWidth: function SVGGraphics_setLineWidth(width) {\n this.current.lineWidth = width;\n },\n setLineCap: function SVGGraphics_setLineCap(style) {\n this.current.lineCap = LINE_CAP_STYLES[style];\n },\n setLineJoin: function SVGGraphics_setLineJoin(style) {\n this.current.lineJoin = LINE_JOIN_STYLES[style];\n },\n setMiterLimit: function SVGGraphics_setMiterLimit(limit) {\n this.current.miterLimit = limit;\n },\n setStrokeAlpha: function SVGGraphics_setStrokeAlpha(strokeAlpha) {\n this.current.strokeAlpha = strokeAlpha;\n },\n setStrokeRGBColor: function SVGGraphics_setStrokeRGBColor(r, g, b) {\n var color = Util.makeCssRgb(r, g, b);\n this.current.strokeColor = color;\n },\n setFillAlpha: function SVGGraphics_setFillAlpha(fillAlpha) {\n this.current.fillAlpha = fillAlpha;\n },\n setFillRGBColor: function SVGGraphics_setFillRGBColor(r, g, b) {\n var color = Util.makeCssRgb(r, g, b);\n this.current.fillColor = color;\n this.current.tspan = document.createElementNS(NS, 'svg:tspan');\n this.current.xcoords = [];\n },\n setDash: function SVGGraphics_setDash(dashArray, dashPhase) {\n this.current.dashArray = dashArray;\n this.current.dashPhase = dashPhase;\n },\n\n constructPath: function SVGGraphics_constructPath(ops, args) {\n var current = this.current;\n var x = current.x, y = current.y;\n current.path = document.createElementNS(NS, 'svg:path');\n var d = [];\n var opLength = ops.length;\n\n for (var i = 0, j = 0; i < opLength; i++) {\n switch (ops[i] | 0) {\n case OPS.rectangle:\n x = args[j++];\n y = args[j++];\n var width = args[j++];\n var height = args[j++];\n var xw = x + width;\n var yh = y + height;\n d.push('M', pf(x), pf(y), 'L', pf(xw), pf(y), 'L', pf(xw), pf(yh),\n 'L', pf(x), pf(yh), 'Z');\n break;\n case OPS.moveTo:\n x = args[j++];\n y = args[j++];\n d.push('M', pf(x), pf(y));\n break;\n case OPS.lineTo:\n x = args[j++];\n y = args[j++];\n d.push('L', pf(x), pf(y));\n break;\n case OPS.curveTo:\n x = args[j + 4];\n y = args[j + 5];\n d.push('C', pf(args[j]), pf(args[j + 1]), pf(args[j + 2]),\n pf(args[j + 3]), pf(x), pf(y));\n j += 6;\n break;\n case OPS.curveTo2:\n x = args[j + 2];\n y = args[j + 3];\n d.push('C', pf(x), pf(y), pf(args[j]), pf(args[j + 1]),\n pf(args[j + 2]), pf(args[j + 3]));\n j += 4;\n break;\n case OPS.curveTo3:\n x = args[j + 2];\n y = args[j + 3];\n d.push('C', pf(args[j]), pf(args[j + 1]), pf(x), pf(y),\n pf(x), pf(y));\n j += 4;\n break;\n case OPS.closePath:\n d.push('Z');\n break;\n }\n }\n current.path.setAttributeNS(null, 'd', d.join(' '));\n current.path.setAttributeNS(null, 'fill', 'none');\n\n this._ensureTransformGroup().appendChild(current.path);\n\n // Saving a reference in current.element so that it can be addressed\n // in 'fill' and 'stroke'\n current.element = current.path;\n current.setCurrentPoint(x, y);\n },\n\n endPath: function SVGGraphics_endPath() {\n if (!this.pendingClip) {\n return;\n }\n var current = this.current;\n // Add current path to clipping path\n var clipId = 'clippath' + clipCount;\n clipCount++;\n var clipPath = document.createElementNS(NS, 'svg:clipPath');\n clipPath.setAttributeNS(null, 'id', clipId);\n clipPath.setAttributeNS(null, 'transform', pm(this.transformMatrix));\n var clipElement = current.element.cloneNode();\n if (this.pendingClip === 'evenodd') {\n clipElement.setAttributeNS(null, 'clip-rule', 'evenodd');\n } else {\n clipElement.setAttributeNS(null, 'clip-rule', 'nonzero');\n }\n this.pendingClip = null;\n clipPath.appendChild(clipElement);\n this.defs.appendChild(clipPath);\n\n if (current.activeClipUrl) {\n // The previous clipping group content can go out of order -- resetting\n // cached clipGroups.\n current.clipGroup = null;\n this.extraStack.forEach(function (prev) {\n prev.clipGroup = null;\n });\n }\n current.activeClipUrl = 'url(#' + clipId + ')';\n\n this.tgrp = null;\n },\n\n clip: function SVGGraphics_clip(type) {\n this.pendingClip = type;\n },\n\n closePath: function SVGGraphics_closePath() {\n var current = this.current;\n var d = current.path.getAttributeNS(null, 'd');\n d += 'Z';\n current.path.setAttributeNS(null, 'd', d);\n },\n\n setLeading: function SVGGraphics_setLeading(leading) {\n this.current.leading = -leading;\n },\n\n setTextRise: function SVGGraphics_setTextRise(textRise) {\n this.current.textRise = textRise;\n },\n\n setHScale: function SVGGraphics_setHScale(scale) {\n this.current.textHScale = scale / 100;\n },\n\n setGState: function SVGGraphics_setGState(states) {\n for (var i = 0, ii = states.length; i < ii; i++) {\n var state = states[i];\n var key = state[0];\n var value = state[1];\n\n switch (key) {\n case 'LW':\n this.setLineWidth(value);\n break;\n case 'LC':\n this.setLineCap(value);\n break;\n case 'LJ':\n this.setLineJoin(value);\n break;\n case 'ML':\n this.setMiterLimit(value);\n break;\n case 'D':\n this.setDash(value[0], value[1]);\n break;\n case 'Font':\n this.setFont(value);\n break;\n case 'CA':\n this.setStrokeAlpha(value);\n break;\n case 'ca':\n this.setFillAlpha(value);\n break;\n default:\n warn('Unimplemented graphic state ' + key);\n break;\n }\n }\n },\n\n fill: function SVGGraphics_fill() {\n var current = this.current;\n current.element.setAttributeNS(null, 'fill', current.fillColor);\n current.element.setAttributeNS(null, 'fill-opacity', current.fillAlpha);\n },\n\n stroke: function SVGGraphics_stroke() {\n var current = this.current;\n\n current.element.setAttributeNS(null, 'stroke', current.strokeColor);\n current.element.setAttributeNS(null, 'stroke-opacity',\n current.strokeAlpha);\n current.element.setAttributeNS(null, 'stroke-miterlimit',\n pf(current.miterLimit));\n current.element.setAttributeNS(null, 'stroke-linecap', current.lineCap);\n current.element.setAttributeNS(null, 'stroke-linejoin', current.lineJoin);\n current.element.setAttributeNS(null, 'stroke-width',\n pf(current.lineWidth) + 'px');\n current.element.setAttributeNS(null, 'stroke-dasharray',\n current.dashArray.map(pf).join(' '));\n current.element.setAttributeNS(null, 'stroke-dashoffset',\n pf(current.dashPhase) + 'px');\n\n current.element.setAttributeNS(null, 'fill', 'none');\n },\n\n eoFill: function SVGGraphics_eoFill() {\n this.current.element.setAttributeNS(null, 'fill-rule', 'evenodd');\n this.fill();\n },\n\n fillStroke: function SVGGraphics_fillStroke() {\n // Order is important since stroke wants fill to be none.\n // First stroke, then if fill needed, it will be overwritten.\n this.stroke();\n this.fill();\n },\n\n eoFillStroke: function SVGGraphics_eoFillStroke() {\n this.current.element.setAttributeNS(null, 'fill-rule', 'evenodd');\n this.fillStroke();\n },\n\n closeStroke: function SVGGraphics_closeStroke() {\n this.closePath();\n this.stroke();\n },\n\n closeFillStroke: function SVGGraphics_closeFillStroke() {\n this.closePath();\n this.fillStroke();\n },\n\n paintSolidColorImageMask:\n function SVGGraphics_paintSolidColorImageMask() {\n var current = this.current;\n var rect = document.createElementNS(NS, 'svg:rect');\n rect.setAttributeNS(null, 'x', '0');\n rect.setAttributeNS(null, 'y', '0');\n rect.setAttributeNS(null, 'width', '1px');\n rect.setAttributeNS(null, 'height', '1px');\n rect.setAttributeNS(null, 'fill', current.fillColor);\n\n this._ensureTransformGroup().appendChild(rect);\n },\n\n paintJpegXObject: function SVGGraphics_paintJpegXObject(objId, w, h) {\n var imgObj = this.objs.get(objId);\n var imgEl = document.createElementNS(NS, 'svg:image');\n imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgObj.src);\n imgEl.setAttributeNS(null, 'width', pf(w));\n imgEl.setAttributeNS(null, 'height', pf(h));\n imgEl.setAttributeNS(null, 'x', '0');\n imgEl.setAttributeNS(null, 'y', pf(-h));\n imgEl.setAttributeNS(null, 'transform',\n 'scale(' + pf(1 / w) + ' ' + pf(-1 / h) + ')');\n\n this._ensureTransformGroup().appendChild(imgEl);\n },\n\n paintImageXObject: function SVGGraphics_paintImageXObject(objId) {\n var imgData = this.objs.get(objId);\n if (!imgData) {\n warn('Dependent image isn\\'t ready yet');\n return;\n }\n this.paintInlineImageXObject(imgData);\n },\n\n paintInlineImageXObject:\n function SVGGraphics_paintInlineImageXObject(imgData, mask) {\n var width = imgData.width;\n var height = imgData.height;\n\n var imgSrc = convertImgDataToPng(imgData, this.forceDataSchema);\n var cliprect = document.createElementNS(NS, 'svg:rect');\n cliprect.setAttributeNS(null, 'x', '0');\n cliprect.setAttributeNS(null, 'y', '0');\n cliprect.setAttributeNS(null, 'width', pf(width));\n cliprect.setAttributeNS(null, 'height', pf(height));\n this.current.element = cliprect;\n this.clip('nonzero');\n var imgEl = document.createElementNS(NS, 'svg:image');\n imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgSrc);\n imgEl.setAttributeNS(null, 'x', '0');\n imgEl.setAttributeNS(null, 'y', pf(-height));\n imgEl.setAttributeNS(null, 'width', pf(width) + 'px');\n imgEl.setAttributeNS(null, 'height', pf(height) + 'px');\n imgEl.setAttributeNS(null, 'transform',\n 'scale(' + pf(1 / width) + ' ' +\n pf(-1 / height) + ')');\n if (mask) {\n mask.appendChild(imgEl);\n } else {\n this._ensureTransformGroup().appendChild(imgEl);\n }\n },\n\n paintImageMaskXObject:\n function SVGGraphics_paintImageMaskXObject(imgData) {\n var current = this.current;\n var width = imgData.width;\n var height = imgData.height;\n var fillColor = current.fillColor;\n\n current.maskId = 'mask' + maskCount++;\n var mask = document.createElementNS(NS, 'svg:mask');\n mask.setAttributeNS(null, 'id', current.maskId);\n\n var rect = document.createElementNS(NS, 'svg:rect');\n rect.setAttributeNS(null, 'x', '0');\n rect.setAttributeNS(null, 'y', '0');\n rect.setAttributeNS(null, 'width', pf(width));\n rect.setAttributeNS(null, 'height', pf(height));\n rect.setAttributeNS(null, 'fill', fillColor);\n rect.setAttributeNS(null, 'mask', 'url(#' + current.maskId + ')');\n this.defs.appendChild(mask);\n\n this._ensureTransformGroup().appendChild(rect);\n\n this.paintInlineImageXObject(imgData, mask);\n },\n\n paintFormXObjectBegin:\n function SVGGraphics_paintFormXObjectBegin(matrix, bbox) {\n if (isArray(matrix) && matrix.length === 6) {\n this.transform(matrix[0], matrix[1], matrix[2],\n matrix[3], matrix[4], matrix[5]);\n }\n\n if (isArray(bbox) && bbox.length === 4) {\n var width = bbox[2] - bbox[0];\n var height = bbox[3] - bbox[1];\n\n var cliprect = document.createElementNS(NS, 'svg:rect');\n cliprect.setAttributeNS(null, 'x', bbox[0]);\n cliprect.setAttributeNS(null, 'y', bbox[1]);\n cliprect.setAttributeNS(null, 'width', pf(width));\n cliprect.setAttributeNS(null, 'height', pf(height));\n this.current.element = cliprect;\n this.clip('nonzero');\n this.endPath();\n }\n },\n\n paintFormXObjectEnd:\n function SVGGraphics_paintFormXObjectEnd() {},\n\n /**\n * @private\n */\n _initialize: function SVGGraphics_initialize(viewport) {\n // Create the SVG element.\n var svg = document.createElementNS(NS, 'svg:svg');\n svg.setAttributeNS(null, 'version', '1.1');\n svg.setAttributeNS(null, 'width', viewport.width + 'px');\n svg.setAttributeNS(null, 'height', viewport.height + 'px');\n svg.setAttributeNS(null, 'preserveAspectRatio', 'none');\n svg.setAttributeNS(null, 'viewBox', '0 0 ' + viewport.width +\n ' ' + viewport.height);\n\n // Create the definitions element.\n var definitions = document.createElementNS(NS, 'svg:defs');\n svg.appendChild(definitions);\n this.defs = definitions;\n\n // Create the root group element, which acts a container for all other\n // groups and applies the viewport transform.\n var rootGroup = document.createElementNS(NS, 'svg:g');\n rootGroup.setAttributeNS(null, 'transform', pm(viewport.transform));\n svg.appendChild(rootGroup);\n\n // For the construction of the SVG image we are only interested in the\n // root group, so we expose it as the entry point of the SVG image for\n // the other code in this class.\n this.svg = rootGroup;\n\n return svg;\n },\n\n /**\n * @private\n */\n _ensureClipGroup: function SVGGraphics_ensureClipGroup() {\n if (!this.current.clipGroup) {\n var clipGroup = document.createElementNS(NS, 'svg:g');\n clipGroup.setAttributeNS(null, 'clip-path',\n this.current.activeClipUrl);\n this.svg.appendChild(clipGroup);\n this.current.clipGroup = clipGroup;\n }\n return this.current.clipGroup;\n },\n\n /**\n * @private\n */\n _ensureTransformGroup: function SVGGraphics_ensureTransformGroup() {\n if (!this.tgrp) {\n this.tgrp = document.createElementNS(NS, 'svg:g');\n this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix));\n if (this.current.activeClipUrl) {\n this._ensureClipGroup().appendChild(this.tgrp);\n } else {\n this.svg.appendChild(this.tgrp);\n }\n }\n return this.tgrp;\n },\n };\n return SVGGraphics;\n})();\n\n}\n\nexport {\n SVGGraphics,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/display/svg.js", + "/* Copyright 2015 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AbortException, createPromiseCapability, Util } from '../shared/util';\nimport { CustomStyle, getDefaultSetting } from './dom_utils';\n\n/**\n * Text layer render parameters.\n *\n * @typedef {Object} TextLayerRenderParameters\n * @property {TextContent} textContent - (optional) Text content to render\n * (the object is returned by the page's getTextContent() method).\n * @property {ReadableStream} textContentStream - (optional) Text content\n * stream to render (the stream is returned by the page's\n * streamTextContent() method).\n * @property {HTMLElement} container - HTML element that will contain text runs.\n * @property {PageViewport} viewport - The target viewport to properly\n * layout the text runs.\n * @property {Array} textDivs - (optional) HTML elements that are correspond\n * the text items of the textContent input. This is output and shall be\n * initially be set to empty array.\n * @property {Array} textContentItemsStr - (optional) Strings that correspond\n * the `str` property of the text items of textContent input. This is output\n * and shall be initially be set to empty array.\n * @property {number} timeout - (optional) Delay in milliseconds before\n * rendering of the text runs occurs.\n * @property {boolean} enhanceTextSelection - (optional) Whether to turn on the\n * text selection enhancement.\n */\nvar renderTextLayer = (function renderTextLayerClosure() {\n var MAX_TEXT_DIVS_TO_RENDER = 100000;\n\n var NonWhitespaceRegexp = /\\S/;\n\n function isAllWhitespace(str) {\n return !NonWhitespaceRegexp.test(str);\n }\n\n // Text layers may contain many thousand div's, and using `styleBuf` avoids\n // creating many intermediate strings when building their 'style' properties.\n var styleBuf = ['left: ', 0, 'px; top: ', 0, 'px; font-size: ', 0,\n 'px; font-family: ', '', ';'];\n\n function appendText(task, geom, styles) {\n // Initialize all used properties to keep the caches monomorphic.\n var textDiv = document.createElement('div');\n var textDivProperties = {\n style: null,\n angle: 0,\n canvasWidth: 0,\n isWhitespace: false,\n originalTransform: null,\n paddingBottom: 0,\n paddingLeft: 0,\n paddingRight: 0,\n paddingTop: 0,\n scale: 1,\n };\n\n task._textDivs.push(textDiv);\n if (isAllWhitespace(geom.str)) {\n textDivProperties.isWhitespace = true;\n task._textDivProperties.set(textDiv, textDivProperties);\n return;\n }\n\n var tx = Util.transform(task._viewport.transform, geom.transform);\n var angle = Math.atan2(tx[1], tx[0]);\n var style = styles[geom.fontName];\n if (style.vertical) {\n angle += Math.PI / 2;\n }\n var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));\n var fontAscent = fontHeight;\n if (style.ascent) {\n fontAscent = style.ascent * fontAscent;\n } else if (style.descent) {\n fontAscent = (1 + style.descent) * fontAscent;\n }\n\n var left;\n var top;\n if (angle === 0) {\n left = tx[4];\n top = tx[5] - fontAscent;\n } else {\n left = tx[4] + (fontAscent * Math.sin(angle));\n top = tx[5] - (fontAscent * Math.cos(angle));\n }\n styleBuf[1] = left;\n styleBuf[3] = top;\n styleBuf[5] = fontHeight;\n styleBuf[7] = style.fontFamily;\n textDivProperties.style = styleBuf.join('');\n textDiv.setAttribute('style', textDivProperties.style);\n\n textDiv.textContent = geom.str;\n // |fontName| is only used by the Font Inspector. This test will succeed\n // when e.g. the Font Inspector is off but the Stepper is on, but it's\n // not worth the effort to do a more accurate test. We only use `dataset`\n // here to make the font name available for the debugger.\n if (getDefaultSetting('pdfBug')) {\n textDiv.dataset.fontName = geom.fontName;\n }\n if (angle !== 0) {\n textDivProperties.angle = angle * (180 / Math.PI);\n }\n // We don't bother scaling single-char text divs, because it has very\n // little effect on text highlighting. This makes scrolling on docs with\n // lots of such divs a lot faster.\n if (geom.str.length > 1) {\n if (style.vertical) {\n textDivProperties.canvasWidth = geom.height * task._viewport.scale;\n } else {\n textDivProperties.canvasWidth = geom.width * task._viewport.scale;\n }\n }\n task._textDivProperties.set(textDiv, textDivProperties);\n if (task._textContentStream) {\n task._layoutText(textDiv);\n }\n\n if (task._enhanceTextSelection) {\n var angleCos = 1, angleSin = 0;\n if (angle !== 0) {\n angleCos = Math.cos(angle);\n angleSin = Math.sin(angle);\n }\n var divWidth = (style.vertical ? geom.height : geom.width) *\n task._viewport.scale;\n var divHeight = fontHeight;\n\n var m, b;\n if (angle !== 0) {\n m = [angleCos, angleSin, -angleSin, angleCos, left, top];\n b = Util.getAxialAlignedBoundingBox([0, 0, divWidth, divHeight], m);\n } else {\n b = [left, top, left + divWidth, top + divHeight];\n }\n\n task._bounds.push({\n left: b[0],\n top: b[1],\n right: b[2],\n bottom: b[3],\n div: textDiv,\n size: [divWidth, divHeight],\n m,\n });\n }\n }\n\n function render(task) {\n if (task._canceled) {\n return;\n }\n var textDivs = task._textDivs;\n var capability = task._capability;\n var textDivsLength = textDivs.length;\n\n // No point in rendering many divs as it would make the browser\n // unusable even after the divs are rendered.\n if (textDivsLength > MAX_TEXT_DIVS_TO_RENDER) {\n task._renderingDone = true;\n capability.resolve();\n return;\n }\n\n if (!task._textContentStream) {\n for (var i = 0; i < textDivsLength; i++) {\n task._layoutText(textDivs[i]);\n }\n }\n\n task._renderingDone = true;\n capability.resolve();\n }\n\n function expand(task) {\n var bounds = task._bounds;\n var viewport = task._viewport;\n\n var expanded = expandBounds(viewport.width, viewport.height, bounds);\n for (var i = 0; i < expanded.length; i++) {\n var div = bounds[i].div;\n var divProperties = task._textDivProperties.get(div);\n if (divProperties.angle === 0) {\n divProperties.paddingLeft = bounds[i].left - expanded[i].left;\n divProperties.paddingTop = bounds[i].top - expanded[i].top;\n divProperties.paddingRight = expanded[i].right - bounds[i].right;\n divProperties.paddingBottom = expanded[i].bottom - bounds[i].bottom;\n task._textDivProperties.set(div, divProperties);\n continue;\n }\n // Box is rotated -- trying to find padding so rotated div will not\n // exceed its expanded bounds.\n var e = expanded[i], b = bounds[i];\n var m = b.m, c = m[0], s = m[1];\n // Finding intersections with expanded box.\n var points = [[0, 0], [0, b.size[1]], [b.size[0], 0], b.size];\n var ts = new Float64Array(64);\n points.forEach(function (p, i) {\n var t = Util.applyTransform(p, m);\n ts[i + 0] = c && (e.left - t[0]) / c;\n ts[i + 4] = s && (e.top - t[1]) / s;\n ts[i + 8] = c && (e.right - t[0]) / c;\n ts[i + 12] = s && (e.bottom - t[1]) / s;\n\n ts[i + 16] = s && (e.left - t[0]) / -s;\n ts[i + 20] = c && (e.top - t[1]) / c;\n ts[i + 24] = s && (e.right - t[0]) / -s;\n ts[i + 28] = c && (e.bottom - t[1]) / c;\n\n ts[i + 32] = c && (e.left - t[0]) / -c;\n ts[i + 36] = s && (e.top - t[1]) / -s;\n ts[i + 40] = c && (e.right - t[0]) / -c;\n ts[i + 44] = s && (e.bottom - t[1]) / -s;\n\n ts[i + 48] = s && (e.left - t[0]) / s;\n ts[i + 52] = c && (e.top - t[1]) / -c;\n ts[i + 56] = s && (e.right - t[0]) / s;\n ts[i + 60] = c && (e.bottom - t[1]) / -c;\n });\n var findPositiveMin = function (ts, offset, count) {\n var result = 0;\n for (var i = 0; i < count; i++) {\n var t = ts[offset++];\n if (t > 0) {\n result = result ? Math.min(t, result) : t;\n }\n }\n return result;\n };\n // Not based on math, but to simplify calculations, using cos and sin\n // absolute values to not exceed the box (it can but insignificantly).\n var boxScale = 1 + Math.min(Math.abs(c), Math.abs(s));\n divProperties.paddingLeft = findPositiveMin(ts, 32, 16) / boxScale;\n divProperties.paddingTop = findPositiveMin(ts, 48, 16) / boxScale;\n divProperties.paddingRight = findPositiveMin(ts, 0, 16) / boxScale;\n divProperties.paddingBottom = findPositiveMin(ts, 16, 16) / boxScale;\n task._textDivProperties.set(div, divProperties);\n }\n }\n\n function expandBounds(width, height, boxes) {\n var bounds = boxes.map(function (box, i) {\n return {\n x1: box.left,\n y1: box.top,\n x2: box.right,\n y2: box.bottom,\n index: i,\n x1New: undefined,\n x2New: undefined,\n };\n });\n expandBoundsLTR(width, bounds);\n var expanded = new Array(boxes.length);\n bounds.forEach(function (b) {\n var i = b.index;\n expanded[i] = {\n left: b.x1New,\n top: 0,\n right: b.x2New,\n bottom: 0,\n };\n });\n\n // Rotating on 90 degrees and extending extended boxes. Reusing the bounds\n // array and objects.\n boxes.map(function (box, i) {\n var e = expanded[i], b = bounds[i];\n b.x1 = box.top;\n b.y1 = width - e.right;\n b.x2 = box.bottom;\n b.y2 = width - e.left;\n b.index = i;\n b.x1New = undefined;\n b.x2New = undefined;\n });\n expandBoundsLTR(height, bounds);\n\n bounds.forEach(function (b) {\n var i = b.index;\n expanded[i].top = b.x1New;\n expanded[i].bottom = b.x2New;\n });\n return expanded;\n }\n\n function expandBoundsLTR(width, bounds) {\n // Sorting by x1 coordinate and walk by the bounds in the same order.\n bounds.sort(function (a, b) {\n return a.x1 - b.x1 || a.index - b.index;\n });\n\n // First we see on the horizon is a fake boundary.\n var fakeBoundary = {\n x1: -Infinity,\n y1: -Infinity,\n x2: 0,\n y2: Infinity,\n index: -1,\n x1New: 0,\n x2New: 0,\n };\n var horizon = [{\n start: -Infinity,\n end: Infinity,\n boundary: fakeBoundary,\n }];\n\n bounds.forEach(function (boundary) {\n // Searching for the affected part of horizon.\n // TODO red-black tree or simple binary search\n var i = 0;\n while (i < horizon.length && horizon[i].end <= boundary.y1) {\n i++;\n }\n var j = horizon.length - 1;\n while (j >= 0 && horizon[j].start >= boundary.y2) {\n j--;\n }\n\n var horizonPart, affectedBoundary;\n var q, k, maxXNew = -Infinity;\n for (q = i; q <= j; q++) {\n horizonPart = horizon[q];\n affectedBoundary = horizonPart.boundary;\n var xNew;\n if (affectedBoundary.x2 > boundary.x1) {\n // In the middle of the previous element, new x shall be at the\n // boundary start. Extending if further if the affected bondary\n // placed on top of the current one.\n xNew = affectedBoundary.index > boundary.index ?\n affectedBoundary.x1New : boundary.x1;\n } else if (affectedBoundary.x2New === undefined) {\n // We have some space in between, new x in middle will be a fair\n // choice.\n xNew = (affectedBoundary.x2 + boundary.x1) / 2;\n } else {\n // Affected boundary has x2new set, using it as new x.\n xNew = affectedBoundary.x2New;\n }\n if (xNew > maxXNew) {\n maxXNew = xNew;\n }\n }\n\n // Set new x1 for current boundary.\n boundary.x1New = maxXNew;\n\n // Adjusts new x2 for the affected boundaries.\n for (q = i; q <= j; q++) {\n horizonPart = horizon[q];\n affectedBoundary = horizonPart.boundary;\n if (affectedBoundary.x2New === undefined) {\n // Was not set yet, choosing new x if possible.\n if (affectedBoundary.x2 > boundary.x1) {\n // Current and affected boundaries intersect. If affected boundary\n // is placed on top of the current, shrinking the affected.\n if (affectedBoundary.index > boundary.index) {\n affectedBoundary.x2New = affectedBoundary.x2;\n }\n } else {\n affectedBoundary.x2New = maxXNew;\n }\n } else if (affectedBoundary.x2New > maxXNew) {\n // Affected boundary is touching new x, pushing it back.\n affectedBoundary.x2New = Math.max(maxXNew, affectedBoundary.x2);\n }\n }\n\n // Fixing the horizon.\n var changedHorizon = [], lastBoundary = null;\n for (q = i; q <= j; q++) {\n horizonPart = horizon[q];\n affectedBoundary = horizonPart.boundary;\n // Checking which boundary will be visible.\n var useBoundary = affectedBoundary.x2 > boundary.x2 ?\n affectedBoundary : boundary;\n if (lastBoundary === useBoundary) {\n // Merging with previous.\n changedHorizon[changedHorizon.length - 1].end = horizonPart.end;\n } else {\n changedHorizon.push({\n start: horizonPart.start,\n end: horizonPart.end,\n boundary: useBoundary,\n });\n lastBoundary = useBoundary;\n }\n }\n if (horizon[i].start < boundary.y1) {\n changedHorizon[0].start = boundary.y1;\n changedHorizon.unshift({\n start: horizon[i].start,\n end: boundary.y1,\n boundary: horizon[i].boundary,\n });\n }\n if (boundary.y2 < horizon[j].end) {\n changedHorizon[changedHorizon.length - 1].end = boundary.y2;\n changedHorizon.push({\n start: boundary.y2,\n end: horizon[j].end,\n boundary: horizon[j].boundary,\n });\n }\n\n // Set x2 new of boundary that is no longer visible (see overlapping case\n // above).\n // TODO more efficient, e.g. via reference counting.\n for (q = i; q <= j; q++) {\n horizonPart = horizon[q];\n affectedBoundary = horizonPart.boundary;\n if (affectedBoundary.x2New !== undefined) {\n continue;\n }\n var used = false;\n for (k = i - 1; !used && k >= 0 &&\n horizon[k].start >= affectedBoundary.y1; k--) {\n used = horizon[k].boundary === affectedBoundary;\n }\n for (k = j + 1; !used && k < horizon.length &&\n horizon[k].end <= affectedBoundary.y2; k++) {\n used = horizon[k].boundary === affectedBoundary;\n }\n for (k = 0; !used && k < changedHorizon.length; k++) {\n used = changedHorizon[k].boundary === affectedBoundary;\n }\n if (!used) {\n affectedBoundary.x2New = maxXNew;\n }\n }\n\n Array.prototype.splice.apply(horizon,\n [i, j - i + 1].concat(changedHorizon));\n });\n\n // Set new x2 for all unset boundaries.\n horizon.forEach(function (horizonPart) {\n var affectedBoundary = horizonPart.boundary;\n if (affectedBoundary.x2New === undefined) {\n affectedBoundary.x2New = Math.max(width, affectedBoundary.x2);\n }\n });\n }\n\n /**\n * Text layer rendering task.\n *\n * @param {TextContent} textContent\n * @param {HTMLElement} container\n * @param {PageViewport} viewport\n * @param {Array} textDivs\n * @param {boolean} enhanceTextSelection\n * @private\n */\n function TextLayerRenderTask({ textContent, textContentStream, container,\n viewport, textDivs, textContentItemsStr,\n enhanceTextSelection, }) {\n this._textContent = textContent;\n this._textContentStream = textContentStream;\n this._container = container;\n this._viewport = viewport;\n this._textDivs = textDivs || [];\n this._textContentItemsStr = textContentItemsStr || [];\n this._enhanceTextSelection = !!enhanceTextSelection;\n\n this._reader = null;\n this._layoutTextLastFontSize = null;\n this._layoutTextLastFontFamily = null;\n this._layoutTextCtx = null;\n this._textDivProperties = new WeakMap();\n this._renderingDone = false;\n this._canceled = false;\n this._capability = createPromiseCapability();\n this._renderTimer = null;\n this._bounds = [];\n }\n TextLayerRenderTask.prototype = {\n get promise() {\n return this._capability.promise;\n },\n\n cancel: function TextLayer_cancel() {\n if (this._reader) {\n this._reader.cancel(new AbortException('text layer task cancelled'));\n this._reader = null;\n }\n this._canceled = true;\n if (this._renderTimer !== null) {\n clearTimeout(this._renderTimer);\n this._renderTimer = null;\n }\n this._capability.reject('canceled');\n },\n\n _processItems(items, styleCache) {\n for (let i = 0, len = items.length; i < len; i++) {\n this._textContentItemsStr.push(items[i].str);\n appendText(this, items[i], styleCache);\n }\n },\n\n _layoutText(textDiv) {\n let textLayerFrag = this._container;\n\n let textDivProperties = this._textDivProperties.get(textDiv);\n if (textDivProperties.isWhitespace) {\n return;\n }\n\n let fontSize = textDiv.style.fontSize;\n let fontFamily = textDiv.style.fontFamily;\n\n // Only build font string and set to context if different from last.\n if (fontSize !== this._layoutTextLastFontSize ||\n fontFamily !== this._layoutTextLastFontFamily) {\n this._layoutTextCtx.font = fontSize + ' ' + fontFamily;\n this._lastFontSize = fontSize;\n this._lastFontFamily = fontFamily;\n }\n\n let width = this._layoutTextCtx.measureText(textDiv.textContent).width;\n\n let transform = '';\n if (textDivProperties.canvasWidth !== 0 && width > 0) {\n textDivProperties.scale = textDivProperties.canvasWidth / width;\n transform = 'scaleX(' + textDivProperties.scale + ')';\n }\n if (textDivProperties.angle !== 0) {\n transform = 'rotate(' + textDivProperties.angle + 'deg) ' + transform;\n }\n if (transform !== '') {\n textDivProperties.originalTransform = transform;\n CustomStyle.setProp('transform', textDiv, transform);\n }\n this._textDivProperties.set(textDiv, textDivProperties);\n textLayerFrag.appendChild(textDiv);\n },\n\n _render: function TextLayer_render(timeout) {\n let capability = createPromiseCapability();\n let styleCache = Object.create(null);\n\n // The temporary canvas is used to measure text length in the DOM.\n let canvas = document.createElement('canvas');\n if (typeof PDFJSDev === 'undefined' ||\n PDFJSDev.test('FIREFOX || MOZCENTRAL || GENERIC')) {\n canvas.mozOpaque = true;\n }\n this._layoutTextCtx = canvas.getContext('2d', { alpha: false, });\n\n if (this._textContent) {\n let textItems = this._textContent.items;\n let textStyles = this._textContent.styles;\n this._processItems(textItems, textStyles);\n capability.resolve();\n } else if (this._textContentStream) {\n let pump = () => {\n this._reader.read().then(({ value, done, }) => {\n if (done) {\n capability.resolve();\n return;\n }\n\n Util.extendObj(styleCache, value.styles);\n this._processItems(value.items, styleCache);\n pump();\n\n }, capability.reject);\n };\n\n this._reader = this._textContentStream.getReader();\n pump();\n } else {\n throw new Error('Neither \"textContent\" nor \"textContentStream\"' +\n ' parameters specified.');\n }\n\n capability.promise.then(() => {\n styleCache = null;\n if (!timeout) { // Render right away\n render(this);\n } else { // Schedule\n this._renderTimer = setTimeout(() => {\n render(this);\n this._renderTimer = null;\n }, timeout);\n }\n }, this._capability.reject);\n },\n\n expandTextDivs: function TextLayer_expandTextDivs(expandDivs) {\n if (!this._enhanceTextSelection || !this._renderingDone) {\n return;\n }\n if (this._bounds !== null) {\n expand(this);\n this._bounds = null;\n }\n\n for (var i = 0, ii = this._textDivs.length; i < ii; i++) {\n var div = this._textDivs[i];\n var divProperties = this._textDivProperties.get(div);\n\n if (divProperties.isWhitespace) {\n continue;\n }\n if (expandDivs) {\n var transform = '', padding = '';\n\n if (divProperties.scale !== 1) {\n transform = 'scaleX(' + divProperties.scale + ')';\n }\n if (divProperties.angle !== 0) {\n transform = 'rotate(' + divProperties.angle + 'deg) ' + transform;\n }\n if (divProperties.paddingLeft !== 0) {\n padding += ' padding-left: ' +\n (divProperties.paddingLeft / divProperties.scale) + 'px;';\n transform += ' translateX(' +\n (-divProperties.paddingLeft / divProperties.scale) + 'px)';\n }\n if (divProperties.paddingTop !== 0) {\n padding += ' padding-top: ' + divProperties.paddingTop + 'px;';\n transform += ' translateY(' + (-divProperties.paddingTop) + 'px)';\n }\n if (divProperties.paddingRight !== 0) {\n padding += ' padding-right: ' +\n (divProperties.paddingRight / divProperties.scale) + 'px;';\n }\n if (divProperties.paddingBottom !== 0) {\n padding += ' padding-bottom: ' +\n divProperties.paddingBottom + 'px;';\n }\n\n if (padding !== '') {\n div.setAttribute('style', divProperties.style + padding);\n }\n if (transform !== '') {\n CustomStyle.setProp('transform', div, transform);\n }\n } else {\n div.style.padding = 0;\n CustomStyle.setProp('transform', div,\n divProperties.originalTransform || '');\n }\n }\n },\n };\n\n /**\n * Starts rendering of the text layer.\n *\n * @param {TextLayerRenderParameters} renderParameters\n * @returns {TextLayerRenderTask}\n */\n function renderTextLayer(renderParameters) {\n var task = new TextLayerRenderTask({\n textContent: renderParameters.textContent,\n textContentStream: renderParameters.textContentStream,\n container: renderParameters.container,\n viewport: renderParameters.viewport,\n textDivs: renderParameters.textDivs,\n textContentItemsStr: renderParameters.textContentItemsStr,\n enhanceTextSelection: renderParameters.enhanceTextSelection,\n });\n task._render(renderParameters.timeout);\n return task;\n }\n\n return renderTextLayer;\n})();\n\nexport {\n renderTextLayer,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/display/text_layer.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nfunction fixMetadata(meta) {\n return meta.replace(/>\\\\376\\\\377([^<]+)/g, function(all, codes) {\n var bytes = codes.replace(/\\\\([0-3])([0-7])([0-7])/g,\n function(code, d1, d2, d3) {\n return String.fromCharCode(d1 * 64 + d2 * 8 + d3 * 1);\n });\n var chars = '';\n for (var i = 0; i < bytes.length; i += 2) {\n var code = bytes.charCodeAt(i) * 256 + bytes.charCodeAt(i + 1);\n chars += (code >= 32 && code < 127 && code !== 60 && code !== 62 &&\n code !== 38) ? String.fromCharCode(code) :\n '&#x' + (0x10000 + code).toString(16).substring(1) + ';';\n }\n return '>' + chars;\n });\n}\n\nfunction Metadata(meta) {\n if (typeof meta === 'string') {\n // Ghostscript produces invalid metadata\n meta = fixMetadata(meta);\n\n var parser = new DOMParser();\n meta = parser.parseFromString(meta, 'application/xml');\n } else if (!(meta instanceof Document)) {\n throw new Error('Metadata: Invalid metadata object');\n }\n\n this.metaDocument = meta;\n this.metadata = Object.create(null);\n this.parse();\n}\n\nMetadata.prototype = {\n parse: function Metadata_parse() {\n var doc = this.metaDocument;\n var rdf = doc.documentElement;\n\n if (rdf.nodeName.toLowerCase() !== 'rdf:rdf') { // Wrapped in \n rdf = rdf.firstChild;\n while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf') {\n rdf = rdf.nextSibling;\n }\n }\n\n var nodeName = (rdf) ? rdf.nodeName.toLowerCase() : null;\n if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes()) {\n return;\n }\n\n var children = rdf.childNodes, desc, entry, name, i, ii, length, iLength;\n for (i = 0, length = children.length; i < length; i++) {\n desc = children[i];\n if (desc.nodeName.toLowerCase() !== 'rdf:description') {\n continue;\n }\n\n for (ii = 0, iLength = desc.childNodes.length; ii < iLength; ii++) {\n if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text') {\n entry = desc.childNodes[ii];\n name = entry.nodeName.toLowerCase();\n this.metadata[name] = entry.textContent.trim();\n }\n }\n }\n },\n\n get: function Metadata_get(name) {\n return this.metadata[name] || null;\n },\n\n has: function Metadata_has(name) {\n return typeof this.metadata[name] !== 'undefined';\n },\n};\n\nexport {\n Metadata,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/display/metadata.js", + "/* Copyright 2014 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* eslint-disable no-multi-str */\n\nimport { getDefaultSetting } from './dom_utils';\nimport { shadow } from '../shared/util';\n\nvar WebGLUtils = (function WebGLUtilsClosure() {\n function loadShader(gl, code, shaderType) {\n var shader = gl.createShader(shaderType);\n gl.shaderSource(shader, code);\n gl.compileShader(shader);\n var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);\n if (!compiled) {\n var errorMsg = gl.getShaderInfoLog(shader);\n throw new Error('Error during shader compilation: ' + errorMsg);\n }\n return shader;\n }\n function createVertexShader(gl, code) {\n return loadShader(gl, code, gl.VERTEX_SHADER);\n }\n function createFragmentShader(gl, code) {\n return loadShader(gl, code, gl.FRAGMENT_SHADER);\n }\n function createProgram(gl, shaders) {\n var program = gl.createProgram();\n for (var i = 0, ii = shaders.length; i < ii; ++i) {\n gl.attachShader(program, shaders[i]);\n }\n gl.linkProgram(program);\n var linked = gl.getProgramParameter(program, gl.LINK_STATUS);\n if (!linked) {\n var errorMsg = gl.getProgramInfoLog(program);\n throw new Error('Error during program linking: ' + errorMsg);\n }\n return program;\n }\n function createTexture(gl, image, textureId) {\n gl.activeTexture(textureId);\n var texture = gl.createTexture();\n gl.bindTexture(gl.TEXTURE_2D, texture);\n\n // Set the parameters so we can render any size image.\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\n // Upload the image into the texture.\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);\n return texture;\n }\n\n var currentGL, currentCanvas;\n function generateGL() {\n if (currentGL) {\n return;\n }\n\n // The temporary canvas is used in the WebGL context.\n currentCanvas = document.createElement('canvas');\n currentGL = currentCanvas.getContext('webgl',\n { premultipliedalpha: false, });\n }\n\n var smaskVertexShaderCode = '\\\n attribute vec2 a_position; \\\n attribute vec2 a_texCoord; \\\n \\\n uniform vec2 u_resolution; \\\n \\\n varying vec2 v_texCoord; \\\n \\\n void main() { \\\n vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0; \\\n gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \\\n \\\n v_texCoord = a_texCoord; \\\n } ';\n\n var smaskFragmentShaderCode = '\\\n precision mediump float; \\\n \\\n uniform vec4 u_backdrop; \\\n uniform int u_subtype; \\\n uniform sampler2D u_image; \\\n uniform sampler2D u_mask; \\\n \\\n varying vec2 v_texCoord; \\\n \\\n void main() { \\\n vec4 imageColor = texture2D(u_image, v_texCoord); \\\n vec4 maskColor = texture2D(u_mask, v_texCoord); \\\n if (u_backdrop.a > 0.0) { \\\n maskColor.rgb = maskColor.rgb * maskColor.a + \\\n u_backdrop.rgb * (1.0 - maskColor.a); \\\n } \\\n float lum; \\\n if (u_subtype == 0) { \\\n lum = maskColor.a; \\\n } else { \\\n lum = maskColor.r * 0.3 + maskColor.g * 0.59 + \\\n maskColor.b * 0.11; \\\n } \\\n imageColor.a *= lum; \\\n imageColor.rgb *= imageColor.a; \\\n gl_FragColor = imageColor; \\\n } ';\n\n var smaskCache = null;\n\n function initSmaskGL() {\n var canvas, gl;\n\n generateGL();\n canvas = currentCanvas;\n currentCanvas = null;\n gl = currentGL;\n currentGL = null;\n\n // setup a GLSL program\n var vertexShader = createVertexShader(gl, smaskVertexShaderCode);\n var fragmentShader = createFragmentShader(gl, smaskFragmentShaderCode);\n var program = createProgram(gl, [vertexShader, fragmentShader]);\n gl.useProgram(program);\n\n var cache = {};\n cache.gl = gl;\n cache.canvas = canvas;\n cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');\n cache.positionLocation = gl.getAttribLocation(program, 'a_position');\n cache.backdropLocation = gl.getUniformLocation(program, 'u_backdrop');\n cache.subtypeLocation = gl.getUniformLocation(program, 'u_subtype');\n\n var texCoordLocation = gl.getAttribLocation(program, 'a_texCoord');\n var texLayerLocation = gl.getUniformLocation(program, 'u_image');\n var texMaskLocation = gl.getUniformLocation(program, 'u_mask');\n\n // provide texture coordinates for the rectangle.\n var texCoordBuffer = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([\n 0.0, 0.0,\n 1.0, 0.0,\n 0.0, 1.0,\n 0.0, 1.0,\n 1.0, 0.0,\n 1.0, 1.0]), gl.STATIC_DRAW);\n gl.enableVertexAttribArray(texCoordLocation);\n gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);\n\n gl.uniform1i(texLayerLocation, 0);\n gl.uniform1i(texMaskLocation, 1);\n\n smaskCache = cache;\n }\n\n function composeSMask(layer, mask, properties) {\n var width = layer.width, height = layer.height;\n\n if (!smaskCache) {\n initSmaskGL();\n }\n var cache = smaskCache, canvas = cache.canvas, gl = cache.gl;\n canvas.width = width;\n canvas.height = height;\n gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n gl.uniform2f(cache.resolutionLocation, width, height);\n\n if (properties.backdrop) {\n gl.uniform4f(cache.resolutionLocation, properties.backdrop[0],\n properties.backdrop[1], properties.backdrop[2], 1);\n } else {\n gl.uniform4f(cache.resolutionLocation, 0, 0, 0, 0);\n }\n gl.uniform1i(cache.subtypeLocation,\n properties.subtype === 'Luminosity' ? 1 : 0);\n\n // Create a textures\n var texture = createTexture(gl, layer, gl.TEXTURE0);\n var maskTexture = createTexture(gl, mask, gl.TEXTURE1);\n\n\n // Create a buffer and put a single clipspace rectangle in\n // it (2 triangles)\n var buffer = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([\n 0, 0,\n width, 0,\n 0, height,\n 0, height,\n width, 0,\n width, height]), gl.STATIC_DRAW);\n gl.enableVertexAttribArray(cache.positionLocation);\n gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);\n\n // draw\n gl.clearColor(0, 0, 0, 0);\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n gl.clear(gl.COLOR_BUFFER_BIT);\n\n gl.drawArrays(gl.TRIANGLES, 0, 6);\n\n gl.flush();\n\n gl.deleteTexture(texture);\n gl.deleteTexture(maskTexture);\n gl.deleteBuffer(buffer);\n\n return canvas;\n }\n\n var figuresVertexShaderCode = '\\\n attribute vec2 a_position; \\\n attribute vec3 a_color; \\\n \\\n uniform vec2 u_resolution; \\\n uniform vec2 u_scale; \\\n uniform vec2 u_offset; \\\n \\\n varying vec4 v_color; \\\n \\\n void main() { \\\n vec2 position = (a_position + u_offset) * u_scale; \\\n vec2 clipSpace = (position / u_resolution) * 2.0 - 1.0; \\\n gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \\\n \\\n v_color = vec4(a_color / 255.0, 1.0); \\\n } ';\n\n var figuresFragmentShaderCode = '\\\n precision mediump float; \\\n \\\n varying vec4 v_color; \\\n \\\n void main() { \\\n gl_FragColor = v_color; \\\n } ';\n\n var figuresCache = null;\n\n function initFiguresGL() {\n var canvas, gl;\n\n generateGL();\n canvas = currentCanvas;\n currentCanvas = null;\n gl = currentGL;\n currentGL = null;\n\n // setup a GLSL program\n var vertexShader = createVertexShader(gl, figuresVertexShaderCode);\n var fragmentShader = createFragmentShader(gl, figuresFragmentShaderCode);\n var program = createProgram(gl, [vertexShader, fragmentShader]);\n gl.useProgram(program);\n\n var cache = {};\n cache.gl = gl;\n cache.canvas = canvas;\n cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');\n cache.scaleLocation = gl.getUniformLocation(program, 'u_scale');\n cache.offsetLocation = gl.getUniformLocation(program, 'u_offset');\n cache.positionLocation = gl.getAttribLocation(program, 'a_position');\n cache.colorLocation = gl.getAttribLocation(program, 'a_color');\n\n figuresCache = cache;\n }\n\n function drawFigures(width, height, backgroundColor, figures, context) {\n if (!figuresCache) {\n initFiguresGL();\n }\n var cache = figuresCache, canvas = cache.canvas, gl = cache.gl;\n\n canvas.width = width;\n canvas.height = height;\n gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n gl.uniform2f(cache.resolutionLocation, width, height);\n\n // count triangle points\n var count = 0;\n var i, ii, rows;\n for (i = 0, ii = figures.length; i < ii; i++) {\n switch (figures[i].type) {\n case 'lattice':\n rows = (figures[i].coords.length / figures[i].verticesPerRow) | 0;\n count += (rows - 1) * (figures[i].verticesPerRow - 1) * 6;\n break;\n case 'triangles':\n count += figures[i].coords.length;\n break;\n }\n }\n // transfer data\n var coords = new Float32Array(count * 2);\n var colors = new Uint8Array(count * 3);\n var coordsMap = context.coords, colorsMap = context.colors;\n var pIndex = 0, cIndex = 0;\n for (i = 0, ii = figures.length; i < ii; i++) {\n var figure = figures[i], ps = figure.coords, cs = figure.colors;\n switch (figure.type) {\n case 'lattice':\n var cols = figure.verticesPerRow;\n rows = (ps.length / cols) | 0;\n for (var row = 1; row < rows; row++) {\n var offset = row * cols + 1;\n for (var col = 1; col < cols; col++, offset++) {\n coords[pIndex] = coordsMap[ps[offset - cols - 1]];\n coords[pIndex + 1] = coordsMap[ps[offset - cols - 1] + 1];\n coords[pIndex + 2] = coordsMap[ps[offset - cols]];\n coords[pIndex + 3] = coordsMap[ps[offset - cols] + 1];\n coords[pIndex + 4] = coordsMap[ps[offset - 1]];\n coords[pIndex + 5] = coordsMap[ps[offset - 1] + 1];\n colors[cIndex] = colorsMap[cs[offset - cols - 1]];\n colors[cIndex + 1] = colorsMap[cs[offset - cols - 1] + 1];\n colors[cIndex + 2] = colorsMap[cs[offset - cols - 1] + 2];\n colors[cIndex + 3] = colorsMap[cs[offset - cols]];\n colors[cIndex + 4] = colorsMap[cs[offset - cols] + 1];\n colors[cIndex + 5] = colorsMap[cs[offset - cols] + 2];\n colors[cIndex + 6] = colorsMap[cs[offset - 1]];\n colors[cIndex + 7] = colorsMap[cs[offset - 1] + 1];\n colors[cIndex + 8] = colorsMap[cs[offset - 1] + 2];\n\n coords[pIndex + 6] = coords[pIndex + 2];\n coords[pIndex + 7] = coords[pIndex + 3];\n coords[pIndex + 8] = coords[pIndex + 4];\n coords[pIndex + 9] = coords[pIndex + 5];\n coords[pIndex + 10] = coordsMap[ps[offset]];\n coords[pIndex + 11] = coordsMap[ps[offset] + 1];\n colors[cIndex + 9] = colors[cIndex + 3];\n colors[cIndex + 10] = colors[cIndex + 4];\n colors[cIndex + 11] = colors[cIndex + 5];\n colors[cIndex + 12] = colors[cIndex + 6];\n colors[cIndex + 13] = colors[cIndex + 7];\n colors[cIndex + 14] = colors[cIndex + 8];\n colors[cIndex + 15] = colorsMap[cs[offset]];\n colors[cIndex + 16] = colorsMap[cs[offset] + 1];\n colors[cIndex + 17] = colorsMap[cs[offset] + 2];\n pIndex += 12;\n cIndex += 18;\n }\n }\n break;\n case 'triangles':\n for (var j = 0, jj = ps.length; j < jj; j++) {\n coords[pIndex] = coordsMap[ps[j]];\n coords[pIndex + 1] = coordsMap[ps[j] + 1];\n colors[cIndex] = colorsMap[cs[j]];\n colors[cIndex + 1] = colorsMap[cs[j] + 1];\n colors[cIndex + 2] = colorsMap[cs[j] + 2];\n pIndex += 2;\n cIndex += 3;\n }\n break;\n }\n }\n\n // draw\n if (backgroundColor) {\n gl.clearColor(backgroundColor[0] / 255, backgroundColor[1] / 255,\n backgroundColor[2] / 255, 1.0);\n } else {\n gl.clearColor(0, 0, 0, 0);\n }\n gl.clear(gl.COLOR_BUFFER_BIT);\n\n var coordsBuffer = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, coordsBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, coords, gl.STATIC_DRAW);\n gl.enableVertexAttribArray(cache.positionLocation);\n gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);\n\n var colorsBuffer = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, colorsBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);\n gl.enableVertexAttribArray(cache.colorLocation);\n gl.vertexAttribPointer(cache.colorLocation, 3, gl.UNSIGNED_BYTE, false,\n 0, 0);\n\n gl.uniform2f(cache.scaleLocation, context.scaleX, context.scaleY);\n gl.uniform2f(cache.offsetLocation, context.offsetX, context.offsetY);\n\n gl.drawArrays(gl.TRIANGLES, 0, count);\n\n gl.flush();\n\n gl.deleteBuffer(coordsBuffer);\n gl.deleteBuffer(colorsBuffer);\n\n return canvas;\n }\n\n function cleanup() {\n if (smaskCache && smaskCache.canvas) {\n smaskCache.canvas.width = 0;\n smaskCache.canvas.height = 0;\n }\n if (figuresCache && figuresCache.canvas) {\n figuresCache.canvas.width = 0;\n figuresCache.canvas.height = 0;\n }\n smaskCache = null;\n figuresCache = null;\n }\n\n return {\n get isEnabled() {\n if (getDefaultSetting('disableWebGL')) {\n return false;\n }\n var enabled = false;\n try {\n generateGL();\n enabled = !!currentGL;\n } catch (e) { }\n return shadow(this, 'isEnabled', enabled);\n },\n composeSMask,\n drawFigures,\n clear: cleanup,\n };\n})();\n\nexport {\n WebGLUtils,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/display/webgl.js", + "/* Copyright 2015 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n _UnsupportedManager, getDocument, LoopbackPort, PDFDataRangeTransport,\n PDFWorker\n} from './api';\nimport {\n addLinkAttributes, CustomStyle, DEFAULT_LINK_REL, getFilenameFromUrl,\n isExternalLinkTargetSet, isValidUrl, LinkTarget\n} from './dom_utils';\nimport {\n createBlob, createObjectURL, createPromiseCapability, deprecated,\n getVerbosityLevel, globalScope, InvalidPDFException, isLittleEndian,\n MissingPDFException, OPS, PageViewport, PasswordException, PasswordResponses,\n removeNullCharacters, setVerbosityLevel, shadow, UnexpectedResponseException,\n UnknownErrorException, UNSUPPORTED_FEATURES, Util, VERBOSITY_LEVELS, warn\n} from '../shared/util';\nimport { AnnotationLayer } from './annotation_layer';\nimport { Metadata } from './metadata';\nimport { renderTextLayer } from './text_layer';\nimport { SVGGraphics } from './svg';\n\nvar isWorker = (typeof window === 'undefined');\n\n// The global PDFJS object is now deprecated and will not be supported in\n// the future. The members below are maintained for backward compatibility\n// and shall not be extended or modified. If the global.js is included as\n// a module, we will create a global PDFJS object instance or use existing.\nif (!globalScope.PDFJS) {\n globalScope.PDFJS = {};\n}\nvar PDFJS = globalScope.PDFJS;\n\nif (typeof PDFJSDev !== 'undefined') {\n PDFJS.version = PDFJSDev.eval('BUNDLE_VERSION');\n PDFJS.build = PDFJSDev.eval('BUNDLE_BUILD');\n}\n\nPDFJS.pdfBug = false;\n\nif (PDFJS.verbosity !== undefined) {\n setVerbosityLevel(PDFJS.verbosity);\n}\ndelete PDFJS.verbosity;\nObject.defineProperty(PDFJS, 'verbosity', {\n get() {\n return getVerbosityLevel();\n },\n set(level) {\n setVerbosityLevel(level);\n },\n enumerable: true,\n configurable: true,\n});\n\nPDFJS.VERBOSITY_LEVELS = VERBOSITY_LEVELS;\nPDFJS.OPS = OPS;\nPDFJS.UNSUPPORTED_FEATURES = UNSUPPORTED_FEATURES;\nPDFJS.isValidUrl = isValidUrl;\nPDFJS.shadow = shadow;\nPDFJS.createBlob = createBlob;\nPDFJS.createObjectURL = function PDFJS_createObjectURL(data, contentType) {\n return createObjectURL(data, contentType, PDFJS.disableCreateObjectURL);\n};\nObject.defineProperty(PDFJS, 'isLittleEndian', {\n configurable: true,\n get: function PDFJS_isLittleEndian() {\n return shadow(PDFJS, 'isLittleEndian', isLittleEndian());\n },\n});\nPDFJS.removeNullCharacters = removeNullCharacters;\nPDFJS.PasswordResponses = PasswordResponses;\nPDFJS.PasswordException = PasswordException;\nPDFJS.UnknownErrorException = UnknownErrorException;\nPDFJS.InvalidPDFException = InvalidPDFException;\nPDFJS.MissingPDFException = MissingPDFException;\nPDFJS.UnexpectedResponseException = UnexpectedResponseException;\nPDFJS.Util = Util;\nPDFJS.PageViewport = PageViewport;\nPDFJS.createPromiseCapability = createPromiseCapability;\n\n/**\n * The maximum allowed image size in total pixels e.g. width * height. Images\n * above this value will not be drawn. Use -1 for no limit.\n * @var {number}\n */\nPDFJS.maxImageSize = (PDFJS.maxImageSize === undefined ?\n -1 : PDFJS.maxImageSize);\n\n/**\n * The url of where the predefined Adobe CMaps are located. Include trailing\n * slash.\n * @var {string}\n */\nPDFJS.cMapUrl = (PDFJS.cMapUrl === undefined ? null : PDFJS.cMapUrl);\n\n/**\n * Specifies if CMaps are binary packed.\n * @var {boolean}\n */\nPDFJS.cMapPacked = PDFJS.cMapPacked === undefined ? false : PDFJS.cMapPacked;\n\n/**\n * By default fonts are converted to OpenType fonts and loaded via font face\n * rules. If disabled, the font will be rendered using a built in font\n * renderer that constructs the glyphs with primitive path commands.\n * @var {boolean}\n */\nPDFJS.disableFontFace = (PDFJS.disableFontFace === undefined ?\n false : PDFJS.disableFontFace);\n\n/**\n * Path for image resources, mainly for annotation icons. Include trailing\n * slash.\n * @var {string}\n */\nPDFJS.imageResourcesPath = (PDFJS.imageResourcesPath === undefined ?\n '' : PDFJS.imageResourcesPath);\n\n/**\n * Disable the web worker and run all code on the main thread. This will\n * happen automatically if the browser doesn't support workers or sending\n * typed arrays to workers.\n * @var {boolean}\n */\nPDFJS.disableWorker = (PDFJS.disableWorker === undefined ?\n false : PDFJS.disableWorker);\n\n/**\n * Path and filename of the worker file. Required when the worker is enabled\n * in development mode. If unspecified in the production build, the worker\n * will be loaded based on the location of the pdf.js file. It is recommended\n * that the workerSrc is set in a custom application to prevent issues caused\n * by third-party frameworks and libraries.\n * @var {string}\n */\nPDFJS.workerSrc = (PDFJS.workerSrc === undefined ? null : PDFJS.workerSrc);\n\n/**\n * Defines global port for worker process. Overrides workerSrc and\n * disableWorker setting.\n */\nPDFJS.workerPort = (PDFJS.workerPort === undefined ? null : PDFJS.workerPort);\n\n/**\n * Disable range request loading of PDF files. When enabled and if the server\n * supports partial content requests then the PDF will be fetched in chunks.\n * Enabled (false) by default.\n * @var {boolean}\n */\nPDFJS.disableRange = (PDFJS.disableRange === undefined ?\n false : PDFJS.disableRange);\n\n/**\n * Disable streaming of PDF file data. By default PDF.js attempts to load PDF\n * in chunks. This default behavior can be disabled.\n * @var {boolean}\n */\nPDFJS.disableStream = (PDFJS.disableStream === undefined ?\n false : PDFJS.disableStream);\n\n/**\n * Disable pre-fetching of PDF file data. When range requests are enabled\n * PDF.js will automatically keep fetching more data even if it isn't needed\n * to display the current page. This default behavior can be disabled.\n *\n * NOTE: It is also necessary to disable streaming, see above,\n * in order for disabling of pre-fetching to work correctly.\n * @var {boolean}\n */\nPDFJS.disableAutoFetch = (PDFJS.disableAutoFetch === undefined ?\n false : PDFJS.disableAutoFetch);\n\n/**\n * Enables special hooks for debugging PDF.js.\n * @var {boolean}\n */\nPDFJS.pdfBug = (PDFJS.pdfBug === undefined ? false : PDFJS.pdfBug);\n\n/**\n * Enables transfer usage in postMessage for ArrayBuffers.\n * @var {boolean}\n */\nPDFJS.postMessageTransfers = (PDFJS.postMessageTransfers === undefined ?\n true : PDFJS.postMessageTransfers);\n\n/**\n * Disables URL.createObjectURL usage.\n * @var {boolean}\n */\nPDFJS.disableCreateObjectURL = (PDFJS.disableCreateObjectURL === undefined ?\n false : PDFJS.disableCreateObjectURL);\n\n/**\n * Disables WebGL usage.\n * @var {boolean}\n */\nPDFJS.disableWebGL = (PDFJS.disableWebGL === undefined ?\n true : PDFJS.disableWebGL);\n\n/**\n * Specifies the |target| attribute for external links.\n * The constants from PDFJS.LinkTarget should be used:\n * - NONE [default]\n * - SELF\n * - BLANK\n * - PARENT\n * - TOP\n * @var {number}\n */\nPDFJS.externalLinkTarget = (PDFJS.externalLinkTarget === undefined ?\n LinkTarget.NONE : PDFJS.externalLinkTarget);\n\n/**\n * Specifies the |rel| attribute for external links. Defaults to stripping\n * the referrer.\n * @var {string}\n */\nPDFJS.externalLinkRel = (PDFJS.externalLinkRel === undefined ?\n DEFAULT_LINK_REL : PDFJS.externalLinkRel);\n\n/**\n * Determines if we can eval strings as JS. Primarily used to improve\n * performance for font rendering.\n * @var {boolean}\n */\nPDFJS.isEvalSupported = (PDFJS.isEvalSupported === undefined ?\n true : PDFJS.isEvalSupported);\n\n/**\n * Opt-in to backwards incompatible API changes. NOTE:\n * If the `PDFJS_NEXT` build flag is set, it will override this setting.\n * @var {boolean}\n */\nPDFJS.pdfjsNext = (PDFJS.pdfjsNext === undefined) ? false : PDFJS.pdfjsNext;\n\nif (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) {\n var savedOpenExternalLinksInNewWindow = PDFJS.openExternalLinksInNewWindow;\n delete PDFJS.openExternalLinksInNewWindow;\n Object.defineProperty(PDFJS, 'openExternalLinksInNewWindow', {\n get() {\n return PDFJS.externalLinkTarget === LinkTarget.BLANK;\n },\n set(value) {\n if (value) {\n deprecated('PDFJS.openExternalLinksInNewWindow, please use ' +\n '\"PDFJS.externalLinkTarget = PDFJS.LinkTarget.BLANK\" instead.');\n }\n if (PDFJS.externalLinkTarget !== LinkTarget.NONE) {\n warn('PDFJS.externalLinkTarget is already initialized');\n return;\n }\n PDFJS.externalLinkTarget = value ? LinkTarget.BLANK : LinkTarget.NONE;\n },\n enumerable: true,\n configurable: true,\n });\n if (savedOpenExternalLinksInNewWindow) {\n /**\n * (Deprecated) Opens external links in a new window if enabled.\n * The default behavior opens external links in the PDF.js window.\n *\n * NOTE: This property has been deprecated, please use\n * `PDFJS.externalLinkTarget = PDFJS.LinkTarget.BLANK` instead.\n * @var {boolean}\n */\n PDFJS.openExternalLinksInNewWindow = savedOpenExternalLinksInNewWindow;\n }\n}\n\nPDFJS.getDocument = getDocument;\nPDFJS.LoopbackPort = LoopbackPort;\nPDFJS.PDFDataRangeTransport = PDFDataRangeTransport;\nPDFJS.PDFWorker = PDFWorker;\n\nPDFJS.hasCanvasTypedArrays = true; // compatibility.js ensures this invariant\nPDFJS.CustomStyle = CustomStyle;\nPDFJS.LinkTarget = LinkTarget;\nPDFJS.addLinkAttributes = addLinkAttributes;\nPDFJS.getFilenameFromUrl = getFilenameFromUrl;\nPDFJS.isExternalLinkTargetSet = isExternalLinkTargetSet;\n\nPDFJS.AnnotationLayer = AnnotationLayer;\n\nPDFJS.renderTextLayer = renderTextLayer;\n\nPDFJS.Metadata = Metadata;\n\nPDFJS.SVGGraphics = SVGGraphics;\n\nPDFJS.UnsupportedManager = _UnsupportedManager;\n\nexport {\n globalScope,\n isWorker,\n PDFJS,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/display/global.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n assert, createPromiseCapability, globalScope, isInt, MissingPDFException,\n UnexpectedResponseException\n} from '../shared/util';\nimport { setPDFNetworkStreamClass } from './api';\n\nif (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n throw new Error('Module \"./network\" shall not ' +\n 'be used with FIREFOX or MOZCENTRAL build.');\n}\n\nvar OK_RESPONSE = 200;\nvar PARTIAL_CONTENT_RESPONSE = 206;\n\nfunction NetworkManager(url, args) {\n this.url = url;\n args = args || {};\n this.isHttp = /^https?:/i.test(url);\n this.httpHeaders = (this.isHttp && args.httpHeaders) || {};\n this.withCredentials = args.withCredentials || false;\n this.getXhr = args.getXhr ||\n function NetworkManager_getXhr() {\n return new XMLHttpRequest();\n };\n\n this.currXhrId = 0;\n this.pendingRequests = Object.create(null);\n this.loadedRequests = Object.create(null);\n}\n\nfunction getArrayBuffer(xhr) {\n var data = xhr.response;\n if (typeof data !== 'string') {\n return data;\n }\n var length = data.length;\n var array = new Uint8Array(length);\n for (var i = 0; i < length; i++) {\n array[i] = data.charCodeAt(i) & 0xFF;\n }\n return array.buffer;\n}\n\nvar supportsMozChunked =\n typeof PDFJSDev !== 'undefined' && PDFJSDev.test('CHROME') ? false :\n (function supportsMozChunkedClosure() {\n try {\n var x = new XMLHttpRequest();\n // Firefox 37- required .open() to be called before setting responseType.\n // https://bugzilla.mozilla.org/show_bug.cgi?id=707484\n // Even though the URL is not visited, .open() could fail if the URL is\n // blocked, e.g. via the connect-src CSP directive or the NoScript addon.\n // When this error occurs, this feature detection method will mistakenly\n // report that moz-chunked-arraybuffer is not supported in Firefox 37-.\n x.open('GET', globalScope.location.href);\n x.responseType = 'moz-chunked-arraybuffer';\n return x.responseType === 'moz-chunked-arraybuffer';\n } catch (e) {\n return false;\n }\n})();\n\nNetworkManager.prototype = {\n requestRange: function NetworkManager_requestRange(begin, end, listeners) {\n var args = {\n begin,\n end,\n };\n for (var prop in listeners) {\n args[prop] = listeners[prop];\n }\n return this.request(args);\n },\n\n requestFull: function NetworkManager_requestFull(listeners) {\n return this.request(listeners);\n },\n\n request: function NetworkManager_request(args) {\n var xhr = this.getXhr();\n var xhrId = this.currXhrId++;\n var pendingRequest = this.pendingRequests[xhrId] = {\n xhr,\n };\n\n xhr.open('GET', this.url);\n xhr.withCredentials = this.withCredentials;\n for (var property in this.httpHeaders) {\n var value = this.httpHeaders[property];\n if (typeof value === 'undefined') {\n continue;\n }\n xhr.setRequestHeader(property, value);\n }\n if (this.isHttp && 'begin' in args && 'end' in args) {\n var rangeStr = args.begin + '-' + (args.end - 1);\n xhr.setRequestHeader('Range', 'bytes=' + rangeStr);\n pendingRequest.expectedStatus = 206;\n } else {\n pendingRequest.expectedStatus = 200;\n }\n\n var useMozChunkedLoading = supportsMozChunked && !!args.onProgressiveData;\n if (useMozChunkedLoading) {\n xhr.responseType = 'moz-chunked-arraybuffer';\n pendingRequest.onProgressiveData = args.onProgressiveData;\n pendingRequest.mozChunked = true;\n } else {\n xhr.responseType = 'arraybuffer';\n }\n\n if (args.onError) {\n xhr.onerror = function(evt) {\n args.onError(xhr.status);\n };\n }\n xhr.onreadystatechange = this.onStateChange.bind(this, xhrId);\n xhr.onprogress = this.onProgress.bind(this, xhrId);\n\n pendingRequest.onHeadersReceived = args.onHeadersReceived;\n pendingRequest.onDone = args.onDone;\n pendingRequest.onError = args.onError;\n pendingRequest.onProgress = args.onProgress;\n\n xhr.send(null);\n\n return xhrId;\n },\n\n onProgress: function NetworkManager_onProgress(xhrId, evt) {\n var pendingRequest = this.pendingRequests[xhrId];\n if (!pendingRequest) {\n // Maybe abortRequest was called...\n return;\n }\n\n if (pendingRequest.mozChunked) {\n var chunk = getArrayBuffer(pendingRequest.xhr);\n pendingRequest.onProgressiveData(chunk);\n }\n\n var onProgress = pendingRequest.onProgress;\n if (onProgress) {\n onProgress(evt);\n }\n },\n\n onStateChange: function NetworkManager_onStateChange(xhrId, evt) {\n var pendingRequest = this.pendingRequests[xhrId];\n if (!pendingRequest) {\n // Maybe abortRequest was called...\n return;\n }\n\n var xhr = pendingRequest.xhr;\n if (xhr.readyState >= 2 && pendingRequest.onHeadersReceived) {\n pendingRequest.onHeadersReceived();\n delete pendingRequest.onHeadersReceived;\n }\n\n if (xhr.readyState !== 4) {\n return;\n }\n\n if (!(xhrId in this.pendingRequests)) {\n // The XHR request might have been aborted in onHeadersReceived()\n // callback, in which case we should abort request\n return;\n }\n\n delete this.pendingRequests[xhrId];\n\n // success status == 0 can be on ftp, file and other protocols\n if (xhr.status === 0 && this.isHttp) {\n if (pendingRequest.onError) {\n pendingRequest.onError(xhr.status);\n }\n return;\n }\n var xhrStatus = xhr.status || OK_RESPONSE;\n\n // From http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2:\n // \"A server MAY ignore the Range header\". This means it's possible to\n // get a 200 rather than a 206 response from a range request.\n var ok_response_on_range_request =\n xhrStatus === OK_RESPONSE &&\n pendingRequest.expectedStatus === PARTIAL_CONTENT_RESPONSE;\n\n if (!ok_response_on_range_request &&\n xhrStatus !== pendingRequest.expectedStatus) {\n if (pendingRequest.onError) {\n pendingRequest.onError(xhr.status);\n }\n return;\n }\n\n this.loadedRequests[xhrId] = true;\n\n var chunk = getArrayBuffer(xhr);\n if (xhrStatus === PARTIAL_CONTENT_RESPONSE) {\n var rangeHeader = xhr.getResponseHeader('Content-Range');\n var matches = /bytes (\\d+)-(\\d+)\\/(\\d+)/.exec(rangeHeader);\n var begin = parseInt(matches[1], 10);\n pendingRequest.onDone({\n begin,\n chunk,\n });\n } else if (pendingRequest.onProgressiveData) {\n pendingRequest.onDone(null);\n } else if (chunk) {\n pendingRequest.onDone({\n begin: 0,\n chunk,\n });\n } else if (pendingRequest.onError) {\n pendingRequest.onError(xhr.status);\n }\n },\n\n hasPendingRequests: function NetworkManager_hasPendingRequests() {\n for (var xhrId in this.pendingRequests) {\n return true;\n }\n return false;\n },\n\n getRequestXhr: function NetworkManager_getXhr(xhrId) {\n return this.pendingRequests[xhrId].xhr;\n },\n\n isStreamingRequest: function NetworkManager_isStreamingRequest(xhrId) {\n return !!(this.pendingRequests[xhrId].onProgressiveData);\n },\n\n isPendingRequest: function NetworkManager_isPendingRequest(xhrId) {\n return xhrId in this.pendingRequests;\n },\n\n isLoadedRequest: function NetworkManager_isLoadedRequest(xhrId) {\n return xhrId in this.loadedRequests;\n },\n\n abortAllRequests: function NetworkManager_abortAllRequests() {\n for (var xhrId in this.pendingRequests) {\n this.abortRequest(xhrId | 0);\n }\n },\n\n abortRequest: function NetworkManager_abortRequest(xhrId) {\n var xhr = this.pendingRequests[xhrId].xhr;\n delete this.pendingRequests[xhrId];\n xhr.abort();\n },\n};\n\n/** @implements {IPDFStream} */\nfunction PDFNetworkStream(options) {\n this._options = options;\n var source = options.source;\n this._manager = new NetworkManager(source.url, {\n httpHeaders: source.httpHeaders,\n withCredentials: source.withCredentials,\n });\n this._rangeChunkSize = source.rangeChunkSize;\n this._fullRequestReader = null;\n this._rangeRequestReaders = [];\n}\n\nPDFNetworkStream.prototype = {\n _onRangeRequestReaderClosed:\n function PDFNetworkStream_onRangeRequestReaderClosed(reader) {\n var i = this._rangeRequestReaders.indexOf(reader);\n if (i >= 0) {\n this._rangeRequestReaders.splice(i, 1);\n }\n },\n\n getFullReader: function PDFNetworkStream_getFullReader() {\n assert(!this._fullRequestReader);\n this._fullRequestReader =\n new PDFNetworkStreamFullRequestReader(this._manager, this._options);\n return this._fullRequestReader;\n },\n\n getRangeReader: function PDFNetworkStream_getRangeReader(begin, end) {\n var reader = new PDFNetworkStreamRangeRequestReader(this._manager,\n begin, end);\n reader.onClosed = this._onRangeRequestReaderClosed.bind(this);\n this._rangeRequestReaders.push(reader);\n return reader;\n },\n\n cancelAllRequests: function PDFNetworkStream_cancelAllRequests(reason) {\n if (this._fullRequestReader) {\n this._fullRequestReader.cancel(reason);\n }\n var readers = this._rangeRequestReaders.slice(0);\n readers.forEach(function (reader) {\n reader.cancel(reason);\n });\n },\n};\n\n/** @implements {IPDFStreamReader} */\nfunction PDFNetworkStreamFullRequestReader(manager, options) {\n this._manager = manager;\n\n var source = options.source;\n var args = {\n onHeadersReceived: this._onHeadersReceived.bind(this),\n onProgressiveData: source.disableStream ? null :\n this._onProgressiveData.bind(this),\n onDone: this._onDone.bind(this),\n onError: this._onError.bind(this),\n onProgress: this._onProgress.bind(this),\n };\n this._url = source.url;\n this._fullRequestId = manager.requestFull(args);\n this._headersReceivedCapability = createPromiseCapability();\n this._disableRange = options.disableRange || false;\n this._contentLength = source.length; // optional\n this._rangeChunkSize = source.rangeChunkSize;\n if (!this._rangeChunkSize && !this._disableRange) {\n this._disableRange = true;\n }\n\n this._isStreamingSupported = false;\n this._isRangeSupported = false;\n\n this._cachedChunks = [];\n this._requests = [];\n this._done = false;\n this._storedError = undefined;\n\n this.onProgress = null;\n}\n\nPDFNetworkStreamFullRequestReader.prototype = {\n _validateRangeRequestCapabilities: function\n PDFNetworkStreamFullRequestReader_validateRangeRequestCapabilities() {\n\n if (this._disableRange) {\n return false;\n }\n\n var networkManager = this._manager;\n if (!networkManager.isHttp) {\n return false;\n }\n var fullRequestXhrId = this._fullRequestId;\n var fullRequestXhr = networkManager.getRequestXhr(fullRequestXhrId);\n if (fullRequestXhr.getResponseHeader('Accept-Ranges') !== 'bytes') {\n return false;\n }\n\n var contentEncoding =\n fullRequestXhr.getResponseHeader('Content-Encoding') || 'identity';\n if (contentEncoding !== 'identity') {\n return false;\n }\n\n var length = fullRequestXhr.getResponseHeader('Content-Length');\n length = parseInt(length, 10);\n if (!isInt(length)) {\n return false;\n }\n\n this._contentLength = length; // setting right content length\n\n if (length <= 2 * this._rangeChunkSize) {\n // The file size is smaller than the size of two chunks, so it does\n // not make any sense to abort the request and retry with a range\n // request.\n return false;\n }\n\n return true;\n },\n\n _onHeadersReceived:\n function PDFNetworkStreamFullRequestReader_onHeadersReceived() {\n\n if (this._validateRangeRequestCapabilities()) {\n this._isRangeSupported = true;\n }\n\n var networkManager = this._manager;\n var fullRequestXhrId = this._fullRequestId;\n if (networkManager.isStreamingRequest(fullRequestXhrId)) {\n // We can continue fetching when progressive loading is enabled,\n // and we don't need the autoFetch feature.\n this._isStreamingSupported = true;\n } else if (this._isRangeSupported) {\n // NOTE: by cancelling the full request, and then issuing range\n // requests, there will be an issue for sites where you can only\n // request the pdf once. However, if this is the case, then the\n // server should not be returning that it can support range\n // requests.\n networkManager.abortRequest(fullRequestXhrId);\n }\n\n this._headersReceivedCapability.resolve();\n },\n\n _onProgressiveData:\n function PDFNetworkStreamFullRequestReader_onProgressiveData(chunk) {\n if (this._requests.length > 0) {\n var requestCapability = this._requests.shift();\n requestCapability.resolve({ value: chunk, done: false, });\n } else {\n this._cachedChunks.push(chunk);\n }\n },\n\n _onDone: function PDFNetworkStreamFullRequestReader_onDone(args) {\n if (args) {\n this._onProgressiveData(args.chunk);\n }\n this._done = true;\n if (this._cachedChunks.length > 0) {\n return;\n }\n this._requests.forEach(function (requestCapability) {\n requestCapability.resolve({ value: undefined, done: true, });\n });\n this._requests = [];\n },\n\n _onError: function PDFNetworkStreamFullRequestReader_onError(status) {\n var url = this._url;\n var exception;\n if (status === 404 || status === 0 && /^file:/.test(url)) {\n exception = new MissingPDFException('Missing PDF \"' + url + '\".');\n } else {\n exception = new UnexpectedResponseException(\n 'Unexpected server response (' + status +\n ') while retrieving PDF \"' + url + '\".', status);\n }\n this._storedError = exception;\n this._headersReceivedCapability.reject(exception);\n this._requests.forEach(function (requestCapability) {\n requestCapability.reject(exception);\n });\n this._requests = [];\n this._cachedChunks = [];\n },\n\n _onProgress: function PDFNetworkStreamFullRequestReader_onProgress(data) {\n if (this.onProgress) {\n this.onProgress({\n loaded: data.loaded,\n total: data.lengthComputable ? data.total : this._contentLength,\n });\n }\n },\n\n get isRangeSupported() {\n return this._isRangeSupported;\n },\n\n get isStreamingSupported() {\n return this._isStreamingSupported;\n },\n\n get contentLength() {\n return this._contentLength;\n },\n\n get headersReady() {\n return this._headersReceivedCapability.promise;\n },\n\n read: function PDFNetworkStreamFullRequestReader_read() {\n if (this._storedError) {\n return Promise.reject(this._storedError);\n }\n if (this._cachedChunks.length > 0) {\n var chunk = this._cachedChunks.shift();\n return Promise.resolve({ value: chunk, done: false, });\n }\n if (this._done) {\n return Promise.resolve({ value: undefined, done: true, });\n }\n var requestCapability = createPromiseCapability();\n this._requests.push(requestCapability);\n return requestCapability.promise;\n },\n\n cancel: function PDFNetworkStreamFullRequestReader_cancel(reason) {\n this._done = true;\n this._headersReceivedCapability.reject(reason);\n this._requests.forEach(function (requestCapability) {\n requestCapability.resolve({ value: undefined, done: true, });\n });\n this._requests = [];\n if (this._manager.isPendingRequest(this._fullRequestId)) {\n this._manager.abortRequest(this._fullRequestId);\n }\n this._fullRequestReader = null;\n },\n};\n\n/** @implements {IPDFStreamRangeReader} */\nfunction PDFNetworkStreamRangeRequestReader(manager, begin, end) {\n this._manager = manager;\n var args = {\n onDone: this._onDone.bind(this),\n onProgress: this._onProgress.bind(this),\n };\n this._requestId = manager.requestRange(begin, end, args);\n this._requests = [];\n this._queuedChunk = null;\n this._done = false;\n\n this.onProgress = null;\n this.onClosed = null;\n}\n\nPDFNetworkStreamRangeRequestReader.prototype = {\n _close: function PDFNetworkStreamRangeRequestReader_close() {\n if (this.onClosed) {\n this.onClosed(this);\n }\n },\n\n _onDone: function PDFNetworkStreamRangeRequestReader_onDone(data) {\n var chunk = data.chunk;\n if (this._requests.length > 0) {\n var requestCapability = this._requests.shift();\n requestCapability.resolve({ value: chunk, done: false, });\n } else {\n this._queuedChunk = chunk;\n }\n this._done = true;\n this._requests.forEach(function (requestCapability) {\n requestCapability.resolve({ value: undefined, done: true, });\n });\n this._requests = [];\n this._close();\n },\n\n _onProgress: function PDFNetworkStreamRangeRequestReader_onProgress(evt) {\n if (!this.isStreamingSupported && this.onProgress) {\n this.onProgress({\n loaded: evt.loaded,\n });\n }\n },\n\n get isStreamingSupported() {\n return false; // TODO allow progressive range bytes loading\n },\n\n read: function PDFNetworkStreamRangeRequestReader_read() {\n if (this._queuedChunk !== null) {\n var chunk = this._queuedChunk;\n this._queuedChunk = null;\n return Promise.resolve({ value: chunk, done: false, });\n }\n if (this._done) {\n return Promise.resolve({ value: undefined, done: true, });\n }\n var requestCapability = createPromiseCapability();\n this._requests.push(requestCapability);\n return requestCapability.promise;\n },\n\n cancel: function PDFNetworkStreamRangeRequestReader_cancel(reason) {\n this._done = true;\n this._requests.forEach(function (requestCapability) {\n requestCapability.resolve({ value: undefined, done: true, });\n });\n this._requests = [];\n if (this._manager.isPendingRequest(this._requestId)) {\n this._manager.abortRequest(this._requestId);\n }\n this._close();\n },\n};\n\nsetPDFNetworkStreamClass(PDFNetworkStream);\n\nexport {\n PDFNetworkStream,\n NetworkManager,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/display/network.js", + "/*\n * To the extent possible under law, the authors have dedicated all copyright\n * and related and neighboring rights to this software to the public\n * domain worldwide. This software is distributed without any warranty.\n *\n * You should have received a copy of the CC0 Public Domain Dedication along\n * with this software. If not, see https://creativecommons.org/publicdomain/zero/1.0/.\n */\n\n(function(e, a) { for(var i in a) e[i] = a[i]; }(exports, /******/ (function(modules) { // webpackBootstrap\n/******/ // The module cache\n/******/ var installedModules = {};\n/******/\n/******/ // The require function\n/******/ function __w_pdfjs_require__(moduleId) {\n/******/\n/******/ // Check if module is in cache\n/******/ if(installedModules[moduleId])\n/******/ return installedModules[moduleId].exports;\n/******/\n/******/ // Create a new module (and put it into the cache)\n/******/ var module = installedModules[moduleId] = {\n/******/ i: moduleId,\n/******/ l: false,\n/******/ exports: {}\n/******/ };\n/******/\n/******/ // Execute the module function\n/******/ modules[moduleId].call(module.exports, module, module.exports, __w_pdfjs_require__);\n/******/\n/******/ // Flag the module as loaded\n/******/ module.l = true;\n/******/\n/******/ // Return the exports of the module\n/******/ return module.exports;\n/******/ }\n/******/\n/******/\n/******/ // expose the modules object (__webpack_modules__)\n/******/ __w_pdfjs_require__.m = modules;\n/******/\n/******/ // expose the module cache\n/******/ __w_pdfjs_require__.c = installedModules;\n/******/\n/******/ // identity function for calling harmony imports with the correct context\n/******/ __w_pdfjs_require__.i = function(value) { return value; };\n/******/\n/******/ // define getter function for harmony exports\n/******/ __w_pdfjs_require__.d = function(exports, name, getter) {\n/******/ if(!__w_pdfjs_require__.o(exports, name)) {\n/******/ Object.defineProperty(exports, name, {\n/******/ configurable: false,\n/******/ enumerable: true,\n/******/ get: getter\n/******/ });\n/******/ }\n/******/ };\n/******/\n/******/ // getDefaultExport function for compatibility with non-harmony modules\n/******/ __w_pdfjs_require__.n = function(module) {\n/******/ var getter = module && module.__esModule ?\n/******/ function getDefault() { return module['default']; } :\n/******/ function getModuleExports() { return module; };\n/******/ __w_pdfjs_require__.d(getter, 'a', getter);\n/******/ return getter;\n/******/ };\n/******/\n/******/ // Object.prototype.hasOwnProperty.call\n/******/ __w_pdfjs_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ // __webpack_public_path__\n/******/ __w_pdfjs_require__.p = \"\";\n/******/\n/******/ // Load entry module and return exports\n/******/ return __w_pdfjs_require__(__w_pdfjs_require__.s = 7);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports, __w_pdfjs_require__) {\n\n\"use strict\";\n\n\nvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; };\n\nvar _require = __w_pdfjs_require__(1),\n assert = _require.assert;\n\nfunction IsPropertyKey(argument) {\n return typeof argument === 'string' || (typeof argument === 'undefined' ? 'undefined' : _typeof(argument)) === 'symbol';\n}\n\nexports.typeIsObject = function (x) {\n return (typeof x === 'undefined' ? 'undefined' : _typeof(x)) === 'object' && x !== null || typeof x === 'function';\n};\n\nexports.createDataProperty = function (o, p, v) {\n assert(exports.typeIsObject(o));\n Object.defineProperty(o, p, { value: v, writable: true, enumerable: true, configurable: true });\n};\n\nexports.createArrayFromList = function (elements) {\n // We use arrays to represent lists, so this is basically a no-op.\n // Do a slice though just in case we happen to depend on the unique-ness.\n return elements.slice();\n};\n\nexports.ArrayBufferCopy = function (dest, destOffset, src, srcOffset, n) {\n new Uint8Array(dest).set(new Uint8Array(src, srcOffset, n), destOffset);\n};\n\nexports.CreateIterResultObject = function (value, done) {\n assert(typeof done === 'boolean');\n var obj = {};\n Object.defineProperty(obj, 'value', { value: value, enumerable: true, writable: true, configurable: true });\n Object.defineProperty(obj, 'done', { value: done, enumerable: true, writable: true, configurable: true });\n return obj;\n};\n\nexports.IsFiniteNonNegativeNumber = function (v) {\n if (Number.isNaN(v)) {\n return false;\n }\n if (v === Infinity) {\n return false;\n }\n if (v < 0) {\n return false;\n }\n\n return true;\n};\n\nfunction Call(F, V, args) {\n if (typeof F !== 'function') {\n throw new TypeError('Argument is not a function');\n }\n\n return Function.prototype.apply.call(F, V, args);\n}\n\nexports.InvokeOrNoop = function (O, P, args) {\n assert(O !== undefined);\n assert(IsPropertyKey(P));\n assert(Array.isArray(args));\n\n var method = O[P];\n if (method === undefined) {\n return undefined;\n }\n\n return Call(method, O, args);\n};\n\nexports.PromiseInvokeOrNoop = function (O, P, args) {\n assert(O !== undefined);\n assert(IsPropertyKey(P));\n assert(Array.isArray(args));\n try {\n return Promise.resolve(exports.InvokeOrNoop(O, P, args));\n } catch (returnValueE) {\n return Promise.reject(returnValueE);\n }\n};\n\nexports.PromiseInvokeOrPerformFallback = function (O, P, args, F, argsF) {\n assert(O !== undefined);\n assert(IsPropertyKey(P));\n assert(Array.isArray(args));\n assert(Array.isArray(argsF));\n\n var method = void 0;\n try {\n method = O[P];\n } catch (methodE) {\n return Promise.reject(methodE);\n }\n\n if (method === undefined) {\n return F.apply(null, argsF);\n }\n\n try {\n return Promise.resolve(Call(method, O, args));\n } catch (e) {\n return Promise.reject(e);\n }\n};\n\n// Not implemented correctly\nexports.TransferArrayBuffer = function (O) {\n return O.slice();\n};\n\nexports.ValidateAndNormalizeHighWaterMark = function (highWaterMark) {\n highWaterMark = Number(highWaterMark);\n if (Number.isNaN(highWaterMark) || highWaterMark < 0) {\n throw new RangeError('highWaterMark property of a queuing strategy must be non-negative and non-NaN');\n }\n\n return highWaterMark;\n};\n\nexports.ValidateAndNormalizeQueuingStrategy = function (size, highWaterMark) {\n if (size !== undefined && typeof size !== 'function') {\n throw new TypeError('size property of a queuing strategy must be a function');\n }\n\n highWaterMark = exports.ValidateAndNormalizeHighWaterMark(highWaterMark);\n\n return { size: size, highWaterMark: highWaterMark };\n};\n\n/***/ }),\n/* 1 */\n/***/ (function(module, exports, __w_pdfjs_require__) {\n\n\"use strict\";\n\n\nfunction rethrowAssertionErrorRejection(e) {\n // Used throughout the reference implementation, as `.catch(rethrowAssertionErrorRejection)`, to ensure any errors\n // get shown. There are places in the spec where we do promise transformations and purposefully ignore or don't\n // expect any errors, but assertion errors are always problematic.\n if (e && e.constructor === AssertionError) {\n setTimeout(function () {\n throw e;\n }, 0);\n }\n};\n\nfunction AssertionError(message) {\n this.name = 'AssertionError';\n this.message = message || '';\n this.stack = new Error().stack;\n}\nAssertionError.prototype = Object.create(Error.prototype);\nAssertionError.prototype.constructor = AssertionError;\n\nfunction assert(value, message) {\n if (!value) {\n throw new AssertionError(message);\n }\n}\n\nmodule.exports = {\n rethrowAssertionErrorRejection: rethrowAssertionErrorRejection,\n AssertionError: AssertionError,\n assert: assert\n};\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports, __w_pdfjs_require__) {\n\n\"use strict\";\n\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar _require = __w_pdfjs_require__(0),\n InvokeOrNoop = _require.InvokeOrNoop,\n PromiseInvokeOrNoop = _require.PromiseInvokeOrNoop,\n ValidateAndNormalizeQueuingStrategy = _require.ValidateAndNormalizeQueuingStrategy,\n typeIsObject = _require.typeIsObject;\n\nvar _require2 = __w_pdfjs_require__(1),\n assert = _require2.assert,\n rethrowAssertionErrorRejection = _require2.rethrowAssertionErrorRejection;\n\nvar _require3 = __w_pdfjs_require__(3),\n DequeueValue = _require3.DequeueValue,\n EnqueueValueWithSize = _require3.EnqueueValueWithSize,\n PeekQueueValue = _require3.PeekQueueValue,\n ResetQueue = _require3.ResetQueue;\n\nvar WritableStream = function () {\n function WritableStream() {\n var underlyingSink = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n size = _ref.size,\n _ref$highWaterMark = _ref.highWaterMark,\n highWaterMark = _ref$highWaterMark === undefined ? 1 : _ref$highWaterMark;\n\n _classCallCheck(this, WritableStream);\n\n this._state = 'writable';\n\n // The error that will be reported by new method calls once the state becomes errored. Only set when [[state]] is\n // 'erroring' or 'errored'. May be set to an undefined value.\n this._storedError = undefined;\n\n this._writer = undefined;\n\n // Initialize to undefined first because the constructor of the controller checks this\n // variable to validate the caller.\n this._writableStreamController = undefined;\n\n // This queue is placed here instead of the writer class in order to allow for passing a writer to the next data\n // producer without waiting for the queued writes to finish.\n this._writeRequests = [];\n\n // Write requests are removed from _writeRequests when write() is called on the underlying sink. This prevents\n // them from being erroneously rejected on error. If a write() call is in-flight, the request is stored here.\n this._inFlightWriteRequest = undefined;\n\n // The promise that was returned from writer.close(). Stored here because it may be fulfilled after the writer\n // has been detached.\n this._closeRequest = undefined;\n\n // Close request is removed from _closeRequest when close() is called on the underlying sink. This prevents it\n // from being erroneously rejected on error. If a close() call is in-flight, the request is stored here.\n this._inFlightCloseRequest = undefined;\n\n // The promise that was returned from writer.abort(). This may also be fulfilled after the writer has detached.\n this._pendingAbortRequest = undefined;\n\n // The backpressure signal set by the controller.\n this._backpressure = false;\n\n var type = underlyingSink.type;\n\n if (type !== undefined) {\n throw new RangeError('Invalid type is specified');\n }\n\n this._writableStreamController = new WritableStreamDefaultController(this, underlyingSink, size, highWaterMark);\n this._writableStreamController.__startSteps();\n }\n\n _createClass(WritableStream, [{\n key: 'abort',\n value: function abort(reason) {\n if (IsWritableStream(this) === false) {\n return Promise.reject(streamBrandCheckException('abort'));\n }\n\n if (IsWritableStreamLocked(this) === true) {\n return Promise.reject(new TypeError('Cannot abort a stream that already has a writer'));\n }\n\n return WritableStreamAbort(this, reason);\n }\n }, {\n key: 'getWriter',\n value: function getWriter() {\n if (IsWritableStream(this) === false) {\n throw streamBrandCheckException('getWriter');\n }\n\n return AcquireWritableStreamDefaultWriter(this);\n }\n }, {\n key: 'locked',\n get: function get() {\n if (IsWritableStream(this) === false) {\n throw streamBrandCheckException('locked');\n }\n\n return IsWritableStreamLocked(this);\n }\n }]);\n\n return WritableStream;\n}();\n\nmodule.exports = {\n AcquireWritableStreamDefaultWriter: AcquireWritableStreamDefaultWriter,\n IsWritableStream: IsWritableStream,\n IsWritableStreamLocked: IsWritableStreamLocked,\n WritableStream: WritableStream,\n WritableStreamAbort: WritableStreamAbort,\n WritableStreamDefaultControllerError: WritableStreamDefaultControllerError,\n WritableStreamDefaultWriterCloseWithErrorPropagation: WritableStreamDefaultWriterCloseWithErrorPropagation,\n WritableStreamDefaultWriterRelease: WritableStreamDefaultWriterRelease,\n WritableStreamDefaultWriterWrite: WritableStreamDefaultWriterWrite,\n WritableStreamCloseQueuedOrInFlight: WritableStreamCloseQueuedOrInFlight\n};\n\n// Abstract operations for the WritableStream.\n\nfunction AcquireWritableStreamDefaultWriter(stream) {\n return new WritableStreamDefaultWriter(stream);\n}\n\nfunction IsWritableStream(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_writableStreamController')) {\n return false;\n }\n\n return true;\n}\n\nfunction IsWritableStreamLocked(stream) {\n assert(IsWritableStream(stream) === true, 'IsWritableStreamLocked should only be used on known writable streams');\n\n if (stream._writer === undefined) {\n return false;\n }\n\n return true;\n}\n\nfunction WritableStreamAbort(stream, reason) {\n var state = stream._state;\n if (state === 'closed') {\n return Promise.resolve(undefined);\n }\n if (state === 'errored') {\n return Promise.reject(stream._storedError);\n }\n var error = new TypeError('Requested to abort');\n if (stream._pendingAbortRequest !== undefined) {\n return Promise.reject(error);\n }\n\n assert(state === 'writable' || state === 'erroring', 'state must be writable or erroring');\n\n var wasAlreadyErroring = false;\n if (state === 'erroring') {\n wasAlreadyErroring = true;\n // reason will not be used, so don't keep a reference to it.\n reason = undefined;\n }\n\n var promise = new Promise(function (resolve, reject) {\n stream._pendingAbortRequest = {\n _resolve: resolve,\n _reject: reject,\n _reason: reason,\n _wasAlreadyErroring: wasAlreadyErroring\n };\n });\n\n if (wasAlreadyErroring === false) {\n WritableStreamStartErroring(stream, error);\n }\n\n return promise;\n}\n\n// WritableStream API exposed for controllers.\n\nfunction WritableStreamAddWriteRequest(stream) {\n assert(IsWritableStreamLocked(stream) === true);\n assert(stream._state === 'writable');\n\n var promise = new Promise(function (resolve, reject) {\n var writeRequest = {\n _resolve: resolve,\n _reject: reject\n };\n\n stream._writeRequests.push(writeRequest);\n });\n\n return promise;\n}\n\nfunction WritableStreamDealWithRejection(stream, error) {\n var state = stream._state;\n\n if (state === 'writable') {\n WritableStreamStartErroring(stream, error);\n return;\n }\n\n assert(state === 'erroring');\n WritableStreamFinishErroring(stream);\n}\n\nfunction WritableStreamStartErroring(stream, reason) {\n assert(stream._storedError === undefined, 'stream._storedError === undefined');\n assert(stream._state === 'writable', 'state must be writable');\n\n var controller = stream._writableStreamController;\n assert(controller !== undefined, 'controller must not be undefined');\n\n stream._state = 'erroring';\n stream._storedError = reason;\n var writer = stream._writer;\n if (writer !== undefined) {\n WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason);\n }\n\n if (WritableStreamHasOperationMarkedInFlight(stream) === false && controller._started === true) {\n WritableStreamFinishErroring(stream);\n }\n}\n\nfunction WritableStreamFinishErroring(stream) {\n assert(stream._state === 'erroring', 'stream._state === erroring');\n assert(WritableStreamHasOperationMarkedInFlight(stream) === false, 'WritableStreamHasOperationMarkedInFlight(stream) === false');\n stream._state = 'errored';\n stream._writableStreamController.__errorSteps();\n\n var storedError = stream._storedError;\n for (var i = 0; i < stream._writeRequests.length; i++) {\n var writeRequest = stream._writeRequests[i];\n writeRequest._reject(storedError);\n }\n stream._writeRequests = [];\n\n if (stream._pendingAbortRequest === undefined) {\n WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);\n return;\n }\n\n var abortRequest = stream._pendingAbortRequest;\n stream._pendingAbortRequest = undefined;\n\n if (abortRequest._wasAlreadyErroring === true) {\n abortRequest._reject(storedError);\n WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);\n return;\n }\n\n var promise = stream._writableStreamController.__abortSteps(abortRequest._reason);\n promise.then(function () {\n abortRequest._resolve();\n WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);\n }, function (reason) {\n abortRequest._reject(reason);\n WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);\n });\n}\n\nfunction WritableStreamFinishInFlightWrite(stream) {\n assert(stream._inFlightWriteRequest !== undefined);\n stream._inFlightWriteRequest._resolve(undefined);\n stream._inFlightWriteRequest = undefined;\n}\n\nfunction WritableStreamFinishInFlightWriteWithError(stream, error) {\n assert(stream._inFlightWriteRequest !== undefined);\n stream._inFlightWriteRequest._reject(error);\n stream._inFlightWriteRequest = undefined;\n\n assert(stream._state === 'writable' || stream._state === 'erroring');\n\n WritableStreamDealWithRejection(stream, error);\n}\n\nfunction WritableStreamFinishInFlightClose(stream) {\n assert(stream._inFlightCloseRequest !== undefined);\n stream._inFlightCloseRequest._resolve(undefined);\n stream._inFlightCloseRequest = undefined;\n\n var state = stream._state;\n\n assert(state === 'writable' || state === 'erroring');\n\n if (state === 'erroring') {\n // The error was too late to do anything, so it is ignored.\n stream._storedError = undefined;\n if (stream._pendingAbortRequest !== undefined) {\n stream._pendingAbortRequest._resolve();\n stream._pendingAbortRequest = undefined;\n }\n }\n\n stream._state = 'closed';\n\n var writer = stream._writer;\n if (writer !== undefined) {\n defaultWriterClosedPromiseResolve(writer);\n }\n\n assert(stream._pendingAbortRequest === undefined, 'stream._pendingAbortRequest === undefined');\n assert(stream._storedError === undefined, 'stream._storedError === undefined');\n}\n\nfunction WritableStreamFinishInFlightCloseWithError(stream, error) {\n assert(stream._inFlightCloseRequest !== undefined);\n stream._inFlightCloseRequest._reject(error);\n stream._inFlightCloseRequest = undefined;\n\n assert(stream._state === 'writable' || stream._state === 'erroring');\n\n // Never execute sink abort() after sink close().\n if (stream._pendingAbortRequest !== undefined) {\n stream._pendingAbortRequest._reject(error);\n stream._pendingAbortRequest = undefined;\n }\n WritableStreamDealWithRejection(stream, error);\n}\n\n// TODO(ricea): Fix alphabetical order.\nfunction WritableStreamCloseQueuedOrInFlight(stream) {\n if (stream._closeRequest === undefined && stream._inFlightCloseRequest === undefined) {\n return false;\n }\n\n return true;\n}\n\nfunction WritableStreamHasOperationMarkedInFlight(stream) {\n if (stream._inFlightWriteRequest === undefined && stream._inFlightCloseRequest === undefined) {\n return false;\n }\n\n return true;\n}\n\nfunction WritableStreamMarkCloseRequestInFlight(stream) {\n assert(stream._inFlightCloseRequest === undefined);\n assert(stream._closeRequest !== undefined);\n stream._inFlightCloseRequest = stream._closeRequest;\n stream._closeRequest = undefined;\n}\n\nfunction WritableStreamMarkFirstWriteRequestInFlight(stream) {\n assert(stream._inFlightWriteRequest === undefined, 'there must be no pending write request');\n assert(stream._writeRequests.length !== 0, 'writeRequests must not be empty');\n stream._inFlightWriteRequest = stream._writeRequests.shift();\n}\n\nfunction WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream) {\n assert(stream._state === 'errored', '_stream_.[[state]] is `\"errored\"`');\n if (stream._closeRequest !== undefined) {\n assert(stream._inFlightCloseRequest === undefined);\n\n stream._closeRequest._reject(stream._storedError);\n stream._closeRequest = undefined;\n }\n var writer = stream._writer;\n if (writer !== undefined) {\n defaultWriterClosedPromiseReject(writer, stream._storedError);\n writer._closedPromise.catch(function () {});\n }\n}\n\nfunction WritableStreamUpdateBackpressure(stream, backpressure) {\n assert(stream._state === 'writable');\n assert(WritableStreamCloseQueuedOrInFlight(stream) === false);\n\n var writer = stream._writer;\n if (writer !== undefined && backpressure !== stream._backpressure) {\n if (backpressure === true) {\n defaultWriterReadyPromiseReset(writer);\n } else {\n assert(backpressure === false);\n\n defaultWriterReadyPromiseResolve(writer);\n }\n }\n\n stream._backpressure = backpressure;\n}\n\nvar WritableStreamDefaultWriter = function () {\n function WritableStreamDefaultWriter(stream) {\n _classCallCheck(this, WritableStreamDefaultWriter);\n\n if (IsWritableStream(stream) === false) {\n throw new TypeError('WritableStreamDefaultWriter can only be constructed with a WritableStream instance');\n }\n if (IsWritableStreamLocked(stream) === true) {\n throw new TypeError('This stream has already been locked for exclusive writing by another writer');\n }\n\n this._ownerWritableStream = stream;\n stream._writer = this;\n\n var state = stream._state;\n\n if (state === 'writable') {\n if (WritableStreamCloseQueuedOrInFlight(stream) === false && stream._backpressure === true) {\n defaultWriterReadyPromiseInitialize(this);\n } else {\n defaultWriterReadyPromiseInitializeAsResolved(this);\n }\n\n defaultWriterClosedPromiseInitialize(this);\n } else if (state === 'erroring') {\n defaultWriterReadyPromiseInitializeAsRejected(this, stream._storedError);\n this._readyPromise.catch(function () {});\n defaultWriterClosedPromiseInitialize(this);\n } else if (state === 'closed') {\n defaultWriterReadyPromiseInitializeAsResolved(this);\n defaultWriterClosedPromiseInitializeAsResolved(this);\n } else {\n assert(state === 'errored', 'state must be errored');\n\n var storedError = stream._storedError;\n defaultWriterReadyPromiseInitializeAsRejected(this, storedError);\n this._readyPromise.catch(function () {});\n defaultWriterClosedPromiseInitializeAsRejected(this, storedError);\n this._closedPromise.catch(function () {});\n }\n }\n\n _createClass(WritableStreamDefaultWriter, [{\n key: 'abort',\n value: function abort(reason) {\n if (IsWritableStreamDefaultWriter(this) === false) {\n return Promise.reject(defaultWriterBrandCheckException('abort'));\n }\n\n if (this._ownerWritableStream === undefined) {\n return Promise.reject(defaultWriterLockException('abort'));\n }\n\n return WritableStreamDefaultWriterAbort(this, reason);\n }\n }, {\n key: 'close',\n value: function close() {\n if (IsWritableStreamDefaultWriter(this) === false) {\n return Promise.reject(defaultWriterBrandCheckException('close'));\n }\n\n var stream = this._ownerWritableStream;\n\n if (stream === undefined) {\n return Promise.reject(defaultWriterLockException('close'));\n }\n\n if (WritableStreamCloseQueuedOrInFlight(stream) === true) {\n return Promise.reject(new TypeError('cannot close an already-closing stream'));\n }\n\n return WritableStreamDefaultWriterClose(this);\n }\n }, {\n key: 'releaseLock',\n value: function releaseLock() {\n if (IsWritableStreamDefaultWriter(this) === false) {\n throw defaultWriterBrandCheckException('releaseLock');\n }\n\n var stream = this._ownerWritableStream;\n\n if (stream === undefined) {\n return;\n }\n\n assert(stream._writer !== undefined);\n\n WritableStreamDefaultWriterRelease(this);\n }\n }, {\n key: 'write',\n value: function write(chunk) {\n if (IsWritableStreamDefaultWriter(this) === false) {\n return Promise.reject(defaultWriterBrandCheckException('write'));\n }\n\n if (this._ownerWritableStream === undefined) {\n return Promise.reject(defaultWriterLockException('write to'));\n }\n\n return WritableStreamDefaultWriterWrite(this, chunk);\n }\n }, {\n key: 'closed',\n get: function get() {\n if (IsWritableStreamDefaultWriter(this) === false) {\n return Promise.reject(defaultWriterBrandCheckException('closed'));\n }\n\n return this._closedPromise;\n }\n }, {\n key: 'desiredSize',\n get: function get() {\n if (IsWritableStreamDefaultWriter(this) === false) {\n throw defaultWriterBrandCheckException('desiredSize');\n }\n\n if (this._ownerWritableStream === undefined) {\n throw defaultWriterLockException('desiredSize');\n }\n\n return WritableStreamDefaultWriterGetDesiredSize(this);\n }\n }, {\n key: 'ready',\n get: function get() {\n if (IsWritableStreamDefaultWriter(this) === false) {\n return Promise.reject(defaultWriterBrandCheckException('ready'));\n }\n\n return this._readyPromise;\n }\n }]);\n\n return WritableStreamDefaultWriter;\n}();\n\n// Abstract operations for the WritableStreamDefaultWriter.\n\nfunction IsWritableStreamDefaultWriter(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_ownerWritableStream')) {\n return false;\n }\n\n return true;\n}\n\n// A client of WritableStreamDefaultWriter may use these functions directly to bypass state check.\n\nfunction WritableStreamDefaultWriterAbort(writer, reason) {\n var stream = writer._ownerWritableStream;\n\n assert(stream !== undefined);\n\n return WritableStreamAbort(stream, reason);\n}\n\nfunction WritableStreamDefaultWriterClose(writer) {\n var stream = writer._ownerWritableStream;\n\n assert(stream !== undefined);\n\n var state = stream._state;\n if (state === 'closed' || state === 'errored') {\n return Promise.reject(new TypeError('The stream (in ' + state + ' state) is not in the writable state and cannot be closed'));\n }\n\n assert(state === 'writable' || state === 'erroring');\n assert(WritableStreamCloseQueuedOrInFlight(stream) === false);\n\n var promise = new Promise(function (resolve, reject) {\n var closeRequest = {\n _resolve: resolve,\n _reject: reject\n };\n\n stream._closeRequest = closeRequest;\n });\n\n if (stream._backpressure === true && state === 'writable') {\n defaultWriterReadyPromiseResolve(writer);\n }\n\n WritableStreamDefaultControllerClose(stream._writableStreamController);\n\n return promise;\n}\n\nfunction WritableStreamDefaultWriterCloseWithErrorPropagation(writer) {\n var stream = writer._ownerWritableStream;\n\n assert(stream !== undefined);\n\n var state = stream._state;\n if (WritableStreamCloseQueuedOrInFlight(stream) === true || state === 'closed') {\n return Promise.resolve();\n }\n\n if (state === 'errored') {\n return Promise.reject(stream._storedError);\n }\n\n assert(state === 'writable' || state === 'erroring');\n\n return WritableStreamDefaultWriterClose(writer);\n}\n\nfunction WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, error) {\n if (writer._closedPromiseState === 'pending') {\n defaultWriterClosedPromiseReject(writer, error);\n } else {\n defaultWriterClosedPromiseResetToRejected(writer, error);\n }\n writer._closedPromise.catch(function () {});\n}\n\nfunction WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, error) {\n if (writer._readyPromiseState === 'pending') {\n defaultWriterReadyPromiseReject(writer, error);\n } else {\n defaultWriterReadyPromiseResetToRejected(writer, error);\n }\n writer._readyPromise.catch(function () {});\n}\n\nfunction WritableStreamDefaultWriterGetDesiredSize(writer) {\n var stream = writer._ownerWritableStream;\n var state = stream._state;\n\n if (state === 'errored' || state === 'erroring') {\n return null;\n }\n\n if (state === 'closed') {\n return 0;\n }\n\n return WritableStreamDefaultControllerGetDesiredSize(stream._writableStreamController);\n}\n\nfunction WritableStreamDefaultWriterRelease(writer) {\n var stream = writer._ownerWritableStream;\n assert(stream !== undefined);\n assert(stream._writer === writer);\n\n var releasedError = new TypeError('Writer was released and can no longer be used to monitor the stream\\'s closedness');\n\n WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, releasedError);\n\n // The state transitions to \"errored\" before the sink abort() method runs, but the writer.closed promise is not\n // rejected until afterwards. This means that simply testing state will not work.\n WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, releasedError);\n\n stream._writer = undefined;\n writer._ownerWritableStream = undefined;\n}\n\nfunction WritableStreamDefaultWriterWrite(writer, chunk) {\n var stream = writer._ownerWritableStream;\n\n assert(stream !== undefined);\n\n var controller = stream._writableStreamController;\n\n var chunkSize = WritableStreamDefaultControllerGetChunkSize(controller, chunk);\n\n if (stream !== writer._ownerWritableStream) {\n return Promise.reject(defaultWriterLockException('write to'));\n }\n\n var state = stream._state;\n if (state === 'errored') {\n return Promise.reject(stream._storedError);\n }\n if (WritableStreamCloseQueuedOrInFlight(stream) === true || state === 'closed') {\n return Promise.reject(new TypeError('The stream is closing or closed and cannot be written to'));\n }\n if (state === 'erroring') {\n return Promise.reject(stream._storedError);\n }\n\n assert(state === 'writable');\n\n var promise = WritableStreamAddWriteRequest(stream);\n\n WritableStreamDefaultControllerWrite(controller, chunk, chunkSize);\n\n return promise;\n}\n\nvar WritableStreamDefaultController = function () {\n function WritableStreamDefaultController(stream, underlyingSink, size, highWaterMark) {\n _classCallCheck(this, WritableStreamDefaultController);\n\n if (IsWritableStream(stream) === false) {\n throw new TypeError('WritableStreamDefaultController can only be constructed with a WritableStream instance');\n }\n\n if (stream._writableStreamController !== undefined) {\n throw new TypeError('WritableStreamDefaultController instances can only be created by the WritableStream constructor');\n }\n\n this._controlledWritableStream = stream;\n\n this._underlyingSink = underlyingSink;\n\n // Need to set the slots so that the assert doesn't fire. In the spec the slots already exist implicitly.\n this._queue = undefined;\n this._queueTotalSize = undefined;\n ResetQueue(this);\n\n this._started = false;\n\n var normalizedStrategy = ValidateAndNormalizeQueuingStrategy(size, highWaterMark);\n this._strategySize = normalizedStrategy.size;\n this._strategyHWM = normalizedStrategy.highWaterMark;\n\n var backpressure = WritableStreamDefaultControllerGetBackpressure(this);\n WritableStreamUpdateBackpressure(stream, backpressure);\n }\n\n _createClass(WritableStreamDefaultController, [{\n key: 'error',\n value: function error(e) {\n if (IsWritableStreamDefaultController(this) === false) {\n throw new TypeError('WritableStreamDefaultController.prototype.error can only be used on a WritableStreamDefaultController');\n }\n var state = this._controlledWritableStream._state;\n if (state !== 'writable') {\n // The stream is closed, errored or will be soon. The sink can't do anything useful if it gets an error here, so\n // just treat it as a no-op.\n return;\n }\n\n WritableStreamDefaultControllerError(this, e);\n }\n }, {\n key: '__abortSteps',\n value: function __abortSteps(reason) {\n return PromiseInvokeOrNoop(this._underlyingSink, 'abort', [reason]);\n }\n }, {\n key: '__errorSteps',\n value: function __errorSteps() {\n ResetQueue(this);\n }\n }, {\n key: '__startSteps',\n value: function __startSteps() {\n var _this = this;\n\n var startResult = InvokeOrNoop(this._underlyingSink, 'start', [this]);\n var stream = this._controlledWritableStream;\n\n Promise.resolve(startResult).then(function () {\n assert(stream._state === 'writable' || stream._state === 'erroring');\n _this._started = true;\n WritableStreamDefaultControllerAdvanceQueueIfNeeded(_this);\n }, function (r) {\n assert(stream._state === 'writable' || stream._state === 'erroring');\n _this._started = true;\n WritableStreamDealWithRejection(stream, r);\n }).catch(rethrowAssertionErrorRejection);\n }\n }]);\n\n return WritableStreamDefaultController;\n}();\n\n// Abstract operations implementing interface required by the WritableStream.\n\nfunction WritableStreamDefaultControllerClose(controller) {\n EnqueueValueWithSize(controller, 'close', 0);\n WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);\n}\n\nfunction WritableStreamDefaultControllerGetChunkSize(controller, chunk) {\n var strategySize = controller._strategySize;\n\n if (strategySize === undefined) {\n return 1;\n }\n\n try {\n return strategySize(chunk);\n } catch (chunkSizeE) {\n WritableStreamDefaultControllerErrorIfNeeded(controller, chunkSizeE);\n return 1;\n }\n}\n\nfunction WritableStreamDefaultControllerGetDesiredSize(controller) {\n return controller._strategyHWM - controller._queueTotalSize;\n}\n\nfunction WritableStreamDefaultControllerWrite(controller, chunk, chunkSize) {\n var writeRecord = { chunk: chunk };\n\n try {\n EnqueueValueWithSize(controller, writeRecord, chunkSize);\n } catch (enqueueE) {\n WritableStreamDefaultControllerErrorIfNeeded(controller, enqueueE);\n return;\n }\n\n var stream = controller._controlledWritableStream;\n if (WritableStreamCloseQueuedOrInFlight(stream) === false && stream._state === 'writable') {\n var backpressure = WritableStreamDefaultControllerGetBackpressure(controller);\n WritableStreamUpdateBackpressure(stream, backpressure);\n }\n\n WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);\n}\n\n// Abstract operations for the WritableStreamDefaultController.\n\nfunction IsWritableStreamDefaultController(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_underlyingSink')) {\n return false;\n }\n\n return true;\n}\n\nfunction WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller) {\n var stream = controller._controlledWritableStream;\n\n if (controller._started === false) {\n return;\n }\n\n if (stream._inFlightWriteRequest !== undefined) {\n return;\n }\n\n var state = stream._state;\n if (state === 'closed' || state === 'errored') {\n return;\n }\n if (state === 'erroring') {\n WritableStreamFinishErroring(stream);\n return;\n }\n\n if (controller._queue.length === 0) {\n return;\n }\n\n var writeRecord = PeekQueueValue(controller);\n if (writeRecord === 'close') {\n WritableStreamDefaultControllerProcessClose(controller);\n } else {\n WritableStreamDefaultControllerProcessWrite(controller, writeRecord.chunk);\n }\n}\n\nfunction WritableStreamDefaultControllerErrorIfNeeded(controller, error) {\n if (controller._controlledWritableStream._state === 'writable') {\n WritableStreamDefaultControllerError(controller, error);\n }\n}\n\nfunction WritableStreamDefaultControllerProcessClose(controller) {\n var stream = controller._controlledWritableStream;\n\n WritableStreamMarkCloseRequestInFlight(stream);\n\n DequeueValue(controller);\n assert(controller._queue.length === 0, 'queue must be empty once the final write record is dequeued');\n\n var sinkClosePromise = PromiseInvokeOrNoop(controller._underlyingSink, 'close', []);\n sinkClosePromise.then(function () {\n WritableStreamFinishInFlightClose(stream);\n }, function (reason) {\n WritableStreamFinishInFlightCloseWithError(stream, reason);\n }).catch(rethrowAssertionErrorRejection);\n}\n\nfunction WritableStreamDefaultControllerProcessWrite(controller, chunk) {\n var stream = controller._controlledWritableStream;\n\n WritableStreamMarkFirstWriteRequestInFlight(stream);\n\n var sinkWritePromise = PromiseInvokeOrNoop(controller._underlyingSink, 'write', [chunk, controller]);\n sinkWritePromise.then(function () {\n WritableStreamFinishInFlightWrite(stream);\n\n var state = stream._state;\n assert(state === 'writable' || state === 'erroring');\n\n DequeueValue(controller);\n\n if (WritableStreamCloseQueuedOrInFlight(stream) === false && state === 'writable') {\n var backpressure = WritableStreamDefaultControllerGetBackpressure(controller);\n WritableStreamUpdateBackpressure(stream, backpressure);\n }\n\n WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);\n }, function (reason) {\n WritableStreamFinishInFlightWriteWithError(stream, reason);\n }).catch(rethrowAssertionErrorRejection);\n}\n\nfunction WritableStreamDefaultControllerGetBackpressure(controller) {\n var desiredSize = WritableStreamDefaultControllerGetDesiredSize(controller);\n return desiredSize <= 0;\n}\n\n// A client of WritableStreamDefaultController may use these functions directly to bypass state check.\n\nfunction WritableStreamDefaultControllerError(controller, error) {\n var stream = controller._controlledWritableStream;\n\n assert(stream._state === 'writable');\n\n WritableStreamStartErroring(stream, error);\n}\n\n// Helper functions for the WritableStream.\n\nfunction streamBrandCheckException(name) {\n return new TypeError('WritableStream.prototype.' + name + ' can only be used on a WritableStream');\n}\n\n// Helper functions for the WritableStreamDefaultWriter.\n\nfunction defaultWriterBrandCheckException(name) {\n return new TypeError('WritableStreamDefaultWriter.prototype.' + name + ' can only be used on a WritableStreamDefaultWriter');\n}\n\nfunction defaultWriterLockException(name) {\n return new TypeError('Cannot ' + name + ' a stream using a released writer');\n}\n\nfunction defaultWriterClosedPromiseInitialize(writer) {\n writer._closedPromise = new Promise(function (resolve, reject) {\n writer._closedPromise_resolve = resolve;\n writer._closedPromise_reject = reject;\n writer._closedPromiseState = 'pending';\n });\n}\n\nfunction defaultWriterClosedPromiseInitializeAsRejected(writer, reason) {\n writer._closedPromise = Promise.reject(reason);\n writer._closedPromise_resolve = undefined;\n writer._closedPromise_reject = undefined;\n writer._closedPromiseState = 'rejected';\n}\n\nfunction defaultWriterClosedPromiseInitializeAsResolved(writer) {\n writer._closedPromise = Promise.resolve(undefined);\n writer._closedPromise_resolve = undefined;\n writer._closedPromise_reject = undefined;\n writer._closedPromiseState = 'resolved';\n}\n\nfunction defaultWriterClosedPromiseReject(writer, reason) {\n assert(writer._closedPromise_resolve !== undefined, 'writer._closedPromise_resolve !== undefined');\n assert(writer._closedPromise_reject !== undefined, 'writer._closedPromise_reject !== undefined');\n assert(writer._closedPromiseState === 'pending', 'writer._closedPromiseState is pending');\n\n writer._closedPromise_reject(reason);\n writer._closedPromise_resolve = undefined;\n writer._closedPromise_reject = undefined;\n writer._closedPromiseState = 'rejected';\n}\n\nfunction defaultWriterClosedPromiseResetToRejected(writer, reason) {\n assert(writer._closedPromise_resolve === undefined, 'writer._closedPromise_resolve === undefined');\n assert(writer._closedPromise_reject === undefined, 'writer._closedPromise_reject === undefined');\n assert(writer._closedPromiseState !== 'pending', 'writer._closedPromiseState is not pending');\n\n writer._closedPromise = Promise.reject(reason);\n writer._closedPromiseState = 'rejected';\n}\n\nfunction defaultWriterClosedPromiseResolve(writer) {\n assert(writer._closedPromise_resolve !== undefined, 'writer._closedPromise_resolve !== undefined');\n assert(writer._closedPromise_reject !== undefined, 'writer._closedPromise_reject !== undefined');\n assert(writer._closedPromiseState === 'pending', 'writer._closedPromiseState is pending');\n\n writer._closedPromise_resolve(undefined);\n writer._closedPromise_resolve = undefined;\n writer._closedPromise_reject = undefined;\n writer._closedPromiseState = 'resolved';\n}\n\nfunction defaultWriterReadyPromiseInitialize(writer) {\n writer._readyPromise = new Promise(function (resolve, reject) {\n writer._readyPromise_resolve = resolve;\n writer._readyPromise_reject = reject;\n });\n writer._readyPromiseState = 'pending';\n}\n\nfunction defaultWriterReadyPromiseInitializeAsRejected(writer, reason) {\n writer._readyPromise = Promise.reject(reason);\n writer._readyPromise_resolve = undefined;\n writer._readyPromise_reject = undefined;\n writer._readyPromiseState = 'rejected';\n}\n\nfunction defaultWriterReadyPromiseInitializeAsResolved(writer) {\n writer._readyPromise = Promise.resolve(undefined);\n writer._readyPromise_resolve = undefined;\n writer._readyPromise_reject = undefined;\n writer._readyPromiseState = 'fulfilled';\n}\n\nfunction defaultWriterReadyPromiseReject(writer, reason) {\n assert(writer._readyPromise_resolve !== undefined, 'writer._readyPromise_resolve !== undefined');\n assert(writer._readyPromise_reject !== undefined, 'writer._readyPromise_reject !== undefined');\n\n writer._readyPromise_reject(reason);\n writer._readyPromise_resolve = undefined;\n writer._readyPromise_reject = undefined;\n writer._readyPromiseState = 'rejected';\n}\n\nfunction defaultWriterReadyPromiseReset(writer) {\n assert(writer._readyPromise_resolve === undefined, 'writer._readyPromise_resolve === undefined');\n assert(writer._readyPromise_reject === undefined, 'writer._readyPromise_reject === undefined');\n\n writer._readyPromise = new Promise(function (resolve, reject) {\n writer._readyPromise_resolve = resolve;\n writer._readyPromise_reject = reject;\n });\n writer._readyPromiseState = 'pending';\n}\n\nfunction defaultWriterReadyPromiseResetToRejected(writer, reason) {\n assert(writer._readyPromise_resolve === undefined, 'writer._readyPromise_resolve === undefined');\n assert(writer._readyPromise_reject === undefined, 'writer._readyPromise_reject === undefined');\n\n writer._readyPromise = Promise.reject(reason);\n writer._readyPromiseState = 'rejected';\n}\n\nfunction defaultWriterReadyPromiseResolve(writer) {\n assert(writer._readyPromise_resolve !== undefined, 'writer._readyPromise_resolve !== undefined');\n assert(writer._readyPromise_reject !== undefined, 'writer._readyPromise_reject !== undefined');\n\n writer._readyPromise_resolve(undefined);\n writer._readyPromise_resolve = undefined;\n writer._readyPromise_reject = undefined;\n writer._readyPromiseState = 'fulfilled';\n}\n\n/***/ }),\n/* 3 */\n/***/ (function(module, exports, __w_pdfjs_require__) {\n\n\"use strict\";\n\n\nvar _require = __w_pdfjs_require__(0),\n IsFiniteNonNegativeNumber = _require.IsFiniteNonNegativeNumber;\n\nvar _require2 = __w_pdfjs_require__(1),\n assert = _require2.assert;\n\nexports.DequeueValue = function (container) {\n assert('_queue' in container && '_queueTotalSize' in container, 'Spec-level failure: DequeueValue should only be used on containers with [[queue]] and [[queueTotalSize]].');\n assert(container._queue.length > 0, 'Spec-level failure: should never dequeue from an empty queue.');\n\n var pair = container._queue.shift();\n container._queueTotalSize -= pair.size;\n if (container._queueTotalSize < 0) {\n container._queueTotalSize = 0;\n }\n\n return pair.value;\n};\n\nexports.EnqueueValueWithSize = function (container, value, size) {\n assert('_queue' in container && '_queueTotalSize' in container, 'Spec-level failure: EnqueueValueWithSize should only be used on containers with [[queue]] and ' + '[[queueTotalSize]].');\n\n size = Number(size);\n if (!IsFiniteNonNegativeNumber(size)) {\n throw new RangeError('Size must be a finite, non-NaN, non-negative number.');\n }\n\n container._queue.push({ value: value, size: size });\n container._queueTotalSize += size;\n};\n\nexports.PeekQueueValue = function (container) {\n assert('_queue' in container && '_queueTotalSize' in container, 'Spec-level failure: PeekQueueValue should only be used on containers with [[queue]] and [[queueTotalSize]].');\n assert(container._queue.length > 0, 'Spec-level failure: should never peek at an empty queue.');\n\n var pair = container._queue[0];\n return pair.value;\n};\n\nexports.ResetQueue = function (container) {\n assert('_queue' in container && '_queueTotalSize' in container, 'Spec-level failure: ResetQueue should only be used on containers with [[queue]] and [[queueTotalSize]].');\n\n container._queue = [];\n container._queueTotalSize = 0;\n};\n\n/***/ }),\n/* 4 */\n/***/ (function(module, exports, __w_pdfjs_require__) {\n\n\"use strict\";\n\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar _require = __w_pdfjs_require__(0),\n ArrayBufferCopy = _require.ArrayBufferCopy,\n CreateIterResultObject = _require.CreateIterResultObject,\n IsFiniteNonNegativeNumber = _require.IsFiniteNonNegativeNumber,\n InvokeOrNoop = _require.InvokeOrNoop,\n PromiseInvokeOrNoop = _require.PromiseInvokeOrNoop,\n TransferArrayBuffer = _require.TransferArrayBuffer,\n ValidateAndNormalizeQueuingStrategy = _require.ValidateAndNormalizeQueuingStrategy,\n ValidateAndNormalizeHighWaterMark = _require.ValidateAndNormalizeHighWaterMark;\n\nvar _require2 = __w_pdfjs_require__(0),\n createArrayFromList = _require2.createArrayFromList,\n createDataProperty = _require2.createDataProperty,\n typeIsObject = _require2.typeIsObject;\n\nvar _require3 = __w_pdfjs_require__(1),\n assert = _require3.assert,\n rethrowAssertionErrorRejection = _require3.rethrowAssertionErrorRejection;\n\nvar _require4 = __w_pdfjs_require__(3),\n DequeueValue = _require4.DequeueValue,\n EnqueueValueWithSize = _require4.EnqueueValueWithSize,\n ResetQueue = _require4.ResetQueue;\n\nvar _require5 = __w_pdfjs_require__(2),\n AcquireWritableStreamDefaultWriter = _require5.AcquireWritableStreamDefaultWriter,\n IsWritableStream = _require5.IsWritableStream,\n IsWritableStreamLocked = _require5.IsWritableStreamLocked,\n WritableStreamAbort = _require5.WritableStreamAbort,\n WritableStreamDefaultWriterCloseWithErrorPropagation = _require5.WritableStreamDefaultWriterCloseWithErrorPropagation,\n WritableStreamDefaultWriterRelease = _require5.WritableStreamDefaultWriterRelease,\n WritableStreamDefaultWriterWrite = _require5.WritableStreamDefaultWriterWrite,\n WritableStreamCloseQueuedOrInFlight = _require5.WritableStreamCloseQueuedOrInFlight;\n\nvar ReadableStream = function () {\n function ReadableStream() {\n var underlyingSource = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n size = _ref.size,\n highWaterMark = _ref.highWaterMark;\n\n _classCallCheck(this, ReadableStream);\n\n // Exposed to controllers.\n this._state = 'readable';\n\n this._reader = undefined;\n this._storedError = undefined;\n\n this._disturbed = false;\n\n // Initialize to undefined first because the constructor of the controller checks this\n // variable to validate the caller.\n this._readableStreamController = undefined;\n var type = underlyingSource.type;\n var typeString = String(type);\n if (typeString === 'bytes') {\n if (highWaterMark === undefined) {\n highWaterMark = 0;\n }\n this._readableStreamController = new ReadableByteStreamController(this, underlyingSource, highWaterMark);\n } else if (type === undefined) {\n if (highWaterMark === undefined) {\n highWaterMark = 1;\n }\n this._readableStreamController = new ReadableStreamDefaultController(this, underlyingSource, size, highWaterMark);\n } else {\n throw new RangeError('Invalid type is specified');\n }\n }\n\n _createClass(ReadableStream, [{\n key: 'cancel',\n value: function cancel(reason) {\n if (IsReadableStream(this) === false) {\n return Promise.reject(streamBrandCheckException('cancel'));\n }\n\n if (IsReadableStreamLocked(this) === true) {\n return Promise.reject(new TypeError('Cannot cancel a stream that already has a reader'));\n }\n\n return ReadableStreamCancel(this, reason);\n }\n }, {\n key: 'getReader',\n value: function getReader() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n mode = _ref2.mode;\n\n if (IsReadableStream(this) === false) {\n throw streamBrandCheckException('getReader');\n }\n\n if (mode === undefined) {\n return AcquireReadableStreamDefaultReader(this);\n }\n\n mode = String(mode);\n\n if (mode === 'byob') {\n return AcquireReadableStreamBYOBReader(this);\n }\n\n throw new RangeError('Invalid mode is specified');\n }\n }, {\n key: 'pipeThrough',\n value: function pipeThrough(_ref3, options) {\n var writable = _ref3.writable,\n readable = _ref3.readable;\n\n var promise = this.pipeTo(writable, options);\n\n ifIsObjectAndHasAPromiseIsHandledInternalSlotSetPromiseIsHandledToTrue(promise);\n\n return readable;\n }\n }, {\n key: 'pipeTo',\n value: function pipeTo(dest) {\n var _this = this;\n\n var _ref4 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n preventClose = _ref4.preventClose,\n preventAbort = _ref4.preventAbort,\n preventCancel = _ref4.preventCancel;\n\n if (IsReadableStream(this) === false) {\n return Promise.reject(streamBrandCheckException('pipeTo'));\n }\n if (IsWritableStream(dest) === false) {\n return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo\\'s first argument must be a WritableStream'));\n }\n\n preventClose = Boolean(preventClose);\n preventAbort = Boolean(preventAbort);\n preventCancel = Boolean(preventCancel);\n\n if (IsReadableStreamLocked(this) === true) {\n return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo cannot be used on a locked ReadableStream'));\n }\n if (IsWritableStreamLocked(dest) === true) {\n return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo cannot be used on a locked WritableStream'));\n }\n\n var reader = AcquireReadableStreamDefaultReader(this);\n var writer = AcquireWritableStreamDefaultWriter(dest);\n\n var shuttingDown = false;\n\n // This is used to keep track of the spec's requirement that we wait for ongoing writes during shutdown.\n var currentWrite = Promise.resolve();\n\n return new Promise(function (resolve, reject) {\n // Using reader and writer, read all chunks from this and write them to dest\n // - Backpressure must be enforced\n // - Shutdown must stop all activity\n function pipeLoop() {\n currentWrite = Promise.resolve();\n\n if (shuttingDown === true) {\n return Promise.resolve();\n }\n\n return writer._readyPromise.then(function () {\n return ReadableStreamDefaultReaderRead(reader).then(function (_ref5) {\n var value = _ref5.value,\n done = _ref5.done;\n\n if (done === true) {\n return;\n }\n\n currentWrite = WritableStreamDefaultWriterWrite(writer, value).catch(function () {});\n });\n }).then(pipeLoop);\n }\n\n // Errors must be propagated forward\n isOrBecomesErrored(_this, reader._closedPromise, function (storedError) {\n if (preventAbort === false) {\n shutdownWithAction(function () {\n return WritableStreamAbort(dest, storedError);\n }, true, storedError);\n } else {\n shutdown(true, storedError);\n }\n });\n\n // Errors must be propagated backward\n isOrBecomesErrored(dest, writer._closedPromise, function (storedError) {\n if (preventCancel === false) {\n shutdownWithAction(function () {\n return ReadableStreamCancel(_this, storedError);\n }, true, storedError);\n } else {\n shutdown(true, storedError);\n }\n });\n\n // Closing must be propagated forward\n isOrBecomesClosed(_this, reader._closedPromise, function () {\n if (preventClose === false) {\n shutdownWithAction(function () {\n return WritableStreamDefaultWriterCloseWithErrorPropagation(writer);\n });\n } else {\n shutdown();\n }\n });\n\n // Closing must be propagated backward\n if (WritableStreamCloseQueuedOrInFlight(dest) === true || dest._state === 'closed') {\n var destClosed = new TypeError('the destination writable stream closed before all data could be piped to it');\n\n if (preventCancel === false) {\n shutdownWithAction(function () {\n return ReadableStreamCancel(_this, destClosed);\n }, true, destClosed);\n } else {\n shutdown(true, destClosed);\n }\n }\n\n pipeLoop().catch(function (err) {\n currentWrite = Promise.resolve();\n rethrowAssertionErrorRejection(err);\n });\n\n function waitForWritesToFinish() {\n // Another write may have started while we were waiting on this currentWrite, so we have to be sure to wait\n // for that too.\n var oldCurrentWrite = currentWrite;\n return currentWrite.then(function () {\n return oldCurrentWrite !== currentWrite ? waitForWritesToFinish() : undefined;\n });\n }\n\n function isOrBecomesErrored(stream, promise, action) {\n if (stream._state === 'errored') {\n action(stream._storedError);\n } else {\n promise.catch(action).catch(rethrowAssertionErrorRejection);\n }\n }\n\n function isOrBecomesClosed(stream, promise, action) {\n if (stream._state === 'closed') {\n action();\n } else {\n promise.then(action).catch(rethrowAssertionErrorRejection);\n }\n }\n\n function shutdownWithAction(action, originalIsError, originalError) {\n if (shuttingDown === true) {\n return;\n }\n shuttingDown = true;\n\n if (dest._state === 'writable' && WritableStreamCloseQueuedOrInFlight(dest) === false) {\n waitForWritesToFinish().then(doTheRest);\n } else {\n doTheRest();\n }\n\n function doTheRest() {\n action().then(function () {\n return finalize(originalIsError, originalError);\n }, function (newError) {\n return finalize(true, newError);\n }).catch(rethrowAssertionErrorRejection);\n }\n }\n\n function shutdown(isError, error) {\n if (shuttingDown === true) {\n return;\n }\n shuttingDown = true;\n\n if (dest._state === 'writable' && WritableStreamCloseQueuedOrInFlight(dest) === false) {\n waitForWritesToFinish().then(function () {\n return finalize(isError, error);\n }).catch(rethrowAssertionErrorRejection);\n } else {\n finalize(isError, error);\n }\n }\n\n function finalize(isError, error) {\n WritableStreamDefaultWriterRelease(writer);\n ReadableStreamReaderGenericRelease(reader);\n\n if (isError) {\n reject(error);\n } else {\n resolve(undefined);\n }\n }\n });\n }\n }, {\n key: 'tee',\n value: function tee() {\n if (IsReadableStream(this) === false) {\n throw streamBrandCheckException('tee');\n }\n\n var branches = ReadableStreamTee(this, false);\n return createArrayFromList(branches);\n }\n }, {\n key: 'locked',\n get: function get() {\n if (IsReadableStream(this) === false) {\n throw streamBrandCheckException('locked');\n }\n\n return IsReadableStreamLocked(this);\n }\n }]);\n\n return ReadableStream;\n}();\n\nmodule.exports = {\n ReadableStream: ReadableStream,\n IsReadableStreamDisturbed: IsReadableStreamDisturbed,\n ReadableStreamDefaultControllerClose: ReadableStreamDefaultControllerClose,\n ReadableStreamDefaultControllerEnqueue: ReadableStreamDefaultControllerEnqueue,\n ReadableStreamDefaultControllerError: ReadableStreamDefaultControllerError,\n ReadableStreamDefaultControllerGetDesiredSize: ReadableStreamDefaultControllerGetDesiredSize\n};\n\n// Abstract operations for the ReadableStream.\n\nfunction AcquireReadableStreamBYOBReader(stream) {\n return new ReadableStreamBYOBReader(stream);\n}\n\nfunction AcquireReadableStreamDefaultReader(stream) {\n return new ReadableStreamDefaultReader(stream);\n}\n\nfunction IsReadableStream(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_readableStreamController')) {\n return false;\n }\n\n return true;\n}\n\nfunction IsReadableStreamDisturbed(stream) {\n assert(IsReadableStream(stream) === true, 'IsReadableStreamDisturbed should only be used on known readable streams');\n\n return stream._disturbed;\n}\n\nfunction IsReadableStreamLocked(stream) {\n assert(IsReadableStream(stream) === true, 'IsReadableStreamLocked should only be used on known readable streams');\n\n if (stream._reader === undefined) {\n return false;\n }\n\n return true;\n}\n\nfunction ReadableStreamTee(stream, cloneForBranch2) {\n assert(IsReadableStream(stream) === true);\n assert(typeof cloneForBranch2 === 'boolean');\n\n var reader = AcquireReadableStreamDefaultReader(stream);\n\n var teeState = {\n closedOrErrored: false,\n canceled1: false,\n canceled2: false,\n reason1: undefined,\n reason2: undefined\n };\n teeState.promise = new Promise(function (resolve) {\n teeState._resolve = resolve;\n });\n\n var pull = create_ReadableStreamTeePullFunction();\n pull._reader = reader;\n pull._teeState = teeState;\n pull._cloneForBranch2 = cloneForBranch2;\n\n var cancel1 = create_ReadableStreamTeeBranch1CancelFunction();\n cancel1._stream = stream;\n cancel1._teeState = teeState;\n\n var cancel2 = create_ReadableStreamTeeBranch2CancelFunction();\n cancel2._stream = stream;\n cancel2._teeState = teeState;\n\n var underlyingSource1 = Object.create(Object.prototype);\n createDataProperty(underlyingSource1, 'pull', pull);\n createDataProperty(underlyingSource1, 'cancel', cancel1);\n var branch1Stream = new ReadableStream(underlyingSource1);\n\n var underlyingSource2 = Object.create(Object.prototype);\n createDataProperty(underlyingSource2, 'pull', pull);\n createDataProperty(underlyingSource2, 'cancel', cancel2);\n var branch2Stream = new ReadableStream(underlyingSource2);\n\n pull._branch1 = branch1Stream._readableStreamController;\n pull._branch2 = branch2Stream._readableStreamController;\n\n reader._closedPromise.catch(function (r) {\n if (teeState.closedOrErrored === true) {\n return;\n }\n\n ReadableStreamDefaultControllerError(pull._branch1, r);\n ReadableStreamDefaultControllerError(pull._branch2, r);\n teeState.closedOrErrored = true;\n });\n\n return [branch1Stream, branch2Stream];\n}\n\nfunction create_ReadableStreamTeePullFunction() {\n function f() {\n var reader = f._reader,\n branch1 = f._branch1,\n branch2 = f._branch2,\n teeState = f._teeState;\n\n\n return ReadableStreamDefaultReaderRead(reader).then(function (result) {\n assert(typeIsObject(result));\n var value = result.value;\n var done = result.done;\n assert(typeof done === 'boolean');\n\n if (done === true && teeState.closedOrErrored === false) {\n if (teeState.canceled1 === false) {\n ReadableStreamDefaultControllerClose(branch1);\n }\n if (teeState.canceled2 === false) {\n ReadableStreamDefaultControllerClose(branch2);\n }\n teeState.closedOrErrored = true;\n }\n\n if (teeState.closedOrErrored === true) {\n return;\n }\n\n var value1 = value;\n var value2 = value;\n\n // There is no way to access the cloning code right now in the reference implementation.\n // If we add one then we'll need an implementation for serializable objects.\n // if (teeState.canceled2 === false && cloneForBranch2 === true) {\n // value2 = StructuredDeserialize(StructuredSerialize(value2));\n // }\n\n if (teeState.canceled1 === false) {\n ReadableStreamDefaultControllerEnqueue(branch1, value1);\n }\n\n if (teeState.canceled2 === false) {\n ReadableStreamDefaultControllerEnqueue(branch2, value2);\n }\n });\n }\n return f;\n}\n\nfunction create_ReadableStreamTeeBranch1CancelFunction() {\n function f(reason) {\n var stream = f._stream,\n teeState = f._teeState;\n\n\n teeState.canceled1 = true;\n teeState.reason1 = reason;\n if (teeState.canceled2 === true) {\n var compositeReason = createArrayFromList([teeState.reason1, teeState.reason2]);\n var cancelResult = ReadableStreamCancel(stream, compositeReason);\n teeState._resolve(cancelResult);\n }\n return teeState.promise;\n }\n return f;\n}\n\nfunction create_ReadableStreamTeeBranch2CancelFunction() {\n function f(reason) {\n var stream = f._stream,\n teeState = f._teeState;\n\n\n teeState.canceled2 = true;\n teeState.reason2 = reason;\n if (teeState.canceled1 === true) {\n var compositeReason = createArrayFromList([teeState.reason1, teeState.reason2]);\n var cancelResult = ReadableStreamCancel(stream, compositeReason);\n teeState._resolve(cancelResult);\n }\n return teeState.promise;\n }\n return f;\n}\n\n// ReadableStream API exposed for controllers.\n\nfunction ReadableStreamAddReadIntoRequest(stream) {\n assert(IsReadableStreamBYOBReader(stream._reader) === true);\n assert(stream._state === 'readable' || stream._state === 'closed');\n\n var promise = new Promise(function (resolve, reject) {\n var readIntoRequest = {\n _resolve: resolve,\n _reject: reject\n };\n\n stream._reader._readIntoRequests.push(readIntoRequest);\n });\n\n return promise;\n}\n\nfunction ReadableStreamAddReadRequest(stream) {\n assert(IsReadableStreamDefaultReader(stream._reader) === true);\n assert(stream._state === 'readable');\n\n var promise = new Promise(function (resolve, reject) {\n var readRequest = {\n _resolve: resolve,\n _reject: reject\n };\n\n stream._reader._readRequests.push(readRequest);\n });\n\n return promise;\n}\n\nfunction ReadableStreamCancel(stream, reason) {\n stream._disturbed = true;\n\n if (stream._state === 'closed') {\n return Promise.resolve(undefined);\n }\n if (stream._state === 'errored') {\n return Promise.reject(stream._storedError);\n }\n\n ReadableStreamClose(stream);\n\n var sourceCancelPromise = stream._readableStreamController.__cancelSteps(reason);\n return sourceCancelPromise.then(function () {\n return undefined;\n });\n}\n\nfunction ReadableStreamClose(stream) {\n assert(stream._state === 'readable');\n\n stream._state = 'closed';\n\n var reader = stream._reader;\n\n if (reader === undefined) {\n return undefined;\n }\n\n if (IsReadableStreamDefaultReader(reader) === true) {\n for (var i = 0; i < reader._readRequests.length; i++) {\n var _resolve = reader._readRequests[i]._resolve;\n\n _resolve(CreateIterResultObject(undefined, true));\n }\n reader._readRequests = [];\n }\n\n defaultReaderClosedPromiseResolve(reader);\n\n return undefined;\n}\n\nfunction ReadableStreamError(stream, e) {\n assert(IsReadableStream(stream) === true, 'stream must be ReadableStream');\n assert(stream._state === 'readable', 'state must be readable');\n\n stream._state = 'errored';\n stream._storedError = e;\n\n var reader = stream._reader;\n\n if (reader === undefined) {\n return undefined;\n }\n\n if (IsReadableStreamDefaultReader(reader) === true) {\n for (var i = 0; i < reader._readRequests.length; i++) {\n var readRequest = reader._readRequests[i];\n readRequest._reject(e);\n }\n\n reader._readRequests = [];\n } else {\n assert(IsReadableStreamBYOBReader(reader), 'reader must be ReadableStreamBYOBReader');\n\n for (var _i = 0; _i < reader._readIntoRequests.length; _i++) {\n var readIntoRequest = reader._readIntoRequests[_i];\n readIntoRequest._reject(e);\n }\n\n reader._readIntoRequests = [];\n }\n\n defaultReaderClosedPromiseReject(reader, e);\n reader._closedPromise.catch(function () {});\n}\n\nfunction ReadableStreamFulfillReadIntoRequest(stream, chunk, done) {\n var reader = stream._reader;\n\n assert(reader._readIntoRequests.length > 0);\n\n var readIntoRequest = reader._readIntoRequests.shift();\n readIntoRequest._resolve(CreateIterResultObject(chunk, done));\n}\n\nfunction ReadableStreamFulfillReadRequest(stream, chunk, done) {\n var reader = stream._reader;\n\n assert(reader._readRequests.length > 0);\n\n var readRequest = reader._readRequests.shift();\n readRequest._resolve(CreateIterResultObject(chunk, done));\n}\n\nfunction ReadableStreamGetNumReadIntoRequests(stream) {\n return stream._reader._readIntoRequests.length;\n}\n\nfunction ReadableStreamGetNumReadRequests(stream) {\n return stream._reader._readRequests.length;\n}\n\nfunction ReadableStreamHasBYOBReader(stream) {\n var reader = stream._reader;\n\n if (reader === undefined) {\n return false;\n }\n\n if (IsReadableStreamBYOBReader(reader) === false) {\n return false;\n }\n\n return true;\n}\n\nfunction ReadableStreamHasDefaultReader(stream) {\n var reader = stream._reader;\n\n if (reader === undefined) {\n return false;\n }\n\n if (IsReadableStreamDefaultReader(reader) === false) {\n return false;\n }\n\n return true;\n}\n\n// Readers\n\nvar ReadableStreamDefaultReader = function () {\n function ReadableStreamDefaultReader(stream) {\n _classCallCheck(this, ReadableStreamDefaultReader);\n\n if (IsReadableStream(stream) === false) {\n throw new TypeError('ReadableStreamDefaultReader can only be constructed with a ReadableStream instance');\n }\n if (IsReadableStreamLocked(stream) === true) {\n throw new TypeError('This stream has already been locked for exclusive reading by another reader');\n }\n\n ReadableStreamReaderGenericInitialize(this, stream);\n\n this._readRequests = [];\n }\n\n _createClass(ReadableStreamDefaultReader, [{\n key: 'cancel',\n value: function cancel(reason) {\n if (IsReadableStreamDefaultReader(this) === false) {\n return Promise.reject(defaultReaderBrandCheckException('cancel'));\n }\n\n if (this._ownerReadableStream === undefined) {\n return Promise.reject(readerLockException('cancel'));\n }\n\n return ReadableStreamReaderGenericCancel(this, reason);\n }\n }, {\n key: 'read',\n value: function read() {\n if (IsReadableStreamDefaultReader(this) === false) {\n return Promise.reject(defaultReaderBrandCheckException('read'));\n }\n\n if (this._ownerReadableStream === undefined) {\n return Promise.reject(readerLockException('read from'));\n }\n\n return ReadableStreamDefaultReaderRead(this);\n }\n }, {\n key: 'releaseLock',\n value: function releaseLock() {\n if (IsReadableStreamDefaultReader(this) === false) {\n throw defaultReaderBrandCheckException('releaseLock');\n }\n\n if (this._ownerReadableStream === undefined) {\n return;\n }\n\n if (this._readRequests.length > 0) {\n throw new TypeError('Tried to release a reader lock when that reader has pending read() calls un-settled');\n }\n\n ReadableStreamReaderGenericRelease(this);\n }\n }, {\n key: 'closed',\n get: function get() {\n if (IsReadableStreamDefaultReader(this) === false) {\n return Promise.reject(defaultReaderBrandCheckException('closed'));\n }\n\n return this._closedPromise;\n }\n }]);\n\n return ReadableStreamDefaultReader;\n}();\n\nvar ReadableStreamBYOBReader = function () {\n function ReadableStreamBYOBReader(stream) {\n _classCallCheck(this, ReadableStreamBYOBReader);\n\n if (!IsReadableStream(stream)) {\n throw new TypeError('ReadableStreamBYOBReader can only be constructed with a ReadableStream instance given a ' + 'byte source');\n }\n if (IsReadableByteStreamController(stream._readableStreamController) === false) {\n throw new TypeError('Cannot construct a ReadableStreamBYOBReader for a stream not constructed with a byte ' + 'source');\n }\n if (IsReadableStreamLocked(stream)) {\n throw new TypeError('This stream has already been locked for exclusive reading by another reader');\n }\n\n ReadableStreamReaderGenericInitialize(this, stream);\n\n this._readIntoRequests = [];\n }\n\n _createClass(ReadableStreamBYOBReader, [{\n key: 'cancel',\n value: function cancel(reason) {\n if (!IsReadableStreamBYOBReader(this)) {\n return Promise.reject(byobReaderBrandCheckException('cancel'));\n }\n\n if (this._ownerReadableStream === undefined) {\n return Promise.reject(readerLockException('cancel'));\n }\n\n return ReadableStreamReaderGenericCancel(this, reason);\n }\n }, {\n key: 'read',\n value: function read(view) {\n if (!IsReadableStreamBYOBReader(this)) {\n return Promise.reject(byobReaderBrandCheckException('read'));\n }\n\n if (this._ownerReadableStream === undefined) {\n return Promise.reject(readerLockException('read from'));\n }\n\n if (!ArrayBuffer.isView(view)) {\n return Promise.reject(new TypeError('view must be an array buffer view'));\n }\n\n if (view.byteLength === 0) {\n return Promise.reject(new TypeError('view must have non-zero byteLength'));\n }\n\n return ReadableStreamBYOBReaderRead(this, view);\n }\n }, {\n key: 'releaseLock',\n value: function releaseLock() {\n if (!IsReadableStreamBYOBReader(this)) {\n throw byobReaderBrandCheckException('releaseLock');\n }\n\n if (this._ownerReadableStream === undefined) {\n return;\n }\n\n if (this._readIntoRequests.length > 0) {\n throw new TypeError('Tried to release a reader lock when that reader has pending read() calls un-settled');\n }\n\n ReadableStreamReaderGenericRelease(this);\n }\n }, {\n key: 'closed',\n get: function get() {\n if (!IsReadableStreamBYOBReader(this)) {\n return Promise.reject(byobReaderBrandCheckException('closed'));\n }\n\n return this._closedPromise;\n }\n }]);\n\n return ReadableStreamBYOBReader;\n}();\n\n// Abstract operations for the readers.\n\nfunction IsReadableStreamBYOBReader(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_readIntoRequests')) {\n return false;\n }\n\n return true;\n}\n\nfunction IsReadableStreamDefaultReader(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_readRequests')) {\n return false;\n }\n\n return true;\n}\n\nfunction ReadableStreamReaderGenericInitialize(reader, stream) {\n reader._ownerReadableStream = stream;\n stream._reader = reader;\n\n if (stream._state === 'readable') {\n defaultReaderClosedPromiseInitialize(reader);\n } else if (stream._state === 'closed') {\n defaultReaderClosedPromiseInitializeAsResolved(reader);\n } else {\n assert(stream._state === 'errored', 'state must be errored');\n\n defaultReaderClosedPromiseInitializeAsRejected(reader, stream._storedError);\n reader._closedPromise.catch(function () {});\n }\n}\n\n// A client of ReadableStreamDefaultReader and ReadableStreamBYOBReader may use these functions directly to bypass state\n// check.\n\nfunction ReadableStreamReaderGenericCancel(reader, reason) {\n var stream = reader._ownerReadableStream;\n assert(stream !== undefined);\n return ReadableStreamCancel(stream, reason);\n}\n\nfunction ReadableStreamReaderGenericRelease(reader) {\n assert(reader._ownerReadableStream !== undefined);\n assert(reader._ownerReadableStream._reader === reader);\n\n if (reader._ownerReadableStream._state === 'readable') {\n defaultReaderClosedPromiseReject(reader, new TypeError('Reader was released and can no longer be used to monitor the stream\\'s closedness'));\n } else {\n defaultReaderClosedPromiseResetToRejected(reader, new TypeError('Reader was released and can no longer be used to monitor the stream\\'s closedness'));\n }\n reader._closedPromise.catch(function () {});\n\n reader._ownerReadableStream._reader = undefined;\n reader._ownerReadableStream = undefined;\n}\n\nfunction ReadableStreamBYOBReaderRead(reader, view) {\n var stream = reader._ownerReadableStream;\n\n assert(stream !== undefined);\n\n stream._disturbed = true;\n\n if (stream._state === 'errored') {\n return Promise.reject(stream._storedError);\n }\n\n // Controllers must implement this.\n return ReadableByteStreamControllerPullInto(stream._readableStreamController, view);\n}\n\nfunction ReadableStreamDefaultReaderRead(reader) {\n var stream = reader._ownerReadableStream;\n\n assert(stream !== undefined);\n\n stream._disturbed = true;\n\n if (stream._state === 'closed') {\n return Promise.resolve(CreateIterResultObject(undefined, true));\n }\n\n if (stream._state === 'errored') {\n return Promise.reject(stream._storedError);\n }\n\n assert(stream._state === 'readable');\n\n return stream._readableStreamController.__pullSteps();\n}\n\n// Controllers\n\nvar ReadableStreamDefaultController = function () {\n function ReadableStreamDefaultController(stream, underlyingSource, size, highWaterMark) {\n _classCallCheck(this, ReadableStreamDefaultController);\n\n if (IsReadableStream(stream) === false) {\n throw new TypeError('ReadableStreamDefaultController can only be constructed with a ReadableStream instance');\n }\n\n if (stream._readableStreamController !== undefined) {\n throw new TypeError('ReadableStreamDefaultController instances can only be created by the ReadableStream constructor');\n }\n\n this._controlledReadableStream = stream;\n\n this._underlyingSource = underlyingSource;\n\n // Need to set the slots so that the assert doesn't fire. In the spec the slots already exist implicitly.\n this._queue = undefined;\n this._queueTotalSize = undefined;\n ResetQueue(this);\n\n this._started = false;\n this._closeRequested = false;\n this._pullAgain = false;\n this._pulling = false;\n\n var normalizedStrategy = ValidateAndNormalizeQueuingStrategy(size, highWaterMark);\n this._strategySize = normalizedStrategy.size;\n this._strategyHWM = normalizedStrategy.highWaterMark;\n\n var controller = this;\n\n var startResult = InvokeOrNoop(underlyingSource, 'start', [this]);\n Promise.resolve(startResult).then(function () {\n controller._started = true;\n\n assert(controller._pulling === false);\n assert(controller._pullAgain === false);\n\n ReadableStreamDefaultControllerCallPullIfNeeded(controller);\n }, function (r) {\n ReadableStreamDefaultControllerErrorIfNeeded(controller, r);\n }).catch(rethrowAssertionErrorRejection);\n }\n\n _createClass(ReadableStreamDefaultController, [{\n key: 'close',\n value: function close() {\n if (IsReadableStreamDefaultController(this) === false) {\n throw defaultControllerBrandCheckException('close');\n }\n\n if (this._closeRequested === true) {\n throw new TypeError('The stream has already been closed; do not close it again!');\n }\n\n var state = this._controlledReadableStream._state;\n if (state !== 'readable') {\n throw new TypeError('The stream (in ' + state + ' state) is not in the readable state and cannot be closed');\n }\n\n ReadableStreamDefaultControllerClose(this);\n }\n }, {\n key: 'enqueue',\n value: function enqueue(chunk) {\n if (IsReadableStreamDefaultController(this) === false) {\n throw defaultControllerBrandCheckException('enqueue');\n }\n\n if (this._closeRequested === true) {\n throw new TypeError('stream is closed or draining');\n }\n\n var state = this._controlledReadableStream._state;\n if (state !== 'readable') {\n throw new TypeError('The stream (in ' + state + ' state) is not in the readable state and cannot be enqueued to');\n }\n\n return ReadableStreamDefaultControllerEnqueue(this, chunk);\n }\n }, {\n key: 'error',\n value: function error(e) {\n if (IsReadableStreamDefaultController(this) === false) {\n throw defaultControllerBrandCheckException('error');\n }\n\n var stream = this._controlledReadableStream;\n if (stream._state !== 'readable') {\n throw new TypeError('The stream is ' + stream._state + ' and so cannot be errored');\n }\n\n ReadableStreamDefaultControllerError(this, e);\n }\n }, {\n key: '__cancelSteps',\n value: function __cancelSteps(reason) {\n ResetQueue(this);\n return PromiseInvokeOrNoop(this._underlyingSource, 'cancel', [reason]);\n }\n }, {\n key: '__pullSteps',\n value: function __pullSteps() {\n var stream = this._controlledReadableStream;\n\n if (this._queue.length > 0) {\n var chunk = DequeueValue(this);\n\n if (this._closeRequested === true && this._queue.length === 0) {\n ReadableStreamClose(stream);\n } else {\n ReadableStreamDefaultControllerCallPullIfNeeded(this);\n }\n\n return Promise.resolve(CreateIterResultObject(chunk, false));\n }\n\n var pendingPromise = ReadableStreamAddReadRequest(stream);\n ReadableStreamDefaultControllerCallPullIfNeeded(this);\n return pendingPromise;\n }\n }, {\n key: 'desiredSize',\n get: function get() {\n if (IsReadableStreamDefaultController(this) === false) {\n throw defaultControllerBrandCheckException('desiredSize');\n }\n\n return ReadableStreamDefaultControllerGetDesiredSize(this);\n }\n }]);\n\n return ReadableStreamDefaultController;\n}();\n\n// Abstract operations for the ReadableStreamDefaultController.\n\nfunction IsReadableStreamDefaultController(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_underlyingSource')) {\n return false;\n }\n\n return true;\n}\n\nfunction ReadableStreamDefaultControllerCallPullIfNeeded(controller) {\n var shouldPull = ReadableStreamDefaultControllerShouldCallPull(controller);\n if (shouldPull === false) {\n return undefined;\n }\n\n if (controller._pulling === true) {\n controller._pullAgain = true;\n return undefined;\n }\n\n assert(controller._pullAgain === false);\n\n controller._pulling = true;\n\n var pullPromise = PromiseInvokeOrNoop(controller._underlyingSource, 'pull', [controller]);\n pullPromise.then(function () {\n controller._pulling = false;\n\n if (controller._pullAgain === true) {\n controller._pullAgain = false;\n return ReadableStreamDefaultControllerCallPullIfNeeded(controller);\n }\n return undefined;\n }, function (e) {\n ReadableStreamDefaultControllerErrorIfNeeded(controller, e);\n }).catch(rethrowAssertionErrorRejection);\n\n return undefined;\n}\n\nfunction ReadableStreamDefaultControllerShouldCallPull(controller) {\n var stream = controller._controlledReadableStream;\n\n if (stream._state === 'closed' || stream._state === 'errored') {\n return false;\n }\n\n if (controller._closeRequested === true) {\n return false;\n }\n\n if (controller._started === false) {\n return false;\n }\n\n if (IsReadableStreamLocked(stream) === true && ReadableStreamGetNumReadRequests(stream) > 0) {\n return true;\n }\n\n var desiredSize = ReadableStreamDefaultControllerGetDesiredSize(controller);\n if (desiredSize > 0) {\n return true;\n }\n\n return false;\n}\n\n// A client of ReadableStreamDefaultController may use these functions directly to bypass state check.\n\nfunction ReadableStreamDefaultControllerClose(controller) {\n var stream = controller._controlledReadableStream;\n\n assert(controller._closeRequested === false);\n assert(stream._state === 'readable');\n\n controller._closeRequested = true;\n\n if (controller._queue.length === 0) {\n ReadableStreamClose(stream);\n }\n}\n\nfunction ReadableStreamDefaultControllerEnqueue(controller, chunk) {\n var stream = controller._controlledReadableStream;\n\n assert(controller._closeRequested === false);\n assert(stream._state === 'readable');\n\n if (IsReadableStreamLocked(stream) === true && ReadableStreamGetNumReadRequests(stream) > 0) {\n ReadableStreamFulfillReadRequest(stream, chunk, false);\n } else {\n var chunkSize = 1;\n\n if (controller._strategySize !== undefined) {\n var strategySize = controller._strategySize;\n try {\n chunkSize = strategySize(chunk);\n } catch (chunkSizeE) {\n ReadableStreamDefaultControllerErrorIfNeeded(controller, chunkSizeE);\n throw chunkSizeE;\n }\n }\n\n try {\n EnqueueValueWithSize(controller, chunk, chunkSize);\n } catch (enqueueE) {\n ReadableStreamDefaultControllerErrorIfNeeded(controller, enqueueE);\n throw enqueueE;\n }\n }\n\n ReadableStreamDefaultControllerCallPullIfNeeded(controller);\n\n return undefined;\n}\n\nfunction ReadableStreamDefaultControllerError(controller, e) {\n var stream = controller._controlledReadableStream;\n\n assert(stream._state === 'readable');\n\n ResetQueue(controller);\n\n ReadableStreamError(stream, e);\n}\n\nfunction ReadableStreamDefaultControllerErrorIfNeeded(controller, e) {\n if (controller._controlledReadableStream._state === 'readable') {\n ReadableStreamDefaultControllerError(controller, e);\n }\n}\n\nfunction ReadableStreamDefaultControllerGetDesiredSize(controller) {\n var stream = controller._controlledReadableStream;\n var state = stream._state;\n\n if (state === 'errored') {\n return null;\n }\n if (state === 'closed') {\n return 0;\n }\n\n return controller._strategyHWM - controller._queueTotalSize;\n}\n\nvar ReadableStreamBYOBRequest = function () {\n function ReadableStreamBYOBRequest(controller, view) {\n _classCallCheck(this, ReadableStreamBYOBRequest);\n\n this._associatedReadableByteStreamController = controller;\n this._view = view;\n }\n\n _createClass(ReadableStreamBYOBRequest, [{\n key: 'respond',\n value: function respond(bytesWritten) {\n if (IsReadableStreamBYOBRequest(this) === false) {\n throw byobRequestBrandCheckException('respond');\n }\n\n if (this._associatedReadableByteStreamController === undefined) {\n throw new TypeError('This BYOB request has been invalidated');\n }\n\n ReadableByteStreamControllerRespond(this._associatedReadableByteStreamController, bytesWritten);\n }\n }, {\n key: 'respondWithNewView',\n value: function respondWithNewView(view) {\n if (IsReadableStreamBYOBRequest(this) === false) {\n throw byobRequestBrandCheckException('respond');\n }\n\n if (this._associatedReadableByteStreamController === undefined) {\n throw new TypeError('This BYOB request has been invalidated');\n }\n\n if (!ArrayBuffer.isView(view)) {\n throw new TypeError('You can only respond with array buffer views');\n }\n\n ReadableByteStreamControllerRespondWithNewView(this._associatedReadableByteStreamController, view);\n }\n }, {\n key: 'view',\n get: function get() {\n return this._view;\n }\n }]);\n\n return ReadableStreamBYOBRequest;\n}();\n\nvar ReadableByteStreamController = function () {\n function ReadableByteStreamController(stream, underlyingByteSource, highWaterMark) {\n _classCallCheck(this, ReadableByteStreamController);\n\n if (IsReadableStream(stream) === false) {\n throw new TypeError('ReadableByteStreamController can only be constructed with a ReadableStream instance given ' + 'a byte source');\n }\n\n if (stream._readableStreamController !== undefined) {\n throw new TypeError('ReadableByteStreamController instances can only be created by the ReadableStream constructor given a byte ' + 'source');\n }\n\n this._controlledReadableStream = stream;\n\n this._underlyingByteSource = underlyingByteSource;\n\n this._pullAgain = false;\n this._pulling = false;\n\n ReadableByteStreamControllerClearPendingPullIntos(this);\n\n // Need to set the slots so that the assert doesn't fire. In the spec the slots already exist implicitly.\n this._queue = this._queueTotalSize = undefined;\n ResetQueue(this);\n\n this._closeRequested = false;\n this._started = false;\n\n this._strategyHWM = ValidateAndNormalizeHighWaterMark(highWaterMark);\n\n var autoAllocateChunkSize = underlyingByteSource.autoAllocateChunkSize;\n if (autoAllocateChunkSize !== undefined) {\n if (Number.isInteger(autoAllocateChunkSize) === false || autoAllocateChunkSize <= 0) {\n throw new RangeError('autoAllocateChunkSize must be a positive integer');\n }\n }\n this._autoAllocateChunkSize = autoAllocateChunkSize;\n\n this._pendingPullIntos = [];\n\n var controller = this;\n\n var startResult = InvokeOrNoop(underlyingByteSource, 'start', [this]);\n Promise.resolve(startResult).then(function () {\n controller._started = true;\n\n assert(controller._pulling === false);\n assert(controller._pullAgain === false);\n\n ReadableByteStreamControllerCallPullIfNeeded(controller);\n }, function (r) {\n if (stream._state === 'readable') {\n ReadableByteStreamControllerError(controller, r);\n }\n }).catch(rethrowAssertionErrorRejection);\n }\n\n _createClass(ReadableByteStreamController, [{\n key: 'close',\n value: function close() {\n if (IsReadableByteStreamController(this) === false) {\n throw byteStreamControllerBrandCheckException('close');\n }\n\n if (this._closeRequested === true) {\n throw new TypeError('The stream has already been closed; do not close it again!');\n }\n\n var state = this._controlledReadableStream._state;\n if (state !== 'readable') {\n throw new TypeError('The stream (in ' + state + ' state) is not in the readable state and cannot be closed');\n }\n\n ReadableByteStreamControllerClose(this);\n }\n }, {\n key: 'enqueue',\n value: function enqueue(chunk) {\n if (IsReadableByteStreamController(this) === false) {\n throw byteStreamControllerBrandCheckException('enqueue');\n }\n\n if (this._closeRequested === true) {\n throw new TypeError('stream is closed or draining');\n }\n\n var state = this._controlledReadableStream._state;\n if (state !== 'readable') {\n throw new TypeError('The stream (in ' + state + ' state) is not in the readable state and cannot be enqueued to');\n }\n\n if (!ArrayBuffer.isView(chunk)) {\n throw new TypeError('You can only enqueue array buffer views when using a ReadableByteStreamController');\n }\n\n ReadableByteStreamControllerEnqueue(this, chunk);\n }\n }, {\n key: 'error',\n value: function error(e) {\n if (IsReadableByteStreamController(this) === false) {\n throw byteStreamControllerBrandCheckException('error');\n }\n\n var stream = this._controlledReadableStream;\n if (stream._state !== 'readable') {\n throw new TypeError('The stream is ' + stream._state + ' and so cannot be errored');\n }\n\n ReadableByteStreamControllerError(this, e);\n }\n }, {\n key: '__cancelSteps',\n value: function __cancelSteps(reason) {\n if (this._pendingPullIntos.length > 0) {\n var firstDescriptor = this._pendingPullIntos[0];\n firstDescriptor.bytesFilled = 0;\n }\n\n ResetQueue(this);\n\n return PromiseInvokeOrNoop(this._underlyingByteSource, 'cancel', [reason]);\n }\n }, {\n key: '__pullSteps',\n value: function __pullSteps() {\n var stream = this._controlledReadableStream;\n assert(ReadableStreamHasDefaultReader(stream) === true);\n\n if (this._queueTotalSize > 0) {\n assert(ReadableStreamGetNumReadRequests(stream) === 0);\n\n var entry = this._queue.shift();\n this._queueTotalSize -= entry.byteLength;\n\n ReadableByteStreamControllerHandleQueueDrain(this);\n\n var view = void 0;\n try {\n view = new Uint8Array(entry.buffer, entry.byteOffset, entry.byteLength);\n } catch (viewE) {\n return Promise.reject(viewE);\n }\n\n return Promise.resolve(CreateIterResultObject(view, false));\n }\n\n var autoAllocateChunkSize = this._autoAllocateChunkSize;\n if (autoAllocateChunkSize !== undefined) {\n var buffer = void 0;\n try {\n buffer = new ArrayBuffer(autoAllocateChunkSize);\n } catch (bufferE) {\n return Promise.reject(bufferE);\n }\n\n var pullIntoDescriptor = {\n buffer: buffer,\n byteOffset: 0,\n byteLength: autoAllocateChunkSize,\n bytesFilled: 0,\n elementSize: 1,\n ctor: Uint8Array,\n readerType: 'default'\n };\n\n this._pendingPullIntos.push(pullIntoDescriptor);\n }\n\n var promise = ReadableStreamAddReadRequest(stream);\n\n ReadableByteStreamControllerCallPullIfNeeded(this);\n\n return promise;\n }\n }, {\n key: 'byobRequest',\n get: function get() {\n if (IsReadableByteStreamController(this) === false) {\n throw byteStreamControllerBrandCheckException('byobRequest');\n }\n\n if (this._byobRequest === undefined && this._pendingPullIntos.length > 0) {\n var firstDescriptor = this._pendingPullIntos[0];\n var view = new Uint8Array(firstDescriptor.buffer, firstDescriptor.byteOffset + firstDescriptor.bytesFilled, firstDescriptor.byteLength - firstDescriptor.bytesFilled);\n\n this._byobRequest = new ReadableStreamBYOBRequest(this, view);\n }\n\n return this._byobRequest;\n }\n }, {\n key: 'desiredSize',\n get: function get() {\n if (IsReadableByteStreamController(this) === false) {\n throw byteStreamControllerBrandCheckException('desiredSize');\n }\n\n return ReadableByteStreamControllerGetDesiredSize(this);\n }\n }]);\n\n return ReadableByteStreamController;\n}();\n\n// Abstract operations for the ReadableByteStreamController.\n\nfunction IsReadableByteStreamController(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_underlyingByteSource')) {\n return false;\n }\n\n return true;\n}\n\nfunction IsReadableStreamBYOBRequest(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_associatedReadableByteStreamController')) {\n return false;\n }\n\n return true;\n}\n\nfunction ReadableByteStreamControllerCallPullIfNeeded(controller) {\n var shouldPull = ReadableByteStreamControllerShouldCallPull(controller);\n if (shouldPull === false) {\n return undefined;\n }\n\n if (controller._pulling === true) {\n controller._pullAgain = true;\n return undefined;\n }\n\n assert(controller._pullAgain === false);\n\n controller._pulling = true;\n\n // TODO: Test controller argument\n var pullPromise = PromiseInvokeOrNoop(controller._underlyingByteSource, 'pull', [controller]);\n pullPromise.then(function () {\n controller._pulling = false;\n\n if (controller._pullAgain === true) {\n controller._pullAgain = false;\n ReadableByteStreamControllerCallPullIfNeeded(controller);\n }\n }, function (e) {\n if (controller._controlledReadableStream._state === 'readable') {\n ReadableByteStreamControllerError(controller, e);\n }\n }).catch(rethrowAssertionErrorRejection);\n\n return undefined;\n}\n\nfunction ReadableByteStreamControllerClearPendingPullIntos(controller) {\n ReadableByteStreamControllerInvalidateBYOBRequest(controller);\n controller._pendingPullIntos = [];\n}\n\nfunction ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor) {\n assert(stream._state !== 'errored', 'state must not be errored');\n\n var done = false;\n if (stream._state === 'closed') {\n assert(pullIntoDescriptor.bytesFilled === 0);\n done = true;\n }\n\n var filledView = ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor);\n if (pullIntoDescriptor.readerType === 'default') {\n ReadableStreamFulfillReadRequest(stream, filledView, done);\n } else {\n assert(pullIntoDescriptor.readerType === 'byob');\n ReadableStreamFulfillReadIntoRequest(stream, filledView, done);\n }\n}\n\nfunction ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor) {\n var bytesFilled = pullIntoDescriptor.bytesFilled;\n var elementSize = pullIntoDescriptor.elementSize;\n\n assert(bytesFilled <= pullIntoDescriptor.byteLength);\n assert(bytesFilled % elementSize === 0);\n\n return new pullIntoDescriptor.ctor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, bytesFilled / elementSize);\n}\n\nfunction ReadableByteStreamControllerEnqueueChunkToQueue(controller, buffer, byteOffset, byteLength) {\n controller._queue.push({ buffer: buffer, byteOffset: byteOffset, byteLength: byteLength });\n controller._queueTotalSize += byteLength;\n}\n\nfunction ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) {\n var elementSize = pullIntoDescriptor.elementSize;\n\n var currentAlignedBytes = pullIntoDescriptor.bytesFilled - pullIntoDescriptor.bytesFilled % elementSize;\n\n var maxBytesToCopy = Math.min(controller._queueTotalSize, pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled);\n var maxBytesFilled = pullIntoDescriptor.bytesFilled + maxBytesToCopy;\n var maxAlignedBytes = maxBytesFilled - maxBytesFilled % elementSize;\n\n var totalBytesToCopyRemaining = maxBytesToCopy;\n var ready = false;\n if (maxAlignedBytes > currentAlignedBytes) {\n totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled;\n ready = true;\n }\n\n var queue = controller._queue;\n\n while (totalBytesToCopyRemaining > 0) {\n var headOfQueue = queue[0];\n\n var bytesToCopy = Math.min(totalBytesToCopyRemaining, headOfQueue.byteLength);\n\n var destStart = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled;\n ArrayBufferCopy(pullIntoDescriptor.buffer, destStart, headOfQueue.buffer, headOfQueue.byteOffset, bytesToCopy);\n\n if (headOfQueue.byteLength === bytesToCopy) {\n queue.shift();\n } else {\n headOfQueue.byteOffset += bytesToCopy;\n headOfQueue.byteLength -= bytesToCopy;\n }\n controller._queueTotalSize -= bytesToCopy;\n\n ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesToCopy, pullIntoDescriptor);\n\n totalBytesToCopyRemaining -= bytesToCopy;\n }\n\n if (ready === false) {\n assert(controller._queueTotalSize === 0, 'queue must be empty');\n assert(pullIntoDescriptor.bytesFilled > 0);\n assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize);\n }\n\n return ready;\n}\n\nfunction ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, size, pullIntoDescriptor) {\n assert(controller._pendingPullIntos.length === 0 || controller._pendingPullIntos[0] === pullIntoDescriptor);\n\n ReadableByteStreamControllerInvalidateBYOBRequest(controller);\n pullIntoDescriptor.bytesFilled += size;\n}\n\nfunction ReadableByteStreamControllerHandleQueueDrain(controller) {\n assert(controller._controlledReadableStream._state === 'readable');\n\n if (controller._queueTotalSize === 0 && controller._closeRequested === true) {\n ReadableStreamClose(controller._controlledReadableStream);\n } else {\n ReadableByteStreamControllerCallPullIfNeeded(controller);\n }\n}\n\nfunction ReadableByteStreamControllerInvalidateBYOBRequest(controller) {\n if (controller._byobRequest === undefined) {\n return;\n }\n\n controller._byobRequest._associatedReadableByteStreamController = undefined;\n controller._byobRequest._view = undefined;\n controller._byobRequest = undefined;\n}\n\nfunction ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller) {\n assert(controller._closeRequested === false);\n\n while (controller._pendingPullIntos.length > 0) {\n if (controller._queueTotalSize === 0) {\n return;\n }\n\n var pullIntoDescriptor = controller._pendingPullIntos[0];\n\n if (ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) === true) {\n ReadableByteStreamControllerShiftPendingPullInto(controller);\n\n ReadableByteStreamControllerCommitPullIntoDescriptor(controller._controlledReadableStream, pullIntoDescriptor);\n }\n }\n}\n\nfunction ReadableByteStreamControllerPullInto(controller, view) {\n var stream = controller._controlledReadableStream;\n\n var elementSize = 1;\n if (view.constructor !== DataView) {\n elementSize = view.constructor.BYTES_PER_ELEMENT;\n }\n\n var ctor = view.constructor;\n\n var pullIntoDescriptor = {\n buffer: view.buffer,\n byteOffset: view.byteOffset,\n byteLength: view.byteLength,\n bytesFilled: 0,\n elementSize: elementSize,\n ctor: ctor,\n readerType: 'byob'\n };\n\n if (controller._pendingPullIntos.length > 0) {\n pullIntoDescriptor.buffer = TransferArrayBuffer(pullIntoDescriptor.buffer);\n controller._pendingPullIntos.push(pullIntoDescriptor);\n\n // No ReadableByteStreamControllerCallPullIfNeeded() call since:\n // - No change happens on desiredSize\n // - The source has already been notified of that there's at least 1 pending read(view)\n\n return ReadableStreamAddReadIntoRequest(stream);\n }\n\n if (stream._state === 'closed') {\n var emptyView = new view.constructor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, 0);\n return Promise.resolve(CreateIterResultObject(emptyView, true));\n }\n\n if (controller._queueTotalSize > 0) {\n if (ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) === true) {\n var filledView = ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor);\n\n ReadableByteStreamControllerHandleQueueDrain(controller);\n\n return Promise.resolve(CreateIterResultObject(filledView, false));\n }\n\n if (controller._closeRequested === true) {\n var e = new TypeError('Insufficient bytes to fill elements in the given buffer');\n ReadableByteStreamControllerError(controller, e);\n\n return Promise.reject(e);\n }\n }\n\n pullIntoDescriptor.buffer = TransferArrayBuffer(pullIntoDescriptor.buffer);\n controller._pendingPullIntos.push(pullIntoDescriptor);\n\n var promise = ReadableStreamAddReadIntoRequest(stream);\n\n ReadableByteStreamControllerCallPullIfNeeded(controller);\n\n return promise;\n}\n\nfunction ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor) {\n firstDescriptor.buffer = TransferArrayBuffer(firstDescriptor.buffer);\n\n assert(firstDescriptor.bytesFilled === 0, 'bytesFilled must be 0');\n\n var stream = controller._controlledReadableStream;\n if (ReadableStreamHasBYOBReader(stream) === true) {\n while (ReadableStreamGetNumReadIntoRequests(stream) > 0) {\n var pullIntoDescriptor = ReadableByteStreamControllerShiftPendingPullInto(controller);\n ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor);\n }\n }\n}\n\nfunction ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, pullIntoDescriptor) {\n if (pullIntoDescriptor.bytesFilled + bytesWritten > pullIntoDescriptor.byteLength) {\n throw new RangeError('bytesWritten out of range');\n }\n\n ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesWritten, pullIntoDescriptor);\n\n if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize) {\n // TODO: Figure out whether we should detach the buffer or not here.\n return;\n }\n\n ReadableByteStreamControllerShiftPendingPullInto(controller);\n\n var remainderSize = pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize;\n if (remainderSize > 0) {\n var end = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled;\n var remainder = pullIntoDescriptor.buffer.slice(end - remainderSize, end);\n ReadableByteStreamControllerEnqueueChunkToQueue(controller, remainder, 0, remainder.byteLength);\n }\n\n pullIntoDescriptor.buffer = TransferArrayBuffer(pullIntoDescriptor.buffer);\n pullIntoDescriptor.bytesFilled -= remainderSize;\n ReadableByteStreamControllerCommitPullIntoDescriptor(controller._controlledReadableStream, pullIntoDescriptor);\n\n ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller);\n}\n\nfunction ReadableByteStreamControllerRespondInternal(controller, bytesWritten) {\n var firstDescriptor = controller._pendingPullIntos[0];\n\n var stream = controller._controlledReadableStream;\n\n if (stream._state === 'closed') {\n if (bytesWritten !== 0) {\n throw new TypeError('bytesWritten must be 0 when calling respond() on a closed stream');\n }\n\n ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor);\n } else {\n assert(stream._state === 'readable');\n\n ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, firstDescriptor);\n }\n}\n\nfunction ReadableByteStreamControllerShiftPendingPullInto(controller) {\n var descriptor = controller._pendingPullIntos.shift();\n ReadableByteStreamControllerInvalidateBYOBRequest(controller);\n return descriptor;\n}\n\nfunction ReadableByteStreamControllerShouldCallPull(controller) {\n var stream = controller._controlledReadableStream;\n\n if (stream._state !== 'readable') {\n return false;\n }\n\n if (controller._closeRequested === true) {\n return false;\n }\n\n if (controller._started === false) {\n return false;\n }\n\n if (ReadableStreamHasDefaultReader(stream) === true && ReadableStreamGetNumReadRequests(stream) > 0) {\n return true;\n }\n\n if (ReadableStreamHasBYOBReader(stream) === true && ReadableStreamGetNumReadIntoRequests(stream) > 0) {\n return true;\n }\n\n if (ReadableByteStreamControllerGetDesiredSize(controller) > 0) {\n return true;\n }\n\n return false;\n}\n\n// A client of ReadableByteStreamController may use these functions directly to bypass state check.\n\nfunction ReadableByteStreamControllerClose(controller) {\n var stream = controller._controlledReadableStream;\n\n assert(controller._closeRequested === false);\n assert(stream._state === 'readable');\n\n if (controller._queueTotalSize > 0) {\n controller._closeRequested = true;\n\n return;\n }\n\n if (controller._pendingPullIntos.length > 0) {\n var firstPendingPullInto = controller._pendingPullIntos[0];\n if (firstPendingPullInto.bytesFilled > 0) {\n var e = new TypeError('Insufficient bytes to fill elements in the given buffer');\n ReadableByteStreamControllerError(controller, e);\n\n throw e;\n }\n }\n\n ReadableStreamClose(stream);\n}\n\nfunction ReadableByteStreamControllerEnqueue(controller, chunk) {\n var stream = controller._controlledReadableStream;\n\n assert(controller._closeRequested === false);\n assert(stream._state === 'readable');\n\n var buffer = chunk.buffer;\n var byteOffset = chunk.byteOffset;\n var byteLength = chunk.byteLength;\n var transferredBuffer = TransferArrayBuffer(buffer);\n\n if (ReadableStreamHasDefaultReader(stream) === true) {\n if (ReadableStreamGetNumReadRequests(stream) === 0) {\n ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength);\n } else {\n assert(controller._queue.length === 0);\n\n var transferredView = new Uint8Array(transferredBuffer, byteOffset, byteLength);\n ReadableStreamFulfillReadRequest(stream, transferredView, false);\n }\n } else if (ReadableStreamHasBYOBReader(stream) === true) {\n // TODO: Ideally in this branch detaching should happen only if the buffer is not consumed fully.\n ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength);\n ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller);\n } else {\n assert(IsReadableStreamLocked(stream) === false, 'stream must not be locked');\n ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength);\n }\n}\n\nfunction ReadableByteStreamControllerError(controller, e) {\n var stream = controller._controlledReadableStream;\n\n assert(stream._state === 'readable');\n\n ReadableByteStreamControllerClearPendingPullIntos(controller);\n\n ResetQueue(controller);\n ReadableStreamError(stream, e);\n}\n\nfunction ReadableByteStreamControllerGetDesiredSize(controller) {\n var stream = controller._controlledReadableStream;\n var state = stream._state;\n\n if (state === 'errored') {\n return null;\n }\n if (state === 'closed') {\n return 0;\n }\n\n return controller._strategyHWM - controller._queueTotalSize;\n}\n\nfunction ReadableByteStreamControllerRespond(controller, bytesWritten) {\n bytesWritten = Number(bytesWritten);\n if (IsFiniteNonNegativeNumber(bytesWritten) === false) {\n throw new RangeError('bytesWritten must be a finite');\n }\n\n assert(controller._pendingPullIntos.length > 0);\n\n ReadableByteStreamControllerRespondInternal(controller, bytesWritten);\n}\n\nfunction ReadableByteStreamControllerRespondWithNewView(controller, view) {\n assert(controller._pendingPullIntos.length > 0);\n\n var firstDescriptor = controller._pendingPullIntos[0];\n\n if (firstDescriptor.byteOffset + firstDescriptor.bytesFilled !== view.byteOffset) {\n throw new RangeError('The region specified by view does not match byobRequest');\n }\n if (firstDescriptor.byteLength !== view.byteLength) {\n throw new RangeError('The buffer of view has different capacity than byobRequest');\n }\n\n firstDescriptor.buffer = view.buffer;\n\n ReadableByteStreamControllerRespondInternal(controller, view.byteLength);\n}\n\n// Helper functions for the ReadableStream.\n\nfunction streamBrandCheckException(name) {\n return new TypeError('ReadableStream.prototype.' + name + ' can only be used on a ReadableStream');\n}\n\n// Helper functions for the readers.\n\nfunction readerLockException(name) {\n return new TypeError('Cannot ' + name + ' a stream using a released reader');\n}\n\n// Helper functions for the ReadableStreamDefaultReader.\n\nfunction defaultReaderBrandCheckException(name) {\n return new TypeError('ReadableStreamDefaultReader.prototype.' + name + ' can only be used on a ReadableStreamDefaultReader');\n}\n\nfunction defaultReaderClosedPromiseInitialize(reader) {\n reader._closedPromise = new Promise(function (resolve, reject) {\n reader._closedPromise_resolve = resolve;\n reader._closedPromise_reject = reject;\n });\n}\n\nfunction defaultReaderClosedPromiseInitializeAsRejected(reader, reason) {\n reader._closedPromise = Promise.reject(reason);\n reader._closedPromise_resolve = undefined;\n reader._closedPromise_reject = undefined;\n}\n\nfunction defaultReaderClosedPromiseInitializeAsResolved(reader) {\n reader._closedPromise = Promise.resolve(undefined);\n reader._closedPromise_resolve = undefined;\n reader._closedPromise_reject = undefined;\n}\n\nfunction defaultReaderClosedPromiseReject(reader, reason) {\n assert(reader._closedPromise_resolve !== undefined);\n assert(reader._closedPromise_reject !== undefined);\n\n reader._closedPromise_reject(reason);\n reader._closedPromise_resolve = undefined;\n reader._closedPromise_reject = undefined;\n}\n\nfunction defaultReaderClosedPromiseResetToRejected(reader, reason) {\n assert(reader._closedPromise_resolve === undefined);\n assert(reader._closedPromise_reject === undefined);\n\n reader._closedPromise = Promise.reject(reason);\n}\n\nfunction defaultReaderClosedPromiseResolve(reader) {\n assert(reader._closedPromise_resolve !== undefined);\n assert(reader._closedPromise_reject !== undefined);\n\n reader._closedPromise_resolve(undefined);\n reader._closedPromise_resolve = undefined;\n reader._closedPromise_reject = undefined;\n}\n\n// Helper functions for the ReadableStreamDefaultReader.\n\nfunction byobReaderBrandCheckException(name) {\n return new TypeError('ReadableStreamBYOBReader.prototype.' + name + ' can only be used on a ReadableStreamBYOBReader');\n}\n\n// Helper functions for the ReadableStreamDefaultController.\n\nfunction defaultControllerBrandCheckException(name) {\n return new TypeError('ReadableStreamDefaultController.prototype.' + name + ' can only be used on a ReadableStreamDefaultController');\n}\n\n// Helper functions for the ReadableStreamBYOBRequest.\n\nfunction byobRequestBrandCheckException(name) {\n return new TypeError('ReadableStreamBYOBRequest.prototype.' + name + ' can only be used on a ReadableStreamBYOBRequest');\n}\n\n// Helper functions for the ReadableByteStreamController.\n\nfunction byteStreamControllerBrandCheckException(name) {\n return new TypeError('ReadableByteStreamController.prototype.' + name + ' can only be used on a ReadableByteStreamController');\n}\n\n// Helper function for ReadableStream pipeThrough\n\nfunction ifIsObjectAndHasAPromiseIsHandledInternalSlotSetPromiseIsHandledToTrue(promise) {\n try {\n // This relies on the brand-check that is enforced by Promise.prototype.then(). As with the rest of the reference\n // implementation, it doesn't attempt to do the right thing if someone has modified the global environment.\n Promise.prototype.then.call(promise, undefined, function () {});\n } catch (e) {\n // The brand check failed, therefore the internal slot is not present and there's nothing further to do.\n }\n}\n\n/***/ }),\n/* 5 */\n/***/ (function(module, exports, __w_pdfjs_require__) {\n\n\"use strict\";\n\n\nvar transformStream = __w_pdfjs_require__(6);\nvar readableStream = __w_pdfjs_require__(4);\nvar writableStream = __w_pdfjs_require__(2);\n\nexports.TransformStream = transformStream.TransformStream;\nexports.ReadableStream = readableStream.ReadableStream;\nexports.IsReadableStreamDisturbed = readableStream.IsReadableStreamDisturbed;\nexports.ReadableStreamDefaultControllerClose = readableStream.ReadableStreamDefaultControllerClose;\nexports.ReadableStreamDefaultControllerEnqueue = readableStream.ReadableStreamDefaultControllerEnqueue;\nexports.ReadableStreamDefaultControllerError = readableStream.ReadableStreamDefaultControllerError;\nexports.ReadableStreamDefaultControllerGetDesiredSize = readableStream.ReadableStreamDefaultControllerGetDesiredSize;\nexports.AcquireWritableStreamDefaultWriter = writableStream.AcquireWritableStreamDefaultWriter;\nexports.IsWritableStream = writableStream.IsWritableStream;\nexports.IsWritableStreamLocked = writableStream.IsWritableStreamLocked;\nexports.WritableStream = writableStream.WritableStream;\nexports.WritableStreamAbort = writableStream.WritableStreamAbort;\nexports.WritableStreamDefaultControllerError = writableStream.WritableStreamDefaultControllerError;\nexports.WritableStreamDefaultWriterCloseWithErrorPropagation = writableStream.WritableStreamDefaultWriterCloseWithErrorPropagation;\nexports.WritableStreamDefaultWriterRelease = writableStream.WritableStreamDefaultWriterRelease;\nexports.WritableStreamDefaultWriterWrite = writableStream.WritableStreamDefaultWriterWrite;\n\n/***/ }),\n/* 6 */\n/***/ (function(module, exports, __w_pdfjs_require__) {\n\n\"use strict\";\n\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar _require = __w_pdfjs_require__(1),\n assert = _require.assert;\n\nvar _require2 = __w_pdfjs_require__(0),\n InvokeOrNoop = _require2.InvokeOrNoop,\n PromiseInvokeOrPerformFallback = _require2.PromiseInvokeOrPerformFallback,\n PromiseInvokeOrNoop = _require2.PromiseInvokeOrNoop,\n typeIsObject = _require2.typeIsObject;\n\nvar _require3 = __w_pdfjs_require__(4),\n ReadableStream = _require3.ReadableStream,\n ReadableStreamDefaultControllerClose = _require3.ReadableStreamDefaultControllerClose,\n ReadableStreamDefaultControllerEnqueue = _require3.ReadableStreamDefaultControllerEnqueue,\n ReadableStreamDefaultControllerError = _require3.ReadableStreamDefaultControllerError,\n ReadableStreamDefaultControllerGetDesiredSize = _require3.ReadableStreamDefaultControllerGetDesiredSize;\n\nvar _require4 = __w_pdfjs_require__(2),\n WritableStream = _require4.WritableStream,\n WritableStreamDefaultControllerError = _require4.WritableStreamDefaultControllerError;\n\n// Methods on the transform stream controller object\n\nfunction TransformStreamCloseReadable(transformStream) {\n // console.log('TransformStreamCloseReadable()');\n\n if (transformStream._errored === true) {\n throw new TypeError('TransformStream is already errored');\n }\n\n if (transformStream._readableClosed === true) {\n throw new TypeError('Readable side is already closed');\n }\n\n TransformStreamCloseReadableInternal(transformStream);\n}\n\nfunction TransformStreamEnqueueToReadable(transformStream, chunk) {\n // console.log('TransformStreamEnqueueToReadable()');\n\n if (transformStream._errored === true) {\n throw new TypeError('TransformStream is already errored');\n }\n\n if (transformStream._readableClosed === true) {\n throw new TypeError('Readable side is already closed');\n }\n\n // We throttle transformer.transform invocation based on the backpressure of the ReadableStream, but we still\n // accept TransformStreamEnqueueToReadable() calls.\n\n var controller = transformStream._readableController;\n\n try {\n ReadableStreamDefaultControllerEnqueue(controller, chunk);\n } catch (e) {\n // This happens when readableStrategy.size() throws.\n // The ReadableStream has already errored itself.\n transformStream._readableClosed = true;\n TransformStreamErrorIfNeeded(transformStream, e);\n\n throw transformStream._storedError;\n }\n\n var desiredSize = ReadableStreamDefaultControllerGetDesiredSize(controller);\n var maybeBackpressure = desiredSize <= 0;\n\n if (maybeBackpressure === true && transformStream._backpressure === false) {\n // This allows pull() again. When desiredSize is 0, it's possible that a pull() will happen immediately (but\n // asynchronously) after this because of pending read()s and set _backpressure back to false.\n //\n // If pull() could be called from inside enqueue(), then this logic would be wrong. This cannot happen\n // because there is always a promise pending from start() or pull() when _backpressure is false.\n TransformStreamSetBackpressure(transformStream, true);\n }\n}\n\nfunction TransformStreamError(transformStream, e) {\n if (transformStream._errored === true) {\n throw new TypeError('TransformStream is already errored');\n }\n\n TransformStreamErrorInternal(transformStream, e);\n}\n\n// Abstract operations.\n\nfunction TransformStreamCloseReadableInternal(transformStream) {\n assert(transformStream._errored === false);\n assert(transformStream._readableClosed === false);\n\n try {\n ReadableStreamDefaultControllerClose(transformStream._readableController);\n } catch (e) {\n assert(false);\n }\n\n transformStream._readableClosed = true;\n}\n\nfunction TransformStreamErrorIfNeeded(transformStream, e) {\n if (transformStream._errored === false) {\n TransformStreamErrorInternal(transformStream, e);\n }\n}\n\nfunction TransformStreamErrorInternal(transformStream, e) {\n // console.log('TransformStreamErrorInternal()');\n\n assert(transformStream._errored === false);\n\n transformStream._errored = true;\n transformStream._storedError = e;\n\n if (transformStream._writableDone === false) {\n WritableStreamDefaultControllerError(transformStream._writableController, e);\n }\n if (transformStream._readableClosed === false) {\n ReadableStreamDefaultControllerError(transformStream._readableController, e);\n }\n}\n\n// Used for preventing the next write() call on TransformStreamSink until there\n// is no longer backpressure.\nfunction TransformStreamReadableReadyPromise(transformStream) {\n assert(transformStream._backpressureChangePromise !== undefined, '_backpressureChangePromise should have been initialized');\n\n if (transformStream._backpressure === false) {\n return Promise.resolve();\n }\n\n assert(transformStream._backpressure === true, '_backpressure should have been initialized');\n\n return transformStream._backpressureChangePromise;\n}\n\nfunction TransformStreamSetBackpressure(transformStream, backpressure) {\n // console.log(`TransformStreamSetBackpressure(${backpressure})`);\n\n // Passes also when called during construction.\n assert(transformStream._backpressure !== backpressure, 'TransformStreamSetBackpressure() should be called only when backpressure is changed');\n\n if (transformStream._backpressureChangePromise !== undefined) {\n // The fulfillment value is just for a sanity check.\n transformStream._backpressureChangePromise_resolve(backpressure);\n }\n\n transformStream._backpressureChangePromise = new Promise(function (resolve) {\n transformStream._backpressureChangePromise_resolve = resolve;\n });\n\n transformStream._backpressureChangePromise.then(function (resolution) {\n assert(resolution !== backpressure, '_backpressureChangePromise should be fulfilled only when backpressure is changed');\n });\n\n transformStream._backpressure = backpressure;\n}\n\nfunction TransformStreamDefaultTransform(chunk, transformStreamController) {\n var transformStream = transformStreamController._controlledTransformStream;\n TransformStreamEnqueueToReadable(transformStream, chunk);\n return Promise.resolve();\n}\n\nfunction TransformStreamTransform(transformStream, chunk) {\n // console.log('TransformStreamTransform()');\n\n assert(transformStream._errored === false);\n assert(transformStream._transforming === false);\n assert(transformStream._backpressure === false);\n\n transformStream._transforming = true;\n\n var transformer = transformStream._transformer;\n var controller = transformStream._transformStreamController;\n\n var transformPromise = PromiseInvokeOrPerformFallback(transformer, 'transform', [chunk, controller], TransformStreamDefaultTransform, [chunk, controller]);\n\n return transformPromise.then(function () {\n transformStream._transforming = false;\n\n return TransformStreamReadableReadyPromise(transformStream);\n }, function (e) {\n TransformStreamErrorIfNeeded(transformStream, e);\n return Promise.reject(e);\n });\n}\n\nfunction IsTransformStreamDefaultController(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_controlledTransformStream')) {\n return false;\n }\n\n return true;\n}\n\nfunction IsTransformStream(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_transformStreamController')) {\n return false;\n }\n\n return true;\n}\n\nvar TransformStreamSink = function () {\n function TransformStreamSink(transformStream, startPromise) {\n _classCallCheck(this, TransformStreamSink);\n\n this._transformStream = transformStream;\n this._startPromise = startPromise;\n }\n\n _createClass(TransformStreamSink, [{\n key: 'start',\n value: function start(c) {\n var transformStream = this._transformStream;\n\n transformStream._writableController = c;\n\n return this._startPromise.then(function () {\n return TransformStreamReadableReadyPromise(transformStream);\n });\n }\n }, {\n key: 'write',\n value: function write(chunk) {\n // console.log('TransformStreamSink.write()');\n\n var transformStream = this._transformStream;\n\n return TransformStreamTransform(transformStream, chunk);\n }\n }, {\n key: 'abort',\n value: function abort() {\n var transformStream = this._transformStream;\n transformStream._writableDone = true;\n TransformStreamErrorInternal(transformStream, new TypeError('Writable side aborted'));\n }\n }, {\n key: 'close',\n value: function close() {\n // console.log('TransformStreamSink.close()');\n\n var transformStream = this._transformStream;\n\n assert(transformStream._transforming === false);\n\n transformStream._writableDone = true;\n\n var flushPromise = PromiseInvokeOrNoop(transformStream._transformer, 'flush', [transformStream._transformStreamController]);\n // Return a promise that is fulfilled with undefined on success.\n return flushPromise.then(function () {\n if (transformStream._errored === true) {\n return Promise.reject(transformStream._storedError);\n }\n if (transformStream._readableClosed === false) {\n TransformStreamCloseReadableInternal(transformStream);\n }\n return Promise.resolve();\n }).catch(function (r) {\n TransformStreamErrorIfNeeded(transformStream, r);\n return Promise.reject(transformStream._storedError);\n });\n }\n }]);\n\n return TransformStreamSink;\n}();\n\nvar TransformStreamSource = function () {\n function TransformStreamSource(transformStream, startPromise) {\n _classCallCheck(this, TransformStreamSource);\n\n this._transformStream = transformStream;\n this._startPromise = startPromise;\n }\n\n _createClass(TransformStreamSource, [{\n key: 'start',\n value: function start(c) {\n var transformStream = this._transformStream;\n\n transformStream._readableController = c;\n\n return this._startPromise.then(function () {\n // Prevent the first pull() call until there is backpressure.\n\n assert(transformStream._backpressureChangePromise !== undefined, '_backpressureChangePromise should have been initialized');\n\n if (transformStream._backpressure === true) {\n return Promise.resolve();\n }\n\n assert(transformStream._backpressure === false, '_backpressure should have been initialized');\n\n return transformStream._backpressureChangePromise;\n });\n }\n }, {\n key: 'pull',\n value: function pull() {\n // console.log('TransformStreamSource.pull()');\n\n var transformStream = this._transformStream;\n\n // Invariant. Enforced by the promises returned by start() and pull().\n assert(transformStream._backpressure === true, 'pull() should be never called while _backpressure is false');\n\n assert(transformStream._backpressureChangePromise !== undefined, '_backpressureChangePromise should have been initialized');\n\n TransformStreamSetBackpressure(transformStream, false);\n\n // Prevent the next pull() call until there is backpressure.\n return transformStream._backpressureChangePromise;\n }\n }, {\n key: 'cancel',\n value: function cancel() {\n var transformStream = this._transformStream;\n transformStream._readableClosed = true;\n TransformStreamErrorInternal(transformStream, new TypeError('Readable side canceled'));\n }\n }]);\n\n return TransformStreamSource;\n}();\n\nvar TransformStreamDefaultController = function () {\n function TransformStreamDefaultController(transformStream) {\n _classCallCheck(this, TransformStreamDefaultController);\n\n if (IsTransformStream(transformStream) === false) {\n throw new TypeError('TransformStreamDefaultController can only be ' + 'constructed with a TransformStream instance');\n }\n\n if (transformStream._transformStreamController !== undefined) {\n throw new TypeError('TransformStreamDefaultController instances can ' + 'only be created by the TransformStream constructor');\n }\n\n this._controlledTransformStream = transformStream;\n }\n\n _createClass(TransformStreamDefaultController, [{\n key: 'enqueue',\n value: function enqueue(chunk) {\n if (IsTransformStreamDefaultController(this) === false) {\n throw defaultControllerBrandCheckException('enqueue');\n }\n\n TransformStreamEnqueueToReadable(this._controlledTransformStream, chunk);\n }\n }, {\n key: 'close',\n value: function close() {\n if (IsTransformStreamDefaultController(this) === false) {\n throw defaultControllerBrandCheckException('close');\n }\n\n TransformStreamCloseReadable(this._controlledTransformStream);\n }\n }, {\n key: 'error',\n value: function error(reason) {\n if (IsTransformStreamDefaultController(this) === false) {\n throw defaultControllerBrandCheckException('error');\n }\n\n TransformStreamError(this._controlledTransformStream, reason);\n }\n }, {\n key: 'desiredSize',\n get: function get() {\n if (IsTransformStreamDefaultController(this) === false) {\n throw defaultControllerBrandCheckException('desiredSize');\n }\n\n var transformStream = this._controlledTransformStream;\n var readableController = transformStream._readableController;\n\n return ReadableStreamDefaultControllerGetDesiredSize(readableController);\n }\n }]);\n\n return TransformStreamDefaultController;\n}();\n\nvar TransformStream = function () {\n function TransformStream() {\n var transformer = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n _classCallCheck(this, TransformStream);\n\n this._transformer = transformer;\n var readableStrategy = transformer.readableStrategy,\n writableStrategy = transformer.writableStrategy;\n\n\n this._transforming = false;\n this._errored = false;\n this._storedError = undefined;\n\n this._writableController = undefined;\n this._readableController = undefined;\n this._transformStreamController = undefined;\n\n this._writableDone = false;\n this._readableClosed = false;\n\n this._backpressure = undefined;\n this._backpressureChangePromise = undefined;\n this._backpressureChangePromise_resolve = undefined;\n\n this._transformStreamController = new TransformStreamDefaultController(this);\n\n var startPromise_resolve = void 0;\n var startPromise = new Promise(function (resolve) {\n startPromise_resolve = resolve;\n });\n\n var source = new TransformStreamSource(this, startPromise);\n\n this._readable = new ReadableStream(source, readableStrategy);\n\n var sink = new TransformStreamSink(this, startPromise);\n\n this._writable = new WritableStream(sink, writableStrategy);\n\n assert(this._writableController !== undefined);\n assert(this._readableController !== undefined);\n\n var desiredSize = ReadableStreamDefaultControllerGetDesiredSize(this._readableController);\n // Set _backpressure based on desiredSize. As there is no read() at this point, we can just interpret\n // desiredSize being non-positive as backpressure.\n TransformStreamSetBackpressure(this, desiredSize <= 0);\n\n var transformStream = this;\n var startResult = InvokeOrNoop(transformer, 'start', [transformStream._transformStreamController]);\n startPromise_resolve(startResult);\n startPromise.catch(function (e) {\n // The underlyingSink and underlyingSource will error the readable and writable ends on their own.\n if (transformStream._errored === false) {\n transformStream._errored = true;\n transformStream._storedError = e;\n }\n });\n }\n\n _createClass(TransformStream, [{\n key: 'readable',\n get: function get() {\n if (IsTransformStream(this) === false) {\n throw streamBrandCheckException('readable');\n }\n\n return this._readable;\n }\n }, {\n key: 'writable',\n get: function get() {\n if (IsTransformStream(this) === false) {\n throw streamBrandCheckException('writable');\n }\n\n return this._writable;\n }\n }]);\n\n return TransformStream;\n}();\n\nmodule.exports = { TransformStream: TransformStream };\n\n// Helper functions for the TransformStreamDefaultController.\n\nfunction defaultControllerBrandCheckException(name) {\n return new TypeError('TransformStreamDefaultController.prototype.' + name + ' can only be used on a TransformStreamDefaultController');\n}\n\n// Helper functions for the TransformStream.\n\nfunction streamBrandCheckException(name) {\n return new TypeError('TransformStream.prototype.' + name + ' can only be used on a TransformStream');\n}\n\n/***/ }),\n/* 7 */\n/***/ (function(module, exports, __w_pdfjs_require__) {\n\nmodule.exports = __w_pdfjs_require__(5);\n\n\n/***/ })\n/******/ ])));\n\n\n// WEBPACK FOOTER //\n// external/streams/streams-lib.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n FONT_IDENTITY_MATRIX, IDENTITY_MATRIX, ImageKind, info, isArray,\n isLittleEndian, isNum, OPS, shadow, TextRenderingMode, Util, warn\n} from '../shared/util';\nimport { getShadingPatternFromIR, TilingPattern } from './pattern_helper';\nimport { WebGLUtils } from './webgl';\n\n// contexts store most of the state we need natively.\n// However, PDF needs a bit more state, which we store here.\n\n// Minimal font size that would be used during canvas fillText operations.\nvar MIN_FONT_SIZE = 16;\n// Maximum font size that would be used during canvas fillText operations.\nvar MAX_FONT_SIZE = 100;\nvar MAX_GROUP_SIZE = 4096;\n\n// Heuristic value used when enforcing minimum line widths.\nvar MIN_WIDTH_FACTOR = 0.65;\n\nvar COMPILE_TYPE3_GLYPHS = true;\nvar MAX_SIZE_TO_COMPILE = 1000;\n\nvar FULL_CHUNK_HEIGHT = 16;\n\nvar IsLittleEndianCached = {\n get value() {\n return shadow(IsLittleEndianCached, 'value', isLittleEndian());\n },\n};\n\nfunction addContextCurrentTransform(ctx) {\n // If the context doesn't expose a `mozCurrentTransform`, add a JS based one.\n if (!ctx.mozCurrentTransform) {\n ctx._originalSave = ctx.save;\n ctx._originalRestore = ctx.restore;\n ctx._originalRotate = ctx.rotate;\n ctx._originalScale = ctx.scale;\n ctx._originalTranslate = ctx.translate;\n ctx._originalTransform = ctx.transform;\n ctx._originalSetTransform = ctx.setTransform;\n\n ctx._transformMatrix = ctx._transformMatrix || [1, 0, 0, 1, 0, 0];\n ctx._transformStack = [];\n\n Object.defineProperty(ctx, 'mozCurrentTransform', {\n get: function getCurrentTransform() {\n return this._transformMatrix;\n },\n });\n\n Object.defineProperty(ctx, 'mozCurrentTransformInverse', {\n get: function getCurrentTransformInverse() {\n // Calculation done using WolframAlpha:\n // http://www.wolframalpha.com/input/?\n // i=Inverse+{{a%2C+c%2C+e}%2C+{b%2C+d%2C+f}%2C+{0%2C+0%2C+1}}\n\n var m = this._transformMatrix;\n var a = m[0], b = m[1], c = m[2], d = m[3], e = m[4], f = m[5];\n\n var ad_bc = a * d - b * c;\n var bc_ad = b * c - a * d;\n\n return [\n d / ad_bc,\n b / bc_ad,\n c / bc_ad,\n a / ad_bc,\n (d * e - c * f) / bc_ad,\n (b * e - a * f) / ad_bc\n ];\n },\n });\n\n ctx.save = function ctxSave() {\n var old = this._transformMatrix;\n this._transformStack.push(old);\n this._transformMatrix = old.slice(0, 6);\n\n this._originalSave();\n };\n\n ctx.restore = function ctxRestore() {\n var prev = this._transformStack.pop();\n if (prev) {\n this._transformMatrix = prev;\n this._originalRestore();\n }\n };\n\n ctx.translate = function ctxTranslate(x, y) {\n var m = this._transformMatrix;\n m[4] = m[0] * x + m[2] * y + m[4];\n m[5] = m[1] * x + m[3] * y + m[5];\n\n this._originalTranslate(x, y);\n };\n\n ctx.scale = function ctxScale(x, y) {\n var m = this._transformMatrix;\n m[0] = m[0] * x;\n m[1] = m[1] * x;\n m[2] = m[2] * y;\n m[3] = m[3] * y;\n\n this._originalScale(x, y);\n };\n\n ctx.transform = function ctxTransform(a, b, c, d, e, f) {\n var m = this._transformMatrix;\n this._transformMatrix = [\n m[0] * a + m[2] * b,\n m[1] * a + m[3] * b,\n m[0] * c + m[2] * d,\n m[1] * c + m[3] * d,\n m[0] * e + m[2] * f + m[4],\n m[1] * e + m[3] * f + m[5]\n ];\n\n ctx._originalTransform(a, b, c, d, e, f);\n };\n\n ctx.setTransform = function ctxSetTransform(a, b, c, d, e, f) {\n this._transformMatrix = [a, b, c, d, e, f];\n\n ctx._originalSetTransform(a, b, c, d, e, f);\n };\n\n ctx.rotate = function ctxRotate(angle) {\n var cosValue = Math.cos(angle);\n var sinValue = Math.sin(angle);\n\n var m = this._transformMatrix;\n this._transformMatrix = [\n m[0] * cosValue + m[2] * sinValue,\n m[1] * cosValue + m[3] * sinValue,\n m[0] * (-sinValue) + m[2] * cosValue,\n m[1] * (-sinValue) + m[3] * cosValue,\n m[4],\n m[5]\n ];\n\n this._originalRotate(angle);\n };\n }\n}\n\nvar CachedCanvases = (function CachedCanvasesClosure() {\n function CachedCanvases(canvasFactory) {\n this.canvasFactory = canvasFactory;\n this.cache = Object.create(null);\n }\n CachedCanvases.prototype = {\n getCanvas: function CachedCanvases_getCanvas(id, width, height,\n trackTransform) {\n var canvasEntry;\n if (this.cache[id] !== undefined) {\n canvasEntry = this.cache[id];\n this.canvasFactory.reset(canvasEntry, width, height);\n // reset canvas transform for emulated mozCurrentTransform, if needed\n canvasEntry.context.setTransform(1, 0, 0, 1, 0, 0);\n } else {\n canvasEntry = this.canvasFactory.create(width, height);\n this.cache[id] = canvasEntry;\n }\n if (trackTransform) {\n addContextCurrentTransform(canvasEntry.context);\n }\n return canvasEntry;\n },\n clear() {\n for (var id in this.cache) {\n var canvasEntry = this.cache[id];\n this.canvasFactory.destroy(canvasEntry);\n delete this.cache[id];\n }\n },\n };\n return CachedCanvases;\n})();\n\nfunction compileType3Glyph(imgData) {\n var POINT_TO_PROCESS_LIMIT = 1000;\n\n var width = imgData.width, height = imgData.height;\n var i, j, j0, width1 = width + 1;\n var points = new Uint8Array(width1 * (height + 1));\n var POINT_TYPES =\n new Uint8Array([0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0]);\n\n // decodes bit-packed mask data\n var lineSize = (width + 7) & ~7, data0 = imgData.data;\n var data = new Uint8Array(lineSize * height), pos = 0, ii;\n for (i = 0, ii = data0.length; i < ii; i++) {\n var mask = 128, elem = data0[i];\n while (mask > 0) {\n data[pos++] = (elem & mask) ? 0 : 255;\n mask >>= 1;\n }\n }\n\n // finding iteresting points: every point is located between mask pixels,\n // so there will be points of the (width + 1)x(height + 1) grid. Every point\n // will have flags assigned based on neighboring mask pixels:\n // 4 | 8\n // --P--\n // 2 | 1\n // We are interested only in points with the flags:\n // - outside corners: 1, 2, 4, 8;\n // - inside corners: 7, 11, 13, 14;\n // - and, intersections: 5, 10.\n var count = 0;\n pos = 0;\n if (data[pos] !== 0) {\n points[0] = 1;\n ++count;\n }\n for (j = 1; j < width; j++) {\n if (data[pos] !== data[pos + 1]) {\n points[j] = data[pos] ? 2 : 1;\n ++count;\n }\n pos++;\n }\n if (data[pos] !== 0) {\n points[j] = 2;\n ++count;\n }\n for (i = 1; i < height; i++) {\n pos = i * lineSize;\n j0 = i * width1;\n if (data[pos - lineSize] !== data[pos]) {\n points[j0] = data[pos] ? 1 : 8;\n ++count;\n }\n // 'sum' is the position of the current pixel configuration in the 'TYPES'\n // array (in order 8-1-2-4, so we can use '>>2' to shift the column).\n var sum = (data[pos] ? 4 : 0) + (data[pos - lineSize] ? 8 : 0);\n for (j = 1; j < width; j++) {\n sum = (sum >> 2) + (data[pos + 1] ? 4 : 0) +\n (data[pos - lineSize + 1] ? 8 : 0);\n if (POINT_TYPES[sum]) {\n points[j0 + j] = POINT_TYPES[sum];\n ++count;\n }\n pos++;\n }\n if (data[pos - lineSize] !== data[pos]) {\n points[j0 + j] = data[pos] ? 2 : 4;\n ++count;\n }\n\n if (count > POINT_TO_PROCESS_LIMIT) {\n return null;\n }\n }\n\n pos = lineSize * (height - 1);\n j0 = i * width1;\n if (data[pos] !== 0) {\n points[j0] = 8;\n ++count;\n }\n for (j = 1; j < width; j++) {\n if (data[pos] !== data[pos + 1]) {\n points[j0 + j] = data[pos] ? 4 : 8;\n ++count;\n }\n pos++;\n }\n if (data[pos] !== 0) {\n points[j0 + j] = 4;\n ++count;\n }\n if (count > POINT_TO_PROCESS_LIMIT) {\n return null;\n }\n\n // building outlines\n var steps = new Int32Array([0, width1, -1, 0, -width1, 0, 0, 0, 1]);\n var outlines = [];\n for (i = 0; count && i <= height; i++) {\n var p = i * width1;\n var end = p + width;\n while (p < end && !points[p]) {\n p++;\n }\n if (p === end) {\n continue;\n }\n var coords = [p % width1, i];\n\n var type = points[p], p0 = p, pp;\n do {\n var step = steps[type];\n do {\n p += step;\n } while (!points[p]);\n\n pp = points[p];\n if (pp !== 5 && pp !== 10) {\n // set new direction\n type = pp;\n // delete mark\n points[p] = 0;\n } else { // type is 5 or 10, ie, a crossing\n // set new direction\n type = pp & ((0x33 * type) >> 4);\n // set new type for \"future hit\"\n points[p] &= (type >> 2 | type << 2);\n }\n\n coords.push(p % width1);\n coords.push((p / width1) | 0);\n --count;\n } while (p0 !== p);\n outlines.push(coords);\n --i;\n }\n\n var drawOutline = function(c) {\n c.save();\n // the path shall be painted in [0..1]x[0..1] space\n c.scale(1 / width, -1 / height);\n c.translate(0, -height);\n c.beginPath();\n for (var i = 0, ii = outlines.length; i < ii; i++) {\n var o = outlines[i];\n c.moveTo(o[0], o[1]);\n for (var j = 2, jj = o.length; j < jj; j += 2) {\n c.lineTo(o[j], o[j + 1]);\n }\n }\n c.fill();\n c.beginPath();\n c.restore();\n };\n\n return drawOutline;\n}\n\nvar CanvasExtraState = (function CanvasExtraStateClosure() {\n function CanvasExtraState() {\n // Are soft masks and alpha values shapes or opacities?\n this.alphaIsShape = false;\n this.fontSize = 0;\n this.fontSizeScale = 1;\n this.textMatrix = IDENTITY_MATRIX;\n this.textMatrixScale = 1;\n this.fontMatrix = FONT_IDENTITY_MATRIX;\n this.leading = 0;\n // Current point (in user coordinates)\n this.x = 0;\n this.y = 0;\n // Start of text line (in text coordinates)\n this.lineX = 0;\n this.lineY = 0;\n // Character and word spacing\n this.charSpacing = 0;\n this.wordSpacing = 0;\n this.textHScale = 1;\n this.textRenderingMode = TextRenderingMode.FILL;\n this.textRise = 0;\n // Default fore and background colors\n this.fillColor = '#000000';\n this.strokeColor = '#000000';\n this.patternFill = false;\n // Note: fill alpha applies to all non-stroking operations\n this.fillAlpha = 1;\n this.strokeAlpha = 1;\n this.lineWidth = 1;\n this.activeSMask = null;\n this.resumeSMaskCtx = null; // nonclonable field (see the save method below)\n }\n\n CanvasExtraState.prototype = {\n clone: function CanvasExtraState_clone() {\n return Object.create(this);\n },\n setCurrentPoint: function CanvasExtraState_setCurrentPoint(x, y) {\n this.x = x;\n this.y = y;\n },\n };\n return CanvasExtraState;\n})();\n\nvar CanvasGraphics = (function CanvasGraphicsClosure() {\n // Defines the time the executeOperatorList is going to be executing\n // before it stops and shedules a continue of execution.\n var EXECUTION_TIME = 15;\n // Defines the number of steps before checking the execution time\n var EXECUTION_STEPS = 10;\n\n function CanvasGraphics(canvasCtx, commonObjs, objs, canvasFactory,\n imageLayer) {\n this.ctx = canvasCtx;\n this.current = new CanvasExtraState();\n this.stateStack = [];\n this.pendingClip = null;\n this.pendingEOFill = false;\n this.res = null;\n this.xobjs = null;\n this.commonObjs = commonObjs;\n this.objs = objs;\n this.canvasFactory = canvasFactory;\n this.imageLayer = imageLayer;\n this.groupStack = [];\n this.processingType3 = null;\n // Patterns are painted relative to the initial page/form transform, see pdf\n // spec 8.7.2 NOTE 1.\n this.baseTransform = null;\n this.baseTransformStack = [];\n this.groupLevel = 0;\n this.smaskStack = [];\n this.smaskCounter = 0;\n this.tempSMask = null;\n this.cachedCanvases = new CachedCanvases(this.canvasFactory);\n if (canvasCtx) {\n // NOTE: if mozCurrentTransform is polyfilled, then the current state of\n // the transformation must already be set in canvasCtx._transformMatrix.\n addContextCurrentTransform(canvasCtx);\n }\n this.cachedGetSinglePixelWidth = null;\n }\n\n function putBinaryImageData(ctx, imgData) {\n if (typeof ImageData !== 'undefined' && imgData instanceof ImageData) {\n ctx.putImageData(imgData, 0, 0);\n return;\n }\n\n // Put the image data to the canvas in chunks, rather than putting the\n // whole image at once. This saves JS memory, because the ImageData object\n // is smaller. It also possibly saves C++ memory within the implementation\n // of putImageData(). (E.g. in Firefox we make two short-lived copies of\n // the data passed to putImageData()). |n| shouldn't be too small, however,\n // because too many putImageData() calls will slow things down.\n //\n // Note: as written, if the last chunk is partial, the putImageData() call\n // will (conceptually) put pixels past the bounds of the canvas. But\n // that's ok; any such pixels are ignored.\n\n var height = imgData.height, width = imgData.width;\n var partialChunkHeight = height % FULL_CHUNK_HEIGHT;\n var fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;\n var totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;\n\n var chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);\n var srcPos = 0, destPos;\n var src = imgData.data;\n var dest = chunkImgData.data;\n var i, j, thisChunkHeight, elemsInThisChunk;\n\n // There are multiple forms in which the pixel data can be passed, and\n // imgData.kind tells us which one this is.\n if (imgData.kind === ImageKind.GRAYSCALE_1BPP) {\n // Grayscale, 1 bit per pixel (i.e. black-and-white).\n var srcLength = src.byteLength;\n var dest32 = new Uint32Array(dest.buffer, 0, dest.byteLength >> 2);\n var dest32DataLength = dest32.length;\n var fullSrcDiff = (width + 7) >> 3;\n var white = 0xFFFFFFFF;\n var black = IsLittleEndianCached.value ? 0xFF000000 : 0x000000FF;\n for (i = 0; i < totalChunks; i++) {\n thisChunkHeight =\n (i < fullChunks) ? FULL_CHUNK_HEIGHT : partialChunkHeight;\n destPos = 0;\n for (j = 0; j < thisChunkHeight; j++) {\n var srcDiff = srcLength - srcPos;\n var k = 0;\n var kEnd = (srcDiff > fullSrcDiff) ? width : srcDiff * 8 - 7;\n var kEndUnrolled = kEnd & ~7;\n var mask = 0;\n var srcByte = 0;\n for (; k < kEndUnrolled; k += 8) {\n srcByte = src[srcPos++];\n dest32[destPos++] = (srcByte & 128) ? white : black;\n dest32[destPos++] = (srcByte & 64) ? white : black;\n dest32[destPos++] = (srcByte & 32) ? white : black;\n dest32[destPos++] = (srcByte & 16) ? white : black;\n dest32[destPos++] = (srcByte & 8) ? white : black;\n dest32[destPos++] = (srcByte & 4) ? white : black;\n dest32[destPos++] = (srcByte & 2) ? white : black;\n dest32[destPos++] = (srcByte & 1) ? white : black;\n }\n for (; k < kEnd; k++) {\n if (mask === 0) {\n srcByte = src[srcPos++];\n mask = 128;\n }\n\n dest32[destPos++] = (srcByte & mask) ? white : black;\n mask >>= 1;\n }\n }\n // We ran out of input. Make all remaining pixels transparent.\n while (destPos < dest32DataLength) {\n dest32[destPos++] = 0;\n }\n\n ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);\n }\n } else if (imgData.kind === ImageKind.RGBA_32BPP) {\n // RGBA, 32-bits per pixel.\n\n j = 0;\n elemsInThisChunk = width * FULL_CHUNK_HEIGHT * 4;\n for (i = 0; i < fullChunks; i++) {\n dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));\n srcPos += elemsInThisChunk;\n\n ctx.putImageData(chunkImgData, 0, j);\n j += FULL_CHUNK_HEIGHT;\n }\n if (i < totalChunks) {\n elemsInThisChunk = width * partialChunkHeight * 4;\n dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));\n ctx.putImageData(chunkImgData, 0, j);\n }\n\n } else if (imgData.kind === ImageKind.RGB_24BPP) {\n // RGB, 24-bits per pixel.\n thisChunkHeight = FULL_CHUNK_HEIGHT;\n elemsInThisChunk = width * thisChunkHeight;\n for (i = 0; i < totalChunks; i++) {\n if (i >= fullChunks) {\n thisChunkHeight = partialChunkHeight;\n elemsInThisChunk = width * thisChunkHeight;\n }\n\n destPos = 0;\n for (j = elemsInThisChunk; j--;) {\n dest[destPos++] = src[srcPos++];\n dest[destPos++] = src[srcPos++];\n dest[destPos++] = src[srcPos++];\n dest[destPos++] = 255;\n }\n ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);\n }\n } else {\n throw new Error(`bad image kind: ${imgData.kind}`);\n }\n }\n\n function putBinaryImageMask(ctx, imgData) {\n var height = imgData.height, width = imgData.width;\n var partialChunkHeight = height % FULL_CHUNK_HEIGHT;\n var fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;\n var totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;\n\n var chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);\n var srcPos = 0;\n var src = imgData.data;\n var dest = chunkImgData.data;\n\n for (var i = 0; i < totalChunks; i++) {\n var thisChunkHeight =\n (i < fullChunks) ? FULL_CHUNK_HEIGHT : partialChunkHeight;\n\n // Expand the mask so it can be used by the canvas. Any required\n // inversion has already been handled.\n var destPos = 3; // alpha component offset\n for (var j = 0; j < thisChunkHeight; j++) {\n var mask = 0;\n for (var k = 0; k < width; k++) {\n if (!mask) {\n var elem = src[srcPos++];\n mask = 128;\n }\n dest[destPos] = (elem & mask) ? 0 : 255;\n destPos += 4;\n mask >>= 1;\n }\n }\n ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);\n }\n }\n\n function copyCtxState(sourceCtx, destCtx) {\n var properties = ['strokeStyle', 'fillStyle', 'fillRule', 'globalAlpha',\n 'lineWidth', 'lineCap', 'lineJoin', 'miterLimit',\n 'globalCompositeOperation', 'font'];\n for (var i = 0, ii = properties.length; i < ii; i++) {\n var property = properties[i];\n if (sourceCtx[property] !== undefined) {\n destCtx[property] = sourceCtx[property];\n }\n }\n if (sourceCtx.setLineDash !== undefined) {\n destCtx.setLineDash(sourceCtx.getLineDash());\n destCtx.lineDashOffset = sourceCtx.lineDashOffset;\n }\n }\n\n function resetCtxToDefault(ctx) {\n ctx.strokeStyle = '#000000';\n ctx.fillStyle = '#000000';\n ctx.fillRule = 'nonzero';\n ctx.globalAlpha = 1;\n ctx.lineWidth = 1;\n ctx.lineCap = 'butt';\n ctx.lineJoin = 'miter';\n ctx.miterLimit = 10;\n ctx.globalCompositeOperation = 'source-over';\n ctx.font = '10px sans-serif';\n if (ctx.setLineDash !== undefined) {\n ctx.setLineDash([]);\n ctx.lineDashOffset = 0;\n }\n }\n\n function composeSMaskBackdrop(bytes, r0, g0, b0) {\n var length = bytes.length;\n for (var i = 3; i < length; i += 4) {\n var alpha = bytes[i];\n if (alpha === 0) {\n bytes[i - 3] = r0;\n bytes[i - 2] = g0;\n bytes[i - 1] = b0;\n } else if (alpha < 255) {\n var alpha_ = 255 - alpha;\n bytes[i - 3] = (bytes[i - 3] * alpha + r0 * alpha_) >> 8;\n bytes[i - 2] = (bytes[i - 2] * alpha + g0 * alpha_) >> 8;\n bytes[i - 1] = (bytes[i - 1] * alpha + b0 * alpha_) >> 8;\n }\n }\n }\n\n function composeSMaskAlpha(maskData, layerData, transferMap) {\n var length = maskData.length;\n var scale = 1 / 255;\n for (var i = 3; i < length; i += 4) {\n var alpha = transferMap ? transferMap[maskData[i]] : maskData[i];\n layerData[i] = (layerData[i] * alpha * scale) | 0;\n }\n }\n\n function composeSMaskLuminosity(maskData, layerData, transferMap) {\n var length = maskData.length;\n for (var i = 3; i < length; i += 4) {\n var y = (maskData[i - 3] * 77) + // * 0.3 / 255 * 0x10000\n (maskData[i - 2] * 152) + // * 0.59 ....\n (maskData[i - 1] * 28); // * 0.11 ....\n layerData[i] = transferMap ?\n (layerData[i] * transferMap[y >> 8]) >> 8 :\n (layerData[i] * y) >> 16;\n }\n }\n\n function genericComposeSMask(maskCtx, layerCtx, width, height,\n subtype, backdrop, transferMap) {\n var hasBackdrop = !!backdrop;\n var r0 = hasBackdrop ? backdrop[0] : 0;\n var g0 = hasBackdrop ? backdrop[1] : 0;\n var b0 = hasBackdrop ? backdrop[2] : 0;\n\n var composeFn;\n if (subtype === 'Luminosity') {\n composeFn = composeSMaskLuminosity;\n } else {\n composeFn = composeSMaskAlpha;\n }\n\n // processing image in chunks to save memory\n var PIXELS_TO_PROCESS = 1048576;\n var chunkSize = Math.min(height, Math.ceil(PIXELS_TO_PROCESS / width));\n for (var row = 0; row < height; row += chunkSize) {\n var chunkHeight = Math.min(chunkSize, height - row);\n var maskData = maskCtx.getImageData(0, row, width, chunkHeight);\n var layerData = layerCtx.getImageData(0, row, width, chunkHeight);\n\n if (hasBackdrop) {\n composeSMaskBackdrop(maskData.data, r0, g0, b0);\n }\n composeFn(maskData.data, layerData.data, transferMap);\n\n maskCtx.putImageData(layerData, 0, row);\n }\n }\n\n function composeSMask(ctx, smask, layerCtx) {\n var mask = smask.canvas;\n var maskCtx = smask.context;\n\n ctx.setTransform(smask.scaleX, 0, 0, smask.scaleY,\n smask.offsetX, smask.offsetY);\n\n var backdrop = smask.backdrop || null;\n if (!smask.transferMap && WebGLUtils.isEnabled) {\n var composed = WebGLUtils.composeSMask(layerCtx.canvas, mask,\n { subtype: smask.subtype, backdrop, });\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.drawImage(composed, smask.offsetX, smask.offsetY);\n return;\n }\n genericComposeSMask(maskCtx, layerCtx, mask.width, mask.height,\n smask.subtype, backdrop, smask.transferMap);\n ctx.drawImage(mask, 0, 0);\n }\n\n var LINE_CAP_STYLES = ['butt', 'round', 'square'];\n var LINE_JOIN_STYLES = ['miter', 'round', 'bevel'];\n var NORMAL_CLIP = {};\n var EO_CLIP = {};\n\n CanvasGraphics.prototype = {\n\n beginDrawing({ transform, viewport, transparency,\n background = null, }) {\n // For pdfs that use blend modes we have to clear the canvas else certain\n // blend modes can look wrong since we'd be blending with a white\n // backdrop. The problem with a transparent backdrop though is we then\n // don't get sub pixel anti aliasing on text, creating temporary\n // transparent canvas when we have blend modes.\n var width = this.ctx.canvas.width;\n var height = this.ctx.canvas.height;\n\n this.ctx.save();\n this.ctx.fillStyle = background || 'rgb(255, 255, 255)';\n this.ctx.fillRect(0, 0, width, height);\n this.ctx.restore();\n\n if (transparency) {\n var transparentCanvas = this.cachedCanvases.getCanvas(\n 'transparent', width, height, true);\n this.compositeCtx = this.ctx;\n this.transparentCanvas = transparentCanvas.canvas;\n this.ctx = transparentCanvas.context;\n this.ctx.save();\n // The transform can be applied before rendering, transferring it to\n // the new canvas.\n this.ctx.transform.apply(this.ctx,\n this.compositeCtx.mozCurrentTransform);\n }\n\n this.ctx.save();\n resetCtxToDefault(this.ctx);\n if (transform) {\n this.ctx.transform.apply(this.ctx, transform);\n }\n this.ctx.transform.apply(this.ctx, viewport.transform);\n\n this.baseTransform = this.ctx.mozCurrentTransform.slice();\n\n if (this.imageLayer) {\n this.imageLayer.beginLayout();\n }\n },\n\n executeOperatorList: function CanvasGraphics_executeOperatorList(\n operatorList,\n executionStartIdx, continueCallback,\n stepper) {\n var argsArray = operatorList.argsArray;\n var fnArray = operatorList.fnArray;\n var i = executionStartIdx || 0;\n var argsArrayLen = argsArray.length;\n\n // Sometimes the OperatorList to execute is empty.\n if (argsArrayLen === i) {\n return i;\n }\n\n var chunkOperations = (argsArrayLen - i > EXECUTION_STEPS &&\n typeof continueCallback === 'function');\n var endTime = chunkOperations ? Date.now() + EXECUTION_TIME : 0;\n var steps = 0;\n\n var commonObjs = this.commonObjs;\n var objs = this.objs;\n var fnId;\n\n while (true) {\n if (stepper !== undefined && i === stepper.nextBreakPoint) {\n stepper.breakIt(i, continueCallback);\n return i;\n }\n\n fnId = fnArray[i];\n\n if (fnId !== OPS.dependency) {\n this[fnId].apply(this, argsArray[i]);\n } else {\n var deps = argsArray[i];\n for (var n = 0, nn = deps.length; n < nn; n++) {\n var depObjId = deps[n];\n var common = depObjId[0] === 'g' && depObjId[1] === '_';\n var objsPool = common ? commonObjs : objs;\n\n // If the promise isn't resolved yet, add the continueCallback\n // to the promise and bail out.\n if (!objsPool.isResolved(depObjId)) {\n objsPool.get(depObjId, continueCallback);\n return i;\n }\n }\n }\n\n i++;\n\n // If the entire operatorList was executed, stop as were done.\n if (i === argsArrayLen) {\n return i;\n }\n\n // If the execution took longer then a certain amount of time and\n // `continueCallback` is specified, interrupt the execution.\n if (chunkOperations && ++steps > EXECUTION_STEPS) {\n if (Date.now() > endTime) {\n continueCallback();\n return i;\n }\n steps = 0;\n }\n\n // If the operatorList isn't executed completely yet OR the execution\n // time was short enough, do another execution round.\n }\n },\n\n endDrawing: function CanvasGraphics_endDrawing() {\n // Finishing all opened operations such as SMask group painting.\n if (this.current.activeSMask !== null) {\n this.endSMaskGroup();\n }\n\n this.ctx.restore();\n\n if (this.transparentCanvas) {\n this.ctx = this.compositeCtx;\n this.ctx.save();\n this.ctx.setTransform(1, 0, 0, 1, 0, 0); // Avoid apply transform twice\n this.ctx.drawImage(this.transparentCanvas, 0, 0);\n this.ctx.restore();\n this.transparentCanvas = null;\n }\n\n this.cachedCanvases.clear();\n WebGLUtils.clear();\n\n if (this.imageLayer) {\n this.imageLayer.endLayout();\n }\n },\n\n // Graphics state\n setLineWidth: function CanvasGraphics_setLineWidth(width) {\n this.current.lineWidth = width;\n this.ctx.lineWidth = width;\n },\n setLineCap: function CanvasGraphics_setLineCap(style) {\n this.ctx.lineCap = LINE_CAP_STYLES[style];\n },\n setLineJoin: function CanvasGraphics_setLineJoin(style) {\n this.ctx.lineJoin = LINE_JOIN_STYLES[style];\n },\n setMiterLimit: function CanvasGraphics_setMiterLimit(limit) {\n this.ctx.miterLimit = limit;\n },\n setDash: function CanvasGraphics_setDash(dashArray, dashPhase) {\n var ctx = this.ctx;\n if (ctx.setLineDash !== undefined) {\n ctx.setLineDash(dashArray);\n ctx.lineDashOffset = dashPhase;\n }\n },\n setRenderingIntent: function CanvasGraphics_setRenderingIntent(intent) {\n // Maybe if we one day fully support color spaces this will be important\n // for now we can ignore.\n // TODO set rendering intent?\n },\n setFlatness: function CanvasGraphics_setFlatness(flatness) {\n // There's no way to control this with canvas, but we can safely ignore.\n // TODO set flatness?\n },\n setGState: function CanvasGraphics_setGState(states) {\n for (var i = 0, ii = states.length; i < ii; i++) {\n var state = states[i];\n var key = state[0];\n var value = state[1];\n\n switch (key) {\n case 'LW':\n this.setLineWidth(value);\n break;\n case 'LC':\n this.setLineCap(value);\n break;\n case 'LJ':\n this.setLineJoin(value);\n break;\n case 'ML':\n this.setMiterLimit(value);\n break;\n case 'D':\n this.setDash(value[0], value[1]);\n break;\n case 'RI':\n this.setRenderingIntent(value);\n break;\n case 'FL':\n this.setFlatness(value);\n break;\n case 'Font':\n this.setFont(value[0], value[1]);\n break;\n case 'CA':\n this.current.strokeAlpha = state[1];\n break;\n case 'ca':\n this.current.fillAlpha = state[1];\n this.ctx.globalAlpha = state[1];\n break;\n case 'BM':\n this.ctx.globalCompositeOperation = value;\n break;\n case 'SMask':\n if (this.current.activeSMask) {\n // If SMask is currrenly used, it needs to be suspended or\n // finished. Suspend only makes sense when at least one save()\n // was performed and state needs to be reverted on restore().\n if (this.stateStack.length > 0 &&\n (this.stateStack[this.stateStack.length - 1].activeSMask ===\n this.current.activeSMask)) {\n this.suspendSMaskGroup();\n } else {\n this.endSMaskGroup();\n }\n }\n this.current.activeSMask = value ? this.tempSMask : null;\n if (this.current.activeSMask) {\n this.beginSMaskGroup();\n }\n this.tempSMask = null;\n break;\n }\n }\n },\n beginSMaskGroup: function CanvasGraphics_beginSMaskGroup() {\n\n var activeSMask = this.current.activeSMask;\n var drawnWidth = activeSMask.canvas.width;\n var drawnHeight = activeSMask.canvas.height;\n var cacheId = 'smaskGroupAt' + this.groupLevel;\n var scratchCanvas = this.cachedCanvases.getCanvas(\n cacheId, drawnWidth, drawnHeight, true);\n\n var currentCtx = this.ctx;\n var currentTransform = currentCtx.mozCurrentTransform;\n this.ctx.save();\n\n var groupCtx = scratchCanvas.context;\n groupCtx.scale(1 / activeSMask.scaleX, 1 / activeSMask.scaleY);\n groupCtx.translate(-activeSMask.offsetX, -activeSMask.offsetY);\n groupCtx.transform.apply(groupCtx, currentTransform);\n\n activeSMask.startTransformInverse = groupCtx.mozCurrentTransformInverse;\n\n copyCtxState(currentCtx, groupCtx);\n this.ctx = groupCtx;\n this.setGState([\n ['BM', 'source-over'],\n ['ca', 1],\n ['CA', 1]\n ]);\n this.groupStack.push(currentCtx);\n this.groupLevel++;\n },\n suspendSMaskGroup: function CanvasGraphics_endSMaskGroup() {\n // Similar to endSMaskGroup, the intermediate canvas has to be composed\n // and future ctx state restored.\n var groupCtx = this.ctx;\n this.groupLevel--;\n this.ctx = this.groupStack.pop();\n\n composeSMask(this.ctx, this.current.activeSMask, groupCtx);\n this.ctx.restore();\n this.ctx.save(); // save is needed since SMask will be resumed.\n copyCtxState(groupCtx, this.ctx);\n\n // Saving state for resuming.\n this.current.resumeSMaskCtx = groupCtx;\n // Transform was changed in the SMask canvas, reflecting this change on\n // this.ctx.\n var deltaTransform = Util.transform(\n this.current.activeSMask.startTransformInverse,\n groupCtx.mozCurrentTransform);\n this.ctx.transform.apply(this.ctx, deltaTransform);\n\n // SMask was composed, the results at the groupCtx can be cleared.\n groupCtx.save();\n groupCtx.setTransform(1, 0, 0, 1, 0, 0);\n groupCtx.clearRect(0, 0, groupCtx.canvas.width, groupCtx.canvas.height);\n groupCtx.restore();\n },\n resumeSMaskGroup: function CanvasGraphics_endSMaskGroup() {\n // Resuming state saved by suspendSMaskGroup. We don't need to restore\n // any groupCtx state since restore() command (the only caller) will do\n // that for us. See also beginSMaskGroup.\n var groupCtx = this.current.resumeSMaskCtx;\n var currentCtx = this.ctx;\n this.ctx = groupCtx;\n this.groupStack.push(currentCtx);\n this.groupLevel++;\n },\n endSMaskGroup: function CanvasGraphics_endSMaskGroup() {\n var groupCtx = this.ctx;\n this.groupLevel--;\n this.ctx = this.groupStack.pop();\n\n composeSMask(this.ctx, this.current.activeSMask, groupCtx);\n this.ctx.restore();\n copyCtxState(groupCtx, this.ctx);\n // Transform was changed in the SMask canvas, reflecting this change on\n // this.ctx.\n var deltaTransform = Util.transform(\n this.current.activeSMask.startTransformInverse,\n groupCtx.mozCurrentTransform);\n this.ctx.transform.apply(this.ctx, deltaTransform);\n },\n save: function CanvasGraphics_save() {\n this.ctx.save();\n var old = this.current;\n this.stateStack.push(old);\n this.current = old.clone();\n this.current.resumeSMaskCtx = null;\n },\n restore: function CanvasGraphics_restore() {\n // SMask was suspended, we just need to resume it.\n if (this.current.resumeSMaskCtx) {\n this.resumeSMaskGroup();\n }\n // SMask has to be finished once there is no states that are using the\n // same SMask.\n if (this.current.activeSMask !== null && (this.stateStack.length === 0 ||\n this.stateStack[this.stateStack.length - 1].activeSMask !==\n this.current.activeSMask)) {\n this.endSMaskGroup();\n }\n\n if (this.stateStack.length !== 0) {\n this.current = this.stateStack.pop();\n this.ctx.restore();\n\n // Ensure that the clipping path is reset (fixes issue6413.pdf).\n this.pendingClip = null;\n\n this.cachedGetSinglePixelWidth = null;\n }\n },\n transform: function CanvasGraphics_transform(a, b, c, d, e, f) {\n this.ctx.transform(a, b, c, d, e, f);\n\n this.cachedGetSinglePixelWidth = null;\n },\n\n // Path\n constructPath: function CanvasGraphics_constructPath(ops, args) {\n var ctx = this.ctx;\n var current = this.current;\n var x = current.x, y = current.y;\n for (var i = 0, j = 0, ii = ops.length; i < ii; i++) {\n switch (ops[i] | 0) {\n case OPS.rectangle:\n x = args[j++];\n y = args[j++];\n var width = args[j++];\n var height = args[j++];\n if (width === 0) {\n width = this.getSinglePixelWidth();\n }\n if (height === 0) {\n height = this.getSinglePixelWidth();\n }\n var xw = x + width;\n var yh = y + height;\n this.ctx.moveTo(x, y);\n this.ctx.lineTo(xw, y);\n this.ctx.lineTo(xw, yh);\n this.ctx.lineTo(x, yh);\n this.ctx.lineTo(x, y);\n this.ctx.closePath();\n break;\n case OPS.moveTo:\n x = args[j++];\n y = args[j++];\n ctx.moveTo(x, y);\n break;\n case OPS.lineTo:\n x = args[j++];\n y = args[j++];\n ctx.lineTo(x, y);\n break;\n case OPS.curveTo:\n x = args[j + 4];\n y = args[j + 5];\n ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3],\n x, y);\n j += 6;\n break;\n case OPS.curveTo2:\n ctx.bezierCurveTo(x, y, args[j], args[j + 1],\n args[j + 2], args[j + 3]);\n x = args[j + 2];\n y = args[j + 3];\n j += 4;\n break;\n case OPS.curveTo3:\n x = args[j + 2];\n y = args[j + 3];\n ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y);\n j += 4;\n break;\n case OPS.closePath:\n ctx.closePath();\n break;\n }\n }\n current.setCurrentPoint(x, y);\n },\n closePath: function CanvasGraphics_closePath() {\n this.ctx.closePath();\n },\n stroke: function CanvasGraphics_stroke(consumePath) {\n consumePath = typeof consumePath !== 'undefined' ? consumePath : true;\n var ctx = this.ctx;\n var strokeColor = this.current.strokeColor;\n // Prevent drawing too thin lines by enforcing a minimum line width.\n ctx.lineWidth = Math.max(this.getSinglePixelWidth() * MIN_WIDTH_FACTOR,\n this.current.lineWidth);\n // For stroke we want to temporarily change the global alpha to the\n // stroking alpha.\n ctx.globalAlpha = this.current.strokeAlpha;\n if (strokeColor && strokeColor.hasOwnProperty('type') &&\n strokeColor.type === 'Pattern') {\n // for patterns, we transform to pattern space, calculate\n // the pattern, call stroke, and restore to user space\n ctx.save();\n ctx.strokeStyle = strokeColor.getPattern(ctx, this);\n ctx.stroke();\n ctx.restore();\n } else {\n ctx.stroke();\n }\n if (consumePath) {\n this.consumePath();\n }\n // Restore the global alpha to the fill alpha\n ctx.globalAlpha = this.current.fillAlpha;\n },\n closeStroke: function CanvasGraphics_closeStroke() {\n this.closePath();\n this.stroke();\n },\n fill: function CanvasGraphics_fill(consumePath) {\n consumePath = typeof consumePath !== 'undefined' ? consumePath : true;\n var ctx = this.ctx;\n var fillColor = this.current.fillColor;\n var isPatternFill = this.current.patternFill;\n var needRestore = false;\n\n if (isPatternFill) {\n ctx.save();\n if (this.baseTransform) {\n ctx.setTransform.apply(ctx, this.baseTransform);\n }\n ctx.fillStyle = fillColor.getPattern(ctx, this);\n needRestore = true;\n }\n\n if (this.pendingEOFill) {\n ctx.fill('evenodd');\n this.pendingEOFill = false;\n } else {\n ctx.fill();\n }\n\n if (needRestore) {\n ctx.restore();\n }\n if (consumePath) {\n this.consumePath();\n }\n },\n eoFill: function CanvasGraphics_eoFill() {\n this.pendingEOFill = true;\n this.fill();\n },\n fillStroke: function CanvasGraphics_fillStroke() {\n this.fill(false);\n this.stroke(false);\n\n this.consumePath();\n },\n eoFillStroke: function CanvasGraphics_eoFillStroke() {\n this.pendingEOFill = true;\n this.fillStroke();\n },\n closeFillStroke: function CanvasGraphics_closeFillStroke() {\n this.closePath();\n this.fillStroke();\n },\n closeEOFillStroke: function CanvasGraphics_closeEOFillStroke() {\n this.pendingEOFill = true;\n this.closePath();\n this.fillStroke();\n },\n endPath: function CanvasGraphics_endPath() {\n this.consumePath();\n },\n\n // Clipping\n clip: function CanvasGraphics_clip() {\n this.pendingClip = NORMAL_CLIP;\n },\n eoClip: function CanvasGraphics_eoClip() {\n this.pendingClip = EO_CLIP;\n },\n\n // Text\n beginText: function CanvasGraphics_beginText() {\n this.current.textMatrix = IDENTITY_MATRIX;\n this.current.textMatrixScale = 1;\n this.current.x = this.current.lineX = 0;\n this.current.y = this.current.lineY = 0;\n },\n endText: function CanvasGraphics_endText() {\n var paths = this.pendingTextPaths;\n var ctx = this.ctx;\n if (paths === undefined) {\n ctx.beginPath();\n return;\n }\n\n ctx.save();\n ctx.beginPath();\n for (var i = 0; i < paths.length; i++) {\n var path = paths[i];\n ctx.setTransform.apply(ctx, path.transform);\n ctx.translate(path.x, path.y);\n path.addToPath(ctx, path.fontSize);\n }\n ctx.restore();\n ctx.clip();\n ctx.beginPath();\n delete this.pendingTextPaths;\n },\n setCharSpacing: function CanvasGraphics_setCharSpacing(spacing) {\n this.current.charSpacing = spacing;\n },\n setWordSpacing: function CanvasGraphics_setWordSpacing(spacing) {\n this.current.wordSpacing = spacing;\n },\n setHScale: function CanvasGraphics_setHScale(scale) {\n this.current.textHScale = scale / 100;\n },\n setLeading: function CanvasGraphics_setLeading(leading) {\n this.current.leading = -leading;\n },\n setFont: function CanvasGraphics_setFont(fontRefName, size) {\n var fontObj = this.commonObjs.get(fontRefName);\n var current = this.current;\n\n if (!fontObj) {\n throw new Error(`Can't find font for ${fontRefName}`);\n }\n\n current.fontMatrix = (fontObj.fontMatrix ?\n fontObj.fontMatrix : FONT_IDENTITY_MATRIX);\n\n // A valid matrix needs all main diagonal elements to be non-zero\n // This also ensures we bypass FF bugzilla bug #719844.\n if (current.fontMatrix[0] === 0 ||\n current.fontMatrix[3] === 0) {\n warn('Invalid font matrix for font ' + fontRefName);\n }\n\n // The spec for Tf (setFont) says that 'size' specifies the font 'scale',\n // and in some docs this can be negative (inverted x-y axes).\n if (size < 0) {\n size = -size;\n current.fontDirection = -1;\n } else {\n current.fontDirection = 1;\n }\n\n this.current.font = fontObj;\n this.current.fontSize = size;\n\n if (fontObj.isType3Font) {\n return; // we don't need ctx.font for Type3 fonts\n }\n\n var name = fontObj.loadedName || 'sans-serif';\n var bold = fontObj.black ? '900' : (fontObj.bold ? 'bold' : 'normal');\n var italic = fontObj.italic ? 'italic' : 'normal';\n var typeface = '\"' + name + '\", ' + fontObj.fallbackName;\n\n // Some font backends cannot handle fonts below certain size.\n // Keeping the font at minimal size and using the fontSizeScale to change\n // the current transformation matrix before the fillText/strokeText.\n // See https://bugzilla.mozilla.org/show_bug.cgi?id=726227\n var browserFontSize = size < MIN_FONT_SIZE ? MIN_FONT_SIZE :\n size > MAX_FONT_SIZE ? MAX_FONT_SIZE : size;\n this.current.fontSizeScale = size / browserFontSize;\n\n var rule = italic + ' ' + bold + ' ' + browserFontSize + 'px ' + typeface;\n this.ctx.font = rule;\n },\n setTextRenderingMode: function CanvasGraphics_setTextRenderingMode(mode) {\n this.current.textRenderingMode = mode;\n },\n setTextRise: function CanvasGraphics_setTextRise(rise) {\n this.current.textRise = rise;\n },\n moveText: function CanvasGraphics_moveText(x, y) {\n this.current.x = this.current.lineX += x;\n this.current.y = this.current.lineY += y;\n },\n setLeadingMoveText: function CanvasGraphics_setLeadingMoveText(x, y) {\n this.setLeading(-y);\n this.moveText(x, y);\n },\n setTextMatrix: function CanvasGraphics_setTextMatrix(a, b, c, d, e, f) {\n this.current.textMatrix = [a, b, c, d, e, f];\n this.current.textMatrixScale = Math.sqrt(a * a + b * b);\n\n this.current.x = this.current.lineX = 0;\n this.current.y = this.current.lineY = 0;\n },\n nextLine: function CanvasGraphics_nextLine() {\n this.moveText(0, this.current.leading);\n },\n\n paintChar: function CanvasGraphics_paintChar(character, x, y) {\n var ctx = this.ctx;\n var current = this.current;\n var font = current.font;\n var textRenderingMode = current.textRenderingMode;\n var fontSize = current.fontSize / current.fontSizeScale;\n var fillStrokeMode = textRenderingMode &\n TextRenderingMode.FILL_STROKE_MASK;\n var isAddToPathSet = !!(textRenderingMode &\n TextRenderingMode.ADD_TO_PATH_FLAG);\n\n var addToPath;\n if (font.disableFontFace || isAddToPathSet) {\n addToPath = font.getPathGenerator(this.commonObjs, character);\n }\n\n if (font.disableFontFace) {\n ctx.save();\n ctx.translate(x, y);\n ctx.beginPath();\n addToPath(ctx, fontSize);\n if (fillStrokeMode === TextRenderingMode.FILL ||\n fillStrokeMode === TextRenderingMode.FILL_STROKE) {\n ctx.fill();\n }\n if (fillStrokeMode === TextRenderingMode.STROKE ||\n fillStrokeMode === TextRenderingMode.FILL_STROKE) {\n ctx.stroke();\n }\n ctx.restore();\n } else {\n if (fillStrokeMode === TextRenderingMode.FILL ||\n fillStrokeMode === TextRenderingMode.FILL_STROKE) {\n ctx.fillText(character, x, y);\n }\n if (fillStrokeMode === TextRenderingMode.STROKE ||\n fillStrokeMode === TextRenderingMode.FILL_STROKE) {\n ctx.strokeText(character, x, y);\n }\n }\n\n if (isAddToPathSet) {\n var paths = this.pendingTextPaths || (this.pendingTextPaths = []);\n paths.push({\n transform: ctx.mozCurrentTransform,\n x,\n y,\n fontSize,\n addToPath,\n });\n }\n },\n\n get isFontSubpixelAAEnabled() {\n // Checks if anti-aliasing is enabled when scaled text is painted.\n // On Windows GDI scaled fonts looks bad.\n var ctx = this.canvasFactory.create(10, 10).context;\n ctx.scale(1.5, 1);\n ctx.fillText('I', 0, 10);\n var data = ctx.getImageData(0, 0, 10, 10).data;\n var enabled = false;\n for (var i = 3; i < data.length; i += 4) {\n if (data[i] > 0 && data[i] < 255) {\n enabled = true;\n break;\n }\n }\n return shadow(this, 'isFontSubpixelAAEnabled', enabled);\n },\n\n showText: function CanvasGraphics_showText(glyphs) {\n var current = this.current;\n var font = current.font;\n if (font.isType3Font) {\n return this.showType3Text(glyphs);\n }\n\n var fontSize = current.fontSize;\n if (fontSize === 0) {\n return;\n }\n\n var ctx = this.ctx;\n var fontSizeScale = current.fontSizeScale;\n var charSpacing = current.charSpacing;\n var wordSpacing = current.wordSpacing;\n var fontDirection = current.fontDirection;\n var textHScale = current.textHScale * fontDirection;\n var glyphsLength = glyphs.length;\n var vertical = font.vertical;\n var spacingDir = vertical ? 1 : -1;\n var defaultVMetrics = font.defaultVMetrics;\n var widthAdvanceScale = fontSize * current.fontMatrix[0];\n\n var simpleFillText =\n current.textRenderingMode === TextRenderingMode.FILL &&\n !font.disableFontFace;\n\n ctx.save();\n ctx.transform.apply(ctx, current.textMatrix);\n ctx.translate(current.x, current.y + current.textRise);\n\n if (current.patternFill) {\n // TODO: Some shading patterns are not applied correctly to text,\n // e.g. issues 3988 and 5432, and ShowText-ShadingPattern.pdf.\n ctx.fillStyle = current.fillColor.getPattern(ctx, this);\n }\n\n if (fontDirection > 0) {\n ctx.scale(textHScale, -1);\n } else {\n ctx.scale(textHScale, 1);\n }\n\n var lineWidth = current.lineWidth;\n var scale = current.textMatrixScale;\n if (scale === 0 || lineWidth === 0) {\n var fillStrokeMode = current.textRenderingMode &\n TextRenderingMode.FILL_STROKE_MASK;\n if (fillStrokeMode === TextRenderingMode.STROKE ||\n fillStrokeMode === TextRenderingMode.FILL_STROKE) {\n this.cachedGetSinglePixelWidth = null;\n lineWidth = this.getSinglePixelWidth() * MIN_WIDTH_FACTOR;\n }\n } else {\n lineWidth /= scale;\n }\n\n if (fontSizeScale !== 1.0) {\n ctx.scale(fontSizeScale, fontSizeScale);\n lineWidth /= fontSizeScale;\n }\n\n ctx.lineWidth = lineWidth;\n\n var x = 0, i;\n for (i = 0; i < glyphsLength; ++i) {\n var glyph = glyphs[i];\n if (isNum(glyph)) {\n x += spacingDir * glyph * fontSize / 1000;\n continue;\n }\n\n var restoreNeeded = false;\n var spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;\n var character = glyph.fontChar;\n var accent = glyph.accent;\n var scaledX, scaledY, scaledAccentX, scaledAccentY;\n var width = glyph.width;\n if (vertical) {\n var vmetric, vx, vy;\n vmetric = glyph.vmetric || defaultVMetrics;\n vx = glyph.vmetric ? vmetric[1] : width * 0.5;\n vx = -vx * widthAdvanceScale;\n vy = vmetric[2] * widthAdvanceScale;\n\n width = vmetric ? -vmetric[0] : width;\n scaledX = vx / fontSizeScale;\n scaledY = (x + vy) / fontSizeScale;\n } else {\n scaledX = x / fontSizeScale;\n scaledY = 0;\n }\n\n if (font.remeasure && width > 0) {\n // Some standard fonts may not have the exact width: rescale per\n // character if measured width is greater than expected glyph width\n // and subpixel-aa is enabled, otherwise just center the glyph.\n var measuredWidth = ctx.measureText(character).width * 1000 /\n fontSize * fontSizeScale;\n if (width < measuredWidth && this.isFontSubpixelAAEnabled) {\n var characterScaleX = width / measuredWidth;\n restoreNeeded = true;\n ctx.save();\n ctx.scale(characterScaleX, 1);\n scaledX /= characterScaleX;\n } else if (width !== measuredWidth) {\n scaledX += (width - measuredWidth) / 2000 *\n fontSize / fontSizeScale;\n }\n }\n\n // Only attempt to draw the glyph if it is actually in the embedded font\n // file or if there isn't a font file so the fallback font is shown.\n if (glyph.isInFont || font.missingFile) {\n if (simpleFillText && !accent) {\n // common case\n ctx.fillText(character, scaledX, scaledY);\n } else {\n this.paintChar(character, scaledX, scaledY);\n if (accent) {\n scaledAccentX = scaledX + accent.offset.x / fontSizeScale;\n scaledAccentY = scaledY - accent.offset.y / fontSizeScale;\n this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY);\n }\n }\n }\n\n var charWidth = width * widthAdvanceScale + spacing * fontDirection;\n x += charWidth;\n\n if (restoreNeeded) {\n ctx.restore();\n }\n }\n if (vertical) {\n current.y -= x * textHScale;\n } else {\n current.x += x * textHScale;\n }\n ctx.restore();\n },\n\n showType3Text: function CanvasGraphics_showType3Text(glyphs) {\n // Type3 fonts - each glyph is a \"mini-PDF\"\n var ctx = this.ctx;\n var current = this.current;\n var font = current.font;\n var fontSize = current.fontSize;\n var fontDirection = current.fontDirection;\n var spacingDir = font.vertical ? 1 : -1;\n var charSpacing = current.charSpacing;\n var wordSpacing = current.wordSpacing;\n var textHScale = current.textHScale * fontDirection;\n var fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;\n var glyphsLength = glyphs.length;\n var isTextInvisible =\n current.textRenderingMode === TextRenderingMode.INVISIBLE;\n var i, glyph, width, spacingLength;\n\n if (isTextInvisible || fontSize === 0) {\n return;\n }\n this.cachedGetSinglePixelWidth = null;\n\n ctx.save();\n ctx.transform.apply(ctx, current.textMatrix);\n ctx.translate(current.x, current.y);\n\n ctx.scale(textHScale, fontDirection);\n\n for (i = 0; i < glyphsLength; ++i) {\n glyph = glyphs[i];\n if (isNum(glyph)) {\n spacingLength = spacingDir * glyph * fontSize / 1000;\n this.ctx.translate(spacingLength, 0);\n current.x += spacingLength * textHScale;\n continue;\n }\n\n var spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;\n var operatorList = font.charProcOperatorList[glyph.operatorListId];\n if (!operatorList) {\n warn(`Type3 character \"${glyph.operatorListId}\" is not available.`);\n continue;\n }\n this.processingType3 = glyph;\n this.save();\n ctx.scale(fontSize, fontSize);\n ctx.transform.apply(ctx, fontMatrix);\n this.executeOperatorList(operatorList);\n this.restore();\n\n var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);\n width = transformed[0] * fontSize + spacing;\n\n ctx.translate(width, 0);\n current.x += width * textHScale;\n }\n ctx.restore();\n this.processingType3 = null;\n },\n\n // Type3 fonts\n setCharWidth: function CanvasGraphics_setCharWidth(xWidth, yWidth) {\n // We can safely ignore this since the width should be the same\n // as the width in the Widths array.\n },\n setCharWidthAndBounds: function CanvasGraphics_setCharWidthAndBounds(xWidth,\n yWidth,\n llx,\n lly,\n urx,\n ury) {\n // TODO According to the spec we're also suppose to ignore any operators\n // that set color or include images while processing this type3 font.\n this.ctx.rect(llx, lly, urx - llx, ury - lly);\n this.clip();\n this.endPath();\n },\n\n // Color\n getColorN_Pattern: function CanvasGraphics_getColorN_Pattern(IR) {\n var pattern;\n if (IR[0] === 'TilingPattern') {\n var color = IR[1];\n var baseTransform = this.baseTransform ||\n this.ctx.mozCurrentTransform.slice();\n var canvasGraphicsFactory = {\n createCanvasGraphics: (ctx) => {\n return new CanvasGraphics(ctx, this.commonObjs, this.objs,\n this.canvasFactory);\n },\n };\n pattern = new TilingPattern(IR, color, this.ctx, canvasGraphicsFactory,\n baseTransform);\n } else {\n pattern = getShadingPatternFromIR(IR);\n }\n return pattern;\n },\n setStrokeColorN: function CanvasGraphics_setStrokeColorN() {\n this.current.strokeColor = this.getColorN_Pattern(arguments);\n },\n setFillColorN: function CanvasGraphics_setFillColorN() {\n this.current.fillColor = this.getColorN_Pattern(arguments);\n this.current.patternFill = true;\n },\n setStrokeRGBColor: function CanvasGraphics_setStrokeRGBColor(r, g, b) {\n var color = Util.makeCssRgb(r, g, b);\n this.ctx.strokeStyle = color;\n this.current.strokeColor = color;\n },\n setFillRGBColor: function CanvasGraphics_setFillRGBColor(r, g, b) {\n var color = Util.makeCssRgb(r, g, b);\n this.ctx.fillStyle = color;\n this.current.fillColor = color;\n this.current.patternFill = false;\n },\n\n shadingFill: function CanvasGraphics_shadingFill(patternIR) {\n var ctx = this.ctx;\n\n this.save();\n var pattern = getShadingPatternFromIR(patternIR);\n ctx.fillStyle = pattern.getPattern(ctx, this, true);\n\n var inv = ctx.mozCurrentTransformInverse;\n if (inv) {\n var canvas = ctx.canvas;\n var width = canvas.width;\n var height = canvas.height;\n\n var bl = Util.applyTransform([0, 0], inv);\n var br = Util.applyTransform([0, height], inv);\n var ul = Util.applyTransform([width, 0], inv);\n var ur = Util.applyTransform([width, height], inv);\n\n var x0 = Math.min(bl[0], br[0], ul[0], ur[0]);\n var y0 = Math.min(bl[1], br[1], ul[1], ur[1]);\n var x1 = Math.max(bl[0], br[0], ul[0], ur[0]);\n var y1 = Math.max(bl[1], br[1], ul[1], ur[1]);\n\n this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0);\n } else {\n // HACK to draw the gradient onto an infinite rectangle.\n // PDF gradients are drawn across the entire image while\n // Canvas only allows gradients to be drawn in a rectangle\n // The following bug should allow us to remove this.\n // https://bugzilla.mozilla.org/show_bug.cgi?id=664884\n\n this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);\n }\n\n this.restore();\n },\n\n // Images\n beginInlineImage: function CanvasGraphics_beginInlineImage() {\n throw new Error('Should not call beginInlineImage');\n },\n beginImageData: function CanvasGraphics_beginImageData() {\n throw new Error('Should not call beginImageData');\n },\n\n paintFormXObjectBegin: function CanvasGraphics_paintFormXObjectBegin(matrix,\n bbox) {\n this.save();\n this.baseTransformStack.push(this.baseTransform);\n\n if (isArray(matrix) && matrix.length === 6) {\n this.transform.apply(this, matrix);\n }\n\n this.baseTransform = this.ctx.mozCurrentTransform;\n\n if (isArray(bbox) && bbox.length === 4) {\n var width = bbox[2] - bbox[0];\n var height = bbox[3] - bbox[1];\n this.ctx.rect(bbox[0], bbox[1], width, height);\n this.clip();\n this.endPath();\n }\n },\n\n paintFormXObjectEnd: function CanvasGraphics_paintFormXObjectEnd() {\n this.restore();\n this.baseTransform = this.baseTransformStack.pop();\n },\n\n beginGroup: function CanvasGraphics_beginGroup(group) {\n this.save();\n var currentCtx = this.ctx;\n // TODO non-isolated groups - according to Rik at adobe non-isolated\n // group results aren't usually that different and they even have tools\n // that ignore this setting. Notes from Rik on implementing:\n // - When you encounter an transparency group, create a new canvas with\n // the dimensions of the bbox\n // - copy the content from the previous canvas to the new canvas\n // - draw as usual\n // - remove the backdrop alpha:\n // alphaNew = 1 - (1 - alpha)/(1 - alphaBackdrop) with 'alpha' the alpha\n // value of your transparency group and 'alphaBackdrop' the alpha of the\n // backdrop\n // - remove background color:\n // colorNew = color - alphaNew *colorBackdrop /(1 - alphaNew)\n if (!group.isolated) {\n info('TODO: Support non-isolated groups.');\n }\n\n // TODO knockout - supposedly possible with the clever use of compositing\n // modes.\n if (group.knockout) {\n warn('Knockout groups not supported.');\n }\n\n var currentTransform = currentCtx.mozCurrentTransform;\n if (group.matrix) {\n currentCtx.transform.apply(currentCtx, group.matrix);\n }\n if (!group.bbox) {\n throw new Error('Bounding box is required.');\n }\n\n // Based on the current transform figure out how big the bounding box\n // will actually be.\n var bounds = Util.getAxialAlignedBoundingBox(\n group.bbox,\n currentCtx.mozCurrentTransform);\n // Clip the bounding box to the current canvas.\n var canvasBounds = [0,\n 0,\n currentCtx.canvas.width,\n currentCtx.canvas.height];\n bounds = Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0];\n // Use ceil in case we're between sizes so we don't create canvas that is\n // too small and make the canvas at least 1x1 pixels.\n var offsetX = Math.floor(bounds[0]);\n var offsetY = Math.floor(bounds[1]);\n var drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1);\n var drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1);\n var scaleX = 1, scaleY = 1;\n if (drawnWidth > MAX_GROUP_SIZE) {\n scaleX = drawnWidth / MAX_GROUP_SIZE;\n drawnWidth = MAX_GROUP_SIZE;\n }\n if (drawnHeight > MAX_GROUP_SIZE) {\n scaleY = drawnHeight / MAX_GROUP_SIZE;\n drawnHeight = MAX_GROUP_SIZE;\n }\n\n var cacheId = 'groupAt' + this.groupLevel;\n if (group.smask) {\n // Using two cache entries is case if masks are used one after another.\n cacheId += '_smask_' + ((this.smaskCounter++) % 2);\n }\n var scratchCanvas = this.cachedCanvases.getCanvas(\n cacheId, drawnWidth, drawnHeight, true);\n var groupCtx = scratchCanvas.context;\n\n // Since we created a new canvas that is just the size of the bounding box\n // we have to translate the group ctx.\n groupCtx.scale(1 / scaleX, 1 / scaleY);\n groupCtx.translate(-offsetX, -offsetY);\n groupCtx.transform.apply(groupCtx, currentTransform);\n\n if (group.smask) {\n // Saving state and cached mask to be used in setGState.\n this.smaskStack.push({\n canvas: scratchCanvas.canvas,\n context: groupCtx,\n offsetX,\n offsetY,\n scaleX,\n scaleY,\n subtype: group.smask.subtype,\n backdrop: group.smask.backdrop,\n transferMap: group.smask.transferMap || null,\n startTransformInverse: null, // used during suspend operation\n });\n } else {\n // Setup the current ctx so when the group is popped we draw it at the\n // right location.\n currentCtx.setTransform(1, 0, 0, 1, 0, 0);\n currentCtx.translate(offsetX, offsetY);\n currentCtx.scale(scaleX, scaleY);\n }\n // The transparency group inherits all off the current graphics state\n // except the blend mode, soft mask, and alpha constants.\n copyCtxState(currentCtx, groupCtx);\n this.ctx = groupCtx;\n this.setGState([\n ['BM', 'source-over'],\n ['ca', 1],\n ['CA', 1]\n ]);\n this.groupStack.push(currentCtx);\n this.groupLevel++;\n\n // Reseting mask state, masks will be applied on restore of the group.\n this.current.activeSMask = null;\n },\n\n endGroup: function CanvasGraphics_endGroup(group) {\n this.groupLevel--;\n var groupCtx = this.ctx;\n this.ctx = this.groupStack.pop();\n // Turn off image smoothing to avoid sub pixel interpolation which can\n // look kind of blurry for some pdfs.\n if (this.ctx.imageSmoothingEnabled !== undefined) {\n this.ctx.imageSmoothingEnabled = false;\n } else {\n this.ctx.mozImageSmoothingEnabled = false;\n }\n if (group.smask) {\n this.tempSMask = this.smaskStack.pop();\n } else {\n this.ctx.drawImage(groupCtx.canvas, 0, 0);\n }\n this.restore();\n },\n\n beginAnnotations: function CanvasGraphics_beginAnnotations() {\n this.save();\n if (this.baseTransform) {\n this.ctx.setTransform.apply(this.ctx, this.baseTransform);\n }\n },\n\n endAnnotations: function CanvasGraphics_endAnnotations() {\n this.restore();\n },\n\n beginAnnotation: function CanvasGraphics_beginAnnotation(rect, transform,\n matrix) {\n this.save();\n resetCtxToDefault(this.ctx);\n this.current = new CanvasExtraState();\n\n if (isArray(rect) && rect.length === 4) {\n var width = rect[2] - rect[0];\n var height = rect[3] - rect[1];\n this.ctx.rect(rect[0], rect[1], width, height);\n this.clip();\n this.endPath();\n }\n\n this.transform.apply(this, transform);\n this.transform.apply(this, matrix);\n },\n\n endAnnotation: function CanvasGraphics_endAnnotation() {\n this.restore();\n },\n\n paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) {\n var domImage = this.objs.get(objId);\n if (!domImage) {\n warn('Dependent image isn\\'t ready yet');\n return;\n }\n\n this.save();\n\n var ctx = this.ctx;\n // scale the image to the unit square\n ctx.scale(1 / w, -1 / h);\n\n ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height,\n 0, -h, w, h);\n if (this.imageLayer) {\n var currentTransform = ctx.mozCurrentTransformInverse;\n var position = this.getCanvasPosition(0, 0);\n this.imageLayer.appendImage({\n objId,\n left: position[0],\n top: position[1],\n width: w / currentTransform[0],\n height: h / currentTransform[3],\n });\n }\n this.restore();\n },\n\n paintImageMaskXObject: function CanvasGraphics_paintImageMaskXObject(img) {\n var ctx = this.ctx;\n var width = img.width, height = img.height;\n var fillColor = this.current.fillColor;\n var isPatternFill = this.current.patternFill;\n\n var glyph = this.processingType3;\n\n if (COMPILE_TYPE3_GLYPHS && glyph && glyph.compiled === undefined) {\n if (width <= MAX_SIZE_TO_COMPILE && height <= MAX_SIZE_TO_COMPILE) {\n glyph.compiled =\n compileType3Glyph({ data: img.data, width, height, });\n } else {\n glyph.compiled = null;\n }\n }\n\n if (glyph && glyph.compiled) {\n glyph.compiled(ctx);\n return;\n }\n\n var maskCanvas = this.cachedCanvases.getCanvas('maskCanvas',\n width, height);\n var maskCtx = maskCanvas.context;\n maskCtx.save();\n\n putBinaryImageMask(maskCtx, img);\n\n maskCtx.globalCompositeOperation = 'source-in';\n\n maskCtx.fillStyle = isPatternFill ?\n fillColor.getPattern(maskCtx, this) : fillColor;\n maskCtx.fillRect(0, 0, width, height);\n\n maskCtx.restore();\n\n this.paintInlineImageXObject(maskCanvas.canvas);\n },\n\n paintImageMaskXObjectRepeat:\n function CanvasGraphics_paintImageMaskXObjectRepeat(imgData, scaleX,\n scaleY, positions) {\n var width = imgData.width;\n var height = imgData.height;\n var fillColor = this.current.fillColor;\n var isPatternFill = this.current.patternFill;\n\n var maskCanvas = this.cachedCanvases.getCanvas('maskCanvas',\n width, height);\n var maskCtx = maskCanvas.context;\n maskCtx.save();\n\n putBinaryImageMask(maskCtx, imgData);\n\n maskCtx.globalCompositeOperation = 'source-in';\n\n maskCtx.fillStyle = isPatternFill ?\n fillColor.getPattern(maskCtx, this) : fillColor;\n maskCtx.fillRect(0, 0, width, height);\n\n maskCtx.restore();\n\n var ctx = this.ctx;\n for (var i = 0, ii = positions.length; i < ii; i += 2) {\n ctx.save();\n ctx.transform(scaleX, 0, 0, scaleY, positions[i], positions[i + 1]);\n ctx.scale(1, -1);\n ctx.drawImage(maskCanvas.canvas, 0, 0, width, height,\n 0, -1, 1, 1);\n ctx.restore();\n }\n },\n\n paintImageMaskXObjectGroup:\n function CanvasGraphics_paintImageMaskXObjectGroup(images) {\n var ctx = this.ctx;\n\n var fillColor = this.current.fillColor;\n var isPatternFill = this.current.patternFill;\n for (var i = 0, ii = images.length; i < ii; i++) {\n var image = images[i];\n var width = image.width, height = image.height;\n\n var maskCanvas = this.cachedCanvases.getCanvas('maskCanvas',\n width, height);\n var maskCtx = maskCanvas.context;\n maskCtx.save();\n\n putBinaryImageMask(maskCtx, image);\n\n maskCtx.globalCompositeOperation = 'source-in';\n\n maskCtx.fillStyle = isPatternFill ?\n fillColor.getPattern(maskCtx, this) : fillColor;\n maskCtx.fillRect(0, 0, width, height);\n\n maskCtx.restore();\n\n ctx.save();\n ctx.transform.apply(ctx, image.transform);\n ctx.scale(1, -1);\n ctx.drawImage(maskCanvas.canvas, 0, 0, width, height,\n 0, -1, 1, 1);\n ctx.restore();\n }\n },\n\n paintImageXObject: function CanvasGraphics_paintImageXObject(objId) {\n var imgData = this.objs.get(objId);\n if (!imgData) {\n warn('Dependent image isn\\'t ready yet');\n return;\n }\n\n this.paintInlineImageXObject(imgData);\n },\n\n paintImageXObjectRepeat:\n function CanvasGraphics_paintImageXObjectRepeat(objId, scaleX, scaleY,\n positions) {\n var imgData = this.objs.get(objId);\n if (!imgData) {\n warn('Dependent image isn\\'t ready yet');\n return;\n }\n\n var width = imgData.width;\n var height = imgData.height;\n var map = [];\n for (var i = 0, ii = positions.length; i < ii; i += 2) {\n map.push({ transform: [scaleX, 0, 0, scaleY, positions[i],\n positions[i + 1]], x: 0, y: 0, w: width, h: height, });\n }\n this.paintInlineImageXObjectGroup(imgData, map);\n },\n\n paintInlineImageXObject:\n function CanvasGraphics_paintInlineImageXObject(imgData) {\n var width = imgData.width;\n var height = imgData.height;\n var ctx = this.ctx;\n\n this.save();\n // scale the image to the unit square\n ctx.scale(1 / width, -1 / height);\n\n var currentTransform = ctx.mozCurrentTransformInverse;\n var a = currentTransform[0], b = currentTransform[1];\n var widthScale = Math.max(Math.sqrt(a * a + b * b), 1);\n var c = currentTransform[2], d = currentTransform[3];\n var heightScale = Math.max(Math.sqrt(c * c + d * d), 1);\n\n var imgToPaint, tmpCanvas;\n // instanceof HTMLElement does not work in jsdom node.js module\n if (imgData instanceof HTMLElement || !imgData.data) {\n imgToPaint = imgData;\n } else {\n tmpCanvas = this.cachedCanvases.getCanvas('inlineImage',\n width, height);\n var tmpCtx = tmpCanvas.context;\n putBinaryImageData(tmpCtx, imgData);\n imgToPaint = tmpCanvas.canvas;\n }\n\n var paintWidth = width, paintHeight = height;\n var tmpCanvasId = 'prescale1';\n // Vertial or horizontal scaling shall not be more than 2 to not loose the\n // pixels during drawImage operation, painting on the temporary canvas(es)\n // that are twice smaller in size\n while ((widthScale > 2 && paintWidth > 1) ||\n (heightScale > 2 && paintHeight > 1)) {\n var newWidth = paintWidth, newHeight = paintHeight;\n if (widthScale > 2 && paintWidth > 1) {\n newWidth = Math.ceil(paintWidth / 2);\n widthScale /= paintWidth / newWidth;\n }\n if (heightScale > 2 && paintHeight > 1) {\n newHeight = Math.ceil(paintHeight / 2);\n heightScale /= paintHeight / newHeight;\n }\n tmpCanvas = this.cachedCanvases.getCanvas(tmpCanvasId,\n newWidth, newHeight);\n tmpCtx = tmpCanvas.context;\n tmpCtx.clearRect(0, 0, newWidth, newHeight);\n tmpCtx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight,\n 0, 0, newWidth, newHeight);\n imgToPaint = tmpCanvas.canvas;\n paintWidth = newWidth;\n paintHeight = newHeight;\n tmpCanvasId = tmpCanvasId === 'prescale1' ? 'prescale2' : 'prescale1';\n }\n ctx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight,\n 0, -height, width, height);\n\n if (this.imageLayer) {\n var position = this.getCanvasPosition(0, -height);\n this.imageLayer.appendImage({\n imgData,\n left: position[0],\n top: position[1],\n width: width / currentTransform[0],\n height: height / currentTransform[3],\n });\n }\n this.restore();\n },\n\n paintInlineImageXObjectGroup:\n function CanvasGraphics_paintInlineImageXObjectGroup(imgData, map) {\n var ctx = this.ctx;\n var w = imgData.width;\n var h = imgData.height;\n\n var tmpCanvas = this.cachedCanvases.getCanvas('inlineImage', w, h);\n var tmpCtx = tmpCanvas.context;\n putBinaryImageData(tmpCtx, imgData);\n\n for (var i = 0, ii = map.length; i < ii; i++) {\n var entry = map[i];\n ctx.save();\n ctx.transform.apply(ctx, entry.transform);\n ctx.scale(1, -1);\n ctx.drawImage(tmpCanvas.canvas, entry.x, entry.y, entry.w, entry.h,\n 0, -1, 1, 1);\n if (this.imageLayer) {\n var position = this.getCanvasPosition(entry.x, entry.y);\n this.imageLayer.appendImage({\n imgData,\n left: position[0],\n top: position[1],\n width: w,\n height: h,\n });\n }\n ctx.restore();\n }\n },\n\n paintSolidColorImageMask:\n function CanvasGraphics_paintSolidColorImageMask() {\n this.ctx.fillRect(0, 0, 1, 1);\n },\n\n paintXObject: function CanvasGraphics_paintXObject() {\n warn('Unsupported \\'paintXObject\\' command.');\n },\n\n // Marked content\n\n markPoint: function CanvasGraphics_markPoint(tag) {\n // TODO Marked content.\n },\n markPointProps: function CanvasGraphics_markPointProps(tag, properties) {\n // TODO Marked content.\n },\n beginMarkedContent: function CanvasGraphics_beginMarkedContent(tag) {\n // TODO Marked content.\n },\n beginMarkedContentProps: function CanvasGraphics_beginMarkedContentProps(\n tag, properties) {\n // TODO Marked content.\n },\n endMarkedContent: function CanvasGraphics_endMarkedContent() {\n // TODO Marked content.\n },\n\n // Compatibility\n\n beginCompat: function CanvasGraphics_beginCompat() {\n // TODO ignore undefined operators (should we do that anyway?)\n },\n endCompat: function CanvasGraphics_endCompat() {\n // TODO stop ignoring undefined operators\n },\n\n // Helper functions\n\n consumePath: function CanvasGraphics_consumePath() {\n var ctx = this.ctx;\n if (this.pendingClip) {\n if (this.pendingClip === EO_CLIP) {\n ctx.clip('evenodd');\n } else {\n ctx.clip();\n }\n this.pendingClip = null;\n }\n ctx.beginPath();\n },\n getSinglePixelWidth: function CanvasGraphics_getSinglePixelWidth(scale) {\n if (this.cachedGetSinglePixelWidth === null) {\n // NOTE: The `save` and `restore` commands used below is a workaround\n // that is necessary in order to prevent `mozCurrentTransformInverse`\n // from intermittently returning incorrect values in Firefox, see:\n // https://github.com/mozilla/pdf.js/issues/7188.\n this.ctx.save();\n var inverse = this.ctx.mozCurrentTransformInverse;\n this.ctx.restore();\n // max of the current horizontal and vertical scale\n this.cachedGetSinglePixelWidth = Math.sqrt(Math.max(\n (inverse[0] * inverse[0] + inverse[1] * inverse[1]),\n (inverse[2] * inverse[2] + inverse[3] * inverse[3])));\n }\n return this.cachedGetSinglePixelWidth;\n },\n getCanvasPosition: function CanvasGraphics_getCanvasPosition(x, y) {\n var transform = this.ctx.mozCurrentTransform;\n return [\n transform[0] * x + transform[2] * y + transform[4],\n transform[1] * x + transform[3] * y + transform[5]\n ];\n },\n };\n\n for (var op in OPS) {\n CanvasGraphics.prototype[OPS[op]] = CanvasGraphics.prototype[op];\n }\n\n return CanvasGraphics;\n})();\n\nexport {\n CanvasGraphics,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/display/canvas.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n assert, bytesToString, isEvalSupported, shadow, string32, warn\n} from '../shared/util';\n\nfunction FontLoader(docId) {\n this.docId = docId;\n this.styleElement = null;\n if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) {\n this.nativeFontFaces = [];\n this.loadTestFontId = 0;\n this.loadingContext = {\n requests: [],\n nextRequestId: 0,\n };\n }\n}\nFontLoader.prototype = {\n insertRule: function fontLoaderInsertRule(rule) {\n var styleElement = this.styleElement;\n if (!styleElement) {\n styleElement = this.styleElement = document.createElement('style');\n styleElement.id = 'PDFJS_FONT_STYLE_TAG_' + this.docId;\n document.documentElement.getElementsByTagName('head')[0].appendChild(\n styleElement);\n }\n\n var styleSheet = styleElement.sheet;\n styleSheet.insertRule(rule, styleSheet.cssRules.length);\n },\n\n clear: function fontLoaderClear() {\n if (this.styleElement) {\n // Note: ChildNode.remove doesn't throw if the parentNode is undefined.\n this.styleElement.remove();\n this.styleElement = null;\n }\n if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) {\n this.nativeFontFaces.forEach(function(nativeFontFace) {\n document.fonts.delete(nativeFontFace);\n });\n this.nativeFontFaces.length = 0;\n }\n },\n};\n\nif (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) {\n var getLoadTestFont = function () {\n // This is a CFF font with 1 glyph for '.' that fills its entire width and\n // height.\n return atob(\n 'T1RUTwALAIAAAwAwQ0ZGIDHtZg4AAAOYAAAAgUZGVE1lkzZwAAAEHAAAABxHREVGABQAFQ' +\n 'AABDgAAAAeT1MvMlYNYwkAAAEgAAAAYGNtYXABDQLUAAACNAAAAUJoZWFk/xVFDQAAALwA' +\n 'AAA2aGhlYQdkA+oAAAD0AAAAJGhtdHgD6AAAAAAEWAAAAAZtYXhwAAJQAAAAARgAAAAGbm' +\n 'FtZVjmdH4AAAGAAAAAsXBvc3T/hgAzAAADeAAAACAAAQAAAAEAALZRFsRfDzz1AAsD6AAA' +\n 'AADOBOTLAAAAAM4KHDwAAAAAA+gDIQAAAAgAAgAAAAAAAAABAAADIQAAAFoD6AAAAAAD6A' +\n 'ABAAAAAAAAAAAAAAAAAAAAAQAAUAAAAgAAAAQD6AH0AAUAAAKKArwAAACMAooCvAAAAeAA' +\n 'MQECAAACAAYJAAAAAAAAAAAAAQAAAAAAAAAAAAAAAFBmRWQAwAAuAC4DIP84AFoDIQAAAA' +\n 'AAAQAAAAAAAAAAACAAIAABAAAADgCuAAEAAAAAAAAAAQAAAAEAAAAAAAEAAQAAAAEAAAAA' +\n 'AAIAAQAAAAEAAAAAAAMAAQAAAAEAAAAAAAQAAQAAAAEAAAAAAAUAAQAAAAEAAAAAAAYAAQ' +\n 'AAAAMAAQQJAAAAAgABAAMAAQQJAAEAAgABAAMAAQQJAAIAAgABAAMAAQQJAAMAAgABAAMA' +\n 'AQQJAAQAAgABAAMAAQQJAAUAAgABAAMAAQQJAAYAAgABWABYAAAAAAAAAwAAAAMAAAAcAA' +\n 'EAAAAAADwAAwABAAAAHAAEACAAAAAEAAQAAQAAAC7//wAAAC7////TAAEAAAAAAAABBgAA' +\n 'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAA' +\n 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +\n 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +\n 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +\n 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAA' +\n 'AAAAD/gwAyAAAAAQAAAAAAAAAAAAAAAAAAAAABAAQEAAEBAQJYAAEBASH4DwD4GwHEAvgc' +\n 'A/gXBIwMAYuL+nz5tQXkD5j3CBLnEQACAQEBIVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWF' +\n 'hYWFhYWFhYAAABAQAADwACAQEEE/t3Dov6fAH6fAT+fPp8+nwHDosMCvm1Cvm1DAz6fBQA' +\n 'AAAAAAABAAAAAMmJbzEAAAAAzgTjFQAAAADOBOQpAAEAAAAAAAAADAAUAAQAAAABAAAAAg' +\n 'ABAAAAAAAAAAAD6AAAAAAAAA==');\n };\n Object.defineProperty(FontLoader.prototype, 'loadTestFont', {\n get() {\n return shadow(this, 'loadTestFont', getLoadTestFont());\n },\n configurable: true,\n });\n\n FontLoader.prototype.addNativeFontFace =\n function fontLoader_addNativeFontFace(nativeFontFace) {\n this.nativeFontFaces.push(nativeFontFace);\n document.fonts.add(nativeFontFace);\n };\n\n FontLoader.prototype.bind = function fontLoaderBind(fonts, callback) {\n var rules = [];\n var fontsToLoad = [];\n var fontLoadPromises = [];\n var getNativeFontPromise = function(nativeFontFace) {\n // Return a promise that is always fulfilled, even when the font fails to\n // load.\n return nativeFontFace.loaded.catch(function(e) {\n warn('Failed to load font \"' + nativeFontFace.family + '\": ' + e);\n });\n };\n // Firefox Font Loading API does not work with mozPrintCallback --\n // disabling it in this case.\n var isFontLoadingAPISupported = FontLoader.isFontLoadingAPISupported &&\n !FontLoader.isSyncFontLoadingSupported;\n for (var i = 0, ii = fonts.length; i < ii; i++) {\n var font = fonts[i];\n\n // Add the font to the DOM only once or skip if the font\n // is already loaded.\n if (font.attached || font.loading === false) {\n continue;\n }\n font.attached = true;\n\n if (isFontLoadingAPISupported) {\n var nativeFontFace = font.createNativeFontFace();\n if (nativeFontFace) {\n this.addNativeFontFace(nativeFontFace);\n fontLoadPromises.push(getNativeFontPromise(nativeFontFace));\n }\n } else {\n var rule = font.createFontFaceRule();\n if (rule) {\n this.insertRule(rule);\n rules.push(rule);\n fontsToLoad.push(font);\n }\n }\n }\n\n var request = this.queueLoadingCallback(callback);\n if (isFontLoadingAPISupported) {\n Promise.all(fontLoadPromises).then(function() {\n request.complete();\n });\n } else if (rules.length > 0 && !FontLoader.isSyncFontLoadingSupported) {\n this.prepareFontLoadEvent(rules, fontsToLoad, request);\n } else {\n request.complete();\n }\n };\n\n FontLoader.prototype.queueLoadingCallback =\n function FontLoader_queueLoadingCallback(callback) {\n function LoadLoader_completeRequest() {\n assert(!request.end, 'completeRequest() cannot be called twice');\n request.end = Date.now();\n\n // sending all completed requests in order how they were queued\n while (context.requests.length > 0 && context.requests[0].end) {\n var otherRequest = context.requests.shift();\n setTimeout(otherRequest.callback, 0);\n }\n }\n\n var context = this.loadingContext;\n var requestId = 'pdfjs-font-loading-' + (context.nextRequestId++);\n var request = {\n id: requestId,\n complete: LoadLoader_completeRequest,\n callback,\n started: Date.now(),\n };\n context.requests.push(request);\n return request;\n };\n\n FontLoader.prototype.prepareFontLoadEvent =\n function fontLoaderPrepareFontLoadEvent(rules, fonts, request) {\n /** Hack begin */\n // There's currently no event when a font has finished downloading so the\n // following code is a dirty hack to 'guess' when a font is\n // ready. It's assumed fonts are loaded in order, so add a known test\n // font after the desired fonts and then test for the loading of that\n // test font.\n\n function int32(data, offset) {\n return (data.charCodeAt(offset) << 24) |\n (data.charCodeAt(offset + 1) << 16) |\n (data.charCodeAt(offset + 2) << 8) |\n (data.charCodeAt(offset + 3) & 0xff);\n }\n\n function spliceString(s, offset, remove, insert) {\n var chunk1 = s.substr(0, offset);\n var chunk2 = s.substr(offset + remove);\n return chunk1 + insert + chunk2;\n }\n\n var i, ii;\n\n // The temporary canvas is used to determine if fonts are loaded.\n var canvas = document.createElement('canvas');\n canvas.width = 1;\n canvas.height = 1;\n var ctx = canvas.getContext('2d');\n\n var called = 0;\n function isFontReady(name, callback) {\n called++;\n // With setTimeout clamping this gives the font ~100ms to load.\n if (called > 30) {\n warn('Load test font never loaded.');\n callback();\n return;\n }\n ctx.font = '30px ' + name;\n ctx.fillText('.', 0, 20);\n var imageData = ctx.getImageData(0, 0, 1, 1);\n if (imageData.data[3] > 0) {\n callback();\n return;\n }\n setTimeout(isFontReady.bind(null, name, callback));\n }\n\n var loadTestFontId = 'lt' + Date.now() + this.loadTestFontId++;\n // Chromium seems to cache fonts based on a hash of the actual font data,\n // so the font must be modified for each load test else it will appear to\n // be loaded already.\n // TODO: This could maybe be made faster by avoiding the btoa of the full\n // font by splitting it in chunks before hand and padding the font id.\n var data = this.loadTestFont;\n var COMMENT_OFFSET = 976; // has to be on 4 byte boundary (for checksum)\n data = spliceString(data, COMMENT_OFFSET, loadTestFontId.length,\n loadTestFontId);\n // CFF checksum is important for IE, adjusting it\n var CFF_CHECKSUM_OFFSET = 16;\n var XXXX_VALUE = 0x58585858; // the \"comment\" filled with 'X'\n var checksum = int32(data, CFF_CHECKSUM_OFFSET);\n for (i = 0, ii = loadTestFontId.length - 3; i < ii; i += 4) {\n checksum = (checksum - XXXX_VALUE + int32(loadTestFontId, i)) | 0;\n }\n if (i < loadTestFontId.length) { // align to 4 bytes boundary\n checksum = (checksum - XXXX_VALUE +\n int32(loadTestFontId + 'XXX', i)) | 0;\n }\n data = spliceString(data, CFF_CHECKSUM_OFFSET, 4, string32(checksum));\n\n var url = 'url(data:font/opentype;base64,' + btoa(data) + ');';\n var rule = '@font-face { font-family:\"' + loadTestFontId + '\";src:' +\n url + '}';\n this.insertRule(rule);\n\n var names = [];\n for (i = 0, ii = fonts.length; i < ii; i++) {\n names.push(fonts[i].loadedName);\n }\n names.push(loadTestFontId);\n\n var div = document.createElement('div');\n div.setAttribute('style',\n 'visibility: hidden;' +\n 'width: 10px; height: 10px;' +\n 'position: absolute; top: 0px; left: 0px;');\n for (i = 0, ii = names.length; i < ii; ++i) {\n var span = document.createElement('span');\n span.textContent = 'Hi';\n span.style.fontFamily = names[i];\n div.appendChild(span);\n }\n document.body.appendChild(div);\n\n isFontReady(loadTestFontId, function() {\n document.body.removeChild(div);\n request.complete();\n });\n /** Hack end */\n };\n} else {\n FontLoader.prototype.bind = function fontLoaderBind(fonts, callback) {\n for (var i = 0, ii = fonts.length; i < ii; i++) {\n var font = fonts[i];\n if (font.attached) {\n continue;\n }\n\n font.attached = true;\n var rule = font.createFontFaceRule();\n if (rule) {\n this.insertRule(rule);\n }\n }\n\n setTimeout(callback);\n };\n}\nif (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL')) {\n FontLoader.isFontLoadingAPISupported = typeof document !== 'undefined' &&\n !!document.fonts;\n}\nif (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('MOZCENTRAL || CHROME')) {\n var isSyncFontLoadingSupported = function isSyncFontLoadingSupported() {\n if (typeof navigator === 'undefined') {\n // node.js - we can pretend sync font loading is supported.\n return true;\n }\n\n var supported = false;\n\n // User agent string sniffing is bad, but there is no reliable way to tell\n // if font is fully loaded and ready to be used with canvas.\n var m = /Mozilla\\/5.0.*?rv:(\\d+).*? Gecko/.exec(navigator.userAgent);\n if (m && m[1] >= 14) {\n supported = true;\n }\n // TODO other browsers\n return supported;\n };\n Object.defineProperty(FontLoader, 'isSyncFontLoadingSupported', {\n get() {\n return shadow(FontLoader, 'isSyncFontLoadingSupported',\n isSyncFontLoadingSupported());\n },\n enumerable: true,\n configurable: true,\n });\n}\n\nvar IsEvalSupportedCached = {\n get value() {\n return shadow(this, 'value', isEvalSupported());\n },\n};\n\nvar FontFaceObject = (function FontFaceObjectClosure() {\n function FontFaceObject(translatedData, options) {\n this.compiledGlyphs = Object.create(null);\n // importing translated data\n for (var i in translatedData) {\n this[i] = translatedData[i];\n }\n this.options = options;\n }\n FontFaceObject.prototype = {\n createNativeFontFace: function FontFaceObject_createNativeFontFace() {\n if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('MOZCENTRAL')) {\n throw new Error('Not implemented: createNativeFontFace');\n }\n\n if (!this.data) {\n return null;\n }\n\n if (this.options.disableFontFace) {\n this.disableFontFace = true;\n return null;\n }\n\n var nativeFontFace = new FontFace(this.loadedName, this.data, {});\n\n if (this.options.fontRegistry) {\n this.options.fontRegistry.registerFont(this);\n }\n return nativeFontFace;\n },\n\n createFontFaceRule: function FontFaceObject_createFontFaceRule() {\n if (!this.data) {\n return null;\n }\n\n if (this.options.disableFontFace) {\n this.disableFontFace = true;\n return null;\n }\n\n var data = bytesToString(new Uint8Array(this.data));\n var fontName = this.loadedName;\n\n // Add the font-face rule to the document\n var url = ('url(data:' + this.mimetype + ';base64,' + btoa(data) + ');');\n var rule = '@font-face { font-family:\"' + fontName + '\";src:' + url + '}';\n\n if (this.options.fontRegistry) {\n this.options.fontRegistry.registerFont(this, url);\n }\n\n return rule;\n },\n\n getPathGenerator:\n function FontFaceObject_getPathGenerator(objs, character) {\n if (!(character in this.compiledGlyphs)) {\n var cmds = objs.get(this.loadedName + '_path_' + character);\n var current, i, len;\n\n // If we can, compile cmds into JS for MAXIMUM SPEED\n if (this.options.isEvalSupported && IsEvalSupportedCached.value) {\n var args, js = '';\n for (i = 0, len = cmds.length; i < len; i++) {\n current = cmds[i];\n\n if (current.args !== undefined) {\n args = current.args.join(',');\n } else {\n args = '';\n }\n\n js += 'c.' + current.cmd + '(' + args + ');\\n';\n }\n // eslint-disable-next-line no-new-func\n this.compiledGlyphs[character] = new Function('c', 'size', js);\n } else {\n // But fall back on using Function.prototype.apply() if we're\n // blocked from using eval() for whatever reason (like CSP policies)\n this.compiledGlyphs[character] = function(c, size) {\n for (i = 0, len = cmds.length; i < len; i++) {\n current = cmds[i];\n\n if (current.cmd === 'scale') {\n current.args = [size, -size];\n }\n\n c[current.cmd].apply(c, current.args);\n }\n };\n }\n }\n return this.compiledGlyphs[character];\n },\n };\n\n return FontFaceObject;\n})();\n\nexport {\n FontFaceObject,\n FontLoader,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/display/font_loader.js", + "/* Copyright 2014 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FormatError, info, isArray, Util } from '../shared/util';\nimport { WebGLUtils } from './webgl';\n\nvar ShadingIRs = {};\n\nShadingIRs.RadialAxial = {\n fromIR: function RadialAxial_fromIR(raw) {\n var type = raw[1];\n var colorStops = raw[2];\n var p0 = raw[3];\n var p1 = raw[4];\n var r0 = raw[5];\n var r1 = raw[6];\n return {\n type: 'Pattern',\n getPattern: function RadialAxial_getPattern(ctx) {\n var grad;\n if (type === 'axial') {\n grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]);\n } else if (type === 'radial') {\n grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1);\n }\n\n for (var i = 0, ii = colorStops.length; i < ii; ++i) {\n var c = colorStops[i];\n grad.addColorStop(c[0], c[1]);\n }\n return grad;\n },\n };\n },\n};\n\nvar createMeshCanvas = (function createMeshCanvasClosure() {\n function drawTriangle(data, context, p1, p2, p3, c1, c2, c3) {\n // Very basic Gouraud-shaded triangle rasterization algorithm.\n var coords = context.coords, colors = context.colors;\n var bytes = data.data, rowSize = data.width * 4;\n var tmp;\n if (coords[p1 + 1] > coords[p2 + 1]) {\n tmp = p1; p1 = p2; p2 = tmp; tmp = c1; c1 = c2; c2 = tmp;\n }\n if (coords[p2 + 1] > coords[p3 + 1]) {\n tmp = p2; p2 = p3; p3 = tmp; tmp = c2; c2 = c3; c3 = tmp;\n }\n if (coords[p1 + 1] > coords[p2 + 1]) {\n tmp = p1; p1 = p2; p2 = tmp; tmp = c1; c1 = c2; c2 = tmp;\n }\n var x1 = (coords[p1] + context.offsetX) * context.scaleX;\n var y1 = (coords[p1 + 1] + context.offsetY) * context.scaleY;\n var x2 = (coords[p2] + context.offsetX) * context.scaleX;\n var y2 = (coords[p2 + 1] + context.offsetY) * context.scaleY;\n var x3 = (coords[p3] + context.offsetX) * context.scaleX;\n var y3 = (coords[p3 + 1] + context.offsetY) * context.scaleY;\n if (y1 >= y3) {\n return;\n }\n var c1r = colors[c1], c1g = colors[c1 + 1], c1b = colors[c1 + 2];\n var c2r = colors[c2], c2g = colors[c2 + 1], c2b = colors[c2 + 2];\n var c3r = colors[c3], c3g = colors[c3 + 1], c3b = colors[c3 + 2];\n\n var minY = Math.round(y1), maxY = Math.round(y3);\n var xa, car, cag, cab;\n var xb, cbr, cbg, cbb;\n var k;\n for (var y = minY; y <= maxY; y++) {\n if (y < y2) {\n k = y < y1 ? 0 : y1 === y2 ? 1 : (y1 - y) / (y1 - y2);\n xa = x1 - (x1 - x2) * k;\n car = c1r - (c1r - c2r) * k;\n cag = c1g - (c1g - c2g) * k;\n cab = c1b - (c1b - c2b) * k;\n } else {\n k = y > y3 ? 1 : y2 === y3 ? 0 : (y2 - y) / (y2 - y3);\n xa = x2 - (x2 - x3) * k;\n car = c2r - (c2r - c3r) * k;\n cag = c2g - (c2g - c3g) * k;\n cab = c2b - (c2b - c3b) * k;\n }\n k = y < y1 ? 0 : y > y3 ? 1 : (y1 - y) / (y1 - y3);\n xb = x1 - (x1 - x3) * k;\n cbr = c1r - (c1r - c3r) * k;\n cbg = c1g - (c1g - c3g) * k;\n cbb = c1b - (c1b - c3b) * k;\n var x1_ = Math.round(Math.min(xa, xb));\n var x2_ = Math.round(Math.max(xa, xb));\n var j = rowSize * y + x1_ * 4;\n for (var x = x1_; x <= x2_; x++) {\n k = (xa - x) / (xa - xb);\n k = k < 0 ? 0 : k > 1 ? 1 : k;\n bytes[j++] = (car - (car - cbr) * k) | 0;\n bytes[j++] = (cag - (cag - cbg) * k) | 0;\n bytes[j++] = (cab - (cab - cbb) * k) | 0;\n bytes[j++] = 255;\n }\n }\n }\n\n function drawFigure(data, figure, context) {\n var ps = figure.coords;\n var cs = figure.colors;\n var i, ii;\n switch (figure.type) {\n case 'lattice':\n var verticesPerRow = figure.verticesPerRow;\n var rows = Math.floor(ps.length / verticesPerRow) - 1;\n var cols = verticesPerRow - 1;\n for (i = 0; i < rows; i++) {\n var q = i * verticesPerRow;\n for (var j = 0; j < cols; j++, q++) {\n drawTriangle(data, context,\n ps[q], ps[q + 1], ps[q + verticesPerRow],\n cs[q], cs[q + 1], cs[q + verticesPerRow]);\n drawTriangle(data, context,\n ps[q + verticesPerRow + 1], ps[q + 1], ps[q + verticesPerRow],\n cs[q + verticesPerRow + 1], cs[q + 1], cs[q + verticesPerRow]);\n }\n }\n break;\n case 'triangles':\n for (i = 0, ii = ps.length; i < ii; i += 3) {\n drawTriangle(data, context,\n ps[i], ps[i + 1], ps[i + 2],\n cs[i], cs[i + 1], cs[i + 2]);\n }\n break;\n default:\n throw new Error('illegal figure');\n }\n }\n\n function createMeshCanvas(bounds, combinesScale, coords, colors, figures,\n backgroundColor, cachedCanvases) {\n // we will increase scale on some weird factor to let antialiasing take\n // care of \"rough\" edges\n var EXPECTED_SCALE = 1.1;\n // MAX_PATTERN_SIZE is used to avoid OOM situation.\n var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough\n // We need to keep transparent border around our pattern for fill():\n // createPattern with 'no-repeat' will bleed edges across entire area.\n var BORDER_SIZE = 2;\n\n var offsetX = Math.floor(bounds[0]);\n var offsetY = Math.floor(bounds[1]);\n var boundsWidth = Math.ceil(bounds[2]) - offsetX;\n var boundsHeight = Math.ceil(bounds[3]) - offsetY;\n\n var width = Math.min(Math.ceil(Math.abs(boundsWidth * combinesScale[0] *\n EXPECTED_SCALE)), MAX_PATTERN_SIZE);\n var height = Math.min(Math.ceil(Math.abs(boundsHeight * combinesScale[1] *\n EXPECTED_SCALE)), MAX_PATTERN_SIZE);\n var scaleX = boundsWidth / width;\n var scaleY = boundsHeight / height;\n\n var context = {\n coords,\n colors,\n offsetX: -offsetX,\n offsetY: -offsetY,\n scaleX: 1 / scaleX,\n scaleY: 1 / scaleY,\n };\n\n var paddedWidth = width + BORDER_SIZE * 2;\n var paddedHeight = height + BORDER_SIZE * 2;\n\n var canvas, tmpCanvas, i, ii;\n if (WebGLUtils.isEnabled) {\n canvas = WebGLUtils.drawFigures(width, height, backgroundColor,\n figures, context);\n\n // https://bugzilla.mozilla.org/show_bug.cgi?id=972126\n tmpCanvas = cachedCanvases.getCanvas('mesh', paddedWidth, paddedHeight,\n false);\n tmpCanvas.context.drawImage(canvas, BORDER_SIZE, BORDER_SIZE);\n canvas = tmpCanvas.canvas;\n } else {\n tmpCanvas = cachedCanvases.getCanvas('mesh', paddedWidth, paddedHeight,\n false);\n var tmpCtx = tmpCanvas.context;\n\n var data = tmpCtx.createImageData(width, height);\n if (backgroundColor) {\n var bytes = data.data;\n for (i = 0, ii = bytes.length; i < ii; i += 4) {\n bytes[i] = backgroundColor[0];\n bytes[i + 1] = backgroundColor[1];\n bytes[i + 2] = backgroundColor[2];\n bytes[i + 3] = 255;\n }\n }\n for (i = 0; i < figures.length; i++) {\n drawFigure(data, figures[i], context);\n }\n tmpCtx.putImageData(data, BORDER_SIZE, BORDER_SIZE);\n canvas = tmpCanvas.canvas;\n }\n\n return {\n canvas,\n offsetX: offsetX - BORDER_SIZE * scaleX,\n offsetY: offsetY - BORDER_SIZE * scaleY,\n scaleX,\n scaleY,\n };\n }\n return createMeshCanvas;\n})();\n\nShadingIRs.Mesh = {\n fromIR: function Mesh_fromIR(raw) {\n // var type = raw[1];\n var coords = raw[2];\n var colors = raw[3];\n var figures = raw[4];\n var bounds = raw[5];\n var matrix = raw[6];\n // var bbox = raw[7];\n var background = raw[8];\n return {\n type: 'Pattern',\n getPattern: function Mesh_getPattern(ctx, owner, shadingFill) {\n var scale;\n if (shadingFill) {\n scale = Util.singularValueDecompose2dScale(ctx.mozCurrentTransform);\n } else {\n // Obtain scale from matrix and current transformation matrix.\n scale = Util.singularValueDecompose2dScale(owner.baseTransform);\n if (matrix) {\n var matrixScale = Util.singularValueDecompose2dScale(matrix);\n scale = [scale[0] * matrixScale[0],\n scale[1] * matrixScale[1]];\n }\n }\n\n\n // Rasterizing on the main thread since sending/queue large canvases\n // might cause OOM.\n var temporaryPatternCanvas = createMeshCanvas(bounds, scale, coords,\n colors, figures, shadingFill ? null : background,\n owner.cachedCanvases);\n\n if (!shadingFill) {\n ctx.setTransform.apply(ctx, owner.baseTransform);\n if (matrix) {\n ctx.transform.apply(ctx, matrix);\n }\n }\n\n ctx.translate(temporaryPatternCanvas.offsetX,\n temporaryPatternCanvas.offsetY);\n ctx.scale(temporaryPatternCanvas.scaleX,\n temporaryPatternCanvas.scaleY);\n\n return ctx.createPattern(temporaryPatternCanvas.canvas, 'no-repeat');\n },\n };\n },\n};\n\nShadingIRs.Dummy = {\n fromIR: function Dummy_fromIR() {\n return {\n type: 'Pattern',\n getPattern: function Dummy_fromIR_getPattern() {\n return 'hotpink';\n },\n };\n },\n};\n\nfunction getShadingPatternFromIR(raw) {\n var shadingIR = ShadingIRs[raw[0]];\n if (!shadingIR) {\n throw new Error(`Unknown IR type: ${raw[0]}`);\n }\n return shadingIR.fromIR(raw);\n}\n\nvar TilingPattern = (function TilingPatternClosure() {\n var PaintType = {\n COLORED: 1,\n UNCOLORED: 2,\n };\n\n var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough\n\n function TilingPattern(IR, color, ctx, canvasGraphicsFactory, baseTransform) {\n this.operatorList = IR[2];\n this.matrix = IR[3] || [1, 0, 0, 1, 0, 0];\n this.bbox = IR[4];\n this.xstep = IR[5];\n this.ystep = IR[6];\n this.paintType = IR[7];\n this.tilingType = IR[8];\n this.color = color;\n this.canvasGraphicsFactory = canvasGraphicsFactory;\n this.baseTransform = baseTransform;\n this.type = 'Pattern';\n this.ctx = ctx;\n }\n\n TilingPattern.prototype = {\n createPatternCanvas: function TilinPattern_createPatternCanvas(owner) {\n var operatorList = this.operatorList;\n var bbox = this.bbox;\n var xstep = this.xstep;\n var ystep = this.ystep;\n var paintType = this.paintType;\n var tilingType = this.tilingType;\n var color = this.color;\n var canvasGraphicsFactory = this.canvasGraphicsFactory;\n\n info('TilingType: ' + tilingType);\n\n var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];\n\n var topLeft = [x0, y0];\n // we want the canvas to be as large as the step size\n var botRight = [x0 + xstep, y0 + ystep];\n\n var width = botRight[0] - topLeft[0];\n var height = botRight[1] - topLeft[1];\n\n // Obtain scale from matrix and current transformation matrix.\n var matrixScale = Util.singularValueDecompose2dScale(this.matrix);\n var curMatrixScale = Util.singularValueDecompose2dScale(\n this.baseTransform);\n var combinedScale = [matrixScale[0] * curMatrixScale[0],\n matrixScale[1] * curMatrixScale[1]];\n\n // MAX_PATTERN_SIZE is used to avoid OOM situation.\n // Use width and height values that are as close as possible to the end\n // result when the pattern is used. Too low value makes the pattern look\n // blurry. Too large value makes it look too crispy.\n width = Math.min(Math.ceil(Math.abs(width * combinedScale[0])),\n MAX_PATTERN_SIZE);\n\n height = Math.min(Math.ceil(Math.abs(height * combinedScale[1])),\n MAX_PATTERN_SIZE);\n\n var tmpCanvas = owner.cachedCanvases.getCanvas('pattern',\n width, height, true);\n var tmpCtx = tmpCanvas.context;\n var graphics = canvasGraphicsFactory.createCanvasGraphics(tmpCtx);\n graphics.groupLevel = owner.groupLevel;\n\n this.setFillAndStrokeStyleToContext(tmpCtx, paintType, color);\n\n this.setScale(width, height, xstep, ystep);\n this.transformToScale(graphics);\n\n // transform coordinates to pattern space\n var tmpTranslate = [1, 0, 0, 1, -topLeft[0], -topLeft[1]];\n graphics.transform.apply(graphics, tmpTranslate);\n\n this.clipBbox(graphics, bbox, x0, y0, x1, y1);\n\n graphics.executeOperatorList(operatorList);\n return tmpCanvas.canvas;\n },\n\n setScale: function TilingPattern_setScale(width, height, xstep, ystep) {\n this.scale = [width / xstep, height / ystep];\n },\n\n transformToScale: function TilingPattern_transformToScale(graphics) {\n var scale = this.scale;\n var tmpScale = [scale[0], 0, 0, scale[1], 0, 0];\n graphics.transform.apply(graphics, tmpScale);\n },\n\n scaleToContext: function TilingPattern_scaleToContext() {\n var scale = this.scale;\n this.ctx.scale(1 / scale[0], 1 / scale[1]);\n },\n\n clipBbox: function clipBbox(graphics, bbox, x0, y0, x1, y1) {\n if (isArray(bbox) && bbox.length === 4) {\n var bboxWidth = x1 - x0;\n var bboxHeight = y1 - y0;\n graphics.ctx.rect(x0, y0, bboxWidth, bboxHeight);\n graphics.clip();\n graphics.endPath();\n }\n },\n\n setFillAndStrokeStyleToContext:\n function setFillAndStrokeStyleToContext(context, paintType, color) {\n switch (paintType) {\n case PaintType.COLORED:\n var ctx = this.ctx;\n context.fillStyle = ctx.fillStyle;\n context.strokeStyle = ctx.strokeStyle;\n break;\n case PaintType.UNCOLORED:\n var cssColor = Util.makeCssRgb(color[0], color[1], color[2]);\n context.fillStyle = cssColor;\n context.strokeStyle = cssColor;\n break;\n default:\n throw new FormatError(`Unsupported paint type: ${paintType}`);\n }\n },\n\n getPattern: function TilingPattern_getPattern(ctx, owner) {\n var temporaryPatternCanvas = this.createPatternCanvas(owner);\n\n ctx = this.ctx;\n ctx.setTransform.apply(ctx, this.baseTransform);\n ctx.transform.apply(ctx, this.matrix);\n this.scaleToContext();\n\n return ctx.createPattern(temporaryPatternCanvas, 'repeat');\n },\n };\n\n return TilingPattern;\n})();\n\nexport {\n getShadingPatternFromIR,\n TilingPattern,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/display/pattern_helper.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert, createPromiseCapability } from '../shared/util';\n\n /** @implements {IPDFStream} */\nvar PDFDataTransportStream = (function PDFDataTransportStreamClosure() {\n function PDFDataTransportStream(params, pdfDataRangeTransport) {\n assert(pdfDataRangeTransport);\n\n this._queuedChunks = [];\n var initialData = params.initialData;\n if (initialData && initialData.length > 0) {\n let buffer = new Uint8Array(initialData).buffer;\n this._queuedChunks.push(buffer);\n }\n\n this._pdfDataRangeTransport = pdfDataRangeTransport;\n this._isRangeSupported = !(params.disableRange);\n this._isStreamingSupported = !(params.disableStream);\n this._contentLength = params.length;\n\n this._fullRequestReader = null;\n this._rangeReaders = [];\n\n this._pdfDataRangeTransport.addRangeListener((begin, chunk) => {\n this._onReceiveData({ begin, chunk, });\n });\n\n this._pdfDataRangeTransport.addProgressListener((loaded) => {\n this._onProgress({ loaded, });\n });\n\n this._pdfDataRangeTransport.addProgressiveReadListener((chunk) => {\n this._onReceiveData({ chunk, });\n });\n\n this._pdfDataRangeTransport.transportReady();\n }\n PDFDataTransportStream.prototype = {\n _onReceiveData: function PDFDataTransportStream_onReceiveData(args) {\n let buffer = new Uint8Array(args.chunk).buffer;\n if (args.begin === undefined) {\n if (this._fullRequestReader) {\n this._fullRequestReader._enqueue(buffer);\n } else {\n this._queuedChunks.push(buffer);\n }\n } else {\n var found = this._rangeReaders.some(function (rangeReader) {\n if (rangeReader._begin !== args.begin) {\n return false;\n }\n rangeReader._enqueue(buffer);\n return true;\n });\n assert(found);\n }\n },\n\n _onProgress: function PDFDataTransportStream_onDataProgress(evt) {\n if (this._rangeReaders.length > 0) {\n // Reporting to first range reader.\n var firstReader = this._rangeReaders[0];\n if (firstReader.onProgress) {\n firstReader.onProgress({ loaded: evt.loaded, });\n }\n }\n },\n\n _removeRangeReader:\n function PDFDataTransportStream_removeRangeReader(reader) {\n var i = this._rangeReaders.indexOf(reader);\n if (i >= 0) {\n this._rangeReaders.splice(i, 1);\n }\n },\n\n getFullReader: function PDFDataTransportStream_getFullReader() {\n assert(!this._fullRequestReader);\n var queuedChunks = this._queuedChunks;\n this._queuedChunks = null;\n return new PDFDataTransportStreamReader(this, queuedChunks);\n },\n\n getRangeReader: function PDFDataTransportStream_getRangeReader(begin, end) {\n var reader = new PDFDataTransportStreamRangeReader(this, begin, end);\n this._pdfDataRangeTransport.requestDataRange(begin, end);\n this._rangeReaders.push(reader);\n return reader;\n },\n\n cancelAllRequests:\n function PDFDataTransportStream_cancelAllRequests(reason) {\n if (this._fullRequestReader) {\n this._fullRequestReader.cancel(reason);\n }\n var readers = this._rangeReaders.slice(0);\n readers.forEach(function (rangeReader) {\n rangeReader.cancel(reason);\n });\n this._pdfDataRangeTransport.abort();\n },\n };\n\n /** @implements {IPDFStreamReader} */\n function PDFDataTransportStreamReader(stream, queuedChunks) {\n this._stream = stream;\n this._done = false;\n this._queuedChunks = queuedChunks || [];\n this._requests = [];\n this._headersReady = Promise.resolve();\n stream._fullRequestReader = this;\n\n this.onProgress = null; // not used\n }\n PDFDataTransportStreamReader.prototype = {\n _enqueue: function PDFDataTransportStreamReader_enqueue(chunk) {\n if (this._done) {\n return; // ignore new data\n }\n if (this._requests.length > 0) {\n var requestCapability = this._requests.shift();\n requestCapability.resolve({ value: chunk, done: false, });\n return;\n }\n this._queuedChunks.push(chunk);\n },\n\n get headersReady() {\n return this._headersReady;\n },\n\n get isRangeSupported() {\n return this._stream._isRangeSupported;\n },\n\n get isStreamingSupported() {\n return this._stream._isStreamingSupported;\n },\n\n get contentLength() {\n return this._stream._contentLength;\n },\n\n read: function PDFDataTransportStreamReader_read() {\n if (this._queuedChunks.length > 0) {\n var chunk = this._queuedChunks.shift();\n return Promise.resolve({ value: chunk, done: false, });\n }\n if (this._done) {\n return Promise.resolve({ value: undefined, done: true, });\n }\n var requestCapability = createPromiseCapability();\n this._requests.push(requestCapability);\n return requestCapability.promise;\n },\n\n cancel: function PDFDataTransportStreamReader_cancel(reason) {\n this._done = true;\n this._requests.forEach(function (requestCapability) {\n requestCapability.resolve({ value: undefined, done: true, });\n });\n this._requests = [];\n },\n };\n\n /** @implements {IPDFStreamRangeReader} */\n function PDFDataTransportStreamRangeReader(stream, begin, end) {\n this._stream = stream;\n this._begin = begin;\n this._end = end;\n this._queuedChunk = null;\n this._requests = [];\n this._done = false;\n\n this.onProgress = null;\n }\n PDFDataTransportStreamRangeReader.prototype = {\n _enqueue: function PDFDataTransportStreamRangeReader_enqueue(chunk) {\n if (this._done) {\n return; // ignore new data\n }\n if (this._requests.length === 0) {\n this._queuedChunk = chunk;\n } else {\n var requestsCapability = this._requests.shift();\n requestsCapability.resolve({ value: chunk, done: false, });\n this._requests.forEach(function (requestCapability) {\n requestCapability.resolve({ value: undefined, done: true, });\n });\n this._requests = [];\n }\n this._done = true;\n this._stream._removeRangeReader(this);\n },\n\n get isStreamingSupported() {\n return false;\n },\n\n read: function PDFDataTransportStreamRangeReader_read() {\n if (this._queuedChunk) {\n let chunk = this._queuedChunk;\n this._queuedChunk = null;\n return Promise.resolve({ value: chunk, done: false, });\n }\n if (this._done) {\n return Promise.resolve({ value: undefined, done: true, });\n }\n var requestCapability = createPromiseCapability();\n this._requests.push(requestCapability);\n return requestCapability.promise;\n },\n\n cancel: function PDFDataTransportStreamRangeReader_cancel(reason) {\n this._done = true;\n this._requests.forEach(function (requestCapability) {\n requestCapability.resolve({ value: undefined, done: true, });\n });\n this._requests = [];\n this._stream._removeRangeReader(this);\n },\n };\n\n return PDFDataTransportStream;\n})();\n\nexport {\n PDFDataTransportStream,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/display/transport_stream.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* eslint-disable no-unused-vars */\n\n'use strict';\n\nvar pdfjsVersion =\n typeof PDFJSDev !== 'undefined' ? PDFJSDev.eval('BUNDLE_VERSION') : void 0;\nvar pdfjsBuild =\n typeof PDFJSDev !== 'undefined' ? PDFJSDev.eval('BUNDLE_BUILD') : void 0;\n\nvar pdfjsSharedUtil = require('./shared/util.js');\nvar pdfjsDisplayGlobal = require('./display/global.js');\nvar pdfjsDisplayAPI = require('./display/api.js');\nvar pdfjsDisplayTextLayer = require('./display/text_layer.js');\nvar pdfjsDisplayAnnotationLayer = require('./display/annotation_layer.js');\nvar pdfjsDisplayDOMUtils = require('./display/dom_utils.js');\nvar pdfjsDisplaySVG = require('./display/svg.js');\n\nif (typeof PDFJSDev === 'undefined' ||\n !PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n require('./display/network.js');\n}\n\nexports.PDFJS = pdfjsDisplayGlobal.PDFJS;\nexports.build = pdfjsDisplayAPI.build;\nexports.version = pdfjsDisplayAPI.version;\nexports.getDocument = pdfjsDisplayAPI.getDocument;\nexports.LoopbackPort = pdfjsDisplayAPI.LoopbackPort;\nexports.PDFDataRangeTransport = pdfjsDisplayAPI.PDFDataRangeTransport;\nexports.PDFWorker = pdfjsDisplayAPI.PDFWorker;\nexports.renderTextLayer = pdfjsDisplayTextLayer.renderTextLayer;\nexports.AnnotationLayer = pdfjsDisplayAnnotationLayer.AnnotationLayer;\nexports.CustomStyle = pdfjsDisplayDOMUtils.CustomStyle;\nexports.createPromiseCapability = pdfjsSharedUtil.createPromiseCapability;\nexports.PasswordResponses = pdfjsSharedUtil.PasswordResponses;\nexports.InvalidPDFException = pdfjsSharedUtil.InvalidPDFException;\nexports.MissingPDFException = pdfjsSharedUtil.MissingPDFException;\nexports.SVGGraphics = pdfjsDisplaySVG.SVGGraphics;\nexports.NativeImageDecoding = pdfjsSharedUtil.NativeImageDecoding;\nexports.UnexpectedResponseException =\n pdfjsSharedUtil.UnexpectedResponseException;\nexports.OPS = pdfjsSharedUtil.OPS;\nexports.UNSUPPORTED_FEATURES = pdfjsSharedUtil.UNSUPPORTED_FEATURES;\nexports.isValidUrl = pdfjsDisplayDOMUtils.isValidUrl;\nexports.createValidAbsoluteUrl = pdfjsSharedUtil.createValidAbsoluteUrl;\nexports.createObjectURL = pdfjsSharedUtil.createObjectURL;\nexports.removeNullCharacters = pdfjsSharedUtil.removeNullCharacters;\nexports.shadow = pdfjsSharedUtil.shadow;\nexports.createBlob = pdfjsSharedUtil.createBlob;\nexports.RenderingCancelledException =\n pdfjsDisplayDOMUtils.RenderingCancelledException;\nexports.getFilenameFromUrl = pdfjsDisplayDOMUtils.getFilenameFromUrl;\nexports.addLinkAttributes = pdfjsDisplayDOMUtils.addLinkAttributes;\nexports.StatTimer = pdfjsSharedUtil.StatTimer;\n\n\n\n// WEBPACK FOOTER //\n// src/pdf.js", + "/* Copyright 2017 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* eslint-disable no-extend-native */\n/* globals VBArray, PDFJS, global */\n\n// Skip compatibility checks for the extensions and if we already ran\n// this module.\nif ((typeof PDFJSDev === 'undefined' ||\n !PDFJSDev.test('FIREFOX || MOZCENTRAL || CHROME')) &&\n (typeof PDFJS === 'undefined' || !PDFJS.compatibilityChecked)) {\n\nvar globalScope =\n (typeof window !== 'undefined' && window.Math === Math) ? window :\n (typeof global !== 'undefined' && global.Math === Math) ? global :\n (typeof self !== 'undefined' && self.Math === Math) ? self :\n (typeof this !== 'undefined' && this.Math === Math) ? this : {};\n\nvar userAgent = (typeof navigator !== 'undefined' && navigator.userAgent) || '';\nvar isAndroid = /Android/.test(userAgent);\nvar isAndroidPre3 = /Android\\s[0-2][^\\d]/.test(userAgent);\nvar isAndroidPre5 = /Android\\s[0-4][^\\d]/.test(userAgent);\nvar isChrome = userAgent.indexOf('Chrom') >= 0;\nvar isChromeWithRangeBug = /Chrome\\/(39|40)\\./.test(userAgent);\nvar isIOSChrome = userAgent.indexOf('CriOS') >= 0;\nvar isIE = userAgent.indexOf('Trident') >= 0;\nvar isIOS = /\\b(iPad|iPhone|iPod)(?=;)/.test(userAgent);\nvar isOpera = userAgent.indexOf('Opera') >= 0;\nvar isSafari = /Safari\\//.test(userAgent) &&\n !/(Chrome\\/|Android\\s)/.test(userAgent);\n\nvar hasDOM = typeof window === 'object' && typeof document === 'object';\n\n// Initializing PDFJS global object here, it case if we need to change/disable\n// some PDF.js features, e.g. range requests\nif (typeof PDFJS === 'undefined') {\n globalScope.PDFJS = {};\n}\n\nPDFJS.compatibilityChecked = true;\n\n// Checking if the typed arrays are supported\n// Support: iOS<6.0 (subarray), IE<10, Android<4.0\n(function checkTypedArrayCompatibility() {\n if (typeof Uint8Array !== 'undefined') {\n // Support: iOS<6.0\n if (typeof Uint8Array.prototype.subarray === 'undefined') {\n Uint8Array.prototype.subarray = function subarray(start, end) {\n return new Uint8Array(this.slice(start, end));\n };\n Float32Array.prototype.subarray = function subarray(start, end) {\n return new Float32Array(this.slice(start, end));\n };\n }\n\n // Support: Android<4.1\n if (typeof Float64Array === 'undefined') {\n globalScope.Float64Array = Float32Array;\n }\n return;\n }\n\n function subarray(start, end) {\n return new TypedArray(this.slice(start, end));\n }\n\n function setArrayOffset(array, offset) {\n if (arguments.length < 2) {\n offset = 0;\n }\n for (var i = 0, n = array.length; i < n; ++i, ++offset) {\n this[offset] = array[i] & 0xFF;\n }\n }\n\n function Uint32ArrayView(buffer, length) {\n this.buffer = buffer;\n this.byteLength = buffer.length;\n this.length = length;\n ensureUint32ArrayViewProps(this.length);\n }\n Uint32ArrayView.prototype = Object.create(null);\n\n var uint32ArrayViewSetters = 0;\n function createUint32ArrayProp(index) {\n return {\n get() {\n var buffer = this.buffer, offset = index << 2;\n return (buffer[offset] | (buffer[offset + 1] << 8) |\n (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24)) >>> 0;\n },\n set(value) {\n var buffer = this.buffer, offset = index << 2;\n buffer[offset] = value & 255;\n buffer[offset + 1] = (value >> 8) & 255;\n buffer[offset + 2] = (value >> 16) & 255;\n buffer[offset + 3] = (value >>> 24) & 255;\n },\n };\n }\n\n function ensureUint32ArrayViewProps(length) {\n while (uint32ArrayViewSetters < length) {\n Object.defineProperty(Uint32ArrayView.prototype,\n uint32ArrayViewSetters,\n createUint32ArrayProp(uint32ArrayViewSetters));\n uint32ArrayViewSetters++;\n }\n }\n\n function TypedArray(arg1) {\n var result, i, n;\n if (typeof arg1 === 'number') {\n result = [];\n for (i = 0; i < arg1; ++i) {\n result[i] = 0;\n }\n } else if ('slice' in arg1) {\n result = arg1.slice(0);\n } else {\n result = [];\n for (i = 0, n = arg1.length; i < n; ++i) {\n result[i] = arg1[i];\n }\n }\n\n result.subarray = subarray;\n result.buffer = result;\n result.byteLength = result.length;\n result.set = setArrayOffset;\n\n if (typeof arg1 === 'object' && arg1.buffer) {\n result.buffer = arg1.buffer;\n }\n return result;\n }\n\n globalScope.Uint8Array = TypedArray;\n globalScope.Int8Array = TypedArray;\n\n // we don't need support for set, byteLength for 32-bit array\n // so we can use the TypedArray as well\n globalScope.Int32Array = TypedArray;\n globalScope.Uint16Array = TypedArray;\n globalScope.Float32Array = TypedArray;\n globalScope.Float64Array = TypedArray;\n\n globalScope.Uint32Array = function () {\n if (arguments.length === 3) {\n // Building view for buffer, offset, and length\n if (arguments[1] !== 0) {\n throw new Error('offset !== 0 is not supported');\n }\n return new Uint32ArrayView(arguments[0], arguments[2]);\n }\n return TypedArray.apply(this, arguments);\n };\n})();\n\n// window.CanvasPixelArray.buffer/.byteLength\n// Support: IE9\n(function canvasPixelArrayBuffer() {\n if (!hasDOM || !window.CanvasPixelArray) {\n return;\n }\n var cpaProto = window.CanvasPixelArray.prototype;\n if ('buffer' in cpaProto) {\n return;\n }\n // Trying to fake CanvasPixelArray as Uint8ClampedArray.\n Object.defineProperty(cpaProto, 'buffer', {\n get() {\n return this;\n },\n enumerable: false,\n configurable: true,\n });\n Object.defineProperty(cpaProto, 'byteLength', {\n get() {\n return this.length;\n },\n enumerable: false,\n configurable: true,\n });\n})();\n\n// URL = URL || webkitURL\n// Support: Safari<7, Android 4.2+\n(function normalizeURLObject() {\n if (!globalScope.URL) {\n globalScope.URL = globalScope.webkitURL;\n }\n})();\n\n// Object.defineProperty()?\n// Support: Android<4.0, Safari<5.1\n(function checkObjectDefinePropertyCompatibility() {\n if (typeof Object.defineProperty !== 'undefined') {\n var definePropertyPossible = true;\n try {\n if (hasDOM) {\n // some browsers (e.g. safari) cannot use defineProperty() on DOM\n // objects and thus the native version is not sufficient\n Object.defineProperty(new Image(), 'id', { value: 'test', });\n }\n // ... another test for android gb browser for non-DOM objects\n var Test = function Test() {};\n Test.prototype = { get id() { }, };\n Object.defineProperty(new Test(), 'id',\n { value: '', configurable: true, enumerable: true, writable: false, });\n } catch (e) {\n definePropertyPossible = false;\n }\n if (definePropertyPossible) {\n return;\n }\n }\n\n Object.defineProperty = function objectDefineProperty(obj, name, def) {\n delete obj[name];\n if ('get' in def) {\n obj.__defineGetter__(name, def['get']);\n }\n if ('set' in def) {\n obj.__defineSetter__(name, def['set']);\n }\n if ('value' in def) {\n obj.__defineSetter__(name, function objectDefinePropertySetter(value) {\n this.__defineGetter__(name, function objectDefinePropertyGetter() {\n return value;\n });\n return value;\n });\n obj[name] = def.value;\n }\n };\n})();\n\n\n// No XMLHttpRequest#response?\n// Support: IE<11, Android <4.0\n(function checkXMLHttpRequestResponseCompatibility() {\n if (typeof XMLHttpRequest === 'undefined') {\n return;\n }\n var xhrPrototype = XMLHttpRequest.prototype;\n var xhr = new XMLHttpRequest();\n if (!('overrideMimeType' in xhr)) {\n // IE10 might have response, but not overrideMimeType\n // Support: IE10\n Object.defineProperty(xhrPrototype, 'overrideMimeType', {\n value: function xmlHttpRequestOverrideMimeType(mimeType) {},\n });\n }\n if ('responseType' in xhr) {\n return;\n }\n\n Object.defineProperty(xhrPrototype, 'responseType', {\n get: function xmlHttpRequestGetResponseType() {\n return this._responseType || 'text';\n },\n set: function xmlHttpRequestSetResponseType(value) {\n if (value === 'text' || value === 'arraybuffer') {\n this._responseType = value;\n if (value === 'arraybuffer' &&\n typeof this.overrideMimeType === 'function') {\n this.overrideMimeType('text/plain; charset=x-user-defined');\n }\n }\n },\n });\n\n // Support: IE9\n if (typeof VBArray !== 'undefined') {\n Object.defineProperty(xhrPrototype, 'response', {\n get: function xmlHttpRequestResponseGet() {\n if (this.responseType === 'arraybuffer') {\n return new Uint8Array(new VBArray(this.responseBody).toArray());\n }\n return this.responseText;\n },\n });\n return;\n }\n\n Object.defineProperty(xhrPrototype, 'response', {\n get: function xmlHttpRequestResponseGet() {\n if (this.responseType !== 'arraybuffer') {\n return this.responseText;\n }\n var text = this.responseText;\n var i, n = text.length;\n var result = new Uint8Array(n);\n for (i = 0; i < n; ++i) {\n result[i] = text.charCodeAt(i) & 0xFF;\n }\n return result.buffer;\n },\n });\n})();\n\n// window.btoa (base64 encode function) ?\n// Support: IE<10\n(function checkWindowBtoaCompatibility() {\n if ('btoa' in globalScope) {\n return;\n }\n\n var digits =\n 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';\n\n globalScope.btoa = function (chars) {\n var buffer = '';\n var i, n;\n for (i = 0, n = chars.length; i < n; i += 3) {\n var b1 = chars.charCodeAt(i) & 0xFF;\n var b2 = chars.charCodeAt(i + 1) & 0xFF;\n var b3 = chars.charCodeAt(i + 2) & 0xFF;\n var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);\n var d3 = i + 1 < n ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;\n var d4 = i + 2 < n ? (b3 & 0x3F) : 64;\n buffer += (digits.charAt(d1) + digits.charAt(d2) +\n digits.charAt(d3) + digits.charAt(d4));\n }\n return buffer;\n };\n})();\n\n// window.atob (base64 encode function)?\n// Support: IE<10\n(function checkWindowAtobCompatibility() {\n if ('atob' in globalScope) {\n return;\n }\n\n // https://github.com/davidchambers/Base64.js\n var digits =\n 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';\n globalScope.atob = function (input) {\n input = input.replace(/=+$/, '');\n if (input.length % 4 === 1) {\n throw new Error('bad atob input');\n }\n for (\n // initialize result and counters\n var bc = 0, bs, buffer, idx = 0, output = '';\n // get next character\n (buffer = input.charAt(idx++));\n // character found in table?\n // initialize bit storage and add its ascii value\n ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,\n // and if not first of each 4 characters,\n // convert the first 8 bits to one ascii character\n bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0\n ) {\n // try to find character in table (0-63, not found => -1)\n buffer = digits.indexOf(buffer);\n }\n return output;\n };\n})();\n\n// Function.prototype.bind?\n// Support: Android<4.0, iOS<6.0\n(function checkFunctionPrototypeBindCompatibility() {\n if (typeof Function.prototype.bind !== 'undefined') {\n return;\n }\n\n Function.prototype.bind = function functionPrototypeBind(obj) {\n var fn = this, headArgs = Array.prototype.slice.call(arguments, 1);\n var bound = function functionPrototypeBindBound() {\n var args = headArgs.concat(Array.prototype.slice.call(arguments));\n return fn.apply(obj, args);\n };\n return bound;\n };\n})();\n\n// HTMLElement dataset property\n// Support: IE<11, Safari<5.1, Android<4.0\n(function checkDatasetProperty() {\n if (!hasDOM) {\n return;\n }\n var div = document.createElement('div');\n if ('dataset' in div) {\n return; // dataset property exists\n }\n\n Object.defineProperty(HTMLElement.prototype, 'dataset', {\n get() {\n if (this._dataset) {\n return this._dataset;\n }\n\n var dataset = {};\n for (var j = 0, jj = this.attributes.length; j < jj; j++) {\n var attribute = this.attributes[j];\n if (attribute.name.substring(0, 5) !== 'data-') {\n continue;\n }\n var key = attribute.name.substring(5).replace(/\\-([a-z])/g,\n function(all, ch) {\n return ch.toUpperCase();\n });\n dataset[key] = attribute.value;\n }\n\n Object.defineProperty(this, '_dataset', {\n value: dataset,\n writable: false,\n enumerable: false,\n });\n return dataset;\n },\n enumerable: true,\n });\n})();\n\n// HTMLElement classList property\n// Support: IE<10, Android<4.0, iOS<5.0\n(function checkClassListProperty() {\n function changeList(element, itemName, add, remove) {\n var s = element.className || '';\n var list = s.split(/\\s+/g);\n if (list[0] === '') {\n list.shift();\n }\n var index = list.indexOf(itemName);\n if (index < 0 && add) {\n list.push(itemName);\n }\n if (index >= 0 && remove) {\n list.splice(index, 1);\n }\n element.className = list.join(' ');\n return (index >= 0);\n }\n\n if (!hasDOM) {\n return;\n }\n\n var div = document.createElement('div');\n if ('classList' in div) {\n return; // classList property exists\n }\n\n var classListPrototype = {\n add(name) {\n changeList(this.element, name, true, false);\n },\n contains(name) {\n return changeList(this.element, name, false, false);\n },\n remove(name) {\n changeList(this.element, name, false, true);\n },\n toggle(name) {\n changeList(this.element, name, true, true);\n },\n };\n\n Object.defineProperty(HTMLElement.prototype, 'classList', {\n get() {\n if (this._classList) {\n return this._classList;\n }\n\n var classList = Object.create(classListPrototype, {\n element: {\n value: this,\n writable: false,\n enumerable: true,\n },\n });\n Object.defineProperty(this, '_classList', {\n value: classList,\n writable: false,\n enumerable: false,\n });\n return classList;\n },\n enumerable: true,\n });\n})();\n\n// Checking if worker has console support. Forwarding all messages to the main\n// thread if console object is absent.\n(function checkWorkerConsoleCompatibility() {\n if (typeof importScripts === 'undefined' || 'console' in globalScope) {\n return;\n }\n\n var consoleTimer = {};\n\n var workerConsole = {\n log: function log() {\n var args = Array.prototype.slice.call(arguments);\n globalScope.postMessage({\n targetName: 'main',\n action: 'console_log',\n data: args,\n });\n },\n\n error: function error() {\n var args = Array.prototype.slice.call(arguments);\n globalScope.postMessage({\n targetName: 'main',\n action: 'console_error',\n data: args,\n });\n },\n\n time: function time(name) {\n consoleTimer[name] = Date.now();\n },\n\n timeEnd: function timeEnd(name) {\n var time = consoleTimer[name];\n if (!time) {\n throw new Error('Unknown timer name ' + name);\n }\n this.log('Timer:', name, Date.now() - time);\n },\n };\n\n globalScope.console = workerConsole;\n})();\n\n// Check console compatibility\n// In older IE versions the console object is not available\n// unless console is open.\n// Support: IE<10\n(function checkConsoleCompatibility() {\n if (!hasDOM) {\n return;\n }\n if (!('console' in window)) {\n window.console = {\n log() {},\n error() {},\n warn() {},\n };\n return;\n }\n if (!('bind' in console.log)) {\n // native functions in IE9 might not have bind\n console.log = (function(fn) {\n return function(msg) {\n return fn(msg);\n };\n })(console.log);\n console.error = (function(fn) {\n return function(msg) {\n return fn(msg);\n };\n })(console.error);\n console.warn = (function(fn) {\n return function(msg) {\n return fn(msg);\n };\n })(console.warn);\n return;\n }\n})();\n\n// Check onclick compatibility in Opera\n// Support: Opera<15\n(function checkOnClickCompatibility() {\n // workaround for reported Opera bug DSK-354448:\n // onclick fires on disabled buttons with opaque content\n function ignoreIfTargetDisabled(event) {\n if (isDisabled(event.target)) {\n event.stopPropagation();\n }\n }\n function isDisabled(node) {\n return node.disabled || (node.parentNode && isDisabled(node.parentNode));\n }\n if (isOpera) {\n // use browser detection since we cannot feature-check this bug\n document.addEventListener('click', ignoreIfTargetDisabled, true);\n }\n})();\n\n// Checks if possible to use URL.createObjectURL()\n// Support: IE, Chrome on iOS\n(function checkOnBlobSupport() {\n // sometimes IE and Chrome on iOS loosing the data created with\n // createObjectURL(), see #3977 and #8081\n if (isIE || isIOSChrome) {\n PDFJS.disableCreateObjectURL = true;\n }\n})();\n\n// Checks if navigator.language is supported\n(function checkNavigatorLanguage() {\n if (typeof navigator === 'undefined') {\n return;\n }\n if ('language' in navigator) {\n return;\n }\n PDFJS.locale = navigator.userLanguage || 'en-US';\n})();\n\n// Support: Safari 6.0+, Android<3.0, Chrome 39/40, iOS\n(function checkRangeRequests() {\n // Safari has issues with cached range requests see:\n // https://github.com/mozilla/pdf.js/issues/3260\n // Last tested with version 6.0.4.\n\n // Older versions of Android (pre 3.0) has issues with range requests, see:\n // https://github.com/mozilla/pdf.js/issues/3381.\n // Make sure that we only match webkit-based Android browsers,\n // since Firefox/Fennec works as expected.\n\n // Range requests are broken in Chrome 39 and 40, https://crbug.com/442318\n if (isSafari || isAndroidPre3 || isChromeWithRangeBug || isIOS) {\n PDFJS.disableRange = true;\n PDFJS.disableStream = true;\n }\n})();\n\n// Check if the browser supports manipulation of the history.\n// Support: IE<10, Android<4.2\n(function checkHistoryManipulation() {\n if (!hasDOM) {\n return;\n }\n // Android 2.x has so buggy pushState support that it was removed in\n // Android 3.0 and restored as late as in Android 4.2.\n // Support: Android 2.x\n if (!history.pushState || isAndroidPre3) {\n PDFJS.disableHistory = true;\n }\n})();\n\n// Support: IE<11, Chrome<21, Android<4.4, Safari<6\n(function checkSetPresenceInImageData() {\n if (!hasDOM) {\n return;\n }\n // IE < 11 will use window.CanvasPixelArray which lacks set function.\n if (window.CanvasPixelArray) {\n if (typeof window.CanvasPixelArray.prototype.set !== 'function') {\n window.CanvasPixelArray.prototype.set = function(arr) {\n for (var i = 0, ii = this.length; i < ii; i++) {\n this[i] = arr[i];\n }\n };\n }\n } else {\n // Old Chrome and Android use an inaccessible CanvasPixelArray prototype.\n // Because we cannot feature detect it, we rely on user agent parsing.\n var polyfill = false, versionMatch;\n if (isChrome) {\n versionMatch = userAgent.match(/Chrom(e|ium)\\/([0-9]+)\\./);\n // Chrome < 21 lacks the set function.\n polyfill = versionMatch && parseInt(versionMatch[2]) < 21;\n } else if (isAndroid) {\n // Android < 4.4 lacks the set function.\n // Android >= 4.4 will contain Chrome in the user agent,\n // thus pass the Chrome check above and not reach this block.\n polyfill = isAndroidPre5;\n } else if (isSafari) {\n versionMatch = userAgent.\n match(/Version\\/([0-9]+)\\.([0-9]+)\\.([0-9]+) Safari\\//);\n // Safari < 6 lacks the set function.\n polyfill = versionMatch && parseInt(versionMatch[1]) < 6;\n }\n\n if (polyfill) {\n var contextPrototype = window.CanvasRenderingContext2D.prototype;\n var createImageData = contextPrototype.createImageData;\n contextPrototype.createImageData = function(w, h) {\n var imageData = createImageData.call(this, w, h);\n imageData.data.set = function(arr) {\n for (var i = 0, ii = this.length; i < ii; i++) {\n this[i] = arr[i];\n }\n };\n return imageData;\n };\n // this closure will be kept referenced, so clear its vars\n contextPrototype = null;\n }\n }\n})();\n\n// Support: IE<10, Android<4.0, iOS\n(function checkRequestAnimationFrame() {\n function installFakeAnimationFrameFunctions() {\n window.requestAnimationFrame = function (callback) {\n return window.setTimeout(callback, 20);\n };\n window.cancelAnimationFrame = function (timeoutID) {\n window.clearTimeout(timeoutID);\n };\n }\n\n if (!hasDOM) {\n return;\n }\n if (isIOS) {\n // requestAnimationFrame on iOS is broken, replacing with fake one.\n installFakeAnimationFrameFunctions();\n return;\n }\n if ('requestAnimationFrame' in window) {\n return;\n }\n window.requestAnimationFrame = window.mozRequestAnimationFrame ||\n window.webkitRequestAnimationFrame;\n if (window.requestAnimationFrame) {\n return;\n }\n installFakeAnimationFrameFunctions();\n})();\n\n// Support: Android, iOS\n(function checkCanvasSizeLimitation() {\n if (isIOS || isAndroid) {\n // 5MP\n PDFJS.maxCanvasPixels = 5242880;\n }\n})();\n\n// Disable fullscreen support for certain problematic configurations.\n// Support: IE11+ (when embedded).\n(function checkFullscreenSupport() {\n if (!hasDOM) {\n return;\n }\n if (isIE && window.parent !== window) {\n PDFJS.disableFullscreen = true;\n }\n})();\n\n// Provides document.currentScript support\n// Support: IE, Chrome<29.\n(function checkCurrentScript() {\n if (!hasDOM) {\n return;\n }\n if ('currentScript' in document) {\n return;\n }\n Object.defineProperty(document, 'currentScript', {\n get() {\n var scripts = document.getElementsByTagName('script');\n return scripts[scripts.length - 1];\n },\n enumerable: true,\n configurable: true,\n });\n})();\n\n// Provides `input.type = 'type'` runtime failure protection.\n// Support: IE9,10.\n(function checkInputTypeNumberAssign() {\n if (!hasDOM) {\n return;\n }\n var el = document.createElement('input');\n try {\n el.type = 'number';\n } catch (ex) {\n var inputProto = el.constructor.prototype;\n var typeProperty = Object.getOwnPropertyDescriptor(inputProto, 'type');\n Object.defineProperty(inputProto, 'type', {\n get() {\n return typeProperty.get.call(this);\n },\n set(value) {\n typeProperty.set.call(this, value === 'number' ? 'text' : value);\n },\n enumerable: true,\n configurable: true,\n });\n }\n})();\n\n// Provides correct document.readyState value for legacy browsers.\n// Support: IE9,10.\n(function checkDocumentReadyState() {\n if (!hasDOM) {\n return;\n }\n if (!document.attachEvent) {\n return;\n }\n var documentProto = document.constructor.prototype;\n var readyStateProto = Object.getOwnPropertyDescriptor(documentProto,\n 'readyState');\n Object.defineProperty(documentProto, 'readyState', {\n get() {\n var value = readyStateProto.get.call(this);\n return value === 'interactive' ? 'loading' : value;\n },\n set(value) {\n readyStateProto.set.call(this, value);\n },\n enumerable: true,\n configurable: true,\n });\n})();\n\n// Provides support for ChildNode.remove in legacy browsers.\n// Support: IE.\n(function checkChildNodeRemove() {\n if (!hasDOM) {\n return;\n }\n if (typeof Element.prototype.remove !== 'undefined') {\n return;\n }\n Element.prototype.remove = function () {\n if (this.parentNode) {\n this.parentNode.removeChild(this);\n }\n };\n})();\n\n// Provides support for Number.isNaN in legacy browsers.\n// Support: IE.\n(function checkNumberIsNaN() {\n if (Number.isNaN) {\n return;\n }\n Number.isNaN = function(value) {\n return typeof value === 'number' && isNaN(value);\n };\n})();\n\n// Provides support for Number.isInteger in legacy browsers.\n// Support: IE.\n(function checkNumberIsInteger() {\n if (Number.isInteger) {\n return;\n }\n Number.isInteger = function(value) {\n return typeof value === 'number' && isFinite(value) &&\n Math.floor(value) === value;\n };\n})();\n\n/**\n * Polyfill for Promises:\n * The following promise implementation tries to generally implement the\n * Promise/A+ spec. Some notable differences from other promise libraries are:\n * - There currently isn't a separate deferred and promise object.\n * - Unhandled rejections eventually show an error if they aren't handled.\n *\n * Based off of the work in:\n * https://bugzilla.mozilla.org/show_bug.cgi?id=810490\n */\n(function checkPromise() {\n if (globalScope.Promise) {\n // Promises existing in the DOM/Worker, checking presence of all/resolve\n if (typeof globalScope.Promise.all !== 'function') {\n globalScope.Promise.all = function (iterable) {\n var count = 0, results = [], resolve, reject;\n var promise = new globalScope.Promise(function (resolve_, reject_) {\n resolve = resolve_;\n reject = reject_;\n });\n iterable.forEach(function (p, i) {\n count++;\n p.then(function (result) {\n results[i] = result;\n count--;\n if (count === 0) {\n resolve(results);\n }\n }, reject);\n });\n if (count === 0) {\n resolve(results);\n }\n return promise;\n };\n }\n if (typeof globalScope.Promise.resolve !== 'function') {\n globalScope.Promise.resolve = function (value) {\n return new globalScope.Promise(function (resolve) {\n resolve(value);\n });\n };\n }\n if (typeof globalScope.Promise.reject !== 'function') {\n globalScope.Promise.reject = function (reason) {\n return new globalScope.Promise(function (resolve, reject) {\n reject(reason);\n });\n };\n }\n if (typeof globalScope.Promise.prototype.catch !== 'function') {\n globalScope.Promise.prototype.catch = function (onReject) {\n return globalScope.Promise.prototype.then(undefined, onReject);\n };\n }\n return;\n }\n\n var STATUS_PENDING = 0;\n var STATUS_RESOLVED = 1;\n var STATUS_REJECTED = 2;\n\n // In an attempt to avoid silent exceptions, unhandled rejections are\n // tracked and if they aren't handled in a certain amount of time an\n // error is logged.\n var REJECTION_TIMEOUT = 500;\n\n var HandlerManager = {\n handlers: [],\n running: false,\n unhandledRejections: [],\n pendingRejectionCheck: false,\n\n scheduleHandlers: function scheduleHandlers(promise) {\n if (promise._status === STATUS_PENDING) {\n return;\n }\n\n this.handlers = this.handlers.concat(promise._handlers);\n promise._handlers = [];\n\n if (this.running) {\n return;\n }\n this.running = true;\n\n setTimeout(this.runHandlers.bind(this), 0);\n },\n\n runHandlers: function runHandlers() {\n var RUN_TIMEOUT = 1; // ms\n var timeoutAt = Date.now() + RUN_TIMEOUT;\n while (this.handlers.length > 0) {\n var handler = this.handlers.shift();\n\n var nextStatus = handler.thisPromise._status;\n var nextValue = handler.thisPromise._value;\n\n try {\n if (nextStatus === STATUS_RESOLVED) {\n if (typeof handler.onResolve === 'function') {\n nextValue = handler.onResolve(nextValue);\n }\n } else if (typeof handler.onReject === 'function') {\n nextValue = handler.onReject(nextValue);\n nextStatus = STATUS_RESOLVED;\n\n if (handler.thisPromise._unhandledRejection) {\n this.removeUnhandeledRejection(handler.thisPromise);\n }\n }\n } catch (ex) {\n nextStatus = STATUS_REJECTED;\n nextValue = ex;\n }\n\n handler.nextPromise._updateStatus(nextStatus, nextValue);\n if (Date.now() >= timeoutAt) {\n break;\n }\n }\n\n if (this.handlers.length > 0) {\n setTimeout(this.runHandlers.bind(this), 0);\n return;\n }\n\n this.running = false;\n },\n\n addUnhandledRejection: function addUnhandledRejection(promise) {\n this.unhandledRejections.push({\n promise,\n time: Date.now(),\n });\n this.scheduleRejectionCheck();\n },\n\n removeUnhandeledRejection: function removeUnhandeledRejection(promise) {\n promise._unhandledRejection = false;\n for (var i = 0; i < this.unhandledRejections.length; i++) {\n if (this.unhandledRejections[i].promise === promise) {\n this.unhandledRejections.splice(i);\n i--;\n }\n }\n },\n\n scheduleRejectionCheck: function scheduleRejectionCheck() {\n if (this.pendingRejectionCheck) {\n return;\n }\n this.pendingRejectionCheck = true;\n setTimeout(() => {\n this.pendingRejectionCheck = false;\n var now = Date.now();\n for (var i = 0; i < this.unhandledRejections.length; i++) {\n if (now - this.unhandledRejections[i].time > REJECTION_TIMEOUT) {\n var unhandled = this.unhandledRejections[i].promise._value;\n var msg = 'Unhandled rejection: ' + unhandled;\n if (unhandled.stack) {\n msg += '\\n' + unhandled.stack;\n }\n // Raising and catching the error, so debugger can break on it.\n try {\n throw new Error(msg);\n } catch (_) {\n console.warn(msg);\n }\n this.unhandledRejections.splice(i);\n i--;\n }\n }\n if (this.unhandledRejections.length) {\n this.scheduleRejectionCheck();\n }\n }, REJECTION_TIMEOUT);\n },\n };\n\n var Promise = function Promise(resolver) {\n this._status = STATUS_PENDING;\n this._handlers = [];\n try {\n resolver.call(this, this._resolve.bind(this), this._reject.bind(this));\n } catch (e) {\n this._reject(e);\n }\n };\n\n /**\n * Builds a promise that is resolved when all the passed in promises are\n * resolved.\n * @param {array} promises array of data and/or promises to wait for.\n * @return {Promise} New dependent promise.\n */\n Promise.all = function Promise_all(promises) {\n var resolveAll, rejectAll;\n var deferred = new Promise(function (resolve, reject) {\n resolveAll = resolve;\n rejectAll = reject;\n });\n var unresolved = promises.length;\n var results = [];\n if (unresolved === 0) {\n resolveAll(results);\n return deferred;\n }\n function reject(reason) {\n if (deferred._status === STATUS_REJECTED) {\n return;\n }\n results = [];\n rejectAll(reason);\n }\n for (var i = 0, ii = promises.length; i < ii; ++i) {\n var promise = promises[i];\n var resolve = (function(i) {\n return function(value) {\n if (deferred._status === STATUS_REJECTED) {\n return;\n }\n results[i] = value;\n unresolved--;\n if (unresolved === 0) {\n resolveAll(results);\n }\n };\n })(i);\n if (Promise.isPromise(promise)) {\n promise.then(resolve, reject);\n } else {\n resolve(promise);\n }\n }\n return deferred;\n };\n\n /**\n * Checks if the value is likely a promise (has a 'then' function).\n * @return {boolean} true if value is thenable\n */\n Promise.isPromise = function Promise_isPromise(value) {\n return value && typeof value.then === 'function';\n };\n\n /**\n * Creates resolved promise\n * @param value resolve value\n * @returns {Promise}\n */\n Promise.resolve = function Promise_resolve(value) {\n return new Promise(function (resolve) {\n resolve(value);\n });\n };\n\n /**\n * Creates rejected promise\n * @param reason rejection value\n * @returns {Promise}\n */\n Promise.reject = function Promise_reject(reason) {\n return new Promise(function (resolve, reject) {\n reject(reason);\n });\n };\n\n Promise.prototype = {\n _status: null,\n _value: null,\n _handlers: null,\n _unhandledRejection: null,\n\n _updateStatus: function Promise__updateStatus(status, value) {\n if (this._status === STATUS_RESOLVED ||\n this._status === STATUS_REJECTED) {\n return;\n }\n\n if (status === STATUS_RESOLVED &&\n Promise.isPromise(value)) {\n value.then(this._updateStatus.bind(this, STATUS_RESOLVED),\n this._updateStatus.bind(this, STATUS_REJECTED));\n return;\n }\n\n this._status = status;\n this._value = value;\n\n if (status === STATUS_REJECTED && this._handlers.length === 0) {\n this._unhandledRejection = true;\n HandlerManager.addUnhandledRejection(this);\n }\n\n HandlerManager.scheduleHandlers(this);\n },\n\n _resolve: function Promise_resolve(value) {\n this._updateStatus(STATUS_RESOLVED, value);\n },\n\n _reject: function Promise_reject(reason) {\n this._updateStatus(STATUS_REJECTED, reason);\n },\n\n then: function Promise_then(onResolve, onReject) {\n var nextPromise = new Promise(function (resolve, reject) {\n this.resolve = resolve;\n this.reject = reject;\n });\n this._handlers.push({\n thisPromise: this,\n onResolve,\n onReject,\n nextPromise,\n });\n HandlerManager.scheduleHandlers(this);\n return nextPromise;\n },\n\n catch: function Promise_catch(onReject) {\n return this.then(undefined, onReject);\n },\n };\n\n globalScope.Promise = Promise;\n})();\n\n(function checkWeakMap() {\n if (globalScope.WeakMap) {\n return;\n }\n\n var id = 0;\n function WeakMap() {\n this.id = '$weakmap' + (id++);\n }\n WeakMap.prototype = {\n has(obj) {\n if ((typeof obj !== 'object' && typeof obj !== 'function') ||\n obj === null) {\n return false;\n }\n return !!Object.getOwnPropertyDescriptor(obj, this.id);\n },\n get(obj) {\n return this.has(obj) ? obj[this.id] : undefined;\n },\n set(obj, value) {\n Object.defineProperty(obj, this.id, {\n value,\n enumerable: false,\n configurable: true,\n });\n },\n delete(obj) {\n delete obj[this.id];\n },\n };\n\n globalScope.WeakMap = WeakMap;\n})();\n\n// Polyfill from https://github.com/Polymer/URL\n/* Any copyright is dedicated to the Public Domain.\n * http://creativecommons.org/publicdomain/zero/1.0/ */\n(function checkURLConstructor() {\n // feature detect for URL constructor\n var hasWorkingUrl = false;\n try {\n if (typeof URL === 'function' &&\n typeof URL.prototype === 'object' &&\n ('origin' in URL.prototype)) {\n var u = new URL('b', 'http://a');\n u.pathname = 'c%20d';\n hasWorkingUrl = u.href === 'http://a/c%20d';\n }\n } catch (e) { }\n\n if (hasWorkingUrl) {\n return;\n }\n\n var relative = Object.create(null);\n relative['ftp'] = 21;\n relative['file'] = 0;\n relative['gopher'] = 70;\n relative['http'] = 80;\n relative['https'] = 443;\n relative['ws'] = 80;\n relative['wss'] = 443;\n\n var relativePathDotMapping = Object.create(null);\n relativePathDotMapping['%2e'] = '.';\n relativePathDotMapping['.%2e'] = '..';\n relativePathDotMapping['%2e.'] = '..';\n relativePathDotMapping['%2e%2e'] = '..';\n\n function isRelativeScheme(scheme) {\n return relative[scheme] !== undefined;\n }\n\n function invalid() {\n clear.call(this);\n this._isInvalid = true;\n }\n\n function IDNAToASCII(h) {\n if (h === '') {\n invalid.call(this);\n }\n // XXX\n return h.toLowerCase();\n }\n\n function percentEscape(c) {\n var unicode = c.charCodeAt(0);\n if (unicode > 0x20 &&\n unicode < 0x7F &&\n // \" # < > ? `\n [0x22, 0x23, 0x3C, 0x3E, 0x3F, 0x60].indexOf(unicode) === -1\n ) {\n return c;\n }\n return encodeURIComponent(c);\n }\n\n function percentEscapeQuery(c) {\n // XXX This actually needs to encode c using encoding and then\n // convert the bytes one-by-one.\n\n var unicode = c.charCodeAt(0);\n if (unicode > 0x20 &&\n unicode < 0x7F &&\n // \" # < > ` (do not escape '?')\n [0x22, 0x23, 0x3C, 0x3E, 0x60].indexOf(unicode) === -1\n ) {\n return c;\n }\n return encodeURIComponent(c);\n }\n\n var EOF, ALPHA = /[a-zA-Z]/,\n ALPHANUMERIC = /[a-zA-Z0-9\\+\\-\\.]/;\n\n function parse(input, stateOverride, base) {\n function err(message) {\n errors.push(message);\n }\n\n var state = stateOverride || 'scheme start',\n cursor = 0,\n buffer = '',\n seenAt = false,\n seenBracket = false,\n errors = [];\n\n loop: while ((input[cursor - 1] !== EOF || cursor === 0) &&\n !this._isInvalid) {\n var c = input[cursor];\n switch (state) {\n case 'scheme start':\n if (c && ALPHA.test(c)) {\n buffer += c.toLowerCase(); // ASCII-safe\n state = 'scheme';\n } else if (!stateOverride) {\n buffer = '';\n state = 'no scheme';\n continue;\n } else {\n err('Invalid scheme.');\n break loop;\n }\n break;\n\n case 'scheme':\n if (c && ALPHANUMERIC.test(c)) {\n buffer += c.toLowerCase(); // ASCII-safe\n } else if (c === ':') {\n this._scheme = buffer;\n buffer = '';\n if (stateOverride) {\n break loop;\n }\n if (isRelativeScheme(this._scheme)) {\n this._isRelative = true;\n }\n if (this._scheme === 'file') {\n state = 'relative';\n } else if (this._isRelative && base &&\n base._scheme === this._scheme) {\n state = 'relative or authority';\n } else if (this._isRelative) {\n state = 'authority first slash';\n } else {\n state = 'scheme data';\n }\n } else if (!stateOverride) {\n buffer = '';\n cursor = 0;\n state = 'no scheme';\n continue;\n } else if (c === EOF) {\n break loop;\n } else {\n err('Code point not allowed in scheme: ' + c);\n break loop;\n }\n break;\n\n case 'scheme data':\n if (c === '?') {\n this._query = '?';\n state = 'query';\n } else if (c === '#') {\n this._fragment = '#';\n state = 'fragment';\n } else {\n // XXX error handling\n if (c !== EOF && c !== '\\t' && c !== '\\n' && c !== '\\r') {\n this._schemeData += percentEscape(c);\n }\n }\n break;\n\n case 'no scheme':\n if (!base || !(isRelativeScheme(base._scheme))) {\n err('Missing scheme.');\n invalid.call(this);\n } else {\n state = 'relative';\n continue;\n }\n break;\n\n case 'relative or authority':\n if (c === '/' && input[cursor + 1] === '/') {\n state = 'authority ignore slashes';\n } else {\n err('Expected /, got: ' + c);\n state = 'relative';\n continue;\n }\n break;\n\n case 'relative':\n this._isRelative = true;\n if (this._scheme !== 'file') {\n this._scheme = base._scheme;\n }\n if (c === EOF) {\n this._host = base._host;\n this._port = base._port;\n this._path = base._path.slice();\n this._query = base._query;\n this._username = base._username;\n this._password = base._password;\n break loop;\n } else if (c === '/' || c === '\\\\') {\n if (c === '\\\\') {\n err('\\\\ is an invalid code point.');\n }\n state = 'relative slash';\n } else if (c === '?') {\n this._host = base._host;\n this._port = base._port;\n this._path = base._path.slice();\n this._query = '?';\n this._username = base._username;\n this._password = base._password;\n state = 'query';\n } else if (c === '#') {\n this._host = base._host;\n this._port = base._port;\n this._path = base._path.slice();\n this._query = base._query;\n this._fragment = '#';\n this._username = base._username;\n this._password = base._password;\n state = 'fragment';\n } else {\n var nextC = input[cursor + 1];\n var nextNextC = input[cursor + 2];\n if (this._scheme !== 'file' || !ALPHA.test(c) ||\n (nextC !== ':' && nextC !== '|') ||\n (nextNextC !== EOF && nextNextC !== '/' && nextNextC !== '\\\\' &&\n nextNextC !== '?' && nextNextC !== '#')) {\n this._host = base._host;\n this._port = base._port;\n this._username = base._username;\n this._password = base._password;\n this._path = base._path.slice();\n this._path.pop();\n }\n state = 'relative path';\n continue;\n }\n break;\n\n case 'relative slash':\n if (c === '/' || c === '\\\\') {\n if (c === '\\\\') {\n err('\\\\ is an invalid code point.');\n }\n if (this._scheme === 'file') {\n state = 'file host';\n } else {\n state = 'authority ignore slashes';\n }\n } else {\n if (this._scheme !== 'file') {\n this._host = base._host;\n this._port = base._port;\n this._username = base._username;\n this._password = base._password;\n }\n state = 'relative path';\n continue;\n }\n break;\n\n case 'authority first slash':\n if (c === '/') {\n state = 'authority second slash';\n } else {\n err('Expected \\'/\\', got: ' + c);\n state = 'authority ignore slashes';\n continue;\n }\n break;\n\n case 'authority second slash':\n state = 'authority ignore slashes';\n if (c !== '/') {\n err('Expected \\'/\\', got: ' + c);\n continue;\n }\n break;\n\n case 'authority ignore slashes':\n if (c !== '/' && c !== '\\\\') {\n state = 'authority';\n continue;\n } else {\n err('Expected authority, got: ' + c);\n }\n break;\n\n case 'authority':\n if (c === '@') {\n if (seenAt) {\n err('@ already seen.');\n buffer += '%40';\n }\n seenAt = true;\n for (var i = 0; i < buffer.length; i++) {\n var cp = buffer[i];\n if (cp === '\\t' || cp === '\\n' || cp === '\\r') {\n err('Invalid whitespace in authority.');\n continue;\n }\n // XXX check URL code points\n if (cp === ':' && this._password === null) {\n this._password = '';\n continue;\n }\n var tempC = percentEscape(cp);\n if (this._password !== null) {\n this._password += tempC;\n } else {\n this._username += tempC;\n }\n }\n buffer = '';\n } else if (c === EOF || c === '/' || c === '\\\\' ||\n c === '?' || c === '#') {\n cursor -= buffer.length;\n buffer = '';\n state = 'host';\n continue;\n } else {\n buffer += c;\n }\n break;\n\n case 'file host':\n if (c === EOF || c === '/' || c === '\\\\' || c === '?' || c === '#') {\n if (buffer.length === 2 && ALPHA.test(buffer[0]) &&\n (buffer[1] === ':' || buffer[1] === '|')) {\n state = 'relative path';\n } else if (buffer.length === 0) {\n state = 'relative path start';\n } else {\n this._host = IDNAToASCII.call(this, buffer);\n buffer = '';\n state = 'relative path start';\n }\n continue;\n } else if (c === '\\t' || c === '\\n' || c === '\\r') {\n err('Invalid whitespace in file host.');\n } else {\n buffer += c;\n }\n break;\n\n case 'host':\n case 'hostname':\n if (c === ':' && !seenBracket) {\n // XXX host parsing\n this._host = IDNAToASCII.call(this, buffer);\n buffer = '';\n state = 'port';\n if (stateOverride === 'hostname') {\n break loop;\n }\n } else if (c === EOF || c === '/' ||\n c === '\\\\' || c === '?' || c === '#') {\n this._host = IDNAToASCII.call(this, buffer);\n buffer = '';\n state = 'relative path start';\n if (stateOverride) {\n break loop;\n }\n continue;\n } else if (c !== '\\t' && c !== '\\n' && c !== '\\r') {\n if (c === '[') {\n seenBracket = true;\n } else if (c === ']') {\n seenBracket = false;\n }\n buffer += c;\n } else {\n err('Invalid code point in host/hostname: ' + c);\n }\n break;\n\n case 'port':\n if (/[0-9]/.test(c)) {\n buffer += c;\n } else if (c === EOF || c === '/' || c === '\\\\' ||\n c === '?' || c === '#' || stateOverride) {\n if (buffer !== '') {\n var temp = parseInt(buffer, 10);\n if (temp !== relative[this._scheme]) {\n this._port = temp + '';\n }\n buffer = '';\n }\n if (stateOverride) {\n break loop;\n }\n state = 'relative path start';\n continue;\n } else if (c === '\\t' || c === '\\n' || c === '\\r') {\n err('Invalid code point in port: ' + c);\n } else {\n invalid.call(this);\n }\n break;\n\n case 'relative path start':\n if (c === '\\\\') {\n err('\\'\\\\\\' not allowed in path.');\n }\n state = 'relative path';\n if (c !== '/' && c !== '\\\\') {\n continue;\n }\n break;\n\n case 'relative path':\n if (c === EOF || c === '/' || c === '\\\\' ||\n (!stateOverride && (c === '?' || c === '#'))) {\n if (c === '\\\\') {\n err('\\\\ not allowed in relative path.');\n }\n var tmp;\n if ((tmp = relativePathDotMapping[buffer.toLowerCase()])) {\n buffer = tmp;\n }\n if (buffer === '..') {\n this._path.pop();\n if (c !== '/' && c !== '\\\\') {\n this._path.push('');\n }\n } else if (buffer === '.' && c !== '/' && c !== '\\\\') {\n this._path.push('');\n } else if (buffer !== '.') {\n if (this._scheme === 'file' && this._path.length === 0 &&\n buffer.length === 2 && ALPHA.test(buffer[0]) &&\n buffer[1] === '|') {\n buffer = buffer[0] + ':';\n }\n this._path.push(buffer);\n }\n buffer = '';\n if (c === '?') {\n this._query = '?';\n state = 'query';\n } else if (c === '#') {\n this._fragment = '#';\n state = 'fragment';\n }\n } else if (c !== '\\t' && c !== '\\n' && c !== '\\r') {\n buffer += percentEscape(c);\n }\n break;\n\n case 'query':\n if (!stateOverride && c === '#') {\n this._fragment = '#';\n state = 'fragment';\n } else if (c !== EOF && c !== '\\t' && c !== '\\n' && c !== '\\r') {\n this._query += percentEscapeQuery(c);\n }\n break;\n\n case 'fragment':\n if (c !== EOF && c !== '\\t' && c !== '\\n' && c !== '\\r') {\n this._fragment += c;\n }\n break;\n }\n\n cursor++;\n }\n }\n\n function clear() {\n this._scheme = '';\n this._schemeData = '';\n this._username = '';\n this._password = null;\n this._host = '';\n this._port = '';\n this._path = [];\n this._query = '';\n this._fragment = '';\n this._isInvalid = false;\n this._isRelative = false;\n }\n\n // Does not process domain names or IP addresses.\n // Does not handle encoding for the query parameter.\n function JURL(url, base /* , encoding */) {\n if (base !== undefined && !(base instanceof JURL)) {\n base = new JURL(String(base));\n }\n\n this._url = url;\n clear.call(this);\n\n var input = url.replace(/^[ \\t\\r\\n\\f]+|[ \\t\\r\\n\\f]+$/g, '');\n // encoding = encoding || 'utf-8'\n\n parse.call(this, input, null, base);\n }\n\n JURL.prototype = {\n toString() {\n return this.href;\n },\n get href() {\n if (this._isInvalid) {\n return this._url;\n }\n var authority = '';\n if (this._username !== '' || this._password !== null) {\n authority = this._username +\n (this._password !== null ? ':' + this._password : '') + '@';\n }\n\n return this.protocol +\n (this._isRelative ? '//' + authority + this.host : '') +\n this.pathname + this._query + this._fragment;\n },\n // The named parameter should be different from the setter's function name.\n // Otherwise Safari 5 will throw an error (see issue 8541)\n set href(value) {\n clear.call(this);\n parse.call(this, value);\n },\n\n get protocol() {\n return this._scheme + ':';\n },\n set protocol(value) {\n if (this._isInvalid) {\n return;\n }\n parse.call(this, value + ':', 'scheme start');\n },\n\n get host() {\n return this._isInvalid ? '' : this._port ?\n this._host + ':' + this._port : this._host;\n },\n set host(value) {\n if (this._isInvalid || !this._isRelative) {\n return;\n }\n parse.call(this, value, 'host');\n },\n\n get hostname() {\n return this._host;\n },\n set hostname(value) {\n if (this._isInvalid || !this._isRelative) {\n return;\n }\n parse.call(this, value, 'hostname');\n },\n\n get port() {\n return this._port;\n },\n set port(value) {\n if (this._isInvalid || !this._isRelative) {\n return;\n }\n parse.call(this, value, 'port');\n },\n\n get pathname() {\n return this._isInvalid ? '' : this._isRelative ?\n '/' + this._path.join('/') : this._schemeData;\n },\n set pathname(value) {\n if (this._isInvalid || !this._isRelative) {\n return;\n }\n this._path = [];\n parse.call(this, value, 'relative path start');\n },\n\n get search() {\n return this._isInvalid || !this._query || this._query === '?' ?\n '' : this._query;\n },\n set search(value) {\n if (this._isInvalid || !this._isRelative) {\n return;\n }\n this._query = '?';\n if (value[0] === '?') {\n value = value.slice(1);\n }\n parse.call(this, value, 'query');\n },\n\n get hash() {\n return this._isInvalid || !this._fragment || this._fragment === '#' ?\n '' : this._fragment;\n },\n set hash(value) {\n if (this._isInvalid) {\n return;\n }\n this._fragment = '#';\n if (value[0] === '#') {\n value = value.slice(1);\n }\n parse.call(this, value, 'fragment');\n },\n\n get origin() {\n var host;\n if (this._isInvalid || !this._scheme) {\n return '';\n }\n // javascript: Gecko returns String(\"\"), WebKit/Blink String(\"null\")\n // Gecko throws error for \"data://\"\n // data: Gecko returns \"\", Blink returns \"data://\", WebKit returns \"null\"\n // Gecko returns String(\"\") for file: mailto:\n // WebKit/Blink returns String(\"SCHEME://\") for file: mailto:\n switch (this._scheme) {\n case 'data':\n case 'file':\n case 'javascript':\n case 'mailto':\n return 'null';\n case 'blob':\n // Special case of blob: -- returns valid origin of _schemeData.\n try {\n return new JURL(this._schemeData).origin || 'null';\n } catch (_) {\n // Invalid _schemeData origin -- ignoring errors.\n }\n return 'null';\n }\n host = this.host;\n if (!host) {\n return '';\n }\n return this._scheme + '://' + host;\n },\n };\n\n // Copy over the static methods\n var OriginalURL = globalScope.URL;\n if (OriginalURL) {\n JURL.createObjectURL = function(blob) {\n // IE extension allows a second optional options argument.\n // http://msdn.microsoft.com/en-us/library/ie/hh772302(v=vs.85).aspx\n return OriginalURL.createObjectURL.apply(OriginalURL, arguments);\n };\n JURL.revokeObjectURL = function(url) {\n OriginalURL.revokeObjectURL(url);\n };\n }\n\n globalScope.URL = JURL;\n})();\n\n}\n\n\n\n// WEBPACK FOOTER //\n// src/shared/compatibility.js", + "/* Copyright 2017 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nlet isReadableStreamSupported = false;\nif (typeof ReadableStream !== 'undefined') {\n // MS Edge may say it has ReadableStream but they are not up to spec yet.\n try {\n // eslint-disable-next-line no-new\n new ReadableStream({\n start(controller) {\n controller.close();\n },\n });\n isReadableStreamSupported = true;\n } catch (e) {\n // The ReadableStream constructor cannot be used.\n }\n}\nif (isReadableStreamSupported) {\n exports.ReadableStream = ReadableStream;\n} else {\n if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('CHROME')) {\n throw new Error('ReadableStream polyfill is not found for Chrome bundle');\n }\n exports.ReadableStream =\n require('../../external/streams/streams-lib').ReadableStream;\n}\n\n\n\n// WEBPACK FOOTER //\n// src/shared/streams_polyfill.js" + ], + "sourceRoot": "" +} \ No newline at end of file diff --git a/twake/frontend/public/public/viewer/PDFViewer/pdf.worker.js b/twake/frontend/public/public/viewer/PDFViewer/pdf.worker.js new file mode 100755 index 00000000..2cf133d3 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/pdf.worker.js @@ -0,0 +1,42687 @@ +/* Copyright 2017 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. + */ + +(function webpackUniversalModuleDefinition(root, factory) { + if (typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if (typeof define === 'function' && define.amd) + define("pdfjs-dist/build/pdf.worker", [], factory); + else if (typeof exports === 'object') + exports["pdfjs-dist/build/pdf.worker"] = factory(); + else + root["pdfjs-dist/build/pdf.worker"] = root.pdfjsDistBuildPdfWorker = 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; + /******/ + /******/ // identity function for calling harmony imports with the correct context + /******/ + __w_pdfjs_require__.i = function (value) { + return value; + }; + /******/ + /******/ // 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, { + /******/ configurable: false, + /******/ enumerable: true, + /******/ get: getter + /******/ + }); + /******/ + } + /******/ + }; + /******/ + /******/ // 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 = 35); + /******/ + }) + /************************************************************************/ + /******/([ + /* 0 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.loadJpegStream = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isNodeJS = exports.isSpace = exports.isString = exports.isNum = exports.isInt = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.isArray = exports.info = exports.globalScope = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.createBlob = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.StatTimer = exports.PasswordResponses = exports.PasswordException = exports.PageViewport = exports.NotImplementedException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.MessageHandler = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VERBOSITY_LEVELS = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined; + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + __w_pdfjs_require__(36); + + var _streams_polyfill = __w_pdfjs_require__(37); + + var globalScope = typeof window !== 'undefined' && window.Math === Math ? window : typeof global !== 'undefined' && global.Math === Math ? global : typeof self !== 'undefined' && self.Math === Math ? self : undefined; + var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0]; + var NativeImageDecoding = { + NONE: 'none', + DECODE: 'decode', + DISPLAY: 'display' + }; + var TextRenderingMode = { + FILL: 0, + STROKE: 1, + FILL_STROKE: 2, + INVISIBLE: 3, + FILL_ADD_TO_PATH: 4, + STROKE_ADD_TO_PATH: 5, + FILL_STROKE_ADD_TO_PATH: 6, + ADD_TO_PATH: 7, + FILL_STROKE_MASK: 3, + ADD_TO_PATH_FLAG: 4 + }; + var ImageKind = { + GRAYSCALE_1BPP: 1, + RGB_24BPP: 2, + RGBA_32BPP: 3 + }; + var AnnotationType = { + TEXT: 1, + LINK: 2, + FREETEXT: 3, + LINE: 4, + SQUARE: 5, + CIRCLE: 6, + POLYGON: 7, + POLYLINE: 8, + HIGHLIGHT: 9, + UNDERLINE: 10, + SQUIGGLY: 11, + STRIKEOUT: 12, + STAMP: 13, + CARET: 14, + INK: 15, + POPUP: 16, + FILEATTACHMENT: 17, + SOUND: 18, + MOVIE: 19, + WIDGET: 20, + SCREEN: 21, + PRINTERMARK: 22, + TRAPNET: 23, + WATERMARK: 24, + THREED: 25, + REDACT: 26 + }; + var AnnotationFlag = { + INVISIBLE: 0x01, + HIDDEN: 0x02, + PRINT: 0x04, + NOZOOM: 0x08, + NOROTATE: 0x10, + NOVIEW: 0x20, + READONLY: 0x40, + LOCKED: 0x80, + TOGGLENOVIEW: 0x100, + LOCKEDCONTENTS: 0x200 + }; + var AnnotationFieldFlag = { + READONLY: 0x0000001, + REQUIRED: 0x0000002, + NOEXPORT: 0x0000004, + MULTILINE: 0x0001000, + PASSWORD: 0x0002000, + NOTOGGLETOOFF: 0x0004000, + RADIO: 0x0008000, + PUSHBUTTON: 0x0010000, + COMBO: 0x0020000, + EDIT: 0x0040000, + SORT: 0x0080000, + FILESELECT: 0x0100000, + MULTISELECT: 0x0200000, + DONOTSPELLCHECK: 0x0400000, + DONOTSCROLL: 0x0800000, + COMB: 0x1000000, + RICHTEXT: 0x2000000, + RADIOSINUNISON: 0x2000000, + COMMITONSELCHANGE: 0x4000000 + }; + var AnnotationBorderStyleType = { + SOLID: 1, + DASHED: 2, + BEVELED: 3, + INSET: 4, + UNDERLINE: 5 + }; + var StreamType = { + UNKNOWN: 0, + FLATE: 1, + LZW: 2, + DCT: 3, + JPX: 4, + JBIG: 5, + A85: 6, + AHX: 7, + CCF: 8, + RL: 9 + }; + var FontType = { + UNKNOWN: 0, + TYPE1: 1, + TYPE1C: 2, + CIDFONTTYPE0: 3, + CIDFONTTYPE0C: 4, + TRUETYPE: 5, + CIDFONTTYPE2: 6, + TYPE3: 7, + OPENTYPE: 8, + TYPE0: 9, + MMTYPE1: 10 + }; + var VERBOSITY_LEVELS = { + errors: 0, + warnings: 1, + infos: 5 + }; + var CMapCompressionType = { + NONE: 0, + BINARY: 1, + STREAM: 2 + }; + var OPS = { + dependency: 1, + setLineWidth: 2, + setLineCap: 3, + setLineJoin: 4, + setMiterLimit: 5, + setDash: 6, + setRenderingIntent: 7, + setFlatness: 8, + setGState: 9, + save: 10, + restore: 11, + transform: 12, + moveTo: 13, + lineTo: 14, + curveTo: 15, + curveTo2: 16, + curveTo3: 17, + closePath: 18, + rectangle: 19, + stroke: 20, + closeStroke: 21, + fill: 22, + eoFill: 23, + fillStroke: 24, + eoFillStroke: 25, + closeFillStroke: 26, + closeEOFillStroke: 27, + endPath: 28, + clip: 29, + eoClip: 30, + beginText: 31, + endText: 32, + setCharSpacing: 33, + setWordSpacing: 34, + setHScale: 35, + setLeading: 36, + setFont: 37, + setTextRenderingMode: 38, + setTextRise: 39, + moveText: 40, + setLeadingMoveText: 41, + setTextMatrix: 42, + nextLine: 43, + showText: 44, + showSpacedText: 45, + nextLineShowText: 46, + nextLineSetSpacingShowText: 47, + setCharWidth: 48, + setCharWidthAndBounds: 49, + setStrokeColorSpace: 50, + setFillColorSpace: 51, + setStrokeColor: 52, + setStrokeColorN: 53, + setFillColor: 54, + setFillColorN: 55, + setStrokeGray: 56, + setFillGray: 57, + setStrokeRGBColor: 58, + setFillRGBColor: 59, + setStrokeCMYKColor: 60, + setFillCMYKColor: 61, + shadingFill: 62, + beginInlineImage: 63, + beginImageData: 64, + endInlineImage: 65, + paintXObject: 66, + markPoint: 67, + markPointProps: 68, + beginMarkedContent: 69, + beginMarkedContentProps: 70, + endMarkedContent: 71, + beginCompat: 72, + endCompat: 73, + paintFormXObjectBegin: 74, + paintFormXObjectEnd: 75, + beginGroup: 76, + endGroup: 77, + beginAnnotations: 78, + endAnnotations: 79, + beginAnnotation: 80, + endAnnotation: 81, + paintJpegXObject: 82, + paintImageMaskXObject: 83, + paintImageMaskXObjectGroup: 84, + paintImageXObject: 85, + paintInlineImageXObject: 86, + paintInlineImageXObjectGroup: 87, + paintImageXObjectRepeat: 88, + paintImageMaskXObjectRepeat: 89, + paintSolidColorImageMask: 90, + constructPath: 91 + }; + var verbosity = VERBOSITY_LEVELS.warnings; + + function setVerbosityLevel(level) { + verbosity = level; + } + + function getVerbosityLevel() { + return verbosity; + } + + function info(msg) { + if (verbosity >= VERBOSITY_LEVELS.infos) { + console.log('Info: ' + msg); + } + } + + function warn(msg) { + if (verbosity >= VERBOSITY_LEVELS.warnings) { + console.log('Warning: ' + msg); + } + } + + function deprecated(details) { + console.log('Deprecated API usage: ' + details); + } + + function unreachable(msg) { + throw new Error(msg); + } + + function assert(cond, msg) { + if (!cond) { + unreachable(msg); + } + } + + var UNSUPPORTED_FEATURES = { + unknown: 'unknown', + forms: 'forms', + javaScript: 'javaScript', + smask: 'smask', + shadingPattern: 'shadingPattern', + font: 'font' + }; + + function isSameOrigin(baseUrl, otherUrl) { + try { + var base = new URL(baseUrl); + if (!base.origin || base.origin === 'null') { + return false; + } + } catch (e) { + return false; + } + var other = new URL(otherUrl, base); + return base.origin === other.origin; + } + + function isValidProtocol(url) { + if (!url) { + return false; + } + switch (url.protocol) { + case 'http:': + case 'https:': + case 'ftp:': + case 'mailto:': + case 'tel:': + return true; + default: + return false; + } + } + + function createValidAbsoluteUrl(url, baseUrl) { + if (!url) { + return null; + } + try { + var absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url); + if (isValidProtocol(absoluteUrl)) { + return absoluteUrl; + } + } catch (ex) { + } + return null; + } + + function shadow(obj, prop, value) { + Object.defineProperty(obj, prop, { + value: value, + enumerable: true, + configurable: true, + writable: false + }); + return value; + } + + function getLookupTableFactory(initializer) { + var lookup; + return function () { + if (initializer) { + lookup = Object.create(null); + initializer(lookup); + initializer = null; + } + return lookup; + }; + } + + var PasswordResponses = { + NEED_PASSWORD: 1, + INCORRECT_PASSWORD: 2 + }; + var PasswordException = function PasswordExceptionClosure() { + function PasswordException(msg, code) { + this.name = 'PasswordException'; + this.message = msg; + this.code = code; + } + + PasswordException.prototype = new Error(); + PasswordException.constructor = PasswordException; + return PasswordException; + }(); + var UnknownErrorException = function UnknownErrorExceptionClosure() { + function UnknownErrorException(msg, details) { + this.name = 'UnknownErrorException'; + this.message = msg; + this.details = details; + } + + UnknownErrorException.prototype = new Error(); + UnknownErrorException.constructor = UnknownErrorException; + return UnknownErrorException; + }(); + var InvalidPDFException = function InvalidPDFExceptionClosure() { + function InvalidPDFException(msg) { + this.name = 'InvalidPDFException'; + this.message = msg; + } + + InvalidPDFException.prototype = new Error(); + InvalidPDFException.constructor = InvalidPDFException; + return InvalidPDFException; + }(); + var MissingPDFException = function MissingPDFExceptionClosure() { + function MissingPDFException(msg) { + this.name = 'MissingPDFException'; + this.message = msg; + } + + MissingPDFException.prototype = new Error(); + MissingPDFException.constructor = MissingPDFException; + return MissingPDFException; + }(); + var UnexpectedResponseException = function UnexpectedResponseExceptionClosure() { + function UnexpectedResponseException(msg, status) { + this.name = 'UnexpectedResponseException'; + this.message = msg; + this.status = status; + } + + UnexpectedResponseException.prototype = new Error(); + UnexpectedResponseException.constructor = UnexpectedResponseException; + return UnexpectedResponseException; + }(); + var NotImplementedException = function NotImplementedExceptionClosure() { + function NotImplementedException(msg) { + this.message = msg; + } + + NotImplementedException.prototype = new Error(); + NotImplementedException.prototype.name = 'NotImplementedException'; + NotImplementedException.constructor = NotImplementedException; + return NotImplementedException; + }(); + var MissingDataException = function MissingDataExceptionClosure() { + function MissingDataException(begin, end) { + this.begin = begin; + this.end = end; + this.message = 'Missing data [' + begin + ', ' + end + ')'; + } + + MissingDataException.prototype = new Error(); + MissingDataException.prototype.name = 'MissingDataException'; + MissingDataException.constructor = MissingDataException; + return MissingDataException; + }(); + var XRefParseException = function XRefParseExceptionClosure() { + function XRefParseException(msg) { + this.message = msg; + } + + XRefParseException.prototype = new Error(); + XRefParseException.prototype.name = 'XRefParseException'; + XRefParseException.constructor = XRefParseException; + return XRefParseException; + }(); + var FormatError = function FormatErrorClosure() { + function FormatError(msg) { + this.message = msg; + } + + FormatError.prototype = new Error(); + FormatError.prototype.name = 'FormatError'; + FormatError.constructor = FormatError; + return FormatError; + }(); + var AbortException = function AbortExceptionClosure() { + function AbortException(msg) { + this.name = 'AbortException'; + this.message = msg; + } + + AbortException.prototype = new Error(); + AbortException.constructor = AbortException; + return AbortException; + }(); + var NullCharactersRegExp = /\x00/g; + + function removeNullCharacters(str) { + if (typeof str !== 'string') { + warn('The argument for removeNullCharacters must be a string.'); + return str; + } + return str.replace(NullCharactersRegExp, ''); + } + + function bytesToString(bytes) { + assert(bytes !== null && (typeof bytes === 'undefined' ? 'undefined' : _typeof(bytes)) === 'object' && bytes.length !== undefined, 'Invalid argument for bytesToString'); + var length = bytes.length; + var MAX_ARGUMENT_COUNT = 8192; + if (length < MAX_ARGUMENT_COUNT) { + return String.fromCharCode.apply(null, bytes); + } + var strBuf = []; + for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) { + var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length); + var chunk = bytes.subarray(i, chunkEnd); + strBuf.push(String.fromCharCode.apply(null, chunk)); + } + return strBuf.join(''); + } + + function stringToBytes(str) { + assert(typeof str === 'string', 'Invalid argument for stringToBytes'); + var length = str.length; + var bytes = new Uint8Array(length); + for (var i = 0; i < length; ++i) { + bytes[i] = str.charCodeAt(i) & 0xFF; + } + return bytes; + } + + function arrayByteLength(arr) { + if (arr.length !== undefined) { + return arr.length; + } + assert(arr.byteLength !== undefined); + return arr.byteLength; + } + + function arraysToBytes(arr) { + if (arr.length === 1 && arr[0] instanceof Uint8Array) { + return arr[0]; + } + var resultLength = 0; + var i, + ii = arr.length; + var item, itemLength; + for (i = 0; i < ii; i++) { + item = arr[i]; + itemLength = arrayByteLength(item); + resultLength += itemLength; + } + var pos = 0; + var data = new Uint8Array(resultLength); + for (i = 0; i < ii; i++) { + item = arr[i]; + if (!(item instanceof Uint8Array)) { + if (typeof item === 'string') { + item = stringToBytes(item); + } else { + item = new Uint8Array(item); + } + } + itemLength = item.byteLength; + data.set(item, pos); + pos += itemLength; + } + return data; + } + + function string32(value) { + return String.fromCharCode(value >> 24 & 0xff, value >> 16 & 0xff, value >> 8 & 0xff, value & 0xff); + } + + function log2(x) { + var n = 1, + i = 0; + while (x > n) { + n <<= 1; + i++; + } + return i; + } + + function readInt8(data, start) { + return data[start] << 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 isLittleEndian() { + var buffer8 = new Uint8Array(4); + buffer8[0] = 1; + var view32 = new Uint32Array(buffer8.buffer, 0, 1); + return view32[0] === 1; + } + + function isEvalSupported() { + try { + new Function(''); + return true; + } catch (e) { + return false; + } + } + + var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0]; + var Util = function UtilClosure() { + function Util() { + } + + var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')']; + Util.makeCssRgb = function Util_makeCssRgb(r, g, b) { + rgbBuf[1] = r; + rgbBuf[3] = g; + rgbBuf[5] = b; + return rgbBuf.join(''); + }; + Util.transform = function Util_transform(m1, m2) { + return [m1[0] * m2[0] + m1[2] * m2[1], m1[1] * m2[0] + m1[3] * m2[1], m1[0] * m2[2] + m1[2] * m2[3], m1[1] * m2[2] + m1[3] * m2[3], m1[0] * m2[4] + m1[2] * m2[5] + m1[4], m1[1] * m2[4] + m1[3] * m2[5] + m1[5]]; + }; + Util.applyTransform = function Util_applyTransform(p, m) { + var xt = p[0] * m[0] + p[1] * m[2] + m[4]; + var yt = p[0] * m[1] + p[1] * m[3] + m[5]; + return [xt, yt]; + }; + Util.applyInverseTransform = function Util_applyInverseTransform(p, m) { + var d = m[0] * m[3] - m[1] * m[2]; + var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d; + var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d; + return [xt, yt]; + }; + Util.getAxialAlignedBoundingBox = function Util_getAxialAlignedBoundingBox(r, m) { + var p1 = Util.applyTransform(r, m); + var p2 = Util.applyTransform(r.slice(2, 4), m); + var p3 = Util.applyTransform([r[0], r[3]], m); + var p4 = Util.applyTransform([r[2], r[1]], m); + return [Math.min(p1[0], p2[0], p3[0], p4[0]), Math.min(p1[1], p2[1], p3[1], p4[1]), Math.max(p1[0], p2[0], p3[0], p4[0]), Math.max(p1[1], p2[1], p3[1], p4[1])]; + }; + Util.inverseTransform = function Util_inverseTransform(m) { + var d = m[0] * m[3] - m[1] * m[2]; + return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d, (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d]; + }; + Util.apply3dTransform = function Util_apply3dTransform(m, v) { + return [m[0] * v[0] + m[1] * v[1] + m[2] * v[2], m[3] * v[0] + m[4] * v[1] + m[5] * v[2], m[6] * v[0] + m[7] * v[1] + m[8] * v[2]]; + }; + Util.singularValueDecompose2dScale = function Util_singularValueDecompose2dScale(m) { + var transpose = [m[0], m[2], m[1], m[3]]; + var a = m[0] * transpose[0] + m[1] * transpose[2]; + var b = m[0] * transpose[1] + m[1] * transpose[3]; + var c = m[2] * transpose[0] + m[3] * transpose[2]; + var d = m[2] * transpose[1] + m[3] * transpose[3]; + var first = (a + d) / 2; + var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2; + var sx = first + second || 1; + var sy = first - second || 1; + return [Math.sqrt(sx), Math.sqrt(sy)]; + }; + Util.normalizeRect = function Util_normalizeRect(rect) { + var r = rect.slice(0); + if (rect[0] > rect[2]) { + r[0] = rect[2]; + r[2] = rect[0]; + } + if (rect[1] > rect[3]) { + r[1] = rect[3]; + r[3] = rect[1]; + } + return r; + }; + Util.intersect = function Util_intersect(rect1, rect2) { + function compare(a, b) { + return a - b; + } + + var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare), + orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare), + 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 { + return false; + } + 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 { + return false; + } + return result; + }; + Util.sign = function Util_sign(num) { + return num < 0 ? -1 : 1; + }; + var 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']; + Util.toRoman = function Util_toRoman(number, lowerCase) { + assert(isInt(number) && number > 0, 'The number should be a positive integer.'); + var pos, + romanBuf = []; + 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]); + var romanStr = romanBuf.join(''); + return lowerCase ? romanStr.toLowerCase() : romanStr; + }; + Util.appendToArray = function Util_appendToArray(arr1, arr2) { + Array.prototype.push.apply(arr1, arr2); + }; + Util.prependToArray = function Util_prependToArray(arr1, arr2) { + Array.prototype.unshift.apply(arr1, arr2); + }; + Util.extendObj = function extendObj(obj1, obj2) { + for (var key in obj2) { + obj1[key] = obj2[key]; + } + }; + Util.getInheritableProperty = function Util_getInheritableProperty(dict, name, getArray) { + while (dict && !dict.has(name)) { + dict = dict.get('Parent'); + } + if (!dict) { + return null; + } + return getArray ? dict.getArray(name) : dict.get(name); + }; + Util.inherit = function Util_inherit(sub, base, prototype) { + sub.prototype = Object.create(base.prototype); + sub.prototype.constructor = sub; + for (var prop in prototype) { + sub.prototype[prop] = prototype[prop]; + } + }; + Util.loadScript = function Util_loadScript(src, callback) { + var script = document.createElement('script'); + var loaded = false; + script.setAttribute('src', src); + if (callback) { + script.onload = function () { + if (!loaded) { + callback(); + } + loaded = true; + }; + } + document.getElementsByTagName('head')[0].appendChild(script); + }; + return Util; + }(); + var PageViewport = function PageViewportClosure() { + function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) { + this.viewBox = viewBox; + this.scale = scale; + this.rotation = rotation; + this.offsetX = offsetX; + this.offsetY = offsetY; + var centerX = (viewBox[2] + viewBox[0]) / 2; + var centerY = (viewBox[3] + viewBox[1]) / 2; + var 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; + default: + rotateA = 1; + rotateB = 0; + rotateC = 0; + rotateD = -1; + break; + } + if (dontFlip) { + rotateC = -rotateC; + rotateD = -rotateD; + } + var offsetCanvasX, offsetCanvasY; + var 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; + this.fontScale = scale; + } + + PageViewport.prototype = { + clone: function PageViewPort_clone(args) { + args = args || {}; + var scale = 'scale' in args ? args.scale : this.scale; + var rotation = 'rotation' in args ? args.rotation : this.rotation; + return new PageViewport(this.viewBox.slice(), scale, rotation, this.offsetX, this.offsetY, args.dontFlip); + }, + convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) { + return Util.applyTransform([x, y], this.transform); + }, + convertToViewportRectangle: function PageViewport_convertToViewportRectangle(rect) { + var tl = Util.applyTransform([rect[0], rect[1]], this.transform); + var br = Util.applyTransform([rect[2], rect[3]], this.transform); + return [tl[0], tl[1], br[0], br[1]]; + }, + convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) { + return Util.applyInverseTransform([x, y], this.transform); + } + }; + return PageViewport; + }(); + var 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) { + var i, + n = str.length, + strBuf = []; + if (str[0] === '\xFE' && str[1] === '\xFF') { + for (i = 2; i < n; i += 2) { + strBuf.push(String.fromCharCode(str.charCodeAt(i) << 8 | str.charCodeAt(i + 1))); + } + } else { + for (i = 0; i < n; ++i) { + var code = PDFStringTranslateTable[str.charCodeAt(i)]; + strBuf.push(code ? String.fromCharCode(code) : str.charAt(i)); + } + } + return strBuf.join(''); + } + + function stringToUTF8String(str) { + return decodeURIComponent(escape(str)); + } + + function utf8StringToString(str) { + return unescape(encodeURIComponent(str)); + } + + function isEmptyObj(obj) { + for (var key in obj) { + return false; + } + return true; + } + + function isBool(v) { + return typeof v === 'boolean'; + } + + function isInt(v) { + return typeof v === 'number' && (v | 0) === v; + } + + function isNum(v) { + return typeof v === 'number'; + } + + function isString(v) { + return typeof v === 'string'; + } + + function isArray(v) { + return v instanceof Array; + } + + function isArrayBuffer(v) { + return (typeof v === 'undefined' ? 'undefined' : _typeof(v)) === 'object' && v !== null && v.byteLength !== undefined; + } + + function isSpace(ch) { + return ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A; + } + + function isNodeJS() { + return (typeof process === 'undefined' ? 'undefined' : _typeof(process)) === 'object' && process + '' === '[object process]'; + } + + function createPromiseCapability() { + var capability = {}; + capability.promise = new Promise(function (resolve, reject) { + capability.resolve = resolve; + capability.reject = reject; + }); + return capability; + } + + var StatTimer = function StatTimerClosure() { + function rpad(str, pad, length) { + while (str.length < length) { + str += pad; + } + return str; + } + + function StatTimer() { + this.started = Object.create(null); + this.times = []; + this.enabled = true; + } + + StatTimer.prototype = { + time: function StatTimer_time(name) { + if (!this.enabled) { + return; + } + if (name in this.started) { + warn('Timer is already running for ' + name); + } + this.started[name] = Date.now(); + }, + timeEnd: function StatTimer_timeEnd(name) { + if (!this.enabled) { + return; + } + if (!(name in this.started)) { + warn('Timer has not been started for ' + name); + } + this.times.push({ + 'name': name, + 'start': this.started[name], + 'end': Date.now() + }); + delete this.started[name]; + }, + toString: function StatTimer_toString() { + var i, ii; + var times = this.times; + var out = ''; + var longest = 0; + for (i = 0, ii = times.length; i < ii; ++i) { + var name = times[i]['name']; + if (name.length > longest) { + longest = name.length; + } + } + for (i = 0, ii = times.length; i < ii; ++i) { + var span = times[i]; + var duration = span.end - span.start; + out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n'; + } + return out; + } + }; + return StatTimer; + }(); + var createBlob = function createBlob(data, contentType) { + if (typeof Blob !== 'undefined') { + return new Blob([data], {type: contentType}); + } + throw new Error('The "Blob" constructor is not supported.'); + }; + var createObjectURL = function createObjectURLClosure() { + var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + return function createObjectURL(data, contentType) { + var forceDataSchema = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + + if (!forceDataSchema && URL.createObjectURL) { + var blob = createBlob(data, contentType); + return URL.createObjectURL(blob); + } + var buffer = 'data:' + contentType + ';base64,'; + for (var i = 0, ii = data.length; i < ii; i += 3) { + var b1 = data[i] & 0xFF; + var b2 = data[i + 1] & 0xFF; + var b3 = data[i + 2] & 0xFF; + var d1 = b1 >> 2, + d2 = (b1 & 3) << 4 | b2 >> 4; + var d3 = i + 1 < ii ? (b2 & 0xF) << 2 | b3 >> 6 : 64; + var d4 = i + 2 < ii ? b3 & 0x3F : 64; + buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4]; + } + return buffer; + }; + }(); + + function resolveCall(fn, args) { + var thisArg = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + + if (!fn) { + return Promise.resolve(undefined); + } + return new Promise(function (resolve, reject) { + resolve(fn.apply(thisArg, args)); + }); + } + + function wrapReason(reason) { + if ((typeof reason === 'undefined' ? 'undefined' : _typeof(reason)) !== 'object') { + return reason; + } + switch (reason.name) { + case 'AbortException': + return new AbortException(reason.message); + case 'MissingPDFException': + return new MissingPDFException(reason.message); + case 'UnexpectedResponseException': + return new UnexpectedResponseException(reason.message, reason.status); + default: + return new UnknownErrorException(reason.message, reason.details); + } + } + + function resolveOrReject(capability, success, reason) { + if (success) { + capability.resolve(); + } else { + capability.reject(reason); + } + } + + function finalize(promise) { + return Promise.resolve(promise).catch(function () { + }); + } + + function MessageHandler(sourceName, targetName, comObj) { + var _this = this; + + this.sourceName = sourceName; + this.targetName = targetName; + this.comObj = comObj; + this.callbackId = 1; + this.streamId = 1; + this.postMessageTransfers = true; + this.streamSinks = Object.create(null); + this.streamControllers = Object.create(null); + var callbacksCapabilities = this.callbacksCapabilities = Object.create(null); + var ah = this.actionHandler = Object.create(null); + this._onComObjOnMessage = function (event) { + var data = event.data; + if (data.targetName !== _this.sourceName) { + return; + } + if (data.stream) { + _this._processStreamMessage(data); + } else if (data.isReply) { + var callbackId = data.callbackId; + if (data.callbackId in callbacksCapabilities) { + var callback = callbacksCapabilities[callbackId]; + delete callbacksCapabilities[callbackId]; + if ('error' in data) { + callback.reject(wrapReason(data.error)); + } else { + callback.resolve(data.data); + } + } else { + throw new Error('Cannot resolve callback ' + callbackId); + } + } else if (data.action in ah) { + var action = ah[data.action]; + if (data.callbackId) { + var _sourceName = _this.sourceName; + var _targetName = data.sourceName; + Promise.resolve().then(function () { + return action[0].call(action[1], data.data); + }).then(function (result) { + comObj.postMessage({ + sourceName: _sourceName, + targetName: _targetName, + isReply: true, + callbackId: data.callbackId, + data: result + }); + }, function (reason) { + if (reason instanceof Error) { + reason = reason + ''; + } + comObj.postMessage({ + sourceName: _sourceName, + targetName: _targetName, + isReply: true, + callbackId: data.callbackId, + error: reason + }); + }); + } else if (data.streamId) { + _this._createStreamSink(data); + } else { + action[0].call(action[1], data.data); + } + } else { + throw new Error('Unknown action from worker: ' + data.action); + } + }; + comObj.addEventListener('message', this._onComObjOnMessage); + } + + MessageHandler.prototype = { + on: function on(actionName, handler, scope) { + var ah = this.actionHandler; + if (ah[actionName]) { + throw new Error('There is already an actionName called "' + actionName + '"'); + } + ah[actionName] = [handler, scope]; + }, + send: function send(actionName, data, transfers) { + var message = { + sourceName: this.sourceName, + targetName: this.targetName, + action: actionName, + data: data + }; + this.postMessage(message, transfers); + }, + sendWithPromise: function sendWithPromise(actionName, data, transfers) { + var callbackId = this.callbackId++; + var message = { + sourceName: this.sourceName, + targetName: this.targetName, + action: actionName, + data: data, + callbackId: callbackId + }; + var capability = createPromiseCapability(); + this.callbacksCapabilities[callbackId] = capability; + try { + this.postMessage(message, transfers); + } catch (e) { + capability.reject(e); + } + return capability.promise; + }, + sendWithStream: function sendWithStream(actionName, data, queueingStrategy, transfers) { + var _this2 = this; + + var streamId = this.streamId++; + var sourceName = this.sourceName; + var targetName = this.targetName; + return new _streams_polyfill.ReadableStream({ + start: function start(controller) { + var startCapability = createPromiseCapability(); + _this2.streamControllers[streamId] = { + controller: controller, + startCall: startCapability, + isClosed: false + }; + _this2.postMessage({ + sourceName: sourceName, + targetName: targetName, + action: actionName, + streamId: streamId, + data: data, + desiredSize: controller.desiredSize + }); + return startCapability.promise; + }, + pull: function pull(controller) { + var pullCapability = createPromiseCapability(); + _this2.streamControllers[streamId].pullCall = pullCapability; + _this2.postMessage({ + sourceName: sourceName, + targetName: targetName, + stream: 'pull', + streamId: streamId, + desiredSize: controller.desiredSize + }); + return pullCapability.promise; + }, + cancel: function cancel(reason) { + var cancelCapability = createPromiseCapability(); + _this2.streamControllers[streamId].cancelCall = cancelCapability; + _this2.streamControllers[streamId].isClosed = true; + _this2.postMessage({ + sourceName: sourceName, + targetName: targetName, + stream: 'cancel', + reason: reason, + streamId: streamId + }); + return cancelCapability.promise; + } + }, queueingStrategy); + }, + _createStreamSink: function _createStreamSink(data) { + var _this3 = this; + + var self = this; + var action = this.actionHandler[data.action]; + var streamId = data.streamId; + var desiredSize = data.desiredSize; + var sourceName = this.sourceName; + var targetName = data.sourceName; + var capability = createPromiseCapability(); + var sendStreamRequest = function sendStreamRequest(_ref) { + var stream = _ref.stream, + chunk = _ref.chunk, + transfers = _ref.transfers, + success = _ref.success, + reason = _ref.reason; + + _this3.postMessage({ + sourceName: sourceName, + targetName: targetName, + stream: stream, + streamId: streamId, + chunk: chunk, + success: success, + reason: reason + }, transfers); + }; + var streamSink = { + enqueue: function enqueue(chunk) { + var size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; + var transfers = arguments[2]; + + if (this.isCancelled) { + return; + } + var lastDesiredSize = this.desiredSize; + this.desiredSize -= size; + if (lastDesiredSize > 0 && this.desiredSize <= 0) { + this.sinkCapability = createPromiseCapability(); + this.ready = this.sinkCapability.promise; + } + sendStreamRequest({ + stream: 'enqueue', + chunk: chunk, + transfers: transfers + }); + }, + close: function close() { + if (this.isCancelled) { + return; + } + sendStreamRequest({stream: 'close'}); + delete self.streamSinks[streamId]; + }, + error: function error(reason) { + if (this.isCancelled) { + return; + } + this.isCancelled = true; + sendStreamRequest({ + stream: 'error', + reason: reason + }); + }, + + sinkCapability: capability, + onPull: null, + onCancel: null, + isCancelled: false, + desiredSize: desiredSize, + ready: null + }; + streamSink.sinkCapability.resolve(); + streamSink.ready = streamSink.sinkCapability.promise; + this.streamSinks[streamId] = streamSink; + resolveCall(action[0], [data.data, streamSink], action[1]).then(function () { + sendStreamRequest({ + stream: 'start_complete', + success: true + }); + }, function (reason) { + sendStreamRequest({ + stream: 'start_complete', + success: false, + reason: reason + }); + }); + }, + _processStreamMessage: function _processStreamMessage(data) { + var _this4 = this; + + var sourceName = this.sourceName; + var targetName = data.sourceName; + var streamId = data.streamId; + var sendStreamResponse = function sendStreamResponse(_ref2) { + var stream = _ref2.stream, + success = _ref2.success, + reason = _ref2.reason; + + _this4.comObj.postMessage({ + sourceName: sourceName, + targetName: targetName, + stream: stream, + success: success, + streamId: streamId, + reason: reason + }); + }; + var deleteStreamController = function deleteStreamController() { + Promise.all([_this4.streamControllers[data.streamId].startCall, _this4.streamControllers[data.streamId].pullCall, _this4.streamControllers[data.streamId].cancelCall].map(function (capability) { + return capability && finalize(capability.promise); + })).then(function () { + delete _this4.streamControllers[data.streamId]; + }); + }; + switch (data.stream) { + case 'start_complete': + resolveOrReject(this.streamControllers[data.streamId].startCall, data.success, wrapReason(data.reason)); + break; + case 'pull_complete': + resolveOrReject(this.streamControllers[data.streamId].pullCall, data.success, wrapReason(data.reason)); + break; + case 'pull': + if (!this.streamSinks[data.streamId]) { + sendStreamResponse({ + stream: 'pull_complete', + success: true + }); + break; + } + if (this.streamSinks[data.streamId].desiredSize <= 0 && data.desiredSize > 0) { + this.streamSinks[data.streamId].sinkCapability.resolve(); + } + this.streamSinks[data.streamId].desiredSize = data.desiredSize; + resolveCall(this.streamSinks[data.streamId].onPull).then(function () { + sendStreamResponse({ + stream: 'pull_complete', + success: true + }); + }, function (reason) { + sendStreamResponse({ + stream: 'pull_complete', + success: false, + reason: reason + }); + }); + break; + case 'enqueue': + assert(this.streamControllers[data.streamId], 'enqueue should have stream controller'); + if (!this.streamControllers[data.streamId].isClosed) { + this.streamControllers[data.streamId].controller.enqueue(data.chunk); + } + break; + case 'close': + assert(this.streamControllers[data.streamId], 'close should have stream controller'); + if (this.streamControllers[data.streamId].isClosed) { + break; + } + this.streamControllers[data.streamId].isClosed = true; + this.streamControllers[data.streamId].controller.close(); + deleteStreamController(); + break; + case 'error': + assert(this.streamControllers[data.streamId], 'error should have stream controller'); + this.streamControllers[data.streamId].controller.error(wrapReason(data.reason)); + deleteStreamController(); + break; + case 'cancel_complete': + resolveOrReject(this.streamControllers[data.streamId].cancelCall, data.success, wrapReason(data.reason)); + deleteStreamController(); + break; + case 'cancel': + if (!this.streamSinks[data.streamId]) { + break; + } + resolveCall(this.streamSinks[data.streamId].onCancel, [wrapReason(data.reason)]).then(function () { + sendStreamResponse({ + stream: 'cancel_complete', + success: true + }); + }, function (reason) { + sendStreamResponse({ + stream: 'cancel_complete', + success: false, + reason: reason + }); + }); + this.streamSinks[data.streamId].sinkCapability.reject(wrapReason(data.reason)); + this.streamSinks[data.streamId].isCancelled = true; + delete this.streamSinks[data.streamId]; + break; + default: + throw new Error('Unexpected stream case'); + } + }, + postMessage: function postMessage(message, transfers) { + if (transfers && this.postMessageTransfers) { + this.comObj.postMessage(message, transfers); + } else { + this.comObj.postMessage(message); + } + }, + destroy: function destroy() { + this.comObj.removeEventListener('message', this._onComObjOnMessage); + } + }; + + function loadJpegStream(id, imageUrl, objs) { + var img = new Image(); + img.onload = function loadJpegStream_onloadClosure() { + objs.resolve(id, img); + }; + img.onerror = function loadJpegStream_onerrorClosure() { + objs.resolve(id, null); + warn('Error during JPEG image loading'); + }; + img.src = imageUrl; + } + + exports.FONT_IDENTITY_MATRIX = FONT_IDENTITY_MATRIX; + exports.IDENTITY_MATRIX = IDENTITY_MATRIX; + exports.OPS = OPS; + exports.VERBOSITY_LEVELS = VERBOSITY_LEVELS; + exports.UNSUPPORTED_FEATURES = UNSUPPORTED_FEATURES; + exports.AnnotationBorderStyleType = AnnotationBorderStyleType; + exports.AnnotationFieldFlag = AnnotationFieldFlag; + exports.AnnotationFlag = AnnotationFlag; + exports.AnnotationType = AnnotationType; + exports.FontType = FontType; + exports.ImageKind = ImageKind; + exports.CMapCompressionType = CMapCompressionType; + exports.AbortException = AbortException; + exports.InvalidPDFException = InvalidPDFException; + exports.MessageHandler = MessageHandler; + exports.MissingDataException = MissingDataException; + exports.MissingPDFException = MissingPDFException; + exports.NativeImageDecoding = NativeImageDecoding; + exports.NotImplementedException = NotImplementedException; + exports.PageViewport = PageViewport; + exports.PasswordException = PasswordException; + exports.PasswordResponses = PasswordResponses; + exports.StatTimer = StatTimer; + exports.StreamType = StreamType; + exports.TextRenderingMode = TextRenderingMode; + exports.UnexpectedResponseException = UnexpectedResponseException; + exports.UnknownErrorException = UnknownErrorException; + exports.Util = Util; + exports.XRefParseException = XRefParseException; + exports.FormatError = FormatError; + exports.arrayByteLength = arrayByteLength; + exports.arraysToBytes = arraysToBytes; + exports.assert = assert; + exports.bytesToString = bytesToString; + exports.createBlob = createBlob; + exports.createPromiseCapability = createPromiseCapability; + exports.createObjectURL = createObjectURL; + exports.deprecated = deprecated; + exports.getLookupTableFactory = getLookupTableFactory; + exports.getVerbosityLevel = getVerbosityLevel; + exports.globalScope = globalScope; + exports.info = info; + exports.isArray = isArray; + exports.isArrayBuffer = isArrayBuffer; + exports.isBool = isBool; + exports.isEmptyObj = isEmptyObj; + exports.isInt = isInt; + exports.isNum = isNum; + exports.isString = isString; + exports.isSpace = isSpace; + exports.isNodeJS = isNodeJS; + exports.isSameOrigin = isSameOrigin; + exports.createValidAbsoluteUrl = createValidAbsoluteUrl; + exports.isLittleEndian = isLittleEndian; + exports.isEvalSupported = isEvalSupported; + exports.loadJpegStream = loadJpegStream; + exports.log2 = log2; + exports.readInt8 = readInt8; + exports.readUint16 = readUint16; + exports.readUint32 = readUint32; + exports.removeNullCharacters = removeNullCharacters; + exports.ReadableStream = _streams_polyfill.ReadableStream; + exports.setVerbosityLevel = setVerbosityLevel; + exports.shadow = shadow; + exports.string32 = string32; + exports.stringToBytes = stringToBytes; + exports.stringToPDFString = stringToPDFString; + exports.stringToUTF8String = stringToUTF8String; + exports.utf8StringToString = utf8StringToString; + exports.warn = warn; + exports.unreachable = unreachable; + + /***/ + }), + /* 1 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.isStream = exports.isRefsEqual = exports.isRef = exports.isName = exports.isDict = exports.isCmd = exports.isEOF = exports.RefSetCache = exports.RefSet = exports.Ref = exports.Name = exports.Dict = exports.Cmd = exports.EOF = undefined; + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + var _util = __w_pdfjs_require__(0); + + var EOF = {}; + var Name = function NameClosure() { + function Name(name) { + this.name = name; + } + + Name.prototype = {}; + var nameCache = Object.create(null); + Name.get = function Name_get(name) { + var nameValue = nameCache[name]; + return nameValue ? nameValue : nameCache[name] = new Name(name); + }; + return Name; + }(); + var Cmd = function CmdClosure() { + function Cmd(cmd) { + this.cmd = cmd; + } + + Cmd.prototype = {}; + var cmdCache = Object.create(null); + Cmd.get = function Cmd_get(cmd) { + var cmdValue = cmdCache[cmd]; + return cmdValue ? cmdValue : cmdCache[cmd] = new Cmd(cmd); + }; + return Cmd; + }(); + var Dict = function DictClosure() { + var nonSerializable = function nonSerializableClosure() { + return nonSerializable; + }; + + function Dict(xref) { + this._map = Object.create(null); + this.xref = xref; + this.objId = null; + this.suppressEncryption = false; + this.__nonSerializable__ = nonSerializable; + } + + Dict.prototype = { + assignXref: function Dict_assignXref(newXref) { + this.xref = newXref; + }, + get: function Dict_get(key1, key2, key3) { + var value; + var xref = this.xref, + suppressEncryption = this.suppressEncryption; + if (typeof (value = this._map[key1]) !== 'undefined' || key1 in this._map || typeof key2 === 'undefined') { + return xref ? xref.fetchIfRef(value, suppressEncryption) : value; + } + if (typeof (value = this._map[key2]) !== 'undefined' || key2 in this._map || typeof key3 === 'undefined') { + return xref ? xref.fetchIfRef(value, suppressEncryption) : value; + } + value = this._map[key3] || null; + return xref ? xref.fetchIfRef(value, suppressEncryption) : value; + }, + getAsync: function Dict_getAsync(key1, key2, key3) { + var value; + var xref = this.xref, + suppressEncryption = this.suppressEncryption; + if (typeof (value = this._map[key1]) !== 'undefined' || key1 in this._map || typeof key2 === 'undefined') { + if (xref) { + return xref.fetchIfRefAsync(value, suppressEncryption); + } + return Promise.resolve(value); + } + if (typeof (value = this._map[key2]) !== 'undefined' || key2 in this._map || typeof key3 === 'undefined') { + if (xref) { + return xref.fetchIfRefAsync(value, suppressEncryption); + } + return Promise.resolve(value); + } + value = this._map[key3] || null; + if (xref) { + return xref.fetchIfRefAsync(value, suppressEncryption); + } + return Promise.resolve(value); + }, + getArray: function Dict_getArray(key1, key2, key3) { + var value = this.get(key1, key2, key3); + var xref = this.xref, + suppressEncryption = this.suppressEncryption; + if (!(0, _util.isArray)(value) || !xref) { + return value; + } + value = value.slice(); + for (var i = 0, ii = value.length; i < ii; i++) { + if (!isRef(value[i])) { + continue; + } + value[i] = xref.fetch(value[i], suppressEncryption); + } + return value; + }, + getRaw: function Dict_getRaw(key) { + return this._map[key]; + }, + getKeys: function Dict_getKeys() { + return Object.keys(this._map); + }, + set: function Dict_set(key, value) { + this._map[key] = value; + }, + has: function Dict_has(key) { + return key in this._map; + }, + forEach: function Dict_forEach(callback) { + for (var key in this._map) { + callback(key, this.get(key)); + } + } + }; + Dict.empty = new Dict(null); + Dict.merge = function (xref, dictArray) { + var mergedDict = new Dict(xref); + for (var i = 0, ii = dictArray.length; i < ii; i++) { + var dict = dictArray[i]; + if (!isDict(dict)) { + continue; + } + for (var keyName in dict._map) { + if (mergedDict._map[keyName] !== undefined) { + continue; + } + mergedDict._map[keyName] = dict._map[keyName]; + } + } + return mergedDict; + }; + return Dict; + }(); + var Ref = function RefClosure() { + function Ref(num, gen) { + this.num = num; + this.gen = gen; + } + + Ref.prototype = { + toString: function Ref_toString() { + var str = this.num + 'R'; + if (this.gen !== 0) { + str += this.gen; + } + return str; + } + }; + return Ref; + }(); + var RefSet = function RefSetClosure() { + function RefSet() { + this.dict = Object.create(null); + } + + RefSet.prototype = { + has: function RefSet_has(ref) { + return ref.toString() in this.dict; + }, + put: function RefSet_put(ref) { + this.dict[ref.toString()] = true; + }, + remove: function RefSet_remove(ref) { + delete this.dict[ref.toString()]; + } + }; + return RefSet; + }(); + var RefSetCache = function RefSetCacheClosure() { + function RefSetCache() { + this.dict = Object.create(null); + } + + RefSetCache.prototype = { + get: function RefSetCache_get(ref) { + return this.dict[ref.toString()]; + }, + has: function RefSetCache_has(ref) { + return ref.toString() in this.dict; + }, + put: function RefSetCache_put(ref, obj) { + this.dict[ref.toString()] = obj; + }, + putAlias: function RefSetCache_putAlias(ref, aliasRef) { + this.dict[ref.toString()] = this.get(aliasRef); + }, + forEach: function RefSetCache_forEach(fn, thisArg) { + for (var i in this.dict) { + fn.call(thisArg, this.dict[i]); + } + }, + clear: function RefSetCache_clear() { + this.dict = Object.create(null); + } + }; + return RefSetCache; + }(); + + function isEOF(v) { + return v === EOF; + } + + function isName(v, name) { + return v instanceof Name && (name === undefined || v.name === name); + } + + function isCmd(v, cmd) { + return v instanceof Cmd && (cmd === undefined || v.cmd === cmd); + } + + 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 === 'undefined' ? 'undefined' : _typeof(v)) === 'object' && v !== null && v.getBytes !== undefined; + } + + exports.EOF = EOF; + exports.Cmd = Cmd; + exports.Dict = Dict; + exports.Name = Name; + exports.Ref = Ref; + exports.RefSet = RefSet; + exports.RefSetCache = RefSetCache; + exports.isEOF = isEOF; + exports.isCmd = isCmd; + exports.isDict = isDict; + exports.isName = isName; + exports.isRef = isRef; + exports.isRefsEqual = isRefsEqual; + exports.isStream = isStream; + + /***/ + }), + /* 2 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.LZWStream = exports.StringStream = exports.StreamsSequenceStream = exports.Stream = exports.RunLengthStream = exports.PredictorStream = exports.NullStream = exports.JpxStream = exports.JpegStream = exports.Jbig2Stream = exports.FlateStream = exports.DecodeStream = exports.DecryptStream = exports.CCITTFaxStream = exports.AsciiHexStream = exports.Ascii85Stream = undefined; + + var _util = __w_pdfjs_require__(0); + + var _primitives = __w_pdfjs_require__(1); + + var _jbig = __w_pdfjs_require__(27); + + var _jpg = __w_pdfjs_require__(28); + + var _jpx = __w_pdfjs_require__(14); + + 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: function Stream_getBytes(length) { + var bytes = this.bytes; + var pos = this.pos; + var strEnd = this.end; + if (!length) { + return bytes.subarray(pos, strEnd); + } + var end = pos + length; + if (end > strEnd) { + end = strEnd; + } + this.pos = end; + return bytes.subarray(pos, end); + }, + peekByte: function Stream_peekByte() { + var peekedByte = this.getByte(); + this.pos--; + return peekedByte; + }, + peekBytes: function Stream_peekBytes(length) { + var bytes = this.getBytes(length); + this.pos -= bytes.length; + return bytes; + }, + 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; + }(); + var StringStream = function StringStreamClosure() { + function StringStream(str) { + var length = str.length; + var bytes = new Uint8Array(length); + for (var n = 0; n < length; ++n) { + bytes[n] = str.charCodeAt(n); + } + Stream.call(this, bytes); + } + + StringStream.prototype = Stream.prototype; + return StringStream; + }(); + var DecodeStream = function DecodeStreamClosure() { + var emptyBuffer = new Uint8Array(0); + + function DecodeStream(maybeMinBufferLength) { + this.pos = 0; + this.bufferLength = 0; + this.eof = false; + this.buffer = emptyBuffer; + this.minBufferLength = 512; + if (maybeMinBufferLength) { + while (this.minBufferLength < maybeMinBufferLength) { + this.minBufferLength *= 2; + } + } + } + + DecodeStream.prototype = { + get isEmpty() { + while (!this.eof && this.bufferLength === 0) { + this.readBlock(); + } + return this.bufferLength === 0; + }, + ensureBuffer: function DecodeStream_ensureBuffer(requested) { + var buffer = this.buffer; + if (requested <= buffer.byteLength) { + return buffer; + } + 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: function DecodeStream_getBytes(length) { + 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; + } + } else { + while (!this.eof) { + this.readBlock(); + } + end = this.bufferLength; + } + this.pos = end; + return this.buffer.subarray(pos, end); + }, + peekByte: function DecodeStream_peekByte() { + var peekedByte = this.getByte(); + this.pos--; + return peekedByte; + }, + peekBytes: function DecodeStream_peekBytes(length) { + var bytes = this.getBytes(length); + 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); + }, + 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; + }(); + var StreamsSequenceStream = function StreamsSequenceStreamClosure() { + function StreamsSequenceStream(streams) { + this.streams = streams; + DecodeStream.call(this, null); + } + + StreamsSequenceStream.prototype = Object.create(DecodeStream.prototype); + StreamsSequenceStream.prototype.readBlock = function streamSequenceStreamReadBlock() { + var streams = this.streams; + 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) { + _util.Util.appendToArray(baseStreams, stream.getBaseStreams()); + } + } + return baseStreams; + }; + return 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'); + } + codeBuf |= b << codeSize; + codeSize += 8; + } + 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; + var bufferLength = this.bufferLength; + buffer = this.ensureBuffer(bufferLength + blockLen); + var end = bufferLength + blockLen; + this.bufferLength = end; + if (blockLen === 0) { + if (str.peekByte() === -1) { + this.eof = true; + } + } else { + for (var n = bufferLength; n < end; ++n) { + if ((b = str.getByte()) === -1) { + this.eof = true; + break; + } + buffer[n] = b; + } + } + 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; + }(); + 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 { + 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; + }(); + var JpegStream = function JpegStreamClosure() { + function JpegStream(stream, maybeLength, dict, params) { + var 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; + DecodeStream.call(this, maybeLength); + } + + JpegStream.prototype = Object.create(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 JpegStream_ensureBuffer(req) { + if (this.bufferLength) { + return; + } + var jpegImage = new _jpg.JpegImage(); + var decodeArr = this.dict.getArray('Decode', 'D'); + if (this.forceRGB && (0, _util.isArray)(decodeArr)) { + var bitsPerComponent = this.dict.get('BitsPerComponent') || 8; + var decodeArrLength = decodeArr.length; + var transform = new Int32Array(decodeArrLength); + var transformNeeded = false; + var maxValue = (1 << bitsPerComponent) - 1; + for (var 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) { + jpegImage.decodeTransform = transform; + } + } + if ((0, _primitives.isDict)(this.params)) { + var colorTransform = this.params.get('ColorTransform'); + if ((0, _util.isInt)(colorTransform)) { + jpegImage.colorTransform = colorTransform; + } + } + jpegImage.parse(this.bytes); + var data = jpegImage.getData(this.drawWidth, this.drawHeight, this.forceRGB); + this.buffer = data; + this.bufferLength = data.length; + this.eof = true; + }; + JpegStream.prototype.getBytes = function JpegStream_getBytes(length) { + this.ensureBuffer(); + return this.buffer; + }; + JpegStream.prototype.getIR = function JpegStream_getIR(forceDataSchema) { + return (0, _util.createObjectURL)(this.bytes, 'image/jpeg', forceDataSchema); + }; + return JpegStream; + }(); + var JpxStream = function JpxStreamClosure() { + function JpxStream(stream, maybeLength, dict, params) { + this.stream = stream; + this.maybeLength = maybeLength; + this.dict = dict; + this.params = params; + DecodeStream.call(this, maybeLength); + } + + JpxStream.prototype = Object.create(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 JpxStream_ensureBuffer(req) { + if (this.bufferLength) { + return; + } + var jpxImage = new _jpx.JpxImage(); + jpxImage.parse(this.bytes); + var width = jpxImage.width; + var height = jpxImage.height; + var componentsCount = jpxImage.componentsCount; + var tileCount = jpxImage.tiles.length; + if (tileCount === 1) { + this.buffer = jpxImage.tiles[0].items; + } else { + var data = new Uint8Array(width * height * componentsCount); + for (var k = 0; k < tileCount; k++) { + var tileComponents = jpxImage.tiles[k]; + var tileWidth = tileComponents.width; + var tileHeight = tileComponents.height; + var tileLeft = tileComponents.left; + var tileTop = tileComponents.top; + var src = tileComponents.items; + var srcPosition = 0; + var dataPosition = (width * tileTop + tileLeft) * componentsCount; + var imgRowSize = width * componentsCount; + var tileRowSize = tileWidth * componentsCount; + for (var j = 0; j < tileHeight; j++) { + var 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; + }(); + var Jbig2Stream = function Jbig2StreamClosure() { + function Jbig2Stream(stream, maybeLength, dict, params) { + this.stream = stream; + this.maybeLength = maybeLength; + this.dict = dict; + this.params = params; + DecodeStream.call(this, maybeLength); + } + + Jbig2Stream.prototype = Object.create(DecodeStream.prototype); + Object.defineProperty(Jbig2Stream.prototype, 'bytes', { + get: function Jbig2Stream_bytes() { + return (0, _util.shadow)(this, 'bytes', this.stream.getBytes(this.maybeLength)); + }, + configurable: true + }); + Jbig2Stream.prototype.ensureBuffer = function Jbig2Stream_ensureBuffer(req) { + if (this.bufferLength) { + return; + } + var jbig2Image = new _jbig.Jbig2Image(); + var chunks = []; + if ((0, _primitives.isDict)(this.params)) { + var globalsStream = this.params.get('JBIG2Globals'); + if ((0, _primitives.isStream)(globalsStream)) { + var globals = globalsStream.getBytes(); + chunks.push({ + data: globals, + start: 0, + end: globals.length + }); + } + } + chunks.push({ + data: this.bytes, + start: 0, + end: this.bytes.length + }); + var data = jbig2Image.parseChunks(chunks); + var dataLength = data.length; + for (var i = 0; i < dataLength; i++) { + data[i] ^= 0xFF; + } + this.buffer = data; + this.bufferLength = dataLength; + this.eof = true; + }; + return Jbig2Stream; + }(); + 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; + }(); + 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, _util.isSpace)(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, _util.isSpace)(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; + }(); + 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; + }(); + 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; + }(); + var CCITTFaxStream = function CCITTFaxStreamClosure() { + var ccittEOL = -2; + var ccittEOF = -1; + var twoDimPass = 0; + var twoDimHoriz = 1; + var twoDimVert0 = 2; + var twoDimVertR1 = 3; + var twoDimVertL1 = 4; + var twoDimVertR2 = 5; + var twoDimVertL2 = 6; + var twoDimVertR3 = 7; + var twoDimVertL3 = 8; + var 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]]; + var 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]]; + var 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]]; + var 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]]; + var 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]]; + var 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 CCITTFaxStream(str, maybeLength, params) { + this.str = str; + this.dict = str.dict; + params = params || _primitives.Dict.empty; + this.encoding = params.get('K') || 0; + this.eoline = params.get('EndOfLine') || false; + this.byteAlign = params.get('EncodedByteAlign') || false; + this.columns = params.get('Columns') || 1728; + this.rows = params.get('Rows') || 0; + var eoblock = params.get('EndOfBlock'); + if (eoblock === null || eoblock === undefined) { + eoblock = true; + } + this.eoblock = eoblock; + this.black = params.get('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; + var 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); + } + DecodeStream.call(this, maybeLength); + } + + CCITTFaxStream.prototype = Object.create(DecodeStream.prototype); + CCITTFaxStream.prototype.readBlock = function CCITTFaxStream_readBlock() { + while (!this.eof) { + var c = this.lookChar(); + this.ensureBuffer(this.bufferLength + 1); + this.buffer[this.bufferLength++] = c; + } + }; + CCITTFaxStream.prototype.addPixels = function ccittFaxStreamAddPixels(a1, blackPixels) { + var codingLine = this.codingLine; + var 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; + }; + CCITTFaxStream.prototype.addPixelsNeg = function ccittFaxStreamAddPixelsNeg(a1, blackPixels) { + var codingLine = this.codingLine; + var 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; + }; + CCITTFaxStream.prototype.lookChar = function CCITTFaxStream_lookChar() { + var refLine = this.refLine; + var codingLine = this.codingLine; + var columns = this.columns; + var refPos, blackPixels, bits, i; + if (this.outputBits === 0) { + if (this.eof) { + return null; + } + this.err = false; + var 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; + } + } + var gotEOL = false; + if (this.byteAlign) { + this.inputBits &= ~7; + } + if (!this.eoblock && this.row === this.rows - 1) { + this.eof = 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.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 null; + } + 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++; + } + var 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; + }; + CCITTFaxStream.prototype.findTableCode = function ccittFaxStreamFindTableCode(start, end, table, limit) { + var limitValue = limit || 0; + for (var i = start; i <= end; ++i) { + var code = this.lookBits(i); + if (code === ccittEOF) { + return [true, 1, false]; + } + if (i < end) { + code <<= end - i; + } + if (!limitValue || code >= limitValue) { + var p = table[code - limitValue]; + if (p[0] === i) { + this.eatBits(i); + return [true, p[1], true]; + } + } + } + return [false, 0, false]; + }; + CCITTFaxStream.prototype.getTwoDimCode = function ccittFaxStreamGetTwoDimCode() { + var code = 0; + var p; + if (this.eoblock) { + code = this.lookBits(7); + p = twoDimTable[code]; + if (p && p[0] > 0) { + this.eatBits(p[0]); + return p[1]; + } + } else { + var result = this.findTableCode(1, 7, twoDimTable); + if (result[0] && result[2]) { + return result[1]; + } + } + (0, _util.info)('Bad two dim code'); + return ccittEOF; + }; + CCITTFaxStream.prototype.getWhiteCode = function ccittFaxStreamGetWhiteCode() { + var code = 0; + var 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 { + var 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; + }; + CCITTFaxStream.prototype.getBlackCode = function ccittFaxStreamGetBlackCode() { + var 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 { + var 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; + }; + CCITTFaxStream.prototype.lookBits = function CCITTFaxStream_lookBits(n) { + var c; + while (this.inputBits < n) { + if ((c = this.str.getByte()) === -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; + }; + CCITTFaxStream.prototype.eatBits = function CCITTFaxStream_eatBits(n) { + if ((this.inputBits -= n) < 0) { + this.inputBits = 0; + } + }; + return CCITTFaxStream; + }(); + 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: earlyChange, + codeLength: 9, + nextCode: 258, + dictionaryValues: new Uint8Array(maxLzwDictionarySize), + dictionaryLengths: new Uint16Array(maxLzwDictionarySize), + dictionaryPrevCodes: new Uint16Array(maxLzwDictionarySize), + currentSequence: new Uint8Array(maxLzwDictionarySize), + currentSequenceLength: 0 + }; + 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); + LZWStream.prototype.readBits = function LZWStream_readBits(n) { + var bitsCached = this.bitsCached; + var cachedData = this.cachedData; + while (bitsCached < n) { + var 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; + }; + LZWStream.prototype.readBlock = function LZWStream_readBlock() { + var blockSize = 512; + var estimatedDecodedSize = blockSize * 2, + decodedSizeDelta = blockSize; + var i, j, q; + var lzwState = this.lzwState; + if (!lzwState) { + 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); + for (i = 0; i < blockSize; i++) { + var code = this.readBits(codeLength); + var 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; + }; + return LZWStream; + }(); + var NullStream = function NullStreamClosure() { + function NullStream() { + Stream.call(this, new Uint8Array(0)); + } + + NullStream.prototype = Stream.prototype; + return NullStream; + }(); + exports.Ascii85Stream = Ascii85Stream; + exports.AsciiHexStream = AsciiHexStream; + exports.CCITTFaxStream = CCITTFaxStream; + exports.DecryptStream = DecryptStream; + exports.DecodeStream = DecodeStream; + exports.FlateStream = FlateStream; + exports.Jbig2Stream = Jbig2Stream; + exports.JpegStream = JpegStream; + exports.JpxStream = JpxStream; + exports.NullStream = NullStream; + exports.PredictorStream = PredictorStream; + exports.RunLengthStream = RunLengthStream; + exports.Stream = Stream; + exports.StreamsSequenceStream = StreamsSequenceStream; + exports.StringStream = StringStream; + exports.LZWStream = LZWStream; + + /***/ + }), + /* 3 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.ColorSpace = undefined; + + var _util = __w_pdfjs_require__(0); + + var _primitives = __w_pdfjs_require__(1); + + var _function = __w_pdfjs_require__(7); + + var ColorSpace = function ColorSpaceClosure() { + function resizeRgbImage(src, bpc, w1, h1, w2, h2, alpha01, dest) { + var COMPONENTS = 3; + alpha01 = alpha01 !== 1 ? 0 : alpha01; + var xRatio = w1 / w2; + var yRatio = h1 / h2; + var i, + j, + py, + newIndex = 0, + oldIndex; + var xScaled = new Uint16Array(w2); + var w1Scanline = w1 * COMPONENTS; + for (i = 0; i < w2; i++) { + xScaled[i] = Math.floor(i * xRatio) * COMPONENTS; + } + for (i = 0; i < h2; i++) { + py = Math.floor(i * yRatio) * w1Scanline; + for (j = 0; j < w2; j++) { + oldIndex = py + xScaled[j]; + dest[newIndex++] = src[oldIndex++]; + dest[newIndex++] = src[oldIndex++]; + dest[newIndex++] = src[oldIndex++]; + newIndex += alpha01; + } + } + } + + function ColorSpace() { + throw new Error('should not call ColorSpace constructor'); + } + + ColorSpace.prototype = { + getRgb: function ColorSpace_getRgb(src, srcOffset) { + var rgb = new Uint8Array(3); + this.getRgbItem(src, srcOffset, rgb, 0); + return rgb; + }, + getRgbItem: function ColorSpace_getRgbItem(src, srcOffset, dest, destOffset) { + throw new Error('Should not call ColorSpace.getRgbItem'); + }, + getRgbBuffer: function ColorSpace_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + throw new Error('Should not call ColorSpace.getRgbBuffer'); + }, + getOutputLength: function ColorSpace_getOutputLength(inputLength, alpha01) { + throw new Error('Should not call ColorSpace.getOutputLength'); + }, + isPassthrough: function ColorSpace_isPassthrough(bits) { + return false; + }, + fillRgb: function ColorSpace_fillRgb(dest, originalWidth, originalHeight, width, height, actualHeight, bpc, comps, alpha01) { + var count = originalWidth * originalHeight; + var rgbBuf = null; + var numComponentColors = 1 << bpc; + var needsResizing = originalHeight !== height || originalWidth !== width; + var i, ii; + if (this.isPassthrough(bpc)) { + rgbBuf = comps; + } else if (this.numComps === 1 && count > numComponentColors && this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') { + var allColors = bpc <= 8 ? new Uint8Array(numComponentColors) : new Uint16Array(numComponentColors); + var key; + for (i = 0; i < numComponentColors; i++) { + allColors[i] = i; + } + var colorMap = new Uint8Array(numComponentColors * 3); + this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc, 0); + var destPos, rgbPos; + if (!needsResizing) { + destPos = 0; + for (i = 0; i < count; ++i) { + key = comps[i] * 3; + dest[destPos++] = colorMap[key]; + dest[destPos++] = colorMap[key + 1]; + dest[destPos++] = colorMap[key + 2]; + destPos += alpha01; + } + } else { + rgbBuf = new Uint8Array(count * 3); + rgbPos = 0; + for (i = 0; i < count; ++i) { + key = comps[i] * 3; + rgbBuf[rgbPos++] = colorMap[key]; + rgbBuf[rgbPos++] = colorMap[key + 1]; + rgbBuf[rgbPos++] = colorMap[key + 2]; + } + } + } else { + if (!needsResizing) { + this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc, alpha01); + } else { + rgbBuf = new Uint8Array(count * 3); + this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc, 0); + } + } + if (rgbBuf) { + if (needsResizing) { + resizeRgbImage(rgbBuf, bpc, originalWidth, originalHeight, width, height, alpha01, dest); + } else { + rgbPos = 0; + destPos = 0; + for (i = 0, ii = width * actualHeight; i < ii; i++) { + dest[destPos++] = rgbBuf[rgbPos++]; + dest[destPos++] = rgbBuf[rgbPos++]; + dest[destPos++] = rgbBuf[rgbPos++]; + destPos += alpha01; + } + } + } + }, + usesZeroToOneRange: true + }; + ColorSpace.parse = function ColorSpace_parse(cs, xref, res) { + var IR = ColorSpace.parseToIR(cs, xref, res); + if (IR instanceof AlternateCS) { + return IR; + } + return ColorSpace.fromIR(IR); + }; + ColorSpace.fromIR = function ColorSpace_fromIR(IR) { + var name = (0, _util.isArray)(IR) ? IR[0] : IR; + var whitePoint, blackPoint, gamma; + switch (name) { + case 'DeviceGrayCS': + return this.singletons.gray; + case 'DeviceRgbCS': + return this.singletons.rgb; + case 'DeviceCmykCS': + return this.singletons.cmyk; + case 'CalGrayCS': + whitePoint = IR[1]; + blackPoint = IR[2]; + gamma = IR[3]; + return new CalGrayCS(whitePoint, blackPoint, gamma); + case 'CalRGBCS': + whitePoint = IR[1]; + blackPoint = IR[2]; + gamma = IR[3]; + var matrix = IR[4]; + return new CalRGBCS(whitePoint, blackPoint, gamma, matrix); + case 'PatternCS': + var basePatternCS = IR[1]; + if (basePatternCS) { + basePatternCS = ColorSpace.fromIR(basePatternCS); + } + return new PatternCS(basePatternCS); + case 'IndexedCS': + var baseIndexedCS = IR[1]; + var hiVal = IR[2]; + var lookup = IR[3]; + return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup); + case 'AlternateCS': + var numComps = IR[1]; + var alt = IR[2]; + var tintFnIR = IR[3]; + return new AlternateCS(numComps, ColorSpace.fromIR(alt), _function.PDFFunction.fromIR(tintFnIR)); + case 'LabCS': + whitePoint = IR[1]; + blackPoint = IR[2]; + var range = IR[3]; + return new LabCS(whitePoint, blackPoint, range); + default: + throw new _util.FormatError('Unknown colorspace name: ' + name); + } + }; + ColorSpace.parseToIR = function ColorSpace_parseToIR(cs, xref, res) { + if ((0, _primitives.isName)(cs)) { + var colorSpaces = res.get('ColorSpace'); + if ((0, _primitives.isDict)(colorSpaces)) { + var refcs = colorSpaces.get(cs.name); + if (refcs) { + cs = refcs; + } + } + } + cs = xref.fetchIfRef(cs); + if ((0, _primitives.isName)(cs)) { + switch (cs.name) { + case 'DeviceGray': + case 'G': + return 'DeviceGrayCS'; + case 'DeviceRGB': + case 'RGB': + return 'DeviceRgbCS'; + case 'DeviceCMYK': + case 'CMYK': + return 'DeviceCmykCS'; + case 'Pattern': + return ['PatternCS', null]; + default: + throw new _util.FormatError('unrecognized colorspace ' + cs.name); + } + } + if ((0, _util.isArray)(cs)) { + var mode = xref.fetchIfRef(cs[0]).name; + var numComps, params, alt, whitePoint, blackPoint, gamma; + switch (mode) { + case 'DeviceGray': + case 'G': + return 'DeviceGrayCS'; + case 'DeviceRGB': + case 'RGB': + return 'DeviceRgbCS'; + case 'DeviceCMYK': + case 'CMYK': + return 'DeviceCmykCS'; + case 'CalGray': + params = xref.fetchIfRef(cs[1]); + whitePoint = params.getArray('WhitePoint'); + blackPoint = params.getArray('BlackPoint'); + gamma = params.get('Gamma'); + return ['CalGrayCS', whitePoint, blackPoint, gamma]; + case 'CalRGB': + params = xref.fetchIfRef(cs[1]); + whitePoint = params.getArray('WhitePoint'); + blackPoint = params.getArray('BlackPoint'); + gamma = params.getArray('Gamma'); + var matrix = params.getArray('Matrix'); + return ['CalRGBCS', whitePoint, blackPoint, gamma, matrix]; + case 'ICCBased': + var stream = xref.fetchIfRef(cs[1]); + var dict = stream.dict; + numComps = dict.get('N'); + alt = dict.get('Alternate'); + if (alt) { + var altIR = ColorSpace.parseToIR(alt, xref, res); + var altCS = ColorSpace.fromIR(altIR); + if (altCS.numComps === numComps) { + return altIR; + } + (0, _util.warn)('ICCBased color space: Ignoring incorrect /Alternate entry.'); + } + if (numComps === 1) { + return 'DeviceGrayCS'; + } else if (numComps === 3) { + return 'DeviceRgbCS'; + } else if (numComps === 4) { + return 'DeviceCmykCS'; + } + break; + case 'Pattern': + var basePatternCS = cs[1] || null; + if (basePatternCS) { + basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res); + } + return ['PatternCS', basePatternCS]; + case 'Indexed': + case 'I': + var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res); + var hiVal = xref.fetchIfRef(cs[2]) + 1; + var lookup = xref.fetchIfRef(cs[3]); + if ((0, _primitives.isStream)(lookup)) { + lookup = lookup.getBytes(); + } + return ['IndexedCS', baseIndexedCS, hiVal, lookup]; + case 'Separation': + case 'DeviceN': + var name = xref.fetchIfRef(cs[1]); + numComps = (0, _util.isArray)(name) ? name.length : 1; + alt = ColorSpace.parseToIR(cs[2], xref, res); + var tintFnIR = _function.PDFFunction.getIR(xref, xref.fetchIfRef(cs[3])); + return ['AlternateCS', numComps, alt, tintFnIR]; + case 'Lab': + params = xref.fetchIfRef(cs[1]); + whitePoint = params.getArray('WhitePoint'); + blackPoint = params.getArray('BlackPoint'); + var range = params.getArray('Range'); + return ['LabCS', whitePoint, blackPoint, range]; + default: + throw new _util.FormatError('unimplemented color space object "' + mode + '"'); + } + } + throw new _util.FormatError('unrecognized color space object: "' + cs + '"'); + }; + ColorSpace.isDefaultDecode = function ColorSpace_isDefaultDecode(decode, n) { + if (!(0, _util.isArray)(decode)) { + return true; + } + if (n * 2 !== decode.length) { + (0, _util.warn)('The decode map is not the correct length'); + return true; + } + for (var i = 0, ii = decode.length; i < ii; i += 2) { + if (decode[i] !== 0 || decode[i + 1] !== 1) { + return false; + } + } + return true; + }; + ColorSpace.singletons = { + get gray() { + return (0, _util.shadow)(this, 'gray', new DeviceGrayCS()); + }, + get rgb() { + return (0, _util.shadow)(this, 'rgb', new DeviceRgbCS()); + }, + get cmyk() { + return (0, _util.shadow)(this, 'cmyk', new DeviceCmykCS()); + } + }; + return ColorSpace; + }(); + var AlternateCS = function AlternateCSClosure() { + function AlternateCS(numComps, base, tintFn) { + this.name = 'Alternate'; + this.numComps = numComps; + this.defaultColor = new Float32Array(numComps); + for (var i = 0; i < numComps; ++i) { + this.defaultColor[i] = 1; + } + this.base = base; + this.tintFn = tintFn; + this.tmpBuf = new Float32Array(base.numComps); + } + + AlternateCS.prototype = { + getRgb: ColorSpace.prototype.getRgb, + getRgbItem: function AlternateCS_getRgbItem(src, srcOffset, dest, destOffset) { + var tmpBuf = this.tmpBuf; + this.tintFn(src, srcOffset, tmpBuf, 0); + this.base.getRgbItem(tmpBuf, 0, dest, destOffset); + }, + getRgbBuffer: function AlternateCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + var tintFn = this.tintFn; + var base = this.base; + var scale = 1 / ((1 << bits) - 1); + var baseNumComps = base.numComps; + var usesZeroToOneRange = base.usesZeroToOneRange; + var isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) && alpha01 === 0; + var pos = isPassthrough ? destOffset : 0; + var baseBuf = isPassthrough ? dest : new Uint8Array(baseNumComps * count); + var numComps = this.numComps; + var scaled = new Float32Array(numComps); + var tinted = new Float32Array(baseNumComps); + var i, j; + for (i = 0; i < count; i++) { + for (j = 0; j < numComps; j++) { + scaled[j] = src[srcOffset++] * scale; + } + tintFn(scaled, 0, tinted, 0); + if (usesZeroToOneRange) { + for (j = 0; j < baseNumComps; j++) { + baseBuf[pos++] = tinted[j] * 255; + } + } else { + base.getRgbItem(tinted, 0, baseBuf, pos); + pos += baseNumComps; + } + } + if (!isPassthrough) { + base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01); + } + }, + getOutputLength: function AlternateCS_getOutputLength(inputLength, alpha01) { + return this.base.getOutputLength(inputLength * this.base.numComps / this.numComps, alpha01); + }, + isPassthrough: ColorSpace.prototype.isPassthrough, + fillRgb: ColorSpace.prototype.fillRgb, + isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) { + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); + }, + usesZeroToOneRange: true + }; + return AlternateCS; + }(); + var PatternCS = function PatternCSClosure() { + function PatternCS(baseCS) { + this.name = 'Pattern'; + this.base = baseCS; + } + + PatternCS.prototype = {}; + return PatternCS; + }(); + var IndexedCS = function IndexedCSClosure() { + function IndexedCS(base, highVal, lookup) { + this.name = 'Indexed'; + this.numComps = 1; + this.defaultColor = new Uint8Array(this.numComps); + this.base = base; + this.highVal = highVal; + var baseNumComps = base.numComps; + var length = baseNumComps * highVal; + if ((0, _primitives.isStream)(lookup)) { + this.lookup = new Uint8Array(length); + var bytes = lookup.getBytes(length); + this.lookup.set(bytes); + } else if ((0, _util.isString)(lookup)) { + this.lookup = new Uint8Array(length); + for (var i = 0; i < length; ++i) { + this.lookup[i] = lookup.charCodeAt(i); + } + } else if (lookup instanceof Uint8Array || lookup instanceof Array) { + this.lookup = lookup; + } else { + throw new _util.FormatError('Unrecognized lookup table: ' + lookup); + } + } + + IndexedCS.prototype = { + getRgb: ColorSpace.prototype.getRgb, + getRgbItem: function IndexedCS_getRgbItem(src, srcOffset, dest, destOffset) { + var numComps = this.base.numComps; + var start = src[srcOffset] * numComps; + this.base.getRgbBuffer(this.lookup, start, 1, dest, destOffset, 8, 0); + }, + getRgbBuffer: function IndexedCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + var base = this.base; + var numComps = base.numComps; + var outputDelta = base.getOutputLength(numComps, alpha01); + var lookup = this.lookup; + for (var i = 0; i < count; ++i) { + var lookupPos = src[srcOffset++] * numComps; + base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01); + destOffset += outputDelta; + } + }, + getOutputLength: function IndexedCS_getOutputLength(inputLength, alpha01) { + return this.base.getOutputLength(inputLength * this.base.numComps, alpha01); + }, + isPassthrough: ColorSpace.prototype.isPassthrough, + fillRgb: ColorSpace.prototype.fillRgb, + isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) { + return true; + }, + usesZeroToOneRange: true + }; + return IndexedCS; + }(); + var DeviceGrayCS = function DeviceGrayCSClosure() { + function DeviceGrayCS() { + this.name = 'DeviceGray'; + this.numComps = 1; + this.defaultColor = new Float32Array(this.numComps); + } + + DeviceGrayCS.prototype = { + getRgb: ColorSpace.prototype.getRgb, + getRgbItem: function DeviceGrayCS_getRgbItem(src, srcOffset, dest, destOffset) { + var c = src[srcOffset] * 255 | 0; + c = c < 0 ? 0 : c > 255 ? 255 : c; + dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c; + }, + getRgbBuffer: function DeviceGrayCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + var scale = 255 / ((1 << bits) - 1); + var j = srcOffset, + q = destOffset; + for (var i = 0; i < count; ++i) { + var c = scale * src[j++] | 0; + dest[q++] = c; + dest[q++] = c; + dest[q++] = c; + q += alpha01; + } + }, + getOutputLength: function DeviceGrayCS_getOutputLength(inputLength, alpha01) { + return inputLength * (3 + alpha01); + }, + isPassthrough: ColorSpace.prototype.isPassthrough, + fillRgb: ColorSpace.prototype.fillRgb, + isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) { + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); + }, + usesZeroToOneRange: true + }; + return DeviceGrayCS; + }(); + var DeviceRgbCS = function DeviceRgbCSClosure() { + function DeviceRgbCS() { + this.name = 'DeviceRGB'; + this.numComps = 3; + this.defaultColor = new Float32Array(this.numComps); + } + + DeviceRgbCS.prototype = { + getRgb: ColorSpace.prototype.getRgb, + getRgbItem: function DeviceRgbCS_getRgbItem(src, srcOffset, dest, destOffset) { + var r = src[srcOffset] * 255 | 0; + var g = src[srcOffset + 1] * 255 | 0; + var b = src[srcOffset + 2] * 255 | 0; + dest[destOffset] = r < 0 ? 0 : r > 255 ? 255 : r; + dest[destOffset + 1] = g < 0 ? 0 : g > 255 ? 255 : g; + dest[destOffset + 2] = b < 0 ? 0 : b > 255 ? 255 : b; + }, + getRgbBuffer: function DeviceRgbCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + if (bits === 8 && alpha01 === 0) { + dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset); + return; + } + var scale = 255 / ((1 << bits) - 1); + var j = srcOffset, + q = destOffset; + for (var i = 0; i < count; ++i) { + dest[q++] = scale * src[j++] | 0; + dest[q++] = scale * src[j++] | 0; + dest[q++] = scale * src[j++] | 0; + q += alpha01; + } + }, + getOutputLength: function DeviceRgbCS_getOutputLength(inputLength, alpha01) { + return inputLength * (3 + alpha01) / 3 | 0; + }, + isPassthrough: function DeviceRgbCS_isPassthrough(bits) { + return bits === 8; + }, + fillRgb: ColorSpace.prototype.fillRgb, + isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) { + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); + }, + usesZeroToOneRange: true + }; + return DeviceRgbCS; + }(); + var DeviceCmykCS = function DeviceCmykCSClosure() { + function convertToRgb(src, srcOffset, srcScale, dest, destOffset) { + var c = src[srcOffset + 0] * srcScale; + var m = src[srcOffset + 1] * srcScale; + var y = src[srcOffset + 2] * srcScale; + var k = src[srcOffset + 3] * srcScale; + var r = c * (-4.387332384609988 * c + 54.48615194189176 * m + 18.82290502165302 * y + 212.25662451639585 * k + -285.2331026137004) + m * (1.7149763477362134 * m - 5.6096736904047315 * y + -17.873870861415444 * k - 5.497006427196366) + y * (-2.5217340131683033 * y - 21.248923337353073 * k + 17.5119270841813) + k * (-21.86122147463605 * k - 189.48180835922747) + 255 | 0; + var g = c * (8.841041422036149 * c + 60.118027045597366 * m + 6.871425592049007 * y + 31.159100130055922 * k + -79.2970844816548) + m * (-15.310361306967817 * m + 17.575251261109482 * y + 131.35250912493976 * k - 190.9453302588951) + y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) + k * (-20.737325471181034 * k - 187.80453709719578) + 255 | 0; + var b = c * (0.8842522430003296 * c + 8.078677503112928 * m + 30.89978309703729 * y - 0.23883238689178934 * k + -14.183576799673286) + m * (10.49593273432072 * m + 63.02378494754052 * y + 50.606957656360734 * k - 112.23884253719248) + y * (0.03296041114873217 * y + 115.60384449646641 * k + -193.58209356861505) + k * (-22.33816807309886 * k - 180.12613974708367) + 255 | 0; + dest[destOffset] = r > 255 ? 255 : r < 0 ? 0 : r; + dest[destOffset + 1] = g > 255 ? 255 : g < 0 ? 0 : g; + dest[destOffset + 2] = b > 255 ? 255 : b < 0 ? 0 : b; + } + + function DeviceCmykCS() { + this.name = 'DeviceCMYK'; + this.numComps = 4; + this.defaultColor = new Float32Array(this.numComps); + this.defaultColor[3] = 1; + } + + DeviceCmykCS.prototype = { + getRgb: ColorSpace.prototype.getRgb, + getRgbItem: function DeviceCmykCS_getRgbItem(src, srcOffset, dest, destOffset) { + convertToRgb(src, srcOffset, 1, dest, destOffset); + }, + getRgbBuffer: function DeviceCmykCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + var scale = 1 / ((1 << bits) - 1); + for (var i = 0; i < count; i++) { + convertToRgb(src, srcOffset, scale, dest, destOffset); + srcOffset += 4; + destOffset += 3 + alpha01; + } + }, + getOutputLength: function DeviceCmykCS_getOutputLength(inputLength, alpha01) { + return inputLength / 4 * (3 + alpha01) | 0; + }, + isPassthrough: ColorSpace.prototype.isPassthrough, + fillRgb: ColorSpace.prototype.fillRgb, + isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) { + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); + }, + usesZeroToOneRange: true + }; + return DeviceCmykCS; + }(); + var CalGrayCS = function CalGrayCSClosure() { + function CalGrayCS(whitePoint, blackPoint, gamma) { + this.name = 'CalGray'; + this.numComps = 1; + this.defaultColor = new Float32Array(this.numComps); + if (!whitePoint) { + throw new _util.FormatError('WhitePoint missing - required for color space CalGray'); + } + blackPoint = blackPoint || [0, 0, 0]; + gamma = gamma || 1; + this.XW = whitePoint[0]; + this.YW = whitePoint[1]; + this.ZW = whitePoint[2]; + this.XB = blackPoint[0]; + this.YB = blackPoint[1]; + this.ZB = blackPoint[2]; + this.G = gamma; + if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { + throw new _util.FormatError('Invalid WhitePoint components for ' + this.name + ', no fallback available'); + } + if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { + (0, _util.info)('Invalid BlackPoint for ' + this.name + ', falling back to default'); + this.XB = this.YB = this.ZB = 0; + } + if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) { + (0, _util.warn)(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB + ', ZB: ' + this.ZB + ', only default values are supported.'); + } + if (this.G < 1) { + (0, _util.info)('Invalid Gamma: ' + this.G + ' for ' + this.name + ', falling back to default'); + this.G = 1; + } + } + + function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) { + var A = src[srcOffset] * scale; + var AG = Math.pow(A, cs.G); + var L = cs.YW * AG; + var val = Math.max(295.8 * Math.pow(L, 0.333333333333333333) - 40.8, 0) | 0; + dest[destOffset] = val; + dest[destOffset + 1] = val; + dest[destOffset + 2] = val; + } + + CalGrayCS.prototype = { + getRgb: ColorSpace.prototype.getRgb, + getRgbItem: function CalGrayCS_getRgbItem(src, srcOffset, dest, destOffset) { + convertToRgb(this, src, srcOffset, dest, destOffset, 1); + }, + getRgbBuffer: function CalGrayCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + var scale = 1 / ((1 << bits) - 1); + for (var i = 0; i < count; ++i) { + convertToRgb(this, src, srcOffset, dest, destOffset, scale); + srcOffset += 1; + destOffset += 3 + alpha01; + } + }, + getOutputLength: function CalGrayCS_getOutputLength(inputLength, alpha01) { + return inputLength * (3 + alpha01); + }, + isPassthrough: ColorSpace.prototype.isPassthrough, + fillRgb: ColorSpace.prototype.fillRgb, + isDefaultDecode: function CalGrayCS_isDefaultDecode(decodeMap) { + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); + }, + usesZeroToOneRange: true + }; + return CalGrayCS; + }(); + var CalRGBCS = function CalRGBCSClosure() { + var BRADFORD_SCALE_MATRIX = new Float32Array([0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296]); + var BRADFORD_SCALE_INVERSE_MATRIX = new Float32Array([0.9869929, -0.1470543, 0.1599627, 0.4323053, 0.5183603, 0.0492912, -0.0085287, 0.0400428, 0.9684867]); + var SRGB_D65_XYZ_TO_RGB_MATRIX = new Float32Array([3.2404542, -1.5371385, -0.4985314, -0.9692660, 1.8760108, 0.0415560, 0.0556434, -0.2040259, 1.0572252]); + var FLAT_WHITEPOINT_MATRIX = new Float32Array([1, 1, 1]); + var tempNormalizeMatrix = new Float32Array(3); + var tempConvertMatrix1 = new Float32Array(3); + var tempConvertMatrix2 = new Float32Array(3); + var DECODE_L_CONSTANT = Math.pow((8 + 16) / 116, 3) / 8.0; + + function CalRGBCS(whitePoint, blackPoint, gamma, matrix) { + this.name = 'CalRGB'; + this.numComps = 3; + this.defaultColor = new Float32Array(this.numComps); + if (!whitePoint) { + throw new _util.FormatError('WhitePoint missing - required for color space CalRGB'); + } + blackPoint = blackPoint || new Float32Array(3); + gamma = gamma || new Float32Array([1, 1, 1]); + matrix = matrix || new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]); + var XW = whitePoint[0]; + var YW = whitePoint[1]; + var ZW = whitePoint[2]; + this.whitePoint = whitePoint; + var XB = blackPoint[0]; + var YB = blackPoint[1]; + var ZB = blackPoint[2]; + this.blackPoint = blackPoint; + this.GR = gamma[0]; + this.GG = gamma[1]; + this.GB = gamma[2]; + this.MXA = matrix[0]; + this.MYA = matrix[1]; + this.MZA = matrix[2]; + this.MXB = matrix[3]; + this.MYB = matrix[4]; + this.MZB = matrix[5]; + this.MXC = matrix[6]; + this.MYC = matrix[7]; + this.MZC = matrix[8]; + if (XW < 0 || ZW < 0 || YW !== 1) { + throw new _util.FormatError('Invalid WhitePoint components for ' + this.name + ', no fallback available'); + } + if (XB < 0 || YB < 0 || ZB < 0) { + (0, _util.info)('Invalid BlackPoint for ' + this.name + ' [' + XB + ', ' + YB + ', ' + ZB + '], falling back to default'); + this.blackPoint = new Float32Array(3); + } + if (this.GR < 0 || this.GG < 0 || this.GB < 0) { + (0, _util.info)('Invalid Gamma [' + this.GR + ', ' + this.GG + ', ' + this.GB + '] for ' + this.name + ', falling back to default'); + this.GR = this.GG = this.GB = 1; + } + if (this.MXA < 0 || this.MYA < 0 || this.MZA < 0 || this.MXB < 0 || this.MYB < 0 || this.MZB < 0 || this.MXC < 0 || this.MYC < 0 || this.MZC < 0) { + (0, _util.info)('Invalid Matrix for ' + this.name + ' [' + this.MXA + ', ' + this.MYA + ', ' + this.MZA + this.MXB + ', ' + this.MYB + ', ' + this.MZB + this.MXC + ', ' + this.MYC + ', ' + this.MZC + '], falling back to default'); + this.MXA = this.MYB = this.MZC = 1; + this.MXB = this.MYA = this.MZA = this.MXC = this.MYC = this.MZB = 0; + } + } + + function matrixProduct(a, b, result) { + result[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; + result[1] = a[3] * b[0] + a[4] * b[1] + a[5] * b[2]; + result[2] = a[6] * b[0] + a[7] * b[1] + a[8] * b[2]; + } + + function convertToFlat(sourceWhitePoint, LMS, result) { + result[0] = LMS[0] * 1 / sourceWhitePoint[0]; + result[1] = LMS[1] * 1 / sourceWhitePoint[1]; + result[2] = LMS[2] * 1 / sourceWhitePoint[2]; + } + + function convertToD65(sourceWhitePoint, LMS, result) { + var D65X = 0.95047; + var D65Y = 1; + var D65Z = 1.08883; + result[0] = LMS[0] * D65X / sourceWhitePoint[0]; + result[1] = LMS[1] * D65Y / sourceWhitePoint[1]; + result[2] = LMS[2] * D65Z / sourceWhitePoint[2]; + } + + function sRGBTransferFunction(color) { + if (color <= 0.0031308) { + return adjustToRange(0, 1, 12.92 * color); + } + return adjustToRange(0, 1, (1 + 0.055) * Math.pow(color, 1 / 2.4) - 0.055); + } + + function adjustToRange(min, max, value) { + return Math.max(min, Math.min(max, value)); + } + + function decodeL(L) { + if (L < 0) { + return -decodeL(-L); + } + if (L > 8.0) { + return Math.pow((L + 16) / 116, 3); + } + return L * DECODE_L_CONSTANT; + } + + function compensateBlackPoint(sourceBlackPoint, XYZ_Flat, result) { + if (sourceBlackPoint[0] === 0 && sourceBlackPoint[1] === 0 && sourceBlackPoint[2] === 0) { + result[0] = XYZ_Flat[0]; + result[1] = XYZ_Flat[1]; + result[2] = XYZ_Flat[2]; + return; + } + var zeroDecodeL = decodeL(0); + var X_DST = zeroDecodeL; + var X_SRC = decodeL(sourceBlackPoint[0]); + var Y_DST = zeroDecodeL; + var Y_SRC = decodeL(sourceBlackPoint[1]); + var Z_DST = zeroDecodeL; + var Z_SRC = decodeL(sourceBlackPoint[2]); + var X_Scale = (1 - X_DST) / (1 - X_SRC); + var X_Offset = 1 - X_Scale; + var Y_Scale = (1 - Y_DST) / (1 - Y_SRC); + var Y_Offset = 1 - Y_Scale; + var Z_Scale = (1 - Z_DST) / (1 - Z_SRC); + var Z_Offset = 1 - Z_Scale; + result[0] = XYZ_Flat[0] * X_Scale + X_Offset; + result[1] = XYZ_Flat[1] * Y_Scale + Y_Offset; + result[2] = XYZ_Flat[2] * Z_Scale + Z_Offset; + } + + function normalizeWhitePointToFlat(sourceWhitePoint, XYZ_In, result) { + if (sourceWhitePoint[0] === 1 && sourceWhitePoint[2] === 1) { + result[0] = XYZ_In[0]; + result[1] = XYZ_In[1]; + result[2] = XYZ_In[2]; + return; + } + var LMS = result; + matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS); + var LMS_Flat = tempNormalizeMatrix; + convertToFlat(sourceWhitePoint, LMS, LMS_Flat); + matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_Flat, result); + } + + function normalizeWhitePointToD65(sourceWhitePoint, XYZ_In, result) { + var LMS = result; + matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS); + var LMS_D65 = tempNormalizeMatrix; + convertToD65(sourceWhitePoint, LMS, LMS_D65); + matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_D65, result); + } + + function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) { + var A = adjustToRange(0, 1, src[srcOffset] * scale); + var B = adjustToRange(0, 1, src[srcOffset + 1] * scale); + var C = adjustToRange(0, 1, src[srcOffset + 2] * scale); + var AGR = Math.pow(A, cs.GR); + var BGG = Math.pow(B, cs.GG); + var CGB = Math.pow(C, cs.GB); + var X = cs.MXA * AGR + cs.MXB * BGG + cs.MXC * CGB; + var Y = cs.MYA * AGR + cs.MYB * BGG + cs.MYC * CGB; + var Z = cs.MZA * AGR + cs.MZB * BGG + cs.MZC * CGB; + var XYZ = tempConvertMatrix1; + XYZ[0] = X; + XYZ[1] = Y; + XYZ[2] = Z; + var XYZ_Flat = tempConvertMatrix2; + normalizeWhitePointToFlat(cs.whitePoint, XYZ, XYZ_Flat); + var XYZ_Black = tempConvertMatrix1; + compensateBlackPoint(cs.blackPoint, XYZ_Flat, XYZ_Black); + var XYZ_D65 = tempConvertMatrix2; + normalizeWhitePointToD65(FLAT_WHITEPOINT_MATRIX, XYZ_Black, XYZ_D65); + var SRGB = tempConvertMatrix1; + matrixProduct(SRGB_D65_XYZ_TO_RGB_MATRIX, XYZ_D65, SRGB); + var sR = sRGBTransferFunction(SRGB[0]); + var sG = sRGBTransferFunction(SRGB[1]); + var sB = sRGBTransferFunction(SRGB[2]); + dest[destOffset] = Math.round(sR * 255); + dest[destOffset + 1] = Math.round(sG * 255); + dest[destOffset + 2] = Math.round(sB * 255); + } + + CalRGBCS.prototype = { + getRgb: ColorSpace.prototype.getRgb, + getRgbItem: function CalRGBCS_getRgbItem(src, srcOffset, dest, destOffset) { + convertToRgb(this, src, srcOffset, dest, destOffset, 1); + }, + getRgbBuffer: function CalRGBCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + var scale = 1 / ((1 << bits) - 1); + for (var i = 0; i < count; ++i) { + convertToRgb(this, src, srcOffset, dest, destOffset, scale); + srcOffset += 3; + destOffset += 3 + alpha01; + } + }, + getOutputLength: function CalRGBCS_getOutputLength(inputLength, alpha01) { + return inputLength * (3 + alpha01) / 3 | 0; + }, + isPassthrough: ColorSpace.prototype.isPassthrough, + fillRgb: ColorSpace.prototype.fillRgb, + isDefaultDecode: function CalRGBCS_isDefaultDecode(decodeMap) { + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); + }, + usesZeroToOneRange: true + }; + return CalRGBCS; + }(); + var LabCS = function LabCSClosure() { + function LabCS(whitePoint, blackPoint, range) { + this.name = 'Lab'; + this.numComps = 3; + this.defaultColor = new Float32Array(this.numComps); + if (!whitePoint) { + throw new _util.FormatError('WhitePoint missing - required for color space Lab'); + } + blackPoint = blackPoint || [0, 0, 0]; + range = range || [-100, 100, -100, 100]; + this.XW = whitePoint[0]; + this.YW = whitePoint[1]; + this.ZW = whitePoint[2]; + this.amin = range[0]; + this.amax = range[1]; + this.bmin = range[2]; + this.bmax = range[3]; + this.XB = blackPoint[0]; + this.YB = blackPoint[1]; + this.ZB = blackPoint[2]; + if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { + throw new _util.FormatError('Invalid WhitePoint components, no fallback available'); + } + if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { + (0, _util.info)('Invalid BlackPoint, falling back to default'); + this.XB = this.YB = this.ZB = 0; + } + if (this.amin > this.amax || this.bmin > this.bmax) { + (0, _util.info)('Invalid Range, falling back to defaults'); + this.amin = -100; + this.amax = 100; + this.bmin = -100; + this.bmax = 100; + } + } + + function fn_g(x) { + var result; + if (x >= 6 / 29) { + result = x * x * x; + } else { + result = 108 / 841 * (x - 4 / 29); + } + return result; + } + + function decode(value, high1, low2, high2) { + return low2 + value * (high2 - low2) / high1; + } + + function convertToRgb(cs, src, srcOffset, maxVal, dest, destOffset) { + var Ls = src[srcOffset]; + var as = src[srcOffset + 1]; + var bs = src[srcOffset + 2]; + if (maxVal !== false) { + Ls = decode(Ls, maxVal, 0, 100); + as = decode(as, maxVal, cs.amin, cs.amax); + bs = decode(bs, maxVal, cs.bmin, cs.bmax); + } + as = as > cs.amax ? cs.amax : as < cs.amin ? cs.amin : as; + bs = bs > cs.bmax ? cs.bmax : bs < cs.bmin ? cs.bmin : bs; + var M = (Ls + 16) / 116; + var L = M + as / 500; + var N = M - bs / 200; + var X = cs.XW * fn_g(L); + var Y = cs.YW * fn_g(M); + var Z = cs.ZW * fn_g(N); + var r, g, b; + if (cs.ZW < 1) { + r = X * 3.1339 + Y * -1.6170 + Z * -0.4906; + g = X * -0.9785 + Y * 1.9160 + Z * 0.0333; + b = X * 0.0720 + Y * -0.2290 + Z * 1.4057; + } else { + r = X * 3.2406 + Y * -1.5372 + Z * -0.4986; + g = X * -0.9689 + Y * 1.8758 + Z * 0.0415; + b = X * 0.0557 + Y * -0.2040 + Z * 1.0570; + } + dest[destOffset] = r <= 0 ? 0 : r >= 1 ? 255 : Math.sqrt(r) * 255 | 0; + dest[destOffset + 1] = g <= 0 ? 0 : g >= 1 ? 255 : Math.sqrt(g) * 255 | 0; + dest[destOffset + 2] = b <= 0 ? 0 : b >= 1 ? 255 : Math.sqrt(b) * 255 | 0; + } + + LabCS.prototype = { + getRgb: ColorSpace.prototype.getRgb, + getRgbItem: function LabCS_getRgbItem(src, srcOffset, dest, destOffset) { + convertToRgb(this, src, srcOffset, false, dest, destOffset); + }, + getRgbBuffer: function LabCS_getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + var maxVal = (1 << bits) - 1; + for (var i = 0; i < count; i++) { + convertToRgb(this, src, srcOffset, maxVal, dest, destOffset); + srcOffset += 3; + destOffset += 3 + alpha01; + } + }, + getOutputLength: function LabCS_getOutputLength(inputLength, alpha01) { + return inputLength * (3 + alpha01) / 3 | 0; + }, + isPassthrough: ColorSpace.prototype.isPassthrough, + fillRgb: ColorSpace.prototype.fillRgb, + isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) { + return true; + }, + usesZeroToOneRange: false + }; + return LabCS; + }(); + exports.ColorSpace = ColorSpace; + + /***/ + }), + /* 4 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + var 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']; + var 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']; + var MacRomanEncoding = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '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', 'space', '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']; + var StandardEncoding = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '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']; + var WinAnsiEncoding = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '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', 'bullet', 'Euro', 'bullet', 'quotesinglbase', 'florin', 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', 'circumflex', 'perthousand', 'Scaron', 'guilsinglleft', 'OE', 'bullet', 'Zcaron', 'bullet', 'bullet', 'quoteleft', 'quoteright', 'quotedblleft', 'quotedblright', 'bullet', 'endash', 'emdash', 'tilde', 'trademark', 'scaron', 'guilsinglright', 'oe', 'bullet', 'zcaron', 'Ydieresis', 'space', 'exclamdown', 'cent', 'sterling', 'currency', 'yen', 'brokenbar', 'section', 'dieresis', 'copyright', 'ordfeminine', 'guillemotleft', 'logicalnot', 'hyphen', 'registered', 'macron', 'degree', 'plusminus', 'twosuperior', 'threesuperior', 'acute', 'mu', 'paragraph', 'periodcentered', 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', 'onequarter', 'onehalf', 'threequarters', 'questiondown', 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', 'Adieresis', 'Aring', 'AE', 'Ccedilla', 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Eth', 'Ntilde', 'Ograve', 'Oacute', 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', 'Udieresis', 'Yacute', 'Thorn', 'germandbls', 'agrave', 'aacute', 'acircumflex', 'atilde', 'adieresis', 'aring', 'ae', 'ccedilla', 'egrave', 'eacute', 'ecircumflex', 'edieresis', 'igrave', 'iacute', 'icircumflex', 'idieresis', 'eth', 'ntilde', 'ograve', 'oacute', 'ocircumflex', 'otilde', 'odieresis', 'divide', 'oslash', 'ugrave', 'uacute', 'ucircumflex', 'udieresis', 'yacute', 'thorn', 'ydieresis']; + var SymbolSetEncoding = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'space', 'exclam', 'universal', 'numbersign', 'existential', 'percent', 'ampersand', 'suchthat', 'parenleft', 'parenright', 'asteriskmath', 'plus', 'comma', 'minus', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'congruent', 'Alpha', 'Beta', 'Chi', 'Delta', 'Epsilon', 'Phi', 'Gamma', 'Eta', 'Iota', 'theta1', 'Kappa', 'Lambda', 'Mu', 'Nu', 'Omicron', 'Pi', 'Theta', 'Rho', 'Sigma', 'Tau', 'Upsilon', 'sigma1', 'Omega', 'Xi', 'Psi', 'Zeta', 'bracketleft', 'therefore', 'bracketright', 'perpendicular', 'underscore', 'radicalex', 'alpha', 'beta', 'chi', 'delta', 'epsilon', 'phi', 'gamma', 'eta', 'iota', 'phi1', 'kappa', 'lambda', 'mu', 'nu', 'omicron', 'pi', 'theta', 'rho', 'sigma', 'tau', 'upsilon', 'omega1', 'omega', 'xi', 'psi', 'zeta', 'braceleft', 'bar', 'braceright', 'similar', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'Euro', 'Upsilon1', 'minute', 'lessequal', 'fraction', 'infinity', 'florin', 'club', 'diamond', 'heart', 'spade', 'arrowboth', 'arrowleft', 'arrowup', 'arrowright', 'arrowdown', 'degree', 'plusminus', 'second', 'greaterequal', 'multiply', 'proportional', 'partialdiff', 'bullet', 'divide', 'notequal', 'equivalence', 'approxequal', 'ellipsis', 'arrowvertex', 'arrowhorizex', 'carriagereturn', 'aleph', 'Ifraktur', 'Rfraktur', 'weierstrass', 'circlemultiply', 'circleplus', 'emptyset', 'intersection', 'union', 'propersuperset', 'reflexsuperset', 'notsubset', 'propersubset', 'reflexsubset', 'element', 'notelement', 'angle', 'gradient', 'registerserif', 'copyrightserif', 'trademarkserif', 'product', 'radical', 'dotmath', 'logicalnot', 'logicaland', 'logicalor', 'arrowdblboth', 'arrowdblleft', 'arrowdblup', 'arrowdblright', 'arrowdbldown', 'lozenge', 'angleleft', 'registersans', 'copyrightsans', 'trademarksans', 'summation', 'parenlefttp', 'parenleftex', 'parenleftbt', 'bracketlefttp', 'bracketleftex', 'bracketleftbt', 'bracelefttp', 'braceleftmid', 'braceleftbt', 'braceex', '', 'angleright', 'integral', 'integraltp', 'integralex', 'integralbt', 'parenrighttp', 'parenrightex', 'parenrightbt', 'bracketrighttp', 'bracketrightex', 'bracketrightbt', 'bracerighttp', 'bracerightmid', 'bracerightbt']; + var ZapfDingbatsEncoding = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'space', 'a1', 'a2', 'a202', 'a3', 'a4', 'a5', 'a119', 'a118', 'a117', 'a11', 'a12', 'a13', 'a14', 'a15', 'a16', 'a105', 'a17', 'a18', 'a19', 'a20', 'a21', 'a22', 'a23', 'a24', 'a25', 'a26', 'a27', 'a28', 'a6', 'a7', 'a8', 'a9', 'a10', 'a29', 'a30', 'a31', 'a32', 'a33', 'a34', 'a35', 'a36', 'a37', 'a38', 'a39', 'a40', 'a41', 'a42', 'a43', 'a44', 'a45', 'a46', 'a47', 'a48', 'a49', 'a50', 'a51', 'a52', 'a53', 'a54', 'a55', 'a56', 'a57', 'a58', 'a59', 'a60', 'a61', 'a62', 'a63', 'a64', 'a65', 'a66', 'a67', 'a68', 'a69', 'a70', 'a71', 'a72', 'a73', 'a74', 'a203', 'a75', 'a204', 'a76', 'a77', 'a78', 'a79', 'a81', 'a82', 'a83', 'a84', 'a97', 'a98', 'a99', 'a100', '', 'a89', 'a90', 'a93', 'a94', 'a91', 'a92', 'a205', 'a85', 'a206', 'a86', 'a87', 'a88', 'a95', 'a96', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'a101', 'a102', 'a103', 'a104', 'a106', 'a107', 'a108', 'a112', 'a111', 'a110', 'a109', 'a120', 'a121', 'a122', 'a123', 'a124', 'a125', 'a126', 'a127', 'a128', 'a129', 'a130', 'a131', 'a132', 'a133', 'a134', 'a135', 'a136', 'a137', 'a138', 'a139', 'a140', 'a141', 'a142', 'a143', 'a144', 'a145', 'a146', 'a147', 'a148', 'a149', 'a150', 'a151', 'a152', 'a153', 'a154', 'a155', 'a156', 'a157', 'a158', 'a159', 'a160', 'a161', 'a163', 'a164', 'a196', 'a165', 'a192', 'a166', 'a167', 'a168', 'a169', 'a170', 'a171', 'a172', 'a173', 'a162', 'a174', 'a175', 'a176', 'a177', 'a178', 'a179', 'a193', 'a180', 'a199', 'a181', 'a200', 'a182', '', 'a201', 'a183', 'a184', 'a197', 'a185', 'a194', 'a198', 'a186', 'a195', 'a187', 'a188', 'a189', 'a190', 'a191']; + + function getEncoding(encodingName) { + switch (encodingName) { + case 'WinAnsiEncoding': + return WinAnsiEncoding; + case 'StandardEncoding': + return StandardEncoding; + case 'MacRomanEncoding': + return MacRomanEncoding; + case 'SymbolSetEncoding': + return SymbolSetEncoding; + case 'ZapfDingbatsEncoding': + return ZapfDingbatsEncoding; + case 'ExpertEncoding': + return ExpertEncoding; + case 'MacExpertEncoding': + return MacExpertEncoding; + default: + return null; + } + } + + exports.WinAnsiEncoding = WinAnsiEncoding; + exports.StandardEncoding = StandardEncoding; + exports.MacRomanEncoding = MacRomanEncoding; + exports.SymbolSetEncoding = SymbolSetEncoding; + exports.ZapfDingbatsEncoding = ZapfDingbatsEncoding; + exports.ExpertEncoding = ExpertEncoding; + exports.getEncoding = getEncoding; + + /***/ + }), + /* 5 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.Parser = exports.Linearization = exports.Lexer = undefined; + + var _stream = __w_pdfjs_require__(2); + + var _util = __w_pdfjs_require__(0); + + var _primitives = __w_pdfjs_require__(1); + + var MAX_LENGTH_TO_CACHE = 1000; + var Parser = function ParserClosure() { + function Parser(lexer, allowStreams, xref, recoveryMode) { + this.lexer = lexer; + this.allowStreams = allowStreams; + this.xref = xref; + this.recoveryMode = recoveryMode || false; + this.imageCache = Object.create(null); + this.refill(); + } + + Parser.prototype = { + refill: function Parser_refill() { + this.buf1 = this.lexer.getObj(); + this.buf2 = this.lexer.getObj(); + }, + shift: function Parser_shift() { + if ((0, _primitives.isCmd)(this.buf2, 'ID')) { + this.buf1 = this.buf2; + this.buf2 = null; + } else { + this.buf1 = this.buf2; + this.buf2 = this.lexer.getObj(); + } + }, + tryShift: function Parser_tryShift() { + try { + this.shift(); + return true; + } catch (e) { + if (e instanceof _util.MissingDataException) { + throw e; + } + return false; + } + }, + getObj: function Parser_getObj(cipherTransform) { + var buf1 = this.buf1; + this.shift(); + if (buf1 instanceof _primitives.Cmd) { + switch (buf1.cmd) { + case 'BI': + return this.makeInlineImage(cipherTransform); + case '[': + var 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 '<<': + var 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; + } + var 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 ((0, _util.isInt)(buf1)) { + var num = buf1; + if ((0, _util.isInt)(this.buf1) && (0, _primitives.isCmd)(this.buf2, 'R')) { + var ref = new _primitives.Ref(num, this.buf1); + this.shift(); + this.shift(); + return ref; + } + return num; + } + if ((0, _util.isString)(buf1)) { + var str = buf1; + if (cipherTransform) { + str = cipherTransform.decryptString(str); + } + return str; + } + return buf1; + }, + findDefaultInlineStreamEnd: function Parser_findDefaultInlineStreamEnd(stream) { + var E = 0x45, + I = 0x49, + SPACE = 0x20, + LF = 0xA, + CR = 0xD; + var startPos = stream.pos, + state = 0, + ch, + i, + n, + followingBytes; + 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); + if (ch === SPACE || ch === LF || ch === CR) { + n = 5; + followingBytes = stream.peekBytes(n); + for (i = 0; i < n; i++) { + ch = followingBytes[i]; + if (ch !== LF && ch !== CR && (ch < SPACE || ch > 0x7F)) { + state = 0; + break; + } + } + if (state === 2) { + break; + } + } else { + state = 0; + } + } + } + return stream.pos - 4 - startPos; + }, + findDCTDecodeInlineStreamEnd: function Parser_findDCTDecodeInlineStreamEnd(stream) { + var startPos = stream.pos, + foundEOI = false, + b, + markerLength, + length; + 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; + } + } + 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: function Parser_findASCII85DecodeInlineStreamEnd(stream) { + var TILDE = 0x7E, + GT = 0x3E; + var startPos = stream.pos, + ch, + length; + while ((ch = stream.getByte()) !== -1) { + if (ch === TILDE && stream.peekByte() === GT) { + stream.skip(); + break; + } + } + 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: function Parser_findASCIIHexDecodeInlineStreamEnd(stream) { + var GT = 0x3E; + var startPos = stream.pos, + ch, + length; + while ((ch = stream.getByte()) !== -1) { + if (ch === GT) { + break; + } + } + 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: function Parser_inlineStreamSkipEI(stream) { + var E = 0x45, + I = 0x49; + var 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: function Parser_makeInlineImage(cipherTransform) { + var lexer = this.lexer; + var stream = lexer.stream; + var dict = new _primitives.Dict(this.xref); + 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'); + } + var key = this.buf1.name; + this.shift(); + if ((0, _primitives.isEOF)(this.buf1)) { + break; + } + dict.set(key, this.getObj(cipherTransform)); + } + var filter = dict.get('Filter', 'F'), + filterName; + if ((0, _primitives.isName)(filter)) { + filterName = filter.name; + } else if ((0, _util.isArray)(filter)) { + var filterZero = this.xref.fetchIfRef(filter[0]); + if ((0, _primitives.isName)(filterZero)) { + filterName = filterZero.name; + } + } + var startPos = stream.pos, + length, + i, + ii; + 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); + } + var imageStream = stream.makeSubStream(startPos, length, dict); + var adler32; + if (length < MAX_LENGTH_TO_CACHE) { + var imageBytes = imageStream.getBytes(); + imageStream.reset(); + var a = 1; + var b = 0; + for (i = 0, ii = imageBytes.length; i < ii; ++i) { + a += imageBytes[i] & 0xff; + b += a; + } + adler32 = b % 65521 << 16 | a % 65521; + if (this.imageCache.adler32 === adler32) { + this.buf2 = _primitives.Cmd.get('EI'); + this.shift(); + this.imageCache[adler32].reset(); + return this.imageCache[adler32]; + } + } + if (cipherTransform) { + imageStream = cipherTransform.createStream(imageStream, length); + } + imageStream = this.filter(imageStream, dict, length); + imageStream.dict = dict; + if (adler32 !== undefined) { + imageStream.cacheKey = 'inline_' + length + '_' + adler32; + this.imageCache[adler32] = imageStream; + } + this.buf2 = _primitives.Cmd.get('EI'); + this.shift(); + return imageStream; + }, + makeStream: function Parser_makeStream(dict, cipherTransform) { + var lexer = this.lexer; + var stream = lexer.stream; + lexer.skipToNextLine(); + var pos = stream.pos - 1; + var length = dict.get('Length'); + if (!(0, _util.isInt)(length)) { + (0, _util.info)('Bad ' + length + ' attribute in stream'); + length = 0; + } + stream.pos = pos + length; + lexer.nextChar(); + if (this.tryShift() && (0, _primitives.isCmd)(this.buf2, 'endstream')) { + this.shift(); + } else { + stream.pos = pos; + var SCAN_BLOCK_SIZE = 2048; + var ENDSTREAM_SIGNATURE_LENGTH = 9; + var ENDSTREAM_SIGNATURE = [0x65, 0x6E, 0x64, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6D]; + var skipped = 0, + found = false, + i, + j; + while (stream.pos < stream.end) { + var scanBytes = stream.peekBytes(SCAN_BLOCK_SIZE); + var scanLength = scanBytes.length - ENDSTREAM_SIGNATURE_LENGTH; + if (scanLength <= 0) { + break; + } + found = false; + i = 0; + while (i < scanLength) { + j = 0; + while (j < ENDSTREAM_SIGNATURE_LENGTH && scanBytes[i + j] === ENDSTREAM_SIGNATURE[j]) { + j++; + } + if (j >= ENDSTREAM_SIGNATURE_LENGTH) { + found = true; + break; + } + i++; + } + if (found) { + skipped += i; + stream.pos += i; + break; + } + skipped += scanLength; + stream.pos += scanLength; + } + if (!found) { + throw new _util.FormatError('Missing endstream'); + } + length = skipped; + lexer.nextChar(); + this.shift(); + this.shift(); + } + this.shift(); + stream = stream.makeSubStream(pos, length, dict); + if (cipherTransform) { + stream = cipherTransform.createStream(stream, length); + } + stream = this.filter(stream, dict, length); + stream.dict = dict; + return stream; + }, + filter: function Parser_filter(stream, dict, length) { + var filter = dict.get('Filter', 'F'); + var params = dict.get('DecodeParms', 'DP'); + if ((0, _primitives.isName)(filter)) { + if ((0, _util.isArray)(params)) { + params = this.xref.fetchIfRef(params[0]); + } + return this.makeFilter(stream, filter.name, length, params); + } + var maybeLength = length; + if ((0, _util.isArray)(filter)) { + var filterArray = filter; + var paramsArray = params; + for (var 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 ((0, _util.isArray)(paramsArray) && i in paramsArray) { + params = this.xref.fetchIfRef(paramsArray[i]); + } + stream = this.makeFilter(stream, filter.name, maybeLength, params); + maybeLength = null; + } + } + return stream; + }, + makeFilter: function Parser_makeFilter(stream, name, maybeLength, params) { + if (maybeLength === 0) { + (0, _util.warn)('Empty "' + name + '" stream.'); + return new _stream.NullStream(stream); + } + try { + var xrefStreamStats = this.xref.stats.streamTypes; + 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 (name === 'LZWDecode' || name === 'LZW') { + xrefStreamStats[_util.StreamType.LZW] = true; + var earlyChange = 1; + 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 (name === 'DCTDecode' || name === 'DCT') { + xrefStreamStats[_util.StreamType.DCT] = true; + return new _stream.JpegStream(stream, maybeLength, stream.dict, params); + } + if (name === 'JPXDecode' || name === 'JPX') { + xrefStreamStats[_util.StreamType.JPX] = true; + return new _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 _stream.CCITTFaxStream(stream, maybeLength, params); + } + if (name === 'RunLengthDecode' || name === 'RL') { + xrefStreamStats[_util.StreamType.RL] = true; + return new _stream.RunLengthStream(stream, maybeLength); + } + if (name === 'JBIG2Decode') { + xrefStreamStats[_util.StreamType.JBIG] = true; + return new _stream.Jbig2Stream(stream, maybeLength, stream.dict, params); + } + (0, _util.warn)('filter "' + name + '" not supported yet'); + return stream; + } catch (ex) { + if (ex instanceof _util.MissingDataException) { + throw ex; + } + (0, _util.warn)('Invalid stream: \"' + ex + '\"'); + return new _stream.NullStream(stream); + } + } + }; + return Parser; + }(); + var Lexer = function LexerClosure() { + function Lexer(stream, knownCommands) { + this.stream = stream; + this.nextChar(); + this.strBuf = []; + this.knownCommands = knownCommands; + } + + var 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; + } + + Lexer.prototype = { + nextChar: function Lexer_nextChar() { + return this.currentChar = this.stream.getByte(); + }, + peekChar: function Lexer_peekChar() { + return this.stream.peekByte(); + }, + getNumber: function Lexer_getNumber() { + var ch = this.currentChar; + var eNotation = false; + var divideBy = 0; + var sign = 1; + if (ch === 0x2D) { + sign = -1; + ch = this.nextChar(); + if (ch === 0x2D) { + ch = this.nextChar(); + } + } else if (ch === 0x2B) { + ch = this.nextChar(); + } + if (ch === 0x2E) { + divideBy = 10; + ch = this.nextChar(); + } + if (ch === 0x0A || ch === 0x0D) { + do { + ch = this.nextChar(); + } while (ch === 0x0A || ch === 0x0D); + } + if (ch < 0x30 || ch > 0x39) { + throw new _util.FormatError('Invalid number: ' + String.fromCharCode(ch) + ' (charCode ' + ch + ')'); + } + var baseValue = ch - 0x30; + var powerValue = 0; + var powerValueSign = 1; + while ((ch = this.nextChar()) >= 0) { + if (0x30 <= ch && ch <= 0x39) { + var 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'); + } 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 *= Math.pow(10, powerValueSign * powerValue); + } + return sign * baseValue; + }, + getString: function Lexer_getString() { + var numParen = 1; + var done = false; + var strBuf = this.strBuf; + strBuf.length = 0; + var ch = this.nextChar(); + while (true) { + var 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: + var 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: function Lexer_getName() { + var ch, previousCh; + var 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; + } + var x = toHexDigit(ch); + if (x !== -1) { + previousCh = ch; + ch = this.nextChar(); + var 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('')); + }, + getHexString: function Lexer_getHexString() { + var strBuf = this.strBuf; + strBuf.length = 0; + var ch = this.currentChar; + var isFirstHex = true; + var firstDigit; + var secondDigit; + 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) { + (0, _util.warn)('Ignoring invalid character "' + ch + '" in hex string'); + ch = this.nextChar(); + continue; + } + } else { + secondDigit = toHexDigit(ch); + if (secondDigit === -1) { + (0, _util.warn)('Ignoring invalid character "' + ch + '" in hex string'); + ch = this.nextChar(); + continue; + } + strBuf.push(String.fromCharCode(firstDigit << 4 | secondDigit)); + } + isFirstHex = !isFirstHex; + ch = this.nextChar(); + } + } + return strBuf.join(''); + }, + getObj: function Lexer_getObj() { + var comment = false; + var 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); + } + var str = String.fromCharCode(ch); + var knownCommands = this.knownCommands; + var knownCommandFound = knownCommands && knownCommands[str] !== undefined; + while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) { + var 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; + } + return _primitives.Cmd.get(str); + }, + skipToNextLine: function Lexer_skipToNextLine() { + var 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(); + } + } + }; + return Lexer; + }(); + var Linearization = { + create: function LinearizationCreate(stream) { + function getInt(name, allowZeroValue) { + var obj = linDict.get(name); + if ((0, _util.isInt)(obj) && (allowZeroValue ? obj >= 0 : obj > 0)) { + return obj; + } + throw new Error('The "' + name + '" parameter in the linearization ' + 'dictionary is invalid.'); + } + + function getHints() { + var hints = linDict.get('H'), + hintsLength, + item; + if ((0, _util.isArray)(hints) && ((hintsLength = hints.length) === 2 || hintsLength === 4)) { + for (var index = 0; index < hintsLength; index++) { + if (!((0, _util.isInt)(item = hints[index]) && item > 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.'); + } + + var parser = new Parser(new Lexer(stream), false, null); + var obj1 = parser.getObj(); + var obj2 = parser.getObj(); + var obj3 = parser.getObj(); + var linDict = parser.getObj(); + var obj, length; + if (!((0, _util.isInt)(obj1) && (0, _util.isInt)(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('L')) !== stream.length) { + throw new Error('The "L" parameter in the linearization dictionary ' + 'does not equal the stream length.'); + } + return { + length: length, + hints: getHints(), + objectNumberFirst: getInt('O'), + endFirst: getInt('E'), + numPages: getInt('N'), + mainXRefEntriesOffset: getInt('T'), + pageFirst: linDict.has('P') ? getInt('P', true) : 0 + }; + } + }; + exports.Lexer = Lexer; + exports.Linearization = Linearization; + exports.Parser = Parser; + + /***/ + }), + /* 6 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + var getLookupTableFactory = __w_pdfjs_require__(0).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['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; + + /***/ + }), + /* 7 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PostScriptCompiler = exports.PostScriptEvaluator = exports.PDFFunction = exports.isPDFFunction = undefined; + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + var _util = __w_pdfjs_require__(0); + + var _primitives = __w_pdfjs_require__(1); + + var _ps_parser = __w_pdfjs_require__(33); + + var PDFFunction = function PDFFunctionClosure() { + var CONSTRUCT_SAMPLED = 0; + var CONSTRUCT_INTERPOLATED = 2; + var CONSTRUCT_STICHED = 3; + var CONSTRUCT_POSTSCRIPT = 4; + return { + getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps, str) { + 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 / (Math.pow(2.0, bps) - 1); + var strBytes = str.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: function PDFFunction_getIR(xref, 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, fn, dict, xref); + }, + fromIR: function PDFFunction_fromIR(IR) { + var type = IR[0]; + switch (type) { + case CONSTRUCT_SAMPLED: + return this.constructSampledFromIR(IR); + case CONSTRUCT_INTERPOLATED: + return this.constructInterpolatedFromIR(IR); + case CONSTRUCT_STICHED: + return this.constructStichedFromIR(IR); + default: + return this.constructPostScriptFromIR(IR); + } + }, + parse: function PDFFunction_parse(xref, fn) { + var IR = this.getIR(xref, fn); + return this.fromIR(IR); + }, + parseArray: function PDFFunction_parseArray(xref, fnObj) { + if (!(0, _util.isArray)(fnObj)) { + return this.parse(xref, fnObj); + } + var fnArray = []; + for (var j = 0, jj = fnObj.length; j < jj; j++) { + var obj = xref.fetchIfRef(fnObj[j]); + fnArray.push(PDFFunction.parse(xref, obj)); + } + return function (src, srcOffset, dest, destOffset) { + for (var i = 0, ii = fnArray.length; i < ii; i++) { + fnArray[i](src, srcOffset, dest, destOffset + i); + } + }; + }, + constructSampled: function PDFFunction_constructSampled(str, 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 = dict.getArray('Domain'); + var range = 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 = dict.get('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 = dict.getArray('Encode'); + if (!encode) { + encode = []; + for (var i = 0; i < inputSize; ++i) { + encode.push(0); + encode.push(size[i] - 1); + } + } + encode = toMultiArray(encode); + var decode = dict.getArray('Decode'); + if (!decode) { + decode = range; + } else { + decode = toMultiArray(decode); + } + var samples = this.getSampleArray(size, outputSize, bps, str); + return [CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size, outputSize, Math.pow(2, bps) - 1, range]; + }, + constructSampledFromIR: function PDFFunction_constructSampledFromIR(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: function PDFFunction_constructInterpolated(str, dict) { + var c0 = dict.getArray('C0') || [0]; + var c1 = dict.getArray('C1') || [1]; + var n = dict.get('N'); + if (!(0, _util.isArray)(c0) || !(0, _util.isArray)(c1)) { + throw new _util.FormatError('Illegal dictionary for interpolated function'); + } + 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: function PDFFunction_constructInterpolatedFromIR(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] : Math.pow(src[srcOffset], n); + for (var j = 0; j < length; ++j) { + dest[destOffset + j] = c0[j] + x * diff[j]; + } + }; + }, + constructStiched: function PDFFunction_constructStiched(fn, dict, xref) { + var domain = 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(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i]))); + } + var bounds = dict.getArray('Bounds'); + var encode = dict.getArray('Encode'); + return [CONSTRUCT_STICHED, domain, bounds, encode, fns]; + }, + constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) { + var domain = IR[1]; + var bounds = IR[2]; + var encode = IR[3]; + var fnsIR = IR[4]; + var fns = []; + var tmpBuf = new Float32Array(1); + for (var i = 0, ii = fnsIR.length; i < ii; i++) { + fns.push(PDFFunction.fromIR(fnsIR[i])); + } + 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: function PDFFunction_constructPostScript(fn, dict, xref) { + var domain = dict.getArray('Domain'); + var range = 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: function PDFFunction_constructPostScriptFromIR(IR) { + var domain = IR[1]; + var range = IR[2]; + var code = IR[3]; + var 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 === 'undefined' ? 'undefined' : _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(Math.pow(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; + }(); + var PostScriptCompiler = function PostScriptCompilerClosure() { + function AstNode(type) { + this.type = type; + } + + AstNode.prototype.visit = function (visitor) { + throw new Error('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: function visitArgument(arg) { + this.parts.push('Math.max(', arg.min, ', Math.min(', arg.max, ', src[srcOffset + ', arg.index, ']))'); + }, + visitVariable: function visitVariable(variable) { + this.parts.push('v', variable.index); + }, + visitLiteral: function visitLiteral(literal) { + this.parts.push(literal.number); + }, + visitBinaryOperation: function visitBinaryOperation(operation) { + this.parts.push('('); + operation.arg1.visit(this); + this.parts.push(' ', operation.op, ' '); + operation.arg2.visit(this); + this.parts.push(')'); + }, + visitVariableDefinition: function visitVariableDefinition(definition) { + this.parts.push('var '); + definition.variable.visit(this); + this.parts.push(' = '); + definition.arg.visit(this); + this.parts.push(';'); + }, + visitMin: function visitMin(max) { + this.parts.push('Math.min('); + max.arg.visit(this); + this.parts.push(', ', max.max, ')'); + }, + toString: function 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 i, ii; + 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 (i = 0; i < inputSize; i++) { + stack.push(new AstArgument(i, domain[i * 2], domain[i * 2 + 1])); + } + for (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 || (n | 0) !== 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 || (n | 0) !== n || (j | 0) !== 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.isPDFFunction = isPDFFunction; + exports.PDFFunction = PDFFunction; + exports.PostScriptEvaluator = PostScriptEvaluator; + exports.PostScriptCompiler = PostScriptCompiler; + + /***/ + }), + /* 8 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + var getLookupTableFactory = __w_pdfjs_require__(0).getLookupTableFactory; + var getSpecialPUASymbols = getLookupTableFactory(function (t) { + t[63721] = 0x00A9; + t[63193] = 0x00A9; + t[63720] = 0x00AE; + t[63194] = 0x00AE; + t[63722] = 0x2122; + t[63195] = 0x2122; + t[63729] = 0x23A7; + t[63730] = 0x23A8; + t[63731] = 0x23A9; + t[63740] = 0x23AB; + t[63741] = 0x23AC; + t[63742] = 0x23AD; + t[63726] = 0x23A1; + t[63727] = 0x23A2; + t[63728] = 0x23A3; + t[63737] = 0x23A4; + t[63738] = 0x23A5; + t[63739] = 0x23A6; + t[63723] = 0x239B; + t[63724] = 0x239C; + t[63725] = 0x239D; + t[63734] = 0x239E; + t[63735] = 0x239F; + t[63736] = 0x23A0; + }); + + function mapSpecialUnicodeValues(code) { + if (code >= 0xFFF0 && code <= 0xFFFF) { + return 0; + } else if (code >= 0xF600 && code <= 0xF8FF) { + return getSpecialPUASymbols()[code] || code; + } + return code; + } + + function getUnicodeForGlyph(name, glyphsUnicodeMap) { + var unicode = glyphsUnicodeMap[name]; + if (unicode !== undefined) { + return unicode; + } + if (!name) { + return -1; + } + if (name[0] === 'u') { + var nameLen = name.length, hexStr; + if (nameLen === 7 && name[1] === 'n' && name[2] === 'i') { + hexStr = name.substr(3); + } else if (nameLen >= 5 && nameLen <= 7) { + hexStr = name.substr(1); + } else { + return -1; + } + if (hexStr === hexStr.toUpperCase()) { + unicode = parseInt(hexStr, 16); + if (unicode >= 0) { + return unicode; + } + } + } + return -1; + } + + var UnicodeRanges = [ + { + 'begin': 0x0000, + 'end': 0x007F + }, + { + 'begin': 0x0080, + 'end': 0x00FF + }, + { + 'begin': 0x0100, + 'end': 0x017F + }, + { + 'begin': 0x0180, + 'end': 0x024F + }, + { + 'begin': 0x0250, + 'end': 0x02AF + }, + { + 'begin': 0x02B0, + 'end': 0x02FF + }, + { + 'begin': 0x0300, + 'end': 0x036F + }, + { + 'begin': 0x0370, + 'end': 0x03FF + }, + { + 'begin': 0x2C80, + 'end': 0x2CFF + }, + { + 'begin': 0x0400, + 'end': 0x04FF + }, + { + 'begin': 0x0530, + 'end': 0x058F + }, + { + 'begin': 0x0590, + 'end': 0x05FF + }, + { + 'begin': 0xA500, + 'end': 0xA63F + }, + { + 'begin': 0x0600, + 'end': 0x06FF + }, + { + 'begin': 0x07C0, + 'end': 0x07FF + }, + { + 'begin': 0x0900, + 'end': 0x097F + }, + { + 'begin': 0x0980, + 'end': 0x09FF + }, + { + 'begin': 0x0A00, + 'end': 0x0A7F + }, + { + 'begin': 0x0A80, + 'end': 0x0AFF + }, + { + 'begin': 0x0B00, + 'end': 0x0B7F + }, + { + 'begin': 0x0B80, + 'end': 0x0BFF + }, + { + 'begin': 0x0C00, + 'end': 0x0C7F + }, + { + 'begin': 0x0C80, + 'end': 0x0CFF + }, + { + 'begin': 0x0D00, + 'end': 0x0D7F + }, + { + 'begin': 0x0E00, + 'end': 0x0E7F + }, + { + 'begin': 0x0E80, + 'end': 0x0EFF + }, + { + 'begin': 0x10A0, + 'end': 0x10FF + }, + { + 'begin': 0x1B00, + 'end': 0x1B7F + }, + { + 'begin': 0x1100, + 'end': 0x11FF + }, + { + 'begin': 0x1E00, + 'end': 0x1EFF + }, + { + 'begin': 0x1F00, + 'end': 0x1FFF + }, + { + 'begin': 0x2000, + 'end': 0x206F + }, + { + 'begin': 0x2070, + 'end': 0x209F + }, + { + 'begin': 0x20A0, + 'end': 0x20CF + }, + { + 'begin': 0x20D0, + 'end': 0x20FF + }, + { + 'begin': 0x2100, + 'end': 0x214F + }, + { + 'begin': 0x2150, + 'end': 0x218F + }, + { + 'begin': 0x2190, + 'end': 0x21FF + }, + { + 'begin': 0x2200, + 'end': 0x22FF + }, + { + 'begin': 0x2300, + 'end': 0x23FF + }, + { + 'begin': 0x2400, + 'end': 0x243F + }, + { + 'begin': 0x2440, + 'end': 0x245F + }, + { + 'begin': 0x2460, + 'end': 0x24FF + }, + { + 'begin': 0x2500, + 'end': 0x257F + }, + { + 'begin': 0x2580, + 'end': 0x259F + }, + { + 'begin': 0x25A0, + 'end': 0x25FF + }, + { + 'begin': 0x2600, + 'end': 0x26FF + }, + { + 'begin': 0x2700, + 'end': 0x27BF + }, + { + 'begin': 0x3000, + 'end': 0x303F + }, + { + 'begin': 0x3040, + 'end': 0x309F + }, + { + 'begin': 0x30A0, + 'end': 0x30FF + }, + { + 'begin': 0x3100, + 'end': 0x312F + }, + { + 'begin': 0x3130, + 'end': 0x318F + }, + { + 'begin': 0xA840, + 'end': 0xA87F + }, + { + 'begin': 0x3200, + 'end': 0x32FF + }, + { + 'begin': 0x3300, + 'end': 0x33FF + }, + { + 'begin': 0xAC00, + 'end': 0xD7AF + }, + { + 'begin': 0xD800, + 'end': 0xDFFF + }, + { + 'begin': 0x10900, + 'end': 0x1091F + }, + { + 'begin': 0x4E00, + 'end': 0x9FFF + }, + { + 'begin': 0xE000, + 'end': 0xF8FF + }, + { + 'begin': 0x31C0, + 'end': 0x31EF + }, + { + 'begin': 0xFB00, + 'end': 0xFB4F + }, + { + 'begin': 0xFB50, + 'end': 0xFDFF + }, + { + 'begin': 0xFE20, + 'end': 0xFE2F + }, + { + 'begin': 0xFE10, + 'end': 0xFE1F + }, + { + 'begin': 0xFE50, + 'end': 0xFE6F + }, + { + 'begin': 0xFE70, + 'end': 0xFEFF + }, + { + 'begin': 0xFF00, + 'end': 0xFFEF + }, + { + 'begin': 0xFFF0, + 'end': 0xFFFF + }, + { + 'begin': 0x0F00, + 'end': 0x0FFF + }, + { + 'begin': 0x0700, + 'end': 0x074F + }, + { + 'begin': 0x0780, + 'end': 0x07BF + }, + { + 'begin': 0x0D80, + 'end': 0x0DFF + }, + { + 'begin': 0x1000, + 'end': 0x109F + }, + { + 'begin': 0x1200, + 'end': 0x137F + }, + { + 'begin': 0x13A0, + 'end': 0x13FF + }, + { + 'begin': 0x1400, + 'end': 0x167F + }, + { + 'begin': 0x1680, + 'end': 0x169F + }, + { + 'begin': 0x16A0, + 'end': 0x16FF + }, + { + 'begin': 0x1780, + 'end': 0x17FF + }, + { + 'begin': 0x1800, + 'end': 0x18AF + }, + { + 'begin': 0x2800, + 'end': 0x28FF + }, + { + 'begin': 0xA000, + 'end': 0xA48F + }, + { + 'begin': 0x1700, + 'end': 0x171F + }, + { + 'begin': 0x10300, + 'end': 0x1032F + }, + { + 'begin': 0x10330, + 'end': 0x1034F + }, + { + 'begin': 0x10400, + 'end': 0x1044F + }, + { + 'begin': 0x1D000, + 'end': 0x1D0FF + }, + { + 'begin': 0x1D400, + 'end': 0x1D7FF + }, + { + 'begin': 0xFF000, + 'end': 0xFFFFD + }, + { + 'begin': 0xFE00, + 'end': 0xFE0F + }, + { + 'begin': 0xE0000, + 'end': 0xE007F + }, + { + 'begin': 0x1900, + 'end': 0x194F + }, + { + 'begin': 0x1950, + 'end': 0x197F + }, + { + 'begin': 0x1980, + 'end': 0x19DF + }, + { + 'begin': 0x1A00, + 'end': 0x1A1F + }, + { + 'begin': 0x2C00, + 'end': 0x2C5F + }, + { + 'begin': 0x2D30, + 'end': 0x2D7F + }, + { + 'begin': 0x4DC0, + 'end': 0x4DFF + }, + { + 'begin': 0xA800, + 'end': 0xA82F + }, + { + 'begin': 0x10000, + 'end': 0x1007F + }, + { + 'begin': 0x10140, + 'end': 0x1018F + }, + { + 'begin': 0x10380, + 'end': 0x1039F + }, + { + 'begin': 0x103A0, + 'end': 0x103DF + }, + { + 'begin': 0x10450, + 'end': 0x1047F + }, + { + 'begin': 0x10480, + 'end': 0x104AF + }, + { + 'begin': 0x10800, + 'end': 0x1083F + }, + { + 'begin': 0x10A00, + 'end': 0x10A5F + }, + { + 'begin': 0x1D300, + 'end': 0x1D35F + }, + { + 'begin': 0x12000, + 'end': 0x123FF + }, + { + 'begin': 0x1D360, + 'end': 0x1D37F + }, + { + 'begin': 0x1B80, + 'end': 0x1BBF + }, + { + 'begin': 0x1C00, + 'end': 0x1C4F + }, + { + 'begin': 0x1C50, + 'end': 0x1C7F + }, + { + 'begin': 0xA880, + 'end': 0xA8DF + }, + { + 'begin': 0xA900, + 'end': 0xA92F + }, + { + 'begin': 0xA930, + 'end': 0xA95F + }, + { + 'begin': 0xAA00, + 'end': 0xAA5F + }, + { + 'begin': 0x10190, + 'end': 0x101CF + }, + { + 'begin': 0x101D0, + 'end': 0x101FF + }, + { + 'begin': 0x102A0, + 'end': 0x102DF + }, + { + 'begin': 0x1F030, + 'end': 0x1F09F + } + ]; + + function getUnicodeRangeFor(value) { + for (var i = 0, ii = UnicodeRanges.length; i < ii; i++) { + var range = UnicodeRanges[i]; + if (value >= range.begin && value < range.end) { + return i; + } + } + return -1; + } + + function isRTLRangeFor(value) { + var range = UnicodeRanges[13]; + if (value >= range.begin && value < range.end) { + return true; + } + range = UnicodeRanges[11]; + if (value >= range.begin && value < range.end) { + return true; + } + 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'; + }); + + function reverseIfRtl(chars) { + var 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]; + } + return s; + } + + exports.mapSpecialUnicodeValues = mapSpecialUnicodeValues; + exports.reverseIfRtl = reverseIfRtl; + exports.getUnicodeRangeFor = getUnicodeRangeFor; + exports.getNormalizedUnicodes = getNormalizedUnicodes; + exports.getUnicodeForGlyph = getUnicodeForGlyph; + + /***/ + }), + /* 9 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + var ArithmeticDecoder = function ArithmeticDecoderClosure() { + var 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 + }]; + + function ArithmeticDecoder(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; + } + + ArithmeticDecoder.prototype = { + byteIn: function ArithmeticDecoder_byteIn() { + var data = this.data; + var bp = this.bp; + if (data[bp] === 0xFF) { + var b1 = data[bp + 1]; + if (b1 > 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: function ArithmeticDecoder_readBit(contexts, pos) { + var cx_index = contexts[pos] >> 1, + cx_mps = contexts[pos] & 1; + var qeTableIcx = QeTable[cx_index]; + var qeIcx = qeTableIcx.qe; + var d; + var 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; + } + }; + return ArithmeticDecoder; + }(); + exports.ArithmeticDecoder = ArithmeticDecoder; + + /***/ + }), + /* 10 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.CFFCompiler = exports.CFFPrivateDict = exports.CFFTopDict = exports.CFFCharset = exports.CFFIndex = exports.CFFStrings = exports.CFFHeader = exports.CFF = exports.CFFParser = exports.CFFStandardStrings = undefined; + + var _util = __w_pdfjs_require__(0); + + var _charsets = __w_pdfjs_require__(21); + + var _encodings = __w_pdfjs_require__(4); + + 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']; + 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 + }]; + + function CFFParser(file, properties, seacAnalysisEnabled) { + this.bytes = file.getBytes(); + this.properties = properties; + this.seacAnalysisEnabled = !!seacAnalysisEnabled; + } + + CFFParser.prototype = { + parse: function CFFParser_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'); + if (fontMatrix) { + properties.fontMatrix = fontMatrix; + } + var fontBBox = topDict.getByName('FontBBox'); + if (fontBBox) { + properties.ascent = Math.max(fontBBox[3], fontBBox[1]); + properties.descent = Math.min(fontBBox[1], fontBBox[3]); + properties.ascentScaled = true; + } + var charset, encoding; + if (cff.isCIDFont) { + var fdArrayIndex = this.parseIndex(topDict.getByName('FDArray')).obj; + 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); + } + 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); + } + 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: function CFFParser_parseHeader() { + var bytes = this.bytes; + var bytesLength = bytes.length; + var 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; + } + 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 + }; + }, + parseDict: function CFFParser_parseDict(dict) { + var pos = 0; + + function parseOperand() { + var 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; + } + (0, _util.warn)('CFFParser_parseDict: "' + value + '" is a reserved command.'); + return NaN; + } + + function parseFloatOperand() { + var str = ''; + var eof = 15; + var lookup = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'E', 'E-', null, '-']; + var length = dict.length; + while (pos < length) { + var b = dict[pos++]; + var b1 = b >> 4; + var b2 = b & 15; + if (b1 === eof) { + break; + } + str += lookup[b1]; + if (b2 === eof) { + break; + } + str += lookup[b2]; + } + return parseFloat(str); + } + + var operands = []; + var entries = []; + pos = 0; + var end = dict.length; + while (pos < end) { + var b = dict[pos]; + if (b <= 21) { + if (b === 12) { + b = b << 8 | dict[++pos]; + } + entries.push([b, operands]); + operands = []; + ++pos; + } else { + operands.push(parseOperand()); + } + } + return entries; + }, + parseIndex: function CFFParser_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++]; + } + offsets.push(startPos + offset); + } + end = offsets[count]; + } + 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: function CFFParser_parseNameIndex(index) { + var names = []; + for (var i = 0, ii = index.count; i < ii; ++i) { + var name = index.get(i); + var length = Math.min(name.length, 127); + var data = []; + for (var j = 0; j < length; ++j) { + var c = name[j]; + if (j === 0 && c === 0) { + data[j] = c; + continue; + } + if (c < 33 || c > 126 || c === 91 || c === 93 || c === 40 || c === 41 || c === 123 || c === 125 || c === 60 || c === 62 || c === 47 || c === 37 || c === 35) { + data[j] = 95; + continue; + } + data[j] = c; + } + names.push((0, _util.bytesToString)(data)); + } + return names; + }, + parseStringIndex: function CFFParser_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: function CFFParser_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: function CFFParser_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; + } + } + 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) { + var subrsIndex; + if (value === 10) { + subrsIndex = localSubrIndex; + } else { + subrsIndex = globalSubrIndex; + } + 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); + 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 (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; + } + } + } + state.stackSize = stackSize; + return true; + }, + parseCharStrings: function parseCharStrings(_ref) { + var charStrings = _ref.charStrings, + localSubrIndex = _ref.localSubrIndex, + globalSubrIndex = _ref.globalSubrIndex, + fdSelect = _ref.fdSelect, + fdArray = _ref.fdArray, + privateDict = _ref.privateDict; + + var seacs = []; + var widths = []; + var count = charStrings.count; + 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 + }; + var valid = true; + var localSubrToUse = null; + var privateDictToUse = privateDict; + if (fdSelect && fdArray.length) { + var fdIndex = fdSelect.getFDIndex(i); + if (fdIndex === -1) { + (0, _util.warn)('Glyph index is not in fd select.'); + valid = false; + } + if (fdIndex >= fdArray.length) { + (0, _util.warn)('Invalid fd index for glyph index.'); + valid = false; + } + if (valid) { + privateDictToUse = fdArray[fdIndex].privateDict; + localSubrToUse = privateDictToUse.subrsIndex; + } + } else if (localSubrIndex) { + localSubrToUse = localSubrIndex; + } + if (valid) { + valid = this.parseCharString(state, charstring, localSubrToUse, globalSubrIndex); + } + if (state.width !== null) { + var nominalWidth = privateDictToUse.getByName('nominalWidthX'); + widths[i] = nominalWidth + state.width; + } else { + var defaultWidth = privateDictToUse.getByName('defaultWidthX'); + widths[i] = defaultWidth; + } + if (state.seac !== null) { + seacs[i] = state.seac; + } + if (!valid) { + charStrings.set(i, new Uint8Array([14])); + } + } + return { + charStrings: charStrings, + seacs: seacs, + widths: widths + }; + }, + + emptyPrivateDictionary: function CFFParser_emptyPrivateDictionary(parentDict) { + var privateDict = this.createDict(CFFPrivateDict, [], parentDict.strings); + parentDict.setByKey(18, [0, 0]); + parentDict.privateDict = privateDict; + }, + parsePrivateDict: function CFFParser_parsePrivateDict(parentDict) { + if (!parentDict.hasName('Private')) { + this.emptyPrivateDictionary(parentDict); + return; + } + var privateOffset = parentDict.getByName('Private'); + if (!(0, _util.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; + }, + parseCharsets: function CFFParser_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); + } + var bytes = this.bytes; + var start = pos; + var format = bytes[pos++]; + var charset = ['.notdef']; + var 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'); + } + var end = pos; + var raw = bytes.subarray(start, end); + return new CFFCharset(false, format, charset, raw); + }, + parseEncoding: function CFFParser_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: function CFFParser_parseFDSelect(pos, length) { + var start = pos; + var bytes = this.bytes; + var format = bytes[pos++]; + var fdSelect = [], + rawBytes; + var i, + invalidFirstGID = false; + switch (format) { + case 0: + for (i = 0; i < length; ++i) { + var id = bytes[pos++]; + fdSelect.push(id); + } + rawBytes = bytes.subarray(start, pos); + 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.'); + invalidFirstGID = true; + 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; + rawBytes = bytes.subarray(start, pos); + if (invalidFirstGID) { + rawBytes[3] = rawBytes[4] = 0; + } + 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(fdSelect, rawBytes); + } + }; + return CFFParser; + }(); + var CFF = function CFFClosure() { + function CFF() { + this.header = null; + this.names = []; + this.topDict = null; + this.strings = new CFFStrings(); + this.globalSubrIndex = null; + this.encoding = null; + this.charset = null; + this.charStrings = null; + this.fdArray = []; + this.fdSelect = null; + this.isCIDFont = false; + } + + return CFF; + }(); + var CFFHeader = function CFFHeaderClosure() { + function CFFHeader(major, minor, hdrSize, offSize) { + this.major = major; + this.minor = minor; + this.hdrSize = hdrSize; + this.offSize = offSize; + } + + return CFFHeader; + }(); + var CFFStrings = function CFFStringsClosure() { + function CFFStrings() { + this.strings = []; + } + + CFFStrings.prototype = { + get: function CFFStrings_get(index) { + if (index >= 0 && index <= 390) { + return CFFStandardStrings[index]; + } + if (index - 391 <= this.strings.length) { + return this.strings[index - 391]; + } + return CFFStandardStrings[0]; + }, + add: function CFFStrings_add(value) { + this.strings.push(value); + }, + get count() { + return this.strings.length; + } + }; + return CFFStrings; + }(); + var CFFIndex = function CFFIndexClosure() { + function CFFIndex() { + this.objects = []; + this.length = 0; + } + + CFFIndex.prototype = { + add: function CFFIndex_add(data) { + this.length += data.length; + this.objects.push(data); + }, + set: function CFFIndex_set(index, data) { + this.length += data.length - this.objects[index].length; + this.objects[index] = data; + }, + get: function CFFIndex_get(index) { + return this.objects[index]; + }, + get count() { + return this.objects.length; + } + }; + return CFFIndex; + }(); + var CFFDict = function CFFDictClosure() { + function CFFDict(tables, strings) { + this.keyToNameMap = tables.keyToNameMap; + this.nameToKeyMap = tables.nameToKeyMap; + this.defaults = tables.defaults; + this.types = tables.types; + this.opcodes = tables.opcodes; + this.order = tables.order; + this.strings = strings; + this.values = Object.create(null); + } + + CFFDict.prototype = { + setByKey: function CFFDict_setByKey(key, value) { + if (!(key in this.keyToNameMap)) { + return false; + } + var valueLength = value.length; + if (valueLength === 0) { + return true; + } + for (var 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]; + if (type === 'num' || type === 'sid' || type === 'offset') { + value = value[0]; + } + this.values[key] = value; + return true; + }, + setByName: function CFFDict_setByName(name, value) { + if (!(name in this.nameToKeyMap)) { + throw new _util.FormatError('Invalid dictionary name "' + name + '"'); + } + this.values[this.nameToKeyMap[name]] = value; + }, + hasName: function CFFDict_hasName(name) { + return this.nameToKeyMap[name] in this.values; + }, + getByName: function CFFDict_getByName(name) { + if (!(name in this.nameToKeyMap)) { + throw new _util.FormatError('Invalid dictionary name ' + name + '"'); + } + var key = this.nameToKeyMap[name]; + if (!(key in this.values)) { + return this.defaults[key]; + } + return this.values[key]; + }, + removeByName: function CFFDict_removeByName(name) { + delete this.values[this.nameToKeyMap[name]]; + } + }; + CFFDict.createTables = function CFFDict_createTables(layout) { + var tables = { + keyToNameMap: {}, + nameToKeyMap: {}, + defaults: {}, + types: {}, + opcodes: {}, + order: [] + }; + for (var i = 0, ii = layout.length; i < ii; ++i) { + var entry = layout[i]; + var key = (0, _util.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]; + tables.defaults[key] = entry[3]; + tables.opcodes[key] = (0, _util.isArray)(entry[0]) ? entry[0] : [entry[0]]; + tables.order.push(key); + } + return tables; + }; + return 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; + + function CFFTopDict(strings) { + if (tables === null) { + tables = CFFDict.createTables(layout); + } + CFFDict.call(this, tables, strings); + this.privateDict = null; + } + + CFFTopDict.prototype = Object.create(CFFDict.prototype); + return CFFTopDict; + }(); + 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; + + function CFFPrivateDict(strings) { + if (tables === null) { + tables = CFFDict.createTables(layout); + } + CFFDict.call(this, tables, strings); + this.subrsIndex = null; + } + + CFFPrivateDict.prototype = Object.create(CFFDict.prototype); + return CFFPrivateDict; + }(); + var CFFCharsetPredefinedTypes = { + ISO_ADOBE: 0, + EXPERT: 1, + EXPERT_SUBSET: 2 + }; + var CFFCharset = function CFFCharsetClosure() { + function CFFCharset(predefined, format, charset, raw) { + this.predefined = predefined; + this.format = format; + this.charset = charset; + this.raw = raw; + } + + return CFFCharset; + }(); + var CFFEncoding = function CFFEncodingClosure() { + function CFFEncoding(predefined, format, encoding, raw) { + this.predefined = predefined; + this.format = format; + this.encoding = encoding; + this.raw = raw; + } + + return CFFEncoding; + }(); + var CFFFDSelect = function CFFFDSelectClosure() { + function CFFFDSelect(fdSelect, raw) { + this.fdSelect = fdSelect; + this.raw = raw; + } + + CFFFDSelect.prototype = { + getFDIndex: function CFFFDSelect_get(glyphIndex) { + if (glyphIndex < 0 || glyphIndex >= this.fdSelect.length) { + return -1; + } + return this.fdSelect[glyphIndex]; + } + }; + return CFFFDSelect; + }(); + var CFFOffsetTracker = function CFFOffsetTrackerClosure() { + function CFFOffsetTracker() { + this.offsets = Object.create(null); + } + + CFFOffsetTracker.prototype = { + isTracking: function CFFOffsetTracker_isTracking(key) { + return key in this.offsets; + }, + track: function CFFOffsetTracker_track(key, location) { + if (key in this.offsets) { + throw new _util.FormatError('Already tracking location of ' + key); + } + this.offsets[key] = location; + }, + offset: function CFFOffsetTracker_offset(value) { + for (var key in this.offsets) { + this.offsets[key] += value; + } + }, + setEntryLocation: function CFFOffsetTracker_setEntryLocation(key, values, output) { + if (!(key in this.offsets)) { + throw new _util.FormatError('Not tracking location of ' + key); + } + var data = output.data; + var dataOffset = this.offsets[key]; + var 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; + 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]; + data[offset0] = 0x1d; + data[offset1] = value >> 24 & 0xFF; + data[offset2] = value >> 16 & 0xFF; + data[offset3] = value >> 8 & 0xFF; + data[offset4] = value & 0xFF; + } + } + }; + return CFFOffsetTracker; + }(); + var CFFCompiler = function CFFCompilerClosure() { + function CFFCompiler(cff) { + this.cff = cff; + } + + CFFCompiler.prototype = { + compile: function CFFCompiler_compile() { + var cff = this.cff; + var output = { + data: [], + length: 0, + add: function CFFCompiler_add(data) { + this.data = this.data.concat(data); + this.length = this.data.length; + } + }; + var header = this.compileHeader(cff.header); + output.add(header); + var nameIndex = this.compileNameIndex(cff.names); + output.add(nameIndex); + if (cff.isCIDFont) { + if (cff.topDict.hasName('FontMatrix')) { + var 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); + if (subDict.hasName('FontMatrix')) { + matrix = _util.Util.transform(matrix, subDict.getByName('FontMatrix')); + } + subDict.setByName('FontMatrix', matrix); + } + } + } + var 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); + output.add(stringIndex); + var 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); + topDictTracker.setEntryLocation('Encoding', [output.length], output); + output.add(encoding); + } + } + if (cff.charset && cff.topDict.hasName('charset')) { + if (cff.charset.predefined) { + topDictTracker.setEntryLocation('charset', [cff.charset.format], output); + } else { + var charset = this.compileCharset(cff.charset); + topDictTracker.setEntryLocation('charset', [output.length], output); + output.add(charset); + } + } + var 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.raw); + 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; + this.compilePrivateDicts(cff.fdArray, fontDictTrackers, output); + } + this.compilePrivateDicts([cff.topDict], [topDictTracker], output); + output.add([0]); + return output.data; + }, + encodeNumber: function CFFCompiler_encodeNumber(value) { + if (parseFloat(value) === parseInt(value, 10) && !isNaN(value)) { + return this.encodeInteger(value); + } + return this.encodeFloat(value); + }, + encodeFloat: function CFFCompiler_encodeFloat(num) { + var value = num.toString(); + var m = /\.(\d*?)(?:9{5,20}|0{5,20})\d{0,2}(?:e(.+)|$)/.exec(value); + if (m) { + var epsilon = parseFloat('1e' + ((m[2] ? +m[2] : 0) + m[1].length)); + value = (Math.round(num * epsilon) / epsilon).toString(); + } + var nibbles = ''; + var i, ii; + for (i = 0, ii = value.length; i < ii; ++i) { + var a = value[i]; + if (a === 'e') { + nibbles += value[++i] === '-' ? 'c' : 'b'; + } else if (a === '.') { + nibbles += 'a'; + } else if (a === '-') { + nibbles += 'e'; + } else { + nibbles += a; + } + } + nibbles += nibbles.length & 1 ? 'f' : 'ff'; + var out = [30]; + for (i = 0, ii = nibbles.length; i < ii; i += 2) { + out.push(parseInt(nibbles.substr(i, 2), 16)); + } + return out; + }, + encodeInteger: function CFFCompiler_encodeInteger(value) { + var code; + if (value >= -107 && value <= 107) { + code = [value + 139]; + } else if (value >= 108 && value <= 1131) { + value = value - 108; + code = [(value >> 8) + 247, value & 0xFF]; + } else if (value >= -1131 && value <= -108) { + value = -value - 108; + code = [(value >> 8) + 251, value & 0xFF]; + } else if (value >= -32768 && value <= 32767) { + code = [0x1c, value >> 8 & 0xFF, value & 0xFF]; + } else { + code = [0x1d, value >> 24 & 0xFF, value >> 16 & 0xFF, value >> 8 & 0xFF, value & 0xFF]; + } + return code; + }, + compileHeader: function CFFCompiler_compileHeader(header) { + return [header.major, header.minor, header.hdrSize, header.offSize]; + }, + compileNameIndex: function CFFCompiler_compileNameIndex(names) { + var nameIndex = new CFFIndex(); + for (var i = 0, ii = names.length; i < ii; ++i) { + nameIndex.add((0, _util.stringToBytes)(names[i])); + } + return this.compileIndex(nameIndex); + }, + compileTopDicts: function CFFCompiler_compileTopDicts(dicts, length, removeCidKeys) { + var fontDictTrackers = []; + var fdArrayIndex = new CFFIndex(); + for (var i = 0, ii = dicts.length; i < ii; ++i) { + var fontDict = dicts[i]; + if (removeCidKeys) { + fontDict.removeByName('CIDFontVersion'); + fontDict.removeByName('CIDFontRevision'); + fontDict.removeByName('CIDFontType'); + fontDict.removeByName('CIDCount'); + fontDict.removeByName('UIDBase'); + } + var fontDictTracker = new CFFOffsetTracker(); + var fontDictData = this.compileDict(fontDict, fontDictTracker); + fontDictTrackers.push(fontDictTracker); + fdArrayIndex.add(fontDictData); + fontDictTracker.offset(length); + } + fdArrayIndex = this.compileIndex(fdArrayIndex, fontDictTrackers); + return { + trackers: fontDictTrackers, + output: fdArrayIndex + }; + }, + compilePrivateDicts: function CFFCompiler_compilePrivateDicts(dicts, trackers, output) { + for (var i = 0, ii = dicts.length; i < ii; ++i) { + var fontDict = dicts[i]; + var 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; + privateDictTracker.offset(outputLength); + if (!privateDictData.length) { + outputLength = 0; + } + trackers[i].setEntryLocation('Private', [privateDictData.length, outputLength], output); + output.add(privateDictData); + if (privateDict.subrsIndex && privateDict.hasName('Subrs')) { + var subrs = this.compileIndex(privateDict.subrsIndex); + privateDictTracker.setEntryLocation('Subrs', [privateDictData.length], output); + output.add(subrs); + } + } + }, + compileDict: function CFFCompiler_compileDict(dict, offsetTracker) { + var out = []; + var order = dict.order; + for (var i = 0; i < order.length; ++i) { + var key = order[i]; + if (!(key in dict.values)) { + continue; + } + var values = dict.values[key]; + var types = dict.types[key]; + if (!(0, _util.isArray)(types)) { + types = [types]; + } + if (!(0, _util.isArray)(values)) { + values = [values]; + } + if (values.length === 0) { + continue; + } + for (var j = 0, jj = types.length; j < jj; ++j) { + var type = types[j]; + var value = values[j]; + switch (type) { + case 'num': + case 'sid': + out = out.concat(this.encodeNumber(value)); + break; + case 'offset': + var name = dict.keyToNameMap[key]; + if (!offsetTracker.isTracking(name)) { + offsetTracker.track(name, out.length); + } + out = out.concat([0x1d, 0, 0, 0, 0]); + break; + case 'array': + case 'delta': + out = out.concat(this.encodeNumber(value)); + for (var k = 1, kk = values.length; k < kk; ++k) { + out = out.concat(this.encodeNumber(values[k])); + } + break; + default: + throw new _util.FormatError('Unknown data type of ' + type); + } + } + out = out.concat(dict.opcodes[key]); + } + return out; + }, + compileStringIndex: function CFFCompiler_compileStringIndex(strings) { + var stringIndex = new CFFIndex(); + for (var i = 0, ii = strings.length; i < ii; ++i) { + stringIndex.add((0, _util.stringToBytes)(strings[i])); + } + return this.compileIndex(stringIndex); + }, + compileGlobalSubrIndex: function CFFCompiler_compileGlobalSubrIndex() { + var globalSubrIndex = this.cff.globalSubrIndex; + this.out.writeByteArray(this.compileIndex(globalSubrIndex)); + }, + compileCharStrings: function CFFCompiler_compileCharStrings(charStrings) { + return this.compileIndex(charStrings); + }, + compileCharset: function CFFCompiler_compileCharset(charset) { + return this.compileTypedArray(charset.raw); + }, + compileEncoding: function CFFCompiler_compileEncoding(encoding) { + return this.compileTypedArray(encoding.raw); + }, + compileFDSelect: function CFFCompiler_compileFDSelect(fdSelect) { + return this.compileTypedArray(fdSelect); + }, + compileTypedArray: function CFFCompiler_compileTypedArray(data) { + var out = []; + for (var i = 0, ii = data.length; i < ii; ++i) { + out[i] = data[i]; + } + return out; + }, + compileIndex: function CFFCompiler_compileIndex(index, trackers) { + trackers = trackers || []; + var objects = index.objects; + var count = objects.length; + if (count === 0) { + return [0, 0, 0]; + } + var data = [count >> 8 & 0xFF, count & 0xff]; + var lastOffset = 1, + i; + for (i = 0; i < count; ++i) { + lastOffset += objects[i].length; + } + var offsetSize; + if (lastOffset < 0x100) { + offsetSize = 1; + } else if (lastOffset < 0x10000) { + offsetSize = 2; + } else if (lastOffset < 0x1000000) { + offsetSize = 3; + } else { + offsetSize = 4; + } + data.push(offsetSize); + var relativeOffset = 1; + for (i = 0; i < count + 1; i++) { + if (offsetSize === 1) { + data.push(relativeOffset & 0xFF); + } else if (offsetSize === 2) { + data.push(relativeOffset >> 8 & 0xFF, relativeOffset & 0xFF); + } else if (offsetSize === 3) { + data.push(relativeOffset >> 16 & 0xFF, relativeOffset >> 8 & 0xFF, relativeOffset & 0xFF); + } else { + data.push(relativeOffset >>> 24 & 0xFF, relativeOffset >> 16 & 0xFF, relativeOffset >> 8 & 0xFF, relativeOffset & 0xFF); + } + if (objects[i]) { + relativeOffset += objects[i].length; + } + } + for (i = 0; i < count; i++) { + if (trackers[i]) { + trackers[i].offset(data.length); + } + for (var j = 0, jj = objects[i].length; j < jj; j++) { + data.push(objects[i][j]); + } + } + return data; + } + }; + return CFFCompiler; + }(); + exports.CFFStandardStrings = CFFStandardStrings; + exports.CFFParser = CFFParser; + exports.CFF = CFF; + exports.CFFHeader = CFFHeader; + exports.CFFStrings = CFFStrings; + exports.CFFIndex = CFFIndex; + exports.CFFCharset = CFFCharset; + exports.CFFTopDict = CFFTopDict; + exports.CFFPrivateDict = CFFPrivateDict; + exports.CFFCompiler = CFFCompiler; + + /***/ + }), + /* 11 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.ChunkedStreamManager = exports.ChunkedStream = undefined; + + var _util = __w_pdfjs_require__(0); + + var ChunkedStream = function ChunkedStreamClosure() { + function ChunkedStream(length, chunkSize, manager) { + this.bytes = new Uint8Array(length); + this.start = 0; + this.pos = 0; + this.end = length; + this.chunkSize = chunkSize; + this.loadedChunks = []; + this.numChunksLoaded = 0; + this.numChunks = Math.ceil(length / chunkSize); + this.manager = manager; + this.progressiveDataLength = 0; + this.lastSuccessfulEnsureByteChunk = -1; + } + + ChunkedStream.prototype = { + getMissingChunks: function ChunkedStream_getMissingChunks() { + var chunks = []; + for (var chunk = 0, n = this.numChunks; chunk < n; ++chunk) { + if (!this.loadedChunks[chunk]) { + chunks.push(chunk); + } + } + return chunks; + }, + getBaseStreams: function ChunkedStream_getBaseStreams() { + return [this]; + }, + allChunksLoaded: function ChunkedStream_allChunksLoaded() { + return this.numChunksLoaded === this.numChunks; + }, + onReceiveData: function ChunkedStream_onReceiveData(begin, chunk) { + var end = begin + chunk.byteLength; + if (begin % this.chunkSize !== 0) { + throw new Error('Bad begin offset: ' + begin); + } + var length = this.bytes.length; + if (end % this.chunkSize !== 0 && end !== length) { + throw new Error('Bad end offset: ' + end); + } + this.bytes.set(new Uint8Array(chunk), begin); + var chunkSize = this.chunkSize; + var beginChunk = Math.floor(begin / chunkSize); + var endChunk = Math.floor((end - 1) / chunkSize) + 1; + var curChunk; + for (curChunk = beginChunk; curChunk < endChunk; ++curChunk) { + if (!this.loadedChunks[curChunk]) { + this.loadedChunks[curChunk] = true; + ++this.numChunksLoaded; + } + } + }, + onReceiveProgressiveData: function ChunkedStream_onReceiveProgressiveData(data) { + var position = this.progressiveDataLength; + var beginChunk = Math.floor(position / this.chunkSize); + this.bytes.set(new Uint8Array(data), position); + position += data.byteLength; + this.progressiveDataLength = position; + var endChunk = position >= this.end ? this.numChunks : Math.floor(position / this.chunkSize); + var curChunk; + for (curChunk = beginChunk; curChunk < endChunk; ++curChunk) { + if (!this.loadedChunks[curChunk]) { + this.loadedChunks[curChunk] = true; + ++this.numChunksLoaded; + } + } + }, + ensureByte: function ChunkedStream_ensureByte(pos) { + var chunk = Math.floor(pos / this.chunkSize); + if (chunk === this.lastSuccessfulEnsureByteChunk) { + return; + } + if (!this.loadedChunks[chunk]) { + throw new _util.MissingDataException(pos, pos + 1); + } + this.lastSuccessfulEnsureByteChunk = chunk; + }, + ensureRange: function ChunkedStream_ensureRange(begin, end) { + if (begin >= end) { + return; + } + if (end <= this.progressiveDataLength) { + return; + } + var chunkSize = this.chunkSize; + var beginChunk = Math.floor(begin / chunkSize); + var endChunk = Math.floor((end - 1) / chunkSize) + 1; + for (var chunk = beginChunk; chunk < endChunk; ++chunk) { + if (!this.loadedChunks[chunk]) { + throw new _util.MissingDataException(begin, end); + } + } + }, + nextEmptyChunk: function ChunkedStream_nextEmptyChunk(beginChunk) { + var chunk, + numChunks = this.numChunks; + for (var i = 0; i < numChunks; ++i) { + chunk = (beginChunk + i) % numChunks; + if (!this.loadedChunks[chunk]) { + return chunk; + } + } + return null; + }, + hasChunk: function ChunkedStream_hasChunk(chunk) { + return !!this.loadedChunks[chunk]; + }, + get length() { + return this.end - this.start; + }, + get isEmpty() { + return this.length === 0; + }, + getByte: function ChunkedStream_getByte() { + var pos = this.pos; + if (pos >= this.end) { + return -1; + } + this.ensureByte(pos); + return this.bytes[this.pos++]; + }, + getUint16: function ChunkedStream_getUint16() { + var b0 = this.getByte(); + var b1 = this.getByte(); + if (b0 === -1 || b1 === -1) { + return -1; + } + return (b0 << 8) + b1; + }, + getInt32: function ChunkedStream_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: function ChunkedStream_getBytes(length) { + var bytes = this.bytes; + var pos = this.pos; + var strEnd = this.end; + if (!length) { + this.ensureRange(pos, strEnd); + return bytes.subarray(pos, strEnd); + } + var end = pos + length; + if (end > strEnd) { + end = strEnd; + } + this.ensureRange(pos, end); + this.pos = end; + return bytes.subarray(pos, end); + }, + peekByte: function ChunkedStream_peekByte() { + var peekedByte = this.getByte(); + this.pos--; + return peekedByte; + }, + peekBytes: function ChunkedStream_peekBytes(length) { + var bytes = this.getBytes(length); + this.pos -= bytes.length; + return bytes; + }, + getByteRange: function ChunkedStream_getBytes(begin, end) { + this.ensureRange(begin, end); + return this.bytes.subarray(begin, end); + }, + skip: function ChunkedStream_skip(n) { + if (!n) { + n = 1; + } + this.pos += n; + }, + reset: function ChunkedStream_reset() { + this.pos = this.start; + }, + moveStart: function ChunkedStream_moveStart() { + this.start = this.pos; + }, + makeSubStream: function ChunkedStream_makeSubStream(start, length, dict) { + this.ensureRange(start, start + length); + + function ChunkedStreamSubstream() { + } + + ChunkedStreamSubstream.prototype = Object.create(this); + ChunkedStreamSubstream.prototype.getMissingChunks = function () { + var chunkSize = this.chunkSize; + var beginChunk = Math.floor(this.start / chunkSize); + var endChunk = Math.floor((this.end - 1) / chunkSize) + 1; + var missingChunks = []; + for (var chunk = beginChunk; chunk < endChunk; ++chunk) { + if (!this.loadedChunks[chunk]) { + missingChunks.push(chunk); + } + } + return missingChunks; + }; + var subStream = new ChunkedStreamSubstream(); + subStream.pos = subStream.start = start; + subStream.end = start + length || this.end; + subStream.dict = dict; + return subStream; + } + }; + return ChunkedStream; + }(); + var ChunkedStreamManager = function ChunkedStreamManagerClosure() { + function ChunkedStreamManager(pdfNetworkStream, args) { + var chunkSize = args.rangeChunkSize; + var length = args.length; + this.stream = new ChunkedStream(length, chunkSize, this); + this.length = length; + this.chunkSize = chunkSize; + this.pdfNetworkStream = pdfNetworkStream; + this.url = args.url; + this.disableAutoFetch = args.disableAutoFetch; + this.msgHandler = args.msgHandler; + this.currRequestId = 0; + this.chunksNeededByRequest = Object.create(null); + this.requestsByChunk = Object.create(null); + this.promisesByRequest = Object.create(null); + this.progressiveDataLength = 0; + this.aborted = false; + this._loadedStreamCapability = (0, _util.createPromiseCapability)(); + } + + ChunkedStreamManager.prototype = { + onLoadedStream: function ChunkedStreamManager_getLoadedStream() { + return this._loadedStreamCapability.promise; + }, + sendRequest: function ChunkedStreamManager_sendRequest(begin, end) { + var _this = this; + + var rangeReader = this.pdfNetworkStream.getRangeReader(begin, end); + if (!rangeReader.isStreamingSupported) { + rangeReader.onProgress = this.onProgress.bind(this); + } + var chunks = [], + loaded = 0; + var manager = this; + var promise = new Promise(function (resolve, reject) { + var readChunk = function readChunk(chunk) { + try { + if (!chunk.done) { + var data = chunk.value; + chunks.push(data); + loaded += (0, _util.arrayByteLength)(data); + if (rangeReader.isStreamingSupported) { + manager.onProgress({loaded: loaded}); + } + rangeReader.read().then(readChunk, reject); + return; + } + var chunkData = (0, _util.arraysToBytes)(chunks); + chunks = null; + resolve(chunkData); + } catch (e) { + reject(e); + } + }; + rangeReader.read().then(readChunk, reject); + }); + promise.then(function (data) { + if (_this.aborted) { + return; + } + _this.onReceiveData({ + chunk: data, + begin: begin + }); + }); + }, + requestAllChunks: function ChunkedStreamManager_requestAllChunks() { + var missingChunks = this.stream.getMissingChunks(); + this._requestChunks(missingChunks); + return this._loadedStreamCapability.promise; + }, + _requestChunks: function ChunkedStreamManager_requestChunks(chunks) { + var requestId = this.currRequestId++; + var i, ii; + var chunksNeeded = Object.create(null); + this.chunksNeededByRequest[requestId] = chunksNeeded; + for (i = 0, ii = chunks.length; i < ii; i++) { + if (!this.stream.hasChunk(chunks[i])) { + chunksNeeded[chunks[i]] = true; + } + } + if ((0, _util.isEmptyObj)(chunksNeeded)) { + return Promise.resolve(); + } + var capability = (0, _util.createPromiseCapability)(); + this.promisesByRequest[requestId] = capability; + var chunksToRequest = []; + for (var chunk in chunksNeeded) { + chunk = chunk | 0; + if (!(chunk in this.requestsByChunk)) { + this.requestsByChunk[chunk] = []; + chunksToRequest.push(chunk); + } + this.requestsByChunk[chunk].push(requestId); + } + if (!chunksToRequest.length) { + return capability.promise; + } + var groupedChunksToRequest = this.groupChunks(chunksToRequest); + for (i = 0; i < groupedChunksToRequest.length; ++i) { + var groupedChunk = groupedChunksToRequest[i]; + var begin = groupedChunk.beginChunk * this.chunkSize; + var end = Math.min(groupedChunk.endChunk * this.chunkSize, this.length); + this.sendRequest(begin, end); + } + return capability.promise; + }, + getStream: function ChunkedStreamManager_getStream() { + return this.stream; + }, + requestRange: function ChunkedStreamManager_requestRange(begin, end) { + end = Math.min(end, this.length); + var beginChunk = this.getBeginChunk(begin); + var endChunk = this.getEndChunk(end); + var chunks = []; + for (var chunk = beginChunk; chunk < endChunk; ++chunk) { + chunks.push(chunk); + } + return this._requestChunks(chunks); + }, + requestRanges: function ChunkedStreamManager_requestRanges(ranges) { + ranges = ranges || []; + var chunksToRequest = []; + for (var i = 0; i < ranges.length; i++) { + var beginChunk = this.getBeginChunk(ranges[i].begin); + var endChunk = this.getEndChunk(ranges[i].end); + for (var chunk = beginChunk; chunk < endChunk; ++chunk) { + if (chunksToRequest.indexOf(chunk) < 0) { + chunksToRequest.push(chunk); + } + } + } + chunksToRequest.sort(function (a, b) { + return a - b; + }); + return this._requestChunks(chunksToRequest); + }, + groupChunks: function ChunkedStreamManager_groupChunks(chunks) { + var groupedChunks = []; + var beginChunk = -1; + var prevChunk = -1; + for (var i = 0; i < chunks.length; ++i) { + var chunk = chunks[i]; + if (beginChunk < 0) { + beginChunk = chunk; + } + if (prevChunk >= 0 && prevChunk + 1 !== chunk) { + groupedChunks.push({ + beginChunk: beginChunk, + endChunk: prevChunk + 1 + }); + beginChunk = chunk; + } + if (i + 1 === chunks.length) { + groupedChunks.push({ + beginChunk: beginChunk, + endChunk: chunk + 1 + }); + } + prevChunk = chunk; + } + return groupedChunks; + }, + onProgress: function ChunkedStreamManager_onProgress(args) { + var bytesLoaded = this.stream.numChunksLoaded * this.chunkSize + args.loaded; + this.msgHandler.send('DocProgress', { + loaded: bytesLoaded, + total: this.length + }); + }, + onReceiveData: function ChunkedStreamManager_onReceiveData(args) { + var chunk = args.chunk; + var isProgressive = args.begin === undefined; + var begin = isProgressive ? this.progressiveDataLength : args.begin; + var end = begin + chunk.byteLength; + var beginChunk = Math.floor(begin / this.chunkSize); + var endChunk = end < this.length ? Math.floor(end / this.chunkSize) : Math.ceil(end / this.chunkSize); + if (isProgressive) { + this.stream.onReceiveProgressiveData(chunk); + this.progressiveDataLength = end; + } else { + this.stream.onReceiveData(begin, chunk); + } + if (this.stream.allChunksLoaded()) { + this._loadedStreamCapability.resolve(this.stream); + } + var loadedRequests = []; + var i, requestId; + for (chunk = beginChunk; chunk < endChunk; ++chunk) { + var requestIds = this.requestsByChunk[chunk] || []; + delete this.requestsByChunk[chunk]; + for (i = 0; i < requestIds.length; ++i) { + requestId = requestIds[i]; + var chunksNeeded = this.chunksNeededByRequest[requestId]; + if (chunk in chunksNeeded) { + delete chunksNeeded[chunk]; + } + if (!(0, _util.isEmptyObj)(chunksNeeded)) { + continue; + } + loadedRequests.push(requestId); + } + } + if (!this.disableAutoFetch && (0, _util.isEmptyObj)(this.requestsByChunk)) { + var nextEmptyChunk; + if (this.stream.numChunksLoaded === 1) { + var lastChunk = this.stream.numChunks - 1; + if (!this.stream.hasChunk(lastChunk)) { + nextEmptyChunk = lastChunk; + } + } else { + nextEmptyChunk = this.stream.nextEmptyChunk(endChunk); + } + if ((0, _util.isInt)(nextEmptyChunk)) { + this._requestChunks([nextEmptyChunk]); + } + } + for (i = 0; i < loadedRequests.length; ++i) { + requestId = loadedRequests[i]; + var capability = this.promisesByRequest[requestId]; + delete this.promisesByRequest[requestId]; + capability.resolve(); + } + this.msgHandler.send('DocProgress', { + loaded: this.stream.numChunksLoaded * this.chunkSize, + total: this.length + }); + }, + onError: function ChunkedStreamManager_onError(err) { + this._loadedStreamCapability.reject(err); + }, + getBeginChunk: function ChunkedStreamManager_getBeginChunk(begin) { + var chunk = Math.floor(begin / this.chunkSize); + return chunk; + }, + getEndChunk: function ChunkedStreamManager_getEndChunk(end) { + var chunk = Math.floor((end - 1) / this.chunkSize) + 1; + return chunk; + }, + abort: function ChunkedStreamManager_abort() { + this.aborted = true; + if (this.pdfNetworkStream) { + this.pdfNetworkStream.cancelAllRequests('abort'); + } + for (var requestId in this.promisesByRequest) { + var capability = this.promisesByRequest[requestId]; + capability.reject(new Error('Request was aborted')); + } + } + }; + return ChunkedStreamManager; + }(); + exports.ChunkedStream = ChunkedStream; + exports.ChunkedStreamManager = ChunkedStreamManager; + + /***/ + }), + /* 12 */ + /***/ (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 = undefined; + + var _util = __w_pdfjs_require__(0); + + var _primitives = __w_pdfjs_require__(1); + + var _stream = __w_pdfjs_require__(2); + + 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; + return 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; + }(); + 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; + }(); + 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; + }(); + var calculateSHA384 = function calculateSHA384Closure() { + function hash(data, offset, length) { + return calculateSHA512(data, offset, length, true); + } + + return hash; + }(); + var NullCipher = function NullCipherClosure() { + function NullCipher() { + } + + NullCipher.prototype = { + decryptBlock: function NullCipher_decryptBlock(data) { + return data; + } + }; + return NullCipher; + }(); + var AES128Cipher = function AES128CipherClosure() { + var 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]); + var 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]); + var 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]); + var mixCol = new Uint8Array(256); + for (var i = 0; i < 256; i++) { + if (i < 128) { + mixCol[i] = i << 1; + } else { + mixCol[i] = i << 1 ^ 0x1b; + } + } + var 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]); + + function expandKey128(cipherKey) { + var b = 176, + result = new Uint8Array(b); + result.set(cipherKey); + for (var j = 16, i = 1; j < b; ++i) { + var 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 ^ rcon[i]; + for (var 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; + } + + function decrypt128(input, key) { + var state = new Uint8Array(16); + state.set(input); + var i, j, k; + var t, u, v; + for (j = 0, k = 160; j < 16; ++j, ++k) { + state[j] ^= key[k]; + } + for (i = 9; 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 (j = 0; j < 16; ++j) { + state[j] = inv_s[state[j]]; + } + for (j = 0, k = i * 16; j < 16; ++j, ++k) { + state[j] ^= key[k]; + } + for (j = 0; j < 16; j += 4) { + var s0 = mix[state[j]], + s1 = mix[state[j + 1]], + s2 = mix[state[j + 2]], + s3 = 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 (j = 0; j < 16; ++j) { + state[j] = inv_s[state[j]]; + state[j] ^= key[j]; + } + return state; + } + + function encrypt128(input, key) { + var t, u, v, k; + var state = new Uint8Array(16); + state.set(input); + for (j = 0; j < 16; ++j) { + state[j] ^= key[j]; + } + for (i = 1; i < 10; i++) { + for (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 (var j = 0; j < 16; j += 4) { + var s0 = state[j + 0], + s1 = state[j + 1]; + var s2 = state[j + 2], + s3 = state[j + 3]; + t = s0 ^ s1 ^ s2 ^ s3; + state[j + 0] ^= t ^ mixCol[s0 ^ s1]; + state[j + 1] ^= t ^ mixCol[s1 ^ s2]; + state[j + 2] ^= t ^ mixCol[s2 ^ s3]; + state[j + 3] ^= t ^ mixCol[s3 ^ s0]; + } + for (j = 0, k = i * 16; j < 16; ++j, ++k) { + state[j] ^= key[k]; + } + } + for (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 (j = 0, k = 160; j < 16; ++j, ++k) { + state[j] ^= key[k]; + } + return state; + } + + function AES128Cipher(key) { + this.key = expandKey128(key); + this.buffer = new Uint8Array(16); + this.bufferPosition = 0; + } + + function decryptBlock2(data, finalize) { + var i, + j, + ii, + sourceLength = data.length, + buffer = this.buffer, + bufferLength = this.bufferPosition, + result = [], + iv = this.iv; + for (i = 0; i < sourceLength; ++i) { + buffer[bufferLength] = data[i]; + ++bufferLength; + if (bufferLength < 16) { + continue; + } + var plain = decrypt128(buffer, this.key); + for (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([]); + } + var outputLength = 16 * result.length; + if (finalize) { + var lastBlock = result[result.length - 1]; + var psLen = lastBlock[15]; + if (psLen <= 16) { + for (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); + } + } + var output = new Uint8Array(outputLength); + for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) { + output.set(result[i], j); + } + return output; + } + + AES128Cipher.prototype = { + decryptBlock: function AES128Cipher_decryptBlock(data, finalize) { + var i, + sourceLength = data.length; + var buffer = this.buffer, + bufferLength = this.bufferPosition; + for (i = 0; bufferLength < 16 && i < sourceLength; ++i, ++bufferLength) { + buffer[bufferLength] = data[i]; + } + if (bufferLength < 16) { + this.bufferLength = bufferLength; + return new Uint8Array([]); + } + this.iv = buffer; + this.buffer = new Uint8Array(16); + this.bufferLength = 0; + this.decryptBlock = decryptBlock2; + return this.decryptBlock(data.subarray(16), finalize); + }, + encrypt: function AES128Cipher_encrypt(data, iv) { + var i, + j, + ii, + sourceLength = data.length, + buffer = this.buffer, + bufferLength = this.bufferPosition, + result = []; + if (!iv) { + iv = new Uint8Array(16); + } + for (i = 0; i < sourceLength; ++i) { + buffer[bufferLength] = data[i]; + ++bufferLength; + if (bufferLength < 16) { + continue; + } + for (j = 0; j < 16; ++j) { + buffer[j] ^= iv[j]; + } + var cipher = encrypt128(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([]); + } + var outputLength = 16 * result.length; + var output = new Uint8Array(outputLength); + for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) { + output.set(result[i], j); + } + return output; + } + }; + return AES128Cipher; + }(); + var AES256Cipher = function AES256CipherClosure() { + var 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]); + var 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]); + var mixCol = new Uint8Array(256); + for (var i = 0; i < 256; i++) { + if (i < 128) { + mixCol[i] = i << 1; + } else { + mixCol[i] = i << 1 ^ 0x1b; + } + } + var 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]); + + function expandKey256(cipherKey) { + var b = 240, + result = new Uint8Array(b); + var r = 1; + result.set(cipherKey); + for (var 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) { + var 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 (var 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; + } + + function decrypt256(input, key) { + var state = new Uint8Array(16); + state.set(input); + var i, j, k; + var t, u, v; + for (j = 0, k = 224; j < 16; ++j, ++k) { + state[j] ^= key[k]; + } + for (i = 13; 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 (j = 0; j < 16; ++j) { + state[j] = inv_s[state[j]]; + } + for (j = 0, k = i * 16; j < 16; ++j, ++k) { + state[j] ^= key[k]; + } + for (j = 0; j < 16; j += 4) { + var s0 = mix[state[j]], + s1 = mix[state[j + 1]], + s2 = mix[state[j + 2]], + s3 = 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 (j = 0; j < 16; ++j) { + state[j] = inv_s[state[j]]; + state[j] ^= key[j]; + } + return state; + } + + function encrypt256(input, key) { + var t, u, v, k; + var state = new Uint8Array(16); + state.set(input); + for (j = 0; j < 16; ++j) { + state[j] ^= key[j]; + } + for (i = 1; i < 14; i++) { + for (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 (var j = 0; j < 16; j += 4) { + var s0 = state[j + 0], + s1 = state[j + 1]; + var s2 = state[j + 2], + s3 = state[j + 3]; + t = s0 ^ s1 ^ s2 ^ s3; + state[j + 0] ^= t ^ mixCol[s0 ^ s1]; + state[j + 1] ^= t ^ mixCol[s1 ^ s2]; + state[j + 2] ^= t ^ mixCol[s2 ^ s3]; + state[j + 3] ^= t ^ mixCol[s3 ^ s0]; + } + for (j = 0, k = i * 16; j < 16; ++j, ++k) { + state[j] ^= key[k]; + } + } + for (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 (j = 0, k = 224; j < 16; ++j, ++k) { + state[j] ^= key[k]; + } + return state; + } + + function AES256Cipher(key) { + this.key = expandKey256(key); + this.buffer = new Uint8Array(16); + this.bufferPosition = 0; + } + + function decryptBlock2(data, finalize) { + var i, + j, + ii, + sourceLength = data.length, + buffer = this.buffer, + bufferLength = this.bufferPosition, + result = [], + iv = this.iv; + for (i = 0; i < sourceLength; ++i) { + buffer[bufferLength] = data[i]; + ++bufferLength; + if (bufferLength < 16) { + continue; + } + var plain = decrypt256(buffer, this.key); + for (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([]); + } + var outputLength = 16 * result.length; + if (finalize) { + var lastBlock = result[result.length - 1]; + var psLen = lastBlock[15]; + if (psLen <= 16) { + for (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); + } + } + var output = new Uint8Array(outputLength); + for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) { + output.set(result[i], j); + } + return output; + } + + AES256Cipher.prototype = { + decryptBlock: function AES256Cipher_decryptBlock(data, finalize, iv) { + var i, + sourceLength = data.length; + var buffer = this.buffer, + bufferLength = this.bufferPosition; + if (iv) { + this.iv = iv; + } else { + for (i = 0; bufferLength < 16 && i < sourceLength; ++i, ++bufferLength) { + buffer[bufferLength] = data[i]; + } + if (bufferLength < 16) { + this.bufferLength = bufferLength; + return new Uint8Array([]); + } + this.iv = buffer; + data = data.subarray(16); + } + this.buffer = new Uint8Array(16); + this.bufferLength = 0; + this.decryptBlock = decryptBlock2; + return this.decryptBlock(data, finalize); + }, + encrypt: function AES256Cipher_encrypt(data, iv) { + var i, + j, + ii, + sourceLength = data.length, + buffer = this.buffer, + bufferLength = this.bufferPosition, + result = []; + if (!iv) { + iv = new Uint8Array(16); + } + for (i = 0; i < sourceLength; ++i) { + buffer[bufferLength] = data[i]; + ++bufferLength; + if (bufferLength < 16) { + continue; + } + for (j = 0; j < 16; ++j) { + buffer[j] ^= iv[j]; + } + var cipher = encrypt256(buffer, this.key); + this.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([]); + } + var outputLength = 16 * result.length; + var output = new Uint8Array(outputLength); + for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) { + output.set(result[i], j); + } + return output; + } + }; + return 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; + }(); + 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; + }(); + 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); + } + }; + 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 (!(0, _util.isInt)(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 (!(0, _util.isInt)(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.AES128Cipher = AES128Cipher; + exports.AES256Cipher = AES256Cipher; + exports.ARCFourCipher = ARCFourCipher; + exports.CipherTransformFactory = CipherTransformFactory; + exports.PDF17 = PDF17; + exports.PDF20 = PDF20; + exports.calculateMD5 = calculateMD5; + exports.calculateSHA256 = calculateSHA256; + exports.calculateSHA384 = calculateSHA384; + exports.calculateSHA512 = calculateSHA512; + + /***/ + }), + /* 13 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PartialEvaluator = exports.OperatorList = undefined; + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + var _util = __w_pdfjs_require__(0); + + var _cmap = __w_pdfjs_require__(22); + + var _stream = __w_pdfjs_require__(2); + + var _primitives = __w_pdfjs_require__(1); + + var _fonts = __w_pdfjs_require__(25); + + var _encodings = __w_pdfjs_require__(4); + + var _unicode = __w_pdfjs_require__(8); + + var _standard_fonts = __w_pdfjs_require__(16); + + var _pattern = __w_pdfjs_require__(31); + + var _function = __w_pdfjs_require__(7); + + var _parser = __w_pdfjs_require__(5); + + var _bidi = __w_pdfjs_require__(20); + + var _colorspace = __w_pdfjs_require__(3); + + var _glyphlist = __w_pdfjs_require__(6); + + var _metrics = __w_pdfjs_require__(29); + + var _murmurhash = __w_pdfjs_require__(30); + + var _image = __w_pdfjs_require__(26); + + var PartialEvaluator = function PartialEvaluatorClosure() { + var DefaultPartialEvaluatorOptions = { + forceDataSchema: false, + maxImageSize: -1, + disableFontFace: false, + nativeImageDecoderSupport: _util.NativeImageDecoding.DECODE, + ignoreErrors: false + }; + + function NativeImageDecoder(xref, resources, handler, forceDataSchema) { + this.xref = xref; + this.resources = resources; + this.handler = handler; + this.forceDataSchema = forceDataSchema; + } + + NativeImageDecoder.prototype = { + canDecode: function canDecode(image) { + return image instanceof _stream.JpegStream && NativeImageDecoder.isDecodable(image, this.xref, this.resources); + }, + decode: function decode(image) { + var dict = image.dict; + var colorSpace = dict.get('ColorSpace', 'CS'); + colorSpace = _colorspace.ColorSpace.parse(colorSpace, this.xref, this.resources); + var numComps = colorSpace.numComps; + var decodePromise = this.handler.sendWithPromise('JpegDecode', [image.getIR(this.forceDataSchema), numComps]); + return decodePromise.then(function (message) { + var data = message.data; + return new _stream.Stream(data, 0, data.length, image.dict); + }); + } + }; + NativeImageDecoder.isSupported = function NativeImageDecoder_isSupported(image, xref, res) { + var dict = image.dict; + if (dict.has('DecodeParms') || dict.has('DP')) { + return false; + } + var cs = _colorspace.ColorSpace.parse(dict.get('ColorSpace', 'CS'), xref, res); + return (cs.name === 'DeviceGray' || cs.name === 'DeviceRGB') && cs.isDefaultDecode(dict.getArray('Decode', 'D')); + }; + NativeImageDecoder.isDecodable = function NativeImageDecoder_isDecodable(image, xref, res) { + var dict = image.dict; + if (dict.has('DecodeParms') || dict.has('DP')) { + return false; + } + var cs = _colorspace.ColorSpace.parse(dict.get('ColorSpace', 'CS'), xref, res); + return (cs.numComps === 1 || cs.numComps === 3) && cs.isDefaultDecode(dict.getArray('Decode', 'D')); + }; + + function PartialEvaluator(_ref) { + var _this = this; + + var pdfManager = _ref.pdfManager, + xref = _ref.xref, + handler = _ref.handler, + pageIndex = _ref.pageIndex, + idFactory = _ref.idFactory, + fontCache = _ref.fontCache, + builtInCMapCache = _ref.builtInCMapCache, + _ref$options = _ref.options, + options = _ref$options === undefined ? null : _ref$options; + + this.pdfManager = pdfManager; + this.xref = xref; + this.handler = handler; + this.pageIndex = pageIndex; + this.idFactory = idFactory; + this.fontCache = fontCache; + this.builtInCMapCache = builtInCMapCache; + this.options = options || DefaultPartialEvaluatorOptions; + this.fetchBuiltInCMap = function (name) { + var cachedCMap = _this.builtInCMapCache[name]; + if (cachedCMap) { + return Promise.resolve(cachedCMap); + } + return _this.handler.sendWithPromise('FetchBuiltInCMap', {name: name}).then(function (data) { + if (data.compressionType !== _util.CMapCompressionType.NONE) { + _this.builtInCMapCache[name] = data; + } + return data; + }); + }; + } + + var TIME_SLOT_DURATION_MS = 20; + var CHECK_TIME_EVERY = 100; + + function TimeSlotManager() { + this.reset(); + } + + TimeSlotManager.prototype = { + check: function TimeSlotManager_check() { + if (++this.checked < CHECK_TIME_EVERY) { + return false; + } + this.checked = 0; + return this.endTime <= Date.now(); + }, + reset: function TimeSlotManager_reset() { + this.endTime = Date.now() + TIME_SLOT_DURATION_MS; + this.checked = 0; + } + }; + + function normalizeBlendMode(value) { + if (!(0, _primitives.isName)(value)) { + return 'source-over'; + } + switch (value.name) { + case 'Normal': + case 'Compatible': + return 'source-over'; + case 'Multiply': + return 'multiply'; + case 'Screen': + return 'screen'; + case 'Overlay': + return 'overlay'; + case 'Darken': + return 'darken'; + case 'Lighten': + return 'lighten'; + case 'ColorDodge': + return 'color-dodge'; + case 'ColorBurn': + return 'color-burn'; + case 'HardLight': + return 'hard-light'; + case 'SoftLight': + return 'soft-light'; + case 'Difference': + return 'difference'; + case 'Exclusion': + return 'exclusion'; + case 'Hue': + return 'hue'; + case 'Saturation': + return 'saturation'; + case 'Color': + return 'color'; + case 'Luminosity': + return 'luminosity'; + } + (0, _util.warn)('Unsupported blend mode: ' + value.name); + return 'source-over'; + } + + var deferred = Promise.resolve(); + var TILING_PATTERN = 1, + SHADING_PATTERN = 2; + PartialEvaluator.prototype = { + clone: function clone() { + var newOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DefaultPartialEvaluatorOptions; + + var newEvaluator = Object.create(this); + newEvaluator.options = newOptions; + return newEvaluator; + }, + + hasBlendModes: function PartialEvaluator_hasBlendModes(resources) { + if (!(0, _primitives.isDict)(resources)) { + return false; + } + var processed = Object.create(null); + if (resources.objId) { + processed[resources.objId] = true; + } + var nodes = [resources], + xref = this.xref; + while (nodes.length) { + var key, i, ii; + var node = nodes.shift(); + var graphicStates = node.get('ExtGState'); + if ((0, _primitives.isDict)(graphicStates)) { + var graphicStatesKeys = graphicStates.getKeys(); + for (i = 0, ii = graphicStatesKeys.length; i < ii; i++) { + key = graphicStatesKeys[i]; + var graphicState = graphicStates.get(key); + var bm = graphicState.get('BM'); + if ((0, _primitives.isName)(bm) && bm.name !== 'Normal') { + return true; + } + } + } + var xObjects = node.get('XObject'); + if (!(0, _primitives.isDict)(xObjects)) { + continue; + } + var xObjectsKeys = xObjects.getKeys(); + for (i = 0, ii = xObjectsKeys.length; i < ii; i++) { + key = xObjectsKeys[i]; + var xObject = xObjects.getRaw(key); + if ((0, _primitives.isRef)(xObject)) { + if (processed[xObject.toString()]) { + continue; + } + xObject = xref.fetch(xObject); + } + if (!(0, _primitives.isStream)(xObject)) { + continue; + } + if (xObject.dict.objId) { + if (processed[xObject.dict.objId]) { + continue; + } + processed[xObject.dict.objId] = true; + } + var xResources = xObject.dict.get('Resources'); + if ((0, _primitives.isDict)(xResources) && (!xResources.objId || !processed[xResources.objId])) { + nodes.push(xResources); + if (xResources.objId) { + processed[xResources.objId] = true; + } + } + } + } + return false; + }, + buildFormXObject: function PartialEvaluator_buildFormXObject(resources, xobj, smask, operatorList, task, initialState) { + var dict = xobj.dict; + var matrix = dict.getArray('Matrix'); + var bbox = dict.getArray('BBox'); + var group = dict.get('Group'); + if (group) { + var groupOptions = { + matrix: matrix, + bbox: bbox, + smask: smask, + isolated: false, + knockout: false + }; + var groupSubtype = group.get('S'); + var colorSpace; + if ((0, _primitives.isName)(groupSubtype, 'Transparency')) { + groupOptions.isolated = group.get('I') || false; + groupOptions.knockout = group.get('K') || false; + colorSpace = group.has('CS') ? _colorspace.ColorSpace.parse(group.get('CS'), this.xref, resources) : null; + } + if (smask && smask.backdrop) { + colorSpace = colorSpace || _colorspace.ColorSpace.singletons.rgb; + smask.backdrop = colorSpace.getRgb(smask.backdrop, 0); + } + operatorList.addOp(_util.OPS.beginGroup, [groupOptions]); + } + operatorList.addOp(_util.OPS.paintFormXObjectBegin, [matrix, bbox]); + return this.getOperatorList({ + stream: xobj, + task: task, + resources: dict.get('Resources') || resources, + operatorList: operatorList, + initialState: initialState + }).then(function () { + operatorList.addOp(_util.OPS.paintFormXObjectEnd, []); + if (group) { + operatorList.addOp(_util.OPS.endGroup, [groupOptions]); + } + }); + }, + buildPaintImageXObject: function PartialEvaluator_buildPaintImageXObject(resources, image, inline, operatorList, cacheKey, imageCache) { + var _this2 = this; + + var dict = image.dict; + var w = dict.get('Width', 'W'); + var h = dict.get('Height', 'H'); + if (!(w && (0, _util.isNum)(w)) || !(h && (0, _util.isNum)(h))) { + (0, _util.warn)('Image dimensions are missing, or not numbers.'); + return; + } + var maxImageSize = this.options.maxImageSize; + if (maxImageSize !== -1 && w * h > maxImageSize) { + (0, _util.warn)('Image exceeded maximum allowed size and was removed.'); + return; + } + var imageMask = dict.get('ImageMask', 'IM') || false; + var 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); + var decode = dict.getArray('Decode', 'D'); + var inverseDecode = !!decode && decode[0] > 0; + imgData = _image.PDFImage.createMask(imgArray, width, height, image instanceof _stream.DecodeStream, inverseDecode); + imgData.cached = true; + args = [imgData]; + operatorList.addOp(_util.OPS.paintImageMaskXObject, args); + if (cacheKey) { + imageCache[cacheKey] = { + fn: _util.OPS.paintImageMaskXObject, + args: args + }; + } + return; + } + var softMask = dict.get('SMask', 'SM') || false; + var mask = dict.get('Mask') || false; + var SMALL_IMAGE_DIMENSIONS = 200; + if (inline && !softMask && !mask && !(image instanceof _stream.JpegStream) && w + h < SMALL_IMAGE_DIMENSIONS) { + var imageObj = new _image.PDFImage(this.xref, resources, image, inline, null, null); + imgData = imageObj.createImageData(true); + operatorList.addOp(_util.OPS.paintInlineImageXObject, [imgData]); + return; + } + var nativeImageDecoderSupport = this.options.nativeImageDecoderSupport; + var objId = 'img_' + this.idFactory.createObjId(); + operatorList.addDependency(objId); + args = [objId, w, h]; + if (nativeImageDecoderSupport !== _util.NativeImageDecoding.NONE && !softMask && !mask && image instanceof _stream.JpegStream && NativeImageDecoder.isSupported(image, this.xref, resources)) { + operatorList.addOp(_util.OPS.paintJpegXObject, args); + this.handler.send('obj', [objId, this.pageIndex, 'JpegStream', image.getIR(this.options.forceDataSchema)]); + if (cacheKey) { + imageCache[cacheKey] = { + fn: _util.OPS.paintJpegXObject, + args: args + }; + } + return; + } + var nativeImageDecoder = null; + if (nativeImageDecoderSupport === _util.NativeImageDecoding.DECODE && (image instanceof _stream.JpegStream || mask instanceof _stream.JpegStream || softMask instanceof _stream.JpegStream)) { + nativeImageDecoder = new NativeImageDecoder(this.xref, resources, this.handler, this.options.forceDataSchema); + } + _image.PDFImage.buildImage(this.handler, this.xref, resources, image, inline, nativeImageDecoder).then(function (imageObj) { + var imgData = imageObj.createImageData(false); + _this2.handler.send('obj', [objId, _this2.pageIndex, 'Image', imgData], [imgData.data.buffer]); + }).catch(function (reason) { + (0, _util.warn)('Unable to decode image: ' + reason); + _this2.handler.send('obj', [objId, _this2.pageIndex, 'Image', null]); + }); + operatorList.addOp(_util.OPS.paintImageXObject, args); + if (cacheKey) { + imageCache[cacheKey] = { + fn: _util.OPS.paintImageXObject, + args: args + }; + } + }, + handleSMask: function PartialEvaluator_handleSmask(smask, resources, operatorList, task, stateManager) { + var smaskContent = smask.get('G'); + var smaskOptions = { + subtype: smask.get('S').name, + backdrop: smask.get('BC') + }; + var transferObj = smask.get('TR'); + if ((0, _function.isPDFFunction)(transferObj)) { + var transferFn = _function.PDFFunction.parse(this.xref, transferObj); + var transferMap = new Uint8Array(256); + var tmp = new Float32Array(1); + for (var i = 0; i < 256; i++) { + tmp[0] = i / 255; + transferFn(tmp, 0, tmp, 0); + transferMap[i] = tmp[0] * 255 | 0; + } + smaskOptions.transferMap = transferMap; + } + return this.buildFormXObject(resources, smaskContent, smaskOptions, operatorList, task, stateManager.state.clone()); + }, + handleTilingType: function handleTilingType(fn, args, resources, pattern, patternDict, operatorList, task) { + var _this3 = this; + + var tilingOpList = new OperatorList(); + var resourcesArray = [patternDict.get('Resources'), resources]; + var patternResources = _primitives.Dict.merge(this.xref, resourcesArray); + return this.getOperatorList({ + stream: pattern, + task: task, + resources: patternResources, + operatorList: tilingOpList + }).then(function () { + return (0, _pattern.getTilingPatternIR)({ + fnArray: tilingOpList.fnArray, + argsArray: tilingOpList.argsArray + }, patternDict, args); + }).then(function (tilingPatternIR) { + operatorList.addDependencies(tilingOpList.dependencies); + operatorList.addOp(fn, tilingPatternIR); + }, function (reason) { + if (_this3.options.ignoreErrors) { + _this3.handler.send('UnsupportedFeature', {featureId: _util.UNSUPPORTED_FEATURES.unknown}); + (0, _util.warn)('handleTilingType - ignoring pattern: "' + reason + '".'); + return; + } + throw reason; + }); + }, + + handleSetFont: function PartialEvaluator_handleSetFont(resources, fontArgs, fontRef, operatorList, task, state) { + var _this4 = this; + + var fontName; + if (fontArgs) { + fontArgs = fontArgs.slice(); + fontName = fontArgs[0].name; + } + return this.loadFont(fontName, fontRef, resources).then(function (translated) { + if (!translated.font.isType3Font) { + return translated; + } + return translated.loadType3Data(_this4, resources, operatorList, task).then(function () { + return translated; + }).catch(function (reason) { + _this4.handler.send('UnsupportedFeature', {featureId: _util.UNSUPPORTED_FEATURES.font}); + return new TranslatedFont('g_font_error', new _fonts.ErrorFont('Type3 font load error: ' + reason), translated.font); + }); + }).then(function (translated) { + state.font = translated.font; + translated.send(_this4.handler); + return translated.loadedName; + }); + }, + handleText: function PartialEvaluator_handleText(chars, state) { + var _this5 = this; + + var font = state.font; + var glyphs = font.charsToGlyphs(chars); + var isAddToPathSet = !!(state.textRenderingMode & _util.TextRenderingMode.ADD_TO_PATH_FLAG); + if (font.data && (isAddToPathSet || this.options.disableFontFace)) { + var buildPath = function buildPath(fontChar) { + if (!font.renderer.hasBuiltPath(fontChar)) { + var path = font.renderer.getPathJs(fontChar); + _this5.handler.send('commonobj', [font.loadedName + '_path_' + fontChar, 'FontPath', path]); + } + }; + for (var i = 0, ii = glyphs.length; i < ii; i++) { + var glyph = glyphs[i]; + buildPath(glyph.fontChar); + var accent = glyph.accent; + if (accent && accent.fontChar) { + buildPath(accent.fontChar); + } + } + } + return glyphs; + }, + setGState: function PartialEvaluator_setGState(resources, gState, operatorList, task, stateManager) { + var _this6 = this; + + var gStateObj = []; + var gStateKeys = gState.getKeys(); + var promise = Promise.resolve(); + + var _loop = function _loop() { + var key = gStateKeys[i]; + var value = gState.get(key); + switch (key) { + case 'Type': + break; + case 'LW': + case 'LC': + case 'LJ': + case 'ML': + case 'D': + case 'RI': + case 'FL': + case 'CA': + case 'ca': + gStateObj.push([key, value]); + break; + case 'Font': + promise = promise.then(function () { + return _this6.handleSetFont(resources, null, value[0], operatorList, task, stateManager.state).then(function (loadedName) { + operatorList.addDependency(loadedName); + gStateObj.push([key, [loadedName, value[1]]]); + }); + }); + break; + case 'BM': + gStateObj.push([key, normalizeBlendMode(value)]); + break; + case 'SMask': + if ((0, _primitives.isName)(value, 'None')) { + gStateObj.push([key, false]); + break; + } + if ((0, _primitives.isDict)(value)) { + promise = promise.then(function () { + return _this6.handleSMask(value, resources, operatorList, task, stateManager); + }); + gStateObj.push([key, true]); + } else { + (0, _util.warn)('Unsupported SMask type'); + } + break; + case 'OP': + case 'op': + case 'OPM': + case 'BG': + case 'BG2': + case 'UCR': + case 'UCR2': + case 'TR': + case 'TR2': + case 'HT': + case 'SM': + case 'SA': + case 'AIS': + case 'TK': + (0, _util.info)('graphic state operator ' + key); + break; + default: + (0, _util.info)('Unknown graphic state operator ' + key); + break; + } + }; + + for (var i = 0, ii = gStateKeys.length; i < ii; i++) { + _loop(); + } + return promise.then(function () { + if (gStateObj.length > 0) { + operatorList.addOp(_util.OPS.setGState, [gStateObj]); + } + }); + }, + loadFont: function PartialEvaluator_loadFont(fontName, font, resources) { + var _this7 = this; + + function errorFont() { + return Promise.resolve(new TranslatedFont('g_font_error', new _fonts.ErrorFont('Font ' + fontName + ' is not available'), font)); + } + + var fontRef, + xref = this.xref; + if (font) { + if (!(0, _primitives.isRef)(font)) { + throw new Error('The "font" object should be a reference.'); + } + fontRef = font; + } else { + var fontRes = resources.get('Font'); + if (fontRes) { + fontRef = fontRes.getRaw(fontName); + } else { + (0, _util.warn)('fontRes not available'); + return errorFont(); + } + } + if (!fontRef) { + (0, _util.warn)('fontRef not available'); + return errorFont(); + } + if (this.fontCache.has(fontRef)) { + return this.fontCache.get(fontRef); + } + font = xref.fetchIfRef(fontRef); + if (!(0, _primitives.isDict)(font)) { + return errorFont(); + } + if (font.translated) { + return font.translated; + } + var fontCapability = (0, _util.createPromiseCapability)(); + var preEvaluatedFont = this.preEvaluateFont(font); + var descriptor = preEvaluatedFont.descriptor; + var fontRefIsRef = (0, _primitives.isRef)(fontRef), + fontID; + if (fontRefIsRef) { + fontID = fontRef.toString(); + } + if ((0, _primitives.isDict)(descriptor)) { + if (!descriptor.fontAliases) { + descriptor.fontAliases = Object.create(null); + } + var fontAliases = descriptor.fontAliases; + var hash = preEvaluatedFont.hash; + if (fontAliases[hash]) { + var aliasFontRef = fontAliases[hash].aliasRef; + if (fontRefIsRef && aliasFontRef && this.fontCache.has(aliasFontRef)) { + this.fontCache.putAlias(fontRef, aliasFontRef); + return this.fontCache.get(fontRef); + } + } else { + fontAliases[hash] = {fontID: _fonts.Font.getFontID()}; + } + if (fontRefIsRef) { + fontAliases[hash].aliasRef = fontRef; + } + fontID = fontAliases[hash].fontID; + } + if (fontRefIsRef) { + this.fontCache.put(fontRef, fontCapability.promise); + } else { + if (!fontID) { + fontID = this.idFactory.createObjId(); + } + this.fontCache.put('id_' + fontID, fontCapability.promise); + } + (0, _util.assert)(fontID, 'The "fontID" must be defined.'); + font.loadedName = 'g_' + this.pdfManager.docId + '_f' + fontID; + font.translated = fontCapability.promise; + var translatedPromise; + try { + translatedPromise = this.translateFont(preEvaluatedFont); + } catch (e) { + translatedPromise = Promise.reject(e); + } + translatedPromise.then(function (translatedFont) { + if (translatedFont.fontType !== undefined) { + var xrefFontStats = xref.stats.fontTypes; + xrefFontStats[translatedFont.fontType] = true; + } + fontCapability.resolve(new TranslatedFont(font.loadedName, translatedFont, font)); + }).catch(function (reason) { + _this7.handler.send('UnsupportedFeature', {featureId: _util.UNSUPPORTED_FEATURES.font}); + try { + var descriptor = preEvaluatedFont.descriptor; + 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; + } catch (ex) { + } + fontCapability.resolve(new TranslatedFont(font.loadedName, new _fonts.ErrorFont(reason instanceof Error ? reason.message : reason), font)); + }); + return fontCapability.promise; + }, + buildPath: function PartialEvaluator_buildPath(operatorList, fn, args) { + var lastIndex = operatorList.length - 1; + if (!args) { + args = []; + } + if (lastIndex < 0 || operatorList.fnArray[lastIndex] !== _util.OPS.constructPath) { + operatorList.addOp(_util.OPS.constructPath, [[fn], args]); + } else { + var opArgs = operatorList.argsArray[lastIndex]; + opArgs[0].push(fn); + Array.prototype.push.apply(opArgs[1], args); + } + }, + handleColorN: function PartialEvaluator_handleColorN(operatorList, fn, args, cs, patterns, resources, task) { + var patternName = args[args.length - 1]; + var pattern; + 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 (typeNum === TILING_PATTERN) { + var color = cs.base ? cs.base.getRgb(args, 0) : null; + return this.handleTilingType(fn, color, resources, pattern, dict, operatorList, task); + } else if (typeNum === SHADING_PATTERN) { + var shading = dict.get('Shading'); + var matrix = dict.getArray('Matrix'); + pattern = _pattern.Pattern.parseShading(shading, matrix, this.xref, resources, this.handler); + operatorList.addOp(fn, pattern.getIR()); + return Promise.resolve(); + } + return Promise.reject(new Error('Unknown PatternType: ' + typeNum)); + } + operatorList.addOp(fn, args); + return Promise.resolve(); + }, + getOperatorList: function getOperatorList(_ref2) { + var _this8 = this; + + var stream = _ref2.stream, + task = _ref2.task, + resources = _ref2.resources, + operatorList = _ref2.operatorList, + _ref2$initialState = _ref2.initialState, + initialState = _ref2$initialState === undefined ? null : _ref2$initialState; + + resources = resources || _primitives.Dict.empty; + initialState = initialState || new EvalState(); + if (!operatorList) { + throw new Error('getOperatorList: missing "operatorList" parameter'); + } + var self = this; + var xref = this.xref; + var imageCache = Object.create(null); + var xobjs = resources.get('XObject') || _primitives.Dict.empty; + var patterns = resources.get('Pattern') || _primitives.Dict.empty; + var stateManager = new StateManager(initialState); + var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager); + var timeSlotManager = new TimeSlotManager(); + + function closePendingRestoreOPS(argument) { + for (var i = 0, ii = preprocessor.savedStatesDepth; i < ii; i++) { + operatorList.addOp(_util.OPS.restore, []); + } + } + + return new Promise(function promiseBody(resolve, reject) { + var next = function next(promise) { + promise.then(function () { + try { + promiseBody(resolve, reject); + } catch (ex) { + reject(ex); + } + }, reject); + }; + task.ensureNotTerminated(); + timeSlotManager.reset(); + var stop, + operation = {}, + i, + ii, + cs; + while (!(stop = timeSlotManager.check())) { + operation.args = null; + if (!preprocessor.read(operation)) { + break; + } + var args = operation.args; + var fn = operation.fn; + switch (fn | 0) { + case _util.OPS.paintXObject: + var name = args[0].name; + if (!name) { + (0, _util.warn)('XObject must be referred to by name.'); + continue; + } + if (imageCache[name] !== undefined) { + operatorList.addOp(imageCache[name].fn, imageCache[name].args); + args = null; + continue; + } + var xobj = xobjs.get(name); + if (xobj) { + if (!(0, _primitives.isStream)(xobj)) { + throw new _util.FormatError('XObject should be a stream'); + } + var type = xobj.dict.get('Subtype'); + if (!(0, _primitives.isName)(type)) { + throw new _util.FormatError('XObject should have a Name subtype'); + } + if (type.name === 'Form') { + stateManager.save(); + next(self.buildFormXObject(resources, xobj, null, operatorList, task, stateManager.state.clone()).then(function () { + stateManager.restore(); + })); + return; + } else if (type.name === 'Image') { + self.buildPaintImageXObject(resources, xobj, false, operatorList, name, imageCache); + args = null; + continue; + } else if (type.name === 'PS') { + (0, _util.info)('Ignored XObject subtype PS'); + continue; + } else { + throw new _util.FormatError('Unhandled XObject subtype ' + type.name); + } + } + break; + case _util.OPS.setFont: + var fontSize = args[1]; + next(self.handleSetFont(resources, args, null, operatorList, task, stateManager.state).then(function (loadedName) { + operatorList.addDependency(loadedName); + operatorList.addOp(_util.OPS.setFont, [loadedName, fontSize]); + })); + return; + case _util.OPS.endInlineImage: + var cacheKey = args[0].cacheKey; + if (cacheKey) { + var cacheEntry = imageCache[cacheKey]; + if (cacheEntry !== undefined) { + operatorList.addOp(cacheEntry.fn, cacheEntry.args); + args = null; + continue; + } + } + self.buildPaintImageXObject(resources, args[0], true, operatorList, cacheKey, imageCache); + args = null; + continue; + case _util.OPS.showText: + args[0] = self.handleText(args[0], stateManager.state); + break; + case _util.OPS.showSpacedText: + var arr = args[0]; + var combinedGlyphs = []; + var arrLength = arr.length; + var state = stateManager.state; + for (i = 0; i < arrLength; ++i) { + var arrItem = arr[i]; + if ((0, _util.isString)(arrItem)) { + Array.prototype.push.apply(combinedGlyphs, self.handleText(arrItem, state)); + } else if ((0, _util.isNum)(arrItem)) { + combinedGlyphs.push(arrItem); + } + } + args[0] = combinedGlyphs; + fn = _util.OPS.showText; + break; + case _util.OPS.nextLineShowText: + operatorList.addOp(_util.OPS.nextLine); + args[0] = self.handleText(args[0], stateManager.state); + fn = _util.OPS.showText; + break; + case _util.OPS.nextLineSetSpacingShowText: + operatorList.addOp(_util.OPS.nextLine); + operatorList.addOp(_util.OPS.setWordSpacing, [args.shift()]); + operatorList.addOp(_util.OPS.setCharSpacing, [args.shift()]); + args[0] = self.handleText(args[0], stateManager.state); + fn = _util.OPS.showText; + break; + case _util.OPS.setTextRenderingMode: + stateManager.state.textRenderingMode = args[0]; + break; + case _util.OPS.setFillColorSpace: + stateManager.state.fillColorSpace = _colorspace.ColorSpace.parse(args[0], xref, resources); + continue; + case _util.OPS.setStrokeColorSpace: + stateManager.state.strokeColorSpace = _colorspace.ColorSpace.parse(args[0], xref, resources); + continue; + case _util.OPS.setFillColor: + cs = stateManager.state.fillColorSpace; + args = cs.getRgb(args, 0); + fn = _util.OPS.setFillRGBColor; + break; + case _util.OPS.setStrokeColor: + cs = stateManager.state.strokeColorSpace; + args = cs.getRgb(args, 0); + fn = _util.OPS.setStrokeRGBColor; + break; + case _util.OPS.setFillGray: + stateManager.state.fillColorSpace = _colorspace.ColorSpace.singletons.gray; + args = _colorspace.ColorSpace.singletons.gray.getRgb(args, 0); + fn = _util.OPS.setFillRGBColor; + break; + case _util.OPS.setStrokeGray: + stateManager.state.strokeColorSpace = _colorspace.ColorSpace.singletons.gray; + args = _colorspace.ColorSpace.singletons.gray.getRgb(args, 0); + fn = _util.OPS.setStrokeRGBColor; + break; + case _util.OPS.setFillCMYKColor: + stateManager.state.fillColorSpace = _colorspace.ColorSpace.singletons.cmyk; + args = _colorspace.ColorSpace.singletons.cmyk.getRgb(args, 0); + fn = _util.OPS.setFillRGBColor; + break; + case _util.OPS.setStrokeCMYKColor: + stateManager.state.strokeColorSpace = _colorspace.ColorSpace.singletons.cmyk; + args = _colorspace.ColorSpace.singletons.cmyk.getRgb(args, 0); + fn = _util.OPS.setStrokeRGBColor; + break; + case _util.OPS.setFillRGBColor: + stateManager.state.fillColorSpace = _colorspace.ColorSpace.singletons.rgb; + args = _colorspace.ColorSpace.singletons.rgb.getRgb(args, 0); + break; + case _util.OPS.setStrokeRGBColor: + stateManager.state.strokeColorSpace = _colorspace.ColorSpace.singletons.rgb; + args = _colorspace.ColorSpace.singletons.rgb.getRgb(args, 0); + break; + case _util.OPS.setFillColorN: + cs = stateManager.state.fillColorSpace; + if (cs.name === 'Pattern') { + next(self.handleColorN(operatorList, _util.OPS.setFillColorN, args, cs, patterns, resources, task)); + return; + } + args = cs.getRgb(args, 0); + fn = _util.OPS.setFillRGBColor; + break; + case _util.OPS.setStrokeColorN: + cs = stateManager.state.strokeColorSpace; + if (cs.name === 'Pattern') { + next(self.handleColorN(operatorList, _util.OPS.setStrokeColorN, args, cs, patterns, resources, task)); + return; + } + args = cs.getRgb(args, 0); + fn = _util.OPS.setStrokeRGBColor; + break; + case _util.OPS.shadingFill: + var shadingRes = resources.get('Shading'); + if (!shadingRes) { + throw new _util.FormatError('No shading resource found'); + } + var shading = shadingRes.get(args[0].name); + if (!shading) { + throw new _util.FormatError('No shading object found'); + } + var shadingFill = _pattern.Pattern.parseShading(shading, null, xref, resources, self.handler); + var patternIR = shadingFill.getIR(); + args = [patternIR]; + fn = _util.OPS.shadingFill; + break; + case _util.OPS.setGState: + var dictName = args[0]; + var extGState = resources.get('ExtGState'); + if (!(0, _primitives.isDict)(extGState) || !extGState.has(dictName.name)) { + break; + } + var gState = extGState.get(dictName.name); + next(self.setGState(resources, gState, operatorList, task, stateManager)); + return; + case _util.OPS.moveTo: + case _util.OPS.lineTo: + case _util.OPS.curveTo: + case _util.OPS.curveTo2: + case _util.OPS.curveTo3: + case _util.OPS.closePath: + self.buildPath(operatorList, fn, args); + continue; + case _util.OPS.rectangle: + self.buildPath(operatorList, fn, args); + continue; + case _util.OPS.markPoint: + case _util.OPS.markPointProps: + case _util.OPS.beginMarkedContent: + case _util.OPS.beginMarkedContentProps: + case _util.OPS.endMarkedContent: + case _util.OPS.beginCompat: + case _util.OPS.endCompat: + continue; + default: + if (args !== null) { + for (i = 0, ii = args.length; i < ii; i++) { + if (args[i] instanceof _primitives.Dict) { + break; + } + } + if (i < ii) { + (0, _util.warn)('getOperatorList - ignoring operator: ' + fn); + continue; + } + } + } + operatorList.addOp(fn, args); + } + if (stop) { + next(deferred); + return; + } + closePendingRestoreOPS(); + resolve(); + }).catch(function (reason) { + if (_this8.options.ignoreErrors) { + _this8.handler.send('UnsupportedFeature', {featureId: _util.UNSUPPORTED_FEATURES.unknown}); + (0, _util.warn)('getOperatorList - ignoring errors during task: ' + task.name); + closePendingRestoreOPS(); + return; + } + throw reason; + }); + }, + getTextContent: function getTextContent(_ref3) { + var _this9 = this; + + var stream = _ref3.stream, + task = _ref3.task, + resources = _ref3.resources, + _ref3$stateManager = _ref3.stateManager, + stateManager = _ref3$stateManager === undefined ? null : _ref3$stateManager, + _ref3$normalizeWhites = _ref3.normalizeWhitespace, + normalizeWhitespace = _ref3$normalizeWhites === undefined ? false : _ref3$normalizeWhites, + _ref3$combineTextItem = _ref3.combineTextItems, + combineTextItems = _ref3$combineTextItem === undefined ? false : _ref3$combineTextItem, + sink = _ref3.sink, + _ref3$seenStyles = _ref3.seenStyles, + seenStyles = _ref3$seenStyles === undefined ? Object.create(null) : _ref3$seenStyles; + + resources = resources || _primitives.Dict.empty; + stateManager = stateManager || new StateManager(new TextState()); + var WhitespaceRegexp = /\s/g; + var textContent = { + items: [], + styles: Object.create(null) + }; + var textContentItem = { + initialized: false, + str: [], + width: 0, + height: 0, + vertical: false, + lastAdvanceWidth: 0, + lastAdvanceHeight: 0, + textAdvanceScale: 0, + spaceWidth: 0, + fakeSpaceMin: Infinity, + fakeMultiSpaceMin: Infinity, + fakeMultiSpaceMax: -0, + textRunBreakAllowed: false, + transform: null, + fontName: null + }; + 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; + var skipEmptyXObjs = Object.create(null); + var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager); + var textState; + + function ensureTextContentItem() { + if (textContentItem.initialized) { + return textContentItem; + } + 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.fontMatrix !== _util.FONT_IDENTITY_MATRIX && textState.fontSize === 1) { + var glyphHeight = font.bbox[3] - font.bbox[1]; + if (glyphHeight > 0) { + glyphHeight = glyphHeight * textState.fontMatrix[3]; + tsm[3] *= glyphHeight; + } + } + var trm = _util.Util.transform(textState.ctm, _util.Util.transform(textState.textMatrix, tsm)); + textContentItem.transform = trm; + if (!font.vertical) { + textContentItem.width = 0; + textContentItem.height = Math.sqrt(trm[2] * trm[2] + trm[3] * trm[3]); + textContentItem.vertical = false; + } else { + textContentItem.width = Math.sqrt(trm[0] * trm[0] + trm[1] * trm[1]); + textContentItem.height = 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); + 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.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++; + } + return i < ii ? str.replace(WhitespaceRegexp, ' ') : str; + } + + function runBidiTransform(textChunk) { + var str = textChunk.str.join(''); + var bidiResult = (0, _bidi.bidi)(str, -1, textChunk.vertical); + return { + str: normalizeWhitespace ? replaceWhitespace(bidiResult.str) : bidiResult.str, + dir: bidiResult.dir, + width: textChunk.width, + height: textChunk.height, + transform: textChunk.transform, + fontName: textChunk.fontName + }; + } + + function handleSetFont(fontName, fontRef) { + return self.loadFont(fontName, fontRef, resources).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); + for (var i = 0; i < glyphs.length; i++) { + var glyph = glyphs[i]; + var glyphWidth = null; + if (font.vertical && glyph.vmetric) { + glyphWidth = glyph.vmetric[0]; + } else { + glyphWidth = glyph.width; + } + var glyphUnicode = glyph.unicode; + var NormalizedUnicodes = (0, _unicode.getNormalizedUnicodes)(); + if (NormalizedUnicodes[glyphUnicode] !== undefined) { + glyphUnicode = NormalizedUnicodes[glyphUnicode]; + } + glyphUnicode = (0, _unicode.reverseIfRtl)(glyphUnicode); + var charSpacing = textState.charSpacing; + if (glyph.isSpace) { + var wordSpacing = textState.wordSpacing; + charSpacing += wordSpacing; + if (wordSpacing > 0) { + addFakeSpaces(wordSpacing, textChunk.str); + } + } + var tx = 0; + var ty = 0; + 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; + } + textState.translateTextMatrix(tx, ty); + textChunk.str.push(glyphUnicode); + } + if (!font.vertical) { + textChunk.lastAdvanceWidth = width; + textChunk.width += width; + } else { + textChunk.lastAdvanceHeight = height; + textChunk.height += Math.abs(height); + } + return textChunk; + } + + function addFakeSpaces(width, strBuf) { + if (width < textContentItem.fakeSpaceMin) { + return; + } + if (width < textContentItem.fakeMultiSpaceMin) { + strBuf.push(' '); + return; + } + var fakeSpaces = Math.round(width / textContentItem.spaceWidth); + while (fakeSpaces-- > 0) { + strBuf.push(' '); + } + } + + function flushTextContentItem() { + if (!textContentItem.initialized) { + return; + } + textContentItem.width *= textContentItem.textAdvanceScale; + textContentItem.height *= textContentItem.textAdvanceScale; + textContent.items.push(runBidiTransform(textContentItem)); + textContentItem.initialized = false; + textContentItem.str.length = 0; + } + + function enqueueChunk() { + var length = textContent.items.length; + if (length > 0) { + sink.enqueue(textContent, length); + textContent.items = []; + textContent.styles = Object.create(null); + } + } + + var timeSlotManager = new TimeSlotManager(); + return new Promise(function promiseBody(resolve, reject) { + var next = function next(promise) { + enqueueChunk(); + Promise.all([promise, sink.ready]).then(function () { + try { + promiseBody(resolve, reject); + } catch (ex) { + reject(ex); + } + }, reject); + }; + task.ensureNotTerminated(); + timeSlotManager.reset(); + var stop, + operation = {}, + args = []; + while (!(stop = timeSlotManager.check())) { + args.length = 0; + operation.args = args; + if (!preprocessor.read(operation)) { + break; + } + textState = stateManager.state; + var fn = operation.fn; + args = operation.args; + var advance, diff; + var fontNameArg, fontSizeArg; + var isSameTextLine; + var items; + var offset; + var j, jj; + var breakTextRun; + var name; + var xobj; + var type; + var currentState; + var xObjStateManager; + var matrix; + var dictName; + var extGState; + var gState; + var gStateFont; + + var _ret2 = function () { + switch (fn | 0) { + case _util.OPS.setFont: + fontNameArg = args[0].name; + fontSizeArg = args[1]; + + if (textState.font && fontNameArg === textState.fontName && fontSizeArg === textState.fontSize) { + break; + } + flushTextContentItem(); + textState.fontName = fontNameArg; + textState.fontSize = fontSizeArg; + next(handleSetFont(fontNameArg, null)); + return { + v: void 0 + }; + 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: + 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]); + break; + case _util.OPS.setCharSpacing: + textState.charSpacing = args[0]; + break; + case _util.OPS.setWordSpacing: + textState.wordSpacing = args[0]; + break; + case _util.OPS.beginText: + flushTextContentItem(); + textState.textMatrix = _util.IDENTITY_MATRIX.slice(); + textState.textLineMatrix = _util.IDENTITY_MATRIX.slice(); + break; + case _util.OPS.showSpacedText: + items = args[0]; + + for (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; + breakTextRun = false; + + 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); + } + } + } + break; + case _util.OPS.showText: + buildTextContentItem(args[0]); + break; + case _util.OPS.nextLineShowText: + flushTextContentItem(); + textState.carriageReturn(); + buildTextContentItem(args[0]); + break; + case _util.OPS.nextLineSetSpacingShowText: + flushTextContentItem(); + textState.wordSpacing = args[0]; + textState.charSpacing = args[1]; + textState.carriageReturn(); + buildTextContentItem(args[2]); + break; + case _util.OPS.paintXObject: + flushTextContentItem(); + if (!xobjs) { + xobjs = resources.get('XObject') || _primitives.Dict.empty; + } + name = args[0].name; + + if (name in skipEmptyXObjs) { + break; + } + xobj = xobjs.get(name); + + if (!xobj) { + break; + } + if (!(0, _primitives.isStream)(xobj)) { + throw new _util.FormatError('XObject should be a stream'); + } + type = xobj.dict.get('Subtype'); + + if (!(0, _primitives.isName)(type)) { + throw new _util.FormatError('XObject should have a Name subtype'); + } + if (type.name !== 'Form') { + skipEmptyXObjs[name] = true; + break; + } + currentState = stateManager.state.clone(); + xObjStateManager = new StateManager(currentState); + matrix = xobj.dict.getArray('Matrix'); + + if ((0, _util.isArray)(matrix) && matrix.length === 6) { + xObjStateManager.transform(matrix); + } + enqueueChunk(); + var sinkWrapper = { + enqueueInvoked: false, + enqueue: function enqueue(chunk, size) { + this.enqueueInvoked = true; + sink.enqueue(chunk, size); + }, + + get desiredSize() { + return sink.desiredSize; + }, + get ready() { + return sink.ready; + } + }; + next(self.getTextContent({ + stream: xobj, + task: task, + resources: xobj.dict.get('Resources') || resources, + stateManager: xObjStateManager, + normalizeWhitespace: normalizeWhitespace, + combineTextItems: combineTextItems, + sink: sinkWrapper, + seenStyles: seenStyles + }).then(function () { + if (!sinkWrapper.enqueueInvoked) { + skipEmptyXObjs[name] = true; + } + })); + return { + v: void 0 + }; + case _util.OPS.setGState: + flushTextContentItem(); + dictName = args[0]; + extGState = resources.get('ExtGState'); + + if (!(0, _primitives.isDict)(extGState) || !(0, _primitives.isName)(dictName)) { + break; + } + gState = extGState.get(dictName.name); + + if (!(0, _primitives.isDict)(gState)) { + break; + } + gStateFont = gState.get('Font'); + + if (gStateFont) { + textState.fontName = null; + textState.fontSize = gStateFont[1]; + next(handleSetFont(null, gStateFont[0])); + return { + v: void 0 + }; + } + break; + } + }(); + + if ((typeof _ret2 === 'undefined' ? 'undefined' : _typeof(_ret2)) === "object") return _ret2.v; + if (textContent.items.length >= sink.desiredSize) { + stop = true; + break; + } + } + if (stop) { + next(deferred); + return; + } + flushTextContentItem(); + enqueueChunk(); + resolve(); + }).catch(function (reason) { + if (reason instanceof _util.AbortException) { + return; + } + if (_this9.options.ignoreErrors) { + (0, _util.warn)('getTextContent - ignoring errors during task: ' + task.name); + flushTextContentItem(); + enqueueChunk(); + return; + } + throw reason; + }); + }, + + extractDataStructures: function PartialEvaluator_extractDataStructures(dict, baseDict, properties) { + var _this10 = this; + + var xref = this.xref; + var toUnicode = dict.get('ToUnicode') || baseDict.get('ToUnicode'); + var toUnicodePromise = toUnicode ? this.readToUnicode(toUnicode) : Promise.resolve(undefined); + if (properties.composite) { + var cidSystemInfo = dict.get('CIDSystemInfo'); + if ((0, _primitives.isDict)(cidSystemInfo)) { + properties.cidSystemInfo = { + registry: cidSystemInfo.get('Registry'), + ordering: cidSystemInfo.get('Ordering'), + supplement: cidSystemInfo.get('Supplement') + }; + } + var cidToGidMap = dict.get('CIDToGIDMap'); + if ((0, _primitives.isStream)(cidToGidMap)) { + properties.cidToGidMap = this.readCidToGidMap(cidToGidMap); + } + } + var differences = []; + var baseEncodingName = null; + var encoding; + if (dict.has('Encoding')) { + encoding = dict.get('Encoding'); + if ((0, _primitives.isDict)(encoding)) { + baseEncodingName = encoding.get('BaseEncoding'); + baseEncodingName = (0, _primitives.isName)(baseEncodingName) ? baseEncodingName.name : null; + if (encoding.has('Differences')) { + var diffEncoding = encoding.get('Differences'); + var index = 0; + for (var j = 0, jj = diffEncoding.length; j < jj; j++) { + var data = xref.fetchIfRef(diffEncoding[j]); + if ((0, _util.isNum)(data)) { + index = data; + } else if ((0, _primitives.isName)(data)) { + differences[index++] = data.name; + } else { + throw new _util.FormatError('Invalid entry in \'Differences\' array: ' + data); + } + } + } + } else if ((0, _primitives.isName)(encoding)) { + baseEncodingName = encoding.name; + } else { + throw new _util.FormatError('Encoding is not a Name nor a Dict'); + } + if (baseEncodingName !== 'MacRomanEncoding' && baseEncodingName !== 'MacExpertEncoding' && baseEncodingName !== 'WinAnsiEncoding') { + baseEncodingName = null; + } + } + if (baseEncodingName) { + properties.defaultEncoding = (0, _encodings.getEncoding)(baseEncodingName).slice(); + } else { + var isSymbolicFont = !!(properties.flags & _fonts.FontFlags.Symbolic); + var isNonsymbolicFont = !!(properties.flags & _fonts.FontFlags.Nonsymbolic); + encoding = _encodings.StandardEncoding; + if (properties.type === 'TrueType' && !isNonsymbolicFont) { + encoding = _encodings.WinAnsiEncoding; + } + if (isSymbolicFont) { + encoding = _encodings.MacRomanEncoding; + if (!properties.file) { + if (/Symbol/i.test(properties.name)) { + encoding = _encodings.SymbolSetEncoding; + } else if (/Dingbats/i.test(properties.name)) { + encoding = _encodings.ZapfDingbatsEncoding; + } + } + } + properties.defaultEncoding = encoding; + } + properties.differences = differences; + properties.baseEncodingName = baseEncodingName; + properties.hasEncoding = !!baseEncodingName || differences.length > 0; + properties.dict = dict; + return toUnicodePromise.then(function (toUnicode) { + properties.toUnicode = toUnicode; + return _this10.buildToUnicode(properties); + }).then(function (toUnicode) { + properties.toUnicode = toUnicode; + return properties; + }); + }, + buildToUnicode: function PartialEvaluator_buildToUnicode(properties) { + properties.hasIncludedToUnicodeMap = !!properties.toUnicode && properties.toUnicode.length > 0; + if (properties.hasIncludedToUnicodeMap) { + return Promise.resolve(properties.toUnicode); + } + var toUnicode, charcode, glyphName; + if (!properties.composite) { + toUnicode = []; + var encoding = properties.defaultEncoding.slice(); + var baseEncodingName = properties.baseEncodingName; + var differences = properties.differences; + for (charcode in differences) { + glyphName = differences[charcode]; + if (glyphName === '.notdef') { + continue; + } + encoding[charcode] = glyphName; + } + var glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)(); + for (charcode in encoding) { + glyphName = encoding[charcode]; + if (glyphName === '') { + continue; + } else if (glyphsUnicodeMap[glyphName] === undefined) { + var code = 0; + switch (glyphName[0]) { + case 'G': + if (glyphName.length === 3) { + code = parseInt(glyphName.substr(1), 16); + } + break; + case 'g': + if (glyphName.length === 5) { + code = parseInt(glyphName.substr(1), 16); + } + break; + case 'C': + case 'c': + if (glyphName.length >= 3) { + code = +glyphName.substr(1); + } + break; + default: + var unicode = (0, _unicode.getUnicodeForGlyph)(glyphName, glyphsUnicodeMap); + if (unicode !== -1) { + code = unicode; + } + } + if (code) { + if (baseEncodingName && code === +charcode) { + var baseEncoding = (0, _encodings.getEncoding)(baseEncodingName); + if (baseEncoding && (glyphName = baseEncoding[charcode])) { + toUnicode[charcode] = String.fromCharCode(glyphsUnicodeMap[glyphName]); + continue; + } + } + toUnicode[charcode] = String.fromCharCode(code); + } + continue; + } + toUnicode[charcode] = String.fromCharCode(glyphsUnicodeMap[glyphName]); + } + return Promise.resolve(new _fonts.ToUnicodeMap(toUnicode)); + } + 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'))) { + var registry = properties.cidSystemInfo.registry; + var ordering = properties.cidSystemInfo.ordering; + var ucs2CMapName = _primitives.Name.get(registry + '-' + ordering + '-UCS2'); + return _cmap.CMapFactory.create({ + encoding: ucs2CMapName, + fetchBuiltInCMap: this.fetchBuiltInCMap, + useCMap: null + }).then(function (ucs2CMap) { + var cMap = properties.cMap; + toUnicode = []; + cMap.forEach(function (charcode, cid) { + if (cid > 0xffff) { + throw new _util.FormatError('Max size of CID is 65,535'); + } + var ucs2 = ucs2CMap.lookup(cid); + if (ucs2) { + toUnicode[charcode] = String.fromCharCode((ucs2.charCodeAt(0) << 8) + ucs2.charCodeAt(1)); + } + }); + return new _fonts.ToUnicodeMap(toUnicode); + }); + } + return Promise.resolve(new _fonts.IdentityToUnicodeMap(properties.firstChar, properties.lastChar)); + }, + readToUnicode: function PartialEvaluator_readToUnicode(toUnicode) { + var cmapObj = toUnicode; + if ((0, _primitives.isName)(cmapObj)) { + return _cmap.CMapFactory.create({ + encoding: cmapObj, + fetchBuiltInCMap: this.fetchBuiltInCMap, + useCMap: null + }).then(function (cmap) { + if (cmap instanceof _cmap.IdentityCMap) { + return new _fonts.IdentityToUnicodeMap(0, 0xFFFF); + } + return new _fonts.ToUnicodeMap(cmap.getMap()); + }); + } else if ((0, _primitives.isStream)(cmapObj)) { + return _cmap.CMapFactory.create({ + encoding: cmapObj, + fetchBuiltInCMap: this.fetchBuiltInCMap, + useCMap: null + }).then(function (cmap) { + if (cmap instanceof _cmap.IdentityCMap) { + return new _fonts.IdentityToUnicodeMap(0, 0xFFFF); + } + var map = new Array(cmap.length); + cmap.forEach(function (charCode, token) { + var str = []; + for (var k = 0; k < token.length; k += 2) { + var w1 = token.charCodeAt(k) << 8 | token.charCodeAt(k + 1); + if ((w1 & 0xF800) !== 0xD800) { + str.push(w1); + continue; + } + k += 2; + var w2 = token.charCodeAt(k) << 8 | token.charCodeAt(k + 1); + str.push(((w1 & 0x3ff) << 10) + (w2 & 0x3ff) + 0x10000); + } + map[charCode] = String.fromCharCode.apply(String, str); + }); + return new _fonts.ToUnicodeMap(map); + }); + } + return Promise.resolve(null); + }, + readCidToGidMap: function PartialEvaluator_readCidToGidMap(cidToGidStream) { + var glyphsData = cidToGidStream.getBytes(); + var result = []; + for (var j = 0, jj = glyphsData.length; j < jj; j++) { + var glyphID = glyphsData[j++] << 8 | glyphsData[j]; + if (glyphID === 0) { + continue; + } + var code = j >> 1; + result[code] = glyphID; + } + return result; + }, + extractWidths: function 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; + if (properties.composite) { + defaultWidth = dict.get('DW') || 1000; + widths = dict.get('W'); + if (widths) { + for (i = 0, ii = widths.length; i < ii; i++) { + start = xref.fetchIfRef(widths[i++]); + code = xref.fetchIfRef(widths[i]); + if ((0, _util.isArray)(code)) { + for (j = 0, jj = code.length; j < jj; j++) { + glyphsWidths[start++] = xref.fetchIfRef(code[j]); + } + } else { + var width = xref.fetchIfRef(widths[++i]); + for (j = start; j <= code; j++) { + glyphsWidths[j] = width; + } + } + } + } + if (properties.vertical) { + var vmetrics = dict.getArray('DW2') || [880, -1000]; + defaultVMetrics = [vmetrics[1], defaultWidth * 0.5, vmetrics[0]]; + vmetrics = dict.get('W2'); + if (vmetrics) { + for (i = 0, ii = vmetrics.length; i < ii; i++) { + start = xref.fetchIfRef(vmetrics[i++]); + code = xref.fetchIfRef(vmetrics[i]); + if ((0, _util.isArray)(code)) { + for (j = 0, jj = code.length; j < jj; j++) { + 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])]; + for (j = start; j <= code; j++) { + glyphsVMetrics[j] = vmetric; + } + } + } + } + } + } else { + var firstChar = properties.firstChar; + widths = dict.get('Widths'); + if (widths) { + j = firstChar; + for (i = 0, ii = widths.length; i < ii; i++) { + glyphsWidths[j++] = xref.fetchIfRef(widths[i]); + } + defaultWidth = parseFloat(descriptor.get('MissingWidth')) || 0; + } else { + var baseFontName = dict.get('BaseFont'); + if ((0, _primitives.isName)(baseFontName)) { + var metrics = this.getBaseFontMetrics(baseFontName.name); + glyphsWidths = this.buildCharCodeToWidth(metrics.widths, properties); + defaultWidth = metrics.defaultWidth; + } + } + } + var isMonospace = true; + var firstWidth = defaultWidth; + for (var glyph in glyphsWidths) { + var glyphWidth = glyphsWidths[glyph]; + if (!glyphWidth) { + continue; + } + if (!firstWidth) { + firstWidth = glyphWidth; + continue; + } + if (firstWidth !== glyphWidth) { + isMonospace = false; + break; + } + } + if (isMonospace) { + properties.flags |= _fonts.FontFlags.FixedPitch; + } + properties.defaultWidth = defaultWidth; + properties.widths = glyphsWidths; + properties.defaultVMetrics = defaultVMetrics; + properties.vmetrics = glyphsVMetrics; + }, + isSerifFont: function PartialEvaluator_isSerifFont(baseFontName) { + var fontNameWoStyle = baseFontName.split('-')[0]; + return fontNameWoStyle in (0, _standard_fonts.getSerifFonts)() || fontNameWoStyle.search(/serif/gi) !== -1; + }, + getBaseFontMetrics: function PartialEvaluator_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)(); + if (!(lookupName in Metrics)) { + if (this.isSerifFont(name)) { + lookupName = 'Times-Roman'; + } else { + lookupName = 'Helvetica'; + } + } + var glyphWidths = Metrics[lookupName]; + if ((0, _util.isNum)(glyphWidths)) { + defaultWidth = glyphWidths; + monospace = true; + } else { + widths = glyphWidths(); + } + return { + defaultWidth: defaultWidth, + monospace: monospace, + widths: widths + }; + }, + buildCharCodeToWidth: function PartialEvaluator_bulildCharCodeToWidth(widthsByGlyphName, properties) { + var widths = Object.create(null); + var differences = properties.differences; + var encoding = properties.defaultEncoding; + for (var charCode = 0; charCode < 256; charCode++) { + if (charCode in differences && widthsByGlyphName[differences[charCode]]) { + widths[charCode] = widthsByGlyphName[differences[charCode]]; + continue; + } + if (charCode in encoding && widthsByGlyphName[encoding[charCode]]) { + widths[charCode] = widthsByGlyphName[encoding[charCode]]; + continue; + } + } + return widths; + }, + preEvaluateFont: function PartialEvaluator_preEvaluateFont(dict) { + var baseDict = dict; + var type = dict.get('Subtype'); + if (!(0, _primitives.isName)(type)) { + throw new _util.FormatError('invalid font Subtype'); + } + var composite = false; + var uint8array; + if (type.name === 'Type0') { + var df = dict.get('DescendantFonts'); + if (!df) { + throw new _util.FormatError('Descendant fonts are not specified'); + } + dict = (0, _util.isArray)(df) ? this.xref.fetchIfRef(df[0]) : df; + type = dict.get('Subtype'); + if (!(0, _primitives.isName)(type)) { + throw new _util.FormatError('invalid font Subtype'); + } + composite = true; + } + var descriptor = dict.get('FontDescriptor'); + if (descriptor) { + var hash = new _murmurhash.MurmurHash3_64(); + var encoding = baseDict.getRaw('Encoding'); + if ((0, _primitives.isName)(encoding)) { + hash.update(encoding.name); + } else if ((0, _primitives.isRef)(encoding)) { + hash.update(encoding.toString()); + } else if ((0, _primitives.isDict)(encoding)) { + var keys = encoding.getKeys(); + for (var i = 0, ii = keys.length; i < ii; i++) { + var entry = encoding.getRaw(keys[i]); + if ((0, _primitives.isName)(entry)) { + hash.update(entry.name); + } else if ((0, _primitives.isRef)(entry)) { + hash.update(entry.toString()); + } else if ((0, _util.isArray)(entry)) { + var diffLength = entry.length, + diffBuf = new Array(diffLength); + for (var j = 0; j < diffLength; j++) { + var diffEntry = entry[j]; + if ((0, _primitives.isName)(diffEntry)) { + diffBuf[j] = diffEntry.name; + } else if ((0, _util.isNum)(diffEntry) || (0, _primitives.isRef)(diffEntry)) { + diffBuf[j] = diffEntry.toString(); + } + } + hash.update(diffBuf.join()); + } + } + } + var 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); + hash.update(uint8array); + } else if ((0, _primitives.isName)(toUnicode)) { + hash.update(toUnicode.name); + } + var widths = dict.get('Widths') || baseDict.get('Widths'); + if (widths) { + uint8array = new Uint8Array(new Uint32Array(widths).buffer); + hash.update(uint8array); + } + } + return { + descriptor: descriptor, + dict: dict, + baseDict: baseDict, + composite: composite, + type: type.name, + hash: hash ? hash.hexdigest() : '' + }; + }, + translateFont: function PartialEvaluator_translateFont(preEvaluatedFont) { + var _this11 = this; + + 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; + if (!descriptor) { + if (type === 'Type3') { + descriptor = new _primitives.Dict(null); + descriptor.set('FontName', _primitives.Name.get(type)); + descriptor.set('FontBBox', dict.getArray('FontBBox')); + } else { + var baseFontName = dict.get('BaseFont'); + if (!(0, _primitives.isName)(baseFontName)) { + 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); + properties = { + type: type, + name: baseFontName, + widths: metrics.widths, + defaultWidth: metrics.defaultWidth, + flags: flags, + firstChar: 0, + lastChar: maxCharIndex + }; + return this.extractDataStructures(dict, dict, properties).then(function (properties) { + properties.widths = _this11.buildCharCodeToWidth(metrics.widths, properties); + return new _fonts.Font(baseFontName, null, properties); + }); + } + } + var firstChar = dict.get('FirstChar') || 0; + var lastChar = dict.get('LastChar') || maxCharIndex; + var fontName = descriptor.get('FontName'); + var baseFont = dict.get('BaseFont'); + if ((0, _util.isString)(fontName)) { + fontName = _primitives.Name.get(fontName); + } + if ((0, _util.isString)(baseFont)) { + baseFont = _primitives.Name.get(baseFont); + } + if (type !== 'Type3') { + var fontNameStr = fontName && fontName.name; + var 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 + '"'); + if (fontNameStr && baseFontStr && baseFontStr.indexOf(fontNameStr) === 0) { + fontName = baseFont; + } + } + } + fontName = fontName || baseFont; + if (!(0, _primitives.isName)(fontName)) { + throw new _util.FormatError('invalid font name'); + } + var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3'); + if (fontFile) { + if (fontFile.dict) { + var subtype = fontFile.dict.get('Subtype'); + if (subtype) { + subtype = subtype.name; + } + var length1 = fontFile.dict.get('Length1'); + var length2 = fontFile.dict.get('Length2'); + var length3 = fontFile.dict.get('Length3'); + } + } + properties = { + type: type, + name: fontName.name, + subtype: subtype, + file: fontFile, + length1: length1, + length2: length2, + length3: length3, + loadedName: baseDict.loadedName, + composite: composite, + wideChars: composite, + fixedPitch: false, + fontMatrix: dict.getArray('FontMatrix') || _util.FONT_IDENTITY_MATRIX, + firstChar: firstChar || 0, + lastChar: lastChar || maxCharIndex, + bbox: descriptor.getArray('FontBBox'), + ascent: descriptor.get('Ascent'), + descent: descriptor.get('Descent'), + xHeight: descriptor.get('XHeight'), + capHeight: descriptor.get('CapHeight'), + flags: descriptor.get('Flags'), + italicAngle: descriptor.get('ItalicAngle'), + isType3Font: false + }; + var cMapPromise; + if (composite) { + var cidEncoding = baseDict.get('Encoding'); + if ((0, _primitives.isName)(cidEncoding)) { + properties.cidEncoding = cidEncoding.name; + } + cMapPromise = _cmap.CMapFactory.create({ + encoding: cidEncoding, + fetchBuiltInCMap: this.fetchBuiltInCMap, + useCMap: null + }).then(function (cMap) { + properties.cMap = cMap; + properties.vertical = properties.cMap.vertical; + }); + } else { + cMapPromise = Promise.resolve(undefined); + } + return cMapPromise.then(function () { + return _this11.extractDataStructures(dict, baseDict, properties); + }).then(function (properties) { + _this11.extractWidths(dict, descriptor, properties); + if (type === 'Type3') { + properties.isType3Font = true; + } + return new _fonts.Font(fontName.name, fontFile, properties); + }); + } + }; + return PartialEvaluator; + }(); + var TranslatedFont = function TranslatedFontClosure() { + function TranslatedFont(loadedName, font, dict) { + this.loadedName = loadedName; + this.font = font; + this.dict = dict; + this.type3Loaded = null; + this.sent = false; + } + + TranslatedFont.prototype = { + send: function send(handler) { + if (this.sent) { + return; + } + var fontData = this.font.exportData(); + handler.send('commonobj', [this.loadedName, 'Font', fontData]); + this.sent = true; + }, + loadType3Data: function loadType3Data(evaluator, resources, parentOperatorList, task) { + if (!this.font.isType3Font) { + throw new Error('Must be a Type3 font.'); + } + if (this.type3Loaded) { + return this.type3Loaded; + } + var type3Options = Object.create(evaluator.options); + type3Options.ignoreErrors = false; + var type3Evaluator = evaluator.clone(type3Options); + var translatedFont = this.font; + var loadCharProcsPromise = Promise.resolve(); + var charProcs = this.dict.get('CharProcs'); + var fontResources = this.dict.get('Resources') || resources; + var charProcKeys = charProcs.getKeys(); + var charProcOperatorList = Object.create(null); + + var _loop2 = function _loop2() { + var key = charProcKeys[i]; + loadCharProcsPromise = loadCharProcsPromise.then(function () { + var glyphStream = charProcs.get(key); + var operatorList = new OperatorList(); + return type3Evaluator.getOperatorList({ + stream: glyphStream, + task: task, + resources: fontResources, + operatorList: operatorList + }).then(function () { + charProcOperatorList[key] = operatorList.getIR(); + parentOperatorList.addDependencies(operatorList.dependencies); + }).catch(function (reason) { + (0, _util.warn)('Type3 font resource "' + key + '" is not available.'); + var operatorList = new OperatorList(); + charProcOperatorList[key] = operatorList.getIR(); + }); + }); + }; + + for (var i = 0, n = charProcKeys.length; i < n; ++i) { + _loop2(); + } + this.type3Loaded = loadCharProcsPromise.then(function () { + translatedFont.charProcOperatorList = charProcOperatorList; + }); + return this.type3Loaded; + } + }; + return TranslatedFont; + }(); + var OperatorList = function OperatorListClosure() { + var CHUNK_SIZE = 1000; + var CHUNK_SIZE_ABOUT = CHUNK_SIZE - 5; + + function getTransfers(queue) { + var transfers = []; + var fnArray = queue.fnArray, + argsArray = queue.argsArray; + for (var i = 0, ii = queue.length; i < ii; i++) { + switch (fnArray[i]) { + case _util.OPS.paintInlineImageXObject: + case _util.OPS.paintInlineImageXObjectGroup: + case _util.OPS.paintImageMaskXObject: + var arg = argsArray[i][0]; + if (!arg.cached) { + transfers.push(arg.data.buffer); + } + break; + } + } + return transfers; + } + + function OperatorList(intent, messageHandler, pageIndex) { + this.messageHandler = messageHandler; + this.fnArray = []; + this.argsArray = []; + this.dependencies = Object.create(null); + this._totalLength = 0; + this.pageIndex = pageIndex; + this.intent = intent; + } + + OperatorList.prototype = { + get length() { + return this.argsArray.length; + }, + get totalLength() { + return this._totalLength + this.length; + }, + addOp: function addOp(fn, args) { + this.fnArray.push(fn); + this.argsArray.push(args); + if (this.messageHandler) { + if (this.fnArray.length >= CHUNK_SIZE) { + this.flush(); + } else if (this.fnArray.length >= CHUNK_SIZE_ABOUT && (fn === _util.OPS.restore || fn === _util.OPS.endText)) { + this.flush(); + } + } + }, + addDependency: function addDependency(dependency) { + if (dependency in this.dependencies) { + return; + } + this.dependencies[dependency] = true; + this.addOp(_util.OPS.dependency, [dependency]); + }, + addDependencies: function addDependencies(dependencies) { + for (var key in dependencies) { + this.addDependency(key); + } + }, + addOpList: function addOpList(opList) { + _util.Util.extendObj(this.dependencies, opList.dependencies); + for (var i = 0, ii = opList.length; i < ii; i++) { + this.addOp(opList.fnArray[i], opList.argsArray[i]); + } + }, + getIR: function getIR() { + return { + fnArray: this.fnArray, + argsArray: this.argsArray, + length: this.length + }; + }, + flush: function flush(lastChunk) { + if (this.intent !== 'oplist') { + new QueueOptimizer().optimize(this); + } + var transfers = getTransfers(this); + var length = this.length; + this._totalLength += length; + this.messageHandler.send('RenderPageChunk', { + operatorList: { + fnArray: this.fnArray, + argsArray: this.argsArray, + lastChunk: lastChunk, + length: length + }, + pageIndex: this.pageIndex, + intent: this.intent + }, transfers); + this.dependencies = Object.create(null); + this.fnArray.length = 0; + this.argsArray.length = 0; + } + }; + return OperatorList; + }(); + var StateManager = function StateManagerClosure() { + function StateManager(initialState) { + this.state = initialState; + this.stateStack = []; + } + + StateManager.prototype = { + save: function save() { + var old = this.state; + this.stateStack.push(this.state); + this.state = old.clone(); + }, + restore: function restore() { + var prev = this.stateStack.pop(); + if (prev) { + this.state = prev; + } + }, + transform: function transform(args) { + this.state.ctm = _util.Util.transform(this.state.ctm, args); + } + }; + return StateManager; + }(); + var TextState = function TextStateClosure() { + function TextState() { + this.ctm = new Float32Array(_util.IDENTITY_MATRIX); + this.fontName = null; + this.fontSize = 0; + this.font = null; + this.fontMatrix = _util.FONT_IDENTITY_MATRIX; + this.textMatrix = _util.IDENTITY_MATRIX.slice(); + this.textLineMatrix = _util.IDENTITY_MATRIX.slice(); + this.charSpacing = 0; + this.wordSpacing = 0; + this.leading = 0; + this.textHScale = 1; + this.textRise = 0; + } + + TextState.prototype = { + setTextMatrix: function TextState_setTextMatrix(a, b, c, d, e, f) { + var m = this.textMatrix; + m[0] = a; + m[1] = b; + m[2] = c; + m[3] = d; + m[4] = e; + m[5] = f; + }, + setTextLineMatrix: function TextState_setTextMatrix(a, b, c, d, e, f) { + var m = this.textLineMatrix; + m[0] = a; + m[1] = b; + m[2] = c; + m[3] = d; + m[4] = e; + m[5] = f; + }, + translateTextMatrix: function TextState_translateTextMatrix(x, y) { + var m = this.textMatrix; + m[4] = m[0] * x + m[2] * y + m[4]; + m[5] = m[1] * x + m[3] * y + m[5]; + }, + translateTextLineMatrix: function TextState_translateTextMatrix(x, y) { + var m = this.textLineMatrix; + m[4] = m[0] * x + m[2] * y + m[4]; + m[5] = m[1] * x + m[3] * y + m[5]; + }, + calcTextLineMatrixAdvance: function TextState_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: function TextState_calcRendeMatrix(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: function TextState_carriageReturn() { + this.translateTextLineMatrix(0, -this.leading); + this.textMatrix = this.textLineMatrix.slice(); + }, + clone: function TextState_clone() { + var clone = Object.create(this); + clone.textMatrix = this.textMatrix.slice(); + clone.textLineMatrix = this.textLineMatrix.slice(); + clone.fontMatrix = this.fontMatrix.slice(); + return clone; + } + }; + return TextState; + }(); + var EvalState = function EvalStateClosure() { + function EvalState() { + this.ctm = new Float32Array(_util.IDENTITY_MATRIX); + this.font = null; + this.textRenderingMode = _util.TextRenderingMode.FILL; + this.fillColorSpace = _colorspace.ColorSpace.singletons.gray; + this.strokeColorSpace = _colorspace.ColorSpace.singletons.gray; + } + + EvalState.prototype = { + clone: function CanvasExtraState_clone() { + return Object.create(this); + } + }; + return EvalState; + }(); + var EvaluatorPreprocessor = function EvaluatorPreprocessorClosure() { + var getOPMap = (0, _util.getLookupTableFactory)(function (t) { + t['w'] = { + id: _util.OPS.setLineWidth, + numArgs: 1, + variableArgs: false + }; + t['J'] = { + id: _util.OPS.setLineCap, + numArgs: 1, + variableArgs: false + }; + t['j'] = { + id: _util.OPS.setLineJoin, + numArgs: 1, + variableArgs: false + }; + t['M'] = { + id: _util.OPS.setMiterLimit, + numArgs: 1, + variableArgs: false + }; + t['d'] = { + id: _util.OPS.setDash, + numArgs: 2, + variableArgs: false + }; + t['ri'] = { + id: _util.OPS.setRenderingIntent, + numArgs: 1, + variableArgs: false + }; + t['i'] = { + id: _util.OPS.setFlatness, + numArgs: 1, + variableArgs: false + }; + t['gs'] = { + id: _util.OPS.setGState, + numArgs: 1, + variableArgs: false + }; + t['q'] = { + id: _util.OPS.save, + numArgs: 0, + variableArgs: false + }; + t['Q'] = { + id: _util.OPS.restore, + numArgs: 0, + variableArgs: false + }; + t['cm'] = { + id: _util.OPS.transform, + numArgs: 6, + variableArgs: false + }; + t['m'] = { + id: _util.OPS.moveTo, + numArgs: 2, + variableArgs: false + }; + t['l'] = { + id: _util.OPS.lineTo, + numArgs: 2, + variableArgs: false + }; + t['c'] = { + id: _util.OPS.curveTo, + numArgs: 6, + variableArgs: false + }; + t['v'] = { + id: _util.OPS.curveTo2, + numArgs: 4, + variableArgs: false + }; + t['y'] = { + id: _util.OPS.curveTo3, + numArgs: 4, + variableArgs: false + }; + t['h'] = { + id: _util.OPS.closePath, + numArgs: 0, + variableArgs: false + }; + t['re'] = { + id: _util.OPS.rectangle, + numArgs: 4, + variableArgs: false + }; + t['S'] = { + id: _util.OPS.stroke, + numArgs: 0, + variableArgs: false + }; + t['s'] = { + id: _util.OPS.closeStroke, + numArgs: 0, + variableArgs: false + }; + t['f'] = { + id: _util.OPS.fill, + numArgs: 0, + variableArgs: false + }; + t['F'] = { + id: _util.OPS.fill, + numArgs: 0, + variableArgs: false + }; + t['f*'] = { + id: _util.OPS.eoFill, + numArgs: 0, + variableArgs: false + }; + t['B'] = { + id: _util.OPS.fillStroke, + numArgs: 0, + variableArgs: false + }; + t['B*'] = { + id: _util.OPS.eoFillStroke, + numArgs: 0, + variableArgs: false + }; + t['b'] = { + id: _util.OPS.closeFillStroke, + numArgs: 0, + variableArgs: false + }; + t['b*'] = { + id: _util.OPS.closeEOFillStroke, + numArgs: 0, + variableArgs: false + }; + t['n'] = { + id: _util.OPS.endPath, + numArgs: 0, + variableArgs: false + }; + t['W'] = { + id: _util.OPS.clip, + numArgs: 0, + variableArgs: false + }; + t['W*'] = { + id: _util.OPS.eoClip, + numArgs: 0, + variableArgs: false + }; + t['BT'] = { + id: _util.OPS.beginText, + numArgs: 0, + variableArgs: false + }; + t['ET'] = { + id: _util.OPS.endText, + numArgs: 0, + variableArgs: false + }; + t['Tc'] = { + id: _util.OPS.setCharSpacing, + numArgs: 1, + variableArgs: false + }; + t['Tw'] = { + id: _util.OPS.setWordSpacing, + numArgs: 1, + variableArgs: false + }; + t['Tz'] = { + id: _util.OPS.setHScale, + numArgs: 1, + variableArgs: false + }; + t['TL'] = { + id: _util.OPS.setLeading, + numArgs: 1, + variableArgs: false + }; + t['Tf'] = { + id: _util.OPS.setFont, + numArgs: 2, + variableArgs: false + }; + t['Tr'] = { + id: _util.OPS.setTextRenderingMode, + numArgs: 1, + variableArgs: false + }; + t['Ts'] = { + id: _util.OPS.setTextRise, + numArgs: 1, + variableArgs: false + }; + t['Td'] = { + id: _util.OPS.moveText, + numArgs: 2, + variableArgs: false + }; + t['TD'] = { + id: _util.OPS.setLeadingMoveText, + numArgs: 2, + variableArgs: false + }; + t['Tm'] = { + id: _util.OPS.setTextMatrix, + numArgs: 6, + variableArgs: false + }; + t['T*'] = { + id: _util.OPS.nextLine, + numArgs: 0, + variableArgs: false + }; + t['Tj'] = { + id: _util.OPS.showText, + numArgs: 1, + variableArgs: false + }; + t['TJ'] = { + id: _util.OPS.showSpacedText, + numArgs: 1, + variableArgs: false + }; + t['\''] = { + id: _util.OPS.nextLineShowText, + numArgs: 1, + variableArgs: false + }; + t['"'] = { + id: _util.OPS.nextLineSetSpacingShowText, + numArgs: 3, + variableArgs: false + }; + t['d0'] = { + id: _util.OPS.setCharWidth, + numArgs: 2, + variableArgs: false + }; + t['d1'] = { + id: _util.OPS.setCharWidthAndBounds, + numArgs: 6, + variableArgs: false + }; + t['CS'] = { + id: _util.OPS.setStrokeColorSpace, + numArgs: 1, + variableArgs: false + }; + t['cs'] = { + id: _util.OPS.setFillColorSpace, + numArgs: 1, + variableArgs: false + }; + t['SC'] = { + id: _util.OPS.setStrokeColor, + numArgs: 4, + variableArgs: true + }; + t['SCN'] = { + id: _util.OPS.setStrokeColorN, + numArgs: 33, + variableArgs: true + }; + t['sc'] = { + id: _util.OPS.setFillColor, + numArgs: 4, + variableArgs: true + }; + t['scn'] = { + id: _util.OPS.setFillColorN, + numArgs: 33, + variableArgs: true + }; + t['G'] = { + id: _util.OPS.setStrokeGray, + numArgs: 1, + variableArgs: false + }; + t['g'] = { + id: _util.OPS.setFillGray, + numArgs: 1, + variableArgs: false + }; + t['RG'] = { + id: _util.OPS.setStrokeRGBColor, + numArgs: 3, + variableArgs: false + }; + t['rg'] = { + id: _util.OPS.setFillRGBColor, + numArgs: 3, + variableArgs: false + }; + t['K'] = { + id: _util.OPS.setStrokeCMYKColor, + numArgs: 4, + variableArgs: false + }; + t['k'] = { + id: _util.OPS.setFillCMYKColor, + numArgs: 4, + variableArgs: false + }; + t['sh'] = { + id: _util.OPS.shadingFill, + numArgs: 1, + variableArgs: false + }; + t['BI'] = { + id: _util.OPS.beginInlineImage, + numArgs: 0, + variableArgs: false + }; + t['ID'] = { + id: _util.OPS.beginImageData, + numArgs: 0, + variableArgs: false + }; + t['EI'] = { + id: _util.OPS.endInlineImage, + numArgs: 1, + variableArgs: false + }; + t['Do'] = { + id: _util.OPS.paintXObject, + numArgs: 1, + variableArgs: false + }; + t['MP'] = { + id: _util.OPS.markPoint, + numArgs: 1, + variableArgs: false + }; + t['DP'] = { + id: _util.OPS.markPointProps, + numArgs: 2, + variableArgs: false + }; + t['BMC'] = { + id: _util.OPS.beginMarkedContent, + numArgs: 1, + variableArgs: false + }; + t['BDC'] = { + id: _util.OPS.beginMarkedContentProps, + numArgs: 2, + variableArgs: false + }; + t['EMC'] = { + id: _util.OPS.endMarkedContent, + numArgs: 0, + variableArgs: false + }; + t['BX'] = { + id: _util.OPS.beginCompat, + numArgs: 0, + variableArgs: false + }; + t['EX'] = { + id: _util.OPS.endCompat, + numArgs: 0, + variableArgs: false + }; + t['BM'] = null; + t['BD'] = null; + t['true'] = null; + t['fa'] = null; + t['fal'] = null; + t['fals'] = null; + t['false'] = null; + t['nu'] = null; + t['nul'] = null; + t['null'] = null; + }); + + function EvaluatorPreprocessor(stream, xref, stateManager) { + this.opMap = getOPMap(); + this.parser = new _parser.Parser(new _parser.Lexer(stream, this.opMap), false, xref); + this.stateManager = stateManager; + this.nonProcessedArgs = []; + } + + EvaluatorPreprocessor.prototype = { + get savedStatesDepth() { + return this.stateManager.stateStack.length; + }, + read: function EvaluatorPreprocessor_read(operation) { + var args = operation.args; + while (true) { + var obj = this.parser.getObj(); + if ((0, _primitives.isCmd)(obj)) { + var cmd = obj.cmd; + var opSpec = this.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; + if (!opSpec.variableArgs) { + if (argsLength !== numArgs) { + var nonProcessedArgs = this.nonProcessedArgs; + while (argsLength > numArgs) { + nonProcessedArgs.push(args.shift()); + argsLength--; + } + while (argsLength < numArgs && nonProcessedArgs.length !== 0) { + if (args === null) { + args = []; + } + args.unshift(nonProcessedArgs.pop()); + argsLength++; + } + } + if (argsLength < numArgs) { + (0, _util.warn)('Skipping command ' + fn + ': expected ' + numArgs + ' args, but received ' + argsLength + ' args.'); + if (args !== null) { + args.length = 0; + } + continue; + } + } else if (argsLength > numArgs) { + (0, _util.info)('Command ' + fn + ': expected [0,' + numArgs + '] args, but received ' + argsLength + ' args.'); + } + this.preprocessCommand(fn, args); + operation.fn = fn; + operation.args = args; + return true; + } + if ((0, _primitives.isEOF)(obj)) { + return false; + } + if (obj !== null) { + if (args === null) { + args = []; + } + args.push(obj); + if (args.length > 33) { + throw new _util.FormatError('Too many arguments'); + } + } + } + }, + preprocessCommand: function EvaluatorPreprocessor_preprocessCommand(fn, args) { + switch (fn | 0) { + case _util.OPS.save: + this.stateManager.save(); + break; + case _util.OPS.restore: + this.stateManager.restore(); + break; + case _util.OPS.transform: + this.stateManager.transform(args); + break; + } + } + }; + return EvaluatorPreprocessor; + }(); + var QueueOptimizer = function QueueOptimizerClosure() { + function addState(parentState, pattern, fn) { + 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]] = fn; + } + + 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], function foundInlineImageGroup(context) { + 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 i = iFirstSave + 4; + var ii = fnArray.length; + while (i + 3 < ii) { + if (fnArray[i] !== _util.OPS.save || fnArray[i + 1] !== _util.OPS.transform || fnArray[i + 2] !== _util.OPS.paintInlineImageXObject || fnArray[i + 3] !== _util.OPS.restore) { + break; + } + i += 4; + } + var count = Math.min((i - iFirstSave) / 4, MAX_IMAGES_IN_INLINE_IMAGES_BLOCK); + if (count < MIN_IMAGES_IN_INLINE_IMAGES_BLOCK) { + return i; + } + 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: 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 Uint8Array(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], function foundImageMaskGroup(context) { + 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 i = iFirstSave + 4; + var ii = fnArray.length; + while (i + 3 < ii) { + if (fnArray[i] !== _util.OPS.save || fnArray[i + 1] !== _util.OPS.transform || fnArray[i + 2] !== _util.OPS.paintImageMaskXObject || fnArray[i + 3] !== _util.OPS.restore) { + break; + } + i += 4; + } + var count = (i - iFirstSave) / 4; + count = handlePaintSolidColorImageMask(iFirstSave, count, fnArray, argsArray); + if (count < MIN_IMAGES_IN_MASKS_BLOCK) { + return i; + } + var q; + var isSameImage = false; + var iTransform, transformArgs; + var firstPIMXOArg0 = argsArray[iFirstPIMXO][0]; + if (argsArray[iFirstTransform][1] === 0 && argsArray[iFirstTransform][2] === 0) { + isSameImage = true; + var firstTransformArg0 = argsArray[iFirstTransform][0]; + var firstTransformArg3 = argsArray[iFirstTransform][3]; + 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] !== 0 || transformArgs[2] !== 0 || 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, 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 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 iFirstRestore = curr; + if (argsArray[iFirstTransform][1] !== 0 || argsArray[iFirstTransform][2] !== 0) { + return iFirstRestore + 1; + } + var firstPIXOArg0 = argsArray[iFirstPIXO][0]; + var firstTransformArg0 = argsArray[iFirstTransform][0]; + var firstTransformArg3 = argsArray[iFirstTransform][3]; + var i = iFirstSave + 4; + var ii = fnArray.length; + while (i + 3 < ii) { + if (fnArray[i] !== _util.OPS.save || fnArray[i + 1] !== _util.OPS.transform || fnArray[i + 2] !== _util.OPS.paintImageXObject || fnArray[i + 3] !== _util.OPS.restore) { + break; + } + if (argsArray[i + 1][0] !== firstTransformArg0 || argsArray[i + 1][1] !== 0 || argsArray[i + 1][2] !== 0 || argsArray[i + 1][3] !== firstTransformArg3) { + break; + } + if (argsArray[i + 2][0] !== firstPIXOArg0) { + break; + } + i += 4; + } + var count = Math.min((i - iFirstSave) / 4, MAX_IMAGES_IN_BLOCK); + if (count < MIN_IMAGES_IN_BLOCK) { + return i; + } + 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], function (context) { + 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 i = iFirstBeginText + 5; + var ii = fnArray.length; + while (i + 4 < ii) { + if (fnArray[i] !== _util.OPS.beginText || fnArray[i + 1] !== _util.OPS.setFont || fnArray[i + 2] !== _util.OPS.setTextMatrix || fnArray[i + 3] !== _util.OPS.showText || fnArray[i + 4] !== _util.OPS.endText) { + break; + } + if (argsArray[i + 1][0] !== firstSetFontArg0 || argsArray[i + 1][1] !== firstSetFontArg1) { + break; + } + i += 5; + } + var count = Math.min((i - iFirstBeginText) / 5, MAX_CHARS_IN_BLOCK); + if (count < MIN_CHARS_IN_BLOCK) { + return i; + } + 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() { + } + + QueueOptimizer.prototype = { + optimize: function QueueOptimizer_optimize(queue) { + var fnArray = queue.fnArray, + argsArray = queue.argsArray; + var context = { + iCurr: 0, + fnArray: fnArray, + argsArray: argsArray + }; + var state; + var i = 0, + ii = fnArray.length; + while (i < ii) { + state = (state || InitialState)[fnArray[i]]; + if (typeof state === 'function') { + context.iCurr = i; + i = state(context); + state = undefined; + ii = context.fnArray.length; + } else { + i++; + } + } + } + }; + return QueueOptimizer; + }(); + exports.OperatorList = OperatorList; + exports.PartialEvaluator = PartialEvaluator; + + /***/ + }), + /* 14 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.JpxImage = undefined; + + var _util = __w_pdfjs_require__(0); + + var _arithmetic_decoder = __w_pdfjs_require__(9); + + var JpxError = function JpxErrorClosure() { + function JpxError(msg) { + this.message = 'JPX error: ' + msg; + } + + JpxError.prototype = new Error(); + JpxError.prototype.name = 'JpxError'; + JpxError.constructor = JpxError; + return JpxError; + }(); + 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, _util.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, _util.readUint32)(data, position); + var tbox = (0, _util.readUint32)(data, position + 4); + position += headerSize; + if (lbox === 1) { + lbox = (0, _util.readUint32)(data, position) * 4294967296 + (0, _util.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, _util.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, _util.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, _util.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, _util.readUint16)(data, position); + var siz = {}; + siz.Xsiz = (0, _util.readUint32)(data, position + 4); + siz.Ysiz = (0, _util.readUint32)(data, position + 8); + siz.XOsiz = (0, _util.readUint32)(data, position + 12); + siz.YOsiz = (0, _util.readUint32)(data, position + 16); + siz.XTsiz = (0, _util.readUint32)(data, position + 20); + siz.YTsiz = (0, _util.readUint32)(data, position + 24); + siz.XTOsiz = (0, _util.readUint32)(data, position + 28); + siz.YTOsiz = (0, _util.readUint32)(data, position + 32); + var componentsCount = (0, _util.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 + 1] + }; + calculateComponentDimensions(component, siz); + components.push(component); + } + context.SIZ = siz; + context.components = components; + calculateTileGrids(context, components); + context.QCC = []; + context.COC = []; + break; + case 0xFF5C: + length = (0, _util.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, _util.readUint16)(data, position); + var qcc = {}; + j = position + 2; + var cqcc; + if (context.SIZ.Csiz < 257) { + cqcc = data[j++]; + } else { + cqcc = (0, _util.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, _util.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, _util.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.verticalyStripe = !!(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.verticalyStripe) { + unsupported.push('verticalyStripe'); + } + 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, _util.readUint16)(data, position); + tile = {}; + tile.index = (0, _util.readUint16)(data, position + 2); + tile.length = (0, _util.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, _util.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: precinctWidth, + precinctHeight: precinctHeight, + numprecinctswide: numprecinctswide, + numprecinctshigh: numprecinctshigh, + numprecincts: numprecincts, + precinctWidthInSubband: precinctWidthInSubband, + precinctHeightInSubband: 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: 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++) { + var 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++) { + var 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: minWidth, + minHeight: minHeight, + maxNumWide: maxNumWide, + maxNumHigh: 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, _util.log2)(codingpasses); + var bits = (codingpasses < 1 << codingpassesLog2 ? codingpassesLog2 - 1 : codingpassesLog2) + codeblock.Lblock; + var codedDataLength = readBits(bits); + queue.push({ + codeblock: codeblock, + codingpasses: 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: 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 : Math.pow(2, precision + gainLog2 - epsilon) * (1 + mu / 2048); + var mb = guardBits + epsilon - 1; + copyCoefficients(coefficients, width, height, subband, delta, mb, reversible, segmentationSymbolUsed); + } + subbandCoefficients.push({ + width: width, + height: 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 Uint8Array(tile0.items.length * componentsCount); + var result = { + left: tile0.left, + top: tile0.top, + width: tile0.width, + height: tile0.height, + items: out + }; + var shift, offset, max, min, maxK; + var pos = 0, + j, + jj, + y0, + y1, + y2, + r, + g, + b, + k, + val; + 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; + max = 255 * (1 << shift); + maxK = max * 0.5; + min = -maxK; + 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]; + r = y0 + 1.402 * y2; + g = y0 - 0.34413 * y1 - 0.71414 * y2; + b = y0 + 1.772 * y1; + out[pos++] = r <= 0 ? 0 : r >= max ? 255 : r >> shift; + out[pos++] = g <= 0 ? 0 : g >= max ? 255 : g >> shift; + out[pos++] = b <= 0 ? 0 : b >= max ? 255 : b >> shift; + } + } else { + for (j = 0; j < jj; j++, pos += alpha01) { + y0 = y0items[j] + offset; + y1 = y1items[j]; + y2 = y2items[j]; + g = y0 - (y2 + y1 >> 2); + r = g + y2; + b = g + y1; + out[pos++] = r <= 0 ? 0 : r >= max ? 255 : r >> shift; + out[pos++] = g <= 0 ? 0 : g >= max ? 255 : g >> shift; + out[pos++] = b <= 0 ? 0 : b >= max ? 255 : b >> shift; + } + } + if (fourComponents) { + for (j = 0, pos = 3; j < jj; j++, pos += 4) { + k = y3items[j]; + out[pos] = k <= min ? 0 : k >= maxK ? 255 : k + offset >> shift; + } + } + } else { + for (c = 0; c < componentsCount; c++) { + var items = transformedTiles[c].items; + shift = components[c].precision - 8; + offset = (128 << shift) + 0.5; + max = 127.5 * (1 << shift); + min = -max; + for (pos = c, j = 0, jj = items.length; j < jj; j++) { + val = items[j]; + out[pos] = val <= min ? 0 : val >= max ? 255 : val + 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, _util.log2)(Math.max(width, height)) + 1; + this.levels = []; + for (var i = 0; i < levelsLength; i++) { + var level = { + width: width, + height: 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, _util.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: width, + height: height, + items: 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; + this.contextLabelTable = subband === 'HH' ? HHContextLabel : subband === 'HL' ? HLContextLabel : LLAndLHContextsLabel; + var coefficientCount = width * height; + this.neighborsSignificance = new Uint8Array(coefficientCount); + this.coefficentsSign = new Uint8Array(coefficientCount); + this.coefficentsMagnitude = mb > 14 ? new Uint32Array(coefficientCount) : mb > 6 ? new Uint16Array(coefficientCount) : new Uint8Array(coefficientCount); + 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: width, + height: height, + items: 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; + + /***/ + }), + /* 15 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.FileSpec = exports.XRef = exports.ObjectLoader = exports.Catalog = undefined; + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + var _slicedToArray = function () { + function sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"]) _i["return"](); + } finally { + if (_d) throw _e; + } + } + return _arr; + } + + return function (arr, i) { + if (Array.isArray(arr)) { + return arr; + } else if (Symbol.iterator in Object(arr)) { + return sliceIterator(arr, i); + } else { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + }; + }(); + + var _util = __w_pdfjs_require__(0); + + var _primitives = __w_pdfjs_require__(1); + + var _parser = __w_pdfjs_require__(5); + + var _chunked_stream = __w_pdfjs_require__(11); + + var _crypto = __w_pdfjs_require__(12); + + var _colorspace = __w_pdfjs_require__(3); + + var Catalog = function CatalogClosure() { + function Catalog(pdfManager, xref, pageFactory) { + this.pdfManager = pdfManager; + this.xref = xref; + this.catDict = xref.getCatalogObj(); + if (!(0, _primitives.isDict)(this.catDict)) { + throw new _util.FormatError('catalog object is not a dictionary'); + } + this.fontCache = new _primitives.RefSetCache(); + this.builtInCMapCache = Object.create(null); + this.pageKidsCountCache = new _primitives.RefSetCache(); + this.pageFactory = pageFactory; + this.pagePromises = []; + } + + Catalog.prototype = { + get metadata() { + var streamRef = this.catDict.getRaw('Metadata'); + if (!(0, _primitives.isRef)(streamRef)) { + return (0, _util.shadow)(this, 'metadata', null); + } + var encryptMetadata = !this.xref.encrypt ? false : this.xref.encrypt.encryptMetadata; + var stream = this.xref.fetch(streamRef, !encryptMetadata); + var metadata; + if (stream && (0, _primitives.isDict)(stream.dict)) { + var type = stream.dict.get('Type'); + var 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 _util.MissingDataException) { + throw e; + } + (0, _util.info)('Skipping invalid metadata.'); + } + } + } + return (0, _util.shadow)(this, 'metadata', metadata); + }, + get toplevelPagesDict() { + var 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() { + var obj = null; + try { + obj = this.readDocumentOutline(); + } catch (ex) { + if (ex instanceof _util.MissingDataException) { + throw ex; + } + (0, _util.warn)('Unable to read document outline'); + } + return (0, _util.shadow)(this, 'documentOutline', obj); + }, + readDocumentOutline: function Catalog_readDocumentOutline() { + var obj = this.catDict.get('Outlines'); + if (!(0, _primitives.isDict)(obj)) { + return null; + } + obj = obj.getRaw('First'); + if (!(0, _primitives.isRef)(obj)) { + return null; + } + var root = {items: []}; + var queue = [{ + obj: obj, + parent: root + }]; + var processed = new _primitives.RefSet(); + processed.put(obj); + var xref = this.xref, + blackColor = new Uint8Array(3); + while (queue.length > 0) { + var i = queue.shift(); + var outlineDict = xref.fetchIfRef(i.obj); + if (outlineDict === null) { + continue; + } + if (!outlineDict.has('Title')) { + throw new _util.FormatError('Invalid outline item'); + } + var data = { + url: null, + dest: null + }; + Catalog.parseDestDictionary({ + destDict: outlineDict, + resultObj: data, + docBaseUrl: this.pdfManager.docBaseUrl + }); + var title = outlineDict.get('Title'); + var flags = outlineDict.get('F') || 0; + var color = outlineDict.getArray('C'), + rgbColor = blackColor; + if ((0, _util.isArray)(color) && color.length === 3 && (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) { + rgbColor = _colorspace.ColorSpace.singletons.rgb.getRgb(color, 0); + } + var outlineItem = { + dest: data.dest, + url: data.url, + unsafeUrl: data.unsafeUrl, + newWindow: data.newWindow, + title: (0, _util.stringToPDFString)(title), + color: rgbColor, + count: outlineDict.get('Count'), + 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: obj, + parent: outlineItem + }); + processed.put(obj); + } + obj = outlineDict.getRaw('Next'); + if ((0, _primitives.isRef)(obj) && !processed.has(obj)) { + queue.push({ + obj: obj, + parent: i.parent + }); + processed.put(obj); + } + } + return root.items.length > 0 ? root.items : null; + }, + get numPages() { + var obj = this.toplevelPagesDict.get('Count'); + if (!(0, _util.isInt)(obj)) { + throw new _util.FormatError('page count in top level pages object is not an integer'); + } + return (0, _util.shadow)(this, 'numPages', obj); + }, + get destinations() { + function fetchDestination(dest) { + return (0, _primitives.isDict)(dest) ? dest.get('D') : dest; + } + + var xref = this.xref; + var dests = {}, + nameTreeRef, + nameDictionaryRef; + var obj = this.catDict.get('Names'); + if (obj && obj.has('Dests')) { + nameTreeRef = obj.getRaw('Dests'); + } else if (this.catDict.has('Dests')) { + nameDictionaryRef = this.catDict.get('Dests'); + } + if (nameDictionaryRef) { + obj = nameDictionaryRef; + obj.forEach(function catalogForEach(key, value) { + if (!value) { + return; + } + dests[key] = fetchDestination(value); + }); + } + if (nameTreeRef) { + var nameTree = new NameTree(nameTreeRef, xref); + var names = nameTree.getAll(); + for (var name in names) { + dests[name] = fetchDestination(names[name]); + } + } + return (0, _util.shadow)(this, 'destinations', dests); + }, + getDestination: function Catalog_getDestination(destinationId) { + function fetchDestination(dest) { + return (0, _primitives.isDict)(dest) ? dest.get('D') : dest; + } + + var xref = this.xref; + var dest = null, + nameTreeRef, + nameDictionaryRef; + var obj = this.catDict.get('Names'); + if (obj && obj.has('Dests')) { + nameTreeRef = obj.getRaw('Dests'); + } else if (this.catDict.has('Dests')) { + nameDictionaryRef = this.catDict.get('Dests'); + } + if (nameDictionaryRef) { + var value = nameDictionaryRef.get(destinationId); + if (value) { + dest = fetchDestination(value); + } + } + if (nameTreeRef) { + var nameTree = new NameTree(nameTreeRef, xref); + dest = fetchDestination(nameTree.get(destinationId)); + } + return dest; + }, + get pageLabels() { + var obj = null; + try { + obj = this.readPageLabels(); + } catch (ex) { + if (ex instanceof _util.MissingDataException) { + throw ex; + } + (0, _util.warn)('Unable to read page labels.'); + } + return (0, _util.shadow)(this, 'pageLabels', obj); + }, + readPageLabels: function Catalog_readPageLabels() { + var obj = this.catDict.getRaw('PageLabels'); + if (!obj) { + return null; + } + var pageLabels = new Array(this.numPages); + var style = null; + var prefix = ''; + var numberTree = new NumberTree(obj, this.xref); + var nums = numberTree.getAll(); + var currentLabel = '', + currentIndex = 1; + for (var i = 0, ii = this.numPages; i < ii; i++) { + if (i in nums) { + var labelDict = nums[i]; + if (!(0, _primitives.isDict)(labelDict)) { + throw new _util.FormatError('The PageLabel is not a dictionary.'); + } + var type = labelDict.get('Type'); + if (type && !(0, _primitives.isName)(type, 'PageLabel')) { + throw new _util.FormatError('Invalid type in PageLabel dictionary.'); + } + var s = labelDict.get('S'); + if (s && !(0, _primitives.isName)(s)) { + throw new _util.FormatError('Invalid style in PageLabel dictionary.'); + } + style = s ? s.name : null; + var p = labelDict.get('P'); + if (p && !(0, _util.isString)(p)) { + throw new _util.FormatError('Invalid prefix in PageLabel dictionary.'); + } + prefix = p ? (0, _util.stringToPDFString)(p) : ''; + var st = labelDict.get('St'); + if (st && !((0, _util.isInt)(st) && st >= 1)) { + throw new _util.FormatError('Invalid start in PageLabel dictionary.'); + } + currentIndex = st || 1; + } + switch (style) { + case 'D': + currentLabel = currentIndex; + break; + case 'R': + case 'r': + currentLabel = _util.Util.toRoman(currentIndex, style === 'r'); + break; + case 'A': + case 'a': + var LIMIT = 26; + var A_UPPER_CASE = 0x41, + A_LOWER_CASE = 0x61; + var baseCharCode = style === 'a' ? A_LOWER_CASE : A_UPPER_CASE; + var letterIndex = currentIndex - 1; + var character = String.fromCharCode(baseCharCode + letterIndex % LIMIT); + var charBuf = []; + for (var 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.'); + } + } + pageLabels[i] = prefix + currentLabel; + currentLabel = ''; + currentIndex++; + } + return pageLabels; + }, + get pageMode() { + var obj = this.catDict.get('PageMode'); + var 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 attachments() { + var xref = this.xref; + var attachments = null, + nameTreeRef; + var obj = this.catDict.get('Names'); + if (obj) { + nameTreeRef = obj.getRaw('EmbeddedFiles'); + } + if (nameTreeRef) { + var nameTree = new NameTree(nameTreeRef, xref); + var names = nameTree.getAll(); + for (var name in names) { + var fs = new FileSpec(names[name], xref); + if (!attachments) { + attachments = Object.create(null); + } + attachments[(0, _util.stringToPDFString)(name)] = fs.serializable; + } + } + return (0, _util.shadow)(this, 'attachments', attachments); + }, + get javaScript() { + var xref = this.xref; + var obj = this.catDict.get('Names'); + var javaScript = []; + + function appendIfJavaScriptDict(jsDict) { + var type = jsDict.get('S'); + if (!(0, _primitives.isName)(type, 'JavaScript')) { + return; + } + var js = jsDict.get('JS'); + if ((0, _primitives.isStream)(js)) { + js = (0, _util.bytesToString)(js.getBytes()); + } else if (!(0, _util.isString)(js)) { + return; + } + javaScript.push((0, _util.stringToPDFString)(js)); + } + + if (obj && obj.has('JavaScript')) { + var nameTree = new NameTree(obj.getRaw('JavaScript'), xref); + var names = nameTree.getAll(); + for (var name in names) { + var jsDict = names[name]; + if ((0, _primitives.isDict)(jsDict)) { + appendIfJavaScriptDict(jsDict); + } + } + } + var openactionDict = this.catDict.get('OpenAction'); + if ((0, _primitives.isDict)(openactionDict, 'Action')) { + var actionType = openactionDict.get('S'); + if ((0, _primitives.isName)(actionType, 'Named')) { + var action = openactionDict.get('N'); + if ((0, _primitives.isName)(action, 'Print')) { + javaScript.push('print({});'); + } + } else { + appendIfJavaScriptDict(openactionDict); + } + } + return (0, _util.shadow)(this, 'javaScript', javaScript); + }, + cleanup: function Catalog_cleanup() { + var _this = this; + + this.pageKidsCountCache.clear(); + var promises = []; + this.fontCache.forEach(function (promise) { + promises.push(promise); + }); + return Promise.all(promises).then(function (translatedFonts) { + for (var i = 0, ii = translatedFonts.length; i < ii; i++) { + var font = translatedFonts[i].dict; + delete font.translated; + } + _this.fontCache.clear(); + _this.builtInCMapCache = Object.create(null); + }); + }, + getPage: function Catalog_getPage(pageIndex) { + var _this2 = this; + + if (!(pageIndex in this.pagePromises)) { + this.pagePromises[pageIndex] = this.getPageDict(pageIndex).then(function (_ref) { + var _ref2 = _slicedToArray(_ref, 2), + dict = _ref2[0], + ref = _ref2[1]; + + return _this2.pageFactory.createPage(pageIndex, dict, ref, _this2.fontCache, _this2.builtInCMapCache); + }); + } + return this.pagePromises[pageIndex]; + }, + getPageDict: function Catalog_getPageDict(pageIndex) { + var capability = (0, _util.createPromiseCapability)(); + var nodesToVisit = [this.catDict.getRaw('Pages')]; + var count, + currentPageIndex = 0; + var xref = this.xref, + pageKidsCountCache = this.pageKidsCountCache; + + function next() { + while (nodesToVisit.length) { + var currentNode = nodesToVisit.pop(); + if ((0, _primitives.isRef)(currentNode)) { + count = pageKidsCountCache.get(currentNode); + if (count > 0 && currentPageIndex + count < pageIndex) { + currentPageIndex += count; + continue; + } + 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'); + var objId = currentNode.objId; + if (objId && !pageKidsCountCache.has(objId)) { + pageKidsCountCache.put(objId, count); + } + if (currentPageIndex + count <= pageIndex) { + currentPageIndex += count; + continue; + } + var kids = currentNode.get('Kids'); + if (!(0, _util.isArray)(kids)) { + capability.reject(new _util.FormatError('page dictionary kids object is not an array')); + return; + } + for (var 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: function Catalog_getPageIndex(pageRef) { + var xref = this.xref; + + function pagesBeforeRef(kidRef) { + var total = 0; + var 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 Dict.'); + } + if (!node) { + return null; + } + if (!(0, _primitives.isDict)(node)) { + throw new _util.FormatError('node must be a Dict.'); + } + 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 Dict.'); + } + return parent.getAsync('Kids'); + }).then(function (kids) { + if (!kids) { + return null; + } + var kidPromises = []; + var found = false; + for (var i = 0; i < kids.length; i++) { + var kid = kids[i]; + if (!(0, _primitives.isRef)(kid)) { + throw new _util.FormatError('kid must be a Ref.'); + } + if (kid.num === kidRef.num) { + found = true; + break; + } + kidPromises.push(xref.fetchAsync(kid).then(function (kid) { + if (kid.has('Count')) { + var count = kid.get('Count'); + total += count; + } else { + total++; + } + })); + } + if (!found) { + throw new _util.FormatError('kid ref not found in parents kids'); + } + return Promise.all(kidPromises).then(function () { + return [total, parentRef]; + }); + }); + } + + var total = 0; + + function next(ref) { + return pagesBeforeRef(ref).then(function (args) { + if (!args) { + return total; + } + var count = args[0]; + var parentRef = args[1]; + total += count; + return next(parentRef); + }); + } + + return next(pageRef); + } + }; + Catalog.parseDestDictionary = function Catalog_parseDestDictionary(params) { + function addDefaultProtocolToUrl(url) { + if (url.indexOf('www.') === 0) { + return 'http://' + url; + } + return url; + } + + function tryConvertUrlEncoding(url) { + try { + return (0, _util.stringToUTF8String)(url); + } catch (e) { + return url; + } + } + + var destDict = params.destDict; + if (!(0, _primitives.isDict)(destDict)) { + (0, _util.warn)('Catalog_parseDestDictionary: "destDict" must be a dictionary.'); + return; + } + var resultObj = params.resultObj; + if ((typeof resultObj === 'undefined' ? 'undefined' : _typeof(resultObj)) !== 'object') { + (0, _util.warn)('Catalog_parseDestDictionary: "resultObj" must be an object.'); + return; + } + var docBaseUrl = params.docBaseUrl || null; + var action = destDict.get('A'), + url, + dest; + if ((0, _primitives.isDict)(action)) { + var linkType = action.get('S').name; + switch (linkType) { + 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': + var urlDict = action.get('F'); + if ((0, _primitives.isDict)(urlDict)) { + url = urlDict.get('F') || null; + } else if ((0, _util.isString)(urlDict)) { + url = urlDict; + } + var remoteDest = action.get('D'); + if (remoteDest) { + if ((0, _primitives.isName)(remoteDest)) { + remoteDest = remoteDest.name; + } + if ((0, _util.isString)(url)) { + var baseUrl = url.split('#')[0]; + if ((0, _util.isString)(remoteDest)) { + url = baseUrl + '#' + remoteDest; + } else if ((0, _util.isArray)(remoteDest)) { + url = baseUrl + '#' + JSON.stringify(remoteDest); + } + } + } + var newWindow = action.get('NewWindow'); + if ((0, _util.isBool)(newWindow)) { + resultObj.newWindow = newWindow; + } + break; + case 'Named': + var namedAction = action.get('N'); + if ((0, _primitives.isName)(namedAction)) { + resultObj.action = namedAction.name; + } + break; + case 'JavaScript': + var jsAction = action.get('JS'), + js; + if ((0, _primitives.isStream)(jsAction)) { + js = (0, _util.bytesToString)(jsAction.getBytes()); + } else if ((0, _util.isString)(jsAction)) { + js = jsAction; + } + if (js) { + var URL_OPEN_METHODS = ['app.launchURL', 'window.open']; + var regex = new RegExp('^\\s*(' + URL_OPEN_METHODS.join('|').split('.').join('\\.') + ')\\((?:\'|\")([^\'\"]*)(?:\'|\")(?:,\\s*(\\w+)\\)|\\))', 'i'); + var 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)('Catalog_parseDestDictionary: Unrecognized link type "' + linkType + '".'); + break; + } + } else if (destDict.has('Dest')) { + dest = destDict.get('Dest'); + } + if ((0, _util.isString)(url)) { + url = tryConvertUrlEncoding(url); + var 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) || (0, _util.isArray)(dest)) { + resultObj.dest = dest; + } + } + }; + return Catalog; + }(); + var XRef = function XRefClosure() { + function XRef(stream, pdfManager) { + this.stream = stream; + this.pdfManager = pdfManager; + this.entries = []; + this.xrefstms = Object.create(null); + this.cache = []; + this.stats = { + streamTypes: [], + fontTypes: [] + }; + } + + XRef.prototype = { + 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; + var encrypt = trailerDict.get('Encrypt'); + 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); + } + if (!(this.root = trailerDict.get('Root'))) { + 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 (!(0, _util.isInt)(first) || !(0, _util.isInt)(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 ((0, _primitives.isCmd)(type, 'f')) { + entry.free = true; + } else if ((0, _primitives.isCmd)(type, 'n')) { + entry.uncompressed = true; + } + if (!(0, _util.isInt)(entry.offset) || !(0, _util.isInt)(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: 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 (!(0, _util.isInt)(first) || !(0, _util.isInt)(n)) { + throw new _util.FormatError('Invalid XRef range fields: ' + first + ', ' + n); + } + if (!(0, _util.isInt)(typeFieldWidth) || !(0, _util.isInt)(offsetFieldWidth) || !(0, _util.isInt)(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/; + var trailerBytes = new Uint8Array([116, 114, 97, 105, 108, 101, 114]); + var startxrefBytes = new Uint8Array([115, 116, 97, 114, 116, 120, 114, 101, 102]); + var endobjBytes = new Uint8Array([101, 110, 100, 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.indexOf('xref') === 0 && (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)) { + if (typeof this.entries[m[1]] === 'undefined') { + this.entries[m[1]] = { + offset: position - stream.start, + gen: m[2] | 0, + uncompressed: true + }; + } + var contentLength = skipUntil(buffer, position, endobjBytes) + 7; + var 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.indexOf('trailer') === 0 && (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); + } + var dict; + for (i = 0, ii = trailers.length; i < ii; ++i) { + stream.pos = trailers[i]; + var parser = new _parser.Parser(new _parser.Lexer(stream), true, this, true); + var obj = parser.getObj(); + if (!(0, _primitives.isCmd)(obj, 'trailer')) { + continue; + } + dict = parser.getObj(); + if (!(0, _primitives.isDict)(dict)) { + continue; + } + if (dict.has('ID')) { + return dict; + } + } + if (dict) { + return dict; + } + throw new _util.InvalidPDFException('Invalid PDF structure'); + }, + readXRef: function XRef_readXRef(recoveryMode) { + var stream = this.stream; + try { + while (this.startXRefQueue.length) { + var startXRef = this.startXRefQueue[0]; + stream.pos = startXRef + stream.start; + var parser = new _parser.Parser(new _parser.Lexer(stream), true, this); + 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 ((0, _util.isInt)(obj)) { + var pos = obj; + if (!(pos in this.xrefstms)) { + this.xrefstms[pos] = 1; + this.startXRefQueue.push(pos); + } + } + } else if ((0, _util.isInt)(obj)) { + if (!(0, _util.isInt)(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 ((0, _util.isInt)(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 _util.MissingDataException) { + throw e; + } + (0, _util.info)('(while reading XRef): ' + e); + } + if (recoveryMode) { + return; + } + throw new _util.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 (!(0, _primitives.isRef)(obj)) { + return obj; + } + return this.fetch(obj, suppressEncryption); + }, + fetch: function XRef_fetch(ref, suppressEncryption) { + if (!(0, _primitives.isRef)(ref)) { + throw new Error('ref object is not a reference'); + } + var num = ref.num; + if (num in this.cache) { + var cacheEntry = this.cache[num]; + if (cacheEntry instanceof _primitives.Dict && !cacheEntry.objId) { + cacheEntry.objId = ref.toString(); + } + return cacheEntry; + } + var xrefEntry = this.getEntry(num); + if (xrefEntry === null) { + return this.cache[num] = null; + } + if (xrefEntry.uncompressed) { + xrefEntry = this.fetchUncompressed(ref, xrefEntry, suppressEncryption); + } else { + xrefEntry = this.fetchCompressed(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: function XRef_fetchUncompressed(ref, xrefEntry, suppressEncryption) { + var gen = ref.gen; + var num = ref.num; + if (xrefEntry.gen !== gen) { + throw new _util.FormatError('inconsistent generation in XRef'); + } + var stream = this.stream.makeSubStream(xrefEntry.offset + this.stream.start); + var parser = new _parser.Parser(new _parser.Lexer(stream), true, this); + var obj1 = parser.getObj(); + var obj2 = parser.getObj(); + var obj3 = parser.getObj(); + if (!(0, _util.isInt)(obj1) || parseInt(obj1, 10) !== num || !(0, _util.isInt)(obj2) || parseInt(obj2, 10) !== gen || !(0, _primitives.isCmd)(obj3)) { + throw new _util.FormatError('bad XRef entry'); + } + if (!(0, _primitives.isCmd)(obj3, 'obj')) { + if (obj3.cmd.indexOf('obj') === 0) { + num = parseInt(obj3.cmd.substring(3), 10); + if (!isNaN(num)) { + return num; + } + } + throw new _util.FormatError('bad XRef entry'); + } + if (this.encrypt && !suppressEncryption) { + xrefEntry = parser.getObj(this.encrypt.createCipherTransform(num, gen)); + } else { + xrefEntry = parser.getObj(); + } + if (!(0, _primitives.isStream)(xrefEntry)) { + this.cache[num] = xrefEntry; + } + return xrefEntry; + }, + fetchCompressed: function XRef_fetchCompressed(xrefEntry, suppressEncryption) { + var tableOffset = xrefEntry.offset; + var stream = this.fetch(new _primitives.Ref(tableOffset, 0)); + if (!(0, _primitives.isStream)(stream)) { + throw new _util.FormatError('bad ObjStm stream'); + } + var first = stream.dict.get('First'); + var n = stream.dict.get('N'); + if (!(0, _util.isInt)(first) || !(0, _util.isInt)(n)) { + throw new _util.FormatError('invalid first and n parameters for ObjStm stream'); + } + var parser = new _parser.Parser(new _parser.Lexer(stream), false, this); + parser.allowStreams = true; + var i, + entries = [], + num, + nums = []; + for (i = 0; i < n; ++i) { + num = parser.getObj(); + if (!(0, _util.isInt)(num)) { + throw new _util.FormatError('invalid object number in the ObjStm stream: ' + num); + } + nums.push(num); + var offset = parser.getObj(); + if (!(0, _util.isInt)(offset)) { + throw new _util.FormatError('invalid object offset in the ObjStm stream: ' + offset); + } + } + for (i = 0; i < n; ++i) { + entries.push(parser.getObj()); + if ((0, _primitives.isCmd)(parser.buf1, 'endobj')) { + parser.shift(); + } + num = nums[i]; + var entry = this.entries[num]; + if (entry && entry.offset === tableOffset && entry.gen === i) { + this.cache[num] = entries[i]; + } + } + xrefEntry = entries[xrefEntry.gen]; + if (xrefEntry === undefined) { + throw new _util.FormatError('bad XRef entry for compressed object'); + } + return xrefEntry; + }, + fetchIfRefAsync: function XRef_fetchIfRefAsync(obj, suppressEncryption) { + if (!(0, _primitives.isRef)(obj)) { + return Promise.resolve(obj); + } + return this.fetchAsync(obj, suppressEncryption); + }, + fetchAsync: function XRef_fetchAsync(ref, suppressEncryption) { + var streamManager = this.stream.manager; + var xref = this; + return new Promise(function tryFetch(resolve, reject) { + try { + resolve(xref.fetch(ref, suppressEncryption)); + } catch (e) { + if (e instanceof _util.MissingDataException) { + streamManager.requestRange(e.begin, e.end).then(function () { + tryFetch(resolve, reject); + }, reject); + return; + } + reject(e); + } + }); + }, + getCatalogObj: function XRef_getCatalogObj() { + return this.root; + } + }; + return XRef; + }(); + var NameOrNumberTree = function NameOrNumberTreeClosure() { + function NameOrNumberTree(root, xref) { + throw new Error('Cannot initialize NameOrNumberTree.'); + } + + NameOrNumberTree.prototype = { + getAll: function NameOrNumberTree_getAll() { + var dict = Object.create(null); + if (!this.root) { + return dict; + } + var xref = this.xref; + var processed = new _primitives.RefSet(); + processed.put(this.root); + var queue = [this.root]; + while (queue.length > 0) { + var i, n; + var obj = xref.fetchIfRef(queue.shift()); + if (!(0, _primitives.isDict)(obj)) { + continue; + } + if (obj.has('Kids')) { + var kids = obj.get('Kids'); + for (i = 0, n = kids.length; i < n; i++) { + var kid = kids[i]; + if (processed.has(kid)) { + throw new _util.FormatError('Duplicate entry in "' + this._type + '" tree.'); + } + queue.push(kid); + processed.put(kid); + } + continue; + } + var entries = obj.get(this._type); + if ((0, _util.isArray)(entries)) { + for (i = 0, n = entries.length; i < n; i += 2) { + dict[xref.fetchIfRef(entries[i])] = xref.fetchIfRef(entries[i + 1]); + } + } + } + return dict; + }, + get: function NameOrNumberTree_get(key) { + if (!this.root) { + return null; + } + var xref = this.xref; + var kidsOrEntries = xref.fetchIfRef(this.root); + var loopCount = 0; + var MAX_LEVELS = 10; + var l, r, m; + while (kidsOrEntries.has('Kids')) { + if (++loopCount > MAX_LEVELS) { + (0, _util.warn)('Search depth limit reached for "' + this._type + '" tree.'); + return null; + } + var kids = kidsOrEntries.get('Kids'); + if (!(0, _util.isArray)(kids)) { + return null; + } + l = 0; + r = kids.length - 1; + while (l <= r) { + m = l + r >> 1; + var kid = xref.fetchIfRef(kids[m]); + var 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; + } + } + var entries = kidsOrEntries.get(this._type); + if ((0, _util.isArray)(entries)) { + l = 0; + r = entries.length - 2; + while (l <= r) { + m = l + r & ~1; + var 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; + } + }; + return NameOrNumberTree; + }(); + var NameTree = function NameTreeClosure() { + function NameTree(root, xref) { + this.root = root; + this.xref = xref; + this._type = 'Names'; + } + + _util.Util.inherit(NameTree, NameOrNumberTree, {}); + return NameTree; + }(); + var NumberTree = function NumberTreeClosure() { + function NumberTree(root, xref) { + this.root = root; + this.xref = xref; + this._type = 'Nums'; + } + + _util.Util.inherit(NumberTree, NameOrNumberTree, {}); + return NumberTree; + }(); + 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; + }(); + var ObjectLoader = function () { + function mayHaveChildren(value) { + return (0, _primitives.isRef)(value) || (0, _primitives.isDict)(value) || (0, _util.isArray)(value) || (0, _primitives.isStream)(value); + } + + function addChildren(node, nodesToVisit) { + if ((0, _primitives.isDict)(node) || (0, _primitives.isStream)(node)) { + var dict = (0, _primitives.isDict)(node) ? node : node.dict; + var dictKeys = dict.getKeys(); + for (var i = 0, ii = dictKeys.length; i < ii; i++) { + var rawValue = dict.getRaw(dictKeys[i]); + if (mayHaveChildren(rawValue)) { + nodesToVisit.push(rawValue); + } + } + } else if ((0, _util.isArray)(node)) { + for (var _i = 0, _ii = node.length; _i < _ii; _i++) { + var value = node[_i]; + if (mayHaveChildren(value)) { + nodesToVisit.push(value); + } + } + } + } + + function ObjectLoader(dict, keys, xref) { + this.dict = dict; + this.keys = keys; + this.xref = xref; + this.refSet = null; + this.capability = null; + } + + ObjectLoader.prototype = { + load: function load() { + this.capability = (0, _util.createPromiseCapability)(); + if (!(this.xref.stream instanceof _chunked_stream.ChunkedStream) || this.xref.stream.getMissingChunks().length === 0) { + this.capability.resolve(); + return this.capability.promise; + } + var keys = this.keys, + dict = this.dict; + + this.refSet = new _primitives.RefSet(); + var nodesToVisit = []; + for (var i = 0, ii = keys.length; i < ii; i++) { + var rawValue = dict.getRaw(keys[i]); + if (rawValue !== undefined) { + nodesToVisit.push(rawValue); + } + } + this._walk(nodesToVisit); + return this.capability.promise; + }, + _walk: function _walk(nodesToVisit) { + var _this3 = this; + + var nodesToRevisit = []; + var pendingRequests = []; + while (nodesToVisit.length) { + var currentNode = nodesToVisit.pop(); + if ((0, _primitives.isRef)(currentNode)) { + if (this.refSet.has(currentNode)) { + continue; + } + try { + this.refSet.put(currentNode); + currentNode = this.xref.fetch(currentNode); + } catch (ex) { + if (!(ex instanceof _util.MissingDataException)) { + throw ex; + } + nodesToRevisit.push(currentNode); + pendingRequests.push({ + begin: ex.begin, + end: ex.end + }); + } + } + if (currentNode && currentNode.getBaseStreams) { + var baseStreams = currentNode.getBaseStreams(); + var foundMissingData = false; + for (var i = 0, ii = baseStreams.length; i < ii; i++) { + var stream = baseStreams[i]; + if (stream.getMissingChunks && stream.getMissingChunks().length) { + foundMissingData = true; + pendingRequests.push({ + begin: stream.start, + end: stream.end + }); + } + } + if (foundMissingData) { + nodesToRevisit.push(currentNode); + } + } + addChildren(currentNode, nodesToVisit); + } + if (pendingRequests.length) { + this.xref.stream.manager.requestRanges(pendingRequests).then(function () { + for (var _i2 = 0, _ii2 = nodesToRevisit.length; _i2 < _ii2; _i2++) { + var node = nodesToRevisit[_i2]; + if ((0, _primitives.isRef)(node)) { + _this3.refSet.remove(node); + } + } + _this3._walk(nodesToRevisit); + }, this.capability.reject); + return; + } + this.refSet = null; + this.capability.resolve(); + } + }; + return ObjectLoader; + }(); + exports.Catalog = Catalog; + exports.ObjectLoader = ObjectLoader; + exports.XRef = XRef; + exports.FileSpec = FileSpec; + + /***/ + }), + /* 16 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.getSupplementalGlyphMapForArialBlack = exports.getGlyphMapForStandardFonts = exports.getSymbolsFonts = exports.getSerifFonts = exports.getNonStdFontMap = exports.getStdFontMap = undefined; + + var _util = __w_pdfjs_require__(0); + + var getStdFontMap = (0, _util.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['SegoeUISymbol'] = 'Helvetica'; + 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'; + }); + var getNonStdFontMap = (0, _util.getLookupTableFactory)(function (t) { + 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['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['Wingdings'] = 'ZapfDingbats'; + }); + var getSerifFonts = (0, _util.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; + }); + var getSymbolsFonts = (0, _util.getLookupTableFactory)(function (t) { + t['Dingbats'] = true; + t['Symbol'] = true; + t['ZapfDingbats'] = true; + }); + var getGlyphMapForStandardFonts = (0, _util.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; + }); + var getSupplementalGlyphMapForArialBlack = (0, _util.getLookupTableFactory)(function (t) { + t[227] = 322; + t[264] = 261; + t[291] = 346; + }); + exports.getStdFontMap = getStdFontMap; + exports.getNonStdFontMap = getNonStdFontMap; + exports.getSerifFonts = getSerifFonts; + exports.getSymbolsFonts = getSymbolsFonts; + exports.getGlyphMapForStandardFonts = getGlyphMapForStandardFonts; + exports.getSupplementalGlyphMapForArialBlack = getSupplementalGlyphMapForArialBlack; + + /***/ + }), + /* 17 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.WorkerMessageHandler = exports.WorkerTask = undefined; + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + var _util = __w_pdfjs_require__(0); + + var _pdf_manager = __w_pdfjs_require__(32); + + var _primitives = __w_pdfjs_require__(1); + + var WorkerTask = function WorkerTaskClosure() { + function WorkerTask(name) { + this.name = name; + this.terminated = false; + this._capability = (0, _util.createPromiseCapability)(); + } + + WorkerTask.prototype = { + get finished() { + return this._capability.promise; + }, + finish: function finish() { + this._capability.resolve(); + }, + terminate: function terminate() { + this.terminated = true; + }, + ensureNotTerminated: function ensureNotTerminated() { + if (this.terminated) { + throw new Error('Worker task was terminated'); + } + } + }; + return WorkerTask; + }(); + ; + var PDFWorkerStream = function PDFWorkerStreamClosure() { + function PDFWorkerStream(msgHandler) { + this._msgHandler = msgHandler; + this._contentLength = null; + this._fullRequestReader = null; + this._rangeRequestReaders = []; + } + + PDFWorkerStream.prototype = { + getFullReader: function getFullReader() { + (0, _util.assert)(!this._fullRequestReader); + this._fullRequestReader = new PDFWorkerStreamReader(this._msgHandler); + return this._fullRequestReader; + }, + getRangeReader: function getRangeReader(begin, end) { + var reader = new PDFWorkerStreamRangeReader(begin, end, this._msgHandler); + this._rangeRequestReaders.push(reader); + return reader; + }, + cancelAllRequests: function cancelAllRequests(reason) { + if (this._fullRequestReader) { + this._fullRequestReader.cancel(reason); + } + var readers = this._rangeRequestReaders.slice(0); + readers.forEach(function (reader) { + reader.cancel(reason); + }); + } + }; + + function PDFWorkerStreamReader(msgHandler) { + var _this = this; + + this._msgHandler = msgHandler; + this._contentLength = null; + this._isRangeSupported = false; + this._isStreamingSupported = false; + var readableStream = this._msgHandler.sendWithStream('GetReader'); + this._reader = readableStream.getReader(); + this._headersReady = this._msgHandler.sendWithPromise('ReaderHeadersReady').then(function (data) { + _this._isStreamingSupported = data.isStreamingSupported; + _this._isRangeSupported = data.isRangeSupported; + _this._contentLength = data.contentLength; + }); + } + + PDFWorkerStreamReader.prototype = { + get headersReady() { + return this._headersReady; + }, + get contentLength() { + return this._contentLength; + }, + get isStreamingSupported() { + return this._isStreamingSupported; + }, + get isRangeSupported() { + return this._isRangeSupported; + }, + read: function read() { + return this._reader.read().then(function (_ref) { + var value = _ref.value, + done = _ref.done; + + if (done) { + return { + value: undefined, + done: true + }; + } + return { + value: value.buffer, + done: false + }; + }); + }, + cancel: function cancel(reason) { + this._reader.cancel(reason); + } + }; + + function PDFWorkerStreamRangeReader(begin, end, msgHandler) { + this._msgHandler = msgHandler; + this.onProgress = null; + var readableStream = this._msgHandler.sendWithStream('GetRangeReader', { + begin: begin, + end: end + }); + this._reader = readableStream.getReader(); + } + + PDFWorkerStreamRangeReader.prototype = { + get isStreamingSupported() { + return false; + }, + read: function read() { + return this._reader.read().then(function (_ref2) { + var value = _ref2.value, + done = _ref2.done; + + if (done) { + return { + value: undefined, + done: true + }; + } + return { + value: value.buffer, + done: false + }; + }); + }, + cancel: function cancel(reason) { + this._reader.cancel(reason); + } + }; + return PDFWorkerStream; + }(); + var WorkerMessageHandler = { + setup: function setup(handler, port) { + var testMessageProcessed = false; + handler.on('test', function wphSetupTest(data) { + if (testMessageProcessed) { + return; + } + testMessageProcessed = true; + if (!(data instanceof Uint8Array)) { + handler.send('test', 'main', false); + return; + } + var supportTransfers = data[0] === 255; + handler.postMessageTransfers = supportTransfers; + var xhr = new XMLHttpRequest(); + var responseExists = 'response' in xhr; + try { + xhr.responseType; + } catch (e) { + responseExists = false; + } + if (!responseExists) { + handler.send('test', false); + return; + } + handler.send('test', { + supportTypedArray: true, + supportTransfers: supportTransfers + }); + }); + handler.on('configure', function wphConfigure(data) { + (0, _util.setVerbosityLevel)(data.verbosity); + }); + handler.on('GetDocRequest', function wphSetupDoc(data) { + return WorkerMessageHandler.createDocumentHandler(data, port); + }); + }, + createDocumentHandler: function createDocumentHandler(docParams, port) { + var pdfManager; + var terminated = false; + var cancelXHRs = null; + var WorkerTasks = []; + var docId = docParams.docId; + var docBaseUrl = docParams.docBaseUrl; + var workerHandlerName = docParams.docId + '_worker'; + var handler = new _util.MessageHandler(workerHandlerName, docId, port); + handler.postMessageTransfers = docParams.postMessageTransfers; + + function ensureNotTerminated() { + if (terminated) { + throw new Error('Worker was terminated'); + } + } + + function startWorkerTask(task) { + WorkerTasks.push(task); + } + + function finishWorkerTask(task) { + task.finish(); + var i = WorkerTasks.indexOf(task); + WorkerTasks.splice(i, 1); + } + + function loadDocument(recoveryMode) { + var loadDocumentCapability = (0, _util.createPromiseCapability)(); + var parseSuccess = function parseSuccess() { + var numPagesPromise = pdfManager.ensureDoc('numPages'); + var fingerprintPromise = pdfManager.ensureDoc('fingerprint'); + var encryptedPromise = pdfManager.ensureXRef('encrypt'); + Promise.all([numPagesPromise, fingerprintPromise, encryptedPromise]).then(function onDocReady(results) { + var doc = { + numPages: results[0], + fingerprint: results[1], + encrypted: !!results[2] + }; + loadDocumentCapability.resolve(doc); + }, parseFailure); + }; + var parseFailure = function parseFailure(e) { + loadDocumentCapability.reject(e); + }; + pdfManager.ensureDoc('checkHeader', []).then(function () { + pdfManager.ensureDoc('parseStartXRef', []).then(function () { + pdfManager.ensureDoc('parse', [recoveryMode]).then(parseSuccess, parseFailure); + }, parseFailure); + }, parseFailure); + return loadDocumentCapability.promise; + } + + function getPdfManager(data, evaluatorOptions) { + var pdfManagerCapability = (0, _util.createPromiseCapability)(); + var pdfManager; + var source = data.source; + if (source.data) { + try { + pdfManager = new _pdf_manager.LocalPdfManager(docId, source.data, source.password, evaluatorOptions, docBaseUrl); + pdfManagerCapability.resolve(pdfManager); + } catch (ex) { + pdfManagerCapability.reject(ex); + } + return pdfManagerCapability.promise; + } + var pdfStream, + cachedChunks = []; + try { + pdfStream = new PDFWorkerStream(handler); + } catch (ex) { + pdfManagerCapability.reject(ex); + return pdfManagerCapability.promise; + } + var fullRequest = pdfStream.getFullReader(); + fullRequest.headersReady.then(function () { + if (!fullRequest.isRangeSupported) { + return; + } + var disableAutoFetch = source.disableAutoFetch || fullRequest.isStreamingSupported; + pdfManager = new _pdf_manager.NetworkPdfManager(docId, pdfStream, { + msgHandler: handler, + url: source.url, + password: source.password, + length: fullRequest.contentLength, + disableAutoFetch: disableAutoFetch, + rangeChunkSize: source.rangeChunkSize + }, evaluatorOptions, docBaseUrl); + for (var i = 0; i < cachedChunks.length; i++) { + pdfManager.sendProgressiveData(cachedChunks[i]); + } + cachedChunks = []; + pdfManagerCapability.resolve(pdfManager); + cancelXHRs = null; + }).catch(function (reason) { + pdfManagerCapability.reject(reason); + cancelXHRs = null; + }); + var loaded = 0; + var flushChunks = function flushChunks() { + var pdfFile = (0, _util.arraysToBytes)(cachedChunks); + if (source.length && pdfFile.length !== source.length) { + (0, _util.warn)('reported HTTP length is different from actual'); + } + try { + pdfManager = new _pdf_manager.LocalPdfManager(docId, pdfFile, source.password, evaluatorOptions, docBaseUrl); + pdfManagerCapability.resolve(pdfManager); + } catch (ex) { + pdfManagerCapability.reject(ex); + } + cachedChunks = []; + }; + var readPromise = new Promise(function (resolve, reject) { + var readChunk = function readChunk(chunk) { + try { + ensureNotTerminated(); + if (chunk.done) { + if (!pdfManager) { + flushChunks(); + } + cancelXHRs = null; + return; + } + var data = chunk.value; + loaded += (0, _util.arrayByteLength)(data); + if (!fullRequest.isStreamingSupported) { + handler.send('DocProgress', { + loaded: loaded, + total: Math.max(loaded, fullRequest.contentLength || 0) + }); + } + if (pdfManager) { + pdfManager.sendProgressiveData(data); + } else { + cachedChunks.push(data); + } + fullRequest.read().then(readChunk, reject); + } catch (e) { + reject(e); + } + }; + fullRequest.read().then(readChunk, reject); + }); + readPromise.catch(function (e) { + pdfManagerCapability.reject(e); + cancelXHRs = null; + }); + cancelXHRs = function cancelXHRs() { + pdfStream.cancelAllRequests('abort'); + }; + return pdfManagerCapability.promise; + } + + function setupDoc(data) { + function onSuccess(doc) { + ensureNotTerminated(); + handler.send('GetDoc', {pdfInfo: doc}); + } + + function onFailure(e) { + ensureNotTerminated(); + if (e instanceof _util.PasswordException) { + var task = new WorkerTask('PasswordException: response ' + e.code); + startWorkerTask(task); + handler.sendWithPromise('PasswordRequest', e).then(function (data) { + finishWorkerTask(task); + pdfManager.updatePassword(data.password); + pdfManagerReady(); + }).catch(function (ex) { + finishWorkerTask(task); + handler.send('PasswordException', ex); + }.bind(null, e)); + } else if (e instanceof _util.InvalidPDFException) { + handler.send('InvalidPDF', e); + } else if (e instanceof _util.MissingPDFException) { + handler.send('MissingPDF', e); + } else if (e instanceof _util.UnexpectedResponseException) { + handler.send('UnexpectedResponse', e); + } else { + handler.send('UnknownError', new _util.UnknownErrorException(e.message, e.toString())); + } + } + + function pdfManagerReady() { + ensureNotTerminated(); + loadDocument(false).then(onSuccess, function loadFailure(ex) { + ensureNotTerminated(); + if (!(ex instanceof _util.XRefParseException)) { + onFailure(ex); + return; + } + pdfManager.requestLoadedStream(); + pdfManager.onLoadedStream().then(function () { + ensureNotTerminated(); + loadDocument(true).then(onSuccess, onFailure); + }); + }, onFailure); + } + + ensureNotTerminated(); + var evaluatorOptions = { + forceDataSchema: data.disableCreateObjectURL, + maxImageSize: data.maxImageSize === undefined ? -1 : data.maxImageSize, + disableFontFace: data.disableFontFace, + nativeImageDecoderSupport: data.nativeImageDecoderSupport, + ignoreErrors: data.ignoreErrors + }; + getPdfManager(data, evaluatorOptions).then(function (newPdfManager) { + if (terminated) { + newPdfManager.terminate(); + throw new Error('Worker was terminated'); + } + pdfManager = newPdfManager; + handler.send('PDFManagerReady', null); + pdfManager.onLoadedStream().then(function (stream) { + handler.send('DataLoaded', {length: stream.bytes.byteLength}); + }); + }).then(pdfManagerReady, onFailure); + } + + handler.on('GetPage', function wphSetupGetPage(data) { + return pdfManager.getPage(data.pageIndex).then(function (page) { + var rotatePromise = pdfManager.ensure(page, 'rotate'); + var refPromise = pdfManager.ensure(page, 'ref'); + var userUnitPromise = pdfManager.ensure(page, 'userUnit'); + var viewPromise = pdfManager.ensure(page, 'view'); + return Promise.all([rotatePromise, refPromise, userUnitPromise, viewPromise]).then(function (results) { + return { + rotate: results[0], + ref: results[1], + userUnit: results[2], + view: results[3] + }; + }); + }); + }); + handler.on('GetPageIndex', function wphSetupGetPageIndex(data) { + var ref = new _primitives.Ref(data.ref.num, data.ref.gen); + var catalog = pdfManager.pdfDocument.catalog; + return catalog.getPageIndex(ref); + }); + handler.on('GetDestinations', function wphSetupGetDestinations(data) { + return pdfManager.ensureCatalog('destinations'); + }); + handler.on('GetDestination', function wphSetupGetDestination(data) { + return pdfManager.ensureCatalog('getDestination', [data.id]); + }); + handler.on('GetPageLabels', function wphSetupGetPageLabels(data) { + return pdfManager.ensureCatalog('pageLabels'); + }); + handler.on('GetPageMode', function wphSetupGetPageMode(data) { + return pdfManager.ensureCatalog('pageMode'); + }); + handler.on('GetAttachments', function wphSetupGetAttachments(data) { + return pdfManager.ensureCatalog('attachments'); + }); + handler.on('GetJavaScript', function wphSetupGetJavaScript(data) { + return pdfManager.ensureCatalog('javaScript'); + }); + handler.on('GetOutline', function wphSetupGetOutline(data) { + return pdfManager.ensureCatalog('documentOutline'); + }); + handler.on('GetMetadata', function wphSetupGetMetadata(data) { + return Promise.all([pdfManager.ensureDoc('documentInfo'), pdfManager.ensureCatalog('metadata')]); + }); + 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.pdfDocument.xref.stats; + }); + handler.on('GetAnnotations', function wphSetupGetAnnotations(data) { + return pdfManager.getPage(data.pageIndex).then(function (page) { + return pdfManager.ensure(page, 'getAnnotationsData', [data.intent]); + }); + }); + handler.on('RenderPageRequest', function wphSetupRenderPage(data) { + var pageIndex = data.pageIndex; + pdfManager.getPage(pageIndex).then(function (page) { + var task = new WorkerTask('RenderPageRequest: page ' + pageIndex); + startWorkerTask(task); + var pageNum = pageIndex + 1; + var start = Date.now(); + page.getOperatorList({ + handler: handler, + task: task, + intent: data.intent, + renderInteractiveForms: data.renderInteractiveForms + }).then(function (operatorList) { + finishWorkerTask(task); + (0, _util.info)('page=' + pageNum + ' - getOperatorList: time=' + (Date.now() - start) + 'ms, len=' + operatorList.totalLength); + }, function (e) { + finishWorkerTask(task); + if (task.terminated) { + return; + } + handler.send('UnsupportedFeature', {featureId: _util.UNSUPPORTED_FEATURES.unknown}); + var minimumStackMessage = 'worker.js: while trying to getPage() and getOperatorList()'; + var wrappedException; + if (typeof e === 'string') { + wrappedException = { + message: e, + stack: minimumStackMessage + }; + } else if ((typeof e === 'undefined' ? 'undefined' : _typeof(e)) === 'object') { + wrappedException = { + message: e.message || e.toString(), + stack: e.stack || minimumStackMessage + }; + } else { + wrappedException = { + message: 'Unknown exception type: ' + (typeof e === 'undefined' ? 'undefined' : _typeof(e)), + stack: minimumStackMessage + }; + } + handler.send('PageError', { + pageNum: pageNum, + error: wrappedException, + intent: data.intent + }); + }); + }); + }, this); + handler.on('GetTextContent', function wphExtractText(data, sink) { + var pageIndex = data.pageIndex; + sink.onPull = function (desiredSize) { + }; + sink.onCancel = function (reason) { + }; + pdfManager.getPage(pageIndex).then(function (page) { + var task = new WorkerTask('GetTextContent: page ' + pageIndex); + startWorkerTask(task); + var pageNum = pageIndex + 1; + var start = Date.now(); + page.extractTextContent({ + handler: handler, + task: task, + sink: sink, + normalizeWhitespace: data.normalizeWhitespace, + combineTextItems: data.combineTextItems + }).then(function () { + finishWorkerTask(task); + (0, _util.info)('text indexing: page=' + pageNum + ' - time=' + (Date.now() - start) + 'ms'); + sink.close(); + }, function (reason) { + finishWorkerTask(task); + if (task.terminated) { + return; + } + sink.error(reason); + throw reason; + }); + }); + }); + handler.on('Cleanup', function wphCleanup(data) { + return pdfManager.cleanup(); + }); + handler.on('Terminate', function wphTerminate(data) { + terminated = true; + if (pdfManager) { + pdfManager.terminate(); + pdfManager = null; + } + if (cancelXHRs) { + cancelXHRs(); + } + var waitOn = []; + WorkerTasks.forEach(function (task) { + waitOn.push(task.finished); + task.terminate(); + }); + return Promise.all(waitOn).then(function () { + handler.destroy(); + handler = null; + }); + }); + handler.on('Ready', function wphReady(data) { + setupDoc(docParams); + docParams = null; + }); + return workerHandlerName; + }, + initializeFromPort: function initializeFromPort(port) { + var handler = new _util.MessageHandler('worker', 'main', port); + WorkerMessageHandler.setup(handler, port); + handler.send('ready', null); + } + }; + + function isMessagePort(maybePort) { + return typeof maybePort.postMessage === 'function' && 'onmessage' in maybePort; + } + + if (typeof window === 'undefined' && !(0, _util.isNodeJS)() && typeof self !== 'undefined' && isMessagePort(self)) { + WorkerMessageHandler.initializeFromPort(self); + } + exports.WorkerTask = WorkerTask; + exports.WorkerMessageHandler = WorkerMessageHandler; + + /***/ + }), + /* 18 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + var _typeof2 = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + (function (e, a) { + for (var i in a) { + e[i] = a[i]; + } + })(exports, function (modules) { + var installedModules = {}; + + function __w_pdfjs_require__(moduleId) { + if (installedModules[moduleId]) return installedModules[moduleId].exports; + var module = installedModules[moduleId] = { + i: moduleId, + l: false, + exports: {} + }; + modules[moduleId].call(module.exports, module, module.exports, __w_pdfjs_require__); + module.l = true; + return module.exports; + } + + __w_pdfjs_require__.m = modules; + __w_pdfjs_require__.c = installedModules; + __w_pdfjs_require__.i = function (value) { + return value; + }; + __w_pdfjs_require__.d = function (exports, name, getter) { + if (!__w_pdfjs_require__.o(exports, name)) { + Object.defineProperty(exports, name, { + configurable: false, + enumerable: true, + get: getter + }); + } + }; + __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; + }; + __w_pdfjs_require__.o = function (object, property) { + return Object.prototype.hasOwnProperty.call(object, property); + }; + __w_pdfjs_require__.p = ""; + return __w_pdfjs_require__(__w_pdfjs_require__.s = 7); + }([function (module, exports, __w_pdfjs_require__) { + "use strict"; + + var _typeof = typeof Symbol === "function" && _typeof2(Symbol.iterator) === "symbol" ? function (obj) { + return typeof obj === 'undefined' ? 'undefined' : _typeof2(obj); + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj === 'undefined' ? 'undefined' : _typeof2(obj); + }; + var _require = __w_pdfjs_require__(1), + assert = _require.assert; + + function IsPropertyKey(argument) { + return typeof argument === 'string' || (typeof argument === 'undefined' ? 'undefined' : _typeof(argument)) === 'symbol'; + } + + exports.typeIsObject = function (x) { + return (typeof x === 'undefined' ? 'undefined' : _typeof(x)) === 'object' && x !== null || typeof x === 'function'; + }; + exports.createDataProperty = function (o, p, v) { + assert(exports.typeIsObject(o)); + Object.defineProperty(o, p, { + value: v, + writable: true, + enumerable: true, + configurable: true + }); + }; + exports.createArrayFromList = function (elements) { + return elements.slice(); + }; + exports.ArrayBufferCopy = function (dest, destOffset, src, srcOffset, n) { + new Uint8Array(dest).set(new Uint8Array(src, srcOffset, n), destOffset); + }; + exports.CreateIterResultObject = function (value, done) { + assert(typeof done === 'boolean'); + var obj = {}; + Object.defineProperty(obj, 'value', { + value: value, + enumerable: true, + writable: true, + configurable: true + }); + Object.defineProperty(obj, 'done', { + value: done, + enumerable: true, + writable: true, + configurable: true + }); + return obj; + }; + exports.IsFiniteNonNegativeNumber = function (v) { + if (Number.isNaN(v)) { + return false; + } + if (v === Infinity) { + return false; + } + if (v < 0) { + return false; + } + return true; + }; + + function Call(F, V, args) { + if (typeof F !== 'function') { + throw new TypeError('Argument is not a function'); + } + return Function.prototype.apply.call(F, V, args); + } + + exports.InvokeOrNoop = function (O, P, args) { + assert(O !== undefined); + assert(IsPropertyKey(P)); + assert(Array.isArray(args)); + var method = O[P]; + if (method === undefined) { + return undefined; + } + return Call(method, O, args); + }; + exports.PromiseInvokeOrNoop = function (O, P, args) { + assert(O !== undefined); + assert(IsPropertyKey(P)); + assert(Array.isArray(args)); + try { + return Promise.resolve(exports.InvokeOrNoop(O, P, args)); + } catch (returnValueE) { + return Promise.reject(returnValueE); + } + }; + exports.PromiseInvokeOrPerformFallback = function (O, P, args, F, argsF) { + assert(O !== undefined); + assert(IsPropertyKey(P)); + assert(Array.isArray(args)); + assert(Array.isArray(argsF)); + var method = void 0; + try { + method = O[P]; + } catch (methodE) { + return Promise.reject(methodE); + } + if (method === undefined) { + return F.apply(null, argsF); + } + try { + return Promise.resolve(Call(method, O, args)); + } catch (e) { + return Promise.reject(e); + } + }; + exports.TransferArrayBuffer = function (O) { + return O.slice(); + }; + exports.ValidateAndNormalizeHighWaterMark = function (highWaterMark) { + highWaterMark = Number(highWaterMark); + if (Number.isNaN(highWaterMark) || highWaterMark < 0) { + throw new RangeError('highWaterMark property of a queuing strategy must be non-negative and non-NaN'); + } + return highWaterMark; + }; + exports.ValidateAndNormalizeQueuingStrategy = function (size, highWaterMark) { + if (size !== undefined && typeof size !== 'function') { + throw new TypeError('size property of a queuing strategy must be a function'); + } + highWaterMark = exports.ValidateAndNormalizeHighWaterMark(highWaterMark); + return { + size: size, + highWaterMark: highWaterMark + }; + }; + }, function (module, exports, __w_pdfjs_require__) { + "use strict"; + + function rethrowAssertionErrorRejection(e) { + if (e && e.constructor === AssertionError) { + setTimeout(function () { + throw e; + }, 0); + } + } + + function AssertionError(message) { + this.name = 'AssertionError'; + this.message = message || ''; + this.stack = new Error().stack; + } + + AssertionError.prototype = Object.create(Error.prototype); + AssertionError.prototype.constructor = AssertionError; + + function assert(value, message) { + if (!value) { + throw new AssertionError(message); + } + } + + module.exports = { + rethrowAssertionErrorRejection: rethrowAssertionErrorRejection, + AssertionError: AssertionError, + assert: assert + }; + }, function (module, exports, __w_pdfjs_require__) { + "use strict"; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var _require = __w_pdfjs_require__(0), + InvokeOrNoop = _require.InvokeOrNoop, + PromiseInvokeOrNoop = _require.PromiseInvokeOrNoop, + ValidateAndNormalizeQueuingStrategy = _require.ValidateAndNormalizeQueuingStrategy, + typeIsObject = _require.typeIsObject; + var _require2 = __w_pdfjs_require__(1), + assert = _require2.assert, + rethrowAssertionErrorRejection = _require2.rethrowAssertionErrorRejection; + var _require3 = __w_pdfjs_require__(3), + DequeueValue = _require3.DequeueValue, + EnqueueValueWithSize = _require3.EnqueueValueWithSize, + PeekQueueValue = _require3.PeekQueueValue, + ResetQueue = _require3.ResetQueue; + var WritableStream = function () { + function WritableStream() { + var underlyingSink = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, + size = _ref.size, + _ref$highWaterMark = _ref.highWaterMark, + highWaterMark = _ref$highWaterMark === undefined ? 1 : _ref$highWaterMark; + _classCallCheck(this, WritableStream); + this._state = 'writable'; + this._storedError = undefined; + this._writer = undefined; + this._writableStreamController = undefined; + this._writeRequests = []; + this._inFlightWriteRequest = undefined; + this._closeRequest = undefined; + this._inFlightCloseRequest = undefined; + this._pendingAbortRequest = undefined; + this._backpressure = false; + var type = underlyingSink.type; + if (type !== undefined) { + throw new RangeError('Invalid type is specified'); + } + this._writableStreamController = new WritableStreamDefaultController(this, underlyingSink, size, highWaterMark); + this._writableStreamController.__startSteps(); + } + + _createClass(WritableStream, [{ + key: 'abort', + value: function abort(reason) { + if (IsWritableStream(this) === false) { + return Promise.reject(streamBrandCheckException('abort')); + } + if (IsWritableStreamLocked(this) === true) { + return Promise.reject(new TypeError('Cannot abort a stream that already has a writer')); + } + return WritableStreamAbort(this, reason); + } + }, { + key: 'getWriter', + value: function getWriter() { + if (IsWritableStream(this) === false) { + throw streamBrandCheckException('getWriter'); + } + return AcquireWritableStreamDefaultWriter(this); + } + }, { + key: 'locked', + get: function get() { + if (IsWritableStream(this) === false) { + throw streamBrandCheckException('locked'); + } + return IsWritableStreamLocked(this); + } + }]); + return WritableStream; + }(); + module.exports = { + AcquireWritableStreamDefaultWriter: AcquireWritableStreamDefaultWriter, + IsWritableStream: IsWritableStream, + IsWritableStreamLocked: IsWritableStreamLocked, + WritableStream: WritableStream, + WritableStreamAbort: WritableStreamAbort, + WritableStreamDefaultControllerError: WritableStreamDefaultControllerError, + WritableStreamDefaultWriterCloseWithErrorPropagation: WritableStreamDefaultWriterCloseWithErrorPropagation, + WritableStreamDefaultWriterRelease: WritableStreamDefaultWriterRelease, + WritableStreamDefaultWriterWrite: WritableStreamDefaultWriterWrite, + WritableStreamCloseQueuedOrInFlight: WritableStreamCloseQueuedOrInFlight + }; + + function AcquireWritableStreamDefaultWriter(stream) { + return new WritableStreamDefaultWriter(stream); + } + + function IsWritableStream(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_writableStreamController')) { + return false; + } + return true; + } + + function IsWritableStreamLocked(stream) { + assert(IsWritableStream(stream) === true, 'IsWritableStreamLocked should only be used on known writable streams'); + if (stream._writer === undefined) { + return false; + } + return true; + } + + function WritableStreamAbort(stream, reason) { + var state = stream._state; + if (state === 'closed') { + return Promise.resolve(undefined); + } + if (state === 'errored') { + return Promise.reject(stream._storedError); + } + var error = new TypeError('Requested to abort'); + if (stream._pendingAbortRequest !== undefined) { + return Promise.reject(error); + } + assert(state === 'writable' || state === 'erroring', 'state must be writable or erroring'); + var wasAlreadyErroring = false; + if (state === 'erroring') { + wasAlreadyErroring = true; + reason = undefined; + } + var promise = new Promise(function (resolve, reject) { + stream._pendingAbortRequest = { + _resolve: resolve, + _reject: reject, + _reason: reason, + _wasAlreadyErroring: wasAlreadyErroring + }; + }); + if (wasAlreadyErroring === false) { + WritableStreamStartErroring(stream, error); + } + return promise; + } + + function WritableStreamAddWriteRequest(stream) { + assert(IsWritableStreamLocked(stream) === true); + assert(stream._state === 'writable'); + var promise = new Promise(function (resolve, reject) { + var writeRequest = { + _resolve: resolve, + _reject: reject + }; + stream._writeRequests.push(writeRequest); + }); + return promise; + } + + function WritableStreamDealWithRejection(stream, error) { + var state = stream._state; + if (state === 'writable') { + WritableStreamStartErroring(stream, error); + return; + } + assert(state === 'erroring'); + WritableStreamFinishErroring(stream); + } + + function WritableStreamStartErroring(stream, reason) { + assert(stream._storedError === undefined, 'stream._storedError === undefined'); + assert(stream._state === 'writable', 'state must be writable'); + var controller = stream._writableStreamController; + assert(controller !== undefined, 'controller must not be undefined'); + stream._state = 'erroring'; + stream._storedError = reason; + var writer = stream._writer; + if (writer !== undefined) { + WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason); + } + if (WritableStreamHasOperationMarkedInFlight(stream) === false && controller._started === true) { + WritableStreamFinishErroring(stream); + } + } + + function WritableStreamFinishErroring(stream) { + assert(stream._state === 'erroring', 'stream._state === erroring'); + assert(WritableStreamHasOperationMarkedInFlight(stream) === false, 'WritableStreamHasOperationMarkedInFlight(stream) === false'); + stream._state = 'errored'; + stream._writableStreamController.__errorSteps(); + var storedError = stream._storedError; + for (var i = 0; i < stream._writeRequests.length; i++) { + var writeRequest = stream._writeRequests[i]; + writeRequest._reject(storedError); + } + stream._writeRequests = []; + if (stream._pendingAbortRequest === undefined) { + WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); + return; + } + var abortRequest = stream._pendingAbortRequest; + stream._pendingAbortRequest = undefined; + if (abortRequest._wasAlreadyErroring === true) { + abortRequest._reject(storedError); + WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); + return; + } + var promise = stream._writableStreamController.__abortSteps(abortRequest._reason); + promise.then(function () { + abortRequest._resolve(); + WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); + }, function (reason) { + abortRequest._reject(reason); + WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); + }); + } + + function WritableStreamFinishInFlightWrite(stream) { + assert(stream._inFlightWriteRequest !== undefined); + stream._inFlightWriteRequest._resolve(undefined); + stream._inFlightWriteRequest = undefined; + } + + function WritableStreamFinishInFlightWriteWithError(stream, error) { + assert(stream._inFlightWriteRequest !== undefined); + stream._inFlightWriteRequest._reject(error); + stream._inFlightWriteRequest = undefined; + assert(stream._state === 'writable' || stream._state === 'erroring'); + WritableStreamDealWithRejection(stream, error); + } + + function WritableStreamFinishInFlightClose(stream) { + assert(stream._inFlightCloseRequest !== undefined); + stream._inFlightCloseRequest._resolve(undefined); + stream._inFlightCloseRequest = undefined; + var state = stream._state; + assert(state === 'writable' || state === 'erroring'); + if (state === 'erroring') { + stream._storedError = undefined; + if (stream._pendingAbortRequest !== undefined) { + stream._pendingAbortRequest._resolve(); + stream._pendingAbortRequest = undefined; + } + } + stream._state = 'closed'; + var writer = stream._writer; + if (writer !== undefined) { + defaultWriterClosedPromiseResolve(writer); + } + assert(stream._pendingAbortRequest === undefined, 'stream._pendingAbortRequest === undefined'); + assert(stream._storedError === undefined, 'stream._storedError === undefined'); + } + + function WritableStreamFinishInFlightCloseWithError(stream, error) { + assert(stream._inFlightCloseRequest !== undefined); + stream._inFlightCloseRequest._reject(error); + stream._inFlightCloseRequest = undefined; + assert(stream._state === 'writable' || stream._state === 'erroring'); + if (stream._pendingAbortRequest !== undefined) { + stream._pendingAbortRequest._reject(error); + stream._pendingAbortRequest = undefined; + } + WritableStreamDealWithRejection(stream, error); + } + + function WritableStreamCloseQueuedOrInFlight(stream) { + if (stream._closeRequest === undefined && stream._inFlightCloseRequest === undefined) { + return false; + } + return true; + } + + function WritableStreamHasOperationMarkedInFlight(stream) { + if (stream._inFlightWriteRequest === undefined && stream._inFlightCloseRequest === undefined) { + return false; + } + return true; + } + + function WritableStreamMarkCloseRequestInFlight(stream) { + assert(stream._inFlightCloseRequest === undefined); + assert(stream._closeRequest !== undefined); + stream._inFlightCloseRequest = stream._closeRequest; + stream._closeRequest = undefined; + } + + function WritableStreamMarkFirstWriteRequestInFlight(stream) { + assert(stream._inFlightWriteRequest === undefined, 'there must be no pending write request'); + assert(stream._writeRequests.length !== 0, 'writeRequests must not be empty'); + stream._inFlightWriteRequest = stream._writeRequests.shift(); + } + + function WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream) { + assert(stream._state === 'errored', '_stream_.[[state]] is `"errored"`'); + if (stream._closeRequest !== undefined) { + assert(stream._inFlightCloseRequest === undefined); + stream._closeRequest._reject(stream._storedError); + stream._closeRequest = undefined; + } + var writer = stream._writer; + if (writer !== undefined) { + defaultWriterClosedPromiseReject(writer, stream._storedError); + writer._closedPromise.catch(function () { + }); + } + } + + function WritableStreamUpdateBackpressure(stream, backpressure) { + assert(stream._state === 'writable'); + assert(WritableStreamCloseQueuedOrInFlight(stream) === false); + var writer = stream._writer; + if (writer !== undefined && backpressure !== stream._backpressure) { + if (backpressure === true) { + defaultWriterReadyPromiseReset(writer); + } else { + assert(backpressure === false); + defaultWriterReadyPromiseResolve(writer); + } + } + stream._backpressure = backpressure; + } + + var WritableStreamDefaultWriter = function () { + function WritableStreamDefaultWriter(stream) { + _classCallCheck(this, WritableStreamDefaultWriter); + if (IsWritableStream(stream) === false) { + throw new TypeError('WritableStreamDefaultWriter can only be constructed with a WritableStream instance'); + } + if (IsWritableStreamLocked(stream) === true) { + throw new TypeError('This stream has already been locked for exclusive writing by another writer'); + } + this._ownerWritableStream = stream; + stream._writer = this; + var state = stream._state; + if (state === 'writable') { + if (WritableStreamCloseQueuedOrInFlight(stream) === false && stream._backpressure === true) { + defaultWriterReadyPromiseInitialize(this); + } else { + defaultWriterReadyPromiseInitializeAsResolved(this); + } + defaultWriterClosedPromiseInitialize(this); + } else if (state === 'erroring') { + defaultWriterReadyPromiseInitializeAsRejected(this, stream._storedError); + this._readyPromise.catch(function () { + }); + defaultWriterClosedPromiseInitialize(this); + } else if (state === 'closed') { + defaultWriterReadyPromiseInitializeAsResolved(this); + defaultWriterClosedPromiseInitializeAsResolved(this); + } else { + assert(state === 'errored', 'state must be errored'); + var storedError = stream._storedError; + defaultWriterReadyPromiseInitializeAsRejected(this, storedError); + this._readyPromise.catch(function () { + }); + defaultWriterClosedPromiseInitializeAsRejected(this, storedError); + this._closedPromise.catch(function () { + }); + } + } + + _createClass(WritableStreamDefaultWriter, [{ + key: 'abort', + value: function abort(reason) { + if (IsWritableStreamDefaultWriter(this) === false) { + return Promise.reject(defaultWriterBrandCheckException('abort')); + } + if (this._ownerWritableStream === undefined) { + return Promise.reject(defaultWriterLockException('abort')); + } + return WritableStreamDefaultWriterAbort(this, reason); + } + }, { + key: 'close', + value: function close() { + if (IsWritableStreamDefaultWriter(this) === false) { + return Promise.reject(defaultWriterBrandCheckException('close')); + } + var stream = this._ownerWritableStream; + if (stream === undefined) { + return Promise.reject(defaultWriterLockException('close')); + } + if (WritableStreamCloseQueuedOrInFlight(stream) === true) { + return Promise.reject(new TypeError('cannot close an already-closing stream')); + } + return WritableStreamDefaultWriterClose(this); + } + }, { + key: 'releaseLock', + value: function releaseLock() { + if (IsWritableStreamDefaultWriter(this) === false) { + throw defaultWriterBrandCheckException('releaseLock'); + } + var stream = this._ownerWritableStream; + if (stream === undefined) { + return; + } + assert(stream._writer !== undefined); + WritableStreamDefaultWriterRelease(this); + } + }, { + key: 'write', + value: function write(chunk) { + if (IsWritableStreamDefaultWriter(this) === false) { + return Promise.reject(defaultWriterBrandCheckException('write')); + } + if (this._ownerWritableStream === undefined) { + return Promise.reject(defaultWriterLockException('write to')); + } + return WritableStreamDefaultWriterWrite(this, chunk); + } + }, { + key: 'closed', + get: function get() { + if (IsWritableStreamDefaultWriter(this) === false) { + return Promise.reject(defaultWriterBrandCheckException('closed')); + } + return this._closedPromise; + } + }, { + key: 'desiredSize', + get: function get() { + if (IsWritableStreamDefaultWriter(this) === false) { + throw defaultWriterBrandCheckException('desiredSize'); + } + if (this._ownerWritableStream === undefined) { + throw defaultWriterLockException('desiredSize'); + } + return WritableStreamDefaultWriterGetDesiredSize(this); + } + }, { + key: 'ready', + get: function get() { + if (IsWritableStreamDefaultWriter(this) === false) { + return Promise.reject(defaultWriterBrandCheckException('ready')); + } + return this._readyPromise; + } + }]); + return WritableStreamDefaultWriter; + }(); + + function IsWritableStreamDefaultWriter(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_ownerWritableStream')) { + return false; + } + return true; + } + + function WritableStreamDefaultWriterAbort(writer, reason) { + var stream = writer._ownerWritableStream; + assert(stream !== undefined); + return WritableStreamAbort(stream, reason); + } + + function WritableStreamDefaultWriterClose(writer) { + var stream = writer._ownerWritableStream; + assert(stream !== undefined); + var state = stream._state; + if (state === 'closed' || state === 'errored') { + return Promise.reject(new TypeError('The stream (in ' + state + ' state) is not in the writable state and cannot be closed')); + } + assert(state === 'writable' || state === 'erroring'); + assert(WritableStreamCloseQueuedOrInFlight(stream) === false); + var promise = new Promise(function (resolve, reject) { + var closeRequest = { + _resolve: resolve, + _reject: reject + }; + stream._closeRequest = closeRequest; + }); + if (stream._backpressure === true && state === 'writable') { + defaultWriterReadyPromiseResolve(writer); + } + WritableStreamDefaultControllerClose(stream._writableStreamController); + return promise; + } + + function WritableStreamDefaultWriterCloseWithErrorPropagation(writer) { + var stream = writer._ownerWritableStream; + assert(stream !== undefined); + var state = stream._state; + if (WritableStreamCloseQueuedOrInFlight(stream) === true || state === 'closed') { + return Promise.resolve(); + } + if (state === 'errored') { + return Promise.reject(stream._storedError); + } + assert(state === 'writable' || state === 'erroring'); + return WritableStreamDefaultWriterClose(writer); + } + + function WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, error) { + if (writer._closedPromiseState === 'pending') { + defaultWriterClosedPromiseReject(writer, error); + } else { + defaultWriterClosedPromiseResetToRejected(writer, error); + } + writer._closedPromise.catch(function () { + }); + } + + function WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, error) { + if (writer._readyPromiseState === 'pending') { + defaultWriterReadyPromiseReject(writer, error); + } else { + defaultWriterReadyPromiseResetToRejected(writer, error); + } + writer._readyPromise.catch(function () { + }); + } + + function WritableStreamDefaultWriterGetDesiredSize(writer) { + var stream = writer._ownerWritableStream; + var state = stream._state; + if (state === 'errored' || state === 'erroring') { + return null; + } + if (state === 'closed') { + return 0; + } + return WritableStreamDefaultControllerGetDesiredSize(stream._writableStreamController); + } + + function WritableStreamDefaultWriterRelease(writer) { + var stream = writer._ownerWritableStream; + assert(stream !== undefined); + assert(stream._writer === writer); + var releasedError = new TypeError('Writer was released and can no longer be used to monitor the stream\'s closedness'); + WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, releasedError); + WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, releasedError); + stream._writer = undefined; + writer._ownerWritableStream = undefined; + } + + function WritableStreamDefaultWriterWrite(writer, chunk) { + var stream = writer._ownerWritableStream; + assert(stream !== undefined); + var controller = stream._writableStreamController; + var chunkSize = WritableStreamDefaultControllerGetChunkSize(controller, chunk); + if (stream !== writer._ownerWritableStream) { + return Promise.reject(defaultWriterLockException('write to')); + } + var state = stream._state; + if (state === 'errored') { + return Promise.reject(stream._storedError); + } + if (WritableStreamCloseQueuedOrInFlight(stream) === true || state === 'closed') { + return Promise.reject(new TypeError('The stream is closing or closed and cannot be written to')); + } + if (state === 'erroring') { + return Promise.reject(stream._storedError); + } + assert(state === 'writable'); + var promise = WritableStreamAddWriteRequest(stream); + WritableStreamDefaultControllerWrite(controller, chunk, chunkSize); + return promise; + } + + var WritableStreamDefaultController = function () { + function WritableStreamDefaultController(stream, underlyingSink, size, highWaterMark) { + _classCallCheck(this, WritableStreamDefaultController); + if (IsWritableStream(stream) === false) { + throw new TypeError('WritableStreamDefaultController can only be constructed with a WritableStream instance'); + } + if (stream._writableStreamController !== undefined) { + throw new TypeError('WritableStreamDefaultController instances can only be created by the WritableStream constructor'); + } + this._controlledWritableStream = stream; + this._underlyingSink = underlyingSink; + this._queue = undefined; + this._queueTotalSize = undefined; + ResetQueue(this); + this._started = false; + var normalizedStrategy = ValidateAndNormalizeQueuingStrategy(size, highWaterMark); + this._strategySize = normalizedStrategy.size; + this._strategyHWM = normalizedStrategy.highWaterMark; + var backpressure = WritableStreamDefaultControllerGetBackpressure(this); + WritableStreamUpdateBackpressure(stream, backpressure); + } + + _createClass(WritableStreamDefaultController, [{ + key: 'error', + value: function error(e) { + if (IsWritableStreamDefaultController(this) === false) { + throw new TypeError('WritableStreamDefaultController.prototype.error can only be used on a WritableStreamDefaultController'); + } + var state = this._controlledWritableStream._state; + if (state !== 'writable') { + return; + } + WritableStreamDefaultControllerError(this, e); + } + }, { + key: '__abortSteps', + value: function __abortSteps(reason) { + return PromiseInvokeOrNoop(this._underlyingSink, 'abort', [reason]); + } + }, { + key: '__errorSteps', + value: function __errorSteps() { + ResetQueue(this); + } + }, { + key: '__startSteps', + value: function __startSteps() { + var _this = this; + var startResult = InvokeOrNoop(this._underlyingSink, 'start', [this]); + var stream = this._controlledWritableStream; + Promise.resolve(startResult).then(function () { + assert(stream._state === 'writable' || stream._state === 'erroring'); + _this._started = true; + WritableStreamDefaultControllerAdvanceQueueIfNeeded(_this); + }, function (r) { + assert(stream._state === 'writable' || stream._state === 'erroring'); + _this._started = true; + WritableStreamDealWithRejection(stream, r); + }).catch(rethrowAssertionErrorRejection); + } + }]); + return WritableStreamDefaultController; + }(); + + function WritableStreamDefaultControllerClose(controller) { + EnqueueValueWithSize(controller, 'close', 0); + WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); + } + + function WritableStreamDefaultControllerGetChunkSize(controller, chunk) { + var strategySize = controller._strategySize; + if (strategySize === undefined) { + return 1; + } + try { + return strategySize(chunk); + } catch (chunkSizeE) { + WritableStreamDefaultControllerErrorIfNeeded(controller, chunkSizeE); + return 1; + } + } + + function WritableStreamDefaultControllerGetDesiredSize(controller) { + return controller._strategyHWM - controller._queueTotalSize; + } + + function WritableStreamDefaultControllerWrite(controller, chunk, chunkSize) { + var writeRecord = {chunk: chunk}; + try { + EnqueueValueWithSize(controller, writeRecord, chunkSize); + } catch (enqueueE) { + WritableStreamDefaultControllerErrorIfNeeded(controller, enqueueE); + return; + } + var stream = controller._controlledWritableStream; + if (WritableStreamCloseQueuedOrInFlight(stream) === false && stream._state === 'writable') { + var backpressure = WritableStreamDefaultControllerGetBackpressure(controller); + WritableStreamUpdateBackpressure(stream, backpressure); + } + WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); + } + + function IsWritableStreamDefaultController(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_underlyingSink')) { + return false; + } + return true; + } + + function WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller) { + var stream = controller._controlledWritableStream; + if (controller._started === false) { + return; + } + if (stream._inFlightWriteRequest !== undefined) { + return; + } + var state = stream._state; + if (state === 'closed' || state === 'errored') { + return; + } + if (state === 'erroring') { + WritableStreamFinishErroring(stream); + return; + } + if (controller._queue.length === 0) { + return; + } + var writeRecord = PeekQueueValue(controller); + if (writeRecord === 'close') { + WritableStreamDefaultControllerProcessClose(controller); + } else { + WritableStreamDefaultControllerProcessWrite(controller, writeRecord.chunk); + } + } + + function WritableStreamDefaultControllerErrorIfNeeded(controller, error) { + if (controller._controlledWritableStream._state === 'writable') { + WritableStreamDefaultControllerError(controller, error); + } + } + + function WritableStreamDefaultControllerProcessClose(controller) { + var stream = controller._controlledWritableStream; + WritableStreamMarkCloseRequestInFlight(stream); + DequeueValue(controller); + assert(controller._queue.length === 0, 'queue must be empty once the final write record is dequeued'); + var sinkClosePromise = PromiseInvokeOrNoop(controller._underlyingSink, 'close', []); + sinkClosePromise.then(function () { + WritableStreamFinishInFlightClose(stream); + }, function (reason) { + WritableStreamFinishInFlightCloseWithError(stream, reason); + }).catch(rethrowAssertionErrorRejection); + } + + function WritableStreamDefaultControllerProcessWrite(controller, chunk) { + var stream = controller._controlledWritableStream; + WritableStreamMarkFirstWriteRequestInFlight(stream); + var sinkWritePromise = PromiseInvokeOrNoop(controller._underlyingSink, 'write', [chunk, controller]); + sinkWritePromise.then(function () { + WritableStreamFinishInFlightWrite(stream); + var state = stream._state; + assert(state === 'writable' || state === 'erroring'); + DequeueValue(controller); + if (WritableStreamCloseQueuedOrInFlight(stream) === false && state === 'writable') { + var backpressure = WritableStreamDefaultControllerGetBackpressure(controller); + WritableStreamUpdateBackpressure(stream, backpressure); + } + WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); + }, function (reason) { + WritableStreamFinishInFlightWriteWithError(stream, reason); + }).catch(rethrowAssertionErrorRejection); + } + + function WritableStreamDefaultControllerGetBackpressure(controller) { + var desiredSize = WritableStreamDefaultControllerGetDesiredSize(controller); + return desiredSize <= 0; + } + + function WritableStreamDefaultControllerError(controller, error) { + var stream = controller._controlledWritableStream; + assert(stream._state === 'writable'); + WritableStreamStartErroring(stream, error); + } + + function streamBrandCheckException(name) { + return new TypeError('WritableStream.prototype.' + name + ' can only be used on a WritableStream'); + } + + function defaultWriterBrandCheckException(name) { + return new TypeError('WritableStreamDefaultWriter.prototype.' + name + ' can only be used on a WritableStreamDefaultWriter'); + } + + function defaultWriterLockException(name) { + return new TypeError('Cannot ' + name + ' a stream using a released writer'); + } + + function defaultWriterClosedPromiseInitialize(writer) { + writer._closedPromise = new Promise(function (resolve, reject) { + writer._closedPromise_resolve = resolve; + writer._closedPromise_reject = reject; + writer._closedPromiseState = 'pending'; + }); + } + + function defaultWriterClosedPromiseInitializeAsRejected(writer, reason) { + writer._closedPromise = Promise.reject(reason); + writer._closedPromise_resolve = undefined; + writer._closedPromise_reject = undefined; + writer._closedPromiseState = 'rejected'; + } + + function defaultWriterClosedPromiseInitializeAsResolved(writer) { + writer._closedPromise = Promise.resolve(undefined); + writer._closedPromise_resolve = undefined; + writer._closedPromise_reject = undefined; + writer._closedPromiseState = 'resolved'; + } + + function defaultWriterClosedPromiseReject(writer, reason) { + assert(writer._closedPromise_resolve !== undefined, 'writer._closedPromise_resolve !== undefined'); + assert(writer._closedPromise_reject !== undefined, 'writer._closedPromise_reject !== undefined'); + assert(writer._closedPromiseState === 'pending', 'writer._closedPromiseState is pending'); + writer._closedPromise_reject(reason); + writer._closedPromise_resolve = undefined; + writer._closedPromise_reject = undefined; + writer._closedPromiseState = 'rejected'; + } + + function defaultWriterClosedPromiseResetToRejected(writer, reason) { + assert(writer._closedPromise_resolve === undefined, 'writer._closedPromise_resolve === undefined'); + assert(writer._closedPromise_reject === undefined, 'writer._closedPromise_reject === undefined'); + assert(writer._closedPromiseState !== 'pending', 'writer._closedPromiseState is not pending'); + writer._closedPromise = Promise.reject(reason); + writer._closedPromiseState = 'rejected'; + } + + function defaultWriterClosedPromiseResolve(writer) { + assert(writer._closedPromise_resolve !== undefined, 'writer._closedPromise_resolve !== undefined'); + assert(writer._closedPromise_reject !== undefined, 'writer._closedPromise_reject !== undefined'); + assert(writer._closedPromiseState === 'pending', 'writer._closedPromiseState is pending'); + writer._closedPromise_resolve(undefined); + writer._closedPromise_resolve = undefined; + writer._closedPromise_reject = undefined; + writer._closedPromiseState = 'resolved'; + } + + function defaultWriterReadyPromiseInitialize(writer) { + writer._readyPromise = new Promise(function (resolve, reject) { + writer._readyPromise_resolve = resolve; + writer._readyPromise_reject = reject; + }); + writer._readyPromiseState = 'pending'; + } + + function defaultWriterReadyPromiseInitializeAsRejected(writer, reason) { + writer._readyPromise = Promise.reject(reason); + writer._readyPromise_resolve = undefined; + writer._readyPromise_reject = undefined; + writer._readyPromiseState = 'rejected'; + } + + function defaultWriterReadyPromiseInitializeAsResolved(writer) { + writer._readyPromise = Promise.resolve(undefined); + writer._readyPromise_resolve = undefined; + writer._readyPromise_reject = undefined; + writer._readyPromiseState = 'fulfilled'; + } + + function defaultWriterReadyPromiseReject(writer, reason) { + assert(writer._readyPromise_resolve !== undefined, 'writer._readyPromise_resolve !== undefined'); + assert(writer._readyPromise_reject !== undefined, 'writer._readyPromise_reject !== undefined'); + writer._readyPromise_reject(reason); + writer._readyPromise_resolve = undefined; + writer._readyPromise_reject = undefined; + writer._readyPromiseState = 'rejected'; + } + + function defaultWriterReadyPromiseReset(writer) { + assert(writer._readyPromise_resolve === undefined, 'writer._readyPromise_resolve === undefined'); + assert(writer._readyPromise_reject === undefined, 'writer._readyPromise_reject === undefined'); + writer._readyPromise = new Promise(function (resolve, reject) { + writer._readyPromise_resolve = resolve; + writer._readyPromise_reject = reject; + }); + writer._readyPromiseState = 'pending'; + } + + function defaultWriterReadyPromiseResetToRejected(writer, reason) { + assert(writer._readyPromise_resolve === undefined, 'writer._readyPromise_resolve === undefined'); + assert(writer._readyPromise_reject === undefined, 'writer._readyPromise_reject === undefined'); + writer._readyPromise = Promise.reject(reason); + writer._readyPromiseState = 'rejected'; + } + + function defaultWriterReadyPromiseResolve(writer) { + assert(writer._readyPromise_resolve !== undefined, 'writer._readyPromise_resolve !== undefined'); + assert(writer._readyPromise_reject !== undefined, 'writer._readyPromise_reject !== undefined'); + writer._readyPromise_resolve(undefined); + writer._readyPromise_resolve = undefined; + writer._readyPromise_reject = undefined; + writer._readyPromiseState = 'fulfilled'; + } + }, function (module, exports, __w_pdfjs_require__) { + "use strict"; + + var _require = __w_pdfjs_require__(0), + IsFiniteNonNegativeNumber = _require.IsFiniteNonNegativeNumber; + var _require2 = __w_pdfjs_require__(1), + assert = _require2.assert; + exports.DequeueValue = function (container) { + assert('_queue' in container && '_queueTotalSize' in container, 'Spec-level failure: DequeueValue should only be used on containers with [[queue]] and [[queueTotalSize]].'); + assert(container._queue.length > 0, 'Spec-level failure: should never dequeue from an empty queue.'); + var pair = container._queue.shift(); + container._queueTotalSize -= pair.size; + if (container._queueTotalSize < 0) { + container._queueTotalSize = 0; + } + return pair.value; + }; + exports.EnqueueValueWithSize = function (container, value, size) { + assert('_queue' in container && '_queueTotalSize' in container, 'Spec-level failure: EnqueueValueWithSize should only be used on containers with [[queue]] and ' + '[[queueTotalSize]].'); + size = Number(size); + if (!IsFiniteNonNegativeNumber(size)) { + throw new RangeError('Size must be a finite, non-NaN, non-negative number.'); + } + container._queue.push({ + value: value, + size: size + }); + container._queueTotalSize += size; + }; + exports.PeekQueueValue = function (container) { + assert('_queue' in container && '_queueTotalSize' in container, 'Spec-level failure: PeekQueueValue should only be used on containers with [[queue]] and [[queueTotalSize]].'); + assert(container._queue.length > 0, 'Spec-level failure: should never peek at an empty queue.'); + var pair = container._queue[0]; + return pair.value; + }; + exports.ResetQueue = function (container) { + assert('_queue' in container && '_queueTotalSize' in container, 'Spec-level failure: ResetQueue should only be used on containers with [[queue]] and [[queueTotalSize]].'); + container._queue = []; + container._queueTotalSize = 0; + }; + }, function (module, exports, __w_pdfjs_require__) { + "use strict"; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var _require = __w_pdfjs_require__(0), + ArrayBufferCopy = _require.ArrayBufferCopy, + CreateIterResultObject = _require.CreateIterResultObject, + IsFiniteNonNegativeNumber = _require.IsFiniteNonNegativeNumber, + InvokeOrNoop = _require.InvokeOrNoop, + PromiseInvokeOrNoop = _require.PromiseInvokeOrNoop, + TransferArrayBuffer = _require.TransferArrayBuffer, + ValidateAndNormalizeQueuingStrategy = _require.ValidateAndNormalizeQueuingStrategy, + ValidateAndNormalizeHighWaterMark = _require.ValidateAndNormalizeHighWaterMark; + var _require2 = __w_pdfjs_require__(0), + createArrayFromList = _require2.createArrayFromList, + createDataProperty = _require2.createDataProperty, + typeIsObject = _require2.typeIsObject; + var _require3 = __w_pdfjs_require__(1), + assert = _require3.assert, + rethrowAssertionErrorRejection = _require3.rethrowAssertionErrorRejection; + var _require4 = __w_pdfjs_require__(3), + DequeueValue = _require4.DequeueValue, + EnqueueValueWithSize = _require4.EnqueueValueWithSize, + ResetQueue = _require4.ResetQueue; + var _require5 = __w_pdfjs_require__(2), + AcquireWritableStreamDefaultWriter = _require5.AcquireWritableStreamDefaultWriter, + IsWritableStream = _require5.IsWritableStream, + IsWritableStreamLocked = _require5.IsWritableStreamLocked, + WritableStreamAbort = _require5.WritableStreamAbort, + WritableStreamDefaultWriterCloseWithErrorPropagation = _require5.WritableStreamDefaultWriterCloseWithErrorPropagation, + WritableStreamDefaultWriterRelease = _require5.WritableStreamDefaultWriterRelease, + WritableStreamDefaultWriterWrite = _require5.WritableStreamDefaultWriterWrite, + WritableStreamCloseQueuedOrInFlight = _require5.WritableStreamCloseQueuedOrInFlight; + var ReadableStream = function () { + function ReadableStream() { + var underlyingSource = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, + size = _ref.size, + highWaterMark = _ref.highWaterMark; + _classCallCheck(this, ReadableStream); + this._state = 'readable'; + this._reader = undefined; + this._storedError = undefined; + this._disturbed = false; + this._readableStreamController = undefined; + var type = underlyingSource.type; + var typeString = String(type); + if (typeString === 'bytes') { + if (highWaterMark === undefined) { + highWaterMark = 0; + } + this._readableStreamController = new ReadableByteStreamController(this, underlyingSource, highWaterMark); + } else if (type === undefined) { + if (highWaterMark === undefined) { + highWaterMark = 1; + } + this._readableStreamController = new ReadableStreamDefaultController(this, underlyingSource, size, highWaterMark); + } else { + throw new RangeError('Invalid type is specified'); + } + } + + _createClass(ReadableStream, [{ + key: 'cancel', + value: function cancel(reason) { + if (IsReadableStream(this) === false) { + return Promise.reject(streamBrandCheckException('cancel')); + } + if (IsReadableStreamLocked(this) === true) { + return Promise.reject(new TypeError('Cannot cancel a stream that already has a reader')); + } + return ReadableStreamCancel(this, reason); + } + }, { + key: 'getReader', + value: function getReader() { + var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, + mode = _ref2.mode; + if (IsReadableStream(this) === false) { + throw streamBrandCheckException('getReader'); + } + if (mode === undefined) { + return AcquireReadableStreamDefaultReader(this); + } + mode = String(mode); + if (mode === 'byob') { + return AcquireReadableStreamBYOBReader(this); + } + throw new RangeError('Invalid mode is specified'); + } + }, { + key: 'pipeThrough', + value: function pipeThrough(_ref3, options) { + var writable = _ref3.writable, + readable = _ref3.readable; + var promise = this.pipeTo(writable, options); + ifIsObjectAndHasAPromiseIsHandledInternalSlotSetPromiseIsHandledToTrue(promise); + return readable; + } + }, { + key: 'pipeTo', + value: function pipeTo(dest) { + var _this = this; + var _ref4 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, + preventClose = _ref4.preventClose, + preventAbort = _ref4.preventAbort, + preventCancel = _ref4.preventCancel; + if (IsReadableStream(this) === false) { + return Promise.reject(streamBrandCheckException('pipeTo')); + } + if (IsWritableStream(dest) === false) { + return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo\'s first argument must be a WritableStream')); + } + preventClose = Boolean(preventClose); + preventAbort = Boolean(preventAbort); + preventCancel = Boolean(preventCancel); + if (IsReadableStreamLocked(this) === true) { + return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo cannot be used on a locked ReadableStream')); + } + if (IsWritableStreamLocked(dest) === true) { + return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo cannot be used on a locked WritableStream')); + } + var reader = AcquireReadableStreamDefaultReader(this); + var writer = AcquireWritableStreamDefaultWriter(dest); + var shuttingDown = false; + var currentWrite = Promise.resolve(); + return new Promise(function (resolve, reject) { + function pipeLoop() { + currentWrite = Promise.resolve(); + if (shuttingDown === true) { + return Promise.resolve(); + } + return writer._readyPromise.then(function () { + return ReadableStreamDefaultReaderRead(reader).then(function (_ref5) { + var value = _ref5.value, + done = _ref5.done; + if (done === true) { + return; + } + currentWrite = WritableStreamDefaultWriterWrite(writer, value).catch(function () { + }); + }); + }).then(pipeLoop); + } + + isOrBecomesErrored(_this, reader._closedPromise, function (storedError) { + if (preventAbort === false) { + shutdownWithAction(function () { + return WritableStreamAbort(dest, storedError); + }, true, storedError); + } else { + shutdown(true, storedError); + } + }); + isOrBecomesErrored(dest, writer._closedPromise, function (storedError) { + if (preventCancel === false) { + shutdownWithAction(function () { + return ReadableStreamCancel(_this, storedError); + }, true, storedError); + } else { + shutdown(true, storedError); + } + }); + isOrBecomesClosed(_this, reader._closedPromise, function () { + if (preventClose === false) { + shutdownWithAction(function () { + return WritableStreamDefaultWriterCloseWithErrorPropagation(writer); + }); + } else { + shutdown(); + } + }); + if (WritableStreamCloseQueuedOrInFlight(dest) === true || dest._state === 'closed') { + var destClosed = new TypeError('the destination writable stream closed before all data could be piped to it'); + if (preventCancel === false) { + shutdownWithAction(function () { + return ReadableStreamCancel(_this, destClosed); + }, true, destClosed); + } else { + shutdown(true, destClosed); + } + } + pipeLoop().catch(function (err) { + currentWrite = Promise.resolve(); + rethrowAssertionErrorRejection(err); + }); + + function waitForWritesToFinish() { + var oldCurrentWrite = currentWrite; + return currentWrite.then(function () { + return oldCurrentWrite !== currentWrite ? waitForWritesToFinish() : undefined; + }); + } + + function isOrBecomesErrored(stream, promise, action) { + if (stream._state === 'errored') { + action(stream._storedError); + } else { + promise.catch(action).catch(rethrowAssertionErrorRejection); + } + } + + function isOrBecomesClosed(stream, promise, action) { + if (stream._state === 'closed') { + action(); + } else { + promise.then(action).catch(rethrowAssertionErrorRejection); + } + } + + function shutdownWithAction(action, originalIsError, originalError) { + if (shuttingDown === true) { + return; + } + shuttingDown = true; + if (dest._state === 'writable' && WritableStreamCloseQueuedOrInFlight(dest) === false) { + waitForWritesToFinish().then(doTheRest); + } else { + doTheRest(); + } + + function doTheRest() { + action().then(function () { + return finalize(originalIsError, originalError); + }, function (newError) { + return finalize(true, newError); + }).catch(rethrowAssertionErrorRejection); + } + } + + function shutdown(isError, error) { + if (shuttingDown === true) { + return; + } + shuttingDown = true; + if (dest._state === 'writable' && WritableStreamCloseQueuedOrInFlight(dest) === false) { + waitForWritesToFinish().then(function () { + return finalize(isError, error); + }).catch(rethrowAssertionErrorRejection); + } else { + finalize(isError, error); + } + } + + function finalize(isError, error) { + WritableStreamDefaultWriterRelease(writer); + ReadableStreamReaderGenericRelease(reader); + if (isError) { + reject(error); + } else { + resolve(undefined); + } + } + }); + } + }, { + key: 'tee', + value: function tee() { + if (IsReadableStream(this) === false) { + throw streamBrandCheckException('tee'); + } + var branches = ReadableStreamTee(this, false); + return createArrayFromList(branches); + } + }, { + key: 'locked', + get: function get() { + if (IsReadableStream(this) === false) { + throw streamBrandCheckException('locked'); + } + return IsReadableStreamLocked(this); + } + }]); + return ReadableStream; + }(); + module.exports = { + ReadableStream: ReadableStream, + IsReadableStreamDisturbed: IsReadableStreamDisturbed, + ReadableStreamDefaultControllerClose: ReadableStreamDefaultControllerClose, + ReadableStreamDefaultControllerEnqueue: ReadableStreamDefaultControllerEnqueue, + ReadableStreamDefaultControllerError: ReadableStreamDefaultControllerError, + ReadableStreamDefaultControllerGetDesiredSize: ReadableStreamDefaultControllerGetDesiredSize + }; + + function AcquireReadableStreamBYOBReader(stream) { + return new ReadableStreamBYOBReader(stream); + } + + function AcquireReadableStreamDefaultReader(stream) { + return new ReadableStreamDefaultReader(stream); + } + + function IsReadableStream(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_readableStreamController')) { + return false; + } + return true; + } + + function IsReadableStreamDisturbed(stream) { + assert(IsReadableStream(stream) === true, 'IsReadableStreamDisturbed should only be used on known readable streams'); + return stream._disturbed; + } + + function IsReadableStreamLocked(stream) { + assert(IsReadableStream(stream) === true, 'IsReadableStreamLocked should only be used on known readable streams'); + if (stream._reader === undefined) { + return false; + } + return true; + } + + function ReadableStreamTee(stream, cloneForBranch2) { + assert(IsReadableStream(stream) === true); + assert(typeof cloneForBranch2 === 'boolean'); + var reader = AcquireReadableStreamDefaultReader(stream); + var teeState = { + closedOrErrored: false, + canceled1: false, + canceled2: false, + reason1: undefined, + reason2: undefined + }; + teeState.promise = new Promise(function (resolve) { + teeState._resolve = resolve; + }); + var pull = create_ReadableStreamTeePullFunction(); + pull._reader = reader; + pull._teeState = teeState; + pull._cloneForBranch2 = cloneForBranch2; + var cancel1 = create_ReadableStreamTeeBranch1CancelFunction(); + cancel1._stream = stream; + cancel1._teeState = teeState; + var cancel2 = create_ReadableStreamTeeBranch2CancelFunction(); + cancel2._stream = stream; + cancel2._teeState = teeState; + var underlyingSource1 = Object.create(Object.prototype); + createDataProperty(underlyingSource1, 'pull', pull); + createDataProperty(underlyingSource1, 'cancel', cancel1); + var branch1Stream = new ReadableStream(underlyingSource1); + var underlyingSource2 = Object.create(Object.prototype); + createDataProperty(underlyingSource2, 'pull', pull); + createDataProperty(underlyingSource2, 'cancel', cancel2); + var branch2Stream = new ReadableStream(underlyingSource2); + pull._branch1 = branch1Stream._readableStreamController; + pull._branch2 = branch2Stream._readableStreamController; + reader._closedPromise.catch(function (r) { + if (teeState.closedOrErrored === true) { + return; + } + ReadableStreamDefaultControllerError(pull._branch1, r); + ReadableStreamDefaultControllerError(pull._branch2, r); + teeState.closedOrErrored = true; + }); + return [branch1Stream, branch2Stream]; + } + + function create_ReadableStreamTeePullFunction() { + function f() { + var reader = f._reader, + branch1 = f._branch1, + branch2 = f._branch2, + teeState = f._teeState; + return ReadableStreamDefaultReaderRead(reader).then(function (result) { + assert(typeIsObject(result)); + var value = result.value; + var done = result.done; + assert(typeof done === 'boolean'); + if (done === true && teeState.closedOrErrored === false) { + if (teeState.canceled1 === false) { + ReadableStreamDefaultControllerClose(branch1); + } + if (teeState.canceled2 === false) { + ReadableStreamDefaultControllerClose(branch2); + } + teeState.closedOrErrored = true; + } + if (teeState.closedOrErrored === true) { + return; + } + var value1 = value; + var value2 = value; + if (teeState.canceled1 === false) { + ReadableStreamDefaultControllerEnqueue(branch1, value1); + } + if (teeState.canceled2 === false) { + ReadableStreamDefaultControllerEnqueue(branch2, value2); + } + }); + } + + return f; + } + + function create_ReadableStreamTeeBranch1CancelFunction() { + function f(reason) { + var stream = f._stream, + teeState = f._teeState; + teeState.canceled1 = true; + teeState.reason1 = reason; + if (teeState.canceled2 === true) { + var compositeReason = createArrayFromList([teeState.reason1, teeState.reason2]); + var cancelResult = ReadableStreamCancel(stream, compositeReason); + teeState._resolve(cancelResult); + } + return teeState.promise; + } + + return f; + } + + function create_ReadableStreamTeeBranch2CancelFunction() { + function f(reason) { + var stream = f._stream, + teeState = f._teeState; + teeState.canceled2 = true; + teeState.reason2 = reason; + if (teeState.canceled1 === true) { + var compositeReason = createArrayFromList([teeState.reason1, teeState.reason2]); + var cancelResult = ReadableStreamCancel(stream, compositeReason); + teeState._resolve(cancelResult); + } + return teeState.promise; + } + + return f; + } + + function ReadableStreamAddReadIntoRequest(stream) { + assert(IsReadableStreamBYOBReader(stream._reader) === true); + assert(stream._state === 'readable' || stream._state === 'closed'); + var promise = new Promise(function (resolve, reject) { + var readIntoRequest = { + _resolve: resolve, + _reject: reject + }; + stream._reader._readIntoRequests.push(readIntoRequest); + }); + return promise; + } + + function ReadableStreamAddReadRequest(stream) { + assert(IsReadableStreamDefaultReader(stream._reader) === true); + assert(stream._state === 'readable'); + var promise = new Promise(function (resolve, reject) { + var readRequest = { + _resolve: resolve, + _reject: reject + }; + stream._reader._readRequests.push(readRequest); + }); + return promise; + } + + function ReadableStreamCancel(stream, reason) { + stream._disturbed = true; + if (stream._state === 'closed') { + return Promise.resolve(undefined); + } + if (stream._state === 'errored') { + return Promise.reject(stream._storedError); + } + ReadableStreamClose(stream); + var sourceCancelPromise = stream._readableStreamController.__cancelSteps(reason); + return sourceCancelPromise.then(function () { + return undefined; + }); + } + + function ReadableStreamClose(stream) { + assert(stream._state === 'readable'); + stream._state = 'closed'; + var reader = stream._reader; + if (reader === undefined) { + return undefined; + } + if (IsReadableStreamDefaultReader(reader) === true) { + for (var i = 0; i < reader._readRequests.length; i++) { + var _resolve = reader._readRequests[i]._resolve; + _resolve(CreateIterResultObject(undefined, true)); + } + reader._readRequests = []; + } + defaultReaderClosedPromiseResolve(reader); + return undefined; + } + + function ReadableStreamError(stream, e) { + assert(IsReadableStream(stream) === true, 'stream must be ReadableStream'); + assert(stream._state === 'readable', 'state must be readable'); + stream._state = 'errored'; + stream._storedError = e; + var reader = stream._reader; + if (reader === undefined) { + return undefined; + } + if (IsReadableStreamDefaultReader(reader) === true) { + for (var i = 0; i < reader._readRequests.length; i++) { + var readRequest = reader._readRequests[i]; + readRequest._reject(e); + } + reader._readRequests = []; + } else { + assert(IsReadableStreamBYOBReader(reader), 'reader must be ReadableStreamBYOBReader'); + for (var _i = 0; _i < reader._readIntoRequests.length; _i++) { + var readIntoRequest = reader._readIntoRequests[_i]; + readIntoRequest._reject(e); + } + reader._readIntoRequests = []; + } + defaultReaderClosedPromiseReject(reader, e); + reader._closedPromise.catch(function () { + }); + } + + function ReadableStreamFulfillReadIntoRequest(stream, chunk, done) { + var reader = stream._reader; + assert(reader._readIntoRequests.length > 0); + var readIntoRequest = reader._readIntoRequests.shift(); + readIntoRequest._resolve(CreateIterResultObject(chunk, done)); + } + + function ReadableStreamFulfillReadRequest(stream, chunk, done) { + var reader = stream._reader; + assert(reader._readRequests.length > 0); + var readRequest = reader._readRequests.shift(); + readRequest._resolve(CreateIterResultObject(chunk, done)); + } + + function ReadableStreamGetNumReadIntoRequests(stream) { + return stream._reader._readIntoRequests.length; + } + + function ReadableStreamGetNumReadRequests(stream) { + return stream._reader._readRequests.length; + } + + function ReadableStreamHasBYOBReader(stream) { + var reader = stream._reader; + if (reader === undefined) { + return false; + } + if (IsReadableStreamBYOBReader(reader) === false) { + return false; + } + return true; + } + + function ReadableStreamHasDefaultReader(stream) { + var reader = stream._reader; + if (reader === undefined) { + return false; + } + if (IsReadableStreamDefaultReader(reader) === false) { + return false; + } + return true; + } + + var ReadableStreamDefaultReader = function () { + function ReadableStreamDefaultReader(stream) { + _classCallCheck(this, ReadableStreamDefaultReader); + if (IsReadableStream(stream) === false) { + throw new TypeError('ReadableStreamDefaultReader can only be constructed with a ReadableStream instance'); + } + if (IsReadableStreamLocked(stream) === true) { + throw new TypeError('This stream has already been locked for exclusive reading by another reader'); + } + ReadableStreamReaderGenericInitialize(this, stream); + this._readRequests = []; + } + + _createClass(ReadableStreamDefaultReader, [{ + key: 'cancel', + value: function cancel(reason) { + if (IsReadableStreamDefaultReader(this) === false) { + return Promise.reject(defaultReaderBrandCheckException('cancel')); + } + if (this._ownerReadableStream === undefined) { + return Promise.reject(readerLockException('cancel')); + } + return ReadableStreamReaderGenericCancel(this, reason); + } + }, { + key: 'read', + value: function read() { + if (IsReadableStreamDefaultReader(this) === false) { + return Promise.reject(defaultReaderBrandCheckException('read')); + } + if (this._ownerReadableStream === undefined) { + return Promise.reject(readerLockException('read from')); + } + return ReadableStreamDefaultReaderRead(this); + } + }, { + key: 'releaseLock', + value: function releaseLock() { + if (IsReadableStreamDefaultReader(this) === false) { + throw defaultReaderBrandCheckException('releaseLock'); + } + if (this._ownerReadableStream === undefined) { + return; + } + if (this._readRequests.length > 0) { + throw new TypeError('Tried to release a reader lock when that reader has pending read() calls un-settled'); + } + ReadableStreamReaderGenericRelease(this); + } + }, { + key: 'closed', + get: function get() { + if (IsReadableStreamDefaultReader(this) === false) { + return Promise.reject(defaultReaderBrandCheckException('closed')); + } + return this._closedPromise; + } + }]); + return ReadableStreamDefaultReader; + }(); + var ReadableStreamBYOBReader = function () { + function ReadableStreamBYOBReader(stream) { + _classCallCheck(this, ReadableStreamBYOBReader); + if (!IsReadableStream(stream)) { + throw new TypeError('ReadableStreamBYOBReader can only be constructed with a ReadableStream instance given a ' + 'byte source'); + } + if (IsReadableByteStreamController(stream._readableStreamController) === false) { + throw new TypeError('Cannot construct a ReadableStreamBYOBReader for a stream not constructed with a byte ' + 'source'); + } + if (IsReadableStreamLocked(stream)) { + throw new TypeError('This stream has already been locked for exclusive reading by another reader'); + } + ReadableStreamReaderGenericInitialize(this, stream); + this._readIntoRequests = []; + } + + _createClass(ReadableStreamBYOBReader, [{ + key: 'cancel', + value: function cancel(reason) { + if (!IsReadableStreamBYOBReader(this)) { + return Promise.reject(byobReaderBrandCheckException('cancel')); + } + if (this._ownerReadableStream === undefined) { + return Promise.reject(readerLockException('cancel')); + } + return ReadableStreamReaderGenericCancel(this, reason); + } + }, { + key: 'read', + value: function read(view) { + if (!IsReadableStreamBYOBReader(this)) { + return Promise.reject(byobReaderBrandCheckException('read')); + } + if (this._ownerReadableStream === undefined) { + return Promise.reject(readerLockException('read from')); + } + if (!ArrayBuffer.isView(view)) { + return Promise.reject(new TypeError('view must be an array buffer view')); + } + if (view.byteLength === 0) { + return Promise.reject(new TypeError('view must have non-zero byteLength')); + } + return ReadableStreamBYOBReaderRead(this, view); + } + }, { + key: 'releaseLock', + value: function releaseLock() { + if (!IsReadableStreamBYOBReader(this)) { + throw byobReaderBrandCheckException('releaseLock'); + } + if (this._ownerReadableStream === undefined) { + return; + } + if (this._readIntoRequests.length > 0) { + throw new TypeError('Tried to release a reader lock when that reader has pending read() calls un-settled'); + } + ReadableStreamReaderGenericRelease(this); + } + }, { + key: 'closed', + get: function get() { + if (!IsReadableStreamBYOBReader(this)) { + return Promise.reject(byobReaderBrandCheckException('closed')); + } + return this._closedPromise; + } + }]); + return ReadableStreamBYOBReader; + }(); + + function IsReadableStreamBYOBReader(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_readIntoRequests')) { + return false; + } + return true; + } + + function IsReadableStreamDefaultReader(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_readRequests')) { + return false; + } + return true; + } + + function ReadableStreamReaderGenericInitialize(reader, stream) { + reader._ownerReadableStream = stream; + stream._reader = reader; + if (stream._state === 'readable') { + defaultReaderClosedPromiseInitialize(reader); + } else if (stream._state === 'closed') { + defaultReaderClosedPromiseInitializeAsResolved(reader); + } else { + assert(stream._state === 'errored', 'state must be errored'); + defaultReaderClosedPromiseInitializeAsRejected(reader, stream._storedError); + reader._closedPromise.catch(function () { + }); + } + } + + function ReadableStreamReaderGenericCancel(reader, reason) { + var stream = reader._ownerReadableStream; + assert(stream !== undefined); + return ReadableStreamCancel(stream, reason); + } + + function ReadableStreamReaderGenericRelease(reader) { + assert(reader._ownerReadableStream !== undefined); + assert(reader._ownerReadableStream._reader === reader); + if (reader._ownerReadableStream._state === 'readable') { + defaultReaderClosedPromiseReject(reader, new TypeError('Reader was released and can no longer be used to monitor the stream\'s closedness')); + } else { + defaultReaderClosedPromiseResetToRejected(reader, new TypeError('Reader was released and can no longer be used to monitor the stream\'s closedness')); + } + reader._closedPromise.catch(function () { + }); + reader._ownerReadableStream._reader = undefined; + reader._ownerReadableStream = undefined; + } + + function ReadableStreamBYOBReaderRead(reader, view) { + var stream = reader._ownerReadableStream; + assert(stream !== undefined); + stream._disturbed = true; + if (stream._state === 'errored') { + return Promise.reject(stream._storedError); + } + return ReadableByteStreamControllerPullInto(stream._readableStreamController, view); + } + + function ReadableStreamDefaultReaderRead(reader) { + var stream = reader._ownerReadableStream; + assert(stream !== undefined); + stream._disturbed = true; + if (stream._state === 'closed') { + return Promise.resolve(CreateIterResultObject(undefined, true)); + } + if (stream._state === 'errored') { + return Promise.reject(stream._storedError); + } + assert(stream._state === 'readable'); + return stream._readableStreamController.__pullSteps(); + } + + var ReadableStreamDefaultController = function () { + function ReadableStreamDefaultController(stream, underlyingSource, size, highWaterMark) { + _classCallCheck(this, ReadableStreamDefaultController); + if (IsReadableStream(stream) === false) { + throw new TypeError('ReadableStreamDefaultController can only be constructed with a ReadableStream instance'); + } + if (stream._readableStreamController !== undefined) { + throw new TypeError('ReadableStreamDefaultController instances can only be created by the ReadableStream constructor'); + } + this._controlledReadableStream = stream; + this._underlyingSource = underlyingSource; + this._queue = undefined; + this._queueTotalSize = undefined; + ResetQueue(this); + this._started = false; + this._closeRequested = false; + this._pullAgain = false; + this._pulling = false; + var normalizedStrategy = ValidateAndNormalizeQueuingStrategy(size, highWaterMark); + this._strategySize = normalizedStrategy.size; + this._strategyHWM = normalizedStrategy.highWaterMark; + var controller = this; + var startResult = InvokeOrNoop(underlyingSource, 'start', [this]); + Promise.resolve(startResult).then(function () { + controller._started = true; + assert(controller._pulling === false); + assert(controller._pullAgain === false); + ReadableStreamDefaultControllerCallPullIfNeeded(controller); + }, function (r) { + ReadableStreamDefaultControllerErrorIfNeeded(controller, r); + }).catch(rethrowAssertionErrorRejection); + } + + _createClass(ReadableStreamDefaultController, [{ + key: 'close', + value: function close() { + if (IsReadableStreamDefaultController(this) === false) { + throw defaultControllerBrandCheckException('close'); + } + if (this._closeRequested === true) { + throw new TypeError('The stream has already been closed; do not close it again!'); + } + var state = this._controlledReadableStream._state; + if (state !== 'readable') { + throw new TypeError('The stream (in ' + state + ' state) is not in the readable state and cannot be closed'); + } + ReadableStreamDefaultControllerClose(this); + } + }, { + key: 'enqueue', + value: function enqueue(chunk) { + if (IsReadableStreamDefaultController(this) === false) { + throw defaultControllerBrandCheckException('enqueue'); + } + if (this._closeRequested === true) { + throw new TypeError('stream is closed or draining'); + } + var state = this._controlledReadableStream._state; + if (state !== 'readable') { + throw new TypeError('The stream (in ' + state + ' state) is not in the readable state and cannot be enqueued to'); + } + return ReadableStreamDefaultControllerEnqueue(this, chunk); + } + }, { + key: 'error', + value: function error(e) { + if (IsReadableStreamDefaultController(this) === false) { + throw defaultControllerBrandCheckException('error'); + } + var stream = this._controlledReadableStream; + if (stream._state !== 'readable') { + throw new TypeError('The stream is ' + stream._state + ' and so cannot be errored'); + } + ReadableStreamDefaultControllerError(this, e); + } + }, { + key: '__cancelSteps', + value: function __cancelSteps(reason) { + ResetQueue(this); + return PromiseInvokeOrNoop(this._underlyingSource, 'cancel', [reason]); + } + }, { + key: '__pullSteps', + value: function __pullSteps() { + var stream = this._controlledReadableStream; + if (this._queue.length > 0) { + var chunk = DequeueValue(this); + if (this._closeRequested === true && this._queue.length === 0) { + ReadableStreamClose(stream); + } else { + ReadableStreamDefaultControllerCallPullIfNeeded(this); + } + return Promise.resolve(CreateIterResultObject(chunk, false)); + } + var pendingPromise = ReadableStreamAddReadRequest(stream); + ReadableStreamDefaultControllerCallPullIfNeeded(this); + return pendingPromise; + } + }, { + key: 'desiredSize', + get: function get() { + if (IsReadableStreamDefaultController(this) === false) { + throw defaultControllerBrandCheckException('desiredSize'); + } + return ReadableStreamDefaultControllerGetDesiredSize(this); + } + }]); + return ReadableStreamDefaultController; + }(); + + function IsReadableStreamDefaultController(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_underlyingSource')) { + return false; + } + return true; + } + + function ReadableStreamDefaultControllerCallPullIfNeeded(controller) { + var shouldPull = ReadableStreamDefaultControllerShouldCallPull(controller); + if (shouldPull === false) { + return undefined; + } + if (controller._pulling === true) { + controller._pullAgain = true; + return undefined; + } + assert(controller._pullAgain === false); + controller._pulling = true; + var pullPromise = PromiseInvokeOrNoop(controller._underlyingSource, 'pull', [controller]); + pullPromise.then(function () { + controller._pulling = false; + if (controller._pullAgain === true) { + controller._pullAgain = false; + return ReadableStreamDefaultControllerCallPullIfNeeded(controller); + } + return undefined; + }, function (e) { + ReadableStreamDefaultControllerErrorIfNeeded(controller, e); + }).catch(rethrowAssertionErrorRejection); + return undefined; + } + + function ReadableStreamDefaultControllerShouldCallPull(controller) { + var stream = controller._controlledReadableStream; + if (stream._state === 'closed' || stream._state === 'errored') { + return false; + } + if (controller._closeRequested === true) { + return false; + } + if (controller._started === false) { + return false; + } + if (IsReadableStreamLocked(stream) === true && ReadableStreamGetNumReadRequests(stream) > 0) { + return true; + } + var desiredSize = ReadableStreamDefaultControllerGetDesiredSize(controller); + if (desiredSize > 0) { + return true; + } + return false; + } + + function ReadableStreamDefaultControllerClose(controller) { + var stream = controller._controlledReadableStream; + assert(controller._closeRequested === false); + assert(stream._state === 'readable'); + controller._closeRequested = true; + if (controller._queue.length === 0) { + ReadableStreamClose(stream); + } + } + + function ReadableStreamDefaultControllerEnqueue(controller, chunk) { + var stream = controller._controlledReadableStream; + assert(controller._closeRequested === false); + assert(stream._state === 'readable'); + if (IsReadableStreamLocked(stream) === true && ReadableStreamGetNumReadRequests(stream) > 0) { + ReadableStreamFulfillReadRequest(stream, chunk, false); + } else { + var chunkSize = 1; + if (controller._strategySize !== undefined) { + var strategySize = controller._strategySize; + try { + chunkSize = strategySize(chunk); + } catch (chunkSizeE) { + ReadableStreamDefaultControllerErrorIfNeeded(controller, chunkSizeE); + throw chunkSizeE; + } + } + try { + EnqueueValueWithSize(controller, chunk, chunkSize); + } catch (enqueueE) { + ReadableStreamDefaultControllerErrorIfNeeded(controller, enqueueE); + throw enqueueE; + } + } + ReadableStreamDefaultControllerCallPullIfNeeded(controller); + return undefined; + } + + function ReadableStreamDefaultControllerError(controller, e) { + var stream = controller._controlledReadableStream; + assert(stream._state === 'readable'); + ResetQueue(controller); + ReadableStreamError(stream, e); + } + + function ReadableStreamDefaultControllerErrorIfNeeded(controller, e) { + if (controller._controlledReadableStream._state === 'readable') { + ReadableStreamDefaultControllerError(controller, e); + } + } + + function ReadableStreamDefaultControllerGetDesiredSize(controller) { + var stream = controller._controlledReadableStream; + var state = stream._state; + if (state === 'errored') { + return null; + } + if (state === 'closed') { + return 0; + } + return controller._strategyHWM - controller._queueTotalSize; + } + + var ReadableStreamBYOBRequest = function () { + function ReadableStreamBYOBRequest(controller, view) { + _classCallCheck(this, ReadableStreamBYOBRequest); + this._associatedReadableByteStreamController = controller; + this._view = view; + } + + _createClass(ReadableStreamBYOBRequest, [{ + key: 'respond', + value: function respond(bytesWritten) { + if (IsReadableStreamBYOBRequest(this) === false) { + throw byobRequestBrandCheckException('respond'); + } + if (this._associatedReadableByteStreamController === undefined) { + throw new TypeError('This BYOB request has been invalidated'); + } + ReadableByteStreamControllerRespond(this._associatedReadableByteStreamController, bytesWritten); + } + }, { + key: 'respondWithNewView', + value: function respondWithNewView(view) { + if (IsReadableStreamBYOBRequest(this) === false) { + throw byobRequestBrandCheckException('respond'); + } + if (this._associatedReadableByteStreamController === undefined) { + throw new TypeError('This BYOB request has been invalidated'); + } + if (!ArrayBuffer.isView(view)) { + throw new TypeError('You can only respond with array buffer views'); + } + ReadableByteStreamControllerRespondWithNewView(this._associatedReadableByteStreamController, view); + } + }, { + key: 'view', + get: function get() { + return this._view; + } + }]); + return ReadableStreamBYOBRequest; + }(); + var ReadableByteStreamController = function () { + function ReadableByteStreamController(stream, underlyingByteSource, highWaterMark) { + _classCallCheck(this, ReadableByteStreamController); + if (IsReadableStream(stream) === false) { + throw new TypeError('ReadableByteStreamController can only be constructed with a ReadableStream instance given ' + 'a byte source'); + } + if (stream._readableStreamController !== undefined) { + throw new TypeError('ReadableByteStreamController instances can only be created by the ReadableStream constructor given a byte ' + 'source'); + } + this._controlledReadableStream = stream; + this._underlyingByteSource = underlyingByteSource; + this._pullAgain = false; + this._pulling = false; + ReadableByteStreamControllerClearPendingPullIntos(this); + this._queue = this._queueTotalSize = undefined; + ResetQueue(this); + this._closeRequested = false; + this._started = false; + this._strategyHWM = ValidateAndNormalizeHighWaterMark(highWaterMark); + var autoAllocateChunkSize = underlyingByteSource.autoAllocateChunkSize; + if (autoAllocateChunkSize !== undefined) { + if (Number.isInteger(autoAllocateChunkSize) === false || autoAllocateChunkSize <= 0) { + throw new RangeError('autoAllocateChunkSize must be a positive integer'); + } + } + this._autoAllocateChunkSize = autoAllocateChunkSize; + this._pendingPullIntos = []; + var controller = this; + var startResult = InvokeOrNoop(underlyingByteSource, 'start', [this]); + Promise.resolve(startResult).then(function () { + controller._started = true; + assert(controller._pulling === false); + assert(controller._pullAgain === false); + ReadableByteStreamControllerCallPullIfNeeded(controller); + }, function (r) { + if (stream._state === 'readable') { + ReadableByteStreamControllerError(controller, r); + } + }).catch(rethrowAssertionErrorRejection); + } + + _createClass(ReadableByteStreamController, [{ + key: 'close', + value: function close() { + if (IsReadableByteStreamController(this) === false) { + throw byteStreamControllerBrandCheckException('close'); + } + if (this._closeRequested === true) { + throw new TypeError('The stream has already been closed; do not close it again!'); + } + var state = this._controlledReadableStream._state; + if (state !== 'readable') { + throw new TypeError('The stream (in ' + state + ' state) is not in the readable state and cannot be closed'); + } + ReadableByteStreamControllerClose(this); + } + }, { + key: 'enqueue', + value: function enqueue(chunk) { + if (IsReadableByteStreamController(this) === false) { + throw byteStreamControllerBrandCheckException('enqueue'); + } + if (this._closeRequested === true) { + throw new TypeError('stream is closed or draining'); + } + var state = this._controlledReadableStream._state; + if (state !== 'readable') { + throw new TypeError('The stream (in ' + state + ' state) is not in the readable state and cannot be enqueued to'); + } + if (!ArrayBuffer.isView(chunk)) { + throw new TypeError('You can only enqueue array buffer views when using a ReadableByteStreamController'); + } + ReadableByteStreamControllerEnqueue(this, chunk); + } + }, { + key: 'error', + value: function error(e) { + if (IsReadableByteStreamController(this) === false) { + throw byteStreamControllerBrandCheckException('error'); + } + var stream = this._controlledReadableStream; + if (stream._state !== 'readable') { + throw new TypeError('The stream is ' + stream._state + ' and so cannot be errored'); + } + ReadableByteStreamControllerError(this, e); + } + }, { + key: '__cancelSteps', + value: function __cancelSteps(reason) { + if (this._pendingPullIntos.length > 0) { + var firstDescriptor = this._pendingPullIntos[0]; + firstDescriptor.bytesFilled = 0; + } + ResetQueue(this); + return PromiseInvokeOrNoop(this._underlyingByteSource, 'cancel', [reason]); + } + }, { + key: '__pullSteps', + value: function __pullSteps() { + var stream = this._controlledReadableStream; + assert(ReadableStreamHasDefaultReader(stream) === true); + if (this._queueTotalSize > 0) { + assert(ReadableStreamGetNumReadRequests(stream) === 0); + var entry = this._queue.shift(); + this._queueTotalSize -= entry.byteLength; + ReadableByteStreamControllerHandleQueueDrain(this); + var view = void 0; + try { + view = new Uint8Array(entry.buffer, entry.byteOffset, entry.byteLength); + } catch (viewE) { + return Promise.reject(viewE); + } + return Promise.resolve(CreateIterResultObject(view, false)); + } + var autoAllocateChunkSize = this._autoAllocateChunkSize; + if (autoAllocateChunkSize !== undefined) { + var buffer = void 0; + try { + buffer = new ArrayBuffer(autoAllocateChunkSize); + } catch (bufferE) { + return Promise.reject(bufferE); + } + var pullIntoDescriptor = { + buffer: buffer, + byteOffset: 0, + byteLength: autoAllocateChunkSize, + bytesFilled: 0, + elementSize: 1, + ctor: Uint8Array, + readerType: 'default' + }; + this._pendingPullIntos.push(pullIntoDescriptor); + } + var promise = ReadableStreamAddReadRequest(stream); + ReadableByteStreamControllerCallPullIfNeeded(this); + return promise; + } + }, { + key: 'byobRequest', + get: function get() { + if (IsReadableByteStreamController(this) === false) { + throw byteStreamControllerBrandCheckException('byobRequest'); + } + if (this._byobRequest === undefined && this._pendingPullIntos.length > 0) { + var firstDescriptor = this._pendingPullIntos[0]; + var view = new Uint8Array(firstDescriptor.buffer, firstDescriptor.byteOffset + firstDescriptor.bytesFilled, firstDescriptor.byteLength - firstDescriptor.bytesFilled); + this._byobRequest = new ReadableStreamBYOBRequest(this, view); + } + return this._byobRequest; + } + }, { + key: 'desiredSize', + get: function get() { + if (IsReadableByteStreamController(this) === false) { + throw byteStreamControllerBrandCheckException('desiredSize'); + } + return ReadableByteStreamControllerGetDesiredSize(this); + } + }]); + return ReadableByteStreamController; + }(); + + function IsReadableByteStreamController(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_underlyingByteSource')) { + return false; + } + return true; + } + + function IsReadableStreamBYOBRequest(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_associatedReadableByteStreamController')) { + return false; + } + return true; + } + + function ReadableByteStreamControllerCallPullIfNeeded(controller) { + var shouldPull = ReadableByteStreamControllerShouldCallPull(controller); + if (shouldPull === false) { + return undefined; + } + if (controller._pulling === true) { + controller._pullAgain = true; + return undefined; + } + assert(controller._pullAgain === false); + controller._pulling = true; + var pullPromise = PromiseInvokeOrNoop(controller._underlyingByteSource, 'pull', [controller]); + pullPromise.then(function () { + controller._pulling = false; + if (controller._pullAgain === true) { + controller._pullAgain = false; + ReadableByteStreamControllerCallPullIfNeeded(controller); + } + }, function (e) { + if (controller._controlledReadableStream._state === 'readable') { + ReadableByteStreamControllerError(controller, e); + } + }).catch(rethrowAssertionErrorRejection); + return undefined; + } + + function ReadableByteStreamControllerClearPendingPullIntos(controller) { + ReadableByteStreamControllerInvalidateBYOBRequest(controller); + controller._pendingPullIntos = []; + } + + function ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor) { + assert(stream._state !== 'errored', 'state must not be errored'); + var done = false; + if (stream._state === 'closed') { + assert(pullIntoDescriptor.bytesFilled === 0); + done = true; + } + var filledView = ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor); + if (pullIntoDescriptor.readerType === 'default') { + ReadableStreamFulfillReadRequest(stream, filledView, done); + } else { + assert(pullIntoDescriptor.readerType === 'byob'); + ReadableStreamFulfillReadIntoRequest(stream, filledView, done); + } + } + + function ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor) { + var bytesFilled = pullIntoDescriptor.bytesFilled; + var elementSize = pullIntoDescriptor.elementSize; + assert(bytesFilled <= pullIntoDescriptor.byteLength); + assert(bytesFilled % elementSize === 0); + return new pullIntoDescriptor.ctor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, bytesFilled / elementSize); + } + + function ReadableByteStreamControllerEnqueueChunkToQueue(controller, buffer, byteOffset, byteLength) { + controller._queue.push({ + buffer: buffer, + byteOffset: byteOffset, + byteLength: byteLength + }); + controller._queueTotalSize += byteLength; + } + + function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) { + var elementSize = pullIntoDescriptor.elementSize; + var currentAlignedBytes = pullIntoDescriptor.bytesFilled - pullIntoDescriptor.bytesFilled % elementSize; + var maxBytesToCopy = Math.min(controller._queueTotalSize, pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled); + var maxBytesFilled = pullIntoDescriptor.bytesFilled + maxBytesToCopy; + var maxAlignedBytes = maxBytesFilled - maxBytesFilled % elementSize; + var totalBytesToCopyRemaining = maxBytesToCopy; + var ready = false; + if (maxAlignedBytes > currentAlignedBytes) { + totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled; + ready = true; + } + var queue = controller._queue; + while (totalBytesToCopyRemaining > 0) { + var headOfQueue = queue[0]; + var bytesToCopy = Math.min(totalBytesToCopyRemaining, headOfQueue.byteLength); + var destStart = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled; + ArrayBufferCopy(pullIntoDescriptor.buffer, destStart, headOfQueue.buffer, headOfQueue.byteOffset, bytesToCopy); + if (headOfQueue.byteLength === bytesToCopy) { + queue.shift(); + } else { + headOfQueue.byteOffset += bytesToCopy; + headOfQueue.byteLength -= bytesToCopy; + } + controller._queueTotalSize -= bytesToCopy; + ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesToCopy, pullIntoDescriptor); + totalBytesToCopyRemaining -= bytesToCopy; + } + if (ready === false) { + assert(controller._queueTotalSize === 0, 'queue must be empty'); + assert(pullIntoDescriptor.bytesFilled > 0); + assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize); + } + return ready; + } + + function ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, size, pullIntoDescriptor) { + assert(controller._pendingPullIntos.length === 0 || controller._pendingPullIntos[0] === pullIntoDescriptor); + ReadableByteStreamControllerInvalidateBYOBRequest(controller); + pullIntoDescriptor.bytesFilled += size; + } + + function ReadableByteStreamControllerHandleQueueDrain(controller) { + assert(controller._controlledReadableStream._state === 'readable'); + if (controller._queueTotalSize === 0 && controller._closeRequested === true) { + ReadableStreamClose(controller._controlledReadableStream); + } else { + ReadableByteStreamControllerCallPullIfNeeded(controller); + } + } + + function ReadableByteStreamControllerInvalidateBYOBRequest(controller) { + if (controller._byobRequest === undefined) { + return; + } + controller._byobRequest._associatedReadableByteStreamController = undefined; + controller._byobRequest._view = undefined; + controller._byobRequest = undefined; + } + + function ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller) { + assert(controller._closeRequested === false); + while (controller._pendingPullIntos.length > 0) { + if (controller._queueTotalSize === 0) { + return; + } + var pullIntoDescriptor = controller._pendingPullIntos[0]; + if (ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) === true) { + ReadableByteStreamControllerShiftPendingPullInto(controller); + ReadableByteStreamControllerCommitPullIntoDescriptor(controller._controlledReadableStream, pullIntoDescriptor); + } + } + } + + function ReadableByteStreamControllerPullInto(controller, view) { + var stream = controller._controlledReadableStream; + var elementSize = 1; + if (view.constructor !== DataView) { + elementSize = view.constructor.BYTES_PER_ELEMENT; + } + var ctor = view.constructor; + var pullIntoDescriptor = { + buffer: view.buffer, + byteOffset: view.byteOffset, + byteLength: view.byteLength, + bytesFilled: 0, + elementSize: elementSize, + ctor: ctor, + readerType: 'byob' + }; + if (controller._pendingPullIntos.length > 0) { + pullIntoDescriptor.buffer = TransferArrayBuffer(pullIntoDescriptor.buffer); + controller._pendingPullIntos.push(pullIntoDescriptor); + return ReadableStreamAddReadIntoRequest(stream); + } + if (stream._state === 'closed') { + var emptyView = new view.constructor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, 0); + return Promise.resolve(CreateIterResultObject(emptyView, true)); + } + if (controller._queueTotalSize > 0) { + if (ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) === true) { + var filledView = ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor); + ReadableByteStreamControllerHandleQueueDrain(controller); + return Promise.resolve(CreateIterResultObject(filledView, false)); + } + if (controller._closeRequested === true) { + var e = new TypeError('Insufficient bytes to fill elements in the given buffer'); + ReadableByteStreamControllerError(controller, e); + return Promise.reject(e); + } + } + pullIntoDescriptor.buffer = TransferArrayBuffer(pullIntoDescriptor.buffer); + controller._pendingPullIntos.push(pullIntoDescriptor); + var promise = ReadableStreamAddReadIntoRequest(stream); + ReadableByteStreamControllerCallPullIfNeeded(controller); + return promise; + } + + function ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor) { + firstDescriptor.buffer = TransferArrayBuffer(firstDescriptor.buffer); + assert(firstDescriptor.bytesFilled === 0, 'bytesFilled must be 0'); + var stream = controller._controlledReadableStream; + if (ReadableStreamHasBYOBReader(stream) === true) { + while (ReadableStreamGetNumReadIntoRequests(stream) > 0) { + var pullIntoDescriptor = ReadableByteStreamControllerShiftPendingPullInto(controller); + ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor); + } + } + } + + function ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, pullIntoDescriptor) { + if (pullIntoDescriptor.bytesFilled + bytesWritten > pullIntoDescriptor.byteLength) { + throw new RangeError('bytesWritten out of range'); + } + ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesWritten, pullIntoDescriptor); + if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize) { + return; + } + ReadableByteStreamControllerShiftPendingPullInto(controller); + var remainderSize = pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize; + if (remainderSize > 0) { + var end = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled; + var remainder = pullIntoDescriptor.buffer.slice(end - remainderSize, end); + ReadableByteStreamControllerEnqueueChunkToQueue(controller, remainder, 0, remainder.byteLength); + } + pullIntoDescriptor.buffer = TransferArrayBuffer(pullIntoDescriptor.buffer); + pullIntoDescriptor.bytesFilled -= remainderSize; + ReadableByteStreamControllerCommitPullIntoDescriptor(controller._controlledReadableStream, pullIntoDescriptor); + ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller); + } + + function ReadableByteStreamControllerRespondInternal(controller, bytesWritten) { + var firstDescriptor = controller._pendingPullIntos[0]; + var stream = controller._controlledReadableStream; + if (stream._state === 'closed') { + if (bytesWritten !== 0) { + throw new TypeError('bytesWritten must be 0 when calling respond() on a closed stream'); + } + ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor); + } else { + assert(stream._state === 'readable'); + ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, firstDescriptor); + } + } + + function ReadableByteStreamControllerShiftPendingPullInto(controller) { + var descriptor = controller._pendingPullIntos.shift(); + ReadableByteStreamControllerInvalidateBYOBRequest(controller); + return descriptor; + } + + function ReadableByteStreamControllerShouldCallPull(controller) { + var stream = controller._controlledReadableStream; + if (stream._state !== 'readable') { + return false; + } + if (controller._closeRequested === true) { + return false; + } + if (controller._started === false) { + return false; + } + if (ReadableStreamHasDefaultReader(stream) === true && ReadableStreamGetNumReadRequests(stream) > 0) { + return true; + } + if (ReadableStreamHasBYOBReader(stream) === true && ReadableStreamGetNumReadIntoRequests(stream) > 0) { + return true; + } + if (ReadableByteStreamControllerGetDesiredSize(controller) > 0) { + return true; + } + return false; + } + + function ReadableByteStreamControllerClose(controller) { + var stream = controller._controlledReadableStream; + assert(controller._closeRequested === false); + assert(stream._state === 'readable'); + if (controller._queueTotalSize > 0) { + controller._closeRequested = true; + return; + } + if (controller._pendingPullIntos.length > 0) { + var firstPendingPullInto = controller._pendingPullIntos[0]; + if (firstPendingPullInto.bytesFilled > 0) { + var e = new TypeError('Insufficient bytes to fill elements in the given buffer'); + ReadableByteStreamControllerError(controller, e); + throw e; + } + } + ReadableStreamClose(stream); + } + + function ReadableByteStreamControllerEnqueue(controller, chunk) { + var stream = controller._controlledReadableStream; + assert(controller._closeRequested === false); + assert(stream._state === 'readable'); + var buffer = chunk.buffer; + var byteOffset = chunk.byteOffset; + var byteLength = chunk.byteLength; + var transferredBuffer = TransferArrayBuffer(buffer); + if (ReadableStreamHasDefaultReader(stream) === true) { + if (ReadableStreamGetNumReadRequests(stream) === 0) { + ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength); + } else { + assert(controller._queue.length === 0); + var transferredView = new Uint8Array(transferredBuffer, byteOffset, byteLength); + ReadableStreamFulfillReadRequest(stream, transferredView, false); + } + } else if (ReadableStreamHasBYOBReader(stream) === true) { + ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength); + ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller); + } else { + assert(IsReadableStreamLocked(stream) === false, 'stream must not be locked'); + ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength); + } + } + + function ReadableByteStreamControllerError(controller, e) { + var stream = controller._controlledReadableStream; + assert(stream._state === 'readable'); + ReadableByteStreamControllerClearPendingPullIntos(controller); + ResetQueue(controller); + ReadableStreamError(stream, e); + } + + function ReadableByteStreamControllerGetDesiredSize(controller) { + var stream = controller._controlledReadableStream; + var state = stream._state; + if (state === 'errored') { + return null; + } + if (state === 'closed') { + return 0; + } + return controller._strategyHWM - controller._queueTotalSize; + } + + function ReadableByteStreamControllerRespond(controller, bytesWritten) { + bytesWritten = Number(bytesWritten); + if (IsFiniteNonNegativeNumber(bytesWritten) === false) { + throw new RangeError('bytesWritten must be a finite'); + } + assert(controller._pendingPullIntos.length > 0); + ReadableByteStreamControllerRespondInternal(controller, bytesWritten); + } + + function ReadableByteStreamControllerRespondWithNewView(controller, view) { + assert(controller._pendingPullIntos.length > 0); + var firstDescriptor = controller._pendingPullIntos[0]; + if (firstDescriptor.byteOffset + firstDescriptor.bytesFilled !== view.byteOffset) { + throw new RangeError('The region specified by view does not match byobRequest'); + } + if (firstDescriptor.byteLength !== view.byteLength) { + throw new RangeError('The buffer of view has different capacity than byobRequest'); + } + firstDescriptor.buffer = view.buffer; + ReadableByteStreamControllerRespondInternal(controller, view.byteLength); + } + + function streamBrandCheckException(name) { + return new TypeError('ReadableStream.prototype.' + name + ' can only be used on a ReadableStream'); + } + + function readerLockException(name) { + return new TypeError('Cannot ' + name + ' a stream using a released reader'); + } + + function defaultReaderBrandCheckException(name) { + return new TypeError('ReadableStreamDefaultReader.prototype.' + name + ' can only be used on a ReadableStreamDefaultReader'); + } + + function defaultReaderClosedPromiseInitialize(reader) { + reader._closedPromise = new Promise(function (resolve, reject) { + reader._closedPromise_resolve = resolve; + reader._closedPromise_reject = reject; + }); + } + + function defaultReaderClosedPromiseInitializeAsRejected(reader, reason) { + reader._closedPromise = Promise.reject(reason); + reader._closedPromise_resolve = undefined; + reader._closedPromise_reject = undefined; + } + + function defaultReaderClosedPromiseInitializeAsResolved(reader) { + reader._closedPromise = Promise.resolve(undefined); + reader._closedPromise_resolve = undefined; + reader._closedPromise_reject = undefined; + } + + function defaultReaderClosedPromiseReject(reader, reason) { + assert(reader._closedPromise_resolve !== undefined); + assert(reader._closedPromise_reject !== undefined); + reader._closedPromise_reject(reason); + reader._closedPromise_resolve = undefined; + reader._closedPromise_reject = undefined; + } + + function defaultReaderClosedPromiseResetToRejected(reader, reason) { + assert(reader._closedPromise_resolve === undefined); + assert(reader._closedPromise_reject === undefined); + reader._closedPromise = Promise.reject(reason); + } + + function defaultReaderClosedPromiseResolve(reader) { + assert(reader._closedPromise_resolve !== undefined); + assert(reader._closedPromise_reject !== undefined); + reader._closedPromise_resolve(undefined); + reader._closedPromise_resolve = undefined; + reader._closedPromise_reject = undefined; + } + + function byobReaderBrandCheckException(name) { + return new TypeError('ReadableStreamBYOBReader.prototype.' + name + ' can only be used on a ReadableStreamBYOBReader'); + } + + function defaultControllerBrandCheckException(name) { + return new TypeError('ReadableStreamDefaultController.prototype.' + name + ' can only be used on a ReadableStreamDefaultController'); + } + + function byobRequestBrandCheckException(name) { + return new TypeError('ReadableStreamBYOBRequest.prototype.' + name + ' can only be used on a ReadableStreamBYOBRequest'); + } + + function byteStreamControllerBrandCheckException(name) { + return new TypeError('ReadableByteStreamController.prototype.' + name + ' can only be used on a ReadableByteStreamController'); + } + + function ifIsObjectAndHasAPromiseIsHandledInternalSlotSetPromiseIsHandledToTrue(promise) { + try { + Promise.prototype.then.call(promise, undefined, function () { + }); + } catch (e) { + } + } + }, function (module, exports, __w_pdfjs_require__) { + "use strict"; + + var transformStream = __w_pdfjs_require__(6); + var readableStream = __w_pdfjs_require__(4); + var writableStream = __w_pdfjs_require__(2); + exports.TransformStream = transformStream.TransformStream; + exports.ReadableStream = readableStream.ReadableStream; + exports.IsReadableStreamDisturbed = readableStream.IsReadableStreamDisturbed; + exports.ReadableStreamDefaultControllerClose = readableStream.ReadableStreamDefaultControllerClose; + exports.ReadableStreamDefaultControllerEnqueue = readableStream.ReadableStreamDefaultControllerEnqueue; + exports.ReadableStreamDefaultControllerError = readableStream.ReadableStreamDefaultControllerError; + exports.ReadableStreamDefaultControllerGetDesiredSize = readableStream.ReadableStreamDefaultControllerGetDesiredSize; + exports.AcquireWritableStreamDefaultWriter = writableStream.AcquireWritableStreamDefaultWriter; + exports.IsWritableStream = writableStream.IsWritableStream; + exports.IsWritableStreamLocked = writableStream.IsWritableStreamLocked; + exports.WritableStream = writableStream.WritableStream; + exports.WritableStreamAbort = writableStream.WritableStreamAbort; + exports.WritableStreamDefaultControllerError = writableStream.WritableStreamDefaultControllerError; + exports.WritableStreamDefaultWriterCloseWithErrorPropagation = writableStream.WritableStreamDefaultWriterCloseWithErrorPropagation; + exports.WritableStreamDefaultWriterRelease = writableStream.WritableStreamDefaultWriterRelease; + exports.WritableStreamDefaultWriterWrite = writableStream.WritableStreamDefaultWriterWrite; + }, function (module, exports, __w_pdfjs_require__) { + "use strict"; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var _require = __w_pdfjs_require__(1), + assert = _require.assert; + var _require2 = __w_pdfjs_require__(0), + InvokeOrNoop = _require2.InvokeOrNoop, + PromiseInvokeOrPerformFallback = _require2.PromiseInvokeOrPerformFallback, + PromiseInvokeOrNoop = _require2.PromiseInvokeOrNoop, + typeIsObject = _require2.typeIsObject; + var _require3 = __w_pdfjs_require__(4), + ReadableStream = _require3.ReadableStream, + ReadableStreamDefaultControllerClose = _require3.ReadableStreamDefaultControllerClose, + ReadableStreamDefaultControllerEnqueue = _require3.ReadableStreamDefaultControllerEnqueue, + ReadableStreamDefaultControllerError = _require3.ReadableStreamDefaultControllerError, + ReadableStreamDefaultControllerGetDesiredSize = _require3.ReadableStreamDefaultControllerGetDesiredSize; + var _require4 = __w_pdfjs_require__(2), + WritableStream = _require4.WritableStream, + WritableStreamDefaultControllerError = _require4.WritableStreamDefaultControllerError; + + function TransformStreamCloseReadable(transformStream) { + if (transformStream._errored === true) { + throw new TypeError('TransformStream is already errored'); + } + if (transformStream._readableClosed === true) { + throw new TypeError('Readable side is already closed'); + } + TransformStreamCloseReadableInternal(transformStream); + } + + function TransformStreamEnqueueToReadable(transformStream, chunk) { + if (transformStream._errored === true) { + throw new TypeError('TransformStream is already errored'); + } + if (transformStream._readableClosed === true) { + throw new TypeError('Readable side is already closed'); + } + var controller = transformStream._readableController; + try { + ReadableStreamDefaultControllerEnqueue(controller, chunk); + } catch (e) { + transformStream._readableClosed = true; + TransformStreamErrorIfNeeded(transformStream, e); + throw transformStream._storedError; + } + var desiredSize = ReadableStreamDefaultControllerGetDesiredSize(controller); + var maybeBackpressure = desiredSize <= 0; + if (maybeBackpressure === true && transformStream._backpressure === false) { + TransformStreamSetBackpressure(transformStream, true); + } + } + + function TransformStreamError(transformStream, e) { + if (transformStream._errored === true) { + throw new TypeError('TransformStream is already errored'); + } + TransformStreamErrorInternal(transformStream, e); + } + + function TransformStreamCloseReadableInternal(transformStream) { + assert(transformStream._errored === false); + assert(transformStream._readableClosed === false); + try { + ReadableStreamDefaultControllerClose(transformStream._readableController); + } catch (e) { + assert(false); + } + transformStream._readableClosed = true; + } + + function TransformStreamErrorIfNeeded(transformStream, e) { + if (transformStream._errored === false) { + TransformStreamErrorInternal(transformStream, e); + } + } + + function TransformStreamErrorInternal(transformStream, e) { + assert(transformStream._errored === false); + transformStream._errored = true; + transformStream._storedError = e; + if (transformStream._writableDone === false) { + WritableStreamDefaultControllerError(transformStream._writableController, e); + } + if (transformStream._readableClosed === false) { + ReadableStreamDefaultControllerError(transformStream._readableController, e); + } + } + + function TransformStreamReadableReadyPromise(transformStream) { + assert(transformStream._backpressureChangePromise !== undefined, '_backpressureChangePromise should have been initialized'); + if (transformStream._backpressure === false) { + return Promise.resolve(); + } + assert(transformStream._backpressure === true, '_backpressure should have been initialized'); + return transformStream._backpressureChangePromise; + } + + function TransformStreamSetBackpressure(transformStream, backpressure) { + assert(transformStream._backpressure !== backpressure, 'TransformStreamSetBackpressure() should be called only when backpressure is changed'); + if (transformStream._backpressureChangePromise !== undefined) { + transformStream._backpressureChangePromise_resolve(backpressure); + } + transformStream._backpressureChangePromise = new Promise(function (resolve) { + transformStream._backpressureChangePromise_resolve = resolve; + }); + transformStream._backpressureChangePromise.then(function (resolution) { + assert(resolution !== backpressure, '_backpressureChangePromise should be fulfilled only when backpressure is changed'); + }); + transformStream._backpressure = backpressure; + } + + function TransformStreamDefaultTransform(chunk, transformStreamController) { + var transformStream = transformStreamController._controlledTransformStream; + TransformStreamEnqueueToReadable(transformStream, chunk); + return Promise.resolve(); + } + + function TransformStreamTransform(transformStream, chunk) { + assert(transformStream._errored === false); + assert(transformStream._transforming === false); + assert(transformStream._backpressure === false); + transformStream._transforming = true; + var transformer = transformStream._transformer; + var controller = transformStream._transformStreamController; + var transformPromise = PromiseInvokeOrPerformFallback(transformer, 'transform', [chunk, controller], TransformStreamDefaultTransform, [chunk, controller]); + return transformPromise.then(function () { + transformStream._transforming = false; + return TransformStreamReadableReadyPromise(transformStream); + }, function (e) { + TransformStreamErrorIfNeeded(transformStream, e); + return Promise.reject(e); + }); + } + + function IsTransformStreamDefaultController(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_controlledTransformStream')) { + return false; + } + return true; + } + + function IsTransformStream(x) { + if (!typeIsObject(x)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x, '_transformStreamController')) { + return false; + } + return true; + } + + var TransformStreamSink = function () { + function TransformStreamSink(transformStream, startPromise) { + _classCallCheck(this, TransformStreamSink); + this._transformStream = transformStream; + this._startPromise = startPromise; + } + + _createClass(TransformStreamSink, [{ + key: 'start', + value: function start(c) { + var transformStream = this._transformStream; + transformStream._writableController = c; + return this._startPromise.then(function () { + return TransformStreamReadableReadyPromise(transformStream); + }); + } + }, { + key: 'write', + value: function write(chunk) { + var transformStream = this._transformStream; + return TransformStreamTransform(transformStream, chunk); + } + }, { + key: 'abort', + value: function abort() { + var transformStream = this._transformStream; + transformStream._writableDone = true; + TransformStreamErrorInternal(transformStream, new TypeError('Writable side aborted')); + } + }, { + key: 'close', + value: function close() { + var transformStream = this._transformStream; + assert(transformStream._transforming === false); + transformStream._writableDone = true; + var flushPromise = PromiseInvokeOrNoop(transformStream._transformer, 'flush', [transformStream._transformStreamController]); + return flushPromise.then(function () { + if (transformStream._errored === true) { + return Promise.reject(transformStream._storedError); + } + if (transformStream._readableClosed === false) { + TransformStreamCloseReadableInternal(transformStream); + } + return Promise.resolve(); + }).catch(function (r) { + TransformStreamErrorIfNeeded(transformStream, r); + return Promise.reject(transformStream._storedError); + }); + } + }]); + return TransformStreamSink; + }(); + var TransformStreamSource = function () { + function TransformStreamSource(transformStream, startPromise) { + _classCallCheck(this, TransformStreamSource); + this._transformStream = transformStream; + this._startPromise = startPromise; + } + + _createClass(TransformStreamSource, [{ + key: 'start', + value: function start(c) { + var transformStream = this._transformStream; + transformStream._readableController = c; + return this._startPromise.then(function () { + assert(transformStream._backpressureChangePromise !== undefined, '_backpressureChangePromise should have been initialized'); + if (transformStream._backpressure === true) { + return Promise.resolve(); + } + assert(transformStream._backpressure === false, '_backpressure should have been initialized'); + return transformStream._backpressureChangePromise; + }); + } + }, { + key: 'pull', + value: function pull() { + var transformStream = this._transformStream; + assert(transformStream._backpressure === true, 'pull() should be never called while _backpressure is false'); + assert(transformStream._backpressureChangePromise !== undefined, '_backpressureChangePromise should have been initialized'); + TransformStreamSetBackpressure(transformStream, false); + return transformStream._backpressureChangePromise; + } + }, { + key: 'cancel', + value: function cancel() { + var transformStream = this._transformStream; + transformStream._readableClosed = true; + TransformStreamErrorInternal(transformStream, new TypeError('Readable side canceled')); + } + }]); + return TransformStreamSource; + }(); + var TransformStreamDefaultController = function () { + function TransformStreamDefaultController(transformStream) { + _classCallCheck(this, TransformStreamDefaultController); + if (IsTransformStream(transformStream) === false) { + throw new TypeError('TransformStreamDefaultController can only be ' + 'constructed with a TransformStream instance'); + } + if (transformStream._transformStreamController !== undefined) { + throw new TypeError('TransformStreamDefaultController instances can ' + 'only be created by the TransformStream constructor'); + } + this._controlledTransformStream = transformStream; + } + + _createClass(TransformStreamDefaultController, [{ + key: 'enqueue', + value: function enqueue(chunk) { + if (IsTransformStreamDefaultController(this) === false) { + throw defaultControllerBrandCheckException('enqueue'); + } + TransformStreamEnqueueToReadable(this._controlledTransformStream, chunk); + } + }, { + key: 'close', + value: function close() { + if (IsTransformStreamDefaultController(this) === false) { + throw defaultControllerBrandCheckException('close'); + } + TransformStreamCloseReadable(this._controlledTransformStream); + } + }, { + key: 'error', + value: function error(reason) { + if (IsTransformStreamDefaultController(this) === false) { + throw defaultControllerBrandCheckException('error'); + } + TransformStreamError(this._controlledTransformStream, reason); + } + }, { + key: 'desiredSize', + get: function get() { + if (IsTransformStreamDefaultController(this) === false) { + throw defaultControllerBrandCheckException('desiredSize'); + } + var transformStream = this._controlledTransformStream; + var readableController = transformStream._readableController; + return ReadableStreamDefaultControllerGetDesiredSize(readableController); + } + }]); + return TransformStreamDefaultController; + }(); + var TransformStream = function () { + function TransformStream() { + var transformer = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + _classCallCheck(this, TransformStream); + this._transformer = transformer; + var readableStrategy = transformer.readableStrategy, + writableStrategy = transformer.writableStrategy; + this._transforming = false; + this._errored = false; + this._storedError = undefined; + this._writableController = undefined; + this._readableController = undefined; + this._transformStreamController = undefined; + this._writableDone = false; + this._readableClosed = false; + this._backpressure = undefined; + this._backpressureChangePromise = undefined; + this._backpressureChangePromise_resolve = undefined; + this._transformStreamController = new TransformStreamDefaultController(this); + var startPromise_resolve = void 0; + var startPromise = new Promise(function (resolve) { + startPromise_resolve = resolve; + }); + var source = new TransformStreamSource(this, startPromise); + this._readable = new ReadableStream(source, readableStrategy); + var sink = new TransformStreamSink(this, startPromise); + this._writable = new WritableStream(sink, writableStrategy); + assert(this._writableController !== undefined); + assert(this._readableController !== undefined); + var desiredSize = ReadableStreamDefaultControllerGetDesiredSize(this._readableController); + TransformStreamSetBackpressure(this, desiredSize <= 0); + var transformStream = this; + var startResult = InvokeOrNoop(transformer, 'start', [transformStream._transformStreamController]); + startPromise_resolve(startResult); + startPromise.catch(function (e) { + if (transformStream._errored === false) { + transformStream._errored = true; + transformStream._storedError = e; + } + }); + } + + _createClass(TransformStream, [{ + key: 'readable', + get: function get() { + if (IsTransformStream(this) === false) { + throw streamBrandCheckException('readable'); + } + return this._readable; + } + }, { + key: 'writable', + get: function get() { + if (IsTransformStream(this) === false) { + throw streamBrandCheckException('writable'); + } + return this._writable; + } + }]); + return TransformStream; + }(); + module.exports = {TransformStream: TransformStream}; + + function defaultControllerBrandCheckException(name) { + return new TypeError('TransformStreamDefaultController.prototype.' + name + ' can only be used on a TransformStreamDefaultController'); + } + + function streamBrandCheckException(name) { + return new TypeError('TransformStream.prototype.' + name + ' can only be used on a TransformStream'); + } + }, function (module, exports, __w_pdfjs_require__) { + module.exports = __w_pdfjs_require__(5); + }])); + + /***/ + }), + /* 19 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.AnnotationFactory = exports.AnnotationBorderStyle = exports.Annotation = undefined; + + var _util = __w_pdfjs_require__(0); + + var _obj = __w_pdfjs_require__(15); + + var _primitives = __w_pdfjs_require__(1); + + var _colorspace = __w_pdfjs_require__(3); + + var _evaluator = __w_pdfjs_require__(13); + + var _stream = __w_pdfjs_require__(2); + + function AnnotationFactory() { + } + + AnnotationFactory.prototype = { + create: function AnnotationFactory_create(xref, ref, pdfManager, idFactory) { + var dict = xref.fetchIfRef(ref); + if (!(0, _primitives.isDict)(dict)) { + return; + } + var id = (0, _primitives.isRef)(ref) ? ref.toString() : 'annot_' + idFactory.createObjId(); + var subtype = dict.get('Subtype'); + subtype = (0, _primitives.isName)(subtype) ? subtype.name : null; + var parameters = { + xref: xref, + dict: dict, + ref: (0, _primitives.isRef)(ref) ? ref : null, + subtype: subtype, + id: id, + pdfManager: pdfManager + }; + switch (subtype) { + case 'Link': + return new LinkAnnotation(parameters); + case 'Text': + return new TextAnnotation(parameters); + case 'Widget': + var fieldType = _util.Util.getInheritableProperty(dict, '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 'Line': + return new LineAnnotation(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 '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); + } + } + }; + var Annotation = function AnnotationClosure() { + function getTransformMatrix(rect, bbox, matrix) { + var bounds = _util.Util.getAxialAlignedBoundingBox(bbox, matrix); + var minX = bounds[0]; + var minY = bounds[1]; + var maxX = bounds[2]; + var maxY = bounds[3]; + if (minX === maxX || minY === maxY) { + return [1, 0, 0, 1, rect[0], rect[1]]; + } + var xRatio = (rect[2] - rect[0]) / (maxX - minX); + var yRatio = (rect[3] - rect[1]) / (maxY - minY); + return [xRatio, 0, 0, yRatio, rect[0] - minX * xRatio, rect[1] - minY * yRatio]; + } + + function Annotation(params) { + var dict = params.dict; + this.setFlags(dict.get('F')); + this.setRectangle(dict.getArray('Rect')); + this.setColor(dict.getArray('C')); + this.setBorderStyle(dict); + this.setAppearance(dict); + this.data = {}; + this.data.id = params.id; + this.data.subtype = params.subtype; + this.data.annotationFlags = this.flags; + this.data.rect = this.rectangle; + this.data.color = this.color; + this.data.borderStyle = this.borderStyle; + this.data.hasAppearance = !!this.appearance; + } + + Annotation.prototype = { + _hasFlag: function Annotation_hasFlag(flags, flag) { + return !!(flags & flag); + }, + _isViewable: function Annotation_isViewable(flags) { + return !this._hasFlag(flags, _util.AnnotationFlag.INVISIBLE) && !this._hasFlag(flags, _util.AnnotationFlag.HIDDEN) && !this._hasFlag(flags, _util.AnnotationFlag.NOVIEW); + }, + _isPrintable: function AnnotationFlag_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); + }, + setFlags: function Annotation_setFlags(flags) { + this.flags = (0, _util.isInt)(flags) && flags > 0 ? flags : 0; + }, + hasFlag: function Annotation_hasFlag(flag) { + return this._hasFlag(this.flags, flag); + }, + setRectangle: function Annotation_setRectangle(rectangle) { + if ((0, _util.isArray)(rectangle) && rectangle.length === 4) { + this.rectangle = _util.Util.normalizeRect(rectangle); + } else { + this.rectangle = [0, 0, 0, 0]; + } + }, + setColor: function Annotation_setColor(color) { + var rgbColor = new Uint8Array(3); + if (!(0, _util.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: function Annotation_setBorderStyle(borderStyle) { + this.borderStyle = new AnnotationBorderStyle(); + if (!(0, _primitives.isDict)(borderStyle)) { + return; + } + if (borderStyle.has('BS')) { + var dict = borderStyle.get('BS'); + var dictType = dict.get('Type'); + if (!dictType || (0, _primitives.isName)(dictType, 'Border')) { + this.borderStyle.setWidth(dict.get('W')); + this.borderStyle.setStyle(dict.get('S')); + this.borderStyle.setDashArray(dict.getArray('D')); + } + } else if (borderStyle.has('Border')) { + var array = borderStyle.getArray('Border'); + if ((0, _util.isArray)(array) && array.length >= 3) { + this.borderStyle.setHorizontalCornerRadius(array[0]); + this.borderStyle.setVerticalCornerRadius(array[1]); + this.borderStyle.setWidth(array[2]); + if (array.length === 4) { + this.borderStyle.setDashArray(array[3]); + } + } + } else { + this.borderStyle.setWidth(0); + } + }, + setAppearance: function Annotation_setAppearance(dict) { + this.appearance = null; + var appearanceStates = dict.get('AP'); + if (!(0, _primitives.isDict)(appearanceStates)) { + return; + } + var normalAppearanceState = appearanceStates.get('N'); + if ((0, _primitives.isStream)(normalAppearanceState)) { + this.appearance = normalAppearanceState; + return; + } + if (!(0, _primitives.isDict)(normalAppearanceState)) { + return; + } + var as = dict.get('AS'); + if (!(0, _primitives.isName)(as) || !normalAppearanceState.has(as.name)) { + return; + } + this.appearance = normalAppearanceState.get(as.name); + }, + _preparePopup: function Annotation_preparePopup(dict) { + if (!dict.has('C')) { + this.data.color = null; + } + this.data.hasPopup = dict.has('Popup'); + this.data.title = (0, _util.stringToPDFString)(dict.get('T') || ''); + this.data.contents = (0, _util.stringToPDFString)(dict.get('Contents') || ''); + }, + loadResources: function Annotation_loadResources(keys) { + return this.appearance.dict.getAsync('Resources').then(function (resources) { + if (!resources) { + return; + } + var objectLoader = new _obj.ObjectLoader(resources, keys, resources.xref); + return objectLoader.load().then(function () { + return resources; + }); + }); + }, + getOperatorList: function Annotation_getOperatorList(evaluator, task, renderForms) { + var _this = this; + + if (!this.appearance) { + return Promise.resolve(new _evaluator.OperatorList()); + } + var data = this.data; + var appearanceDict = this.appearance.dict; + var resourcesPromise = this.loadResources(['ExtGState', 'ColorSpace', 'Pattern', 'Shading', 'XObject', 'Font']); + var bbox = appearanceDict.getArray('BBox') || [0, 0, 1, 1]; + var matrix = appearanceDict.getArray('Matrix') || [1, 0, 0, 1, 0, 0]; + var transform = getTransformMatrix(data.rect, bbox, matrix); + return resourcesPromise.then(function (resources) { + var opList = new _evaluator.OperatorList(); + opList.addOp(_util.OPS.beginAnnotation, [data.rect, transform, matrix]); + return evaluator.getOperatorList({ + stream: _this.appearance, + task: task, + resources: resources, + operatorList: opList + }).then(function () { + opList.addOp(_util.OPS.endAnnotation, []); + _this.appearance.reset(); + return opList; + }); + }); + } + }; + return Annotation; + }(); + var AnnotationBorderStyle = function AnnotationBorderStyleClosure() { + function AnnotationBorderStyle() { + this.width = 1; + this.style = _util.AnnotationBorderStyleType.SOLID; + this.dashArray = [3]; + this.horizontalCornerRadius = 0; + this.verticalCornerRadius = 0; + } + + AnnotationBorderStyle.prototype = { + setWidth: function AnnotationBorderStyle_setWidth(width) { + if (width === (width | 0)) { + this.width = width; + } + }, + setStyle: function AnnotationBorderStyle_setStyle(style) { + if (!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: function AnnotationBorderStyle_setDashArray(dashArray) { + if ((0, _util.isArray)(dashArray) && dashArray.length > 0) { + var isValid = true; + var allZeros = true; + for (var i = 0, len = dashArray.length; i < len; i++) { + var element = dashArray[i]; + var 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: function AnnotationBorderStyle_setHorizontalCornerRadius(radius) { + if (radius === (radius | 0)) { + this.horizontalCornerRadius = radius; + } + }, + setVerticalCornerRadius: function AnnotationBorderStyle_setVerticalCornerRadius(radius) { + if (radius === (radius | 0)) { + this.verticalCornerRadius = radius; + } + } + }; + return AnnotationBorderStyle; + }(); + var WidgetAnnotation = function WidgetAnnotationClosure() { + function WidgetAnnotation(params) { + Annotation.call(this, params); + var dict = params.dict; + var data = this.data; + data.annotationType = _util.AnnotationType.WIDGET; + data.fieldName = this._constructFieldName(dict); + data.fieldValue = _util.Util.getInheritableProperty(dict, 'V', true); + data.alternativeText = (0, _util.stringToPDFString)(dict.get('TU') || ''); + data.defaultAppearance = _util.Util.getInheritableProperty(dict, 'DA') || ''; + var fieldType = _util.Util.getInheritableProperty(dict, 'FT'); + data.fieldType = (0, _primitives.isName)(fieldType) ? fieldType.name : null; + this.fieldResources = _util.Util.getInheritableProperty(dict, 'DR') || _primitives.Dict.empty; + data.fieldFlags = _util.Util.getInheritableProperty(dict, 'Ff'); + if (!(0, _util.isInt)(data.fieldFlags) || data.fieldFlags < 0) { + data.fieldFlags = 0; + } + data.readOnly = this.hasFieldFlag(_util.AnnotationFieldFlag.READONLY); + if (data.fieldType === 'Sig') { + this.setFlags(_util.AnnotationFlag.HIDDEN); + } + } + + _util.Util.inherit(WidgetAnnotation, Annotation, { + _constructFieldName: function WidgetAnnotation_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')); + } + var fieldName = []; + if (dict.has('T')) { + fieldName.unshift((0, _util.stringToPDFString)(dict.get('T'))); + } + var 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('.'); + }, + hasFieldFlag: function WidgetAnnotation_hasFieldFlag(flag) { + return !!(this.data.fieldFlags & flag); + } + }); + return WidgetAnnotation; + }(); + var TextWidgetAnnotation = function TextWidgetAnnotationClosure() { + function TextWidgetAnnotation(params) { + WidgetAnnotation.call(this, params); + this.data.fieldValue = (0, _util.stringToPDFString)(this.data.fieldValue || ''); + var alignment = _util.Util.getInheritableProperty(params.dict, 'Q'); + if (!(0, _util.isInt)(alignment) || alignment < 0 || alignment > 2) { + alignment = null; + } + this.data.textAlignment = alignment; + var maximumLength = _util.Util.getInheritableProperty(params.dict, 'MaxLen'); + if (!(0, _util.isInt)(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; + } + + _util.Util.inherit(TextWidgetAnnotation, WidgetAnnotation, { + getOperatorList: function TextWidgetAnnotation_getOperatorList(evaluator, task, renderForms) { + var operatorList = new _evaluator.OperatorList(); + if (renderForms) { + return Promise.resolve(operatorList); + } + if (this.appearance) { + return Annotation.prototype.getOperatorList.call(this, evaluator, task, renderForms); + } + if (!this.data.defaultAppearance) { + return Promise.resolve(operatorList); + } + var stream = new _stream.Stream((0, _util.stringToBytes)(this.data.defaultAppearance)); + return evaluator.getOperatorList({ + stream: stream, + task: task, + resources: this.fieldResources, + operatorList: operatorList + }).then(function () { + return operatorList; + }); + } + }); + return TextWidgetAnnotation; + }(); + var ButtonWidgetAnnotation = function ButtonWidgetAnnotationClosure() { + function ButtonWidgetAnnotation(params) { + WidgetAnnotation.call(this, params); + this.data.checkBox = !this.hasFieldFlag(_util.AnnotationFieldFlag.RADIO) && !this.hasFieldFlag(_util.AnnotationFieldFlag.PUSHBUTTON); + if (this.data.checkBox) { + if (!(0, _primitives.isName)(this.data.fieldValue)) { + return; + } + this.data.fieldValue = this.data.fieldValue.name; + } + this.data.radioButton = this.hasFieldFlag(_util.AnnotationFieldFlag.RADIO) && !this.hasFieldFlag(_util.AnnotationFieldFlag.PUSHBUTTON); + if (this.data.radioButton) { + this.data.fieldValue = this.data.buttonValue = null; + var fieldParent = params.dict.get('Parent'); + if ((0, _primitives.isDict)(fieldParent) && fieldParent.has('V')) { + var fieldParentValue = fieldParent.get('V'); + if ((0, _primitives.isName)(fieldParentValue)) { + this.data.fieldValue = fieldParentValue.name; + } + } + var appearanceStates = params.dict.get('AP'); + if (!(0, _primitives.isDict)(appearanceStates)) { + return; + } + var normalAppearanceState = appearanceStates.get('N'); + if (!(0, _primitives.isDict)(normalAppearanceState)) { + return; + } + var keys = normalAppearanceState.getKeys(); + for (var i = 0, ii = keys.length; i < ii; i++) { + if (keys[i] !== 'Off') { + this.data.buttonValue = keys[i]; + break; + } + } + } + } + + _util.Util.inherit(ButtonWidgetAnnotation, WidgetAnnotation, { + getOperatorList: function ButtonWidgetAnnotation_getOperatorList(evaluator, task, renderForms) { + var operatorList = new _evaluator.OperatorList(); + if (renderForms) { + return Promise.resolve(operatorList); + } + if (this.appearance) { + return Annotation.prototype.getOperatorList.call(this, evaluator, task, renderForms); + } + return Promise.resolve(operatorList); + } + }); + return ButtonWidgetAnnotation; + }(); + var ChoiceWidgetAnnotation = function ChoiceWidgetAnnotationClosure() { + function ChoiceWidgetAnnotation(params) { + WidgetAnnotation.call(this, params); + this.data.options = []; + var options = _util.Util.getInheritableProperty(params.dict, 'Opt'); + if ((0, _util.isArray)(options)) { + var xref = params.xref; + for (var i = 0, ii = options.length; i < ii; i++) { + var option = xref.fetchIfRef(options[i]); + var isOptionArray = (0, _util.isArray)(option); + this.data.options[i] = { + exportValue: isOptionArray ? xref.fetchIfRef(option[0]) : option, + displayValue: isOptionArray ? xref.fetchIfRef(option[1]) : option + }; + } + } + if (!(0, _util.isArray)(this.data.fieldValue)) { + this.data.fieldValue = [this.data.fieldValue]; + } + this.data.combo = this.hasFieldFlag(_util.AnnotationFieldFlag.COMBO); + this.data.multiSelect = this.hasFieldFlag(_util.AnnotationFieldFlag.MULTISELECT); + } + + _util.Util.inherit(ChoiceWidgetAnnotation, WidgetAnnotation, { + getOperatorList: function ChoiceWidgetAnnotation_getOperatorList(evaluator, task, renderForms) { + var operatorList = new _evaluator.OperatorList(); + if (renderForms) { + return Promise.resolve(operatorList); + } + return Annotation.prototype.getOperatorList.call(this, evaluator, task, renderForms); + } + }); + return ChoiceWidgetAnnotation; + }(); + var TextAnnotation = function TextAnnotationClosure() { + var DEFAULT_ICON_SIZE = 22; + + function TextAnnotation(parameters) { + Annotation.call(this, parameters); + 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 = parameters.dict.has('Name') ? parameters.dict.get('Name').name : 'Note'; + } + this._preparePopup(parameters.dict); + } + + _util.Util.inherit(TextAnnotation, Annotation, {}); + return TextAnnotation; + }(); + var LinkAnnotation = function LinkAnnotationClosure() { + function LinkAnnotation(params) { + Annotation.call(this, params); + var data = this.data; + data.annotationType = _util.AnnotationType.LINK; + _obj.Catalog.parseDestDictionary({ + destDict: params.dict, + resultObj: data, + docBaseUrl: params.pdfManager.docBaseUrl + }); + } + + _util.Util.inherit(LinkAnnotation, Annotation, {}); + return LinkAnnotation; + }(); + var PopupAnnotation = function PopupAnnotationClosure() { + function PopupAnnotation(parameters) { + Annotation.call(this, parameters); + this.data.annotationType = _util.AnnotationType.POPUP; + var dict = parameters.dict; + var parentItem = dict.get('Parent'); + if (!parentItem) { + (0, _util.warn)('Popup annotation has a missing or invalid parent annotation.'); + return; + } + var parentSubtype = parentItem.get('Subtype'); + this.data.parentType = (0, _primitives.isName)(parentSubtype) ? parentSubtype.name : null; + this.data.parentId = dict.getRaw('Parent').toString(); + this.data.title = (0, _util.stringToPDFString)(parentItem.get('T') || ''); + this.data.contents = (0, _util.stringToPDFString)(parentItem.get('Contents') || ''); + if (!parentItem.has('C')) { + this.data.color = null; + } else { + this.setColor(parentItem.getArray('C')); + this.data.color = this.color; + } + if (!this.viewable) { + var parentFlags = parentItem.get('F'); + if (this._isViewable(parentFlags)) { + this.setFlags(parentFlags); + } + } + } + + _util.Util.inherit(PopupAnnotation, Annotation, {}); + return PopupAnnotation; + }(); + var LineAnnotation = function LineAnnotationClosure() { + function LineAnnotation(parameters) { + Annotation.call(this, parameters); + this.data.annotationType = _util.AnnotationType.LINE; + var dict = parameters.dict; + this.data.lineCoordinates = _util.Util.normalizeRect(dict.getArray('L')); + this._preparePopup(dict); + } + + _util.Util.inherit(LineAnnotation, Annotation, {}); + return LineAnnotation; + }(); + var HighlightAnnotation = function HighlightAnnotationClosure() { + function HighlightAnnotation(parameters) { + Annotation.call(this, parameters); + this.data.annotationType = _util.AnnotationType.HIGHLIGHT; + this._preparePopup(parameters.dict); + } + + _util.Util.inherit(HighlightAnnotation, Annotation, {}); + return HighlightAnnotation; + }(); + var UnderlineAnnotation = function UnderlineAnnotationClosure() { + function UnderlineAnnotation(parameters) { + Annotation.call(this, parameters); + this.data.annotationType = _util.AnnotationType.UNDERLINE; + this._preparePopup(parameters.dict); + } + + _util.Util.inherit(UnderlineAnnotation, Annotation, {}); + return UnderlineAnnotation; + }(); + var SquigglyAnnotation = function SquigglyAnnotationClosure() { + function SquigglyAnnotation(parameters) { + Annotation.call(this, parameters); + this.data.annotationType = _util.AnnotationType.SQUIGGLY; + this._preparePopup(parameters.dict); + } + + _util.Util.inherit(SquigglyAnnotation, Annotation, {}); + return SquigglyAnnotation; + }(); + var StrikeOutAnnotation = function StrikeOutAnnotationClosure() { + function StrikeOutAnnotation(parameters) { + Annotation.call(this, parameters); + this.data.annotationType = _util.AnnotationType.STRIKEOUT; + this._preparePopup(parameters.dict); + } + + _util.Util.inherit(StrikeOutAnnotation, Annotation, {}); + return StrikeOutAnnotation; + }(); + var FileAttachmentAnnotation = function FileAttachmentAnnotationClosure() { + function FileAttachmentAnnotation(parameters) { + Annotation.call(this, parameters); + var file = new _obj.FileSpec(parameters.dict.get('FS'), parameters.xref); + this.data.annotationType = _util.AnnotationType.FILEATTACHMENT; + this.data.file = file.serializable; + this._preparePopup(parameters.dict); + } + + _util.Util.inherit(FileAttachmentAnnotation, Annotation, {}); + return FileAttachmentAnnotation; + }(); + exports.Annotation = Annotation; + exports.AnnotationBorderStyle = AnnotationBorderStyle; + exports.AnnotationFactory = AnnotationFactory; + + /***/ + }), + /* 20 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.bidi = undefined; + + var _util = __w_pdfjs_require__(0); + + 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) { + return { + str: str, + dir: vertical ? 'ttb' : isLTR ? 'ltr' : 'rtl' + }; + } + + 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); + } + + exports.bidi = bidi; + + /***/ + }), + /* 21 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + var 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']; + var 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']; + var ExpertSubsetCharset = ['.notdef', 'space', 'dollaroldstyle', 'dollarsuperior', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', 'parenrightinferior', 'hyphensuperior', 'colonmonetary', 'onefitted', 'rupiah', 'centoldstyle', 'figuredash', 'hypheninferior', 'onequarter', 'onehalf', 'threequarters', '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']; + exports.ISOAdobeCharset = ISOAdobeCharset; + exports.ExpertCharset = ExpertCharset; + exports.ExpertSubsetCharset = ExpertSubsetCharset; + + /***/ + }), + /* 22 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.CMapFactory = exports.IdentityCMap = exports.CMap = undefined; + + var _util = __w_pdfjs_require__(0); + + var _primitives = __w_pdfjs_require__(1); + + var _parser = __w_pdfjs_require__(5); + + var _stream = __w_pdfjs_require__(2); + + 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 CMap = function CMapClosure() { + function CMap(builtInCMap) { + this.codespaceRanges = [[], [], [], []]; + this.numCodespaceRanges = 0; + this._map = []; + this.name = ''; + this.vertical = false; + this.useCMap = null; + this.builtInCMap = builtInCMap; + } + + CMap.prototype = { + addCodespaceRange: function addCodespaceRange(n, low, high) { + this.codespaceRanges[n - 1].push(low, high); + this.numCodespaceRanges++; + }, + mapCidRange: function mapCidRange(low, high, dstLow) { + while (low <= high) { + this._map[low++] = dstLow++; + } + }, + mapBfRange: function mapBfRange(low, high, dstLow) { + var lastByte = dstLow.length - 1; + while (low <= high) { + this._map[low++] = dstLow; + dstLow = dstLow.substr(0, lastByte) + String.fromCharCode(dstLow.charCodeAt(lastByte) + 1); + } + }, + mapBfRangeToArray: function mapBfRangeToArray(low, high, array) { + var i = 0, + ii = array.length; + while (low <= high && i < ii) { + this._map[low] = array[i++]; + ++low; + } + }, + mapOne: function mapOne(src, dst) { + this._map[src] = dst; + }, + lookup: function lookup(code) { + return this._map[code]; + }, + contains: function contains(code) { + return this._map[code] !== undefined; + }, + forEach: function forEach(callback) { + var map = this._map; + var length = map.length; + if (length <= 0x10000) { + for (var i = 0; i < length; i++) { + if (map[i] !== undefined) { + callback(i, map[i]); + } + } + } else { + for (var _i in map) { + callback(_i, map[_i]); + } + } + }, + charCodeOf: function charCodeOf(value) { + var map = this._map; + if (map.length <= 0x10000) { + return map.indexOf(value); + } + for (var charCode in map) { + if (map[charCode] === value) { + return charCode | 0; + } + } + return -1; + }, + getMap: function getMap() { + return this._map; + }, + readCharCode: function readCharCode(str, offset, out) { + var c = 0; + var codespaceRanges = this.codespaceRanges; + var codespaceRangesLen = this.codespaceRanges.length; + for (var n = 0; n < codespaceRangesLen; n++) { + c = (c << 8 | str.charCodeAt(offset + n)) >>> 0; + var codespaceRange = codespaceRanges[n]; + for (var k = 0, kk = codespaceRange.length; k < kk;) { + var low = codespaceRange[k++]; + var high = codespaceRange[k++]; + if (c >= low && c <= high) { + out.charcode = c; + out.length = n + 1; + return; + } + } + } + out.charcode = 0; + out.length = 1; + }, + + get length() { + return this._map.length; + }, + get isIdentityCMap() { + if (!(this.name === 'Identity-H' || this.name === 'Identity-V')) { + return false; + } + if (this._map.length !== 0x10000) { + return false; + } + for (var i = 0; i < 0x10000; i++) { + if (this._map[i] !== i) { + return false; + } + } + return true; + } + }; + return CMap; + }(); + var IdentityCMap = function IdentityCMapClosure() { + function IdentityCMap(vertical, n) { + CMap.call(this); + this.vertical = vertical; + this.addCodespaceRange(n, 0, 0xffff); + } + + _util.Util.inherit(IdentityCMap, CMap, {}); + IdentityCMap.prototype = { + addCodespaceRange: CMap.prototype.addCodespaceRange, + mapCidRange: function mapCidRange(low, high, dstLow) { + throw new Error('should not call mapCidRange'); + }, + mapBfRange: function mapBfRange(low, high, dstLow) { + throw new Error('should not call mapBfRange'); + }, + mapBfRangeToArray: function mapBfRangeToArray(low, high, array) { + throw new Error('should not call mapBfRangeToArray'); + }, + mapOne: function mapOne(src, dst) { + throw new Error('should not call mapCidOne'); + }, + lookup: function lookup(code) { + return (0, _util.isInt)(code) && code <= 0xffff ? code : undefined; + }, + contains: function contains(code) { + return (0, _util.isInt)(code) && code <= 0xffff; + }, + forEach: function forEach(callback) { + for (var i = 0; i <= 0xffff; i++) { + callback(i, i); + } + }, + charCodeOf: function charCodeOf(value) { + return (0, _util.isInt)(value) && value <= 0xffff ? value : -1; + }, + getMap: function getMap() { + var map = new Array(0x10000); + for (var i = 0; i <= 0xffff; i++) { + map[i] = i; + } + return map; + }, + + readCharCode: CMap.prototype.readCharCode, + get length() { + return 0x10000; + }, + get isIdentityCMap() { + throw new Error('should not access .isIdentityCMap'); + } + }; + return IdentityCMap; + }(); + var BinaryCMapReader = function BinaryCMapReaderClosure() { + function hexToInt(a, size) { + var n = 0; + for (var i = 0; i <= size; i++) { + n = n << 8 | a[i]; + } + return n >>> 0; + } + + function hexToStr(a, size) { + if (size === 1) { + return String.fromCharCode(a[0], a[1]); + } + if (size === 3) { + return String.fromCharCode(a[0], a[1], a[2], a[3]); + } + return String.fromCharCode.apply(null, a.subarray(0, size + 1)); + } + + function addHex(a, b, size) { + var c = 0; + for (var i = size; i >= 0; i--) { + c += a[i] + b[i]; + a[i] = c & 255; + c >>= 8; + } + } + + function incHex(a, size) { + var c = 1; + for (var 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; + + function BinaryCMapStream(data) { + this.buffer = data; + this.pos = 0; + this.end = data.length; + this.tmpBuf = new Uint8Array(MAX_ENCODED_NUM_SIZE); + } + + BinaryCMapStream.prototype = { + readByte: function readByte() { + if (this.pos >= this.end) { + return -1; + } + return this.buffer[this.pos++]; + }, + readNumber: function readNumber() { + var n = 0; + var last; + do { + var b = this.readByte(); + if (b < 0) { + throw new _util.FormatError('unexpected EOF in bcmap'); + } + last = !(b & 0x80); + n = n << 7 | b & 0x7F; + } while (!last); + return n; + }, + readSigned: function readSigned() { + var n = this.readNumber(); + return n & 1 ? ~(n >>> 1) : n >>> 1; + }, + readHex: function readHex(num, size) { + num.set(this.buffer.subarray(this.pos, this.pos + size + 1)); + this.pos += size + 1; + }, + readHexNumber: function readHexNumber(num, size) { + var last; + var stack = this.tmpBuf, + sp = 0; + do { + var b = this.readByte(); + if (b < 0) { + throw new _util.FormatError('unexpected EOF in bcmap'); + } + last = !(b & 0x80); + stack[sp++] = b & 0x7F; + } while (!last); + var i = size, + buffer = 0, + bufferSize = 0; + while (i >= 0) { + while (bufferSize < 8 && stack.length > 0) { + buffer = stack[--sp] << bufferSize | buffer; + bufferSize += 7; + } + num[i] = buffer & 255; + i--; + buffer >>= 8; + bufferSize -= 8; + } + }, + readHexSigned: function readHexSigned(num, size) { + this.readHexNumber(num, size); + var sign = num[size] & 1 ? 255 : 0; + var c = 0; + for (var i = 0; i <= size; i++) { + c = (c & 1) << 8 | num[i]; + num[i] = c >> 1 ^ sign; + } + }, + readString: function readString() { + var len = this.readNumber(); + var s = ''; + for (var 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(); + 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; + while ((b = stream.readByte()) >= 0) { + var type = b >> 5; + if (type === 7) { + switch (b & 0x1F) { + case 0: + stream.readString(); + break; + case 1: + useCMap = stream.readString(); + break; + } + continue; + } + var sequence = !!(b & 0x10); + var dataSize = b & 15; + if (dataSize + 1 > MAX_NUM_SIZE) { + throw new Error('processBinaryCMap: Invalid dataSize.'); + } + var ucs2DataSize = 1; + var subitemsCount = stream.readNumber(); + var i; + switch (type) { + case 0: + stream.readHex(start, dataSize); + stream.readHexNumber(end, dataSize); + addHex(end, start, dataSize); + cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize), hexToInt(end, dataSize)); + for (i = 1; i < subitemsCount; i++) { + incHex(end, dataSize); + stream.readHexNumber(start, dataSize); + addHex(start, end, dataSize); + stream.readHexNumber(end, dataSize); + addHex(end, start, dataSize); + cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize), hexToInt(end, dataSize)); + } + break; + case 1: + stream.readHex(start, dataSize); + stream.readHexNumber(end, dataSize); + addHex(end, start, dataSize); + code = stream.readNumber(); + for (i = 1; i < subitemsCount; i++) { + incHex(end, dataSize); + stream.readHexNumber(start, dataSize); + addHex(start, end, dataSize); + stream.readHexNumber(end, dataSize); + addHex(end, start, dataSize); + code = stream.readNumber(); + } + break; + case 2: + stream.readHex(char, dataSize); + code = stream.readNumber(); + cMap.mapOne(hexToInt(char, dataSize), code); + for (i = 1; i < subitemsCount; i++) { + incHex(char, dataSize); + if (!sequence) { + stream.readHexNumber(tmp, dataSize); + addHex(char, tmp, dataSize); + } + code = stream.readSigned() + (code + 1); + cMap.mapOne(hexToInt(char, dataSize), code); + } + break; + case 3: + stream.readHex(start, dataSize); + stream.readHexNumber(end, dataSize); + addHex(end, start, dataSize); + code = stream.readNumber(); + cMap.mapCidRange(hexToInt(start, dataSize), hexToInt(end, dataSize), code); + for (i = 1; i < subitemsCount; i++) { + incHex(end, dataSize); + if (!sequence) { + stream.readHexNumber(start, dataSize); + addHex(start, end, dataSize); + } else { + start.set(end); + } + stream.readHexNumber(end, dataSize); + addHex(end, start, dataSize); + code = stream.readNumber(); + cMap.mapCidRange(hexToInt(start, dataSize), hexToInt(end, dataSize), code); + } + break; + case 4: + stream.readHex(char, ucs2DataSize); + stream.readHex(charCode, dataSize); + cMap.mapOne(hexToInt(char, ucs2DataSize), hexToStr(charCode, dataSize)); + for (i = 1; i < subitemsCount; i++) { + incHex(char, ucs2DataSize); + if (!sequence) { + stream.readHexNumber(tmp, ucs2DataSize); + addHex(char, tmp, ucs2DataSize); + } + incHex(charCode, dataSize); + stream.readHexSigned(tmp, dataSize); + addHex(charCode, tmp, dataSize); + cMap.mapOne(hexToInt(char, ucs2DataSize), hexToStr(charCode, dataSize)); + } + break; + case 5: + stream.readHex(start, ucs2DataSize); + stream.readHexNumber(end, ucs2DataSize); + addHex(end, start, ucs2DataSize); + stream.readHex(charCode, dataSize); + cMap.mapBfRange(hexToInt(start, ucs2DataSize), hexToInt(end, ucs2DataSize), hexToStr(charCode, dataSize)); + for (i = 1; i < subitemsCount; i++) { + incHex(end, ucs2DataSize); + if (!sequence) { + stream.readHexNumber(start, ucs2DataSize); + addHex(start, end, ucs2DataSize); + } else { + start.set(end); + } + stream.readHexNumber(end, ucs2DataSize); + addHex(end, start, ucs2DataSize); + stream.readHex(charCode, dataSize); + cMap.mapBfRange(hexToInt(start, ucs2DataSize), hexToInt(end, ucs2DataSize), hexToStr(charCode, dataSize)); + } + break; + default: + reject(new Error('processBinaryCMap: Unknown type: ' + type)); + return; + } + } + if (useCMap) { + resolve(extend(useCMap)); + return; + } + resolve(cMap); + }); + } + + function BinaryCMapReader() { + } + + BinaryCMapReader.prototype = {process: processBinaryCMap}; + return BinaryCMapReader; + }(); + var CMapFactory = function CMapFactoryClosure() { + function strToInt(str) { + var a = 0; + for (var i = 0; i < str.length; i++) { + a = a << 8 | str.charCodeAt(i); + } + return a >>> 0; + } + + function expectString(obj) { + if (!(0, _util.isString)(obj)) { + throw new _util.FormatError('Malformed CMap: expected string.'); + } + } + + function expectInt(obj) { + if (!(0, _util.isInt)(obj)) { + throw new _util.FormatError('Malformed CMap: expected int.'); + } + } + + function parseBfChar(cMap, lexer) { + while (true) { + var obj = lexer.getObj(); + if ((0, _primitives.isEOF)(obj)) { + break; + } + if ((0, _primitives.isCmd)(obj, 'endbfchar')) { + return; + } + expectString(obj); + var src = strToInt(obj); + obj = lexer.getObj(); + expectString(obj); + var dst = obj; + cMap.mapOne(src, dst); + } + } + + function parseBfRange(cMap, lexer) { + while (true) { + var obj = lexer.getObj(); + if ((0, _primitives.isEOF)(obj)) { + break; + } + if ((0, _primitives.isCmd)(obj, 'endbfrange')) { + return; + } + expectString(obj); + var low = strToInt(obj); + obj = lexer.getObj(); + expectString(obj); + var high = strToInt(obj); + obj = lexer.getObj(); + if ((0, _util.isInt)(obj) || (0, _util.isString)(obj)) { + var dstLow = (0, _util.isInt)(obj) ? String.fromCharCode(obj) : obj; + cMap.mapBfRange(low, high, dstLow); + } else if ((0, _primitives.isCmd)(obj, '[')) { + obj = lexer.getObj(); + var array = []; + while (!(0, _primitives.isCmd)(obj, ']') && !(0, _primitives.isEOF)(obj)) { + array.push(obj); + obj = lexer.getObj(); + } + cMap.mapBfRangeToArray(low, high, array); + } else { + break; + } + } + throw new _util.FormatError('Invalid bf range.'); + } + + function parseCidChar(cMap, lexer) { + while (true) { + var obj = lexer.getObj(); + if ((0, _primitives.isEOF)(obj)) { + break; + } + if ((0, _primitives.isCmd)(obj, 'endcidchar')) { + return; + } + expectString(obj); + var src = strToInt(obj); + obj = lexer.getObj(); + expectInt(obj); + var dst = obj; + cMap.mapOne(src, dst); + } + } + + function parseCidRange(cMap, lexer) { + while (true) { + var obj = lexer.getObj(); + if ((0, _primitives.isEOF)(obj)) { + break; + } + if ((0, _primitives.isCmd)(obj, 'endcidrange')) { + return; + } + expectString(obj); + var low = strToInt(obj); + obj = lexer.getObj(); + expectString(obj); + var high = strToInt(obj); + obj = lexer.getObj(); + expectInt(obj); + var dstLow = obj; + cMap.mapCidRange(low, high, dstLow); + } + } + + function parseCodespaceRange(cMap, lexer) { + while (true) { + var obj = lexer.getObj(); + if ((0, _primitives.isEOF)(obj)) { + break; + } + if ((0, _primitives.isCmd)(obj, 'endcodespacerange')) { + return; + } + if (!(0, _util.isString)(obj)) { + break; + } + var low = strToInt(obj); + obj = lexer.getObj(); + if (!(0, _util.isString)(obj)) { + break; + } + var high = strToInt(obj); + cMap.addCodespaceRange(obj.length, low, high); + } + throw new _util.FormatError('Invalid codespace range.'); + } + + function parseWMode(cMap, lexer) { + var obj = lexer.getObj(); + if ((0, _util.isInt)(obj)) { + cMap.vertical = !!obj; + } + } + + function parseCMapName(cMap, lexer) { + var obj = lexer.getObj(); + if ((0, _primitives.isName)(obj) && (0, _util.isString)(obj.name)) { + cMap.name = obj.name; + } + } + + function parseCMap(cMap, lexer, fetchBuiltInCMap, useCMap) { + var previous; + var embededUseCMap; + objLoop: while (true) { + try { + var obj = lexer.getObj(); + if ((0, _primitives.isEOF)(obj)) { + break; + } else if ((0, _primitives.isName)(obj)) { + if (obj.name === 'WMode') { + parseWMode(cMap, lexer); + } else if (obj.name === 'CMapName') { + parseCMapName(cMap, lexer); + } + previous = obj; + } else if ((0, _primitives.isCmd)(obj)) { + switch (obj.cmd) { + case 'endcmap': + break objLoop; + case 'usecmap': + if ((0, _primitives.isName)(previous)) { + embededUseCMap = previous.name; + } + break; + case 'begincodespacerange': + parseCodespaceRange(cMap, lexer); + break; + case 'beginbfchar': + parseBfChar(cMap, lexer); + break; + case 'begincidchar': + parseCidChar(cMap, lexer); + break; + case 'beginbfrange': + parseBfRange(cMap, lexer); + break; + case 'begincidrange': + parseCidRange(cMap, lexer); + break; + } + } + } catch (ex) { + if (ex instanceof _util.MissingDataException) { + throw ex; + } + (0, _util.warn)('Invalid cMap data: ' + ex); + continue; + } + } + if (!useCMap && embededUseCMap) { + useCMap = embededUseCMap; + } + if (useCMap) { + return extendCMap(cMap, fetchBuiltInCMap, useCMap); + } + return Promise.resolve(cMap); + } + + function extendCMap(cMap, fetchBuiltInCMap, useCMap) { + return createBuiltInCMap(useCMap, fetchBuiltInCMap).then(function (newCMap) { + cMap.useCMap = newCMap; + if (cMap.numCodespaceRanges === 0) { + var useCodespaceRanges = cMap.useCMap.codespaceRanges; + for (var i = 0; i < useCodespaceRanges.length; i++) { + cMap.codespaceRanges[i] = useCodespaceRanges[i].slice(); + } + 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) { + if (name === 'Identity-H') { + return Promise.resolve(new IdentityCMap(false, 2)); + } else if (name === 'Identity-V') { + return Promise.resolve(new IdentityCMap(true, 2)); + } + if (BUILT_IN_CMAPS.indexOf(name) === -1) { + return Promise.reject(new Error('Unknown CMap name: ' + name)); + } + if (!fetchBuiltInCMap) { + return Promise.reject(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); + if (compressionType === _util.CMapCompressionType.BINARY) { + return new BinaryCMapReader().process(cMapData, cMap, function (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); + } + return Promise.reject(new Error('TODO: Only BINARY/NONE CMap compression is currently supported.')); + }); + } + + return { + create: function create(params) { + var encoding = params.encoding; + var fetchBuiltInCMap = params.fetchBuiltInCMap; + var useCMap = params.useCMap; + if ((0, _primitives.isName)(encoding)) { + 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); + } + return parsedCMap; + }); + } + return Promise.reject(new Error('Encoding required.')); + } + }; + }(); + exports.CMap = CMap; + exports.IdentityCMap = IdentityCMap; + exports.CMapFactory = CMapFactory; + + /***/ + }), + /* 23 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFDocument = exports.Page = undefined; + + var _slicedToArray = function () { + function sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"]) _i["return"](); + } finally { + if (_d) throw _e; + } + } + return _arr; + } + + return function (arr, i) { + if (Array.isArray(arr)) { + return arr; + } else if (Symbol.iterator in Object(arr)) { + return sliceIterator(arr, i); + } else { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + }; + }(); + + var _obj = __w_pdfjs_require__(15); + + var _primitives = __w_pdfjs_require__(1); + + var _util = __w_pdfjs_require__(0); + + var _stream = __w_pdfjs_require__(2); + + var _evaluator = __w_pdfjs_require__(13); + + var _annotation = __w_pdfjs_require__(19); + + var _crypto = __w_pdfjs_require__(12); + + var _parser = __w_pdfjs_require__(5); + + var Page = function PageClosure() { + var DEFAULT_USER_UNIT = 1.0; + var LETTER_SIZE_MEDIABOX = [0, 0, 612, 792]; + + function isAnnotationRenderable(annotation, intent) { + return intent === 'display' && annotation.viewable || intent === 'print' && annotation.printable; + } + + function Page(pdfManager, xref, pageIndex, pageDict, ref, fontCache, builtInCMapCache) { + this.pdfManager = pdfManager; + this.pageIndex = pageIndex; + this.pageDict = pageDict; + this.xref = xref; + this.ref = ref; + this.fontCache = fontCache; + this.builtInCMapCache = builtInCMapCache; + this.evaluatorOptions = pdfManager.evaluatorOptions; + this.resourcesPromise = null; + var uniquePrefix = 'p' + this.pageIndex + '_'; + var idCounters = {obj: 0}; + this.idFactory = { + createObjId: function createObjId() { + return uniquePrefix + ++idCounters.obj; + } + }; + } + + Page.prototype = { + getPageProp: function Page_getPageProp(key) { + return this.pageDict.get(key); + }, + getInheritedPageProp: function Page_getInheritedPageProp(key, getArray) { + var dict = this.pageDict, + valueArray = null, + loopCount = 0; + var MAX_LOOP_COUNT = 100; + getArray = getArray || false; + while (dict) { + var value = getArray ? dict.getArray(key) : dict.get(key); + if (value !== undefined) { + if (!valueArray) { + valueArray = []; + } + valueArray.push(value); + } + if (++loopCount > MAX_LOOP_COUNT) { + (0, _util.warn)('getInheritedPageProp: maximum loop count exceeded for ' + key); + return valueArray ? valueArray[0] : undefined; + } + dict = dict.get('Parent'); + } + if (!valueArray) { + return undefined; + } + if (valueArray.length === 1 || !(0, _primitives.isDict)(valueArray[0])) { + return valueArray[0]; + } + return _primitives.Dict.merge(this.xref, valueArray); + }, + get content() { + return this.getPageProp('Contents'); + }, + get resources() { + return (0, _util.shadow)(this, 'resources', this.getInheritedPageProp('Resources') || _primitives.Dict.empty); + }, + get mediaBox() { + var mediaBox = this.getInheritedPageProp('MediaBox', true); + if (!(0, _util.isArray)(mediaBox) || mediaBox.length !== 4) { + return (0, _util.shadow)(this, 'mediaBox', LETTER_SIZE_MEDIABOX); + } + return (0, _util.shadow)(this, 'mediaBox', mediaBox); + }, + get cropBox() { + var cropBox = this.getInheritedPageProp('CropBox', true); + if (!(0, _util.isArray)(cropBox) || cropBox.length !== 4) { + return (0, _util.shadow)(this, 'cropBox', this.mediaBox); + } + return (0, _util.shadow)(this, 'cropBox', cropBox); + }, + get userUnit() { + var obj = this.getPageProp('UserUnit'); + if (!(0, _util.isNum)(obj) || obj <= 0) { + obj = DEFAULT_USER_UNIT; + } + return (0, _util.shadow)(this, 'userUnit', obj); + }, + get view() { + var mediaBox = this.mediaBox, + cropBox = this.cropBox; + if (mediaBox === cropBox) { + return (0, _util.shadow)(this, 'view', mediaBox); + } + var intersection = _util.Util.intersect(cropBox, mediaBox); + return (0, _util.shadow)(this, 'view', intersection || mediaBox); + }, + get rotate() { + var rotate = this.getInheritedPageProp('Rotate') || 0; + if (rotate % 90 !== 0) { + rotate = 0; + } else if (rotate >= 360) { + rotate = rotate % 360; + } else if (rotate < 0) { + rotate = (rotate % 360 + 360) % 360; + } + return (0, _util.shadow)(this, 'rotate', rotate); + }, + getContentStream: function Page_getContentStream() { + var content = this.content; + var stream; + if ((0, _util.isArray)(content)) { + var xref = this.xref; + var i, + n = content.length; + var streams = []; + for (i = 0; i < n; ++i) { + streams.push(xref.fetchIfRef(content[i])); + } + stream = new _stream.StreamsSequenceStream(streams); + } else if ((0, _primitives.isStream)(content)) { + stream = content; + } else { + stream = new _stream.NullStream(); + } + return stream; + }, + loadResources: function Page_loadResources(keys) { + var _this = this; + + if (!this.resourcesPromise) { + this.resourcesPromise = this.pdfManager.ensure(this, 'resources'); + } + return this.resourcesPromise.then(function () { + var objectLoader = new _obj.ObjectLoader(_this.resources, keys, _this.xref); + return objectLoader.load(); + }); + }, + getOperatorList: function getOperatorList(_ref) { + var _this2 = this; + + var handler = _ref.handler, + task = _ref.task, + intent = _ref.intent, + renderInteractiveForms = _ref.renderInteractiveForms; + + var contentStreamPromise = this.pdfManager.ensure(this, 'getContentStream'); + var resourcesPromise = this.loadResources(['ExtGState', 'ColorSpace', 'Pattern', 'Shading', 'XObject', 'Font']); + var partialEvaluator = new _evaluator.PartialEvaluator({ + pdfManager: this.pdfManager, + xref: this.xref, + handler: handler, + pageIndex: this.pageIndex, + idFactory: this.idFactory, + fontCache: this.fontCache, + builtInCMapCache: this.builtInCMapCache, + options: this.evaluatorOptions + }); + var dataPromises = Promise.all([contentStreamPromise, resourcesPromise]); + var pageListPromise = dataPromises.then(function (_ref2) { + var _ref3 = _slicedToArray(_ref2, 1), + contentStream = _ref3[0]; + + var opList = new _evaluator.OperatorList(intent, handler, _this2.pageIndex); + handler.send('StartRenderPage', { + transparency: partialEvaluator.hasBlendModes(_this2.resources), + pageIndex: _this2.pageIndex, + intent: intent + }); + return partialEvaluator.getOperatorList({ + stream: contentStream, + task: task, + resources: _this2.resources, + operatorList: opList + }).then(function () { + return opList; + }); + }); + var annotationsPromise = this.pdfManager.ensure(this, 'annotations'); + return Promise.all([pageListPromise, annotationsPromise]).then(function (_ref4) { + var _ref5 = _slicedToArray(_ref4, 2), + pageOpList = _ref5[0], + annotations = _ref5[1]; + + if (annotations.length === 0) { + pageOpList.flush(true); + return pageOpList; + } + var i, + ii, + opListPromises = []; + for (i = 0, ii = annotations.length; i < ii; i++) { + if (isAnnotationRenderable(annotations[i], intent)) { + opListPromises.push(annotations[i].getOperatorList(partialEvaluator, task, renderInteractiveForms)); + } + } + return Promise.all(opListPromises).then(function (opLists) { + pageOpList.addOp(_util.OPS.beginAnnotations, []); + for (i = 0, ii = opLists.length; i < ii; i++) { + pageOpList.addOpList(opLists[i]); + } + pageOpList.addOp(_util.OPS.endAnnotations, []); + pageOpList.flush(true); + return pageOpList; + }); + }); + }, + extractTextContent: function extractTextContent(_ref6) { + var _this3 = this; + + var handler = _ref6.handler, + task = _ref6.task, + normalizeWhitespace = _ref6.normalizeWhitespace, + sink = _ref6.sink, + combineTextItems = _ref6.combineTextItems; + + var contentStreamPromise = this.pdfManager.ensure(this, 'getContentStream'); + var resourcesPromise = this.loadResources(['ExtGState', 'XObject', 'Font']); + var dataPromises = Promise.all([contentStreamPromise, resourcesPromise]); + return dataPromises.then(function (_ref7) { + var _ref8 = _slicedToArray(_ref7, 1), + contentStream = _ref8[0]; + + var partialEvaluator = new _evaluator.PartialEvaluator({ + pdfManager: _this3.pdfManager, + xref: _this3.xref, + handler: handler, + pageIndex: _this3.pageIndex, + idFactory: _this3.idFactory, + fontCache: _this3.fontCache, + builtInCMapCache: _this3.builtInCMapCache, + options: _this3.evaluatorOptions + }); + return partialEvaluator.getTextContent({ + stream: contentStream, + task: task, + resources: _this3.resources, + normalizeWhitespace: normalizeWhitespace, + combineTextItems: combineTextItems, + sink: sink + }); + }); + }, + + getAnnotationsData: function Page_getAnnotationsData(intent) { + var annotations = this.annotations; + var annotationsData = []; + for (var i = 0, n = annotations.length; i < n; ++i) { + if (!intent || isAnnotationRenderable(annotations[i], intent)) { + annotationsData.push(annotations[i].data); + } + } + return annotationsData; + }, + get annotations() { + var annotations = []; + var annotationRefs = this.getInheritedPageProp('Annots') || []; + var annotationFactory = new _annotation.AnnotationFactory(); + for (var i = 0, n = annotationRefs.length; i < n; ++i) { + var annotationRef = annotationRefs[i]; + var annotation = annotationFactory.create(this.xref, annotationRef, this.pdfManager, this.idFactory); + if (annotation) { + annotations.push(annotation); + } + } + return (0, _util.shadow)(this, 'annotations', annotations); + } + }; + return Page; + }(); + var PDFDocument = function PDFDocumentClosure() { + var FINGERPRINT_FIRST_BYTES = 1024; + var EMPTY_FINGERPRINT = '\x00\x00\x00\x00\x00\x00\x00' + '\x00\x00\x00\x00\x00\x00\x00\x00\x00'; + + function PDFDocument(pdfManager, arg) { + var 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'); + } + if (stream.length <= 0) { + throw new Error('PDFDocument: stream must have data'); + } + this.pdfManager = pdfManager; + this.stream = stream; + this.xref = new _obj.XRef(stream, pdfManager); + } + + function find(stream, needle, limit, backwards) { + var pos = stream.pos; + var end = stream.end; + var strBuf = []; + if (pos + limit > end) { + limit = end - pos; + } + for (var n = 0; n < limit; ++n) { + strBuf.push(String.fromCharCode(stream.getByte())); + } + var str = strBuf.join(''); + stream.pos = pos; + var index = backwards ? str.lastIndexOf(needle) : str.indexOf(needle); + if (index === -1) { + return false; + } + stream.pos += index; + return true; + } + + var DocumentInfoValidators = { + get entries() { + return (0, _util.shadow)(this, 'entries', { + 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 + }); + } + }; + PDFDocument.prototype = { + parse: function PDFDocument_parse(recoveryMode) { + this.setup(recoveryMode); + var version = this.catalog.catDict.get('Version'); + if ((0, _primitives.isName)(version)) { + this.pdfFormatVersion = version.name; + } + try { + this.acroForm = this.catalog.catDict.get('AcroForm'); + if (this.acroForm) { + this.xfa = this.acroForm.get('XFA'); + var fields = this.acroForm.get('Fields'); + if ((!fields || !(0, _util.isArray)(fields) || fields.length === 0) && !this.xfa) { + this.acroForm = null; + } + } + } catch (ex) { + if (ex instanceof _util.MissingDataException) { + throw ex; + } + (0, _util.info)('Something wrong with AcroForm entry'); + this.acroForm = null; + } + }, + get linearization() { + var linearization = null; + if (this.stream.length) { + try { + linearization = _parser.Linearization.create(this.stream); + } catch (err) { + if (err instanceof _util.MissingDataException) { + throw err; + } + (0, _util.info)(err); + } + } + return (0, _util.shadow)(this, 'linearization', linearization); + }, + get startXRef() { + var stream = this.stream; + var startXRef = 0; + var linearization = this.linearization; + if (linearization) { + stream.reset(); + if (find(stream, 'endobj', 1024)) { + startXRef = stream.pos + 6; + } + } else { + var step = 1024; + var found = false, + pos = stream.end; + while (!found && pos > 0) { + pos -= step - 'startxref'.length; + if (pos < 0) { + pos = 0; + } + stream.pos = pos; + found = find(stream, 'startxref', step, true); + } + if (found) { + stream.skip(9); + var ch; + do { + ch = stream.getByte(); + } while ((0, _util.isSpace)(ch)); + var str = ''; + while (ch >= 0x20 && ch <= 0x39) { + str += String.fromCharCode(ch); + ch = stream.getByte(); + } + startXRef = parseInt(str, 10); + if (isNaN(startXRef)) { + startXRef = 0; + } + } + } + return (0, _util.shadow)(this, 'startXRef', startXRef); + }, + get mainXRefEntriesOffset() { + var mainXRefEntriesOffset = 0; + var linearization = this.linearization; + if (linearization) { + mainXRefEntriesOffset = linearization.mainXRefEntriesOffset; + } + return (0, _util.shadow)(this, 'mainXRefEntriesOffset', mainXRefEntriesOffset); + }, + checkHeader: function PDFDocument_checkHeader() { + var stream = this.stream; + stream.reset(); + if (find(stream, '%PDF-', 1024)) { + stream.moveStart(); + var MAX_VERSION_LENGTH = 12; + var version = '', + ch; + while ((ch = stream.getByte()) > 0x20) { + if (version.length >= MAX_VERSION_LENGTH) { + break; + } + version += String.fromCharCode(ch); + } + if (!this.pdfFormatVersion) { + this.pdfFormatVersion = version.substring(5); + } + return; + } + }, + parseStartXRef: function PDFDocument_parseStartXRef() { + var startXRef = this.startXRef; + this.xref.setStartXRef(startXRef); + }, + setup: function PDFDocument_setup(recoveryMode) { + var _this4 = this; + + this.xref.parse(recoveryMode); + var pageFactory = { + createPage: function createPage(pageIndex, dict, ref, fontCache, builtInCMapCache) { + return new Page(_this4.pdfManager, _this4.xref, pageIndex, dict, ref, fontCache, builtInCMapCache); + } + }; + this.catalog = new _obj.Catalog(this.pdfManager, this.xref, pageFactory); + }, + get numPages() { + var linearization = this.linearization; + var num = linearization ? linearization.numPages : this.catalog.numPages; + return (0, _util.shadow)(this, 'numPages', num); + }, + get documentInfo() { + var docInfo = { + PDFFormatVersion: this.pdfFormatVersion, + IsAcroFormPresent: !!this.acroForm, + IsXFAPresent: !!this.xfa + }; + var infoDict; + try { + infoDict = this.xref.trailer.get('Info'); + } catch (err) { + if (err instanceof _util.MissingDataException) { + throw err; + } + (0, _util.info)('The document information dictionary is invalid.'); + } + if (infoDict) { + var validEntries = DocumentInfoValidators.entries; + for (var key in validEntries) { + if (infoDict.has(key)) { + var value = infoDict.get(key); + if (validEntries[key](value)) { + docInfo[key] = typeof value !== 'string' ? value : (0, _util.stringToPDFString)(value); + } else { + (0, _util.info)('Bad value in document info for "' + key + '"'); + } + } + } + } + return (0, _util.shadow)(this, 'documentInfo', docInfo); + }, + get fingerprint() { + var xref = this.xref, + hash, + fileID = ''; + var idArray = xref.trailer.get('ID'); + if (idArray && (0, _util.isArray)(idArray) && idArray[0] && (0, _util.isString)(idArray[0]) && idArray[0] !== EMPTY_FINGERPRINT) { + hash = (0, _util.stringToBytes)(idArray[0]); + } else { + if (this.stream.ensureRange) { + this.stream.ensureRange(0, Math.min(FINGERPRINT_FIRST_BYTES, this.stream.end)); + } + hash = (0, _crypto.calculateMD5)(this.stream.bytes.subarray(0, FINGERPRINT_FIRST_BYTES), 0, FINGERPRINT_FIRST_BYTES); + } + for (var i = 0, n = hash.length; i < n; i++) { + var hex = hash[i].toString(16); + fileID += hex.length === 1 ? '0' + hex : hex; + } + return (0, _util.shadow)(this, 'fingerprint', fileID); + }, + getPage: function PDFDocument_getPage(pageIndex) { + return this.catalog.getPage(pageIndex); + }, + cleanup: function PDFDocument_cleanup() { + return this.catalog.cleanup(); + } + }; + return PDFDocument; + }(); + exports.Page = Page; + exports.PDFDocument = PDFDocument; + + /***/ + }), + /* 24 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.FontRendererFactory = undefined; + + var _util = __w_pdfjs_require__(0); + + var _cff_parser = __w_pdfjs_require__(10); + + var _glyphlist = __w_pdfjs_require__(6); + + var _encodings = __w_pdfjs_require__(4); + + var _stream = __w_pdfjs_require__(2); + + var FontRendererFactory = function FontRendererFactoryClosure() { + function getLong(data, offset) { + return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]; + } + + function getUshort(data, offset) { + return data[offset] << 8 | data[offset + 1]; + } + + 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 + }; + } + + 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]; + }; + } else { + itemSize = 2; + itemDecode = function fontItemDecode(data, offset) { + return data[offset] << 9 | data[offset + 1] << 1; + }; + } + 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.charCodeAt(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 + }; + } + + function compileGlyf(code, cmds, font) { + function moveTo(x, y) { + cmds.push({ + cmd: 'moveTo', + args: [x, y] + }); + } + + function lineTo(x, y) { + cmds.push({ + cmd: 'lineTo', + args: [x, y] + }); + } + + function quadraticCurveTo(xa, ya, x, y) { + cmds.push({ + cmd: 'quadraticCurveTo', + args: [xa, ya, x, y] + }); + } + + var i = 0; + var numberOfContours = (code[i] << 24 | code[i + 1] << 16) >> 16; + var flags; + var x = 0, + y = 0; + i += 10; + 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 { + arg1 = code[i++]; + arg2 = code[i++]; + } + if (flags & 0x02) { + x = arg1; + y = arg2; + } else { + x = 0; + y = 0; + } + var 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]); + i += 2; + } + var instructionLength = code[i] << 8 | code[i + 1]; + i += 2 + instructionLength; + var numberOfPoints = endPtsOfContours[endPtsOfContours.length - 1] + 1; + var points = []; + while (points.length < numberOfPoints) { + flags = code[i++]; + var repeat = 1; + if (flags & 0x08) { + repeat += code[i++]; + } + while (repeat-- > 0) { + points.push({flags: flags}); + } + } + 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; + case 0x02: + x -= code[i++]; + break; + case 0x12: + x += code[i++]; + break; + } + points[j].x = x; + } + 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; + case 0x04: + y -= code[i++]; + break; + case 0x24: + y += code[i++]; + break; + } + points[j].y = y; + } + var startPoint = 0; + for (i = 0; i < numberOfContours; i++) { + var endPoint = endPtsOfContours[i]; + var contour = points.slice(startPoint, endPoint + 1); + if (contour[0].flags & 1) { + contour.push(contour[0]); + } else if (contour[contour.length - 1].flags & 1) { + contour.unshift(contour[contour.length - 1]); + } 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); + } + 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; + } + } + } + + function compileCharString(code, cmds, font) { + var stack = []; + var x = 0, + y = 0; + var stems = 0; + + function moveTo(x, y) { + cmds.push({ + cmd: 'moveTo', + 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 parse(code) { + var i = 0; + while (i < code.length) { + var stackClean = false; + var v = code[i++]; + var xa, xb, ya, yb, y1, y2, y3, n, subrCode; + switch (v) { + case 1: + 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() + font.subrsBias; + subrCode = font.subrs[n]; + 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); + cmds.push({cmd: 'restore'}); + cmap = lookupCmap(font.cmap, String.fromCharCode(font.glyphNameMap[_encodings.StandardEncoding[bchar]])); + compileCharString(font.glyphs[cmap.glyphId], cmds, font); + } + 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; + } + 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; + 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); + if (stack.length === 0) { + 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); + } + break; + default: + if (v < 32) { + throw new _util.FormatError('unknown operator: ' + v); + } + 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; + } + break; + } + if (stackClean) { + stack.length = 0; + } + } + } + + parse(code); + } + + var noop = ''; + + function CompiledFont(fontMatrix) { + this.compiledGlyphs = Object.create(null); + this.compiledCharCodeToGlyphId = Object.create(null); + this.fontMatrix = fontMatrix; + } + + CompiledFont.prototype = { + getPathJs: function getPathJs(unicode) { + var cmap = lookupCmap(this.cmap, unicode); + var fn = this.compiledGlyphs[cmap.glyphId]; + if (!fn) { + fn = this.compileGlyph(this.glyphs[cmap.glyphId]); + this.compiledGlyphs[cmap.glyphId] = fn; + } + if (this.compiledCharCodeToGlyphId[cmap.charCode] === undefined) { + this.compiledCharCodeToGlyphId[cmap.charCode] = cmap.glyphId; + } + return fn; + }, + compileGlyph: function compileGlyph(code) { + if (!code || code.length === 0 || code[0] === 14) { + return noop; + } + var cmds = []; + cmds.push({cmd: 'save'}); + cmds.push({ + cmd: 'transform', + args: this.fontMatrix.slice() + }); + cmds.push({ + cmd: 'scale', + args: ['size', '-size'] + }); + this.compileGlyphImpl(code, cmds); + cmds.push({cmd: 'restore'}); + return cmds; + }, + compileGlyphImpl: function compileGlyphImpl() { + throw new Error('Children classes should implement this.'); + }, + hasBuiltPath: function hasBuiltPath(unicode) { + var cmap = lookupCmap(this.cmap, unicode); + return this.compiledGlyphs[cmap.glyphId] !== undefined && this.compiledCharCodeToGlyphId[cmap.charCode] !== undefined; + } + }; + + function TrueTypeCompiled(glyphs, cmap, fontMatrix) { + fontMatrix = fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0]; + CompiledFont.call(this, fontMatrix); + this.glyphs = glyphs; + this.cmap = cmap; + } + + _util.Util.inherit(TrueTypeCompiled, CompiledFont, { + compileGlyphImpl: function compileGlyphImpl(code, cmds) { + compileGlyf(code, cmds, this); + } + }); + + function Type2Compiled(cffInfo, cmap, fontMatrix, glyphNameMap) { + fontMatrix = fontMatrix || [0.001, 0, 0, 0.001, 0, 0]; + CompiledFont.call(this, fontMatrix); + this.glyphs = cffInfo.glyphs; + this.gsubrs = cffInfo.gsubrs || []; + this.subrs = cffInfo.subrs || []; + this.cmap = cmap; + this.glyphNameMap = glyphNameMap || (0, _glyphlist.getGlyphsUnicode)(); + this.gsubrsBias = this.gsubrs.length < 1240 ? 107 : this.gsubrs.length < 33900 ? 1131 : 32768; + this.subrsBias = this.subrs.length < 1240 ? 107 : this.subrs.length < 33900 ? 1131 : 32768; + } + + _util.Util.inherit(Type2Compiled, CompiledFont, { + compileGlyphImpl: function compileGlyphImpl(code, cmds) { + compileCharString(code, cmds, 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); + 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; + case 'glyf': + glyf = data.subarray(offset, offset + length); + break; + case 'loca': + loca = data.subarray(offset, offset + length); + break; + case 'head': + unitsPerEm = getUshort(data, offset + 18); + indexToLocFormat = getUshort(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); + } + }; + }(); + exports.FontRendererFactory = FontRendererFactory; + + /***/ + }), + /* 25 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.getFontType = exports.ProblematicCharRanges = exports.IdentityToUnicodeMap = exports.ToUnicodeMap = exports.FontFlags = exports.Font = exports.ErrorFont = exports.PRIVATE_USE_OFFSET_END = exports.PRIVATE_USE_OFFSET_START = exports.SEAC_ANALYSIS_ENABLED = undefined; + + var _util = __w_pdfjs_require__(0); + + var _cff_parser = __w_pdfjs_require__(10); + + var _glyphlist = __w_pdfjs_require__(6); + + var _encodings = __w_pdfjs_require__(4); + + var _standard_fonts = __w_pdfjs_require__(16); + + var _unicode = __w_pdfjs_require__(8); + + var _font_renderer = __w_pdfjs_require__(24); + + var _stream = __w_pdfjs_require__(2); + + var _type1_parser = __w_pdfjs_require__(34); + + var PRIVATE_USE_OFFSET_START = 0xE000; + var PRIVATE_USE_OFFSET_END = 0xF8FF; + var SKIP_PRIVATE_USE_RANGE_F000_TO_F01F = false; + var PDF_GLYPH_SPACE_UNITS = 1000; + var SEAC_ANALYSIS_ENABLED = false; + var FontFlags = { + FixedPitch: 1, + Serif: 2, + Symbolic: 4, + Script: 8, + Nonsymbolic: 32, + Italic: 64, + AllCap: 65536, + SmallCap: 131072, + ForceBold: 262144 + }; + 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']; + + function adjustWidths(properties) { + if (!properties.fontMatrix) { + return; + } + if (properties.fontMatrix[0] === _util.FONT_IDENTITY_MATRIX[0]) { + return; + } + var scale = 0.001 / properties.fontMatrix[0]; + var glyphsWidths = properties.widths; + for (var glyph in glyphsWidths) { + glyphsWidths[glyph] *= scale; + } + properties.defaultWidth *= scale; + } + + function adjustToUnicode(properties, builtInEncoding) { + if (properties.hasIncludedToUnicodeMap) { + return; + } + if (properties.hasEncoding) { + return; + } + if (builtInEncoding === properties.defaultEncoding) { + return; + } + if (properties.toUnicode instanceof IdentityToUnicodeMap) { + return; + } + var toUnicode = [], + glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)(); + for (var charCode in builtInEncoding) { + var glyphName = builtInEncoding[charCode]; + var 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; + } + } + + function recoverGlyphName(name, glyphsUnicodeMap) { + if (glyphsUnicodeMap[name] !== undefined) { + return name; + } + var unicode = (0, _unicode.getUnicodeForGlyph)(name, glyphsUnicodeMap); + if (unicode !== -1) { + for (var key in glyphsUnicodeMap) { + if (glyphsUnicodeMap[key] === unicode) { + return key; + } + } + } + (0, _util.info)('Unable to recover a standard glyph name for: ' + name); + return name; + } + + var Glyph = function GlyphClosure() { + function Glyph(fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont) { + this.fontChar = fontChar; + this.unicode = unicode; + this.accent = accent; + this.width = width; + this.vmetric = vmetric; + this.operatorListId = operatorListId; + this.isSpace = isSpace; + this.isInFont = isInFont; + } + + 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; + }; + return Glyph; + }(); + var ToUnicodeMap = function ToUnicodeMapClosure() { + function ToUnicodeMap(cmap) { + this._map = cmap; + } + + ToUnicodeMap.prototype = { + get length() { + return this._map.length; + }, + forEach: function forEach(callback) { + for (var charCode in this._map) { + callback(charCode, this._map[charCode].charCodeAt(0)); + } + }, + has: function has(i) { + return this._map[i] !== undefined; + }, + get: function get(i) { + return this._map[i]; + }, + charCodeOf: function charCodeOf(value) { + var map = this._map; + if (map.length <= 0x10000) { + return map.indexOf(value); + } + for (var charCode in map) { + if (map[charCode] === value) { + return charCode | 0; + } + } + return -1; + }, + amend: function amend(map) { + for (var charCode in map) { + this._map[charCode] = map[charCode]; + } + } + }; + return ToUnicodeMap; + }(); + var IdentityToUnicodeMap = function IdentityToUnicodeMapClosure() { + function IdentityToUnicodeMap(firstChar, lastChar) { + this.firstChar = firstChar; + this.lastChar = lastChar; + } + + IdentityToUnicodeMap.prototype = { + get length() { + return this.lastChar + 1 - this.firstChar; + }, + forEach: function forEach(callback) { + for (var i = this.firstChar, ii = this.lastChar; i <= ii; i++) { + callback(i, i); + } + }, + has: function has(i) { + return this.firstChar <= i && i <= this.lastChar; + }, + get: function get(i) { + if (this.firstChar <= i && i <= this.lastChar) { + return String.fromCharCode(i); + } + return undefined; + }, + charCodeOf: function charCodeOf(v) { + return (0, _util.isInt)(v) && v >= this.firstChar && v <= this.lastChar ? v : -1; + }, + amend: function amend(map) { + throw new Error('Should not call amend()'); + } + }; + return 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; + } + } else { + for (i = 0, ii = data.length; i < ii; i++) { + dest[offset++] = data[i] & 0xFF; + } + } + } + + function OpenTypeFileBuilder(sfnt) { + this.sfnt = sfnt; + this.tables = Object.create(null); + } + + OpenTypeFileBuilder.getSearchParams = function OpenTypeFileBuilder_getSearchParams(entriesCount, entrySize) { + var maxPower2 = 1, + log2 = 0; + while ((maxPower2 ^ entriesCount) > maxPower2) { + maxPower2 <<= 1; + log2++; + } + var searchRange = maxPower2 * entrySize; + return { + range: searchRange, + entry: log2, + rangeShift: entrySize * entriesCount - searchRange + }; + }; + 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, _util.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: function OpenTypeFileBuilder_addTable(tag, data) { + if (tag in this.tables) { + throw new Error('Table ' + tag + ' already exists'); + } + this.tables[tag] = data; + } + }; + return OpenTypeFileBuilder; + }(); + var ProblematicCharRanges = new Int32Array([0x0000, 0x0020, 0x007F, 0x00A1, 0x00AD, 0x00AE, 0x0600, 0x0780, 0x08A0, 0x10A0, 0x1780, 0x1800, 0x1C00, 0x1C50, 0x2000, 0x2010, 0x2011, 0x2012, 0x2028, 0x2030, 0x205F, 0x2070, 0x25CC, 0x25CD, 0x3000, 0x3001, 0x3164, 0x3165, 0xAA60, 0xAA80, 0xFFF0, 0x10000]); + var Font = function FontClosure() { + function Font(name, file, properties) { + var charCode; + this.name = name; + this.loadedName = properties.loadedName; + this.isType3Font = properties.isType3Font; + this.sizes = []; + 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.type = type; + this.subtype = subtype; + this.fallbackName = this.isMonospace ? 'monospace' : this.isSerifFont ? 'serif' : 'sans-serif'; + this.differences = properties.differences; + this.widths = properties.widths; + this.defaultWidth = properties.defaultWidth; + this.composite = properties.composite; + this.wideChars = properties.wideChars; + this.cMap = properties.cMap; + this.ascent = properties.ascent / PDF_GLYPH_SPACE_UNITS; + this.descent = properties.descent / PDF_GLYPH_SPACE_UNITS; + this.fontMatrix = properties.fontMatrix; + this.bbox = properties.bbox; + this.defaultEncoding = properties.defaultEncoding; + this.toUnicode = properties.toUnicode; + this.toFontChar = []; + if (properties.type === 'Type3') { + for (charCode = 0; charCode < 256; charCode++) { + this.toFontChar[charCode] = this.differences[charCode] || properties.defaultEncoding[charCode]; + } + this.fontType = _util.FontType.TYPE3; + return; + } + this.cidEncoding = properties.cidEncoding; + this.vertical = properties.vertical; + if (this.vertical) { + this.vmetrics = properties.vmetrics; + this.defaultVMetrics = properties.defaultVMetrics; + } + if (!file || file.isEmpty) { + if (file) { + (0, _util.warn)('Font file is empty in "' + name + '" (' + this.loadedName + ')'); + } + this.fallbackToSystemFont(); + return; + } + if (subtype === 'Type1C') { + if (type !== 'Type1' && type !== 'MMType1') { + if (isTrueTypeFile(file)) { + subtype = 'TrueType'; + } else { + type = 'Type1'; + } + } else if (isOpenTypeFile(file)) { + subtype = 'OpenType'; + } + } + if (subtype === 'CIDFontType0C' && type !== 'CIDFontType0') { + type = 'CIDFontType0'; + } + if (type === 'CIDFontType0') { + if (isType1File(file)) { + subtype = 'CIDFontType0'; + } else if (isOpenTypeFile(file)) { + subtype = 'OpenType'; + } else { + subtype = 'CIDFontType0C'; + } + } + if (subtype === 'OpenType' && type !== 'OpenType') { + type = 'OpenType'; + } + try { + var data; + switch (type) { + case 'MMType1': + (0, _util.info)('MMType1 font (' + name + '), falling back to Type1.'); + case 'Type1': + case 'CIDFontType0': + this.mimetype = 'font/opentype'; + var cff = subtype === 'Type1C' || subtype === 'CIDFontType0C' ? new CFFFont(file, properties) : new Type1Font(name, file, properties); + adjustWidths(properties); + data = this.convert(name, cff, properties); + break; + case 'OpenType': + case 'TrueType': + case 'CIDFontType2': + this.mimetype = 'font/opentype'; + data = this.checkAndRepair(name, file, properties); + if (this.isOpenType) { + adjustWidths(properties); + type = 'OpenType'; + } + break; + default: + throw new _util.FormatError('Font ' + type + ' is not supported'); + } + } catch (e) { + if (!(e instanceof _util.FormatError)) { + throw e; + } + (0, _util.warn)(e); + this.fallbackToSystemFont(); + return; + } + this.data = data; + this.fontType = getFontType(type, subtype); + this.fontMatrix = properties.fontMatrix; + this.widths = properties.widths; + this.defaultWidth = properties.defaultWidth; + this.toUnicode = properties.toUnicode; + this.encoding = properties.baseEncoding; + this.seacMap = properties.seacMap; + this.loading = true; + } + + Font.getFontID = function () { + var ID = 1; + return function Font_getFontID() { + return String(ID++); + }; + }(); + + function int16(b0, b1) { + return (b0 << 8) + b1; + } + + function signedInt16(b0, b1) { + var 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) { + value = value > 0x7FFF ? 0x7FFF : value < -0x8000 ? -0x8000 : value; + return String.fromCharCode(value >> 8 & 0xff, value & 0xff); + } + + function isTrueTypeFile(file) { + var header = file.peekBytes(4); + return (0, _util.readUint32)(header, 0) === 0x00010000; + } + + 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 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; + } + } + for (var charCode in differences) { + unicode = (0, _unicode.getUnicodeForGlyph)(differences[charCode], glyphsUnicodeMap); + if (unicode !== -1) { + toFontChar[+charCode] = unicode; + } + } + return toFontChar; + } + + function isProblematicUnicodeLocation(code) { + var i = 0, + j = ProblematicCharRanges.length - 1; + while (i < j) { + var c = i + j + 1 >> 1; + if (code < ProblematicCharRanges[c]) { + j = c - 1; + } else { + i = c; + } + } + return !(i & 1); + } + + function adjustMapping(charCodeToGlyphId, properties, missingGlyphs) { + var toUnicode = properties.toUnicode; + var isSymbolic = !!(properties.flags & FontFlags.Symbolic); + var isIdentityUnicode = properties.toUnicode instanceof IdentityToUnicodeMap; + var newMap = Object.create(null); + var toFontChar = []; + var usedFontCharCodes = []; + var nextAvailableFontCharCode = PRIVATE_USE_OFFSET_START; + for (var originalCharCode in charCodeToGlyphId) { + originalCharCode |= 0; + var glyphId = charCodeToGlyphId[originalCharCode]; + if (missingGlyphs[glyphId]) { + continue; + } + var fontCharCode = originalCharCode; + var hasUnicodeValue = false; + if (!isIdentityUnicode && toUnicode.has(originalCharCode)) { + hasUnicodeValue = true; + var unicode = toUnicode.get(fontCharCode); + if (unicode.length === 1) { + fontCharCode = unicode.charCodeAt(0); + } + } + if (usedFontCharCodes[fontCharCode] !== undefined || isProblematicUnicodeLocation(fontCharCode) || isSymbolic && !hasUnicodeValue) { + do { + if (nextAvailableFontCharCode > PRIVATE_USE_OFFSET_END) { + (0, _util.warn)('Ran out of space in font private use area.'); + break; + } + fontCharCode = nextAvailableFontCharCode++; + if (SKIP_PRIVATE_USE_RANGE_F000_TO_F01F && fontCharCode === 0xF000) { + fontCharCode = 0xF020; + nextAvailableFontCharCode = fontCharCode + 1; + } + } while (usedFontCharCodes[fontCharCode] !== undefined); + } + newMap[fontCharCode] = glyphId; + toFontChar[originalCharCode] = fontCharCode; + usedFontCharCodes[fontCharCode] = true; + } + return { + toFontChar: toFontChar, + charCodeToGlyphId: newMap, + nextAvailableFontCharCode: 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) { + var stream = new _stream.Stream(os2.data); + var version = stream.getUint16(); + stream.getBytes(60); + var selection = stream.getUint16(); + if (version < 4 && selection & 0x0300) { + return false; + } + var firstChar = stream.getUint16(); + var lastChar = stream.getUint16(); + if (firstChar > lastChar) { + return false; + } + stream.getBytes(6); + var usWinAscent = stream.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'); + } + } + } 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 * Math.pow(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, + encoding: null, + get renderer() { + var renderer = _font_renderer.FontRendererFactory.create(this, SEAC_ANALYSIS_ENABLED); + return (0, _util.shadow)(this, 'renderer', renderer); + }, + exportData: function Font_exportData() { + var data = {}; + for (var i in this) { + if (this.hasOwnProperty(i)) { + data[i] = this[i]; + } + } + return data; + }, + fallbackToSystemFont: function Font_fallbackToSystemFont() { + var _this = this; + + this.missingFile = true; + var charCode, unicode; + var name = this.name; + var type = this.type; + var subtype = this.subtype; + var fontName = name.replace(/[,_]/g, '-'); + var 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; + if (isStandardFont && type === 'CIDFontType2' && this.cidEncoding.indexOf('Identity-') === 0) { + var GlyphMapForStandardFonts = (0, _standard_fonts.getGlyphMapForStandardFonts)(); + var map = []; + for (charCode in GlyphMapForStandardFonts) { + map[+charCode] = GlyphMapForStandardFonts[charCode]; + } + if (/Arial-?Black/i.test(name)) { + var SupplementalGlyphMapForArialBlack = (0, _standard_fonts.getSupplementalGlyphMapForArialBlack)(); + for (charCode in SupplementalGlyphMapForArialBlack) { + map[+charCode] = SupplementalGlyphMapForArialBlack[charCode]; + } + } + var isIdentityUnicode = this.toUnicode instanceof IdentityToUnicodeMap; + if (!isIdentityUnicode) { + this.toUnicode.forEach(function (charCode, unicodeCharCode) { + 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 { + var glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)(); + this.toUnicode.forEach(function (charCode, unicodeCharCode) { + if (!_this.composite) { + var glyphName = _this.differences[charCode] || _this.defaultEncoding[charCode]; + unicode = (0, _unicode.getUnicodeForGlyph)(glyphName, glyphsUnicodeMap); + if (unicode !== -1) { + unicodeCharCode = unicode; + } + } + _this.toFontChar[charCode] = unicodeCharCode; + }); + } + this.loadedName = fontName.split('-')[0]; + this.loading = false; + this.fontType = getFontType(type, subtype); + }, + checkAndRepair: function Font_checkAndRepair(name, font, properties) { + 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: tag, + checksum: checksum, + length: length, + offset: offset, + data: 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 readCmapTable(cmap, font, isSymbolicFont, hasEncoding) { + if (!cmap) { + (0, _util.warn)('No cmap table available.'); + return { + platformId: -1, + encodingId: -1, + mappings: [], + hasShortCmap: false + }; + } + var segment; + var start = (font.start ? font.start : 0) + cmap.offset; + font.pos = start; + font.getUint16(); + var numTables = font.getUint16(); + var potentialTable; + var canBreak = false; + for (var i = 0; i < numTables; i++) { + var platformId = font.getUint16(); + var encodingId = font.getUint16(); + var offset = font.getInt32() >>> 0; + var useTable = false; + if (potentialTable && potentialTable.platformId === platformId && potentialTable.encodingId === encodingId) { + continue; + } + if (platformId === 0 && encodingId === 0) { + 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: platformId, + encodingId: encodingId, + offset: offset + }; + } + if (canBreak) { + break; + } + } + if (potentialTable) { + font.pos = start + potentialTable.offset; + } + if (!potentialTable || font.peekByte() === -1) { + (0, _util.warn)('Could not find a preferred cmap table.'); + return { + platformId: -1, + encodingId: -1, + mappings: [], + hasShortCmap: false + }; + } + var format = font.getUint16(); + font.getUint16(); + font.getUint16(); + var hasShortCmap = false; + var mappings = []; + var j, glyphId; + if (format === 0) { + for (j = 0; j < 256; j++) { + var index = font.getByte(); + if (!index) { + continue; + } + mappings.push({ + charCode: j, + glyphId: index + }); + } + hasShortCmap = true; + } else if (format === 4) { + var segCount = font.getUint16() >> 1; + font.getBytes(6); + var segIndex, + segments = []; + for (segIndex = 0; segIndex < segCount; segIndex++) { + segments.push({end: font.getUint16()}); + } + font.getUint16(); + for (segIndex = 0; segIndex < segCount; segIndex++) { + segments[segIndex].start = font.getUint16(); + } + for (segIndex = 0; segIndex < segCount; segIndex++) { + segments[segIndex].delta = font.getUint16(); + } + var offsetsCount = 0; + for (segIndex = 0; segIndex < segCount; segIndex++) { + segment = segments[segIndex]; + var rangeOffset = font.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(font.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; + } + glyphId = offsetIndex < 0 ? j : offsets[offsetIndex + j - start]; + glyphId = glyphId + delta & 0xFFFF; + mappings.push({ + charCode: j, + glyphId: glyphId + }); + } + } + } else if (format === 6) { + var firstCode = font.getUint16(); + var entryCount = font.getUint16(); + for (j = 0; j < entryCount; j++) { + glyphId = font.getUint16(); + var charCode = firstCode + j; + mappings.push({ + charCode: charCode, + glyphId: glyphId + }); + } + } else { + (0, _util.warn)('cmap table has unsupported format: ' + format); + return { + platformId: -1, + encodingId: -1, + mappings: [], + hasShortCmap: false + }; + } + mappings.sort(function (a, b) { + return a.charCode - b.charCode; + }); + for (i = 1; i < mappings.length; i++) { + if (mappings[i - 1].charCode === mappings[i].charCode) { + mappings.splice(i, 1); + i--; + } + } + return { + platformId: potentialTable.platformId, + encodingId: potentialTable.encodingId, + mappings: mappings, + hasShortCmap: hasShortCmap + }; + } + + function sanitizeMetrics(font, header, metrics, numGlyphs) { + if (!header) { + if (metrics) { + metrics.data = null; + } + return; + } + font.pos = (font.start ? font.start : 0) + header.offset; + font.pos += header.length - 2; + var numOfMetrics = font.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); + metrics.data = entries; + } + } + + function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart, hintsValid) { + if (sourceEnd - sourceStart <= 12) { + return 0; + } + var glyf = source.subarray(sourceStart, sourceEnd); + var contoursCount = glyf[0] << 8 | glyf[1]; + if (contoursCount & 0x8000) { + dest.set(glyf, destStart); + return glyf.length; + } + var i, + j = 10, + flagsCount = 0; + for (i = 0; i < contoursCount; i++) { + var endPoint = glyf[j] << 8 | glyf[j + 1]; + flagsCount = endPoint + 1; + j += 2; + } + var instructionsStart = j; + var instructionsLength = glyf[j] << 8 | glyf[j + 1]; + j += 2 + instructionsLength; + var instructionsEnd = j; + var coordinatesLength = 0; + for (i = 0; i < flagsCount; i++) { + var flag = glyf[j++]; + if (flag & 0xC0) { + glyf[j - 1] = flag & 0x3F; + } + var xyLength = (flag & 2 ? 1 : flag & 16 ? 0 : 2) + (flag & 4 ? 1 : flag & 32 ? 0 : 2); + coordinatesLength += xyLength; + if (flag & 8) { + var repeat = glyf[j++]; + i += repeat; + coordinatesLength += repeat * xyLength; + } + } + if (coordinatesLength === 0) { + return 0; + } + var glyphDataLength = j + coordinatesLength; + if (glyphDataLength > glyf.length) { + return 0; + } + 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; + } + return glyphDataLength; + } + if (glyf.length - glyphDataLength > 3) { + glyphDataLength = glyphDataLength + 3 & ~3; + dest.set(glyf.subarray(0, glyphDataLength), destStart); + return glyphDataLength; + } + dest.set(glyf, destStart); + return glyf.length; + } + + function sanitizeHead(head, numGlyphs, locaLength) { + var data = head.data; + var 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; + } + var indexToLocFormat = int16(data[50], data[51]); + if (indexToLocFormat < 0 || indexToLocFormat > 1) { + (0, _util.info)('Attempting to fix invalid indexToLocFormat in head table: ' + indexToLocFormat); + var 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 { + throw new _util.FormatError('Could not fix indexToLocFormat: ' + indexToLocFormat); + } + } + } + + function sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong, hintsValid, dupFirstEntry) { + var itemSize, itemDecode, itemEncode; + if (isGlyphLocationsLong) { + itemSize = 4; + itemDecode = function fontItemDecodeLong(data, offset) { + return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]; + }; + 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; + 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; + }; + } + var locaData = loca.data; + var locaDataSize = itemSize * (1 + numGlyphs); + if (locaData.length !== locaDataSize) { + 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 startOffset = itemDecode(locaData, 0); + var writeOffset = 0; + var missingGlyphData = Object.create(null); + itemEncode(locaData, 0, writeOffset); + var i, j; + var locaCount = dupFirstEntry ? numGlyphs - 1 : numGlyphs; + for (i = 0, j = itemSize; i < locaCount; i++, j += itemSize) { + var endOffset = itemDecode(locaData, j); + if (endOffset > oldGlyfDataLength && (oldGlyfDataLength + 3 & ~3) === endOffset) { + endOffset = oldGlyfDataLength; + } + if (endOffset > oldGlyfDataLength) { + startOffset = endOffset; + } + var newLength = sanitizeGlyph(oldGlyfData, startOffset, endOffset, newGlyfData, writeOffset, hintsValid); + if (newLength === 0) { + missingGlyphData[i] = true; + } + writeOffset += newLength; + itemEncode(locaData, j, writeOffset); + startOffset = endOffset; + } + 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 < numGlyphs; i++, j += itemSize) { + itemEncode(locaData, j, simpleGlyph.length); + } + glyf.data = simpleGlyph; + return missingGlyphData; + } + 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 missingGlyphData; + } + + function readPostScriptTable(post, properties, maxpNumGlyphs) { + var start = (font.start ? font.start : 0) + post.offset; + font.pos = start; + var length = post.length, + end = start + length; + var version = font.getInt32(); + font.getBytes(28); + var glyphNames; + var valid = true; + var i; + switch (version) { + case 0x00010000: + glyphNames = MacStandardGlyphOrdering; + break; + case 0x00020000: + var numGlyphs = font.getUint16(); + if (numGlyphs !== maxpNumGlyphs) { + 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]); + } + break; + case 0x00030000: + break; + default: + (0, _util.warn)('Unknown/unsupported post table version ' + version); + valid = false; + if (properties.defaultEncoding) { + glyphNames = properties.defaultEncoding; + } + break; + } + properties.glyphNames = glyphNames; + return valid; + } + + function readNameTable(nameTable) { + var start = (font.start ? font.start : 0) + nameTable.offset; + font.pos = start; + var names = [[], []]; + var 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)); + } + } + 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]; + + 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 (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]; + ttContext.functionsUsed[funcId] = true; + if (funcId in ttContext.functionsStackDeltas) { + stack.length += ttContext.functionsStackDeltas[funcId]; + } else if (funcId in ttContext.functionsDefined && functionsCalled.indexOf(funcId) < 0) { + callstack.push({ + data: data, + i: 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: data, + i: 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) { + var stackDelta = op <= 0x8E ? TTOpsStackDeltas[op] : op >= 0xC0 && op <= 0xDF ? -1 : op >= 0xE0 ? -2 : 0; + 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; + 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; + } + if (ttContext.functionsDefined.length > maxFunctionDefs) { + (0, _util.warn)('TT: more functions defined than expected'); + 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; + } + } + } + + function foldTTTable(table, content) { + if (content.length > 1) { + var newLength = 0; + var 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; + } + } + + function sanitizeTTPrograms(fpgm, prep, cvt, maxFunctionDefs) { + var ttContext = { + functionsDefined: [], + functionsUsed: [], + functionsStackDeltas: [], + tooComplexToFollowFunctions: false, + hintsValid: true + }; + 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())); + var VALID_TABLES = ['OS/2', 'cmap', 'head', 'hhea', 'hmtx', 'maxp', 'name', 'post', 'loca', 'glyf', 'fpgm', 'prep', 'cvt ', 'CFF ']; + var header = readOpenTypeHeader(font); + var numTables = header.numTables; + var cff, cffFile; + var 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; + var table; + for (var i = 0; i < numTables; i++) { + table = readTableEntry(font); + if (VALID_TABLES.indexOf(table.tag) < 0) { + continue; + } + if (table.length === 0) { + continue; + } + tables[table.tag] = table; + } + var isTrueType = !tables['CFF ']; + if (!isTrueType) { + if (header.version === 'OTTO' && !(properties.composite && properties.cidToGidMap) || !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); + } + 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) + }; + } + this.isOpenType = false; + } + if (!tables['maxp']) { + throw new _util.FormatError('Required "maxp" table is not found'); + } + font.pos = (font.start || 0) + tables['maxp'].offset; + var version = font.getInt32(); + var numGlyphs = font.getUint16(); + var maxFunctionDefs = 0; + if (version >= 0x00010000 && tables['maxp'].length >= 22) { + font.pos += 8; + var maxZones = font.getUint16(); + if (maxZones > 2) { + tables['maxp'].data[14] = 0; + tables['maxp'].data[15] = 2; + } + font.pos += 4; + maxFunctionDefs = font.getUint16(); + } + var dupFirstEntry = false; + if (properties.type === 'CIDFontType2' && properties.toUnicode && properties.toUnicode.get(0) > '\0') { + dupFirstEntry = true; + numGlyphs++; + tables['maxp'].data[4] = numGlyphs >> 8; + tables['maxp'].data[5] = numGlyphs & 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'], numGlyphs); + 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]); + missingGlyphs = sanitizeGlyphLocations(tables['loca'], tables['glyf'], numGlyphs, isGlyphLocationsLong, hintsValid, dupFirstEntry); + } + 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']) { + var valid = readPostScriptTable(tables['post'], properties, numGlyphs); + if (!valid) { + tables['post'] = null; + } + } + var charCodeToGlyphId = [], + charCode; + + 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; + } + }); + if (dupFirstEntry && (isCidToGidMapEmpty || !charCodeToGlyphId[0])) { + charCodeToGlyphId[0] = numGlyphs - 1; + } + } 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; + if (properties.hasEncoding && (cmapPlatformId === 3 && cmapEncodingId === 1 || cmapPlatformId === 1 && cmapEncodingId === 0) || cmapPlatformId === -1 && cmapEncodingId === -1 && !!(0, _encodings.getEncoding)(properties.baseEncodingName)) { + var baseEncoding = []; + if (properties.baseEncodingName === 'MacRomanEncoding' || properties.baseEncodingName === 'WinAnsiEncoding') { + baseEncoding = (0, _encodings.getEncoding)(properties.baseEncodingName); + } + var glyphsUnicodeMap = (0, _glyphlist.getGlyphsUnicode)(); + for (charCode = 0; charCode < 256; charCode++) { + var glyphName, standardGlyphName; + 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 (!glyphName) { + 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); + } + var found = false; + for (i = 0; i < cmapMappingsLength; ++i) { + if (cmapMappings[i].charCode !== unicodeOrCharCode) { + continue; + } + charCodeToGlyphId[charCode] = cmapMappings[i].glyphId; + found = true; + break; + } + if (!found && properties.glyphNames) { + var glyphId = properties.glyphNames.indexOf(glyphName); + if (glyphId === -1 && standardGlyphName !== glyphName) { + glyphId = properties.glyphNames.indexOf(standardGlyphName); + } + if (glyphId > 0 && hasGlyph(glyphId)) { + charCodeToGlyphId[charCode] = glyphId; + found = true; + } + } + } + } else if (cmapPlatformId === 0 && cmapEncodingId === 0) { + for (i = 0; i < cmapMappingsLength; ++i) { + charCodeToGlyphId[cmapMappings[i].charCode] = cmapMappings[i].glyphId; + } + } else { + for (i = 0; i < cmapMappingsLength; ++i) { + charCode = cmapMappings[i].charCode; + if (cmapPlatformId === 3 && charCode >= 0xF000 && charCode <= 0xF0FF) { + charCode &= 0xFF; + } + charCodeToGlyphId[charCode] = cmapMappings[i].glyphId; + } + } + } + if (charCodeToGlyphId.length === 0) { + charCodeToGlyphId[0] = 0; + } + var newMapping = adjustMapping(charCodeToGlyphId, properties, missingGlyphs); + this.toFontChar = newMapping.toFontChar; + tables['cmap'] = { + tag: 'cmap', + data: createCmapTable(newMapping.charCodeToGlyphId, numGlyphs) + }; + if (!tables['OS/2'] || !validateOS2Table(tables['OS/2'])) { + tables['OS/2'] = { + tag: 'OS/2', + data: createOS2Table(properties, newMapping.charCodeToGlyphId, metricsOverride) + }; + } + if (!tables['post']) { + tables['post'] = { + tag: 'post', + data: createPostTable(properties) + }; + } + if (!isTrueType) { + try { + cffFile = new _stream.Stream(tables['CFF '].data); + var parser = new _cff_parser.CFFParser(cffFile, properties, SEAC_ANALYSIS_ENABLED); + cff = parser.parse(); + 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); + } + var mapping = font.getGlyphMapping(properties); + var newMapping = adjustMapping(mapping, properties, Object.create(null)); + 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 (var 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: baseFontCharCode, + accentFontCharCode: accentFontCharCode, + accentOffset: 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 (var 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() { + if ('_shadowWidth' in this) { + return this._shadowWidth; + } + 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) { + if (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; + this._shadowWidth = width; + return 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]; + var unicode = this.toUnicode.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) { + 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.fromCharCode(seac.accentFontCharCode), + offset: seac.accentOffset + }; + } + var fontChar = String.fromCharCode(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; + } + }; + return Font; + }(); + var ErrorFont = function ErrorFontClosure() { + function ErrorFont(error) { + this.error = error; + this.loadedName = 'g_font_error'; + this.loading = false; + } + + ErrorFont.prototype = { + charsToGlyphs: function ErrorFont_charsToGlyphs() { + return []; + }, + exportData: function ErrorFont_exportData() { + return {error: this.error}; + } + }; + return 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, _util.isSpace)(streamBytes[i])) { + i++; + } + found = true; + break; + } + i++; + } + return { + found: 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 _util.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); + headerBlockLength = headerBlock.length; + 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); + eexecBlockLength = eexecBlock.length; + var eexecBlockParser = new _type1_parser.Type1Parser(eexecBlock.stream, true, SEAC_ANALYSIS_ENABLED); + var data = eexecBlockParser.extractFontProgram(); + for (var info in data.properties) { + properties[info] = data.properties[info]; + } + 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; + 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); + }, + 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 = [0]; + var i, ii; + for (i = 0; i < count; i++) { + var index = _cff_parser.CFFStandardStrings.indexOf(charstrings[i].glyphName); + if (index === -1) { + index = 0; + } + charsetArray.push(index >> 8 & 0xff, index & 0xff); + } + 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++) { + var glyph = glyphs[i]; + if (glyph.length === 0) { + charStringsIndex.add([0x8B, 0x0E]); + continue; + } + charStringsIndex.add(glyph); + } + 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 ((0, _util.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(); + 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); + if (cff.isCIDFont) { + for (glyphId = 0; glyphId < charsets.length; glyphId++) { + var cid = charsets[glyphId]; + var charCode = properties.cMap.charCodeOf(cid); + charCodeToGlyphId[charCode] = glyphId; + } + } else { + for (glyphId = 0; glyphId < cff.charStrings.count; glyphId++) { + charCodeToGlyphId[glyphId] = glyphId; + } + } + return charCodeToGlyphId; + } + var encoding = cff.encoding ? cff.encoding.encoding : null; + charCodeToGlyphId = type1FontGlyphMapping(properties, encoding, charsets); + return charCodeToGlyphId; + } + }; + return CFFFont; + }(); + (function checkSeacSupport() { + if (typeof navigator !== 'undefined' && /Windows/.test(navigator.userAgent)) { + exports.SEAC_ANALYSIS_ENABLED = SEAC_ANALYSIS_ENABLED = true; + } + })(); + (function checkChromeWindows() { + if (typeof navigator !== 'undefined' && /Windows.*Chrome/.test(navigator.userAgent)) { + SKIP_PRIVATE_USE_RANGE_F000_TO_F01F = true; + } + })(); + exports.SEAC_ANALYSIS_ENABLED = SEAC_ANALYSIS_ENABLED; + exports.PRIVATE_USE_OFFSET_START = PRIVATE_USE_OFFSET_START; + exports.PRIVATE_USE_OFFSET_END = PRIVATE_USE_OFFSET_END; + exports.ErrorFont = ErrorFont; + exports.Font = Font; + exports.FontFlags = FontFlags; + exports.ToUnicodeMap = ToUnicodeMap; + exports.IdentityToUnicodeMap = IdentityToUnicodeMap; + exports.ProblematicCharRanges = ProblematicCharRanges; + exports.getFontType = getFontType; + + /***/ + }), + /* 26 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFImage = undefined; + + var _util = __w_pdfjs_require__(0); + + var _stream = __w_pdfjs_require__(2); + + var _primitives = __w_pdfjs_require__(1); + + var _colorspace = __w_pdfjs_require__(3); + + var _jpx = __w_pdfjs_require__(14); + + var PDFImage = function PDFImageClosure() { + function handleImageData(image, nativeDecoder) { + if (nativeDecoder && nativeDecoder.canDecode(image)) { + return nativeDecoder.decode(image); + } + return Promise.resolve(image); + } + + function decodeAndClamp(value, addend, coefficient, max) { + value = addend + value * coefficient; + return value < 0 ? 0 : value > max ? max : value; + } + + function resizeImageMask(src, bpc, w1, h1, w2, h2) { + var length = w2 * h2; + var dest = bpc <= 8 ? new Uint8Array(length) : bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length); + var xRatio = w1 / w2; + var yRatio = h1 / h2; + var i, + j, + py, + newIndex = 0, + oldIndex; + var xScaled = new Uint16Array(w2); + var w1Scanline = w1; + for (i = 0; i < w2; i++) { + xScaled[i] = Math.floor(i * xRatio); + } + for (i = 0; i < h2; i++) { + py = Math.floor(i * yRatio) * w1Scanline; + for (j = 0; j < w2; j++) { + oldIndex = py + xScaled[j]; + dest[newIndex++] = src[oldIndex]; + } + } + return dest; + } + + function PDFImage(xref, res, image, inline, smask, mask, isMask) { + this.image = image; + var dict = image.dict; + if (dict.has('Filter')) { + var filter = dict.get('Filter').name; + if (filter === 'JPXDecode') { + var jpxImage = new _jpx.JpxImage(); + jpxImage.parseImageProperties(image.stream); + image.stream.reset(); + image.bitsPerComponent = jpxImage.bitsPerComponent; + image.numComps = jpxImage.componentsCount; + } else if (filter === 'JBIG2Decode') { + image.bitsPerComponent = 1; + image.numComps = 1; + } + } + this.width = dict.get('Width', 'W'); + this.height = dict.get('Height', 'H'); + if (this.width < 1 || this.height < 1) { + throw new _util.FormatError('Invalid image width: ' + this.width + ' or ' + ('height: ' + this.height)); + } + this.interpolate = dict.get('Interpolate', 'I') || false; + this.imageMask = dict.get('ImageMask', 'IM') || false; + this.matte = dict.get('Matte') || false; + var bitsPerComponent = image.bitsPerComponent; + if (!bitsPerComponent) { + bitsPerComponent = dict.get('BitsPerComponent', 'BPC'); + if (!bitsPerComponent) { + if (this.imageMask) { + bitsPerComponent = 1; + } else { + throw new _util.FormatError('Bits per component missing in image: ' + this.imageMask); + } + } + } + this.bpc = bitsPerComponent; + if (!this.imageMask) { + var colorSpace = dict.get('ColorSpace', 'CS'); + if (!colorSpace) { + (0, _util.info)('JPX images (which do not require color spaces)'); + switch (image.numComps) { + case 1: + colorSpace = _primitives.Name.get('DeviceGray'); + break; + case 3: + colorSpace = _primitives.Name.get('DeviceRGB'); + break; + case 4: + colorSpace = _primitives.Name.get('DeviceCMYK'); + break; + default: + throw new Error('JPX images with ' + this.numComps + ' ' + 'color components not supported.'); + } + } + this.colorSpace = _colorspace.ColorSpace.parse(colorSpace, xref, res); + this.numComps = this.colorSpace.numComps; + } + this.decode = dict.getArray('Decode', 'D'); + this.needsDecode = false; + if (this.decode && (this.colorSpace && !this.colorSpace.isDefaultDecode(this.decode) || isMask && !_colorspace.ColorSpace.isDefaultDecode(this.decode, 1))) { + this.needsDecode = true; + var max = (1 << bitsPerComponent) - 1; + this.decodeCoefficients = []; + this.decodeAddends = []; + for (var i = 0, j = 0; i < this.decode.length; i += 2, ++j) { + var dmin = this.decode[i]; + var dmax = this.decode[i + 1]; + this.decodeCoefficients[j] = dmax - dmin; + this.decodeAddends[j] = max * dmin; + } + } + if (smask) { + this.smask = new PDFImage(xref, res, smask, false); + } else if (mask) { + if ((0, _primitives.isStream)(mask)) { + var maskDict = mask.dict, + imageMask = maskDict.get('ImageMask', 'IM'); + if (!imageMask) { + (0, _util.warn)('Ignoring /Mask in image without /ImageMask.'); + } else { + this.mask = new PDFImage(xref, res, mask, false, null, null, true); + } + } else { + this.mask = mask; + } + } + } + + PDFImage.buildImage = function PDFImage_buildImage(handler, xref, res, image, inline, nativeDecoder) { + var imagePromise = handleImageData(image, nativeDecoder); + var smaskPromise; + var maskPromise; + var smask = image.dict.get('SMask'); + var mask = image.dict.get('Mask'); + if (smask) { + smaskPromise = handleImageData(smask, nativeDecoder); + maskPromise = Promise.resolve(null); + } else { + smaskPromise = Promise.resolve(null); + if (mask) { + if ((0, _primitives.isStream)(mask)) { + maskPromise = handleImageData(mask, nativeDecoder); + } else if ((0, _util.isArray)(mask)) { + maskPromise = Promise.resolve(mask); + } else { + (0, _util.warn)('Unsupported mask format.'); + maskPromise = Promise.resolve(null); + } + } else { + maskPromise = Promise.resolve(null); + } + } + return Promise.all([imagePromise, smaskPromise, maskPromise]).then(function (results) { + var imageData = results[0]; + var smaskData = results[1]; + var maskData = results[2]; + return new PDFImage(xref, res, imageData, inline, smaskData, maskData); + }); + }; + PDFImage.createMask = function PDFImage_createMask(imgArray, width, height, imageIsFromDecodeStream, inverseDecode) { + var computedLength = (width + 7 >> 3) * height; + var actualLength = imgArray.byteLength; + var haveFullData = computedLength === actualLength; + var data, i; + if (imageIsFromDecodeStream && (!inverseDecode || haveFullData)) { + data = imgArray; + } else if (!inverseDecode) { + data = new Uint8Array(actualLength); + data.set(imgArray); + } else { + data = new Uint8Array(computedLength); + data.set(imgArray); + for (i = actualLength; i < computedLength; i++) { + data[i] = 0xff; + } + } + if (inverseDecode) { + for (i = 0; i < actualLength; i++) { + data[i] = ~data[i]; + } + } + return { + data: data, + width: width, + height: height + }; + }; + PDFImage.prototype = { + get drawWidth() { + return Math.max(this.width, this.smask && this.smask.width || 0, this.mask && this.mask.width || 0); + }, + get drawHeight() { + return Math.max(this.height, this.smask && this.smask.height || 0, this.mask && this.mask.height || 0); + }, + decodeBuffer: function 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; + if (bpc === 1) { + for (i = 0, ii = buffer.length; i < ii; i++) { + buffer[i] = +!buffer[i]; + } + return; + } + var index = 0; + for (i = 0, ii = this.width * this.height; i < ii; i++) { + for (var j = 0; j < numComps; j++) { + buffer[index] = decodeAndClamp(buffer[index], decodeAddends[j], decodeCoefficients[j], max); + index++; + } + } + }, + getComponents: function PDFImage_getComponents(buffer) { + var 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; + var output = bpc <= 8 ? new Uint8Array(length) : bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length); + var rowComps = width * numComps; + var max = (1 << bpc) - 1; + var i = 0, + ii, + buf; + if (bpc === 1) { + var mask, loop1End, loop2End; + for (var j = 0; j < height; j++) { + loop1End = i + (rowComps & ~7); + loop2End = i + rowComps; + while (i < loop1End) { + buf = buffer[bufferPos++]; + output[i] = buf >> 7 & 1; + output[i + 1] = buf >> 6 & 1; + output[i + 2] = buf >> 5 & 1; + output[i + 3] = buf >> 4 & 1; + output[i + 4] = buf >> 3 & 1; + output[i + 5] = buf >> 2 & 1; + output[i + 6] = buf >> 1 & 1; + output[i + 7] = buf & 1; + i += 8; + } + if (i < loop2End) { + buf = buffer[bufferPos++]; + mask = 128; + while (i < loop2End) { + output[i++] = +!!(buf & mask); + mask >>= 1; + } + } + } + } else { + var bits = 0; + buf = 0; + for (i = 0, ii = length; i < ii; ++i) { + if (i % rowComps === 0) { + buf = 0; + bits = 0; + } + while (bits < bpc) { + buf = buf << 8 | buffer[bufferPos++]; + bits += 8; + } + var remainingBits = bits - bpc; + var value = buf >> remainingBits; + output[i] = value < 0 ? 0 : value > max ? max : value; + buf = buf & (1 << remainingBits) - 1; + bits = remainingBits; + } + } + return output; + }, + fillOpacity: function PDFImage_fillOpacity(rgbaBuf, width, height, actualHeight, image) { + var smask = this.smask; + var mask = this.mask; + var alphaBuf, sw, sh, i, ii, j; + if (smask) { + sw = smask.width; + sh = smask.height; + alphaBuf = new Uint8Array(sw * sh); + smask.fillGrayBuffer(alphaBuf); + if (sw !== width || sh !== height) { + alphaBuf = resizeImageMask(alphaBuf, smask.bpc, sw, sh, width, height); + } + } else if (mask) { + if (mask instanceof PDFImage) { + sw = mask.width; + sh = mask.height; + alphaBuf = new Uint8Array(sw * sh); + mask.numComps = 1; + mask.fillGrayBuffer(alphaBuf); + for (i = 0, ii = sw * sh; i < ii; ++i) { + alphaBuf[i] = 255 - alphaBuf[i]; + } + if (sw !== width || sh !== height) { + alphaBuf = resizeImageMask(alphaBuf, mask.bpc, sw, sh, width, height); + } + } else if ((0, _util.isArray)(mask)) { + alphaBuf = new Uint8Array(width * height); + var numComps = this.numComps; + for (i = 0, ii = width * height; i < ii; ++i) { + var opacity = 0; + var imageOffset = i * numComps; + for (j = 0; j < numComps; ++j) { + var color = image[imageOffset + j]; + var maskOffset = j * 2; + if (color < mask[maskOffset] || color > mask[maskOffset + 1]) { + opacity = 255; + break; + } + } + alphaBuf[i] = opacity; + } + } else { + throw new _util.FormatError('Unknown mask format.'); + } + } + if (alphaBuf) { + for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) { + rgbaBuf[j] = alphaBuf[i]; + } + } else { + for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) { + rgbaBuf[j] = 255; + } + } + }, + undoPreblend: function PDFImage_undoPreblend(buffer, width, height) { + var 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; + var r, g, b; + for (var i = 0; i < length; i += 4) { + var alpha = buffer[i + 3]; + if (alpha === 0) { + buffer[i] = 255; + buffer[i + 1] = 255; + buffer[i + 2] = 255; + continue; + } + var k = 255 / alpha; + r = (buffer[i] - matteR) * k + matteR; + g = (buffer[i + 1] - matteG) * k + matteG; + b = (buffer[i + 2] - matteB) * k + matteB; + buffer[i] = r <= 0 ? 0 : r >= 255 ? 255 : r | 0; + buffer[i + 1] = g <= 0 ? 0 : g >= 255 ? 255 : g | 0; + buffer[i + 2] = b <= 0 ? 0 : b >= 255 ? 255 : b | 0; + } + }, + createImageData: function PDFImage_createImageData(forceRGBA) { + var drawWidth = this.drawWidth; + var drawHeight = this.drawHeight; + var imgData = { + width: drawWidth, + height: drawHeight + }; + 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; + if (!forceRGBA) { + var kind; + if (this.colorSpace.name === 'DeviceGray' && bpc === 1) { + kind = _util.ImageKind.GRAYSCALE_1BPP; + } else if (this.colorSpace.name === 'DeviceRGB' && bpc === 8 && !this.needsDecode) { + kind = _util.ImageKind.RGB_24BPP; + } + 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 Uint8Array(imgArray.length); + newArray.set(imgArray); + imgData.data = newArray; + } + if (this.needsDecode) { + (0, _util.assert)(kind === _util.ImageKind.GRAYSCALE_1BPP); + var buffer = imgData.data; + for (var i = 0, ii = buffer.length; i < ii; i++) { + buffer[i] ^= 0xff; + } + } + return imgData; + } + if (this.image instanceof _stream.JpegStream && !this.smask && !this.mask && (this.colorSpace.name === 'DeviceGray' || this.colorSpace.name === 'DeviceRGB' || this.colorSpace.name === 'DeviceCMYK')) { + imgData.kind = _util.ImageKind.RGB_24BPP; + imgData.data = this.getImageBytes(originalHeight * rowBytes, drawWidth, drawHeight, true); + return imgData; + } + } + imgArray = this.getImageBytes(originalHeight * rowBytes); + var actualHeight = 0 | imgArray.length / rowBytes * drawHeight / originalHeight; + var comps = this.getComponents(imgArray); + var alpha01, maybeUndoPreblend; + if (!forceRGBA && !this.smask && !this.mask) { + imgData.kind = _util.ImageKind.RGB_24BPP; + imgData.data = new Uint8Array(drawWidth * drawHeight * 3); + alpha01 = 0; + maybeUndoPreblend = false; + } else { + imgData.kind = _util.ImageKind.RGBA_32BPP; + imgData.data = new Uint8Array(drawWidth * drawHeight * 4); + alpha01 = 1; + maybeUndoPreblend = true; + this.fillOpacity(imgData.data, drawWidth, drawHeight, actualHeight, comps); + } + if (this.needsDecode) { + this.decodeBuffer(comps); + } + this.colorSpace.fillRgb(imgData.data, originalWidth, originalHeight, drawWidth, drawHeight, actualHeight, bpc, comps, alpha01); + if (maybeUndoPreblend) { + this.undoPreblend(imgData.data, drawWidth, actualHeight); + } + return imgData; + }, + fillGrayBuffer: function PDFImage_fillGrayBuffer(buffer) { + var 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; + if (bpc === 1) { + length = width * height; + if (this.needsDecode) { + for (i = 0; i < length; ++i) { + buffer[i] = comps[i] - 1 & 255; + } + } else { + for (i = 0; i < length; ++i) { + buffer[i] = -comps[i] & 255; + } + } + return; + } + if (this.needsDecode) { + this.decodeBuffer(comps); + } + length = width * height; + var scale = 255 / ((1 << bpc) - 1); + for (i = 0; i < length; ++i) { + buffer[i] = scale * comps[i] | 0; + } + }, + getImageBytes: function PDFImage_getImageBytes(length, drawWidth, drawHeight, forceRGB) { + this.image.reset(); + this.image.drawWidth = drawWidth || this.width; + this.image.drawHeight = drawHeight || this.height; + this.image.forceRGB = !!forceRGB; + return this.image.getBytes(length); + } + }; + return PDFImage; + }(); + exports.PDFImage = PDFImage; + + /***/ + }), + /* 27 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.Jbig2Image = undefined; + + var _util = __w_pdfjs_require__(0); + + var _arithmetic_decoder = __w_pdfjs_require__(9); + + var Jbig2Error = function Jbig2ErrorClosure() { + function Jbig2Error(msg) { + this.message = 'JBIG2 error: ' + msg; + } + + Jbig2Error.prototype = new Error(); + Jbig2Error.prototype.name = 'Jbig2Error'; + Jbig2Error.constructor = Jbig2Error; + return Jbig2Error; + }(); + var Jbig2Image = function Jbig2ImageClosure() { + function ContextCache() { + } + + ContextCache.prototype = { + getContexts: function 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); + return sign === 0 ? value : value > 0 ? -value : 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) { + throw new Jbig2Error('MMR encoding is not supported'); + } + 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) { + if (huffman) { + throw new Jbig2Error('huffman is not supported'); + } + var newSymbols = []; + var currentHeight = 0; + var symbolCodeLength = (0, _util.log2)(symbols.length + numberOfNewSymbols); + var decoder = decodingContext.decoder; + var contextCache = decodingContext.contextCache; + while (newSymbols.length < numberOfNewSymbols) { + var deltaHeight = decodeInteger(contextCache, 'IADH', decoder); + currentHeight += deltaHeight; + var currentWidth = 0; + while (true) { + var deltaWidth = decodeInteger(contextCache, 'IADW', decoder); + if (deltaWidth === null) { + break; + } + currentWidth += deltaWidth; + 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); + } 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); + } + } else { + bitmap = decodeBitmap(false, currentWidth, currentHeight, templateIndex, false, null, at, decodingContext); + } + newSymbols.push(bitmap); + } + } + var exportedSymbols = []; + var flags = [], + currentFlag = false; + var totalSymbolsLength = symbols.length + numberOfNewSymbols; + while (flags.length < totalSymbolsLength) { + var runLength = 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) { + if (huffman) { + throw new Jbig2Error('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 = -decodeInteger(contextCache, 'IADT', decoder); + var firstS = 0; + i = 0; + while (i < numberOfSymbolInstances) { + var deltaT = decodeInteger(contextCache, 'IADT', decoder); + stripT += deltaT; + var deltaFirstS = decodeInteger(contextCache, 'IAFS', decoder); + firstS += deltaFirstS; + var currentS = firstS; + do { + var currentT = stripSize === 1 ? 0 : decodeInteger(contextCache, 'IAIT', decoder); + var t = stripSize * stripT + currentT; + var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength); + var applyRefinement = refinement && 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); + var offsetS = currentS - (referenceCorner & 2 ? symbolWidth : 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 = decodeInteger(contextCache, 'IADS', decoder); + if (deltaS === null) { + break; + } + currentS += deltaS + dsOffset; + } while (true); + } + return bitmap; + } + + function readSegmentHeader(data, start) { + var segmentHeader = {}; + segmentHeader.number = (0, _util.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, _util.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; + var referredToSegmentNumberSize = segmentHeader.number <= 256 ? 1 : segmentHeader.number <= 65536 ? 2 : 4; + var referredTo = []; + var i, ii; + for (i = 0; i < referredToCount; i++) { + var number = referredToSegmentNumberSize === 1 ? data[position] : referredToSegmentNumberSize === 2 ? (0, _util.readUint16)(data, position) : (0, _util.readUint32)(data, position); + referredTo.push(number); + position += referredToSegmentNumberSize; + } + segmentHeader.referredTo = referredTo; + if (!pageAssociationFieldSize) { + segmentHeader.pageAssociation = data[position++]; + } else { + segmentHeader.pageAssociation = (0, _util.readUint32)(data, position); + position += 4; + } + segmentHeader.length = (0, _util.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: 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, _util.readUint32)(data, start), + height: (0, _util.readUint32)(data, start + 4), + x: (0, _util.readUint32)(data, start + 8), + y: (0, _util.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, _util.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, _util.readInt8)(data, position), + y: (0, _util.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, _util.readInt8)(data, position), + y: (0, _util.readInt8)(data, position + 1) + }); + position += 2; + } + dictionary.refinementAt = at; + } + dictionary.numberOfExportedSymbols = (0, _util.readUint32)(data, position); + position += 4; + dictionary.numberOfNewSymbols = (0, _util.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, _util.readUint16)(data, position); + position += 2; + textRegion.huffman = !!(textRegionSegmentFlags & 1); + textRegion.refinement = !!(textRegionSegmentFlags & 2); + textRegion.stripSize = 1 << (textRegionSegmentFlags >> 2 & 3); + 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, _util.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 & 14); + } + if (textRegion.refinement && !textRegion.refinementTemplate) { + at = []; + for (i = 0; i < 2; i++) { + at.push({ + x: (0, _util.readInt8)(data, position), + y: (0, _util.readInt8)(data, position + 1) + }); + position += 2; + } + textRegion.refinementAt = at; + } + textRegion.numberOfSymbolInstances = (0, _util.readUint32)(data, position); + position += 4; + if (textRegion.huffman) { + throw new Jbig2Error('huffman is not supported'); + } + args = [textRegion, 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, _util.readInt8)(data, position), + y: (0, _util.readInt8)(data, position + 1) + }); + position += 2; + } + genericRegion.at = at; + } + args = [genericRegion, data, position, end]; + break; + case 48: + var pageInfo = { + width: (0, _util.readUint32)(data, position), + height: (0, _util.readUint32)(data, position + 4), + resolutionX: (0, _util.readUint32)(data, position + 8), + resolutionY: (0, _util.readUint32)(data, position + 12) + }; + if (pageInfo.height === 0xFFFFFFFF) { + delete pageInfo.height; + } + var pageSegmentFlags = data[position + 16]; + (0, _util.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 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 parseJbig2(data, start, end) { + var position = start; + 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('invalid header'); + } + var header = {}; + position += 8; + var flags = data[position++]; + header.randomAccess = !(flags & 1); + if (!(flags & 2)) { + header.numberOfPages = (0, _util.readUint32)(data, position); + position += 4; + } + readSegments(header, data, position, end); + throw new Error('Not implemented'); + } + + 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 SimpleSegmentVisitor() { + } + + SimpleSegmentVisitor.prototype = { + onPageInformation: function SimpleSegmentVisitor_onPageInformation(info) { + this.currentPageInfo = info; + var rowSize = info.width + 7 >> 3; + var buffer = new Uint8Array(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) { + var huffmanTables; + if (dictionary.huffman) { + throw new Jbig2Error('huffman is not supported'); + } + var symbols = this.symbols; + if (!symbols) { + this.symbols = symbols = {}; + } + var inputSymbols = []; + for (var i = 0, ii = referredSegments.length; i < ii; i++) { + inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]); + } + 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); + }, + onImmediateTextRegion: function SimpleSegmentVisitor_onImmediateTextRegion(region, referredSegments, data, start, end) { + var regionInfo = region.info; + var huffmanTables; + var symbols = this.symbols; + var inputSymbols = []; + for (var i = 0, ii = referredSegments.length; i < ii; i++) { + inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]); + } + var symbolCodeLength = (0, _util.log2)(inputSymbols.length); + 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); + this.drawBitmap(regionInfo, bitmap); + }, + onImmediateLosslessTextRegion: function SimpleSegmentVisitor_onImmediateLosslessTextRegion() { + this.onImmediateTextRegion.apply(this, arguments); + } + }; + + function Jbig2Image() { + } + + Jbig2Image.prototype = { + parseChunks: function Jbig2Image_parseChunks(chunks) { + return parseJbig2Chunks(chunks); + } + }; + return Jbig2Image; + }(); + exports.Jbig2Image = Jbig2Image; + + /***/ + }), + /* 28 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.JpegImage = undefined; + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + var _util = __w_pdfjs_require__(0); + + var JpegError = function JpegErrorClosure() { + function JpegError(msg) { + this.message = 'JPEG error: ' + msg; + } + + JpegError.prototype = new Error(); + JpegError.prototype.name = 'JpegError'; + JpegError.constructor = JpegError; + return JpegError; + }(); + 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() { + this.decodeTransform = null; + this.colorTransform = -1; + } + + 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) { + var mcusPerLine = frame.mcusPerLine; + var progressive = frame.progressive; + var startOffset = offset, + 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) { + 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()]; + if (typeof node === 'number') { + return node; + } + if ((typeof node === 'undefined' ? 'undefined' : _typeof(node)) !== 'object') { + 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, offset) { + var t = decodeHuffman(component.huffmanTableDC); + var diff = t === 0 ? 0 : receiveAndExtend(t); + component.blockData[offset] = 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[offset + z] = receiveAndExtend(s); + k++; + } + } + + function decodeDCFirst(component, offset) { + var t = decodeHuffman(component.huffmanTableDC); + var diff = t === 0 ? 0 : receiveAndExtend(t) << successive; + component.blockData[offset] = component.pred += diff; + } + + function decodeDCSuccessive(component, offset) { + component.blockData[offset] |= readBit() << successive; + } + + var eobrun = 0; + + function decodeACFirst(component, offset) { + 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[offset + z] = receiveAndExtend(s) * (1 << successive); + k++; + } + } + + var successiveACState = 0, + successiveACNextValue; + + function decodeACSuccessive(component, offset) { + var k = spectralStart; + var e = spectralEnd; + var r = 0; + var s; + var rs; + while (k <= e) { + var z = dctZigZag[k]; + 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[offset + z]) { + component.blockData[offset + z] += readBit() << successive; + } else { + r--; + if (r === 0) { + successiveACState = successiveACState === 2 ? 3 : 0; + } + } + break; + case 3: + if (component.blockData[offset + z]) { + component.blockData[offset + z] += readBit() << successive; + } else { + component.blockData[offset + z] = successiveACNextValue << successive; + successiveACState = 0; + } + break; + case 4: + if (component.blockData[offset + z]) { + component.blockData[offset + z] += readBit() << successive; + } + break; + } + k++; + } + if (successiveACState === 4) { + eobrun--; + if (eobrun === 0) { + successiveACState = 0; + } + } + } + + function decodeMcu(component, decode, mcu, row, col) { + var mcuRow = mcu / mcusPerLine | 0; + var mcuCol = mcu % mcusPerLine; + var blockRow = mcuRow * component.v + row; + var blockCol = mcuCol * component.h + col; + var offset = getBlockBufferOffset(component, blockRow, blockCol); + decode(component, offset); + } + + function decodeBlock(component, decode, mcu) { + var blockRow = mcu / component.blocksPerLine | 0; + var blockCol = mcu % component.blocksPerLine; + var offset = getBlockBufferOffset(component, blockRow, blockCol); + decode(component, offset); + } + + 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; + 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 && fileMarker.invalid) { + (0, _util.warn)('decodeScan - unexpected MCU data, next marker is: ' + fileMarker.invalid); + offset = fileMarker.offset; + } + var marker = fileMarker && fileMarker.marker; + if (!marker || marker <= 0xFF00) { + throw new JpegError('marker was not found'); + } + if (marker >= 0xFFD0 && marker <= 0xFFD7) { + offset += 2; + } else { + break; + } + } + fileMarker = findNextFileMarker(data, offset); + if (fileMarker && fileMarker.invalid) { + (0, _util.warn)('decodeScan - unexpected Scan data, next marker is: ' + fileMarker.invalid); + offset = fileMarker.offset; + } + 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; + t = t < -2040 ? 0 : t >= 2024 ? 255 : 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; + p0 = p0 < 16 ? 0 : p0 >= 4080 ? 255 : p0 >> 4; + p1 = p1 < 16 ? 0 : p1 >= 4080 ? 255 : p1 >> 4; + p2 = p2 < 16 ? 0 : p2 >= 4080 ? 255 : p2 >> 4; + p3 = p3 < 16 ? 0 : p3 >= 4080 ? 255 : p3 >> 4; + p4 = p4 < 16 ? 0 : p4 >= 4080 ? 255 : p4 >> 4; + p5 = p5 < 16 ? 0 : p5 >= 4080 ? 255 : p5 >> 4; + p6 = p6 < 16 ? 0 : p6 >= 4080 ? 255 : p6 >> 4; + p7 = p7 < 16 ? 0 : p7 >= 4080 ? 255 : 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 clamp0to255(a) { + return a <= 0 ? 0 : a >= 255 ? 255 : a; + } + + function findNextFileMarker(data, currentPos, startPos) { + function peekUint16(pos) { + return data[pos] << 8 | data[pos + 1]; + } + + var maxPos = data.length - 1; + var newPos = startPos < currentPos ? startPos : currentPos; + if (currentPos >= maxPos) { + return null; + } + var currentMarker = peekUint16(currentPos); + if (currentMarker >= 0xFFC0 && currentMarker <= 0xFFFE) { + return { + invalid: null, + marker: currentMarker, + offset: currentPos + }; + } + var newMarker = peekUint16(newPos); + while (!(newMarker >= 0xFFC0 && newMarker <= 0xFFFE)) { + if (++newPos >= maxPos) { + return null; + } + newMarker = peekUint16(newPos); + } + return { + invalid: currentMarker.toString(16), + marker: newMarker, + offset: newPos + }; + } + + JpegImage.prototype = { + parse: function parse(data) { + function readUint16() { + var value = data[offset] << 8 | data[offset + 1]; + offset += 2; + return value; + } + + function readDataBlock() { + var length = readUint16(); + var endOffset = offset + length - 2; + var fileMarker = findNextFileMarker(data, endOffset, offset); + if (fileMarker && fileMarker.invalid) { + (0, _util.warn)('readDataBlock - incorrect length, next 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; + var quantizationTables = []; + var huffmanTablesAC = [], + huffmanTablesDC = []; + var fileMarker = readUint16(); + if (fileMarker !== 0xFFD8) { + throw new JpegError('SOI not found'); + } + fileMarker = readUint16(); + 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: + var quantizationTablesLength = readUint16(); + 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] = readUint16(); + } + } 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'); + } + readUint16(); + frame = {}; + frame.extended = fileMarker === 0xFFC1; + frame.progressive = fileMarker === 0xFFC2; + frame.precision = data[offset++]; + frame.scanLines = readUint16(); + frame.samplesPerLine = readUint16(); + 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: h, + v: v, + quantizationId: qId, + quantizationTable: null + }); + frame.componentIds[componentId] = l - 1; + offset += 3; + } + frame.maxH = maxH; + frame.maxV = maxV; + prepareComponents(frame); + break; + case 0xFFC4: + var huffmanLength = readUint16(); + 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: + readUint16(); + resetInterval = readUint16(); + break; + case 0xFFDA: + readUint16(); + var selectorsCount = data[offset++]; + var components = [], + component; + for (i = 0; i < selectorsCount; i++) { + var componentIndex = frame.componentIds[data[offset++]]; + component = frame.components[componentIndex]; + 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++]; + var processed = decodeScan(data, offset, frame, components, resetInterval, spectralStart, spectralEnd, successiveApproximation >> 4, successiveApproximation & 15); + offset += processed; + break; + case 0xFFFF: + if (data[offset] !== 0xFF) { + offset--; + } + break; + default: + if (data[offset - 3] === 0xFF && data[offset - 2] >= 0xC0 && data[offset - 2] <= 0xFE) { + offset -= 3; + break; + } + throw new JpegError('unknown marker ' + fileMarker.toString(16)); + } + fileMarker = readUint16(); + } + 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({ + 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; + }, + _getLinearizedBlockData: function getLinearizedBlockData(width, height) { + 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 Uint8Array(dataLength); + var xScaleBlockOffset = new Uint32Array(width); + var mask3LSB = 0xfffffff8; + 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; + for (x = 0; x < width; x++) { + j = 0 | x * componentScaleX; + xScaleBlockOffset[x] = (j & mask3LSB) << 3 | j & 7; + } + 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; + } + } + } + var transform = this.decodeTransform; + 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; + }, + _isColorConversionNeeded: function _isColorConversionNeeded() { + if (this.adobe) { + return !!this.adobe.transformCode; + } + if (this.numComponents === 3) { + if (this.colorTransform === 0) { + 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] = clamp0to255(Y - 179.456 + 1.402 * Cr); + data[i + 1] = clamp0to255(Y + 135.459 - 0.344 * Cb - 0.714 * Cr); + data[i + 2] = clamp0to255(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]; + var r = -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); + var g = 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); + var b = -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); + data[offset++] = clamp0to255(r); + data[offset++] = clamp0to255(g); + data[offset++] = clamp0to255(b); + } + return data; + }, + _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] = clamp0to255(434.456 - Y - 1.402 * Cr); + data[i + 1] = clamp0to255(119.541 - Y + 0.344 * Cb + 0.714 * Cr); + data[i + 2] = clamp0to255(481.816 - Y - 1.772 * Cb); + } + return data; + }, + _convertCmykToRgb: function convertCmykToRgb(data) { + var c, m, y, k; + var offset = 0; + var min = -255 * 255 * 255; + var scale = 1 / 255 / 255; + 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]; + var r = c * (-4.387332384609988 * c + 54.48615194189176 * m + 18.82290502165302 * y + 212.25662451639585 * k - 72734.4411664936) + m * (1.7149763477362134 * m - 5.6096736904047315 * y - 17.873870861415444 * k - 1401.7366389350734) + y * (-2.5217340131683033 * y - 21.248923337353073 * k + 4465.541406466231) - k * (21.86122147463605 * k + 48317.86113160301); + var g = c * (8.841041422036149 * c + 60.118027045597366 * m + 6.871425592049007 * y + 31.159100130055922 * k - 20220.756542821975) + m * (-15.310361306967817 * m + 17.575251261109482 * y + 131.35250912493976 * k - 48691.05921601825) + y * (4.444339102852739 * y + 9.8632861493405 * k - 6341.191035517494) - k * (20.737325471181034 * k + 47890.15695978492); + var b = c * (0.8842522430003296 * c + 8.078677503112928 * m + 30.89978309703729 * y - 0.23883238689178934 * k - 3616.812083916688) + m * (10.49593273432072 * m + 63.02378494754052 * y + 50.606957656360734 * k - 28620.90484698408) + y * (0.03296041114873217 * y + 115.60384449646641 * k - 49363.43385999684) - k * (22.33816807309886 * k + 45932.16563550634); + data[offset++] = r >= 0 ? 255 : r <= min ? 0 : 255 + r * scale | 0; + data[offset++] = g >= 0 ? 255 : g <= min ? 0 : 255 + g * scale | 0; + data[offset++] = b >= 0 ? 255 : b <= min ? 0 : 255 + b * scale | 0; + } + return data; + }, + getData: function getData(width, height, forceRGBoutput) { + if (this.numComponents > 4) { + throw new JpegError('Unsupported color mode'); + } + var data = this._getLinearizedBlockData(width, height); + if (this.numComponents === 1 && forceRGBoutput) { + var dataLength = data.length; + var rgbData = new Uint8Array(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 (forceRGBoutput) { + return this._convertYcckToRgb(data); + } + return this._convertYcckToCmyk(data); + } else if (forceRGBoutput) { + return this._convertCmykToRgb(data); + } + } + return data; + } + }; + return JpegImage; + }(); + exports.JpegImage = JpegImage; + + /***/ + }), + /* 29 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.getMetrics = undefined; + + var _util = __w_pdfjs_require__(0); + + var getMetrics = (0, _util.getLookupTableFactory)(function (t) { + t['Courier'] = 600; + t['Courier-Bold'] = 600; + t['Courier-BoldOblique'] = 600; + t['Courier-Oblique'] = 600; + t['Helvetica'] = (0, _util.getLookupTableFactory)(function (t) { + t['space'] = 278; + t['exclam'] = 278; + t['quotedbl'] = 355; + t['numbersign'] = 556; + t['dollar'] = 556; + t['percent'] = 889; + t['ampersand'] = 667; + t['quoteright'] = 222; + t['parenleft'] = 333; + t['parenright'] = 333; + t['asterisk'] = 389; + t['plus'] = 584; + t['comma'] = 278; + t['hyphen'] = 333; + t['period'] = 278; + t['slash'] = 278; + t['zero'] = 556; + t['one'] = 556; + t['two'] = 556; + t['three'] = 556; + t['four'] = 556; + t['five'] = 556; + t['six'] = 556; + t['seven'] = 556; + t['eight'] = 556; + t['nine'] = 556; + t['colon'] = 278; + t['semicolon'] = 278; + t['less'] = 584; + t['equal'] = 584; + t['greater'] = 584; + t['question'] = 556; + t['at'] = 1015; + t['A'] = 667; + t['B'] = 667; + t['C'] = 722; + t['D'] = 722; + t['E'] = 667; + t['F'] = 611; + t['G'] = 778; + t['H'] = 722; + t['I'] = 278; + t['J'] = 500; + t['K'] = 667; + t['L'] = 556; + t['M'] = 833; + t['N'] = 722; + t['O'] = 778; + t['P'] = 667; + t['Q'] = 778; + t['R'] = 722; + t['S'] = 667; + t['T'] = 611; + t['U'] = 722; + t['V'] = 667; + t['W'] = 944; + t['X'] = 667; + t['Y'] = 667; + t['Z'] = 611; + t['bracketleft'] = 278; + t['backslash'] = 278; + t['bracketright'] = 278; + t['asciicircum'] = 469; + t['underscore'] = 556; + t['quoteleft'] = 222; + t['a'] = 556; + t['b'] = 556; + t['c'] = 500; + t['d'] = 556; + t['e'] = 556; + t['f'] = 278; + t['g'] = 556; + t['h'] = 556; + t['i'] = 222; + t['j'] = 222; + t['k'] = 500; + t['l'] = 222; + t['m'] = 833; + t['n'] = 556; + t['o'] = 556; + t['p'] = 556; + t['q'] = 556; + t['r'] = 333; + t['s'] = 500; + t['t'] = 278; + t['u'] = 556; + t['v'] = 500; + t['w'] = 722; + t['x'] = 500; + t['y'] = 500; + t['z'] = 500; + t['braceleft'] = 334; + t['bar'] = 260; + t['braceright'] = 334; + t['asciitilde'] = 584; + t['exclamdown'] = 333; + t['cent'] = 556; + t['sterling'] = 556; + t['fraction'] = 167; + t['yen'] = 556; + t['florin'] = 556; + t['section'] = 556; + t['currency'] = 556; + t['quotesingle'] = 191; + t['quotedblleft'] = 333; + t['guillemotleft'] = 556; + t['guilsinglleft'] = 333; + t['guilsinglright'] = 333; + t['fi'] = 500; + t['fl'] = 500; + t['endash'] = 556; + t['dagger'] = 556; + t['daggerdbl'] = 556; + t['periodcentered'] = 278; + t['paragraph'] = 537; + t['bullet'] = 350; + t['quotesinglbase'] = 222; + t['quotedblbase'] = 333; + t['quotedblright'] = 333; + t['guillemotright'] = 556; + t['ellipsis'] = 1000; + t['perthousand'] = 1000; + t['questiondown'] = 611; + t['grave'] = 333; + t['acute'] = 333; + t['circumflex'] = 333; + t['tilde'] = 333; + t['macron'] = 333; + t['breve'] = 333; + t['dotaccent'] = 333; + t['dieresis'] = 333; + t['ring'] = 333; + t['cedilla'] = 333; + t['hungarumlaut'] = 333; + t['ogonek'] = 333; + t['caron'] = 333; + t['emdash'] = 1000; + t['AE'] = 1000; + t['ordfeminine'] = 370; + t['Lslash'] = 556; + t['Oslash'] = 778; + t['OE'] = 1000; + t['ordmasculine'] = 365; + t['ae'] = 889; + t['dotlessi'] = 278; + t['lslash'] = 222; + t['oslash'] = 611; + t['oe'] = 944; + t['germandbls'] = 611; + t['Idieresis'] = 278; + t['eacute'] = 556; + t['abreve'] = 556; + t['uhungarumlaut'] = 556; + t['ecaron'] = 556; + t['Ydieresis'] = 667; + t['divide'] = 584; + t['Yacute'] = 667; + t['Acircumflex'] = 667; + t['aacute'] = 556; + t['Ucircumflex'] = 722; + t['yacute'] = 500; + t['scommaaccent'] = 500; + t['ecircumflex'] = 556; + t['Uring'] = 722; + t['Udieresis'] = 722; + t['aogonek'] = 556; + t['Uacute'] = 722; + t['uogonek'] = 556; + t['Edieresis'] = 667; + t['Dcroat'] = 722; + t['commaaccent'] = 250; + t['copyright'] = 737; + t['Emacron'] = 667; + t['ccaron'] = 500; + t['aring'] = 556; + t['Ncommaaccent'] = 722; + t['lacute'] = 222; + t['agrave'] = 556; + t['Tcommaaccent'] = 611; + t['Cacute'] = 722; + t['atilde'] = 556; + t['Edotaccent'] = 667; + t['scaron'] = 500; + t['scedilla'] = 500; + t['iacute'] = 278; + t['lozenge'] = 471; + t['Rcaron'] = 722; + t['Gcommaaccent'] = 778; + t['ucircumflex'] = 556; + t['acircumflex'] = 556; + t['Amacron'] = 667; + t['rcaron'] = 333; + t['ccedilla'] = 500; + t['Zdotaccent'] = 611; + t['Thorn'] = 667; + t['Omacron'] = 778; + t['Racute'] = 722; + t['Sacute'] = 667; + t['dcaron'] = 643; + t['Umacron'] = 722; + t['uring'] = 556; + t['threesuperior'] = 333; + t['Ograve'] = 778; + t['Agrave'] = 667; + t['Abreve'] = 667; + t['multiply'] = 584; + t['uacute'] = 556; + t['Tcaron'] = 611; + t['partialdiff'] = 476; + t['ydieresis'] = 500; + t['Nacute'] = 722; + t['icircumflex'] = 278; + t['Ecircumflex'] = 667; + t['adieresis'] = 556; + t['edieresis'] = 556; + t['cacute'] = 500; + t['nacute'] = 556; + t['umacron'] = 556; + t['Ncaron'] = 722; + t['Iacute'] = 278; + t['plusminus'] = 584; + t['brokenbar'] = 260; + t['registered'] = 737; + t['Gbreve'] = 778; + t['Idotaccent'] = 278; + t['summation'] = 600; + t['Egrave'] = 667; + t['racute'] = 333; + t['omacron'] = 556; + t['Zacute'] = 611; + t['Zcaron'] = 611; + t['greaterequal'] = 549; + t['Eth'] = 722; + t['Ccedilla'] = 722; + t['lcommaaccent'] = 222; + t['tcaron'] = 317; + t['eogonek'] = 556; + t['Uogonek'] = 722; + t['Aacute'] = 667; + t['Adieresis'] = 667; + t['egrave'] = 556; + t['zacute'] = 500; + t['iogonek'] = 222; + t['Oacute'] = 778; + t['oacute'] = 556; + t['amacron'] = 556; + t['sacute'] = 500; + t['idieresis'] = 278; + t['Ocircumflex'] = 778; + t['Ugrave'] = 722; + t['Delta'] = 612; + t['thorn'] = 556; + t['twosuperior'] = 333; + t['Odieresis'] = 778; + t['mu'] = 556; + t['igrave'] = 278; + t['ohungarumlaut'] = 556; + t['Eogonek'] = 667; + t['dcroat'] = 556; + t['threequarters'] = 834; + t['Scedilla'] = 667; + t['lcaron'] = 299; + t['Kcommaaccent'] = 667; + t['Lacute'] = 556; + t['trademark'] = 1000; + t['edotaccent'] = 556; + t['Igrave'] = 278; + t['Imacron'] = 278; + t['Lcaron'] = 556; + t['onehalf'] = 834; + t['lessequal'] = 549; + t['ocircumflex'] = 556; + t['ntilde'] = 556; + t['Uhungarumlaut'] = 722; + t['Eacute'] = 667; + t['emacron'] = 556; + t['gbreve'] = 556; + t['onequarter'] = 834; + t['Scaron'] = 667; + t['Scommaaccent'] = 667; + t['Ohungarumlaut'] = 778; + t['degree'] = 400; + t['ograve'] = 556; + t['Ccaron'] = 722; + t['ugrave'] = 556; + t['radical'] = 453; + t['Dcaron'] = 722; + t['rcommaaccent'] = 333; + t['Ntilde'] = 722; + t['otilde'] = 556; + t['Rcommaaccent'] = 722; + t['Lcommaaccent'] = 556; + t['Atilde'] = 667; + t['Aogonek'] = 667; + t['Aring'] = 667; + t['Otilde'] = 778; + t['zdotaccent'] = 500; + t['Ecaron'] = 667; + t['Iogonek'] = 278; + t['kcommaaccent'] = 500; + t['minus'] = 584; + t['Icircumflex'] = 278; + t['ncaron'] = 556; + t['tcommaaccent'] = 278; + t['logicalnot'] = 584; + t['odieresis'] = 556; + t['udieresis'] = 556; + t['notequal'] = 549; + t['gcommaaccent'] = 556; + t['eth'] = 556; + t['zcaron'] = 500; + t['ncommaaccent'] = 556; + t['onesuperior'] = 333; + t['imacron'] = 278; + t['Euro'] = 556; + }); + t['Helvetica-Bold'] = (0, _util.getLookupTableFactory)(function (t) { + t['space'] = 278; + t['exclam'] = 333; + t['quotedbl'] = 474; + t['numbersign'] = 556; + t['dollar'] = 556; + t['percent'] = 889; + t['ampersand'] = 722; + t['quoteright'] = 278; + t['parenleft'] = 333; + t['parenright'] = 333; + t['asterisk'] = 389; + t['plus'] = 584; + t['comma'] = 278; + t['hyphen'] = 333; + t['period'] = 278; + t['slash'] = 278; + t['zero'] = 556; + t['one'] = 556; + t['two'] = 556; + t['three'] = 556; + t['four'] = 556; + t['five'] = 556; + t['six'] = 556; + t['seven'] = 556; + t['eight'] = 556; + t['nine'] = 556; + t['colon'] = 333; + t['semicolon'] = 333; + t['less'] = 584; + t['equal'] = 584; + t['greater'] = 584; + t['question'] = 611; + t['at'] = 975; + t['A'] = 722; + t['B'] = 722; + t['C'] = 722; + t['D'] = 722; + t['E'] = 667; + t['F'] = 611; + t['G'] = 778; + t['H'] = 722; + t['I'] = 278; + t['J'] = 556; + t['K'] = 722; + t['L'] = 611; + t['M'] = 833; + t['N'] = 722; + t['O'] = 778; + t['P'] = 667; + t['Q'] = 778; + t['R'] = 722; + t['S'] = 667; + t['T'] = 611; + t['U'] = 722; + t['V'] = 667; + t['W'] = 944; + t['X'] = 667; + t['Y'] = 667; + t['Z'] = 611; + t['bracketleft'] = 333; + t['backslash'] = 278; + t['bracketright'] = 333; + t['asciicircum'] = 584; + t['underscore'] = 556; + t['quoteleft'] = 278; + t['a'] = 556; + t['b'] = 611; + t['c'] = 556; + t['d'] = 611; + t['e'] = 556; + t['f'] = 333; + t['g'] = 611; + t['h'] = 611; + t['i'] = 278; + t['j'] = 278; + t['k'] = 556; + t['l'] = 278; + t['m'] = 889; + t['n'] = 611; + t['o'] = 611; + t['p'] = 611; + t['q'] = 611; + t['r'] = 389; + t['s'] = 556; + t['t'] = 333; + t['u'] = 611; + t['v'] = 556; + t['w'] = 778; + t['x'] = 556; + t['y'] = 556; + t['z'] = 500; + t['braceleft'] = 389; + t['bar'] = 280; + t['braceright'] = 389; + t['asciitilde'] = 584; + t['exclamdown'] = 333; + t['cent'] = 556; + t['sterling'] = 556; + t['fraction'] = 167; + t['yen'] = 556; + t['florin'] = 556; + t['section'] = 556; + t['currency'] = 556; + t['quotesingle'] = 238; + t['quotedblleft'] = 500; + t['guillemotleft'] = 556; + t['guilsinglleft'] = 333; + t['guilsinglright'] = 333; + t['fi'] = 611; + t['fl'] = 611; + t['endash'] = 556; + t['dagger'] = 556; + t['daggerdbl'] = 556; + t['periodcentered'] = 278; + t['paragraph'] = 556; + t['bullet'] = 350; + t['quotesinglbase'] = 278; + t['quotedblbase'] = 500; + t['quotedblright'] = 500; + t['guillemotright'] = 556; + t['ellipsis'] = 1000; + t['perthousand'] = 1000; + t['questiondown'] = 611; + t['grave'] = 333; + t['acute'] = 333; + t['circumflex'] = 333; + t['tilde'] = 333; + t['macron'] = 333; + t['breve'] = 333; + t['dotaccent'] = 333; + t['dieresis'] = 333; + t['ring'] = 333; + t['cedilla'] = 333; + t['hungarumlaut'] = 333; + t['ogonek'] = 333; + t['caron'] = 333; + t['emdash'] = 1000; + t['AE'] = 1000; + t['ordfeminine'] = 370; + t['Lslash'] = 611; + t['Oslash'] = 778; + t['OE'] = 1000; + t['ordmasculine'] = 365; + t['ae'] = 889; + t['dotlessi'] = 278; + t['lslash'] = 278; + t['oslash'] = 611; + t['oe'] = 944; + t['germandbls'] = 611; + t['Idieresis'] = 278; + t['eacute'] = 556; + t['abreve'] = 556; + t['uhungarumlaut'] = 611; + t['ecaron'] = 556; + t['Ydieresis'] = 667; + t['divide'] = 584; + t['Yacute'] = 667; + t['Acircumflex'] = 722; + t['aacute'] = 556; + t['Ucircumflex'] = 722; + t['yacute'] = 556; + t['scommaaccent'] = 556; + t['ecircumflex'] = 556; + t['Uring'] = 722; + t['Udieresis'] = 722; + t['aogonek'] = 556; + t['Uacute'] = 722; + t['uogonek'] = 611; + t['Edieresis'] = 667; + t['Dcroat'] = 722; + t['commaaccent'] = 250; + t['copyright'] = 737; + t['Emacron'] = 667; + t['ccaron'] = 556; + t['aring'] = 556; + t['Ncommaaccent'] = 722; + t['lacute'] = 278; + t['agrave'] = 556; + t['Tcommaaccent'] = 611; + t['Cacute'] = 722; + t['atilde'] = 556; + t['Edotaccent'] = 667; + t['scaron'] = 556; + t['scedilla'] = 556; + t['iacute'] = 278; + t['lozenge'] = 494; + t['Rcaron'] = 722; + t['Gcommaaccent'] = 778; + t['ucircumflex'] = 611; + t['acircumflex'] = 556; + t['Amacron'] = 722; + t['rcaron'] = 389; + t['ccedilla'] = 556; + t['Zdotaccent'] = 611; + t['Thorn'] = 667; + t['Omacron'] = 778; + t['Racute'] = 722; + t['Sacute'] = 667; + t['dcaron'] = 743; + t['Umacron'] = 722; + t['uring'] = 611; + t['threesuperior'] = 333; + t['Ograve'] = 778; + t['Agrave'] = 722; + t['Abreve'] = 722; + t['multiply'] = 584; + t['uacute'] = 611; + t['Tcaron'] = 611; + t['partialdiff'] = 494; + t['ydieresis'] = 556; + t['Nacute'] = 722; + t['icircumflex'] = 278; + t['Ecircumflex'] = 667; + t['adieresis'] = 556; + t['edieresis'] = 556; + t['cacute'] = 556; + t['nacute'] = 611; + t['umacron'] = 611; + t['Ncaron'] = 722; + t['Iacute'] = 278; + t['plusminus'] = 584; + t['brokenbar'] = 280; + t['registered'] = 737; + t['Gbreve'] = 778; + t['Idotaccent'] = 278; + t['summation'] = 600; + t['Egrave'] = 667; + t['racute'] = 389; + t['omacron'] = 611; + t['Zacute'] = 611; + t['Zcaron'] = 611; + t['greaterequal'] = 549; + t['Eth'] = 722; + t['Ccedilla'] = 722; + t['lcommaaccent'] = 278; + t['tcaron'] = 389; + t['eogonek'] = 556; + t['Uogonek'] = 722; + t['Aacute'] = 722; + t['Adieresis'] = 722; + t['egrave'] = 556; + t['zacute'] = 500; + t['iogonek'] = 278; + t['Oacute'] = 778; + t['oacute'] = 611; + t['amacron'] = 556; + t['sacute'] = 556; + t['idieresis'] = 278; + t['Ocircumflex'] = 778; + t['Ugrave'] = 722; + t['Delta'] = 612; + t['thorn'] = 611; + t['twosuperior'] = 333; + t['Odieresis'] = 778; + t['mu'] = 611; + t['igrave'] = 278; + t['ohungarumlaut'] = 611; + t['Eogonek'] = 667; + t['dcroat'] = 611; + t['threequarters'] = 834; + t['Scedilla'] = 667; + t['lcaron'] = 400; + t['Kcommaaccent'] = 722; + t['Lacute'] = 611; + t['trademark'] = 1000; + t['edotaccent'] = 556; + t['Igrave'] = 278; + t['Imacron'] = 278; + t['Lcaron'] = 611; + t['onehalf'] = 834; + t['lessequal'] = 549; + t['ocircumflex'] = 611; + t['ntilde'] = 611; + t['Uhungarumlaut'] = 722; + t['Eacute'] = 667; + t['emacron'] = 556; + t['gbreve'] = 611; + t['onequarter'] = 834; + t['Scaron'] = 667; + t['Scommaaccent'] = 667; + t['Ohungarumlaut'] = 778; + t['degree'] = 400; + t['ograve'] = 611; + t['Ccaron'] = 722; + t['ugrave'] = 611; + t['radical'] = 549; + t['Dcaron'] = 722; + t['rcommaaccent'] = 389; + t['Ntilde'] = 722; + t['otilde'] = 611; + t['Rcommaaccent'] = 722; + t['Lcommaaccent'] = 611; + t['Atilde'] = 722; + t['Aogonek'] = 722; + t['Aring'] = 722; + t['Otilde'] = 778; + t['zdotaccent'] = 500; + t['Ecaron'] = 667; + t['Iogonek'] = 278; + t['kcommaaccent'] = 556; + t['minus'] = 584; + t['Icircumflex'] = 278; + t['ncaron'] = 611; + t['tcommaaccent'] = 333; + t['logicalnot'] = 584; + t['odieresis'] = 611; + t['udieresis'] = 611; + t['notequal'] = 549; + t['gcommaaccent'] = 611; + t['eth'] = 611; + t['zcaron'] = 500; + t['ncommaaccent'] = 611; + t['onesuperior'] = 333; + t['imacron'] = 278; + t['Euro'] = 556; + }); + t['Helvetica-BoldOblique'] = (0, _util.getLookupTableFactory)(function (t) { + t['space'] = 278; + t['exclam'] = 333; + t['quotedbl'] = 474; + t['numbersign'] = 556; + t['dollar'] = 556; + t['percent'] = 889; + t['ampersand'] = 722; + t['quoteright'] = 278; + t['parenleft'] = 333; + t['parenright'] = 333; + t['asterisk'] = 389; + t['plus'] = 584; + t['comma'] = 278; + t['hyphen'] = 333; + t['period'] = 278; + t['slash'] = 278; + t['zero'] = 556; + t['one'] = 556; + t['two'] = 556; + t['three'] = 556; + t['four'] = 556; + t['five'] = 556; + t['six'] = 556; + t['seven'] = 556; + t['eight'] = 556; + t['nine'] = 556; + t['colon'] = 333; + t['semicolon'] = 333; + t['less'] = 584; + t['equal'] = 584; + t['greater'] = 584; + t['question'] = 611; + t['at'] = 975; + t['A'] = 722; + t['B'] = 722; + t['C'] = 722; + t['D'] = 722; + t['E'] = 667; + t['F'] = 611; + t['G'] = 778; + t['H'] = 722; + t['I'] = 278; + t['J'] = 556; + t['K'] = 722; + t['L'] = 611; + t['M'] = 833; + t['N'] = 722; + t['O'] = 778; + t['P'] = 667; + t['Q'] = 778; + t['R'] = 722; + t['S'] = 667; + t['T'] = 611; + t['U'] = 722; + t['V'] = 667; + t['W'] = 944; + t['X'] = 667; + t['Y'] = 667; + t['Z'] = 611; + t['bracketleft'] = 333; + t['backslash'] = 278; + t['bracketright'] = 333; + t['asciicircum'] = 584; + t['underscore'] = 556; + t['quoteleft'] = 278; + t['a'] = 556; + t['b'] = 611; + t['c'] = 556; + t['d'] = 611; + t['e'] = 556; + t['f'] = 333; + t['g'] = 611; + t['h'] = 611; + t['i'] = 278; + t['j'] = 278; + t['k'] = 556; + t['l'] = 278; + t['m'] = 889; + t['n'] = 611; + t['o'] = 611; + t['p'] = 611; + t['q'] = 611; + t['r'] = 389; + t['s'] = 556; + t['t'] = 333; + t['u'] = 611; + t['v'] = 556; + t['w'] = 778; + t['x'] = 556; + t['y'] = 556; + t['z'] = 500; + t['braceleft'] = 389; + t['bar'] = 280; + t['braceright'] = 389; + t['asciitilde'] = 584; + t['exclamdown'] = 333; + t['cent'] = 556; + t['sterling'] = 556; + t['fraction'] = 167; + t['yen'] = 556; + t['florin'] = 556; + t['section'] = 556; + t['currency'] = 556; + t['quotesingle'] = 238; + t['quotedblleft'] = 500; + t['guillemotleft'] = 556; + t['guilsinglleft'] = 333; + t['guilsinglright'] = 333; + t['fi'] = 611; + t['fl'] = 611; + t['endash'] = 556; + t['dagger'] = 556; + t['daggerdbl'] = 556; + t['periodcentered'] = 278; + t['paragraph'] = 556; + t['bullet'] = 350; + t['quotesinglbase'] = 278; + t['quotedblbase'] = 500; + t['quotedblright'] = 500; + t['guillemotright'] = 556; + t['ellipsis'] = 1000; + t['perthousand'] = 1000; + t['questiondown'] = 611; + t['grave'] = 333; + t['acute'] = 333; + t['circumflex'] = 333; + t['tilde'] = 333; + t['macron'] = 333; + t['breve'] = 333; + t['dotaccent'] = 333; + t['dieresis'] = 333; + t['ring'] = 333; + t['cedilla'] = 333; + t['hungarumlaut'] = 333; + t['ogonek'] = 333; + t['caron'] = 333; + t['emdash'] = 1000; + t['AE'] = 1000; + t['ordfeminine'] = 370; + t['Lslash'] = 611; + t['Oslash'] = 778; + t['OE'] = 1000; + t['ordmasculine'] = 365; + t['ae'] = 889; + t['dotlessi'] = 278; + t['lslash'] = 278; + t['oslash'] = 611; + t['oe'] = 944; + t['germandbls'] = 611; + t['Idieresis'] = 278; + t['eacute'] = 556; + t['abreve'] = 556; + t['uhungarumlaut'] = 611; + t['ecaron'] = 556; + t['Ydieresis'] = 667; + t['divide'] = 584; + t['Yacute'] = 667; + t['Acircumflex'] = 722; + t['aacute'] = 556; + t['Ucircumflex'] = 722; + t['yacute'] = 556; + t['scommaaccent'] = 556; + t['ecircumflex'] = 556; + t['Uring'] = 722; + t['Udieresis'] = 722; + t['aogonek'] = 556; + t['Uacute'] = 722; + t['uogonek'] = 611; + t['Edieresis'] = 667; + t['Dcroat'] = 722; + t['commaaccent'] = 250; + t['copyright'] = 737; + t['Emacron'] = 667; + t['ccaron'] = 556; + t['aring'] = 556; + t['Ncommaaccent'] = 722; + t['lacute'] = 278; + t['agrave'] = 556; + t['Tcommaaccent'] = 611; + t['Cacute'] = 722; + t['atilde'] = 556; + t['Edotaccent'] = 667; + t['scaron'] = 556; + t['scedilla'] = 556; + t['iacute'] = 278; + t['lozenge'] = 494; + t['Rcaron'] = 722; + t['Gcommaaccent'] = 778; + t['ucircumflex'] = 611; + t['acircumflex'] = 556; + t['Amacron'] = 722; + t['rcaron'] = 389; + t['ccedilla'] = 556; + t['Zdotaccent'] = 611; + t['Thorn'] = 667; + t['Omacron'] = 778; + t['Racute'] = 722; + t['Sacute'] = 667; + t['dcaron'] = 743; + t['Umacron'] = 722; + t['uring'] = 611; + t['threesuperior'] = 333; + t['Ograve'] = 778; + t['Agrave'] = 722; + t['Abreve'] = 722; + t['multiply'] = 584; + t['uacute'] = 611; + t['Tcaron'] = 611; + t['partialdiff'] = 494; + t['ydieresis'] = 556; + t['Nacute'] = 722; + t['icircumflex'] = 278; + t['Ecircumflex'] = 667; + t['adieresis'] = 556; + t['edieresis'] = 556; + t['cacute'] = 556; + t['nacute'] = 611; + t['umacron'] = 611; + t['Ncaron'] = 722; + t['Iacute'] = 278; + t['plusminus'] = 584; + t['brokenbar'] = 280; + t['registered'] = 737; + t['Gbreve'] = 778; + t['Idotaccent'] = 278; + t['summation'] = 600; + t['Egrave'] = 667; + t['racute'] = 389; + t['omacron'] = 611; + t['Zacute'] = 611; + t['Zcaron'] = 611; + t['greaterequal'] = 549; + t['Eth'] = 722; + t['Ccedilla'] = 722; + t['lcommaaccent'] = 278; + t['tcaron'] = 389; + t['eogonek'] = 556; + t['Uogonek'] = 722; + t['Aacute'] = 722; + t['Adieresis'] = 722; + t['egrave'] = 556; + t['zacute'] = 500; + t['iogonek'] = 278; + t['Oacute'] = 778; + t['oacute'] = 611; + t['amacron'] = 556; + t['sacute'] = 556; + t['idieresis'] = 278; + t['Ocircumflex'] = 778; + t['Ugrave'] = 722; + t['Delta'] = 612; + t['thorn'] = 611; + t['twosuperior'] = 333; + t['Odieresis'] = 778; + t['mu'] = 611; + t['igrave'] = 278; + t['ohungarumlaut'] = 611; + t['Eogonek'] = 667; + t['dcroat'] = 611; + t['threequarters'] = 834; + t['Scedilla'] = 667; + t['lcaron'] = 400; + t['Kcommaaccent'] = 722; + t['Lacute'] = 611; + t['trademark'] = 1000; + t['edotaccent'] = 556; + t['Igrave'] = 278; + t['Imacron'] = 278; + t['Lcaron'] = 611; + t['onehalf'] = 834; + t['lessequal'] = 549; + t['ocircumflex'] = 611; + t['ntilde'] = 611; + t['Uhungarumlaut'] = 722; + t['Eacute'] = 667; + t['emacron'] = 556; + t['gbreve'] = 611; + t['onequarter'] = 834; + t['Scaron'] = 667; + t['Scommaaccent'] = 667; + t['Ohungarumlaut'] = 778; + t['degree'] = 400; + t['ograve'] = 611; + t['Ccaron'] = 722; + t['ugrave'] = 611; + t['radical'] = 549; + t['Dcaron'] = 722; + t['rcommaaccent'] = 389; + t['Ntilde'] = 722; + t['otilde'] = 611; + t['Rcommaaccent'] = 722; + t['Lcommaaccent'] = 611; + t['Atilde'] = 722; + t['Aogonek'] = 722; + t['Aring'] = 722; + t['Otilde'] = 778; + t['zdotaccent'] = 500; + t['Ecaron'] = 667; + t['Iogonek'] = 278; + t['kcommaaccent'] = 556; + t['minus'] = 584; + t['Icircumflex'] = 278; + t['ncaron'] = 611; + t['tcommaaccent'] = 333; + t['logicalnot'] = 584; + t['odieresis'] = 611; + t['udieresis'] = 611; + t['notequal'] = 549; + t['gcommaaccent'] = 611; + t['eth'] = 611; + t['zcaron'] = 500; + t['ncommaaccent'] = 611; + t['onesuperior'] = 333; + t['imacron'] = 278; + t['Euro'] = 556; + }); + t['Helvetica-Oblique'] = (0, _util.getLookupTableFactory)(function (t) { + t['space'] = 278; + t['exclam'] = 278; + t['quotedbl'] = 355; + t['numbersign'] = 556; + t['dollar'] = 556; + t['percent'] = 889; + t['ampersand'] = 667; + t['quoteright'] = 222; + t['parenleft'] = 333; + t['parenright'] = 333; + t['asterisk'] = 389; + t['plus'] = 584; + t['comma'] = 278; + t['hyphen'] = 333; + t['period'] = 278; + t['slash'] = 278; + t['zero'] = 556; + t['one'] = 556; + t['two'] = 556; + t['three'] = 556; + t['four'] = 556; + t['five'] = 556; + t['six'] = 556; + t['seven'] = 556; + t['eight'] = 556; + t['nine'] = 556; + t['colon'] = 278; + t['semicolon'] = 278; + t['less'] = 584; + t['equal'] = 584; + t['greater'] = 584; + t['question'] = 556; + t['at'] = 1015; + t['A'] = 667; + t['B'] = 667; + t['C'] = 722; + t['D'] = 722; + t['E'] = 667; + t['F'] = 611; + t['G'] = 778; + t['H'] = 722; + t['I'] = 278; + t['J'] = 500; + t['K'] = 667; + t['L'] = 556; + t['M'] = 833; + t['N'] = 722; + t['O'] = 778; + t['P'] = 667; + t['Q'] = 778; + t['R'] = 722; + t['S'] = 667; + t['T'] = 611; + t['U'] = 722; + t['V'] = 667; + t['W'] = 944; + t['X'] = 667; + t['Y'] = 667; + t['Z'] = 611; + t['bracketleft'] = 278; + t['backslash'] = 278; + t['bracketright'] = 278; + t['asciicircum'] = 469; + t['underscore'] = 556; + t['quoteleft'] = 222; + t['a'] = 556; + t['b'] = 556; + t['c'] = 500; + t['d'] = 556; + t['e'] = 556; + t['f'] = 278; + t['g'] = 556; + t['h'] = 556; + t['i'] = 222; + t['j'] = 222; + t['k'] = 500; + t['l'] = 222; + t['m'] = 833; + t['n'] = 556; + t['o'] = 556; + t['p'] = 556; + t['q'] = 556; + t['r'] = 333; + t['s'] = 500; + t['t'] = 278; + t['u'] = 556; + t['v'] = 500; + t['w'] = 722; + t['x'] = 500; + t['y'] = 500; + t['z'] = 500; + t['braceleft'] = 334; + t['bar'] = 260; + t['braceright'] = 334; + t['asciitilde'] = 584; + t['exclamdown'] = 333; + t['cent'] = 556; + t['sterling'] = 556; + t['fraction'] = 167; + t['yen'] = 556; + t['florin'] = 556; + t['section'] = 556; + t['currency'] = 556; + t['quotesingle'] = 191; + t['quotedblleft'] = 333; + t['guillemotleft'] = 556; + t['guilsinglleft'] = 333; + t['guilsinglright'] = 333; + t['fi'] = 500; + t['fl'] = 500; + t['endash'] = 556; + t['dagger'] = 556; + t['daggerdbl'] = 556; + t['periodcentered'] = 278; + t['paragraph'] = 537; + t['bullet'] = 350; + t['quotesinglbase'] = 222; + t['quotedblbase'] = 333; + t['quotedblright'] = 333; + t['guillemotright'] = 556; + t['ellipsis'] = 1000; + t['perthousand'] = 1000; + t['questiondown'] = 611; + t['grave'] = 333; + t['acute'] = 333; + t['circumflex'] = 333; + t['tilde'] = 333; + t['macron'] = 333; + t['breve'] = 333; + t['dotaccent'] = 333; + t['dieresis'] = 333; + t['ring'] = 333; + t['cedilla'] = 333; + t['hungarumlaut'] = 333; + t['ogonek'] = 333; + t['caron'] = 333; + t['emdash'] = 1000; + t['AE'] = 1000; + t['ordfeminine'] = 370; + t['Lslash'] = 556; + t['Oslash'] = 778; + t['OE'] = 1000; + t['ordmasculine'] = 365; + t['ae'] = 889; + t['dotlessi'] = 278; + t['lslash'] = 222; + t['oslash'] = 611; + t['oe'] = 944; + t['germandbls'] = 611; + t['Idieresis'] = 278; + t['eacute'] = 556; + t['abreve'] = 556; + t['uhungarumlaut'] = 556; + t['ecaron'] = 556; + t['Ydieresis'] = 667; + t['divide'] = 584; + t['Yacute'] = 667; + t['Acircumflex'] = 667; + t['aacute'] = 556; + t['Ucircumflex'] = 722; + t['yacute'] = 500; + t['scommaaccent'] = 500; + t['ecircumflex'] = 556; + t['Uring'] = 722; + t['Udieresis'] = 722; + t['aogonek'] = 556; + t['Uacute'] = 722; + t['uogonek'] = 556; + t['Edieresis'] = 667; + t['Dcroat'] = 722; + t['commaaccent'] = 250; + t['copyright'] = 737; + t['Emacron'] = 667; + t['ccaron'] = 500; + t['aring'] = 556; + t['Ncommaaccent'] = 722; + t['lacute'] = 222; + t['agrave'] = 556; + t['Tcommaaccent'] = 611; + t['Cacute'] = 722; + t['atilde'] = 556; + t['Edotaccent'] = 667; + t['scaron'] = 500; + t['scedilla'] = 500; + t['iacute'] = 278; + t['lozenge'] = 471; + t['Rcaron'] = 722; + t['Gcommaaccent'] = 778; + t['ucircumflex'] = 556; + t['acircumflex'] = 556; + t['Amacron'] = 667; + t['rcaron'] = 333; + t['ccedilla'] = 500; + t['Zdotaccent'] = 611; + t['Thorn'] = 667; + t['Omacron'] = 778; + t['Racute'] = 722; + t['Sacute'] = 667; + t['dcaron'] = 643; + t['Umacron'] = 722; + t['uring'] = 556; + t['threesuperior'] = 333; + t['Ograve'] = 778; + t['Agrave'] = 667; + t['Abreve'] = 667; + t['multiply'] = 584; + t['uacute'] = 556; + t['Tcaron'] = 611; + t['partialdiff'] = 476; + t['ydieresis'] = 500; + t['Nacute'] = 722; + t['icircumflex'] = 278; + t['Ecircumflex'] = 667; + t['adieresis'] = 556; + t['edieresis'] = 556; + t['cacute'] = 500; + t['nacute'] = 556; + t['umacron'] = 556; + t['Ncaron'] = 722; + t['Iacute'] = 278; + t['plusminus'] = 584; + t['brokenbar'] = 260; + t['registered'] = 737; + t['Gbreve'] = 778; + t['Idotaccent'] = 278; + t['summation'] = 600; + t['Egrave'] = 667; + t['racute'] = 333; + t['omacron'] = 556; + t['Zacute'] = 611; + t['Zcaron'] = 611; + t['greaterequal'] = 549; + t['Eth'] = 722; + t['Ccedilla'] = 722; + t['lcommaaccent'] = 222; + t['tcaron'] = 317; + t['eogonek'] = 556; + t['Uogonek'] = 722; + t['Aacute'] = 667; + t['Adieresis'] = 667; + t['egrave'] = 556; + t['zacute'] = 500; + t['iogonek'] = 222; + t['Oacute'] = 778; + t['oacute'] = 556; + t['amacron'] = 556; + t['sacute'] = 500; + t['idieresis'] = 278; + t['Ocircumflex'] = 778; + t['Ugrave'] = 722; + t['Delta'] = 612; + t['thorn'] = 556; + t['twosuperior'] = 333; + t['Odieresis'] = 778; + t['mu'] = 556; + t['igrave'] = 278; + t['ohungarumlaut'] = 556; + t['Eogonek'] = 667; + t['dcroat'] = 556; + t['threequarters'] = 834; + t['Scedilla'] = 667; + t['lcaron'] = 299; + t['Kcommaaccent'] = 667; + t['Lacute'] = 556; + t['trademark'] = 1000; + t['edotaccent'] = 556; + t['Igrave'] = 278; + t['Imacron'] = 278; + t['Lcaron'] = 556; + t['onehalf'] = 834; + t['lessequal'] = 549; + t['ocircumflex'] = 556; + t['ntilde'] = 556; + t['Uhungarumlaut'] = 722; + t['Eacute'] = 667; + t['emacron'] = 556; + t['gbreve'] = 556; + t['onequarter'] = 834; + t['Scaron'] = 667; + t['Scommaaccent'] = 667; + t['Ohungarumlaut'] = 778; + t['degree'] = 400; + t['ograve'] = 556; + t['Ccaron'] = 722; + t['ugrave'] = 556; + t['radical'] = 453; + t['Dcaron'] = 722; + t['rcommaaccent'] = 333; + t['Ntilde'] = 722; + t['otilde'] = 556; + t['Rcommaaccent'] = 722; + t['Lcommaaccent'] = 556; + t['Atilde'] = 667; + t['Aogonek'] = 667; + t['Aring'] = 667; + t['Otilde'] = 778; + t['zdotaccent'] = 500; + t['Ecaron'] = 667; + t['Iogonek'] = 278; + t['kcommaaccent'] = 500; + t['minus'] = 584; + t['Icircumflex'] = 278; + t['ncaron'] = 556; + t['tcommaaccent'] = 278; + t['logicalnot'] = 584; + t['odieresis'] = 556; + t['udieresis'] = 556; + t['notequal'] = 549; + t['gcommaaccent'] = 556; + t['eth'] = 556; + t['zcaron'] = 500; + t['ncommaaccent'] = 556; + t['onesuperior'] = 333; + t['imacron'] = 278; + t['Euro'] = 556; + }); + t['Symbol'] = (0, _util.getLookupTableFactory)(function (t) { + t['space'] = 250; + t['exclam'] = 333; + t['universal'] = 713; + t['numbersign'] = 500; + t['existential'] = 549; + t['percent'] = 833; + t['ampersand'] = 778; + t['suchthat'] = 439; + t['parenleft'] = 333; + t['parenright'] = 333; + t['asteriskmath'] = 500; + t['plus'] = 549; + t['comma'] = 250; + t['minus'] = 549; + t['period'] = 250; + t['slash'] = 278; + t['zero'] = 500; + t['one'] = 500; + t['two'] = 500; + t['three'] = 500; + t['four'] = 500; + t['five'] = 500; + t['six'] = 500; + t['seven'] = 500; + t['eight'] = 500; + t['nine'] = 500; + t['colon'] = 278; + t['semicolon'] = 278; + t['less'] = 549; + t['equal'] = 549; + t['greater'] = 549; + t['question'] = 444; + t['congruent'] = 549; + t['Alpha'] = 722; + t['Beta'] = 667; + t['Chi'] = 722; + t['Delta'] = 612; + t['Epsilon'] = 611; + t['Phi'] = 763; + t['Gamma'] = 603; + t['Eta'] = 722; + t['Iota'] = 333; + t['theta1'] = 631; + t['Kappa'] = 722; + t['Lambda'] = 686; + t['Mu'] = 889; + t['Nu'] = 722; + t['Omicron'] = 722; + t['Pi'] = 768; + t['Theta'] = 741; + t['Rho'] = 556; + t['Sigma'] = 592; + t['Tau'] = 611; + t['Upsilon'] = 690; + t['sigma1'] = 439; + t['Omega'] = 768; + t['Xi'] = 645; + t['Psi'] = 795; + t['Zeta'] = 611; + t['bracketleft'] = 333; + t['therefore'] = 863; + t['bracketright'] = 333; + t['perpendicular'] = 658; + t['underscore'] = 500; + t['radicalex'] = 500; + t['alpha'] = 631; + t['beta'] = 549; + t['chi'] = 549; + t['delta'] = 494; + t['epsilon'] = 439; + t['phi'] = 521; + t['gamma'] = 411; + t['eta'] = 603; + t['iota'] = 329; + t['phi1'] = 603; + t['kappa'] = 549; + t['lambda'] = 549; + t['mu'] = 576; + t['nu'] = 521; + t['omicron'] = 549; + t['pi'] = 549; + t['theta'] = 521; + t['rho'] = 549; + t['sigma'] = 603; + t['tau'] = 439; + t['upsilon'] = 576; + t['omega1'] = 713; + t['omega'] = 686; + t['xi'] = 493; + t['psi'] = 686; + t['zeta'] = 494; + t['braceleft'] = 480; + t['bar'] = 200; + t['braceright'] = 480; + t['similar'] = 549; + t['Euro'] = 750; + t['Upsilon1'] = 620; + t['minute'] = 247; + t['lessequal'] = 549; + t['fraction'] = 167; + t['infinity'] = 713; + t['florin'] = 500; + t['club'] = 753; + t['diamond'] = 753; + t['heart'] = 753; + t['spade'] = 753; + t['arrowboth'] = 1042; + t['arrowleft'] = 987; + t['arrowup'] = 603; + t['arrowright'] = 987; + t['arrowdown'] = 603; + t['degree'] = 400; + t['plusminus'] = 549; + t['second'] = 411; + t['greaterequal'] = 549; + t['multiply'] = 549; + t['proportional'] = 713; + t['partialdiff'] = 494; + t['bullet'] = 460; + t['divide'] = 549; + t['notequal'] = 549; + t['equivalence'] = 549; + t['approxequal'] = 549; + t['ellipsis'] = 1000; + t['arrowvertex'] = 603; + t['arrowhorizex'] = 1000; + t['carriagereturn'] = 658; + t['aleph'] = 823; + t['Ifraktur'] = 686; + t['Rfraktur'] = 795; + t['weierstrass'] = 987; + t['circlemultiply'] = 768; + t['circleplus'] = 768; + t['emptyset'] = 823; + t['intersection'] = 768; + t['union'] = 768; + t['propersuperset'] = 713; + t['reflexsuperset'] = 713; + t['notsubset'] = 713; + t['propersubset'] = 713; + t['reflexsubset'] = 713; + t['element'] = 713; + t['notelement'] = 713; + t['angle'] = 768; + t['gradient'] = 713; + t['registerserif'] = 790; + t['copyrightserif'] = 790; + t['trademarkserif'] = 890; + t['product'] = 823; + t['radical'] = 549; + t['dotmath'] = 250; + t['logicalnot'] = 713; + t['logicaland'] = 603; + t['logicalor'] = 603; + t['arrowdblboth'] = 1042; + t['arrowdblleft'] = 987; + t['arrowdblup'] = 603; + t['arrowdblright'] = 987; + t['arrowdbldown'] = 603; + t['lozenge'] = 494; + t['angleleft'] = 329; + t['registersans'] = 790; + t['copyrightsans'] = 790; + t['trademarksans'] = 786; + t['summation'] = 713; + t['parenlefttp'] = 384; + t['parenleftex'] = 384; + t['parenleftbt'] = 384; + t['bracketlefttp'] = 384; + t['bracketleftex'] = 384; + t['bracketleftbt'] = 384; + t['bracelefttp'] = 494; + t['braceleftmid'] = 494; + t['braceleftbt'] = 494; + t['braceex'] = 494; + t['angleright'] = 329; + t['integral'] = 274; + t['integraltp'] = 686; + t['integralex'] = 686; + t['integralbt'] = 686; + t['parenrighttp'] = 384; + t['parenrightex'] = 384; + t['parenrightbt'] = 384; + t['bracketrighttp'] = 384; + t['bracketrightex'] = 384; + t['bracketrightbt'] = 384; + t['bracerighttp'] = 494; + t['bracerightmid'] = 494; + t['bracerightbt'] = 494; + t['apple'] = 790; + }); + t['Times-Roman'] = (0, _util.getLookupTableFactory)(function (t) { + t['space'] = 250; + t['exclam'] = 333; + t['quotedbl'] = 408; + t['numbersign'] = 500; + t['dollar'] = 500; + t['percent'] = 833; + t['ampersand'] = 778; + t['quoteright'] = 333; + t['parenleft'] = 333; + t['parenright'] = 333; + t['asterisk'] = 500; + t['plus'] = 564; + t['comma'] = 250; + t['hyphen'] = 333; + t['period'] = 250; + t['slash'] = 278; + t['zero'] = 500; + t['one'] = 500; + t['two'] = 500; + t['three'] = 500; + t['four'] = 500; + t['five'] = 500; + t['six'] = 500; + t['seven'] = 500; + t['eight'] = 500; + t['nine'] = 500; + t['colon'] = 278; + t['semicolon'] = 278; + t['less'] = 564; + t['equal'] = 564; + t['greater'] = 564; + t['question'] = 444; + t['at'] = 921; + t['A'] = 722; + t['B'] = 667; + t['C'] = 667; + t['D'] = 722; + t['E'] = 611; + t['F'] = 556; + t['G'] = 722; + t['H'] = 722; + t['I'] = 333; + t['J'] = 389; + t['K'] = 722; + t['L'] = 611; + t['M'] = 889; + t['N'] = 722; + t['O'] = 722; + t['P'] = 556; + t['Q'] = 722; + t['R'] = 667; + t['S'] = 556; + t['T'] = 611; + t['U'] = 722; + t['V'] = 722; + t['W'] = 944; + t['X'] = 722; + t['Y'] = 722; + t['Z'] = 611; + t['bracketleft'] = 333; + t['backslash'] = 278; + t['bracketright'] = 333; + t['asciicircum'] = 469; + t['underscore'] = 500; + t['quoteleft'] = 333; + t['a'] = 444; + t['b'] = 500; + t['c'] = 444; + t['d'] = 500; + t['e'] = 444; + t['f'] = 333; + t['g'] = 500; + t['h'] = 500; + t['i'] = 278; + t['j'] = 278; + t['k'] = 500; + t['l'] = 278; + t['m'] = 778; + t['n'] = 500; + t['o'] = 500; + t['p'] = 500; + t['q'] = 500; + t['r'] = 333; + t['s'] = 389; + t['t'] = 278; + t['u'] = 500; + t['v'] = 500; + t['w'] = 722; + t['x'] = 500; + t['y'] = 500; + t['z'] = 444; + t['braceleft'] = 480; + t['bar'] = 200; + t['braceright'] = 480; + t['asciitilde'] = 541; + t['exclamdown'] = 333; + t['cent'] = 500; + t['sterling'] = 500; + t['fraction'] = 167; + t['yen'] = 500; + t['florin'] = 500; + t['section'] = 500; + t['currency'] = 500; + t['quotesingle'] = 180; + t['quotedblleft'] = 444; + t['guillemotleft'] = 500; + t['guilsinglleft'] = 333; + t['guilsinglright'] = 333; + t['fi'] = 556; + t['fl'] = 556; + t['endash'] = 500; + t['dagger'] = 500; + t['daggerdbl'] = 500; + t['periodcentered'] = 250; + t['paragraph'] = 453; + t['bullet'] = 350; + t['quotesinglbase'] = 333; + t['quotedblbase'] = 444; + t['quotedblright'] = 444; + t['guillemotright'] = 500; + t['ellipsis'] = 1000; + t['perthousand'] = 1000; + t['questiondown'] = 444; + t['grave'] = 333; + t['acute'] = 333; + t['circumflex'] = 333; + t['tilde'] = 333; + t['macron'] = 333; + t['breve'] = 333; + t['dotaccent'] = 333; + t['dieresis'] = 333; + t['ring'] = 333; + t['cedilla'] = 333; + t['hungarumlaut'] = 333; + t['ogonek'] = 333; + t['caron'] = 333; + t['emdash'] = 1000; + t['AE'] = 889; + t['ordfeminine'] = 276; + t['Lslash'] = 611; + t['Oslash'] = 722; + t['OE'] = 889; + t['ordmasculine'] = 310; + t['ae'] = 667; + t['dotlessi'] = 278; + t['lslash'] = 278; + t['oslash'] = 500; + t['oe'] = 722; + t['germandbls'] = 500; + t['Idieresis'] = 333; + t['eacute'] = 444; + t['abreve'] = 444; + t['uhungarumlaut'] = 500; + t['ecaron'] = 444; + t['Ydieresis'] = 722; + t['divide'] = 564; + t['Yacute'] = 722; + t['Acircumflex'] = 722; + t['aacute'] = 444; + t['Ucircumflex'] = 722; + t['yacute'] = 500; + t['scommaaccent'] = 389; + t['ecircumflex'] = 444; + t['Uring'] = 722; + t['Udieresis'] = 722; + t['aogonek'] = 444; + t['Uacute'] = 722; + t['uogonek'] = 500; + t['Edieresis'] = 611; + t['Dcroat'] = 722; + t['commaaccent'] = 250; + t['copyright'] = 760; + t['Emacron'] = 611; + t['ccaron'] = 444; + t['aring'] = 444; + t['Ncommaaccent'] = 722; + t['lacute'] = 278; + t['agrave'] = 444; + t['Tcommaaccent'] = 611; + t['Cacute'] = 667; + t['atilde'] = 444; + t['Edotaccent'] = 611; + t['scaron'] = 389; + t['scedilla'] = 389; + t['iacute'] = 278; + t['lozenge'] = 471; + t['Rcaron'] = 667; + t['Gcommaaccent'] = 722; + t['ucircumflex'] = 500; + t['acircumflex'] = 444; + t['Amacron'] = 722; + t['rcaron'] = 333; + t['ccedilla'] = 444; + t['Zdotaccent'] = 611; + t['Thorn'] = 556; + t['Omacron'] = 722; + t['Racute'] = 667; + t['Sacute'] = 556; + t['dcaron'] = 588; + t['Umacron'] = 722; + t['uring'] = 500; + t['threesuperior'] = 300; + t['Ograve'] = 722; + t['Agrave'] = 722; + t['Abreve'] = 722; + t['multiply'] = 564; + t['uacute'] = 500; + t['Tcaron'] = 611; + t['partialdiff'] = 476; + t['ydieresis'] = 500; + t['Nacute'] = 722; + t['icircumflex'] = 278; + t['Ecircumflex'] = 611; + t['adieresis'] = 444; + t['edieresis'] = 444; + t['cacute'] = 444; + t['nacute'] = 500; + t['umacron'] = 500; + t['Ncaron'] = 722; + t['Iacute'] = 333; + t['plusminus'] = 564; + t['brokenbar'] = 200; + t['registered'] = 760; + t['Gbreve'] = 722; + t['Idotaccent'] = 333; + t['summation'] = 600; + t['Egrave'] = 611; + t['racute'] = 333; + t['omacron'] = 500; + t['Zacute'] = 611; + t['Zcaron'] = 611; + t['greaterequal'] = 549; + t['Eth'] = 722; + t['Ccedilla'] = 667; + t['lcommaaccent'] = 278; + t['tcaron'] = 326; + t['eogonek'] = 444; + t['Uogonek'] = 722; + t['Aacute'] = 722; + t['Adieresis'] = 722; + t['egrave'] = 444; + t['zacute'] = 444; + t['iogonek'] = 278; + t['Oacute'] = 722; + t['oacute'] = 500; + t['amacron'] = 444; + t['sacute'] = 389; + t['idieresis'] = 278; + t['Ocircumflex'] = 722; + t['Ugrave'] = 722; + t['Delta'] = 612; + t['thorn'] = 500; + t['twosuperior'] = 300; + t['Odieresis'] = 722; + t['mu'] = 500; + t['igrave'] = 278; + t['ohungarumlaut'] = 500; + t['Eogonek'] = 611; + t['dcroat'] = 500; + t['threequarters'] = 750; + t['Scedilla'] = 556; + t['lcaron'] = 344; + t['Kcommaaccent'] = 722; + t['Lacute'] = 611; + t['trademark'] = 980; + t['edotaccent'] = 444; + t['Igrave'] = 333; + t['Imacron'] = 333; + t['Lcaron'] = 611; + t['onehalf'] = 750; + t['lessequal'] = 549; + t['ocircumflex'] = 500; + t['ntilde'] = 500; + t['Uhungarumlaut'] = 722; + t['Eacute'] = 611; + t['emacron'] = 444; + t['gbreve'] = 500; + t['onequarter'] = 750; + t['Scaron'] = 556; + t['Scommaaccent'] = 556; + t['Ohungarumlaut'] = 722; + t['degree'] = 400; + t['ograve'] = 500; + t['Ccaron'] = 667; + t['ugrave'] = 500; + t['radical'] = 453; + t['Dcaron'] = 722; + t['rcommaaccent'] = 333; + t['Ntilde'] = 722; + t['otilde'] = 500; + t['Rcommaaccent'] = 667; + t['Lcommaaccent'] = 611; + t['Atilde'] = 722; + t['Aogonek'] = 722; + t['Aring'] = 722; + t['Otilde'] = 722; + t['zdotaccent'] = 444; + t['Ecaron'] = 611; + t['Iogonek'] = 333; + t['kcommaaccent'] = 500; + t['minus'] = 564; + t['Icircumflex'] = 333; + t['ncaron'] = 500; + t['tcommaaccent'] = 278; + t['logicalnot'] = 564; + t['odieresis'] = 500; + t['udieresis'] = 500; + t['notequal'] = 549; + t['gcommaaccent'] = 500; + t['eth'] = 500; + t['zcaron'] = 444; + t['ncommaaccent'] = 500; + t['onesuperior'] = 300; + t['imacron'] = 278; + t['Euro'] = 500; + }); + t['Times-Bold'] = (0, _util.getLookupTableFactory)(function (t) { + t['space'] = 250; + t['exclam'] = 333; + t['quotedbl'] = 555; + t['numbersign'] = 500; + t['dollar'] = 500; + t['percent'] = 1000; + t['ampersand'] = 833; + t['quoteright'] = 333; + t['parenleft'] = 333; + t['parenright'] = 333; + t['asterisk'] = 500; + t['plus'] = 570; + t['comma'] = 250; + t['hyphen'] = 333; + t['period'] = 250; + t['slash'] = 278; + t['zero'] = 500; + t['one'] = 500; + t['two'] = 500; + t['three'] = 500; + t['four'] = 500; + t['five'] = 500; + t['six'] = 500; + t['seven'] = 500; + t['eight'] = 500; + t['nine'] = 500; + t['colon'] = 333; + t['semicolon'] = 333; + t['less'] = 570; + t['equal'] = 570; + t['greater'] = 570; + t['question'] = 500; + t['at'] = 930; + t['A'] = 722; + t['B'] = 667; + t['C'] = 722; + t['D'] = 722; + t['E'] = 667; + t['F'] = 611; + t['G'] = 778; + t['H'] = 778; + t['I'] = 389; + t['J'] = 500; + t['K'] = 778; + t['L'] = 667; + t['M'] = 944; + t['N'] = 722; + t['O'] = 778; + t['P'] = 611; + t['Q'] = 778; + t['R'] = 722; + t['S'] = 556; + t['T'] = 667; + t['U'] = 722; + t['V'] = 722; + t['W'] = 1000; + t['X'] = 722; + t['Y'] = 722; + t['Z'] = 667; + t['bracketleft'] = 333; + t['backslash'] = 278; + t['bracketright'] = 333; + t['asciicircum'] = 581; + t['underscore'] = 500; + t['quoteleft'] = 333; + t['a'] = 500; + t['b'] = 556; + t['c'] = 444; + t['d'] = 556; + t['e'] = 444; + t['f'] = 333; + t['g'] = 500; + t['h'] = 556; + t['i'] = 278; + t['j'] = 333; + t['k'] = 556; + t['l'] = 278; + t['m'] = 833; + t['n'] = 556; + t['o'] = 500; + t['p'] = 556; + t['q'] = 556; + t['r'] = 444; + t['s'] = 389; + t['t'] = 333; + t['u'] = 556; + t['v'] = 500; + t['w'] = 722; + t['x'] = 500; + t['y'] = 500; + t['z'] = 444; + t['braceleft'] = 394; + t['bar'] = 220; + t['braceright'] = 394; + t['asciitilde'] = 520; + t['exclamdown'] = 333; + t['cent'] = 500; + t['sterling'] = 500; + t['fraction'] = 167; + t['yen'] = 500; + t['florin'] = 500; + t['section'] = 500; + t['currency'] = 500; + t['quotesingle'] = 278; + t['quotedblleft'] = 500; + t['guillemotleft'] = 500; + t['guilsinglleft'] = 333; + t['guilsinglright'] = 333; + t['fi'] = 556; + t['fl'] = 556; + t['endash'] = 500; + t['dagger'] = 500; + t['daggerdbl'] = 500; + t['periodcentered'] = 250; + t['paragraph'] = 540; + t['bullet'] = 350; + t['quotesinglbase'] = 333; + t['quotedblbase'] = 500; + t['quotedblright'] = 500; + t['guillemotright'] = 500; + t['ellipsis'] = 1000; + t['perthousand'] = 1000; + t['questiondown'] = 500; + t['grave'] = 333; + t['acute'] = 333; + t['circumflex'] = 333; + t['tilde'] = 333; + t['macron'] = 333; + t['breve'] = 333; + t['dotaccent'] = 333; + t['dieresis'] = 333; + t['ring'] = 333; + t['cedilla'] = 333; + t['hungarumlaut'] = 333; + t['ogonek'] = 333; + t['caron'] = 333; + t['emdash'] = 1000; + t['AE'] = 1000; + t['ordfeminine'] = 300; + t['Lslash'] = 667; + t['Oslash'] = 778; + t['OE'] = 1000; + t['ordmasculine'] = 330; + t['ae'] = 722; + t['dotlessi'] = 278; + t['lslash'] = 278; + t['oslash'] = 500; + t['oe'] = 722; + t['germandbls'] = 556; + t['Idieresis'] = 389; + t['eacute'] = 444; + t['abreve'] = 500; + t['uhungarumlaut'] = 556; + t['ecaron'] = 444; + t['Ydieresis'] = 722; + t['divide'] = 570; + t['Yacute'] = 722; + t['Acircumflex'] = 722; + t['aacute'] = 500; + t['Ucircumflex'] = 722; + t['yacute'] = 500; + t['scommaaccent'] = 389; + t['ecircumflex'] = 444; + t['Uring'] = 722; + t['Udieresis'] = 722; + t['aogonek'] = 500; + t['Uacute'] = 722; + t['uogonek'] = 556; + t['Edieresis'] = 667; + t['Dcroat'] = 722; + t['commaaccent'] = 250; + t['copyright'] = 747; + t['Emacron'] = 667; + t['ccaron'] = 444; + t['aring'] = 500; + t['Ncommaaccent'] = 722; + t['lacute'] = 278; + t['agrave'] = 500; + t['Tcommaaccent'] = 667; + t['Cacute'] = 722; + t['atilde'] = 500; + t['Edotaccent'] = 667; + t['scaron'] = 389; + t['scedilla'] = 389; + t['iacute'] = 278; + t['lozenge'] = 494; + t['Rcaron'] = 722; + t['Gcommaaccent'] = 778; + t['ucircumflex'] = 556; + t['acircumflex'] = 500; + t['Amacron'] = 722; + t['rcaron'] = 444; + t['ccedilla'] = 444; + t['Zdotaccent'] = 667; + t['Thorn'] = 611; + t['Omacron'] = 778; + t['Racute'] = 722; + t['Sacute'] = 556; + t['dcaron'] = 672; + t['Umacron'] = 722; + t['uring'] = 556; + t['threesuperior'] = 300; + t['Ograve'] = 778; + t['Agrave'] = 722; + t['Abreve'] = 722; + t['multiply'] = 570; + t['uacute'] = 556; + t['Tcaron'] = 667; + t['partialdiff'] = 494; + t['ydieresis'] = 500; + t['Nacute'] = 722; + t['icircumflex'] = 278; + t['Ecircumflex'] = 667; + t['adieresis'] = 500; + t['edieresis'] = 444; + t['cacute'] = 444; + t['nacute'] = 556; + t['umacron'] = 556; + t['Ncaron'] = 722; + t['Iacute'] = 389; + t['plusminus'] = 570; + t['brokenbar'] = 220; + t['registered'] = 747; + t['Gbreve'] = 778; + t['Idotaccent'] = 389; + t['summation'] = 600; + t['Egrave'] = 667; + t['racute'] = 444; + t['omacron'] = 500; + t['Zacute'] = 667; + t['Zcaron'] = 667; + t['greaterequal'] = 549; + t['Eth'] = 722; + t['Ccedilla'] = 722; + t['lcommaaccent'] = 278; + t['tcaron'] = 416; + t['eogonek'] = 444; + t['Uogonek'] = 722; + t['Aacute'] = 722; + t['Adieresis'] = 722; + t['egrave'] = 444; + t['zacute'] = 444; + t['iogonek'] = 278; + t['Oacute'] = 778; + t['oacute'] = 500; + t['amacron'] = 500; + t['sacute'] = 389; + t['idieresis'] = 278; + t['Ocircumflex'] = 778; + t['Ugrave'] = 722; + t['Delta'] = 612; + t['thorn'] = 556; + t['twosuperior'] = 300; + t['Odieresis'] = 778; + t['mu'] = 556; + t['igrave'] = 278; + t['ohungarumlaut'] = 500; + t['Eogonek'] = 667; + t['dcroat'] = 556; + t['threequarters'] = 750; + t['Scedilla'] = 556; + t['lcaron'] = 394; + t['Kcommaaccent'] = 778; + t['Lacute'] = 667; + t['trademark'] = 1000; + t['edotaccent'] = 444; + t['Igrave'] = 389; + t['Imacron'] = 389; + t['Lcaron'] = 667; + t['onehalf'] = 750; + t['lessequal'] = 549; + t['ocircumflex'] = 500; + t['ntilde'] = 556; + t['Uhungarumlaut'] = 722; + t['Eacute'] = 667; + t['emacron'] = 444; + t['gbreve'] = 500; + t['onequarter'] = 750; + t['Scaron'] = 556; + t['Scommaaccent'] = 556; + t['Ohungarumlaut'] = 778; + t['degree'] = 400; + t['ograve'] = 500; + t['Ccaron'] = 722; + t['ugrave'] = 556; + t['radical'] = 549; + t['Dcaron'] = 722; + t['rcommaaccent'] = 444; + t['Ntilde'] = 722; + t['otilde'] = 500; + t['Rcommaaccent'] = 722; + t['Lcommaaccent'] = 667; + t['Atilde'] = 722; + t['Aogonek'] = 722; + t['Aring'] = 722; + t['Otilde'] = 778; + t['zdotaccent'] = 444; + t['Ecaron'] = 667; + t['Iogonek'] = 389; + t['kcommaaccent'] = 556; + t['minus'] = 570; + t['Icircumflex'] = 389; + t['ncaron'] = 556; + t['tcommaaccent'] = 333; + t['logicalnot'] = 570; + t['odieresis'] = 500; + t['udieresis'] = 556; + t['notequal'] = 549; + t['gcommaaccent'] = 500; + t['eth'] = 500; + t['zcaron'] = 444; + t['ncommaaccent'] = 556; + t['onesuperior'] = 300; + t['imacron'] = 278; + t['Euro'] = 500; + }); + t['Times-BoldItalic'] = (0, _util.getLookupTableFactory)(function (t) { + t['space'] = 250; + t['exclam'] = 389; + t['quotedbl'] = 555; + t['numbersign'] = 500; + t['dollar'] = 500; + t['percent'] = 833; + t['ampersand'] = 778; + t['quoteright'] = 333; + t['parenleft'] = 333; + t['parenright'] = 333; + t['asterisk'] = 500; + t['plus'] = 570; + t['comma'] = 250; + t['hyphen'] = 333; + t['period'] = 250; + t['slash'] = 278; + t['zero'] = 500; + t['one'] = 500; + t['two'] = 500; + t['three'] = 500; + t['four'] = 500; + t['five'] = 500; + t['six'] = 500; + t['seven'] = 500; + t['eight'] = 500; + t['nine'] = 500; + t['colon'] = 333; + t['semicolon'] = 333; + t['less'] = 570; + t['equal'] = 570; + t['greater'] = 570; + t['question'] = 500; + t['at'] = 832; + t['A'] = 667; + t['B'] = 667; + t['C'] = 667; + t['D'] = 722; + t['E'] = 667; + t['F'] = 667; + t['G'] = 722; + t['H'] = 778; + t['I'] = 389; + t['J'] = 500; + t['K'] = 667; + t['L'] = 611; + t['M'] = 889; + t['N'] = 722; + t['O'] = 722; + t['P'] = 611; + t['Q'] = 722; + t['R'] = 667; + t['S'] = 556; + t['T'] = 611; + t['U'] = 722; + t['V'] = 667; + t['W'] = 889; + t['X'] = 667; + t['Y'] = 611; + t['Z'] = 611; + t['bracketleft'] = 333; + t['backslash'] = 278; + t['bracketright'] = 333; + t['asciicircum'] = 570; + t['underscore'] = 500; + t['quoteleft'] = 333; + t['a'] = 500; + t['b'] = 500; + t['c'] = 444; + t['d'] = 500; + t['e'] = 444; + t['f'] = 333; + t['g'] = 500; + t['h'] = 556; + t['i'] = 278; + t['j'] = 278; + t['k'] = 500; + t['l'] = 278; + t['m'] = 778; + t['n'] = 556; + t['o'] = 500; + t['p'] = 500; + t['q'] = 500; + t['r'] = 389; + t['s'] = 389; + t['t'] = 278; + t['u'] = 556; + t['v'] = 444; + t['w'] = 667; + t['x'] = 500; + t['y'] = 444; + t['z'] = 389; + t['braceleft'] = 348; + t['bar'] = 220; + t['braceright'] = 348; + t['asciitilde'] = 570; + t['exclamdown'] = 389; + t['cent'] = 500; + t['sterling'] = 500; + t['fraction'] = 167; + t['yen'] = 500; + t['florin'] = 500; + t['section'] = 500; + t['currency'] = 500; + t['quotesingle'] = 278; + t['quotedblleft'] = 500; + t['guillemotleft'] = 500; + t['guilsinglleft'] = 333; + t['guilsinglright'] = 333; + t['fi'] = 556; + t['fl'] = 556; + t['endash'] = 500; + t['dagger'] = 500; + t['daggerdbl'] = 500; + t['periodcentered'] = 250; + t['paragraph'] = 500; + t['bullet'] = 350; + t['quotesinglbase'] = 333; + t['quotedblbase'] = 500; + t['quotedblright'] = 500; + t['guillemotright'] = 500; + t['ellipsis'] = 1000; + t['perthousand'] = 1000; + t['questiondown'] = 500; + t['grave'] = 333; + t['acute'] = 333; + t['circumflex'] = 333; + t['tilde'] = 333; + t['macron'] = 333; + t['breve'] = 333; + t['dotaccent'] = 333; + t['dieresis'] = 333; + t['ring'] = 333; + t['cedilla'] = 333; + t['hungarumlaut'] = 333; + t['ogonek'] = 333; + t['caron'] = 333; + t['emdash'] = 1000; + t['AE'] = 944; + t['ordfeminine'] = 266; + t['Lslash'] = 611; + t['Oslash'] = 722; + t['OE'] = 944; + t['ordmasculine'] = 300; + t['ae'] = 722; + t['dotlessi'] = 278; + t['lslash'] = 278; + t['oslash'] = 500; + t['oe'] = 722; + t['germandbls'] = 500; + t['Idieresis'] = 389; + t['eacute'] = 444; + t['abreve'] = 500; + t['uhungarumlaut'] = 556; + t['ecaron'] = 444; + t['Ydieresis'] = 611; + t['divide'] = 570; + t['Yacute'] = 611; + t['Acircumflex'] = 667; + t['aacute'] = 500; + t['Ucircumflex'] = 722; + t['yacute'] = 444; + t['scommaaccent'] = 389; + t['ecircumflex'] = 444; + t['Uring'] = 722; + t['Udieresis'] = 722; + t['aogonek'] = 500; + t['Uacute'] = 722; + t['uogonek'] = 556; + t['Edieresis'] = 667; + t['Dcroat'] = 722; + t['commaaccent'] = 250; + t['copyright'] = 747; + t['Emacron'] = 667; + t['ccaron'] = 444; + t['aring'] = 500; + t['Ncommaaccent'] = 722; + t['lacute'] = 278; + t['agrave'] = 500; + t['Tcommaaccent'] = 611; + t['Cacute'] = 667; + t['atilde'] = 500; + t['Edotaccent'] = 667; + t['scaron'] = 389; + t['scedilla'] = 389; + t['iacute'] = 278; + t['lozenge'] = 494; + t['Rcaron'] = 667; + t['Gcommaaccent'] = 722; + t['ucircumflex'] = 556; + t['acircumflex'] = 500; + t['Amacron'] = 667; + t['rcaron'] = 389; + t['ccedilla'] = 444; + t['Zdotaccent'] = 611; + t['Thorn'] = 611; + t['Omacron'] = 722; + t['Racute'] = 667; + t['Sacute'] = 556; + t['dcaron'] = 608; + t['Umacron'] = 722; + t['uring'] = 556; + t['threesuperior'] = 300; + t['Ograve'] = 722; + t['Agrave'] = 667; + t['Abreve'] = 667; + t['multiply'] = 570; + t['uacute'] = 556; + t['Tcaron'] = 611; + t['partialdiff'] = 494; + t['ydieresis'] = 444; + t['Nacute'] = 722; + t['icircumflex'] = 278; + t['Ecircumflex'] = 667; + t['adieresis'] = 500; + t['edieresis'] = 444; + t['cacute'] = 444; + t['nacute'] = 556; + t['umacron'] = 556; + t['Ncaron'] = 722; + t['Iacute'] = 389; + t['plusminus'] = 570; + t['brokenbar'] = 220; + t['registered'] = 747; + t['Gbreve'] = 722; + t['Idotaccent'] = 389; + t['summation'] = 600; + t['Egrave'] = 667; + t['racute'] = 389; + t['omacron'] = 500; + t['Zacute'] = 611; + t['Zcaron'] = 611; + t['greaterequal'] = 549; + t['Eth'] = 722; + t['Ccedilla'] = 667; + t['lcommaaccent'] = 278; + t['tcaron'] = 366; + t['eogonek'] = 444; + t['Uogonek'] = 722; + t['Aacute'] = 667; + t['Adieresis'] = 667; + t['egrave'] = 444; + t['zacute'] = 389; + t['iogonek'] = 278; + t['Oacute'] = 722; + t['oacute'] = 500; + t['amacron'] = 500; + t['sacute'] = 389; + t['idieresis'] = 278; + t['Ocircumflex'] = 722; + t['Ugrave'] = 722; + t['Delta'] = 612; + t['thorn'] = 500; + t['twosuperior'] = 300; + t['Odieresis'] = 722; + t['mu'] = 576; + t['igrave'] = 278; + t['ohungarumlaut'] = 500; + t['Eogonek'] = 667; + t['dcroat'] = 500; + t['threequarters'] = 750; + t['Scedilla'] = 556; + t['lcaron'] = 382; + t['Kcommaaccent'] = 667; + t['Lacute'] = 611; + t['trademark'] = 1000; + t['edotaccent'] = 444; + t['Igrave'] = 389; + t['Imacron'] = 389; + t['Lcaron'] = 611; + t['onehalf'] = 750; + t['lessequal'] = 549; + t['ocircumflex'] = 500; + t['ntilde'] = 556; + t['Uhungarumlaut'] = 722; + t['Eacute'] = 667; + t['emacron'] = 444; + t['gbreve'] = 500; + t['onequarter'] = 750; + t['Scaron'] = 556; + t['Scommaaccent'] = 556; + t['Ohungarumlaut'] = 722; + t['degree'] = 400; + t['ograve'] = 500; + t['Ccaron'] = 667; + t['ugrave'] = 556; + t['radical'] = 549; + t['Dcaron'] = 722; + t['rcommaaccent'] = 389; + t['Ntilde'] = 722; + t['otilde'] = 500; + t['Rcommaaccent'] = 667; + t['Lcommaaccent'] = 611; + t['Atilde'] = 667; + t['Aogonek'] = 667; + t['Aring'] = 667; + t['Otilde'] = 722; + t['zdotaccent'] = 389; + t['Ecaron'] = 667; + t['Iogonek'] = 389; + t['kcommaaccent'] = 500; + t['minus'] = 606; + t['Icircumflex'] = 389; + t['ncaron'] = 556; + t['tcommaaccent'] = 278; + t['logicalnot'] = 606; + t['odieresis'] = 500; + t['udieresis'] = 556; + t['notequal'] = 549; + t['gcommaaccent'] = 500; + t['eth'] = 500; + t['zcaron'] = 389; + t['ncommaaccent'] = 556; + t['onesuperior'] = 300; + t['imacron'] = 278; + t['Euro'] = 500; + }); + t['Times-Italic'] = (0, _util.getLookupTableFactory)(function (t) { + t['space'] = 250; + t['exclam'] = 333; + t['quotedbl'] = 420; + t['numbersign'] = 500; + t['dollar'] = 500; + t['percent'] = 833; + t['ampersand'] = 778; + t['quoteright'] = 333; + t['parenleft'] = 333; + t['parenright'] = 333; + t['asterisk'] = 500; + t['plus'] = 675; + t['comma'] = 250; + t['hyphen'] = 333; + t['period'] = 250; + t['slash'] = 278; + t['zero'] = 500; + t['one'] = 500; + t['two'] = 500; + t['three'] = 500; + t['four'] = 500; + t['five'] = 500; + t['six'] = 500; + t['seven'] = 500; + t['eight'] = 500; + t['nine'] = 500; + t['colon'] = 333; + t['semicolon'] = 333; + t['less'] = 675; + t['equal'] = 675; + t['greater'] = 675; + t['question'] = 500; + t['at'] = 920; + t['A'] = 611; + t['B'] = 611; + t['C'] = 667; + t['D'] = 722; + t['E'] = 611; + t['F'] = 611; + t['G'] = 722; + t['H'] = 722; + t['I'] = 333; + t['J'] = 444; + t['K'] = 667; + t['L'] = 556; + t['M'] = 833; + t['N'] = 667; + t['O'] = 722; + t['P'] = 611; + t['Q'] = 722; + t['R'] = 611; + t['S'] = 500; + t['T'] = 556; + t['U'] = 722; + t['V'] = 611; + t['W'] = 833; + t['X'] = 611; + t['Y'] = 556; + t['Z'] = 556; + t['bracketleft'] = 389; + t['backslash'] = 278; + t['bracketright'] = 389; + t['asciicircum'] = 422; + t['underscore'] = 500; + t['quoteleft'] = 333; + t['a'] = 500; + t['b'] = 500; + t['c'] = 444; + t['d'] = 500; + t['e'] = 444; + t['f'] = 278; + t['g'] = 500; + t['h'] = 500; + t['i'] = 278; + t['j'] = 278; + t['k'] = 444; + t['l'] = 278; + t['m'] = 722; + t['n'] = 500; + t['o'] = 500; + t['p'] = 500; + t['q'] = 500; + t['r'] = 389; + t['s'] = 389; + t['t'] = 278; + t['u'] = 500; + t['v'] = 444; + t['w'] = 667; + t['x'] = 444; + t['y'] = 444; + t['z'] = 389; + t['braceleft'] = 400; + t['bar'] = 275; + t['braceright'] = 400; + t['asciitilde'] = 541; + t['exclamdown'] = 389; + t['cent'] = 500; + t['sterling'] = 500; + t['fraction'] = 167; + t['yen'] = 500; + t['florin'] = 500; + t['section'] = 500; + t['currency'] = 500; + t['quotesingle'] = 214; + t['quotedblleft'] = 556; + t['guillemotleft'] = 500; + t['guilsinglleft'] = 333; + t['guilsinglright'] = 333; + t['fi'] = 500; + t['fl'] = 500; + t['endash'] = 500; + t['dagger'] = 500; + t['daggerdbl'] = 500; + t['periodcentered'] = 250; + t['paragraph'] = 523; + t['bullet'] = 350; + t['quotesinglbase'] = 333; + t['quotedblbase'] = 556; + t['quotedblright'] = 556; + t['guillemotright'] = 500; + t['ellipsis'] = 889; + t['perthousand'] = 1000; + t['questiondown'] = 500; + t['grave'] = 333; + t['acute'] = 333; + t['circumflex'] = 333; + t['tilde'] = 333; + t['macron'] = 333; + t['breve'] = 333; + t['dotaccent'] = 333; + t['dieresis'] = 333; + t['ring'] = 333; + t['cedilla'] = 333; + t['hungarumlaut'] = 333; + t['ogonek'] = 333; + t['caron'] = 333; + t['emdash'] = 889; + t['AE'] = 889; + t['ordfeminine'] = 276; + t['Lslash'] = 556; + t['Oslash'] = 722; + t['OE'] = 944; + t['ordmasculine'] = 310; + t['ae'] = 667; + t['dotlessi'] = 278; + t['lslash'] = 278; + t['oslash'] = 500; + t['oe'] = 667; + t['germandbls'] = 500; + t['Idieresis'] = 333; + t['eacute'] = 444; + t['abreve'] = 500; + t['uhungarumlaut'] = 500; + t['ecaron'] = 444; + t['Ydieresis'] = 556; + t['divide'] = 675; + t['Yacute'] = 556; + t['Acircumflex'] = 611; + t['aacute'] = 500; + t['Ucircumflex'] = 722; + t['yacute'] = 444; + t['scommaaccent'] = 389; + t['ecircumflex'] = 444; + t['Uring'] = 722; + t['Udieresis'] = 722; + t['aogonek'] = 500; + t['Uacute'] = 722; + t['uogonek'] = 500; + t['Edieresis'] = 611; + t['Dcroat'] = 722; + t['commaaccent'] = 250; + t['copyright'] = 760; + t['Emacron'] = 611; + t['ccaron'] = 444; + t['aring'] = 500; + t['Ncommaaccent'] = 667; + t['lacute'] = 278; + t['agrave'] = 500; + t['Tcommaaccent'] = 556; + t['Cacute'] = 667; + t['atilde'] = 500; + t['Edotaccent'] = 611; + t['scaron'] = 389; + t['scedilla'] = 389; + t['iacute'] = 278; + t['lozenge'] = 471; + t['Rcaron'] = 611; + t['Gcommaaccent'] = 722; + t['ucircumflex'] = 500; + t['acircumflex'] = 500; + t['Amacron'] = 611; + t['rcaron'] = 389; + t['ccedilla'] = 444; + t['Zdotaccent'] = 556; + t['Thorn'] = 611; + t['Omacron'] = 722; + t['Racute'] = 611; + t['Sacute'] = 500; + t['dcaron'] = 544; + t['Umacron'] = 722; + t['uring'] = 500; + t['threesuperior'] = 300; + t['Ograve'] = 722; + t['Agrave'] = 611; + t['Abreve'] = 611; + t['multiply'] = 675; + t['uacute'] = 500; + t['Tcaron'] = 556; + t['partialdiff'] = 476; + t['ydieresis'] = 444; + t['Nacute'] = 667; + t['icircumflex'] = 278; + t['Ecircumflex'] = 611; + t['adieresis'] = 500; + t['edieresis'] = 444; + t['cacute'] = 444; + t['nacute'] = 500; + t['umacron'] = 500; + t['Ncaron'] = 667; + t['Iacute'] = 333; + t['plusminus'] = 675; + t['brokenbar'] = 275; + t['registered'] = 760; + t['Gbreve'] = 722; + t['Idotaccent'] = 333; + t['summation'] = 600; + t['Egrave'] = 611; + t['racute'] = 389; + t['omacron'] = 500; + t['Zacute'] = 556; + t['Zcaron'] = 556; + t['greaterequal'] = 549; + t['Eth'] = 722; + t['Ccedilla'] = 667; + t['lcommaaccent'] = 278; + t['tcaron'] = 300; + t['eogonek'] = 444; + t['Uogonek'] = 722; + t['Aacute'] = 611; + t['Adieresis'] = 611; + t['egrave'] = 444; + t['zacute'] = 389; + t['iogonek'] = 278; + t['Oacute'] = 722; + t['oacute'] = 500; + t['amacron'] = 500; + t['sacute'] = 389; + t['idieresis'] = 278; + t['Ocircumflex'] = 722; + t['Ugrave'] = 722; + t['Delta'] = 612; + t['thorn'] = 500; + t['twosuperior'] = 300; + t['Odieresis'] = 722; + t['mu'] = 500; + t['igrave'] = 278; + t['ohungarumlaut'] = 500; + t['Eogonek'] = 611; + t['dcroat'] = 500; + t['threequarters'] = 750; + t['Scedilla'] = 500; + t['lcaron'] = 300; + t['Kcommaaccent'] = 667; + t['Lacute'] = 556; + t['trademark'] = 980; + t['edotaccent'] = 444; + t['Igrave'] = 333; + t['Imacron'] = 333; + t['Lcaron'] = 611; + t['onehalf'] = 750; + t['lessequal'] = 549; + t['ocircumflex'] = 500; + t['ntilde'] = 500; + t['Uhungarumlaut'] = 722; + t['Eacute'] = 611; + t['emacron'] = 444; + t['gbreve'] = 500; + t['onequarter'] = 750; + t['Scaron'] = 500; + t['Scommaaccent'] = 500; + t['Ohungarumlaut'] = 722; + t['degree'] = 400; + t['ograve'] = 500; + t['Ccaron'] = 667; + t['ugrave'] = 500; + t['radical'] = 453; + t['Dcaron'] = 722; + t['rcommaaccent'] = 389; + t['Ntilde'] = 667; + t['otilde'] = 500; + t['Rcommaaccent'] = 611; + t['Lcommaaccent'] = 556; + t['Atilde'] = 611; + t['Aogonek'] = 611; + t['Aring'] = 611; + t['Otilde'] = 722; + t['zdotaccent'] = 389; + t['Ecaron'] = 611; + t['Iogonek'] = 333; + t['kcommaaccent'] = 444; + t['minus'] = 675; + t['Icircumflex'] = 333; + t['ncaron'] = 500; + t['tcommaaccent'] = 278; + t['logicalnot'] = 675; + t['odieresis'] = 500; + t['udieresis'] = 500; + t['notequal'] = 549; + t['gcommaaccent'] = 500; + t['eth'] = 500; + t['zcaron'] = 389; + t['ncommaaccent'] = 500; + t['onesuperior'] = 300; + t['imacron'] = 278; + t['Euro'] = 500; + }); + t['ZapfDingbats'] = (0, _util.getLookupTableFactory)(function (t) { + t['space'] = 278; + t['a1'] = 974; + t['a2'] = 961; + t['a202'] = 974; + t['a3'] = 980; + t['a4'] = 719; + t['a5'] = 789; + t['a119'] = 790; + t['a118'] = 791; + t['a117'] = 690; + t['a11'] = 960; + t['a12'] = 939; + t['a13'] = 549; + t['a14'] = 855; + t['a15'] = 911; + t['a16'] = 933; + t['a105'] = 911; + t['a17'] = 945; + t['a18'] = 974; + t['a19'] = 755; + t['a20'] = 846; + t['a21'] = 762; + t['a22'] = 761; + t['a23'] = 571; + t['a24'] = 677; + t['a25'] = 763; + t['a26'] = 760; + t['a27'] = 759; + t['a28'] = 754; + t['a6'] = 494; + t['a7'] = 552; + t['a8'] = 537; + t['a9'] = 577; + t['a10'] = 692; + t['a29'] = 786; + t['a30'] = 788; + t['a31'] = 788; + t['a32'] = 790; + t['a33'] = 793; + t['a34'] = 794; + t['a35'] = 816; + t['a36'] = 823; + t['a37'] = 789; + t['a38'] = 841; + t['a39'] = 823; + t['a40'] = 833; + t['a41'] = 816; + t['a42'] = 831; + t['a43'] = 923; + t['a44'] = 744; + t['a45'] = 723; + t['a46'] = 749; + t['a47'] = 790; + t['a48'] = 792; + t['a49'] = 695; + t['a50'] = 776; + t['a51'] = 768; + t['a52'] = 792; + t['a53'] = 759; + t['a54'] = 707; + t['a55'] = 708; + t['a56'] = 682; + t['a57'] = 701; + t['a58'] = 826; + t['a59'] = 815; + t['a60'] = 789; + t['a61'] = 789; + t['a62'] = 707; + t['a63'] = 687; + t['a64'] = 696; + t['a65'] = 689; + t['a66'] = 786; + t['a67'] = 787; + t['a68'] = 713; + t['a69'] = 791; + t['a70'] = 785; + t['a71'] = 791; + t['a72'] = 873; + t['a73'] = 761; + t['a74'] = 762; + t['a203'] = 762; + t['a75'] = 759; + t['a204'] = 759; + t['a76'] = 892; + t['a77'] = 892; + t['a78'] = 788; + t['a79'] = 784; + t['a81'] = 438; + t['a82'] = 138; + t['a83'] = 277; + t['a84'] = 415; + t['a97'] = 392; + t['a98'] = 392; + t['a99'] = 668; + t['a100'] = 668; + t['a89'] = 390; + t['a90'] = 390; + t['a93'] = 317; + t['a94'] = 317; + t['a91'] = 276; + t['a92'] = 276; + t['a205'] = 509; + t['a85'] = 509; + t['a206'] = 410; + t['a86'] = 410; + t['a87'] = 234; + t['a88'] = 234; + t['a95'] = 334; + t['a96'] = 334; + t['a101'] = 732; + t['a102'] = 544; + t['a103'] = 544; + t['a104'] = 910; + t['a106'] = 667; + t['a107'] = 760; + t['a108'] = 760; + t['a112'] = 776; + t['a111'] = 595; + t['a110'] = 694; + t['a109'] = 626; + t['a120'] = 788; + t['a121'] = 788; + t['a122'] = 788; + t['a123'] = 788; + t['a124'] = 788; + t['a125'] = 788; + t['a126'] = 788; + t['a127'] = 788; + t['a128'] = 788; + t['a129'] = 788; + t['a130'] = 788; + t['a131'] = 788; + t['a132'] = 788; + t['a133'] = 788; + t['a134'] = 788; + t['a135'] = 788; + t['a136'] = 788; + t['a137'] = 788; + t['a138'] = 788; + t['a139'] = 788; + t['a140'] = 788; + t['a141'] = 788; + t['a142'] = 788; + t['a143'] = 788; + t['a144'] = 788; + t['a145'] = 788; + t['a146'] = 788; + t['a147'] = 788; + t['a148'] = 788; + t['a149'] = 788; + t['a150'] = 788; + t['a151'] = 788; + t['a152'] = 788; + t['a153'] = 788; + t['a154'] = 788; + t['a155'] = 788; + t['a156'] = 788; + t['a157'] = 788; + t['a158'] = 788; + t['a159'] = 788; + t['a160'] = 894; + t['a161'] = 838; + t['a163'] = 1016; + t['a164'] = 458; + t['a196'] = 748; + t['a165'] = 924; + t['a192'] = 748; + t['a166'] = 918; + t['a167'] = 927; + t['a168'] = 928; + t['a169'] = 928; + t['a170'] = 834; + t['a171'] = 873; + t['a172'] = 828; + t['a173'] = 924; + t['a162'] = 924; + t['a174'] = 917; + t['a175'] = 930; + t['a176'] = 931; + t['a177'] = 463; + t['a178'] = 883; + t['a179'] = 836; + t['a193'] = 836; + t['a180'] = 867; + t['a199'] = 867; + t['a181'] = 696; + t['a200'] = 696; + t['a182'] = 874; + t['a201'] = 874; + t['a183'] = 760; + t['a184'] = 946; + t['a197'] = 771; + t['a185'] = 865; + t['a194'] = 771; + t['a198'] = 888; + t['a186'] = 967; + t['a195'] = 888; + t['a187'] = 831; + t['a188'] = 873; + t['a189'] = 927; + t['a190'] = 970; + t['a191'] = 918; + }); + }); + exports.getMetrics = getMetrics; + + /***/ + }), + /* 30 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + var MurmurHash3_64 = function MurmurHash3_64Closure(seed) { + var MASK_HIGH = 0xffff0000; + var MASK_LOW = 0xffff; + + function MurmurHash3_64(seed) { + var SEED = 0xc3d2e1f0; + this.h1 = seed ? seed & 0xffffffff : SEED; + this.h2 = seed ? seed & 0xffffffff : SEED; + } + + MurmurHash3_64.prototype = { + update: function MurmurHash3_64_update(input) { + var i; + if (typeof input === 'string') { + var data = new Uint8Array(input.length * 2); + var length = 0; + for (i = 0; i < input.length; i++) { + var code = input.charCodeAt(i); + if (code <= 0xff) { + data[length++] = code; + } else { + data[length++] = code >>> 8; + data[length++] = code & 0xff; + } + } + } else if ((typeof input === 'undefined' ? 'undefined' : _typeof(input)) === 'object' && 'byteLength' in input) { + data = input; + length = data.byteLength; + } else { + throw new Error('Wrong data format in MurmurHash3_64_update. ' + 'Input must be a string or array.'); + } + var blockCounts = length >> 2; + var tailLength = length - blockCounts * 4; + var dataUint32 = new Uint32Array(data.buffer, 0, blockCounts); + var k1 = 0; + var k2 = 0; + var h1 = this.h1; + var h2 = this.h2; + var C1 = 0xcc9e2d51; + var C2 = 0x1b873593; + var C1_LOW = C1 & MASK_LOW; + var C2_LOW = C2 & MASK_LOW; + for (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; + return this; + }, + hexdigest: function MurmurHash3_64_hexdigest() { + var h1 = this.h1; + var 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; + for (var i = 0, arr = [h1, h2], str = ''; i < arr.length; i++) { + var hex = (arr[i] >>> 0).toString(16); + while (hex.length < 8) { + hex = '0' + hex; + } + str += hex; + } + return str; + } + }; + return MurmurHash3_64; + }(); + exports.MurmurHash3_64 = MurmurHash3_64; + + /***/ + }), + /* 31 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.getTilingPatternIR = exports.Pattern = undefined; + + var _util = __w_pdfjs_require__(0); + + var _colorspace = __w_pdfjs_require__(3); + + var _primitives = __w_pdfjs_require__(1); + + var _function = __w_pdfjs_require__(7); + + 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() { + throw new Error('should not call Pattern constructor'); + } + + Pattern.prototype = { + getPattern: function Pattern_getPattern(ctx) { + throw new Error('Should not call Pattern.getStyle: ' + ctx); + } + }; + Pattern.parseShading = function Pattern_parseShading(shading, matrix, xref, res, handler) { + 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); + 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); + default: + throw new _util.FormatError('Unsupported ShadingType: ' + type); + } + } catch (ex) { + if (ex instanceof _util.MissingDataException) { + throw ex; + } + handler.send('UnsupportedFeature', {featureId: _util.UNSUPPORTED_FEATURES.shadingPattern}); + (0, _util.warn)(ex); + return new Shadings.Dummy(); + } + }; + return Pattern; + }(); + var Shadings = {}; + Shadings.SMALL_NUMBER = 1e-6; + Shadings.RadialAxial = function RadialAxialClosure() { + function RadialAxial(dict, matrix, xref, res) { + this.matrix = matrix; + this.coordsArr = dict.getArray('Coords'); + this.shadingType = dict.get('ShadingType'); + this.type = 'Pattern'; + var cs = dict.get('ColorSpace', 'CS'); + cs = _colorspace.ColorSpace.parse(cs, xref, res); + this.cs = cs; + 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.get('Function'); + var fn = _function.PDFFunction.parseArray(xref, fnObj); + var diff = t1 - t0; + var step = diff / 10; + 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 (var i = t0; i <= t1; i += step) { + ratio[0] = i; + fn(ratio, 0, color, 0); + rgbColor = cs.getRgb(color, 0); + var cssColor = _util.Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]); + colorStops.push([(i - t0) / diff, 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.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: 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: 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, res) { + 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'; + this.bbox = dict.getArray('BBox'); + var cs = dict.get('ColorSpace', 'CS'); + cs = _colorspace.ColorSpace.parse(cs, xref, res); + this.cs = cs; + this.background = dict.has('Background') ? cs.getRgb(dict.get('Background'), 0) : null; + var fnObj = dict.get('Function'); + var fn = fnObj ? _function.PDFFunction.parseArray(xref, 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) { + var matrix = dict.getArray('Matrix'); + var bbox = _util.Util.normalizeRect(dict.getArray('BBox')); + var xstep = dict.get('XStep'); + var ystep = dict.get('YStep'); + var paintType = dict.get('PaintType'); + var 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]; + } + + exports.Pattern = Pattern; + exports.getTilingPatternIR = getTilingPatternIR; + + /***/ + }), + /* 32 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.NetworkPdfManager = exports.LocalPdfManager = undefined; + + var _util = __w_pdfjs_require__(0); + + var _chunked_stream = __w_pdfjs_require__(11); + + var _document = __w_pdfjs_require__(23); + + var _stream = __w_pdfjs_require__(2); + + var BasePdfManager = function BasePdfManagerClosure() { + function BasePdfManager() { + throw new Error('Cannot initialize BaseManagerManager'); + } + + BasePdfManager.prototype = { + get docId() { + return this._docId; + }, + get password() { + return this._password; + }, + get docBaseUrl() { + var docBaseUrl = null; + if (this._docBaseUrl) { + var 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); + }, + onLoadedStream: function BasePdfManager_onLoadedStream() { + throw new _util.NotImplementedException(); + }, + ensureDoc: function BasePdfManager_ensureDoc(prop, args) { + return this.ensure(this.pdfDocument, prop, args); + }, + ensureXRef: function BasePdfManager_ensureXRef(prop, args) { + return this.ensure(this.pdfDocument.xref, prop, args); + }, + ensureCatalog: function BasePdfManager_ensureCatalog(prop, args) { + return this.ensure(this.pdfDocument.catalog, prop, args); + }, + getPage: function BasePdfManager_getPage(pageIndex) { + return this.pdfDocument.getPage(pageIndex); + }, + cleanup: function BasePdfManager_cleanup() { + return this.pdfDocument.cleanup(); + }, + ensure: function BasePdfManager_ensure(obj, prop, args) { + return new _util.NotImplementedException(); + }, + requestRange: function BasePdfManager_requestRange(begin, end) { + return new _util.NotImplementedException(); + }, + requestLoadedStream: function BasePdfManager_requestLoadedStream() { + return new _util.NotImplementedException(); + }, + sendProgressiveData: function BasePdfManager_sendProgressiveData(chunk) { + return new _util.NotImplementedException(); + }, + updatePassword: function BasePdfManager_updatePassword(password) { + this._password = password; + }, + terminate: function BasePdfManager_terminate() { + return new _util.NotImplementedException(); + } + }; + return BasePdfManager; + }(); + var LocalPdfManager = function LocalPdfManagerClosure() { + function LocalPdfManager(docId, data, password, evaluatorOptions, docBaseUrl) { + this._docId = docId; + this._password = password; + this._docBaseUrl = docBaseUrl; + this.evaluatorOptions = evaluatorOptions; + var stream = new _stream.Stream(data); + this.pdfDocument = new _document.PDFDocument(this, stream); + this._loadedStreamCapability = (0, _util.createPromiseCapability)(); + this._loadedStreamCapability.resolve(stream); + } + + _util.Util.inherit(LocalPdfManager, BasePdfManager, { + ensure: function LocalPdfManager_ensure(obj, prop, args) { + return new Promise(function (resolve, reject) { + try { + var value = obj[prop]; + var result; + if (typeof value === 'function') { + result = value.apply(obj, args); + } else { + result = value; + } + resolve(result); + } catch (e) { + reject(e); + } + }); + }, + requestRange: function LocalPdfManager_requestRange(begin, end) { + return Promise.resolve(); + }, + requestLoadedStream: function LocalPdfManager_requestLoadedStream() { + }, + onLoadedStream: function LocalPdfManager_onLoadedStream() { + return this._loadedStreamCapability.promise; + }, + terminate: function LocalPdfManager_terminate() { + } + }); + return LocalPdfManager; + }(); + var NetworkPdfManager = function NetworkPdfManagerClosure() { + function NetworkPdfManager(docId, pdfNetworkStream, args, evaluatorOptions, docBaseUrl) { + this._docId = docId; + this._password = args.password; + this._docBaseUrl = docBaseUrl; + this.msgHandler = args.msgHandler; + this.evaluatorOptions = evaluatorOptions; + var params = { + msgHandler: args.msgHandler, + url: args.url, + length: args.length, + disableAutoFetch: args.disableAutoFetch, + rangeChunkSize: args.rangeChunkSize + }; + this.streamManager = new _chunked_stream.ChunkedStreamManager(pdfNetworkStream, params); + this.pdfDocument = new _document.PDFDocument(this, this.streamManager.getStream()); + } + + _util.Util.inherit(NetworkPdfManager, BasePdfManager, { + ensure: function NetworkPdfManager_ensure(obj, prop, args) { + var pdfManager = this; + return new Promise(function (resolve, reject) { + function ensureHelper() { + try { + var result; + var value = obj[prop]; + if (typeof value === 'function') { + result = value.apply(obj, args); + } else { + result = value; + } + resolve(result); + } catch (e) { + if (!(e instanceof _util.MissingDataException)) { + reject(e); + return; + } + pdfManager.streamManager.requestRange(e.begin, e.end).then(ensureHelper, reject); + } + } + + ensureHelper(); + }); + }, + requestRange: function NetworkPdfManager_requestRange(begin, end) { + return this.streamManager.requestRange(begin, end); + }, + requestLoadedStream: function NetworkPdfManager_requestLoadedStream() { + this.streamManager.requestAllChunks(); + }, + sendProgressiveData: function NetworkPdfManager_sendProgressiveData(chunk) { + this.streamManager.onReceiveData({chunk: chunk}); + }, + onLoadedStream: function NetworkPdfManager_onLoadedStream() { + return this.streamManager.onLoadedStream(); + }, + terminate: function NetworkPdfManager_terminate() { + this.streamManager.abort(); + } + }); + return NetworkPdfManager; + }(); + exports.LocalPdfManager = LocalPdfManager; + exports.NetworkPdfManager = NetworkPdfManager; + + /***/ + }), + /* 33 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PostScriptParser = exports.PostScriptLexer = undefined; + + var _util = __w_pdfjs_require__(0); + + var _primitives = __w_pdfjs_require__(1); + + var PostScriptParser = function PostScriptParserClosure() { + function PostScriptParser(lexer) { + this.lexer = lexer; + this.operators = []; + this.token = null; + this.prev = null; + } + + PostScriptParser.prototype = { + nextToken: function PostScriptParser_nextToken() { + this.prev = this.token; + this.token = this.lexer.getToken(); + }, + accept: function PostScriptParser_accept(type) { + if (this.token.type === type) { + this.nextToken(); + return true; + } + return false; + }, + expect: function PostScriptParser_expect(type) { + if (this.accept(type)) { + return true; + } + throw new _util.FormatError('Unexpected symbol: found ' + this.token.type + ' expected ' + type + '.'); + }, + parse: function PostScriptParser_parse() { + this.nextToken(); + this.expect(PostScriptTokenTypes.LBRACE); + this.parseBlock(); + this.expect(PostScriptTokenTypes.RBRACE); + return this.operators; + }, + parseBlock: function PostScriptParser_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: function PostScriptParser_parseCondition() { + var 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)) { + var jumpLocation = this.operators.length; + this.operators.push(null, null); + var 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.'); + } + } + }; + return PostScriptParser; + }(); + var PostScriptTokenTypes = { + LBRACE: 0, + RBRACE: 1, + NUMBER: 2, + OPERATOR: 3, + IF: 4, + IFELSE: 5 + }; + var PostScriptToken = function PostScriptTokenClosure() { + function PostScriptToken(type, value) { + this.type = type; + this.value = value; + } + + var opCache = Object.create(null); + PostScriptToken.getOperator = function PostScriptToken_getOperator(op) { + var opValue = opCache[op]; + if (opValue) { + return opValue; + } + return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op); + }; + PostScriptToken.LBRACE = new PostScriptToken(PostScriptTokenTypes.LBRACE, '{'); + PostScriptToken.RBRACE = new PostScriptToken(PostScriptTokenTypes.RBRACE, '}'); + PostScriptToken.IF = new PostScriptToken(PostScriptTokenTypes.IF, 'IF'); + PostScriptToken.IFELSE = new PostScriptToken(PostScriptTokenTypes.IFELSE, 'IFELSE'); + return PostScriptToken; + }(); + var PostScriptLexer = function PostScriptLexerClosure() { + function PostScriptLexer(stream) { + this.stream = stream; + this.nextChar(); + this.strBuf = []; + } + + PostScriptLexer.prototype = { + nextChar: function PostScriptLexer_nextChar() { + return this.currentChar = this.stream.getByte(); + }, + getToken: function PostScriptLexer_getToken() { + var comment = false; + var 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, _util.isSpace)(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; + } + var 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)); + } + var str = strBuf.join(''); + switch (str.toLowerCase()) { + case 'if': + return PostScriptToken.IF; + case 'ifelse': + return PostScriptToken.IFELSE; + default: + return PostScriptToken.getOperator(str); + } + }, + getNumber: function PostScriptLexer_getNumber() { + var ch = this.currentChar; + var 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; + } + } + var value = parseFloat(strBuf.join('')); + if (isNaN(value)) { + throw new _util.FormatError('Invalid floating point number: ' + value); + } + return value; + } + }; + return PostScriptLexer; + }(); + exports.PostScriptLexer = PostScriptLexer; + exports.PostScriptParser = PostScriptParser; + + /***/ + }), + /* 34 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.Type1Parser = undefined; + + var _util = __w_pdfjs_require__(0); + + var _encodings = __w_pdfjs_require__(4); + + var _stream = __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(); + 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) { + this.seac = this.stack.splice(-4, 4); + 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: function 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 (value === (value | 0)) { + 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 Array.prototype.slice.call(decrypted, 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]) && isHexDigit(data[1]) && isHexDigit(data[2]) && isHexDigit(data[3])); + 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, _util.isSpace)(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, _util.isSpace)(ch) && !isSpecial(ch)); + return token; + }, + extractFontProgram: function Type1Parser_extractFontProgram() { + var stream = this.stream; + var subrs = [], + charstrings = []; + var privateData = Object.create(null); + privateData['lenIV'] = 4; + var program = { + subrs: [], + charstrings: [], + properties: {'privateData': 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 = stream.makeSubStream(stream.pos, length); + lenIV = program.properties.privateData['lenIV']; + encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY, lenIV); + stream.skip(length); + this.nextChar(); + token = this.getToken(); + if (token === 'noaccess') { + this.getToken(); + } + charstrings.push({ + glyph: glyph, + encoded: encoded + }); + } + break; + case 'Subrs': + this.readInt(); + this.getToken(); + while ((token = this.getToken()) === 'dup') { + var index = this.readInt(); + length = this.readInt(); + this.getToken(); + data = stream.makeSubStream(stream.pos, length); + lenIV = program.properties.privateData['lenIV']; + encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY, lenIV); + stream.skip(length); + 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]; + } + program.charstrings.push({ + glyphName: glyph, + charstring: output, + width: charString.width, + lsb: charString.lsb, + seac: charString.seac + }); + } + 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; + + /***/ + }), + /* 35 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + var pdfjsVersion = '1.9.426'; + var pdfjsBuild = '2558a58d'; + var pdfjsCoreWorker = __w_pdfjs_require__(17); + exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler; + + /***/ + }), + /* 36 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + if (typeof PDFJS === 'undefined' || !PDFJS.compatibilityChecked) { + var globalScope = typeof window !== 'undefined' && window.Math === Math ? window : typeof global !== 'undefined' && global.Math === Math ? global : typeof self !== 'undefined' && self.Math === Math ? self : false ? undefined : {}; + var userAgent = typeof navigator !== 'undefined' && navigator.userAgent || ''; + var isAndroid = /Android/.test(userAgent); + var isAndroidPre3 = /Android\s[0-2][^\d]/.test(userAgent); + var isAndroidPre5 = /Android\s[0-4][^\d]/.test(userAgent); + var isChrome = userAgent.indexOf('Chrom') >= 0; + var isChromeWithRangeBug = /Chrome\/(39|40)\./.test(userAgent); + var isIOSChrome = userAgent.indexOf('CriOS') >= 0; + var isIE = userAgent.indexOf('Trident') >= 0; + var isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent); + var isOpera = userAgent.indexOf('Opera') >= 0; + var isSafari = /Safari\//.test(userAgent) && !/(Chrome\/|Android\s)/.test(userAgent); + var hasDOM = (typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && (typeof document === 'undefined' ? 'undefined' : _typeof(document)) === 'object'; + if (typeof PDFJS === 'undefined') { + globalScope.PDFJS = {}; + } + PDFJS.compatibilityChecked = true; + (function checkTypedArrayCompatibility() { + if (typeof Uint8Array !== 'undefined') { + if (typeof Uint8Array.prototype.subarray === 'undefined') { + Uint8Array.prototype.subarray = function subarray(start, end) { + return new Uint8Array(this.slice(start, end)); + }; + Float32Array.prototype.subarray = function subarray(start, end) { + return new Float32Array(this.slice(start, end)); + }; + } + if (typeof Float64Array === 'undefined') { + globalScope.Float64Array = Float32Array; + } + return; + } + + function subarray(start, end) { + return new TypedArray(this.slice(start, end)); + } + + function setArrayOffset(array, offset) { + if (arguments.length < 2) { + offset = 0; + } + for (var i = 0, n = array.length; i < n; ++i, ++offset) { + this[offset] = array[i] & 0xFF; + } + } + + function Uint32ArrayView(buffer, length) { + this.buffer = buffer; + this.byteLength = buffer.length; + this.length = length; + ensureUint32ArrayViewProps(this.length); + } + + Uint32ArrayView.prototype = Object.create(null); + var uint32ArrayViewSetters = 0; + + function createUint32ArrayProp(index) { + return { + get: function get() { + var buffer = this.buffer, + offset = index << 2; + return (buffer[offset] | buffer[offset + 1] << 8 | buffer[offset + 2] << 16 | buffer[offset + 3] << 24) >>> 0; + }, + set: function set(value) { + var buffer = this.buffer, + offset = index << 2; + buffer[offset] = value & 255; + buffer[offset + 1] = value >> 8 & 255; + buffer[offset + 2] = value >> 16 & 255; + buffer[offset + 3] = value >>> 24 & 255; + } + }; + } + + function ensureUint32ArrayViewProps(length) { + while (uint32ArrayViewSetters < length) { + Object.defineProperty(Uint32ArrayView.prototype, uint32ArrayViewSetters, createUint32ArrayProp(uint32ArrayViewSetters)); + uint32ArrayViewSetters++; + } + } + + function TypedArray(arg1) { + var result, i, n; + if (typeof arg1 === 'number') { + result = []; + for (i = 0; i < arg1; ++i) { + result[i] = 0; + } + } else if ('slice' in arg1) { + result = arg1.slice(0); + } else { + result = []; + for (i = 0, n = arg1.length; i < n; ++i) { + result[i] = arg1[i]; + } + } + result.subarray = subarray; + result.buffer = result; + result.byteLength = result.length; + result.set = setArrayOffset; + if ((typeof arg1 === 'undefined' ? 'undefined' : _typeof(arg1)) === 'object' && arg1.buffer) { + result.buffer = arg1.buffer; + } + return result; + } + + globalScope.Uint8Array = TypedArray; + globalScope.Int8Array = TypedArray; + globalScope.Int32Array = TypedArray; + globalScope.Uint16Array = TypedArray; + globalScope.Float32Array = TypedArray; + globalScope.Float64Array = TypedArray; + globalScope.Uint32Array = function () { + if (arguments.length === 3) { + if (arguments[1] !== 0) { + throw new Error('offset !== 0 is not supported'); + } + return new Uint32ArrayView(arguments[0], arguments[2]); + } + return TypedArray.apply(this, arguments); + }; + })(); + (function canvasPixelArrayBuffer() { + if (!hasDOM || !window.CanvasPixelArray) { + return; + } + var cpaProto = window.CanvasPixelArray.prototype; + if ('buffer' in cpaProto) { + return; + } + Object.defineProperty(cpaProto, 'buffer', { + get: function get() { + return this; + }, + + enumerable: false, + configurable: true + }); + Object.defineProperty(cpaProto, 'byteLength', { + get: function get() { + return this.length; + }, + + enumerable: false, + configurable: true + }); + })(); + (function normalizeURLObject() { + if (!globalScope.URL) { + globalScope.URL = globalScope.webkitURL; + } + })(); + (function checkObjectDefinePropertyCompatibility() { + if (typeof Object.defineProperty !== 'undefined') { + var definePropertyPossible = true; + try { + if (hasDOM) { + Object.defineProperty(new Image(), 'id', {value: 'test'}); + } + var Test = function Test() { + }; + Test.prototype = { + get id() { + } + }; + Object.defineProperty(new Test(), 'id', { + value: '', + configurable: true, + enumerable: true, + writable: false + }); + } catch (e) { + definePropertyPossible = false; + } + if (definePropertyPossible) { + return; + } + } + Object.defineProperty = function objectDefineProperty(obj, name, def) { + delete obj[name]; + if ('get' in def) { + obj.__defineGetter__(name, def['get']); + } + if ('set' in def) { + obj.__defineSetter__(name, def['set']); + } + if ('value' in def) { + obj.__defineSetter__(name, function objectDefinePropertySetter(value) { + this.__defineGetter__(name, function objectDefinePropertyGetter() { + return value; + }); + return value; + }); + obj[name] = def.value; + } + }; + })(); + (function checkXMLHttpRequestResponseCompatibility() { + if (typeof XMLHttpRequest === 'undefined') { + return; + } + var xhrPrototype = XMLHttpRequest.prototype; + var xhr = new XMLHttpRequest(); + if (!('overrideMimeType' in xhr)) { + Object.defineProperty(xhrPrototype, 'overrideMimeType', { + value: function xmlHttpRequestOverrideMimeType(mimeType) { + } + }); + } + if ('responseType' in xhr) { + return; + } + Object.defineProperty(xhrPrototype, 'responseType', { + get: function xmlHttpRequestGetResponseType() { + return this._responseType || 'text'; + }, + set: function xmlHttpRequestSetResponseType(value) { + if (value === 'text' || value === 'arraybuffer') { + this._responseType = value; + if (value === 'arraybuffer' && typeof this.overrideMimeType === 'function') { + this.overrideMimeType('text/plain; charset=x-user-defined'); + } + } + } + }); + if (typeof VBArray !== 'undefined') { + Object.defineProperty(xhrPrototype, 'response', { + get: function xmlHttpRequestResponseGet() { + if (this.responseType === 'arraybuffer') { + return new Uint8Array(new VBArray(this.responseBody).toArray()); + } + return this.responseText; + } + }); + return; + } + Object.defineProperty(xhrPrototype, 'response', { + get: function xmlHttpRequestResponseGet() { + if (this.responseType !== 'arraybuffer') { + return this.responseText; + } + var text = this.responseText; + var i, + n = text.length; + var result = new Uint8Array(n); + for (i = 0; i < n; ++i) { + result[i] = text.charCodeAt(i) & 0xFF; + } + return result.buffer; + } + }); + })(); + (function checkWindowBtoaCompatibility() { + if ('btoa' in globalScope) { + return; + } + var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + globalScope.btoa = function (chars) { + var buffer = ''; + var i, n; + for (i = 0, n = chars.length; i < n; i += 3) { + var b1 = chars.charCodeAt(i) & 0xFF; + var b2 = chars.charCodeAt(i + 1) & 0xFF; + var b3 = chars.charCodeAt(i + 2) & 0xFF; + var d1 = b1 >> 2, + d2 = (b1 & 3) << 4 | b2 >> 4; + var d3 = i + 1 < n ? (b2 & 0xF) << 2 | b3 >> 6 : 64; + var d4 = i + 2 < n ? b3 & 0x3F : 64; + buffer += digits.charAt(d1) + digits.charAt(d2) + digits.charAt(d3) + digits.charAt(d4); + } + return buffer; + }; + })(); + (function checkWindowAtobCompatibility() { + if ('atob' in globalScope) { + return; + } + var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + globalScope.atob = function (input) { + input = input.replace(/=+$/, ''); + if (input.length % 4 === 1) { + throw new Error('bad atob input'); + } + for (var bc = 0, bs, buffer, idx = 0, output = ''; buffer = input.charAt(idx++); ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer, bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0) { + buffer = digits.indexOf(buffer); + } + return output; + }; + })(); + (function checkFunctionPrototypeBindCompatibility() { + if (typeof Function.prototype.bind !== 'undefined') { + return; + } + Function.prototype.bind = function functionPrototypeBind(obj) { + var fn = this, + headArgs = Array.prototype.slice.call(arguments, 1); + var bound = function functionPrototypeBindBound() { + var args = headArgs.concat(Array.prototype.slice.call(arguments)); + return fn.apply(obj, args); + }; + return bound; + }; + })(); + (function checkDatasetProperty() { + if (!hasDOM) { + return; + } + var div = document.createElement('div'); + if ('dataset' in div) { + return; + } + Object.defineProperty(HTMLElement.prototype, 'dataset', { + get: function get() { + if (this._dataset) { + return this._dataset; + } + var dataset = {}; + for (var j = 0, jj = this.attributes.length; j < jj; j++) { + var attribute = this.attributes[j]; + if (attribute.name.substring(0, 5) !== 'data-') { + continue; + } + var key = attribute.name.substring(5).replace(/\-([a-z])/g, function (all, ch) { + return ch.toUpperCase(); + }); + dataset[key] = attribute.value; + } + Object.defineProperty(this, '_dataset', { + value: dataset, + writable: false, + enumerable: false + }); + return dataset; + }, + + enumerable: true + }); + })(); + (function checkClassListProperty() { + function changeList(element, itemName, add, remove) { + var s = element.className || ''; + var list = s.split(/\s+/g); + if (list[0] === '') { + list.shift(); + } + var index = list.indexOf(itemName); + if (index < 0 && add) { + list.push(itemName); + } + if (index >= 0 && remove) { + list.splice(index, 1); + } + element.className = list.join(' '); + return index >= 0; + } + + if (!hasDOM) { + return; + } + var div = document.createElement('div'); + if ('classList' in div) { + return; + } + var classListPrototype = { + add: function add(name) { + changeList(this.element, name, true, false); + }, + contains: function contains(name) { + return changeList(this.element, name, false, false); + }, + remove: function remove(name) { + changeList(this.element, name, false, true); + }, + toggle: function toggle(name) { + changeList(this.element, name, true, true); + } + }; + Object.defineProperty(HTMLElement.prototype, 'classList', { + get: function get() { + if (this._classList) { + return this._classList; + } + var classList = Object.create(classListPrototype, { + element: { + value: this, + writable: false, + enumerable: true + } + }); + Object.defineProperty(this, '_classList', { + value: classList, + writable: false, + enumerable: false + }); + return classList; + }, + + enumerable: true + }); + })(); + (function checkWorkerConsoleCompatibility() { + if (typeof importScripts === 'undefined' || 'console' in globalScope) { + return; + } + var consoleTimer = {}; + var workerConsole = { + log: function log() { + var args = Array.prototype.slice.call(arguments); + globalScope.postMessage({ + targetName: 'main', + action: 'console_log', + data: args + }); + }, + error: function error() { + var args = Array.prototype.slice.call(arguments); + globalScope.postMessage({ + targetName: 'main', + action: 'console_error', + data: args + }); + }, + time: function time(name) { + consoleTimer[name] = Date.now(); + }, + timeEnd: function timeEnd(name) { + var time = consoleTimer[name]; + if (!time) { + throw new Error('Unknown timer name ' + name); + } + this.log('Timer:', name, Date.now() - time); + } + }; + globalScope.console = workerConsole; + })(); + (function checkConsoleCompatibility() { + if (!hasDOM) { + return; + } + if (!('console' in window)) { + window.console = { + log: function log() { + }, + error: function error() { + }, + warn: function warn() { + } + }; + return; + } + if (!('bind' in console.log)) { + console.log = function (fn) { + return function (msg) { + return fn(msg); + }; + }(console.log); + console.error = function (fn) { + return function (msg) { + return fn(msg); + }; + }(console.error); + console.warn = function (fn) { + return function (msg) { + return fn(msg); + }; + }(console.warn); + return; + } + })(); + (function checkOnClickCompatibility() { + function ignoreIfTargetDisabled(event) { + if (isDisabled(event.target)) { + event.stopPropagation(); + } + } + + function isDisabled(node) { + return node.disabled || node.parentNode && isDisabled(node.parentNode); + } + + if (isOpera) { + document.addEventListener('click', ignoreIfTargetDisabled, true); + } + })(); + (function checkOnBlobSupport() { + if (isIE || isIOSChrome) { + PDFJS.disableCreateObjectURL = true; + } + })(); + (function checkNavigatorLanguage() { + if (typeof navigator === 'undefined') { + return; + } + if ('language' in navigator) { + return; + } + PDFJS.locale = navigator.userLanguage || 'en-US'; + })(); + (function checkRangeRequests() { + if (isSafari || isAndroidPre3 || isChromeWithRangeBug || isIOS) { + PDFJS.disableRange = true; + PDFJS.disableStream = true; + } + })(); + (function checkHistoryManipulation() { + if (!hasDOM) { + return; + } + if (!history.pushState || isAndroidPre3) { + PDFJS.disableHistory = true; + } + })(); + (function checkSetPresenceInImageData() { + if (!hasDOM) { + return; + } + if (window.CanvasPixelArray) { + if (typeof window.CanvasPixelArray.prototype.set !== 'function') { + window.CanvasPixelArray.prototype.set = function (arr) { + for (var i = 0, ii = this.length; i < ii; i++) { + this[i] = arr[i]; + } + }; + } + } else { + var polyfill = false, + versionMatch; + if (isChrome) { + versionMatch = userAgent.match(/Chrom(e|ium)\/([0-9]+)\./); + polyfill = versionMatch && parseInt(versionMatch[2]) < 21; + } else if (isAndroid) { + polyfill = isAndroidPre5; + } else if (isSafari) { + versionMatch = userAgent.match(/Version\/([0-9]+)\.([0-9]+)\.([0-9]+) Safari\//); + polyfill = versionMatch && parseInt(versionMatch[1]) < 6; + } + if (polyfill) { + var contextPrototype = window.CanvasRenderingContext2D.prototype; + var createImageData = contextPrototype.createImageData; + contextPrototype.createImageData = function (w, h) { + var imageData = createImageData.call(this, w, h); + imageData.data.set = function (arr) { + for (var i = 0, ii = this.length; i < ii; i++) { + this[i] = arr[i]; + } + }; + return imageData; + }; + contextPrototype = null; + } + } + })(); + (function checkRequestAnimationFrame() { + function installFakeAnimationFrameFunctions() { + window.requestAnimationFrame = function (callback) { + return window.setTimeout(callback, 20); + }; + window.cancelAnimationFrame = function (timeoutID) { + window.clearTimeout(timeoutID); + }; + } + + if (!hasDOM) { + return; + } + if (isIOS) { + installFakeAnimationFrameFunctions(); + return; + } + if ('requestAnimationFrame' in window) { + return; + } + window.requestAnimationFrame = window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame; + if (window.requestAnimationFrame) { + return; + } + installFakeAnimationFrameFunctions(); + })(); + (function checkCanvasSizeLimitation() { + if (isIOS || isAndroid) { + PDFJS.maxCanvasPixels = 5242880; + } + })(); + (function checkFullscreenSupport() { + if (!hasDOM) { + return; + } + if (isIE && window.parent !== window) { + PDFJS.disableFullscreen = true; + } + })(); + (function checkCurrentScript() { + if (!hasDOM) { + return; + } + if ('currentScript' in document) { + return; + } + Object.defineProperty(document, 'currentScript', { + get: function get() { + var scripts = document.getElementsByTagName('script'); + return scripts[scripts.length - 1]; + }, + + enumerable: true, + configurable: true + }); + })(); + (function checkInputTypeNumberAssign() { + if (!hasDOM) { + return; + } + var el = document.createElement('input'); + try { + el.type = 'number'; + } catch (ex) { + var inputProto = el.constructor.prototype; + var typeProperty = Object.getOwnPropertyDescriptor(inputProto, 'type'); + Object.defineProperty(inputProto, 'type', { + get: function get() { + return typeProperty.get.call(this); + }, + set: function set(value) { + typeProperty.set.call(this, value === 'number' ? 'text' : value); + }, + + enumerable: true, + configurable: true + }); + } + })(); + (function checkDocumentReadyState() { + if (!hasDOM) { + return; + } + if (!document.attachEvent) { + return; + } + var documentProto = document.constructor.prototype; + var readyStateProto = Object.getOwnPropertyDescriptor(documentProto, 'readyState'); + Object.defineProperty(documentProto, 'readyState', { + get: function get() { + var value = readyStateProto.get.call(this); + return value === 'interactive' ? 'loading' : value; + }, + set: function set(value) { + readyStateProto.set.call(this, value); + }, + + enumerable: true, + configurable: true + }); + })(); + (function checkChildNodeRemove() { + if (!hasDOM) { + return; + } + if (typeof Element.prototype.remove !== 'undefined') { + return; + } + Element.prototype.remove = function () { + if (this.parentNode) { + this.parentNode.removeChild(this); + } + }; + })(); + (function checkNumberIsNaN() { + if (Number.isNaN) { + return; + } + Number.isNaN = function (value) { + return typeof value === 'number' && isNaN(value); + }; + })(); + (function checkNumberIsInteger() { + if (Number.isInteger) { + return; + } + Number.isInteger = function (value) { + return typeof value === 'number' && isFinite(value) && Math.floor(value) === value; + }; + })(); + (function checkPromise() { + if (globalScope.Promise) { + if (typeof globalScope.Promise.all !== 'function') { + globalScope.Promise.all = function (iterable) { + var count = 0, + results = [], + resolve, + reject; + var promise = new globalScope.Promise(function (resolve_, reject_) { + resolve = resolve_; + reject = reject_; + }); + iterable.forEach(function (p, i) { + count++; + p.then(function (result) { + results[i] = result; + count--; + if (count === 0) { + resolve(results); + } + }, reject); + }); + if (count === 0) { + resolve(results); + } + return promise; + }; + } + if (typeof globalScope.Promise.resolve !== 'function') { + globalScope.Promise.resolve = function (value) { + return new globalScope.Promise(function (resolve) { + resolve(value); + }); + }; + } + if (typeof globalScope.Promise.reject !== 'function') { + globalScope.Promise.reject = function (reason) { + return new globalScope.Promise(function (resolve, reject) { + reject(reason); + }); + }; + } + if (typeof globalScope.Promise.prototype.catch !== 'function') { + globalScope.Promise.prototype.catch = function (onReject) { + return globalScope.Promise.prototype.then(undefined, onReject); + }; + } + return; + } + var STATUS_PENDING = 0; + var STATUS_RESOLVED = 1; + var STATUS_REJECTED = 2; + var REJECTION_TIMEOUT = 500; + var HandlerManager = { + handlers: [], + running: false, + unhandledRejections: [], + pendingRejectionCheck: false, + scheduleHandlers: function scheduleHandlers(promise) { + if (promise._status === STATUS_PENDING) { + return; + } + this.handlers = this.handlers.concat(promise._handlers); + promise._handlers = []; + if (this.running) { + return; + } + this.running = true; + setTimeout(this.runHandlers.bind(this), 0); + }, + runHandlers: function runHandlers() { + var RUN_TIMEOUT = 1; + var timeoutAt = Date.now() + RUN_TIMEOUT; + while (this.handlers.length > 0) { + var handler = this.handlers.shift(); + var nextStatus = handler.thisPromise._status; + var nextValue = handler.thisPromise._value; + try { + if (nextStatus === STATUS_RESOLVED) { + if (typeof handler.onResolve === 'function') { + nextValue = handler.onResolve(nextValue); + } + } else if (typeof handler.onReject === 'function') { + nextValue = handler.onReject(nextValue); + nextStatus = STATUS_RESOLVED; + if (handler.thisPromise._unhandledRejection) { + this.removeUnhandeledRejection(handler.thisPromise); + } + } + } catch (ex) { + nextStatus = STATUS_REJECTED; + nextValue = ex; + } + handler.nextPromise._updateStatus(nextStatus, nextValue); + if (Date.now() >= timeoutAt) { + break; + } + } + if (this.handlers.length > 0) { + setTimeout(this.runHandlers.bind(this), 0); + return; + } + this.running = false; + }, + addUnhandledRejection: function addUnhandledRejection(promise) { + this.unhandledRejections.push({ + promise: promise, + time: Date.now() + }); + this.scheduleRejectionCheck(); + }, + removeUnhandeledRejection: function removeUnhandeledRejection(promise) { + promise._unhandledRejection = false; + for (var i = 0; i < this.unhandledRejections.length; i++) { + if (this.unhandledRejections[i].promise === promise) { + this.unhandledRejections.splice(i); + i--; + } + } + }, + scheduleRejectionCheck: function scheduleRejectionCheck() { + var _this = this; + + if (this.pendingRejectionCheck) { + return; + } + this.pendingRejectionCheck = true; + setTimeout(function () { + _this.pendingRejectionCheck = false; + var now = Date.now(); + for (var i = 0; i < _this.unhandledRejections.length; i++) { + if (now - _this.unhandledRejections[i].time > REJECTION_TIMEOUT) { + var unhandled = _this.unhandledRejections[i].promise._value; + var msg = 'Unhandled rejection: ' + unhandled; + if (unhandled.stack) { + msg += '\n' + unhandled.stack; + } + try { + throw new Error(msg); + } catch (_) { + console.warn(msg); + } + _this.unhandledRejections.splice(i); + i--; + } + } + if (_this.unhandledRejections.length) { + _this.scheduleRejectionCheck(); + } + }, REJECTION_TIMEOUT); + } + }; + var Promise = function Promise(resolver) { + this._status = STATUS_PENDING; + this._handlers = []; + try { + resolver.call(this, this._resolve.bind(this), this._reject.bind(this)); + } catch (e) { + this._reject(e); + } + }; + Promise.all = function Promise_all(promises) { + var resolveAll, rejectAll; + var deferred = new Promise(function (resolve, reject) { + resolveAll = resolve; + rejectAll = reject; + }); + var unresolved = promises.length; + var results = []; + if (unresolved === 0) { + resolveAll(results); + return deferred; + } + + function reject(reason) { + if (deferred._status === STATUS_REJECTED) { + return; + } + results = []; + rejectAll(reason); + } + + for (var i = 0, ii = promises.length; i < ii; ++i) { + var promise = promises[i]; + var resolve = function (i) { + return function (value) { + if (deferred._status === STATUS_REJECTED) { + return; + } + results[i] = value; + unresolved--; + if (unresolved === 0) { + resolveAll(results); + } + }; + }(i); + if (Promise.isPromise(promise)) { + promise.then(resolve, reject); + } else { + resolve(promise); + } + } + return deferred; + }; + Promise.isPromise = function Promise_isPromise(value) { + return value && typeof value.then === 'function'; + }; + Promise.resolve = function Promise_resolve(value) { + return new Promise(function (resolve) { + resolve(value); + }); + }; + Promise.reject = function Promise_reject(reason) { + return new Promise(function (resolve, reject) { + reject(reason); + }); + }; + Promise.prototype = { + _status: null, + _value: null, + _handlers: null, + _unhandledRejection: null, + _updateStatus: function Promise__updateStatus(status, value) { + if (this._status === STATUS_RESOLVED || this._status === STATUS_REJECTED) { + return; + } + if (status === STATUS_RESOLVED && Promise.isPromise(value)) { + value.then(this._updateStatus.bind(this, STATUS_RESOLVED), this._updateStatus.bind(this, STATUS_REJECTED)); + return; + } + this._status = status; + this._value = value; + if (status === STATUS_REJECTED && this._handlers.length === 0) { + this._unhandledRejection = true; + HandlerManager.addUnhandledRejection(this); + } + HandlerManager.scheduleHandlers(this); + }, + _resolve: function Promise_resolve(value) { + this._updateStatus(STATUS_RESOLVED, value); + }, + _reject: function Promise_reject(reason) { + this._updateStatus(STATUS_REJECTED, reason); + }, + then: function Promise_then(onResolve, onReject) { + var nextPromise = new Promise(function (resolve, reject) { + this.resolve = resolve; + this.reject = reject; + }); + this._handlers.push({ + thisPromise: this, + onResolve: onResolve, + onReject: onReject, + nextPromise: nextPromise + }); + HandlerManager.scheduleHandlers(this); + return nextPromise; + }, + catch: function Promise_catch(onReject) { + return this.then(undefined, onReject); + } + }; + globalScope.Promise = Promise; + })(); + (function checkWeakMap() { + if (globalScope.WeakMap) { + return; + } + var id = 0; + + function WeakMap() { + this.id = '$weakmap' + id++; + } + + WeakMap.prototype = { + has: function has(obj) { + if ((typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) !== 'object' && typeof obj !== 'function' || obj === null) { + return false; + } + return !!Object.getOwnPropertyDescriptor(obj, this.id); + }, + get: function get(obj) { + return this.has(obj) ? obj[this.id] : undefined; + }, + set: function set(obj, value) { + Object.defineProperty(obj, this.id, { + value: value, + enumerable: false, + configurable: true + }); + }, + delete: function _delete(obj) { + delete obj[this.id]; + } + }; + globalScope.WeakMap = WeakMap; + })(); + (function checkURLConstructor() { + var hasWorkingUrl = false; + try { + if (typeof URL === 'function' && _typeof(URL.prototype) === 'object' && 'origin' in URL.prototype) { + var u = new URL('b', 'http://a'); + u.pathname = 'c%20d'; + hasWorkingUrl = u.href === 'http://a/c%20d'; + } + } catch (e) { + } + if (hasWorkingUrl) { + return; + } + var relative = Object.create(null); + relative['ftp'] = 21; + relative['file'] = 0; + relative['gopher'] = 70; + relative['http'] = 80; + relative['https'] = 443; + relative['ws'] = 80; + relative['wss'] = 443; + var relativePathDotMapping = Object.create(null); + relativePathDotMapping['%2e'] = '.'; + relativePathDotMapping['.%2e'] = '..'; + relativePathDotMapping['%2e.'] = '..'; + relativePathDotMapping['%2e%2e'] = '..'; + + function isRelativeScheme(scheme) { + return relative[scheme] !== undefined; + } + + function invalid() { + clear.call(this); + this._isInvalid = true; + } + + function IDNAToASCII(h) { + if (h === '') { + invalid.call(this); + } + return h.toLowerCase(); + } + + function percentEscape(c) { + var unicode = c.charCodeAt(0); + if (unicode > 0x20 && unicode < 0x7F && [0x22, 0x23, 0x3C, 0x3E, 0x3F, 0x60].indexOf(unicode) === -1) { + return c; + } + return encodeURIComponent(c); + } + + function percentEscapeQuery(c) { + var unicode = c.charCodeAt(0); + if (unicode > 0x20 && unicode < 0x7F && [0x22, 0x23, 0x3C, 0x3E, 0x60].indexOf(unicode) === -1) { + return c; + } + return encodeURIComponent(c); + } + + var EOF, + ALPHA = /[a-zA-Z]/, + ALPHANUMERIC = /[a-zA-Z0-9\+\-\.]/; + + function parse(input, stateOverride, base) { + function err(message) { + errors.push(message); + } + + var state = stateOverride || 'scheme start', + cursor = 0, + buffer = '', + seenAt = false, + seenBracket = false, + errors = []; + loop: while ((input[cursor - 1] !== EOF || cursor === 0) && !this._isInvalid) { + var c = input[cursor]; + switch (state) { + case 'scheme start': + if (c && ALPHA.test(c)) { + buffer += c.toLowerCase(); + state = 'scheme'; + } else if (!stateOverride) { + buffer = ''; + state = 'no scheme'; + continue; + } else { + err('Invalid scheme.'); + break loop; + } + break; + case 'scheme': + if (c && ALPHANUMERIC.test(c)) { + buffer += c.toLowerCase(); + } else if (c === ':') { + this._scheme = buffer; + buffer = ''; + if (stateOverride) { + break loop; + } + if (isRelativeScheme(this._scheme)) { + this._isRelative = true; + } + if (this._scheme === 'file') { + state = 'relative'; + } else if (this._isRelative && base && base._scheme === this._scheme) { + state = 'relative or authority'; + } else if (this._isRelative) { + state = 'authority first slash'; + } else { + state = 'scheme data'; + } + } else if (!stateOverride) { + buffer = ''; + cursor = 0; + state = 'no scheme'; + continue; + } else if (c === EOF) { + break loop; + } else { + err('Code point not allowed in scheme: ' + c); + break loop; + } + break; + case 'scheme data': + if (c === '?') { + this._query = '?'; + state = 'query'; + } else if (c === '#') { + this._fragment = '#'; + state = 'fragment'; + } else { + if (c !== EOF && c !== '\t' && c !== '\n' && c !== '\r') { + this._schemeData += percentEscape(c); + } + } + break; + case 'no scheme': + if (!base || !isRelativeScheme(base._scheme)) { + err('Missing scheme.'); + invalid.call(this); + } else { + state = 'relative'; + continue; + } + break; + case 'relative or authority': + if (c === '/' && input[cursor + 1] === '/') { + state = 'authority ignore slashes'; + } else { + err('Expected /, got: ' + c); + state = 'relative'; + continue; + } + break; + case 'relative': + this._isRelative = true; + if (this._scheme !== 'file') { + this._scheme = base._scheme; + } + if (c === EOF) { + this._host = base._host; + this._port = base._port; + this._path = base._path.slice(); + this._query = base._query; + this._username = base._username; + this._password = base._password; + break loop; + } else if (c === '/' || c === '\\') { + if (c === '\\') { + err('\\ is an invalid code point.'); + } + state = 'relative slash'; + } else if (c === '?') { + this._host = base._host; + this._port = base._port; + this._path = base._path.slice(); + this._query = '?'; + this._username = base._username; + this._password = base._password; + state = 'query'; + } else if (c === '#') { + this._host = base._host; + this._port = base._port; + this._path = base._path.slice(); + this._query = base._query; + this._fragment = '#'; + this._username = base._username; + this._password = base._password; + state = 'fragment'; + } else { + var nextC = input[cursor + 1]; + var nextNextC = input[cursor + 2]; + if (this._scheme !== 'file' || !ALPHA.test(c) || nextC !== ':' && nextC !== '|' || nextNextC !== EOF && nextNextC !== '/' && nextNextC !== '\\' && nextNextC !== '?' && nextNextC !== '#') { + this._host = base._host; + this._port = base._port; + this._username = base._username; + this._password = base._password; + this._path = base._path.slice(); + this._path.pop(); + } + state = 'relative path'; + continue; + } + break; + case 'relative slash': + if (c === '/' || c === '\\') { + if (c === '\\') { + err('\\ is an invalid code point.'); + } + if (this._scheme === 'file') { + state = 'file host'; + } else { + state = 'authority ignore slashes'; + } + } else { + if (this._scheme !== 'file') { + this._host = base._host; + this._port = base._port; + this._username = base._username; + this._password = base._password; + } + state = 'relative path'; + continue; + } + break; + case 'authority first slash': + if (c === '/') { + state = 'authority second slash'; + } else { + err('Expected \'/\', got: ' + c); + state = 'authority ignore slashes'; + continue; + } + break; + case 'authority second slash': + state = 'authority ignore slashes'; + if (c !== '/') { + err('Expected \'/\', got: ' + c); + continue; + } + break; + case 'authority ignore slashes': + if (c !== '/' && c !== '\\') { + state = 'authority'; + continue; + } else { + err('Expected authority, got: ' + c); + } + break; + case 'authority': + if (c === '@') { + if (seenAt) { + err('@ already seen.'); + buffer += '%40'; + } + seenAt = true; + for (var i = 0; i < buffer.length; i++) { + var cp = buffer[i]; + if (cp === '\t' || cp === '\n' || cp === '\r') { + err('Invalid whitespace in authority.'); + continue; + } + if (cp === ':' && this._password === null) { + this._password = ''; + continue; + } + var tempC = percentEscape(cp); + if (this._password !== null) { + this._password += tempC; + } else { + this._username += tempC; + } + } + buffer = ''; + } else if (c === EOF || c === '/' || c === '\\' || c === '?' || c === '#') { + cursor -= buffer.length; + buffer = ''; + state = 'host'; + continue; + } else { + buffer += c; + } + break; + case 'file host': + if (c === EOF || c === '/' || c === '\\' || c === '?' || c === '#') { + if (buffer.length === 2 && ALPHA.test(buffer[0]) && (buffer[1] === ':' || buffer[1] === '|')) { + state = 'relative path'; + } else if (buffer.length === 0) { + state = 'relative path start'; + } else { + this._host = IDNAToASCII.call(this, buffer); + buffer = ''; + state = 'relative path start'; + } + continue; + } else if (c === '\t' || c === '\n' || c === '\r') { + err('Invalid whitespace in file host.'); + } else { + buffer += c; + } + break; + case 'host': + case 'hostname': + if (c === ':' && !seenBracket) { + this._host = IDNAToASCII.call(this, buffer); + buffer = ''; + state = 'port'; + if (stateOverride === 'hostname') { + break loop; + } + } else if (c === EOF || c === '/' || c === '\\' || c === '?' || c === '#') { + this._host = IDNAToASCII.call(this, buffer); + buffer = ''; + state = 'relative path start'; + if (stateOverride) { + break loop; + } + continue; + } else if (c !== '\t' && c !== '\n' && c !== '\r') { + if (c === '[') { + seenBracket = true; + } else if (c === ']') { + seenBracket = false; + } + buffer += c; + } else { + err('Invalid code point in host/hostname: ' + c); + } + break; + case 'port': + if (/[0-9]/.test(c)) { + buffer += c; + } else if (c === EOF || c === '/' || c === '\\' || c === '?' || c === '#' || stateOverride) { + if (buffer !== '') { + var temp = parseInt(buffer, 10); + if (temp !== relative[this._scheme]) { + this._port = temp + ''; + } + buffer = ''; + } + if (stateOverride) { + break loop; + } + state = 'relative path start'; + continue; + } else if (c === '\t' || c === '\n' || c === '\r') { + err('Invalid code point in port: ' + c); + } else { + invalid.call(this); + } + break; + case 'relative path start': + if (c === '\\') { + err('\'\\\' not allowed in path.'); + } + state = 'relative path'; + if (c !== '/' && c !== '\\') { + continue; + } + break; + case 'relative path': + if (c === EOF || c === '/' || c === '\\' || !stateOverride && (c === '?' || c === '#')) { + if (c === '\\') { + err('\\ not allowed in relative path.'); + } + var tmp; + if (tmp = relativePathDotMapping[buffer.toLowerCase()]) { + buffer = tmp; + } + if (buffer === '..') { + this._path.pop(); + if (c !== '/' && c !== '\\') { + this._path.push(''); + } + } else if (buffer === '.' && c !== '/' && c !== '\\') { + this._path.push(''); + } else if (buffer !== '.') { + if (this._scheme === 'file' && this._path.length === 0 && buffer.length === 2 && ALPHA.test(buffer[0]) && buffer[1] === '|') { + buffer = buffer[0] + ':'; + } + this._path.push(buffer); + } + buffer = ''; + if (c === '?') { + this._query = '?'; + state = 'query'; + } else if (c === '#') { + this._fragment = '#'; + state = 'fragment'; + } + } else if (c !== '\t' && c !== '\n' && c !== '\r') { + buffer += percentEscape(c); + } + break; + case 'query': + if (!stateOverride && c === '#') { + this._fragment = '#'; + state = 'fragment'; + } else if (c !== EOF && c !== '\t' && c !== '\n' && c !== '\r') { + this._query += percentEscapeQuery(c); + } + break; + case 'fragment': + if (c !== EOF && c !== '\t' && c !== '\n' && c !== '\r') { + this._fragment += c; + } + break; + } + cursor++; + } + } + + function clear() { + this._scheme = ''; + this._schemeData = ''; + this._username = ''; + this._password = null; + this._host = ''; + this._port = ''; + this._path = []; + this._query = ''; + this._fragment = ''; + this._isInvalid = false; + this._isRelative = false; + } + + function JURL(url, base) { + if (base !== undefined && !(base instanceof JURL)) { + base = new JURL(String(base)); + } + this._url = url; + clear.call(this); + var input = url.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g, ''); + parse.call(this, input, null, base); + } + + JURL.prototype = { + toString: function toString() { + return this.href; + }, + + get href() { + if (this._isInvalid) { + return this._url; + } + var authority = ''; + if (this._username !== '' || this._password !== null) { + authority = this._username + (this._password !== null ? ':' + this._password : '') + '@'; + } + return this.protocol + (this._isRelative ? '//' + authority + this.host : '') + this.pathname + this._query + this._fragment; + }, + set href(value) { + clear.call(this); + parse.call(this, value); + }, + get protocol() { + return this._scheme + ':'; + }, + set protocol(value) { + if (this._isInvalid) { + return; + } + parse.call(this, value + ':', 'scheme start'); + }, + get host() { + return this._isInvalid ? '' : this._port ? this._host + ':' + this._port : this._host; + }, + set host(value) { + if (this._isInvalid || !this._isRelative) { + return; + } + parse.call(this, value, 'host'); + }, + get hostname() { + return this._host; + }, + set hostname(value) { + if (this._isInvalid || !this._isRelative) { + return; + } + parse.call(this, value, 'hostname'); + }, + get port() { + return this._port; + }, + set port(value) { + if (this._isInvalid || !this._isRelative) { + return; + } + parse.call(this, value, 'port'); + }, + get pathname() { + return this._isInvalid ? '' : this._isRelative ? '/' + this._path.join('/') : this._schemeData; + }, + set pathname(value) { + if (this._isInvalid || !this._isRelative) { + return; + } + this._path = []; + parse.call(this, value, 'relative path start'); + }, + get search() { + return this._isInvalid || !this._query || this._query === '?' ? '' : this._query; + }, + set search(value) { + if (this._isInvalid || !this._isRelative) { + return; + } + this._query = '?'; + if (value[0] === '?') { + value = value.slice(1); + } + parse.call(this, value, 'query'); + }, + get hash() { + return this._isInvalid || !this._fragment || this._fragment === '#' ? '' : this._fragment; + }, + set hash(value) { + if (this._isInvalid) { + return; + } + this._fragment = '#'; + if (value[0] === '#') { + value = value.slice(1); + } + parse.call(this, value, 'fragment'); + }, + get origin() { + var host; + if (this._isInvalid || !this._scheme) { + return ''; + } + switch (this._scheme) { + case 'data': + case 'file': + case 'javascript': + case 'mailto': + return 'null'; + case 'blob': + try { + return new JURL(this._schemeData).origin || 'null'; + } catch (_) { + } + return 'null'; + } + host = this.host; + if (!host) { + return ''; + } + return this._scheme + '://' + host; + } + }; + var OriginalURL = globalScope.URL; + if (OriginalURL) { + JURL.createObjectURL = function (blob) { + return OriginalURL.createObjectURL.apply(OriginalURL, arguments); + }; + JURL.revokeObjectURL = function (url) { + OriginalURL.revokeObjectURL(url); + }; + } + globalScope.URL = JURL; + })(); + } + + /***/ + }), + /* 37 */ + /***/ (function (module, exports, __w_pdfjs_require__) { + + "use strict"; + + + var isReadableStreamSupported = false; + if (typeof ReadableStream !== 'undefined') { + try { + new ReadableStream({ + start: function start(controller) { + controller.close(); + } + }); + isReadableStreamSupported = true; + } catch (e) { + } + } + if (isReadableStreamSupported) { + exports.ReadableStream = ReadableStream; + } else { + exports.ReadableStream = __w_pdfjs_require__(18).ReadableStream; + } + + /***/ + }) + /******/]); +}); +//# sourceMappingURL=pdf.worker.js.map \ No newline at end of file diff --git a/twake/frontend/public/public/viewer/PDFViewer/pdf.worker.js.map b/twake/frontend/public/public/viewer/PDFViewer/pdf.worker.js.map new file mode 100755 index 00000000..68f2025f --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/pdf.worker.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///webpack/bootstrap 709206543ea702ff19cc","webpack:///src/shared/util.js","webpack:///src/core/primitives.js","webpack:///src/core/stream.js","webpack:///src/core/colorspace.js","webpack:///src/core/encodings.js","webpack:///src/core/parser.js","webpack:///src/core/glyphlist.js","webpack:///src/core/function.js","webpack:///src/core/unicode.js","webpack:///src/core/arithmetic_decoder.js","webpack:///src/core/cff_parser.js","webpack:///src/core/chunked_stream.js","webpack:///src/core/crypto.js","webpack:///src/core/evaluator.js","webpack:///src/core/jpx.js","webpack:///src/core/obj.js","webpack:///src/core/standard_fonts.js","webpack:///src/core/worker.js","webpack:///external/streams/streams-lib.js","webpack:///src/core/annotation.js","webpack:///src/core/bidi.js","webpack:///src/core/charsets.js","webpack:///src/core/cmap.js","webpack:///src/core/document.js","webpack:///src/core/font_renderer.js","webpack:///src/core/fonts.js","webpack:///src/core/image.js","webpack:///src/core/jbig2.js","webpack:///src/core/jpg.js","webpack:///src/core/metrics.js","webpack:///src/core/murmurhash3.js","webpack:///src/core/pattern.js","webpack:///src/core/pdf_manager.js","webpack:///src/core/ps_parser.js","webpack:///src/core/type1_parser.js","webpack:///src/pdf.worker.js","webpack:///src/shared/compatibility.js","webpack:///src/shared/streams_polyfill.js"],"names":["getLookupTableFactory","getGlyphsUnicode","t","getDingbatsGlyphsUnicode","exports","getSpecialPUASymbols","mapSpecialUnicodeValues","code","getUnicodeForGlyph","name","glyphsUnicodeMap","unicode","undefined","nameLen","length","hexStr","substr","toUpperCase","parseInt","UnicodeRanges","getUnicodeRangeFor","value","i","ii","range","begin","end","isRTLRangeFor","getNormalizedUnicodes","reverseIfRtl","chars","charsLength","charCodeAt","s"],"mappings":"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S,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS;AAG/C,MAAI,kBAAkB,CAAC,IAAI,WAAW,CACpC,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAAS,SAC/D,SAAS,SAAS,SAAS,SAAS,SAAS,SA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,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,eAAe,CAAC,GAAG,eACvB,CAAC,GAAG,eAAe,CAAC,GAAG,eACvB,CAAC,GAAG,eAAe,CAAC,GAAG,eACvB,CAAC,GAAG,eAAe,CAAC,GAAG,eACvB,CAAC,GAAG,eAAe,CAAC,GAAG,eACvB,CAAC,GAAG,eAAe,CAAC,GAAG,eACvB,CAAC,GAAG,eAAe,CAAC,GAAG,eACvB,CAAC,GAAG,eAAe,CAAC,GAAG,eACvB,CAAC,GAAG,eAAe,CAAC,GAAG,eACvB,CAAC,GAAG,eAAe,CAAC,GAAG,eACvB,CAAC,GAAG,eAAe,CAAC,GAAG,eACvB,CAAC,GAAG,eAAe,CAAC,GAAG,eACvB,CAAC,GAAG,eAAe,CAAC,GAAG,eACvB,CAAC,GAAG,eAAe,CAAC,GAAG,eACvB,CAAC,GAAG,eAAe,CAAC,GAAG,eACvB,CAAC,GAAG,eAAe,CAAC,GAAG,eACvB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG,cACtB,CAAC,GAAG,cAAc,CAAC,GAAG;AAGxB,MAAI,cAAc,CAChB,CAAC,CAAC,GAAG,CAAC,IACN,CAAC,IAAI,WACL,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAChB,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IACpC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IACpC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IACpC,CAAC,IAAI,OAAO,CAAC,IAAI,OACjB,CAAC,IAAI,OACL,CAAC,IAAI,OACL,CAAC,IAAI,OACL,CAAC,IAAI,OACL,CAAC,IAAI,OACL,CAAC,IAAI,OACL,CAAC,IAAI,OAAO,CAAC,IAAI,OACjB,CAAC,IAAI,OAAO,CAAC,IAAI,OACjB,CAAC,IAAI,OACL,CAAC,IAAI,OACL,CAAC,IAAI,OACL,CAAC,IAAI;AAGP,MAAI,cAAc,CAChB,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IACpC,CAAC,GAAG,KAAK,CAAC,GAAG,KACb,CAAC,GAAG,KAAK,CAAC,GAAG,KACb,CAAC,GAAG,KAAK,CAAC,GAAG,KACb,CAAC,GAAG,KAAK,CAAC,GAAG,KACb,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KACb,CAAC,GAAG,KAAK,CAAC,GAAG,KACb,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KACb,CAAC,GAAG,KAAK,CAAC,GAAG,KACb,CAAC,GAAG,KAAK,CAAC,GAAG,KACb,CAAC,GAAG,KAAK,CAAC,GAAG,KACb,CAAC,GAAG,KAAK,CAAC,GAAG,KACb,CAAC,GAAG,KAAK,CAAC,GAAG,KACb,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KACb,CAAC,GAAG,KAAK,CAAC,GAAG,KACb,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KACb,CAAC,GAAG,KAAK,CAAC,GAAG,KACb,CAA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AAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,MAClC,CAAC,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,MAClC,CAAC,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,MAClC,CAAC,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,MAClC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAC5B,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IA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AI,KACL,CAAC,IAAI,KAAK,CAAC,IAAI,KACf,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAC/B,CAA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AAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM;AAEpB,MAAI,IAAI,IAAI,WAAW,CACrB,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM;AAEpB,MAAI,QAAQ,IAAI,WAAW,CACzB,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM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AM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM;AAEpB,MAAI,QAAQ,IAAI,WAAW,CACzB,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM;AAEpB,MAAI,SAAS,IAAI,WAAW;AAC5B,OAAK,IAAI,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,QAAI,IAAI,KAAK;AACX,aAAO,KAAK,KAAK;AADnB,WAEO;AACL,aAAO,KAAM,KAAK,IAAK;AAJG;AAlDmB;AAyDjD,MAAI,MAAM,IAAI,YAAY,CACxB,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,YAAY,YAAY,YAAY,YAAY,YAC5D,YAAY,Y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M;AACpE,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AACpE,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAK,IAAE,MAAM;AAAI,IAAE,MAAM;AACrE,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AACpE,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AACpE,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AACpE,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AACpE,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AACpE,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AACpE,IAAE,MAAM;AAAI,IAAE,MAAM;AAAI,IAAE,MAAM;AAAK,IAAE,MAAM;AAAK,IAAE,MAAM;AAAK,IAAE,MAAM;AACvE,IAAE,MAAM;AAAK,IAAE,MAAM;AAAK,IAAE,MAAM;AAAK,IAAE,MAAM;AAAK,IAAE,MAAM;AAC5D,IAAE,MAAM;AAAK,IAAE,MAAM;AAAK,IAAE,MAAM;AAAK,IAAE,MAAM;AAAK,IAAE,MAAM;AAC5D,IAAE,MAAM;AAAK,IAAE,MAAM;AAAK,IAAE,MAAM;AAAK,IAAE,MAAM;AAAK,IAAE,MAAM;AAC5D,IAAE,MAAM;AAAK,IAAE,MAAM;AAAK,IAAE,MAAM;AAAK,IAAE,MAAM;AAAK,IAAE,MAAM;AAC5D,IAAE,MAAM;AAAK,IAAE,MAAM;AAAK,IAAE,MAAM;AAAK,IAAE,MAAM;AAAK,IAAE,MAAM;AAC5D,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AACjE,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AACjE,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AACjE,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AACjE,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AACjE,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AACjE,IAAE,OAAO;AAAM,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAClE,IAAE,OAAO;AAAM,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAClE,IAAE,OAAO;AAAM,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAM,IAAE,OAAO;AACnE,IAAE,OAAO;AAAK,IAAE,OAAO;AAAM,IAAE,OAAO;AAAK,IAAE,OAAO;AAAM,IAAE,OAAO;AACnE,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAM,IAAE,OAAO;AAAM,IAAE,OAAO;AACnE,IAAE,OAAO;AAAM,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAM,IAAE,OAAO;AACnE,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AACjE,IAAE,OAAO;AAAK,IAAE,OAAO;AAAM,IAAE,OAAO;AAAM,IAAE,OAAO;AAAK,IAAE,OAAO;AACnE,IAAE,OAAO;AAAM,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAClE,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AACjE,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AACjE,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AACjE,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AACjE,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AACjE,IAAE,OAAO;AAAK,IAAE,OAAO;AAAM,IAAE,OAAO;AAAM,IAAE,OAAO;AAAM,IAAE,OAAO;AACpE,IAAE,OAAO;AAAM,IAAE,OAAO;AAAM,IAAE,OAAO;AAAM,IAAE,OAAO;AACtD,IAAE,OAAO;AAAM,IAAE,OAAO;AAAM,IAAE,OAAO;AAAM,IAAE,OAAO;AAAO,IAAE,OAAO;AACtE,IAAE,OAAO;AAAM,IAAE,OAAO;AAAM,IAAE,OAAO;AAAM,IAAE,OAAO;AAAM,IAAE,OAAO;AACrE,IAAE,OAAO;AAAM,IAAE,OAAO;AAAM,IAAE,OAAO;AAAM,IAAE,OAAO;AAAK,IAAE,OAAO;AACpE,IAAE,OAAO;AAAM,IAAE,OAAO;AAAM,IAAE,OAAO;AAAK,IAAE,OAAO;AAAK,IAAE,OAAO;AACnE,IAAE,OAAO;AAAK,IAAE,OAAO;AAAO,IAAE,OAAO;AAAO,IAAE,OAAO;AACvD,IAAE,OAAO;AAAO,IAAE,OAAO;AAAO,IAAE,OAAO;AAAO,IAAE,OAAO;AACzD,IAAE,OAAO;AAAO,IAAE,OAAO;AAAO,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAK,IAAE,QAAQ;AAAK,IAAE,QAAQ;AAAK,IAAE,QAAQ;AACvE,IAAE,QAAQ;AAAK,IAAE,QAAQ;AAAK,IAAE,QAAQ;AAAK,IAAE,QAAQ;AAAK,IAAE,QAAQ;AACtE,IAAE,QAAQ;AAAK,IAAE,QAAQ;AAAK,IAAE,QAAQ;AAAK,IAAE,QAAQ;AAAK,IAAE,QAAQ;AACtE,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAC1D,IAAE,QAAQ;AAAM,IAAE,QAAQ;AAAO,IAAE,QAAQ;AAAO,IAAE,QAAQ;AAC5D,IAAE,QAAQ;AAAO,IAAE,QAAQ;AAAO,IAAE,QAAQ;AAAO,IAAE,QAAQ;AAC7D,I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ACvD,uBAAuB,kBAAkB,aAAa,aACtD,gBAAgB,aAAa,aAAa,aAAa,aACvD,aAAa,aAAa,aAAa,aAAa,aACpD,aAAa,MAAM,MAAM,MAAM,OAAO,OAAO,qBAC7C,sBAAsB,kBAAkB,iBAAiB,aACzD,UAAU,gBAAgB,cAAc,kBAAkB,cAC1D,WAAW,iBAAiB,aAAa,gBAAgB,eACzD,gBAAgB,YAAY,aAAa,gBAAgB,eACzD,eAAe,iBAAiB,gBAAgB,gBAChD,eAAe,iBAAiB,iBAAiB,gBACjD,gBAAgB,eAAe,eAAe,iBAC9C,gBAAgB,gBAAgB,eAAe,iBAC/C,iBAAiB,gBAAgB,gBAAgB,kBACjD,kBAGF;QACE;QACA;QACA,0C;;;;;;;;;;;;;;ACpGK;;AACwC;;AACzB;;AACC;;AAEvB,IAAI,iBAAiB,CAErB,kBACA,mBACA,qBACA,qBAEA,YACA,YACA,QACA,aACA,aACA,QACA,eACA,eACA,eACA,eACA,eACA,gBACA,gBACA,eACA,eACA,SACA,cACA,cACA,SACA,gBACA,gBACA,gBACA,gBACA,gBACA,gBACA,gBACA,eACA,eACA,eACA,eACA,eACA,eACA,kBACA,kBACA,kBACA,kBACA,kBACA,kBACA,kBACA,kBACA,kBACA,kBACA,QACA,QACA,UACA,UACA,aACA,aACA,UACA,UACA,UACA,UACA,aACA,aACA,aACA,aACA,eACA,eACA,SACA,SACA,SACA,cACA,cACA,SACA,YACA,YACA,QACA,QACA,aACA,aACA,WACA,WACA,cACA,cACA,aACA,aACA,SACA,SACA,eACA,eACA,cACA,cACA,KACA,cACA,cACA,cACA,cACA,eACA,eACA,eACA,eACA,eACA,eACA,cACA,cACA,WACA,YACA,aACA,aACA,SACA,eACA,eACA,SACA,eACA,kBACA,kBACA,eACA,eACA,eACA,YACA,SACA,SACA,UACA,UACA,SACA,iBACA,iBACA,kBACA,kBACA,kBACA,kBACA,iBACA,iBACA,gBACA,gBACA,iBACA,iBACA,iBACA,iBACA,gBACA,gBACA,iBACA,oBACA,oBACA,iBACA,kBACA,kBACA,kBACA,kBACA,iBACA,iBACA,sBACA,sBACA,sBACA,sBACA,qBACA,qBACA,uBACA,oBACA,oBACA,uBACA,uBACA,2BACA,2BACA,gBACA,gBACA,iBACA,iBACA,iBACA,iBACA,gBACA,gBACA,KACA;AAGA,IAAI,gBAAiB,cAAc;AACjC,WAAS,KAAK,aAAa;AAIzB,SAAK,kBAAkB,CAAC,IAAI,IAAI,IAAI;AACpC,SAAK,qBAAqB;AAK1B,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,WAAW;AAChB,SAAK,UAAU;AACf,SAAK,cAAc;AAfY;AAiBjC,OAAK;AACH,kDAAkB,GAAG,KAAK,MAAM;AAC9B,WAAK,gBAAgB,IAAI,GAAG,KAAK,KAAK;AACtC,WAAK;AAHQ;AAMf,sCAAY,KAAK,MAAM,QAAQ;AAC7B,aAAO,OAAO,MAAM;AAClB,aAAK,KAAK,SAAS;AAFQ;AANhB;AAYf,oCAAW,KAAK,MAAM,QAAQ;AAC5B,UAAI,WAAW,OAAO,SAAS;AAC/B,aAAO,OAAO,MAAM;AAClB,aAAK,KAAK,SAAS;AAEnB,iBAAS,OAAO,OAAO,GAAG,YACjB,OAAO,aAAa,OAAO,WAAW,YAAY;AANjC;AAZf;AAsBf,kDAAkB,KAAK,MAAM,OAAO;AAClC,UAAI,IAAI;UAAG,KAAK,MAAM;AACtB,aAAO,OAAO,QAAQ,IAAI,IAAI;AAC5B,aAAK,KAAK,OAAO,MAAM;AACvB,UAAE;AAJ8B;AAtBrB;AA+Bf,4BAAO,KAAK,KAAK;AACf,WAAK,KAAK,OAAO;AAhCJ;AAmCf,4BAAO,MAAM;AACX,aAAO,KAAK,KAAK;AApCJ;AAuCf,gCAAS,MAAM;AACb,aAAO,KAAK,KAAK,UAAU;AAxCd;AA2Cf,8BAAQ,UAAU;AAMhB,UAAI,MAAM,KAAK;AACf,UAAI,SAAS,IAAI;AACjB,UAAI,UAAU,SAAS;AACrB,aAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,cAAI,IAAI,OAAO,WAAW;AACxB,qBAAS,GAAG,IAAI;AAFa;AADZ;AAAvB,aAMO;AACL,iBAAS,MAAK,KAAK;AACjB,mBAAS,IAAG,IAAI;AAFb;AAdS;AA3CH;AAgEf,oCAAW,OAAO;AAGhB,UAAI,MAAM,KAAK;AACf,UAAI,IAAI,UAAU,SAAS;AACzB,eAAO,IAAI,QAAQ;AALL;AAOhB,eAAS,YAAY,KAAK;AACxB,YAAI,IAAI,cAAc,OAAO;AAC3B,iBAAQ,WAAW;AAFG;AAPV;AAYhB,aAAO,CAAC;AA5EK;AA+Ef,8BAAS;AACP,aAAO,KAAK;AAhFC;AAmFf,wCAAa,KAAK,QAAQ,KAAK;AAC7B,UAAI,IAAI;AACR,UAAI,kBAAkB,KAAK;AAC3B,UAAI,qBAAqB,KAAK,gBAAgB;AAG9C,WAAK,IAAI,IAAI,GAAG,IAAI,oBAAoB,KAAK;AAC3C,YAAK,CAAC,KAAK,IAAK,IAAI,WAAW,SAAS,QAAQ;AAEhD,YAAI,iBAAiB,gBAAgB;AACrC,aAAK,IAAI,IAAI,GAAG,KAAK,eAAe,QAAQ,IAAI,KAAK;AACnD,cAAI,MAAM,eAAe;AACzB,cAAI,OAAO,eAAe;AAC1B,cAAI,KAAK,OAAO,KAAK,MAAM;AACzB,gBAAI,WAAW;AACf,gBAAI,SAAS,IAAI;AACjB;AANiD;AAJV;AANhB;AAoB7B,UAAI,WAAW;AACf,UAAI,SAAS;AAxGA;;AA2Gf,QAAI,SAAS;AACX,aAAO,KAAK,KAAK;AA5GJ;AA+Gf,QAAI,iBAAiB;AACnB,UAAM,OAAK,SAAS,gBAAgB,KAAK,SAAS,eAAe;AAC/D,eAAO;AAFU;AAInB,UAAI,KAAK,KAAK,WAAW,SAAS;AAChC,eAAO;AALU;AAOnB,WAAK,IAAI,IAAI,GAAG,IAAI,SAAS,KAAK;AAChC,YAAI,KAAK,KAAK,OAAO,GAAG;AACtB,iBAAO;AAFuB;AAPf;AAYnB,aAAO;AA3HM;AAAA;AA8HjB,SAAO;AA/IE,CAAC;AAoJZ,IAAI,wBAAyB,sBAAsB;AACjD,WAAS,aAAa,UAAU,GAAG;AACjC,SAAK,KAAK;AACV,SAAK,WAAW;AAChB,SAAK,kBAAkB,GAAG,GAAG;AAJkB;AAMjD,aAAK,QAAQ,cAAc,MAAM;AAEjC,eAAa;AACX,uBAAmB,KAAK,UAAU;AAElC,sCAAY,KAAK,MAAM,QAAQ;AAC7B,YAAM,IAAI,MAAM;AAJK;AAOvB,oCAAW,KAAK,MAAM,QAAQ;AAC5B,YAAM,IAAI,MAAM;AARK;AAWvB,kDAAkB,KAAK,MAAM,OAAO;AAClC,YAAM,IAAI,MAAM;AAZK;AAevB,4BAAO,KAAK,KAAK;AACf,YAAM,IAAI,MAAM;AAhBK;AAmBvB,4BAAO,MAAM;AACX,aAAQ,iBAAM,SAAS,QAAQ,SAAU,OAAO;AApB3B;AAuBvB,gCAAS,MAAM;AACb,aAAO,iBAAM,SAAS,QAAQ;AAxBT;AA2BvB,8BAAQ,UAAU;AAChB,WAAK,IAAI,IAAI,GAAG,KAAK,QAAQ,KAAK;AAChC,iBAAS,GAAG;AAFE;AA3BK;AAiCvB,oCAAW,OAAO;AAChB,aAAQ,iBAAM,UAAU,SAAS,SAAU,QAAQ,CAAC;AAlC/B;AAqCvB,8BAAS;AAEP,UAAI,MAAM,IAAI,MAAM;AACpB,WAAK,IAAI,IAAI,GAAG,KAAK,QAAQ,KAAK;AAChC,YAAI,KAAK;AAJJ;AAMP,aAAO;AA3Cc;;AA8CvB,kBAAc,KAAK,UAAU;AAE7B,QAAI,SAAS;AACX,aAAO;AAjDc;AAoDvB,QAAI,iBAAiB;AACnB,YAAM,IAAI,MAAM;AArDK;AAAA;AAyDzB,SAAO;AAjEU,CAAC;AAoEpB,IAAI,4BAA6B,0BAA0B;AACzD,WAAS,SAAS,GAAG,MAAM;AACzB,QAAI,IAAI;AACR,SAAK,IAAI,IAAI,GAAG,KAAK,MAAM,KAAK;AAC9B,UAAK,KAAK,IAAK,EAAE;AAHM;AAKzB,WAAO,MAAM;AAN0C;AASzD,WAAS,SAAS,GAAG,MAAM;AAGzB,QAAI,SAAS,GAAG;AACd,aAAO,OAAO,aAAa,EAAE,IAAI,EAAE;AAJZ;AAMzB,QAAI,SAAS,GAAG;AACd,aAAO,OAAO,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;AAPxB;AASzB,WAAO,OAAO,aAAa,MAAM,MAAM,EAAE,SAAS,GAAG,OAAO;AAlBL;AAqBzD,WAAS,OAAO,GAAG,GAAG,MAAM;AAC1B,QAAI,IAAI;AACR,SAAK,IAAI,IAAI,MAAM,KAAK,GAAG,KAAK;AAC9B,WAAK,EAAE,KAAK,EAAE;AACd,QAAE,KAAK,IAAI;AACX,YAAM;AALkB;AArB6B;AA8BzD,WAAS,OAAO,GAAG,MAAM;AACvB,QAAI,IAAI;AACR,SAAK,IAAI,IAAI,MAAM,KAAK,KAAK,IAAI,GAAG,KAAK;AACvC,WAAK,EAAE;AACP,QAAE,KAAK,IAAI;AACX,YAAM;AALe;AA9BgC;AAuCzD,MAAI,eAAe;AACnB,MAAI,uBAAuB;AAE3B,WAAS,iBAAiB,MAAM;AAC9B,SAAK,SAAS;AACd,SAAK,MAAM;AACX,SAAK,MAAM,KAAK;AAChB,SAAK,SAAS,IAAI,WAAW;AA9C0B;AAiDzD,mBAAiB;AACf,kCAAW;AACT,UAAI,KAAK,OAAO,KAAK,KAAK;AACxB,eAAO,CAAC;AAFD;AAIT,aAAO,KAAK,OAAO,KAAK;AALC;AAO3B,sCAAa;AACX,UAAI,IAAI;AACR,UAAI;AACJ,SAAG;AACD,YAAI,IAAI,KAAK;AACb,YAAI,IAAI,GAAG;AACT,gBAAU,sBAAY;AAHvB;AAKD,eAAS,MAAI;AACb,YAAK,KAAK,IAAM,IAAI;AANtB,eAOS,CAAC;AACV,aAAO;AAlBkB;AAoB3B,sCAAa;AACX,UAAI,IAAI,KAAK;AACb,aAAQ,IAAI,IAAO,QAAM,KAAK,MAAM;AAtBX;AAwB3B,8BAAQ,KAAK,MAAM;AACjB,UAAI,IAAI,KAAK,OAAO,SAAS,KAAK,KAChC,KAAK,MAAM,OAAO;AACpB,WAAK,OAAO,OAAO;AA3BM;AA6B3B,0CAAc,KAAK,MAAM;AACvB,UAAI;AACJ,UAAI,QAAQ,KAAK;UAAQ,KAAK;AAC9B,SAAG;AACD,YAAI,IAAI,KAAK;AACb,YAAI,IAAI,GAAG;AACT,gBAAU,sBAAY;AAHvB;AAKD,eAAS,MAAI;AACb,cAAM,QAAQ,IAAI;AANpB,eAOS,CAAC;AACV,UAAI,IAAI;UAAM,SAAS;UAAG,aAAa;AACvC,aAAO,KAAK,GAAG;AACb,eAAO,aAAa,KAAK,MAAM,SAAS,GAAG;AACzC,mBAAU,MAAM,EAAE,OAAO,aAAc;AACvC,wBAAc;AAHH;AAKb,YAAI,KAAK,SAAS;AAClB;AACA,mBAAW;AACX,sBAAc;AApBO;AA7BE;AAoD3B,0CAAc,KAAK,MAAM;AACvB,WAAK,cAAc,KAAK;AACxB,UAAI,OAAO,IAAI,QAAQ,IAAI,MAAM;AACjC,UAAI,IAAI;AACR,WAAK,IAAI,IAAI,GAAG,KAAK,MAAM,KAAK;AAC9B,YAAM,KAAI,MAAM,IAAK,IAAI;AACzB,YAAI,KAAM,KAAK,IAAK;AANC;AApDE;AA6D3B,sCAAa;AACX,UAAI,MAAM,KAAK;AACf,UAAI,IAAI;AACR,WAAK,IAAI,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,aAAK,OAAO,aAAa,KAAK;AAJrB;AAMX,aAAO;AAnEkB;AAAA;AAuE7B,WAAS,kBAAkB,MAAM,MAAM,QAAQ;AAC7C,eAAW,QAAQ,UAAU,SAAS,QAAQ;AAC5C,UAAI,SAAS,IAAI,iBAAiB;AAClC,UAAI,SAAS,OAAO;AACpB,WAAK,WAAW,CAAG,WAAS;AAE5B,UAAI,UAAU;AACd,UAAI,QAAQ,IAAI,WAAW;AAC3B,UAAI,MAAM,IAAI,WAAW;AACzB,UAAI,OAAO,IAAI,WAAW;AAC1B,UAAI,WAAW,IAAI,WAAW;AAC9B,UAAI,MAAM,IAAI,WAAW;AACzB,UAAI;AAEJ,UAAI;AACJ,aAAQ,KAAI,OAAO,eAAe,GAAG;AACnC,YAAI,OAAO,KAAK;AAChB,YAAI,SAAS,GAAG;AACd,kBAAQ,IAAI;AACV,iBAAK;AACH,qBAAO;AACP;AACF,iBAAK;AACH,wBAAU,OAAO;AACjB;;AAEJ;AAXiC;AAanC,YAAI,WAAW,CAAG,MAAI;AACtB,YAAI,WAAW,IAAI;AAEnB,YAAI,WAAW,IAAI,cAAc;AAC/B,gBAAM,IAAI,MAAM;AAjBiB;AAoBnC,YAAI,eAAe;AACnB,YAAI,gBAAgB,OAAO;AAC3B,YAAI;AACJ,gBAAQ;AACN,eAAK;AACH,mBAAO,QAAQ,OAAO;AACtB,mBAAO,cAAc,KAAK;AAC1B,mBAAO,KAAK,OAAO;AACnB,iBAAK,kBAAkB,WAAW,GAAG,SAAS,OAAO,WAC9B,SAAS,KAAK;AACrC,iBAAK,IAAI,GAAG,IAAI,eAAe,KAAK;AAClC,qBAAO,KAAK;AACZ,qBAAO,cAAc,OAAO;AAC5B,qBAAO,OAAO,KAAK;AACnB,qBAAO,cAAc,KAAK;AAC1B,qBAAO,KAAK,OAAO;AACnB,mBAAK,kBAAkB,WAAW,GAAG,SAAS,OAAO,WAC9B,SAAS,KAAK;AAbzC;AAeE;AACF,eAAK;AACH,mBAAO,QAAQ,OAAO;AACtB,mBAAO,cAAc,KAAK;AAC1B,mBAAO,KAAK,OAAO;AACnB,mBAAO,OAAO;AAEd,iBAAK,IAAI,GAAG,IAAI,eAAe,KAAK;AAClC,qBAAO,KAAK;AACZ,qBAAO,cAAc,OAAO;AAC5B,qBAAO,OAAO,KAAK;AACnB,qBAAO,cAAc,KAAK;AAC1B,qBAAO,KAAK,OAAO;AACnB,qBAAO,OAAO;AAZlB;AAeE;AACF,eAAK;AACH,mBAAO,QAAQ,MAAM;AACrB,mBAAO,OAAO;AACd,iBAAK,OAAO,SAAS,MAAM,WAAW;AACtC,iBAAK,IAAI,GAAG,IAAI,eAAe,KAAK;AAClC,qBAAO,MAAM;AACb,kBAAI,CAAC,UAAU;AACb,uBAAO,cAAc,KAAK;AAC1B,uBAAO,MAAM,KAAK;AAJc;AAMlC,qBAAO,OAAuB,uBAAO;AACrC,mBAAK,OAAO,SAAS,MAAM,WAAW;AAX1C;AAaE;AACF,eAAK;AACH,mBAAO,QAAQ,OAAO;AACtB,mBAAO,cAAc,KAAK;AAC1B,mBAAO,KAAK,OAAO;AACnB,mBAAO,OAAO;AACd,iBAAK,YAAY,SAAS,OAAO,WAAW,SAAS,KAAK,WACzC;AACjB,iBAAK,IAAI,GAAG,IAAI,eAAe,KAAK;AAClC,qBAAO,KAAK;AACZ,kBAAI,CAAC,UAAU;AACb,uBAAO,cAAc,OAAO;AAC5B,uBAAO,OAAO,KAAK;AAFrB,qBAGO;AACL,sBAAM,IAAI;AANsB;AAQlC,qBAAO,cAAc,KAAK;AAC1B,qBAAO,KAAK,OAAO;AACnB,qBAAO,OAAO;AACd,mBAAK,YAAY,SAAS,OAAO,WAChB,SAAS,KAAK,WAAW;AAnB9C;AAqBE;AACF,eAAK;AACH,mBAAO,QAAQ,MAAM;AACrB,mBAAO,QAAQ,UAAU;AACzB,iBAAK,OAAO,SAAS,MAAM,eACf,SAAS,UAAU;AAC/B,iBAAK,IAAI,GAAG,IAAI,eAAe,KAAK;AAClC,qBAAO,MAAM;AACb,kBAAI,CAAC,UAAU;AACb,uBAAO,cAAc,KAAK;AAC1B,uBAAO,MAAM,KAAK;AAJc;AAMlC,qBAAO,UAAU;AACjB,qBAAO,cAAc,KAAK;AAC1B,qBAAO,UAAU,KAAK;AACtB,mBAAK,OAAO,SAAS,MAAM,eACf,SAAS,UAAU;AAfnC;AAiBE;AACF,eAAK;AACH,mBAAO,QAAQ,OAAO;AACtB,mBAAO,cAAc,KAAK;AAC1B,mBAAO,KAAK,OAAO;AACnB,mBAAO,QAAQ,UAAU;AACzB,iBAAK,WAAW,SAAS,OAAO,eAChB,SAAS,KAAK,eACd,SAAS,UAAU;AACnC,iBAAK,IAAI,GAAG,IAAI,eAAe,KAAK;AAClC,qBAAO,KAAK;AACZ,kBAAI,CAAC,UAAU;AACb,uBAAO,cAAc,OAAO;AAC5B,uBAAO,OAAO,KAAK;AAFrB,qBAGO;AACL,sBAAM,IAAI;AANsB;AAQlC,qBAAO,cAAc,KAAK;AAC1B,qBAAO,KAAK,OAAO;AACnB,qBAAO,QAAQ,UAAU;AACzB,mBAAK,WAAW,SAAS,OAAO,eAChB,SAAS,KAAK,eACd,SAAS,UAAU;AArBvC;AAuBE;AACF;AACE,mBAAO,IAAI,MAAM,sCAAsC;AACvD;;AAtJsC;AA0J5C,UAAI,SAAS;AACX,gBAAQ,OAAO;AACf;AA5J0C;AA8J5C,cAAQ;AA9JH;AAzHgD;AA2RzD,WAAS,mBAAmB,CA3R6B;AA6RzD,mBAAiB,YAAY,EAC3B,SAAS;AAGX,SAAO;AAjSc,CAAC;AAoSxB,IAAI,uBAAwB,qBAAqB;AAC/C,WAAS,SAAS,KAAK;AACrB,QAAI,IAAI;AACR,SAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAK,KAAK,IAAK,IAAI,WAAW;AAHX;AAKrB,WAAO,MAAM;AANgC;AAS/C,WAAS,aAAa,KAAK;AACzB,QAAI,CAAC,oBAAS,MAAM;AAClB,YAAU,sBAAY;AAFC;AAToB;AAe/C,WAAS,UAAU,KAAK;AACtB,QAAI,CAAC,iBAAM,MAAM;AACf,YAAU,sBAAY;AAFF;AAfuB;AAqB/C,WAAS,YAAY,MAAM,OAAO;AAChC,WAAO,MAAM;AACX,UAAI,MAAM,MAAM;AAChB,UAAI,uBAAM,MAAM;AACd;AAHS;AAKX,UAAI,uBAAM,KAAK,cAAc;AAC3B;AANS;AAQX,mBAAa;AACb,UAAI,MAAM,SAAS;AACnB,YAAM,MAAM;AAEZ,mBAAa;AACb,UAAI,MAAM;AACV,WAAK,OAAO,KAAK;AAfa;AArBa;AAwC/C,WAAS,aAAa,MAAM,OAAO;AACjC,WAAO,MAAM;AACX,UAAI,MAAM,MAAM;AAChB,UAAI,uBAAM,MAAM;AACd;AAHS;AAKX,UAAI,uBAAM,KAAK,eAAe;AAC5B;AANS;AAQX,mBAAa;AACb,UAAI,MAAM,SAAS;AACnB,YAAM,MAAM;AACZ,mBAAa;AACb,UAAI,OAAO,SAAS;AACpB,YAAM,MAAM;AACZ,UAAI,iBAAM,QAAQ,oBAAS,MAAM;AAC/B,YAAI,SAAS,iBAAM,OAAO,OAAO,aAAa,OAAO;AACrD,aAAK,WAAW,KAAK,MAAM;AAF7B,iBAGW,uBAAM,KAAK,MAAM;AAC1B,cAAM,MAAM;AACZ,YAAI,QAAQ;AACZ,eAAO,CAAC,uBAAM,KAAK,QAAQ,CAAC,uBAAM,MAAM;AACtC,gBAAM,KAAK;AACX,gBAAM,MAAM;AALY;AAO1B,aAAK,kBAAkB,KAAK,MAAM;AAP7B,aAQA;AACL;AA1BS;AADoB;AA8BjC,UAAU,sBAAY;AAtEuB;AAyE/C,WAAS,aAAa,MAAM,OAAO;AACjC,WAAO,MAAM;AACX,UAAI,MAAM,MAAM;AAChB,UAAI,uBAAM,MAAM;AACd;AAHS;AAKX,UAAI,uBAAM,KAAK,eAAe;AAC5B;AANS;AAQX,mBAAa;AACb,UAAI,MAAM,SAAS;AACnB,YAAM,MAAM;AACZ,gBAAU;AACV,UAAI,MAAM;AACV,WAAK,OAAO,KAAK;AAdc;AAzEY;AA2F/C,WAAS,cAAc,MAAM,OAAO;AAClC,WAAO,MAAM;AACX,UAAI,MAAM,MAAM;AAChB,UAAI,uBAAM,MAAM;AACd;AAHS;AAKX,UAAI,uBAAM,KAAK,gBAAgB;AAC7B;AANS;AAQX,mBAAa;AACb,UAAI,MAAM,SAAS;AACnB,YAAM,MAAM;AACZ,mBAAa;AACb,UAAI,OAAO,SAAS;AACpB,YAAM,MAAM;AACZ,gBAAU;AACV,UAAI,SAAS;AACb,WAAK,YAAY,KAAK,MAAM;AAjBI;AA3FW;AAgH/C,WAAS,oBAAoB,MAAM,OAAO;AACxC,WAAO,MAAM;AACX,UAAI,MAAM,MAAM;AAChB,UAAI,uBAAM,MAAM;AACd;AAHS;AAKX,UAAI,uBAAM,KAAK,sBAAsB;AACnC;AANS;AAQX,UAAI,CAAC,oBAAS,MAAM;AAClB;AATS;AAWX,UAAI,MAAM,SAAS;AACnB,YAAM,MAAM;AACZ,UAAI,CAAC,oBAAS,MAAM;AAClB;AAdS;AAgBX,UAAI,OAAO,SAAS;AACpB,WAAK,kBAAkB,IAAI,QAAQ,KAAK;AAlBF;AAoBxC,UAAU,sBAAY;AApIuB;AAuI/C,WAAS,WAAW,MAAM,OAAO;AAC/B,QAAI,MAAM,MAAM;AAChB,QAAI,iBAAM,MAAM;AACd,WAAK,WAAW,CAAC,CAAC;AAHW;AAvIc;AA8I/C,WAAS,cAAc,MAAM,OAAO;AAClC,QAAI,MAAM,MAAM;AAChB,QAAI,wBAAO,QAAQ,oBAAS,IAAI,OAAO;AACrC,WAAK,OAAO,IAAI;AAHgB;AA9IW;AAqJ/C,WAAS,UAAU,MAAM,OAAO,kBAAkB,SAAS;AACzD,QAAI;AACJ,QAAI;AACJ,aAAS,OAAO,MAAM;AACpB,UAAI;AACF,YAAI,MAAM,MAAM;AAChB,YAAI,uBAAM,MAAM;AACd;AADF,mBAEW,wBAAO,MAAM;AACtB,cAAI,IAAI,SAAS,SAAS;AACxB,uBAAW,MAAM;AADnB,iBAEO,IAAI,IAAI,SAAS,YAAY;AAClC,0BAAc,MAAM;AAJA;AAMtB,qBAAW;AANN,eAOA,IAAI,uBAAM,MAAM;AACrB,kBAAQ,IAAI;AACV,iBAAK;AACH,oBAFJ;AAGE,iBAAK;AACH,kBAAI,wBAAO,WAAW;AACpB,iCAAiB,SAAS;AAF9B;AAIE;AACF,iBAAK;AACH,kCAAoB,MAAM;AAC1B;AACF,iBAAK;AACH,0BAAY,MAAM;AAClB;AACF,iBAAK;AACH,2BAAa,MAAM;AACnB;AACF,iBAAK;AACH,2BAAa,MAAM;AACnB;AACF,iBAAK;AACH,4BAAc,MAAM;AACpB;;AAlCJ;AAAJ,QAqCE,OAAO,IAAI;AACX,YAAkB,0CAAsB;AACtC,gBAAM;AAFG;AAIX,wBAAK,wBAAwB;AAC7B;AA3CkB;AAHmC;AAkDzD,QAAI,CAAC,WAAW,gBAAgB;AAG9B,gBAAU;AArD6C;AAuDzD,QAAI,SAAS;AACX,aAAO,WAAW,MAAM,kBAAkB;AAxDa;AA0DzD,WAAO,QAAQ,QAAQ;AA/MsB;AAkN/C,WAAS,WAAW,MAAM,kBAAkB,SAAS;AACnD,6BAAyB,SAAS,kBAAkB,KAAK,UAAS,SAAS;AACzE,WAAK,UAAU;AAGf,UAAI,KAAK,uBAAuB,GAAG;AACjC,YAAI,qBAAqB,KAAK,QAAQ;AACtC,aAAK,IAAI,IAAI,GAAG,IAAI,mBAAmB,QAAQ,KAAK;AAClD,eAAK,gBAAgB,KAAK,mBAAmB,GAAG;AAHjB;AAKjC,aAAK,qBAAqB,KAAK,QAAQ;AATgC;AAazE,WAAK,QAAQ,QAAQ,UAAS,KAAK,OAAO;AACxC,YAAI,CAAC,KAAK,SAAS,MAAM;AACvB,eAAK,OAAO,KAAK,KAAK,QAAQ,OAAO;AAFC;AAA1C;AAMA,aAAO;AAnBF;AAnNsC;AA0O/C,WAAS,kBAAkB,MAAM,kBAAkB;AACjD,QAAI,SAAS,cAAc;AACzB,aAAO,QAAQ,QAAQ,IAAI,aAAa,OAAO;AADjD,WAEO,IAAI,SAAS,cAAc;AAChC,aAAO,QAAQ,QAAQ,IAAI,aAAa,MAAM;AAJC;AAMjD,QAAI,eAAe,QAAQ,UAAU,CAAC,GAAG;AACvC,aAAO,QAAQ,OAAO,IAAI,MAAM,wBAAwB;AAPT;AASjD,QAAI,CAAC,kBAAkB;AACrB,aAAO,QAAQ,OAAO,IAAI,MACxB;AAX6C;AAcjD,4BAAwB,MAAM,KAAK,UAAU,MAAM;AACjD,UAAI,WAAW,KAAK;UAAU,kBAAkB,KAAK;AACrD,UAAI,OAAO,IAAI,KAAK;AAEpB,UAAI,oBAAoB,0BAAoB,QAAQ;AAClD,mBAAW,mBAAmB,QAAQ,UAAU,MAC5C,UAAU,SAAS;AACrB,iBAAO,WAAW,MAAM,kBAAkB;AAFrC;AALwC;AAUjD,UAAI,oBAAoB,0BAAoB,MAAM;AAChD,YAAI,QAAY,kBAAU,mBAAO;AACjC,eAAO,UAAU,MAAM,OAAO,kBAAkB;AAZD;AAcjD,aAAO,QAAQ,OAAO,IAAI,MACxB;AAfG;AAxPsC;AA2Q/C;AACE,4BAAO,QAAQ;AACb,UAAI,WAAW,OAAO;AACtB,UAAI,mBAAmB,OAAO;AAC9B,UAAI,UAAU,OAAO;AAErB,UAAI,wBAAO,WAAW;AACpB,eAAO,kBAAkB,SAAS,MAAM;AAD1C,aAEO,IAAI,0BAAS,WAAW;AAC7B,YAAI,OAAO,IAAI;AACf,YAAI,QAAY,kBAAM;AACtB,yBAAiB,MAAM,OAAO,kBAAkB,SAAS,KACrD,UAAU,YAAY;AACxB,cAAI,WAAW,gBAAgB;AAC7B,mBAAO,kBAAkB,WAAW,MAAM;AAFpB;AAIxB,iBAAO;AALF;AAVI;AAkBb,aAAO,QAAQ,OAAO,IAAI,MAAM;AAnB7B;AAAA;AAwBT,CAnSmB;QAoSjB;QACA;QACA,0B;;;;;;;;;;;;;;;;ACv9B0C;;AACG;;AAIxC;;AACmD;;AACX;;AACb;;AACL;;AACC;;AAE9B,IAAI,gBAAiB,cAAc;AAEjC,MAAI,oBAAoB;AACxB,MAAI,uBAAuB,CAAC,GAAG,GAAG,KAAK;AAEvC,WAAS,uBAAuB,YAAY,QAAQ;AAClD,WAAQ,WAAW,aAAa,WAAW,YACnC,WAAW,WAAW,WAAW;AAPV;AAUjC,WAAS,KAAK,YAAY,MAAM,WAAW,UAAU,KAAK,WAC5C,kBAAkB;AAC9B,SAAK,aAAa;AAClB,SAAK,YAAY;AACjB,SAAK,WAAW;AAChB,SAAK,OAAO;AACZ,SAAK,MAAM;AACX,SAAK,YAAY;AACjB,SAAK,mBAAmB;AACxB,SAAK,mBAAmB,WAAW;AACnC,SAAK,mBAAmB;AAExB,QAAI,eAAe,MAAM,KAAK,YAAY;AAC1C,QAAI,aAAa,EACf,KAAK;AAEP,SAAK;AACH,0CAAc;AACZ,eAAO,eAAgB,EAAE,WAAW;AAFvB;AAAA;AA1Bc;AAiCjC,OAAK;AACH,iBAAa,SAAS,iBAAiB,KAAK;AAC1C,aAAO,KAAK,SAAS,IAAI;AAFZ;AAKf,0BAAsB,SAAS,0BAA0B,KAAK,UAAU;AACtE,UAAI,OAAO,KAAK;UAAU,aAAa;UAAM,YAAY;AACzD,UAAI,iBAAiB;AACrB,iBAAW,YAAY;AAGvB,aAAO,MAAM;AACX,YAAI,QAAQ,WAAW,KAAK,SAAS,OAAO,KAAK,IAAI;AACrD,YAAI,UAAU,WAAW;AACvB,cAAI,CAAC,YAAY;AACf,yBAAa;AAFQ;AAIvB,qBAAW,KAAK;AANP;AAQX,YAAI,EAAE,YAAY,gBAAgB;AAChC,0BAAK,2DAA2D;AAChE,iBAAO,aAAa,WAAW,KAAK;AAV3B;AAYX,eAAO,KAAK,IAAI;AAlBoD;AAoBtE,UAAI,CAAC,YAAY;AACf,eAAO;AArB6D;AAuBtE,UAAI,WAAW,WAAW,KAAK,CAAC,wBAAO,WAAW,KAAK;AACrD,eAAO,WAAW;AAxBkD;AA0BtE,aAAO,iBAAK,MAAM,KAAK,MAAM;AA/BhB;AAkCf,QAAI,UAAU;AACZ,aAAO,KAAK,YAAY;AAnCX;AAsCf,QAAI,YAAY;AAId,aAAO,kBAAO,MAAM,aACN,KAAK,qBAAqB,gBAAgB,iBAAK;AA3ChD;AA8Cf,QAAI,WAAW;AACb,UAAI,WAAW,KAAK,qBAAqB,YAAY;AAErD,UAAI,CAAC,mBAAQ,aAAa,SAAS,WAAW,GAAG;AAC/C,eAAO,kBAAO,MAAM,YAAY;AAJrB;AAMb,aAAO,kBAAO,MAAM,YAAY;AApDnB;AAuDf,QAAI,UAAU;AACZ,UAAI,UAAU,KAAK,qBAAqB,WAAW;AAEnD,UAAI,CAAC,mBAAQ,YAAY,QAAQ,WAAW,GAAG;AAC7C,eAAO,kBAAO,MAAM,WAAW,KAAK;AAJ1B;AAMZ,aAAO,kBAAO,MAAM,WAAW;AA7DlB;AAgEf,QAAI,WAAW;AACb,UAAI,MAAM,KAAK,YAAY;AAC3B,UAAI,CAAC,iBAAM,QAAQ,OAAO,GAAG;AAC3B,cAAM;AAHK;AAKb,aAAO,kBAAO,MAAM,YAAY;AArEnB;AAwEf,QAAI,OAAO;AAKT,UAAI,WAAW,KAAK;UAAU,UAAU,KAAK;AAC7C,UAAI,aAAa,SAAS;AACxB,eAAO,kBAAO,MAAM,QAAQ;AAPrB;AAST,UAAI,eAAe,WAAK,UAAU,SAAS;AAC3C,aAAO,kBAAO,MAAM,QAAQ,gBAAgB;AAlF/B;AAqFf,QAAI,SAAS;AACX,UAAI,SAAS,KAAK,qBAAqB,aAAa;AAEpD,UAAI,SAAS,OAAO,GAAG;AACrB,iBAAS;AADX,iBAEW,UAAU,KAAK;AACxB,iBAAS,SAAS;AADb,aAEA,IAAI,SAAS,GAAG;AAGrB,iBAAU,CAAC,SAAS,MAAO,OAAO;AAVzB;AAYX,aAAO,kBAAO,MAAM,UAAU;AAjGjB;AAoGf,sBAAkB,SAAS,wBAAwB;AACjD,UAAI,UAAU,KAAK;AACnB,UAAI;AACJ,UAAI,mBAAQ,UAAU;AAEpB,YAAI,OAAO,KAAK;AAChB,YAAI;YAAG,IAAI,QAAQ;AACnB,YAAI,UAAU;AACd,aAAK,IAAI,GAAG,IAAI,GAAG,EAAE,GAAG;AACtB,kBAAQ,KAAK,KAAK,WAAW,QAAQ;AANnB;AAQpB,iBAAa,kCAAsB;AARrC,iBASW,0BAAS,UAAU;AAC5B,iBAAS;AADJ,aAEA;AAEL,iBAAa;AAhBkC;AAkBjD,aAAO;AAtHM;AAyHf,mBAAe,SAAS,mBAAmB;AAAM;;AAC/C,UAAI,CAAC,KAAK,kBAAkB;AAE1B,aAAK,mBAAmB,KAAK,WAAW,OAAO,MAAM;AAHR;AAK/C,kBAAY,iBAAiB,KAAK,YAAM;AACtC,YAAI,eAAmB,sBAAa,MAAK,WAAW,MAAM,MAAK;AAE/D,eAAO,aAAa;AAHf;AA9HM;AAqIC;AAAoD;;UAAlD;UAAS;UAAM;UAAQ;;AACvC,UAAI,uBAAuB,KAAK,WAAW,OAAO,MACA;AAClD,UAAI,mBAAmB,KAAK,cAAc,CACxC,aACA,cACA,WACA,WACA,WACA;AAKF,UAAI;AACF,oBAAY,KAAK;AACjB,cAAM,KAAK;AACX;AACA,mBAAW,KAAK;AAChB,mBAAW,KAAK;AAChB,mBAAW,KAAK;AAChB,0BAAkB,KAAK;AACvB,iBAAS,KAAK;AAR4B,OAAjB;AAW3B,UAAI,eAAe,QAAQ,IAAI,CAAC,sBAAsB;AACtD,UAAI,+BAA+B,KAAM;AAAoB;YAAnB;;AACxC,YAAI,SAAa,4BAAa,QAAQ,SAAS,OAAK;AAEpD,gBAAQ,KAAK;AACX,wBAAc,iBAAiB,cAAc,OAAK;AAClD,qBAAW,OAAK;AAChB;AAH8B;AAKhC,gCAAwB;AACtB,kBAAQ;AACR;AACA,qBAAW,OAAK;AAChB,wBAAc;AAJwB,SAAjC,EAKJ,KAAK,YAAY;AAClB,iBAAO;AANF;AARa;AAoBtB,UAAI,qBAAqB,KAAK,WAAW,OAAO,MAAM;AACtD,qBAAe,IAAI,CAAC,iBAAiB,qBAAqB,KAC5C;AAA2B;YAA1B;YAAY;;AACzB,YAAI,YAAY,WAAW,GAAG;AAC5B,qBAAW,MAAM;AACjB,iBAAO;AAH8B;AAQvC,YAAI;YAAG;YAAI,iBAAiB;AAC5B,aAAK,IAAI,GAAG,KAAK,YAAY,QAAQ,IAAI,IAAI,KAAK;AAChD,cAAI,uBAAuB,YAAY,IAAI,SAAS;AAClD,2BAAe,KAAK,YAAY,GAAG,gBACjC,kBAAkB,MAAM;AAHoB;AATX;AAgBvC,uBAAe,IAAI,gBAAgB,KAAK,UAAS,SAAS;AACxD,qBAAW,MAAM,UAAI,kBAAkB;AACvC,eAAK,IAAI,GAAG,KAAK,QAAQ,QAAQ,IAAI,IAAI,KAAK;AAC5C,uBAAW,UAAU,QAAQ;AAHyB;AAKxD,qBAAW,MAAM,UAAI,gBAAgB;AAErC,qBAAW,MAAM;AACjB,iBAAO;AARF;AAjBF;AApLM;AAkNI;AAC6B;;UAD3B;UAAS;UAAM;UACf;UAAM;;AACzB,UAAI,uBAAuB,KAAK,WAAW,OAAO,MACA;AAClD,UAAI,mBAAmB,KAAK,cAAc,CACxC,aACA,WACA;AAGF,UAAI,eAAe,QAAQ,IAAI,CAAC,sBAAsB;AACtD,0BAAoB,KAAM;AAAoB;YAAnB;;AACzB,YAAI;AACF,sBAAY,OAAK;AACjB,gBAAM,OAAK;AACX;AACA,qBAAW,OAAK;AAChB,qBAAW,OAAK;AAChB,qBAAW,OAAK;AAChB,4BAAkB,OAAK;AACvB,mBAAS,OAAK;AAR4B,SAAjB;AAW3B,gCAAwB;AACtB,kBAAQ;AACR;AACA,qBAAW,OAAK;AAChB;AACA;AACA;AANqC,SAAhC;AAZF;AA7NM;;AAoPf,wBAAoB,SAAS,wBAAwB,QAAQ;AAC3D,UAAI,cAAc,KAAK;AACvB,UAAI,kBAAkB;AACtB,WAAK,IAAI,IAAI,GAAG,IAAI,YAAY,QAAQ,IAAI,GAAG,EAAE,GAAG;AAClD,YAAI,CAAC,UAAU,uBAAuB,YAAY,IAAI,SAAS;AAC7D,0BAAgB,KAAK,YAAY,GAAG;AAFY;AAHO;AAQ3D,aAAO;AA5PM;AA+Pf,QAAI,cAAc;AAChB,UAAI,cAAc;AAClB,UAAI,iBAAiB,KAAK,qBAAqB,aAAa;AAC5D,UAAI,oBAAwB;AAC5B,WAAK,IAAI,IAAI,GAAG,IAAI,eAAe,QAAQ,IAAI,GAAG,EAAE,GAAG;AACrD,YAAI,gBAAgB,eAAe;AACnC,YAAI,aAAa,kBAAkB,OAAO,KAAK,MAAM,eACX,KAAK,YACL,KAAK;AAC/C,YAAI,YAAY;AACd,sBAAY,KAAK;AANkC;AAJvC;AAahB,aAAO,kBAAO,MAAM,eAAe;AA5QtB;AAAA;AAgRjB,SAAO;AAjTE,CAAC;AA2TZ,IAAI,uBAAwB,qBAAqB;AAC/C,MAAI,0BAA0B;AAC9B,MAAI,oBAAoB,iCACtB;AAEF,WAAS,YAAY,YAAY,KAAK;AACpC,QAAI;AACJ,QAAI,0BAAS,MAAM;AACjB,eAAS;AADX,eAEW,yBAAc,MAAM;AAC7B,eAAa,mBAAO;AADf,WAEA;AACL,YAAM,IAAI,MAAM;AAPkB;AASpC,QAAI,OAAO,UAAU,GAAG;AACtB,YAAM,IAAI,MAAM;AAVkB;AAapC,SAAK,aAAa;AAClB,SAAK,SAAS;AACd,SAAK,OAAW,cAAK,QAAQ;AApBgB;AAuB/C,WAAS,KAAK,QAAQ,QAAQ,OAAO,WAAW;AAC9C,QAAI,MAAM,OAAO;AACjB,QAAI,MAAM,OAAO;AACjB,QAAI,SAAS;AACb,QAAI,MAAM,QAAQ,KAAK;AACrB,cAAQ,MAAM;AAL8B;AAO9C,SAAK,IAAI,IAAI,GAAG,IAAI,OAAO,EAAE,GAAG;AAC9B,aAAO,KAAK,OAAO,aAAa,OAAO;AARK;AAU9C,QAAI,MAAM,OAAO,KAAK;AACtB,WAAO,MAAM;AACb,QAAI,QAAQ,YAAY,IAAI,YAAY,UAAU,IAAI,QAAQ;AAC9D,QAAI,UAAU,CAAC,GAAG;AAChB,aAAO;AAdqC;AAgB9C,WAAO,OAAO;AACd,WAAO;AAxCsC;AA2C/C,MAAI;AACF,QAAI,UAAU;AAGZ,+BAAc,MAAM;AACX;AACC;AACC;AACC;AACD;AACC;AACI;AACL;AACA;AAToB,OAAxB;AAJkB;AAAA;AAkB7B,cAAY;AACV,WAAO,SAAS,kBAAkB,cAAc;AAC9C,WAAK,MAAM;AACX,UAAI,UAAU,KAAK,QAAQ,QAAQ,IAAI;AACvC,UAAI,wBAAO,UAAU;AACnB,aAAK,mBAAmB,QAAQ;AAJY;AAM9C,UAAI;AAEF,aAAK,WAAW,KAAK,QAAQ,QAAQ,IAAI;AACzC,YAAI,KAAK,UAAU;AACjB,eAAK,MAAM,KAAK,SAAS,IAAI;AAC7B,cAAI,SAAS,KAAK,SAAS,IAAI;AAC/B,cAAK,EAAC,UAAU,CAAC,mBAAQ,WAAW,OAAO,WAAW,MAClD,CAAC,KAAK,KAAK;AAEb,iBAAK,WAAW;AAND;AAHjB;AAAJ,QAYE,OAAO,IAAI;AACX,YAAkB,0CAAsB;AACtC,gBAAM;AAFG;AAIX,wBAAK;AACL,aAAK,WAAW;AAvB4B;AAD1B;AA4BtB,QAAI,gBAAgB;AAClB,UAAI,gBAAgB;AACpB,UAAI,KAAK,OAAO,QAAQ;AACtB,YAAI;AACF,0BAAgB,sBAAc,OAAO,KAAK;AAD5C,UAEE,OAAO,KAAK;AACZ,cAAmB,2CAAsB;AACvC,kBAAM;AAFI;AAIZ,0BAAK;AAPe;AAFN;AAalB,aAAO,kBAAO,MAAM,iBAAiB;AAzCjB;AA2CtB,QAAI,YAAY;AACd,UAAI,SAAS,KAAK;AAClB,UAAI,YAAY;AAChB,UAAI,gBAAgB,KAAK;AACzB,UAAI,eAAe;AAEjB,eAAO;AACP,YAAI,KAAK,QAAQ,UAAU,OAAO;AAChC,sBAAY,OAAO,MAAM;AAJV;AAAnB,aAMO;AAEL,YAAI,OAAO;AACX,YAAI,QAAQ;YAAO,MAAM,OAAO;AAChC,eAAO,CAAC,SAAS,MAAM,GAAG;AACxB,iBAAO,OAAO,YAAY;AAC1B,cAAI,MAAM,GAAG;AACX,kBAAM;AAHgB;AAKxB,iBAAO,MAAM;AACb,kBAAQ,KAAK,QAAQ,aAAa,MAAM;AAVrC;AAYL,YAAI,OAAO;AACT,iBAAO,KAAK;AACZ,cAAI;AACJ,aAAG;AACD,iBAAK,OAAO;AADd,mBAES,mBAAQ;AACjB,cAAI,MAAM;AACV,iBAAO,MAAM,QAAQ,MAAM,MAAM;AAC/B,mBAAO,OAAO,aAAa;AAC3B,iBAAK,OAAO;AATL;AAWT,sBAAY,SAAS,KAAK;AAC1B,cAAI,MAAM,YAAY;AACpB,wBAAY;AAbL;AAZN;AAVO;AAwCd,aAAO,kBAAO,MAAM,aAAa;AAnFb;AAqFtB,QAAI,wBAAwB;AAC1B,UAAI,wBAAwB;AAC5B,UAAI,gBAAgB,KAAK;AACzB,UAAI,eAAe;AACjB,gCAAwB,cAAc;AAJd;AAO1B,aAAO,kBAAO,MAAM,yBAAyB;AA5FzB;AAgGtB,iBAAa,SAAS,0BAA0B;AAC9C,UAAI,SAAS,KAAK;AAClB,aAAO;AACP,UAAI,KAAK,QAAQ,SAAS,OAAO;AAE/B,eAAO;AAEP,YAAI,qBAAqB;AACzB,YAAI,UAAU;YAAI;AAClB,eAAQ,MAAK,OAAO,aAAa,MAAM;AACrC,cAAI,QAAQ,UAAU,oBAAoB;AACxC;AAFmC;AAIrC,qBAAW,OAAO,aAAa;AAVF;AAY/B,YAAI,CAAC,KAAK,kBAAkB;AAE1B,eAAK,mBAAmB,QAAQ,UAAU;AAdb;AAgB/B;AAnB4C;AAhG1B;AAuHtB,oBAAgB,SAAS,6BAA6B;AACpD,UAAI,YAAY,KAAK;AACrB,WAAK,KAAK,aAAa;AAzHH;AA2HtB,WAAO,SAAS,kBAAkB;AAAc;;AAC9C,WAAK,KAAK,MAAM;AAChB,UAAI;AACF,oBAAY,oBAAC,WAAW,MAAM,KAAK,WAAW,kBAAqB;AACjE,iBAAO,IAAI,KAAK,OAAK,YAAY,OAAK,MAAM,WAAW,MAAM,KAC7C,WAAW;AAHb;AAAA;AAMlB,WAAK,UAAc,iBAAQ,KAAK,YAAY,KAAK,MAAM;AAnInC;AAqItB,QAAI,WAAW;AACb,UAAI,gBAAgB,KAAK;AACzB,UAAI,MAAM,gBAAgB,cAAc,WAAW,KAAK,QAAQ;AAEhE,aAAO,kBAAO,MAAM,YAAY;AAzIZ;AA2ItB,QAAI,eAAe;AACjB,UAAI;AACF,0BAAkB,KAAK;AACvB,2BAAmB,CAAC,CAAC,KAAK;AAC1B,sBAAc,CAAC,CAAC,KAAK;AAHT;AAKd,UAAI;AACJ,UAAI;AACF,mBAAW,KAAK,KAAK,QAAQ,IAAI;AADnC,QAEE,OAAO,KAAK;AACZ,YAAmB,2CAAsB;AACvC,gBAAM;AAFI;AAIZ,wBAAK;AAbU;AAejB,UAAI,UAAU;AACZ,YAAI,eAAe,uBAAuB;AAE1C,iBAAS,OAAO,cAAc;AAC5B,cAAI,SAAS,IAAI,MAAM;AACrB,gBAAI,QAAQ,SAAS,IAAI;AAEzB,gBAAI,aAAa,KAAK,QAAQ;AAC5B,sBAAQ,OAAQ,OAAO,UAAU,WACjB,QAAQ,6BAAkB;AAF5C,mBAGO;AACL,8BAAK,qCAAqC,MAAM;AAP7B;AADK;AAHlB;AAfG;AA+BjB,aAAO,kBAAO,MAAM,gBAAgB;AA1KhB;AA4KtB,QAAI,cAAc;AAChB,UAAI,OAAO,KAAK;UAAM;UAAM,SAAS;AACrC,UAAI,UAAU,KAAK,QAAQ,IAAI;AAE/B,UAAI,WAAW,mBAAQ,YAAY,QAAQ,MAAM,oBAAS,QAAQ,OAC9D,QAAQ,OAAO,mBAAmB;AACpC,eAAO,yBAAc,QAAQ;AAF/B,aAGO;AACL,YAAI,KAAK,OAAO,aAAa;AAC3B,eAAK,OAAO,YAAY,GACtB,KAAK,IAAI,yBAAyB,KAAK,OAAO;AAH7C;AAKL,eAAO,0BAAa,KAAK,OAAO,MAAM,SAAS,GAC7C,0BAA0B,GAAG;AAbjB;AAgBhB,WAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,IAAI,GAAG,KAAK;AAC3C,YAAI,MAAM,KAAK,GAAG,SAAS;AAC3B,kBAAU,IAAI,WAAW,IAAI,MAAM,MAAM;AAlB3B;AAqBhB,aAAO,kBAAO,MAAM,eAAe;AAjMf;AAoMtB,aAAS,SAAS,oBAAoB,WAAW;AAC/C,aAAO,KAAK,QAAQ,QAAQ;AArMR;AAwMtB,aAAS,SAAS,sBAAsB;AACtC,aAAO,KAAK,QAAQ;AAzMA;AAAA;AA6MxB,SAAO;AAGT,CA7QmB;QA8QjB;QACA,0B;;;;;;;;;;;;;;ACtlB+C;;AACvB;;AACO;;AACA;;AACV;;AAEvB,IAAI,+BAAgC,6BAA6B;AAC/D,WAAS,QAAQ,MAAM,QAAQ;AAC7B,WAAQ,KAAK,WAAW,KAAO,KAAK,SAAS,MAAM,KAC3C,KAAK,SAAS,MAAM,IAAK,KAAK,SAAS;AAHc;AAM/D,WAAS,UAAU,MAAM,QAAQ;AAC/B,WAAQ,KAAK,WAAW,IAAK,KAAK,SAAS;AAPkB;AAU/D,WAAS,UAAU,MAAM,OAAO,KAAK;AACnC,QAAI,SAAU,UAAU,MAAM,QAAQ,OAAO,IAC/B,QAAQ,MAAM,QAAQ,KAAK,QAAQ,MAAM,QAAQ;AAC/D,QAAI,SAAS,UAAU,MAAM,QAAQ;AACrC,QAAI,QAAQ,GAAG;AACf,QAAI,WAAW,GAAG;AAChB,gBAAU,MAAM,QAAQ,SAAS;AACjC,UAAI,WAAW,UAAU,MAAM,QAAQ,SAAS,MAAM;AACtD,UAAI,QAAQ,SAAS;AACrB,eAAS;AACT,WAAK,IAAI,GAAG,IAAI,UAAU,KAAK,KAAK,GAAG;AACrC,eAAO,KAAK,EAAE,KAAK,UAAU,MAAM;AANrB;AAQhB,WAAK;AACL,WAAK,IAAI,GAAG,IAAI,UAAU,KAAK,KAAK,GAAG;AACrC,eAAO,GAAG,QAAQ,UAAU,MAAM;AAVpB;AAYhB,WAAK,IAAI,GAAG,IAAI,UAAU,KAAK,KAAK,GAAG;AACrC,eAAO,GAAG,UAAU,UAAU,MAAM;AAbtB;AAehB,WAAK,IAAI,GAAG,IAAI,UAAU,KAAK,KAAK,GAAG;AACrC,YAAI,WAAW,UAAU,MAAM;AAC/B,YAAI,aAAa,GAAG;AAClB;AAHmC;AAKrC,eAAO,GAAG,MAAM;AAChB,aAAK,IAAI,IAAI,GAAG,KAAK,OAAO,GAAG,MAAM,OAAO,GAAG,QAAQ,GAAG,IAAI,IAAI,KAAK;AACrE,iBAAO,GAAG,IAAI,KAAK,UAAU,MAAM,IAAI;AACvC,sBAAY;AARuB;AAfvB;AA0BhB,aAAO;AA1BT,WA2BO,IAAI,WAAW,IAAI;AACxB,cAAQ,MAAM,QAAQ,SAAS;AAC/B,UAAI,SAAS,QAAQ,MAAM,QAAQ,SAAS;AAC5C,UAAI,QAAQ,SAAS;AACrB,eAAS;AACT,WAAK,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC3B,eAAO;AACL,iBAAO,QAAQ,MAAM;AACrB,eAAK,QAAQ,MAAM,IAAI;AACvB,mBAAS,QAAQ,MAAM,IAAI,KAAK,QAAQ,MAAM;AAHpC;AAKZ,aAAK;AAXiB;AAaxB,aAAO;AA7C0B;AA+CnC,UAAuB,6CAAoB;AAzDkB;AA4D/D,WAAS,SAAS,MAAM,OAAO,KAAK,qBAAqB;AACvD,QAAI,aAAa;AACjB,QAAI,SAAa,0BAAc,mBAAO,MAAM,OAAO,MAAM,QAC9B,YAAY;AACvC,QAAI,MAAM,OAAO;AACjB;AACE,cAAQ,IAAI,YAAY;AACxB,aAAQ,IAAI,QAAQ,eAAe,IAAI,QAAQ,YAAY,cACnD,IAAI,QAAQ,YAAY,WAAW;AAC3C,cAAQ,IAAI,mBAAmB,IAAI,gBAAgB;AAJ9C;AAjEsD;AAyE/D,WAAS,eAAe,MAAM,MAAM,sBAAsB;AACxD,QAAI,UAAU;AACd,QAAI,sBAAsB;AACxB,iBAAW;AACX,mBAAa,SAAS,mBAAmB,MAAM,QAAQ;AACrD,eAAQ,KAAK,WAAW,KAAO,KAAK,SAAS,MAAM,KAC3C,KAAK,SAAS,MAAM,IAAK,KAAK,SAAS;AAFjD;AAFF,WAMO;AACL,iBAAW;AACX,mBAAa,SAAS,eAAe,MAAM,QAAQ;AACjD,eAAQ,KAAK,WAAW,IAAM,KAAK,SAAS,MAAM;AADpD;AAVsD;AAcxD,QAAI,SAAS;AACb,QAAI,cAAc,WAAW,MAAM;AACnC,SAAK,IAAI,IAAI,UAAU,IAAI,KAAK,QAAQ,KAAK,UAAU;AACrD,UAAI,YAAY,WAAW,MAAM;AACjC,aAAO,KAAK,KAAK,SAAS,aAAa;AACvC,oBAAc;AAnBwC;AAqBxD,WAAO;AA9FsD;AAiG/D,WAAS,WAAW,QAAQ,SAAS;AACnC,QAAI,OAAO,QAAQ,WAAW;QAAI,MAAM;AACxC,QAAI,IAAI;QAAG,IAAI,OAAO,SAAS;AAC/B,WAAO,IAAI,GAAG;AACZ,UAAI,IAAK,IAAI,IAAI,KAAM;AACvB,UAAI,OAAO,OAAO,GAAG,OAAO;AAC1B,YAAI,IAAI;AADV,aAEO;AACL,YAAI;AALM;AAHqB;AAWnC,QAAI,OAAO,GAAG,SAAS,QAAQ,QAAQ,OAAO,GAAG,KAAK;AACpD,YAAO,OAAO,GAAc,kBAAO,GAAG,MAC/B,OAAO,GAAG,IAAI,OAAO,OAAO,GAAG,SAAS,QAAS;AAbvB;AAenC;AACE,gBAAU;AACV,eAAS;AAFJ;AAhHsD;AAsH/D,WAAS,YAAY,MAAM,MAAM,MAAM;AACrC,aAAS,OAAO,GAAG,GAAG;AACpB,WAAK;AAAO,aAAK;AAAU,cAAM,CAAC,GAAG;AAA3B;AAFyB;AAIrC,aAAS,OAAO,GAAG,GAAG;AACpB,WAAK;AAAO,aAAK;AAAU,cAAM,CAAC,GAAG;AAA3B;AALyB;AAOrC,aAAS,iBAAiB,IAAI,IAAI,GAAG,GAAG;AACtC,WAAK;AAAO,aAAK;AAAoB,cAAM,CAAC,IAAI,IAAI,GAAG;AAA7C;AARyB;AAWrC,QAAI,IAAI;AACR,QAAI,mBAAoB,CAAC,KAAK,MAAM,KAAO,KAAK,IAAI,MAAM,OAAQ;AAClE,QAAI;AACJ,QAAI,IAAI;QAAG,IAAI;AACf,SAAK;AACL,QAAI,mBAAmB,GAAG;AAExB,SAAG;AACD,gBAAS,KAAK,MAAM,IAAK,KAAK,IAAI;AAClC,YAAI,aAAc,KAAK,IAAI,MAAM,IAAK,KAAK,IAAI;AAC/C,aAAK;AACL,YAAI,MAAM;AACV,YAAK,QAAQ,MAAO;AAClB,iBAAQ,CAAC,KAAK,MAAM,KAAO,KAAK,IAAI,MAAM,OAAQ;AAClD,iBAAQ,CAAC,KAAK,IAAI,MAAM,KAAO,KAAK,IAAI,MAAM,OAAQ;AACtD,eAAK;AAHP,eAIO;AACL,iBAAO,KAAK;AAAM,iBAAO,KAAK;AAV/B;AAYD,YAAK,QAAQ,MAAO;AACjB,cAAI;AACJ,cAAI;AAFP,eAGO;AACJ,cAAI;AAAG,cAAI;AAhBb;AAkBD,YAAI,SAAS;YAAG,SAAS;YAAG,UAAU;YAAG,UAAU;AACnD,YAAK,QAAQ,MAAO;AAClB,mBACA,SAAU,CAAC,KAAK,MAAM,KAAO,KAAK,IAAI,MAAM,MAAO;AACnD,eAAK;AAHP,mBAIY,QAAQ,MAAO;AACzB,mBAAU,CAAC,KAAK,MAAM,KAAO,KAAK,IAAI,MAAM,MAAO;AACnD,mBAAU,CAAC,KAAK,IAAI,MAAM,KAAO,KAAK,IAAI,MAAM,MAAO;AACvD,eAAK;AAHA,eAIA,IAAK,QAAQ,MAAO;AACzB,mBAAU,CAAC,KAAK,MAAM,KAAO,KAAK,IAAI,MAAM,MAAO;AACnD,oBAAW,CAAC,KAAK,IAAI,MAAM,KAAO,KAAK,IAAI,MAAM,MAAO;AACxD,oBAAW,CAAC,KAAK,IAAI,MAAM,KAAO,KAAK,IAAI,MAAM,MAAO;AACxD,mBAAU,CAAC,KAAK,IAAI,MAAM,KAAO,KAAK,IAAI,MAAM,MAAO;AACvD,eAAK;AAhCN;AAkCD,YAAI,WAAW,KAAK,OAAO;AAC3B,YAAI,UAAU;AACZ,eAAK,KAAK,EAAE,KAAK;AACjB,eAAK;AAAO,iBAAK;AACN,kBAAM,CAAC,QAAQ,SAAS,SAAS,QAAQ,GAAG;AAD7C;AAEV,sBAAY,UAAU,MAAM;AAC5B,eAAK,KAAK,EAAE,KAAK;AAxClB;AAAH,eA0CU,QAAQ;AA5CpB,WA6CO;AAEL,UAAI,mBAAmB;AACvB,UAAI,GAAG;AACP,WAAK,IAAI,GAAG,IAAI,kBAAkB,KAAK;AACrC,yBAAiB,KAAM,KAAK,MAAM,IAAK,KAAK,IAAI;AAChD,aAAK;AANF;AAQL,UAAI,oBAAqB,KAAK,MAAM,IAAK,KAAK,IAAI;AAClD,WAAK,IAAI;AACT,UAAI,iBAAiB,iBAAiB,iBAAiB,SAAS,KAAK;AACrE,UAAI,SAAS;AACb,aAAO,OAAO,SAAS,gBAAgB;AACrC,gBAAQ,KAAK;AACb,YAAI,SAAS;AACb,YAAK,QAAQ,MAAO;AAClB,oBAAU,KAAK;AAJoB;AAMrC,eAAO,WAAW,GAAG;AACnB,iBAAO,KAAK,EAAE;AAPqB;AAZlC;AAsBL,WAAK,IAAI,GAAG,IAAI,gBAAgB,KAAK;AACnC,gBAAQ,OAAO,GAAG,QAAQ;AACxB,eAAK;AACH,iBAAM,CAAC,KAAK,MAAM,KAAO,KAAK,IAAI,MAAM,OAAQ;AAChD,iBAAK;AACL;AACF,eAAK;AACH,iBAAK,KAAK;AACV;AACF,eAAK;AACH,iBAAK,KAAK;AACV;;AAEJ,eAAO,GAAG,IAAI;AAnCX;AAqCL,WAAK,IAAI,GAAG,IAAI,gBAAgB,KAAK;AACnC,gBAAQ,OAAO,GAAG,QAAQ;AACxB,eAAK;AACH,iBAAM,CAAC,KAAK,MAAM,KAAO,KAAK,IAAI,MAAM,OAAQ;AAChD,iBAAK;AACL;AACF,eAAK;AACH,iBAAK,KAAK;AACV;AACF,eAAK;AACH,iBAAK,KAAK;AACV;;AAEJ,eAAO,GAAG,IAAI;AAlDX;AAqDL,UAAI,aAAa;AACjB,WAAK,IAAI,GAAG,IAAI,kBAAkB,KAAK;AACrC,YAAI,WAAW,iBAAiB;AAGhC,YAAI,UAAU,OAAO,MAAM,YAAY,WAAW;AAClD,YAAK,QAAQ,GAAG,QAAQ,GAAI;AAC1B,kBAAQ,KAAK,QAAQ;AADvB,mBAEY,QAAQ,QAAQ,SAAS,GAAG,QAAQ,GAAI;AAElD,kBAAQ,QAAQ,QAAQ,QAAQ,SAAS;AAFpC,eAGA;AAEL,cAAI;AACF,mBAAO;AACP,eAAI,SAAQ,GAAG,IAAI,QAAQ,QAAQ,SAAS,GAAG,KAAK;AACpD,eAAI,SAAQ,GAAG,IAAI,QAAQ,QAAQ,SAAS,GAAG,KAAK;AAH9C;AAKR,kBAAQ,QAAQ;AAChB,kBAAQ,KAAK;AAlBsB;AAoBrC,eAAO,QAAQ,GAAG,GAAG,QAAQ,GAAG;AAChC,aAAK,IAAI,GAAG,KAAK,QAAQ,QAAQ,IAAI,IAAI,KAAK;AAC5C,cAAK,QAAQ,GAAG,QAAQ,GAAI;AAC1B,mBAAO,QAAQ,GAAG,GAAG,QAAQ,GAAG;AADlC,qBAEY,QAAQ,IAAI,GAAG,QAAQ,GAAI;AACrC,6BAAiB,QAAQ,GAAG,GAAG,QAAQ,GAAG,GACzB,QAAQ,IAAI,GAAG,GAAG,QAAQ,IAAI,GAAG;AAClD;AAHK,iBAIA;AACL,6BAAiB,QAAQ,GAAG,GAAG,QAAQ,GAAG,GACvC,SAAQ,GAAG,IAAI,QAAQ,IAAI,GAAG,KAAK,GACnC,SAAQ,GAAG,IAAI,QAAQ,IAAI,GAAG,KAAK;AAVI;AArBT;AAkCrC,qBAAa,WAAW;AAxFrB;AA7D8B;AAtHwB;AAgR/D,WAAS,kBAAkB,MAAM,MAAM,MAAM;AAC3C,QAAI,QAAQ;AACZ,QAAI,IAAI;QAAG,IAAI;AACf,QAAI,QAAQ;AAEZ,aAAS,OAAO,GAAG,GAAG;AACpB,WAAK;AAAO,aAAK;AAAU,cAAM,CAAC,GAAG;AAA3B;AAN+B;AAQ3C,aAAS,OAAO,GAAG,GAAG;AACpB,WAAK;AAAO,aAAK;AAAU,cAAM,CAAC,GAAG;AAA3B;AAT+B;AAW3C,aAAS,cAAc,IAAI,IAAI,IAAI,IAAI,GAAG,GAAG;AAC3C,WAAK;AAAO,aAAK;AAAiB,cAAM,CAAC,IAAI,IAAI,IAAI,IAAI,GAAG;AAAlD;AAZ+B;AAe3C,aAAS,MAAM,MAAM;AACnB,UAAI,IAAI;AACR,aAAO,IAAI,KAAK,QAAQ;AACtB,YAAI,aAAa;AACjB,YAAI,IAAI,KAAK;AACb,YAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG;AACnC,gBAAQ;AACN,eAAK;AACH,qBAAS,MAAM,UAAU;AACzB,yBAAa;AACb;AACF,eAAK;AACH,qBAAS,MAAM,UAAU;AACzB,yBAAa;AACb;AACF,eAAK;AACH,iBAAK,MAAM;AACX,mBAAO,GAAG;AACV,yBAAa;AACb;AACF,eAAK;AACH,mBAAO,MAAM,SAAS,GAAG;AACvB,mBAAK,MAAM;AACX,mBAAK,MAAM;AACX,qBAAO,GAAG;AAJd;AAME;AACF,eAAK;AACH,mBAAO,MAAM,SAAS,GAAG;AACvB,mBAAK,MAAM;AACX,qBAAO,GAAG;AACV,kBAAI,MAAM,WAAW,GAAG;AACtB;AAJqB;AAMvB,mBAAK,MAAM;AACX,qBAAO,GAAG;AARd;AAUE;AACF,eAAK;AACH,mBAAO,MAAM,SAAS,GAAG;AACvB,mBAAK,MAAM;AACX,qBAAO,GAAG;AACV,kBAAI,MAAM,WAAW,GAAG;AACtB;AAJqB;AAMvB,mBAAK,MAAM;AACX,qBAAO,GAAG;AARd;AAUE;AACF,eAAK;AACH,mBAAO,MAAM,SAAS,GAAG;AACvB,mBAAK,IAAI,MAAM;AAAS,mBAAK,IAAI,MAAM;AACvC,mBAAK,KAAK,MAAM;AAAS,mBAAK,KAAK,MAAM;AACzC,kBAAI,KAAK,MAAM;AAAS,kBAAI,KAAK,MAAM;AACvC,4BAAc,IAAI,IAAI,IAAI,IAAI,GAAG;AALrC;AAOE;AACF,eAAK;AACH,gBAAI,MAAM,QAAQ,KAAK;AACvB,uBAAW,KAAK,MAAM;AACtB,gBAAI,UAAU;AACZ,oBAAM;AAJV;AAME;AACF,eAAK;AACH;AACF,eAAK;AACH,gBAAI,KAAK;AACT,oBAAQ;AACN,mBAAK;AACH,qBAAK,IAAI,MAAM;AACf,qBAAK,KAAK,MAAM;AAAS,qBAAK,IAAI,MAAM;AACxC,oBAAI,KAAK,MAAM;AACf,8BAAc,IAAI,GAAG,IAAI,IAAI,GAAG;AAChC,qBAAK,IAAI,MAAM;AACf,qBAAK,KAAK,MAAM;AAChB,oBAAI,KAAK,MAAM;AACf,8BAAc,IAAI,IAAI,IAAI,GAAG,GAAG;AAChC;AACF,mBAAK;AACH,qBAAK,IAAI,MAAM;AAAS,qBAAK,IAAI,MAAM;AACvC,qBAAK,KAAK,MAAM;AAAS,qBAAK,KAAK,MAAM;AACzC,oBAAI,KAAK,MAAM;AAAS,oBAAI,KAAK,MAAM;AACvC,8BAAc,IAAI,IAAI,IAAI,IAAI,GAAG;AACjC,qBAAK,IAAI,MAAM;AAAS,qBAAK,IAAI,MAAM;AACvC,qBAAK,KAAK,MAAM;AAAS,qBAAK,KAAK,MAAM;AACzC,oBAAI,KAAK,MAAM;AAAS,oBAAI,KAAK,MAAM;AACvC,8BAAc,IAAI,IAAI,IAAI,IAAI,GAAG;AACjC,sBAAM;AACN;AACF,mBAAK;AACH,qBAAK,IAAI,MAAM;AAAS,qBAAK,IAAI,MAAM;AACvC,qBAAK,KAAK,MAAM;AAAS,qBAAK,KAAK,MAAM;AACzC,oBAAI,KAAK,MAAM;AACf,8BAAc,IAAI,IAAI,IAAI,IAAI,GAAG;AACjC,qBAAK,IAAI,MAAM;AACf,qBAAK,KAAK,MAAM;AAAS,qBAAK,KAAK,MAAM;AACzC,oBAAI,KAAK,MAAM;AACf,8BAAc,IAAI,IAAI,IAAI,IAAI,GAAG;AACjC;AACF,mBAAK;AACH,oBAAI,KAAK;oBAAG,KAAK;AACjB,qBAAK,IAAI,MAAM;AAAS,qBAAK,IAAI,MAAM;AACvC,qBAAK,KAAK,MAAM;AAAS,qBAAK,KAAK,MAAM;AACzC,oBAAI,KAAK,MAAM;AAAS,oBAAI,KAAK,MAAM;AACvC,8BAAc,IAAI,IAAI,IAAI,IAAI,GAAG;AACjC,qBAAK,IAAI,MAAM;AAAS,qBAAK,IAAI,MAAM;AACvC,qBAAK,KAAK,MAAM;AAAS,qBAAK,KAAK,MAAM;AACzC,oBAAI;AAAI,oBAAI;AACZ,oBAAI,KAAK,IAAI,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK;AACvC,uBAAK,MAAM;AADb,uBAEO;AACL,uBAAK,MAAM;AAZf;AAcE,8BAAc,IAAI,IAAI,IAAI,IAAI,GAAG;AACjC;AACF;AACE,sBAAuB,gDAAuB;;AAElD;AACF,eAAK;AACH,gBAAI,MAAM,UAAU,GAAG;AACrB,kBAAI,QAAQ,MAAM;AAClB,kBAAI,QAAQ,MAAM;AAClB,kBAAI,MAAM;AACV,kBAAI,MAAM;AACV,mBAAK,KAAK,EAAE,KAAK;AACjB,mBAAK;AAAO,qBAAK;AAAa,sBAAM,CAAC,GAAG;AAA9B;AACV,kBAAI,OAAO,WAAW,KAAK,MAAM,OAAO,aACtC,KAAK,aAAa,4BAAiB;AACrC,gCAAkB,KAAK,OAAO,KAAK,UAAU,MAAM;AACnD,mBAAK,KAAK,EAAE,KAAK;AAEjB,qBAAO,WAAW,KAAK,MAAM,OAAO,aAClC,KAAK,aAAa,4BAAiB;AACrC,gCAAkB,KAAK,OAAO,KAAK,UAAU,MAAM;AAfvD;AAiBE;AACF,eAAK;AACH,qBAAS,MAAM,UAAU;AACzB,yBAAa;AACb;AACF,eAAK;AACH,qBAAS,MAAM,UAAU;AACzB,iBAAM,QAAQ,KAAM;AACpB,yBAAa;AACb;AACF,eAAK;AACH,qBAAS,MAAM,UAAU;AACzB,iBAAM,QAAQ,KAAM;AACpB,yBAAa;AACb;AACF,eAAK;AACH,iBAAK,MAAM;AACX,iBAAK,MAAM;AACX,mBAAO,GAAG;AACV,yBAAa;AACb;AACF,eAAK;AACH,iBAAK,MAAM;AACX,mBAAO,GAAG;AACV,yBAAa;AACb;AACF,eAAK;AACH,qBAAS,MAAM,UAAU;AACzB,yBAAa;AACb;AACF,eAAK;AACH,mBAAO,MAAM,SAAS,GAAG;AACvB,mBAAK,IAAI,MAAM;AAAS,mBAAK,IAAI,MAAM;AACvC,mBAAK,KAAK,MAAM;AAAS,mBAAK,KAAK,MAAM;AACzC,kBAAI,KAAK,MAAM;AAAS,kBAAI,KAAK,MAAM;AACvC,4BAAc,IAAI,IAAI,IAAI,IAAI,GAAG;AALrC;AAOE,iBAAK,MAAM;AACX,iBAAK,MAAM;AACX,mBAAO,GAAG;AACV;AACF,eAAK;AACH,mBAAO,MAAM,SAAS,GAAG;AACvB,mBAAK,MAAM;AACX,mBAAK,MAAM;AACX,qBAAO,GAAG;AAJd;AAME,iBAAK,IAAI,MAAM;AAAS,iBAAK,IAAI,MAAM;AACvC,iBAAK,KAAK,MAAM;AAAS,iBAAK,KAAK,MAAM;AACzC,gBAAI,KAAK,MAAM;AAAS,gBAAI,KAAK,MAAM;AACvC,0BAAc,IAAI,IAAI,IAAI,IAAI,GAAG;AACjC;AACF,eAAK;AACH,gBAAI,MAAM,SAAS,GAAG;AACpB,mBAAK,MAAM;AAFf;AAIE,mBAAO,MAAM,SAAS,GAAG;AACvB,mBAAK;AAAG,mBAAK,IAAI,MAAM;AACvB,mBAAK,KAAK,MAAM;AAAS,mBAAK,KAAK,MAAM;AACzC,kBAAI;AAAI,kBAAI,KAAK,MAAM;AACvB,4BAAc,IAAI,IAAI,IAAI,IAAI,GAAG;AARrC;AAUE;AACF,eAAK;AACH,gBAAI,MAAM,SAAS,GAAG;AACpB,mBAAK,MAAM;AAFf;AAIE,mBAAO,MAAM,SAAS,GAAG;AACvB,mBAAK,IAAI,MAAM;AAAS,mBAAK;AAC7B,mBAAK,KAAK,MAAM;AAAS,mBAAK,KAAK,MAAM;AACzC,kBAAI,KAAK,MAAM;AAAS,kBAAI;AAC5B,4BAAc,IAAI,IAAI,IAAI,IAAI,GAAG;AARrC;AAUE;AACF,eAAK;AACH,kBAAM,KAAM,CAAC,KAAK,MAAM,KAAO,KAAK,IAAI,MAAM,OAAQ;AACtD,iBAAK;AACL;AACF,eAAK;AACH,gBAAI,MAAM,QAAQ,KAAK;AACvB,uBAAW,KAAK,OAAO;AACvB,gBAAI,UAAU;AACZ,oBAAM;AAJV;AAME;AACF,eAAK;AACH,mBAAO,MAAM,SAAS,GAAG;AACvB,mBAAK;AAAG,mBAAK,IAAI,MAAM;AACvB,mBAAK,KAAK,MAAM;AAAS,mBAAK,KAAK,MAAM;AACzC,kBAAI,KAAK,MAAM;AACf,kBAAU,YAAM,WAAW,IAAI,MAAM,UAAU;AAC/C,4BAAc,IAAI,IAAI,IAAI,IAAI,GAAG;AACjC,kBAAI,MAAM,WAAW,GAAG;AACtB;AAPqB;AAUvB,mBAAK,IAAI,MAAM;AAAS,mBAAK;AAC7B,mBAAK,KAAK,MAAM;AAAS,mBAAK,KAAK,MAAM;AACzC,kBAAI,KAAK,MAAM;AACf,kBAAU,YAAM,WAAW,IAAI,MAAM,UAAU;AAC/C,4BAAc,IAAI,IAAI,IAAI,IAAI,GAAG;AAfrC;AAiBE;AACF,eAAK;AACH,mBAAO,MAAM,SAAS,GAAG;AACvB,mBAAK,IAAI,MAAM;AAAS,mBAAK;AAC7B,mBAAK,KAAK,MAAM;AAAS,mBAAK,KAAK,MAAM;AACzC,kBAAI,KAAK,MAAM;AACf,kBAAU,YAAM,WAAW,IAAI,MAAM,UAAU;AAC/C,4BAAc,IAAI,IAAI,IAAI,IAAI,GAAG;AACjC,kBAAI,MAAM,WAAW,GAAG;AACtB;AAPqB;AAUvB,mBAAK;AAAG,mBAAK,IAAI,MAAM;AACvB,mBAAK,KAAK,MAAM;AAAS,mBAAK,KAAK,MAAM;AACzC,kBAAI,KAAK,MAAM;AACf,kBAAU,YAAM,WAAW,IAAI,MAAM,UAAU;AAC/C,4BAAc,IAAI,IAAI,IAAI,IAAI,GAAG;AAfrC;AAiBE;AACF;AACE,gBAAI,IAAI,IAAI;AACV,oBAAuB,6CAAoB;AAF/C;AAIE,gBAAI,IAAI,KAAK;AACX,oBAAM,KAAK,IAAI;AADjB,uBAEW,IAAI,KAAK;AAClB,oBAAM,KAAM,KAAI,OAAO,MAAM,KAAK,OAAO;AADpC,uBAEI,IAAI,KAAK;AAClB,oBAAM,KAAO,MAAI,OAAO,MAAM,KAAK,OAAO;AADrC,mBAEA;AACL,oBAAM,KAAM,CAAC,KAAK,MAAM,KAAO,KAAK,IAAI,MAAM,KAClC,KAAK,IAAI,MAAM,IAAK,KAAK,IAAI,MAAM;AAC/C,mBAAK;AAbT;AAeE;;AAEJ,YAAI,YAAY;AACd,gBAAM,SAAS;AAlRK;AAFL;AAfsB;AAuS3C,UAAM;AAvjBuD;AA0jB/D,MAAI,OAAO;AAEX,WAAS,aAAa,YAAY;AAChC,SAAK,iBAAiB,OAAO,OAAO;AACpC,SAAK,4BAA4B,OAAO,OAAO;AAC/C,SAAK,aAAa;AA/jB2C;AAikB/D,eAAa;AACX,kCAAU,SAAS;AACjB,UAAI,OAAO,WAAW,KAAK,MAAM;AACjC,UAAI,KAAK,KAAK,eAAe,KAAK;AAClC,UAAI,CAAC,IAAI;AACP,aAAK,KAAK,aAAa,KAAK,OAAO,KAAK;AACxC,aAAK,eAAe,KAAK,WAAW;AALrB;AAOjB,UAAI,KAAK,0BAA0B,KAAK,cAAc,WAAW;AAC/D,aAAK,0BAA0B,KAAK,YAAY,KAAK;AARtC;AAUjB,aAAO;AAXc;AAcvB,wCAAa,MAAM;AACjB,UAAI,CAAC,QAAQ,KAAK,WAAW,KAAK,KAAK,OAAO,IAAI;AAChD,eAAO;AAFQ;AAKjB,UAAI,OAAO;AACX,WAAK,KAAK,EAAE,KAAK;AACjB,WAAK;AAAO,aAAK;AAAa,cAAM,KAAK,WAAW;AAA1C;AACV,WAAK;AAAO,aAAK;AAAS,cAAM,CAAC,QAAQ;AAA/B;AAEV,WAAK,iBAAiB,MAAM;AAE5B,WAAK,KAAK,EAAE,KAAK;AAEjB,aAAO;AA5Bc;AA+BvB,kDAAmB;AACjB,YAAM,IAAI,MAAM;AAhCK;AAmCvB,wCAAa,SAAS;AACpB,UAAI,OAAO,WAAW,KAAK,MAAM;AACjC,aAAQ,KAAK,eAAe,KAAK,aAAa,aACtC,KAAK,0BAA0B,KAAK,cAAc;AAtCrC;AAAA;AA0CzB,WAAS,iBAAiB,QAAQ,MAAM,YAAY;AAClD,iBAAa,cAAc,CAAC,UAAU,GAAG,GAAG,UAAU,GAAG;AACzD,iBAAa,KAAK,MAAM;AAExB,SAAK,SAAS;AACd,SAAK,OAAO;AAhnBiD;AAmnB/D,aAAK,QAAQ,kBAAkB;AAC7B,gDAAiB,MAAM,MAAM;AAC3B,kBAAY,MAAM,MAAM;AAFiB;AAAA;AAM7C,WAAS,cAAc,SAAS,MAAM,YAAY,cAAc;AAC9D,iBAAa,cAAc,CAAC,OAAO,GAAG,GAAG,OAAO,GAAG;AACnD,iBAAa,KAAK,MAAM;AAExB,SAAK,SAAS,QAAQ;AACtB,SAAK,SAAS,QAAQ,UAAU;AAChC,SAAK,QAAQ,QAAQ,SAAS;AAC9B,SAAK,OAAO;AACZ,SAAK,eAAe,gBAAgB;AAEpC,SAAK,aAAc,KAAK,OAAO,SAAS,OACrB,MAAO,KAAK,OAAO,SAAS,QAAQ,OAAO;AAC9D,SAAK,YAAa,KAAK,MAAM,SAAS,OACpB,MAAO,KAAK,MAAM,SAAS,QAAQ,OAAO;AAtoBC;AAyoB/D,aAAK,QAAQ,eAAe;AAC1B,gDAAiB,MAAM,MAAM;AAC3B,wBAAkB,MAAM,MAAM;AAFQ;AAAA;AAO1C;AACE,YAAQ,SAAS,2BAA2B,MAAM,qBAAqB;AACrE,UAAI,OAAO,IAAI,WAAW,KAAK;AAC/B,UAAI,MAAM,MAAM,MAAM,KAAK,kBAAkB;AAC7C,UAAI,YAAY,UAAU,MAAM;AAChC,WAAK,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,WAAW,KAAK,KAAK,IAAI;AACnD,YAAI,MAAM,yBAAc,KAAK,SAAS,GAAG,IAAI;AAC7C,YAAI,SAAS,QAAQ,MAAM,IAAI;AAC/B,YAAI,SAAS,QAAQ,MAAM,IAAI;AAC/B,gBAAQ;AACN,eAAK;AACH,mBAAO,UAAU,MAAM,QAAQ,SAAS;AACxC;AACF,eAAK;AACH,mBAAO,KAAK,SAAS,QAAQ,SAAS;AACtC;AACF,eAAK;AACH,mBAAO,KAAK,SAAS,QAAQ,SAAS;AACtC;AACF,eAAK;AACH,yBAAa,UAAU,MAAM,SAAS;AACtC,+BAAmB,UAAU,MAAM,SAAS;AAC5C;AACF,eAAK;AACH,kBAAM,SAAS,MAAM,QAAQ,SAAS,QAAQ;AAC9C;;AAxB+D;AA4BrE,UAAI,MAAM;AACR,YAAI,aAAc,CAAC,aAAa,KAAK,aACnB,CAAC,IAAI,YAAY,GAAG,GAAG,IAAI,YAAY,GAAG;AAC5D,eAAO,IAAI,iBACT,eAAe,MAAM,MAAM,mBAAmB,MAAM;AAhCa;AAkCrE,aAAO,IAAI,cAAc,KAAK,MAAM,KAAK,YAAY,KAAK;AAnCvD;AAAA;AAwCT,CAxrB2B;QAyrBzB,0C;;;;;;;;;;;;;;AC3rBK;;AAIA;;AACoD;;AAIpD;;AAIA;;AAGA;;AAC6B;;AACb;;AACK;;AAG5B,IAAI,2BAA2B;AAC/B,IAAI,yBAAyB;AAC7B,IAAI,sCAAsC;AAI1C,IAAI,wBAAwB;AAI5B,IAAI,wBAAwB;AAE5B,IAAI;AACF,cAAY;AACZ,SAAO;AACP,YAAU;AACV,UAAQ;AACR,eAAa;AACb,UAAQ;AACR,UAAQ;AACR,YAAU;AACV,aAAW;AATG;AAYhB,IAAI,2BAA2B,CAC7B,WAAW,SAAS,oBAAoB,SAAS,UAAU,YAC3D,cAAc,UAAU,WAAW,aAAa,eAAe,aAC/D,cAAc,YAAY,QAAQ,SAAS,UAAU,UAAU,SAC/D,QAAQ,OAAO,OAAO,SAAS,QAAQ,QAAQ,OAAO,SAAS,SAC/D,QAAQ,SAAS,aAAa,QAAQ,SAAS,WAAW,YAAY,MACtE,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KACtE,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,eACvD,aAAa,gBAAgB,eAAe,cAAc,SAAS,KAAK,KACxE,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KACtE,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,aAAa,OAAO,cACjE,cAAc,aAAa,SAAS,YAAY,UAAU,UAC1D,aAAa,aAAa,UAAU,UAAU,eAAe,aAC7D,UAAU,SAAS,YAAY,UAAU,UAAU,eAAe,aAClE,UAAU,UAAU,eAAe,aAAa,UAAU,UAAU,UACpE,eAAe,aAAa,UAAU,UAAU,UAAU,eAC1D,aAAa,UAAU,UAAU,QAAQ,YAAY,WAAW,UAChE,aAAa,cAAc,cAAc,aAAa,aAAa,SACnE,YAAY,YAAY,MAAM,UAAU,YAAY,aAAa,aACjE,gBAAgB,OAAO,MAAM,eAAe,aAAa,WAAW,MACpE,YAAY,eAAe,gBAAgB,SAAS,MAAM,UAC1D,gBAAgB,cAAc,cAAc,WAAW,UACvD,eAAe,SAAS,iBAAiB,kBAAkB,YAC3D,oBAAoB,UAAU,UAAU,UAAU,MAAM,MAAM,UAC9D,UAAU,gBAAgB,iBAAiB,aAAa,cACxD,UAAU,WAAW,aAAa,aAAa,YAAY,YAC3D,iBAAiB,kBAAkB,MAAM,MAAM,aAAa,kBAC5D,kBAAkB,gBAAgB,eAAe,eACjD,eAAe,UAAU,aAAa,UAAU,UAAU,eAC1D,aAAa,UAAU,UAAU,eAAe,SAAS,UAAU,UACnE,eAAe,UAAU,YAAY,cAAc,SAAS,UAC5D,SAAS,aAAa,QAAQ,WAAW,gBAAgB,UAAU,SACnE,UAAU,UAAU,UAAU,UAAU,UAAU,UAAU,aAC5D,OAAO,OAAO,UAAU,UAAU,SAAS,SAAS,SAAS,YAC7D,eAAe,eAAe,iBAAiB,WAAW,cAC1D,iBAAiB,SAAS,UAAU,UAAU,cAAc,YAC5D,YAAY,UAAU,UAAU,UAAU,UAAU;AAEtD,SAAS,aAAa,YAAY;AAChC,MAAI,CAAC,WAAW,YAAY;AAC1B;AAF8B;AAIhC,MAAI,WAAW,WAAW,OAAO,2BAAqB,IAAI;AACxD;AAL8B;AAQhC,MAAI,QAAQ,QAAQ,WAAW,WAAW;AAC1C,MAAI,eAAe,WAAW;AAC9B,WAAS,SAAS,cAAc;AAC9B,iBAAa,UAAU;AAXO;AAahC,aAAW,gBAAgB;AApH7B;AAuHA,SAAS,gBAAgB,YAAY,iBAAiB;AACpD,MAAI,WAAW,yBAAyB;AACtC;AAFkD;AAIpD,MAAI,WAAW,aAAa;AAC1B;AALkD;AAOpD,MAAI,oBAAoB,WAAW,iBAAiB;AAClD;AARkD;AAUpD,MAAI,WAAW,qBAAqB,sBAAsB;AACxD;AAXkD;AAapD,MAAI,YAAY;MAAI,mBAAmB;AACvC,WAAS,YAAY,iBAAiB;AACpC,QAAI,YAAY,gBAAgB;AAChC,QAAI,UAAU,iCAAmB,WAAW;AAC5C,QAAI,YAAY,CAAC,GAAG;AAClB,gBAAU,YAAY,OAAO,aAAa;AAJR;AAdc;AAqBpD,aAAW,UAAU,MAAM;AA5I7B;AA+IA,SAAS,YAAY,MAAM,SAAS;AAClC,UAAQ;AACN,SAAK;AACH,aAAO,YAAY,WAAW,eAAS,SAAS,eAAS;AAC3D,SAAK;AACH,aAAO,YAAY,kBAAkB,eAAS,gBAC5C,eAAS;AACb,SAAK;AACH,aAAO,eAAS;AAClB,SAAK;AACH,aAAO,eAAS;AAClB,SAAK;AACH,aAAO,eAAS;AAClB,SAAK;AACH,aAAO,eAAS;AAClB,SAAK;AACH,aAAO,eAAS;AAClB;AACE,aAAO,eAAS;;AAjKtB;AAuKA,SAAS,iBAAiB,MAAM,kBAAkB;AAChD,MAAI,iBAAiB,UAAU,WAAW;AACxC,WAAO;AAFuC;AAKhD,MAAI,UAAU,iCAAmB,MAAM;AACvC,MAAI,YAAY,CAAC,GAAG;AAClB,aAAS,OAAO,kBAAkB;AAChC,UAAI,iBAAiB,SAAS,SAAS;AACrC,eAAO;AAFuB;AADhB;AAN4B;AAahD,kBAAK,kDAAkD;AACvD,SAAO;AArLT;AAwLA,IAAI,iBAAkB,eAAe;AACnC,WAAS,MAAM,UAAU,SAAS,QAAQ,OAAO,SAAS,gBAC3C,SAAS,UAAU;AAChC,SAAK,WAAW;AAChB,SAAK,UAAU;AACf,SAAK,SAAS;AACd,SAAK,QAAQ;AACb,SAAK,UAAU;AACf,SAAK,iBAAiB;AACtB,SAAK,UAAU;AACf,SAAK,WAAW;AAViB;AAanC,QAAM,UAAU,kBAAkB,UAAS,UAAU,SAAS,QAAQ,OAC3B,SAAS,gBAAgB,SACzB,UAAU;AACnD,WAAO,KAAK,aAAa,YAClB,KAAK,YAAY,WACjB,KAAK,WAAW,UAChB,KAAK,UAAU,SACf,KAAK,YAAY,WACjB,KAAK,mBAAmB,kBACxB,KAAK,YAAY,WACjB,KAAK,aAAa;AAV3B;AAaA,SAAO;AA1BG,CAAC;AA6Bb,IAAI,wBAAyB,sBAAsB;AACjD,WAAS,aAAa,MAAM;AAG1B,SAAK,OAAO;AAJmC;AAOjD,eAAa;AACX,QAAI,SAAS;AACX,aAAO,KAAK,KAAK;AAFI;AAKvB,8BAAQ,UAAU;AAChB,eAAS,YAAY,KAAK,MAAM;AAC9B,iBAAS,UAAU,KAAK,KAAK,UAAU,WAAW;AAFpC;AALK;AAWvB,sBAAI,GAAG;AACL,aAAO,KAAK,KAAK,OAAO;AAZH;AAevB,sBAAI,GAAG;AACL,aAAO,KAAK,KAAK;AAhBI;AAmBvB,oCAAW,OAAO;AAGhB,UAAI,MAAM,KAAK;AACf,UAAI,IAAI,UAAU,SAAS;AACzB,eAAO,IAAI,QAAQ;AALL;AAOhB,eAAS,YAAY,KAAK;AACxB,YAAI,IAAI,cAAc,OAAO;AAC3B,iBAAQ,WAAW;AAFG;AAPV;AAYhB,aAAO,CAAC;AA/Ba;AAkCvB,0BAAM,KAAK;AACT,eAAS,YAAY,KAAK;AACxB,aAAK,KAAK,YAAY,IAAI;AAFnB;AAlCY;AAAA;AAyCzB,SAAO;AAhDU,CAAC;AAmDpB,IAAI,gCAAiC,8BAA8B;AACjE,WAAS,qBAAqB,WAAW,UAAU;AACjD,SAAK,YAAY;AACjB,SAAK,WAAW;AAH+C;AAMjE,uBAAqB;AACnB,QAAI,SAAS;AACX,aAAQ,KAAK,WAAW,IAAK,KAAK;AAFL;AAK/B,8BAAQ,UAAU;AAChB,WAAK,IAAI,IAAI,KAAK,WAAW,KAAK,KAAK,UAAU,KAAK,IAAI,KAAK;AAC7D,iBAAS,GAAG;AAFE;AALa;AAW/B,sBAAI,GAAG;AACL,aAAO,KAAK,aAAa,KAAK,KAAK,KAAK;AAZX;AAe/B,sBAAI,GAAG;AACL,UAAI,KAAK,aAAa,KAAK,KAAK,KAAK,UAAU;AAC7C,eAAO,OAAO,aAAa;AAFxB;AAIL,aAAO;AAnBsB;AAsB/B,oCAAW,GAAG;AACZ,aAAQ,iBAAM,MAAM,KAAK,KAAK,aAAa,KAAK,KAAK,WAAY,IAAI,CAAC;AAvBzC;AA0B/B,0BAAM,KAAK;AACT,YAAM,IAAI,MAAM;AA3Ba;AAAA;AA+BjC,SAAO;AArCkB,CAAC;AAwC5B,IAAI,+BAAgC,6BAA6B;AAC/D,WAAS,WAAW,MAAM,QAAQ,KAAK;AACrC,SAAK,UAAW,OAAO,IAAK;AAC5B,SAAK,SAAS,KAAK,MAAM;AAHoC;AAM/D,WAAS,WAAW,MAAM,QAAQ,KAAK;AACrC,SAAK,UAAW,OAAO,KAAM;AAC7B,SAAK,SAAS,KAAM,OAAO,KAAM;AACjC,SAAK,SAAS,KAAM,OAAO,IAAK;AAChC,SAAK,SAAS,KAAK,MAAM;AAVoC;AAa/D,WAAS,UAAU,MAAM,QAAQ,MAAM;AACrC,QAAI,GAAG;AACP,QAAI,gBAAgB,YAAY;AAC9B,WAAK,IAAI,MAAM;AADjB,eAEW,OAAO,SAAS,UAAU;AACnC,WAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,IAAI,IAAI,KAAK;AACzC,aAAK,YAAY,KAAK,WAAW,KAAK;AAFL;AAA9B,WAIA;AAEL,WAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,IAAI,IAAI,KAAK;AACzC,aAAK,YAAY,KAAK,KAAK;AAHxB;AAR8B;AAbwB;AA6B/D,WAAS,oBAAoB,MAAM;AACjC,SAAK,OAAO;AACZ,SAAK,SAAS,OAAO,OAAO;AA/BiC;AAkC/D,sBAAoB,kBAChB,SAAS,oCAAoC,cAAc,WAAW;AACxE,QAAI,YAAY;QAAG,OAAO;AAC1B,WAAQ,aAAY,gBAAgB,WAAW;AAC7C,oBAAc;AACd;AAJsE;AAMxE,QAAI,cAAc,YAAY;AAC9B;AACE,aAAO;AACP,aAAO;AACP,kBAAY,YAAY,eAAe;AAHlC;AART;AAeA,MAAI,kBAAkB;AACtB,MAAI,uBAAuB;AAE3B,sBAAoB;AAClB,aAAS,SAAS,8BAA8B;AAC9C,UAAI,OAAO,KAAK;AAGhB,UAAI,SAAS,KAAK;AAClB,UAAI,cAAc,OAAO,KAAK;AAC9B,kBAAY;AACZ,UAAI,YAAY,YAAY;AAE5B,UAAI,GAAG,GAAG,IAAI,OAAO;AAErB,UAAI,SAAS,kBAAkB,YAAY;AAC3C,UAAI,eAAe,CAAC;AACpB,WAAK,IAAI,GAAG,IAAI,WAAW,KAAK;AAC9B,gBAAQ,OAAO,YAAY;AAC3B,YAAI,eAAgB,CAAC,MAAM,SAAS,IAAK,CAAC,OAAO;AACjD,kBAAU;AACV,qBAAa,KAAK;AAjB0B;AAoB9C,UAAI,OAAO,IAAI,WAAW;AAE1B,WAAK,IAAI,GAAG,IAAI,WAAW,KAAK;AAC9B,gBAAQ,OAAO,YAAY;AAC3B,kBAAU,MAAM,aAAa,IAAI;AAxBW;AA4B9C,UAAI,SAAS,QAAQ;AAEnB,eAAO,oBAAS;AA9B4B;AAgC9C,WAAK,KAAK,KAAK,WAAW,KAAK;AAC/B,WAAK,KAAK,KAAK,WAAW,KAAK;AAC/B,WAAK,KAAK,KAAK,WAAW,KAAK;AAC/B,WAAK,KAAK,KAAK,WAAW,KAAK;AAG/B,iBAAW,MAAM,GAAG;AAEpB,UAAI,eAAe,oBAAoB,gBAAgB,WAAW;AAGlE,iBAAW,MAAM,GAAG,aAAa;AAEjC,iBAAW,MAAM,GAAG,aAAa;AAEjC,iBAAW,MAAM,IAAI,aAAa;AAElC,eAAS;AAET,WAAK,IAAI,GAAG,IAAI,WAAW,KAAK;AAC9B,oBAAY,YAAY;AACxB,aAAK,UAAU,UAAU,WAAW,KAAK;AACzC,aAAK,SAAS,KAAK,UAAU,WAAW,KAAK;AAC7C,aAAK,SAAS,KAAK,UAAU,WAAW,KAAK;AAC7C,aAAK,SAAS,KAAK,UAAU,WAAW,KAAK;AAG7C,YAAI,WAAW;AACf,aAAK,IAAI,aAAa,IAAI,KAAK,aAAa,IAAI,IAAI,IAAI,IAAI,KAAK,GAAG;AAClE,cAAI,OAAO,sBAAW,MAAM;AAC5B,qBAAY,WAAW,SAAU;AAXL;AAa9B,mBAAW,MAAM,SAAS,GAAG;AAG7B,mBAAW,MAAM,SAAS,GAAG,aAAa;AAE1C,mBAAW,MAAM,SAAS,IAAI,OAAO,WAAW;AAEhD,kBAAU;AAvEkC;AAyE9C,aAAO;AA1EqB;AA6E9B,cAAU,SAAS,6BAA6B,KAAK,MAAM;AACzD,UAAI,OAAO,KAAK,QAAQ;AACtB,cAAM,IAAI,MAAM,WAAW,MAAM;AAFsB;AAIzD,WAAK,OAAO,OAAO;AAjFS;AAAA;AAqFhC,SAAO;AAzIiB,CAAC;AAiJ3B,IAAI,wBAAwB,IAAI,WAAW,CAEzC,QAAQ,QACR,QAAQ,QACR,QAAQ,QAER,QAAQ,QACR,QAAQ,QACR,QAAQ,QACR,QAAQ,QAER,QAAQ,QACR,QAAQ,QACR,QAAQ,QACR,QAAQ,QACR,QAAQ,QACR,QAAQ,QACR,QAAQ,QAER,QAAQ,QAER,QAAQ;AAWV,IAAI,gBAAiB,cAAc;AACjC,WAAS,KAAK,MAAM,MAAM,YAAY;AACpC,QAAI;AAEJ,SAAK,OAAO;AACZ,SAAK,aAAa,WAAW;AAC7B,SAAK,cAAc,WAAW;AAC9B,SAAK,QAAQ;AACb,SAAK,cAAc;AAEnB,SAAK,aAAa,OAAO,OAAO;AAEhC,SAAK,cAAc,CAAG,aAAW,QAAQ,UAAU;AACnD,SAAK,iBAAiB,CAAG,aAAW,QAAQ,UAAU;AACtD,SAAK,cAAc,CAAG,aAAW,QAAQ,UAAU;AAEnD,QAAI,OAAO,WAAW;AACtB,QAAI,UAAU,WAAW;AACzB,SAAK,OAAO;AACZ,SAAK,UAAU;AAEf,SAAK,eAAgB,KAAK,cAAc,cAClB,KAAK,cAAc,UAAU;AAEnD,SAAK,cAAc,WAAW;AAC9B,SAAK,SAAS,WAAW;AACzB,SAAK,eAAe,WAAW;AAC/B,SAAK,YAAY,WAAW;AAC5B,SAAK,YAAY,WAAW;AAC5B,SAAK,OAAO,WAAW;AACvB,SAAK,SAAS,WAAW,SAAS;AAClC,SAAK,UAAU,WAAW,UAAU;AACpC,SAAK,aAAa,WAAW;AAC7B,SAAK,OAAO,WAAW;AACvB,SAAK,kBAAkB,WAAW;AAElC,SAAK,YAAY,WAAW;AAE5B,SAAK,aAAa;AAElB,QAAI,WAAW,SAAS,SAAS;AAC/B,WAAK,WAAW,GAAG,WAAW,KAAK,YAAY;AAC7C,aAAK,WAAW,YAAa,KAAK,YAAY,aACjB,WAAW,gBAAgB;AAH3B;AAK/B,WAAK,WAAW,eAAS;AACzB;AA7CkC;AAgDpC,SAAK,cAAc,WAAW;AAC9B,SAAK,WAAW,WAAW;AAC3B,QAAI,KAAK,UAAU;AACjB,WAAK,WAAW,WAAW;AAC3B,WAAK,kBAAkB,WAAW;AApDA;AAuDpC,QAAI,CAAC,QAAQ,KAAK,SAAS;AACzB,UAAI,MAAM;AAGR,wBAAK,4BAA4B,OAAO,QAAQ,KAAK,aAAa;AAJ3C;AAMzB,WAAK;AACL;AA9DkC;AAkEpC,QAAI,YAAY,UAAU;AACxB,UAAI,SAAS,WAAW,SAAS,WAAW;AAE1C,YAAI,eAAe,OAAO;AACxB,oBAAU;AADZ,eAEO;AACL,iBAAO;AALiC;AAA5C,aAOO,IAAI,eAAe,OAAO;AAE/B,kBAAU;AAVY;AAlEU;AA+EpC,QAAI,YAAY,mBAAmB,SAAS,gBAAgB;AAC1D,aAAO;AAhF2B;AAmFpC,QAAI,SAAS,gBAAgB;AAC3B,UAAI,YAAY,OAAO;AACrB,kBAAU;AADZ,iBAEW,eAAe,OAAO;AAE/B,kBAAU;AAFL,aAGA;AACL,kBAAU;AAPe;AAnFO;AA6FpC,QAAI,YAAY,cAAc,SAAS,YAAY;AACjD,aAAO;AA9F2B;AAiGpC,QAAI;AACF,UAAI;AACJ,cAAQ;AACN,aAAK;AACH,0BAAK,mBAAmB,OAAO;AAEjC,aAAK;AACL,aAAK;AACH,eAAK,WAAW;AAEhB,cAAI,MAAO,YAAY,YAAY,YAAY,kBAC7C,IAAI,QAAQ,MAAM,cAClB,IAAI,UAAU,MAAM,MAAM;AAE5B,uBAAa;AAGb,iBAAO,KAAK,QAAQ,MAAM,KAAK;AAC/B;AAEF,aAAK;AACL,aAAK;AACL,aAAK;AACH,eAAK,WAAW;AAIhB,iBAAO,KAAK,eAAe,MAAM,MAAM;AACvC,cAAI,KAAK,YAAY;AACnB,yBAAa;AAEb,mBAAO;AATX;AAWE;AAEF;AACE,gBAAuB,gCAAY;;AApCzC,MAsCE,OAAO,GAAG;AACV,UAAM,EAAa,iCAAc;AAC/B,cAAM;AAFE;AAIV,sBAAK;AACL,WAAK;AACL;AA7IkC;AAgJpC,SAAK,OAAO;AACZ,SAAK,WAAW,YAAY,MAAM;AAGlC,SAAK,aAAa,WAAW;AAC7B,SAAK,SAAS,WAAW;AACzB,SAAK,eAAe,WAAW;AAC/B,SAAK,YAAY,WAAW;AAC5B,SAAK,WAAW,WAAW;AAC3B,SAAK,UAAU,WAAW;AAE1B,SAAK,UAAU;AA5JgB;AA+JjC,OAAK,wBAAyB;AAC5B,QAAI,KAAK;AACT,WAAO,SAAS,iBAAiB;AAC/B,aAAO,OAAO;AADhB;AAFe,GAAC;AAOlB,WAAS,MAAM,IAAI,IAAI;AACrB,WAAQ,OAAM,KAAK;AAvKY;AA0KjC,WAAS,YAAY,IAAI,IAAI;AAC3B,QAAI,QAAS,OAAM,KAAK;AACxB,WAAO,QAAS,KAAK,KAAM,QAAQ,UAAU;AA5Kd;AA+KjC,WAAS,MAAM,IAAI,IAAI,IAAI,IAAI;AAC7B,WAAQ,OAAa,aAAa,aAAM,KAAK;AAhLd;AAmLjC,WAAS,SAAS,OAAO;AACvB,WAAO,OAAO,aAAc,SAAS,IAAK,MAAM,QAAQ;AApLzB;AAuLjC,WAAS,aAAa,OAAO;AAE3B,YAAS,QAAQ,SAAS,SAAU,QAAQ,CAAC,SAAS,CAAC,SAAS;AAChE,WAAO,OAAO,aAAc,SAAS,IAAK,MAAM,QAAQ;AA1LzB;AA6LjC,WAAS,eAAe,MAAM;AAC5B,QAAI,SAAS,KAAK,UAAU;AAC5B,WAAO,sBAAW,QAAQ,OAAO;AA/LF;AAkMjC,WAAS,eAAe,MAAM;AAC5B,QAAI,SAAS,KAAK,UAAU;AAC5B,WAAO,yBAAc,YAAY;AApMF;AAuMjC,WAAS,YAAY,MAAM;AACzB,QAAI,SAAS,KAAK,UAAU;AAE5B,QAAI,OAAO,OAAO,QAAQ,OAAO,OAAO,MAAM;AAC5C,aAAO;AAJgB;AAQzB,QAAI,OAAO,OAAO,QAAQ,OAAO,OAAO,MAAM;AAC5C,aAAO;AATgB;AAWzB,WAAO;AAlNwB;AAqNjC,WAAS,gBAAgB,UAAU,kBAAkB,aAAa;AAChE,QAAI,aAAa;QAAI;AACrB,SAAK,IAAI,IAAI,GAAG,KAAK,SAAS,QAAQ,IAAI,IAAI,KAAK;AACjD,gBAAU,iCAAmB,SAAS,IAAI;AAC1C,UAAI,YAAY,CAAC,GAAG;AAClB,mBAAW,KAAK;AAH+B;AAFa;AAQhE,aAAS,YAAY,aAAa;AAChC,gBAAU,iCAAmB,YAAY,WAAW;AACpD,UAAI,YAAY,CAAC,GAAG;AAClB,mBAAW,CAAC,YAAY;AAHM;AAR8B;AAchE,WAAO;AAnOwB;AA0OjC,WAAS,6BAA6B,MAAM;AAE1C,QAAI,IAAI;QAAG,IAAI,sBAAsB,SAAS;AAC9C,WAAO,IAAI,GAAG;AACZ,UAAI,IAAK,IAAI,IAAI,KAAM;AACvB,UAAI,OAAO,sBAAsB,IAAI;AACnC,YAAI,IAAI;AADV,aAEO;AACL,YAAI;AALM;AAH4B;AAY1C,WAAS,MAAI;AAtPkB;AAmQjC,WAAS,cAAc,mBAAmB,YAAY,eAAe;AACnE,QAAI,YAAY,WAAW;AAC3B,QAAI,aAAa,CAAG,aAAW,QAAQ,UAAU;AACjD,QAAI,oBACF,WAAW,qBAAqB;AAClC,QAAI,SAAS,OAAO,OAAO;AAC3B,QAAI,aAAa;AACjB,QAAI,oBAAoB;AACxB,QAAI,4BAA4B;AAChC,aAAS,oBAAoB,mBAAmB;AAC9C,0BAAoB;AACpB,UAAI,UAAU,kBAAkB;AAGhC,UAAI,cAAc,UAAU;AAC1B;AAN4C;AAQ9C,UAAI,eAAe;AAGnB,UAAI,kBAAkB;AACtB,UAAI,CAAC,qBAAqB,UAAU,IAAI,mBAAmB;AACzD,0BAAkB;AAClB,YAAI,UAAU,UAAU,IAAI;AAE5B,YAAI,QAAQ,WAAW,GAAG;AACxB,yBAAe,QAAQ,WAAW;AALqB;AAZb;AA0B9C,UAAK,kBAAkB,kBAAkB,aACpC,6BAA6B,iBAC5B,cAAc,CAAC,iBAAmB;AAEtC,WAAG;AACD,cAAI,4BAA4B,wBAAwB;AACtD,4BAAK;AACL;AAHD;AAKD,yBAAe;AAEf,cAAI,uCAAuC,iBAAiB,QAAQ;AAClE,2BAAe;AACf,wCAA4B,eAAe;AAT5C;AAAH,iBAYS,kBAAkB,kBAAkB;AA1CD;AA6C9C,aAAO,gBAAgB;AACvB,iBAAW,oBAAoB;AAC/B,wBAAkB,gBAAgB;AAxD+B;AA0DnE;AACE;AACA,yBAAmB;AACnB;AAHK;AA7TwB;AAoUjC,WAAS,UAAU,QAAQ,WAAW;AAGpC,QAAI,QAAQ;AACZ,aAAS,YAAY,QAAQ;AAE3B,UAAI,OAAO,aAAa,WAAW;AACjC;AAHyB;AAK3B,YAAM;AAAO,sBAAc,WAAW;AAAG,iBAAS,OAAO;AAA9C;AATuB;AAapC,QAAI,MAAM,WAAW,GAAG;AACtB,YAAM;AAAO,sBAAc;AAAG,iBAAS;AAA5B;AAduB;AAgBpC,UAAM,KAAK,SAAS,kBAAkB,GAAG,GAAG;AAC1C,aAAO,EAAE,eAAe,EAAE;AAD5B;AAKA,QAAI,SAAS;AACb,QAAI,SAAS,MAAM;AACnB,SAAK,IAAI,IAAI,GAAG,IAAI,SAAU;AAC5B,UAAI,QAAQ,MAAM,GAAG;AACrB,UAAI,cAAc,CAAC,MAAM,GAAG;AAC5B,QAAE;AACF,UAAI,MAAM;AACV,aAAO,IAAI,UAAU,MAAM,MAAM,MAAM,GAAG,cAAc;AACtD,oBAAY,KAAK,MAAM,GAAG;AAC1B,UAAE;AACF,UAAE;AACF,YAAI,QAAQ,QAAQ;AAClB;AALoD;AAL5B;AAa5B,aAAO,KAAK,CAAC,OAAO,KAAK;AApCS;AAuCpC,WAAO;AA3WwB;AA8WjC,WAAS,gBAAgB,QAAQ,WAAW;AAC1C,QAAI,SAAS,UAAU,QAAQ;AAC/B,QAAI,YAAY,OAAO,OAAO,SAAS,GAAG,KAAK,SAAS,IAAI;AAC5D,QAAI,OAAO,aACA,SAAS,aACT,aACA,aACA,oBAAS,IAAI,YAAY;AAEpC,QAAI,GAAG,IAAI,GAAG;AACd,SAAK,IAAI,OAAO,SAAS,GAAG,KAAK,GAAG,EAAE,GAAG;AACvC,UAAI,OAAO,GAAG,MAAM,QAAQ;AAC1B;AAFqC;AAVC;AAe1C,QAAI,YAAY,IAAI;AAEpB,QAAI,OAAO,GAAG,KAAK,UAAU,OAAO,GAAG,OAAO,QAAQ;AACpD,aAAO,GAAG,KAAK;AAlByB;AAoB1C,QAAI,sBAAsB,OAAO,GAAG,KAAK,SAAS,IAAI;AACtD,QAAI,WAAW,YAAY;AAC3B,QAAI,eAAe,oBAAoB,gBAAgB,UAAU;AAGjE,QAAI,aAAa;AACjB,QAAI,WAAW;AACf,QAAI,WAAW;AACf,QAAI,iBAAiB;AACrB,QAAI,YAAY;AAChB,QAAI,OAAO;AAEX,QAAI,OAAO,OAAO,KAAK;AACvB,SAAK,IAAI,GAAG,KAAK,WAAW,IAAI,IAAI,KAAK;AACvC,cAAQ,OAAO;AACf,cAAQ,MAAM;AACd,YAAM,MAAM;AACZ,oBAAc,SAAS;AACvB,kBAAY,SAAS;AACrB,cAAQ,MAAM;AACd,UAAI,aAAa;AACjB,WAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,IAAI,IAAI,EAAE,GAAG;AAC1C,YAAI,MAAM,OAAO,MAAM,IAAI,KAAK,GAAG;AACjC,uBAAa;AACb;AAHwC;AARL;AAcvC,UAAI,CAAC,YAAY;AACf,YAAI,SAAU,YAAW,KAAK,IAAI,OAAO;AACzC,gBAAS,MAAM,QAAQ;AAEvB,oBAAY,SAAS;AACrB,0BAAkB,SAAS;AAE3B,aAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,IAAI,IAAI,EAAE,GAAG;AAC1C,uBAAa,SAAS,MAAM;AARf;AAAjB,aAUO;AACL,YAAI,YAAY,MAAM;AAEtB,oBAAY,SAAU,YAAY,QAAS;AAC3C,0BAAkB,SAAS;AA5BU;AAjCC;AAiE1C,QAAI,sBAAsB,GAAG;AAC3B,kBAAY;AACZ,oBAAc;AACd,kBAAY;AACZ,wBAAkB;AArEsB;AAwE1C,QAAI,YAAY,aACA,SAAS,IAAI,YACb,SAAS,aAAa,SACtB,SAAS,aAAa,SACtB,SAAS,aAAa,cACtB,WAAW,aAAa,aACxB,WAAW,iBAAiB;AAE5C,QAAI,cAAc;AAClB,QAAI,cAAc;AAClB,QAAI,YAAY,GAAG;AACjB,cAAQ,aACA,aACA,oBAAS,IAAI,YAAY,IAChB,IAAI,UAAU;AAC/B,oBAAc;AACd,WAAK,IAAI,GAAG,KAAK,OAAO,QAAQ,IAAI,IAAI,KAAK;AAC3C,gBAAQ,OAAO;AACf,gBAAQ,MAAM;AACd,gBAAQ,MAAM;AACd,YAAI,OAAO,MAAM;AACjB,aAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,IAAI,IAAI,EAAE,GAAG;AAC1C,cAAI,MAAM,OAAO,MAAM,IAAI,KAAK,GAAG;AACjC,kBAAM,MAAM,KAAK,IAAI;AACrB,2BAAe,oBAAS,SACT,oBAAS,OACT,oBAAS;AACxB,oBAAQ,MAAM;AACd,mBAAO,MAAM;AAP2B;AALD;AAe3C,uBAAe,oBAAS,SACT,oBAAS,MAAM,MACf,oBAAS;AAvBT;AAyBjB,oBAAc,aACA,aACA,oBAAS,YAAY,SAAS,MAC9B,qBACA,oBAAS,YAAY,SAAS;AA/GJ;AAkH1C,WAAO,OAAO,aACA,SAAS,UAAU,SAAS,KAC5B,YAAY,cAAc;AAleT;AAqejC,WAAS,iBAAiB,KAAK;AAC7B,QAAI,SAAa,mBAAO,IAAI;AAC5B,QAAI,UAAU,OAAO;AAGrB,WAAO,SAAS;AAChB,QAAI,YAAY,OAAO;AACvB,QAAI,UAAU,KAAM,YAAY,QAAS;AACvC,aAAO;AARoB;AAU7B,QAAI,YAAY,OAAO;AACvB,QAAI,WAAW,OAAO;AACtB,QAAI,YAAY,UAAU;AACxB,aAAO;AAboB;AAe7B,WAAO,SAAS;AAChB,QAAI,cAAc,OAAO;AACzB,QAAI,gBAAgB,GAAG;AACrB,aAAO;AAlBoB;AAsB7B,QAAI,KAAK,KAAK,IAAI,KAAK,KAAK;AAC5B,WAAO;AA5fwB;AA+fjC,WAAS,eAAe,YAAY,aAAa,UAAU;AACzD,eAAW;AACT,kBAAY;AACZ,YAAM;AACN,YAAM;AACN,cAAQ;AACR,eAAS;AALY;AAQvB,QAAI,kBAAkB;AACtB,QAAI,kBAAkB;AACtB,QAAI,kBAAkB;AACtB,QAAI,kBAAkB;AAEtB,QAAI,iBAAiB;AACrB,QAAI,gBAAgB;AAEpB,QAAI,aAAa;AACf,eAAS,QAAQ,aAAa;AAC5B,gBAAQ;AACR,YAAI,iBAAiB,QAAQ,CAAC,gBAAgB;AAC5C,2BAAiB;AAHS;AAK5B,YAAI,gBAAgB,MAAM;AACxB,0BAAgB;AANU;AAS5B,YAAI,WAAW,iCAAmB;AAClC,YAAI,WAAW,IAAI;AACjB,6BAAmB,KAAK;AAD1B,mBAEW,WAAW,IAAI;AACxB,6BAAmB,KAAK,WAAW;AAD9B,mBAEI,WAAW,IAAI;AACxB,6BAAmB,KAAK,WAAW;AAD9B,mBAEI,WAAW,KAAK;AACzB,6BAAmB,KAAK,WAAW;AAD9B,eAEA;AACL,gBAAU,sBACR;AApBwB;AADf;AAAjB,WAwBO;AAEL,uBAAiB;AACjB,sBAAgB;AA5CuC;AA+CzD,QAAI,OAAO,WAAW,QAAQ,CAAC,GAAG,GAAG,GAAG;AACxC,QAAI,aAAc,SAAS,cACT,IAAK,YAAyB,0CAAsB;AAItE,QAAI,QAAS,WAAW,eAAe,MAC1B,aAAa;AAE1B,QAAI,aAAc,SAAS,UACT,KAAK,MAAe,oBAAW,UAAU,KAAK;AAChE,QAAI,cAAe,SAAS,WACT,KAAK,MAAe,oBAAW,WAAW,KAAK;AAClE,QAAI,cAAc,KAAK,WAAW,UAAU,KAAK,KAAK,KAAK,GAAG;AAC5D,oBAAc,CAAC;AA7DwC;AA+DzD,QAAI,YAAY,SAAS,QAAQ;AACjC,QAAI,aAAa,CAAC,SAAS,QAAQ,CAAC;AAEpC,WAAO,aACA,aACA,aACA,aACA,aACA,aACA,aACA,aACA,aACA,aACA,aACA,aACA,aACA,aACA,aACA,aACA,iBACA,OAAO,aAAa,WAAW,aAAa,OAAO,QACnD,6BACA,oBAAS,mBACT,oBAAS,mBACT,oBAAS,mBACT,oBAAS,mBACT,qBACA,SAAS,WAAW,cAAc,IAAI,KACtC,SAAS,kBACA,WAAW,aACpB,SAAS,iBAAiB,WAAW,YACrC,SAAS,cACT,SAAS,eACT,aACA,SAAS,aACT,SAAS,cACT,qBACA,qBACA,SAAS,WAAW,WACpB,SAAS,WAAW,aACpB,SAAS,KACT,SAAS,kBAAkB,WAAW,aACtC;AAxmBwB;AA2mBjC,WAAS,gBAAgB,YAAY;AACnC,QAAI,QAAQ,KAAK,MAAM,WAAW,cAAe,KAAK,IAAI,GAAG;AAC7D,WAAQ,qBACA,oBAAS,SACT,aACA,aACA,oBAAS,WAAW,cACpB,qBACA,qBACA,qBACA;AArnBuB;AAwnBjC,WAAS,gBAAgB,MAAM,OAAO;AACpC,QAAI,CAAC,OAAO;AACV,cAAQ,CAAC,IAAI;AAFqB;AAKpC,QAAI,UAAU,CACZ,MAAM,GAAG,MAAM,oBACf,MAAM,GAAG,MAAM,MACf,MAAM,GAAG,MAAM,WACf,MAAM,GAAG,MAAM,YACf,MAAM,GAAG,MAAM,MACf,MAAM,GAAG,MAAM,gBACf,MAAM,GAAG,MAAM,IACf,MAAM,GAAG,MAAM,WACf,MAAM,GAAG,MAAM,WACf,MAAM,GAAG,MAAM;AAKjB,QAAI,iBAAiB;AACrB,QAAI,GAAG,IAAI,GAAG,IAAI;AAClB,SAAK,IAAI,GAAG,KAAK,QAAQ,QAAQ,IAAI,IAAI,KAAK;AAC5C,YAAM,MAAM,GAAG,MAAM,QAAQ;AAE7B,UAAI,gBAAgB;AACpB,WAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,IAAI,IAAI,KAAK;AACxC,sBAAc,KAAK,SAAS,IAAI,WAAW;AALD;AAO5C,qBAAe,KAAK,cAAc,KAAK;AA7BL;AAgCpC,QAAI,QAAQ,CAAC,SAAS;AACtB,QAAI,YAAY,CAAC,YAAY;AAC7B,QAAI,YAAY,CAAC,YAAY;AAC7B,QAAI,YAAY,CAAC,YAAY;AAE7B,QAAI,mBAAmB,QAAQ,SAAS,UAAU;AAClD,QAAI,YACF,aACA,SAAS,oBACT,SAAS,mBAAmB,KAAK;AAGnC,QAAI,YAAY;AAChB,SAAK,IAAI,GAAG,KAAK,UAAU,QAAQ,IAAI,IAAI,KAAK;AAC9C,UAAI,OAAO,MAAM;AACjB,WAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,IAAI,IAAI,KAAK;AACzC,cAAM,KAAK;AACX,YAAI,aACF,UAAU,KACV,UAAU,KACV,UAAU,KACV,SAAS,KACT,SAAS,IAAI,UACb,SAAS;AACX,qBAAa;AACb,qBAAa,IAAI;AAZ2B;AA7CZ;AA6DpC,iBAAa,QAAQ,KAAK,MAAM,eAAe,KAAK;AACpD,WAAO;AAtrBwB;AAyrBjC,OAAK;AACH,UAAM;AACN,UAAM;AACN,cAAU;AACV,cAAU;AACV,QAAI,WAAW;AACb,UAAI,WAAW,mCAAoB,OAAO,MAAM;AAChD,aAAO,kBAAO,MAAM,YAAY;AAPnB;AAUf,gBAAY,SAAS,kBAAkB;AAErC,UAAI,OAAO;AACX,eAAS,KAAK,MAAM;AAClB,YAAI,KAAK,eAAe,IAAI;AAC1B,eAAK,KAAK,KAAK;AAFC;AAHiB;AAQrC,aAAO;AAlBM;AAqBf,0BAAsB,SAAS;AAA4B;;AACzD,WAAK,cAAc;AACnB,UAAI,UAAU;AAGd,UAAI,OAAO,KAAK;AAChB,UAAI,OAAO,KAAK;AAChB,UAAI,UAAU,KAAK;AACnB,UAAI,WAAW,KAAK,QAAQ,SAAS;AACrC,UAAI,aAAa;UAAiB,gBAAgB;AAClD,UAAI,iBAAiB,CAAC,CAAC,WAAW,aAChC,CAAG,gBAAc,aAAa,WAAW,cAAc;AACzD,iBAAW,WAAW,aAAa,cAAc,aAAa;AAE9D,WAAK,OAAQ,SAAS,OAAO,cAAc,CAAC;AAC5C,WAAK,SAAW,SAAS,OAAO,iBAAiB,CAAC,KAClC,SAAS,OAAO,gBAAgB,CAAC;AAIjD,WAAK,QAAS,KAAK,OAAO,cAAc,CAAC;AAGzC,WAAK,YAAY,OAAO,KAAK,KAAK,QAAQ,SAAS;AACnD,UAAI,kBAAkB,SAAS,kBAC3B,KAAK,YAAY,QAAQ,iBAAiB,GAAG;AAC/C,YAAI,2BAA2B;AAG/B,YAAI,MAAM;AACV,aAAK,YAAY,0BAA0B;AACzC,cAAI,CAAC,YAAY,yBAAyB;AANG;AAQ/C,YAAI,gBAAgB,KAAK,OAAO;AAC9B,cAAI,oCACF;AACF,eAAK,YAAY,mCAAmC;AAClD,gBAAI,CAAC,YAAY,kCAAkC;AAJvB;AARe;AAe/C,YAAI,oBAAoB,KAAK,qBAAqB;AAClD,YAAI,CAAC,mBAAmB;AACtB,eAAK,UAAU,QAAQ,UAAS,UAAU,iBAAiB;AACzD,gBAAI,CAAC,YAAY;AADnB;AAjB6C;AAqB/C,aAAK,aAAa;AAClB,aAAK,YAAY,IAAI,aAAa;AAvBpC,iBAwBW,UAAU,KAAK,WAAW;AACnC,aAAK,aAA6B,8CAAmB,oCACnB,KAAK;AAFlC,iBAGI,YAAY,KAAK,WAAW;AACrC,YAAI,aAAa,KAAK,OAAO;AAC3B,0BAAK;AAF8B;AAIrC,aAAK,aAA6B,iDACA,4CACA,KAAK;AANlC,iBAOI,gBAAgB;AACzB,aAAK,aAAa,gBAAgB,KAAK,iBACL,oCACA,KAAK;AAHlC,aAIA;AACL,YAAI,mBAAmB;AACvB,aAAK,UAAU,QAAQ,UAAC,UAAU,iBAAoB;AACpD,cAAI,CAAC,MAAK,WAAW;AACnB,gBAAI,YAAa,MAAK,YAAY,aACjB,MAAK,gBAAgB;AACtC,sBAAU,iCAAmB,WAAW;AACxC,gBAAI,YAAY,CAAC,GAAG;AAClB,gCAAkB;AALD;AAD+B;AASpD,gBAAK,WAAW,YAAY;AAT9B;AAhEuD;AA4EzD,WAAK,aAAa,SAAS,MAAM,KAAK;AACtC,WAAK,UAAU;AACf,WAAK,WAAW,YAAY,MAAM;AAnGrB;AAsGf,oBAAgB,SAAS,oBAAoB,MAAM,MAAM,YAAY;AACnE,eAAS,eAAe,MAAM;AAC5B,YAAI,MAAM,yBAAc,KAAK,SAAS;AAEtC,YAAI,WAAW,KAAK,eAAe;AACnC,YAAI,SAAS,KAAK,eAAe;AACjC,YAAI,SAAS,KAAK,eAAe;AAGjC,YAAI,mBAAmB,KAAK;AAC5B,aAAK,MAAM,KAAK,QAAQ,KAAK,QAAQ;AACrC,aAAK,KAAK;AACV,YAAI,OAAO,KAAK,SAAS;AACzB,aAAK,MAAM;AAEX,YAAI,QAAQ,QAAQ;AAElB,eAAK,KAAK,KAAK,KAAK,KAAK,MAAM,KAAK,MAAM;AAC1C,eAAK,OAAO;AAjBc;AAoB5B;AACE;AACA;AACA;AACA;AACA;AALK;AArB0D;AA8BnE,eAAS,mBAAmB,KAAK;AAC/B;AACE,mBAAS,yBAAc,IAAI,SAAS;AACpC,qBAAW,IAAI;AACf,uBAAa,IAAI;AACjB,yBAAe,IAAI;AACnB,sBAAY,IAAI;AALX;AA/B0D;AA4CnE,eAAS,cAAc,MAAM,MAAM,gBAAgB,aAAa;AAC9D,YAAI,CAAC,MAAM;AACT,0BAAK;AACL;AACE,wBAAY,CAAC;AACb,wBAAY,CAAC;AACb,sBAAU;AACV,0BAAc;AAJT;AAHqD;AAU9D,YAAI;AACJ,YAAI,QAAS,MAAK,QAAQ,KAAK,QAAQ,KAAK,KAAK;AACjD,aAAK,MAAM;AAEX,aAAK;AACL,YAAI,YAAY,KAAK;AAErB,YAAI;AACJ,YAAI,WAAW;AAOf,aAAK,IAAI,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,cAAI,aAAa,KAAK;AACtB,cAAI,aAAa,KAAK;AACtB,cAAI,SAAS,KAAK,eAAe;AACjC,cAAI,WAAW;AAIf,cAAI,kBAAkB,eAAe,eAAe,cAChD,eAAe,eAAe,YAAY;AAC5C;AAVgC;AAalC,cAAI,eAAe,KAAK,eAAe,GAAG;AACxC,uBAAW;AADb,qBAIW,eAAe,KAAK,eAAe,GAAG;AAC/C,uBAAW;AADN,qBAII,eAAe,KAAK,eACnB,qBAAe,CAAC,iBAAiB;AAC3C,uBAAW;AACX,gBAAI,CAAC,gBAAgB;AACnB,yBAAW;AAH8B;AADtC,iBAMA,IAAI,kBAAkB,eAAe,KAAK,eAAe,GAAG;AACjE,uBAAW;AACX,uBAAW;AA7BqB;AAgClC,cAAI,UAAU;AACZ;AACE;AACA;AACA;AAHe;AAjCe;AAuClC,cAAI,UAAU;AACZ;AAxCgC;AAzB0B;AAqE9D,YAAI,gBAAgB;AAClB,eAAK,MAAM,QAAQ,eAAe;AAtE0B;AAwE9D,YAAI,CAAC,kBAAkB,KAAK,eAAe,CAAC,GAAG;AAC7C,0BAAK;AACL;AACE,wBAAY,CAAC;AACb,wBAAY,CAAC;AACb,sBAAU;AACV,0BAAc;AAJT;AA1EqD;AAkF9D,YAAI,SAAS,KAAK;AAClB,aAAK;AACL,aAAK;AAEL,YAAI,eAAe;AACnB,YAAI,WAAW;AACf,YAAI,GAAG;AAGP,YAAI,WAAW,GAAG;AAChB,eAAK,IAAI,GAAG,IAAI,KAAK,KAAK;AACxB,gBAAI,QAAQ,KAAK;AACjB,gBAAI,CAAC,OAAO;AACV;AAHsB;AAKxB,qBAAS;AACP,wBAAU;AACV,uBAAS;AAFG;AANA;AAWhB,yBAAe;AAXjB,mBAYW,WAAW,GAAG;AAGvB,cAAI,WAAY,KAAK,eAAe;AACpC,eAAK,SAAS;AACd,cAAI;cAAU,WAAW;AACzB,eAAK,WAAW,GAAG,WAAW,UAAU,YAAY;AAClD,qBAAS,KAAK,EAAE,KAAK,KAAK;AAPL;AASvB,eAAK;AACL,eAAK,WAAW,GAAG,WAAW,UAAU,YAAY;AAClD,qBAAS,UAAU,QAAQ,KAAK;AAXX;AAcvB,eAAK,WAAW,GAAG,WAAW,UAAU,YAAY;AAClD,qBAAS,UAAU,QAAQ,KAAK;AAfX;AAkBvB,cAAI,eAAe;AACnB,eAAK,WAAW,GAAG,WAAW,UAAU,YAAY;AAClD,sBAAU,SAAS;AACnB,gBAAI,cAAc,KAAK;AACvB,gBAAI,CAAC,aAAa;AAChB,sBAAQ,cAAc,CAAC;AACvB;AALgD;AAQlD,gBAAI,cAAe,gBAAqB,iBAAW;AACnD,oBAAQ,cAAc;AACtB,2BAAe,KAAK,IAAI,cAAc,cACd,QAAQ,MAAM,QAAQ,QAAQ;AA9BjC;AAiCvB,cAAI,UAAU;AACd,eAAK,IAAI,GAAG,IAAI,cAAc,KAAK;AACjC,oBAAQ,KAAK,KAAK;AAnCG;AAsCvB,eAAK,WAAW,GAAG,WAAW,UAAU,YAAY;AAClD,sBAAU,SAAS;AACnB,oBAAQ,QAAQ;AAChB,gBAAI,MAAM,QAAQ;AAClB,gBAAI,QAAQ,QAAQ;AACpB,0BAAc,QAAQ;AAEtB,iBAAK,IAAI,OAAO,KAAK,KAAK,KAAK;AAC7B,kBAAI,MAAM,QAAQ;AAChB;AAF2B;AAK7B,wBAAW,cAAc,IACd,IAAI,QAAQ,cAAc,IAAI;AACzC,wBAAW,UAAU,QAAS;AAC9B,uBAAS;AACP,0BAAU;AACV;AAFY;AAfkC;AAtC7B;AAAlB,mBA2DI,WAAW,GAAG;AAMvB,cAAI,YAAY,KAAK;AACrB,cAAI,aAAa,KAAK;AAEtB,eAAK,IAAI,GAAG,IAAI,YAAY,KAAK;AAC/B,sBAAU,KAAK;AACf,gBAAI,WAAW,YAAY;AAE3B,qBAAS;AACP;AACA;AAFY;AAbO;AAAlB,eAkBA;AACL,0BAAK,wCAAwC;AAC7C;AACE,wBAAY,CAAC;AACb,wBAAY,CAAC;AACb,sBAAU;AACV,0BAAc;AAJT;AAtLqD;AA+L9D,iBAAS,KAAK,UAAU,GAAG,GAAG;AAC5B,iBAAO,EAAE,WAAW,EAAE;AADxB;AAGA,aAAK,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACpC,cAAI,SAAS,IAAI,GAAG,aAAa,SAAS,GAAG,UAAU;AACrD,qBAAS,OAAO,GAAG;AACnB;AAHkC;AAlMwB;AAyM9D;AACE,sBAAY,eAAe;AAC3B,sBAAY,eAAe;AAC3B;AACA;AAJK;AArP0D;AA6PnE,eAAS,gBAAgB,MAAM,QAAQ,SAAS,WAAW;AACzD,YAAI,CAAC,QAAQ;AACX,cAAI,SAAS;AACX,oBAAQ,OAAO;AAFN;AAIX;AALuD;AAQzD,aAAK,MAAO,MAAK,QAAQ,KAAK,QAAQ,KAAK,OAAO;AAClD,aAAK,OAAO,OAAO,SAAS;AAC5B,YAAI,eAAe,KAAK;AAExB,YAAI,eAAe,WAAW;AAC5B,0BAAK,uBAAuB,eAAe,qBACtC,iCAAiC,YAAY;AAElD,yBAAe;AACf,iBAAO,KAAK,MAAO,gBAAe,WAAW;AAC7C,iBAAO,KAAK,MAAM,eAAe;AAlBsB;AAqBzD,YAAI,oBAAoB,YAAY;AACpC,YAAI,aACD,qBAAC,QAAQ,SAAS,eAAe,KAAM;AAE1C,YAAI,aAAa,GAAG;AAIlB,cAAI,UAAU,IAAI,WAAW,QAAQ,SAAS,aAAa;AAC3D,kBAAQ,IAAI,QAAQ;AACpB,kBAAQ,OAAO;AA/BwC;AA7PQ;AAgSnE,eAAS,cAAc,QAAQ,aAAa,WAAW,MAAM,WACtC,YAAY;AACjC,YAAI,YAAY,eAAe,IAAI;AAEjC,iBAAO;AAHwB;AAKjC,YAAI,OAAO,OAAO,SAAS,aAAa;AACxC,YAAI,gBAAiB,KAAK,MAAM,IAAK,KAAK;AAC1C,YAAI,gBAAgB,QAAQ;AAE1B,eAAK,IAAI,MAAM;AACf,iBAAO,KAAK;AAVmB;AAajC,YAAI;YAAG,IAAI;YAAI,aAAa;AAC5B,aAAK,IAAI,GAAG,IAAI,eAAe,KAAK;AAClC,cAAI,WAAY,KAAK,MAAM,IAAK,KAAK,IAAI;AACzC,uBAAa,WAAW;AACxB,eAAK;AAjB0B;AAoBjC,YAAI,oBAAoB;AACxB,YAAI,qBAAsB,KAAK,MAAM,IAAK,KAAK,IAAI;AACnD,aAAK,IAAI;AACT,YAAI,kBAAkB;AAEtB,YAAI,oBAAoB;AACxB,aAAK,IAAI,GAAG,IAAI,YAAY,KAAK;AAC/B,cAAI,OAAO,KAAK;AAChB,cAAI,OAAO,MAAM;AAEf,iBAAK,IAAI,KAAK,OAAO;AAJQ;AAM/B,cAAI,WAAY,CAAC,OAAO,IAAK,IAAK,OAAO,KAAM,IAC/B,MAAC,OAAO,IAAK,IAAK,OAAO,KAAM,IAAI;AACnD,+BAAqB;AACrB,cAAI,OAAO,GAAG;AACZ,gBAAI,SAAS,KAAK;AAClB,iBAAK;AACL,iCAAqB,SAAS;AAZD;AA1BA;AA0CjC,YAAI,sBAAsB,GAAG;AAC3B,iBAAO;AA3CwB;AA6CjC,YAAI,kBAAkB,IAAI;AAC1B,YAAI,kBAAkB,KAAK,QAAQ;AAEjC,iBAAO;AAhDwB;AAkDjC,YAAI,CAAC,cAAc,qBAAqB,GAAG;AACzC,eAAK,IAAI,KAAK,SAAS,GAAG,oBAAoB;AAC9C,eAAK,IAAI,CAAC,GAAG,IAAI,YAAY;AAC7B,eAAK,IAAI,KAAK,SAAS,iBAAiB,kBAC/B,YAAY,oBAAoB;AACzC,6BAAmB;AACnB,cAAI,KAAK,SAAS,kBAAkB,GAAG;AACrC,8BAAmB,kBAAkB,IAAK,CAAC;AAPJ;AASzC,iBAAO;AA3DwB;AA6DjC,YAAI,KAAK,SAAS,kBAAkB,GAAG;AAErC,4BAAmB,kBAAkB,IAAK,CAAC;AAC3C,eAAK,IAAI,KAAK,SAAS,GAAG,kBAAkB;AAC5C,iBAAO;AAjEwB;AAoEjC,aAAK,IAAI,MAAM;AACf,eAAO,KAAK;AAtWqD;AAyWnE,eAAS,aAAa,MAAM,WAAW,YAAY;AACjD,YAAI,OAAO,KAAK;AAIhB,YAAI,UAAU,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK;AACpD,YAAI,WAAW,OAAO,GAAG;AACvB,0BAAK,sDAAsD;AAC3D,eAAK,KAAK;AACV,eAAK,KAAK;AACV,eAAK,KAAK;AACV,eAAK,KAAK;AAXqC;AAcjD,YAAI,mBAAmB,MAAM,KAAK,KAAK,KAAK;AAC5C,YAAI,mBAAmB,KAAK,mBAAmB,GAAG;AAChD,0BAAK,+DACA;AAYL,cAAI,mBAAmB,YAAY;AACnC,cAAI,eAAe,oBAAoB,GAAG;AAExC,iBAAK,MAAM;AACX,iBAAK,MAAM;AAHb,qBAIW,eAAe,oBAAoB,GAAG;AAE/C,iBAAK,MAAM;AACX,iBAAK,MAAM;AAHN,iBAIA;AACL,kBAAU,sBAAY,qCACA;AAzBwB;AAfD;AAzWgB;AAsZnE,eAAS,uBAAuB,MAAM,MAAM,WACZ,sBAAsB,YACtB,eAAe;AAC7C,YAAI,UAAU,YAAY;AAC1B,YAAI,sBAAsB;AACxB,qBAAW;AACX,uBAAa,SAAS,mBAAmB,MAAM,QAAQ;AACrD,mBAAQ,KAAK,WAAW,KAAO,KAAK,SAAS,MAAM,KAC3C,KAAK,SAAS,MAAM,IAAK,KAAK,SAAS;AAFjD;AAIA,uBAAa,SAAS,mBAAmB,MAAM,QAAQ,OAAO;AAC5D,iBAAK,UAAW,UAAU,KAAM;AAChC,iBAAK,SAAS,KAAM,SAAS,KAAM;AACnC,iBAAK,SAAS,KAAM,SAAS,IAAK;AAClC,iBAAK,SAAS,KAAK,QAAQ;AAJ7B;AANF,eAYO;AACL,qBAAW;AACX,uBAAa,SAAS,eAAe,MAAM,QAAQ;AACjD,mBAAQ,KAAK,WAAW,IAAM,KAAK,SAAS,MAAM;AADpD;AAGA,uBAAa,SAAS,eAAe,MAAM,QAAQ,OAAO;AACxD,iBAAK,UAAW,SAAS,IAAK;AAC9B,iBAAK,SAAS,KAAM,SAAS,IAAK;AAFpC;AAnB2C;AAwB7C,YAAI,WAAW,KAAK;AACpB,YAAI,eAA2B,gBAAI;AAEnC,YAAI,SAAS,WAAW,cAAc;AACpC,qBAAW,IAAI,WAAW;AAC1B,mBAAS,IAAI,KAAK,KAAK,SAAS,GAAG;AACnC,eAAK,OAAO;AA9B+B;AAiC7C,YAAI,cAAc,KAAK;AACvB,YAAI,oBAAoB,YAAY;AACpC,YAAI,cAAc,IAAI,WAAW;AACjC,YAAI,cAAc,WAAW,UAAU;AACvC,YAAI,cAAc;AAClB,YAAI,mBAAmB,OAAO,OAAO;AACrC,mBAAW,UAAU,GAAG;AACxB,YAAI,GAAG;AAGP,YAAI,YAAY,gBAAgB,YAAY,IAAI;AAChD,aAAK,IAAI,GAAG,IAAI,UAAU,IAAI,WAAW,KAAK,KAAK,UAAU;AAC3D,cAAI,YAAY,WAAW,UAAU;AACrC,cAAI,YAAY,qBACX,CAAC,oBAAoB,IAAK,CAAC,OAAO,WAAW;AAGhD,wBAAY;AAN6C;AAQ3D,cAAI,YAAY,mBAAmB;AAEjC,0BAAc;AAV2C;AAa3D,cAAI,YAAY,cAAc,aAAa,aAAa,WAC1B,aAAa,aAAa;AACxD,cAAI,cAAc,GAAG;AACnB,6BAAiB,KAAK;AAhBmC;AAkB3D,yBAAe;AACf,qBAAW,UAAU,GAAG;AACxB,wBAAc;AAhE6B;AAmE7C,YAAI,gBAAgB,GAAG;AAGrB,cAAI,cAAc,IAAI,WACpB,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI;AACjD,eAAK,IAAI,GAAG,IAAI,UAAU,IAAI,WAAW,KAAK,KAAK,UAAU;AAC3D,uBAAW,UAAU,GAAG,YAAY;AANjB;AAQrB,eAAK,OAAO;AACZ,iBAAO;AA5EoC;AA+E7C,YAAI,eAAe;AACjB,cAAI,mBAAmB,WAAW,UAAU;AAC5C,cAAI,YAAY,SAAS,mBAAmB,aAAa;AACvD,iBAAK,OAAO,YAAY,SAAS,GAAG,mBAAmB;AADzD,iBAEO;AACL,iBAAK,OAAO,IAAI,WAAW,mBAAmB;AAC9C,iBAAK,KAAK,IAAI,YAAY,SAAS,GAAG;AANvB;AAQjB,eAAK,KAAK,IAAI,YAAY,SAAS,GAAG,mBAAmB;AACzD,qBAAW,KAAK,MAAM,SAAS,SAAS,UAC7B,cAAc;AAV3B,eAWO;AACL,eAAK,OAAO,YAAY,SAAS,GAAG;AA3FO;AA6F7C,eAAO;AArf0D;AAwfnE,eAAS,oBAAoB,MAAM,YAAY,eAAe;AAC5D,YAAI,QAAS,MAAK,QAAQ,KAAK,QAAQ,KAAK,KAAK;AACjD,aAAK,MAAM;AAEX,YAAI,SAAS,KAAK;YAAQ,MAAM,QAAQ;AACxC,YAAI,UAAU,KAAK;AAEnB,aAAK,SAAS;AAEd,YAAI;AACJ,YAAI,QAAQ;AACZ,YAAI;AAEJ,gBAAQ;AACN,eAAK;AACH,yBAAa;AACb;AACF,eAAK;AACH,gBAAI,YAAY,KAAK;AACrB,gBAAI,cAAc,eAAe;AAC/B,sBAAQ;AACR;AAJJ;AAME,gBAAI,mBAAmB;AACvB,iBAAK,IAAI,GAAG,IAAI,WAAW,EAAE,GAAG;AAC9B,kBAAI,QAAQ,KAAK;AACjB,kBAAI,SAAS,OAAO;AAClB,wBAAQ;AACR;AAJ4B;AAM9B,+BAAiB,KAAK;AAb1B;AAeE,gBAAI,CAAC,OAAO;AACV;AAhBJ;AAkBE,gBAAI,cAAc;AAClB,gBAAI,SAAS;AACb,mBAAO,KAAK,MAAM,KAAK;AACrB,kBAAI,eAAe,KAAK;AACxB,qBAAO,SAAS;AAChB,mBAAK,IAAI,GAAG,IAAI,cAAc,EAAE,GAAG;AACjC,uBAAO,KAAK,OAAO,aAAa,KAAK;AAJlB;AAMrB,0BAAY,KAAK,OAAO,KAAK;AA1BjC;AA4BE,yBAAa;AACb,iBAAK,IAAI,GAAG,IAAI,WAAW,EAAE,GAAG;AAC9B,kBAAI,IAAI,iBAAiB;AACzB,kBAAI,IAAI,KAAK;AACX,2BAAW,KAAK,yBAAyB;AACzC;AAJ4B;AAM9B,yBAAW,KAAK,YAAY,IAAI;AAnCpC;AAqCE;AACF,eAAK;AACH;AACF;AACE,4BAAK,4CAA4C;AACjD,oBAAQ;AACR,gBAAI,WAAW,iBAAiB;AAC9B,2BAAa,WAAW;AAJ5B;AAME;;AAEJ,mBAAW,aAAa;AACxB,eAAO;AA1jB0D;AA6jBnE,eAAS,cAAc,WAAW;AAChC,YAAI,QAAS,MAAK,QAAQ,KAAK,QAAQ,KAAK,UAAU;AACtD,aAAK,MAAM;AAEX,YAAI,QAAQ,CAAC,IAAI;AACjB,YAAI,SAAS,UAAU;YAAQ,MAAM,QAAQ;AAC7C,YAAI,SAAS,KAAK;AAClB,YAAI,yBAAyB;AAC7B,YAAI,WAAW,KAAK,SAAS,wBAAwB;AAEnD,iBAAO;AAVuB;AAYhC,YAAI,aAAa,KAAK;AACtB,YAAI,eAAe,KAAK;AACxB,YAAI,UAAU;AACd,YAAI,qBAAqB;AACzB,YAAI,GAAG;AAEP,aAAK,IAAI,GAAG,IAAI,cACA,KAAK,MAAM,sBAAsB,KAAK,KAAK;AACzD,cAAI;AACF,sBAAU,KAAK;AACf,sBAAU,KAAK;AACf,sBAAU,KAAK;AACf,kBAAM,KAAK;AACX,oBAAQ,KAAK;AACb,oBAAQ,KAAK;AANP;AASR,cAAK,EAAE,aAAa,KAAK,EAAE,aAAa,KAAK,EAAE,aAAa,KACvD,EAAE,aAAa,KAAK,EAAE,aAAa,KAAK,EAAE,aAAa,OAAQ;AAClE,oBAAQ,KAAK;AAZ0C;AAnB3B;AAkChC,aAAK,IAAI,GAAG,KAAK,QAAQ,QAAQ,IAAI,IAAI,KAAK;AAC5C,cAAI,SAAS,QAAQ;AACrB,cAAI,OAAO,UAAU,GAAG;AACtB;AAH0C;AAK5C,cAAI,MAAM,QAAQ,eAAe,OAAO;AACxC,cAAI,MAAM,OAAO,SAAS,KAAK;AAC7B;AAP0C;AAS5C,eAAK,MAAM;AACX,cAAI,YAAY,OAAO;AACvB,cAAI,OAAO,UAAU;AAEnB,gBAAI,MAAM;AACV,iBAAK,IAAI,IAAI,GAAG,KAAK,OAAO,QAAQ,IAAI,IAAI,KAAK,GAAG;AAClD,qBAAO,OAAO,aAAa,KAAK;AAJf;AAMnB,kBAAM,GAAG,aAAa;AANxB,iBAOO;AACL,kBAAM,GAAG,aAAa,yBAAc,KAAK,SAAS,OAAO;AAnBf;AAlCd;AAwDhC,eAAO;AArnB0D;AAwnBnE,UAAI,mBAAmB,CACrB,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GACnD,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAC1D,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,GACzD,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,GAClE,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,GACnD,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAC3D,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GACjD,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GACnE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;AAGxD,eAAS,kBAAkB,OAAO,WAAW;AAC3C,YAAI,OAAO,MAAM;AACjB,YAAI,IAAI;YAAG;YAAG;YAAG;YAAG;YAAQ;YAAI,WAAW;YAAG,WAAW;AACzD,YAAI,QAAQ;AACZ,YAAI,YAAY;AAChB,YAAI,kBAAkB;AACtB,YAAI,8BACF,UAAU;AACZ,YAAI,SAAS;YAAO,UAAU;YAAG,SAAS;AAC1C,aAAK,IAAI,KAAK,KAAK,QAAQ,IAAI,KAAK;AAClC,cAAI,KAAK,KAAK;AAGd,cAAI,OAAO,MAAM;AACf,gBAAI,KAAK;AACT,gBAAI,UAAU,QAAQ;AACpB,mBAAK;AADP,mBAEO;AACL,mBAAK,IAAI,GAAG,IAAI,GAAG,KAAK;AACtB,sBAAM,KAAK,KAAK;AAFb;AAJQ;AAAjB,qBASW,OAAO,MAAM;AACtB,gBAAI,KAAK;AACT,gBAAI,UAAU,QAAQ;AACpB,mBAAK,IAAI;AADX,mBAEO;AACL,mBAAK,IAAI,GAAG,IAAI,GAAG,KAAK;AACtB,oBAAI,KAAK;AACT,sBAAM,KAAM,KAAK,IAAK,KAAK;AAHxB;AAJe;AAAjB,qBAUK,MAAK,UAAU,MAAM;AAC/B,gBAAI,KAAK,OAAO;AAChB,gBAAI,UAAU,QAAQ;AACpB,mBAAK;AADP,mBAEO;AACL,mBAAK,IAAI,GAAG,IAAI,GAAG,KAAK;AACtB,sBAAM,KAAK,KAAK;AAFb;AAJwB;AAA1B,qBASK,MAAK,UAAU,MAAM;AAC/B,gBAAI,KAAK,OAAO;AAChB,gBAAI,UAAU,QAAQ;AACpB,mBAAK,IAAI;AADX,mBAEO;AACL,mBAAK,IAAI,GAAG,IAAI,GAAG,KAAK;AACtB,oBAAI,KAAK;AACT,sBAAM,KAAM,KAAK,IAAK,KAAK;AAHxB;AAJwB;AAA1B,qBAUI,OAAO,QAAQ,CAAC,6BAA6B;AACtD,gBAAI,CAAC,UAAU,CAAC,QAAQ;AAEtB,uBAAS,MAAM,MAAM,SAAS;AAC9B,wBAAU,cAAc,UAAU;AAClC,kBAAI,UAAU,UAAU,sBAAsB;AAC5C,sBAAM,UAAU,UAAU,qBAAqB;AADjD,qBAEO,IAAI,UAAU,UAAU,oBACpB,gBAAgB,QAAQ,UAAU,GAAG;AAC9C,0BAAU;AAAO;AAAM;AAAG,4BAAU,MAAM,SAAS;AAApC;AACf,gCAAgB,KAAK;AACrB,qBAAK,UAAU,iBAAiB;AAChC,oBAAI,CAAC,IAAI;AACP,kCAAK;AACL,4BAAU,aAAa;AACvB;AAP4C;AAS9C,uBAAO,GAAG;AACV,oBAAI,GAAG;AAjBa;AAD8B;AAAjD,qBAqBI,OAAO,QAAQ,CAAC,6BAA6B;AACtD,gBAAI,UAAU,QAAQ;AACpB,8BAAK;AACL,4CAA8B;AAHsB;AAKtD,qBAAS;AAET,uBAAW;AACX,qBAAS,MAAM;AACf,sBAAU,iBAAiB;AAAY;AAAM;AAAR;AAThC,qBAUI,OAAO,MAAM;AACtB,gBAAI,QAAQ;AACV,uBAAS;AACT,yBAAW;AAFb,mBAGO;AACL,mBAAK,UAAU;AACf,kBAAI,CAAC,IAAI;AACP,gCAAK;AACL,0BAAU,aAAa;AACvB;AALG;AAOL,uBAAS,gBAAgB;AACzB,qBAAO,GAAG;AACV,kBAAI,GAAG;AACP,wBAAU,qBAAqB,UAC7B,MAAM,SAAS,GAAG;AAfA;AAAjB,qBAiBI,OAAO,MAAM;AACtB,gBAAI,UAAU,QAAQ;AACpB,8BAAK;AACL,4CAA8B;AAHV;AAKtB,qBAAS;AAET,uBAAW;AAPN,qBAQI,OAAO,MAAM;AACtB,cAAE;AADG,qBAEI,OAAO,MAAM;AACtB,qBAAS;AADJ,qBAEI,OAAO,MAAM;AACtB,gBAAI,WAAW,SAAS;AACtB,uBAAS;AAFW;AAItB,cAAE;AAJG,iBAKA,IAAI,OAAO,MAAM;AACtB,gBAAI,CAAC,UAAU,CAAC,QAAQ;AACtB,kBAAI,SAAS,MAAM,MAAM,SAAS;AAElC,kBAAI,SAAS,GAAG;AACd,qBAAK,SAAS;AAJM;AADF;AA3GU;AAqHlC,cAAI,CAAC,UAAU,CAAC,QAAQ;AACtB,gBAAI,aAAa,MAAM,OAAO,iBAAiB,MAC7C,MAAM,QAAQ,MAAM,OAAO,CAAC,IAAI,MAAM,OAAO,CAAC,IAAI;AACpD,gBAAI,MAAM,QAAQ,MAAM,MAAM;AAC5B,kBAAI,MAAM;AACV,kBAAI,CAAC,MAAM,IAAI;AACb,6BAAa,CAAC,IAAI;AAHQ;AAHR;AAStB,mBAAO,aAAa,KAAK,MAAM,SAAS,GAAG;AACzC,oBAAM;AACN;AAXoB;AAatB,mBAAO,aAAa,GAAG;AACrB,oBAAM,KAAK;AACX;AAfoB;AArHU;AATO;AAiJ3C,kBAAU,8BAA8B;AACxC,YAAI,UAAU,CAAC;AACf,YAAI,IAAI,KAAK,QAAQ;AACnB,kBAAQ,KAAK,IAAI,WAAW,IAAI,KAAK;AApJI;AAsJ3C,YAAI,WAAW,UAAU;AACvB,0BAAK;AAGL,kBAAQ,KAAK,IAAI,WAAW,CAAC,MAAM;AA1JM;AA4J3C,oBAAY,OAAO;AAhyB8C;AAmyBnE,eAAS,sBAAsB,WAAW,iBAAiB;AACzD,YAAI,UAAU,6BAA6B;AACzC;AAFuD;AAIzD,YAAI,UAAU,iBAAiB,SAAS,iBAAiB;AACvD,0BAAK;AACL,oBAAU,aAAa;AACvB;AAPuD;AASzD,aAAK,IAAI,IAAI,GAAG,KAAK,UAAU,cAAc,QAAQ,IAAI,IAAI,KAAK;AAChE,cAAI,IAAI,iBAAiB;AACvB,4BAAK,8BAA8B;AACnC,sBAAU,aAAa;AACvB;AAJ8D;AAMhE,cAAI,UAAU,cAAc,MAAM,CAAC,UAAU,iBAAiB,IAAI;AAChE,4BAAK,6BAA6B;AAClC,sBAAU,aAAa;AACvB;AAT8D;AATT;AAnyBQ;AA0zBnE,eAAS,YAAY,OAAO,SAAS;AACnC,YAAI,QAAQ,SAAS,GAAG;AAEtB,cAAI,YAAY;AAChB,cAAI,GAAG;AACP,eAAK,IAAI,GAAG,KAAK,QAAQ,QAAQ,IAAI,IAAI,KAAK;AAC5C,yBAAa,QAAQ,GAAG;AALJ;AAOtB,sBAAa,YAAY,IAAK,CAAC;AAC/B,cAAI,SAAS,IAAI,WAAW;AAC5B,cAAI,MAAM;AACV,eAAK,IAAI,GAAG,KAAK,QAAQ,QAAQ,IAAI,IAAI,KAAK;AAC5C,mBAAO,IAAI,QAAQ,IAAI;AACvB,mBAAO,QAAQ,GAAG;AAZE;AActB,gBAAM,OAAO;AACb,gBAAM,SAAS;AAhBkB;AA1zB8B;AA80BnE,eAAS,mBAAmB,MAAM,MAAM,KAAK,iBAAiB;AAC5D,YAAI;AACF,4BAAkB;AAClB,yBAAe;AACf,gCAAsB;AACtB,uCAA6B;AAC7B,sBAAY;AALE;AAOhB,YAAI,MAAM;AACR,4BAAkB,MAAM;AATkC;AAW5D,YAAI,MAAM;AACR,4BAAkB,MAAM;AAZkC;AAc5D,YAAI,MAAM;AACR,gCAAsB,WAAW;AAfyB;AAiB5D,YAAI,OAAQ,IAAI,SAAS,GAAI;AAC3B,cAAI,UAAU,IAAI,WAAW,IAAI,SAAS;AAC1C,kBAAQ,IAAI,IAAI;AAChB,cAAI,OAAO;AApB+C;AAsB5D,eAAO,UAAU;AAp2BgD;AAw2BnE,aAAW,mBAAO,IAAI,WAAW,KAAK;AAEtC,UAAI,eAAe,CAAC,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,QAC1D,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ;AAE1D,UAAI,SAAS,mBAAmB;AAChC,UAAI,YAAY,OAAO;AACvB,UAAI,KAAK;AAET,UAAI,SAAS,OAAO,OAAO;AAC3B,aAAO,UAAU;AACjB,aAAO,UAAU;AACjB,aAAO,UAAU;AACjB,aAAO,UAAU;AACjB,aAAO,UAAU;AACjB,aAAO,UAAU;AACjB,aAAO,UAAU;AACjB,aAAO,UAAU;AAEjB,UAAI;AACJ,WAAK,IAAI,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,gBAAQ,eAAe;AACvB,YAAI,aAAa,QAAQ,MAAM,OAAO,GAAG;AACvC;AAHgC;AAKlC,YAAI,MAAM,WAAW,GAAG;AACtB;AANgC;AAQlC,eAAO,MAAM,OAAO;AAp4B6C;AAu4BnE,UAAI,aAAa,CAAC,OAAO;AACzB,UAAI,CAAC,YAAY;AAEf,YAAK,OAAO,YAAY,UACjB,aAAW,aAAa,WAAW,gBACtC,CAAC,OAAO,WAAW,CAAC,OAAO,WAAW,CAAC,OAAO,WAC9C,CAAC,OAAO,SAAS;AAEnB,oBAAc,mBAAO,OAAO,QAAQ;AACpC,gBAAM,IAAI,QAAQ,SAAS;AAE3B,uBAAa;AAEb,iBAAO,KAAK,QAAQ,MAAM,KAAK;AAZlB;AAef,eAAO,OAAO;AACd,eAAO,OAAO;AACd,eAAO,OAAO;AACd,eAAO,OAAO;AACd,eAAO,OAAO;AACd,aAAK,aAAa;AApBpB,aAqBO;AACL,YAAI,CAAC,OAAO,SAAS;AACnB,gBAAU,sBAAY;AAFnB;AAIL,YAAI,CAAC,OAAO,SAAS;AACnB,0BAAK;AAEL,iBAAO;AACL,iBAAK;AACL,kBAAM,IAAI,WAAW;AAFN;AAPd;AAYL,aAAK,aAAa;AAz6B+C;AA46BnE,UAAI,CAAC,OAAO,SAAS;AACnB,cAAU,sBAAY;AA76B2C;AAg7BnE,WAAK,MAAO,MAAK,SAAS,KAAK,OAAO,QAAQ;AAC9C,UAAI,UAAU,KAAK;AACnB,UAAI,YAAY,KAAK;AACrB,UAAI,kBAAkB;AACtB,UAAI,WAAW,cAAc,OAAO,QAAQ,UAAU,IAAI;AAExD,aAAK,OAAO;AACZ,YAAI,WAAW,KAAK;AACpB,YAAI,WAAW,GAAG;AAChB,iBAAO,QAAQ,KAAK,MAAM;AAC1B,iBAAO,QAAQ,KAAK,MAAM;AAN4B;AAQxD,aAAK,OAAO;AACZ,0BAAkB,KAAK;AA77B0C;AAg8BnE,UAAI,gBAAgB;AACpB,UAAI,WAAW,SAAS,kBAAkB,WAAW,aACjD,WAAW,UAAU,IAAI,KAAK,MAAU;AAE1C,wBAAgB;AAChB;AACA,eAAO,QAAQ,KAAK,KAAK,aAAa;AACtC,eAAO,QAAQ,KAAK,KAAK,YAAY;AAv8B4B;AA08BnE,UAAI,aAAa,mBAAmB,OAAO,SAAS,OAAO,SACvB,OAAO,SAAS;AACpD,UAAI,CAAC,YAAY;AACf,eAAO,OAAO;AACd,eAAO,OAAO;AACd,eAAO,OAAO;AA/8BmD;AAo9BnE,sBAAgB,MAAM,OAAO,SAAS,OAAO,SAAS;AAEtD,UAAI,CAAC,OAAO,SAAS;AACnB,cAAU,sBAAY;AAv9B2C;AA09BnE,mBAAa,OAAO,SAAS,WAChB,aAAa,OAAO,QAAQ,SAAS;AAElD,UAAI,gBAAgB,OAAO,OAAO;AAClC,UAAI,YAAY;AACd,YAAI,uBAAuB,MAAM,OAAO,QAAQ,KAAK,KACpB,OAAO,QAAQ,KAAK;AACrD,wBAAgB,uBAAuB,OAAO,SAAS,OAAO,SACvB,WAAW,sBACX,YAAY;AAn+Bc;AAs+BnE,UAAI,CAAC,OAAO,SAAS;AACnB,cAAU,sBAAY;AAv+B2C;AA4+BnE,UAAI,OAAO,QAAQ,KAAK,QAAQ,KAAK,OAAO,QAAQ,KAAK,QAAQ,GAAG;AAClE,eAAO,QAAQ,KAAK,MAAM;AAC1B,eAAO,QAAQ,KAAK,MAAM;AA9+BuC;AAm/BnE,UAAI;AACF,oBAAY,MAAM,OAAO,QAAQ,KAAK,KAAK,OAAO,QAAQ,KAAK;AAC/D,cAAM,MAAM,OAAO,QAAQ,KAAK,KAAK,OAAO,QAAQ,KAAK;AACzD,cAAM,YAAY,OAAO,QAAQ,KAAK,KAAK,OAAO,QAAQ,KAAK;AAC/D,gBAAQ,MAAM,OAAO,QAAQ,KAAK,IAAI,OAAO,QAAQ,KAAK;AAC1D,iBAAS,YAAY,OAAO,QAAQ,KAAK,IAAI,OAAO,QAAQ,KAAK;AAL7C;AAStB,WAAK,SAAS,gBAAgB,SAAS,gBAAgB;AACvD,WAAK,UAAU,gBAAgB,UAAU,gBAAgB;AAGzD,UAAI,OAAO,SAAS;AAClB,YAAI,QAAQ,oBAAoB,OAAO,SAAS,YAAY;AAC5D,YAAI,CAAC,OAAO;AACV,iBAAO,UAAU;AAHD;AAhgC+C;AAugCnE,UAAI,oBAAoB;UAAI;AAG5B,eAAS,SAAS,SAAS;AACzB,eAAO,CAAC,cAAc;AA3gC2C;AA8gCnE,UAAI,WAAW,WAAW;AACxB,YAAI,cAAc,WAAW,eAAe;AAC5C,YAAI,qBAAqB,YAAY,WAAW;AAEhD,mBAAW,KAAK,QAAQ,UAAS,UAAU,KAAK;AAC9C,cAAI,MAAM,QAAQ;AAChB,kBAAU,sBAAY;AAFsB;AAI9C,cAAI,UAAU,CAAC;AACf,cAAI,oBAAoB;AACtB,sBAAU;AADZ,iBAEO,IAAI,YAAY,SAAS,WAAW;AACzC,sBAAU,YAAY;AARsB;AAW9C,cAAI,WAAW,KAAK,UAAU,aAAa,SAAS,UAAU;AAC5D,8BAAkB,YAAY;AAZc;AAAhD;AAeA,YAAsB,wCAAsB,CAAC,kBAAkB,KAAK;AAIlE,4BAAkB,KAAK,YAAY;AAvBb;AAA1B,aAyBO;AAGL,YAAI,YAAY,cAAc,OAAO,SAAS,MAAM,KAAK,gBAC3B,WAAW;AACzC,YAAI,iBAAiB,UAAU;AAC/B,YAAI,iBAAiB,UAAU;AAC/B,YAAI,eAAe,UAAU;AAC7B,YAAI,qBAAqB,aAAa;AAKtC,YAAI,WACC,mCAAmB,KAAK,mBAAmB,KAC3C,mBAAmB,KAAK,mBAAmB,MAC3C,mBAAmB,CAAC,KAAK,mBAAmB,CAAC,KAC7C,CAAC,CAAC,4BAAY,WAAW,mBAAoB;AAOhD,cAAI,eAAe;AACnB,cAAI,WAAW,qBAAqB,sBAChC,WAAW,qBAAqB,mBAAmB;AACrD,2BAAe,4BAAY,WAAW;AAVQ;AAYhD,cAAI,mBAAmB;AACvB,eAAK,WAAW,GAAG,WAAW,KAAK,YAAY;AAC7C,gBAAI,WAAW;AACf,gBAAI,KAAK,eAAe,YAAY,KAAK,aAAa;AACpD,0BAAY,KAAK,YAAY;AAD/B,uBAEW,YAAY,gBACZ,aAAa,cAAc,IAAI;AACxC,0BAAY,aAAa;AAFpB,mBAGA;AACL,0BAAY,4BAAiB;AARc;AAU7C,gBAAI,CAAC,WAAW;AACd;AAX2C;AAc7C,gCAAoB,iBAAiB,WAAW;AAEhD,gBAAI;AACJ,gBAAI,mBAAmB,KAAK,mBAAmB,GAAG;AAChD,kCAAoB,iBAAiB;AADvC,mBAEO,IAAI,mBAAmB,KAAK,mBAAmB,GAAG;AAEvD,kCAAoB,4BAAiB,QAAQ;AArBF;AAwB7C,gBAAI,QAAQ;AACZ,iBAAK,IAAI,GAAG,IAAI,oBAAoB,EAAE,GAAG;AACvC,kBAAI,aAAa,GAAG,aAAa,mBAAmB;AAClD;AAFqC;AAIvC,gCAAkB,YAAY,aAAa,GAAG;AAC9C,sBAAQ;AACR;AA/B2C;AAiC7C,gBAAI,CAAC,SAAS,WAAW,YAAY;AAEnC,kBAAI,UAAU,WAAW,WAAW,QAAQ;AAG5C,kBAAI,YAAY,CAAC,KAAK,sBAAsB,WAAW;AACrD,0BAAU,WAAW,WAAW,QAAQ;AANP;AAQnC,kBAAI,UAAU,KAAK,SAAS,UAAU;AACpC,kCAAkB,YAAY;AAC9B,wBAAQ;AAVyB;AAjCQ;AAbC;AAJlD,mBAgEW,mBAAmB,KAAK,mBAAmB,GAAG;AAEvD,eAAK,IAAI,GAAG,IAAI,oBAAoB,EAAE,GAAG;AACvC,8BAAkB,aAAa,GAAG,YAChC,aAAa,GAAG;AAJmC;AAAlD,eAMA;AAYL,eAAK,IAAI,GAAG,IAAI,oBAAoB,EAAE,GAAG;AACvC,uBAAW,aAAa,GAAG;AAC3B,gBAAI,mBAAmB,KACnB,YAAY,UAAU,YAAY,QAAQ;AAC5C,0BAAY;AAJyB;AAMvC,8BAAkB,YAAY,aAAa,GAAG;AAlB3C;AAnFF;AAviC4D;AAipCnE,UAAI,kBAAkB,WAAW,GAAG;AAElC,0BAAkB,KAAK;AAnpC0C;AAupCnE,UAAI,aAAa,cAAc,mBAAmB,YACnB;AAC/B,WAAK,aAAa,WAAW;AAC7B,aAAO;AACL,aAAK;AACL,cAAM,gBAAgB,WAAW,mBAAmB;AAFrC;AAKjB,UAAI,CAAC,OAAO,WAAW,CAAC,iBAAiB,OAAO,UAAU;AACxD,eAAO;AACL,eAAK;AACL,gBAAM,eAAe,YAAY,WAAW,mBACvB;AAHN;AAhqCgD;AAwqCnE,UAAI,CAAC,OAAO,SAAS;AACnB,eAAO;AACL,eAAK;AACL,gBAAM,gBAAgB;AAFP;AAzqCgD;AA+qCnE,UAAI,CAAC,YAAY;AACf,YAAI;AAEF,oBAAc,mBAAO,OAAO,QAAQ;AACpC,cAAI,SAAa,0BAAU,SAAS,YACT;AAC3B,gBAAM,OAAO;AACb,cAAI,WAAe,4BAAY;AAC/B,iBAAO,QAAQ,OAAO,SAAS;AAPjC,UAQE,OAAO,GAAG;AACV,0BAAK,4BAA4B,WAAW;AAV/B;AA/qCkD;AA8rCnE,UAAI,CAAC,OAAO,SAAS;AACnB,eAAO;AACL,eAAK;AACL,gBAAM,gBAAgB,KAAK;AAFZ;AADnB,aAKO;AAEL,YAAI,gBAAgB,cAAc,OAAO;AACzC,eAAO,QAAQ,OAAO,gBAAgB,MAAM;AAtsCqB;AAysCnE,UAAI,UAAU,IAAI,oBAAoB,OAAO;AAC7C,eAAS,YAAY,QAAQ;AAC3B,gBAAQ,SAAS,UAAU,OAAO,UAAU;AA3sCqB;AA6sCnE,aAAO,QAAQ;AAnzCF;AAszCf,aAAS,SAAS,aAAa,UAAU,MAAM,YAAY;AAEzD,iBAAW,aAAa;AAExB,UAAI,WAAW,iBAAiB;AAG9B,wBAAgB,YAAY,WAAW;AAPgB;AAUzD,UAAI,UAAU,KAAK,gBAAgB;AACnC,UAAI,aAAa,cAAc,SAAS,YAAY,OAAO,OAAO;AAClE,WAAK,aAAa,WAAW;AAC7B,UAAI,YAAY,KAAK;AAErB,eAAS,aAAa,mBAAmB,SAAS;AAChD,YAAI,YAAY;AAChB,iBAAS,YAAY,mBAAmB;AACtC,cAAI,YAAY,kBAAkB,WAAW;AAC3C,gBAAI,CAAC,WAAW;AACd,0BAAY;AAF6B;AAI3C,sBAAU,KAAK,WAAW;AALU;AAFQ;AAUhD,eAAO;AAzBgD;AA4BzD,eAAS,eAAe,mBAAmB,SAAS;AAClD,iBAAS,YAAY,mBAAmB;AACtC,cAAI,YAAY,kBAAkB,WAAW;AAC3C,mBAAO,WAAW;AAFkB;AADU;AAMlD,mBAAW,kBAAkB,WAAW,6BACpC;AACJ,eAAO,WAAW;AApCqC;AAuCzD,UAAI,QAAQ,KAAK;AACjB,UAAI,yBAAyB,SAAS,MAAM,QAAQ;AAClD,YAAI,SAAS,WAAyB;AACtC,YAAI,UAAU,KAAK;AACnB,YAAI,UAAU,OAAO,OAAO;AAC5B,iBAAS,WAAW,OAAO;AACzB,qBAAW;AACX,cAAI,OAAO,MAAM;AACjB,cAAI,gBAAgB,4BAAiB,KAAK;AAC1C,cAAI,kBAAkB,4BAAiB,KAAK;AAC5C,cAAI,cAAc,QAAQ,QAAQ;AAClC,cAAI,gBAAgB,QAAQ,QAAQ;AACpC,cAAI,cAAc,KAAK,gBAAgB,GAAG;AACxC;AARuB;AAUzB,cAAI;AACF,eAAG,KAAK,KAAK,OAAO,KAAK,KAAK,KAAK,OAAO,KAAK,OAAO;AACtD,eAAG,KAAK,KAAK,OAAO,KAAK,KAAK,KAAK,OAAO,KAAK,OAAO;AAFrC;AAKnB,cAAI,YAAY,aAAa,SAAS;AACtC,cAAI,CAAC,WAAW;AAGd;AAnBuB;AAqBzB,eAAK,IAAI,IAAI,GAAG,KAAK,UAAU,QAAQ,IAAI,IAAI,KAAK;AAClD,gBAAI,WAAW,UAAU;AAGzB,gBAAI,oBAAoB,WAAW;AACnC,gBAAI,mBAAmB,eAAe,mBACA;AACtC,gBAAI,qBAAqB,eAAe,mBACA;AACxC,oBAAQ;AACN;AACA;AACA;AAHkB;AA9BG;AAJuB;AAyClD,mBAAW,UAAU;AAjFkC;AAoFzD,UAAI,aAAa,IAAK,YAAyB,0CAAsB;AAErE,UAAI,UAAU,IAAI,oBAAoB;AAEtC,cAAQ,SAAS,QAAQ,KAAK;AAE9B,cAAQ,SAAS,QAAQ,eAAe,YACA,WAAW;AAEnD,cAAQ,SAAS,QAAQ,gBAAgB,WAAW,mBACnC;AAEjB,cAAQ,SAAS,QACX,qBACA,qBACA,qBACA,qBACA,aACA,aAAa,cACb,qCACA,qCACA,aACA,aAAa,WAAW,WACxB,aACA,aAAa,WAAW,UACxB,SAAS,WAAW,cAAc,IAAI,KACtC,aACA,aACA,aACA;AAGN,cAAQ,SAAS,QACX,qBACA,aAAa,WAAW,UACxB,aAAa,WAAW,WACxB,aACA,aACA,aACA,aACA,aACA,aAAa,WAAW,aACxB,aAAa,KAAK,IAAI,WAAW,eACpB,WAAW,WACxB,aACA,aACA,aACA,aACA,aACA,aACA,SAAS;AAGf,cAAQ,SAAS,iBAAkB,iBAAiB;AAChD,YAAI,cAAc,KAAK;AACvB,YAAI,YAAY,KAAK,MAAM,KAAK,IAAI,SAAS;AAC7C,YAAI,OAAO;AACX,aAAK,IAAI,IAAI,GAAG,KAAK,WAAW,IAAI,IAAI,KAAK;AAC3C,cAAI,QAAQ;AACZ,cAAI,aAAa;AACf,gBAAI,aAAa,YAAY,IAAI;AACjC,oBAAQ,WAAW,aAAa,WAAW,QAAQ;AAFrD,iBAGO,IAAI,WAAW;AACpB,oBAAQ,KAAK,KAAK,UAAU,MAAM;AANO;AAQ3C,kBAAQ,SAAS,SAAS,SAAS;AAZW;AAchD,eAAO;AAdc,OAAC;AAkB1B,cAAQ,SAAS,QACX,qBACA,SAAS;AAGf,cAAQ,SAAS,QAAQ,gBAAgB;AAGzC,cAAQ,SAAS,QAAQ,gBAAgB;AAEzC,aAAO,QAAQ;AA39CF;AA89Cf,QAAI,aAAa;AACf,UAAI,kBAAkB,MAAM;AAC1B,eAAO,KAAK;AAFC;AAMf,UAAI,4BAA4B,CAAC,SAAS,SAAS,OAAO,KAAK;AAC/D,UAAI;AACJ,WAAK,IAAI,IAAI,GAAG,KAAK,0BAA0B,QAAQ,IAAI,IAAI,KAAK;AAClE,YAAI,YAAY,0BAA0B;AAE1C,YAAI,aAAa,KAAK,QAAQ;AAC5B,kBAAQ,KAAK,OAAO;AACpB;AALgE;AAOlE,YAAI,mBAAmB;AACvB,YAAI,eAAe,iBAAiB;AAEpC,YAAI,WAAW;AACf,YAAI,KAAK,WAAW;AAClB,cAAI,KAAK,KAAK,SAAS,eAAe;AACpC,uBAAW,KAAK,KAAK,OAAO;AAFZ;AAX8C;AAiBlE,YAAI,CAAC,YAAY,KAAK,WAAW;AAC/B,qBAAW,KAAK,UAAU,WAAW;AAlB2B;AAqBlE,YAAI,YAAY,GAAG;AACjB,qBAAW;AAtBqD;AAyBlE,gBAAQ,KAAK,OAAO;AACpB,YAAI,OAAO;AACT;AA3BgE;AARrD;AAsCf,cAAQ,SAAS,KAAK;AAGtB,WAAK,eAAe;AACpB,aAAO;AAxgDM;AA2gDf,iBAAa,SAAS,iBAAiB,UAAU,SAAS;AACxD,UAAI,cAAc,OAAO;AAEzB,UAAI,YAAY;AAChB,UAAI,KAAK,QAAQ,KAAK,KAAK,SAAS,WAAW;AAC7C,oBAAY,KAAK,KAAK,OAAO;AALyB;AAOxD,cAAQ,KAAK,OAAO;AACpB,cAAQ,iBAAM,SAAS,QAAQ,KAAK;AACpC,UAAI,UAAU,KAAK,YAAY,KAAK,SAAS;AAE7C,UAAI,UAAU,KAAK,UAAU,IAAI,aAAa;AAC9C,UAAI,OAAO,YAAY,UAAU;AAC/B,kBAAU,OAAO,aAAa;AAbwB;AAgBxD,UAAI,WAAW,YAAY,KAAK;AAGhC,qBAAe,KAAK,WAAW,aAAa;AAC5C,UAAI,KAAK,aAAa;AACpB,uBAAe,sCAAwB;AArBe;AAwBxD,UAAI,KAAK,aAAa;AAEpB,yBAAiB;AA1BqC;AA6BxD,UAAI,SAAS;AACb,UAAI,KAAK,WAAW,KAAK,QAAQ,WAAW;AAC1C,mBAAW;AACX,YAAI,OAAO,KAAK,QAAQ;AACxB,uBAAe,KAAK;AACpB;AACE,oBAAU,OAAO,aAAa,KAAK;AACnC,kBAAQ,KAAK;AAFN;AAlC6C;AAwCxD,UAAI,WAAW,OAAO,aAAa;AAEnC,UAAI,QAAQ,KAAK,WAAW;AAC5B,UAAI,CAAC,SACD,CAAC,MAAM,gBAAgB,UAAU,SAAS,QAAQ,OAAO,SAClC,gBAAgB,SAAS,WAAW;AAC7D,gBAAQ,IAAI,MAAM,UAAU,SAAS,QAAQ,OAAO,SAClC,gBAAgB,SAAS;AAC3C,aAAK,WAAW,YAAY;AAhD0B;AAkDxD,aAAO;AA7jDM;AAgkDf,mBAAe,SAAS,mBAAmB,OAAO;AAChD,UAAI,aAAa,KAAK;AACtB,UAAI,QAAQ,OAAO;AAGnB,UAAI,YAAY;AACd,iBAAS,WAAW;AACpB,YAAI,QAAQ;AACV,iBAAO;AAHK;AALgC;AAahD,UAAI,CAAC,YAAY;AACf,qBAAa,KAAK,aAAa,OAAO,OAAO;AAdC;AAiBhD,eAAS;AACT,UAAI,gBAAgB;AACpB,UAAI,IAAI;UAAG;AAEX,UAAI,KAAK,MAAM;AAGb,YAAI,IAAI,OAAO,OAAO;AACtB,eAAO,IAAI,MAAM,QAAQ;AACvB,eAAK,KAAK,aAAa,OAAO,GAAG;AACjC,qBAAW,EAAE;AACb,cAAI,SAAS,EAAE;AACf,eAAK;AAEL,cAAI,UAAU,WAAW,KAAK,MAAM,WAAW,IAAI,OAAO;AAC1D,kBAAQ,KAAK,YAAY,UAAU;AACnC,iBAAO,KAAK;AAZD;AAAf,aAcO;AACL,aAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,IAAI,IAAI,EAAE,GAAG;AAC1C,qBAAW,MAAM,WAAW;AAC5B,kBAAQ,KAAK,YAAY,UAAU,aAAa;AAChD,iBAAO,KAAK;AAJT;AAnCyC;AA4ChD,aAAQ,WAAW,iBAAiB;AA5mDvB;AAAA;AAgnDjB,SAAO;AAzyEE,CAAC;AA4yEZ,IAAI,qBAAsB,mBAAmB;AAC3C,WAAS,UAAU,OAAO;AACxB,SAAK,QAAQ;AACb,SAAK,aAAa;AAClB,SAAK,UAAU;AAJ0B;AAO3C,YAAU;AACR,mBAAe,SAAS,0BAA0B;AAChD,aAAO;AAFW;AAIpB,gBAAY,SAAS,uBAAuB;AAC1C,aAAO,EAAE,OAAO,KAAK;AALH;AAAA;AAStB,SAAO;AAhBO,CAAC;AA6BjB,SAAS,sBAAsB,YAAY,iBAAiB,YAAY;AACtE,MAAI,oBAAoB,OAAO,OAAO;AACtC,MAAI,SAAS,UAAU;AACvB,MAAI,iBAAiB,CAAG,aAAW,QAAQ,UAAU;AAErD,MAAI,WAAW,kBAAkB;AAG/B,mBAAe,4BAAY,WAAW;AACtC,SAAK,WAAW,GAAG,WAAW,aAAa,QAAQ,YAAY;AAC7D,gBAAU,WAAW,QAAQ,aAAa;AAC1C,UAAI,WAAW,GAAG;AAChB,0BAAkB,YAAY;AADhC,aAEO;AACL,0BAAkB,YAAY;AAL6B;AAJhC;AAAjC,aAYW,gBAAgB;AAEzB,SAAK,YAAY,iBAAiB;AAChC,wBAAkB,YAAY,gBAAgB;AAHvB;AAApB,SAKA;AAGU;AACf,SAAK,WAAW,GAAG,WAAW,aAAa,QAAQ,YAAY;AAC7D,gBAAU,WAAW,QAAQ,aAAa;AAC1C,UAAI,WAAW,GAAG;AAChB,0BAAkB,YAAY;AADhC,aAEO;AACL,0BAAkB,YAAY;AAL6B;AAJ1D;AAtB+D;AAqCtE,MAAI,cAAc,WAAW;MAAa;AAC1C,MAAI,aAAa;AACf,SAAK,YAAY,aAAa;AAC5B,UAAI,YAAY,YAAY;AAC5B,gBAAU,WAAW,QAAQ;AAE7B,UAAI,YAAY,CAAC,GAAG;AAClB,YAAI,CAAC,kBAAkB;AACrB,6BAAmB;AAFH;AAIlB,YAAI,oBAAoB,iBAAiB,WAAW;AACpD,YAAI,sBAAsB,WAAW;AACnC,oBAAU,WAAW,QAAQ;AANb;AAJQ;AAa5B,UAAI,WAAW,GAAG;AAChB,0BAAkB,YAAY;AADhC,aAEO;AACL,0BAAkB,YAAY;AAhBJ;AADf;AAtCqD;AA2DtE,SAAO;AAr2FT;AAy2FA,IAAI,qBAAsB,mBAAmB;AAC3C,WAAS,UAAU,aAAa,WAAW,YAAY;AACrD,QAAI,oBAAoB,YAAY;AACpC,QAAI,kBAAkB,UAAU;AAChC,QAAI,aAAa,oBAAoB;AAErC,QAAI,IAAI;QAAY;QAAG,QAAQ;AAC/B,WAAO,IAAI,YAAY;AACrB,UAAI;AACJ,aAAO,IAAI,mBAAmB,YAAY,IAAI,OAAO,UAAU,IAAI;AACjE;AAHmB;AAKrB,UAAI,KAAK,iBAAiB;AACxB,aAAK;AACL,eAAO,IAAI,qBAAqB,mBAAQ,YAAY,KAAK;AACvD;AAHsB;AAKxB,gBAAQ;AACR;AAXmB;AAarB;AAnBmD;AAqBrD;AACE;AACA,cAAQ;AAFH;AAtBkC;AA4B3C,WAAS,eAAe,QAAQ,iBAAiB;AAC/C,QAAI,kBAAkB,CAAC,MAAM,MAAM,MAAM,MAAM;AAE/C,QAAI,iBAAiB,OAAO;AAC5B,QAAI,aAAa,mBAAmB;AACpC,QAAI;AACF,oBAAc,OAAO,SAAS;AAC9B,0BAAoB,YAAY;AAFlC,MAGE,OAAO,IAAI;AACX,UAAkB,0CAAsB;AACtC,cAAM;AAFG;AARkC;AAiB/C,QAAI,sBAAsB,iBAAiB;AAKzC,cAAQ,UAAU,aAAa,iBACb,kBAAkB,IAAI,gBAAgB;AAExD,UAAI,MAAM,SAAS,MAAM,WAAW,iBAAiB;AACnD;AACE,kBAAY,mBAAO;AACnB,kBAAQ;AAFH;AATgC;AAjBI;AAgC/C,oBAAK;AACL,WAAO,MAAM;AAEb,QAAI,oBAAoB;AACxB,QAAI;AACJ,WAAO,MAAM;AACX,UAAI,YAAY,OAAO,UAAU;AACjC,cAAQ,UAAU,WAAW,iBAAiB;AAE9C,UAAI,MAAM,WAAW,GAAG;AACtB;AALS;AAOX,aAAO,OAAO,MAAM;AAEpB,UAAI,MAAM,OAAO;AACf,uBAAe,OAAO,MAAM;AAC5B;AAXS;AArCkC;AAmD/C,WAAO,MAAM;AAEb,QAAI,cAAc;AAChB;AACE,gBAAY,mBAAO,OAAO,SAAS;AACnC,gBAAQ;AAFH;AAtDsC;AA2D/C,oBAAK;AACL;AACE,cAAY,mBAAO,OAAO,SAAS;AACnC,cAAQ;AAFH;AAxFkC;AA8F3C,WAAS,cAAc,QAAQ,iBAAiB;AAc9C,QAAI,aAAa,OAAO;AACxB;AACE,cAAY,mBAAO;AACnB,cAAQ,WAAW;AAFd;AA7GkC;AAmH3C,WAAS,UAAU,MAAM,MAAM,YAAY;AAIzC,QAAI,kBAAkB;AACtB,QAAI,oBAAoB,WAAW;AACnC,QAAI,mBAAmB,WAAW;AAClC,QAAI,YAAY,KAAK,UAAU;AAC/B,QAAI,mBAAmB,UAAU,OAAO,QAAQ,UAAU,OAAO;AACjE,QAAI,kBAAkB;AACpB,WAAK,KAAK;AACV,0BAAqB,UAAU,MAAM,KAAO,UAAU,MAAM,KACvC,UAAU,MAAM,IAAK,UAAU;AAZb;AAgBzC,QAAI,cAAc,eAAe,MAAM;AACvC,wBAAoB,YAAY;AAChC,QAAI,oBAAwB,8BAAY,YAAY,QAAQ,OACpB;AACxC,sBAAkB,kBAAkB;AAEpC,QAAI,kBAAkB;AACpB,kBAAY,KAAK,SAAS;AAC1B,yBAAoB,UAAU,MAAM,KAAO,UAAU,MAAM,KACvC,UAAU,MAAM,IAAK,UAAU;AAzBZ;AA6BzC,QAAI,aAAa,cAAc,MAAM;AACrC,uBAAmB,WAAW;AAC9B,QAAI,mBAAuB,8BAAY,WAAW,QAAQ,MACnB;AACvC,QAAI,OAAO,iBAAiB;AAC5B,aAAS,QAAQ,KAAK,YAAY;AAChC,iBAAW,QAAQ,KAAK,WAAW;AAnCI;AAsCzC,QAAI,cAAc,KAAK;AACvB,QAAI,mBAAmB,KAAK,oBAAoB;AAChD,QAAI,QAAQ,KAAK,cAAc,KAAK;AAEpC,SAAK,cAAc;AACnB,SAAK,OAAO,KAAK,KAAK,MAAM,kBAAkB,KAAK,aAC7B,OAAO;AAC7B,SAAK,QAAQ,KAAK,SAAS,KAAK;AAhKS;AAmK3C,YAAU;AACR,QAAI,YAAY;AACd,aAAO,KAAK,YAAY,SAAS;AAFf;AAKpB,gBAAY,SAAS,uBAAuB;AAC1C,UAAI,UAAU,CAAC;AACf,UAAI,cAAc,KAAK;AACvB,WAAK,IAAI,UAAU,GAAG,UAAU,YAAY,QAAQ,WAAW;AAC7D,gBAAQ,KAAK,YAAY,SAAS;AAJM;AAM1C,aAAO;AAXW;AAcpB,qBAAiB,SAAS,0BAA0B,YAAY;AAC9D,UAAI,cAAc,KAAK;AACvB,UAAI,aAAa,CAAC;UAAY;AAC9B,WAAK,UAAU,GAAG,UAAU,YAAY,QAAQ,WAAW;AACzD,mBAAW,KAAK,YAAY,SAAS;AAJuB;AAM9D,UAAI,WAAW,WAAW;AAC1B,UAAI,UAAU;AACZ,YAAI,kBAAkB,OAAO,OAAO;AACpC,iBAAS,YAAY,UAAU;AAC7B,oBAAU,WAAW,QAAQ,SAAS;AACtC,cAAI,WAAW,GAAG;AAChB,4BAAgB,YAAY;AAHD;AAFnB;AAPgD;AAiB9D,aAAO,sBAAsB,YAAY,iBAAiB;AA/BxC;AAkCpB,cAAU,SAAS,mBAAmB,aAAa;AACjD,UAAI,GAAG;AACP,UAAI,UAAU;AACd,WAAK,IAAI,GAAG,KAAK,YAAY,QAAQ,IAAI,IAAI,KAAK;AAChD,YAAI,aAAa,YAAY;AAC7B,YAAI,WAAW,MAAM;AAEnB,kBAAQ,IAAI,KAAK,WAAW;AAJkB;AAHD;AAUjD,aAAO;AA5CW;AA+CpB,yBAAqB,SAAS,8BACE,kBAAkB;AAChD,UAAI,mBAAmB;AACvB,WAAK,IAAI,IAAI,GAAG,KAAK,iBAAiB,QAAQ,IAAI,IAAI,KAAK;AACzD,yBAAiB,KAAK,iBAAiB,GAAG;AAHI;AAKhD,aAAO;AArDW;AAwDpB,mBAAe,SAAS,wBAAwB,YAAY;AAC1D,UAAI,OAAO;AACX,UAAI,QAAQ,WAAW;AACvB,UAAI,QAAQ,MAAM;AAChB,eAAO;AADT,iBAEW,QAAQ,OAAO;AACxB,eAAO;AADF,aAEA;AACL,eAAO;AARiD;AAY1D,UAAI,aAAa;AACjB,UAAI;AACJ,WAAK,IAAI,GAAG,IAAI,MAAM,KAAK;AACzB,mBAAW,KAAK,CAAC;AAfuC;AAkB1D,WAAK,IAAI,GAAG,IAAI,OAAO,KAAK;AAC1B,mBAAW,KAAK,WAAW;AAnB6B;AAsB1D,aAAO;AA9EW;AAiFpB,UAAM,SAAS,eAAe,MAAM,QAAQ,aAAa,OAC3B,YAAY;AACxC,UAAI,MAAU;AACd,UAAI,SAAa,0BAAU,GAAG,GAAG,GAAG;AAEpC,UAAI,QAAQ,CAAC;AAEb,UAAI,UAAc;AAGlB,cAAQ,UAAU,WAAW;AAC7B,cAAQ,UAAU,UAAU;AAC5B,cAAQ,UAAU,YAAY;AAC9B,cAAQ,UAAU,cAAc;AAChC,cAAQ,UAAU,UAAU;AAC5B,cAAQ,UAAU,YAAY;AAC9B,cAAQ,UAAU,cAAc,WAAW;AAC3C,cAAQ,UAAU,YAAY,WAAW;AACzC,cAAQ,UAAU,WAAW;AAC7B,cAAQ,UAAU,eAAe;AACjC,cAAQ,UAAU,WAAW;AAC7B,UAAI,UAAU;AAEd,UAAI,UAAc;AAClB,cAAQ,IAAI;AACZ,cAAQ,IAAI;AACZ,cAAQ,IAAI;AACZ,cAAQ,IAAI;AACZ,cAAQ,IAAI;AACZ,UAAI,UAAU;AAEd,UAAI,kBAAsB;AAE1B,UAAI,QAAQ,OAAO;AACnB,UAAI,eAAe,CAAC;AACpB,UAAI,GAAG;AACP,WAAK,IAAI,GAAG,IAAI,OAAO,KAAK;AAC1B,YAAI,QAAQ,+BAAmB,QAAQ,YAAY,GAAG;AAKtD,YAAI,UAAU,CAAC,GAAG;AAChB,kBAAQ;AAPgB;AAS1B,qBAAa,KAAM,SAAS,IAAK,MAAM,QAAQ;AA5CT;AA8CxC,UAAI,UAAc,2BAAW,OAAO,GAAG,IAAI;AAE3C,UAAI,mBAAuB;AAC3B,uBAAiB,IAAI,CAAC,MAAM;AAC5B,WAAK,IAAI,GAAG,IAAI,OAAO,KAAK;AAC1B,YAAI,QAAQ,OAAO;AAGnB,YAAI,MAAM,WAAW,GAAG;AACtB,2BAAiB,IAAI,CAAC,MAAM;AAC5B;AANwB;AAQ1B,yBAAiB,IAAI;AA1DiB;AA4DxC,UAAI,cAAc;AAElB,UAAI,cAAkB;AACtB,kBAAY,UAAU,SAAS;AAC/B,UAAI,SAAS,CACX,cACA,cACA,eACA,oBACA,aACA,aACA,aACA,YACA,aACA,iBACA,mBACA,aACA,SACA;AAEF,WAAK,IAAI,GAAG,KAAK,OAAO,QAAQ,IAAI,IAAI,KAAK;AAC3C,YAAI,QAAQ,OAAO;AACnB,YAAM,WAAS,WAAW,cAAc;AACtC;AAHyC;AAK3C,YAAI,QAAQ,WAAW,YAAY;AACnC,YAAI,mBAAQ,QAAQ;AAGlB,eAAK,IAAI,IAAI,MAAM,SAAS,GAAG,IAAI,GAAG,KAAK;AACzC,kBAAM,MAAM,MAAM,IAAI;AAJN;AANuB;AAa3C,oBAAY,UAAU,OAAO;AA7FS;AA+FxC,UAAI,QAAQ,cAAc;AAE1B,UAAI,YAAgB;AACpB,WAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,IAAI,IAAI,KAAK;AAC1C,kBAAU,IAAI,MAAM;AAnGkB;AAqGxC,kBAAY,aAAa;AAEzB,UAAI,WAAe,4BAAY;AAC/B,aAAO,SAAS;AA1LE;AAAA;AA8LtB,SAAO;AAjWO,CAAC;AAoWjB,IAAI,mBAAoB,iBAAiB;AACvC,WAAS,QAAQ,MAAM,YAAY;AACjC,SAAK,aAAa;AAElB,QAAI,SAAa,0BAAU,MAAM,YAAY;AAC7C,SAAK,MAAM,OAAO;AAClB,QAAI,WAAe,4BAAY,KAAK;AACpC,SAAK,QAAQ,KAAK,IAAI;AACtB,QAAI;AACF,WAAK,OAAO,SAAS;AADvB,MAEE,OAAO,GAAG;AACV,sBAAK,4BAA4B,WAAW;AAG5C,WAAK,OAAO;AAbmB;AADI;AAkBvC,UAAQ;AACN,QAAI,YAAY;AACd,aAAO,KAAK,IAAI,YAAY;AAFZ;AAIlB,gBAAY,SAAS,qBAAqB;AACxC,aAAO,KAAK,IAAI,QAAQ;AALR;AAOlB,qBAAiB,SAAS,0BAA0B;AAClD,UAAI,MAAM,KAAK;AACf,UAAI,aAAa,KAAK;AACtB,UAAI,WAAW,IAAI,QAAQ;AAC3B,UAAI;AACJ,UAAI;AAEJ,UAAI,WAAW,WAAW;AACxB,4BAAoB,OAAO,OAAO;AAClC,YAAI,IAAI,WAAW;AAGjB,eAAK,UAAU,GAAG,UAAU,SAAS,QAAQ,WAAW;AACtD,gBAAI,MAAM,SAAS;AACnB,gBAAI,WAAW,WAAW,KAAK,WAAW;AAC1C,8BAAkB,YAAY;AANf;AAAnB,eAQO;AAGL,eAAK,UAAU,GAAG,UAAU,IAAI,YAAY,OAAO,WAAW;AAC5D,8BAAkB,WAAW;AAJ1B;AAViB;AAiBxB,eAAO;AAxByC;AA2BlD,UAAI,WAAW,IAAI,WAAW,IAAI,SAAS,WAAW;AACtD,0BAAoB,sBAAsB,YAAY,UAAU;AAChE,aAAO;AApCS;AAAA;AAwCpB,SAAO;AA1DK,CAAC;AA8Dd,UAAS,mBAAmB;AAC3B,MAAI,OAAO,cAAc,eAAe,UAAU,KAAK,UAAU,YAAY;AAC3E,4DAAwB;AAFC;AAA7B;AASC,UAAS,qBAAqB;AAC7B,MAAI,OAAO,cAAc,eACrB,kBAAkB,KAAK,UAAU,YAAY;AAC/C,0CAAsC;AAHX;AAO/B,IAPA;QAQE;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,0B;;;;;;;;;;;;;;ACpxGK;;AACkC;;AACV;;AACJ;;AACF;;AAEzB,IAAI,oBAAqB,kBAAkB;AAKzC,WAAS,gBAAgB,OAAO,eAAe;AAC7C,QAAI,iBAAiB,cAAc,UAAU,QAAQ;AACnD,aAAO,cAAc,OAAO;AAFe;AAI7C,WAAO,QAAQ,QAAQ;AATgB;AAgBzC,WAAS,eAAe,OAAO,QAAQ,aAAa,KAAK;AACvD,YAAQ,SAAS,QAAQ;AAEzB,WAAQ,QAAQ,IAAI,IAAK,QAAQ,MAAM,MAAM;AAnBN;AAgCzC,WAAS,gBAAgB,KAAK,KAAK,IAAI,IAAI,IAAI,IAAI;AACjD,QAAI,SAAS,KAAK;AAClB,QAAI,OAAQ,OAAO,IAAI,IAAI,WAAW,UACnC,OAAO,KAAK,IAAI,YAAY,UAAU,IAAI,YAAY;AACzD,QAAI,SAAS,KAAK;AAClB,QAAI,SAAS,KAAK;AAClB,QAAI;QAAG;QAAG;QAAI,WAAW;QAAG;AAC5B,QAAI,UAAU,IAAI,YAAY;AAC9B,QAAI,aAAa;AAEjB,SAAK,IAAI,GAAG,IAAI,IAAI,KAAK;AACvB,cAAQ,KAAK,KAAK,MAAM,IAAI;AAXmB;AAajD,SAAK,IAAI,GAAG,IAAI,IAAI,KAAK;AACvB,WAAK,KAAK,MAAM,IAAI,UAAU;AAC9B,WAAK,IAAI,GAAG,IAAI,IAAI,KAAK;AACvB,mBAAW,KAAK,QAAQ;AACxB,aAAK,cAAc,IAAI;AAJF;AAbwB;AAoBjD,WAAO;AApDgC;AAuDzC,WAAS,SAAS,MAAM,KAAK,OAAO,QAAQ,OAAO,MAAM,QAAQ;AAC/D,SAAK,QAAQ;AACb,QAAI,OAAO,MAAM;AACjB,QAAI,KAAK,IAAI,WAAW;AACtB,UAAI,SAAS,KAAK,IAAI,UAAU;AAChC,UAAI,WAAW,aAAa;AAC1B,YAAI,WAAe;AACnB,iBAAS,qBAAqB,MAAM;AACpC,cAAM,OAAO;AACb,cAAM,mBAAmB,SAAS;AAClC,cAAM,WAAW,SAAS;AAL5B,aAMO,IAAI,WAAW,eAAe;AACnC,cAAM,mBAAmB;AACzB,cAAM,WAAW;AAVG;AAHuC;AAkB/D,SAAK,QAAQ,KAAK,IAAI,SAAS;AAC/B,SAAK,SAAS,KAAK,IAAI,UAAU;AAEjC,QAAI,KAAK,QAAQ,KAAK,KAAK,SAAS,GAAG;AACrC,YAAU,sBAAa,0BAAuB,KACvB,+BAAU,KAAK;AAvBuB;AA0B/D,SAAK,cAAc,KAAK,IAAI,eAAe,QAAQ;AACnD,SAAK,YAAY,KAAK,IAAI,aAAa,SAAS;AAChD,SAAK,QAAQ,KAAK,IAAI,YAAY;AAElC,QAAI,mBAAmB,MAAM;AAC7B,QAAI,CAAC,kBAAkB;AACrB,yBAAmB,KAAK,IAAI,oBAAoB;AAChD,UAAI,CAAC,kBAAkB;AACrB,YAAI,KAAK,WAAW;AAClB,6BAAmB;AADrB,eAEO;AACL,gBACG,gEAAuC,KAAK;AAL5B;AAFF;AA/BwC;AA0C/D,SAAK,MAAM;AAEX,QAAI,CAAC,KAAK,WAAW;AACnB,UAAI,aAAa,KAAK,IAAI,cAAc;AACxC,UAAI,CAAC,YAAY;AACf,wBAAK;AACL,gBAAQ,MAAM;AACZ,eAAK;AACH,yBAAa,iBAAK,IAAI;AACtB;AACF,eAAK;AACH,yBAAa,iBAAK,IAAI;AACtB;AACF,eAAK;AACH,yBAAa,iBAAK,IAAI;AACtB;AACF;AACE,kBAAM,IAAI,MAAO,qBAAkB,KAAc,iBACjC;;AAhBH;AAmBnB,WAAK,aAAa,uBAAW,MAAM,YAAY,MAAM;AACrD,WAAK,WAAW,KAAK,WAAW;AAhE6B;AAmE/D,SAAK,SAAS,KAAK,SAAS,UAAU;AACtC,SAAK,cAAc;AACnB,QAAI,KACC,WAAC,KAAK,cAAc,CAAC,KAAK,WAAW,gBAAgB,KAAK,WACzD,UAAU,CAAC,uBAAW,gBAAgB,KAAK,QAAQ,KAAM;AAC7D,WAAK,cAAc;AAEnB,UAAI,MAAO,MAAK,oBAAoB;AACpC,WAAK,qBAAqB;AAC1B,WAAK,gBAAgB;AACrB,WAAK,IAAI,IAAI,GAAG,IAAI,GAAG,IAAI,KAAK,OAAO,QAAQ,KAAK,GAAG,EAAE,GAAG;AAC1D,YAAI,OAAO,KAAK,OAAO;AACvB,YAAI,OAAO,KAAK,OAAO,IAAI;AAC3B,aAAK,mBAAmB,KAAK,OAAO;AACpC,aAAK,cAAc,KAAK,MAAM;AAV6B;AAvEA;AAqF/D,QAAI,OAAO;AACT,WAAK,QAAQ,IAAI,SAAS,MAAM,KAAK,OAAO;AAD9C,WAEO,IAAI,MAAM;AACf,UAAI,0BAAS,OAAO;AAClB,YAAI,WAAW,KAAK;YAAM,YAAY,SAAS,IAAI,aAAa;AAChE,YAAI,CAAC,WAAW;AACd,0BAAK;AADP,eAEO;AACL,eAAK,OAAO,IAAI,SAAS,MAAM,KAAK,MAAM,OAAO,MAAM,MAAM;AAL7C;AAApB,aAOO;AAEL,aAAK,OAAO;AAVC;AAvF8C;AAvDxB;AAgKzC,WAAS,aAAa,SAAS,oBAAoB,SAAS,MACT,KAAK,OAAO,QACZ,eAAe;AAChE,QAAI,eAAe,gBAAgB,OAAO;AAC1C,QAAI;AACJ,QAAI;AAEJ,QAAI,QAAQ,MAAM,KAAK,IAAI;AAC3B,QAAI,OAAO,MAAM,KAAK,IAAI;AAE1B,QAAI,OAAO;AACT,qBAAe,gBAAgB,OAAO;AACtC,oBAAc,QAAQ,QAAQ;AAFhC,WAGO;AACL,qBAAe,QAAQ,QAAQ;AAC/B,UAAI,MAAM;AACR,YAAI,0BAAS,OAAO;AAClB,wBAAc,gBAAgB,MAAM;AADtC,mBAEW,mBAAQ,OAAO;AACxB,wBAAc,QAAQ,QAAQ;AADzB,eAEA;AACL,0BAAK;AACL,wBAAc,QAAQ,QAAQ;AAPxB;AAAV,aASO;AACL,sBAAc,QAAQ,QAAQ;AAZ3B;AAXyD;AA0BhE,mBAAe,IAAI,CAAC,cAAc,cAAc,cAAc,KAC5D,UAAS,SAAS;AAChB,UAAI,YAAY,QAAQ;AACxB,UAAI,YAAY,QAAQ;AACxB,UAAI,WAAW,QAAQ;AACvB,aAAO,IAAI,SAAS,MAAM,KAAK,WAAW,QAAQ,WAAW;AAL1D;AA5BT;AAqCA,WAAS,aACL,SAAS,oBAAoB,UAAU,OAAO,QACjB,yBAAyB,eAAe;AAOvE,QAAI,iBAAkB,CAAC,QAAQ,KAAM,KAAK;AAC1C,QAAI,eAAe,SAAS;AAC5B,QAAI,eAAe,mBAAmB;AACtC,QAAI,MAAM;AAEV,QAAgC,6BAAC,iBAAiB,eAAe;AAG/D,aAAO;AAHT,eAIW,CAAC,eAAe;AACzB,aAAO,IAAI,WAAW;AACtB,WAAK,IAAI;AAFJ,WAGA;AACL,aAAO,IAAI,WAAW;AACtB,WAAK,IAAI;AACT,WAAK,IAAI,cAAc,IAAI,gBAAgB,KAAK;AAC9C,aAAK,KAAK;AAJP;AAnBgE;AA+BvE,QAAI,eAAe;AACjB,WAAK,IAAI,GAAG,IAAI,cAAc,KAAK;AACjC,aAAK,KAAK,CAAC,KAAK;AAFD;AA/BoD;AAqCvE;AAAS;AAAM;AAAO;AAAf;AAvCT;AA0CA,WAAS;AACP,QAAI,YAAY;AACd,aAAO,KAAK,IAAI,KAAK,OACL,KAAK,SAAS,KAAK,MAAM,SAAS,GAClC,KAAK,QAAQ,KAAK,KAAK,SAAS;AAJ/B;AAOnB,QAAI,aAAa;AACf,aAAO,KAAK,IAAI,KAAK,QACL,KAAK,SAAS,KAAK,MAAM,UAAU,GACnC,KAAK,QAAQ,KAAK,KAAK,UAAU;AAVhC;AAanB,kBAAc,SAAS,sBAAsB,QAAQ;AACnD,UAAI,MAAM,KAAK;AACf,UAAI,WAAW,KAAK;AAEpB,UAAI,gBAAgB,KAAK;AACzB,UAAI,qBAAqB,KAAK;AAC9B,UAAI,MAAO,MAAK,OAAO;AACvB,UAAI,GAAG;AAEP,UAAI,QAAQ,GAAG;AAEb,aAAK,IAAI,GAAG,KAAK,OAAO,QAAQ,IAAI,IAAI,KAAK;AAC3C,iBAAO,KAAK,CAAC,CAAE,OAAO;AAHX;AAKb;AAdiD;AAgBnD,UAAI,QAAQ;AACZ,WAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,KAAK,QAAQ,IAAI,IAAI,KAAK;AACtD,aAAK,IAAI,IAAI,GAAG,IAAI,UAAU,KAAK;AACjC,iBAAO,SAAS,eAAe,OAAO,QAAQ,cAAc,IAC7B,mBAAmB,IAAI;AACtD;AAJoD;AAjBL;AAblC;AAuCnB,mBAAe,SAAS,uBAAuB,QAAQ;AACrD,UAAI,MAAM,KAAK;AAGf,UAAI,QAAQ,GAAG;AACb,eAAO;AAL4C;AAQrD,UAAI,QAAQ,KAAK;AACjB,UAAI,SAAS,KAAK;AAClB,UAAI,WAAW,KAAK;AAEpB,UAAI,SAAS,QAAQ,SAAS;AAC9B,UAAI,YAAY;AAChB,UAAI,SAAU,OAAO,IAAI,IAAI,WAAW,UACrC,OAAO,KAAK,IAAI,YAAY,UAAU,IAAI,YAAY;AACzD,UAAI,WAAW,QAAQ;AAEvB,UAAI,MAAO,MAAK,OAAO;AACvB,UAAI,IAAI;UAAG;UAAI;AAEf,UAAI,QAAQ,GAAG;AAEb,YAAI,MAAM,UAAU;AACpB,aAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,qBAAgB,gBAAW,CAAC;AAC5B,qBAAW,IAAI;AAGf,iBAAO,IAAI,UAAU;AACnB,kBAAM,OAAO;AACb,mBAAO,KAAM,OAAO,IAAK;AACzB,mBAAO,IAAI,KAAM,OAAO,IAAK;AAC7B,mBAAO,IAAI,KAAM,OAAO,IAAK;AAC7B,mBAAO,IAAI,KAAM,OAAO,IAAK;AAC7B,mBAAO,IAAI,KAAM,OAAO,IAAK;AAC7B,mBAAO,IAAI,KAAM,OAAO,IAAK;AAC7B,mBAAO,IAAI,KAAM,OAAO,IAAK;AAC7B,mBAAO,IAAI,KAAK,MAAM;AACtB,iBAAK;AAfwB;AAmB/B,cAAI,IAAI,UAAU;AAChB,kBAAM,OAAO;AACb,mBAAO;AACP,mBAAO,IAAI,UAAU;AACnB,qBAAO,OAAO,CAAC,CAAG,QAAM;AACxB,uBAAS;AALK;AAnBa;AAHpB;AAAf,aA+BO;AAEL,YAAI,OAAO;AACX,cAAM;AACN,aAAK,IAAI,GAAG,KAAK,QAAQ,IAAI,IAAI,EAAE,GAAG;AACpC,cAAI,IAAI,aAAa,GAAG;AACtB,kBAAM;AACN,mBAAO;AAH2B;AAMpC,iBAAO,OAAO,KAAK;AACjB,kBAAO,OAAO,IAAK,OAAO;AAC1B,oBAAQ;AAR0B;AAWpC,cAAI,gBAAgB,OAAO;AAC3B,cAAI,QAAQ,OAAO;AACnB,iBAAO,KAAM,QAAQ,IAAI,IAAK,QAAQ,MAAM,MAAM;AAClD,gBAAM,MAAQ,MAAK,iBAAiB;AACpC,iBAAO;AAnBJ;AApD8C;AA0ErD,aAAO;AAjHU;AAoHnB,iBAAa,SAAS,qBAAqB,SAAS,OAAO,QAChB,cAAc,OAAO;AAC9D,UAAI,QAAQ,KAAK;AACjB,UAAI,OAAO,KAAK;AAChB,UAAI,UAAU,IAAI,IAAI,GAAG,IAAI;AAE7B,UAAI,OAAO;AACT,aAAK,MAAM;AACX,aAAK,MAAM;AACX,mBAAW,IAAI,WAAW,KAAK;AAC/B,cAAM,eAAe;AACrB,YAAI,OAAO,SAAS,OAAO,QAAQ;AACjC,qBAAW,gBAAgB,UAAU,MAAM,KAAK,IAAI,IACzB,OAAO;AAP3B;AAAX,aASO,IAAI,MAAM;AACf,YAAI,gBAAgB,UAAU;AAC5B,eAAK,KAAK;AACV,eAAK,KAAK;AACV,qBAAW,IAAI,WAAW,KAAK;AAC/B,eAAK,WAAW;AAChB,eAAK,eAAe;AAGpB,eAAK,IAAI,GAAG,KAAK,KAAK,IAAI,IAAI,IAAI,EAAE,GAAG;AACrC,qBAAS,KAAK,MAAM,SAAS;AATH;AAY5B,cAAI,OAAO,SAAS,OAAO,QAAQ;AACjC,uBAAW,gBAAgB,UAAU,KAAK,KAAK,IAAI,IACxB,OAAO;AAdR;AAA9B,mBAgBW,mBAAQ,OAAO;AAGxB,qBAAW,IAAI,WAAW,QAAQ;AAClC,cAAI,WAAW,KAAK;AACpB,eAAK,IAAI,GAAG,KAAK,QAAQ,QAAQ,IAAI,IAAI,EAAE,GAAG;AAC5C,gBAAI,UAAU;AACd,gBAAI,cAAc,IAAI;AACtB,iBAAK,IAAI,GAAG,IAAI,UAAU,EAAE,GAAG;AAC7B,kBAAI,QAAQ,MAAM,cAAc;AAChC,kBAAI,aAAa,IAAI;AACrB,kBAAI,QAAQ,KAAK,eAAe,QAAQ,KAAK,aAAa,IAAI;AAC5D,0BAAU;AACV;AAL2B;AAHa;AAW5C,qBAAS,KAAK;AAhBQ;AAAnB,eAkBA;AACL,gBAAU,sBAAY;AApCT;AAd6C;AAsD9D,UAAI,UAAU;AACZ,aAAK,IAAI,GAAG,IAAI,GAAG,KAAK,QAAQ,cAAc,IAAI,IAAI,EAAE,GAAG,KAAK,GAAG;AACjE,kBAAQ,KAAK,SAAS;AAFZ;AAAd,aAIO;AAEL,aAAK,IAAI,GAAG,IAAI,GAAG,KAAK,QAAQ,cAAc,IAAI,IAAI,EAAE,GAAG,KAAK,GAAG;AACjE,kBAAQ,KAAK;AAHV;AA1DuD;AArH7C;AAuLnB,kBAAc,SAAS,sBAAsB,QAAQ,OAAO,QAAQ;AAClE,UAAI,QAAQ,KAAK,SAAS,KAAK,MAAM;AACrC,UAAI,CAAC,OAAO;AACV;AAHgE;AAKlE,UAAI,WAAW,KAAK,WAAW,OAAO,OAAO;AAC7C,UAAI,SAAS,SAAS;AACtB,UAAI,SAAS,SAAS;AACtB,UAAI,SAAS,SAAS;AACtB,UAAI,SAAS,QAAQ,SAAS;AAC9B,UAAI,GAAG,GAAG;AACV,WAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK,GAAG;AAClC,YAAI,QAAQ,OAAO,IAAI;AACvB,YAAI,UAAU,GAAG;AAGf,iBAAO,KAAK;AACZ,iBAAO,IAAI,KAAK;AAChB,iBAAO,IAAI,KAAK;AAChB;AARgC;AAUlC,YAAI,IAAI,MAAM;AACd,YAAK,QAAO,KAAK,UAAU,IAAI;AAC/B,YAAK,QAAO,IAAI,KAAK,UAAU,IAAI;AACnC,YAAK,QAAO,IAAI,KAAK,UAAU,IAAI;AACnC,eAAO,KAAK,KAAK,IAAI,IAAI,KAAK,MAAM,MAAM,IAAI;AAC9C,eAAO,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,MAAM,MAAM,IAAI;AAClD,eAAO,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,MAAM,MAAM,IAAI;AA3Bc;AAvLjD;AAsNnB,qBAAiB,SAAS,yBAAyB,WAAW;AAC5D,UAAI,YAAY,KAAK;AACrB,UAAI,aAAa,KAAK;AACtB,UAAI;AACF,eAAO;AACP,gBAAQ;AAFI;AAKd,UAAI,WAAW,KAAK;AACpB,UAAI,gBAAgB,KAAK;AACzB,UAAI,iBAAiB,KAAK;AAC1B,UAAI,MAAM,KAAK;AAGf,UAAI,WAAY,gBAAgB,WAAW,MAAM,KAAM;AACvD,UAAI;AAEJ,UAAI,CAAC,WAAW;AAQd,YAAI;AACJ,YAAI,KAAK,WAAW,SAAS,gBAAgB,QAAQ,GAAG;AACtD,iBAAO,gBAAU;AADnB,eAEO,IAAI,KAAK,WAAW,SAAS,eAAe,QAAQ,KAChD,CAAC,KAAK,aAAa;AAC5B,iBAAO,gBAAU;AAbL;AAed,YAAI,QAAQ,CAAC,KAAK,SAAS,CAAC,KAAK,QAC7B,cAAc,iBAAiB,eAAe,gBAAgB;AAChE,kBAAQ,OAAO;AAEf,qBAAW,KAAK,cAAc,iBAAiB;AAM/C,cAAI,KAAsB,uCAAc;AACtC,oBAAQ,OAAO;AADjB,iBAEO;AACL,gBAAI,WAAW,IAAI,WAAW,SAAS;AACvC,qBAAS,IAAI;AACb,oBAAQ,OAAO;AAd+C;AAgBhE,cAAI,KAAK,aAAa;AAEpB,8BAAO,SAAS,gBAAU;AAC1B,gBAAI,SAAS,QAAQ;AACrB,iBAAK,IAAI,IAAI,GAAG,KAAK,OAAO,QAAQ,IAAI,IAAI,KAAK;AAC/C,qBAAO,MAAM;AALK;AAhB0C;AAwBhE,iBAAO;AAxCK;AA0Cd,YAAI,KAAsB,uCAAc,CAAC,KAAK,SAAS,CAAC,KACnD,cAAK,WAAW,SAAS,gBACzB,KAAK,WAAW,SAAS,eACzB,KAAK,WAAW,SAAS,eAAe;AAC3C,kBAAQ,OAAO,gBAAU;AACzB,kBAAQ,OAAO,KAAK,cAAc,iBAAiB,UACjB,WAAW,YAAY;AACzD,iBAAO;AAjDK;AAjB4C;AAsE5D,iBAAW,KAAK,cAAc,iBAAiB;AAE/C,UAAI,eAAe,IAAK,SAAS,SAAS,WACvB,aAAa;AAEhC,UAAI,QAAQ,KAAK,cAAc;AAI/B,UAAI,SAAS;AACb,UAAI,CAAC,aAAa,CAAC,KAAK,SAAS,CAAC,KAAK,MAAM;AAC3C,gBAAQ,OAAO,gBAAU;AACzB,gBAAQ,OAAO,IAAI,WAAW,YAAY,aAAa;AACvD,kBAAU;AACV,4BAAoB;AAJtB,aAKO;AACL,gBAAQ,OAAO,gBAAU;AACzB,gBAAQ,OAAO,IAAI,WAAW,YAAY,aAAa;AACvD,kBAAU;AACV,4BAAoB;AAGpB,aAAK,YAAY,QAAQ,MAAM,WAAW,YAAY,cACrC;AA7FyC;AAgG5D,UAAI,KAAK,aAAa;AACpB,aAAK,aAAa;AAjGwC;AAmG5D,WAAK,WAAW,QAAQ,QAAQ,MAAM,eAAe,gBAC7B,WAAW,YAAY,cAAc,KAAK,OAC1C;AACxB,UAAI,mBAAmB;AACrB,aAAK,aAAa,QAAQ,MAAM,WAAW;AAvGe;AA0G5D,aAAO;AAhUU;AAmUnB,oBAAgB,SAAS,wBAAwB,QAAQ;AACvD,UAAI,WAAW,KAAK;AACpB,UAAI,aAAa,GAAG;AAClB,cACG,kEAAyC;AAJS;AAOvD,UAAI,QAAQ,KAAK;AACjB,UAAI,SAAS,KAAK;AAClB,UAAI,MAAM,KAAK;AAGf,UAAI,WAAY,QAAQ,WAAW,MAAM,KAAM;AAC/C,UAAI,WAAW,KAAK,cAAc,SAAS;AAE3C,UAAI,QAAQ,KAAK,cAAc;AAC/B,UAAI,GAAG;AAEP,UAAI,QAAQ,GAAG;AAEb,iBAAS,QAAQ;AACjB,YAAI,KAAK,aAAa;AAEpB,eAAK,IAAI,GAAG,IAAI,QAAQ,EAAE,GAAG;AAC3B,mBAAO,KAAM,MAAM,KAAK,IAAK;AAHX;AAAtB,eAKO;AAEL,eAAK,IAAI,GAAG,IAAI,QAAQ,EAAE,GAAG;AAC3B,mBAAO,KAAM,CAAC,MAAM,KAAM;AAHvB;AARM;AAcb;AAhCqD;AAmCvD,UAAI,KAAK,aAAa;AACpB,aAAK,aAAa;AApCmC;AAsCvD,eAAS,QAAQ;AAEjB,UAAI,QAAe,OAAC,MAAK,OAAO;AAChC,WAAK,IAAI,GAAG,IAAI,QAAQ,EAAE,GAAG;AAC3B,eAAO,KAAM,QAAQ,MAAM,KAAM;AA1CoB;AAnUtC;AAiXnB,mBAAe,SAAS,uBAAuB,QACA,WAAW,YACX,UAAU;AACvD,WAAK,MAAM;AACX,WAAK,MAAM,YAAY,aAAa,KAAK;AACzC,WAAK,MAAM,aAAa,cAAc,KAAK;AAC3C,WAAK,MAAM,WAAW,CAAC,CAAC;AACxB,aAAO,KAAK,MAAM,SAAS;AAxXV;AAAA;AA2XrB,SAAO;AAGT,CA7mBgB;QA8mBd,oB;;;;;;;;;;;;;;ACpnBK;;AAC2B;;AAElC,IAAI,sBAAuB,oBAAoB;AAC7C,WAAS,WAAW,KAAK;AACvB,SAAK,UAAU,kBAAkB;AAFU;AAK7C,aAAW,YAAY,IAAI;AAC3B,aAAW,UAAU,OAAO;AAC5B,aAAW,cAAc;AAEzB,SAAO;AATQ,CAAC;AAYlB,IAAI,sBAAuB,oBAAoB;AAE7C,WAAS,eAAe,CAFqB;AAI7C,eAAa;AACX,sCAAY,IAAI;AACd,UAAI,MAAM,MAAM;AACd,eAAO,KAAK;AAFA;AAId,aAAQ,KAAK,MAAM,IAAI,UAAU,KAAK;AALjB;AAAA;AASzB,WAAS,gBAAgB,MAAM,OAAO,KAAK;AACzC,SAAK,OAAO;AACZ,SAAK,QAAQ;AACb,SAAK,MAAM;AAhBgC;AAmB7C,kBAAgB;AACd,QAAI,UAAU;AACZ,UAAI,UAAc,0CAAkB,KAAK,MAAM,KAAK,OAAO,KAAK;AAChE,aAAO,kBAAO,MAAM,WAAW;AAHP;AAK1B,QAAI,eAAe;AACjB,UAAI,QAAQ,IAAI;AAChB,aAAO,kBAAO,MAAM,gBAAgB;AAPZ;AAAA;AAa5B,WAAS,cAAc,cAAc,WAAW,SAAS;AACvD,QAAI,WAAW,aAAa,YAAY;AACxC,QAAI,OAAO;AAEX,aAAS,SAAS,QAAQ;AACxB,UAAI,IAAI;AACR,WAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,YAAI,MAAM,QAAQ,QAAQ,UAAU;AACpC,eAAQ,OAAO,MAAO,QAAQ,IAAK,MACzB,CAAC,QAAQ,IAAK,OAAO,MAAO;AACtC,YAAK,KAAK,IAAK;AANO;AAQxB,aAAO,MAAM;AAZwC;AAevD,QAAI,OAAO,SAAS;AACpB,QAAI,QAAQ,SAAS,KACN,SAAS,KACP,SAAS,KACP,SAAS,KACP,SAAS,KACP,SAAS,MAAM,OAClB,SAAS,MAAM,MACjB,SAAS,KAAK,KAChB,SAAS,KAAK,KAChB,SAAS,KAAK,IAChB,SAAS;AACrB,WAAQ,SAAS,IAAI,QAAS,QAAQ,IAAI,CAAC,QAAQ;AA3DR;AA+D7C,WAAS,WAAW,cAAc,SAAS,YAAY;AACrD,QAAI,WAAW,aAAa,YAAY;AAExC,QAAI,OAAO;AACX,SAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAAK;AACnC,UAAI,MAAM,QAAQ,QAAQ,UAAU;AACpC,aAAQ,QAAQ,IAAK;AAN8B;AAQrD,QAAI,aAAa,IAAI;AACnB,aAAO,OAAS,MAAK,cAAc;AATgB;AAWrD,WAAO,OAAO;AA1E6B;AA8E7C,MAAI,eAAe,CACjB,oBAAoB,MAAM,MAAM,MAAM,0BAA0B,MAChE,uBAAuB,+BAA+B,MAAM,MAAM,MAClE,MAAM,MAAM,MAAM,MAAM,MAAM,qBAAqB,MAAM,MAAM,MAC/D,8BAA8B,MAAM,2BACpC,mCAAmC,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MACvE,MAAM,MAAM,MAAM,MAAM,MAAM,6BAA6B,MAC3D,0BAA0B,kCAC1B,uCAAuC,MACvC,oCACA,4CAA4C,MAAM,MAAM,MAAM,MAC9D,mBAAmB,aAAa,eAAe,aAAa,YAC5D,UAAU,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MACpD;AAGF,MAAI;AACC,OAAG,CAAC;AAAG,OAAG,CAAC;AAAb,GAAD;AAAsB,OAAG;AAAG,OAAG,CAAC;AAAZ;AAAoB,OAAG;AAAG,OAAG,CAAC;AAAZ;AAAoB,OAAG,CAAC;AAAG,OAAG,CAAC;AAAb;AACrD,OAAG,CAAC;AAAG,OAAG,CAAC;AAAb;AAAqB,OAAG;AAAG,OAAG,CAAC;AAAZ;AAAoB,OAAG;AAAG,OAAG,CAAC;AAAZ;AAAoB,OAAG;AAAG,OAAG,CAAC;AAAZ;AACrD,OAAG,CAAC;AAAG,OAAG;AAAZ;AAAoB,OAAG,CAAC;AAAG,OAAG;AAAZ;AAAoB,OAAG,CAAC;AAAG,OAAG;AAAZ;AAAoB,OAAG,CAAC;AAAG,OAAG;AAAZ,IAHnC;AAIjB,OAAG,CAAC;AAAG,OAAG,CAAC;AAAb,GAAD;AAAsB,OAAG;AAAG,OAAG,CAAC;AAAZ;AAAoB,OAAG;AAAG,OAAG,CAAC;AAAZ;AAAoB,OAAG;AAAG,OAAG,CAAC;AAAZ;AACrD,OAAG,CAAC;AAAG,OAAG,CAAC;AAAb;AAAqB,OAAG,CAAC;AAAG,OAAG,CAAC;AAAb;AAAqB,OAAG;AAAG,OAAG,CAAC;AAAZ;AAAoB,OAAG;AAAG,OAAG,CAAC;AAAZ;AACtD,OAAG;AAAG,OAAG,CAAC;AAAZ;AAAoB,OAAG,CAAC;AAAG,OAAG;AAAZ;AAAoB,OAAG,CAAC;AAAG,OAAG;AAAZ;AAAoB,OAAG,CAAC;AAAG,OAAG;AAAZ;AACpD,OAAG,CAAC;AAAG,OAAG,CAAC;AAAb,GAAD;AAAsB,OAAG;AAAG,OAAG,CAAC;AAAZ;AAAoB,OAAG;AAAG,OAAG,CAAC;AAAZ;AAAoB,OAAG,CAAC;AAAG,OAAG,CAAC;AAAb;AACrD,OAAG,CAAC;AAAG,OAAG,CAAC;AAAb;AAAqB,OAAG;AAAG,OAAG,CAAC;AAAZ;AAAoB,OAAG;AAAG,OAAG,CAAC;AAAZ;AAAoB,OAAG,CAAC;AAAG,OAAG;AAAZ;AACrD,OAAG,CAAC;AAAG,OAAG;AAAZ;AACE,OAAG,CAAC;AAAG,OAAG,CAAC;AAAb,GAAD;AAAsB,OAAG,CAAC;AAAG,OAAG,CAAC;AAAb;AAAqB,OAAG,CAAC;AAAG,OAAG,CAAC;AAAb;AAAqB,OAAG;AAAG,OAAG,CAAC;AAAZ;AACvD,OAAG;AAAG,OAAG,CAAC;AAAZ;AAAoB,OAAG,CAAC;AAAG,OAAG;AAAZ;AAAoB,OAAG,CAAC;AAAG,OAAG;AAAZ;AAAoB,OAAG,CAAC;AAAG,OAAG;AAAZ;AACpD,OAAG,CAAC;AAAG,OAAG;AAAZ;AAGH,MAAI;AAEA;AAAW,SAAG;AAAG,SAAG,CAAC;AAAZ,KAAD;AAAqB,SAAG;AAAG,SAAG,CAAC;AAAZ;AAAoB,SAAG,CAAC;AAAG,SAAG;AAAZ;AAC7C;AAAc,SAAG;AAAG,SAAG,CAAC;AAAZ,KAAD;AAAqB,SAAG;AAAG,SAAG,CAAC;AAAZ;AAAoB,SAAG,CAAC;AAAG,SAAG;AAAZ;AAClC,SAAG;AAAG,SAAG;AAAX;AAAmB,SAAG;AAAG,SAAG;AAAX;AAAmB,SAAG,CAAC;AAAG,SAAG;AAAZ;AAChC,SAAG;AAAG,SAAG;AAAX;AAAmB,SAAG;AAAG,SAAG;AAAX;AAJ/B,GADwB;AAQtB;AAAW,SAAG,CAAC;AAAG,SAAG,CAAC;AAAb,KAAD;AAAsB,SAAG;AAAG,SAAG,CAAC;AAAZ;AAAoB,SAAG;AAAG,SAAG,CAAC;AAAZ;AACnC,SAAG,CAAC;AAAG,SAAG;AAAZ;AACT;AAAc,SAAG;AAAG,SAAG,CAAC;AAAZ,KAAD;AAAqB,SAAG,CAAC;AAAG,SAAG;AAAZ;AAAoB,SAAG;AAAG,SAAG;AAAX;AAClC,SAAG;AAAG,SAAG;AAAX;AAAmB,SAAG;AAAG,SAAG;AAAX;AAAmB,SAAG;AAAG,SAAG;AAAX;AAJhD;AASF,MAAI,iBAAiB,CACnB,QACA,QACA,QACA;AAGF,MAAI,2BAA2B,CAC7B,QACA;AAGF,WAAS,sBAAsB,OAAO,QAAQ,iBAAiB;AAC7D,QAAI,UAAU,gBAAgB;AAC9B,QAAI,WAAW,gBAAgB,aAAa,YAAY;AACxD,QAAI;QAAc;QAAG;QAAG;QAAO;QAAK;QAAM;QAAM,SAAS;AAKzD,QAAI,iBAAiB;AAErB,SAAK,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC3B,YAAM,OAAO,KAAK,IAAI,WAAW;AACjC,aAAQ,IAAI,IAAK,MAAM,OAAO,IAAI;AAClC,aAAQ,IAAI,IAAK,MAAM,OAAO,IAAI;AAIlC,qBAAgB,KAAK,MAAM,KAAO,KAAK,MAAM,KAAO,KAAK,MAAM,KAC/C,KAAK,MAAM,IAAM,KAAK,MAAM,IAAM,KAAK,MAAM,IAC7C,KAAK,MAAM;AAE3B,WAAK,IAAI,GAAG,IAAI,OAAO,KAAK;AAC1B,YAAI,KAAK,QAAQ,QAAQ,QAAQ,UAAU;AAI3C,uBAAiB,gBAAe,mBAChB,SAAI,IAAI,QAAQ,KAAK,IAAI,MAAM,KAC/B,UAAI,IAAI,QAAQ,KAAK,IAAI,MAAM,IAAI,KAAK;AAlB/B;AAVgC;AAgC7D,WAAO;AAzKoC;AA6K7C,WAAS,aAAa,KAAK,OAAO,QAAQ,eAAe,YAAY,MAAM,IACrD,iBAAiB;AACrC,QAAI,KAAK;AACP,YAAM,IAAI,WAAW;AAFc;AAMrC,QAAI,kBAAkB,KAAK,CAAC,QAAQ,CAAC,cAAc,GAAG,WAAW,KAC7D,GAAG,GAAG,MAAM,KAAK,GAAG,GAAG,MAAM,CAAC,KAAK,GAAG,GAAG,MAAM,CAAC,KAAK,GAAG,GAAG,MAAM,CAAC,KAClE,GAAG,GAAG,MAAM,KAAK,GAAG,GAAG,MAAM,CAAC,KAAK,GAAG,GAAG,MAAM,CAAC,KAAK,GAAG,GAAG,MAAM,CAAC,GAAG;AACvE,aAAO,sBAAsB,OAAO,QAAQ;AATT;AAYrC,QAAI,UAAU,CAAC,CAAC;AAChB,QAAI,WAAW,gBAAgB,eAAe,OAAO;AAKrD,aAAS,KAAK,UAAU,GAAG,GAAG;AAC5B,aAAQ,EAAE,IAAI,EAAE,KAAO,EAAE,IAAI,EAAE;AADjC;AAIA,QAAI,iBAAiB,SAAS;AAC9B,QAAI,YAAY,IAAI,UAAU;AAC9B,QAAI,YAAY,IAAI,UAAU;AAC9B,QAAI,0BAA0B;AAC9B,QAAI,YAAY;QAAG,OAAO;QAAG,OAAO;QAAG,OAAO;AAC9C,QAAI,GAAG;AAEP,SAAK,IAAI,GAAG,IAAI,gBAAgB,KAAK;AACnC,gBAAU,KAAK,SAAS,GAAG;AAC3B,gBAAU,KAAK,SAAS,GAAG;AAC3B,aAAO,KAAK,IAAI,MAAM,SAAS,GAAG;AAClC,aAAO,KAAK,IAAI,MAAM,SAAS,GAAG;AAClC,aAAO,KAAK,IAAI,MAAM,SAAS,GAAG;AAIlC,UAAI,IAAI,iBAAiB,KACrB,SAAS,GAAG,MAAM,SAAS,IAAI,GAAG,KAClC,SAAS,GAAG,MAAM,SAAS,IAAI,GAAG,IAAI,GAAG;AAC3C,qBAAa,KAAM,iBAAiB,IAAI;AAH1C,aAIO;AACL,gCAAwB,KAAK;AAdI;AA7BA;AA8CrC,QAAI,wBAAwB,wBAAwB;AAEpD,QAAI,oBAAoB,IAAI,UAAU;AACtC,QAAI,oBAAoB,IAAI,UAAU;AACtC,QAAI,sBAAsB,IAAI,YAAY;AAC1C,SAAK,IAAI,GAAG,IAAI,uBAAuB,KAAK;AAC1C,UAAI,wBAAwB;AAC5B,wBAAkB,KAAK,SAAS,GAAG;AACnC,wBAAkB,KAAK,SAAS,GAAG;AACnC,0BAAoB,KAAK,KAAM,iBAAiB,IAAI;AAvDjB;AA2DrC,QAAI,WAAW,CAAC;AAChB,QAAI,UAAU,CAAC;AACf,QAAI,YAAY,QAAQ;AAExB,QAAI,qBAAqB,eAAe;AACxC,QAAI,MAAM,IAAI,WAAW;AACzB,QAAI,SAAS;AAEb,QAAI,UAAU,gBAAgB;AAC9B,QAAI,WAAW,gBAAgB,aAAa,YAAY;AAExD,QAAI,MAAM;QAAG;QAAG;QAAI;QAAI,eAAe;QAAG;QAAK;AAC/C,SAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,UAAI,YAAY;AACd,YAAI,OAAO,QAAQ,QAAQ,UAAU;AACrC,eAAO;AACP,YAAI,KAAK;AACP,iBAAO,KAAK;AACZ;AALY;AADe;AAS/B,YAAM,IAAI,WAAW;AACrB,aAAO,KAAK;AACZ,WAAK,IAAI,GAAG,IAAI,OAAO,KAAK;AAC1B,YAAI,WAAW,KAAK,GAAG,IAAI;AACzB,cAAI,KAAK;AACT;AAHwB;AAO1B,YAAI,KAAK,YAAY,IAAI,aAAa,KAAK,SAAS;AAGlD,yBAAgB,gBAAgB,IAAK;AACrC,eAAK,IAAI,GAAG,IAAI,uBAAuB,KAAK;AAC1C,iBAAK,IAAI,kBAAkB;AAC3B,iBAAK,IAAI,kBAAkB;AAC3B,kBAAM,OAAO,IAAI;AACjB,gBAAI,KAAK;AACP,oBAAM,oBAAoB;AAC1B,8BAAgB;AANwB;AAJM;AAApD,eAaO;AAEL,yBAAe;AACf,kBAAQ,iBAAiB;AACzB,eAAK,IAAI,GAAG,IAAI,gBAAgB,KAAK,SAAS;AAC5C,iBAAK,IAAI,UAAU;AACnB,gBAAI,MAAM,KAAK,KAAK,OAAO;AACzB,mBAAK,IAAI,UAAU;AACnB,kBAAI,MAAM,GAAG;AACX,sBAAM,OAAO,IAAI;AACjB,oBAAI,KAAK;AACP,kCAAgB,OAAO;AAHd;AAFY;AAFiB;AAJzC;AApBmB;AAqC1B,YAAI,QAAQ,QAAQ,QAAQ,UAAU;AACtC,YAAI,KAAK;AAjDoB;AAvEI;AA2HrC,WAAO;AAzSoC;AA6S7C,WAAS,iBAAiB,OAAO,QAAQ,eAAe,iBAC9B,SAAS,SAAS,YAAY,IAC9B,iBAAiB;AACzC,QAAI,iBAAiB,oBAAoB,eAAe;AACxD,QAAI,kBAAkB,GAAG;AACvB,uBAAiB,eAAe,OAAO,CAAC,GAAG;AAHJ;AAKzC,QAAI,uBAAuB,eAAe;AAC1C,QAAI,kBAAkB,IAAI,WAAW;AACrC,QAAI,kBAAkB,IAAI,WAAW;AACrC,QAAI;AACJ,SAAK,IAAI,GAAG,IAAI,sBAAsB,KAAK;AACzC,sBAAgB,KAAK,eAAe,GAAG;AACvC,sBAAgB,KAAK,eAAe,GAAG;AAXA;AAczC,QAAI,oBAAoB,oBAAoB,eAAe;AAC3D,QAAI,kBAAkB,GAAG;AACvB,0BAAoB,kBAAkB,OAAO,CAAC,GAAG;AAhBV;AAkBzC,QAAI,0BAA0B,kBAAkB;AAChD,QAAI,qBAAqB,IAAI,WAAW;AACxC,QAAI,qBAAqB,IAAI,WAAW;AACxC,SAAK,IAAI,GAAG,IAAI,yBAAyB,KAAK;AAC5C,yBAAmB,KAAK,kBAAkB,GAAG;AAC7C,yBAAmB,KAAK,kBAAkB,GAAG;AAvBN;AAyBzC,QAAI,iBAAiB,gBAAgB,GAAG;AACxC,QAAI,kBAAkB,gBAAgB;AAEtC,QAAI,qBAAqB,yBAAyB;AAClD,QAAI,SAAS;AAEb,QAAI,UAAU,gBAAgB;AAC9B,QAAI,WAAW,gBAAgB,aAAa,YAAY;AAExD,QAAI,MAAM;AACV,SAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,UAAI,YAAY;AACd,YAAI,OAAO,QAAQ,QAAQ,UAAU;AACrC,eAAO;AACP,YAAI,KAAK;AACP,gBAAM,IAAI,WAAW;AAJT;AADe;AAQ/B,UAAI,MAAM,IAAI,WAAW;AACzB,aAAO,KAAK;AACZ,WAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,YAAI,IAAI;AACR,YAAI,eAAe;AACnB,aAAK,IAAI,GAAG,IAAI,sBAAsB,KAAK;AACzC,eAAK,IAAI,gBAAgB;AACzB,eAAK,IAAI,gBAAgB;AACzB,cAAI,KAAK,KAAK,KAAK,KAAK,MAAM,OAAO;AACnC,6BAAiB;AADnB,iBAEO;AACL,2BAAgB,gBAAgB,IAAK,OAAO,IAAI;AANT;AAHb;AAY9B,aAAK,IAAI,GAAG,IAAI,yBAAyB,KAAK;AAC5C,eAAK,IAAI,mBAAmB,KAAK;AACjC,eAAK,IAAI,mBAAmB,KAAK;AACjC,cAAI,KAAK,KAAK,MAAM,mBAAmB,KAAK,KACxC,MAAM,gBAAgB;AACxB,6BAAiB;AAFnB,iBAGO;AACL,2BAAgB,gBAAgB,IAAK,gBAAgB,IAAI;AAPf;AAZhB;AAsB9B,YAAI,QAAQ,QAAQ,QAAQ,UAAU;AACtC,YAAI,KAAK;AAjCoB;AAnCQ;AAwEzC,WAAO;AAvXoC;AA2X7C,WAAS,uBAAuB,SAAS,YAAY,SACrB,oBAAoB,yBACpB,eAAe,eAAe,IAC9B,yBAAyB,cACzB,iBAAiB;AAC/C,QAAI,SAAS;AACX,YAAM,IAAI,WAAW;AAFwB;AAK/C,QAAI,aAAa;AACjB,QAAI,gBAAgB;AACpB,QAAI,mBAAmB,gBAAK,QAAQ,SAAS;AAE7C,QAAI,UAAU,gBAAgB;AAC9B,QAAI,eAAe,gBAAgB;AAEnC,WAAO,WAAW,SAAS,oBAAoB;AAC7C,UAAI,cAAc,cAAc,cAAc,QAAQ;AACtD,uBAAiB;AACjB,UAAI,eAAe;AACnB,aAAO,MAAM;AACX,YAAI,aAAa,cAAc,cAAc,QAAQ;AACrD,YAAI,eAAe,MAAM;AACvB;AAHS;AAKX,wBAAgB;AAChB,YAAI;AACJ,YAAI,YAAY;AAEd,cAAI,oBAAoB,cAAc,cAAc,QAAQ;AAC5D,cAAI,oBAAoB,GAAG;AACzB,qBAAS,iBAAiB,SAAS,YACT,cAAc,eAAe,GAC7B,mBAAmB,GACnB,QAAQ,OAAO,aACf,kBACA,GACA,GACA,GACA,GACA,eACA,yBAAyB,cACzB;AAZ5B,iBAaO;AACL,gBAAI,WAAW,WAAW,cAAc,SAAS;AACjD,gBAAI,MAAM,cAAc,cAAc,SAAS;AAC/C,gBAAI,MAAM,cAAc,cAAc,SAAS;AAC/C,gBAAI,SAAU,WAAW,QAAQ,SAAS,QAAQ,YACpC,WAAW,WAAW,QAAQ;AAC5C,qBAAS,iBAAiB,cAAc,eACxC,yBAAyB,QAAQ,KAAK,KAAK,OAAO,cAClD;AAxBY;AAAhB,eA0BO;AAEL,mBAAS,aAAa,OAAO,cAAc,eACzC,eAAe,OAAO,MAAM,IAAI;AApCzB;AAsCX,mBAAW,KAAK;AA1C2B;AAZA;AA0D/C,QAAI,kBAAkB;AACtB,QAAI,QAAQ;QAAI,cAAc;AAC9B,QAAI,qBAAqB,QAAQ,SAAS;AAC1C,WAAO,MAAM,SAAS,oBAAoB;AACxC,UAAI,YAAY,cAAc,cAAc,QAAQ;AACpD,aAAO,aAAa;AAClB,cAAM,KAAK;AAH2B;AAKxC,oBAAc,CAAC;AAlE8B;AAoE/C,SAAK,IAAI,IAAI,GAAG,KAAK,QAAQ,QAAQ,IAAI,IAAI,KAAK;AAChD,UAAI,MAAM,IAAI;AACZ,wBAAgB,KAAK,QAAQ;AAFiB;AApEH;AAyE/C,SAAK,IAAI,IAAI,GAAG,IAAI,oBAAoB,KAAK,KAAK;AAChD,UAAI,MAAM,IAAI;AACZ,wBAAgB,KAAK,WAAW;AAFc;AAzEH;AA8E/C,WAAO;AA7coC;AAgd7C,WAAS,iBAAiB,SAAS,YAAY,OAAO,QAC5B,mBAAmB,yBACnB,WAAW,cAAc,kBACzB,YAAY,UAAU,iBACtB,qBAAqB,eACrB,yBAAyB,cACzB,iBAAiB;AACzC,QAAI,SAAS;AACX,YAAM,IAAI,WAAW;AAFkB;AAMzC,QAAI,SAAS;AACb,QAAI,GAAG;AACP,SAAK,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC3B,YAAM,IAAI,WAAW;AACrB,UAAI,mBAAmB;AACrB,aAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,cAAI,KAAK;AAFU;AAFI;AAO3B,aAAO,KAAK;AAf2B;AAkBzC,QAAI,UAAU,gBAAgB;AAC9B,QAAI,eAAe,gBAAgB;AACnC,QAAI,SAAS,CAAC,cAAc,cAAc,QAAQ;AAClD,QAAI,SAAS;AACb,QAAI;AACJ,WAAO,IAAI,yBAAyB;AAClC,UAAI,SAAS,cAAc,cAAc,QAAQ;AACjD,gBAAU;AAEV,UAAI,cAAc,cAAc,cAAc,QAAQ;AACtD,gBAAU;AACV,UAAI,WAAW;AACf,SAAG;AACD,YAAI,WAAY,cAAc,IAAI,IAClB,cAAc,cAAc,QAAQ;AACpD,YAAI,IAAI,YAAY,SAAS;AAC7B,YAAI,WAAW,WAAW,cAAc,SAAS;AACjD,YAAI,kBAAmB,cACA,cAAc,cAAc,QAAQ;AAC3D,YAAI,eAAe,aAAa;AAChC,YAAI,cAAc,aAAa,GAAG;AAClC,YAAI,eAAe,aAAa;AAChC,YAAI,iBAAiB;AACnB,cAAI,MAAM,cAAc,cAAc,SAAS;AAC/C,cAAI,MAAM,cAAc,cAAc,SAAS;AAC/C,cAAI,MAAM,cAAc,cAAc,SAAS;AAC/C,cAAI,MAAM,cAAc,cAAc,SAAS;AAC/C,yBAAe;AACf,0BAAgB;AAChB,yBAAe,iBAAiB,aAAa,cAC3C,yBAAyB,cAAe,QAAO,KAAK,KACnD,QAAO,KAAK,KAAK,OAAO,cACzB;AApBH;AAsBD,YAAI,UAAe,KAAC,kBAAkB,IAAK,IAAI;AAC/C,YAAI,UAAsB,YAAC,kBAAkB,IAAK,cAAc;AAChE,YAAI,IAAI,IAAI;AACZ,YAAI,YAAY;AAEd,eAAK,KAAK,GAAG,KAAK,cAAc,MAAM;AACpC,kBAAM,OAAO,UAAU;AACvB,gBAAI,CAAC,KAAK;AACR;AAHkC;AAKpC,wBAAY,aAAa;AAGzB,gBAAI,WAAW,KAAK,IAAI,QAAQ,SAAS;AACzC,oBAAQ;AACN,mBAAK;AACH,qBAAK,KAAK,GAAG,KAAK,UAAU,MAAM;AAChC,sBAAI,UAAU,OAAO,UAAU;AAFnC;AAIE;AACF,mBAAK;AACH,qBAAK,KAAK,GAAG,KAAK,UAAU,MAAM;AAChC,sBAAI,UAAU,OAAO,UAAU;AAFnC;AAIE;AACF;AACE,sBAAM,IACH,yBAA+B;;AAxB1B;AA2Bd,sBAAY,eAAe;AA3B7B,eA4BO;AACL,eAAK,KAAK,GAAG,KAAK,cAAc,MAAM;AACpC,kBAAM,OAAO,UAAU;AACvB,gBAAI,CAAC,KAAK;AACR;AAHkC;AAKpC,wBAAY,aAAa;AACzB,oBAAQ;AACN,mBAAK;AACH,qBAAK,KAAK,GAAG,KAAK,aAAa,MAAM;AACnC,sBAAI,UAAU,OAAO,UAAU;AAFnC;AAIE;AACF,mBAAK;AACH,qBAAK,KAAK,GAAG,KAAK,aAAa,MAAM;AACnC,sBAAI,UAAU,OAAO,UAAU;AAFnC;AAIE;AACF;AACE,sBAAM,IACH,yBAA+B;;AApBnC;AAuBL,sBAAY,cAAc;AA5E3B;AA8ED;AACA,YAAI,SAAS,cAAc,cAAc,QAAQ;AACjD,YAAI,WAAW,MAAM;AACnB;AAjFD;AAmFD,oBAAY,SAAS;AAnFvB,eAoFS;AAlH8B;AAoHzC,WAAO;AA1kBoC;AA6kB7C,WAAS,kBAAkB,MAAM,OAAO;AACtC,QAAI,gBAAgB;AACpB,kBAAc,SAAS,sBAAW,MAAM;AACxC,QAAI,QAAQ,KAAK,QAAQ;AACzB,QAAI,cAAc,QAAQ;AAC1B,QAAI,CAAC,aAAa,cAAc;AAC9B,YAAM,IAAI,WAAW,2BAA2B;AANZ;AAQtC,kBAAc,OAAO;AACrB,kBAAc,WAAW,aAAa;AACtC,kBAAc,oBAAoB,CAAG,UAAQ;AAE7C,QAAI,2BAA2B,CAAG,UAAQ;AAC1C,QAAI,gBAAgB,KAAK,QAAQ;AACjC,QAAI,kBAAmB,iBAAiB,IAAK;AAC7C,QAAI,aAAa,CAAC,gBAAgB;AAClC,QAAI,WAAW,QAAQ;AACvB,QAAI,kBAAkB,GAAG;AACvB,wBAAkB,sBAAW,MAAM,WAAW,KAAK;AACnD,kBAAY;AACZ,UAAI,QAAS,kBAAkB,KAAM;AACrC,iBAAW,KAAK,KAAK;AACrB,aAAO,EAAE,QAAQ,GAAG;AAClB,mBAAW,KAAK,KAAK;AANA;AAAzB,WAQO,IAAI,kBAAkB,KAAK,kBAAkB,GAAG;AACrD,YAAM,IAAI,WAAW;AA1Be;AA6BtC,kBAAc,aAAa;AAC3B,QAAI,8BAA+B,cAAc,UAAU,MAAM,IAC9D,cAAc,UAAU,QAAQ,IAAI;AACvC,QAAI,aAAa;AACjB,QAAI,GAAG;AACP,SAAK,IAAI,GAAG,IAAI,iBAAiB,KAAK;AACpC,UAAI,SAAU,gCAAgC,IAAI,KAAK,YACpD,gCAAgC,IAAI,sBAAW,MAAM,YACtD,sBAAW,MAAM;AACnB,iBAAW,KAAK;AAChB,kBAAY;AAvCwB;AAyCtC,kBAAc,aAAa;AAC3B,QAAI,CAAC,0BAA0B;AAC7B,oBAAc,kBAAkB,KAAK;AADvC,WAEO;AACL,oBAAc,kBAAkB,sBAAW,MAAM;AACjD,kBAAY;AA9CwB;AAgDtC,kBAAc,SAAS,sBAAW,MAAM;AACxC,gBAAY;AAEZ,QAAI,cAAc,WAAW,YAAY;AAEvC,UAAI,gBAAgB,IAAI;AACtB,YAAI,oBAAoB,6BAA6B,MAAM;AAC3D,YAAI,4BAA4B,KAAK,WACnC;AACF,YAAI,mBAAmB,CAAG,8BAA4B;AAEtD,YAAI,sBAAsB;AAC1B,YAAI,gBAAgB,IAAI,WAAW;AACnC,YAAI,CAAC,kBAAkB;AACrB,wBAAc,KAAK;AACnB,wBAAc,KAAK;AAVC;AAYtB,sBAAc,KAAM,kBAAkB,WAAW,KAAM;AACvD,sBAAc,KAAM,kBAAkB,UAAU,KAAM;AACtD,sBAAc,KAAM,kBAAkB,UAAU,IAAK;AACrD,sBAAc,KAAK,kBAAkB,SAAS;AAC9C,aAAK,IAAI,UAAU,KAAK,KAAK,QAAQ,IAAI,IAAI,KAAK;AAChD,cAAI,IAAI;AACR,iBAAO,IAAI,uBAAuB,cAAc,OAAO,KAAK,IAAI,IAAI;AAClE;AAH8C;AAKhD,cAAI,MAAM,qBAAqB;AAC7B,0BAAc,SAAS,IAAI;AAC3B;AAP8C;AAhB5B;AA0BtB,YAAI,cAAc,WAAW,YAAY;AACvC,gBAAM,IAAI,WAAW;AA3BD;AAAxB,aA6BO;AACL,cAAM,IAAI,WAAW;AAhCgB;AAnDH;AAsFtC,kBAAc,YAAY;AAC1B,WAAO;AApqBoC;AAuqB7C,WAAS,aAAa,QAAQ,MAAM,OAAO,KAAK;AAC9C,QAAI,WAAW;AACf,QAAI,WAAW;AACf,WAAO,WAAW,KAAK;AACrB,UAAI,gBAAgB,kBAAkB,MAAM;AAC5C,iBAAW,cAAc;AACzB,UAAI;AACF,gBAAQ;AACR;AAFY;AAId,UAAI,CAAC,OAAO,cAAc;AACxB,gBAAQ,QAAQ;AAChB,oBAAY,cAAc;AAC1B,gBAAQ,MAAM;AAVK;AAYrB,eAAS,KAAK;AACd,UAAI,cAAc,SAAS,IAAI;AAC7B;AAdmB;AAHuB;AAoB9C,QAAI,OAAO,cAAc;AACvB,WAAK,IAAI,IAAI,GAAG,KAAK,SAAS,QAAQ,IAAI,IAAI,KAAK;AACjD,iBAAS,GAAG,QAAQ;AACpB,oBAAY,SAAS,GAAG,OAAO;AAC/B,iBAAS,GAAG,MAAM;AAJG;AApBqB;AA2B9C,WAAO;AAlsBoC;AAssB7C,WAAS,6BAA6B,MAAM,OAAO;AACjD;AACE,aAAO,sBAAW,MAAM;AACxB,cAAQ,sBAAW,MAAM,QAAQ;AACjC,SAAG,sBAAW,MAAM,QAAQ;AAC5B,SAAG,sBAAW,MAAM,QAAQ;AAC5B,2BAAqB,KAAK,QAAQ,MAAM;AALnC;AAvsBoC;AA+sB7C,MAAI,sCAAsC;AAE1C,WAAS,eAAe,SAAS,SAAS;AACxC,QAAI,SAAS,QAAQ;AAErB,QAAI,OAAO,QAAQ;QAAM,WAAW,QAAQ;QAAO,MAAM,QAAQ;AACjE,QAAI,MAAM,IAAI,GAAG;AACjB,YAAQ,OAAO;AACb,WAAK;AAEH,YAAI,aAAa;AACjB,YAAI,kBAAkB,sBAAW,MAAM;AACvC,mBAAW,UAAU,CAAG,oBAAkB;AAC1C,mBAAW,aAAa,CAAG,oBAAkB;AAC7C,mBAAW,oBAAqB,mBAAmB,IAAK;AACxD,mBAAW,oBAAqB,mBAAmB,IAAK;AACxD,mBAAW,qBAAsB,mBAAmB,IAAK;AACzD,mBAAW,+BAAgC,mBAAmB,IAAK;AACnE,mBAAW,0BAA0B,CAAG,oBAAkB;AAC1D,mBAAW,8BAA8B,CAAG,oBAAkB;AAC9D,mBAAW,WAAY,mBAAmB,KAAM;AAChD,mBAAW,qBAAsB,mBAAmB,KAAM;AAC1D,oBAAY;AACZ,YAAI,CAAC,WAAW,SAAS;AACvB,qBAAW,WAAW,aAAa,IAAI,IAAI;AAC3C,eAAK;AACL,eAAK,IAAI,GAAG,IAAI,UAAU,KAAK;AAC7B,eAAG;AACD,iBAAG,oBAAS,MAAM;AAClB,iBAAG,oBAAS,MAAM,WAAW;AAFvB;AAIR,wBAAY;AARS;AAUvB,qBAAW,KAAK;AAzBpB;AA2BE,YAAI,WAAW,cAAc,CAAC,WAAW,oBAAoB;AAC3D,eAAK;AACL,eAAK,IAAI,GAAG,IAAI,GAAG,KAAK;AACtB,eAAG;AACD,iBAAG,oBAAS,MAAM;AAClB,iBAAG,oBAAS,MAAM,WAAW;AAFvB;AAIR,wBAAY;AAP6C;AAS3D,qBAAW,eAAe;AApC9B;AAsCE,mBAAW,0BAA0B,sBAAW,MAAM;AACtD,oBAAY;AACZ,mBAAW,qBAAqB,sBAAW,MAAM;AACjD,oBAAY;AACZ,eAAO,CAAC,YAAY,OAAO,QAAQ,OAAO,YAClC,MAAM,UAAU;AACxB;AACF,WAAK;AACL,WAAK;AACH,YAAI,aAAa;AACjB,mBAAW,OAAO,6BAA6B,MAAM;AACrD,oBAAY;AACZ,YAAI,yBAAyB,sBAAW,MAAM;AAC9C,oBAAY;AACZ,mBAAW,UAAU,CAAG,2BAAyB;AACjD,mBAAW,aAAa,CAAG,2BAAyB;AACpD,mBAAW,YAAkB,MAAC,0BAA0B,IAAK;AAC7D,mBAAW,kBAAmB,0BAA0B,IAAK;AAC7D,mBAAW,aAAa,CAAG,2BAAyB;AACpD,mBAAW,sBAAuB,0BAA0B,IAAK;AACjE,mBAAW,oBAAqB,0BAA0B,IAAK;AAC/D,mBAAW,WAAY,0BAA0B,MAAO;AACxD,mBAAW,qBAAsB,0BAA0B,KAAM;AACjE,YAAI,WAAW,SAAS;AACtB,cAAI,yBAAyB,sBAAW,MAAM;AAC9C,sBAAY;AACZ,qBAAW,YAAa,yBAA0B;AAClD,qBAAW,YAAa,0BAA0B,IAAK;AACvD,qBAAW,YAAa,0BAA0B,IAAK;AACvD,qBAAW,sBAAuB,0BAA0B,IAAK;AACjE,qBAAW,sBAAuB,0BAA0B,IAAK;AACjE,qBAAW,sBAAuB,0BAA0B,KAAM;AAClE,qBAAW,sBAAuB,0BAA0B,KAAM;AAClE,qBAAW,gCACT,CAAG,2BAAyB;AA1BlC;AA4BE,YAAI,WAAW,cAAc,CAAC,WAAW,oBAAoB;AAC3D,eAAK;AACL,eAAK,IAAI,GAAG,IAAI,GAAG,KAAK;AACtB,eAAG;AACD,iBAAG,oBAAS,MAAM;AAClB,iBAAG,oBAAS,MAAM,WAAW;AAFvB;AAIR,wBAAY;AAP6C;AAS3D,qBAAW,eAAe;AArC9B;AAuCE,mBAAW,0BAA0B,sBAAW,MAAM;AACtD,oBAAY;AAEZ,YAAI,WAAW,SAAS;AACtB,gBAAM,IAAI,WAAW;AA3CzB;AA6CE,eAAO,CAAC,YAAY,OAAO,YAAY,MAAM,UAAU;AACvD;AACF,WAAK;AACL,WAAK;AACH,YAAI,gBAAgB;AACpB,sBAAc,OAAO,6BAA6B,MAAM;AACxD,oBAAY;AACZ,YAAI,4BAA4B,KAAK;AACrC,sBAAc,MAAM,CAAG,8BAA4B;AACnD,sBAAc,WAAY,6BAA6B,IAAK;AAC5D,sBAAc,aAAa,CAAG,8BAA4B;AAC1D,YAAI,CAAC,cAAc,KAAK;AACtB,qBAAW,cAAc,aAAa,IAAI,IAAI;AAC9C,eAAK;AACL,eAAK,IAAI,GAAG,IAAI,UAAU,KAAK;AAC7B,eAAG;AACD,iBAAG,oBAAS,MAAM;AAClB,iBAAG,oBAAS,MAAM,WAAW;AAFvB;AAIR,wBAAY;AARQ;AAUtB,wBAAc,KAAK;AAlBvB;AAoBE,eAAO,CAAC,eAAe,MAAM,UAAU;AACvC;AACF,WAAK;AACH,YAAI;AACF,iBAAO,sBAAW,MAAM;AACxB,kBAAQ,sBAAW,MAAM,WAAW;AACpC,uBAAa,sBAAW,MAAM,WAAW;AACzC,uBAAa,sBAAW,MAAM,WAAW;AAJ5B;AAMf,YAAI,SAAS,WAAW,YAAY;AAClC,iBAAO,SAAS;AARpB;AAUE,YAAI,mBAAmB,KAAK,WAAW;AACvC,8BAAW,MAAM,WAAW;AAC5B,iBAAS,WAAW,CAAG,qBAAmB;AAC1C,iBAAS,aAAa,CAAG,qBAAmB;AAC5C,iBAAS,oBAAqB,oBAAoB,IAAK;AACvD,iBAAS,sBAAuB,oBAAoB,IAAK;AACzD,iBAAS,iBAAiB,CAAG,qBAAmB;AAChD,iBAAS,8BAA8B,CAAG,qBAAmB;AAC7D,eAAO,CAAC;AACR;AACF,WAAK;AACH;AACF,WAAK;AACH;AACF,WAAK;AACH;AACF,WAAK;AAEH;AACF;AACE,cAAM,IAAI,WAAY,kBAAe,OAAgB,iBAAG,OAAY,aAC/C;;AAEzB,QAAI,eAAe,OAAO,OAAO;AACjC,QAAI,gBAAgB,SAAS;AAC3B,cAAQ,cAAc,MAAM,SAAS;AA7JC;AAjtBG;AAk3B7C,WAAS,gBAAgB,UAAU,SAAS;AAC1C,SAAK,IAAI,IAAI,GAAG,KAAK,SAAS,QAAQ,IAAI,IAAI,KAAK;AACjD,qBAAe,SAAS,IAAI;AAFY;AAl3BC;AAw3B7C,WAAS,WAAW,MAAM,OAAO,KAAK;AACpC,QAAI,WAAW;AACf,QAAI,KAAK,cAAc,QAAQ,KAAK,WAAW,OAAO,QAClD,KAAK,WAAW,OAAO,QAAQ,KAAK,WAAW,OAAO,QACtD,KAAK,WAAW,OAAO,QAAQ,KAAK,WAAW,OAAO,QACtD,KAAK,WAAW,OAAO,QAAQ,KAAK,WAAW,OAAO,MAAM;AAC9D,YAAM,IAAI,WAAW;AANa;AAQpC,QAAI,SAAS;AACb,gBAAY;AACZ,QAAI,QAAQ,KAAK;AACjB,WAAO,eAAiB,UAAQ;AAChC,QAAM,UAAQ,IAAI;AAChB,aAAO,gBAAgB,sBAAW,MAAM;AACxC,kBAAY;AAdsB;AAgBpC,iBAAa,QAAQ,MAAM,UAAU;AACrC,UAAM,IAAI,MAAM;AAz4B2B;AA64B7C,WAAS,iBAAiB,QAAQ;AAChC,QAAI,UAAU,IAAI;AAClB,SAAK,IAAI,IAAI,GAAG,KAAK,OAAO,QAAQ,IAAI,IAAI,KAAK;AAC/C,UAAI,QAAQ,OAAO;AACnB,UAAI,WAAW,aAAa,IAAI,MAAM,MAAM,MAAM,OAAO,MAAM;AAC/D,sBAAgB,UAAU;AALI;AAOhC,WAAO,QAAQ;AAp5B4B;AAu5B7C,WAAS,uBAAuB,CAv5Ba;AAy5B7C,uBAAqB;AACnB,uBAAmB,SAAS,uCAAuC,MAAM;AACvE,WAAK,kBAAkB;AACvB,UAAI,UAAW,KAAK,QAAQ,KAAM;AAClC,UAAI,SAAS,IAAI,WAAW,UAAU,KAAK;AAG3C,UAAI,KAAK,mBAAmB;AAC1B,aAAK,IAAI,IAAI,GAAG,KAAK,OAAO,QAAQ,IAAI,IAAI,KAAK;AAC/C,iBAAO,KAAK;AAFY;AAN2C;AAWvE,WAAK,SAAS;AAZe;AAc/B,gBAAY,SAAS,gCAAgC,YAAY,QAAQ;AACvE,UAAI,WAAW,KAAK;AACpB,UAAI,QAAQ,WAAW;UAAO,SAAS,WAAW;AAClD,UAAI,UAAW,SAAS,QAAQ,KAAM;AACtC,UAAI,sBAAsB,SAAS,8BACjC,WAAW,sBAAsB,SAAS;AAC5C,UAAI,SAAS,KAAK;AAClB,UAAI,QAAgB,mBAAW,IAAI;AACnC,UAAI,UAAU,WAAW,IAAe,sBAAW,KAAK;AACxD,UAAI,GAAG,GAAG,MAAM;AAChB,cAAQ;AACN,aAAK;AACH,eAAK,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC3B,mBAAO;AACP,qBAAS;AACT,iBAAK,IAAI,GAAG,IAAI,OAAO,KAAK;AAC1B,kBAAI,OAAO,GAAG,IAAI;AAChB,uBAAO,WAAW;AAFM;AAI1B,uBAAS;AACT,kBAAI,CAAC,MAAM;AACT,uBAAO;AACP;AAPwB;AAHD;AAa3B,uBAAW;AAdf;AAgBA;AACA,aAAK;AACH,eAAK,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC3B,mBAAO;AACP,qBAAS;AACT,iBAAK,IAAI,GAAG,IAAI,OAAO,KAAK;AAC1B,kBAAI,OAAO,GAAG,IAAI;AAChB,uBAAO,WAAW;AAFM;AAI1B,uBAAS;AACT,kBAAI,CAAC,MAAM;AACT,uBAAO;AACP;AAPwB;AAHD;AAa3B,uBAAW;AAdf;AAgBE;AACF;AACE,gBAAM,IACH,yBAA+B;;AA7DT;AAgE/B,8BACE,SAAS,8CAA8C,QAAQ,MACR,OAAO,KAAK;AACnE,UAAI,aAAa,OAAO;AACxB,UAAI,kBAAkB,IAAI,gBAAgB,MAAM,OAAO;AACvD,UAAI,SAAS,aAAa,OAAO,KAAK,WAAW,OAAO,WAAW,QACzC,OAAO,UAAU,OAAO,YAAY,MACpC,OAAO,IAAI;AACrC,WAAK,WAAW,YAAY;AAxEC;AA0E/B,sCACE,SAAS,wDAAwD;AACjE,WAAK,yBAAyB,MAAM,MAAM;AA5Eb;AA8E/B,wBACE,SAAS,wCAAwC,YACA,gBACA,kBACA,MAAM,OAAO,KAAK;AACnE,UAAI;AACJ,UAAI,WAAW,SAAS;AACtB,cAAM,IAAI,WAAW;AAH4C;AAOnE,UAAI,UAAU,KAAK;AACnB,UAAI,CAAC,SAAS;AACZ,aAAK,UAAU,UAAU;AATwC;AAYnE,UAAI,eAAe;AACnB,WAAK,IAAI,IAAI,GAAG,KAAK,iBAAiB,QAAQ,IAAI,IAAI,KAAK;AACzD,uBAAe,aAAa,OAAO,QAAQ,iBAAiB;AAdK;AAiBnE,UAAI,kBAAkB,IAAI,gBAAgB,MAAM,OAAO;AACvD,cAAQ,kBAAkB,uBAAuB,WAAW,SAC1D,WAAW,YAAY,cAAc,WAAW,oBAChD,WAAW,yBAAyB,eACpC,WAAW,UAAU,WAAW,IAChC,WAAW,oBAAoB,WAAW,cAC1C;AAzG2B;AA2G/B,2BACE,SAAS,2CAA2C,QACA,kBACA,MAAM,OAAO,KAAK;AACtE,UAAI,aAAa,OAAO;AACxB,UAAI;AAGJ,UAAI,UAAU,KAAK;AACnB,UAAI,eAAe;AACnB,WAAK,IAAI,IAAI,GAAG,KAAK,iBAAiB,QAAQ,IAAI,IAAI,KAAK;AACzD,uBAAe,aAAa,OAAO,QAAQ,iBAAiB;AARQ;AAUtE,UAAI,mBAAmB,gBAAK,aAAa;AAEzC,UAAI,kBAAkB,IAAI,gBAAgB,MAAM,OAAO;AACvD,UAAI,SAAS,iBAAiB,OAAO,SAAS,OAAO,YACnD,WAAW,OAAO,WAAW,QAAQ,OAAO,mBAC5C,OAAO,yBAAyB,OAAO,WAAW,cAClD,kBAAkB,OAAO,YAAY,OAAO,UAC5C,OAAO,iBAAiB,OAAO,qBAAqB,eACpD,OAAO,oBAAoB,OAAO,cAAc;AAClD,WAAK,WAAW,YAAY;AAjIC;AAmI/B,mCACE,SAAS,qDAAqD;AAC9D,WAAK,sBAAsB,MAAM,MAAM;AArIV;AAAA;AAyIjC,WAAS,aAAa,CAliCuB;AAoiC7C,aAAW;AACT,iBAAa,SAAS,uBAAuB,QAAQ;AACnD,aAAO,iBAAiB;AAFL;AAAA;AAMvB,SAAO;AAGT,CA7iCkB;QA8iChB,wB;;;;;;;;;;;;;;;;AC9jCmB;;AAErB,IAAI,qBAAsB,mBAAmB;AAC3C,WAAS,UAAU,KAAK;AACtB,SAAK,UAAU,iBAAiB;AAFS;AAK3C,YAAU,YAAY,IAAI;AAC1B,YAAU,UAAU,OAAO;AAC3B,YAAU,cAAc;AAExB,SAAO;AATO,CAAC;AAyBjB,IAAI,qBAAsB,mBAAmB;AAC3C,MAAI,YAAY,IAAI,WAAW,CAC5B,GACA,GAAI,GACL,IAAK,GAAI,GACR,GAAG,IAAI,IAAI,IACZ,IAAI,IAAI,IAAI,IAAI,GACf,GAAG,IAAI,IAAI,IAAI,IAAI,IACpB,IAAI,IAAI,IAAI,IAAI,IAAI,IAAK,GACxB,GAAG,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAC5B,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IACxB,IAAI,IAAI,IAAI,IAAI,IAAI,IACpB,IAAI,IAAI,IAAI,IAAI,IAChB,IAAI,IAAI,IAAI,IACZ,IAAI,IAAI,IACR,IAAI,IACJ;AAGF,MAAI,UAAY;AAChB,MAAI,UAAa;AACjB,MAAI,UAAY;AAChB,MAAI,UAAY;AAChB,MAAI,UAAY;AAChB,MAAI,UAAY;AAChB,MAAI,WAAY;AAChB,MAAI,aAAa;AAEjB,WAAS,YAAY;AACnB,SAAK,kBAAkB;AACvB,SAAK,iBAAiB,CAAC;AA9BkB;AAiC3C,WAAS,kBAAkB,aAAa,QAAQ;AAC9C,QAAI,IAAI;QAAG,OAAO;QAAI;QAAG;QAAG,SAAS;AACrC,WAAO,SAAS,KAAK,CAAC,YAAY,SAAS,IAAI;AAC7C;AAH4C;AAK9C,SAAK;AAAO,gBAAU;AAAI,aAAO;AAAvB;AACV,QAAI,IAAI,KAAK;QAAI;AACjB,SAAK,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC3B,WAAK,IAAI,GAAG,IAAI,YAAY,IAAI,KAAK;AACnC,YAAI,KAAK;AACT,UAAE,SAAS,EAAE,SAAS,OAAO;AAC7B,eAAO,EAAE,QAAQ,GAAG;AAClB,cAAI,KAAK;AAJwB;AAMnC,UAAE;AACF,aAAK,KAAK;AACV,eAAO,KAAK,UAAU,GAAG;AACvB,eAAK,KAAK;AAAM,sBAAU;AAAI,mBAAO;AAAvB;AACd,YAAE,SAAS,EAAE,SAAS,EAAE;AACxB,cAAI;AAX6B;AAanC;AAdyB;AAgB3B,UAAI,IAAI,IAAI,QAAQ;AAElB,aAAK,KAAK;AAAM,oBAAU;AAAI,iBAAO;AAAvB;AACd,UAAE,SAAS,EAAE,SAAS,EAAE;AACxB,YAAI;AApBqB;AAPiB;AA8B9C,WAAO,KAAK,GAAG;AA/D0B;AAkE3C,WAAS,qBAAqB,WAAW,KAAK,KAAK;AACjD,WAAa,MAAC,WAAU,gBAAgB,KAAK,MAAM;AAnEV;AAsE3C,WAAS,WAAW,MAAM,QAAQ,OAAO,YAAY,eACjC,eAAe,aAAa,gBAAgB,YAAY;AAC1E,QAAI,cAAc,MAAM;AACxB,QAAI,cAAc,MAAM;AAExB,QAAI,cAAc;QAAQ,WAAW;QAAG,YAAY;AAEpD,aAAS,UAAU;AACjB,UAAI,YAAY,GAAG;AACjB;AACA,eAAQ,YAAY,YAAa;AAHlB;AAKjB,iBAAW,KAAK;AAChB,UAAI,aAAa,MAAM;AACrB,YAAI,WAAW,KAAK;AACpB,YAAI,UAAU;AACZ,gBAAM,IACH,iCAAqB,CAAC,YAAY,IAAK,UAAU,SAAS;AAJ1C;AANN;AAcjB,kBAAY;AACZ,aAAO,aAAa;AArBoD;AAwB1E,aAAS,cAAc,MAAM;AAC3B,UAAI,OAAO;AACX,aAAO,MAAM;AACX,eAAO,KAAK;AACZ,YAAI,OAAO,SAAS,UAAU;AAC5B,iBAAO;AAHE;AAKX,YAAI,QAAO,wDAAS,UAAU;AAC5B,gBAAM,IAAI,UAAU;AANX;AAFc;AAxB6C;AAqC1E,aAAS,QAAQ,QAAQ;AACvB,UAAI,IAAI;AACR,aAAO,SAAS,GAAG;AACjB,YAAK,KAAK,IAAK;AACf;AAJqB;AAMvB,aAAO;AA3CiE;AA8C1E,aAAS,iBAAiB,QAAQ;AAChC,UAAI,WAAW,GAAG;AAChB,eAAO,cAAc,IAAI,IAAI,CAAC;AAFA;AAIhC,UAAI,IAAI,QAAQ;AAChB,UAAI,KAAK,KAAM,SAAS,GAAI;AAC1B,eAAO;AANuB;AAQhC,aAAY,MAAC,KAAK,UAAU;AAtD4C;AAyD1E,aAAS,eAAe,WAAW,QAAQ;AACzC,UAAI,IAAI,cAAc,UAAU;AAChC,UAAI,OAAO,MAAM,IAAI,IAAI,iBAAiB;AAC1C,gBAAU,UAAU,UAAW,UAAU,QAAQ;AACjD,UAAI,IAAI;AACR,aAAO,IAAI,IAAI;AACb,YAAI,KAAK,cAAc,UAAU;AACjC,YAAI,IAAI,KAAK;YAAI,IAAI,MAAM;AAC3B,YAAI,MAAM,GAAG;AACX,cAAI,IAAI,IAAI;AACV;AAFS;AAIX,eAAK;AACL;AARW;AAUb,aAAK;AACL,YAAI,IAAI,UAAU;AAClB,kBAAU,UAAU,SAAS,KAAK,iBAAiB;AACnD;AAlBuC;AAzD+B;AA+E1E,aAAS,cAAc,WAAW,QAAQ;AACxC,UAAI,IAAI,cAAc,UAAU;AAChC,UAAI,OAAO,MAAM,IAAI,IAAK,iBAAiB,MAAM;AACjD,gBAAU,UAAU,UAAW,UAAU,QAAQ;AAlFuB;AAqF1E,aAAS,mBAAmB,WAAW,QAAQ;AAC7C,gBAAU,UAAU,WAAW,aAAa;AAtF4B;AAyF1E,QAAI,SAAS;AACb,aAAS,cAAc,WAAW,QAAQ;AACxC,UAAI,SAAS,GAAG;AACd;AACA;AAHsC;AAKxC,UAAI,IAAI;UAAe,IAAI;AAC3B,aAAO,KAAK,GAAG;AACb,YAAI,KAAK,cAAc,UAAU;AACjC,YAAI,IAAI,KAAK;YAAI,IAAI,MAAM;AAC3B,YAAI,MAAM,GAAG;AACX,cAAI,IAAI,IAAI;AACV,qBAAS,QAAc,WAAK,KAAK;AACjC;AAHS;AAKX,eAAK;AACL;AATW;AAWb,aAAK;AACL,YAAI,IAAI,UAAU;AAClB,kBAAU,UAAU,SAAS,KAC3B,iBAAuB,WAAK;AAC9B;AArBsC;AA1FgC;AAmH1E,QAAI,oBAAoB;QAAG;AAC3B,aAAS,mBAAmB,WAAW,QAAQ;AAC7C,UAAI,IAAI;AACR,UAAI,IAAI;AACR,UAAI,IAAI;AACR,UAAI;AACJ,UAAI;AACJ,aAAO,KAAK,GAAG;AACb,YAAI,IAAI,UAAU;AAClB,gBAAQ;AACR,eAAK;AACH,iBAAK,cAAc,UAAU;AAC7B,gBAAI,KAAK;AACT,gBAAI,MAAM;AACV,gBAAI,MAAM,GAAG;AACX,kBAAI,IAAI,IAAI;AACV,yBAAS,QAAc,WAAK;AAC5B,oCAAoB;AAFtB,qBAGO;AACL,oBAAI;AACJ,oCAAoB;AANX;AAAb,mBAQO;AACL,kBAAI,MAAM,GAAG;AACX,sBAAM,IAAI,UAAU;AAFjB;AAIL,sCAAwB,iBAAiB;AACzC,kCAAoB,IAAI,IAAI;AAjBhC;AAmBE;AACF,eAAK;AACL,eAAK;AACH,gBAAI,UAAU,UAAU,SAAS,IAAI;AACnC,wBAAU,UAAU,SAAS,MAAO,aAAa;AADnD,mBAEO;AACL;AACA,kBAAI,MAAM,GAAG;AACX,oCAAoB,sBAAsB,IAAI,IAAI;AAH/C;AAHT;AASE;AACF,eAAK;AACH,gBAAI,UAAU,UAAU,SAAS,IAAI;AACnC,wBAAU,UAAU,SAAS,MAAO,aAAa;AADnD,mBAEO;AACL,wBAAU,UAAU,SAAS,KAC3B,yBAAyB;AAC3B,kCAAoB;AANxB;AAQE;AACF,eAAK;AACH,gBAAI,UAAU,UAAU,SAAS,IAAI;AACnC,wBAAU,UAAU,SAAS,MAAO,aAAa;AAFrD;AAIE;;AAEF;AAvD2C;AAyD7C,UAAI,sBAAsB,GAAG;AAC3B;AACA,YAAI,WAAW,GAAG;AAChB,8BAAoB;AAHK;AAzDgB;AApH2B;AAqL1E,aAAS,UAAU,WAAW,QAAQ,KAAK,KAAK,KAAK;AACnD,UAAI,SAAU,MAAM,cAAe;AACnC,UAAI,SAAS,MAAM;AACnB,UAAI,WAAW,SAAS,UAAU,IAAI;AACtC,UAAI,WAAW,SAAS,UAAU,IAAI;AACtC,UAAI,SAAS,qBAAqB,WAAW,UAAU;AACvD,aAAO,WAAW;AA3LsD;AA8L1E,aAAS,YAAY,WAAW,QAAQ,KAAK;AAC3C,UAAI,WAAY,MAAM,UAAU,gBAAiB;AACjD,UAAI,WAAW,MAAM,UAAU;AAC/B,UAAI,SAAS,qBAAqB,WAAW,UAAU;AACvD,aAAO,WAAW;AAlMsD;AAqM1E,QAAI,mBAAmB,WAAW;AAClC,QAAI,WAAW,GAAG,GAAG,GAAG;AACxB,QAAI;AACJ,QAAI,aAAa;AACf,UAAI,kBAAkB,GAAG;AACvB,mBAAW,mBAAmB,IAAI,gBAAgB;AADpD,aAEO;AACL,mBAAW,mBAAmB,IAAI,gBAAgB;AAJrC;AAAjB,WAMO;AACL,iBAAW;AA/M6D;AAkN1E,QAAI,MAAM;QAAG;AACb,QAAI;AACJ,QAAI,qBAAqB,GAAG;AAC1B,oBAAc,WAAW,GAAG,gBAAgB,WAAW,GAAG;AAD5D,WAEO;AACL,oBAAc,cAAc,MAAM;AAvNsC;AA0N1E,QAAI,GAAG;AACP,WAAO,MAAM,aAAa;AAExB,UAAI,YAAY,gBACd,KAAK,IAAI,cAAc,KAAK,iBAAiB;AAC/C,WAAK,IAAI,GAAG,IAAI,kBAAkB,KAAK;AACrC,mBAAW,GAAG,OAAO;AALC;AAOxB,eAAS;AAET,UAAI,qBAAqB,GAAG;AAC1B,oBAAY,WAAW;AACvB,aAAK,IAAI,GAAG,IAAI,WAAW,KAAK;AAC9B,sBAAY,WAAW,UAAU;AACjC;AAJwB;AAA5B,aAMO;AACL,aAAK,IAAI,GAAG,IAAI,WAAW,KAAK;AAC9B,eAAK,IAAI,GAAG,IAAI,kBAAkB,KAAK;AACrC,wBAAY,WAAW;AACvB,gBAAI,UAAU;AACd,gBAAI,UAAU;AACd,iBAAK,IAAI,GAAG,IAAI,GAAG,KAAK;AACtB,mBAAK,IAAI,GAAG,IAAI,GAAG,KAAK;AACtB,0BAAU,WAAW,UAAU,KAAK,GAAG;AAFnB;AAJa;AADT;AAW9B;AAZG;AAfiB;AAgCxB,kBAAY;AACZ,mBAAa,mBAAmB,MAAM;AAGtC,UAAI,cAAc,WAAW,SAAS;AACpC,wBAAK,uDACA,WAAW;AAChB,iBAAS,WAAW;AAvCE;AAyCxB,UAAI,SAAS,cAAc,WAAW;AACtC,UAAI,CAAC,UAAU,UAAU,QAAQ;AAC/B,cAAM,IAAI,UAAU;AA3CE;AA8CxB,UAAI,UAAU,UAAU,UAAU,QAAQ;AACxC,kBAAU;AADZ,aAEO;AACL;AAjDsB;AA3NgD;AAgR1E,iBAAa,mBAAmB,MAAM;AAGtC,QAAI,cAAc,WAAW,SAAS;AACpC,sBAAK,wDACA,WAAW;AAChB,eAAS,WAAW;AAtRoD;AAyR1E,WAAO,SAAS;AAhWyB;AAwW3C,WAAS,mBAAmB,WAAW,mBAAmB,GAAG;AAC3D,QAAI,KAAK,UAAU;QAAmB,YAAY,UAAU;AAC5D,QAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;AAChC,QAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;AAChC,QAAI;AAEJ,QAAI,CAAC,IAAI;AACP,YAAM,IAAI,UAAU;AAPqC;AAW3D,SAAK,IAAI,MAAM,GAAG,MAAM,IAAI,OAAO,GAAG;AAEpC,WAAK,UAAU,oBAAoB;AACnC,WAAK,UAAU,oBAAoB,MAAM;AACzC,WAAK,UAAU,oBAAoB,MAAM;AACzC,WAAK,UAAU,oBAAoB,MAAM;AACzC,WAAK,UAAU,oBAAoB,MAAM;AACzC,WAAK,UAAU,oBAAoB,MAAM;AACzC,WAAK,UAAU,oBAAoB,MAAM;AACzC,WAAK,UAAU,oBAAoB,MAAM;AAGzC,YAAM,GAAG;AAGT,UAAK,MAAK,KAAK,KAAK,KAAK,KAAK,KAAK,QAAQ,GAAG;AAC5C,YAAK,WAAW,KAAK,OAAQ;AAC7B,UAAE,OAAO;AACT,UAAE,MAAM,KAAK;AACb,UAAE,MAAM,KAAK;AACb,UAAE,MAAM,KAAK;AACb,UAAE,MAAM,KAAK;AACb,UAAE,MAAM,KAAK;AACb,UAAE,MAAM,KAAK;AACb,UAAE,MAAM,KAAK;AACb;AAzBkC;AA4BpC,YAAM,GAAG,MAAM;AACf,YAAM,GAAG,MAAM;AACf,YAAM,GAAG,MAAM;AACf,YAAM,GAAG,MAAM;AACf,YAAM,GAAG,MAAM;AACf,YAAM,GAAG,MAAM;AACf,YAAM,GAAG,MAAM;AAGf,WAAM,WAAW,KAAK,OAAQ;AAC9B,WAAM,WAAW,KAAK,OAAQ;AAC9B,WAAK;AACL,WAAK;AACL,WAAoB,mBAAK,MAAM,OAAQ;AACvC,WAAoB,mBAAK,MAAM,OAAQ;AACvC,WAAK,MAAM;AACX,WAAK,MAAM;AAGX,WAAM,KAAK,KAAK,KAAM;AACtB,WAAK,KAAK;AACV,UAAM,KAAK,UAAU,KAAK,UAAU,OAAQ;AAC5C,WAAM,KAAK,UAAU,KAAK,UAAU,OAAQ;AAC5C,WAAK;AACL,WAAM,KAAK,KAAK,KAAM;AACtB,WAAK,KAAK;AACV,WAAM,KAAK,KAAK,KAAM;AACtB,WAAK,KAAK;AAGV,WAAM,KAAK,KAAK,KAAM;AACtB,WAAK,KAAK;AACV,WAAM,KAAK,KAAK,KAAM;AACtB,WAAK,KAAK;AACV,UAAM,KAAK,UAAU,KAAK,UAAU,QAAS;AAC7C,WAAM,KAAK,UAAU,KAAK,UAAU,QAAS;AAC7C,WAAK;AACL,UAAM,KAAK,UAAU,KAAK,UAAU,QAAS;AAC7C,WAAM,KAAK,UAAU,KAAK,UAAU,QAAS;AAC7C,WAAK;AAGL,QAAE,OAAO,KAAK;AACd,QAAE,MAAM,KAAK,KAAK;AAClB,QAAE,MAAM,KAAK,KAAK;AAClB,QAAE,MAAM,KAAK,KAAK;AAClB,QAAE,MAAM,KAAK,KAAK;AAClB,QAAE,MAAM,KAAK,KAAK;AAClB,QAAE,MAAM,KAAK,KAAK;AAClB,QAAE,MAAM,KAAK,KAAK;AAxFuC;AA4F3D,SAAK,IAAI,MAAM,GAAG,MAAM,GAAG,EAAE,KAAK;AAChC,WAAK,EAAE;AACP,WAAK,EAAE,MAAO;AACd,WAAK,EAAE,MAAM;AACb,WAAK,EAAE,MAAM;AACb,WAAK,EAAE,MAAM;AACb,WAAK,EAAE,MAAM;AACb,WAAK,EAAE,MAAM;AACb,WAAK,EAAE,MAAM;AAGb,UAAK,MAAK,KAAK,KAAK,KAAK,KAAK,KAAK,QAAQ,GAAG;AAC5C,YAAK,WAAW,KAAK,QAAS;AAE9B,YAAK,IAAI,CAAC,OAAQ,IAAK,KAAK,OAAQ,MAAO,IAAI,QAAS;AACxD,kBAAU,oBAAoB,OAAO;AACrC,kBAAU,oBAAoB,MAAO,KAAK;AAC1C,kBAAU,oBAAoB,MAAM,MAAM;AAC1C,kBAAU,oBAAoB,MAAM,MAAM;AAC1C,kBAAU,oBAAoB,MAAM,MAAM;AAC1C,kBAAU,oBAAoB,MAAM,MAAM;AAC1C,kBAAU,oBAAoB,MAAM,MAAM;AAC1C,kBAAU,oBAAoB,MAAM,MAAM;AAC1C;AAvB8B;AA2BhC,WAAM,WAAW,KAAK,QAAS;AAC/B,WAAM,WAAW,KAAK,QAAS;AAC/B,WAAK;AACL,WAAK;AACL,WAAoB,mBAAK,MAAM,QAAS;AACxC,WAAoB,mBAAK,MAAM,QAAS;AACxC,WAAK;AACL,WAAK;AAKL,WAAM,CAAC,KAAK,KAAK,KAAM,KAAK;AAC5B,WAAK,KAAK;AACV,UAAM,KAAK,UAAU,KAAK,UAAU,QAAS;AAC7C,WAAM,KAAK,UAAU,KAAK,UAAU,QAAS;AAC7C,WAAK;AACL,WAAM,KAAK,KAAK,KAAM;AACtB,WAAK,KAAK;AACV,WAAM,KAAK,KAAK,KAAM;AACtB,WAAK,KAAK;AAGV,WAAM,KAAK,KAAK,KAAM;AACtB,WAAK,KAAK;AACV,WAAM,KAAK,KAAK,KAAM;AACtB,WAAK,KAAK;AACV,UAAM,KAAK,UAAU,KAAK,UAAU,QAAS;AAC7C,WAAM,KAAK,UAAU,KAAK,UAAU,QAAS;AAC7C,WAAK;AACL,UAAM,KAAK,UAAU,KAAK,UAAU,QAAS;AAC7C,WAAM,KAAK,UAAU,KAAK,UAAU,QAAS;AAC7C,WAAK;AAGL,WAAK,KAAK;AACV,WAAK,KAAK;AACV,WAAK,KAAK;AACV,WAAK,KAAK;AACV,WAAK,KAAK;AACV,WAAK,KAAK;AACV,WAAK,KAAK;AACV,WAAK,KAAK;AAGV,WAAM,KAAK,KAAM,IAAK,MAAM,OAAQ,MAAM,MAAM;AAChD,WAAM,KAAK,KAAM,IAAK,MAAM,OAAQ,MAAM,MAAM;AAChD,WAAM,KAAK,KAAM,IAAK,MAAM,OAAQ,MAAM,MAAM;AAChD,WAAM,KAAK,KAAM,IAAK,MAAM,OAAQ,MAAM,MAAM;AAChD,WAAM,KAAK,KAAM,IAAK,MAAM,OAAQ,MAAM,MAAM;AAChD,WAAM,KAAK,KAAM,IAAK,MAAM,OAAQ,MAAM,MAAM;AAChD,WAAM,KAAK,KAAM,IAAK,MAAM,OAAQ,MAAM,MAAM;AAChD,WAAM,KAAK,KAAM,IAAK,MAAM,OAAQ,MAAM,MAAM;AAGhD,gBAAU,oBAAoB,OAAO;AACrC,gBAAU,oBAAoB,MAAO,KAAK;AAC1C,gBAAU,oBAAoB,MAAM,MAAM;AAC1C,gBAAU,oBAAoB,MAAM,MAAM;AAC1C,gBAAU,oBAAoB,MAAM,MAAM;AAC1C,gBAAU,oBAAoB,MAAM,MAAM;AAC1C,gBAAU,oBAAoB,MAAM,MAAM;AAC1C,gBAAU,oBAAoB,MAAM,MAAM;AArLe;AAxWlB;AAiiB3C,WAAS,mBAAmB,OAAO,WAAW;AAC5C,QAAI,gBAAgB,UAAU;AAC9B,QAAI,kBAAkB,UAAU;AAChC,QAAI,oBAAoB,IAAI,WAAW;AAEvC,SAAK,IAAI,WAAW,GAAG,WAAW,iBAAiB,YAAY;AAC7D,WAAK,IAAI,WAAW,GAAG,WAAW,eAAe,YAAY;AAC3D,YAAI,SAAS,qBAAqB,WAAW,UAAU;AACvD,2BAAmB,WAAW,QAAQ;AAHqB;AALnB;AAW5C,WAAO,UAAU;AA5iBwB;AA+iB3C,WAAS,YAAY,GAAG;AACtB,WAAO,KAAK,IAAI,IAAI,KAAK,MAAM,MAAM;AAhjBI;AAmjB3C,WAAS,mBAAmB,MAAM,YAAY,UAAU;AACtD,aAAS,WAAW,KAAK;AACvB,aAAQ,KAAK,QAAQ,IAAK,KAAK,MAAM;AAFe;AAKtD,QAAI,SAAS,KAAK,SAAS;AAC3B,QAAI,SAAS,WAAW,aAAa,WAAW;AAEhD,QAAI,cAAc,QAAQ;AACxB,aAAO;AAT6C;AAWtD,QAAI,gBAAgB,WAAW;AAC/B,QAAI,iBAAiB,UAAU,iBAAiB,QAAQ;AACtD;AACE,iBAAS;AACT,gBAAQ;AACR,gBAAQ;AAHH;AAb6C;AAmBtD,QAAI,YAAY,WAAW;AAC3B,WAAS,eAAa,UAAU,aAAa,SAAS;AACpD,UAAI,EAAE,UAAU,QAAQ;AACtB,eAAO;AAF2C;AAIpD,kBAAY,WAAW;AAxB6B;AA0BtD;AACE,eAAS,cAAc,SAAS;AAChC,cAAQ;AACR,cAAQ;AAHH;AA7kBkC;AAolB3C,YAAU;AACR,WAAO,SAAS,MAAM,MAAM;AAE1B,eAAS,aAAa;AACpB,YAAI,QAAS,KAAK,WAAW,IAAK,KAAK,SAAS;AAChD,kBAAU;AACV,eAAO;AALiB;AAQ1B,eAAS,gBAAgB;AACvB,YAAI,SAAS;AACb,YAAI,YAAY,SAAS,SAAS;AAElC,YAAI,aAAa,mBAAmB,MAAM,WAAW;AACrD,YAAI,cAAc,WAAW,SAAS;AACpC,0BAAK,uDACA,WAAW;AAChB,sBAAY,WAAW;AARF;AAWvB,YAAI,QAAQ,KAAK,SAAS,QAAQ;AAClC,kBAAU,MAAM;AAChB,eAAO;AArBiB;AAwB1B,eAAS,kBAAkB,OAAO;AAChC,YAAI,cAAc,KAAK,KAAK,MAAM,iBAAiB,IAAI,MAAM;AAC7D,YAAI,gBAAgB,KAAK,KAAK,MAAM,YAAY,IAAI,MAAM;AAC1D,aAAK,IAAI,IAAI,GAAG,IAAI,MAAM,WAAW,QAAQ,KAAK;AAChD,sBAAY,MAAM,WAAW;AAC7B,cAAI,gBAAgB,KAAK,KAAK,KAAK,KAAK,MAAM,iBAAiB,KACjC,UAAU,IAAI,MAAM;AAClD,cAAI,kBAAkB,KAAK,KAAK,KAAK,KAAK,MAAM,YAAY,KAC5B,UAAU,IAAI,MAAM;AACpD,cAAI,sBAAsB,cAAc,UAAU;AAClD,cAAI,wBAAwB,gBAAgB,UAAU;AAEtD,cAAI,mBAAmB,KACM,+CAAsB;AACnD,oBAAU,YAAY,IAAI,WAAW;AACrC,oBAAU,gBAAgB;AAC1B,oBAAU,kBAAkB;AAhBE;AAkBhC,cAAM,cAAc;AACpB,cAAM,gBAAgB;AA3CE;AA8C1B,UAAI,SAAS;AACb,UAAI,OAAO;AACX,UAAI,QAAQ;AACZ,UAAI,OAAO;AACX,UAAI,qBAAqB;AACzB,UAAI,kBAAkB;UAAI,kBAAkB;AAC5C,UAAI,aAAa;AACjB,UAAI,eAAe,QAAQ;AACzB,cAAM,IAAI,UAAU;AAtDI;AAyD1B,mBAAa;AACb,aAAO,eAAe,QAAQ;AAC5B,YAAI,GAAG,GAAG;AACV,gBAAQ;AACN,eAAK;AACL,eAAK;AACL,eAAK;AACL,eAAK;AACL,eAAK;AACL,eAAK;AACL,eAAK;AACL,eAAK;AACL,eAAK;AACL,eAAK;AACL,eAAK;AACL,eAAK;AACL,eAAK;AACL,eAAK;AACL,eAAK;AACL,eAAK;AACL,eAAK;AACH,gBAAI,UAAU;AAEd,gBAAI,eAAe,QAAQ;AACzB,kBAAI,QAAQ,OAAO,QAAQ,QAAQ,OAAO,QACtC,QAAQ,OAAO,QAAQ,QAAQ,OAAO,QACtC,QAAQ,OAAO,GAAG;AACpB;AACE;AAAW,2BAAO,QAAQ;AAAI,2BAAO,QAAQ;AAApC;AACT,gCAAc,QAAQ;AACtB,4BAAW,QAAQ,MAAM,IAAK,QAAQ;AACtC,4BAAW,QAAQ,OAAO,IAAK,QAAQ;AACvC,8BAAY,QAAQ;AACpB,+BAAa,QAAQ;AACrB,6BAAW,QAAQ,SAAS,IAAI,KACJ,IAAI,QAAQ,MAAM,QAAQ;AARjD;AAJgB;AAH7B;AAoBE,gBAAI,eAAe,QAAQ;AACzB,kBAAI,QAAQ,OAAO,QAAQ,QAAQ,OAAO,QACtC,QAAQ,OAAO,QAAQ,QAAQ,OAAO,QACtC,QAAQ,OAAO,MAAM;AACvB;AACE,2BAAU,QAAQ,MAAM,IAAK,QAAQ;AACrC,0BAAS,QAAQ,MAAM,IAAK,QAAQ;AACpC,0BAAS,QAAQ,MAAM,IAAK,QAAQ;AACpC,iCAAe,QAAQ;AAJjB;AAJe;AApB7B;AAgCE;AAEF,eAAK;AACH,gBAAI,2BAA2B;AAC/B,gBAAI,wBAAwB,2BAA2B,SAAS;AAChE,gBAAI;AACJ,mBAAO,SAAS,uBAAuB;AACrC,kBAAI,wBAAwB,KAAK;AACjC,kBAAI,YAAY,IAAI,YAAY;AAChC,kBAAK,yBAAyB,MAAO,GAAG;AACtC,qBAAK,IAAI,GAAG,IAAI,IAAI,KAAK;AACvB,sBAAI,UAAU;AACd,4BAAU,KAAK,KAAK;AAHgB;AAAxC,yBAKY,yBAAyB,MAAO,GAAG;AAC7C,qBAAK,IAAI,GAAG,IAAI,IAAI,KAAK;AACvB,sBAAI,UAAU;AACd,4BAAU,KAAK;AAH4B;AAAxC,qBAKA;AACL,sBAAM,IAAI,UAAU;AAde;AAgBrC,iCAAmB,wBAAwB,MAAM;AApBrD;AAsBE;AAEF,eAAK;AACL,eAAK;AACL,eAAK;AACH,gBAAI,OAAO;AACT,oBAAM,IAAI,UAAU;AAFxB;AAIE;AACA,oBAAQ;AACR,kBAAM,WAAY,eAAe;AACjC,kBAAM,cAAe,eAAe;AACpC,kBAAM,YAAY,KAAK;AACvB,kBAAM,YAAY;AAClB,kBAAM,iBAAiB;AACvB,kBAAM,aAAa;AACnB,kBAAM,eAAe;AACrB,gBAAI,kBAAkB,KAAK;gBAAW;AACtC,gBAAI,OAAO;gBAAG,OAAO;AACrB,iBAAK,IAAI,GAAG,IAAI,iBAAiB,KAAK;AACpC,4BAAc,KAAK;AACnB,kBAAI,IAAI,KAAK,SAAS,MAAM;AAC5B,kBAAI,IAAI,KAAK,SAAS,KAAK;AAC3B,kBAAI,OAAO,GAAG;AACZ,uBAAO;AAL2B;AAOpC,kBAAI,OAAO,GAAG;AACZ,uBAAO;AAR2B;AAUpC,kBAAI,MAAM,KAAK,SAAS;AACxB,wBAAU,WAAW;AACnB;AACA;AACA,gCAAgB;AAChB,mCAAmB;AAJK,eAAtB;AAMJ,oBAAM,aAAa,eAAe,IAAI;AACtC,wBAAU;AAjCd;AAmCE,kBAAM,OAAO;AACb,kBAAM,OAAO;AACb,8BAAkB;AAClB;AAEF,eAAK;AACH,gBAAI,gBAAgB;AACpB,iBAAK,IAAI,GAAG,IAAI,gBAAgB;AAC9B,kBAAI,mBAAmB,KAAK;AAC5B,kBAAI,cAAc,IAAI,WAAW;AACjC,kBAAI,gBAAgB;AACpB,mBAAK,IAAI,GAAG,IAAI,IAAI,KAAK,UAAU;AACjC,iCAAkB,YAAY,KAAK,KAAK;AALZ;AAO9B,kBAAI,gBAAgB,IAAI,WAAW;AACnC,mBAAK,IAAI,GAAG,IAAI,eAAe,KAAK,UAAU;AAC5C,8BAAc,KAAK,KAAK;AATI;AAW9B,mBAAK,KAAK;AAET,eAAC,oBAAoB,MAAO,IAC3B,kBAAkB,iBAAiB,mBAAmB,MACtD,kBAAkB,aAAa;AAjBrC;AAmBE;AAEF,eAAK;AACH;AACA,4BAAgB;AAChB;AAEF,eAAK;AACH;AACA,gBAAI,iBAAiB,KAAK;AAC1B,gBAAI,aAAa;gBAAI;AACrB,iBAAK,IAAI,GAAG,IAAI,gBAAgB,KAAK;AACnC,kBAAI,iBAAiB,MAAM,aAAa,KAAK;AAC7C,0BAAY,MAAM,WAAW;AAC7B,kBAAI,YAAY,KAAK;AACrB,wBAAU,iBAAiB,gBAAgB,aAAa;AACxD,wBAAU,iBAAiB,gBAAgB,YAAY;AACvD,yBAAW,KAAK;AAVpB;AAYE,gBAAI,gBAAgB,KAAK;AACzB,gBAAI,cAAc,KAAK;AACvB,gBAAI,0BAA0B,KAAK;AACnC,gBAAI,YAAY,WAAW,MAAM,QAC/B,OAAO,YAAY,eACnB,eAAe,aACf,2BAA2B,GAAG,0BAA0B;AAC1D,sBAAU;AACV;AAEF,eAAK;AACH,gBAAI,KAAK,YAAY,MAAM;AACzB;AAFJ;AAIE;AAEF;AACE,gBAAI,KAAK,SAAS,OAAO,QACrB,KAAK,SAAS,MAAM,QAAQ,KAAK,SAAS,MAAM,MAAM;AAGxD,wBAAU;AACV;AANJ;AAQE,kBAAM,IAAI,UAAU,oBAAoB,WAAW,SAAS;;AAEhE,qBAAa;AAjPW;AAoP1B,WAAK,QAAQ,MAAM;AACnB,WAAK,SAAS,MAAM;AACpB,WAAK,OAAO;AACZ,WAAK,QAAQ;AACb,WAAK,aAAa;AAClB,WAAK,IAAI,GAAG,IAAI,MAAM,WAAW,QAAQ,KAAK;AAC5C,oBAAY,MAAM,WAAW;AAK7B,YAAI,oBAAoB,mBAAmB,UAAU;AACrD,YAAI,mBAAmB;AACrB,oBAAU,oBAAoB;AARY;AAW5C,aAAK,WAAW;AACd,kBAAQ,mBAAmB,OAAO;AAClC,kBAAQ,UAAU,IAAI,MAAM;AAC5B,kBAAQ,UAAU,IAAI,MAAM;AAC5B,yBAAe,UAAU;AACzB,2BAAiB,UAAU;AALR;AApQG;AA4Q1B,WAAK,gBAAgB,KAAK,WAAW;AA7QnB;AAgRpB,6BAAyB,SAAS,uBAAuB,OAAO,QAAQ;AACtE,UAAI,SAAS,KAAK,QAAQ;UAAO,SAAS,KAAK,SAAS;AAExD,UAAI,WAAW,iBAAiB,iBAAiB;AACjD,UAAI,GAAG,GAAG,GAAG,GAAG;AAChB,UAAI;AACJ,UAAI,SAAS;AACb,UAAI;AACJ,UAAI,gBAAgB,KAAK,WAAW;AACpC,UAAI,aAAa,QAAQ,SAAS;AAClC,UAAI,OAAO,IAAI,WAAW;AAC1B,UAAI,oBAAoB,IAAI,YAAY;AACxC,UAAI,WAAW;AAEf,WAAK,IAAI,GAAG,IAAI,eAAe,KAAK;AAClC,oBAAY,KAAK,WAAW;AAC5B,0BAAkB,UAAU,SAAS;AACrC,0BAAkB,UAAU,SAAS;AACrC,iBAAS;AACT,iBAAS,UAAU;AACnB,4BAAqB,UAAU,gBAAgB,KAAM;AAErD,aAAK,IAAI,GAAG,IAAI,OAAO,KAAK;AAC1B,cAAI,IAAK,IAAI;AACb,4BAAkB,KAAO,KAAI,aAAa,IAAM,IAAI;AAVpB;AAalC,aAAK,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC3B,cAAI,IAAK,IAAI;AACb,kBAA6B,yBAAI,YAAc,KAAI,MAAM;AACzD,eAAK,IAAI,GAAG,IAAI,OAAO,KAAK;AAC1B,iBAAK,UAAU,OAAO,QAAQ,kBAAkB;AAChD,sBAAU;AALe;AAbK;AAdkC;AAsCtE,UAAI,YAAY,KAAK;AACrB,UAAI,WAAW;AACb,aAAK,IAAI,GAAG,IAAI,aAAa;AAC3B,eAAK,IAAI,GAAG,IAAI,GAAG,IAAI,eAAe,KAAK,KAAK,KAAK,GAAG;AACtD,iBAAK,KAAM,CAAC,KAAK,KAAK,UAAU,MAAO,KAAK,UAAU,IAAI;AAFjC;AADhB;AAvCuD;AA8CtE,aAAO;AA9TW;AAiUpB,kEAA2B;AACzB,UAAI,KAAK,OAAO;AAEd,eAAO,CAAC,CAAC,KAAK,MAAM;AAHG;AAKzB,UAAI,KAAK,kBAAkB,GAAG;AAC5B,YAAI,KAAK,mBAAmB,GAAG;AAI7B,iBAAO;AALmB;AAO5B,eAAO;AAZgB;AAezB,UAAI,KAAK,mBAAmB,GAAG;AAI7B,eAAO;AAnBgB;AAqBzB,aAAO;AAtVW;;AAyVpB,sBAAkB,SAAS,gBAAgB,MAAM;AAC/C,UAAI,GAAG,IAAI;AACX,WAAK,IAAI,IAAI,GAAG,SAAS,KAAK,QAAQ,IAAI,QAAQ,KAAK,GAAG;AACxD,YAAK,KAAK;AACV,aAAK,KAAK,IAAI;AACd,aAAK,KAAK,IAAI;AACd,aAAK,KAAS,YAAY,IAAI,UAAU,QAAQ;AAChD,aAAK,IAAI,KAAK,YAAY,IAAI,UAAU,QAAQ,KAAK,QAAQ;AAC7D,aAAK,IAAI,KAAK,YAAY,IAAI,UAAU,QAAQ;AARH;AAU/C,aAAO;AAnWW;AAsWpB,uBAAmB,SAAS,iBAAiB,MAAM;AACjD,UAAI,GAAG,IAAI,IAAI;AACf,UAAI,SAAS;AACb,WAAK,IAAI,IAAI,GAAG,SAAS,KAAK,QAAQ,IAAI,QAAQ,KAAK,GAAG;AACxD,YAAK,KAAK;AACV,aAAK,KAAK,IAAI;AACd,aAAK,KAAK,IAAI;AACd,YAAI,KAAK,IAAI;AAEb,YAAI,IAAI,CAAC,kBACD,OAAC,sBAAsB,KAAK,uBAAuB,KACnD,qBAAqB,IAAI,sBAAsB,IAC/C,qBACA,OAAC,uBAAuB,KAAK,uBAAuB,IACpD,sBAAsB,IAAI,oBAC3B,4BAAuB,IAAI,sBAAsB,IACjD,oBACA,MAAC,uBAAuB,IAAI;AAEnC,YAAI,IAAI,mBACA,4BAAsB,KAAK,uBAAuB,KAClD,uBAAuB,IAAI,uBAAuB,IAClD,qBACA,OAAC,uBAAuB,KAAK,sBAAsB,IACnD,uBAAuB,IAAI,qBAC5B,2BAAsB,IAAI,sBAAsB,IAChD,oBACA,MAAC,uBAAuB,IAAI;AAEnC,YAAI,IAAI,CAAC,kBACD,OAAC,uBAAuB,KAAK,sBAAsB,KACnD,qBAAqB,IAAI,sBAAsB,IAC/C,qBACA,OAAC,sBAAsB,KAAK,uBAAuB,IACnD,uBAAuB,IAAI,qBAC5B,2BAAsB,IAAI,sBAAsB,IAChD,qBACA,MAAC,uBAAuB,IAAI;AAEnC,aAAK,YAAY,YAAY;AAC7B,aAAK,YAAY,YAAY;AAC7B,aAAK,YAAY,YAAY;AAzCkB;AA2CjD,aAAO;AAjZW;AAoZpB,wBAAoB,SAAS,kBAAkB,MAAM;AACnD,UAAI,GAAG,IAAI;AACX,WAAK,IAAI,IAAI,GAAG,SAAS,KAAK,QAAQ,IAAI,QAAQ,KAAK,GAAG;AACxD,YAAK,KAAK;AACV,aAAK,KAAK,IAAI;AACd,aAAK,KAAK,IAAI;AACd,aAAK,KAAS,YAAY,UAAU,IAAI,QAAQ;AAChD,aAAK,IAAI,KAAK,YAAY,UAAU,IAAI,QAAQ,KAAK,QAAQ;AAC7D,aAAK,IAAI,KAAK,YAAY,UAAU,IAAI,QAAQ;AARC;AAWnD,aAAO;AA/ZW;AAkapB,uBAAmB,SAAS,iBAAiB,MAAM;AACjD,UAAI,GAAG,GAAG,GAAG;AACb,UAAI,SAAS;AACb,UAAI,MAAM,CAAC,MAAM,MAAM;AACvB,UAAI,QAAQ,IAAI,MAAM;AACtB,WAAK,IAAI,IAAI,GAAG,SAAS,KAAK,QAAQ,IAAI,QAAQ,KAAK,GAAG;AACxD,YAAI,KAAK;AACT,YAAI,KAAK,IAAI;AACb,YAAI,KAAK,IAAI;AACb,YAAI,KAAK,IAAI;AAEb,YAAI,IACG,MAAC,oBAAoB,IAAI,oBAAoB,IAC7C,oBAAoB,IAAI,qBAAqB,IAC7C,oBACA,0BAAqB,IAAI,qBAAqB,IAC9C,qBAAqB,IAAI,sBACzB,MAAC,qBAAqB,IAAI,qBAAqB,IAC/C,qBACA,yBAAoB,IAAI;AAC/B,YAAI,IACG,yBAAoB,IAAI,qBAAqB,IAC7C,oBAAoB,IAAI,qBAAqB,IAC7C,sBACA,MAAC,qBAAqB,IAAI,qBAAqB,IAC/C,qBAAqB,IAAI,qBACzB,yBAAoB,IAAI,kBAAkB,IAC1C,qBACA,0BAAqB,IAAI;AAChC,YAAI,IACG,0BAAqB,IAAI,oBAAoB,IAC7C,oBAAoB,IAAI,sBAAsB,IAC9C,qBACA,yBAAoB,IAAI,oBAAoB,IAC5C,qBAAqB,IAAI,qBACzB,2BAAsB,IAAI,qBAAqB,IAC/C,qBACA,yBAAoB,IAAI;AAE/B,aAAK,YAAY,KAAK,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,IAAI,QAAQ;AACjE,aAAK,YAAY,KAAK,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,IAAI,QAAQ;AACjE,aAAK,YAAY,KAAK,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,IAAI,QAAQ;AAzClB;AA2CjD,aAAO;AA7cW;AAgdpB,aAAS,SAAS,QAAQ,OAAO,QAAQ,gBAAgB;AACvD,UAAI,KAAK,gBAAgB,GAAG;AAC1B,cAAM,IAAI,UAAU;AAFiC;AAKvD,UAAI,OAAO,KAAK,wBAAwB,OAAO;AAE/C,UAAI,KAAK,kBAAkB,KAAK,gBAAgB;AAC9C,YAAI,aAAa,KAAK;AACtB,YAAI,UAAU,IAAI,WAAW,aAAa;AAC1C,YAAI,SAAS;AACb,aAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAAK;AACnC,cAAI,YAAY,KAAK;AACrB,kBAAQ,YAAY;AACpB,kBAAQ,YAAY;AACpB,kBAAQ,YAAY;AARwB;AAU9C,eAAO;AAVT,iBAWW,KAAK,kBAAkB,KAAK,KAAK,4BAA4B;AACtE,eAAO,KAAK,iBAAiB;AADxB,aAEA,IAAI,KAAK,kBAAkB,GAAG;AACnC,YAAI,KAAK,4BAA4B;AACnC,cAAI,gBAAgB;AAClB,mBAAO,KAAK,kBAAkB;AAFG;AAInC,iBAAO,KAAK,mBAAmB;AAJjC,eAKO,IAAI,gBAAgB;AACzB,iBAAO,KAAK,kBAAkB;AAPG;AApBkB;AA8BvD,aAAO;AA9eW;AAAA;AAkftB,SAAO;AAGT,CAzkCiB;QA0kCf,sB;;;;;;;;;;;;;;ACtmCoC;;AAKtC,IAAI,8CAAmC,UAAU,GAAG;AAClD,IAAE,aAAa;AACf,IAAE,kBAAkB;AACpB,IAAE,yBAAyB;AAC3B,IAAE,qBAAqB;AACvB,IAAE,gDAAqC,UAAU,GAAG;AAClD,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,cAAc;AAChB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,cAAc;AAChB,MAAE,QAAQ;AACV,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,eAAe;AACjB,MAAE,SAAS;AACX,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,UAAU;AACZ,MAAE,cAAc;AAChB,MAAE,cAAc;AAChB,MAAE,SAAS;AACX,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,mBAAmB;AACrB,MAAE,oBAAoB;AACtB,MAAE,QAAQ;AACV,MAAE,QAAQ;AACV,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,oBAAoB;AACtB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,oBAAoB;AACtB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,oBAAoB;AACtB,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,gBAAgB;AAClB,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,UAAU;AACZ,MAAE,aAAa;AACf,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,kBAAkB;AACpB,MAAE,QAAQ;AACV,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,gBAAgB;AAClB,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,WAAW;AACb,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,SAAS;AACX,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,QAAQ;AACV,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,kBAAkB;AACpB,MAAE,WAAW;AACb,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,SAAS;AACX,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,UAAU;AA3TG;AA6TjB,IAAE,qDAA0C,UAAU,GAAG;AACvD,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,cAAc;AAChB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,cAAc;AAChB,MAAE,QAAQ;AACV,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,eAAe;AACjB,MAAE,SAAS;AACX,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,UAAU;AACZ,MAAE,cAAc;AAChB,MAAE,cAAc;AAChB,MAAE,SAAS;AACX,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,mBAAmB;AACrB,MAAE,oBAAoB;AACtB,MAAE,QAAQ;AACV,MAAE,QAAQ;AACV,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,oBAAoB;AACtB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,oBAAoB;AACtB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,oBAAoB;AACtB,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,gBAAgB;AAClB,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,UAAU;AACZ,MAAE,aAAa;AACf,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,kBAAkB;AACpB,MAAE,QAAQ;AACV,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,gBAAgB;AAClB,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,WAAW;AACb,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,SAAS;AACX,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,QAAQ;AACV,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,kBAAkB;AACpB,MAAE,WAAW;AACb,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,SAAS;AACX,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,UAAU;AA3TQ;AA6TtB,IAAE,4DAAiD,UAAU,GAAG;AAC9D,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,cAAc;AAChB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,cAAc;AAChB,MAAE,QAAQ;AACV,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,eAAe;AACjB,MAAE,SAAS;AACX,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,UAAU;AACZ,MAAE,cAAc;AAChB,MAAE,cAAc;AAChB,MAAE,SAAS;AACX,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,mBAAmB;AACrB,MAAE,oBAAoB;AACtB,MAAE,QAAQ;AACV,MAAE,QAAQ;AACV,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,oBAAoB;AACtB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,oBAAoB;AACtB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,oBAAoB;AACtB,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,gBAAgB;AAClB,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,UAAU;AACZ,MAAE,aAAa;AACf,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,kBAAkB;AACpB,MAAE,QAAQ;AACV,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,gBAAgB;AAClB,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,WAAW;AACb,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,SAAS;AACX,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,QAAQ;AACV,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,kBAAkB;AACpB,MAAE,WAAW;AACb,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,SAAS;AACX,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,UAAU;AA3Te;AA6T7B,IAAE,wDAA6C,UAAU,GAAG;AAC1D,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,cAAc;AAChB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,cAAc;AAChB,MAAE,QAAQ;AACV,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,eAAe;AACjB,MAAE,SAAS;AACX,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,UAAU;AACZ,MAAE,cAAc;AAChB,MAAE,cAAc;AAChB,MAAE,SAAS;AACX,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,mBAAmB;AACrB,MAAE,oBAAoB;AACtB,MAAE,QAAQ;AACV,MAAE,QAAQ;AACV,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,oBAAoB;AACtB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,oBAAoB;AACtB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,oBAAoB;AACtB,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,gBAAgB;AAClB,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,UAAU;AACZ,MAAE,aAAa;AACf,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,kBAAkB;AACpB,MAAE,QAAQ;AACV,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,gBAAgB;AAClB,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,WAAW;AACb,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,SAAS;AACX,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,QAAQ;AACV,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,kBAAkB;AACpB,MAAE,WAAW;AACb,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,SAAS;AACX,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,UAAU;AA3TW;AA6TzB,IAAE,6CAAkC,UAAU,GAAG;AAC/C,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,kBAAkB;AACpB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,cAAc;AAChB,MAAE,eAAe;AACjB,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,SAAS;AACX,MAAE,UAAU;AACZ,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,QAAQ;AACV,MAAE,aAAa;AACf,MAAE,QAAQ;AACV,MAAE,WAAW;AACb,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,SAAS;AACX,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,QAAQ;AACV,MAAE,SAAS;AACX,MAAE,UAAU;AACZ,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,SAAS;AACX,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,QAAQ;AACV,MAAE,aAAa;AACf,MAAE,QAAQ;AACV,MAAE,WAAW;AACb,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,SAAS;AACX,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,QAAQ;AACV,MAAE,SAAS;AACX,MAAE,UAAU;AACZ,MAAE,eAAe;AACjB,MAAE,SAAS;AACX,MAAE,gBAAgB;AAClB,MAAE,aAAa;AACf,MAAE,UAAU;AACZ,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,UAAU;AACZ,MAAE,aAAa;AACf,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,aAAa;AACf,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,oBAAoB;AACtB,MAAE,WAAW;AACb,MAAE,cAAc;AAChB,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,oBAAoB;AACtB,MAAE,gBAAgB;AAClB,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,WAAW;AACb,MAAE,oBAAoB;AACtB,MAAE,oBAAoB;AACtB,MAAE,eAAe;AACjB,MAAE,kBAAkB;AACpB,MAAE,kBAAkB;AACpB,MAAE,aAAa;AACf,MAAE,gBAAgB;AAClB,MAAE,WAAW;AACb,MAAE,cAAc;AAChB,MAAE,mBAAmB;AACrB,MAAE,oBAAoB;AACtB,MAAE,oBAAoB;AACtB,MAAE,aAAa;AACf,MAAE,aAAa;AACf,MAAE,aAAa;AACf,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,kBAAkB;AACpB,MAAE,kBAAkB;AACpB,MAAE,gBAAgB;AAClB,MAAE,mBAAmB;AACrB,MAAE,kBAAkB;AACpB,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,mBAAmB;AACrB,MAAE,eAAe;AACjB,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,mBAAmB;AACrB,MAAE,mBAAmB;AACrB,MAAE,mBAAmB;AACrB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,gBAAgB;AAClB,MAAE,cAAc;AAChB,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,kBAAkB;AACpB,MAAE,kBAAkB;AACpB,MAAE,kBAAkB;AACpB,MAAE,oBAAoB;AACtB,MAAE,oBAAoB;AACtB,MAAE,oBAAoB;AACtB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,kBAAkB;AACpB,MAAE,WAAW;AA9LD;AAgMd,IAAE,kDAAuC,UAAU,GAAG;AACpD,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,cAAc;AAChB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,cAAc;AAChB,MAAE,QAAQ;AACV,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,eAAe;AACjB,MAAE,SAAS;AACX,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,UAAU;AACZ,MAAE,cAAc;AAChB,MAAE,cAAc;AAChB,MAAE,SAAS;AACX,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,mBAAmB;AACrB,MAAE,oBAAoB;AACtB,MAAE,QAAQ;AACV,MAAE,QAAQ;AACV,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,oBAAoB;AACtB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,oBAAoB;AACtB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,oBAAoB;AACtB,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,gBAAgB;AAClB,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,UAAU;AACZ,MAAE,aAAa;AACf,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,kBAAkB;AACpB,MAAE,QAAQ;AACV,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,gBAAgB;AAClB,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,WAAW;AACb,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,SAAS;AACX,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,QAAQ;AACV,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,kBAAkB;AACpB,MAAE,WAAW;AACb,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,SAAS;AACX,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,UAAU;AA3TK;AA6TnB,IAAE,iDAAsC,UAAU,GAAG;AACnD,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,cAAc;AAChB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,cAAc;AAChB,MAAE,QAAQ;AACV,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,eAAe;AACjB,MAAE,SAAS;AACX,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,UAAU;AACZ,MAAE,cAAc;AAChB,MAAE,cAAc;AAChB,MAAE,SAAS;AACX,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,mBAAmB;AACrB,MAAE,oBAAoB;AACtB,MAAE,QAAQ;AACV,MAAE,QAAQ;AACV,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,oBAAoB;AACtB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,oBAAoB;AACtB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,oBAAoB;AACtB,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,gBAAgB;AAClB,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,UAAU;AACZ,MAAE,aAAa;AACf,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,kBAAkB;AACpB,MAAE,QAAQ;AACV,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,gBAAgB;AAClB,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,WAAW;AACb,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,SAAS;AACX,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,QAAQ;AACV,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,kBAAkB;AACpB,MAAE,WAAW;AACb,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,SAAS;AACX,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,UAAU;AA3TI;AA6TlB,IAAE,uDAA4C,UAAU,GAAG;AACzD,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,cAAc;AAChB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,cAAc;AAChB,MAAE,QAAQ;AACV,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,eAAe;AACjB,MAAE,SAAS;AACX,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,UAAU;AACZ,MAAE,cAAc;AAChB,MAAE,cAAc;AAChB,MAAE,SAAS;AACX,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,mBAAmB;AACrB,MAAE,oBAAoB;AACtB,MAAE,QAAQ;AACV,MAAE,QAAQ;AACV,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,oBAAoB;AACtB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,oBAAoB;AACtB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,oBAAoB;AACtB,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,gBAAgB;AAClB,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,UAAU;AACZ,MAAE,aAAa;AACf,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,kBAAkB;AACpB,MAAE,QAAQ;AACV,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,gBAAgB;AAClB,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,WAAW;AACb,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,SAAS;AACX,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,QAAQ;AACV,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,kBAAkB;AACpB,MAAE,WAAW;AACb,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,SAAS;AACX,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,UAAU;AA3TU;AA6TxB,IAAE,mDAAwC,UAAU,GAAG;AACrD,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,cAAc;AAChB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,UAAU;AACZ,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,cAAc;AAChB,MAAE,QAAQ;AACV,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,OAAO;AACT,MAAE,eAAe;AACjB,MAAE,SAAS;AACX,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,gBAAgB;AAClB,MAAE,UAAU;AACZ,MAAE,cAAc;AAChB,MAAE,cAAc;AAChB,MAAE,SAAS;AACX,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,mBAAmB;AACrB,MAAE,oBAAoB;AACtB,MAAE,QAAQ;AACV,MAAE,QAAQ;AACV,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,oBAAoB;AACtB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,oBAAoB;AACtB,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,oBAAoB;AACtB,MAAE,cAAc;AAChB,MAAE,iBAAiB;AACnB,MAAE,kBAAkB;AACpB,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,gBAAgB;AAClB,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,UAAU;AACZ,MAAE,aAAa;AACf,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,kBAAkB;AACpB,MAAE,QAAQ;AACV,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,QAAQ;AACV,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,WAAW;AACb,MAAE,eAAe;AACjB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,gBAAgB;AAClB,MAAE,WAAW;AACb,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,WAAW;AACb,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,iBAAiB;AACnB,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,SAAS;AACX,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,WAAW;AACb,MAAE,WAAW;AACb,MAAE,iBAAiB;AACnB,MAAE,eAAe;AACjB,MAAE,QAAQ;AACV,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,cAAc;AAChB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,eAAe;AACjB,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,mBAAmB;AACrB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,kBAAkB;AACpB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,WAAW;AACb,MAAE,YAAY;AACd,MAAE,gBAAgB;AAClB,MAAE,YAAY;AACd,MAAE,aAAa;AACf,MAAE,kBAAkB;AACpB,MAAE,WAAW;AACb,MAAE,iBAAiB;AACnB,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,gBAAgB;AAClB,MAAE,eAAe;AACjB,MAAE,eAAe;AACjB,MAAE,cAAc;AAChB,MAAE,kBAAkB;AACpB,MAAE,SAAS;AACX,MAAE,YAAY;AACd,MAAE,kBAAkB;AACpB,MAAE,iBAAiB;AACnB,MAAE,aAAa;AACf,MAAE,UAAU;AA3TM;AA6TpB,IAAE,mDAAwC,UAAU,GAAG;AACrD,MAAE,WAAW;AACb,MAAE,QAAQ;AACV,MAAE,QAAQ;AACV,MAAE,UAAU;AACZ,MAAE,QAAQ;AACV,MAAE,QAAQ;AACV,MAAE,QAAQ;AACV,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,QAAQ;AACV,MAAE,QAAQ;AACV,MAAE,QAAQ;AACV,MAAE,QAAQ;AACV,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,UAAU;AACZ,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UAAU;AACZ,MAAE,UA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","file":"pdf.worker.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"pdfjs-dist/build/pdf.worker\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"pdfjs-dist/build/pdf.worker\"] = factory();\n\telse\n\t\troot[\"pdfjs-dist/build/pdf.worker\"] = factory();\n})(this, function() {\nreturn \n\n\n// WEBPACK FOOTER //\n// webpack/universalModuleDefinition"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __w_pdfjs_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __w_pdfjs_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__w_pdfjs_require__.m = modules;\n\n \t// expose the module cache\n \t__w_pdfjs_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__w_pdfjs_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__w_pdfjs_require__.d = function(exports, name, getter) {\n \t\tif(!__w_pdfjs_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__w_pdfjs_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__w_pdfjs_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__w_pdfjs_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__w_pdfjs_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __w_pdfjs_require__(__w_pdfjs_require__.s = 35);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 709206543ea702ff19cc","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport './compatibility';\nimport { ReadableStream } from './streams_polyfill';\n\nvar globalScope =\n (typeof window !== 'undefined' && window.Math === Math) ? window :\n // eslint-disable-next-line no-undef\n (typeof global !== 'undefined' && global.Math === Math) ? global :\n (typeof self !== 'undefined' && self.Math === Math) ? self : this;\n\nvar FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];\n\nconst NativeImageDecoding = {\n NONE: 'none',\n DECODE: 'decode',\n DISPLAY: 'display',\n};\n\nvar TextRenderingMode = {\n FILL: 0,\n STROKE: 1,\n FILL_STROKE: 2,\n INVISIBLE: 3,\n FILL_ADD_TO_PATH: 4,\n STROKE_ADD_TO_PATH: 5,\n FILL_STROKE_ADD_TO_PATH: 6,\n ADD_TO_PATH: 7,\n FILL_STROKE_MASK: 3,\n ADD_TO_PATH_FLAG: 4,\n};\n\nvar ImageKind = {\n GRAYSCALE_1BPP: 1,\n RGB_24BPP: 2,\n RGBA_32BPP: 3,\n};\n\nvar AnnotationType = {\n TEXT: 1,\n LINK: 2,\n FREETEXT: 3,\n LINE: 4,\n SQUARE: 5,\n CIRCLE: 6,\n POLYGON: 7,\n POLYLINE: 8,\n HIGHLIGHT: 9,\n UNDERLINE: 10,\n SQUIGGLY: 11,\n STRIKEOUT: 12,\n STAMP: 13,\n CARET: 14,\n INK: 15,\n POPUP: 16,\n FILEATTACHMENT: 17,\n SOUND: 18,\n MOVIE: 19,\n WIDGET: 20,\n SCREEN: 21,\n PRINTERMARK: 22,\n TRAPNET: 23,\n WATERMARK: 24,\n THREED: 25,\n REDACT: 26,\n};\n\nvar AnnotationFlag = {\n INVISIBLE: 0x01,\n HIDDEN: 0x02,\n PRINT: 0x04,\n NOZOOM: 0x08,\n NOROTATE: 0x10,\n NOVIEW: 0x20,\n READONLY: 0x40,\n LOCKED: 0x80,\n TOGGLENOVIEW: 0x100,\n LOCKEDCONTENTS: 0x200,\n};\n\nvar AnnotationFieldFlag = {\n READONLY: 0x0000001,\n REQUIRED: 0x0000002,\n NOEXPORT: 0x0000004,\n MULTILINE: 0x0001000,\n PASSWORD: 0x0002000,\n NOTOGGLETOOFF: 0x0004000,\n RADIO: 0x0008000,\n PUSHBUTTON: 0x0010000,\n COMBO: 0x0020000,\n EDIT: 0x0040000,\n SORT: 0x0080000,\n FILESELECT: 0x0100000,\n MULTISELECT: 0x0200000,\n DONOTSPELLCHECK: 0x0400000,\n DONOTSCROLL: 0x0800000,\n COMB: 0x1000000,\n RICHTEXT: 0x2000000,\n RADIOSINUNISON: 0x2000000,\n COMMITONSELCHANGE: 0x4000000,\n};\n\nvar AnnotationBorderStyleType = {\n SOLID: 1,\n DASHED: 2,\n BEVELED: 3,\n INSET: 4,\n UNDERLINE: 5,\n};\n\nvar StreamType = {\n UNKNOWN: 0,\n FLATE: 1,\n LZW: 2,\n DCT: 3,\n JPX: 4,\n JBIG: 5,\n A85: 6,\n AHX: 7,\n CCF: 8,\n RL: 9,\n};\n\nvar FontType = {\n UNKNOWN: 0,\n TYPE1: 1,\n TYPE1C: 2,\n CIDFONTTYPE0: 3,\n CIDFONTTYPE0C: 4,\n TRUETYPE: 5,\n CIDFONTTYPE2: 6,\n TYPE3: 7,\n OPENTYPE: 8,\n TYPE0: 9,\n MMTYPE1: 10,\n};\n\nvar VERBOSITY_LEVELS = {\n errors: 0,\n warnings: 1,\n infos: 5,\n};\n\nvar CMapCompressionType = {\n NONE: 0,\n BINARY: 1,\n STREAM: 2,\n};\n\n// All the possible operations for an operator list.\nvar OPS = {\n // Intentionally start from 1 so it is easy to spot bad operators that will be\n // 0's.\n dependency: 1,\n setLineWidth: 2,\n setLineCap: 3,\n setLineJoin: 4,\n setMiterLimit: 5,\n setDash: 6,\n setRenderingIntent: 7,\n setFlatness: 8,\n setGState: 9,\n save: 10,\n restore: 11,\n transform: 12,\n moveTo: 13,\n lineTo: 14,\n curveTo: 15,\n curveTo2: 16,\n curveTo3: 17,\n closePath: 18,\n rectangle: 19,\n stroke: 20,\n closeStroke: 21,\n fill: 22,\n eoFill: 23,\n fillStroke: 24,\n eoFillStroke: 25,\n closeFillStroke: 26,\n closeEOFillStroke: 27,\n endPath: 28,\n clip: 29,\n eoClip: 30,\n beginText: 31,\n endText: 32,\n setCharSpacing: 33,\n setWordSpacing: 34,\n setHScale: 35,\n setLeading: 36,\n setFont: 37,\n setTextRenderingMode: 38,\n setTextRise: 39,\n moveText: 40,\n setLeadingMoveText: 41,\n setTextMatrix: 42,\n nextLine: 43,\n showText: 44,\n showSpacedText: 45,\n nextLineShowText: 46,\n nextLineSetSpacingShowText: 47,\n setCharWidth: 48,\n setCharWidthAndBounds: 49,\n setStrokeColorSpace: 50,\n setFillColorSpace: 51,\n setStrokeColor: 52,\n setStrokeColorN: 53,\n setFillColor: 54,\n setFillColorN: 55,\n setStrokeGray: 56,\n setFillGray: 57,\n setStrokeRGBColor: 58,\n setFillRGBColor: 59,\n setStrokeCMYKColor: 60,\n setFillCMYKColor: 61,\n shadingFill: 62,\n beginInlineImage: 63,\n beginImageData: 64,\n endInlineImage: 65,\n paintXObject: 66,\n markPoint: 67,\n markPointProps: 68,\n beginMarkedContent: 69,\n beginMarkedContentProps: 70,\n endMarkedContent: 71,\n beginCompat: 72,\n endCompat: 73,\n paintFormXObjectBegin: 74,\n paintFormXObjectEnd: 75,\n beginGroup: 76,\n endGroup: 77,\n beginAnnotations: 78,\n endAnnotations: 79,\n beginAnnotation: 80,\n endAnnotation: 81,\n paintJpegXObject: 82,\n paintImageMaskXObject: 83,\n paintImageMaskXObjectGroup: 84,\n paintImageXObject: 85,\n paintInlineImageXObject: 86,\n paintInlineImageXObjectGroup: 87,\n paintImageXObjectRepeat: 88,\n paintImageMaskXObjectRepeat: 89,\n paintSolidColorImageMask: 90,\n constructPath: 91,\n};\n\nvar verbosity = VERBOSITY_LEVELS.warnings;\n\nfunction setVerbosityLevel(level) {\n verbosity = level;\n}\n\nfunction getVerbosityLevel() {\n return verbosity;\n}\n\n// A notice for devs. These are good for things that are helpful to devs, such\n// as warning that Workers were disabled, which is important to devs but not\n// end users.\nfunction info(msg) {\n if (verbosity >= VERBOSITY_LEVELS.infos) {\n console.log('Info: ' + msg);\n }\n}\n\n// Non-fatal warnings.\nfunction warn(msg) {\n if (verbosity >= VERBOSITY_LEVELS.warnings) {\n console.log('Warning: ' + msg);\n }\n}\n\n// Deprecated API function -- display regardless of the PDFJS.verbosity setting.\nfunction deprecated(details) {\n console.log('Deprecated API usage: ' + details);\n}\n\nfunction unreachable(msg) {\n throw new Error(msg);\n}\n\nfunction assert(cond, msg) {\n if (!cond) {\n unreachable(msg);\n }\n}\n\nvar UNSUPPORTED_FEATURES = {\n unknown: 'unknown',\n forms: 'forms',\n javaScript: 'javaScript',\n smask: 'smask',\n shadingPattern: 'shadingPattern',\n font: 'font',\n};\n\n// Checks if URLs have the same origin. For non-HTTP based URLs, returns false.\nfunction isSameOrigin(baseUrl, otherUrl) {\n try {\n var base = new URL(baseUrl);\n if (!base.origin || base.origin === 'null') {\n return false; // non-HTTP url\n }\n } catch (e) {\n return false;\n }\n\n var other = new URL(otherUrl, base);\n return base.origin === other.origin;\n}\n\n// Checks if URLs use one of the whitelisted protocols, e.g. to avoid XSS.\nfunction isValidProtocol(url) {\n if (!url) {\n return false;\n }\n switch (url.protocol) {\n case 'http:':\n case 'https:':\n case 'ftp:':\n case 'mailto:':\n case 'tel:':\n return true;\n default:\n return false;\n }\n}\n\n/**\n * Attempts to create a valid absolute URL (utilizing `isValidProtocol`).\n * @param {URL|string} url - An absolute, or relative, URL.\n * @param {URL|string} baseUrl - An absolute URL.\n * @returns Either a valid {URL}, or `null` otherwise.\n */\nfunction createValidAbsoluteUrl(url, baseUrl) {\n if (!url) {\n return null;\n }\n try {\n var absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url);\n if (isValidProtocol(absoluteUrl)) {\n return absoluteUrl;\n }\n } catch (ex) { /* `new URL()` will throw on incorrect data. */ }\n return null;\n}\n\nfunction shadow(obj, prop, value) {\n Object.defineProperty(obj, prop, { value,\n enumerable: true,\n configurable: true,\n writable: false, });\n return value;\n}\n\nfunction getLookupTableFactory(initializer) {\n var lookup;\n return function () {\n if (initializer) {\n lookup = Object.create(null);\n initializer(lookup);\n initializer = null;\n }\n return lookup;\n };\n}\n\nvar PasswordResponses = {\n NEED_PASSWORD: 1,\n INCORRECT_PASSWORD: 2,\n};\n\nvar PasswordException = (function PasswordExceptionClosure() {\n function PasswordException(msg, code) {\n this.name = 'PasswordException';\n this.message = msg;\n this.code = code;\n }\n\n PasswordException.prototype = new Error();\n PasswordException.constructor = PasswordException;\n\n return PasswordException;\n})();\n\nvar UnknownErrorException = (function UnknownErrorExceptionClosure() {\n function UnknownErrorException(msg, details) {\n this.name = 'UnknownErrorException';\n this.message = msg;\n this.details = details;\n }\n\n UnknownErrorException.prototype = new Error();\n UnknownErrorException.constructor = UnknownErrorException;\n\n return UnknownErrorException;\n})();\n\nvar InvalidPDFException = (function InvalidPDFExceptionClosure() {\n function InvalidPDFException(msg) {\n this.name = 'InvalidPDFException';\n this.message = msg;\n }\n\n InvalidPDFException.prototype = new Error();\n InvalidPDFException.constructor = InvalidPDFException;\n\n return InvalidPDFException;\n})();\n\nvar MissingPDFException = (function MissingPDFExceptionClosure() {\n function MissingPDFException(msg) {\n this.name = 'MissingPDFException';\n this.message = msg;\n }\n\n MissingPDFException.prototype = new Error();\n MissingPDFException.constructor = MissingPDFException;\n\n return MissingPDFException;\n})();\n\nvar UnexpectedResponseException =\n (function UnexpectedResponseExceptionClosure() {\n function UnexpectedResponseException(msg, status) {\n this.name = 'UnexpectedResponseException';\n this.message = msg;\n this.status = status;\n }\n\n UnexpectedResponseException.prototype = new Error();\n UnexpectedResponseException.constructor = UnexpectedResponseException;\n\n return UnexpectedResponseException;\n})();\n\nvar NotImplementedException = (function NotImplementedExceptionClosure() {\n function NotImplementedException(msg) {\n this.message = msg;\n }\n\n NotImplementedException.prototype = new Error();\n NotImplementedException.prototype.name = 'NotImplementedException';\n NotImplementedException.constructor = NotImplementedException;\n\n return NotImplementedException;\n})();\n\nvar MissingDataException = (function MissingDataExceptionClosure() {\n function MissingDataException(begin, end) {\n this.begin = begin;\n this.end = end;\n this.message = 'Missing data [' + begin + ', ' + end + ')';\n }\n\n MissingDataException.prototype = new Error();\n MissingDataException.prototype.name = 'MissingDataException';\n MissingDataException.constructor = MissingDataException;\n\n return MissingDataException;\n})();\n\nvar XRefParseException = (function XRefParseExceptionClosure() {\n function XRefParseException(msg) {\n this.message = msg;\n }\n\n XRefParseException.prototype = new Error();\n XRefParseException.prototype.name = 'XRefParseException';\n XRefParseException.constructor = XRefParseException;\n\n return XRefParseException;\n})();\n\n/**\n * Error caused during parsing PDF data.\n */\nlet FormatError = (function FormatErrorClosure() {\n function FormatError(msg) {\n this.message = msg;\n }\n\n FormatError.prototype = new Error();\n FormatError.prototype.name = 'FormatError';\n FormatError.constructor = FormatError;\n\n return FormatError;\n})();\n\n/**\n * Error used to indicate task cancellation.\n */\nlet AbortException = (function AbortExceptionClosure() {\n function AbortException(msg) {\n this.name = 'AbortException';\n this.message = msg;\n }\n\n AbortException.prototype = new Error();\n AbortException.constructor = AbortException;\n\n return AbortException;\n})();\n\nvar NullCharactersRegExp = /\\x00/g;\n\nfunction removeNullCharacters(str) {\n if (typeof str !== 'string') {\n warn('The argument for removeNullCharacters must be a string.');\n return str;\n }\n return str.replace(NullCharactersRegExp, '');\n}\n\nfunction bytesToString(bytes) {\n assert(bytes !== null && typeof bytes === 'object' &&\n bytes.length !== undefined, 'Invalid argument for bytesToString');\n var length = bytes.length;\n var MAX_ARGUMENT_COUNT = 8192;\n if (length < MAX_ARGUMENT_COUNT) {\n return String.fromCharCode.apply(null, bytes);\n }\n var strBuf = [];\n for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) {\n var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length);\n var chunk = bytes.subarray(i, chunkEnd);\n strBuf.push(String.fromCharCode.apply(null, chunk));\n }\n return strBuf.join('');\n}\n\nfunction stringToBytes(str) {\n assert(typeof str === 'string', 'Invalid argument for stringToBytes');\n var length = str.length;\n var bytes = new Uint8Array(length);\n for (var i = 0; i < length; ++i) {\n bytes[i] = str.charCodeAt(i) & 0xFF;\n }\n return bytes;\n}\n\n/**\n * Gets length of the array (Array, Uint8Array, or string) in bytes.\n * @param {Array|Uint8Array|string} arr\n * @returns {number}\n */\nfunction arrayByteLength(arr) {\n if (arr.length !== undefined) {\n return arr.length;\n }\n assert(arr.byteLength !== undefined);\n return arr.byteLength;\n}\n\n/**\n * Combines array items (arrays) into single Uint8Array object.\n * @param {Array} arr - the array of the arrays (Array, Uint8Array, or string).\n * @returns {Uint8Array}\n */\nfunction arraysToBytes(arr) {\n // Shortcut: if first and only item is Uint8Array, return it.\n if (arr.length === 1 && (arr[0] instanceof Uint8Array)) {\n return arr[0];\n }\n var resultLength = 0;\n var i, ii = arr.length;\n var item, itemLength;\n for (i = 0; i < ii; i++) {\n item = arr[i];\n itemLength = arrayByteLength(item);\n resultLength += itemLength;\n }\n var pos = 0;\n var data = new Uint8Array(resultLength);\n for (i = 0; i < ii; i++) {\n item = arr[i];\n if (!(item instanceof Uint8Array)) {\n if (typeof item === 'string') {\n item = stringToBytes(item);\n } else {\n item = new Uint8Array(item);\n }\n }\n itemLength = item.byteLength;\n data.set(item, pos);\n pos += itemLength;\n }\n return data;\n}\n\nfunction string32(value) {\n return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff,\n (value >> 8) & 0xff, value & 0xff);\n}\n\nfunction log2(x) {\n var n = 1, i = 0;\n while (x > n) {\n n <<= 1;\n i++;\n }\n return i;\n}\n\nfunction readInt8(data, start) {\n return (data[start] << 24) >> 24;\n}\n\nfunction readUint16(data, offset) {\n return (data[offset] << 8) | data[offset + 1];\n}\n\nfunction readUint32(data, offset) {\n return ((data[offset] << 24) | (data[offset + 1] << 16) |\n (data[offset + 2] << 8) | data[offset + 3]) >>> 0;\n}\n\n// Lazy test the endianness of the platform\n// NOTE: This will be 'true' for simulated TypedArrays\nfunction isLittleEndian() {\n var buffer8 = new Uint8Array(4);\n buffer8[0] = 1;\n var view32 = new Uint32Array(buffer8.buffer, 0, 1);\n return (view32[0] === 1);\n}\n\n// Checks if it's possible to eval JS expressions.\nfunction isEvalSupported() {\n try {\n new Function(''); // eslint-disable-line no-new, no-new-func\n return true;\n } catch (e) {\n return false;\n }\n}\n\nvar IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];\n\nvar Util = (function UtilClosure() {\n function Util() {}\n\n var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')'];\n\n // makeCssRgb() can be called thousands of times. Using |rgbBuf| avoids\n // creating many intermediate strings.\n Util.makeCssRgb = function Util_makeCssRgb(r, g, b) {\n rgbBuf[1] = r;\n rgbBuf[3] = g;\n rgbBuf[5] = b;\n return rgbBuf.join('');\n };\n\n // Concatenates two transformation matrices together and returns the result.\n Util.transform = function Util_transform(m1, m2) {\n return [\n m1[0] * m2[0] + m1[2] * m2[1],\n m1[1] * m2[0] + m1[3] * m2[1],\n m1[0] * m2[2] + m1[2] * m2[3],\n m1[1] * m2[2] + m1[3] * m2[3],\n m1[0] * m2[4] + m1[2] * m2[5] + m1[4],\n m1[1] * m2[4] + m1[3] * m2[5] + m1[5]\n ];\n };\n\n // For 2d affine transforms\n Util.applyTransform = function Util_applyTransform(p, m) {\n var xt = p[0] * m[0] + p[1] * m[2] + m[4];\n var yt = p[0] * m[1] + p[1] * m[3] + m[5];\n return [xt, yt];\n };\n\n Util.applyInverseTransform = function Util_applyInverseTransform(p, m) {\n var d = m[0] * m[3] - m[1] * m[2];\n var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;\n var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;\n return [xt, yt];\n };\n\n // Applies the transform to the rectangle and finds the minimum axially\n // aligned bounding box.\n Util.getAxialAlignedBoundingBox =\n function Util_getAxialAlignedBoundingBox(r, m) {\n\n var p1 = Util.applyTransform(r, m);\n var p2 = Util.applyTransform(r.slice(2, 4), m);\n var p3 = Util.applyTransform([r[0], r[3]], m);\n var p4 = Util.applyTransform([r[2], r[1]], m);\n return [\n Math.min(p1[0], p2[0], p3[0], p4[0]),\n Math.min(p1[1], p2[1], p3[1], p4[1]),\n Math.max(p1[0], p2[0], p3[0], p4[0]),\n Math.max(p1[1], p2[1], p3[1], p4[1])\n ];\n };\n\n Util.inverseTransform = function Util_inverseTransform(m) {\n var d = m[0] * m[3] - m[1] * m[2];\n return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d,\n (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d];\n };\n\n // Apply a generic 3d matrix M on a 3-vector v:\n // | a b c | | X |\n // | d e f | x | Y |\n // | g h i | | Z |\n // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i],\n // with v as [X,Y,Z]\n Util.apply3dTransform = function Util_apply3dTransform(m, v) {\n return [\n m[0] * v[0] + m[1] * v[1] + m[2] * v[2],\n m[3] * v[0] + m[4] * v[1] + m[5] * v[2],\n m[6] * v[0] + m[7] * v[1] + m[8] * v[2]\n ];\n };\n\n // This calculation uses Singular Value Decomposition.\n // The SVD can be represented with formula A = USV. We are interested in the\n // matrix S here because it represents the scale values.\n Util.singularValueDecompose2dScale =\n function Util_singularValueDecompose2dScale(m) {\n\n var transpose = [m[0], m[2], m[1], m[3]];\n\n // Multiply matrix m with its transpose.\n var a = m[0] * transpose[0] + m[1] * transpose[2];\n var b = m[0] * transpose[1] + m[1] * transpose[3];\n var c = m[2] * transpose[0] + m[3] * transpose[2];\n var d = m[2] * transpose[1] + m[3] * transpose[3];\n\n // Solve the second degree polynomial to get roots.\n var first = (a + d) / 2;\n var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2;\n var sx = first + second || 1;\n var sy = first - second || 1;\n\n // Scale values are the square roots of the eigenvalues.\n return [Math.sqrt(sx), Math.sqrt(sy)];\n };\n\n // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)\n // For coordinate systems whose origin lies in the bottom-left, this\n // means normalization to (BL,TR) ordering. For systems with origin in the\n // top-left, this means (TL,BR) ordering.\n Util.normalizeRect = function Util_normalizeRect(rect) {\n var r = rect.slice(0); // clone rect\n if (rect[0] > rect[2]) {\n r[0] = rect[2];\n r[2] = rect[0];\n }\n if (rect[1] > rect[3]) {\n r[1] = rect[3];\n r[3] = rect[1];\n }\n return r;\n };\n\n // Returns a rectangle [x1, y1, x2, y2] corresponding to the\n // intersection of rect1 and rect2. If no intersection, returns 'false'\n // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2]\n Util.intersect = function Util_intersect(rect1, rect2) {\n function compare(a, b) {\n return a - b;\n }\n\n // Order points along the axes\n var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare),\n orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare),\n result = [];\n\n rect1 = Util.normalizeRect(rect1);\n rect2 = Util.normalizeRect(rect2);\n\n // X: first and second points belong to different rectangles?\n if ((orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) ||\n (orderedX[0] === rect2[0] && orderedX[1] === rect1[0])) {\n // Intersection must be between second and third points\n result[0] = orderedX[1];\n result[2] = orderedX[2];\n } else {\n return false;\n }\n\n // Y: first and second points belong to different rectangles?\n if ((orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) ||\n (orderedY[0] === rect2[1] && orderedY[1] === rect1[1])) {\n // Intersection must be between second and third points\n result[1] = orderedY[1];\n result[3] = orderedY[2];\n } else {\n return false;\n }\n\n return result;\n };\n\n Util.sign = function Util_sign(num) {\n return num < 0 ? -1 : 1;\n };\n\n var ROMAN_NUMBER_MAP = [\n '', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM',\n '', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC',\n '', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'\n ];\n /**\n * Converts positive integers to (upper case) Roman numerals.\n * @param {integer} number - The number that should be converted.\n * @param {boolean} lowerCase - Indicates if the result should be converted\n * to lower case letters. The default is false.\n * @return {string} The resulting Roman number.\n */\n Util.toRoman = function Util_toRoman(number, lowerCase) {\n assert(isInt(number) && number > 0,\n 'The number should be a positive integer.');\n var pos, romanBuf = [];\n // Thousands\n while (number >= 1000) {\n number -= 1000;\n romanBuf.push('M');\n }\n // Hundreds\n pos = (number / 100) | 0;\n number %= 100;\n romanBuf.push(ROMAN_NUMBER_MAP[pos]);\n // Tens\n pos = (number / 10) | 0;\n number %= 10;\n romanBuf.push(ROMAN_NUMBER_MAP[10 + pos]);\n // Ones\n romanBuf.push(ROMAN_NUMBER_MAP[20 + number]);\n\n var romanStr = romanBuf.join('');\n return (lowerCase ? romanStr.toLowerCase() : romanStr);\n };\n\n Util.appendToArray = function Util_appendToArray(arr1, arr2) {\n Array.prototype.push.apply(arr1, arr2);\n };\n\n Util.prependToArray = function Util_prependToArray(arr1, arr2) {\n Array.prototype.unshift.apply(arr1, arr2);\n };\n\n Util.extendObj = function extendObj(obj1, obj2) {\n for (var key in obj2) {\n obj1[key] = obj2[key];\n }\n };\n\n Util.getInheritableProperty =\n function Util_getInheritableProperty(dict, name, getArray) {\n while (dict && !dict.has(name)) {\n dict = dict.get('Parent');\n }\n if (!dict) {\n return null;\n }\n return getArray ? dict.getArray(name) : dict.get(name);\n };\n\n Util.inherit = function Util_inherit(sub, base, prototype) {\n sub.prototype = Object.create(base.prototype);\n sub.prototype.constructor = sub;\n for (var prop in prototype) {\n sub.prototype[prop] = prototype[prop];\n }\n };\n\n Util.loadScript = function Util_loadScript(src, callback) {\n var script = document.createElement('script');\n var loaded = false;\n script.setAttribute('src', src);\n if (callback) {\n script.onload = function() {\n if (!loaded) {\n callback();\n }\n loaded = true;\n };\n }\n document.getElementsByTagName('head')[0].appendChild(script);\n };\n\n return Util;\n})();\n\n/**\n * PDF page viewport created based on scale, rotation and offset.\n * @class\n * @alias PageViewport\n */\nvar PageViewport = (function PageViewportClosure() {\n /**\n * @constructor\n * @private\n * @param viewBox {Array} xMin, yMin, xMax and yMax coordinates.\n * @param scale {number} scale of the viewport.\n * @param rotation {number} rotations of the viewport in degrees.\n * @param offsetX {number} offset X\n * @param offsetY {number} offset Y\n * @param dontFlip {boolean} if true, axis Y will not be flipped.\n */\n function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {\n this.viewBox = viewBox;\n this.scale = scale;\n this.rotation = rotation;\n this.offsetX = offsetX;\n this.offsetY = offsetY;\n\n // creating transform to convert pdf coordinate system to the normal\n // canvas like coordinates taking in account scale and rotation\n var centerX = (viewBox[2] + viewBox[0]) / 2;\n var centerY = (viewBox[3] + viewBox[1]) / 2;\n var rotateA, rotateB, rotateC, rotateD;\n rotation = rotation % 360;\n rotation = rotation < 0 ? rotation + 360 : rotation;\n switch (rotation) {\n case 180:\n rotateA = -1; rotateB = 0; rotateC = 0; rotateD = 1;\n break;\n case 90:\n rotateA = 0; rotateB = 1; rotateC = 1; rotateD = 0;\n break;\n case 270:\n rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0;\n break;\n // case 0:\n default:\n rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1;\n break;\n }\n\n if (dontFlip) {\n rotateC = -rotateC; rotateD = -rotateD;\n }\n\n var offsetCanvasX, offsetCanvasY;\n var width, height;\n if (rotateA === 0) {\n offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX;\n offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY;\n width = Math.abs(viewBox[3] - viewBox[1]) * scale;\n height = Math.abs(viewBox[2] - viewBox[0]) * scale;\n } else {\n offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX;\n offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY;\n width = Math.abs(viewBox[2] - viewBox[0]) * scale;\n height = Math.abs(viewBox[3] - viewBox[1]) * scale;\n }\n // creating transform for the following operations:\n // translate(-centerX, -centerY), rotate and flip vertically,\n // scale, and translate(offsetCanvasX, offsetCanvasY)\n this.transform = [\n rotateA * scale,\n rotateB * scale,\n rotateC * scale,\n rotateD * scale,\n offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY,\n offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY\n ];\n\n this.width = width;\n this.height = height;\n this.fontScale = scale;\n }\n PageViewport.prototype = /** @lends PageViewport.prototype */ {\n /**\n * Clones viewport with additional properties.\n * @param args {Object} (optional) If specified, may contain the 'scale' or\n * 'rotation' properties to override the corresponding properties in\n * the cloned viewport.\n * @returns {PageViewport} Cloned viewport.\n */\n clone: function PageViewPort_clone(args) {\n args = args || {};\n var scale = 'scale' in args ? args.scale : this.scale;\n var rotation = 'rotation' in args ? args.rotation : this.rotation;\n return new PageViewport(this.viewBox.slice(), scale, rotation,\n this.offsetX, this.offsetY, args.dontFlip);\n },\n /**\n * Converts PDF point to the viewport coordinates. For examples, useful for\n * converting PDF location into canvas pixel coordinates.\n * @param x {number} X coordinate.\n * @param y {number} Y coordinate.\n * @returns {Object} Object that contains 'x' and 'y' properties of the\n * point in the viewport coordinate space.\n * @see {@link convertToPdfPoint}\n * @see {@link convertToViewportRectangle}\n */\n convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {\n return Util.applyTransform([x, y], this.transform);\n },\n /**\n * Converts PDF rectangle to the viewport coordinates.\n * @param rect {Array} xMin, yMin, xMax and yMax coordinates.\n * @returns {Array} Contains corresponding coordinates of the rectangle\n * in the viewport coordinate space.\n * @see {@link convertToViewportPoint}\n */\n convertToViewportRectangle:\n function PageViewport_convertToViewportRectangle(rect) {\n var tl = Util.applyTransform([rect[0], rect[1]], this.transform);\n var br = Util.applyTransform([rect[2], rect[3]], this.transform);\n return [tl[0], tl[1], br[0], br[1]];\n },\n /**\n * Converts viewport coordinates to the PDF location. For examples, useful\n * for converting canvas pixel location into PDF one.\n * @param x {number} X coordinate.\n * @param y {number} Y coordinate.\n * @returns {Object} Object that contains 'x' and 'y' properties of the\n * point in the PDF coordinate space.\n * @see {@link convertToViewportPoint}\n */\n convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) {\n return Util.applyInverseTransform([x, y], this.transform);\n },\n };\n return PageViewport;\n})();\n\nvar PDFStringTranslateTable = [\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014,\n 0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C,\n 0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160,\n 0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC\n];\n\nfunction stringToPDFString(str) {\n var i, n = str.length, strBuf = [];\n if (str[0] === '\\xFE' && str[1] === '\\xFF') {\n // UTF16BE BOM\n for (i = 2; i < n; i += 2) {\n strBuf.push(String.fromCharCode(\n (str.charCodeAt(i) << 8) | str.charCodeAt(i + 1)));\n }\n } else {\n for (i = 0; i < n; ++i) {\n var code = PDFStringTranslateTable[str.charCodeAt(i)];\n strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));\n }\n }\n return strBuf.join('');\n}\n\nfunction stringToUTF8String(str) {\n return decodeURIComponent(escape(str));\n}\n\nfunction utf8StringToString(str) {\n return unescape(encodeURIComponent(str));\n}\n\nfunction isEmptyObj(obj) {\n for (var key in obj) {\n return false;\n }\n return true;\n}\n\nfunction isBool(v) {\n return typeof v === 'boolean';\n}\n\nfunction isInt(v) {\n return typeof v === 'number' && ((v | 0) === v);\n}\n\nfunction isNum(v) {\n return typeof v === 'number';\n}\n\nfunction isString(v) {\n return typeof v === 'string';\n}\n\nfunction isArray(v) {\n return v instanceof Array;\n}\n\nfunction isArrayBuffer(v) {\n return typeof v === 'object' && v !== null && v.byteLength !== undefined;\n}\n\n// Checks if ch is one of the following characters: SPACE, TAB, CR or LF.\nfunction isSpace(ch) {\n return (ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A);\n}\n\nfunction isNodeJS() {\n // eslint-disable-next-line no-undef\n return typeof process === 'object' && process + '' === '[object process]';\n}\n\n/**\n * Promise Capability object.\n *\n * @typedef {Object} PromiseCapability\n * @property {Promise} promise - A promise object.\n * @property {function} resolve - Fulfills the promise.\n * @property {function} reject - Rejects the promise.\n */\n\n/**\n * Creates a promise capability object.\n * @alias createPromiseCapability\n *\n * @return {PromiseCapability} A capability object contains:\n * - a Promise, resolve and reject methods.\n */\nfunction createPromiseCapability() {\n var capability = {};\n capability.promise = new Promise(function (resolve, reject) {\n capability.resolve = resolve;\n capability.reject = reject;\n });\n return capability;\n}\n\nvar StatTimer = (function StatTimerClosure() {\n function rpad(str, pad, length) {\n while (str.length < length) {\n str += pad;\n }\n return str;\n }\n function StatTimer() {\n this.started = Object.create(null);\n this.times = [];\n this.enabled = true;\n }\n StatTimer.prototype = {\n time: function StatTimer_time(name) {\n if (!this.enabled) {\n return;\n }\n if (name in this.started) {\n warn('Timer is already running for ' + name);\n }\n this.started[name] = Date.now();\n },\n timeEnd: function StatTimer_timeEnd(name) {\n if (!this.enabled) {\n return;\n }\n if (!(name in this.started)) {\n warn('Timer has not been started for ' + name);\n }\n this.times.push({\n 'name': name,\n 'start': this.started[name],\n 'end': Date.now(),\n });\n // Remove timer from started so it can be called again.\n delete this.started[name];\n },\n toString: function StatTimer_toString() {\n var i, ii;\n var times = this.times;\n var out = '';\n // Find the longest name for padding purposes.\n var longest = 0;\n for (i = 0, ii = times.length; i < ii; ++i) {\n var name = times[i]['name'];\n if (name.length > longest) {\n longest = name.length;\n }\n }\n for (i = 0, ii = times.length; i < ii; ++i) {\n var span = times[i];\n var duration = span.end - span.start;\n out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\\n';\n }\n return out;\n },\n };\n return StatTimer;\n})();\n\nvar createBlob = function createBlob(data, contentType) {\n if (typeof Blob !== 'undefined') {\n return new Blob([data], { type: contentType, });\n }\n throw new Error('The \"Blob\" constructor is not supported.');\n};\n\nvar createObjectURL = (function createObjectURLClosure() {\n // Blob/createObjectURL is not available, falling back to data schema.\n var digits =\n 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';\n\n return function createObjectURL(data, contentType, forceDataSchema = false) {\n if (!forceDataSchema && URL.createObjectURL) {\n var blob = createBlob(data, contentType);\n return URL.createObjectURL(blob);\n }\n\n var buffer = 'data:' + contentType + ';base64,';\n for (var i = 0, ii = data.length; i < ii; i += 3) {\n var b1 = data[i] & 0xFF;\n var b2 = data[i + 1] & 0xFF;\n var b3 = data[i + 2] & 0xFF;\n var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);\n var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;\n var d4 = i + 2 < ii ? (b3 & 0x3F) : 64;\n buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];\n }\n return buffer;\n };\n})();\n\nfunction resolveCall(fn, args, thisArg = null) {\n if (!fn) {\n return Promise.resolve(undefined);\n }\n return new Promise((resolve, reject) => {\n resolve(fn.apply(thisArg, args));\n });\n}\n\nfunction wrapReason(reason) {\n if (typeof reason !== 'object') {\n return reason;\n }\n switch (reason.name) {\n case 'AbortException':\n return new AbortException(reason.message);\n case 'MissingPDFException':\n return new MissingPDFException(reason.message);\n case 'UnexpectedResponseException':\n return new UnexpectedResponseException(reason.message, reason.status);\n default:\n return new UnknownErrorException(reason.message, reason.details);\n }\n}\n\nfunction resolveOrReject(capability, success, reason) {\n if (success) {\n capability.resolve();\n } else {\n capability.reject(reason);\n }\n}\n\nfunction finalize(promise) {\n return Promise.resolve(promise).catch(() => {});\n}\n\nfunction MessageHandler(sourceName, targetName, comObj) {\n this.sourceName = sourceName;\n this.targetName = targetName;\n this.comObj = comObj;\n this.callbackId = 1;\n this.streamId = 1;\n this.postMessageTransfers = true;\n this.streamSinks = Object.create(null);\n this.streamControllers = Object.create(null);\n let callbacksCapabilities = this.callbacksCapabilities = Object.create(null);\n let ah = this.actionHandler = Object.create(null);\n\n this._onComObjOnMessage = (event) => {\n let data = event.data;\n if (data.targetName !== this.sourceName) {\n return;\n }\n if (data.stream) {\n this._processStreamMessage(data);\n } else if (data.isReply) {\n let callbackId = data.callbackId;\n if (data.callbackId in callbacksCapabilities) {\n let callback = callbacksCapabilities[callbackId];\n delete callbacksCapabilities[callbackId];\n if ('error' in data) {\n callback.reject(wrapReason(data.error));\n } else {\n callback.resolve(data.data);\n }\n } else {\n throw new Error(`Cannot resolve callback ${callbackId}`);\n }\n } else if (data.action in ah) {\n let action = ah[data.action];\n if (data.callbackId) {\n let sourceName = this.sourceName;\n let targetName = data.sourceName;\n Promise.resolve().then(function () {\n return action[0].call(action[1], data.data);\n }).then((result) => {\n comObj.postMessage({\n sourceName,\n targetName,\n isReply: true,\n callbackId: data.callbackId,\n data: result,\n });\n }, (reason) => {\n if (reason instanceof Error) {\n // Serialize error to avoid \"DataCloneError\"\n reason = reason + '';\n }\n comObj.postMessage({\n sourceName,\n targetName,\n isReply: true,\n callbackId: data.callbackId,\n error: reason,\n });\n });\n } else if (data.streamId) {\n this._createStreamSink(data);\n } else {\n action[0].call(action[1], data.data);\n }\n } else {\n throw new Error(`Unknown action from worker: ${data.action}`);\n }\n };\n comObj.addEventListener('message', this._onComObjOnMessage);\n}\n\nMessageHandler.prototype = {\n on(actionName, handler, scope) {\n var ah = this.actionHandler;\n if (ah[actionName]) {\n throw new Error(`There is already an actionName called \"${actionName}\"`);\n }\n ah[actionName] = [handler, scope];\n },\n /**\n * Sends a message to the comObj to invoke the action with the supplied data.\n * @param {String} actionName - Action to call.\n * @param {JSON} data - JSON data to send.\n * @param {Array} [transfers] - Optional list of transfers/ArrayBuffers\n */\n send(actionName, data, transfers) {\n var message = {\n sourceName: this.sourceName,\n targetName: this.targetName,\n action: actionName,\n data,\n };\n this.postMessage(message, transfers);\n },\n /**\n * Sends a message to the comObj to invoke the action with the supplied data.\n * Expects that the other side will callback with the response.\n * @param {String} actionName - Action to call.\n * @param {JSON} data - JSON data to send.\n * @param {Array} [transfers] - Optional list of transfers/ArrayBuffers.\n * @returns {Promise} Promise to be resolved with response data.\n */\n sendWithPromise(actionName, data, transfers) {\n var callbackId = this.callbackId++;\n var message = {\n sourceName: this.sourceName,\n targetName: this.targetName,\n action: actionName,\n data,\n callbackId,\n };\n var capability = createPromiseCapability();\n this.callbacksCapabilities[callbackId] = capability;\n try {\n this.postMessage(message, transfers);\n } catch (e) {\n capability.reject(e);\n }\n return capability.promise;\n },\n /**\n * Sends a message to the comObj to invoke the action with the supplied data.\n * Expect that the other side will callback to signal 'start_complete'.\n * @param {String} actionName - Action to call.\n * @param {JSON} data - JSON data to send.\n * @param {Object} queueingStrategy - strategy to signal backpressure based on\n * internal queue.\n * @param {Array} [transfers] - Optional list of transfers/ArrayBuffers.\n * @return {ReadableStream} ReadableStream to read data in chunks.\n */\n sendWithStream(actionName, data, queueingStrategy, transfers) {\n let streamId = this.streamId++;\n let sourceName = this.sourceName;\n let targetName = this.targetName;\n\n return new ReadableStream({\n start: (controller) => {\n let startCapability = createPromiseCapability();\n this.streamControllers[streamId] = {\n controller,\n startCall: startCapability,\n isClosed: false,\n };\n this.postMessage({\n sourceName,\n targetName,\n action: actionName,\n streamId,\n data,\n desiredSize: controller.desiredSize,\n });\n // Return Promise for Async process, to signal success/failure.\n return startCapability.promise;\n },\n\n pull: (controller) => {\n let pullCapability = createPromiseCapability();\n this.streamControllers[streamId].pullCall = pullCapability;\n this.postMessage({\n sourceName,\n targetName,\n stream: 'pull',\n streamId,\n desiredSize: controller.desiredSize,\n });\n // Returning Promise will not call \"pull\"\n // again until current pull is resolved.\n return pullCapability.promise;\n },\n\n cancel: (reason) => {\n let cancelCapability = createPromiseCapability();\n this.streamControllers[streamId].cancelCall = cancelCapability;\n this.streamControllers[streamId].isClosed = true;\n this.postMessage({\n sourceName,\n targetName,\n stream: 'cancel',\n reason,\n streamId,\n });\n // Return Promise to signal success or failure.\n return cancelCapability.promise;\n },\n }, queueingStrategy);\n },\n\n _createStreamSink(data) {\n let self = this;\n let action = this.actionHandler[data.action];\n let streamId = data.streamId;\n let desiredSize = data.desiredSize;\n let sourceName = this.sourceName;\n let targetName = data.sourceName;\n let capability = createPromiseCapability();\n\n let sendStreamRequest = ({ stream, chunk, transfers,\n success, reason, }) => {\n this.postMessage({ sourceName, targetName, stream, streamId,\n chunk, success, reason, }, transfers);\n };\n\n let streamSink = {\n enqueue(chunk, size = 1, transfers) {\n if (this.isCancelled) {\n return;\n }\n let lastDesiredSize = this.desiredSize;\n this.desiredSize -= size;\n // Enqueue decreases the desiredSize property of sink,\n // so when it changes from positive to negative,\n // set ready as unresolved promise.\n if (lastDesiredSize > 0 && this.desiredSize <= 0) {\n this.sinkCapability = createPromiseCapability();\n this.ready = this.sinkCapability.promise;\n }\n sendStreamRequest({ stream: 'enqueue', chunk, transfers, });\n },\n\n close() {\n if (this.isCancelled) {\n return;\n }\n sendStreamRequest({ stream: 'close', });\n delete self.streamSinks[streamId];\n },\n\n error(reason) {\n if (this.isCancelled) {\n return;\n }\n this.isCancelled = true;\n sendStreamRequest({ stream: 'error', reason, });\n },\n\n sinkCapability: capability,\n onPull: null,\n onCancel: null,\n isCancelled: false,\n desiredSize,\n ready: null,\n };\n\n streamSink.sinkCapability.resolve();\n streamSink.ready = streamSink.sinkCapability.promise;\n this.streamSinks[streamId] = streamSink;\n resolveCall(action[0], [data.data, streamSink], action[1]).then(() => {\n sendStreamRequest({ stream: 'start_complete', success: true, });\n }, (reason) => {\n sendStreamRequest({ stream: 'start_complete', success: false, reason, });\n });\n },\n\n _processStreamMessage(data) {\n let sourceName = this.sourceName;\n let targetName = data.sourceName;\n let streamId = data.streamId;\n\n let sendStreamResponse = ({ stream, success, reason, }) => {\n this.comObj.postMessage({ sourceName, targetName, stream,\n success, streamId, reason, });\n };\n\n let deleteStreamController = () => {\n // Delete streamController only when start, pull and\n // cancel callbacks are resolved, to avoid \"TypeError\".\n Promise.all([\n this.streamControllers[data.streamId].startCall,\n this.streamControllers[data.streamId].pullCall,\n this.streamControllers[data.streamId].cancelCall\n ].map(function(capability) {\n return capability && finalize(capability.promise);\n })).then(() => {\n delete this.streamControllers[data.streamId];\n });\n };\n\n switch (data.stream) {\n case 'start_complete':\n resolveOrReject(this.streamControllers[data.streamId].startCall,\n data.success, wrapReason(data.reason));\n break;\n case 'pull_complete':\n resolveOrReject(this.streamControllers[data.streamId].pullCall,\n data.success, wrapReason(data.reason));\n break;\n case 'pull':\n // Ignore any pull after close is called.\n if (!this.streamSinks[data.streamId]) {\n sendStreamResponse({ stream: 'pull_complete', success: true, });\n break;\n }\n // Pull increases the desiredSize property of sink,\n // so when it changes from negative to positive,\n // set ready property as resolved promise.\n if (this.streamSinks[data.streamId].desiredSize <= 0 &&\n data.desiredSize > 0) {\n this.streamSinks[data.streamId].sinkCapability.resolve();\n }\n // Reset desiredSize property of sink on every pull.\n this.streamSinks[data.streamId].desiredSize = data.desiredSize;\n resolveCall(this.streamSinks[data.streamId].onPull).then(() => {\n sendStreamResponse({ stream: 'pull_complete', success: true, });\n }, (reason) => {\n sendStreamResponse({ stream: 'pull_complete',\n success: false, reason, });\n });\n break;\n case 'enqueue':\n assert(this.streamControllers[data.streamId],\n 'enqueue should have stream controller');\n if (!this.streamControllers[data.streamId].isClosed) {\n this.streamControllers[data.streamId].controller.enqueue(data.chunk);\n }\n break;\n case 'close':\n assert(this.streamControllers[data.streamId],\n 'close should have stream controller');\n if (this.streamControllers[data.streamId].isClosed) {\n break;\n }\n this.streamControllers[data.streamId].isClosed = true;\n this.streamControllers[data.streamId].controller.close();\n deleteStreamController();\n break;\n case 'error':\n assert(this.streamControllers[data.streamId],\n 'error should have stream controller');\n this.streamControllers[data.streamId].controller.\n error(wrapReason(data.reason));\n deleteStreamController();\n break;\n case 'cancel_complete':\n resolveOrReject(this.streamControllers[data.streamId].cancelCall,\n data.success, wrapReason(data.reason));\n deleteStreamController();\n break;\n case 'cancel':\n if (!this.streamSinks[data.streamId]) {\n break;\n }\n resolveCall(this.streamSinks[data.streamId].onCancel,\n [wrapReason(data.reason)]).then(() => {\n sendStreamResponse({ stream: 'cancel_complete', success: true, });\n }, (reason) => {\n sendStreamResponse({ stream: 'cancel_complete',\n success: false, reason, });\n });\n this.streamSinks[data.streamId].sinkCapability.\n reject(wrapReason(data.reason));\n this.streamSinks[data.streamId].isCancelled = true;\n delete this.streamSinks[data.streamId];\n break;\n default:\n throw new Error('Unexpected stream case');\n }\n },\n\n /**\n * Sends raw message to the comObj.\n * @private\n * @param {Object} message - Raw message.\n * @param transfers List of transfers/ArrayBuffers, or undefined.\n */\n postMessage(message, transfers) {\n if (transfers && this.postMessageTransfers) {\n this.comObj.postMessage(message, transfers);\n } else {\n this.comObj.postMessage(message);\n }\n },\n\n destroy() {\n this.comObj.removeEventListener('message', this._onComObjOnMessage);\n },\n};\n\nfunction loadJpegStream(id, imageUrl, objs) {\n var img = new Image();\n img.onload = (function loadJpegStream_onloadClosure() {\n objs.resolve(id, img);\n });\n img.onerror = (function loadJpegStream_onerrorClosure() {\n objs.resolve(id, null);\n warn('Error during JPEG image loading');\n });\n img.src = imageUrl;\n}\n\nexport {\n FONT_IDENTITY_MATRIX,\n IDENTITY_MATRIX,\n OPS,\n VERBOSITY_LEVELS,\n UNSUPPORTED_FEATURES,\n AnnotationBorderStyleType,\n AnnotationFieldFlag,\n AnnotationFlag,\n AnnotationType,\n FontType,\n ImageKind,\n CMapCompressionType,\n AbortException,\n InvalidPDFException,\n MessageHandler,\n MissingDataException,\n MissingPDFException,\n NativeImageDecoding,\n NotImplementedException,\n PageViewport,\n PasswordException,\n PasswordResponses,\n StatTimer,\n StreamType,\n TextRenderingMode,\n UnexpectedResponseException,\n UnknownErrorException,\n Util,\n XRefParseException,\n FormatError,\n arrayByteLength,\n arraysToBytes,\n assert,\n bytesToString,\n createBlob,\n createPromiseCapability,\n createObjectURL,\n deprecated,\n getLookupTableFactory,\n getVerbosityLevel,\n globalScope,\n info,\n isArray,\n isArrayBuffer,\n isBool,\n isEmptyObj,\n isInt,\n isNum,\n isString,\n isSpace,\n isNodeJS,\n isSameOrigin,\n createValidAbsoluteUrl,\n isLittleEndian,\n isEvalSupported,\n loadJpegStream,\n log2,\n readInt8,\n readUint16,\n readUint32,\n removeNullCharacters,\n ReadableStream,\n setVerbosityLevel,\n shadow,\n string32,\n stringToBytes,\n stringToPDFString,\n stringToUTF8String,\n utf8StringToString,\n warn,\n unreachable,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/shared/util.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* uses XRef */\n\nimport { isArray } from '../shared/util';\n\nvar EOF = {};\n\nvar Name = (function NameClosure() {\n function Name(name) {\n this.name = name;\n }\n\n Name.prototype = {};\n\n var nameCache = Object.create(null);\n\n Name.get = function Name_get(name) {\n var nameValue = nameCache[name];\n return (nameValue ? nameValue : (nameCache[name] = new Name(name)));\n };\n\n return Name;\n})();\n\nvar Cmd = (function CmdClosure() {\n function Cmd(cmd) {\n this.cmd = cmd;\n }\n\n Cmd.prototype = {};\n\n var cmdCache = Object.create(null);\n\n Cmd.get = function Cmd_get(cmd) {\n var cmdValue = cmdCache[cmd];\n return (cmdValue ? cmdValue : (cmdCache[cmd] = new Cmd(cmd)));\n };\n\n return Cmd;\n})();\n\nvar Dict = (function DictClosure() {\n var nonSerializable = function nonSerializableClosure() {\n return nonSerializable; // creating closure on some variable\n };\n\n // xref is optional\n function Dict(xref) {\n // Map should only be used internally, use functions below to access.\n this._map = Object.create(null);\n this.xref = xref;\n this.objId = null;\n this.suppressEncryption = false;\n this.__nonSerializable__ = nonSerializable; // disable cloning of the Dict\n }\n\n Dict.prototype = {\n assignXref: function Dict_assignXref(newXref) {\n this.xref = newXref;\n },\n\n // automatically dereferences Ref objects\n get: function Dict_get(key1, key2, key3) {\n var value;\n var xref = this.xref, suppressEncryption = this.suppressEncryption;\n if (typeof (value = this._map[key1]) !== 'undefined' ||\n key1 in this._map || typeof key2 === 'undefined') {\n return xref ? xref.fetchIfRef(value, suppressEncryption) : value;\n }\n if (typeof (value = this._map[key2]) !== 'undefined' ||\n key2 in this._map || typeof key3 === 'undefined') {\n return xref ? xref.fetchIfRef(value, suppressEncryption) : value;\n }\n value = this._map[key3] || null;\n return xref ? xref.fetchIfRef(value, suppressEncryption) : value;\n },\n\n // Same as get(), but returns a promise and uses fetchIfRefAsync().\n getAsync: function Dict_getAsync(key1, key2, key3) {\n var value;\n var xref = this.xref, suppressEncryption = this.suppressEncryption;\n if (typeof (value = this._map[key1]) !== 'undefined' ||\n key1 in this._map || typeof key2 === 'undefined') {\n if (xref) {\n return xref.fetchIfRefAsync(value, suppressEncryption);\n }\n return Promise.resolve(value);\n }\n if (typeof (value = this._map[key2]) !== 'undefined' ||\n key2 in this._map || typeof key3 === 'undefined') {\n if (xref) {\n return xref.fetchIfRefAsync(value, suppressEncryption);\n }\n return Promise.resolve(value);\n }\n value = this._map[key3] || null;\n if (xref) {\n return xref.fetchIfRefAsync(value, suppressEncryption);\n }\n return Promise.resolve(value);\n },\n\n // Same as get(), but dereferences all elements if the result is an Array.\n getArray: function Dict_getArray(key1, key2, key3) {\n var value = this.get(key1, key2, key3);\n var xref = this.xref, suppressEncryption = this.suppressEncryption;\n if (!isArray(value) || !xref) {\n return value;\n }\n value = value.slice(); // Ensure that we don't modify the Dict data.\n for (var i = 0, ii = value.length; i < ii; i++) {\n if (!isRef(value[i])) {\n continue;\n }\n value[i] = xref.fetch(value[i], suppressEncryption);\n }\n return value;\n },\n\n // no dereferencing\n getRaw: function Dict_getRaw(key) {\n return this._map[key];\n },\n\n getKeys: function Dict_getKeys() {\n return Object.keys(this._map);\n },\n\n set: function Dict_set(key, value) {\n this._map[key] = value;\n },\n\n has: function Dict_has(key) {\n return key in this._map;\n },\n\n forEach: function Dict_forEach(callback) {\n for (var key in this._map) {\n callback(key, this.get(key));\n }\n },\n };\n\n Dict.empty = new Dict(null);\n\n Dict.merge = function(xref, dictArray) {\n let mergedDict = new Dict(xref);\n\n for (let i = 0, ii = dictArray.length; i < ii; i++) {\n let dict = dictArray[i];\n if (!isDict(dict)) {\n continue;\n }\n for (let keyName in dict._map) {\n if (mergedDict._map[keyName] !== undefined) {\n continue;\n }\n mergedDict._map[keyName] = dict._map[keyName];\n }\n }\n return mergedDict;\n };\n\n return Dict;\n})();\n\nvar Ref = (function RefClosure() {\n function Ref(num, gen) {\n this.num = num;\n this.gen = gen;\n }\n\n Ref.prototype = {\n toString: function Ref_toString() {\n // This function is hot, so we make the string as compact as possible.\n // |this.gen| is almost always zero, so we treat that case specially.\n var str = this.num + 'R';\n if (this.gen !== 0) {\n str += this.gen;\n }\n return str;\n },\n };\n\n return Ref;\n})();\n\n// The reference is identified by number and generation.\n// This structure stores only one instance of the reference.\nvar RefSet = (function RefSetClosure() {\n function RefSet() {\n this.dict = Object.create(null);\n }\n\n RefSet.prototype = {\n has: function RefSet_has(ref) {\n return ref.toString() in this.dict;\n },\n\n put: function RefSet_put(ref) {\n this.dict[ref.toString()] = true;\n },\n\n remove: function RefSet_remove(ref) {\n delete this.dict[ref.toString()];\n },\n };\n\n return RefSet;\n})();\n\nvar RefSetCache = (function RefSetCacheClosure() {\n function RefSetCache() {\n this.dict = Object.create(null);\n }\n\n RefSetCache.prototype = {\n get: function RefSetCache_get(ref) {\n return this.dict[ref.toString()];\n },\n\n has: function RefSetCache_has(ref) {\n return ref.toString() in this.dict;\n },\n\n put: function RefSetCache_put(ref, obj) {\n this.dict[ref.toString()] = obj;\n },\n\n putAlias: function RefSetCache_putAlias(ref, aliasRef) {\n this.dict[ref.toString()] = this.get(aliasRef);\n },\n\n forEach: function RefSetCache_forEach(fn, thisArg) {\n for (var i in this.dict) {\n fn.call(thisArg, this.dict[i]);\n }\n },\n\n clear: function RefSetCache_clear() {\n this.dict = Object.create(null);\n },\n };\n\n return RefSetCache;\n})();\n\nfunction isEOF(v) {\n return (v === EOF);\n}\n\nfunction isName(v, name) {\n return v instanceof Name && (name === undefined || v.name === name);\n}\n\nfunction isCmd(v, cmd) {\n return v instanceof Cmd && (cmd === undefined || v.cmd === cmd);\n}\n\nfunction isDict(v, type) {\n return v instanceof Dict &&\n (type === undefined || isName(v.get('Type'), type));\n}\n\nfunction isRef(v) {\n return v instanceof Ref;\n}\n\nfunction isRefsEqual(v1, v2) {\n return v1.num === v2.num && v1.gen === v2.gen;\n}\n\nfunction isStream(v) {\n return typeof v === 'object' && v !== null && v.getBytes !== undefined;\n}\n\nexport {\n EOF,\n Cmd,\n Dict,\n Name,\n Ref,\n RefSet,\n RefSetCache,\n isEOF,\n isCmd,\n isDict,\n isName,\n isRef,\n isRefsEqual,\n isStream,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/primitives.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createObjectURL, FormatError, info, isArray, isInt, isSpace, shadow, Util\n} from '../shared/util';\nimport { Dict, isDict, isStream } from './primitives';\nimport { Jbig2Image } from './jbig2';\nimport { JpegImage } from './jpg';\nimport { JpxImage } from './jpx';\n\nvar Stream = (function StreamClosure() {\n function Stream(arrayBuffer, start, length, dict) {\n this.bytes = (arrayBuffer instanceof Uint8Array ?\n arrayBuffer : new Uint8Array(arrayBuffer));\n this.start = start || 0;\n this.pos = this.start;\n this.end = (start + length) || this.bytes.length;\n this.dict = dict;\n }\n\n // required methods for a stream. if a particular stream does not\n // implement these, an error should be thrown\n Stream.prototype = {\n get length() {\n return this.end - this.start;\n },\n get isEmpty() {\n return this.length === 0;\n },\n getByte: function Stream_getByte() {\n if (this.pos >= this.end) {\n return -1;\n }\n return this.bytes[this.pos++];\n },\n getUint16: function Stream_getUint16() {\n var b0 = this.getByte();\n var b1 = this.getByte();\n if (b0 === -1 || b1 === -1) {\n return -1;\n }\n return (b0 << 8) + b1;\n },\n getInt32: function Stream_getInt32() {\n var b0 = this.getByte();\n var b1 = this.getByte();\n var b2 = this.getByte();\n var b3 = this.getByte();\n return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;\n },\n // returns subarray of original buffer\n // should only be read\n getBytes: function Stream_getBytes(length) {\n var bytes = this.bytes;\n var pos = this.pos;\n var strEnd = this.end;\n\n if (!length) {\n return bytes.subarray(pos, strEnd);\n }\n var end = pos + length;\n if (end > strEnd) {\n end = strEnd;\n }\n this.pos = end;\n return bytes.subarray(pos, end);\n },\n peekByte: function Stream_peekByte() {\n var peekedByte = this.getByte();\n this.pos--;\n return peekedByte;\n },\n peekBytes: function Stream_peekBytes(length) {\n var bytes = this.getBytes(length);\n this.pos -= bytes.length;\n return bytes;\n },\n skip: function Stream_skip(n) {\n if (!n) {\n n = 1;\n }\n this.pos += n;\n },\n reset: function Stream_reset() {\n this.pos = this.start;\n },\n moveStart: function Stream_moveStart() {\n this.start = this.pos;\n },\n makeSubStream: function Stream_makeSubStream(start, length, dict) {\n return new Stream(this.bytes.buffer, start, length, dict);\n },\n };\n\n return Stream;\n})();\n\nvar StringStream = (function StringStreamClosure() {\n function StringStream(str) {\n var length = str.length;\n var bytes = new Uint8Array(length);\n for (var n = 0; n < length; ++n) {\n bytes[n] = str.charCodeAt(n);\n }\n Stream.call(this, bytes);\n }\n\n StringStream.prototype = Stream.prototype;\n\n return StringStream;\n})();\n\n// super class for the decoding streams\nvar DecodeStream = (function DecodeStreamClosure() {\n // Lots of DecodeStreams are created whose buffers are never used. For these\n // we share a single empty buffer. This is (a) space-efficient and (b) avoids\n // having special cases that would be required if we used |null| for an empty\n // buffer.\n var emptyBuffer = new Uint8Array(0);\n\n function DecodeStream(maybeMinBufferLength) {\n this.pos = 0;\n this.bufferLength = 0;\n this.eof = false;\n this.buffer = emptyBuffer;\n this.minBufferLength = 512;\n if (maybeMinBufferLength) {\n // Compute the first power of two that is as big as maybeMinBufferLength.\n while (this.minBufferLength < maybeMinBufferLength) {\n this.minBufferLength *= 2;\n }\n }\n }\n\n DecodeStream.prototype = {\n get isEmpty() {\n while (!this.eof && this.bufferLength === 0) {\n this.readBlock();\n }\n return this.bufferLength === 0;\n },\n ensureBuffer: function DecodeStream_ensureBuffer(requested) {\n var buffer = this.buffer;\n if (requested <= buffer.byteLength) {\n return buffer;\n }\n var size = this.minBufferLength;\n while (size < requested) {\n size *= 2;\n }\n var buffer2 = new Uint8Array(size);\n buffer2.set(buffer);\n return (this.buffer = buffer2);\n },\n getByte: function DecodeStream_getByte() {\n var pos = this.pos;\n while (this.bufferLength <= pos) {\n if (this.eof) {\n return -1;\n }\n this.readBlock();\n }\n return this.buffer[this.pos++];\n },\n getUint16: function DecodeStream_getUint16() {\n var b0 = this.getByte();\n var b1 = this.getByte();\n if (b0 === -1 || b1 === -1) {\n return -1;\n }\n return (b0 << 8) + b1;\n },\n getInt32: function DecodeStream_getInt32() {\n var b0 = this.getByte();\n var b1 = this.getByte();\n var b2 = this.getByte();\n var b3 = this.getByte();\n return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;\n },\n getBytes: function DecodeStream_getBytes(length) {\n var end, pos = this.pos;\n\n if (length) {\n this.ensureBuffer(pos + length);\n end = pos + length;\n\n while (!this.eof && this.bufferLength < end) {\n this.readBlock();\n }\n var bufEnd = this.bufferLength;\n if (end > bufEnd) {\n end = bufEnd;\n }\n } else {\n while (!this.eof) {\n this.readBlock();\n }\n end = this.bufferLength;\n }\n\n this.pos = end;\n return this.buffer.subarray(pos, end);\n },\n peekByte: function DecodeStream_peekByte() {\n var peekedByte = this.getByte();\n this.pos--;\n return peekedByte;\n },\n peekBytes: function DecodeStream_peekBytes(length) {\n var bytes = this.getBytes(length);\n this.pos -= bytes.length;\n return bytes;\n },\n makeSubStream: function DecodeStream_makeSubStream(start, length, dict) {\n var end = start + length;\n while (this.bufferLength <= end && !this.eof) {\n this.readBlock();\n }\n return new Stream(this.buffer, start, length, dict);\n },\n skip: function DecodeStream_skip(n) {\n if (!n) {\n n = 1;\n }\n this.pos += n;\n },\n reset: function DecodeStream_reset() {\n this.pos = 0;\n },\n getBaseStreams: function DecodeStream_getBaseStreams() {\n if (this.str && this.str.getBaseStreams) {\n return this.str.getBaseStreams();\n }\n return [];\n },\n };\n\n return DecodeStream;\n})();\n\nvar StreamsSequenceStream = (function StreamsSequenceStreamClosure() {\n function StreamsSequenceStream(streams) {\n this.streams = streams;\n DecodeStream.call(this, /* maybeLength = */ null);\n }\n\n StreamsSequenceStream.prototype = Object.create(DecodeStream.prototype);\n\n StreamsSequenceStream.prototype.readBlock =\n function streamSequenceStreamReadBlock() {\n\n var streams = this.streams;\n if (streams.length === 0) {\n this.eof = true;\n return;\n }\n var stream = streams.shift();\n var chunk = stream.getBytes();\n var bufferLength = this.bufferLength;\n var newLength = bufferLength + chunk.length;\n var buffer = this.ensureBuffer(newLength);\n buffer.set(chunk, bufferLength);\n this.bufferLength = newLength;\n };\n\n StreamsSequenceStream.prototype.getBaseStreams =\n function StreamsSequenceStream_getBaseStreams() {\n\n var baseStreams = [];\n for (var i = 0, ii = this.streams.length; i < ii; i++) {\n var stream = this.streams[i];\n if (stream.getBaseStreams) {\n Util.appendToArray(baseStreams, stream.getBaseStreams());\n }\n }\n return baseStreams;\n };\n\n return StreamsSequenceStream;\n})();\n\nvar FlateStream = (function FlateStreamClosure() {\n var codeLenCodeMap = new Int32Array([\n 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15\n ]);\n\n var lengthDecode = new Int32Array([\n 0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a,\n 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f,\n 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073,\n 0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102\n ]);\n\n var distDecode = new Int32Array([\n 0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d,\n 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1,\n 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01,\n 0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001\n ]);\n\n var fixedLitCodeTab = [new Int32Array([\n 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0,\n 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0,\n 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0,\n 0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0,\n 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8,\n 0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8,\n 0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8,\n 0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8,\n 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4,\n 0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4,\n 0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4,\n 0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4,\n 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc,\n 0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec,\n 0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc,\n 0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc,\n 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2,\n 0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2,\n 0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2,\n 0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2,\n 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca,\n 0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea,\n 0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da,\n 0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa,\n 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6,\n 0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6,\n 0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6,\n 0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6,\n 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce,\n 0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee,\n 0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de,\n 0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe,\n 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1,\n 0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1,\n 0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1,\n 0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1,\n 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9,\n 0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9,\n 0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9,\n 0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9,\n 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5,\n 0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5,\n 0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5,\n 0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5,\n 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd,\n 0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed,\n 0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd,\n 0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd,\n 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3,\n 0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3,\n 0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3,\n 0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3,\n 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb,\n 0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb,\n 0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db,\n 0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb,\n 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7,\n 0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7,\n 0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7,\n 0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 0x900f7,\n 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf,\n 0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef,\n 0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df,\n 0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff\n ]), 9];\n\n var fixedDistCodeTab = [new Int32Array([\n 0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c,\n 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000,\n 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d,\n 0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000\n ]), 5];\n\n function FlateStream(str, maybeLength) {\n this.str = str;\n this.dict = str.dict;\n\n var cmf = str.getByte();\n var flg = str.getByte();\n if (cmf === -1 || flg === -1) {\n throw new FormatError(\n `Invalid header in flate stream: ${cmf}, ${flg}`);\n }\n if ((cmf & 0x0f) !== 0x08) {\n throw new FormatError(\n `Unknown compression method in flate stream: ${cmf}, ${flg}`);\n }\n if ((((cmf << 8) + flg) % 31) !== 0) {\n throw new FormatError(`Bad FCHECK in flate stream: ${cmf}, ${flg}`);\n }\n if (flg & 0x20) {\n throw new FormatError(\n `FDICT bit set in flate stream: ${cmf}, ${flg}`);\n }\n\n this.codeSize = 0;\n this.codeBuf = 0;\n\n DecodeStream.call(this, maybeLength);\n }\n\n FlateStream.prototype = Object.create(DecodeStream.prototype);\n\n FlateStream.prototype.getBits = function FlateStream_getBits(bits) {\n var str = this.str;\n var codeSize = this.codeSize;\n var codeBuf = this.codeBuf;\n\n var b;\n while (codeSize < bits) {\n if ((b = str.getByte()) === -1) {\n throw new FormatError('Bad encoding in flate stream');\n }\n codeBuf |= b << codeSize;\n codeSize += 8;\n }\n b = codeBuf & ((1 << bits) - 1);\n this.codeBuf = codeBuf >> bits;\n this.codeSize = codeSize -= bits;\n\n return b;\n };\n\n FlateStream.prototype.getCode = function FlateStream_getCode(table) {\n var str = this.str;\n var codes = table[0];\n var maxLen = table[1];\n var codeSize = this.codeSize;\n var codeBuf = this.codeBuf;\n\n var b;\n while (codeSize < maxLen) {\n if ((b = str.getByte()) === -1) {\n // premature end of stream. code might however still be valid.\n // codeSize < codeLen check below guards against incomplete codeVal.\n break;\n }\n codeBuf |= (b << codeSize);\n codeSize += 8;\n }\n var code = codes[codeBuf & ((1 << maxLen) - 1)];\n var codeLen = code >> 16;\n var codeVal = code & 0xffff;\n if (codeLen < 1 || codeSize < codeLen) {\n throw new FormatError('Bad encoding in flate stream');\n }\n this.codeBuf = (codeBuf >> codeLen);\n this.codeSize = (codeSize - codeLen);\n return codeVal;\n };\n\n FlateStream.prototype.generateHuffmanTable =\n function flateStreamGenerateHuffmanTable(lengths) {\n var n = lengths.length;\n\n // find max code length\n var maxLen = 0;\n var i;\n for (i = 0; i < n; ++i) {\n if (lengths[i] > maxLen) {\n maxLen = lengths[i];\n }\n }\n\n // build the table\n var size = 1 << maxLen;\n var codes = new Int32Array(size);\n for (var len = 1, code = 0, skip = 2;\n len <= maxLen;\n ++len, code <<= 1, skip <<= 1) {\n for (var val = 0; val < n; ++val) {\n if (lengths[val] === len) {\n // bit-reverse the code\n var code2 = 0;\n var t = code;\n for (i = 0; i < len; ++i) {\n code2 = (code2 << 1) | (t & 1);\n t >>= 1;\n }\n\n // fill the table entries\n for (i = code2; i < size; i += skip) {\n codes[i] = (len << 16) | val;\n }\n ++code;\n }\n }\n }\n\n return [codes, maxLen];\n };\n\n FlateStream.prototype.readBlock = function FlateStream_readBlock() {\n var buffer, len;\n var str = this.str;\n // read block header\n var hdr = this.getBits(3);\n if (hdr & 1) {\n this.eof = true;\n }\n hdr >>= 1;\n\n if (hdr === 0) { // uncompressed block\n var b;\n\n if ((b = str.getByte()) === -1) {\n throw new FormatError('Bad block header in flate stream');\n }\n var blockLen = b;\n if ((b = str.getByte()) === -1) {\n throw new FormatError('Bad block header in flate stream');\n }\n blockLen |= (b << 8);\n if ((b = str.getByte()) === -1) {\n throw new FormatError('Bad block header in flate stream');\n }\n var check = b;\n if ((b = str.getByte()) === -1) {\n throw new FormatError('Bad block header in flate stream');\n }\n check |= (b << 8);\n if (check !== (~blockLen & 0xffff) &&\n (blockLen !== 0 || check !== 0)) {\n // Ignoring error for bad \"empty\" block (see issue 1277)\n throw new FormatError(\n 'Bad uncompressed block length in flate stream');\n }\n\n this.codeBuf = 0;\n this.codeSize = 0;\n\n var bufferLength = this.bufferLength;\n buffer = this.ensureBuffer(bufferLength + blockLen);\n var end = bufferLength + blockLen;\n this.bufferLength = end;\n if (blockLen === 0) {\n if (str.peekByte() === -1) {\n this.eof = true;\n }\n } else {\n for (var n = bufferLength; n < end; ++n) {\n if ((b = str.getByte()) === -1) {\n this.eof = true;\n break;\n }\n buffer[n] = b;\n }\n }\n return;\n }\n\n var litCodeTable;\n var distCodeTable;\n if (hdr === 1) { // compressed block, fixed codes\n litCodeTable = fixedLitCodeTab;\n distCodeTable = fixedDistCodeTab;\n } else if (hdr === 2) { // compressed block, dynamic codes\n var numLitCodes = this.getBits(5) + 257;\n var numDistCodes = this.getBits(5) + 1;\n var numCodeLenCodes = this.getBits(4) + 4;\n\n // build the code lengths code table\n var codeLenCodeLengths = new Uint8Array(codeLenCodeMap.length);\n\n var i;\n for (i = 0; i < numCodeLenCodes; ++i) {\n codeLenCodeLengths[codeLenCodeMap[i]] = this.getBits(3);\n }\n var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths);\n\n // build the literal and distance code tables\n len = 0;\n i = 0;\n var codes = numLitCodes + numDistCodes;\n var codeLengths = new Uint8Array(codes);\n var bitsLength, bitsOffset, what;\n while (i < codes) {\n var code = this.getCode(codeLenCodeTab);\n if (code === 16) {\n bitsLength = 2; bitsOffset = 3; what = len;\n } else if (code === 17) {\n bitsLength = 3; bitsOffset = 3; what = (len = 0);\n } else if (code === 18) {\n bitsLength = 7; bitsOffset = 11; what = (len = 0);\n } else {\n codeLengths[i++] = len = code;\n continue;\n }\n\n var repeatLength = this.getBits(bitsLength) + bitsOffset;\n while (repeatLength-- > 0) {\n codeLengths[i++] = what;\n }\n }\n\n litCodeTable =\n this.generateHuffmanTable(codeLengths.subarray(0, numLitCodes));\n distCodeTable =\n this.generateHuffmanTable(codeLengths.subarray(numLitCodes, codes));\n } else {\n throw new FormatError('Unknown block type in flate stream');\n }\n\n buffer = this.buffer;\n var limit = buffer ? buffer.length : 0;\n var pos = this.bufferLength;\n while (true) {\n var code1 = this.getCode(litCodeTable);\n if (code1 < 256) {\n if (pos + 1 >= limit) {\n buffer = this.ensureBuffer(pos + 1);\n limit = buffer.length;\n }\n buffer[pos++] = code1;\n continue;\n }\n if (code1 === 256) {\n this.bufferLength = pos;\n return;\n }\n code1 -= 257;\n code1 = lengthDecode[code1];\n var code2 = code1 >> 16;\n if (code2 > 0) {\n code2 = this.getBits(code2);\n }\n len = (code1 & 0xffff) + code2;\n code1 = this.getCode(distCodeTable);\n code1 = distDecode[code1];\n code2 = code1 >> 16;\n if (code2 > 0) {\n code2 = this.getBits(code2);\n }\n var dist = (code1 & 0xffff) + code2;\n if (pos + len >= limit) {\n buffer = this.ensureBuffer(pos + len);\n limit = buffer.length;\n }\n for (var k = 0; k < len; ++k, ++pos) {\n buffer[pos] = buffer[pos - dist];\n }\n }\n };\n\n return FlateStream;\n})();\n\nvar PredictorStream = (function PredictorStreamClosure() {\n function PredictorStream(str, maybeLength, params) {\n if (!isDict(params)) {\n return str; // no prediction\n }\n var predictor = this.predictor = params.get('Predictor') || 1;\n\n if (predictor <= 1) {\n return str; // no prediction\n }\n if (predictor !== 2 && (predictor < 10 || predictor > 15)) {\n throw new FormatError(`Unsupported predictor: ${predictor}`);\n }\n\n if (predictor === 2) {\n this.readBlock = this.readBlockTiff;\n } else {\n this.readBlock = this.readBlockPng;\n }\n\n this.str = str;\n this.dict = str.dict;\n\n var colors = this.colors = params.get('Colors') || 1;\n var bits = this.bits = params.get('BitsPerComponent') || 8;\n var columns = this.columns = params.get('Columns') || 1;\n\n this.pixBytes = (colors * bits + 7) >> 3;\n this.rowBytes = (columns * colors * bits + 7) >> 3;\n\n DecodeStream.call(this, maybeLength);\n return this;\n }\n\n PredictorStream.prototype = Object.create(DecodeStream.prototype);\n\n PredictorStream.prototype.readBlockTiff =\n function predictorStreamReadBlockTiff() {\n var rowBytes = this.rowBytes;\n\n var bufferLength = this.bufferLength;\n var buffer = this.ensureBuffer(bufferLength + rowBytes);\n\n var bits = this.bits;\n var colors = this.colors;\n\n var rawBytes = this.str.getBytes(rowBytes);\n this.eof = !rawBytes.length;\n if (this.eof) {\n return;\n }\n\n var inbuf = 0, outbuf = 0;\n var inbits = 0, outbits = 0;\n var pos = bufferLength;\n var i;\n\n if (bits === 1 && colors === 1) {\n // Optimized version of the loop in the \"else\"-branch\n // for 1 bit-per-component and 1 color TIFF images.\n for (i = 0; i < rowBytes; ++i) {\n var c = rawBytes[i] ^ inbuf;\n c ^= c >> 1;\n c ^= c >> 2;\n c ^= c >> 4;\n inbuf = (c & 1) << 7;\n buffer[pos++] = c;\n }\n } else if (bits === 8) {\n for (i = 0; i < colors; ++i) {\n buffer[pos++] = rawBytes[i];\n }\n for (; i < rowBytes; ++i) {\n buffer[pos] = buffer[pos - colors] + rawBytes[i];\n pos++;\n }\n } else {\n var compArray = new Uint8Array(colors + 1);\n var bitMask = (1 << bits) - 1;\n var j = 0, k = bufferLength;\n var columns = this.columns;\n for (i = 0; i < columns; ++i) {\n for (var kk = 0; kk < colors; ++kk) {\n if (inbits < bits) {\n inbuf = (inbuf << 8) | (rawBytes[j++] & 0xFF);\n inbits += 8;\n }\n compArray[kk] = (compArray[kk] +\n (inbuf >> (inbits - bits))) & bitMask;\n inbits -= bits;\n outbuf = (outbuf << bits) | compArray[kk];\n outbits += bits;\n if (outbits >= 8) {\n buffer[k++] = (outbuf >> (outbits - 8)) & 0xFF;\n outbits -= 8;\n }\n }\n }\n if (outbits > 0) {\n buffer[k++] = (outbuf << (8 - outbits)) +\n (inbuf & ((1 << (8 - outbits)) - 1));\n }\n }\n this.bufferLength += rowBytes;\n };\n\n PredictorStream.prototype.readBlockPng =\n function predictorStreamReadBlockPng() {\n\n var rowBytes = this.rowBytes;\n var pixBytes = this.pixBytes;\n\n var predictor = this.str.getByte();\n var rawBytes = this.str.getBytes(rowBytes);\n this.eof = !rawBytes.length;\n if (this.eof) {\n return;\n }\n\n var bufferLength = this.bufferLength;\n var buffer = this.ensureBuffer(bufferLength + rowBytes);\n\n var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength);\n if (prevRow.length === 0) {\n prevRow = new Uint8Array(rowBytes);\n }\n\n var i, j = bufferLength, up, c;\n switch (predictor) {\n case 0:\n for (i = 0; i < rowBytes; ++i) {\n buffer[j++] = rawBytes[i];\n }\n break;\n case 1:\n for (i = 0; i < pixBytes; ++i) {\n buffer[j++] = rawBytes[i];\n }\n for (; i < rowBytes; ++i) {\n buffer[j] = (buffer[j - pixBytes] + rawBytes[i]) & 0xFF;\n j++;\n }\n break;\n case 2:\n for (i = 0; i < rowBytes; ++i) {\n buffer[j++] = (prevRow[i] + rawBytes[i]) & 0xFF;\n }\n break;\n case 3:\n for (i = 0; i < pixBytes; ++i) {\n buffer[j++] = (prevRow[i] >> 1) + rawBytes[i];\n }\n for (; i < rowBytes; ++i) {\n buffer[j] = (((prevRow[i] + buffer[j - pixBytes]) >> 1) +\n rawBytes[i]) & 0xFF;\n j++;\n }\n break;\n case 4:\n // we need to save the up left pixels values. the simplest way\n // is to create a new buffer\n for (i = 0; i < pixBytes; ++i) {\n up = prevRow[i];\n c = rawBytes[i];\n buffer[j++] = up + c;\n }\n for (; i < rowBytes; ++i) {\n up = prevRow[i];\n var upLeft = prevRow[i - pixBytes];\n var left = buffer[j - pixBytes];\n var p = left + up - upLeft;\n\n var pa = p - left;\n if (pa < 0) {\n pa = -pa;\n }\n var pb = p - up;\n if (pb < 0) {\n pb = -pb;\n }\n var pc = p - upLeft;\n if (pc < 0) {\n pc = -pc;\n }\n\n c = rawBytes[i];\n if (pa <= pb && pa <= pc) {\n buffer[j++] = left + c;\n } else if (pb <= pc) {\n buffer[j++] = up + c;\n } else {\n buffer[j++] = upLeft + c;\n }\n }\n break;\n default:\n throw new FormatError(`Unsupported predictor: ${predictor}`);\n }\n this.bufferLength += rowBytes;\n };\n\n return PredictorStream;\n})();\n\n/**\n * Depending on the type of JPEG a JpegStream is handled in different ways. For\n * JPEG's that are supported natively such as DeviceGray and DeviceRGB the image\n * data is stored and then loaded by the browser. For unsupported JPEG's we use\n * a library to decode these images and the stream behaves like all the other\n * DecodeStreams.\n */\nvar JpegStream = (function JpegStreamClosure() {\n function JpegStream(stream, maybeLength, dict, params) {\n // Some images may contain 'junk' before the SOI (start-of-image) marker.\n // Note: this seems to mainly affect inline images.\n var ch;\n while ((ch = stream.getByte()) !== -1) {\n if (ch === 0xFF) { // Find the first byte of the SOI marker (0xFFD8).\n stream.skip(-1); // Reset the stream position to the SOI.\n break;\n }\n }\n this.stream = stream;\n this.maybeLength = maybeLength;\n this.dict = dict;\n this.params = params;\n\n DecodeStream.call(this, maybeLength);\n }\n\n JpegStream.prototype = Object.create(DecodeStream.prototype);\n\n Object.defineProperty(JpegStream.prototype, 'bytes', {\n get: function JpegStream_bytes() {\n // If this.maybeLength is null, we'll get the entire stream.\n return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength));\n },\n configurable: true,\n });\n\n JpegStream.prototype.ensureBuffer = function JpegStream_ensureBuffer(req) {\n if (this.bufferLength) {\n return;\n }\n var jpegImage = new JpegImage();\n\n // Checking if values need to be transformed before conversion.\n var decodeArr = this.dict.getArray('Decode', 'D');\n if (this.forceRGB && isArray(decodeArr)) {\n var bitsPerComponent = this.dict.get('BitsPerComponent') || 8;\n var decodeArrLength = decodeArr.length;\n var transform = new Int32Array(decodeArrLength);\n var transformNeeded = false;\n var maxValue = (1 << bitsPerComponent) - 1;\n for (var i = 0; i < decodeArrLength; i += 2) {\n transform[i] = ((decodeArr[i + 1] - decodeArr[i]) * 256) | 0;\n transform[i + 1] = (decodeArr[i] * maxValue) | 0;\n if (transform[i] !== 256 || transform[i + 1] !== 0) {\n transformNeeded = true;\n }\n }\n if (transformNeeded) {\n jpegImage.decodeTransform = transform;\n }\n }\n // Fetching the 'ColorTransform' entry, if it exists.\n if (isDict(this.params)) {\n var colorTransform = this.params.get('ColorTransform');\n if (isInt(colorTransform)) {\n jpegImage.colorTransform = colorTransform;\n }\n }\n\n jpegImage.parse(this.bytes);\n var data = jpegImage.getData(this.drawWidth, this.drawHeight,\n this.forceRGB);\n this.buffer = data;\n this.bufferLength = data.length;\n this.eof = true;\n };\n\n JpegStream.prototype.getBytes = function JpegStream_getBytes(length) {\n this.ensureBuffer();\n return this.buffer;\n };\n\n JpegStream.prototype.getIR = function JpegStream_getIR(forceDataSchema) {\n return createObjectURL(this.bytes, 'image/jpeg', forceDataSchema);\n };\n\n return JpegStream;\n})();\n\n/**\n * For JPEG 2000's we use a library to decode these images and\n * the stream behaves like all the other DecodeStreams.\n */\nvar JpxStream = (function JpxStreamClosure() {\n function JpxStream(stream, maybeLength, dict, params) {\n this.stream = stream;\n this.maybeLength = maybeLength;\n this.dict = dict;\n this.params = params;\n\n DecodeStream.call(this, maybeLength);\n }\n\n JpxStream.prototype = Object.create(DecodeStream.prototype);\n\n Object.defineProperty(JpxStream.prototype, 'bytes', {\n get: function JpxStream_bytes() {\n // If this.maybeLength is null, we'll get the entire stream.\n return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength));\n },\n configurable: true,\n });\n\n JpxStream.prototype.ensureBuffer = function JpxStream_ensureBuffer(req) {\n if (this.bufferLength) {\n return;\n }\n\n var jpxImage = new JpxImage();\n jpxImage.parse(this.bytes);\n\n var width = jpxImage.width;\n var height = jpxImage.height;\n var componentsCount = jpxImage.componentsCount;\n var tileCount = jpxImage.tiles.length;\n if (tileCount === 1) {\n this.buffer = jpxImage.tiles[0].items;\n } else {\n var data = new Uint8Array(width * height * componentsCount);\n\n for (var k = 0; k < tileCount; k++) {\n var tileComponents = jpxImage.tiles[k];\n var tileWidth = tileComponents.width;\n var tileHeight = tileComponents.height;\n var tileLeft = tileComponents.left;\n var tileTop = tileComponents.top;\n\n var src = tileComponents.items;\n var srcPosition = 0;\n var dataPosition = (width * tileTop + tileLeft) * componentsCount;\n var imgRowSize = width * componentsCount;\n var tileRowSize = tileWidth * componentsCount;\n\n for (var j = 0; j < tileHeight; j++) {\n var rowBytes = src.subarray(srcPosition, srcPosition + tileRowSize);\n data.set(rowBytes, dataPosition);\n srcPosition += tileRowSize;\n dataPosition += imgRowSize;\n }\n }\n this.buffer = data;\n }\n this.bufferLength = this.buffer.length;\n this.eof = true;\n };\n\n return JpxStream;\n})();\n\n/**\n * For JBIG2's we use a library to decode these images and\n * the stream behaves like all the other DecodeStreams.\n */\nvar Jbig2Stream = (function Jbig2StreamClosure() {\n function Jbig2Stream(stream, maybeLength, dict, params) {\n this.stream = stream;\n this.maybeLength = maybeLength;\n this.dict = dict;\n this.params = params;\n\n DecodeStream.call(this, maybeLength);\n }\n\n Jbig2Stream.prototype = Object.create(DecodeStream.prototype);\n\n Object.defineProperty(Jbig2Stream.prototype, 'bytes', {\n get: function Jbig2Stream_bytes() {\n // If this.maybeLength is null, we'll get the entire stream.\n return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength));\n },\n configurable: true,\n });\n\n Jbig2Stream.prototype.ensureBuffer = function Jbig2Stream_ensureBuffer(req) {\n if (this.bufferLength) {\n return;\n }\n\n var jbig2Image = new Jbig2Image();\n\n var chunks = [];\n if (isDict(this.params)) {\n var globalsStream = this.params.get('JBIG2Globals');\n if (isStream(globalsStream)) {\n var globals = globalsStream.getBytes();\n chunks.push({ data: globals, start: 0, end: globals.length, });\n }\n }\n chunks.push({ data: this.bytes, start: 0, end: this.bytes.length, });\n var data = jbig2Image.parseChunks(chunks);\n var dataLength = data.length;\n\n // JBIG2 had black as 1 and white as 0, inverting the colors\n for (var i = 0; i < dataLength; i++) {\n data[i] ^= 0xFF;\n }\n\n this.buffer = data;\n this.bufferLength = dataLength;\n this.eof = true;\n };\n\n return Jbig2Stream;\n})();\n\nvar DecryptStream = (function DecryptStreamClosure() {\n function DecryptStream(str, maybeLength, decrypt) {\n this.str = str;\n this.dict = str.dict;\n this.decrypt = decrypt;\n this.nextChunk = null;\n this.initialized = false;\n\n DecodeStream.call(this, maybeLength);\n }\n\n var chunkSize = 512;\n\n DecryptStream.prototype = Object.create(DecodeStream.prototype);\n\n DecryptStream.prototype.readBlock = function DecryptStream_readBlock() {\n var chunk;\n if (this.initialized) {\n chunk = this.nextChunk;\n } else {\n chunk = this.str.getBytes(chunkSize);\n this.initialized = true;\n }\n if (!chunk || chunk.length === 0) {\n this.eof = true;\n return;\n }\n this.nextChunk = this.str.getBytes(chunkSize);\n var hasMoreData = this.nextChunk && this.nextChunk.length > 0;\n\n var decrypt = this.decrypt;\n chunk = decrypt(chunk, !hasMoreData);\n\n var bufferLength = this.bufferLength;\n var i, n = chunk.length;\n var buffer = this.ensureBuffer(bufferLength + n);\n for (i = 0; i < n; i++) {\n buffer[bufferLength++] = chunk[i];\n }\n this.bufferLength = bufferLength;\n };\n\n return DecryptStream;\n})();\n\nvar Ascii85Stream = (function Ascii85StreamClosure() {\n function Ascii85Stream(str, maybeLength) {\n this.str = str;\n this.dict = str.dict;\n this.input = new Uint8Array(5);\n\n // Most streams increase in size when decoded, but Ascii85 streams\n // typically shrink by ~20%.\n if (maybeLength) {\n maybeLength = 0.8 * maybeLength;\n }\n DecodeStream.call(this, maybeLength);\n }\n\n Ascii85Stream.prototype = Object.create(DecodeStream.prototype);\n\n Ascii85Stream.prototype.readBlock = function Ascii85Stream_readBlock() {\n var TILDA_CHAR = 0x7E; // '~'\n var Z_LOWER_CHAR = 0x7A; // 'z'\n var EOF = -1;\n\n var str = this.str;\n\n var c = str.getByte();\n while (isSpace(c)) {\n c = str.getByte();\n }\n\n if (c === EOF || c === TILDA_CHAR) {\n this.eof = true;\n return;\n }\n\n var bufferLength = this.bufferLength, buffer;\n var i;\n\n // special code for z\n if (c === Z_LOWER_CHAR) {\n buffer = this.ensureBuffer(bufferLength + 4);\n for (i = 0; i < 4; ++i) {\n buffer[bufferLength + i] = 0;\n }\n this.bufferLength += 4;\n } else {\n var input = this.input;\n input[0] = c;\n for (i = 1; i < 5; ++i) {\n c = str.getByte();\n while (isSpace(c)) {\n c = str.getByte();\n }\n\n input[i] = c;\n\n if (c === EOF || c === TILDA_CHAR) {\n break;\n }\n }\n buffer = this.ensureBuffer(bufferLength + i - 1);\n this.bufferLength += i - 1;\n\n // partial ending;\n if (i < 5) {\n for (; i < 5; ++i) {\n input[i] = 0x21 + 84;\n }\n this.eof = true;\n }\n var t = 0;\n for (i = 0; i < 5; ++i) {\n t = t * 85 + (input[i] - 0x21);\n }\n\n for (i = 3; i >= 0; --i) {\n buffer[bufferLength + i] = t & 0xFF;\n t >>= 8;\n }\n }\n };\n\n return Ascii85Stream;\n})();\n\nvar AsciiHexStream = (function AsciiHexStreamClosure() {\n function AsciiHexStream(str, maybeLength) {\n this.str = str;\n this.dict = str.dict;\n\n this.firstDigit = -1;\n\n // Most streams increase in size when decoded, but AsciiHex streams shrink\n // by 50%.\n if (maybeLength) {\n maybeLength = 0.5 * maybeLength;\n }\n DecodeStream.call(this, maybeLength);\n }\n\n AsciiHexStream.prototype = Object.create(DecodeStream.prototype);\n\n AsciiHexStream.prototype.readBlock = function AsciiHexStream_readBlock() {\n var UPSTREAM_BLOCK_SIZE = 8000;\n var bytes = this.str.getBytes(UPSTREAM_BLOCK_SIZE);\n if (!bytes.length) {\n this.eof = true;\n return;\n }\n\n var maxDecodeLength = (bytes.length + 1) >> 1;\n var buffer = this.ensureBuffer(this.bufferLength + maxDecodeLength);\n var bufferLength = this.bufferLength;\n\n var firstDigit = this.firstDigit;\n for (var i = 0, ii = bytes.length; i < ii; i++) {\n var ch = bytes[i], digit;\n if (ch >= 0x30 && ch <= 0x39) { // '0'-'9'\n digit = ch & 0x0F;\n } else if ((ch >= 0x41 && ch <= 0x46) || (ch >= 0x61 && ch <= 0x66)) {\n // 'A'-'Z', 'a'-'z'\n digit = (ch & 0x0F) + 9;\n } else if (ch === 0x3E) { // '>'\n this.eof = true;\n break;\n } else { // probably whitespace\n continue; // ignoring\n }\n if (firstDigit < 0) {\n firstDigit = digit;\n } else {\n buffer[bufferLength++] = (firstDigit << 4) | digit;\n firstDigit = -1;\n }\n }\n if (firstDigit >= 0 && this.eof) {\n // incomplete byte\n buffer[bufferLength++] = (firstDigit << 4);\n firstDigit = -1;\n }\n this.firstDigit = firstDigit;\n this.bufferLength = bufferLength;\n };\n\n return AsciiHexStream;\n})();\n\nvar RunLengthStream = (function RunLengthStreamClosure() {\n function RunLengthStream(str, maybeLength) {\n this.str = str;\n this.dict = str.dict;\n\n DecodeStream.call(this, maybeLength);\n }\n\n RunLengthStream.prototype = Object.create(DecodeStream.prototype);\n\n RunLengthStream.prototype.readBlock = function RunLengthStream_readBlock() {\n // The repeatHeader has following format. The first byte defines type of run\n // and amount of bytes to repeat/copy: n = 0 through 127 - copy next n bytes\n // (in addition to the second byte from the header), n = 129 through 255 -\n // duplicate the second byte from the header (257 - n) times, n = 128 - end.\n var repeatHeader = this.str.getBytes(2);\n if (!repeatHeader || repeatHeader.length < 2 || repeatHeader[0] === 128) {\n this.eof = true;\n return;\n }\n\n var buffer;\n var bufferLength = this.bufferLength;\n var n = repeatHeader[0];\n if (n < 128) {\n // copy n bytes\n buffer = this.ensureBuffer(bufferLength + n + 1);\n buffer[bufferLength++] = repeatHeader[1];\n if (n > 0) {\n var source = this.str.getBytes(n);\n buffer.set(source, bufferLength);\n bufferLength += n;\n }\n } else {\n n = 257 - n;\n var b = repeatHeader[1];\n buffer = this.ensureBuffer(bufferLength + n + 1);\n for (var i = 0; i < n; i++) {\n buffer[bufferLength++] = b;\n }\n }\n this.bufferLength = bufferLength;\n };\n\n return RunLengthStream;\n})();\n\nvar CCITTFaxStream = (function CCITTFaxStreamClosure() {\n\n var ccittEOL = -2;\n var ccittEOF = -1;\n var twoDimPass = 0;\n var twoDimHoriz = 1;\n var twoDimVert0 = 2;\n var twoDimVertR1 = 3;\n var twoDimVertL1 = 4;\n var twoDimVertR2 = 5;\n var twoDimVertL2 = 6;\n var twoDimVertR3 = 7;\n var twoDimVertL3 = 8;\n\n var twoDimTable = [\n [-1, -1], [-1, -1], // 000000x\n [7, twoDimVertL3], // 0000010\n [7, twoDimVertR3], // 0000011\n [6, twoDimVertL2], [6, twoDimVertL2], // 000010x\n [6, twoDimVertR2], [6, twoDimVertR2], // 000011x\n [4, twoDimPass], [4, twoDimPass], // 0001xxx\n [4, twoDimPass], [4, twoDimPass],\n [4, twoDimPass], [4, twoDimPass],\n [4, twoDimPass], [4, twoDimPass],\n [3, twoDimHoriz], [3, twoDimHoriz], // 001xxxx\n [3, twoDimHoriz], [3, twoDimHoriz],\n [3, twoDimHoriz], [3, twoDimHoriz],\n [3, twoDimHoriz], [3, twoDimHoriz],\n [3, twoDimHoriz], [3, twoDimHoriz],\n [3, twoDimHoriz], [3, twoDimHoriz],\n [3, twoDimHoriz], [3, twoDimHoriz],\n [3, twoDimHoriz], [3, twoDimHoriz],\n [3, twoDimVertL1], [3, twoDimVertL1], // 010xxxx\n [3, twoDimVertL1], [3, twoDimVertL1],\n [3, twoDimVertL1], [3, twoDimVertL1],\n [3, twoDimVertL1], [3, twoDimVertL1],\n [3, twoDimVertL1], [3, twoDimVertL1],\n [3, twoDimVertL1], [3, twoDimVertL1],\n [3, twoDimVertL1], [3, twoDimVertL1],\n [3, twoDimVertL1], [3, twoDimVertL1],\n [3, twoDimVertR1], [3, twoDimVertR1], // 011xxxx\n [3, twoDimVertR1], [3, twoDimVertR1],\n [3, twoDimVertR1], [3, twoDimVertR1],\n [3, twoDimVertR1], [3, twoDimVertR1],\n [3, twoDimVertR1], [3, twoDimVertR1],\n [3, twoDimVertR1], [3, twoDimVertR1],\n [3, twoDimVertR1], [3, twoDimVertR1],\n [3, twoDimVertR1], [3, twoDimVertR1],\n [1, twoDimVert0], [1, twoDimVert0], // 1xxxxxx\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0],\n [1, twoDimVert0], [1, twoDimVert0]\n ];\n\n var whiteTable1 = [\n [-1, -1], // 00000\n [12, ccittEOL], // 00001\n [-1, -1], [-1, -1], // 0001x\n [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 001xx\n [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 010xx\n [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 011xx\n [11, 1792], [11, 1792], // 1000x\n [12, 1984], // 10010\n [12, 2048], // 10011\n [12, 2112], // 10100\n [12, 2176], // 10101\n [12, 2240], // 10110\n [12, 2304], // 10111\n [11, 1856], [11, 1856], // 1100x\n [11, 1920], [11, 1920], // 1101x\n [12, 2368], // 11100\n [12, 2432], // 11101\n [12, 2496], // 11110\n [12, 2560] // 11111\n ];\n\n var whiteTable2 = [\n [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 0000000xx\n [8, 29], [8, 29], // 00000010x\n [8, 30], [8, 30], // 00000011x\n [8, 45], [8, 45], // 00000100x\n [8, 46], [8, 46], // 00000101x\n [7, 22], [7, 22], [7, 22], [7, 22], // 0000011xx\n [7, 23], [7, 23], [7, 23], [7, 23], // 0000100xx\n [8, 47], [8, 47], // 00001010x\n [8, 48], [8, 48], // 00001011x\n [6, 13], [6, 13], [6, 13], [6, 13], // 000011xxx\n [6, 13], [6, 13], [6, 13], [6, 13],\n [7, 20], [7, 20], [7, 20], [7, 20], // 0001000xx\n [8, 33], [8, 33], // 00010010x\n [8, 34], [8, 34], // 00010011x\n [8, 35], [8, 35], // 00010100x\n [8, 36], [8, 36], // 00010101x\n [8, 37], [8, 37], // 00010110x\n [8, 38], [8, 38], // 00010111x\n [7, 19], [7, 19], [7, 19], [7, 19], // 0001100xx\n [8, 31], [8, 31], // 00011010x\n [8, 32], [8, 32], // 00011011x\n [6, 1], [6, 1], [6, 1], [6, 1], // 000111xxx\n [6, 1], [6, 1], [6, 1], [6, 1],\n [6, 12], [6, 12], [6, 12], [6, 12], // 001000xxx\n [6, 12], [6, 12], [6, 12], [6, 12],\n [8, 53], [8, 53], // 00100100x\n [8, 54], [8, 54], // 00100101x\n [7, 26], [7, 26], [7, 26], [7, 26], // 0010011xx\n [8, 39], [8, 39], // 00101000x\n [8, 40], [8, 40], // 00101001x\n [8, 41], [8, 41], // 00101010x\n [8, 42], [8, 42], // 00101011x\n [8, 43], [8, 43], // 00101100x\n [8, 44], [8, 44], // 00101101x\n [7, 21], [7, 21], [7, 21], [7, 21], // 0010111xx\n [7, 28], [7, 28], [7, 28], [7, 28], // 0011000xx\n [8, 61], [8, 61], // 00110010x\n [8, 62], [8, 62], // 00110011x\n [8, 63], [8, 63], // 00110100x\n [8, 0], [8, 0], // 00110101x\n [8, 320], [8, 320], // 00110110x\n [8, 384], [8, 384], // 00110111x\n [5, 10], [5, 10], [5, 10], [5, 10], // 00111xxxx\n [5, 10], [5, 10], [5, 10], [5, 10],\n [5, 10], [5, 10], [5, 10], [5, 10],\n [5, 10], [5, 10], [5, 10], [5, 10],\n [5, 11], [5, 11], [5, 11], [5, 11], // 01000xxxx\n [5, 11], [5, 11], [5, 11], [5, 11],\n [5, 11], [5, 11], [5, 11], [5, 11],\n [5, 11], [5, 11], [5, 11], [5, 11],\n [7, 27], [7, 27], [7, 27], [7, 27], // 0100100xx\n [8, 59], [8, 59], // 01001010x\n [8, 60], [8, 60], // 01001011x\n [9, 1472], // 010011000\n [9, 1536], // 010011001\n [9, 1600], // 010011010\n [9, 1728], // 010011011\n [7, 18], [7, 18], [7, 18], [7, 18], // 0100111xx\n [7, 24], [7, 24], [7, 24], [7, 24], // 0101000xx\n [8, 49], [8, 49], // 01010010x\n [8, 50], [8, 50], // 01010011x\n [8, 51], [8, 51], // 01010100x\n [8, 52], [8, 52], // 01010101x\n [7, 25], [7, 25], [7, 25], [7, 25], // 0101011xx\n [8, 55], [8, 55], // 01011000x\n [8, 56], [8, 56], // 01011001x\n [8, 57], [8, 57], // 01011010x\n [8, 58], [8, 58], // 01011011x\n [6, 192], [6, 192], [6, 192], [6, 192], // 010111xxx\n [6, 192], [6, 192], [6, 192], [6, 192],\n [6, 1664], [6, 1664], [6, 1664], [6, 1664], // 011000xxx\n [6, 1664], [6, 1664], [6, 1664], [6, 1664],\n [8, 448], [8, 448], // 01100100x\n [8, 512], [8, 512], // 01100101x\n [9, 704], // 011001100\n [9, 768], // 011001101\n [8, 640], [8, 640], // 01100111x\n [8, 576], [8, 576], // 01101000x\n [9, 832], // 011010010\n [9, 896], // 011010011\n [9, 960], // 011010100\n [9, 1024], // 011010101\n [9, 1088], // 011010110\n [9, 1152], // 011010111\n [9, 1216], // 011011000\n [9, 1280], // 011011001\n [9, 1344], // 011011010\n [9, 1408], // 011011011\n [7, 256], [7, 256], [7, 256], [7, 256], // 0110111xx\n [4, 2], [4, 2], [4, 2], [4, 2], // 0111xxxxx\n [4, 2], [4, 2], [4, 2], [4, 2],\n [4, 2], [4, 2], [4, 2], [4, 2],\n [4, 2], [4, 2], [4, 2], [4, 2],\n [4, 2], [4, 2], [4, 2], [4, 2],\n [4, 2], [4, 2], [4, 2], [4, 2],\n [4, 2], [4, 2], [4, 2], [4, 2],\n [4, 2], [4, 2], [4, 2], [4, 2],\n [4, 3], [4, 3], [4, 3], [4, 3], // 1000xxxxx\n [4, 3], [4, 3], [4, 3], [4, 3],\n [4, 3], [4, 3], [4, 3], [4, 3],\n [4, 3], [4, 3], [4, 3], [4, 3],\n [4, 3], [4, 3], [4, 3], [4, 3],\n [4, 3], [4, 3], [4, 3], [4, 3],\n [4, 3], [4, 3], [4, 3], [4, 3],\n [4, 3], [4, 3], [4, 3], [4, 3],\n [5, 128], [5, 128], [5, 128], [5, 128], // 10010xxxx\n [5, 128], [5, 128], [5, 128], [5, 128],\n [5, 128], [5, 128], [5, 128], [5, 128],\n [5, 128], [5, 128], [5, 128], [5, 128],\n [5, 8], [5, 8], [5, 8], [5, 8], // 10011xxxx\n [5, 8], [5, 8], [5, 8], [5, 8],\n [5, 8], [5, 8], [5, 8], [5, 8],\n [5, 8], [5, 8], [5, 8], [5, 8],\n [5, 9], [5, 9], [5, 9], [5, 9], // 10100xxxx\n [5, 9], [5, 9], [5, 9], [5, 9],\n [5, 9], [5, 9], [5, 9], [5, 9],\n [5, 9], [5, 9], [5, 9], [5, 9],\n [6, 16], [6, 16], [6, 16], [6, 16], // 101010xxx\n [6, 16], [6, 16], [6, 16], [6, 16],\n [6, 17], [6, 17], [6, 17], [6, 17], // 101011xxx\n [6, 17], [6, 17], [6, 17], [6, 17],\n [4, 4], [4, 4], [4, 4], [4, 4], // 1011xxxxx\n [4, 4], [4, 4], [4, 4], [4, 4],\n [4, 4], [4, 4], [4, 4], [4, 4],\n [4, 4], [4, 4], [4, 4], [4, 4],\n [4, 4], [4, 4], [4, 4], [4, 4],\n [4, 4], [4, 4], [4, 4], [4, 4],\n [4, 4], [4, 4], [4, 4], [4, 4],\n [4, 4], [4, 4], [4, 4], [4, 4],\n [4, 5], [4, 5], [4, 5], [4, 5], // 1100xxxxx\n [4, 5], [4, 5], [4, 5], [4, 5],\n [4, 5], [4, 5], [4, 5], [4, 5],\n [4, 5], [4, 5], [4, 5], [4, 5],\n [4, 5], [4, 5], [4, 5], [4, 5],\n [4, 5], [4, 5], [4, 5], [4, 5],\n [4, 5], [4, 5], [4, 5], [4, 5],\n [4, 5], [4, 5], [4, 5], [4, 5],\n [6, 14], [6, 14], [6, 14], [6, 14], // 110100xxx\n [6, 14], [6, 14], [6, 14], [6, 14],\n [6, 15], [6, 15], [6, 15], [6, 15], // 110101xxx\n [6, 15], [6, 15], [6, 15], [6, 15],\n [5, 64], [5, 64], [5, 64], [5, 64], // 11011xxxx\n [5, 64], [5, 64], [5, 64], [5, 64],\n [5, 64], [5, 64], [5, 64], [5, 64],\n [5, 64], [5, 64], [5, 64], [5, 64],\n [4, 6], [4, 6], [4, 6], [4, 6], // 1110xxxxx\n [4, 6], [4, 6], [4, 6], [4, 6],\n [4, 6], [4, 6], [4, 6], [4, 6],\n [4, 6], [4, 6], [4, 6], [4, 6],\n [4, 6], [4, 6], [4, 6], [4, 6],\n [4, 6], [4, 6], [4, 6], [4, 6],\n [4, 6], [4, 6], [4, 6], [4, 6],\n [4, 6], [4, 6], [4, 6], [4, 6],\n [4, 7], [4, 7], [4, 7], [4, 7], // 1111xxxxx\n [4, 7], [4, 7], [4, 7], [4, 7],\n [4, 7], [4, 7], [4, 7], [4, 7],\n [4, 7], [4, 7], [4, 7], [4, 7],\n [4, 7], [4, 7], [4, 7], [4, 7],\n [4, 7], [4, 7], [4, 7], [4, 7],\n [4, 7], [4, 7], [4, 7], [4, 7],\n [4, 7], [4, 7], [4, 7], [4, 7]\n ];\n\n var blackTable1 = [\n [-1, -1], [-1, -1], // 000000000000x\n [12, ccittEOL], [12, ccittEOL], // 000000000001x\n [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000001xx\n [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000010xx\n [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000011xx\n [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000100xx\n [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000101xx\n [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000110xx\n [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000111xx\n [11, 1792], [11, 1792], [11, 1792], [11, 1792], // 00000001000xx\n [12, 1984], [12, 1984], // 000000010010x\n [12, 2048], [12, 2048], // 000000010011x\n [12, 2112], [12, 2112], // 000000010100x\n [12, 2176], [12, 2176], // 000000010101x\n [12, 2240], [12, 2240], // 000000010110x\n [12, 2304], [12, 2304], // 000000010111x\n [11, 1856], [11, 1856], [11, 1856], [11, 1856], // 00000001100xx\n [11, 1920], [11, 1920], [11, 1920], [11, 1920], // 00000001101xx\n [12, 2368], [12, 2368], // 000000011100x\n [12, 2432], [12, 2432], // 000000011101x\n [12, 2496], [12, 2496], // 000000011110x\n [12, 2560], [12, 2560], // 000000011111x\n [10, 18], [10, 18], [10, 18], [10, 18], // 0000001000xxx\n [10, 18], [10, 18], [10, 18], [10, 18],\n [12, 52], [12, 52], // 000000100100x\n [13, 640], // 0000001001010\n [13, 704], // 0000001001011\n [13, 768], // 0000001001100\n [13, 832], // 0000001001101\n [12, 55], [12, 55], // 000000100111x\n [12, 56], [12, 56], // 000000101000x\n [13, 1280], // 0000001010010\n [13, 1344], // 0000001010011\n [13, 1408], // 0000001010100\n [13, 1472], // 0000001010101\n [12, 59], [12, 59], // 000000101011x\n [12, 60], [12, 60], // 000000101100x\n [13, 1536], // 0000001011010\n [13, 1600], // 0000001011011\n [11, 24], [11, 24], [11, 24], [11, 24], // 00000010111xx\n [11, 25], [11, 25], [11, 25], [11, 25], // 00000011000xx\n [13, 1664], // 0000001100100\n [13, 1728], // 0000001100101\n [12, 320], [12, 320], // 000000110011x\n [12, 384], [12, 384], // 000000110100x\n [12, 448], [12, 448], // 000000110101x\n [13, 512], // 0000001101100\n [13, 576], // 0000001101101\n [12, 53], [12, 53], // 000000110111x\n [12, 54], [12, 54], // 000000111000x\n [13, 896], // 0000001110010\n [13, 960], // 0000001110011\n [13, 1024], // 0000001110100\n [13, 1088], // 0000001110101\n [13, 1152], // 0000001110110\n [13, 1216], // 0000001110111\n [10, 64], [10, 64], [10, 64], [10, 64], // 0000001111xxx\n [10, 64], [10, 64], [10, 64], [10, 64]\n ];\n\n var blackTable2 = [\n [8, 13], [8, 13], [8, 13], [8, 13], // 00000100xxxx\n [8, 13], [8, 13], [8, 13], [8, 13],\n [8, 13], [8, 13], [8, 13], [8, 13],\n [8, 13], [8, 13], [8, 13], [8, 13],\n [11, 23], [11, 23], // 00000101000x\n [12, 50], // 000001010010\n [12, 51], // 000001010011\n [12, 44], // 000001010100\n [12, 45], // 000001010101\n [12, 46], // 000001010110\n [12, 47], // 000001010111\n [12, 57], // 000001011000\n [12, 58], // 000001011001\n [12, 61], // 000001011010\n [12, 256], // 000001011011\n [10, 16], [10, 16], [10, 16], [10, 16], // 0000010111xx\n [10, 17], [10, 17], [10, 17], [10, 17], // 0000011000xx\n [12, 48], // 000001100100\n [12, 49], // 000001100101\n [12, 62], // 000001100110\n [12, 63], // 000001100111\n [12, 30], // 000001101000\n [12, 31], // 000001101001\n [12, 32], // 000001101010\n [12, 33], // 000001101011\n [12, 40], // 000001101100\n [12, 41], // 000001101101\n [11, 22], [11, 22], // 00000110111x\n [8, 14], [8, 14], [8, 14], [8, 14], // 00000111xxxx\n [8, 14], [8, 14], [8, 14], [8, 14],\n [8, 14], [8, 14], [8, 14], [8, 14],\n [8, 14], [8, 14], [8, 14], [8, 14],\n [7, 10], [7, 10], [7, 10], [7, 10], // 0000100xxxxx\n [7, 10], [7, 10], [7, 10], [7, 10],\n [7, 10], [7, 10], [7, 10], [7, 10],\n [7, 10], [7, 10], [7, 10], [7, 10],\n [7, 10], [7, 10], [7, 10], [7, 10],\n [7, 10], [7, 10], [7, 10], [7, 10],\n [7, 10], [7, 10], [7, 10], [7, 10],\n [7, 10], [7, 10], [7, 10], [7, 10],\n [7, 11], [7, 11], [7, 11], [7, 11], // 0000101xxxxx\n [7, 11], [7, 11], [7, 11], [7, 11],\n [7, 11], [7, 11], [7, 11], [7, 11],\n [7, 11], [7, 11], [7, 11], [7, 11],\n [7, 11], [7, 11], [7, 11], [7, 11],\n [7, 11], [7, 11], [7, 11], [7, 11],\n [7, 11], [7, 11], [7, 11], [7, 11],\n [7, 11], [7, 11], [7, 11], [7, 11],\n [9, 15], [9, 15], [9, 15], [9, 15], // 000011000xxx\n [9, 15], [9, 15], [9, 15], [9, 15],\n [12, 128], // 000011001000\n [12, 192], // 000011001001\n [12, 26], // 000011001010\n [12, 27], // 000011001011\n [12, 28], // 000011001100\n [12, 29], // 000011001101\n [11, 19], [11, 19], // 00001100111x\n [11, 20], [11, 20], // 00001101000x\n [12, 34], // 000011010010\n [12, 35], // 000011010011\n [12, 36], // 000011010100\n [12, 37], // 000011010101\n [12, 38], // 000011010110\n [12, 39], // 000011010111\n [11, 21], [11, 21], // 00001101100x\n [12, 42], // 000011011010\n [12, 43], // 000011011011\n [10, 0], [10, 0], [10, 0], [10, 0], // 0000110111xx\n [7, 12], [7, 12], [7, 12], [7, 12], // 0000111xxxxx\n [7, 12], [7, 12], [7, 12], [7, 12],\n [7, 12], [7, 12], [7, 12], [7, 12],\n [7, 12], [7, 12], [7, 12], [7, 12],\n [7, 12], [7, 12], [7, 12], [7, 12],\n [7, 12], [7, 12], [7, 12], [7, 12],\n [7, 12], [7, 12], [7, 12], [7, 12],\n [7, 12], [7, 12], [7, 12], [7, 12]\n ];\n\n var blackTable3 = [\n [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 0000xx\n [6, 9], // 000100\n [6, 8], // 000101\n [5, 7], [5, 7], // 00011x\n [4, 6], [4, 6], [4, 6], [4, 6], // 0010xx\n [4, 5], [4, 5], [4, 5], [4, 5], // 0011xx\n [3, 1], [3, 1], [3, 1], [3, 1], // 010xxx\n [3, 1], [3, 1], [3, 1], [3, 1],\n [3, 4], [3, 4], [3, 4], [3, 4], // 011xxx\n [3, 4], [3, 4], [3, 4], [3, 4],\n [2, 3], [2, 3], [2, 3], [2, 3], // 10xxxx\n [2, 3], [2, 3], [2, 3], [2, 3],\n [2, 3], [2, 3], [2, 3], [2, 3],\n [2, 3], [2, 3], [2, 3], [2, 3],\n [2, 2], [2, 2], [2, 2], [2, 2], // 11xxxx\n [2, 2], [2, 2], [2, 2], [2, 2],\n [2, 2], [2, 2], [2, 2], [2, 2],\n [2, 2], [2, 2], [2, 2], [2, 2]\n ];\n\n function CCITTFaxStream(str, maybeLength, params) {\n this.str = str;\n this.dict = str.dict;\n\n params = params || Dict.empty;\n\n this.encoding = params.get('K') || 0;\n this.eoline = params.get('EndOfLine') || false;\n this.byteAlign = params.get('EncodedByteAlign') || false;\n this.columns = params.get('Columns') || 1728;\n this.rows = params.get('Rows') || 0;\n var eoblock = params.get('EndOfBlock');\n if (eoblock === null || eoblock === undefined) {\n eoblock = true;\n }\n this.eoblock = eoblock;\n this.black = params.get('BlackIs1') || false;\n\n this.codingLine = new Uint32Array(this.columns + 1);\n this.refLine = new Uint32Array(this.columns + 2);\n\n this.codingLine[0] = this.columns;\n this.codingPos = 0;\n\n this.row = 0;\n this.nextLine2D = this.encoding < 0;\n this.inputBits = 0;\n this.inputBuf = 0;\n this.outputBits = 0;\n\n var code1;\n while ((code1 = this.lookBits(12)) === 0) {\n this.eatBits(1);\n }\n if (code1 === 1) {\n this.eatBits(12);\n }\n if (this.encoding > 0) {\n this.nextLine2D = !this.lookBits(1);\n this.eatBits(1);\n }\n\n DecodeStream.call(this, maybeLength);\n }\n\n CCITTFaxStream.prototype = Object.create(DecodeStream.prototype);\n\n CCITTFaxStream.prototype.readBlock = function CCITTFaxStream_readBlock() {\n while (!this.eof) {\n var c = this.lookChar();\n this.ensureBuffer(this.bufferLength + 1);\n this.buffer[this.bufferLength++] = c;\n }\n };\n\n CCITTFaxStream.prototype.addPixels =\n function ccittFaxStreamAddPixels(a1, blackPixels) {\n var codingLine = this.codingLine;\n var codingPos = this.codingPos;\n\n if (a1 > codingLine[codingPos]) {\n if (a1 > this.columns) {\n info('row is wrong length');\n this.err = true;\n a1 = this.columns;\n }\n if ((codingPos & 1) ^ blackPixels) {\n ++codingPos;\n }\n\n codingLine[codingPos] = a1;\n }\n this.codingPos = codingPos;\n };\n\n CCITTFaxStream.prototype.addPixelsNeg =\n function ccittFaxStreamAddPixelsNeg(a1, blackPixels) {\n var codingLine = this.codingLine;\n var codingPos = this.codingPos;\n\n if (a1 > codingLine[codingPos]) {\n if (a1 > this.columns) {\n info('row is wrong length');\n this.err = true;\n a1 = this.columns;\n }\n if ((codingPos & 1) ^ blackPixels) {\n ++codingPos;\n }\n\n codingLine[codingPos] = a1;\n } else if (a1 < codingLine[codingPos]) {\n if (a1 < 0) {\n info('invalid code');\n this.err = true;\n a1 = 0;\n }\n while (codingPos > 0 && a1 < codingLine[codingPos - 1]) {\n --codingPos;\n }\n codingLine[codingPos] = a1;\n }\n\n this.codingPos = codingPos;\n };\n\n CCITTFaxStream.prototype.lookChar = function CCITTFaxStream_lookChar() {\n var refLine = this.refLine;\n var codingLine = this.codingLine;\n var columns = this.columns;\n\n var refPos, blackPixels, bits, i;\n\n if (this.outputBits === 0) {\n if (this.eof) {\n return null;\n }\n this.err = false;\n\n var code1, code2, code3;\n if (this.nextLine2D) {\n for (i = 0; codingLine[i] < columns; ++i) {\n refLine[i] = codingLine[i];\n }\n refLine[i++] = columns;\n refLine[i] = columns;\n codingLine[0] = 0;\n this.codingPos = 0;\n refPos = 0;\n blackPixels = 0;\n\n while (codingLine[this.codingPos] < columns) {\n code1 = this.getTwoDimCode();\n switch (code1) {\n case twoDimPass:\n this.addPixels(refLine[refPos + 1], blackPixels);\n if (refLine[refPos + 1] < columns) {\n refPos += 2;\n }\n break;\n case twoDimHoriz:\n code1 = code2 = 0;\n if (blackPixels) {\n do {\n code1 += (code3 = this.getBlackCode());\n } while (code3 >= 64);\n do {\n code2 += (code3 = this.getWhiteCode());\n } while (code3 >= 64);\n } else {\n do {\n code1 += (code3 = this.getWhiteCode());\n } while (code3 >= 64);\n do {\n code2 += (code3 = this.getBlackCode());\n } while (code3 >= 64);\n }\n this.addPixels(codingLine[this.codingPos] +\n code1, blackPixels);\n if (codingLine[this.codingPos] < columns) {\n this.addPixels(codingLine[this.codingPos] + code2,\n blackPixels ^ 1);\n }\n while (refLine[refPos] <= codingLine[this.codingPos] &&\n refLine[refPos] < columns) {\n refPos += 2;\n }\n break;\n case twoDimVertR3:\n this.addPixels(refLine[refPos] + 3, blackPixels);\n blackPixels ^= 1;\n if (codingLine[this.codingPos] < columns) {\n ++refPos;\n while (refLine[refPos] <= codingLine[this.codingPos] &&\n refLine[refPos] < columns) {\n refPos += 2;\n }\n }\n break;\n case twoDimVertR2:\n this.addPixels(refLine[refPos] + 2, blackPixels);\n blackPixels ^= 1;\n if (codingLine[this.codingPos] < columns) {\n ++refPos;\n while (refLine[refPos] <= codingLine[this.codingPos] &&\n refLine[refPos] < columns) {\n refPos += 2;\n }\n }\n break;\n case twoDimVertR1:\n this.addPixels(refLine[refPos] + 1, blackPixels);\n blackPixels ^= 1;\n if (codingLine[this.codingPos] < columns) {\n ++refPos;\n while (refLine[refPos] <= codingLine[this.codingPos] &&\n refLine[refPos] < columns) {\n refPos += 2;\n }\n }\n break;\n case twoDimVert0:\n this.addPixels(refLine[refPos], blackPixels);\n blackPixels ^= 1;\n if (codingLine[this.codingPos] < columns) {\n ++refPos;\n while (refLine[refPos] <= codingLine[this.codingPos] &&\n refLine[refPos] < columns) {\n refPos += 2;\n }\n }\n break;\n case twoDimVertL3:\n this.addPixelsNeg(refLine[refPos] - 3, blackPixels);\n blackPixels ^= 1;\n if (codingLine[this.codingPos] < columns) {\n if (refPos > 0) {\n --refPos;\n } else {\n ++refPos;\n }\n while (refLine[refPos] <= codingLine[this.codingPos] &&\n refLine[refPos] < columns) {\n refPos += 2;\n }\n }\n break;\n case twoDimVertL2:\n this.addPixelsNeg(refLine[refPos] - 2, blackPixels);\n blackPixels ^= 1;\n if (codingLine[this.codingPos] < columns) {\n if (refPos > 0) {\n --refPos;\n } else {\n ++refPos;\n }\n while (refLine[refPos] <= codingLine[this.codingPos] &&\n refLine[refPos] < columns) {\n refPos += 2;\n }\n }\n break;\n case twoDimVertL1:\n this.addPixelsNeg(refLine[refPos] - 1, blackPixels);\n blackPixels ^= 1;\n if (codingLine[this.codingPos] < columns) {\n if (refPos > 0) {\n --refPos;\n } else {\n ++refPos;\n }\n while (refLine[refPos] <= codingLine[this.codingPos] &&\n refLine[refPos] < columns) {\n refPos += 2;\n }\n }\n break;\n case ccittEOF:\n this.addPixels(columns, 0);\n this.eof = true;\n break;\n default:\n info('bad 2d code');\n this.addPixels(columns, 0);\n this.err = true;\n }\n }\n } else {\n codingLine[0] = 0;\n this.codingPos = 0;\n blackPixels = 0;\n while (codingLine[this.codingPos] < columns) {\n code1 = 0;\n if (blackPixels) {\n do {\n code1 += (code3 = this.getBlackCode());\n } while (code3 >= 64);\n } else {\n do {\n code1 += (code3 = this.getWhiteCode());\n } while (code3 >= 64);\n }\n this.addPixels(codingLine[this.codingPos] + code1, blackPixels);\n blackPixels ^= 1;\n }\n }\n\n var gotEOL = false;\n\n if (this.byteAlign) {\n this.inputBits &= ~7;\n }\n\n if (!this.eoblock && this.row === this.rows - 1) {\n this.eof = true;\n } else {\n code1 = this.lookBits(12);\n if (this.eoline) {\n while (code1 !== ccittEOF && code1 !== 1) {\n this.eatBits(1);\n code1 = this.lookBits(12);\n }\n } else {\n while (code1 === 0) {\n this.eatBits(1);\n code1 = this.lookBits(12);\n }\n }\n if (code1 === 1) {\n this.eatBits(12);\n gotEOL = true;\n } else if (code1 === ccittEOF) {\n this.eof = true;\n }\n }\n\n if (!this.eof && this.encoding > 0) {\n this.nextLine2D = !this.lookBits(1);\n this.eatBits(1);\n }\n\n if (this.eoblock && gotEOL && this.byteAlign) {\n code1 = this.lookBits(12);\n if (code1 === 1) {\n this.eatBits(12);\n if (this.encoding > 0) {\n this.lookBits(1);\n this.eatBits(1);\n }\n if (this.encoding >= 0) {\n for (i = 0; i < 4; ++i) {\n code1 = this.lookBits(12);\n if (code1 !== 1) {\n info('bad rtc code: ' + code1);\n }\n this.eatBits(12);\n if (this.encoding > 0) {\n this.lookBits(1);\n this.eatBits(1);\n }\n }\n }\n this.eof = true;\n }\n } else if (this.err && this.eoline) {\n while (true) {\n code1 = this.lookBits(13);\n if (code1 === ccittEOF) {\n this.eof = true;\n return null;\n }\n if ((code1 >> 1) === 1) {\n break;\n }\n this.eatBits(1);\n }\n this.eatBits(12);\n if (this.encoding > 0) {\n this.eatBits(1);\n this.nextLine2D = !(code1 & 1);\n }\n }\n\n if (codingLine[0] > 0) {\n this.outputBits = codingLine[this.codingPos = 0];\n } else {\n this.outputBits = codingLine[this.codingPos = 1];\n }\n this.row++;\n }\n\n var c;\n if (this.outputBits >= 8) {\n c = (this.codingPos & 1) ? 0 : 0xFF;\n this.outputBits -= 8;\n if (this.outputBits === 0 && codingLine[this.codingPos] < columns) {\n this.codingPos++;\n this.outputBits = (codingLine[this.codingPos] -\n codingLine[this.codingPos - 1]);\n }\n } else {\n bits = 8;\n c = 0;\n do {\n if (this.outputBits > bits) {\n c <<= bits;\n if (!(this.codingPos & 1)) {\n c |= 0xFF >> (8 - bits);\n }\n this.outputBits -= bits;\n bits = 0;\n } else {\n c <<= this.outputBits;\n if (!(this.codingPos & 1)) {\n c |= 0xFF >> (8 - this.outputBits);\n }\n bits -= this.outputBits;\n this.outputBits = 0;\n if (codingLine[this.codingPos] < columns) {\n this.codingPos++;\n this.outputBits = (codingLine[this.codingPos] -\n codingLine[this.codingPos - 1]);\n } else if (bits > 0) {\n c <<= bits;\n bits = 0;\n }\n }\n } while (bits);\n }\n if (this.black) {\n c ^= 0xFF;\n }\n return c;\n };\n\n // This functions returns the code found from the table.\n // The start and end parameters set the boundaries for searching the table.\n // The limit parameter is optional. Function returns an array with three\n // values. The first array element indicates whether a valid code is being\n // returned. The second array element is the actual code. The third array\n // element indicates whether EOF was reached.\n CCITTFaxStream.prototype.findTableCode =\n function ccittFaxStreamFindTableCode(start, end, table, limit) {\n\n var limitValue = limit || 0;\n for (var i = start; i <= end; ++i) {\n var code = this.lookBits(i);\n if (code === ccittEOF) {\n return [true, 1, false];\n }\n if (i < end) {\n code <<= end - i;\n }\n if (!limitValue || code >= limitValue) {\n var p = table[code - limitValue];\n if (p[0] === i) {\n this.eatBits(i);\n return [true, p[1], true];\n }\n }\n }\n return [false, 0, false];\n };\n\n CCITTFaxStream.prototype.getTwoDimCode =\n function ccittFaxStreamGetTwoDimCode() {\n\n var code = 0;\n var p;\n if (this.eoblock) {\n code = this.lookBits(7);\n p = twoDimTable[code];\n if (p && p[0] > 0) {\n this.eatBits(p[0]);\n return p[1];\n }\n } else {\n var result = this.findTableCode(1, 7, twoDimTable);\n if (result[0] && result[2]) {\n return result[1];\n }\n }\n info('Bad two dim code');\n return ccittEOF;\n };\n\n CCITTFaxStream.prototype.getWhiteCode =\n function ccittFaxStreamGetWhiteCode() {\n\n var code = 0;\n var p;\n if (this.eoblock) {\n code = this.lookBits(12);\n if (code === ccittEOF) {\n return 1;\n }\n\n if ((code >> 5) === 0) {\n p = whiteTable1[code];\n } else {\n p = whiteTable2[code >> 3];\n }\n\n if (p[0] > 0) {\n this.eatBits(p[0]);\n return p[1];\n }\n } else {\n var result = this.findTableCode(1, 9, whiteTable2);\n if (result[0]) {\n return result[1];\n }\n\n result = this.findTableCode(11, 12, whiteTable1);\n if (result[0]) {\n return result[1];\n }\n }\n info('bad white code');\n this.eatBits(1);\n return 1;\n };\n\n CCITTFaxStream.prototype.getBlackCode =\n function ccittFaxStreamGetBlackCode() {\n\n var code, p;\n if (this.eoblock) {\n code = this.lookBits(13);\n if (code === ccittEOF) {\n return 1;\n }\n if ((code >> 7) === 0) {\n p = blackTable1[code];\n } else if ((code >> 9) === 0 && (code >> 7) !== 0) {\n p = blackTable2[(code >> 1) - 64];\n } else {\n p = blackTable3[code >> 7];\n }\n\n if (p[0] > 0) {\n this.eatBits(p[0]);\n return p[1];\n }\n } else {\n var result = this.findTableCode(2, 6, blackTable3);\n if (result[0]) {\n return result[1];\n }\n\n result = this.findTableCode(7, 12, blackTable2, 64);\n if (result[0]) {\n return result[1];\n }\n\n result = this.findTableCode(10, 13, blackTable1);\n if (result[0]) {\n return result[1];\n }\n }\n info('bad black code');\n this.eatBits(1);\n return 1;\n };\n\n CCITTFaxStream.prototype.lookBits = function CCITTFaxStream_lookBits(n) {\n var c;\n while (this.inputBits < n) {\n if ((c = this.str.getByte()) === -1) {\n if (this.inputBits === 0) {\n return ccittEOF;\n }\n return ((this.inputBuf << (n - this.inputBits)) &\n (0xFFFF >> (16 - n)));\n }\n this.inputBuf = (this.inputBuf << 8) | c;\n this.inputBits += 8;\n }\n return (this.inputBuf >> (this.inputBits - n)) & (0xFFFF >> (16 - n));\n };\n\n CCITTFaxStream.prototype.eatBits = function CCITTFaxStream_eatBits(n) {\n if ((this.inputBits -= n) < 0) {\n this.inputBits = 0;\n }\n };\n\n return CCITTFaxStream;\n})();\n\nvar LZWStream = (function LZWStreamClosure() {\n function LZWStream(str, maybeLength, earlyChange) {\n this.str = str;\n this.dict = str.dict;\n this.cachedData = 0;\n this.bitsCached = 0;\n\n var maxLzwDictionarySize = 4096;\n var lzwState = {\n earlyChange,\n codeLength: 9,\n nextCode: 258,\n dictionaryValues: new Uint8Array(maxLzwDictionarySize),\n dictionaryLengths: new Uint16Array(maxLzwDictionarySize),\n dictionaryPrevCodes: new Uint16Array(maxLzwDictionarySize),\n currentSequence: new Uint8Array(maxLzwDictionarySize),\n currentSequenceLength: 0,\n };\n for (var i = 0; i < 256; ++i) {\n lzwState.dictionaryValues[i] = i;\n lzwState.dictionaryLengths[i] = 1;\n }\n this.lzwState = lzwState;\n\n DecodeStream.call(this, maybeLength);\n }\n\n LZWStream.prototype = Object.create(DecodeStream.prototype);\n\n LZWStream.prototype.readBits = function LZWStream_readBits(n) {\n var bitsCached = this.bitsCached;\n var cachedData = this.cachedData;\n while (bitsCached < n) {\n var c = this.str.getByte();\n if (c === -1) {\n this.eof = true;\n return null;\n }\n cachedData = (cachedData << 8) | c;\n bitsCached += 8;\n }\n this.bitsCached = (bitsCached -= n);\n this.cachedData = cachedData;\n this.lastCode = null;\n return (cachedData >>> bitsCached) & ((1 << n) - 1);\n };\n\n LZWStream.prototype.readBlock = function LZWStream_readBlock() {\n var blockSize = 512;\n var estimatedDecodedSize = blockSize * 2, decodedSizeDelta = blockSize;\n var i, j, q;\n\n var lzwState = this.lzwState;\n if (!lzwState) {\n return; // eof was found\n }\n\n var earlyChange = lzwState.earlyChange;\n var nextCode = lzwState.nextCode;\n var dictionaryValues = lzwState.dictionaryValues;\n var dictionaryLengths = lzwState.dictionaryLengths;\n var dictionaryPrevCodes = lzwState.dictionaryPrevCodes;\n var codeLength = lzwState.codeLength;\n var prevCode = lzwState.prevCode;\n var currentSequence = lzwState.currentSequence;\n var currentSequenceLength = lzwState.currentSequenceLength;\n\n var decodedLength = 0;\n var currentBufferLength = this.bufferLength;\n var buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize);\n\n for (i = 0; i < blockSize; i++) {\n var code = this.readBits(codeLength);\n var hasPrev = currentSequenceLength > 0;\n if (code < 256) {\n currentSequence[0] = code;\n currentSequenceLength = 1;\n } else if (code >= 258) {\n if (code < nextCode) {\n currentSequenceLength = dictionaryLengths[code];\n for (j = currentSequenceLength - 1, q = code; j >= 0; j--) {\n currentSequence[j] = dictionaryValues[q];\n q = dictionaryPrevCodes[q];\n }\n } else {\n currentSequence[currentSequenceLength++] = currentSequence[0];\n }\n } else if (code === 256) {\n codeLength = 9;\n nextCode = 258;\n currentSequenceLength = 0;\n continue;\n } else {\n this.eof = true;\n delete this.lzwState;\n break;\n }\n\n if (hasPrev) {\n dictionaryPrevCodes[nextCode] = prevCode;\n dictionaryLengths[nextCode] = dictionaryLengths[prevCode] + 1;\n dictionaryValues[nextCode] = currentSequence[0];\n nextCode++;\n codeLength = (nextCode + earlyChange) & (nextCode + earlyChange - 1) ?\n codeLength : Math.min(Math.log(nextCode + earlyChange) /\n 0.6931471805599453 + 1, 12) | 0;\n }\n prevCode = code;\n\n decodedLength += currentSequenceLength;\n if (estimatedDecodedSize < decodedLength) {\n do {\n estimatedDecodedSize += decodedSizeDelta;\n } while (estimatedDecodedSize < decodedLength);\n buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize);\n }\n for (j = 0; j < currentSequenceLength; j++) {\n buffer[currentBufferLength++] = currentSequence[j];\n }\n }\n lzwState.nextCode = nextCode;\n lzwState.codeLength = codeLength;\n lzwState.prevCode = prevCode;\n lzwState.currentSequenceLength = currentSequenceLength;\n\n this.bufferLength = currentBufferLength;\n };\n\n return LZWStream;\n})();\n\nvar NullStream = (function NullStreamClosure() {\n function NullStream() {\n Stream.call(this, new Uint8Array(0));\n }\n\n NullStream.prototype = Stream.prototype;\n\n return NullStream;\n})();\n\nexport {\n Ascii85Stream,\n AsciiHexStream,\n CCITTFaxStream,\n DecryptStream,\n DecodeStream,\n FlateStream,\n Jbig2Stream,\n JpegStream,\n JpxStream,\n NullStream,\n PredictorStream,\n RunLengthStream,\n Stream,\n StreamsSequenceStream,\n StringStream,\n LZWStream,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/stream.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n FormatError, info, isArray, isString, shadow, warn\n} from '../shared/util';\nimport { isDict, isName, isStream } from './primitives';\nimport { PDFFunction } from './function';\n\nvar ColorSpace = (function ColorSpaceClosure() {\n /**\n * Resizes an RGB image with 3 components.\n * @param {TypedArray} src - The source buffer.\n * @param {Number} bpc - Number of bits per component.\n * @param {Number} w1 - Original width.\n * @param {Number} h1 - Original height.\n * @param {Number} w2 - New width.\n * @param {Number} h2 - New height.\n * @param {Number} alpha01 - Size reserved for the alpha channel.\n * @param {TypedArray} dest - The destination buffer.\n */\n function resizeRgbImage(src, bpc, w1, h1, w2, h2, alpha01, dest) {\n var COMPONENTS = 3;\n alpha01 = alpha01 !== 1 ? 0 : alpha01;\n var xRatio = w1 / w2;\n var yRatio = h1 / h2;\n var i, j, py, newIndex = 0, oldIndex;\n var xScaled = new Uint16Array(w2);\n var w1Scanline = w1 * COMPONENTS;\n\n for (i = 0; i < w2; i++) {\n xScaled[i] = Math.floor(i * xRatio) * COMPONENTS;\n }\n for (i = 0; i < h2; i++) {\n py = Math.floor(i * yRatio) * w1Scanline;\n for (j = 0; j < w2; j++) {\n oldIndex = py + xScaled[j];\n dest[newIndex++] = src[oldIndex++];\n dest[newIndex++] = src[oldIndex++];\n dest[newIndex++] = src[oldIndex++];\n newIndex += alpha01;\n }\n }\n }\n\n // Constructor should define this.numComps, this.defaultColor, this.name\n function ColorSpace() {\n throw new Error('should not call ColorSpace constructor');\n }\n\n ColorSpace.prototype = {\n /**\n * Converts the color value to the RGB color. The color components are\n * located in the src array starting from the srcOffset. Returns the array\n * of the rgb components, each value ranging from [0,255].\n */\n getRgb: function ColorSpace_getRgb(src, srcOffset) {\n var rgb = new Uint8Array(3);\n this.getRgbItem(src, srcOffset, rgb, 0);\n return rgb;\n },\n /**\n * Converts the color value to the RGB color, similar to the getRgb method.\n * The result placed into the dest array starting from the destOffset.\n */\n getRgbItem: function ColorSpace_getRgbItem(src, srcOffset,\n dest, destOffset) {\n throw new Error('Should not call ColorSpace.getRgbItem');\n },\n /**\n * Converts the specified number of the color values to the RGB colors.\n * The colors are located in the src array starting from the srcOffset.\n * The result is placed into the dest array starting from the destOffset.\n * The src array items shall be in [0,2^bits) range, the dest array items\n * will be in [0,255] range. alpha01 indicates how many alpha components\n * there are in the dest array; it will be either 0 (RGB array) or 1 (RGBA\n * array).\n */\n getRgbBuffer: function ColorSpace_getRgbBuffer(src, srcOffset, count,\n dest, destOffset, bits,\n alpha01) {\n throw new Error('Should not call ColorSpace.getRgbBuffer');\n },\n /**\n * Determines the number of bytes required to store the result of the\n * conversion done by the getRgbBuffer method. As in getRgbBuffer,\n * |alpha01| is either 0 (RGB output) or 1 (RGBA output).\n */\n getOutputLength: function ColorSpace_getOutputLength(inputLength,\n alpha01) {\n throw new Error('Should not call ColorSpace.getOutputLength');\n },\n /**\n * Returns true if source data will be equal the result/output data.\n */\n isPassthrough: function ColorSpace_isPassthrough(bits) {\n return false;\n },\n /**\n * Fills in the RGB colors in the destination buffer. alpha01 indicates\n * how many alpha components there are in the dest array; it will be either\n * 0 (RGB array) or 1 (RGBA array).\n */\n fillRgb: function ColorSpace_fillRgb(dest, originalWidth,\n originalHeight, width, height,\n actualHeight, bpc, comps, alpha01) {\n var count = originalWidth * originalHeight;\n var rgbBuf = null;\n var numComponentColors = 1 << bpc;\n var needsResizing = originalHeight !== height || originalWidth !== width;\n var i, ii;\n\n if (this.isPassthrough(bpc)) {\n rgbBuf = comps;\n } else if (this.numComps === 1 && count > numComponentColors &&\n this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') {\n // Optimization: create a color map when there is just one component and\n // we are converting more colors than the size of the color map. We\n // don't build the map if the colorspace is gray or rgb since those\n // methods are faster than building a map. This mainly offers big speed\n // ups for indexed and alternate colorspaces.\n //\n // TODO it may be worth while to cache the color map. While running\n // testing I never hit a cache so I will leave that out for now (perhaps\n // we are reparsing colorspaces too much?).\n var allColors = bpc <= 8 ? new Uint8Array(numComponentColors) :\n new Uint16Array(numComponentColors);\n var key;\n for (i = 0; i < numComponentColors; i++) {\n allColors[i] = i;\n }\n var colorMap = new Uint8Array(numComponentColors * 3);\n this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc,\n /* alpha01 = */ 0);\n\n var destPos, rgbPos;\n if (!needsResizing) {\n // Fill in the RGB values directly into |dest|.\n destPos = 0;\n for (i = 0; i < count; ++i) {\n key = comps[i] * 3;\n dest[destPos++] = colorMap[key];\n dest[destPos++] = colorMap[key + 1];\n dest[destPos++] = colorMap[key + 2];\n destPos += alpha01;\n }\n } else {\n rgbBuf = new Uint8Array(count * 3);\n rgbPos = 0;\n for (i = 0; i < count; ++i) {\n key = comps[i] * 3;\n rgbBuf[rgbPos++] = colorMap[key];\n rgbBuf[rgbPos++] = colorMap[key + 1];\n rgbBuf[rgbPos++] = colorMap[key + 2];\n }\n }\n } else {\n if (!needsResizing) {\n // Fill in the RGB values directly into |dest|.\n this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc,\n alpha01);\n } else {\n rgbBuf = new Uint8Array(count * 3);\n this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc,\n /* alpha01 = */ 0);\n }\n }\n\n if (rgbBuf) {\n if (needsResizing) {\n resizeRgbImage(rgbBuf, bpc, originalWidth, originalHeight,\n width, height, alpha01, dest);\n } else {\n rgbPos = 0;\n destPos = 0;\n for (i = 0, ii = width * actualHeight; i < ii; i++) {\n dest[destPos++] = rgbBuf[rgbPos++];\n dest[destPos++] = rgbBuf[rgbPos++];\n dest[destPos++] = rgbBuf[rgbPos++];\n destPos += alpha01;\n }\n }\n }\n },\n /**\n * True if the colorspace has components in the default range of [0, 1].\n * This should be true for all colorspaces except for lab color spaces\n * which are [0,100], [-128, 127], [-128, 127].\n */\n usesZeroToOneRange: true,\n };\n\n ColorSpace.parse = function ColorSpace_parse(cs, xref, res) {\n var IR = ColorSpace.parseToIR(cs, xref, res);\n if (IR instanceof AlternateCS) {\n return IR;\n }\n return ColorSpace.fromIR(IR);\n };\n\n ColorSpace.fromIR = function ColorSpace_fromIR(IR) {\n var name = isArray(IR) ? IR[0] : IR;\n var whitePoint, blackPoint, gamma;\n\n switch (name) {\n case 'DeviceGrayCS':\n return this.singletons.gray;\n case 'DeviceRgbCS':\n return this.singletons.rgb;\n case 'DeviceCmykCS':\n return this.singletons.cmyk;\n case 'CalGrayCS':\n whitePoint = IR[1];\n blackPoint = IR[2];\n gamma = IR[3];\n return new CalGrayCS(whitePoint, blackPoint, gamma);\n case 'CalRGBCS':\n whitePoint = IR[1];\n blackPoint = IR[2];\n gamma = IR[3];\n var matrix = IR[4];\n return new CalRGBCS(whitePoint, blackPoint, gamma, matrix);\n case 'PatternCS':\n var basePatternCS = IR[1];\n if (basePatternCS) {\n basePatternCS = ColorSpace.fromIR(basePatternCS);\n }\n return new PatternCS(basePatternCS);\n case 'IndexedCS':\n var baseIndexedCS = IR[1];\n var hiVal = IR[2];\n var lookup = IR[3];\n return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup);\n case 'AlternateCS':\n var numComps = IR[1];\n var alt = IR[2];\n var tintFnIR = IR[3];\n\n return new AlternateCS(numComps, ColorSpace.fromIR(alt),\n PDFFunction.fromIR(tintFnIR));\n case 'LabCS':\n whitePoint = IR[1];\n blackPoint = IR[2];\n var range = IR[3];\n return new LabCS(whitePoint, blackPoint, range);\n default:\n throw new FormatError(`Unknown colorspace name: ${name}`);\n }\n };\n\n ColorSpace.parseToIR = function ColorSpace_parseToIR(cs, xref, res) {\n if (isName(cs)) {\n var colorSpaces = res.get('ColorSpace');\n if (isDict(colorSpaces)) {\n var refcs = colorSpaces.get(cs.name);\n if (refcs) {\n cs = refcs;\n }\n }\n }\n\n cs = xref.fetchIfRef(cs);\n if (isName(cs)) {\n switch (cs.name) {\n case 'DeviceGray':\n case 'G':\n return 'DeviceGrayCS';\n case 'DeviceRGB':\n case 'RGB':\n return 'DeviceRgbCS';\n case 'DeviceCMYK':\n case 'CMYK':\n return 'DeviceCmykCS';\n case 'Pattern':\n return ['PatternCS', null];\n default:\n throw new FormatError(`unrecognized colorspace ${cs.name}`);\n }\n }\n if (isArray(cs)) {\n var mode = xref.fetchIfRef(cs[0]).name;\n var numComps, params, alt, whitePoint, blackPoint, gamma;\n\n switch (mode) {\n case 'DeviceGray':\n case 'G':\n return 'DeviceGrayCS';\n case 'DeviceRGB':\n case 'RGB':\n return 'DeviceRgbCS';\n case 'DeviceCMYK':\n case 'CMYK':\n return 'DeviceCmykCS';\n case 'CalGray':\n params = xref.fetchIfRef(cs[1]);\n whitePoint = params.getArray('WhitePoint');\n blackPoint = params.getArray('BlackPoint');\n gamma = params.get('Gamma');\n return ['CalGrayCS', whitePoint, blackPoint, gamma];\n case 'CalRGB':\n params = xref.fetchIfRef(cs[1]);\n whitePoint = params.getArray('WhitePoint');\n blackPoint = params.getArray('BlackPoint');\n gamma = params.getArray('Gamma');\n var matrix = params.getArray('Matrix');\n return ['CalRGBCS', whitePoint, blackPoint, gamma, matrix];\n case 'ICCBased':\n var stream = xref.fetchIfRef(cs[1]);\n var dict = stream.dict;\n numComps = dict.get('N');\n alt = dict.get('Alternate');\n if (alt) {\n var altIR = ColorSpace.parseToIR(alt, xref, res);\n // Parse the /Alternate CS to ensure that the number of components\n // are correct, and also (indirectly) that it is not a PatternCS.\n var altCS = ColorSpace.fromIR(altIR);\n if (altCS.numComps === numComps) {\n return altIR;\n }\n warn('ICCBased color space: Ignoring incorrect /Alternate entry.');\n }\n if (numComps === 1) {\n return 'DeviceGrayCS';\n } else if (numComps === 3) {\n return 'DeviceRgbCS';\n } else if (numComps === 4) {\n return 'DeviceCmykCS';\n }\n break;\n case 'Pattern':\n var basePatternCS = cs[1] || null;\n if (basePatternCS) {\n basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res);\n }\n return ['PatternCS', basePatternCS];\n case 'Indexed':\n case 'I':\n var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res);\n var hiVal = xref.fetchIfRef(cs[2]) + 1;\n var lookup = xref.fetchIfRef(cs[3]);\n if (isStream(lookup)) {\n lookup = lookup.getBytes();\n }\n return ['IndexedCS', baseIndexedCS, hiVal, lookup];\n case 'Separation':\n case 'DeviceN':\n var name = xref.fetchIfRef(cs[1]);\n numComps = isArray(name) ? name.length : 1;\n alt = ColorSpace.parseToIR(cs[2], xref, res);\n var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));\n return ['AlternateCS', numComps, alt, tintFnIR];\n case 'Lab':\n params = xref.fetchIfRef(cs[1]);\n whitePoint = params.getArray('WhitePoint');\n blackPoint = params.getArray('BlackPoint');\n var range = params.getArray('Range');\n return ['LabCS', whitePoint, blackPoint, range];\n default:\n throw new FormatError(`unimplemented color space object \"${mode}\"`);\n }\n }\n throw new FormatError(`unrecognized color space object: \"${cs}\"`);\n };\n /**\n * Checks if a decode map matches the default decode map for a color space.\n * This handles the general decode maps where there are two values per\n * component. e.g. [0, 1, 0, 1, 0, 1] for a RGB color.\n * This does not handle Lab, Indexed, or Pattern decode maps since they are\n * slightly different.\n * @param {Array} decode Decode map (usually from an image).\n * @param {Number} n Number of components the color space has.\n */\n ColorSpace.isDefaultDecode = function ColorSpace_isDefaultDecode(decode, n) {\n if (!isArray(decode)) {\n return true;\n }\n\n if (n * 2 !== decode.length) {\n warn('The decode map is not the correct length');\n return true;\n }\n for (var i = 0, ii = decode.length; i < ii; i += 2) {\n if (decode[i] !== 0 || decode[i + 1] !== 1) {\n return false;\n }\n }\n return true;\n };\n\n ColorSpace.singletons = {\n get gray() {\n return shadow(this, 'gray', new DeviceGrayCS());\n },\n get rgb() {\n return shadow(this, 'rgb', new DeviceRgbCS());\n },\n get cmyk() {\n return shadow(this, 'cmyk', new DeviceCmykCS());\n },\n };\n\n return ColorSpace;\n})();\n\n/**\n * Alternate color space handles both Separation and DeviceN color spaces. A\n * Separation color space is actually just a DeviceN with one color component.\n * Both color spaces use a tinting function to convert colors to a base color\n * space.\n */\nvar AlternateCS = (function AlternateCSClosure() {\n function AlternateCS(numComps, base, tintFn) {\n this.name = 'Alternate';\n this.numComps = numComps;\n this.defaultColor = new Float32Array(numComps);\n for (var i = 0; i < numComps; ++i) {\n this.defaultColor[i] = 1;\n }\n this.base = base;\n this.tintFn = tintFn;\n this.tmpBuf = new Float32Array(base.numComps);\n }\n\n AlternateCS.prototype = {\n getRgb: ColorSpace.prototype.getRgb,\n getRgbItem: function AlternateCS_getRgbItem(src, srcOffset,\n dest, destOffset) {\n var tmpBuf = this.tmpBuf;\n this.tintFn(src, srcOffset, tmpBuf, 0);\n this.base.getRgbItem(tmpBuf, 0, dest, destOffset);\n },\n getRgbBuffer: function AlternateCS_getRgbBuffer(src, srcOffset, count,\n dest, destOffset, bits,\n alpha01) {\n var tintFn = this.tintFn;\n var base = this.base;\n var scale = 1 / ((1 << bits) - 1);\n var baseNumComps = base.numComps;\n var usesZeroToOneRange = base.usesZeroToOneRange;\n var isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) &&\n alpha01 === 0;\n var pos = isPassthrough ? destOffset : 0;\n var baseBuf = isPassthrough ? dest : new Uint8Array(baseNumComps * count);\n var numComps = this.numComps;\n\n var scaled = new Float32Array(numComps);\n var tinted = new Float32Array(baseNumComps);\n var i, j;\n\n for (i = 0; i < count; i++) {\n for (j = 0; j < numComps; j++) {\n scaled[j] = src[srcOffset++] * scale;\n }\n tintFn(scaled, 0, tinted, 0);\n if (usesZeroToOneRange) {\n for (j = 0; j < baseNumComps; j++) {\n baseBuf[pos++] = tinted[j] * 255;\n }\n } else {\n base.getRgbItem(tinted, 0, baseBuf, pos);\n pos += baseNumComps;\n }\n }\n\n if (!isPassthrough) {\n base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01);\n }\n },\n getOutputLength: function AlternateCS_getOutputLength(inputLength,\n alpha01) {\n return this.base.getOutputLength(inputLength *\n this.base.numComps / this.numComps,\n alpha01);\n },\n isPassthrough: ColorSpace.prototype.isPassthrough,\n fillRgb: ColorSpace.prototype.fillRgb,\n isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) {\n return ColorSpace.isDefaultDecode(decodeMap, this.numComps);\n },\n usesZeroToOneRange: true,\n };\n\n return AlternateCS;\n})();\n\nvar PatternCS = (function PatternCSClosure() {\n function PatternCS(baseCS) {\n this.name = 'Pattern';\n this.base = baseCS;\n }\n PatternCS.prototype = {};\n\n return PatternCS;\n})();\n\nvar IndexedCS = (function IndexedCSClosure() {\n function IndexedCS(base, highVal, lookup) {\n this.name = 'Indexed';\n this.numComps = 1;\n this.defaultColor = new Uint8Array(this.numComps);\n this.base = base;\n this.highVal = highVal;\n\n var baseNumComps = base.numComps;\n var length = baseNumComps * highVal;\n\n if (isStream(lookup)) {\n this.lookup = new Uint8Array(length);\n var bytes = lookup.getBytes(length);\n this.lookup.set(bytes);\n } else if (isString(lookup)) {\n this.lookup = new Uint8Array(length);\n for (var i = 0; i < length; ++i) {\n this.lookup[i] = lookup.charCodeAt(i);\n }\n } else if (lookup instanceof Uint8Array || lookup instanceof Array) {\n this.lookup = lookup;\n } else {\n throw new FormatError(`Unrecognized lookup table: ${lookup}`);\n }\n }\n\n IndexedCS.prototype = {\n getRgb: ColorSpace.prototype.getRgb,\n getRgbItem: function IndexedCS_getRgbItem(src, srcOffset,\n dest, destOffset) {\n var numComps = this.base.numComps;\n var start = src[srcOffset] * numComps;\n this.base.getRgbBuffer(this.lookup, start, 1, dest, destOffset, 8, 0);\n },\n getRgbBuffer: function IndexedCS_getRgbBuffer(src, srcOffset, count,\n dest, destOffset, bits,\n alpha01) {\n var base = this.base;\n var numComps = base.numComps;\n var outputDelta = base.getOutputLength(numComps, alpha01);\n var lookup = this.lookup;\n\n for (var i = 0; i < count; ++i) {\n var lookupPos = src[srcOffset++] * numComps;\n base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01);\n destOffset += outputDelta;\n }\n },\n getOutputLength: function IndexedCS_getOutputLength(inputLength, alpha01) {\n return this.base.getOutputLength(inputLength * this.base.numComps,\n alpha01);\n },\n isPassthrough: ColorSpace.prototype.isPassthrough,\n fillRgb: ColorSpace.prototype.fillRgb,\n isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) {\n // indexed color maps shouldn't be changed\n return true;\n },\n usesZeroToOneRange: true,\n };\n return IndexedCS;\n})();\n\nvar DeviceGrayCS = (function DeviceGrayCSClosure() {\n function DeviceGrayCS() {\n this.name = 'DeviceGray';\n this.numComps = 1;\n this.defaultColor = new Float32Array(this.numComps);\n }\n\n DeviceGrayCS.prototype = {\n getRgb: ColorSpace.prototype.getRgb,\n getRgbItem: function DeviceGrayCS_getRgbItem(src, srcOffset,\n dest, destOffset) {\n var c = (src[srcOffset] * 255) | 0;\n c = c < 0 ? 0 : c > 255 ? 255 : c;\n dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c;\n },\n getRgbBuffer: function DeviceGrayCS_getRgbBuffer(src, srcOffset, count,\n dest, destOffset, bits,\n alpha01) {\n var scale = 255 / ((1 << bits) - 1);\n var j = srcOffset, q = destOffset;\n for (var i = 0; i < count; ++i) {\n var c = (scale * src[j++]) | 0;\n dest[q++] = c;\n dest[q++] = c;\n dest[q++] = c;\n q += alpha01;\n }\n },\n getOutputLength: function DeviceGrayCS_getOutputLength(inputLength,\n alpha01) {\n return inputLength * (3 + alpha01);\n },\n isPassthrough: ColorSpace.prototype.isPassthrough,\n fillRgb: ColorSpace.prototype.fillRgb,\n isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {\n return ColorSpace.isDefaultDecode(decodeMap, this.numComps);\n },\n usesZeroToOneRange: true,\n };\n return DeviceGrayCS;\n})();\n\nvar DeviceRgbCS = (function DeviceRgbCSClosure() {\n function DeviceRgbCS() {\n this.name = 'DeviceRGB';\n this.numComps = 3;\n this.defaultColor = new Float32Array(this.numComps);\n }\n DeviceRgbCS.prototype = {\n getRgb: ColorSpace.prototype.getRgb,\n getRgbItem: function DeviceRgbCS_getRgbItem(src, srcOffset,\n dest, destOffset) {\n var r = (src[srcOffset] * 255) | 0;\n var g = (src[srcOffset + 1] * 255) | 0;\n var b = (src[srcOffset + 2] * 255) | 0;\n dest[destOffset] = r < 0 ? 0 : r > 255 ? 255 : r;\n dest[destOffset + 1] = g < 0 ? 0 : g > 255 ? 255 : g;\n dest[destOffset + 2] = b < 0 ? 0 : b > 255 ? 255 : b;\n },\n getRgbBuffer: function DeviceRgbCS_getRgbBuffer(src, srcOffset, count,\n dest, destOffset, bits,\n alpha01) {\n if (bits === 8 && alpha01 === 0) {\n dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset);\n return;\n }\n var scale = 255 / ((1 << bits) - 1);\n var j = srcOffset, q = destOffset;\n for (var i = 0; i < count; ++i) {\n dest[q++] = (scale * src[j++]) | 0;\n dest[q++] = (scale * src[j++]) | 0;\n dest[q++] = (scale * src[j++]) | 0;\n q += alpha01;\n }\n },\n getOutputLength: function DeviceRgbCS_getOutputLength(inputLength,\n alpha01) {\n return (inputLength * (3 + alpha01) / 3) | 0;\n },\n isPassthrough: function DeviceRgbCS_isPassthrough(bits) {\n return bits === 8;\n },\n fillRgb: ColorSpace.prototype.fillRgb,\n isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) {\n return ColorSpace.isDefaultDecode(decodeMap, this.numComps);\n },\n usesZeroToOneRange: true,\n };\n return DeviceRgbCS;\n})();\n\nvar DeviceCmykCS = (function DeviceCmykCSClosure() {\n // The coefficients below was found using numerical analysis: the method of\n // steepest descent for the sum((f_i - color_value_i)^2) for r/g/b colors,\n // where color_value is the tabular value from the table of sampled RGB colors\n // from CMYK US Web Coated (SWOP) colorspace, and f_i is the corresponding\n // CMYK color conversion using the estimation below:\n // f(A, B,.. N) = Acc+Bcm+Ccy+Dck+c+Fmm+Gmy+Hmk+Im+Jyy+Kyk+Ly+Mkk+Nk+255\n function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {\n var c = src[srcOffset + 0] * srcScale;\n var m = src[srcOffset + 1] * srcScale;\n var y = src[srcOffset + 2] * srcScale;\n var k = src[srcOffset + 3] * srcScale;\n\n var r =\n (c * (-4.387332384609988 * c + 54.48615194189176 * m +\n 18.82290502165302 * y + 212.25662451639585 * k +\n -285.2331026137004) +\n m * (1.7149763477362134 * m - 5.6096736904047315 * y +\n -17.873870861415444 * k - 5.497006427196366) +\n y * (-2.5217340131683033 * y - 21.248923337353073 * k +\n 17.5119270841813) +\n k * (-21.86122147463605 * k - 189.48180835922747) + 255) | 0;\n var g =\n (c * (8.841041422036149 * c + 60.118027045597366 * m +\n 6.871425592049007 * y + 31.159100130055922 * k +\n -79.2970844816548) +\n m * (-15.310361306967817 * m + 17.575251261109482 * y +\n 131.35250912493976 * k - 190.9453302588951) +\n y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) +\n k * (-20.737325471181034 * k - 187.80453709719578) + 255) | 0;\n var b =\n (c * (0.8842522430003296 * c + 8.078677503112928 * m +\n 30.89978309703729 * y - 0.23883238689178934 * k +\n -14.183576799673286) +\n m * (10.49593273432072 * m + 63.02378494754052 * y +\n 50.606957656360734 * k - 112.23884253719248) +\n y * (0.03296041114873217 * y + 115.60384449646641 * k +\n -193.58209356861505) +\n k * (-22.33816807309886 * k - 180.12613974708367) + 255) | 0;\n\n dest[destOffset] = r > 255 ? 255 : r < 0 ? 0 : r;\n dest[destOffset + 1] = g > 255 ? 255 : g < 0 ? 0 : g;\n dest[destOffset + 2] = b > 255 ? 255 : b < 0 ? 0 : b;\n }\n\n function DeviceCmykCS() {\n this.name = 'DeviceCMYK';\n this.numComps = 4;\n this.defaultColor = new Float32Array(this.numComps);\n // Set the fourth component to the maximum value for a black color.\n this.defaultColor[3] = 1;\n }\n DeviceCmykCS.prototype = {\n getRgb: ColorSpace.prototype.getRgb,\n getRgbItem: function DeviceCmykCS_getRgbItem(src, srcOffset,\n dest, destOffset) {\n convertToRgb(src, srcOffset, 1, dest, destOffset);\n },\n getRgbBuffer: function DeviceCmykCS_getRgbBuffer(src, srcOffset, count,\n dest, destOffset, bits,\n alpha01) {\n var scale = 1 / ((1 << bits) - 1);\n for (var i = 0; i < count; i++) {\n convertToRgb(src, srcOffset, scale, dest, destOffset);\n srcOffset += 4;\n destOffset += 3 + alpha01;\n }\n },\n getOutputLength: function DeviceCmykCS_getOutputLength(inputLength,\n alpha01) {\n return (inputLength / 4 * (3 + alpha01)) | 0;\n },\n isPassthrough: ColorSpace.prototype.isPassthrough,\n fillRgb: ColorSpace.prototype.fillRgb,\n isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) {\n return ColorSpace.isDefaultDecode(decodeMap, this.numComps);\n },\n usesZeroToOneRange: true,\n };\n\n return DeviceCmykCS;\n})();\n\n//\n// CalGrayCS: Based on \"PDF Reference, Sixth Ed\", p.245\n//\nvar CalGrayCS = (function CalGrayCSClosure() {\n function CalGrayCS(whitePoint, blackPoint, gamma) {\n this.name = 'CalGray';\n this.numComps = 1;\n this.defaultColor = new Float32Array(this.numComps);\n\n if (!whitePoint) {\n throw new FormatError(\n 'WhitePoint missing - required for color space CalGray');\n }\n blackPoint = blackPoint || [0, 0, 0];\n gamma = gamma || 1;\n\n // Translate arguments to spec variables.\n this.XW = whitePoint[0];\n this.YW = whitePoint[1];\n this.ZW = whitePoint[2];\n\n this.XB = blackPoint[0];\n this.YB = blackPoint[1];\n this.ZB = blackPoint[2];\n\n this.G = gamma;\n\n // Validate variables as per spec.\n if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {\n throw new FormatError(`Invalid WhitePoint components for ${this.name}` +\n ', no fallback available');\n }\n\n if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {\n info('Invalid BlackPoint for ' + this.name + ', falling back to default');\n this.XB = this.YB = this.ZB = 0;\n }\n\n if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) {\n warn(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB +\n ', ZB: ' + this.ZB + ', only default values are supported.');\n }\n\n if (this.G < 1) {\n info('Invalid Gamma: ' + this.G + ' for ' + this.name +\n ', falling back to default');\n this.G = 1;\n }\n }\n\n function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {\n // A represents a gray component of a calibrated gray space.\n // A <---> AG in the spec\n var A = src[srcOffset] * scale;\n var AG = Math.pow(A, cs.G);\n\n // Computes L as per spec. ( = cs.YW * AG )\n // Except if other than default BlackPoint values are used.\n var L = cs.YW * AG;\n // http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html, Ch 4.\n // Convert values to rgb range [0, 255].\n var val = Math.max(295.8 * Math.pow(L, 0.333333333333333333) - 40.8, 0) | 0;\n dest[destOffset] = val;\n dest[destOffset + 1] = val;\n dest[destOffset + 2] = val;\n }\n\n CalGrayCS.prototype = {\n getRgb: ColorSpace.prototype.getRgb,\n getRgbItem: function CalGrayCS_getRgbItem(src, srcOffset,\n dest, destOffset) {\n convertToRgb(this, src, srcOffset, dest, destOffset, 1);\n },\n getRgbBuffer: function CalGrayCS_getRgbBuffer(src, srcOffset, count,\n dest, destOffset, bits,\n alpha01) {\n var scale = 1 / ((1 << bits) - 1);\n\n for (var i = 0; i < count; ++i) {\n convertToRgb(this, src, srcOffset, dest, destOffset, scale);\n srcOffset += 1;\n destOffset += 3 + alpha01;\n }\n },\n getOutputLength: function CalGrayCS_getOutputLength(inputLength, alpha01) {\n return inputLength * (3 + alpha01);\n },\n isPassthrough: ColorSpace.prototype.isPassthrough,\n fillRgb: ColorSpace.prototype.fillRgb,\n isDefaultDecode: function CalGrayCS_isDefaultDecode(decodeMap) {\n return ColorSpace.isDefaultDecode(decodeMap, this.numComps);\n },\n usesZeroToOneRange: true,\n };\n return CalGrayCS;\n})();\n\n//\n// CalRGBCS: Based on \"PDF Reference, Sixth Ed\", p.247\n//\nvar CalRGBCS = (function CalRGBCSClosure() {\n\n // See http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html for these\n // matrices.\n var BRADFORD_SCALE_MATRIX = new Float32Array([\n 0.8951, 0.2664, -0.1614,\n -0.7502, 1.7135, 0.0367,\n 0.0389, -0.0685, 1.0296]);\n\n var BRADFORD_SCALE_INVERSE_MATRIX = new Float32Array([\n 0.9869929, -0.1470543, 0.1599627,\n 0.4323053, 0.5183603, 0.0492912,\n -0.0085287, 0.0400428, 0.9684867]);\n\n // See http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html.\n var SRGB_D65_XYZ_TO_RGB_MATRIX = new Float32Array([\n 3.2404542, -1.5371385, -0.4985314,\n -0.9692660, 1.8760108, 0.0415560,\n 0.0556434, -0.2040259, 1.0572252]);\n\n var FLAT_WHITEPOINT_MATRIX = new Float32Array([1, 1, 1]);\n\n var tempNormalizeMatrix = new Float32Array(3);\n var tempConvertMatrix1 = new Float32Array(3);\n var tempConvertMatrix2 = new Float32Array(3);\n\n var DECODE_L_CONSTANT = Math.pow(((8 + 16) / 116), 3) / 8.0;\n\n function CalRGBCS(whitePoint, blackPoint, gamma, matrix) {\n this.name = 'CalRGB';\n this.numComps = 3;\n this.defaultColor = new Float32Array(this.numComps);\n\n if (!whitePoint) {\n throw new FormatError(\n 'WhitePoint missing - required for color space CalRGB');\n }\n blackPoint = blackPoint || new Float32Array(3);\n gamma = gamma || new Float32Array([1, 1, 1]);\n matrix = matrix || new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]);\n\n // Translate arguments to spec variables.\n var XW = whitePoint[0];\n var YW = whitePoint[1];\n var ZW = whitePoint[2];\n this.whitePoint = whitePoint;\n\n var XB = blackPoint[0];\n var YB = blackPoint[1];\n var ZB = blackPoint[2];\n this.blackPoint = blackPoint;\n\n this.GR = gamma[0];\n this.GG = gamma[1];\n this.GB = gamma[2];\n\n this.MXA = matrix[0];\n this.MYA = matrix[1];\n this.MZA = matrix[2];\n this.MXB = matrix[3];\n this.MYB = matrix[4];\n this.MZB = matrix[5];\n this.MXC = matrix[6];\n this.MYC = matrix[7];\n this.MZC = matrix[8];\n\n // Validate variables as per spec.\n if (XW < 0 || ZW < 0 || YW !== 1) {\n throw new FormatError(`Invalid WhitePoint components for ${this.name}` +\n ', no fallback available');\n }\n\n if (XB < 0 || YB < 0 || ZB < 0) {\n info('Invalid BlackPoint for ' + this.name + ' [' + XB + ', ' + YB +\n ', ' + ZB + '], falling back to default');\n this.blackPoint = new Float32Array(3);\n }\n\n if (this.GR < 0 || this.GG < 0 || this.GB < 0) {\n info('Invalid Gamma [' + this.GR + ', ' + this.GG + ', ' + this.GB +\n '] for ' + this.name + ', falling back to default');\n this.GR = this.GG = this.GB = 1;\n }\n\n if (this.MXA < 0 || this.MYA < 0 || this.MZA < 0 ||\n this.MXB < 0 || this.MYB < 0 || this.MZB < 0 ||\n this.MXC < 0 || this.MYC < 0 || this.MZC < 0) {\n info('Invalid Matrix for ' + this.name + ' [' +\n this.MXA + ', ' + this.MYA + ', ' + this.MZA +\n this.MXB + ', ' + this.MYB + ', ' + this.MZB +\n this.MXC + ', ' + this.MYC + ', ' + this.MZC +\n '], falling back to default');\n this.MXA = this.MYB = this.MZC = 1;\n this.MXB = this.MYA = this.MZA = this.MXC = this.MYC = this.MZB = 0;\n }\n }\n\n function matrixProduct(a, b, result) {\n result[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\n result[1] = a[3] * b[0] + a[4] * b[1] + a[5] * b[2];\n result[2] = a[6] * b[0] + a[7] * b[1] + a[8] * b[2];\n }\n\n function convertToFlat(sourceWhitePoint, LMS, result) {\n result[0] = LMS[0] * 1 / sourceWhitePoint[0];\n result[1] = LMS[1] * 1 / sourceWhitePoint[1];\n result[2] = LMS[2] * 1 / sourceWhitePoint[2];\n }\n\n function convertToD65(sourceWhitePoint, LMS, result) {\n var D65X = 0.95047;\n var D65Y = 1;\n var D65Z = 1.08883;\n\n result[0] = LMS[0] * D65X / sourceWhitePoint[0];\n result[1] = LMS[1] * D65Y / sourceWhitePoint[1];\n result[2] = LMS[2] * D65Z / sourceWhitePoint[2];\n }\n\n function sRGBTransferFunction(color) {\n // See http://en.wikipedia.org/wiki/SRGB.\n if (color <= 0.0031308) {\n return adjustToRange(0, 1, 12.92 * color);\n }\n\n return adjustToRange(0, 1, (1 + 0.055) * Math.pow(color, 1 / 2.4) - 0.055);\n }\n\n function adjustToRange(min, max, value) {\n return Math.max(min, Math.min(max, value));\n }\n\n function decodeL(L) {\n if (L < 0) {\n return -decodeL(-L);\n }\n\n if (L > 8.0) {\n return Math.pow(((L + 16) / 116), 3);\n }\n\n return L * DECODE_L_CONSTANT;\n }\n\n function compensateBlackPoint(sourceBlackPoint, XYZ_Flat, result) {\n\n // In case the blackPoint is already the default blackPoint then there is\n // no need to do compensation.\n if (sourceBlackPoint[0] === 0 &&\n sourceBlackPoint[1] === 0 &&\n sourceBlackPoint[2] === 0) {\n result[0] = XYZ_Flat[0];\n result[1] = XYZ_Flat[1];\n result[2] = XYZ_Flat[2];\n return;\n }\n\n // For the blackPoint calculation details, please see\n // http://www.adobe.com/content/dam/Adobe/en/devnet/photoshop/sdk/\n // AdobeBPC.pdf.\n // The destination blackPoint is the default blackPoint [0, 0, 0].\n var zeroDecodeL = decodeL(0);\n\n var X_DST = zeroDecodeL;\n var X_SRC = decodeL(sourceBlackPoint[0]);\n\n var Y_DST = zeroDecodeL;\n var Y_SRC = decodeL(sourceBlackPoint[1]);\n\n var Z_DST = zeroDecodeL;\n var Z_SRC = decodeL(sourceBlackPoint[2]);\n\n var X_Scale = (1 - X_DST) / (1 - X_SRC);\n var X_Offset = 1 - X_Scale;\n\n var Y_Scale = (1 - Y_DST) / (1 - Y_SRC);\n var Y_Offset = 1 - Y_Scale;\n\n var Z_Scale = (1 - Z_DST) / (1 - Z_SRC);\n var Z_Offset = 1 - Z_Scale;\n\n result[0] = XYZ_Flat[0] * X_Scale + X_Offset;\n result[1] = XYZ_Flat[1] * Y_Scale + Y_Offset;\n result[2] = XYZ_Flat[2] * Z_Scale + Z_Offset;\n }\n\n function normalizeWhitePointToFlat(sourceWhitePoint, XYZ_In, result) {\n\n // In case the whitePoint is already flat then there is no need to do\n // normalization.\n if (sourceWhitePoint[0] === 1 && sourceWhitePoint[2] === 1) {\n result[0] = XYZ_In[0];\n result[1] = XYZ_In[1];\n result[2] = XYZ_In[2];\n return;\n }\n\n var LMS = result;\n matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS);\n\n var LMS_Flat = tempNormalizeMatrix;\n convertToFlat(sourceWhitePoint, LMS, LMS_Flat);\n\n matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_Flat, result);\n }\n\n function normalizeWhitePointToD65(sourceWhitePoint, XYZ_In, result) {\n\n var LMS = result;\n matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS);\n\n var LMS_D65 = tempNormalizeMatrix;\n convertToD65(sourceWhitePoint, LMS, LMS_D65);\n\n matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_D65, result);\n }\n\n function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {\n // A, B and C represent a red, green and blue components of a calibrated\n // rgb space.\n var A = adjustToRange(0, 1, src[srcOffset] * scale);\n var B = adjustToRange(0, 1, src[srcOffset + 1] * scale);\n var C = adjustToRange(0, 1, src[srcOffset + 2] * scale);\n\n // A <---> AGR in the spec\n // B <---> BGG in the spec\n // C <---> CGB in the spec\n var AGR = Math.pow(A, cs.GR);\n var BGG = Math.pow(B, cs.GG);\n var CGB = Math.pow(C, cs.GB);\n\n // Computes intermediate variables L, M, N as per spec.\n // To decode X, Y, Z values map L, M, N directly to them.\n var X = cs.MXA * AGR + cs.MXB * BGG + cs.MXC * CGB;\n var Y = cs.MYA * AGR + cs.MYB * BGG + cs.MYC * CGB;\n var Z = cs.MZA * AGR + cs.MZB * BGG + cs.MZC * CGB;\n\n // The following calculations are based on this document:\n // http://www.adobe.com/content/dam/Adobe/en/devnet/photoshop/sdk/\n // AdobeBPC.pdf.\n var XYZ = tempConvertMatrix1;\n XYZ[0] = X;\n XYZ[1] = Y;\n XYZ[2] = Z;\n var XYZ_Flat = tempConvertMatrix2;\n\n normalizeWhitePointToFlat(cs.whitePoint, XYZ, XYZ_Flat);\n\n var XYZ_Black = tempConvertMatrix1;\n compensateBlackPoint(cs.blackPoint, XYZ_Flat, XYZ_Black);\n\n var XYZ_D65 = tempConvertMatrix2;\n normalizeWhitePointToD65(FLAT_WHITEPOINT_MATRIX, XYZ_Black, XYZ_D65);\n\n var SRGB = tempConvertMatrix1;\n matrixProduct(SRGB_D65_XYZ_TO_RGB_MATRIX, XYZ_D65, SRGB);\n\n var sR = sRGBTransferFunction(SRGB[0]);\n var sG = sRGBTransferFunction(SRGB[1]);\n var sB = sRGBTransferFunction(SRGB[2]);\n\n // Convert the values to rgb range [0, 255].\n dest[destOffset] = Math.round(sR * 255);\n dest[destOffset + 1] = Math.round(sG * 255);\n dest[destOffset + 2] = Math.round(sB * 255);\n }\n\n CalRGBCS.prototype = {\n getRgb: ColorSpace.prototype.getRgb,\n getRgbItem: function CalRGBCS_getRgbItem(src, srcOffset,\n dest, destOffset) {\n convertToRgb(this, src, srcOffset, dest, destOffset, 1);\n },\n getRgbBuffer: function CalRGBCS_getRgbBuffer(src, srcOffset, count,\n dest, destOffset, bits,\n alpha01) {\n var scale = 1 / ((1 << bits) - 1);\n\n for (var i = 0; i < count; ++i) {\n convertToRgb(this, src, srcOffset, dest, destOffset, scale);\n srcOffset += 3;\n destOffset += 3 + alpha01;\n }\n },\n getOutputLength: function CalRGBCS_getOutputLength(inputLength, alpha01) {\n return (inputLength * (3 + alpha01) / 3) | 0;\n },\n isPassthrough: ColorSpace.prototype.isPassthrough,\n fillRgb: ColorSpace.prototype.fillRgb,\n isDefaultDecode: function CalRGBCS_isDefaultDecode(decodeMap) {\n return ColorSpace.isDefaultDecode(decodeMap, this.numComps);\n },\n usesZeroToOneRange: true,\n };\n return CalRGBCS;\n})();\n\n//\n// LabCS: Based on \"PDF Reference, Sixth Ed\", p.250\n//\nvar LabCS = (function LabCSClosure() {\n function LabCS(whitePoint, blackPoint, range) {\n this.name = 'Lab';\n this.numComps = 3;\n this.defaultColor = new Float32Array(this.numComps);\n\n if (!whitePoint) {\n throw new FormatError(\n 'WhitePoint missing - required for color space Lab');\n }\n blackPoint = blackPoint || [0, 0, 0];\n range = range || [-100, 100, -100, 100];\n\n // Translate args to spec variables\n this.XW = whitePoint[0];\n this.YW = whitePoint[1];\n this.ZW = whitePoint[2];\n this.amin = range[0];\n this.amax = range[1];\n this.bmin = range[2];\n this.bmax = range[3];\n\n // These are here just for completeness - the spec doesn't offer any\n // formulas that use BlackPoint in Lab\n this.XB = blackPoint[0];\n this.YB = blackPoint[1];\n this.ZB = blackPoint[2];\n\n // Validate vars as per spec\n if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {\n throw new FormatError(\n 'Invalid WhitePoint components, no fallback available');\n }\n\n if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {\n info('Invalid BlackPoint, falling back to default');\n this.XB = this.YB = this.ZB = 0;\n }\n\n if (this.amin > this.amax || this.bmin > this.bmax) {\n info('Invalid Range, falling back to defaults');\n this.amin = -100;\n this.amax = 100;\n this.bmin = -100;\n this.bmax = 100;\n }\n }\n\n // Function g(x) from spec\n function fn_g(x) {\n var result;\n if (x >= 6 / 29) {\n result = x * x * x;\n } else {\n result = (108 / 841) * (x - 4 / 29);\n }\n return result;\n }\n\n function decode(value, high1, low2, high2) {\n return low2 + (value) * (high2 - low2) / (high1);\n }\n\n // If decoding is needed maxVal should be 2^bits per component - 1.\n function convertToRgb(cs, src, srcOffset, maxVal, dest, destOffset) {\n // XXX: Lab input is in the range of [0, 100], [amin, amax], [bmin, bmax]\n // not the usual [0, 1]. If a command like setFillColor is used the src\n // values will already be within the correct range. However, if we are\n // converting an image we have to map the values to the correct range given\n // above.\n // Ls,as,bs <---> L*,a*,b* in the spec\n var Ls = src[srcOffset];\n var as = src[srcOffset + 1];\n var bs = src[srcOffset + 2];\n if (maxVal !== false) {\n Ls = decode(Ls, maxVal, 0, 100);\n as = decode(as, maxVal, cs.amin, cs.amax);\n bs = decode(bs, maxVal, cs.bmin, cs.bmax);\n }\n\n // Adjust limits of 'as' and 'bs'\n as = as > cs.amax ? cs.amax : as < cs.amin ? cs.amin : as;\n bs = bs > cs.bmax ? cs.bmax : bs < cs.bmin ? cs.bmin : bs;\n\n // Computes intermediate variables X,Y,Z as per spec\n var M = (Ls + 16) / 116;\n var L = M + (as / 500);\n var N = M - (bs / 200);\n\n var X = cs.XW * fn_g(L);\n var Y = cs.YW * fn_g(M);\n var Z = cs.ZW * fn_g(N);\n\n var r, g, b;\n // Using different conversions for D50 and D65 white points,\n // per http://www.color.org/srgb.pdf\n if (cs.ZW < 1) {\n // Assuming D50 (X=0.9642, Y=1.00, Z=0.8249)\n r = X * 3.1339 + Y * -1.6170 + Z * -0.4906;\n g = X * -0.9785 + Y * 1.9160 + Z * 0.0333;\n b = X * 0.0720 + Y * -0.2290 + Z * 1.4057;\n } else {\n // Assuming D65 (X=0.9505, Y=1.00, Z=1.0888)\n r = X * 3.2406 + Y * -1.5372 + Z * -0.4986;\n g = X * -0.9689 + Y * 1.8758 + Z * 0.0415;\n b = X * 0.0557 + Y * -0.2040 + Z * 1.0570;\n }\n // clamp color values to [0,1] range then convert to [0,255] range.\n dest[destOffset] = r <= 0 ? 0 : r >= 1 ? 255 : Math.sqrt(r) * 255 | 0;\n dest[destOffset + 1] = g <= 0 ? 0 : g >= 1 ? 255 : Math.sqrt(g) * 255 | 0;\n dest[destOffset + 2] = b <= 0 ? 0 : b >= 1 ? 255 : Math.sqrt(b) * 255 | 0;\n }\n\n LabCS.prototype = {\n getRgb: ColorSpace.prototype.getRgb,\n getRgbItem: function LabCS_getRgbItem(src, srcOffset, dest, destOffset) {\n convertToRgb(this, src, srcOffset, false, dest, destOffset);\n },\n getRgbBuffer: function LabCS_getRgbBuffer(src, srcOffset, count,\n dest, destOffset, bits,\n alpha01) {\n var maxVal = (1 << bits) - 1;\n for (var i = 0; i < count; i++) {\n convertToRgb(this, src, srcOffset, maxVal, dest, destOffset);\n srcOffset += 3;\n destOffset += 3 + alpha01;\n }\n },\n getOutputLength: function LabCS_getOutputLength(inputLength, alpha01) {\n return (inputLength * (3 + alpha01) / 3) | 0;\n },\n isPassthrough: ColorSpace.prototype.isPassthrough,\n fillRgb: ColorSpace.prototype.fillRgb,\n isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) {\n // XXX: Decoding is handled with the lab conversion because of the strange\n // ranges that are used.\n return true;\n },\n usesZeroToOneRange: false,\n };\n return LabCS;\n})();\n\nexport {\n ColorSpace,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/colorspace.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nvar ExpertEncoding = [\n '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',\n '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',\n 'space', 'exclamsmall', 'Hungarumlautsmall', '', 'dollaroldstyle',\n 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior',\n 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma',\n 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle',\n 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle',\n 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon',\n 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior',\n 'questionsmall', '', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior',\n 'esuperior', '', '', '', 'isuperior', '', '', 'lsuperior', 'msuperior',\n 'nsuperior', 'osuperior', '', '', 'rsuperior', 'ssuperior', 'tsuperior',\n '', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '',\n 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',\n 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall',\n 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall',\n 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall',\n 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary',\n 'onefitted', 'rupiah', 'Tildesmall', '', '', '', '', '', '', '', '', '',\n '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',\n '', '', '', '', '', '', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall',\n '', '', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall',\n 'Caronsmall', '', 'Dotaccentsmall', '', '', 'Macronsmall', '', '',\n 'figuredash', 'hypheninferior', '', '', 'Ogoneksmall', 'Ringsmall',\n 'Cedillasmall', '', '', '', 'onequarter', 'onehalf', 'threequarters',\n 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',\n 'seveneighths', 'onethird', 'twothirds', '', '', 'zerosuperior',\n 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior',\n 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior',\n 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior',\n 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior',\n 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior',\n 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall',\n 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall',\n 'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall',\n 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',\n 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall',\n 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall',\n 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',\n 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall',\n 'Ydieresissmall'];\n\nvar MacExpertEncoding = [\n '', '', '', '', '', '', '', '', '', '', '', '', '', '',\n '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',\n 'space', 'exclamsmall', 'Hungarumlautsmall', 'centoldstyle',\n 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall',\n 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',\n 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle',\n 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle',\n 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle',\n 'nineoldstyle', 'colon', 'semicolon', '', 'threequartersemdash', '',\n 'questionsmall', '', '', '', '', 'Ethsmall', '', '', 'onequarter',\n 'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths',\n 'seveneighths', 'onethird', 'twothirds', '', '', '', '', '', '', 'ff',\n 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '', 'parenrightinferior',\n 'Circumflexsmall', 'hypheninferior', 'Gravesmall', 'Asmall', 'Bsmall',\n 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall',\n 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall',\n 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall',\n 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah',\n 'Tildesmall', '', '', 'asuperior', 'centsuperior', '', '', '', '',\n 'Aacutesmall', 'Agravesmall', 'Acircumflexsmall', 'Adieresissmall',\n 'Atildesmall', 'Aringsmall', 'Ccedillasmall', 'Eacutesmall', 'Egravesmall',\n 'Ecircumflexsmall', 'Edieresissmall', 'Iacutesmall', 'Igravesmall',\n 'Icircumflexsmall', 'Idieresissmall', 'Ntildesmall', 'Oacutesmall',\n 'Ogravesmall', 'Ocircumflexsmall', 'Odieresissmall', 'Otildesmall',\n 'Uacutesmall', 'Ugravesmall', 'Ucircumflexsmall', 'Udieresissmall', '',\n 'eightsuperior', 'fourinferior', 'threeinferior', 'sixinferior',\n 'eightinferior', 'seveninferior', 'Scaronsmall', '', 'centinferior',\n 'twoinferior', '', 'Dieresissmall', '', 'Caronsmall', 'osuperior',\n 'fiveinferior', '', 'commainferior', 'periodinferior', 'Yacutesmall', '',\n 'dollarinferior', '', 'Thornsmall', '', 'nineinferior', 'zeroinferior',\n 'Zcaronsmall', 'AEsmall', 'Oslashsmall', 'questiondownsmall',\n 'oneinferior', 'Lslashsmall', '', '', '', '', '', '', 'Cedillasmall', '',\n '', '', '', '', 'OEsmall', 'figuredash', 'hyphensuperior', '', '', '', '',\n 'exclamdownsmall', '', 'Ydieresissmall', '', 'onesuperior', 'twosuperior',\n 'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior',\n 'sevensuperior', 'ninesuperior', 'zerosuperior', '', 'esuperior',\n 'rsuperior', 'tsuperior', '', '', 'isuperior', 'ssuperior', 'dsuperior',\n '', '', '', '', '', 'lsuperior', 'Ogoneksmall', 'Brevesmall',\n 'Macronsmall', 'bsuperior', 'nsuperior', 'msuperior', 'commasuperior',\n 'periodsuperior', 'Dotaccentsmall', 'Ringsmall'];\n\nvar MacRomanEncoding = [\n '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',\n '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',\n 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',\n 'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus',\n 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',\n 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',\n 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',\n 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',\n 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',\n 'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g',\n 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',\n 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', '',\n 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde', 'Odieresis',\n 'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis', 'atilde',\n 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis',\n 'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute',\n 'ograve', 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave',\n 'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling',\n 'section', 'bullet', 'paragraph', 'germandbls', 'registered', 'copyright',\n 'trademark', 'acute', 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity',\n 'plusminus', 'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff',\n 'summation', 'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine',\n 'Omega', 'ae', 'oslash', 'questiondown', 'exclamdown', 'logicalnot',\n 'radical', 'florin', 'approxequal', 'Delta', 'guillemotleft',\n 'guillemotright', 'ellipsis', 'space', 'Agrave', 'Atilde', 'Otilde', 'OE',\n 'oe', 'endash', 'emdash', 'quotedblleft', 'quotedblright', 'quoteleft',\n 'quoteright', 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction',\n 'currency', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl',\n 'periodcentered', 'quotesinglbase', 'quotedblbase', 'perthousand',\n 'Acircumflex', 'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute',\n 'Icircumflex', 'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple',\n 'Ograve', 'Uacute', 'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex',\n 'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut',\n 'ogonek', 'caron'];\n\nvar StandardEncoding = [\n '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',\n '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',\n 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',\n 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus',\n 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',\n 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',\n 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',\n 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',\n 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',\n 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f',\n 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',\n 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde',\n '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',\n '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'exclamdown',\n 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',\n 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',\n 'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger', 'daggerdbl',\n 'periodcentered', '', 'paragraph', 'bullet', 'quotesinglbase',\n 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis',\n 'perthousand', '', 'questiondown', '', 'grave', 'acute', 'circumflex',\n 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', '', 'ring', 'cedilla',\n '', 'hungarumlaut', 'ogonek', 'caron', 'emdash', '', '', '', '', '', '',\n '', '', '', '', '', '', '', '', '', '', 'AE', '', 'ordfeminine', '', '',\n '', '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae',\n '', '', '', 'dotlessi', '', '', 'lslash', 'oslash', 'oe', 'germandbls'];\n\nvar WinAnsiEncoding = [\n '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',\n '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',\n 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',\n 'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus',\n 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',\n 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',\n 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',\n 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',\n 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',\n 'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g',\n 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',\n 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde',\n 'bullet', 'Euro', 'bullet', 'quotesinglbase', 'florin', 'quotedblbase',\n 'ellipsis', 'dagger', 'daggerdbl', 'circumflex', 'perthousand', 'Scaron',\n 'guilsinglleft', 'OE', 'bullet', 'Zcaron', 'bullet', 'bullet', 'quoteleft',\n 'quoteright', 'quotedblleft', 'quotedblright', 'bullet', 'endash',\n 'emdash', 'tilde', 'trademark', 'scaron', 'guilsinglright', 'oe', 'bullet',\n 'zcaron', 'Ydieresis', 'space', 'exclamdown', 'cent', 'sterling',\n 'currency', 'yen', 'brokenbar', 'section', 'dieresis', 'copyright',\n 'ordfeminine', 'guillemotleft', 'logicalnot', 'hyphen', 'registered',\n 'macron', 'degree', 'plusminus', 'twosuperior', 'threesuperior', 'acute',\n 'mu', 'paragraph', 'periodcentered', 'cedilla', 'onesuperior',\n 'ordmasculine', 'guillemotright', 'onequarter', 'onehalf', 'threequarters',\n 'questiondown', 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', 'Adieresis',\n 'Aring', 'AE', 'Ccedilla', 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis',\n 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Eth', 'Ntilde', 'Ograve',\n 'Oacute', 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', 'Oslash',\n 'Ugrave', 'Uacute', 'Ucircumflex', 'Udieresis', 'Yacute', 'Thorn',\n 'germandbls', 'agrave', 'aacute', 'acircumflex', 'atilde', 'adieresis',\n 'aring', 'ae', 'ccedilla', 'egrave', 'eacute', 'ecircumflex', 'edieresis',\n 'igrave', 'iacute', 'icircumflex', 'idieresis', 'eth', 'ntilde', 'ograve',\n 'oacute', 'ocircumflex', 'otilde', 'odieresis', 'divide', 'oslash',\n 'ugrave', 'uacute', 'ucircumflex', 'udieresis', 'yacute', 'thorn',\n 'ydieresis'];\n\nvar SymbolSetEncoding = [\n '', '', '', '', '', '', '', '', '', '', '', '', '', '',\n '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',\n 'space', 'exclam', 'universal', 'numbersign', 'existential', 'percent',\n 'ampersand', 'suchthat', 'parenleft', 'parenright', 'asteriskmath', 'plus',\n 'comma', 'minus', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four',\n 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less',\n 'equal', 'greater', 'question', 'congruent', 'Alpha', 'Beta', 'Chi',\n 'Delta', 'Epsilon', 'Phi', 'Gamma', 'Eta', 'Iota', 'theta1', 'Kappa',\n 'Lambda', 'Mu', 'Nu', 'Omicron', 'Pi', 'Theta', 'Rho', 'Sigma', 'Tau',\n 'Upsilon', 'sigma1', 'Omega', 'Xi', 'Psi', 'Zeta', 'bracketleft',\n 'therefore', 'bracketright', 'perpendicular', 'underscore', 'radicalex',\n 'alpha', 'beta', 'chi', 'delta', 'epsilon', 'phi', 'gamma', 'eta', 'iota',\n 'phi1', 'kappa', 'lambda', 'mu', 'nu', 'omicron', 'pi', 'theta', 'rho',\n 'sigma', 'tau', 'upsilon', 'omega1', 'omega', 'xi', 'psi', 'zeta',\n 'braceleft', 'bar', 'braceright', 'similar', '', '', '', '', '', '', '',\n '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',\n '', '', '', '', '', '', '', 'Euro', 'Upsilon1', 'minute', 'lessequal',\n 'fraction', 'infinity', 'florin', 'club', 'diamond', 'heart', 'spade',\n 'arrowboth', 'arrowleft', 'arrowup', 'arrowright', 'arrowdown', 'degree',\n 'plusminus', 'second', 'greaterequal', 'multiply', 'proportional',\n 'partialdiff', 'bullet', 'divide', 'notequal', 'equivalence',\n 'approxequal', 'ellipsis', 'arrowvertex', 'arrowhorizex', 'carriagereturn',\n 'aleph', 'Ifraktur', 'Rfraktur', 'weierstrass', 'circlemultiply',\n 'circleplus', 'emptyset', 'intersection', 'union', 'propersuperset',\n 'reflexsuperset', 'notsubset', 'propersubset', 'reflexsubset', 'element',\n 'notelement', 'angle', 'gradient', 'registerserif', 'copyrightserif',\n 'trademarkserif', 'product', 'radical', 'dotmath', 'logicalnot',\n 'logicaland', 'logicalor', 'arrowdblboth', 'arrowdblleft', 'arrowdblup',\n 'arrowdblright', 'arrowdbldown', 'lozenge', 'angleleft', 'registersans',\n 'copyrightsans', 'trademarksans', 'summation', 'parenlefttp',\n 'parenleftex', 'parenleftbt', 'bracketlefttp', 'bracketleftex',\n 'bracketleftbt', 'bracelefttp', 'braceleftmid', 'braceleftbt', 'braceex',\n '', 'angleright', 'integral', 'integraltp', 'integralex', 'integralbt',\n 'parenrighttp', 'parenrightex', 'parenrightbt', 'bracketrighttp',\n 'bracketrightex', 'bracketrightbt', 'bracerighttp', 'bracerightmid',\n 'bracerightbt'];\n\nvar ZapfDingbatsEncoding = [\n '', '', '', '', '', '', '', '', '', '', '', '', '', '',\n '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',\n 'space', 'a1', 'a2', 'a202', 'a3', 'a4', 'a5', 'a119', 'a118', 'a117',\n 'a11', 'a12', 'a13', 'a14', 'a15', 'a16', 'a105', 'a17', 'a18', 'a19',\n 'a20', 'a21', 'a22', 'a23', 'a24', 'a25', 'a26', 'a27', 'a28', 'a6', 'a7',\n 'a8', 'a9', 'a10', 'a29', 'a30', 'a31', 'a32', 'a33', 'a34', 'a35', 'a36',\n 'a37', 'a38', 'a39', 'a40', 'a41', 'a42', 'a43', 'a44', 'a45', 'a46',\n 'a47', 'a48', 'a49', 'a50', 'a51', 'a52', 'a53', 'a54', 'a55', 'a56',\n 'a57', 'a58', 'a59', 'a60', 'a61', 'a62', 'a63', 'a64', 'a65', 'a66',\n 'a67', 'a68', 'a69', 'a70', 'a71', 'a72', 'a73', 'a74', 'a203', 'a75',\n 'a204', 'a76', 'a77', 'a78', 'a79', 'a81', 'a82', 'a83', 'a84', 'a97',\n 'a98', 'a99', 'a100', '', 'a89', 'a90', 'a93', 'a94', 'a91', 'a92', 'a205',\n 'a85', 'a206', 'a86', 'a87', 'a88', 'a95', 'a96', '', '', '', '', '', '',\n '', '', '', '', '', '', '', '', '', '', '', '', '', 'a101', 'a102', 'a103',\n 'a104', 'a106', 'a107', 'a108', 'a112', 'a111', 'a110', 'a109', 'a120',\n 'a121', 'a122', 'a123', 'a124', 'a125', 'a126', 'a127', 'a128', 'a129',\n 'a130', 'a131', 'a132', 'a133', 'a134', 'a135', 'a136', 'a137', 'a138',\n 'a139', 'a140', 'a141', 'a142', 'a143', 'a144', 'a145', 'a146', 'a147',\n 'a148', 'a149', 'a150', 'a151', 'a152', 'a153', 'a154', 'a155', 'a156',\n 'a157', 'a158', 'a159', 'a160', 'a161', 'a163', 'a164', 'a196', 'a165',\n 'a192', 'a166', 'a167', 'a168', 'a169', 'a170', 'a171', 'a172', 'a173',\n 'a162', 'a174', 'a175', 'a176', 'a177', 'a178', 'a179', 'a193', 'a180',\n 'a199', 'a181', 'a200', 'a182', '', 'a201', 'a183', 'a184', 'a197', 'a185',\n 'a194', 'a198', 'a186', 'a195', 'a187', 'a188', 'a189', 'a190', 'a191'];\n\nfunction getEncoding(encodingName) {\n switch (encodingName) {\n case 'WinAnsiEncoding':\n return WinAnsiEncoding;\n case 'StandardEncoding':\n return StandardEncoding;\n case 'MacRomanEncoding':\n return MacRomanEncoding;\n case 'SymbolSetEncoding':\n return SymbolSetEncoding;\n case 'ZapfDingbatsEncoding':\n return ZapfDingbatsEncoding;\n case 'ExpertEncoding':\n return ExpertEncoding;\n case 'MacExpertEncoding':\n return MacExpertEncoding;\n default:\n return null;\n }\n}\n\nexport {\n WinAnsiEncoding,\n StandardEncoding,\n MacRomanEncoding,\n SymbolSetEncoding,\n ZapfDingbatsEncoding,\n ExpertEncoding,\n getEncoding,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/encodings.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Ascii85Stream, AsciiHexStream, CCITTFaxStream, FlateStream, Jbig2Stream,\n JpegStream, JpxStream, LZWStream, NullStream, PredictorStream, RunLengthStream\n} from './stream';\nimport {\n assert, FormatError, info, isArray, isInt, isNum, isString,\n MissingDataException, StreamType, warn\n} from '../shared/util';\nimport {\n Cmd, Dict, EOF, isCmd, isDict, isEOF, isName, Name, Ref\n} from './primitives';\n\nvar MAX_LENGTH_TO_CACHE = 1000;\n\nvar Parser = (function ParserClosure() {\n function Parser(lexer, allowStreams, xref, recoveryMode) {\n this.lexer = lexer;\n this.allowStreams = allowStreams;\n this.xref = xref;\n this.recoveryMode = recoveryMode || false;\n this.imageCache = Object.create(null);\n this.refill();\n }\n\n Parser.prototype = {\n refill: function Parser_refill() {\n this.buf1 = this.lexer.getObj();\n this.buf2 = this.lexer.getObj();\n },\n shift: function Parser_shift() {\n if (isCmd(this.buf2, 'ID')) {\n this.buf1 = this.buf2;\n this.buf2 = null;\n } else {\n this.buf1 = this.buf2;\n this.buf2 = this.lexer.getObj();\n }\n },\n tryShift: function Parser_tryShift() {\n try {\n this.shift();\n return true;\n } catch (e) {\n if (e instanceof MissingDataException) {\n throw e;\n }\n // Upon failure, the caller should reset this.lexer.pos to a known good\n // state and call this.shift() twice to reset the buffers.\n return false;\n }\n },\n getObj: function Parser_getObj(cipherTransform) {\n var buf1 = this.buf1;\n this.shift();\n\n if (buf1 instanceof Cmd) {\n switch (buf1.cmd) {\n case 'BI': // inline image\n return this.makeInlineImage(cipherTransform);\n case '[': // array\n var array = [];\n while (!isCmd(this.buf1, ']') && !isEOF(this.buf1)) {\n array.push(this.getObj(cipherTransform));\n }\n if (isEOF(this.buf1)) {\n if (!this.recoveryMode) {\n throw new FormatError('End of file inside array');\n }\n return array;\n }\n this.shift();\n return array;\n case '<<': // dictionary or stream\n var dict = new Dict(this.xref);\n while (!isCmd(this.buf1, '>>') && !isEOF(this.buf1)) {\n if (!isName(this.buf1)) {\n info('Malformed dictionary: key must be a name object');\n this.shift();\n continue;\n }\n\n var key = this.buf1.name;\n this.shift();\n if (isEOF(this.buf1)) {\n break;\n }\n dict.set(key, this.getObj(cipherTransform));\n }\n if (isEOF(this.buf1)) {\n if (!this.recoveryMode) {\n throw new FormatError('End of file inside dictionary');\n }\n return dict;\n }\n\n // Stream objects are not allowed inside content streams or\n // object streams.\n if (isCmd(this.buf2, 'stream')) {\n return (this.allowStreams ?\n this.makeStream(dict, cipherTransform) : dict);\n }\n this.shift();\n return dict;\n default: // simple object\n return buf1;\n }\n }\n\n if (isInt(buf1)) { // indirect reference or integer\n var num = buf1;\n if (isInt(this.buf1) && isCmd(this.buf2, 'R')) {\n var ref = new Ref(num, this.buf1);\n this.shift();\n this.shift();\n return ref;\n }\n return num;\n }\n\n if (isString(buf1)) { // string\n var str = buf1;\n if (cipherTransform) {\n str = cipherTransform.decryptString(str);\n }\n return str;\n }\n\n // simple object\n return buf1;\n },\n /**\n * Find the end of the stream by searching for the /EI\\s/.\n * @returns {number} The inline stream length.\n */\n findDefaultInlineStreamEnd:\n function Parser_findDefaultInlineStreamEnd(stream) {\n var E = 0x45, I = 0x49, SPACE = 0x20, LF = 0xA, CR = 0xD;\n var startPos = stream.pos, state = 0, ch, i, n, followingBytes;\n while ((ch = stream.getByte()) !== -1) {\n if (state === 0) {\n state = (ch === E) ? 1 : 0;\n } else if (state === 1) {\n state = (ch === I) ? 2 : 0;\n } else {\n assert(state === 2);\n if (ch === SPACE || ch === LF || ch === CR) {\n // Let's check the next five bytes are ASCII... just be sure.\n n = 5;\n followingBytes = stream.peekBytes(n);\n for (i = 0; i < n; i++) {\n ch = followingBytes[i];\n if (ch !== LF && ch !== CR && (ch < SPACE || ch > 0x7F)) {\n // Not a LF, CR, SPACE or any visible ASCII character, i.e.\n // it's binary stuff. Resetting the state.\n state = 0;\n break;\n }\n }\n if (state === 2) {\n break; // Finished!\n }\n } else {\n state = 0;\n }\n }\n }\n return ((stream.pos - 4) - startPos);\n },\n /**\n * Find the EOI (end-of-image) marker 0xFFD9 of the stream.\n * @returns {number} The inline stream length.\n */\n findDCTDecodeInlineStreamEnd:\n function Parser_findDCTDecodeInlineStreamEnd(stream) {\n var startPos = stream.pos, foundEOI = false, b, markerLength, length;\n while ((b = stream.getByte()) !== -1) {\n if (b !== 0xFF) { // Not a valid marker.\n continue;\n }\n switch (stream.getByte()) {\n case 0x00: // Byte stuffing.\n // 0xFF00 appears to be a very common byte sequence in JPEG images.\n break;\n\n case 0xFF: // Fill byte.\n // Avoid skipping a valid marker, resetting the stream position.\n stream.skip(-1);\n break;\n\n case 0xD9: // EOI\n foundEOI = true;\n break;\n\n case 0xC0: // SOF0\n case 0xC1: // SOF1\n case 0xC2: // SOF2\n case 0xC3: // SOF3\n /* falls through */\n case 0xC5: // SOF5\n case 0xC6: // SOF6\n case 0xC7: // SOF7\n /* falls through */\n case 0xC9: // SOF9\n case 0xCA: // SOF10\n case 0xCB: // SOF11\n /* falls through */\n case 0xCD: // SOF13\n case 0xCE: // SOF14\n case 0xCF: // SOF15\n /* falls through */\n case 0xC4: // DHT\n case 0xCC: // DAC\n /* falls through */\n case 0xDA: // SOS\n case 0xDB: // DQT\n case 0xDC: // DNL\n case 0xDD: // DRI\n case 0xDE: // DHP\n case 0xDF: // EXP\n /* falls through */\n case 0xE0: // APP0\n case 0xE1: // APP1\n case 0xE2: // APP2\n case 0xE3: // APP3\n case 0xE4: // APP4\n case 0xE5: // APP5\n case 0xE6: // APP6\n case 0xE7: // APP7\n case 0xE8: // APP8\n case 0xE9: // APP9\n case 0xEA: // APP10\n case 0xEB: // APP11\n case 0xEC: // APP12\n case 0xED: // APP13\n case 0xEE: // APP14\n case 0xEF: // APP15\n /* falls through */\n case 0xFE: // COM\n // The marker should be followed by the length of the segment.\n markerLength = stream.getUint16();\n if (markerLength > 2) {\n // |markerLength| contains the byte length of the marker segment,\n // including its own length (2 bytes) and excluding the marker.\n stream.skip(markerLength - 2); // Jump to the next marker.\n } else {\n // The marker length is invalid, resetting the stream position.\n stream.skip(-2);\n }\n break;\n }\n if (foundEOI) {\n break;\n }\n }\n length = stream.pos - startPos;\n if (b === -1) {\n warn('Inline DCTDecode image stream: ' +\n 'EOI marker not found, searching for /EI/ instead.');\n stream.skip(-length); // Reset the stream position.\n return this.findDefaultInlineStreamEnd(stream);\n }\n this.inlineStreamSkipEI(stream);\n return length;\n },\n /**\n * Find the EOD (end-of-data) marker '~>' (i.e. TILDE + GT) of the stream.\n * @returns {number} The inline stream length.\n */\n findASCII85DecodeInlineStreamEnd:\n function Parser_findASCII85DecodeInlineStreamEnd(stream) {\n var TILDE = 0x7E, GT = 0x3E;\n var startPos = stream.pos, ch, length;\n while ((ch = stream.getByte()) !== -1) {\n if (ch === TILDE && stream.peekByte() === GT) {\n stream.skip();\n break;\n }\n }\n length = stream.pos - startPos;\n if (ch === -1) {\n warn('Inline ASCII85Decode image stream: ' +\n 'EOD marker not found, searching for /EI/ instead.');\n stream.skip(-length); // Reset the stream position.\n return this.findDefaultInlineStreamEnd(stream);\n }\n this.inlineStreamSkipEI(stream);\n return length;\n },\n /**\n * Find the EOD (end-of-data) marker '>' (i.e. GT) of the stream.\n * @returns {number} The inline stream length.\n */\n findASCIIHexDecodeInlineStreamEnd:\n function Parser_findASCIIHexDecodeInlineStreamEnd(stream) {\n var GT = 0x3E;\n var startPos = stream.pos, ch, length;\n while ((ch = stream.getByte()) !== -1) {\n if (ch === GT) {\n break;\n }\n }\n length = stream.pos - startPos;\n if (ch === -1) {\n warn('Inline ASCIIHexDecode image stream: ' +\n 'EOD marker not found, searching for /EI/ instead.');\n stream.skip(-length); // Reset the stream position.\n return this.findDefaultInlineStreamEnd(stream);\n }\n this.inlineStreamSkipEI(stream);\n return length;\n },\n /**\n * Skip over the /EI/ for streams where we search for an EOD marker.\n */\n inlineStreamSkipEI: function Parser_inlineStreamSkipEI(stream) {\n var E = 0x45, I = 0x49;\n var state = 0, ch;\n while ((ch = stream.getByte()) !== -1) {\n if (state === 0) {\n state = (ch === E) ? 1 : 0;\n } else if (state === 1) {\n state = (ch === I) ? 2 : 0;\n } else if (state === 2) {\n break;\n }\n }\n },\n makeInlineImage: function Parser_makeInlineImage(cipherTransform) {\n var lexer = this.lexer;\n var stream = lexer.stream;\n\n // Parse dictionary.\n var dict = new Dict(this.xref);\n while (!isCmd(this.buf1, 'ID') && !isEOF(this.buf1)) {\n if (!isName(this.buf1)) {\n throw new FormatError('Dictionary key must be a name object');\n }\n var key = this.buf1.name;\n this.shift();\n if (isEOF(this.buf1)) {\n break;\n }\n dict.set(key, this.getObj(cipherTransform));\n }\n\n // Extract the name of the first (i.e. the current) image filter.\n var filter = dict.get('Filter', 'F'), filterName;\n if (isName(filter)) {\n filterName = filter.name;\n } else if (isArray(filter)) {\n var filterZero = this.xref.fetchIfRef(filter[0]);\n if (isName(filterZero)) {\n filterName = filterZero.name;\n }\n }\n\n // Parse image stream.\n var startPos = stream.pos, length, i, ii;\n if (filterName === 'DCTDecode' || filterName === 'DCT') {\n length = this.findDCTDecodeInlineStreamEnd(stream);\n } else if (filterName === 'ASCII85Decode' || filterName === 'A85') {\n length = this.findASCII85DecodeInlineStreamEnd(stream);\n } else if (filterName === 'ASCIIHexDecode' || filterName === 'AHx') {\n length = this.findASCIIHexDecodeInlineStreamEnd(stream);\n } else {\n length = this.findDefaultInlineStreamEnd(stream);\n }\n var imageStream = stream.makeSubStream(startPos, length, dict);\n\n // Cache all images below the MAX_LENGTH_TO_CACHE threshold by their\n // adler32 checksum.\n var adler32;\n if (length < MAX_LENGTH_TO_CACHE) {\n var imageBytes = imageStream.getBytes();\n imageStream.reset();\n\n var a = 1;\n var b = 0;\n for (i = 0, ii = imageBytes.length; i < ii; ++i) {\n // No modulo required in the loop if imageBytes.length < 5552.\n a += imageBytes[i] & 0xff;\n b += a;\n }\n adler32 = ((b % 65521) << 16) | (a % 65521);\n\n if (this.imageCache.adler32 === adler32) {\n this.buf2 = Cmd.get('EI');\n this.shift();\n\n this.imageCache[adler32].reset();\n return this.imageCache[adler32];\n }\n }\n\n if (cipherTransform) {\n imageStream = cipherTransform.createStream(imageStream, length);\n }\n\n imageStream = this.filter(imageStream, dict, length);\n imageStream.dict = dict;\n if (adler32 !== undefined) {\n imageStream.cacheKey = 'inline_' + length + '_' + adler32;\n this.imageCache[adler32] = imageStream;\n }\n\n this.buf2 = Cmd.get('EI');\n this.shift();\n\n return imageStream;\n },\n makeStream: function Parser_makeStream(dict, cipherTransform) {\n var lexer = this.lexer;\n var stream = lexer.stream;\n\n // get stream start position\n lexer.skipToNextLine();\n var pos = stream.pos - 1;\n\n // get length\n var length = dict.get('Length');\n if (!isInt(length)) {\n info('Bad ' + length + ' attribute in stream');\n length = 0;\n }\n\n // skip over the stream data\n stream.pos = pos + length;\n lexer.nextChar();\n\n // Shift '>>' and check whether the new object marks the end of the stream\n if (this.tryShift() && isCmd(this.buf2, 'endstream')) {\n this.shift(); // 'stream'\n } else {\n // bad stream length, scanning for endstream\n stream.pos = pos;\n var SCAN_BLOCK_SIZE = 2048;\n var ENDSTREAM_SIGNATURE_LENGTH = 9;\n var ENDSTREAM_SIGNATURE = [0x65, 0x6E, 0x64, 0x73, 0x74, 0x72, 0x65,\n 0x61, 0x6D];\n var skipped = 0, found = false, i, j;\n while (stream.pos < stream.end) {\n var scanBytes = stream.peekBytes(SCAN_BLOCK_SIZE);\n var scanLength = scanBytes.length - ENDSTREAM_SIGNATURE_LENGTH;\n if (scanLength <= 0) {\n break;\n }\n found = false;\n i = 0;\n while (i < scanLength) {\n j = 0;\n while (j < ENDSTREAM_SIGNATURE_LENGTH &&\n scanBytes[i + j] === ENDSTREAM_SIGNATURE[j]) {\n j++;\n }\n if (j >= ENDSTREAM_SIGNATURE_LENGTH) {\n found = true;\n break;\n }\n i++;\n }\n if (found) {\n skipped += i;\n stream.pos += i;\n break;\n }\n skipped += scanLength;\n stream.pos += scanLength;\n }\n if (!found) {\n throw new FormatError('Missing endstream');\n }\n length = skipped;\n\n lexer.nextChar();\n this.shift();\n this.shift();\n }\n this.shift(); // 'endstream'\n\n stream = stream.makeSubStream(pos, length, dict);\n if (cipherTransform) {\n stream = cipherTransform.createStream(stream, length);\n }\n stream = this.filter(stream, dict, length);\n stream.dict = dict;\n return stream;\n },\n filter: function Parser_filter(stream, dict, length) {\n var filter = dict.get('Filter', 'F');\n var params = dict.get('DecodeParms', 'DP');\n if (isName(filter)) {\n if (isArray(params)) {\n params = this.xref.fetchIfRef(params[0]);\n }\n return this.makeFilter(stream, filter.name, length, params);\n }\n\n var maybeLength = length;\n if (isArray(filter)) {\n var filterArray = filter;\n var paramsArray = params;\n for (var i = 0, ii = filterArray.length; i < ii; ++i) {\n filter = this.xref.fetchIfRef(filterArray[i]);\n if (!isName(filter)) {\n throw new FormatError('Bad filter name: ' + filter);\n }\n\n params = null;\n if (isArray(paramsArray) && (i in paramsArray)) {\n params = this.xref.fetchIfRef(paramsArray[i]);\n }\n stream = this.makeFilter(stream, filter.name, maybeLength, params);\n // after the first stream the length variable is invalid\n maybeLength = null;\n }\n }\n return stream;\n },\n makeFilter: function Parser_makeFilter(stream, name, maybeLength, params) {\n // Since the 'Length' entry in the stream dictionary can be completely\n // wrong, e.g. zero for non-empty streams, only skip parsing the stream\n // when we can be absolutely certain that it actually is empty.\n if (maybeLength === 0) {\n warn('Empty \"' + name + '\" stream.');\n return new NullStream(stream);\n }\n try {\n var xrefStreamStats = this.xref.stats.streamTypes;\n if (name === 'FlateDecode' || name === 'Fl') {\n xrefStreamStats[StreamType.FLATE] = true;\n if (params) {\n return new PredictorStream(new FlateStream(stream, maybeLength),\n maybeLength, params);\n }\n return new FlateStream(stream, maybeLength);\n }\n if (name === 'LZWDecode' || name === 'LZW') {\n xrefStreamStats[StreamType.LZW] = true;\n var earlyChange = 1;\n if (params) {\n if (params.has('EarlyChange')) {\n earlyChange = params.get('EarlyChange');\n }\n return new PredictorStream(\n new LZWStream(stream, maybeLength, earlyChange),\n maybeLength, params);\n }\n return new LZWStream(stream, maybeLength, earlyChange);\n }\n if (name === 'DCTDecode' || name === 'DCT') {\n xrefStreamStats[StreamType.DCT] = true;\n return new JpegStream(stream, maybeLength, stream.dict, params);\n }\n if (name === 'JPXDecode' || name === 'JPX') {\n xrefStreamStats[StreamType.JPX] = true;\n return new JpxStream(stream, maybeLength, stream.dict, params);\n }\n if (name === 'ASCII85Decode' || name === 'A85') {\n xrefStreamStats[StreamType.A85] = true;\n return new Ascii85Stream(stream, maybeLength);\n }\n if (name === 'ASCIIHexDecode' || name === 'AHx') {\n xrefStreamStats[StreamType.AHX] = true;\n return new AsciiHexStream(stream, maybeLength);\n }\n if (name === 'CCITTFaxDecode' || name === 'CCF') {\n xrefStreamStats[StreamType.CCF] = true;\n return new CCITTFaxStream(stream, maybeLength, params);\n }\n if (name === 'RunLengthDecode' || name === 'RL') {\n xrefStreamStats[StreamType.RL] = true;\n return new RunLengthStream(stream, maybeLength);\n }\n if (name === 'JBIG2Decode') {\n xrefStreamStats[StreamType.JBIG] = true;\n return new Jbig2Stream(stream, maybeLength, stream.dict, params);\n }\n warn('filter \"' + name + '\" not supported yet');\n return stream;\n } catch (ex) {\n if (ex instanceof MissingDataException) {\n throw ex;\n }\n warn('Invalid stream: \\\"' + ex + '\\\"');\n return new NullStream(stream);\n }\n },\n };\n\n return Parser;\n})();\n\nvar Lexer = (function LexerClosure() {\n function Lexer(stream, knownCommands) {\n this.stream = stream;\n this.nextChar();\n\n // While lexing, we build up many strings one char at a time. Using += for\n // this can result in lots of garbage strings. It's better to build an\n // array of single-char strings and then join() them together at the end.\n // And reusing a single array (i.e. |this.strBuf|) over and over for this\n // purpose uses less memory than using a new array for each string.\n this.strBuf = [];\n\n // The PDFs might have \"glued\" commands with other commands, operands or\n // literals, e.g. \"q1\". The knownCommands is a dictionary of the valid\n // commands and their prefixes. The prefixes are built the following way:\n // if there a command that is a prefix of the other valid command or\n // literal (e.g. 'f' and 'false') the following prefixes must be included,\n // 'fa', 'fal', 'fals'. The prefixes are not needed, if the command has no\n // other commands or literals as a prefix. The knowCommands is optional.\n this.knownCommands = knownCommands;\n }\n\n // A '1' in this array means the character is white space. A '1' or\n // '2' means the character ends a name or command.\n var specialChars = [\n 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x\n 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx\n ];\n\n function toHexDigit(ch) {\n if (ch >= 0x30 && ch <= 0x39) { // '0'-'9'\n return ch & 0x0F;\n }\n if ((ch >= 0x41 && ch <= 0x46) || (ch >= 0x61 && ch <= 0x66)) {\n // 'A'-'F', 'a'-'f'\n return (ch & 0x0F) + 9;\n }\n return -1;\n }\n\n Lexer.prototype = {\n nextChar: function Lexer_nextChar() {\n return (this.currentChar = this.stream.getByte());\n },\n peekChar: function Lexer_peekChar() {\n return this.stream.peekByte();\n },\n getNumber: function Lexer_getNumber() {\n var ch = this.currentChar;\n var eNotation = false;\n var divideBy = 0; // different from 0 if it's a floating point value\n var sign = 1;\n\n if (ch === 0x2D) { // '-'\n sign = -1;\n ch = this.nextChar();\n\n if (ch === 0x2D) { // '-'\n // Ignore double negative (this is consistent with Adobe Reader).\n ch = this.nextChar();\n }\n } else if (ch === 0x2B) { // '+'\n ch = this.nextChar();\n }\n if (ch === 0x2E) { // '.'\n divideBy = 10;\n ch = this.nextChar();\n }\n if (ch === 0x0A || ch === 0x0D) { // LF, CR\n // Ignore line-breaks (this is consistent with Adobe Reader).\n do {\n ch = this.nextChar();\n } while (ch === 0x0A || ch === 0x0D);\n }\n if (ch < 0x30 || ch > 0x39) { // '0' - '9'\n throw new FormatError(\n `Invalid number: ${String.fromCharCode(ch)} (charCode ${ch})`);\n }\n\n var baseValue = ch - 0x30; // '0'\n var powerValue = 0;\n var powerValueSign = 1;\n\n while ((ch = this.nextChar()) >= 0) {\n if (0x30 <= ch && ch <= 0x39) { // '0' - '9'\n var currentDigit = ch - 0x30; // '0'\n if (eNotation) { // We are after an 'e' or 'E'\n powerValue = powerValue * 10 + currentDigit;\n } else {\n if (divideBy !== 0) { // We are after a point\n divideBy *= 10;\n }\n baseValue = baseValue * 10 + currentDigit;\n }\n } else if (ch === 0x2E) { // '.'\n if (divideBy === 0) {\n divideBy = 1;\n } else {\n // A number can have only one '.'\n break;\n }\n } else if (ch === 0x2D) { // '-'\n // ignore minus signs in the middle of numbers to match\n // Adobe's behavior\n warn('Badly formatted number');\n } else if (ch === 0x45 || ch === 0x65) { // 'E', 'e'\n // 'E' can be either a scientific notation or the beginning of a new\n // operator\n ch = this.peekChar();\n if (ch === 0x2B || ch === 0x2D) { // '+', '-'\n powerValueSign = (ch === 0x2D) ? -1 : 1;\n this.nextChar(); // Consume the sign character\n } else if (ch < 0x30 || ch > 0x39) { // '0' - '9'\n // The 'E' must be the beginning of a new operator\n break;\n }\n eNotation = true;\n } else {\n // the last character doesn't belong to us\n break;\n }\n }\n\n if (divideBy !== 0) {\n baseValue /= divideBy;\n }\n if (eNotation) {\n baseValue *= Math.pow(10, powerValueSign * powerValue);\n }\n return sign * baseValue;\n },\n getString: function Lexer_getString() {\n var numParen = 1;\n var done = false;\n var strBuf = this.strBuf;\n strBuf.length = 0;\n\n var ch = this.nextChar();\n while (true) {\n var charBuffered = false;\n switch (ch | 0) {\n case -1:\n warn('Unterminated string');\n done = true;\n break;\n case 0x28: // '('\n ++numParen;\n strBuf.push('(');\n break;\n case 0x29: // ')'\n if (--numParen === 0) {\n this.nextChar(); // consume strings ')'\n done = true;\n } else {\n strBuf.push(')');\n }\n break;\n case 0x5C: // '\\\\'\n ch = this.nextChar();\n switch (ch) {\n case -1:\n warn('Unterminated string');\n done = true;\n break;\n case 0x6E: // 'n'\n strBuf.push('\\n');\n break;\n case 0x72: // 'r'\n strBuf.push('\\r');\n break;\n case 0x74: // 't'\n strBuf.push('\\t');\n break;\n case 0x62: // 'b'\n strBuf.push('\\b');\n break;\n case 0x66: // 'f'\n strBuf.push('\\f');\n break;\n case 0x5C: // '\\'\n case 0x28: // '('\n case 0x29: // ')'\n strBuf.push(String.fromCharCode(ch));\n break;\n case 0x30: case 0x31: case 0x32: case 0x33: // '0'-'3'\n case 0x34: case 0x35: case 0x36: case 0x37: // '4'-'7'\n var x = ch & 0x0F;\n ch = this.nextChar();\n charBuffered = true;\n if (ch >= 0x30 && ch <= 0x37) { // '0'-'7'\n x = (x << 3) + (ch & 0x0F);\n ch = this.nextChar();\n if (ch >= 0x30 && ch <= 0x37) { // '0'-'7'\n charBuffered = false;\n x = (x << 3) + (ch & 0x0F);\n }\n }\n strBuf.push(String.fromCharCode(x));\n break;\n case 0x0D: // CR\n if (this.peekChar() === 0x0A) { // LF\n this.nextChar();\n }\n break;\n case 0x0A: // LF\n break;\n default:\n strBuf.push(String.fromCharCode(ch));\n break;\n }\n break;\n default:\n strBuf.push(String.fromCharCode(ch));\n break;\n }\n if (done) {\n break;\n }\n if (!charBuffered) {\n ch = this.nextChar();\n }\n }\n return strBuf.join('');\n },\n getName: function Lexer_getName() {\n var ch, previousCh;\n var strBuf = this.strBuf;\n strBuf.length = 0;\n while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {\n if (ch === 0x23) { // '#'\n ch = this.nextChar();\n if (specialChars[ch]) {\n warn('Lexer_getName: ' +\n 'NUMBER SIGN (#) should be followed by a hexadecimal number.');\n strBuf.push('#');\n break;\n }\n var x = toHexDigit(ch);\n if (x !== -1) {\n previousCh = ch;\n ch = this.nextChar();\n var x2 = toHexDigit(ch);\n if (x2 === -1) {\n warn('Lexer_getName: Illegal digit (' +\n String.fromCharCode(ch) + ') in hexadecimal number.');\n strBuf.push('#', String.fromCharCode(previousCh));\n if (specialChars[ch]) {\n break;\n }\n strBuf.push(String.fromCharCode(ch));\n continue;\n }\n strBuf.push(String.fromCharCode((x << 4) | x2));\n } else {\n strBuf.push('#', String.fromCharCode(ch));\n }\n } else {\n strBuf.push(String.fromCharCode(ch));\n }\n }\n if (strBuf.length > 127) {\n warn('name token is longer than allowed by the spec: ' + strBuf.length);\n }\n return Name.get(strBuf.join(''));\n },\n getHexString: function Lexer_getHexString() {\n var strBuf = this.strBuf;\n strBuf.length = 0;\n var ch = this.currentChar;\n var isFirstHex = true;\n var firstDigit;\n var secondDigit;\n while (true) {\n if (ch < 0) {\n warn('Unterminated hex string');\n break;\n } else if (ch === 0x3E) { // '>'\n this.nextChar();\n break;\n } else if (specialChars[ch] === 1) {\n ch = this.nextChar();\n continue;\n } else {\n if (isFirstHex) {\n firstDigit = toHexDigit(ch);\n if (firstDigit === -1) {\n warn('Ignoring invalid character \"' + ch + '\" in hex string');\n ch = this.nextChar();\n continue;\n }\n } else {\n secondDigit = toHexDigit(ch);\n if (secondDigit === -1) {\n warn('Ignoring invalid character \"' + ch + '\" in hex string');\n ch = this.nextChar();\n continue;\n }\n strBuf.push(String.fromCharCode((firstDigit << 4) | secondDigit));\n }\n isFirstHex = !isFirstHex;\n ch = this.nextChar();\n }\n }\n return strBuf.join('');\n },\n getObj: function Lexer_getObj() {\n // skip whitespace and comments\n var comment = false;\n var ch = this.currentChar;\n while (true) {\n if (ch < 0) {\n return EOF;\n }\n if (comment) {\n if (ch === 0x0A || ch === 0x0D) { // LF, CR\n comment = false;\n }\n } else if (ch === 0x25) { // '%'\n comment = true;\n } else if (specialChars[ch] !== 1) {\n break;\n }\n ch = this.nextChar();\n }\n\n // start reading token\n switch (ch | 0) {\n case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4'\n case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9'\n case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.'\n return this.getNumber();\n case 0x28: // '('\n return this.getString();\n case 0x2F: // '/'\n return this.getName();\n // array punctuation\n case 0x5B: // '['\n this.nextChar();\n return Cmd.get('[');\n case 0x5D: // ']'\n this.nextChar();\n return Cmd.get(']');\n // hex string or dict punctuation\n case 0x3C: // '<'\n ch = this.nextChar();\n if (ch === 0x3C) {\n // dict punctuation\n this.nextChar();\n return Cmd.get('<<');\n }\n return this.getHexString();\n // dict punctuation\n case 0x3E: // '>'\n ch = this.nextChar();\n if (ch === 0x3E) {\n this.nextChar();\n return Cmd.get('>>');\n }\n return Cmd.get('>');\n case 0x7B: // '{'\n this.nextChar();\n return Cmd.get('{');\n case 0x7D: // '}'\n this.nextChar();\n return Cmd.get('}');\n case 0x29: // ')'\n // Consume the current character in order to avoid permanently hanging\n // the worker thread if `Lexer.getObject` is called from within a loop\n // containing try-catch statements, since we would otherwise attempt\n // to parse the *same* character over and over (fixes issue8061.pdf).\n this.nextChar();\n throw new FormatError(`Illegal character: ${ch}`);\n }\n\n // command\n var str = String.fromCharCode(ch);\n var knownCommands = this.knownCommands;\n var knownCommandFound = knownCommands && knownCommands[str] !== undefined;\n while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {\n // stop if known command is found and next character does not make\n // the str a command\n var possibleCommand = str + String.fromCharCode(ch);\n if (knownCommandFound && knownCommands[possibleCommand] === undefined) {\n break;\n }\n if (str.length === 128) {\n throw new FormatError(`Command token too long: ${str.length}`);\n }\n str = possibleCommand;\n knownCommandFound = knownCommands && knownCommands[str] !== undefined;\n }\n if (str === 'true') {\n return true;\n }\n if (str === 'false') {\n return false;\n }\n if (str === 'null') {\n return null;\n }\n return Cmd.get(str);\n },\n skipToNextLine: function Lexer_skipToNextLine() {\n var ch = this.currentChar;\n while (ch >= 0) {\n if (ch === 0x0D) { // CR\n ch = this.nextChar();\n if (ch === 0x0A) { // LF\n this.nextChar();\n }\n break;\n } else if (ch === 0x0A) { // LF\n this.nextChar();\n break;\n }\n ch = this.nextChar();\n }\n },\n };\n\n return Lexer;\n})();\n\nvar Linearization = {\n create: function LinearizationCreate(stream) {\n function getInt(name, allowZeroValue) {\n var obj = linDict.get(name);\n if (isInt(obj) && (allowZeroValue ? obj >= 0 : obj > 0)) {\n return obj;\n }\n throw new Error('The \"' + name + '\" parameter in the linearization ' +\n 'dictionary is invalid.');\n }\n function getHints() {\n var hints = linDict.get('H'), hintsLength, item;\n if (isArray(hints) &&\n ((hintsLength = hints.length) === 2 || hintsLength === 4)) {\n for (var index = 0; index < hintsLength; index++) {\n if (!(isInt(item = hints[index]) && item > 0)) {\n throw new Error('Hint (' + index +\n ') in the linearization dictionary is invalid.');\n }\n }\n return hints;\n }\n throw new Error('Hint array in the linearization dictionary is invalid.');\n }\n var parser = new Parser(new Lexer(stream), false, null);\n var obj1 = parser.getObj();\n var obj2 = parser.getObj();\n var obj3 = parser.getObj();\n var linDict = parser.getObj();\n var obj, length;\n if (!(isInt(obj1) && isInt(obj2) && isCmd(obj3, 'obj') && isDict(linDict) &&\n isNum(obj = linDict.get('Linearized')) && obj > 0)) {\n return null; // No valid linearization dictionary found.\n } else if ((length = getInt('L')) !== stream.length) {\n throw new Error('The \"L\" parameter in the linearization dictionary ' +\n 'does not equal the stream length.');\n }\n return {\n length,\n hints: getHints(),\n objectNumberFirst: getInt('O'),\n endFirst: getInt('E'),\n numPages: getInt('N'),\n mainXRefEntriesOffset: getInt('T'),\n pageFirst: (linDict.has('P') ? getInt('P', true) : 0),\n };\n },\n};\n\nexport {\n Lexer,\n Linearization,\n Parser,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/parser.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* no-babel-preset */\n\nvar getLookupTableFactory = require('../shared/util').getLookupTableFactory;\n\nvar getGlyphsUnicode = getLookupTableFactory(function (t) {\n t['A'] = 0x0041;\n t['AE'] = 0x00C6;\n t['AEacute'] = 0x01FC;\n t['AEmacron'] = 0x01E2;\n t['AEsmall'] = 0xF7E6;\n t['Aacute'] = 0x00C1;\n t['Aacutesmall'] = 0xF7E1;\n t['Abreve'] = 0x0102;\n t['Abreveacute'] = 0x1EAE;\n t['Abrevecyrillic'] = 0x04D0;\n t['Abrevedotbelow'] = 0x1EB6;\n t['Abrevegrave'] = 0x1EB0;\n t['Abrevehookabove'] = 0x1EB2;\n t['Abrevetilde'] = 0x1EB4;\n t['Acaron'] = 0x01CD;\n t['Acircle'] = 0x24B6;\n t['Acircumflex'] = 0x00C2;\n t['Acircumflexacute'] = 0x1EA4;\n t['Acircumflexdotbelow'] = 0x1EAC;\n t['Acircumflexgrave'] = 0x1EA6;\n t['Acircumflexhookabove'] = 0x1EA8;\n t['Acircumflexsmall'] = 0xF7E2;\n t['Acircumflextilde'] = 0x1EAA;\n t['Acute'] = 0xF6C9;\n t['Acutesmall'] = 0xF7B4;\n t['Acyrillic'] = 0x0410;\n t['Adblgrave'] = 0x0200;\n t['Adieresis'] = 0x00C4;\n t['Adieresiscyrillic'] = 0x04D2;\n t['Adieresismacron'] = 0x01DE;\n t['Adieresissmall'] = 0xF7E4;\n t['Adotbelow'] = 0x1EA0;\n t['Adotmacron'] = 0x01E0;\n t['Agrave'] = 0x00C0;\n t['Agravesmall'] = 0xF7E0;\n t['Ahookabove'] = 0x1EA2;\n t['Aiecyrillic'] = 0x04D4;\n t['Ainvertedbreve'] = 0x0202;\n t['Alpha'] = 0x0391;\n t['Alphatonos'] = 0x0386;\n t['Amacron'] = 0x0100;\n t['Amonospace'] = 0xFF21;\n t['Aogonek'] = 0x0104;\n t['Aring'] = 0x00C5;\n t['Aringacute'] = 0x01FA;\n t['Aringbelow'] = 0x1E00;\n t['Aringsmall'] = 0xF7E5;\n t['Asmall'] = 0xF761;\n t['Atilde'] = 0x00C3;\n t['Atildesmall'] = 0xF7E3;\n t['Aybarmenian'] = 0x0531;\n t['B'] = 0x0042;\n t['Bcircle'] = 0x24B7;\n t['Bdotaccent'] = 0x1E02;\n t['Bdotbelow'] = 0x1E04;\n t['Becyrillic'] = 0x0411;\n t['Benarmenian'] = 0x0532;\n t['Beta'] = 0x0392;\n t['Bhook'] = 0x0181;\n t['Blinebelow'] = 0x1E06;\n t['Bmonospace'] = 0xFF22;\n t['Brevesmall'] = 0xF6F4;\n t['Bsmall'] = 0xF762;\n t['Btopbar'] = 0x0182;\n t['C'] = 0x0043;\n t['Caarmenian'] = 0x053E;\n t['Cacute'] = 0x0106;\n t['Caron'] = 0xF6CA;\n t['Caronsmall'] = 0xF6F5;\n t['Ccaron'] = 0x010C;\n t['Ccedilla'] = 0x00C7;\n t['Ccedillaacute'] = 0x1E08;\n t['Ccedillasmall'] = 0xF7E7;\n t['Ccircle'] = 0x24B8;\n t['Ccircumflex'] = 0x0108;\n t['Cdot'] = 0x010A;\n t['Cdotaccent'] = 0x010A;\n t['Cedillasmall'] = 0xF7B8;\n t['Chaarmenian'] = 0x0549;\n t['Cheabkhasiancyrillic'] = 0x04BC;\n t['Checyrillic'] = 0x0427;\n t['Chedescenderabkhasiancyrillic'] = 0x04BE;\n t['Chedescendercyrillic'] = 0x04B6;\n t['Chedieresiscyrillic'] = 0x04F4;\n t['Cheharmenian'] = 0x0543;\n t['Chekhakassiancyrillic'] = 0x04CB;\n t['Cheverticalstrokecyrillic'] = 0x04B8;\n t['Chi'] = 0x03A7;\n t['Chook'] = 0x0187;\n t['Circumflexsmall'] = 0xF6F6;\n t['Cmonospace'] = 0xFF23;\n t['Coarmenian'] = 0x0551;\n t['Csmall'] = 0xF763;\n t['D'] = 0x0044;\n t['DZ'] = 0x01F1;\n t['DZcaron'] = 0x01C4;\n t['Daarmenian'] = 0x0534;\n t['Dafrican'] = 0x0189;\n t['Dcaron'] = 0x010E;\n t['Dcedilla'] = 0x1E10;\n t['Dcircle'] = 0x24B9;\n t['Dcircumflexbelow'] = 0x1E12;\n t['Dcroat'] = 0x0110;\n t['Ddotaccent'] = 0x1E0A;\n t['Ddotbelow'] = 0x1E0C;\n t['Decyrillic'] = 0x0414;\n t['Deicoptic'] = 0x03EE;\n t['Delta'] = 0x2206;\n t['Deltagreek'] = 0x0394;\n t['Dhook'] = 0x018A;\n t['Dieresis'] = 0xF6CB;\n t['DieresisAcute'] = 0xF6CC;\n t['DieresisGrave'] = 0xF6CD;\n t['Dieresissmall'] = 0xF7A8;\n t['Digammagreek'] = 0x03DC;\n t['Djecyrillic'] = 0x0402;\n t['Dlinebelow'] = 0x1E0E;\n t['Dmonospace'] = 0xFF24;\n t['Dotaccentsmall'] = 0xF6F7;\n t['Dslash'] = 0x0110;\n t['Dsmall'] = 0xF764;\n t['Dtopbar'] = 0x018B;\n t['Dz'] = 0x01F2;\n t['Dzcaron'] = 0x01C5;\n t['Dzeabkhasiancyrillic'] = 0x04E0;\n t['Dzecyrillic'] = 0x0405;\n t['Dzhecyrillic'] = 0x040F;\n t['E'] = 0x0045;\n t['Eacute'] = 0x00C9;\n t['Eacutesmall'] = 0xF7E9;\n t['Ebreve'] = 0x0114;\n t['Ecaron'] = 0x011A;\n t['Ecedillabreve'] = 0x1E1C;\n t['Echarmenian'] = 0x0535;\n t['Ecircle'] = 0x24BA;\n t['Ecircumflex'] = 0x00CA;\n t['Ecircumflexacute'] = 0x1EBE;\n t['Ecircumflexbelow'] = 0x1E18;\n t['Ecircumflexdotbelow'] = 0x1EC6;\n t['Ecircumflexgrave'] = 0x1EC0;\n t['Ecircumflexhookabove'] = 0x1EC2;\n t['Ecircumflexsmall'] = 0xF7EA;\n t['Ecircumflextilde'] = 0x1EC4;\n t['Ecyrillic'] = 0x0404;\n t['Edblgrave'] = 0x0204;\n t['Edieresis'] = 0x00CB;\n t['Edieresissmall'] = 0xF7EB;\n t['Edot'] = 0x0116;\n t['Edotaccent'] = 0x0116;\n t['Edotbelow'] = 0x1EB8;\n t['Efcyrillic'] = 0x0424;\n t['Egrave'] = 0x00C8;\n t['Egravesmall'] = 0xF7E8;\n t['Eharmenian'] = 0x0537;\n t['Ehookabove'] = 0x1EBA;\n t['Eightroman'] = 0x2167;\n t['Einvertedbreve'] = 0x0206;\n t['Eiotifiedcyrillic'] = 0x0464;\n t['Elcyrillic'] = 0x041B;\n t['Elevenroman'] = 0x216A;\n t['Emacron'] = 0x0112;\n t['Emacronacute'] = 0x1E16;\n t['Emacrongrave'] = 0x1E14;\n t['Emcyrillic'] = 0x041C;\n t['Emonospace'] = 0xFF25;\n t['Encyrillic'] = 0x041D;\n t['Endescendercyrillic'] = 0x04A2;\n t['Eng'] = 0x014A;\n t['Enghecyrillic'] = 0x04A4;\n t['Enhookcyrillic'] = 0x04C7;\n t['Eogonek'] = 0x0118;\n t['Eopen'] = 0x0190;\n t['Epsilon'] = 0x0395;\n t['Epsilontonos'] = 0x0388;\n t['Ercyrillic'] = 0x0420;\n t['Ereversed'] = 0x018E;\n t['Ereversedcyrillic'] = 0x042D;\n t['Escyrillic'] = 0x0421;\n t['Esdescendercyrillic'] = 0x04AA;\n t['Esh'] = 0x01A9;\n t['Esmall'] = 0xF765;\n t['Eta'] = 0x0397;\n t['Etarmenian'] = 0x0538;\n t['Etatonos'] = 0x0389;\n t['Eth'] = 0x00D0;\n t['Ethsmall'] = 0xF7F0;\n t['Etilde'] = 0x1EBC;\n t['Etildebelow'] = 0x1E1A;\n t['Euro'] = 0x20AC;\n t['Ezh'] = 0x01B7;\n t['Ezhcaron'] = 0x01EE;\n t['Ezhreversed'] = 0x01B8;\n t['F'] = 0x0046;\n t['Fcircle'] = 0x24BB;\n t['Fdotaccent'] = 0x1E1E;\n t['Feharmenian'] = 0x0556;\n t['Feicoptic'] = 0x03E4;\n t['Fhook'] = 0x0191;\n t['Fitacyrillic'] = 0x0472;\n t['Fiveroman'] = 0x2164;\n t['Fmonospace'] = 0xFF26;\n t['Fourroman'] = 0x2163;\n t['Fsmall'] = 0xF766;\n t['G'] = 0x0047;\n t['GBsquare'] = 0x3387;\n t['Gacute'] = 0x01F4;\n t['Gamma'] = 0x0393;\n t['Gammaafrican'] = 0x0194;\n t['Gangiacoptic'] = 0x03EA;\n t['Gbreve'] = 0x011E;\n t['Gcaron'] = 0x01E6;\n t['Gcedilla'] = 0x0122;\n t['Gcircle'] = 0x24BC;\n t['Gcircumflex'] = 0x011C;\n t['Gcommaaccent'] = 0x0122;\n t['Gdot'] = 0x0120;\n t['Gdotaccent'] = 0x0120;\n t['Gecyrillic'] = 0x0413;\n t['Ghadarmenian'] = 0x0542;\n t['Ghemiddlehookcyrillic'] = 0x0494;\n t['Ghestrokecyrillic'] = 0x0492;\n t['Gheupturncyrillic'] = 0x0490;\n t['Ghook'] = 0x0193;\n t['Gimarmenian'] = 0x0533;\n t['Gjecyrillic'] = 0x0403;\n t['Gmacron'] = 0x1E20;\n t['Gmonospace'] = 0xFF27;\n t['Grave'] = 0xF6CE;\n t['Gravesmall'] = 0xF760;\n t['Gsmall'] = 0xF767;\n t['Gsmallhook'] = 0x029B;\n t['Gstroke'] = 0x01E4;\n t['H'] = 0x0048;\n t['H18533'] = 0x25CF;\n t['H18543'] = 0x25AA;\n t['H18551'] = 0x25AB;\n t['H22073'] = 0x25A1;\n t['HPsquare'] = 0x33CB;\n t['Haabkhasiancyrillic'] = 0x04A8;\n t['Hadescendercyrillic'] = 0x04B2;\n t['Hardsigncyrillic'] = 0x042A;\n t['Hbar'] = 0x0126;\n t['Hbrevebelow'] = 0x1E2A;\n t['Hcedilla'] = 0x1E28;\n t['Hcircle'] = 0x24BD;\n t['Hcircumflex'] = 0x0124;\n t['Hdieresis'] = 0x1E26;\n t['Hdotaccent'] = 0x1E22;\n t['Hdotbelow'] = 0x1E24;\n t['Hmonospace'] = 0xFF28;\n t['Hoarmenian'] = 0x0540;\n t['Horicoptic'] = 0x03E8;\n t['Hsmall'] = 0xF768;\n t['Hungarumlaut'] = 0xF6CF;\n t['Hungarumlautsmall'] = 0xF6F8;\n t['Hzsquare'] = 0x3390;\n t['I'] = 0x0049;\n t['IAcyrillic'] = 0x042F;\n t['IJ'] = 0x0132;\n t['IUcyrillic'] = 0x042E;\n t['Iacute'] = 0x00CD;\n t['Iacutesmall'] = 0xF7ED;\n t['Ibreve'] = 0x012C;\n t['Icaron'] = 0x01CF;\n t['Icircle'] = 0x24BE;\n t['Icircumflex'] = 0x00CE;\n t['Icircumflexsmall'] = 0xF7EE;\n t['Icyrillic'] = 0x0406;\n t['Idblgrave'] = 0x0208;\n t['Idieresis'] = 0x00CF;\n t['Idieresisacute'] = 0x1E2E;\n t['Idieresiscyrillic'] = 0x04E4;\n t['Idieresissmall'] = 0xF7EF;\n t['Idot'] = 0x0130;\n t['Idotaccent'] = 0x0130;\n t['Idotbelow'] = 0x1ECA;\n t['Iebrevecyrillic'] = 0x04D6;\n t['Iecyrillic'] = 0x0415;\n t['Ifraktur'] = 0x2111;\n t['Igrave'] = 0x00CC;\n t['Igravesmall'] = 0xF7EC;\n t['Ihookabove'] = 0x1EC8;\n t['Iicyrillic'] = 0x0418;\n t['Iinvertedbreve'] = 0x020A;\n t['Iishortcyrillic'] = 0x0419;\n t['Imacron'] = 0x012A;\n t['Imacroncyrillic'] = 0x04E2;\n t['Imonospace'] = 0xFF29;\n t['Iniarmenian'] = 0x053B;\n t['Iocyrillic'] = 0x0401;\n t['Iogonek'] = 0x012E;\n t['Iota'] = 0x0399;\n t['Iotaafrican'] = 0x0196;\n t['Iotadieresis'] = 0x03AA;\n t['Iotatonos'] = 0x038A;\n t['Ismall'] = 0xF769;\n t['Istroke'] = 0x0197;\n t['Itilde'] = 0x0128;\n t['Itildebelow'] = 0x1E2C;\n t['Izhitsacyrillic'] = 0x0474;\n t['Izhitsadblgravecyrillic'] = 0x0476;\n t['J'] = 0x004A;\n t['Jaarmenian'] = 0x0541;\n t['Jcircle'] = 0x24BF;\n t['Jcircumflex'] = 0x0134;\n t['Jecyrillic'] = 0x0408;\n t['Jheharmenian'] = 0x054B;\n t['Jmonospace'] = 0xFF2A;\n t['Jsmall'] = 0xF76A;\n t['K'] = 0x004B;\n t['KBsquare'] = 0x3385;\n t['KKsquare'] = 0x33CD;\n t['Kabashkircyrillic'] = 0x04A0;\n t['Kacute'] = 0x1E30;\n t['Kacyrillic'] = 0x041A;\n t['Kadescendercyrillic'] = 0x049A;\n t['Kahookcyrillic'] = 0x04C3;\n t['Kappa'] = 0x039A;\n t['Kastrokecyrillic'] = 0x049E;\n t['Kaverticalstrokecyrillic'] = 0x049C;\n t['Kcaron'] = 0x01E8;\n t['Kcedilla'] = 0x0136;\n t['Kcircle'] = 0x24C0;\n t['Kcommaaccent'] = 0x0136;\n t['Kdotbelow'] = 0x1E32;\n t['Keharmenian'] = 0x0554;\n t['Kenarmenian'] = 0x053F;\n t['Khacyrillic'] = 0x0425;\n t['Kheicoptic'] = 0x03E6;\n t['Khook'] = 0x0198;\n t['Kjecyrillic'] = 0x040C;\n t['Klinebelow'] = 0x1E34;\n t['Kmonospace'] = 0xFF2B;\n t['Koppacyrillic'] = 0x0480;\n t['Koppagreek'] = 0x03DE;\n t['Ksicyrillic'] = 0x046E;\n t['Ksmall'] = 0xF76B;\n t['L'] = 0x004C;\n t['LJ'] = 0x01C7;\n t['LL'] = 0xF6BF;\n t['Lacute'] = 0x0139;\n t['Lambda'] = 0x039B;\n t['Lcaron'] = 0x013D;\n t['Lcedilla'] = 0x013B;\n t['Lcircle'] = 0x24C1;\n t['Lcircumflexbelow'] = 0x1E3C;\n t['Lcommaaccent'] = 0x013B;\n t['Ldot'] = 0x013F;\n t['Ldotaccent'] = 0x013F;\n t['Ldotbelow'] = 0x1E36;\n t['Ldotbelowmacron'] = 0x1E38;\n t['Liwnarmenian'] = 0x053C;\n t['Lj'] = 0x01C8;\n t['Ljecyrillic'] = 0x0409;\n t['Llinebelow'] = 0x1E3A;\n t['Lmonospace'] = 0xFF2C;\n t['Lslash'] = 0x0141;\n t['Lslashsmall'] = 0xF6F9;\n t['Lsmall'] = 0xF76C;\n t['M'] = 0x004D;\n t['MBsquare'] = 0x3386;\n t['Macron'] = 0xF6D0;\n t['Macronsmall'] = 0xF7AF;\n t['Macute'] = 0x1E3E;\n t['Mcircle'] = 0x24C2;\n t['Mdotaccent'] = 0x1E40;\n t['Mdotbelow'] = 0x1E42;\n t['Menarmenian'] = 0x0544;\n t['Mmonospace'] = 0xFF2D;\n t['Msmall'] = 0xF76D;\n t['Mturned'] = 0x019C;\n t['Mu'] = 0x039C;\n t['N'] = 0x004E;\n t['NJ'] = 0x01CA;\n t['Nacute'] = 0x0143;\n t['Ncaron'] = 0x0147;\n t['Ncedilla'] = 0x0145;\n t['Ncircle'] = 0x24C3;\n t['Ncircumflexbelow'] = 0x1E4A;\n t['Ncommaaccent'] = 0x0145;\n t['Ndotaccent'] = 0x1E44;\n t['Ndotbelow'] = 0x1E46;\n t['Nhookleft'] = 0x019D;\n t['Nineroman'] = 0x2168;\n t['Nj'] = 0x01CB;\n t['Njecyrillic'] = 0x040A;\n t['Nlinebelow'] = 0x1E48;\n t['Nmonospace'] = 0xFF2E;\n t['Nowarmenian'] = 0x0546;\n t['Nsmall'] = 0xF76E;\n t['Ntilde'] = 0x00D1;\n t['Ntildesmall'] = 0xF7F1;\n t['Nu'] = 0x039D;\n t['O'] = 0x004F;\n t['OE'] = 0x0152;\n t['OEsmall'] = 0xF6FA;\n t['Oacute'] = 0x00D3;\n t['Oacutesmall'] = 0xF7F3;\n t['Obarredcyrillic'] = 0x04E8;\n t['Obarreddieresiscyrillic'] = 0x04EA;\n t['Obreve'] = 0x014E;\n t['Ocaron'] = 0x01D1;\n t['Ocenteredtilde'] = 0x019F;\n t['Ocircle'] = 0x24C4;\n t['Ocircumflex'] = 0x00D4;\n t['Ocircumflexacute'] = 0x1ED0;\n t['Ocircumflexdotbelow'] = 0x1ED8;\n t['Ocircumflexgrave'] = 0x1ED2;\n t['Ocircumflexhookabove'] = 0x1ED4;\n t['Ocircumflexsmall'] = 0xF7F4;\n t['Ocircumflextilde'] = 0x1ED6;\n t['Ocyrillic'] = 0x041E;\n t['Odblacute'] = 0x0150;\n t['Odblgrave'] = 0x020C;\n t['Odieresis'] = 0x00D6;\n t['Odieresiscyrillic'] = 0x04E6;\n t['Odieresissmall'] = 0xF7F6;\n t['Odotbelow'] = 0x1ECC;\n t['Ogoneksmall'] = 0xF6FB;\n t['Ograve'] = 0x00D2;\n t['Ogravesmall'] = 0xF7F2;\n t['Oharmenian'] = 0x0555;\n t['Ohm'] = 0x2126;\n t['Ohookabove'] = 0x1ECE;\n t['Ohorn'] = 0x01A0;\n t['Ohornacute'] = 0x1EDA;\n t['Ohorndotbelow'] = 0x1EE2;\n t['Ohorngrave'] = 0x1EDC;\n t['Ohornhookabove'] = 0x1EDE;\n t['Ohorntilde'] = 0x1EE0;\n t['Ohungarumlaut'] = 0x0150;\n t['Oi'] = 0x01A2;\n t['Oinvertedbreve'] = 0x020E;\n t['Omacron'] = 0x014C;\n t['Omacronacute'] = 0x1E52;\n t['Omacrongrave'] = 0x1E50;\n t['Omega'] = 0x2126;\n t['Omegacyrillic'] = 0x0460;\n t['Omegagreek'] = 0x03A9;\n t['Omegaroundcyrillic'] = 0x047A;\n t['Omegatitlocyrillic'] = 0x047C;\n t['Omegatonos'] = 0x038F;\n t['Omicron'] = 0x039F;\n t['Omicrontonos'] = 0x038C;\n t['Omonospace'] = 0xFF2F;\n t['Oneroman'] = 0x2160;\n t['Oogonek'] = 0x01EA;\n t['Oogonekmacron'] = 0x01EC;\n t['Oopen'] = 0x0186;\n t['Oslash'] = 0x00D8;\n t['Oslashacute'] = 0x01FE;\n t['Oslashsmall'] = 0xF7F8;\n t['Osmall'] = 0xF76F;\n t['Ostrokeacute'] = 0x01FE;\n t['Otcyrillic'] = 0x047E;\n t['Otilde'] = 0x00D5;\n t['Otildeacute'] = 0x1E4C;\n t['Otildedieresis'] = 0x1E4E;\n t['Otildesmall'] = 0xF7F5;\n t['P'] = 0x0050;\n t['Pacute'] = 0x1E54;\n t['Pcircle'] = 0x24C5;\n t['Pdotaccent'] = 0x1E56;\n t['Pecyrillic'] = 0x041F;\n t['Peharmenian'] = 0x054A;\n t['Pemiddlehookcyrillic'] = 0x04A6;\n t['Phi'] = 0x03A6;\n t['Phook'] = 0x01A4;\n t['Pi'] = 0x03A0;\n t['Piwrarmenian'] = 0x0553;\n t['Pmonospace'] = 0xFF30;\n t['Psi'] = 0x03A8;\n t['Psicyrillic'] = 0x0470;\n t['Psmall'] = 0xF770;\n t['Q'] = 0x0051;\n t['Qcircle'] = 0x24C6;\n t['Qmonospace'] = 0xFF31;\n t['Qsmall'] = 0xF771;\n t['R'] = 0x0052;\n t['Raarmenian'] = 0x054C;\n t['Racute'] = 0x0154;\n t['Rcaron'] = 0x0158;\n t['Rcedilla'] = 0x0156;\n t['Rcircle'] = 0x24C7;\n t['Rcommaaccent'] = 0x0156;\n t['Rdblgrave'] = 0x0210;\n t['Rdotaccent'] = 0x1E58;\n t['Rdotbelow'] = 0x1E5A;\n t['Rdotbelowmacron'] = 0x1E5C;\n t['Reharmenian'] = 0x0550;\n t['Rfraktur'] = 0x211C;\n t['Rho'] = 0x03A1;\n t['Ringsmall'] = 0xF6FC;\n t['Rinvertedbreve'] = 0x0212;\n t['Rlinebelow'] = 0x1E5E;\n t['Rmonospace'] = 0xFF32;\n t['Rsmall'] = 0xF772;\n t['Rsmallinverted'] = 0x0281;\n t['Rsmallinvertedsuperior'] = 0x02B6;\n t['S'] = 0x0053;\n t['SF010000'] = 0x250C;\n t['SF020000'] = 0x2514;\n t['SF030000'] = 0x2510;\n t['SF040000'] = 0x2518;\n t['SF050000'] = 0x253C;\n t['SF060000'] = 0x252C;\n t['SF070000'] = 0x2534;\n t['SF080000'] = 0x251C;\n t['SF090000'] = 0x2524;\n t['SF100000'] = 0x2500;\n t['SF110000'] = 0x2502;\n t['SF190000'] = 0x2561;\n t['SF200000'] = 0x2562;\n t['SF210000'] = 0x2556;\n t['SF220000'] = 0x2555;\n t['SF230000'] = 0x2563;\n t['SF240000'] = 0x2551;\n t['SF250000'] = 0x2557;\n t['SF260000'] = 0x255D;\n t['SF270000'] = 0x255C;\n t['SF280000'] = 0x255B;\n t['SF360000'] = 0x255E;\n t['SF370000'] = 0x255F;\n t['SF380000'] = 0x255A;\n t['SF390000'] = 0x2554;\n t['SF400000'] = 0x2569;\n t['SF410000'] = 0x2566;\n t['SF420000'] = 0x2560;\n t['SF430000'] = 0x2550;\n t['SF440000'] = 0x256C;\n t['SF450000'] = 0x2567;\n t['SF460000'] = 0x2568;\n t['SF470000'] = 0x2564;\n t['SF480000'] = 0x2565;\n t['SF490000'] = 0x2559;\n t['SF500000'] = 0x2558;\n t['SF510000'] = 0x2552;\n t['SF520000'] = 0x2553;\n t['SF530000'] = 0x256B;\n t['SF540000'] = 0x256A;\n t['Sacute'] = 0x015A;\n t['Sacutedotaccent'] = 0x1E64;\n t['Sampigreek'] = 0x03E0;\n t['Scaron'] = 0x0160;\n t['Scarondotaccent'] = 0x1E66;\n t['Scaronsmall'] = 0xF6FD;\n t['Scedilla'] = 0x015E;\n t['Schwa'] = 0x018F;\n t['Schwacyrillic'] = 0x04D8;\n t['Schwadieresiscyrillic'] = 0x04DA;\n t['Scircle'] = 0x24C8;\n t['Scircumflex'] = 0x015C;\n t['Scommaaccent'] = 0x0218;\n t['Sdotaccent'] = 0x1E60;\n t['Sdotbelow'] = 0x1E62;\n t['Sdotbelowdotaccent'] = 0x1E68;\n t['Seharmenian'] = 0x054D;\n t['Sevenroman'] = 0x2166;\n t['Shaarmenian'] = 0x0547;\n t['Shacyrillic'] = 0x0428;\n t['Shchacyrillic'] = 0x0429;\n t['Sheicoptic'] = 0x03E2;\n t['Shhacyrillic'] = 0x04BA;\n t['Shimacoptic'] = 0x03EC;\n t['Sigma'] = 0x03A3;\n t['Sixroman'] = 0x2165;\n t['Smonospace'] = 0xFF33;\n t['Softsigncyrillic'] = 0x042C;\n t['Ssmall'] = 0xF773;\n t['Stigmagreek'] = 0x03DA;\n t['T'] = 0x0054;\n t['Tau'] = 0x03A4;\n t['Tbar'] = 0x0166;\n t['Tcaron'] = 0x0164;\n t['Tcedilla'] = 0x0162;\n t['Tcircle'] = 0x24C9;\n t['Tcircumflexbelow'] = 0x1E70;\n t['Tcommaaccent'] = 0x0162;\n t['Tdotaccent'] = 0x1E6A;\n t['Tdotbelow'] = 0x1E6C;\n t['Tecyrillic'] = 0x0422;\n t['Tedescendercyrillic'] = 0x04AC;\n t['Tenroman'] = 0x2169;\n t['Tetsecyrillic'] = 0x04B4;\n t['Theta'] = 0x0398;\n t['Thook'] = 0x01AC;\n t['Thorn'] = 0x00DE;\n t['Thornsmall'] = 0xF7FE;\n t['Threeroman'] = 0x2162;\n t['Tildesmall'] = 0xF6FE;\n t['Tiwnarmenian'] = 0x054F;\n t['Tlinebelow'] = 0x1E6E;\n t['Tmonospace'] = 0xFF34;\n t['Toarmenian'] = 0x0539;\n t['Tonefive'] = 0x01BC;\n t['Tonesix'] = 0x0184;\n t['Tonetwo'] = 0x01A7;\n t['Tretroflexhook'] = 0x01AE;\n t['Tsecyrillic'] = 0x0426;\n t['Tshecyrillic'] = 0x040B;\n t['Tsmall'] = 0xF774;\n t['Twelveroman'] = 0x216B;\n t['Tworoman'] = 0x2161;\n t['U'] = 0x0055;\n t['Uacute'] = 0x00DA;\n t['Uacutesmall'] = 0xF7FA;\n t['Ubreve'] = 0x016C;\n t['Ucaron'] = 0x01D3;\n t['Ucircle'] = 0x24CA;\n t['Ucircumflex'] = 0x00DB;\n t['Ucircumflexbelow'] = 0x1E76;\n t['Ucircumflexsmall'] = 0xF7FB;\n t['Ucyrillic'] = 0x0423;\n t['Udblacute'] = 0x0170;\n t['Udblgrave'] = 0x0214;\n t['Udieresis'] = 0x00DC;\n t['Udieresisacute'] = 0x01D7;\n t['Udieresisbelow'] = 0x1E72;\n t['Udieresiscaron'] = 0x01D9;\n t['Udieresiscyrillic'] = 0x04F0;\n t['Udieresisgrave'] = 0x01DB;\n t['Udieresismacron'] = 0x01D5;\n t['Udieresissmall'] = 0xF7FC;\n t['Udotbelow'] = 0x1EE4;\n t['Ugrave'] = 0x00D9;\n t['Ugravesmall'] = 0xF7F9;\n t['Uhookabove'] = 0x1EE6;\n t['Uhorn'] = 0x01AF;\n t['Uhornacute'] = 0x1EE8;\n t['Uhorndotbelow'] = 0x1EF0;\n t['Uhorngrave'] = 0x1EEA;\n t['Uhornhookabove'] = 0x1EEC;\n t['Uhorntilde'] = 0x1EEE;\n t['Uhungarumlaut'] = 0x0170;\n t['Uhungarumlautcyrillic'] = 0x04F2;\n t['Uinvertedbreve'] = 0x0216;\n t['Ukcyrillic'] = 0x0478;\n t['Umacron'] = 0x016A;\n t['Umacroncyrillic'] = 0x04EE;\n t['Umacrondieresis'] = 0x1E7A;\n t['Umonospace'] = 0xFF35;\n t['Uogonek'] = 0x0172;\n t['Upsilon'] = 0x03A5;\n t['Upsilon1'] = 0x03D2;\n t['Upsilonacutehooksymbolgreek'] = 0x03D3;\n t['Upsilonafrican'] = 0x01B1;\n t['Upsilondieresis'] = 0x03AB;\n t['Upsilondieresishooksymbolgreek'] = 0x03D4;\n t['Upsilonhooksymbol'] = 0x03D2;\n t['Upsilontonos'] = 0x038E;\n t['Uring'] = 0x016E;\n t['Ushortcyrillic'] = 0x040E;\n t['Usmall'] = 0xF775;\n t['Ustraightcyrillic'] = 0x04AE;\n t['Ustraightstrokecyrillic'] = 0x04B0;\n t['Utilde'] = 0x0168;\n t['Utildeacute'] = 0x1E78;\n t['Utildebelow'] = 0x1E74;\n t['V'] = 0x0056;\n t['Vcircle'] = 0x24CB;\n t['Vdotbelow'] = 0x1E7E;\n t['Vecyrillic'] = 0x0412;\n t['Vewarmenian'] = 0x054E;\n t['Vhook'] = 0x01B2;\n t['Vmonospace'] = 0xFF36;\n t['Voarmenian'] = 0x0548;\n t['Vsmall'] = 0xF776;\n t['Vtilde'] = 0x1E7C;\n t['W'] = 0x0057;\n t['Wacute'] = 0x1E82;\n t['Wcircle'] = 0x24CC;\n t['Wcircumflex'] = 0x0174;\n t['Wdieresis'] = 0x1E84;\n t['Wdotaccent'] = 0x1E86;\n t['Wdotbelow'] = 0x1E88;\n t['Wgrave'] = 0x1E80;\n t['Wmonospace'] = 0xFF37;\n t['Wsmall'] = 0xF777;\n t['X'] = 0x0058;\n t['Xcircle'] = 0x24CD;\n t['Xdieresis'] = 0x1E8C;\n t['Xdotaccent'] = 0x1E8A;\n t['Xeharmenian'] = 0x053D;\n t['Xi'] = 0x039E;\n t['Xmonospace'] = 0xFF38;\n t['Xsmall'] = 0xF778;\n t['Y'] = 0x0059;\n t['Yacute'] = 0x00DD;\n t['Yacutesmall'] = 0xF7FD;\n t['Yatcyrillic'] = 0x0462;\n t['Ycircle'] = 0x24CE;\n t['Ycircumflex'] = 0x0176;\n t['Ydieresis'] = 0x0178;\n t['Ydieresissmall'] = 0xF7FF;\n t['Ydotaccent'] = 0x1E8E;\n t['Ydotbelow'] = 0x1EF4;\n t['Yericyrillic'] = 0x042B;\n t['Yerudieresiscyrillic'] = 0x04F8;\n t['Ygrave'] = 0x1EF2;\n t['Yhook'] = 0x01B3;\n t['Yhookabove'] = 0x1EF6;\n t['Yiarmenian'] = 0x0545;\n t['Yicyrillic'] = 0x0407;\n t['Yiwnarmenian'] = 0x0552;\n t['Ymonospace'] = 0xFF39;\n t['Ysmall'] = 0xF779;\n t['Ytilde'] = 0x1EF8;\n t['Yusbigcyrillic'] = 0x046A;\n t['Yusbigiotifiedcyrillic'] = 0x046C;\n t['Yuslittlecyrillic'] = 0x0466;\n t['Yuslittleiotifiedcyrillic'] = 0x0468;\n t['Z'] = 0x005A;\n t['Zaarmenian'] = 0x0536;\n t['Zacute'] = 0x0179;\n t['Zcaron'] = 0x017D;\n t['Zcaronsmall'] = 0xF6FF;\n t['Zcircle'] = 0x24CF;\n t['Zcircumflex'] = 0x1E90;\n t['Zdot'] = 0x017B;\n t['Zdotaccent'] = 0x017B;\n t['Zdotbelow'] = 0x1E92;\n t['Zecyrillic'] = 0x0417;\n t['Zedescendercyrillic'] = 0x0498;\n t['Zedieresiscyrillic'] = 0x04DE;\n t['Zeta'] = 0x0396;\n t['Zhearmenian'] = 0x053A;\n t['Zhebrevecyrillic'] = 0x04C1;\n t['Zhecyrillic'] = 0x0416;\n t['Zhedescendercyrillic'] = 0x0496;\n t['Zhedieresiscyrillic'] = 0x04DC;\n t['Zlinebelow'] = 0x1E94;\n t['Zmonospace'] = 0xFF3A;\n t['Zsmall'] = 0xF77A;\n t['Zstroke'] = 0x01B5;\n t['a'] = 0x0061;\n t['aabengali'] = 0x0986;\n t['aacute'] = 0x00E1;\n t['aadeva'] = 0x0906;\n t['aagujarati'] = 0x0A86;\n t['aagurmukhi'] = 0x0A06;\n t['aamatragurmukhi'] = 0x0A3E;\n t['aarusquare'] = 0x3303;\n t['aavowelsignbengali'] = 0x09BE;\n t['aavowelsigndeva'] = 0x093E;\n t['aavowelsigngujarati'] = 0x0ABE;\n t['abbreviationmarkarmenian'] = 0x055F;\n t['abbreviationsigndeva'] = 0x0970;\n t['abengali'] = 0x0985;\n t['abopomofo'] = 0x311A;\n t['abreve'] = 0x0103;\n t['abreveacute'] = 0x1EAF;\n t['abrevecyrillic'] = 0x04D1;\n t['abrevedotbelow'] = 0x1EB7;\n t['abrevegrave'] = 0x1EB1;\n t['abrevehookabove'] = 0x1EB3;\n t['abrevetilde'] = 0x1EB5;\n t['acaron'] = 0x01CE;\n t['acircle'] = 0x24D0;\n t['acircumflex'] = 0x00E2;\n t['acircumflexacute'] = 0x1EA5;\n t['acircumflexdotbelow'] = 0x1EAD;\n t['acircumflexgrave'] = 0x1EA7;\n t['acircumflexhookabove'] = 0x1EA9;\n t['acircumflextilde'] = 0x1EAB;\n t['acute'] = 0x00B4;\n t['acutebelowcmb'] = 0x0317;\n t['acutecmb'] = 0x0301;\n t['acutecomb'] = 0x0301;\n t['acutedeva'] = 0x0954;\n t['acutelowmod'] = 0x02CF;\n t['acutetonecmb'] = 0x0341;\n t['acyrillic'] = 0x0430;\n t['adblgrave'] = 0x0201;\n t['addakgurmukhi'] = 0x0A71;\n t['adeva'] = 0x0905;\n t['adieresis'] = 0x00E4;\n t['adieresiscyrillic'] = 0x04D3;\n t['adieresismacron'] = 0x01DF;\n t['adotbelow'] = 0x1EA1;\n t['adotmacron'] = 0x01E1;\n t['ae'] = 0x00E6;\n t['aeacute'] = 0x01FD;\n t['aekorean'] = 0x3150;\n t['aemacron'] = 0x01E3;\n t['afii00208'] = 0x2015;\n t['afii08941'] = 0x20A4;\n t['afii10017'] = 0x0410;\n t['afii10018'] = 0x0411;\n t['afii10019'] = 0x0412;\n t['afii10020'] = 0x0413;\n t['afii10021'] = 0x0414;\n t['afii10022'] = 0x0415;\n t['afii10023'] = 0x0401;\n t['afii10024'] = 0x0416;\n t['afii10025'] = 0x0417;\n t['afii10026'] = 0x0418;\n t['afii10027'] = 0x0419;\n t['afii10028'] = 0x041A;\n t['afii10029'] = 0x041B;\n t['afii10030'] = 0x041C;\n t['afii10031'] = 0x041D;\n t['afii10032'] = 0x041E;\n t['afii10033'] = 0x041F;\n t['afii10034'] = 0x0420;\n t['afii10035'] = 0x0421;\n t['afii10036'] = 0x0422;\n t['afii10037'] = 0x0423;\n t['afii10038'] = 0x0424;\n t['afii10039'] = 0x0425;\n t['afii10040'] = 0x0426;\n t['afii10041'] = 0x0427;\n t['afii10042'] = 0x0428;\n t['afii10043'] = 0x0429;\n t['afii10044'] = 0x042A;\n t['afii10045'] = 0x042B;\n t['afii10046'] = 0x042C;\n t['afii10047'] = 0x042D;\n t['afii10048'] = 0x042E;\n t['afii10049'] = 0x042F;\n t['afii10050'] = 0x0490;\n t['afii10051'] = 0x0402;\n t['afii10052'] = 0x0403;\n t['afii10053'] = 0x0404;\n t['afii10054'] = 0x0405;\n t['afii10055'] = 0x0406;\n t['afii10056'] = 0x0407;\n t['afii10057'] = 0x0408;\n t['afii10058'] = 0x0409;\n t['afii10059'] = 0x040A;\n t['afii10060'] = 0x040B;\n t['afii10061'] = 0x040C;\n t['afii10062'] = 0x040E;\n t['afii10063'] = 0xF6C4;\n t['afii10064'] = 0xF6C5;\n t['afii10065'] = 0x0430;\n t['afii10066'] = 0x0431;\n t['afii10067'] = 0x0432;\n t['afii10068'] = 0x0433;\n t['afii10069'] = 0x0434;\n t['afii10070'] = 0x0435;\n t['afii10071'] = 0x0451;\n t['afii10072'] = 0x0436;\n t['afii10073'] = 0x0437;\n t['afii10074'] = 0x0438;\n t['afii10075'] = 0x0439;\n t['afii10076'] = 0x043A;\n t['afii10077'] = 0x043B;\n t['afii10078'] = 0x043C;\n t['afii10079'] = 0x043D;\n t['afii10080'] = 0x043E;\n t['afii10081'] = 0x043F;\n t['afii10082'] = 0x0440;\n t['afii10083'] = 0x0441;\n t['afii10084'] = 0x0442;\n t['afii10085'] = 0x0443;\n t['afii10086'] = 0x0444;\n t['afii10087'] = 0x0445;\n t['afii10088'] = 0x0446;\n t['afii10089'] = 0x0447;\n t['afii10090'] = 0x0448;\n t['afii10091'] = 0x0449;\n t['afii10092'] = 0x044A;\n t['afii10093'] = 0x044B;\n t['afii10094'] = 0x044C;\n t['afii10095'] = 0x044D;\n t['afii10096'] = 0x044E;\n t['afii10097'] = 0x044F;\n t['afii10098'] = 0x0491;\n t['afii10099'] = 0x0452;\n t['afii10100'] = 0x0453;\n t['afii10101'] = 0x0454;\n t['afii10102'] = 0x0455;\n t['afii10103'] = 0x0456;\n t['afii10104'] = 0x0457;\n t['afii10105'] = 0x0458;\n t['afii10106'] = 0x0459;\n t['afii10107'] = 0x045A;\n t['afii10108'] = 0x045B;\n t['afii10109'] = 0x045C;\n t['afii10110'] = 0x045E;\n t['afii10145'] = 0x040F;\n t['afii10146'] = 0x0462;\n t['afii10147'] = 0x0472;\n t['afii10148'] = 0x0474;\n t['afii10192'] = 0xF6C6;\n t['afii10193'] = 0x045F;\n t['afii10194'] = 0x0463;\n t['afii10195'] = 0x0473;\n t['afii10196'] = 0x0475;\n t['afii10831'] = 0xF6C7;\n t['afii10832'] = 0xF6C8;\n t['afii10846'] = 0x04D9;\n t['afii299'] = 0x200E;\n t['afii300'] = 0x200F;\n t['afii301'] = 0x200D;\n t['afii57381'] = 0x066A;\n t['afii57388'] = 0x060C;\n t['afii57392'] = 0x0660;\n t['afii57393'] = 0x0661;\n t['afii57394'] = 0x0662;\n t['afii57395'] = 0x0663;\n t['afii57396'] = 0x0664;\n t['afii57397'] = 0x0665;\n t['afii57398'] = 0x0666;\n t['afii57399'] = 0x0667;\n t['afii57400'] = 0x0668;\n t['afii57401'] = 0x0669;\n t['afii57403'] = 0x061B;\n t['afii57407'] = 0x061F;\n t['afii57409'] = 0x0621;\n t['afii57410'] = 0x0622;\n t['afii57411'] = 0x0623;\n t['afii57412'] = 0x0624;\n t['afii57413'] = 0x0625;\n t['afii57414'] = 0x0626;\n t['afii57415'] = 0x0627;\n t['afii57416'] = 0x0628;\n t['afii57417'] = 0x0629;\n t['afii57418'] = 0x062A;\n t['afii57419'] = 0x062B;\n t['afii57420'] = 0x062C;\n t['afii57421'] = 0x062D;\n t['afii57422'] = 0x062E;\n t['afii57423'] = 0x062F;\n t['afii57424'] = 0x0630;\n t['afii57425'] = 0x0631;\n t['afii57426'] = 0x0632;\n t['afii57427'] = 0x0633;\n t['afii57428'] = 0x0634;\n t['afii57429'] = 0x0635;\n t['afii57430'] = 0x0636;\n t['afii57431'] = 0x0637;\n t['afii57432'] = 0x0638;\n t['afii57433'] = 0x0639;\n t['afii57434'] = 0x063A;\n t['afii57440'] = 0x0640;\n t['afii57441'] = 0x0641;\n t['afii57442'] = 0x0642;\n t['afii57443'] = 0x0643;\n t['afii57444'] = 0x0644;\n t['afii57445'] = 0x0645;\n t['afii57446'] = 0x0646;\n t['afii57448'] = 0x0648;\n t['afii57449'] = 0x0649;\n t['afii57450'] = 0x064A;\n t['afii57451'] = 0x064B;\n t['afii57452'] = 0x064C;\n t['afii57453'] = 0x064D;\n t['afii57454'] = 0x064E;\n t['afii57455'] = 0x064F;\n t['afii57456'] = 0x0650;\n t['afii57457'] = 0x0651;\n t['afii57458'] = 0x0652;\n t['afii57470'] = 0x0647;\n t['afii57505'] = 0x06A4;\n t['afii57506'] = 0x067E;\n t['afii57507'] = 0x0686;\n t['afii57508'] = 0x0698;\n t['afii57509'] = 0x06AF;\n t['afii57511'] = 0x0679;\n t['afii57512'] = 0x0688;\n t['afii57513'] = 0x0691;\n t['afii57514'] = 0x06BA;\n t['afii57519'] = 0x06D2;\n t['afii57534'] = 0x06D5;\n t['afii57636'] = 0x20AA;\n t['afii57645'] = 0x05BE;\n t['afii57658'] = 0x05C3;\n t['afii57664'] = 0x05D0;\n t['afii57665'] = 0x05D1;\n t['afii57666'] = 0x05D2;\n t['afii57667'] = 0x05D3;\n t['afii57668'] = 0x05D4;\n t['afii57669'] = 0x05D5;\n t['afii57670'] = 0x05D6;\n t['afii57671'] = 0x05D7;\n t['afii57672'] = 0x05D8;\n t['afii57673'] = 0x05D9;\n t['afii57674'] = 0x05DA;\n t['afii57675'] = 0x05DB;\n t['afii57676'] = 0x05DC;\n t['afii57677'] = 0x05DD;\n t['afii57678'] = 0x05DE;\n t['afii57679'] = 0x05DF;\n t['afii57680'] = 0x05E0;\n t['afii57681'] = 0x05E1;\n t['afii57682'] = 0x05E2;\n t['afii57683'] = 0x05E3;\n t['afii57684'] = 0x05E4;\n t['afii57685'] = 0x05E5;\n t['afii57686'] = 0x05E6;\n t['afii57687'] = 0x05E7;\n t['afii57688'] = 0x05E8;\n t['afii57689'] = 0x05E9;\n t['afii57690'] = 0x05EA;\n t['afii57694'] = 0xFB2A;\n t['afii57695'] = 0xFB2B;\n t['afii57700'] = 0xFB4B;\n t['afii57705'] = 0xFB1F;\n t['afii57716'] = 0x05F0;\n t['afii57717'] = 0x05F1;\n t['afii57718'] = 0x05F2;\n t['afii57723'] = 0xFB35;\n t['afii57793'] = 0x05B4;\n t['afii57794'] = 0x05B5;\n t['afii57795'] = 0x05B6;\n t['afii57796'] = 0x05BB;\n t['afii57797'] = 0x05B8;\n t['afii57798'] = 0x05B7;\n t['afii57799'] = 0x05B0;\n t['afii57800'] = 0x05B2;\n t['afii57801'] = 0x05B1;\n t['afii57802'] = 0x05B3;\n t['afii57803'] = 0x05C2;\n t['afii57804'] = 0x05C1;\n t['afii57806'] = 0x05B9;\n t['afii57807'] = 0x05BC;\n t['afii57839'] = 0x05BD;\n t['afii57841'] = 0x05BF;\n t['afii57842'] = 0x05C0;\n t['afii57929'] = 0x02BC;\n t['afii61248'] = 0x2105;\n t['afii61289'] = 0x2113;\n t['afii61352'] = 0x2116;\n t['afii61573'] = 0x202C;\n t['afii61574'] = 0x202D;\n t['afii61575'] = 0x202E;\n t['afii61664'] = 0x200C;\n t['afii63167'] = 0x066D;\n t['afii64937'] = 0x02BD;\n t['agrave'] = 0x00E0;\n t['agujarati'] = 0x0A85;\n t['agurmukhi'] = 0x0A05;\n t['ahiragana'] = 0x3042;\n t['ahookabove'] = 0x1EA3;\n t['aibengali'] = 0x0990;\n t['aibopomofo'] = 0x311E;\n t['aideva'] = 0x0910;\n t['aiecyrillic'] = 0x04D5;\n t['aigujarati'] = 0x0A90;\n t['aigurmukhi'] = 0x0A10;\n t['aimatragurmukhi'] = 0x0A48;\n t['ainarabic'] = 0x0639;\n t['ainfinalarabic'] = 0xFECA;\n t['aininitialarabic'] = 0xFECB;\n t['ainmedialarabic'] = 0xFECC;\n t['ainvertedbreve'] = 0x0203;\n t['aivowelsignbengali'] = 0x09C8;\n t['aivowelsigndeva'] = 0x0948;\n t['aivowelsigngujarati'] = 0x0AC8;\n t['akatakana'] = 0x30A2;\n t['akatakanahalfwidth'] = 0xFF71;\n t['akorean'] = 0x314F;\n t['alef'] = 0x05D0;\n t['alefarabic'] = 0x0627;\n t['alefdageshhebrew'] = 0xFB30;\n t['aleffinalarabic'] = 0xFE8E;\n t['alefhamzaabovearabic'] = 0x0623;\n t['alefhamzaabovefinalarabic'] = 0xFE84;\n t['alefhamzabelowarabic'] = 0x0625;\n t['alefhamzabelowfinalarabic'] = 0xFE88;\n t['alefhebrew'] = 0x05D0;\n t['aleflamedhebrew'] = 0xFB4F;\n t['alefmaddaabovearabic'] = 0x0622;\n t['alefmaddaabovefinalarabic'] = 0xFE82;\n t['alefmaksuraarabic'] = 0x0649;\n t['alefmaksurafinalarabic'] = 0xFEF0;\n t['alefmaksurainitialarabic'] = 0xFEF3;\n t['alefmaksuramedialarabic'] = 0xFEF4;\n t['alefpatahhebrew'] = 0xFB2E;\n t['alefqamatshebrew'] = 0xFB2F;\n t['aleph'] = 0x2135;\n t['allequal'] = 0x224C;\n t['alpha'] = 0x03B1;\n t['alphatonos'] = 0x03AC;\n t['amacron'] = 0x0101;\n t['amonospace'] = 0xFF41;\n t['ampersand'] = 0x0026;\n t['ampersandmonospace'] = 0xFF06;\n t['ampersandsmall'] = 0xF726;\n t['amsquare'] = 0x33C2;\n t['anbopomofo'] = 0x3122;\n t['angbopomofo'] = 0x3124;\n t['angbracketleft'] = 0x3008; // Glyph is missing from Adobe's original list.\n t['angbracketright'] = 0x3009; // Glyph is missing from Adobe's original list.\n t['angkhankhuthai'] = 0x0E5A;\n t['angle'] = 0x2220;\n t['anglebracketleft'] = 0x3008;\n t['anglebracketleftvertical'] = 0xFE3F;\n t['anglebracketright'] = 0x3009;\n t['anglebracketrightvertical'] = 0xFE40;\n t['angleleft'] = 0x2329;\n t['angleright'] = 0x232A;\n t['angstrom'] = 0x212B;\n t['anoteleia'] = 0x0387;\n t['anudattadeva'] = 0x0952;\n t['anusvarabengali'] = 0x0982;\n t['anusvaradeva'] = 0x0902;\n t['anusvaragujarati'] = 0x0A82;\n t['aogonek'] = 0x0105;\n t['apaatosquare'] = 0x3300;\n t['aparen'] = 0x249C;\n t['apostrophearmenian'] = 0x055A;\n t['apostrophemod'] = 0x02BC;\n t['apple'] = 0xF8FF;\n t['approaches'] = 0x2250;\n t['approxequal'] = 0x2248;\n t['approxequalorimage'] = 0x2252;\n t['approximatelyequal'] = 0x2245;\n t['araeaekorean'] = 0x318E;\n t['araeakorean'] = 0x318D;\n t['arc'] = 0x2312;\n t['arighthalfring'] = 0x1E9A;\n t['aring'] = 0x00E5;\n t['aringacute'] = 0x01FB;\n t['aringbelow'] = 0x1E01;\n t['arrowboth'] = 0x2194;\n t['arrowdashdown'] = 0x21E3;\n t['arrowdashleft'] = 0x21E0;\n t['arrowdashright'] = 0x21E2;\n t['arrowdashup'] = 0x21E1;\n t['arrowdblboth'] = 0x21D4;\n t['arrowdbldown'] = 0x21D3;\n t['arrowdblleft'] = 0x21D0;\n t['arrowdblright'] = 0x21D2;\n t['arrowdblup'] = 0x21D1;\n t['arrowdown'] = 0x2193;\n t['arrowdownleft'] = 0x2199;\n t['arrowdownright'] = 0x2198;\n t['arrowdownwhite'] = 0x21E9;\n t['arrowheaddownmod'] = 0x02C5;\n t['arrowheadleftmod'] = 0x02C2;\n t['arrowheadrightmod'] = 0x02C3;\n t['arrowheadupmod'] = 0x02C4;\n t['arrowhorizex'] = 0xF8E7;\n t['arrowleft'] = 0x2190;\n t['arrowleftdbl'] = 0x21D0;\n t['arrowleftdblstroke'] = 0x21CD;\n t['arrowleftoverright'] = 0x21C6;\n t['arrowleftwhite'] = 0x21E6;\n t['arrowright'] = 0x2192;\n t['arrowrightdblstroke'] = 0x21CF;\n t['arrowrightheavy'] = 0x279E;\n t['arrowrightoverleft'] = 0x21C4;\n t['arrowrightwhite'] = 0x21E8;\n t['arrowtableft'] = 0x21E4;\n t['arrowtabright'] = 0x21E5;\n t['arrowup'] = 0x2191;\n t['arrowupdn'] = 0x2195;\n t['arrowupdnbse'] = 0x21A8;\n t['arrowupdownbase'] = 0x21A8;\n t['arrowupleft'] = 0x2196;\n t['arrowupleftofdown'] = 0x21C5;\n t['arrowupright'] = 0x2197;\n t['arrowupwhite'] = 0x21E7;\n t['arrowvertex'] = 0xF8E6;\n t['asciicircum'] = 0x005E;\n t['asciicircummonospace'] = 0xFF3E;\n t['asciitilde'] = 0x007E;\n t['asciitildemonospace'] = 0xFF5E;\n t['ascript'] = 0x0251;\n t['ascriptturned'] = 0x0252;\n t['asmallhiragana'] = 0x3041;\n t['asmallkatakana'] = 0x30A1;\n t['asmallkatakanahalfwidth'] = 0xFF67;\n t['asterisk'] = 0x002A;\n t['asteriskaltonearabic'] = 0x066D;\n t['asteriskarabic'] = 0x066D;\n t['asteriskmath'] = 0x2217;\n t['asteriskmonospace'] = 0xFF0A;\n t['asterisksmall'] = 0xFE61;\n t['asterism'] = 0x2042;\n t['asuperior'] = 0xF6E9;\n t['asymptoticallyequal'] = 0x2243;\n t['at'] = 0x0040;\n t['atilde'] = 0x00E3;\n t['atmonospace'] = 0xFF20;\n t['atsmall'] = 0xFE6B;\n t['aturned'] = 0x0250;\n t['aubengali'] = 0x0994;\n t['aubopomofo'] = 0x3120;\n t['audeva'] = 0x0914;\n t['augujarati'] = 0x0A94;\n t['augurmukhi'] = 0x0A14;\n t['aulengthmarkbengali'] = 0x09D7;\n t['aumatragurmukhi'] = 0x0A4C;\n t['auvowelsignbengali'] = 0x09CC;\n t['auvowelsigndeva'] = 0x094C;\n t['auvowelsigngujarati'] = 0x0ACC;\n t['avagrahadeva'] = 0x093D;\n t['aybarmenian'] = 0x0561;\n t['ayin'] = 0x05E2;\n t['ayinaltonehebrew'] = 0xFB20;\n t['ayinhebrew'] = 0x05E2;\n t['b'] = 0x0062;\n t['babengali'] = 0x09AC;\n t['backslash'] = 0x005C;\n t['backslashmonospace'] = 0xFF3C;\n t['badeva'] = 0x092C;\n t['bagujarati'] = 0x0AAC;\n t['bagurmukhi'] = 0x0A2C;\n t['bahiragana'] = 0x3070;\n t['bahtthai'] = 0x0E3F;\n t['bakatakana'] = 0x30D0;\n t['bar'] = 0x007C;\n t['barmonospace'] = 0xFF5C;\n t['bbopomofo'] = 0x3105;\n t['bcircle'] = 0x24D1;\n t['bdotaccent'] = 0x1E03;\n t['bdotbelow'] = 0x1E05;\n t['beamedsixteenthnotes'] = 0x266C;\n t['because'] = 0x2235;\n t['becyrillic'] = 0x0431;\n t['beharabic'] = 0x0628;\n t['behfinalarabic'] = 0xFE90;\n t['behinitialarabic'] = 0xFE91;\n t['behiragana'] = 0x3079;\n t['behmedialarabic'] = 0xFE92;\n t['behmeeminitialarabic'] = 0xFC9F;\n t['behmeemisolatedarabic'] = 0xFC08;\n t['behnoonfinalarabic'] = 0xFC6D;\n t['bekatakana'] = 0x30D9;\n t['benarmenian'] = 0x0562;\n t['bet'] = 0x05D1;\n t['beta'] = 0x03B2;\n t['betasymbolgreek'] = 0x03D0;\n t['betdagesh'] = 0xFB31;\n t['betdageshhebrew'] = 0xFB31;\n t['bethebrew'] = 0x05D1;\n t['betrafehebrew'] = 0xFB4C;\n t['bhabengali'] = 0x09AD;\n t['bhadeva'] = 0x092D;\n t['bhagujarati'] = 0x0AAD;\n t['bhagurmukhi'] = 0x0A2D;\n t['bhook'] = 0x0253;\n t['bihiragana'] = 0x3073;\n t['bikatakana'] = 0x30D3;\n t['bilabialclick'] = 0x0298;\n t['bindigurmukhi'] = 0x0A02;\n t['birusquare'] = 0x3331;\n t['blackcircle'] = 0x25CF;\n t['blackdiamond'] = 0x25C6;\n t['blackdownpointingtriangle'] = 0x25BC;\n t['blackleftpointingpointer'] = 0x25C4;\n t['blackleftpointingtriangle'] = 0x25C0;\n t['blacklenticularbracketleft'] = 0x3010;\n t['blacklenticularbracketleftvertical'] = 0xFE3B;\n t['blacklenticularbracketright'] = 0x3011;\n t['blacklenticularbracketrightvertical'] = 0xFE3C;\n t['blacklowerlefttriangle'] = 0x25E3;\n t['blacklowerrighttriangle'] = 0x25E2;\n t['blackrectangle'] = 0x25AC;\n t['blackrightpointingpointer'] = 0x25BA;\n t['blackrightpointingtriangle'] = 0x25B6;\n t['blacksmallsquare'] = 0x25AA;\n t['blacksmilingface'] = 0x263B;\n t['blacksquare'] = 0x25A0;\n t['blackstar'] = 0x2605;\n t['blackupperlefttriangle'] = 0x25E4;\n t['blackupperrighttriangle'] = 0x25E5;\n t['blackuppointingsmalltriangle'] = 0x25B4;\n t['blackuppointingtriangle'] = 0x25B2;\n t['blank'] = 0x2423;\n t['blinebelow'] = 0x1E07;\n t['block'] = 0x2588;\n t['bmonospace'] = 0xFF42;\n t['bobaimaithai'] = 0x0E1A;\n t['bohiragana'] = 0x307C;\n t['bokatakana'] = 0x30DC;\n t['bparen'] = 0x249D;\n t['bqsquare'] = 0x33C3;\n t['braceex'] = 0xF8F4;\n t['braceleft'] = 0x007B;\n t['braceleftbt'] = 0xF8F3;\n t['braceleftmid'] = 0xF8F2;\n t['braceleftmonospace'] = 0xFF5B;\n t['braceleftsmall'] = 0xFE5B;\n t['bracelefttp'] = 0xF8F1;\n t['braceleftvertical'] = 0xFE37;\n t['braceright'] = 0x007D;\n t['bracerightbt'] = 0xF8FE;\n t['bracerightmid'] = 0xF8FD;\n t['bracerightmonospace'] = 0xFF5D;\n t['bracerightsmall'] = 0xFE5C;\n t['bracerighttp'] = 0xF8FC;\n t['bracerightvertical'] = 0xFE38;\n t['bracketleft'] = 0x005B;\n t['bracketleftbt'] = 0xF8F0;\n t['bracketleftex'] = 0xF8EF;\n t['bracketleftmonospace'] = 0xFF3B;\n t['bracketlefttp'] = 0xF8EE;\n t['bracketright'] = 0x005D;\n t['bracketrightbt'] = 0xF8FB;\n t['bracketrightex'] = 0xF8FA;\n t['bracketrightmonospace'] = 0xFF3D;\n t['bracketrighttp'] = 0xF8F9;\n t['breve'] = 0x02D8;\n t['brevebelowcmb'] = 0x032E;\n t['brevecmb'] = 0x0306;\n t['breveinvertedbelowcmb'] = 0x032F;\n t['breveinvertedcmb'] = 0x0311;\n t['breveinverteddoublecmb'] = 0x0361;\n t['bridgebelowcmb'] = 0x032A;\n t['bridgeinvertedbelowcmb'] = 0x033A;\n t['brokenbar'] = 0x00A6;\n t['bstroke'] = 0x0180;\n t['bsuperior'] = 0xF6EA;\n t['btopbar'] = 0x0183;\n t['buhiragana'] = 0x3076;\n t['bukatakana'] = 0x30D6;\n t['bullet'] = 0x2022;\n t['bulletinverse'] = 0x25D8;\n t['bulletoperator'] = 0x2219;\n t['bullseye'] = 0x25CE;\n t['c'] = 0x0063;\n t['caarmenian'] = 0x056E;\n t['cabengali'] = 0x099A;\n t['cacute'] = 0x0107;\n t['cadeva'] = 0x091A;\n t['cagujarati'] = 0x0A9A;\n t['cagurmukhi'] = 0x0A1A;\n t['calsquare'] = 0x3388;\n t['candrabindubengali'] = 0x0981;\n t['candrabinducmb'] = 0x0310;\n t['candrabindudeva'] = 0x0901;\n t['candrabindugujarati'] = 0x0A81;\n t['capslock'] = 0x21EA;\n t['careof'] = 0x2105;\n t['caron'] = 0x02C7;\n t['caronbelowcmb'] = 0x032C;\n t['caroncmb'] = 0x030C;\n t['carriagereturn'] = 0x21B5;\n t['cbopomofo'] = 0x3118;\n t['ccaron'] = 0x010D;\n t['ccedilla'] = 0x00E7;\n t['ccedillaacute'] = 0x1E09;\n t['ccircle'] = 0x24D2;\n t['ccircumflex'] = 0x0109;\n t['ccurl'] = 0x0255;\n t['cdot'] = 0x010B;\n t['cdotaccent'] = 0x010B;\n t['cdsquare'] = 0x33C5;\n t['cedilla'] = 0x00B8;\n t['cedillacmb'] = 0x0327;\n t['cent'] = 0x00A2;\n t['centigrade'] = 0x2103;\n t['centinferior'] = 0xF6DF;\n t['centmonospace'] = 0xFFE0;\n t['centoldstyle'] = 0xF7A2;\n t['centsuperior'] = 0xF6E0;\n t['chaarmenian'] = 0x0579;\n t['chabengali'] = 0x099B;\n t['chadeva'] = 0x091B;\n t['chagujarati'] = 0x0A9B;\n t['chagurmukhi'] = 0x0A1B;\n t['chbopomofo'] = 0x3114;\n t['cheabkhasiancyrillic'] = 0x04BD;\n t['checkmark'] = 0x2713;\n t['checyrillic'] = 0x0447;\n t['chedescenderabkhasiancyrillic'] = 0x04BF;\n t['chedescendercyrillic'] = 0x04B7;\n t['chedieresiscyrillic'] = 0x04F5;\n t['cheharmenian'] = 0x0573;\n t['chekhakassiancyrillic'] = 0x04CC;\n t['cheverticalstrokecyrillic'] = 0x04B9;\n t['chi'] = 0x03C7;\n t['chieuchacirclekorean'] = 0x3277;\n t['chieuchaparenkorean'] = 0x3217;\n t['chieuchcirclekorean'] = 0x3269;\n t['chieuchkorean'] = 0x314A;\n t['chieuchparenkorean'] = 0x3209;\n t['chochangthai'] = 0x0E0A;\n t['chochanthai'] = 0x0E08;\n t['chochingthai'] = 0x0E09;\n t['chochoethai'] = 0x0E0C;\n t['chook'] = 0x0188;\n t['cieucacirclekorean'] = 0x3276;\n t['cieucaparenkorean'] = 0x3216;\n t['cieuccirclekorean'] = 0x3268;\n t['cieuckorean'] = 0x3148;\n t['cieucparenkorean'] = 0x3208;\n t['cieucuparenkorean'] = 0x321C;\n t['circle'] = 0x25CB;\n t['circlecopyrt'] = 0x00A9; // Glyph is missing from Adobe's original list.\n t['circlemultiply'] = 0x2297;\n t['circleot'] = 0x2299;\n t['circleplus'] = 0x2295;\n t['circlepostalmark'] = 0x3036;\n t['circlewithlefthalfblack'] = 0x25D0;\n t['circlewithrighthalfblack'] = 0x25D1;\n t['circumflex'] = 0x02C6;\n t['circumflexbelowcmb'] = 0x032D;\n t['circumflexcmb'] = 0x0302;\n t['clear'] = 0x2327;\n t['clickalveolar'] = 0x01C2;\n t['clickdental'] = 0x01C0;\n t['clicklateral'] = 0x01C1;\n t['clickretroflex'] = 0x01C3;\n t['club'] = 0x2663;\n t['clubsuitblack'] = 0x2663;\n t['clubsuitwhite'] = 0x2667;\n t['cmcubedsquare'] = 0x33A4;\n t['cmonospace'] = 0xFF43;\n t['cmsquaredsquare'] = 0x33A0;\n t['coarmenian'] = 0x0581;\n t['colon'] = 0x003A;\n t['colonmonetary'] = 0x20A1;\n t['colonmonospace'] = 0xFF1A;\n t['colonsign'] = 0x20A1;\n t['colonsmall'] = 0xFE55;\n t['colontriangularhalfmod'] = 0x02D1;\n t['colontriangularmod'] = 0x02D0;\n t['comma'] = 0x002C;\n t['commaabovecmb'] = 0x0313;\n t['commaaboverightcmb'] = 0x0315;\n t['commaaccent'] = 0xF6C3;\n t['commaarabic'] = 0x060C;\n t['commaarmenian'] = 0x055D;\n t['commainferior'] = 0xF6E1;\n t['commamonospace'] = 0xFF0C;\n t['commareversedabovecmb'] = 0x0314;\n t['commareversedmod'] = 0x02BD;\n t['commasmall'] = 0xFE50;\n t['commasuperior'] = 0xF6E2;\n t['commaturnedabovecmb'] = 0x0312;\n t['commaturnedmod'] = 0x02BB;\n t['compass'] = 0x263C;\n t['congruent'] = 0x2245;\n t['contourintegral'] = 0x222E;\n t['control'] = 0x2303;\n t['controlACK'] = 0x0006;\n t['controlBEL'] = 0x0007;\n t['controlBS'] = 0x0008;\n t['controlCAN'] = 0x0018;\n t['controlCR'] = 0x000D;\n t['controlDC1'] = 0x0011;\n t['controlDC2'] = 0x0012;\n t['controlDC3'] = 0x0013;\n t['controlDC4'] = 0x0014;\n t['controlDEL'] = 0x007F;\n t['controlDLE'] = 0x0010;\n t['controlEM'] = 0x0019;\n t['controlENQ'] = 0x0005;\n t['controlEOT'] = 0x0004;\n t['controlESC'] = 0x001B;\n t['controlETB'] = 0x0017;\n t['controlETX'] = 0x0003;\n t['controlFF'] = 0x000C;\n t['controlFS'] = 0x001C;\n t['controlGS'] = 0x001D;\n t['controlHT'] = 0x0009;\n t['controlLF'] = 0x000A;\n t['controlNAK'] = 0x0015;\n t['controlNULL'] = 0x0000; // Glyph is missing from Adobe's original list.\n t['controlRS'] = 0x001E;\n t['controlSI'] = 0x000F;\n t['controlSO'] = 0x000E;\n t['controlSOT'] = 0x0002;\n t['controlSTX'] = 0x0001;\n t['controlSUB'] = 0x001A;\n t['controlSYN'] = 0x0016;\n t['controlUS'] = 0x001F;\n t['controlVT'] = 0x000B;\n t['copyright'] = 0x00A9;\n t['copyrightsans'] = 0xF8E9;\n t['copyrightserif'] = 0xF6D9;\n t['cornerbracketleft'] = 0x300C;\n t['cornerbracketlefthalfwidth'] = 0xFF62;\n t['cornerbracketleftvertical'] = 0xFE41;\n t['cornerbracketright'] = 0x300D;\n t['cornerbracketrighthalfwidth'] = 0xFF63;\n t['cornerbracketrightvertical'] = 0xFE42;\n t['corporationsquare'] = 0x337F;\n t['cosquare'] = 0x33C7;\n t['coverkgsquare'] = 0x33C6;\n t['cparen'] = 0x249E;\n t['cruzeiro'] = 0x20A2;\n t['cstretched'] = 0x0297;\n t['curlyand'] = 0x22CF;\n t['curlyor'] = 0x22CE;\n t['currency'] = 0x00A4;\n t['cyrBreve'] = 0xF6D1;\n t['cyrFlex'] = 0xF6D2;\n t['cyrbreve'] = 0xF6D4;\n t['cyrflex'] = 0xF6D5;\n t['d'] = 0x0064;\n t['daarmenian'] = 0x0564;\n t['dabengali'] = 0x09A6;\n t['dadarabic'] = 0x0636;\n t['dadeva'] = 0x0926;\n t['dadfinalarabic'] = 0xFEBE;\n t['dadinitialarabic'] = 0xFEBF;\n t['dadmedialarabic'] = 0xFEC0;\n t['dagesh'] = 0x05BC;\n t['dageshhebrew'] = 0x05BC;\n t['dagger'] = 0x2020;\n t['daggerdbl'] = 0x2021;\n t['dagujarati'] = 0x0AA6;\n t['dagurmukhi'] = 0x0A26;\n t['dahiragana'] = 0x3060;\n t['dakatakana'] = 0x30C0;\n t['dalarabic'] = 0x062F;\n t['dalet'] = 0x05D3;\n t['daletdagesh'] = 0xFB33;\n t['daletdageshhebrew'] = 0xFB33;\n t['dalethebrew'] = 0x05D3;\n t['dalfinalarabic'] = 0xFEAA;\n t['dammaarabic'] = 0x064F;\n t['dammalowarabic'] = 0x064F;\n t['dammatanaltonearabic'] = 0x064C;\n t['dammatanarabic'] = 0x064C;\n t['danda'] = 0x0964;\n t['dargahebrew'] = 0x05A7;\n t['dargalefthebrew'] = 0x05A7;\n t['dasiapneumatacyrilliccmb'] = 0x0485;\n t['dblGrave'] = 0xF6D3;\n t['dblanglebracketleft'] = 0x300A;\n t['dblanglebracketleftvertical'] = 0xFE3D;\n t['dblanglebracketright'] = 0x300B;\n t['dblanglebracketrightvertical'] = 0xFE3E;\n t['dblarchinvertedbelowcmb'] = 0x032B;\n t['dblarrowleft'] = 0x21D4;\n t['dblarrowright'] = 0x21D2;\n t['dbldanda'] = 0x0965;\n t['dblgrave'] = 0xF6D6;\n t['dblgravecmb'] = 0x030F;\n t['dblintegral'] = 0x222C;\n t['dbllowline'] = 0x2017;\n t['dbllowlinecmb'] = 0x0333;\n t['dbloverlinecmb'] = 0x033F;\n t['dblprimemod'] = 0x02BA;\n t['dblverticalbar'] = 0x2016;\n t['dblverticallineabovecmb'] = 0x030E;\n t['dbopomofo'] = 0x3109;\n t['dbsquare'] = 0x33C8;\n t['dcaron'] = 0x010F;\n t['dcedilla'] = 0x1E11;\n t['dcircle'] = 0x24D3;\n t['dcircumflexbelow'] = 0x1E13;\n t['dcroat'] = 0x0111;\n t['ddabengali'] = 0x09A1;\n t['ddadeva'] = 0x0921;\n t['ddagujarati'] = 0x0AA1;\n t['ddagurmukhi'] = 0x0A21;\n t['ddalarabic'] = 0x0688;\n t['ddalfinalarabic'] = 0xFB89;\n t['dddhadeva'] = 0x095C;\n t['ddhabengali'] = 0x09A2;\n t['ddhadeva'] = 0x0922;\n t['ddhagujarati'] = 0x0AA2;\n t['ddhagurmukhi'] = 0x0A22;\n t['ddotaccent'] = 0x1E0B;\n t['ddotbelow'] = 0x1E0D;\n t['decimalseparatorarabic'] = 0x066B;\n t['decimalseparatorpersian'] = 0x066B;\n t['decyrillic'] = 0x0434;\n t['degree'] = 0x00B0;\n t['dehihebrew'] = 0x05AD;\n t['dehiragana'] = 0x3067;\n t['deicoptic'] = 0x03EF;\n t['dekatakana'] = 0x30C7;\n t['deleteleft'] = 0x232B;\n t['deleteright'] = 0x2326;\n t['delta'] = 0x03B4;\n t['deltaturned'] = 0x018D;\n t['denominatorminusonenumeratorbengali'] = 0x09F8;\n t['dezh'] = 0x02A4;\n t['dhabengali'] = 0x09A7;\n t['dhadeva'] = 0x0927;\n t['dhagujarati'] = 0x0AA7;\n t['dhagurmukhi'] = 0x0A27;\n t['dhook'] = 0x0257;\n t['dialytikatonos'] = 0x0385;\n t['dialytikatonoscmb'] = 0x0344;\n t['diamond'] = 0x2666;\n t['diamondsuitwhite'] = 0x2662;\n t['dieresis'] = 0x00A8;\n t['dieresisacute'] = 0xF6D7;\n t['dieresisbelowcmb'] = 0x0324;\n t['dieresiscmb'] = 0x0308;\n t['dieresisgrave'] = 0xF6D8;\n t['dieresistonos'] = 0x0385;\n t['dihiragana'] = 0x3062;\n t['dikatakana'] = 0x30C2;\n t['dittomark'] = 0x3003;\n t['divide'] = 0x00F7;\n t['divides'] = 0x2223;\n t['divisionslash'] = 0x2215;\n t['djecyrillic'] = 0x0452;\n t['dkshade'] = 0x2593;\n t['dlinebelow'] = 0x1E0F;\n t['dlsquare'] = 0x3397;\n t['dmacron'] = 0x0111;\n t['dmonospace'] = 0xFF44;\n t['dnblock'] = 0x2584;\n t['dochadathai'] = 0x0E0E;\n t['dodekthai'] = 0x0E14;\n t['dohiragana'] = 0x3069;\n t['dokatakana'] = 0x30C9;\n t['dollar'] = 0x0024;\n t['dollarinferior'] = 0xF6E3;\n t['dollarmonospace'] = 0xFF04;\n t['dollaroldstyle'] = 0xF724;\n t['dollarsmall'] = 0xFE69;\n t['dollarsuperior'] = 0xF6E4;\n t['dong'] = 0x20AB;\n t['dorusquare'] = 0x3326;\n t['dotaccent'] = 0x02D9;\n t['dotaccentcmb'] = 0x0307;\n t['dotbelowcmb'] = 0x0323;\n t['dotbelowcomb'] = 0x0323;\n t['dotkatakana'] = 0x30FB;\n t['dotlessi'] = 0x0131;\n t['dotlessj'] = 0xF6BE;\n t['dotlessjstrokehook'] = 0x0284;\n t['dotmath'] = 0x22C5;\n t['dottedcircle'] = 0x25CC;\n t['doubleyodpatah'] = 0xFB1F;\n t['doubleyodpatahhebrew'] = 0xFB1F;\n t['downtackbelowcmb'] = 0x031E;\n t['downtackmod'] = 0x02D5;\n t['dparen'] = 0x249F;\n t['dsuperior'] = 0xF6EB;\n t['dtail'] = 0x0256;\n t['dtopbar'] = 0x018C;\n t['duhiragana'] = 0x3065;\n t['dukatakana'] = 0x30C5;\n t['dz'] = 0x01F3;\n t['dzaltone'] = 0x02A3;\n t['dzcaron'] = 0x01C6;\n t['dzcurl'] = 0x02A5;\n t['dzeabkhasiancyrillic'] = 0x04E1;\n t['dzecyrillic'] = 0x0455;\n t['dzhecyrillic'] = 0x045F;\n t['e'] = 0x0065;\n t['eacute'] = 0x00E9;\n t['earth'] = 0x2641;\n t['ebengali'] = 0x098F;\n t['ebopomofo'] = 0x311C;\n t['ebreve'] = 0x0115;\n t['ecandradeva'] = 0x090D;\n t['ecandragujarati'] = 0x0A8D;\n t['ecandravowelsigndeva'] = 0x0945;\n t['ecandravowelsigngujarati'] = 0x0AC5;\n t['ecaron'] = 0x011B;\n t['ecedillabreve'] = 0x1E1D;\n t['echarmenian'] = 0x0565;\n t['echyiwnarmenian'] = 0x0587;\n t['ecircle'] = 0x24D4;\n t['ecircumflex'] = 0x00EA;\n t['ecircumflexacute'] = 0x1EBF;\n t['ecircumflexbelow'] = 0x1E19;\n t['ecircumflexdotbelow'] = 0x1EC7;\n t['ecircumflexgrave'] = 0x1EC1;\n t['ecircumflexhookabove'] = 0x1EC3;\n t['ecircumflextilde'] = 0x1EC5;\n t['ecyrillic'] = 0x0454;\n t['edblgrave'] = 0x0205;\n t['edeva'] = 0x090F;\n t['edieresis'] = 0x00EB;\n t['edot'] = 0x0117;\n t['edotaccent'] = 0x0117;\n t['edotbelow'] = 0x1EB9;\n t['eegurmukhi'] = 0x0A0F;\n t['eematragurmukhi'] = 0x0A47;\n t['efcyrillic'] = 0x0444;\n t['egrave'] = 0x00E8;\n t['egujarati'] = 0x0A8F;\n t['eharmenian'] = 0x0567;\n t['ehbopomofo'] = 0x311D;\n t['ehiragana'] = 0x3048;\n t['ehookabove'] = 0x1EBB;\n t['eibopomofo'] = 0x311F;\n t['eight'] = 0x0038;\n t['eightarabic'] = 0x0668;\n t['eightbengali'] = 0x09EE;\n t['eightcircle'] = 0x2467;\n t['eightcircleinversesansserif'] = 0x2791;\n t['eightdeva'] = 0x096E;\n t['eighteencircle'] = 0x2471;\n t['eighteenparen'] = 0x2485;\n t['eighteenperiod'] = 0x2499;\n t['eightgujarati'] = 0x0AEE;\n t['eightgurmukhi'] = 0x0A6E;\n t['eighthackarabic'] = 0x0668;\n t['eighthangzhou'] = 0x3028;\n t['eighthnotebeamed'] = 0x266B;\n t['eightideographicparen'] = 0x3227;\n t['eightinferior'] = 0x2088;\n t['eightmonospace'] = 0xFF18;\n t['eightoldstyle'] = 0xF738;\n t['eightparen'] = 0x247B;\n t['eightperiod'] = 0x248F;\n t['eightpersian'] = 0x06F8;\n t['eightroman'] = 0x2177;\n t['eightsuperior'] = 0x2078;\n t['eightthai'] = 0x0E58;\n t['einvertedbreve'] = 0x0207;\n t['eiotifiedcyrillic'] = 0x0465;\n t['ekatakana'] = 0x30A8;\n t['ekatakanahalfwidth'] = 0xFF74;\n t['ekonkargurmukhi'] = 0x0A74;\n t['ekorean'] = 0x3154;\n t['elcyrillic'] = 0x043B;\n t['element'] = 0x2208;\n t['elevencircle'] = 0x246A;\n t['elevenparen'] = 0x247E;\n t['elevenperiod'] = 0x2492;\n t['elevenroman'] = 0x217A;\n t['ellipsis'] = 0x2026;\n t['ellipsisvertical'] = 0x22EE;\n t['emacron'] = 0x0113;\n t['emacronacute'] = 0x1E17;\n t['emacrongrave'] = 0x1E15;\n t['emcyrillic'] = 0x043C;\n t['emdash'] = 0x2014;\n t['emdashvertical'] = 0xFE31;\n t['emonospace'] = 0xFF45;\n t['emphasismarkarmenian'] = 0x055B;\n t['emptyset'] = 0x2205;\n t['enbopomofo'] = 0x3123;\n t['encyrillic'] = 0x043D;\n t['endash'] = 0x2013;\n t['endashvertical'] = 0xFE32;\n t['endescendercyrillic'] = 0x04A3;\n t['eng'] = 0x014B;\n t['engbopomofo'] = 0x3125;\n t['enghecyrillic'] = 0x04A5;\n t['enhookcyrillic'] = 0x04C8;\n t['enspace'] = 0x2002;\n t['eogonek'] = 0x0119;\n t['eokorean'] = 0x3153;\n t['eopen'] = 0x025B;\n t['eopenclosed'] = 0x029A;\n t['eopenreversed'] = 0x025C;\n t['eopenreversedclosed'] = 0x025E;\n t['eopenreversedhook'] = 0x025D;\n t['eparen'] = 0x24A0;\n t['epsilon'] = 0x03B5;\n t['epsilontonos'] = 0x03AD;\n t['equal'] = 0x003D;\n t['equalmonospace'] = 0xFF1D;\n t['equalsmall'] = 0xFE66;\n t['equalsuperior'] = 0x207C;\n t['equivalence'] = 0x2261;\n t['erbopomofo'] = 0x3126;\n t['ercyrillic'] = 0x0440;\n t['ereversed'] = 0x0258;\n t['ereversedcyrillic'] = 0x044D;\n t['escyrillic'] = 0x0441;\n t['esdescendercyrillic'] = 0x04AB;\n t['esh'] = 0x0283;\n t['eshcurl'] = 0x0286;\n t['eshortdeva'] = 0x090E;\n t['eshortvowelsigndeva'] = 0x0946;\n t['eshreversedloop'] = 0x01AA;\n t['eshsquatreversed'] = 0x0285;\n t['esmallhiragana'] = 0x3047;\n t['esmallkatakana'] = 0x30A7;\n t['esmallkatakanahalfwidth'] = 0xFF6A;\n t['estimated'] = 0x212E;\n t['esuperior'] = 0xF6EC;\n t['eta'] = 0x03B7;\n t['etarmenian'] = 0x0568;\n t['etatonos'] = 0x03AE;\n t['eth'] = 0x00F0;\n t['etilde'] = 0x1EBD;\n t['etildebelow'] = 0x1E1B;\n t['etnahtafoukhhebrew'] = 0x0591;\n t['etnahtafoukhlefthebrew'] = 0x0591;\n t['etnahtahebrew'] = 0x0591;\n t['etnahtalefthebrew'] = 0x0591;\n t['eturned'] = 0x01DD;\n t['eukorean'] = 0x3161;\n t['euro'] = 0x20AC;\n t['evowelsignbengali'] = 0x09C7;\n t['evowelsigndeva'] = 0x0947;\n t['evowelsigngujarati'] = 0x0AC7;\n t['exclam'] = 0x0021;\n t['exclamarmenian'] = 0x055C;\n t['exclamdbl'] = 0x203C;\n t['exclamdown'] = 0x00A1;\n t['exclamdownsmall'] = 0xF7A1;\n t['exclammonospace'] = 0xFF01;\n t['exclamsmall'] = 0xF721;\n t['existential'] = 0x2203;\n t['ezh'] = 0x0292;\n t['ezhcaron'] = 0x01EF;\n t['ezhcurl'] = 0x0293;\n t['ezhreversed'] = 0x01B9;\n t['ezhtail'] = 0x01BA;\n t['f'] = 0x0066;\n t['fadeva'] = 0x095E;\n t['fagurmukhi'] = 0x0A5E;\n t['fahrenheit'] = 0x2109;\n t['fathaarabic'] = 0x064E;\n t['fathalowarabic'] = 0x064E;\n t['fathatanarabic'] = 0x064B;\n t['fbopomofo'] = 0x3108;\n t['fcircle'] = 0x24D5;\n t['fdotaccent'] = 0x1E1F;\n t['feharabic'] = 0x0641;\n t['feharmenian'] = 0x0586;\n t['fehfinalarabic'] = 0xFED2;\n t['fehinitialarabic'] = 0xFED3;\n t['fehmedialarabic'] = 0xFED4;\n t['feicoptic'] = 0x03E5;\n t['female'] = 0x2640;\n t['ff'] = 0xFB00;\n t['ffi'] = 0xFB03;\n t['ffl'] = 0xFB04;\n t['fi'] = 0xFB01;\n t['fifteencircle'] = 0x246E;\n t['fifteenparen'] = 0x2482;\n t['fifteenperiod'] = 0x2496;\n t['figuredash'] = 0x2012;\n t['filledbox'] = 0x25A0;\n t['filledrect'] = 0x25AC;\n t['finalkaf'] = 0x05DA;\n t['finalkafdagesh'] = 0xFB3A;\n t['finalkafdageshhebrew'] = 0xFB3A;\n t['finalkafhebrew'] = 0x05DA;\n t['finalmem'] = 0x05DD;\n t['finalmemhebrew'] = 0x05DD;\n t['finalnun'] = 0x05DF;\n t['finalnunhebrew'] = 0x05DF;\n t['finalpe'] = 0x05E3;\n t['finalpehebrew'] = 0x05E3;\n t['finaltsadi'] = 0x05E5;\n t['finaltsadihebrew'] = 0x05E5;\n t['firsttonechinese'] = 0x02C9;\n t['fisheye'] = 0x25C9;\n t['fitacyrillic'] = 0x0473;\n t['five'] = 0x0035;\n t['fivearabic'] = 0x0665;\n t['fivebengali'] = 0x09EB;\n t['fivecircle'] = 0x2464;\n t['fivecircleinversesansserif'] = 0x278E;\n t['fivedeva'] = 0x096B;\n t['fiveeighths'] = 0x215D;\n t['fivegujarati'] = 0x0AEB;\n t['fivegurmukhi'] = 0x0A6B;\n t['fivehackarabic'] = 0x0665;\n t['fivehangzhou'] = 0x3025;\n t['fiveideographicparen'] = 0x3224;\n t['fiveinferior'] = 0x2085;\n t['fivemonospace'] = 0xFF15;\n t['fiveoldstyle'] = 0xF735;\n t['fiveparen'] = 0x2478;\n t['fiveperiod'] = 0x248C;\n t['fivepersian'] = 0x06F5;\n t['fiveroman'] = 0x2174;\n t['fivesuperior'] = 0x2075;\n t['fivethai'] = 0x0E55;\n t['fl'] = 0xFB02;\n t['florin'] = 0x0192;\n t['fmonospace'] = 0xFF46;\n t['fmsquare'] = 0x3399;\n t['fofanthai'] = 0x0E1F;\n t['fofathai'] = 0x0E1D;\n t['fongmanthai'] = 0x0E4F;\n t['forall'] = 0x2200;\n t['four'] = 0x0034;\n t['fourarabic'] = 0x0664;\n t['fourbengali'] = 0x09EA;\n t['fourcircle'] = 0x2463;\n t['fourcircleinversesansserif'] = 0x278D;\n t['fourdeva'] = 0x096A;\n t['fourgujarati'] = 0x0AEA;\n t['fourgurmukhi'] = 0x0A6A;\n t['fourhackarabic'] = 0x0664;\n t['fourhangzhou'] = 0x3024;\n t['fourideographicparen'] = 0x3223;\n t['fourinferior'] = 0x2084;\n t['fourmonospace'] = 0xFF14;\n t['fournumeratorbengali'] = 0x09F7;\n t['fouroldstyle'] = 0xF734;\n t['fourparen'] = 0x2477;\n t['fourperiod'] = 0x248B;\n t['fourpersian'] = 0x06F4;\n t['fourroman'] = 0x2173;\n t['foursuperior'] = 0x2074;\n t['fourteencircle'] = 0x246D;\n t['fourteenparen'] = 0x2481;\n t['fourteenperiod'] = 0x2495;\n t['fourthai'] = 0x0E54;\n t['fourthtonechinese'] = 0x02CB;\n t['fparen'] = 0x24A1;\n t['fraction'] = 0x2044;\n t['franc'] = 0x20A3;\n t['g'] = 0x0067;\n t['gabengali'] = 0x0997;\n t['gacute'] = 0x01F5;\n t['gadeva'] = 0x0917;\n t['gafarabic'] = 0x06AF;\n t['gaffinalarabic'] = 0xFB93;\n t['gafinitialarabic'] = 0xFB94;\n t['gafmedialarabic'] = 0xFB95;\n t['gagujarati'] = 0x0A97;\n t['gagurmukhi'] = 0x0A17;\n t['gahiragana'] = 0x304C;\n t['gakatakana'] = 0x30AC;\n t['gamma'] = 0x03B3;\n t['gammalatinsmall'] = 0x0263;\n t['gammasuperior'] = 0x02E0;\n t['gangiacoptic'] = 0x03EB;\n t['gbopomofo'] = 0x310D;\n t['gbreve'] = 0x011F;\n t['gcaron'] = 0x01E7;\n t['gcedilla'] = 0x0123;\n t['gcircle'] = 0x24D6;\n t['gcircumflex'] = 0x011D;\n t['gcommaaccent'] = 0x0123;\n t['gdot'] = 0x0121;\n t['gdotaccent'] = 0x0121;\n t['gecyrillic'] = 0x0433;\n t['gehiragana'] = 0x3052;\n t['gekatakana'] = 0x30B2;\n t['geometricallyequal'] = 0x2251;\n t['gereshaccenthebrew'] = 0x059C;\n t['gereshhebrew'] = 0x05F3;\n t['gereshmuqdamhebrew'] = 0x059D;\n t['germandbls'] = 0x00DF;\n t['gershayimaccenthebrew'] = 0x059E;\n t['gershayimhebrew'] = 0x05F4;\n t['getamark'] = 0x3013;\n t['ghabengali'] = 0x0998;\n t['ghadarmenian'] = 0x0572;\n t['ghadeva'] = 0x0918;\n t['ghagujarati'] = 0x0A98;\n t['ghagurmukhi'] = 0x0A18;\n t['ghainarabic'] = 0x063A;\n t['ghainfinalarabic'] = 0xFECE;\n t['ghaininitialarabic'] = 0xFECF;\n t['ghainmedialarabic'] = 0xFED0;\n t['ghemiddlehookcyrillic'] = 0x0495;\n t['ghestrokecyrillic'] = 0x0493;\n t['gheupturncyrillic'] = 0x0491;\n t['ghhadeva'] = 0x095A;\n t['ghhagurmukhi'] = 0x0A5A;\n t['ghook'] = 0x0260;\n t['ghzsquare'] = 0x3393;\n t['gihiragana'] = 0x304E;\n t['gikatakana'] = 0x30AE;\n t['gimarmenian'] = 0x0563;\n t['gimel'] = 0x05D2;\n t['gimeldagesh'] = 0xFB32;\n t['gimeldageshhebrew'] = 0xFB32;\n t['gimelhebrew'] = 0x05D2;\n t['gjecyrillic'] = 0x0453;\n t['glottalinvertedstroke'] = 0x01BE;\n t['glottalstop'] = 0x0294;\n t['glottalstopinverted'] = 0x0296;\n t['glottalstopmod'] = 0x02C0;\n t['glottalstopreversed'] = 0x0295;\n t['glottalstopreversedmod'] = 0x02C1;\n t['glottalstopreversedsuperior'] = 0x02E4;\n t['glottalstopstroke'] = 0x02A1;\n t['glottalstopstrokereversed'] = 0x02A2;\n t['gmacron'] = 0x1E21;\n t['gmonospace'] = 0xFF47;\n t['gohiragana'] = 0x3054;\n t['gokatakana'] = 0x30B4;\n t['gparen'] = 0x24A2;\n t['gpasquare'] = 0x33AC;\n t['gradient'] = 0x2207;\n t['grave'] = 0x0060;\n t['gravebelowcmb'] = 0x0316;\n t['gravecmb'] = 0x0300;\n t['gravecomb'] = 0x0300;\n t['gravedeva'] = 0x0953;\n t['gravelowmod'] = 0x02CE;\n t['gravemonospace'] = 0xFF40;\n t['gravetonecmb'] = 0x0340;\n t['greater'] = 0x003E;\n t['greaterequal'] = 0x2265;\n t['greaterequalorless'] = 0x22DB;\n t['greatermonospace'] = 0xFF1E;\n t['greaterorequivalent'] = 0x2273;\n t['greaterorless'] = 0x2277;\n t['greateroverequal'] = 0x2267;\n t['greatersmall'] = 0xFE65;\n t['gscript'] = 0x0261;\n t['gstroke'] = 0x01E5;\n t['guhiragana'] = 0x3050;\n t['guillemotleft'] = 0x00AB;\n t['guillemotright'] = 0x00BB;\n t['guilsinglleft'] = 0x2039;\n t['guilsinglright'] = 0x203A;\n t['gukatakana'] = 0x30B0;\n t['guramusquare'] = 0x3318;\n t['gysquare'] = 0x33C9;\n t['h'] = 0x0068;\n t['haabkhasiancyrillic'] = 0x04A9;\n t['haaltonearabic'] = 0x06C1;\n t['habengali'] = 0x09B9;\n t['hadescendercyrillic'] = 0x04B3;\n t['hadeva'] = 0x0939;\n t['hagujarati'] = 0x0AB9;\n t['hagurmukhi'] = 0x0A39;\n t['haharabic'] = 0x062D;\n t['hahfinalarabic'] = 0xFEA2;\n t['hahinitialarabic'] = 0xFEA3;\n t['hahiragana'] = 0x306F;\n t['hahmedialarabic'] = 0xFEA4;\n t['haitusquare'] = 0x332A;\n t['hakatakana'] = 0x30CF;\n t['hakatakanahalfwidth'] = 0xFF8A;\n t['halantgurmukhi'] = 0x0A4D;\n t['hamzaarabic'] = 0x0621;\n t['hamzalowarabic'] = 0x0621;\n t['hangulfiller'] = 0x3164;\n t['hardsigncyrillic'] = 0x044A;\n t['harpoonleftbarbup'] = 0x21BC;\n t['harpoonrightbarbup'] = 0x21C0;\n t['hasquare'] = 0x33CA;\n t['hatafpatah'] = 0x05B2;\n t['hatafpatah16'] = 0x05B2;\n t['hatafpatah23'] = 0x05B2;\n t['hatafpatah2f'] = 0x05B2;\n t['hatafpatahhebrew'] = 0x05B2;\n t['hatafpatahnarrowhebrew'] = 0x05B2;\n t['hatafpatahquarterhebrew'] = 0x05B2;\n t['hatafpatahwidehebrew'] = 0x05B2;\n t['hatafqamats'] = 0x05B3;\n t['hatafqamats1b'] = 0x05B3;\n t['hatafqamats28'] = 0x05B3;\n t['hatafqamats34'] = 0x05B3;\n t['hatafqamatshebrew'] = 0x05B3;\n t['hatafqamatsnarrowhebrew'] = 0x05B3;\n t['hatafqamatsquarterhebrew'] = 0x05B3;\n t['hatafqamatswidehebrew'] = 0x05B3;\n t['hatafsegol'] = 0x05B1;\n t['hatafsegol17'] = 0x05B1;\n t['hatafsegol24'] = 0x05B1;\n t['hatafsegol30'] = 0x05B1;\n t['hatafsegolhebrew'] = 0x05B1;\n t['hatafsegolnarrowhebrew'] = 0x05B1;\n t['hatafsegolquarterhebrew'] = 0x05B1;\n t['hatafsegolwidehebrew'] = 0x05B1;\n t['hbar'] = 0x0127;\n t['hbopomofo'] = 0x310F;\n t['hbrevebelow'] = 0x1E2B;\n t['hcedilla'] = 0x1E29;\n t['hcircle'] = 0x24D7;\n t['hcircumflex'] = 0x0125;\n t['hdieresis'] = 0x1E27;\n t['hdotaccent'] = 0x1E23;\n t['hdotbelow'] = 0x1E25;\n t['he'] = 0x05D4;\n t['heart'] = 0x2665;\n t['heartsuitblack'] = 0x2665;\n t['heartsuitwhite'] = 0x2661;\n t['hedagesh'] = 0xFB34;\n t['hedageshhebrew'] = 0xFB34;\n t['hehaltonearabic'] = 0x06C1;\n t['heharabic'] = 0x0647;\n t['hehebrew'] = 0x05D4;\n t['hehfinalaltonearabic'] = 0xFBA7;\n t['hehfinalalttwoarabic'] = 0xFEEA;\n t['hehfinalarabic'] = 0xFEEA;\n t['hehhamzaabovefinalarabic'] = 0xFBA5;\n t['hehhamzaaboveisolatedarabic'] = 0xFBA4;\n t['hehinitialaltonearabic'] = 0xFBA8;\n t['hehinitialarabic'] = 0xFEEB;\n t['hehiragana'] = 0x3078;\n t['hehmedialaltonearabic'] = 0xFBA9;\n t['hehmedialarabic'] = 0xFEEC;\n t['heiseierasquare'] = 0x337B;\n t['hekatakana'] = 0x30D8;\n t['hekatakanahalfwidth'] = 0xFF8D;\n t['hekutaarusquare'] = 0x3336;\n t['henghook'] = 0x0267;\n t['herutusquare'] = 0x3339;\n t['het'] = 0x05D7;\n t['hethebrew'] = 0x05D7;\n t['hhook'] = 0x0266;\n t['hhooksuperior'] = 0x02B1;\n t['hieuhacirclekorean'] = 0x327B;\n t['hieuhaparenkorean'] = 0x321B;\n t['hieuhcirclekorean'] = 0x326D;\n t['hieuhkorean'] = 0x314E;\n t['hieuhparenkorean'] = 0x320D;\n t['hihiragana'] = 0x3072;\n t['hikatakana'] = 0x30D2;\n t['hikatakanahalfwidth'] = 0xFF8B;\n t['hiriq'] = 0x05B4;\n t['hiriq14'] = 0x05B4;\n t['hiriq21'] = 0x05B4;\n t['hiriq2d'] = 0x05B4;\n t['hiriqhebrew'] = 0x05B4;\n t['hiriqnarrowhebrew'] = 0x05B4;\n t['hiriqquarterhebrew'] = 0x05B4;\n t['hiriqwidehebrew'] = 0x05B4;\n t['hlinebelow'] = 0x1E96;\n t['hmonospace'] = 0xFF48;\n t['hoarmenian'] = 0x0570;\n t['hohipthai'] = 0x0E2B;\n t['hohiragana'] = 0x307B;\n t['hokatakana'] = 0x30DB;\n t['hokatakanahalfwidth'] = 0xFF8E;\n t['holam'] = 0x05B9;\n t['holam19'] = 0x05B9;\n t['holam26'] = 0x05B9;\n t['holam32'] = 0x05B9;\n t['holamhebrew'] = 0x05B9;\n t['holamnarrowhebrew'] = 0x05B9;\n t['holamquarterhebrew'] = 0x05B9;\n t['holamwidehebrew'] = 0x05B9;\n t['honokhukthai'] = 0x0E2E;\n t['hookabovecomb'] = 0x0309;\n t['hookcmb'] = 0x0309;\n t['hookpalatalizedbelowcmb'] = 0x0321;\n t['hookretroflexbelowcmb'] = 0x0322;\n t['hoonsquare'] = 0x3342;\n t['horicoptic'] = 0x03E9;\n t['horizontalbar'] = 0x2015;\n t['horncmb'] = 0x031B;\n t['hotsprings'] = 0x2668;\n t['house'] = 0x2302;\n t['hparen'] = 0x24A3;\n t['hsuperior'] = 0x02B0;\n t['hturned'] = 0x0265;\n t['huhiragana'] = 0x3075;\n t['huiitosquare'] = 0x3333;\n t['hukatakana'] = 0x30D5;\n t['hukatakanahalfwidth'] = 0xFF8C;\n t['hungarumlaut'] = 0x02DD;\n t['hungarumlautcmb'] = 0x030B;\n t['hv'] = 0x0195;\n t['hyphen'] = 0x002D;\n t['hypheninferior'] = 0xF6E5;\n t['hyphenmonospace'] = 0xFF0D;\n t['hyphensmall'] = 0xFE63;\n t['hyphensuperior'] = 0xF6E6;\n t['hyphentwo'] = 0x2010;\n t['i'] = 0x0069;\n t['iacute'] = 0x00ED;\n t['iacyrillic'] = 0x044F;\n t['ibengali'] = 0x0987;\n t['ibopomofo'] = 0x3127;\n t['ibreve'] = 0x012D;\n t['icaron'] = 0x01D0;\n t['icircle'] = 0x24D8;\n t['icircumflex'] = 0x00EE;\n t['icyrillic'] = 0x0456;\n t['idblgrave'] = 0x0209;\n t['ideographearthcircle'] = 0x328F;\n t['ideographfirecircle'] = 0x328B;\n t['ideographicallianceparen'] = 0x323F;\n t['ideographiccallparen'] = 0x323A;\n t['ideographiccentrecircle'] = 0x32A5;\n t['ideographicclose'] = 0x3006;\n t['ideographiccomma'] = 0x3001;\n t['ideographiccommaleft'] = 0xFF64;\n t['ideographiccongratulationparen'] = 0x3237;\n t['ideographiccorrectcircle'] = 0x32A3;\n t['ideographicearthparen'] = 0x322F;\n t['ideographicenterpriseparen'] = 0x323D;\n t['ideographicexcellentcircle'] = 0x329D;\n t['ideographicfestivalparen'] = 0x3240;\n t['ideographicfinancialcircle'] = 0x3296;\n t['ideographicfinancialparen'] = 0x3236;\n t['ideographicfireparen'] = 0x322B;\n t['ideographichaveparen'] = 0x3232;\n t['ideographichighcircle'] = 0x32A4;\n t['ideographiciterationmark'] = 0x3005;\n t['ideographiclaborcircle'] = 0x3298;\n t['ideographiclaborparen'] = 0x3238;\n t['ideographicleftcircle'] = 0x32A7;\n t['ideographiclowcircle'] = 0x32A6;\n t['ideographicmedicinecircle'] = 0x32A9;\n t['ideographicmetalparen'] = 0x322E;\n t['ideographicmoonparen'] = 0x322A;\n t['ideographicnameparen'] = 0x3234;\n t['ideographicperiod'] = 0x3002;\n t['ideographicprintcircle'] = 0x329E;\n t['ideographicreachparen'] = 0x3243;\n t['ideographicrepresentparen'] = 0x3239;\n t['ideographicresourceparen'] = 0x323E;\n t['ideographicrightcircle'] = 0x32A8;\n t['ideographicsecretcircle'] = 0x3299;\n t['ideographicselfparen'] = 0x3242;\n t['ideographicsocietyparen'] = 0x3233;\n t['ideographicspace'] = 0x3000;\n t['ideographicspecialparen'] = 0x3235;\n t['ideographicstockparen'] = 0x3231;\n t['ideographicstudyparen'] = 0x323B;\n t['ideographicsunparen'] = 0x3230;\n t['ideographicsuperviseparen'] = 0x323C;\n t['ideographicwaterparen'] = 0x322C;\n t['ideographicwoodparen'] = 0x322D;\n t['ideographiczero'] = 0x3007;\n t['ideographmetalcircle'] = 0x328E;\n t['ideographmooncircle'] = 0x328A;\n t['ideographnamecircle'] = 0x3294;\n t['ideographsuncircle'] = 0x3290;\n t['ideographwatercircle'] = 0x328C;\n t['ideographwoodcircle'] = 0x328D;\n t['ideva'] = 0x0907;\n t['idieresis'] = 0x00EF;\n t['idieresisacute'] = 0x1E2F;\n t['idieresiscyrillic'] = 0x04E5;\n t['idotbelow'] = 0x1ECB;\n t['iebrevecyrillic'] = 0x04D7;\n t['iecyrillic'] = 0x0435;\n t['ieungacirclekorean'] = 0x3275;\n t['ieungaparenkorean'] = 0x3215;\n t['ieungcirclekorean'] = 0x3267;\n t['ieungkorean'] = 0x3147;\n t['ieungparenkorean'] = 0x3207;\n t['igrave'] = 0x00EC;\n t['igujarati'] = 0x0A87;\n t['igurmukhi'] = 0x0A07;\n t['ihiragana'] = 0x3044;\n t['ihookabove'] = 0x1EC9;\n t['iibengali'] = 0x0988;\n t['iicyrillic'] = 0x0438;\n t['iideva'] = 0x0908;\n t['iigujarati'] = 0x0A88;\n t['iigurmukhi'] = 0x0A08;\n t['iimatragurmukhi'] = 0x0A40;\n t['iinvertedbreve'] = 0x020B;\n t['iishortcyrillic'] = 0x0439;\n t['iivowelsignbengali'] = 0x09C0;\n t['iivowelsigndeva'] = 0x0940;\n t['iivowelsigngujarati'] = 0x0AC0;\n t['ij'] = 0x0133;\n t['ikatakana'] = 0x30A4;\n t['ikatakanahalfwidth'] = 0xFF72;\n t['ikorean'] = 0x3163;\n t['ilde'] = 0x02DC;\n t['iluyhebrew'] = 0x05AC;\n t['imacron'] = 0x012B;\n t['imacroncyrillic'] = 0x04E3;\n t['imageorapproximatelyequal'] = 0x2253;\n t['imatragurmukhi'] = 0x0A3F;\n t['imonospace'] = 0xFF49;\n t['increment'] = 0x2206;\n t['infinity'] = 0x221E;\n t['iniarmenian'] = 0x056B;\n t['integral'] = 0x222B;\n t['integralbottom'] = 0x2321;\n t['integralbt'] = 0x2321;\n t['integralex'] = 0xF8F5;\n t['integraltop'] = 0x2320;\n t['integraltp'] = 0x2320;\n t['intersection'] = 0x2229;\n t['intisquare'] = 0x3305;\n t['invbullet'] = 0x25D8;\n t['invcircle'] = 0x25D9;\n t['invsmileface'] = 0x263B;\n t['iocyrillic'] = 0x0451;\n t['iogonek'] = 0x012F;\n t['iota'] = 0x03B9;\n t['iotadieresis'] = 0x03CA;\n t['iotadieresistonos'] = 0x0390;\n t['iotalatin'] = 0x0269;\n t['iotatonos'] = 0x03AF;\n t['iparen'] = 0x24A4;\n t['irigurmukhi'] = 0x0A72;\n t['ismallhiragana'] = 0x3043;\n t['ismallkatakana'] = 0x30A3;\n t['ismallkatakanahalfwidth'] = 0xFF68;\n t['issharbengali'] = 0x09FA;\n t['istroke'] = 0x0268;\n t['isuperior'] = 0xF6ED;\n t['iterationhiragana'] = 0x309D;\n t['iterationkatakana'] = 0x30FD;\n t['itilde'] = 0x0129;\n t['itildebelow'] = 0x1E2D;\n t['iubopomofo'] = 0x3129;\n t['iucyrillic'] = 0x044E;\n t['ivowelsignbengali'] = 0x09BF;\n t['ivowelsigndeva'] = 0x093F;\n t['ivowelsigngujarati'] = 0x0ABF;\n t['izhitsacyrillic'] = 0x0475;\n t['izhitsadblgravecyrillic'] = 0x0477;\n t['j'] = 0x006A;\n t['jaarmenian'] = 0x0571;\n t['jabengali'] = 0x099C;\n t['jadeva'] = 0x091C;\n t['jagujarati'] = 0x0A9C;\n t['jagurmukhi'] = 0x0A1C;\n t['jbopomofo'] = 0x3110;\n t['jcaron'] = 0x01F0;\n t['jcircle'] = 0x24D9;\n t['jcircumflex'] = 0x0135;\n t['jcrossedtail'] = 0x029D;\n t['jdotlessstroke'] = 0x025F;\n t['jecyrillic'] = 0x0458;\n t['jeemarabic'] = 0x062C;\n t['jeemfinalarabic'] = 0xFE9E;\n t['jeeminitialarabic'] = 0xFE9F;\n t['jeemmedialarabic'] = 0xFEA0;\n t['jeharabic'] = 0x0698;\n t['jehfinalarabic'] = 0xFB8B;\n t['jhabengali'] = 0x099D;\n t['jhadeva'] = 0x091D;\n t['jhagujarati'] = 0x0A9D;\n t['jhagurmukhi'] = 0x0A1D;\n t['jheharmenian'] = 0x057B;\n t['jis'] = 0x3004;\n t['jmonospace'] = 0xFF4A;\n t['jparen'] = 0x24A5;\n t['jsuperior'] = 0x02B2;\n t['k'] = 0x006B;\n t['kabashkircyrillic'] = 0x04A1;\n t['kabengali'] = 0x0995;\n t['kacute'] = 0x1E31;\n t['kacyrillic'] = 0x043A;\n t['kadescendercyrillic'] = 0x049B;\n t['kadeva'] = 0x0915;\n t['kaf'] = 0x05DB;\n t['kafarabic'] = 0x0643;\n t['kafdagesh'] = 0xFB3B;\n t['kafdageshhebrew'] = 0xFB3B;\n t['kaffinalarabic'] = 0xFEDA;\n t['kafhebrew'] = 0x05DB;\n t['kafinitialarabic'] = 0xFEDB;\n t['kafmedialarabic'] = 0xFEDC;\n t['kafrafehebrew'] = 0xFB4D;\n t['kagujarati'] = 0x0A95;\n t['kagurmukhi'] = 0x0A15;\n t['kahiragana'] = 0x304B;\n t['kahookcyrillic'] = 0x04C4;\n t['kakatakana'] = 0x30AB;\n t['kakatakanahalfwidth'] = 0xFF76;\n t['kappa'] = 0x03BA;\n t['kappasymbolgreek'] = 0x03F0;\n t['kapyeounmieumkorean'] = 0x3171;\n t['kapyeounphieuphkorean'] = 0x3184;\n t['kapyeounpieupkorean'] = 0x3178;\n t['kapyeounssangpieupkorean'] = 0x3179;\n t['karoriisquare'] = 0x330D;\n t['kashidaautoarabic'] = 0x0640;\n t['kashidaautonosidebearingarabic'] = 0x0640;\n t['kasmallkatakana'] = 0x30F5;\n t['kasquare'] = 0x3384;\n t['kasraarabic'] = 0x0650;\n t['kasratanarabic'] = 0x064D;\n t['kastrokecyrillic'] = 0x049F;\n t['katahiraprolongmarkhalfwidth'] = 0xFF70;\n t['kaverticalstrokecyrillic'] = 0x049D;\n t['kbopomofo'] = 0x310E;\n t['kcalsquare'] = 0x3389;\n t['kcaron'] = 0x01E9;\n t['kcedilla'] = 0x0137;\n t['kcircle'] = 0x24DA;\n t['kcommaaccent'] = 0x0137;\n t['kdotbelow'] = 0x1E33;\n t['keharmenian'] = 0x0584;\n t['kehiragana'] = 0x3051;\n t['kekatakana'] = 0x30B1;\n t['kekatakanahalfwidth'] = 0xFF79;\n t['kenarmenian'] = 0x056F;\n t['kesmallkatakana'] = 0x30F6;\n t['kgreenlandic'] = 0x0138;\n t['khabengali'] = 0x0996;\n t['khacyrillic'] = 0x0445;\n t['khadeva'] = 0x0916;\n t['khagujarati'] = 0x0A96;\n t['khagurmukhi'] = 0x0A16;\n t['khaharabic'] = 0x062E;\n t['khahfinalarabic'] = 0xFEA6;\n t['khahinitialarabic'] = 0xFEA7;\n t['khahmedialarabic'] = 0xFEA8;\n t['kheicoptic'] = 0x03E7;\n t['khhadeva'] = 0x0959;\n t['khhagurmukhi'] = 0x0A59;\n t['khieukhacirclekorean'] = 0x3278;\n t['khieukhaparenkorean'] = 0x3218;\n t['khieukhcirclekorean'] = 0x326A;\n t['khieukhkorean'] = 0x314B;\n t['khieukhparenkorean'] = 0x320A;\n t['khokhaithai'] = 0x0E02;\n t['khokhonthai'] = 0x0E05;\n t['khokhuatthai'] = 0x0E03;\n t['khokhwaithai'] = 0x0E04;\n t['khomutthai'] = 0x0E5B;\n t['khook'] = 0x0199;\n t['khorakhangthai'] = 0x0E06;\n t['khzsquare'] = 0x3391;\n t['kihiragana'] = 0x304D;\n t['kikatakana'] = 0x30AD;\n t['kikatakanahalfwidth'] = 0xFF77;\n t['kiroguramusquare'] = 0x3315;\n t['kiromeetorusquare'] = 0x3316;\n t['kirosquare'] = 0x3314;\n t['kiyeokacirclekorean'] = 0x326E;\n t['kiyeokaparenkorean'] = 0x320E;\n t['kiyeokcirclekorean'] = 0x3260;\n t['kiyeokkorean'] = 0x3131;\n t['kiyeokparenkorean'] = 0x3200;\n t['kiyeoksioskorean'] = 0x3133;\n t['kjecyrillic'] = 0x045C;\n t['klinebelow'] = 0x1E35;\n t['klsquare'] = 0x3398;\n t['kmcubedsquare'] = 0x33A6;\n t['kmonospace'] = 0xFF4B;\n t['kmsquaredsquare'] = 0x33A2;\n t['kohiragana'] = 0x3053;\n t['kohmsquare'] = 0x33C0;\n t['kokaithai'] = 0x0E01;\n t['kokatakana'] = 0x30B3;\n t['kokatakanahalfwidth'] = 0xFF7A;\n t['kooposquare'] = 0x331E;\n t['koppacyrillic'] = 0x0481;\n t['koreanstandardsymbol'] = 0x327F;\n t['koroniscmb'] = 0x0343;\n t['kparen'] = 0x24A6;\n t['kpasquare'] = 0x33AA;\n t['ksicyrillic'] = 0x046F;\n t['ktsquare'] = 0x33CF;\n t['kturned'] = 0x029E;\n t['kuhiragana'] = 0x304F;\n t['kukatakana'] = 0x30AF;\n t['kukatakanahalfwidth'] = 0xFF78;\n t['kvsquare'] = 0x33B8;\n t['kwsquare'] = 0x33BE;\n t['l'] = 0x006C;\n t['labengali'] = 0x09B2;\n t['lacute'] = 0x013A;\n t['ladeva'] = 0x0932;\n t['lagujarati'] = 0x0AB2;\n t['lagurmukhi'] = 0x0A32;\n t['lakkhangyaothai'] = 0x0E45;\n t['lamaleffinalarabic'] = 0xFEFC;\n t['lamalefhamzaabovefinalarabic'] = 0xFEF8;\n t['lamalefhamzaaboveisolatedarabic'] = 0xFEF7;\n t['lamalefhamzabelowfinalarabic'] = 0xFEFA;\n t['lamalefhamzabelowisolatedarabic'] = 0xFEF9;\n t['lamalefisolatedarabic'] = 0xFEFB;\n t['lamalefmaddaabovefinalarabic'] = 0xFEF6;\n t['lamalefmaddaaboveisolatedarabic'] = 0xFEF5;\n t['lamarabic'] = 0x0644;\n t['lambda'] = 0x03BB;\n t['lambdastroke'] = 0x019B;\n t['lamed'] = 0x05DC;\n t['lameddagesh'] = 0xFB3C;\n t['lameddageshhebrew'] = 0xFB3C;\n t['lamedhebrew'] = 0x05DC;\n t['lamfinalarabic'] = 0xFEDE;\n t['lamhahinitialarabic'] = 0xFCCA;\n t['laminitialarabic'] = 0xFEDF;\n t['lamjeeminitialarabic'] = 0xFCC9;\n t['lamkhahinitialarabic'] = 0xFCCB;\n t['lamlamhehisolatedarabic'] = 0xFDF2;\n t['lammedialarabic'] = 0xFEE0;\n t['lammeemhahinitialarabic'] = 0xFD88;\n t['lammeeminitialarabic'] = 0xFCCC;\n t['largecircle'] = 0x25EF;\n t['lbar'] = 0x019A;\n t['lbelt'] = 0x026C;\n t['lbopomofo'] = 0x310C;\n t['lcaron'] = 0x013E;\n t['lcedilla'] = 0x013C;\n t['lcircle'] = 0x24DB;\n t['lcircumflexbelow'] = 0x1E3D;\n t['lcommaaccent'] = 0x013C;\n t['ldot'] = 0x0140;\n t['ldotaccent'] = 0x0140;\n t['ldotbelow'] = 0x1E37;\n t['ldotbelowmacron'] = 0x1E39;\n t['leftangleabovecmb'] = 0x031A;\n t['lefttackbelowcmb'] = 0x0318;\n t['less'] = 0x003C;\n t['lessequal'] = 0x2264;\n t['lessequalorgreater'] = 0x22DA;\n t['lessmonospace'] = 0xFF1C;\n t['lessorequivalent'] = 0x2272;\n t['lessorgreater'] = 0x2276;\n t['lessoverequal'] = 0x2266;\n t['lesssmall'] = 0xFE64;\n t['lezh'] = 0x026E;\n t['lfblock'] = 0x258C;\n t['lhookretroflex'] = 0x026D;\n t['lira'] = 0x20A4;\n t['liwnarmenian'] = 0x056C;\n t['lj'] = 0x01C9;\n t['ljecyrillic'] = 0x0459;\n t['ll'] = 0xF6C0;\n t['lladeva'] = 0x0933;\n t['llagujarati'] = 0x0AB3;\n t['llinebelow'] = 0x1E3B;\n t['llladeva'] = 0x0934;\n t['llvocalicbengali'] = 0x09E1;\n t['llvocalicdeva'] = 0x0961;\n t['llvocalicvowelsignbengali'] = 0x09E3;\n t['llvocalicvowelsigndeva'] = 0x0963;\n t['lmiddletilde'] = 0x026B;\n t['lmonospace'] = 0xFF4C;\n t['lmsquare'] = 0x33D0;\n t['lochulathai'] = 0x0E2C;\n t['logicaland'] = 0x2227;\n t['logicalnot'] = 0x00AC;\n t['logicalnotreversed'] = 0x2310;\n t['logicalor'] = 0x2228;\n t['lolingthai'] = 0x0E25;\n t['longs'] = 0x017F;\n t['lowlinecenterline'] = 0xFE4E;\n t['lowlinecmb'] = 0x0332;\n t['lowlinedashed'] = 0xFE4D;\n t['lozenge'] = 0x25CA;\n t['lparen'] = 0x24A7;\n t['lslash'] = 0x0142;\n t['lsquare'] = 0x2113;\n t['lsuperior'] = 0xF6EE;\n t['ltshade'] = 0x2591;\n t['luthai'] = 0x0E26;\n t['lvocalicbengali'] = 0x098C;\n t['lvocalicdeva'] = 0x090C;\n t['lvocalicvowelsignbengali'] = 0x09E2;\n t['lvocalicvowelsigndeva'] = 0x0962;\n t['lxsquare'] = 0x33D3;\n t['m'] = 0x006D;\n t['mabengali'] = 0x09AE;\n t['macron'] = 0x00AF;\n t['macronbelowcmb'] = 0x0331;\n t['macroncmb'] = 0x0304;\n t['macronlowmod'] = 0x02CD;\n t['macronmonospace'] = 0xFFE3;\n t['macute'] = 0x1E3F;\n t['madeva'] = 0x092E;\n t['magujarati'] = 0x0AAE;\n t['magurmukhi'] = 0x0A2E;\n t['mahapakhhebrew'] = 0x05A4;\n t['mahapakhlefthebrew'] = 0x05A4;\n t['mahiragana'] = 0x307E;\n t['maichattawalowleftthai'] = 0xF895;\n t['maichattawalowrightthai'] = 0xF894;\n t['maichattawathai'] = 0x0E4B;\n t['maichattawaupperleftthai'] = 0xF893;\n t['maieklowleftthai'] = 0xF88C;\n t['maieklowrightthai'] = 0xF88B;\n t['maiekthai'] = 0x0E48;\n t['maiekupperleftthai'] = 0xF88A;\n t['maihanakatleftthai'] = 0xF884;\n t['maihanakatthai'] = 0x0E31;\n t['maitaikhuleftthai'] = 0xF889;\n t['maitaikhuthai'] = 0x0E47;\n t['maitholowleftthai'] = 0xF88F;\n t['maitholowrightthai'] = 0xF88E;\n t['maithothai'] = 0x0E49;\n t['maithoupperleftthai'] = 0xF88D;\n t['maitrilowleftthai'] = 0xF892;\n t['maitrilowrightthai'] = 0xF891;\n t['maitrithai'] = 0x0E4A;\n t['maitriupperleftthai'] = 0xF890;\n t['maiyamokthai'] = 0x0E46;\n t['makatakana'] = 0x30DE;\n t['makatakanahalfwidth'] = 0xFF8F;\n t['male'] = 0x2642;\n t['mansyonsquare'] = 0x3347;\n t['maqafhebrew'] = 0x05BE;\n t['mars'] = 0x2642;\n t['masoracirclehebrew'] = 0x05AF;\n t['masquare'] = 0x3383;\n t['mbopomofo'] = 0x3107;\n t['mbsquare'] = 0x33D4;\n t['mcircle'] = 0x24DC;\n t['mcubedsquare'] = 0x33A5;\n t['mdotaccent'] = 0x1E41;\n t['mdotbelow'] = 0x1E43;\n t['meemarabic'] = 0x0645;\n t['meemfinalarabic'] = 0xFEE2;\n t['meeminitialarabic'] = 0xFEE3;\n t['meemmedialarabic'] = 0xFEE4;\n t['meemmeeminitialarabic'] = 0xFCD1;\n t['meemmeemisolatedarabic'] = 0xFC48;\n t['meetorusquare'] = 0x334D;\n t['mehiragana'] = 0x3081;\n t['meizierasquare'] = 0x337E;\n t['mekatakana'] = 0x30E1;\n t['mekatakanahalfwidth'] = 0xFF92;\n t['mem'] = 0x05DE;\n t['memdagesh'] = 0xFB3E;\n t['memdageshhebrew'] = 0xFB3E;\n t['memhebrew'] = 0x05DE;\n t['menarmenian'] = 0x0574;\n t['merkhahebrew'] = 0x05A5;\n t['merkhakefulahebrew'] = 0x05A6;\n t['merkhakefulalefthebrew'] = 0x05A6;\n t['merkhalefthebrew'] = 0x05A5;\n t['mhook'] = 0x0271;\n t['mhzsquare'] = 0x3392;\n t['middledotkatakanahalfwidth'] = 0xFF65;\n t['middot'] = 0x00B7;\n t['mieumacirclekorean'] = 0x3272;\n t['mieumaparenkorean'] = 0x3212;\n t['mieumcirclekorean'] = 0x3264;\n t['mieumkorean'] = 0x3141;\n t['mieumpansioskorean'] = 0x3170;\n t['mieumparenkorean'] = 0x3204;\n t['mieumpieupkorean'] = 0x316E;\n t['mieumsioskorean'] = 0x316F;\n t['mihiragana'] = 0x307F;\n t['mikatakana'] = 0x30DF;\n t['mikatakanahalfwidth'] = 0xFF90;\n t['minus'] = 0x2212;\n t['minusbelowcmb'] = 0x0320;\n t['minuscircle'] = 0x2296;\n t['minusmod'] = 0x02D7;\n t['minusplus'] = 0x2213;\n t['minute'] = 0x2032;\n t['miribaarusquare'] = 0x334A;\n t['mirisquare'] = 0x3349;\n t['mlonglegturned'] = 0x0270;\n t['mlsquare'] = 0x3396;\n t['mmcubedsquare'] = 0x33A3;\n t['mmonospace'] = 0xFF4D;\n t['mmsquaredsquare'] = 0x339F;\n t['mohiragana'] = 0x3082;\n t['mohmsquare'] = 0x33C1;\n t['mokatakana'] = 0x30E2;\n t['mokatakanahalfwidth'] = 0xFF93;\n t['molsquare'] = 0x33D6;\n t['momathai'] = 0x0E21;\n t['moverssquare'] = 0x33A7;\n t['moverssquaredsquare'] = 0x33A8;\n t['mparen'] = 0x24A8;\n t['mpasquare'] = 0x33AB;\n t['mssquare'] = 0x33B3;\n t['msuperior'] = 0xF6EF;\n t['mturned'] = 0x026F;\n t['mu'] = 0x00B5;\n t['mu1'] = 0x00B5;\n t['muasquare'] = 0x3382;\n t['muchgreater'] = 0x226B;\n t['muchless'] = 0x226A;\n t['mufsquare'] = 0x338C;\n t['mugreek'] = 0x03BC;\n t['mugsquare'] = 0x338D;\n t['muhiragana'] = 0x3080;\n t['mukatakana'] = 0x30E0;\n t['mukatakanahalfwidth'] = 0xFF91;\n t['mulsquare'] = 0x3395;\n t['multiply'] = 0x00D7;\n t['mumsquare'] = 0x339B;\n t['munahhebrew'] = 0x05A3;\n t['munahlefthebrew'] = 0x05A3;\n t['musicalnote'] = 0x266A;\n t['musicalnotedbl'] = 0x266B;\n t['musicflatsign'] = 0x266D;\n t['musicsharpsign'] = 0x266F;\n t['mussquare'] = 0x33B2;\n t['muvsquare'] = 0x33B6;\n t['muwsquare'] = 0x33BC;\n t['mvmegasquare'] = 0x33B9;\n t['mvsquare'] = 0x33B7;\n t['mwmegasquare'] = 0x33BF;\n t['mwsquare'] = 0x33BD;\n t['n'] = 0x006E;\n t['nabengali'] = 0x09A8;\n t['nabla'] = 0x2207;\n t['nacute'] = 0x0144;\n t['nadeva'] = 0x0928;\n t['nagujarati'] = 0x0AA8;\n t['nagurmukhi'] = 0x0A28;\n t['nahiragana'] = 0x306A;\n t['nakatakana'] = 0x30CA;\n t['nakatakanahalfwidth'] = 0xFF85;\n t['napostrophe'] = 0x0149;\n t['nasquare'] = 0x3381;\n t['nbopomofo'] = 0x310B;\n t['nbspace'] = 0x00A0;\n t['ncaron'] = 0x0148;\n t['ncedilla'] = 0x0146;\n t['ncircle'] = 0x24DD;\n t['ncircumflexbelow'] = 0x1E4B;\n t['ncommaaccent'] = 0x0146;\n t['ndotaccent'] = 0x1E45;\n t['ndotbelow'] = 0x1E47;\n t['nehiragana'] = 0x306D;\n t['nekatakana'] = 0x30CD;\n t['nekatakanahalfwidth'] = 0xFF88;\n t['newsheqelsign'] = 0x20AA;\n t['nfsquare'] = 0x338B;\n t['ngabengali'] = 0x0999;\n t['ngadeva'] = 0x0919;\n t['ngagujarati'] = 0x0A99;\n t['ngagurmukhi'] = 0x0A19;\n t['ngonguthai'] = 0x0E07;\n t['nhiragana'] = 0x3093;\n t['nhookleft'] = 0x0272;\n t['nhookretroflex'] = 0x0273;\n t['nieunacirclekorean'] = 0x326F;\n t['nieunaparenkorean'] = 0x320F;\n t['nieuncieuckorean'] = 0x3135;\n t['nieuncirclekorean'] = 0x3261;\n t['nieunhieuhkorean'] = 0x3136;\n t['nieunkorean'] = 0x3134;\n t['nieunpansioskorean'] = 0x3168;\n t['nieunparenkorean'] = 0x3201;\n t['nieunsioskorean'] = 0x3167;\n t['nieuntikeutkorean'] = 0x3166;\n t['nihiragana'] = 0x306B;\n t['nikatakana'] = 0x30CB;\n t['nikatakanahalfwidth'] = 0xFF86;\n t['nikhahitleftthai'] = 0xF899;\n t['nikhahitthai'] = 0x0E4D;\n t['nine'] = 0x0039;\n t['ninearabic'] = 0x0669;\n t['ninebengali'] = 0x09EF;\n t['ninecircle'] = 0x2468;\n t['ninecircleinversesansserif'] = 0x2792;\n t['ninedeva'] = 0x096F;\n t['ninegujarati'] = 0x0AEF;\n t['ninegurmukhi'] = 0x0A6F;\n t['ninehackarabic'] = 0x0669;\n t['ninehangzhou'] = 0x3029;\n t['nineideographicparen'] = 0x3228;\n t['nineinferior'] = 0x2089;\n t['ninemonospace'] = 0xFF19;\n t['nineoldstyle'] = 0xF739;\n t['nineparen'] = 0x247C;\n t['nineperiod'] = 0x2490;\n t['ninepersian'] = 0x06F9;\n t['nineroman'] = 0x2178;\n t['ninesuperior'] = 0x2079;\n t['nineteencircle'] = 0x2472;\n t['nineteenparen'] = 0x2486;\n t['nineteenperiod'] = 0x249A;\n t['ninethai'] = 0x0E59;\n t['nj'] = 0x01CC;\n t['njecyrillic'] = 0x045A;\n t['nkatakana'] = 0x30F3;\n t['nkatakanahalfwidth'] = 0xFF9D;\n t['nlegrightlong'] = 0x019E;\n t['nlinebelow'] = 0x1E49;\n t['nmonospace'] = 0xFF4E;\n t['nmsquare'] = 0x339A;\n t['nnabengali'] = 0x09A3;\n t['nnadeva'] = 0x0923;\n t['nnagujarati'] = 0x0AA3;\n t['nnagurmukhi'] = 0x0A23;\n t['nnnadeva'] = 0x0929;\n t['nohiragana'] = 0x306E;\n t['nokatakana'] = 0x30CE;\n t['nokatakanahalfwidth'] = 0xFF89;\n t['nonbreakingspace'] = 0x00A0;\n t['nonenthai'] = 0x0E13;\n t['nonuthai'] = 0x0E19;\n t['noonarabic'] = 0x0646;\n t['noonfinalarabic'] = 0xFEE6;\n t['noonghunnaarabic'] = 0x06BA;\n t['noonghunnafinalarabic'] = 0xFB9F;\n t['nooninitialarabic'] = 0xFEE7;\n t['noonjeeminitialarabic'] = 0xFCD2;\n t['noonjeemisolatedarabic'] = 0xFC4B;\n t['noonmedialarabic'] = 0xFEE8;\n t['noonmeeminitialarabic'] = 0xFCD5;\n t['noonmeemisolatedarabic'] = 0xFC4E;\n t['noonnoonfinalarabic'] = 0xFC8D;\n t['notcontains'] = 0x220C;\n t['notelement'] = 0x2209;\n t['notelementof'] = 0x2209;\n t['notequal'] = 0x2260;\n t['notgreater'] = 0x226F;\n t['notgreaternorequal'] = 0x2271;\n t['notgreaternorless'] = 0x2279;\n t['notidentical'] = 0x2262;\n t['notless'] = 0x226E;\n t['notlessnorequal'] = 0x2270;\n t['notparallel'] = 0x2226;\n t['notprecedes'] = 0x2280;\n t['notsubset'] = 0x2284;\n t['notsucceeds'] = 0x2281;\n t['notsuperset'] = 0x2285;\n t['nowarmenian'] = 0x0576;\n t['nparen'] = 0x24A9;\n t['nssquare'] = 0x33B1;\n t['nsuperior'] = 0x207F;\n t['ntilde'] = 0x00F1;\n t['nu'] = 0x03BD;\n t['nuhiragana'] = 0x306C;\n t['nukatakana'] = 0x30CC;\n t['nukatakanahalfwidth'] = 0xFF87;\n t['nuktabengali'] = 0x09BC;\n t['nuktadeva'] = 0x093C;\n t['nuktagujarati'] = 0x0ABC;\n t['nuktagurmukhi'] = 0x0A3C;\n t['numbersign'] = 0x0023;\n t['numbersignmonospace'] = 0xFF03;\n t['numbersignsmall'] = 0xFE5F;\n t['numeralsigngreek'] = 0x0374;\n t['numeralsignlowergreek'] = 0x0375;\n t['numero'] = 0x2116;\n t['nun'] = 0x05E0;\n t['nundagesh'] = 0xFB40;\n t['nundageshhebrew'] = 0xFB40;\n t['nunhebrew'] = 0x05E0;\n t['nvsquare'] = 0x33B5;\n t['nwsquare'] = 0x33BB;\n t['nyabengali'] = 0x099E;\n t['nyadeva'] = 0x091E;\n t['nyagujarati'] = 0x0A9E;\n t['nyagurmukhi'] = 0x0A1E;\n t['o'] = 0x006F;\n t['oacute'] = 0x00F3;\n t['oangthai'] = 0x0E2D;\n t['obarred'] = 0x0275;\n t['obarredcyrillic'] = 0x04E9;\n t['obarreddieresiscyrillic'] = 0x04EB;\n t['obengali'] = 0x0993;\n t['obopomofo'] = 0x311B;\n t['obreve'] = 0x014F;\n t['ocandradeva'] = 0x0911;\n t['ocandragujarati'] = 0x0A91;\n t['ocandravowelsigndeva'] = 0x0949;\n t['ocandravowelsigngujarati'] = 0x0AC9;\n t['ocaron'] = 0x01D2;\n t['ocircle'] = 0x24DE;\n t['ocircumflex'] = 0x00F4;\n t['ocircumflexacute'] = 0x1ED1;\n t['ocircumflexdotbelow'] = 0x1ED9;\n t['ocircumflexgrave'] = 0x1ED3;\n t['ocircumflexhookabove'] = 0x1ED5;\n t['ocircumflextilde'] = 0x1ED7;\n t['ocyrillic'] = 0x043E;\n t['odblacute'] = 0x0151;\n t['odblgrave'] = 0x020D;\n t['odeva'] = 0x0913;\n t['odieresis'] = 0x00F6;\n t['odieresiscyrillic'] = 0x04E7;\n t['odotbelow'] = 0x1ECD;\n t['oe'] = 0x0153;\n t['oekorean'] = 0x315A;\n t['ogonek'] = 0x02DB;\n t['ogonekcmb'] = 0x0328;\n t['ograve'] = 0x00F2;\n t['ogujarati'] = 0x0A93;\n t['oharmenian'] = 0x0585;\n t['ohiragana'] = 0x304A;\n t['ohookabove'] = 0x1ECF;\n t['ohorn'] = 0x01A1;\n t['ohornacute'] = 0x1EDB;\n t['ohorndotbelow'] = 0x1EE3;\n t['ohorngrave'] = 0x1EDD;\n t['ohornhookabove'] = 0x1EDF;\n t['ohorntilde'] = 0x1EE1;\n t['ohungarumlaut'] = 0x0151;\n t['oi'] = 0x01A3;\n t['oinvertedbreve'] = 0x020F;\n t['okatakana'] = 0x30AA;\n t['okatakanahalfwidth'] = 0xFF75;\n t['okorean'] = 0x3157;\n t['olehebrew'] = 0x05AB;\n t['omacron'] = 0x014D;\n t['omacronacute'] = 0x1E53;\n t['omacrongrave'] = 0x1E51;\n t['omdeva'] = 0x0950;\n t['omega'] = 0x03C9;\n t['omega1'] = 0x03D6;\n t['omegacyrillic'] = 0x0461;\n t['omegalatinclosed'] = 0x0277;\n t['omegaroundcyrillic'] = 0x047B;\n t['omegatitlocyrillic'] = 0x047D;\n t['omegatonos'] = 0x03CE;\n t['omgujarati'] = 0x0AD0;\n t['omicron'] = 0x03BF;\n t['omicrontonos'] = 0x03CC;\n t['omonospace'] = 0xFF4F;\n t['one'] = 0x0031;\n t['onearabic'] = 0x0661;\n t['onebengali'] = 0x09E7;\n t['onecircle'] = 0x2460;\n t['onecircleinversesansserif'] = 0x278A;\n t['onedeva'] = 0x0967;\n t['onedotenleader'] = 0x2024;\n t['oneeighth'] = 0x215B;\n t['onefitted'] = 0xF6DC;\n t['onegujarati'] = 0x0AE7;\n t['onegurmukhi'] = 0x0A67;\n t['onehackarabic'] = 0x0661;\n t['onehalf'] = 0x00BD;\n t['onehangzhou'] = 0x3021;\n t['oneideographicparen'] = 0x3220;\n t['oneinferior'] = 0x2081;\n t['onemonospace'] = 0xFF11;\n t['onenumeratorbengali'] = 0x09F4;\n t['oneoldstyle'] = 0xF731;\n t['oneparen'] = 0x2474;\n t['oneperiod'] = 0x2488;\n t['onepersian'] = 0x06F1;\n t['onequarter'] = 0x00BC;\n t['oneroman'] = 0x2170;\n t['onesuperior'] = 0x00B9;\n t['onethai'] = 0x0E51;\n t['onethird'] = 0x2153;\n t['oogonek'] = 0x01EB;\n t['oogonekmacron'] = 0x01ED;\n t['oogurmukhi'] = 0x0A13;\n t['oomatragurmukhi'] = 0x0A4B;\n t['oopen'] = 0x0254;\n t['oparen'] = 0x24AA;\n t['openbullet'] = 0x25E6;\n t['option'] = 0x2325;\n t['ordfeminine'] = 0x00AA;\n t['ordmasculine'] = 0x00BA;\n t['orthogonal'] = 0x221F;\n t['oshortdeva'] = 0x0912;\n t['oshortvowelsigndeva'] = 0x094A;\n t['oslash'] = 0x00F8;\n t['oslashacute'] = 0x01FF;\n t['osmallhiragana'] = 0x3049;\n t['osmallkatakana'] = 0x30A9;\n t['osmallkatakanahalfwidth'] = 0xFF6B;\n t['ostrokeacute'] = 0x01FF;\n t['osuperior'] = 0xF6F0;\n t['otcyrillic'] = 0x047F;\n t['otilde'] = 0x00F5;\n t['otildeacute'] = 0x1E4D;\n t['otildedieresis'] = 0x1E4F;\n t['oubopomofo'] = 0x3121;\n t['overline'] = 0x203E;\n t['overlinecenterline'] = 0xFE4A;\n t['overlinecmb'] = 0x0305;\n t['overlinedashed'] = 0xFE49;\n t['overlinedblwavy'] = 0xFE4C;\n t['overlinewavy'] = 0xFE4B;\n t['overscore'] = 0x00AF;\n t['ovowelsignbengali'] = 0x09CB;\n t['ovowelsigndeva'] = 0x094B;\n t['ovowelsigngujarati'] = 0x0ACB;\n t['p'] = 0x0070;\n t['paampssquare'] = 0x3380;\n t['paasentosquare'] = 0x332B;\n t['pabengali'] = 0x09AA;\n t['pacute'] = 0x1E55;\n t['padeva'] = 0x092A;\n t['pagedown'] = 0x21DF;\n t['pageup'] = 0x21DE;\n t['pagujarati'] = 0x0AAA;\n t['pagurmukhi'] = 0x0A2A;\n t['pahiragana'] = 0x3071;\n t['paiyannoithai'] = 0x0E2F;\n t['pakatakana'] = 0x30D1;\n t['palatalizationcyrilliccmb'] = 0x0484;\n t['palochkacyrillic'] = 0x04C0;\n t['pansioskorean'] = 0x317F;\n t['paragraph'] = 0x00B6;\n t['parallel'] = 0x2225;\n t['parenleft'] = 0x0028;\n t['parenleftaltonearabic'] = 0xFD3E;\n t['parenleftbt'] = 0xF8ED;\n t['parenleftex'] = 0xF8EC;\n t['parenleftinferior'] = 0x208D;\n t['parenleftmonospace'] = 0xFF08;\n t['parenleftsmall'] = 0xFE59;\n t['parenleftsuperior'] = 0x207D;\n t['parenlefttp'] = 0xF8EB;\n t['parenleftvertical'] = 0xFE35;\n t['parenright'] = 0x0029;\n t['parenrightaltonearabic'] = 0xFD3F;\n t['parenrightbt'] = 0xF8F8;\n t['parenrightex'] = 0xF8F7;\n t['parenrightinferior'] = 0x208E;\n t['parenrightmonospace'] = 0xFF09;\n t['parenrightsmall'] = 0xFE5A;\n t['parenrightsuperior'] = 0x207E;\n t['parenrighttp'] = 0xF8F6;\n t['parenrightvertical'] = 0xFE36;\n t['partialdiff'] = 0x2202;\n t['paseqhebrew'] = 0x05C0;\n t['pashtahebrew'] = 0x0599;\n t['pasquare'] = 0x33A9;\n t['patah'] = 0x05B7;\n t['patah11'] = 0x05B7;\n t['patah1d'] = 0x05B7;\n t['patah2a'] = 0x05B7;\n t['patahhebrew'] = 0x05B7;\n t['patahnarrowhebrew'] = 0x05B7;\n t['patahquarterhebrew'] = 0x05B7;\n t['patahwidehebrew'] = 0x05B7;\n t['pazerhebrew'] = 0x05A1;\n t['pbopomofo'] = 0x3106;\n t['pcircle'] = 0x24DF;\n t['pdotaccent'] = 0x1E57;\n t['pe'] = 0x05E4;\n t['pecyrillic'] = 0x043F;\n t['pedagesh'] = 0xFB44;\n t['pedageshhebrew'] = 0xFB44;\n t['peezisquare'] = 0x333B;\n t['pefinaldageshhebrew'] = 0xFB43;\n t['peharabic'] = 0x067E;\n t['peharmenian'] = 0x057A;\n t['pehebrew'] = 0x05E4;\n t['pehfinalarabic'] = 0xFB57;\n t['pehinitialarabic'] = 0xFB58;\n t['pehiragana'] = 0x307A;\n t['pehmedialarabic'] = 0xFB59;\n t['pekatakana'] = 0x30DA;\n t['pemiddlehookcyrillic'] = 0x04A7;\n t['perafehebrew'] = 0xFB4E;\n t['percent'] = 0x0025;\n t['percentarabic'] = 0x066A;\n t['percentmonospace'] = 0xFF05;\n t['percentsmall'] = 0xFE6A;\n t['period'] = 0x002E;\n t['periodarmenian'] = 0x0589;\n t['periodcentered'] = 0x00B7;\n t['periodhalfwidth'] = 0xFF61;\n t['periodinferior'] = 0xF6E7;\n t['periodmonospace'] = 0xFF0E;\n t['periodsmall'] = 0xFE52;\n t['periodsuperior'] = 0xF6E8;\n t['perispomenigreekcmb'] = 0x0342;\n t['perpendicular'] = 0x22A5;\n t['perthousand'] = 0x2030;\n t['peseta'] = 0x20A7;\n t['pfsquare'] = 0x338A;\n t['phabengali'] = 0x09AB;\n t['phadeva'] = 0x092B;\n t['phagujarati'] = 0x0AAB;\n t['phagurmukhi'] = 0x0A2B;\n t['phi'] = 0x03C6;\n t['phi1'] = 0x03D5;\n t['phieuphacirclekorean'] = 0x327A;\n t['phieuphaparenkorean'] = 0x321A;\n t['phieuphcirclekorean'] = 0x326C;\n t['phieuphkorean'] = 0x314D;\n t['phieuphparenkorean'] = 0x320C;\n t['philatin'] = 0x0278;\n t['phinthuthai'] = 0x0E3A;\n t['phisymbolgreek'] = 0x03D5;\n t['phook'] = 0x01A5;\n t['phophanthai'] = 0x0E1E;\n t['phophungthai'] = 0x0E1C;\n t['phosamphaothai'] = 0x0E20;\n t['pi'] = 0x03C0;\n t['pieupacirclekorean'] = 0x3273;\n t['pieupaparenkorean'] = 0x3213;\n t['pieupcieuckorean'] = 0x3176;\n t['pieupcirclekorean'] = 0x3265;\n t['pieupkiyeokkorean'] = 0x3172;\n t['pieupkorean'] = 0x3142;\n t['pieupparenkorean'] = 0x3205;\n t['pieupsioskiyeokkorean'] = 0x3174;\n t['pieupsioskorean'] = 0x3144;\n t['pieupsiostikeutkorean'] = 0x3175;\n t['pieupthieuthkorean'] = 0x3177;\n t['pieuptikeutkorean'] = 0x3173;\n t['pihiragana'] = 0x3074;\n t['pikatakana'] = 0x30D4;\n t['pisymbolgreek'] = 0x03D6;\n t['piwrarmenian'] = 0x0583;\n t['plus'] = 0x002B;\n t['plusbelowcmb'] = 0x031F;\n t['pluscircle'] = 0x2295;\n t['plusminus'] = 0x00B1;\n t['plusmod'] = 0x02D6;\n t['plusmonospace'] = 0xFF0B;\n t['plussmall'] = 0xFE62;\n t['plussuperior'] = 0x207A;\n t['pmonospace'] = 0xFF50;\n t['pmsquare'] = 0x33D8;\n t['pohiragana'] = 0x307D;\n t['pointingindexdownwhite'] = 0x261F;\n t['pointingindexleftwhite'] = 0x261C;\n t['pointingindexrightwhite'] = 0x261E;\n t['pointingindexupwhite'] = 0x261D;\n t['pokatakana'] = 0x30DD;\n t['poplathai'] = 0x0E1B;\n t['postalmark'] = 0x3012;\n t['postalmarkface'] = 0x3020;\n t['pparen'] = 0x24AB;\n t['precedes'] = 0x227A;\n t['prescription'] = 0x211E;\n t['primemod'] = 0x02B9;\n t['primereversed'] = 0x2035;\n t['product'] = 0x220F;\n t['projective'] = 0x2305;\n t['prolongedkana'] = 0x30FC;\n t['propellor'] = 0x2318;\n t['propersubset'] = 0x2282;\n t['propersuperset'] = 0x2283;\n t['proportion'] = 0x2237;\n t['proportional'] = 0x221D;\n t['psi'] = 0x03C8;\n t['psicyrillic'] = 0x0471;\n t['psilipneumatacyrilliccmb'] = 0x0486;\n t['pssquare'] = 0x33B0;\n t['puhiragana'] = 0x3077;\n t['pukatakana'] = 0x30D7;\n t['pvsquare'] = 0x33B4;\n t['pwsquare'] = 0x33BA;\n t['q'] = 0x0071;\n t['qadeva'] = 0x0958;\n t['qadmahebrew'] = 0x05A8;\n t['qafarabic'] = 0x0642;\n t['qaffinalarabic'] = 0xFED6;\n t['qafinitialarabic'] = 0xFED7;\n t['qafmedialarabic'] = 0xFED8;\n t['qamats'] = 0x05B8;\n t['qamats10'] = 0x05B8;\n t['qamats1a'] = 0x05B8;\n t['qamats1c'] = 0x05B8;\n t['qamats27'] = 0x05B8;\n t['qamats29'] = 0x05B8;\n t['qamats33'] = 0x05B8;\n t['qamatsde'] = 0x05B8;\n t['qamatshebrew'] = 0x05B8;\n t['qamatsnarrowhebrew'] = 0x05B8;\n t['qamatsqatanhebrew'] = 0x05B8;\n t['qamatsqatannarrowhebrew'] = 0x05B8;\n t['qamatsqatanquarterhebrew'] = 0x05B8;\n t['qamatsqatanwidehebrew'] = 0x05B8;\n t['qamatsquarterhebrew'] = 0x05B8;\n t['qamatswidehebrew'] = 0x05B8;\n t['qarneyparahebrew'] = 0x059F;\n t['qbopomofo'] = 0x3111;\n t['qcircle'] = 0x24E0;\n t['qhook'] = 0x02A0;\n t['qmonospace'] = 0xFF51;\n t['qof'] = 0x05E7;\n t['qofdagesh'] = 0xFB47;\n t['qofdageshhebrew'] = 0xFB47;\n t['qofhebrew'] = 0x05E7;\n t['qparen'] = 0x24AC;\n t['quarternote'] = 0x2669;\n t['qubuts'] = 0x05BB;\n t['qubuts18'] = 0x05BB;\n t['qubuts25'] = 0x05BB;\n t['qubuts31'] = 0x05BB;\n t['qubutshebrew'] = 0x05BB;\n t['qubutsnarrowhebrew'] = 0x05BB;\n t['qubutsquarterhebrew'] = 0x05BB;\n t['qubutswidehebrew'] = 0x05BB;\n t['question'] = 0x003F;\n t['questionarabic'] = 0x061F;\n t['questionarmenian'] = 0x055E;\n t['questiondown'] = 0x00BF;\n t['questiondownsmall'] = 0xF7BF;\n t['questiongreek'] = 0x037E;\n t['questionmonospace'] = 0xFF1F;\n t['questionsmall'] = 0xF73F;\n t['quotedbl'] = 0x0022;\n t['quotedblbase'] = 0x201E;\n t['quotedblleft'] = 0x201C;\n t['quotedblmonospace'] = 0xFF02;\n t['quotedblprime'] = 0x301E;\n t['quotedblprimereversed'] = 0x301D;\n t['quotedblright'] = 0x201D;\n t['quoteleft'] = 0x2018;\n t['quoteleftreversed'] = 0x201B;\n t['quotereversed'] = 0x201B;\n t['quoteright'] = 0x2019;\n t['quoterightn'] = 0x0149;\n t['quotesinglbase'] = 0x201A;\n t['quotesingle'] = 0x0027;\n t['quotesinglemonospace'] = 0xFF07;\n t['r'] = 0x0072;\n t['raarmenian'] = 0x057C;\n t['rabengali'] = 0x09B0;\n t['racute'] = 0x0155;\n t['radeva'] = 0x0930;\n t['radical'] = 0x221A;\n t['radicalex'] = 0xF8E5;\n t['radoverssquare'] = 0x33AE;\n t['radoverssquaredsquare'] = 0x33AF;\n t['radsquare'] = 0x33AD;\n t['rafe'] = 0x05BF;\n t['rafehebrew'] = 0x05BF;\n t['ragujarati'] = 0x0AB0;\n t['ragurmukhi'] = 0x0A30;\n t['rahiragana'] = 0x3089;\n t['rakatakana'] = 0x30E9;\n t['rakatakanahalfwidth'] = 0xFF97;\n t['ralowerdiagonalbengali'] = 0x09F1;\n t['ramiddlediagonalbengali'] = 0x09F0;\n t['ramshorn'] = 0x0264;\n t['ratio'] = 0x2236;\n t['rbopomofo'] = 0x3116;\n t['rcaron'] = 0x0159;\n t['rcedilla'] = 0x0157;\n t['rcircle'] = 0x24E1;\n t['rcommaaccent'] = 0x0157;\n t['rdblgrave'] = 0x0211;\n t['rdotaccent'] = 0x1E59;\n t['rdotbelow'] = 0x1E5B;\n t['rdotbelowmacron'] = 0x1E5D;\n t['referencemark'] = 0x203B;\n t['reflexsubset'] = 0x2286;\n t['reflexsuperset'] = 0x2287;\n t['registered'] = 0x00AE;\n t['registersans'] = 0xF8E8;\n t['registerserif'] = 0xF6DA;\n t['reharabic'] = 0x0631;\n t['reharmenian'] = 0x0580;\n t['rehfinalarabic'] = 0xFEAE;\n t['rehiragana'] = 0x308C;\n t['rekatakana'] = 0x30EC;\n t['rekatakanahalfwidth'] = 0xFF9A;\n t['resh'] = 0x05E8;\n t['reshdageshhebrew'] = 0xFB48;\n t['reshhebrew'] = 0x05E8;\n t['reversedtilde'] = 0x223D;\n t['reviahebrew'] = 0x0597;\n t['reviamugrashhebrew'] = 0x0597;\n t['revlogicalnot'] = 0x2310;\n t['rfishhook'] = 0x027E;\n t['rfishhookreversed'] = 0x027F;\n t['rhabengali'] = 0x09DD;\n t['rhadeva'] = 0x095D;\n t['rho'] = 0x03C1;\n t['rhook'] = 0x027D;\n t['rhookturned'] = 0x027B;\n t['rhookturnedsuperior'] = 0x02B5;\n t['rhosymbolgreek'] = 0x03F1;\n t['rhotichookmod'] = 0x02DE;\n t['rieulacirclekorean'] = 0x3271;\n t['rieulaparenkorean'] = 0x3211;\n t['rieulcirclekorean'] = 0x3263;\n t['rieulhieuhkorean'] = 0x3140;\n t['rieulkiyeokkorean'] = 0x313A;\n t['rieulkiyeoksioskorean'] = 0x3169;\n t['rieulkorean'] = 0x3139;\n t['rieulmieumkorean'] = 0x313B;\n t['rieulpansioskorean'] = 0x316C;\n t['rieulparenkorean'] = 0x3203;\n t['rieulphieuphkorean'] = 0x313F;\n t['rieulpieupkorean'] = 0x313C;\n t['rieulpieupsioskorean'] = 0x316B;\n t['rieulsioskorean'] = 0x313D;\n t['rieulthieuthkorean'] = 0x313E;\n t['rieultikeutkorean'] = 0x316A;\n t['rieulyeorinhieuhkorean'] = 0x316D;\n t['rightangle'] = 0x221F;\n t['righttackbelowcmb'] = 0x0319;\n t['righttriangle'] = 0x22BF;\n t['rihiragana'] = 0x308A;\n t['rikatakana'] = 0x30EA;\n t['rikatakanahalfwidth'] = 0xFF98;\n t['ring'] = 0x02DA;\n t['ringbelowcmb'] = 0x0325;\n t['ringcmb'] = 0x030A;\n t['ringhalfleft'] = 0x02BF;\n t['ringhalfleftarmenian'] = 0x0559;\n t['ringhalfleftbelowcmb'] = 0x031C;\n t['ringhalfleftcentered'] = 0x02D3;\n t['ringhalfright'] = 0x02BE;\n t['ringhalfrightbelowcmb'] = 0x0339;\n t['ringhalfrightcentered'] = 0x02D2;\n t['rinvertedbreve'] = 0x0213;\n t['rittorusquare'] = 0x3351;\n t['rlinebelow'] = 0x1E5F;\n t['rlongleg'] = 0x027C;\n t['rlonglegturned'] = 0x027A;\n t['rmonospace'] = 0xFF52;\n t['rohiragana'] = 0x308D;\n t['rokatakana'] = 0x30ED;\n t['rokatakanahalfwidth'] = 0xFF9B;\n t['roruathai'] = 0x0E23;\n t['rparen'] = 0x24AD;\n t['rrabengali'] = 0x09DC;\n t['rradeva'] = 0x0931;\n t['rragurmukhi'] = 0x0A5C;\n t['rreharabic'] = 0x0691;\n t['rrehfinalarabic'] = 0xFB8D;\n t['rrvocalicbengali'] = 0x09E0;\n t['rrvocalicdeva'] = 0x0960;\n t['rrvocalicgujarati'] = 0x0AE0;\n t['rrvocalicvowelsignbengali'] = 0x09C4;\n t['rrvocalicvowelsigndeva'] = 0x0944;\n t['rrvocalicvowelsigngujarati'] = 0x0AC4;\n t['rsuperior'] = 0xF6F1;\n t['rtblock'] = 0x2590;\n t['rturned'] = 0x0279;\n t['rturnedsuperior'] = 0x02B4;\n t['ruhiragana'] = 0x308B;\n t['rukatakana'] = 0x30EB;\n t['rukatakanahalfwidth'] = 0xFF99;\n t['rupeemarkbengali'] = 0x09F2;\n t['rupeesignbengali'] = 0x09F3;\n t['rupiah'] = 0xF6DD;\n t['ruthai'] = 0x0E24;\n t['rvocalicbengali'] = 0x098B;\n t['rvocalicdeva'] = 0x090B;\n t['rvocalicgujarati'] = 0x0A8B;\n t['rvocalicvowelsignbengali'] = 0x09C3;\n t['rvocalicvowelsigndeva'] = 0x0943;\n t['rvocalicvowelsigngujarati'] = 0x0AC3;\n t['s'] = 0x0073;\n t['sabengali'] = 0x09B8;\n t['sacute'] = 0x015B;\n t['sacutedotaccent'] = 0x1E65;\n t['sadarabic'] = 0x0635;\n t['sadeva'] = 0x0938;\n t['sadfinalarabic'] = 0xFEBA;\n t['sadinitialarabic'] = 0xFEBB;\n t['sadmedialarabic'] = 0xFEBC;\n t['sagujarati'] = 0x0AB8;\n t['sagurmukhi'] = 0x0A38;\n t['sahiragana'] = 0x3055;\n t['sakatakana'] = 0x30B5;\n t['sakatakanahalfwidth'] = 0xFF7B;\n t['sallallahoualayhewasallamarabic'] = 0xFDFA;\n t['samekh'] = 0x05E1;\n t['samekhdagesh'] = 0xFB41;\n t['samekhdageshhebrew'] = 0xFB41;\n t['samekhhebrew'] = 0x05E1;\n t['saraaathai'] = 0x0E32;\n t['saraaethai'] = 0x0E41;\n t['saraaimaimalaithai'] = 0x0E44;\n t['saraaimaimuanthai'] = 0x0E43;\n t['saraamthai'] = 0x0E33;\n t['saraathai'] = 0x0E30;\n t['saraethai'] = 0x0E40;\n t['saraiileftthai'] = 0xF886;\n t['saraiithai'] = 0x0E35;\n t['saraileftthai'] = 0xF885;\n t['saraithai'] = 0x0E34;\n t['saraothai'] = 0x0E42;\n t['saraueeleftthai'] = 0xF888;\n t['saraueethai'] = 0x0E37;\n t['saraueleftthai'] = 0xF887;\n t['sarauethai'] = 0x0E36;\n t['sarauthai'] = 0x0E38;\n t['sarauuthai'] = 0x0E39;\n t['sbopomofo'] = 0x3119;\n t['scaron'] = 0x0161;\n t['scarondotaccent'] = 0x1E67;\n t['scedilla'] = 0x015F;\n t['schwa'] = 0x0259;\n t['schwacyrillic'] = 0x04D9;\n t['schwadieresiscyrillic'] = 0x04DB;\n t['schwahook'] = 0x025A;\n t['scircle'] = 0x24E2;\n t['scircumflex'] = 0x015D;\n t['scommaaccent'] = 0x0219;\n t['sdotaccent'] = 0x1E61;\n t['sdotbelow'] = 0x1E63;\n t['sdotbelowdotaccent'] = 0x1E69;\n t['seagullbelowcmb'] = 0x033C;\n t['second'] = 0x2033;\n t['secondtonechinese'] = 0x02CA;\n t['section'] = 0x00A7;\n t['seenarabic'] = 0x0633;\n t['seenfinalarabic'] = 0xFEB2;\n t['seeninitialarabic'] = 0xFEB3;\n t['seenmedialarabic'] = 0xFEB4;\n t['segol'] = 0x05B6;\n t['segol13'] = 0x05B6;\n t['segol1f'] = 0x05B6;\n t['segol2c'] = 0x05B6;\n t['segolhebrew'] = 0x05B6;\n t['segolnarrowhebrew'] = 0x05B6;\n t['segolquarterhebrew'] = 0x05B6;\n t['segoltahebrew'] = 0x0592;\n t['segolwidehebrew'] = 0x05B6;\n t['seharmenian'] = 0x057D;\n t['sehiragana'] = 0x305B;\n t['sekatakana'] = 0x30BB;\n t['sekatakanahalfwidth'] = 0xFF7E;\n t['semicolon'] = 0x003B;\n t['semicolonarabic'] = 0x061B;\n t['semicolonmonospace'] = 0xFF1B;\n t['semicolonsmall'] = 0xFE54;\n t['semivoicedmarkkana'] = 0x309C;\n t['semivoicedmarkkanahalfwidth'] = 0xFF9F;\n t['sentisquare'] = 0x3322;\n t['sentosquare'] = 0x3323;\n t['seven'] = 0x0037;\n t['sevenarabic'] = 0x0667;\n t['sevenbengali'] = 0x09ED;\n t['sevencircle'] = 0x2466;\n t['sevencircleinversesansserif'] = 0x2790;\n t['sevendeva'] = 0x096D;\n t['seveneighths'] = 0x215E;\n t['sevengujarati'] = 0x0AED;\n t['sevengurmukhi'] = 0x0A6D;\n t['sevenhackarabic'] = 0x0667;\n t['sevenhangzhou'] = 0x3027;\n t['sevenideographicparen'] = 0x3226;\n t['seveninferior'] = 0x2087;\n t['sevenmonospace'] = 0xFF17;\n t['sevenoldstyle'] = 0xF737;\n t['sevenparen'] = 0x247A;\n t['sevenperiod'] = 0x248E;\n t['sevenpersian'] = 0x06F7;\n t['sevenroman'] = 0x2176;\n t['sevensuperior'] = 0x2077;\n t['seventeencircle'] = 0x2470;\n t['seventeenparen'] = 0x2484;\n t['seventeenperiod'] = 0x2498;\n t['seventhai'] = 0x0E57;\n t['sfthyphen'] = 0x00AD;\n t['shaarmenian'] = 0x0577;\n t['shabengali'] = 0x09B6;\n t['shacyrillic'] = 0x0448;\n t['shaddaarabic'] = 0x0651;\n t['shaddadammaarabic'] = 0xFC61;\n t['shaddadammatanarabic'] = 0xFC5E;\n t['shaddafathaarabic'] = 0xFC60;\n t['shaddakasraarabic'] = 0xFC62;\n t['shaddakasratanarabic'] = 0xFC5F;\n t['shade'] = 0x2592;\n t['shadedark'] = 0x2593;\n t['shadelight'] = 0x2591;\n t['shademedium'] = 0x2592;\n t['shadeva'] = 0x0936;\n t['shagujarati'] = 0x0AB6;\n t['shagurmukhi'] = 0x0A36;\n t['shalshelethebrew'] = 0x0593;\n t['shbopomofo'] = 0x3115;\n t['shchacyrillic'] = 0x0449;\n t['sheenarabic'] = 0x0634;\n t['sheenfinalarabic'] = 0xFEB6;\n t['sheeninitialarabic'] = 0xFEB7;\n t['sheenmedialarabic'] = 0xFEB8;\n t['sheicoptic'] = 0x03E3;\n t['sheqel'] = 0x20AA;\n t['sheqelhebrew'] = 0x20AA;\n t['sheva'] = 0x05B0;\n t['sheva115'] = 0x05B0;\n t['sheva15'] = 0x05B0;\n t['sheva22'] = 0x05B0;\n t['sheva2e'] = 0x05B0;\n t['shevahebrew'] = 0x05B0;\n t['shevanarrowhebrew'] = 0x05B0;\n t['shevaquarterhebrew'] = 0x05B0;\n t['shevawidehebrew'] = 0x05B0;\n t['shhacyrillic'] = 0x04BB;\n t['shimacoptic'] = 0x03ED;\n t['shin'] = 0x05E9;\n t['shindagesh'] = 0xFB49;\n t['shindageshhebrew'] = 0xFB49;\n t['shindageshshindot'] = 0xFB2C;\n t['shindageshshindothebrew'] = 0xFB2C;\n t['shindageshsindot'] = 0xFB2D;\n t['shindageshsindothebrew'] = 0xFB2D;\n t['shindothebrew'] = 0x05C1;\n t['shinhebrew'] = 0x05E9;\n t['shinshindot'] = 0xFB2A;\n t['shinshindothebrew'] = 0xFB2A;\n t['shinsindot'] = 0xFB2B;\n t['shinsindothebrew'] = 0xFB2B;\n t['shook'] = 0x0282;\n t['sigma'] = 0x03C3;\n t['sigma1'] = 0x03C2;\n t['sigmafinal'] = 0x03C2;\n t['sigmalunatesymbolgreek'] = 0x03F2;\n t['sihiragana'] = 0x3057;\n t['sikatakana'] = 0x30B7;\n t['sikatakanahalfwidth'] = 0xFF7C;\n t['siluqhebrew'] = 0x05BD;\n t['siluqlefthebrew'] = 0x05BD;\n t['similar'] = 0x223C;\n t['sindothebrew'] = 0x05C2;\n t['siosacirclekorean'] = 0x3274;\n t['siosaparenkorean'] = 0x3214;\n t['sioscieuckorean'] = 0x317E;\n t['sioscirclekorean'] = 0x3266;\n t['sioskiyeokkorean'] = 0x317A;\n t['sioskorean'] = 0x3145;\n t['siosnieunkorean'] = 0x317B;\n t['siosparenkorean'] = 0x3206;\n t['siospieupkorean'] = 0x317D;\n t['siostikeutkorean'] = 0x317C;\n t['six'] = 0x0036;\n t['sixarabic'] = 0x0666;\n t['sixbengali'] = 0x09EC;\n t['sixcircle'] = 0x2465;\n t['sixcircleinversesansserif'] = 0x278F;\n t['sixdeva'] = 0x096C;\n t['sixgujarati'] = 0x0AEC;\n t['sixgurmukhi'] = 0x0A6C;\n t['sixhackarabic'] = 0x0666;\n t['sixhangzhou'] = 0x3026;\n t['sixideographicparen'] = 0x3225;\n t['sixinferior'] = 0x2086;\n t['sixmonospace'] = 0xFF16;\n t['sixoldstyle'] = 0xF736;\n t['sixparen'] = 0x2479;\n t['sixperiod'] = 0x248D;\n t['sixpersian'] = 0x06F6;\n t['sixroman'] = 0x2175;\n t['sixsuperior'] = 0x2076;\n t['sixteencircle'] = 0x246F;\n t['sixteencurrencydenominatorbengali'] = 0x09F9;\n t['sixteenparen'] = 0x2483;\n t['sixteenperiod'] = 0x2497;\n t['sixthai'] = 0x0E56;\n t['slash'] = 0x002F;\n t['slashmonospace'] = 0xFF0F;\n t['slong'] = 0x017F;\n t['slongdotaccent'] = 0x1E9B;\n t['smileface'] = 0x263A;\n t['smonospace'] = 0xFF53;\n t['sofpasuqhebrew'] = 0x05C3;\n t['softhyphen'] = 0x00AD;\n t['softsigncyrillic'] = 0x044C;\n t['sohiragana'] = 0x305D;\n t['sokatakana'] = 0x30BD;\n t['sokatakanahalfwidth'] = 0xFF7F;\n t['soliduslongoverlaycmb'] = 0x0338;\n t['solidusshortoverlaycmb'] = 0x0337;\n t['sorusithai'] = 0x0E29;\n t['sosalathai'] = 0x0E28;\n t['sosothai'] = 0x0E0B;\n t['sosuathai'] = 0x0E2A;\n t['space'] = 0x0020;\n t['spacehackarabic'] = 0x0020;\n t['spade'] = 0x2660;\n t['spadesuitblack'] = 0x2660;\n t['spadesuitwhite'] = 0x2664;\n t['sparen'] = 0x24AE;\n t['squarebelowcmb'] = 0x033B;\n t['squarecc'] = 0x33C4;\n t['squarecm'] = 0x339D;\n t['squarediagonalcrosshatchfill'] = 0x25A9;\n t['squarehorizontalfill'] = 0x25A4;\n t['squarekg'] = 0x338F;\n t['squarekm'] = 0x339E;\n t['squarekmcapital'] = 0x33CE;\n t['squareln'] = 0x33D1;\n t['squarelog'] = 0x33D2;\n t['squaremg'] = 0x338E;\n t['squaremil'] = 0x33D5;\n t['squaremm'] = 0x339C;\n t['squaremsquared'] = 0x33A1;\n t['squareorthogonalcrosshatchfill'] = 0x25A6;\n t['squareupperlefttolowerrightfill'] = 0x25A7;\n t['squareupperrighttolowerleftfill'] = 0x25A8;\n t['squareverticalfill'] = 0x25A5;\n t['squarewhitewithsmallblack'] = 0x25A3;\n t['srsquare'] = 0x33DB;\n t['ssabengali'] = 0x09B7;\n t['ssadeva'] = 0x0937;\n t['ssagujarati'] = 0x0AB7;\n t['ssangcieuckorean'] = 0x3149;\n t['ssanghieuhkorean'] = 0x3185;\n t['ssangieungkorean'] = 0x3180;\n t['ssangkiyeokkorean'] = 0x3132;\n t['ssangnieunkorean'] = 0x3165;\n t['ssangpieupkorean'] = 0x3143;\n t['ssangsioskorean'] = 0x3146;\n t['ssangtikeutkorean'] = 0x3138;\n t['ssuperior'] = 0xF6F2;\n t['sterling'] = 0x00A3;\n t['sterlingmonospace'] = 0xFFE1;\n t['strokelongoverlaycmb'] = 0x0336;\n t['strokeshortoverlaycmb'] = 0x0335;\n t['subset'] = 0x2282;\n t['subsetnotequal'] = 0x228A;\n t['subsetorequal'] = 0x2286;\n t['succeeds'] = 0x227B;\n t['suchthat'] = 0x220B;\n t['suhiragana'] = 0x3059;\n t['sukatakana'] = 0x30B9;\n t['sukatakanahalfwidth'] = 0xFF7D;\n t['sukunarabic'] = 0x0652;\n t['summation'] = 0x2211;\n t['sun'] = 0x263C;\n t['superset'] = 0x2283;\n t['supersetnotequal'] = 0x228B;\n t['supersetorequal'] = 0x2287;\n t['svsquare'] = 0x33DC;\n t['syouwaerasquare'] = 0x337C;\n t['t'] = 0x0074;\n t['tabengali'] = 0x09A4;\n t['tackdown'] = 0x22A4;\n t['tackleft'] = 0x22A3;\n t['tadeva'] = 0x0924;\n t['tagujarati'] = 0x0AA4;\n t['tagurmukhi'] = 0x0A24;\n t['taharabic'] = 0x0637;\n t['tahfinalarabic'] = 0xFEC2;\n t['tahinitialarabic'] = 0xFEC3;\n t['tahiragana'] = 0x305F;\n t['tahmedialarabic'] = 0xFEC4;\n t['taisyouerasquare'] = 0x337D;\n t['takatakana'] = 0x30BF;\n t['takatakanahalfwidth'] = 0xFF80;\n t['tatweelarabic'] = 0x0640;\n t['tau'] = 0x03C4;\n t['tav'] = 0x05EA;\n t['tavdages'] = 0xFB4A;\n t['tavdagesh'] = 0xFB4A;\n t['tavdageshhebrew'] = 0xFB4A;\n t['tavhebrew'] = 0x05EA;\n t['tbar'] = 0x0167;\n t['tbopomofo'] = 0x310A;\n t['tcaron'] = 0x0165;\n t['tccurl'] = 0x02A8;\n t['tcedilla'] = 0x0163;\n t['tcheharabic'] = 0x0686;\n t['tchehfinalarabic'] = 0xFB7B;\n t['tchehinitialarabic'] = 0xFB7C;\n t['tchehmedialarabic'] = 0xFB7D;\n t['tcircle'] = 0x24E3;\n t['tcircumflexbelow'] = 0x1E71;\n t['tcommaaccent'] = 0x0163;\n t['tdieresis'] = 0x1E97;\n t['tdotaccent'] = 0x1E6B;\n t['tdotbelow'] = 0x1E6D;\n t['tecyrillic'] = 0x0442;\n t['tedescendercyrillic'] = 0x04AD;\n t['teharabic'] = 0x062A;\n t['tehfinalarabic'] = 0xFE96;\n t['tehhahinitialarabic'] = 0xFCA2;\n t['tehhahisolatedarabic'] = 0xFC0C;\n t['tehinitialarabic'] = 0xFE97;\n t['tehiragana'] = 0x3066;\n t['tehjeeminitialarabic'] = 0xFCA1;\n t['tehjeemisolatedarabic'] = 0xFC0B;\n t['tehmarbutaarabic'] = 0x0629;\n t['tehmarbutafinalarabic'] = 0xFE94;\n t['tehmedialarabic'] = 0xFE98;\n t['tehmeeminitialarabic'] = 0xFCA4;\n t['tehmeemisolatedarabic'] = 0xFC0E;\n t['tehnoonfinalarabic'] = 0xFC73;\n t['tekatakana'] = 0x30C6;\n t['tekatakanahalfwidth'] = 0xFF83;\n t['telephone'] = 0x2121;\n t['telephoneblack'] = 0x260E;\n t['telishagedolahebrew'] = 0x05A0;\n t['telishaqetanahebrew'] = 0x05A9;\n t['tencircle'] = 0x2469;\n t['tenideographicparen'] = 0x3229;\n t['tenparen'] = 0x247D;\n t['tenperiod'] = 0x2491;\n t['tenroman'] = 0x2179;\n t['tesh'] = 0x02A7;\n t['tet'] = 0x05D8;\n t['tetdagesh'] = 0xFB38;\n t['tetdageshhebrew'] = 0xFB38;\n t['tethebrew'] = 0x05D8;\n t['tetsecyrillic'] = 0x04B5;\n t['tevirhebrew'] = 0x059B;\n t['tevirlefthebrew'] = 0x059B;\n t['thabengali'] = 0x09A5;\n t['thadeva'] = 0x0925;\n t['thagujarati'] = 0x0AA5;\n t['thagurmukhi'] = 0x0A25;\n t['thalarabic'] = 0x0630;\n t['thalfinalarabic'] = 0xFEAC;\n t['thanthakhatlowleftthai'] = 0xF898;\n t['thanthakhatlowrightthai'] = 0xF897;\n t['thanthakhatthai'] = 0x0E4C;\n t['thanthakhatupperleftthai'] = 0xF896;\n t['theharabic'] = 0x062B;\n t['thehfinalarabic'] = 0xFE9A;\n t['thehinitialarabic'] = 0xFE9B;\n t['thehmedialarabic'] = 0xFE9C;\n t['thereexists'] = 0x2203;\n t['therefore'] = 0x2234;\n t['theta'] = 0x03B8;\n t['theta1'] = 0x03D1;\n t['thetasymbolgreek'] = 0x03D1;\n t['thieuthacirclekorean'] = 0x3279;\n t['thieuthaparenkorean'] = 0x3219;\n t['thieuthcirclekorean'] = 0x326B;\n t['thieuthkorean'] = 0x314C;\n t['thieuthparenkorean'] = 0x320B;\n t['thirteencircle'] = 0x246C;\n t['thirteenparen'] = 0x2480;\n t['thirteenperiod'] = 0x2494;\n t['thonangmonthothai'] = 0x0E11;\n t['thook'] = 0x01AD;\n t['thophuthaothai'] = 0x0E12;\n t['thorn'] = 0x00FE;\n t['thothahanthai'] = 0x0E17;\n t['thothanthai'] = 0x0E10;\n t['thothongthai'] = 0x0E18;\n t['thothungthai'] = 0x0E16;\n t['thousandcyrillic'] = 0x0482;\n t['thousandsseparatorarabic'] = 0x066C;\n t['thousandsseparatorpersian'] = 0x066C;\n t['three'] = 0x0033;\n t['threearabic'] = 0x0663;\n t['threebengali'] = 0x09E9;\n t['threecircle'] = 0x2462;\n t['threecircleinversesansserif'] = 0x278C;\n t['threedeva'] = 0x0969;\n t['threeeighths'] = 0x215C;\n t['threegujarati'] = 0x0AE9;\n t['threegurmukhi'] = 0x0A69;\n t['threehackarabic'] = 0x0663;\n t['threehangzhou'] = 0x3023;\n t['threeideographicparen'] = 0x3222;\n t['threeinferior'] = 0x2083;\n t['threemonospace'] = 0xFF13;\n t['threenumeratorbengali'] = 0x09F6;\n t['threeoldstyle'] = 0xF733;\n t['threeparen'] = 0x2476;\n t['threeperiod'] = 0x248A;\n t['threepersian'] = 0x06F3;\n t['threequarters'] = 0x00BE;\n t['threequartersemdash'] = 0xF6DE;\n t['threeroman'] = 0x2172;\n t['threesuperior'] = 0x00B3;\n t['threethai'] = 0x0E53;\n t['thzsquare'] = 0x3394;\n t['tihiragana'] = 0x3061;\n t['tikatakana'] = 0x30C1;\n t['tikatakanahalfwidth'] = 0xFF81;\n t['tikeutacirclekorean'] = 0x3270;\n t['tikeutaparenkorean'] = 0x3210;\n t['tikeutcirclekorean'] = 0x3262;\n t['tikeutkorean'] = 0x3137;\n t['tikeutparenkorean'] = 0x3202;\n t['tilde'] = 0x02DC;\n t['tildebelowcmb'] = 0x0330;\n t['tildecmb'] = 0x0303;\n t['tildecomb'] = 0x0303;\n t['tildedoublecmb'] = 0x0360;\n t['tildeoperator'] = 0x223C;\n t['tildeoverlaycmb'] = 0x0334;\n t['tildeverticalcmb'] = 0x033E;\n t['timescircle'] = 0x2297;\n t['tipehahebrew'] = 0x0596;\n t['tipehalefthebrew'] = 0x0596;\n t['tippigurmukhi'] = 0x0A70;\n t['titlocyrilliccmb'] = 0x0483;\n t['tiwnarmenian'] = 0x057F;\n t['tlinebelow'] = 0x1E6F;\n t['tmonospace'] = 0xFF54;\n t['toarmenian'] = 0x0569;\n t['tohiragana'] = 0x3068;\n t['tokatakana'] = 0x30C8;\n t['tokatakanahalfwidth'] = 0xFF84;\n t['tonebarextrahighmod'] = 0x02E5;\n t['tonebarextralowmod'] = 0x02E9;\n t['tonebarhighmod'] = 0x02E6;\n t['tonebarlowmod'] = 0x02E8;\n t['tonebarmidmod'] = 0x02E7;\n t['tonefive'] = 0x01BD;\n t['tonesix'] = 0x0185;\n t['tonetwo'] = 0x01A8;\n t['tonos'] = 0x0384;\n t['tonsquare'] = 0x3327;\n t['topatakthai'] = 0x0E0F;\n t['tortoiseshellbracketleft'] = 0x3014;\n t['tortoiseshellbracketleftsmall'] = 0xFE5D;\n t['tortoiseshellbracketleftvertical'] = 0xFE39;\n t['tortoiseshellbracketright'] = 0x3015;\n t['tortoiseshellbracketrightsmall'] = 0xFE5E;\n t['tortoiseshellbracketrightvertical'] = 0xFE3A;\n t['totaothai'] = 0x0E15;\n t['tpalatalhook'] = 0x01AB;\n t['tparen'] = 0x24AF;\n t['trademark'] = 0x2122;\n t['trademarksans'] = 0xF8EA;\n t['trademarkserif'] = 0xF6DB;\n t['tretroflexhook'] = 0x0288;\n t['triagdn'] = 0x25BC;\n t['triaglf'] = 0x25C4;\n t['triagrt'] = 0x25BA;\n t['triagup'] = 0x25B2;\n t['ts'] = 0x02A6;\n t['tsadi'] = 0x05E6;\n t['tsadidagesh'] = 0xFB46;\n t['tsadidageshhebrew'] = 0xFB46;\n t['tsadihebrew'] = 0x05E6;\n t['tsecyrillic'] = 0x0446;\n t['tsere'] = 0x05B5;\n t['tsere12'] = 0x05B5;\n t['tsere1e'] = 0x05B5;\n t['tsere2b'] = 0x05B5;\n t['tserehebrew'] = 0x05B5;\n t['tserenarrowhebrew'] = 0x05B5;\n t['tserequarterhebrew'] = 0x05B5;\n t['tserewidehebrew'] = 0x05B5;\n t['tshecyrillic'] = 0x045B;\n t['tsuperior'] = 0xF6F3;\n t['ttabengali'] = 0x099F;\n t['ttadeva'] = 0x091F;\n t['ttagujarati'] = 0x0A9F;\n t['ttagurmukhi'] = 0x0A1F;\n t['tteharabic'] = 0x0679;\n t['ttehfinalarabic'] = 0xFB67;\n t['ttehinitialarabic'] = 0xFB68;\n t['ttehmedialarabic'] = 0xFB69;\n t['tthabengali'] = 0x09A0;\n t['tthadeva'] = 0x0920;\n t['tthagujarati'] = 0x0AA0;\n t['tthagurmukhi'] = 0x0A20;\n t['tturned'] = 0x0287;\n t['tuhiragana'] = 0x3064;\n t['tukatakana'] = 0x30C4;\n t['tukatakanahalfwidth'] = 0xFF82;\n t['tusmallhiragana'] = 0x3063;\n t['tusmallkatakana'] = 0x30C3;\n t['tusmallkatakanahalfwidth'] = 0xFF6F;\n t['twelvecircle'] = 0x246B;\n t['twelveparen'] = 0x247F;\n t['twelveperiod'] = 0x2493;\n t['twelveroman'] = 0x217B;\n t['twentycircle'] = 0x2473;\n t['twentyhangzhou'] = 0x5344;\n t['twentyparen'] = 0x2487;\n t['twentyperiod'] = 0x249B;\n t['two'] = 0x0032;\n t['twoarabic'] = 0x0662;\n t['twobengali'] = 0x09E8;\n t['twocircle'] = 0x2461;\n t['twocircleinversesansserif'] = 0x278B;\n t['twodeva'] = 0x0968;\n t['twodotenleader'] = 0x2025;\n t['twodotleader'] = 0x2025;\n t['twodotleadervertical'] = 0xFE30;\n t['twogujarati'] = 0x0AE8;\n t['twogurmukhi'] = 0x0A68;\n t['twohackarabic'] = 0x0662;\n t['twohangzhou'] = 0x3022;\n t['twoideographicparen'] = 0x3221;\n t['twoinferior'] = 0x2082;\n t['twomonospace'] = 0xFF12;\n t['twonumeratorbengali'] = 0x09F5;\n t['twooldstyle'] = 0xF732;\n t['twoparen'] = 0x2475;\n t['twoperiod'] = 0x2489;\n t['twopersian'] = 0x06F2;\n t['tworoman'] = 0x2171;\n t['twostroke'] = 0x01BB;\n t['twosuperior'] = 0x00B2;\n t['twothai'] = 0x0E52;\n t['twothirds'] = 0x2154;\n t['u'] = 0x0075;\n t['uacute'] = 0x00FA;\n t['ubar'] = 0x0289;\n t['ubengali'] = 0x0989;\n t['ubopomofo'] = 0x3128;\n t['ubreve'] = 0x016D;\n t['ucaron'] = 0x01D4;\n t['ucircle'] = 0x24E4;\n t['ucircumflex'] = 0x00FB;\n t['ucircumflexbelow'] = 0x1E77;\n t['ucyrillic'] = 0x0443;\n t['udattadeva'] = 0x0951;\n t['udblacute'] = 0x0171;\n t['udblgrave'] = 0x0215;\n t['udeva'] = 0x0909;\n t['udieresis'] = 0x00FC;\n t['udieresisacute'] = 0x01D8;\n t['udieresisbelow'] = 0x1E73;\n t['udieresiscaron'] = 0x01DA;\n t['udieresiscyrillic'] = 0x04F1;\n t['udieresisgrave'] = 0x01DC;\n t['udieresismacron'] = 0x01D6;\n t['udotbelow'] = 0x1EE5;\n t['ugrave'] = 0x00F9;\n t['ugujarati'] = 0x0A89;\n t['ugurmukhi'] = 0x0A09;\n t['uhiragana'] = 0x3046;\n t['uhookabove'] = 0x1EE7;\n t['uhorn'] = 0x01B0;\n t['uhornacute'] = 0x1EE9;\n t['uhorndotbelow'] = 0x1EF1;\n t['uhorngrave'] = 0x1EEB;\n t['uhornhookabove'] = 0x1EED;\n t['uhorntilde'] = 0x1EEF;\n t['uhungarumlaut'] = 0x0171;\n t['uhungarumlautcyrillic'] = 0x04F3;\n t['uinvertedbreve'] = 0x0217;\n t['ukatakana'] = 0x30A6;\n t['ukatakanahalfwidth'] = 0xFF73;\n t['ukcyrillic'] = 0x0479;\n t['ukorean'] = 0x315C;\n t['umacron'] = 0x016B;\n t['umacroncyrillic'] = 0x04EF;\n t['umacrondieresis'] = 0x1E7B;\n t['umatragurmukhi'] = 0x0A41;\n t['umonospace'] = 0xFF55;\n t['underscore'] = 0x005F;\n t['underscoredbl'] = 0x2017;\n t['underscoremonospace'] = 0xFF3F;\n t['underscorevertical'] = 0xFE33;\n t['underscorewavy'] = 0xFE4F;\n t['union'] = 0x222A;\n t['universal'] = 0x2200;\n t['uogonek'] = 0x0173;\n t['uparen'] = 0x24B0;\n t['upblock'] = 0x2580;\n t['upperdothebrew'] = 0x05C4;\n t['upsilon'] = 0x03C5;\n t['upsilondieresis'] = 0x03CB;\n t['upsilondieresistonos'] = 0x03B0;\n t['upsilonlatin'] = 0x028A;\n t['upsilontonos'] = 0x03CD;\n t['uptackbelowcmb'] = 0x031D;\n t['uptackmod'] = 0x02D4;\n t['uragurmukhi'] = 0x0A73;\n t['uring'] = 0x016F;\n t['ushortcyrillic'] = 0x045E;\n t['usmallhiragana'] = 0x3045;\n t['usmallkatakana'] = 0x30A5;\n t['usmallkatakanahalfwidth'] = 0xFF69;\n t['ustraightcyrillic'] = 0x04AF;\n t['ustraightstrokecyrillic'] = 0x04B1;\n t['utilde'] = 0x0169;\n t['utildeacute'] = 0x1E79;\n t['utildebelow'] = 0x1E75;\n t['uubengali'] = 0x098A;\n t['uudeva'] = 0x090A;\n t['uugujarati'] = 0x0A8A;\n t['uugurmukhi'] = 0x0A0A;\n t['uumatragurmukhi'] = 0x0A42;\n t['uuvowelsignbengali'] = 0x09C2;\n t['uuvowelsigndeva'] = 0x0942;\n t['uuvowelsigngujarati'] = 0x0AC2;\n t['uvowelsignbengali'] = 0x09C1;\n t['uvowelsigndeva'] = 0x0941;\n t['uvowelsigngujarati'] = 0x0AC1;\n t['v'] = 0x0076;\n t['vadeva'] = 0x0935;\n t['vagujarati'] = 0x0AB5;\n t['vagurmukhi'] = 0x0A35;\n t['vakatakana'] = 0x30F7;\n t['vav'] = 0x05D5;\n t['vavdagesh'] = 0xFB35;\n t['vavdagesh65'] = 0xFB35;\n t['vavdageshhebrew'] = 0xFB35;\n t['vavhebrew'] = 0x05D5;\n t['vavholam'] = 0xFB4B;\n t['vavholamhebrew'] = 0xFB4B;\n t['vavvavhebrew'] = 0x05F0;\n t['vavyodhebrew'] = 0x05F1;\n t['vcircle'] = 0x24E5;\n t['vdotbelow'] = 0x1E7F;\n t['vecyrillic'] = 0x0432;\n t['veharabic'] = 0x06A4;\n t['vehfinalarabic'] = 0xFB6B;\n t['vehinitialarabic'] = 0xFB6C;\n t['vehmedialarabic'] = 0xFB6D;\n t['vekatakana'] = 0x30F9;\n t['venus'] = 0x2640;\n t['verticalbar'] = 0x007C;\n t['verticallineabovecmb'] = 0x030D;\n t['verticallinebelowcmb'] = 0x0329;\n t['verticallinelowmod'] = 0x02CC;\n t['verticallinemod'] = 0x02C8;\n t['vewarmenian'] = 0x057E;\n t['vhook'] = 0x028B;\n t['vikatakana'] = 0x30F8;\n t['viramabengali'] = 0x09CD;\n t['viramadeva'] = 0x094D;\n t['viramagujarati'] = 0x0ACD;\n t['visargabengali'] = 0x0983;\n t['visargadeva'] = 0x0903;\n t['visargagujarati'] = 0x0A83;\n t['vmonospace'] = 0xFF56;\n t['voarmenian'] = 0x0578;\n t['voicediterationhiragana'] = 0x309E;\n t['voicediterationkatakana'] = 0x30FE;\n t['voicedmarkkana'] = 0x309B;\n t['voicedmarkkanahalfwidth'] = 0xFF9E;\n t['vokatakana'] = 0x30FA;\n t['vparen'] = 0x24B1;\n t['vtilde'] = 0x1E7D;\n t['vturned'] = 0x028C;\n t['vuhiragana'] = 0x3094;\n t['vukatakana'] = 0x30F4;\n t['w'] = 0x0077;\n t['wacute'] = 0x1E83;\n t['waekorean'] = 0x3159;\n t['wahiragana'] = 0x308F;\n t['wakatakana'] = 0x30EF;\n t['wakatakanahalfwidth'] = 0xFF9C;\n t['wakorean'] = 0x3158;\n t['wasmallhiragana'] = 0x308E;\n t['wasmallkatakana'] = 0x30EE;\n t['wattosquare'] = 0x3357;\n t['wavedash'] = 0x301C;\n t['wavyunderscorevertical'] = 0xFE34;\n t['wawarabic'] = 0x0648;\n t['wawfinalarabic'] = 0xFEEE;\n t['wawhamzaabovearabic'] = 0x0624;\n t['wawhamzaabovefinalarabic'] = 0xFE86;\n t['wbsquare'] = 0x33DD;\n t['wcircle'] = 0x24E6;\n t['wcircumflex'] = 0x0175;\n t['wdieresis'] = 0x1E85;\n t['wdotaccent'] = 0x1E87;\n t['wdotbelow'] = 0x1E89;\n t['wehiragana'] = 0x3091;\n t['weierstrass'] = 0x2118;\n t['wekatakana'] = 0x30F1;\n t['wekorean'] = 0x315E;\n t['weokorean'] = 0x315D;\n t['wgrave'] = 0x1E81;\n t['whitebullet'] = 0x25E6;\n t['whitecircle'] = 0x25CB;\n t['whitecircleinverse'] = 0x25D9;\n t['whitecornerbracketleft'] = 0x300E;\n t['whitecornerbracketleftvertical'] = 0xFE43;\n t['whitecornerbracketright'] = 0x300F;\n t['whitecornerbracketrightvertical'] = 0xFE44;\n t['whitediamond'] = 0x25C7;\n t['whitediamondcontainingblacksmalldiamond'] = 0x25C8;\n t['whitedownpointingsmalltriangle'] = 0x25BF;\n t['whitedownpointingtriangle'] = 0x25BD;\n t['whiteleftpointingsmalltriangle'] = 0x25C3;\n t['whiteleftpointingtriangle'] = 0x25C1;\n t['whitelenticularbracketleft'] = 0x3016;\n t['whitelenticularbracketright'] = 0x3017;\n t['whiterightpointingsmalltriangle'] = 0x25B9;\n t['whiterightpointingtriangle'] = 0x25B7;\n t['whitesmallsquare'] = 0x25AB;\n t['whitesmilingface'] = 0x263A;\n t['whitesquare'] = 0x25A1;\n t['whitestar'] = 0x2606;\n t['whitetelephone'] = 0x260F;\n t['whitetortoiseshellbracketleft'] = 0x3018;\n t['whitetortoiseshellbracketright'] = 0x3019;\n t['whiteuppointingsmalltriangle'] = 0x25B5;\n t['whiteuppointingtriangle'] = 0x25B3;\n t['wihiragana'] = 0x3090;\n t['wikatakana'] = 0x30F0;\n t['wikorean'] = 0x315F;\n t['wmonospace'] = 0xFF57;\n t['wohiragana'] = 0x3092;\n t['wokatakana'] = 0x30F2;\n t['wokatakanahalfwidth'] = 0xFF66;\n t['won'] = 0x20A9;\n t['wonmonospace'] = 0xFFE6;\n t['wowaenthai'] = 0x0E27;\n t['wparen'] = 0x24B2;\n t['wring'] = 0x1E98;\n t['wsuperior'] = 0x02B7;\n t['wturned'] = 0x028D;\n t['wynn'] = 0x01BF;\n t['x'] = 0x0078;\n t['xabovecmb'] = 0x033D;\n t['xbopomofo'] = 0x3112;\n t['xcircle'] = 0x24E7;\n t['xdieresis'] = 0x1E8D;\n t['xdotaccent'] = 0x1E8B;\n t['xeharmenian'] = 0x056D;\n t['xi'] = 0x03BE;\n t['xmonospace'] = 0xFF58;\n t['xparen'] = 0x24B3;\n t['xsuperior'] = 0x02E3;\n t['y'] = 0x0079;\n t['yaadosquare'] = 0x334E;\n t['yabengali'] = 0x09AF;\n t['yacute'] = 0x00FD;\n t['yadeva'] = 0x092F;\n t['yaekorean'] = 0x3152;\n t['yagujarati'] = 0x0AAF;\n t['yagurmukhi'] = 0x0A2F;\n t['yahiragana'] = 0x3084;\n t['yakatakana'] = 0x30E4;\n t['yakatakanahalfwidth'] = 0xFF94;\n t['yakorean'] = 0x3151;\n t['yamakkanthai'] = 0x0E4E;\n t['yasmallhiragana'] = 0x3083;\n t['yasmallkatakana'] = 0x30E3;\n t['yasmallkatakanahalfwidth'] = 0xFF6C;\n t['yatcyrillic'] = 0x0463;\n t['ycircle'] = 0x24E8;\n t['ycircumflex'] = 0x0177;\n t['ydieresis'] = 0x00FF;\n t['ydotaccent'] = 0x1E8F;\n t['ydotbelow'] = 0x1EF5;\n t['yeharabic'] = 0x064A;\n t['yehbarreearabic'] = 0x06D2;\n t['yehbarreefinalarabic'] = 0xFBAF;\n t['yehfinalarabic'] = 0xFEF2;\n t['yehhamzaabovearabic'] = 0x0626;\n t['yehhamzaabovefinalarabic'] = 0xFE8A;\n t['yehhamzaaboveinitialarabic'] = 0xFE8B;\n t['yehhamzaabovemedialarabic'] = 0xFE8C;\n t['yehinitialarabic'] = 0xFEF3;\n t['yehmedialarabic'] = 0xFEF4;\n t['yehmeeminitialarabic'] = 0xFCDD;\n t['yehmeemisolatedarabic'] = 0xFC58;\n t['yehnoonfinalarabic'] = 0xFC94;\n t['yehthreedotsbelowarabic'] = 0x06D1;\n t['yekorean'] = 0x3156;\n t['yen'] = 0x00A5;\n t['yenmonospace'] = 0xFFE5;\n t['yeokorean'] = 0x3155;\n t['yeorinhieuhkorean'] = 0x3186;\n t['yerahbenyomohebrew'] = 0x05AA;\n t['yerahbenyomolefthebrew'] = 0x05AA;\n t['yericyrillic'] = 0x044B;\n t['yerudieresiscyrillic'] = 0x04F9;\n t['yesieungkorean'] = 0x3181;\n t['yesieungpansioskorean'] = 0x3183;\n t['yesieungsioskorean'] = 0x3182;\n t['yetivhebrew'] = 0x059A;\n t['ygrave'] = 0x1EF3;\n t['yhook'] = 0x01B4;\n t['yhookabove'] = 0x1EF7;\n t['yiarmenian'] = 0x0575;\n t['yicyrillic'] = 0x0457;\n t['yikorean'] = 0x3162;\n t['yinyang'] = 0x262F;\n t['yiwnarmenian'] = 0x0582;\n t['ymonospace'] = 0xFF59;\n t['yod'] = 0x05D9;\n t['yoddagesh'] = 0xFB39;\n t['yoddageshhebrew'] = 0xFB39;\n t['yodhebrew'] = 0x05D9;\n t['yodyodhebrew'] = 0x05F2;\n t['yodyodpatahhebrew'] = 0xFB1F;\n t['yohiragana'] = 0x3088;\n t['yoikorean'] = 0x3189;\n t['yokatakana'] = 0x30E8;\n t['yokatakanahalfwidth'] = 0xFF96;\n t['yokorean'] = 0x315B;\n t['yosmallhiragana'] = 0x3087;\n t['yosmallkatakana'] = 0x30E7;\n t['yosmallkatakanahalfwidth'] = 0xFF6E;\n t['yotgreek'] = 0x03F3;\n t['yoyaekorean'] = 0x3188;\n t['yoyakorean'] = 0x3187;\n t['yoyakthai'] = 0x0E22;\n t['yoyingthai'] = 0x0E0D;\n t['yparen'] = 0x24B4;\n t['ypogegrammeni'] = 0x037A;\n t['ypogegrammenigreekcmb'] = 0x0345;\n t['yr'] = 0x01A6;\n t['yring'] = 0x1E99;\n t['ysuperior'] = 0x02B8;\n t['ytilde'] = 0x1EF9;\n t['yturned'] = 0x028E;\n t['yuhiragana'] = 0x3086;\n t['yuikorean'] = 0x318C;\n t['yukatakana'] = 0x30E6;\n t['yukatakanahalfwidth'] = 0xFF95;\n t['yukorean'] = 0x3160;\n t['yusbigcyrillic'] = 0x046B;\n t['yusbigiotifiedcyrillic'] = 0x046D;\n t['yuslittlecyrillic'] = 0x0467;\n t['yuslittleiotifiedcyrillic'] = 0x0469;\n t['yusmallhiragana'] = 0x3085;\n t['yusmallkatakana'] = 0x30E5;\n t['yusmallkatakanahalfwidth'] = 0xFF6D;\n t['yuyekorean'] = 0x318B;\n t['yuyeokorean'] = 0x318A;\n t['yyabengali'] = 0x09DF;\n t['yyadeva'] = 0x095F;\n t['z'] = 0x007A;\n t['zaarmenian'] = 0x0566;\n t['zacute'] = 0x017A;\n t['zadeva'] = 0x095B;\n t['zagurmukhi'] = 0x0A5B;\n t['zaharabic'] = 0x0638;\n t['zahfinalarabic'] = 0xFEC6;\n t['zahinitialarabic'] = 0xFEC7;\n t['zahiragana'] = 0x3056;\n t['zahmedialarabic'] = 0xFEC8;\n t['zainarabic'] = 0x0632;\n t['zainfinalarabic'] = 0xFEB0;\n t['zakatakana'] = 0x30B6;\n t['zaqefgadolhebrew'] = 0x0595;\n t['zaqefqatanhebrew'] = 0x0594;\n t['zarqahebrew'] = 0x0598;\n t['zayin'] = 0x05D6;\n t['zayindagesh'] = 0xFB36;\n t['zayindageshhebrew'] = 0xFB36;\n t['zayinhebrew'] = 0x05D6;\n t['zbopomofo'] = 0x3117;\n t['zcaron'] = 0x017E;\n t['zcircle'] = 0x24E9;\n t['zcircumflex'] = 0x1E91;\n t['zcurl'] = 0x0291;\n t['zdot'] = 0x017C;\n t['zdotaccent'] = 0x017C;\n t['zdotbelow'] = 0x1E93;\n t['zecyrillic'] = 0x0437;\n t['zedescendercyrillic'] = 0x0499;\n t['zedieresiscyrillic'] = 0x04DF;\n t['zehiragana'] = 0x305C;\n t['zekatakana'] = 0x30BC;\n t['zero'] = 0x0030;\n t['zeroarabic'] = 0x0660;\n t['zerobengali'] = 0x09E6;\n t['zerodeva'] = 0x0966;\n t['zerogujarati'] = 0x0AE6;\n t['zerogurmukhi'] = 0x0A66;\n t['zerohackarabic'] = 0x0660;\n t['zeroinferior'] = 0x2080;\n t['zeromonospace'] = 0xFF10;\n t['zerooldstyle'] = 0xF730;\n t['zeropersian'] = 0x06F0;\n t['zerosuperior'] = 0x2070;\n t['zerothai'] = 0x0E50;\n t['zerowidthjoiner'] = 0xFEFF;\n t['zerowidthnonjoiner'] = 0x200C;\n t['zerowidthspace'] = 0x200B;\n t['zeta'] = 0x03B6;\n t['zhbopomofo'] = 0x3113;\n t['zhearmenian'] = 0x056A;\n t['zhebrevecyrillic'] = 0x04C2;\n t['zhecyrillic'] = 0x0436;\n t['zhedescendercyrillic'] = 0x0497;\n t['zhedieresiscyrillic'] = 0x04DD;\n t['zihiragana'] = 0x3058;\n t['zikatakana'] = 0x30B8;\n t['zinorhebrew'] = 0x05AE;\n t['zlinebelow'] = 0x1E95;\n t['zmonospace'] = 0xFF5A;\n t['zohiragana'] = 0x305E;\n t['zokatakana'] = 0x30BE;\n t['zparen'] = 0x24B5;\n t['zretroflexhook'] = 0x0290;\n t['zstroke'] = 0x01B6;\n t['zuhiragana'] = 0x305A;\n t['zukatakana'] = 0x30BA;\n t['.notdef'] = 0x0000;\n\n // TeX-specific glyph names.\n t['angbracketleftbig'] = 0x2329;\n t['angbracketleftBig'] = 0x2329;\n t['angbracketleftbigg'] = 0x2329;\n t['angbracketleftBigg'] = 0x2329;\n t['angbracketrightBig'] = 0x232A;\n t['angbracketrightbig'] = 0x232A;\n t['angbracketrightBigg'] = 0x232A;\n t['angbracketrightbigg'] = 0x232A;\n t['arrowhookleft'] = 0x21AA;\n t['arrowhookright'] = 0x21A9;\n t['arrowlefttophalf'] = 0x21BC;\n t['arrowleftbothalf'] = 0x21BD;\n t['arrownortheast'] = 0x2197;\n t['arrownorthwest'] = 0x2196;\n t['arrowrighttophalf'] = 0x21C0;\n t['arrowrightbothalf'] = 0x21C1;\n t['arrowsoutheast'] = 0x2198;\n t['arrowsouthwest'] = 0x2199;\n t['backslashbig'] = 0x2216;\n t['backslashBig'] = 0x2216;\n t['backslashBigg'] = 0x2216;\n t['backslashbigg'] = 0x2216;\n t['bardbl'] = 0x2016;\n t['bracehtipdownleft'] = 0xFE37;\n t['bracehtipdownright'] = 0xFE37;\n t['bracehtipupleft'] = 0xFE38;\n t['bracehtipupright'] = 0xFE38;\n t['braceleftBig'] = 0x007B;\n t['braceleftbig'] = 0x007B;\n t['braceleftbigg'] = 0x007B;\n t['braceleftBigg'] = 0x007B;\n t['bracerightBig'] = 0x007D;\n t['bracerightbig'] = 0x007D;\n t['bracerightbigg'] = 0x007D;\n t['bracerightBigg'] = 0x007D;\n t['bracketleftbig'] = 0x005B;\n t['bracketleftBig'] = 0x005B;\n t['bracketleftbigg'] = 0x005B;\n t['bracketleftBigg'] = 0x005B;\n t['bracketrightBig'] = 0x005D;\n t['bracketrightbig'] = 0x005D;\n t['bracketrightbigg'] = 0x005D;\n t['bracketrightBigg'] = 0x005D;\n t['ceilingleftbig'] = 0x2308;\n t['ceilingleftBig'] = 0x2308;\n t['ceilingleftBigg'] = 0x2308;\n t['ceilingleftbigg'] = 0x2308;\n t['ceilingrightbig'] = 0x2309;\n t['ceilingrightBig'] = 0x2309;\n t['ceilingrightbigg'] = 0x2309;\n t['ceilingrightBigg'] = 0x2309;\n t['circledotdisplay'] = 0x2299;\n t['circledottext'] = 0x2299;\n t['circlemultiplydisplay'] = 0x2297;\n t['circlemultiplytext'] = 0x2297;\n t['circleplusdisplay'] = 0x2295;\n t['circleplustext'] = 0x2295;\n t['contintegraldisplay'] = 0x222E;\n t['contintegraltext'] = 0x222E;\n t['coproductdisplay'] = 0x2210;\n t['coproducttext'] = 0x2210;\n t['floorleftBig'] = 0x230A;\n t['floorleftbig'] = 0x230A;\n t['floorleftbigg'] = 0x230A;\n t['floorleftBigg'] = 0x230A;\n t['floorrightbig'] = 0x230B;\n t['floorrightBig'] = 0x230B;\n t['floorrightBigg'] = 0x230B;\n t['floorrightbigg'] = 0x230B;\n t['hatwide'] = 0x0302;\n t['hatwider'] = 0x0302;\n t['hatwidest'] = 0x0302;\n t['intercal'] = 0x1D40;\n t['integraldisplay'] = 0x222B;\n t['integraltext'] = 0x222B;\n t['intersectiondisplay'] = 0x22C2;\n t['intersectiontext'] = 0x22C2;\n t['logicalanddisplay'] = 0x2227;\n t['logicalandtext'] = 0x2227;\n t['logicalordisplay'] = 0x2228;\n t['logicalortext'] = 0x2228;\n t['parenleftBig'] = 0x0028;\n t['parenleftbig'] = 0x0028;\n t['parenleftBigg'] = 0x0028;\n t['parenleftbigg'] = 0x0028;\n t['parenrightBig'] = 0x0029;\n t['parenrightbig'] = 0x0029;\n t['parenrightBigg'] = 0x0029;\n t['parenrightbigg'] = 0x0029;\n t['prime'] = 0x2032;\n t['productdisplay'] = 0x220F;\n t['producttext'] = 0x220F;\n t['radicalbig'] = 0x221A;\n t['radicalBig'] = 0x221A;\n t['radicalBigg'] = 0x221A;\n t['radicalbigg'] = 0x221A;\n t['radicalbt'] = 0x221A;\n t['radicaltp'] = 0x221A;\n t['radicalvertex'] = 0x221A;\n t['slashbig'] = 0x002F;\n t['slashBig'] = 0x002F;\n t['slashBigg'] = 0x002F;\n t['slashbigg'] = 0x002F;\n t['summationdisplay'] = 0x2211;\n t['summationtext'] = 0x2211;\n t['tildewide'] = 0x02DC;\n t['tildewider'] = 0x02DC;\n t['tildewidest'] = 0x02DC;\n t['uniondisplay'] = 0x22C3;\n t['unionmultidisplay'] = 0x228E;\n t['unionmultitext'] = 0x228E;\n t['unionsqdisplay'] = 0x2294;\n t['unionsqtext'] = 0x2294;\n t['uniontext'] = 0x22C3;\n t['vextenddouble'] = 0x2225;\n t['vextendsingle'] = 0x2223;\n});\n\nvar getDingbatsGlyphsUnicode = getLookupTableFactory(function (t) {\n t['space'] = 0x0020;\n t['a1'] = 0x2701;\n t['a2'] = 0x2702;\n t['a202'] = 0x2703;\n t['a3'] = 0x2704;\n t['a4'] = 0x260E;\n t['a5'] = 0x2706;\n t['a119'] = 0x2707;\n t['a118'] = 0x2708;\n t['a117'] = 0x2709;\n t['a11'] = 0x261B;\n t['a12'] = 0x261E;\n t['a13'] = 0x270C;\n t['a14'] = 0x270D;\n t['a15'] = 0x270E;\n t['a16'] = 0x270F;\n t['a105'] = 0x2710;\n t['a17'] = 0x2711;\n t['a18'] = 0x2712;\n t['a19'] = 0x2713;\n t['a20'] = 0x2714;\n t['a21'] = 0x2715;\n t['a22'] = 0x2716;\n t['a23'] = 0x2717;\n t['a24'] = 0x2718;\n t['a25'] = 0x2719;\n t['a26'] = 0x271A;\n t['a27'] = 0x271B;\n t['a28'] = 0x271C;\n t['a6'] = 0x271D;\n t['a7'] = 0x271E;\n t['a8'] = 0x271F;\n t['a9'] = 0x2720;\n t['a10'] = 0x2721;\n t['a29'] = 0x2722;\n t['a30'] = 0x2723;\n t['a31'] = 0x2724;\n t['a32'] = 0x2725;\n t['a33'] = 0x2726;\n t['a34'] = 0x2727;\n t['a35'] = 0x2605;\n t['a36'] = 0x2729;\n t['a37'] = 0x272A;\n t['a38'] = 0x272B;\n t['a39'] = 0x272C;\n t['a40'] = 0x272D;\n t['a41'] = 0x272E;\n t['a42'] = 0x272F;\n t['a43'] = 0x2730;\n t['a44'] = 0x2731;\n t['a45'] = 0x2732;\n t['a46'] = 0x2733;\n t['a47'] = 0x2734;\n t['a48'] = 0x2735;\n t['a49'] = 0x2736;\n t['a50'] = 0x2737;\n t['a51'] = 0x2738;\n t['a52'] = 0x2739;\n t['a53'] = 0x273A;\n t['a54'] = 0x273B;\n t['a55'] = 0x273C;\n t['a56'] = 0x273D;\n t['a57'] = 0x273E;\n t['a58'] = 0x273F;\n t['a59'] = 0x2740;\n t['a60'] = 0x2741;\n t['a61'] = 0x2742;\n t['a62'] = 0x2743;\n t['a63'] = 0x2744;\n t['a64'] = 0x2745;\n t['a65'] = 0x2746;\n t['a66'] = 0x2747;\n t['a67'] = 0x2748;\n t['a68'] = 0x2749;\n t['a69'] = 0x274A;\n t['a70'] = 0x274B;\n t['a71'] = 0x25CF;\n t['a72'] = 0x274D;\n t['a73'] = 0x25A0;\n t['a74'] = 0x274F;\n t['a203'] = 0x2750;\n t['a75'] = 0x2751;\n t['a204'] = 0x2752;\n t['a76'] = 0x25B2;\n t['a77'] = 0x25BC;\n t['a78'] = 0x25C6;\n t['a79'] = 0x2756;\n t['a81'] = 0x25D7;\n t['a82'] = 0x2758;\n t['a83'] = 0x2759;\n t['a84'] = 0x275A;\n t['a97'] = 0x275B;\n t['a98'] = 0x275C;\n t['a99'] = 0x275D;\n t['a100'] = 0x275E;\n t['a101'] = 0x2761;\n t['a102'] = 0x2762;\n t['a103'] = 0x2763;\n t['a104'] = 0x2764;\n t['a106'] = 0x2765;\n t['a107'] = 0x2766;\n t['a108'] = 0x2767;\n t['a112'] = 0x2663;\n t['a111'] = 0x2666;\n t['a110'] = 0x2665;\n t['a109'] = 0x2660;\n t['a120'] = 0x2460;\n t['a121'] = 0x2461;\n t['a122'] = 0x2462;\n t['a123'] = 0x2463;\n t['a124'] = 0x2464;\n t['a125'] = 0x2465;\n t['a126'] = 0x2466;\n t['a127'] = 0x2467;\n t['a128'] = 0x2468;\n t['a129'] = 0x2469;\n t['a130'] = 0x2776;\n t['a131'] = 0x2777;\n t['a132'] = 0x2778;\n t['a133'] = 0x2779;\n t['a134'] = 0x277A;\n t['a135'] = 0x277B;\n t['a136'] = 0x277C;\n t['a137'] = 0x277D;\n t['a138'] = 0x277E;\n t['a139'] = 0x277F;\n t['a140'] = 0x2780;\n t['a141'] = 0x2781;\n t['a142'] = 0x2782;\n t['a143'] = 0x2783;\n t['a144'] = 0x2784;\n t['a145'] = 0x2785;\n t['a146'] = 0x2786;\n t['a147'] = 0x2787;\n t['a148'] = 0x2788;\n t['a149'] = 0x2789;\n t['a150'] = 0x278A;\n t['a151'] = 0x278B;\n t['a152'] = 0x278C;\n t['a153'] = 0x278D;\n t['a154'] = 0x278E;\n t['a155'] = 0x278F;\n t['a156'] = 0x2790;\n t['a157'] = 0x2791;\n t['a158'] = 0x2792;\n t['a159'] = 0x2793;\n t['a160'] = 0x2794;\n t['a161'] = 0x2192;\n t['a163'] = 0x2194;\n t['a164'] = 0x2195;\n t['a196'] = 0x2798;\n t['a165'] = 0x2799;\n t['a192'] = 0x279A;\n t['a166'] = 0x279B;\n t['a167'] = 0x279C;\n t['a168'] = 0x279D;\n t['a169'] = 0x279E;\n t['a170'] = 0x279F;\n t['a171'] = 0x27A0;\n t['a172'] = 0x27A1;\n t['a173'] = 0x27A2;\n t['a162'] = 0x27A3;\n t['a174'] = 0x27A4;\n t['a175'] = 0x27A5;\n t['a176'] = 0x27A6;\n t['a177'] = 0x27A7;\n t['a178'] = 0x27A8;\n t['a179'] = 0x27A9;\n t['a193'] = 0x27AA;\n t['a180'] = 0x27AB;\n t['a199'] = 0x27AC;\n t['a181'] = 0x27AD;\n t['a200'] = 0x27AE;\n t['a182'] = 0x27AF;\n t['a201'] = 0x27B1;\n t['a183'] = 0x27B2;\n t['a184'] = 0x27B3;\n t['a197'] = 0x27B4;\n t['a185'] = 0x27B5;\n t['a194'] = 0x27B6;\n t['a198'] = 0x27B7;\n t['a186'] = 0x27B8;\n t['a195'] = 0x27B9;\n t['a187'] = 0x27BA;\n t['a188'] = 0x27BB;\n t['a189'] = 0x27BC;\n t['a190'] = 0x27BD;\n t['a191'] = 0x27BE;\n t['a89'] = 0x2768; // 0xF8D7\n t['a90'] = 0x2769; // 0xF8D8\n t['a93'] = 0x276A; // 0xF8D9\n t['a94'] = 0x276B; // 0xF8DA\n t['a91'] = 0x276C; // 0xF8DB\n t['a92'] = 0x276D; // 0xF8DC\n t['a205'] = 0x276E; // 0xF8DD\n t['a85'] = 0x276F; // 0xF8DE\n t['a206'] = 0x2770; // 0xF8DF\n t['a86'] = 0x2771; // 0xF8E0\n t['a87'] = 0x2772; // 0xF8E1\n t['a88'] = 0x2773; // 0xF8E2\n t['a95'] = 0x2774; // 0xF8E3\n t['a96'] = 0x2775; // 0xF8E4\n t['.notdef'] = 0x0000;\n});\n\nexports.getGlyphsUnicode = getGlyphsUnicode;\nexports.getDingbatsGlyphsUnicode = getDingbatsGlyphsUnicode;\n\n\n\n// WEBPACK FOOTER //\n// src/core/glyphlist.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FormatError, info, isArray, isBool } from '../shared/util';\nimport { isDict, isStream } from './primitives';\nimport { PostScriptLexer, PostScriptParser } from './ps_parser';\n\nvar PDFFunction = (function PDFFunctionClosure() {\n var CONSTRUCT_SAMPLED = 0;\n var CONSTRUCT_INTERPOLATED = 2;\n var CONSTRUCT_STICHED = 3;\n var CONSTRUCT_POSTSCRIPT = 4;\n\n return {\n getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps,\n str) {\n var i, ii;\n var length = 1;\n for (i = 0, ii = size.length; i < ii; i++) {\n length *= size[i];\n }\n length *= outputSize;\n\n var array = new Array(length);\n var codeSize = 0;\n var codeBuf = 0;\n // 32 is a valid bps so shifting won't work\n var sampleMul = 1.0 / (Math.pow(2.0, bps) - 1);\n\n var strBytes = str.getBytes((length * bps + 7) / 8);\n var strIdx = 0;\n for (i = 0; i < length; i++) {\n while (codeSize < bps) {\n codeBuf <<= 8;\n codeBuf |= strBytes[strIdx++];\n codeSize += 8;\n }\n codeSize -= bps;\n array[i] = (codeBuf >> codeSize) * sampleMul;\n codeBuf &= (1 << codeSize) - 1;\n }\n return array;\n },\n\n getIR: function PDFFunction_getIR(xref, fn) {\n var dict = fn.dict;\n if (!dict) {\n dict = fn;\n }\n\n var types = [this.constructSampled,\n null,\n this.constructInterpolated,\n this.constructStiched,\n this.constructPostScript];\n\n var typeNum = dict.get('FunctionType');\n var typeFn = types[typeNum];\n if (!typeFn) {\n throw new FormatError('Unknown type of function');\n }\n\n return typeFn.call(this, fn, dict, xref);\n },\n\n fromIR: function PDFFunction_fromIR(IR) {\n var type = IR[0];\n switch (type) {\n case CONSTRUCT_SAMPLED:\n return this.constructSampledFromIR(IR);\n case CONSTRUCT_INTERPOLATED:\n return this.constructInterpolatedFromIR(IR);\n case CONSTRUCT_STICHED:\n return this.constructStichedFromIR(IR);\n // case CONSTRUCT_POSTSCRIPT:\n default:\n return this.constructPostScriptFromIR(IR);\n }\n },\n\n parse: function PDFFunction_parse(xref, fn) {\n var IR = this.getIR(xref, fn);\n return this.fromIR(IR);\n },\n\n parseArray: function PDFFunction_parseArray(xref, fnObj) {\n if (!isArray(fnObj)) {\n // not an array -- parsing as regular function\n return this.parse(xref, fnObj);\n }\n\n var fnArray = [];\n for (var j = 0, jj = fnObj.length; j < jj; j++) {\n var obj = xref.fetchIfRef(fnObj[j]);\n fnArray.push(PDFFunction.parse(xref, obj));\n }\n return function (src, srcOffset, dest, destOffset) {\n for (var i = 0, ii = fnArray.length; i < ii; i++) {\n fnArray[i](src, srcOffset, dest, destOffset + i);\n }\n };\n },\n\n constructSampled: function PDFFunction_constructSampled(str, dict) {\n function toMultiArray(arr) {\n var inputLength = arr.length;\n var out = [];\n var index = 0;\n for (var i = 0; i < inputLength; i += 2) {\n out[index] = [arr[i], arr[i + 1]];\n ++index;\n }\n return out;\n }\n var domain = dict.getArray('Domain');\n var range = dict.getArray('Range');\n\n if (!domain || !range) {\n throw new FormatError('No domain or range');\n }\n\n var inputSize = domain.length / 2;\n var outputSize = range.length / 2;\n\n domain = toMultiArray(domain);\n range = toMultiArray(range);\n\n var size = dict.get('Size');\n var bps = dict.get('BitsPerSample');\n var order = dict.get('Order') || 1;\n if (order !== 1) {\n // No description how cubic spline interpolation works in PDF32000:2008\n // As in poppler, ignoring order, linear interpolation may work as good\n info('No support for cubic spline interpolation: ' + order);\n }\n\n var encode = dict.getArray('Encode');\n if (!encode) {\n encode = [];\n for (var i = 0; i < inputSize; ++i) {\n encode.push(0);\n encode.push(size[i] - 1);\n }\n }\n encode = toMultiArray(encode);\n\n var decode = dict.getArray('Decode');\n if (!decode) {\n decode = range;\n } else {\n decode = toMultiArray(decode);\n }\n\n var samples = this.getSampleArray(size, outputSize, bps, str);\n\n return [\n CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size,\n outputSize, Math.pow(2, bps) - 1, range\n ];\n },\n\n constructSampledFromIR: function PDFFunction_constructSampledFromIR(IR) {\n // See chapter 3, page 109 of the PDF reference\n function interpolate(x, xmin, xmax, ymin, ymax) {\n return ymin + ((x - xmin) * ((ymax - ymin) / (xmax - xmin)));\n }\n\n return function constructSampledFromIRResult(src, srcOffset,\n dest, destOffset) {\n // See chapter 3, page 110 of the PDF reference.\n var m = IR[1];\n var domain = IR[2];\n var encode = IR[3];\n var decode = IR[4];\n var samples = IR[5];\n var size = IR[6];\n var n = IR[7];\n // var mask = IR[8];\n var range = IR[9];\n\n // Building the cube vertices: its part and sample index\n // http://rjwagner49.com/Mathematics/Interpolation.pdf\n var cubeVertices = 1 << m;\n var cubeN = new Float64Array(cubeVertices);\n var cubeVertex = new Uint32Array(cubeVertices);\n var i, j;\n for (j = 0; j < cubeVertices; j++) {\n cubeN[j] = 1;\n }\n\n var k = n, pos = 1;\n // Map x_i to y_j for 0 <= i < m using the sampled function.\n for (i = 0; i < m; ++i) {\n // x_i' = min(max(x_i, Domain_2i), Domain_2i+1)\n var domain_2i = domain[i][0];\n var domain_2i_1 = domain[i][1];\n var xi = Math.min(Math.max(src[srcOffset + i], domain_2i),\n domain_2i_1);\n\n // e_i = Interpolate(x_i', Domain_2i, Domain_2i+1,\n // Encode_2i, Encode_2i+1)\n var e = interpolate(xi, domain_2i, domain_2i_1,\n encode[i][0], encode[i][1]);\n\n // e_i' = min(max(e_i, 0), Size_i - 1)\n var size_i = size[i];\n e = Math.min(Math.max(e, 0), size_i - 1);\n\n // Adjusting the cube: N and vertex sample index\n var e0 = e < size_i - 1 ? Math.floor(e) : e - 1; // e1 = e0 + 1;\n var n0 = e0 + 1 - e; // (e1 - e) / (e1 - e0);\n var n1 = e - e0; // (e - e0) / (e1 - e0);\n var offset0 = e0 * k;\n var offset1 = offset0 + k; // e1 * k\n for (j = 0; j < cubeVertices; j++) {\n if (j & pos) {\n cubeN[j] *= n1;\n cubeVertex[j] += offset1;\n } else {\n cubeN[j] *= n0;\n cubeVertex[j] += offset0;\n }\n }\n\n k *= size_i;\n pos <<= 1;\n }\n\n for (j = 0; j < n; ++j) {\n // Sum all cube vertices' samples portions\n var rj = 0;\n for (i = 0; i < cubeVertices; i++) {\n rj += samples[cubeVertex[i] + j] * cubeN[i];\n }\n\n // r_j' = Interpolate(r_j, 0, 2^BitsPerSample - 1,\n // Decode_2j, Decode_2j+1)\n rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]);\n\n // y_j = min(max(r_j, range_2j), range_2j+1)\n dest[destOffset + j] = Math.min(Math.max(rj, range[j][0]),\n range[j][1]);\n }\n };\n },\n\n constructInterpolated: function PDFFunction_constructInterpolated(str,\n dict) {\n var c0 = dict.getArray('C0') || [0];\n var c1 = dict.getArray('C1') || [1];\n var n = dict.get('N');\n\n if (!isArray(c0) || !isArray(c1)) {\n throw new FormatError(\n 'Illegal dictionary for interpolated function');\n }\n\n var length = c0.length;\n var diff = [];\n for (var i = 0; i < length; ++i) {\n diff.push(c1[i] - c0[i]);\n }\n\n return [CONSTRUCT_INTERPOLATED, c0, diff, n];\n },\n\n constructInterpolatedFromIR:\n function PDFFunction_constructInterpolatedFromIR(IR) {\n var c0 = IR[1];\n var diff = IR[2];\n var n = IR[3];\n\n var length = diff.length;\n\n return function constructInterpolatedFromIRResult(src, srcOffset,\n dest, destOffset) {\n var x = n === 1 ? src[srcOffset] : Math.pow(src[srcOffset], n);\n\n for (var j = 0; j < length; ++j) {\n dest[destOffset + j] = c0[j] + (x * diff[j]);\n }\n };\n },\n\n constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {\n var domain = dict.getArray('Domain');\n\n if (!domain) {\n throw new FormatError('No domain');\n }\n\n var inputSize = domain.length / 2;\n if (inputSize !== 1) {\n throw new FormatError('Bad domain for stiched function');\n }\n\n var fnRefs = dict.get('Functions');\n var fns = [];\n for (var i = 0, ii = fnRefs.length; i < ii; ++i) {\n fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i])));\n }\n\n var bounds = dict.getArray('Bounds');\n var encode = dict.getArray('Encode');\n\n return [CONSTRUCT_STICHED, domain, bounds, encode, fns];\n },\n\n constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) {\n var domain = IR[1];\n var bounds = IR[2];\n var encode = IR[3];\n var fnsIR = IR[4];\n var fns = [];\n var tmpBuf = new Float32Array(1);\n\n for (var i = 0, ii = fnsIR.length; i < ii; i++) {\n fns.push(PDFFunction.fromIR(fnsIR[i]));\n }\n\n return function constructStichedFromIRResult(src, srcOffset,\n dest, destOffset) {\n var clip = function constructStichedFromIRClip(v, min, max) {\n if (v > max) {\n v = max;\n } else if (v < min) {\n v = min;\n }\n return v;\n };\n\n // clip to domain\n var v = clip(src[srcOffset], domain[0], domain[1]);\n // calculate which bound the value is in\n for (var i = 0, ii = bounds.length; i < ii; ++i) {\n if (v < bounds[i]) {\n break;\n }\n }\n\n // encode value into domain of function\n var dmin = domain[0];\n if (i > 0) {\n dmin = bounds[i - 1];\n }\n var dmax = domain[1];\n if (i < bounds.length) {\n dmax = bounds[i];\n }\n\n var rmin = encode[2 * i];\n var rmax = encode[2 * i + 1];\n\n // Prevent the value from becoming NaN as a result\n // of division by zero (fixes issue6113.pdf).\n tmpBuf[0] = dmin === dmax ? rmin :\n rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);\n\n // call the appropriate function\n fns[i](tmpBuf, 0, dest, destOffset);\n };\n },\n\n constructPostScript: function PDFFunction_constructPostScript(fn, dict,\n xref) {\n var domain = dict.getArray('Domain');\n var range = dict.getArray('Range');\n\n if (!domain) {\n throw new FormatError('No domain.');\n }\n\n if (!range) {\n throw new FormatError('No range.');\n }\n\n var lexer = new PostScriptLexer(fn);\n var parser = new PostScriptParser(lexer);\n var code = parser.parse();\n\n return [CONSTRUCT_POSTSCRIPT, domain, range, code];\n },\n\n constructPostScriptFromIR: function PDFFunction_constructPostScriptFromIR(\n IR) {\n var domain = IR[1];\n var range = IR[2];\n var code = IR[3];\n\n var compiled = (new PostScriptCompiler()).compile(code, domain, range);\n if (compiled) {\n // Compiled function consists of simple expressions such as addition,\n // subtraction, Math.max, and also contains 'var' and 'return'\n // statements. See the generation in the PostScriptCompiler below.\n // eslint-disable-next-line no-new-func\n return new Function('src', 'srcOffset', 'dest', 'destOffset', compiled);\n }\n\n info('Unable to compile PS function');\n\n var numOutputs = range.length >> 1;\n var numInputs = domain.length >> 1;\n var evaluator = new PostScriptEvaluator(code);\n // Cache the values for a big speed up, the cache size is limited though\n // since the number of possible values can be huge from a PS function.\n var cache = Object.create(null);\n // The MAX_CACHE_SIZE is set to ~4x the maximum number of distinct values\n // seen in our tests.\n var MAX_CACHE_SIZE = 2048 * 4;\n var cache_available = MAX_CACHE_SIZE;\n var tmpBuf = new Float32Array(numInputs);\n\n return function constructPostScriptFromIRResult(src, srcOffset,\n dest, destOffset) {\n var i, value;\n var key = '';\n var input = tmpBuf;\n for (i = 0; i < numInputs; i++) {\n value = src[srcOffset + i];\n input[i] = value;\n key += value + '_';\n }\n\n var cachedValue = cache[key];\n if (cachedValue !== undefined) {\n dest.set(cachedValue, destOffset);\n return;\n }\n\n var output = new Float32Array(numOutputs);\n var stack = evaluator.execute(input);\n var stackIndex = stack.length - numOutputs;\n for (i = 0; i < numOutputs; i++) {\n value = stack[stackIndex + i];\n var bound = range[i * 2];\n if (value < bound) {\n value = bound;\n } else {\n bound = range[i * 2 + 1];\n if (value > bound) {\n value = bound;\n }\n }\n output[i] = value;\n }\n if (cache_available > 0) {\n cache_available--;\n cache[key] = output;\n }\n dest.set(output, destOffset);\n };\n },\n };\n})();\n\nfunction isPDFFunction(v) {\n var fnDict;\n if (typeof v !== 'object') {\n return false;\n } else if (isDict(v)) {\n fnDict = v;\n } else if (isStream(v)) {\n fnDict = v.dict;\n } else {\n return false;\n }\n return fnDict.has('FunctionType');\n}\n\nvar PostScriptStack = (function PostScriptStackClosure() {\n var MAX_STACK_SIZE = 100;\n function PostScriptStack(initialStack) {\n this.stack = !initialStack ? [] :\n Array.prototype.slice.call(initialStack, 0);\n }\n\n PostScriptStack.prototype = {\n push: function PostScriptStack_push(value) {\n if (this.stack.length >= MAX_STACK_SIZE) {\n throw new Error('PostScript function stack overflow.');\n }\n this.stack.push(value);\n },\n pop: function PostScriptStack_pop() {\n if (this.stack.length <= 0) {\n throw new Error('PostScript function stack underflow.');\n }\n return this.stack.pop();\n },\n copy: function PostScriptStack_copy(n) {\n if (this.stack.length + n >= MAX_STACK_SIZE) {\n throw new Error('PostScript function stack overflow.');\n }\n var stack = this.stack;\n for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++) {\n stack.push(stack[i]);\n }\n },\n index: function PostScriptStack_index(n) {\n this.push(this.stack[this.stack.length - n - 1]);\n },\n // rotate the last n stack elements p times\n roll: function PostScriptStack_roll(n, p) {\n var stack = this.stack;\n var l = stack.length - n;\n var r = stack.length - 1, c = l + (p - Math.floor(p / n) * n), i, j, t;\n for (i = l, j = r; i < j; i++, j--) {\n t = stack[i]; stack[i] = stack[j]; stack[j] = t;\n }\n for (i = l, j = c - 1; i < j; i++, j--) {\n t = stack[i]; stack[i] = stack[j]; stack[j] = t;\n }\n for (i = c, j = r; i < j; i++, j--) {\n t = stack[i]; stack[i] = stack[j]; stack[j] = t;\n }\n },\n };\n return PostScriptStack;\n})();\nvar PostScriptEvaluator = (function PostScriptEvaluatorClosure() {\n function PostScriptEvaluator(operators) {\n this.operators = operators;\n }\n PostScriptEvaluator.prototype = {\n execute: function PostScriptEvaluator_execute(initialStack) {\n var stack = new PostScriptStack(initialStack);\n var counter = 0;\n var operators = this.operators;\n var length = operators.length;\n var operator, a, b;\n while (counter < length) {\n operator = operators[counter++];\n if (typeof operator === 'number') {\n // Operator is really an operand and should be pushed to the stack.\n stack.push(operator);\n continue;\n }\n switch (operator) {\n // non standard ps operators\n case 'jz': // jump if false\n b = stack.pop();\n a = stack.pop();\n if (!a) {\n counter = b;\n }\n break;\n case 'j': // jump\n a = stack.pop();\n counter = a;\n break;\n\n // all ps operators in alphabetical order (excluding if/ifelse)\n case 'abs':\n a = stack.pop();\n stack.push(Math.abs(a));\n break;\n case 'add':\n b = stack.pop();\n a = stack.pop();\n stack.push(a + b);\n break;\n case 'and':\n b = stack.pop();\n a = stack.pop();\n if (isBool(a) && isBool(b)) {\n stack.push(a && b);\n } else {\n stack.push(a & b);\n }\n break;\n case 'atan':\n a = stack.pop();\n stack.push(Math.atan(a));\n break;\n case 'bitshift':\n b = stack.pop();\n a = stack.pop();\n if (a > 0) {\n stack.push(a << b);\n } else {\n stack.push(a >> b);\n }\n break;\n case 'ceiling':\n a = stack.pop();\n stack.push(Math.ceil(a));\n break;\n case 'copy':\n a = stack.pop();\n stack.copy(a);\n break;\n case 'cos':\n a = stack.pop();\n stack.push(Math.cos(a));\n break;\n case 'cvi':\n a = stack.pop() | 0;\n stack.push(a);\n break;\n case 'cvr':\n // noop\n break;\n case 'div':\n b = stack.pop();\n a = stack.pop();\n stack.push(a / b);\n break;\n case 'dup':\n stack.copy(1);\n break;\n case 'eq':\n b = stack.pop();\n a = stack.pop();\n stack.push(a === b);\n break;\n case 'exch':\n stack.roll(2, 1);\n break;\n case 'exp':\n b = stack.pop();\n a = stack.pop();\n stack.push(Math.pow(a, b));\n break;\n case 'false':\n stack.push(false);\n break;\n case 'floor':\n a = stack.pop();\n stack.push(Math.floor(a));\n break;\n case 'ge':\n b = stack.pop();\n a = stack.pop();\n stack.push(a >= b);\n break;\n case 'gt':\n b = stack.pop();\n a = stack.pop();\n stack.push(a > b);\n break;\n case 'idiv':\n b = stack.pop();\n a = stack.pop();\n stack.push((a / b) | 0);\n break;\n case 'index':\n a = stack.pop();\n stack.index(a);\n break;\n case 'le':\n b = stack.pop();\n a = stack.pop();\n stack.push(a <= b);\n break;\n case 'ln':\n a = stack.pop();\n stack.push(Math.log(a));\n break;\n case 'log':\n a = stack.pop();\n stack.push(Math.log(a) / Math.LN10);\n break;\n case 'lt':\n b = stack.pop();\n a = stack.pop();\n stack.push(a < b);\n break;\n case 'mod':\n b = stack.pop();\n a = stack.pop();\n stack.push(a % b);\n break;\n case 'mul':\n b = stack.pop();\n a = stack.pop();\n stack.push(a * b);\n break;\n case 'ne':\n b = stack.pop();\n a = stack.pop();\n stack.push(a !== b);\n break;\n case 'neg':\n a = stack.pop();\n stack.push(-a);\n break;\n case 'not':\n a = stack.pop();\n if (isBool(a)) {\n stack.push(!a);\n } else {\n stack.push(~a);\n }\n break;\n case 'or':\n b = stack.pop();\n a = stack.pop();\n if (isBool(a) && isBool(b)) {\n stack.push(a || b);\n } else {\n stack.push(a | b);\n }\n break;\n case 'pop':\n stack.pop();\n break;\n case 'roll':\n b = stack.pop();\n a = stack.pop();\n stack.roll(a, b);\n break;\n case 'round':\n a = stack.pop();\n stack.push(Math.round(a));\n break;\n case 'sin':\n a = stack.pop();\n stack.push(Math.sin(a));\n break;\n case 'sqrt':\n a = stack.pop();\n stack.push(Math.sqrt(a));\n break;\n case 'sub':\n b = stack.pop();\n a = stack.pop();\n stack.push(a - b);\n break;\n case 'true':\n stack.push(true);\n break;\n case 'truncate':\n a = stack.pop();\n a = a < 0 ? Math.ceil(a) : Math.floor(a);\n stack.push(a);\n break;\n case 'xor':\n b = stack.pop();\n a = stack.pop();\n if (isBool(a) && isBool(b)) {\n stack.push(a !== b);\n } else {\n stack.push(a ^ b);\n }\n break;\n default:\n throw new FormatError(`Unknown operator ${operator}`);\n }\n }\n return stack.stack;\n },\n };\n return PostScriptEvaluator;\n})();\n\n// Most of the PDFs functions consist of simple operations such as:\n// roll, exch, sub, cvr, pop, index, dup, mul, if, gt, add.\n//\n// We can compile most of such programs, and at the same moment, we can\n// optimize some expressions using basic math properties. Keeping track of\n// min/max values will allow us to avoid extra Math.min/Math.max calls.\nvar PostScriptCompiler = (function PostScriptCompilerClosure() {\n function AstNode(type) {\n this.type = type;\n }\n AstNode.prototype.visit = function (visitor) {\n throw new Error('abstract method');\n };\n\n function AstArgument(index, min, max) {\n AstNode.call(this, 'args');\n this.index = index;\n this.min = min;\n this.max = max;\n }\n AstArgument.prototype = Object.create(AstNode.prototype);\n AstArgument.prototype.visit = function (visitor) {\n visitor.visitArgument(this);\n };\n\n function AstLiteral(number) {\n AstNode.call(this, 'literal');\n this.number = number;\n this.min = number;\n this.max = number;\n }\n AstLiteral.prototype = Object.create(AstNode.prototype);\n AstLiteral.prototype.visit = function (visitor) {\n visitor.visitLiteral(this);\n };\n\n function AstBinaryOperation(op, arg1, arg2, min, max) {\n AstNode.call(this, 'binary');\n this.op = op;\n this.arg1 = arg1;\n this.arg2 = arg2;\n this.min = min;\n this.max = max;\n }\n AstBinaryOperation.prototype = Object.create(AstNode.prototype);\n AstBinaryOperation.prototype.visit = function (visitor) {\n visitor.visitBinaryOperation(this);\n };\n\n function AstMin(arg, max) {\n AstNode.call(this, 'max');\n this.arg = arg;\n this.min = arg.min;\n this.max = max;\n }\n AstMin.prototype = Object.create(AstNode.prototype);\n AstMin.prototype.visit = function (visitor) {\n visitor.visitMin(this);\n };\n\n function AstVariable(index, min, max) {\n AstNode.call(this, 'var');\n this.index = index;\n this.min = min;\n this.max = max;\n }\n AstVariable.prototype = Object.create(AstNode.prototype);\n AstVariable.prototype.visit = function (visitor) {\n visitor.visitVariable(this);\n };\n\n function AstVariableDefinition(variable, arg) {\n AstNode.call(this, 'definition');\n this.variable = variable;\n this.arg = arg;\n }\n AstVariableDefinition.prototype = Object.create(AstNode.prototype);\n AstVariableDefinition.prototype.visit = function (visitor) {\n visitor.visitVariableDefinition(this);\n };\n\n function ExpressionBuilderVisitor() {\n this.parts = [];\n }\n ExpressionBuilderVisitor.prototype = {\n visitArgument(arg) {\n this.parts.push('Math.max(', arg.min, ', Math.min(',\n arg.max, ', src[srcOffset + ', arg.index, ']))');\n },\n visitVariable(variable) {\n this.parts.push('v', variable.index);\n },\n visitLiteral(literal) {\n this.parts.push(literal.number);\n },\n visitBinaryOperation(operation) {\n this.parts.push('(');\n operation.arg1.visit(this);\n this.parts.push(' ', operation.op, ' ');\n operation.arg2.visit(this);\n this.parts.push(')');\n },\n visitVariableDefinition(definition) {\n this.parts.push('var ');\n definition.variable.visit(this);\n this.parts.push(' = ');\n definition.arg.visit(this);\n this.parts.push(';');\n },\n visitMin(max) {\n this.parts.push('Math.min(');\n max.arg.visit(this);\n this.parts.push(', ', max.max, ')');\n },\n toString() {\n return this.parts.join('');\n },\n };\n\n function buildAddOperation(num1, num2) {\n if (num2.type === 'literal' && num2.number === 0) {\n // optimization: second operand is 0\n return num1;\n }\n if (num1.type === 'literal' && num1.number === 0) {\n // optimization: first operand is 0\n return num2;\n }\n if (num2.type === 'literal' && num1.type === 'literal') {\n // optimization: operands operand are literals\n return new AstLiteral(num1.number + num2.number);\n }\n return new AstBinaryOperation('+', num1, num2,\n num1.min + num2.min, num1.max + num2.max);\n }\n\n function buildMulOperation(num1, num2) {\n if (num2.type === 'literal') {\n // optimization: second operands is a literal...\n if (num2.number === 0) {\n return new AstLiteral(0); // and it's 0\n } else if (num2.number === 1) {\n return num1; // and it's 1\n } else if (num1.type === 'literal') {\n // ... and first operands is a literal too\n return new AstLiteral(num1.number * num2.number);\n }\n }\n if (num1.type === 'literal') {\n // optimization: first operands is a literal...\n if (num1.number === 0) {\n return new AstLiteral(0); // and it's 0\n } else if (num1.number === 1) {\n return num2; // and it's 1\n }\n }\n var min = Math.min(num1.min * num2.min, num1.min * num2.max,\n num1.max * num2.min, num1.max * num2.max);\n var max = Math.max(num1.min * num2.min, num1.min * num2.max,\n num1.max * num2.min, num1.max * num2.max);\n return new AstBinaryOperation('*', num1, num2, min, max);\n }\n\n function buildSubOperation(num1, num2) {\n if (num2.type === 'literal') {\n // optimization: second operands is a literal...\n if (num2.number === 0) {\n return num1; // ... and it's 0\n } else if (num1.type === 'literal') {\n // ... and first operands is a literal too\n return new AstLiteral(num1.number - num2.number);\n }\n }\n if (num2.type === 'binary' && num2.op === '-' &&\n num1.type === 'literal' && num1.number === 1 &&\n num2.arg1.type === 'literal' && num2.arg1.number === 1) {\n // optimization for case: 1 - (1 - x)\n return num2.arg2;\n }\n return new AstBinaryOperation('-', num1, num2,\n num1.min - num2.max, num1.max - num2.min);\n }\n\n function buildMinOperation(num1, max) {\n if (num1.min >= max) {\n // optimization: num1 min value is not less than required max\n return new AstLiteral(max); // just returning max\n } else if (num1.max <= max) {\n // optimization: num1 max value is not greater than required max\n return num1; // just returning an argument\n }\n return new AstMin(num1, max);\n }\n\n function PostScriptCompiler() {}\n PostScriptCompiler.prototype = {\n compile: function PostScriptCompiler_compile(code, domain, range) {\n var stack = [];\n var i, ii;\n var instructions = [];\n var inputSize = domain.length >> 1, outputSize = range.length >> 1;\n var lastRegister = 0;\n var n, j;\n var num1, num2, ast1, ast2, tmpVar, item;\n for (i = 0; i < inputSize; i++) {\n stack.push(new AstArgument(i, domain[i * 2], domain[i * 2 + 1]));\n }\n\n for (i = 0, ii = code.length; i < ii; i++) {\n item = code[i];\n if (typeof item === 'number') {\n stack.push(new AstLiteral(item));\n continue;\n }\n\n switch (item) {\n case 'add':\n if (stack.length < 2) {\n return null;\n }\n num2 = stack.pop();\n num1 = stack.pop();\n stack.push(buildAddOperation(num1, num2));\n break;\n case 'cvr':\n if (stack.length < 1) {\n return null;\n }\n break;\n case 'mul':\n if (stack.length < 2) {\n return null;\n }\n num2 = stack.pop();\n num1 = stack.pop();\n stack.push(buildMulOperation(num1, num2));\n break;\n case 'sub':\n if (stack.length < 2) {\n return null;\n }\n num2 = stack.pop();\n num1 = stack.pop();\n stack.push(buildSubOperation(num1, num2));\n break;\n case 'exch':\n if (stack.length < 2) {\n return null;\n }\n ast1 = stack.pop(); ast2 = stack.pop();\n stack.push(ast1, ast2);\n break;\n case 'pop':\n if (stack.length < 1) {\n return null;\n }\n stack.pop();\n break;\n case 'index':\n if (stack.length < 1) {\n return null;\n }\n num1 = stack.pop();\n if (num1.type !== 'literal') {\n return null;\n }\n n = num1.number;\n if (n < 0 || (n | 0) !== n || stack.length < n) {\n return null;\n }\n ast1 = stack[stack.length - n - 1];\n if (ast1.type === 'literal' || ast1.type === 'var') {\n stack.push(ast1);\n break;\n }\n tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max);\n stack[stack.length - n - 1] = tmpVar;\n stack.push(tmpVar);\n instructions.push(new AstVariableDefinition(tmpVar, ast1));\n break;\n case 'dup':\n if (stack.length < 1) {\n return null;\n }\n if (typeof code[i + 1] === 'number' && code[i + 2] === 'gt' &&\n code[i + 3] === i + 7 && code[i + 4] === 'jz' &&\n code[i + 5] === 'pop' && code[i + 6] === code[i + 1]) {\n // special case of the commands sequence for the min operation\n num1 = stack.pop();\n stack.push(buildMinOperation(num1, code[i + 1]));\n i += 6;\n break;\n }\n ast1 = stack[stack.length - 1];\n if (ast1.type === 'literal' || ast1.type === 'var') {\n // we don't have to save into intermediate variable a literal or\n // variable.\n stack.push(ast1);\n break;\n }\n tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max);\n stack[stack.length - 1] = tmpVar;\n stack.push(tmpVar);\n instructions.push(new AstVariableDefinition(tmpVar, ast1));\n break;\n case 'roll':\n if (stack.length < 2) {\n return null;\n }\n num2 = stack.pop();\n num1 = stack.pop();\n if (num2.type !== 'literal' || num1.type !== 'literal') {\n // both roll operands must be numbers\n return null;\n }\n j = num2.number;\n n = num1.number;\n if (n <= 0 || (n | 0) !== n || (j | 0) !== j || stack.length < n) {\n // ... and integers\n return null;\n }\n j = ((j % n) + n) % n;\n if (j === 0) {\n break; // just skipping -- there are nothing to rotate\n }\n Array.prototype.push.apply(stack,\n stack.splice(stack.length - n, n - j));\n break;\n default:\n return null; // unsupported operator\n }\n }\n\n if (stack.length !== outputSize) {\n return null;\n }\n\n var result = [];\n instructions.forEach(function (instruction) {\n var statementBuilder = new ExpressionBuilderVisitor();\n instruction.visit(statementBuilder);\n result.push(statementBuilder.toString());\n });\n stack.forEach(function (expr, i) {\n var statementBuilder = new ExpressionBuilderVisitor();\n expr.visit(statementBuilder);\n var min = range[i * 2], max = range[i * 2 + 1];\n var out = [statementBuilder.toString()];\n if (min > expr.min) {\n out.unshift('Math.max(', min, ', ');\n out.push(')');\n }\n if (max < expr.max) {\n out.unshift('Math.min(', max, ', ');\n out.push(')');\n }\n out.unshift('dest[destOffset + ', i, '] = ');\n out.push(';');\n result.push(out.join(''));\n });\n return result.join('\\n');\n },\n };\n\n return PostScriptCompiler;\n})();\n\nexport {\n isPDFFunction,\n PDFFunction,\n PostScriptEvaluator,\n PostScriptCompiler,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/function.js","/* Copyright 2016 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* no-babel-preset */\n\nvar getLookupTableFactory = require('../shared/util').getLookupTableFactory;\n\n// Some characters, e.g. copyrightserif, are mapped to the private use area\n// and might not be displayed using standard fonts. Mapping/hacking well-known\n// chars to the similar equivalents in the normal characters range.\nvar getSpecialPUASymbols = getLookupTableFactory(function (t) {\n t[63721] = 0x00A9; // copyrightsans (0xF8E9) => copyright\n t[63193] = 0x00A9; // copyrightserif (0xF6D9) => copyright\n t[63720] = 0x00AE; // registersans (0xF8E8) => registered\n t[63194] = 0x00AE; // registerserif (0xF6DA) => registered\n t[63722] = 0x2122; // trademarksans (0xF8EA) => trademark\n t[63195] = 0x2122; // trademarkserif (0xF6DB) => trademark\n t[63729] = 0x23A7; // bracelefttp (0xF8F1)\n t[63730] = 0x23A8; // braceleftmid (0xF8F2)\n t[63731] = 0x23A9; // braceleftbt (0xF8F3)\n t[63740] = 0x23AB; // bracerighttp (0xF8FC)\n t[63741] = 0x23AC; // bracerightmid (0xF8FD)\n t[63742] = 0x23AD; // bracerightbt (0xF8FE)\n t[63726] = 0x23A1; // bracketlefttp (0xF8EE)\n t[63727] = 0x23A2; // bracketleftex (0xF8EF)\n t[63728] = 0x23A3; // bracketleftbt (0xF8F0)\n t[63737] = 0x23A4; // bracketrighttp (0xF8F9)\n t[63738] = 0x23A5; // bracketrightex (0xF8FA)\n t[63739] = 0x23A6; // bracketrightbt (0xF8FB)\n t[63723] = 0x239B; // parenlefttp (0xF8EB)\n t[63724] = 0x239C; // parenleftex (0xF8EC)\n t[63725] = 0x239D; // parenleftbt (0xF8ED)\n t[63734] = 0x239E; // parenrighttp (0xF8F6)\n t[63735] = 0x239F; // parenrightex (0xF8F7)\n t[63736] = 0x23A0; // parenrightbt (0xF8F8)\n});\n\nfunction mapSpecialUnicodeValues(code) {\n if (code >= 0xFFF0 && code <= 0xFFFF) { // Specials unicode block.\n return 0;\n } else if (code >= 0xF600 && code <= 0xF8FF) {\n return (getSpecialPUASymbols()[code] || code);\n }\n return code;\n}\n\nfunction getUnicodeForGlyph(name, glyphsUnicodeMap) {\n var unicode = glyphsUnicodeMap[name];\n if (unicode !== undefined) {\n return unicode;\n }\n if (!name) {\n return -1;\n }\n // Try to recover valid Unicode values from 'uniXXXX'/'uXXXX{XX}' glyphs.\n if (name[0] === 'u') {\n var nameLen = name.length, hexStr;\n\n if (nameLen === 7 && name[1] === 'n' && name[2] === 'i') { // 'uniXXXX'\n hexStr = name.substr(3);\n } else if (nameLen >= 5 && nameLen <= 7) { // 'uXXXX{XX}'\n hexStr = name.substr(1);\n } else {\n return -1;\n }\n // Check for upper-case hexadecimal characters, to avoid false positives.\n if (hexStr === hexStr.toUpperCase()) {\n unicode = parseInt(hexStr, 16);\n if (unicode >= 0) {\n return unicode;\n }\n }\n }\n return -1;\n}\n\nvar UnicodeRanges = [\n { 'begin': 0x0000, 'end': 0x007F, }, // Basic Latin\n { 'begin': 0x0080, 'end': 0x00FF, }, // Latin-1 Supplement\n { 'begin': 0x0100, 'end': 0x017F, }, // Latin Extended-A\n { 'begin': 0x0180, 'end': 0x024F, }, // Latin Extended-B\n { 'begin': 0x0250, 'end': 0x02AF, }, // IPA Extensions\n { 'begin': 0x02B0, 'end': 0x02FF, }, // Spacing Modifier Letters\n { 'begin': 0x0300, 'end': 0x036F, }, // Combining Diacritical Marks\n { 'begin': 0x0370, 'end': 0x03FF, }, // Greek and Coptic\n { 'begin': 0x2C80, 'end': 0x2CFF, }, // Coptic\n { 'begin': 0x0400, 'end': 0x04FF, }, // Cyrillic\n { 'begin': 0x0530, 'end': 0x058F, }, // Armenian\n { 'begin': 0x0590, 'end': 0x05FF, }, // Hebrew\n { 'begin': 0xA500, 'end': 0xA63F, }, // Vai\n { 'begin': 0x0600, 'end': 0x06FF, }, // Arabic\n { 'begin': 0x07C0, 'end': 0x07FF, }, // NKo\n { 'begin': 0x0900, 'end': 0x097F, }, // Devanagari\n { 'begin': 0x0980, 'end': 0x09FF, }, // Bengali\n { 'begin': 0x0A00, 'end': 0x0A7F, }, // Gurmukhi\n { 'begin': 0x0A80, 'end': 0x0AFF, }, // Gujarati\n { 'begin': 0x0B00, 'end': 0x0B7F, }, // Oriya\n { 'begin': 0x0B80, 'end': 0x0BFF, }, // Tamil\n { 'begin': 0x0C00, 'end': 0x0C7F, }, // Telugu\n { 'begin': 0x0C80, 'end': 0x0CFF, }, // Kannada\n { 'begin': 0x0D00, 'end': 0x0D7F, }, // Malayalam\n { 'begin': 0x0E00, 'end': 0x0E7F, }, // Thai\n { 'begin': 0x0E80, 'end': 0x0EFF, }, // Lao\n { 'begin': 0x10A0, 'end': 0x10FF, }, // Georgian\n { 'begin': 0x1B00, 'end': 0x1B7F, }, // Balinese\n { 'begin': 0x1100, 'end': 0x11FF, }, // Hangul Jamo\n { 'begin': 0x1E00, 'end': 0x1EFF, }, // Latin Extended Additional\n { 'begin': 0x1F00, 'end': 0x1FFF, }, // Greek Extended\n { 'begin': 0x2000, 'end': 0x206F, }, // General Punctuation\n { 'begin': 0x2070, 'end': 0x209F, }, // Superscripts And Subscripts\n { 'begin': 0x20A0, 'end': 0x20CF, }, // Currency Symbol\n { 'begin': 0x20D0, 'end': 0x20FF, }, // Combining Diacritical Marks\n { 'begin': 0x2100, 'end': 0x214F, }, // Letterlike Symbols\n { 'begin': 0x2150, 'end': 0x218F, }, // Number Forms\n { 'begin': 0x2190, 'end': 0x21FF, }, // Arrows\n { 'begin': 0x2200, 'end': 0x22FF, }, // Mathematical Operators\n { 'begin': 0x2300, 'end': 0x23FF, }, // Miscellaneous Technical\n { 'begin': 0x2400, 'end': 0x243F, }, // Control Pictures\n { 'begin': 0x2440, 'end': 0x245F, }, // Optical Character Recognition\n { 'begin': 0x2460, 'end': 0x24FF, }, // Enclosed Alphanumerics\n { 'begin': 0x2500, 'end': 0x257F, }, // Box Drawing\n { 'begin': 0x2580, 'end': 0x259F, }, // Block Elements\n { 'begin': 0x25A0, 'end': 0x25FF, }, // Geometric Shapes\n { 'begin': 0x2600, 'end': 0x26FF, }, // Miscellaneous Symbols\n { 'begin': 0x2700, 'end': 0x27BF, }, // Dingbats\n { 'begin': 0x3000, 'end': 0x303F, }, // CJK Symbols And Punctuation\n { 'begin': 0x3040, 'end': 0x309F, }, // Hiragana\n { 'begin': 0x30A0, 'end': 0x30FF, }, // Katakana\n { 'begin': 0x3100, 'end': 0x312F, }, // Bopomofo\n { 'begin': 0x3130, 'end': 0x318F, }, // Hangul Compatibility Jamo\n { 'begin': 0xA840, 'end': 0xA87F, }, // Phags-pa\n { 'begin': 0x3200, 'end': 0x32FF, }, // Enclosed CJK Letters And Months\n { 'begin': 0x3300, 'end': 0x33FF, }, // CJK Compatibility\n { 'begin': 0xAC00, 'end': 0xD7AF, }, // Hangul Syllables\n { 'begin': 0xD800, 'end': 0xDFFF, }, // Non-Plane 0 *\n { 'begin': 0x10900, 'end': 0x1091F, }, // Phoenicia\n { 'begin': 0x4E00, 'end': 0x9FFF, }, // CJK Unified Ideographs\n { 'begin': 0xE000, 'end': 0xF8FF, }, // Private Use Area (plane 0)\n { 'begin': 0x31C0, 'end': 0x31EF, }, // CJK Strokes\n { 'begin': 0xFB00, 'end': 0xFB4F, }, // Alphabetic Presentation Forms\n { 'begin': 0xFB50, 'end': 0xFDFF, }, // Arabic Presentation Forms-A\n { 'begin': 0xFE20, 'end': 0xFE2F, }, // Combining Half Marks\n { 'begin': 0xFE10, 'end': 0xFE1F, }, // Vertical Forms\n { 'begin': 0xFE50, 'end': 0xFE6F, }, // Small Form Variants\n { 'begin': 0xFE70, 'end': 0xFEFF, }, // Arabic Presentation Forms-B\n { 'begin': 0xFF00, 'end': 0xFFEF, }, // Halfwidth And Fullwidth Forms\n { 'begin': 0xFFF0, 'end': 0xFFFF, }, // Specials\n { 'begin': 0x0F00, 'end': 0x0FFF, }, // Tibetan\n { 'begin': 0x0700, 'end': 0x074F, }, // Syriac\n { 'begin': 0x0780, 'end': 0x07BF, }, // Thaana\n { 'begin': 0x0D80, 'end': 0x0DFF, }, // Sinhala\n { 'begin': 0x1000, 'end': 0x109F, }, // Myanmar\n { 'begin': 0x1200, 'end': 0x137F, }, // Ethiopic\n { 'begin': 0x13A0, 'end': 0x13FF, }, // Cherokee\n { 'begin': 0x1400, 'end': 0x167F, }, // Unified Canadian Aboriginal Syllabics\n { 'begin': 0x1680, 'end': 0x169F, }, // Ogham\n { 'begin': 0x16A0, 'end': 0x16FF, }, // Runic\n { 'begin': 0x1780, 'end': 0x17FF, }, // Khmer\n { 'begin': 0x1800, 'end': 0x18AF, }, // Mongolian\n { 'begin': 0x2800, 'end': 0x28FF, }, // Braille Patterns\n { 'begin': 0xA000, 'end': 0xA48F, }, // Yi Syllables\n { 'begin': 0x1700, 'end': 0x171F, }, // Tagalog\n { 'begin': 0x10300, 'end': 0x1032F, }, // Old Italic\n { 'begin': 0x10330, 'end': 0x1034F, }, // Gothic\n { 'begin': 0x10400, 'end': 0x1044F, }, // Deseret\n { 'begin': 0x1D000, 'end': 0x1D0FF, }, // Byzantine Musical Symbols\n { 'begin': 0x1D400, 'end': 0x1D7FF, }, // Mathematical Alphanumeric Symbols\n { 'begin': 0xFF000, 'end': 0xFFFFD, }, // Private Use (plane 15)\n { 'begin': 0xFE00, 'end': 0xFE0F, }, // Variation Selectors\n { 'begin': 0xE0000, 'end': 0xE007F, }, // Tags\n { 'begin': 0x1900, 'end': 0x194F, }, // Limbu\n { 'begin': 0x1950, 'end': 0x197F, }, // Tai Le\n { 'begin': 0x1980, 'end': 0x19DF, }, // New Tai Lue\n { 'begin': 0x1A00, 'end': 0x1A1F, }, // Buginese\n { 'begin': 0x2C00, 'end': 0x2C5F, }, // Glagolitic\n { 'begin': 0x2D30, 'end': 0x2D7F, }, // Tifinagh\n { 'begin': 0x4DC0, 'end': 0x4DFF, }, // Yijing Hexagram Symbols\n { 'begin': 0xA800, 'end': 0xA82F, }, // Syloti Nagri\n { 'begin': 0x10000, 'end': 0x1007F, }, // Linear B Syllabary\n { 'begin': 0x10140, 'end': 0x1018F, }, // Ancient Greek Numbers\n { 'begin': 0x10380, 'end': 0x1039F, }, // Ugaritic\n { 'begin': 0x103A0, 'end': 0x103DF, }, // Old Persian\n { 'begin': 0x10450, 'end': 0x1047F, }, // Shavian\n { 'begin': 0x10480, 'end': 0x104AF, }, // Osmanya\n { 'begin': 0x10800, 'end': 0x1083F, }, // Cypriot Syllabary\n { 'begin': 0x10A00, 'end': 0x10A5F, }, // Kharoshthi\n { 'begin': 0x1D300, 'end': 0x1D35F, }, // Tai Xuan Jing Symbols\n { 'begin': 0x12000, 'end': 0x123FF, }, // Cuneiform\n { 'begin': 0x1D360, 'end': 0x1D37F, }, // Counting Rod Numerals\n { 'begin': 0x1B80, 'end': 0x1BBF, }, // Sundanese\n { 'begin': 0x1C00, 'end': 0x1C4F, }, // Lepcha\n { 'begin': 0x1C50, 'end': 0x1C7F, }, // Ol Chiki\n { 'begin': 0xA880, 'end': 0xA8DF, }, // Saurashtra\n { 'begin': 0xA900, 'end': 0xA92F, }, // Kayah Li\n { 'begin': 0xA930, 'end': 0xA95F, }, // Rejang\n { 'begin': 0xAA00, 'end': 0xAA5F, }, // Cham\n { 'begin': 0x10190, 'end': 0x101CF, }, // Ancient Symbols\n { 'begin': 0x101D0, 'end': 0x101FF, }, // Phaistos Disc\n { 'begin': 0x102A0, 'end': 0x102DF, }, // Carian\n { 'begin': 0x1F030, 'end': 0x1F09F, } // Domino Tiles\n];\n\nfunction getUnicodeRangeFor(value) {\n for (var i = 0, ii = UnicodeRanges.length; i < ii; i++) {\n var range = UnicodeRanges[i];\n if (value >= range.begin && value < range.end) {\n return i;\n }\n }\n return -1;\n}\n\nfunction isRTLRangeFor(value) {\n var range = UnicodeRanges[13];\n if (value >= range.begin && value < range.end) {\n return true;\n }\n range = UnicodeRanges[11];\n if (value >= range.begin && value < range.end) {\n return true;\n }\n return false;\n}\n\n// The normalization table is obtained by filtering the Unicode characters\n// database with entries.\nvar getNormalizedUnicodes = getLookupTableFactory(function (t) {\n t['\\u00A8'] = '\\u0020\\u0308';\n t['\\u00AF'] = '\\u0020\\u0304';\n t['\\u00B4'] = '\\u0020\\u0301';\n t['\\u00B5'] = '\\u03BC';\n t['\\u00B8'] = '\\u0020\\u0327';\n t['\\u0132'] = '\\u0049\\u004A';\n t['\\u0133'] = '\\u0069\\u006A';\n t['\\u013F'] = '\\u004C\\u00B7';\n t['\\u0140'] = '\\u006C\\u00B7';\n t['\\u0149'] = '\\u02BC\\u006E';\n t['\\u017F'] = '\\u0073';\n t['\\u01C4'] = '\\u0044\\u017D';\n t['\\u01C5'] = '\\u0044\\u017E';\n t['\\u01C6'] = '\\u0064\\u017E';\n t['\\u01C7'] = '\\u004C\\u004A';\n t['\\u01C8'] = '\\u004C\\u006A';\n t['\\u01C9'] = '\\u006C\\u006A';\n t['\\u01CA'] = '\\u004E\\u004A';\n t['\\u01CB'] = '\\u004E\\u006A';\n t['\\u01CC'] = '\\u006E\\u006A';\n t['\\u01F1'] = '\\u0044\\u005A';\n t['\\u01F2'] = '\\u0044\\u007A';\n t['\\u01F3'] = '\\u0064\\u007A';\n t['\\u02D8'] = '\\u0020\\u0306';\n t['\\u02D9'] = '\\u0020\\u0307';\n t['\\u02DA'] = '\\u0020\\u030A';\n t['\\u02DB'] = '\\u0020\\u0328';\n t['\\u02DC'] = '\\u0020\\u0303';\n t['\\u02DD'] = '\\u0020\\u030B';\n t['\\u037A'] = '\\u0020\\u0345';\n t['\\u0384'] = '\\u0020\\u0301';\n t['\\u03D0'] = '\\u03B2';\n t['\\u03D1'] = '\\u03B8';\n t['\\u03D2'] = '\\u03A5';\n t['\\u03D5'] = '\\u03C6';\n t['\\u03D6'] = '\\u03C0';\n t['\\u03F0'] = '\\u03BA';\n t['\\u03F1'] = '\\u03C1';\n t['\\u03F2'] = '\\u03C2';\n t['\\u03F4'] = '\\u0398';\n t['\\u03F5'] = '\\u03B5';\n t['\\u03F9'] = '\\u03A3';\n t['\\u0587'] = '\\u0565\\u0582';\n t['\\u0675'] = '\\u0627\\u0674';\n t['\\u0676'] = '\\u0648\\u0674';\n t['\\u0677'] = '\\u06C7\\u0674';\n t['\\u0678'] = '\\u064A\\u0674';\n t['\\u0E33'] = '\\u0E4D\\u0E32';\n t['\\u0EB3'] = '\\u0ECD\\u0EB2';\n t['\\u0EDC'] = '\\u0EAB\\u0E99';\n t['\\u0EDD'] = '\\u0EAB\\u0EA1';\n t['\\u0F77'] = '\\u0FB2\\u0F81';\n t['\\u0F79'] = '\\u0FB3\\u0F81';\n t['\\u1E9A'] = '\\u0061\\u02BE';\n t['\\u1FBD'] = '\\u0020\\u0313';\n t['\\u1FBF'] = '\\u0020\\u0313';\n t['\\u1FC0'] = '\\u0020\\u0342';\n t['\\u1FFE'] = '\\u0020\\u0314';\n t['\\u2002'] = '\\u0020';\n t['\\u2003'] = '\\u0020';\n t['\\u2004'] = '\\u0020';\n t['\\u2005'] = '\\u0020';\n t['\\u2006'] = '\\u0020';\n t['\\u2008'] = '\\u0020';\n t['\\u2009'] = '\\u0020';\n t['\\u200A'] = '\\u0020';\n t['\\u2017'] = '\\u0020\\u0333';\n t['\\u2024'] = '\\u002E';\n t['\\u2025'] = '\\u002E\\u002E';\n t['\\u2026'] = '\\u002E\\u002E\\u002E';\n t['\\u2033'] = '\\u2032\\u2032';\n t['\\u2034'] = '\\u2032\\u2032\\u2032';\n t['\\u2036'] = '\\u2035\\u2035';\n t['\\u2037'] = '\\u2035\\u2035\\u2035';\n t['\\u203C'] = '\\u0021\\u0021';\n t['\\u203E'] = '\\u0020\\u0305';\n t['\\u2047'] = '\\u003F\\u003F';\n t['\\u2048'] = '\\u003F\\u0021';\n t['\\u2049'] = '\\u0021\\u003F';\n t['\\u2057'] = '\\u2032\\u2032\\u2032\\u2032';\n t['\\u205F'] = '\\u0020';\n t['\\u20A8'] = '\\u0052\\u0073';\n t['\\u2100'] = '\\u0061\\u002F\\u0063';\n t['\\u2101'] = '\\u0061\\u002F\\u0073';\n t['\\u2103'] = '\\u00B0\\u0043';\n t['\\u2105'] = '\\u0063\\u002F\\u006F';\n t['\\u2106'] = '\\u0063\\u002F\\u0075';\n t['\\u2107'] = '\\u0190';\n t['\\u2109'] = '\\u00B0\\u0046';\n t['\\u2116'] = '\\u004E\\u006F';\n t['\\u2121'] = '\\u0054\\u0045\\u004C';\n t['\\u2135'] = '\\u05D0';\n t['\\u2136'] = '\\u05D1';\n t['\\u2137'] = '\\u05D2';\n t['\\u2138'] = '\\u05D3';\n t['\\u213B'] = '\\u0046\\u0041\\u0058';\n t['\\u2160'] = '\\u0049';\n t['\\u2161'] = '\\u0049\\u0049';\n t['\\u2162'] = '\\u0049\\u0049\\u0049';\n t['\\u2163'] = '\\u0049\\u0056';\n t['\\u2164'] = '\\u0056';\n t['\\u2165'] = '\\u0056\\u0049';\n t['\\u2166'] = '\\u0056\\u0049\\u0049';\n t['\\u2167'] = '\\u0056\\u0049\\u0049\\u0049';\n t['\\u2168'] = '\\u0049\\u0058';\n t['\\u2169'] = '\\u0058';\n t['\\u216A'] = '\\u0058\\u0049';\n t['\\u216B'] = '\\u0058\\u0049\\u0049';\n t['\\u216C'] = '\\u004C';\n t['\\u216D'] = '\\u0043';\n t['\\u216E'] = '\\u0044';\n t['\\u216F'] = '\\u004D';\n t['\\u2170'] = '\\u0069';\n t['\\u2171'] = '\\u0069\\u0069';\n t['\\u2172'] = '\\u0069\\u0069\\u0069';\n t['\\u2173'] = '\\u0069\\u0076';\n t['\\u2174'] = '\\u0076';\n t['\\u2175'] = '\\u0076\\u0069';\n t['\\u2176'] = '\\u0076\\u0069\\u0069';\n t['\\u2177'] = '\\u0076\\u0069\\u0069\\u0069';\n t['\\u2178'] = '\\u0069\\u0078';\n t['\\u2179'] = '\\u0078';\n t['\\u217A'] = '\\u0078\\u0069';\n t['\\u217B'] = '\\u0078\\u0069\\u0069';\n t['\\u217C'] = '\\u006C';\n t['\\u217D'] = '\\u0063';\n t['\\u217E'] = '\\u0064';\n t['\\u217F'] = '\\u006D';\n t['\\u222C'] = '\\u222B\\u222B';\n t['\\u222D'] = '\\u222B\\u222B\\u222B';\n t['\\u222F'] = '\\u222E\\u222E';\n t['\\u2230'] = '\\u222E\\u222E\\u222E';\n t['\\u2474'] = '\\u0028\\u0031\\u0029';\n t['\\u2475'] = '\\u0028\\u0032\\u0029';\n t['\\u2476'] = '\\u0028\\u0033\\u0029';\n t['\\u2477'] = '\\u0028\\u0034\\u0029';\n t['\\u2478'] = '\\u0028\\u0035\\u0029';\n t['\\u2479'] = '\\u0028\\u0036\\u0029';\n t['\\u247A'] = '\\u0028\\u0037\\u0029';\n t['\\u247B'] = '\\u0028\\u0038\\u0029';\n t['\\u247C'] = '\\u0028\\u0039\\u0029';\n t['\\u247D'] = '\\u0028\\u0031\\u0030\\u0029';\n t['\\u247E'] = '\\u0028\\u0031\\u0031\\u0029';\n t['\\u247F'] = '\\u0028\\u0031\\u0032\\u0029';\n t['\\u2480'] = '\\u0028\\u0031\\u0033\\u0029';\n t['\\u2481'] = '\\u0028\\u0031\\u0034\\u0029';\n t['\\u2482'] = '\\u0028\\u0031\\u0035\\u0029';\n t['\\u2483'] = '\\u0028\\u0031\\u0036\\u0029';\n t['\\u2484'] = '\\u0028\\u0031\\u0037\\u0029';\n t['\\u2485'] = '\\u0028\\u0031\\u0038\\u0029';\n t['\\u2486'] = '\\u0028\\u0031\\u0039\\u0029';\n t['\\u2487'] = '\\u0028\\u0032\\u0030\\u0029';\n t['\\u2488'] = '\\u0031\\u002E';\n t['\\u2489'] = '\\u0032\\u002E';\n t['\\u248A'] = '\\u0033\\u002E';\n t['\\u248B'] = '\\u0034\\u002E';\n t['\\u248C'] = '\\u0035\\u002E';\n t['\\u248D'] = '\\u0036\\u002E';\n t['\\u248E'] = '\\u0037\\u002E';\n t['\\u248F'] = '\\u0038\\u002E';\n t['\\u2490'] = '\\u0039\\u002E';\n t['\\u2491'] = '\\u0031\\u0030\\u002E';\n t['\\u2492'] = '\\u0031\\u0031\\u002E';\n t['\\u2493'] = '\\u0031\\u0032\\u002E';\n t['\\u2494'] = '\\u0031\\u0033\\u002E';\n t['\\u2495'] = '\\u0031\\u0034\\u002E';\n t['\\u2496'] = '\\u0031\\u0035\\u002E';\n t['\\u2497'] = '\\u0031\\u0036\\u002E';\n t['\\u2498'] = '\\u0031\\u0037\\u002E';\n t['\\u2499'] = '\\u0031\\u0038\\u002E';\n t['\\u249A'] = '\\u0031\\u0039\\u002E';\n t['\\u249B'] = '\\u0032\\u0030\\u002E';\n t['\\u249C'] = '\\u0028\\u0061\\u0029';\n t['\\u249D'] = '\\u0028\\u0062\\u0029';\n t['\\u249E'] = '\\u0028\\u0063\\u0029';\n t['\\u249F'] = '\\u0028\\u0064\\u0029';\n t['\\u24A0'] = '\\u0028\\u0065\\u0029';\n t['\\u24A1'] = '\\u0028\\u0066\\u0029';\n t['\\u24A2'] = '\\u0028\\u0067\\u0029';\n t['\\u24A3'] = '\\u0028\\u0068\\u0029';\n t['\\u24A4'] = '\\u0028\\u0069\\u0029';\n t['\\u24A5'] = '\\u0028\\u006A\\u0029';\n t['\\u24A6'] = '\\u0028\\u006B\\u0029';\n t['\\u24A7'] = '\\u0028\\u006C\\u0029';\n t['\\u24A8'] = '\\u0028\\u006D\\u0029';\n t['\\u24A9'] = '\\u0028\\u006E\\u0029';\n t['\\u24AA'] = '\\u0028\\u006F\\u0029';\n t['\\u24AB'] = '\\u0028\\u0070\\u0029';\n t['\\u24AC'] = '\\u0028\\u0071\\u0029';\n t['\\u24AD'] = '\\u0028\\u0072\\u0029';\n t['\\u24AE'] = '\\u0028\\u0073\\u0029';\n t['\\u24AF'] = '\\u0028\\u0074\\u0029';\n t['\\u24B0'] = '\\u0028\\u0075\\u0029';\n t['\\u24B1'] = '\\u0028\\u0076\\u0029';\n t['\\u24B2'] = '\\u0028\\u0077\\u0029';\n t['\\u24B3'] = '\\u0028\\u0078\\u0029';\n t['\\u24B4'] = '\\u0028\\u0079\\u0029';\n t['\\u24B5'] = '\\u0028\\u007A\\u0029';\n t['\\u2A0C'] = '\\u222B\\u222B\\u222B\\u222B';\n t['\\u2A74'] = '\\u003A\\u003A\\u003D';\n t['\\u2A75'] = '\\u003D\\u003D';\n t['\\u2A76'] = '\\u003D\\u003D\\u003D';\n t['\\u2E9F'] = '\\u6BCD';\n t['\\u2EF3'] = '\\u9F9F';\n t['\\u2F00'] = '\\u4E00';\n t['\\u2F01'] = '\\u4E28';\n t['\\u2F02'] = '\\u4E36';\n t['\\u2F03'] = '\\u4E3F';\n t['\\u2F04'] = '\\u4E59';\n t['\\u2F05'] = '\\u4E85';\n t['\\u2F06'] = '\\u4E8C';\n t['\\u2F07'] = '\\u4EA0';\n t['\\u2F08'] = '\\u4EBA';\n t['\\u2F09'] = '\\u513F';\n t['\\u2F0A'] = '\\u5165';\n t['\\u2F0B'] = '\\u516B';\n t['\\u2F0C'] = '\\u5182';\n t['\\u2F0D'] = '\\u5196';\n t['\\u2F0E'] = '\\u51AB';\n t['\\u2F0F'] = '\\u51E0';\n t['\\u2F10'] = '\\u51F5';\n t['\\u2F11'] = '\\u5200';\n t['\\u2F12'] = '\\u529B';\n t['\\u2F13'] = '\\u52F9';\n t['\\u2F14'] = '\\u5315';\n t['\\u2F15'] = '\\u531A';\n t['\\u2F16'] = '\\u5338';\n t['\\u2F17'] = '\\u5341';\n t['\\u2F18'] = '\\u535C';\n t['\\u2F19'] = '\\u5369';\n t['\\u2F1A'] = '\\u5382';\n t['\\u2F1B'] = '\\u53B6';\n t['\\u2F1C'] = '\\u53C8';\n t['\\u2F1D'] = '\\u53E3';\n t['\\u2F1E'] = '\\u56D7';\n t['\\u2F1F'] = '\\u571F';\n t['\\u2F20'] = '\\u58EB';\n t['\\u2F21'] = '\\u5902';\n t['\\u2F22'] = '\\u590A';\n t['\\u2F23'] = '\\u5915';\n t['\\u2F24'] = '\\u5927';\n t['\\u2F25'] = '\\u5973';\n t['\\u2F26'] = '\\u5B50';\n t['\\u2F27'] = '\\u5B80';\n t['\\u2F28'] = '\\u5BF8';\n t['\\u2F29'] = '\\u5C0F';\n t['\\u2F2A'] = '\\u5C22';\n t['\\u2F2B'] = '\\u5C38';\n t['\\u2F2C'] = '\\u5C6E';\n t['\\u2F2D'] = '\\u5C71';\n t['\\u2F2E'] = '\\u5DDB';\n t['\\u2F2F'] = '\\u5DE5';\n t['\\u2F30'] = '\\u5DF1';\n t['\\u2F31'] = '\\u5DFE';\n t['\\u2F32'] = '\\u5E72';\n t['\\u2F33'] = '\\u5E7A';\n t['\\u2F34'] = '\\u5E7F';\n t['\\u2F35'] = '\\u5EF4';\n t['\\u2F36'] = '\\u5EFE';\n t['\\u2F37'] = '\\u5F0B';\n t['\\u2F38'] = '\\u5F13';\n t['\\u2F39'] = '\\u5F50';\n t['\\u2F3A'] = '\\u5F61';\n t['\\u2F3B'] = '\\u5F73';\n t['\\u2F3C'] = '\\u5FC3';\n t['\\u2F3D'] = '\\u6208';\n t['\\u2F3E'] = '\\u6236';\n t['\\u2F3F'] = '\\u624B';\n t['\\u2F40'] = '\\u652F';\n t['\\u2F41'] = '\\u6534';\n t['\\u2F42'] = '\\u6587';\n t['\\u2F43'] = '\\u6597';\n t['\\u2F44'] = '\\u65A4';\n t['\\u2F45'] = '\\u65B9';\n t['\\u2F46'] = '\\u65E0';\n t['\\u2F47'] = '\\u65E5';\n t['\\u2F48'] = '\\u66F0';\n t['\\u2F49'] = '\\u6708';\n t['\\u2F4A'] = '\\u6728';\n t['\\u2F4B'] = '\\u6B20';\n t['\\u2F4C'] = '\\u6B62';\n t['\\u2F4D'] = '\\u6B79';\n t['\\u2F4E'] = '\\u6BB3';\n t['\\u2F4F'] = '\\u6BCB';\n t['\\u2F50'] = '\\u6BD4';\n t['\\u2F51'] = '\\u6BDB';\n t['\\u2F52'] = '\\u6C0F';\n t['\\u2F53'] = '\\u6C14';\n t['\\u2F54'] = '\\u6C34';\n t['\\u2F55'] = '\\u706B';\n t['\\u2F56'] = '\\u722A';\n t['\\u2F57'] = '\\u7236';\n t['\\u2F58'] = '\\u723B';\n t['\\u2F59'] = '\\u723F';\n t['\\u2F5A'] = '\\u7247';\n t['\\u2F5B'] = '\\u7259';\n t['\\u2F5C'] = '\\u725B';\n t['\\u2F5D'] = '\\u72AC';\n t['\\u2F5E'] = '\\u7384';\n t['\\u2F5F'] = '\\u7389';\n t['\\u2F60'] = '\\u74DC';\n t['\\u2F61'] = '\\u74E6';\n t['\\u2F62'] = '\\u7518';\n t['\\u2F63'] = '\\u751F';\n t['\\u2F64'] = '\\u7528';\n t['\\u2F65'] = '\\u7530';\n t['\\u2F66'] = '\\u758B';\n t['\\u2F67'] = '\\u7592';\n t['\\u2F68'] = '\\u7676';\n t['\\u2F69'] = '\\u767D';\n t['\\u2F6A'] = '\\u76AE';\n t['\\u2F6B'] = '\\u76BF';\n t['\\u2F6C'] = '\\u76EE';\n t['\\u2F6D'] = '\\u77DB';\n t['\\u2F6E'] = '\\u77E2';\n t['\\u2F6F'] = '\\u77F3';\n t['\\u2F70'] = '\\u793A';\n t['\\u2F71'] = '\\u79B8';\n t['\\u2F72'] = '\\u79BE';\n t['\\u2F73'] = '\\u7A74';\n t['\\u2F74'] = '\\u7ACB';\n t['\\u2F75'] = '\\u7AF9';\n t['\\u2F76'] = '\\u7C73';\n t['\\u2F77'] = '\\u7CF8';\n t['\\u2F78'] = '\\u7F36';\n t['\\u2F79'] = '\\u7F51';\n t['\\u2F7A'] = '\\u7F8A';\n t['\\u2F7B'] = '\\u7FBD';\n t['\\u2F7C'] = '\\u8001';\n t['\\u2F7D'] = '\\u800C';\n t['\\u2F7E'] = '\\u8012';\n t['\\u2F7F'] = '\\u8033';\n t['\\u2F80'] = '\\u807F';\n t['\\u2F81'] = '\\u8089';\n t['\\u2F82'] = '\\u81E3';\n t['\\u2F83'] = '\\u81EA';\n t['\\u2F84'] = '\\u81F3';\n t['\\u2F85'] = '\\u81FC';\n t['\\u2F86'] = '\\u820C';\n t['\\u2F87'] = '\\u821B';\n t['\\u2F88'] = '\\u821F';\n t['\\u2F89'] = '\\u826E';\n t['\\u2F8A'] = '\\u8272';\n t['\\u2F8B'] = '\\u8278';\n t['\\u2F8C'] = '\\u864D';\n t['\\u2F8D'] = '\\u866B';\n t['\\u2F8E'] = '\\u8840';\n t['\\u2F8F'] = '\\u884C';\n t['\\u2F90'] = '\\u8863';\n t['\\u2F91'] = '\\u897E';\n t['\\u2F92'] = '\\u898B';\n t['\\u2F93'] = '\\u89D2';\n t['\\u2F94'] = '\\u8A00';\n t['\\u2F95'] = '\\u8C37';\n t['\\u2F96'] = '\\u8C46';\n t['\\u2F97'] = '\\u8C55';\n t['\\u2F98'] = '\\u8C78';\n t['\\u2F99'] = '\\u8C9D';\n t['\\u2F9A'] = '\\u8D64';\n t['\\u2F9B'] = '\\u8D70';\n t['\\u2F9C'] = '\\u8DB3';\n t['\\u2F9D'] = '\\u8EAB';\n t['\\u2F9E'] = '\\u8ECA';\n t['\\u2F9F'] = '\\u8F9B';\n t['\\u2FA0'] = '\\u8FB0';\n t['\\u2FA1'] = '\\u8FB5';\n t['\\u2FA2'] = '\\u9091';\n t['\\u2FA3'] = '\\u9149';\n t['\\u2FA4'] = '\\u91C6';\n t['\\u2FA5'] = '\\u91CC';\n t['\\u2FA6'] = '\\u91D1';\n t['\\u2FA7'] = '\\u9577';\n t['\\u2FA8'] = '\\u9580';\n t['\\u2FA9'] = '\\u961C';\n t['\\u2FAA'] = '\\u96B6';\n t['\\u2FAB'] = '\\u96B9';\n t['\\u2FAC'] = '\\u96E8';\n t['\\u2FAD'] = '\\u9751';\n t['\\u2FAE'] = '\\u975E';\n t['\\u2FAF'] = '\\u9762';\n t['\\u2FB0'] = '\\u9769';\n t['\\u2FB1'] = '\\u97CB';\n t['\\u2FB2'] = '\\u97ED';\n t['\\u2FB3'] = '\\u97F3';\n t['\\u2FB4'] = '\\u9801';\n t['\\u2FB5'] = '\\u98A8';\n t['\\u2FB6'] = '\\u98DB';\n t['\\u2FB7'] = '\\u98DF';\n t['\\u2FB8'] = '\\u9996';\n t['\\u2FB9'] = '\\u9999';\n t['\\u2FBA'] = '\\u99AC';\n t['\\u2FBB'] = '\\u9AA8';\n t['\\u2FBC'] = '\\u9AD8';\n t['\\u2FBD'] = '\\u9ADF';\n t['\\u2FBE'] = '\\u9B25';\n t['\\u2FBF'] = '\\u9B2F';\n t['\\u2FC0'] = '\\u9B32';\n t['\\u2FC1'] = '\\u9B3C';\n t['\\u2FC2'] = '\\u9B5A';\n t['\\u2FC3'] = '\\u9CE5';\n t['\\u2FC4'] = '\\u9E75';\n t['\\u2FC5'] = '\\u9E7F';\n t['\\u2FC6'] = '\\u9EA5';\n t['\\u2FC7'] = '\\u9EBB';\n t['\\u2FC8'] = '\\u9EC3';\n t['\\u2FC9'] = '\\u9ECD';\n t['\\u2FCA'] = '\\u9ED1';\n t['\\u2FCB'] = '\\u9EF9';\n t['\\u2FCC'] = '\\u9EFD';\n t['\\u2FCD'] = '\\u9F0E';\n t['\\u2FCE'] = '\\u9F13';\n t['\\u2FCF'] = '\\u9F20';\n t['\\u2FD0'] = '\\u9F3B';\n t['\\u2FD1'] = '\\u9F4A';\n t['\\u2FD2'] = '\\u9F52';\n t['\\u2FD3'] = '\\u9F8D';\n t['\\u2FD4'] = '\\u9F9C';\n t['\\u2FD5'] = '\\u9FA0';\n t['\\u3036'] = '\\u3012';\n t['\\u3038'] = '\\u5341';\n t['\\u3039'] = '\\u5344';\n t['\\u303A'] = '\\u5345';\n t['\\u309B'] = '\\u0020\\u3099';\n t['\\u309C'] = '\\u0020\\u309A';\n t['\\u3131'] = '\\u1100';\n t['\\u3132'] = '\\u1101';\n t['\\u3133'] = '\\u11AA';\n t['\\u3134'] = '\\u1102';\n t['\\u3135'] = '\\u11AC';\n t['\\u3136'] = '\\u11AD';\n t['\\u3137'] = '\\u1103';\n t['\\u3138'] = '\\u1104';\n t['\\u3139'] = '\\u1105';\n t['\\u313A'] = '\\u11B0';\n t['\\u313B'] = '\\u11B1';\n t['\\u313C'] = '\\u11B2';\n t['\\u313D'] = '\\u11B3';\n t['\\u313E'] = '\\u11B4';\n t['\\u313F'] = '\\u11B5';\n t['\\u3140'] = '\\u111A';\n t['\\u3141'] = '\\u1106';\n t['\\u3142'] = '\\u1107';\n t['\\u3143'] = '\\u1108';\n t['\\u3144'] = '\\u1121';\n t['\\u3145'] = '\\u1109';\n t['\\u3146'] = '\\u110A';\n t['\\u3147'] = '\\u110B';\n t['\\u3148'] = '\\u110C';\n t['\\u3149'] = '\\u110D';\n t['\\u314A'] = '\\u110E';\n t['\\u314B'] = '\\u110F';\n t['\\u314C'] = '\\u1110';\n t['\\u314D'] = '\\u1111';\n t['\\u314E'] = '\\u1112';\n t['\\u314F'] = '\\u1161';\n t['\\u3150'] = '\\u1162';\n t['\\u3151'] = '\\u1163';\n t['\\u3152'] = '\\u1164';\n t['\\u3153'] = '\\u1165';\n t['\\u3154'] = '\\u1166';\n t['\\u3155'] = '\\u1167';\n t['\\u3156'] = '\\u1168';\n t['\\u3157'] = '\\u1169';\n t['\\u3158'] = '\\u116A';\n t['\\u3159'] = '\\u116B';\n t['\\u315A'] = '\\u116C';\n t['\\u315B'] = '\\u116D';\n t['\\u315C'] = '\\u116E';\n t['\\u315D'] = '\\u116F';\n t['\\u315E'] = '\\u1170';\n t['\\u315F'] = '\\u1171';\n t['\\u3160'] = '\\u1172';\n t['\\u3161'] = '\\u1173';\n t['\\u3162'] = '\\u1174';\n t['\\u3163'] = '\\u1175';\n t['\\u3164'] = '\\u1160';\n t['\\u3165'] = '\\u1114';\n t['\\u3166'] = '\\u1115';\n t['\\u3167'] = '\\u11C7';\n t['\\u3168'] = '\\u11C8';\n t['\\u3169'] = '\\u11CC';\n t['\\u316A'] = '\\u11CE';\n t['\\u316B'] = '\\u11D3';\n t['\\u316C'] = '\\u11D7';\n t['\\u316D'] = '\\u11D9';\n t['\\u316E'] = '\\u111C';\n t['\\u316F'] = '\\u11DD';\n t['\\u3170'] = '\\u11DF';\n t['\\u3171'] = '\\u111D';\n t['\\u3172'] = '\\u111E';\n t['\\u3173'] = '\\u1120';\n t['\\u3174'] = '\\u1122';\n t['\\u3175'] = '\\u1123';\n t['\\u3176'] = '\\u1127';\n t['\\u3177'] = '\\u1129';\n t['\\u3178'] = '\\u112B';\n t['\\u3179'] = '\\u112C';\n t['\\u317A'] = '\\u112D';\n t['\\u317B'] = '\\u112E';\n t['\\u317C'] = '\\u112F';\n t['\\u317D'] = '\\u1132';\n t['\\u317E'] = '\\u1136';\n t['\\u317F'] = '\\u1140';\n t['\\u3180'] = '\\u1147';\n t['\\u3181'] = '\\u114C';\n t['\\u3182'] = '\\u11F1';\n t['\\u3183'] = '\\u11F2';\n t['\\u3184'] = '\\u1157';\n t['\\u3185'] = '\\u1158';\n t['\\u3186'] = '\\u1159';\n t['\\u3187'] = '\\u1184';\n t['\\u3188'] = '\\u1185';\n t['\\u3189'] = '\\u1188';\n t['\\u318A'] = '\\u1191';\n t['\\u318B'] = '\\u1192';\n t['\\u318C'] = '\\u1194';\n t['\\u318D'] = '\\u119E';\n t['\\u318E'] = '\\u11A1';\n t['\\u3200'] = '\\u0028\\u1100\\u0029';\n t['\\u3201'] = '\\u0028\\u1102\\u0029';\n t['\\u3202'] = '\\u0028\\u1103\\u0029';\n t['\\u3203'] = '\\u0028\\u1105\\u0029';\n t['\\u3204'] = '\\u0028\\u1106\\u0029';\n t['\\u3205'] = '\\u0028\\u1107\\u0029';\n t['\\u3206'] = '\\u0028\\u1109\\u0029';\n t['\\u3207'] = '\\u0028\\u110B\\u0029';\n t['\\u3208'] = '\\u0028\\u110C\\u0029';\n t['\\u3209'] = '\\u0028\\u110E\\u0029';\n t['\\u320A'] = '\\u0028\\u110F\\u0029';\n t['\\u320B'] = '\\u0028\\u1110\\u0029';\n t['\\u320C'] = '\\u0028\\u1111\\u0029';\n t['\\u320D'] = '\\u0028\\u1112\\u0029';\n t['\\u320E'] = '\\u0028\\u1100\\u1161\\u0029';\n t['\\u320F'] = '\\u0028\\u1102\\u1161\\u0029';\n t['\\u3210'] = '\\u0028\\u1103\\u1161\\u0029';\n t['\\u3211'] = '\\u0028\\u1105\\u1161\\u0029';\n t['\\u3212'] = '\\u0028\\u1106\\u1161\\u0029';\n t['\\u3213'] = '\\u0028\\u1107\\u1161\\u0029';\n t['\\u3214'] = '\\u0028\\u1109\\u1161\\u0029';\n t['\\u3215'] = '\\u0028\\u110B\\u1161\\u0029';\n t['\\u3216'] = '\\u0028\\u110C\\u1161\\u0029';\n t['\\u3217'] = '\\u0028\\u110E\\u1161\\u0029';\n t['\\u3218'] = '\\u0028\\u110F\\u1161\\u0029';\n t['\\u3219'] = '\\u0028\\u1110\\u1161\\u0029';\n t['\\u321A'] = '\\u0028\\u1111\\u1161\\u0029';\n t['\\u321B'] = '\\u0028\\u1112\\u1161\\u0029';\n t['\\u321C'] = '\\u0028\\u110C\\u116E\\u0029';\n t['\\u321D'] = '\\u0028\\u110B\\u1169\\u110C\\u1165\\u11AB\\u0029';\n t['\\u321E'] = '\\u0028\\u110B\\u1169\\u1112\\u116E\\u0029';\n t['\\u3220'] = '\\u0028\\u4E00\\u0029';\n t['\\u3221'] = '\\u0028\\u4E8C\\u0029';\n t['\\u3222'] = '\\u0028\\u4E09\\u0029';\n t['\\u3223'] = '\\u0028\\u56DB\\u0029';\n t['\\u3224'] = '\\u0028\\u4E94\\u0029';\n t['\\u3225'] = '\\u0028\\u516D\\u0029';\n t['\\u3226'] = '\\u0028\\u4E03\\u0029';\n t['\\u3227'] = '\\u0028\\u516B\\u0029';\n t['\\u3228'] = '\\u0028\\u4E5D\\u0029';\n t['\\u3229'] = '\\u0028\\u5341\\u0029';\n t['\\u322A'] = '\\u0028\\u6708\\u0029';\n t['\\u322B'] = '\\u0028\\u706B\\u0029';\n t['\\u322C'] = '\\u0028\\u6C34\\u0029';\n t['\\u322D'] = '\\u0028\\u6728\\u0029';\n t['\\u322E'] = '\\u0028\\u91D1\\u0029';\n t['\\u322F'] = '\\u0028\\u571F\\u0029';\n t['\\u3230'] = '\\u0028\\u65E5\\u0029';\n t['\\u3231'] = '\\u0028\\u682A\\u0029';\n t['\\u3232'] = '\\u0028\\u6709\\u0029';\n t['\\u3233'] = '\\u0028\\u793E\\u0029';\n t['\\u3234'] = '\\u0028\\u540D\\u0029';\n t['\\u3235'] = '\\u0028\\u7279\\u0029';\n t['\\u3236'] = '\\u0028\\u8CA1\\u0029';\n t['\\u3237'] = '\\u0028\\u795D\\u0029';\n t['\\u3238'] = '\\u0028\\u52B4\\u0029';\n t['\\u3239'] = '\\u0028\\u4EE3\\u0029';\n t['\\u323A'] = '\\u0028\\u547C\\u0029';\n t['\\u323B'] = '\\u0028\\u5B66\\u0029';\n t['\\u323C'] = '\\u0028\\u76E3\\u0029';\n t['\\u323D'] = '\\u0028\\u4F01\\u0029';\n t['\\u323E'] = '\\u0028\\u8CC7\\u0029';\n t['\\u323F'] = '\\u0028\\u5354\\u0029';\n t['\\u3240'] = '\\u0028\\u796D\\u0029';\n t['\\u3241'] = '\\u0028\\u4F11\\u0029';\n t['\\u3242'] = '\\u0028\\u81EA\\u0029';\n t['\\u3243'] = '\\u0028\\u81F3\\u0029';\n t['\\u32C0'] = '\\u0031\\u6708';\n t['\\u32C1'] = '\\u0032\\u6708';\n t['\\u32C2'] = '\\u0033\\u6708';\n t['\\u32C3'] = '\\u0034\\u6708';\n t['\\u32C4'] = '\\u0035\\u6708';\n t['\\u32C5'] = '\\u0036\\u6708';\n t['\\u32C6'] = '\\u0037\\u6708';\n t['\\u32C7'] = '\\u0038\\u6708';\n t['\\u32C8'] = '\\u0039\\u6708';\n t['\\u32C9'] = '\\u0031\\u0030\\u6708';\n t['\\u32CA'] = '\\u0031\\u0031\\u6708';\n t['\\u32CB'] = '\\u0031\\u0032\\u6708';\n t['\\u3358'] = '\\u0030\\u70B9';\n t['\\u3359'] = '\\u0031\\u70B9';\n t['\\u335A'] = '\\u0032\\u70B9';\n t['\\u335B'] = '\\u0033\\u70B9';\n t['\\u335C'] = '\\u0034\\u70B9';\n t['\\u335D'] = '\\u0035\\u70B9';\n t['\\u335E'] = '\\u0036\\u70B9';\n t['\\u335F'] = '\\u0037\\u70B9';\n t['\\u3360'] = '\\u0038\\u70B9';\n t['\\u3361'] = '\\u0039\\u70B9';\n t['\\u3362'] = '\\u0031\\u0030\\u70B9';\n t['\\u3363'] = '\\u0031\\u0031\\u70B9';\n t['\\u3364'] = '\\u0031\\u0032\\u70B9';\n t['\\u3365'] = '\\u0031\\u0033\\u70B9';\n t['\\u3366'] = '\\u0031\\u0034\\u70B9';\n t['\\u3367'] = '\\u0031\\u0035\\u70B9';\n t['\\u3368'] = '\\u0031\\u0036\\u70B9';\n t['\\u3369'] = '\\u0031\\u0037\\u70B9';\n t['\\u336A'] = '\\u0031\\u0038\\u70B9';\n t['\\u336B'] = '\\u0031\\u0039\\u70B9';\n t['\\u336C'] = '\\u0032\\u0030\\u70B9';\n t['\\u336D'] = '\\u0032\\u0031\\u70B9';\n t['\\u336E'] = '\\u0032\\u0032\\u70B9';\n t['\\u336F'] = '\\u0032\\u0033\\u70B9';\n t['\\u3370'] = '\\u0032\\u0034\\u70B9';\n t['\\u33E0'] = '\\u0031\\u65E5';\n t['\\u33E1'] = '\\u0032\\u65E5';\n t['\\u33E2'] = '\\u0033\\u65E5';\n t['\\u33E3'] = '\\u0034\\u65E5';\n t['\\u33E4'] = '\\u0035\\u65E5';\n t['\\u33E5'] = '\\u0036\\u65E5';\n t['\\u33E6'] = '\\u0037\\u65E5';\n t['\\u33E7'] = '\\u0038\\u65E5';\n t['\\u33E8'] = '\\u0039\\u65E5';\n t['\\u33E9'] = '\\u0031\\u0030\\u65E5';\n t['\\u33EA'] = '\\u0031\\u0031\\u65E5';\n t['\\u33EB'] = '\\u0031\\u0032\\u65E5';\n t['\\u33EC'] = '\\u0031\\u0033\\u65E5';\n t['\\u33ED'] = '\\u0031\\u0034\\u65E5';\n t['\\u33EE'] = '\\u0031\\u0035\\u65E5';\n t['\\u33EF'] = '\\u0031\\u0036\\u65E5';\n t['\\u33F0'] = '\\u0031\\u0037\\u65E5';\n t['\\u33F1'] = '\\u0031\\u0038\\u65E5';\n t['\\u33F2'] = '\\u0031\\u0039\\u65E5';\n t['\\u33F3'] = '\\u0032\\u0030\\u65E5';\n t['\\u33F4'] = '\\u0032\\u0031\\u65E5';\n t['\\u33F5'] = '\\u0032\\u0032\\u65E5';\n t['\\u33F6'] = '\\u0032\\u0033\\u65E5';\n t['\\u33F7'] = '\\u0032\\u0034\\u65E5';\n t['\\u33F8'] = '\\u0032\\u0035\\u65E5';\n t['\\u33F9'] = '\\u0032\\u0036\\u65E5';\n t['\\u33FA'] = '\\u0032\\u0037\\u65E5';\n t['\\u33FB'] = '\\u0032\\u0038\\u65E5';\n t['\\u33FC'] = '\\u0032\\u0039\\u65E5';\n t['\\u33FD'] = '\\u0033\\u0030\\u65E5';\n t['\\u33FE'] = '\\u0033\\u0031\\u65E5';\n t['\\uFB00'] = '\\u0066\\u0066';\n t['\\uFB01'] = '\\u0066\\u0069';\n t['\\uFB02'] = '\\u0066\\u006C';\n t['\\uFB03'] = '\\u0066\\u0066\\u0069';\n t['\\uFB04'] = '\\u0066\\u0066\\u006C';\n t['\\uFB05'] = '\\u017F\\u0074';\n t['\\uFB06'] = '\\u0073\\u0074';\n t['\\uFB13'] = '\\u0574\\u0576';\n t['\\uFB14'] = '\\u0574\\u0565';\n t['\\uFB15'] = '\\u0574\\u056B';\n t['\\uFB16'] = '\\u057E\\u0576';\n t['\\uFB17'] = '\\u0574\\u056D';\n t['\\uFB4F'] = '\\u05D0\\u05DC';\n t['\\uFB50'] = '\\u0671';\n t['\\uFB51'] = '\\u0671';\n t['\\uFB52'] = '\\u067B';\n t['\\uFB53'] = '\\u067B';\n t['\\uFB54'] = '\\u067B';\n t['\\uFB55'] = '\\u067B';\n t['\\uFB56'] = '\\u067E';\n t['\\uFB57'] = '\\u067E';\n t['\\uFB58'] = '\\u067E';\n t['\\uFB59'] = '\\u067E';\n t['\\uFB5A'] = '\\u0680';\n t['\\uFB5B'] = '\\u0680';\n t['\\uFB5C'] = '\\u0680';\n t['\\uFB5D'] = '\\u0680';\n t['\\uFB5E'] = '\\u067A';\n t['\\uFB5F'] = '\\u067A';\n t['\\uFB60'] = '\\u067A';\n t['\\uFB61'] = '\\u067A';\n t['\\uFB62'] = '\\u067F';\n t['\\uFB63'] = '\\u067F';\n t['\\uFB64'] = '\\u067F';\n t['\\uFB65'] = '\\u067F';\n t['\\uFB66'] = '\\u0679';\n t['\\uFB67'] = '\\u0679';\n t['\\uFB68'] = '\\u0679';\n t['\\uFB69'] = '\\u0679';\n t['\\uFB6A'] = '\\u06A4';\n t['\\uFB6B'] = '\\u06A4';\n t['\\uFB6C'] = '\\u06A4';\n t['\\uFB6D'] = '\\u06A4';\n t['\\uFB6E'] = '\\u06A6';\n t['\\uFB6F'] = '\\u06A6';\n t['\\uFB70'] = '\\u06A6';\n t['\\uFB71'] = '\\u06A6';\n t['\\uFB72'] = '\\u0684';\n t['\\uFB73'] = '\\u0684';\n t['\\uFB74'] = '\\u0684';\n t['\\uFB75'] = '\\u0684';\n t['\\uFB76'] = '\\u0683';\n t['\\uFB77'] = '\\u0683';\n t['\\uFB78'] = '\\u0683';\n t['\\uFB79'] = '\\u0683';\n t['\\uFB7A'] = '\\u0686';\n t['\\uFB7B'] = '\\u0686';\n t['\\uFB7C'] = '\\u0686';\n t['\\uFB7D'] = '\\u0686';\n t['\\uFB7E'] = '\\u0687';\n t['\\uFB7F'] = '\\u0687';\n t['\\uFB80'] = '\\u0687';\n t['\\uFB81'] = '\\u0687';\n t['\\uFB82'] = '\\u068D';\n t['\\uFB83'] = '\\u068D';\n t['\\uFB84'] = '\\u068C';\n t['\\uFB85'] = '\\u068C';\n t['\\uFB86'] = '\\u068E';\n t['\\uFB87'] = '\\u068E';\n t['\\uFB88'] = '\\u0688';\n t['\\uFB89'] = '\\u0688';\n t['\\uFB8A'] = '\\u0698';\n t['\\uFB8B'] = '\\u0698';\n t['\\uFB8C'] = '\\u0691';\n t['\\uFB8D'] = '\\u0691';\n t['\\uFB8E'] = '\\u06A9';\n t['\\uFB8F'] = '\\u06A9';\n t['\\uFB90'] = '\\u06A9';\n t['\\uFB91'] = '\\u06A9';\n t['\\uFB92'] = '\\u06AF';\n t['\\uFB93'] = '\\u06AF';\n t['\\uFB94'] = '\\u06AF';\n t['\\uFB95'] = '\\u06AF';\n t['\\uFB96'] = '\\u06B3';\n t['\\uFB97'] = '\\u06B3';\n t['\\uFB98'] = '\\u06B3';\n t['\\uFB99'] = '\\u06B3';\n t['\\uFB9A'] = '\\u06B1';\n t['\\uFB9B'] = '\\u06B1';\n t['\\uFB9C'] = '\\u06B1';\n t['\\uFB9D'] = '\\u06B1';\n t['\\uFB9E'] = '\\u06BA';\n t['\\uFB9F'] = '\\u06BA';\n t['\\uFBA0'] = '\\u06BB';\n t['\\uFBA1'] = '\\u06BB';\n t['\\uFBA2'] = '\\u06BB';\n t['\\uFBA3'] = '\\u06BB';\n t['\\uFBA4'] = '\\u06C0';\n t['\\uFBA5'] = '\\u06C0';\n t['\\uFBA6'] = '\\u06C1';\n t['\\uFBA7'] = '\\u06C1';\n t['\\uFBA8'] = '\\u06C1';\n t['\\uFBA9'] = '\\u06C1';\n t['\\uFBAA'] = '\\u06BE';\n t['\\uFBAB'] = '\\u06BE';\n t['\\uFBAC'] = '\\u06BE';\n t['\\uFBAD'] = '\\u06BE';\n t['\\uFBAE'] = '\\u06D2';\n t['\\uFBAF'] = '\\u06D2';\n t['\\uFBB0'] = '\\u06D3';\n t['\\uFBB1'] = '\\u06D3';\n t['\\uFBD3'] = '\\u06AD';\n t['\\uFBD4'] = '\\u06AD';\n t['\\uFBD5'] = '\\u06AD';\n t['\\uFBD6'] = '\\u06AD';\n t['\\uFBD7'] = '\\u06C7';\n t['\\uFBD8'] = '\\u06C7';\n t['\\uFBD9'] = '\\u06C6';\n t['\\uFBDA'] = '\\u06C6';\n t['\\uFBDB'] = '\\u06C8';\n t['\\uFBDC'] = '\\u06C8';\n t['\\uFBDD'] = '\\u0677';\n t['\\uFBDE'] = '\\u06CB';\n t['\\uFBDF'] = '\\u06CB';\n t['\\uFBE0'] = '\\u06C5';\n t['\\uFBE1'] = '\\u06C5';\n t['\\uFBE2'] = '\\u06C9';\n t['\\uFBE3'] = '\\u06C9';\n t['\\uFBE4'] = '\\u06D0';\n t['\\uFBE5'] = '\\u06D0';\n t['\\uFBE6'] = '\\u06D0';\n t['\\uFBE7'] = '\\u06D0';\n t['\\uFBE8'] = '\\u0649';\n t['\\uFBE9'] = '\\u0649';\n t['\\uFBEA'] = '\\u0626\\u0627';\n t['\\uFBEB'] = '\\u0626\\u0627';\n t['\\uFBEC'] = '\\u0626\\u06D5';\n t['\\uFBED'] = '\\u0626\\u06D5';\n t['\\uFBEE'] = '\\u0626\\u0648';\n t['\\uFBEF'] = '\\u0626\\u0648';\n t['\\uFBF0'] = '\\u0626\\u06C7';\n t['\\uFBF1'] = '\\u0626\\u06C7';\n t['\\uFBF2'] = '\\u0626\\u06C6';\n t['\\uFBF3'] = '\\u0626\\u06C6';\n t['\\uFBF4'] = '\\u0626\\u06C8';\n t['\\uFBF5'] = '\\u0626\\u06C8';\n t['\\uFBF6'] = '\\u0626\\u06D0';\n t['\\uFBF7'] = '\\u0626\\u06D0';\n t['\\uFBF8'] = '\\u0626\\u06D0';\n t['\\uFBF9'] = '\\u0626\\u0649';\n t['\\uFBFA'] = '\\u0626\\u0649';\n t['\\uFBFB'] = '\\u0626\\u0649';\n t['\\uFBFC'] = '\\u06CC';\n t['\\uFBFD'] = '\\u06CC';\n t['\\uFBFE'] = '\\u06CC';\n t['\\uFBFF'] = '\\u06CC';\n t['\\uFC00'] = '\\u0626\\u062C';\n t['\\uFC01'] = '\\u0626\\u062D';\n t['\\uFC02'] = '\\u0626\\u0645';\n t['\\uFC03'] = '\\u0626\\u0649';\n t['\\uFC04'] = '\\u0626\\u064A';\n t['\\uFC05'] = '\\u0628\\u062C';\n t['\\uFC06'] = '\\u0628\\u062D';\n t['\\uFC07'] = '\\u0628\\u062E';\n t['\\uFC08'] = '\\u0628\\u0645';\n t['\\uFC09'] = '\\u0628\\u0649';\n t['\\uFC0A'] = '\\u0628\\u064A';\n t['\\uFC0B'] = '\\u062A\\u062C';\n t['\\uFC0C'] = '\\u062A\\u062D';\n t['\\uFC0D'] = '\\u062A\\u062E';\n t['\\uFC0E'] = '\\u062A\\u0645';\n t['\\uFC0F'] = '\\u062A\\u0649';\n t['\\uFC10'] = '\\u062A\\u064A';\n t['\\uFC11'] = '\\u062B\\u062C';\n t['\\uFC12'] = '\\u062B\\u0645';\n t['\\uFC13'] = '\\u062B\\u0649';\n t['\\uFC14'] = '\\u062B\\u064A';\n t['\\uFC15'] = '\\u062C\\u062D';\n t['\\uFC16'] = '\\u062C\\u0645';\n t['\\uFC17'] = '\\u062D\\u062C';\n t['\\uFC18'] = '\\u062D\\u0645';\n t['\\uFC19'] = '\\u062E\\u062C';\n t['\\uFC1A'] = '\\u062E\\u062D';\n t['\\uFC1B'] = '\\u062E\\u0645';\n t['\\uFC1C'] = '\\u0633\\u062C';\n t['\\uFC1D'] = '\\u0633\\u062D';\n t['\\uFC1E'] = '\\u0633\\u062E';\n t['\\uFC1F'] = '\\u0633\\u0645';\n t['\\uFC20'] = '\\u0635\\u062D';\n t['\\uFC21'] = '\\u0635\\u0645';\n t['\\uFC22'] = '\\u0636\\u062C';\n t['\\uFC23'] = '\\u0636\\u062D';\n t['\\uFC24'] = '\\u0636\\u062E';\n t['\\uFC25'] = '\\u0636\\u0645';\n t['\\uFC26'] = '\\u0637\\u062D';\n t['\\uFC27'] = '\\u0637\\u0645';\n t['\\uFC28'] = '\\u0638\\u0645';\n t['\\uFC29'] = '\\u0639\\u062C';\n t['\\uFC2A'] = '\\u0639\\u0645';\n t['\\uFC2B'] = '\\u063A\\u062C';\n t['\\uFC2C'] = '\\u063A\\u0645';\n t['\\uFC2D'] = '\\u0641\\u062C';\n t['\\uFC2E'] = '\\u0641\\u062D';\n t['\\uFC2F'] = '\\u0641\\u062E';\n t['\\uFC30'] = '\\u0641\\u0645';\n t['\\uFC31'] = '\\u0641\\u0649';\n t['\\uFC32'] = '\\u0641\\u064A';\n t['\\uFC33'] = '\\u0642\\u062D';\n t['\\uFC34'] = '\\u0642\\u0645';\n t['\\uFC35'] = '\\u0642\\u0649';\n t['\\uFC36'] = '\\u0642\\u064A';\n t['\\uFC37'] = '\\u0643\\u0627';\n t['\\uFC38'] = '\\u0643\\u062C';\n t['\\uFC39'] = '\\u0643\\u062D';\n t['\\uFC3A'] = '\\u0643\\u062E';\n t['\\uFC3B'] = '\\u0643\\u0644';\n t['\\uFC3C'] = '\\u0643\\u0645';\n t['\\uFC3D'] = '\\u0643\\u0649';\n t['\\uFC3E'] = '\\u0643\\u064A';\n t['\\uFC3F'] = '\\u0644\\u062C';\n t['\\uFC40'] = '\\u0644\\u062D';\n t['\\uFC41'] = '\\u0644\\u062E';\n t['\\uFC42'] = '\\u0644\\u0645';\n t['\\uFC43'] = '\\u0644\\u0649';\n t['\\uFC44'] = '\\u0644\\u064A';\n t['\\uFC45'] = '\\u0645\\u062C';\n t['\\uFC46'] = '\\u0645\\u062D';\n t['\\uFC47'] = '\\u0645\\u062E';\n t['\\uFC48'] = '\\u0645\\u0645';\n t['\\uFC49'] = '\\u0645\\u0649';\n t['\\uFC4A'] = '\\u0645\\u064A';\n t['\\uFC4B'] = '\\u0646\\u062C';\n t['\\uFC4C'] = '\\u0646\\u062D';\n t['\\uFC4D'] = '\\u0646\\u062E';\n t['\\uFC4E'] = '\\u0646\\u0645';\n t['\\uFC4F'] = '\\u0646\\u0649';\n t['\\uFC50'] = '\\u0646\\u064A';\n t['\\uFC51'] = '\\u0647\\u062C';\n t['\\uFC52'] = '\\u0647\\u0645';\n t['\\uFC53'] = '\\u0647\\u0649';\n t['\\uFC54'] = '\\u0647\\u064A';\n t['\\uFC55'] = '\\u064A\\u062C';\n t['\\uFC56'] = '\\u064A\\u062D';\n t['\\uFC57'] = '\\u064A\\u062E';\n t['\\uFC58'] = '\\u064A\\u0645';\n t['\\uFC59'] = '\\u064A\\u0649';\n t['\\uFC5A'] = '\\u064A\\u064A';\n t['\\uFC5B'] = '\\u0630\\u0670';\n t['\\uFC5C'] = '\\u0631\\u0670';\n t['\\uFC5D'] = '\\u0649\\u0670';\n t['\\uFC5E'] = '\\u0020\\u064C\\u0651';\n t['\\uFC5F'] = '\\u0020\\u064D\\u0651';\n t['\\uFC60'] = '\\u0020\\u064E\\u0651';\n t['\\uFC61'] = '\\u0020\\u064F\\u0651';\n t['\\uFC62'] = '\\u0020\\u0650\\u0651';\n t['\\uFC63'] = '\\u0020\\u0651\\u0670';\n t['\\uFC64'] = '\\u0626\\u0631';\n t['\\uFC65'] = '\\u0626\\u0632';\n t['\\uFC66'] = '\\u0626\\u0645';\n t['\\uFC67'] = '\\u0626\\u0646';\n t['\\uFC68'] = '\\u0626\\u0649';\n t['\\uFC69'] = '\\u0626\\u064A';\n t['\\uFC6A'] = '\\u0628\\u0631';\n t['\\uFC6B'] = '\\u0628\\u0632';\n t['\\uFC6C'] = '\\u0628\\u0645';\n t['\\uFC6D'] = '\\u0628\\u0646';\n t['\\uFC6E'] = '\\u0628\\u0649';\n t['\\uFC6F'] = '\\u0628\\u064A';\n t['\\uFC70'] = '\\u062A\\u0631';\n t['\\uFC71'] = '\\u062A\\u0632';\n t['\\uFC72'] = '\\u062A\\u0645';\n t['\\uFC73'] = '\\u062A\\u0646';\n t['\\uFC74'] = '\\u062A\\u0649';\n t['\\uFC75'] = '\\u062A\\u064A';\n t['\\uFC76'] = '\\u062B\\u0631';\n t['\\uFC77'] = '\\u062B\\u0632';\n t['\\uFC78'] = '\\u062B\\u0645';\n t['\\uFC79'] = '\\u062B\\u0646';\n t['\\uFC7A'] = '\\u062B\\u0649';\n t['\\uFC7B'] = '\\u062B\\u064A';\n t['\\uFC7C'] = '\\u0641\\u0649';\n t['\\uFC7D'] = '\\u0641\\u064A';\n t['\\uFC7E'] = '\\u0642\\u0649';\n t['\\uFC7F'] = '\\u0642\\u064A';\n t['\\uFC80'] = '\\u0643\\u0627';\n t['\\uFC81'] = '\\u0643\\u0644';\n t['\\uFC82'] = '\\u0643\\u0645';\n t['\\uFC83'] = '\\u0643\\u0649';\n t['\\uFC84'] = '\\u0643\\u064A';\n t['\\uFC85'] = '\\u0644\\u0645';\n t['\\uFC86'] = '\\u0644\\u0649';\n t['\\uFC87'] = '\\u0644\\u064A';\n t['\\uFC88'] = '\\u0645\\u0627';\n t['\\uFC89'] = '\\u0645\\u0645';\n t['\\uFC8A'] = '\\u0646\\u0631';\n t['\\uFC8B'] = '\\u0646\\u0632';\n t['\\uFC8C'] = '\\u0646\\u0645';\n t['\\uFC8D'] = '\\u0646\\u0646';\n t['\\uFC8E'] = '\\u0646\\u0649';\n t['\\uFC8F'] = '\\u0646\\u064A';\n t['\\uFC90'] = '\\u0649\\u0670';\n t['\\uFC91'] = '\\u064A\\u0631';\n t['\\uFC92'] = '\\u064A\\u0632';\n t['\\uFC93'] = '\\u064A\\u0645';\n t['\\uFC94'] = '\\u064A\\u0646';\n t['\\uFC95'] = '\\u064A\\u0649';\n t['\\uFC96'] = '\\u064A\\u064A';\n t['\\uFC97'] = '\\u0626\\u062C';\n t['\\uFC98'] = '\\u0626\\u062D';\n t['\\uFC99'] = '\\u0626\\u062E';\n t['\\uFC9A'] = '\\u0626\\u0645';\n t['\\uFC9B'] = '\\u0626\\u0647';\n t['\\uFC9C'] = '\\u0628\\u062C';\n t['\\uFC9D'] = '\\u0628\\u062D';\n t['\\uFC9E'] = '\\u0628\\u062E';\n t['\\uFC9F'] = '\\u0628\\u0645';\n t['\\uFCA0'] = '\\u0628\\u0647';\n t['\\uFCA1'] = '\\u062A\\u062C';\n t['\\uFCA2'] = '\\u062A\\u062D';\n t['\\uFCA3'] = '\\u062A\\u062E';\n t['\\uFCA4'] = '\\u062A\\u0645';\n t['\\uFCA5'] = '\\u062A\\u0647';\n t['\\uFCA6'] = '\\u062B\\u0645';\n t['\\uFCA7'] = '\\u062C\\u062D';\n t['\\uFCA8'] = '\\u062C\\u0645';\n t['\\uFCA9'] = '\\u062D\\u062C';\n t['\\uFCAA'] = '\\u062D\\u0645';\n t['\\uFCAB'] = '\\u062E\\u062C';\n t['\\uFCAC'] = '\\u062E\\u0645';\n t['\\uFCAD'] = '\\u0633\\u062C';\n t['\\uFCAE'] = '\\u0633\\u062D';\n t['\\uFCAF'] = '\\u0633\\u062E';\n t['\\uFCB0'] = '\\u0633\\u0645';\n t['\\uFCB1'] = '\\u0635\\u062D';\n t['\\uFCB2'] = '\\u0635\\u062E';\n t['\\uFCB3'] = '\\u0635\\u0645';\n t['\\uFCB4'] = '\\u0636\\u062C';\n t['\\uFCB5'] = '\\u0636\\u062D';\n t['\\uFCB6'] = '\\u0636\\u062E';\n t['\\uFCB7'] = '\\u0636\\u0645';\n t['\\uFCB8'] = '\\u0637\\u062D';\n t['\\uFCB9'] = '\\u0638\\u0645';\n t['\\uFCBA'] = '\\u0639\\u062C';\n t['\\uFCBB'] = '\\u0639\\u0645';\n t['\\uFCBC'] = '\\u063A\\u062C';\n t['\\uFCBD'] = '\\u063A\\u0645';\n t['\\uFCBE'] = '\\u0641\\u062C';\n t['\\uFCBF'] = '\\u0641\\u062D';\n t['\\uFCC0'] = '\\u0641\\u062E';\n t['\\uFCC1'] = '\\u0641\\u0645';\n t['\\uFCC2'] = '\\u0642\\u062D';\n t['\\uFCC3'] = '\\u0642\\u0645';\n t['\\uFCC4'] = '\\u0643\\u062C';\n t['\\uFCC5'] = '\\u0643\\u062D';\n t['\\uFCC6'] = '\\u0643\\u062E';\n t['\\uFCC7'] = '\\u0643\\u0644';\n t['\\uFCC8'] = '\\u0643\\u0645';\n t['\\uFCC9'] = '\\u0644\\u062C';\n t['\\uFCCA'] = '\\u0644\\u062D';\n t['\\uFCCB'] = '\\u0644\\u062E';\n t['\\uFCCC'] = '\\u0644\\u0645';\n t['\\uFCCD'] = '\\u0644\\u0647';\n t['\\uFCCE'] = '\\u0645\\u062C';\n t['\\uFCCF'] = '\\u0645\\u062D';\n t['\\uFCD0'] = '\\u0645\\u062E';\n t['\\uFCD1'] = '\\u0645\\u0645';\n t['\\uFCD2'] = '\\u0646\\u062C';\n t['\\uFCD3'] = '\\u0646\\u062D';\n t['\\uFCD4'] = '\\u0646\\u062E';\n t['\\uFCD5'] = '\\u0646\\u0645';\n t['\\uFCD6'] = '\\u0646\\u0647';\n t['\\uFCD7'] = '\\u0647\\u062C';\n t['\\uFCD8'] = '\\u0647\\u0645';\n t['\\uFCD9'] = '\\u0647\\u0670';\n t['\\uFCDA'] = '\\u064A\\u062C';\n t['\\uFCDB'] = '\\u064A\\u062D';\n t['\\uFCDC'] = '\\u064A\\u062E';\n t['\\uFCDD'] = '\\u064A\\u0645';\n t['\\uFCDE'] = '\\u064A\\u0647';\n t['\\uFCDF'] = '\\u0626\\u0645';\n t['\\uFCE0'] = '\\u0626\\u0647';\n t['\\uFCE1'] = '\\u0628\\u0645';\n t['\\uFCE2'] = '\\u0628\\u0647';\n t['\\uFCE3'] = '\\u062A\\u0645';\n t['\\uFCE4'] = '\\u062A\\u0647';\n t['\\uFCE5'] = '\\u062B\\u0645';\n t['\\uFCE6'] = '\\u062B\\u0647';\n t['\\uFCE7'] = '\\u0633\\u0645';\n t['\\uFCE8'] = '\\u0633\\u0647';\n t['\\uFCE9'] = '\\u0634\\u0645';\n t['\\uFCEA'] = '\\u0634\\u0647';\n t['\\uFCEB'] = '\\u0643\\u0644';\n t['\\uFCEC'] = '\\u0643\\u0645';\n t['\\uFCED'] = '\\u0644\\u0645';\n t['\\uFCEE'] = '\\u0646\\u0645';\n t['\\uFCEF'] = '\\u0646\\u0647';\n t['\\uFCF0'] = '\\u064A\\u0645';\n t['\\uFCF1'] = '\\u064A\\u0647';\n t['\\uFCF2'] = '\\u0640\\u064E\\u0651';\n t['\\uFCF3'] = '\\u0640\\u064F\\u0651';\n t['\\uFCF4'] = '\\u0640\\u0650\\u0651';\n t['\\uFCF5'] = '\\u0637\\u0649';\n t['\\uFCF6'] = '\\u0637\\u064A';\n t['\\uFCF7'] = '\\u0639\\u0649';\n t['\\uFCF8'] = '\\u0639\\u064A';\n t['\\uFCF9'] = '\\u063A\\u0649';\n t['\\uFCFA'] = '\\u063A\\u064A';\n t['\\uFCFB'] = '\\u0633\\u0649';\n t['\\uFCFC'] = '\\u0633\\u064A';\n t['\\uFCFD'] = '\\u0634\\u0649';\n t['\\uFCFE'] = '\\u0634\\u064A';\n t['\\uFCFF'] = '\\u062D\\u0649';\n t['\\uFD00'] = '\\u062D\\u064A';\n t['\\uFD01'] = '\\u062C\\u0649';\n t['\\uFD02'] = '\\u062C\\u064A';\n t['\\uFD03'] = '\\u062E\\u0649';\n t['\\uFD04'] = '\\u062E\\u064A';\n t['\\uFD05'] = '\\u0635\\u0649';\n t['\\uFD06'] = '\\u0635\\u064A';\n t['\\uFD07'] = '\\u0636\\u0649';\n t['\\uFD08'] = '\\u0636\\u064A';\n t['\\uFD09'] = '\\u0634\\u062C';\n t['\\uFD0A'] = '\\u0634\\u062D';\n t['\\uFD0B'] = '\\u0634\\u062E';\n t['\\uFD0C'] = '\\u0634\\u0645';\n t['\\uFD0D'] = '\\u0634\\u0631';\n t['\\uFD0E'] = '\\u0633\\u0631';\n t['\\uFD0F'] = '\\u0635\\u0631';\n t['\\uFD10'] = '\\u0636\\u0631';\n t['\\uFD11'] = '\\u0637\\u0649';\n t['\\uFD12'] = '\\u0637\\u064A';\n t['\\uFD13'] = '\\u0639\\u0649';\n t['\\uFD14'] = '\\u0639\\u064A';\n t['\\uFD15'] = '\\u063A\\u0649';\n t['\\uFD16'] = '\\u063A\\u064A';\n t['\\uFD17'] = '\\u0633\\u0649';\n t['\\uFD18'] = '\\u0633\\u064A';\n t['\\uFD19'] = '\\u0634\\u0649';\n t['\\uFD1A'] = '\\u0634\\u064A';\n t['\\uFD1B'] = '\\u062D\\u0649';\n t['\\uFD1C'] = '\\u062D\\u064A';\n t['\\uFD1D'] = '\\u062C\\u0649';\n t['\\uFD1E'] = '\\u062C\\u064A';\n t['\\uFD1F'] = '\\u062E\\u0649';\n t['\\uFD20'] = '\\u062E\\u064A';\n t['\\uFD21'] = '\\u0635\\u0649';\n t['\\uFD22'] = '\\u0635\\u064A';\n t['\\uFD23'] = '\\u0636\\u0649';\n t['\\uFD24'] = '\\u0636\\u064A';\n t['\\uFD25'] = '\\u0634\\u062C';\n t['\\uFD26'] = '\\u0634\\u062D';\n t['\\uFD27'] = '\\u0634\\u062E';\n t['\\uFD28'] = '\\u0634\\u0645';\n t['\\uFD29'] = '\\u0634\\u0631';\n t['\\uFD2A'] = '\\u0633\\u0631';\n t['\\uFD2B'] = '\\u0635\\u0631';\n t['\\uFD2C'] = '\\u0636\\u0631';\n t['\\uFD2D'] = '\\u0634\\u062C';\n t['\\uFD2E'] = '\\u0634\\u062D';\n t['\\uFD2F'] = '\\u0634\\u062E';\n t['\\uFD30'] = '\\u0634\\u0645';\n t['\\uFD31'] = '\\u0633\\u0647';\n t['\\uFD32'] = '\\u0634\\u0647';\n t['\\uFD33'] = '\\u0637\\u0645';\n t['\\uFD34'] = '\\u0633\\u062C';\n t['\\uFD35'] = '\\u0633\\u062D';\n t['\\uFD36'] = '\\u0633\\u062E';\n t['\\uFD37'] = '\\u0634\\u062C';\n t['\\uFD38'] = '\\u0634\\u062D';\n t['\\uFD39'] = '\\u0634\\u062E';\n t['\\uFD3A'] = '\\u0637\\u0645';\n t['\\uFD3B'] = '\\u0638\\u0645';\n t['\\uFD3C'] = '\\u0627\\u064B';\n t['\\uFD3D'] = '\\u0627\\u064B';\n t['\\uFD50'] = '\\u062A\\u062C\\u0645';\n t['\\uFD51'] = '\\u062A\\u062D\\u062C';\n t['\\uFD52'] = '\\u062A\\u062D\\u062C';\n t['\\uFD53'] = '\\u062A\\u062D\\u0645';\n t['\\uFD54'] = '\\u062A\\u062E\\u0645';\n t['\\uFD55'] = '\\u062A\\u0645\\u062C';\n t['\\uFD56'] = '\\u062A\\u0645\\u062D';\n t['\\uFD57'] = '\\u062A\\u0645\\u062E';\n t['\\uFD58'] = '\\u062C\\u0645\\u062D';\n t['\\uFD59'] = '\\u062C\\u0645\\u062D';\n t['\\uFD5A'] = '\\u062D\\u0645\\u064A';\n t['\\uFD5B'] = '\\u062D\\u0645\\u0649';\n t['\\uFD5C'] = '\\u0633\\u062D\\u062C';\n t['\\uFD5D'] = '\\u0633\\u062C\\u062D';\n t['\\uFD5E'] = '\\u0633\\u062C\\u0649';\n t['\\uFD5F'] = '\\u0633\\u0645\\u062D';\n t['\\uFD60'] = '\\u0633\\u0645\\u062D';\n t['\\uFD61'] = '\\u0633\\u0645\\u062C';\n t['\\uFD62'] = '\\u0633\\u0645\\u0645';\n t['\\uFD63'] = '\\u0633\\u0645\\u0645';\n t['\\uFD64'] = '\\u0635\\u062D\\u062D';\n t['\\uFD65'] = '\\u0635\\u062D\\u062D';\n t['\\uFD66'] = '\\u0635\\u0645\\u0645';\n t['\\uFD67'] = '\\u0634\\u062D\\u0645';\n t['\\uFD68'] = '\\u0634\\u062D\\u0645';\n t['\\uFD69'] = '\\u0634\\u062C\\u064A';\n t['\\uFD6A'] = '\\u0634\\u0645\\u062E';\n t['\\uFD6B'] = '\\u0634\\u0645\\u062E';\n t['\\uFD6C'] = '\\u0634\\u0645\\u0645';\n t['\\uFD6D'] = '\\u0634\\u0645\\u0645';\n t['\\uFD6E'] = '\\u0636\\u062D\\u0649';\n t['\\uFD6F'] = '\\u0636\\u062E\\u0645';\n t['\\uFD70'] = '\\u0636\\u062E\\u0645';\n t['\\uFD71'] = '\\u0637\\u0645\\u062D';\n t['\\uFD72'] = '\\u0637\\u0645\\u062D';\n t['\\uFD73'] = '\\u0637\\u0645\\u0645';\n t['\\uFD74'] = '\\u0637\\u0645\\u064A';\n t['\\uFD75'] = '\\u0639\\u062C\\u0645';\n t['\\uFD76'] = '\\u0639\\u0645\\u0645';\n t['\\uFD77'] = '\\u0639\\u0645\\u0645';\n t['\\uFD78'] = '\\u0639\\u0645\\u0649';\n t['\\uFD79'] = '\\u063A\\u0645\\u0645';\n t['\\uFD7A'] = '\\u063A\\u0645\\u064A';\n t['\\uFD7B'] = '\\u063A\\u0645\\u0649';\n t['\\uFD7C'] = '\\u0641\\u062E\\u0645';\n t['\\uFD7D'] = '\\u0641\\u062E\\u0645';\n t['\\uFD7E'] = '\\u0642\\u0645\\u062D';\n t['\\uFD7F'] = '\\u0642\\u0645\\u0645';\n t['\\uFD80'] = '\\u0644\\u062D\\u0645';\n t['\\uFD81'] = '\\u0644\\u062D\\u064A';\n t['\\uFD82'] = '\\u0644\\u062D\\u0649';\n t['\\uFD83'] = '\\u0644\\u062C\\u062C';\n t['\\uFD84'] = '\\u0644\\u062C\\u062C';\n t['\\uFD85'] = '\\u0644\\u062E\\u0645';\n t['\\uFD86'] = '\\u0644\\u062E\\u0645';\n t['\\uFD87'] = '\\u0644\\u0645\\u062D';\n t['\\uFD88'] = '\\u0644\\u0645\\u062D';\n t['\\uFD89'] = '\\u0645\\u062D\\u062C';\n t['\\uFD8A'] = '\\u0645\\u062D\\u0645';\n t['\\uFD8B'] = '\\u0645\\u062D\\u064A';\n t['\\uFD8C'] = '\\u0645\\u062C\\u062D';\n t['\\uFD8D'] = '\\u0645\\u062C\\u0645';\n t['\\uFD8E'] = '\\u0645\\u062E\\u062C';\n t['\\uFD8F'] = '\\u0645\\u062E\\u0645';\n t['\\uFD92'] = '\\u0645\\u062C\\u062E';\n t['\\uFD93'] = '\\u0647\\u0645\\u062C';\n t['\\uFD94'] = '\\u0647\\u0645\\u0645';\n t['\\uFD95'] = '\\u0646\\u062D\\u0645';\n t['\\uFD96'] = '\\u0646\\u062D\\u0649';\n t['\\uFD97'] = '\\u0646\\u062C\\u0645';\n t['\\uFD98'] = '\\u0646\\u062C\\u0645';\n t['\\uFD99'] = '\\u0646\\u062C\\u0649';\n t['\\uFD9A'] = '\\u0646\\u0645\\u064A';\n t['\\uFD9B'] = '\\u0646\\u0645\\u0649';\n t['\\uFD9C'] = '\\u064A\\u0645\\u0645';\n t['\\uFD9D'] = '\\u064A\\u0645\\u0645';\n t['\\uFD9E'] = '\\u0628\\u062E\\u064A';\n t['\\uFD9F'] = '\\u062A\\u062C\\u064A';\n t['\\uFDA0'] = '\\u062A\\u062C\\u0649';\n t['\\uFDA1'] = '\\u062A\\u062E\\u064A';\n t['\\uFDA2'] = '\\u062A\\u062E\\u0649';\n t['\\uFDA3'] = '\\u062A\\u0645\\u064A';\n t['\\uFDA4'] = '\\u062A\\u0645\\u0649';\n t['\\uFDA5'] = '\\u062C\\u0645\\u064A';\n t['\\uFDA6'] = '\\u062C\\u062D\\u0649';\n t['\\uFDA7'] = '\\u062C\\u0645\\u0649';\n t['\\uFDA8'] = '\\u0633\\u062E\\u0649';\n t['\\uFDA9'] = '\\u0635\\u062D\\u064A';\n t['\\uFDAA'] = '\\u0634\\u062D\\u064A';\n t['\\uFDAB'] = '\\u0636\\u062D\\u064A';\n t['\\uFDAC'] = '\\u0644\\u062C\\u064A';\n t['\\uFDAD'] = '\\u0644\\u0645\\u064A';\n t['\\uFDAE'] = '\\u064A\\u062D\\u064A';\n t['\\uFDAF'] = '\\u064A\\u062C\\u064A';\n t['\\uFDB0'] = '\\u064A\\u0645\\u064A';\n t['\\uFDB1'] = '\\u0645\\u0645\\u064A';\n t['\\uFDB2'] = '\\u0642\\u0645\\u064A';\n t['\\uFDB3'] = '\\u0646\\u062D\\u064A';\n t['\\uFDB4'] = '\\u0642\\u0645\\u062D';\n t['\\uFDB5'] = '\\u0644\\u062D\\u0645';\n t['\\uFDB6'] = '\\u0639\\u0645\\u064A';\n t['\\uFDB7'] = '\\u0643\\u0645\\u064A';\n t['\\uFDB8'] = '\\u0646\\u062C\\u062D';\n t['\\uFDB9'] = '\\u0645\\u062E\\u064A';\n t['\\uFDBA'] = '\\u0644\\u062C\\u0645';\n t['\\uFDBB'] = '\\u0643\\u0645\\u0645';\n t['\\uFDBC'] = '\\u0644\\u062C\\u0645';\n t['\\uFDBD'] = '\\u0646\\u062C\\u062D';\n t['\\uFDBE'] = '\\u062C\\u062D\\u064A';\n t['\\uFDBF'] = '\\u062D\\u062C\\u064A';\n t['\\uFDC0'] = '\\u0645\\u062C\\u064A';\n t['\\uFDC1'] = '\\u0641\\u0645\\u064A';\n t['\\uFDC2'] = '\\u0628\\u062D\\u064A';\n t['\\uFDC3'] = '\\u0643\\u0645\\u0645';\n t['\\uFDC4'] = '\\u0639\\u062C\\u0645';\n t['\\uFDC5'] = '\\u0635\\u0645\\u0645';\n t['\\uFDC6'] = '\\u0633\\u062E\\u064A';\n t['\\uFDC7'] = '\\u0646\\u062C\\u064A';\n t['\\uFE49'] = '\\u203E';\n t['\\uFE4A'] = '\\u203E';\n t['\\uFE4B'] = '\\u203E';\n t['\\uFE4C'] = '\\u203E';\n t['\\uFE4D'] = '\\u005F';\n t['\\uFE4E'] = '\\u005F';\n t['\\uFE4F'] = '\\u005F';\n t['\\uFE80'] = '\\u0621';\n t['\\uFE81'] = '\\u0622';\n t['\\uFE82'] = '\\u0622';\n t['\\uFE83'] = '\\u0623';\n t['\\uFE84'] = '\\u0623';\n t['\\uFE85'] = '\\u0624';\n t['\\uFE86'] = '\\u0624';\n t['\\uFE87'] = '\\u0625';\n t['\\uFE88'] = '\\u0625';\n t['\\uFE89'] = '\\u0626';\n t['\\uFE8A'] = '\\u0626';\n t['\\uFE8B'] = '\\u0626';\n t['\\uFE8C'] = '\\u0626';\n t['\\uFE8D'] = '\\u0627';\n t['\\uFE8E'] = '\\u0627';\n t['\\uFE8F'] = '\\u0628';\n t['\\uFE90'] = '\\u0628';\n t['\\uFE91'] = '\\u0628';\n t['\\uFE92'] = '\\u0628';\n t['\\uFE93'] = '\\u0629';\n t['\\uFE94'] = '\\u0629';\n t['\\uFE95'] = '\\u062A';\n t['\\uFE96'] = '\\u062A';\n t['\\uFE97'] = '\\u062A';\n t['\\uFE98'] = '\\u062A';\n t['\\uFE99'] = '\\u062B';\n t['\\uFE9A'] = '\\u062B';\n t['\\uFE9B'] = '\\u062B';\n t['\\uFE9C'] = '\\u062B';\n t['\\uFE9D'] = '\\u062C';\n t['\\uFE9E'] = '\\u062C';\n t['\\uFE9F'] = '\\u062C';\n t['\\uFEA0'] = '\\u062C';\n t['\\uFEA1'] = '\\u062D';\n t['\\uFEA2'] = '\\u062D';\n t['\\uFEA3'] = '\\u062D';\n t['\\uFEA4'] = '\\u062D';\n t['\\uFEA5'] = '\\u062E';\n t['\\uFEA6'] = '\\u062E';\n t['\\uFEA7'] = '\\u062E';\n t['\\uFEA8'] = '\\u062E';\n t['\\uFEA9'] = '\\u062F';\n t['\\uFEAA'] = '\\u062F';\n t['\\uFEAB'] = '\\u0630';\n t['\\uFEAC'] = '\\u0630';\n t['\\uFEAD'] = '\\u0631';\n t['\\uFEAE'] = '\\u0631';\n t['\\uFEAF'] = '\\u0632';\n t['\\uFEB0'] = '\\u0632';\n t['\\uFEB1'] = '\\u0633';\n t['\\uFEB2'] = '\\u0633';\n t['\\uFEB3'] = '\\u0633';\n t['\\uFEB4'] = '\\u0633';\n t['\\uFEB5'] = '\\u0634';\n t['\\uFEB6'] = '\\u0634';\n t['\\uFEB7'] = '\\u0634';\n t['\\uFEB8'] = '\\u0634';\n t['\\uFEB9'] = '\\u0635';\n t['\\uFEBA'] = '\\u0635';\n t['\\uFEBB'] = '\\u0635';\n t['\\uFEBC'] = '\\u0635';\n t['\\uFEBD'] = '\\u0636';\n t['\\uFEBE'] = '\\u0636';\n t['\\uFEBF'] = '\\u0636';\n t['\\uFEC0'] = '\\u0636';\n t['\\uFEC1'] = '\\u0637';\n t['\\uFEC2'] = '\\u0637';\n t['\\uFEC3'] = '\\u0637';\n t['\\uFEC4'] = '\\u0637';\n t['\\uFEC5'] = '\\u0638';\n t['\\uFEC6'] = '\\u0638';\n t['\\uFEC7'] = '\\u0638';\n t['\\uFEC8'] = '\\u0638';\n t['\\uFEC9'] = '\\u0639';\n t['\\uFECA'] = '\\u0639';\n t['\\uFECB'] = '\\u0639';\n t['\\uFECC'] = '\\u0639';\n t['\\uFECD'] = '\\u063A';\n t['\\uFECE'] = '\\u063A';\n t['\\uFECF'] = '\\u063A';\n t['\\uFED0'] = '\\u063A';\n t['\\uFED1'] = '\\u0641';\n t['\\uFED2'] = '\\u0641';\n t['\\uFED3'] = '\\u0641';\n t['\\uFED4'] = '\\u0641';\n t['\\uFED5'] = '\\u0642';\n t['\\uFED6'] = '\\u0642';\n t['\\uFED7'] = '\\u0642';\n t['\\uFED8'] = '\\u0642';\n t['\\uFED9'] = '\\u0643';\n t['\\uFEDA'] = '\\u0643';\n t['\\uFEDB'] = '\\u0643';\n t['\\uFEDC'] = '\\u0643';\n t['\\uFEDD'] = '\\u0644';\n t['\\uFEDE'] = '\\u0644';\n t['\\uFEDF'] = '\\u0644';\n t['\\uFEE0'] = '\\u0644';\n t['\\uFEE1'] = '\\u0645';\n t['\\uFEE2'] = '\\u0645';\n t['\\uFEE3'] = '\\u0645';\n t['\\uFEE4'] = '\\u0645';\n t['\\uFEE5'] = '\\u0646';\n t['\\uFEE6'] = '\\u0646';\n t['\\uFEE7'] = '\\u0646';\n t['\\uFEE8'] = '\\u0646';\n t['\\uFEE9'] = '\\u0647';\n t['\\uFEEA'] = '\\u0647';\n t['\\uFEEB'] = '\\u0647';\n t['\\uFEEC'] = '\\u0647';\n t['\\uFEED'] = '\\u0648';\n t['\\uFEEE'] = '\\u0648';\n t['\\uFEEF'] = '\\u0649';\n t['\\uFEF0'] = '\\u0649';\n t['\\uFEF1'] = '\\u064A';\n t['\\uFEF2'] = '\\u064A';\n t['\\uFEF3'] = '\\u064A';\n t['\\uFEF4'] = '\\u064A';\n t['\\uFEF5'] = '\\u0644\\u0622';\n t['\\uFEF6'] = '\\u0644\\u0622';\n t['\\uFEF7'] = '\\u0644\\u0623';\n t['\\uFEF8'] = '\\u0644\\u0623';\n t['\\uFEF9'] = '\\u0644\\u0625';\n t['\\uFEFA'] = '\\u0644\\u0625';\n t['\\uFEFB'] = '\\u0644\\u0627';\n t['\\uFEFC'] = '\\u0644\\u0627';\n});\n\nfunction reverseIfRtl(chars) {\n var charsLength = chars.length;\n // Reverse an arabic ligature.\n if (charsLength <= 1 || !isRTLRangeFor(chars.charCodeAt(0))) {\n return chars;\n }\n var s = '';\n for (var ii = charsLength - 1; ii >= 0; ii--) {\n s += chars[ii];\n }\n return s;\n}\n\nexports.mapSpecialUnicodeValues = mapSpecialUnicodeValues;\nexports.reverseIfRtl = reverseIfRtl;\nexports.getUnicodeRangeFor = getUnicodeRangeFor;\nexports.getNormalizedUnicodes = getNormalizedUnicodes;\nexports.getUnicodeForGlyph = getUnicodeForGlyph;\n\n\n\n// WEBPACK FOOTER //\n// src/core/unicode.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/* This class implements the QM Coder decoding as defined in\n * JPEG 2000 Part I Final Committee Draft Version 1.0\n * Annex C.3 Arithmetic decoding procedure\n * available at http://www.jpeg.org/public/fcd15444-1.pdf\n *\n * The arithmetic decoder is used in conjunction with context models to decode\n * JPEG2000 and JBIG2 streams.\n */\nvar ArithmeticDecoder = (function ArithmeticDecoderClosure() {\n // Table C-2\n var QeTable = [\n { qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1, },\n { qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0, },\n { qe: 0x1801, nmps: 3, nlps: 9, switchFlag: 0, },\n { qe: 0x0AC1, nmps: 4, nlps: 12, switchFlag: 0, },\n { qe: 0x0521, nmps: 5, nlps: 29, switchFlag: 0, },\n { qe: 0x0221, nmps: 38, nlps: 33, switchFlag: 0, },\n { qe: 0x5601, nmps: 7, nlps: 6, switchFlag: 1, },\n { qe: 0x5401, nmps: 8, nlps: 14, switchFlag: 0, },\n { qe: 0x4801, nmps: 9, nlps: 14, switchFlag: 0, },\n { qe: 0x3801, nmps: 10, nlps: 14, switchFlag: 0, },\n { qe: 0x3001, nmps: 11, nlps: 17, switchFlag: 0, },\n { qe: 0x2401, nmps: 12, nlps: 18, switchFlag: 0, },\n { qe: 0x1C01, nmps: 13, nlps: 20, switchFlag: 0, },\n { qe: 0x1601, nmps: 29, nlps: 21, switchFlag: 0, },\n { qe: 0x5601, nmps: 15, nlps: 14, switchFlag: 1, },\n { qe: 0x5401, nmps: 16, nlps: 14, switchFlag: 0, },\n { qe: 0x5101, nmps: 17, nlps: 15, switchFlag: 0, },\n { qe: 0x4801, nmps: 18, nlps: 16, switchFlag: 0, },\n { qe: 0x3801, nmps: 19, nlps: 17, switchFlag: 0, },\n { qe: 0x3401, nmps: 20, nlps: 18, switchFlag: 0, },\n { qe: 0x3001, nmps: 21, nlps: 19, switchFlag: 0, },\n { qe: 0x2801, nmps: 22, nlps: 19, switchFlag: 0, },\n { qe: 0x2401, nmps: 23, nlps: 20, switchFlag: 0, },\n { qe: 0x2201, nmps: 24, nlps: 21, switchFlag: 0, },\n { qe: 0x1C01, nmps: 25, nlps: 22, switchFlag: 0, },\n { qe: 0x1801, nmps: 26, nlps: 23, switchFlag: 0, },\n { qe: 0x1601, nmps: 27, nlps: 24, switchFlag: 0, },\n { qe: 0x1401, nmps: 28, nlps: 25, switchFlag: 0, },\n { qe: 0x1201, nmps: 29, nlps: 26, switchFlag: 0, },\n { qe: 0x1101, nmps: 30, nlps: 27, switchFlag: 0, },\n { qe: 0x0AC1, nmps: 31, nlps: 28, switchFlag: 0, },\n { qe: 0x09C1, nmps: 32, nlps: 29, switchFlag: 0, },\n { qe: 0x08A1, nmps: 33, nlps: 30, switchFlag: 0, },\n { qe: 0x0521, nmps: 34, nlps: 31, switchFlag: 0, },\n { qe: 0x0441, nmps: 35, nlps: 32, switchFlag: 0, },\n { qe: 0x02A1, nmps: 36, nlps: 33, switchFlag: 0, },\n { qe: 0x0221, nmps: 37, nlps: 34, switchFlag: 0, },\n { qe: 0x0141, nmps: 38, nlps: 35, switchFlag: 0, },\n { qe: 0x0111, nmps: 39, nlps: 36, switchFlag: 0, },\n { qe: 0x0085, nmps: 40, nlps: 37, switchFlag: 0, },\n { qe: 0x0049, nmps: 41, nlps: 38, switchFlag: 0, },\n { qe: 0x0025, nmps: 42, nlps: 39, switchFlag: 0, },\n { qe: 0x0015, nmps: 43, nlps: 40, switchFlag: 0, },\n { qe: 0x0009, nmps: 44, nlps: 41, switchFlag: 0, },\n { qe: 0x0005, nmps: 45, nlps: 42, switchFlag: 0, },\n { qe: 0x0001, nmps: 45, nlps: 43, switchFlag: 0, },\n { qe: 0x5601, nmps: 46, nlps: 46, switchFlag: 0, }\n ];\n\n // C.3.5 Initialisation of the decoder (INITDEC)\n function ArithmeticDecoder(data, start, end) {\n this.data = data;\n this.bp = start;\n this.dataEnd = end;\n\n this.chigh = data[start];\n this.clow = 0;\n\n this.byteIn();\n\n this.chigh = ((this.chigh << 7) & 0xFFFF) | ((this.clow >> 9) & 0x7F);\n this.clow = (this.clow << 7) & 0xFFFF;\n this.ct -= 7;\n this.a = 0x8000;\n }\n\n ArithmeticDecoder.prototype = {\n // C.3.4 Compressed data input (BYTEIN)\n byteIn: function ArithmeticDecoder_byteIn() {\n var data = this.data;\n var bp = this.bp;\n if (data[bp] === 0xFF) {\n var b1 = data[bp + 1];\n if (b1 > 0x8F) {\n this.clow += 0xFF00;\n this.ct = 8;\n } else {\n bp++;\n this.clow += (data[bp] << 9);\n this.ct = 7;\n this.bp = bp;\n }\n } else {\n bp++;\n this.clow += bp < this.dataEnd ? (data[bp] << 8) : 0xFF00;\n this.ct = 8;\n this.bp = bp;\n }\n if (this.clow > 0xFFFF) {\n this.chigh += (this.clow >> 16);\n this.clow &= 0xFFFF;\n }\n },\n // C.3.2 Decoding a decision (DECODE)\n readBit: function ArithmeticDecoder_readBit(contexts, pos) {\n // contexts are packed into 1 byte:\n // highest 7 bits carry cx.index, lowest bit carries cx.mps\n var cx_index = contexts[pos] >> 1, cx_mps = contexts[pos] & 1;\n var qeTableIcx = QeTable[cx_index];\n var qeIcx = qeTableIcx.qe;\n var d;\n var a = this.a - qeIcx;\n\n if (this.chigh < qeIcx) {\n // exchangeLps\n if (a < qeIcx) {\n a = qeIcx;\n d = cx_mps;\n cx_index = qeTableIcx.nmps;\n } else {\n a = qeIcx;\n d = 1 ^ cx_mps;\n if (qeTableIcx.switchFlag === 1) {\n cx_mps = d;\n }\n cx_index = qeTableIcx.nlps;\n }\n } else {\n this.chigh -= qeIcx;\n if ((a & 0x8000) !== 0) {\n this.a = a;\n return cx_mps;\n }\n // exchangeMps\n if (a < qeIcx) {\n d = 1 ^ cx_mps;\n if (qeTableIcx.switchFlag === 1) {\n cx_mps = d;\n }\n cx_index = qeTableIcx.nlps;\n } else {\n d = cx_mps;\n cx_index = qeTableIcx.nmps;\n }\n }\n // C.3.3 renormD;\n do {\n if (this.ct === 0) {\n this.byteIn();\n }\n\n a <<= 1;\n this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1);\n this.clow = (this.clow << 1) & 0xFFFF;\n this.ct--;\n } while ((a & 0x8000) === 0);\n this.a = a;\n\n contexts[pos] = cx_index << 1 | cx_mps;\n return d;\n },\n };\n\n return ArithmeticDecoder;\n})();\n\nexport {\n ArithmeticDecoder,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/arithmetic_decoder.js","/* Copyright 2016 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n bytesToString, FormatError, info, isArray, stringToBytes, Util, warn\n} from '../shared/util';\nimport {\n ExpertCharset, ExpertSubsetCharset, ISOAdobeCharset\n} from './charsets';\nimport { ExpertEncoding, StandardEncoding } from './encodings';\n\n// Maximum subroutine call depth of type 2 chartrings. Matches OTS.\nvar MAX_SUBR_NESTING = 10;\n\n/**\n * The CFF class takes a Type1 file and wrap it into a\n * 'Compact Font Format' which itself embed Type2 charstrings.\n */\nvar CFFStandardStrings = [\n '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',\n 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus',\n 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four',\n 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less',\n 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',\n 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',\n 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum',\n 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',\n 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',\n 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent',\n 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',\n 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',\n 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl',\n 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase',\n 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', 'questiondown',\n 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent',\n 'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'emdash',\n 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae',\n 'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior',\n 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn',\n 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters',\n 'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior',\n 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring',\n 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave',\n 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute',\n 'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute',\n 'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron',\n 'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde',\n 'ccedilla', 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute',\n 'icircumflex', 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex',\n 'odieresis', 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex',\n 'udieresis', 'ugrave', 'yacute', 'ydieresis', 'zcaron', 'exclamsmall',\n 'Hungarumlautsmall', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall',\n 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',\n 'onedotenleader', 'zerooldstyle', 'oneoldstyle', 'twooldstyle',\n 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle',\n 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'commasuperior',\n 'threequartersemdash', 'periodsuperior', 'questionsmall', 'asuperior',\n 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior',\n 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',\n 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior', 'parenrightinferior',\n 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall',\n 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall',\n 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall',\n 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall',\n 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah',\n 'Tildesmall', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall',\n 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall',\n 'Dotaccentsmall', 'Macronsmall', 'figuredash', 'hypheninferior',\n 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', 'questiondownsmall', 'oneeighth',\n 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds',\n 'zerosuperior', 'foursuperior', 'fivesuperior', 'sixsuperior',\n 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior',\n 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior',\n 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior',\n 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior',\n 'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall',\n 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall',\n 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall',\n 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall',\n 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall',\n 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall',\n 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall',\n 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002', '001.003',\n 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', 'Semibold'\n];\n\n\nvar CFFParser = (function CFFParserClosure() {\n var CharstringValidationData = [\n null,\n { id: 'hstem', min: 2, stackClearing: true, stem: true, },\n null,\n { id: 'vstem', min: 2, stackClearing: true, stem: true, },\n { id: 'vmoveto', min: 1, stackClearing: true, },\n { id: 'rlineto', min: 2, resetStack: true, },\n { id: 'hlineto', min: 1, resetStack: true, },\n { id: 'vlineto', min: 1, resetStack: true, },\n { id: 'rrcurveto', min: 6, resetStack: true, },\n null,\n { id: 'callsubr', min: 1, undefStack: true, },\n { id: 'return', min: 0, undefStack: true, },\n null, // 12\n null,\n { id: 'endchar', min: 0, stackClearing: true, },\n null,\n null,\n null,\n { id: 'hstemhm', min: 2, stackClearing: true, stem: true, },\n { id: 'hintmask', min: 0, stackClearing: true, },\n { id: 'cntrmask', min: 0, stackClearing: true, },\n { id: 'rmoveto', min: 2, stackClearing: true, },\n { id: 'hmoveto', min: 1, stackClearing: true, },\n { id: 'vstemhm', min: 2, stackClearing: true, stem: true, },\n { id: 'rcurveline', min: 8, resetStack: true, },\n { id: 'rlinecurve', min: 8, resetStack: true, },\n { id: 'vvcurveto', min: 4, resetStack: true, },\n { id: 'hhcurveto', min: 4, resetStack: true, },\n null, // shortint\n { id: 'callgsubr', min: 1, undefStack: true, },\n { id: 'vhcurveto', min: 4, resetStack: true, },\n { id: 'hvcurveto', min: 4, resetStack: true, }\n ];\n var CharstringValidationData12 = [\n null,\n null,\n null,\n { id: 'and', min: 2, stackDelta: -1, },\n { id: 'or', min: 2, stackDelta: -1, },\n { id: 'not', min: 1, stackDelta: 0, },\n null,\n null,\n null,\n { id: 'abs', min: 1, stackDelta: 0, },\n { id: 'add', min: 2, stackDelta: -1,\n stackFn: function stack_div(stack, index) {\n stack[index - 2] = stack[index - 2] + stack[index - 1];\n },\n },\n { id: 'sub', min: 2, stackDelta: -1,\n stackFn: function stack_div(stack, index) {\n stack[index - 2] = stack[index - 2] - stack[index - 1];\n },\n },\n { id: 'div', min: 2, stackDelta: -1,\n stackFn: function stack_div(stack, index) {\n stack[index - 2] = stack[index - 2] / stack[index - 1];\n },\n },\n null,\n { id: 'neg', min: 1, stackDelta: 0,\n stackFn: function stack_div(stack, index) {\n stack[index - 1] = -stack[index - 1];\n },\n },\n { id: 'eq', min: 2, stackDelta: -1, },\n null,\n null,\n { id: 'drop', min: 1, stackDelta: -1, },\n null,\n { id: 'put', min: 2, stackDelta: -2, },\n { id: 'get', min: 1, stackDelta: 0, },\n { id: 'ifelse', min: 4, stackDelta: -3, },\n { id: 'random', min: 0, stackDelta: 1, },\n { id: 'mul', min: 2, stackDelta: -1,\n stackFn: function stack_div(stack, index) {\n stack[index - 2] = stack[index - 2] * stack[index - 1];\n },\n },\n null,\n { id: 'sqrt', min: 1, stackDelta: 0, },\n { id: 'dup', min: 1, stackDelta: 1, },\n { id: 'exch', min: 2, stackDelta: 0, },\n { id: 'index', min: 2, stackDelta: 0, },\n { id: 'roll', min: 3, stackDelta: -2, },\n null,\n null,\n null,\n { id: 'hflex', min: 7, resetStack: true, },\n { id: 'flex', min: 13, resetStack: true, },\n { id: 'hflex1', min: 9, resetStack: true, },\n { id: 'flex1', min: 11, resetStack: true, }\n ];\n\n function CFFParser(file, properties, seacAnalysisEnabled) {\n this.bytes = file.getBytes();\n this.properties = properties;\n this.seacAnalysisEnabled = !!seacAnalysisEnabled;\n }\n CFFParser.prototype = {\n parse: function CFFParser_parse() {\n var properties = this.properties;\n var cff = new CFF();\n this.cff = cff;\n\n // The first five sections must be in order, all the others are reached\n // via offsets contained in one of the below.\n var header = this.parseHeader();\n var nameIndex = this.parseIndex(header.endPos);\n var topDictIndex = this.parseIndex(nameIndex.endPos);\n var stringIndex = this.parseIndex(topDictIndex.endPos);\n var globalSubrIndex = this.parseIndex(stringIndex.endPos);\n\n var topDictParsed = this.parseDict(topDictIndex.obj.get(0));\n var topDict = this.createDict(CFFTopDict, topDictParsed, cff.strings);\n\n cff.header = header.obj;\n cff.names = this.parseNameIndex(nameIndex.obj);\n cff.strings = this.parseStringIndex(stringIndex.obj);\n cff.topDict = topDict;\n cff.globalSubrIndex = globalSubrIndex.obj;\n\n this.parsePrivateDict(cff.topDict);\n\n cff.isCIDFont = topDict.hasName('ROS');\n\n var charStringOffset = topDict.getByName('CharStrings');\n var charStringIndex = this.parseIndex(charStringOffset).obj;\n\n var fontMatrix = topDict.getByName('FontMatrix');\n if (fontMatrix) {\n properties.fontMatrix = fontMatrix;\n }\n\n var fontBBox = topDict.getByName('FontBBox');\n if (fontBBox) {\n // adjusting ascent/descent\n properties.ascent = Math.max(fontBBox[3], fontBBox[1]);\n properties.descent = Math.min(fontBBox[1], fontBBox[3]);\n properties.ascentScaled = true;\n }\n\n var charset, encoding;\n if (cff.isCIDFont) {\n var fdArrayIndex = this.parseIndex(topDict.getByName('FDArray')).obj;\n for (var i = 0, ii = fdArrayIndex.count; i < ii; ++i) {\n var dictRaw = fdArrayIndex.get(i);\n var fontDict = this.createDict(CFFTopDict, this.parseDict(dictRaw),\n cff.strings);\n this.parsePrivateDict(fontDict);\n cff.fdArray.push(fontDict);\n }\n // cid fonts don't have an encoding\n encoding = null;\n charset = this.parseCharsets(topDict.getByName('charset'),\n charStringIndex.count, cff.strings, true);\n cff.fdSelect = this.parseFDSelect(topDict.getByName('FDSelect'),\n charStringIndex.count);\n } else {\n charset = this.parseCharsets(topDict.getByName('charset'),\n charStringIndex.count, cff.strings, false);\n encoding = this.parseEncoding(topDict.getByName('Encoding'),\n properties,\n cff.strings, charset.charset);\n }\n\n cff.charset = charset;\n cff.encoding = encoding;\n\n var charStringsAndSeacs = this.parseCharStrings({\n charStrings: charStringIndex,\n localSubrIndex: topDict.privateDict.subrsIndex,\n globalSubrIndex: globalSubrIndex.obj,\n fdSelect: cff.fdSelect,\n fdArray: cff.fdArray,\n privateDict: topDict.privateDict,\n });\n cff.charStrings = charStringsAndSeacs.charStrings;\n cff.seacs = charStringsAndSeacs.seacs;\n cff.widths = charStringsAndSeacs.widths;\n\n return cff;\n },\n parseHeader: function CFFParser_parseHeader() {\n var bytes = this.bytes;\n var bytesLength = bytes.length;\n var offset = 0;\n\n // Prevent an infinite loop, by checking that the offset is within the\n // bounds of the bytes array. Necessary in empty, or invalid, font files.\n while (offset < bytesLength && bytes[offset] !== 1) {\n ++offset;\n }\n if (offset >= bytesLength) {\n throw new FormatError('Invalid CFF header');\n }\n if (offset !== 0) {\n info('cff data is shifted');\n bytes = bytes.subarray(offset);\n this.bytes = bytes;\n }\n var major = bytes[0];\n var minor = bytes[1];\n var hdrSize = bytes[2];\n var offSize = bytes[3];\n var header = new CFFHeader(major, minor, hdrSize, offSize);\n return { obj: header, endPos: hdrSize, };\n },\n parseDict: function CFFParser_parseDict(dict) {\n var pos = 0;\n\n function parseOperand() {\n var value = dict[pos++];\n if (value === 30) {\n return parseFloatOperand();\n } else if (value === 28) {\n value = dict[pos++];\n value = ((value << 24) | (dict[pos++] << 16)) >> 16;\n return value;\n } else if (value === 29) {\n value = dict[pos++];\n value = (value << 8) | dict[pos++];\n value = (value << 8) | dict[pos++];\n value = (value << 8) | dict[pos++];\n return value;\n } else if (value >= 32 && value <= 246) {\n return value - 139;\n } else if (value >= 247 && value <= 250) {\n return ((value - 247) * 256) + dict[pos++] + 108;\n } else if (value >= 251 && value <= 254) {\n return -((value - 251) * 256) - dict[pos++] - 108;\n }\n warn('CFFParser_parseDict: \"' + value + '\" is a reserved command.');\n return NaN;\n }\n\n function parseFloatOperand() {\n var str = '';\n var eof = 15;\n var lookup = ['0', '1', '2', '3', '4', '5', '6', '7', '8',\n '9', '.', 'E', 'E-', null, '-'];\n var length = dict.length;\n while (pos < length) {\n var b = dict[pos++];\n var b1 = b >> 4;\n var b2 = b & 15;\n\n if (b1 === eof) {\n break;\n }\n str += lookup[b1];\n\n if (b2 === eof) {\n break;\n }\n str += lookup[b2];\n }\n return parseFloat(str);\n }\n\n var operands = [];\n var entries = [];\n\n pos = 0;\n var end = dict.length;\n while (pos < end) {\n var b = dict[pos];\n if (b <= 21) {\n if (b === 12) {\n b = (b << 8) | dict[++pos];\n }\n entries.push([b, operands]);\n operands = [];\n ++pos;\n } else {\n operands.push(parseOperand());\n }\n }\n return entries;\n },\n parseIndex: function CFFParser_parseIndex(pos) {\n var cffIndex = new CFFIndex();\n var bytes = this.bytes;\n var count = (bytes[pos++] << 8) | bytes[pos++];\n var offsets = [];\n var end = pos;\n var i, ii;\n\n if (count !== 0) {\n var offsetSize = bytes[pos++];\n // add 1 for offset to determine size of last object\n var startPos = pos + ((count + 1) * offsetSize) - 1;\n\n for (i = 0, ii = count + 1; i < ii; ++i) {\n var offset = 0;\n for (var j = 0; j < offsetSize; ++j) {\n offset <<= 8;\n offset += bytes[pos++];\n }\n offsets.push(startPos + offset);\n }\n end = offsets[count];\n }\n for (i = 0, ii = offsets.length - 1; i < ii; ++i) {\n var offsetStart = offsets[i];\n var offsetEnd = offsets[i + 1];\n cffIndex.add(bytes.subarray(offsetStart, offsetEnd));\n }\n return { obj: cffIndex, endPos: end, };\n },\n parseNameIndex: function CFFParser_parseNameIndex(index) {\n var names = [];\n for (var i = 0, ii = index.count; i < ii; ++i) {\n var name = index.get(i);\n // OTS doesn't allow names to be over 127 characters.\n var length = Math.min(name.length, 127);\n var data = [];\n // OTS also only permits certain characters in the name.\n for (var j = 0; j < length; ++j) {\n var c = name[j];\n if (j === 0 && c === 0) {\n data[j] = c;\n continue;\n }\n if ((c < 33 || c > 126) || c === 91 /* [ */ || c === 93 /* ] */ ||\n c === 40 /* ( */ || c === 41 /* ) */ || c === 123 /* { */ ||\n c === 125 /* } */ || c === 60 /* < */ || c === 62 /* > */ ||\n c === 47 /* / */ || c === 37 /* % */ || c === 35 /* # */) {\n data[j] = 95;\n continue;\n }\n data[j] = c;\n }\n names.push(bytesToString(data));\n }\n return names;\n },\n parseStringIndex: function CFFParser_parseStringIndex(index) {\n var strings = new CFFStrings();\n for (var i = 0, ii = index.count; i < ii; ++i) {\n var data = index.get(i);\n strings.add(bytesToString(data));\n }\n return strings;\n },\n createDict: function CFFParser_createDict(Type, dict, strings) {\n var cffDict = new Type(strings);\n for (var i = 0, ii = dict.length; i < ii; ++i) {\n var pair = dict[i];\n var key = pair[0];\n var value = pair[1];\n cffDict.setByKey(key, value);\n }\n return cffDict;\n },\n parseCharString: function CFFParser_parseCharString(state, data,\n localSubrIndex,\n globalSubrIndex) {\n if (!data || state.callDepth > MAX_SUBR_NESTING) {\n return false;\n }\n var stackSize = state.stackSize;\n var stack = state.stack;\n\n var length = data.length;\n\n for (var j = 0; j < length;) {\n var value = data[j++];\n var validationCommand = null;\n if (value === 12) {\n var q = data[j++];\n if (q === 0) {\n // The CFF specification state that the 'dotsection' command\n // (12, 0) is deprecated and treated as a no-op, but all Type2\n // charstrings processors should support them. Unfortunately\n // the font sanitizer don't. As a workaround the sequence (12, 0)\n // is replaced by a useless (0, hmoveto).\n data[j - 2] = 139;\n data[j - 1] = 22;\n stackSize = 0;\n } else {\n validationCommand = CharstringValidationData12[q];\n }\n } else if (value === 28) { // number (16 bit)\n stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16)) >> 16;\n j += 2;\n stackSize++;\n } else if (value === 14) {\n if (stackSize >= 4) {\n stackSize -= 4;\n if (this.seacAnalysisEnabled) {\n state.seac = stack.slice(stackSize, stackSize + 4);\n return false;\n }\n }\n validationCommand = CharstringValidationData[value];\n } else if (value >= 32 && value <= 246) { // number\n stack[stackSize] = value - 139;\n stackSize++;\n } else if (value >= 247 && value <= 254) { // number (+1 bytes)\n stack[stackSize] = (value < 251 ?\n ((value - 247) << 8) + data[j] + 108 :\n -((value - 251) << 8) - data[j] - 108);\n j++;\n stackSize++;\n } else if (value === 255) { // number (32 bit)\n stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16) |\n (data[j + 2] << 8) | data[j + 3]) / 65536;\n j += 4;\n stackSize++;\n } else if (value === 19 || value === 20) {\n state.hints += stackSize >> 1;\n // skipping right amount of hints flag data\n j += (state.hints + 7) >> 3;\n stackSize %= 2;\n validationCommand = CharstringValidationData[value];\n } else if (value === 10 || value === 29) {\n var subrsIndex;\n if (value === 10) {\n subrsIndex = localSubrIndex;\n } else {\n subrsIndex = globalSubrIndex;\n }\n if (!subrsIndex) {\n validationCommand = CharstringValidationData[value];\n warn('Missing subrsIndex for ' + validationCommand.id);\n return false;\n }\n var bias = 32768;\n if (subrsIndex.count < 1240) {\n bias = 107;\n } else if (subrsIndex.count < 33900) {\n bias = 1131;\n }\n var subrNumber = stack[--stackSize] + bias;\n if (subrNumber < 0 || subrNumber >= subrsIndex.count ||\n isNaN(subrNumber)) {\n validationCommand = CharstringValidationData[value];\n warn('Out of bounds subrIndex for ' + validationCommand.id);\n return false;\n }\n state.stackSize = stackSize;\n state.callDepth++;\n var valid = this.parseCharString(state, subrsIndex.get(subrNumber),\n localSubrIndex, globalSubrIndex);\n if (!valid) {\n return false;\n }\n state.callDepth--;\n stackSize = state.stackSize;\n continue;\n } else if (value === 11) {\n state.stackSize = stackSize;\n return true;\n } else {\n validationCommand = CharstringValidationData[value];\n }\n if (validationCommand) {\n if (validationCommand.stem) {\n state.hints += stackSize >> 1;\n }\n if ('min' in validationCommand) {\n if (!state.undefStack && stackSize < validationCommand.min) {\n warn('Not enough parameters for ' + validationCommand.id +\n '; actual: ' + stackSize +\n ', expected: ' + validationCommand.min);\n return false;\n }\n }\n if (state.firstStackClearing && validationCommand.stackClearing) {\n state.firstStackClearing = false;\n // the optional character width can be found before the first\n // stack-clearing command arguments\n stackSize -= validationCommand.min;\n if (stackSize >= 2 && validationCommand.stem) {\n // there are even amount of arguments for stem commands\n stackSize %= 2;\n } else if (stackSize > 1) {\n warn('Found too many parameters for stack-clearing command');\n }\n if (stackSize > 0 && stack[stackSize - 1] >= 0) {\n state.width = stack[stackSize - 1];\n }\n }\n if ('stackDelta' in validationCommand) {\n if ('stackFn' in validationCommand) {\n validationCommand.stackFn(stack, stackSize);\n }\n stackSize += validationCommand.stackDelta;\n } else if (validationCommand.stackClearing) {\n stackSize = 0;\n } else if (validationCommand.resetStack) {\n stackSize = 0;\n state.undefStack = false;\n } else if (validationCommand.undefStack) {\n stackSize = 0;\n state.undefStack = true;\n state.firstStackClearing = false;\n }\n }\n }\n state.stackSize = stackSize;\n return true;\n },\n parseCharStrings({ charStrings, localSubrIndex, globalSubrIndex, fdSelect,\n fdArray, privateDict, }) {\n var seacs = [];\n var widths = [];\n var count = charStrings.count;\n for (var i = 0; i < count; i++) {\n var charstring = charStrings.get(i);\n var state = {\n callDepth: 0,\n stackSize: 0,\n stack: [],\n undefStack: true,\n hints: 0,\n firstStackClearing: true,\n seac: null,\n width: null,\n };\n var valid = true;\n var localSubrToUse = null;\n var privateDictToUse = privateDict;\n if (fdSelect && fdArray.length) {\n var fdIndex = fdSelect.getFDIndex(i);\n if (fdIndex === -1) {\n warn('Glyph index is not in fd select.');\n valid = false;\n }\n if (fdIndex >= fdArray.length) {\n warn('Invalid fd index for glyph index.');\n valid = false;\n }\n if (valid) {\n privateDictToUse = fdArray[fdIndex].privateDict;\n localSubrToUse = privateDictToUse.subrsIndex;\n }\n } else if (localSubrIndex) {\n localSubrToUse = localSubrIndex;\n }\n if (valid) {\n valid = this.parseCharString(state, charstring, localSubrToUse,\n globalSubrIndex);\n }\n if (state.width !== null) {\n const nominalWidth = privateDictToUse.getByName('nominalWidthX');\n widths[i] = nominalWidth + state.width;\n } else {\n const defaultWidth = privateDictToUse.getByName('defaultWidthX');\n widths[i] = defaultWidth;\n }\n if (state.seac !== null) {\n seacs[i] = state.seac;\n }\n if (!valid) {\n // resetting invalid charstring to single 'endchar'\n charStrings.set(i, new Uint8Array([14]));\n }\n }\n return { charStrings, seacs, widths, };\n },\n emptyPrivateDictionary:\n function CFFParser_emptyPrivateDictionary(parentDict) {\n var privateDict = this.createDict(CFFPrivateDict, [],\n parentDict.strings);\n parentDict.setByKey(18, [0, 0]);\n parentDict.privateDict = privateDict;\n },\n parsePrivateDict: function CFFParser_parsePrivateDict(parentDict) {\n // no private dict, do nothing\n if (!parentDict.hasName('Private')) {\n this.emptyPrivateDictionary(parentDict);\n return;\n }\n var privateOffset = parentDict.getByName('Private');\n // make sure the params are formatted correctly\n if (!isArray(privateOffset) || privateOffset.length !== 2) {\n parentDict.removeByName('Private');\n return;\n }\n var size = privateOffset[0];\n var offset = privateOffset[1];\n // remove empty dicts or ones that refer to invalid location\n if (size === 0 || offset >= this.bytes.length) {\n this.emptyPrivateDictionary(parentDict);\n return;\n }\n\n var privateDictEnd = offset + size;\n var dictData = this.bytes.subarray(offset, privateDictEnd);\n var dict = this.parseDict(dictData);\n var privateDict = this.createDict(CFFPrivateDict, dict,\n parentDict.strings);\n parentDict.privateDict = privateDict;\n\n // Parse the Subrs index also since it's relative to the private dict.\n if (!privateDict.getByName('Subrs')) {\n return;\n }\n var subrsOffset = privateDict.getByName('Subrs');\n var relativeOffset = offset + subrsOffset;\n // Validate the offset.\n if (subrsOffset === 0 || relativeOffset >= this.bytes.length) {\n this.emptyPrivateDictionary(parentDict);\n return;\n }\n var subrsIndex = this.parseIndex(relativeOffset);\n privateDict.subrsIndex = subrsIndex.obj;\n },\n parseCharsets: function CFFParser_parseCharsets(pos, length, strings, cid) {\n if (pos === 0) {\n return new CFFCharset(true, CFFCharsetPredefinedTypes.ISO_ADOBE,\n ISOAdobeCharset);\n } else if (pos === 1) {\n return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT,\n ExpertCharset);\n } else if (pos === 2) {\n return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT_SUBSET,\n ExpertSubsetCharset);\n }\n\n var bytes = this.bytes;\n var start = pos;\n var format = bytes[pos++];\n var charset = ['.notdef'];\n var id, count, i;\n\n // subtract 1 for the .notdef glyph\n length -= 1;\n\n switch (format) {\n case 0:\n for (i = 0; i < length; i++) {\n id = (bytes[pos++] << 8) | bytes[pos++];\n charset.push(cid ? id : strings.get(id));\n }\n break;\n case 1:\n while (charset.length <= length) {\n id = (bytes[pos++] << 8) | bytes[pos++];\n count = bytes[pos++];\n for (i = 0; i <= count; i++) {\n charset.push(cid ? id++ : strings.get(id++));\n }\n }\n break;\n case 2:\n while (charset.length <= length) {\n id = (bytes[pos++] << 8) | bytes[pos++];\n count = (bytes[pos++] << 8) | bytes[pos++];\n for (i = 0; i <= count; i++) {\n charset.push(cid ? id++ : strings.get(id++));\n }\n }\n break;\n default:\n throw new FormatError('Unknown charset format');\n }\n // Raw won't be needed if we actually compile the charset.\n var end = pos;\n var raw = bytes.subarray(start, end);\n\n return new CFFCharset(false, format, charset, raw);\n },\n parseEncoding: function CFFParser_parseEncoding(pos,\n properties,\n strings,\n charset) {\n var encoding = Object.create(null);\n var bytes = this.bytes;\n var predefined = false;\n var format, i, ii;\n var raw = null;\n\n function readSupplement() {\n var supplementsCount = bytes[pos++];\n for (i = 0; i < supplementsCount; i++) {\n var code = bytes[pos++];\n var sid = (bytes[pos++] << 8) + (bytes[pos++] & 0xff);\n encoding[code] = charset.indexOf(strings.get(sid));\n }\n }\n\n if (pos === 0 || pos === 1) {\n predefined = true;\n format = pos;\n var baseEncoding = pos ? ExpertEncoding : StandardEncoding;\n for (i = 0, ii = charset.length; i < ii; i++) {\n var index = baseEncoding.indexOf(charset[i]);\n if (index !== -1) {\n encoding[index] = i;\n }\n }\n } else {\n var dataStart = pos;\n format = bytes[pos++];\n switch (format & 0x7f) {\n case 0:\n var glyphsCount = bytes[pos++];\n for (i = 1; i <= glyphsCount; i++) {\n encoding[bytes[pos++]] = i;\n }\n break;\n\n case 1:\n var rangesCount = bytes[pos++];\n var gid = 1;\n for (i = 0; i < rangesCount; i++) {\n var start = bytes[pos++];\n var left = bytes[pos++];\n for (var j = start; j <= start + left; j++) {\n encoding[j] = gid++;\n }\n }\n break;\n\n default:\n throw new FormatError(`Unknown encoding format: ${format} in CFF`);\n }\n var dataEnd = pos;\n if (format & 0x80) { // hasSupplement\n // The font sanitizer does not support CFF encoding with a\n // supplement, since the encoding is not really used to map\n // between gid to glyph, let's overwrite what is declared in\n // the top dictionary to let the sanitizer think the font use\n // StandardEncoding, that's a lie but that's ok.\n bytes[dataStart] &= 0x7f;\n readSupplement();\n }\n raw = bytes.subarray(dataStart, dataEnd);\n }\n format = format & 0x7f;\n return new CFFEncoding(predefined, format, encoding, raw);\n },\n parseFDSelect: function CFFParser_parseFDSelect(pos, length) {\n var start = pos;\n var bytes = this.bytes;\n var format = bytes[pos++];\n var fdSelect = [], rawBytes;\n var i, invalidFirstGID = false;\n\n switch (format) {\n case 0:\n for (i = 0; i < length; ++i) {\n var id = bytes[pos++];\n fdSelect.push(id);\n }\n rawBytes = bytes.subarray(start, pos);\n break;\n case 3:\n var rangesCount = (bytes[pos++] << 8) | bytes[pos++];\n for (i = 0; i < rangesCount; ++i) {\n var first = (bytes[pos++] << 8) | bytes[pos++];\n if (i === 0 && first !== 0) {\n warn('parseFDSelect: The first range must have a first GID of 0' +\n ' -- trying to recover.');\n invalidFirstGID = true;\n first = 0;\n }\n var fdIndex = bytes[pos++];\n var next = (bytes[pos] << 8) | bytes[pos + 1];\n for (var j = first; j < next; ++j) {\n fdSelect.push(fdIndex);\n }\n }\n // Advance past the sentinel(next).\n pos += 2;\n rawBytes = bytes.subarray(start, pos);\n\n if (invalidFirstGID) {\n rawBytes[3] = rawBytes[4] = 0; // Adjust the first range, first GID.\n }\n break;\n default:\n throw new FormatError(`parseFDSelect: Unknown format \"${format}\".`);\n }\n if (fdSelect.length !== length) {\n throw new FormatError('parseFDSelect: Invalid font data.');\n }\n\n return new CFFFDSelect(fdSelect, rawBytes);\n },\n };\n return CFFParser;\n})();\n\n// Compact Font Format\nvar CFF = (function CFFClosure() {\n function CFF() {\n this.header = null;\n this.names = [];\n this.topDict = null;\n this.strings = new CFFStrings();\n this.globalSubrIndex = null;\n\n // The following could really be per font, but since we only have one font\n // store them here.\n this.encoding = null;\n this.charset = null;\n this.charStrings = null;\n this.fdArray = [];\n this.fdSelect = null;\n\n this.isCIDFont = false;\n }\n return CFF;\n})();\n\nvar CFFHeader = (function CFFHeaderClosure() {\n function CFFHeader(major, minor, hdrSize, offSize) {\n this.major = major;\n this.minor = minor;\n this.hdrSize = hdrSize;\n this.offSize = offSize;\n }\n return CFFHeader;\n})();\n\nvar CFFStrings = (function CFFStringsClosure() {\n function CFFStrings() {\n this.strings = [];\n }\n CFFStrings.prototype = {\n get: function CFFStrings_get(index) {\n if (index >= 0 && index <= 390) {\n return CFFStandardStrings[index];\n }\n if (index - 391 <= this.strings.length) {\n return this.strings[index - 391];\n }\n return CFFStandardStrings[0];\n },\n add: function CFFStrings_add(value) {\n this.strings.push(value);\n },\n get count() {\n return this.strings.length;\n },\n };\n return CFFStrings;\n})();\n\nvar CFFIndex = (function CFFIndexClosure() {\n function CFFIndex() {\n this.objects = [];\n this.length = 0;\n }\n CFFIndex.prototype = {\n add: function CFFIndex_add(data) {\n this.length += data.length;\n this.objects.push(data);\n },\n set: function CFFIndex_set(index, data) {\n this.length += data.length - this.objects[index].length;\n this.objects[index] = data;\n },\n get: function CFFIndex_get(index) {\n return this.objects[index];\n },\n get count() {\n return this.objects.length;\n },\n };\n return CFFIndex;\n})();\n\nvar CFFDict = (function CFFDictClosure() {\n function CFFDict(tables, strings) {\n this.keyToNameMap = tables.keyToNameMap;\n this.nameToKeyMap = tables.nameToKeyMap;\n this.defaults = tables.defaults;\n this.types = tables.types;\n this.opcodes = tables.opcodes;\n this.order = tables.order;\n this.strings = strings;\n this.values = Object.create(null);\n }\n CFFDict.prototype = {\n // value should always be an array\n setByKey: function CFFDict_setByKey(key, value) {\n if (!(key in this.keyToNameMap)) {\n return false;\n }\n var valueLength = value.length;\n // ignore empty values\n if (valueLength === 0) {\n return true;\n }\n // Ignore invalid values (fixes bug1068432.pdf and bug1308536.pdf).\n for (var i = 0; i < valueLength; i++) {\n if (isNaN(value[i])) {\n warn('Invalid CFFDict value: \"' + value + '\" for key \"' + key + '\".');\n return true;\n }\n }\n var type = this.types[key];\n // remove the array wrapping these types of values\n if (type === 'num' || type === 'sid' || type === 'offset') {\n value = value[0];\n }\n this.values[key] = value;\n return true;\n },\n setByName: function CFFDict_setByName(name, value) {\n if (!(name in this.nameToKeyMap)) {\n throw new FormatError(`Invalid dictionary name \"${name}\"`);\n }\n this.values[this.nameToKeyMap[name]] = value;\n },\n hasName: function CFFDict_hasName(name) {\n return this.nameToKeyMap[name] in this.values;\n },\n getByName: function CFFDict_getByName(name) {\n if (!(name in this.nameToKeyMap)) {\n throw new FormatError(`Invalid dictionary name ${name}\"`);\n }\n var key = this.nameToKeyMap[name];\n if (!(key in this.values)) {\n return this.defaults[key];\n }\n return this.values[key];\n },\n removeByName: function CFFDict_removeByName(name) {\n delete this.values[this.nameToKeyMap[name]];\n },\n };\n CFFDict.createTables = function CFFDict_createTables(layout) {\n var tables = {\n keyToNameMap: {},\n nameToKeyMap: {},\n defaults: {},\n types: {},\n opcodes: {},\n order: [],\n };\n for (var i = 0, ii = layout.length; i < ii; ++i) {\n var entry = layout[i];\n var key = isArray(entry[0]) ? (entry[0][0] << 8) + entry[0][1] : entry[0];\n tables.keyToNameMap[key] = entry[1];\n tables.nameToKeyMap[entry[1]] = key;\n tables.types[key] = entry[2];\n tables.defaults[key] = entry[3];\n tables.opcodes[key] = isArray(entry[0]) ? entry[0] : [entry[0]];\n tables.order.push(key);\n }\n return tables;\n };\n return CFFDict;\n})();\n\nvar CFFTopDict = (function CFFTopDictClosure() {\n var layout = [\n [[12, 30], 'ROS', ['sid', 'sid', 'num'], null],\n [[12, 20], 'SyntheticBase', 'num', null],\n [0, 'version', 'sid', null],\n [1, 'Notice', 'sid', null],\n [[12, 0], 'Copyright', 'sid', null],\n [2, 'FullName', 'sid', null],\n [3, 'FamilyName', 'sid', null],\n [4, 'Weight', 'sid', null],\n [[12, 1], 'isFixedPitch', 'num', 0],\n [[12, 2], 'ItalicAngle', 'num', 0],\n [[12, 3], 'UnderlinePosition', 'num', -100],\n [[12, 4], 'UnderlineThickness', 'num', 50],\n [[12, 5], 'PaintType', 'num', 0],\n [[12, 6], 'CharstringType', 'num', 2],\n [[12, 7], 'FontMatrix', ['num', 'num', 'num', 'num', 'num', 'num'],\n [0.001, 0, 0, 0.001, 0, 0]],\n [13, 'UniqueID', 'num', null],\n [5, 'FontBBox', ['num', 'num', 'num', 'num'], [0, 0, 0, 0]],\n [[12, 8], 'StrokeWidth', 'num', 0],\n [14, 'XUID', 'array', null],\n [15, 'charset', 'offset', 0],\n [16, 'Encoding', 'offset', 0],\n [17, 'CharStrings', 'offset', 0],\n [18, 'Private', ['offset', 'offset'], null],\n [[12, 21], 'PostScript', 'sid', null],\n [[12, 22], 'BaseFontName', 'sid', null],\n [[12, 23], 'BaseFontBlend', 'delta', null],\n [[12, 31], 'CIDFontVersion', 'num', 0],\n [[12, 32], 'CIDFontRevision', 'num', 0],\n [[12, 33], 'CIDFontType', 'num', 0],\n [[12, 34], 'CIDCount', 'num', 8720],\n [[12, 35], 'UIDBase', 'num', null],\n // XXX: CID Fonts on DirectWrite 6.1 only seem to work if FDSelect comes\n // before FDArray.\n [[12, 37], 'FDSelect', 'offset', null],\n [[12, 36], 'FDArray', 'offset', null],\n [[12, 38], 'FontName', 'sid', null]\n ];\n var tables = null;\n function CFFTopDict(strings) {\n if (tables === null) {\n tables = CFFDict.createTables(layout);\n }\n CFFDict.call(this, tables, strings);\n this.privateDict = null;\n }\n CFFTopDict.prototype = Object.create(CFFDict.prototype);\n return CFFTopDict;\n})();\n\nvar CFFPrivateDict = (function CFFPrivateDictClosure() {\n var layout = [\n [6, 'BlueValues', 'delta', null],\n [7, 'OtherBlues', 'delta', null],\n [8, 'FamilyBlues', 'delta', null],\n [9, 'FamilyOtherBlues', 'delta', null],\n [[12, 9], 'BlueScale', 'num', 0.039625],\n [[12, 10], 'BlueShift', 'num', 7],\n [[12, 11], 'BlueFuzz', 'num', 1],\n [10, 'StdHW', 'num', null],\n [11, 'StdVW', 'num', null],\n [[12, 12], 'StemSnapH', 'delta', null],\n [[12, 13], 'StemSnapV', 'delta', null],\n [[12, 14], 'ForceBold', 'num', 0],\n [[12, 17], 'LanguageGroup', 'num', 0],\n [[12, 18], 'ExpansionFactor', 'num', 0.06],\n [[12, 19], 'initialRandomSeed', 'num', 0],\n [20, 'defaultWidthX', 'num', 0],\n [21, 'nominalWidthX', 'num', 0],\n [19, 'Subrs', 'offset', null]\n ];\n var tables = null;\n function CFFPrivateDict(strings) {\n if (tables === null) {\n tables = CFFDict.createTables(layout);\n }\n CFFDict.call(this, tables, strings);\n this.subrsIndex = null;\n }\n CFFPrivateDict.prototype = Object.create(CFFDict.prototype);\n return CFFPrivateDict;\n})();\n\nvar CFFCharsetPredefinedTypes = {\n ISO_ADOBE: 0,\n EXPERT: 1,\n EXPERT_SUBSET: 2,\n};\nvar CFFCharset = (function CFFCharsetClosure() {\n function CFFCharset(predefined, format, charset, raw) {\n this.predefined = predefined;\n this.format = format;\n this.charset = charset;\n this.raw = raw;\n }\n return CFFCharset;\n})();\n\nvar CFFEncoding = (function CFFEncodingClosure() {\n function CFFEncoding(predefined, format, encoding, raw) {\n this.predefined = predefined;\n this.format = format;\n this.encoding = encoding;\n this.raw = raw;\n }\n return CFFEncoding;\n})();\n\nvar CFFFDSelect = (function CFFFDSelectClosure() {\n function CFFFDSelect(fdSelect, raw) {\n this.fdSelect = fdSelect;\n this.raw = raw;\n }\n CFFFDSelect.prototype = {\n getFDIndex: function CFFFDSelect_get(glyphIndex) {\n if (glyphIndex < 0 || glyphIndex >= this.fdSelect.length) {\n return -1;\n }\n return this.fdSelect[glyphIndex];\n },\n };\n return CFFFDSelect;\n})();\n\n// Helper class to keep track of where an offset is within the data and helps\n// filling in that offset once it's known.\nvar CFFOffsetTracker = (function CFFOffsetTrackerClosure() {\n function CFFOffsetTracker() {\n this.offsets = Object.create(null);\n }\n CFFOffsetTracker.prototype = {\n isTracking: function CFFOffsetTracker_isTracking(key) {\n return key in this.offsets;\n },\n track: function CFFOffsetTracker_track(key, location) {\n if (key in this.offsets) {\n throw new FormatError(`Already tracking location of ${key}`);\n }\n this.offsets[key] = location;\n },\n offset: function CFFOffsetTracker_offset(value) {\n for (var key in this.offsets) {\n this.offsets[key] += value;\n }\n },\n setEntryLocation: function CFFOffsetTracker_setEntryLocation(key,\n values,\n output) {\n if (!(key in this.offsets)) {\n throw new FormatError(`Not tracking location of ${key}`);\n }\n var data = output.data;\n var dataOffset = this.offsets[key];\n var size = 5;\n for (var i = 0, ii = values.length; i < ii; ++i) {\n var offset0 = i * size + dataOffset;\n var offset1 = offset0 + 1;\n var offset2 = offset0 + 2;\n var offset3 = offset0 + 3;\n var offset4 = offset0 + 4;\n // It's easy to screw up offsets so perform this sanity check.\n if (data[offset0] !== 0x1d || data[offset1] !== 0 ||\n data[offset2] !== 0 || data[offset3] !== 0 || data[offset4] !== 0) {\n throw new FormatError('writing to an offset that is not empty');\n }\n var value = values[i];\n data[offset0] = 0x1d;\n data[offset1] = (value >> 24) & 0xFF;\n data[offset2] = (value >> 16) & 0xFF;\n data[offset3] = (value >> 8) & 0xFF;\n data[offset4] = value & 0xFF;\n }\n },\n };\n return CFFOffsetTracker;\n})();\n\n// Takes a CFF and converts it to the binary representation.\nvar CFFCompiler = (function CFFCompilerClosure() {\n function CFFCompiler(cff) {\n this.cff = cff;\n }\n CFFCompiler.prototype = {\n compile: function CFFCompiler_compile() {\n var cff = this.cff;\n var output = {\n data: [],\n length: 0,\n add: function CFFCompiler_add(data) {\n this.data = this.data.concat(data);\n this.length = this.data.length;\n },\n };\n\n // Compile the five entries that must be in order.\n var header = this.compileHeader(cff.header);\n output.add(header);\n\n var nameIndex = this.compileNameIndex(cff.names);\n output.add(nameIndex);\n\n if (cff.isCIDFont) {\n // The spec is unclear on how font matrices should relate to each other\n // when there is one in the main top dict and the sub top dicts.\n // Windows handles this differently than linux and osx so we have to\n // normalize to work on all.\n // Rules based off of some mailing list discussions:\n // - If main font has a matrix and subfont doesn't, use the main matrix.\n // - If no main font matrix and there is a subfont matrix, use the\n // subfont matrix.\n // - If both have matrices, concat together.\n // - If neither have matrices, use default.\n // To make this work on all platforms we move the top matrix into each\n // sub top dict and concat if necessary.\n if (cff.topDict.hasName('FontMatrix')) {\n var base = cff.topDict.getByName('FontMatrix');\n cff.topDict.removeByName('FontMatrix');\n for (var i = 0, ii = cff.fdArray.length; i < ii; i++) {\n var subDict = cff.fdArray[i];\n var matrix = base.slice(0);\n if (subDict.hasName('FontMatrix')) {\n matrix = Util.transform(matrix, subDict.getByName('FontMatrix'));\n }\n subDict.setByName('FontMatrix', matrix);\n }\n }\n }\n\n var compiled = this.compileTopDicts([cff.topDict],\n output.length,\n cff.isCIDFont);\n output.add(compiled.output);\n var topDictTracker = compiled.trackers[0];\n\n var stringIndex = this.compileStringIndex(cff.strings.strings);\n output.add(stringIndex);\n\n var globalSubrIndex = this.compileIndex(cff.globalSubrIndex);\n output.add(globalSubrIndex);\n\n // Now start on the other entries that have no specific order.\n if (cff.encoding && cff.topDict.hasName('Encoding')) {\n if (cff.encoding.predefined) {\n topDictTracker.setEntryLocation('Encoding', [cff.encoding.format],\n output);\n } else {\n var encoding = this.compileEncoding(cff.encoding);\n topDictTracker.setEntryLocation('Encoding', [output.length], output);\n output.add(encoding);\n }\n }\n\n if (cff.charset && cff.topDict.hasName('charset')) {\n if (cff.charset.predefined) {\n topDictTracker.setEntryLocation('charset', [cff.charset.format],\n output);\n } else {\n var charset = this.compileCharset(cff.charset);\n topDictTracker.setEntryLocation('charset', [output.length], output);\n output.add(charset);\n }\n }\n\n var charStrings = this.compileCharStrings(cff.charStrings);\n topDictTracker.setEntryLocation('CharStrings', [output.length], output);\n output.add(charStrings);\n\n if (cff.isCIDFont) {\n // For some reason FDSelect must be in front of FDArray on windows. OSX\n // and linux don't seem to care.\n topDictTracker.setEntryLocation('FDSelect', [output.length], output);\n var fdSelect = this.compileFDSelect(cff.fdSelect.raw);\n output.add(fdSelect);\n // It is unclear if the sub font dictionary can have CID related\n // dictionary keys, but the sanitizer doesn't like them so remove them.\n compiled = this.compileTopDicts(cff.fdArray, output.length, true);\n topDictTracker.setEntryLocation('FDArray', [output.length], output);\n output.add(compiled.output);\n var fontDictTrackers = compiled.trackers;\n\n this.compilePrivateDicts(cff.fdArray, fontDictTrackers, output);\n }\n\n this.compilePrivateDicts([cff.topDict], [topDictTracker], output);\n\n // If the font data ends with INDEX whose object data is zero-length,\n // the sanitizer will bail out. Add a dummy byte to avoid that.\n output.add([0]);\n\n return output.data;\n },\n encodeNumber: function CFFCompiler_encodeNumber(value) {\n if (parseFloat(value) === parseInt(value, 10) && !isNaN(value)) { // isInt\n return this.encodeInteger(value);\n }\n return this.encodeFloat(value);\n },\n encodeFloat: function CFFCompiler_encodeFloat(num) {\n var value = num.toString();\n\n // rounding inaccurate doubles\n var m = /\\.(\\d*?)(?:9{5,20}|0{5,20})\\d{0,2}(?:e(.+)|$)/.exec(value);\n if (m) {\n var epsilon = parseFloat('1e' + ((m[2] ? +m[2] : 0) + m[1].length));\n value = (Math.round(num * epsilon) / epsilon).toString();\n }\n\n var nibbles = '';\n var i, ii;\n for (i = 0, ii = value.length; i < ii; ++i) {\n var a = value[i];\n if (a === 'e') {\n nibbles += value[++i] === '-' ? 'c' : 'b';\n } else if (a === '.') {\n nibbles += 'a';\n } else if (a === '-') {\n nibbles += 'e';\n } else {\n nibbles += a;\n }\n }\n nibbles += (nibbles.length & 1) ? 'f' : 'ff';\n var out = [30];\n for (i = 0, ii = nibbles.length; i < ii; i += 2) {\n out.push(parseInt(nibbles.substr(i, 2), 16));\n }\n return out;\n },\n encodeInteger: function CFFCompiler_encodeInteger(value) {\n var code;\n if (value >= -107 && value <= 107) {\n code = [value + 139];\n } else if (value >= 108 && value <= 1131) {\n value = value - 108;\n code = [(value >> 8) + 247, value & 0xFF];\n } else if (value >= -1131 && value <= -108) {\n value = -value - 108;\n code = [(value >> 8) + 251, value & 0xFF];\n } else if (value >= -32768 && value <= 32767) {\n code = [0x1c, (value >> 8) & 0xFF, value & 0xFF];\n } else {\n code = [0x1d,\n (value >> 24) & 0xFF,\n (value >> 16) & 0xFF,\n (value >> 8) & 0xFF,\n value & 0xFF];\n }\n return code;\n },\n compileHeader: function CFFCompiler_compileHeader(header) {\n return [\n header.major,\n header.minor,\n header.hdrSize,\n header.offSize\n ];\n },\n compileNameIndex: function CFFCompiler_compileNameIndex(names) {\n var nameIndex = new CFFIndex();\n for (var i = 0, ii = names.length; i < ii; ++i) {\n nameIndex.add(stringToBytes(names[i]));\n }\n return this.compileIndex(nameIndex);\n },\n compileTopDicts: function CFFCompiler_compileTopDicts(dicts,\n length,\n removeCidKeys) {\n var fontDictTrackers = [];\n var fdArrayIndex = new CFFIndex();\n for (var i = 0, ii = dicts.length; i < ii; ++i) {\n var fontDict = dicts[i];\n if (removeCidKeys) {\n fontDict.removeByName('CIDFontVersion');\n fontDict.removeByName('CIDFontRevision');\n fontDict.removeByName('CIDFontType');\n fontDict.removeByName('CIDCount');\n fontDict.removeByName('UIDBase');\n }\n var fontDictTracker = new CFFOffsetTracker();\n var fontDictData = this.compileDict(fontDict, fontDictTracker);\n fontDictTrackers.push(fontDictTracker);\n fdArrayIndex.add(fontDictData);\n fontDictTracker.offset(length);\n }\n fdArrayIndex = this.compileIndex(fdArrayIndex, fontDictTrackers);\n return {\n trackers: fontDictTrackers,\n output: fdArrayIndex,\n };\n },\n compilePrivateDicts: function CFFCompiler_compilePrivateDicts(dicts,\n trackers,\n output) {\n for (var i = 0, ii = dicts.length; i < ii; ++i) {\n var fontDict = dicts[i];\n var privateDict = fontDict.privateDict;\n if (!privateDict || !fontDict.hasName('Private')) {\n throw new FormatError('There must be a private dictionary.');\n }\n var privateDictTracker = new CFFOffsetTracker();\n var privateDictData = this.compileDict(privateDict, privateDictTracker);\n\n var outputLength = output.length;\n privateDictTracker.offset(outputLength);\n if (!privateDictData.length) {\n // The private dictionary was empty, set the output length to zero to\n // ensure the offset length isn't out of bounds in the eyes of the\n // sanitizer.\n outputLength = 0;\n }\n\n trackers[i].setEntryLocation('Private',\n [privateDictData.length, outputLength],\n output);\n output.add(privateDictData);\n\n if (privateDict.subrsIndex && privateDict.hasName('Subrs')) {\n var subrs = this.compileIndex(privateDict.subrsIndex);\n privateDictTracker.setEntryLocation('Subrs', [privateDictData.length],\n output);\n output.add(subrs);\n }\n }\n },\n compileDict: function CFFCompiler_compileDict(dict, offsetTracker) {\n var out = [];\n // The dictionary keys must be in a certain order.\n var order = dict.order;\n for (var i = 0; i < order.length; ++i) {\n var key = order[i];\n if (!(key in dict.values)) {\n continue;\n }\n var values = dict.values[key];\n var types = dict.types[key];\n if (!isArray(types)) {\n types = [types];\n }\n if (!isArray(values)) {\n values = [values];\n }\n\n // Remove any empty dict values.\n if (values.length === 0) {\n continue;\n }\n\n for (var j = 0, jj = types.length; j < jj; ++j) {\n var type = types[j];\n var value = values[j];\n switch (type) {\n case 'num':\n case 'sid':\n out = out.concat(this.encodeNumber(value));\n break;\n case 'offset':\n // For offsets we just insert a 32bit integer so we don't have to\n // deal with figuring out the length of the offset when it gets\n // replaced later on by the compiler.\n var name = dict.keyToNameMap[key];\n // Some offsets have the offset and the length, so just record the\n // position of the first one.\n if (!offsetTracker.isTracking(name)) {\n offsetTracker.track(name, out.length);\n }\n out = out.concat([0x1d, 0, 0, 0, 0]);\n break;\n case 'array':\n case 'delta':\n out = out.concat(this.encodeNumber(value));\n for (var k = 1, kk = values.length; k < kk; ++k) {\n out = out.concat(this.encodeNumber(values[k]));\n }\n break;\n default:\n throw new FormatError(`Unknown data type of ${type}`);\n }\n }\n out = out.concat(dict.opcodes[key]);\n }\n return out;\n },\n compileStringIndex: function CFFCompiler_compileStringIndex(strings) {\n var stringIndex = new CFFIndex();\n for (var i = 0, ii = strings.length; i < ii; ++i) {\n stringIndex.add(stringToBytes(strings[i]));\n }\n return this.compileIndex(stringIndex);\n },\n compileGlobalSubrIndex: function CFFCompiler_compileGlobalSubrIndex() {\n var globalSubrIndex = this.cff.globalSubrIndex;\n this.out.writeByteArray(this.compileIndex(globalSubrIndex));\n },\n compileCharStrings: function CFFCompiler_compileCharStrings(charStrings) {\n return this.compileIndex(charStrings);\n },\n compileCharset: function CFFCompiler_compileCharset(charset) {\n return this.compileTypedArray(charset.raw);\n },\n compileEncoding: function CFFCompiler_compileEncoding(encoding) {\n return this.compileTypedArray(encoding.raw);\n },\n compileFDSelect: function CFFCompiler_compileFDSelect(fdSelect) {\n return this.compileTypedArray(fdSelect);\n },\n compileTypedArray: function CFFCompiler_compileTypedArray(data) {\n var out = [];\n for (var i = 0, ii = data.length; i < ii; ++i) {\n out[i] = data[i];\n }\n return out;\n },\n compileIndex: function CFFCompiler_compileIndex(index, trackers) {\n trackers = trackers || [];\n var objects = index.objects;\n // First 2 bytes contains the number of objects contained into this index\n var count = objects.length;\n\n // If there is no object, just create an index. This technically\n // should just be [0, 0] but OTS has an issue with that.\n if (count === 0) {\n return [0, 0, 0];\n }\n\n var data = [(count >> 8) & 0xFF, count & 0xff];\n\n var lastOffset = 1, i;\n for (i = 0; i < count; ++i) {\n lastOffset += objects[i].length;\n }\n\n var offsetSize;\n if (lastOffset < 0x100) {\n offsetSize = 1;\n } else if (lastOffset < 0x10000) {\n offsetSize = 2;\n } else if (lastOffset < 0x1000000) {\n offsetSize = 3;\n } else {\n offsetSize = 4;\n }\n\n // Next byte contains the offset size use to reference object in the file\n data.push(offsetSize);\n\n // Add another offset after this one because we need a new offset\n var relativeOffset = 1;\n for (i = 0; i < count + 1; i++) {\n if (offsetSize === 1) {\n data.push(relativeOffset & 0xFF);\n } else if (offsetSize === 2) {\n data.push((relativeOffset >> 8) & 0xFF,\n relativeOffset & 0xFF);\n } else if (offsetSize === 3) {\n data.push((relativeOffset >> 16) & 0xFF,\n (relativeOffset >> 8) & 0xFF,\n relativeOffset & 0xFF);\n } else {\n data.push((relativeOffset >>> 24) & 0xFF,\n (relativeOffset >> 16) & 0xFF,\n (relativeOffset >> 8) & 0xFF,\n relativeOffset & 0xFF);\n }\n\n if (objects[i]) {\n relativeOffset += objects[i].length;\n }\n }\n\n for (i = 0; i < count; i++) {\n // Notify the tracker where the object will be offset in the data.\n if (trackers[i]) {\n trackers[i].offset(data.length);\n }\n for (var j = 0, jj = objects[i].length; j < jj; j++) {\n data.push(objects[i][j]);\n }\n }\n return data;\n },\n };\n return CFFCompiler;\n})();\n\nexport {\n CFFStandardStrings,\n CFFParser,\n CFF,\n CFFHeader,\n CFFStrings,\n CFFIndex,\n CFFCharset,\n CFFTopDict,\n CFFPrivateDict,\n CFFCompiler,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/cff_parser.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n arrayByteLength, arraysToBytes, createPromiseCapability, isEmptyObj, isInt,\n MissingDataException\n} from '../shared/util';\n\nvar ChunkedStream = (function ChunkedStreamClosure() {\n function ChunkedStream(length, chunkSize, manager) {\n this.bytes = new Uint8Array(length);\n this.start = 0;\n this.pos = 0;\n this.end = length;\n this.chunkSize = chunkSize;\n this.loadedChunks = [];\n this.numChunksLoaded = 0;\n this.numChunks = Math.ceil(length / chunkSize);\n this.manager = manager;\n this.progressiveDataLength = 0;\n this.lastSuccessfulEnsureByteChunk = -1; // a single-entry cache\n }\n\n // required methods for a stream. if a particular stream does not\n // implement these, an error should be thrown\n ChunkedStream.prototype = {\n\n getMissingChunks: function ChunkedStream_getMissingChunks() {\n var chunks = [];\n for (var chunk = 0, n = this.numChunks; chunk < n; ++chunk) {\n if (!this.loadedChunks[chunk]) {\n chunks.push(chunk);\n }\n }\n return chunks;\n },\n\n getBaseStreams: function ChunkedStream_getBaseStreams() {\n return [this];\n },\n\n allChunksLoaded: function ChunkedStream_allChunksLoaded() {\n return this.numChunksLoaded === this.numChunks;\n },\n\n onReceiveData: function ChunkedStream_onReceiveData(begin, chunk) {\n var end = begin + chunk.byteLength;\n\n if (begin % this.chunkSize !== 0) {\n throw new Error(`Bad begin offset: ${begin}`);\n }\n // Using this.length is inaccurate here since this.start can be moved\n // See ChunkedStream.moveStart()\n var length = this.bytes.length;\n if (end % this.chunkSize !== 0 && end !== length) {\n throw new Error(`Bad end offset: ${end}`);\n }\n\n this.bytes.set(new Uint8Array(chunk), begin);\n var chunkSize = this.chunkSize;\n var beginChunk = Math.floor(begin / chunkSize);\n var endChunk = Math.floor((end - 1) / chunkSize) + 1;\n var curChunk;\n\n for (curChunk = beginChunk; curChunk < endChunk; ++curChunk) {\n if (!this.loadedChunks[curChunk]) {\n this.loadedChunks[curChunk] = true;\n ++this.numChunksLoaded;\n }\n }\n },\n\n onReceiveProgressiveData:\n function ChunkedStream_onReceiveProgressiveData(data) {\n var position = this.progressiveDataLength;\n var beginChunk = Math.floor(position / this.chunkSize);\n\n this.bytes.set(new Uint8Array(data), position);\n position += data.byteLength;\n this.progressiveDataLength = position;\n var endChunk = position >= this.end ? this.numChunks :\n Math.floor(position / this.chunkSize);\n var curChunk;\n for (curChunk = beginChunk; curChunk < endChunk; ++curChunk) {\n if (!this.loadedChunks[curChunk]) {\n this.loadedChunks[curChunk] = true;\n ++this.numChunksLoaded;\n }\n }\n },\n\n ensureByte: function ChunkedStream_ensureByte(pos) {\n var chunk = Math.floor(pos / this.chunkSize);\n if (chunk === this.lastSuccessfulEnsureByteChunk) {\n return;\n }\n\n if (!this.loadedChunks[chunk]) {\n throw new MissingDataException(pos, pos + 1);\n }\n this.lastSuccessfulEnsureByteChunk = chunk;\n },\n\n ensureRange: function ChunkedStream_ensureRange(begin, end) {\n if (begin >= end) {\n return;\n }\n\n if (end <= this.progressiveDataLength) {\n return;\n }\n\n var chunkSize = this.chunkSize;\n var beginChunk = Math.floor(begin / chunkSize);\n var endChunk = Math.floor((end - 1) / chunkSize) + 1;\n for (var chunk = beginChunk; chunk < endChunk; ++chunk) {\n if (!this.loadedChunks[chunk]) {\n throw new MissingDataException(begin, end);\n }\n }\n },\n\n nextEmptyChunk: function ChunkedStream_nextEmptyChunk(beginChunk) {\n var chunk, numChunks = this.numChunks;\n for (var i = 0; i < numChunks; ++i) {\n chunk = (beginChunk + i) % numChunks; // Wrap around to beginning\n if (!this.loadedChunks[chunk]) {\n return chunk;\n }\n }\n return null;\n },\n\n hasChunk: function ChunkedStream_hasChunk(chunk) {\n return !!this.loadedChunks[chunk];\n },\n\n get length() {\n return this.end - this.start;\n },\n\n get isEmpty() {\n return this.length === 0;\n },\n\n getByte: function ChunkedStream_getByte() {\n var pos = this.pos;\n if (pos >= this.end) {\n return -1;\n }\n this.ensureByte(pos);\n return this.bytes[this.pos++];\n },\n\n getUint16: function ChunkedStream_getUint16() {\n var b0 = this.getByte();\n var b1 = this.getByte();\n if (b0 === -1 || b1 === -1) {\n return -1;\n }\n return (b0 << 8) + b1;\n },\n\n getInt32: function ChunkedStream_getInt32() {\n var b0 = this.getByte();\n var b1 = this.getByte();\n var b2 = this.getByte();\n var b3 = this.getByte();\n return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;\n },\n\n // returns subarray of original buffer\n // should only be read\n getBytes: function ChunkedStream_getBytes(length) {\n var bytes = this.bytes;\n var pos = this.pos;\n var strEnd = this.end;\n\n if (!length) {\n this.ensureRange(pos, strEnd);\n return bytes.subarray(pos, strEnd);\n }\n\n var end = pos + length;\n if (end > strEnd) {\n end = strEnd;\n }\n this.ensureRange(pos, end);\n\n this.pos = end;\n return bytes.subarray(pos, end);\n },\n\n peekByte: function ChunkedStream_peekByte() {\n var peekedByte = this.getByte();\n this.pos--;\n return peekedByte;\n },\n\n peekBytes: function ChunkedStream_peekBytes(length) {\n var bytes = this.getBytes(length);\n this.pos -= bytes.length;\n return bytes;\n },\n\n getByteRange: function ChunkedStream_getBytes(begin, end) {\n this.ensureRange(begin, end);\n return this.bytes.subarray(begin, end);\n },\n\n skip: function ChunkedStream_skip(n) {\n if (!n) {\n n = 1;\n }\n this.pos += n;\n },\n\n reset: function ChunkedStream_reset() {\n this.pos = this.start;\n },\n\n moveStart: function ChunkedStream_moveStart() {\n this.start = this.pos;\n },\n\n makeSubStream: function ChunkedStream_makeSubStream(start, length, dict) {\n this.ensureRange(start, start + length);\n\n function ChunkedStreamSubstream() {}\n ChunkedStreamSubstream.prototype = Object.create(this);\n ChunkedStreamSubstream.prototype.getMissingChunks = function() {\n var chunkSize = this.chunkSize;\n var beginChunk = Math.floor(this.start / chunkSize);\n var endChunk = Math.floor((this.end - 1) / chunkSize) + 1;\n var missingChunks = [];\n for (var chunk = beginChunk; chunk < endChunk; ++chunk) {\n if (!this.loadedChunks[chunk]) {\n missingChunks.push(chunk);\n }\n }\n return missingChunks;\n };\n var subStream = new ChunkedStreamSubstream();\n subStream.pos = subStream.start = start;\n subStream.end = start + length || this.end;\n subStream.dict = dict;\n return subStream;\n },\n };\n\n return ChunkedStream;\n})();\n\nvar ChunkedStreamManager = (function ChunkedStreamManagerClosure() {\n\n function ChunkedStreamManager(pdfNetworkStream, args) {\n var chunkSize = args.rangeChunkSize;\n var length = args.length;\n this.stream = new ChunkedStream(length, chunkSize, this);\n this.length = length;\n this.chunkSize = chunkSize;\n this.pdfNetworkStream = pdfNetworkStream;\n this.url = args.url;\n this.disableAutoFetch = args.disableAutoFetch;\n this.msgHandler = args.msgHandler;\n\n this.currRequestId = 0;\n\n this.chunksNeededByRequest = Object.create(null);\n this.requestsByChunk = Object.create(null);\n this.promisesByRequest = Object.create(null);\n this.progressiveDataLength = 0;\n this.aborted = false;\n\n this._loadedStreamCapability = createPromiseCapability();\n }\n\n ChunkedStreamManager.prototype = {\n onLoadedStream: function ChunkedStreamManager_getLoadedStream() {\n return this._loadedStreamCapability.promise;\n },\n\n sendRequest: function ChunkedStreamManager_sendRequest(begin, end) {\n var rangeReader = this.pdfNetworkStream.getRangeReader(begin, end);\n if (!rangeReader.isStreamingSupported) {\n rangeReader.onProgress = this.onProgress.bind(this);\n }\n var chunks = [], loaded = 0;\n var manager = this;\n var promise = new Promise(function (resolve, reject) {\n var readChunk = function (chunk) {\n try {\n if (!chunk.done) {\n var data = chunk.value;\n chunks.push(data);\n loaded += arrayByteLength(data);\n if (rangeReader.isStreamingSupported) {\n manager.onProgress({ loaded, });\n }\n rangeReader.read().then(readChunk, reject);\n return;\n }\n var chunkData = arraysToBytes(chunks);\n chunks = null;\n resolve(chunkData);\n } catch (e) {\n reject(e);\n }\n };\n rangeReader.read().then(readChunk, reject);\n });\n promise.then((data) => {\n if (this.aborted) {\n return; // ignoring any data after abort\n }\n this.onReceiveData({ chunk: data, begin, });\n });\n // TODO check errors\n },\n\n // Get all the chunks that are not yet loaded and groups them into\n // contiguous ranges to load in as few requests as possible\n requestAllChunks: function ChunkedStreamManager_requestAllChunks() {\n var missingChunks = this.stream.getMissingChunks();\n this._requestChunks(missingChunks);\n return this._loadedStreamCapability.promise;\n },\n\n _requestChunks: function ChunkedStreamManager_requestChunks(chunks) {\n var requestId = this.currRequestId++;\n\n var i, ii;\n var chunksNeeded = Object.create(null);\n this.chunksNeededByRequest[requestId] = chunksNeeded;\n for (i = 0, ii = chunks.length; i < ii; i++) {\n if (!this.stream.hasChunk(chunks[i])) {\n chunksNeeded[chunks[i]] = true;\n }\n }\n\n if (isEmptyObj(chunksNeeded)) {\n return Promise.resolve();\n }\n\n var capability = createPromiseCapability();\n this.promisesByRequest[requestId] = capability;\n\n var chunksToRequest = [];\n for (var chunk in chunksNeeded) {\n chunk = chunk | 0;\n if (!(chunk in this.requestsByChunk)) {\n this.requestsByChunk[chunk] = [];\n chunksToRequest.push(chunk);\n }\n this.requestsByChunk[chunk].push(requestId);\n }\n\n if (!chunksToRequest.length) {\n return capability.promise;\n }\n\n var groupedChunksToRequest = this.groupChunks(chunksToRequest);\n\n for (i = 0; i < groupedChunksToRequest.length; ++i) {\n var groupedChunk = groupedChunksToRequest[i];\n var begin = groupedChunk.beginChunk * this.chunkSize;\n var end = Math.min(groupedChunk.endChunk * this.chunkSize, this.length);\n this.sendRequest(begin, end);\n }\n\n return capability.promise;\n },\n\n getStream: function ChunkedStreamManager_getStream() {\n return this.stream;\n },\n\n // Loads any chunks in the requested range that are not yet loaded\n requestRange: function ChunkedStreamManager_requestRange(begin, end) {\n\n end = Math.min(end, this.length);\n\n var beginChunk = this.getBeginChunk(begin);\n var endChunk = this.getEndChunk(end);\n\n var chunks = [];\n for (var chunk = beginChunk; chunk < endChunk; ++chunk) {\n chunks.push(chunk);\n }\n\n return this._requestChunks(chunks);\n },\n\n requestRanges: function ChunkedStreamManager_requestRanges(ranges) {\n ranges = ranges || [];\n var chunksToRequest = [];\n\n for (var i = 0; i < ranges.length; i++) {\n var beginChunk = this.getBeginChunk(ranges[i].begin);\n var endChunk = this.getEndChunk(ranges[i].end);\n for (var chunk = beginChunk; chunk < endChunk; ++chunk) {\n if (chunksToRequest.indexOf(chunk) < 0) {\n chunksToRequest.push(chunk);\n }\n }\n }\n\n chunksToRequest.sort(function(a, b) {\n return a - b;\n });\n return this._requestChunks(chunksToRequest);\n },\n\n // Groups a sorted array of chunks into as few contiguous larger\n // chunks as possible\n groupChunks: function ChunkedStreamManager_groupChunks(chunks) {\n var groupedChunks = [];\n var beginChunk = -1;\n var prevChunk = -1;\n for (var i = 0; i < chunks.length; ++i) {\n var chunk = chunks[i];\n\n if (beginChunk < 0) {\n beginChunk = chunk;\n }\n\n if (prevChunk >= 0 && prevChunk + 1 !== chunk) {\n groupedChunks.push({ beginChunk,\n endChunk: prevChunk + 1, });\n beginChunk = chunk;\n }\n if (i + 1 === chunks.length) {\n groupedChunks.push({ beginChunk,\n endChunk: chunk + 1, });\n }\n\n prevChunk = chunk;\n }\n return groupedChunks;\n },\n\n onProgress: function ChunkedStreamManager_onProgress(args) {\n var bytesLoaded = (this.stream.numChunksLoaded * this.chunkSize +\n args.loaded);\n this.msgHandler.send('DocProgress', {\n loaded: bytesLoaded,\n total: this.length,\n });\n },\n\n onReceiveData: function ChunkedStreamManager_onReceiveData(args) {\n var chunk = args.chunk;\n var isProgressive = args.begin === undefined;\n var begin = isProgressive ? this.progressiveDataLength : args.begin;\n var end = begin + chunk.byteLength;\n\n var beginChunk = Math.floor(begin / this.chunkSize);\n var endChunk = end < this.length ? Math.floor(end / this.chunkSize) :\n Math.ceil(end / this.chunkSize);\n\n if (isProgressive) {\n this.stream.onReceiveProgressiveData(chunk);\n this.progressiveDataLength = end;\n } else {\n this.stream.onReceiveData(begin, chunk);\n }\n\n if (this.stream.allChunksLoaded()) {\n this._loadedStreamCapability.resolve(this.stream);\n }\n\n var loadedRequests = [];\n var i, requestId;\n for (chunk = beginChunk; chunk < endChunk; ++chunk) {\n // The server might return more chunks than requested\n var requestIds = this.requestsByChunk[chunk] || [];\n delete this.requestsByChunk[chunk];\n\n for (i = 0; i < requestIds.length; ++i) {\n requestId = requestIds[i];\n var chunksNeeded = this.chunksNeededByRequest[requestId];\n if (chunk in chunksNeeded) {\n delete chunksNeeded[chunk];\n }\n\n if (!isEmptyObj(chunksNeeded)) {\n continue;\n }\n\n loadedRequests.push(requestId);\n }\n }\n\n // If there are no pending requests, automatically fetch the next\n // unfetched chunk of the PDF\n if (!this.disableAutoFetch && isEmptyObj(this.requestsByChunk)) {\n var nextEmptyChunk;\n if (this.stream.numChunksLoaded === 1) {\n // This is a special optimization so that after fetching the first\n // chunk, rather than fetching the second chunk, we fetch the last\n // chunk.\n var lastChunk = this.stream.numChunks - 1;\n if (!this.stream.hasChunk(lastChunk)) {\n nextEmptyChunk = lastChunk;\n }\n } else {\n nextEmptyChunk = this.stream.nextEmptyChunk(endChunk);\n }\n if (isInt(nextEmptyChunk)) {\n this._requestChunks([nextEmptyChunk]);\n }\n }\n\n for (i = 0; i < loadedRequests.length; ++i) {\n requestId = loadedRequests[i];\n var capability = this.promisesByRequest[requestId];\n delete this.promisesByRequest[requestId];\n capability.resolve();\n }\n\n this.msgHandler.send('DocProgress', {\n loaded: this.stream.numChunksLoaded * this.chunkSize,\n total: this.length,\n });\n },\n\n onError: function ChunkedStreamManager_onError(err) {\n this._loadedStreamCapability.reject(err);\n },\n\n getBeginChunk: function ChunkedStreamManager_getBeginChunk(begin) {\n var chunk = Math.floor(begin / this.chunkSize);\n return chunk;\n },\n\n getEndChunk: function ChunkedStreamManager_getEndChunk(end) {\n var chunk = Math.floor((end - 1) / this.chunkSize) + 1;\n return chunk;\n },\n\n abort: function ChunkedStreamManager_abort() {\n this.aborted = true;\n if (this.pdfNetworkStream) {\n this.pdfNetworkStream.cancelAllRequests('abort');\n }\n for (var requestId in this.promisesByRequest) {\n var capability = this.promisesByRequest[requestId];\n capability.reject(new Error('Request was aborted'));\n }\n },\n };\n\n return ChunkedStreamManager;\n})();\n\nexport {\n ChunkedStream,\n ChunkedStreamManager,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/chunked_stream.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n bytesToString, FormatError, isInt, PasswordException, PasswordResponses,\n stringToBytes, utf8StringToString, warn\n} from '../shared/util';\nimport { isDict, isName, Name } from './primitives';\nimport { DecryptStream } from './stream';\n\nvar ARCFourCipher = (function ARCFourCipherClosure() {\n function ARCFourCipher(key) {\n this.a = 0;\n this.b = 0;\n var s = new Uint8Array(256);\n var i, j = 0, tmp, keyLength = key.length;\n for (i = 0; i < 256; ++i) {\n s[i] = i;\n }\n for (i = 0; i < 256; ++i) {\n tmp = s[i];\n j = (j + tmp + key[i % keyLength]) & 0xFF;\n s[i] = s[j];\n s[j] = tmp;\n }\n this.s = s;\n }\n\n ARCFourCipher.prototype = {\n encryptBlock: function ARCFourCipher_encryptBlock(data) {\n var i, n = data.length, tmp, tmp2;\n var a = this.a, b = this.b, s = this.s;\n var output = new Uint8Array(n);\n for (i = 0; i < n; ++i) {\n a = (a + 1) & 0xFF;\n tmp = s[a];\n b = (b + tmp) & 0xFF;\n tmp2 = s[b];\n s[a] = tmp2;\n s[b] = tmp;\n output[i] = data[i] ^ s[(tmp + tmp2) & 0xFF];\n }\n this.a = a;\n this.b = b;\n return output;\n },\n };\n ARCFourCipher.prototype.decryptBlock = ARCFourCipher.prototype.encryptBlock;\n\n return ARCFourCipher;\n})();\n\nvar calculateMD5 = (function calculateMD5Closure() {\n var r = new Uint8Array([\n 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,\n 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,\n 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,\n 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]);\n\n var k = new Int32Array([\n -680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426,\n -1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162,\n 1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632,\n 643717713, -373897302, -701558691, 38016083, -660478335, -405537848,\n 568446438, -1019803690, -187363961, 1163531501, -1444681467, -51403784,\n 1735328473, -1926607734, -378558, -2022574463, 1839030562, -35309556,\n -1530992060, 1272893353, -155497632, -1094730640, 681279174, -358537222,\n -722521979, 76029189, -640364487, -421815835, 530742520, -995338651,\n -198630844, 1126891415, -1416354905, -57434055, 1700485571, -1894986606,\n -1051523, -2054922799, 1873313359, -30611744, -1560198380, 1309151649,\n -145523070, -1120210379, 718787259, -343485551]);\n\n function hash(data, offset, length) {\n var h0 = 1732584193, h1 = -271733879, h2 = -1732584194, h3 = 271733878;\n // pre-processing\n var paddedLength = (length + 72) & ~63; // data + 9 extra bytes\n var padded = new Uint8Array(paddedLength);\n var i, j, n;\n for (i = 0; i < length; ++i) {\n padded[i] = data[offset++];\n }\n padded[i++] = 0x80;\n n = paddedLength - 8;\n while (i < n) {\n padded[i++] = 0;\n }\n padded[i++] = (length << 3) & 0xFF;\n padded[i++] = (length >> 5) & 0xFF;\n padded[i++] = (length >> 13) & 0xFF;\n padded[i++] = (length >> 21) & 0xFF;\n padded[i++] = (length >>> 29) & 0xFF;\n padded[i++] = 0;\n padded[i++] = 0;\n padded[i++] = 0;\n var w = new Int32Array(16);\n for (i = 0; i < paddedLength;) {\n for (j = 0; j < 16; ++j, i += 4) {\n w[j] = (padded[i] | (padded[i + 1] << 8) |\n (padded[i + 2] << 16) | (padded[i + 3] << 24));\n }\n var a = h0, b = h1, c = h2, d = h3, f, g;\n for (j = 0; j < 64; ++j) {\n if (j < 16) {\n f = (b & c) | ((~b) & d);\n g = j;\n } else if (j < 32) {\n f = (d & b) | ((~d) & c);\n g = (5 * j + 1) & 15;\n } else if (j < 48) {\n f = b ^ c ^ d;\n g = (3 * j + 5) & 15;\n } else {\n f = c ^ (b | (~d));\n g = (7 * j) & 15;\n }\n var tmp = d, rotateArg = (a + f + k[j] + w[g]) | 0, rotate = r[j];\n d = c;\n c = b;\n b = (b + ((rotateArg << rotate) | (rotateArg >>> (32 - rotate)))) | 0;\n a = tmp;\n }\n h0 = (h0 + a) | 0;\n h1 = (h1 + b) | 0;\n h2 = (h2 + c) | 0;\n h3 = (h3 + d) | 0;\n }\n return new Uint8Array([\n h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >>> 24) & 0xFF,\n h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >>> 24) & 0xFF,\n h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >>> 24) & 0xFF,\n h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >>> 24) & 0xFF\n ]);\n }\n\n return hash;\n})();\nvar Word64 = (function Word64Closure() {\n function Word64(highInteger, lowInteger) {\n this.high = highInteger | 0;\n this.low = lowInteger | 0;\n }\n Word64.prototype = {\n and: function Word64_and(word) {\n this.high &= word.high;\n this.low &= word.low;\n },\n xor: function Word64_xor(word) {\n this.high ^= word.high;\n this.low ^= word.low;\n },\n\n or: function Word64_or(word) {\n this.high |= word.high;\n this.low |= word.low;\n },\n\n shiftRight: function Word64_shiftRight(places) {\n if (places >= 32) {\n this.low = (this.high >>> (places - 32)) | 0;\n this.high = 0;\n } else {\n this.low = (this.low >>> places) | (this.high << (32 - places));\n this.high = (this.high >>> places) | 0;\n }\n },\n\n shiftLeft: function Word64_shiftLeft(places) {\n if (places >= 32) {\n this.high = this.low << (places - 32);\n this.low = 0;\n } else {\n this.high = (this.high << places) | (this.low >>> (32 - places));\n this.low = this.low << places;\n }\n },\n\n rotateRight: function Word64_rotateRight(places) {\n var low, high;\n if (places & 32) {\n high = this.low;\n low = this.high;\n } else {\n low = this.low;\n high = this.high;\n }\n places &= 31;\n this.low = (low >>> places) | (high << (32 - places));\n this.high = (high >>> places) | (low << (32 - places));\n },\n\n not: function Word64_not() {\n this.high = ~this.high;\n this.low = ~this.low;\n },\n\n add: function Word64_add(word) {\n var lowAdd = (this.low >>> 0) + (word.low >>> 0);\n var highAdd = (this.high >>> 0) + (word.high >>> 0);\n if (lowAdd > 0xFFFFFFFF) {\n highAdd += 1;\n }\n this.low = lowAdd | 0;\n this.high = highAdd | 0;\n },\n\n copyTo: function Word64_copyTo(bytes, offset) {\n bytes[offset] = (this.high >>> 24) & 0xFF;\n bytes[offset + 1] = (this.high >> 16) & 0xFF;\n bytes[offset + 2] = (this.high >> 8) & 0xFF;\n bytes[offset + 3] = this.high & 0xFF;\n bytes[offset + 4] = (this.low >>> 24) & 0xFF;\n bytes[offset + 5] = (this.low >> 16) & 0xFF;\n bytes[offset + 6] = (this.low >> 8) & 0xFF;\n bytes[offset + 7] = this.low & 0xFF;\n },\n\n assign: function Word64_assign(word) {\n this.high = word.high;\n this.low = word.low;\n },\n };\n return Word64;\n})();\n\nvar calculateSHA256 = (function calculateSHA256Closure() {\n function rotr(x, n) {\n return (x >>> n) | (x << 32 - n);\n }\n\n function ch(x, y, z) {\n return (x & y) ^ (~x & z);\n }\n\n function maj(x, y, z) {\n return (x & y) ^ (x & z) ^ (y & z);\n }\n\n function sigma(x) {\n return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22);\n }\n\n function sigmaPrime(x) {\n return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25);\n }\n\n function littleSigma(x) {\n return rotr(x, 7) ^ rotr(x, 18) ^ x >>> 3;\n }\n\n function littleSigmaPrime(x) {\n return rotr(x, 17) ^ rotr(x, 19) ^ x >>> 10;\n }\n\n var k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,\n 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,\n 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,\n 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,\n 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,\n 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,\n 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,\n 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,\n 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];\n\n function hash(data, offset, length) {\n // initial hash values\n var h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372,\n h3 = 0xa54ff53a, h4 = 0x510e527f, h5 = 0x9b05688c,\n h6 = 0x1f83d9ab, h7 = 0x5be0cd19;\n // pre-processing\n var paddedLength = Math.ceil((length + 9) / 64) * 64;\n var padded = new Uint8Array(paddedLength);\n var i, j, n;\n for (i = 0; i < length; ++i) {\n padded[i] = data[offset++];\n }\n padded[i++] = 0x80;\n n = paddedLength - 8;\n while (i < n) {\n padded[i++] = 0;\n }\n padded[i++] = 0;\n padded[i++] = 0;\n padded[i++] = 0;\n padded[i++] = (length >>> 29) & 0xFF;\n padded[i++] = (length >> 21) & 0xFF;\n padded[i++] = (length >> 13) & 0xFF;\n padded[i++] = (length >> 5) & 0xFF;\n padded[i++] = (length << 3) & 0xFF;\n var w = new Uint32Array(64);\n // for each 512 bit block\n for (i = 0; i < paddedLength;) {\n for (j = 0; j < 16; ++j) {\n w[j] = (padded[i] << 24 | (padded[i + 1] << 16) |\n (padded[i + 2] << 8) | (padded[i + 3]));\n i += 4;\n }\n\n for (j = 16; j < 64; ++j) {\n w[j] = littleSigmaPrime(w[j - 2]) + w[j - 7] +\n littleSigma(w[j - 15]) + w[j - 16] | 0;\n }\n var a = h0, b = h1, c = h2, d = h3, e = h4,\n f = h5, g = h6, h = h7, t1, t2;\n for (j = 0; j < 64; ++j) {\n t1 = h + sigmaPrime(e) + ch(e, f, g) + k[j] + w[j];\n t2 = sigma(a) + maj(a, b, c);\n h = g;\n g = f;\n f = e;\n e = (d + t1) | 0;\n d = c;\n c = b;\n b = a;\n a = (t1 + t2) | 0;\n }\n h0 = (h0 + a) | 0;\n h1 = (h1 + b) | 0;\n h2 = (h2 + c) | 0;\n h3 = (h3 + d) | 0;\n h4 = (h4 + e) | 0;\n h5 = (h5 + f) | 0;\n h6 = (h6 + g) | 0;\n h7 = (h7 + h) | 0;\n }\n return new Uint8Array([\n (h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, (h0) & 0xFF,\n (h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, (h1) & 0xFF,\n (h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, (h2) & 0xFF,\n (h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, (h3) & 0xFF,\n (h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, (h4) & 0xFF,\n (h5 >> 24) & 0xFF, (h5 >> 16) & 0xFF, (h5 >> 8) & 0xFF, (h5) & 0xFF,\n (h6 >> 24) & 0xFF, (h6 >> 16) & 0xFF, (h6 >> 8) & 0xFF, (h6) & 0xFF,\n (h7 >> 24) & 0xFF, (h7 >> 16) & 0xFF, (h7 >> 8) & 0xFF, (h7) & 0xFF\n ]);\n }\n\n return hash;\n})();\n\nvar calculateSHA512 = (function calculateSHA512Closure() {\n function ch(result, x, y, z, tmp) {\n result.assign(x);\n result.and(y);\n tmp.assign(x);\n tmp.not();\n tmp.and(z);\n result.xor(tmp);\n }\n\n function maj(result, x, y, z, tmp) {\n result.assign(x);\n result.and(y);\n tmp.assign(x);\n tmp.and(z);\n result.xor(tmp);\n tmp.assign(y);\n tmp.and(z);\n result.xor(tmp);\n }\n\n function sigma(result, x, tmp) {\n result.assign(x);\n result.rotateRight(28);\n tmp.assign(x);\n tmp.rotateRight(34);\n result.xor(tmp);\n tmp.assign(x);\n tmp.rotateRight(39);\n result.xor(tmp);\n }\n\n function sigmaPrime(result, x, tmp) {\n result.assign(x);\n result.rotateRight(14);\n tmp.assign(x);\n tmp.rotateRight(18);\n result.xor(tmp);\n tmp.assign(x);\n tmp.rotateRight(41);\n result.xor(tmp);\n }\n\n function littleSigma(result, x, tmp) {\n result.assign(x);\n result.rotateRight(1);\n tmp.assign(x);\n tmp.rotateRight(8);\n result.xor(tmp);\n tmp.assign(x);\n tmp.shiftRight(7);\n result.xor(tmp);\n }\n\n function littleSigmaPrime(result, x, tmp) {\n result.assign(x);\n result.rotateRight(19);\n tmp.assign(x);\n tmp.rotateRight(61);\n result.xor(tmp);\n tmp.assign(x);\n tmp.shiftRight(6);\n result.xor(tmp);\n }\n\n var k = [\n new Word64(0x428a2f98, 0xd728ae22), new Word64(0x71374491, 0x23ef65cd),\n new Word64(0xb5c0fbcf, 0xec4d3b2f), new Word64(0xe9b5dba5, 0x8189dbbc),\n new Word64(0x3956c25b, 0xf348b538), new Word64(0x59f111f1, 0xb605d019),\n new Word64(0x923f82a4, 0xaf194f9b), new Word64(0xab1c5ed5, 0xda6d8118),\n new Word64(0xd807aa98, 0xa3030242), new Word64(0x12835b01, 0x45706fbe),\n new Word64(0x243185be, 0x4ee4b28c), new Word64(0x550c7dc3, 0xd5ffb4e2),\n new Word64(0x72be5d74, 0xf27b896f), new Word64(0x80deb1fe, 0x3b1696b1),\n new Word64(0x9bdc06a7, 0x25c71235), new Word64(0xc19bf174, 0xcf692694),\n new Word64(0xe49b69c1, 0x9ef14ad2), new Word64(0xefbe4786, 0x384f25e3),\n new Word64(0x0fc19dc6, 0x8b8cd5b5), new Word64(0x240ca1cc, 0x77ac9c65),\n new Word64(0x2de92c6f, 0x592b0275), new Word64(0x4a7484aa, 0x6ea6e483),\n new Word64(0x5cb0a9dc, 0xbd41fbd4), new Word64(0x76f988da, 0x831153b5),\n new Word64(0x983e5152, 0xee66dfab), new Word64(0xa831c66d, 0x2db43210),\n new Word64(0xb00327c8, 0x98fb213f), new Word64(0xbf597fc7, 0xbeef0ee4),\n new Word64(0xc6e00bf3, 0x3da88fc2), new Word64(0xd5a79147, 0x930aa725),\n new Word64(0x06ca6351, 0xe003826f), new Word64(0x14292967, 0x0a0e6e70),\n new Word64(0x27b70a85, 0x46d22ffc), new Word64(0x2e1b2138, 0x5c26c926),\n new Word64(0x4d2c6dfc, 0x5ac42aed), new Word64(0x53380d13, 0x9d95b3df),\n new Word64(0x650a7354, 0x8baf63de), new Word64(0x766a0abb, 0x3c77b2a8),\n new Word64(0x81c2c92e, 0x47edaee6), new Word64(0x92722c85, 0x1482353b),\n new Word64(0xa2bfe8a1, 0x4cf10364), new Word64(0xa81a664b, 0xbc423001),\n new Word64(0xc24b8b70, 0xd0f89791), new Word64(0xc76c51a3, 0x0654be30),\n new Word64(0xd192e819, 0xd6ef5218), new Word64(0xd6990624, 0x5565a910),\n new Word64(0xf40e3585, 0x5771202a), new Word64(0x106aa070, 0x32bbd1b8),\n new Word64(0x19a4c116, 0xb8d2d0c8), new Word64(0x1e376c08, 0x5141ab53),\n new Word64(0x2748774c, 0xdf8eeb99), new Word64(0x34b0bcb5, 0xe19b48a8),\n new Word64(0x391c0cb3, 0xc5c95a63), new Word64(0x4ed8aa4a, 0xe3418acb),\n new Word64(0x5b9cca4f, 0x7763e373), new Word64(0x682e6ff3, 0xd6b2b8a3),\n new Word64(0x748f82ee, 0x5defb2fc), new Word64(0x78a5636f, 0x43172f60),\n new Word64(0x84c87814, 0xa1f0ab72), new Word64(0x8cc70208, 0x1a6439ec),\n new Word64(0x90befffa, 0x23631e28), new Word64(0xa4506ceb, 0xde82bde9),\n new Word64(0xbef9a3f7, 0xb2c67915), new Word64(0xc67178f2, 0xe372532b),\n new Word64(0xca273ece, 0xea26619c), new Word64(0xd186b8c7, 0x21c0c207),\n new Word64(0xeada7dd6, 0xcde0eb1e), new Word64(0xf57d4f7f, 0xee6ed178),\n new Word64(0x06f067aa, 0x72176fba), new Word64(0x0a637dc5, 0xa2c898a6),\n new Word64(0x113f9804, 0xbef90dae), new Word64(0x1b710b35, 0x131c471b),\n new Word64(0x28db77f5, 0x23047d84), new Word64(0x32caab7b, 0x40c72493),\n new Word64(0x3c9ebe0a, 0x15c9bebc), new Word64(0x431d67c4, 0x9c100d4c),\n new Word64(0x4cc5d4be, 0xcb3e42b6), new Word64(0x597f299c, 0xfc657e2a),\n new Word64(0x5fcb6fab, 0x3ad6faec), new Word64(0x6c44198c, 0x4a475817)];\n\n function hash(data, offset, length, mode384) {\n mode384 = !!mode384;\n // initial hash values\n var h0, h1, h2, h3, h4, h5, h6, h7;\n if (!mode384) {\n h0 = new Word64(0x6a09e667, 0xf3bcc908);\n h1 = new Word64(0xbb67ae85, 0x84caa73b);\n h2 = new Word64(0x3c6ef372, 0xfe94f82b);\n h3 = new Word64(0xa54ff53a, 0x5f1d36f1);\n h4 = new Word64(0x510e527f, 0xade682d1);\n h5 = new Word64(0x9b05688c, 0x2b3e6c1f);\n h6 = new Word64(0x1f83d9ab, 0xfb41bd6b);\n h7 = new Word64(0x5be0cd19, 0x137e2179);\n } else {\n // SHA384 is exactly the same\n // except with different starting values and a trimmed result\n h0 = new Word64(0xcbbb9d5d, 0xc1059ed8);\n h1 = new Word64(0x629a292a, 0x367cd507);\n h2 = new Word64(0x9159015a, 0x3070dd17);\n h3 = new Word64(0x152fecd8, 0xf70e5939);\n h4 = new Word64(0x67332667, 0xffc00b31);\n h5 = new Word64(0x8eb44a87, 0x68581511);\n h6 = new Word64(0xdb0c2e0d, 0x64f98fa7);\n h7 = new Word64(0x47b5481d, 0xbefa4fa4);\n }\n\n // pre-processing\n var paddedLength = Math.ceil((length + 17) / 128) * 128;\n var padded = new Uint8Array(paddedLength);\n var i, j, n;\n for (i = 0; i < length; ++i) {\n padded[i] = data[offset++];\n }\n padded[i++] = 0x80;\n n = paddedLength - 16;\n while (i < n) {\n padded[i++] = 0;\n }\n padded[i++] = 0;\n padded[i++] = 0;\n padded[i++] = 0;\n padded[i++] = 0;\n padded[i++] = 0;\n padded[i++] = 0;\n padded[i++] = 0;\n padded[i++] = 0;\n padded[i++] = 0;\n padded[i++] = 0;\n padded[i++] = 0;\n padded[i++] = (length >>> 29) & 0xFF;\n padded[i++] = (length >> 21) & 0xFF;\n padded[i++] = (length >> 13) & 0xFF;\n padded[i++] = (length >> 5) & 0xFF;\n padded[i++] = (length << 3) & 0xFF;\n\n var w = new Array(80);\n for (i = 0; i < 80; i++) {\n w[i] = new Word64(0, 0);\n }\n var a = new Word64(0, 0), b = new Word64(0, 0), c = new Word64(0, 0);\n var d = new Word64(0, 0), e = new Word64(0, 0), f = new Word64(0, 0);\n var g = new Word64(0, 0), h = new Word64(0, 0);\n var t1 = new Word64(0, 0), t2 = new Word64(0, 0);\n var tmp1 = new Word64(0, 0), tmp2 = new Word64(0, 0), tmp3;\n\n // for each 1024 bit block\n for (i = 0; i < paddedLength;) {\n for (j = 0; j < 16; ++j) {\n w[j].high = (padded[i] << 24) | (padded[i + 1] << 16) |\n (padded[i + 2] << 8) | (padded[i + 3]);\n w[j].low = (padded[i + 4]) << 24 | (padded[i + 5]) << 16 |\n (padded[i + 6]) << 8 | (padded[i + 7]);\n i += 8;\n }\n for (j = 16; j < 80; ++j) {\n tmp3 = w[j];\n littleSigmaPrime(tmp3, w[j - 2], tmp2);\n tmp3.add(w[j - 7]);\n littleSigma(tmp1, w[j - 15], tmp2);\n tmp3.add(tmp1);\n tmp3.add(w[j - 16]);\n }\n\n a.assign(h0); b.assign(h1); c.assign(h2); d.assign(h3);\n e.assign(h4); f.assign(h5); g.assign(h6); h.assign(h7);\n for (j = 0; j < 80; ++j) {\n t1.assign(h);\n sigmaPrime(tmp1, e, tmp2);\n t1.add(tmp1);\n ch(tmp1, e, f, g, tmp2);\n t1.add(tmp1);\n t1.add(k[j]);\n t1.add(w[j]);\n\n sigma(t2, a, tmp2);\n maj(tmp1, a, b, c, tmp2);\n t2.add(tmp1);\n\n tmp3 = h;\n h = g;\n g = f;\n f = e;\n d.add(t1);\n e = d;\n d = c;\n c = b;\n b = a;\n tmp3.assign(t1);\n tmp3.add(t2);\n a = tmp3;\n }\n h0.add(a);\n h1.add(b);\n h2.add(c);\n h3.add(d);\n h4.add(e);\n h5.add(f);\n h6.add(g);\n h7.add(h);\n }\n\n var result;\n if (!mode384) {\n result = new Uint8Array(64);\n h0.copyTo(result, 0);\n h1.copyTo(result, 8);\n h2.copyTo(result, 16);\n h3.copyTo(result, 24);\n h4.copyTo(result, 32);\n h5.copyTo(result, 40);\n h6.copyTo(result, 48);\n h7.copyTo(result, 56);\n } else {\n result = new Uint8Array(48);\n h0.copyTo(result, 0);\n h1.copyTo(result, 8);\n h2.copyTo(result, 16);\n h3.copyTo(result, 24);\n h4.copyTo(result, 32);\n h5.copyTo(result, 40);\n }\n return result;\n }\n\n return hash;\n})();\nvar calculateSHA384 = (function calculateSHA384Closure() {\n function hash(data, offset, length) {\n return calculateSHA512(data, offset, length, true);\n }\n\n return hash;\n})();\nvar NullCipher = (function NullCipherClosure() {\n function NullCipher() {\n }\n\n NullCipher.prototype = {\n decryptBlock: function NullCipher_decryptBlock(data) {\n return data;\n },\n };\n\n return NullCipher;\n})();\n\nvar AES128Cipher = (function AES128CipherClosure() {\n var rcon = new Uint8Array([\n 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,\n 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,\n 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,\n 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,\n 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,\n 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6,\n 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72,\n 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,\n 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10,\n 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e,\n 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5,\n 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,\n 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02,\n 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d,\n 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d,\n 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,\n 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb,\n 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,\n 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,\n 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,\n 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,\n 0x74, 0xe8, 0xcb, 0x8d]);\n\n var s = new Uint8Array([\n 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,\n 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,\n 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,\n 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,\n 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,\n 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,\n 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,\n 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,\n 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,\n 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,\n 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,\n 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,\n 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,\n 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,\n 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,\n 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,\n 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,\n 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,\n 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,\n 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,\n 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,\n 0xb0, 0x54, 0xbb, 0x16]);\n\n var inv_s = new Uint8Array([\n 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,\n 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,\n 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,\n 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,\n 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,\n 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,\n 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,\n 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,\n 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,\n 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,\n 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,\n 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,\n 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,\n 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,\n 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,\n 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,\n 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,\n 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,\n 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,\n 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,\n 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,\n 0x55, 0x21, 0x0c, 0x7d]);\n var mixCol = new Uint8Array(256);\n for (var i = 0; i < 256; i++) {\n if (i < 128) {\n mixCol[i] = i << 1;\n } else {\n mixCol[i] = (i << 1) ^ 0x1b;\n }\n }\n var mix = new Uint32Array([\n 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927,\n 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45,\n 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb,\n 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381,\n 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf,\n 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66,\n 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28,\n 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012,\n 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec,\n 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e,\n 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd,\n 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7,\n 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89,\n 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b,\n 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815,\n 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f,\n 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa,\n 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8,\n 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36,\n 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c,\n 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742,\n 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea,\n 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4,\n 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e,\n 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360,\n 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502,\n 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87,\n 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd,\n 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3,\n 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621,\n 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f,\n 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55,\n 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26,\n 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844,\n 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba,\n 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480,\n 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce,\n 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67,\n 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929,\n 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713,\n 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed,\n 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f,\n 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3]);\n\n function expandKey128(cipherKey) {\n var b = 176, result = new Uint8Array(b);\n result.set(cipherKey);\n for (var j = 16, i = 1; j < b; ++i) {\n // RotWord\n var t1 = result[j - 3], t2 = result[j - 2],\n t3 = result[j - 1], t4 = result[j - 4];\n // SubWord\n t1 = s[t1];\n t2 = s[t2];\n t3 = s[t3];\n t4 = s[t4];\n // Rcon\n t1 = t1 ^ rcon[i];\n for (var n = 0; n < 4; ++n) {\n result[j] = (t1 ^= result[j - 16]);\n j++;\n result[j] = (t2 ^= result[j - 16]);\n j++;\n result[j] = (t3 ^= result[j - 16]);\n j++;\n result[j] = (t4 ^= result[j - 16]);\n j++;\n }\n }\n return result;\n }\n\n function decrypt128(input, key) {\n var state = new Uint8Array(16);\n state.set(input);\n var i, j, k;\n var t, u, v;\n // AddRoundKey\n for (j = 0, k = 160; j < 16; ++j, ++k) {\n state[j] ^= key[k];\n }\n for (i = 9; i >= 1; --i) {\n // InvShiftRows\n t = state[13];\n state[13] = state[9];\n state[9] = state[5];\n state[5] = state[1];\n state[1] = t;\n t = state[14];\n u = state[10];\n state[14] = state[6];\n state[10] = state[2];\n state[6] = t;\n state[2] = u;\n t = state[15];\n u = state[11];\n v = state[7];\n state[15] = state[3];\n state[11] = t;\n state[7] = u;\n state[3] = v;\n // InvSubBytes\n for (j = 0; j < 16; ++j) {\n state[j] = inv_s[state[j]];\n }\n // AddRoundKey\n for (j = 0, k = i * 16; j < 16; ++j, ++k) {\n state[j] ^= key[k];\n }\n // InvMixColumns\n for (j = 0; j < 16; j += 4) {\n var s0 = mix[state[j]], s1 = mix[state[j + 1]],\n s2 = mix[state[j + 2]], s3 = mix[state[j + 3]];\n t = (s0 ^ (s1 >>> 8) ^ (s1 << 24) ^ (s2 >>> 16) ^ (s2 << 16) ^\n (s3 >>> 24) ^ (s3 << 8));\n state[j] = (t >>> 24) & 0xFF;\n state[j + 1] = (t >> 16) & 0xFF;\n state[j + 2] = (t >> 8) & 0xFF;\n state[j + 3] = t & 0xFF;\n }\n }\n // InvShiftRows\n t = state[13];\n state[13] = state[9];\n state[9] = state[5];\n state[5] = state[1];\n state[1] = t;\n t = state[14];\n u = state[10];\n state[14] = state[6];\n state[10] = state[2];\n state[6] = t;\n state[2] = u;\n t = state[15];\n u = state[11];\n v = state[7];\n state[15] = state[3];\n state[11] = t;\n state[7] = u;\n state[3] = v;\n for (j = 0; j < 16; ++j) {\n // InvSubBytes\n state[j] = inv_s[state[j]];\n // AddRoundKey\n state[j] ^= key[j];\n }\n return state;\n }\n\n function encrypt128(input, key) {\n var t, u, v, k;\n var state = new Uint8Array(16);\n state.set(input);\n for (j = 0; j < 16; ++j) {\n // AddRoundKey\n state[j] ^= key[j];\n }\n\n for (i = 1; i < 10; i++) {\n // SubBytes\n for (j = 0; j < 16; ++j) {\n state[j] = s[state[j]];\n }\n // ShiftRows\n v = state[1];\n state[1] = state[5];\n state[5] = state[9];\n state[9] = state[13];\n state[13] = v;\n v = state[2];\n u = state[6];\n state[2] = state[10];\n state[6] = state[14];\n state[10] = v;\n state[14] = u;\n v = state[3];\n u = state[7];\n t = state[11];\n state[3] = state[15];\n state[7] = v;\n state[11] = u;\n state[15] = t;\n // MixColumns\n for (var j = 0; j < 16; j += 4) {\n var s0 = state[j + 0], s1 = state[j + 1];\n var s2 = state[j + 2], s3 = state[j + 3];\n t = s0 ^ s1 ^ s2 ^ s3;\n state[j + 0] ^= t ^ mixCol[s0 ^ s1];\n state[j + 1] ^= t ^ mixCol[s1 ^ s2];\n state[j + 2] ^= t ^ mixCol[s2 ^ s3];\n state[j + 3] ^= t ^ mixCol[s3 ^ s0];\n }\n // AddRoundKey\n for (j = 0, k = i * 16; j < 16; ++j, ++k) {\n state[j] ^= key[k];\n }\n }\n\n // SubBytes\n for (j = 0; j < 16; ++j) {\n state[j] = s[state[j]];\n }\n // ShiftRows\n v = state[1];\n state[1] = state[5];\n state[5] = state[9];\n state[9] = state[13];\n state[13] = v;\n v = state[2];\n u = state[6];\n state[2] = state[10];\n state[6] = state[14];\n state[10] = v;\n state[14] = u;\n v = state[3];\n u = state[7];\n t = state[11];\n state[3] = state[15];\n state[7] = v;\n state[11] = u;\n state[15] = t;\n // AddRoundKey\n for (j = 0, k = 160; j < 16; ++j, ++k) {\n state[j] ^= key[k];\n }\n return state;\n }\n\n function AES128Cipher(key) {\n this.key = expandKey128(key);\n this.buffer = new Uint8Array(16);\n this.bufferPosition = 0;\n }\n\n function decryptBlock2(data, finalize) {\n var i, j, ii, sourceLength = data.length,\n buffer = this.buffer, bufferLength = this.bufferPosition,\n result = [], iv = this.iv;\n for (i = 0; i < sourceLength; ++i) {\n buffer[bufferLength] = data[i];\n ++bufferLength;\n if (bufferLength < 16) {\n continue;\n }\n // buffer is full, decrypting\n var plain = decrypt128(buffer, this.key);\n // xor-ing the IV vector to get plain text\n for (j = 0; j < 16; ++j) {\n plain[j] ^= iv[j];\n }\n iv = buffer;\n result.push(plain);\n buffer = new Uint8Array(16);\n bufferLength = 0;\n }\n // saving incomplete buffer\n this.buffer = buffer;\n this.bufferLength = bufferLength;\n this.iv = iv;\n if (result.length === 0) {\n return new Uint8Array([]);\n }\n // combining plain text blocks into one\n var outputLength = 16 * result.length;\n if (finalize) {\n // undo a padding that is described in RFC 2898\n var lastBlock = result[result.length - 1];\n var psLen = lastBlock[15];\n if (psLen <= 16) {\n for (i = 15, ii = 16 - psLen; i >= ii; --i) {\n if (lastBlock[i] !== psLen) {\n // Invalid padding, assume that the block has no padding.\n psLen = 0;\n break;\n }\n }\n outputLength -= psLen;\n result[result.length - 1] = lastBlock.subarray(0, 16 - psLen);\n }\n }\n var output = new Uint8Array(outputLength);\n for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {\n output.set(result[i], j);\n }\n return output;\n }\n\n AES128Cipher.prototype = {\n decryptBlock: function AES128Cipher_decryptBlock(data, finalize) {\n var i, sourceLength = data.length;\n var buffer = this.buffer, bufferLength = this.bufferPosition;\n // waiting for IV values -- they are at the start of the stream\n for (i = 0; bufferLength < 16 && i < sourceLength; ++i, ++bufferLength) {\n buffer[bufferLength] = data[i];\n }\n if (bufferLength < 16) {\n // need more data\n this.bufferLength = bufferLength;\n return new Uint8Array([]);\n }\n this.iv = buffer;\n this.buffer = new Uint8Array(16);\n this.bufferLength = 0;\n // starting decryption\n this.decryptBlock = decryptBlock2;\n return this.decryptBlock(data.subarray(16), finalize);\n },\n encrypt: function AES128Cipher_encrypt(data, iv) {\n var i, j, ii, sourceLength = data.length,\n buffer = this.buffer, bufferLength = this.bufferPosition,\n result = [];\n if (!iv) {\n iv = new Uint8Array(16);\n }\n for (i = 0; i < sourceLength; ++i) {\n buffer[bufferLength] = data[i];\n ++bufferLength;\n if (bufferLength < 16) {\n continue;\n }\n for (j = 0; j < 16; ++j) {\n buffer[j] ^= iv[j];\n }\n\n // buffer is full, encrypting\n var cipher = encrypt128(buffer, this.key);\n iv = cipher;\n result.push(cipher);\n buffer = new Uint8Array(16);\n bufferLength = 0;\n }\n // saving incomplete buffer\n this.buffer = buffer;\n this.bufferLength = bufferLength;\n this.iv = iv;\n if (result.length === 0) {\n return new Uint8Array([]);\n }\n // combining plain text blocks into one\n var outputLength = 16 * result.length;\n var output = new Uint8Array(outputLength);\n for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {\n output.set(result[i], j);\n }\n return output;\n },\n };\n\n return AES128Cipher;\n})();\n\nvar AES256Cipher = (function AES256CipherClosure() {\n var s = new Uint8Array([\n 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,\n 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,\n 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,\n 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,\n 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,\n 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,\n 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,\n 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,\n 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,\n 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,\n 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,\n 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,\n 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,\n 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,\n 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,\n 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,\n 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,\n 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,\n 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,\n 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,\n 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,\n 0xb0, 0x54, 0xbb, 0x16]);\n\n var inv_s = new Uint8Array([\n 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,\n 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,\n 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,\n 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,\n 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,\n 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,\n 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,\n 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,\n 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,\n 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,\n 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,\n 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,\n 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,\n 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,\n 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,\n 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,\n 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,\n 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,\n 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,\n 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,\n 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,\n 0x55, 0x21, 0x0c, 0x7d]);\n\n var mixCol = new Uint8Array(256);\n for (var i = 0; i < 256; i++) {\n if (i < 128) {\n mixCol[i] = i << 1;\n } else {\n mixCol[i] = (i << 1) ^ 0x1b;\n }\n }\n var mix = new Uint32Array([\n 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927,\n 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45,\n 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb,\n 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381,\n 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf,\n 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66,\n 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28,\n 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012,\n 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec,\n 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e,\n 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd,\n 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7,\n 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89,\n 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b,\n 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815,\n 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f,\n 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa,\n 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8,\n 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36,\n 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c,\n 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742,\n 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea,\n 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4,\n 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e,\n 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360,\n 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502,\n 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87,\n 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd,\n 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3,\n 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621,\n 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f,\n 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55,\n 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26,\n 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844,\n 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba,\n 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480,\n 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce,\n 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67,\n 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929,\n 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713,\n 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed,\n 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f,\n 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3]);\n\n function expandKey256(cipherKey) {\n var b = 240, result = new Uint8Array(b);\n var r = 1;\n\n result.set(cipherKey);\n for (var j = 32, i = 1; j < b; ++i) {\n if (j % 32 === 16) {\n t1 = s[t1];\n t2 = s[t2];\n t3 = s[t3];\n t4 = s[t4];\n } else if (j % 32 === 0) {\n // RotWord\n var t1 = result[j - 3], t2 = result[j - 2],\n t3 = result[j - 1], t4 = result[j - 4];\n // SubWord\n t1 = s[t1];\n t2 = s[t2];\n t3 = s[t3];\n t4 = s[t4];\n // Rcon\n t1 = t1 ^ r;\n if ((r <<= 1) >= 256) {\n r = (r ^ 0x1b) & 0xFF;\n }\n }\n\n for (var n = 0; n < 4; ++n) {\n result[j] = (t1 ^= result[j - 32]);\n j++;\n result[j] = (t2 ^= result[j - 32]);\n j++;\n result[j] = (t3 ^= result[j - 32]);\n j++;\n result[j] = (t4 ^= result[j - 32]);\n j++;\n }\n }\n return result;\n }\n\n function decrypt256(input, key) {\n var state = new Uint8Array(16);\n state.set(input);\n var i, j, k;\n var t, u, v;\n // AddRoundKey\n for (j = 0, k = 224; j < 16; ++j, ++k) {\n state[j] ^= key[k];\n }\n for (i = 13; i >= 1; --i) {\n // InvShiftRows\n t = state[13];\n state[13] = state[9];\n state[9] = state[5];\n state[5] = state[1];\n state[1] = t;\n t = state[14];\n u = state[10];\n state[14] = state[6];\n state[10] = state[2];\n state[6] = t;\n state[2] = u;\n t = state[15];\n u = state[11];\n v = state[7];\n state[15] = state[3];\n state[11] = t;\n state[7] = u;\n state[3] = v;\n // InvSubBytes\n for (j = 0; j < 16; ++j) {\n state[j] = inv_s[state[j]];\n }\n // AddRoundKey\n for (j = 0, k = i * 16; j < 16; ++j, ++k) {\n state[j] ^= key[k];\n }\n // InvMixColumns\n for (j = 0; j < 16; j += 4) {\n var s0 = mix[state[j]], s1 = mix[state[j + 1]],\n s2 = mix[state[j + 2]], s3 = mix[state[j + 3]];\n t = (s0 ^ (s1 >>> 8) ^ (s1 << 24) ^ (s2 >>> 16) ^ (s2 << 16) ^\n (s3 >>> 24) ^ (s3 << 8));\n state[j] = (t >>> 24) & 0xFF;\n state[j + 1] = (t >> 16) & 0xFF;\n state[j + 2] = (t >> 8) & 0xFF;\n state[j + 3] = t & 0xFF;\n }\n }\n // InvShiftRows\n t = state[13];\n state[13] = state[9];\n state[9] = state[5];\n state[5] = state[1];\n state[1] = t;\n t = state[14];\n u = state[10];\n state[14] = state[6];\n state[10] = state[2];\n state[6] = t;\n state[2] = u;\n t = state[15];\n u = state[11];\n v = state[7];\n state[15] = state[3];\n state[11] = t;\n state[7] = u;\n state[3] = v;\n for (j = 0; j < 16; ++j) {\n // InvSubBytes\n state[j] = inv_s[state[j]];\n // AddRoundKey\n state[j] ^= key[j];\n }\n return state;\n }\n\n function encrypt256(input, key) {\n var t, u, v, k;\n var state = new Uint8Array(16);\n state.set(input);\n for (j = 0; j < 16; ++j) {\n // AddRoundKey\n state[j] ^= key[j];\n }\n\n for (i = 1; i < 14; i++) {\n // SubBytes\n for (j = 0; j < 16; ++j) {\n state[j] = s[state[j]];\n }\n // ShiftRows\n v = state[1];\n state[1] = state[5];\n state[5] = state[9];\n state[9] = state[13];\n state[13] = v;\n v = state[2];\n u = state[6];\n state[2] = state[10];\n state[6] = state[14];\n state[10] = v;\n state[14] = u;\n v = state[3];\n u = state[7];\n t = state[11];\n state[3] = state[15];\n state[7] = v;\n state[11] = u;\n state[15] = t;\n // MixColumns\n for (var j = 0; j < 16; j += 4) {\n var s0 = state[j + 0], s1 = state[j + 1];\n var s2 = state[j + 2], s3 = state[j + 3];\n t = s0 ^ s1 ^ s2 ^ s3;\n state[j + 0] ^= t ^ mixCol[s0 ^ s1];\n state[j + 1] ^= t ^ mixCol[s1 ^ s2];\n state[j + 2] ^= t ^ mixCol[s2 ^ s3];\n state[j + 3] ^= t ^ mixCol[s3 ^ s0];\n }\n // AddRoundKey\n for (j = 0, k = i * 16; j < 16; ++j, ++k) {\n state[j] ^= key[k];\n }\n }\n\n // SubBytes\n for (j = 0; j < 16; ++j) {\n state[j] = s[state[j]];\n }\n // ShiftRows\n v = state[1];\n state[1] = state[5];\n state[5] = state[9];\n state[9] = state[13];\n state[13] = v;\n v = state[2];\n u = state[6];\n state[2] = state[10];\n state[6] = state[14];\n state[10] = v;\n state[14] = u;\n v = state[3];\n u = state[7];\n t = state[11];\n state[3] = state[15];\n state[7] = v;\n state[11] = u;\n state[15] = t;\n // AddRoundKey\n for (j = 0, k = 224; j < 16; ++j, ++k) {\n state[j] ^= key[k];\n }\n\n return state;\n\n }\n\n function AES256Cipher(key) {\n this.key = expandKey256(key);\n this.buffer = new Uint8Array(16);\n this.bufferPosition = 0;\n }\n\n function decryptBlock2(data, finalize) {\n var i, j, ii, sourceLength = data.length,\n buffer = this.buffer, bufferLength = this.bufferPosition,\n result = [], iv = this.iv;\n\n for (i = 0; i < sourceLength; ++i) {\n buffer[bufferLength] = data[i];\n ++bufferLength;\n if (bufferLength < 16) {\n continue;\n }\n // buffer is full, decrypting\n var plain = decrypt256(buffer, this.key);\n // xor-ing the IV vector to get plain text\n for (j = 0; j < 16; ++j) {\n plain[j] ^= iv[j];\n }\n iv = buffer;\n result.push(plain);\n buffer = new Uint8Array(16);\n bufferLength = 0;\n }\n // saving incomplete buffer\n this.buffer = buffer;\n this.bufferLength = bufferLength;\n this.iv = iv;\n if (result.length === 0) {\n return new Uint8Array([]);\n }\n // combining plain text blocks into one\n var outputLength = 16 * result.length;\n if (finalize) {\n // undo a padding that is described in RFC 2898\n var lastBlock = result[result.length - 1];\n var psLen = lastBlock[15];\n if (psLen <= 16) {\n for (i = 15, ii = 16 - psLen; i >= ii; --i) {\n if (lastBlock[i] !== psLen) {\n // Invalid padding, assume that the block has no padding.\n psLen = 0;\n break;\n }\n }\n outputLength -= psLen;\n result[result.length - 1] = lastBlock.subarray(0, 16 - psLen);\n }\n }\n var output = new Uint8Array(outputLength);\n for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {\n output.set(result[i], j);\n }\n return output;\n\n }\n\n AES256Cipher.prototype = {\n decryptBlock: function AES256Cipher_decryptBlock(data, finalize, iv) {\n var i, sourceLength = data.length;\n var buffer = this.buffer, bufferLength = this.bufferPosition;\n // if not supplied an IV wait for IV values\n // they are at the start of the stream\n if (iv) {\n this.iv = iv;\n } else {\n for (i = 0; bufferLength < 16 &&\n i < sourceLength; ++i, ++bufferLength) {\n buffer[bufferLength] = data[i];\n }\n if (bufferLength < 16) { // Need more data.\n this.bufferLength = bufferLength;\n return new Uint8Array([]);\n }\n this.iv = buffer;\n data = data.subarray(16);\n }\n this.buffer = new Uint8Array(16);\n this.bufferLength = 0;\n // starting decryption\n this.decryptBlock = decryptBlock2;\n return this.decryptBlock(data, finalize);\n },\n encrypt: function AES256Cipher_encrypt(data, iv) {\n var i, j, ii, sourceLength = data.length,\n buffer = this.buffer, bufferLength = this.bufferPosition,\n result = [];\n if (!iv) {\n iv = new Uint8Array(16);\n }\n for (i = 0; i < sourceLength; ++i) {\n buffer[bufferLength] = data[i];\n ++bufferLength;\n if (bufferLength < 16) {\n continue;\n }\n for (j = 0; j < 16; ++j) {\n buffer[j] ^= iv[j];\n }\n\n // buffer is full, encrypting\n var cipher = encrypt256(buffer, this.key);\n this.iv = cipher;\n result.push(cipher);\n buffer = new Uint8Array(16);\n bufferLength = 0;\n }\n // saving incomplete buffer\n this.buffer = buffer;\n this.bufferLength = bufferLength;\n this.iv = iv;\n if (result.length === 0) {\n return new Uint8Array([]);\n }\n // combining plain text blocks into one\n var outputLength = 16 * result.length;\n var output = new Uint8Array(outputLength);\n for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {\n output.set(result[i], j);\n }\n return output;\n },\n };\n\n return AES256Cipher;\n})();\n\nvar PDF17 = (function PDF17Closure() {\n\n function compareByteArrays(array1, array2) {\n if (array1.length !== array2.length) {\n return false;\n }\n for (var i = 0; i < array1.length; i++) {\n if (array1[i] !== array2[i]) {\n return false;\n }\n }\n return true;\n }\n\n function PDF17() {\n }\n\n PDF17.prototype = {\n checkOwnerPassword: function PDF17_checkOwnerPassword(password,\n ownerValidationSalt,\n userBytes,\n ownerPassword) {\n var hashData = new Uint8Array(password.length + 56);\n hashData.set(password, 0);\n hashData.set(ownerValidationSalt, password.length);\n hashData.set(userBytes, password.length + ownerValidationSalt.length);\n var result = calculateSHA256(hashData, 0, hashData.length);\n return compareByteArrays(result, ownerPassword);\n },\n checkUserPassword: function PDF17_checkUserPassword(password,\n userValidationSalt,\n userPassword) {\n var hashData = new Uint8Array(password.length + 8);\n hashData.set(password, 0);\n hashData.set(userValidationSalt, password.length);\n var result = calculateSHA256(hashData, 0, hashData.length);\n return compareByteArrays(result, userPassword);\n },\n getOwnerKey: function PDF17_getOwnerKey(password, ownerKeySalt, userBytes,\n ownerEncryption) {\n var hashData = new Uint8Array(password.length + 56);\n hashData.set(password, 0);\n hashData.set(ownerKeySalt, password.length);\n hashData.set(userBytes, password.length + ownerKeySalt.length);\n var key = calculateSHA256(hashData, 0, hashData.length);\n var cipher = new AES256Cipher(key);\n return cipher.decryptBlock(ownerEncryption,\n false,\n new Uint8Array(16));\n\n },\n getUserKey: function PDF17_getUserKey(password, userKeySalt,\n userEncryption) {\n var hashData = new Uint8Array(password.length + 8);\n hashData.set(password, 0);\n hashData.set(userKeySalt, password.length);\n // `key` is the decryption key for the UE string.\n var key = calculateSHA256(hashData, 0, hashData.length);\n var cipher = new AES256Cipher(key);\n return cipher.decryptBlock(userEncryption,\n false,\n new Uint8Array(16));\n },\n };\n return PDF17;\n})();\n\nvar PDF20 = (function PDF20Closure() {\n\n function concatArrays(array1, array2) {\n var t = new Uint8Array(array1.length + array2.length);\n t.set(array1, 0);\n t.set(array2, array1.length);\n return t;\n }\n\n function calculatePDF20Hash(password, input, userBytes) {\n // This refers to Algorithm 2.B as defined in ISO 32000-2.\n var k = calculateSHA256(input, 0, input.length).subarray(0, 32);\n var e = [0];\n var i = 0;\n while (i < 64 || e[e.length - 1] > i - 32) {\n var arrayLength = password.length + k.length + userBytes.length;\n\n var k1 = new Uint8Array(arrayLength * 64);\n var array = concatArrays(password, k);\n array = concatArrays(array, userBytes);\n for (var j = 0, pos = 0; j < 64; j++, pos += arrayLength) {\n k1.set(array, pos);\n }\n // AES128 CBC NO PADDING with first 16 bytes of k as the key\n // and the second 16 as the iv.\n var cipher = new AES128Cipher(k.subarray(0, 16));\n e = cipher.encrypt(k1, k.subarray(16, 32));\n // Now we have to take the first 16 bytes of an unsigned big endian\n // integer and compute the remainder modulo 3. That is a fairly large\n // number and JavaScript isn't going to handle that well, so we're using\n // a trick that allows us to perform modulo math byte by byte.\n var remainder = 0;\n for (var z = 0; z < 16; z++) {\n remainder *= (256 % 3);\n remainder %= 3;\n remainder += ((e[z] >>> 0) % 3);\n remainder %= 3;\n }\n if (remainder === 0) {\n k = calculateSHA256(e, 0, e.length);\n } else if (remainder === 1) {\n k = calculateSHA384(e, 0, e.length);\n } else if (remainder === 2) {\n k = calculateSHA512(e, 0, e.length);\n }\n i++;\n }\n return k.subarray(0, 32);\n }\n\n function PDF20() {\n }\n\n function compareByteArrays(array1, array2) {\n if (array1.length !== array2.length) {\n return false;\n }\n for (var i = 0; i < array1.length; i++) {\n if (array1[i] !== array2[i]) {\n return false;\n }\n }\n return true;\n }\n\n PDF20.prototype = {\n hash: function PDF20_hash(password, concatBytes, userBytes) {\n return calculatePDF20Hash(password, concatBytes, userBytes);\n },\n checkOwnerPassword: function PDF20_checkOwnerPassword(password,\n ownerValidationSalt,\n userBytes,\n ownerPassword) {\n var hashData = new Uint8Array(password.length + 56);\n hashData.set(password, 0);\n hashData.set(ownerValidationSalt, password.length);\n hashData.set(userBytes, password.length + ownerValidationSalt.length);\n var result = calculatePDF20Hash(password, hashData, userBytes);\n return compareByteArrays(result, ownerPassword);\n },\n checkUserPassword: function PDF20_checkUserPassword(password,\n userValidationSalt,\n userPassword) {\n var hashData = new Uint8Array(password.length + 8);\n hashData.set(password, 0);\n hashData.set(userValidationSalt, password.length);\n var result = calculatePDF20Hash(password, hashData, []);\n return compareByteArrays(result, userPassword);\n },\n getOwnerKey: function PDF20_getOwnerKey(password, ownerKeySalt, userBytes,\n ownerEncryption) {\n var hashData = new Uint8Array(password.length + 56);\n hashData.set(password, 0);\n hashData.set(ownerKeySalt, password.length);\n hashData.set(userBytes, password.length + ownerKeySalt.length);\n var key = calculatePDF20Hash(password, hashData, userBytes);\n var cipher = new AES256Cipher(key);\n return cipher.decryptBlock(ownerEncryption,\n false,\n new Uint8Array(16));\n\n },\n getUserKey: function PDF20_getUserKey(password, userKeySalt,\n userEncryption) {\n var hashData = new Uint8Array(password.length + 8);\n hashData.set(password, 0);\n hashData.set(userKeySalt, password.length);\n // `key` is the decryption key for the UE string.\n var key = calculatePDF20Hash(password, hashData, []);\n var cipher = new AES256Cipher(key);\n return cipher.decryptBlock(userEncryption,\n false,\n new Uint8Array(16));\n },\n };\n return PDF20;\n})();\n\nvar CipherTransform = (function CipherTransformClosure() {\n function CipherTransform(stringCipherConstructor, streamCipherConstructor) {\n this.StringCipherConstructor = stringCipherConstructor;\n this.StreamCipherConstructor = streamCipherConstructor;\n }\n\n CipherTransform.prototype = {\n createStream: function CipherTransform_createStream(stream, length) {\n var cipher = new this.StreamCipherConstructor();\n return new DecryptStream(stream, length,\n function cipherTransformDecryptStream(data, finalize) {\n return cipher.decryptBlock(data, finalize);\n }\n );\n },\n decryptString: function CipherTransform_decryptString(s) {\n var cipher = new this.StringCipherConstructor();\n var data = stringToBytes(s);\n data = cipher.decryptBlock(data, true);\n return bytesToString(data);\n },\n };\n return CipherTransform;\n})();\n\nvar CipherTransformFactory = (function CipherTransformFactoryClosure() {\n var defaultPasswordBytes = new Uint8Array([\n 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41,\n 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,\n 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80,\n 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]);\n\n function createEncryptionKey20(revision, password, ownerPassword,\n ownerValidationSalt, ownerKeySalt, uBytes,\n userPassword, userValidationSalt, userKeySalt,\n ownerEncryption, userEncryption, perms) {\n if (password) {\n var passwordLength = Math.min(127, password.length);\n password = password.subarray(0, passwordLength);\n } else {\n password = [];\n }\n var pdfAlgorithm;\n if (revision === 6) {\n pdfAlgorithm = new PDF20();\n } else {\n pdfAlgorithm = new PDF17();\n }\n\n if (pdfAlgorithm.checkUserPassword(password, userValidationSalt,\n userPassword)) {\n return pdfAlgorithm.getUserKey(password, userKeySalt, userEncryption);\n } else if (password.length && pdfAlgorithm.checkOwnerPassword(password,\n ownerValidationSalt,\n uBytes,\n ownerPassword)) {\n return pdfAlgorithm.getOwnerKey(password, ownerKeySalt, uBytes,\n ownerEncryption);\n }\n\n return null;\n }\n\n function prepareKeyData(fileId, password, ownerPassword, userPassword,\n flags, revision, keyLength, encryptMetadata) {\n var hashDataSize = 40 + ownerPassword.length + fileId.length;\n var hashData = new Uint8Array(hashDataSize), i = 0, j, n;\n if (password) {\n n = Math.min(32, password.length);\n for (; i < n; ++i) {\n hashData[i] = password[i];\n }\n }\n j = 0;\n while (i < 32) {\n hashData[i++] = defaultPasswordBytes[j++];\n }\n // as now the padded password in the hashData[0..i]\n for (j = 0, n = ownerPassword.length; j < n; ++j) {\n hashData[i++] = ownerPassword[j];\n }\n hashData[i++] = flags & 0xFF;\n hashData[i++] = (flags >> 8) & 0xFF;\n hashData[i++] = (flags >> 16) & 0xFF;\n hashData[i++] = (flags >>> 24) & 0xFF;\n for (j = 0, n = fileId.length; j < n; ++j) {\n hashData[i++] = fileId[j];\n }\n if (revision >= 4 && !encryptMetadata) {\n hashData[i++] = 0xFF;\n hashData[i++] = 0xFF;\n hashData[i++] = 0xFF;\n hashData[i++] = 0xFF;\n }\n var hash = calculateMD5(hashData, 0, i);\n var keyLengthInBytes = keyLength >> 3;\n if (revision >= 3) {\n for (j = 0; j < 50; ++j) {\n hash = calculateMD5(hash, 0, keyLengthInBytes);\n }\n }\n var encryptionKey = hash.subarray(0, keyLengthInBytes);\n var cipher, checkData;\n\n if (revision >= 3) {\n for (i = 0; i < 32; ++i) {\n hashData[i] = defaultPasswordBytes[i];\n }\n for (j = 0, n = fileId.length; j < n; ++j) {\n hashData[i++] = fileId[j];\n }\n cipher = new ARCFourCipher(encryptionKey);\n checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i));\n n = encryptionKey.length;\n var derivedKey = new Uint8Array(n), k;\n for (j = 1; j <= 19; ++j) {\n for (k = 0; k < n; ++k) {\n derivedKey[k] = encryptionKey[k] ^ j;\n }\n cipher = new ARCFourCipher(derivedKey);\n checkData = cipher.encryptBlock(checkData);\n }\n for (j = 0, n = checkData.length; j < n; ++j) {\n if (userPassword[j] !== checkData[j]) {\n return null;\n }\n }\n } else {\n cipher = new ARCFourCipher(encryptionKey);\n checkData = cipher.encryptBlock(defaultPasswordBytes);\n for (j = 0, n = checkData.length; j < n; ++j) {\n if (userPassword[j] !== checkData[j]) {\n return null;\n }\n }\n }\n return encryptionKey;\n }\n\n function decodeUserPassword(password, ownerPassword, revision, keyLength) {\n var hashData = new Uint8Array(32), i = 0, j, n;\n n = Math.min(32, password.length);\n for (; i < n; ++i) {\n hashData[i] = password[i];\n }\n j = 0;\n while (i < 32) {\n hashData[i++] = defaultPasswordBytes[j++];\n }\n var hash = calculateMD5(hashData, 0, i);\n var keyLengthInBytes = keyLength >> 3;\n if (revision >= 3) {\n for (j = 0; j < 50; ++j) {\n hash = calculateMD5(hash, 0, hash.length);\n }\n }\n\n var cipher, userPassword;\n if (revision >= 3) {\n userPassword = ownerPassword;\n var derivedKey = new Uint8Array(keyLengthInBytes), k;\n for (j = 19; j >= 0; j--) {\n for (k = 0; k < keyLengthInBytes; ++k) {\n derivedKey[k] = hash[k] ^ j;\n }\n cipher = new ARCFourCipher(derivedKey);\n userPassword = cipher.encryptBlock(userPassword);\n }\n } else {\n cipher = new ARCFourCipher(hash.subarray(0, keyLengthInBytes));\n userPassword = cipher.encryptBlock(ownerPassword);\n }\n return userPassword;\n }\n\n var identityName = Name.get('Identity');\n\n function CipherTransformFactory(dict, fileId, password) {\n var filter = dict.get('Filter');\n if (!isName(filter, 'Standard')) {\n throw new FormatError('unknown encryption method');\n }\n this.dict = dict;\n var algorithm = dict.get('V');\n if (!isInt(algorithm) ||\n (algorithm !== 1 && algorithm !== 2 && algorithm !== 4 &&\n algorithm !== 5)) {\n throw new FormatError('unsupported encryption algorithm');\n }\n this.algorithm = algorithm;\n var keyLength = dict.get('Length');\n if (!keyLength) {\n // Spec asks to rely on encryption dictionary's Length entry, however\n // some PDFs don't have it. Trying to recover.\n if (algorithm <= 3) {\n // For 1 and 2 it's fixed to 40-bit, for 3 40-bit is a minimal value.\n keyLength = 40;\n } else {\n // Trying to find default handler -- it usually has Length.\n var cfDict = dict.get('CF');\n var streamCryptoName = dict.get('StmF');\n if (isDict(cfDict) && isName(streamCryptoName)) {\n cfDict.suppressEncryption = true; // See comment below.\n var handlerDict = cfDict.get(streamCryptoName.name);\n keyLength = (handlerDict && handlerDict.get('Length')) || 128;\n if (keyLength < 40) {\n // Sometimes it's incorrect value of bits, generators specify bytes.\n keyLength <<= 3;\n }\n }\n }\n }\n if (!isInt(keyLength) ||\n keyLength < 40 || (keyLength % 8) !== 0) {\n throw new FormatError('invalid key length');\n }\n\n // prepare keys\n var ownerPassword = stringToBytes(dict.get('O')).subarray(0, 32);\n var userPassword = stringToBytes(dict.get('U')).subarray(0, 32);\n var flags = dict.get('P');\n var revision = dict.get('R');\n // meaningful when V is 4 or 5\n var encryptMetadata = ((algorithm === 4 || algorithm === 5) &&\n dict.get('EncryptMetadata') !== false);\n this.encryptMetadata = encryptMetadata;\n\n var fileIdBytes = stringToBytes(fileId);\n var passwordBytes;\n if (password) {\n if (revision === 6) {\n try {\n password = utf8StringToString(password);\n } catch (ex) {\n warn('CipherTransformFactory: ' +\n 'Unable to convert UTF8 encoded password.');\n }\n }\n passwordBytes = stringToBytes(password);\n }\n\n var encryptionKey;\n if (algorithm !== 5) {\n encryptionKey = prepareKeyData(fileIdBytes, passwordBytes,\n ownerPassword, userPassword, flags,\n revision, keyLength, encryptMetadata);\n } else {\n var ownerValidationSalt = stringToBytes(dict.get('O')).subarray(32, 40);\n var ownerKeySalt = stringToBytes(dict.get('O')).subarray(40, 48);\n var uBytes = stringToBytes(dict.get('U')).subarray(0, 48);\n var userValidationSalt = stringToBytes(dict.get('U')).subarray(32, 40);\n var userKeySalt = stringToBytes(dict.get('U')).subarray(40, 48);\n var ownerEncryption = stringToBytes(dict.get('OE'));\n var userEncryption = stringToBytes(dict.get('UE'));\n var perms = stringToBytes(dict.get('Perms'));\n encryptionKey =\n createEncryptionKey20(revision, passwordBytes,\n ownerPassword, ownerValidationSalt,\n ownerKeySalt, uBytes,\n userPassword, userValidationSalt,\n userKeySalt, ownerEncryption,\n userEncryption, perms);\n }\n if (!encryptionKey && !password) {\n throw new PasswordException('No password given',\n PasswordResponses.NEED_PASSWORD);\n } else if (!encryptionKey && password) {\n // Attempting use the password as an owner password\n var decodedPassword = decodeUserPassword(passwordBytes, ownerPassword,\n revision, keyLength);\n encryptionKey = prepareKeyData(fileIdBytes, decodedPassword,\n ownerPassword, userPassword, flags,\n revision, keyLength, encryptMetadata);\n }\n\n if (!encryptionKey) {\n throw new PasswordException('Incorrect Password',\n PasswordResponses.INCORRECT_PASSWORD);\n }\n\n this.encryptionKey = encryptionKey;\n\n if (algorithm >= 4) {\n var cf = dict.get('CF');\n if (isDict(cf)) {\n // The 'CF' dictionary itself should not be encrypted, and by setting\n // `suppressEncryption` we can prevent an infinite loop inside of\n // `XRef_fetchUncompressed` if the dictionary contains indirect objects\n // (fixes issue7665.pdf).\n cf.suppressEncryption = true;\n }\n this.cf = cf;\n this.stmf = dict.get('StmF') || identityName;\n this.strf = dict.get('StrF') || identityName;\n this.eff = dict.get('EFF') || this.stmf;\n }\n }\n\n function buildObjectKey(num, gen, encryptionKey, isAes) {\n var key = new Uint8Array(encryptionKey.length + 9), i, n;\n for (i = 0, n = encryptionKey.length; i < n; ++i) {\n key[i] = encryptionKey[i];\n }\n key[i++] = num & 0xFF;\n key[i++] = (num >> 8) & 0xFF;\n key[i++] = (num >> 16) & 0xFF;\n key[i++] = gen & 0xFF;\n key[i++] = (gen >> 8) & 0xFF;\n if (isAes) {\n key[i++] = 0x73;\n key[i++] = 0x41;\n key[i++] = 0x6C;\n key[i++] = 0x54;\n }\n var hash = calculateMD5(key, 0, i);\n return hash.subarray(0, Math.min(encryptionKey.length + 5, 16));\n }\n\n function buildCipherConstructor(cf, name, num, gen, key) {\n if (!isName(name)) {\n throw new FormatError('Invalid crypt filter name.');\n }\n var cryptFilter = cf.get(name.name);\n var cfm;\n if (cryptFilter !== null && cryptFilter !== undefined) {\n cfm = cryptFilter.get('CFM');\n }\n if (!cfm || cfm.name === 'None') {\n return function cipherTransformFactoryBuildCipherConstructorNone() {\n return new NullCipher();\n };\n }\n if (cfm.name === 'V2') {\n return function cipherTransformFactoryBuildCipherConstructorV2() {\n return new ARCFourCipher(buildObjectKey(num, gen, key, false));\n };\n }\n if (cfm.name === 'AESV2') {\n return function cipherTransformFactoryBuildCipherConstructorAESV2() {\n return new AES128Cipher(buildObjectKey(num, gen, key, true));\n };\n }\n if (cfm.name === 'AESV3') {\n return function cipherTransformFactoryBuildCipherConstructorAESV3() {\n return new AES256Cipher(key);\n };\n }\n throw new FormatError('Unknown crypto method');\n }\n\n CipherTransformFactory.prototype = {\n createCipherTransform:\n function CipherTransformFactory_createCipherTransform(num, gen) {\n if (this.algorithm === 4 || this.algorithm === 5) {\n return new CipherTransform(\n buildCipherConstructor(this.cf, this.stmf,\n num, gen, this.encryptionKey),\n buildCipherConstructor(this.cf, this.strf,\n num, gen, this.encryptionKey));\n }\n // algorithms 1 and 2\n var key = buildObjectKey(num, gen, this.encryptionKey, false);\n var cipherConstructor = function buildCipherCipherConstructor() {\n return new ARCFourCipher(key);\n };\n return new CipherTransform(cipherConstructor, cipherConstructor);\n },\n };\n\n return CipherTransformFactory;\n})();\n\nexport {\n AES128Cipher,\n AES256Cipher,\n ARCFourCipher,\n CipherTransformFactory,\n PDF17,\n PDF20,\n calculateMD5,\n calculateSHA256,\n calculateSHA384,\n calculateSHA512,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/crypto.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AbortException, assert, CMapCompressionType, createPromiseCapability,\n FONT_IDENTITY_MATRIX, FormatError, getLookupTableFactory, IDENTITY_MATRIX,\n ImageKind, info, isArray, isNum, isString, NativeImageDecoding, OPS,\n TextRenderingMode, UNSUPPORTED_FEATURES, Util, warn\n} from '../shared/util';\nimport { CMapFactory, IdentityCMap } from './cmap';\nimport { DecodeStream, JpegStream, Stream } from './stream';\nimport {\n Dict, isCmd, isDict, isEOF, isName, isRef, isStream, Name\n} from './primitives';\nimport {\n ErrorFont, Font, FontFlags, getFontType, IdentityToUnicodeMap, ToUnicodeMap\n} from './fonts';\nimport {\n getEncoding, MacRomanEncoding, StandardEncoding, SymbolSetEncoding,\n WinAnsiEncoding, ZapfDingbatsEncoding\n} from './encodings';\nimport {\n getNormalizedUnicodes, getUnicodeForGlyph, reverseIfRtl\n} from './unicode';\nimport {\n getSerifFonts, getStdFontMap, getSymbolsFonts\n} from './standard_fonts';\nimport { getTilingPatternIR, Pattern } from './pattern';\nimport { isPDFFunction, PDFFunction } from './function';\nimport { Lexer, Parser } from './parser';\nimport { bidi } from './bidi';\nimport { ColorSpace } from './colorspace';\nimport { getGlyphsUnicode } from './glyphlist';\nimport { getMetrics } from './metrics';\nimport { MurmurHash3_64 } from './murmurhash3';\nimport { PDFImage } from './image';\n\nvar PartialEvaluator = (function PartialEvaluatorClosure() {\n const DefaultPartialEvaluatorOptions = {\n forceDataSchema: false,\n maxImageSize: -1,\n disableFontFace: false,\n nativeImageDecoderSupport: NativeImageDecoding.DECODE,\n ignoreErrors: false,\n };\n\n function NativeImageDecoder(xref, resources, handler, forceDataSchema) {\n this.xref = xref;\n this.resources = resources;\n this.handler = handler;\n this.forceDataSchema = forceDataSchema;\n }\n NativeImageDecoder.prototype = {\n canDecode(image) {\n return image instanceof JpegStream &&\n NativeImageDecoder.isDecodable(image, this.xref, this.resources);\n },\n decode(image) {\n // For natively supported JPEGs send them to the main thread for decoding.\n var dict = image.dict;\n var colorSpace = dict.get('ColorSpace', 'CS');\n colorSpace = ColorSpace.parse(colorSpace, this.xref, this.resources);\n var numComps = colorSpace.numComps;\n var decodePromise = this.handler.sendWithPromise('JpegDecode',\n [image.getIR(this.forceDataSchema), numComps]);\n return decodePromise.then(function (message) {\n var data = message.data;\n return new Stream(data, 0, data.length, image.dict);\n });\n },\n };\n /**\n * Checks if the image can be decoded and displayed by the browser without any\n * further processing such as color space conversions.\n */\n NativeImageDecoder.isSupported =\n function NativeImageDecoder_isSupported(image, xref, res) {\n var dict = image.dict;\n if (dict.has('DecodeParms') || dict.has('DP')) {\n return false;\n }\n var cs = ColorSpace.parse(dict.get('ColorSpace', 'CS'), xref, res);\n return (cs.name === 'DeviceGray' || cs.name === 'DeviceRGB') &&\n cs.isDefaultDecode(dict.getArray('Decode', 'D'));\n };\n /**\n * Checks if the image can be decoded by the browser.\n */\n NativeImageDecoder.isDecodable =\n function NativeImageDecoder_isDecodable(image, xref, res) {\n var dict = image.dict;\n if (dict.has('DecodeParms') || dict.has('DP')) {\n return false;\n }\n var cs = ColorSpace.parse(dict.get('ColorSpace', 'CS'), xref, res);\n return (cs.numComps === 1 || cs.numComps === 3) &&\n cs.isDefaultDecode(dict.getArray('Decode', 'D'));\n };\n\n function PartialEvaluator({ pdfManager, xref, handler, pageIndex, idFactory,\n fontCache, builtInCMapCache, options = null, }) {\n this.pdfManager = pdfManager;\n this.xref = xref;\n this.handler = handler;\n this.pageIndex = pageIndex;\n this.idFactory = idFactory;\n this.fontCache = fontCache;\n this.builtInCMapCache = builtInCMapCache;\n this.options = options || DefaultPartialEvaluatorOptions;\n\n this.fetchBuiltInCMap = (name) => {\n var cachedCMap = this.builtInCMapCache[name];\n if (cachedCMap) {\n return Promise.resolve(cachedCMap);\n }\n return this.handler.sendWithPromise('FetchBuiltInCMap', {\n name,\n }).then((data) => {\n if (data.compressionType !== CMapCompressionType.NONE) {\n // Given the size of uncompressed CMaps, only cache compressed ones.\n this.builtInCMapCache[name] = data;\n }\n return data;\n });\n };\n }\n\n // Trying to minimize Date.now() usage and check every 100 time\n var TIME_SLOT_DURATION_MS = 20;\n var CHECK_TIME_EVERY = 100;\n function TimeSlotManager() {\n this.reset();\n }\n TimeSlotManager.prototype = {\n check: function TimeSlotManager_check() {\n if (++this.checked < CHECK_TIME_EVERY) {\n return false;\n }\n this.checked = 0;\n return this.endTime <= Date.now();\n },\n reset: function TimeSlotManager_reset() {\n this.endTime = Date.now() + TIME_SLOT_DURATION_MS;\n this.checked = 0;\n },\n };\n\n // Convert PDF blend mode names to HTML5 blend mode names.\n function normalizeBlendMode(value) {\n if (!isName(value)) {\n return 'source-over';\n }\n switch (value.name) {\n case 'Normal':\n case 'Compatible':\n return 'source-over';\n case 'Multiply':\n return 'multiply';\n case 'Screen':\n return 'screen';\n case 'Overlay':\n return 'overlay';\n case 'Darken':\n return 'darken';\n case 'Lighten':\n return 'lighten';\n case 'ColorDodge':\n return 'color-dodge';\n case 'ColorBurn':\n return 'color-burn';\n case 'HardLight':\n return 'hard-light';\n case 'SoftLight':\n return 'soft-light';\n case 'Difference':\n return 'difference';\n case 'Exclusion':\n return 'exclusion';\n case 'Hue':\n return 'hue';\n case 'Saturation':\n return 'saturation';\n case 'Color':\n return 'color';\n case 'Luminosity':\n return 'luminosity';\n }\n warn('Unsupported blend mode: ' + value.name);\n return 'source-over';\n }\n\n var deferred = Promise.resolve();\n\n var TILING_PATTERN = 1, SHADING_PATTERN = 2;\n\n PartialEvaluator.prototype = {\n clone(newOptions = DefaultPartialEvaluatorOptions) {\n var newEvaluator = Object.create(this);\n newEvaluator.options = newOptions;\n return newEvaluator;\n },\n\n hasBlendModes: function PartialEvaluator_hasBlendModes(resources) {\n if (!isDict(resources)) {\n return false;\n }\n\n var processed = Object.create(null);\n if (resources.objId) {\n processed[resources.objId] = true;\n }\n\n var nodes = [resources], xref = this.xref;\n while (nodes.length) {\n var key, i, ii;\n var node = nodes.shift();\n // First check the current resources for blend modes.\n var graphicStates = node.get('ExtGState');\n if (isDict(graphicStates)) {\n var graphicStatesKeys = graphicStates.getKeys();\n for (i = 0, ii = graphicStatesKeys.length; i < ii; i++) {\n key = graphicStatesKeys[i];\n\n var graphicState = graphicStates.get(key);\n var bm = graphicState.get('BM');\n if (isName(bm) && bm.name !== 'Normal') {\n return true;\n }\n }\n }\n // Descend into the XObjects to look for more resources and blend modes.\n var xObjects = node.get('XObject');\n if (!isDict(xObjects)) {\n continue;\n }\n var xObjectsKeys = xObjects.getKeys();\n for (i = 0, ii = xObjectsKeys.length; i < ii; i++) {\n key = xObjectsKeys[i];\n\n var xObject = xObjects.getRaw(key);\n if (isRef(xObject)) {\n if (processed[xObject.toString()]) {\n // The XObject has already been processed, and by avoiding a\n // redundant `xref.fetch` we can *significantly* reduce the load\n // time for badly generated PDF files (fixes issue6961.pdf).\n continue;\n }\n xObject = xref.fetch(xObject);\n }\n if (!isStream(xObject)) {\n continue;\n }\n if (xObject.dict.objId) {\n if (processed[xObject.dict.objId]) {\n // stream has objId and is processed already\n continue;\n }\n processed[xObject.dict.objId] = true;\n }\n var xResources = xObject.dict.get('Resources');\n // Checking objId to detect an infinite loop.\n if (isDict(xResources) &&\n (!xResources.objId || !processed[xResources.objId])) {\n nodes.push(xResources);\n if (xResources.objId) {\n processed[xResources.objId] = true;\n }\n }\n }\n }\n return false;\n },\n\n buildFormXObject: function PartialEvaluator_buildFormXObject(resources,\n xobj, smask,\n operatorList,\n task,\n initialState) {\n var dict = xobj.dict;\n var matrix = dict.getArray('Matrix');\n var bbox = dict.getArray('BBox');\n var group = dict.get('Group');\n if (group) {\n var groupOptions = {\n matrix,\n bbox,\n smask,\n isolated: false,\n knockout: false,\n };\n\n var groupSubtype = group.get('S');\n var colorSpace;\n if (isName(groupSubtype, 'Transparency')) {\n groupOptions.isolated = (group.get('I') || false);\n groupOptions.knockout = (group.get('K') || false);\n colorSpace = (group.has('CS') ?\n ColorSpace.parse(group.get('CS'), this.xref, resources) : null);\n }\n\n if (smask && smask.backdrop) {\n colorSpace = colorSpace || ColorSpace.singletons.rgb;\n smask.backdrop = colorSpace.getRgb(smask.backdrop, 0);\n }\n\n operatorList.addOp(OPS.beginGroup, [groupOptions]);\n }\n\n operatorList.addOp(OPS.paintFormXObjectBegin, [matrix, bbox]);\n\n return this.getOperatorList({\n stream: xobj,\n task,\n resources: dict.get('Resources') || resources,\n operatorList,\n initialState,\n }).then(function () {\n operatorList.addOp(OPS.paintFormXObjectEnd, []);\n\n if (group) {\n operatorList.addOp(OPS.endGroup, [groupOptions]);\n }\n });\n },\n\n buildPaintImageXObject:\n function PartialEvaluator_buildPaintImageXObject(resources, image,\n inline, operatorList,\n cacheKey, imageCache) {\n var dict = image.dict;\n var w = dict.get('Width', 'W');\n var h = dict.get('Height', 'H');\n\n if (!(w && isNum(w)) || !(h && isNum(h))) {\n warn('Image dimensions are missing, or not numbers.');\n return;\n }\n var maxImageSize = this.options.maxImageSize;\n if (maxImageSize !== -1 && w * h > maxImageSize) {\n warn('Image exceeded maximum allowed size and was removed.');\n return;\n }\n\n var imageMask = (dict.get('ImageMask', 'IM') || false);\n var imgData, args;\n if (imageMask) {\n // This depends on a tmpCanvas being filled with the\n // current fillStyle, such that processing the pixel\n // data can't be done here. Instead of creating a\n // complete PDFImage, only read the information needed\n // for later.\n\n var width = dict.get('Width', 'W');\n var height = dict.get('Height', 'H');\n var bitStrideLength = (width + 7) >> 3;\n var imgArray = image.getBytes(bitStrideLength * height);\n var decode = dict.getArray('Decode', 'D');\n var inverseDecode = (!!decode && decode[0] > 0);\n\n imgData = PDFImage.createMask(imgArray, width, height,\n image instanceof DecodeStream,\n inverseDecode);\n imgData.cached = true;\n args = [imgData];\n operatorList.addOp(OPS.paintImageMaskXObject, args);\n if (cacheKey) {\n imageCache[cacheKey] = {\n fn: OPS.paintImageMaskXObject,\n args,\n };\n }\n return;\n }\n\n var softMask = (dict.get('SMask', 'SM') || false);\n var mask = (dict.get('Mask') || false);\n\n var SMALL_IMAGE_DIMENSIONS = 200;\n // Inlining small images into the queue as RGB data\n if (inline && !softMask && !mask && !(image instanceof JpegStream) &&\n (w + h) < SMALL_IMAGE_DIMENSIONS) {\n var imageObj = new PDFImage(this.xref, resources, image,\n inline, null, null);\n // We force the use of RGBA_32BPP images here, because we can't handle\n // any other kind.\n imgData = imageObj.createImageData(/* forceRGBA = */ true);\n operatorList.addOp(OPS.paintInlineImageXObject, [imgData]);\n return;\n }\n\n var nativeImageDecoderSupport = this.options.nativeImageDecoderSupport;\n // If there is no imageMask, create the PDFImage and a lot\n // of image processing can be done here.\n var objId = 'img_' + this.idFactory.createObjId();\n operatorList.addDependency(objId);\n args = [objId, w, h];\n\n if (nativeImageDecoderSupport !== NativeImageDecoding.NONE &&\n !softMask && !mask && image instanceof JpegStream &&\n NativeImageDecoder.isSupported(image, this.xref, resources)) {\n // These JPEGs don't need any more processing so we can just send it.\n operatorList.addOp(OPS.paintJpegXObject, args);\n this.handler.send('obj', [objId, this.pageIndex, 'JpegStream',\n image.getIR(this.options.forceDataSchema)]);\n if (cacheKey) {\n imageCache[cacheKey] = {\n fn: OPS.paintJpegXObject,\n args,\n };\n }\n return;\n }\n\n // Creates native image decoder only if a JPEG image or mask is present.\n var nativeImageDecoder = null;\n if (nativeImageDecoderSupport === NativeImageDecoding.DECODE &&\n (image instanceof JpegStream || mask instanceof JpegStream ||\n softMask instanceof JpegStream)) {\n nativeImageDecoder = new NativeImageDecoder(this.xref, resources,\n this.handler, this.options.forceDataSchema);\n }\n\n PDFImage.buildImage(this.handler, this.xref, resources, image, inline,\n nativeImageDecoder).then((imageObj) => {\n var imgData = imageObj.createImageData(/* forceRGBA = */ false);\n this.handler.send('obj', [objId, this.pageIndex, 'Image', imgData],\n [imgData.data.buffer]);\n }).catch((reason) => {\n warn('Unable to decode image: ' + reason);\n this.handler.send('obj', [objId, this.pageIndex, 'Image', null]);\n });\n\n operatorList.addOp(OPS.paintImageXObject, args);\n if (cacheKey) {\n imageCache[cacheKey] = {\n fn: OPS.paintImageXObject,\n args,\n };\n }\n },\n\n handleSMask: function PartialEvaluator_handleSmask(smask, resources,\n operatorList, task,\n stateManager) {\n var smaskContent = smask.get('G');\n var smaskOptions = {\n subtype: smask.get('S').name,\n backdrop: smask.get('BC'),\n };\n\n // The SMask might have a alpha/luminosity value transfer function --\n // we will build a map of integer values in range 0..255 to be fast.\n var transferObj = smask.get('TR');\n if (isPDFFunction(transferObj)) {\n var transferFn = PDFFunction.parse(this.xref, transferObj);\n var transferMap = new Uint8Array(256);\n var tmp = new Float32Array(1);\n for (var i = 0; i < 256; i++) {\n tmp[0] = i / 255;\n transferFn(tmp, 0, tmp, 0);\n transferMap[i] = (tmp[0] * 255) | 0;\n }\n smaskOptions.transferMap = transferMap;\n }\n\n return this.buildFormXObject(resources, smaskContent, smaskOptions,\n operatorList, task,\n stateManager.state.clone());\n },\n\n handleTilingType(fn, args, resources, pattern, patternDict, operatorList,\n task) {\n // Create an IR of the pattern code.\n let tilingOpList = new OperatorList();\n // Merge the available resources, to prevent issues when the patternDict\n // is missing some /Resources entries (fixes issue6541.pdf).\n let resourcesArray = [patternDict.get('Resources'), resources];\n let patternResources = Dict.merge(this.xref, resourcesArray);\n\n return this.getOperatorList({\n stream: pattern,\n task,\n resources: patternResources,\n operatorList: tilingOpList,\n }).then(function() {\n return getTilingPatternIR({\n fnArray: tilingOpList.fnArray,\n argsArray: tilingOpList.argsArray,\n }, patternDict, args);\n }).then(function(tilingPatternIR) {\n // Add the dependencies to the parent operator list so they are\n // resolved before the sub operator list is executed synchronously.\n operatorList.addDependencies(tilingOpList.dependencies);\n operatorList.addOp(fn, tilingPatternIR);\n }, (reason) => {\n if (this.options.ignoreErrors) {\n // Error(s) in the TilingPattern -- sending unsupported feature\n // notification and allow rendering to continue.\n this.handler.send('UnsupportedFeature',\n { featureId: UNSUPPORTED_FEATURES.unknown, });\n warn(`handleTilingType - ignoring pattern: \"${reason}\".`);\n return;\n }\n throw reason;\n });\n },\n\n handleSetFont:\n function PartialEvaluator_handleSetFont(resources, fontArgs, fontRef,\n operatorList, task, state) {\n // TODO(mack): Not needed?\n var fontName;\n if (fontArgs) {\n fontArgs = fontArgs.slice();\n fontName = fontArgs[0].name;\n }\n\n return this.loadFont(fontName, fontRef, resources).then((translated) => {\n if (!translated.font.isType3Font) {\n return translated;\n }\n return translated.loadType3Data(this, resources, operatorList, task).\n then(function () {\n return translated;\n }).catch((reason) => {\n // Error in the font data -- sending unsupported feature notification.\n this.handler.send('UnsupportedFeature',\n { featureId: UNSUPPORTED_FEATURES.font, });\n return new TranslatedFont('g_font_error',\n new ErrorFont('Type3 font load error: ' + reason), translated.font);\n });\n }).then((translated) => {\n state.font = translated.font;\n translated.send(this.handler);\n return translated.loadedName;\n });\n },\n\n handleText: function PartialEvaluator_handleText(chars, state) {\n var font = state.font;\n var glyphs = font.charsToGlyphs(chars);\n var isAddToPathSet = !!(state.textRenderingMode &\n TextRenderingMode.ADD_TO_PATH_FLAG);\n if (font.data && (isAddToPathSet || this.options.disableFontFace)) {\n var buildPath = (fontChar) => {\n if (!font.renderer.hasBuiltPath(fontChar)) {\n var path = font.renderer.getPathJs(fontChar);\n this.handler.send('commonobj', [\n font.loadedName + '_path_' + fontChar,\n 'FontPath',\n path\n ]);\n }\n };\n\n for (var i = 0, ii = glyphs.length; i < ii; i++) {\n var glyph = glyphs[i];\n buildPath(glyph.fontChar);\n\n // If the glyph has an accent we need to build a path for its\n // fontChar too, otherwise CanvasGraphics_paintChar will fail.\n var accent = glyph.accent;\n if (accent && accent.fontChar) {\n buildPath(accent.fontChar);\n }\n }\n }\n\n return glyphs;\n },\n\n setGState: function PartialEvaluator_setGState(resources, gState,\n operatorList, task,\n stateManager) {\n // This array holds the converted/processed state data.\n var gStateObj = [];\n var gStateKeys = gState.getKeys();\n var promise = Promise.resolve();\n for (var i = 0, ii = gStateKeys.length; i < ii; i++) {\n let key = gStateKeys[i];\n let value = gState.get(key);\n switch (key) {\n case 'Type':\n break;\n case 'LW':\n case 'LC':\n case 'LJ':\n case 'ML':\n case 'D':\n case 'RI':\n case 'FL':\n case 'CA':\n case 'ca':\n gStateObj.push([key, value]);\n break;\n case 'Font':\n promise = promise.then(() => {\n return this.handleSetFont(resources, null, value[0], operatorList,\n task, stateManager.state).\n then(function (loadedName) {\n operatorList.addDependency(loadedName);\n gStateObj.push([key, [loadedName, value[1]]]);\n });\n });\n break;\n case 'BM':\n gStateObj.push([key, normalizeBlendMode(value)]);\n break;\n case 'SMask':\n if (isName(value, 'None')) {\n gStateObj.push([key, false]);\n break;\n }\n if (isDict(value)) {\n promise = promise.then(() => {\n return this.handleSMask(value, resources, operatorList,\n task, stateManager);\n });\n gStateObj.push([key, true]);\n } else {\n warn('Unsupported SMask type');\n }\n\n break;\n // Only generate info log messages for the following since\n // they are unlikely to have a big impact on the rendering.\n case 'OP':\n case 'op':\n case 'OPM':\n case 'BG':\n case 'BG2':\n case 'UCR':\n case 'UCR2':\n case 'TR':\n case 'TR2':\n case 'HT':\n case 'SM':\n case 'SA':\n case 'AIS':\n case 'TK':\n // TODO implement these operators.\n info('graphic state operator ' + key);\n break;\n default:\n info('Unknown graphic state operator ' + key);\n break;\n }\n }\n return promise.then(function () {\n if (gStateObj.length > 0) {\n operatorList.addOp(OPS.setGState, [gStateObj]);\n }\n });\n },\n\n loadFont: function PartialEvaluator_loadFont(fontName, font, resources) {\n function errorFont() {\n return Promise.resolve(new TranslatedFont('g_font_error',\n new ErrorFont('Font ' + fontName + ' is not available'), font));\n }\n\n var fontRef, xref = this.xref;\n if (font) { // Loading by ref.\n if (!isRef(font)) {\n throw new Error('The \"font\" object should be a reference.');\n }\n fontRef = font;\n } else { // Loading by name.\n var fontRes = resources.get('Font');\n if (fontRes) {\n fontRef = fontRes.getRaw(fontName);\n } else {\n warn('fontRes not available');\n return errorFont();\n }\n }\n if (!fontRef) {\n warn('fontRef not available');\n return errorFont();\n }\n\n if (this.fontCache.has(fontRef)) {\n return this.fontCache.get(fontRef);\n }\n\n font = xref.fetchIfRef(fontRef);\n if (!isDict(font)) {\n return errorFont();\n }\n\n // We are holding `font.translated` references just for `fontRef`s that\n // are not actually `Ref`s, but rather `Dict`s. See explanation below.\n if (font.translated) {\n return font.translated;\n }\n\n var fontCapability = createPromiseCapability();\n\n var preEvaluatedFont = this.preEvaluateFont(font);\n var descriptor = preEvaluatedFont.descriptor;\n\n var fontRefIsRef = isRef(fontRef), fontID;\n if (fontRefIsRef) {\n fontID = fontRef.toString();\n }\n\n if (isDict(descriptor)) {\n if (!descriptor.fontAliases) {\n descriptor.fontAliases = Object.create(null);\n }\n\n var fontAliases = descriptor.fontAliases;\n var hash = preEvaluatedFont.hash;\n if (fontAliases[hash]) {\n var aliasFontRef = fontAliases[hash].aliasRef;\n if (fontRefIsRef && aliasFontRef &&\n this.fontCache.has(aliasFontRef)) {\n this.fontCache.putAlias(fontRef, aliasFontRef);\n return this.fontCache.get(fontRef);\n }\n } else {\n fontAliases[hash] = {\n fontID: Font.getFontID(),\n };\n }\n\n if (fontRefIsRef) {\n fontAliases[hash].aliasRef = fontRef;\n }\n fontID = fontAliases[hash].fontID;\n }\n\n // Workaround for bad PDF generators that reference fonts incorrectly,\n // where `fontRef` is a `Dict` rather than a `Ref` (fixes bug946506.pdf).\n // In this case we should not put the font into `this.fontCache` (which is\n // a `RefSetCache`), since it's not meaningful to use a `Dict` as a key.\n //\n // However, if we don't cache the font it's not possible to remove it\n // when `cleanup` is triggered from the API, which causes issues on\n // subsequent rendering operations (see issue7403.pdf).\n // A simple workaround would be to just not hold `font.translated`\n // references in this case, but this would force us to unnecessarily load\n // the same fonts over and over.\n //\n // Instead, we cheat a bit by attempting to use a modified `fontID` as a\n // key in `this.fontCache`, to allow the font to be cached.\n // NOTE: This works because `RefSetCache` calls `toString()` on provided\n // keys. Also, since `fontRef` is used when getting cached fonts,\n // we'll not accidentally match fonts cached with the `fontID`.\n if (fontRefIsRef) {\n this.fontCache.put(fontRef, fontCapability.promise);\n } else {\n if (!fontID) {\n fontID = this.idFactory.createObjId();\n }\n this.fontCache.put('id_' + fontID, fontCapability.promise);\n }\n assert(fontID, 'The \"fontID\" must be defined.');\n\n // Keep track of each font we translated so the caller can\n // load them asynchronously before calling display on a page.\n font.loadedName = 'g_' + this.pdfManager.docId + '_f' + fontID;\n\n font.translated = fontCapability.promise;\n\n // TODO move promises into translate font\n var translatedPromise;\n try {\n translatedPromise = this.translateFont(preEvaluatedFont);\n } catch (e) {\n translatedPromise = Promise.reject(e);\n }\n\n translatedPromise.then(function (translatedFont) {\n if (translatedFont.fontType !== undefined) {\n var xrefFontStats = xref.stats.fontTypes;\n xrefFontStats[translatedFont.fontType] = true;\n }\n\n fontCapability.resolve(new TranslatedFont(font.loadedName,\n translatedFont, font));\n }).catch((reason) => {\n // TODO fontCapability.reject?\n // Error in the font data -- sending unsupported feature notification.\n this.handler.send('UnsupportedFeature',\n { featureId: UNSUPPORTED_FEATURES.font, });\n\n try {\n // error, but it's still nice to have font type reported\n var descriptor = preEvaluatedFont.descriptor;\n var fontFile3 = descriptor && descriptor.get('FontFile3');\n var subtype = fontFile3 && fontFile3.get('Subtype');\n var fontType = getFontType(preEvaluatedFont.type,\n subtype && subtype.name);\n var xrefFontStats = xref.stats.fontTypes;\n xrefFontStats[fontType] = true;\n } catch (ex) { }\n\n fontCapability.resolve(new TranslatedFont(font.loadedName,\n new ErrorFont(reason instanceof Error ? reason.message : reason),\n font));\n });\n return fontCapability.promise;\n },\n\n buildPath: function PartialEvaluator_buildPath(operatorList, fn, args) {\n var lastIndex = operatorList.length - 1;\n if (!args) {\n args = [];\n }\n if (lastIndex < 0 ||\n operatorList.fnArray[lastIndex] !== OPS.constructPath) {\n operatorList.addOp(OPS.constructPath, [[fn], args]);\n } else {\n var opArgs = operatorList.argsArray[lastIndex];\n opArgs[0].push(fn);\n Array.prototype.push.apply(opArgs[1], args);\n }\n },\n\n handleColorN: function PartialEvaluator_handleColorN(operatorList, fn, args,\n cs, patterns,\n resources, task) {\n // compile tiling patterns\n var patternName = args[args.length - 1];\n // SCN/scn applies patterns along with normal colors\n var pattern;\n if (isName(patternName) &&\n (pattern = patterns.get(patternName.name))) {\n var dict = (isStream(pattern) ? pattern.dict : pattern);\n var typeNum = dict.get('PatternType');\n\n if (typeNum === TILING_PATTERN) {\n var color = cs.base ? cs.base.getRgb(args, 0) : null;\n return this.handleTilingType(fn, color, resources, pattern,\n dict, operatorList, task);\n } else if (typeNum === SHADING_PATTERN) {\n var shading = dict.get('Shading');\n var matrix = dict.getArray('Matrix');\n pattern = Pattern.parseShading(shading, matrix, this.xref, resources,\n this.handler);\n operatorList.addOp(fn, pattern.getIR());\n return Promise.resolve();\n }\n return Promise.reject(new Error('Unknown PatternType: ' + typeNum));\n }\n // TODO shall we fail here?\n operatorList.addOp(fn, args);\n return Promise.resolve();\n },\n\n getOperatorList({ stream, task, resources, operatorList,\n initialState = null, }) {\n // Ensure that `resources`/`initialState` is correctly initialized,\n // even if the provided parameter is e.g. `null`.\n resources = resources || Dict.empty;\n initialState = initialState || new EvalState();\n\n if (!operatorList) {\n throw new Error('getOperatorList: missing \"operatorList\" parameter');\n }\n\n var self = this;\n var xref = this.xref;\n var imageCache = Object.create(null);\n\n var xobjs = (resources.get('XObject') || Dict.empty);\n var patterns = (resources.get('Pattern') || Dict.empty);\n var stateManager = new StateManager(initialState);\n var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);\n var timeSlotManager = new TimeSlotManager();\n\n function closePendingRestoreOPS(argument) {\n for (var i = 0, ii = preprocessor.savedStatesDepth; i < ii; i++) {\n operatorList.addOp(OPS.restore, []);\n }\n }\n\n return new Promise(function promiseBody(resolve, reject) {\n var next = function (promise) {\n promise.then(function () {\n try {\n promiseBody(resolve, reject);\n } catch (ex) {\n reject(ex);\n }\n }, reject);\n };\n task.ensureNotTerminated();\n timeSlotManager.reset();\n var stop, operation = {}, i, ii, cs;\n while (!(stop = timeSlotManager.check())) {\n // The arguments parsed by read() are used beyond this loop, so we\n // cannot reuse the same array on each iteration. Therefore we pass\n // in |null| as the initial value (see the comment on\n // EvaluatorPreprocessor_read() for why).\n operation.args = null;\n if (!(preprocessor.read(operation))) {\n break;\n }\n var args = operation.args;\n var fn = operation.fn;\n\n switch (fn | 0) {\n case OPS.paintXObject:\n // eagerly compile XForm objects\n var name = args[0].name;\n if (!name) {\n warn('XObject must be referred to by name.');\n continue;\n }\n if (imageCache[name] !== undefined) {\n operatorList.addOp(imageCache[name].fn, imageCache[name].args);\n args = null;\n continue;\n }\n\n var xobj = xobjs.get(name);\n if (xobj) {\n if (!isStream(xobj)) {\n throw new FormatError('XObject should be a stream');\n }\n\n var type = xobj.dict.get('Subtype');\n if (!isName(type)) {\n throw new FormatError('XObject should have a Name subtype');\n }\n\n if (type.name === 'Form') {\n stateManager.save();\n next(self.buildFormXObject(resources, xobj, null,\n operatorList, task,\n stateManager.state.clone()).\n then(function () {\n stateManager.restore();\n }));\n return;\n } else if (type.name === 'Image') {\n self.buildPaintImageXObject(resources, xobj, false,\n operatorList, name, imageCache);\n args = null;\n continue;\n } else if (type.name === 'PS') {\n // PostScript XObjects are unused when viewing documents.\n // See section 4.7.1 of Adobe's PDF reference.\n info('Ignored XObject subtype PS');\n continue;\n } else {\n throw new FormatError(\n `Unhandled XObject subtype ${type.name}`);\n }\n }\n break;\n case OPS.setFont:\n var fontSize = args[1];\n // eagerly collect all fonts\n next(self.handleSetFont(resources, args, null, operatorList,\n task, stateManager.state).\n then(function (loadedName) {\n operatorList.addDependency(loadedName);\n operatorList.addOp(OPS.setFont, [loadedName, fontSize]);\n }));\n return;\n case OPS.endInlineImage:\n var cacheKey = args[0].cacheKey;\n if (cacheKey) {\n var cacheEntry = imageCache[cacheKey];\n if (cacheEntry !== undefined) {\n operatorList.addOp(cacheEntry.fn, cacheEntry.args);\n args = null;\n continue;\n }\n }\n self.buildPaintImageXObject(resources, args[0], true,\n operatorList, cacheKey, imageCache);\n args = null;\n continue;\n case OPS.showText:\n args[0] = self.handleText(args[0], stateManager.state);\n break;\n case OPS.showSpacedText:\n var arr = args[0];\n var combinedGlyphs = [];\n var arrLength = arr.length;\n var state = stateManager.state;\n for (i = 0; i < arrLength; ++i) {\n var arrItem = arr[i];\n if (isString(arrItem)) {\n Array.prototype.push.apply(combinedGlyphs,\n self.handleText(arrItem, state));\n } else if (isNum(arrItem)) {\n combinedGlyphs.push(arrItem);\n }\n }\n args[0] = combinedGlyphs;\n fn = OPS.showText;\n break;\n case OPS.nextLineShowText:\n operatorList.addOp(OPS.nextLine);\n args[0] = self.handleText(args[0], stateManager.state);\n fn = OPS.showText;\n break;\n case OPS.nextLineSetSpacingShowText:\n operatorList.addOp(OPS.nextLine);\n operatorList.addOp(OPS.setWordSpacing, [args.shift()]);\n operatorList.addOp(OPS.setCharSpacing, [args.shift()]);\n args[0] = self.handleText(args[0], stateManager.state);\n fn = OPS.showText;\n break;\n case OPS.setTextRenderingMode:\n stateManager.state.textRenderingMode = args[0];\n break;\n\n case OPS.setFillColorSpace:\n stateManager.state.fillColorSpace =\n ColorSpace.parse(args[0], xref, resources);\n continue;\n case OPS.setStrokeColorSpace:\n stateManager.state.strokeColorSpace =\n ColorSpace.parse(args[0], xref, resources);\n continue;\n case OPS.setFillColor:\n cs = stateManager.state.fillColorSpace;\n args = cs.getRgb(args, 0);\n fn = OPS.setFillRGBColor;\n break;\n case OPS.setStrokeColor:\n cs = stateManager.state.strokeColorSpace;\n args = cs.getRgb(args, 0);\n fn = OPS.setStrokeRGBColor;\n break;\n case OPS.setFillGray:\n stateManager.state.fillColorSpace = ColorSpace.singletons.gray;\n args = ColorSpace.singletons.gray.getRgb(args, 0);\n fn = OPS.setFillRGBColor;\n break;\n case OPS.setStrokeGray:\n stateManager.state.strokeColorSpace = ColorSpace.singletons.gray;\n args = ColorSpace.singletons.gray.getRgb(args, 0);\n fn = OPS.setStrokeRGBColor;\n break;\n case OPS.setFillCMYKColor:\n stateManager.state.fillColorSpace = ColorSpace.singletons.cmyk;\n args = ColorSpace.singletons.cmyk.getRgb(args, 0);\n fn = OPS.setFillRGBColor;\n break;\n case OPS.setStrokeCMYKColor:\n stateManager.state.strokeColorSpace = ColorSpace.singletons.cmyk;\n args = ColorSpace.singletons.cmyk.getRgb(args, 0);\n fn = OPS.setStrokeRGBColor;\n break;\n case OPS.setFillRGBColor:\n stateManager.state.fillColorSpace = ColorSpace.singletons.rgb;\n args = ColorSpace.singletons.rgb.getRgb(args, 0);\n break;\n case OPS.setStrokeRGBColor:\n stateManager.state.strokeColorSpace = ColorSpace.singletons.rgb;\n args = ColorSpace.singletons.rgb.getRgb(args, 0);\n break;\n case OPS.setFillColorN:\n cs = stateManager.state.fillColorSpace;\n if (cs.name === 'Pattern') {\n next(self.handleColorN(operatorList, OPS.setFillColorN, args,\n cs, patterns, resources, task));\n return;\n }\n args = cs.getRgb(args, 0);\n fn = OPS.setFillRGBColor;\n break;\n case OPS.setStrokeColorN:\n cs = stateManager.state.strokeColorSpace;\n if (cs.name === 'Pattern') {\n next(self.handleColorN(operatorList, OPS.setStrokeColorN, args,\n cs, patterns, resources, task));\n return;\n }\n args = cs.getRgb(args, 0);\n fn = OPS.setStrokeRGBColor;\n break;\n\n case OPS.shadingFill:\n var shadingRes = resources.get('Shading');\n if (!shadingRes) {\n throw new FormatError('No shading resource found');\n }\n\n var shading = shadingRes.get(args[0].name);\n if (!shading) {\n throw new FormatError('No shading object found');\n }\n\n var shadingFill = Pattern.parseShading(shading, null, xref,\n resources, self.handler);\n var patternIR = shadingFill.getIR();\n args = [patternIR];\n fn = OPS.shadingFill;\n break;\n case OPS.setGState:\n var dictName = args[0];\n var extGState = resources.get('ExtGState');\n\n if (!isDict(extGState) || !extGState.has(dictName.name)) {\n break;\n }\n\n var gState = extGState.get(dictName.name);\n next(self.setGState(resources, gState, operatorList, task,\n stateManager));\n return;\n case OPS.moveTo:\n case OPS.lineTo:\n case OPS.curveTo:\n case OPS.curveTo2:\n case OPS.curveTo3:\n case OPS.closePath:\n self.buildPath(operatorList, fn, args);\n continue;\n case OPS.rectangle:\n self.buildPath(operatorList, fn, args);\n continue;\n case OPS.markPoint:\n case OPS.markPointProps:\n case OPS.beginMarkedContent:\n case OPS.beginMarkedContentProps:\n case OPS.endMarkedContent:\n case OPS.beginCompat:\n case OPS.endCompat:\n // Ignore operators where the corresponding handlers are known to\n // be no-op in CanvasGraphics (display/canvas.js). This prevents\n // serialization errors and is also a bit more efficient.\n // We could also try to serialize all objects in a general way,\n // e.g. as done in https://github.com/mozilla/pdf.js/pull/6266,\n // but doing so is meaningless without knowing the semantics.\n continue;\n default:\n // Note: Ignore the operator if it has `Dict` arguments, since\n // those are non-serializable, otherwise postMessage will throw\n // \"An object could not be cloned.\".\n if (args !== null) {\n for (i = 0, ii = args.length; i < ii; i++) {\n if (args[i] instanceof Dict) {\n break;\n }\n }\n if (i < ii) {\n warn('getOperatorList - ignoring operator: ' + fn);\n continue;\n }\n }\n }\n operatorList.addOp(fn, args);\n }\n if (stop) {\n next(deferred);\n return;\n }\n // Some PDFs don't close all restores inside object/form.\n // Closing those for them.\n closePendingRestoreOPS();\n resolve();\n }).catch((reason) => {\n if (this.options.ignoreErrors) {\n // Error(s) in the OperatorList -- sending unsupported feature\n // notification and allow rendering to continue.\n this.handler.send('UnsupportedFeature',\n { featureId: UNSUPPORTED_FEATURES.unknown, });\n warn('getOperatorList - ignoring errors during task: ' + task.name);\n\n closePendingRestoreOPS();\n return;\n }\n throw reason;\n });\n },\n\n getTextContent({ stream, task, resources, stateManager = null,\n normalizeWhitespace = false, combineTextItems = false,\n sink, seenStyles = Object.create(null), }) {\n // Ensure that `resources`/`stateManager` is correctly initialized,\n // even if the provided parameter is e.g. `null`.\n resources = resources || Dict.empty;\n stateManager = stateManager || new StateManager(new TextState());\n\n var WhitespaceRegexp = /\\s/g;\n\n var textContent = {\n items: [],\n styles: Object.create(null),\n };\n var textContentItem = {\n initialized: false,\n str: [],\n width: 0,\n height: 0,\n vertical: false,\n lastAdvanceWidth: 0,\n lastAdvanceHeight: 0,\n textAdvanceScale: 0,\n spaceWidth: 0,\n fakeSpaceMin: Infinity,\n fakeMultiSpaceMin: Infinity,\n fakeMultiSpaceMax: -0,\n textRunBreakAllowed: false,\n transform: null,\n fontName: null,\n };\n var SPACE_FACTOR = 0.3;\n var MULTI_SPACE_FACTOR = 1.5;\n var MULTI_SPACE_FACTOR_MAX = 4;\n\n var self = this;\n var xref = this.xref;\n\n // The xobj is parsed iff it's needed, e.g. if there is a `DO` cmd.\n var xobjs = null;\n var skipEmptyXObjs = Object.create(null);\n\n var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);\n\n var textState;\n\n function ensureTextContentItem() {\n if (textContentItem.initialized) {\n return textContentItem;\n }\n var font = textState.font;\n if (!(font.loadedName in seenStyles)) {\n seenStyles[font.loadedName] = true;\n textContent.styles[font.loadedName] = {\n fontFamily: font.fallbackName,\n ascent: font.ascent,\n descent: font.descent,\n vertical: font.vertical,\n };\n }\n textContentItem.fontName = font.loadedName;\n\n // 9.4.4 Text Space Details\n var tsm = [textState.fontSize * textState.textHScale, 0,\n 0, textState.fontSize,\n 0, textState.textRise];\n\n if (font.isType3Font &&\n textState.fontMatrix !== FONT_IDENTITY_MATRIX &&\n textState.fontSize === 1) {\n var glyphHeight = font.bbox[3] - font.bbox[1];\n if (glyphHeight > 0) {\n glyphHeight = glyphHeight * textState.fontMatrix[3];\n tsm[3] *= glyphHeight;\n }\n }\n\n var trm = Util.transform(textState.ctm,\n Util.transform(textState.textMatrix, tsm));\n textContentItem.transform = trm;\n if (!font.vertical) {\n textContentItem.width = 0;\n textContentItem.height = Math.sqrt(trm[2] * trm[2] + trm[3] * trm[3]);\n textContentItem.vertical = false;\n } else {\n textContentItem.width = Math.sqrt(trm[0] * trm[0] + trm[1] * trm[1]);\n textContentItem.height = 0;\n textContentItem.vertical = true;\n }\n\n var a = textState.textLineMatrix[0];\n var b = textState.textLineMatrix[1];\n var scaleLineX = Math.sqrt(a * a + b * b);\n a = textState.ctm[0];\n b = textState.ctm[1];\n var scaleCtmX = Math.sqrt(a * a + b * b);\n textContentItem.textAdvanceScale = scaleCtmX * scaleLineX;\n textContentItem.lastAdvanceWidth = 0;\n textContentItem.lastAdvanceHeight = 0;\n\n var spaceWidth = font.spaceWidth / 1000 * textState.fontSize;\n if (spaceWidth) {\n textContentItem.spaceWidth = spaceWidth;\n textContentItem.fakeSpaceMin = spaceWidth * SPACE_FACTOR;\n textContentItem.fakeMultiSpaceMin = spaceWidth * MULTI_SPACE_FACTOR;\n textContentItem.fakeMultiSpaceMax =\n spaceWidth * MULTI_SPACE_FACTOR_MAX;\n // It's okay for monospace fonts to fake as much space as needed.\n textContentItem.textRunBreakAllowed = !font.isMonospace;\n } else {\n textContentItem.spaceWidth = 0;\n textContentItem.fakeSpaceMin = Infinity;\n textContentItem.fakeMultiSpaceMin = Infinity;\n textContentItem.fakeMultiSpaceMax = 0;\n textContentItem.textRunBreakAllowed = false;\n }\n\n\n textContentItem.initialized = true;\n return textContentItem;\n }\n\n function replaceWhitespace(str) {\n // Replaces all whitespaces with standard spaces (0x20), to avoid\n // alignment issues between the textLayer and the canvas if the text\n // contains e.g. tabs (fixes issue6612.pdf).\n var i = 0, ii = str.length, code;\n while (i < ii && (code = str.charCodeAt(i)) >= 0x20 && code <= 0x7F) {\n i++;\n }\n return (i < ii ? str.replace(WhitespaceRegexp, ' ') : str);\n }\n\n function runBidiTransform(textChunk) {\n var str = textChunk.str.join('');\n var bidiResult = bidi(str, -1, textChunk.vertical);\n return {\n str: (normalizeWhitespace ? replaceWhitespace(bidiResult.str) :\n bidiResult.str),\n dir: bidiResult.dir,\n width: textChunk.width,\n height: textChunk.height,\n transform: textChunk.transform,\n fontName: textChunk.fontName,\n };\n }\n\n function handleSetFont(fontName, fontRef) {\n return self.loadFont(fontName, fontRef, resources).\n then(function (translated) {\n textState.font = translated.font;\n textState.fontMatrix = translated.font.fontMatrix ||\n FONT_IDENTITY_MATRIX;\n });\n }\n\n function buildTextContentItem(chars) {\n var font = textState.font;\n var textChunk = ensureTextContentItem();\n var width = 0;\n var height = 0;\n var glyphs = font.charsToGlyphs(chars);\n for (var i = 0; i < glyphs.length; i++) {\n var glyph = glyphs[i];\n var glyphWidth = null;\n if (font.vertical && glyph.vmetric) {\n glyphWidth = glyph.vmetric[0];\n } else {\n glyphWidth = glyph.width;\n }\n\n var glyphUnicode = glyph.unicode;\n var NormalizedUnicodes = getNormalizedUnicodes();\n if (NormalizedUnicodes[glyphUnicode] !== undefined) {\n glyphUnicode = NormalizedUnicodes[glyphUnicode];\n }\n glyphUnicode = reverseIfRtl(glyphUnicode);\n\n var charSpacing = textState.charSpacing;\n if (glyph.isSpace) {\n var wordSpacing = textState.wordSpacing;\n charSpacing += wordSpacing;\n if (wordSpacing > 0) {\n addFakeSpaces(wordSpacing, textChunk.str);\n }\n }\n\n var tx = 0;\n var ty = 0;\n if (!font.vertical) {\n var w0 = glyphWidth * textState.fontMatrix[0];\n tx = (w0 * textState.fontSize + charSpacing) *\n textState.textHScale;\n width += tx;\n } else {\n var w1 = glyphWidth * textState.fontMatrix[0];\n ty = w1 * textState.fontSize + charSpacing;\n height += ty;\n }\n textState.translateTextMatrix(tx, ty);\n\n textChunk.str.push(glyphUnicode);\n }\n\n if (!font.vertical) {\n textChunk.lastAdvanceWidth = width;\n textChunk.width += width;\n } else {\n textChunk.lastAdvanceHeight = height;\n textChunk.height += Math.abs(height);\n }\n\n return textChunk;\n }\n\n function addFakeSpaces(width, strBuf) {\n if (width < textContentItem.fakeSpaceMin) {\n return;\n }\n if (width < textContentItem.fakeMultiSpaceMin) {\n strBuf.push(' ');\n return;\n }\n var fakeSpaces = Math.round(width / textContentItem.spaceWidth);\n while (fakeSpaces-- > 0) {\n strBuf.push(' ');\n }\n }\n\n function flushTextContentItem() {\n if (!textContentItem.initialized) {\n return;\n }\n\n // Do final text scaling\n textContentItem.width *= textContentItem.textAdvanceScale;\n textContentItem.height *= textContentItem.textAdvanceScale;\n textContent.items.push(runBidiTransform(textContentItem));\n\n textContentItem.initialized = false;\n textContentItem.str.length = 0;\n }\n\n function enqueueChunk() {\n let length = textContent.items.length;\n if (length > 0) {\n sink.enqueue(textContent, length);\n textContent.items = [];\n textContent.styles = Object.create(null);\n }\n }\n\n var timeSlotManager = new TimeSlotManager();\n\n return new Promise(function promiseBody(resolve, reject) {\n let next = function (promise) {\n enqueueChunk();\n Promise.all([promise, sink.ready]).then(function () {\n try {\n promiseBody(resolve, reject);\n } catch (ex) {\n reject(ex);\n }\n }, reject);\n };\n task.ensureNotTerminated();\n timeSlotManager.reset();\n var stop, operation = {}, args = [];\n while (!(stop = timeSlotManager.check())) {\n // The arguments parsed by read() are not used beyond this loop, so\n // we can reuse the same array on every iteration, thus avoiding\n // unnecessary allocations.\n args.length = 0;\n operation.args = args;\n if (!(preprocessor.read(operation))) {\n break;\n }\n textState = stateManager.state;\n var fn = operation.fn;\n args = operation.args;\n var advance, diff;\n\n switch (fn | 0) {\n case OPS.setFont:\n // Optimization to ignore multiple identical Tf commands.\n var fontNameArg = args[0].name, fontSizeArg = args[1];\n if (textState.font && fontNameArg === textState.fontName &&\n fontSizeArg === textState.fontSize) {\n break;\n }\n\n flushTextContentItem();\n textState.fontName = fontNameArg;\n textState.fontSize = fontSizeArg;\n next(handleSetFont(fontNameArg, null));\n return;\n case OPS.setTextRise:\n flushTextContentItem();\n textState.textRise = args[0];\n break;\n case OPS.setHScale:\n flushTextContentItem();\n textState.textHScale = args[0] / 100;\n break;\n case OPS.setLeading:\n flushTextContentItem();\n textState.leading = args[0];\n break;\n case OPS.moveText:\n // Optimization to treat same line movement as advance\n var isSameTextLine = !textState.font ? false :\n ((textState.font.vertical ? args[0] : args[1]) === 0);\n advance = args[0] - args[1];\n if (combineTextItems &&\n isSameTextLine && textContentItem.initialized &&\n advance > 0 &&\n advance <= textContentItem.fakeMultiSpaceMax) {\n textState.translateTextLineMatrix(args[0], args[1]);\n textContentItem.width +=\n (args[0] - textContentItem.lastAdvanceWidth);\n textContentItem.height +=\n (args[1] - textContentItem.lastAdvanceHeight);\n diff = (args[0] - textContentItem.lastAdvanceWidth) -\n (args[1] - textContentItem.lastAdvanceHeight);\n addFakeSpaces(diff, textContentItem.str);\n break;\n }\n\n flushTextContentItem();\n textState.translateTextLineMatrix(args[0], args[1]);\n textState.textMatrix = textState.textLineMatrix.slice();\n break;\n case OPS.setLeadingMoveText:\n flushTextContentItem();\n textState.leading = -args[1];\n textState.translateTextLineMatrix(args[0], args[1]);\n textState.textMatrix = textState.textLineMatrix.slice();\n break;\n case OPS.nextLine:\n flushTextContentItem();\n textState.carriageReturn();\n break;\n case OPS.setTextMatrix:\n // Optimization to treat same line movement as advance.\n advance = textState.calcTextLineMatrixAdvance(\n args[0], args[1], args[2], args[3], args[4], args[5]);\n if (combineTextItems &&\n advance !== null && textContentItem.initialized &&\n advance.value > 0 &&\n advance.value <= textContentItem.fakeMultiSpaceMax) {\n textState.translateTextLineMatrix(advance.width,\n advance.height);\n textContentItem.width +=\n (advance.width - textContentItem.lastAdvanceWidth);\n textContentItem.height +=\n (advance.height - textContentItem.lastAdvanceHeight);\n diff = (advance.width - textContentItem.lastAdvanceWidth) -\n (advance.height - textContentItem.lastAdvanceHeight);\n addFakeSpaces(diff, textContentItem.str);\n break;\n }\n\n flushTextContentItem();\n textState.setTextMatrix(args[0], args[1], args[2], args[3],\n args[4], args[5]);\n textState.setTextLineMatrix(args[0], args[1], args[2], args[3],\n args[4], args[5]);\n break;\n case OPS.setCharSpacing:\n textState.charSpacing = args[0];\n break;\n case OPS.setWordSpacing:\n textState.wordSpacing = args[0];\n break;\n case OPS.beginText:\n flushTextContentItem();\n textState.textMatrix = IDENTITY_MATRIX.slice();\n textState.textLineMatrix = IDENTITY_MATRIX.slice();\n break;\n case OPS.showSpacedText:\n var items = args[0];\n var offset;\n for (var j = 0, jj = items.length; j < jj; j++) {\n if (typeof items[j] === 'string') {\n buildTextContentItem(items[j]);\n } else if (isNum(items[j])) {\n ensureTextContentItem();\n\n // PDF Specification 5.3.2 states:\n // The number is expressed in thousandths of a unit of text\n // space.\n // This amount is subtracted from the current horizontal or\n // vertical coordinate, depending on the writing mode.\n // In the default coordinate system, a positive adjustment\n // has the effect of moving the next glyph painted either to\n // the left or down by the given amount.\n advance = items[j] * textState.fontSize / 1000;\n var breakTextRun = false;\n if (textState.font.vertical) {\n offset = advance;\n textState.translateTextMatrix(0, offset);\n breakTextRun = textContentItem.textRunBreakAllowed &&\n advance > textContentItem.fakeMultiSpaceMax;\n if (!breakTextRun) {\n // Value needs to be added to height to paint down.\n textContentItem.height += offset;\n }\n } else {\n advance = -advance;\n offset = advance * textState.textHScale;\n textState.translateTextMatrix(offset, 0);\n breakTextRun = textContentItem.textRunBreakAllowed &&\n advance > textContentItem.fakeMultiSpaceMax;\n if (!breakTextRun) {\n // Value needs to be subtracted from width to paint left.\n textContentItem.width += offset;\n }\n }\n if (breakTextRun) {\n flushTextContentItem();\n } else if (advance > 0) {\n addFakeSpaces(advance, textContentItem.str);\n }\n }\n }\n break;\n case OPS.showText:\n buildTextContentItem(args[0]);\n break;\n case OPS.nextLineShowText:\n flushTextContentItem();\n textState.carriageReturn();\n buildTextContentItem(args[0]);\n break;\n case OPS.nextLineSetSpacingShowText:\n flushTextContentItem();\n textState.wordSpacing = args[0];\n textState.charSpacing = args[1];\n textState.carriageReturn();\n buildTextContentItem(args[2]);\n break;\n case OPS.paintXObject:\n flushTextContentItem();\n if (!xobjs) {\n xobjs = (resources.get('XObject') || Dict.empty);\n }\n\n var name = args[0].name;\n if (name in skipEmptyXObjs) {\n break;\n }\n\n var xobj = xobjs.get(name);\n if (!xobj) {\n break;\n }\n if (!isStream(xobj)) {\n throw new FormatError('XObject should be a stream');\n }\n\n var type = xobj.dict.get('Subtype');\n if (!isName(type)) {\n throw new FormatError('XObject should have a Name subtype');\n }\n\n if (type.name !== 'Form') {\n skipEmptyXObjs[name] = true;\n break;\n }\n\n // Use a new `StateManager` to prevent incorrect positioning of\n // textItems *after* the Form XObject, since errors in the data\n // can otherwise prevent `restore` operators from being executed.\n // NOTE: This is only an issue when `options.ignoreErrors = true`.\n var currentState = stateManager.state.clone();\n var xObjStateManager = new StateManager(currentState);\n\n var matrix = xobj.dict.getArray('Matrix');\n if (isArray(matrix) && matrix.length === 6) {\n xObjStateManager.transform(matrix);\n }\n\n // Enqueue the `textContent` chunk before parsing the /Form\n // XObject.\n enqueueChunk();\n let sinkWrapper = {\n enqueueInvoked: false,\n\n enqueue(chunk, size) {\n this.enqueueInvoked = true;\n sink.enqueue(chunk, size);\n },\n\n get desiredSize() {\n return sink.desiredSize;\n },\n\n get ready() {\n return sink.ready;\n },\n };\n\n next(self.getTextContent({\n stream: xobj,\n task,\n resources: xobj.dict.get('Resources') || resources,\n stateManager: xObjStateManager,\n normalizeWhitespace,\n combineTextItems,\n sink: sinkWrapper,\n seenStyles,\n }).then(function() {\n if (!sinkWrapper.enqueueInvoked) {\n skipEmptyXObjs[name] = true;\n }\n }));\n return;\n case OPS.setGState:\n flushTextContentItem();\n var dictName = args[0];\n var extGState = resources.get('ExtGState');\n\n if (!isDict(extGState) || !isName(dictName)) {\n break;\n }\n var gState = extGState.get(dictName.name);\n if (!isDict(gState)) {\n break;\n }\n var gStateFont = gState.get('Font');\n if (gStateFont) {\n textState.fontName = null;\n textState.fontSize = gStateFont[1];\n next(handleSetFont(null, gStateFont[0]));\n return;\n }\n break;\n } // switch\n if (textContent.items.length >= sink.desiredSize) {\n // Wait for ready, if we reach highWaterMark.\n stop = true;\n break;\n }\n } // while\n if (stop) {\n next(deferred);\n return;\n }\n flushTextContentItem();\n enqueueChunk();\n resolve();\n }).catch((reason) => {\n if (reason instanceof AbortException) {\n return;\n }\n if (this.options.ignoreErrors) {\n // Error(s) in the TextContent -- allow text-extraction to continue.\n warn('getTextContent - ignoring errors during task: ' + task.name);\n\n flushTextContentItem();\n enqueueChunk();\n return;\n }\n throw reason;\n });\n },\n\n extractDataStructures:\n function PartialEvaluator_extractDataStructures(dict, baseDict,\n properties) {\n var xref = this.xref;\n // 9.10.2\n var toUnicode = (dict.get('ToUnicode') || baseDict.get('ToUnicode'));\n var toUnicodePromise = toUnicode ?\n this.readToUnicode(toUnicode) : Promise.resolve(undefined);\n\n if (properties.composite) {\n // CIDSystemInfo helps to match CID to glyphs\n var cidSystemInfo = dict.get('CIDSystemInfo');\n if (isDict(cidSystemInfo)) {\n properties.cidSystemInfo = {\n registry: cidSystemInfo.get('Registry'),\n ordering: cidSystemInfo.get('Ordering'),\n supplement: cidSystemInfo.get('Supplement'),\n };\n }\n\n var cidToGidMap = dict.get('CIDToGIDMap');\n if (isStream(cidToGidMap)) {\n properties.cidToGidMap = this.readCidToGidMap(cidToGidMap);\n }\n }\n\n // Based on 9.6.6 of the spec the encoding can come from multiple places\n // and depends on the font type. The base encoding and differences are\n // read here, but the encoding that is actually used is chosen during\n // glyph mapping in the font.\n // TODO: Loading the built in encoding in the font would allow the\n // differences to be merged in here not require us to hold on to it.\n var differences = [];\n var baseEncodingName = null;\n var encoding;\n if (dict.has('Encoding')) {\n encoding = dict.get('Encoding');\n if (isDict(encoding)) {\n baseEncodingName = encoding.get('BaseEncoding');\n baseEncodingName = (isName(baseEncodingName) ?\n baseEncodingName.name : null);\n // Load the differences between the base and original\n if (encoding.has('Differences')) {\n var diffEncoding = encoding.get('Differences');\n var index = 0;\n for (var j = 0, jj = diffEncoding.length; j < jj; j++) {\n var data = xref.fetchIfRef(diffEncoding[j]);\n if (isNum(data)) {\n index = data;\n } else if (isName(data)) {\n differences[index++] = data.name;\n } else {\n throw new FormatError(\n `Invalid entry in 'Differences' array: ${data}`);\n }\n }\n }\n } else if (isName(encoding)) {\n baseEncodingName = encoding.name;\n } else {\n throw new FormatError('Encoding is not a Name nor a Dict');\n }\n // According to table 114 if the encoding is a named encoding it must be\n // one of these predefined encodings.\n if ((baseEncodingName !== 'MacRomanEncoding' &&\n baseEncodingName !== 'MacExpertEncoding' &&\n baseEncodingName !== 'WinAnsiEncoding')) {\n baseEncodingName = null;\n }\n }\n\n if (baseEncodingName) {\n properties.defaultEncoding = getEncoding(baseEncodingName).slice();\n } else {\n var isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);\n var isNonsymbolicFont = !!(properties.flags & FontFlags.Nonsymbolic);\n // According to \"Table 114\" in section \"9.6.6.1 General\" (under\n // \"9.6.6 Character Encoding\") of the PDF specification, a Nonsymbolic\n // font should use the `StandardEncoding` if no encoding is specified.\n encoding = StandardEncoding;\n if (properties.type === 'TrueType' && !isNonsymbolicFont) {\n encoding = WinAnsiEncoding;\n }\n // The Symbolic attribute can be misused for regular fonts\n // Heuristic: we have to check if the font is a standard one also\n if (isSymbolicFont) {\n encoding = MacRomanEncoding;\n if (!properties.file) {\n if (/Symbol/i.test(properties.name)) {\n encoding = SymbolSetEncoding;\n } else if (/Dingbats/i.test(properties.name)) {\n encoding = ZapfDingbatsEncoding;\n }\n }\n }\n properties.defaultEncoding = encoding;\n }\n\n properties.differences = differences;\n properties.baseEncodingName = baseEncodingName;\n properties.hasEncoding = !!baseEncodingName || differences.length > 0;\n properties.dict = dict;\n return toUnicodePromise.then((toUnicode) => {\n properties.toUnicode = toUnicode;\n return this.buildToUnicode(properties);\n }).then(function (toUnicode) {\n properties.toUnicode = toUnicode;\n return properties;\n });\n },\n\n /**\n * Builds a char code to unicode map based on section 9.10 of the spec.\n * @param {Object} properties Font properties object.\n * @return {Promise} A Promise that is resolved with a\n * {ToUnicodeMap|IdentityToUnicodeMap} object.\n */\n buildToUnicode: function PartialEvaluator_buildToUnicode(properties) {\n properties.hasIncludedToUnicodeMap =\n !!properties.toUnicode && properties.toUnicode.length > 0;\n // Section 9.10.2 Mapping Character Codes to Unicode Values\n if (properties.hasIncludedToUnicodeMap) {\n return Promise.resolve(properties.toUnicode);\n }\n // According to the spec if the font is a simple font we should only map\n // to unicode if the base encoding is MacRoman, MacExpert, or WinAnsi or\n // the differences array only contains adobe standard or symbol set names,\n // in pratice it seems better to always try to create a toUnicode\n // map based of the default encoding.\n var toUnicode, charcode, glyphName;\n if (!properties.composite /* is simple font */) {\n toUnicode = [];\n var encoding = properties.defaultEncoding.slice();\n var baseEncodingName = properties.baseEncodingName;\n // Merge in the differences array.\n var differences = properties.differences;\n for (charcode in differences) {\n glyphName = differences[charcode];\n if (glyphName === '.notdef') {\n // Skip .notdef to prevent rendering errors, e.g. boxes appearing\n // where there should be spaces (fixes issue5256.pdf).\n continue;\n }\n encoding[charcode] = glyphName;\n }\n var glyphsUnicodeMap = getGlyphsUnicode();\n for (charcode in encoding) {\n // a) Map the character code to a character name.\n glyphName = encoding[charcode];\n // b) Look up the character name in the Adobe Glyph List (see the\n // Bibliography) to obtain the corresponding Unicode value.\n if (glyphName === '') {\n continue;\n } else if (glyphsUnicodeMap[glyphName] === undefined) {\n // (undocumented) c) Few heuristics to recognize unknown glyphs\n // NOTE: Adobe Reader does not do this step, but OSX Preview does\n var code = 0;\n switch (glyphName[0]) {\n case 'G': // Gxx glyph\n if (glyphName.length === 3) {\n code = parseInt(glyphName.substr(1), 16);\n }\n break;\n case 'g': // g00xx glyph\n if (glyphName.length === 5) {\n code = parseInt(glyphName.substr(1), 16);\n }\n break;\n case 'C': // Cddd glyph\n case 'c': // cddd glyph\n if (glyphName.length >= 3) {\n code = +glyphName.substr(1);\n }\n break;\n default:\n // 'uniXXXX'/'uXXXX{XX}' glyphs\n var unicode = getUnicodeForGlyph(glyphName, glyphsUnicodeMap);\n if (unicode !== -1) {\n code = unicode;\n }\n }\n if (code) {\n // If |baseEncodingName| is one the predefined encodings,\n // and |code| equals |charcode|, using the glyph defined in the\n // baseEncoding seems to yield a better |toUnicode| mapping\n // (fixes issue 5070).\n if (baseEncodingName && code === +charcode) {\n var baseEncoding = getEncoding(baseEncodingName);\n if (baseEncoding && (glyphName = baseEncoding[charcode])) {\n toUnicode[charcode] =\n String.fromCharCode(glyphsUnicodeMap[glyphName]);\n continue;\n }\n }\n toUnicode[charcode] = String.fromCharCode(code);\n }\n continue;\n }\n toUnicode[charcode] =\n String.fromCharCode(glyphsUnicodeMap[glyphName]);\n }\n return Promise.resolve(new ToUnicodeMap(toUnicode));\n }\n // If the font is a composite font that uses one of the predefined CMaps\n // listed in Table 118 (except Identity–H and Identity–V) or whose\n // descendant CIDFont uses the Adobe-GB1, Adobe-CNS1, Adobe-Japan1, or\n // Adobe-Korea1 character collection:\n if (properties.composite && (\n (properties.cMap.builtInCMap &&\n !(properties.cMap instanceof IdentityCMap)) ||\n (properties.cidSystemInfo.registry === 'Adobe' &&\n (properties.cidSystemInfo.ordering === 'GB1' ||\n properties.cidSystemInfo.ordering === 'CNS1' ||\n properties.cidSystemInfo.ordering === 'Japan1' ||\n properties.cidSystemInfo.ordering === 'Korea1')))) {\n // Then:\n // a) Map the character code to a character identifier (CID) according\n // to the font’s CMap.\n // b) Obtain the registry and ordering of the character collection used\n // by the font’s CMap (for example, Adobe and Japan1) from its\n // CIDSystemInfo dictionary.\n var registry = properties.cidSystemInfo.registry;\n var ordering = properties.cidSystemInfo.ordering;\n // c) Construct a second CMap name by concatenating the registry and\n // ordering obtained in step (b) in the format registry–ordering–UCS2\n // (for example, Adobe–Japan1–UCS2).\n var ucs2CMapName = Name.get(registry + '-' + ordering + '-UCS2');\n // d) Obtain the CMap with the name constructed in step (c) (available\n // from the ASN Web site; see the Bibliography).\n return CMapFactory.create({\n encoding: ucs2CMapName,\n fetchBuiltInCMap: this.fetchBuiltInCMap,\n useCMap: null,\n }).then(function (ucs2CMap) {\n var cMap = properties.cMap;\n toUnicode = [];\n cMap.forEach(function(charcode, cid) {\n if (cid > 0xffff) {\n throw new FormatError('Max size of CID is 65,535');\n }\n // e) Map the CID obtained in step (a) according to the CMap\n // obtained in step (d), producing a Unicode value.\n var ucs2 = ucs2CMap.lookup(cid);\n if (ucs2) {\n toUnicode[charcode] =\n String.fromCharCode((ucs2.charCodeAt(0) << 8) +\n ucs2.charCodeAt(1));\n }\n });\n return new ToUnicodeMap(toUnicode);\n });\n }\n\n // The viewer's choice, just use an identity map.\n return Promise.resolve(new IdentityToUnicodeMap(properties.firstChar,\n properties.lastChar));\n },\n\n readToUnicode: function PartialEvaluator_readToUnicode(toUnicode) {\n var cmapObj = toUnicode;\n if (isName(cmapObj)) {\n return CMapFactory.create({\n encoding: cmapObj,\n fetchBuiltInCMap: this.fetchBuiltInCMap,\n useCMap: null,\n }).then(function (cmap) {\n if (cmap instanceof IdentityCMap) {\n return new IdentityToUnicodeMap(0, 0xFFFF);\n }\n return new ToUnicodeMap(cmap.getMap());\n });\n } else if (isStream(cmapObj)) {\n return CMapFactory.create({\n encoding: cmapObj,\n fetchBuiltInCMap: this.fetchBuiltInCMap,\n useCMap: null,\n }).then(function (cmap) {\n if (cmap instanceof IdentityCMap) {\n return new IdentityToUnicodeMap(0, 0xFFFF);\n }\n var map = new Array(cmap.length);\n // Convert UTF-16BE\n // NOTE: cmap can be a sparse array, so use forEach instead of for(;;)\n // to iterate over all keys.\n cmap.forEach(function(charCode, token) {\n var str = [];\n for (var k = 0; k < token.length; k += 2) {\n var w1 = (token.charCodeAt(k) << 8) | token.charCodeAt(k + 1);\n if ((w1 & 0xF800) !== 0xD800) { // w1 < 0xD800 || w1 > 0xDFFF\n str.push(w1);\n continue;\n }\n k += 2;\n var w2 = (token.charCodeAt(k) << 8) | token.charCodeAt(k + 1);\n str.push(((w1 & 0x3ff) << 10) + (w2 & 0x3ff) + 0x10000);\n }\n map[charCode] = String.fromCharCode.apply(String, str);\n });\n return new ToUnicodeMap(map);\n });\n }\n return Promise.resolve(null);\n },\n\n readCidToGidMap: function PartialEvaluator_readCidToGidMap(cidToGidStream) {\n // Extract the encoding from the CIDToGIDMap\n var glyphsData = cidToGidStream.getBytes();\n\n // Set encoding 0 to later verify the font has an encoding\n var result = [];\n for (var j = 0, jj = glyphsData.length; j < jj; j++) {\n var glyphID = (glyphsData[j++] << 8) | glyphsData[j];\n if (glyphID === 0) {\n continue;\n }\n var code = j >> 1;\n result[code] = glyphID;\n }\n return result;\n },\n\n extractWidths: function PartialEvaluator_extractWidths(dict, descriptor,\n properties) {\n var xref = this.xref;\n var glyphsWidths = [];\n var defaultWidth = 0;\n var glyphsVMetrics = [];\n var defaultVMetrics;\n var i, ii, j, jj, start, code, widths;\n if (properties.composite) {\n defaultWidth = dict.get('DW') || 1000;\n\n widths = dict.get('W');\n if (widths) {\n for (i = 0, ii = widths.length; i < ii; i++) {\n start = xref.fetchIfRef(widths[i++]);\n code = xref.fetchIfRef(widths[i]);\n if (isArray(code)) {\n for (j = 0, jj = code.length; j < jj; j++) {\n glyphsWidths[start++] = xref.fetchIfRef(code[j]);\n }\n } else {\n var width = xref.fetchIfRef(widths[++i]);\n for (j = start; j <= code; j++) {\n glyphsWidths[j] = width;\n }\n }\n }\n }\n\n if (properties.vertical) {\n var vmetrics = dict.getArray('DW2') || [880, -1000];\n defaultVMetrics = [vmetrics[1], defaultWidth * 0.5, vmetrics[0]];\n vmetrics = dict.get('W2');\n if (vmetrics) {\n for (i = 0, ii = vmetrics.length; i < ii; i++) {\n start = xref.fetchIfRef(vmetrics[i++]);\n code = xref.fetchIfRef(vmetrics[i]);\n if (isArray(code)) {\n for (j = 0, jj = code.length; j < jj; j++) {\n glyphsVMetrics[start++] = [\n xref.fetchIfRef(code[j++]),\n xref.fetchIfRef(code[j++]),\n xref.fetchIfRef(code[j])\n ];\n }\n } else {\n var vmetric = [\n xref.fetchIfRef(vmetrics[++i]),\n xref.fetchIfRef(vmetrics[++i]),\n xref.fetchIfRef(vmetrics[++i])\n ];\n for (j = start; j <= code; j++) {\n glyphsVMetrics[j] = vmetric;\n }\n }\n }\n }\n }\n } else {\n var firstChar = properties.firstChar;\n widths = dict.get('Widths');\n if (widths) {\n j = firstChar;\n for (i = 0, ii = widths.length; i < ii; i++) {\n glyphsWidths[j++] = xref.fetchIfRef(widths[i]);\n }\n defaultWidth = (parseFloat(descriptor.get('MissingWidth')) || 0);\n } else {\n // Trying get the BaseFont metrics (see comment above).\n var baseFontName = dict.get('BaseFont');\n if (isName(baseFontName)) {\n var metrics = this.getBaseFontMetrics(baseFontName.name);\n\n glyphsWidths = this.buildCharCodeToWidth(metrics.widths,\n properties);\n defaultWidth = metrics.defaultWidth;\n }\n }\n }\n\n // Heuristic: detection of monospace font by checking all non-zero widths\n var isMonospace = true;\n var firstWidth = defaultWidth;\n for (var glyph in glyphsWidths) {\n var glyphWidth = glyphsWidths[glyph];\n if (!glyphWidth) {\n continue;\n }\n if (!firstWidth) {\n firstWidth = glyphWidth;\n continue;\n }\n if (firstWidth !== glyphWidth) {\n isMonospace = false;\n break;\n }\n }\n if (isMonospace) {\n properties.flags |= FontFlags.FixedPitch;\n }\n\n properties.defaultWidth = defaultWidth;\n properties.widths = glyphsWidths;\n properties.defaultVMetrics = defaultVMetrics;\n properties.vmetrics = glyphsVMetrics;\n },\n\n isSerifFont: function PartialEvaluator_isSerifFont(baseFontName) {\n // Simulating descriptor flags attribute\n var fontNameWoStyle = baseFontName.split('-')[0];\n return (fontNameWoStyle in getSerifFonts()) ||\n (fontNameWoStyle.search(/serif/gi) !== -1);\n },\n\n getBaseFontMetrics: function PartialEvaluator_getBaseFontMetrics(name) {\n var defaultWidth = 0;\n var widths = [];\n var monospace = false;\n var stdFontMap = getStdFontMap();\n var lookupName = (stdFontMap[name] || name);\n var Metrics = getMetrics();\n\n if (!(lookupName in Metrics)) {\n // Use default fonts for looking up font metrics if the passed\n // font is not a base font\n if (this.isSerifFont(name)) {\n lookupName = 'Times-Roman';\n } else {\n lookupName = 'Helvetica';\n }\n }\n var glyphWidths = Metrics[lookupName];\n\n if (isNum(glyphWidths)) {\n defaultWidth = glyphWidths;\n monospace = true;\n } else {\n widths = glyphWidths(); // expand lazy widths array\n }\n\n return {\n defaultWidth,\n monospace,\n widths,\n };\n },\n\n buildCharCodeToWidth:\n function PartialEvaluator_bulildCharCodeToWidth(widthsByGlyphName,\n properties) {\n var widths = Object.create(null);\n var differences = properties.differences;\n var encoding = properties.defaultEncoding;\n for (var charCode = 0; charCode < 256; charCode++) {\n if (charCode in differences &&\n widthsByGlyphName[differences[charCode]]) {\n widths[charCode] = widthsByGlyphName[differences[charCode]];\n continue;\n }\n if (charCode in encoding && widthsByGlyphName[encoding[charCode]]) {\n widths[charCode] = widthsByGlyphName[encoding[charCode]];\n continue;\n }\n }\n return widths;\n },\n\n preEvaluateFont: function PartialEvaluator_preEvaluateFont(dict) {\n var baseDict = dict;\n var type = dict.get('Subtype');\n if (!isName(type)) {\n throw new FormatError('invalid font Subtype');\n }\n\n var composite = false;\n var uint8array;\n if (type.name === 'Type0') {\n // If font is a composite\n // - get the descendant font\n // - set the type according to the descendant font\n // - get the FontDescriptor from the descendant font\n var df = dict.get('DescendantFonts');\n if (!df) {\n throw new FormatError('Descendant fonts are not specified');\n }\n dict = (isArray(df) ? this.xref.fetchIfRef(df[0]) : df);\n\n type = dict.get('Subtype');\n if (!isName(type)) {\n throw new FormatError('invalid font Subtype');\n }\n composite = true;\n }\n\n var descriptor = dict.get('FontDescriptor');\n if (descriptor) {\n var hash = new MurmurHash3_64();\n var encoding = baseDict.getRaw('Encoding');\n if (isName(encoding)) {\n hash.update(encoding.name);\n } else if (isRef(encoding)) {\n hash.update(encoding.toString());\n } else if (isDict(encoding)) {\n var keys = encoding.getKeys();\n for (var i = 0, ii = keys.length; i < ii; i++) {\n var entry = encoding.getRaw(keys[i]);\n if (isName(entry)) {\n hash.update(entry.name);\n } else if (isRef(entry)) {\n hash.update(entry.toString());\n } else if (isArray(entry)) {\n // 'Differences' array (fixes bug1157493.pdf).\n var diffLength = entry.length, diffBuf = new Array(diffLength);\n\n for (var j = 0; j < diffLength; j++) {\n var diffEntry = entry[j];\n if (isName(diffEntry)) {\n diffBuf[j] = diffEntry.name;\n } else if (isNum(diffEntry) || isRef(diffEntry)) {\n diffBuf[j] = diffEntry.toString();\n }\n }\n hash.update(diffBuf.join());\n }\n }\n }\n\n var toUnicode = dict.get('ToUnicode') || baseDict.get('ToUnicode');\n if (isStream(toUnicode)) {\n var stream = toUnicode.str || toUnicode;\n uint8array = stream.buffer ?\n new Uint8Array(stream.buffer.buffer, 0, stream.bufferLength) :\n new Uint8Array(stream.bytes.buffer,\n stream.start, stream.end - stream.start);\n hash.update(uint8array);\n\n } else if (isName(toUnicode)) {\n hash.update(toUnicode.name);\n }\n\n var widths = dict.get('Widths') || baseDict.get('Widths');\n if (widths) {\n uint8array = new Uint8Array(new Uint32Array(widths).buffer);\n hash.update(uint8array);\n }\n }\n\n return {\n descriptor,\n dict,\n baseDict,\n composite,\n type: type.name,\n hash: hash ? hash.hexdigest() : '',\n };\n },\n\n translateFont: function PartialEvaluator_translateFont(preEvaluatedFont) {\n var baseDict = preEvaluatedFont.baseDict;\n var dict = preEvaluatedFont.dict;\n var composite = preEvaluatedFont.composite;\n var descriptor = preEvaluatedFont.descriptor;\n var type = preEvaluatedFont.type;\n var maxCharIndex = (composite ? 0xFFFF : 0xFF);\n var properties;\n\n if (!descriptor) {\n if (type === 'Type3') {\n // FontDescriptor is only required for Type3 fonts when the document\n // is a tagged pdf. Create a barbebones one to get by.\n descriptor = new Dict(null);\n descriptor.set('FontName', Name.get(type));\n descriptor.set('FontBBox', dict.getArray('FontBBox'));\n } else {\n // Before PDF 1.5 if the font was one of the base 14 fonts, having a\n // FontDescriptor was not required.\n // This case is here for compatibility.\n var baseFontName = dict.get('BaseFont');\n if (!isName(baseFontName)) {\n throw new FormatError('Base font is not specified');\n }\n\n // Using base font name as a font name.\n baseFontName = baseFontName.name.replace(/[,_]/g, '-');\n var metrics = this.getBaseFontMetrics(baseFontName);\n\n // Simulating descriptor flags attribute\n var fontNameWoStyle = baseFontName.split('-')[0];\n var flags =\n (this.isSerifFont(fontNameWoStyle) ? FontFlags.Serif : 0) |\n (metrics.monospace ? FontFlags.FixedPitch : 0) |\n (getSymbolsFonts()[fontNameWoStyle] ? FontFlags.Symbolic :\n FontFlags.Nonsymbolic);\n\n properties = {\n type,\n name: baseFontName,\n widths: metrics.widths,\n defaultWidth: metrics.defaultWidth,\n flags,\n firstChar: 0,\n lastChar: maxCharIndex,\n };\n return this.extractDataStructures(dict, dict, properties).\n then((properties) => {\n properties.widths = this.buildCharCodeToWidth(metrics.widths,\n properties);\n return new Font(baseFontName, null, properties);\n });\n }\n }\n\n // According to the spec if 'FontDescriptor' is declared, 'FirstChar',\n // 'LastChar' and 'Widths' should exist too, but some PDF encoders seem\n // to ignore this rule when a variant of a standard font is used.\n // TODO Fill the width array depending on which of the base font this is\n // a variant.\n var firstChar = (dict.get('FirstChar') || 0);\n var lastChar = (dict.get('LastChar') || maxCharIndex);\n\n var fontName = descriptor.get('FontName');\n var baseFont = dict.get('BaseFont');\n // Some bad PDFs have a string as the font name.\n if (isString(fontName)) {\n fontName = Name.get(fontName);\n }\n if (isString(baseFont)) {\n baseFont = Name.get(baseFont);\n }\n\n if (type !== 'Type3') {\n var fontNameStr = fontName && fontName.name;\n var baseFontStr = baseFont && baseFont.name;\n if (fontNameStr !== baseFontStr) {\n info('The FontDescriptor\\'s FontName is \"' + fontNameStr +\n '\" but should be the same as the Font\\'s BaseFont \"' +\n baseFontStr + '\"');\n // Workaround for cases where e.g. fontNameStr = 'Arial' and\n // baseFontStr = 'Arial,Bold' (needed when no font file is embedded).\n if (fontNameStr && baseFontStr &&\n baseFontStr.indexOf(fontNameStr) === 0) {\n fontName = baseFont;\n }\n }\n }\n fontName = (fontName || baseFont);\n\n if (!isName(fontName)) {\n throw new FormatError('invalid font name');\n }\n\n var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3');\n if (fontFile) {\n if (fontFile.dict) {\n var subtype = fontFile.dict.get('Subtype');\n if (subtype) {\n subtype = subtype.name;\n }\n var length1 = fontFile.dict.get('Length1');\n var length2 = fontFile.dict.get('Length2');\n var length3 = fontFile.dict.get('Length3');\n }\n }\n\n properties = {\n type,\n name: fontName.name,\n subtype,\n file: fontFile,\n length1,\n length2,\n length3,\n loadedName: baseDict.loadedName,\n composite,\n wideChars: composite,\n fixedPitch: false,\n fontMatrix: (dict.getArray('FontMatrix') || FONT_IDENTITY_MATRIX),\n firstChar: firstChar || 0,\n lastChar: (lastChar || maxCharIndex),\n bbox: descriptor.getArray('FontBBox'),\n ascent: descriptor.get('Ascent'),\n descent: descriptor.get('Descent'),\n xHeight: descriptor.get('XHeight'),\n capHeight: descriptor.get('CapHeight'),\n flags: descriptor.get('Flags'),\n italicAngle: descriptor.get('ItalicAngle'),\n isType3Font: false,\n };\n\n var cMapPromise;\n if (composite) {\n var cidEncoding = baseDict.get('Encoding');\n if (isName(cidEncoding)) {\n properties.cidEncoding = cidEncoding.name;\n }\n cMapPromise = CMapFactory.create({\n encoding: cidEncoding,\n fetchBuiltInCMap: this.fetchBuiltInCMap,\n useCMap: null,\n }).then(function (cMap) {\n properties.cMap = cMap;\n properties.vertical = properties.cMap.vertical;\n });\n } else {\n cMapPromise = Promise.resolve(undefined);\n }\n\n return cMapPromise.then(() => {\n return this.extractDataStructures(dict, baseDict, properties);\n }).then((properties) => {\n this.extractWidths(dict, descriptor, properties);\n\n if (type === 'Type3') {\n properties.isType3Font = true;\n }\n return new Font(fontName.name, fontFile, properties);\n });\n },\n };\n\n return PartialEvaluator;\n})();\n\nvar TranslatedFont = (function TranslatedFontClosure() {\n function TranslatedFont(loadedName, font, dict) {\n this.loadedName = loadedName;\n this.font = font;\n this.dict = dict;\n this.type3Loaded = null;\n this.sent = false;\n }\n TranslatedFont.prototype = {\n send(handler) {\n if (this.sent) {\n return;\n }\n var fontData = this.font.exportData();\n handler.send('commonobj', [\n this.loadedName,\n 'Font',\n fontData\n ]);\n this.sent = true;\n },\n loadType3Data(evaluator, resources, parentOperatorList, task) {\n if (!this.font.isType3Font) {\n throw new Error('Must be a Type3 font.');\n }\n\n if (this.type3Loaded) {\n return this.type3Loaded;\n }\n // When parsing Type3 glyphs, always ignore them if there are errors.\n // Compared to the parsing of e.g. an entire page, it doesn't really\n // make sense to only be able to render a Type3 glyph partially.\n var type3Options = Object.create(evaluator.options);\n type3Options.ignoreErrors = false;\n var type3Evaluator = evaluator.clone(type3Options);\n\n var translatedFont = this.font;\n var loadCharProcsPromise = Promise.resolve();\n var charProcs = this.dict.get('CharProcs');\n var fontResources = this.dict.get('Resources') || resources;\n var charProcKeys = charProcs.getKeys();\n var charProcOperatorList = Object.create(null);\n\n for (var i = 0, n = charProcKeys.length; i < n; ++i) {\n let key = charProcKeys[i];\n loadCharProcsPromise = loadCharProcsPromise.then(function () {\n var glyphStream = charProcs.get(key);\n var operatorList = new OperatorList();\n return type3Evaluator.getOperatorList({\n stream: glyphStream,\n task,\n resources: fontResources,\n operatorList,\n }).then(function () {\n charProcOperatorList[key] = operatorList.getIR();\n\n // Add the dependencies to the parent operator list so they are\n // resolved before sub operator list is executed synchronously.\n parentOperatorList.addDependencies(operatorList.dependencies);\n }).catch(function(reason) {\n warn(`Type3 font resource \"${key}\" is not available.`);\n var operatorList = new OperatorList();\n charProcOperatorList[key] = operatorList.getIR();\n });\n });\n }\n this.type3Loaded = loadCharProcsPromise.then(function () {\n translatedFont.charProcOperatorList = charProcOperatorList;\n });\n return this.type3Loaded;\n },\n };\n return TranslatedFont;\n})();\n\nvar OperatorList = (function OperatorListClosure() {\n var CHUNK_SIZE = 1000;\n var CHUNK_SIZE_ABOUT = CHUNK_SIZE - 5; // close to chunk size\n\n function getTransfers(queue) {\n var transfers = [];\n var fnArray = queue.fnArray, argsArray = queue.argsArray;\n for (var i = 0, ii = queue.length; i < ii; i++) {\n switch (fnArray[i]) {\n case OPS.paintInlineImageXObject:\n case OPS.paintInlineImageXObjectGroup:\n case OPS.paintImageMaskXObject:\n var arg = argsArray[i][0]; // first param in imgData\n if (!arg.cached) {\n transfers.push(arg.data.buffer);\n }\n break;\n }\n }\n return transfers;\n }\n\n function OperatorList(intent, messageHandler, pageIndex) {\n this.messageHandler = messageHandler;\n this.fnArray = [];\n this.argsArray = [];\n this.dependencies = Object.create(null);\n this._totalLength = 0;\n this.pageIndex = pageIndex;\n this.intent = intent;\n }\n\n OperatorList.prototype = {\n get length() {\n return this.argsArray.length;\n },\n\n /**\n * @returns {number} The total length of the entire operator list,\n * since `this.length === 0` after flushing.\n */\n get totalLength() {\n return (this._totalLength + this.length);\n },\n\n addOp(fn, args) {\n this.fnArray.push(fn);\n this.argsArray.push(args);\n if (this.messageHandler) {\n if (this.fnArray.length >= CHUNK_SIZE) {\n this.flush();\n } else if (this.fnArray.length >= CHUNK_SIZE_ABOUT &&\n (fn === OPS.restore || fn === OPS.endText)) {\n // heuristic to flush on boundary of restore or endText\n this.flush();\n }\n }\n },\n\n addDependency(dependency) {\n if (dependency in this.dependencies) {\n return;\n }\n this.dependencies[dependency] = true;\n this.addOp(OPS.dependency, [dependency]);\n },\n\n addDependencies(dependencies) {\n for (var key in dependencies) {\n this.addDependency(key);\n }\n },\n\n addOpList(opList) {\n Util.extendObj(this.dependencies, opList.dependencies);\n for (var i = 0, ii = opList.length; i < ii; i++) {\n this.addOp(opList.fnArray[i], opList.argsArray[i]);\n }\n },\n\n getIR() {\n return {\n fnArray: this.fnArray,\n argsArray: this.argsArray,\n length: this.length,\n };\n },\n\n flush(lastChunk) {\n if (this.intent !== 'oplist') {\n new QueueOptimizer().optimize(this);\n }\n var transfers = getTransfers(this);\n var length = this.length;\n this._totalLength += length;\n\n this.messageHandler.send('RenderPageChunk', {\n operatorList: {\n fnArray: this.fnArray,\n argsArray: this.argsArray,\n lastChunk,\n length,\n },\n pageIndex: this.pageIndex,\n intent: this.intent,\n }, transfers);\n this.dependencies = Object.create(null);\n this.fnArray.length = 0;\n this.argsArray.length = 0;\n },\n };\n\n return OperatorList;\n})();\n\nvar StateManager = (function StateManagerClosure() {\n function StateManager(initialState) {\n this.state = initialState;\n this.stateStack = [];\n }\n StateManager.prototype = {\n save() {\n var old = this.state;\n this.stateStack.push(this.state);\n this.state = old.clone();\n },\n restore() {\n var prev = this.stateStack.pop();\n if (prev) {\n this.state = prev;\n }\n },\n transform(args) {\n this.state.ctm = Util.transform(this.state.ctm, args);\n },\n };\n return StateManager;\n})();\n\nvar TextState = (function TextStateClosure() {\n function TextState() {\n this.ctm = new Float32Array(IDENTITY_MATRIX);\n this.fontName = null;\n this.fontSize = 0;\n this.font = null;\n this.fontMatrix = FONT_IDENTITY_MATRIX;\n this.textMatrix = IDENTITY_MATRIX.slice();\n this.textLineMatrix = IDENTITY_MATRIX.slice();\n this.charSpacing = 0;\n this.wordSpacing = 0;\n this.leading = 0;\n this.textHScale = 1;\n this.textRise = 0;\n }\n\n TextState.prototype = {\n setTextMatrix: function TextState_setTextMatrix(a, b, c, d, e, f) {\n var m = this.textMatrix;\n m[0] = a; m[1] = b; m[2] = c; m[3] = d; m[4] = e; m[5] = f;\n },\n setTextLineMatrix: function TextState_setTextMatrix(a, b, c, d, e, f) {\n var m = this.textLineMatrix;\n m[0] = a; m[1] = b; m[2] = c; m[3] = d; m[4] = e; m[5] = f;\n },\n translateTextMatrix: function TextState_translateTextMatrix(x, y) {\n var m = this.textMatrix;\n m[4] = m[0] * x + m[2] * y + m[4];\n m[5] = m[1] * x + m[3] * y + m[5];\n },\n translateTextLineMatrix: function TextState_translateTextMatrix(x, y) {\n var m = this.textLineMatrix;\n m[4] = m[0] * x + m[2] * y + m[4];\n m[5] = m[1] * x + m[3] * y + m[5];\n },\n calcTextLineMatrixAdvance:\n function TextState_calcTextLineMatrixAdvance(a, b, c, d, e, f) {\n var font = this.font;\n if (!font) {\n return null;\n }\n var m = this.textLineMatrix;\n if (!(a === m[0] && b === m[1] && c === m[2] && d === m[3])) {\n return null;\n }\n var txDiff = e - m[4], tyDiff = f - m[5];\n if ((font.vertical && txDiff !== 0) || (!font.vertical && tyDiff !== 0)) {\n return null;\n }\n var tx, ty, denominator = a * d - b * c;\n if (font.vertical) {\n tx = -tyDiff * c / denominator;\n ty = tyDiff * a / denominator;\n } else {\n tx = txDiff * d / denominator;\n ty = -txDiff * b / denominator;\n }\n return { width: tx, height: ty, value: (font.vertical ? ty : tx), };\n },\n calcRenderMatrix: function TextState_calcRendeMatrix(ctm) {\n // 9.4.4 Text Space Details\n var tsm = [this.fontSize * this.textHScale, 0,\n 0, this.fontSize,\n 0, this.textRise];\n return Util.transform(ctm, Util.transform(this.textMatrix, tsm));\n },\n carriageReturn: function TextState_carriageReturn() {\n this.translateTextLineMatrix(0, -this.leading);\n this.textMatrix = this.textLineMatrix.slice();\n },\n clone: function TextState_clone() {\n var clone = Object.create(this);\n clone.textMatrix = this.textMatrix.slice();\n clone.textLineMatrix = this.textLineMatrix.slice();\n clone.fontMatrix = this.fontMatrix.slice();\n return clone;\n },\n };\n return TextState;\n})();\n\nvar EvalState = (function EvalStateClosure() {\n function EvalState() {\n this.ctm = new Float32Array(IDENTITY_MATRIX);\n this.font = null;\n this.textRenderingMode = TextRenderingMode.FILL;\n this.fillColorSpace = ColorSpace.singletons.gray;\n this.strokeColorSpace = ColorSpace.singletons.gray;\n }\n EvalState.prototype = {\n clone: function CanvasExtraState_clone() {\n return Object.create(this);\n },\n };\n return EvalState;\n})();\n\nvar EvaluatorPreprocessor = (function EvaluatorPreprocessorClosure() {\n // Specifies properties for each command\n //\n // If variableArgs === true: [0, `numArgs`] expected\n // If variableArgs === false: exactly `numArgs` expected\n var getOPMap = getLookupTableFactory(function (t) {\n // Graphic state\n t['w'] = { id: OPS.setLineWidth, numArgs: 1, variableArgs: false, };\n t['J'] = { id: OPS.setLineCap, numArgs: 1, variableArgs: false, };\n t['j'] = { id: OPS.setLineJoin, numArgs: 1, variableArgs: false, };\n t['M'] = { id: OPS.setMiterLimit, numArgs: 1, variableArgs: false, };\n t['d'] = { id: OPS.setDash, numArgs: 2, variableArgs: false, };\n t['ri'] = { id: OPS.setRenderingIntent, numArgs: 1, variableArgs: false, };\n t['i'] = { id: OPS.setFlatness, numArgs: 1, variableArgs: false, };\n t['gs'] = { id: OPS.setGState, numArgs: 1, variableArgs: false, };\n t['q'] = { id: OPS.save, numArgs: 0, variableArgs: false, };\n t['Q'] = { id: OPS.restore, numArgs: 0, variableArgs: false, };\n t['cm'] = { id: OPS.transform, numArgs: 6, variableArgs: false, };\n\n // Path\n t['m'] = { id: OPS.moveTo, numArgs: 2, variableArgs: false, };\n t['l'] = { id: OPS.lineTo, numArgs: 2, variableArgs: false, };\n t['c'] = { id: OPS.curveTo, numArgs: 6, variableArgs: false, };\n t['v'] = { id: OPS.curveTo2, numArgs: 4, variableArgs: false, };\n t['y'] = { id: OPS.curveTo3, numArgs: 4, variableArgs: false, };\n t['h'] = { id: OPS.closePath, numArgs: 0, variableArgs: false, };\n t['re'] = { id: OPS.rectangle, numArgs: 4, variableArgs: false, };\n t['S'] = { id: OPS.stroke, numArgs: 0, variableArgs: false, };\n t['s'] = { id: OPS.closeStroke, numArgs: 0, variableArgs: false, };\n t['f'] = { id: OPS.fill, numArgs: 0, variableArgs: false, };\n t['F'] = { id: OPS.fill, numArgs: 0, variableArgs: false, };\n t['f*'] = { id: OPS.eoFill, numArgs: 0, variableArgs: false, };\n t['B'] = { id: OPS.fillStroke, numArgs: 0, variableArgs: false, };\n t['B*'] = { id: OPS.eoFillStroke, numArgs: 0, variableArgs: false, };\n t['b'] = { id: OPS.closeFillStroke, numArgs: 0, variableArgs: false, };\n t['b*'] = { id: OPS.closeEOFillStroke, numArgs: 0, variableArgs: false, };\n t['n'] = { id: OPS.endPath, numArgs: 0, variableArgs: false, };\n\n // Clipping\n t['W'] = { id: OPS.clip, numArgs: 0, variableArgs: false, };\n t['W*'] = { id: OPS.eoClip, numArgs: 0, variableArgs: false, };\n\n // Text\n t['BT'] = { id: OPS.beginText, numArgs: 0, variableArgs: false, };\n t['ET'] = { id: OPS.endText, numArgs: 0, variableArgs: false, };\n t['Tc'] = { id: OPS.setCharSpacing, numArgs: 1, variableArgs: false, };\n t['Tw'] = { id: OPS.setWordSpacing, numArgs: 1, variableArgs: false, };\n t['Tz'] = { id: OPS.setHScale, numArgs: 1, variableArgs: false, };\n t['TL'] = { id: OPS.setLeading, numArgs: 1, variableArgs: false, };\n t['Tf'] = { id: OPS.setFont, numArgs: 2, variableArgs: false, };\n t['Tr'] = { id: OPS.setTextRenderingMode, numArgs: 1,\n variableArgs: false, };\n t['Ts'] = { id: OPS.setTextRise, numArgs: 1, variableArgs: false, };\n t['Td'] = { id: OPS.moveText, numArgs: 2, variableArgs: false, };\n t['TD'] = { id: OPS.setLeadingMoveText, numArgs: 2, variableArgs: false, };\n t['Tm'] = { id: OPS.setTextMatrix, numArgs: 6, variableArgs: false, };\n t['T*'] = { id: OPS.nextLine, numArgs: 0, variableArgs: false, };\n t['Tj'] = { id: OPS.showText, numArgs: 1, variableArgs: false, };\n t['TJ'] = { id: OPS.showSpacedText, numArgs: 1, variableArgs: false, };\n t['\\''] = { id: OPS.nextLineShowText, numArgs: 1, variableArgs: false, };\n t['\"'] = { id: OPS.nextLineSetSpacingShowText, numArgs: 3,\n variableArgs: false, };\n\n // Type3 fonts\n t['d0'] = { id: OPS.setCharWidth, numArgs: 2, variableArgs: false, };\n t['d1'] = { id: OPS.setCharWidthAndBounds, numArgs: 6,\n variableArgs: false, };\n\n // Color\n t['CS'] = { id: OPS.setStrokeColorSpace, numArgs: 1, variableArgs: false, };\n t['cs'] = { id: OPS.setFillColorSpace, numArgs: 1, variableArgs: false, };\n t['SC'] = { id: OPS.setStrokeColor, numArgs: 4, variableArgs: true, };\n t['SCN'] = { id: OPS.setStrokeColorN, numArgs: 33, variableArgs: true, };\n t['sc'] = { id: OPS.setFillColor, numArgs: 4, variableArgs: true, };\n t['scn'] = { id: OPS.setFillColorN, numArgs: 33, variableArgs: true, };\n t['G'] = { id: OPS.setStrokeGray, numArgs: 1, variableArgs: false, };\n t['g'] = { id: OPS.setFillGray, numArgs: 1, variableArgs: false, };\n t['RG'] = { id: OPS.setStrokeRGBColor, numArgs: 3, variableArgs: false, };\n t['rg'] = { id: OPS.setFillRGBColor, numArgs: 3, variableArgs: false, };\n t['K'] = { id: OPS.setStrokeCMYKColor, numArgs: 4, variableArgs: false, };\n t['k'] = { id: OPS.setFillCMYKColor, numArgs: 4, variableArgs: false, };\n\n // Shading\n t['sh'] = { id: OPS.shadingFill, numArgs: 1, variableArgs: false, };\n\n // Images\n t['BI'] = { id: OPS.beginInlineImage, numArgs: 0, variableArgs: false, };\n t['ID'] = { id: OPS.beginImageData, numArgs: 0, variableArgs: false, };\n t['EI'] = { id: OPS.endInlineImage, numArgs: 1, variableArgs: false, };\n\n // XObjects\n t['Do'] = { id: OPS.paintXObject, numArgs: 1, variableArgs: false, };\n t['MP'] = { id: OPS.markPoint, numArgs: 1, variableArgs: false, };\n t['DP'] = { id: OPS.markPointProps, numArgs: 2, variableArgs: false, };\n t['BMC'] = { id: OPS.beginMarkedContent, numArgs: 1, variableArgs: false, };\n t['BDC'] = { id: OPS.beginMarkedContentProps, numArgs: 2,\n variableArgs: false, };\n t['EMC'] = { id: OPS.endMarkedContent, numArgs: 0, variableArgs: false, };\n\n // Compatibility\n t['BX'] = { id: OPS.beginCompat, numArgs: 0, variableArgs: false, };\n t['EX'] = { id: OPS.endCompat, numArgs: 0, variableArgs: false, };\n\n // (reserved partial commands for the lexer)\n t['BM'] = null;\n t['BD'] = null;\n t['true'] = null;\n t['fa'] = null;\n t['fal'] = null;\n t['fals'] = null;\n t['false'] = null;\n t['nu'] = null;\n t['nul'] = null;\n t['null'] = null;\n });\n\n function EvaluatorPreprocessor(stream, xref, stateManager) {\n this.opMap = getOPMap();\n // TODO(mduan): pass array of knownCommands rather than this.opMap\n // dictionary\n this.parser = new Parser(new Lexer(stream, this.opMap), false, xref);\n this.stateManager = stateManager;\n this.nonProcessedArgs = [];\n }\n\n EvaluatorPreprocessor.prototype = {\n get savedStatesDepth() {\n return this.stateManager.stateStack.length;\n },\n\n // |operation| is an object with two fields:\n //\n // - |fn| is an out param.\n //\n // - |args| is an inout param. On entry, it should have one of two values.\n //\n // - An empty array. This indicates that the caller is providing the\n // array in which the args will be stored in. The caller should use\n // this value if it can reuse a single array for each call to read().\n //\n // - |null|. This indicates that the caller needs this function to create\n // the array in which any args are stored in. If there are zero args,\n // this function will leave |operation.args| as |null| (thus avoiding\n // allocations that would occur if we used an empty array to represent\n // zero arguments). Otherwise, it will replace |null| with a new array\n // containing the arguments. The caller should use this value if it\n // cannot reuse an array for each call to read().\n //\n // These two modes are present because this function is very hot and so\n // avoiding allocations where possible is worthwhile.\n //\n read: function EvaluatorPreprocessor_read(operation) {\n var args = operation.args;\n while (true) {\n var obj = this.parser.getObj();\n if (isCmd(obj)) {\n var cmd = obj.cmd;\n // Check that the command is valid\n var opSpec = this.opMap[cmd];\n if (!opSpec) {\n warn('Unknown command \"' + cmd + '\"');\n continue;\n }\n\n var fn = opSpec.id;\n var numArgs = opSpec.numArgs;\n var argsLength = args !== null ? args.length : 0;\n\n if (!opSpec.variableArgs) {\n // Postscript commands can be nested, e.g. /F2 /GS2 gs 5.711 Tf\n if (argsLength !== numArgs) {\n var nonProcessedArgs = this.nonProcessedArgs;\n while (argsLength > numArgs) {\n nonProcessedArgs.push(args.shift());\n argsLength--;\n }\n while (argsLength < numArgs && nonProcessedArgs.length !== 0) {\n if (args === null) {\n args = [];\n }\n args.unshift(nonProcessedArgs.pop());\n argsLength++;\n }\n }\n\n if (argsLength < numArgs) {\n // If we receive too few arguments, it's not possible to execute\n // the command, hence we skip the command.\n warn('Skipping command ' + fn + ': expected ' + numArgs +\n ' args, but received ' + argsLength + ' args.');\n if (args !== null) {\n args.length = 0;\n }\n continue;\n }\n } else if (argsLength > numArgs) {\n info('Command ' + fn + ': expected [0,' + numArgs +\n '] args, but received ' + argsLength + ' args.');\n }\n\n // TODO figure out how to type-check vararg functions\n this.preprocessCommand(fn, args);\n\n operation.fn = fn;\n operation.args = args;\n return true;\n }\n if (isEOF(obj)) {\n return false; // no more commands\n }\n // argument\n if (obj !== null) {\n if (args === null) {\n args = [];\n }\n args.push(obj);\n if (args.length > 33) {\n throw new FormatError('Too many arguments');\n }\n }\n }\n },\n\n preprocessCommand:\n function EvaluatorPreprocessor_preprocessCommand(fn, args) {\n switch (fn | 0) {\n case OPS.save:\n this.stateManager.save();\n break;\n case OPS.restore:\n this.stateManager.restore();\n break;\n case OPS.transform:\n this.stateManager.transform(args);\n break;\n }\n },\n };\n return EvaluatorPreprocessor;\n})();\n\nvar QueueOptimizer = (function QueueOptimizerClosure() {\n function addState(parentState, pattern, fn) {\n var state = parentState;\n for (var i = 0, ii = pattern.length - 1; i < ii; i++) {\n var item = pattern[i];\n state = (state[item] || (state[item] = []));\n }\n state[pattern[pattern.length - 1]] = fn;\n }\n\n function handlePaintSolidColorImageMask(iFirstSave, count, fnArray,\n argsArray) {\n // Handles special case of mainly LaTeX documents which use image masks to\n // draw lines with the current fill style.\n // 'count' groups of (save, transform, paintImageMaskXObject, restore)+\n // have been found at iFirstSave.\n var iFirstPIMXO = iFirstSave + 2;\n for (var i = 0; i < count; i++) {\n var arg = argsArray[iFirstPIMXO + 4 * i];\n var imageMask = arg.length === 1 && arg[0];\n if (imageMask && imageMask.width === 1 && imageMask.height === 1 &&\n (!imageMask.data.length ||\n (imageMask.data.length === 1 && imageMask.data[0] === 0))) {\n fnArray[iFirstPIMXO + 4 * i] = OPS.paintSolidColorImageMask;\n continue;\n }\n break;\n }\n return count - i;\n }\n\n var InitialState = [];\n\n // This replaces (save, transform, paintInlineImageXObject, restore)+\n // sequences with one |paintInlineImageXObjectGroup| operation.\n addState(InitialState,\n [OPS.save, OPS.transform, OPS.paintInlineImageXObject, OPS.restore],\n function foundInlineImageGroup(context) {\n var MIN_IMAGES_IN_INLINE_IMAGES_BLOCK = 10;\n var MAX_IMAGES_IN_INLINE_IMAGES_BLOCK = 200;\n var MAX_WIDTH = 1000;\n var IMAGE_PADDING = 1;\n\n var fnArray = context.fnArray, argsArray = context.argsArray;\n var curr = context.iCurr;\n var iFirstSave = curr - 3;\n var iFirstTransform = curr - 2;\n var iFirstPIIXO = curr - 1;\n\n // Look for the quartets.\n var i = iFirstSave + 4;\n var ii = fnArray.length;\n while (i + 3 < ii) {\n if (fnArray[i] !== OPS.save ||\n fnArray[i + 1] !== OPS.transform ||\n fnArray[i + 2] !== OPS.paintInlineImageXObject ||\n fnArray[i + 3] !== OPS.restore) {\n break; // ops don't match\n }\n i += 4;\n }\n\n // At this point, i is the index of the first op past the last valid\n // quartet.\n var count = Math.min((i - iFirstSave) / 4,\n MAX_IMAGES_IN_INLINE_IMAGES_BLOCK);\n if (count < MIN_IMAGES_IN_INLINE_IMAGES_BLOCK) {\n return i;\n }\n\n // assuming that heights of those image is too small (~1 pixel)\n // packing as much as possible by lines\n var maxX = 0;\n var map = [], maxLineHeight = 0;\n var currentX = IMAGE_PADDING, currentY = IMAGE_PADDING;\n var q;\n for (q = 0; q < count; q++) {\n var transform = argsArray[iFirstTransform + (q << 2)];\n var img = argsArray[iFirstPIIXO + (q << 2)][0];\n if (currentX + img.width > MAX_WIDTH) {\n // starting new line\n maxX = Math.max(maxX, currentX);\n currentY += maxLineHeight + 2 * IMAGE_PADDING;\n currentX = 0;\n maxLineHeight = 0;\n }\n map.push({\n transform,\n x: currentX, y: currentY,\n w: img.width, h: img.height,\n });\n currentX += img.width + 2 * IMAGE_PADDING;\n maxLineHeight = Math.max(maxLineHeight, img.height);\n }\n var imgWidth = Math.max(maxX, currentX) + IMAGE_PADDING;\n var imgHeight = currentY + maxLineHeight + IMAGE_PADDING;\n var imgData = new Uint8Array(imgWidth * imgHeight * 4);\n var imgRowSize = imgWidth << 2;\n for (q = 0; q < count; q++) {\n var data = argsArray[iFirstPIIXO + (q << 2)][0].data;\n // Copy image by lines and extends pixels into padding.\n var rowSize = map[q].w << 2;\n var dataOffset = 0;\n var offset = (map[q].x + map[q].y * imgWidth) << 2;\n imgData.set(data.subarray(0, rowSize), offset - imgRowSize);\n for (var k = 0, kk = map[q].h; k < kk; k++) {\n imgData.set(data.subarray(dataOffset, dataOffset + rowSize), offset);\n dataOffset += rowSize;\n offset += imgRowSize;\n }\n imgData.set(data.subarray(dataOffset - rowSize, dataOffset), offset);\n while (offset >= 0) {\n data[offset - 4] = data[offset];\n data[offset - 3] = data[offset + 1];\n data[offset - 2] = data[offset + 2];\n data[offset - 1] = data[offset + 3];\n data[offset + rowSize] = data[offset + rowSize - 4];\n data[offset + rowSize + 1] = data[offset + rowSize - 3];\n data[offset + rowSize + 2] = data[offset + rowSize - 2];\n data[offset + rowSize + 3] = data[offset + rowSize - 1];\n offset -= imgRowSize;\n }\n }\n\n // Replace queue items.\n fnArray.splice(iFirstSave, count * 4, OPS.paintInlineImageXObjectGroup);\n argsArray.splice(iFirstSave, count * 4,\n [{ width: imgWidth, height: imgHeight, kind: ImageKind.RGBA_32BPP,\n data: imgData, }, map]);\n\n return iFirstSave + 1;\n });\n\n // This replaces (save, transform, paintImageMaskXObject, restore)+\n // sequences with one |paintImageMaskXObjectGroup| or one\n // |paintImageMaskXObjectRepeat| operation.\n addState(InitialState,\n [OPS.save, OPS.transform, OPS.paintImageMaskXObject, OPS.restore],\n function foundImageMaskGroup(context) {\n var MIN_IMAGES_IN_MASKS_BLOCK = 10;\n var MAX_IMAGES_IN_MASKS_BLOCK = 100;\n var MAX_SAME_IMAGES_IN_MASKS_BLOCK = 1000;\n\n var fnArray = context.fnArray, argsArray = context.argsArray;\n var curr = context.iCurr;\n var iFirstSave = curr - 3;\n var iFirstTransform = curr - 2;\n var iFirstPIMXO = curr - 1;\n\n // Look for the quartets.\n var i = iFirstSave + 4;\n var ii = fnArray.length;\n while (i + 3 < ii) {\n if (fnArray[i] !== OPS.save ||\n fnArray[i + 1] !== OPS.transform ||\n fnArray[i + 2] !== OPS.paintImageMaskXObject ||\n fnArray[i + 3] !== OPS.restore) {\n break; // ops don't match\n }\n i += 4;\n }\n\n // At this point, i is the index of the first op past the last valid\n // quartet.\n var count = (i - iFirstSave) / 4;\n count = handlePaintSolidColorImageMask(iFirstSave, count, fnArray,\n argsArray);\n if (count < MIN_IMAGES_IN_MASKS_BLOCK) {\n return i;\n }\n\n var q;\n var isSameImage = false;\n var iTransform, transformArgs;\n var firstPIMXOArg0 = argsArray[iFirstPIMXO][0];\n if (argsArray[iFirstTransform][1] === 0 &&\n argsArray[iFirstTransform][2] === 0) {\n isSameImage = true;\n var firstTransformArg0 = argsArray[iFirstTransform][0];\n var firstTransformArg3 = argsArray[iFirstTransform][3];\n iTransform = iFirstTransform + 4;\n var iPIMXO = iFirstPIMXO + 4;\n for (q = 1; q < count; q++, iTransform += 4, iPIMXO += 4) {\n transformArgs = argsArray[iTransform];\n if (argsArray[iPIMXO][0] !== firstPIMXOArg0 ||\n transformArgs[0] !== firstTransformArg0 ||\n transformArgs[1] !== 0 ||\n transformArgs[2] !== 0 ||\n transformArgs[3] !== firstTransformArg3) {\n if (q < MIN_IMAGES_IN_MASKS_BLOCK) {\n isSameImage = false;\n } else {\n count = q;\n }\n break; // different image or transform\n }\n }\n }\n\n if (isSameImage) {\n count = Math.min(count, MAX_SAME_IMAGES_IN_MASKS_BLOCK);\n var positions = new Float32Array(count * 2);\n iTransform = iFirstTransform;\n for (q = 0; q < count; q++, iTransform += 4) {\n transformArgs = argsArray[iTransform];\n positions[(q << 1)] = transformArgs[4];\n positions[(q << 1) + 1] = transformArgs[5];\n }\n\n // Replace queue items.\n fnArray.splice(iFirstSave, count * 4, OPS.paintImageMaskXObjectRepeat);\n argsArray.splice(iFirstSave, count * 4,\n [firstPIMXOArg0, firstTransformArg0, firstTransformArg3, positions]);\n } else {\n count = Math.min(count, MAX_IMAGES_IN_MASKS_BLOCK);\n var images = [];\n for (q = 0; q < count; q++) {\n transformArgs = argsArray[iFirstTransform + (q << 2)];\n var maskParams = argsArray[iFirstPIMXO + (q << 2)][0];\n images.push({ data: maskParams.data, width: maskParams.width,\n height: maskParams.height,\n transform: transformArgs, });\n }\n\n // Replace queue items.\n fnArray.splice(iFirstSave, count * 4, OPS.paintImageMaskXObjectGroup);\n argsArray.splice(iFirstSave, count * 4, [images]);\n }\n\n return iFirstSave + 1;\n });\n\n // This replaces (save, transform, paintImageXObject, restore)+ sequences\n // with one paintImageXObjectRepeat operation, if the |transform| and\n // |paintImageXObjectRepeat| ops are appropriate.\n addState(InitialState,\n [OPS.save, OPS.transform, OPS.paintImageXObject, OPS.restore],\n function (context) {\n var MIN_IMAGES_IN_BLOCK = 3;\n var MAX_IMAGES_IN_BLOCK = 1000;\n\n var fnArray = context.fnArray, argsArray = context.argsArray;\n var curr = context.iCurr;\n var iFirstSave = curr - 3;\n var iFirstTransform = curr - 2;\n var iFirstPIXO = curr - 1;\n var iFirstRestore = curr;\n\n if (argsArray[iFirstTransform][1] !== 0 ||\n argsArray[iFirstTransform][2] !== 0) {\n return iFirstRestore + 1; // transform has the wrong form\n }\n\n // Look for the quartets.\n var firstPIXOArg0 = argsArray[iFirstPIXO][0];\n var firstTransformArg0 = argsArray[iFirstTransform][0];\n var firstTransformArg3 = argsArray[iFirstTransform][3];\n var i = iFirstSave + 4;\n var ii = fnArray.length;\n while (i + 3 < ii) {\n if (fnArray[i] !== OPS.save ||\n fnArray[i + 1] !== OPS.transform ||\n fnArray[i + 2] !== OPS.paintImageXObject ||\n fnArray[i + 3] !== OPS.restore) {\n break; // ops don't match\n }\n if (argsArray[i + 1][0] !== firstTransformArg0 ||\n argsArray[i + 1][1] !== 0 ||\n argsArray[i + 1][2] !== 0 ||\n argsArray[i + 1][3] !== firstTransformArg3) {\n break; // transforms don't match\n }\n if (argsArray[i + 2][0] !== firstPIXOArg0) {\n break; // images don't match\n }\n i += 4;\n }\n\n // At this point, i is the index of the first op past the last valid\n // quartet.\n var count = Math.min((i - iFirstSave) / 4, MAX_IMAGES_IN_BLOCK);\n if (count < MIN_IMAGES_IN_BLOCK) {\n return i;\n }\n\n // Extract the (x,y) positions from all of the matching transforms.\n var positions = new Float32Array(count * 2);\n var iTransform = iFirstTransform;\n for (var q = 0; q < count; q++, iTransform += 4) {\n var transformArgs = argsArray[iTransform];\n positions[(q << 1)] = transformArgs[4];\n positions[(q << 1) + 1] = transformArgs[5];\n }\n\n // Replace queue items.\n var args = [firstPIXOArg0, firstTransformArg0, firstTransformArg3,\n positions];\n fnArray.splice(iFirstSave, count * 4, OPS.paintImageXObjectRepeat);\n argsArray.splice(iFirstSave, count * 4, args);\n\n return iFirstSave + 1;\n });\n\n // This replaces (beginText, setFont, setTextMatrix, showText, endText)+\n // sequences with (beginText, setFont, (setTextMatrix, showText)+, endText)+\n // sequences, if the font for each one is the same.\n addState(InitialState,\n [OPS.beginText, OPS.setFont, OPS.setTextMatrix, OPS.showText, OPS.endText],\n function (context) {\n var MIN_CHARS_IN_BLOCK = 3;\n var MAX_CHARS_IN_BLOCK = 1000;\n\n var fnArray = context.fnArray, argsArray = context.argsArray;\n var curr = context.iCurr;\n var iFirstBeginText = curr - 4;\n var iFirstSetFont = curr - 3;\n var iFirstSetTextMatrix = curr - 2;\n var iFirstShowText = curr - 1;\n var iFirstEndText = curr;\n\n // Look for the quintets.\n var firstSetFontArg0 = argsArray[iFirstSetFont][0];\n var firstSetFontArg1 = argsArray[iFirstSetFont][1];\n var i = iFirstBeginText + 5;\n var ii = fnArray.length;\n while (i + 4 < ii) {\n if (fnArray[i] !== OPS.beginText ||\n fnArray[i + 1] !== OPS.setFont ||\n fnArray[i + 2] !== OPS.setTextMatrix ||\n fnArray[i + 3] !== OPS.showText ||\n fnArray[i + 4] !== OPS.endText) {\n break; // ops don't match\n }\n if (argsArray[i + 1][0] !== firstSetFontArg0 ||\n argsArray[i + 1][1] !== firstSetFontArg1) {\n break; // fonts don't match\n }\n i += 5;\n }\n\n // At this point, i is the index of the first op past the last valid\n // quintet.\n var count = Math.min(((i - iFirstBeginText) / 5), MAX_CHARS_IN_BLOCK);\n if (count < MIN_CHARS_IN_BLOCK) {\n return i;\n }\n\n // If the preceding quintet is (, setFont, setTextMatrix,\n // showText, endText), include that as well. (E.g. might be\n // |dependency|.)\n var iFirst = iFirstBeginText;\n if (iFirstBeginText >= 4 &&\n fnArray[iFirstBeginText - 4] === fnArray[iFirstSetFont] &&\n fnArray[iFirstBeginText - 3] === fnArray[iFirstSetTextMatrix] &&\n fnArray[iFirstBeginText - 2] === fnArray[iFirstShowText] &&\n fnArray[iFirstBeginText - 1] === fnArray[iFirstEndText] &&\n argsArray[iFirstBeginText - 4][0] === firstSetFontArg0 &&\n argsArray[iFirstBeginText - 4][1] === firstSetFontArg1) {\n count++;\n iFirst -= 5;\n }\n\n // Remove (endText, beginText, setFont) trios.\n var iEndText = iFirst + 4;\n for (var q = 1; q < count; q++) {\n fnArray.splice(iEndText, 3);\n argsArray.splice(iEndText, 3);\n iEndText += 2;\n }\n\n return iEndText + 1;\n });\n\n function QueueOptimizer() {}\n\n QueueOptimizer.prototype = {\n optimize: function QueueOptimizer_optimize(queue) {\n var fnArray = queue.fnArray, argsArray = queue.argsArray;\n var context = {\n iCurr: 0,\n fnArray,\n argsArray,\n };\n var state;\n var i = 0, ii = fnArray.length;\n while (i < ii) {\n state = (state || InitialState)[fnArray[i]];\n if (typeof state === 'function') { // we found some handler\n context.iCurr = i;\n // state() returns the index of the first non-matching op (if we\n // didn't match) or the first op past the modified ops (if we did\n // match and replace).\n i = state(context);\n state = undefined; // reset the state machine\n ii = context.fnArray.length;\n } else {\n i++;\n }\n }\n },\n };\n return QueueOptimizer;\n})();\n\nexport {\n OperatorList,\n PartialEvaluator,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/evaluator.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n info, log2, readUint16, readUint32, warn\n} from '../shared/util';\nimport { ArithmeticDecoder } from './arithmetic_decoder';\n\nlet JpxError = (function JpxErrorClosure() {\n function JpxError(msg) {\n this.message = 'JPX error: ' + msg;\n }\n\n JpxError.prototype = new Error();\n JpxError.prototype.name = 'JpxError';\n JpxError.constructor = JpxError;\n\n return JpxError;\n})();\n\nvar JpxImage = (function JpxImageClosure() {\n // Table E.1\n var SubbandsGainLog2 = {\n 'LL': 0,\n 'LH': 1,\n 'HL': 1,\n 'HH': 2,\n };\n function JpxImage() {\n this.failOnCorruptedImage = false;\n }\n JpxImage.prototype = {\n parse: function JpxImage_parse(data) {\n\n var head = readUint16(data, 0);\n // No box header, immediate start of codestream (SOC)\n if (head === 0xFF4F) {\n this.parseCodestream(data, 0, data.length);\n return;\n }\n\n var position = 0, length = data.length;\n while (position < length) {\n var headerSize = 8;\n var lbox = readUint32(data, position);\n var tbox = readUint32(data, position + 4);\n position += headerSize;\n if (lbox === 1) {\n // XLBox: read UInt64 according to spec.\n // JavaScript's int precision of 53 bit should be sufficient here.\n lbox = readUint32(data, position) * 4294967296 +\n readUint32(data, position + 4);\n position += 8;\n headerSize += 8;\n }\n if (lbox === 0) {\n lbox = length - position + headerSize;\n }\n if (lbox < headerSize) {\n throw new JpxError('Invalid box field size');\n }\n var dataLength = lbox - headerSize;\n var jumpDataLength = true;\n switch (tbox) {\n case 0x6A703268: // 'jp2h'\n jumpDataLength = false; // parsing child boxes\n break;\n case 0x636F6C72: // 'colr'\n // Colorspaces are not used, the CS from the PDF is used.\n var method = data[position];\n if (method === 1) {\n // enumerated colorspace\n var colorspace = readUint32(data, position + 3);\n switch (colorspace) {\n case 16: // this indicates a sRGB colorspace\n case 17: // this indicates a grayscale colorspace\n case 18: // this indicates a YUV colorspace\n break;\n default:\n warn('Unknown colorspace ' + colorspace);\n break;\n }\n } else if (method === 2) {\n info('ICC profile not supported');\n }\n break;\n case 0x6A703263: // 'jp2c'\n this.parseCodestream(data, position, position + dataLength);\n break;\n case 0x6A502020: // 'jP\\024\\024'\n if (readUint32(data, position) !== 0x0d0a870a) {\n warn('Invalid JP2 signature');\n }\n break;\n // The following header types are valid but currently not used:\n case 0x6A501A1A: // 'jP\\032\\032'\n case 0x66747970: // 'ftyp'\n case 0x72726571: // 'rreq'\n case 0x72657320: // 'res '\n case 0x69686472: // 'ihdr'\n break;\n default:\n var headerType = String.fromCharCode((tbox >> 24) & 0xFF,\n (tbox >> 16) & 0xFF,\n (tbox >> 8) & 0xFF,\n tbox & 0xFF);\n warn('Unsupported header type ' + tbox + ' (' + headerType + ')');\n break;\n }\n if (jumpDataLength) {\n position += dataLength;\n }\n }\n },\n parseImageProperties: function JpxImage_parseImageProperties(stream) {\n var newByte = stream.getByte();\n while (newByte >= 0) {\n var oldByte = newByte;\n newByte = stream.getByte();\n var code = (oldByte << 8) | newByte;\n // Image and tile size (SIZ)\n if (code === 0xFF51) {\n stream.skip(4);\n var Xsiz = stream.getInt32() >>> 0; // Byte 4\n var Ysiz = stream.getInt32() >>> 0; // Byte 8\n var XOsiz = stream.getInt32() >>> 0; // Byte 12\n var YOsiz = stream.getInt32() >>> 0; // Byte 16\n stream.skip(16);\n var Csiz = stream.getUint16(); // Byte 36\n this.width = Xsiz - XOsiz;\n this.height = Ysiz - YOsiz;\n this.componentsCount = Csiz;\n // Results are always returned as Uint8Arrays\n this.bitsPerComponent = 8;\n return;\n }\n }\n throw new JpxError('No size marker found in JPX stream');\n },\n parseCodestream: function JpxImage_parseCodestream(data, start, end) {\n var context = {};\n var doNotRecover = false;\n try {\n var position = start;\n while (position + 1 < end) {\n var code = readUint16(data, position);\n position += 2;\n\n var length = 0, j, sqcd, spqcds, spqcdSize, scalarExpounded, tile;\n switch (code) {\n case 0xFF4F: // Start of codestream (SOC)\n context.mainHeader = true;\n break;\n case 0xFFD9: // End of codestream (EOC)\n break;\n case 0xFF51: // Image and tile size (SIZ)\n length = readUint16(data, position);\n var siz = {};\n siz.Xsiz = readUint32(data, position + 4);\n siz.Ysiz = readUint32(data, position + 8);\n siz.XOsiz = readUint32(data, position + 12);\n siz.YOsiz = readUint32(data, position + 16);\n siz.XTsiz = readUint32(data, position + 20);\n siz.YTsiz = readUint32(data, position + 24);\n siz.XTOsiz = readUint32(data, position + 28);\n siz.YTOsiz = readUint32(data, position + 32);\n var componentsCount = readUint16(data, position + 36);\n siz.Csiz = componentsCount;\n var components = [];\n j = position + 38;\n for (var i = 0; i < componentsCount; i++) {\n var component = {\n precision: (data[j] & 0x7F) + 1,\n isSigned: !!(data[j] & 0x80),\n XRsiz: data[j + 1],\n YRsiz: data[j + 1],\n };\n calculateComponentDimensions(component, siz);\n components.push(component);\n }\n context.SIZ = siz;\n context.components = components;\n calculateTileGrids(context, components);\n context.QCC = [];\n context.COC = [];\n break;\n case 0xFF5C: // Quantization default (QCD)\n length = readUint16(data, position);\n var qcd = {};\n j = position + 2;\n sqcd = data[j++];\n switch (sqcd & 0x1F) {\n case 0:\n spqcdSize = 8;\n scalarExpounded = true;\n break;\n case 1:\n spqcdSize = 16;\n scalarExpounded = false;\n break;\n case 2:\n spqcdSize = 16;\n scalarExpounded = true;\n break;\n default:\n throw new Error('Invalid SQcd value ' + sqcd);\n }\n qcd.noQuantization = (spqcdSize === 8);\n qcd.scalarExpounded = scalarExpounded;\n qcd.guardBits = sqcd >> 5;\n spqcds = [];\n while (j < length + position) {\n var spqcd = {};\n if (spqcdSize === 8) {\n spqcd.epsilon = data[j++] >> 3;\n spqcd.mu = 0;\n } else {\n spqcd.epsilon = data[j] >> 3;\n spqcd.mu = ((data[j] & 0x7) << 8) | data[j + 1];\n j += 2;\n }\n spqcds.push(spqcd);\n }\n qcd.SPqcds = spqcds;\n if (context.mainHeader) {\n context.QCD = qcd;\n } else {\n context.currentTile.QCD = qcd;\n context.currentTile.QCC = [];\n }\n break;\n case 0xFF5D: // Quantization component (QCC)\n length = readUint16(data, position);\n var qcc = {};\n j = position + 2;\n var cqcc;\n if (context.SIZ.Csiz < 257) {\n cqcc = data[j++];\n } else {\n cqcc = readUint16(data, j);\n j += 2;\n }\n sqcd = data[j++];\n switch (sqcd & 0x1F) {\n case 0:\n spqcdSize = 8;\n scalarExpounded = true;\n break;\n case 1:\n spqcdSize = 16;\n scalarExpounded = false;\n break;\n case 2:\n spqcdSize = 16;\n scalarExpounded = true;\n break;\n default:\n throw new Error('Invalid SQcd value ' + sqcd);\n }\n qcc.noQuantization = (spqcdSize === 8);\n qcc.scalarExpounded = scalarExpounded;\n qcc.guardBits = sqcd >> 5;\n spqcds = [];\n while (j < (length + position)) {\n spqcd = {};\n if (spqcdSize === 8) {\n spqcd.epsilon = data[j++] >> 3;\n spqcd.mu = 0;\n } else {\n spqcd.epsilon = data[j] >> 3;\n spqcd.mu = ((data[j] & 0x7) << 8) | data[j + 1];\n j += 2;\n }\n spqcds.push(spqcd);\n }\n qcc.SPqcds = spqcds;\n if (context.mainHeader) {\n context.QCC[cqcc] = qcc;\n } else {\n context.currentTile.QCC[cqcc] = qcc;\n }\n break;\n case 0xFF52: // Coding style default (COD)\n length = readUint16(data, position);\n var cod = {};\n j = position + 2;\n var scod = data[j++];\n cod.entropyCoderWithCustomPrecincts = !!(scod & 1);\n cod.sopMarkerUsed = !!(scod & 2);\n cod.ephMarkerUsed = !!(scod & 4);\n cod.progressionOrder = data[j++];\n cod.layersCount = readUint16(data, j);\n j += 2;\n cod.multipleComponentTransform = data[j++];\n\n cod.decompositionLevelsCount = data[j++];\n cod.xcb = (data[j++] & 0xF) + 2;\n cod.ycb = (data[j++] & 0xF) + 2;\n var blockStyle = data[j++];\n cod.selectiveArithmeticCodingBypass = !!(blockStyle & 1);\n cod.resetContextProbabilities = !!(blockStyle & 2);\n cod.terminationOnEachCodingPass = !!(blockStyle & 4);\n cod.verticalyStripe = !!(blockStyle & 8);\n cod.predictableTermination = !!(blockStyle & 16);\n cod.segmentationSymbolUsed = !!(blockStyle & 32);\n cod.reversibleTransformation = data[j++];\n if (cod.entropyCoderWithCustomPrecincts) {\n var precinctsSizes = [];\n while (j < length + position) {\n var precinctsSize = data[j++];\n precinctsSizes.push({\n PPx: precinctsSize & 0xF,\n PPy: precinctsSize >> 4,\n });\n }\n cod.precinctsSizes = precinctsSizes;\n }\n var unsupported = [];\n if (cod.selectiveArithmeticCodingBypass) {\n unsupported.push('selectiveArithmeticCodingBypass');\n }\n if (cod.resetContextProbabilities) {\n unsupported.push('resetContextProbabilities');\n }\n if (cod.terminationOnEachCodingPass) {\n unsupported.push('terminationOnEachCodingPass');\n }\n if (cod.verticalyStripe) {\n unsupported.push('verticalyStripe');\n }\n if (cod.predictableTermination) {\n unsupported.push('predictableTermination');\n }\n if (unsupported.length > 0) {\n doNotRecover = true;\n throw new Error('Unsupported COD options (' +\n unsupported.join(', ') + ')');\n }\n if (context.mainHeader) {\n context.COD = cod;\n } else {\n context.currentTile.COD = cod;\n context.currentTile.COC = [];\n }\n break;\n case 0xFF90: // Start of tile-part (SOT)\n length = readUint16(data, position);\n tile = {};\n tile.index = readUint16(data, position + 2);\n tile.length = readUint32(data, position + 4);\n tile.dataEnd = tile.length + position - 2;\n tile.partIndex = data[position + 8];\n tile.partsCount = data[position + 9];\n\n context.mainHeader = false;\n if (tile.partIndex === 0) {\n // reset component specific settings\n tile.COD = context.COD;\n tile.COC = context.COC.slice(0); // clone of the global COC\n tile.QCD = context.QCD;\n tile.QCC = context.QCC.slice(0); // clone of the global COC\n }\n context.currentTile = tile;\n break;\n case 0xFF93: // Start of data (SOD)\n tile = context.currentTile;\n if (tile.partIndex === 0) {\n initializeTile(context, tile.index);\n buildPackets(context);\n }\n\n // moving to the end of the data\n length = tile.dataEnd - position;\n parseTilePackets(context, data, position, length);\n break;\n case 0xFF55: // Tile-part lengths, main header (TLM)\n case 0xFF57: // Packet length, main header (PLM)\n case 0xFF58: // Packet length, tile-part header (PLT)\n case 0xFF64: // Comment (COM)\n length = readUint16(data, position);\n // skipping content\n break;\n case 0xFF53: // Coding style component (COC)\n throw new Error('Codestream code 0xFF53 (COC) is ' +\n 'not implemented');\n default:\n throw new Error('Unknown codestream code: ' + code.toString(16));\n }\n position += length;\n }\n } catch (e) {\n if (doNotRecover || this.failOnCorruptedImage) {\n throw new JpxError(e.message);\n } else {\n warn('JPX: Trying to recover from: ' + e.message);\n }\n }\n this.tiles = transformComponents(context);\n this.width = context.SIZ.Xsiz - context.SIZ.XOsiz;\n this.height = context.SIZ.Ysiz - context.SIZ.YOsiz;\n this.componentsCount = context.SIZ.Csiz;\n },\n };\n function calculateComponentDimensions(component, siz) {\n // Section B.2 Component mapping\n component.x0 = Math.ceil(siz.XOsiz / component.XRsiz);\n component.x1 = Math.ceil(siz.Xsiz / component.XRsiz);\n component.y0 = Math.ceil(siz.YOsiz / component.YRsiz);\n component.y1 = Math.ceil(siz.Ysiz / component.YRsiz);\n component.width = component.x1 - component.x0;\n component.height = component.y1 - component.y0;\n }\n function calculateTileGrids(context, components) {\n var siz = context.SIZ;\n // Section B.3 Division into tile and tile-components\n var tile, tiles = [];\n var numXtiles = Math.ceil((siz.Xsiz - siz.XTOsiz) / siz.XTsiz);\n var numYtiles = Math.ceil((siz.Ysiz - siz.YTOsiz) / siz.YTsiz);\n for (var q = 0; q < numYtiles; q++) {\n for (var p = 0; p < numXtiles; p++) {\n tile = {};\n tile.tx0 = Math.max(siz.XTOsiz + p * siz.XTsiz, siz.XOsiz);\n tile.ty0 = Math.max(siz.YTOsiz + q * siz.YTsiz, siz.YOsiz);\n tile.tx1 = Math.min(siz.XTOsiz + (p + 1) * siz.XTsiz, siz.Xsiz);\n tile.ty1 = Math.min(siz.YTOsiz + (q + 1) * siz.YTsiz, siz.Ysiz);\n tile.width = tile.tx1 - tile.tx0;\n tile.height = tile.ty1 - tile.ty0;\n tile.components = [];\n tiles.push(tile);\n }\n }\n context.tiles = tiles;\n\n var componentsCount = siz.Csiz;\n for (var i = 0, ii = componentsCount; i < ii; i++) {\n var component = components[i];\n for (var j = 0, jj = tiles.length; j < jj; j++) {\n var tileComponent = {};\n tile = tiles[j];\n tileComponent.tcx0 = Math.ceil(tile.tx0 / component.XRsiz);\n tileComponent.tcy0 = Math.ceil(tile.ty0 / component.YRsiz);\n tileComponent.tcx1 = Math.ceil(tile.tx1 / component.XRsiz);\n tileComponent.tcy1 = Math.ceil(tile.ty1 / component.YRsiz);\n tileComponent.width = tileComponent.tcx1 - tileComponent.tcx0;\n tileComponent.height = tileComponent.tcy1 - tileComponent.tcy0;\n tile.components[i] = tileComponent;\n }\n }\n }\n function getBlocksDimensions(context, component, r) {\n var codOrCoc = component.codingStyleParameters;\n var result = {};\n if (!codOrCoc.entropyCoderWithCustomPrecincts) {\n result.PPx = 15;\n result.PPy = 15;\n } else {\n result.PPx = codOrCoc.precinctsSizes[r].PPx;\n result.PPy = codOrCoc.precinctsSizes[r].PPy;\n }\n // calculate codeblock size as described in section B.7\n result.xcb_ = (r > 0 ? Math.min(codOrCoc.xcb, result.PPx - 1) :\n Math.min(codOrCoc.xcb, result.PPx));\n result.ycb_ = (r > 0 ? Math.min(codOrCoc.ycb, result.PPy - 1) :\n Math.min(codOrCoc.ycb, result.PPy));\n return result;\n }\n function buildPrecincts(context, resolution, dimensions) {\n // Section B.6 Division resolution to precincts\n var precinctWidth = 1 << dimensions.PPx;\n var precinctHeight = 1 << dimensions.PPy;\n // Jasper introduces codeblock groups for mapping each subband codeblocks\n // to precincts. Precinct partition divides a resolution according to width\n // and height parameters. The subband that belongs to the resolution level\n // has a different size than the level, unless it is the zero resolution.\n\n // From Jasper documentation: jpeg2000.pdf, section K: Tier-2 coding:\n // The precinct partitioning for a particular subband is derived from a\n // partitioning of its parent LL band (i.e., the LL band at the next higher\n // resolution level)... The LL band associated with each resolution level is\n // divided into precincts... Each of the resulting precinct regions is then\n // mapped into its child subbands (if any) at the next lower resolution\n // level. This is accomplished by using the coordinate transformation\n // (u, v) = (ceil(x/2), ceil(y/2)) where (x, y) and (u, v) are the\n // coordinates of a point in the LL band and child subband, respectively.\n var isZeroRes = resolution.resLevel === 0;\n var precinctWidthInSubband = 1 << (dimensions.PPx + (isZeroRes ? 0 : -1));\n var precinctHeightInSubband = 1 << (dimensions.PPy + (isZeroRes ? 0 : -1));\n var numprecinctswide = (resolution.trx1 > resolution.trx0 ?\n Math.ceil(resolution.trx1 / precinctWidth) -\n Math.floor(resolution.trx0 / precinctWidth) : 0);\n var numprecinctshigh = (resolution.try1 > resolution.try0 ?\n Math.ceil(resolution.try1 / precinctHeight) -\n Math.floor(resolution.try0 / precinctHeight) : 0);\n var numprecincts = numprecinctswide * numprecinctshigh;\n\n resolution.precinctParameters = {\n precinctWidth,\n precinctHeight,\n numprecinctswide,\n numprecinctshigh,\n numprecincts,\n precinctWidthInSubband,\n precinctHeightInSubband,\n };\n }\n function buildCodeblocks(context, subband, dimensions) {\n // Section B.7 Division sub-band into code-blocks\n var xcb_ = dimensions.xcb_;\n var ycb_ = dimensions.ycb_;\n var codeblockWidth = 1 << xcb_;\n var codeblockHeight = 1 << ycb_;\n var cbx0 = subband.tbx0 >> xcb_;\n var cby0 = subband.tby0 >> ycb_;\n var cbx1 = (subband.tbx1 + codeblockWidth - 1) >> xcb_;\n var cby1 = (subband.tby1 + codeblockHeight - 1) >> ycb_;\n var precinctParameters = subband.resolution.precinctParameters;\n var codeblocks = [];\n var precincts = [];\n var i, j, codeblock, precinctNumber;\n for (j = cby0; j < cby1; j++) {\n for (i = cbx0; i < cbx1; i++) {\n codeblock = {\n cbx: i,\n cby: j,\n tbx0: codeblockWidth * i,\n tby0: codeblockHeight * j,\n tbx1: codeblockWidth * (i + 1),\n tby1: codeblockHeight * (j + 1),\n };\n\n codeblock.tbx0_ = Math.max(subband.tbx0, codeblock.tbx0);\n codeblock.tby0_ = Math.max(subband.tby0, codeblock.tby0);\n codeblock.tbx1_ = Math.min(subband.tbx1, codeblock.tbx1);\n codeblock.tby1_ = Math.min(subband.tby1, codeblock.tby1);\n\n // Calculate precinct number for this codeblock, codeblock position\n // should be relative to its subband, use actual dimension and position\n // See comment about codeblock group width and height\n var pi = Math.floor((codeblock.tbx0_ - subband.tbx0) /\n precinctParameters.precinctWidthInSubband);\n var pj = Math.floor((codeblock.tby0_ - subband.tby0) /\n precinctParameters.precinctHeightInSubband);\n precinctNumber = pi + (pj * precinctParameters.numprecinctswide);\n\n codeblock.precinctNumber = precinctNumber;\n codeblock.subbandType = subband.type;\n codeblock.Lblock = 3;\n\n if (codeblock.tbx1_ <= codeblock.tbx0_ ||\n codeblock.tby1_ <= codeblock.tby0_) {\n continue;\n }\n codeblocks.push(codeblock);\n // building precinct for the sub-band\n var precinct = precincts[precinctNumber];\n if (precinct !== undefined) {\n if (i < precinct.cbxMin) {\n precinct.cbxMin = i;\n } else if (i > precinct.cbxMax) {\n precinct.cbxMax = i;\n }\n if (j < precinct.cbyMin) {\n precinct.cbxMin = j;\n } else if (j > precinct.cbyMax) {\n precinct.cbyMax = j;\n }\n } else {\n precincts[precinctNumber] = precinct = {\n cbxMin: i,\n cbyMin: j,\n cbxMax: i,\n cbyMax: j,\n };\n }\n codeblock.precinct = precinct;\n }\n }\n subband.codeblockParameters = {\n codeblockWidth: xcb_,\n codeblockHeight: ycb_,\n numcodeblockwide: cbx1 - cbx0 + 1,\n numcodeblockhigh: cby1 - cby0 + 1,\n };\n subband.codeblocks = codeblocks;\n subband.precincts = precincts;\n }\n function createPacket(resolution, precinctNumber, layerNumber) {\n var precinctCodeblocks = [];\n // Section B.10.8 Order of info in packet\n var subbands = resolution.subbands;\n // sub-bands already ordered in 'LL', 'HL', 'LH', and 'HH' sequence\n for (var i = 0, ii = subbands.length; i < ii; i++) {\n var subband = subbands[i];\n var codeblocks = subband.codeblocks;\n for (var j = 0, jj = codeblocks.length; j < jj; j++) {\n var codeblock = codeblocks[j];\n if (codeblock.precinctNumber !== precinctNumber) {\n continue;\n }\n precinctCodeblocks.push(codeblock);\n }\n }\n return {\n layerNumber,\n codeblocks: precinctCodeblocks,\n };\n }\n function LayerResolutionComponentPositionIterator(context) {\n var siz = context.SIZ;\n var tileIndex = context.currentTile.index;\n var tile = context.tiles[tileIndex];\n var layersCount = tile.codingStyleDefaultParameters.layersCount;\n var componentsCount = siz.Csiz;\n var maxDecompositionLevelsCount = 0;\n for (var q = 0; q < componentsCount; q++) {\n maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount,\n tile.components[q].codingStyleParameters.decompositionLevelsCount);\n }\n\n var l = 0, r = 0, i = 0, k = 0;\n\n this.nextPacket = function JpxImage_nextPacket() {\n // Section B.12.1.1 Layer-resolution-component-position\n for (; l < layersCount; l++) {\n for (; r <= maxDecompositionLevelsCount; r++) {\n for (; i < componentsCount; i++) {\n var component = tile.components[i];\n if (r > component.codingStyleParameters.decompositionLevelsCount) {\n continue;\n }\n\n var resolution = component.resolutions[r];\n var numprecincts = resolution.precinctParameters.numprecincts;\n for (; k < numprecincts;) {\n var packet = createPacket(resolution, k, l);\n k++;\n return packet;\n }\n k = 0;\n }\n i = 0;\n }\n r = 0;\n }\n throw new JpxError('Out of packets');\n };\n }\n function ResolutionLayerComponentPositionIterator(context) {\n var siz = context.SIZ;\n var tileIndex = context.currentTile.index;\n var tile = context.tiles[tileIndex];\n var layersCount = tile.codingStyleDefaultParameters.layersCount;\n var componentsCount = siz.Csiz;\n var maxDecompositionLevelsCount = 0;\n for (var q = 0; q < componentsCount; q++) {\n maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount,\n tile.components[q].codingStyleParameters.decompositionLevelsCount);\n }\n\n var r = 0, l = 0, i = 0, k = 0;\n\n this.nextPacket = function JpxImage_nextPacket() {\n // Section B.12.1.2 Resolution-layer-component-position\n for (; r <= maxDecompositionLevelsCount; r++) {\n for (; l < layersCount; l++) {\n for (; i < componentsCount; i++) {\n var component = tile.components[i];\n if (r > component.codingStyleParameters.decompositionLevelsCount) {\n continue;\n }\n\n var resolution = component.resolutions[r];\n var numprecincts = resolution.precinctParameters.numprecincts;\n for (; k < numprecincts;) {\n var packet = createPacket(resolution, k, l);\n k++;\n return packet;\n }\n k = 0;\n }\n i = 0;\n }\n l = 0;\n }\n throw new JpxError('Out of packets');\n };\n }\n function ResolutionPositionComponentLayerIterator(context) {\n var siz = context.SIZ;\n var tileIndex = context.currentTile.index;\n var tile = context.tiles[tileIndex];\n var layersCount = tile.codingStyleDefaultParameters.layersCount;\n var componentsCount = siz.Csiz;\n var l, r, c, p;\n var maxDecompositionLevelsCount = 0;\n for (c = 0; c < componentsCount; c++) {\n var component = tile.components[c];\n maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount,\n component.codingStyleParameters.decompositionLevelsCount);\n }\n var maxNumPrecinctsInLevel = new Int32Array(\n maxDecompositionLevelsCount + 1);\n for (r = 0; r <= maxDecompositionLevelsCount; ++r) {\n var maxNumPrecincts = 0;\n for (c = 0; c < componentsCount; ++c) {\n var resolutions = tile.components[c].resolutions;\n if (r < resolutions.length) {\n maxNumPrecincts = Math.max(maxNumPrecincts,\n resolutions[r].precinctParameters.numprecincts);\n }\n }\n maxNumPrecinctsInLevel[r] = maxNumPrecincts;\n }\n l = 0;\n r = 0;\n c = 0;\n p = 0;\n\n this.nextPacket = function JpxImage_nextPacket() {\n // Section B.12.1.3 Resolution-position-component-layer\n for (; r <= maxDecompositionLevelsCount; r++) {\n for (; p < maxNumPrecinctsInLevel[r]; p++) {\n for (; c < componentsCount; c++) {\n var component = tile.components[c];\n if (r > component.codingStyleParameters.decompositionLevelsCount) {\n continue;\n }\n var resolution = component.resolutions[r];\n var numprecincts = resolution.precinctParameters.numprecincts;\n if (p >= numprecincts) {\n continue;\n }\n for (; l < layersCount;) {\n var packet = createPacket(resolution, p, l);\n l++;\n return packet;\n }\n l = 0;\n }\n c = 0;\n }\n p = 0;\n }\n throw new JpxError('Out of packets');\n };\n }\n function PositionComponentResolutionLayerIterator(context) {\n var siz = context.SIZ;\n var tileIndex = context.currentTile.index;\n var tile = context.tiles[tileIndex];\n var layersCount = tile.codingStyleDefaultParameters.layersCount;\n var componentsCount = siz.Csiz;\n var precinctsSizes = getPrecinctSizesInImageScale(tile);\n var precinctsIterationSizes = precinctsSizes;\n var l = 0, r = 0, c = 0, px = 0, py = 0;\n\n this.nextPacket = function JpxImage_nextPacket() {\n // Section B.12.1.4 Position-component-resolution-layer\n for (; py < precinctsIterationSizes.maxNumHigh; py++) {\n for (; px < precinctsIterationSizes.maxNumWide; px++) {\n for (; c < componentsCount; c++) {\n var component = tile.components[c];\n var decompositionLevelsCount =\n component.codingStyleParameters.decompositionLevelsCount;\n for (; r <= decompositionLevelsCount; r++) {\n var resolution = component.resolutions[r];\n var sizeInImageScale =\n precinctsSizes.components[c].resolutions[r];\n var k = getPrecinctIndexIfExist(\n px,\n py,\n sizeInImageScale,\n precinctsIterationSizes,\n resolution);\n if (k === null) {\n continue;\n }\n for (; l < layersCount;) {\n var packet = createPacket(resolution, k, l);\n l++;\n return packet;\n }\n l = 0;\n }\n r = 0;\n }\n c = 0;\n }\n px = 0;\n }\n throw new JpxError('Out of packets');\n };\n }\n function ComponentPositionResolutionLayerIterator(context) {\n var siz = context.SIZ;\n var tileIndex = context.currentTile.index;\n var tile = context.tiles[tileIndex];\n var layersCount = tile.codingStyleDefaultParameters.layersCount;\n var componentsCount = siz.Csiz;\n var precinctsSizes = getPrecinctSizesInImageScale(tile);\n var l = 0, r = 0, c = 0, px = 0, py = 0;\n\n this.nextPacket = function JpxImage_nextPacket() {\n // Section B.12.1.5 Component-position-resolution-layer\n for (; c < componentsCount; ++c) {\n var component = tile.components[c];\n var precinctsIterationSizes = precinctsSizes.components[c];\n var decompositionLevelsCount =\n component.codingStyleParameters.decompositionLevelsCount;\n for (; py < precinctsIterationSizes.maxNumHigh; py++) {\n for (; px < precinctsIterationSizes.maxNumWide; px++) {\n for (; r <= decompositionLevelsCount; r++) {\n var resolution = component.resolutions[r];\n var sizeInImageScale = precinctsIterationSizes.resolutions[r];\n var k = getPrecinctIndexIfExist(\n px,\n py,\n sizeInImageScale,\n precinctsIterationSizes,\n resolution);\n if (k === null) {\n continue;\n }\n for (; l < layersCount;) {\n var packet = createPacket(resolution, k, l);\n l++;\n return packet;\n }\n l = 0;\n }\n r = 0;\n }\n px = 0;\n }\n py = 0;\n }\n throw new JpxError('Out of packets');\n };\n }\n function getPrecinctIndexIfExist(\n pxIndex, pyIndex, sizeInImageScale, precinctIterationSizes, resolution) {\n var posX = pxIndex * precinctIterationSizes.minWidth;\n var posY = pyIndex * precinctIterationSizes.minHeight;\n if (posX % sizeInImageScale.width !== 0 ||\n posY % sizeInImageScale.height !== 0) {\n return null;\n }\n var startPrecinctRowIndex =\n (posY / sizeInImageScale.width) *\n resolution.precinctParameters.numprecinctswide;\n return (posX / sizeInImageScale.height) + startPrecinctRowIndex;\n }\n function getPrecinctSizesInImageScale(tile) {\n var componentsCount = tile.components.length;\n var minWidth = Number.MAX_VALUE;\n var minHeight = Number.MAX_VALUE;\n var maxNumWide = 0;\n var maxNumHigh = 0;\n var sizePerComponent = new Array(componentsCount);\n for (var c = 0; c < componentsCount; c++) {\n var component = tile.components[c];\n var decompositionLevelsCount =\n component.codingStyleParameters.decompositionLevelsCount;\n var sizePerResolution = new Array(decompositionLevelsCount + 1);\n var minWidthCurrentComponent = Number.MAX_VALUE;\n var minHeightCurrentComponent = Number.MAX_VALUE;\n var maxNumWideCurrentComponent = 0;\n var maxNumHighCurrentComponent = 0;\n var scale = 1;\n for (var r = decompositionLevelsCount; r >= 0; --r) {\n var resolution = component.resolutions[r];\n var widthCurrentResolution =\n scale * resolution.precinctParameters.precinctWidth;\n var heightCurrentResolution =\n scale * resolution.precinctParameters.precinctHeight;\n minWidthCurrentComponent = Math.min(\n minWidthCurrentComponent,\n widthCurrentResolution);\n minHeightCurrentComponent = Math.min(\n minHeightCurrentComponent,\n heightCurrentResolution);\n maxNumWideCurrentComponent = Math.max(maxNumWideCurrentComponent,\n resolution.precinctParameters.numprecinctswide);\n maxNumHighCurrentComponent = Math.max(maxNumHighCurrentComponent,\n resolution.precinctParameters.numprecinctshigh);\n sizePerResolution[r] = {\n width: widthCurrentResolution,\n height: heightCurrentResolution,\n };\n scale <<= 1;\n }\n minWidth = Math.min(minWidth, minWidthCurrentComponent);\n minHeight = Math.min(minHeight, minHeightCurrentComponent);\n maxNumWide = Math.max(maxNumWide, maxNumWideCurrentComponent);\n maxNumHigh = Math.max(maxNumHigh, maxNumHighCurrentComponent);\n sizePerComponent[c] = {\n resolutions: sizePerResolution,\n minWidth: minWidthCurrentComponent,\n minHeight: minHeightCurrentComponent,\n maxNumWide: maxNumWideCurrentComponent,\n maxNumHigh: maxNumHighCurrentComponent,\n };\n }\n return {\n components: sizePerComponent,\n minWidth,\n minHeight,\n maxNumWide,\n maxNumHigh,\n };\n }\n function buildPackets(context) {\n var siz = context.SIZ;\n var tileIndex = context.currentTile.index;\n var tile = context.tiles[tileIndex];\n var componentsCount = siz.Csiz;\n // Creating resolutions and sub-bands for each component\n for (var c = 0; c < componentsCount; c++) {\n var component = tile.components[c];\n var decompositionLevelsCount =\n component.codingStyleParameters.decompositionLevelsCount;\n // Section B.5 Resolution levels and sub-bands\n var resolutions = [];\n var subbands = [];\n for (var r = 0; r <= decompositionLevelsCount; r++) {\n var blocksDimensions = getBlocksDimensions(context, component, r);\n var resolution = {};\n var scale = 1 << (decompositionLevelsCount - r);\n resolution.trx0 = Math.ceil(component.tcx0 / scale);\n resolution.try0 = Math.ceil(component.tcy0 / scale);\n resolution.trx1 = Math.ceil(component.tcx1 / scale);\n resolution.try1 = Math.ceil(component.tcy1 / scale);\n resolution.resLevel = r;\n buildPrecincts(context, resolution, blocksDimensions);\n resolutions.push(resolution);\n\n var subband;\n if (r === 0) {\n // one sub-band (LL) with last decomposition\n subband = {};\n subband.type = 'LL';\n subband.tbx0 = Math.ceil(component.tcx0 / scale);\n subband.tby0 = Math.ceil(component.tcy0 / scale);\n subband.tbx1 = Math.ceil(component.tcx1 / scale);\n subband.tby1 = Math.ceil(component.tcy1 / scale);\n subband.resolution = resolution;\n buildCodeblocks(context, subband, blocksDimensions);\n subbands.push(subband);\n resolution.subbands = [subband];\n } else {\n var bscale = 1 << (decompositionLevelsCount - r + 1);\n var resolutionSubbands = [];\n // three sub-bands (HL, LH and HH) with rest of decompositions\n subband = {};\n subband.type = 'HL';\n subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5);\n subband.tby0 = Math.ceil(component.tcy0 / bscale);\n subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5);\n subband.tby1 = Math.ceil(component.tcy1 / bscale);\n subband.resolution = resolution;\n buildCodeblocks(context, subband, blocksDimensions);\n subbands.push(subband);\n resolutionSubbands.push(subband);\n\n subband = {};\n subband.type = 'LH';\n subband.tbx0 = Math.ceil(component.tcx0 / bscale);\n subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5);\n subband.tbx1 = Math.ceil(component.tcx1 / bscale);\n subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5);\n subband.resolution = resolution;\n buildCodeblocks(context, subband, blocksDimensions);\n subbands.push(subband);\n resolutionSubbands.push(subband);\n\n subband = {};\n subband.type = 'HH';\n subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5);\n subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5);\n subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5);\n subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5);\n subband.resolution = resolution;\n buildCodeblocks(context, subband, blocksDimensions);\n subbands.push(subband);\n resolutionSubbands.push(subband);\n\n resolution.subbands = resolutionSubbands;\n }\n }\n component.resolutions = resolutions;\n component.subbands = subbands;\n }\n // Generate the packets sequence\n var progressionOrder = tile.codingStyleDefaultParameters.progressionOrder;\n switch (progressionOrder) {\n case 0:\n tile.packetsIterator =\n new LayerResolutionComponentPositionIterator(context);\n break;\n case 1:\n tile.packetsIterator =\n new ResolutionLayerComponentPositionIterator(context);\n break;\n case 2:\n tile.packetsIterator =\n new ResolutionPositionComponentLayerIterator(context);\n break;\n case 3:\n tile.packetsIterator =\n new PositionComponentResolutionLayerIterator(context);\n break;\n case 4:\n tile.packetsIterator =\n new ComponentPositionResolutionLayerIterator(context);\n break;\n default:\n throw new JpxError(`Unsupported progression order ${progressionOrder}`);\n }\n }\n function parseTilePackets(context, data, offset, dataLength) {\n var position = 0;\n var buffer, bufferSize = 0, skipNextBit = false;\n function readBits(count) {\n while (bufferSize < count) {\n var b = data[offset + position];\n position++;\n if (skipNextBit) {\n buffer = (buffer << 7) | b;\n bufferSize += 7;\n skipNextBit = false;\n } else {\n buffer = (buffer << 8) | b;\n bufferSize += 8;\n }\n if (b === 0xFF) {\n skipNextBit = true;\n }\n }\n bufferSize -= count;\n return (buffer >>> bufferSize) & ((1 << count) - 1);\n }\n function skipMarkerIfEqual(value) {\n if (data[offset + position - 1] === 0xFF &&\n data[offset + position] === value) {\n skipBytes(1);\n return true;\n } else if (data[offset + position] === 0xFF &&\n data[offset + position + 1] === value) {\n skipBytes(2);\n return true;\n }\n return false;\n }\n function skipBytes(count) {\n position += count;\n }\n function alignToByte() {\n bufferSize = 0;\n if (skipNextBit) {\n position++;\n skipNextBit = false;\n }\n }\n function readCodingpasses() {\n if (readBits(1) === 0) {\n return 1;\n }\n if (readBits(1) === 0) {\n return 2;\n }\n var value = readBits(2);\n if (value < 3) {\n return value + 3;\n }\n value = readBits(5);\n if (value < 31) {\n return value + 6;\n }\n value = readBits(7);\n return value + 37;\n }\n var tileIndex = context.currentTile.index;\n var tile = context.tiles[tileIndex];\n var sopMarkerUsed = context.COD.sopMarkerUsed;\n var ephMarkerUsed = context.COD.ephMarkerUsed;\n var packetsIterator = tile.packetsIterator;\n while (position < dataLength) {\n alignToByte();\n if (sopMarkerUsed && skipMarkerIfEqual(0x91)) {\n // Skip also marker segment length and packet sequence ID\n skipBytes(4);\n }\n var packet = packetsIterator.nextPacket();\n if (!readBits(1)) {\n continue;\n }\n var layerNumber = packet.layerNumber;\n var queue = [], codeblock;\n for (var i = 0, ii = packet.codeblocks.length; i < ii; i++) {\n codeblock = packet.codeblocks[i];\n var precinct = codeblock.precinct;\n var codeblockColumn = codeblock.cbx - precinct.cbxMin;\n var codeblockRow = codeblock.cby - precinct.cbyMin;\n var codeblockIncluded = false;\n var firstTimeInclusion = false;\n var valueReady;\n if (codeblock['included'] !== undefined) {\n codeblockIncluded = !!readBits(1);\n } else {\n // reading inclusion tree\n precinct = codeblock.precinct;\n var inclusionTree, zeroBitPlanesTree;\n if (precinct['inclusionTree'] !== undefined) {\n inclusionTree = precinct.inclusionTree;\n } else {\n // building inclusion and zero bit-planes trees\n var width = precinct.cbxMax - precinct.cbxMin + 1;\n var height = precinct.cbyMax - precinct.cbyMin + 1;\n inclusionTree = new InclusionTree(width, height, layerNumber);\n zeroBitPlanesTree = new TagTree(width, height);\n precinct.inclusionTree = inclusionTree;\n precinct.zeroBitPlanesTree = zeroBitPlanesTree;\n }\n\n if (inclusionTree.reset(codeblockColumn, codeblockRow, layerNumber)) {\n while (true) {\n if (readBits(1)) {\n valueReady = !inclusionTree.nextLevel();\n if (valueReady) {\n codeblock.included = true;\n codeblockIncluded = firstTimeInclusion = true;\n break;\n }\n } else {\n inclusionTree.incrementValue(layerNumber);\n break;\n }\n }\n }\n }\n if (!codeblockIncluded) {\n continue;\n }\n if (firstTimeInclusion) {\n zeroBitPlanesTree = precinct.zeroBitPlanesTree;\n zeroBitPlanesTree.reset(codeblockColumn, codeblockRow);\n while (true) {\n if (readBits(1)) {\n valueReady = !zeroBitPlanesTree.nextLevel();\n if (valueReady) {\n break;\n }\n } else {\n zeroBitPlanesTree.incrementValue();\n }\n }\n codeblock.zeroBitPlanes = zeroBitPlanesTree.value;\n }\n var codingpasses = readCodingpasses();\n while (readBits(1)) {\n codeblock.Lblock++;\n }\n var codingpassesLog2 = log2(codingpasses);\n // rounding down log2\n var bits = ((codingpasses < (1 << codingpassesLog2)) ?\n codingpassesLog2 - 1 : codingpassesLog2) + codeblock.Lblock;\n var codedDataLength = readBits(bits);\n queue.push({\n codeblock,\n codingpasses,\n dataLength: codedDataLength,\n });\n }\n alignToByte();\n if (ephMarkerUsed) {\n skipMarkerIfEqual(0x92);\n }\n while (queue.length > 0) {\n var packetItem = queue.shift();\n codeblock = packetItem.codeblock;\n if (codeblock['data'] === undefined) {\n codeblock.data = [];\n }\n codeblock.data.push({\n data,\n start: offset + position,\n end: offset + position + packetItem.dataLength,\n codingpasses: packetItem.codingpasses,\n });\n position += packetItem.dataLength;\n }\n }\n return position;\n }\n function copyCoefficients(coefficients, levelWidth, levelHeight, subband,\n delta, mb, reversible, segmentationSymbolUsed) {\n var x0 = subband.tbx0;\n var y0 = subband.tby0;\n var width = subband.tbx1 - subband.tbx0;\n var codeblocks = subband.codeblocks;\n var right = subband.type.charAt(0) === 'H' ? 1 : 0;\n var bottom = subband.type.charAt(1) === 'H' ? levelWidth : 0;\n\n for (var i = 0, ii = codeblocks.length; i < ii; ++i) {\n var codeblock = codeblocks[i];\n var blockWidth = codeblock.tbx1_ - codeblock.tbx0_;\n var blockHeight = codeblock.tby1_ - codeblock.tby0_;\n if (blockWidth === 0 || blockHeight === 0) {\n continue;\n }\n if (codeblock['data'] === undefined) {\n continue;\n }\n\n var bitModel, currentCodingpassType;\n bitModel = new BitModel(blockWidth, blockHeight, codeblock.subbandType,\n codeblock.zeroBitPlanes, mb);\n currentCodingpassType = 2; // first bit plane starts from cleanup\n\n // collect data\n var data = codeblock.data, totalLength = 0, codingpasses = 0;\n var j, jj, dataItem;\n for (j = 0, jj = data.length; j < jj; j++) {\n dataItem = data[j];\n totalLength += dataItem.end - dataItem.start;\n codingpasses += dataItem.codingpasses;\n }\n var encodedData = new Uint8Array(totalLength);\n var position = 0;\n for (j = 0, jj = data.length; j < jj; j++) {\n dataItem = data[j];\n var chunk = dataItem.data.subarray(dataItem.start, dataItem.end);\n encodedData.set(chunk, position);\n position += chunk.length;\n }\n // decoding the item\n var decoder = new ArithmeticDecoder(encodedData, 0, totalLength);\n bitModel.setDecoder(decoder);\n\n for (j = 0; j < codingpasses; j++) {\n switch (currentCodingpassType) {\n case 0:\n bitModel.runSignificancePropagationPass();\n break;\n case 1:\n bitModel.runMagnitudeRefinementPass();\n break;\n case 2:\n bitModel.runCleanupPass();\n if (segmentationSymbolUsed) {\n bitModel.checkSegmentationSymbol();\n }\n break;\n }\n currentCodingpassType = (currentCodingpassType + 1) % 3;\n }\n\n var offset = (codeblock.tbx0_ - x0) + (codeblock.tby0_ - y0) * width;\n var sign = bitModel.coefficentsSign;\n var magnitude = bitModel.coefficentsMagnitude;\n var bitsDecoded = bitModel.bitsDecoded;\n var magnitudeCorrection = reversible ? 0 : 0.5;\n var k, n, nb;\n position = 0;\n // Do the interleaving of Section F.3.3 here, so we do not need\n // to copy later. LL level is not interleaved, just copied.\n var interleave = (subband.type !== 'LL');\n for (j = 0; j < blockHeight; j++) {\n var row = (offset / width) | 0; // row in the non-interleaved subband\n var levelOffset = 2 * row * (levelWidth - width) + right + bottom;\n for (k = 0; k < blockWidth; k++) {\n n = magnitude[position];\n if (n !== 0) {\n n = (n + magnitudeCorrection) * delta;\n if (sign[position] !== 0) {\n n = -n;\n }\n nb = bitsDecoded[position];\n var pos = interleave ? (levelOffset + (offset << 1)) : offset;\n if (reversible && (nb >= mb)) {\n coefficients[pos] = n;\n } else {\n coefficients[pos] = n * (1 << (mb - nb));\n }\n }\n offset++;\n position++;\n }\n offset += width - blockWidth;\n }\n }\n }\n function transformTile(context, tile, c) {\n var component = tile.components[c];\n var codingStyleParameters = component.codingStyleParameters;\n var quantizationParameters = component.quantizationParameters;\n var decompositionLevelsCount =\n codingStyleParameters.decompositionLevelsCount;\n var spqcds = quantizationParameters.SPqcds;\n var scalarExpounded = quantizationParameters.scalarExpounded;\n var guardBits = quantizationParameters.guardBits;\n var segmentationSymbolUsed = codingStyleParameters.segmentationSymbolUsed;\n var precision = context.components[c].precision;\n\n var reversible = codingStyleParameters.reversibleTransformation;\n var transform = (reversible ? new ReversibleTransform() :\n new IrreversibleTransform());\n\n var subbandCoefficients = [];\n var b = 0;\n for (var i = 0; i <= decompositionLevelsCount; i++) {\n var resolution = component.resolutions[i];\n\n var width = resolution.trx1 - resolution.trx0;\n var height = resolution.try1 - resolution.try0;\n // Allocate space for the whole sublevel.\n var coefficients = new Float32Array(width * height);\n\n for (var j = 0, jj = resolution.subbands.length; j < jj; j++) {\n var mu, epsilon;\n if (!scalarExpounded) {\n // formula E-5\n mu = spqcds[0].mu;\n epsilon = spqcds[0].epsilon + (i > 0 ? 1 - i : 0);\n } else {\n mu = spqcds[b].mu;\n epsilon = spqcds[b].epsilon;\n b++;\n }\n\n var subband = resolution.subbands[j];\n var gainLog2 = SubbandsGainLog2[subband.type];\n\n // calculate quantization coefficient (Section E.1.1.1)\n var delta = (reversible ? 1 :\n Math.pow(2, precision + gainLog2 - epsilon) * (1 + mu / 2048));\n var mb = (guardBits + epsilon - 1);\n\n // In the first resolution level, copyCoefficients will fill the\n // whole array with coefficients. In the succeeding passes,\n // copyCoefficients will consecutively fill in the values that belong\n // to the interleaved positions of the HL, LH, and HH coefficients.\n // The LL coefficients will then be interleaved in Transform.iterate().\n copyCoefficients(coefficients, width, height, subband, delta, mb,\n reversible, segmentationSymbolUsed);\n }\n subbandCoefficients.push({\n width,\n height,\n items: coefficients,\n });\n }\n\n var result = transform.calculate(subbandCoefficients,\n component.tcx0, component.tcy0);\n return {\n left: component.tcx0,\n top: component.tcy0,\n width: result.width,\n height: result.height,\n items: result.items,\n };\n }\n function transformComponents(context) {\n var siz = context.SIZ;\n var components = context.components;\n var componentsCount = siz.Csiz;\n var resultImages = [];\n for (var i = 0, ii = context.tiles.length; i < ii; i++) {\n var tile = context.tiles[i];\n var transformedTiles = [];\n var c;\n for (c = 0; c < componentsCount; c++) {\n transformedTiles[c] = transformTile(context, tile, c);\n }\n var tile0 = transformedTiles[0];\n var out = new Uint8Array(tile0.items.length * componentsCount);\n var result = {\n left: tile0.left,\n top: tile0.top,\n width: tile0.width,\n height: tile0.height,\n items: out,\n };\n\n // Section G.2.2 Inverse multi component transform\n var shift, offset, max, min, maxK;\n var pos = 0, j, jj, y0, y1, y2, r, g, b, k, val;\n if (tile.codingStyleDefaultParameters.multipleComponentTransform) {\n var fourComponents = componentsCount === 4;\n var y0items = transformedTiles[0].items;\n var y1items = transformedTiles[1].items;\n var y2items = transformedTiles[2].items;\n var y3items = fourComponents ? transformedTiles[3].items : null;\n\n // HACK: The multiple component transform formulas below assume that\n // all components have the same precision. With this in mind, we\n // compute shift and offset only once.\n shift = components[0].precision - 8;\n offset = (128 << shift) + 0.5;\n max = 255 * (1 << shift);\n maxK = max * 0.5;\n min = -maxK;\n\n var component0 = tile.components[0];\n var alpha01 = componentsCount - 3;\n jj = y0items.length;\n if (!component0.codingStyleParameters.reversibleTransformation) {\n // inverse irreversible multiple component transform\n for (j = 0; j < jj; j++, pos += alpha01) {\n y0 = y0items[j] + offset;\n y1 = y1items[j];\n y2 = y2items[j];\n r = y0 + 1.402 * y2;\n g = y0 - 0.34413 * y1 - 0.71414 * y2;\n b = y0 + 1.772 * y1;\n out[pos++] = r <= 0 ? 0 : r >= max ? 255 : r >> shift;\n out[pos++] = g <= 0 ? 0 : g >= max ? 255 : g >> shift;\n out[pos++] = b <= 0 ? 0 : b >= max ? 255 : b >> shift;\n }\n } else {\n // inverse reversible multiple component transform\n for (j = 0; j < jj; j++, pos += alpha01) {\n y0 = y0items[j] + offset;\n y1 = y1items[j];\n y2 = y2items[j];\n g = y0 - ((y2 + y1) >> 2);\n r = g + y2;\n b = g + y1;\n out[pos++] = r <= 0 ? 0 : r >= max ? 255 : r >> shift;\n out[pos++] = g <= 0 ? 0 : g >= max ? 255 : g >> shift;\n out[pos++] = b <= 0 ? 0 : b >= max ? 255 : b >> shift;\n }\n }\n if (fourComponents) {\n for (j = 0, pos = 3; j < jj; j++, pos += 4) {\n k = y3items[j];\n out[pos] = k <= min ? 0 : k >= maxK ? 255 : (k + offset) >> shift;\n }\n }\n } else { // no multi-component transform\n for (c = 0; c < componentsCount; c++) {\n var items = transformedTiles[c].items;\n shift = components[c].precision - 8;\n offset = (128 << shift) + 0.5;\n max = (127.5 * (1 << shift));\n min = -max;\n for (pos = c, j = 0, jj = items.length; j < jj; j++) {\n val = items[j];\n out[pos] = val <= min ? 0 :\n val >= max ? 255 : (val + offset) >> shift;\n pos += componentsCount;\n }\n }\n }\n resultImages.push(result);\n }\n return resultImages;\n }\n function initializeTile(context, tileIndex) {\n var siz = context.SIZ;\n var componentsCount = siz.Csiz;\n var tile = context.tiles[tileIndex];\n for (var c = 0; c < componentsCount; c++) {\n var component = tile.components[c];\n var qcdOrQcc = (context.currentTile.QCC[c] !== undefined ?\n context.currentTile.QCC[c] : context.currentTile.QCD);\n component.quantizationParameters = qcdOrQcc;\n var codOrCoc = (context.currentTile.COC[c] !== undefined ?\n context.currentTile.COC[c] : context.currentTile.COD);\n component.codingStyleParameters = codOrCoc;\n }\n tile.codingStyleDefaultParameters = context.currentTile.COD;\n }\n\n // Section B.10.2 Tag trees\n var TagTree = (function TagTreeClosure() {\n function TagTree(width, height) {\n var levelsLength = log2(Math.max(width, height)) + 1;\n this.levels = [];\n for (var i = 0; i < levelsLength; i++) {\n var level = {\n width,\n height,\n items: [],\n };\n this.levels.push(level);\n width = Math.ceil(width / 2);\n height = Math.ceil(height / 2);\n }\n }\n TagTree.prototype = {\n reset: function TagTree_reset(i, j) {\n var currentLevel = 0, value = 0, level;\n while (currentLevel < this.levels.length) {\n level = this.levels[currentLevel];\n var index = i + j * level.width;\n if (level.items[index] !== undefined) {\n value = level.items[index];\n break;\n }\n level.index = index;\n i >>= 1;\n j >>= 1;\n currentLevel++;\n }\n currentLevel--;\n level = this.levels[currentLevel];\n level.items[level.index] = value;\n this.currentLevel = currentLevel;\n delete this.value;\n },\n incrementValue: function TagTree_incrementValue() {\n var level = this.levels[this.currentLevel];\n level.items[level.index]++;\n },\n nextLevel: function TagTree_nextLevel() {\n var currentLevel = this.currentLevel;\n var level = this.levels[currentLevel];\n var value = level.items[level.index];\n currentLevel--;\n if (currentLevel < 0) {\n this.value = value;\n return false;\n }\n\n this.currentLevel = currentLevel;\n level = this.levels[currentLevel];\n level.items[level.index] = value;\n return true;\n },\n };\n return TagTree;\n })();\n\n var InclusionTree = (function InclusionTreeClosure() {\n function InclusionTree(width, height, defaultValue) {\n var levelsLength = log2(Math.max(width, height)) + 1;\n this.levels = [];\n for (var i = 0; i < levelsLength; i++) {\n var items = new Uint8Array(width * height);\n for (var j = 0, jj = items.length; j < jj; j++) {\n items[j] = defaultValue;\n }\n\n var level = {\n width,\n height,\n items,\n };\n this.levels.push(level);\n\n width = Math.ceil(width / 2);\n height = Math.ceil(height / 2);\n }\n }\n InclusionTree.prototype = {\n reset: function InclusionTree_reset(i, j, stopValue) {\n var currentLevel = 0;\n while (currentLevel < this.levels.length) {\n var level = this.levels[currentLevel];\n var index = i + j * level.width;\n level.index = index;\n var value = level.items[index];\n\n if (value === 0xFF) {\n break;\n }\n\n if (value > stopValue) {\n this.currentLevel = currentLevel;\n // already know about this one, propagating the value to top levels\n this.propagateValues();\n return false;\n }\n\n i >>= 1;\n j >>= 1;\n currentLevel++;\n }\n this.currentLevel = currentLevel - 1;\n return true;\n },\n incrementValue: function InclusionTree_incrementValue(stopValue) {\n var level = this.levels[this.currentLevel];\n level.items[level.index] = stopValue + 1;\n this.propagateValues();\n },\n propagateValues: function InclusionTree_propagateValues() {\n var levelIndex = this.currentLevel;\n var level = this.levels[levelIndex];\n var currentValue = level.items[level.index];\n while (--levelIndex >= 0) {\n level = this.levels[levelIndex];\n level.items[level.index] = currentValue;\n }\n },\n nextLevel: function InclusionTree_nextLevel() {\n var currentLevel = this.currentLevel;\n var level = this.levels[currentLevel];\n var value = level.items[level.index];\n level.items[level.index] = 0xFF;\n currentLevel--;\n if (currentLevel < 0) {\n return false;\n }\n\n this.currentLevel = currentLevel;\n level = this.levels[currentLevel];\n level.items[level.index] = value;\n return true;\n },\n };\n return InclusionTree;\n })();\n\n // Section D. Coefficient bit modeling\n var BitModel = (function BitModelClosure() {\n var UNIFORM_CONTEXT = 17;\n var RUNLENGTH_CONTEXT = 18;\n // Table D-1\n // The index is binary presentation: 0dddvvhh, ddd - sum of Di (0..4),\n // vv - sum of Vi (0..2), and hh - sum of Hi (0..2)\n var LLAndLHContextsLabel = new Uint8Array([\n 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,\n 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,\n 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\n ]);\n var HLContextLabel = new Uint8Array([\n 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,\n 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,\n 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\n ]);\n var HHContextLabel = new Uint8Array([\n 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,\n 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,\n 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\n ]);\n\n function BitModel(width, height, subband, zeroBitPlanes, mb) {\n this.width = width;\n this.height = height;\n\n this.contextLabelTable = (subband === 'HH' ? HHContextLabel :\n (subband === 'HL' ? HLContextLabel : LLAndLHContextsLabel));\n\n var coefficientCount = width * height;\n\n // coefficients outside the encoding region treated as insignificant\n // add border state cells for significanceState\n this.neighborsSignificance = new Uint8Array(coefficientCount);\n this.coefficentsSign = new Uint8Array(coefficientCount);\n this.coefficentsMagnitude = mb > 14 ? new Uint32Array(coefficientCount) :\n mb > 6 ? new Uint16Array(coefficientCount) :\n new Uint8Array(coefficientCount);\n this.processingFlags = new Uint8Array(coefficientCount);\n\n var bitsDecoded = new Uint8Array(coefficientCount);\n if (zeroBitPlanes !== 0) {\n for (var i = 0; i < coefficientCount; i++) {\n bitsDecoded[i] = zeroBitPlanes;\n }\n }\n this.bitsDecoded = bitsDecoded;\n\n this.reset();\n }\n\n BitModel.prototype = {\n setDecoder: function BitModel_setDecoder(decoder) {\n this.decoder = decoder;\n },\n reset: function BitModel_reset() {\n // We have 17 contexts that are accessed via context labels,\n // plus the uniform and runlength context.\n this.contexts = new Int8Array(19);\n\n // Contexts are packed into 1 byte:\n // highest 7 bits carry the index, lowest bit carries mps\n this.contexts[0] = (4 << 1) | 0;\n this.contexts[UNIFORM_CONTEXT] = (46 << 1) | 0;\n this.contexts[RUNLENGTH_CONTEXT] = (3 << 1) | 0;\n },\n setNeighborsSignificance:\n function BitModel_setNeighborsSignificance(row, column, index) {\n var neighborsSignificance = this.neighborsSignificance;\n var width = this.width, height = this.height;\n var left = (column > 0);\n var right = (column + 1 < width);\n var i;\n\n if (row > 0) {\n i = index - width;\n if (left) {\n neighborsSignificance[i - 1] += 0x10;\n }\n if (right) {\n neighborsSignificance[i + 1] += 0x10;\n }\n neighborsSignificance[i] += 0x04;\n }\n\n if (row + 1 < height) {\n i = index + width;\n if (left) {\n neighborsSignificance[i - 1] += 0x10;\n }\n if (right) {\n neighborsSignificance[i + 1] += 0x10;\n }\n neighborsSignificance[i] += 0x04;\n }\n\n if (left) {\n neighborsSignificance[index - 1] += 0x01;\n }\n if (right) {\n neighborsSignificance[index + 1] += 0x01;\n }\n neighborsSignificance[index] |= 0x80;\n },\n runSignificancePropagationPass:\n function BitModel_runSignificancePropagationPass() {\n var decoder = this.decoder;\n var width = this.width, height = this.height;\n var coefficentsMagnitude = this.coefficentsMagnitude;\n var coefficentsSign = this.coefficentsSign;\n var neighborsSignificance = this.neighborsSignificance;\n var processingFlags = this.processingFlags;\n var contexts = this.contexts;\n var labels = this.contextLabelTable;\n var bitsDecoded = this.bitsDecoded;\n var processedInverseMask = ~1;\n var processedMask = 1;\n var firstMagnitudeBitMask = 2;\n\n for (var i0 = 0; i0 < height; i0 += 4) {\n for (var j = 0; j < width; j++) {\n var index = i0 * width + j;\n for (var i1 = 0; i1 < 4; i1++, index += width) {\n var i = i0 + i1;\n if (i >= height) {\n break;\n }\n // clear processed flag first\n processingFlags[index] &= processedInverseMask;\n\n if (coefficentsMagnitude[index] ||\n !neighborsSignificance[index]) {\n continue;\n }\n\n var contextLabel = labels[neighborsSignificance[index]];\n var decision = decoder.readBit(contexts, contextLabel);\n if (decision) {\n var sign = this.decodeSignBit(i, j, index);\n coefficentsSign[index] = sign;\n coefficentsMagnitude[index] = 1;\n this.setNeighborsSignificance(i, j, index);\n processingFlags[index] |= firstMagnitudeBitMask;\n }\n bitsDecoded[index]++;\n processingFlags[index] |= processedMask;\n }\n }\n }\n },\n decodeSignBit: function BitModel_decodeSignBit(row, column, index) {\n var width = this.width, height = this.height;\n var coefficentsMagnitude = this.coefficentsMagnitude;\n var coefficentsSign = this.coefficentsSign;\n var contribution, sign0, sign1, significance1;\n var contextLabel, decoded;\n\n // calculate horizontal contribution\n significance1 = (column > 0 && coefficentsMagnitude[index - 1] !== 0);\n if (column + 1 < width && coefficentsMagnitude[index + 1] !== 0) {\n sign1 = coefficentsSign[index + 1];\n if (significance1) {\n sign0 = coefficentsSign[index - 1];\n contribution = 1 - sign1 - sign0;\n } else {\n contribution = 1 - sign1 - sign1;\n }\n } else if (significance1) {\n sign0 = coefficentsSign[index - 1];\n contribution = 1 - sign0 - sign0;\n } else {\n contribution = 0;\n }\n var horizontalContribution = 3 * contribution;\n\n // calculate vertical contribution and combine with the horizontal\n significance1 = (row > 0 && coefficentsMagnitude[index - width] !== 0);\n if (row + 1 < height && coefficentsMagnitude[index + width] !== 0) {\n sign1 = coefficentsSign[index + width];\n if (significance1) {\n sign0 = coefficentsSign[index - width];\n contribution = 1 - sign1 - sign0 + horizontalContribution;\n } else {\n contribution = 1 - sign1 - sign1 + horizontalContribution;\n }\n } else if (significance1) {\n sign0 = coefficentsSign[index - width];\n contribution = 1 - sign0 - sign0 + horizontalContribution;\n } else {\n contribution = horizontalContribution;\n }\n\n if (contribution >= 0) {\n contextLabel = 9 + contribution;\n decoded = this.decoder.readBit(this.contexts, contextLabel);\n } else {\n contextLabel = 9 - contribution;\n decoded = this.decoder.readBit(this.contexts, contextLabel) ^ 1;\n }\n return decoded;\n },\n runMagnitudeRefinementPass:\n function BitModel_runMagnitudeRefinementPass() {\n var decoder = this.decoder;\n var width = this.width, height = this.height;\n var coefficentsMagnitude = this.coefficentsMagnitude;\n var neighborsSignificance = this.neighborsSignificance;\n var contexts = this.contexts;\n var bitsDecoded = this.bitsDecoded;\n var processingFlags = this.processingFlags;\n var processedMask = 1;\n var firstMagnitudeBitMask = 2;\n var length = width * height;\n var width4 = width * 4;\n\n for (var index0 = 0, indexNext; index0 < length; index0 = indexNext) {\n indexNext = Math.min(length, index0 + width4);\n for (var j = 0; j < width; j++) {\n for (var index = index0 + j; index < indexNext; index += width) {\n\n // significant but not those that have just become\n if (!coefficentsMagnitude[index] ||\n (processingFlags[index] & processedMask) !== 0) {\n continue;\n }\n\n var contextLabel = 16;\n if ((processingFlags[index] & firstMagnitudeBitMask) !== 0) {\n processingFlags[index] ^= firstMagnitudeBitMask;\n // first refinement\n var significance = neighborsSignificance[index] & 127;\n contextLabel = significance === 0 ? 15 : 14;\n }\n\n var bit = decoder.readBit(contexts, contextLabel);\n coefficentsMagnitude[index] =\n (coefficentsMagnitude[index] << 1) | bit;\n bitsDecoded[index]++;\n processingFlags[index] |= processedMask;\n }\n }\n }\n },\n runCleanupPass: function BitModel_runCleanupPass() {\n var decoder = this.decoder;\n var width = this.width, height = this.height;\n var neighborsSignificance = this.neighborsSignificance;\n var coefficentsMagnitude = this.coefficentsMagnitude;\n var coefficentsSign = this.coefficentsSign;\n var contexts = this.contexts;\n var labels = this.contextLabelTable;\n var bitsDecoded = this.bitsDecoded;\n var processingFlags = this.processingFlags;\n var processedMask = 1;\n var firstMagnitudeBitMask = 2;\n var oneRowDown = width;\n var twoRowsDown = width * 2;\n var threeRowsDown = width * 3;\n var iNext;\n for (var i0 = 0; i0 < height; i0 = iNext) {\n iNext = Math.min(i0 + 4, height);\n var indexBase = i0 * width;\n var checkAllEmpty = i0 + 3 < height;\n for (var j = 0; j < width; j++) {\n var index0 = indexBase + j;\n // using the property: labels[neighborsSignificance[index]] === 0\n // when neighborsSignificance[index] === 0\n var allEmpty = (checkAllEmpty &&\n processingFlags[index0] === 0 &&\n processingFlags[index0 + oneRowDown] === 0 &&\n processingFlags[index0 + twoRowsDown] === 0 &&\n processingFlags[index0 + threeRowsDown] === 0 &&\n neighborsSignificance[index0] === 0 &&\n neighborsSignificance[index0 + oneRowDown] === 0 &&\n neighborsSignificance[index0 + twoRowsDown] === 0 &&\n neighborsSignificance[index0 + threeRowsDown] === 0);\n var i1 = 0, index = index0;\n var i = i0, sign;\n if (allEmpty) {\n var hasSignificantCoefficent =\n decoder.readBit(contexts, RUNLENGTH_CONTEXT);\n if (!hasSignificantCoefficent) {\n bitsDecoded[index0]++;\n bitsDecoded[index0 + oneRowDown]++;\n bitsDecoded[index0 + twoRowsDown]++;\n bitsDecoded[index0 + threeRowsDown]++;\n continue; // next column\n }\n i1 = (decoder.readBit(contexts, UNIFORM_CONTEXT) << 1) |\n decoder.readBit(contexts, UNIFORM_CONTEXT);\n if (i1 !== 0) {\n i = i0 + i1;\n index += i1 * width;\n }\n\n sign = this.decodeSignBit(i, j, index);\n coefficentsSign[index] = sign;\n coefficentsMagnitude[index] = 1;\n this.setNeighborsSignificance(i, j, index);\n processingFlags[index] |= firstMagnitudeBitMask;\n\n index = index0;\n for (var i2 = i0; i2 <= i; i2++, index += width) {\n bitsDecoded[index]++;\n }\n\n i1++;\n }\n for (i = i0 + i1; i < iNext; i++, index += width) {\n if (coefficentsMagnitude[index] ||\n (processingFlags[index] & processedMask) !== 0) {\n continue;\n }\n\n var contextLabel = labels[neighborsSignificance[index]];\n var decision = decoder.readBit(contexts, contextLabel);\n if (decision === 1) {\n sign = this.decodeSignBit(i, j, index);\n coefficentsSign[index] = sign;\n coefficentsMagnitude[index] = 1;\n this.setNeighborsSignificance(i, j, index);\n processingFlags[index] |= firstMagnitudeBitMask;\n }\n bitsDecoded[index]++;\n }\n }\n }\n },\n checkSegmentationSymbol: function BitModel_checkSegmentationSymbol() {\n var decoder = this.decoder;\n var contexts = this.contexts;\n var symbol = (decoder.readBit(contexts, UNIFORM_CONTEXT) << 3) |\n (decoder.readBit(contexts, UNIFORM_CONTEXT) << 2) |\n (decoder.readBit(contexts, UNIFORM_CONTEXT) << 1) |\n decoder.readBit(contexts, UNIFORM_CONTEXT);\n if (symbol !== 0xA) {\n throw new JpxError('Invalid segmentation symbol');\n }\n },\n };\n\n return BitModel;\n })();\n\n // Section F, Discrete wavelet transformation\n var Transform = (function TransformClosure() {\n function Transform() {}\n\n Transform.prototype.calculate =\n function transformCalculate(subbands, u0, v0) {\n var ll = subbands[0];\n for (var i = 1, ii = subbands.length; i < ii; i++) {\n ll = this.iterate(ll, subbands[i], u0, v0);\n }\n return ll;\n };\n Transform.prototype.extend = function extend(buffer, offset, size) {\n // Section F.3.7 extending... using max extension of 4\n var i1 = offset - 1, j1 = offset + 1;\n var i2 = offset + size - 2, j2 = offset + size;\n buffer[i1--] = buffer[j1++];\n buffer[j2++] = buffer[i2--];\n buffer[i1--] = buffer[j1++];\n buffer[j2++] = buffer[i2--];\n buffer[i1--] = buffer[j1++];\n buffer[j2++] = buffer[i2--];\n buffer[i1] = buffer[j1];\n buffer[j2] = buffer[i2];\n };\n Transform.prototype.iterate = function Transform_iterate(ll, hl_lh_hh,\n u0, v0) {\n var llWidth = ll.width, llHeight = ll.height, llItems = ll.items;\n var width = hl_lh_hh.width;\n var height = hl_lh_hh.height;\n var items = hl_lh_hh.items;\n var i, j, k, l, u, v;\n\n // Interleave LL according to Section F.3.3\n for (k = 0, i = 0; i < llHeight; i++) {\n l = i * 2 * width;\n for (j = 0; j < llWidth; j++, k++, l += 2) {\n items[l] = llItems[k];\n }\n }\n // The LL band is not needed anymore.\n llItems = ll.items = null;\n\n var bufferPadding = 4;\n var rowBuffer = new Float32Array(width + 2 * bufferPadding);\n\n // Section F.3.4 HOR_SR\n if (width === 1) {\n // if width = 1, when u0 even keep items as is, when odd divide by 2\n if ((u0 & 1) !== 0) {\n for (v = 0, k = 0; v < height; v++, k += width) {\n items[k] *= 0.5;\n }\n }\n } else {\n for (v = 0, k = 0; v < height; v++, k += width) {\n rowBuffer.set(items.subarray(k, k + width), bufferPadding);\n\n this.extend(rowBuffer, bufferPadding, width);\n this.filter(rowBuffer, bufferPadding, width);\n\n items.set(\n rowBuffer.subarray(bufferPadding, bufferPadding + width),\n k);\n }\n }\n\n // Accesses to the items array can take long, because it may not fit into\n // CPU cache and has to be fetched from main memory. Since subsequent\n // accesses to the items array are not local when reading columns, we\n // have a cache miss every time. To reduce cache misses, get up to\n // 'numBuffers' items at a time and store them into the individual\n // buffers. The colBuffers should be small enough to fit into CPU cache.\n var numBuffers = 16;\n var colBuffers = [];\n for (i = 0; i < numBuffers; i++) {\n colBuffers.push(new Float32Array(height + 2 * bufferPadding));\n }\n var b, currentBuffer = 0;\n ll = bufferPadding + height;\n\n // Section F.3.5 VER_SR\n if (height === 1) {\n // if height = 1, when v0 even keep items as is, when odd divide by 2\n if ((v0 & 1) !== 0) {\n for (u = 0; u < width; u++) {\n items[u] *= 0.5;\n }\n }\n } else {\n for (u = 0; u < width; u++) {\n // if we ran out of buffers, copy several image columns at once\n if (currentBuffer === 0) {\n numBuffers = Math.min(width - u, numBuffers);\n for (k = u, l = bufferPadding; l < ll; k += width, l++) {\n for (b = 0; b < numBuffers; b++) {\n colBuffers[b][l] = items[k + b];\n }\n }\n currentBuffer = numBuffers;\n }\n\n currentBuffer--;\n var buffer = colBuffers[currentBuffer];\n this.extend(buffer, bufferPadding, height);\n this.filter(buffer, bufferPadding, height);\n\n // If this is last buffer in this group of buffers, flush all buffers.\n if (currentBuffer === 0) {\n k = u - numBuffers + 1;\n for (l = bufferPadding; l < ll; k += width, l++) {\n for (b = 0; b < numBuffers; b++) {\n items[k + b] = colBuffers[b][l];\n }\n }\n }\n }\n }\n\n return {\n width,\n height,\n items,\n };\n };\n return Transform;\n })();\n\n // Section 3.8.2 Irreversible 9-7 filter\n var IrreversibleTransform = (function IrreversibleTransformClosure() {\n function IrreversibleTransform() {\n Transform.call(this);\n }\n\n IrreversibleTransform.prototype = Object.create(Transform.prototype);\n IrreversibleTransform.prototype.filter =\n function irreversibleTransformFilter(x, offset, length) {\n var len = length >> 1;\n offset = offset | 0;\n var j, n, current, next;\n\n var alpha = -1.586134342059924;\n var beta = -0.052980118572961;\n var gamma = 0.882911075530934;\n var delta = 0.443506852043971;\n var K = 1.230174104914001;\n var K_ = 1 / K;\n\n // step 1 is combined with step 3\n\n // step 2\n j = offset - 3;\n for (n = len + 4; n--; j += 2) {\n x[j] *= K_;\n }\n\n // step 1 & 3\n j = offset - 2;\n current = delta * x[j - 1];\n for (n = len + 3; n--; j += 2) {\n next = delta * x[j + 1];\n x[j] = K * x[j] - current - next;\n if (n--) {\n j += 2;\n current = delta * x[j + 1];\n x[j] = K * x[j] - current - next;\n } else {\n break;\n }\n }\n\n // step 4\n j = offset - 1;\n current = gamma * x[j - 1];\n for (n = len + 2; n--; j += 2) {\n next = gamma * x[j + 1];\n x[j] -= current + next;\n if (n--) {\n j += 2;\n current = gamma * x[j + 1];\n x[j] -= current + next;\n } else {\n break;\n }\n }\n\n // step 5\n j = offset;\n current = beta * x[j - 1];\n for (n = len + 1; n--; j += 2) {\n next = beta * x[j + 1];\n x[j] -= current + next;\n if (n--) {\n j += 2;\n current = beta * x[j + 1];\n x[j] -= current + next;\n } else {\n break;\n }\n }\n\n // step 6\n if (len !== 0) {\n j = offset + 1;\n current = alpha * x[j - 1];\n for (n = len; n--; j += 2) {\n next = alpha * x[j + 1];\n x[j] -= current + next;\n if (n--) {\n j += 2;\n current = alpha * x[j + 1];\n x[j] -= current + next;\n } else {\n break;\n }\n }\n }\n };\n\n return IrreversibleTransform;\n })();\n\n // Section 3.8.1 Reversible 5-3 filter\n var ReversibleTransform = (function ReversibleTransformClosure() {\n function ReversibleTransform() {\n Transform.call(this);\n }\n\n ReversibleTransform.prototype = Object.create(Transform.prototype);\n ReversibleTransform.prototype.filter =\n function reversibleTransformFilter(x, offset, length) {\n var len = length >> 1;\n offset = offset | 0;\n var j, n;\n\n for (j = offset, n = len + 1; n--; j += 2) {\n x[j] -= (x[j - 1] + x[j + 1] + 2) >> 2;\n }\n\n for (j = offset + 1, n = len; n--; j += 2) {\n x[j] += (x[j - 1] + x[j + 1]) >> 1;\n }\n };\n\n return ReversibleTransform;\n })();\n\n return JpxImage;\n})();\n\nexport {\n JpxImage,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/jpx.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n bytesToString, createPromiseCapability, createValidAbsoluteUrl, FormatError,\n info, InvalidPDFException, isArray, isBool, isInt, isString,\n MissingDataException, shadow, stringToPDFString, stringToUTF8String, Util,\n warn, XRefParseException\n} from '../shared/util';\nimport {\n Dict, isCmd, isDict, isName, isRef, isRefsEqual, isStream, Ref, RefSet,\n RefSetCache\n} from './primitives';\nimport { Lexer, Parser } from './parser';\nimport { ChunkedStream } from './chunked_stream';\nimport { CipherTransformFactory } from './crypto';\nimport { ColorSpace } from './colorspace';\n\nvar Catalog = (function CatalogClosure() {\n function Catalog(pdfManager, xref, pageFactory) {\n this.pdfManager = pdfManager;\n this.xref = xref;\n this.catDict = xref.getCatalogObj();\n if (!isDict(this.catDict)) {\n throw new FormatError('catalog object is not a dictionary');\n }\n\n this.fontCache = new RefSetCache();\n this.builtInCMapCache = Object.create(null);\n this.pageKidsCountCache = new RefSetCache();\n // TODO refactor to move getPage() to the PDFDocument.\n this.pageFactory = pageFactory;\n this.pagePromises = [];\n }\n\n Catalog.prototype = {\n get metadata() {\n var streamRef = this.catDict.getRaw('Metadata');\n if (!isRef(streamRef)) {\n return shadow(this, 'metadata', null);\n }\n\n var encryptMetadata = (!this.xref.encrypt ? false :\n this.xref.encrypt.encryptMetadata);\n\n var stream = this.xref.fetch(streamRef, !encryptMetadata);\n var metadata;\n if (stream && isDict(stream.dict)) {\n var type = stream.dict.get('Type');\n var subtype = stream.dict.get('Subtype');\n\n if (isName(type, 'Metadata') && isName(subtype, 'XML')) {\n // XXX: This should examine the charset the XML document defines,\n // however since there are currently no real means to decode\n // arbitrary charsets, let's just hope that the author of the PDF\n // was reasonable enough to stick with the XML default charset,\n // which is UTF-8.\n try {\n metadata = stringToUTF8String(bytesToString(stream.getBytes()));\n } catch (e) {\n if (e instanceof MissingDataException) {\n throw e;\n }\n info('Skipping invalid metadata.');\n }\n }\n }\n\n return shadow(this, 'metadata', metadata);\n },\n get toplevelPagesDict() {\n var pagesObj = this.catDict.get('Pages');\n if (!isDict(pagesObj)) {\n throw new FormatError('invalid top-level pages dictionary');\n }\n // shadow the prototype getter\n return shadow(this, 'toplevelPagesDict', pagesObj);\n },\n get documentOutline() {\n var obj = null;\n try {\n obj = this.readDocumentOutline();\n } catch (ex) {\n if (ex instanceof MissingDataException) {\n throw ex;\n }\n warn('Unable to read document outline');\n }\n return shadow(this, 'documentOutline', obj);\n },\n readDocumentOutline: function Catalog_readDocumentOutline() {\n var obj = this.catDict.get('Outlines');\n if (!isDict(obj)) {\n return null;\n }\n obj = obj.getRaw('First');\n if (!isRef(obj)) {\n return null;\n }\n var root = { items: [], };\n var queue = [{ obj, parent: root, }];\n // To avoid recursion, keep track of the already processed items.\n var processed = new RefSet();\n processed.put(obj);\n var xref = this.xref, blackColor = new Uint8Array(3);\n\n while (queue.length > 0) {\n var i = queue.shift();\n var outlineDict = xref.fetchIfRef(i.obj);\n if (outlineDict === null) {\n continue;\n }\n if (!outlineDict.has('Title')) {\n throw new FormatError('Invalid outline item');\n }\n\n var data = { url: null, dest: null, };\n Catalog.parseDestDictionary({\n destDict: outlineDict,\n resultObj: data,\n docBaseUrl: this.pdfManager.docBaseUrl,\n });\n var title = outlineDict.get('Title');\n var flags = outlineDict.get('F') || 0;\n\n var color = outlineDict.getArray('C'), rgbColor = blackColor;\n // We only need to parse the color when it's valid, and non-default.\n if (isArray(color) && color.length === 3 &&\n (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) {\n rgbColor = ColorSpace.singletons.rgb.getRgb(color, 0);\n }\n var outlineItem = {\n dest: data.dest,\n url: data.url,\n unsafeUrl: data.unsafeUrl,\n newWindow: data.newWindow,\n title: stringToPDFString(title),\n color: rgbColor,\n count: outlineDict.get('Count'),\n bold: !!(flags & 2),\n italic: !!(flags & 1),\n items: [],\n };\n i.parent.items.push(outlineItem);\n obj = outlineDict.getRaw('First');\n if (isRef(obj) && !processed.has(obj)) {\n queue.push({ obj, parent: outlineItem, });\n processed.put(obj);\n }\n obj = outlineDict.getRaw('Next');\n if (isRef(obj) && !processed.has(obj)) {\n queue.push({ obj, parent: i.parent, });\n processed.put(obj);\n }\n }\n return (root.items.length > 0 ? root.items : null);\n },\n get numPages() {\n var obj = this.toplevelPagesDict.get('Count');\n if (!isInt(obj)) {\n throw new FormatError(\n 'page count in top level pages object is not an integer');\n }\n // shadow the prototype getter\n return shadow(this, 'numPages', obj);\n },\n get destinations() {\n function fetchDestination(dest) {\n return isDict(dest) ? dest.get('D') : dest;\n }\n\n var xref = this.xref;\n var dests = {}, nameTreeRef, nameDictionaryRef;\n var obj = this.catDict.get('Names');\n if (obj && obj.has('Dests')) {\n nameTreeRef = obj.getRaw('Dests');\n } else if (this.catDict.has('Dests')) {\n nameDictionaryRef = this.catDict.get('Dests');\n }\n\n if (nameDictionaryRef) {\n // reading simple destination dictionary\n obj = nameDictionaryRef;\n obj.forEach(function catalogForEach(key, value) {\n if (!value) {\n return;\n }\n dests[key] = fetchDestination(value);\n });\n }\n if (nameTreeRef) {\n var nameTree = new NameTree(nameTreeRef, xref);\n var names = nameTree.getAll();\n for (var name in names) {\n dests[name] = fetchDestination(names[name]);\n }\n }\n return shadow(this, 'destinations', dests);\n },\n getDestination: function Catalog_getDestination(destinationId) {\n function fetchDestination(dest) {\n return isDict(dest) ? dest.get('D') : dest;\n }\n\n var xref = this.xref;\n var dest = null, nameTreeRef, nameDictionaryRef;\n var obj = this.catDict.get('Names');\n if (obj && obj.has('Dests')) {\n nameTreeRef = obj.getRaw('Dests');\n } else if (this.catDict.has('Dests')) {\n nameDictionaryRef = this.catDict.get('Dests');\n }\n\n if (nameDictionaryRef) { // Simple destination dictionary.\n var value = nameDictionaryRef.get(destinationId);\n if (value) {\n dest = fetchDestination(value);\n }\n }\n if (nameTreeRef) {\n var nameTree = new NameTree(nameTreeRef, xref);\n dest = fetchDestination(nameTree.get(destinationId));\n }\n return dest;\n },\n\n get pageLabels() {\n var obj = null;\n try {\n obj = this.readPageLabels();\n } catch (ex) {\n if (ex instanceof MissingDataException) {\n throw ex;\n }\n warn('Unable to read page labels.');\n }\n return shadow(this, 'pageLabels', obj);\n },\n readPageLabels: function Catalog_readPageLabels() {\n var obj = this.catDict.getRaw('PageLabels');\n if (!obj) {\n return null;\n }\n var pageLabels = new Array(this.numPages);\n var style = null;\n var prefix = '';\n\n var numberTree = new NumberTree(obj, this.xref);\n var nums = numberTree.getAll();\n var currentLabel = '', currentIndex = 1;\n\n for (var i = 0, ii = this.numPages; i < ii; i++) {\n if (i in nums) {\n var labelDict = nums[i];\n if (!isDict(labelDict)) {\n throw new FormatError('The PageLabel is not a dictionary.');\n }\n\n var type = labelDict.get('Type');\n if (type && !isName(type, 'PageLabel')) {\n throw new FormatError('Invalid type in PageLabel dictionary.');\n }\n\n var s = labelDict.get('S');\n if (s && !isName(s)) {\n throw new FormatError('Invalid style in PageLabel dictionary.');\n }\n style = s ? s.name : null;\n\n var p = labelDict.get('P');\n if (p && !isString(p)) {\n throw new FormatError('Invalid prefix in PageLabel dictionary.');\n }\n prefix = p ? stringToPDFString(p) : '';\n\n var st = labelDict.get('St');\n if (st && !(isInt(st) && st >= 1)) {\n throw new FormatError('Invalid start in PageLabel dictionary.');\n }\n currentIndex = st || 1;\n }\n\n switch (style) {\n case 'D':\n currentLabel = currentIndex;\n break;\n case 'R':\n case 'r':\n currentLabel = Util.toRoman(currentIndex, style === 'r');\n break;\n case 'A':\n case 'a':\n var LIMIT = 26; // Use only the characters A--Z, or a--z.\n var A_UPPER_CASE = 0x41, A_LOWER_CASE = 0x61;\n\n var baseCharCode = (style === 'a' ? A_LOWER_CASE : A_UPPER_CASE);\n var letterIndex = currentIndex - 1;\n var character = String.fromCharCode(baseCharCode +\n (letterIndex % LIMIT));\n var charBuf = [];\n for (var j = 0, jj = (letterIndex / LIMIT) | 0; j <= jj; j++) {\n charBuf.push(character);\n }\n currentLabel = charBuf.join('');\n break;\n default:\n if (style) {\n throw new FormatError(\n `Invalid style \"${style}\" in PageLabel dictionary.`);\n }\n }\n pageLabels[i] = prefix + currentLabel;\n\n currentLabel = '';\n currentIndex++;\n }\n return pageLabels;\n },\n\n get pageMode() {\n let obj = this.catDict.get('PageMode');\n let pageMode = 'UseNone'; // Default value.\n\n if (isName(obj)) {\n switch (obj.name) {\n case 'UseNone':\n case 'UseOutlines':\n case 'UseThumbs':\n case 'FullScreen':\n case 'UseOC':\n case 'UseAttachments':\n pageMode = obj.name;\n }\n }\n return shadow(this, 'pageMode', pageMode);\n },\n\n get attachments() {\n var xref = this.xref;\n var attachments = null, nameTreeRef;\n var obj = this.catDict.get('Names');\n if (obj) {\n nameTreeRef = obj.getRaw('EmbeddedFiles');\n }\n\n if (nameTreeRef) {\n var nameTree = new NameTree(nameTreeRef, xref);\n var names = nameTree.getAll();\n for (var name in names) {\n var fs = new FileSpec(names[name], xref);\n if (!attachments) {\n attachments = Object.create(null);\n }\n attachments[stringToPDFString(name)] = fs.serializable;\n }\n }\n return shadow(this, 'attachments', attachments);\n },\n get javaScript() {\n var xref = this.xref;\n var obj = this.catDict.get('Names');\n\n var javaScript = [];\n function appendIfJavaScriptDict(jsDict) {\n var type = jsDict.get('S');\n if (!isName(type, 'JavaScript')) {\n return;\n }\n var js = jsDict.get('JS');\n if (isStream(js)) {\n js = bytesToString(js.getBytes());\n } else if (!isString(js)) {\n return;\n }\n javaScript.push(stringToPDFString(js));\n }\n if (obj && obj.has('JavaScript')) {\n var nameTree = new NameTree(obj.getRaw('JavaScript'), xref);\n var names = nameTree.getAll();\n for (var name in names) {\n // We don't really use the JavaScript right now. This code is\n // defensive so we don't cause errors on document load.\n var jsDict = names[name];\n if (isDict(jsDict)) {\n appendIfJavaScriptDict(jsDict);\n }\n }\n }\n\n // Append OpenAction actions to javaScript array\n var openactionDict = this.catDict.get('OpenAction');\n if (isDict(openactionDict, 'Action')) {\n var actionType = openactionDict.get('S');\n if (isName(actionType, 'Named')) {\n // The named Print action is not a part of the PDF 1.7 specification,\n // but is supported by many PDF readers/writers (including Adobe's).\n var action = openactionDict.get('N');\n if (isName(action, 'Print')) {\n javaScript.push('print({});');\n }\n } else {\n appendIfJavaScriptDict(openactionDict);\n }\n }\n\n return shadow(this, 'javaScript', javaScript);\n },\n\n cleanup: function Catalog_cleanup() {\n this.pageKidsCountCache.clear();\n\n var promises = [];\n this.fontCache.forEach(function (promise) {\n promises.push(promise);\n });\n return Promise.all(promises).then((translatedFonts) => {\n for (var i = 0, ii = translatedFonts.length; i < ii; i++) {\n var font = translatedFonts[i].dict;\n delete font.translated;\n }\n this.fontCache.clear();\n this.builtInCMapCache = Object.create(null);\n });\n },\n\n getPage: function Catalog_getPage(pageIndex) {\n if (!(pageIndex in this.pagePromises)) {\n this.pagePromises[pageIndex] = this.getPageDict(pageIndex).then(\n ([dict, ref]) => {\n return this.pageFactory.createPage(pageIndex, dict, ref,\n this.fontCache,\n this.builtInCMapCache);\n });\n }\n return this.pagePromises[pageIndex];\n },\n\n getPageDict: function Catalog_getPageDict(pageIndex) {\n var capability = createPromiseCapability();\n var nodesToVisit = [this.catDict.getRaw('Pages')];\n var count, currentPageIndex = 0;\n var xref = this.xref, pageKidsCountCache = this.pageKidsCountCache;\n\n function next() {\n while (nodesToVisit.length) {\n var currentNode = nodesToVisit.pop();\n\n if (isRef(currentNode)) {\n count = pageKidsCountCache.get(currentNode);\n // Skip nodes where the page can't be.\n if (count > 0 && currentPageIndex + count < pageIndex) {\n currentPageIndex += count;\n continue;\n }\n\n xref.fetchAsync(currentNode).then(function (obj) {\n if (isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids'))) {\n if (pageIndex === currentPageIndex) {\n // Cache the Page reference, since it can *greatly* improve\n // performance by reducing redundant lookups in long documents\n // where all nodes are found at *one* level of the tree.\n if (currentNode && !pageKidsCountCache.has(currentNode)) {\n pageKidsCountCache.put(currentNode, 1);\n }\n capability.resolve([obj, currentNode]);\n } else {\n currentPageIndex++;\n next();\n }\n return;\n }\n nodesToVisit.push(obj);\n next();\n }, capability.reject);\n return;\n }\n\n // Must be a child page dictionary.\n if (!isDict(currentNode)) {\n capability.reject(new FormatError(\n 'page dictionary kid reference points to wrong type of object'));\n return;\n }\n\n count = currentNode.get('Count');\n // Cache the Kids count, since it can reduce redundant lookups in long\n // documents where all nodes are found at *one* level of the tree.\n var objId = currentNode.objId;\n if (objId && !pageKidsCountCache.has(objId)) {\n pageKidsCountCache.put(objId, count);\n }\n // Skip nodes where the page can't be.\n if (currentPageIndex + count <= pageIndex) {\n currentPageIndex += count;\n continue;\n }\n\n var kids = currentNode.get('Kids');\n if (!isArray(kids)) {\n capability.reject(new FormatError(\n 'page dictionary kids object is not an array'));\n return;\n }\n\n // Always check all `Kids` nodes, to avoid getting stuck in an empty\n // node further down in the tree (see issue5644.pdf, issue8088.pdf),\n // and to ensure that we actually find the correct `Page` dict.\n for (var last = kids.length - 1; last >= 0; last--) {\n nodesToVisit.push(kids[last]);\n }\n }\n capability.reject(new Error('Page index ' + pageIndex + ' not found.'));\n }\n next();\n return capability.promise;\n },\n\n getPageIndex: function Catalog_getPageIndex(pageRef) {\n // The page tree nodes have the count of all the leaves below them. To get\n // how many pages are before we just have to walk up the tree and keep\n // adding the count of siblings to the left of the node.\n var xref = this.xref;\n function pagesBeforeRef(kidRef) {\n var total = 0;\n var parentRef;\n return xref.fetchAsync(kidRef).then(function (node) {\n if (isRefsEqual(kidRef, pageRef) && !isDict(node, 'Page') &&\n !(isDict(node) && !node.has('Type') && node.has('Contents'))) {\n throw new FormatError(\n 'The reference does not point to a /Page Dict.');\n }\n if (!node) {\n return null;\n }\n if (!isDict(node)) {\n throw new FormatError('node must be a Dict.');\n }\n parentRef = node.getRaw('Parent');\n return node.getAsync('Parent');\n }).then(function (parent) {\n if (!parent) {\n return null;\n }\n if (!isDict(parent)) {\n throw new FormatError('parent must be a Dict.');\n }\n return parent.getAsync('Kids');\n }).then(function (kids) {\n if (!kids) {\n return null;\n }\n var kidPromises = [];\n var found = false;\n for (var i = 0; i < kids.length; i++) {\n var kid = kids[i];\n if (!isRef(kid)) {\n throw new FormatError('kid must be a Ref.');\n }\n if (kid.num === kidRef.num) {\n found = true;\n break;\n }\n kidPromises.push(xref.fetchAsync(kid).then(function (kid) {\n if (kid.has('Count')) {\n var count = kid.get('Count');\n total += count;\n } else { // page leaf node\n total++;\n }\n }));\n }\n if (!found) {\n throw new FormatError('kid ref not found in parents kids');\n }\n return Promise.all(kidPromises).then(function () {\n return [total, parentRef];\n });\n });\n }\n\n var total = 0;\n function next(ref) {\n return pagesBeforeRef(ref).then(function (args) {\n if (!args) {\n return total;\n }\n var count = args[0];\n var parentRef = args[1];\n total += count;\n return next(parentRef);\n });\n }\n\n return next(pageRef);\n },\n };\n\n /**\n * @typedef ParseDestDictionaryParameters\n * @property {Dict} destDict - The dictionary containing the destination.\n * @property {Object} resultObj - The object where the parsed destination\n * properties will be placed.\n * @property {string} docBaseUrl - (optional) The document base URL that is\n * used when attempting to recover valid absolute URLs from relative ones.\n */\n\n /**\n * Helper function used to parse the contents of destination dictionaries.\n * @param {ParseDestDictionaryParameters} params\n */\n Catalog.parseDestDictionary = function Catalog_parseDestDictionary(params) {\n // Lets URLs beginning with 'www.' default to using the 'http://' protocol.\n function addDefaultProtocolToUrl(url) {\n if (url.indexOf('www.') === 0) {\n return ('http://' + url);\n }\n return url;\n }\n // According to ISO 32000-1:2008, section 12.6.4.7, URIs should be encoded\n // in 7-bit ASCII. Some bad PDFs use UTF-8 encoding, see Bugzilla 1122280.\n function tryConvertUrlEncoding(url) {\n try {\n return stringToUTF8String(url);\n } catch (e) {\n return url;\n }\n }\n\n var destDict = params.destDict;\n if (!isDict(destDict)) {\n warn('Catalog_parseDestDictionary: \"destDict\" must be a dictionary.');\n return;\n }\n var resultObj = params.resultObj;\n if (typeof resultObj !== 'object') {\n warn('Catalog_parseDestDictionary: \"resultObj\" must be an object.');\n return;\n }\n var docBaseUrl = params.docBaseUrl || null;\n\n var action = destDict.get('A'), url, dest;\n if (isDict(action)) {\n var linkType = action.get('S').name;\n switch (linkType) {\n case 'URI':\n url = action.get('URI');\n if (isName(url)) {\n // Some bad PDFs do not put parentheses around relative URLs.\n url = '/' + url.name;\n } else if (isString(url)) {\n url = addDefaultProtocolToUrl(url);\n }\n // TODO: pdf spec mentions urls can be relative to a Base\n // entry in the dictionary.\n break;\n\n case 'GoTo':\n dest = action.get('D');\n break;\n\n case 'Launch':\n // We neither want, nor can, support arbitrary 'Launch' actions.\n // However, in practice they are mostly used for linking to other PDF\n // files, which we thus attempt to support (utilizing `docBaseUrl`).\n /* falls through */\n\n case 'GoToR':\n var urlDict = action.get('F');\n if (isDict(urlDict)) {\n // We assume that we found a FileSpec dictionary\n // and fetch the URL without checking any further.\n url = urlDict.get('F') || null;\n } else if (isString(urlDict)) {\n url = urlDict;\n }\n\n // NOTE: the destination is relative to the *remote* document.\n var remoteDest = action.get('D');\n if (remoteDest) {\n if (isName(remoteDest)) {\n remoteDest = remoteDest.name;\n }\n if (isString(url)) {\n let baseUrl = url.split('#')[0];\n if (isString(remoteDest)) {\n url = baseUrl + '#' + remoteDest;\n } else if (isArray(remoteDest)) {\n url = baseUrl + '#' + JSON.stringify(remoteDest);\n }\n }\n }\n // The 'NewWindow' property, equal to `LinkTarget.BLANK`.\n var newWindow = action.get('NewWindow');\n if (isBool(newWindow)) {\n resultObj.newWindow = newWindow;\n }\n break;\n\n case 'Named':\n var namedAction = action.get('N');\n if (isName(namedAction)) {\n resultObj.action = namedAction.name;\n }\n break;\n\n case 'JavaScript':\n var jsAction = action.get('JS'), js;\n if (isStream(jsAction)) {\n js = bytesToString(jsAction.getBytes());\n } else if (isString(jsAction)) {\n js = jsAction;\n }\n\n if (js) {\n // Attempt to recover valid URLs from 'JS' entries with certain\n // white-listed formats, e.g.\n // - window.open('http://example.com')\n // - app.launchURL('http://example.com', true)\n var URL_OPEN_METHODS = [\n 'app.launchURL',\n 'window.open'\n ];\n var regex = new RegExp(\n '^\\\\s*(' + URL_OPEN_METHODS.join('|').split('.').join('\\\\.') +\n ')\\\\((?:\\'|\\\")([^\\'\\\"]*)(?:\\'|\\\")(?:,\\\\s*(\\\\w+)\\\\)|\\\\))', 'i');\n\n var jsUrl = regex.exec(stringToPDFString(js));\n if (jsUrl && jsUrl[2]) {\n url = jsUrl[2];\n\n if (jsUrl[3] === 'true' && jsUrl[1] === 'app.launchURL') {\n resultObj.newWindow = true;\n }\n break;\n }\n }\n /* falls through */\n default:\n warn('Catalog_parseDestDictionary: Unrecognized link type \"' +\n linkType + '\".');\n break;\n }\n } else if (destDict.has('Dest')) { // Simple destination link.\n dest = destDict.get('Dest');\n }\n\n if (isString(url)) {\n url = tryConvertUrlEncoding(url);\n var absoluteUrl = createValidAbsoluteUrl(url, docBaseUrl);\n if (absoluteUrl) {\n resultObj.url = absoluteUrl.href;\n }\n resultObj.unsafeUrl = url;\n }\n if (dest) {\n if (isName(dest)) {\n dest = dest.name;\n }\n if (isString(dest) || isArray(dest)) {\n resultObj.dest = dest;\n }\n }\n };\n\n return Catalog;\n})();\n\nvar XRef = (function XRefClosure() {\n function XRef(stream, pdfManager) {\n this.stream = stream;\n this.pdfManager = pdfManager;\n this.entries = [];\n this.xrefstms = Object.create(null);\n // prepare the XRef cache\n this.cache = [];\n this.stats = {\n streamTypes: [],\n fontTypes: [],\n };\n }\n\n XRef.prototype = {\n setStartXRef: function XRef_setStartXRef(startXRef) {\n // Store the starting positions of xref tables as we process them\n // so we can recover from missing data errors\n this.startXRefQueue = [startXRef];\n },\n\n parse: function XRef_parse(recoveryMode) {\n var trailerDict;\n if (!recoveryMode) {\n trailerDict = this.readXRef();\n } else {\n warn('Indexing all PDF objects');\n trailerDict = this.indexObjects();\n }\n trailerDict.assignXref(this);\n this.trailer = trailerDict;\n var encrypt = trailerDict.get('Encrypt');\n if (isDict(encrypt)) {\n var ids = trailerDict.get('ID');\n var fileId = (ids && ids.length) ? ids[0] : '';\n // The 'Encrypt' dictionary itself should not be encrypted, and by\n // setting `suppressEncryption` we can prevent an infinite loop inside\n // of `XRef_fetchUncompressed` if the dictionary contains indirect\n // objects (fixes issue7665.pdf).\n encrypt.suppressEncryption = true;\n this.encrypt = new CipherTransformFactory(encrypt, fileId,\n this.pdfManager.password);\n }\n\n // get the root dictionary (catalog) object\n if (!(this.root = trailerDict.get('Root'))) {\n throw new FormatError('Invalid root reference');\n }\n },\n\n processXRefTable: function XRef_processXRefTable(parser) {\n if (!('tableState' in this)) {\n // Stores state of the table as we process it so we can resume\n // from middle of table in case of missing data error\n this.tableState = {\n entryNum: 0,\n streamPos: parser.lexer.stream.pos,\n parserBuf1: parser.buf1,\n parserBuf2: parser.buf2,\n };\n }\n\n var obj = this.readXRefTable(parser);\n\n // Sanity check\n if (!isCmd(obj, 'trailer')) {\n throw new FormatError(\n 'Invalid XRef table: could not find trailer dictionary');\n }\n // Read trailer dictionary, e.g.\n // trailer\n // << /Size 22\n // /Root 20R\n // /Info 10R\n // /ID [ <81b14aafa313db63dbd6f981e49f94f4> ]\n // >>\n // The parser goes through the entire stream << ... >> and provides\n // a getter interface for the key-value table\n var dict = parser.getObj();\n\n // The pdflib PDF generator can generate a nested trailer dictionary\n if (!isDict(dict) && dict.dict) {\n dict = dict.dict;\n }\n if (!isDict(dict)) {\n throw new FormatError(\n 'Invalid XRef table: could not parse trailer dictionary');\n }\n delete this.tableState;\n\n return dict;\n },\n\n readXRefTable: function XRef_readXRefTable(parser) {\n // Example of cross-reference table:\n // xref\n // 0 1 <-- subsection header (first obj #, obj count)\n // 0000000000 65535 f <-- actual object (offset, generation #, f/n)\n // 23 2 <-- subsection header ... and so on ...\n // 0000025518 00002 n\n // 0000025635 00000 n\n // trailer\n // ...\n\n var stream = parser.lexer.stream;\n var tableState = this.tableState;\n stream.pos = tableState.streamPos;\n parser.buf1 = tableState.parserBuf1;\n parser.buf2 = tableState.parserBuf2;\n\n // Outer loop is over subsection headers\n var obj;\n\n while (true) {\n if (!('firstEntryNum' in tableState) || !('entryCount' in tableState)) {\n if (isCmd(obj = parser.getObj(), 'trailer')) {\n break;\n }\n tableState.firstEntryNum = obj;\n tableState.entryCount = parser.getObj();\n }\n\n var first = tableState.firstEntryNum;\n var count = tableState.entryCount;\n if (!isInt(first) || !isInt(count)) {\n throw new FormatError(\n 'Invalid XRef table: wrong types in subsection header');\n }\n // Inner loop is over objects themselves\n for (var i = tableState.entryNum; i < count; i++) {\n tableState.streamPos = stream.pos;\n tableState.entryNum = i;\n tableState.parserBuf1 = parser.buf1;\n tableState.parserBuf2 = parser.buf2;\n\n var entry = {};\n entry.offset = parser.getObj();\n entry.gen = parser.getObj();\n var type = parser.getObj();\n\n if (isCmd(type, 'f')) {\n entry.free = true;\n } else if (isCmd(type, 'n')) {\n entry.uncompressed = true;\n }\n\n // Validate entry obj\n if (!isInt(entry.offset) || !isInt(entry.gen) ||\n !(entry.free || entry.uncompressed)) {\n throw new FormatError(\n `Invalid entry in XRef subsection: ${first}, ${count}`);\n }\n\n // The first xref table entry, i.e. obj 0, should be free. Attempting\n // to adjust an incorrect first obj # (fixes issue 3248 and 7229).\n if (i === 0 && entry.free && first === 1) {\n first = 0;\n }\n\n if (!this.entries[i + first]) {\n this.entries[i + first] = entry;\n }\n }\n\n tableState.entryNum = 0;\n tableState.streamPos = stream.pos;\n tableState.parserBuf1 = parser.buf1;\n tableState.parserBuf2 = parser.buf2;\n delete tableState.firstEntryNum;\n delete tableState.entryCount;\n }\n\n // Sanity check: as per spec, first object must be free\n if (this.entries[0] && !this.entries[0].free) {\n throw new FormatError(\n 'Invalid XRef table: unexpected first object');\n }\n return obj;\n },\n\n processXRefStream: function XRef_processXRefStream(stream) {\n if (!('streamState' in this)) {\n // Stores state of the stream as we process it so we can resume\n // from middle of stream in case of missing data error\n var streamParameters = stream.dict;\n var byteWidths = streamParameters.get('W');\n var range = streamParameters.get('Index');\n if (!range) {\n range = [0, streamParameters.get('Size')];\n }\n\n this.streamState = {\n entryRanges: range,\n byteWidths,\n entryNum: 0,\n streamPos: stream.pos,\n };\n }\n this.readXRefStream(stream);\n delete this.streamState;\n\n return stream.dict;\n },\n\n readXRefStream: function XRef_readXRefStream(stream) {\n var i, j;\n var streamState = this.streamState;\n stream.pos = streamState.streamPos;\n\n var byteWidths = streamState.byteWidths;\n var typeFieldWidth = byteWidths[0];\n var offsetFieldWidth = byteWidths[1];\n var generationFieldWidth = byteWidths[2];\n\n var entryRanges = streamState.entryRanges;\n while (entryRanges.length > 0) {\n var first = entryRanges[0];\n var n = entryRanges[1];\n\n if (!isInt(first) || !isInt(n)) {\n throw new FormatError(\n `Invalid XRef range fields: ${first}, ${n}`);\n }\n if (!isInt(typeFieldWidth) || !isInt(offsetFieldWidth) ||\n !isInt(generationFieldWidth)) {\n throw new FormatError(\n `Invalid XRef entry fields length: ${first}, ${n}`);\n }\n for (i = streamState.entryNum; i < n; ++i) {\n streamState.entryNum = i;\n streamState.streamPos = stream.pos;\n\n var type = 0, offset = 0, generation = 0;\n for (j = 0; j < typeFieldWidth; ++j) {\n type = (type << 8) | stream.getByte();\n }\n // if type field is absent, its default value is 1\n if (typeFieldWidth === 0) {\n type = 1;\n }\n for (j = 0; j < offsetFieldWidth; ++j) {\n offset = (offset << 8) | stream.getByte();\n }\n for (j = 0; j < generationFieldWidth; ++j) {\n generation = (generation << 8) | stream.getByte();\n }\n var entry = {};\n entry.offset = offset;\n entry.gen = generation;\n switch (type) {\n case 0:\n entry.free = true;\n break;\n case 1:\n entry.uncompressed = true;\n break;\n case 2:\n break;\n default:\n throw new FormatError(`Invalid XRef entry type: ${type}`);\n }\n if (!this.entries[first + i]) {\n this.entries[first + i] = entry;\n }\n }\n\n streamState.entryNum = 0;\n streamState.streamPos = stream.pos;\n entryRanges.splice(0, 2);\n }\n },\n\n indexObjects: function XRef_indexObjects() {\n // Simple scan through the PDF content to find objects,\n // trailers and XRef streams.\n var TAB = 0x9, LF = 0xA, CR = 0xD, SPACE = 0x20;\n var PERCENT = 0x25, LT = 0x3C;\n\n function readToken(data, offset) {\n var token = '', ch = data[offset];\n while (ch !== LF && ch !== CR && ch !== LT) {\n if (++offset >= data.length) {\n break;\n }\n token += String.fromCharCode(ch);\n ch = data[offset];\n }\n return token;\n }\n function skipUntil(data, offset, what) {\n var length = what.length, dataLength = data.length;\n var skipped = 0;\n // finding byte sequence\n while (offset < dataLength) {\n var i = 0;\n while (i < length && data[offset + i] === what[i]) {\n ++i;\n }\n if (i >= length) {\n break; // sequence found\n }\n offset++;\n skipped++;\n }\n return skipped;\n }\n var objRegExp = /^(\\d+)\\s+(\\d+)\\s+obj\\b/;\n var trailerBytes = new Uint8Array([116, 114, 97, 105, 108, 101, 114]);\n var startxrefBytes = new Uint8Array([115, 116, 97, 114, 116, 120, 114,\n 101, 102]);\n var endobjBytes = new Uint8Array([101, 110, 100, 111, 98, 106]);\n var xrefBytes = new Uint8Array([47, 88, 82, 101, 102]);\n\n // Clear out any existing entries, since they may be bogus.\n this.entries.length = 0;\n\n var stream = this.stream;\n stream.pos = 0;\n var buffer = stream.getBytes();\n var position = stream.start, length = buffer.length;\n var trailers = [], xrefStms = [];\n while (position < length) {\n var ch = buffer[position];\n if (ch === TAB || ch === LF || ch === CR || ch === SPACE) {\n ++position;\n continue;\n }\n if (ch === PERCENT) { // %-comment\n do {\n ++position;\n if (position >= length) {\n break;\n }\n ch = buffer[position];\n } while (ch !== LF && ch !== CR);\n continue;\n }\n var token = readToken(buffer, position);\n var m;\n if (token.indexOf('xref') === 0 &&\n (token.length === 4 || /\\s/.test(token[4]))) {\n position += skipUntil(buffer, position, trailerBytes);\n trailers.push(position);\n position += skipUntil(buffer, position, startxrefBytes);\n } else if ((m = objRegExp.exec(token))) {\n if (typeof this.entries[m[1]] === 'undefined') {\n this.entries[m[1]] = {\n offset: position - stream.start,\n gen: m[2] | 0,\n uncompressed: true,\n };\n }\n var contentLength = skipUntil(buffer, position, endobjBytes) + 7;\n var content = buffer.subarray(position, position + contentLength);\n\n // checking XRef stream suspect\n // (it shall have '/XRef' and next char is not a letter)\n var xrefTagOffset = skipUntil(content, 0, xrefBytes);\n if (xrefTagOffset < contentLength &&\n content[xrefTagOffset + 5] < 64) {\n xrefStms.push(position - stream.start);\n this.xrefstms[position - stream.start] = 1; // Avoid recursion\n }\n\n position += contentLength;\n } else if (token.indexOf('trailer') === 0 &&\n (token.length === 7 || /\\s/.test(token[7]))) {\n trailers.push(position);\n position += skipUntil(buffer, position, startxrefBytes);\n } else {\n position += token.length + 1;\n }\n }\n // reading XRef streams\n var i, ii;\n for (i = 0, ii = xrefStms.length; i < ii; ++i) {\n this.startXRefQueue.push(xrefStms[i]);\n this.readXRef(/* recoveryMode */ true);\n }\n // finding main trailer\n var dict;\n for (i = 0, ii = trailers.length; i < ii; ++i) {\n stream.pos = trailers[i];\n var parser = new Parser(new Lexer(stream), /* allowStreams = */ true,\n /* xref = */ this, /* recoveryMode = */ true);\n var obj = parser.getObj();\n if (!isCmd(obj, 'trailer')) {\n continue;\n }\n // read the trailer dictionary\n dict = parser.getObj();\n if (!isDict(dict)) {\n continue;\n }\n // taking the first one with 'ID'\n if (dict.has('ID')) {\n return dict;\n }\n }\n // no tailer with 'ID', taking last one (if exists)\n if (dict) {\n return dict;\n }\n // nothing helps\n throw new InvalidPDFException('Invalid PDF structure');\n },\n\n readXRef: function XRef_readXRef(recoveryMode) {\n var stream = this.stream;\n\n try {\n while (this.startXRefQueue.length) {\n var startXRef = this.startXRefQueue[0];\n\n stream.pos = startXRef + stream.start;\n\n var parser = new Parser(new Lexer(stream), true, this);\n var obj = parser.getObj();\n var dict;\n\n // Get dictionary\n if (isCmd(obj, 'xref')) {\n // Parse end-of-file XRef\n dict = this.processXRefTable(parser);\n if (!this.topDict) {\n this.topDict = dict;\n }\n\n // Recursively get other XRefs 'XRefStm', if any\n obj = dict.get('XRefStm');\n if (isInt(obj)) {\n var pos = obj;\n // ignore previously loaded xref streams\n // (possible infinite recursion)\n if (!(pos in this.xrefstms)) {\n this.xrefstms[pos] = 1;\n this.startXRefQueue.push(pos);\n }\n }\n } else if (isInt(obj)) {\n // Parse in-stream XRef\n if (!isInt(parser.getObj()) ||\n !isCmd(parser.getObj(), 'obj') ||\n !isStream(obj = parser.getObj())) {\n throw new FormatError('Invalid XRef stream');\n }\n dict = this.processXRefStream(obj);\n if (!this.topDict) {\n this.topDict = dict;\n }\n if (!dict) {\n throw new FormatError('Failed to read XRef stream');\n }\n } else {\n throw new FormatError('Invalid XRef stream header');\n }\n\n // Recursively get previous dictionary, if any\n obj = dict.get('Prev');\n if (isInt(obj)) {\n this.startXRefQueue.push(obj);\n } else if (isRef(obj)) {\n // The spec says Prev must not be a reference, i.e. \"/Prev NNN\"\n // This is a fallback for non-compliant PDFs, i.e. \"/Prev NNN 0 R\"\n this.startXRefQueue.push(obj.num);\n }\n\n this.startXRefQueue.shift();\n }\n\n return this.topDict;\n } catch (e) {\n if (e instanceof MissingDataException) {\n throw e;\n }\n info('(while reading XRef): ' + e);\n }\n\n if (recoveryMode) {\n return;\n }\n throw new XRefParseException();\n },\n\n getEntry: function XRef_getEntry(i) {\n var xrefEntry = this.entries[i];\n if (xrefEntry && !xrefEntry.free && xrefEntry.offset) {\n return xrefEntry;\n }\n return null;\n },\n\n fetchIfRef: function XRef_fetchIfRef(obj, suppressEncryption) {\n if (!isRef(obj)) {\n return obj;\n }\n return this.fetch(obj, suppressEncryption);\n },\n\n fetch: function XRef_fetch(ref, suppressEncryption) {\n if (!isRef(ref)) {\n throw new Error('ref object is not a reference');\n }\n var num = ref.num;\n if (num in this.cache) {\n var cacheEntry = this.cache[num];\n // In documents with Object Streams, it's possible that cached `Dict`s\n // have not been assigned an `objId` yet (see e.g. issue3115r.pdf).\n if (cacheEntry instanceof Dict && !cacheEntry.objId) {\n cacheEntry.objId = ref.toString();\n }\n return cacheEntry;\n }\n\n var xrefEntry = this.getEntry(num);\n\n // the referenced entry can be free\n if (xrefEntry === null) {\n return (this.cache[num] = null);\n }\n\n if (xrefEntry.uncompressed) {\n xrefEntry = this.fetchUncompressed(ref, xrefEntry, suppressEncryption);\n } else {\n xrefEntry = this.fetchCompressed(xrefEntry, suppressEncryption);\n }\n if (isDict(xrefEntry)) {\n xrefEntry.objId = ref.toString();\n } else if (isStream(xrefEntry)) {\n xrefEntry.dict.objId = ref.toString();\n }\n return xrefEntry;\n },\n\n fetchUncompressed: function XRef_fetchUncompressed(ref, xrefEntry,\n suppressEncryption) {\n var gen = ref.gen;\n var num = ref.num;\n if (xrefEntry.gen !== gen) {\n throw new FormatError('inconsistent generation in XRef');\n }\n var stream = this.stream.makeSubStream(xrefEntry.offset +\n this.stream.start);\n var parser = new Parser(new Lexer(stream), true, this);\n var obj1 = parser.getObj();\n var obj2 = parser.getObj();\n var obj3 = parser.getObj();\n if (!isInt(obj1) || parseInt(obj1, 10) !== num ||\n !isInt(obj2) || parseInt(obj2, 10) !== gen ||\n !isCmd(obj3)) {\n throw new FormatError('bad XRef entry');\n }\n if (!isCmd(obj3, 'obj')) {\n // some bad PDFs use \"obj1234\" and really mean 1234\n if (obj3.cmd.indexOf('obj') === 0) {\n num = parseInt(obj3.cmd.substring(3), 10);\n if (!isNaN(num)) {\n return num;\n }\n }\n throw new FormatError('bad XRef entry');\n }\n if (this.encrypt && !suppressEncryption) {\n xrefEntry = parser.getObj(this.encrypt.createCipherTransform(num, gen));\n } else {\n xrefEntry = parser.getObj();\n }\n if (!isStream(xrefEntry)) {\n this.cache[num] = xrefEntry;\n }\n return xrefEntry;\n },\n\n fetchCompressed: function XRef_fetchCompressed(xrefEntry,\n suppressEncryption) {\n var tableOffset = xrefEntry.offset;\n var stream = this.fetch(new Ref(tableOffset, 0));\n if (!isStream(stream)) {\n throw new FormatError('bad ObjStm stream');\n }\n var first = stream.dict.get('First');\n var n = stream.dict.get('N');\n if (!isInt(first) || !isInt(n)) {\n throw new FormatError(\n 'invalid first and n parameters for ObjStm stream');\n }\n var parser = new Parser(new Lexer(stream), false, this);\n parser.allowStreams = true;\n var i, entries = [], num, nums = [];\n // read the object numbers to populate cache\n for (i = 0; i < n; ++i) {\n num = parser.getObj();\n if (!isInt(num)) {\n throw new FormatError(\n `invalid object number in the ObjStm stream: ${num}`);\n }\n nums.push(num);\n var offset = parser.getObj();\n if (!isInt(offset)) {\n throw new FormatError(\n `invalid object offset in the ObjStm stream: ${offset}`);\n }\n }\n // read stream objects for cache\n for (i = 0; i < n; ++i) {\n entries.push(parser.getObj());\n // The ObjStm should not contain 'endobj'. If it's present, skip over it\n // to support corrupt PDFs (fixes issue 5241, bug 898610, bug 1037816).\n if (isCmd(parser.buf1, 'endobj')) {\n parser.shift();\n }\n num = nums[i];\n var entry = this.entries[num];\n if (entry && entry.offset === tableOffset && entry.gen === i) {\n this.cache[num] = entries[i];\n }\n }\n xrefEntry = entries[xrefEntry.gen];\n if (xrefEntry === undefined) {\n throw new FormatError('bad XRef entry for compressed object');\n }\n return xrefEntry;\n },\n\n fetchIfRefAsync: function XRef_fetchIfRefAsync(obj, suppressEncryption) {\n if (!isRef(obj)) {\n return Promise.resolve(obj);\n }\n return this.fetchAsync(obj, suppressEncryption);\n },\n\n fetchAsync: function XRef_fetchAsync(ref, suppressEncryption) {\n var streamManager = this.stream.manager;\n var xref = this;\n return new Promise(function tryFetch(resolve, reject) {\n try {\n resolve(xref.fetch(ref, suppressEncryption));\n } catch (e) {\n if (e instanceof MissingDataException) {\n streamManager.requestRange(e.begin, e.end).then(function () {\n tryFetch(resolve, reject);\n }, reject);\n return;\n }\n reject(e);\n }\n });\n },\n\n getCatalogObj: function XRef_getCatalogObj() {\n return this.root;\n },\n };\n\n return XRef;\n})();\n\n/**\n * A NameTree/NumberTree is like a Dict but has some advantageous properties,\n * see the specification (7.9.6 and 7.9.7) for additional details.\n * TODO: implement all the Dict functions and make this more efficient.\n */\nvar NameOrNumberTree = (function NameOrNumberTreeClosure() {\n function NameOrNumberTree(root, xref) {\n throw new Error('Cannot initialize NameOrNumberTree.');\n }\n\n NameOrNumberTree.prototype = {\n getAll: function NameOrNumberTree_getAll() {\n var dict = Object.create(null);\n if (!this.root) {\n return dict;\n }\n var xref = this.xref;\n // Reading Name/Number tree.\n var processed = new RefSet();\n processed.put(this.root);\n var queue = [this.root];\n while (queue.length > 0) {\n var i, n;\n var obj = xref.fetchIfRef(queue.shift());\n if (!isDict(obj)) {\n continue;\n }\n if (obj.has('Kids')) {\n var kids = obj.get('Kids');\n for (i = 0, n = kids.length; i < n; i++) {\n var kid = kids[i];\n if (processed.has(kid)) {\n throw new FormatError(`Duplicate entry in \"${this._type}\" tree.`);\n }\n queue.push(kid);\n processed.put(kid);\n }\n continue;\n }\n var entries = obj.get(this._type);\n if (isArray(entries)) {\n for (i = 0, n = entries.length; i < n; i += 2) {\n dict[xref.fetchIfRef(entries[i])] = xref.fetchIfRef(entries[i + 1]);\n }\n }\n }\n return dict;\n },\n\n get: function NameOrNumberTree_get(key) {\n if (!this.root) {\n return null;\n }\n\n var xref = this.xref;\n var kidsOrEntries = xref.fetchIfRef(this.root);\n var loopCount = 0;\n var MAX_LEVELS = 10;\n var l, r, m;\n\n // Perform a binary search to quickly find the entry that\n // contains the key we are looking for.\n while (kidsOrEntries.has('Kids')) {\n if (++loopCount > MAX_LEVELS) {\n warn('Search depth limit reached for \"' + this._type + '\" tree.');\n return null;\n }\n\n var kids = kidsOrEntries.get('Kids');\n if (!isArray(kids)) {\n return null;\n }\n\n l = 0;\n r = kids.length - 1;\n while (l <= r) {\n m = (l + r) >> 1;\n var kid = xref.fetchIfRef(kids[m]);\n var limits = kid.get('Limits');\n\n if (key < xref.fetchIfRef(limits[0])) {\n r = m - 1;\n } else if (key > xref.fetchIfRef(limits[1])) {\n l = m + 1;\n } else {\n kidsOrEntries = xref.fetchIfRef(kids[m]);\n break;\n }\n }\n if (l > r) {\n return null;\n }\n }\n\n // If we get here, then we have found the right entry. Now go through the\n // entries in the dictionary until we find the key we're looking for.\n var entries = kidsOrEntries.get(this._type);\n if (isArray(entries)) {\n // Perform a binary search to reduce the lookup time.\n l = 0;\n r = entries.length - 2;\n while (l <= r) {\n // Check only even indices (0, 2, 4, ...) because the\n // odd indices contain the actual data.\n m = (l + r) & ~1;\n var currentKey = xref.fetchIfRef(entries[m]);\n if (key < currentKey) {\n r = m - 2;\n } else if (key > currentKey) {\n l = m + 2;\n } else {\n return xref.fetchIfRef(entries[m + 1]);\n }\n }\n }\n return null;\n },\n };\n return NameOrNumberTree;\n})();\n\nvar NameTree = (function NameTreeClosure() {\n function NameTree(root, xref) {\n this.root = root;\n this.xref = xref;\n this._type = 'Names';\n }\n\n Util.inherit(NameTree, NameOrNumberTree, {});\n\n return NameTree;\n})();\n\nvar NumberTree = (function NumberTreeClosure() {\n function NumberTree(root, xref) {\n this.root = root;\n this.xref = xref;\n this._type = 'Nums';\n }\n\n Util.inherit(NumberTree, NameOrNumberTree, {});\n\n return NumberTree;\n})();\n\n/**\n * \"A PDF file can refer to the contents of another file by using a File\n * Specification (PDF 1.1)\", see the spec (7.11) for more details.\n * NOTE: Only embedded files are supported (as part of the attachments support)\n * TODO: support the 'URL' file system (with caching if !/V), portable\n * collections attributes and related files (/RF)\n */\nvar FileSpec = (function FileSpecClosure() {\n function FileSpec(root, xref) {\n if (!root || !isDict(root)) {\n return;\n }\n this.xref = xref;\n this.root = root;\n if (root.has('FS')) {\n this.fs = root.get('FS');\n }\n this.description = root.has('Desc') ?\n stringToPDFString(root.get('Desc')) :\n '';\n if (root.has('RF')) {\n warn('Related file specifications are not supported');\n }\n this.contentAvailable = true;\n if (!root.has('EF')) {\n this.contentAvailable = false;\n warn('Non-embedded file specifications are not supported');\n }\n }\n\n function pickPlatformItem(dict) {\n // Look for the filename in this order:\n // UF, F, Unix, Mac, DOS\n if (dict.has('UF')) {\n return dict.get('UF');\n } else if (dict.has('F')) {\n return dict.get('F');\n } else if (dict.has('Unix')) {\n return dict.get('Unix');\n } else if (dict.has('Mac')) {\n return dict.get('Mac');\n } else if (dict.has('DOS')) {\n return dict.get('DOS');\n }\n return null;\n }\n\n FileSpec.prototype = {\n get filename() {\n if (!this._filename && this.root) {\n var filename = pickPlatformItem(this.root) || 'unnamed';\n this._filename = stringToPDFString(filename).\n replace(/\\\\\\\\/g, '\\\\').\n replace(/\\\\\\//g, '/').\n replace(/\\\\/g, '/');\n }\n return this._filename;\n },\n get content() {\n if (!this.contentAvailable) {\n return null;\n }\n if (!this.contentRef && this.root) {\n this.contentRef = pickPlatformItem(this.root.get('EF'));\n }\n var content = null;\n if (this.contentRef) {\n var xref = this.xref;\n var fileObj = xref.fetchIfRef(this.contentRef);\n if (fileObj && isStream(fileObj)) {\n content = fileObj.getBytes();\n } else {\n warn('Embedded file specification points to non-existing/invalid ' +\n 'content');\n }\n } else {\n warn('Embedded file specification does not have a content');\n }\n return content;\n },\n get serializable() {\n return {\n filename: this.filename,\n content: this.content,\n };\n },\n };\n return FileSpec;\n})();\n\n/**\n * A helper for loading missing data in `Dict` graphs. It traverses the graph\n * depth first and queues up any objects that have missing data. Once it has\n * has traversed as many objects that are available it attempts to bundle the\n * missing data requests and then resume from the nodes that weren't ready.\n *\n * NOTE: It provides protection from circular references by keeping track of\n * loaded references. However, you must be careful not to load any graphs\n * that have references to the catalog or other pages since that will cause the\n * entire PDF document object graph to be traversed.\n */\nlet ObjectLoader = (function() {\n function mayHaveChildren(value) {\n return isRef(value) || isDict(value) || isArray(value) || isStream(value);\n }\n\n function addChildren(node, nodesToVisit) {\n if (isDict(node) || isStream(node)) {\n let dict = isDict(node) ? node : node.dict;\n let dictKeys = dict.getKeys();\n for (let i = 0, ii = dictKeys.length; i < ii; i++) {\n let rawValue = dict.getRaw(dictKeys[i]);\n if (mayHaveChildren(rawValue)) {\n nodesToVisit.push(rawValue);\n }\n }\n } else if (isArray(node)) {\n for (let i = 0, ii = node.length; i < ii; i++) {\n let value = node[i];\n if (mayHaveChildren(value)) {\n nodesToVisit.push(value);\n }\n }\n }\n }\n\n function ObjectLoader(dict, keys, xref) {\n this.dict = dict;\n this.keys = keys;\n this.xref = xref;\n this.refSet = null;\n this.capability = null;\n }\n\n ObjectLoader.prototype = {\n load() {\n this.capability = createPromiseCapability();\n // Don't walk the graph if all the data is already loaded.\n if (!(this.xref.stream instanceof ChunkedStream) ||\n this.xref.stream.getMissingChunks().length === 0) {\n this.capability.resolve();\n return this.capability.promise;\n }\n\n let { keys, dict, } = this;\n this.refSet = new RefSet();\n // Setup the initial nodes to visit.\n let nodesToVisit = [];\n for (let i = 0, ii = keys.length; i < ii; i++) {\n let rawValue = dict.getRaw(keys[i]);\n // Skip nodes that are guaranteed to be empty.\n if (rawValue !== undefined) {\n nodesToVisit.push(rawValue);\n }\n }\n\n this._walk(nodesToVisit);\n return this.capability.promise;\n },\n\n _walk(nodesToVisit) {\n let nodesToRevisit = [];\n let pendingRequests = [];\n // DFS walk of the object graph.\n while (nodesToVisit.length) {\n let currentNode = nodesToVisit.pop();\n\n // Only references or chunked streams can cause missing data exceptions.\n if (isRef(currentNode)) {\n // Skip nodes that have already been visited.\n if (this.refSet.has(currentNode)) {\n continue;\n }\n try {\n this.refSet.put(currentNode);\n currentNode = this.xref.fetch(currentNode);\n } catch (ex) {\n if (!(ex instanceof MissingDataException)) {\n throw ex;\n }\n nodesToRevisit.push(currentNode);\n pendingRequests.push({ begin: ex.begin, end: ex.end, });\n }\n }\n if (currentNode && currentNode.getBaseStreams) {\n let baseStreams = currentNode.getBaseStreams();\n let foundMissingData = false;\n for (let i = 0, ii = baseStreams.length; i < ii; i++) {\n let stream = baseStreams[i];\n if (stream.getMissingChunks && stream.getMissingChunks().length) {\n foundMissingData = true;\n pendingRequests.push({ begin: stream.start, end: stream.end, });\n }\n }\n if (foundMissingData) {\n nodesToRevisit.push(currentNode);\n }\n }\n\n addChildren(currentNode, nodesToVisit);\n }\n\n if (pendingRequests.length) {\n this.xref.stream.manager.requestRanges(pendingRequests).then(() => {\n for (let i = 0, ii = nodesToRevisit.length; i < ii; i++) {\n let node = nodesToRevisit[i];\n // Remove any reference nodes from the current `RefSet` so they\n // aren't skipped when we revist them.\n if (isRef(node)) {\n this.refSet.remove(node);\n }\n }\n this._walk(nodesToRevisit);\n }, this.capability.reject);\n return;\n }\n // Everything is loaded.\n this.refSet = null;\n this.capability.resolve();\n },\n };\n\n return ObjectLoader;\n})();\n\nexport {\n Catalog,\n ObjectLoader,\n XRef,\n FileSpec,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/obj.js","/* Copyright 2015 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getLookupTableFactory } from '../shared/util';\n\n/**\n * Hold a map of decoded fonts and of the standard fourteen Type1\n * fonts and their acronyms.\n */\nvar getStdFontMap = getLookupTableFactory(function (t) {\n t['ArialNarrow'] = 'Helvetica';\n t['ArialNarrow-Bold'] = 'Helvetica-Bold';\n t['ArialNarrow-BoldItalic'] = 'Helvetica-BoldOblique';\n t['ArialNarrow-Italic'] = 'Helvetica-Oblique';\n t['ArialBlack'] = 'Helvetica';\n t['ArialBlack-Bold'] = 'Helvetica-Bold';\n t['ArialBlack-BoldItalic'] = 'Helvetica-BoldOblique';\n t['ArialBlack-Italic'] = 'Helvetica-Oblique';\n t['Arial-Black'] = 'Helvetica';\n t['Arial-Black-Bold'] = 'Helvetica-Bold';\n t['Arial-Black-BoldItalic'] = 'Helvetica-BoldOblique';\n t['Arial-Black-Italic'] = 'Helvetica-Oblique';\n t['Arial'] = 'Helvetica';\n t['Arial-Bold'] = 'Helvetica-Bold';\n t['Arial-BoldItalic'] = 'Helvetica-BoldOblique';\n t['Arial-Italic'] = 'Helvetica-Oblique';\n t['Arial-BoldItalicMT'] = 'Helvetica-BoldOblique';\n t['Arial-BoldMT'] = 'Helvetica-Bold';\n t['Arial-ItalicMT'] = 'Helvetica-Oblique';\n t['ArialMT'] = 'Helvetica';\n t['Courier-Bold'] = 'Courier-Bold';\n t['Courier-BoldItalic'] = 'Courier-BoldOblique';\n t['Courier-Italic'] = 'Courier-Oblique';\n t['CourierNew'] = 'Courier';\n t['CourierNew-Bold'] = 'Courier-Bold';\n t['CourierNew-BoldItalic'] = 'Courier-BoldOblique';\n t['CourierNew-Italic'] = 'Courier-Oblique';\n t['CourierNewPS-BoldItalicMT'] = 'Courier-BoldOblique';\n t['CourierNewPS-BoldMT'] = 'Courier-Bold';\n t['CourierNewPS-ItalicMT'] = 'Courier-Oblique';\n t['CourierNewPSMT'] = 'Courier';\n t['Helvetica'] = 'Helvetica';\n t['Helvetica-Bold'] = 'Helvetica-Bold';\n t['Helvetica-BoldItalic'] = 'Helvetica-BoldOblique';\n t['Helvetica-BoldOblique'] = 'Helvetica-BoldOblique';\n t['Helvetica-Italic'] = 'Helvetica-Oblique';\n t['Helvetica-Oblique'] = 'Helvetica-Oblique';\n t['SegoeUISymbol'] = 'Helvetica';\n t['Symbol-Bold'] = 'Symbol';\n t['Symbol-BoldItalic'] = 'Symbol';\n t['Symbol-Italic'] = 'Symbol';\n t['TimesNewRoman'] = 'Times-Roman';\n t['TimesNewRoman-Bold'] = 'Times-Bold';\n t['TimesNewRoman-BoldItalic'] = 'Times-BoldItalic';\n t['TimesNewRoman-Italic'] = 'Times-Italic';\n t['TimesNewRomanPS'] = 'Times-Roman';\n t['TimesNewRomanPS-Bold'] = 'Times-Bold';\n t['TimesNewRomanPS-BoldItalic'] = 'Times-BoldItalic';\n t['TimesNewRomanPS-BoldItalicMT'] = 'Times-BoldItalic';\n t['TimesNewRomanPS-BoldMT'] = 'Times-Bold';\n t['TimesNewRomanPS-Italic'] = 'Times-Italic';\n t['TimesNewRomanPS-ItalicMT'] = 'Times-Italic';\n t['TimesNewRomanPSMT'] = 'Times-Roman';\n t['TimesNewRomanPSMT-Bold'] = 'Times-Bold';\n t['TimesNewRomanPSMT-BoldItalic'] = 'Times-BoldItalic';\n t['TimesNewRomanPSMT-Italic'] = 'Times-Italic';\n});\n\n/**\n * Holds the map of the non-standard fonts that might be included as\n * a standard fonts without glyph data.\n */\nvar getNonStdFontMap = getLookupTableFactory(function (t) {\n t['CenturyGothic'] = 'Helvetica';\n t['CenturyGothic-Bold'] = 'Helvetica-Bold';\n t['CenturyGothic-BoldItalic'] = 'Helvetica-BoldOblique';\n t['CenturyGothic-Italic'] = 'Helvetica-Oblique';\n t['ComicSansMS'] = 'Comic Sans MS';\n t['ComicSansMS-Bold'] = 'Comic Sans MS-Bold';\n t['ComicSansMS-BoldItalic'] = 'Comic Sans MS-BoldItalic';\n t['ComicSansMS-Italic'] = 'Comic Sans MS-Italic';\n t['LucidaConsole'] = 'Courier';\n t['LucidaConsole-Bold'] = 'Courier-Bold';\n t['LucidaConsole-BoldItalic'] = 'Courier-BoldOblique';\n t['LucidaConsole-Italic'] = 'Courier-Oblique';\n t['MS-Gothic'] = 'MS Gothic';\n t['MS-Gothic-Bold'] = 'MS Gothic-Bold';\n t['MS-Gothic-BoldItalic'] = 'MS Gothic-BoldItalic';\n t['MS-Gothic-Italic'] = 'MS Gothic-Italic';\n t['MS-Mincho'] = 'MS Mincho';\n t['MS-Mincho-Bold'] = 'MS Mincho-Bold';\n t['MS-Mincho-BoldItalic'] = 'MS Mincho-BoldItalic';\n t['MS-Mincho-Italic'] = 'MS Mincho-Italic';\n t['MS-PGothic'] = 'MS PGothic';\n t['MS-PGothic-Bold'] = 'MS PGothic-Bold';\n t['MS-PGothic-BoldItalic'] = 'MS PGothic-BoldItalic';\n t['MS-PGothic-Italic'] = 'MS PGothic-Italic';\n t['MS-PMincho'] = 'MS PMincho';\n t['MS-PMincho-Bold'] = 'MS PMincho-Bold';\n t['MS-PMincho-BoldItalic'] = 'MS PMincho-BoldItalic';\n t['MS-PMincho-Italic'] = 'MS PMincho-Italic';\n t['NuptialScript'] = 'Times-Italic';\n t['Wingdings'] = 'ZapfDingbats';\n});\n\nvar getSerifFonts = getLookupTableFactory(function (t) {\n t['Adobe Jenson'] = true;\n t['Adobe Text'] = true;\n t['Albertus'] = true;\n t['Aldus'] = true;\n t['Alexandria'] = true;\n t['Algerian'] = true;\n t['American Typewriter'] = true;\n t['Antiqua'] = true;\n t['Apex'] = true;\n t['Arno'] = true;\n t['Aster'] = true;\n t['Aurora'] = true;\n t['Baskerville'] = true;\n t['Bell'] = true;\n t['Bembo'] = true;\n t['Bembo Schoolbook'] = true;\n t['Benguiat'] = true;\n t['Berkeley Old Style'] = true;\n t['Bernhard Modern'] = true;\n t['Berthold City'] = true;\n t['Bodoni'] = true;\n t['Bauer Bodoni'] = true;\n t['Book Antiqua'] = true;\n t['Bookman'] = true;\n t['Bordeaux Roman'] = true;\n t['Californian FB'] = true;\n t['Calisto'] = true;\n t['Calvert'] = true;\n t['Capitals'] = true;\n t['Cambria'] = true;\n t['Cartier'] = true;\n t['Caslon'] = true;\n t['Catull'] = true;\n t['Centaur'] = true;\n t['Century Old Style'] = true;\n t['Century Schoolbook'] = true;\n t['Chaparral'] = true;\n t['Charis SIL'] = true;\n t['Cheltenham'] = true;\n t['Cholla Slab'] = true;\n t['Clarendon'] = true;\n t['Clearface'] = true;\n t['Cochin'] = true;\n t['Colonna'] = true;\n t['Computer Modern'] = true;\n t['Concrete Roman'] = true;\n t['Constantia'] = true;\n t['Cooper Black'] = true;\n t['Corona'] = true;\n t['Ecotype'] = true;\n t['Egyptienne'] = true;\n t['Elephant'] = true;\n t['Excelsior'] = true;\n t['Fairfield'] = true;\n t['FF Scala'] = true;\n t['Folkard'] = true;\n t['Footlight'] = true;\n t['FreeSerif'] = true;\n t['Friz Quadrata'] = true;\n t['Garamond'] = true;\n t['Gentium'] = true;\n t['Georgia'] = true;\n t['Gloucester'] = true;\n t['Goudy Old Style'] = true;\n t['Goudy Schoolbook'] = true;\n t['Goudy Pro Font'] = true;\n t['Granjon'] = true;\n t['Guardian Egyptian'] = true;\n t['Heather'] = true;\n t['Hercules'] = true;\n t['High Tower Text'] = true;\n t['Hiroshige'] = true;\n t['Hoefler Text'] = true;\n t['Humana Serif'] = true;\n t['Imprint'] = true;\n t['Ionic No. 5'] = true;\n t['Janson'] = true;\n t['Joanna'] = true;\n t['Korinna'] = true;\n t['Lexicon'] = true;\n t['Liberation Serif'] = true;\n t['Linux Libertine'] = true;\n t['Literaturnaya'] = true;\n t['Lucida'] = true;\n t['Lucida Bright'] = true;\n t['Melior'] = true;\n t['Memphis'] = true;\n t['Miller'] = true;\n t['Minion'] = true;\n t['Modern'] = true;\n t['Mona Lisa'] = true;\n t['Mrs Eaves'] = true;\n t['MS Serif'] = true;\n t['Museo Slab'] = true;\n t['New York'] = true;\n t['Nimbus Roman'] = true;\n t['NPS Rawlinson Roadway'] = true;\n t['NuptialScript'] = true;\n t['Palatino'] = true;\n t['Perpetua'] = true;\n t['Plantin'] = true;\n t['Plantin Schoolbook'] = true;\n t['Playbill'] = true;\n t['Poor Richard'] = true;\n t['Rawlinson Roadway'] = true;\n t['Renault'] = true;\n t['Requiem'] = true;\n t['Rockwell'] = true;\n t['Roman'] = true;\n t['Rotis Serif'] = true;\n t['Sabon'] = true;\n t['Scala'] = true;\n t['Seagull'] = true;\n t['Sistina'] = true;\n t['Souvenir'] = true;\n t['STIX'] = true;\n t['Stone Informal'] = true;\n t['Stone Serif'] = true;\n t['Sylfaen'] = true;\n t['Times'] = true;\n t['Trajan'] = true;\n t['TrinitΓ©'] = true;\n t['Trump Mediaeval'] = true;\n t['Utopia'] = true;\n t['Vale Type'] = true;\n t['Bitstream Vera'] = true;\n t['Vera Serif'] = true;\n t['Versailles'] = true;\n t['Wanted'] = true;\n t['Weiss'] = true;\n t['Wide Latin'] = true;\n t['Windsor'] = true;\n t['XITS'] = true;\n});\n\nvar getSymbolsFonts = getLookupTableFactory(function (t) {\n t['Dingbats'] = true;\n t['Symbol'] = true;\n t['ZapfDingbats'] = true;\n});\n\n// Glyph map for well-known standard fonts. Sometimes Ghostscript uses CID\n// fonts, but does not embed the CID to GID mapping. The mapping is incomplete\n// for all glyphs, but common for some set of the standard fonts.\nvar getGlyphMapForStandardFonts = getLookupTableFactory(function (t) {\n t[2] = 10; t[3] = 32; t[4] = 33; t[5] = 34; t[6] = 35; t[7] = 36; t[8] = 37;\n t[9] = 38; t[10] = 39; t[11] = 40; t[12] = 41; t[13] = 42; t[14] = 43;\n t[15] = 44; t[16] = 45; t[17] = 46; t[18] = 47; t[19] = 48; t[20] = 49;\n t[21] = 50; t[22] = 51; t[23] = 52; t[24] = 53; t[25] = 54; t[26] = 55;\n t[27] = 56; t[28] = 57; t[29] = 58; t[30] = 894; t[31] = 60; t[32] = 61;\n t[33] = 62; t[34] = 63; t[35] = 64; t[36] = 65; t[37] = 66; t[38] = 67;\n t[39] = 68; t[40] = 69; t[41] = 70; t[42] = 71; t[43] = 72; t[44] = 73;\n t[45] = 74; t[46] = 75; t[47] = 76; t[48] = 77; t[49] = 78; t[50] = 79;\n t[51] = 80; t[52] = 81; t[53] = 82; t[54] = 83; t[55] = 84; t[56] = 85;\n t[57] = 86; t[58] = 87; t[59] = 88; t[60] = 89; t[61] = 90; t[62] = 91;\n t[63] = 92; t[64] = 93; t[65] = 94; t[66] = 95; t[67] = 96; t[68] = 97;\n t[69] = 98; t[70] = 99; t[71] = 100; t[72] = 101; t[73] = 102; t[74] = 103;\n t[75] = 104; t[76] = 105; t[77] = 106; t[78] = 107; t[79] = 108;\n t[80] = 109; t[81] = 110; t[82] = 111; t[83] = 112; t[84] = 113;\n t[85] = 114; t[86] = 115; t[87] = 116; t[88] = 117; t[89] = 118;\n t[90] = 119; t[91] = 120; t[92] = 121; t[93] = 122; t[94] = 123;\n t[95] = 124; t[96] = 125; t[97] = 126; t[98] = 196; t[99] = 197;\n t[100] = 199; t[101] = 201; t[102] = 209; t[103] = 214; t[104] = 220;\n t[105] = 225; t[106] = 224; t[107] = 226; t[108] = 228; t[109] = 227;\n t[110] = 229; t[111] = 231; t[112] = 233; t[113] = 232; t[114] = 234;\n t[115] = 235; t[116] = 237; t[117] = 236; t[118] = 238; t[119] = 239;\n t[120] = 241; t[121] = 243; t[122] = 242; t[123] = 244; t[124] = 246;\n t[125] = 245; t[126] = 250; t[127] = 249; t[128] = 251; t[129] = 252;\n t[130] = 8224; t[131] = 176; t[132] = 162; t[133] = 163; t[134] = 167;\n t[135] = 8226; t[136] = 182; t[137] = 223; t[138] = 174; t[139] = 169;\n t[140] = 8482; t[141] = 180; t[142] = 168; t[143] = 8800; t[144] = 198;\n t[145] = 216; t[146] = 8734; t[147] = 177; t[148] = 8804; t[149] = 8805;\n t[150] = 165; t[151] = 181; t[152] = 8706; t[153] = 8721; t[154] = 8719;\n t[156] = 8747; t[157] = 170; t[158] = 186; t[159] = 8486; t[160] = 230;\n t[161] = 248; t[162] = 191; t[163] = 161; t[164] = 172; t[165] = 8730;\n t[166] = 402; t[167] = 8776; t[168] = 8710; t[169] = 171; t[170] = 187;\n t[171] = 8230; t[210] = 218; t[223] = 711; t[224] = 321; t[225] = 322;\n t[227] = 353; t[229] = 382; t[234] = 253; t[252] = 263; t[253] = 268;\n t[254] = 269; t[258] = 258; t[260] = 260; t[261] = 261; t[265] = 280;\n t[266] = 281; t[268] = 283; t[269] = 313; t[275] = 323; t[276] = 324;\n t[278] = 328; t[284] = 345; t[285] = 346; t[286] = 347; t[292] = 367;\n t[295] = 377; t[296] = 378; t[298] = 380; t[305] = 963; t[306] = 964;\n t[307] = 966; t[308] = 8215; t[309] = 8252; t[310] = 8319; t[311] = 8359;\n t[312] = 8592; t[313] = 8593; t[337] = 9552; t[493] = 1039;\n t[494] = 1040; t[705] = 1524; t[706] = 8362; t[710] = 64288; t[711] = 64298;\n t[759] = 1617; t[761] = 1776; t[763] = 1778; t[775] = 1652; t[777] = 1764;\n t[778] = 1780; t[779] = 1781; t[780] = 1782; t[782] = 771; t[783] = 64726;\n t[786] = 8363; t[788] = 8532; t[790] = 768; t[791] = 769; t[792] = 768;\n t[795] = 803; t[797] = 64336; t[798] = 64337; t[799] = 64342;\n t[800] = 64343; t[801] = 64344; t[802] = 64345; t[803] = 64362;\n t[804] = 64363; t[805] = 64364; t[2424] = 7821; t[2425] = 7822;\n t[2426] = 7823; t[2427] = 7824; t[2428] = 7825; t[2429] = 7826;\n t[2430] = 7827; t[2433] = 7682; t[2678] = 8045; t[2679] = 8046;\n t[2830] = 1552; t[2838] = 686; t[2840] = 751; t[2842] = 753; t[2843] = 754;\n t[2844] = 755; t[2846] = 757; t[2856] = 767; t[2857] = 848; t[2858] = 849;\n t[2862] = 853; t[2863] = 854; t[2864] = 855; t[2865] = 861; t[2866] = 862;\n t[2906] = 7460; t[2908] = 7462; t[2909] = 7463; t[2910] = 7464;\n t[2912] = 7466; t[2913] = 7467; t[2914] = 7468; t[2916] = 7470;\n t[2917] = 7471; t[2918] = 7472; t[2920] = 7474; t[2921] = 7475;\n t[2922] = 7476; t[2924] = 7478; t[2925] = 7479; t[2926] = 7480;\n t[2928] = 7482; t[2929] = 7483; t[2930] = 7484; t[2932] = 7486;\n t[2933] = 7487; t[2934] = 7488; t[2936] = 7490; t[2937] = 7491;\n t[2938] = 7492; t[2940] = 7494; t[2941] = 7495; t[2942] = 7496;\n t[2944] = 7498; t[2946] = 7500; t[2948] = 7502; t[2950] = 7504;\n t[2951] = 7505; t[2952] = 7506; t[2954] = 7508; t[2955] = 7509;\n t[2956] = 7510; t[2958] = 7512; t[2959] = 7513; t[2960] = 7514;\n t[2962] = 7516; t[2963] = 7517; t[2964] = 7518; t[2966] = 7520;\n t[2967] = 7521; t[2968] = 7522; t[2970] = 7524; t[2971] = 7525;\n t[2972] = 7526; t[2974] = 7528; t[2975] = 7529; t[2976] = 7530;\n t[2978] = 1537; t[2979] = 1538; t[2980] = 1539; t[2982] = 1549;\n t[2983] = 1551; t[2984] = 1552; t[2986] = 1554; t[2987] = 1555;\n t[2988] = 1556; t[2990] = 1623; t[2991] = 1624; t[2995] = 1775;\n t[2999] = 1791; t[3002] = 64290; t[3003] = 64291; t[3004] = 64292;\n t[3006] = 64294; t[3007] = 64295; t[3008] = 64296; t[3011] = 1900;\n t[3014] = 8223; t[3015] = 8244; t[3017] = 7532; t[3018] = 7533;\n t[3019] = 7534; t[3075] = 7590; t[3076] = 7591; t[3079] = 7594;\n t[3080] = 7595; t[3083] = 7598; t[3084] = 7599; t[3087] = 7602;\n t[3088] = 7603; t[3091] = 7606; t[3092] = 7607; t[3095] = 7610;\n t[3096] = 7611; t[3099] = 7614; t[3100] = 7615; t[3103] = 7618;\n t[3104] = 7619; t[3107] = 8337; t[3108] = 8338; t[3116] = 1884;\n t[3119] = 1885; t[3120] = 1885; t[3123] = 1886; t[3124] = 1886;\n t[3127] = 1887; t[3128] = 1887; t[3131] = 1888; t[3132] = 1888;\n t[3135] = 1889; t[3136] = 1889; t[3139] = 1890; t[3140] = 1890;\n t[3143] = 1891; t[3144] = 1891; t[3147] = 1892; t[3148] = 1892;\n t[3153] = 580; t[3154] = 581; t[3157] = 584; t[3158] = 585; t[3161] = 588;\n t[3162] = 589; t[3165] = 891; t[3166] = 892; t[3169] = 1274; t[3170] = 1275;\n t[3173] = 1278; t[3174] = 1279; t[3181] = 7622; t[3182] = 7623;\n t[3282] = 11799; t[3316] = 578; t[3379] = 42785; t[3393] = 1159;\n t[3416] = 8377;\n});\n\n// The glyph map for ArialBlack differs slightly from the glyph map used for\n// other well-known standard fonts. Hence we use this (incomplete) CID to GID\n// mapping to adjust the glyph map for non-embedded ArialBlack fonts.\nvar getSupplementalGlyphMapForArialBlack =\n getLookupTableFactory(function (t) {\n t[227] = 322; t[264] = 261; t[291] = 346;\n});\n\nexport {\n getStdFontMap,\n getNonStdFontMap,\n getSerifFonts,\n getSymbolsFonts,\n getGlyphMapForStandardFonts,\n getSupplementalGlyphMapForArialBlack,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/standard_fonts.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n arrayByteLength, arraysToBytes, assert, createPromiseCapability, info,\n InvalidPDFException, isNodeJS, MessageHandler, MissingPDFException,\n PasswordException, setVerbosityLevel, UnexpectedResponseException,\n UnknownErrorException, UNSUPPORTED_FEATURES, warn, XRefParseException\n} from '../shared/util';\nimport { LocalPdfManager, NetworkPdfManager } from './pdf_manager';\nimport { Ref } from './primitives';\n\nvar WorkerTask = (function WorkerTaskClosure() {\n function WorkerTask(name) {\n this.name = name;\n this.terminated = false;\n this._capability = createPromiseCapability();\n }\n\n WorkerTask.prototype = {\n get finished() {\n return this._capability.promise;\n },\n\n finish() {\n this._capability.resolve();\n },\n\n terminate() {\n this.terminated = true;\n },\n\n ensureNotTerminated() {\n if (this.terminated) {\n throw new Error('Worker task was terminated');\n }\n },\n };\n\n return WorkerTask;\n})();\n\nif (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('PRODUCTION')) {\n/**\n * Interface that represents PDF data transport. If possible, it allows\n * progressively load entire or fragment of the PDF binary data.\n *\n * @interface\n */\nfunction IPDFStream() {} // eslint-disable-line no-inner-declarations\nIPDFStream.prototype = {\n /**\n * Gets a reader for the entire PDF data.\n * @returns {IPDFStreamReader}\n */\n getFullReader() {\n return null;\n },\n\n /**\n * Gets a reader for the range of the PDF data.\n * @param {number} begin - the start offset of the data.\n * @param {number} end - the end offset of the data.\n * @returns {IPDFStreamRangeReader}\n */\n getRangeReader(begin, end) {\n return null;\n },\n\n /**\n * Cancels all opened reader and closes all their opened requests.\n * @param {Object} reason - the reason for cancelling\n */\n cancelAllRequests(reason) {},\n};\n\n/**\n * Interface for a PDF binary data reader.\n *\n * @interface\n */\nfunction IPDFStreamReader() {} // eslint-disable-line no-inner-declarations\nIPDFStreamReader.prototype = {\n /**\n * Gets a promise that is resolved when the headers and other metadata of\n * the PDF data stream are available.\n * @returns {Promise}\n */\n get headersReady() {\n return null;\n },\n\n /**\n * Gets PDF binary data length. It is defined after the headersReady promise\n * is resolved.\n * @returns {number} The data length (or 0 if unknown).\n */\n get contentLength() {\n return 0;\n },\n\n /**\n * Gets ability of the stream to handle range requests. It is defined after\n * the headersReady promise is resolved. Rejected when the reader is cancelled\n * or an error occurs.\n * @returns {boolean}\n */\n get isRangeSupported() {\n return false;\n },\n\n /**\n * Gets ability of the stream to progressively load binary data. It is defined\n * after the headersReady promise is resolved.\n * @returns {boolean}\n */\n get isStreamingSupported() {\n return false;\n },\n\n /**\n * Requests a chunk of the binary data. The method returns the promise, which\n * is resolved into object with properties \"value\" and \"done\". If the done\n * is set to true, then the stream has reached its end, otherwise the value\n * contains binary data. Cancelled requests will be resolved with the done is\n * set to true.\n * @returns {Promise}\n */\n read() {},\n\n /**\n * Cancels all pending read requests and closes the stream.\n * @param {Object} reason\n */\n cancel(reason) {},\n\n /**\n * Sets or gets the progress callback. The callback can be useful when the\n * isStreamingSupported property of the object is defined as false.\n * The callback is called with one parameter: an object with the loaded and\n * total properties.\n */\n onProgress: null,\n};\n\n/**\n * Interface for a PDF binary data fragment reader.\n *\n * @interface\n */\nfunction IPDFStreamRangeReader() {} // eslint-disable-line no-inner-declarations\nIPDFStreamRangeReader.prototype = {\n /**\n * Gets ability of the stream to progressively load binary data.\n * @returns {boolean}\n */\n get isStreamingSupported() {\n return false;\n },\n\n /**\n * Requests a chunk of the binary data. The method returns the promise, which\n * is resolved into object with properties \"value\" and \"done\". If the done\n * is set to true, then the stream has reached its end, otherwise the value\n * contains binary data. Cancelled requests will be resolved with the done is\n * set to true.\n * @returns {Promise}\n */\n read() {},\n\n /**\n * Cancels all pending read requests and closes the stream.\n * @param {Object} reason\n */\n cancel(reason) {},\n\n /**\n * Sets or gets the progress callback. The callback can be useful when the\n * isStreamingSupported property of the object is defined as false.\n * The callback is called with one parameter: an object with the loaded\n * property.\n */\n onProgress: null,\n};\n}\n\n/** @implements {IPDFStream} */\nvar PDFWorkerStream = (function PDFWorkerStreamClosure() {\n function PDFWorkerStream(msgHandler) {\n this._msgHandler = msgHandler;\n this._contentLength = null;\n this._fullRequestReader = null;\n this._rangeRequestReaders = [];\n }\n PDFWorkerStream.prototype = {\n getFullReader() {\n assert(!this._fullRequestReader);\n this._fullRequestReader = new PDFWorkerStreamReader(this._msgHandler);\n return this._fullRequestReader;\n },\n\n getRangeReader(begin, end) {\n let reader = new PDFWorkerStreamRangeReader(begin, end, this._msgHandler);\n this._rangeRequestReaders.push(reader);\n return reader;\n },\n\n cancelAllRequests(reason) {\n if (this._fullRequestReader) {\n this._fullRequestReader.cancel(reason);\n }\n let readers = this._rangeRequestReaders.slice(0);\n readers.forEach(function (reader) {\n reader.cancel(reason);\n });\n },\n };\n\n /** @implements {IPDFStreamReader} */\n function PDFWorkerStreamReader(msgHandler) {\n this._msgHandler = msgHandler;\n\n this._contentLength = null;\n this._isRangeSupported = false;\n this._isStreamingSupported = false;\n\n let readableStream = this._msgHandler.sendWithStream('GetReader');\n\n this._reader = readableStream.getReader();\n\n this._headersReady = this._msgHandler.sendWithPromise('ReaderHeadersReady').\n then((data) => {\n this._isStreamingSupported = data.isStreamingSupported;\n this._isRangeSupported = data.isRangeSupported;\n this._contentLength = data.contentLength;\n });\n }\n PDFWorkerStreamReader.prototype = {\n get headersReady() {\n return this._headersReady;\n },\n\n get contentLength() {\n return this._contentLength;\n },\n\n get isStreamingSupported() {\n return this._isStreamingSupported;\n },\n\n get isRangeSupported() {\n return this._isRangeSupported;\n },\n\n read() {\n return this._reader.read().then(function({ value, done, }) {\n if (done) {\n return { value: undefined, done: true, };\n }\n // `value` is wrapped into Uint8Array, we need to\n // unwrap it to ArrayBuffer for further processing.\n return { value: value.buffer, done: false, };\n });\n },\n\n cancel(reason) {\n this._reader.cancel(reason);\n },\n };\n\n /** @implements {IPDFStreamRangeReader} */\n function PDFWorkerStreamRangeReader(begin, end, msgHandler) {\n this._msgHandler = msgHandler;\n this.onProgress = null;\n\n let readableStream = this._msgHandler.sendWithStream('GetRangeReader',\n { begin, end, });\n\n this._reader = readableStream.getReader();\n }\n PDFWorkerStreamRangeReader.prototype = {\n get isStreamingSupported() {\n return false;\n },\n\n read() {\n return this._reader.read().then(function({ value, done, }) {\n if (done) {\n return { value: undefined, done: true, };\n }\n return { value: value.buffer, done: false, };\n });\n },\n\n cancel(reason) {\n this._reader.cancel(reason);\n },\n };\n\n return PDFWorkerStream;\n})();\n\nvar WorkerMessageHandler = {\n setup(handler, port) {\n var testMessageProcessed = false;\n handler.on('test', function wphSetupTest(data) {\n if (testMessageProcessed) {\n return; // we already processed 'test' message once\n }\n testMessageProcessed = true;\n\n // check if Uint8Array can be sent to worker\n if (!(data instanceof Uint8Array)) {\n handler.send('test', 'main', false);\n return;\n }\n // making sure postMessage transfers are working\n var supportTransfers = data[0] === 255;\n handler.postMessageTransfers = supportTransfers;\n // check if the response property is supported by xhr\n var xhr = new XMLHttpRequest();\n var responseExists = 'response' in xhr;\n // check if the property is actually implemented\n try {\n xhr.responseType; // eslint-disable-line no-unused-expressions\n } catch (e) {\n responseExists = false;\n }\n if (!responseExists) {\n handler.send('test', false);\n return;\n }\n handler.send('test', {\n supportTypedArray: true,\n supportTransfers,\n });\n });\n\n handler.on('configure', function wphConfigure(data) {\n setVerbosityLevel(data.verbosity);\n });\n\n handler.on('GetDocRequest', function wphSetupDoc(data) {\n return WorkerMessageHandler.createDocumentHandler(data, port);\n });\n },\n createDocumentHandler(docParams, port) {\n // This context is actually holds references on pdfManager and handler,\n // until the latter is destroyed.\n var pdfManager;\n var terminated = false;\n var cancelXHRs = null;\n var WorkerTasks = [];\n\n var docId = docParams.docId;\n var docBaseUrl = docParams.docBaseUrl;\n var workerHandlerName = docParams.docId + '_worker';\n var handler = new MessageHandler(workerHandlerName, docId, port);\n\n // Ensure that postMessage transfers are correctly enabled/disabled,\n // to prevent \"DataCloneError\" in older versions of IE (see issue 6957).\n handler.postMessageTransfers = docParams.postMessageTransfers;\n\n function ensureNotTerminated() {\n if (terminated) {\n throw new Error('Worker was terminated');\n }\n }\n\n function startWorkerTask(task) {\n WorkerTasks.push(task);\n }\n\n function finishWorkerTask(task) {\n task.finish();\n var i = WorkerTasks.indexOf(task);\n WorkerTasks.splice(i, 1);\n }\n\n function loadDocument(recoveryMode) {\n var loadDocumentCapability = createPromiseCapability();\n\n var parseSuccess = function parseSuccess() {\n var numPagesPromise = pdfManager.ensureDoc('numPages');\n var fingerprintPromise = pdfManager.ensureDoc('fingerprint');\n var encryptedPromise = pdfManager.ensureXRef('encrypt');\n Promise.all([numPagesPromise, fingerprintPromise,\n encryptedPromise]).then(function onDocReady(results) {\n var doc = {\n numPages: results[0],\n fingerprint: results[1],\n encrypted: !!results[2],\n };\n loadDocumentCapability.resolve(doc);\n },\n parseFailure);\n };\n\n var parseFailure = function parseFailure(e) {\n loadDocumentCapability.reject(e);\n };\n\n pdfManager.ensureDoc('checkHeader', []).then(function() {\n pdfManager.ensureDoc('parseStartXRef', []).then(function() {\n pdfManager.ensureDoc('parse', [recoveryMode]).then(\n parseSuccess, parseFailure);\n }, parseFailure);\n }, parseFailure);\n\n return loadDocumentCapability.promise;\n }\n\n function getPdfManager(data, evaluatorOptions) {\n var pdfManagerCapability = createPromiseCapability();\n var pdfManager;\n\n var source = data.source;\n if (source.data) {\n try {\n pdfManager = new LocalPdfManager(docId, source.data, source.password,\n evaluatorOptions, docBaseUrl);\n pdfManagerCapability.resolve(pdfManager);\n } catch (ex) {\n pdfManagerCapability.reject(ex);\n }\n return pdfManagerCapability.promise;\n }\n\n var pdfStream, cachedChunks = [];\n try {\n pdfStream = new PDFWorkerStream(handler);\n } catch (ex) {\n pdfManagerCapability.reject(ex);\n return pdfManagerCapability.promise;\n }\n\n var fullRequest = pdfStream.getFullReader();\n fullRequest.headersReady.then(function () {\n if (!fullRequest.isRangeSupported) {\n return;\n }\n\n // We don't need auto-fetch when streaming is enabled.\n var disableAutoFetch = source.disableAutoFetch ||\n fullRequest.isStreamingSupported;\n pdfManager = new NetworkPdfManager(docId, pdfStream, {\n msgHandler: handler,\n url: source.url,\n password: source.password,\n length: fullRequest.contentLength,\n disableAutoFetch,\n rangeChunkSize: source.rangeChunkSize,\n }, evaluatorOptions, docBaseUrl);\n // There may be a chance that `pdfManager` is not initialized\n // for first few runs of `readchunk` block of code. Be sure\n // to send all cached chunks, if any, to chunked_stream via\n // pdf_manager.\n for (let i = 0; i < cachedChunks.length; i++) {\n pdfManager.sendProgressiveData(cachedChunks[i]);\n }\n\n cachedChunks = [];\n pdfManagerCapability.resolve(pdfManager);\n cancelXHRs = null;\n }).catch(function (reason) {\n pdfManagerCapability.reject(reason);\n cancelXHRs = null;\n });\n\n var loaded = 0;\n var flushChunks = function () {\n var pdfFile = arraysToBytes(cachedChunks);\n if (source.length && pdfFile.length !== source.length) {\n warn('reported HTTP length is different from actual');\n }\n // the data is array, instantiating directly from it\n try {\n pdfManager = new LocalPdfManager(docId, pdfFile, source.password,\n evaluatorOptions, docBaseUrl);\n pdfManagerCapability.resolve(pdfManager);\n } catch (ex) {\n pdfManagerCapability.reject(ex);\n }\n cachedChunks = [];\n };\n var readPromise = new Promise(function (resolve, reject) {\n var readChunk = function (chunk) {\n try {\n ensureNotTerminated();\n if (chunk.done) {\n if (!pdfManager) {\n flushChunks();\n }\n cancelXHRs = null;\n return;\n }\n\n var data = chunk.value;\n loaded += arrayByteLength(data);\n if (!fullRequest.isStreamingSupported) {\n handler.send('DocProgress', {\n loaded,\n total: Math.max(loaded, fullRequest.contentLength || 0),\n });\n }\n\n if (pdfManager) {\n pdfManager.sendProgressiveData(data);\n } else {\n cachedChunks.push(data);\n }\n\n fullRequest.read().then(readChunk, reject);\n } catch (e) {\n reject(e);\n }\n };\n fullRequest.read().then(readChunk, reject);\n });\n readPromise.catch(function (e) {\n pdfManagerCapability.reject(e);\n cancelXHRs = null;\n });\n\n cancelXHRs = function () {\n pdfStream.cancelAllRequests('abort');\n };\n\n return pdfManagerCapability.promise;\n }\n\n function setupDoc(data) {\n function onSuccess(doc) {\n ensureNotTerminated();\n handler.send('GetDoc', { pdfInfo: doc, });\n }\n\n function onFailure(e) {\n ensureNotTerminated();\n\n if (e instanceof PasswordException) {\n var task = new WorkerTask('PasswordException: response ' + e.code);\n startWorkerTask(task);\n\n handler.sendWithPromise('PasswordRequest', e).then(function (data) {\n finishWorkerTask(task);\n pdfManager.updatePassword(data.password);\n pdfManagerReady();\n }).catch(function (ex) {\n finishWorkerTask(task);\n handler.send('PasswordException', ex);\n }.bind(null, e));\n } else if (e instanceof InvalidPDFException) {\n handler.send('InvalidPDF', e);\n } else if (e instanceof MissingPDFException) {\n handler.send('MissingPDF', e);\n } else if (e instanceof UnexpectedResponseException) {\n handler.send('UnexpectedResponse', e);\n } else {\n handler.send('UnknownError',\n new UnknownErrorException(e.message, e.toString()));\n }\n }\n\n function pdfManagerReady() {\n ensureNotTerminated();\n\n loadDocument(false).then(onSuccess, function loadFailure(ex) {\n ensureNotTerminated();\n\n // Try again with recoveryMode == true\n if (!(ex instanceof XRefParseException)) {\n onFailure(ex);\n return;\n }\n pdfManager.requestLoadedStream();\n pdfManager.onLoadedStream().then(function() {\n ensureNotTerminated();\n\n loadDocument(true).then(onSuccess, onFailure);\n });\n }, onFailure);\n }\n\n ensureNotTerminated();\n\n var evaluatorOptions = {\n forceDataSchema: data.disableCreateObjectURL,\n maxImageSize: data.maxImageSize === undefined ? -1 : data.maxImageSize,\n disableFontFace: data.disableFontFace,\n nativeImageDecoderSupport: data.nativeImageDecoderSupport,\n ignoreErrors: data.ignoreErrors,\n };\n\n getPdfManager(data, evaluatorOptions).then(function (newPdfManager) {\n if (terminated) {\n // We were in a process of setting up the manager, but it got\n // terminated in the middle.\n newPdfManager.terminate();\n throw new Error('Worker was terminated');\n }\n\n pdfManager = newPdfManager;\n handler.send('PDFManagerReady', null);\n pdfManager.onLoadedStream().then(function(stream) {\n handler.send('DataLoaded', { length: stream.bytes.byteLength, });\n });\n }).then(pdfManagerReady, onFailure);\n }\n\n handler.on('GetPage', function wphSetupGetPage(data) {\n return pdfManager.getPage(data.pageIndex).then(function(page) {\n var rotatePromise = pdfManager.ensure(page, 'rotate');\n var refPromise = pdfManager.ensure(page, 'ref');\n var userUnitPromise = pdfManager.ensure(page, 'userUnit');\n var viewPromise = pdfManager.ensure(page, 'view');\n\n return Promise.all([\n rotatePromise, refPromise, userUnitPromise, viewPromise\n ]).then(function(results) {\n return {\n rotate: results[0],\n ref: results[1],\n userUnit: results[2],\n view: results[3],\n };\n });\n });\n });\n\n handler.on('GetPageIndex', function wphSetupGetPageIndex(data) {\n var ref = new Ref(data.ref.num, data.ref.gen);\n var catalog = pdfManager.pdfDocument.catalog;\n return catalog.getPageIndex(ref);\n });\n\n handler.on('GetDestinations',\n function wphSetupGetDestinations(data) {\n return pdfManager.ensureCatalog('destinations');\n }\n );\n\n handler.on('GetDestination',\n function wphSetupGetDestination(data) {\n return pdfManager.ensureCatalog('getDestination', [data.id]);\n }\n );\n\n handler.on('GetPageLabels',\n function wphSetupGetPageLabels(data) {\n return pdfManager.ensureCatalog('pageLabels');\n }\n );\n\n handler.on('GetPageMode', function wphSetupGetPageMode(data) {\n return pdfManager.ensureCatalog('pageMode');\n });\n\n handler.on('GetAttachments',\n function wphSetupGetAttachments(data) {\n return pdfManager.ensureCatalog('attachments');\n }\n );\n\n handler.on('GetJavaScript',\n function wphSetupGetJavaScript(data) {\n return pdfManager.ensureCatalog('javaScript');\n }\n );\n\n handler.on('GetOutline',\n function wphSetupGetOutline(data) {\n return pdfManager.ensureCatalog('documentOutline');\n }\n );\n\n handler.on('GetMetadata',\n function wphSetupGetMetadata(data) {\n return Promise.all([pdfManager.ensureDoc('documentInfo'),\n pdfManager.ensureCatalog('metadata')]);\n }\n );\n\n handler.on('GetData', function wphSetupGetData(data) {\n pdfManager.requestLoadedStream();\n return pdfManager.onLoadedStream().then(function(stream) {\n return stream.bytes;\n });\n });\n\n handler.on('GetStats',\n function wphSetupGetStats(data) {\n return pdfManager.pdfDocument.xref.stats;\n }\n );\n\n handler.on('GetAnnotations', function wphSetupGetAnnotations(data) {\n return pdfManager.getPage(data.pageIndex).then(function(page) {\n return pdfManager.ensure(page, 'getAnnotationsData', [data.intent]);\n });\n });\n\n handler.on('RenderPageRequest', function wphSetupRenderPage(data) {\n var pageIndex = data.pageIndex;\n pdfManager.getPage(pageIndex).then(function(page) {\n var task = new WorkerTask('RenderPageRequest: page ' + pageIndex);\n startWorkerTask(task);\n\n var pageNum = pageIndex + 1;\n var start = Date.now();\n // Pre compile the pdf page and fetch the fonts/images.\n page.getOperatorList({\n handler,\n task,\n intent: data.intent,\n renderInteractiveForms: data.renderInteractiveForms,\n }).then(function(operatorList) {\n finishWorkerTask(task);\n\n info('page=' + pageNum + ' - getOperatorList: time=' +\n (Date.now() - start) + 'ms, len=' + operatorList.totalLength);\n }, function(e) {\n finishWorkerTask(task);\n if (task.terminated) {\n return; // ignoring errors from the terminated thread\n }\n\n // For compatibility with older behavior, generating unknown\n // unsupported feature notification on errors.\n handler.send('UnsupportedFeature',\n { featureId: UNSUPPORTED_FEATURES.unknown, });\n\n var minimumStackMessage =\n 'worker.js: while trying to getPage() and getOperatorList()';\n\n var wrappedException;\n\n // Turn the error into an obj that can be serialized\n if (typeof e === 'string') {\n wrappedException = {\n message: e,\n stack: minimumStackMessage,\n };\n } else if (typeof e === 'object') {\n wrappedException = {\n message: e.message || e.toString(),\n stack: e.stack || minimumStackMessage,\n };\n } else {\n wrappedException = {\n message: 'Unknown exception type: ' + (typeof e),\n stack: minimumStackMessage,\n };\n }\n\n handler.send('PageError', {\n pageNum,\n error: wrappedException,\n intent: data.intent,\n });\n });\n });\n }, this);\n\n handler.on('GetTextContent', function wphExtractText(data, sink) {\n var pageIndex = data.pageIndex;\n sink.onPull = function (desiredSize) { };\n sink.onCancel = function (reason) { };\n\n pdfManager.getPage(pageIndex).then(function(page) {\n var task = new WorkerTask('GetTextContent: page ' + pageIndex);\n startWorkerTask(task);\n\n var pageNum = pageIndex + 1;\n var start = Date.now();\n page.extractTextContent({\n handler,\n task,\n sink,\n normalizeWhitespace: data.normalizeWhitespace,\n combineTextItems: data.combineTextItems,\n }).then(function() {\n finishWorkerTask(task);\n\n info('text indexing: page=' + pageNum + ' - time=' +\n (Date.now() - start) + 'ms');\n sink.close();\n }, function (reason) {\n finishWorkerTask(task);\n if (task.terminated) {\n return; // ignoring errors from the terminated thread\n }\n sink.error(reason);\n throw reason;\n });\n });\n });\n\n handler.on('Cleanup', function wphCleanup(data) {\n return pdfManager.cleanup();\n });\n\n handler.on('Terminate', function wphTerminate(data) {\n terminated = true;\n if (pdfManager) {\n pdfManager.terminate();\n pdfManager = null;\n }\n if (cancelXHRs) {\n cancelXHRs();\n }\n\n var waitOn = [];\n WorkerTasks.forEach(function (task) {\n waitOn.push(task.finished);\n task.terminate();\n });\n\n return Promise.all(waitOn).then(function () {\n // Notice that even if we destroying handler, resolved response promise\n // must be sent back.\n handler.destroy();\n handler = null;\n });\n });\n\n handler.on('Ready', function wphReady(data) {\n setupDoc(docParams);\n docParams = null; // we don't need docParams anymore -- saving memory.\n });\n return workerHandlerName;\n },\n initializeFromPort(port) {\n var handler = new MessageHandler('worker', 'main', port);\n WorkerMessageHandler.setup(handler, port);\n handler.send('ready', null);\n },\n};\n\nfunction isMessagePort(maybePort) {\n return typeof maybePort.postMessage === 'function' &&\n ('onmessage' in maybePort);\n}\n\n// Worker thread (and not node.js)?\nif (typeof window === 'undefined' && !isNodeJS() &&\n typeof self !== 'undefined' && isMessagePort(self)) {\n WorkerMessageHandler.initializeFromPort(self);\n}\n\nexport {\n WorkerTask,\n WorkerMessageHandler,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/worker.js","/*\n * To the extent possible under law, the authors have dedicated all copyright\n * and related and neighboring rights to this software to the public\n * domain worldwide. This software is distributed without any warranty.\n *\n * You should have received a copy of the CC0 Public Domain Dedication along\n * with this software. If not, see https://creativecommons.org/publicdomain/zero/1.0/.\n */\n\n(function(e, a) { for(var i in a) e[i] = a[i]; }(exports, /******/ (function(modules) { // webpackBootstrap\n/******/ // The module cache\n/******/ var installedModules = {};\n/******/\n/******/ // The require function\n/******/ function __w_pdfjs_require__(moduleId) {\n/******/\n/******/ // Check if module is in cache\n/******/ if(installedModules[moduleId])\n/******/ return installedModules[moduleId].exports;\n/******/\n/******/ // Create a new module (and put it into the cache)\n/******/ var module = installedModules[moduleId] = {\n/******/ i: moduleId,\n/******/ l: false,\n/******/ exports: {}\n/******/ };\n/******/\n/******/ // Execute the module function\n/******/ modules[moduleId].call(module.exports, module, module.exports, __w_pdfjs_require__);\n/******/\n/******/ // Flag the module as loaded\n/******/ module.l = true;\n/******/\n/******/ // Return the exports of the module\n/******/ return module.exports;\n/******/ }\n/******/\n/******/\n/******/ // expose the modules object (__webpack_modules__)\n/******/ __w_pdfjs_require__.m = modules;\n/******/\n/******/ // expose the module cache\n/******/ __w_pdfjs_require__.c = installedModules;\n/******/\n/******/ // identity function for calling harmony imports with the correct context\n/******/ __w_pdfjs_require__.i = function(value) { return value; };\n/******/\n/******/ // define getter function for harmony exports\n/******/ __w_pdfjs_require__.d = function(exports, name, getter) {\n/******/ if(!__w_pdfjs_require__.o(exports, name)) {\n/******/ Object.defineProperty(exports, name, {\n/******/ configurable: false,\n/******/ enumerable: true,\n/******/ get: getter\n/******/ });\n/******/ }\n/******/ };\n/******/\n/******/ // getDefaultExport function for compatibility with non-harmony modules\n/******/ __w_pdfjs_require__.n = function(module) {\n/******/ var getter = module && module.__esModule ?\n/******/ function getDefault() { return module['default']; } :\n/******/ function getModuleExports() { return module; };\n/******/ __w_pdfjs_require__.d(getter, 'a', getter);\n/******/ return getter;\n/******/ };\n/******/\n/******/ // Object.prototype.hasOwnProperty.call\n/******/ __w_pdfjs_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ // __webpack_public_path__\n/******/ __w_pdfjs_require__.p = \"\";\n/******/\n/******/ // Load entry module and return exports\n/******/ return __w_pdfjs_require__(__w_pdfjs_require__.s = 7);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports, __w_pdfjs_require__) {\n\n\"use strict\";\n\n\nvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; };\n\nvar _require = __w_pdfjs_require__(1),\n assert = _require.assert;\n\nfunction IsPropertyKey(argument) {\n return typeof argument === 'string' || (typeof argument === 'undefined' ? 'undefined' : _typeof(argument)) === 'symbol';\n}\n\nexports.typeIsObject = function (x) {\n return (typeof x === 'undefined' ? 'undefined' : _typeof(x)) === 'object' && x !== null || typeof x === 'function';\n};\n\nexports.createDataProperty = function (o, p, v) {\n assert(exports.typeIsObject(o));\n Object.defineProperty(o, p, { value: v, writable: true, enumerable: true, configurable: true });\n};\n\nexports.createArrayFromList = function (elements) {\n // We use arrays to represent lists, so this is basically a no-op.\n // Do a slice though just in case we happen to depend on the unique-ness.\n return elements.slice();\n};\n\nexports.ArrayBufferCopy = function (dest, destOffset, src, srcOffset, n) {\n new Uint8Array(dest).set(new Uint8Array(src, srcOffset, n), destOffset);\n};\n\nexports.CreateIterResultObject = function (value, done) {\n assert(typeof done === 'boolean');\n var obj = {};\n Object.defineProperty(obj, 'value', { value: value, enumerable: true, writable: true, configurable: true });\n Object.defineProperty(obj, 'done', { value: done, enumerable: true, writable: true, configurable: true });\n return obj;\n};\n\nexports.IsFiniteNonNegativeNumber = function (v) {\n if (Number.isNaN(v)) {\n return false;\n }\n if (v === Infinity) {\n return false;\n }\n if (v < 0) {\n return false;\n }\n\n return true;\n};\n\nfunction Call(F, V, args) {\n if (typeof F !== 'function') {\n throw new TypeError('Argument is not a function');\n }\n\n return Function.prototype.apply.call(F, V, args);\n}\n\nexports.InvokeOrNoop = function (O, P, args) {\n assert(O !== undefined);\n assert(IsPropertyKey(P));\n assert(Array.isArray(args));\n\n var method = O[P];\n if (method === undefined) {\n return undefined;\n }\n\n return Call(method, O, args);\n};\n\nexports.PromiseInvokeOrNoop = function (O, P, args) {\n assert(O !== undefined);\n assert(IsPropertyKey(P));\n assert(Array.isArray(args));\n try {\n return Promise.resolve(exports.InvokeOrNoop(O, P, args));\n } catch (returnValueE) {\n return Promise.reject(returnValueE);\n }\n};\n\nexports.PromiseInvokeOrPerformFallback = function (O, P, args, F, argsF) {\n assert(O !== undefined);\n assert(IsPropertyKey(P));\n assert(Array.isArray(args));\n assert(Array.isArray(argsF));\n\n var method = void 0;\n try {\n method = O[P];\n } catch (methodE) {\n return Promise.reject(methodE);\n }\n\n if (method === undefined) {\n return F.apply(null, argsF);\n }\n\n try {\n return Promise.resolve(Call(method, O, args));\n } catch (e) {\n return Promise.reject(e);\n }\n};\n\n// Not implemented correctly\nexports.TransferArrayBuffer = function (O) {\n return O.slice();\n};\n\nexports.ValidateAndNormalizeHighWaterMark = function (highWaterMark) {\n highWaterMark = Number(highWaterMark);\n if (Number.isNaN(highWaterMark) || highWaterMark < 0) {\n throw new RangeError('highWaterMark property of a queuing strategy must be non-negative and non-NaN');\n }\n\n return highWaterMark;\n};\n\nexports.ValidateAndNormalizeQueuingStrategy = function (size, highWaterMark) {\n if (size !== undefined && typeof size !== 'function') {\n throw new TypeError('size property of a queuing strategy must be a function');\n }\n\n highWaterMark = exports.ValidateAndNormalizeHighWaterMark(highWaterMark);\n\n return { size: size, highWaterMark: highWaterMark };\n};\n\n/***/ }),\n/* 1 */\n/***/ (function(module, exports, __w_pdfjs_require__) {\n\n\"use strict\";\n\n\nfunction rethrowAssertionErrorRejection(e) {\n // Used throughout the reference implementation, as `.catch(rethrowAssertionErrorRejection)`, to ensure any errors\n // get shown. There are places in the spec where we do promise transformations and purposefully ignore or don't\n // expect any errors, but assertion errors are always problematic.\n if (e && e.constructor === AssertionError) {\n setTimeout(function () {\n throw e;\n }, 0);\n }\n};\n\nfunction AssertionError(message) {\n this.name = 'AssertionError';\n this.message = message || '';\n this.stack = new Error().stack;\n}\nAssertionError.prototype = Object.create(Error.prototype);\nAssertionError.prototype.constructor = AssertionError;\n\nfunction assert(value, message) {\n if (!value) {\n throw new AssertionError(message);\n }\n}\n\nmodule.exports = {\n rethrowAssertionErrorRejection: rethrowAssertionErrorRejection,\n AssertionError: AssertionError,\n assert: assert\n};\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports, __w_pdfjs_require__) {\n\n\"use strict\";\n\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar _require = __w_pdfjs_require__(0),\n InvokeOrNoop = _require.InvokeOrNoop,\n PromiseInvokeOrNoop = _require.PromiseInvokeOrNoop,\n ValidateAndNormalizeQueuingStrategy = _require.ValidateAndNormalizeQueuingStrategy,\n typeIsObject = _require.typeIsObject;\n\nvar _require2 = __w_pdfjs_require__(1),\n assert = _require2.assert,\n rethrowAssertionErrorRejection = _require2.rethrowAssertionErrorRejection;\n\nvar _require3 = __w_pdfjs_require__(3),\n DequeueValue = _require3.DequeueValue,\n EnqueueValueWithSize = _require3.EnqueueValueWithSize,\n PeekQueueValue = _require3.PeekQueueValue,\n ResetQueue = _require3.ResetQueue;\n\nvar WritableStream = function () {\n function WritableStream() {\n var underlyingSink = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n size = _ref.size,\n _ref$highWaterMark = _ref.highWaterMark,\n highWaterMark = _ref$highWaterMark === undefined ? 1 : _ref$highWaterMark;\n\n _classCallCheck(this, WritableStream);\n\n this._state = 'writable';\n\n // The error that will be reported by new method calls once the state becomes errored. Only set when [[state]] is\n // 'erroring' or 'errored'. May be set to an undefined value.\n this._storedError = undefined;\n\n this._writer = undefined;\n\n // Initialize to undefined first because the constructor of the controller checks this\n // variable to validate the caller.\n this._writableStreamController = undefined;\n\n // This queue is placed here instead of the writer class in order to allow for passing a writer to the next data\n // producer without waiting for the queued writes to finish.\n this._writeRequests = [];\n\n // Write requests are removed from _writeRequests when write() is called on the underlying sink. This prevents\n // them from being erroneously rejected on error. If a write() call is in-flight, the request is stored here.\n this._inFlightWriteRequest = undefined;\n\n // The promise that was returned from writer.close(). Stored here because it may be fulfilled after the writer\n // has been detached.\n this._closeRequest = undefined;\n\n // Close request is removed from _closeRequest when close() is called on the underlying sink. This prevents it\n // from being erroneously rejected on error. If a close() call is in-flight, the request is stored here.\n this._inFlightCloseRequest = undefined;\n\n // The promise that was returned from writer.abort(). This may also be fulfilled after the writer has detached.\n this._pendingAbortRequest = undefined;\n\n // The backpressure signal set by the controller.\n this._backpressure = false;\n\n var type = underlyingSink.type;\n\n if (type !== undefined) {\n throw new RangeError('Invalid type is specified');\n }\n\n this._writableStreamController = new WritableStreamDefaultController(this, underlyingSink, size, highWaterMark);\n this._writableStreamController.__startSteps();\n }\n\n _createClass(WritableStream, [{\n key: 'abort',\n value: function abort(reason) {\n if (IsWritableStream(this) === false) {\n return Promise.reject(streamBrandCheckException('abort'));\n }\n\n if (IsWritableStreamLocked(this) === true) {\n return Promise.reject(new TypeError('Cannot abort a stream that already has a writer'));\n }\n\n return WritableStreamAbort(this, reason);\n }\n }, {\n key: 'getWriter',\n value: function getWriter() {\n if (IsWritableStream(this) === false) {\n throw streamBrandCheckException('getWriter');\n }\n\n return AcquireWritableStreamDefaultWriter(this);\n }\n }, {\n key: 'locked',\n get: function get() {\n if (IsWritableStream(this) === false) {\n throw streamBrandCheckException('locked');\n }\n\n return IsWritableStreamLocked(this);\n }\n }]);\n\n return WritableStream;\n}();\n\nmodule.exports = {\n AcquireWritableStreamDefaultWriter: AcquireWritableStreamDefaultWriter,\n IsWritableStream: IsWritableStream,\n IsWritableStreamLocked: IsWritableStreamLocked,\n WritableStream: WritableStream,\n WritableStreamAbort: WritableStreamAbort,\n WritableStreamDefaultControllerError: WritableStreamDefaultControllerError,\n WritableStreamDefaultWriterCloseWithErrorPropagation: WritableStreamDefaultWriterCloseWithErrorPropagation,\n WritableStreamDefaultWriterRelease: WritableStreamDefaultWriterRelease,\n WritableStreamDefaultWriterWrite: WritableStreamDefaultWriterWrite,\n WritableStreamCloseQueuedOrInFlight: WritableStreamCloseQueuedOrInFlight\n};\n\n// Abstract operations for the WritableStream.\n\nfunction AcquireWritableStreamDefaultWriter(stream) {\n return new WritableStreamDefaultWriter(stream);\n}\n\nfunction IsWritableStream(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_writableStreamController')) {\n return false;\n }\n\n return true;\n}\n\nfunction IsWritableStreamLocked(stream) {\n assert(IsWritableStream(stream) === true, 'IsWritableStreamLocked should only be used on known writable streams');\n\n if (stream._writer === undefined) {\n return false;\n }\n\n return true;\n}\n\nfunction WritableStreamAbort(stream, reason) {\n var state = stream._state;\n if (state === 'closed') {\n return Promise.resolve(undefined);\n }\n if (state === 'errored') {\n return Promise.reject(stream._storedError);\n }\n var error = new TypeError('Requested to abort');\n if (stream._pendingAbortRequest !== undefined) {\n return Promise.reject(error);\n }\n\n assert(state === 'writable' || state === 'erroring', 'state must be writable or erroring');\n\n var wasAlreadyErroring = false;\n if (state === 'erroring') {\n wasAlreadyErroring = true;\n // reason will not be used, so don't keep a reference to it.\n reason = undefined;\n }\n\n var promise = new Promise(function (resolve, reject) {\n stream._pendingAbortRequest = {\n _resolve: resolve,\n _reject: reject,\n _reason: reason,\n _wasAlreadyErroring: wasAlreadyErroring\n };\n });\n\n if (wasAlreadyErroring === false) {\n WritableStreamStartErroring(stream, error);\n }\n\n return promise;\n}\n\n// WritableStream API exposed for controllers.\n\nfunction WritableStreamAddWriteRequest(stream) {\n assert(IsWritableStreamLocked(stream) === true);\n assert(stream._state === 'writable');\n\n var promise = new Promise(function (resolve, reject) {\n var writeRequest = {\n _resolve: resolve,\n _reject: reject\n };\n\n stream._writeRequests.push(writeRequest);\n });\n\n return promise;\n}\n\nfunction WritableStreamDealWithRejection(stream, error) {\n var state = stream._state;\n\n if (state === 'writable') {\n WritableStreamStartErroring(stream, error);\n return;\n }\n\n assert(state === 'erroring');\n WritableStreamFinishErroring(stream);\n}\n\nfunction WritableStreamStartErroring(stream, reason) {\n assert(stream._storedError === undefined, 'stream._storedError === undefined');\n assert(stream._state === 'writable', 'state must be writable');\n\n var controller = stream._writableStreamController;\n assert(controller !== undefined, 'controller must not be undefined');\n\n stream._state = 'erroring';\n stream._storedError = reason;\n var writer = stream._writer;\n if (writer !== undefined) {\n WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason);\n }\n\n if (WritableStreamHasOperationMarkedInFlight(stream) === false && controller._started === true) {\n WritableStreamFinishErroring(stream);\n }\n}\n\nfunction WritableStreamFinishErroring(stream) {\n assert(stream._state === 'erroring', 'stream._state === erroring');\n assert(WritableStreamHasOperationMarkedInFlight(stream) === false, 'WritableStreamHasOperationMarkedInFlight(stream) === false');\n stream._state = 'errored';\n stream._writableStreamController.__errorSteps();\n\n var storedError = stream._storedError;\n for (var i = 0; i < stream._writeRequests.length; i++) {\n var writeRequest = stream._writeRequests[i];\n writeRequest._reject(storedError);\n }\n stream._writeRequests = [];\n\n if (stream._pendingAbortRequest === undefined) {\n WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);\n return;\n }\n\n var abortRequest = stream._pendingAbortRequest;\n stream._pendingAbortRequest = undefined;\n\n if (abortRequest._wasAlreadyErroring === true) {\n abortRequest._reject(storedError);\n WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);\n return;\n }\n\n var promise = stream._writableStreamController.__abortSteps(abortRequest._reason);\n promise.then(function () {\n abortRequest._resolve();\n WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);\n }, function (reason) {\n abortRequest._reject(reason);\n WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);\n });\n}\n\nfunction WritableStreamFinishInFlightWrite(stream) {\n assert(stream._inFlightWriteRequest !== undefined);\n stream._inFlightWriteRequest._resolve(undefined);\n stream._inFlightWriteRequest = undefined;\n}\n\nfunction WritableStreamFinishInFlightWriteWithError(stream, error) {\n assert(stream._inFlightWriteRequest !== undefined);\n stream._inFlightWriteRequest._reject(error);\n stream._inFlightWriteRequest = undefined;\n\n assert(stream._state === 'writable' || stream._state === 'erroring');\n\n WritableStreamDealWithRejection(stream, error);\n}\n\nfunction WritableStreamFinishInFlightClose(stream) {\n assert(stream._inFlightCloseRequest !== undefined);\n stream._inFlightCloseRequest._resolve(undefined);\n stream._inFlightCloseRequest = undefined;\n\n var state = stream._state;\n\n assert(state === 'writable' || state === 'erroring');\n\n if (state === 'erroring') {\n // The error was too late to do anything, so it is ignored.\n stream._storedError = undefined;\n if (stream._pendingAbortRequest !== undefined) {\n stream._pendingAbortRequest._resolve();\n stream._pendingAbortRequest = undefined;\n }\n }\n\n stream._state = 'closed';\n\n var writer = stream._writer;\n if (writer !== undefined) {\n defaultWriterClosedPromiseResolve(writer);\n }\n\n assert(stream._pendingAbortRequest === undefined, 'stream._pendingAbortRequest === undefined');\n assert(stream._storedError === undefined, 'stream._storedError === undefined');\n}\n\nfunction WritableStreamFinishInFlightCloseWithError(stream, error) {\n assert(stream._inFlightCloseRequest !== undefined);\n stream._inFlightCloseRequest._reject(error);\n stream._inFlightCloseRequest = undefined;\n\n assert(stream._state === 'writable' || stream._state === 'erroring');\n\n // Never execute sink abort() after sink close().\n if (stream._pendingAbortRequest !== undefined) {\n stream._pendingAbortRequest._reject(error);\n stream._pendingAbortRequest = undefined;\n }\n WritableStreamDealWithRejection(stream, error);\n}\n\n// TODO(ricea): Fix alphabetical order.\nfunction WritableStreamCloseQueuedOrInFlight(stream) {\n if (stream._closeRequest === undefined && stream._inFlightCloseRequest === undefined) {\n return false;\n }\n\n return true;\n}\n\nfunction WritableStreamHasOperationMarkedInFlight(stream) {\n if (stream._inFlightWriteRequest === undefined && stream._inFlightCloseRequest === undefined) {\n return false;\n }\n\n return true;\n}\n\nfunction WritableStreamMarkCloseRequestInFlight(stream) {\n assert(stream._inFlightCloseRequest === undefined);\n assert(stream._closeRequest !== undefined);\n stream._inFlightCloseRequest = stream._closeRequest;\n stream._closeRequest = undefined;\n}\n\nfunction WritableStreamMarkFirstWriteRequestInFlight(stream) {\n assert(stream._inFlightWriteRequest === undefined, 'there must be no pending write request');\n assert(stream._writeRequests.length !== 0, 'writeRequests must not be empty');\n stream._inFlightWriteRequest = stream._writeRequests.shift();\n}\n\nfunction WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream) {\n assert(stream._state === 'errored', '_stream_.[[state]] is `\"errored\"`');\n if (stream._closeRequest !== undefined) {\n assert(stream._inFlightCloseRequest === undefined);\n\n stream._closeRequest._reject(stream._storedError);\n stream._closeRequest = undefined;\n }\n var writer = stream._writer;\n if (writer !== undefined) {\n defaultWriterClosedPromiseReject(writer, stream._storedError);\n writer._closedPromise.catch(function () {});\n }\n}\n\nfunction WritableStreamUpdateBackpressure(stream, backpressure) {\n assert(stream._state === 'writable');\n assert(WritableStreamCloseQueuedOrInFlight(stream) === false);\n\n var writer = stream._writer;\n if (writer !== undefined && backpressure !== stream._backpressure) {\n if (backpressure === true) {\n defaultWriterReadyPromiseReset(writer);\n } else {\n assert(backpressure === false);\n\n defaultWriterReadyPromiseResolve(writer);\n }\n }\n\n stream._backpressure = backpressure;\n}\n\nvar WritableStreamDefaultWriter = function () {\n function WritableStreamDefaultWriter(stream) {\n _classCallCheck(this, WritableStreamDefaultWriter);\n\n if (IsWritableStream(stream) === false) {\n throw new TypeError('WritableStreamDefaultWriter can only be constructed with a WritableStream instance');\n }\n if (IsWritableStreamLocked(stream) === true) {\n throw new TypeError('This stream has already been locked for exclusive writing by another writer');\n }\n\n this._ownerWritableStream = stream;\n stream._writer = this;\n\n var state = stream._state;\n\n if (state === 'writable') {\n if (WritableStreamCloseQueuedOrInFlight(stream) === false && stream._backpressure === true) {\n defaultWriterReadyPromiseInitialize(this);\n } else {\n defaultWriterReadyPromiseInitializeAsResolved(this);\n }\n\n defaultWriterClosedPromiseInitialize(this);\n } else if (state === 'erroring') {\n defaultWriterReadyPromiseInitializeAsRejected(this, stream._storedError);\n this._readyPromise.catch(function () {});\n defaultWriterClosedPromiseInitialize(this);\n } else if (state === 'closed') {\n defaultWriterReadyPromiseInitializeAsResolved(this);\n defaultWriterClosedPromiseInitializeAsResolved(this);\n } else {\n assert(state === 'errored', 'state must be errored');\n\n var storedError = stream._storedError;\n defaultWriterReadyPromiseInitializeAsRejected(this, storedError);\n this._readyPromise.catch(function () {});\n defaultWriterClosedPromiseInitializeAsRejected(this, storedError);\n this._closedPromise.catch(function () {});\n }\n }\n\n _createClass(WritableStreamDefaultWriter, [{\n key: 'abort',\n value: function abort(reason) {\n if (IsWritableStreamDefaultWriter(this) === false) {\n return Promise.reject(defaultWriterBrandCheckException('abort'));\n }\n\n if (this._ownerWritableStream === undefined) {\n return Promise.reject(defaultWriterLockException('abort'));\n }\n\n return WritableStreamDefaultWriterAbort(this, reason);\n }\n }, {\n key: 'close',\n value: function close() {\n if (IsWritableStreamDefaultWriter(this) === false) {\n return Promise.reject(defaultWriterBrandCheckException('close'));\n }\n\n var stream = this._ownerWritableStream;\n\n if (stream === undefined) {\n return Promise.reject(defaultWriterLockException('close'));\n }\n\n if (WritableStreamCloseQueuedOrInFlight(stream) === true) {\n return Promise.reject(new TypeError('cannot close an already-closing stream'));\n }\n\n return WritableStreamDefaultWriterClose(this);\n }\n }, {\n key: 'releaseLock',\n value: function releaseLock() {\n if (IsWritableStreamDefaultWriter(this) === false) {\n throw defaultWriterBrandCheckException('releaseLock');\n }\n\n var stream = this._ownerWritableStream;\n\n if (stream === undefined) {\n return;\n }\n\n assert(stream._writer !== undefined);\n\n WritableStreamDefaultWriterRelease(this);\n }\n }, {\n key: 'write',\n value: function write(chunk) {\n if (IsWritableStreamDefaultWriter(this) === false) {\n return Promise.reject(defaultWriterBrandCheckException('write'));\n }\n\n if (this._ownerWritableStream === undefined) {\n return Promise.reject(defaultWriterLockException('write to'));\n }\n\n return WritableStreamDefaultWriterWrite(this, chunk);\n }\n }, {\n key: 'closed',\n get: function get() {\n if (IsWritableStreamDefaultWriter(this) === false) {\n return Promise.reject(defaultWriterBrandCheckException('closed'));\n }\n\n return this._closedPromise;\n }\n }, {\n key: 'desiredSize',\n get: function get() {\n if (IsWritableStreamDefaultWriter(this) === false) {\n throw defaultWriterBrandCheckException('desiredSize');\n }\n\n if (this._ownerWritableStream === undefined) {\n throw defaultWriterLockException('desiredSize');\n }\n\n return WritableStreamDefaultWriterGetDesiredSize(this);\n }\n }, {\n key: 'ready',\n get: function get() {\n if (IsWritableStreamDefaultWriter(this) === false) {\n return Promise.reject(defaultWriterBrandCheckException('ready'));\n }\n\n return this._readyPromise;\n }\n }]);\n\n return WritableStreamDefaultWriter;\n}();\n\n// Abstract operations for the WritableStreamDefaultWriter.\n\nfunction IsWritableStreamDefaultWriter(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_ownerWritableStream')) {\n return false;\n }\n\n return true;\n}\n\n// A client of WritableStreamDefaultWriter may use these functions directly to bypass state check.\n\nfunction WritableStreamDefaultWriterAbort(writer, reason) {\n var stream = writer._ownerWritableStream;\n\n assert(stream !== undefined);\n\n return WritableStreamAbort(stream, reason);\n}\n\nfunction WritableStreamDefaultWriterClose(writer) {\n var stream = writer._ownerWritableStream;\n\n assert(stream !== undefined);\n\n var state = stream._state;\n if (state === 'closed' || state === 'errored') {\n return Promise.reject(new TypeError('The stream (in ' + state + ' state) is not in the writable state and cannot be closed'));\n }\n\n assert(state === 'writable' || state === 'erroring');\n assert(WritableStreamCloseQueuedOrInFlight(stream) === false);\n\n var promise = new Promise(function (resolve, reject) {\n var closeRequest = {\n _resolve: resolve,\n _reject: reject\n };\n\n stream._closeRequest = closeRequest;\n });\n\n if (stream._backpressure === true && state === 'writable') {\n defaultWriterReadyPromiseResolve(writer);\n }\n\n WritableStreamDefaultControllerClose(stream._writableStreamController);\n\n return promise;\n}\n\nfunction WritableStreamDefaultWriterCloseWithErrorPropagation(writer) {\n var stream = writer._ownerWritableStream;\n\n assert(stream !== undefined);\n\n var state = stream._state;\n if (WritableStreamCloseQueuedOrInFlight(stream) === true || state === 'closed') {\n return Promise.resolve();\n }\n\n if (state === 'errored') {\n return Promise.reject(stream._storedError);\n }\n\n assert(state === 'writable' || state === 'erroring');\n\n return WritableStreamDefaultWriterClose(writer);\n}\n\nfunction WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, error) {\n if (writer._closedPromiseState === 'pending') {\n defaultWriterClosedPromiseReject(writer, error);\n } else {\n defaultWriterClosedPromiseResetToRejected(writer, error);\n }\n writer._closedPromise.catch(function () {});\n}\n\nfunction WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, error) {\n if (writer._readyPromiseState === 'pending') {\n defaultWriterReadyPromiseReject(writer, error);\n } else {\n defaultWriterReadyPromiseResetToRejected(writer, error);\n }\n writer._readyPromise.catch(function () {});\n}\n\nfunction WritableStreamDefaultWriterGetDesiredSize(writer) {\n var stream = writer._ownerWritableStream;\n var state = stream._state;\n\n if (state === 'errored' || state === 'erroring') {\n return null;\n }\n\n if (state === 'closed') {\n return 0;\n }\n\n return WritableStreamDefaultControllerGetDesiredSize(stream._writableStreamController);\n}\n\nfunction WritableStreamDefaultWriterRelease(writer) {\n var stream = writer._ownerWritableStream;\n assert(stream !== undefined);\n assert(stream._writer === writer);\n\n var releasedError = new TypeError('Writer was released and can no longer be used to monitor the stream\\'s closedness');\n\n WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, releasedError);\n\n // The state transitions to \"errored\" before the sink abort() method runs, but the writer.closed promise is not\n // rejected until afterwards. This means that simply testing state will not work.\n WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, releasedError);\n\n stream._writer = undefined;\n writer._ownerWritableStream = undefined;\n}\n\nfunction WritableStreamDefaultWriterWrite(writer, chunk) {\n var stream = writer._ownerWritableStream;\n\n assert(stream !== undefined);\n\n var controller = stream._writableStreamController;\n\n var chunkSize = WritableStreamDefaultControllerGetChunkSize(controller, chunk);\n\n if (stream !== writer._ownerWritableStream) {\n return Promise.reject(defaultWriterLockException('write to'));\n }\n\n var state = stream._state;\n if (state === 'errored') {\n return Promise.reject(stream._storedError);\n }\n if (WritableStreamCloseQueuedOrInFlight(stream) === true || state === 'closed') {\n return Promise.reject(new TypeError('The stream is closing or closed and cannot be written to'));\n }\n if (state === 'erroring') {\n return Promise.reject(stream._storedError);\n }\n\n assert(state === 'writable');\n\n var promise = WritableStreamAddWriteRequest(stream);\n\n WritableStreamDefaultControllerWrite(controller, chunk, chunkSize);\n\n return promise;\n}\n\nvar WritableStreamDefaultController = function () {\n function WritableStreamDefaultController(stream, underlyingSink, size, highWaterMark) {\n _classCallCheck(this, WritableStreamDefaultController);\n\n if (IsWritableStream(stream) === false) {\n throw new TypeError('WritableStreamDefaultController can only be constructed with a WritableStream instance');\n }\n\n if (stream._writableStreamController !== undefined) {\n throw new TypeError('WritableStreamDefaultController instances can only be created by the WritableStream constructor');\n }\n\n this._controlledWritableStream = stream;\n\n this._underlyingSink = underlyingSink;\n\n // Need to set the slots so that the assert doesn't fire. In the spec the slots already exist implicitly.\n this._queue = undefined;\n this._queueTotalSize = undefined;\n ResetQueue(this);\n\n this._started = false;\n\n var normalizedStrategy = ValidateAndNormalizeQueuingStrategy(size, highWaterMark);\n this._strategySize = normalizedStrategy.size;\n this._strategyHWM = normalizedStrategy.highWaterMark;\n\n var backpressure = WritableStreamDefaultControllerGetBackpressure(this);\n WritableStreamUpdateBackpressure(stream, backpressure);\n }\n\n _createClass(WritableStreamDefaultController, [{\n key: 'error',\n value: function error(e) {\n if (IsWritableStreamDefaultController(this) === false) {\n throw new TypeError('WritableStreamDefaultController.prototype.error can only be used on a WritableStreamDefaultController');\n }\n var state = this._controlledWritableStream._state;\n if (state !== 'writable') {\n // The stream is closed, errored or will be soon. The sink can't do anything useful if it gets an error here, so\n // just treat it as a no-op.\n return;\n }\n\n WritableStreamDefaultControllerError(this, e);\n }\n }, {\n key: '__abortSteps',\n value: function __abortSteps(reason) {\n return PromiseInvokeOrNoop(this._underlyingSink, 'abort', [reason]);\n }\n }, {\n key: '__errorSteps',\n value: function __errorSteps() {\n ResetQueue(this);\n }\n }, {\n key: '__startSteps',\n value: function __startSteps() {\n var _this = this;\n\n var startResult = InvokeOrNoop(this._underlyingSink, 'start', [this]);\n var stream = this._controlledWritableStream;\n\n Promise.resolve(startResult).then(function () {\n assert(stream._state === 'writable' || stream._state === 'erroring');\n _this._started = true;\n WritableStreamDefaultControllerAdvanceQueueIfNeeded(_this);\n }, function (r) {\n assert(stream._state === 'writable' || stream._state === 'erroring');\n _this._started = true;\n WritableStreamDealWithRejection(stream, r);\n }).catch(rethrowAssertionErrorRejection);\n }\n }]);\n\n return WritableStreamDefaultController;\n}();\n\n// Abstract operations implementing interface required by the WritableStream.\n\nfunction WritableStreamDefaultControllerClose(controller) {\n EnqueueValueWithSize(controller, 'close', 0);\n WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);\n}\n\nfunction WritableStreamDefaultControllerGetChunkSize(controller, chunk) {\n var strategySize = controller._strategySize;\n\n if (strategySize === undefined) {\n return 1;\n }\n\n try {\n return strategySize(chunk);\n } catch (chunkSizeE) {\n WritableStreamDefaultControllerErrorIfNeeded(controller, chunkSizeE);\n return 1;\n }\n}\n\nfunction WritableStreamDefaultControllerGetDesiredSize(controller) {\n return controller._strategyHWM - controller._queueTotalSize;\n}\n\nfunction WritableStreamDefaultControllerWrite(controller, chunk, chunkSize) {\n var writeRecord = { chunk: chunk };\n\n try {\n EnqueueValueWithSize(controller, writeRecord, chunkSize);\n } catch (enqueueE) {\n WritableStreamDefaultControllerErrorIfNeeded(controller, enqueueE);\n return;\n }\n\n var stream = controller._controlledWritableStream;\n if (WritableStreamCloseQueuedOrInFlight(stream) === false && stream._state === 'writable') {\n var backpressure = WritableStreamDefaultControllerGetBackpressure(controller);\n WritableStreamUpdateBackpressure(stream, backpressure);\n }\n\n WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);\n}\n\n// Abstract operations for the WritableStreamDefaultController.\n\nfunction IsWritableStreamDefaultController(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_underlyingSink')) {\n return false;\n }\n\n return true;\n}\n\nfunction WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller) {\n var stream = controller._controlledWritableStream;\n\n if (controller._started === false) {\n return;\n }\n\n if (stream._inFlightWriteRequest !== undefined) {\n return;\n }\n\n var state = stream._state;\n if (state === 'closed' || state === 'errored') {\n return;\n }\n if (state === 'erroring') {\n WritableStreamFinishErroring(stream);\n return;\n }\n\n if (controller._queue.length === 0) {\n return;\n }\n\n var writeRecord = PeekQueueValue(controller);\n if (writeRecord === 'close') {\n WritableStreamDefaultControllerProcessClose(controller);\n } else {\n WritableStreamDefaultControllerProcessWrite(controller, writeRecord.chunk);\n }\n}\n\nfunction WritableStreamDefaultControllerErrorIfNeeded(controller, error) {\n if (controller._controlledWritableStream._state === 'writable') {\n WritableStreamDefaultControllerError(controller, error);\n }\n}\n\nfunction WritableStreamDefaultControllerProcessClose(controller) {\n var stream = controller._controlledWritableStream;\n\n WritableStreamMarkCloseRequestInFlight(stream);\n\n DequeueValue(controller);\n assert(controller._queue.length === 0, 'queue must be empty once the final write record is dequeued');\n\n var sinkClosePromise = PromiseInvokeOrNoop(controller._underlyingSink, 'close', []);\n sinkClosePromise.then(function () {\n WritableStreamFinishInFlightClose(stream);\n }, function (reason) {\n WritableStreamFinishInFlightCloseWithError(stream, reason);\n }).catch(rethrowAssertionErrorRejection);\n}\n\nfunction WritableStreamDefaultControllerProcessWrite(controller, chunk) {\n var stream = controller._controlledWritableStream;\n\n WritableStreamMarkFirstWriteRequestInFlight(stream);\n\n var sinkWritePromise = PromiseInvokeOrNoop(controller._underlyingSink, 'write', [chunk, controller]);\n sinkWritePromise.then(function () {\n WritableStreamFinishInFlightWrite(stream);\n\n var state = stream._state;\n assert(state === 'writable' || state === 'erroring');\n\n DequeueValue(controller);\n\n if (WritableStreamCloseQueuedOrInFlight(stream) === false && state === 'writable') {\n var backpressure = WritableStreamDefaultControllerGetBackpressure(controller);\n WritableStreamUpdateBackpressure(stream, backpressure);\n }\n\n WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);\n }, function (reason) {\n WritableStreamFinishInFlightWriteWithError(stream, reason);\n }).catch(rethrowAssertionErrorRejection);\n}\n\nfunction WritableStreamDefaultControllerGetBackpressure(controller) {\n var desiredSize = WritableStreamDefaultControllerGetDesiredSize(controller);\n return desiredSize <= 0;\n}\n\n// A client of WritableStreamDefaultController may use these functions directly to bypass state check.\n\nfunction WritableStreamDefaultControllerError(controller, error) {\n var stream = controller._controlledWritableStream;\n\n assert(stream._state === 'writable');\n\n WritableStreamStartErroring(stream, error);\n}\n\n// Helper functions for the WritableStream.\n\nfunction streamBrandCheckException(name) {\n return new TypeError('WritableStream.prototype.' + name + ' can only be used on a WritableStream');\n}\n\n// Helper functions for the WritableStreamDefaultWriter.\n\nfunction defaultWriterBrandCheckException(name) {\n return new TypeError('WritableStreamDefaultWriter.prototype.' + name + ' can only be used on a WritableStreamDefaultWriter');\n}\n\nfunction defaultWriterLockException(name) {\n return new TypeError('Cannot ' + name + ' a stream using a released writer');\n}\n\nfunction defaultWriterClosedPromiseInitialize(writer) {\n writer._closedPromise = new Promise(function (resolve, reject) {\n writer._closedPromise_resolve = resolve;\n writer._closedPromise_reject = reject;\n writer._closedPromiseState = 'pending';\n });\n}\n\nfunction defaultWriterClosedPromiseInitializeAsRejected(writer, reason) {\n writer._closedPromise = Promise.reject(reason);\n writer._closedPromise_resolve = undefined;\n writer._closedPromise_reject = undefined;\n writer._closedPromiseState = 'rejected';\n}\n\nfunction defaultWriterClosedPromiseInitializeAsResolved(writer) {\n writer._closedPromise = Promise.resolve(undefined);\n writer._closedPromise_resolve = undefined;\n writer._closedPromise_reject = undefined;\n writer._closedPromiseState = 'resolved';\n}\n\nfunction defaultWriterClosedPromiseReject(writer, reason) {\n assert(writer._closedPromise_resolve !== undefined, 'writer._closedPromise_resolve !== undefined');\n assert(writer._closedPromise_reject !== undefined, 'writer._closedPromise_reject !== undefined');\n assert(writer._closedPromiseState === 'pending', 'writer._closedPromiseState is pending');\n\n writer._closedPromise_reject(reason);\n writer._closedPromise_resolve = undefined;\n writer._closedPromise_reject = undefined;\n writer._closedPromiseState = 'rejected';\n}\n\nfunction defaultWriterClosedPromiseResetToRejected(writer, reason) {\n assert(writer._closedPromise_resolve === undefined, 'writer._closedPromise_resolve === undefined');\n assert(writer._closedPromise_reject === undefined, 'writer._closedPromise_reject === undefined');\n assert(writer._closedPromiseState !== 'pending', 'writer._closedPromiseState is not pending');\n\n writer._closedPromise = Promise.reject(reason);\n writer._closedPromiseState = 'rejected';\n}\n\nfunction defaultWriterClosedPromiseResolve(writer) {\n assert(writer._closedPromise_resolve !== undefined, 'writer._closedPromise_resolve !== undefined');\n assert(writer._closedPromise_reject !== undefined, 'writer._closedPromise_reject !== undefined');\n assert(writer._closedPromiseState === 'pending', 'writer._closedPromiseState is pending');\n\n writer._closedPromise_resolve(undefined);\n writer._closedPromise_resolve = undefined;\n writer._closedPromise_reject = undefined;\n writer._closedPromiseState = 'resolved';\n}\n\nfunction defaultWriterReadyPromiseInitialize(writer) {\n writer._readyPromise = new Promise(function (resolve, reject) {\n writer._readyPromise_resolve = resolve;\n writer._readyPromise_reject = reject;\n });\n writer._readyPromiseState = 'pending';\n}\n\nfunction defaultWriterReadyPromiseInitializeAsRejected(writer, reason) {\n writer._readyPromise = Promise.reject(reason);\n writer._readyPromise_resolve = undefined;\n writer._readyPromise_reject = undefined;\n writer._readyPromiseState = 'rejected';\n}\n\nfunction defaultWriterReadyPromiseInitializeAsResolved(writer) {\n writer._readyPromise = Promise.resolve(undefined);\n writer._readyPromise_resolve = undefined;\n writer._readyPromise_reject = undefined;\n writer._readyPromiseState = 'fulfilled';\n}\n\nfunction defaultWriterReadyPromiseReject(writer, reason) {\n assert(writer._readyPromise_resolve !== undefined, 'writer._readyPromise_resolve !== undefined');\n assert(writer._readyPromise_reject !== undefined, 'writer._readyPromise_reject !== undefined');\n\n writer._readyPromise_reject(reason);\n writer._readyPromise_resolve = undefined;\n writer._readyPromise_reject = undefined;\n writer._readyPromiseState = 'rejected';\n}\n\nfunction defaultWriterReadyPromiseReset(writer) {\n assert(writer._readyPromise_resolve === undefined, 'writer._readyPromise_resolve === undefined');\n assert(writer._readyPromise_reject === undefined, 'writer._readyPromise_reject === undefined');\n\n writer._readyPromise = new Promise(function (resolve, reject) {\n writer._readyPromise_resolve = resolve;\n writer._readyPromise_reject = reject;\n });\n writer._readyPromiseState = 'pending';\n}\n\nfunction defaultWriterReadyPromiseResetToRejected(writer, reason) {\n assert(writer._readyPromise_resolve === undefined, 'writer._readyPromise_resolve === undefined');\n assert(writer._readyPromise_reject === undefined, 'writer._readyPromise_reject === undefined');\n\n writer._readyPromise = Promise.reject(reason);\n writer._readyPromiseState = 'rejected';\n}\n\nfunction defaultWriterReadyPromiseResolve(writer) {\n assert(writer._readyPromise_resolve !== undefined, 'writer._readyPromise_resolve !== undefined');\n assert(writer._readyPromise_reject !== undefined, 'writer._readyPromise_reject !== undefined');\n\n writer._readyPromise_resolve(undefined);\n writer._readyPromise_resolve = undefined;\n writer._readyPromise_reject = undefined;\n writer._readyPromiseState = 'fulfilled';\n}\n\n/***/ }),\n/* 3 */\n/***/ (function(module, exports, __w_pdfjs_require__) {\n\n\"use strict\";\n\n\nvar _require = __w_pdfjs_require__(0),\n IsFiniteNonNegativeNumber = _require.IsFiniteNonNegativeNumber;\n\nvar _require2 = __w_pdfjs_require__(1),\n assert = _require2.assert;\n\nexports.DequeueValue = function (container) {\n assert('_queue' in container && '_queueTotalSize' in container, 'Spec-level failure: DequeueValue should only be used on containers with [[queue]] and [[queueTotalSize]].');\n assert(container._queue.length > 0, 'Spec-level failure: should never dequeue from an empty queue.');\n\n var pair = container._queue.shift();\n container._queueTotalSize -= pair.size;\n if (container._queueTotalSize < 0) {\n container._queueTotalSize = 0;\n }\n\n return pair.value;\n};\n\nexports.EnqueueValueWithSize = function (container, value, size) {\n assert('_queue' in container && '_queueTotalSize' in container, 'Spec-level failure: EnqueueValueWithSize should only be used on containers with [[queue]] and ' + '[[queueTotalSize]].');\n\n size = Number(size);\n if (!IsFiniteNonNegativeNumber(size)) {\n throw new RangeError('Size must be a finite, non-NaN, non-negative number.');\n }\n\n container._queue.push({ value: value, size: size });\n container._queueTotalSize += size;\n};\n\nexports.PeekQueueValue = function (container) {\n assert('_queue' in container && '_queueTotalSize' in container, 'Spec-level failure: PeekQueueValue should only be used on containers with [[queue]] and [[queueTotalSize]].');\n assert(container._queue.length > 0, 'Spec-level failure: should never peek at an empty queue.');\n\n var pair = container._queue[0];\n return pair.value;\n};\n\nexports.ResetQueue = function (container) {\n assert('_queue' in container && '_queueTotalSize' in container, 'Spec-level failure: ResetQueue should only be used on containers with [[queue]] and [[queueTotalSize]].');\n\n container._queue = [];\n container._queueTotalSize = 0;\n};\n\n/***/ }),\n/* 4 */\n/***/ (function(module, exports, __w_pdfjs_require__) {\n\n\"use strict\";\n\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar _require = __w_pdfjs_require__(0),\n ArrayBufferCopy = _require.ArrayBufferCopy,\n CreateIterResultObject = _require.CreateIterResultObject,\n IsFiniteNonNegativeNumber = _require.IsFiniteNonNegativeNumber,\n InvokeOrNoop = _require.InvokeOrNoop,\n PromiseInvokeOrNoop = _require.PromiseInvokeOrNoop,\n TransferArrayBuffer = _require.TransferArrayBuffer,\n ValidateAndNormalizeQueuingStrategy = _require.ValidateAndNormalizeQueuingStrategy,\n ValidateAndNormalizeHighWaterMark = _require.ValidateAndNormalizeHighWaterMark;\n\nvar _require2 = __w_pdfjs_require__(0),\n createArrayFromList = _require2.createArrayFromList,\n createDataProperty = _require2.createDataProperty,\n typeIsObject = _require2.typeIsObject;\n\nvar _require3 = __w_pdfjs_require__(1),\n assert = _require3.assert,\n rethrowAssertionErrorRejection = _require3.rethrowAssertionErrorRejection;\n\nvar _require4 = __w_pdfjs_require__(3),\n DequeueValue = _require4.DequeueValue,\n EnqueueValueWithSize = _require4.EnqueueValueWithSize,\n ResetQueue = _require4.ResetQueue;\n\nvar _require5 = __w_pdfjs_require__(2),\n AcquireWritableStreamDefaultWriter = _require5.AcquireWritableStreamDefaultWriter,\n IsWritableStream = _require5.IsWritableStream,\n IsWritableStreamLocked = _require5.IsWritableStreamLocked,\n WritableStreamAbort = _require5.WritableStreamAbort,\n WritableStreamDefaultWriterCloseWithErrorPropagation = _require5.WritableStreamDefaultWriterCloseWithErrorPropagation,\n WritableStreamDefaultWriterRelease = _require5.WritableStreamDefaultWriterRelease,\n WritableStreamDefaultWriterWrite = _require5.WritableStreamDefaultWriterWrite,\n WritableStreamCloseQueuedOrInFlight = _require5.WritableStreamCloseQueuedOrInFlight;\n\nvar ReadableStream = function () {\n function ReadableStream() {\n var underlyingSource = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n size = _ref.size,\n highWaterMark = _ref.highWaterMark;\n\n _classCallCheck(this, ReadableStream);\n\n // Exposed to controllers.\n this._state = 'readable';\n\n this._reader = undefined;\n this._storedError = undefined;\n\n this._disturbed = false;\n\n // Initialize to undefined first because the constructor of the controller checks this\n // variable to validate the caller.\n this._readableStreamController = undefined;\n var type = underlyingSource.type;\n var typeString = String(type);\n if (typeString === 'bytes') {\n if (highWaterMark === undefined) {\n highWaterMark = 0;\n }\n this._readableStreamController = new ReadableByteStreamController(this, underlyingSource, highWaterMark);\n } else if (type === undefined) {\n if (highWaterMark === undefined) {\n highWaterMark = 1;\n }\n this._readableStreamController = new ReadableStreamDefaultController(this, underlyingSource, size, highWaterMark);\n } else {\n throw new RangeError('Invalid type is specified');\n }\n }\n\n _createClass(ReadableStream, [{\n key: 'cancel',\n value: function cancel(reason) {\n if (IsReadableStream(this) === false) {\n return Promise.reject(streamBrandCheckException('cancel'));\n }\n\n if (IsReadableStreamLocked(this) === true) {\n return Promise.reject(new TypeError('Cannot cancel a stream that already has a reader'));\n }\n\n return ReadableStreamCancel(this, reason);\n }\n }, {\n key: 'getReader',\n value: function getReader() {\n var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n mode = _ref2.mode;\n\n if (IsReadableStream(this) === false) {\n throw streamBrandCheckException('getReader');\n }\n\n if (mode === undefined) {\n return AcquireReadableStreamDefaultReader(this);\n }\n\n mode = String(mode);\n\n if (mode === 'byob') {\n return AcquireReadableStreamBYOBReader(this);\n }\n\n throw new RangeError('Invalid mode is specified');\n }\n }, {\n key: 'pipeThrough',\n value: function pipeThrough(_ref3, options) {\n var writable = _ref3.writable,\n readable = _ref3.readable;\n\n var promise = this.pipeTo(writable, options);\n\n ifIsObjectAndHasAPromiseIsHandledInternalSlotSetPromiseIsHandledToTrue(promise);\n\n return readable;\n }\n }, {\n key: 'pipeTo',\n value: function pipeTo(dest) {\n var _this = this;\n\n var _ref4 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n preventClose = _ref4.preventClose,\n preventAbort = _ref4.preventAbort,\n preventCancel = _ref4.preventCancel;\n\n if (IsReadableStream(this) === false) {\n return Promise.reject(streamBrandCheckException('pipeTo'));\n }\n if (IsWritableStream(dest) === false) {\n return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo\\'s first argument must be a WritableStream'));\n }\n\n preventClose = Boolean(preventClose);\n preventAbort = Boolean(preventAbort);\n preventCancel = Boolean(preventCancel);\n\n if (IsReadableStreamLocked(this) === true) {\n return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo cannot be used on a locked ReadableStream'));\n }\n if (IsWritableStreamLocked(dest) === true) {\n return Promise.reject(new TypeError('ReadableStream.prototype.pipeTo cannot be used on a locked WritableStream'));\n }\n\n var reader = AcquireReadableStreamDefaultReader(this);\n var writer = AcquireWritableStreamDefaultWriter(dest);\n\n var shuttingDown = false;\n\n // This is used to keep track of the spec's requirement that we wait for ongoing writes during shutdown.\n var currentWrite = Promise.resolve();\n\n return new Promise(function (resolve, reject) {\n // Using reader and writer, read all chunks from this and write them to dest\n // - Backpressure must be enforced\n // - Shutdown must stop all activity\n function pipeLoop() {\n currentWrite = Promise.resolve();\n\n if (shuttingDown === true) {\n return Promise.resolve();\n }\n\n return writer._readyPromise.then(function () {\n return ReadableStreamDefaultReaderRead(reader).then(function (_ref5) {\n var value = _ref5.value,\n done = _ref5.done;\n\n if (done === true) {\n return;\n }\n\n currentWrite = WritableStreamDefaultWriterWrite(writer, value).catch(function () {});\n });\n }).then(pipeLoop);\n }\n\n // Errors must be propagated forward\n isOrBecomesErrored(_this, reader._closedPromise, function (storedError) {\n if (preventAbort === false) {\n shutdownWithAction(function () {\n return WritableStreamAbort(dest, storedError);\n }, true, storedError);\n } else {\n shutdown(true, storedError);\n }\n });\n\n // Errors must be propagated backward\n isOrBecomesErrored(dest, writer._closedPromise, function (storedError) {\n if (preventCancel === false) {\n shutdownWithAction(function () {\n return ReadableStreamCancel(_this, storedError);\n }, true, storedError);\n } else {\n shutdown(true, storedError);\n }\n });\n\n // Closing must be propagated forward\n isOrBecomesClosed(_this, reader._closedPromise, function () {\n if (preventClose === false) {\n shutdownWithAction(function () {\n return WritableStreamDefaultWriterCloseWithErrorPropagation(writer);\n });\n } else {\n shutdown();\n }\n });\n\n // Closing must be propagated backward\n if (WritableStreamCloseQueuedOrInFlight(dest) === true || dest._state === 'closed') {\n var destClosed = new TypeError('the destination writable stream closed before all data could be piped to it');\n\n if (preventCancel === false) {\n shutdownWithAction(function () {\n return ReadableStreamCancel(_this, destClosed);\n }, true, destClosed);\n } else {\n shutdown(true, destClosed);\n }\n }\n\n pipeLoop().catch(function (err) {\n currentWrite = Promise.resolve();\n rethrowAssertionErrorRejection(err);\n });\n\n function waitForWritesToFinish() {\n // Another write may have started while we were waiting on this currentWrite, so we have to be sure to wait\n // for that too.\n var oldCurrentWrite = currentWrite;\n return currentWrite.then(function () {\n return oldCurrentWrite !== currentWrite ? waitForWritesToFinish() : undefined;\n });\n }\n\n function isOrBecomesErrored(stream, promise, action) {\n if (stream._state === 'errored') {\n action(stream._storedError);\n } else {\n promise.catch(action).catch(rethrowAssertionErrorRejection);\n }\n }\n\n function isOrBecomesClosed(stream, promise, action) {\n if (stream._state === 'closed') {\n action();\n } else {\n promise.then(action).catch(rethrowAssertionErrorRejection);\n }\n }\n\n function shutdownWithAction(action, originalIsError, originalError) {\n if (shuttingDown === true) {\n return;\n }\n shuttingDown = true;\n\n if (dest._state === 'writable' && WritableStreamCloseQueuedOrInFlight(dest) === false) {\n waitForWritesToFinish().then(doTheRest);\n } else {\n doTheRest();\n }\n\n function doTheRest() {\n action().then(function () {\n return finalize(originalIsError, originalError);\n }, function (newError) {\n return finalize(true, newError);\n }).catch(rethrowAssertionErrorRejection);\n }\n }\n\n function shutdown(isError, error) {\n if (shuttingDown === true) {\n return;\n }\n shuttingDown = true;\n\n if (dest._state === 'writable' && WritableStreamCloseQueuedOrInFlight(dest) === false) {\n waitForWritesToFinish().then(function () {\n return finalize(isError, error);\n }).catch(rethrowAssertionErrorRejection);\n } else {\n finalize(isError, error);\n }\n }\n\n function finalize(isError, error) {\n WritableStreamDefaultWriterRelease(writer);\n ReadableStreamReaderGenericRelease(reader);\n\n if (isError) {\n reject(error);\n } else {\n resolve(undefined);\n }\n }\n });\n }\n }, {\n key: 'tee',\n value: function tee() {\n if (IsReadableStream(this) === false) {\n throw streamBrandCheckException('tee');\n }\n\n var branches = ReadableStreamTee(this, false);\n return createArrayFromList(branches);\n }\n }, {\n key: 'locked',\n get: function get() {\n if (IsReadableStream(this) === false) {\n throw streamBrandCheckException('locked');\n }\n\n return IsReadableStreamLocked(this);\n }\n }]);\n\n return ReadableStream;\n}();\n\nmodule.exports = {\n ReadableStream: ReadableStream,\n IsReadableStreamDisturbed: IsReadableStreamDisturbed,\n ReadableStreamDefaultControllerClose: ReadableStreamDefaultControllerClose,\n ReadableStreamDefaultControllerEnqueue: ReadableStreamDefaultControllerEnqueue,\n ReadableStreamDefaultControllerError: ReadableStreamDefaultControllerError,\n ReadableStreamDefaultControllerGetDesiredSize: ReadableStreamDefaultControllerGetDesiredSize\n};\n\n// Abstract operations for the ReadableStream.\n\nfunction AcquireReadableStreamBYOBReader(stream) {\n return new ReadableStreamBYOBReader(stream);\n}\n\nfunction AcquireReadableStreamDefaultReader(stream) {\n return new ReadableStreamDefaultReader(stream);\n}\n\nfunction IsReadableStream(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_readableStreamController')) {\n return false;\n }\n\n return true;\n}\n\nfunction IsReadableStreamDisturbed(stream) {\n assert(IsReadableStream(stream) === true, 'IsReadableStreamDisturbed should only be used on known readable streams');\n\n return stream._disturbed;\n}\n\nfunction IsReadableStreamLocked(stream) {\n assert(IsReadableStream(stream) === true, 'IsReadableStreamLocked should only be used on known readable streams');\n\n if (stream._reader === undefined) {\n return false;\n }\n\n return true;\n}\n\nfunction ReadableStreamTee(stream, cloneForBranch2) {\n assert(IsReadableStream(stream) === true);\n assert(typeof cloneForBranch2 === 'boolean');\n\n var reader = AcquireReadableStreamDefaultReader(stream);\n\n var teeState = {\n closedOrErrored: false,\n canceled1: false,\n canceled2: false,\n reason1: undefined,\n reason2: undefined\n };\n teeState.promise = new Promise(function (resolve) {\n teeState._resolve = resolve;\n });\n\n var pull = create_ReadableStreamTeePullFunction();\n pull._reader = reader;\n pull._teeState = teeState;\n pull._cloneForBranch2 = cloneForBranch2;\n\n var cancel1 = create_ReadableStreamTeeBranch1CancelFunction();\n cancel1._stream = stream;\n cancel1._teeState = teeState;\n\n var cancel2 = create_ReadableStreamTeeBranch2CancelFunction();\n cancel2._stream = stream;\n cancel2._teeState = teeState;\n\n var underlyingSource1 = Object.create(Object.prototype);\n createDataProperty(underlyingSource1, 'pull', pull);\n createDataProperty(underlyingSource1, 'cancel', cancel1);\n var branch1Stream = new ReadableStream(underlyingSource1);\n\n var underlyingSource2 = Object.create(Object.prototype);\n createDataProperty(underlyingSource2, 'pull', pull);\n createDataProperty(underlyingSource2, 'cancel', cancel2);\n var branch2Stream = new ReadableStream(underlyingSource2);\n\n pull._branch1 = branch1Stream._readableStreamController;\n pull._branch2 = branch2Stream._readableStreamController;\n\n reader._closedPromise.catch(function (r) {\n if (teeState.closedOrErrored === true) {\n return;\n }\n\n ReadableStreamDefaultControllerError(pull._branch1, r);\n ReadableStreamDefaultControllerError(pull._branch2, r);\n teeState.closedOrErrored = true;\n });\n\n return [branch1Stream, branch2Stream];\n}\n\nfunction create_ReadableStreamTeePullFunction() {\n function f() {\n var reader = f._reader,\n branch1 = f._branch1,\n branch2 = f._branch2,\n teeState = f._teeState;\n\n\n return ReadableStreamDefaultReaderRead(reader).then(function (result) {\n assert(typeIsObject(result));\n var value = result.value;\n var done = result.done;\n assert(typeof done === 'boolean');\n\n if (done === true && teeState.closedOrErrored === false) {\n if (teeState.canceled1 === false) {\n ReadableStreamDefaultControllerClose(branch1);\n }\n if (teeState.canceled2 === false) {\n ReadableStreamDefaultControllerClose(branch2);\n }\n teeState.closedOrErrored = true;\n }\n\n if (teeState.closedOrErrored === true) {\n return;\n }\n\n var value1 = value;\n var value2 = value;\n\n // There is no way to access the cloning code right now in the reference implementation.\n // If we add one then we'll need an implementation for serializable objects.\n // if (teeState.canceled2 === false && cloneForBranch2 === true) {\n // value2 = StructuredDeserialize(StructuredSerialize(value2));\n // }\n\n if (teeState.canceled1 === false) {\n ReadableStreamDefaultControllerEnqueue(branch1, value1);\n }\n\n if (teeState.canceled2 === false) {\n ReadableStreamDefaultControllerEnqueue(branch2, value2);\n }\n });\n }\n return f;\n}\n\nfunction create_ReadableStreamTeeBranch1CancelFunction() {\n function f(reason) {\n var stream = f._stream,\n teeState = f._teeState;\n\n\n teeState.canceled1 = true;\n teeState.reason1 = reason;\n if (teeState.canceled2 === true) {\n var compositeReason = createArrayFromList([teeState.reason1, teeState.reason2]);\n var cancelResult = ReadableStreamCancel(stream, compositeReason);\n teeState._resolve(cancelResult);\n }\n return teeState.promise;\n }\n return f;\n}\n\nfunction create_ReadableStreamTeeBranch2CancelFunction() {\n function f(reason) {\n var stream = f._stream,\n teeState = f._teeState;\n\n\n teeState.canceled2 = true;\n teeState.reason2 = reason;\n if (teeState.canceled1 === true) {\n var compositeReason = createArrayFromList([teeState.reason1, teeState.reason2]);\n var cancelResult = ReadableStreamCancel(stream, compositeReason);\n teeState._resolve(cancelResult);\n }\n return teeState.promise;\n }\n return f;\n}\n\n// ReadableStream API exposed for controllers.\n\nfunction ReadableStreamAddReadIntoRequest(stream) {\n assert(IsReadableStreamBYOBReader(stream._reader) === true);\n assert(stream._state === 'readable' || stream._state === 'closed');\n\n var promise = new Promise(function (resolve, reject) {\n var readIntoRequest = {\n _resolve: resolve,\n _reject: reject\n };\n\n stream._reader._readIntoRequests.push(readIntoRequest);\n });\n\n return promise;\n}\n\nfunction ReadableStreamAddReadRequest(stream) {\n assert(IsReadableStreamDefaultReader(stream._reader) === true);\n assert(stream._state === 'readable');\n\n var promise = new Promise(function (resolve, reject) {\n var readRequest = {\n _resolve: resolve,\n _reject: reject\n };\n\n stream._reader._readRequests.push(readRequest);\n });\n\n return promise;\n}\n\nfunction ReadableStreamCancel(stream, reason) {\n stream._disturbed = true;\n\n if (stream._state === 'closed') {\n return Promise.resolve(undefined);\n }\n if (stream._state === 'errored') {\n return Promise.reject(stream._storedError);\n }\n\n ReadableStreamClose(stream);\n\n var sourceCancelPromise = stream._readableStreamController.__cancelSteps(reason);\n return sourceCancelPromise.then(function () {\n return undefined;\n });\n}\n\nfunction ReadableStreamClose(stream) {\n assert(stream._state === 'readable');\n\n stream._state = 'closed';\n\n var reader = stream._reader;\n\n if (reader === undefined) {\n return undefined;\n }\n\n if (IsReadableStreamDefaultReader(reader) === true) {\n for (var i = 0; i < reader._readRequests.length; i++) {\n var _resolve = reader._readRequests[i]._resolve;\n\n _resolve(CreateIterResultObject(undefined, true));\n }\n reader._readRequests = [];\n }\n\n defaultReaderClosedPromiseResolve(reader);\n\n return undefined;\n}\n\nfunction ReadableStreamError(stream, e) {\n assert(IsReadableStream(stream) === true, 'stream must be ReadableStream');\n assert(stream._state === 'readable', 'state must be readable');\n\n stream._state = 'errored';\n stream._storedError = e;\n\n var reader = stream._reader;\n\n if (reader === undefined) {\n return undefined;\n }\n\n if (IsReadableStreamDefaultReader(reader) === true) {\n for (var i = 0; i < reader._readRequests.length; i++) {\n var readRequest = reader._readRequests[i];\n readRequest._reject(e);\n }\n\n reader._readRequests = [];\n } else {\n assert(IsReadableStreamBYOBReader(reader), 'reader must be ReadableStreamBYOBReader');\n\n for (var _i = 0; _i < reader._readIntoRequests.length; _i++) {\n var readIntoRequest = reader._readIntoRequests[_i];\n readIntoRequest._reject(e);\n }\n\n reader._readIntoRequests = [];\n }\n\n defaultReaderClosedPromiseReject(reader, e);\n reader._closedPromise.catch(function () {});\n}\n\nfunction ReadableStreamFulfillReadIntoRequest(stream, chunk, done) {\n var reader = stream._reader;\n\n assert(reader._readIntoRequests.length > 0);\n\n var readIntoRequest = reader._readIntoRequests.shift();\n readIntoRequest._resolve(CreateIterResultObject(chunk, done));\n}\n\nfunction ReadableStreamFulfillReadRequest(stream, chunk, done) {\n var reader = stream._reader;\n\n assert(reader._readRequests.length > 0);\n\n var readRequest = reader._readRequests.shift();\n readRequest._resolve(CreateIterResultObject(chunk, done));\n}\n\nfunction ReadableStreamGetNumReadIntoRequests(stream) {\n return stream._reader._readIntoRequests.length;\n}\n\nfunction ReadableStreamGetNumReadRequests(stream) {\n return stream._reader._readRequests.length;\n}\n\nfunction ReadableStreamHasBYOBReader(stream) {\n var reader = stream._reader;\n\n if (reader === undefined) {\n return false;\n }\n\n if (IsReadableStreamBYOBReader(reader) === false) {\n return false;\n }\n\n return true;\n}\n\nfunction ReadableStreamHasDefaultReader(stream) {\n var reader = stream._reader;\n\n if (reader === undefined) {\n return false;\n }\n\n if (IsReadableStreamDefaultReader(reader) === false) {\n return false;\n }\n\n return true;\n}\n\n// Readers\n\nvar ReadableStreamDefaultReader = function () {\n function ReadableStreamDefaultReader(stream) {\n _classCallCheck(this, ReadableStreamDefaultReader);\n\n if (IsReadableStream(stream) === false) {\n throw new TypeError('ReadableStreamDefaultReader can only be constructed with a ReadableStream instance');\n }\n if (IsReadableStreamLocked(stream) === true) {\n throw new TypeError('This stream has already been locked for exclusive reading by another reader');\n }\n\n ReadableStreamReaderGenericInitialize(this, stream);\n\n this._readRequests = [];\n }\n\n _createClass(ReadableStreamDefaultReader, [{\n key: 'cancel',\n value: function cancel(reason) {\n if (IsReadableStreamDefaultReader(this) === false) {\n return Promise.reject(defaultReaderBrandCheckException('cancel'));\n }\n\n if (this._ownerReadableStream === undefined) {\n return Promise.reject(readerLockException('cancel'));\n }\n\n return ReadableStreamReaderGenericCancel(this, reason);\n }\n }, {\n key: 'read',\n value: function read() {\n if (IsReadableStreamDefaultReader(this) === false) {\n return Promise.reject(defaultReaderBrandCheckException('read'));\n }\n\n if (this._ownerReadableStream === undefined) {\n return Promise.reject(readerLockException('read from'));\n }\n\n return ReadableStreamDefaultReaderRead(this);\n }\n }, {\n key: 'releaseLock',\n value: function releaseLock() {\n if (IsReadableStreamDefaultReader(this) === false) {\n throw defaultReaderBrandCheckException('releaseLock');\n }\n\n if (this._ownerReadableStream === undefined) {\n return;\n }\n\n if (this._readRequests.length > 0) {\n throw new TypeError('Tried to release a reader lock when that reader has pending read() calls un-settled');\n }\n\n ReadableStreamReaderGenericRelease(this);\n }\n }, {\n key: 'closed',\n get: function get() {\n if (IsReadableStreamDefaultReader(this) === false) {\n return Promise.reject(defaultReaderBrandCheckException('closed'));\n }\n\n return this._closedPromise;\n }\n }]);\n\n return ReadableStreamDefaultReader;\n}();\n\nvar ReadableStreamBYOBReader = function () {\n function ReadableStreamBYOBReader(stream) {\n _classCallCheck(this, ReadableStreamBYOBReader);\n\n if (!IsReadableStream(stream)) {\n throw new TypeError('ReadableStreamBYOBReader can only be constructed with a ReadableStream instance given a ' + 'byte source');\n }\n if (IsReadableByteStreamController(stream._readableStreamController) === false) {\n throw new TypeError('Cannot construct a ReadableStreamBYOBReader for a stream not constructed with a byte ' + 'source');\n }\n if (IsReadableStreamLocked(stream)) {\n throw new TypeError('This stream has already been locked for exclusive reading by another reader');\n }\n\n ReadableStreamReaderGenericInitialize(this, stream);\n\n this._readIntoRequests = [];\n }\n\n _createClass(ReadableStreamBYOBReader, [{\n key: 'cancel',\n value: function cancel(reason) {\n if (!IsReadableStreamBYOBReader(this)) {\n return Promise.reject(byobReaderBrandCheckException('cancel'));\n }\n\n if (this._ownerReadableStream === undefined) {\n return Promise.reject(readerLockException('cancel'));\n }\n\n return ReadableStreamReaderGenericCancel(this, reason);\n }\n }, {\n key: 'read',\n value: function read(view) {\n if (!IsReadableStreamBYOBReader(this)) {\n return Promise.reject(byobReaderBrandCheckException('read'));\n }\n\n if (this._ownerReadableStream === undefined) {\n return Promise.reject(readerLockException('read from'));\n }\n\n if (!ArrayBuffer.isView(view)) {\n return Promise.reject(new TypeError('view must be an array buffer view'));\n }\n\n if (view.byteLength === 0) {\n return Promise.reject(new TypeError('view must have non-zero byteLength'));\n }\n\n return ReadableStreamBYOBReaderRead(this, view);\n }\n }, {\n key: 'releaseLock',\n value: function releaseLock() {\n if (!IsReadableStreamBYOBReader(this)) {\n throw byobReaderBrandCheckException('releaseLock');\n }\n\n if (this._ownerReadableStream === undefined) {\n return;\n }\n\n if (this._readIntoRequests.length > 0) {\n throw new TypeError('Tried to release a reader lock when that reader has pending read() calls un-settled');\n }\n\n ReadableStreamReaderGenericRelease(this);\n }\n }, {\n key: 'closed',\n get: function get() {\n if (!IsReadableStreamBYOBReader(this)) {\n return Promise.reject(byobReaderBrandCheckException('closed'));\n }\n\n return this._closedPromise;\n }\n }]);\n\n return ReadableStreamBYOBReader;\n}();\n\n// Abstract operations for the readers.\n\nfunction IsReadableStreamBYOBReader(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_readIntoRequests')) {\n return false;\n }\n\n return true;\n}\n\nfunction IsReadableStreamDefaultReader(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_readRequests')) {\n return false;\n }\n\n return true;\n}\n\nfunction ReadableStreamReaderGenericInitialize(reader, stream) {\n reader._ownerReadableStream = stream;\n stream._reader = reader;\n\n if (stream._state === 'readable') {\n defaultReaderClosedPromiseInitialize(reader);\n } else if (stream._state === 'closed') {\n defaultReaderClosedPromiseInitializeAsResolved(reader);\n } else {\n assert(stream._state === 'errored', 'state must be errored');\n\n defaultReaderClosedPromiseInitializeAsRejected(reader, stream._storedError);\n reader._closedPromise.catch(function () {});\n }\n}\n\n// A client of ReadableStreamDefaultReader and ReadableStreamBYOBReader may use these functions directly to bypass state\n// check.\n\nfunction ReadableStreamReaderGenericCancel(reader, reason) {\n var stream = reader._ownerReadableStream;\n assert(stream !== undefined);\n return ReadableStreamCancel(stream, reason);\n}\n\nfunction ReadableStreamReaderGenericRelease(reader) {\n assert(reader._ownerReadableStream !== undefined);\n assert(reader._ownerReadableStream._reader === reader);\n\n if (reader._ownerReadableStream._state === 'readable') {\n defaultReaderClosedPromiseReject(reader, new TypeError('Reader was released and can no longer be used to monitor the stream\\'s closedness'));\n } else {\n defaultReaderClosedPromiseResetToRejected(reader, new TypeError('Reader was released and can no longer be used to monitor the stream\\'s closedness'));\n }\n reader._closedPromise.catch(function () {});\n\n reader._ownerReadableStream._reader = undefined;\n reader._ownerReadableStream = undefined;\n}\n\nfunction ReadableStreamBYOBReaderRead(reader, view) {\n var stream = reader._ownerReadableStream;\n\n assert(stream !== undefined);\n\n stream._disturbed = true;\n\n if (stream._state === 'errored') {\n return Promise.reject(stream._storedError);\n }\n\n // Controllers must implement this.\n return ReadableByteStreamControllerPullInto(stream._readableStreamController, view);\n}\n\nfunction ReadableStreamDefaultReaderRead(reader) {\n var stream = reader._ownerReadableStream;\n\n assert(stream !== undefined);\n\n stream._disturbed = true;\n\n if (stream._state === 'closed') {\n return Promise.resolve(CreateIterResultObject(undefined, true));\n }\n\n if (stream._state === 'errored') {\n return Promise.reject(stream._storedError);\n }\n\n assert(stream._state === 'readable');\n\n return stream._readableStreamController.__pullSteps();\n}\n\n// Controllers\n\nvar ReadableStreamDefaultController = function () {\n function ReadableStreamDefaultController(stream, underlyingSource, size, highWaterMark) {\n _classCallCheck(this, ReadableStreamDefaultController);\n\n if (IsReadableStream(stream) === false) {\n throw new TypeError('ReadableStreamDefaultController can only be constructed with a ReadableStream instance');\n }\n\n if (stream._readableStreamController !== undefined) {\n throw new TypeError('ReadableStreamDefaultController instances can only be created by the ReadableStream constructor');\n }\n\n this._controlledReadableStream = stream;\n\n this._underlyingSource = underlyingSource;\n\n // Need to set the slots so that the assert doesn't fire. In the spec the slots already exist implicitly.\n this._queue = undefined;\n this._queueTotalSize = undefined;\n ResetQueue(this);\n\n this._started = false;\n this._closeRequested = false;\n this._pullAgain = false;\n this._pulling = false;\n\n var normalizedStrategy = ValidateAndNormalizeQueuingStrategy(size, highWaterMark);\n this._strategySize = normalizedStrategy.size;\n this._strategyHWM = normalizedStrategy.highWaterMark;\n\n var controller = this;\n\n var startResult = InvokeOrNoop(underlyingSource, 'start', [this]);\n Promise.resolve(startResult).then(function () {\n controller._started = true;\n\n assert(controller._pulling === false);\n assert(controller._pullAgain === false);\n\n ReadableStreamDefaultControllerCallPullIfNeeded(controller);\n }, function (r) {\n ReadableStreamDefaultControllerErrorIfNeeded(controller, r);\n }).catch(rethrowAssertionErrorRejection);\n }\n\n _createClass(ReadableStreamDefaultController, [{\n key: 'close',\n value: function close() {\n if (IsReadableStreamDefaultController(this) === false) {\n throw defaultControllerBrandCheckException('close');\n }\n\n if (this._closeRequested === true) {\n throw new TypeError('The stream has already been closed; do not close it again!');\n }\n\n var state = this._controlledReadableStream._state;\n if (state !== 'readable') {\n throw new TypeError('The stream (in ' + state + ' state) is not in the readable state and cannot be closed');\n }\n\n ReadableStreamDefaultControllerClose(this);\n }\n }, {\n key: 'enqueue',\n value: function enqueue(chunk) {\n if (IsReadableStreamDefaultController(this) === false) {\n throw defaultControllerBrandCheckException('enqueue');\n }\n\n if (this._closeRequested === true) {\n throw new TypeError('stream is closed or draining');\n }\n\n var state = this._controlledReadableStream._state;\n if (state !== 'readable') {\n throw new TypeError('The stream (in ' + state + ' state) is not in the readable state and cannot be enqueued to');\n }\n\n return ReadableStreamDefaultControllerEnqueue(this, chunk);\n }\n }, {\n key: 'error',\n value: function error(e) {\n if (IsReadableStreamDefaultController(this) === false) {\n throw defaultControllerBrandCheckException('error');\n }\n\n var stream = this._controlledReadableStream;\n if (stream._state !== 'readable') {\n throw new TypeError('The stream is ' + stream._state + ' and so cannot be errored');\n }\n\n ReadableStreamDefaultControllerError(this, e);\n }\n }, {\n key: '__cancelSteps',\n value: function __cancelSteps(reason) {\n ResetQueue(this);\n return PromiseInvokeOrNoop(this._underlyingSource, 'cancel', [reason]);\n }\n }, {\n key: '__pullSteps',\n value: function __pullSteps() {\n var stream = this._controlledReadableStream;\n\n if (this._queue.length > 0) {\n var chunk = DequeueValue(this);\n\n if (this._closeRequested === true && this._queue.length === 0) {\n ReadableStreamClose(stream);\n } else {\n ReadableStreamDefaultControllerCallPullIfNeeded(this);\n }\n\n return Promise.resolve(CreateIterResultObject(chunk, false));\n }\n\n var pendingPromise = ReadableStreamAddReadRequest(stream);\n ReadableStreamDefaultControllerCallPullIfNeeded(this);\n return pendingPromise;\n }\n }, {\n key: 'desiredSize',\n get: function get() {\n if (IsReadableStreamDefaultController(this) === false) {\n throw defaultControllerBrandCheckException('desiredSize');\n }\n\n return ReadableStreamDefaultControllerGetDesiredSize(this);\n }\n }]);\n\n return ReadableStreamDefaultController;\n}();\n\n// Abstract operations for the ReadableStreamDefaultController.\n\nfunction IsReadableStreamDefaultController(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_underlyingSource')) {\n return false;\n }\n\n return true;\n}\n\nfunction ReadableStreamDefaultControllerCallPullIfNeeded(controller) {\n var shouldPull = ReadableStreamDefaultControllerShouldCallPull(controller);\n if (shouldPull === false) {\n return undefined;\n }\n\n if (controller._pulling === true) {\n controller._pullAgain = true;\n return undefined;\n }\n\n assert(controller._pullAgain === false);\n\n controller._pulling = true;\n\n var pullPromise = PromiseInvokeOrNoop(controller._underlyingSource, 'pull', [controller]);\n pullPromise.then(function () {\n controller._pulling = false;\n\n if (controller._pullAgain === true) {\n controller._pullAgain = false;\n return ReadableStreamDefaultControllerCallPullIfNeeded(controller);\n }\n return undefined;\n }, function (e) {\n ReadableStreamDefaultControllerErrorIfNeeded(controller, e);\n }).catch(rethrowAssertionErrorRejection);\n\n return undefined;\n}\n\nfunction ReadableStreamDefaultControllerShouldCallPull(controller) {\n var stream = controller._controlledReadableStream;\n\n if (stream._state === 'closed' || stream._state === 'errored') {\n return false;\n }\n\n if (controller._closeRequested === true) {\n return false;\n }\n\n if (controller._started === false) {\n return false;\n }\n\n if (IsReadableStreamLocked(stream) === true && ReadableStreamGetNumReadRequests(stream) > 0) {\n return true;\n }\n\n var desiredSize = ReadableStreamDefaultControllerGetDesiredSize(controller);\n if (desiredSize > 0) {\n return true;\n }\n\n return false;\n}\n\n// A client of ReadableStreamDefaultController may use these functions directly to bypass state check.\n\nfunction ReadableStreamDefaultControllerClose(controller) {\n var stream = controller._controlledReadableStream;\n\n assert(controller._closeRequested === false);\n assert(stream._state === 'readable');\n\n controller._closeRequested = true;\n\n if (controller._queue.length === 0) {\n ReadableStreamClose(stream);\n }\n}\n\nfunction ReadableStreamDefaultControllerEnqueue(controller, chunk) {\n var stream = controller._controlledReadableStream;\n\n assert(controller._closeRequested === false);\n assert(stream._state === 'readable');\n\n if (IsReadableStreamLocked(stream) === true && ReadableStreamGetNumReadRequests(stream) > 0) {\n ReadableStreamFulfillReadRequest(stream, chunk, false);\n } else {\n var chunkSize = 1;\n\n if (controller._strategySize !== undefined) {\n var strategySize = controller._strategySize;\n try {\n chunkSize = strategySize(chunk);\n } catch (chunkSizeE) {\n ReadableStreamDefaultControllerErrorIfNeeded(controller, chunkSizeE);\n throw chunkSizeE;\n }\n }\n\n try {\n EnqueueValueWithSize(controller, chunk, chunkSize);\n } catch (enqueueE) {\n ReadableStreamDefaultControllerErrorIfNeeded(controller, enqueueE);\n throw enqueueE;\n }\n }\n\n ReadableStreamDefaultControllerCallPullIfNeeded(controller);\n\n return undefined;\n}\n\nfunction ReadableStreamDefaultControllerError(controller, e) {\n var stream = controller._controlledReadableStream;\n\n assert(stream._state === 'readable');\n\n ResetQueue(controller);\n\n ReadableStreamError(stream, e);\n}\n\nfunction ReadableStreamDefaultControllerErrorIfNeeded(controller, e) {\n if (controller._controlledReadableStream._state === 'readable') {\n ReadableStreamDefaultControllerError(controller, e);\n }\n}\n\nfunction ReadableStreamDefaultControllerGetDesiredSize(controller) {\n var stream = controller._controlledReadableStream;\n var state = stream._state;\n\n if (state === 'errored') {\n return null;\n }\n if (state === 'closed') {\n return 0;\n }\n\n return controller._strategyHWM - controller._queueTotalSize;\n}\n\nvar ReadableStreamBYOBRequest = function () {\n function ReadableStreamBYOBRequest(controller, view) {\n _classCallCheck(this, ReadableStreamBYOBRequest);\n\n this._associatedReadableByteStreamController = controller;\n this._view = view;\n }\n\n _createClass(ReadableStreamBYOBRequest, [{\n key: 'respond',\n value: function respond(bytesWritten) {\n if (IsReadableStreamBYOBRequest(this) === false) {\n throw byobRequestBrandCheckException('respond');\n }\n\n if (this._associatedReadableByteStreamController === undefined) {\n throw new TypeError('This BYOB request has been invalidated');\n }\n\n ReadableByteStreamControllerRespond(this._associatedReadableByteStreamController, bytesWritten);\n }\n }, {\n key: 'respondWithNewView',\n value: function respondWithNewView(view) {\n if (IsReadableStreamBYOBRequest(this) === false) {\n throw byobRequestBrandCheckException('respond');\n }\n\n if (this._associatedReadableByteStreamController === undefined) {\n throw new TypeError('This BYOB request has been invalidated');\n }\n\n if (!ArrayBuffer.isView(view)) {\n throw new TypeError('You can only respond with array buffer views');\n }\n\n ReadableByteStreamControllerRespondWithNewView(this._associatedReadableByteStreamController, view);\n }\n }, {\n key: 'view',\n get: function get() {\n return this._view;\n }\n }]);\n\n return ReadableStreamBYOBRequest;\n}();\n\nvar ReadableByteStreamController = function () {\n function ReadableByteStreamController(stream, underlyingByteSource, highWaterMark) {\n _classCallCheck(this, ReadableByteStreamController);\n\n if (IsReadableStream(stream) === false) {\n throw new TypeError('ReadableByteStreamController can only be constructed with a ReadableStream instance given ' + 'a byte source');\n }\n\n if (stream._readableStreamController !== undefined) {\n throw new TypeError('ReadableByteStreamController instances can only be created by the ReadableStream constructor given a byte ' + 'source');\n }\n\n this._controlledReadableStream = stream;\n\n this._underlyingByteSource = underlyingByteSource;\n\n this._pullAgain = false;\n this._pulling = false;\n\n ReadableByteStreamControllerClearPendingPullIntos(this);\n\n // Need to set the slots so that the assert doesn't fire. In the spec the slots already exist implicitly.\n this._queue = this._queueTotalSize = undefined;\n ResetQueue(this);\n\n this._closeRequested = false;\n this._started = false;\n\n this._strategyHWM = ValidateAndNormalizeHighWaterMark(highWaterMark);\n\n var autoAllocateChunkSize = underlyingByteSource.autoAllocateChunkSize;\n if (autoAllocateChunkSize !== undefined) {\n if (Number.isInteger(autoAllocateChunkSize) === false || autoAllocateChunkSize <= 0) {\n throw new RangeError('autoAllocateChunkSize must be a positive integer');\n }\n }\n this._autoAllocateChunkSize = autoAllocateChunkSize;\n\n this._pendingPullIntos = [];\n\n var controller = this;\n\n var startResult = InvokeOrNoop(underlyingByteSource, 'start', [this]);\n Promise.resolve(startResult).then(function () {\n controller._started = true;\n\n assert(controller._pulling === false);\n assert(controller._pullAgain === false);\n\n ReadableByteStreamControllerCallPullIfNeeded(controller);\n }, function (r) {\n if (stream._state === 'readable') {\n ReadableByteStreamControllerError(controller, r);\n }\n }).catch(rethrowAssertionErrorRejection);\n }\n\n _createClass(ReadableByteStreamController, [{\n key: 'close',\n value: function close() {\n if (IsReadableByteStreamController(this) === false) {\n throw byteStreamControllerBrandCheckException('close');\n }\n\n if (this._closeRequested === true) {\n throw new TypeError('The stream has already been closed; do not close it again!');\n }\n\n var state = this._controlledReadableStream._state;\n if (state !== 'readable') {\n throw new TypeError('The stream (in ' + state + ' state) is not in the readable state and cannot be closed');\n }\n\n ReadableByteStreamControllerClose(this);\n }\n }, {\n key: 'enqueue',\n value: function enqueue(chunk) {\n if (IsReadableByteStreamController(this) === false) {\n throw byteStreamControllerBrandCheckException('enqueue');\n }\n\n if (this._closeRequested === true) {\n throw new TypeError('stream is closed or draining');\n }\n\n var state = this._controlledReadableStream._state;\n if (state !== 'readable') {\n throw new TypeError('The stream (in ' + state + ' state) is not in the readable state and cannot be enqueued to');\n }\n\n if (!ArrayBuffer.isView(chunk)) {\n throw new TypeError('You can only enqueue array buffer views when using a ReadableByteStreamController');\n }\n\n ReadableByteStreamControllerEnqueue(this, chunk);\n }\n }, {\n key: 'error',\n value: function error(e) {\n if (IsReadableByteStreamController(this) === false) {\n throw byteStreamControllerBrandCheckException('error');\n }\n\n var stream = this._controlledReadableStream;\n if (stream._state !== 'readable') {\n throw new TypeError('The stream is ' + stream._state + ' and so cannot be errored');\n }\n\n ReadableByteStreamControllerError(this, e);\n }\n }, {\n key: '__cancelSteps',\n value: function __cancelSteps(reason) {\n if (this._pendingPullIntos.length > 0) {\n var firstDescriptor = this._pendingPullIntos[0];\n firstDescriptor.bytesFilled = 0;\n }\n\n ResetQueue(this);\n\n return PromiseInvokeOrNoop(this._underlyingByteSource, 'cancel', [reason]);\n }\n }, {\n key: '__pullSteps',\n value: function __pullSteps() {\n var stream = this._controlledReadableStream;\n assert(ReadableStreamHasDefaultReader(stream) === true);\n\n if (this._queueTotalSize > 0) {\n assert(ReadableStreamGetNumReadRequests(stream) === 0);\n\n var entry = this._queue.shift();\n this._queueTotalSize -= entry.byteLength;\n\n ReadableByteStreamControllerHandleQueueDrain(this);\n\n var view = void 0;\n try {\n view = new Uint8Array(entry.buffer, entry.byteOffset, entry.byteLength);\n } catch (viewE) {\n return Promise.reject(viewE);\n }\n\n return Promise.resolve(CreateIterResultObject(view, false));\n }\n\n var autoAllocateChunkSize = this._autoAllocateChunkSize;\n if (autoAllocateChunkSize !== undefined) {\n var buffer = void 0;\n try {\n buffer = new ArrayBuffer(autoAllocateChunkSize);\n } catch (bufferE) {\n return Promise.reject(bufferE);\n }\n\n var pullIntoDescriptor = {\n buffer: buffer,\n byteOffset: 0,\n byteLength: autoAllocateChunkSize,\n bytesFilled: 0,\n elementSize: 1,\n ctor: Uint8Array,\n readerType: 'default'\n };\n\n this._pendingPullIntos.push(pullIntoDescriptor);\n }\n\n var promise = ReadableStreamAddReadRequest(stream);\n\n ReadableByteStreamControllerCallPullIfNeeded(this);\n\n return promise;\n }\n }, {\n key: 'byobRequest',\n get: function get() {\n if (IsReadableByteStreamController(this) === false) {\n throw byteStreamControllerBrandCheckException('byobRequest');\n }\n\n if (this._byobRequest === undefined && this._pendingPullIntos.length > 0) {\n var firstDescriptor = this._pendingPullIntos[0];\n var view = new Uint8Array(firstDescriptor.buffer, firstDescriptor.byteOffset + firstDescriptor.bytesFilled, firstDescriptor.byteLength - firstDescriptor.bytesFilled);\n\n this._byobRequest = new ReadableStreamBYOBRequest(this, view);\n }\n\n return this._byobRequest;\n }\n }, {\n key: 'desiredSize',\n get: function get() {\n if (IsReadableByteStreamController(this) === false) {\n throw byteStreamControllerBrandCheckException('desiredSize');\n }\n\n return ReadableByteStreamControllerGetDesiredSize(this);\n }\n }]);\n\n return ReadableByteStreamController;\n}();\n\n// Abstract operations for the ReadableByteStreamController.\n\nfunction IsReadableByteStreamController(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_underlyingByteSource')) {\n return false;\n }\n\n return true;\n}\n\nfunction IsReadableStreamBYOBRequest(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_associatedReadableByteStreamController')) {\n return false;\n }\n\n return true;\n}\n\nfunction ReadableByteStreamControllerCallPullIfNeeded(controller) {\n var shouldPull = ReadableByteStreamControllerShouldCallPull(controller);\n if (shouldPull === false) {\n return undefined;\n }\n\n if (controller._pulling === true) {\n controller._pullAgain = true;\n return undefined;\n }\n\n assert(controller._pullAgain === false);\n\n controller._pulling = true;\n\n // TODO: Test controller argument\n var pullPromise = PromiseInvokeOrNoop(controller._underlyingByteSource, 'pull', [controller]);\n pullPromise.then(function () {\n controller._pulling = false;\n\n if (controller._pullAgain === true) {\n controller._pullAgain = false;\n ReadableByteStreamControllerCallPullIfNeeded(controller);\n }\n }, function (e) {\n if (controller._controlledReadableStream._state === 'readable') {\n ReadableByteStreamControllerError(controller, e);\n }\n }).catch(rethrowAssertionErrorRejection);\n\n return undefined;\n}\n\nfunction ReadableByteStreamControllerClearPendingPullIntos(controller) {\n ReadableByteStreamControllerInvalidateBYOBRequest(controller);\n controller._pendingPullIntos = [];\n}\n\nfunction ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor) {\n assert(stream._state !== 'errored', 'state must not be errored');\n\n var done = false;\n if (stream._state === 'closed') {\n assert(pullIntoDescriptor.bytesFilled === 0);\n done = true;\n }\n\n var filledView = ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor);\n if (pullIntoDescriptor.readerType === 'default') {\n ReadableStreamFulfillReadRequest(stream, filledView, done);\n } else {\n assert(pullIntoDescriptor.readerType === 'byob');\n ReadableStreamFulfillReadIntoRequest(stream, filledView, done);\n }\n}\n\nfunction ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor) {\n var bytesFilled = pullIntoDescriptor.bytesFilled;\n var elementSize = pullIntoDescriptor.elementSize;\n\n assert(bytesFilled <= pullIntoDescriptor.byteLength);\n assert(bytesFilled % elementSize === 0);\n\n return new pullIntoDescriptor.ctor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, bytesFilled / elementSize);\n}\n\nfunction ReadableByteStreamControllerEnqueueChunkToQueue(controller, buffer, byteOffset, byteLength) {\n controller._queue.push({ buffer: buffer, byteOffset: byteOffset, byteLength: byteLength });\n controller._queueTotalSize += byteLength;\n}\n\nfunction ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) {\n var elementSize = pullIntoDescriptor.elementSize;\n\n var currentAlignedBytes = pullIntoDescriptor.bytesFilled - pullIntoDescriptor.bytesFilled % elementSize;\n\n var maxBytesToCopy = Math.min(controller._queueTotalSize, pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled);\n var maxBytesFilled = pullIntoDescriptor.bytesFilled + maxBytesToCopy;\n var maxAlignedBytes = maxBytesFilled - maxBytesFilled % elementSize;\n\n var totalBytesToCopyRemaining = maxBytesToCopy;\n var ready = false;\n if (maxAlignedBytes > currentAlignedBytes) {\n totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled;\n ready = true;\n }\n\n var queue = controller._queue;\n\n while (totalBytesToCopyRemaining > 0) {\n var headOfQueue = queue[0];\n\n var bytesToCopy = Math.min(totalBytesToCopyRemaining, headOfQueue.byteLength);\n\n var destStart = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled;\n ArrayBufferCopy(pullIntoDescriptor.buffer, destStart, headOfQueue.buffer, headOfQueue.byteOffset, bytesToCopy);\n\n if (headOfQueue.byteLength === bytesToCopy) {\n queue.shift();\n } else {\n headOfQueue.byteOffset += bytesToCopy;\n headOfQueue.byteLength -= bytesToCopy;\n }\n controller._queueTotalSize -= bytesToCopy;\n\n ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesToCopy, pullIntoDescriptor);\n\n totalBytesToCopyRemaining -= bytesToCopy;\n }\n\n if (ready === false) {\n assert(controller._queueTotalSize === 0, 'queue must be empty');\n assert(pullIntoDescriptor.bytesFilled > 0);\n assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize);\n }\n\n return ready;\n}\n\nfunction ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, size, pullIntoDescriptor) {\n assert(controller._pendingPullIntos.length === 0 || controller._pendingPullIntos[0] === pullIntoDescriptor);\n\n ReadableByteStreamControllerInvalidateBYOBRequest(controller);\n pullIntoDescriptor.bytesFilled += size;\n}\n\nfunction ReadableByteStreamControllerHandleQueueDrain(controller) {\n assert(controller._controlledReadableStream._state === 'readable');\n\n if (controller._queueTotalSize === 0 && controller._closeRequested === true) {\n ReadableStreamClose(controller._controlledReadableStream);\n } else {\n ReadableByteStreamControllerCallPullIfNeeded(controller);\n }\n}\n\nfunction ReadableByteStreamControllerInvalidateBYOBRequest(controller) {\n if (controller._byobRequest === undefined) {\n return;\n }\n\n controller._byobRequest._associatedReadableByteStreamController = undefined;\n controller._byobRequest._view = undefined;\n controller._byobRequest = undefined;\n}\n\nfunction ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller) {\n assert(controller._closeRequested === false);\n\n while (controller._pendingPullIntos.length > 0) {\n if (controller._queueTotalSize === 0) {\n return;\n }\n\n var pullIntoDescriptor = controller._pendingPullIntos[0];\n\n if (ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) === true) {\n ReadableByteStreamControllerShiftPendingPullInto(controller);\n\n ReadableByteStreamControllerCommitPullIntoDescriptor(controller._controlledReadableStream, pullIntoDescriptor);\n }\n }\n}\n\nfunction ReadableByteStreamControllerPullInto(controller, view) {\n var stream = controller._controlledReadableStream;\n\n var elementSize = 1;\n if (view.constructor !== DataView) {\n elementSize = view.constructor.BYTES_PER_ELEMENT;\n }\n\n var ctor = view.constructor;\n\n var pullIntoDescriptor = {\n buffer: view.buffer,\n byteOffset: view.byteOffset,\n byteLength: view.byteLength,\n bytesFilled: 0,\n elementSize: elementSize,\n ctor: ctor,\n readerType: 'byob'\n };\n\n if (controller._pendingPullIntos.length > 0) {\n pullIntoDescriptor.buffer = TransferArrayBuffer(pullIntoDescriptor.buffer);\n controller._pendingPullIntos.push(pullIntoDescriptor);\n\n // No ReadableByteStreamControllerCallPullIfNeeded() call since:\n // - No change happens on desiredSize\n // - The source has already been notified of that there's at least 1 pending read(view)\n\n return ReadableStreamAddReadIntoRequest(stream);\n }\n\n if (stream._state === 'closed') {\n var emptyView = new view.constructor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, 0);\n return Promise.resolve(CreateIterResultObject(emptyView, true));\n }\n\n if (controller._queueTotalSize > 0) {\n if (ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) === true) {\n var filledView = ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor);\n\n ReadableByteStreamControllerHandleQueueDrain(controller);\n\n return Promise.resolve(CreateIterResultObject(filledView, false));\n }\n\n if (controller._closeRequested === true) {\n var e = new TypeError('Insufficient bytes to fill elements in the given buffer');\n ReadableByteStreamControllerError(controller, e);\n\n return Promise.reject(e);\n }\n }\n\n pullIntoDescriptor.buffer = TransferArrayBuffer(pullIntoDescriptor.buffer);\n controller._pendingPullIntos.push(pullIntoDescriptor);\n\n var promise = ReadableStreamAddReadIntoRequest(stream);\n\n ReadableByteStreamControllerCallPullIfNeeded(controller);\n\n return promise;\n}\n\nfunction ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor) {\n firstDescriptor.buffer = TransferArrayBuffer(firstDescriptor.buffer);\n\n assert(firstDescriptor.bytesFilled === 0, 'bytesFilled must be 0');\n\n var stream = controller._controlledReadableStream;\n if (ReadableStreamHasBYOBReader(stream) === true) {\n while (ReadableStreamGetNumReadIntoRequests(stream) > 0) {\n var pullIntoDescriptor = ReadableByteStreamControllerShiftPendingPullInto(controller);\n ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor);\n }\n }\n}\n\nfunction ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, pullIntoDescriptor) {\n if (pullIntoDescriptor.bytesFilled + bytesWritten > pullIntoDescriptor.byteLength) {\n throw new RangeError('bytesWritten out of range');\n }\n\n ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesWritten, pullIntoDescriptor);\n\n if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize) {\n // TODO: Figure out whether we should detach the buffer or not here.\n return;\n }\n\n ReadableByteStreamControllerShiftPendingPullInto(controller);\n\n var remainderSize = pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize;\n if (remainderSize > 0) {\n var end = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled;\n var remainder = pullIntoDescriptor.buffer.slice(end - remainderSize, end);\n ReadableByteStreamControllerEnqueueChunkToQueue(controller, remainder, 0, remainder.byteLength);\n }\n\n pullIntoDescriptor.buffer = TransferArrayBuffer(pullIntoDescriptor.buffer);\n pullIntoDescriptor.bytesFilled -= remainderSize;\n ReadableByteStreamControllerCommitPullIntoDescriptor(controller._controlledReadableStream, pullIntoDescriptor);\n\n ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller);\n}\n\nfunction ReadableByteStreamControllerRespondInternal(controller, bytesWritten) {\n var firstDescriptor = controller._pendingPullIntos[0];\n\n var stream = controller._controlledReadableStream;\n\n if (stream._state === 'closed') {\n if (bytesWritten !== 0) {\n throw new TypeError('bytesWritten must be 0 when calling respond() on a closed stream');\n }\n\n ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor);\n } else {\n assert(stream._state === 'readable');\n\n ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, firstDescriptor);\n }\n}\n\nfunction ReadableByteStreamControllerShiftPendingPullInto(controller) {\n var descriptor = controller._pendingPullIntos.shift();\n ReadableByteStreamControllerInvalidateBYOBRequest(controller);\n return descriptor;\n}\n\nfunction ReadableByteStreamControllerShouldCallPull(controller) {\n var stream = controller._controlledReadableStream;\n\n if (stream._state !== 'readable') {\n return false;\n }\n\n if (controller._closeRequested === true) {\n return false;\n }\n\n if (controller._started === false) {\n return false;\n }\n\n if (ReadableStreamHasDefaultReader(stream) === true && ReadableStreamGetNumReadRequests(stream) > 0) {\n return true;\n }\n\n if (ReadableStreamHasBYOBReader(stream) === true && ReadableStreamGetNumReadIntoRequests(stream) > 0) {\n return true;\n }\n\n if (ReadableByteStreamControllerGetDesiredSize(controller) > 0) {\n return true;\n }\n\n return false;\n}\n\n// A client of ReadableByteStreamController may use these functions directly to bypass state check.\n\nfunction ReadableByteStreamControllerClose(controller) {\n var stream = controller._controlledReadableStream;\n\n assert(controller._closeRequested === false);\n assert(stream._state === 'readable');\n\n if (controller._queueTotalSize > 0) {\n controller._closeRequested = true;\n\n return;\n }\n\n if (controller._pendingPullIntos.length > 0) {\n var firstPendingPullInto = controller._pendingPullIntos[0];\n if (firstPendingPullInto.bytesFilled > 0) {\n var e = new TypeError('Insufficient bytes to fill elements in the given buffer');\n ReadableByteStreamControllerError(controller, e);\n\n throw e;\n }\n }\n\n ReadableStreamClose(stream);\n}\n\nfunction ReadableByteStreamControllerEnqueue(controller, chunk) {\n var stream = controller._controlledReadableStream;\n\n assert(controller._closeRequested === false);\n assert(stream._state === 'readable');\n\n var buffer = chunk.buffer;\n var byteOffset = chunk.byteOffset;\n var byteLength = chunk.byteLength;\n var transferredBuffer = TransferArrayBuffer(buffer);\n\n if (ReadableStreamHasDefaultReader(stream) === true) {\n if (ReadableStreamGetNumReadRequests(stream) === 0) {\n ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength);\n } else {\n assert(controller._queue.length === 0);\n\n var transferredView = new Uint8Array(transferredBuffer, byteOffset, byteLength);\n ReadableStreamFulfillReadRequest(stream, transferredView, false);\n }\n } else if (ReadableStreamHasBYOBReader(stream) === true) {\n // TODO: Ideally in this branch detaching should happen only if the buffer is not consumed fully.\n ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength);\n ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller);\n } else {\n assert(IsReadableStreamLocked(stream) === false, 'stream must not be locked');\n ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength);\n }\n}\n\nfunction ReadableByteStreamControllerError(controller, e) {\n var stream = controller._controlledReadableStream;\n\n assert(stream._state === 'readable');\n\n ReadableByteStreamControllerClearPendingPullIntos(controller);\n\n ResetQueue(controller);\n ReadableStreamError(stream, e);\n}\n\nfunction ReadableByteStreamControllerGetDesiredSize(controller) {\n var stream = controller._controlledReadableStream;\n var state = stream._state;\n\n if (state === 'errored') {\n return null;\n }\n if (state === 'closed') {\n return 0;\n }\n\n return controller._strategyHWM - controller._queueTotalSize;\n}\n\nfunction ReadableByteStreamControllerRespond(controller, bytesWritten) {\n bytesWritten = Number(bytesWritten);\n if (IsFiniteNonNegativeNumber(bytesWritten) === false) {\n throw new RangeError('bytesWritten must be a finite');\n }\n\n assert(controller._pendingPullIntos.length > 0);\n\n ReadableByteStreamControllerRespondInternal(controller, bytesWritten);\n}\n\nfunction ReadableByteStreamControllerRespondWithNewView(controller, view) {\n assert(controller._pendingPullIntos.length > 0);\n\n var firstDescriptor = controller._pendingPullIntos[0];\n\n if (firstDescriptor.byteOffset + firstDescriptor.bytesFilled !== view.byteOffset) {\n throw new RangeError('The region specified by view does not match byobRequest');\n }\n if (firstDescriptor.byteLength !== view.byteLength) {\n throw new RangeError('The buffer of view has different capacity than byobRequest');\n }\n\n firstDescriptor.buffer = view.buffer;\n\n ReadableByteStreamControllerRespondInternal(controller, view.byteLength);\n}\n\n// Helper functions for the ReadableStream.\n\nfunction streamBrandCheckException(name) {\n return new TypeError('ReadableStream.prototype.' + name + ' can only be used on a ReadableStream');\n}\n\n// Helper functions for the readers.\n\nfunction readerLockException(name) {\n return new TypeError('Cannot ' + name + ' a stream using a released reader');\n}\n\n// Helper functions for the ReadableStreamDefaultReader.\n\nfunction defaultReaderBrandCheckException(name) {\n return new TypeError('ReadableStreamDefaultReader.prototype.' + name + ' can only be used on a ReadableStreamDefaultReader');\n}\n\nfunction defaultReaderClosedPromiseInitialize(reader) {\n reader._closedPromise = new Promise(function (resolve, reject) {\n reader._closedPromise_resolve = resolve;\n reader._closedPromise_reject = reject;\n });\n}\n\nfunction defaultReaderClosedPromiseInitializeAsRejected(reader, reason) {\n reader._closedPromise = Promise.reject(reason);\n reader._closedPromise_resolve = undefined;\n reader._closedPromise_reject = undefined;\n}\n\nfunction defaultReaderClosedPromiseInitializeAsResolved(reader) {\n reader._closedPromise = Promise.resolve(undefined);\n reader._closedPromise_resolve = undefined;\n reader._closedPromise_reject = undefined;\n}\n\nfunction defaultReaderClosedPromiseReject(reader, reason) {\n assert(reader._closedPromise_resolve !== undefined);\n assert(reader._closedPromise_reject !== undefined);\n\n reader._closedPromise_reject(reason);\n reader._closedPromise_resolve = undefined;\n reader._closedPromise_reject = undefined;\n}\n\nfunction defaultReaderClosedPromiseResetToRejected(reader, reason) {\n assert(reader._closedPromise_resolve === undefined);\n assert(reader._closedPromise_reject === undefined);\n\n reader._closedPromise = Promise.reject(reason);\n}\n\nfunction defaultReaderClosedPromiseResolve(reader) {\n assert(reader._closedPromise_resolve !== undefined);\n assert(reader._closedPromise_reject !== undefined);\n\n reader._closedPromise_resolve(undefined);\n reader._closedPromise_resolve = undefined;\n reader._closedPromise_reject = undefined;\n}\n\n// Helper functions for the ReadableStreamDefaultReader.\n\nfunction byobReaderBrandCheckException(name) {\n return new TypeError('ReadableStreamBYOBReader.prototype.' + name + ' can only be used on a ReadableStreamBYOBReader');\n}\n\n// Helper functions for the ReadableStreamDefaultController.\n\nfunction defaultControllerBrandCheckException(name) {\n return new TypeError('ReadableStreamDefaultController.prototype.' + name + ' can only be used on a ReadableStreamDefaultController');\n}\n\n// Helper functions for the ReadableStreamBYOBRequest.\n\nfunction byobRequestBrandCheckException(name) {\n return new TypeError('ReadableStreamBYOBRequest.prototype.' + name + ' can only be used on a ReadableStreamBYOBRequest');\n}\n\n// Helper functions for the ReadableByteStreamController.\n\nfunction byteStreamControllerBrandCheckException(name) {\n return new TypeError('ReadableByteStreamController.prototype.' + name + ' can only be used on a ReadableByteStreamController');\n}\n\n// Helper function for ReadableStream pipeThrough\n\nfunction ifIsObjectAndHasAPromiseIsHandledInternalSlotSetPromiseIsHandledToTrue(promise) {\n try {\n // This relies on the brand-check that is enforced by Promise.prototype.then(). As with the rest of the reference\n // implementation, it doesn't attempt to do the right thing if someone has modified the global environment.\n Promise.prototype.then.call(promise, undefined, function () {});\n } catch (e) {\n // The brand check failed, therefore the internal slot is not present and there's nothing further to do.\n }\n}\n\n/***/ }),\n/* 5 */\n/***/ (function(module, exports, __w_pdfjs_require__) {\n\n\"use strict\";\n\n\nvar transformStream = __w_pdfjs_require__(6);\nvar readableStream = __w_pdfjs_require__(4);\nvar writableStream = __w_pdfjs_require__(2);\n\nexports.TransformStream = transformStream.TransformStream;\nexports.ReadableStream = readableStream.ReadableStream;\nexports.IsReadableStreamDisturbed = readableStream.IsReadableStreamDisturbed;\nexports.ReadableStreamDefaultControllerClose = readableStream.ReadableStreamDefaultControllerClose;\nexports.ReadableStreamDefaultControllerEnqueue = readableStream.ReadableStreamDefaultControllerEnqueue;\nexports.ReadableStreamDefaultControllerError = readableStream.ReadableStreamDefaultControllerError;\nexports.ReadableStreamDefaultControllerGetDesiredSize = readableStream.ReadableStreamDefaultControllerGetDesiredSize;\nexports.AcquireWritableStreamDefaultWriter = writableStream.AcquireWritableStreamDefaultWriter;\nexports.IsWritableStream = writableStream.IsWritableStream;\nexports.IsWritableStreamLocked = writableStream.IsWritableStreamLocked;\nexports.WritableStream = writableStream.WritableStream;\nexports.WritableStreamAbort = writableStream.WritableStreamAbort;\nexports.WritableStreamDefaultControllerError = writableStream.WritableStreamDefaultControllerError;\nexports.WritableStreamDefaultWriterCloseWithErrorPropagation = writableStream.WritableStreamDefaultWriterCloseWithErrorPropagation;\nexports.WritableStreamDefaultWriterRelease = writableStream.WritableStreamDefaultWriterRelease;\nexports.WritableStreamDefaultWriterWrite = writableStream.WritableStreamDefaultWriterWrite;\n\n/***/ }),\n/* 6 */\n/***/ (function(module, exports, __w_pdfjs_require__) {\n\n\"use strict\";\n\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar _require = __w_pdfjs_require__(1),\n assert = _require.assert;\n\nvar _require2 = __w_pdfjs_require__(0),\n InvokeOrNoop = _require2.InvokeOrNoop,\n PromiseInvokeOrPerformFallback = _require2.PromiseInvokeOrPerformFallback,\n PromiseInvokeOrNoop = _require2.PromiseInvokeOrNoop,\n typeIsObject = _require2.typeIsObject;\n\nvar _require3 = __w_pdfjs_require__(4),\n ReadableStream = _require3.ReadableStream,\n ReadableStreamDefaultControllerClose = _require3.ReadableStreamDefaultControllerClose,\n ReadableStreamDefaultControllerEnqueue = _require3.ReadableStreamDefaultControllerEnqueue,\n ReadableStreamDefaultControllerError = _require3.ReadableStreamDefaultControllerError,\n ReadableStreamDefaultControllerGetDesiredSize = _require3.ReadableStreamDefaultControllerGetDesiredSize;\n\nvar _require4 = __w_pdfjs_require__(2),\n WritableStream = _require4.WritableStream,\n WritableStreamDefaultControllerError = _require4.WritableStreamDefaultControllerError;\n\n// Methods on the transform stream controller object\n\nfunction TransformStreamCloseReadable(transformStream) {\n // console.log('TransformStreamCloseReadable()');\n\n if (transformStream._errored === true) {\n throw new TypeError('TransformStream is already errored');\n }\n\n if (transformStream._readableClosed === true) {\n throw new TypeError('Readable side is already closed');\n }\n\n TransformStreamCloseReadableInternal(transformStream);\n}\n\nfunction TransformStreamEnqueueToReadable(transformStream, chunk) {\n // console.log('TransformStreamEnqueueToReadable()');\n\n if (transformStream._errored === true) {\n throw new TypeError('TransformStream is already errored');\n }\n\n if (transformStream._readableClosed === true) {\n throw new TypeError('Readable side is already closed');\n }\n\n // We throttle transformer.transform invocation based on the backpressure of the ReadableStream, but we still\n // accept TransformStreamEnqueueToReadable() calls.\n\n var controller = transformStream._readableController;\n\n try {\n ReadableStreamDefaultControllerEnqueue(controller, chunk);\n } catch (e) {\n // This happens when readableStrategy.size() throws.\n // The ReadableStream has already errored itself.\n transformStream._readableClosed = true;\n TransformStreamErrorIfNeeded(transformStream, e);\n\n throw transformStream._storedError;\n }\n\n var desiredSize = ReadableStreamDefaultControllerGetDesiredSize(controller);\n var maybeBackpressure = desiredSize <= 0;\n\n if (maybeBackpressure === true && transformStream._backpressure === false) {\n // This allows pull() again. When desiredSize is 0, it's possible that a pull() will happen immediately (but\n // asynchronously) after this because of pending read()s and set _backpressure back to false.\n //\n // If pull() could be called from inside enqueue(), then this logic would be wrong. This cannot happen\n // because there is always a promise pending from start() or pull() when _backpressure is false.\n TransformStreamSetBackpressure(transformStream, true);\n }\n}\n\nfunction TransformStreamError(transformStream, e) {\n if (transformStream._errored === true) {\n throw new TypeError('TransformStream is already errored');\n }\n\n TransformStreamErrorInternal(transformStream, e);\n}\n\n// Abstract operations.\n\nfunction TransformStreamCloseReadableInternal(transformStream) {\n assert(transformStream._errored === false);\n assert(transformStream._readableClosed === false);\n\n try {\n ReadableStreamDefaultControllerClose(transformStream._readableController);\n } catch (e) {\n assert(false);\n }\n\n transformStream._readableClosed = true;\n}\n\nfunction TransformStreamErrorIfNeeded(transformStream, e) {\n if (transformStream._errored === false) {\n TransformStreamErrorInternal(transformStream, e);\n }\n}\n\nfunction TransformStreamErrorInternal(transformStream, e) {\n // console.log('TransformStreamErrorInternal()');\n\n assert(transformStream._errored === false);\n\n transformStream._errored = true;\n transformStream._storedError = e;\n\n if (transformStream._writableDone === false) {\n WritableStreamDefaultControllerError(transformStream._writableController, e);\n }\n if (transformStream._readableClosed === false) {\n ReadableStreamDefaultControllerError(transformStream._readableController, e);\n }\n}\n\n// Used for preventing the next write() call on TransformStreamSink until there\n// is no longer backpressure.\nfunction TransformStreamReadableReadyPromise(transformStream) {\n assert(transformStream._backpressureChangePromise !== undefined, '_backpressureChangePromise should have been initialized');\n\n if (transformStream._backpressure === false) {\n return Promise.resolve();\n }\n\n assert(transformStream._backpressure === true, '_backpressure should have been initialized');\n\n return transformStream._backpressureChangePromise;\n}\n\nfunction TransformStreamSetBackpressure(transformStream, backpressure) {\n // console.log(`TransformStreamSetBackpressure(${backpressure})`);\n\n // Passes also when called during construction.\n assert(transformStream._backpressure !== backpressure, 'TransformStreamSetBackpressure() should be called only when backpressure is changed');\n\n if (transformStream._backpressureChangePromise !== undefined) {\n // The fulfillment value is just for a sanity check.\n transformStream._backpressureChangePromise_resolve(backpressure);\n }\n\n transformStream._backpressureChangePromise = new Promise(function (resolve) {\n transformStream._backpressureChangePromise_resolve = resolve;\n });\n\n transformStream._backpressureChangePromise.then(function (resolution) {\n assert(resolution !== backpressure, '_backpressureChangePromise should be fulfilled only when backpressure is changed');\n });\n\n transformStream._backpressure = backpressure;\n}\n\nfunction TransformStreamDefaultTransform(chunk, transformStreamController) {\n var transformStream = transformStreamController._controlledTransformStream;\n TransformStreamEnqueueToReadable(transformStream, chunk);\n return Promise.resolve();\n}\n\nfunction TransformStreamTransform(transformStream, chunk) {\n // console.log('TransformStreamTransform()');\n\n assert(transformStream._errored === false);\n assert(transformStream._transforming === false);\n assert(transformStream._backpressure === false);\n\n transformStream._transforming = true;\n\n var transformer = transformStream._transformer;\n var controller = transformStream._transformStreamController;\n\n var transformPromise = PromiseInvokeOrPerformFallback(transformer, 'transform', [chunk, controller], TransformStreamDefaultTransform, [chunk, controller]);\n\n return transformPromise.then(function () {\n transformStream._transforming = false;\n\n return TransformStreamReadableReadyPromise(transformStream);\n }, function (e) {\n TransformStreamErrorIfNeeded(transformStream, e);\n return Promise.reject(e);\n });\n}\n\nfunction IsTransformStreamDefaultController(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_controlledTransformStream')) {\n return false;\n }\n\n return true;\n}\n\nfunction IsTransformStream(x) {\n if (!typeIsObject(x)) {\n return false;\n }\n\n if (!Object.prototype.hasOwnProperty.call(x, '_transformStreamController')) {\n return false;\n }\n\n return true;\n}\n\nvar TransformStreamSink = function () {\n function TransformStreamSink(transformStream, startPromise) {\n _classCallCheck(this, TransformStreamSink);\n\n this._transformStream = transformStream;\n this._startPromise = startPromise;\n }\n\n _createClass(TransformStreamSink, [{\n key: 'start',\n value: function start(c) {\n var transformStream = this._transformStream;\n\n transformStream._writableController = c;\n\n return this._startPromise.then(function () {\n return TransformStreamReadableReadyPromise(transformStream);\n });\n }\n }, {\n key: 'write',\n value: function write(chunk) {\n // console.log('TransformStreamSink.write()');\n\n var transformStream = this._transformStream;\n\n return TransformStreamTransform(transformStream, chunk);\n }\n }, {\n key: 'abort',\n value: function abort() {\n var transformStream = this._transformStream;\n transformStream._writableDone = true;\n TransformStreamErrorInternal(transformStream, new TypeError('Writable side aborted'));\n }\n }, {\n key: 'close',\n value: function close() {\n // console.log('TransformStreamSink.close()');\n\n var transformStream = this._transformStream;\n\n assert(transformStream._transforming === false);\n\n transformStream._writableDone = true;\n\n var flushPromise = PromiseInvokeOrNoop(transformStream._transformer, 'flush', [transformStream._transformStreamController]);\n // Return a promise that is fulfilled with undefined on success.\n return flushPromise.then(function () {\n if (transformStream._errored === true) {\n return Promise.reject(transformStream._storedError);\n }\n if (transformStream._readableClosed === false) {\n TransformStreamCloseReadableInternal(transformStream);\n }\n return Promise.resolve();\n }).catch(function (r) {\n TransformStreamErrorIfNeeded(transformStream, r);\n return Promise.reject(transformStream._storedError);\n });\n }\n }]);\n\n return TransformStreamSink;\n}();\n\nvar TransformStreamSource = function () {\n function TransformStreamSource(transformStream, startPromise) {\n _classCallCheck(this, TransformStreamSource);\n\n this._transformStream = transformStream;\n this._startPromise = startPromise;\n }\n\n _createClass(TransformStreamSource, [{\n key: 'start',\n value: function start(c) {\n var transformStream = this._transformStream;\n\n transformStream._readableController = c;\n\n return this._startPromise.then(function () {\n // Prevent the first pull() call until there is backpressure.\n\n assert(transformStream._backpressureChangePromise !== undefined, '_backpressureChangePromise should have been initialized');\n\n if (transformStream._backpressure === true) {\n return Promise.resolve();\n }\n\n assert(transformStream._backpressure === false, '_backpressure should have been initialized');\n\n return transformStream._backpressureChangePromise;\n });\n }\n }, {\n key: 'pull',\n value: function pull() {\n // console.log('TransformStreamSource.pull()');\n\n var transformStream = this._transformStream;\n\n // Invariant. Enforced by the promises returned by start() and pull().\n assert(transformStream._backpressure === true, 'pull() should be never called while _backpressure is false');\n\n assert(transformStream._backpressureChangePromise !== undefined, '_backpressureChangePromise should have been initialized');\n\n TransformStreamSetBackpressure(transformStream, false);\n\n // Prevent the next pull() call until there is backpressure.\n return transformStream._backpressureChangePromise;\n }\n }, {\n key: 'cancel',\n value: function cancel() {\n var transformStream = this._transformStream;\n transformStream._readableClosed = true;\n TransformStreamErrorInternal(transformStream, new TypeError('Readable side canceled'));\n }\n }]);\n\n return TransformStreamSource;\n}();\n\nvar TransformStreamDefaultController = function () {\n function TransformStreamDefaultController(transformStream) {\n _classCallCheck(this, TransformStreamDefaultController);\n\n if (IsTransformStream(transformStream) === false) {\n throw new TypeError('TransformStreamDefaultController can only be ' + 'constructed with a TransformStream instance');\n }\n\n if (transformStream._transformStreamController !== undefined) {\n throw new TypeError('TransformStreamDefaultController instances can ' + 'only be created by the TransformStream constructor');\n }\n\n this._controlledTransformStream = transformStream;\n }\n\n _createClass(TransformStreamDefaultController, [{\n key: 'enqueue',\n value: function enqueue(chunk) {\n if (IsTransformStreamDefaultController(this) === false) {\n throw defaultControllerBrandCheckException('enqueue');\n }\n\n TransformStreamEnqueueToReadable(this._controlledTransformStream, chunk);\n }\n }, {\n key: 'close',\n value: function close() {\n if (IsTransformStreamDefaultController(this) === false) {\n throw defaultControllerBrandCheckException('close');\n }\n\n TransformStreamCloseReadable(this._controlledTransformStream);\n }\n }, {\n key: 'error',\n value: function error(reason) {\n if (IsTransformStreamDefaultController(this) === false) {\n throw defaultControllerBrandCheckException('error');\n }\n\n TransformStreamError(this._controlledTransformStream, reason);\n }\n }, {\n key: 'desiredSize',\n get: function get() {\n if (IsTransformStreamDefaultController(this) === false) {\n throw defaultControllerBrandCheckException('desiredSize');\n }\n\n var transformStream = this._controlledTransformStream;\n var readableController = transformStream._readableController;\n\n return ReadableStreamDefaultControllerGetDesiredSize(readableController);\n }\n }]);\n\n return TransformStreamDefaultController;\n}();\n\nvar TransformStream = function () {\n function TransformStream() {\n var transformer = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n _classCallCheck(this, TransformStream);\n\n this._transformer = transformer;\n var readableStrategy = transformer.readableStrategy,\n writableStrategy = transformer.writableStrategy;\n\n\n this._transforming = false;\n this._errored = false;\n this._storedError = undefined;\n\n this._writableController = undefined;\n this._readableController = undefined;\n this._transformStreamController = undefined;\n\n this._writableDone = false;\n this._readableClosed = false;\n\n this._backpressure = undefined;\n this._backpressureChangePromise = undefined;\n this._backpressureChangePromise_resolve = undefined;\n\n this._transformStreamController = new TransformStreamDefaultController(this);\n\n var startPromise_resolve = void 0;\n var startPromise = new Promise(function (resolve) {\n startPromise_resolve = resolve;\n });\n\n var source = new TransformStreamSource(this, startPromise);\n\n this._readable = new ReadableStream(source, readableStrategy);\n\n var sink = new TransformStreamSink(this, startPromise);\n\n this._writable = new WritableStream(sink, writableStrategy);\n\n assert(this._writableController !== undefined);\n assert(this._readableController !== undefined);\n\n var desiredSize = ReadableStreamDefaultControllerGetDesiredSize(this._readableController);\n // Set _backpressure based on desiredSize. As there is no read() at this point, we can just interpret\n // desiredSize being non-positive as backpressure.\n TransformStreamSetBackpressure(this, desiredSize <= 0);\n\n var transformStream = this;\n var startResult = InvokeOrNoop(transformer, 'start', [transformStream._transformStreamController]);\n startPromise_resolve(startResult);\n startPromise.catch(function (e) {\n // The underlyingSink and underlyingSource will error the readable and writable ends on their own.\n if (transformStream._errored === false) {\n transformStream._errored = true;\n transformStream._storedError = e;\n }\n });\n }\n\n _createClass(TransformStream, [{\n key: 'readable',\n get: function get() {\n if (IsTransformStream(this) === false) {\n throw streamBrandCheckException('readable');\n }\n\n return this._readable;\n }\n }, {\n key: 'writable',\n get: function get() {\n if (IsTransformStream(this) === false) {\n throw streamBrandCheckException('writable');\n }\n\n return this._writable;\n }\n }]);\n\n return TransformStream;\n}();\n\nmodule.exports = { TransformStream: TransformStream };\n\n// Helper functions for the TransformStreamDefaultController.\n\nfunction defaultControllerBrandCheckException(name) {\n return new TypeError('TransformStreamDefaultController.prototype.' + name + ' can only be used on a TransformStreamDefaultController');\n}\n\n// Helper functions for the TransformStream.\n\nfunction streamBrandCheckException(name) {\n return new TypeError('TransformStream.prototype.' + name + ' can only be used on a TransformStream');\n}\n\n/***/ }),\n/* 7 */\n/***/ (function(module, exports, __w_pdfjs_require__) {\n\nmodule.exports = __w_pdfjs_require__(5);\n\n\n/***/ })\n/******/ ])));\n\n\n// WEBPACK FOOTER //\n// external/streams/streams-lib.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AnnotationBorderStyleType, AnnotationFieldFlag, AnnotationFlag,\n AnnotationType, isArray, isInt, OPS, stringToBytes, stringToPDFString, Util,\n warn\n} from '../shared/util';\nimport { Catalog, FileSpec, ObjectLoader } from './obj';\nimport { Dict, isDict, isName, isRef, isStream } from './primitives';\nimport { ColorSpace } from './colorspace';\nimport { OperatorList } from './evaluator';\nimport { Stream } from './stream';\n\n/**\n * @class\n * @alias AnnotationFactory\n */\nfunction AnnotationFactory() {}\nAnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {\n /**\n * @param {XRef} xref\n * @param {Object} ref\n * @param {PDFManager} pdfManager\n * @param {Object} idFactory\n * @returns {Annotation}\n */\n create: function AnnotationFactory_create(xref, ref, pdfManager, idFactory) {\n var dict = xref.fetchIfRef(ref);\n if (!isDict(dict)) {\n return;\n }\n var id = isRef(ref) ? ref.toString() : 'annot_' + idFactory.createObjId();\n\n // Determine the annotation's subtype.\n var subtype = dict.get('Subtype');\n subtype = isName(subtype) ? subtype.name : null;\n\n // Return the right annotation object based on the subtype and field type.\n var parameters = {\n xref,\n dict,\n ref: isRef(ref) ? ref : null,\n subtype,\n id,\n pdfManager,\n };\n\n switch (subtype) {\n case 'Link':\n return new LinkAnnotation(parameters);\n\n case 'Text':\n return new TextAnnotation(parameters);\n\n case 'Widget':\n var fieldType = Util.getInheritableProperty(dict, 'FT');\n fieldType = isName(fieldType) ? fieldType.name : null;\n\n switch (fieldType) {\n case 'Tx':\n return new TextWidgetAnnotation(parameters);\n case 'Btn':\n return new ButtonWidgetAnnotation(parameters);\n case 'Ch':\n return new ChoiceWidgetAnnotation(parameters);\n }\n warn('Unimplemented widget field type \"' + fieldType + '\", ' +\n 'falling back to base field type.');\n return new WidgetAnnotation(parameters);\n\n case 'Popup':\n return new PopupAnnotation(parameters);\n\n case 'Line':\n return new LineAnnotation(parameters);\n\n case 'Highlight':\n return new HighlightAnnotation(parameters);\n\n case 'Underline':\n return new UnderlineAnnotation(parameters);\n\n case 'Squiggly':\n return new SquigglyAnnotation(parameters);\n\n case 'StrikeOut':\n return new StrikeOutAnnotation(parameters);\n\n case 'FileAttachment':\n return new FileAttachmentAnnotation(parameters);\n\n default:\n if (!subtype) {\n warn('Annotation is missing the required /Subtype.');\n } else {\n warn('Unimplemented annotation type \"' + subtype + '\", ' +\n 'falling back to base annotation.');\n }\n return new Annotation(parameters);\n }\n },\n};\n\nvar Annotation = (function AnnotationClosure() {\n // 12.5.5: Algorithm: Appearance streams\n function getTransformMatrix(rect, bbox, matrix) {\n var bounds = Util.getAxialAlignedBoundingBox(bbox, matrix);\n var minX = bounds[0];\n var minY = bounds[1];\n var maxX = bounds[2];\n var maxY = bounds[3];\n\n if (minX === maxX || minY === maxY) {\n // From real-life file, bbox was [0, 0, 0, 0]. In this case,\n // just apply the transform for rect\n return [1, 0, 0, 1, rect[0], rect[1]];\n }\n\n var xRatio = (rect[2] - rect[0]) / (maxX - minX);\n var yRatio = (rect[3] - rect[1]) / (maxY - minY);\n return [\n xRatio,\n 0,\n 0,\n yRatio,\n rect[0] - minX * xRatio,\n rect[1] - minY * yRatio\n ];\n }\n\n function Annotation(params) {\n var dict = params.dict;\n\n this.setFlags(dict.get('F'));\n this.setRectangle(dict.getArray('Rect'));\n this.setColor(dict.getArray('C'));\n this.setBorderStyle(dict);\n this.setAppearance(dict);\n\n // Expose public properties using a data object.\n this.data = {};\n this.data.id = params.id;\n this.data.subtype = params.subtype;\n this.data.annotationFlags = this.flags;\n this.data.rect = this.rectangle;\n this.data.color = this.color;\n this.data.borderStyle = this.borderStyle;\n this.data.hasAppearance = !!this.appearance;\n }\n\n Annotation.prototype = {\n /**\n * @private\n */\n _hasFlag: function Annotation_hasFlag(flags, flag) {\n return !!(flags & flag);\n },\n\n /**\n * @private\n */\n _isViewable: function Annotation_isViewable(flags) {\n return !this._hasFlag(flags, AnnotationFlag.INVISIBLE) &&\n !this._hasFlag(flags, AnnotationFlag.HIDDEN) &&\n !this._hasFlag(flags, AnnotationFlag.NOVIEW);\n },\n\n /**\n * @private\n */\n _isPrintable: function AnnotationFlag_isPrintable(flags) {\n return this._hasFlag(flags, AnnotationFlag.PRINT) &&\n !this._hasFlag(flags, AnnotationFlag.INVISIBLE) &&\n !this._hasFlag(flags, AnnotationFlag.HIDDEN);\n },\n\n /**\n * @return {boolean}\n */\n get viewable() {\n if (this.flags === 0) {\n return true;\n }\n return this._isViewable(this.flags);\n },\n\n /**\n * @return {boolean}\n */\n get printable() {\n if (this.flags === 0) {\n return false;\n }\n return this._isPrintable(this.flags);\n },\n\n /**\n * Set the flags.\n *\n * @public\n * @memberof Annotation\n * @param {number} flags - Unsigned 32-bit integer specifying annotation\n * characteristics\n * @see {@link shared/util.js}\n */\n setFlags: function Annotation_setFlags(flags) {\n this.flags = (isInt(flags) && flags > 0) ? flags : 0;\n },\n\n /**\n * Check if a provided flag is set.\n *\n * @public\n * @memberof Annotation\n * @param {number} flag - Hexadecimal representation for an annotation\n * characteristic\n * @return {boolean}\n * @see {@link shared/util.js}\n */\n hasFlag: function Annotation_hasFlag(flag) {\n return this._hasFlag(this.flags, flag);\n },\n\n /**\n * Set the rectangle.\n *\n * @public\n * @memberof Annotation\n * @param {Array} rectangle - The rectangle array with exactly four entries\n */\n setRectangle: function Annotation_setRectangle(rectangle) {\n if (isArray(rectangle) && rectangle.length === 4) {\n this.rectangle = Util.normalizeRect(rectangle);\n } else {\n this.rectangle = [0, 0, 0, 0];\n }\n },\n\n /**\n * Set the color and take care of color space conversion.\n *\n * @public\n * @memberof Annotation\n * @param {Array} color - The color array containing either 0\n * (transparent), 1 (grayscale), 3 (RGB) or\n * 4 (CMYK) elements\n */\n setColor: function Annotation_setColor(color) {\n var rgbColor = new Uint8Array(3); // Black in RGB color space (default)\n if (!isArray(color)) {\n this.color = rgbColor;\n return;\n }\n\n switch (color.length) {\n case 0: // Transparent, which we indicate with a null value\n this.color = null;\n break;\n\n case 1: // Convert grayscale to RGB\n ColorSpace.singletons.gray.getRgbItem(color, 0, rgbColor, 0);\n this.color = rgbColor;\n break;\n\n case 3: // Convert RGB percentages to RGB\n ColorSpace.singletons.rgb.getRgbItem(color, 0, rgbColor, 0);\n this.color = rgbColor;\n break;\n\n case 4: // Convert CMYK to RGB\n ColorSpace.singletons.cmyk.getRgbItem(color, 0, rgbColor, 0);\n this.color = rgbColor;\n break;\n\n default:\n this.color = rgbColor;\n break;\n }\n },\n\n /**\n * Set the border style (as AnnotationBorderStyle object).\n *\n * @public\n * @memberof Annotation\n * @param {Dict} borderStyle - The border style dictionary\n */\n setBorderStyle: function Annotation_setBorderStyle(borderStyle) {\n this.borderStyle = new AnnotationBorderStyle();\n if (!isDict(borderStyle)) {\n return;\n }\n if (borderStyle.has('BS')) {\n var dict = borderStyle.get('BS');\n var dictType = dict.get('Type');\n\n if (!dictType || isName(dictType, 'Border')) {\n this.borderStyle.setWidth(dict.get('W'));\n this.borderStyle.setStyle(dict.get('S'));\n this.borderStyle.setDashArray(dict.getArray('D'));\n }\n } else if (borderStyle.has('Border')) {\n var array = borderStyle.getArray('Border');\n if (isArray(array) && array.length >= 3) {\n this.borderStyle.setHorizontalCornerRadius(array[0]);\n this.borderStyle.setVerticalCornerRadius(array[1]);\n this.borderStyle.setWidth(array[2]);\n\n if (array.length === 4) { // Dash array available\n this.borderStyle.setDashArray(array[3]);\n }\n }\n } else {\n // There are no border entries in the dictionary. According to the\n // specification, we should draw a solid border of width 1 in that\n // case, but Adobe Reader did not implement that part of the\n // specification and instead draws no border at all, so we do the same.\n // See also https://github.com/mozilla/pdf.js/issues/6179.\n this.borderStyle.setWidth(0);\n }\n },\n\n /**\n * Set the (normal) appearance.\n *\n * @public\n * @memberof Annotation\n * @param {Dict} dict - The annotation's data dictionary\n */\n setAppearance: function Annotation_setAppearance(dict) {\n this.appearance = null;\n\n var appearanceStates = dict.get('AP');\n if (!isDict(appearanceStates)) {\n return;\n }\n\n // In case the normal appearance is a stream, then it is used directly.\n var normalAppearanceState = appearanceStates.get('N');\n if (isStream(normalAppearanceState)) {\n this.appearance = normalAppearanceState;\n return;\n }\n if (!isDict(normalAppearanceState)) {\n return;\n }\n\n // In case the normal appearance is a dictionary, the `AS` entry provides\n // the key of the stream in this dictionary.\n var as = dict.get('AS');\n if (!isName(as) || !normalAppearanceState.has(as.name)) {\n return;\n }\n this.appearance = normalAppearanceState.get(as.name);\n },\n\n /**\n * Prepare the annotation for working with a popup in the display layer.\n *\n * @private\n * @memberof Annotation\n * @param {Dict} dict - The annotation's data dictionary\n */\n _preparePopup: function Annotation_preparePopup(dict) {\n if (!dict.has('C')) {\n // Fall back to the default background color.\n this.data.color = null;\n }\n\n this.data.hasPopup = dict.has('Popup');\n this.data.title = stringToPDFString(dict.get('T') || '');\n this.data.contents = stringToPDFString(dict.get('Contents') || '');\n },\n\n loadResources: function Annotation_loadResources(keys) {\n return this.appearance.dict.getAsync('Resources').then((resources) => {\n if (!resources) {\n return;\n }\n let objectLoader = new ObjectLoader(resources, keys, resources.xref);\n\n return objectLoader.load().then(function() {\n return resources;\n });\n });\n },\n\n getOperatorList: function Annotation_getOperatorList(evaluator, task,\n renderForms) {\n if (!this.appearance) {\n return Promise.resolve(new OperatorList());\n }\n\n var data = this.data;\n var appearanceDict = this.appearance.dict;\n var resourcesPromise = this.loadResources([\n 'ExtGState',\n 'ColorSpace',\n 'Pattern',\n 'Shading',\n 'XObject',\n 'Font'\n // ProcSet\n // Properties\n ]);\n var bbox = appearanceDict.getArray('BBox') || [0, 0, 1, 1];\n var matrix = appearanceDict.getArray('Matrix') || [1, 0, 0, 1, 0, 0];\n var transform = getTransformMatrix(data.rect, bbox, matrix);\n\n return resourcesPromise.then((resources) => {\n var opList = new OperatorList();\n opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);\n return evaluator.getOperatorList({\n stream: this.appearance,\n task,\n resources,\n operatorList: opList,\n }).then(() => {\n opList.addOp(OPS.endAnnotation, []);\n this.appearance.reset();\n return opList;\n });\n });\n },\n };\n\n return Annotation;\n})();\n\n/**\n * Contains all data regarding an annotation's border style.\n *\n * @class\n */\nvar AnnotationBorderStyle = (function AnnotationBorderStyleClosure() {\n /**\n * @constructor\n * @private\n */\n function AnnotationBorderStyle() {\n this.width = 1;\n this.style = AnnotationBorderStyleType.SOLID;\n this.dashArray = [3];\n this.horizontalCornerRadius = 0;\n this.verticalCornerRadius = 0;\n }\n\n AnnotationBorderStyle.prototype = {\n /**\n * Set the width.\n *\n * @public\n * @memberof AnnotationBorderStyle\n * @param {integer} width - The width\n */\n setWidth: function AnnotationBorderStyle_setWidth(width) {\n if (width === (width | 0)) {\n this.width = width;\n }\n },\n\n /**\n * Set the style.\n *\n * @public\n * @memberof AnnotationBorderStyle\n * @param {Object} style - The style object\n * @see {@link shared/util.js}\n */\n setStyle: function AnnotationBorderStyle_setStyle(style) {\n if (!style) {\n return;\n }\n switch (style.name) {\n case 'S':\n this.style = AnnotationBorderStyleType.SOLID;\n break;\n\n case 'D':\n this.style = AnnotationBorderStyleType.DASHED;\n break;\n\n case 'B':\n this.style = AnnotationBorderStyleType.BEVELED;\n break;\n\n case 'I':\n this.style = AnnotationBorderStyleType.INSET;\n break;\n\n case 'U':\n this.style = AnnotationBorderStyleType.UNDERLINE;\n break;\n\n default:\n break;\n }\n },\n\n /**\n * Set the dash array.\n *\n * @public\n * @memberof AnnotationBorderStyle\n * @param {Array} dashArray - The dash array with at least one element\n */\n setDashArray: function AnnotationBorderStyle_setDashArray(dashArray) {\n // We validate the dash array, but we do not use it because CSS does not\n // allow us to change spacing of dashes. For more information, visit\n // http://www.w3.org/TR/css3-background/#the-border-style.\n if (isArray(dashArray) && dashArray.length > 0) {\n // According to the PDF specification: the elements in a dashArray\n // shall be numbers that are nonnegative and not all equal to zero.\n var isValid = true;\n var allZeros = true;\n for (var i = 0, len = dashArray.length; i < len; i++) {\n var element = dashArray[i];\n var validNumber = (+element >= 0);\n if (!validNumber) {\n isValid = false;\n break;\n } else if (element > 0) {\n allZeros = false;\n }\n }\n if (isValid && !allZeros) {\n this.dashArray = dashArray;\n } else {\n this.width = 0; // Adobe behavior when the array is invalid.\n }\n } else if (dashArray) {\n this.width = 0; // Adobe behavior when the array is invalid.\n }\n },\n\n /**\n * Set the horizontal corner radius (from a Border dictionary).\n *\n * @public\n * @memberof AnnotationBorderStyle\n * @param {integer} radius - The horizontal corner radius\n */\n setHorizontalCornerRadius:\n function AnnotationBorderStyle_setHorizontalCornerRadius(radius) {\n if (radius === (radius | 0)) {\n this.horizontalCornerRadius = radius;\n }\n },\n\n /**\n * Set the vertical corner radius (from a Border dictionary).\n *\n * @public\n * @memberof AnnotationBorderStyle\n * @param {integer} radius - The vertical corner radius\n */\n setVerticalCornerRadius:\n function AnnotationBorderStyle_setVerticalCornerRadius(radius) {\n if (radius === (radius | 0)) {\n this.verticalCornerRadius = radius;\n }\n },\n };\n\n return AnnotationBorderStyle;\n})();\n\nvar WidgetAnnotation = (function WidgetAnnotationClosure() {\n function WidgetAnnotation(params) {\n Annotation.call(this, params);\n\n var dict = params.dict;\n var data = this.data;\n\n data.annotationType = AnnotationType.WIDGET;\n data.fieldName = this._constructFieldName(dict);\n data.fieldValue = Util.getInheritableProperty(dict, 'V',\n /* getArray = */ true);\n data.alternativeText = stringToPDFString(dict.get('TU') || '');\n data.defaultAppearance = Util.getInheritableProperty(dict, 'DA') || '';\n var fieldType = Util.getInheritableProperty(dict, 'FT');\n data.fieldType = isName(fieldType) ? fieldType.name : null;\n this.fieldResources = Util.getInheritableProperty(dict, 'DR') || Dict.empty;\n\n data.fieldFlags = Util.getInheritableProperty(dict, 'Ff');\n if (!isInt(data.fieldFlags) || data.fieldFlags < 0) {\n data.fieldFlags = 0;\n }\n\n data.readOnly = this.hasFieldFlag(AnnotationFieldFlag.READONLY);\n\n // Hide signatures because we cannot validate them.\n if (data.fieldType === 'Sig') {\n this.setFlags(AnnotationFlag.HIDDEN);\n }\n }\n\n Util.inherit(WidgetAnnotation, Annotation, {\n /**\n * Construct the (fully qualified) field name from the (partial) field\n * names of the field and its ancestors.\n *\n * @private\n * @memberof WidgetAnnotation\n * @param {Dict} dict - Complete widget annotation dictionary\n * @return {string}\n */\n _constructFieldName: function WidgetAnnotation_constructFieldName(dict) {\n // Both the `Parent` and `T` fields are optional. While at least one of\n // them should be provided, bad PDF generators may fail to do so.\n if (!dict.has('T') && !dict.has('Parent')) {\n warn('Unknown field name, falling back to empty field name.');\n return '';\n }\n\n // If no parent exists, the partial and fully qualified names are equal.\n if (!dict.has('Parent')) {\n return stringToPDFString(dict.get('T'));\n }\n\n // Form the fully qualified field name by appending the partial name to\n // the parent's fully qualified name, separated by a period.\n var fieldName = [];\n if (dict.has('T')) {\n fieldName.unshift(stringToPDFString(dict.get('T')));\n }\n\n var loopDict = dict;\n while (loopDict.has('Parent')) {\n loopDict = loopDict.get('Parent');\n if (!isDict(loopDict)) {\n // Even though it is not allowed according to the PDF specification,\n // bad PDF generators may provide a `Parent` entry that is not a\n // dictionary, but `null` for example (issue 8143).\n break;\n }\n\n if (loopDict.has('T')) {\n fieldName.unshift(stringToPDFString(loopDict.get('T')));\n }\n }\n return fieldName.join('.');\n },\n\n /**\n * Check if a provided field flag is set.\n *\n * @public\n * @memberof WidgetAnnotation\n * @param {number} flag - Hexadecimal representation for an annotation\n * field characteristic\n * @return {boolean}\n * @see {@link shared/util.js}\n */\n hasFieldFlag: function WidgetAnnotation_hasFieldFlag(flag) {\n return !!(this.data.fieldFlags & flag);\n },\n });\n\n return WidgetAnnotation;\n})();\n\nvar TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {\n function TextWidgetAnnotation(params) {\n WidgetAnnotation.call(this, params);\n\n // The field value is always a string.\n this.data.fieldValue = stringToPDFString(this.data.fieldValue || '');\n\n // Determine the alignment of text in the field.\n var alignment = Util.getInheritableProperty(params.dict, 'Q');\n if (!isInt(alignment) || alignment < 0 || alignment > 2) {\n alignment = null;\n }\n this.data.textAlignment = alignment;\n\n // Determine the maximum length of text in the field.\n var maximumLength = Util.getInheritableProperty(params.dict, 'MaxLen');\n if (!isInt(maximumLength) || maximumLength < 0) {\n maximumLength = null;\n }\n this.data.maxLen = maximumLength;\n\n // Process field flags for the display layer.\n this.data.multiLine = this.hasFieldFlag(AnnotationFieldFlag.MULTILINE);\n this.data.comb = this.hasFieldFlag(AnnotationFieldFlag.COMB) &&\n !this.hasFieldFlag(AnnotationFieldFlag.MULTILINE) &&\n !this.hasFieldFlag(AnnotationFieldFlag.PASSWORD) &&\n !this.hasFieldFlag(AnnotationFieldFlag.FILESELECT) &&\n this.data.maxLen !== null;\n }\n\n Util.inherit(TextWidgetAnnotation, WidgetAnnotation, {\n getOperatorList:\n function TextWidgetAnnotation_getOperatorList(evaluator, task,\n renderForms) {\n var operatorList = new OperatorList();\n\n // Do not render form elements on the canvas when interactive forms are\n // enabled. The display layer is responsible for rendering them instead.\n if (renderForms) {\n return Promise.resolve(operatorList);\n }\n\n if (this.appearance) {\n return Annotation.prototype.getOperatorList.call(this, evaluator, task,\n renderForms);\n }\n\n // Even if there is an appearance stream, ignore it. This is the\n // behaviour used by Adobe Reader.\n if (!this.data.defaultAppearance) {\n return Promise.resolve(operatorList);\n }\n\n var stream = new Stream(stringToBytes(this.data.defaultAppearance));\n return evaluator.getOperatorList({\n stream,\n task,\n resources: this.fieldResources,\n operatorList,\n }).then(function () {\n return operatorList;\n });\n },\n });\n\n return TextWidgetAnnotation;\n})();\n\nvar ButtonWidgetAnnotation = (function ButtonWidgetAnnotationClosure() {\n function ButtonWidgetAnnotation(params) {\n WidgetAnnotation.call(this, params);\n\n this.data.checkBox = !this.hasFieldFlag(AnnotationFieldFlag.RADIO) &&\n !this.hasFieldFlag(AnnotationFieldFlag.PUSHBUTTON);\n if (this.data.checkBox) {\n if (!isName(this.data.fieldValue)) {\n return;\n }\n this.data.fieldValue = this.data.fieldValue.name;\n }\n\n this.data.radioButton = this.hasFieldFlag(AnnotationFieldFlag.RADIO) &&\n !this.hasFieldFlag(AnnotationFieldFlag.PUSHBUTTON);\n if (this.data.radioButton) {\n this.data.fieldValue = this.data.buttonValue = null;\n\n // The parent field's `V` entry holds a `Name` object with the appearance\n // state of whichever child field is currently in the \"on\" state.\n var fieldParent = params.dict.get('Parent');\n if (isDict(fieldParent) && fieldParent.has('V')) {\n var fieldParentValue = fieldParent.get('V');\n if (isName(fieldParentValue)) {\n this.data.fieldValue = fieldParentValue.name;\n }\n }\n\n // The button's value corresponds to its appearance state.\n var appearanceStates = params.dict.get('AP');\n if (!isDict(appearanceStates)) {\n return;\n }\n var normalAppearanceState = appearanceStates.get('N');\n if (!isDict(normalAppearanceState)) {\n return;\n }\n var keys = normalAppearanceState.getKeys();\n for (var i = 0, ii = keys.length; i < ii; i++) {\n if (keys[i] !== 'Off') {\n this.data.buttonValue = keys[i];\n break;\n }\n }\n }\n }\n\n Util.inherit(ButtonWidgetAnnotation, WidgetAnnotation, {\n getOperatorList:\n function ButtonWidgetAnnotation_getOperatorList(evaluator, task,\n renderForms) {\n var operatorList = new OperatorList();\n\n // Do not render form elements on the canvas when interactive forms are\n // enabled. The display layer is responsible for rendering them instead.\n if (renderForms) {\n return Promise.resolve(operatorList);\n }\n\n if (this.appearance) {\n return Annotation.prototype.getOperatorList.call(this, evaluator, task,\n renderForms);\n }\n return Promise.resolve(operatorList);\n },\n });\n\n return ButtonWidgetAnnotation;\n})();\n\nvar ChoiceWidgetAnnotation = (function ChoiceWidgetAnnotationClosure() {\n function ChoiceWidgetAnnotation(params) {\n WidgetAnnotation.call(this, params);\n\n // Determine the options. The options array may consist of strings or\n // arrays. If the array consists of arrays, then the first element of\n // each array is the export value and the second element of each array is\n // the display value. If the array consists of strings, then these\n // represent both the export and display value. In this case, we convert\n // it to an array of arrays as well for convenience in the display layer.\n // Note that the specification does not state that the `Opt` field is\n // inheritable, but in practice PDF generators do make annotations\n // inherit the options from a parent annotation (issue 8094).\n this.data.options = [];\n\n var options = Util.getInheritableProperty(params.dict, 'Opt');\n if (isArray(options)) {\n var xref = params.xref;\n for (var i = 0, ii = options.length; i < ii; i++) {\n var option = xref.fetchIfRef(options[i]);\n var isOptionArray = isArray(option);\n\n this.data.options[i] = {\n exportValue: isOptionArray ? xref.fetchIfRef(option[0]) : option,\n displayValue: isOptionArray ? xref.fetchIfRef(option[1]) : option,\n };\n }\n }\n\n // Determine the field value. In this case, it may be a string or an\n // array of strings. For convenience in the display layer, convert the\n // string to an array of one string as well.\n if (!isArray(this.data.fieldValue)) {\n this.data.fieldValue = [this.data.fieldValue];\n }\n\n // Process field flags for the display layer.\n this.data.combo = this.hasFieldFlag(AnnotationFieldFlag.COMBO);\n this.data.multiSelect = this.hasFieldFlag(AnnotationFieldFlag.MULTISELECT);\n }\n\n Util.inherit(ChoiceWidgetAnnotation, WidgetAnnotation, {\n getOperatorList:\n function ChoiceWidgetAnnotation_getOperatorList(evaluator, task,\n renderForms) {\n var operatorList = new OperatorList();\n\n // Do not render form elements on the canvas when interactive forms are\n // enabled. The display layer is responsible for rendering them instead.\n if (renderForms) {\n return Promise.resolve(operatorList);\n }\n\n return Annotation.prototype.getOperatorList.call(this, evaluator, task,\n renderForms);\n },\n });\n\n return ChoiceWidgetAnnotation;\n})();\n\nvar TextAnnotation = (function TextAnnotationClosure() {\n var DEFAULT_ICON_SIZE = 22; // px\n\n function TextAnnotation(parameters) {\n Annotation.call(this, parameters);\n\n this.data.annotationType = AnnotationType.TEXT;\n\n if (this.data.hasAppearance) {\n this.data.name = 'NoIcon';\n } else {\n this.data.rect[1] = this.data.rect[3] - DEFAULT_ICON_SIZE;\n this.data.rect[2] = this.data.rect[0] + DEFAULT_ICON_SIZE;\n this.data.name = parameters.dict.has('Name') ?\n parameters.dict.get('Name').name : 'Note';\n }\n this._preparePopup(parameters.dict);\n }\n\n Util.inherit(TextAnnotation, Annotation, {});\n\n return TextAnnotation;\n})();\n\nvar LinkAnnotation = (function LinkAnnotationClosure() {\n function LinkAnnotation(params) {\n Annotation.call(this, params);\n\n var data = this.data;\n data.annotationType = AnnotationType.LINK;\n\n Catalog.parseDestDictionary({\n destDict: params.dict,\n resultObj: data,\n docBaseUrl: params.pdfManager.docBaseUrl,\n });\n }\n\n Util.inherit(LinkAnnotation, Annotation, {});\n\n return LinkAnnotation;\n})();\n\nvar PopupAnnotation = (function PopupAnnotationClosure() {\n function PopupAnnotation(parameters) {\n Annotation.call(this, parameters);\n\n this.data.annotationType = AnnotationType.POPUP;\n\n var dict = parameters.dict;\n var parentItem = dict.get('Parent');\n if (!parentItem) {\n warn('Popup annotation has a missing or invalid parent annotation.');\n return;\n }\n\n var parentSubtype = parentItem.get('Subtype');\n this.data.parentType = isName(parentSubtype) ? parentSubtype.name : null;\n this.data.parentId = dict.getRaw('Parent').toString();\n this.data.title = stringToPDFString(parentItem.get('T') || '');\n this.data.contents = stringToPDFString(parentItem.get('Contents') || '');\n\n if (!parentItem.has('C')) {\n // Fall back to the default background color.\n this.data.color = null;\n } else {\n this.setColor(parentItem.getArray('C'));\n this.data.color = this.color;\n }\n\n // If the Popup annotation is not viewable, but the parent annotation is,\n // that is most likely a bug. Fallback to inherit the flags from the parent\n // annotation (this is consistent with the behaviour in Adobe Reader).\n if (!this.viewable) {\n var parentFlags = parentItem.get('F');\n if (this._isViewable(parentFlags)) {\n this.setFlags(parentFlags);\n }\n }\n }\n\n Util.inherit(PopupAnnotation, Annotation, {});\n\n return PopupAnnotation;\n})();\n\nvar LineAnnotation = (function LineAnnotationClosure() {\n function LineAnnotation(parameters) {\n Annotation.call(this, parameters);\n\n this.data.annotationType = AnnotationType.LINE;\n\n var dict = parameters.dict;\n this.data.lineCoordinates = Util.normalizeRect(dict.getArray('L'));\n this._preparePopup(dict);\n }\n\n Util.inherit(LineAnnotation, Annotation, {});\n\n return LineAnnotation;\n})();\n\nvar HighlightAnnotation = (function HighlightAnnotationClosure() {\n function HighlightAnnotation(parameters) {\n Annotation.call(this, parameters);\n\n this.data.annotationType = AnnotationType.HIGHLIGHT;\n this._preparePopup(parameters.dict);\n }\n\n Util.inherit(HighlightAnnotation, Annotation, {});\n\n return HighlightAnnotation;\n})();\n\nvar UnderlineAnnotation = (function UnderlineAnnotationClosure() {\n function UnderlineAnnotation(parameters) {\n Annotation.call(this, parameters);\n\n this.data.annotationType = AnnotationType.UNDERLINE;\n this._preparePopup(parameters.dict);\n }\n\n Util.inherit(UnderlineAnnotation, Annotation, {});\n\n return UnderlineAnnotation;\n})();\n\nvar SquigglyAnnotation = (function SquigglyAnnotationClosure() {\n function SquigglyAnnotation(parameters) {\n Annotation.call(this, parameters);\n\n this.data.annotationType = AnnotationType.SQUIGGLY;\n this._preparePopup(parameters.dict);\n }\n\n Util.inherit(SquigglyAnnotation, Annotation, {});\n\n return SquigglyAnnotation;\n})();\n\nvar StrikeOutAnnotation = (function StrikeOutAnnotationClosure() {\n function StrikeOutAnnotation(parameters) {\n Annotation.call(this, parameters);\n\n this.data.annotationType = AnnotationType.STRIKEOUT;\n this._preparePopup(parameters.dict);\n }\n\n Util.inherit(StrikeOutAnnotation, Annotation, {});\n\n return StrikeOutAnnotation;\n})();\n\nvar FileAttachmentAnnotation = (function FileAttachmentAnnotationClosure() {\n function FileAttachmentAnnotation(parameters) {\n Annotation.call(this, parameters);\n\n var file = new FileSpec(parameters.dict.get('FS'), parameters.xref);\n\n this.data.annotationType = AnnotationType.FILEATTACHMENT;\n this.data.file = file.serializable;\n this._preparePopup(parameters.dict);\n }\n\n Util.inherit(FileAttachmentAnnotation, Annotation, {});\n\n return FileAttachmentAnnotation;\n})();\n\nexport {\n Annotation,\n AnnotationBorderStyle,\n AnnotationFactory,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/annotation.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { warn } from '../shared/util';\n\n// Character types for symbols from 0000 to 00FF.\n// Source: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt\nvar baseTypes = [\n 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'S', 'B', 'S',\n 'WS', 'B', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',\n 'BN', 'BN', 'BN', 'BN', 'B', 'B', 'B', 'S', 'WS', 'ON', 'ON', 'ET',\n 'ET', 'ET', 'ON', 'ON', 'ON', 'ON', 'ON', 'ES', 'CS', 'ES', 'CS', 'CS',\n 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'CS', 'ON',\n 'ON', 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',\n 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',\n 'L', 'L', 'L', 'L', 'ON', 'ON', 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L',\n 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',\n 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'ON', 'ON', 'ON', 'ON',\n 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'B', 'BN', 'BN', 'BN', 'BN', 'BN',\n 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',\n 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'CS', 'ON', 'ET',\n 'ET', 'ET', 'ET', 'ON', 'ON', 'ON', 'ON', 'L', 'ON', 'ON', 'BN', 'ON',\n 'ON', 'ET', 'ET', 'EN', 'EN', 'ON', 'L', 'ON', 'ON', 'ON', 'EN', 'L',\n 'ON', 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',\n 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',\n 'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',\n 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',\n 'L', 'L', 'L', 'L', 'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'\n];\n\n// Character types for symbols from 0600 to 06FF.\n// Source: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt\n// Note that 061D does not exist in the Unicode standard (see\n// http://unicode.org/charts/PDF/U0600.pdf), so we replace it with an\n// empty string and issue a warning if we encounter this character. The\n// empty string is required to properly index the items after it.\nvar arabicTypes = [\n 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'ON', 'ON', 'AL', 'ET', 'ET', 'AL',\n 'CS', 'AL', 'ON', 'ON', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',\n 'NSM', 'NSM', 'NSM', 'NSM', 'AL', 'AL', '', 'AL', 'AL', 'AL', 'AL', 'AL',\n 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',\n 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',\n 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',\n 'AL', 'AL', 'AL', 'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',\n 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',\n 'NSM', 'NSM', 'NSM', 'NSM', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN',\n 'AN', 'AN', 'AN', 'ET', 'AN', 'AN', 'AL', 'AL', 'AL', 'NSM', 'AL', 'AL',\n 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',\n 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',\n 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',\n 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',\n 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',\n 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',\n 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',\n 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',\n 'AL', 'AL', 'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AN',\n 'ON', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL', 'AL', 'NSM', 'NSM',\n 'ON', 'NSM', 'NSM', 'NSM', 'NSM', 'AL', 'AL', 'EN', 'EN', 'EN', 'EN',\n 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL'\n];\n\nfunction isOdd(i) {\n return (i & 1) !== 0;\n}\n\nfunction isEven(i) {\n return (i & 1) === 0;\n}\n\nfunction findUnequal(arr, start, value) {\n for (var j = start, jj = arr.length; j < jj; ++j) {\n if (arr[j] !== value) {\n return j;\n }\n }\n return j;\n}\n\nfunction setValues(arr, start, end, value) {\n for (var j = start; j < end; ++j) {\n arr[j] = value;\n }\n}\n\nfunction reverseValues(arr, start, end) {\n for (var i = start, j = end - 1; i < j; ++i, --j) {\n var temp = arr[i];\n arr[i] = arr[j];\n arr[j] = temp;\n }\n}\n\nfunction createBidiText(str, isLTR, vertical) {\n return {\n str,\n dir: (vertical ? 'ttb' : (isLTR ? 'ltr' : 'rtl')),\n };\n}\n\n// These are used in bidi(), which is called frequently. We re-use them on\n// each call to avoid unnecessary allocations.\nvar chars = [];\nvar types = [];\n\nfunction bidi(str, startLevel, vertical) {\n var isLTR = true;\n var strLength = str.length;\n if (strLength === 0 || vertical) {\n return createBidiText(str, isLTR, vertical);\n }\n\n // Get types and fill arrays\n chars.length = strLength;\n types.length = strLength;\n var numBidi = 0;\n\n var i, ii;\n for (i = 0; i < strLength; ++i) {\n chars[i] = str.charAt(i);\n\n var charCode = str.charCodeAt(i);\n var charType = 'L';\n if (charCode <= 0x00ff) {\n charType = baseTypes[charCode];\n } else if (0x0590 <= charCode && charCode <= 0x05f4) {\n charType = 'R';\n } else if (0x0600 <= charCode && charCode <= 0x06ff) {\n charType = arabicTypes[charCode & 0xff];\n if (!charType) {\n warn('Bidi: invalid Unicode character ' + charCode.toString(16));\n }\n } else if (0x0700 <= charCode && charCode <= 0x08AC) {\n charType = 'AL';\n }\n if (charType === 'R' || charType === 'AL' || charType === 'AN') {\n numBidi++;\n }\n types[i] = charType;\n }\n\n // Detect the bidi method\n // - If there are no rtl characters then no bidi needed\n // - If less than 30% chars are rtl then string is primarily ltr\n // - If more than 30% chars are rtl then string is primarily rtl\n if (numBidi === 0) {\n isLTR = true;\n return createBidiText(str, isLTR);\n }\n\n if (startLevel === -1) {\n if ((numBidi / strLength) < 0.3) {\n isLTR = true;\n startLevel = 0;\n } else {\n isLTR = false;\n startLevel = 1;\n }\n }\n\n var levels = [];\n for (i = 0; i < strLength; ++i) {\n levels[i] = startLevel;\n }\n\n /*\n X1-X10: skip most of this, since we are NOT doing the embeddings.\n */\n var e = (isOdd(startLevel) ? 'R' : 'L');\n var sor = e;\n var eor = sor;\n\n /*\n W1. Examine each non-spacing mark (NSM) in the level run, and change the\n type of the NSM to the type of the previous character. If the NSM is at the\n start of the level run, it will get the type of sor.\n */\n var lastType = sor;\n for (i = 0; i < strLength; ++i) {\n if (types[i] === 'NSM') {\n types[i] = lastType;\n } else {\n lastType = types[i];\n }\n }\n\n /*\n W2. Search backwards from each instance of a European number until the\n first strong type (R, L, AL, or sor) is found. If an AL is found, change\n the type of the European number to Arabic number.\n */\n lastType = sor;\n var t;\n for (i = 0; i < strLength; ++i) {\n t = types[i];\n if (t === 'EN') {\n types[i] = (lastType === 'AL') ? 'AN' : 'EN';\n } else if (t === 'R' || t === 'L' || t === 'AL') {\n lastType = t;\n }\n }\n\n /*\n W3. Change all ALs to R.\n */\n for (i = 0; i < strLength; ++i) {\n t = types[i];\n if (t === 'AL') {\n types[i] = 'R';\n }\n }\n\n /*\n W4. A single European separator between two European numbers changes to a\n European number. A single common separator between two numbers of the same\n type changes to that type:\n */\n for (i = 1; i < strLength - 1; ++i) {\n if (types[i] === 'ES' && types[i - 1] === 'EN' && types[i + 1] === 'EN') {\n types[i] = 'EN';\n }\n if (types[i] === 'CS' &&\n (types[i - 1] === 'EN' || types[i - 1] === 'AN') &&\n types[i + 1] === types[i - 1]) {\n types[i] = types[i - 1];\n }\n }\n\n /*\n W5. A sequence of European terminators adjacent to European numbers changes\n to all European numbers:\n */\n for (i = 0; i < strLength; ++i) {\n if (types[i] === 'EN') {\n // do before\n var j;\n for (j = i - 1; j >= 0; --j) {\n if (types[j] !== 'ET') {\n break;\n }\n types[j] = 'EN';\n }\n // do after\n for (j = i + 1; j < strLength; ++j) {\n if (types[j] !== 'ET') {\n break;\n }\n types[j] = 'EN';\n }\n }\n }\n\n /*\n W6. Otherwise, separators and terminators change to Other Neutral:\n */\n for (i = 0; i < strLength; ++i) {\n t = types[i];\n if (t === 'WS' || t === 'ES' || t === 'ET' || t === 'CS') {\n types[i] = 'ON';\n }\n }\n\n /*\n W7. Search backwards from each instance of a European number until the\n first strong type (R, L, or sor) is found. If an L is found, then change\n the type of the European number to L.\n */\n lastType = sor;\n for (i = 0; i < strLength; ++i) {\n t = types[i];\n if (t === 'EN') {\n types[i] = ((lastType === 'L') ? 'L' : 'EN');\n } else if (t === 'R' || t === 'L') {\n lastType = t;\n }\n }\n\n /*\n N1. A sequence of neutrals takes the direction of the surrounding strong\n text if the text on both sides has the same direction. European and Arabic\n numbers are treated as though they were R. Start-of-level-run (sor) and\n end-of-level-run (eor) are used at level run boundaries.\n */\n for (i = 0; i < strLength; ++i) {\n if (types[i] === 'ON') {\n var end = findUnequal(types, i + 1, 'ON');\n var before = sor;\n if (i > 0) {\n before = types[i - 1];\n }\n\n var after = eor;\n if (end + 1 < strLength) {\n after = types[end + 1];\n }\n if (before !== 'L') {\n before = 'R';\n }\n if (after !== 'L') {\n after = 'R';\n }\n if (before === after) {\n setValues(types, i, end, before);\n }\n i = end - 1; // reset to end (-1 so next iteration is ok)\n }\n }\n\n /*\n N2. Any remaining neutrals take the embedding direction.\n */\n for (i = 0; i < strLength; ++i) {\n if (types[i] === 'ON') {\n types[i] = e;\n }\n }\n\n /*\n I1. For all characters with an even (left-to-right) embedding direction,\n those of type R go up one level and those of type AN or EN go up two\n levels.\n I2. For all characters with an odd (right-to-left) embedding direction,\n those of type L, EN or AN go up one level.\n */\n for (i = 0; i < strLength; ++i) {\n t = types[i];\n if (isEven(levels[i])) {\n if (t === 'R') {\n levels[i] += 1;\n } else if (t === 'AN' || t === 'EN') {\n levels[i] += 2;\n }\n } else { // isOdd\n if (t === 'L' || t === 'AN' || t === 'EN') {\n levels[i] += 1;\n }\n }\n }\n\n /*\n L1. On each line, reset the embedding level of the following characters to\n the paragraph embedding level:\n\n segment separators,\n paragraph separators,\n any sequence of whitespace characters preceding a segment separator or\n paragraph separator, and any sequence of white space characters at the end\n of the line.\n */\n\n // don't bother as text is only single line\n\n /*\n L2. From the highest level found in the text to the lowest odd level on\n each line, reverse any contiguous sequence of characters that are at that\n level or higher.\n */\n\n // find highest level & lowest odd level\n var highestLevel = -1;\n var lowestOddLevel = 99;\n var level;\n for (i = 0, ii = levels.length; i < ii; ++i) {\n level = levels[i];\n if (highestLevel < level) {\n highestLevel = level;\n }\n if (lowestOddLevel > level && isOdd(level)) {\n lowestOddLevel = level;\n }\n }\n\n // now reverse between those limits\n for (level = highestLevel; level >= lowestOddLevel; --level) {\n // find segments to reverse\n var start = -1;\n for (i = 0, ii = levels.length; i < ii; ++i) {\n if (levels[i] < level) {\n if (start >= 0) {\n reverseValues(chars, start, i);\n start = -1;\n }\n } else if (start < 0) {\n start = i;\n }\n }\n if (start >= 0) {\n reverseValues(chars, start, levels.length);\n }\n }\n\n /*\n L3. Combining marks applied to a right-to-left base character will at this\n point precede their base character. If the rendering engine expects them to\n follow the base characters in the final display process, then the ordering\n of the marks and the base character must be reversed.\n */\n\n // don't bother for now\n\n /*\n L4. A character that possesses the mirrored property as specified by\n Section 4.7, Mirrored, must be depicted by a mirrored glyph if the resolved\n directionality of that character is R.\n */\n\n // don't mirror as characters are already mirrored in the pdf\n\n // Finally, return string\n for (i = 0, ii = chars.length; i < ii; ++i) {\n var ch = chars[i];\n if (ch === '<' || ch === '>') {\n chars[i] = '';\n }\n }\n return createBidiText(chars.join(''), isLTR);\n}\n\nexport {\n bidi,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/bidi.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nvar ISOAdobeCharset = [\n '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar',\n 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright',\n 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero',\n 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',\n 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question',\n 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',\n 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',\n 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',\n 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',\n 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',\n 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent',\n 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',\n 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',\n 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl',\n 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase',\n 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis',\n 'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', 'tilde',\n 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla',\n 'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine',\n 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash',\n 'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu',\n 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter',\n 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior',\n 'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright',\n 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde',\n 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute',\n 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex',\n 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex',\n 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute',\n 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla',\n 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex',\n 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis',\n 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis',\n 'ugrave', 'yacute', 'ydieresis', 'zcaron'\n];\n\nvar ExpertCharset = [\n '.notdef', 'space', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle',\n 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior',\n 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma',\n 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle',\n 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle',\n 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle',\n 'colon', 'semicolon', 'commasuperior', 'threequartersemdash',\n 'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior',\n 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',\n 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',\n 'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',\n 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',\n 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall',\n 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall',\n 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall',\n 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary',\n 'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle',\n 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall',\n 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall',\n 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall',\n 'Cedillasmall', 'onequarter', 'onehalf', 'threequarters',\n 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',\n 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',\n 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',\n 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',\n 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',\n 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',\n 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',\n 'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall',\n 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall',\n 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall',\n 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',\n 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall',\n 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall',\n 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',\n 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall',\n 'Ydieresissmall'\n];\n\nvar ExpertSubsetCharset = [\n '.notdef', 'space', 'dollaroldstyle', 'dollarsuperior',\n 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',\n 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction',\n 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle',\n 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle',\n 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior',\n 'threequartersemdash', 'periodsuperior', 'asuperior', 'bsuperior',\n 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',\n 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',\n 'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',\n 'parenrightinferior', 'hyphensuperior', 'colonmonetary', 'onefitted',\n 'rupiah', 'centoldstyle', 'figuredash', 'hypheninferior', 'onequarter',\n 'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths',\n 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',\n 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',\n 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',\n 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',\n 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',\n 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',\n 'periodinferior', 'commainferior'\n];\n\nexport {\n ISOAdobeCharset,\n ExpertCharset,\n ExpertSubsetCharset,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/charsets.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n CMapCompressionType, FormatError, isInt, isString, MissingDataException, Util,\n warn\n} from '../shared/util';\nimport { isCmd, isEOF, isName, isStream } from './primitives';\nimport { Lexer } from './parser';\nimport { Stream } from './stream';\n\nvar BUILT_IN_CMAPS = [\n// << Start unicode maps.\n'Adobe-GB1-UCS2',\n'Adobe-CNS1-UCS2',\n'Adobe-Japan1-UCS2',\n'Adobe-Korea1-UCS2',\n// >> End unicode maps.\n'78-EUC-H',\n'78-EUC-V',\n'78-H',\n'78-RKSJ-H',\n'78-RKSJ-V',\n'78-V',\n'78ms-RKSJ-H',\n'78ms-RKSJ-V',\n'83pv-RKSJ-H',\n'90ms-RKSJ-H',\n'90ms-RKSJ-V',\n'90msp-RKSJ-H',\n'90msp-RKSJ-V',\n'90pv-RKSJ-H',\n'90pv-RKSJ-V',\n'Add-H',\n'Add-RKSJ-H',\n'Add-RKSJ-V',\n'Add-V',\n'Adobe-CNS1-0',\n'Adobe-CNS1-1',\n'Adobe-CNS1-2',\n'Adobe-CNS1-3',\n'Adobe-CNS1-4',\n'Adobe-CNS1-5',\n'Adobe-CNS1-6',\n'Adobe-GB1-0',\n'Adobe-GB1-1',\n'Adobe-GB1-2',\n'Adobe-GB1-3',\n'Adobe-GB1-4',\n'Adobe-GB1-5',\n'Adobe-Japan1-0',\n'Adobe-Japan1-1',\n'Adobe-Japan1-2',\n'Adobe-Japan1-3',\n'Adobe-Japan1-4',\n'Adobe-Japan1-5',\n'Adobe-Japan1-6',\n'Adobe-Korea1-0',\n'Adobe-Korea1-1',\n'Adobe-Korea1-2',\n'B5-H',\n'B5-V',\n'B5pc-H',\n'B5pc-V',\n'CNS-EUC-H',\n'CNS-EUC-V',\n'CNS1-H',\n'CNS1-V',\n'CNS2-H',\n'CNS2-V',\n'ETHK-B5-H',\n'ETHK-B5-V',\n'ETen-B5-H',\n'ETen-B5-V',\n'ETenms-B5-H',\n'ETenms-B5-V',\n'EUC-H',\n'EUC-V',\n'Ext-H',\n'Ext-RKSJ-H',\n'Ext-RKSJ-V',\n'Ext-V',\n'GB-EUC-H',\n'GB-EUC-V',\n'GB-H',\n'GB-V',\n'GBK-EUC-H',\n'GBK-EUC-V',\n'GBK2K-H',\n'GBK2K-V',\n'GBKp-EUC-H',\n'GBKp-EUC-V',\n'GBT-EUC-H',\n'GBT-EUC-V',\n'GBT-H',\n'GBT-V',\n'GBTpc-EUC-H',\n'GBTpc-EUC-V',\n'GBpc-EUC-H',\n'GBpc-EUC-V',\n'H',\n'HKdla-B5-H',\n'HKdla-B5-V',\n'HKdlb-B5-H',\n'HKdlb-B5-V',\n'HKgccs-B5-H',\n'HKgccs-B5-V',\n'HKm314-B5-H',\n'HKm314-B5-V',\n'HKm471-B5-H',\n'HKm471-B5-V',\n'HKscs-B5-H',\n'HKscs-B5-V',\n'Hankaku',\n'Hiragana',\n'KSC-EUC-H',\n'KSC-EUC-V',\n'KSC-H',\n'KSC-Johab-H',\n'KSC-Johab-V',\n'KSC-V',\n'KSCms-UHC-H',\n'KSCms-UHC-HW-H',\n'KSCms-UHC-HW-V',\n'KSCms-UHC-V',\n'KSCpc-EUC-H',\n'KSCpc-EUC-V',\n'Katakana',\n'NWP-H',\n'NWP-V',\n'RKSJ-H',\n'RKSJ-V',\n'Roman',\n'UniCNS-UCS2-H',\n'UniCNS-UCS2-V',\n'UniCNS-UTF16-H',\n'UniCNS-UTF16-V',\n'UniCNS-UTF32-H',\n'UniCNS-UTF32-V',\n'UniCNS-UTF8-H',\n'UniCNS-UTF8-V',\n'UniGB-UCS2-H',\n'UniGB-UCS2-V',\n'UniGB-UTF16-H',\n'UniGB-UTF16-V',\n'UniGB-UTF32-H',\n'UniGB-UTF32-V',\n'UniGB-UTF8-H',\n'UniGB-UTF8-V',\n'UniJIS-UCS2-H',\n'UniJIS-UCS2-HW-H',\n'UniJIS-UCS2-HW-V',\n'UniJIS-UCS2-V',\n'UniJIS-UTF16-H',\n'UniJIS-UTF16-V',\n'UniJIS-UTF32-H',\n'UniJIS-UTF32-V',\n'UniJIS-UTF8-H',\n'UniJIS-UTF8-V',\n'UniJIS2004-UTF16-H',\n'UniJIS2004-UTF16-V',\n'UniJIS2004-UTF32-H',\n'UniJIS2004-UTF32-V',\n'UniJIS2004-UTF8-H',\n'UniJIS2004-UTF8-V',\n'UniJISPro-UCS2-HW-V',\n'UniJISPro-UCS2-V',\n'UniJISPro-UTF8-V',\n'UniJISX0213-UTF32-H',\n'UniJISX0213-UTF32-V',\n'UniJISX02132004-UTF32-H',\n'UniJISX02132004-UTF32-V',\n'UniKS-UCS2-H',\n'UniKS-UCS2-V',\n'UniKS-UTF16-H',\n'UniKS-UTF16-V',\n'UniKS-UTF32-H',\n'UniKS-UTF32-V',\n'UniKS-UTF8-H',\n'UniKS-UTF8-V',\n'V',\n'WP-Symbol'];\n\n// CMap, not to be confused with TrueType's cmap.\nvar CMap = (function CMapClosure() {\n function CMap(builtInCMap) {\n // Codespace ranges are stored as follows:\n // [[1BytePairs], [2BytePairs], [3BytePairs], [4BytePairs]]\n // where nBytePairs are ranges e.g. [low1, high1, low2, high2, ...]\n this.codespaceRanges = [[], [], [], []];\n this.numCodespaceRanges = 0;\n // Map entries have one of two forms.\n // - cid chars are 16-bit unsigned integers, stored as integers.\n // - bf chars are variable-length byte sequences, stored as strings, with\n // one byte per character.\n this._map = [];\n this.name = '';\n this.vertical = false;\n this.useCMap = null;\n this.builtInCMap = builtInCMap;\n }\n CMap.prototype = {\n addCodespaceRange(n, low, high) {\n this.codespaceRanges[n - 1].push(low, high);\n this.numCodespaceRanges++;\n },\n\n mapCidRange(low, high, dstLow) {\n while (low <= high) {\n this._map[low++] = dstLow++;\n }\n },\n\n mapBfRange(low, high, dstLow) {\n var lastByte = dstLow.length - 1;\n while (low <= high) {\n this._map[low++] = dstLow;\n // Only the last byte has to be incremented.\n dstLow = dstLow.substr(0, lastByte) +\n String.fromCharCode(dstLow.charCodeAt(lastByte) + 1);\n }\n },\n\n mapBfRangeToArray(low, high, array) {\n var i = 0, ii = array.length;\n while (low <= high && i < ii) {\n this._map[low] = array[i++];\n ++low;\n }\n },\n\n // This is used for both bf and cid chars.\n mapOne(src, dst) {\n this._map[src] = dst;\n },\n\n lookup(code) {\n return this._map[code];\n },\n\n contains(code) {\n return this._map[code] !== undefined;\n },\n\n forEach(callback) {\n // Most maps have fewer than 65536 entries, and for those we use normal\n // array iteration. But really sparse tables are possible -- e.g. with\n // indices in the *billions*. For such tables we use for..in, which isn't\n // ideal because it stringifies the indices for all present elements, but\n // it does avoid iterating over every undefined entry.\n let map = this._map;\n let length = map.length;\n if (length <= 0x10000) {\n for (let i = 0; i < length; i++) {\n if (map[i] !== undefined) {\n callback(i, map[i]);\n }\n }\n } else {\n for (let i in map) {\n callback(i, map[i]);\n }\n }\n },\n\n charCodeOf(value) {\n // `Array.prototype.indexOf` is *extremely* inefficient for arrays which\n // are both very sparse and very large (see issue8372.pdf).\n let map = this._map;\n if (map.length <= 0x10000) {\n return map.indexOf(value);\n }\n for (let charCode in map) {\n if (map[charCode] === value) {\n return (charCode | 0);\n }\n }\n return -1;\n },\n\n getMap() {\n return this._map;\n },\n\n readCharCode(str, offset, out) {\n var c = 0;\n var codespaceRanges = this.codespaceRanges;\n var codespaceRangesLen = this.codespaceRanges.length;\n // 9.7.6.2 CMap Mapping\n // The code length is at most 4.\n for (var n = 0; n < codespaceRangesLen; n++) {\n c = ((c << 8) | str.charCodeAt(offset + n)) >>> 0;\n // Check each codespace range to see if it falls within.\n var codespaceRange = codespaceRanges[n];\n for (var k = 0, kk = codespaceRange.length; k < kk;) {\n var low = codespaceRange[k++];\n var high = codespaceRange[k++];\n if (c >= low && c <= high) {\n out.charcode = c;\n out.length = n + 1;\n return;\n }\n }\n }\n out.charcode = 0;\n out.length = 1;\n },\n\n get length() {\n return this._map.length;\n },\n\n get isIdentityCMap() {\n if (!(this.name === 'Identity-H' || this.name === 'Identity-V')) {\n return false;\n }\n if (this._map.length !== 0x10000) {\n return false;\n }\n for (var i = 0; i < 0x10000; i++) {\n if (this._map[i] !== i) {\n return false;\n }\n }\n return true;\n },\n };\n return CMap;\n})();\n\n// A special case of CMap, where the _map array implicitly has a length of\n// 65536 and each element is equal to its index.\nvar IdentityCMap = (function IdentityCMapClosure() {\n function IdentityCMap(vertical, n) {\n CMap.call(this);\n this.vertical = vertical;\n this.addCodespaceRange(n, 0, 0xffff);\n }\n Util.inherit(IdentityCMap, CMap, {});\n\n IdentityCMap.prototype = {\n addCodespaceRange: CMap.prototype.addCodespaceRange,\n\n mapCidRange(low, high, dstLow) {\n throw new Error('should not call mapCidRange');\n },\n\n mapBfRange(low, high, dstLow) {\n throw new Error('should not call mapBfRange');\n },\n\n mapBfRangeToArray(low, high, array) {\n throw new Error('should not call mapBfRangeToArray');\n },\n\n mapOne(src, dst) {\n throw new Error('should not call mapCidOne');\n },\n\n lookup(code) {\n return (isInt(code) && code <= 0xffff) ? code : undefined;\n },\n\n contains(code) {\n return isInt(code) && code <= 0xffff;\n },\n\n forEach(callback) {\n for (var i = 0; i <= 0xffff; i++) {\n callback(i, i);\n }\n },\n\n charCodeOf(value) {\n return (isInt(value) && value <= 0xffff) ? value : -1;\n },\n\n getMap() {\n // Sometimes identity maps must be instantiated, but it's rare.\n var map = new Array(0x10000);\n for (var i = 0; i <= 0xffff; i++) {\n map[i] = i;\n }\n return map;\n },\n\n readCharCode: CMap.prototype.readCharCode,\n\n get length() {\n return 0x10000;\n },\n\n get isIdentityCMap() {\n throw new Error('should not access .isIdentityCMap');\n },\n };\n\n return IdentityCMap;\n})();\n\nvar BinaryCMapReader = (function BinaryCMapReaderClosure() {\n function hexToInt(a, size) {\n var n = 0;\n for (var i = 0; i <= size; i++) {\n n = (n << 8) | a[i];\n }\n return n >>> 0;\n }\n\n function hexToStr(a, size) {\n // This code is hot. Special-case some common values to avoid creating an\n // object with subarray().\n if (size === 1) {\n return String.fromCharCode(a[0], a[1]);\n }\n if (size === 3) {\n return String.fromCharCode(a[0], a[1], a[2], a[3]);\n }\n return String.fromCharCode.apply(null, a.subarray(0, size + 1));\n }\n\n function addHex(a, b, size) {\n var c = 0;\n for (var i = size; i >= 0; i--) {\n c += a[i] + b[i];\n a[i] = c & 255;\n c >>= 8;\n }\n }\n\n function incHex(a, size) {\n var c = 1;\n for (var i = size; i >= 0 && c > 0; i--) {\n c += a[i];\n a[i] = c & 255;\n c >>= 8;\n }\n }\n\n var MAX_NUM_SIZE = 16;\n var MAX_ENCODED_NUM_SIZE = 19; // ceil(MAX_NUM_SIZE * 7 / 8)\n\n function BinaryCMapStream(data) {\n this.buffer = data;\n this.pos = 0;\n this.end = data.length;\n this.tmpBuf = new Uint8Array(MAX_ENCODED_NUM_SIZE);\n }\n\n BinaryCMapStream.prototype = {\n readByte() {\n if (this.pos >= this.end) {\n return -1;\n }\n return this.buffer[this.pos++];\n },\n readNumber() {\n var n = 0;\n var last;\n do {\n var b = this.readByte();\n if (b < 0) {\n throw new FormatError('unexpected EOF in bcmap');\n }\n last = !(b & 0x80);\n n = (n << 7) | (b & 0x7F);\n } while (!last);\n return n;\n },\n readSigned() {\n var n = this.readNumber();\n return (n & 1) ? ~(n >>> 1) : n >>> 1;\n },\n readHex(num, size) {\n num.set(this.buffer.subarray(this.pos,\n this.pos + size + 1));\n this.pos += size + 1;\n },\n readHexNumber(num, size) {\n var last;\n var stack = this.tmpBuf, sp = 0;\n do {\n var b = this.readByte();\n if (b < 0) {\n throw new FormatError('unexpected EOF in bcmap');\n }\n last = !(b & 0x80);\n stack[sp++] = b & 0x7F;\n } while (!last);\n var i = size, buffer = 0, bufferSize = 0;\n while (i >= 0) {\n while (bufferSize < 8 && stack.length > 0) {\n buffer = (stack[--sp] << bufferSize) | buffer;\n bufferSize += 7;\n }\n num[i] = buffer & 255;\n i--;\n buffer >>= 8;\n bufferSize -= 8;\n }\n },\n readHexSigned(num, size) {\n this.readHexNumber(num, size);\n var sign = num[size] & 1 ? 255 : 0;\n var c = 0;\n for (var i = 0; i <= size; i++) {\n c = ((c & 1) << 8) | num[i];\n num[i] = (c >> 1) ^ sign;\n }\n },\n readString() {\n var len = this.readNumber();\n var s = '';\n for (var i = 0; i < len; i++) {\n s += String.fromCharCode(this.readNumber());\n }\n return s;\n },\n };\n\n function processBinaryCMap(data, cMap, extend) {\n return new Promise(function (resolve, reject) {\n var stream = new BinaryCMapStream(data);\n var header = stream.readByte();\n cMap.vertical = !!(header & 1);\n\n var useCMap = null;\n var start = new Uint8Array(MAX_NUM_SIZE);\n var end = new Uint8Array(MAX_NUM_SIZE);\n var char = new Uint8Array(MAX_NUM_SIZE);\n var charCode = new Uint8Array(MAX_NUM_SIZE);\n var tmp = new Uint8Array(MAX_NUM_SIZE);\n var code;\n\n var b;\n while ((b = stream.readByte()) >= 0) {\n var type = b >> 5;\n if (type === 7) { // metadata, e.g. comment or usecmap\n switch (b & 0x1F) {\n case 0:\n stream.readString(); // skipping comment\n break;\n case 1:\n useCMap = stream.readString();\n break;\n }\n continue;\n }\n var sequence = !!(b & 0x10);\n var dataSize = b & 15;\n\n if (dataSize + 1 > MAX_NUM_SIZE) {\n throw new Error('processBinaryCMap: Invalid dataSize.');\n }\n\n var ucs2DataSize = 1;\n var subitemsCount = stream.readNumber();\n var i;\n switch (type) {\n case 0: // codespacerange\n stream.readHex(start, dataSize);\n stream.readHexNumber(end, dataSize);\n addHex(end, start, dataSize);\n cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize),\n hexToInt(end, dataSize));\n for (i = 1; i < subitemsCount; i++) {\n incHex(end, dataSize);\n stream.readHexNumber(start, dataSize);\n addHex(start, end, dataSize);\n stream.readHexNumber(end, dataSize);\n addHex(end, start, dataSize);\n cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize),\n hexToInt(end, dataSize));\n }\n break;\n case 1: // notdefrange\n stream.readHex(start, dataSize);\n stream.readHexNumber(end, dataSize);\n addHex(end, start, dataSize);\n code = stream.readNumber();\n // undefined range, skipping\n for (i = 1; i < subitemsCount; i++) {\n incHex(end, dataSize);\n stream.readHexNumber(start, dataSize);\n addHex(start, end, dataSize);\n stream.readHexNumber(end, dataSize);\n addHex(end, start, dataSize);\n code = stream.readNumber();\n // nop\n }\n break;\n case 2: // cidchar\n stream.readHex(char, dataSize);\n code = stream.readNumber();\n cMap.mapOne(hexToInt(char, dataSize), code);\n for (i = 1; i < subitemsCount; i++) {\n incHex(char, dataSize);\n if (!sequence) {\n stream.readHexNumber(tmp, dataSize);\n addHex(char, tmp, dataSize);\n }\n code = stream.readSigned() + (code + 1);\n cMap.mapOne(hexToInt(char, dataSize), code);\n }\n break;\n case 3: // cidrange\n stream.readHex(start, dataSize);\n stream.readHexNumber(end, dataSize);\n addHex(end, start, dataSize);\n code = stream.readNumber();\n cMap.mapCidRange(hexToInt(start, dataSize), hexToInt(end, dataSize),\n code);\n for (i = 1; i < subitemsCount; i++) {\n incHex(end, dataSize);\n if (!sequence) {\n stream.readHexNumber(start, dataSize);\n addHex(start, end, dataSize);\n } else {\n start.set(end);\n }\n stream.readHexNumber(end, dataSize);\n addHex(end, start, dataSize);\n code = stream.readNumber();\n cMap.mapCidRange(hexToInt(start, dataSize),\n hexToInt(end, dataSize), code);\n }\n break;\n case 4: // bfchar\n stream.readHex(char, ucs2DataSize);\n stream.readHex(charCode, dataSize);\n cMap.mapOne(hexToInt(char, ucs2DataSize),\n hexToStr(charCode, dataSize));\n for (i = 1; i < subitemsCount; i++) {\n incHex(char, ucs2DataSize);\n if (!sequence) {\n stream.readHexNumber(tmp, ucs2DataSize);\n addHex(char, tmp, ucs2DataSize);\n }\n incHex(charCode, dataSize);\n stream.readHexSigned(tmp, dataSize);\n addHex(charCode, tmp, dataSize);\n cMap.mapOne(hexToInt(char, ucs2DataSize),\n hexToStr(charCode, dataSize));\n }\n break;\n case 5: // bfrange\n stream.readHex(start, ucs2DataSize);\n stream.readHexNumber(end, ucs2DataSize);\n addHex(end, start, ucs2DataSize);\n stream.readHex(charCode, dataSize);\n cMap.mapBfRange(hexToInt(start, ucs2DataSize),\n hexToInt(end, ucs2DataSize),\n hexToStr(charCode, dataSize));\n for (i = 1; i < subitemsCount; i++) {\n incHex(end, ucs2DataSize);\n if (!sequence) {\n stream.readHexNumber(start, ucs2DataSize);\n addHex(start, end, ucs2DataSize);\n } else {\n start.set(end);\n }\n stream.readHexNumber(end, ucs2DataSize);\n addHex(end, start, ucs2DataSize);\n stream.readHex(charCode, dataSize);\n cMap.mapBfRange(hexToInt(start, ucs2DataSize),\n hexToInt(end, ucs2DataSize),\n hexToStr(charCode, dataSize));\n }\n break;\n default:\n reject(new Error('processBinaryCMap: Unknown type: ' + type));\n return;\n }\n }\n\n if (useCMap) {\n resolve(extend(useCMap));\n return;\n }\n resolve(cMap);\n });\n }\n\n function BinaryCMapReader() {}\n\n BinaryCMapReader.prototype = {\n process: processBinaryCMap,\n };\n\n return BinaryCMapReader;\n})();\n\nvar CMapFactory = (function CMapFactoryClosure() {\n function strToInt(str) {\n var a = 0;\n for (var i = 0; i < str.length; i++) {\n a = (a << 8) | str.charCodeAt(i);\n }\n return a >>> 0;\n }\n\n function expectString(obj) {\n if (!isString(obj)) {\n throw new FormatError('Malformed CMap: expected string.');\n }\n }\n\n function expectInt(obj) {\n if (!isInt(obj)) {\n throw new FormatError('Malformed CMap: expected int.');\n }\n }\n\n function parseBfChar(cMap, lexer) {\n while (true) {\n var obj = lexer.getObj();\n if (isEOF(obj)) {\n break;\n }\n if (isCmd(obj, 'endbfchar')) {\n return;\n }\n expectString(obj);\n var src = strToInt(obj);\n obj = lexer.getObj();\n // TODO are /dstName used?\n expectString(obj);\n var dst = obj;\n cMap.mapOne(src, dst);\n }\n }\n\n function parseBfRange(cMap, lexer) {\n while (true) {\n var obj = lexer.getObj();\n if (isEOF(obj)) {\n break;\n }\n if (isCmd(obj, 'endbfrange')) {\n return;\n }\n expectString(obj);\n var low = strToInt(obj);\n obj = lexer.getObj();\n expectString(obj);\n var high = strToInt(obj);\n obj = lexer.getObj();\n if (isInt(obj) || isString(obj)) {\n var dstLow = isInt(obj) ? String.fromCharCode(obj) : obj;\n cMap.mapBfRange(low, high, dstLow);\n } else if (isCmd(obj, '[')) {\n obj = lexer.getObj();\n var array = [];\n while (!isCmd(obj, ']') && !isEOF(obj)) {\n array.push(obj);\n obj = lexer.getObj();\n }\n cMap.mapBfRangeToArray(low, high, array);\n } else {\n break;\n }\n }\n throw new FormatError('Invalid bf range.');\n }\n\n function parseCidChar(cMap, lexer) {\n while (true) {\n var obj = lexer.getObj();\n if (isEOF(obj)) {\n break;\n }\n if (isCmd(obj, 'endcidchar')) {\n return;\n }\n expectString(obj);\n var src = strToInt(obj);\n obj = lexer.getObj();\n expectInt(obj);\n var dst = obj;\n cMap.mapOne(src, dst);\n }\n }\n\n function parseCidRange(cMap, lexer) {\n while (true) {\n var obj = lexer.getObj();\n if (isEOF(obj)) {\n break;\n }\n if (isCmd(obj, 'endcidrange')) {\n return;\n }\n expectString(obj);\n var low = strToInt(obj);\n obj = lexer.getObj();\n expectString(obj);\n var high = strToInt(obj);\n obj = lexer.getObj();\n expectInt(obj);\n var dstLow = obj;\n cMap.mapCidRange(low, high, dstLow);\n }\n }\n\n function parseCodespaceRange(cMap, lexer) {\n while (true) {\n var obj = lexer.getObj();\n if (isEOF(obj)) {\n break;\n }\n if (isCmd(obj, 'endcodespacerange')) {\n return;\n }\n if (!isString(obj)) {\n break;\n }\n var low = strToInt(obj);\n obj = lexer.getObj();\n if (!isString(obj)) {\n break;\n }\n var high = strToInt(obj);\n cMap.addCodespaceRange(obj.length, low, high);\n }\n throw new FormatError('Invalid codespace range.');\n }\n\n function parseWMode(cMap, lexer) {\n var obj = lexer.getObj();\n if (isInt(obj)) {\n cMap.vertical = !!obj;\n }\n }\n\n function parseCMapName(cMap, lexer) {\n var obj = lexer.getObj();\n if (isName(obj) && isString(obj.name)) {\n cMap.name = obj.name;\n }\n }\n\n function parseCMap(cMap, lexer, fetchBuiltInCMap, useCMap) {\n var previous;\n var embededUseCMap;\n objLoop: while (true) {\n try {\n var obj = lexer.getObj();\n if (isEOF(obj)) {\n break;\n } else if (isName(obj)) {\n if (obj.name === 'WMode') {\n parseWMode(cMap, lexer);\n } else if (obj.name === 'CMapName') {\n parseCMapName(cMap, lexer);\n }\n previous = obj;\n } else if (isCmd(obj)) {\n switch (obj.cmd) {\n case 'endcmap':\n break objLoop;\n case 'usecmap':\n if (isName(previous)) {\n embededUseCMap = previous.name;\n }\n break;\n case 'begincodespacerange':\n parseCodespaceRange(cMap, lexer);\n break;\n case 'beginbfchar':\n parseBfChar(cMap, lexer);\n break;\n case 'begincidchar':\n parseCidChar(cMap, lexer);\n break;\n case 'beginbfrange':\n parseBfRange(cMap, lexer);\n break;\n case 'begincidrange':\n parseCidRange(cMap, lexer);\n break;\n }\n }\n } catch (ex) {\n if (ex instanceof MissingDataException) {\n throw ex;\n }\n warn('Invalid cMap data: ' + ex);\n continue;\n }\n }\n\n if (!useCMap && embededUseCMap) {\n // Load the usecmap definition from the file only if there wasn't one\n // specified.\n useCMap = embededUseCMap;\n }\n if (useCMap) {\n return extendCMap(cMap, fetchBuiltInCMap, useCMap);\n }\n return Promise.resolve(cMap);\n }\n\n function extendCMap(cMap, fetchBuiltInCMap, useCMap) {\n return createBuiltInCMap(useCMap, fetchBuiltInCMap).then(function(newCMap) {\n cMap.useCMap = newCMap;\n // If there aren't any code space ranges defined clone all the parent ones\n // into this cMap.\n if (cMap.numCodespaceRanges === 0) {\n var useCodespaceRanges = cMap.useCMap.codespaceRanges;\n for (var i = 0; i < useCodespaceRanges.length; i++) {\n cMap.codespaceRanges[i] = useCodespaceRanges[i].slice();\n }\n cMap.numCodespaceRanges = cMap.useCMap.numCodespaceRanges;\n }\n // Merge the map into the current one, making sure not to override\n // any previously defined entries.\n cMap.useCMap.forEach(function(key, value) {\n if (!cMap.contains(key)) {\n cMap.mapOne(key, cMap.useCMap.lookup(key));\n }\n });\n\n return cMap;\n });\n }\n\n function createBuiltInCMap(name, fetchBuiltInCMap) {\n if (name === 'Identity-H') {\n return Promise.resolve(new IdentityCMap(false, 2));\n } else if (name === 'Identity-V') {\n return Promise.resolve(new IdentityCMap(true, 2));\n }\n if (BUILT_IN_CMAPS.indexOf(name) === -1) {\n return Promise.reject(new Error('Unknown CMap name: ' + name));\n }\n if (!fetchBuiltInCMap) {\n return Promise.reject(new Error(\n 'Built-in CMap parameters are not provided.'));\n }\n\n return fetchBuiltInCMap(name).then(function (data) {\n var cMapData = data.cMapData, compressionType = data.compressionType;\n var cMap = new CMap(true);\n\n if (compressionType === CMapCompressionType.BINARY) {\n return new BinaryCMapReader().process(cMapData, cMap,\n function (useCMap) {\n return extendCMap(cMap, fetchBuiltInCMap, useCMap);\n });\n }\n if (compressionType === CMapCompressionType.NONE) {\n var lexer = new Lexer(new Stream(cMapData));\n return parseCMap(cMap, lexer, fetchBuiltInCMap, null);\n }\n return Promise.reject(new Error(\n 'TODO: Only BINARY/NONE CMap compression is currently supported.'));\n });\n }\n\n return {\n create(params) {\n var encoding = params.encoding;\n var fetchBuiltInCMap = params.fetchBuiltInCMap;\n var useCMap = params.useCMap;\n\n if (isName(encoding)) {\n return createBuiltInCMap(encoding.name, fetchBuiltInCMap);\n } else if (isStream(encoding)) {\n var cMap = new CMap();\n var lexer = new Lexer(encoding);\n return parseCMap(cMap, lexer, fetchBuiltInCMap, useCMap).then(\n function (parsedCMap) {\n if (parsedCMap.isIdentityCMap) {\n return createBuiltInCMap(parsedCMap.name, fetchBuiltInCMap);\n }\n return parsedCMap;\n });\n }\n return Promise.reject(new Error('Encoding required.'));\n },\n };\n})();\n\nexport {\n CMap,\n IdentityCMap,\n CMapFactory,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/cmap.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Catalog, ObjectLoader, XRef } from './obj';\nimport { Dict, isDict, isName, isStream } from './primitives';\nimport {\n info, isArray, isArrayBuffer, isNum, isSpace, isString, MissingDataException,\n OPS, shadow, stringToBytes, stringToPDFString, Util, warn\n} from '../shared/util';\nimport { NullStream, Stream, StreamsSequenceStream } from './stream';\nimport { OperatorList, PartialEvaluator } from './evaluator';\nimport { AnnotationFactory } from './annotation';\nimport { calculateMD5 } from './crypto';\nimport { Linearization } from './parser';\n\nvar Page = (function PageClosure() {\n\n var DEFAULT_USER_UNIT = 1.0;\n var LETTER_SIZE_MEDIABOX = [0, 0, 612, 792];\n\n function isAnnotationRenderable(annotation, intent) {\n return (intent === 'display' && annotation.viewable) ||\n (intent === 'print' && annotation.printable);\n }\n\n function Page(pdfManager, xref, pageIndex, pageDict, ref, fontCache,\n builtInCMapCache) {\n this.pdfManager = pdfManager;\n this.pageIndex = pageIndex;\n this.pageDict = pageDict;\n this.xref = xref;\n this.ref = ref;\n this.fontCache = fontCache;\n this.builtInCMapCache = builtInCMapCache;\n this.evaluatorOptions = pdfManager.evaluatorOptions;\n this.resourcesPromise = null;\n\n var uniquePrefix = 'p' + this.pageIndex + '_';\n var idCounters = {\n obj: 0,\n };\n this.idFactory = {\n createObjId() {\n return uniquePrefix + (++idCounters.obj);\n },\n };\n }\n\n Page.prototype = {\n getPageProp: function Page_getPageProp(key) {\n return this.pageDict.get(key);\n },\n\n getInheritedPageProp: function Page_getInheritedPageProp(key, getArray) {\n var dict = this.pageDict, valueArray = null, loopCount = 0;\n var MAX_LOOP_COUNT = 100;\n getArray = getArray || false;\n // Always walk up the entire parent chain, to be able to find\n // e.g. \\Resources placed on multiple levels of the tree.\n while (dict) {\n var value = getArray ? dict.getArray(key) : dict.get(key);\n if (value !== undefined) {\n if (!valueArray) {\n valueArray = [];\n }\n valueArray.push(value);\n }\n if (++loopCount > MAX_LOOP_COUNT) {\n warn('getInheritedPageProp: maximum loop count exceeded for ' + key);\n return valueArray ? valueArray[0] : undefined;\n }\n dict = dict.get('Parent');\n }\n if (!valueArray) {\n return undefined;\n }\n if (valueArray.length === 1 || !isDict(valueArray[0])) {\n return valueArray[0];\n }\n return Dict.merge(this.xref, valueArray);\n },\n\n get content() {\n return this.getPageProp('Contents');\n },\n\n get resources() {\n // For robustness: The spec states that a \\Resources entry has to be\n // present, but can be empty. Some document omit it still, in this case\n // we return an empty dictionary.\n return shadow(this, 'resources',\n this.getInheritedPageProp('Resources') || Dict.empty);\n },\n\n get mediaBox() {\n var mediaBox = this.getInheritedPageProp('MediaBox', true);\n // Reset invalid media box to letter size.\n if (!isArray(mediaBox) || mediaBox.length !== 4) {\n return shadow(this, 'mediaBox', LETTER_SIZE_MEDIABOX);\n }\n return shadow(this, 'mediaBox', mediaBox);\n },\n\n get cropBox() {\n var cropBox = this.getInheritedPageProp('CropBox', true);\n // Reset invalid crop box to media box.\n if (!isArray(cropBox) || cropBox.length !== 4) {\n return shadow(this, 'cropBox', this.mediaBox);\n }\n return shadow(this, 'cropBox', cropBox);\n },\n\n get userUnit() {\n var obj = this.getPageProp('UserUnit');\n if (!isNum(obj) || obj <= 0) {\n obj = DEFAULT_USER_UNIT;\n }\n return shadow(this, 'userUnit', obj);\n },\n\n get view() {\n // From the spec, 6th ed., p.963:\n // \"The crop, bleed, trim, and art boxes should not ordinarily\n // extend beyond the boundaries of the media box. If they do, they are\n // effectively reduced to their intersection with the media box.\"\n var mediaBox = this.mediaBox, cropBox = this.cropBox;\n if (mediaBox === cropBox) {\n return shadow(this, 'view', mediaBox);\n }\n var intersection = Util.intersect(cropBox, mediaBox);\n return shadow(this, 'view', intersection || mediaBox);\n },\n\n get rotate() {\n var rotate = this.getInheritedPageProp('Rotate') || 0;\n // Normalize rotation so it's a multiple of 90 and between 0 and 270\n if (rotate % 90 !== 0) {\n rotate = 0;\n } else if (rotate >= 360) {\n rotate = rotate % 360;\n } else if (rotate < 0) {\n // The spec doesn't cover negatives, assume its counterclockwise\n // rotation. The following is the other implementation of modulo.\n rotate = ((rotate % 360) + 360) % 360;\n }\n return shadow(this, 'rotate', rotate);\n },\n\n getContentStream: function Page_getContentStream() {\n var content = this.content;\n var stream;\n if (isArray(content)) {\n // fetching items\n var xref = this.xref;\n var i, n = content.length;\n var streams = [];\n for (i = 0; i < n; ++i) {\n streams.push(xref.fetchIfRef(content[i]));\n }\n stream = new StreamsSequenceStream(streams);\n } else if (isStream(content)) {\n stream = content;\n } else {\n // replacing non-existent page content with empty one\n stream = new NullStream();\n }\n return stream;\n },\n\n loadResources: function Page_loadResources(keys) {\n if (!this.resourcesPromise) {\n // TODO: add async getInheritedPageProp and remove this.\n this.resourcesPromise = this.pdfManager.ensure(this, 'resources');\n }\n return this.resourcesPromise.then(() => {\n let objectLoader = new ObjectLoader(this.resources, keys, this.xref);\n\n return objectLoader.load();\n });\n },\n\n getOperatorList({ handler, task, intent, renderInteractiveForms, }) {\n var contentStreamPromise = this.pdfManager.ensure(this,\n 'getContentStream');\n var resourcesPromise = this.loadResources([\n 'ExtGState',\n 'ColorSpace',\n 'Pattern',\n 'Shading',\n 'XObject',\n 'Font'\n // ProcSet\n // Properties\n ]);\n\n var partialEvaluator = new PartialEvaluator({\n pdfManager: this.pdfManager,\n xref: this.xref,\n handler,\n pageIndex: this.pageIndex,\n idFactory: this.idFactory,\n fontCache: this.fontCache,\n builtInCMapCache: this.builtInCMapCache,\n options: this.evaluatorOptions,\n });\n\n var dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);\n var pageListPromise = dataPromises.then(([contentStream]) => {\n var opList = new OperatorList(intent, handler, this.pageIndex);\n\n handler.send('StartRenderPage', {\n transparency: partialEvaluator.hasBlendModes(this.resources),\n pageIndex: this.pageIndex,\n intent,\n });\n return partialEvaluator.getOperatorList({\n stream: contentStream,\n task,\n resources: this.resources,\n operatorList: opList,\n }).then(function () {\n return opList;\n });\n });\n\n // Fetch the page's annotations and add their operator lists to the\n // page's operator list to render them.\n var annotationsPromise = this.pdfManager.ensure(this, 'annotations');\n return Promise.all([pageListPromise, annotationsPromise]).then(\n function ([pageOpList, annotations]) {\n if (annotations.length === 0) {\n pageOpList.flush(true);\n return pageOpList;\n }\n\n // Collect the operator list promises for the annotations. Each promise\n // is resolved with the complete operator list for a single annotation.\n var i, ii, opListPromises = [];\n for (i = 0, ii = annotations.length; i < ii; i++) {\n if (isAnnotationRenderable(annotations[i], intent)) {\n opListPromises.push(annotations[i].getOperatorList(\n partialEvaluator, task, renderInteractiveForms));\n }\n }\n\n return Promise.all(opListPromises).then(function(opLists) {\n pageOpList.addOp(OPS.beginAnnotations, []);\n for (i = 0, ii = opLists.length; i < ii; i++) {\n pageOpList.addOpList(opLists[i]);\n }\n pageOpList.addOp(OPS.endAnnotations, []);\n\n pageOpList.flush(true);\n return pageOpList;\n });\n });\n },\n\n extractTextContent({ handler, task, normalizeWhitespace,\n sink, combineTextItems, }) {\n var contentStreamPromise = this.pdfManager.ensure(this,\n 'getContentStream');\n var resourcesPromise = this.loadResources([\n 'ExtGState',\n 'XObject',\n 'Font'\n ]);\n\n var dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);\n return dataPromises.then(([contentStream]) => {\n var partialEvaluator = new PartialEvaluator({\n pdfManager: this.pdfManager,\n xref: this.xref,\n handler,\n pageIndex: this.pageIndex,\n idFactory: this.idFactory,\n fontCache: this.fontCache,\n builtInCMapCache: this.builtInCMapCache,\n options: this.evaluatorOptions,\n });\n\n return partialEvaluator.getTextContent({\n stream: contentStream,\n task,\n resources: this.resources,\n normalizeWhitespace,\n combineTextItems,\n sink,\n });\n });\n },\n\n getAnnotationsData: function Page_getAnnotationsData(intent) {\n var annotations = this.annotations;\n var annotationsData = [];\n for (var i = 0, n = annotations.length; i < n; ++i) {\n if (!intent || isAnnotationRenderable(annotations[i], intent)) {\n annotationsData.push(annotations[i].data);\n }\n }\n return annotationsData;\n },\n\n get annotations() {\n var annotations = [];\n var annotationRefs = this.getInheritedPageProp('Annots') || [];\n var annotationFactory = new AnnotationFactory();\n for (var i = 0, n = annotationRefs.length; i < n; ++i) {\n var annotationRef = annotationRefs[i];\n var annotation = annotationFactory.create(this.xref, annotationRef,\n this.pdfManager,\n this.idFactory);\n if (annotation) {\n annotations.push(annotation);\n }\n }\n return shadow(this, 'annotations', annotations);\n },\n };\n\n return Page;\n})();\n\n/**\n * The `PDFDocument` holds all the data of the PDF file. Compared to the\n * `PDFDoc`, this one doesn't have any job management code.\n * Right now there exists one PDFDocument on the main thread + one object\n * for each worker. If there is no worker support enabled, there are two\n * `PDFDocument` objects on the main thread created.\n */\nvar PDFDocument = (function PDFDocumentClosure() {\n var FINGERPRINT_FIRST_BYTES = 1024;\n var EMPTY_FINGERPRINT = '\\x00\\x00\\x00\\x00\\x00\\x00\\x00' +\n '\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00';\n\n function PDFDocument(pdfManager, arg) {\n var stream;\n if (isStream(arg)) {\n stream = arg;\n } else if (isArrayBuffer(arg)) {\n stream = new Stream(arg);\n } else {\n throw new Error('PDFDocument: Unknown argument type');\n }\n if (stream.length <= 0) {\n throw new Error('PDFDocument: stream must have data');\n }\n\n this.pdfManager = pdfManager;\n this.stream = stream;\n this.xref = new XRef(stream, pdfManager);\n }\n\n function find(stream, needle, limit, backwards) {\n var pos = stream.pos;\n var end = stream.end;\n var strBuf = [];\n if (pos + limit > end) {\n limit = end - pos;\n }\n for (var n = 0; n < limit; ++n) {\n strBuf.push(String.fromCharCode(stream.getByte()));\n }\n var str = strBuf.join('');\n stream.pos = pos;\n var index = backwards ? str.lastIndexOf(needle) : str.indexOf(needle);\n if (index === -1) {\n return false; /* not found */\n }\n stream.pos += index;\n return true; /* found */\n }\n\n var DocumentInfoValidators = {\n get entries() {\n // Lazily build this since all the validation functions below are not\n // defined until after this file loads.\n return shadow(this, 'entries', {\n Title: isString,\n Author: isString,\n Subject: isString,\n Keywords: isString,\n Creator: isString,\n Producer: isString,\n CreationDate: isString,\n ModDate: isString,\n Trapped: isName,\n });\n },\n };\n\n PDFDocument.prototype = {\n parse: function PDFDocument_parse(recoveryMode) {\n this.setup(recoveryMode);\n var version = this.catalog.catDict.get('Version');\n if (isName(version)) {\n this.pdfFormatVersion = version.name;\n }\n try {\n // checking if AcroForm is present\n this.acroForm = this.catalog.catDict.get('AcroForm');\n if (this.acroForm) {\n this.xfa = this.acroForm.get('XFA');\n var fields = this.acroForm.get('Fields');\n if ((!fields || !isArray(fields) || fields.length === 0) &&\n !this.xfa) {\n // no fields and no XFA -- not a form (?)\n this.acroForm = null;\n }\n }\n } catch (ex) {\n if (ex instanceof MissingDataException) {\n throw ex;\n }\n info('Something wrong with AcroForm entry');\n this.acroForm = null;\n }\n },\n\n get linearization() {\n var linearization = null;\n if (this.stream.length) {\n try {\n linearization = Linearization.create(this.stream);\n } catch (err) {\n if (err instanceof MissingDataException) {\n throw err;\n }\n info(err);\n }\n }\n // shadow the prototype getter with a data property\n return shadow(this, 'linearization', linearization);\n },\n get startXRef() {\n var stream = this.stream;\n var startXRef = 0;\n var linearization = this.linearization;\n if (linearization) {\n // Find end of first obj.\n stream.reset();\n if (find(stream, 'endobj', 1024)) {\n startXRef = stream.pos + 6;\n }\n } else {\n // Find startxref by jumping backward from the end of the file.\n var step = 1024;\n var found = false, pos = stream.end;\n while (!found && pos > 0) {\n pos -= step - 'startxref'.length;\n if (pos < 0) {\n pos = 0;\n }\n stream.pos = pos;\n found = find(stream, 'startxref', step, true);\n }\n if (found) {\n stream.skip(9);\n var ch;\n do {\n ch = stream.getByte();\n } while (isSpace(ch));\n var str = '';\n while (ch >= 0x20 && ch <= 0x39) { // < '9'\n str += String.fromCharCode(ch);\n ch = stream.getByte();\n }\n startXRef = parseInt(str, 10);\n if (isNaN(startXRef)) {\n startXRef = 0;\n }\n }\n }\n // shadow the prototype getter with a data property\n return shadow(this, 'startXRef', startXRef);\n },\n get mainXRefEntriesOffset() {\n var mainXRefEntriesOffset = 0;\n var linearization = this.linearization;\n if (linearization) {\n mainXRefEntriesOffset = linearization.mainXRefEntriesOffset;\n }\n // shadow the prototype getter with a data property\n return shadow(this, 'mainXRefEntriesOffset', mainXRefEntriesOffset);\n },\n // Find the header, remove leading garbage and setup the stream\n // starting from the header.\n checkHeader: function PDFDocument_checkHeader() {\n var stream = this.stream;\n stream.reset();\n if (find(stream, '%PDF-', 1024)) {\n // Found the header, trim off any garbage before it.\n stream.moveStart();\n // Reading file format version\n var MAX_VERSION_LENGTH = 12;\n var version = '', ch;\n while ((ch = stream.getByte()) > 0x20) { // SPACE\n if (version.length >= MAX_VERSION_LENGTH) {\n break;\n }\n version += String.fromCharCode(ch);\n }\n if (!this.pdfFormatVersion) {\n // removing \"%PDF-\"-prefix\n this.pdfFormatVersion = version.substring(5);\n }\n return;\n }\n // May not be a PDF file, continue anyway.\n },\n parseStartXRef: function PDFDocument_parseStartXRef() {\n var startXRef = this.startXRef;\n this.xref.setStartXRef(startXRef);\n },\n setup: function PDFDocument_setup(recoveryMode) {\n this.xref.parse(recoveryMode);\n var pageFactory = {\n createPage: (pageIndex, dict, ref, fontCache, builtInCMapCache) => {\n return new Page(this.pdfManager, this.xref, pageIndex, dict, ref,\n fontCache, builtInCMapCache);\n },\n };\n this.catalog = new Catalog(this.pdfManager, this.xref, pageFactory);\n },\n get numPages() {\n var linearization = this.linearization;\n var num = linearization ? linearization.numPages : this.catalog.numPages;\n // shadow the prototype getter\n return shadow(this, 'numPages', num);\n },\n get documentInfo() {\n var docInfo = {\n PDFFormatVersion: this.pdfFormatVersion,\n IsAcroFormPresent: !!this.acroForm,\n IsXFAPresent: !!this.xfa,\n };\n var infoDict;\n try {\n infoDict = this.xref.trailer.get('Info');\n } catch (err) {\n if (err instanceof MissingDataException) {\n throw err;\n }\n info('The document information dictionary is invalid.');\n }\n if (infoDict) {\n var validEntries = DocumentInfoValidators.entries;\n // Only fill the document info with valid entries from the spec.\n for (var key in validEntries) {\n if (infoDict.has(key)) {\n var value = infoDict.get(key);\n // Make sure the value conforms to the spec.\n if (validEntries[key](value)) {\n docInfo[key] = (typeof value !== 'string' ?\n value : stringToPDFString(value));\n } else {\n info('Bad value in document info for \"' + key + '\"');\n }\n }\n }\n }\n return shadow(this, 'documentInfo', docInfo);\n },\n get fingerprint() {\n var xref = this.xref, hash, fileID = '';\n var idArray = xref.trailer.get('ID');\n\n if (idArray && isArray(idArray) && idArray[0] && isString(idArray[0]) &&\n idArray[0] !== EMPTY_FINGERPRINT) {\n hash = stringToBytes(idArray[0]);\n } else {\n if (this.stream.ensureRange) {\n this.stream.ensureRange(0,\n Math.min(FINGERPRINT_FIRST_BYTES, this.stream.end));\n }\n hash = calculateMD5(this.stream.bytes.subarray(0,\n FINGERPRINT_FIRST_BYTES), 0, FINGERPRINT_FIRST_BYTES);\n }\n\n for (var i = 0, n = hash.length; i < n; i++) {\n var hex = hash[i].toString(16);\n fileID += hex.length === 1 ? '0' + hex : hex;\n }\n\n return shadow(this, 'fingerprint', fileID);\n },\n\n getPage: function PDFDocument_getPage(pageIndex) {\n return this.catalog.getPage(pageIndex);\n },\n\n cleanup: function PDFDocument_cleanup() {\n return this.catalog.cleanup();\n },\n };\n\n return PDFDocument;\n})();\n\nexport {\n Page,\n PDFDocument,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/document.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { bytesToString, FormatError, Util } from '../shared/util';\nimport { CFFParser } from './cff_parser';\nimport { getGlyphsUnicode } from './glyphlist';\nimport { StandardEncoding } from './encodings';\nimport { Stream } from './stream';\n\nvar FontRendererFactory = (function FontRendererFactoryClosure() {\n function getLong(data, offset) {\n return (data[offset] << 24) | (data[offset + 1] << 16) |\n (data[offset + 2] << 8) | data[offset + 3];\n }\n\n function getUshort(data, offset) {\n return (data[offset] << 8) | data[offset + 1];\n }\n\n function parseCmap(data, start, end) {\n var offset = (getUshort(data, start + 2) === 1 ?\n getLong(data, start + 8) : getLong(data, start + 16));\n var format = getUshort(data, start + offset);\n var ranges, p, i;\n if (format === 4) {\n getUshort(data, start + offset + 2); // length\n var segCount = getUshort(data, start + offset + 6) >> 1;\n p = start + offset + 14;\n ranges = [];\n for (i = 0; i < segCount; i++, p += 2) {\n ranges[i] = { end: getUshort(data, p), };\n }\n p += 2;\n for (i = 0; i < segCount; i++, p += 2) {\n ranges[i].start = getUshort(data, p);\n }\n for (i = 0; i < segCount; i++, p += 2) {\n ranges[i].idDelta = getUshort(data, p);\n }\n for (i = 0; i < segCount; i++, p += 2) {\n var idOffset = getUshort(data, p);\n if (idOffset === 0) {\n continue;\n }\n ranges[i].ids = [];\n for (var j = 0, jj = ranges[i].end - ranges[i].start + 1; j < jj; j++) {\n ranges[i].ids[j] = getUshort(data, p + idOffset);\n idOffset += 2;\n }\n }\n return ranges;\n } else if (format === 12) {\n getLong(data, start + offset + 4); // length\n var groups = getLong(data, start + offset + 12);\n p = start + offset + 16;\n ranges = [];\n for (i = 0; i < groups; i++) {\n ranges.push({\n start: getLong(data, p),\n end: getLong(data, p + 4),\n idDelta: getLong(data, p + 8) - getLong(data, p),\n });\n p += 12;\n }\n return ranges;\n }\n throw new FormatError(`unsupported cmap: ${format}`);\n }\n\n function parseCff(data, start, end, seacAnalysisEnabled) {\n var properties = {};\n var parser = new CFFParser(new Stream(data, start, end - start),\n properties, seacAnalysisEnabled);\n var cff = parser.parse();\n return {\n glyphs: cff.charStrings.objects,\n subrs: (cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex &&\n cff.topDict.privateDict.subrsIndex.objects),\n gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects,\n };\n }\n\n function parseGlyfTable(glyf, loca, isGlyphLocationsLong) {\n var itemSize, itemDecode;\n if (isGlyphLocationsLong) {\n itemSize = 4;\n itemDecode = function fontItemDecodeLong(data, offset) {\n return (data[offset] << 24) | (data[offset + 1] << 16) |\n (data[offset + 2] << 8) | data[offset + 3];\n };\n } else {\n itemSize = 2;\n itemDecode = function fontItemDecode(data, offset) {\n return (data[offset] << 9) | (data[offset + 1] << 1);\n };\n }\n var glyphs = [];\n var startOffset = itemDecode(loca, 0);\n for (var j = itemSize; j < loca.length; j += itemSize) {\n var endOffset = itemDecode(loca, j);\n glyphs.push(glyf.subarray(startOffset, endOffset));\n startOffset = endOffset;\n }\n return glyphs;\n }\n\n function lookupCmap(ranges, unicode) {\n var code = unicode.charCodeAt(0), gid = 0;\n var l = 0, r = ranges.length - 1;\n while (l < r) {\n var c = (l + r + 1) >> 1;\n if (code < ranges[c].start) {\n r = c - 1;\n } else {\n l = c;\n }\n }\n if (ranges[l].start <= code && code <= ranges[l].end) {\n gid = (ranges[l].idDelta + (ranges[l].ids ?\n ranges[l].ids[code - ranges[l].start] : code)) & 0xFFFF;\n }\n return {\n charCode: code,\n glyphId: gid,\n };\n }\n\n function compileGlyf(code, cmds, font) {\n function moveTo(x, y) {\n cmds.push({ cmd: 'moveTo', args: [x, y], });\n }\n function lineTo(x, y) {\n cmds.push({ cmd: 'lineTo', args: [x, y], });\n }\n function quadraticCurveTo(xa, ya, x, y) {\n cmds.push({ cmd: 'quadraticCurveTo', args: [xa, ya, x, y], });\n }\n\n var i = 0;\n var numberOfContours = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;\n var flags;\n var x = 0, y = 0;\n i += 10;\n if (numberOfContours < 0) {\n // composite glyph\n do {\n flags = (code[i] << 8) | code[i + 1];\n var glyphIndex = (code[i + 2] << 8) | code[i + 3];\n i += 4;\n var arg1, arg2;\n if ((flags & 0x01)) {\n arg1 = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;\n arg2 = ((code[i + 2] << 24) | (code[i + 3] << 16)) >> 16;\n i += 4;\n } else {\n arg1 = code[i++]; arg2 = code[i++];\n }\n if ((flags & 0x02)) {\n x = arg1;\n y = arg2;\n } else {\n x = 0; y = 0; // TODO \"they are points\" ?\n }\n var scaleX = 1, scaleY = 1, scale01 = 0, scale10 = 0;\n if ((flags & 0x08)) {\n scaleX =\n scaleY = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;\n i += 2;\n } else if ((flags & 0x40)) {\n scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;\n scaleY = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824;\n i += 4;\n } else if ((flags & 0x80)) {\n scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;\n scale01 = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824;\n scale10 = ((code[i + 4] << 24) | (code[i + 5] << 16)) / 1073741824;\n scaleY = ((code[i + 6] << 24) | (code[i + 7] << 16)) / 1073741824;\n i += 8;\n }\n var subglyph = font.glyphs[glyphIndex];\n if (subglyph) {\n cmds.push({ cmd: 'save', });\n cmds.push({ cmd: 'transform',\n args: [scaleX, scale01, scale10, scaleY, x, y], });\n compileGlyf(subglyph, cmds, font);\n cmds.push({ cmd: 'restore', });\n }\n } while ((flags & 0x20));\n } else {\n // simple glyph\n var endPtsOfContours = [];\n var j, jj;\n for (j = 0; j < numberOfContours; j++) {\n endPtsOfContours.push((code[i] << 8) | code[i + 1]);\n i += 2;\n }\n var instructionLength = (code[i] << 8) | code[i + 1];\n i += 2 + instructionLength; // skipping the instructions\n var numberOfPoints = endPtsOfContours[endPtsOfContours.length - 1] + 1;\n var points = [];\n while (points.length < numberOfPoints) {\n flags = code[i++];\n var repeat = 1;\n if ((flags & 0x08)) {\n repeat += code[i++];\n }\n while (repeat-- > 0) {\n points.push({ flags, });\n }\n }\n for (j = 0; j < numberOfPoints; j++) {\n switch (points[j].flags & 0x12) {\n case 0x00:\n x += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;\n i += 2;\n break;\n case 0x02:\n x -= code[i++];\n break;\n case 0x12:\n x += code[i++];\n break;\n }\n points[j].x = x;\n }\n for (j = 0; j < numberOfPoints; j++) {\n switch (points[j].flags & 0x24) {\n case 0x00:\n y += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;\n i += 2;\n break;\n case 0x04:\n y -= code[i++];\n break;\n case 0x24:\n y += code[i++];\n break;\n }\n points[j].y = y;\n }\n\n var startPoint = 0;\n for (i = 0; i < numberOfContours; i++) {\n var endPoint = endPtsOfContours[i];\n // contours might have implicit points, which is located in the middle\n // between two neighboring off-curve points\n var contour = points.slice(startPoint, endPoint + 1);\n if ((contour[0].flags & 1)) {\n contour.push(contour[0]); // using start point at the contour end\n } else if ((contour[contour.length - 1].flags & 1)) {\n // first is off-curve point, trying to use one from the end\n contour.unshift(contour[contour.length - 1]);\n } else {\n // start and end are off-curve points, creating implicit one\n var p = {\n flags: 1,\n x: (contour[0].x + contour[contour.length - 1].x) / 2,\n y: (contour[0].y + contour[contour.length - 1].y) / 2,\n };\n contour.unshift(p);\n contour.push(p);\n }\n moveTo(contour[0].x, contour[0].y);\n for (j = 1, jj = contour.length; j < jj; j++) {\n if ((contour[j].flags & 1)) {\n lineTo(contour[j].x, contour[j].y);\n } else if ((contour[j + 1].flags & 1)) {\n quadraticCurveTo(contour[j].x, contour[j].y,\n contour[j + 1].x, contour[j + 1].y);\n j++;\n } else {\n quadraticCurveTo(contour[j].x, contour[j].y,\n (contour[j].x + contour[j + 1].x) / 2,\n (contour[j].y + contour[j + 1].y) / 2);\n }\n }\n startPoint = endPoint + 1;\n }\n }\n }\n\n function compileCharString(code, cmds, font) {\n var stack = [];\n var x = 0, y = 0;\n var stems = 0;\n\n function moveTo(x, y) {\n cmds.push({ cmd: 'moveTo', args: [x, y], });\n }\n function lineTo(x, y) {\n cmds.push({ cmd: 'lineTo', args: [x, y], });\n }\n function bezierCurveTo(x1, y1, x2, y2, x, y) {\n cmds.push({ cmd: 'bezierCurveTo', args: [x1, y1, x2, y2, x, y], });\n }\n\n function parse(code) {\n var i = 0;\n while (i < code.length) {\n var stackClean = false;\n var v = code[i++];\n var xa, xb, ya, yb, y1, y2, y3, n, subrCode;\n switch (v) {\n case 1: // hstem\n stems += stack.length >> 1;\n stackClean = true;\n break;\n case 3: // vstem\n stems += stack.length >> 1;\n stackClean = true;\n break;\n case 4: // vmoveto\n y += stack.pop();\n moveTo(x, y);\n stackClean = true;\n break;\n case 5: // rlineto\n while (stack.length > 0) {\n x += stack.shift();\n y += stack.shift();\n lineTo(x, y);\n }\n break;\n case 6: // hlineto\n while (stack.length > 0) {\n x += stack.shift();\n lineTo(x, y);\n if (stack.length === 0) {\n break;\n }\n y += stack.shift();\n lineTo(x, y);\n }\n break;\n case 7: // vlineto\n while (stack.length > 0) {\n y += stack.shift();\n lineTo(x, y);\n if (stack.length === 0) {\n break;\n }\n x += stack.shift();\n lineTo(x, y);\n }\n break;\n case 8: // rrcurveto\n while (stack.length > 0) {\n xa = x + stack.shift(); ya = y + stack.shift();\n xb = xa + stack.shift(); yb = ya + stack.shift();\n x = xb + stack.shift(); y = yb + stack.shift();\n bezierCurveTo(xa, ya, xb, yb, x, y);\n }\n break;\n case 10: // callsubr\n n = stack.pop() + font.subrsBias;\n subrCode = font.subrs[n];\n if (subrCode) {\n parse(subrCode);\n }\n break;\n case 11: // return\n return;\n case 12:\n v = code[i++];\n switch (v) {\n case 34: // flex\n xa = x + stack.shift();\n xb = xa + stack.shift(); y1 = y + stack.shift();\n x = xb + stack.shift();\n bezierCurveTo(xa, y, xb, y1, x, y1);\n xa = x + stack.shift();\n xb = xa + stack.shift();\n x = xb + stack.shift();\n bezierCurveTo(xa, y1, xb, y, x, y);\n break;\n case 35: // flex\n xa = x + stack.shift(); ya = y + stack.shift();\n xb = xa + stack.shift(); yb = ya + stack.shift();\n x = xb + stack.shift(); y = yb + stack.shift();\n bezierCurveTo(xa, ya, xb, yb, x, y);\n xa = x + stack.shift(); ya = y + stack.shift();\n xb = xa + stack.shift(); yb = ya + stack.shift();\n x = xb + stack.shift(); y = yb + stack.shift();\n bezierCurveTo(xa, ya, xb, yb, x, y);\n stack.pop(); // fd\n break;\n case 36: // hflex1\n xa = x + stack.shift(); y1 = y + stack.shift();\n xb = xa + stack.shift(); y2 = y1 + stack.shift();\n x = xb + stack.shift();\n bezierCurveTo(xa, y1, xb, y2, x, y2);\n xa = x + stack.shift();\n xb = xa + stack.shift(); y3 = y2 + stack.shift();\n x = xb + stack.shift();\n bezierCurveTo(xa, y2, xb, y3, x, y);\n break;\n case 37: // flex1\n var x0 = x, y0 = y;\n xa = x + stack.shift(); ya = y + stack.shift();\n xb = xa + stack.shift(); yb = ya + stack.shift();\n x = xb + stack.shift(); y = yb + stack.shift();\n bezierCurveTo(xa, ya, xb, yb, x, y);\n xa = x + stack.shift(); ya = y + stack.shift();\n xb = xa + stack.shift(); yb = ya + stack.shift();\n x = xb; y = yb;\n if (Math.abs(x - x0) > Math.abs(y - y0)) {\n x += stack.shift();\n } else {\n y += stack.shift();\n }\n bezierCurveTo(xa, ya, xb, yb, x, y);\n break;\n default:\n throw new FormatError(`unknown operator: 12 ${v}`);\n }\n break;\n case 14: // endchar\n if (stack.length >= 4) {\n var achar = stack.pop();\n var bchar = stack.pop();\n y = stack.pop();\n x = stack.pop();\n cmds.push({ cmd: 'save', });\n cmds.push({ cmd: 'translate', args: [x, y], });\n var cmap = lookupCmap(font.cmap, String.fromCharCode(\n font.glyphNameMap[StandardEncoding[achar]]));\n compileCharString(font.glyphs[cmap.glyphId], cmds, font);\n cmds.push({ cmd: 'restore', });\n\n cmap = lookupCmap(font.cmap, String.fromCharCode(\n font.glyphNameMap[StandardEncoding[bchar]]));\n compileCharString(font.glyphs[cmap.glyphId], cmds, font);\n }\n return;\n case 18: // hstemhm\n stems += stack.length >> 1;\n stackClean = true;\n break;\n case 19: // hintmask\n stems += stack.length >> 1;\n i += (stems + 7) >> 3;\n stackClean = true;\n break;\n case 20: // cntrmask\n stems += stack.length >> 1;\n i += (stems + 7) >> 3;\n stackClean = true;\n break;\n case 21: // rmoveto\n y += stack.pop();\n x += stack.pop();\n moveTo(x, y);\n stackClean = true;\n break;\n case 22: // hmoveto\n x += stack.pop();\n moveTo(x, y);\n stackClean = true;\n break;\n case 23: // vstemhm\n stems += stack.length >> 1;\n stackClean = true;\n break;\n case 24: // rcurveline\n while (stack.length > 2) {\n xa = x + stack.shift(); ya = y + stack.shift();\n xb = xa + stack.shift(); yb = ya + stack.shift();\n x = xb + stack.shift(); y = yb + stack.shift();\n bezierCurveTo(xa, ya, xb, yb, x, y);\n }\n x += stack.shift();\n y += stack.shift();\n lineTo(x, y);\n break;\n case 25: // rlinecurve\n while (stack.length > 6) {\n x += stack.shift();\n y += stack.shift();\n lineTo(x, y);\n }\n xa = x + stack.shift(); ya = y + stack.shift();\n xb = xa + stack.shift(); yb = ya + stack.shift();\n x = xb + stack.shift(); y = yb + stack.shift();\n bezierCurveTo(xa, ya, xb, yb, x, y);\n break;\n case 26: // vvcurveto\n if (stack.length % 2) {\n x += stack.shift();\n }\n while (stack.length > 0) {\n xa = x; ya = y + stack.shift();\n xb = xa + stack.shift(); yb = ya + stack.shift();\n x = xb; y = yb + stack.shift();\n bezierCurveTo(xa, ya, xb, yb, x, y);\n }\n break;\n case 27: // hhcurveto\n if (stack.length % 2) {\n y += stack.shift();\n }\n while (stack.length > 0) {\n xa = x + stack.shift(); ya = y;\n xb = xa + stack.shift(); yb = ya + stack.shift();\n x = xb + stack.shift(); y = yb;\n bezierCurveTo(xa, ya, xb, yb, x, y);\n }\n break;\n case 28:\n stack.push(((code[i] << 24) | (code[i + 1] << 16)) >> 16);\n i += 2;\n break;\n case 29: // callgsubr\n n = stack.pop() + font.gsubrsBias;\n subrCode = font.gsubrs[n];\n if (subrCode) {\n parse(subrCode);\n }\n break;\n case 30: // vhcurveto\n while (stack.length > 0) {\n xa = x; ya = y + stack.shift();\n xb = xa + stack.shift(); yb = ya + stack.shift();\n x = xb + stack.shift();\n y = yb + (stack.length === 1 ? stack.shift() : 0);\n bezierCurveTo(xa, ya, xb, yb, x, y);\n if (stack.length === 0) {\n break;\n }\n\n xa = x + stack.shift(); ya = y;\n xb = xa + stack.shift(); yb = ya + stack.shift();\n y = yb + stack.shift();\n x = xb + (stack.length === 1 ? stack.shift() : 0);\n bezierCurveTo(xa, ya, xb, yb, x, y);\n }\n break;\n case 31: // hvcurveto\n while (stack.length > 0) {\n xa = x + stack.shift(); ya = y;\n xb = xa + stack.shift(); yb = ya + stack.shift();\n y = yb + stack.shift();\n x = xb + (stack.length === 1 ? stack.shift() : 0);\n bezierCurveTo(xa, ya, xb, yb, x, y);\n if (stack.length === 0) {\n break;\n }\n\n xa = x; ya = y + stack.shift();\n xb = xa + stack.shift(); yb = ya + stack.shift();\n x = xb + stack.shift();\n y = yb + (stack.length === 1 ? stack.shift() : 0);\n bezierCurveTo(xa, ya, xb, yb, x, y);\n }\n break;\n default:\n if (v < 32) {\n throw new FormatError(`unknown operator: ${v}`);\n }\n if (v < 247) {\n stack.push(v - 139);\n } else if (v < 251) {\n stack.push((v - 247) * 256 + code[i++] + 108);\n } else if (v < 255) {\n stack.push(-(v - 251) * 256 - code[i++] - 108);\n } else {\n stack.push(((code[i] << 24) | (code[i + 1] << 16) |\n (code[i + 2] << 8) | code[i + 3]) / 65536);\n i += 4;\n }\n break;\n }\n if (stackClean) {\n stack.length = 0;\n }\n }\n }\n parse(code);\n }\n\n var noop = '';\n\n function CompiledFont(fontMatrix) {\n this.compiledGlyphs = Object.create(null);\n this.compiledCharCodeToGlyphId = Object.create(null);\n this.fontMatrix = fontMatrix;\n }\n CompiledFont.prototype = {\n getPathJs(unicode) {\n var cmap = lookupCmap(this.cmap, unicode);\n var fn = this.compiledGlyphs[cmap.glyphId];\n if (!fn) {\n fn = this.compileGlyph(this.glyphs[cmap.glyphId]);\n this.compiledGlyphs[cmap.glyphId] = fn;\n }\n if (this.compiledCharCodeToGlyphId[cmap.charCode] === undefined) {\n this.compiledCharCodeToGlyphId[cmap.charCode] = cmap.glyphId;\n }\n return fn;\n },\n\n compileGlyph(code) {\n if (!code || code.length === 0 || code[0] === 14) {\n return noop;\n }\n\n var cmds = [];\n cmds.push({ cmd: 'save', });\n cmds.push({ cmd: 'transform', args: this.fontMatrix.slice(), });\n cmds.push({ cmd: 'scale', args: ['size', '-size'], });\n\n this.compileGlyphImpl(code, cmds);\n\n cmds.push({ cmd: 'restore', });\n\n return cmds;\n },\n\n compileGlyphImpl() {\n throw new Error('Children classes should implement this.');\n },\n\n hasBuiltPath(unicode) {\n var cmap = lookupCmap(this.cmap, unicode);\n return (this.compiledGlyphs[cmap.glyphId] !== undefined &&\n this.compiledCharCodeToGlyphId[cmap.charCode] !== undefined);\n },\n };\n\n function TrueTypeCompiled(glyphs, cmap, fontMatrix) {\n fontMatrix = fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0];\n CompiledFont.call(this, fontMatrix);\n\n this.glyphs = glyphs;\n this.cmap = cmap;\n }\n\n Util.inherit(TrueTypeCompiled, CompiledFont, {\n compileGlyphImpl(code, cmds) {\n compileGlyf(code, cmds, this);\n },\n });\n\n function Type2Compiled(cffInfo, cmap, fontMatrix, glyphNameMap) {\n fontMatrix = fontMatrix || [0.001, 0, 0, 0.001, 0, 0];\n CompiledFont.call(this, fontMatrix);\n\n this.glyphs = cffInfo.glyphs;\n this.gsubrs = cffInfo.gsubrs || [];\n this.subrs = cffInfo.subrs || [];\n this.cmap = cmap;\n this.glyphNameMap = glyphNameMap || getGlyphsUnicode();\n\n this.gsubrsBias = (this.gsubrs.length < 1240 ?\n 107 : (this.gsubrs.length < 33900 ? 1131 : 32768));\n this.subrsBias = (this.subrs.length < 1240 ?\n 107 : (this.subrs.length < 33900 ? 1131 : 32768));\n }\n\n Util.inherit(Type2Compiled, CompiledFont, {\n compileGlyphImpl(code, cmds) {\n compileCharString(code, cmds, this);\n },\n });\n\n\n return {\n create: function FontRendererFactory_create(font, seacAnalysisEnabled) {\n var data = new Uint8Array(font.data);\n var cmap, glyf, loca, cff, indexToLocFormat, unitsPerEm;\n var numTables = getUshort(data, 4);\n for (var i = 0, p = 12; i < numTables; i++, p += 16) {\n var tag = bytesToString(data.subarray(p, p + 4));\n var offset = getLong(data, p + 8);\n var length = getLong(data, p + 12);\n switch (tag) {\n case 'cmap':\n cmap = parseCmap(data, offset, offset + length);\n break;\n case 'glyf':\n glyf = data.subarray(offset, offset + length);\n break;\n case 'loca':\n loca = data.subarray(offset, offset + length);\n break;\n case 'head':\n unitsPerEm = getUshort(data, offset + 18);\n indexToLocFormat = getUshort(data, offset + 50);\n break;\n case 'CFF ':\n cff = parseCff(data, offset, offset + length, seacAnalysisEnabled);\n break;\n }\n }\n\n if (glyf) {\n var fontMatrix = (!unitsPerEm ? font.fontMatrix :\n [1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0]);\n return new TrueTypeCompiled(\n parseGlyfTable(glyf, loca, indexToLocFormat), cmap, fontMatrix);\n }\n return new Type2Compiled(cff, cmap, font.fontMatrix, font.glyphNameMap);\n },\n };\n})();\n\nexport {\n FontRendererFactory,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/font_renderer.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n bytesToString, FONT_IDENTITY_MATRIX, FontType, FormatError, info, isArray,\n isInt, isNum, isSpace, MissingDataException, readUint32, shadow, string32,\n warn\n} from '../shared/util';\nimport {\n CFF, CFFCharset, CFFCompiler, CFFHeader, CFFIndex, CFFParser, CFFPrivateDict,\n CFFStandardStrings, CFFStrings, CFFTopDict\n} from './cff_parser';\nimport { getDingbatsGlyphsUnicode, getGlyphsUnicode } from './glyphlist';\nimport {\n getEncoding, MacRomanEncoding, StandardEncoding, SymbolSetEncoding,\n ZapfDingbatsEncoding\n} from './encodings';\nimport {\n getGlyphMapForStandardFonts, getNonStdFontMap, getStdFontMap,\n getSupplementalGlyphMapForArialBlack\n} from './standard_fonts';\nimport {\n getUnicodeForGlyph, getUnicodeRangeFor, mapSpecialUnicodeValues\n} from './unicode';\nimport { FontRendererFactory } from './font_renderer';\nimport { Stream } from './stream';\nimport { Type1Parser } from './type1_parser';\n\n// Unicode Private Use Area\nvar PRIVATE_USE_OFFSET_START = 0xE000;\nvar PRIVATE_USE_OFFSET_END = 0xF8FF;\nvar SKIP_PRIVATE_USE_RANGE_F000_TO_F01F = false;\n\n// PDF Glyph Space Units are one Thousandth of a TextSpace Unit\n// except for Type 3 fonts\nvar PDF_GLYPH_SPACE_UNITS = 1000;\n\n// Accented charactars are not displayed properly on Windows, using this flag\n// to control analysis of seac charstrings.\nvar SEAC_ANALYSIS_ENABLED = false;\n\nvar FontFlags = {\n FixedPitch: 1,\n Serif: 2,\n Symbolic: 4,\n Script: 8,\n Nonsymbolic: 32,\n Italic: 64,\n AllCap: 65536,\n SmallCap: 131072,\n ForceBold: 262144,\n};\n\nvar MacStandardGlyphOrdering = [\n '.notdef', '.null', 'nonmarkingreturn', 'space', 'exclam', 'quotedbl',\n 'numbersign', 'dollar', 'percent', 'ampersand', 'quotesingle', 'parenleft',\n 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash',\n 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',\n 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at',\n 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',\n 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft',\n 'backslash', 'bracketright', 'asciicircum', 'underscore', 'grave', 'a', 'b',\n 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',\n 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright',\n 'asciitilde', 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde',\n 'Odieresis', 'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis',\n 'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis',\n 'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute', 'ograve',\n 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave', 'ucircumflex',\n 'udieresis', 'dagger', 'degree', 'cent', 'sterling', 'section', 'bullet',\n 'paragraph', 'germandbls', 'registered', 'copyright', 'trademark', 'acute',\n 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity', 'plusminus', 'lessequal',\n 'greaterequal', 'yen', 'mu', 'partialdiff', 'summation', 'product', 'pi',\n 'integral', 'ordfeminine', 'ordmasculine', 'Omega', 'ae', 'oslash',\n 'questiondown', 'exclamdown', 'logicalnot', 'radical', 'florin',\n 'approxequal', 'Delta', 'guillemotleft', 'guillemotright', 'ellipsis',\n 'nonbreakingspace', 'Agrave', 'Atilde', 'Otilde', 'OE', 'oe', 'endash',\n 'emdash', 'quotedblleft', 'quotedblright', 'quoteleft', 'quoteright',\n 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction', 'currency',\n 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl', 'periodcentered',\n 'quotesinglbase', 'quotedblbase', 'perthousand', 'Acircumflex',\n 'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex',\n 'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple', 'Ograve', 'Uacute',\n 'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex', 'tilde', 'macron',\n 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron',\n 'Lslash', 'lslash', 'Scaron', 'scaron', 'Zcaron', 'zcaron', 'brokenbar',\n 'Eth', 'eth', 'Yacute', 'yacute', 'Thorn', 'thorn', 'minus', 'multiply',\n 'onesuperior', 'twosuperior', 'threesuperior', 'onehalf', 'onequarter',\n 'threequarters', 'franc', 'Gbreve', 'gbreve', 'Idotaccent', 'Scedilla',\n 'scedilla', 'Cacute', 'cacute', 'Ccaron', 'ccaron', 'dcroat'];\n\nfunction adjustWidths(properties) {\n if (!properties.fontMatrix) {\n return;\n }\n if (properties.fontMatrix[0] === FONT_IDENTITY_MATRIX[0]) {\n return;\n }\n // adjusting width to fontMatrix scale\n var scale = 0.001 / properties.fontMatrix[0];\n var glyphsWidths = properties.widths;\n for (var glyph in glyphsWidths) {\n glyphsWidths[glyph] *= scale;\n }\n properties.defaultWidth *= scale;\n}\n\nfunction adjustToUnicode(properties, builtInEncoding) {\n if (properties.hasIncludedToUnicodeMap) {\n return; // The font dictionary has a `ToUnicode` entry.\n }\n if (properties.hasEncoding) {\n return; // The font dictionary has an `Encoding` entry.\n }\n if (builtInEncoding === properties.defaultEncoding) {\n return; // No point in trying to adjust `toUnicode` if the encodings match.\n }\n if (properties.toUnicode instanceof IdentityToUnicodeMap) {\n return;\n }\n var toUnicode = [], glyphsUnicodeMap = getGlyphsUnicode();\n for (var charCode in builtInEncoding) {\n var glyphName = builtInEncoding[charCode];\n var unicode = getUnicodeForGlyph(glyphName, glyphsUnicodeMap);\n if (unicode !== -1) {\n toUnicode[charCode] = String.fromCharCode(unicode);\n }\n }\n properties.toUnicode.amend(toUnicode);\n}\n\nfunction getFontType(type, subtype) {\n switch (type) {\n case 'Type1':\n return subtype === 'Type1C' ? FontType.TYPE1C : FontType.TYPE1;\n case 'CIDFontType0':\n return subtype === 'CIDFontType0C' ? FontType.CIDFONTTYPE0C :\n FontType.CIDFONTTYPE0;\n case 'OpenType':\n return FontType.OPENTYPE;\n case 'TrueType':\n return FontType.TRUETYPE;\n case 'CIDFontType2':\n return FontType.CIDFONTTYPE2;\n case 'MMType1':\n return FontType.MMTYPE1;\n case 'Type0':\n return FontType.TYPE0;\n default:\n return FontType.UNKNOWN;\n }\n}\n\n// Some bad PDF generators, e.g. Scribus PDF, include glyph names\n// in a 'uniXXXX' format -- attempting to recover proper ones.\nfunction recoverGlyphName(name, glyphsUnicodeMap) {\n if (glyphsUnicodeMap[name] !== undefined) {\n return name;\n }\n // The glyph name is non-standard, trying to recover.\n var unicode = getUnicodeForGlyph(name, glyphsUnicodeMap);\n if (unicode !== -1) {\n for (var key in glyphsUnicodeMap) {\n if (glyphsUnicodeMap[key] === unicode) {\n return key;\n }\n }\n }\n info('Unable to recover a standard glyph name for: ' + name);\n return name;\n}\n\nvar Glyph = (function GlyphClosure() {\n function Glyph(fontChar, unicode, accent, width, vmetric, operatorListId,\n isSpace, isInFont) {\n this.fontChar = fontChar;\n this.unicode = unicode;\n this.accent = accent;\n this.width = width;\n this.vmetric = vmetric;\n this.operatorListId = operatorListId;\n this.isSpace = isSpace;\n this.isInFont = isInFont;\n }\n\n Glyph.prototype.matchesForCache = function(fontChar, unicode, accent, width,\n vmetric, operatorListId, isSpace,\n isInFont) {\n return this.fontChar === fontChar &&\n this.unicode === unicode &&\n this.accent === accent &&\n this.width === width &&\n this.vmetric === vmetric &&\n this.operatorListId === operatorListId &&\n this.isSpace === isSpace &&\n this.isInFont === isInFont;\n };\n\n return Glyph;\n})();\n\nvar ToUnicodeMap = (function ToUnicodeMapClosure() {\n function ToUnicodeMap(cmap) {\n // The elements of this._map can be integers or strings, depending on how\n // |cmap| was created.\n this._map = cmap;\n }\n\n ToUnicodeMap.prototype = {\n get length() {\n return this._map.length;\n },\n\n forEach(callback) {\n for (var charCode in this._map) {\n callback(charCode, this._map[charCode].charCodeAt(0));\n }\n },\n\n has(i) {\n return this._map[i] !== undefined;\n },\n\n get(i) {\n return this._map[i];\n },\n\n charCodeOf(value) {\n // `Array.prototype.indexOf` is *extremely* inefficient for arrays which\n // are both very sparse and very large (see issue8372.pdf).\n let map = this._map;\n if (map.length <= 0x10000) {\n return map.indexOf(value);\n }\n for (let charCode in map) {\n if (map[charCode] === value) {\n return (charCode | 0);\n }\n }\n return -1;\n },\n\n amend(map) {\n for (var charCode in map) {\n this._map[charCode] = map[charCode];\n }\n },\n };\n\n return ToUnicodeMap;\n})();\n\nvar IdentityToUnicodeMap = (function IdentityToUnicodeMapClosure() {\n function IdentityToUnicodeMap(firstChar, lastChar) {\n this.firstChar = firstChar;\n this.lastChar = lastChar;\n }\n\n IdentityToUnicodeMap.prototype = {\n get length() {\n return (this.lastChar + 1) - this.firstChar;\n },\n\n forEach(callback) {\n for (var i = this.firstChar, ii = this.lastChar; i <= ii; i++) {\n callback(i, i);\n }\n },\n\n has(i) {\n return this.firstChar <= i && i <= this.lastChar;\n },\n\n get(i) {\n if (this.firstChar <= i && i <= this.lastChar) {\n return String.fromCharCode(i);\n }\n return undefined;\n },\n\n charCodeOf(v) {\n return (isInt(v) && v >= this.firstChar && v <= this.lastChar) ? v : -1;\n },\n\n amend(map) {\n throw new Error('Should not call amend()');\n },\n };\n\n return IdentityToUnicodeMap;\n})();\n\nvar OpenTypeFileBuilder = (function OpenTypeFileBuilderClosure() {\n function writeInt16(dest, offset, num) {\n dest[offset] = (num >> 8) & 0xFF;\n dest[offset + 1] = num & 0xFF;\n }\n\n function writeInt32(dest, offset, num) {\n dest[offset] = (num >> 24) & 0xFF;\n dest[offset + 1] = (num >> 16) & 0xFF;\n dest[offset + 2] = (num >> 8) & 0xFF;\n dest[offset + 3] = num & 0xFF;\n }\n\n function writeData(dest, offset, data) {\n var i, ii;\n if (data instanceof Uint8Array) {\n dest.set(data, offset);\n } else if (typeof data === 'string') {\n for (i = 0, ii = data.length; i < ii; i++) {\n dest[offset++] = data.charCodeAt(i) & 0xFF;\n }\n } else {\n // treating everything else as array\n for (i = 0, ii = data.length; i < ii; i++) {\n dest[offset++] = data[i] & 0xFF;\n }\n }\n }\n\n function OpenTypeFileBuilder(sfnt) {\n this.sfnt = sfnt;\n this.tables = Object.create(null);\n }\n\n OpenTypeFileBuilder.getSearchParams =\n function OpenTypeFileBuilder_getSearchParams(entriesCount, entrySize) {\n var maxPower2 = 1, log2 = 0;\n while ((maxPower2 ^ entriesCount) > maxPower2) {\n maxPower2 <<= 1;\n log2++;\n }\n var searchRange = maxPower2 * entrySize;\n return {\n range: searchRange,\n entry: log2,\n rangeShift: entrySize * entriesCount - searchRange,\n };\n };\n\n var OTF_HEADER_SIZE = 12;\n var OTF_TABLE_ENTRY_SIZE = 16;\n\n OpenTypeFileBuilder.prototype = {\n toArray: function OpenTypeFileBuilder_toArray() {\n var sfnt = this.sfnt;\n\n // Tables needs to be written by ascendant alphabetic order\n var tables = this.tables;\n var tablesNames = Object.keys(tables);\n tablesNames.sort();\n var numTables = tablesNames.length;\n\n var i, j, jj, table, tableName;\n // layout the tables data\n var offset = OTF_HEADER_SIZE + numTables * OTF_TABLE_ENTRY_SIZE;\n var tableOffsets = [offset];\n for (i = 0; i < numTables; i++) {\n table = tables[tablesNames[i]];\n var paddedLength = ((table.length + 3) & ~3) >>> 0;\n offset += paddedLength;\n tableOffsets.push(offset);\n }\n\n var file = new Uint8Array(offset);\n // write the table data first (mostly for checksum)\n for (i = 0; i < numTables; i++) {\n table = tables[tablesNames[i]];\n writeData(file, tableOffsets[i], table);\n }\n\n // sfnt version (4 bytes)\n if (sfnt === 'true') {\n // Windows hates the Mac TrueType sfnt version number\n sfnt = string32(0x00010000);\n }\n file[0] = sfnt.charCodeAt(0) & 0xFF;\n file[1] = sfnt.charCodeAt(1) & 0xFF;\n file[2] = sfnt.charCodeAt(2) & 0xFF;\n file[3] = sfnt.charCodeAt(3) & 0xFF;\n\n // numTables (2 bytes)\n writeInt16(file, 4, numTables);\n\n var searchParams = OpenTypeFileBuilder.getSearchParams(numTables, 16);\n\n // searchRange (2 bytes)\n writeInt16(file, 6, searchParams.range);\n // entrySelector (2 bytes)\n writeInt16(file, 8, searchParams.entry);\n // rangeShift (2 bytes)\n writeInt16(file, 10, searchParams.rangeShift);\n\n offset = OTF_HEADER_SIZE;\n // writing table entries\n for (i = 0; i < numTables; i++) {\n tableName = tablesNames[i];\n file[offset] = tableName.charCodeAt(0) & 0xFF;\n file[offset + 1] = tableName.charCodeAt(1) & 0xFF;\n file[offset + 2] = tableName.charCodeAt(2) & 0xFF;\n file[offset + 3] = tableName.charCodeAt(3) & 0xFF;\n\n // checksum\n var checksum = 0;\n for (j = tableOffsets[i], jj = tableOffsets[i + 1]; j < jj; j += 4) {\n var quad = readUint32(file, j);\n checksum = (checksum + quad) >>> 0;\n }\n writeInt32(file, offset + 4, checksum);\n\n // offset\n writeInt32(file, offset + 8, tableOffsets[i]);\n // length\n writeInt32(file, offset + 12, tables[tableName].length);\n\n offset += OTF_TABLE_ENTRY_SIZE;\n }\n return file;\n },\n\n addTable: function OpenTypeFileBuilder_addTable(tag, data) {\n if (tag in this.tables) {\n throw new Error('Table ' + tag + ' already exists');\n }\n this.tables[tag] = data;\n },\n };\n\n return OpenTypeFileBuilder;\n})();\n\n// Problematic Unicode characters in the fonts that needs to be moved to avoid\n// issues when they are painted on the canvas, e.g. complex-script shaping or\n// control/whitespace characters. The ranges are listed in pairs: the first item\n// is a code of the first problematic code, the second one is the next\n// non-problematic code. The ranges must be in sorted order.\nvar ProblematicCharRanges = new Int32Array([\n // Control characters.\n 0x0000, 0x0020,\n 0x007F, 0x00A1,\n 0x00AD, 0x00AE,\n // Chars that is used in complex-script shaping.\n 0x0600, 0x0780,\n 0x08A0, 0x10A0,\n 0x1780, 0x1800,\n 0x1C00, 0x1C50,\n // General punctuation chars.\n 0x2000, 0x2010,\n 0x2011, 0x2012,\n 0x2028, 0x2030,\n 0x205F, 0x2070,\n 0x25CC, 0x25CD,\n 0x3000, 0x3001,\n 0x3164, 0x3165,\n // Chars that is used in complex-script shaping.\n 0xAA60, 0xAA80,\n // Specials Unicode block.\n 0xFFF0, 0x10000\n]);\n\n/**\n * 'Font' is the class the outside world should use, it encapsulate all the font\n * decoding logics whatever type it is (assuming the font type is supported).\n *\n * For example to read a Type1 font and to attach it to the document:\n * var type1Font = new Font(\"MyFontName\", binaryFile, propertiesObject);\n * type1Font.bind();\n */\nvar Font = (function FontClosure() {\n function Font(name, file, properties) {\n var charCode;\n\n this.name = name;\n this.loadedName = properties.loadedName;\n this.isType3Font = properties.isType3Font;\n this.sizes = [];\n this.missingFile = false;\n\n this.glyphCache = Object.create(null);\n\n this.isSerifFont = !!(properties.flags & FontFlags.Serif);\n this.isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);\n this.isMonospace = !!(properties.flags & FontFlags.FixedPitch);\n\n var type = properties.type;\n var subtype = properties.subtype;\n this.type = type;\n this.subtype = subtype;\n\n this.fallbackName = (this.isMonospace ? 'monospace' :\n (this.isSerifFont ? 'serif' : 'sans-serif'));\n\n this.differences = properties.differences;\n this.widths = properties.widths;\n this.defaultWidth = properties.defaultWidth;\n this.composite = properties.composite;\n this.wideChars = properties.wideChars;\n this.cMap = properties.cMap;\n this.ascent = properties.ascent / PDF_GLYPH_SPACE_UNITS;\n this.descent = properties.descent / PDF_GLYPH_SPACE_UNITS;\n this.fontMatrix = properties.fontMatrix;\n this.bbox = properties.bbox;\n this.defaultEncoding = properties.defaultEncoding;\n\n this.toUnicode = properties.toUnicode;\n\n this.toFontChar = [];\n\n if (properties.type === 'Type3') {\n for (charCode = 0; charCode < 256; charCode++) {\n this.toFontChar[charCode] = (this.differences[charCode] ||\n properties.defaultEncoding[charCode]);\n }\n this.fontType = FontType.TYPE3;\n return;\n }\n\n this.cidEncoding = properties.cidEncoding;\n this.vertical = properties.vertical;\n if (this.vertical) {\n this.vmetrics = properties.vmetrics;\n this.defaultVMetrics = properties.defaultVMetrics;\n }\n\n if (!file || file.isEmpty) {\n if (file) {\n // Some bad PDF generators will include empty font files,\n // attempting to recover by assuming that no file exists.\n warn('Font file is empty in \"' + name + '\" (' + this.loadedName + ')');\n }\n this.fallbackToSystemFont();\n return;\n }\n\n // Some fonts might use wrong font types for Type1C or CIDFontType0C\n if (subtype === 'Type1C') {\n if (type !== 'Type1' && type !== 'MMType1') {\n // Some TrueType fonts by mistake claim Type1C\n if (isTrueTypeFile(file)) {\n subtype = 'TrueType';\n } else {\n type = 'Type1';\n }\n } else if (isOpenTypeFile(file)) {\n // Sometimes the type/subtype can be a complete lie (see issue7598.pdf).\n subtype = 'OpenType';\n }\n }\n if (subtype === 'CIDFontType0C' && type !== 'CIDFontType0') {\n type = 'CIDFontType0';\n }\n // Some CIDFontType0C fonts by mistake claim CIDFontType0.\n if (type === 'CIDFontType0') {\n if (isType1File(file)) {\n subtype = 'CIDFontType0';\n } else if (isOpenTypeFile(file)) {\n // Sometimes the type/subtype can be a complete lie (see issue6782.pdf).\n subtype = 'OpenType';\n } else {\n subtype = 'CIDFontType0C';\n }\n }\n if (subtype === 'OpenType' && type !== 'OpenType') {\n type = 'OpenType';\n }\n\n try {\n var data;\n switch (type) {\n case 'MMType1':\n info('MMType1 font (' + name + '), falling back to Type1.');\n /* falls through */\n case 'Type1':\n case 'CIDFontType0':\n this.mimetype = 'font/opentype';\n\n var cff = (subtype === 'Type1C' || subtype === 'CIDFontType0C') ?\n new CFFFont(file, properties) :\n new Type1Font(name, file, properties);\n\n adjustWidths(properties);\n\n // Wrap the CFF data inside an OTF font file\n data = this.convert(name, cff, properties);\n break;\n\n case 'OpenType':\n case 'TrueType':\n case 'CIDFontType2':\n this.mimetype = 'font/opentype';\n\n // Repair the TrueType file. It is can be damaged in the point of\n // view of the sanitizer\n data = this.checkAndRepair(name, file, properties);\n if (this.isOpenType) {\n adjustWidths(properties);\n\n type = 'OpenType';\n }\n break;\n\n default:\n throw new FormatError(`Font ${type} is not supported`);\n }\n } catch (e) {\n if (!(e instanceof FormatError)) {\n throw e;\n }\n warn(e);\n this.fallbackToSystemFont();\n return;\n }\n\n this.data = data;\n this.fontType = getFontType(type, subtype);\n\n // Transfer some properties again that could change during font conversion\n this.fontMatrix = properties.fontMatrix;\n this.widths = properties.widths;\n this.defaultWidth = properties.defaultWidth;\n this.toUnicode = properties.toUnicode;\n this.encoding = properties.baseEncoding;\n this.seacMap = properties.seacMap;\n\n this.loading = true;\n }\n\n Font.getFontID = (function () {\n var ID = 1;\n return function Font_getFontID() {\n return String(ID++);\n };\n })();\n\n function int16(b0, b1) {\n return (b0 << 8) + b1;\n }\n\n function signedInt16(b0, b1) {\n var value = (b0 << 8) + b1;\n return value & (1 << 15) ? value - 0x10000 : value;\n }\n\n function int32(b0, b1, b2, b3) {\n return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;\n }\n\n function string16(value) {\n return String.fromCharCode((value >> 8) & 0xff, value & 0xff);\n }\n\n function safeString16(value) {\n // clamp value to the 16-bit int range\n value = (value > 0x7FFF ? 0x7FFF : (value < -0x8000 ? -0x8000 : value));\n return String.fromCharCode((value >> 8) & 0xff, value & 0xff);\n }\n\n function isTrueTypeFile(file) {\n var header = file.peekBytes(4);\n return readUint32(header, 0) === 0x00010000;\n }\n\n function isOpenTypeFile(file) {\n var header = file.peekBytes(4);\n return bytesToString(header) === 'OTTO';\n }\n\n function isType1File(file) {\n var header = file.peekBytes(2);\n // All Type1 font programs must begin with the comment '%!' (0x25 + 0x21).\n if (header[0] === 0x25 && header[1] === 0x21) {\n return true;\n }\n // ... obviously some fonts violate that part of the specification,\n // please refer to the comment in |Type1Font| below.\n if (header[0] === 0x80 && header[1] === 0x01) { // pfb file header.\n return true;\n }\n return false;\n }\n\n function buildToFontChar(encoding, glyphsUnicodeMap, differences) {\n var toFontChar = [], unicode;\n for (var i = 0, ii = encoding.length; i < ii; i++) {\n unicode = getUnicodeForGlyph(encoding[i], glyphsUnicodeMap);\n if (unicode !== -1) {\n toFontChar[i] = unicode;\n }\n }\n for (var charCode in differences) {\n unicode = getUnicodeForGlyph(differences[charCode], glyphsUnicodeMap);\n if (unicode !== -1) {\n toFontChar[+charCode] = unicode;\n }\n }\n return toFontChar;\n }\n\n /**\n * Helper function for `adjustMapping`.\n * @return {boolean}\n */\n function isProblematicUnicodeLocation(code) {\n // Using binary search to find a range start.\n var i = 0, j = ProblematicCharRanges.length - 1;\n while (i < j) {\n var c = (i + j + 1) >> 1;\n if (code < ProblematicCharRanges[c]) {\n j = c - 1;\n } else {\n i = c;\n }\n }\n // Even index means code in problematic range.\n return !(i & 1);\n }\n\n /**\n * Rebuilds the char code to glyph ID map by trying to replace the char codes\n * with their unicode value. It also moves char codes that are in known\n * problematic locations.\n * @return {Object} Two properties:\n * 'toFontChar' - maps original char codes(the value that will be read\n * from commands such as show text) to the char codes that will be used in the\n * font that we build\n * 'charCodeToGlyphId' - maps the new font char codes to glyph ids\n */\n function adjustMapping(charCodeToGlyphId, properties, missingGlyphs) {\n var toUnicode = properties.toUnicode;\n var isSymbolic = !!(properties.flags & FontFlags.Symbolic);\n var isIdentityUnicode =\n properties.toUnicode instanceof IdentityToUnicodeMap;\n var newMap = Object.create(null);\n var toFontChar = [];\n var usedFontCharCodes = [];\n var nextAvailableFontCharCode = PRIVATE_USE_OFFSET_START;\n for (var originalCharCode in charCodeToGlyphId) {\n originalCharCode |= 0;\n var glyphId = charCodeToGlyphId[originalCharCode];\n // For missing glyphs don't create the mappings so the glyph isn't\n // drawn.\n if (missingGlyphs[glyphId]) {\n continue;\n }\n var fontCharCode = originalCharCode;\n // First try to map the value to a unicode position if a non identity map\n // was created.\n var hasUnicodeValue = false;\n if (!isIdentityUnicode && toUnicode.has(originalCharCode)) {\n hasUnicodeValue = true;\n var unicode = toUnicode.get(fontCharCode);\n // TODO: Try to map ligatures to the correct spot.\n if (unicode.length === 1) {\n fontCharCode = unicode.charCodeAt(0);\n }\n }\n // Try to move control characters, special characters and already mapped\n // characters to the private use area since they will not be drawn by\n // canvas if left in their current position. Also, move characters if the\n // font was symbolic and there is only an identity unicode map since the\n // characters probably aren't in the correct position (fixes an issue\n // with firefox and thuluthfont).\n if ((usedFontCharCodes[fontCharCode] !== undefined ||\n isProblematicUnicodeLocation(fontCharCode) ||\n (isSymbolic && !hasUnicodeValue))) {\n // Loop to try and find a free spot in the private use area.\n do {\n if (nextAvailableFontCharCode > PRIVATE_USE_OFFSET_END) {\n warn('Ran out of space in font private use area.');\n break;\n }\n fontCharCode = nextAvailableFontCharCode++;\n\n if (SKIP_PRIVATE_USE_RANGE_F000_TO_F01F && fontCharCode === 0xF000) {\n fontCharCode = 0xF020;\n nextAvailableFontCharCode = fontCharCode + 1;\n }\n\n } while (usedFontCharCodes[fontCharCode] !== undefined);\n }\n\n newMap[fontCharCode] = glyphId;\n toFontChar[originalCharCode] = fontCharCode;\n usedFontCharCodes[fontCharCode] = true;\n }\n return {\n toFontChar,\n charCodeToGlyphId: newMap,\n nextAvailableFontCharCode,\n };\n }\n\n function getRanges(glyphs, numGlyphs) {\n // Array.sort() sorts by characters, not numerically, so convert to an\n // array of characters.\n var codes = [];\n for (var charCode in glyphs) {\n // Remove an invalid glyph ID mappings to make OTS happy.\n if (glyphs[charCode] >= numGlyphs) {\n continue;\n }\n codes.push({ fontCharCode: charCode | 0, glyphId: glyphs[charCode], });\n }\n // Some fonts have zero glyphs and are used only for text selection, but\n // there needs to be at least one to build a valid cmap table.\n if (codes.length === 0) {\n codes.push({ fontCharCode: 0, glyphId: 0, });\n }\n codes.sort(function fontGetRangesSort(a, b) {\n return a.fontCharCode - b.fontCharCode;\n });\n\n // Split the sorted codes into ranges.\n var ranges = [];\n var length = codes.length;\n for (var n = 0; n < length; ) { // eslint-disable-line space-in-parens\n var start = codes[n].fontCharCode;\n var codeIndices = [codes[n].glyphId];\n ++n;\n var end = start;\n while (n < length && end + 1 === codes[n].fontCharCode) {\n codeIndices.push(codes[n].glyphId);\n ++end;\n ++n;\n if (end === 0xFFFF) {\n break;\n }\n }\n ranges.push([start, end, codeIndices]);\n }\n\n return ranges;\n }\n\n function createCmapTable(glyphs, numGlyphs) {\n var ranges = getRanges(glyphs, numGlyphs);\n var numTables = ranges[ranges.length - 1][1] > 0xFFFF ? 2 : 1;\n var cmap = '\\x00\\x00' + // version\n string16(numTables) + // numTables\n '\\x00\\x03' + // platformID\n '\\x00\\x01' + // encodingID\n string32(4 + numTables * 8); // start of the table record\n\n var i, ii, j, jj;\n for (i = ranges.length - 1; i >= 0; --i) {\n if (ranges[i][0] <= 0xFFFF) {\n break;\n }\n }\n var bmpLength = i + 1;\n\n if (ranges[i][0] < 0xFFFF && ranges[i][1] === 0xFFFF) {\n ranges[i][1] = 0xFFFE;\n }\n var trailingRangesCount = ranges[i][1] < 0xFFFF ? 1 : 0;\n var segCount = bmpLength + trailingRangesCount;\n var searchParams = OpenTypeFileBuilder.getSearchParams(segCount, 2);\n\n // Fill up the 4 parallel arrays describing the segments.\n var startCount = '';\n var endCount = '';\n var idDeltas = '';\n var idRangeOffsets = '';\n var glyphsIds = '';\n var bias = 0;\n\n var range, start, end, codes;\n for (i = 0, ii = bmpLength; i < ii; i++) {\n range = ranges[i];\n start = range[0];\n end = range[1];\n startCount += string16(start);\n endCount += string16(end);\n codes = range[2];\n var contiguous = true;\n for (j = 1, jj = codes.length; j < jj; ++j) {\n if (codes[j] !== codes[j - 1] + 1) {\n contiguous = false;\n break;\n }\n }\n if (!contiguous) {\n var offset = (segCount - i) * 2 + bias * 2;\n bias += (end - start + 1);\n\n idDeltas += string16(0);\n idRangeOffsets += string16(offset);\n\n for (j = 0, jj = codes.length; j < jj; ++j) {\n glyphsIds += string16(codes[j]);\n }\n } else {\n var startCode = codes[0];\n\n idDeltas += string16((startCode - start) & 0xFFFF);\n idRangeOffsets += string16(0);\n }\n }\n\n if (trailingRangesCount > 0) {\n endCount += '\\xFF\\xFF';\n startCount += '\\xFF\\xFF';\n idDeltas += '\\x00\\x01';\n idRangeOffsets += '\\x00\\x00';\n }\n\n var format314 = '\\x00\\x00' + // language\n string16(2 * segCount) +\n string16(searchParams.range) +\n string16(searchParams.entry) +\n string16(searchParams.rangeShift) +\n endCount + '\\x00\\x00' + startCount +\n idDeltas + idRangeOffsets + glyphsIds;\n\n var format31012 = '';\n var header31012 = '';\n if (numTables > 1) {\n cmap += '\\x00\\x03' + // platformID\n '\\x00\\x0A' + // encodingID\n string32(4 + numTables * 8 +\n 4 + format314.length); // start of the table record\n format31012 = '';\n for (i = 0, ii = ranges.length; i < ii; i++) {\n range = ranges[i];\n start = range[0];\n codes = range[2];\n var code = codes[0];\n for (j = 1, jj = codes.length; j < jj; ++j) {\n if (codes[j] !== codes[j - 1] + 1) {\n end = range[0] + j - 1;\n format31012 += string32(start) + // startCharCode\n string32(end) + // endCharCode\n string32(code); // startGlyphID\n start = end + 1;\n code = codes[j];\n }\n }\n format31012 += string32(start) + // startCharCode\n string32(range[1]) + // endCharCode\n string32(code); // startGlyphID\n }\n header31012 = '\\x00\\x0C' + // format\n '\\x00\\x00' + // reserved\n string32(format31012.length + 16) + // length\n '\\x00\\x00\\x00\\x00' + // language\n string32(format31012.length / 12); // nGroups\n }\n\n return cmap + '\\x00\\x04' + // format\n string16(format314.length + 4) + // length\n format314 + header31012 + format31012;\n }\n\n function validateOS2Table(os2) {\n var stream = new Stream(os2.data);\n var version = stream.getUint16();\n // TODO verify all OS/2 tables fields, but currently we validate only those\n // that give us issues\n stream.getBytes(60); // skipping type, misc sizes, panose, unicode ranges\n var selection = stream.getUint16();\n if (version < 4 && (selection & 0x0300)) {\n return false;\n }\n var firstChar = stream.getUint16();\n var lastChar = stream.getUint16();\n if (firstChar > lastChar) {\n return false;\n }\n stream.getBytes(6); // skipping sTypoAscender/Descender/LineGap\n var usWinAscent = stream.getUint16();\n if (usWinAscent === 0) { // makes font unreadable by windows\n return false;\n }\n\n // OS/2 appears to be valid, resetting some fields\n os2.data[8] = os2.data[9] = 0; // IE rejects fonts if fsType != 0\n return true;\n }\n\n function createOS2Table(properties, charstrings, override) {\n override = override || {\n unitsPerEm: 0,\n yMax: 0,\n yMin: 0,\n ascent: 0,\n descent: 0,\n };\n\n var ulUnicodeRange1 = 0;\n var ulUnicodeRange2 = 0;\n var ulUnicodeRange3 = 0;\n var ulUnicodeRange4 = 0;\n\n var firstCharIndex = null;\n var lastCharIndex = 0;\n\n if (charstrings) {\n for (var code in charstrings) {\n code |= 0;\n if (firstCharIndex > code || !firstCharIndex) {\n firstCharIndex = code;\n }\n if (lastCharIndex < code) {\n lastCharIndex = code;\n }\n\n var position = getUnicodeRangeFor(code);\n if (position < 32) {\n ulUnicodeRange1 |= 1 << position;\n } else if (position < 64) {\n ulUnicodeRange2 |= 1 << position - 32;\n } else if (position < 96) {\n ulUnicodeRange3 |= 1 << position - 64;\n } else if (position < 123) {\n ulUnicodeRange4 |= 1 << position - 96;\n } else {\n throw new FormatError(\n 'Unicode ranges Bits > 123 are reserved for internal usage');\n }\n }\n } else {\n // TODO\n firstCharIndex = 0;\n lastCharIndex = 255;\n }\n\n var bbox = properties.bbox || [0, 0, 0, 0];\n var unitsPerEm = (override.unitsPerEm ||\n 1 / (properties.fontMatrix || FONT_IDENTITY_MATRIX)[0]);\n\n // if the font units differ to the PDF glyph space units\n // then scale up the values\n var scale = (properties.ascentScaled ? 1.0 :\n unitsPerEm / PDF_GLYPH_SPACE_UNITS);\n\n var typoAscent = (override.ascent ||\n Math.round(scale * (properties.ascent || bbox[3])));\n var typoDescent = (override.descent ||\n Math.round(scale * (properties.descent || bbox[1])));\n if (typoDescent > 0 && properties.descent > 0 && bbox[1] < 0) {\n typoDescent = -typoDescent; // fixing incorrect descent\n }\n var winAscent = override.yMax || typoAscent;\n var winDescent = -override.yMin || -typoDescent;\n\n return '\\x00\\x03' + // version\n '\\x02\\x24' + // xAvgCharWidth\n '\\x01\\xF4' + // usWeightClass\n '\\x00\\x05' + // usWidthClass\n '\\x00\\x00' + // fstype (0 to let the font loads via font-face on IE)\n '\\x02\\x8A' + // ySubscriptXSize\n '\\x02\\xBB' + // ySubscriptYSize\n '\\x00\\x00' + // ySubscriptXOffset\n '\\x00\\x8C' + // ySubscriptYOffset\n '\\x02\\x8A' + // ySuperScriptXSize\n '\\x02\\xBB' + // ySuperScriptYSize\n '\\x00\\x00' + // ySuperScriptXOffset\n '\\x01\\xDF' + // ySuperScriptYOffset\n '\\x00\\x31' + // yStrikeOutSize\n '\\x01\\x02' + // yStrikeOutPosition\n '\\x00\\x00' + // sFamilyClass\n '\\x00\\x00\\x06' +\n String.fromCharCode(properties.fixedPitch ? 0x09 : 0x00) +\n '\\x00\\x00\\x00\\x00\\x00\\x00' + // Panose\n string32(ulUnicodeRange1) + // ulUnicodeRange1 (Bits 0-31)\n string32(ulUnicodeRange2) + // ulUnicodeRange2 (Bits 32-63)\n string32(ulUnicodeRange3) + // ulUnicodeRange3 (Bits 64-95)\n string32(ulUnicodeRange4) + // ulUnicodeRange4 (Bits 96-127)\n '\\x2A\\x32\\x31\\x2A' + // achVendID\n string16(properties.italicAngle ? 1 : 0) + // fsSelection\n string16(firstCharIndex ||\n properties.firstChar) + // usFirstCharIndex\n string16(lastCharIndex || properties.lastChar) + // usLastCharIndex\n string16(typoAscent) + // sTypoAscender\n string16(typoDescent) + // sTypoDescender\n '\\x00\\x64' + // sTypoLineGap (7%-10% of the unitsPerEM value)\n string16(winAscent) + // usWinAscent\n string16(winDescent) + // usWinDescent\n '\\x00\\x00\\x00\\x00' + // ulCodePageRange1 (Bits 0-31)\n '\\x00\\x00\\x00\\x00' + // ulCodePageRange2 (Bits 32-63)\n string16(properties.xHeight) + // sxHeight\n string16(properties.capHeight) + // sCapHeight\n string16(0) + // usDefaultChar\n string16(firstCharIndex || properties.firstChar) + // usBreakChar\n '\\x00\\x03'; // usMaxContext\n }\n\n function createPostTable(properties) {\n var angle = Math.floor(properties.italicAngle * (Math.pow(2, 16)));\n return ('\\x00\\x03\\x00\\x00' + // Version number\n string32(angle) + // italicAngle\n '\\x00\\x00' + // underlinePosition\n '\\x00\\x00' + // underlineThickness\n string32(properties.fixedPitch) + // isFixedPitch\n '\\x00\\x00\\x00\\x00' + // minMemType42\n '\\x00\\x00\\x00\\x00' + // maxMemType42\n '\\x00\\x00\\x00\\x00' + // minMemType1\n '\\x00\\x00\\x00\\x00'); // maxMemType1\n }\n\n function createNameTable(name, proto) {\n if (!proto) {\n proto = [[], []]; // no strings and unicode strings\n }\n\n var strings = [\n proto[0][0] || 'Original licence', // 0.Copyright\n proto[0][1] || name, // 1.Font family\n proto[0][2] || 'Unknown', // 2.Font subfamily (font weight)\n proto[0][3] || 'uniqueID', // 3.Unique ID\n proto[0][4] || name, // 4.Full font name\n proto[0][5] || 'Version 0.11', // 5.Version\n proto[0][6] || '', // 6.Postscript name\n proto[0][7] || 'Unknown', // 7.Trademark\n proto[0][8] || 'Unknown', // 8.Manufacturer\n proto[0][9] || 'Unknown' // 9.Designer\n ];\n\n // Mac want 1-byte per character strings while Windows want\n // 2-bytes per character, so duplicate the names table\n var stringsUnicode = [];\n var i, ii, j, jj, str;\n for (i = 0, ii = strings.length; i < ii; i++) {\n str = proto[1][i] || strings[i];\n\n var strBufUnicode = [];\n for (j = 0, jj = str.length; j < jj; j++) {\n strBufUnicode.push(string16(str.charCodeAt(j)));\n }\n stringsUnicode.push(strBufUnicode.join(''));\n }\n\n var names = [strings, stringsUnicode];\n var platforms = ['\\x00\\x01', '\\x00\\x03'];\n var encodings = ['\\x00\\x00', '\\x00\\x01'];\n var languages = ['\\x00\\x00', '\\x04\\x09'];\n\n var namesRecordCount = strings.length * platforms.length;\n var nameTable =\n '\\x00\\x00' + // format\n string16(namesRecordCount) + // Number of names Record\n string16(namesRecordCount * 12 + 6); // Storage\n\n // Build the name records field\n var strOffset = 0;\n for (i = 0, ii = platforms.length; i < ii; i++) {\n var strs = names[i];\n for (j = 0, jj = strs.length; j < jj; j++) {\n str = strs[j];\n var nameRecord =\n platforms[i] + // platform ID\n encodings[i] + // encoding ID\n languages[i] + // language ID\n string16(j) + // name ID\n string16(str.length) +\n string16(strOffset);\n nameTable += nameRecord;\n strOffset += str.length;\n }\n }\n\n nameTable += strings.join('') + stringsUnicode.join('');\n return nameTable;\n }\n\n Font.prototype = {\n name: null,\n font: null,\n mimetype: null,\n encoding: null,\n get renderer() {\n var renderer = FontRendererFactory.create(this, SEAC_ANALYSIS_ENABLED);\n return shadow(this, 'renderer', renderer);\n },\n\n exportData: function Font_exportData() {\n // TODO remove enumerating of the properties, e.g. hardcode exact names.\n var data = {};\n for (var i in this) {\n if (this.hasOwnProperty(i)) {\n data[i] = this[i];\n }\n }\n return data;\n },\n\n fallbackToSystemFont: function Font_fallbackToSystemFont() {\n this.missingFile = true;\n var charCode, unicode;\n // The file data is not specified. Trying to fix the font name\n // to be used with the canvas.font.\n var name = this.name;\n var type = this.type;\n var subtype = this.subtype;\n var fontName = name.replace(/[,_]/g, '-');\n var stdFontMap = getStdFontMap(), nonStdFontMap = getNonStdFontMap();\n var isStandardFont = !!stdFontMap[fontName] ||\n !!(nonStdFontMap[fontName] && stdFontMap[nonStdFontMap[fontName]]);\n fontName = stdFontMap[fontName] || nonStdFontMap[fontName] || fontName;\n\n this.bold = (fontName.search(/bold/gi) !== -1);\n this.italic = ((fontName.search(/oblique/gi) !== -1) ||\n (fontName.search(/italic/gi) !== -1));\n\n // Use 'name' instead of 'fontName' here because the original\n // name ArialBlack for example will be replaced by Helvetica.\n this.black = (name.search(/Black/g) !== -1);\n\n // if at least one width is present, remeasure all chars when exists\n this.remeasure = Object.keys(this.widths).length > 0;\n if (isStandardFont && type === 'CIDFontType2' &&\n this.cidEncoding.indexOf('Identity-') === 0) {\n var GlyphMapForStandardFonts = getGlyphMapForStandardFonts();\n // Standard fonts might be embedded as CID font without glyph mapping.\n // Building one based on GlyphMapForStandardFonts.\n var map = [];\n for (charCode in GlyphMapForStandardFonts) {\n map[+charCode] = GlyphMapForStandardFonts[charCode];\n }\n if (/Arial-?Black/i.test(name)) {\n var SupplementalGlyphMapForArialBlack =\n getSupplementalGlyphMapForArialBlack();\n for (charCode in SupplementalGlyphMapForArialBlack) {\n map[+charCode] = SupplementalGlyphMapForArialBlack[charCode];\n }\n }\n var isIdentityUnicode = this.toUnicode instanceof IdentityToUnicodeMap;\n if (!isIdentityUnicode) {\n this.toUnicode.forEach(function(charCode, unicodeCharCode) {\n map[+charCode] = unicodeCharCode;\n });\n }\n this.toFontChar = map;\n this.toUnicode = new ToUnicodeMap(map);\n } else if (/Symbol/i.test(fontName)) {\n this.toFontChar = buildToFontChar(SymbolSetEncoding, getGlyphsUnicode(),\n this.differences);\n } else if (/Dingbats/i.test(fontName)) {\n if (/Wingdings/i.test(name)) {\n warn('Non-embedded Wingdings font, falling back to ZapfDingbats.');\n }\n this.toFontChar = buildToFontChar(ZapfDingbatsEncoding,\n getDingbatsGlyphsUnicode(),\n this.differences);\n } else if (isStandardFont) {\n this.toFontChar = buildToFontChar(this.defaultEncoding,\n getGlyphsUnicode(),\n this.differences);\n } else {\n var glyphsUnicodeMap = getGlyphsUnicode();\n this.toUnicode.forEach((charCode, unicodeCharCode) => {\n if (!this.composite) {\n var glyphName = (this.differences[charCode] ||\n this.defaultEncoding[charCode]);\n unicode = getUnicodeForGlyph(glyphName, glyphsUnicodeMap);\n if (unicode !== -1) {\n unicodeCharCode = unicode;\n }\n }\n this.toFontChar[charCode] = unicodeCharCode;\n });\n }\n this.loadedName = fontName.split('-')[0];\n this.loading = false;\n this.fontType = getFontType(type, subtype);\n },\n\n checkAndRepair: function Font_checkAndRepair(name, font, properties) {\n function readTableEntry(file) {\n var tag = bytesToString(file.getBytes(4));\n\n var checksum = file.getInt32() >>> 0;\n var offset = file.getInt32() >>> 0;\n var length = file.getInt32() >>> 0;\n\n // Read the table associated data\n var previousPosition = file.pos;\n file.pos = file.start ? file.start : 0;\n file.skip(offset);\n var data = file.getBytes(length);\n file.pos = previousPosition;\n\n if (tag === 'head') {\n // clearing checksum adjustment\n data[8] = data[9] = data[10] = data[11] = 0;\n data[17] |= 0x20; // Set font optimized for cleartype flag.\n }\n\n return {\n tag,\n checksum,\n length,\n offset,\n data,\n };\n }\n\n function readOpenTypeHeader(ttf) {\n return {\n version: bytesToString(ttf.getBytes(4)),\n numTables: ttf.getUint16(),\n searchRange: ttf.getUint16(),\n entrySelector: ttf.getUint16(),\n rangeShift: ttf.getUint16(),\n };\n }\n\n /**\n * Read the appropriate subtable from the cmap according to 9.6.6.4 from\n * PDF spec\n */\n function readCmapTable(cmap, font, isSymbolicFont, hasEncoding) {\n if (!cmap) {\n warn('No cmap table available.');\n return {\n platformId: -1,\n encodingId: -1,\n mappings: [],\n hasShortCmap: false,\n };\n }\n var segment;\n var start = (font.start ? font.start : 0) + cmap.offset;\n font.pos = start;\n\n font.getUint16(); // version\n var numTables = font.getUint16();\n\n var potentialTable;\n var canBreak = false;\n // There's an order of preference in terms of which cmap subtable to\n // use:\n // - non-symbolic fonts the preference is a 3,1 table then a 1,0 table\n // - symbolic fonts the preference is a 3,0 table then a 1,0 table\n // The following takes advantage of the fact that the tables are sorted\n // to work.\n for (var i = 0; i < numTables; i++) {\n var platformId = font.getUint16();\n var encodingId = font.getUint16();\n var offset = font.getInt32() >>> 0;\n var useTable = false;\n\n // Sometimes there are multiple of the same type of table. Default\n // to choosing the first table and skip the rest.\n if (potentialTable && potentialTable.platformId === platformId &&\n potentialTable.encodingId === encodingId) {\n continue;\n }\n\n if (platformId === 0 && encodingId === 0) {\n useTable = true;\n // Continue the loop since there still may be a higher priority\n // table.\n } else if (platformId === 1 && encodingId === 0) {\n useTable = true;\n // Continue the loop since there still may be a higher priority\n // table.\n } else if (platformId === 3 && encodingId === 1 &&\n (hasEncoding || !potentialTable)) {\n useTable = true;\n if (!isSymbolicFont) {\n canBreak = true;\n }\n } else if (isSymbolicFont && platformId === 3 && encodingId === 0) {\n useTable = true;\n canBreak = true;\n }\n\n if (useTable) {\n potentialTable = {\n platformId,\n encodingId,\n offset,\n };\n }\n if (canBreak) {\n break;\n }\n }\n\n if (potentialTable) {\n font.pos = start + potentialTable.offset;\n }\n if (!potentialTable || font.peekByte() === -1) {\n warn('Could not find a preferred cmap table.');\n return {\n platformId: -1,\n encodingId: -1,\n mappings: [],\n hasShortCmap: false,\n };\n }\n\n var format = font.getUint16();\n font.getUint16(); // length\n font.getUint16(); // language\n\n var hasShortCmap = false;\n var mappings = [];\n var j, glyphId;\n\n // TODO(mack): refactor this cmap subtable reading logic out\n if (format === 0) {\n for (j = 0; j < 256; j++) {\n var index = font.getByte();\n if (!index) {\n continue;\n }\n mappings.push({\n charCode: j,\n glyphId: index,\n });\n }\n hasShortCmap = true;\n } else if (format === 4) {\n // re-creating the table in format 4 since the encoding\n // might be changed\n var segCount = (font.getUint16() >> 1);\n font.getBytes(6); // skipping range fields\n var segIndex, segments = [];\n for (segIndex = 0; segIndex < segCount; segIndex++) {\n segments.push({ end: font.getUint16(), });\n }\n font.getUint16();\n for (segIndex = 0; segIndex < segCount; segIndex++) {\n segments[segIndex].start = font.getUint16();\n }\n\n for (segIndex = 0; segIndex < segCount; segIndex++) {\n segments[segIndex].delta = font.getUint16();\n }\n\n var offsetsCount = 0;\n for (segIndex = 0; segIndex < segCount; segIndex++) {\n segment = segments[segIndex];\n var rangeOffset = font.getUint16();\n if (!rangeOffset) {\n segment.offsetIndex = -1;\n continue;\n }\n\n var offsetIndex = (rangeOffset >> 1) - (segCount - segIndex);\n segment.offsetIndex = offsetIndex;\n offsetsCount = Math.max(offsetsCount, offsetIndex +\n segment.end - segment.start + 1);\n }\n\n var offsets = [];\n for (j = 0; j < offsetsCount; j++) {\n offsets.push(font.getUint16());\n }\n\n for (segIndex = 0; segIndex < segCount; segIndex++) {\n segment = segments[segIndex];\n start = segment.start;\n var end = segment.end;\n var delta = segment.delta;\n offsetIndex = segment.offsetIndex;\n\n for (j = start; j <= end; j++) {\n if (j === 0xFFFF) {\n continue;\n }\n\n glyphId = (offsetIndex < 0 ?\n j : offsets[offsetIndex + j - start]);\n glyphId = (glyphId + delta) & 0xFFFF;\n mappings.push({\n charCode: j,\n glyphId,\n });\n }\n }\n } else if (format === 6) {\n // Format 6 is a 2-bytes dense mapping, which means the font data\n // lives glue together even if they are pretty far in the unicode\n // table. (This looks weird, so I can have missed something), this\n // works on Linux but seems to fails on Mac so let's rewrite the\n // cmap table to a 3-1-4 style\n var firstCode = font.getUint16();\n var entryCount = font.getUint16();\n\n for (j = 0; j < entryCount; j++) {\n glyphId = font.getUint16();\n var charCode = firstCode + j;\n\n mappings.push({\n charCode,\n glyphId,\n });\n }\n } else {\n warn('cmap table has unsupported format: ' + format);\n return {\n platformId: -1,\n encodingId: -1,\n mappings: [],\n hasShortCmap: false,\n };\n }\n\n // removing duplicate entries\n mappings.sort(function (a, b) {\n return a.charCode - b.charCode;\n });\n for (i = 1; i < mappings.length; i++) {\n if (mappings[i - 1].charCode === mappings[i].charCode) {\n mappings.splice(i, 1);\n i--;\n }\n }\n\n return {\n platformId: potentialTable.platformId,\n encodingId: potentialTable.encodingId,\n mappings,\n hasShortCmap,\n };\n }\n\n function sanitizeMetrics(font, header, metrics, numGlyphs) {\n if (!header) {\n if (metrics) {\n metrics.data = null;\n }\n return;\n }\n\n font.pos = (font.start ? font.start : 0) + header.offset;\n font.pos += header.length - 2;\n var numOfMetrics = font.getUint16();\n\n if (numOfMetrics > numGlyphs) {\n info('The numOfMetrics (' + numOfMetrics + ') should not be ' +\n 'greater than the numGlyphs (' + numGlyphs + ')');\n // Reduce numOfMetrics if it is greater than numGlyphs\n numOfMetrics = numGlyphs;\n header.data[34] = (numOfMetrics & 0xff00) >> 8;\n header.data[35] = numOfMetrics & 0x00ff;\n }\n\n var numOfSidebearings = numGlyphs - numOfMetrics;\n var numMissing = numOfSidebearings -\n ((metrics.length - numOfMetrics * 4) >> 1);\n\n if (numMissing > 0) {\n // For each missing glyph, we set both the width and lsb to 0 (zero).\n // Since we need to add two properties for each glyph, this explains\n // the use of |numMissing * 2| when initializing the typed array.\n var entries = new Uint8Array(metrics.length + numMissing * 2);\n entries.set(metrics.data);\n metrics.data = entries;\n }\n }\n\n function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart,\n hintsValid) {\n if (sourceEnd - sourceStart <= 12) {\n // glyph with data less than 12 is invalid one\n return 0;\n }\n var glyf = source.subarray(sourceStart, sourceEnd);\n var contoursCount = (glyf[0] << 8) | glyf[1];\n if (contoursCount & 0x8000) {\n // complex glyph, writing as is\n dest.set(glyf, destStart);\n return glyf.length;\n }\n\n var i, j = 10, flagsCount = 0;\n for (i = 0; i < contoursCount; i++) {\n var endPoint = (glyf[j] << 8) | glyf[j + 1];\n flagsCount = endPoint + 1;\n j += 2;\n }\n // skipping instructions\n var instructionsStart = j;\n var instructionsLength = (glyf[j] << 8) | glyf[j + 1];\n j += 2 + instructionsLength;\n var instructionsEnd = j;\n // validating flags\n var coordinatesLength = 0;\n for (i = 0; i < flagsCount; i++) {\n var flag = glyf[j++];\n if (flag & 0xC0) {\n // reserved flags must be zero, cleaning up\n glyf[j - 1] = flag & 0x3F;\n }\n var xyLength = ((flag & 2) ? 1 : (flag & 16) ? 0 : 2) +\n ((flag & 4) ? 1 : (flag & 32) ? 0 : 2);\n coordinatesLength += xyLength;\n if (flag & 8) {\n var repeat = glyf[j++];\n i += repeat;\n coordinatesLength += repeat * xyLength;\n }\n }\n // glyph without coordinates will be rejected\n if (coordinatesLength === 0) {\n return 0;\n }\n var glyphDataLength = j + coordinatesLength;\n if (glyphDataLength > glyf.length) {\n // not enough data for coordinates\n return 0;\n }\n if (!hintsValid && instructionsLength > 0) {\n dest.set(glyf.subarray(0, instructionsStart), destStart);\n dest.set([0, 0], destStart + instructionsStart);\n dest.set(glyf.subarray(instructionsEnd, glyphDataLength),\n destStart + instructionsStart + 2);\n glyphDataLength -= instructionsLength;\n if (glyf.length - glyphDataLength > 3) {\n glyphDataLength = (glyphDataLength + 3) & ~3;\n }\n return glyphDataLength;\n }\n if (glyf.length - glyphDataLength > 3) {\n // truncating and aligning to 4 bytes the long glyph data\n glyphDataLength = (glyphDataLength + 3) & ~3;\n dest.set(glyf.subarray(0, glyphDataLength), destStart);\n return glyphDataLength;\n }\n // glyph data is fine\n dest.set(glyf, destStart);\n return glyf.length;\n }\n\n function sanitizeHead(head, numGlyphs, locaLength) {\n var data = head.data;\n\n // Validate version:\n // Should always be 0x00010000\n var version = int32(data[0], data[1], data[2], data[3]);\n if (version >> 16 !== 1) {\n info('Attempting to fix invalid version in head table: ' + version);\n data[0] = 0;\n data[1] = 1;\n data[2] = 0;\n data[3] = 0;\n }\n\n var indexToLocFormat = int16(data[50], data[51]);\n if (indexToLocFormat < 0 || indexToLocFormat > 1) {\n info('Attempting to fix invalid indexToLocFormat in head table: ' +\n indexToLocFormat);\n\n // The value of indexToLocFormat should be 0 if the loca table\n // consists of short offsets, and should be 1 if the loca table\n // consists of long offsets.\n //\n // The number of entries in the loca table should be numGlyphs + 1.\n //\n // Using this information, we can work backwards to deduce if the\n // size of each offset in the loca table, and thus figure out the\n // appropriate value for indexToLocFormat.\n\n var numGlyphsPlusOne = numGlyphs + 1;\n if (locaLength === numGlyphsPlusOne << 1) {\n // 0x0000 indicates the loca table consists of short offsets\n data[50] = 0;\n data[51] = 0;\n } else if (locaLength === numGlyphsPlusOne << 2) {\n // 0x0001 indicates the loca table consists of long offsets\n data[50] = 0;\n data[51] = 1;\n } else {\n throw new FormatError('Could not fix indexToLocFormat: ' +\n indexToLocFormat);\n }\n }\n }\n\n function sanitizeGlyphLocations(loca, glyf, numGlyphs,\n isGlyphLocationsLong, hintsValid,\n dupFirstEntry) {\n var itemSize, itemDecode, itemEncode;\n if (isGlyphLocationsLong) {\n itemSize = 4;\n itemDecode = function fontItemDecodeLong(data, offset) {\n return (data[offset] << 24) | (data[offset + 1] << 16) |\n (data[offset + 2] << 8) | data[offset + 3];\n };\n itemEncode = function fontItemEncodeLong(data, offset, value) {\n data[offset] = (value >>> 24) & 0xFF;\n data[offset + 1] = (value >> 16) & 0xFF;\n data[offset + 2] = (value >> 8) & 0xFF;\n data[offset + 3] = value & 0xFF;\n };\n } else {\n itemSize = 2;\n itemDecode = function fontItemDecode(data, offset) {\n return (data[offset] << 9) | (data[offset + 1] << 1);\n };\n itemEncode = function fontItemEncode(data, offset, value) {\n data[offset] = (value >> 9) & 0xFF;\n data[offset + 1] = (value >> 1) & 0xFF;\n };\n }\n var locaData = loca.data;\n var locaDataSize = itemSize * (1 + numGlyphs);\n // is loca.data too short or long?\n if (locaData.length !== locaDataSize) {\n locaData = new Uint8Array(locaDataSize);\n locaData.set(loca.data.subarray(0, locaDataSize));\n loca.data = locaData;\n }\n // removing the invalid glyphs\n var oldGlyfData = glyf.data;\n var oldGlyfDataLength = oldGlyfData.length;\n var newGlyfData = new Uint8Array(oldGlyfDataLength);\n var startOffset = itemDecode(locaData, 0);\n var writeOffset = 0;\n var missingGlyphData = Object.create(null);\n itemEncode(locaData, 0, writeOffset);\n var i, j;\n // When called with dupFirstEntry the number of glyphs has already been\n // increased but there isn't data yet for the duplicated glyph.\n var locaCount = dupFirstEntry ? numGlyphs - 1 : numGlyphs;\n for (i = 0, j = itemSize; i < locaCount; i++, j += itemSize) {\n var endOffset = itemDecode(locaData, j);\n if (endOffset > oldGlyfDataLength &&\n ((oldGlyfDataLength + 3) & ~3) === endOffset) {\n // Aspose breaks fonts by aligning the glyphs to the qword, but not\n // the glyf table size, which makes last glyph out of range.\n endOffset = oldGlyfDataLength;\n }\n if (endOffset > oldGlyfDataLength) {\n // glyph end offset points outside glyf data, rejecting the glyph\n startOffset = endOffset;\n }\n\n var newLength = sanitizeGlyph(oldGlyfData, startOffset, endOffset,\n newGlyfData, writeOffset, hintsValid);\n if (newLength === 0) {\n missingGlyphData[i] = true;\n }\n writeOffset += newLength;\n itemEncode(locaData, j, writeOffset);\n startOffset = endOffset;\n }\n\n if (writeOffset === 0) {\n // glyf table cannot be empty -- redoing the glyf and loca tables\n // to have single glyph with one point\n var simpleGlyph = new Uint8Array(\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0]);\n for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {\n itemEncode(locaData, j, simpleGlyph.length);\n }\n glyf.data = simpleGlyph;\n return missingGlyphData;\n }\n\n if (dupFirstEntry) {\n var firstEntryLength = itemDecode(locaData, itemSize);\n if (newGlyfData.length > firstEntryLength + writeOffset) {\n glyf.data = newGlyfData.subarray(0, firstEntryLength + writeOffset);\n } else {\n glyf.data = new Uint8Array(firstEntryLength + writeOffset);\n glyf.data.set(newGlyfData.subarray(0, writeOffset));\n }\n glyf.data.set(newGlyfData.subarray(0, firstEntryLength), writeOffset);\n itemEncode(loca.data, locaData.length - itemSize,\n writeOffset + firstEntryLength);\n } else {\n glyf.data = newGlyfData.subarray(0, writeOffset);\n }\n return missingGlyphData;\n }\n\n function readPostScriptTable(post, properties, maxpNumGlyphs) {\n var start = (font.start ? font.start : 0) + post.offset;\n font.pos = start;\n\n var length = post.length, end = start + length;\n var version = font.getInt32();\n // skip rest to the tables\n font.getBytes(28);\n\n var glyphNames;\n var valid = true;\n var i;\n\n switch (version) {\n case 0x00010000:\n glyphNames = MacStandardGlyphOrdering;\n break;\n case 0x00020000:\n var numGlyphs = font.getUint16();\n if (numGlyphs !== maxpNumGlyphs) {\n valid = false;\n break;\n }\n var glyphNameIndexes = [];\n for (i = 0; i < numGlyphs; ++i) {\n var index = font.getUint16();\n if (index >= 32768) {\n valid = false;\n break;\n }\n glyphNameIndexes.push(index);\n }\n if (!valid) {\n break;\n }\n var customNames = [];\n var strBuf = [];\n while (font.pos < end) {\n var stringLength = font.getByte();\n strBuf.length = stringLength;\n for (i = 0; i < stringLength; ++i) {\n strBuf[i] = String.fromCharCode(font.getByte());\n }\n customNames.push(strBuf.join(''));\n }\n glyphNames = [];\n for (i = 0; i < numGlyphs; ++i) {\n var j = glyphNameIndexes[i];\n if (j < 258) {\n glyphNames.push(MacStandardGlyphOrdering[j]);\n continue;\n }\n glyphNames.push(customNames[j - 258]);\n }\n break;\n case 0x00030000:\n break;\n default:\n warn('Unknown/unsupported post table version ' + version);\n valid = false;\n if (properties.defaultEncoding) {\n glyphNames = properties.defaultEncoding;\n }\n break;\n }\n properties.glyphNames = glyphNames;\n return valid;\n }\n\n function readNameTable(nameTable) {\n var start = (font.start ? font.start : 0) + nameTable.offset;\n font.pos = start;\n\n var names = [[], []];\n var length = nameTable.length, end = start + length;\n var format = font.getUint16();\n var FORMAT_0_HEADER_LENGTH = 6;\n if (format !== 0 || length < FORMAT_0_HEADER_LENGTH) {\n // unsupported name table format or table \"too\" small\n return names;\n }\n var numRecords = font.getUint16();\n var stringsStart = font.getUint16();\n var records = [];\n var NAME_RECORD_LENGTH = 12;\n var i, ii;\n\n for (i = 0; i < numRecords &&\n font.pos + NAME_RECORD_LENGTH <= end; i++) {\n var r = {\n platform: font.getUint16(),\n encoding: font.getUint16(),\n language: font.getUint16(),\n name: font.getUint16(),\n length: font.getUint16(),\n offset: font.getUint16(),\n };\n // using only Macintosh and Windows platform/encoding names\n if ((r.platform === 1 && r.encoding === 0 && r.language === 0) ||\n (r.platform === 3 && r.encoding === 1 && r.language === 0x409)) {\n records.push(r);\n }\n }\n for (i = 0, ii = records.length; i < ii; i++) {\n var record = records[i];\n if (record.length <= 0) {\n continue; // Nothing to process, ignoring.\n }\n var pos = start + stringsStart + record.offset;\n if (pos + record.length > end) {\n continue; // outside of name table, ignoring\n }\n font.pos = pos;\n var nameIndex = record.name;\n if (record.encoding) {\n // unicode\n var str = '';\n for (var j = 0, jj = record.length; j < jj; j += 2) {\n str += String.fromCharCode(font.getUint16());\n }\n names[1][nameIndex] = str;\n } else {\n names[0][nameIndex] = bytesToString(font.getBytes(record.length));\n }\n }\n return names;\n }\n\n var TTOpsStackDeltas = [\n 0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, -2, -5,\n -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, -1, -1,\n 1, -1, -999, 0, 1, 0, -1, -2, 0, -1, -2, -1, -1, 0, -1, -1,\n 0, 0, -999, -999, -1, -1, -1, -1, -2, -999, -2, -2, -999, 0, -2, -2,\n 0, 0, -2, 0, -2, 0, 0, 0, -2, -1, -1, 1, 1, 0, 0, -1,\n -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, 0, -999, -1, -1,\n -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n -2, -999, -999, -999, -999, -999, -1, -1, -2, -2, 0, 0, 0, 0, -1, -1,\n -999, -2, -2, 0, 0, -1, -2, -2, 0, 0, 0, -1, -1, -1, -2];\n // 0xC0-DF == -1 and 0xE0-FF == -2\n\n function sanitizeTTProgram(table, ttContext) {\n var data = table.data;\n var i = 0, j, n, b, funcId, pc, lastEndf = 0, lastDeff = 0;\n var stack = [];\n var callstack = [];\n var functionsCalled = [];\n var tooComplexToFollowFunctions =\n ttContext.tooComplexToFollowFunctions;\n var inFDEF = false, ifLevel = 0, inELSE = 0;\n for (var ii = data.length; i < ii;) {\n var op = data[i++];\n // The TrueType instruction set docs can be found at\n // https://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html\n if (op === 0x40) { // NPUSHB - pushes n bytes\n n = data[i++];\n if (inFDEF || inELSE) {\n i += n;\n } else {\n for (j = 0; j < n; j++) {\n stack.push(data[i++]);\n }\n }\n } else if (op === 0x41) { // NPUSHW - pushes n words\n n = data[i++];\n if (inFDEF || inELSE) {\n i += n * 2;\n } else {\n for (j = 0; j < n; j++) {\n b = data[i++];\n stack.push((b << 8) | data[i++]);\n }\n }\n } else if ((op & 0xF8) === 0xB0) { // PUSHB - pushes bytes\n n = op - 0xB0 + 1;\n if (inFDEF || inELSE) {\n i += n;\n } else {\n for (j = 0; j < n; j++) {\n stack.push(data[i++]);\n }\n }\n } else if ((op & 0xF8) === 0xB8) { // PUSHW - pushes words\n n = op - 0xB8 + 1;\n if (inFDEF || inELSE) {\n i += n * 2;\n } else {\n for (j = 0; j < n; j++) {\n b = data[i++];\n stack.push((b << 8) | data[i++]);\n }\n }\n } else if (op === 0x2B && !tooComplexToFollowFunctions) { // CALL\n if (!inFDEF && !inELSE) {\n // collecting inforamtion about which functions are used\n funcId = stack[stack.length - 1];\n ttContext.functionsUsed[funcId] = true;\n if (funcId in ttContext.functionsStackDeltas) {\n stack.length += ttContext.functionsStackDeltas[funcId];\n } else if (funcId in ttContext.functionsDefined &&\n functionsCalled.indexOf(funcId) < 0) {\n callstack.push({ data, i, stackTop: stack.length - 1, });\n functionsCalled.push(funcId);\n pc = ttContext.functionsDefined[funcId];\n if (!pc) {\n warn('TT: CALL non-existent function');\n ttContext.hintsValid = false;\n return;\n }\n data = pc.data;\n i = pc.i;\n }\n }\n } else if (op === 0x2C && !tooComplexToFollowFunctions) { // FDEF\n if (inFDEF || inELSE) {\n warn('TT: nested FDEFs not allowed');\n tooComplexToFollowFunctions = true;\n }\n inFDEF = true;\n // collecting inforamtion about which functions are defined\n lastDeff = i;\n funcId = stack.pop();\n ttContext.functionsDefined[funcId] = { data, i, };\n } else if (op === 0x2D) { // ENDF - end of function\n if (inFDEF) {\n inFDEF = false;\n lastEndf = i;\n } else {\n pc = callstack.pop();\n if (!pc) {\n warn('TT: ENDF bad stack');\n ttContext.hintsValid = false;\n return;\n }\n funcId = functionsCalled.pop();\n data = pc.data;\n i = pc.i;\n ttContext.functionsStackDeltas[funcId] =\n stack.length - pc.stackTop;\n }\n } else if (op === 0x89) { // IDEF - instruction definition\n if (inFDEF || inELSE) {\n warn('TT: nested IDEFs not allowed');\n tooComplexToFollowFunctions = true;\n }\n inFDEF = true;\n // recording it as a function to track ENDF\n lastDeff = i;\n } else if (op === 0x58) { // IF\n ++ifLevel;\n } else if (op === 0x1B) { // ELSE\n inELSE = ifLevel;\n } else if (op === 0x59) { // EIF\n if (inELSE === ifLevel) {\n inELSE = 0;\n }\n --ifLevel;\n } else if (op === 0x1C) { // JMPR\n if (!inFDEF && !inELSE) {\n var offset = stack[stack.length - 1];\n // only jumping forward to prevent infinite loop\n if (offset > 0) {\n i += offset - 1;\n }\n }\n }\n // Adjusting stack not extactly, but just enough to get function id\n if (!inFDEF && !inELSE) {\n var stackDelta = op <= 0x8E ? TTOpsStackDeltas[op] :\n op >= 0xC0 && op <= 0xDF ? -1 : op >= 0xE0 ? -2 : 0;\n if (op >= 0x71 && op <= 0x75) {\n n = stack.pop();\n if (!isNaN(n)) {\n stackDelta = -n * 2;\n }\n }\n while (stackDelta < 0 && stack.length > 0) {\n stack.pop();\n stackDelta++;\n }\n while (stackDelta > 0) {\n stack.push(NaN); // pushing any number into stack\n stackDelta--;\n }\n }\n }\n ttContext.tooComplexToFollowFunctions = tooComplexToFollowFunctions;\n var content = [data];\n if (i > data.length) {\n content.push(new Uint8Array(i - data.length));\n }\n if (lastDeff > lastEndf) {\n warn('TT: complementing a missing function tail');\n // new function definition started, but not finished\n // complete function by [CLEAR, ENDF]\n content.push(new Uint8Array([0x22, 0x2D]));\n }\n foldTTTable(table, content);\n }\n\n function checkInvalidFunctions(ttContext, maxFunctionDefs) {\n if (ttContext.tooComplexToFollowFunctions) {\n return;\n }\n if (ttContext.functionsDefined.length > maxFunctionDefs) {\n warn('TT: more functions defined than expected');\n ttContext.hintsValid = false;\n return;\n }\n for (var j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) {\n if (j > maxFunctionDefs) {\n warn('TT: invalid function id: ' + j);\n ttContext.hintsValid = false;\n return;\n }\n if (ttContext.functionsUsed[j] && !ttContext.functionsDefined[j]) {\n warn('TT: undefined function: ' + j);\n ttContext.hintsValid = false;\n return;\n }\n }\n }\n\n function foldTTTable(table, content) {\n if (content.length > 1) {\n // concatenating the content items\n var newLength = 0;\n var j, jj;\n for (j = 0, jj = content.length; j < jj; j++) {\n newLength += content[j].length;\n }\n newLength = (newLength + 3) & ~3;\n var result = new Uint8Array(newLength);\n var pos = 0;\n for (j = 0, jj = content.length; j < jj; j++) {\n result.set(content[j], pos);\n pos += content[j].length;\n }\n table.data = result;\n table.length = newLength;\n }\n }\n\n function sanitizeTTPrograms(fpgm, prep, cvt, maxFunctionDefs) {\n var ttContext = {\n functionsDefined: [],\n functionsUsed: [],\n functionsStackDeltas: [],\n tooComplexToFollowFunctions: false,\n hintsValid: true,\n };\n if (fpgm) {\n sanitizeTTProgram(fpgm, ttContext);\n }\n if (prep) {\n sanitizeTTProgram(prep, ttContext);\n }\n if (fpgm) {\n checkInvalidFunctions(ttContext, maxFunctionDefs);\n }\n if (cvt && (cvt.length & 1)) {\n var cvtData = new Uint8Array(cvt.length + 1);\n cvtData.set(cvt.data);\n cvt.data = cvtData;\n }\n return ttContext.hintsValid;\n }\n\n // The following steps modify the original font data, making copy\n font = new Stream(new Uint8Array(font.getBytes()));\n\n var VALID_TABLES = ['OS/2', 'cmap', 'head', 'hhea', 'hmtx', 'maxp',\n 'name', 'post', 'loca', 'glyf', 'fpgm', 'prep', 'cvt ', 'CFF '];\n\n var header = readOpenTypeHeader(font);\n var numTables = header.numTables;\n var cff, cffFile;\n\n var tables = Object.create(null);\n tables['OS/2'] = null;\n tables['cmap'] = null;\n tables['head'] = null;\n tables['hhea'] = null;\n tables['hmtx'] = null;\n tables['maxp'] = null;\n tables['name'] = null;\n tables['post'] = null;\n\n var table;\n for (var i = 0; i < numTables; i++) {\n table = readTableEntry(font);\n if (VALID_TABLES.indexOf(table.tag) < 0) {\n continue; // skipping table if it's not a required or optional table\n }\n if (table.length === 0) {\n continue; // skipping empty tables\n }\n tables[table.tag] = table;\n }\n\n var isTrueType = !tables['CFF '];\n if (!isTrueType) {\n // OpenType font (skip composite fonts with non-default CID to GID map).\n if ((header.version === 'OTTO' &&\n !(properties.composite && properties.cidToGidMap)) ||\n !tables['head'] || !tables['hhea'] || !tables['maxp'] ||\n !tables['post']) {\n // No major tables: throwing everything at `CFFFont`.\n cffFile = new Stream(tables['CFF '].data);\n cff = new CFFFont(cffFile, properties);\n\n adjustWidths(properties);\n\n return this.convert(name, cff, properties);\n }\n\n delete tables['glyf'];\n delete tables['loca'];\n delete tables['fpgm'];\n delete tables['prep'];\n delete tables['cvt '];\n this.isOpenType = true;\n } else {\n if (!tables['loca']) {\n throw new FormatError('Required \"loca\" table is not found');\n }\n if (!tables['glyf']) {\n warn('Required \"glyf\" table is not found -- trying to recover.');\n // Note: We use `sanitizeGlyphLocations` to add dummy glyf data below.\n tables['glyf'] = {\n tag: 'glyf',\n data: new Uint8Array(0),\n };\n }\n this.isOpenType = false;\n }\n\n if (!tables['maxp']) {\n throw new FormatError('Required \"maxp\" table is not found');\n }\n\n font.pos = (font.start || 0) + tables['maxp'].offset;\n var version = font.getInt32();\n var numGlyphs = font.getUint16();\n var maxFunctionDefs = 0;\n if (version >= 0x00010000 && tables['maxp'].length >= 22) {\n // maxZones can be invalid\n font.pos += 8;\n var maxZones = font.getUint16();\n if (maxZones > 2) { // reset to 2 if font has invalid maxZones\n tables['maxp'].data[14] = 0;\n tables['maxp'].data[15] = 2;\n }\n font.pos += 4;\n maxFunctionDefs = font.getUint16();\n }\n\n var dupFirstEntry = false;\n if (properties.type === 'CIDFontType2' && properties.toUnicode &&\n properties.toUnicode.get(0) > '\\u0000') {\n // oracle's defect (see 3427), duplicating first entry\n dupFirstEntry = true;\n numGlyphs++;\n tables['maxp'].data[4] = numGlyphs >> 8;\n tables['maxp'].data[5] = numGlyphs & 255;\n }\n\n var hintsValid = sanitizeTTPrograms(tables['fpgm'], tables['prep'],\n tables['cvt '], maxFunctionDefs);\n if (!hintsValid) {\n delete tables['fpgm'];\n delete tables['prep'];\n delete tables['cvt '];\n }\n\n // Ensure the hmtx table contains the advance width and\n // sidebearings information for numGlyphs in the maxp table\n sanitizeMetrics(font, tables['hhea'], tables['hmtx'], numGlyphs);\n\n if (!tables['head']) {\n throw new FormatError('Required \"head\" table is not found');\n }\n\n sanitizeHead(tables['head'], numGlyphs,\n isTrueType ? tables['loca'].length : 0);\n\n var missingGlyphs = Object.create(null);\n if (isTrueType) {\n var isGlyphLocationsLong = int16(tables['head'].data[50],\n tables['head'].data[51]);\n missingGlyphs = sanitizeGlyphLocations(tables['loca'], tables['glyf'],\n numGlyphs, isGlyphLocationsLong,\n hintsValid, dupFirstEntry);\n }\n\n if (!tables['hhea']) {\n throw new FormatError('Required \"hhea\" table is not found');\n }\n\n // Sanitizer reduces the glyph advanceWidth to the maxAdvanceWidth\n // Sometimes it's 0. That needs to be fixed\n if (tables['hhea'].data[10] === 0 && tables['hhea'].data[11] === 0) {\n tables['hhea'].data[10] = 0xFF;\n tables['hhea'].data[11] = 0xFF;\n }\n\n // Extract some more font properties from the OpenType head and\n // hhea tables; yMin and descent value are always negative.\n var metricsOverride = {\n unitsPerEm: int16(tables['head'].data[18], tables['head'].data[19]),\n yMax: int16(tables['head'].data[42], tables['head'].data[43]),\n yMin: signedInt16(tables['head'].data[38], tables['head'].data[39]),\n ascent: int16(tables['hhea'].data[4], tables['hhea'].data[5]),\n descent: signedInt16(tables['hhea'].data[6], tables['hhea'].data[7]),\n };\n\n // PDF FontDescriptor metrics lie -- using data from actual font.\n this.ascent = metricsOverride.ascent / metricsOverride.unitsPerEm;\n this.descent = metricsOverride.descent / metricsOverride.unitsPerEm;\n\n // The 'post' table has glyphs names.\n if (tables['post']) {\n var valid = readPostScriptTable(tables['post'], properties, numGlyphs);\n if (!valid) {\n tables['post'] = null;\n }\n }\n\n var charCodeToGlyphId = [], charCode;\n\n // Helper function to try to skip mapping of empty glyphs.\n function hasGlyph(glyphId) {\n return !missingGlyphs[glyphId];\n }\n\n if (properties.composite) {\n var cidToGidMap = properties.cidToGidMap || [];\n var isCidToGidMapEmpty = cidToGidMap.length === 0;\n\n properties.cMap.forEach(function(charCode, cid) {\n if (cid > 0xffff) {\n throw new FormatError('Max size of CID is 65,535');\n }\n var glyphId = -1;\n if (isCidToGidMapEmpty) {\n glyphId = cid;\n } else if (cidToGidMap[cid] !== undefined) {\n glyphId = cidToGidMap[cid];\n }\n\n if (glyphId >= 0 && glyphId < numGlyphs && hasGlyph(glyphId)) {\n charCodeToGlyphId[charCode] = glyphId;\n }\n });\n if (dupFirstEntry && (isCidToGidMapEmpty || !charCodeToGlyphId[0])) {\n // We don't duplicate the first entry in the `charCodeToGlyphId` map\n // if the font has a `CIDToGIDMap` which has already mapped the first\n // entry to a non-zero `glyphId` (fixes issue7544.pdf).\n charCodeToGlyphId[0] = numGlyphs - 1;\n }\n } else {\n // Most of the following logic in this code branch is based on the\n // 9.6.6.4 of the PDF spec.\n var cmapTable = readCmapTable(tables['cmap'], font, this.isSymbolicFont,\n properties.hasEncoding);\n var cmapPlatformId = cmapTable.platformId;\n var cmapEncodingId = cmapTable.encodingId;\n var cmapMappings = cmapTable.mappings;\n var cmapMappingsLength = cmapMappings.length;\n\n // The spec seems to imply that if the font is symbolic the encoding\n // should be ignored, this doesn't appear to work for 'preistabelle.pdf'\n // where the the font is symbolic and it has an encoding.\n if (properties.hasEncoding &&\n (cmapPlatformId === 3 && cmapEncodingId === 1 ||\n cmapPlatformId === 1 && cmapEncodingId === 0) ||\n (cmapPlatformId === -1 && cmapEncodingId === -1 && // Temporary hack\n !!getEncoding(properties.baseEncodingName))) { // Temporary hack\n // When no preferred cmap table was found and |baseEncodingName| is\n // one of the predefined encodings, we seem to obtain a better\n // |charCodeToGlyphId| map from the code below (fixes bug 1057544).\n // TODO: Note that this is a hack which should be removed as soon as\n // we have proper support for more exotic cmap tables.\n\n var baseEncoding = [];\n if (properties.baseEncodingName === 'MacRomanEncoding' ||\n properties.baseEncodingName === 'WinAnsiEncoding') {\n baseEncoding = getEncoding(properties.baseEncodingName);\n }\n var glyphsUnicodeMap = getGlyphsUnicode();\n for (charCode = 0; charCode < 256; charCode++) {\n var glyphName, standardGlyphName;\n if (this.differences && charCode in this.differences) {\n glyphName = this.differences[charCode];\n } else if (charCode in baseEncoding &&\n baseEncoding[charCode] !== '') {\n glyphName = baseEncoding[charCode];\n } else {\n glyphName = StandardEncoding[charCode];\n }\n if (!glyphName) {\n continue;\n }\n // Ensure that non-standard glyph names are resolved to valid ones.\n standardGlyphName = recoverGlyphName(glyphName, glyphsUnicodeMap);\n\n var unicodeOrCharCode;\n if (cmapPlatformId === 3 && cmapEncodingId === 1) {\n unicodeOrCharCode = glyphsUnicodeMap[standardGlyphName];\n } else if (cmapPlatformId === 1 && cmapEncodingId === 0) {\n // TODO: the encoding needs to be updated with mac os table.\n unicodeOrCharCode = MacRomanEncoding.indexOf(standardGlyphName);\n }\n\n var found = false;\n for (i = 0; i < cmapMappingsLength; ++i) {\n if (cmapMappings[i].charCode !== unicodeOrCharCode) {\n continue;\n }\n charCodeToGlyphId[charCode] = cmapMappings[i].glyphId;\n found = true;\n break;\n }\n if (!found && properties.glyphNames) {\n // Try to map using the post table.\n var glyphId = properties.glyphNames.indexOf(glyphName);\n // The post table ought to use the same kind of glyph names as the\n // `differences` array, but check the standard ones as a fallback.\n if (glyphId === -1 && standardGlyphName !== glyphName) {\n glyphId = properties.glyphNames.indexOf(standardGlyphName);\n }\n if (glyphId > 0 && hasGlyph(glyphId)) {\n charCodeToGlyphId[charCode] = glyphId;\n found = true;\n }\n }\n }\n } else if (cmapPlatformId === 0 && cmapEncodingId === 0) {\n // Default Unicode semantics, use the charcodes as is.\n for (i = 0; i < cmapMappingsLength; ++i) {\n charCodeToGlyphId[cmapMappings[i].charCode] =\n cmapMappings[i].glyphId;\n }\n } else {\n // When there is only a (1, 0) cmap table, the char code is a single\n // byte and it is used directly as the char code.\n\n // When a (3, 0) cmap table is present, it is used instead but the\n // spec has special rules for char codes in the range of 0xF000 to\n // 0xF0FF and it says the (3, 0) table should map the values from\n // the (1, 0) table by prepending 0xF0 to the char codes. To reverse\n // this, the upper bits of the char code are cleared, but only for the\n // special range since some PDFs have char codes outside of this range\n // (e.g. 0x2013) which when masked would overwrite other values in the\n // cmap.\n for (i = 0; i < cmapMappingsLength; ++i) {\n charCode = cmapMappings[i].charCode;\n if (cmapPlatformId === 3 &&\n charCode >= 0xF000 && charCode <= 0xF0FF) {\n charCode &= 0xFF;\n }\n charCodeToGlyphId[charCode] = cmapMappings[i].glyphId;\n }\n }\n }\n\n if (charCodeToGlyphId.length === 0) {\n // defines at least one glyph\n charCodeToGlyphId[0] = 0;\n }\n\n // Converting glyphs and ids into font's cmap table\n var newMapping = adjustMapping(charCodeToGlyphId, properties,\n missingGlyphs);\n this.toFontChar = newMapping.toFontChar;\n tables['cmap'] = {\n tag: 'cmap',\n data: createCmapTable(newMapping.charCodeToGlyphId, numGlyphs),\n };\n\n if (!tables['OS/2'] || !validateOS2Table(tables['OS/2'])) {\n tables['OS/2'] = {\n tag: 'OS/2',\n data: createOS2Table(properties, newMapping.charCodeToGlyphId,\n metricsOverride),\n };\n }\n\n // Rewrite the 'post' table if needed\n if (!tables['post']) {\n tables['post'] = {\n tag: 'post',\n data: createPostTable(properties),\n };\n }\n\n if (!isTrueType) {\n try {\n // Trying to repair CFF file\n cffFile = new Stream(tables['CFF '].data);\n var parser = new CFFParser(cffFile, properties,\n SEAC_ANALYSIS_ENABLED);\n cff = parser.parse();\n var compiler = new CFFCompiler(cff);\n tables['CFF '].data = compiler.compile();\n } catch (e) {\n warn('Failed to compile font ' + properties.loadedName);\n }\n }\n\n // Re-creating 'name' table\n if (!tables['name']) {\n tables['name'] = {\n tag: 'name',\n data: createNameTable(this.name),\n };\n } else {\n // ... using existing 'name' table as prototype\n var namePrototype = readNameTable(tables['name']);\n tables['name'].data = createNameTable(name, namePrototype);\n }\n\n var builder = new OpenTypeFileBuilder(header.version);\n for (var tableTag in tables) {\n builder.addTable(tableTag, tables[tableTag].data);\n }\n return builder.toArray();\n },\n\n convert: function Font_convert(fontName, font, properties) {\n // TODO: Check the charstring widths to determine this.\n properties.fixedPitch = false;\n\n if (properties.builtInEncoding) {\n // For Type1 fonts that do not include either `ToUnicode` or `Encoding`\n // data, attempt to use the `builtInEncoding` to improve text selection.\n adjustToUnicode(properties, properties.builtInEncoding);\n }\n\n var mapping = font.getGlyphMapping(properties);\n var newMapping = adjustMapping(mapping, properties, Object.create(null));\n this.toFontChar = newMapping.toFontChar;\n var numGlyphs = font.numGlyphs;\n\n function getCharCodes(charCodeToGlyphId, glyphId) {\n var charCodes = null;\n for (var charCode in charCodeToGlyphId) {\n if (glyphId === charCodeToGlyphId[charCode]) {\n if (!charCodes) {\n charCodes = [];\n }\n charCodes.push(charCode | 0);\n }\n }\n return charCodes;\n }\n\n function createCharCode(charCodeToGlyphId, glyphId) {\n for (var charCode in charCodeToGlyphId) {\n if (glyphId === charCodeToGlyphId[charCode]) {\n return charCode | 0;\n }\n }\n newMapping.charCodeToGlyphId[newMapping.nextAvailableFontCharCode] =\n glyphId;\n return newMapping.nextAvailableFontCharCode++;\n }\n\n var seacs = font.seacs;\n if (SEAC_ANALYSIS_ENABLED && seacs && seacs.length) {\n var matrix = properties.fontMatrix || FONT_IDENTITY_MATRIX;\n var charset = font.getCharset();\n var seacMap = Object.create(null);\n for (var glyphId in seacs) {\n glyphId |= 0;\n var seac = seacs[glyphId];\n var baseGlyphName = StandardEncoding[seac[2]];\n var accentGlyphName = StandardEncoding[seac[3]];\n var baseGlyphId = charset.indexOf(baseGlyphName);\n var accentGlyphId = charset.indexOf(accentGlyphName);\n if (baseGlyphId < 0 || accentGlyphId < 0) {\n continue;\n }\n var accentOffset = {\n x: seac[0] * matrix[0] + seac[1] * matrix[2] + matrix[4],\n y: seac[0] * matrix[1] + seac[1] * matrix[3] + matrix[5],\n };\n\n var charCodes = getCharCodes(mapping, glyphId);\n if (!charCodes) {\n // There's no point in mapping it if the char code was never mapped\n // to begin with.\n continue;\n }\n for (var i = 0, ii = charCodes.length; i < ii; i++) {\n var charCode = charCodes[i];\n // Find a fontCharCode that maps to the base and accent glyphs.\n // If one doesn't exists, create it.\n var charCodeToGlyphId = newMapping.charCodeToGlyphId;\n var baseFontCharCode = createCharCode(charCodeToGlyphId,\n baseGlyphId);\n var accentFontCharCode = createCharCode(charCodeToGlyphId,\n accentGlyphId);\n seacMap[charCode] = {\n baseFontCharCode,\n accentFontCharCode,\n accentOffset,\n };\n }\n }\n properties.seacMap = seacMap;\n }\n\n var unitsPerEm = 1 / (properties.fontMatrix || FONT_IDENTITY_MATRIX)[0];\n\n var builder = new OpenTypeFileBuilder('\\x4F\\x54\\x54\\x4F');\n // PostScript Font Program\n builder.addTable('CFF ', font.data);\n // OS/2 and Windows Specific metrics\n builder.addTable('OS/2', createOS2Table(properties,\n newMapping.charCodeToGlyphId));\n // Character to glyphs mapping\n builder.addTable('cmap', createCmapTable(newMapping.charCodeToGlyphId,\n numGlyphs));\n // Font header\n builder.addTable('head',\n '\\x00\\x01\\x00\\x00' + // Version number\n '\\x00\\x00\\x10\\x00' + // fontRevision\n '\\x00\\x00\\x00\\x00' + // checksumAdjustement\n '\\x5F\\x0F\\x3C\\xF5' + // magicNumber\n '\\x00\\x00' + // Flags\n safeString16(unitsPerEm) + // unitsPerEM\n '\\x00\\x00\\x00\\x00\\x9e\\x0b\\x7e\\x27' + // creation date\n '\\x00\\x00\\x00\\x00\\x9e\\x0b\\x7e\\x27' + // modifification date\n '\\x00\\x00' + // xMin\n safeString16(properties.descent) + // yMin\n '\\x0F\\xFF' + // xMax\n safeString16(properties.ascent) + // yMax\n string16(properties.italicAngle ? 2 : 0) + // macStyle\n '\\x00\\x11' + // lowestRecPPEM\n '\\x00\\x00' + // fontDirectionHint\n '\\x00\\x00' + // indexToLocFormat\n '\\x00\\x00'); // glyphDataFormat\n\n // Horizontal header\n builder.addTable('hhea',\n '\\x00\\x01\\x00\\x00' + // Version number\n safeString16(properties.ascent) + // Typographic Ascent\n safeString16(properties.descent) + // Typographic Descent\n '\\x00\\x00' + // Line Gap\n '\\xFF\\xFF' + // advanceWidthMax\n '\\x00\\x00' + // minLeftSidebearing\n '\\x00\\x00' + // minRightSidebearing\n '\\x00\\x00' + // xMaxExtent\n safeString16(properties.capHeight) + // caretSlopeRise\n safeString16(Math.tan(properties.italicAngle) *\n properties.xHeight) + // caretSlopeRun\n '\\x00\\x00' + // caretOffset\n '\\x00\\x00' + // -reserved-\n '\\x00\\x00' + // -reserved-\n '\\x00\\x00' + // -reserved-\n '\\x00\\x00' + // -reserved-\n '\\x00\\x00' + // metricDataFormat\n string16(numGlyphs)); // Number of HMetrics\n\n // Horizontal metrics\n builder.addTable('hmtx', (function fontFieldsHmtx() {\n var charstrings = font.charstrings;\n var cffWidths = font.cff ? font.cff.widths : null;\n var hmtx = '\\x00\\x00\\x00\\x00'; // Fake .notdef\n for (var i = 1, ii = numGlyphs; i < ii; i++) {\n var width = 0;\n if (charstrings) {\n var charstring = charstrings[i - 1];\n width = 'width' in charstring ? charstring.width : 0;\n } else if (cffWidths) {\n width = Math.ceil(cffWidths[i] || 0);\n }\n hmtx += string16(width) + string16(0);\n }\n return hmtx;\n })());\n\n // Maximum profile\n builder.addTable('maxp',\n '\\x00\\x00\\x50\\x00' + // Version number\n string16(numGlyphs)); // Num of glyphs\n\n // Naming tables\n builder.addTable('name', createNameTable(fontName));\n\n // PostScript information\n builder.addTable('post', createPostTable(properties));\n\n return builder.toArray();\n },\n\n get spaceWidth() {\n if ('_shadowWidth' in this) {\n return this._shadowWidth;\n }\n\n // trying to estimate space character width\n var possibleSpaceReplacements = ['space', 'minus', 'one', 'i', 'I'];\n var width;\n for (var i = 0, ii = possibleSpaceReplacements.length; i < ii; i++) {\n var glyphName = possibleSpaceReplacements[i];\n // if possible, getting width by glyph name\n if (glyphName in this.widths) {\n width = this.widths[glyphName];\n break;\n }\n var glyphsUnicodeMap = getGlyphsUnicode();\n var glyphUnicode = glyphsUnicodeMap[glyphName];\n // finding the charcode via unicodeToCID map\n var charcode = 0;\n if (this.composite) {\n if (this.cMap.contains(glyphUnicode)) {\n charcode = this.cMap.lookup(glyphUnicode);\n }\n }\n // ... via toUnicode map\n if (!charcode && this.toUnicode) {\n charcode = this.toUnicode.charCodeOf(glyphUnicode);\n }\n // setting it to unicode if negative or undefined\n if (charcode <= 0) {\n charcode = glyphUnicode;\n }\n // trying to get width via charcode\n width = this.widths[charcode];\n if (width) {\n break; // the non-zero width found\n }\n }\n width = width || this.defaultWidth;\n // Do not shadow the property here. See discussion:\n // https://github.com/mozilla/pdf.js/pull/2127#discussion_r1662280\n this._shadowWidth = width;\n return width;\n },\n\n charToGlyph: function Font_charToGlyph(charcode, isSpace) {\n var fontCharCode, width, operatorListId;\n\n var widthCode = charcode;\n if (this.cMap && this.cMap.contains(charcode)) {\n widthCode = this.cMap.lookup(charcode);\n }\n width = this.widths[widthCode];\n width = isNum(width) ? width : this.defaultWidth;\n var vmetric = this.vmetrics && this.vmetrics[widthCode];\n\n var unicode = this.toUnicode.get(charcode) || charcode;\n if (typeof unicode === 'number') {\n unicode = String.fromCharCode(unicode);\n }\n\n var isInFont = charcode in this.toFontChar;\n // First try the toFontChar map, if it's not there then try falling\n // back to the char code.\n fontCharCode = this.toFontChar[charcode] || charcode;\n if (this.missingFile) {\n fontCharCode = mapSpecialUnicodeValues(fontCharCode);\n }\n\n if (this.isType3Font) {\n // Font char code in this case is actually a glyph name.\n operatorListId = fontCharCode;\n }\n\n var accent = null;\n if (this.seacMap && this.seacMap[charcode]) {\n isInFont = true;\n var seac = this.seacMap[charcode];\n fontCharCode = seac.baseFontCharCode;\n accent = {\n fontChar: String.fromCharCode(seac.accentFontCharCode),\n offset: seac.accentOffset,\n };\n }\n\n var fontChar = String.fromCharCode(fontCharCode);\n\n var glyph = this.glyphCache[charcode];\n if (!glyph ||\n !glyph.matchesForCache(fontChar, unicode, accent, width, vmetric,\n operatorListId, isSpace, isInFont)) {\n glyph = new Glyph(fontChar, unicode, accent, width, vmetric,\n operatorListId, isSpace, isInFont);\n this.glyphCache[charcode] = glyph;\n }\n return glyph;\n },\n\n charsToGlyphs: function Font_charsToGlyphs(chars) {\n var charsCache = this.charsCache;\n var glyphs, glyph, charcode;\n\n // if we translated this string before, just grab it from the cache\n if (charsCache) {\n glyphs = charsCache[chars];\n if (glyphs) {\n return glyphs;\n }\n }\n\n // lazily create the translation cache\n if (!charsCache) {\n charsCache = this.charsCache = Object.create(null);\n }\n\n glyphs = [];\n var charsCacheKey = chars;\n var i = 0, ii;\n\n if (this.cMap) {\n // composite fonts have multi-byte strings convert the string from\n // single-byte to multi-byte\n var c = Object.create(null);\n while (i < chars.length) {\n this.cMap.readCharCode(chars, i, c);\n charcode = c.charcode;\n var length = c.length;\n i += length;\n // Space is char with code 0x20 and length 1 in multiple-byte codes.\n var isSpace = length === 1 && chars.charCodeAt(i - 1) === 0x20;\n glyph = this.charToGlyph(charcode, isSpace);\n glyphs.push(glyph);\n }\n } else {\n for (i = 0, ii = chars.length; i < ii; ++i) {\n charcode = chars.charCodeAt(i);\n glyph = this.charToGlyph(charcode, charcode === 0x20);\n glyphs.push(glyph);\n }\n }\n\n // Enter the translated string into the cache\n return (charsCache[charsCacheKey] = glyphs);\n },\n };\n\n return Font;\n})();\n\nvar ErrorFont = (function ErrorFontClosure() {\n function ErrorFont(error) {\n this.error = error;\n this.loadedName = 'g_font_error';\n this.loading = false;\n }\n\n ErrorFont.prototype = {\n charsToGlyphs: function ErrorFont_charsToGlyphs() {\n return [];\n },\n exportData: function ErrorFont_exportData() {\n return { error: this.error, };\n },\n };\n\n return ErrorFont;\n})();\n\n/**\n * Shared logic for building a char code to glyph id mapping for Type1 and\n * simple CFF fonts. See section 9.6.6.2 of the spec.\n * @param {Object} properties Font properties object.\n * @param {Object} builtInEncoding The encoding contained within the actual font\n * data.\n * @param {Array} glyphNames Array of glyph names where the index is the\n * glyph ID.\n * @returns {Object} A char code to glyph ID map.\n */\nfunction type1FontGlyphMapping(properties, builtInEncoding, glyphNames) {\n var charCodeToGlyphId = Object.create(null);\n var glyphId, charCode, baseEncoding;\n var isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);\n\n if (properties.baseEncodingName) {\n // If a valid base encoding name was used, the mapping is initialized with\n // that.\n baseEncoding = getEncoding(properties.baseEncodingName);\n for (charCode = 0; charCode < baseEncoding.length; charCode++) {\n glyphId = glyphNames.indexOf(baseEncoding[charCode]);\n if (glyphId >= 0) {\n charCodeToGlyphId[charCode] = glyphId;\n } else {\n charCodeToGlyphId[charCode] = 0; // notdef\n }\n }\n } else if (isSymbolicFont) {\n // For a symbolic font the encoding should be the fonts built-in encoding.\n for (charCode in builtInEncoding) {\n charCodeToGlyphId[charCode] = builtInEncoding[charCode];\n }\n } else {\n // For non-symbolic fonts that don't have a base encoding the standard\n // encoding should be used.\n baseEncoding = StandardEncoding;\n for (charCode = 0; charCode < baseEncoding.length; charCode++) {\n glyphId = glyphNames.indexOf(baseEncoding[charCode]);\n if (glyphId >= 0) {\n charCodeToGlyphId[charCode] = glyphId;\n } else {\n charCodeToGlyphId[charCode] = 0; // notdef\n }\n }\n }\n\n // Lastly, merge in the differences.\n var differences = properties.differences, glyphsUnicodeMap;\n if (differences) {\n for (charCode in differences) {\n var glyphName = differences[charCode];\n glyphId = glyphNames.indexOf(glyphName);\n\n if (glyphId === -1) {\n if (!glyphsUnicodeMap) {\n glyphsUnicodeMap = getGlyphsUnicode();\n }\n var standardGlyphName = recoverGlyphName(glyphName, glyphsUnicodeMap);\n if (standardGlyphName !== glyphName) {\n glyphId = glyphNames.indexOf(standardGlyphName);\n }\n }\n if (glyphId >= 0) {\n charCodeToGlyphId[charCode] = glyphId;\n } else {\n charCodeToGlyphId[charCode] = 0; // notdef\n }\n }\n }\n return charCodeToGlyphId;\n}\n\n// Type1Font is also a CIDFontType0.\nvar Type1Font = (function Type1FontClosure() {\n function findBlock(streamBytes, signature, startIndex) {\n var streamBytesLength = streamBytes.length;\n var signatureLength = signature.length;\n var scanLength = streamBytesLength - signatureLength;\n\n var i = startIndex, j, found = false;\n while (i < scanLength) {\n j = 0;\n while (j < signatureLength && streamBytes[i + j] === signature[j]) {\n j++;\n }\n if (j >= signatureLength) { // `signature` found, skip over whitespace.\n i += j;\n while (i < streamBytesLength && isSpace(streamBytes[i])) {\n i++;\n }\n found = true;\n break;\n }\n i++;\n }\n return {\n found,\n length: i,\n };\n }\n\n function getHeaderBlock(stream, suggestedLength) {\n var EEXEC_SIGNATURE = [0x65, 0x65, 0x78, 0x65, 0x63];\n\n var streamStartPos = stream.pos; // Save the initial stream position.\n var headerBytes, headerBytesLength, block;\n try {\n headerBytes = stream.getBytes(suggestedLength);\n headerBytesLength = headerBytes.length;\n } catch (ex) {\n if (ex instanceof MissingDataException) {\n throw ex;\n }\n // Ignore errors if the `suggestedLength` is huge enough that a Uint8Array\n // cannot hold the result of `getBytes`, and fallback to simply checking\n // the entire stream (fixes issue3928.pdf).\n }\n\n if (headerBytesLength === suggestedLength) {\n // Most of the time `suggestedLength` is correct, so to speed things up we\n // initially only check the last few bytes to see if the header was found.\n // Otherwise we (potentially) check the entire stream to prevent errors in\n // `Type1Parser` (fixes issue5686.pdf).\n block = findBlock(headerBytes, EEXEC_SIGNATURE,\n suggestedLength - 2 * EEXEC_SIGNATURE.length);\n\n if (block.found && block.length === suggestedLength) {\n return {\n stream: new Stream(headerBytes),\n length: suggestedLength,\n };\n }\n }\n warn('Invalid \"Length1\" property in Type1 font -- trying to recover.');\n stream.pos = streamStartPos; // Reset the stream position.\n\n var SCAN_BLOCK_LENGTH = 2048;\n var actualLength;\n while (true) {\n var scanBytes = stream.peekBytes(SCAN_BLOCK_LENGTH);\n block = findBlock(scanBytes, EEXEC_SIGNATURE, 0);\n\n if (block.length === 0) {\n break;\n }\n stream.pos += block.length; // Update the stream position.\n\n if (block.found) {\n actualLength = stream.pos - streamStartPos;\n break;\n }\n }\n stream.pos = streamStartPos; // Reset the stream position.\n\n if (actualLength) {\n return {\n stream: new Stream(stream.getBytes(actualLength)),\n length: actualLength,\n };\n }\n warn('Unable to recover \"Length1\" property in Type1 font -- using as is.');\n return {\n stream: new Stream(stream.getBytes(suggestedLength)),\n length: suggestedLength,\n };\n }\n\n function getEexecBlock(stream, suggestedLength) {\n // We should ideally parse the eexec block to ensure that `suggestedLength`\n // is correct, so we don't truncate the block data if it's too small.\n // However, this would also require checking if the fixed-content portion\n // exists (using the 'Length3' property), and ensuring that it's valid.\n //\n // Given that `suggestedLength` almost always is correct, all the validation\n // would require a great deal of unnecessary parsing for most fonts.\n // To save time, we always fetch the entire stream instead, which also avoid\n // issues if `suggestedLength` is huge (see comment in `getHeaderBlock`).\n //\n // NOTE: This means that the function can include the fixed-content portion\n // in the returned eexec block. In practice this does *not* seem to matter,\n // since `Type1Parser_extractFontProgram` will skip over any non-commands.\n var eexecBytes = stream.getBytes();\n return {\n stream: new Stream(eexecBytes),\n length: eexecBytes.length,\n };\n }\n\n function Type1Font(name, file, properties) {\n // Some bad generators embed pfb file as is, we have to strip 6-byte header.\n // Also, length1 and length2 might be off by 6 bytes as well.\n // http://www.math.ubc.ca/~cass/piscript/type1.pdf\n var PFB_HEADER_SIZE = 6;\n var headerBlockLength = properties.length1;\n var eexecBlockLength = properties.length2;\n var pfbHeader = file.peekBytes(PFB_HEADER_SIZE);\n var pfbHeaderPresent = pfbHeader[0] === 0x80 && pfbHeader[1] === 0x01;\n if (pfbHeaderPresent) {\n file.skip(PFB_HEADER_SIZE);\n headerBlockLength = (pfbHeader[5] << 24) | (pfbHeader[4] << 16) |\n (pfbHeader[3] << 8) | pfbHeader[2];\n }\n\n // Get the data block containing glyphs and subrs information\n var headerBlock = getHeaderBlock(file, headerBlockLength);\n headerBlockLength = headerBlock.length;\n var headerBlockParser = new Type1Parser(headerBlock.stream, false,\n SEAC_ANALYSIS_ENABLED);\n headerBlockParser.extractFontHeader(properties);\n\n if (pfbHeaderPresent) {\n pfbHeader = file.getBytes(PFB_HEADER_SIZE);\n eexecBlockLength = (pfbHeader[5] << 24) | (pfbHeader[4] << 16) |\n (pfbHeader[3] << 8) | pfbHeader[2];\n }\n\n // Decrypt the data blocks and retrieve it's content\n var eexecBlock = getEexecBlock(file, eexecBlockLength);\n eexecBlockLength = eexecBlock.length;\n var eexecBlockParser = new Type1Parser(eexecBlock.stream, true,\n SEAC_ANALYSIS_ENABLED);\n var data = eexecBlockParser.extractFontProgram();\n for (var info in data.properties) {\n properties[info] = data.properties[info];\n }\n\n var charstrings = data.charstrings;\n var type2Charstrings = this.getType2Charstrings(charstrings);\n var subrs = this.getType2Subrs(data.subrs);\n\n this.charstrings = charstrings;\n this.data = this.wrap(name, type2Charstrings, this.charstrings,\n subrs, properties);\n this.seacs = this.getSeacs(data.charstrings);\n }\n\n Type1Font.prototype = {\n get numGlyphs() {\n return this.charstrings.length + 1;\n },\n\n getCharset: function Type1Font_getCharset() {\n var charset = ['.notdef'];\n var charstrings = this.charstrings;\n for (var glyphId = 0; glyphId < charstrings.length; glyphId++) {\n charset.push(charstrings[glyphId].glyphName);\n }\n return charset;\n },\n\n getGlyphMapping: function Type1Font_getGlyphMapping(properties) {\n var charstrings = this.charstrings;\n var glyphNames = ['.notdef'], glyphId;\n for (glyphId = 0; glyphId < charstrings.length; glyphId++) {\n glyphNames.push(charstrings[glyphId].glyphName);\n }\n var encoding = properties.builtInEncoding;\n if (encoding) {\n var builtInEncoding = Object.create(null);\n for (var charCode in encoding) {\n glyphId = glyphNames.indexOf(encoding[charCode]);\n if (glyphId >= 0) {\n builtInEncoding[charCode] = glyphId;\n }\n }\n }\n\n return type1FontGlyphMapping(properties, builtInEncoding, glyphNames);\n },\n\n getSeacs: function Type1Font_getSeacs(charstrings) {\n var i, ii;\n var seacMap = [];\n for (i = 0, ii = charstrings.length; i < ii; i++) {\n var charstring = charstrings[i];\n if (charstring.seac) {\n // Offset by 1 for .notdef\n seacMap[i + 1] = charstring.seac;\n }\n }\n return seacMap;\n },\n\n getType2Charstrings: function Type1Font_getType2Charstrings(\n type1Charstrings) {\n var type2Charstrings = [];\n for (var i = 0, ii = type1Charstrings.length; i < ii; i++) {\n type2Charstrings.push(type1Charstrings[i].charstring);\n }\n return type2Charstrings;\n },\n\n getType2Subrs: function Type1Font_getType2Subrs(type1Subrs) {\n var bias = 0;\n var count = type1Subrs.length;\n if (count < 1133) {\n bias = 107;\n } else if (count < 33769) {\n bias = 1131;\n } else {\n bias = 32768;\n }\n\n // Add a bunch of empty subrs to deal with the Type2 bias\n var type2Subrs = [];\n var i;\n for (i = 0; i < bias; i++) {\n type2Subrs.push([0x0B]);\n }\n\n for (i = 0; i < count; i++) {\n type2Subrs.push(type1Subrs[i]);\n }\n\n return type2Subrs;\n },\n\n wrap: function Type1Font_wrap(name, glyphs, charstrings, subrs,\n properties) {\n var cff = new CFF();\n cff.header = new CFFHeader(1, 0, 4, 4);\n\n cff.names = [name];\n\n var topDict = new CFFTopDict();\n // CFF strings IDs 0...390 are predefined names, so refering\n // to entries in our own String INDEX starts at SID 391.\n topDict.setByName('version', 391);\n topDict.setByName('Notice', 392);\n topDict.setByName('FullName', 393);\n topDict.setByName('FamilyName', 394);\n topDict.setByName('Weight', 395);\n topDict.setByName('Encoding', null); // placeholder\n topDict.setByName('FontMatrix', properties.fontMatrix);\n topDict.setByName('FontBBox', properties.bbox);\n topDict.setByName('charset', null); // placeholder\n topDict.setByName('CharStrings', null); // placeholder\n topDict.setByName('Private', null); // placeholder\n cff.topDict = topDict;\n\n var strings = new CFFStrings();\n strings.add('Version 0.11'); // Version\n strings.add('See original notice'); // Notice\n strings.add(name); // FullName\n strings.add(name); // FamilyName\n strings.add('Medium'); // Weight\n cff.strings = strings;\n\n cff.globalSubrIndex = new CFFIndex();\n\n var count = glyphs.length;\n var charsetArray = [0];\n var i, ii;\n for (i = 0; i < count; i++) {\n var index = CFFStandardStrings.indexOf(charstrings[i].glyphName);\n // TODO: Insert the string and correctly map it. Previously it was\n // thought mapping names that aren't in the standard strings to .notdef\n // was fine, however in issue818 when mapping them all to .notdef the\n // adieresis glyph no longer worked.\n if (index === -1) {\n index = 0;\n }\n charsetArray.push((index >> 8) & 0xff, index & 0xff);\n }\n cff.charset = new CFFCharset(false, 0, [], charsetArray);\n\n var charStringsIndex = new CFFIndex();\n charStringsIndex.add([0x8B, 0x0E]); // .notdef\n for (i = 0; i < count; i++) {\n var glyph = glyphs[i];\n // If the CharString outline is empty, replace it with .notdef to\n // prevent OTS from rejecting the font (fixes bug1252420.pdf).\n if (glyph.length === 0) {\n charStringsIndex.add([0x8B, 0x0E]); // .notdef\n continue;\n }\n charStringsIndex.add(glyph);\n }\n cff.charStrings = charStringsIndex;\n\n var privateDict = new CFFPrivateDict();\n privateDict.setByName('Subrs', null); // placeholder\n var fields = [\n 'BlueValues',\n 'OtherBlues',\n 'FamilyBlues',\n 'FamilyOtherBlues',\n 'StemSnapH',\n 'StemSnapV',\n 'BlueShift',\n 'BlueFuzz',\n 'BlueScale',\n 'LanguageGroup',\n 'ExpansionFactor',\n 'ForceBold',\n 'StdHW',\n 'StdVW'\n ];\n for (i = 0, ii = fields.length; i < ii; i++) {\n var field = fields[i];\n if (!(field in properties.privateData)) {\n continue;\n }\n var value = properties.privateData[field];\n if (isArray(value)) {\n // All of the private dictionary array data in CFF must be stored as\n // \"delta-encoded\" numbers.\n for (var j = value.length - 1; j > 0; j--) {\n value[j] -= value[j - 1]; // ... difference from previous value\n }\n }\n privateDict.setByName(field, value);\n }\n cff.topDict.privateDict = privateDict;\n\n var subrIndex = new CFFIndex();\n for (i = 0, ii = subrs.length; i < ii; i++) {\n subrIndex.add(subrs[i]);\n }\n privateDict.subrsIndex = subrIndex;\n\n var compiler = new CFFCompiler(cff);\n return compiler.compile();\n },\n };\n\n return Type1Font;\n})();\n\nvar CFFFont = (function CFFFontClosure() {\n function CFFFont(file, properties) {\n this.properties = properties;\n\n var parser = new CFFParser(file, properties, SEAC_ANALYSIS_ENABLED);\n this.cff = parser.parse();\n var compiler = new CFFCompiler(this.cff);\n this.seacs = this.cff.seacs;\n try {\n this.data = compiler.compile();\n } catch (e) {\n warn('Failed to compile font ' + properties.loadedName);\n // There may have just been an issue with the compiler, set the data\n // anyway and hope the font loaded.\n this.data = file;\n }\n }\n\n CFFFont.prototype = {\n get numGlyphs() {\n return this.cff.charStrings.count;\n },\n getCharset: function CFFFont_getCharset() {\n return this.cff.charset.charset;\n },\n getGlyphMapping: function CFFFont_getGlyphMapping() {\n var cff = this.cff;\n var properties = this.properties;\n var charsets = cff.charset.charset;\n var charCodeToGlyphId;\n var glyphId;\n\n if (properties.composite) {\n charCodeToGlyphId = Object.create(null);\n if (cff.isCIDFont) {\n // If the font is actually a CID font then we should use the charset\n // to map CIDs to GIDs.\n for (glyphId = 0; glyphId < charsets.length; glyphId++) {\n var cid = charsets[glyphId];\n var charCode = properties.cMap.charCodeOf(cid);\n charCodeToGlyphId[charCode] = glyphId;\n }\n } else {\n // If it is NOT actually a CID font then CIDs should be mapped\n // directly to GIDs.\n for (glyphId = 0; glyphId < cff.charStrings.count; glyphId++) {\n charCodeToGlyphId[glyphId] = glyphId;\n }\n }\n return charCodeToGlyphId;\n }\n\n var encoding = cff.encoding ? cff.encoding.encoding : null;\n charCodeToGlyphId = type1FontGlyphMapping(properties, encoding, charsets);\n return charCodeToGlyphId;\n },\n };\n\n return CFFFont;\n})();\n\n// Workaround for seac on Windows.\n(function checkSeacSupport() {\n if (typeof navigator !== 'undefined' && /Windows/.test(navigator.userAgent)) {\n SEAC_ANALYSIS_ENABLED = true;\n }\n})();\n\n// Workaround for Private Use Area characters in Chrome on Windows\n// http://code.google.com/p/chromium/issues/detail?id=122465\n// https://github.com/mozilla/pdf.js/issues/1689\n(function checkChromeWindows() {\n if (typeof navigator !== 'undefined' &&\n /Windows.*Chrome/.test(navigator.userAgent)) {\n SKIP_PRIVATE_USE_RANGE_F000_TO_F01F = true;\n }\n})();\n\nexport {\n SEAC_ANALYSIS_ENABLED,\n PRIVATE_USE_OFFSET_START,\n PRIVATE_USE_OFFSET_END,\n ErrorFont,\n Font,\n FontFlags,\n ToUnicodeMap,\n IdentityToUnicodeMap,\n ProblematicCharRanges,\n getFontType,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/fonts.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n assert, FormatError, ImageKind, info, isArray, warn\n} from '../shared/util';\nimport { DecodeStream, JpegStream } from './stream';\nimport { isStream, Name } from './primitives';\nimport { ColorSpace } from './colorspace';\nimport { JpxImage } from './jpx';\n\nvar PDFImage = (function PDFImageClosure() {\n /**\n * Decodes the image using native decoder if possible. Resolves the promise\n * when the image data is ready.\n */\n function handleImageData(image, nativeDecoder) {\n if (nativeDecoder && nativeDecoder.canDecode(image)) {\n return nativeDecoder.decode(image);\n }\n return Promise.resolve(image);\n }\n\n /**\n * Decode and clamp a value. The formula is different from the spec because we\n * don't decode to float range [0,1], we decode it in the [0,max] range.\n */\n function decodeAndClamp(value, addend, coefficient, max) {\n value = addend + value * coefficient;\n // Clamp the value to the range\n return (value < 0 ? 0 : (value > max ? max : value));\n }\n\n /**\n * Resizes an image mask with 1 component.\n * @param {TypedArray} src - The source buffer.\n * @param {Number} bpc - Number of bits per component.\n * @param {Number} w1 - Original width.\n * @param {Number} h1 - Original height.\n * @param {Number} w2 - New width.\n * @param {Number} h2 - New height.\n * @returns {TypedArray} The resized image mask buffer.\n */\n function resizeImageMask(src, bpc, w1, h1, w2, h2) {\n var length = w2 * h2;\n var dest = (bpc <= 8 ? new Uint8Array(length) :\n (bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length)));\n var xRatio = w1 / w2;\n var yRatio = h1 / h2;\n var i, j, py, newIndex = 0, oldIndex;\n var xScaled = new Uint16Array(w2);\n var w1Scanline = w1;\n\n for (i = 0; i < w2; i++) {\n xScaled[i] = Math.floor(i * xRatio);\n }\n for (i = 0; i < h2; i++) {\n py = Math.floor(i * yRatio) * w1Scanline;\n for (j = 0; j < w2; j++) {\n oldIndex = py + xScaled[j];\n dest[newIndex++] = src[oldIndex];\n }\n }\n return dest;\n }\n\n function PDFImage(xref, res, image, inline, smask, mask, isMask) {\n this.image = image;\n var dict = image.dict;\n if (dict.has('Filter')) {\n var filter = dict.get('Filter').name;\n if (filter === 'JPXDecode') {\n var jpxImage = new JpxImage();\n jpxImage.parseImageProperties(image.stream);\n image.stream.reset();\n image.bitsPerComponent = jpxImage.bitsPerComponent;\n image.numComps = jpxImage.componentsCount;\n } else if (filter === 'JBIG2Decode') {\n image.bitsPerComponent = 1;\n image.numComps = 1;\n }\n }\n // TODO cache rendered images?\n\n this.width = dict.get('Width', 'W');\n this.height = dict.get('Height', 'H');\n\n if (this.width < 1 || this.height < 1) {\n throw new FormatError(`Invalid image width: ${this.width} or ` +\n `height: ${this.height}`);\n }\n\n this.interpolate = dict.get('Interpolate', 'I') || false;\n this.imageMask = dict.get('ImageMask', 'IM') || false;\n this.matte = dict.get('Matte') || false;\n\n var bitsPerComponent = image.bitsPerComponent;\n if (!bitsPerComponent) {\n bitsPerComponent = dict.get('BitsPerComponent', 'BPC');\n if (!bitsPerComponent) {\n if (this.imageMask) {\n bitsPerComponent = 1;\n } else {\n throw new FormatError(\n `Bits per component missing in image: ${this.imageMask}`);\n }\n }\n }\n this.bpc = bitsPerComponent;\n\n if (!this.imageMask) {\n var colorSpace = dict.get('ColorSpace', 'CS');\n if (!colorSpace) {\n info('JPX images (which do not require color spaces)');\n switch (image.numComps) {\n case 1:\n colorSpace = Name.get('DeviceGray');\n break;\n case 3:\n colorSpace = Name.get('DeviceRGB');\n break;\n case 4:\n colorSpace = Name.get('DeviceCMYK');\n break;\n default:\n throw new Error(`JPX images with ${this.numComps} ` +\n 'color components not supported.');\n }\n }\n this.colorSpace = ColorSpace.parse(colorSpace, xref, res);\n this.numComps = this.colorSpace.numComps;\n }\n\n this.decode = dict.getArray('Decode', 'D');\n this.needsDecode = false;\n if (this.decode &&\n ((this.colorSpace && !this.colorSpace.isDefaultDecode(this.decode)) ||\n (isMask && !ColorSpace.isDefaultDecode(this.decode, 1)))) {\n this.needsDecode = true;\n // Do some preprocessing to avoid more math.\n var max = (1 << bitsPerComponent) - 1;\n this.decodeCoefficients = [];\n this.decodeAddends = [];\n for (var i = 0, j = 0; i < this.decode.length; i += 2, ++j) {\n var dmin = this.decode[i];\n var dmax = this.decode[i + 1];\n this.decodeCoefficients[j] = dmax - dmin;\n this.decodeAddends[j] = max * dmin;\n }\n }\n\n if (smask) {\n this.smask = new PDFImage(xref, res, smask, false);\n } else if (mask) {\n if (isStream(mask)) {\n var maskDict = mask.dict, imageMask = maskDict.get('ImageMask', 'IM');\n if (!imageMask) {\n warn('Ignoring /Mask in image without /ImageMask.');\n } else {\n this.mask = new PDFImage(xref, res, mask, false, null, null, true);\n }\n } else {\n // Color key mask (just an array).\n this.mask = mask;\n }\n }\n }\n /**\n * Handles processing of image data and returns the Promise that is resolved\n * with a PDFImage when the image is ready to be used.\n */\n PDFImage.buildImage = function PDFImage_buildImage(handler, xref,\n res, image, inline,\n nativeDecoder) {\n var imagePromise = handleImageData(image, nativeDecoder);\n var smaskPromise;\n var maskPromise;\n\n var smask = image.dict.get('SMask');\n var mask = image.dict.get('Mask');\n\n if (smask) {\n smaskPromise = handleImageData(smask, nativeDecoder);\n maskPromise = Promise.resolve(null);\n } else {\n smaskPromise = Promise.resolve(null);\n if (mask) {\n if (isStream(mask)) {\n maskPromise = handleImageData(mask, nativeDecoder);\n } else if (isArray(mask)) {\n maskPromise = Promise.resolve(mask);\n } else {\n warn('Unsupported mask format.');\n maskPromise = Promise.resolve(null);\n }\n } else {\n maskPromise = Promise.resolve(null);\n }\n }\n return Promise.all([imagePromise, smaskPromise, maskPromise]).then(\n function(results) {\n var imageData = results[0];\n var smaskData = results[1];\n var maskData = results[2];\n return new PDFImage(xref, res, imageData, inline, smaskData, maskData);\n });\n };\n\n PDFImage.createMask =\n function PDFImage_createMask(imgArray, width, height,\n imageIsFromDecodeStream, inverseDecode) {\n\n // |imgArray| might not contain full data for every pixel of the mask, so\n // we need to distinguish between |computedLength| and |actualLength|.\n // In particular, if inverseDecode is true, then the array we return must\n // have a length of |computedLength|.\n\n var computedLength = ((width + 7) >> 3) * height;\n var actualLength = imgArray.byteLength;\n var haveFullData = computedLength === actualLength;\n var data, i;\n\n if (imageIsFromDecodeStream && (!inverseDecode || haveFullData)) {\n // imgArray came from a DecodeStream and its data is in an appropriate\n // form, so we can just transfer it.\n data = imgArray;\n } else if (!inverseDecode) {\n data = new Uint8Array(actualLength);\n data.set(imgArray);\n } else {\n data = new Uint8Array(computedLength);\n data.set(imgArray);\n for (i = actualLength; i < computedLength; i++) {\n data[i] = 0xff;\n }\n }\n\n // If necessary, invert the original mask data (but not any extra we might\n // have added above). It's safe to modify the array -- whether it's the\n // original or a copy, we're about to transfer it anyway, so nothing else\n // in this thread can be relying on its contents.\n if (inverseDecode) {\n for (i = 0; i < actualLength; i++) {\n data[i] = ~data[i];\n }\n }\n\n return { data, width, height, };\n };\n\n PDFImage.prototype = {\n get drawWidth() {\n return Math.max(this.width,\n this.smask && this.smask.width || 0,\n this.mask && this.mask.width || 0);\n },\n\n get drawHeight() {\n return Math.max(this.height,\n this.smask && this.smask.height || 0,\n this.mask && this.mask.height || 0);\n },\n\n decodeBuffer: function PDFImage_decodeBuffer(buffer) {\n var bpc = this.bpc;\n var numComps = this.numComps;\n\n var decodeAddends = this.decodeAddends;\n var decodeCoefficients = this.decodeCoefficients;\n var max = (1 << bpc) - 1;\n var i, ii;\n\n if (bpc === 1) {\n // If the buffer needed decode that means it just needs to be inverted.\n for (i = 0, ii = buffer.length; i < ii; i++) {\n buffer[i] = +!(buffer[i]);\n }\n return;\n }\n var index = 0;\n for (i = 0, ii = this.width * this.height; i < ii; i++) {\n for (var j = 0; j < numComps; j++) {\n buffer[index] = decodeAndClamp(buffer[index], decodeAddends[j],\n decodeCoefficients[j], max);\n index++;\n }\n }\n },\n\n getComponents: function PDFImage_getComponents(buffer) {\n var bpc = this.bpc;\n\n // This image doesn't require any extra work.\n if (bpc === 8) {\n return buffer;\n }\n\n var width = this.width;\n var height = this.height;\n var numComps = this.numComps;\n\n var length = width * height * numComps;\n var bufferPos = 0;\n var output = (bpc <= 8 ? new Uint8Array(length) :\n (bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length)));\n var rowComps = width * numComps;\n\n var max = (1 << bpc) - 1;\n var i = 0, ii, buf;\n\n if (bpc === 1) {\n // Optimization for reading 1 bpc images.\n var mask, loop1End, loop2End;\n for (var j = 0; j < height; j++) {\n loop1End = i + (rowComps & ~7);\n loop2End = i + rowComps;\n\n // unroll loop for all full bytes\n while (i < loop1End) {\n buf = buffer[bufferPos++];\n output[i] = (buf >> 7) & 1;\n output[i + 1] = (buf >> 6) & 1;\n output[i + 2] = (buf >> 5) & 1;\n output[i + 3] = (buf >> 4) & 1;\n output[i + 4] = (buf >> 3) & 1;\n output[i + 5] = (buf >> 2) & 1;\n output[i + 6] = (buf >> 1) & 1;\n output[i + 7] = buf & 1;\n i += 8;\n }\n\n // handle remaining bits\n if (i < loop2End) {\n buf = buffer[bufferPos++];\n mask = 128;\n while (i < loop2End) {\n output[i++] = +!!(buf & mask);\n mask >>= 1;\n }\n }\n }\n } else {\n // The general case that handles all other bpc values.\n var bits = 0;\n buf = 0;\n for (i = 0, ii = length; i < ii; ++i) {\n if (i % rowComps === 0) {\n buf = 0;\n bits = 0;\n }\n\n while (bits < bpc) {\n buf = (buf << 8) | buffer[bufferPos++];\n bits += 8;\n }\n\n var remainingBits = bits - bpc;\n var value = buf >> remainingBits;\n output[i] = (value < 0 ? 0 : (value > max ? max : value));\n buf = buf & ((1 << remainingBits) - 1);\n bits = remainingBits;\n }\n }\n return output;\n },\n\n fillOpacity: function PDFImage_fillOpacity(rgbaBuf, width, height,\n actualHeight, image) {\n var smask = this.smask;\n var mask = this.mask;\n var alphaBuf, sw, sh, i, ii, j;\n\n if (smask) {\n sw = smask.width;\n sh = smask.height;\n alphaBuf = new Uint8Array(sw * sh);\n smask.fillGrayBuffer(alphaBuf);\n if (sw !== width || sh !== height) {\n alphaBuf = resizeImageMask(alphaBuf, smask.bpc, sw, sh,\n width, height);\n }\n } else if (mask) {\n if (mask instanceof PDFImage) {\n sw = mask.width;\n sh = mask.height;\n alphaBuf = new Uint8Array(sw * sh);\n mask.numComps = 1;\n mask.fillGrayBuffer(alphaBuf);\n\n // Need to invert values in rgbaBuf\n for (i = 0, ii = sw * sh; i < ii; ++i) {\n alphaBuf[i] = 255 - alphaBuf[i];\n }\n\n if (sw !== width || sh !== height) {\n alphaBuf = resizeImageMask(alphaBuf, mask.bpc, sw, sh,\n width, height);\n }\n } else if (isArray(mask)) {\n // Color key mask: if any of the components are outside the range\n // then they should be painted.\n alphaBuf = new Uint8Array(width * height);\n var numComps = this.numComps;\n for (i = 0, ii = width * height; i < ii; ++i) {\n var opacity = 0;\n var imageOffset = i * numComps;\n for (j = 0; j < numComps; ++j) {\n var color = image[imageOffset + j];\n var maskOffset = j * 2;\n if (color < mask[maskOffset] || color > mask[maskOffset + 1]) {\n opacity = 255;\n break;\n }\n }\n alphaBuf[i] = opacity;\n }\n } else {\n throw new FormatError('Unknown mask format.');\n }\n }\n\n if (alphaBuf) {\n for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {\n rgbaBuf[j] = alphaBuf[i];\n }\n } else {\n // No mask.\n for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {\n rgbaBuf[j] = 255;\n }\n }\n },\n\n undoPreblend: function PDFImage_undoPreblend(buffer, width, height) {\n var matte = this.smask && this.smask.matte;\n if (!matte) {\n return;\n }\n var matteRgb = this.colorSpace.getRgb(matte, 0);\n var matteR = matteRgb[0];\n var matteG = matteRgb[1];\n var matteB = matteRgb[2];\n var length = width * height * 4;\n var r, g, b;\n for (var i = 0; i < length; i += 4) {\n var alpha = buffer[i + 3];\n if (alpha === 0) {\n // according formula we have to get Infinity in all components\n // making it white (typical paper color) should be okay\n buffer[i] = 255;\n buffer[i + 1] = 255;\n buffer[i + 2] = 255;\n continue;\n }\n var k = 255 / alpha;\n r = (buffer[i] - matteR) * k + matteR;\n g = (buffer[i + 1] - matteG) * k + matteG;\n b = (buffer[i + 2] - matteB) * k + matteB;\n buffer[i] = r <= 0 ? 0 : r >= 255 ? 255 : r | 0;\n buffer[i + 1] = g <= 0 ? 0 : g >= 255 ? 255 : g | 0;\n buffer[i + 2] = b <= 0 ? 0 : b >= 255 ? 255 : b | 0;\n }\n },\n\n createImageData: function PDFImage_createImageData(forceRGBA) {\n var drawWidth = this.drawWidth;\n var drawHeight = this.drawHeight;\n var imgData = { // other fields are filled in below\n width: drawWidth,\n height: drawHeight,\n };\n\n var numComps = this.numComps;\n var originalWidth = this.width;\n var originalHeight = this.height;\n var bpc = this.bpc;\n\n // Rows start at byte boundary.\n var rowBytes = (originalWidth * numComps * bpc + 7) >> 3;\n var imgArray;\n\n if (!forceRGBA) {\n // If it is a 1-bit-per-pixel grayscale (i.e. black-and-white) image\n // without any complications, we pass a same-sized copy to the main\n // thread rather than expanding by 32x to RGBA form. This saves *lots*\n // of memory for many scanned documents. It's also much faster.\n //\n // Similarly, if it is a 24-bit-per pixel RGB image without any\n // complications, we avoid expanding by 1.333x to RGBA form.\n var kind;\n if (this.colorSpace.name === 'DeviceGray' && bpc === 1) {\n kind = ImageKind.GRAYSCALE_1BPP;\n } else if (this.colorSpace.name === 'DeviceRGB' && bpc === 8 &&\n !this.needsDecode) {\n kind = ImageKind.RGB_24BPP;\n }\n if (kind && !this.smask && !this.mask &&\n drawWidth === originalWidth && drawHeight === originalHeight) {\n imgData.kind = kind;\n\n imgArray = this.getImageBytes(originalHeight * rowBytes);\n // If imgArray came from a DecodeStream, we're safe to transfer it\n // (and thus detach its underlying buffer) because it will constitute\n // the entire DecodeStream's data. But if it came from a Stream, we\n // need to copy it because it'll only be a portion of the Stream's\n // data, and the rest will be read later on.\n if (this.image instanceof DecodeStream) {\n imgData.data = imgArray;\n } else {\n var newArray = new Uint8Array(imgArray.length);\n newArray.set(imgArray);\n imgData.data = newArray;\n }\n if (this.needsDecode) {\n // Invert the buffer (which must be grayscale if we reached here).\n assert(kind === ImageKind.GRAYSCALE_1BPP);\n var buffer = imgData.data;\n for (var i = 0, ii = buffer.length; i < ii; i++) {\n buffer[i] ^= 0xff;\n }\n }\n return imgData;\n }\n if (this.image instanceof JpegStream && !this.smask && !this.mask &&\n (this.colorSpace.name === 'DeviceGray' ||\n this.colorSpace.name === 'DeviceRGB' ||\n this.colorSpace.name === 'DeviceCMYK')) {\n imgData.kind = ImageKind.RGB_24BPP;\n imgData.data = this.getImageBytes(originalHeight * rowBytes,\n drawWidth, drawHeight, true);\n return imgData;\n }\n }\n\n imgArray = this.getImageBytes(originalHeight * rowBytes);\n // imgArray can be incomplete (e.g. after CCITT fax encoding).\n var actualHeight = 0 | (imgArray.length / rowBytes *\n drawHeight / originalHeight);\n\n var comps = this.getComponents(imgArray);\n\n // If opacity data is present, use RGBA_32BPP form. Otherwise, use the\n // more compact RGB_24BPP form if allowable.\n var alpha01, maybeUndoPreblend;\n if (!forceRGBA && !this.smask && !this.mask) {\n imgData.kind = ImageKind.RGB_24BPP;\n imgData.data = new Uint8Array(drawWidth * drawHeight * 3);\n alpha01 = 0;\n maybeUndoPreblend = false;\n } else {\n imgData.kind = ImageKind.RGBA_32BPP;\n imgData.data = new Uint8Array(drawWidth * drawHeight * 4);\n alpha01 = 1;\n maybeUndoPreblend = true;\n\n // Color key masking (opacity) must be performed before decoding.\n this.fillOpacity(imgData.data, drawWidth, drawHeight, actualHeight,\n comps);\n }\n\n if (this.needsDecode) {\n this.decodeBuffer(comps);\n }\n this.colorSpace.fillRgb(imgData.data, originalWidth, originalHeight,\n drawWidth, drawHeight, actualHeight, bpc, comps,\n alpha01);\n if (maybeUndoPreblend) {\n this.undoPreblend(imgData.data, drawWidth, actualHeight);\n }\n\n return imgData;\n },\n\n fillGrayBuffer: function PDFImage_fillGrayBuffer(buffer) {\n var numComps = this.numComps;\n if (numComps !== 1) {\n throw new FormatError(\n `Reading gray scale from a color image: ${numComps}`);\n }\n\n var width = this.width;\n var height = this.height;\n var bpc = this.bpc;\n\n // rows start at byte boundary\n var rowBytes = (width * numComps * bpc + 7) >> 3;\n var imgArray = this.getImageBytes(height * rowBytes);\n\n var comps = this.getComponents(imgArray);\n var i, length;\n\n if (bpc === 1) {\n // inline decoding (= inversion) for 1 bpc images\n length = width * height;\n if (this.needsDecode) {\n // invert and scale to {0, 255}\n for (i = 0; i < length; ++i) {\n buffer[i] = (comps[i] - 1) & 255;\n }\n } else {\n // scale to {0, 255}\n for (i = 0; i < length; ++i) {\n buffer[i] = (-comps[i]) & 255;\n }\n }\n return;\n }\n\n if (this.needsDecode) {\n this.decodeBuffer(comps);\n }\n length = width * height;\n // we aren't using a colorspace so we need to scale the value\n var scale = 255 / ((1 << bpc) - 1);\n for (i = 0; i < length; ++i) {\n buffer[i] = (scale * comps[i]) | 0;\n }\n },\n\n getImageBytes: function PDFImage_getImageBytes(length,\n drawWidth, drawHeight,\n forceRGB) {\n this.image.reset();\n this.image.drawWidth = drawWidth || this.width;\n this.image.drawHeight = drawHeight || this.height;\n this.image.forceRGB = !!forceRGB;\n return this.image.getBytes(length);\n },\n };\n return PDFImage;\n})();\n\nexport {\n PDFImage,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/image.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n log2, readInt8, readUint16, readUint32, shadow\n} from '../shared/util';\nimport { ArithmeticDecoder } from './arithmetic_decoder';\n\nlet Jbig2Error = (function Jbig2ErrorClosure() {\n function Jbig2Error(msg) {\n this.message = 'JBIG2 error: ' + msg;\n }\n\n Jbig2Error.prototype = new Error();\n Jbig2Error.prototype.name = 'Jbig2Error';\n Jbig2Error.constructor = Jbig2Error;\n\n return Jbig2Error;\n})();\n\nvar Jbig2Image = (function Jbig2ImageClosure() {\n // Utility data structures\n function ContextCache() {}\n\n ContextCache.prototype = {\n getContexts(id) {\n if (id in this) {\n return this[id];\n }\n return (this[id] = new Int8Array(1 << 16));\n },\n };\n\n function DecodingContext(data, start, end) {\n this.data = data;\n this.start = start;\n this.end = end;\n }\n\n DecodingContext.prototype = {\n get decoder() {\n var decoder = new ArithmeticDecoder(this.data, this.start, this.end);\n return shadow(this, 'decoder', decoder);\n },\n get contextCache() {\n var cache = new ContextCache();\n return shadow(this, 'contextCache', cache);\n },\n };\n\n // Annex A. Arithmetic Integer Decoding Procedure\n // A.2 Procedure for decoding values\n function decodeInteger(contextCache, procedure, decoder) {\n var contexts = contextCache.getContexts(procedure);\n var prev = 1;\n\n function readBits(length) {\n var v = 0;\n for (var i = 0; i < length; i++) {\n var bit = decoder.readBit(contexts, prev);\n prev = (prev < 256 ? (prev << 1) | bit :\n (((prev << 1) | bit) & 511) | 256);\n v = (v << 1) | bit;\n }\n return v >>> 0;\n }\n\n var sign = readBits(1);\n var value = readBits(1) ?\n (readBits(1) ?\n (readBits(1) ?\n (readBits(1) ?\n (readBits(1) ?\n (readBits(32) + 4436) :\n readBits(12) + 340) :\n readBits(8) + 84) :\n readBits(6) + 20) :\n readBits(4) + 4) :\n readBits(2);\n return (sign === 0 ? value : (value > 0 ? -value : null));\n }\n\n // A.3 The IAID decoding procedure\n function decodeIAID(contextCache, decoder, codeLength) {\n var contexts = contextCache.getContexts('IAID');\n\n var prev = 1;\n for (var i = 0; i < codeLength; i++) {\n var bit = decoder.readBit(contexts, prev);\n prev = (prev << 1) | bit;\n }\n if (codeLength < 31) {\n return prev & ((1 << codeLength) - 1);\n }\n return prev & 0x7FFFFFFF;\n }\n\n // 7.3 Segment types\n var SegmentTypes = [\n 'SymbolDictionary', null, null, null, 'IntermediateTextRegion', null,\n 'ImmediateTextRegion', 'ImmediateLosslessTextRegion', null, null, null,\n null, null, null, null, null, 'patternDictionary', null, null, null,\n 'IntermediateHalftoneRegion', null, 'ImmediateHalftoneRegion',\n 'ImmediateLosslessHalftoneRegion', null, null, null, null, null, null, null,\n null, null, null, null, null, 'IntermediateGenericRegion', null,\n 'ImmediateGenericRegion', 'ImmediateLosslessGenericRegion',\n 'IntermediateGenericRefinementRegion', null,\n 'ImmediateGenericRefinementRegion',\n 'ImmediateLosslessGenericRefinementRegion', null, null, null, null,\n 'PageInformation', 'EndOfPage', 'EndOfStripe', 'EndOfFile', 'Profiles',\n 'Tables', null, null, null, null, null, null, null, null,\n 'Extension'\n ];\n\n var CodingTemplates = [\n [{ x: -1, y: -2, }, { x: 0, y: -2, }, { x: 1, y: -2, }, { x: -2, y: -1, },\n { x: -1, y: -1, }, { x: 0, y: -1, }, { x: 1, y: -1, }, { x: 2, y: -1, },\n { x: -4, y: 0, }, { x: -3, y: 0, }, { x: -2, y: 0, }, { x: -1, y: 0, }],\n [{ x: -1, y: -2, }, { x: 0, y: -2, }, { x: 1, y: -2, }, { x: 2, y: -2, },\n { x: -2, y: -1, }, { x: -1, y: -1, }, { x: 0, y: -1, }, { x: 1, y: -1, },\n { x: 2, y: -1, }, { x: -3, y: 0, }, { x: -2, y: 0, }, { x: -1, y: 0, }],\n [{ x: -1, y: -2, }, { x: 0, y: -2, }, { x: 1, y: -2, }, { x: -2, y: -1, },\n { x: -1, y: -1, }, { x: 0, y: -1, }, { x: 1, y: -1, }, { x: -2, y: 0, },\n { x: -1, y: 0, }],\n [{ x: -3, y: -1, }, { x: -2, y: -1, }, { x: -1, y: -1, }, { x: 0, y: -1, },\n { x: 1, y: -1, }, { x: -4, y: 0, }, { x: -3, y: 0, }, { x: -2, y: 0, },\n { x: -1, y: 0, }]\n ];\n\n var RefinementTemplates = [\n {\n coding: [{ x: 0, y: -1, }, { x: 1, y: -1, }, { x: -1, y: 0, }],\n reference: [{ x: 0, y: -1, }, { x: 1, y: -1, }, { x: -1, y: 0, },\n { x: 0, y: 0, }, { x: 1, y: 0, }, { x: -1, y: 1, },\n { x: 0, y: 1, }, { x: 1, y: 1, }],\n },\n {\n coding: [{ x: -1, y: -1, }, { x: 0, y: -1, }, { x: 1, y: -1, },\n { x: -1, y: 0, }],\n reference: [{ x: 0, y: -1, }, { x: -1, y: 0, }, { x: 0, y: 0, },\n { x: 1, y: 0, }, { x: 0, y: 1, }, { x: 1, y: 1, }],\n }\n ];\n\n // See 6.2.5.7 Decoding the bitmap.\n var ReusedContexts = [\n 0x9B25, // 10011 0110010 0101\n 0x0795, // 0011 110010 101\n 0x00E5, // 001 11001 01\n 0x0195 // 011001 0101\n ];\n\n var RefinementReusedContexts = [\n 0x0020, // '000' + '0' (coding) + '00010000' + '0' (reference)\n 0x0008 // '0000' + '001000'\n ];\n\n function decodeBitmapTemplate0(width, height, decodingContext) {\n var decoder = decodingContext.decoder;\n var contexts = decodingContext.contextCache.getContexts('GB');\n var contextLabel, i, j, pixel, row, row1, row2, bitmap = [];\n\n // ...ooooo....\n // ..ooooooo... Context template for current pixel (X)\n // .ooooX...... (concatenate values of 'o'-pixels to get contextLabel)\n var OLD_PIXEL_MASK = 0x7BF7; // 01111 0111111 0111\n\n for (i = 0; i < height; i++) {\n row = bitmap[i] = new Uint8Array(width);\n row1 = (i < 1) ? row : bitmap[i - 1];\n row2 = (i < 2) ? row : bitmap[i - 2];\n\n // At the beginning of each row:\n // Fill contextLabel with pixels that are above/right of (X)\n contextLabel = (row2[0] << 13) | (row2[1] << 12) | (row2[2] << 11) |\n (row1[0] << 7) | (row1[1] << 6) | (row1[2] << 5) |\n (row1[3] << 4);\n\n for (j = 0; j < width; j++) {\n row[j] = pixel = decoder.readBit(contexts, contextLabel);\n\n // At each pixel: Clear contextLabel pixels that are shifted\n // out of the context, then add new ones.\n contextLabel = ((contextLabel & OLD_PIXEL_MASK) << 1) |\n (j + 3 < width ? row2[j + 3] << 11 : 0) |\n (j + 4 < width ? row1[j + 4] << 4 : 0) | pixel;\n }\n }\n\n return bitmap;\n }\n\n // 6.2 Generic Region Decoding Procedure\n function decodeBitmap(mmr, width, height, templateIndex, prediction, skip, at,\n decodingContext) {\n if (mmr) {\n throw new Jbig2Error('MMR encoding is not supported');\n }\n\n // Use optimized version for the most common case\n if (templateIndex === 0 && !skip && !prediction && at.length === 4 &&\n at[0].x === 3 && at[0].y === -1 && at[1].x === -3 && at[1].y === -1 &&\n at[2].x === 2 && at[2].y === -2 && at[3].x === -2 && at[3].y === -2) {\n return decodeBitmapTemplate0(width, height, decodingContext);\n }\n\n var useskip = !!skip;\n var template = CodingTemplates[templateIndex].concat(at);\n\n // Sorting is non-standard, and it is not required. But sorting increases\n // the number of template bits that can be reused from the previous\n // contextLabel in the main loop.\n template.sort(function (a, b) {\n return (a.y - b.y) || (a.x - b.x);\n });\n\n var templateLength = template.length;\n var templateX = new Int8Array(templateLength);\n var templateY = new Int8Array(templateLength);\n var changingTemplateEntries = [];\n var reuseMask = 0, minX = 0, maxX = 0, minY = 0;\n var c, k;\n\n for (k = 0; k < templateLength; k++) {\n templateX[k] = template[k].x;\n templateY[k] = template[k].y;\n minX = Math.min(minX, template[k].x);\n maxX = Math.max(maxX, template[k].x);\n minY = Math.min(minY, template[k].y);\n // Check if the template pixel appears in two consecutive context labels,\n // so it can be reused. Otherwise, we add it to the list of changing\n // template entries.\n if (k < templateLength - 1 &&\n template[k].y === template[k + 1].y &&\n template[k].x === template[k + 1].x - 1) {\n reuseMask |= 1 << (templateLength - 1 - k);\n } else {\n changingTemplateEntries.push(k);\n }\n }\n var changingEntriesLength = changingTemplateEntries.length;\n\n var changingTemplateX = new Int8Array(changingEntriesLength);\n var changingTemplateY = new Int8Array(changingEntriesLength);\n var changingTemplateBit = new Uint16Array(changingEntriesLength);\n for (c = 0; c < changingEntriesLength; c++) {\n k = changingTemplateEntries[c];\n changingTemplateX[c] = template[k].x;\n changingTemplateY[c] = template[k].y;\n changingTemplateBit[c] = 1 << (templateLength - 1 - k);\n }\n\n // Get the safe bounding box edges from the width, height, minX, maxX, minY\n var sbb_left = -minX;\n var sbb_top = -minY;\n var sbb_right = width - maxX;\n\n var pseudoPixelContext = ReusedContexts[templateIndex];\n var row = new Uint8Array(width);\n var bitmap = [];\n\n var decoder = decodingContext.decoder;\n var contexts = decodingContext.contextCache.getContexts('GB');\n\n var ltp = 0, j, i0, j0, contextLabel = 0, bit, shift;\n for (var i = 0; i < height; i++) {\n if (prediction) {\n var sltp = decoder.readBit(contexts, pseudoPixelContext);\n ltp ^= sltp;\n if (ltp) {\n bitmap.push(row); // duplicate previous row\n continue;\n }\n }\n row = new Uint8Array(row);\n bitmap.push(row);\n for (j = 0; j < width; j++) {\n if (useskip && skip[i][j]) {\n row[j] = 0;\n continue;\n }\n // Are we in the middle of a scanline, so we can reuse contextLabel\n // bits?\n if (j >= sbb_left && j < sbb_right && i >= sbb_top) {\n // If yes, we can just shift the bits that are reusable and only\n // fetch the remaining ones.\n contextLabel = (contextLabel << 1) & reuseMask;\n for (k = 0; k < changingEntriesLength; k++) {\n i0 = i + changingTemplateY[k];\n j0 = j + changingTemplateX[k];\n bit = bitmap[i0][j0];\n if (bit) {\n bit = changingTemplateBit[k];\n contextLabel |= bit;\n }\n }\n } else {\n // compute the contextLabel from scratch\n contextLabel = 0;\n shift = templateLength - 1;\n for (k = 0; k < templateLength; k++, shift--) {\n j0 = j + templateX[k];\n if (j0 >= 0 && j0 < width) {\n i0 = i + templateY[k];\n if (i0 >= 0) {\n bit = bitmap[i0][j0];\n if (bit) {\n contextLabel |= bit << shift;\n }\n }\n }\n }\n }\n var pixel = decoder.readBit(contexts, contextLabel);\n row[j] = pixel;\n }\n }\n return bitmap;\n }\n\n // 6.3.2 Generic Refinement Region Decoding Procedure\n function decodeRefinement(width, height, templateIndex, referenceBitmap,\n offsetX, offsetY, prediction, at,\n decodingContext) {\n var codingTemplate = RefinementTemplates[templateIndex].coding;\n if (templateIndex === 0) {\n codingTemplate = codingTemplate.concat([at[0]]);\n }\n var codingTemplateLength = codingTemplate.length;\n var codingTemplateX = new Int32Array(codingTemplateLength);\n var codingTemplateY = new Int32Array(codingTemplateLength);\n var k;\n for (k = 0; k < codingTemplateLength; k++) {\n codingTemplateX[k] = codingTemplate[k].x;\n codingTemplateY[k] = codingTemplate[k].y;\n }\n\n var referenceTemplate = RefinementTemplates[templateIndex].reference;\n if (templateIndex === 0) {\n referenceTemplate = referenceTemplate.concat([at[1]]);\n }\n var referenceTemplateLength = referenceTemplate.length;\n var referenceTemplateX = new Int32Array(referenceTemplateLength);\n var referenceTemplateY = new Int32Array(referenceTemplateLength);\n for (k = 0; k < referenceTemplateLength; k++) {\n referenceTemplateX[k] = referenceTemplate[k].x;\n referenceTemplateY[k] = referenceTemplate[k].y;\n }\n var referenceWidth = referenceBitmap[0].length;\n var referenceHeight = referenceBitmap.length;\n\n var pseudoPixelContext = RefinementReusedContexts[templateIndex];\n var bitmap = [];\n\n var decoder = decodingContext.decoder;\n var contexts = decodingContext.contextCache.getContexts('GR');\n\n var ltp = 0;\n for (var i = 0; i < height; i++) {\n if (prediction) {\n var sltp = decoder.readBit(contexts, pseudoPixelContext);\n ltp ^= sltp;\n if (ltp) {\n throw new Jbig2Error('prediction is not supported');\n }\n }\n var row = new Uint8Array(width);\n bitmap.push(row);\n for (var j = 0; j < width; j++) {\n var i0, j0;\n var contextLabel = 0;\n for (k = 0; k < codingTemplateLength; k++) {\n i0 = i + codingTemplateY[k];\n j0 = j + codingTemplateX[k];\n if (i0 < 0 || j0 < 0 || j0 >= width) {\n contextLabel <<= 1; // out of bound pixel\n } else {\n contextLabel = (contextLabel << 1) | bitmap[i0][j0];\n }\n }\n for (k = 0; k < referenceTemplateLength; k++) {\n i0 = i + referenceTemplateY[k] - offsetY;\n j0 = j + referenceTemplateX[k] - offsetX;\n if (i0 < 0 || i0 >= referenceHeight || j0 < 0 ||\n j0 >= referenceWidth) {\n contextLabel <<= 1; // out of bound pixel\n } else {\n contextLabel = (contextLabel << 1) | referenceBitmap[i0][j0];\n }\n }\n var pixel = decoder.readBit(contexts, contextLabel);\n row[j] = pixel;\n }\n }\n\n return bitmap;\n }\n\n // 6.5.5 Decoding the symbol dictionary\n function decodeSymbolDictionary(huffman, refinement, symbols,\n numberOfNewSymbols, numberOfExportedSymbols,\n huffmanTables, templateIndex, at,\n refinementTemplateIndex, refinementAt,\n decodingContext) {\n if (huffman) {\n throw new Jbig2Error('huffman is not supported');\n }\n\n var newSymbols = [];\n var currentHeight = 0;\n var symbolCodeLength = log2(symbols.length + numberOfNewSymbols);\n\n var decoder = decodingContext.decoder;\n var contextCache = decodingContext.contextCache;\n\n while (newSymbols.length < numberOfNewSymbols) {\n var deltaHeight = decodeInteger(contextCache, 'IADH', decoder); // 6.5.6\n currentHeight += deltaHeight;\n var currentWidth = 0;\n while (true) {\n var deltaWidth = decodeInteger(contextCache, 'IADW', decoder); // 6.5.7\n if (deltaWidth === null) {\n break; // OOB\n }\n currentWidth += deltaWidth;\n var bitmap;\n if (refinement) {\n // 6.5.8.2 Refinement/aggregate-coded symbol bitmap\n var numberOfInstances = decodeInteger(contextCache, 'IAAI', decoder);\n if (numberOfInstances > 1) {\n bitmap = decodeTextRegion(huffman, refinement,\n currentWidth, currentHeight, 0,\n numberOfInstances, 1, // strip size\n symbols.concat(newSymbols),\n symbolCodeLength,\n 0, // transposed\n 0, // ds offset\n 1, // top left 7.4.3.1.1\n 0, // OR operator\n huffmanTables,\n refinementTemplateIndex, refinementAt,\n decodingContext);\n } else {\n var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);\n var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3\n var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4\n var symbol = (symbolId < symbols.length ? symbols[symbolId] :\n newSymbols[symbolId - symbols.length]);\n bitmap = decodeRefinement(currentWidth, currentHeight,\n refinementTemplateIndex, symbol, rdx, rdy, false, refinementAt,\n decodingContext);\n }\n } else {\n // 6.5.8.1 Direct-coded symbol bitmap\n bitmap = decodeBitmap(false, currentWidth, currentHeight,\n templateIndex, false, null, at, decodingContext);\n }\n newSymbols.push(bitmap);\n }\n }\n // 6.5.10 Exported symbols\n var exportedSymbols = [];\n var flags = [], currentFlag = false;\n var totalSymbolsLength = symbols.length + numberOfNewSymbols;\n while (flags.length < totalSymbolsLength) {\n var runLength = decodeInteger(contextCache, 'IAEX', decoder);\n while (runLength--) {\n flags.push(currentFlag);\n }\n currentFlag = !currentFlag;\n }\n for (var i = 0, ii = symbols.length; i < ii; i++) {\n if (flags[i]) {\n exportedSymbols.push(symbols[i]);\n }\n }\n for (var j = 0; j < numberOfNewSymbols; i++, j++) {\n if (flags[i]) {\n exportedSymbols.push(newSymbols[j]);\n }\n }\n return exportedSymbols;\n }\n\n function decodeTextRegion(huffman, refinement, width, height,\n defaultPixelValue, numberOfSymbolInstances,\n stripSize, inputSymbols, symbolCodeLength,\n transposed, dsOffset, referenceCorner,\n combinationOperator, huffmanTables,\n refinementTemplateIndex, refinementAt,\n decodingContext) {\n if (huffman) {\n throw new Jbig2Error('huffman is not supported');\n }\n\n // Prepare bitmap\n var bitmap = [];\n var i, row;\n for (i = 0; i < height; i++) {\n row = new Uint8Array(width);\n if (defaultPixelValue) {\n for (var j = 0; j < width; j++) {\n row[j] = defaultPixelValue;\n }\n }\n bitmap.push(row);\n }\n\n var decoder = decodingContext.decoder;\n var contextCache = decodingContext.contextCache;\n var stripT = -decodeInteger(contextCache, 'IADT', decoder); // 6.4.6\n var firstS = 0;\n i = 0;\n while (i < numberOfSymbolInstances) {\n var deltaT = decodeInteger(contextCache, 'IADT', decoder); // 6.4.6\n stripT += deltaT;\n\n var deltaFirstS = decodeInteger(contextCache, 'IAFS', decoder); // 6.4.7\n firstS += deltaFirstS;\n var currentS = firstS;\n do {\n var currentT = (stripSize === 1 ? 0 :\n decodeInteger(contextCache, 'IAIT', decoder)); // 6.4.9\n var t = stripSize * stripT + currentT;\n var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);\n var applyRefinement = (refinement &&\n decodeInteger(contextCache, 'IARI', decoder));\n var symbolBitmap = inputSymbols[symbolId];\n var symbolWidth = symbolBitmap[0].length;\n var symbolHeight = symbolBitmap.length;\n if (applyRefinement) {\n var rdw = decodeInteger(contextCache, 'IARDW', decoder); // 6.4.11.1\n var rdh = decodeInteger(contextCache, 'IARDH', decoder); // 6.4.11.2\n var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3\n var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4\n symbolWidth += rdw;\n symbolHeight += rdh;\n symbolBitmap = decodeRefinement(symbolWidth, symbolHeight,\n refinementTemplateIndex, symbolBitmap, (rdw >> 1) + rdx,\n (rdh >> 1) + rdy, false, refinementAt,\n decodingContext);\n }\n var offsetT = t - ((referenceCorner & 1) ? 0 : symbolHeight);\n var offsetS = currentS - ((referenceCorner & 2) ? symbolWidth : 0);\n var s2, t2, symbolRow;\n if (transposed) {\n // Place Symbol Bitmap from T1,S1\n for (s2 = 0; s2 < symbolHeight; s2++) {\n row = bitmap[offsetS + s2];\n if (!row) {\n continue;\n }\n symbolRow = symbolBitmap[s2];\n // To ignore Parts of Symbol bitmap which goes\n // outside bitmap region\n var maxWidth = Math.min(width - offsetT, symbolWidth);\n switch (combinationOperator) {\n case 0: // OR\n for (t2 = 0; t2 < maxWidth; t2++) {\n row[offsetT + t2] |= symbolRow[t2];\n }\n break;\n case 2: // XOR\n for (t2 = 0; t2 < maxWidth; t2++) {\n row[offsetT + t2] ^= symbolRow[t2];\n }\n break;\n default:\n throw new Jbig2Error(\n `operator ${combinationOperator} is not supported`);\n }\n }\n currentS += symbolHeight - 1;\n } else {\n for (t2 = 0; t2 < symbolHeight; t2++) {\n row = bitmap[offsetT + t2];\n if (!row) {\n continue;\n }\n symbolRow = symbolBitmap[t2];\n switch (combinationOperator) {\n case 0: // OR\n for (s2 = 0; s2 < symbolWidth; s2++) {\n row[offsetS + s2] |= symbolRow[s2];\n }\n break;\n case 2: // XOR\n for (s2 = 0; s2 < symbolWidth; s2++) {\n row[offsetS + s2] ^= symbolRow[s2];\n }\n break;\n default:\n throw new Jbig2Error(\n `operator ${combinationOperator} is not supported`);\n }\n }\n currentS += symbolWidth - 1;\n }\n i++;\n var deltaS = decodeInteger(contextCache, 'IADS', decoder); // 6.4.8\n if (deltaS === null) {\n break; // OOB\n }\n currentS += deltaS + dsOffset;\n } while (true);\n }\n return bitmap;\n }\n\n function readSegmentHeader(data, start) {\n var segmentHeader = {};\n segmentHeader.number = readUint32(data, start);\n var flags = data[start + 4];\n var segmentType = flags & 0x3F;\n if (!SegmentTypes[segmentType]) {\n throw new Jbig2Error('invalid segment type: ' + segmentType);\n }\n segmentHeader.type = segmentType;\n segmentHeader.typeName = SegmentTypes[segmentType];\n segmentHeader.deferredNonRetain = !!(flags & 0x80);\n\n var pageAssociationFieldSize = !!(flags & 0x40);\n var referredFlags = data[start + 5];\n var referredToCount = (referredFlags >> 5) & 7;\n var retainBits = [referredFlags & 31];\n var position = start + 6;\n if (referredFlags === 7) {\n referredToCount = readUint32(data, position - 1) & 0x1FFFFFFF;\n position += 3;\n var bytes = (referredToCount + 7) >> 3;\n retainBits[0] = data[position++];\n while (--bytes > 0) {\n retainBits.push(data[position++]);\n }\n } else if (referredFlags === 5 || referredFlags === 6) {\n throw new Jbig2Error('invalid referred-to flags');\n }\n\n segmentHeader.retainBits = retainBits;\n var referredToSegmentNumberSize = (segmentHeader.number <= 256 ? 1 :\n (segmentHeader.number <= 65536 ? 2 : 4));\n var referredTo = [];\n var i, ii;\n for (i = 0; i < referredToCount; i++) {\n var number = (referredToSegmentNumberSize === 1 ? data[position] :\n (referredToSegmentNumberSize === 2 ? readUint16(data, position) :\n readUint32(data, position)));\n referredTo.push(number);\n position += referredToSegmentNumberSize;\n }\n segmentHeader.referredTo = referredTo;\n if (!pageAssociationFieldSize) {\n segmentHeader.pageAssociation = data[position++];\n } else {\n segmentHeader.pageAssociation = readUint32(data, position);\n position += 4;\n }\n segmentHeader.length = readUint32(data, position);\n position += 4;\n\n if (segmentHeader.length === 0xFFFFFFFF) {\n // 7.2.7 Segment data length, unknown segment length\n if (segmentType === 38) { // ImmediateGenericRegion\n var genericRegionInfo = readRegionSegmentInformation(data, position);\n var genericRegionSegmentFlags = data[position +\n RegionSegmentInformationFieldLength];\n var genericRegionMmr = !!(genericRegionSegmentFlags & 1);\n // searching for the segment end\n var searchPatternLength = 6;\n var searchPattern = new Uint8Array(searchPatternLength);\n if (!genericRegionMmr) {\n searchPattern[0] = 0xFF;\n searchPattern[1] = 0xAC;\n }\n searchPattern[2] = (genericRegionInfo.height >>> 24) & 0xFF;\n searchPattern[3] = (genericRegionInfo.height >> 16) & 0xFF;\n searchPattern[4] = (genericRegionInfo.height >> 8) & 0xFF;\n searchPattern[5] = genericRegionInfo.height & 0xFF;\n for (i = position, ii = data.length; i < ii; i++) {\n var j = 0;\n while (j < searchPatternLength && searchPattern[j] === data[i + j]) {\n j++;\n }\n if (j === searchPatternLength) {\n segmentHeader.length = i + searchPatternLength;\n break;\n }\n }\n if (segmentHeader.length === 0xFFFFFFFF) {\n throw new Jbig2Error('segment end was not found');\n }\n } else {\n throw new Jbig2Error('invalid unknown segment length');\n }\n }\n segmentHeader.headerEnd = position;\n return segmentHeader;\n }\n\n function readSegments(header, data, start, end) {\n var segments = [];\n var position = start;\n while (position < end) {\n var segmentHeader = readSegmentHeader(data, position);\n position = segmentHeader.headerEnd;\n var segment = {\n header: segmentHeader,\n data,\n };\n if (!header.randomAccess) {\n segment.start = position;\n position += segmentHeader.length;\n segment.end = position;\n }\n segments.push(segment);\n if (segmentHeader.type === 51) {\n break; // end of file is found\n }\n }\n if (header.randomAccess) {\n for (var i = 0, ii = segments.length; i < ii; i++) {\n segments[i].start = position;\n position += segments[i].header.length;\n segments[i].end = position;\n }\n }\n return segments;\n }\n\n // 7.4.1 Region segment information field\n function readRegionSegmentInformation(data, start) {\n return {\n width: readUint32(data, start),\n height: readUint32(data, start + 4),\n x: readUint32(data, start + 8),\n y: readUint32(data, start + 12),\n combinationOperator: data[start + 16] & 7,\n };\n }\n var RegionSegmentInformationFieldLength = 17;\n\n function processSegment(segment, visitor) {\n var header = segment.header;\n\n var data = segment.data, position = segment.start, end = segment.end;\n var args, at, i, atLength;\n switch (header.type) {\n case 0: // SymbolDictionary\n // 7.4.2 Symbol dictionary segment syntax\n var dictionary = {};\n var dictionaryFlags = readUint16(data, position); // 7.4.2.1.1\n dictionary.huffman = !!(dictionaryFlags & 1);\n dictionary.refinement = !!(dictionaryFlags & 2);\n dictionary.huffmanDHSelector = (dictionaryFlags >> 2) & 3;\n dictionary.huffmanDWSelector = (dictionaryFlags >> 4) & 3;\n dictionary.bitmapSizeSelector = (dictionaryFlags >> 6) & 1;\n dictionary.aggregationInstancesSelector = (dictionaryFlags >> 7) & 1;\n dictionary.bitmapCodingContextUsed = !!(dictionaryFlags & 256);\n dictionary.bitmapCodingContextRetained = !!(dictionaryFlags & 512);\n dictionary.template = (dictionaryFlags >> 10) & 3;\n dictionary.refinementTemplate = (dictionaryFlags >> 12) & 1;\n position += 2;\n if (!dictionary.huffman) {\n atLength = dictionary.template === 0 ? 4 : 1;\n at = [];\n for (i = 0; i < atLength; i++) {\n at.push({\n x: readInt8(data, position),\n y: readInt8(data, position + 1),\n });\n position += 2;\n }\n dictionary.at = at;\n }\n if (dictionary.refinement && !dictionary.refinementTemplate) {\n at = [];\n for (i = 0; i < 2; i++) {\n at.push({\n x: readInt8(data, position),\n y: readInt8(data, position + 1),\n });\n position += 2;\n }\n dictionary.refinementAt = at;\n }\n dictionary.numberOfExportedSymbols = readUint32(data, position);\n position += 4;\n dictionary.numberOfNewSymbols = readUint32(data, position);\n position += 4;\n args = [dictionary, header.number, header.referredTo,\n data, position, end];\n break;\n case 6: // ImmediateTextRegion\n case 7: // ImmediateLosslessTextRegion\n var textRegion = {};\n textRegion.info = readRegionSegmentInformation(data, position);\n position += RegionSegmentInformationFieldLength;\n var textRegionSegmentFlags = readUint16(data, position);\n position += 2;\n textRegion.huffman = !!(textRegionSegmentFlags & 1);\n textRegion.refinement = !!(textRegionSegmentFlags & 2);\n textRegion.stripSize = 1 << ((textRegionSegmentFlags >> 2) & 3);\n textRegion.referenceCorner = (textRegionSegmentFlags >> 4) & 3;\n textRegion.transposed = !!(textRegionSegmentFlags & 64);\n textRegion.combinationOperator = (textRegionSegmentFlags >> 7) & 3;\n textRegion.defaultPixelValue = (textRegionSegmentFlags >> 9) & 1;\n textRegion.dsOffset = (textRegionSegmentFlags << 17) >> 27;\n textRegion.refinementTemplate = (textRegionSegmentFlags >> 15) & 1;\n if (textRegion.huffman) {\n var textRegionHuffmanFlags = readUint16(data, position);\n position += 2;\n textRegion.huffmanFS = (textRegionHuffmanFlags) & 3;\n textRegion.huffmanDS = (textRegionHuffmanFlags >> 2) & 3;\n textRegion.huffmanDT = (textRegionHuffmanFlags >> 4) & 3;\n textRegion.huffmanRefinementDW = (textRegionHuffmanFlags >> 6) & 3;\n textRegion.huffmanRefinementDH = (textRegionHuffmanFlags >> 8) & 3;\n textRegion.huffmanRefinementDX = (textRegionHuffmanFlags >> 10) & 3;\n textRegion.huffmanRefinementDY = (textRegionHuffmanFlags >> 12) & 3;\n textRegion.huffmanRefinementSizeSelector =\n !!(textRegionHuffmanFlags & 14);\n }\n if (textRegion.refinement && !textRegion.refinementTemplate) {\n at = [];\n for (i = 0; i < 2; i++) {\n at.push({\n x: readInt8(data, position),\n y: readInt8(data, position + 1),\n });\n position += 2;\n }\n textRegion.refinementAt = at;\n }\n textRegion.numberOfSymbolInstances = readUint32(data, position);\n position += 4;\n // TODO 7.4.3.1.7 Symbol ID Huffman table decoding\n if (textRegion.huffman) {\n throw new Jbig2Error('huffman is not supported');\n }\n args = [textRegion, header.referredTo, data, position, end];\n break;\n case 38: // ImmediateGenericRegion\n case 39: // ImmediateLosslessGenericRegion\n var genericRegion = {};\n genericRegion.info = readRegionSegmentInformation(data, position);\n position += RegionSegmentInformationFieldLength;\n var genericRegionSegmentFlags = data[position++];\n genericRegion.mmr = !!(genericRegionSegmentFlags & 1);\n genericRegion.template = (genericRegionSegmentFlags >> 1) & 3;\n genericRegion.prediction = !!(genericRegionSegmentFlags & 8);\n if (!genericRegion.mmr) {\n atLength = genericRegion.template === 0 ? 4 : 1;\n at = [];\n for (i = 0; i < atLength; i++) {\n at.push({\n x: readInt8(data, position),\n y: readInt8(data, position + 1),\n });\n position += 2;\n }\n genericRegion.at = at;\n }\n args = [genericRegion, data, position, end];\n break;\n case 48: // PageInformation\n var pageInfo = {\n width: readUint32(data, position),\n height: readUint32(data, position + 4),\n resolutionX: readUint32(data, position + 8),\n resolutionY: readUint32(data, position + 12),\n };\n if (pageInfo.height === 0xFFFFFFFF) {\n delete pageInfo.height;\n }\n var pageSegmentFlags = data[position + 16];\n readUint16(data, position + 17); // pageStripingInformation\n pageInfo.lossless = !!(pageSegmentFlags & 1);\n pageInfo.refinement = !!(pageSegmentFlags & 2);\n pageInfo.defaultPixelValue = (pageSegmentFlags >> 2) & 1;\n pageInfo.combinationOperator = (pageSegmentFlags >> 3) & 3;\n pageInfo.requiresBuffer = !!(pageSegmentFlags & 32);\n pageInfo.combinationOperatorOverride = !!(pageSegmentFlags & 64);\n args = [pageInfo];\n break;\n case 49: // EndOfPage\n break;\n case 50: // EndOfStripe\n break;\n case 51: // EndOfFile\n break;\n case 62: // 7.4.15 defines 2 extension types which\n // are comments and can be ignored.\n break;\n default:\n throw new Jbig2Error(`segment type ${header.typeName}(${header.type})` +\n ' is not implemented');\n }\n var callbackName = 'on' + header.typeName;\n if (callbackName in visitor) {\n visitor[callbackName].apply(visitor, args);\n }\n }\n\n function processSegments(segments, visitor) {\n for (var i = 0, ii = segments.length; i < ii; i++) {\n processSegment(segments[i], visitor);\n }\n }\n\n function parseJbig2(data, start, end) { // eslint-disable-line no-unused-vars\n var position = start;\n if (data[position] !== 0x97 || data[position + 1] !== 0x4A ||\n data[position + 2] !== 0x42 || data[position + 3] !== 0x32 ||\n data[position + 4] !== 0x0D || data[position + 5] !== 0x0A ||\n data[position + 6] !== 0x1A || data[position + 7] !== 0x0A) {\n throw new Jbig2Error('invalid header');\n }\n var header = {};\n position += 8;\n var flags = data[position++];\n header.randomAccess = !(flags & 1);\n if (!(flags & 2)) {\n header.numberOfPages = readUint32(data, position);\n position += 4;\n }\n readSegments(header, data, position, end); // segments\n throw new Error('Not implemented');\n // processSegments(segments, new SimpleSegmentVisitor());\n }\n\n function parseJbig2Chunks(chunks) {\n var visitor = new SimpleSegmentVisitor();\n for (var i = 0, ii = chunks.length; i < ii; i++) {\n var chunk = chunks[i];\n var segments = readSegments({}, chunk.data, chunk.start, chunk.end);\n processSegments(segments, visitor);\n }\n return visitor.buffer;\n }\n\n function SimpleSegmentVisitor() {}\n\n SimpleSegmentVisitor.prototype = {\n onPageInformation: function SimpleSegmentVisitor_onPageInformation(info) {\n this.currentPageInfo = info;\n var rowSize = (info.width + 7) >> 3;\n var buffer = new Uint8Array(rowSize * info.height);\n // The contents of ArrayBuffers are initialized to 0.\n // Fill the buffer with 0xFF only if info.defaultPixelValue is set\n if (info.defaultPixelValue) {\n for (var i = 0, ii = buffer.length; i < ii; i++) {\n buffer[i] = 0xFF;\n }\n }\n this.buffer = buffer;\n },\n drawBitmap: function SimpleSegmentVisitor_drawBitmap(regionInfo, bitmap) {\n var pageInfo = this.currentPageInfo;\n var width = regionInfo.width, height = regionInfo.height;\n var rowSize = (pageInfo.width + 7) >> 3;\n var combinationOperator = pageInfo.combinationOperatorOverride ?\n regionInfo.combinationOperator : pageInfo.combinationOperator;\n var buffer = this.buffer;\n var mask0 = 128 >> (regionInfo.x & 7);\n var offset0 = regionInfo.y * rowSize + (regionInfo.x >> 3);\n var i, j, mask, offset;\n switch (combinationOperator) {\n case 0: // OR\n for (i = 0; i < height; i++) {\n mask = mask0;\n offset = offset0;\n for (j = 0; j < width; j++) {\n if (bitmap[i][j]) {\n buffer[offset] |= mask;\n }\n mask >>= 1;\n if (!mask) {\n mask = 128;\n offset++;\n }\n }\n offset0 += rowSize;\n }\n break;\n case 2: // XOR\n for (i = 0; i < height; i++) {\n mask = mask0;\n offset = offset0;\n for (j = 0; j < width; j++) {\n if (bitmap[i][j]) {\n buffer[offset] ^= mask;\n }\n mask >>= 1;\n if (!mask) {\n mask = 128;\n offset++;\n }\n }\n offset0 += rowSize;\n }\n break;\n default:\n throw new Jbig2Error(\n `operator ${combinationOperator} is not supported`);\n }\n },\n onImmediateGenericRegion:\n function SimpleSegmentVisitor_onImmediateGenericRegion(region, data,\n start, end) {\n var regionInfo = region.info;\n var decodingContext = new DecodingContext(data, start, end);\n var bitmap = decodeBitmap(region.mmr, regionInfo.width, regionInfo.height,\n region.template, region.prediction, null,\n region.at, decodingContext);\n this.drawBitmap(regionInfo, bitmap);\n },\n onImmediateLosslessGenericRegion:\n function SimpleSegmentVisitor_onImmediateLosslessGenericRegion() {\n this.onImmediateGenericRegion.apply(this, arguments);\n },\n onSymbolDictionary:\n function SimpleSegmentVisitor_onSymbolDictionary(dictionary,\n currentSegment,\n referredSegments,\n data, start, end) {\n var huffmanTables;\n if (dictionary.huffman) {\n throw new Jbig2Error('huffman is not supported');\n }\n\n // Combines exported symbols from all referred segments\n var symbols = this.symbols;\n if (!symbols) {\n this.symbols = symbols = {};\n }\n\n var inputSymbols = [];\n for (var i = 0, ii = referredSegments.length; i < ii; i++) {\n inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]);\n }\n\n var decodingContext = new DecodingContext(data, start, end);\n symbols[currentSegment] = decodeSymbolDictionary(dictionary.huffman,\n dictionary.refinement, inputSymbols, dictionary.numberOfNewSymbols,\n dictionary.numberOfExportedSymbols, huffmanTables,\n dictionary.template, dictionary.at,\n dictionary.refinementTemplate, dictionary.refinementAt,\n decodingContext);\n },\n onImmediateTextRegion:\n function SimpleSegmentVisitor_onImmediateTextRegion(region,\n referredSegments,\n data, start, end) {\n var regionInfo = region.info;\n var huffmanTables;\n\n // Combines exported symbols from all referred segments\n var symbols = this.symbols;\n var inputSymbols = [];\n for (var i = 0, ii = referredSegments.length; i < ii; i++) {\n inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]);\n }\n var symbolCodeLength = log2(inputSymbols.length);\n\n var decodingContext = new DecodingContext(data, start, end);\n var bitmap = decodeTextRegion(region.huffman, region.refinement,\n regionInfo.width, regionInfo.height, region.defaultPixelValue,\n region.numberOfSymbolInstances, region.stripSize, inputSymbols,\n symbolCodeLength, region.transposed, region.dsOffset,\n region.referenceCorner, region.combinationOperator, huffmanTables,\n region.refinementTemplate, region.refinementAt, decodingContext);\n this.drawBitmap(regionInfo, bitmap);\n },\n onImmediateLosslessTextRegion:\n function SimpleSegmentVisitor_onImmediateLosslessTextRegion() {\n this.onImmediateTextRegion.apply(this, arguments);\n },\n };\n\n function Jbig2Image() {}\n\n Jbig2Image.prototype = {\n parseChunks: function Jbig2Image_parseChunks(chunks) {\n return parseJbig2Chunks(chunks);\n },\n };\n\n return Jbig2Image;\n})();\n\nexport {\n Jbig2Image,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/jbig2.js","/* Copyright 2014 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the 'License');\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an 'AS IS' BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* eslint-disable no-multi-spaces */\n\nimport { warn } from '../shared/util';\n\nlet JpegError = (function JpegErrorClosure() {\n function JpegError(msg) {\n this.message = 'JPEG error: ' + msg;\n }\n\n JpegError.prototype = new Error();\n JpegError.prototype.name = 'JpegError';\n JpegError.constructor = JpegError;\n\n return JpegError;\n})();\n\n/**\n * This code was forked from https://github.com/notmasteryet/jpgjs.\n * The original version was created by GitHub user notmasteryet.\n *\n * - The JPEG specification can be found in the ITU CCITT Recommendation T.81\n * (www.w3.org/Graphics/JPEG/itu-t81.pdf)\n * - The JFIF specification can be found in the JPEG File Interchange Format\n * (www.w3.org/Graphics/JPEG/jfif3.pdf)\n * - The Adobe Application-Specific JPEG markers in the\n * Supporting the DCT Filters in PostScript Level 2, Technical Note #5116\n * (partners.adobe.com/public/developer/en/ps/sdk/5116.DCT_Filter.pdf)\n */\n\nvar JpegImage = (function JpegImageClosure() {\n var dctZigZag = new Uint8Array([\n 0,\n 1, 8,\n 16, 9, 2,\n 3, 10, 17, 24,\n 32, 25, 18, 11, 4,\n 5, 12, 19, 26, 33, 40,\n 48, 41, 34, 27, 20, 13, 6,\n 7, 14, 21, 28, 35, 42, 49, 56,\n 57, 50, 43, 36, 29, 22, 15,\n 23, 30, 37, 44, 51, 58,\n 59, 52, 45, 38, 31,\n 39, 46, 53, 60,\n 61, 54, 47,\n 55, 62,\n 63\n ]);\n\n var dctCos1 = 4017; // cos(pi/16)\n var dctSin1 = 799; // sin(pi/16)\n var dctCos3 = 3406; // cos(3*pi/16)\n var dctSin3 = 2276; // sin(3*pi/16)\n var dctCos6 = 1567; // cos(6*pi/16)\n var dctSin6 = 3784; // sin(6*pi/16)\n var dctSqrt2 = 5793; // sqrt(2)\n var dctSqrt1d2 = 2896; // sqrt(2) / 2\n\n function JpegImage() {\n this.decodeTransform = null;\n this.colorTransform = -1;\n }\n\n function buildHuffmanTable(codeLengths, values) {\n var k = 0, code = [], i, j, length = 16;\n while (length > 0 && !codeLengths[length - 1]) {\n length--;\n }\n code.push({ children: [], index: 0, });\n var p = code[0], q;\n for (i = 0; i < length; i++) {\n for (j = 0; j < codeLengths[i]; j++) {\n p = code.pop();\n p.children[p.index] = values[k];\n while (p.index > 0) {\n p = code.pop();\n }\n p.index++;\n code.push(p);\n while (code.length <= i) {\n code.push(q = { children: [], index: 0, });\n p.children[p.index] = q.children;\n p = q;\n }\n k++;\n }\n if (i + 1 < length) {\n // p here points to last code\n code.push(q = { children: [], index: 0, });\n p.children[p.index] = q.children;\n p = q;\n }\n }\n return code[0].children;\n }\n\n function getBlockBufferOffset(component, row, col) {\n return 64 * ((component.blocksPerLine + 1) * row + col);\n }\n\n function decodeScan(data, offset, frame, components, resetInterval,\n spectralStart, spectralEnd, successivePrev, successive) {\n var mcusPerLine = frame.mcusPerLine;\n var progressive = frame.progressive;\n\n var startOffset = offset, bitsData = 0, bitsCount = 0;\n\n function readBit() {\n if (bitsCount > 0) {\n bitsCount--;\n return (bitsData >> bitsCount) & 1;\n }\n bitsData = data[offset++];\n if (bitsData === 0xFF) {\n var nextByte = data[offset++];\n if (nextByte) {\n throw new JpegError(\n `unexpected marker ${((bitsData << 8) | nextByte).toString(16)}`);\n }\n // unstuff 0\n }\n bitsCount = 7;\n return bitsData >>> 7;\n }\n\n function decodeHuffman(tree) {\n var node = tree;\n while (true) {\n node = node[readBit()];\n if (typeof node === 'number') {\n return node;\n }\n if (typeof node !== 'object') {\n throw new JpegError('invalid huffman sequence');\n }\n }\n }\n\n function receive(length) {\n var n = 0;\n while (length > 0) {\n n = (n << 1) | readBit();\n length--;\n }\n return n;\n }\n\n function receiveAndExtend(length) {\n if (length === 1) {\n return readBit() === 1 ? 1 : -1;\n }\n var n = receive(length);\n if (n >= 1 << (length - 1)) {\n return n;\n }\n return n + (-1 << length) + 1;\n }\n\n function decodeBaseline(component, offset) {\n var t = decodeHuffman(component.huffmanTableDC);\n var diff = t === 0 ? 0 : receiveAndExtend(t);\n component.blockData[offset] = (component.pred += diff);\n var k = 1;\n while (k < 64) {\n var rs = decodeHuffman(component.huffmanTableAC);\n var s = rs & 15, r = rs >> 4;\n if (s === 0) {\n if (r < 15) {\n break;\n }\n k += 16;\n continue;\n }\n k += r;\n var z = dctZigZag[k];\n component.blockData[offset + z] = receiveAndExtend(s);\n k++;\n }\n }\n\n function decodeDCFirst(component, offset) {\n var t = decodeHuffman(component.huffmanTableDC);\n var diff = t === 0 ? 0 : (receiveAndExtend(t) << successive);\n component.blockData[offset] = (component.pred += diff);\n }\n\n function decodeDCSuccessive(component, offset) {\n component.blockData[offset] |= readBit() << successive;\n }\n\n var eobrun = 0;\n function decodeACFirst(component, offset) {\n if (eobrun > 0) {\n eobrun--;\n return;\n }\n var k = spectralStart, e = spectralEnd;\n while (k <= e) {\n var rs = decodeHuffman(component.huffmanTableAC);\n var s = rs & 15, r = rs >> 4;\n if (s === 0) {\n if (r < 15) {\n eobrun = receive(r) + (1 << r) - 1;\n break;\n }\n k += 16;\n continue;\n }\n k += r;\n var z = dctZigZag[k];\n component.blockData[offset + z] =\n receiveAndExtend(s) * (1 << successive);\n k++;\n }\n }\n\n var successiveACState = 0, successiveACNextValue;\n function decodeACSuccessive(component, offset) {\n var k = spectralStart;\n var e = spectralEnd;\n var r = 0;\n var s;\n var rs;\n while (k <= e) {\n var z = dctZigZag[k];\n switch (successiveACState) {\n case 0: // initial state\n rs = decodeHuffman(component.huffmanTableAC);\n s = rs & 15;\n r = rs >> 4;\n if (s === 0) {\n if (r < 15) {\n eobrun = receive(r) + (1 << r);\n successiveACState = 4;\n } else {\n r = 16;\n successiveACState = 1;\n }\n } else {\n if (s !== 1) {\n throw new JpegError('invalid ACn encoding');\n }\n successiveACNextValue = receiveAndExtend(s);\n successiveACState = r ? 2 : 3;\n }\n continue;\n case 1: // skipping r zero items\n case 2:\n if (component.blockData[offset + z]) {\n component.blockData[offset + z] += (readBit() << successive);\n } else {\n r--;\n if (r === 0) {\n successiveACState = successiveACState === 2 ? 3 : 0;\n }\n }\n break;\n case 3: // set value for a zero item\n if (component.blockData[offset + z]) {\n component.blockData[offset + z] += (readBit() << successive);\n } else {\n component.blockData[offset + z] =\n successiveACNextValue << successive;\n successiveACState = 0;\n }\n break;\n case 4: // eob\n if (component.blockData[offset + z]) {\n component.blockData[offset + z] += (readBit() << successive);\n }\n break;\n }\n k++;\n }\n if (successiveACState === 4) {\n eobrun--;\n if (eobrun === 0) {\n successiveACState = 0;\n }\n }\n }\n\n function decodeMcu(component, decode, mcu, row, col) {\n var mcuRow = (mcu / mcusPerLine) | 0;\n var mcuCol = mcu % mcusPerLine;\n var blockRow = mcuRow * component.v + row;\n var blockCol = mcuCol * component.h + col;\n var offset = getBlockBufferOffset(component, blockRow, blockCol);\n decode(component, offset);\n }\n\n function decodeBlock(component, decode, mcu) {\n var blockRow = (mcu / component.blocksPerLine) | 0;\n var blockCol = mcu % component.blocksPerLine;\n var offset = getBlockBufferOffset(component, blockRow, blockCol);\n decode(component, offset);\n }\n\n var componentsLength = components.length;\n var component, i, j, k, n;\n var decodeFn;\n if (progressive) {\n if (spectralStart === 0) {\n decodeFn = successivePrev === 0 ? decodeDCFirst : decodeDCSuccessive;\n } else {\n decodeFn = successivePrev === 0 ? decodeACFirst : decodeACSuccessive;\n }\n } else {\n decodeFn = decodeBaseline;\n }\n\n var mcu = 0, fileMarker;\n var mcuExpected;\n if (componentsLength === 1) {\n mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn;\n } else {\n mcuExpected = mcusPerLine * frame.mcusPerColumn;\n }\n\n var h, v;\n while (mcu < mcuExpected) {\n // reset interval stuff\n var mcuToRead = resetInterval ?\n Math.min(mcuExpected - mcu, resetInterval) : mcuExpected;\n for (i = 0; i < componentsLength; i++) {\n components[i].pred = 0;\n }\n eobrun = 0;\n\n if (componentsLength === 1) {\n component = components[0];\n for (n = 0; n < mcuToRead; n++) {\n decodeBlock(component, decodeFn, mcu);\n mcu++;\n }\n } else {\n for (n = 0; n < mcuToRead; n++) {\n for (i = 0; i < componentsLength; i++) {\n component = components[i];\n h = component.h;\n v = component.v;\n for (j = 0; j < v; j++) {\n for (k = 0; k < h; k++) {\n decodeMcu(component, decodeFn, mcu, j, k);\n }\n }\n }\n mcu++;\n }\n }\n\n // find marker\n bitsCount = 0;\n fileMarker = findNextFileMarker(data, offset);\n // Some bad images seem to pad Scan blocks with e.g. zero bytes, skip past\n // those to attempt to find a valid marker (fixes issue4090.pdf).\n if (fileMarker && fileMarker.invalid) {\n warn('decodeScan - unexpected MCU data, next marker is: ' +\n fileMarker.invalid);\n offset = fileMarker.offset;\n }\n var marker = fileMarker && fileMarker.marker;\n if (!marker || marker <= 0xFF00) {\n throw new JpegError('marker was not found');\n }\n\n if (marker >= 0xFFD0 && marker <= 0xFFD7) { // RSTx\n offset += 2;\n } else {\n break;\n }\n }\n\n fileMarker = findNextFileMarker(data, offset);\n // Some images include more Scan blocks than expected, skip past those and\n // attempt to find the next valid marker (fixes issue8182.pdf).\n if (fileMarker && fileMarker.invalid) {\n warn('decodeScan - unexpected Scan data, next marker is: ' +\n fileMarker.invalid);\n offset = fileMarker.offset;\n }\n\n return offset - startOffset;\n }\n\n // A port of poppler's IDCT method which in turn is taken from:\n // Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,\n // 'Practical Fast 1-D DCT Algorithms with 11 Multiplications',\n // IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,\n // 988-991.\n function quantizeAndInverse(component, blockBufferOffset, p) {\n var qt = component.quantizationTable, blockData = component.blockData;\n var v0, v1, v2, v3, v4, v5, v6, v7;\n var p0, p1, p2, p3, p4, p5, p6, p7;\n var t;\n\n if (!qt) {\n throw new JpegError('missing required Quantization Table.');\n }\n\n // inverse DCT on rows\n for (var row = 0; row < 64; row += 8) {\n // gather block data\n p0 = blockData[blockBufferOffset + row];\n p1 = blockData[blockBufferOffset + row + 1];\n p2 = blockData[blockBufferOffset + row + 2];\n p3 = blockData[blockBufferOffset + row + 3];\n p4 = blockData[blockBufferOffset + row + 4];\n p5 = blockData[blockBufferOffset + row + 5];\n p6 = blockData[blockBufferOffset + row + 6];\n p7 = blockData[blockBufferOffset + row + 7];\n\n // dequant p0\n p0 *= qt[row];\n\n // check for all-zero AC coefficients\n if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {\n t = (dctSqrt2 * p0 + 512) >> 10;\n p[row] = t;\n p[row + 1] = t;\n p[row + 2] = t;\n p[row + 3] = t;\n p[row + 4] = t;\n p[row + 5] = t;\n p[row + 6] = t;\n p[row + 7] = t;\n continue;\n }\n // dequant p1 ... p7\n p1 *= qt[row + 1];\n p2 *= qt[row + 2];\n p3 *= qt[row + 3];\n p4 *= qt[row + 4];\n p5 *= qt[row + 5];\n p6 *= qt[row + 6];\n p7 *= qt[row + 7];\n\n // stage 4\n v0 = (dctSqrt2 * p0 + 128) >> 8;\n v1 = (dctSqrt2 * p4 + 128) >> 8;\n v2 = p2;\n v3 = p6;\n v4 = (dctSqrt1d2 * (p1 - p7) + 128) >> 8;\n v7 = (dctSqrt1d2 * (p1 + p7) + 128) >> 8;\n v5 = p3 << 4;\n v6 = p5 << 4;\n\n // stage 3\n v0 = (v0 + v1 + 1) >> 1;\n v1 = v0 - v1;\n t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8;\n v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8;\n v3 = t;\n v4 = (v4 + v6 + 1) >> 1;\n v6 = v4 - v6;\n v7 = (v7 + v5 + 1) >> 1;\n v5 = v7 - v5;\n\n // stage 2\n v0 = (v0 + v3 + 1) >> 1;\n v3 = v0 - v3;\n v1 = (v1 + v2 + 1) >> 1;\n v2 = v1 - v2;\n t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;\n v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;\n v7 = t;\n t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;\n v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;\n v6 = t;\n\n // stage 1\n p[row] = v0 + v7;\n p[row + 7] = v0 - v7;\n p[row + 1] = v1 + v6;\n p[row + 6] = v1 - v6;\n p[row + 2] = v2 + v5;\n p[row + 5] = v2 - v5;\n p[row + 3] = v3 + v4;\n p[row + 4] = v3 - v4;\n }\n\n // inverse DCT on columns\n for (var col = 0; col < 8; ++col) {\n p0 = p[col];\n p1 = p[col + 8];\n p2 = p[col + 16];\n p3 = p[col + 24];\n p4 = p[col + 32];\n p5 = p[col + 40];\n p6 = p[col + 48];\n p7 = p[col + 56];\n\n // check for all-zero AC coefficients\n if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {\n t = (dctSqrt2 * p0 + 8192) >> 14;\n // convert to 8 bit\n t = (t < -2040) ? 0 : (t >= 2024) ? 255 : (t + 2056) >> 4;\n blockData[blockBufferOffset + col] = t;\n blockData[blockBufferOffset + col + 8] = t;\n blockData[blockBufferOffset + col + 16] = t;\n blockData[blockBufferOffset + col + 24] = t;\n blockData[blockBufferOffset + col + 32] = t;\n blockData[blockBufferOffset + col + 40] = t;\n blockData[blockBufferOffset + col + 48] = t;\n blockData[blockBufferOffset + col + 56] = t;\n continue;\n }\n\n // stage 4\n v0 = (dctSqrt2 * p0 + 2048) >> 12;\n v1 = (dctSqrt2 * p4 + 2048) >> 12;\n v2 = p2;\n v3 = p6;\n v4 = (dctSqrt1d2 * (p1 - p7) + 2048) >> 12;\n v7 = (dctSqrt1d2 * (p1 + p7) + 2048) >> 12;\n v5 = p3;\n v6 = p5;\n\n // stage 3\n // Shift v0 by 128.5 << 5 here, so we don't need to shift p0...p7 when\n // converting to UInt8 range later.\n v0 = ((v0 + v1 + 1) >> 1) + 4112;\n v1 = v0 - v1;\n t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12;\n v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12;\n v3 = t;\n v4 = (v4 + v6 + 1) >> 1;\n v6 = v4 - v6;\n v7 = (v7 + v5 + 1) >> 1;\n v5 = v7 - v5;\n\n // stage 2\n v0 = (v0 + v3 + 1) >> 1;\n v3 = v0 - v3;\n v1 = (v1 + v2 + 1) >> 1;\n v2 = v1 - v2;\n t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;\n v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;\n v7 = t;\n t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;\n v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;\n v6 = t;\n\n // stage 1\n p0 = v0 + v7;\n p7 = v0 - v7;\n p1 = v1 + v6;\n p6 = v1 - v6;\n p2 = v2 + v5;\n p5 = v2 - v5;\n p3 = v3 + v4;\n p4 = v3 - v4;\n\n // convert to 8-bit integers\n p0 = (p0 < 16) ? 0 : (p0 >= 4080) ? 255 : p0 >> 4;\n p1 = (p1 < 16) ? 0 : (p1 >= 4080) ? 255 : p1 >> 4;\n p2 = (p2 < 16) ? 0 : (p2 >= 4080) ? 255 : p2 >> 4;\n p3 = (p3 < 16) ? 0 : (p3 >= 4080) ? 255 : p3 >> 4;\n p4 = (p4 < 16) ? 0 : (p4 >= 4080) ? 255 : p4 >> 4;\n p5 = (p5 < 16) ? 0 : (p5 >= 4080) ? 255 : p5 >> 4;\n p6 = (p6 < 16) ? 0 : (p6 >= 4080) ? 255 : p6 >> 4;\n p7 = (p7 < 16) ? 0 : (p7 >= 4080) ? 255 : p7 >> 4;\n\n // store block data\n blockData[blockBufferOffset + col] = p0;\n blockData[blockBufferOffset + col + 8] = p1;\n blockData[blockBufferOffset + col + 16] = p2;\n blockData[blockBufferOffset + col + 24] = p3;\n blockData[blockBufferOffset + col + 32] = p4;\n blockData[blockBufferOffset + col + 40] = p5;\n blockData[blockBufferOffset + col + 48] = p6;\n blockData[blockBufferOffset + col + 56] = p7;\n }\n }\n\n function buildComponentData(frame, component) {\n var blocksPerLine = component.blocksPerLine;\n var blocksPerColumn = component.blocksPerColumn;\n var computationBuffer = new Int16Array(64);\n\n for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) {\n for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) {\n var offset = getBlockBufferOffset(component, blockRow, blockCol);\n quantizeAndInverse(component, offset, computationBuffer);\n }\n }\n return component.blockData;\n }\n\n function clamp0to255(a) {\n return a <= 0 ? 0 : a >= 255 ? 255 : a;\n }\n\n function findNextFileMarker(data, currentPos, startPos) {\n function peekUint16(pos) {\n return (data[pos] << 8) | data[pos + 1];\n }\n\n var maxPos = data.length - 1;\n var newPos = startPos < currentPos ? startPos : currentPos;\n\n if (currentPos >= maxPos) {\n return null; // Don't attempt to read non-existent data and just return.\n }\n var currentMarker = peekUint16(currentPos);\n if (currentMarker >= 0xFFC0 && currentMarker <= 0xFFFE) {\n return {\n invalid: null,\n marker: currentMarker,\n offset: currentPos,\n };\n }\n var newMarker = peekUint16(newPos);\n while (!(newMarker >= 0xFFC0 && newMarker <= 0xFFFE)) {\n if (++newPos >= maxPos) {\n return null; // Don't attempt to read non-existent data and just return.\n }\n newMarker = peekUint16(newPos);\n }\n return {\n invalid: currentMarker.toString(16),\n marker: newMarker,\n offset: newPos,\n };\n }\n\n JpegImage.prototype = {\n parse: function parse(data) {\n\n function readUint16() {\n var value = (data[offset] << 8) | data[offset + 1];\n offset += 2;\n return value;\n }\n\n function readDataBlock() {\n var length = readUint16();\n var endOffset = offset + length - 2;\n\n var fileMarker = findNextFileMarker(data, endOffset, offset);\n if (fileMarker && fileMarker.invalid) {\n warn('readDataBlock - incorrect length, next marker is: ' +\n fileMarker.invalid);\n endOffset = fileMarker.offset;\n }\n\n var array = data.subarray(offset, endOffset);\n offset += array.length;\n return array;\n }\n\n function prepareComponents(frame) {\n var mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / frame.maxH);\n var mcusPerColumn = Math.ceil(frame.scanLines / 8 / frame.maxV);\n for (var i = 0; i < frame.components.length; i++) {\n component = frame.components[i];\n var blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) *\n component.h / frame.maxH);\n var blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines / 8) *\n component.v / frame.maxV);\n var blocksPerLineForMcu = mcusPerLine * component.h;\n var blocksPerColumnForMcu = mcusPerColumn * component.v;\n\n var blocksBufferSize = 64 * blocksPerColumnForMcu *\n (blocksPerLineForMcu + 1);\n component.blockData = new Int16Array(blocksBufferSize);\n component.blocksPerLine = blocksPerLine;\n component.blocksPerColumn = blocksPerColumn;\n }\n frame.mcusPerLine = mcusPerLine;\n frame.mcusPerColumn = mcusPerColumn;\n }\n\n var offset = 0;\n var jfif = null;\n var adobe = null;\n var frame, resetInterval;\n var quantizationTables = [];\n var huffmanTablesAC = [], huffmanTablesDC = [];\n var fileMarker = readUint16();\n if (fileMarker !== 0xFFD8) { // SOI (Start of Image)\n throw new JpegError('SOI not found');\n }\n\n fileMarker = readUint16();\n while (fileMarker !== 0xFFD9) { // EOI (End of image)\n var i, j, l;\n switch (fileMarker) {\n case 0xFFE0: // APP0 (Application Specific)\n case 0xFFE1: // APP1\n case 0xFFE2: // APP2\n case 0xFFE3: // APP3\n case 0xFFE4: // APP4\n case 0xFFE5: // APP5\n case 0xFFE6: // APP6\n case 0xFFE7: // APP7\n case 0xFFE8: // APP8\n case 0xFFE9: // APP9\n case 0xFFEA: // APP10\n case 0xFFEB: // APP11\n case 0xFFEC: // APP12\n case 0xFFED: // APP13\n case 0xFFEE: // APP14\n case 0xFFEF: // APP15\n case 0xFFFE: // COM (Comment)\n var appData = readDataBlock();\n\n if (fileMarker === 0xFFE0) {\n if (appData[0] === 0x4A && appData[1] === 0x46 &&\n appData[2] === 0x49 && appData[3] === 0x46 &&\n appData[4] === 0) { // 'JFIF\\x00'\n jfif = {\n version: { major: appData[5], minor: appData[6], },\n densityUnits: appData[7],\n xDensity: (appData[8] << 8) | appData[9],\n yDensity: (appData[10] << 8) | appData[11],\n thumbWidth: appData[12],\n thumbHeight: appData[13],\n thumbData: appData.subarray(14, 14 +\n 3 * appData[12] * appData[13]),\n };\n }\n }\n // TODO APP1 - Exif\n if (fileMarker === 0xFFEE) {\n if (appData[0] === 0x41 && appData[1] === 0x64 &&\n appData[2] === 0x6F && appData[3] === 0x62 &&\n appData[4] === 0x65) { // 'Adobe'\n adobe = {\n version: (appData[5] << 8) | appData[6],\n flags0: (appData[7] << 8) | appData[8],\n flags1: (appData[9] << 8) | appData[10],\n transformCode: appData[11],\n };\n }\n }\n break;\n\n case 0xFFDB: // DQT (Define Quantization Tables)\n var quantizationTablesLength = readUint16();\n var quantizationTablesEnd = quantizationTablesLength + offset - 2;\n var z;\n while (offset < quantizationTablesEnd) {\n var quantizationTableSpec = data[offset++];\n var tableData = new Uint16Array(64);\n if ((quantizationTableSpec >> 4) === 0) { // 8 bit values\n for (j = 0; j < 64; j++) {\n z = dctZigZag[j];\n tableData[z] = data[offset++];\n }\n } else if ((quantizationTableSpec >> 4) === 1) { // 16 bit values\n for (j = 0; j < 64; j++) {\n z = dctZigZag[j];\n tableData[z] = readUint16();\n }\n } else {\n throw new JpegError('DQT - invalid table spec');\n }\n quantizationTables[quantizationTableSpec & 15] = tableData;\n }\n break;\n\n case 0xFFC0: // SOF0 (Start of Frame, Baseline DCT)\n case 0xFFC1: // SOF1 (Start of Frame, Extended DCT)\n case 0xFFC2: // SOF2 (Start of Frame, Progressive DCT)\n if (frame) {\n throw new JpegError('Only single frame JPEGs supported');\n }\n readUint16(); // skip data length\n frame = {};\n frame.extended = (fileMarker === 0xFFC1);\n frame.progressive = (fileMarker === 0xFFC2);\n frame.precision = data[offset++];\n frame.scanLines = readUint16();\n frame.samplesPerLine = readUint16();\n frame.components = [];\n frame.componentIds = {};\n var componentsCount = data[offset++], componentId;\n var maxH = 0, maxV = 0;\n for (i = 0; i < componentsCount; i++) {\n componentId = data[offset];\n var h = data[offset + 1] >> 4;\n var v = data[offset + 1] & 15;\n if (maxH < h) {\n maxH = h;\n }\n if (maxV < v) {\n maxV = v;\n }\n var qId = data[offset + 2];\n l = frame.components.push({\n h,\n v,\n quantizationId: qId,\n quantizationTable: null, // See comment below.\n });\n frame.componentIds[componentId] = l - 1;\n offset += 3;\n }\n frame.maxH = maxH;\n frame.maxV = maxV;\n prepareComponents(frame);\n break;\n\n case 0xFFC4: // DHT (Define Huffman Tables)\n var huffmanLength = readUint16();\n for (i = 2; i < huffmanLength;) {\n var huffmanTableSpec = data[offset++];\n var codeLengths = new Uint8Array(16);\n var codeLengthSum = 0;\n for (j = 0; j < 16; j++, offset++) {\n codeLengthSum += (codeLengths[j] = data[offset]);\n }\n var huffmanValues = new Uint8Array(codeLengthSum);\n for (j = 0; j < codeLengthSum; j++, offset++) {\n huffmanValues[j] = data[offset];\n }\n i += 17 + codeLengthSum;\n\n ((huffmanTableSpec >> 4) === 0 ?\n huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] =\n buildHuffmanTable(codeLengths, huffmanValues);\n }\n break;\n\n case 0xFFDD: // DRI (Define Restart Interval)\n readUint16(); // skip data length\n resetInterval = readUint16();\n break;\n\n case 0xFFDA: // SOS (Start of Scan)\n readUint16(); // scanLength\n var selectorsCount = data[offset++];\n var components = [], component;\n for (i = 0; i < selectorsCount; i++) {\n var componentIndex = frame.componentIds[data[offset++]];\n component = frame.components[componentIndex];\n var tableSpec = data[offset++];\n component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4];\n component.huffmanTableAC = huffmanTablesAC[tableSpec & 15];\n components.push(component);\n }\n var spectralStart = data[offset++];\n var spectralEnd = data[offset++];\n var successiveApproximation = data[offset++];\n var processed = decodeScan(data, offset,\n frame, components, resetInterval,\n spectralStart, spectralEnd,\n successiveApproximation >> 4, successiveApproximation & 15);\n offset += processed;\n break;\n\n case 0xFFFF: // Fill bytes\n if (data[offset] !== 0xFF) { // Avoid skipping a valid marker.\n offset--;\n }\n break;\n\n default:\n if (data[offset - 3] === 0xFF &&\n data[offset - 2] >= 0xC0 && data[offset - 2] <= 0xFE) {\n // could be incorrect encoding -- last 0xFF byte of the previous\n // block was eaten by the encoder\n offset -= 3;\n break;\n }\n throw new JpegError('unknown marker ' + fileMarker.toString(16));\n }\n fileMarker = readUint16();\n }\n\n this.width = frame.samplesPerLine;\n this.height = frame.scanLines;\n this.jfif = jfif;\n this.adobe = adobe;\n this.components = [];\n for (i = 0; i < frame.components.length; i++) {\n component = frame.components[i];\n\n // Prevent errors when DQT markers are placed after SOF{n} markers,\n // by assigning the `quantizationTable` entry after the entire image\n // has been parsed (fixes issue7406.pdf).\n var quantizationTable = quantizationTables[component.quantizationId];\n if (quantizationTable) {\n component.quantizationTable = quantizationTable;\n }\n\n this.components.push({\n output: buildComponentData(frame, component),\n scaleX: component.h / frame.maxH,\n scaleY: component.v / frame.maxV,\n blocksPerLine: component.blocksPerLine,\n blocksPerColumn: component.blocksPerColumn,\n });\n }\n this.numComponents = this.components.length;\n },\n\n _getLinearizedBlockData: function getLinearizedBlockData(width, height) {\n var scaleX = this.width / width, scaleY = this.height / height;\n\n var component, componentScaleX, componentScaleY, blocksPerScanline;\n var x, y, i, j, k;\n var index;\n var offset = 0;\n var output;\n var numComponents = this.components.length;\n var dataLength = width * height * numComponents;\n var data = new Uint8Array(dataLength);\n var xScaleBlockOffset = new Uint32Array(width);\n var mask3LSB = 0xfffffff8; // used to clear the 3 LSBs\n\n for (i = 0; i < numComponents; i++) {\n component = this.components[i];\n componentScaleX = component.scaleX * scaleX;\n componentScaleY = component.scaleY * scaleY;\n offset = i;\n output = component.output;\n blocksPerScanline = (component.blocksPerLine + 1) << 3;\n // precalculate the xScaleBlockOffset\n for (x = 0; x < width; x++) {\n j = 0 | (x * componentScaleX);\n xScaleBlockOffset[x] = ((j & mask3LSB) << 3) | (j & 7);\n }\n // linearize the blocks of the component\n for (y = 0; y < height; y++) {\n j = 0 | (y * componentScaleY);\n index = blocksPerScanline * (j & mask3LSB) | ((j & 7) << 3);\n for (x = 0; x < width; x++) {\n data[offset] = output[index + xScaleBlockOffset[x]];\n offset += numComponents;\n }\n }\n }\n\n // decodeTransform contains pairs of multiplier (-256..256) and additive\n var transform = this.decodeTransform;\n if (transform) {\n for (i = 0; i < dataLength;) {\n for (j = 0, k = 0; j < numComponents; j++, i++, k += 2) {\n data[i] = ((data[i] * transform[k]) >> 8) + transform[k + 1];\n }\n }\n }\n return data;\n },\n\n _isColorConversionNeeded() {\n if (this.adobe) {\n // The adobe transform marker overrides any previous setting.\n return !!this.adobe.transformCode;\n }\n if (this.numComponents === 3) {\n if (this.colorTransform === 0) {\n // If the Adobe transform marker is not present and the image\n // dictionary has a 'ColorTransform' entry, explicitly set to `0`,\n // then the colours should *not* be transformed.\n return false;\n }\n return true;\n }\n // `this.numComponents !== 3`\n if (this.colorTransform === 1) {\n // If the Adobe transform marker is not present and the image\n // dictionary has a 'ColorTransform' entry, explicitly set to `1`,\n // then the colours should be transformed.\n return true;\n }\n return false;\n },\n\n _convertYccToRgb: function convertYccToRgb(data) {\n var Y, Cb, Cr;\n for (var i = 0, length = data.length; i < length; i += 3) {\n Y = data[i ];\n Cb = data[i + 1];\n Cr = data[i + 2];\n data[i ] = clamp0to255(Y - 179.456 + 1.402 * Cr);\n data[i + 1] = clamp0to255(Y + 135.459 - 0.344 * Cb - 0.714 * Cr);\n data[i + 2] = clamp0to255(Y - 226.816 + 1.772 * Cb);\n }\n return data;\n },\n\n _convertYcckToRgb: function convertYcckToRgb(data) {\n var Y, Cb, Cr, k;\n var offset = 0;\n for (var i = 0, length = data.length; i < length; i += 4) {\n Y = data[i];\n Cb = data[i + 1];\n Cr = data[i + 2];\n k = data[i + 3];\n\n var r = -122.67195406894 +\n Cb * (-6.60635669420364e-5 * Cb + 0.000437130475926232 * Cr -\n 5.4080610064599e-5 * Y + 0.00048449797120281 * k -\n 0.154362151871126) +\n Cr * (-0.000957964378445773 * Cr + 0.000817076911346625 * Y -\n 0.00477271405408747 * k + 1.53380253221734) +\n Y * (0.000961250184130688 * Y - 0.00266257332283933 * k +\n 0.48357088451265) +\n k * (-0.000336197177618394 * k + 0.484791561490776);\n\n var g = 107.268039397724 +\n Cb * (2.19927104525741e-5 * Cb - 0.000640992018297945 * Cr +\n 0.000659397001245577 * Y + 0.000426105652938837 * k -\n 0.176491792462875) +\n Cr * (-0.000778269941513683 * Cr + 0.00130872261408275 * Y +\n 0.000770482631801132 * k - 0.151051492775562) +\n Y * (0.00126935368114843 * Y - 0.00265090189010898 * k +\n 0.25802910206845) +\n k * (-0.000318913117588328 * k - 0.213742400323665);\n\n var b = -20.810012546947 +\n Cb * (-0.000570115196973677 * Cb - 2.63409051004589e-5 * Cr +\n 0.0020741088115012 * Y - 0.00288260236853442 * k +\n 0.814272968359295) +\n Cr * (-1.53496057440975e-5 * Cr - 0.000132689043961446 * Y +\n 0.000560833691242812 * k - 0.195152027534049) +\n Y * (0.00174418132927582 * Y - 0.00255243321439347 * k +\n 0.116935020465145) +\n k * (-0.000343531996510555 * k + 0.24165260232407);\n\n data[offset++] = clamp0to255(r);\n data[offset++] = clamp0to255(g);\n data[offset++] = clamp0to255(b);\n }\n return data;\n },\n\n _convertYcckToCmyk: function convertYcckToCmyk(data) {\n var Y, Cb, Cr;\n for (var i = 0, length = data.length; i < length; i += 4) {\n Y = data[i];\n Cb = data[i + 1];\n Cr = data[i + 2];\n data[i ] = clamp0to255(434.456 - Y - 1.402 * Cr);\n data[i + 1] = clamp0to255(119.541 - Y + 0.344 * Cb + 0.714 * Cr);\n data[i + 2] = clamp0to255(481.816 - Y - 1.772 * Cb);\n // K in data[i + 3] is unchanged\n }\n return data;\n },\n\n _convertCmykToRgb: function convertCmykToRgb(data) {\n var c, m, y, k;\n var offset = 0;\n var min = -255 * 255 * 255;\n var scale = 1 / 255 / 255;\n for (var i = 0, length = data.length; i < length; i += 4) {\n c = data[i];\n m = data[i + 1];\n y = data[i + 2];\n k = data[i + 3];\n\n var r =\n c * (-4.387332384609988 * c + 54.48615194189176 * m +\n 18.82290502165302 * y + 212.25662451639585 * k -\n 72734.4411664936) +\n m * (1.7149763477362134 * m - 5.6096736904047315 * y -\n 17.873870861415444 * k - 1401.7366389350734) +\n y * (-2.5217340131683033 * y - 21.248923337353073 * k +\n 4465.541406466231) -\n k * (21.86122147463605 * k + 48317.86113160301);\n var g =\n c * (8.841041422036149 * c + 60.118027045597366 * m +\n 6.871425592049007 * y + 31.159100130055922 * k -\n 20220.756542821975) +\n m * (-15.310361306967817 * m + 17.575251261109482 * y +\n 131.35250912493976 * k - 48691.05921601825) +\n y * (4.444339102852739 * y + 9.8632861493405 * k -\n 6341.191035517494) -\n k * (20.737325471181034 * k + 47890.15695978492);\n var b =\n c * (0.8842522430003296 * c + 8.078677503112928 * m +\n 30.89978309703729 * y - 0.23883238689178934 * k -\n 3616.812083916688) +\n m * (10.49593273432072 * m + 63.02378494754052 * y +\n 50.606957656360734 * k - 28620.90484698408) +\n y * (0.03296041114873217 * y + 115.60384449646641 * k -\n 49363.43385999684) -\n k * (22.33816807309886 * k + 45932.16563550634);\n\n data[offset++] = r >= 0 ? 255 : r <= min ? 0 : 255 + r * scale | 0;\n data[offset++] = g >= 0 ? 255 : g <= min ? 0 : 255 + g * scale | 0;\n data[offset++] = b >= 0 ? 255 : b <= min ? 0 : 255 + b * scale | 0;\n }\n return data;\n },\n\n getData: function getData(width, height, forceRGBoutput) {\n if (this.numComponents > 4) {\n throw new JpegError('Unsupported color mode');\n }\n // type of data: Uint8Array(width * height * numComponents)\n var data = this._getLinearizedBlockData(width, height);\n\n if (this.numComponents === 1 && forceRGBoutput) {\n var dataLength = data.length;\n var rgbData = new Uint8Array(dataLength * 3);\n var offset = 0;\n for (var i = 0; i < dataLength; i++) {\n var grayColor = data[i];\n rgbData[offset++] = grayColor;\n rgbData[offset++] = grayColor;\n rgbData[offset++] = grayColor;\n }\n return rgbData;\n } else if (this.numComponents === 3 && this._isColorConversionNeeded()) {\n return this._convertYccToRgb(data);\n } else if (this.numComponents === 4) {\n if (this._isColorConversionNeeded()) {\n if (forceRGBoutput) {\n return this._convertYcckToRgb(data);\n }\n return this._convertYcckToCmyk(data);\n } else if (forceRGBoutput) {\n return this._convertCmykToRgb(data);\n }\n }\n return data;\n },\n };\n\n return JpegImage;\n})();\n\nexport {\n JpegImage,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/jpg.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getLookupTableFactory } from '../shared/util';\n\n// The Metrics object contains glyph widths (in glyph space units).\n// As per PDF spec, for most fonts (Type 3 being an exception) a glyph\n// space unit corresponds to 1/1000th of text space unit.\nvar getMetrics = getLookupTableFactory(function (t) {\n t['Courier'] = 600;\n t['Courier-Bold'] = 600;\n t['Courier-BoldOblique'] = 600;\n t['Courier-Oblique'] = 600;\n t['Helvetica'] = getLookupTableFactory(function (t) {\n t['space'] = 278;\n t['exclam'] = 278;\n t['quotedbl'] = 355;\n t['numbersign'] = 556;\n t['dollar'] = 556;\n t['percent'] = 889;\n t['ampersand'] = 667;\n t['quoteright'] = 222;\n t['parenleft'] = 333;\n t['parenright'] = 333;\n t['asterisk'] = 389;\n t['plus'] = 584;\n t['comma'] = 278;\n t['hyphen'] = 333;\n t['period'] = 278;\n t['slash'] = 278;\n t['zero'] = 556;\n t['one'] = 556;\n t['two'] = 556;\n t['three'] = 556;\n t['four'] = 556;\n t['five'] = 556;\n t['six'] = 556;\n t['seven'] = 556;\n t['eight'] = 556;\n t['nine'] = 556;\n t['colon'] = 278;\n t['semicolon'] = 278;\n t['less'] = 584;\n t['equal'] = 584;\n t['greater'] = 584;\n t['question'] = 556;\n t['at'] = 1015;\n t['A'] = 667;\n t['B'] = 667;\n t['C'] = 722;\n t['D'] = 722;\n t['E'] = 667;\n t['F'] = 611;\n t['G'] = 778;\n t['H'] = 722;\n t['I'] = 278;\n t['J'] = 500;\n t['K'] = 667;\n t['L'] = 556;\n t['M'] = 833;\n t['N'] = 722;\n t['O'] = 778;\n t['P'] = 667;\n t['Q'] = 778;\n t['R'] = 722;\n t['S'] = 667;\n t['T'] = 611;\n t['U'] = 722;\n t['V'] = 667;\n t['W'] = 944;\n t['X'] = 667;\n t['Y'] = 667;\n t['Z'] = 611;\n t['bracketleft'] = 278;\n t['backslash'] = 278;\n t['bracketright'] = 278;\n t['asciicircum'] = 469;\n t['underscore'] = 556;\n t['quoteleft'] = 222;\n t['a'] = 556;\n t['b'] = 556;\n t['c'] = 500;\n t['d'] = 556;\n t['e'] = 556;\n t['f'] = 278;\n t['g'] = 556;\n t['h'] = 556;\n t['i'] = 222;\n t['j'] = 222;\n t['k'] = 500;\n t['l'] = 222;\n t['m'] = 833;\n t['n'] = 556;\n t['o'] = 556;\n t['p'] = 556;\n t['q'] = 556;\n t['r'] = 333;\n t['s'] = 500;\n t['t'] = 278;\n t['u'] = 556;\n t['v'] = 500;\n t['w'] = 722;\n t['x'] = 500;\n t['y'] = 500;\n t['z'] = 500;\n t['braceleft'] = 334;\n t['bar'] = 260;\n t['braceright'] = 334;\n t['asciitilde'] = 584;\n t['exclamdown'] = 333;\n t['cent'] = 556;\n t['sterling'] = 556;\n t['fraction'] = 167;\n t['yen'] = 556;\n t['florin'] = 556;\n t['section'] = 556;\n t['currency'] = 556;\n t['quotesingle'] = 191;\n t['quotedblleft'] = 333;\n t['guillemotleft'] = 556;\n t['guilsinglleft'] = 333;\n t['guilsinglright'] = 333;\n t['fi'] = 500;\n t['fl'] = 500;\n t['endash'] = 556;\n t['dagger'] = 556;\n t['daggerdbl'] = 556;\n t['periodcentered'] = 278;\n t['paragraph'] = 537;\n t['bullet'] = 350;\n t['quotesinglbase'] = 222;\n t['quotedblbase'] = 333;\n t['quotedblright'] = 333;\n t['guillemotright'] = 556;\n t['ellipsis'] = 1000;\n t['perthousand'] = 1000;\n t['questiondown'] = 611;\n t['grave'] = 333;\n t['acute'] = 333;\n t['circumflex'] = 333;\n t['tilde'] = 333;\n t['macron'] = 333;\n t['breve'] = 333;\n t['dotaccent'] = 333;\n t['dieresis'] = 333;\n t['ring'] = 333;\n t['cedilla'] = 333;\n t['hungarumlaut'] = 333;\n t['ogonek'] = 333;\n t['caron'] = 333;\n t['emdash'] = 1000;\n t['AE'] = 1000;\n t['ordfeminine'] = 370;\n t['Lslash'] = 556;\n t['Oslash'] = 778;\n t['OE'] = 1000;\n t['ordmasculine'] = 365;\n t['ae'] = 889;\n t['dotlessi'] = 278;\n t['lslash'] = 222;\n t['oslash'] = 611;\n t['oe'] = 944;\n t['germandbls'] = 611;\n t['Idieresis'] = 278;\n t['eacute'] = 556;\n t['abreve'] = 556;\n t['uhungarumlaut'] = 556;\n t['ecaron'] = 556;\n t['Ydieresis'] = 667;\n t['divide'] = 584;\n t['Yacute'] = 667;\n t['Acircumflex'] = 667;\n t['aacute'] = 556;\n t['Ucircumflex'] = 722;\n t['yacute'] = 500;\n t['scommaaccent'] = 500;\n t['ecircumflex'] = 556;\n t['Uring'] = 722;\n t['Udieresis'] = 722;\n t['aogonek'] = 556;\n t['Uacute'] = 722;\n t['uogonek'] = 556;\n t['Edieresis'] = 667;\n t['Dcroat'] = 722;\n t['commaaccent'] = 250;\n t['copyright'] = 737;\n t['Emacron'] = 667;\n t['ccaron'] = 500;\n t['aring'] = 556;\n t['Ncommaaccent'] = 722;\n t['lacute'] = 222;\n t['agrave'] = 556;\n t['Tcommaaccent'] = 611;\n t['Cacute'] = 722;\n t['atilde'] = 556;\n t['Edotaccent'] = 667;\n t['scaron'] = 500;\n t['scedilla'] = 500;\n t['iacute'] = 278;\n t['lozenge'] = 471;\n t['Rcaron'] = 722;\n t['Gcommaaccent'] = 778;\n t['ucircumflex'] = 556;\n t['acircumflex'] = 556;\n t['Amacron'] = 667;\n t['rcaron'] = 333;\n t['ccedilla'] = 500;\n t['Zdotaccent'] = 611;\n t['Thorn'] = 667;\n t['Omacron'] = 778;\n t['Racute'] = 722;\n t['Sacute'] = 667;\n t['dcaron'] = 643;\n t['Umacron'] = 722;\n t['uring'] = 556;\n t['threesuperior'] = 333;\n t['Ograve'] = 778;\n t['Agrave'] = 667;\n t['Abreve'] = 667;\n t['multiply'] = 584;\n t['uacute'] = 556;\n t['Tcaron'] = 611;\n t['partialdiff'] = 476;\n t['ydieresis'] = 500;\n t['Nacute'] = 722;\n t['icircumflex'] = 278;\n t['Ecircumflex'] = 667;\n t['adieresis'] = 556;\n t['edieresis'] = 556;\n t['cacute'] = 500;\n t['nacute'] = 556;\n t['umacron'] = 556;\n t['Ncaron'] = 722;\n t['Iacute'] = 278;\n t['plusminus'] = 584;\n t['brokenbar'] = 260;\n t['registered'] = 737;\n t['Gbreve'] = 778;\n t['Idotaccent'] = 278;\n t['summation'] = 600;\n t['Egrave'] = 667;\n t['racute'] = 333;\n t['omacron'] = 556;\n t['Zacute'] = 611;\n t['Zcaron'] = 611;\n t['greaterequal'] = 549;\n t['Eth'] = 722;\n t['Ccedilla'] = 722;\n t['lcommaaccent'] = 222;\n t['tcaron'] = 317;\n t['eogonek'] = 556;\n t['Uogonek'] = 722;\n t['Aacute'] = 667;\n t['Adieresis'] = 667;\n t['egrave'] = 556;\n t['zacute'] = 500;\n t['iogonek'] = 222;\n t['Oacute'] = 778;\n t['oacute'] = 556;\n t['amacron'] = 556;\n t['sacute'] = 500;\n t['idieresis'] = 278;\n t['Ocircumflex'] = 778;\n t['Ugrave'] = 722;\n t['Delta'] = 612;\n t['thorn'] = 556;\n t['twosuperior'] = 333;\n t['Odieresis'] = 778;\n t['mu'] = 556;\n t['igrave'] = 278;\n t['ohungarumlaut'] = 556;\n t['Eogonek'] = 667;\n t['dcroat'] = 556;\n t['threequarters'] = 834;\n t['Scedilla'] = 667;\n t['lcaron'] = 299;\n t['Kcommaaccent'] = 667;\n t['Lacute'] = 556;\n t['trademark'] = 1000;\n t['edotaccent'] = 556;\n t['Igrave'] = 278;\n t['Imacron'] = 278;\n t['Lcaron'] = 556;\n t['onehalf'] = 834;\n t['lessequal'] = 549;\n t['ocircumflex'] = 556;\n t['ntilde'] = 556;\n t['Uhungarumlaut'] = 722;\n t['Eacute'] = 667;\n t['emacron'] = 556;\n t['gbreve'] = 556;\n t['onequarter'] = 834;\n t['Scaron'] = 667;\n t['Scommaaccent'] = 667;\n t['Ohungarumlaut'] = 778;\n t['degree'] = 400;\n t['ograve'] = 556;\n t['Ccaron'] = 722;\n t['ugrave'] = 556;\n t['radical'] = 453;\n t['Dcaron'] = 722;\n t['rcommaaccent'] = 333;\n t['Ntilde'] = 722;\n t['otilde'] = 556;\n t['Rcommaaccent'] = 722;\n t['Lcommaaccent'] = 556;\n t['Atilde'] = 667;\n t['Aogonek'] = 667;\n t['Aring'] = 667;\n t['Otilde'] = 778;\n t['zdotaccent'] = 500;\n t['Ecaron'] = 667;\n t['Iogonek'] = 278;\n t['kcommaaccent'] = 500;\n t['minus'] = 584;\n t['Icircumflex'] = 278;\n t['ncaron'] = 556;\n t['tcommaaccent'] = 278;\n t['logicalnot'] = 584;\n t['odieresis'] = 556;\n t['udieresis'] = 556;\n t['notequal'] = 549;\n t['gcommaaccent'] = 556;\n t['eth'] = 556;\n t['zcaron'] = 500;\n t['ncommaaccent'] = 556;\n t['onesuperior'] = 333;\n t['imacron'] = 278;\n t['Euro'] = 556;\n });\n t['Helvetica-Bold'] = getLookupTableFactory(function (t) {\n t['space'] = 278;\n t['exclam'] = 333;\n t['quotedbl'] = 474;\n t['numbersign'] = 556;\n t['dollar'] = 556;\n t['percent'] = 889;\n t['ampersand'] = 722;\n t['quoteright'] = 278;\n t['parenleft'] = 333;\n t['parenright'] = 333;\n t['asterisk'] = 389;\n t['plus'] = 584;\n t['comma'] = 278;\n t['hyphen'] = 333;\n t['period'] = 278;\n t['slash'] = 278;\n t['zero'] = 556;\n t['one'] = 556;\n t['two'] = 556;\n t['three'] = 556;\n t['four'] = 556;\n t['five'] = 556;\n t['six'] = 556;\n t['seven'] = 556;\n t['eight'] = 556;\n t['nine'] = 556;\n t['colon'] = 333;\n t['semicolon'] = 333;\n t['less'] = 584;\n t['equal'] = 584;\n t['greater'] = 584;\n t['question'] = 611;\n t['at'] = 975;\n t['A'] = 722;\n t['B'] = 722;\n t['C'] = 722;\n t['D'] = 722;\n t['E'] = 667;\n t['F'] = 611;\n t['G'] = 778;\n t['H'] = 722;\n t['I'] = 278;\n t['J'] = 556;\n t['K'] = 722;\n t['L'] = 611;\n t['M'] = 833;\n t['N'] = 722;\n t['O'] = 778;\n t['P'] = 667;\n t['Q'] = 778;\n t['R'] = 722;\n t['S'] = 667;\n t['T'] = 611;\n t['U'] = 722;\n t['V'] = 667;\n t['W'] = 944;\n t['X'] = 667;\n t['Y'] = 667;\n t['Z'] = 611;\n t['bracketleft'] = 333;\n t['backslash'] = 278;\n t['bracketright'] = 333;\n t['asciicircum'] = 584;\n t['underscore'] = 556;\n t['quoteleft'] = 278;\n t['a'] = 556;\n t['b'] = 611;\n t['c'] = 556;\n t['d'] = 611;\n t['e'] = 556;\n t['f'] = 333;\n t['g'] = 611;\n t['h'] = 611;\n t['i'] = 278;\n t['j'] = 278;\n t['k'] = 556;\n t['l'] = 278;\n t['m'] = 889;\n t['n'] = 611;\n t['o'] = 611;\n t['p'] = 611;\n t['q'] = 611;\n t['r'] = 389;\n t['s'] = 556;\n t['t'] = 333;\n t['u'] = 611;\n t['v'] = 556;\n t['w'] = 778;\n t['x'] = 556;\n t['y'] = 556;\n t['z'] = 500;\n t['braceleft'] = 389;\n t['bar'] = 280;\n t['braceright'] = 389;\n t['asciitilde'] = 584;\n t['exclamdown'] = 333;\n t['cent'] = 556;\n t['sterling'] = 556;\n t['fraction'] = 167;\n t['yen'] = 556;\n t['florin'] = 556;\n t['section'] = 556;\n t['currency'] = 556;\n t['quotesingle'] = 238;\n t['quotedblleft'] = 500;\n t['guillemotleft'] = 556;\n t['guilsinglleft'] = 333;\n t['guilsinglright'] = 333;\n t['fi'] = 611;\n t['fl'] = 611;\n t['endash'] = 556;\n t['dagger'] = 556;\n t['daggerdbl'] = 556;\n t['periodcentered'] = 278;\n t['paragraph'] = 556;\n t['bullet'] = 350;\n t['quotesinglbase'] = 278;\n t['quotedblbase'] = 500;\n t['quotedblright'] = 500;\n t['guillemotright'] = 556;\n t['ellipsis'] = 1000;\n t['perthousand'] = 1000;\n t['questiondown'] = 611;\n t['grave'] = 333;\n t['acute'] = 333;\n t['circumflex'] = 333;\n t['tilde'] = 333;\n t['macron'] = 333;\n t['breve'] = 333;\n t['dotaccent'] = 333;\n t['dieresis'] = 333;\n t['ring'] = 333;\n t['cedilla'] = 333;\n t['hungarumlaut'] = 333;\n t['ogonek'] = 333;\n t['caron'] = 333;\n t['emdash'] = 1000;\n t['AE'] = 1000;\n t['ordfeminine'] = 370;\n t['Lslash'] = 611;\n t['Oslash'] = 778;\n t['OE'] = 1000;\n t['ordmasculine'] = 365;\n t['ae'] = 889;\n t['dotlessi'] = 278;\n t['lslash'] = 278;\n t['oslash'] = 611;\n t['oe'] = 944;\n t['germandbls'] = 611;\n t['Idieresis'] = 278;\n t['eacute'] = 556;\n t['abreve'] = 556;\n t['uhungarumlaut'] = 611;\n t['ecaron'] = 556;\n t['Ydieresis'] = 667;\n t['divide'] = 584;\n t['Yacute'] = 667;\n t['Acircumflex'] = 722;\n t['aacute'] = 556;\n t['Ucircumflex'] = 722;\n t['yacute'] = 556;\n t['scommaaccent'] = 556;\n t['ecircumflex'] = 556;\n t['Uring'] = 722;\n t['Udieresis'] = 722;\n t['aogonek'] = 556;\n t['Uacute'] = 722;\n t['uogonek'] = 611;\n t['Edieresis'] = 667;\n t['Dcroat'] = 722;\n t['commaaccent'] = 250;\n t['copyright'] = 737;\n t['Emacron'] = 667;\n t['ccaron'] = 556;\n t['aring'] = 556;\n t['Ncommaaccent'] = 722;\n t['lacute'] = 278;\n t['agrave'] = 556;\n t['Tcommaaccent'] = 611;\n t['Cacute'] = 722;\n t['atilde'] = 556;\n t['Edotaccent'] = 667;\n t['scaron'] = 556;\n t['scedilla'] = 556;\n t['iacute'] = 278;\n t['lozenge'] = 494;\n t['Rcaron'] = 722;\n t['Gcommaaccent'] = 778;\n t['ucircumflex'] = 611;\n t['acircumflex'] = 556;\n t['Amacron'] = 722;\n t['rcaron'] = 389;\n t['ccedilla'] = 556;\n t['Zdotaccent'] = 611;\n t['Thorn'] = 667;\n t['Omacron'] = 778;\n t['Racute'] = 722;\n t['Sacute'] = 667;\n t['dcaron'] = 743;\n t['Umacron'] = 722;\n t['uring'] = 611;\n t['threesuperior'] = 333;\n t['Ograve'] = 778;\n t['Agrave'] = 722;\n t['Abreve'] = 722;\n t['multiply'] = 584;\n t['uacute'] = 611;\n t['Tcaron'] = 611;\n t['partialdiff'] = 494;\n t['ydieresis'] = 556;\n t['Nacute'] = 722;\n t['icircumflex'] = 278;\n t['Ecircumflex'] = 667;\n t['adieresis'] = 556;\n t['edieresis'] = 556;\n t['cacute'] = 556;\n t['nacute'] = 611;\n t['umacron'] = 611;\n t['Ncaron'] = 722;\n t['Iacute'] = 278;\n t['plusminus'] = 584;\n t['brokenbar'] = 280;\n t['registered'] = 737;\n t['Gbreve'] = 778;\n t['Idotaccent'] = 278;\n t['summation'] = 600;\n t['Egrave'] = 667;\n t['racute'] = 389;\n t['omacron'] = 611;\n t['Zacute'] = 611;\n t['Zcaron'] = 611;\n t['greaterequal'] = 549;\n t['Eth'] = 722;\n t['Ccedilla'] = 722;\n t['lcommaaccent'] = 278;\n t['tcaron'] = 389;\n t['eogonek'] = 556;\n t['Uogonek'] = 722;\n t['Aacute'] = 722;\n t['Adieresis'] = 722;\n t['egrave'] = 556;\n t['zacute'] = 500;\n t['iogonek'] = 278;\n t['Oacute'] = 778;\n t['oacute'] = 611;\n t['amacron'] = 556;\n t['sacute'] = 556;\n t['idieresis'] = 278;\n t['Ocircumflex'] = 778;\n t['Ugrave'] = 722;\n t['Delta'] = 612;\n t['thorn'] = 611;\n t['twosuperior'] = 333;\n t['Odieresis'] = 778;\n t['mu'] = 611;\n t['igrave'] = 278;\n t['ohungarumlaut'] = 611;\n t['Eogonek'] = 667;\n t['dcroat'] = 611;\n t['threequarters'] = 834;\n t['Scedilla'] = 667;\n t['lcaron'] = 400;\n t['Kcommaaccent'] = 722;\n t['Lacute'] = 611;\n t['trademark'] = 1000;\n t['edotaccent'] = 556;\n t['Igrave'] = 278;\n t['Imacron'] = 278;\n t['Lcaron'] = 611;\n t['onehalf'] = 834;\n t['lessequal'] = 549;\n t['ocircumflex'] = 611;\n t['ntilde'] = 611;\n t['Uhungarumlaut'] = 722;\n t['Eacute'] = 667;\n t['emacron'] = 556;\n t['gbreve'] = 611;\n t['onequarter'] = 834;\n t['Scaron'] = 667;\n t['Scommaaccent'] = 667;\n t['Ohungarumlaut'] = 778;\n t['degree'] = 400;\n t['ograve'] = 611;\n t['Ccaron'] = 722;\n t['ugrave'] = 611;\n t['radical'] = 549;\n t['Dcaron'] = 722;\n t['rcommaaccent'] = 389;\n t['Ntilde'] = 722;\n t['otilde'] = 611;\n t['Rcommaaccent'] = 722;\n t['Lcommaaccent'] = 611;\n t['Atilde'] = 722;\n t['Aogonek'] = 722;\n t['Aring'] = 722;\n t['Otilde'] = 778;\n t['zdotaccent'] = 500;\n t['Ecaron'] = 667;\n t['Iogonek'] = 278;\n t['kcommaaccent'] = 556;\n t['minus'] = 584;\n t['Icircumflex'] = 278;\n t['ncaron'] = 611;\n t['tcommaaccent'] = 333;\n t['logicalnot'] = 584;\n t['odieresis'] = 611;\n t['udieresis'] = 611;\n t['notequal'] = 549;\n t['gcommaaccent'] = 611;\n t['eth'] = 611;\n t['zcaron'] = 500;\n t['ncommaaccent'] = 611;\n t['onesuperior'] = 333;\n t['imacron'] = 278;\n t['Euro'] = 556;\n });\n t['Helvetica-BoldOblique'] = getLookupTableFactory(function (t) {\n t['space'] = 278;\n t['exclam'] = 333;\n t['quotedbl'] = 474;\n t['numbersign'] = 556;\n t['dollar'] = 556;\n t['percent'] = 889;\n t['ampersand'] = 722;\n t['quoteright'] = 278;\n t['parenleft'] = 333;\n t['parenright'] = 333;\n t['asterisk'] = 389;\n t['plus'] = 584;\n t['comma'] = 278;\n t['hyphen'] = 333;\n t['period'] = 278;\n t['slash'] = 278;\n t['zero'] = 556;\n t['one'] = 556;\n t['two'] = 556;\n t['three'] = 556;\n t['four'] = 556;\n t['five'] = 556;\n t['six'] = 556;\n t['seven'] = 556;\n t['eight'] = 556;\n t['nine'] = 556;\n t['colon'] = 333;\n t['semicolon'] = 333;\n t['less'] = 584;\n t['equal'] = 584;\n t['greater'] = 584;\n t['question'] = 611;\n t['at'] = 975;\n t['A'] = 722;\n t['B'] = 722;\n t['C'] = 722;\n t['D'] = 722;\n t['E'] = 667;\n t['F'] = 611;\n t['G'] = 778;\n t['H'] = 722;\n t['I'] = 278;\n t['J'] = 556;\n t['K'] = 722;\n t['L'] = 611;\n t['M'] = 833;\n t['N'] = 722;\n t['O'] = 778;\n t['P'] = 667;\n t['Q'] = 778;\n t['R'] = 722;\n t['S'] = 667;\n t['T'] = 611;\n t['U'] = 722;\n t['V'] = 667;\n t['W'] = 944;\n t['X'] = 667;\n t['Y'] = 667;\n t['Z'] = 611;\n t['bracketleft'] = 333;\n t['backslash'] = 278;\n t['bracketright'] = 333;\n t['asciicircum'] = 584;\n t['underscore'] = 556;\n t['quoteleft'] = 278;\n t['a'] = 556;\n t['b'] = 611;\n t['c'] = 556;\n t['d'] = 611;\n t['e'] = 556;\n t['f'] = 333;\n t['g'] = 611;\n t['h'] = 611;\n t['i'] = 278;\n t['j'] = 278;\n t['k'] = 556;\n t['l'] = 278;\n t['m'] = 889;\n t['n'] = 611;\n t['o'] = 611;\n t['p'] = 611;\n t['q'] = 611;\n t['r'] = 389;\n t['s'] = 556;\n t['t'] = 333;\n t['u'] = 611;\n t['v'] = 556;\n t['w'] = 778;\n t['x'] = 556;\n t['y'] = 556;\n t['z'] = 500;\n t['braceleft'] = 389;\n t['bar'] = 280;\n t['braceright'] = 389;\n t['asciitilde'] = 584;\n t['exclamdown'] = 333;\n t['cent'] = 556;\n t['sterling'] = 556;\n t['fraction'] = 167;\n t['yen'] = 556;\n t['florin'] = 556;\n t['section'] = 556;\n t['currency'] = 556;\n t['quotesingle'] = 238;\n t['quotedblleft'] = 500;\n t['guillemotleft'] = 556;\n t['guilsinglleft'] = 333;\n t['guilsinglright'] = 333;\n t['fi'] = 611;\n t['fl'] = 611;\n t['endash'] = 556;\n t['dagger'] = 556;\n t['daggerdbl'] = 556;\n t['periodcentered'] = 278;\n t['paragraph'] = 556;\n t['bullet'] = 350;\n t['quotesinglbase'] = 278;\n t['quotedblbase'] = 500;\n t['quotedblright'] = 500;\n t['guillemotright'] = 556;\n t['ellipsis'] = 1000;\n t['perthousand'] = 1000;\n t['questiondown'] = 611;\n t['grave'] = 333;\n t['acute'] = 333;\n t['circumflex'] = 333;\n t['tilde'] = 333;\n t['macron'] = 333;\n t['breve'] = 333;\n t['dotaccent'] = 333;\n t['dieresis'] = 333;\n t['ring'] = 333;\n t['cedilla'] = 333;\n t['hungarumlaut'] = 333;\n t['ogonek'] = 333;\n t['caron'] = 333;\n t['emdash'] = 1000;\n t['AE'] = 1000;\n t['ordfeminine'] = 370;\n t['Lslash'] = 611;\n t['Oslash'] = 778;\n t['OE'] = 1000;\n t['ordmasculine'] = 365;\n t['ae'] = 889;\n t['dotlessi'] = 278;\n t['lslash'] = 278;\n t['oslash'] = 611;\n t['oe'] = 944;\n t['germandbls'] = 611;\n t['Idieresis'] = 278;\n t['eacute'] = 556;\n t['abreve'] = 556;\n t['uhungarumlaut'] = 611;\n t['ecaron'] = 556;\n t['Ydieresis'] = 667;\n t['divide'] = 584;\n t['Yacute'] = 667;\n t['Acircumflex'] = 722;\n t['aacute'] = 556;\n t['Ucircumflex'] = 722;\n t['yacute'] = 556;\n t['scommaaccent'] = 556;\n t['ecircumflex'] = 556;\n t['Uring'] = 722;\n t['Udieresis'] = 722;\n t['aogonek'] = 556;\n t['Uacute'] = 722;\n t['uogonek'] = 611;\n t['Edieresis'] = 667;\n t['Dcroat'] = 722;\n t['commaaccent'] = 250;\n t['copyright'] = 737;\n t['Emacron'] = 667;\n t['ccaron'] = 556;\n t['aring'] = 556;\n t['Ncommaaccent'] = 722;\n t['lacute'] = 278;\n t['agrave'] = 556;\n t['Tcommaaccent'] = 611;\n t['Cacute'] = 722;\n t['atilde'] = 556;\n t['Edotaccent'] = 667;\n t['scaron'] = 556;\n t['scedilla'] = 556;\n t['iacute'] = 278;\n t['lozenge'] = 494;\n t['Rcaron'] = 722;\n t['Gcommaaccent'] = 778;\n t['ucircumflex'] = 611;\n t['acircumflex'] = 556;\n t['Amacron'] = 722;\n t['rcaron'] = 389;\n t['ccedilla'] = 556;\n t['Zdotaccent'] = 611;\n t['Thorn'] = 667;\n t['Omacron'] = 778;\n t['Racute'] = 722;\n t['Sacute'] = 667;\n t['dcaron'] = 743;\n t['Umacron'] = 722;\n t['uring'] = 611;\n t['threesuperior'] = 333;\n t['Ograve'] = 778;\n t['Agrave'] = 722;\n t['Abreve'] = 722;\n t['multiply'] = 584;\n t['uacute'] = 611;\n t['Tcaron'] = 611;\n t['partialdiff'] = 494;\n t['ydieresis'] = 556;\n t['Nacute'] = 722;\n t['icircumflex'] = 278;\n t['Ecircumflex'] = 667;\n t['adieresis'] = 556;\n t['edieresis'] = 556;\n t['cacute'] = 556;\n t['nacute'] = 611;\n t['umacron'] = 611;\n t['Ncaron'] = 722;\n t['Iacute'] = 278;\n t['plusminus'] = 584;\n t['brokenbar'] = 280;\n t['registered'] = 737;\n t['Gbreve'] = 778;\n t['Idotaccent'] = 278;\n t['summation'] = 600;\n t['Egrave'] = 667;\n t['racute'] = 389;\n t['omacron'] = 611;\n t['Zacute'] = 611;\n t['Zcaron'] = 611;\n t['greaterequal'] = 549;\n t['Eth'] = 722;\n t['Ccedilla'] = 722;\n t['lcommaaccent'] = 278;\n t['tcaron'] = 389;\n t['eogonek'] = 556;\n t['Uogonek'] = 722;\n t['Aacute'] = 722;\n t['Adieresis'] = 722;\n t['egrave'] = 556;\n t['zacute'] = 500;\n t['iogonek'] = 278;\n t['Oacute'] = 778;\n t['oacute'] = 611;\n t['amacron'] = 556;\n t['sacute'] = 556;\n t['idieresis'] = 278;\n t['Ocircumflex'] = 778;\n t['Ugrave'] = 722;\n t['Delta'] = 612;\n t['thorn'] = 611;\n t['twosuperior'] = 333;\n t['Odieresis'] = 778;\n t['mu'] = 611;\n t['igrave'] = 278;\n t['ohungarumlaut'] = 611;\n t['Eogonek'] = 667;\n t['dcroat'] = 611;\n t['threequarters'] = 834;\n t['Scedilla'] = 667;\n t['lcaron'] = 400;\n t['Kcommaaccent'] = 722;\n t['Lacute'] = 611;\n t['trademark'] = 1000;\n t['edotaccent'] = 556;\n t['Igrave'] = 278;\n t['Imacron'] = 278;\n t['Lcaron'] = 611;\n t['onehalf'] = 834;\n t['lessequal'] = 549;\n t['ocircumflex'] = 611;\n t['ntilde'] = 611;\n t['Uhungarumlaut'] = 722;\n t['Eacute'] = 667;\n t['emacron'] = 556;\n t['gbreve'] = 611;\n t['onequarter'] = 834;\n t['Scaron'] = 667;\n t['Scommaaccent'] = 667;\n t['Ohungarumlaut'] = 778;\n t['degree'] = 400;\n t['ograve'] = 611;\n t['Ccaron'] = 722;\n t['ugrave'] = 611;\n t['radical'] = 549;\n t['Dcaron'] = 722;\n t['rcommaaccent'] = 389;\n t['Ntilde'] = 722;\n t['otilde'] = 611;\n t['Rcommaaccent'] = 722;\n t['Lcommaaccent'] = 611;\n t['Atilde'] = 722;\n t['Aogonek'] = 722;\n t['Aring'] = 722;\n t['Otilde'] = 778;\n t['zdotaccent'] = 500;\n t['Ecaron'] = 667;\n t['Iogonek'] = 278;\n t['kcommaaccent'] = 556;\n t['minus'] = 584;\n t['Icircumflex'] = 278;\n t['ncaron'] = 611;\n t['tcommaaccent'] = 333;\n t['logicalnot'] = 584;\n t['odieresis'] = 611;\n t['udieresis'] = 611;\n t['notequal'] = 549;\n t['gcommaaccent'] = 611;\n t['eth'] = 611;\n t['zcaron'] = 500;\n t['ncommaaccent'] = 611;\n t['onesuperior'] = 333;\n t['imacron'] = 278;\n t['Euro'] = 556;\n });\n t['Helvetica-Oblique'] = getLookupTableFactory(function (t) {\n t['space'] = 278;\n t['exclam'] = 278;\n t['quotedbl'] = 355;\n t['numbersign'] = 556;\n t['dollar'] = 556;\n t['percent'] = 889;\n t['ampersand'] = 667;\n t['quoteright'] = 222;\n t['parenleft'] = 333;\n t['parenright'] = 333;\n t['asterisk'] = 389;\n t['plus'] = 584;\n t['comma'] = 278;\n t['hyphen'] = 333;\n t['period'] = 278;\n t['slash'] = 278;\n t['zero'] = 556;\n t['one'] = 556;\n t['two'] = 556;\n t['three'] = 556;\n t['four'] = 556;\n t['five'] = 556;\n t['six'] = 556;\n t['seven'] = 556;\n t['eight'] = 556;\n t['nine'] = 556;\n t['colon'] = 278;\n t['semicolon'] = 278;\n t['less'] = 584;\n t['equal'] = 584;\n t['greater'] = 584;\n t['question'] = 556;\n t['at'] = 1015;\n t['A'] = 667;\n t['B'] = 667;\n t['C'] = 722;\n t['D'] = 722;\n t['E'] = 667;\n t['F'] = 611;\n t['G'] = 778;\n t['H'] = 722;\n t['I'] = 278;\n t['J'] = 500;\n t['K'] = 667;\n t['L'] = 556;\n t['M'] = 833;\n t['N'] = 722;\n t['O'] = 778;\n t['P'] = 667;\n t['Q'] = 778;\n t['R'] = 722;\n t['S'] = 667;\n t['T'] = 611;\n t['U'] = 722;\n t['V'] = 667;\n t['W'] = 944;\n t['X'] = 667;\n t['Y'] = 667;\n t['Z'] = 611;\n t['bracketleft'] = 278;\n t['backslash'] = 278;\n t['bracketright'] = 278;\n t['asciicircum'] = 469;\n t['underscore'] = 556;\n t['quoteleft'] = 222;\n t['a'] = 556;\n t['b'] = 556;\n t['c'] = 500;\n t['d'] = 556;\n t['e'] = 556;\n t['f'] = 278;\n t['g'] = 556;\n t['h'] = 556;\n t['i'] = 222;\n t['j'] = 222;\n t['k'] = 500;\n t['l'] = 222;\n t['m'] = 833;\n t['n'] = 556;\n t['o'] = 556;\n t['p'] = 556;\n t['q'] = 556;\n t['r'] = 333;\n t['s'] = 500;\n t['t'] = 278;\n t['u'] = 556;\n t['v'] = 500;\n t['w'] = 722;\n t['x'] = 500;\n t['y'] = 500;\n t['z'] = 500;\n t['braceleft'] = 334;\n t['bar'] = 260;\n t['braceright'] = 334;\n t['asciitilde'] = 584;\n t['exclamdown'] = 333;\n t['cent'] = 556;\n t['sterling'] = 556;\n t['fraction'] = 167;\n t['yen'] = 556;\n t['florin'] = 556;\n t['section'] = 556;\n t['currency'] = 556;\n t['quotesingle'] = 191;\n t['quotedblleft'] = 333;\n t['guillemotleft'] = 556;\n t['guilsinglleft'] = 333;\n t['guilsinglright'] = 333;\n t['fi'] = 500;\n t['fl'] = 500;\n t['endash'] = 556;\n t['dagger'] = 556;\n t['daggerdbl'] = 556;\n t['periodcentered'] = 278;\n t['paragraph'] = 537;\n t['bullet'] = 350;\n t['quotesinglbase'] = 222;\n t['quotedblbase'] = 333;\n t['quotedblright'] = 333;\n t['guillemotright'] = 556;\n t['ellipsis'] = 1000;\n t['perthousand'] = 1000;\n t['questiondown'] = 611;\n t['grave'] = 333;\n t['acute'] = 333;\n t['circumflex'] = 333;\n t['tilde'] = 333;\n t['macron'] = 333;\n t['breve'] = 333;\n t['dotaccent'] = 333;\n t['dieresis'] = 333;\n t['ring'] = 333;\n t['cedilla'] = 333;\n t['hungarumlaut'] = 333;\n t['ogonek'] = 333;\n t['caron'] = 333;\n t['emdash'] = 1000;\n t['AE'] = 1000;\n t['ordfeminine'] = 370;\n t['Lslash'] = 556;\n t['Oslash'] = 778;\n t['OE'] = 1000;\n t['ordmasculine'] = 365;\n t['ae'] = 889;\n t['dotlessi'] = 278;\n t['lslash'] = 222;\n t['oslash'] = 611;\n t['oe'] = 944;\n t['germandbls'] = 611;\n t['Idieresis'] = 278;\n t['eacute'] = 556;\n t['abreve'] = 556;\n t['uhungarumlaut'] = 556;\n t['ecaron'] = 556;\n t['Ydieresis'] = 667;\n t['divide'] = 584;\n t['Yacute'] = 667;\n t['Acircumflex'] = 667;\n t['aacute'] = 556;\n t['Ucircumflex'] = 722;\n t['yacute'] = 500;\n t['scommaaccent'] = 500;\n t['ecircumflex'] = 556;\n t['Uring'] = 722;\n t['Udieresis'] = 722;\n t['aogonek'] = 556;\n t['Uacute'] = 722;\n t['uogonek'] = 556;\n t['Edieresis'] = 667;\n t['Dcroat'] = 722;\n t['commaaccent'] = 250;\n t['copyright'] = 737;\n t['Emacron'] = 667;\n t['ccaron'] = 500;\n t['aring'] = 556;\n t['Ncommaaccent'] = 722;\n t['lacute'] = 222;\n t['agrave'] = 556;\n t['Tcommaaccent'] = 611;\n t['Cacute'] = 722;\n t['atilde'] = 556;\n t['Edotaccent'] = 667;\n t['scaron'] = 500;\n t['scedilla'] = 500;\n t['iacute'] = 278;\n t['lozenge'] = 471;\n t['Rcaron'] = 722;\n t['Gcommaaccent'] = 778;\n t['ucircumflex'] = 556;\n t['acircumflex'] = 556;\n t['Amacron'] = 667;\n t['rcaron'] = 333;\n t['ccedilla'] = 500;\n t['Zdotaccent'] = 611;\n t['Thorn'] = 667;\n t['Omacron'] = 778;\n t['Racute'] = 722;\n t['Sacute'] = 667;\n t['dcaron'] = 643;\n t['Umacron'] = 722;\n t['uring'] = 556;\n t['threesuperior'] = 333;\n t['Ograve'] = 778;\n t['Agrave'] = 667;\n t['Abreve'] = 667;\n t['multiply'] = 584;\n t['uacute'] = 556;\n t['Tcaron'] = 611;\n t['partialdiff'] = 476;\n t['ydieresis'] = 500;\n t['Nacute'] = 722;\n t['icircumflex'] = 278;\n t['Ecircumflex'] = 667;\n t['adieresis'] = 556;\n t['edieresis'] = 556;\n t['cacute'] = 500;\n t['nacute'] = 556;\n t['umacron'] = 556;\n t['Ncaron'] = 722;\n t['Iacute'] = 278;\n t['plusminus'] = 584;\n t['brokenbar'] = 260;\n t['registered'] = 737;\n t['Gbreve'] = 778;\n t['Idotaccent'] = 278;\n t['summation'] = 600;\n t['Egrave'] = 667;\n t['racute'] = 333;\n t['omacron'] = 556;\n t['Zacute'] = 611;\n t['Zcaron'] = 611;\n t['greaterequal'] = 549;\n t['Eth'] = 722;\n t['Ccedilla'] = 722;\n t['lcommaaccent'] = 222;\n t['tcaron'] = 317;\n t['eogonek'] = 556;\n t['Uogonek'] = 722;\n t['Aacute'] = 667;\n t['Adieresis'] = 667;\n t['egrave'] = 556;\n t['zacute'] = 500;\n t['iogonek'] = 222;\n t['Oacute'] = 778;\n t['oacute'] = 556;\n t['amacron'] = 556;\n t['sacute'] = 500;\n t['idieresis'] = 278;\n t['Ocircumflex'] = 778;\n t['Ugrave'] = 722;\n t['Delta'] = 612;\n t['thorn'] = 556;\n t['twosuperior'] = 333;\n t['Odieresis'] = 778;\n t['mu'] = 556;\n t['igrave'] = 278;\n t['ohungarumlaut'] = 556;\n t['Eogonek'] = 667;\n t['dcroat'] = 556;\n t['threequarters'] = 834;\n t['Scedilla'] = 667;\n t['lcaron'] = 299;\n t['Kcommaaccent'] = 667;\n t['Lacute'] = 556;\n t['trademark'] = 1000;\n t['edotaccent'] = 556;\n t['Igrave'] = 278;\n t['Imacron'] = 278;\n t['Lcaron'] = 556;\n t['onehalf'] = 834;\n t['lessequal'] = 549;\n t['ocircumflex'] = 556;\n t['ntilde'] = 556;\n t['Uhungarumlaut'] = 722;\n t['Eacute'] = 667;\n t['emacron'] = 556;\n t['gbreve'] = 556;\n t['onequarter'] = 834;\n t['Scaron'] = 667;\n t['Scommaaccent'] = 667;\n t['Ohungarumlaut'] = 778;\n t['degree'] = 400;\n t['ograve'] = 556;\n t['Ccaron'] = 722;\n t['ugrave'] = 556;\n t['radical'] = 453;\n t['Dcaron'] = 722;\n t['rcommaaccent'] = 333;\n t['Ntilde'] = 722;\n t['otilde'] = 556;\n t['Rcommaaccent'] = 722;\n t['Lcommaaccent'] = 556;\n t['Atilde'] = 667;\n t['Aogonek'] = 667;\n t['Aring'] = 667;\n t['Otilde'] = 778;\n t['zdotaccent'] = 500;\n t['Ecaron'] = 667;\n t['Iogonek'] = 278;\n t['kcommaaccent'] = 500;\n t['minus'] = 584;\n t['Icircumflex'] = 278;\n t['ncaron'] = 556;\n t['tcommaaccent'] = 278;\n t['logicalnot'] = 584;\n t['odieresis'] = 556;\n t['udieresis'] = 556;\n t['notequal'] = 549;\n t['gcommaaccent'] = 556;\n t['eth'] = 556;\n t['zcaron'] = 500;\n t['ncommaaccent'] = 556;\n t['onesuperior'] = 333;\n t['imacron'] = 278;\n t['Euro'] = 556;\n });\n t['Symbol'] = getLookupTableFactory(function (t) {\n t['space'] = 250;\n t['exclam'] = 333;\n t['universal'] = 713;\n t['numbersign'] = 500;\n t['existential'] = 549;\n t['percent'] = 833;\n t['ampersand'] = 778;\n t['suchthat'] = 439;\n t['parenleft'] = 333;\n t['parenright'] = 333;\n t['asteriskmath'] = 500;\n t['plus'] = 549;\n t['comma'] = 250;\n t['minus'] = 549;\n t['period'] = 250;\n t['slash'] = 278;\n t['zero'] = 500;\n t['one'] = 500;\n t['two'] = 500;\n t['three'] = 500;\n t['four'] = 500;\n t['five'] = 500;\n t['six'] = 500;\n t['seven'] = 500;\n t['eight'] = 500;\n t['nine'] = 500;\n t['colon'] = 278;\n t['semicolon'] = 278;\n t['less'] = 549;\n t['equal'] = 549;\n t['greater'] = 549;\n t['question'] = 444;\n t['congruent'] = 549;\n t['Alpha'] = 722;\n t['Beta'] = 667;\n t['Chi'] = 722;\n t['Delta'] = 612;\n t['Epsilon'] = 611;\n t['Phi'] = 763;\n t['Gamma'] = 603;\n t['Eta'] = 722;\n t['Iota'] = 333;\n t['theta1'] = 631;\n t['Kappa'] = 722;\n t['Lambda'] = 686;\n t['Mu'] = 889;\n t['Nu'] = 722;\n t['Omicron'] = 722;\n t['Pi'] = 768;\n t['Theta'] = 741;\n t['Rho'] = 556;\n t['Sigma'] = 592;\n t['Tau'] = 611;\n t['Upsilon'] = 690;\n t['sigma1'] = 439;\n t['Omega'] = 768;\n t['Xi'] = 645;\n t['Psi'] = 795;\n t['Zeta'] = 611;\n t['bracketleft'] = 333;\n t['therefore'] = 863;\n t['bracketright'] = 333;\n t['perpendicular'] = 658;\n t['underscore'] = 500;\n t['radicalex'] = 500;\n t['alpha'] = 631;\n t['beta'] = 549;\n t['chi'] = 549;\n t['delta'] = 494;\n t['epsilon'] = 439;\n t['phi'] = 521;\n t['gamma'] = 411;\n t['eta'] = 603;\n t['iota'] = 329;\n t['phi1'] = 603;\n t['kappa'] = 549;\n t['lambda'] = 549;\n t['mu'] = 576;\n t['nu'] = 521;\n t['omicron'] = 549;\n t['pi'] = 549;\n t['theta'] = 521;\n t['rho'] = 549;\n t['sigma'] = 603;\n t['tau'] = 439;\n t['upsilon'] = 576;\n t['omega1'] = 713;\n t['omega'] = 686;\n t['xi'] = 493;\n t['psi'] = 686;\n t['zeta'] = 494;\n t['braceleft'] = 480;\n t['bar'] = 200;\n t['braceright'] = 480;\n t['similar'] = 549;\n t['Euro'] = 750;\n t['Upsilon1'] = 620;\n t['minute'] = 247;\n t['lessequal'] = 549;\n t['fraction'] = 167;\n t['infinity'] = 713;\n t['florin'] = 500;\n t['club'] = 753;\n t['diamond'] = 753;\n t['heart'] = 753;\n t['spade'] = 753;\n t['arrowboth'] = 1042;\n t['arrowleft'] = 987;\n t['arrowup'] = 603;\n t['arrowright'] = 987;\n t['arrowdown'] = 603;\n t['degree'] = 400;\n t['plusminus'] = 549;\n t['second'] = 411;\n t['greaterequal'] = 549;\n t['multiply'] = 549;\n t['proportional'] = 713;\n t['partialdiff'] = 494;\n t['bullet'] = 460;\n t['divide'] = 549;\n t['notequal'] = 549;\n t['equivalence'] = 549;\n t['approxequal'] = 549;\n t['ellipsis'] = 1000;\n t['arrowvertex'] = 603;\n t['arrowhorizex'] = 1000;\n t['carriagereturn'] = 658;\n t['aleph'] = 823;\n t['Ifraktur'] = 686;\n t['Rfraktur'] = 795;\n t['weierstrass'] = 987;\n t['circlemultiply'] = 768;\n t['circleplus'] = 768;\n t['emptyset'] = 823;\n t['intersection'] = 768;\n t['union'] = 768;\n t['propersuperset'] = 713;\n t['reflexsuperset'] = 713;\n t['notsubset'] = 713;\n t['propersubset'] = 713;\n t['reflexsubset'] = 713;\n t['element'] = 713;\n t['notelement'] = 713;\n t['angle'] = 768;\n t['gradient'] = 713;\n t['registerserif'] = 790;\n t['copyrightserif'] = 790;\n t['trademarkserif'] = 890;\n t['product'] = 823;\n t['radical'] = 549;\n t['dotmath'] = 250;\n t['logicalnot'] = 713;\n t['logicaland'] = 603;\n t['logicalor'] = 603;\n t['arrowdblboth'] = 1042;\n t['arrowdblleft'] = 987;\n t['arrowdblup'] = 603;\n t['arrowdblright'] = 987;\n t['arrowdbldown'] = 603;\n t['lozenge'] = 494;\n t['angleleft'] = 329;\n t['registersans'] = 790;\n t['copyrightsans'] = 790;\n t['trademarksans'] = 786;\n t['summation'] = 713;\n t['parenlefttp'] = 384;\n t['parenleftex'] = 384;\n t['parenleftbt'] = 384;\n t['bracketlefttp'] = 384;\n t['bracketleftex'] = 384;\n t['bracketleftbt'] = 384;\n t['bracelefttp'] = 494;\n t['braceleftmid'] = 494;\n t['braceleftbt'] = 494;\n t['braceex'] = 494;\n t['angleright'] = 329;\n t['integral'] = 274;\n t['integraltp'] = 686;\n t['integralex'] = 686;\n t['integralbt'] = 686;\n t['parenrighttp'] = 384;\n t['parenrightex'] = 384;\n t['parenrightbt'] = 384;\n t['bracketrighttp'] = 384;\n t['bracketrightex'] = 384;\n t['bracketrightbt'] = 384;\n t['bracerighttp'] = 494;\n t['bracerightmid'] = 494;\n t['bracerightbt'] = 494;\n t['apple'] = 790;\n });\n t['Times-Roman'] = getLookupTableFactory(function (t) {\n t['space'] = 250;\n t['exclam'] = 333;\n t['quotedbl'] = 408;\n t['numbersign'] = 500;\n t['dollar'] = 500;\n t['percent'] = 833;\n t['ampersand'] = 778;\n t['quoteright'] = 333;\n t['parenleft'] = 333;\n t['parenright'] = 333;\n t['asterisk'] = 500;\n t['plus'] = 564;\n t['comma'] = 250;\n t['hyphen'] = 333;\n t['period'] = 250;\n t['slash'] = 278;\n t['zero'] = 500;\n t['one'] = 500;\n t['two'] = 500;\n t['three'] = 500;\n t['four'] = 500;\n t['five'] = 500;\n t['six'] = 500;\n t['seven'] = 500;\n t['eight'] = 500;\n t['nine'] = 500;\n t['colon'] = 278;\n t['semicolon'] = 278;\n t['less'] = 564;\n t['equal'] = 564;\n t['greater'] = 564;\n t['question'] = 444;\n t['at'] = 921;\n t['A'] = 722;\n t['B'] = 667;\n t['C'] = 667;\n t['D'] = 722;\n t['E'] = 611;\n t['F'] = 556;\n t['G'] = 722;\n t['H'] = 722;\n t['I'] = 333;\n t['J'] = 389;\n t['K'] = 722;\n t['L'] = 611;\n t['M'] = 889;\n t['N'] = 722;\n t['O'] = 722;\n t['P'] = 556;\n t['Q'] = 722;\n t['R'] = 667;\n t['S'] = 556;\n t['T'] = 611;\n t['U'] = 722;\n t['V'] = 722;\n t['W'] = 944;\n t['X'] = 722;\n t['Y'] = 722;\n t['Z'] = 611;\n t['bracketleft'] = 333;\n t['backslash'] = 278;\n t['bracketright'] = 333;\n t['asciicircum'] = 469;\n t['underscore'] = 500;\n t['quoteleft'] = 333;\n t['a'] = 444;\n t['b'] = 500;\n t['c'] = 444;\n t['d'] = 500;\n t['e'] = 444;\n t['f'] = 333;\n t['g'] = 500;\n t['h'] = 500;\n t['i'] = 278;\n t['j'] = 278;\n t['k'] = 500;\n t['l'] = 278;\n t['m'] = 778;\n t['n'] = 500;\n t['o'] = 500;\n t['p'] = 500;\n t['q'] = 500;\n t['r'] = 333;\n t['s'] = 389;\n t['t'] = 278;\n t['u'] = 500;\n t['v'] = 500;\n t['w'] = 722;\n t['x'] = 500;\n t['y'] = 500;\n t['z'] = 444;\n t['braceleft'] = 480;\n t['bar'] = 200;\n t['braceright'] = 480;\n t['asciitilde'] = 541;\n t['exclamdown'] = 333;\n t['cent'] = 500;\n t['sterling'] = 500;\n t['fraction'] = 167;\n t['yen'] = 500;\n t['florin'] = 500;\n t['section'] = 500;\n t['currency'] = 500;\n t['quotesingle'] = 180;\n t['quotedblleft'] = 444;\n t['guillemotleft'] = 500;\n t['guilsinglleft'] = 333;\n t['guilsinglright'] = 333;\n t['fi'] = 556;\n t['fl'] = 556;\n t['endash'] = 500;\n t['dagger'] = 500;\n t['daggerdbl'] = 500;\n t['periodcentered'] = 250;\n t['paragraph'] = 453;\n t['bullet'] = 350;\n t['quotesinglbase'] = 333;\n t['quotedblbase'] = 444;\n t['quotedblright'] = 444;\n t['guillemotright'] = 500;\n t['ellipsis'] = 1000;\n t['perthousand'] = 1000;\n t['questiondown'] = 444;\n t['grave'] = 333;\n t['acute'] = 333;\n t['circumflex'] = 333;\n t['tilde'] = 333;\n t['macron'] = 333;\n t['breve'] = 333;\n t['dotaccent'] = 333;\n t['dieresis'] = 333;\n t['ring'] = 333;\n t['cedilla'] = 333;\n t['hungarumlaut'] = 333;\n t['ogonek'] = 333;\n t['caron'] = 333;\n t['emdash'] = 1000;\n t['AE'] = 889;\n t['ordfeminine'] = 276;\n t['Lslash'] = 611;\n t['Oslash'] = 722;\n t['OE'] = 889;\n t['ordmasculine'] = 310;\n t['ae'] = 667;\n t['dotlessi'] = 278;\n t['lslash'] = 278;\n t['oslash'] = 500;\n t['oe'] = 722;\n t['germandbls'] = 500;\n t['Idieresis'] = 333;\n t['eacute'] = 444;\n t['abreve'] = 444;\n t['uhungarumlaut'] = 500;\n t['ecaron'] = 444;\n t['Ydieresis'] = 722;\n t['divide'] = 564;\n t['Yacute'] = 722;\n t['Acircumflex'] = 722;\n t['aacute'] = 444;\n t['Ucircumflex'] = 722;\n t['yacute'] = 500;\n t['scommaaccent'] = 389;\n t['ecircumflex'] = 444;\n t['Uring'] = 722;\n t['Udieresis'] = 722;\n t['aogonek'] = 444;\n t['Uacute'] = 722;\n t['uogonek'] = 500;\n t['Edieresis'] = 611;\n t['Dcroat'] = 722;\n t['commaaccent'] = 250;\n t['copyright'] = 760;\n t['Emacron'] = 611;\n t['ccaron'] = 444;\n t['aring'] = 444;\n t['Ncommaaccent'] = 722;\n t['lacute'] = 278;\n t['agrave'] = 444;\n t['Tcommaaccent'] = 611;\n t['Cacute'] = 667;\n t['atilde'] = 444;\n t['Edotaccent'] = 611;\n t['scaron'] = 389;\n t['scedilla'] = 389;\n t['iacute'] = 278;\n t['lozenge'] = 471;\n t['Rcaron'] = 667;\n t['Gcommaaccent'] = 722;\n t['ucircumflex'] = 500;\n t['acircumflex'] = 444;\n t['Amacron'] = 722;\n t['rcaron'] = 333;\n t['ccedilla'] = 444;\n t['Zdotaccent'] = 611;\n t['Thorn'] = 556;\n t['Omacron'] = 722;\n t['Racute'] = 667;\n t['Sacute'] = 556;\n t['dcaron'] = 588;\n t['Umacron'] = 722;\n t['uring'] = 500;\n t['threesuperior'] = 300;\n t['Ograve'] = 722;\n t['Agrave'] = 722;\n t['Abreve'] = 722;\n t['multiply'] = 564;\n t['uacute'] = 500;\n t['Tcaron'] = 611;\n t['partialdiff'] = 476;\n t['ydieresis'] = 500;\n t['Nacute'] = 722;\n t['icircumflex'] = 278;\n t['Ecircumflex'] = 611;\n t['adieresis'] = 444;\n t['edieresis'] = 444;\n t['cacute'] = 444;\n t['nacute'] = 500;\n t['umacron'] = 500;\n t['Ncaron'] = 722;\n t['Iacute'] = 333;\n t['plusminus'] = 564;\n t['brokenbar'] = 200;\n t['registered'] = 760;\n t['Gbreve'] = 722;\n t['Idotaccent'] = 333;\n t['summation'] = 600;\n t['Egrave'] = 611;\n t['racute'] = 333;\n t['omacron'] = 500;\n t['Zacute'] = 611;\n t['Zcaron'] = 611;\n t['greaterequal'] = 549;\n t['Eth'] = 722;\n t['Ccedilla'] = 667;\n t['lcommaaccent'] = 278;\n t['tcaron'] = 326;\n t['eogonek'] = 444;\n t['Uogonek'] = 722;\n t['Aacute'] = 722;\n t['Adieresis'] = 722;\n t['egrave'] = 444;\n t['zacute'] = 444;\n t['iogonek'] = 278;\n t['Oacute'] = 722;\n t['oacute'] = 500;\n t['amacron'] = 444;\n t['sacute'] = 389;\n t['idieresis'] = 278;\n t['Ocircumflex'] = 722;\n t['Ugrave'] = 722;\n t['Delta'] = 612;\n t['thorn'] = 500;\n t['twosuperior'] = 300;\n t['Odieresis'] = 722;\n t['mu'] = 500;\n t['igrave'] = 278;\n t['ohungarumlaut'] = 500;\n t['Eogonek'] = 611;\n t['dcroat'] = 500;\n t['threequarters'] = 750;\n t['Scedilla'] = 556;\n t['lcaron'] = 344;\n t['Kcommaaccent'] = 722;\n t['Lacute'] = 611;\n t['trademark'] = 980;\n t['edotaccent'] = 444;\n t['Igrave'] = 333;\n t['Imacron'] = 333;\n t['Lcaron'] = 611;\n t['onehalf'] = 750;\n t['lessequal'] = 549;\n t['ocircumflex'] = 500;\n t['ntilde'] = 500;\n t['Uhungarumlaut'] = 722;\n t['Eacute'] = 611;\n t['emacron'] = 444;\n t['gbreve'] = 500;\n t['onequarter'] = 750;\n t['Scaron'] = 556;\n t['Scommaaccent'] = 556;\n t['Ohungarumlaut'] = 722;\n t['degree'] = 400;\n t['ograve'] = 500;\n t['Ccaron'] = 667;\n t['ugrave'] = 500;\n t['radical'] = 453;\n t['Dcaron'] = 722;\n t['rcommaaccent'] = 333;\n t['Ntilde'] = 722;\n t['otilde'] = 500;\n t['Rcommaaccent'] = 667;\n t['Lcommaaccent'] = 611;\n t['Atilde'] = 722;\n t['Aogonek'] = 722;\n t['Aring'] = 722;\n t['Otilde'] = 722;\n t['zdotaccent'] = 444;\n t['Ecaron'] = 611;\n t['Iogonek'] = 333;\n t['kcommaaccent'] = 500;\n t['minus'] = 564;\n t['Icircumflex'] = 333;\n t['ncaron'] = 500;\n t['tcommaaccent'] = 278;\n t['logicalnot'] = 564;\n t['odieresis'] = 500;\n t['udieresis'] = 500;\n t['notequal'] = 549;\n t['gcommaaccent'] = 500;\n t['eth'] = 500;\n t['zcaron'] = 444;\n t['ncommaaccent'] = 500;\n t['onesuperior'] = 300;\n t['imacron'] = 278;\n t['Euro'] = 500;\n });\n t['Times-Bold'] = getLookupTableFactory(function (t) {\n t['space'] = 250;\n t['exclam'] = 333;\n t['quotedbl'] = 555;\n t['numbersign'] = 500;\n t['dollar'] = 500;\n t['percent'] = 1000;\n t['ampersand'] = 833;\n t['quoteright'] = 333;\n t['parenleft'] = 333;\n t['parenright'] = 333;\n t['asterisk'] = 500;\n t['plus'] = 570;\n t['comma'] = 250;\n t['hyphen'] = 333;\n t['period'] = 250;\n t['slash'] = 278;\n t['zero'] = 500;\n t['one'] = 500;\n t['two'] = 500;\n t['three'] = 500;\n t['four'] = 500;\n t['five'] = 500;\n t['six'] = 500;\n t['seven'] = 500;\n t['eight'] = 500;\n t['nine'] = 500;\n t['colon'] = 333;\n t['semicolon'] = 333;\n t['less'] = 570;\n t['equal'] = 570;\n t['greater'] = 570;\n t['question'] = 500;\n t['at'] = 930;\n t['A'] = 722;\n t['B'] = 667;\n t['C'] = 722;\n t['D'] = 722;\n t['E'] = 667;\n t['F'] = 611;\n t['G'] = 778;\n t['H'] = 778;\n t['I'] = 389;\n t['J'] = 500;\n t['K'] = 778;\n t['L'] = 667;\n t['M'] = 944;\n t['N'] = 722;\n t['O'] = 778;\n t['P'] = 611;\n t['Q'] = 778;\n t['R'] = 722;\n t['S'] = 556;\n t['T'] = 667;\n t['U'] = 722;\n t['V'] = 722;\n t['W'] = 1000;\n t['X'] = 722;\n t['Y'] = 722;\n t['Z'] = 667;\n t['bracketleft'] = 333;\n t['backslash'] = 278;\n t['bracketright'] = 333;\n t['asciicircum'] = 581;\n t['underscore'] = 500;\n t['quoteleft'] = 333;\n t['a'] = 500;\n t['b'] = 556;\n t['c'] = 444;\n t['d'] = 556;\n t['e'] = 444;\n t['f'] = 333;\n t['g'] = 500;\n t['h'] = 556;\n t['i'] = 278;\n t['j'] = 333;\n t['k'] = 556;\n t['l'] = 278;\n t['m'] = 833;\n t['n'] = 556;\n t['o'] = 500;\n t['p'] = 556;\n t['q'] = 556;\n t['r'] = 444;\n t['s'] = 389;\n t['t'] = 333;\n t['u'] = 556;\n t['v'] = 500;\n t['w'] = 722;\n t['x'] = 500;\n t['y'] = 500;\n t['z'] = 444;\n t['braceleft'] = 394;\n t['bar'] = 220;\n t['braceright'] = 394;\n t['asciitilde'] = 520;\n t['exclamdown'] = 333;\n t['cent'] = 500;\n t['sterling'] = 500;\n t['fraction'] = 167;\n t['yen'] = 500;\n t['florin'] = 500;\n t['section'] = 500;\n t['currency'] = 500;\n t['quotesingle'] = 278;\n t['quotedblleft'] = 500;\n t['guillemotleft'] = 500;\n t['guilsinglleft'] = 333;\n t['guilsinglright'] = 333;\n t['fi'] = 556;\n t['fl'] = 556;\n t['endash'] = 500;\n t['dagger'] = 500;\n t['daggerdbl'] = 500;\n t['periodcentered'] = 250;\n t['paragraph'] = 540;\n t['bullet'] = 350;\n t['quotesinglbase'] = 333;\n t['quotedblbase'] = 500;\n t['quotedblright'] = 500;\n t['guillemotright'] = 500;\n t['ellipsis'] = 1000;\n t['perthousand'] = 1000;\n t['questiondown'] = 500;\n t['grave'] = 333;\n t['acute'] = 333;\n t['circumflex'] = 333;\n t['tilde'] = 333;\n t['macron'] = 333;\n t['breve'] = 333;\n t['dotaccent'] = 333;\n t['dieresis'] = 333;\n t['ring'] = 333;\n t['cedilla'] = 333;\n t['hungarumlaut'] = 333;\n t['ogonek'] = 333;\n t['caron'] = 333;\n t['emdash'] = 1000;\n t['AE'] = 1000;\n t['ordfeminine'] = 300;\n t['Lslash'] = 667;\n t['Oslash'] = 778;\n t['OE'] = 1000;\n t['ordmasculine'] = 330;\n t['ae'] = 722;\n t['dotlessi'] = 278;\n t['lslash'] = 278;\n t['oslash'] = 500;\n t['oe'] = 722;\n t['germandbls'] = 556;\n t['Idieresis'] = 389;\n t['eacute'] = 444;\n t['abreve'] = 500;\n t['uhungarumlaut'] = 556;\n t['ecaron'] = 444;\n t['Ydieresis'] = 722;\n t['divide'] = 570;\n t['Yacute'] = 722;\n t['Acircumflex'] = 722;\n t['aacute'] = 500;\n t['Ucircumflex'] = 722;\n t['yacute'] = 500;\n t['scommaaccent'] = 389;\n t['ecircumflex'] = 444;\n t['Uring'] = 722;\n t['Udieresis'] = 722;\n t['aogonek'] = 500;\n t['Uacute'] = 722;\n t['uogonek'] = 556;\n t['Edieresis'] = 667;\n t['Dcroat'] = 722;\n t['commaaccent'] = 250;\n t['copyright'] = 747;\n t['Emacron'] = 667;\n t['ccaron'] = 444;\n t['aring'] = 500;\n t['Ncommaaccent'] = 722;\n t['lacute'] = 278;\n t['agrave'] = 500;\n t['Tcommaaccent'] = 667;\n t['Cacute'] = 722;\n t['atilde'] = 500;\n t['Edotaccent'] = 667;\n t['scaron'] = 389;\n t['scedilla'] = 389;\n t['iacute'] = 278;\n t['lozenge'] = 494;\n t['Rcaron'] = 722;\n t['Gcommaaccent'] = 778;\n t['ucircumflex'] = 556;\n t['acircumflex'] = 500;\n t['Amacron'] = 722;\n t['rcaron'] = 444;\n t['ccedilla'] = 444;\n t['Zdotaccent'] = 667;\n t['Thorn'] = 611;\n t['Omacron'] = 778;\n t['Racute'] = 722;\n t['Sacute'] = 556;\n t['dcaron'] = 672;\n t['Umacron'] = 722;\n t['uring'] = 556;\n t['threesuperior'] = 300;\n t['Ograve'] = 778;\n t['Agrave'] = 722;\n t['Abreve'] = 722;\n t['multiply'] = 570;\n t['uacute'] = 556;\n t['Tcaron'] = 667;\n t['partialdiff'] = 494;\n t['ydieresis'] = 500;\n t['Nacute'] = 722;\n t['icircumflex'] = 278;\n t['Ecircumflex'] = 667;\n t['adieresis'] = 500;\n t['edieresis'] = 444;\n t['cacute'] = 444;\n t['nacute'] = 556;\n t['umacron'] = 556;\n t['Ncaron'] = 722;\n t['Iacute'] = 389;\n t['plusminus'] = 570;\n t['brokenbar'] = 220;\n t['registered'] = 747;\n t['Gbreve'] = 778;\n t['Idotaccent'] = 389;\n t['summation'] = 600;\n t['Egrave'] = 667;\n t['racute'] = 444;\n t['omacron'] = 500;\n t['Zacute'] = 667;\n t['Zcaron'] = 667;\n t['greaterequal'] = 549;\n t['Eth'] = 722;\n t['Ccedilla'] = 722;\n t['lcommaaccent'] = 278;\n t['tcaron'] = 416;\n t['eogonek'] = 444;\n t['Uogonek'] = 722;\n t['Aacute'] = 722;\n t['Adieresis'] = 722;\n t['egrave'] = 444;\n t['zacute'] = 444;\n t['iogonek'] = 278;\n t['Oacute'] = 778;\n t['oacute'] = 500;\n t['amacron'] = 500;\n t['sacute'] = 389;\n t['idieresis'] = 278;\n t['Ocircumflex'] = 778;\n t['Ugrave'] = 722;\n t['Delta'] = 612;\n t['thorn'] = 556;\n t['twosuperior'] = 300;\n t['Odieresis'] = 778;\n t['mu'] = 556;\n t['igrave'] = 278;\n t['ohungarumlaut'] = 500;\n t['Eogonek'] = 667;\n t['dcroat'] = 556;\n t['threequarters'] = 750;\n t['Scedilla'] = 556;\n t['lcaron'] = 394;\n t['Kcommaaccent'] = 778;\n t['Lacute'] = 667;\n t['trademark'] = 1000;\n t['edotaccent'] = 444;\n t['Igrave'] = 389;\n t['Imacron'] = 389;\n t['Lcaron'] = 667;\n t['onehalf'] = 750;\n t['lessequal'] = 549;\n t['ocircumflex'] = 500;\n t['ntilde'] = 556;\n t['Uhungarumlaut'] = 722;\n t['Eacute'] = 667;\n t['emacron'] = 444;\n t['gbreve'] = 500;\n t['onequarter'] = 750;\n t['Scaron'] = 556;\n t['Scommaaccent'] = 556;\n t['Ohungarumlaut'] = 778;\n t['degree'] = 400;\n t['ograve'] = 500;\n t['Ccaron'] = 722;\n t['ugrave'] = 556;\n t['radical'] = 549;\n t['Dcaron'] = 722;\n t['rcommaaccent'] = 444;\n t['Ntilde'] = 722;\n t['otilde'] = 500;\n t['Rcommaaccent'] = 722;\n t['Lcommaaccent'] = 667;\n t['Atilde'] = 722;\n t['Aogonek'] = 722;\n t['Aring'] = 722;\n t['Otilde'] = 778;\n t['zdotaccent'] = 444;\n t['Ecaron'] = 667;\n t['Iogonek'] = 389;\n t['kcommaaccent'] = 556;\n t['minus'] = 570;\n t['Icircumflex'] = 389;\n t['ncaron'] = 556;\n t['tcommaaccent'] = 333;\n t['logicalnot'] = 570;\n t['odieresis'] = 500;\n t['udieresis'] = 556;\n t['notequal'] = 549;\n t['gcommaaccent'] = 500;\n t['eth'] = 500;\n t['zcaron'] = 444;\n t['ncommaaccent'] = 556;\n t['onesuperior'] = 300;\n t['imacron'] = 278;\n t['Euro'] = 500;\n });\n t['Times-BoldItalic'] = getLookupTableFactory(function (t) {\n t['space'] = 250;\n t['exclam'] = 389;\n t['quotedbl'] = 555;\n t['numbersign'] = 500;\n t['dollar'] = 500;\n t['percent'] = 833;\n t['ampersand'] = 778;\n t['quoteright'] = 333;\n t['parenleft'] = 333;\n t['parenright'] = 333;\n t['asterisk'] = 500;\n t['plus'] = 570;\n t['comma'] = 250;\n t['hyphen'] = 333;\n t['period'] = 250;\n t['slash'] = 278;\n t['zero'] = 500;\n t['one'] = 500;\n t['two'] = 500;\n t['three'] = 500;\n t['four'] = 500;\n t['five'] = 500;\n t['six'] = 500;\n t['seven'] = 500;\n t['eight'] = 500;\n t['nine'] = 500;\n t['colon'] = 333;\n t['semicolon'] = 333;\n t['less'] = 570;\n t['equal'] = 570;\n t['greater'] = 570;\n t['question'] = 500;\n t['at'] = 832;\n t['A'] = 667;\n t['B'] = 667;\n t['C'] = 667;\n t['D'] = 722;\n t['E'] = 667;\n t['F'] = 667;\n t['G'] = 722;\n t['H'] = 778;\n t['I'] = 389;\n t['J'] = 500;\n t['K'] = 667;\n t['L'] = 611;\n t['M'] = 889;\n t['N'] = 722;\n t['O'] = 722;\n t['P'] = 611;\n t['Q'] = 722;\n t['R'] = 667;\n t['S'] = 556;\n t['T'] = 611;\n t['U'] = 722;\n t['V'] = 667;\n t['W'] = 889;\n t['X'] = 667;\n t['Y'] = 611;\n t['Z'] = 611;\n t['bracketleft'] = 333;\n t['backslash'] = 278;\n t['bracketright'] = 333;\n t['asciicircum'] = 570;\n t['underscore'] = 500;\n t['quoteleft'] = 333;\n t['a'] = 500;\n t['b'] = 500;\n t['c'] = 444;\n t['d'] = 500;\n t['e'] = 444;\n t['f'] = 333;\n t['g'] = 500;\n t['h'] = 556;\n t['i'] = 278;\n t['j'] = 278;\n t['k'] = 500;\n t['l'] = 278;\n t['m'] = 778;\n t['n'] = 556;\n t['o'] = 500;\n t['p'] = 500;\n t['q'] = 500;\n t['r'] = 389;\n t['s'] = 389;\n t['t'] = 278;\n t['u'] = 556;\n t['v'] = 444;\n t['w'] = 667;\n t['x'] = 500;\n t['y'] = 444;\n t['z'] = 389;\n t['braceleft'] = 348;\n t['bar'] = 220;\n t['braceright'] = 348;\n t['asciitilde'] = 570;\n t['exclamdown'] = 389;\n t['cent'] = 500;\n t['sterling'] = 500;\n t['fraction'] = 167;\n t['yen'] = 500;\n t['florin'] = 500;\n t['section'] = 500;\n t['currency'] = 500;\n t['quotesingle'] = 278;\n t['quotedblleft'] = 500;\n t['guillemotleft'] = 500;\n t['guilsinglleft'] = 333;\n t['guilsinglright'] = 333;\n t['fi'] = 556;\n t['fl'] = 556;\n t['endash'] = 500;\n t['dagger'] = 500;\n t['daggerdbl'] = 500;\n t['periodcentered'] = 250;\n t['paragraph'] = 500;\n t['bullet'] = 350;\n t['quotesinglbase'] = 333;\n t['quotedblbase'] = 500;\n t['quotedblright'] = 500;\n t['guillemotright'] = 500;\n t['ellipsis'] = 1000;\n t['perthousand'] = 1000;\n t['questiondown'] = 500;\n t['grave'] = 333;\n t['acute'] = 333;\n t['circumflex'] = 333;\n t['tilde'] = 333;\n t['macron'] = 333;\n t['breve'] = 333;\n t['dotaccent'] = 333;\n t['dieresis'] = 333;\n t['ring'] = 333;\n t['cedilla'] = 333;\n t['hungarumlaut'] = 333;\n t['ogonek'] = 333;\n t['caron'] = 333;\n t['emdash'] = 1000;\n t['AE'] = 944;\n t['ordfeminine'] = 266;\n t['Lslash'] = 611;\n t['Oslash'] = 722;\n t['OE'] = 944;\n t['ordmasculine'] = 300;\n t['ae'] = 722;\n t['dotlessi'] = 278;\n t['lslash'] = 278;\n t['oslash'] = 500;\n t['oe'] = 722;\n t['germandbls'] = 500;\n t['Idieresis'] = 389;\n t['eacute'] = 444;\n t['abreve'] = 500;\n t['uhungarumlaut'] = 556;\n t['ecaron'] = 444;\n t['Ydieresis'] = 611;\n t['divide'] = 570;\n t['Yacute'] = 611;\n t['Acircumflex'] = 667;\n t['aacute'] = 500;\n t['Ucircumflex'] = 722;\n t['yacute'] = 444;\n t['scommaaccent'] = 389;\n t['ecircumflex'] = 444;\n t['Uring'] = 722;\n t['Udieresis'] = 722;\n t['aogonek'] = 500;\n t['Uacute'] = 722;\n t['uogonek'] = 556;\n t['Edieresis'] = 667;\n t['Dcroat'] = 722;\n t['commaaccent'] = 250;\n t['copyright'] = 747;\n t['Emacron'] = 667;\n t['ccaron'] = 444;\n t['aring'] = 500;\n t['Ncommaaccent'] = 722;\n t['lacute'] = 278;\n t['agrave'] = 500;\n t['Tcommaaccent'] = 611;\n t['Cacute'] = 667;\n t['atilde'] = 500;\n t['Edotaccent'] = 667;\n t['scaron'] = 389;\n t['scedilla'] = 389;\n t['iacute'] = 278;\n t['lozenge'] = 494;\n t['Rcaron'] = 667;\n t['Gcommaaccent'] = 722;\n t['ucircumflex'] = 556;\n t['acircumflex'] = 500;\n t['Amacron'] = 667;\n t['rcaron'] = 389;\n t['ccedilla'] = 444;\n t['Zdotaccent'] = 611;\n t['Thorn'] = 611;\n t['Omacron'] = 722;\n t['Racute'] = 667;\n t['Sacute'] = 556;\n t['dcaron'] = 608;\n t['Umacron'] = 722;\n t['uring'] = 556;\n t['threesuperior'] = 300;\n t['Ograve'] = 722;\n t['Agrave'] = 667;\n t['Abreve'] = 667;\n t['multiply'] = 570;\n t['uacute'] = 556;\n t['Tcaron'] = 611;\n t['partialdiff'] = 494;\n t['ydieresis'] = 444;\n t['Nacute'] = 722;\n t['icircumflex'] = 278;\n t['Ecircumflex'] = 667;\n t['adieresis'] = 500;\n t['edieresis'] = 444;\n t['cacute'] = 444;\n t['nacute'] = 556;\n t['umacron'] = 556;\n t['Ncaron'] = 722;\n t['Iacute'] = 389;\n t['plusminus'] = 570;\n t['brokenbar'] = 220;\n t['registered'] = 747;\n t['Gbreve'] = 722;\n t['Idotaccent'] = 389;\n t['summation'] = 600;\n t['Egrave'] = 667;\n t['racute'] = 389;\n t['omacron'] = 500;\n t['Zacute'] = 611;\n t['Zcaron'] = 611;\n t['greaterequal'] = 549;\n t['Eth'] = 722;\n t['Ccedilla'] = 667;\n t['lcommaaccent'] = 278;\n t['tcaron'] = 366;\n t['eogonek'] = 444;\n t['Uogonek'] = 722;\n t['Aacute'] = 667;\n t['Adieresis'] = 667;\n t['egrave'] = 444;\n t['zacute'] = 389;\n t['iogonek'] = 278;\n t['Oacute'] = 722;\n t['oacute'] = 500;\n t['amacron'] = 500;\n t['sacute'] = 389;\n t['idieresis'] = 278;\n t['Ocircumflex'] = 722;\n t['Ugrave'] = 722;\n t['Delta'] = 612;\n t['thorn'] = 500;\n t['twosuperior'] = 300;\n t['Odieresis'] = 722;\n t['mu'] = 576;\n t['igrave'] = 278;\n t['ohungarumlaut'] = 500;\n t['Eogonek'] = 667;\n t['dcroat'] = 500;\n t['threequarters'] = 750;\n t['Scedilla'] = 556;\n t['lcaron'] = 382;\n t['Kcommaaccent'] = 667;\n t['Lacute'] = 611;\n t['trademark'] = 1000;\n t['edotaccent'] = 444;\n t['Igrave'] = 389;\n t['Imacron'] = 389;\n t['Lcaron'] = 611;\n t['onehalf'] = 750;\n t['lessequal'] = 549;\n t['ocircumflex'] = 500;\n t['ntilde'] = 556;\n t['Uhungarumlaut'] = 722;\n t['Eacute'] = 667;\n t['emacron'] = 444;\n t['gbreve'] = 500;\n t['onequarter'] = 750;\n t['Scaron'] = 556;\n t['Scommaaccent'] = 556;\n t['Ohungarumlaut'] = 722;\n t['degree'] = 400;\n t['ograve'] = 500;\n t['Ccaron'] = 667;\n t['ugrave'] = 556;\n t['radical'] = 549;\n t['Dcaron'] = 722;\n t['rcommaaccent'] = 389;\n t['Ntilde'] = 722;\n t['otilde'] = 500;\n t['Rcommaaccent'] = 667;\n t['Lcommaaccent'] = 611;\n t['Atilde'] = 667;\n t['Aogonek'] = 667;\n t['Aring'] = 667;\n t['Otilde'] = 722;\n t['zdotaccent'] = 389;\n t['Ecaron'] = 667;\n t['Iogonek'] = 389;\n t['kcommaaccent'] = 500;\n t['minus'] = 606;\n t['Icircumflex'] = 389;\n t['ncaron'] = 556;\n t['tcommaaccent'] = 278;\n t['logicalnot'] = 606;\n t['odieresis'] = 500;\n t['udieresis'] = 556;\n t['notequal'] = 549;\n t['gcommaaccent'] = 500;\n t['eth'] = 500;\n t['zcaron'] = 389;\n t['ncommaaccent'] = 556;\n t['onesuperior'] = 300;\n t['imacron'] = 278;\n t['Euro'] = 500;\n });\n t['Times-Italic'] = getLookupTableFactory(function (t) {\n t['space'] = 250;\n t['exclam'] = 333;\n t['quotedbl'] = 420;\n t['numbersign'] = 500;\n t['dollar'] = 500;\n t['percent'] = 833;\n t['ampersand'] = 778;\n t['quoteright'] = 333;\n t['parenleft'] = 333;\n t['parenright'] = 333;\n t['asterisk'] = 500;\n t['plus'] = 675;\n t['comma'] = 250;\n t['hyphen'] = 333;\n t['period'] = 250;\n t['slash'] = 278;\n t['zero'] = 500;\n t['one'] = 500;\n t['two'] = 500;\n t['three'] = 500;\n t['four'] = 500;\n t['five'] = 500;\n t['six'] = 500;\n t['seven'] = 500;\n t['eight'] = 500;\n t['nine'] = 500;\n t['colon'] = 333;\n t['semicolon'] = 333;\n t['less'] = 675;\n t['equal'] = 675;\n t['greater'] = 675;\n t['question'] = 500;\n t['at'] = 920;\n t['A'] = 611;\n t['B'] = 611;\n t['C'] = 667;\n t['D'] = 722;\n t['E'] = 611;\n t['F'] = 611;\n t['G'] = 722;\n t['H'] = 722;\n t['I'] = 333;\n t['J'] = 444;\n t['K'] = 667;\n t['L'] = 556;\n t['M'] = 833;\n t['N'] = 667;\n t['O'] = 722;\n t['P'] = 611;\n t['Q'] = 722;\n t['R'] = 611;\n t['S'] = 500;\n t['T'] = 556;\n t['U'] = 722;\n t['V'] = 611;\n t['W'] = 833;\n t['X'] = 611;\n t['Y'] = 556;\n t['Z'] = 556;\n t['bracketleft'] = 389;\n t['backslash'] = 278;\n t['bracketright'] = 389;\n t['asciicircum'] = 422;\n t['underscore'] = 500;\n t['quoteleft'] = 333;\n t['a'] = 500;\n t['b'] = 500;\n t['c'] = 444;\n t['d'] = 500;\n t['e'] = 444;\n t['f'] = 278;\n t['g'] = 500;\n t['h'] = 500;\n t['i'] = 278;\n t['j'] = 278;\n t['k'] = 444;\n t['l'] = 278;\n t['m'] = 722;\n t['n'] = 500;\n t['o'] = 500;\n t['p'] = 500;\n t['q'] = 500;\n t['r'] = 389;\n t['s'] = 389;\n t['t'] = 278;\n t['u'] = 500;\n t['v'] = 444;\n t['w'] = 667;\n t['x'] = 444;\n t['y'] = 444;\n t['z'] = 389;\n t['braceleft'] = 400;\n t['bar'] = 275;\n t['braceright'] = 400;\n t['asciitilde'] = 541;\n t['exclamdown'] = 389;\n t['cent'] = 500;\n t['sterling'] = 500;\n t['fraction'] = 167;\n t['yen'] = 500;\n t['florin'] = 500;\n t['section'] = 500;\n t['currency'] = 500;\n t['quotesingle'] = 214;\n t['quotedblleft'] = 556;\n t['guillemotleft'] = 500;\n t['guilsinglleft'] = 333;\n t['guilsinglright'] = 333;\n t['fi'] = 500;\n t['fl'] = 500;\n t['endash'] = 500;\n t['dagger'] = 500;\n t['daggerdbl'] = 500;\n t['periodcentered'] = 250;\n t['paragraph'] = 523;\n t['bullet'] = 350;\n t['quotesinglbase'] = 333;\n t['quotedblbase'] = 556;\n t['quotedblright'] = 556;\n t['guillemotright'] = 500;\n t['ellipsis'] = 889;\n t['perthousand'] = 1000;\n t['questiondown'] = 500;\n t['grave'] = 333;\n t['acute'] = 333;\n t['circumflex'] = 333;\n t['tilde'] = 333;\n t['macron'] = 333;\n t['breve'] = 333;\n t['dotaccent'] = 333;\n t['dieresis'] = 333;\n t['ring'] = 333;\n t['cedilla'] = 333;\n t['hungarumlaut'] = 333;\n t['ogonek'] = 333;\n t['caron'] = 333;\n t['emdash'] = 889;\n t['AE'] = 889;\n t['ordfeminine'] = 276;\n t['Lslash'] = 556;\n t['Oslash'] = 722;\n t['OE'] = 944;\n t['ordmasculine'] = 310;\n t['ae'] = 667;\n t['dotlessi'] = 278;\n t['lslash'] = 278;\n t['oslash'] = 500;\n t['oe'] = 667;\n t['germandbls'] = 500;\n t['Idieresis'] = 333;\n t['eacute'] = 444;\n t['abreve'] = 500;\n t['uhungarumlaut'] = 500;\n t['ecaron'] = 444;\n t['Ydieresis'] = 556;\n t['divide'] = 675;\n t['Yacute'] = 556;\n t['Acircumflex'] = 611;\n t['aacute'] = 500;\n t['Ucircumflex'] = 722;\n t['yacute'] = 444;\n t['scommaaccent'] = 389;\n t['ecircumflex'] = 444;\n t['Uring'] = 722;\n t['Udieresis'] = 722;\n t['aogonek'] = 500;\n t['Uacute'] = 722;\n t['uogonek'] = 500;\n t['Edieresis'] = 611;\n t['Dcroat'] = 722;\n t['commaaccent'] = 250;\n t['copyright'] = 760;\n t['Emacron'] = 611;\n t['ccaron'] = 444;\n t['aring'] = 500;\n t['Ncommaaccent'] = 667;\n t['lacute'] = 278;\n t['agrave'] = 500;\n t['Tcommaaccent'] = 556;\n t['Cacute'] = 667;\n t['atilde'] = 500;\n t['Edotaccent'] = 611;\n t['scaron'] = 389;\n t['scedilla'] = 389;\n t['iacute'] = 278;\n t['lozenge'] = 471;\n t['Rcaron'] = 611;\n t['Gcommaaccent'] = 722;\n t['ucircumflex'] = 500;\n t['acircumflex'] = 500;\n t['Amacron'] = 611;\n t['rcaron'] = 389;\n t['ccedilla'] = 444;\n t['Zdotaccent'] = 556;\n t['Thorn'] = 611;\n t['Omacron'] = 722;\n t['Racute'] = 611;\n t['Sacute'] = 500;\n t['dcaron'] = 544;\n t['Umacron'] = 722;\n t['uring'] = 500;\n t['threesuperior'] = 300;\n t['Ograve'] = 722;\n t['Agrave'] = 611;\n t['Abreve'] = 611;\n t['multiply'] = 675;\n t['uacute'] = 500;\n t['Tcaron'] = 556;\n t['partialdiff'] = 476;\n t['ydieresis'] = 444;\n t['Nacute'] = 667;\n t['icircumflex'] = 278;\n t['Ecircumflex'] = 611;\n t['adieresis'] = 500;\n t['edieresis'] = 444;\n t['cacute'] = 444;\n t['nacute'] = 500;\n t['umacron'] = 500;\n t['Ncaron'] = 667;\n t['Iacute'] = 333;\n t['plusminus'] = 675;\n t['brokenbar'] = 275;\n t['registered'] = 760;\n t['Gbreve'] = 722;\n t['Idotaccent'] = 333;\n t['summation'] = 600;\n t['Egrave'] = 611;\n t['racute'] = 389;\n t['omacron'] = 500;\n t['Zacute'] = 556;\n t['Zcaron'] = 556;\n t['greaterequal'] = 549;\n t['Eth'] = 722;\n t['Ccedilla'] = 667;\n t['lcommaaccent'] = 278;\n t['tcaron'] = 300;\n t['eogonek'] = 444;\n t['Uogonek'] = 722;\n t['Aacute'] = 611;\n t['Adieresis'] = 611;\n t['egrave'] = 444;\n t['zacute'] = 389;\n t['iogonek'] = 278;\n t['Oacute'] = 722;\n t['oacute'] = 500;\n t['amacron'] = 500;\n t['sacute'] = 389;\n t['idieresis'] = 278;\n t['Ocircumflex'] = 722;\n t['Ugrave'] = 722;\n t['Delta'] = 612;\n t['thorn'] = 500;\n t['twosuperior'] = 300;\n t['Odieresis'] = 722;\n t['mu'] = 500;\n t['igrave'] = 278;\n t['ohungarumlaut'] = 500;\n t['Eogonek'] = 611;\n t['dcroat'] = 500;\n t['threequarters'] = 750;\n t['Scedilla'] = 500;\n t['lcaron'] = 300;\n t['Kcommaaccent'] = 667;\n t['Lacute'] = 556;\n t['trademark'] = 980;\n t['edotaccent'] = 444;\n t['Igrave'] = 333;\n t['Imacron'] = 333;\n t['Lcaron'] = 611;\n t['onehalf'] = 750;\n t['lessequal'] = 549;\n t['ocircumflex'] = 500;\n t['ntilde'] = 500;\n t['Uhungarumlaut'] = 722;\n t['Eacute'] = 611;\n t['emacron'] = 444;\n t['gbreve'] = 500;\n t['onequarter'] = 750;\n t['Scaron'] = 500;\n t['Scommaaccent'] = 500;\n t['Ohungarumlaut'] = 722;\n t['degree'] = 400;\n t['ograve'] = 500;\n t['Ccaron'] = 667;\n t['ugrave'] = 500;\n t['radical'] = 453;\n t['Dcaron'] = 722;\n t['rcommaaccent'] = 389;\n t['Ntilde'] = 667;\n t['otilde'] = 500;\n t['Rcommaaccent'] = 611;\n t['Lcommaaccent'] = 556;\n t['Atilde'] = 611;\n t['Aogonek'] = 611;\n t['Aring'] = 611;\n t['Otilde'] = 722;\n t['zdotaccent'] = 389;\n t['Ecaron'] = 611;\n t['Iogonek'] = 333;\n t['kcommaaccent'] = 444;\n t['minus'] = 675;\n t['Icircumflex'] = 333;\n t['ncaron'] = 500;\n t['tcommaaccent'] = 278;\n t['logicalnot'] = 675;\n t['odieresis'] = 500;\n t['udieresis'] = 500;\n t['notequal'] = 549;\n t['gcommaaccent'] = 500;\n t['eth'] = 500;\n t['zcaron'] = 389;\n t['ncommaaccent'] = 500;\n t['onesuperior'] = 300;\n t['imacron'] = 278;\n t['Euro'] = 500;\n });\n t['ZapfDingbats'] = getLookupTableFactory(function (t) {\n t['space'] = 278;\n t['a1'] = 974;\n t['a2'] = 961;\n t['a202'] = 974;\n t['a3'] = 980;\n t['a4'] = 719;\n t['a5'] = 789;\n t['a119'] = 790;\n t['a118'] = 791;\n t['a117'] = 690;\n t['a11'] = 960;\n t['a12'] = 939;\n t['a13'] = 549;\n t['a14'] = 855;\n t['a15'] = 911;\n t['a16'] = 933;\n t['a105'] = 911;\n t['a17'] = 945;\n t['a18'] = 974;\n t['a19'] = 755;\n t['a20'] = 846;\n t['a21'] = 762;\n t['a22'] = 761;\n t['a23'] = 571;\n t['a24'] = 677;\n t['a25'] = 763;\n t['a26'] = 760;\n t['a27'] = 759;\n t['a28'] = 754;\n t['a6'] = 494;\n t['a7'] = 552;\n t['a8'] = 537;\n t['a9'] = 577;\n t['a10'] = 692;\n t['a29'] = 786;\n t['a30'] = 788;\n t['a31'] = 788;\n t['a32'] = 790;\n t['a33'] = 793;\n t['a34'] = 794;\n t['a35'] = 816;\n t['a36'] = 823;\n t['a37'] = 789;\n t['a38'] = 841;\n t['a39'] = 823;\n t['a40'] = 833;\n t['a41'] = 816;\n t['a42'] = 831;\n t['a43'] = 923;\n t['a44'] = 744;\n t['a45'] = 723;\n t['a46'] = 749;\n t['a47'] = 790;\n t['a48'] = 792;\n t['a49'] = 695;\n t['a50'] = 776;\n t['a51'] = 768;\n t['a52'] = 792;\n t['a53'] = 759;\n t['a54'] = 707;\n t['a55'] = 708;\n t['a56'] = 682;\n t['a57'] = 701;\n t['a58'] = 826;\n t['a59'] = 815;\n t['a60'] = 789;\n t['a61'] = 789;\n t['a62'] = 707;\n t['a63'] = 687;\n t['a64'] = 696;\n t['a65'] = 689;\n t['a66'] = 786;\n t['a67'] = 787;\n t['a68'] = 713;\n t['a69'] = 791;\n t['a70'] = 785;\n t['a71'] = 791;\n t['a72'] = 873;\n t['a73'] = 761;\n t['a74'] = 762;\n t['a203'] = 762;\n t['a75'] = 759;\n t['a204'] = 759;\n t['a76'] = 892;\n t['a77'] = 892;\n t['a78'] = 788;\n t['a79'] = 784;\n t['a81'] = 438;\n t['a82'] = 138;\n t['a83'] = 277;\n t['a84'] = 415;\n t['a97'] = 392;\n t['a98'] = 392;\n t['a99'] = 668;\n t['a100'] = 668;\n t['a89'] = 390;\n t['a90'] = 390;\n t['a93'] = 317;\n t['a94'] = 317;\n t['a91'] = 276;\n t['a92'] = 276;\n t['a205'] = 509;\n t['a85'] = 509;\n t['a206'] = 410;\n t['a86'] = 410;\n t['a87'] = 234;\n t['a88'] = 234;\n t['a95'] = 334;\n t['a96'] = 334;\n t['a101'] = 732;\n t['a102'] = 544;\n t['a103'] = 544;\n t['a104'] = 910;\n t['a106'] = 667;\n t['a107'] = 760;\n t['a108'] = 760;\n t['a112'] = 776;\n t['a111'] = 595;\n t['a110'] = 694;\n t['a109'] = 626;\n t['a120'] = 788;\n t['a121'] = 788;\n t['a122'] = 788;\n t['a123'] = 788;\n t['a124'] = 788;\n t['a125'] = 788;\n t['a126'] = 788;\n t['a127'] = 788;\n t['a128'] = 788;\n t['a129'] = 788;\n t['a130'] = 788;\n t['a131'] = 788;\n t['a132'] = 788;\n t['a133'] = 788;\n t['a134'] = 788;\n t['a135'] = 788;\n t['a136'] = 788;\n t['a137'] = 788;\n t['a138'] = 788;\n t['a139'] = 788;\n t['a140'] = 788;\n t['a141'] = 788;\n t['a142'] = 788;\n t['a143'] = 788;\n t['a144'] = 788;\n t['a145'] = 788;\n t['a146'] = 788;\n t['a147'] = 788;\n t['a148'] = 788;\n t['a149'] = 788;\n t['a150'] = 788;\n t['a151'] = 788;\n t['a152'] = 788;\n t['a153'] = 788;\n t['a154'] = 788;\n t['a155'] = 788;\n t['a156'] = 788;\n t['a157'] = 788;\n t['a158'] = 788;\n t['a159'] = 788;\n t['a160'] = 894;\n t['a161'] = 838;\n t['a163'] = 1016;\n t['a164'] = 458;\n t['a196'] = 748;\n t['a165'] = 924;\n t['a192'] = 748;\n t['a166'] = 918;\n t['a167'] = 927;\n t['a168'] = 928;\n t['a169'] = 928;\n t['a170'] = 834;\n t['a171'] = 873;\n t['a172'] = 828;\n t['a173'] = 924;\n t['a162'] = 924;\n t['a174'] = 917;\n t['a175'] = 930;\n t['a176'] = 931;\n t['a177'] = 463;\n t['a178'] = 883;\n t['a179'] = 836;\n t['a193'] = 836;\n t['a180'] = 867;\n t['a199'] = 867;\n t['a181'] = 696;\n t['a200'] = 696;\n t['a182'] = 874;\n t['a201'] = 874;\n t['a183'] = 760;\n t['a184'] = 946;\n t['a197'] = 771;\n t['a185'] = 865;\n t['a194'] = 771;\n t['a198'] = 888;\n t['a186'] = 967;\n t['a195'] = 888;\n t['a187'] = 831;\n t['a188'] = 873;\n t['a189'] = 927;\n t['a190'] = 970;\n t['a191'] = 918;\n });\n});\n\nexport {\n getMetrics,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/metrics.js","/* Copyright 2014 Opera Software ASA\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *\n * Based on https://code.google.com/p/smhasher/wiki/MurmurHash3.\n * Hashes roughly 100 KB per millisecond on i7 3.4 GHz.\n */\n\nvar MurmurHash3_64 = (function MurmurHash3_64Closure(seed) {\n // Workaround for missing math precision in JS.\n var MASK_HIGH = 0xffff0000;\n var MASK_LOW = 0xffff;\n\n function MurmurHash3_64(seed) {\n var SEED = 0xc3d2e1f0;\n this.h1 = seed ? seed & 0xffffffff : SEED;\n this.h2 = seed ? seed & 0xffffffff : SEED;\n }\n\n MurmurHash3_64.prototype = {\n update: function MurmurHash3_64_update(input) {\n var i;\n if (typeof input === 'string') {\n var data = new Uint8Array(input.length * 2);\n var length = 0;\n for (i = 0; i < input.length; i++) {\n var code = input.charCodeAt(i);\n if (code <= 0xff) {\n data[length++] = code;\n } else {\n data[length++] = code >>> 8;\n data[length++] = code & 0xff;\n }\n }\n } else if (typeof input === 'object' && ('byteLength' in input)) {\n data = input;\n length = data.byteLength;\n } else {\n throw new Error('Wrong data format in MurmurHash3_64_update. ' +\n 'Input must be a string or array.');\n }\n\n var blockCounts = length >> 2;\n var tailLength = length - blockCounts * 4;\n // we don't care about endianness here\n var dataUint32 = new Uint32Array(data.buffer, 0, blockCounts);\n var k1 = 0;\n var k2 = 0;\n var h1 = this.h1;\n var h2 = this.h2;\n var C1 = 0xcc9e2d51;\n var C2 = 0x1b873593;\n var C1_LOW = C1 & MASK_LOW;\n var C2_LOW = C2 & MASK_LOW;\n\n for (i = 0; i < blockCounts; i++) {\n if (i & 1) {\n k1 = dataUint32[i];\n k1 = (k1 * C1 & MASK_HIGH) | (k1 * C1_LOW & MASK_LOW);\n k1 = k1 << 15 | k1 >>> 17;\n k1 = (k1 * C2 & MASK_HIGH) | (k1 * C2_LOW & MASK_LOW);\n h1 ^= k1;\n h1 = h1 << 13 | h1 >>> 19;\n h1 = h1 * 5 + 0xe6546b64;\n } else {\n k2 = dataUint32[i];\n k2 = (k2 * C1 & MASK_HIGH) | (k2 * C1_LOW & MASK_LOW);\n k2 = k2 << 15 | k2 >>> 17;\n k2 = (k2 * C2 & MASK_HIGH) | (k2 * C2_LOW & MASK_LOW);\n h2 ^= k2;\n h2 = h2 << 13 | h2 >>> 19;\n h2 = h2 * 5 + 0xe6546b64;\n }\n }\n\n k1 = 0;\n\n switch (tailLength) {\n case 3:\n k1 ^= data[blockCounts * 4 + 2] << 16;\n /* falls through */\n case 2:\n k1 ^= data[blockCounts * 4 + 1] << 8;\n /* falls through */\n case 1:\n k1 ^= data[blockCounts * 4];\n /* falls through */\n k1 = (k1 * C1 & MASK_HIGH) | (k1 * C1_LOW & MASK_LOW);\n k1 = k1 << 15 | k1 >>> 17;\n k1 = (k1 * C2 & MASK_HIGH) | (k1 * C2_LOW & MASK_LOW);\n if (blockCounts & 1) {\n h1 ^= k1;\n } else {\n h2 ^= k1;\n }\n }\n\n this.h1 = h1;\n this.h2 = h2;\n return this;\n },\n\n hexdigest: function MurmurHash3_64_hexdigest() {\n var h1 = this.h1;\n var h2 = this.h2;\n\n h1 ^= h2 >>> 1;\n h1 = (h1 * 0xed558ccd & MASK_HIGH) | (h1 * 0x8ccd & MASK_LOW);\n h2 = (h2 * 0xff51afd7 & MASK_HIGH) |\n (((h2 << 16 | h1 >>> 16) * 0xafd7ed55 & MASK_HIGH) >>> 16);\n h1 ^= h2 >>> 1;\n h1 = (h1 * 0x1a85ec53 & MASK_HIGH) | (h1 * 0xec53 & MASK_LOW);\n h2 = (h2 * 0xc4ceb9fe & MASK_HIGH) |\n (((h2 << 16 | h1 >>> 16) * 0xb9fe1a85 & MASK_HIGH) >>> 16);\n h1 ^= h2 >>> 1;\n\n for (var i = 0, arr = [h1, h2], str = ''; i < arr.length; i++) {\n var hex = (arr[i] >>> 0).toString(16);\n while (hex.length < 8) {\n hex = '0' + hex;\n }\n str += hex;\n }\n\n return str;\n },\n };\n\n return MurmurHash3_64;\n})();\n\nexport {\n MurmurHash3_64,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/murmurhash3.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* eslint-disable no-multi-spaces */\n\nimport {\n assert, FormatError, info, MissingDataException, unreachable,\n UNSUPPORTED_FEATURES, Util, warn\n} from '../shared/util';\nimport { ColorSpace } from './colorspace';\nimport { isStream } from './primitives';\nimport { PDFFunction } from './function';\n\nvar ShadingType = {\n FUNCTION_BASED: 1,\n AXIAL: 2,\n RADIAL: 3,\n FREE_FORM_MESH: 4,\n LATTICE_FORM_MESH: 5,\n COONS_PATCH_MESH: 6,\n TENSOR_PATCH_MESH: 7,\n};\n\nvar Pattern = (function PatternClosure() {\n // Constructor should define this.getPattern\n function Pattern() {\n throw new Error('should not call Pattern constructor');\n }\n\n Pattern.prototype = {\n // Input: current Canvas context\n // Output: the appropriate fillStyle or strokeStyle\n getPattern: function Pattern_getPattern(ctx) {\n throw new Error(`Should not call Pattern.getStyle: ${ctx}`);\n },\n };\n\n Pattern.parseShading = function Pattern_parseShading(shading, matrix, xref,\n res, handler) {\n\n var dict = isStream(shading) ? shading.dict : shading;\n var type = dict.get('ShadingType');\n\n try {\n switch (type) {\n case ShadingType.AXIAL:\n case ShadingType.RADIAL:\n // Both radial and axial shadings are handled by RadialAxial shading.\n return new Shadings.RadialAxial(dict, matrix, xref, res);\n case ShadingType.FREE_FORM_MESH:\n case ShadingType.LATTICE_FORM_MESH:\n case ShadingType.COONS_PATCH_MESH:\n case ShadingType.TENSOR_PATCH_MESH:\n return new Shadings.Mesh(shading, matrix, xref, res);\n default:\n throw new FormatError('Unsupported ShadingType: ' + type);\n }\n } catch (ex) {\n if (ex instanceof MissingDataException) {\n throw ex;\n }\n handler.send('UnsupportedFeature',\n { featureId: UNSUPPORTED_FEATURES.shadingPattern, });\n warn(ex);\n return new Shadings.Dummy();\n }\n };\n return Pattern;\n})();\n\nvar Shadings = {};\n\n// A small number to offset the first/last color stops so we can insert ones to\n// support extend. Number.MIN_VALUE is too small and breaks the extend.\nShadings.SMALL_NUMBER = 1e-6;\n\n// Radial and axial shading have very similar implementations\n// If needed, the implementations can be broken into two classes\nShadings.RadialAxial = (function RadialAxialClosure() {\n function RadialAxial(dict, matrix, xref, res) {\n this.matrix = matrix;\n this.coordsArr = dict.getArray('Coords');\n this.shadingType = dict.get('ShadingType');\n this.type = 'Pattern';\n var cs = dict.get('ColorSpace', 'CS');\n cs = ColorSpace.parse(cs, xref, res);\n this.cs = cs;\n\n var t0 = 0.0, t1 = 1.0;\n if (dict.has('Domain')) {\n var domainArr = dict.getArray('Domain');\n t0 = domainArr[0];\n t1 = domainArr[1];\n }\n\n var extendStart = false, extendEnd = false;\n if (dict.has('Extend')) {\n var extendArr = dict.getArray('Extend');\n extendStart = extendArr[0];\n extendEnd = extendArr[1];\n }\n\n if (this.shadingType === ShadingType.RADIAL &&\n (!extendStart || !extendEnd)) {\n // Radial gradient only currently works if either circle is fully within\n // the other circle.\n var x1 = this.coordsArr[0];\n var y1 = this.coordsArr[1];\n var r1 = this.coordsArr[2];\n var x2 = this.coordsArr[3];\n var y2 = this.coordsArr[4];\n var r2 = this.coordsArr[5];\n var distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));\n if (r1 <= r2 + distance &&\n r2 <= r1 + distance) {\n warn('Unsupported radial gradient.');\n }\n }\n\n this.extendStart = extendStart;\n this.extendEnd = extendEnd;\n\n var fnObj = dict.get('Function');\n var fn = PDFFunction.parseArray(xref, fnObj);\n\n // 10 samples seems good enough for now, but probably won't work\n // if there are sharp color changes. Ideally, we would implement\n // the spec faithfully and add lossless optimizations.\n var diff = t1 - t0;\n var step = diff / 10;\n\n var colorStops = this.colorStops = [];\n\n // Protect against bad domains so we don't end up in an infinte loop below.\n if (t0 >= t1 || step <= 0) {\n // Acrobat doesn't seem to handle these cases so we'll ignore for\n // now.\n info('Bad shading domain.');\n return;\n }\n\n var color = new Float32Array(cs.numComps), ratio = new Float32Array(1);\n var rgbColor;\n for (var i = t0; i <= t1; i += step) {\n ratio[0] = i;\n fn(ratio, 0, color, 0);\n rgbColor = cs.getRgb(color, 0);\n var cssColor = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);\n colorStops.push([(i - t0) / diff, cssColor]);\n }\n\n var background = 'transparent';\n if (dict.has('Background')) {\n rgbColor = cs.getRgb(dict.get('Background'), 0);\n background = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);\n }\n\n if (!extendStart) {\n // Insert a color stop at the front and offset the first real color stop\n // so it doesn't conflict with the one we insert.\n colorStops.unshift([0, background]);\n colorStops[1][0] += Shadings.SMALL_NUMBER;\n }\n if (!extendEnd) {\n // Same idea as above in extendStart but for the end.\n colorStops[colorStops.length - 1][0] -= Shadings.SMALL_NUMBER;\n colorStops.push([1, background]);\n }\n\n this.colorStops = colorStops;\n }\n\n RadialAxial.prototype = {\n getIR: function RadialAxial_getIR() {\n var coordsArr = this.coordsArr;\n var shadingType = this.shadingType;\n var type, p0, p1, r0, r1;\n if (shadingType === ShadingType.AXIAL) {\n p0 = [coordsArr[0], coordsArr[1]];\n p1 = [coordsArr[2], coordsArr[3]];\n r0 = null;\n r1 = null;\n type = 'axial';\n } else if (shadingType === ShadingType.RADIAL) {\n p0 = [coordsArr[0], coordsArr[1]];\n p1 = [coordsArr[3], coordsArr[4]];\n r0 = coordsArr[2];\n r1 = coordsArr[5];\n type = 'radial';\n } else {\n unreachable(`getPattern type unknown: ${shadingType}`);\n }\n\n var matrix = this.matrix;\n if (matrix) {\n p0 = Util.applyTransform(p0, matrix);\n p1 = Util.applyTransform(p1, matrix);\n if (shadingType === ShadingType.RADIAL) {\n var scale = Util.singularValueDecompose2dScale(matrix);\n r0 *= scale[0];\n r1 *= scale[1];\n }\n }\n\n return ['RadialAxial', type, this.colorStops, p0, p1, r0, r1];\n },\n };\n\n return RadialAxial;\n})();\n\n// All mesh shading. For now, they will be presented as set of the triangles\n// to be drawn on the canvas and rgb color for each vertex.\nShadings.Mesh = (function MeshClosure() {\n function MeshStreamReader(stream, context) {\n this.stream = stream;\n this.context = context;\n this.buffer = 0;\n this.bufferLength = 0;\n\n var numComps = context.numComps;\n this.tmpCompsBuf = new Float32Array(numComps);\n var csNumComps = context.colorSpace.numComps;\n this.tmpCsCompsBuf = context.colorFn ? new Float32Array(csNumComps) :\n this.tmpCompsBuf;\n }\n MeshStreamReader.prototype = {\n get hasData() {\n if (this.stream.end) {\n return this.stream.pos < this.stream.end;\n }\n if (this.bufferLength > 0) {\n return true;\n }\n var nextByte = this.stream.getByte();\n if (nextByte < 0) {\n return false;\n }\n this.buffer = nextByte;\n this.bufferLength = 8;\n return true;\n },\n readBits: function MeshStreamReader_readBits(n) {\n var buffer = this.buffer;\n var bufferLength = this.bufferLength;\n if (n === 32) {\n if (bufferLength === 0) {\n return ((this.stream.getByte() << 24) |\n (this.stream.getByte() << 16) | (this.stream.getByte() << 8) |\n this.stream.getByte()) >>> 0;\n }\n buffer = (buffer << 24) | (this.stream.getByte() << 16) |\n (this.stream.getByte() << 8) | this.stream.getByte();\n var nextByte = this.stream.getByte();\n this.buffer = nextByte & ((1 << bufferLength) - 1);\n return ((buffer << (8 - bufferLength)) |\n ((nextByte & 0xFF) >> bufferLength)) >>> 0;\n }\n if (n === 8 && bufferLength === 0) {\n return this.stream.getByte();\n }\n while (bufferLength < n) {\n buffer = (buffer << 8) | this.stream.getByte();\n bufferLength += 8;\n }\n bufferLength -= n;\n this.bufferLength = bufferLength;\n this.buffer = buffer & ((1 << bufferLength) - 1);\n return buffer >> bufferLength;\n },\n align: function MeshStreamReader_align() {\n this.buffer = 0;\n this.bufferLength = 0;\n },\n readFlag: function MeshStreamReader_readFlag() {\n return this.readBits(this.context.bitsPerFlag);\n },\n readCoordinate: function MeshStreamReader_readCoordinate() {\n var bitsPerCoordinate = this.context.bitsPerCoordinate;\n var xi = this.readBits(bitsPerCoordinate);\n var yi = this.readBits(bitsPerCoordinate);\n var decode = this.context.decode;\n var scale = bitsPerCoordinate < 32 ? 1 / ((1 << bitsPerCoordinate) - 1) :\n 2.3283064365386963e-10; // 2 ^ -32\n return [\n xi * scale * (decode[1] - decode[0]) + decode[0],\n yi * scale * (decode[3] - decode[2]) + decode[2]\n ];\n },\n readComponents: function MeshStreamReader_readComponents() {\n var numComps = this.context.numComps;\n var bitsPerComponent = this.context.bitsPerComponent;\n var scale = bitsPerComponent < 32 ? 1 / ((1 << bitsPerComponent) - 1) :\n 2.3283064365386963e-10; // 2 ^ -32\n var decode = this.context.decode;\n var components = this.tmpCompsBuf;\n for (var i = 0, j = 4; i < numComps; i++, j += 2) {\n var ci = this.readBits(bitsPerComponent);\n components[i] = ci * scale * (decode[j + 1] - decode[j]) + decode[j];\n }\n var color = this.tmpCsCompsBuf;\n if (this.context.colorFn) {\n this.context.colorFn(components, 0, color, 0);\n }\n return this.context.colorSpace.getRgb(color, 0);\n },\n };\n\n function decodeType4Shading(mesh, reader) {\n var coords = mesh.coords;\n var colors = mesh.colors;\n var operators = [];\n var ps = []; // not maintaining cs since that will match ps\n var verticesLeft = 0; // assuming we have all data to start a new triangle\n while (reader.hasData) {\n var f = reader.readFlag();\n var coord = reader.readCoordinate();\n var color = reader.readComponents();\n if (verticesLeft === 0) { // ignoring flags if we started a triangle\n if (!(0 <= f && f <= 2)) {\n throw new FormatError('Unknown type4 flag');\n }\n switch (f) {\n case 0:\n verticesLeft = 3;\n break;\n case 1:\n ps.push(ps[ps.length - 2], ps[ps.length - 1]);\n verticesLeft = 1;\n break;\n case 2:\n ps.push(ps[ps.length - 3], ps[ps.length - 1]);\n verticesLeft = 1;\n break;\n }\n operators.push(f);\n }\n ps.push(coords.length);\n coords.push(coord);\n colors.push(color);\n verticesLeft--;\n\n reader.align();\n }\n mesh.figures.push({\n type: 'triangles',\n coords: new Int32Array(ps),\n colors: new Int32Array(ps),\n });\n }\n\n function decodeType5Shading(mesh, reader, verticesPerRow) {\n var coords = mesh.coords;\n var colors = mesh.colors;\n var ps = []; // not maintaining cs since that will match ps\n while (reader.hasData) {\n var coord = reader.readCoordinate();\n var color = reader.readComponents();\n ps.push(coords.length);\n coords.push(coord);\n colors.push(color);\n }\n mesh.figures.push({\n type: 'lattice',\n coords: new Int32Array(ps),\n colors: new Int32Array(ps),\n verticesPerRow,\n });\n }\n\n var MIN_SPLIT_PATCH_CHUNKS_AMOUNT = 3;\n var MAX_SPLIT_PATCH_CHUNKS_AMOUNT = 20;\n\n var TRIANGLE_DENSITY = 20; // count of triangles per entire mesh bounds\n\n var getB = (function getBClosure() {\n function buildB(count) {\n var lut = [];\n for (var i = 0; i <= count; i++) {\n var t = i / count, t_ = 1 - t;\n lut.push(new Float32Array([t_ * t_ * t_, 3 * t * t_ * t_,\n 3 * t * t * t_, t * t * t]));\n }\n return lut;\n }\n var cache = [];\n return function getB(count) {\n if (!cache[count]) {\n cache[count] = buildB(count);\n }\n return cache[count];\n };\n })();\n\n function buildFigureFromPatch(mesh, index) {\n var figure = mesh.figures[index];\n assert(figure.type === 'patch', 'Unexpected patch mesh figure');\n\n var coords = mesh.coords, colors = mesh.colors;\n var pi = figure.coords;\n var ci = figure.colors;\n\n var figureMinX = Math.min(coords[pi[0]][0], coords[pi[3]][0],\n coords[pi[12]][0], coords[pi[15]][0]);\n var figureMinY = Math.min(coords[pi[0]][1], coords[pi[3]][1],\n coords[pi[12]][1], coords[pi[15]][1]);\n var figureMaxX = Math.max(coords[pi[0]][0], coords[pi[3]][0],\n coords[pi[12]][0], coords[pi[15]][0]);\n var figureMaxY = Math.max(coords[pi[0]][1], coords[pi[3]][1],\n coords[pi[12]][1], coords[pi[15]][1]);\n var splitXBy = Math.ceil((figureMaxX - figureMinX) * TRIANGLE_DENSITY /\n (mesh.bounds[2] - mesh.bounds[0]));\n splitXBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT,\n Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitXBy));\n var splitYBy = Math.ceil((figureMaxY - figureMinY) * TRIANGLE_DENSITY /\n (mesh.bounds[3] - mesh.bounds[1]));\n splitYBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT,\n Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitYBy));\n\n var verticesPerRow = splitXBy + 1;\n var figureCoords = new Int32Array((splitYBy + 1) * verticesPerRow);\n var figureColors = new Int32Array((splitYBy + 1) * verticesPerRow);\n var k = 0;\n var cl = new Uint8Array(3), cr = new Uint8Array(3);\n var c0 = colors[ci[0]], c1 = colors[ci[1]],\n c2 = colors[ci[2]], c3 = colors[ci[3]];\n var bRow = getB(splitYBy), bCol = getB(splitXBy);\n for (var row = 0; row <= splitYBy; row++) {\n cl[0] = ((c0[0] * (splitYBy - row) + c2[0] * row) / splitYBy) | 0;\n cl[1] = ((c0[1] * (splitYBy - row) + c2[1] * row) / splitYBy) | 0;\n cl[2] = ((c0[2] * (splitYBy - row) + c2[2] * row) / splitYBy) | 0;\n\n cr[0] = ((c1[0] * (splitYBy - row) + c3[0] * row) / splitYBy) | 0;\n cr[1] = ((c1[1] * (splitYBy - row) + c3[1] * row) / splitYBy) | 0;\n cr[2] = ((c1[2] * (splitYBy - row) + c3[2] * row) / splitYBy) | 0;\n\n for (var col = 0; col <= splitXBy; col++, k++) {\n if ((row === 0 || row === splitYBy) &&\n (col === 0 || col === splitXBy)) {\n continue;\n }\n var x = 0, y = 0;\n var q = 0;\n for (var i = 0; i <= 3; i++) {\n for (var j = 0; j <= 3; j++, q++) {\n var m = bRow[row][i] * bCol[col][j];\n x += coords[pi[q]][0] * m;\n y += coords[pi[q]][1] * m;\n }\n }\n figureCoords[k] = coords.length;\n coords.push([x, y]);\n figureColors[k] = colors.length;\n var newColor = new Uint8Array(3);\n newColor[0] = ((cl[0] * (splitXBy - col) + cr[0] * col) / splitXBy) | 0;\n newColor[1] = ((cl[1] * (splitXBy - col) + cr[1] * col) / splitXBy) | 0;\n newColor[2] = ((cl[2] * (splitXBy - col) + cr[2] * col) / splitXBy) | 0;\n colors.push(newColor);\n }\n }\n figureCoords[0] = pi[0];\n figureColors[0] = ci[0];\n figureCoords[splitXBy] = pi[3];\n figureColors[splitXBy] = ci[1];\n figureCoords[verticesPerRow * splitYBy] = pi[12];\n figureColors[verticesPerRow * splitYBy] = ci[2];\n figureCoords[verticesPerRow * splitYBy + splitXBy] = pi[15];\n figureColors[verticesPerRow * splitYBy + splitXBy] = ci[3];\n\n mesh.figures[index] = {\n type: 'lattice',\n coords: figureCoords,\n colors: figureColors,\n verticesPerRow,\n };\n }\n\n function decodeType6Shading(mesh, reader) {\n // A special case of Type 7. The p11, p12, p21, p22 automatically filled\n var coords = mesh.coords;\n var colors = mesh.colors;\n var ps = new Int32Array(16); // p00, p10, ..., p30, p01, ..., p33\n var cs = new Int32Array(4); // c00, c30, c03, c33\n while (reader.hasData) {\n var f = reader.readFlag();\n if (!(0 <= f && f <= 3)) {\n throw new FormatError('Unknown type6 flag');\n }\n var i, ii;\n var pi = coords.length;\n for (i = 0, ii = (f !== 0 ? 8 : 12); i < ii; i++) {\n coords.push(reader.readCoordinate());\n }\n var ci = colors.length;\n for (i = 0, ii = (f !== 0 ? 2 : 4); i < ii; i++) {\n colors.push(reader.readComponents());\n }\n var tmp1, tmp2, tmp3, tmp4;\n switch (f) {\n case 0:\n ps[12] = pi + 3; ps[13] = pi + 4; ps[14] = pi + 5; ps[15] = pi + 6;\n ps[ 8] = pi + 2; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 7;\n ps[ 4] = pi + 1; /* calculated below */ ps[ 7] = pi + 8;\n ps[ 0] = pi; ps[ 1] = pi + 11; ps[ 2] = pi + 10; ps[ 3] = pi + 9;\n cs[2] = ci + 1; cs[3] = ci + 2;\n cs[0] = ci; cs[1] = ci + 3;\n break;\n case 1:\n tmp1 = ps[12]; tmp2 = ps[13]; tmp3 = ps[14]; tmp4 = ps[15];\n ps[12] = tmp4; ps[13] = pi + 0; ps[14] = pi + 1; ps[15] = pi + 2;\n ps[ 8] = tmp3; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 3;\n ps[ 4] = tmp2; /* calculated below */ ps[ 7] = pi + 4;\n ps[ 0] = tmp1; ps[ 1] = pi + 7; ps[ 2] = pi + 6; ps[ 3] = pi + 5;\n tmp1 = cs[2]; tmp2 = cs[3];\n cs[2] = tmp2; cs[3] = ci;\n cs[0] = tmp1; cs[1] = ci + 1;\n break;\n case 2:\n tmp1 = ps[15];\n tmp2 = ps[11];\n ps[12] = ps[3]; ps[13] = pi + 0; ps[14] = pi + 1; ps[15] = pi + 2;\n ps[ 8] = ps[7]; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 3;\n ps[ 4] = tmp2; /* calculated below */ ps[ 7] = pi + 4;\n ps[ 0] = tmp1; ps[ 1] = pi + 7; ps[ 2] = pi + 6; ps[ 3] = pi + 5;\n tmp1 = cs[3];\n cs[2] = cs[1]; cs[3] = ci;\n cs[0] = tmp1; cs[1] = ci + 1;\n break;\n case 3:\n ps[12] = ps[0]; ps[13] = pi + 0; ps[14] = pi + 1; ps[15] = pi + 2;\n ps[ 8] = ps[1]; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 3;\n ps[ 4] = ps[2]; /* calculated below */ ps[ 7] = pi + 4;\n ps[ 0] = ps[3]; ps[ 1] = pi + 7; ps[ 2] = pi + 6; ps[ 3] = pi + 5;\n cs[2] = cs[0]; cs[3] = ci;\n cs[0] = cs[1]; cs[1] = ci + 1;\n break;\n }\n // set p11, p12, p21, p22\n ps[5] = coords.length;\n coords.push([\n (-4 * coords[ps[0]][0] - coords[ps[15]][0] +\n 6 * (coords[ps[4]][0] + coords[ps[1]][0]) -\n 2 * (coords[ps[12]][0] + coords[ps[3]][0]) +\n 3 * (coords[ps[13]][0] + coords[ps[7]][0])) / 9,\n (-4 * coords[ps[0]][1] - coords[ps[15]][1] +\n 6 * (coords[ps[4]][1] + coords[ps[1]][1]) -\n 2 * (coords[ps[12]][1] + coords[ps[3]][1]) +\n 3 * (coords[ps[13]][1] + coords[ps[7]][1])) / 9\n ]);\n ps[6] = coords.length;\n coords.push([\n (-4 * coords[ps[3]][0] - coords[ps[12]][0] +\n 6 * (coords[ps[2]][0] + coords[ps[7]][0]) -\n 2 * (coords[ps[0]][0] + coords[ps[15]][0]) +\n 3 * (coords[ps[4]][0] + coords[ps[14]][0])) / 9,\n (-4 * coords[ps[3]][1] - coords[ps[12]][1] +\n 6 * (coords[ps[2]][1] + coords[ps[7]][1]) -\n 2 * (coords[ps[0]][1] + coords[ps[15]][1]) +\n 3 * (coords[ps[4]][1] + coords[ps[14]][1])) / 9\n ]);\n ps[9] = coords.length;\n coords.push([\n (-4 * coords[ps[12]][0] - coords[ps[3]][0] +\n 6 * (coords[ps[8]][0] + coords[ps[13]][0]) -\n 2 * (coords[ps[0]][0] + coords[ps[15]][0]) +\n 3 * (coords[ps[11]][0] + coords[ps[1]][0])) / 9,\n (-4 * coords[ps[12]][1] - coords[ps[3]][1] +\n 6 * (coords[ps[8]][1] + coords[ps[13]][1]) -\n 2 * (coords[ps[0]][1] + coords[ps[15]][1]) +\n 3 * (coords[ps[11]][1] + coords[ps[1]][1])) / 9\n ]);\n ps[10] = coords.length;\n coords.push([\n (-4 * coords[ps[15]][0] - coords[ps[0]][0] +\n 6 * (coords[ps[11]][0] + coords[ps[14]][0]) -\n 2 * (coords[ps[12]][0] + coords[ps[3]][0]) +\n 3 * (coords[ps[2]][0] + coords[ps[8]][0])) / 9,\n (-4 * coords[ps[15]][1] - coords[ps[0]][1] +\n 6 * (coords[ps[11]][1] + coords[ps[14]][1]) -\n 2 * (coords[ps[12]][1] + coords[ps[3]][1]) +\n 3 * (coords[ps[2]][1] + coords[ps[8]][1])) / 9\n ]);\n mesh.figures.push({\n type: 'patch',\n coords: new Int32Array(ps), // making copies of ps and cs\n colors: new Int32Array(cs),\n });\n }\n }\n\n function decodeType7Shading(mesh, reader) {\n var coords = mesh.coords;\n var colors = mesh.colors;\n var ps = new Int32Array(16); // p00, p10, ..., p30, p01, ..., p33\n var cs = new Int32Array(4); // c00, c30, c03, c33\n while (reader.hasData) {\n var f = reader.readFlag();\n if (!(0 <= f && f <= 3)) {\n throw new FormatError('Unknown type7 flag');\n }\n var i, ii;\n var pi = coords.length;\n for (i = 0, ii = (f !== 0 ? 12 : 16); i < ii; i++) {\n coords.push(reader.readCoordinate());\n }\n var ci = colors.length;\n for (i = 0, ii = (f !== 0 ? 2 : 4); i < ii; i++) {\n colors.push(reader.readComponents());\n }\n var tmp1, tmp2, tmp3, tmp4;\n switch (f) {\n case 0:\n ps[12] = pi + 3; ps[13] = pi + 4; ps[14] = pi + 5; ps[15] = pi + 6;\n ps[ 8] = pi + 2; ps[ 9] = pi + 13; ps[10] = pi + 14; ps[11] = pi + 7;\n ps[ 4] = pi + 1; ps[ 5] = pi + 12; ps[ 6] = pi + 15; ps[ 7] = pi + 8;\n ps[ 0] = pi; ps[ 1] = pi + 11; ps[ 2] = pi + 10; ps[ 3] = pi + 9;\n cs[2] = ci + 1; cs[3] = ci + 2;\n cs[0] = ci; cs[1] = ci + 3;\n break;\n case 1:\n tmp1 = ps[12]; tmp2 = ps[13]; tmp3 = ps[14]; tmp4 = ps[15];\n ps[12] = tmp4; ps[13] = pi + 0; ps[14] = pi + 1; ps[15] = pi + 2;\n ps[ 8] = tmp3; ps[ 9] = pi + 9; ps[10] = pi + 10; ps[11] = pi + 3;\n ps[ 4] = tmp2; ps[ 5] = pi + 8; ps[ 6] = pi + 11; ps[ 7] = pi + 4;\n ps[ 0] = tmp1; ps[ 1] = pi + 7; ps[ 2] = pi + 6; ps[ 3] = pi + 5;\n tmp1 = cs[2]; tmp2 = cs[3];\n cs[2] = tmp2; cs[3] = ci;\n cs[0] = tmp1; cs[1] = ci + 1;\n break;\n case 2:\n tmp1 = ps[15];\n tmp2 = ps[11];\n ps[12] = ps[3]; ps[13] = pi + 0; ps[14] = pi + 1; ps[15] = pi + 2;\n ps[ 8] = ps[7]; ps[ 9] = pi + 9; ps[10] = pi + 10; ps[11] = pi + 3;\n ps[ 4] = tmp2; ps[ 5] = pi + 8; ps[ 6] = pi + 11; ps[ 7] = pi + 4;\n ps[ 0] = tmp1; ps[ 1] = pi + 7; ps[ 2] = pi + 6; ps[ 3] = pi + 5;\n tmp1 = cs[3];\n cs[2] = cs[1]; cs[3] = ci;\n cs[0] = tmp1; cs[1] = ci + 1;\n break;\n case 3:\n ps[12] = ps[0]; ps[13] = pi + 0; ps[14] = pi + 1; ps[15] = pi + 2;\n ps[ 8] = ps[1]; ps[ 9] = pi + 9; ps[10] = pi + 10; ps[11] = pi + 3;\n ps[ 4] = ps[2]; ps[ 5] = pi + 8; ps[ 6] = pi + 11; ps[ 7] = pi + 4;\n ps[ 0] = ps[3]; ps[ 1] = pi + 7; ps[ 2] = pi + 6; ps[ 3] = pi + 5;\n cs[2] = cs[0]; cs[3] = ci;\n cs[0] = cs[1]; cs[1] = ci + 1;\n break;\n }\n mesh.figures.push({\n type: 'patch',\n coords: new Int32Array(ps), // making copies of ps and cs\n colors: new Int32Array(cs),\n });\n }\n }\n\n function updateBounds(mesh) {\n var minX = mesh.coords[0][0], minY = mesh.coords[0][1],\n maxX = minX, maxY = minY;\n for (var i = 1, ii = mesh.coords.length; i < ii; i++) {\n var x = mesh.coords[i][0], y = mesh.coords[i][1];\n minX = minX > x ? x : minX;\n minY = minY > y ? y : minY;\n maxX = maxX < x ? x : maxX;\n maxY = maxY < y ? y : maxY;\n }\n mesh.bounds = [minX, minY, maxX, maxY];\n }\n\n function packData(mesh) {\n var i, ii, j, jj;\n\n var coords = mesh.coords;\n var coordsPacked = new Float32Array(coords.length * 2);\n for (i = 0, j = 0, ii = coords.length; i < ii; i++) {\n var xy = coords[i];\n coordsPacked[j++] = xy[0];\n coordsPacked[j++] = xy[1];\n }\n mesh.coords = coordsPacked;\n\n var colors = mesh.colors;\n var colorsPacked = new Uint8Array(colors.length * 3);\n for (i = 0, j = 0, ii = colors.length; i < ii; i++) {\n var c = colors[i];\n colorsPacked[j++] = c[0];\n colorsPacked[j++] = c[1];\n colorsPacked[j++] = c[2];\n }\n mesh.colors = colorsPacked;\n\n var figures = mesh.figures;\n for (i = 0, ii = figures.length; i < ii; i++) {\n var figure = figures[i], ps = figure.coords, cs = figure.colors;\n for (j = 0, jj = ps.length; j < jj; j++) {\n ps[j] *= 2;\n cs[j] *= 3;\n }\n }\n }\n\n function Mesh(stream, matrix, xref, res) {\n if (!isStream(stream)) {\n throw new FormatError('Mesh data is not a stream');\n }\n var dict = stream.dict;\n this.matrix = matrix;\n this.shadingType = dict.get('ShadingType');\n this.type = 'Pattern';\n this.bbox = dict.getArray('BBox');\n var cs = dict.get('ColorSpace', 'CS');\n cs = ColorSpace.parse(cs, xref, res);\n this.cs = cs;\n this.background = dict.has('Background') ?\n cs.getRgb(dict.get('Background'), 0) : null;\n\n var fnObj = dict.get('Function');\n var fn = fnObj ? PDFFunction.parseArray(xref, fnObj) : null;\n\n this.coords = [];\n this.colors = [];\n this.figures = [];\n\n var decodeContext = {\n bitsPerCoordinate: dict.get('BitsPerCoordinate'),\n bitsPerComponent: dict.get('BitsPerComponent'),\n bitsPerFlag: dict.get('BitsPerFlag'),\n decode: dict.getArray('Decode'),\n colorFn: fn,\n colorSpace: cs,\n numComps: fn ? 1 : cs.numComps,\n };\n var reader = new MeshStreamReader(stream, decodeContext);\n\n var patchMesh = false;\n switch (this.shadingType) {\n case ShadingType.FREE_FORM_MESH:\n decodeType4Shading(this, reader);\n break;\n case ShadingType.LATTICE_FORM_MESH:\n var verticesPerRow = dict.get('VerticesPerRow') | 0;\n if (verticesPerRow < 2) {\n throw new FormatError('Invalid VerticesPerRow');\n }\n decodeType5Shading(this, reader, verticesPerRow);\n break;\n case ShadingType.COONS_PATCH_MESH:\n decodeType6Shading(this, reader);\n patchMesh = true;\n break;\n case ShadingType.TENSOR_PATCH_MESH:\n decodeType7Shading(this, reader);\n patchMesh = true;\n break;\n default:\n unreachable('Unsupported mesh type.');\n break;\n }\n\n if (patchMesh) {\n // dirty bounds calculation for determining, how dense shall be triangles\n updateBounds(this);\n for (var i = 0, ii = this.figures.length; i < ii; i++) {\n buildFigureFromPatch(this, i);\n }\n }\n // calculate bounds\n updateBounds(this);\n\n packData(this);\n }\n\n Mesh.prototype = {\n getIR: function Mesh_getIR() {\n return ['Mesh', this.shadingType, this.coords, this.colors, this.figures,\n this.bounds, this.matrix, this.bbox, this.background];\n },\n };\n\n return Mesh;\n})();\n\nShadings.Dummy = (function DummyClosure() {\n function Dummy() {\n this.type = 'Pattern';\n }\n\n Dummy.prototype = {\n getIR: function Dummy_getIR() {\n return ['Dummy'];\n },\n };\n return Dummy;\n})();\n\nfunction getTilingPatternIR(operatorList, dict, args) {\n let matrix = dict.getArray('Matrix');\n let bbox = Util.normalizeRect(dict.getArray('BBox'));\n let xstep = dict.get('XStep');\n let ystep = dict.get('YStep');\n let paintType = dict.get('PaintType');\n let tilingType = dict.get('TilingType');\n\n // Ensure that the pattern has a non-zero width and height, to prevent errors\n // in `pattern_helper.js` (fixes issue8330.pdf).\n if ((bbox[2] - bbox[0]) === 0 || (bbox[3] - bbox[1]) === 0) {\n throw new FormatError(`Invalid getTilingPatternIR /BBox array: [${bbox}].`);\n }\n\n return [\n 'TilingPattern', args, operatorList, matrix, bbox, xstep, ystep,\n paintType, tilingType\n ];\n}\n\nexport {\n Pattern,\n getTilingPatternIR,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/pattern.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createPromiseCapability, createValidAbsoluteUrl, MissingDataException,\n NotImplementedException, shadow, Util, warn\n} from '../shared/util';\nimport { ChunkedStreamManager } from './chunked_stream';\nimport { PDFDocument } from './document';\nimport { Stream } from './stream';\n\nvar BasePdfManager = (function BasePdfManagerClosure() {\n function BasePdfManager() {\n throw new Error('Cannot initialize BaseManagerManager');\n }\n\n BasePdfManager.prototype = {\n get docId() {\n return this._docId;\n },\n\n get password() {\n return this._password;\n },\n\n get docBaseUrl() {\n var docBaseUrl = null;\n if (this._docBaseUrl) {\n var absoluteUrl = createValidAbsoluteUrl(this._docBaseUrl);\n if (absoluteUrl) {\n docBaseUrl = absoluteUrl.href;\n } else {\n warn('Invalid absolute docBaseUrl: \"' + this._docBaseUrl + '\".');\n }\n }\n return shadow(this, 'docBaseUrl', docBaseUrl);\n },\n\n onLoadedStream: function BasePdfManager_onLoadedStream() {\n throw new NotImplementedException();\n },\n\n ensureDoc: function BasePdfManager_ensureDoc(prop, args) {\n return this.ensure(this.pdfDocument, prop, args);\n },\n\n ensureXRef: function BasePdfManager_ensureXRef(prop, args) {\n return this.ensure(this.pdfDocument.xref, prop, args);\n },\n\n ensureCatalog: function BasePdfManager_ensureCatalog(prop, args) {\n return this.ensure(this.pdfDocument.catalog, prop, args);\n },\n\n getPage: function BasePdfManager_getPage(pageIndex) {\n return this.pdfDocument.getPage(pageIndex);\n },\n\n cleanup: function BasePdfManager_cleanup() {\n return this.pdfDocument.cleanup();\n },\n\n ensure: function BasePdfManager_ensure(obj, prop, args) {\n return new NotImplementedException();\n },\n\n requestRange: function BasePdfManager_requestRange(begin, end) {\n return new NotImplementedException();\n },\n\n requestLoadedStream: function BasePdfManager_requestLoadedStream() {\n return new NotImplementedException();\n },\n\n sendProgressiveData: function BasePdfManager_sendProgressiveData(chunk) {\n return new NotImplementedException();\n },\n\n updatePassword: function BasePdfManager_updatePassword(password) {\n this._password = password;\n },\n\n terminate: function BasePdfManager_terminate() {\n return new NotImplementedException();\n },\n };\n\n return BasePdfManager;\n})();\n\nvar LocalPdfManager = (function LocalPdfManagerClosure() {\n function LocalPdfManager(docId, data, password, evaluatorOptions,\n docBaseUrl) {\n this._docId = docId;\n this._password = password;\n this._docBaseUrl = docBaseUrl;\n this.evaluatorOptions = evaluatorOptions;\n var stream = new Stream(data);\n this.pdfDocument = new PDFDocument(this, stream);\n this._loadedStreamCapability = createPromiseCapability();\n this._loadedStreamCapability.resolve(stream);\n }\n\n Util.inherit(LocalPdfManager, BasePdfManager, {\n ensure: function LocalPdfManager_ensure(obj, prop, args) {\n return new Promise(function (resolve, reject) {\n try {\n var value = obj[prop];\n var result;\n if (typeof value === 'function') {\n result = value.apply(obj, args);\n } else {\n result = value;\n }\n resolve(result);\n } catch (e) {\n reject(e);\n }\n });\n },\n\n requestRange: function LocalPdfManager_requestRange(begin, end) {\n return Promise.resolve();\n },\n\n requestLoadedStream: function LocalPdfManager_requestLoadedStream() {\n return;\n },\n\n onLoadedStream: function LocalPdfManager_onLoadedStream() {\n return this._loadedStreamCapability.promise;\n },\n\n terminate: function LocalPdfManager_terminate() {\n return;\n },\n });\n\n return LocalPdfManager;\n})();\n\nvar NetworkPdfManager = (function NetworkPdfManagerClosure() {\n function NetworkPdfManager(docId, pdfNetworkStream, args, evaluatorOptions,\n docBaseUrl) {\n this._docId = docId;\n this._password = args.password;\n this._docBaseUrl = docBaseUrl;\n this.msgHandler = args.msgHandler;\n this.evaluatorOptions = evaluatorOptions;\n\n var params = {\n msgHandler: args.msgHandler,\n url: args.url,\n length: args.length,\n disableAutoFetch: args.disableAutoFetch,\n rangeChunkSize: args.rangeChunkSize,\n };\n this.streamManager = new ChunkedStreamManager(pdfNetworkStream, params);\n this.pdfDocument = new PDFDocument(this, this.streamManager.getStream());\n }\n\n Util.inherit(NetworkPdfManager, BasePdfManager, {\n ensure: function NetworkPdfManager_ensure(obj, prop, args) {\n var pdfManager = this;\n\n return new Promise(function (resolve, reject) {\n function ensureHelper() {\n try {\n var result;\n var value = obj[prop];\n if (typeof value === 'function') {\n result = value.apply(obj, args);\n } else {\n result = value;\n }\n resolve(result);\n } catch (e) {\n if (!(e instanceof MissingDataException)) {\n reject(e);\n return;\n }\n pdfManager.streamManager.requestRange(e.begin, e.end).\n then(ensureHelper, reject);\n }\n }\n\n ensureHelper();\n });\n },\n\n requestRange: function NetworkPdfManager_requestRange(begin, end) {\n return this.streamManager.requestRange(begin, end);\n },\n\n requestLoadedStream: function NetworkPdfManager_requestLoadedStream() {\n this.streamManager.requestAllChunks();\n },\n\n sendProgressiveData:\n function NetworkPdfManager_sendProgressiveData(chunk) {\n this.streamManager.onReceiveData({ chunk, });\n },\n\n onLoadedStream: function NetworkPdfManager_onLoadedStream() {\n return this.streamManager.onLoadedStream();\n },\n\n terminate: function NetworkPdfManager_terminate() {\n this.streamManager.abort();\n },\n });\n\n return NetworkPdfManager;\n})();\n\nexport {\n LocalPdfManager,\n NetworkPdfManager,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/pdf_manager.js","/* Copyright 2014 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FormatError, isSpace } from '../shared/util';\nimport { EOF } from './primitives';\n\nvar PostScriptParser = (function PostScriptParserClosure() {\n function PostScriptParser(lexer) {\n this.lexer = lexer;\n this.operators = [];\n this.token = null;\n this.prev = null;\n }\n PostScriptParser.prototype = {\n nextToken: function PostScriptParser_nextToken() {\n this.prev = this.token;\n this.token = this.lexer.getToken();\n },\n accept: function PostScriptParser_accept(type) {\n if (this.token.type === type) {\n this.nextToken();\n return true;\n }\n return false;\n },\n expect: function PostScriptParser_expect(type) {\n if (this.accept(type)) {\n return true;\n }\n throw new FormatError(\n `Unexpected symbol: found ${this.token.type} expected ${type}.`);\n },\n parse: function PostScriptParser_parse() {\n this.nextToken();\n this.expect(PostScriptTokenTypes.LBRACE);\n this.parseBlock();\n this.expect(PostScriptTokenTypes.RBRACE);\n return this.operators;\n },\n parseBlock: function PostScriptParser_parseBlock() {\n while (true) {\n if (this.accept(PostScriptTokenTypes.NUMBER)) {\n this.operators.push(this.prev.value);\n } else if (this.accept(PostScriptTokenTypes.OPERATOR)) {\n this.operators.push(this.prev.value);\n } else if (this.accept(PostScriptTokenTypes.LBRACE)) {\n this.parseCondition();\n } else {\n return;\n }\n }\n },\n parseCondition: function PostScriptParser_parseCondition() {\n // Add two place holders that will be updated later\n var conditionLocation = this.operators.length;\n this.operators.push(null, null);\n\n this.parseBlock();\n this.expect(PostScriptTokenTypes.RBRACE);\n if (this.accept(PostScriptTokenTypes.IF)) {\n // The true block is right after the 'if' so it just falls through on\n // true else it jumps and skips the true block.\n this.operators[conditionLocation] = this.operators.length;\n this.operators[conditionLocation + 1] = 'jz';\n } else if (this.accept(PostScriptTokenTypes.LBRACE)) {\n var jumpLocation = this.operators.length;\n this.operators.push(null, null);\n var endOfTrue = this.operators.length;\n this.parseBlock();\n this.expect(PostScriptTokenTypes.RBRACE);\n this.expect(PostScriptTokenTypes.IFELSE);\n // The jump is added at the end of the true block to skip the false\n // block.\n this.operators[jumpLocation] = this.operators.length;\n this.operators[jumpLocation + 1] = 'j';\n\n this.operators[conditionLocation] = endOfTrue;\n this.operators[conditionLocation + 1] = 'jz';\n } else {\n throw new FormatError('PS Function: error parsing conditional.');\n }\n },\n };\n return PostScriptParser;\n})();\n\nvar PostScriptTokenTypes = {\n LBRACE: 0,\n RBRACE: 1,\n NUMBER: 2,\n OPERATOR: 3,\n IF: 4,\n IFELSE: 5,\n};\n\nvar PostScriptToken = (function PostScriptTokenClosure() {\n function PostScriptToken(type, value) {\n this.type = type;\n this.value = value;\n }\n\n var opCache = Object.create(null);\n\n PostScriptToken.getOperator = function PostScriptToken_getOperator(op) {\n var opValue = opCache[op];\n if (opValue) {\n return opValue;\n }\n return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op);\n };\n\n PostScriptToken.LBRACE = new PostScriptToken(PostScriptTokenTypes.LBRACE,\n '{');\n PostScriptToken.RBRACE = new PostScriptToken(PostScriptTokenTypes.RBRACE,\n '}');\n PostScriptToken.IF = new PostScriptToken(PostScriptTokenTypes.IF, 'IF');\n PostScriptToken.IFELSE = new PostScriptToken(PostScriptTokenTypes.IFELSE,\n 'IFELSE');\n return PostScriptToken;\n})();\n\nvar PostScriptLexer = (function PostScriptLexerClosure() {\n function PostScriptLexer(stream) {\n this.stream = stream;\n this.nextChar();\n\n this.strBuf = [];\n }\n PostScriptLexer.prototype = {\n nextChar: function PostScriptLexer_nextChar() {\n return (this.currentChar = this.stream.getByte());\n },\n getToken: function PostScriptLexer_getToken() {\n var comment = false;\n var ch = this.currentChar;\n\n // skip comments\n while (true) {\n if (ch < 0) {\n return EOF;\n }\n\n if (comment) {\n if (ch === 0x0A || ch === 0x0D) {\n comment = false;\n }\n } else if (ch === 0x25) { // '%'\n comment = true;\n } else if (!isSpace(ch)) {\n break;\n }\n ch = this.nextChar();\n }\n switch (ch | 0) {\n case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4'\n case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9'\n case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.'\n return new PostScriptToken(PostScriptTokenTypes.NUMBER,\n this.getNumber());\n case 0x7B: // '{'\n this.nextChar();\n return PostScriptToken.LBRACE;\n case 0x7D: // '}'\n this.nextChar();\n return PostScriptToken.RBRACE;\n }\n // operator\n var strBuf = this.strBuf;\n strBuf.length = 0;\n strBuf[0] = String.fromCharCode(ch);\n\n while ((ch = this.nextChar()) >= 0 && // and 'A'-'Z', 'a'-'z'\n ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) {\n strBuf.push(String.fromCharCode(ch));\n }\n var str = strBuf.join('');\n switch (str.toLowerCase()) {\n case 'if':\n return PostScriptToken.IF;\n case 'ifelse':\n return PostScriptToken.IFELSE;\n default:\n return PostScriptToken.getOperator(str);\n }\n },\n getNumber: function PostScriptLexer_getNumber() {\n var ch = this.currentChar;\n var strBuf = this.strBuf;\n strBuf.length = 0;\n strBuf[0] = String.fromCharCode(ch);\n\n while ((ch = this.nextChar()) >= 0) {\n if ((ch >= 0x30 && ch <= 0x39) || // '0'-'9'\n ch === 0x2D || ch === 0x2E) { // '-', '.'\n strBuf.push(String.fromCharCode(ch));\n } else {\n break;\n }\n }\n var value = parseFloat(strBuf.join(''));\n if (isNaN(value)) {\n throw new FormatError(`Invalid floating point number: ${value}`);\n }\n return value;\n },\n };\n return PostScriptLexer;\n})();\n\nexport {\n PostScriptLexer,\n PostScriptParser,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/ps_parser.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { isSpace, warn } from '../shared/util';\nimport { getEncoding } from './encodings';\nimport { Stream } from './stream';\n\n// Hinting is currently disabled due to unknown problems on windows\n// in tracemonkey and various other pdfs with type1 fonts.\nvar HINTING_ENABLED = false;\n\n/*\n * CharStrings are encoded following the the CharString Encoding sequence\n * describe in Chapter 6 of the \"Adobe Type1 Font Format\" specification.\n * The value in a byte indicates a command, a number, or subsequent bytes\n * that are to be interpreted in a special way.\n *\n * CharString Number Encoding:\n * A CharString byte containing the values from 32 through 255 inclusive\n * indicate an integer. These values are decoded in four ranges.\n *\n * 1. A CharString byte containing a value, v, between 32 and 246 inclusive,\n * indicate the integer v - 139. Thus, the integer values from -107 through\n * 107 inclusive may be encoded in single byte.\n *\n * 2. A CharString byte containing a value, v, between 247 and 250 inclusive,\n * indicates an integer involving the next byte, w, according to the formula:\n * [(v - 247) x 256] + w + 108\n *\n * 3. A CharString byte containing a value, v, between 251 and 254 inclusive,\n * indicates an integer involving the next byte, w, according to the formula:\n * -[(v - 251) * 256] - w - 108\n *\n * 4. A CharString containing the value 255 indicates that the next 4 bytes\n * are a two complement signed integer. The first of these bytes contains the\n * highest order bits, the second byte contains the next higher order bits\n * and the fourth byte contain the lowest order bits.\n *\n *\n * CharString Command Encoding:\n * CharStrings commands are encoded in 1 or 2 bytes.\n *\n * Single byte commands are encoded in 1 byte that contains a value between\n * 0 and 31 inclusive.\n * If a command byte contains the value 12, then the value in the next byte\n * indicates a command. This \"escape\" mechanism allows many extra commands\n * to be encoded and this encoding technique helps to minimize the length of\n * the charStrings.\n */\nvar Type1CharString = (function Type1CharStringClosure() {\n var COMMAND_MAP = {\n 'hstem': [1],\n 'vstem': [3],\n 'vmoveto': [4],\n 'rlineto': [5],\n 'hlineto': [6],\n 'vlineto': [7],\n 'rrcurveto': [8],\n 'callsubr': [10],\n 'flex': [12, 35],\n 'drop': [12, 18],\n 'endchar': [14],\n 'rmoveto': [21],\n 'hmoveto': [22],\n 'vhcurveto': [30],\n 'hvcurveto': [31],\n };\n\n function Type1CharString() {\n this.width = 0;\n this.lsb = 0;\n this.flexing = false;\n this.output = [];\n this.stack = [];\n }\n\n Type1CharString.prototype = {\n convert: function Type1CharString_convert(encoded, subrs,\n seacAnalysisEnabled) {\n var count = encoded.length;\n var error = false;\n var wx, sbx, subrNumber;\n for (var i = 0; i < count; i++) {\n var value = encoded[i];\n if (value < 32) {\n if (value === 12) {\n value = (value << 8) + encoded[++i];\n }\n switch (value) {\n case 1: // hstem\n if (!HINTING_ENABLED) {\n this.stack = [];\n break;\n }\n error = this.executeCommand(2, COMMAND_MAP.hstem);\n break;\n case 3: // vstem\n if (!HINTING_ENABLED) {\n this.stack = [];\n break;\n }\n error = this.executeCommand(2, COMMAND_MAP.vstem);\n break;\n case 4: // vmoveto\n if (this.flexing) {\n if (this.stack.length < 1) {\n error = true;\n break;\n }\n // Add the dx for flex and but also swap the values so they are\n // the right order.\n var dy = this.stack.pop();\n this.stack.push(0, dy);\n break;\n }\n error = this.executeCommand(1, COMMAND_MAP.vmoveto);\n break;\n case 5: // rlineto\n error = this.executeCommand(2, COMMAND_MAP.rlineto);\n break;\n case 6: // hlineto\n error = this.executeCommand(1, COMMAND_MAP.hlineto);\n break;\n case 7: // vlineto\n error = this.executeCommand(1, COMMAND_MAP.vlineto);\n break;\n case 8: // rrcurveto\n error = this.executeCommand(6, COMMAND_MAP.rrcurveto);\n break;\n case 9: // closepath\n // closepath is a Type1 command that does not take argument and is\n // useless in Type2 and it can simply be ignored.\n this.stack = [];\n break;\n case 10: // callsubr\n if (this.stack.length < 1) {\n error = true;\n break;\n }\n subrNumber = this.stack.pop();\n error = this.convert(subrs[subrNumber], subrs,\n seacAnalysisEnabled);\n break;\n case 11: // return\n return error;\n case 13: // hsbw\n if (this.stack.length < 2) {\n error = true;\n break;\n }\n // To convert to type2 we have to move the width value to the\n // first part of the charstring and then use hmoveto with lsb.\n wx = this.stack.pop();\n sbx = this.stack.pop();\n this.lsb = sbx;\n this.width = wx;\n this.stack.push(wx, sbx);\n error = this.executeCommand(2, COMMAND_MAP.hmoveto);\n break;\n case 14: // endchar\n this.output.push(COMMAND_MAP.endchar[0]);\n break;\n case 21: // rmoveto\n if (this.flexing) {\n break;\n }\n error = this.executeCommand(2, COMMAND_MAP.rmoveto);\n break;\n case 22: // hmoveto\n if (this.flexing) {\n // Add the dy for flex.\n this.stack.push(0);\n break;\n }\n error = this.executeCommand(1, COMMAND_MAP.hmoveto);\n break;\n case 30: // vhcurveto\n error = this.executeCommand(4, COMMAND_MAP.vhcurveto);\n break;\n case 31: // hvcurveto\n error = this.executeCommand(4, COMMAND_MAP.hvcurveto);\n break;\n case (12 << 8) + 0: // dotsection\n // dotsection is a Type1 command to specify some hinting feature\n // for dots that do not take a parameter and it can safely be\n // ignored for Type2.\n this.stack = [];\n break;\n case (12 << 8) + 1: // vstem3\n if (!HINTING_ENABLED) {\n this.stack = [];\n break;\n }\n // [vh]stem3 are Type1 only and Type2 supports [vh]stem with\n // multiple parameters, so instead of returning [vh]stem3 take a\n // shortcut and return [vhstem] instead.\n error = this.executeCommand(2, COMMAND_MAP.vstem);\n break;\n case (12 << 8) + 2: // hstem3\n if (!HINTING_ENABLED) {\n this.stack = [];\n break;\n }\n // See vstem3.\n error = this.executeCommand(2, COMMAND_MAP.hstem);\n break;\n case (12 << 8) + 6: // seac\n // seac is like type 2's special endchar but it doesn't use the\n // first argument asb, so remove it.\n if (seacAnalysisEnabled) {\n this.seac = this.stack.splice(-4, 4);\n error = this.executeCommand(0, COMMAND_MAP.endchar);\n } else {\n error = this.executeCommand(4, COMMAND_MAP.endchar);\n }\n break;\n case (12 << 8) + 7: // sbw\n if (this.stack.length < 4) {\n error = true;\n break;\n }\n // To convert to type2 we have to move the width value to the\n // first part of the charstring and then use rmoveto with\n // (dx, dy). The height argument will not be used for vmtx and\n // vhea tables reconstruction -- ignoring it.\n this.stack.pop(); // wy\n wx = this.stack.pop();\n var sby = this.stack.pop();\n sbx = this.stack.pop();\n this.lsb = sbx;\n this.width = wx;\n this.stack.push(wx, sbx, sby);\n error = this.executeCommand(3, COMMAND_MAP.rmoveto);\n break;\n case (12 << 8) + 12: // div\n if (this.stack.length < 2) {\n error = true;\n break;\n }\n var num2 = this.stack.pop();\n var num1 = this.stack.pop();\n this.stack.push(num1 / num2);\n break;\n case (12 << 8) + 16: // callothersubr\n if (this.stack.length < 2) {\n error = true;\n break;\n }\n subrNumber = this.stack.pop();\n var numArgs = this.stack.pop();\n if (subrNumber === 0 && numArgs === 3) {\n var flexArgs = this.stack.splice(this.stack.length - 17, 17);\n this.stack.push(\n flexArgs[2] + flexArgs[0], // bcp1x + rpx\n flexArgs[3] + flexArgs[1], // bcp1y + rpy\n flexArgs[4], // bcp2x\n flexArgs[5], // bcp2y\n flexArgs[6], // p2x\n flexArgs[7], // p2y\n flexArgs[8], // bcp3x\n flexArgs[9], // bcp3y\n flexArgs[10], // bcp4x\n flexArgs[11], // bcp4y\n flexArgs[12], // p3x\n flexArgs[13], // p3y\n flexArgs[14] // flexDepth\n // 15 = finalx unused by flex\n // 16 = finaly unused by flex\n );\n error = this.executeCommand(13, COMMAND_MAP.flex, true);\n this.flexing = false;\n this.stack.push(flexArgs[15], flexArgs[16]);\n } else if (subrNumber === 1 && numArgs === 0) {\n this.flexing = true;\n }\n break;\n case (12 << 8) + 17: // pop\n // Ignore this since it is only used with othersubr.\n break;\n case (12 << 8) + 33: // setcurrentpoint\n // Ignore for now.\n this.stack = [];\n break;\n default:\n warn('Unknown type 1 charstring command of \"' + value + '\"');\n break;\n }\n if (error) {\n break;\n }\n continue;\n } else if (value <= 246) {\n value = value - 139;\n } else if (value <= 250) {\n value = ((value - 247) * 256) + encoded[++i] + 108;\n } else if (value <= 254) {\n value = -((value - 251) * 256) - encoded[++i] - 108;\n } else {\n value = (encoded[++i] & 0xff) << 24 | (encoded[++i] & 0xff) << 16 |\n (encoded[++i] & 0xff) << 8 | (encoded[++i] & 0xff) << 0;\n }\n this.stack.push(value);\n }\n return error;\n },\n\n executeCommand(howManyArgs, command, keepStack) {\n var stackLength = this.stack.length;\n if (howManyArgs > stackLength) {\n return true;\n }\n var start = stackLength - howManyArgs;\n for (var i = start; i < stackLength; i++) {\n var value = this.stack[i];\n if (value === (value | 0)) { // int\n this.output.push(28, (value >> 8) & 0xff, value & 0xff);\n } else { // fixed point\n value = (65536 * value) | 0;\n this.output.push(255,\n (value >> 24) & 0xFF,\n (value >> 16) & 0xFF,\n (value >> 8) & 0xFF,\n value & 0xFF);\n }\n }\n this.output.push.apply(this.output, command);\n if (keepStack) {\n this.stack.splice(start, howManyArgs);\n } else {\n this.stack.length = 0;\n }\n return false;\n },\n };\n\n return Type1CharString;\n})();\n\n/*\n * Type1Parser encapsulate the needed code for parsing a Type1 font\n * program. Some of its logic depends on the Type2 charstrings\n * structure.\n * Note: this doesn't really parse the font since that would require evaluation\n * of PostScript, but it is possible in most cases to extract what we need\n * without a full parse.\n */\nvar Type1Parser = (function Type1ParserClosure() {\n /*\n * Decrypt a Sequence of Ciphertext Bytes to Produce the Original Sequence\n * of Plaintext Bytes. The function took a key as a parameter which can be\n * for decrypting the eexec block of for decoding charStrings.\n */\n var EEXEC_ENCRYPT_KEY = 55665;\n var CHAR_STRS_ENCRYPT_KEY = 4330;\n\n function isHexDigit(code) {\n return code >= 48 && code <= 57 || // '0'-'9'\n code >= 65 && code <= 70 || // 'A'-'F'\n code >= 97 && code <= 102; // 'a'-'f'\n }\n\n function decrypt(data, key, discardNumber) {\n if (discardNumber >= data.length) {\n return new Uint8Array(0);\n }\n var r = key | 0, c1 = 52845, c2 = 22719, i, j;\n for (i = 0; i < discardNumber; i++) {\n r = ((data[i] + r) * c1 + c2) & ((1 << 16) - 1);\n }\n var count = data.length - discardNumber;\n var decrypted = new Uint8Array(count);\n for (i = discardNumber, j = 0; j < count; i++, j++) {\n var value = data[i];\n decrypted[j] = value ^ (r >> 8);\n r = ((value + r) * c1 + c2) & ((1 << 16) - 1);\n }\n return decrypted;\n }\n\n function decryptAscii(data, key, discardNumber) {\n var r = key | 0, c1 = 52845, c2 = 22719;\n var count = data.length, maybeLength = count >>> 1;\n var decrypted = new Uint8Array(maybeLength);\n var i, j;\n for (i = 0, j = 0; i < count; i++) {\n var digit1 = data[i];\n if (!isHexDigit(digit1)) {\n continue;\n }\n i++;\n var digit2;\n while (i < count && !isHexDigit(digit2 = data[i])) {\n i++;\n }\n if (i < count) {\n var value = parseInt(String.fromCharCode(digit1, digit2), 16);\n decrypted[j++] = value ^ (r >> 8);\n r = ((value + r) * c1 + c2) & ((1 << 16) - 1);\n }\n }\n return Array.prototype.slice.call(decrypted, discardNumber, j);\n }\n\n function isSpecial(c) {\n return c === 0x2F || // '/'\n c === 0x5B || c === 0x5D || // '[', ']'\n c === 0x7B || c === 0x7D || // '{', '}'\n c === 0x28 || c === 0x29; // '(', ')'\n }\n\n function Type1Parser(stream, encrypted, seacAnalysisEnabled) {\n if (encrypted) {\n var data = stream.getBytes();\n var isBinary = !(isHexDigit(data[0]) && isHexDigit(data[1]) &&\n isHexDigit(data[2]) && isHexDigit(data[3]));\n stream = new Stream(isBinary ? decrypt(data, EEXEC_ENCRYPT_KEY, 4) :\n decryptAscii(data, EEXEC_ENCRYPT_KEY, 4));\n }\n this.seacAnalysisEnabled = !!seacAnalysisEnabled;\n\n this.stream = stream;\n this.nextChar();\n }\n\n Type1Parser.prototype = {\n readNumberArray: function Type1Parser_readNumberArray() {\n this.getToken(); // read '[' or '{' (arrays can start with either)\n var array = [];\n while (true) {\n var token = this.getToken();\n if (token === null || token === ']' || token === '}') {\n break;\n }\n array.push(parseFloat(token || 0));\n }\n return array;\n },\n\n readNumber: function Type1Parser_readNumber() {\n var token = this.getToken();\n return parseFloat(token || 0);\n },\n\n readInt: function Type1Parser_readInt() {\n // Use '| 0' to prevent setting a double into length such as the double\n // does not flow into the loop variable.\n var token = this.getToken();\n return parseInt(token || 0, 10) | 0;\n },\n\n readBoolean: function Type1Parser_readBoolean() {\n var token = this.getToken();\n\n // Use 1 and 0 since that's what type2 charstrings use.\n return token === 'true' ? 1 : 0;\n },\n\n nextChar: function Type1_nextChar() {\n return (this.currentChar = this.stream.getByte());\n },\n\n getToken: function Type1Parser_getToken() {\n // Eat whitespace and comments.\n var comment = false;\n var ch = this.currentChar;\n while (true) {\n if (ch === -1) {\n return null;\n }\n\n if (comment) {\n if (ch === 0x0A || ch === 0x0D) {\n comment = false;\n }\n } else if (ch === 0x25) { // '%'\n comment = true;\n } else if (!isSpace(ch)) {\n break;\n }\n ch = this.nextChar();\n }\n if (isSpecial(ch)) {\n this.nextChar();\n return String.fromCharCode(ch);\n }\n var token = '';\n do {\n token += String.fromCharCode(ch);\n ch = this.nextChar();\n } while (ch >= 0 && !isSpace(ch) && !isSpecial(ch));\n return token;\n },\n\n /*\n * Returns an object containing a Subrs array and a CharStrings\n * array extracted from and eexec encrypted block of data\n */\n extractFontProgram: function Type1Parser_extractFontProgram() {\n var stream = this.stream;\n\n var subrs = [], charstrings = [];\n var privateData = Object.create(null);\n privateData['lenIV'] = 4;\n var program = {\n subrs: [],\n charstrings: [],\n properties: {\n 'privateData': privateData,\n },\n };\n var token, length, data, lenIV, encoded;\n while ((token = this.getToken()) !== null) {\n if (token !== '/') {\n continue;\n }\n token = this.getToken();\n switch (token) {\n case 'CharStrings':\n // The number immediately following CharStrings must be greater or\n // equal to the number of CharStrings.\n this.getToken();\n this.getToken(); // read in 'dict'\n this.getToken(); // read in 'dup'\n this.getToken(); // read in 'begin'\n while (true) {\n token = this.getToken();\n if (token === null || token === 'end') {\n break;\n }\n\n if (token !== '/') {\n continue;\n }\n var glyph = this.getToken();\n length = this.readInt();\n this.getToken(); // read in 'RD' or '-|'\n data = stream.makeSubStream(stream.pos, length);\n lenIV = program.properties.privateData['lenIV'];\n encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY, lenIV);\n // Skip past the required space and binary data.\n stream.skip(length);\n this.nextChar();\n token = this.getToken(); // read in 'ND' or '|-'\n if (token === 'noaccess') {\n this.getToken(); // read in 'def'\n }\n charstrings.push({\n glyph,\n encoded,\n });\n }\n break;\n case 'Subrs':\n this.readInt(); // num\n this.getToken(); // read in 'array'\n while ((token = this.getToken()) === 'dup') {\n var index = this.readInt();\n length = this.readInt();\n this.getToken(); // read in 'RD' or '-|'\n data = stream.makeSubStream(stream.pos, length);\n lenIV = program.properties.privateData['lenIV'];\n encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY, lenIV);\n // Skip past the required space and binary data.\n stream.skip(length);\n this.nextChar();\n token = this.getToken(); // read in 'NP' or '|'\n if (token === 'noaccess') {\n this.getToken(); // read in 'put'\n }\n subrs[index] = encoded;\n }\n break;\n case 'BlueValues':\n case 'OtherBlues':\n case 'FamilyBlues':\n case 'FamilyOtherBlues':\n var blueArray = this.readNumberArray();\n // *Blue* values may contain invalid data: disables reading of\n // those values when hinting is disabled.\n if (blueArray.length > 0 && (blueArray.length % 2) === 0 &&\n HINTING_ENABLED) {\n program.properties.privateData[token] = blueArray;\n }\n break;\n case 'StemSnapH':\n case 'StemSnapV':\n program.properties.privateData[token] = this.readNumberArray();\n break;\n case 'StdHW':\n case 'StdVW':\n program.properties.privateData[token] =\n this.readNumberArray()[0];\n break;\n case 'BlueShift':\n case 'lenIV':\n case 'BlueFuzz':\n case 'BlueScale':\n case 'LanguageGroup':\n case 'ExpansionFactor':\n program.properties.privateData[token] = this.readNumber();\n break;\n case 'ForceBold':\n program.properties.privateData[token] = this.readBoolean();\n break;\n }\n }\n\n for (var i = 0; i < charstrings.length; i++) {\n glyph = charstrings[i].glyph;\n encoded = charstrings[i].encoded;\n var charString = new Type1CharString();\n var error = charString.convert(encoded, subrs,\n this.seacAnalysisEnabled);\n var output = charString.output;\n if (error) {\n // It seems when FreeType encounters an error while evaluating a glyph\n // that it completely ignores the glyph so we'll mimic that behaviour\n // here and put an endchar to make the validator happy.\n output = [14];\n }\n program.charstrings.push({\n glyphName: glyph,\n charstring: output,\n width: charString.width,\n lsb: charString.lsb,\n seac: charString.seac,\n });\n }\n\n return program;\n },\n\n extractFontHeader: function Type1Parser_extractFontHeader(properties) {\n var token;\n while ((token = this.getToken()) !== null) {\n if (token !== '/') {\n continue;\n }\n token = this.getToken();\n switch (token) {\n case 'FontMatrix':\n var matrix = this.readNumberArray();\n properties.fontMatrix = matrix;\n break;\n case 'Encoding':\n var encodingArg = this.getToken();\n var encoding;\n if (!/^\\d+$/.test(encodingArg)) {\n // encoding name is specified\n encoding = getEncoding(encodingArg);\n } else {\n encoding = [];\n var size = parseInt(encodingArg, 10) | 0;\n this.getToken(); // read in 'array'\n\n for (var j = 0; j < size; j++) {\n token = this.getToken();\n // skipping till first dup or def (e.g. ignoring for statement)\n while (token !== 'dup' && token !== 'def') {\n token = this.getToken();\n if (token === null) {\n return; // invalid header\n }\n }\n if (token === 'def') {\n break; // read all array data\n }\n var index = this.readInt();\n this.getToken(); // read in '/'\n var glyph = this.getToken();\n encoding[index] = glyph;\n this.getToken(); // read the in 'put'\n }\n }\n properties.builtInEncoding = encoding;\n break;\n case 'FontBBox':\n var fontBBox = this.readNumberArray();\n // adjusting ascent/descent\n properties.ascent = Math.max(fontBBox[3], fontBBox[1]);\n properties.descent = Math.min(fontBBox[1], fontBBox[3]);\n properties.ascentScaled = true;\n break;\n }\n }\n },\n };\n\n return Type1Parser;\n})();\n\nexport {\n Type1Parser,\n};\n\n\n\n// WEBPACK FOOTER //\n// src/core/type1_parser.js","/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* eslint-disable no-unused-vars */\n\n'use strict';\n\nvar pdfjsVersion = PDFJSDev.eval('BUNDLE_VERSION');\nvar pdfjsBuild = PDFJSDev.eval('BUNDLE_BUILD');\n\nvar pdfjsCoreWorker = require('./core/worker.js');\n\nexports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;\n\n\n\n// WEBPACK FOOTER //\n// src/pdf.worker.js","/* Copyright 2017 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* eslint-disable no-extend-native */\n/* globals VBArray, PDFJS, global */\n\n// Skip compatibility checks for the extensions and if we already ran\n// this module.\nif ((typeof PDFJSDev === 'undefined' ||\n !PDFJSDev.test('FIREFOX || MOZCENTRAL || CHROME')) &&\n (typeof PDFJS === 'undefined' || !PDFJS.compatibilityChecked)) {\n\nvar globalScope =\n (typeof window !== 'undefined' && window.Math === Math) ? window :\n (typeof global !== 'undefined' && global.Math === Math) ? global :\n (typeof self !== 'undefined' && self.Math === Math) ? self :\n (typeof this !== 'undefined' && this.Math === Math) ? this : {};\n\nvar userAgent = (typeof navigator !== 'undefined' && navigator.userAgent) || '';\nvar isAndroid = /Android/.test(userAgent);\nvar isAndroidPre3 = /Android\\s[0-2][^\\d]/.test(userAgent);\nvar isAndroidPre5 = /Android\\s[0-4][^\\d]/.test(userAgent);\nvar isChrome = userAgent.indexOf('Chrom') >= 0;\nvar isChromeWithRangeBug = /Chrome\\/(39|40)\\./.test(userAgent);\nvar isIOSChrome = userAgent.indexOf('CriOS') >= 0;\nvar isIE = userAgent.indexOf('Trident') >= 0;\nvar isIOS = /\\b(iPad|iPhone|iPod)(?=;)/.test(userAgent);\nvar isOpera = userAgent.indexOf('Opera') >= 0;\nvar isSafari = /Safari\\//.test(userAgent) &&\n !/(Chrome\\/|Android\\s)/.test(userAgent);\n\nvar hasDOM = typeof window === 'object' && typeof document === 'object';\n\n// Initializing PDFJS global object here, it case if we need to change/disable\n// some PDF.js features, e.g. range requests\nif (typeof PDFJS === 'undefined') {\n globalScope.PDFJS = {};\n}\n\nPDFJS.compatibilityChecked = true;\n\n// Checking if the typed arrays are supported\n// Support: iOS<6.0 (subarray), IE<10, Android<4.0\n(function checkTypedArrayCompatibility() {\n if (typeof Uint8Array !== 'undefined') {\n // Support: iOS<6.0\n if (typeof Uint8Array.prototype.subarray === 'undefined') {\n Uint8Array.prototype.subarray = function subarray(start, end) {\n return new Uint8Array(this.slice(start, end));\n };\n Float32Array.prototype.subarray = function subarray(start, end) {\n return new Float32Array(this.slice(start, end));\n };\n }\n\n // Support: Android<4.1\n if (typeof Float64Array === 'undefined') {\n globalScope.Float64Array = Float32Array;\n }\n return;\n }\n\n function subarray(start, end) {\n return new TypedArray(this.slice(start, end));\n }\n\n function setArrayOffset(array, offset) {\n if (arguments.length < 2) {\n offset = 0;\n }\n for (var i = 0, n = array.length; i < n; ++i, ++offset) {\n this[offset] = array[i] & 0xFF;\n }\n }\n\n function Uint32ArrayView(buffer, length) {\n this.buffer = buffer;\n this.byteLength = buffer.length;\n this.length = length;\n ensureUint32ArrayViewProps(this.length);\n }\n Uint32ArrayView.prototype = Object.create(null);\n\n var uint32ArrayViewSetters = 0;\n function createUint32ArrayProp(index) {\n return {\n get() {\n var buffer = this.buffer, offset = index << 2;\n return (buffer[offset] | (buffer[offset + 1] << 8) |\n (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24)) >>> 0;\n },\n set(value) {\n var buffer = this.buffer, offset = index << 2;\n buffer[offset] = value & 255;\n buffer[offset + 1] = (value >> 8) & 255;\n buffer[offset + 2] = (value >> 16) & 255;\n buffer[offset + 3] = (value >>> 24) & 255;\n },\n };\n }\n\n function ensureUint32ArrayViewProps(length) {\n while (uint32ArrayViewSetters < length) {\n Object.defineProperty(Uint32ArrayView.prototype,\n uint32ArrayViewSetters,\n createUint32ArrayProp(uint32ArrayViewSetters));\n uint32ArrayViewSetters++;\n }\n }\n\n function TypedArray(arg1) {\n var result, i, n;\n if (typeof arg1 === 'number') {\n result = [];\n for (i = 0; i < arg1; ++i) {\n result[i] = 0;\n }\n } else if ('slice' in arg1) {\n result = arg1.slice(0);\n } else {\n result = [];\n for (i = 0, n = arg1.length; i < n; ++i) {\n result[i] = arg1[i];\n }\n }\n\n result.subarray = subarray;\n result.buffer = result;\n result.byteLength = result.length;\n result.set = setArrayOffset;\n\n if (typeof arg1 === 'object' && arg1.buffer) {\n result.buffer = arg1.buffer;\n }\n return result;\n }\n\n globalScope.Uint8Array = TypedArray;\n globalScope.Int8Array = TypedArray;\n\n // we don't need support for set, byteLength for 32-bit array\n // so we can use the TypedArray as well\n globalScope.Int32Array = TypedArray;\n globalScope.Uint16Array = TypedArray;\n globalScope.Float32Array = TypedArray;\n globalScope.Float64Array = TypedArray;\n\n globalScope.Uint32Array = function () {\n if (arguments.length === 3) {\n // Building view for buffer, offset, and length\n if (arguments[1] !== 0) {\n throw new Error('offset !== 0 is not supported');\n }\n return new Uint32ArrayView(arguments[0], arguments[2]);\n }\n return TypedArray.apply(this, arguments);\n };\n})();\n\n// window.CanvasPixelArray.buffer/.byteLength\n// Support: IE9\n(function canvasPixelArrayBuffer() {\n if (!hasDOM || !window.CanvasPixelArray) {\n return;\n }\n var cpaProto = window.CanvasPixelArray.prototype;\n if ('buffer' in cpaProto) {\n return;\n }\n // Trying to fake CanvasPixelArray as Uint8ClampedArray.\n Object.defineProperty(cpaProto, 'buffer', {\n get() {\n return this;\n },\n enumerable: false,\n configurable: true,\n });\n Object.defineProperty(cpaProto, 'byteLength', {\n get() {\n return this.length;\n },\n enumerable: false,\n configurable: true,\n });\n})();\n\n// URL = URL || webkitURL\n// Support: Safari<7, Android 4.2+\n(function normalizeURLObject() {\n if (!globalScope.URL) {\n globalScope.URL = globalScope.webkitURL;\n }\n})();\n\n// Object.defineProperty()?\n// Support: Android<4.0, Safari<5.1\n(function checkObjectDefinePropertyCompatibility() {\n if (typeof Object.defineProperty !== 'undefined') {\n var definePropertyPossible = true;\n try {\n if (hasDOM) {\n // some browsers (e.g. safari) cannot use defineProperty() on DOM\n // objects and thus the native version is not sufficient\n Object.defineProperty(new Image(), 'id', { value: 'test', });\n }\n // ... another test for android gb browser for non-DOM objects\n var Test = function Test() {};\n Test.prototype = { get id() { }, };\n Object.defineProperty(new Test(), 'id',\n { value: '', configurable: true, enumerable: true, writable: false, });\n } catch (e) {\n definePropertyPossible = false;\n }\n if (definePropertyPossible) {\n return;\n }\n }\n\n Object.defineProperty = function objectDefineProperty(obj, name, def) {\n delete obj[name];\n if ('get' in def) {\n obj.__defineGetter__(name, def['get']);\n }\n if ('set' in def) {\n obj.__defineSetter__(name, def['set']);\n }\n if ('value' in def) {\n obj.__defineSetter__(name, function objectDefinePropertySetter(value) {\n this.__defineGetter__(name, function objectDefinePropertyGetter() {\n return value;\n });\n return value;\n });\n obj[name] = def.value;\n }\n };\n})();\n\n\n// No XMLHttpRequest#response?\n// Support: IE<11, Android <4.0\n(function checkXMLHttpRequestResponseCompatibility() {\n if (typeof XMLHttpRequest === 'undefined') {\n return;\n }\n var xhrPrototype = XMLHttpRequest.prototype;\n var xhr = new XMLHttpRequest();\n if (!('overrideMimeType' in xhr)) {\n // IE10 might have response, but not overrideMimeType\n // Support: IE10\n Object.defineProperty(xhrPrototype, 'overrideMimeType', {\n value: function xmlHttpRequestOverrideMimeType(mimeType) {},\n });\n }\n if ('responseType' in xhr) {\n return;\n }\n\n Object.defineProperty(xhrPrototype, 'responseType', {\n get: function xmlHttpRequestGetResponseType() {\n return this._responseType || 'text';\n },\n set: function xmlHttpRequestSetResponseType(value) {\n if (value === 'text' || value === 'arraybuffer') {\n this._responseType = value;\n if (value === 'arraybuffer' &&\n typeof this.overrideMimeType === 'function') {\n this.overrideMimeType('text/plain; charset=x-user-defined');\n }\n }\n },\n });\n\n // Support: IE9\n if (typeof VBArray !== 'undefined') {\n Object.defineProperty(xhrPrototype, 'response', {\n get: function xmlHttpRequestResponseGet() {\n if (this.responseType === 'arraybuffer') {\n return new Uint8Array(new VBArray(this.responseBody).toArray());\n }\n return this.responseText;\n },\n });\n return;\n }\n\n Object.defineProperty(xhrPrototype, 'response', {\n get: function xmlHttpRequestResponseGet() {\n if (this.responseType !== 'arraybuffer') {\n return this.responseText;\n }\n var text = this.responseText;\n var i, n = text.length;\n var result = new Uint8Array(n);\n for (i = 0; i < n; ++i) {\n result[i] = text.charCodeAt(i) & 0xFF;\n }\n return result.buffer;\n },\n });\n})();\n\n// window.btoa (base64 encode function) ?\n// Support: IE<10\n(function checkWindowBtoaCompatibility() {\n if ('btoa' in globalScope) {\n return;\n }\n\n var digits =\n 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';\n\n globalScope.btoa = function (chars) {\n var buffer = '';\n var i, n;\n for (i = 0, n = chars.length; i < n; i += 3) {\n var b1 = chars.charCodeAt(i) & 0xFF;\n var b2 = chars.charCodeAt(i + 1) & 0xFF;\n var b3 = chars.charCodeAt(i + 2) & 0xFF;\n var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);\n var d3 = i + 1 < n ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;\n var d4 = i + 2 < n ? (b3 & 0x3F) : 64;\n buffer += (digits.charAt(d1) + digits.charAt(d2) +\n digits.charAt(d3) + digits.charAt(d4));\n }\n return buffer;\n };\n})();\n\n// window.atob (base64 encode function)?\n// Support: IE<10\n(function checkWindowAtobCompatibility() {\n if ('atob' in globalScope) {\n return;\n }\n\n // https://github.com/davidchambers/Base64.js\n var digits =\n 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';\n globalScope.atob = function (input) {\n input = input.replace(/=+$/, '');\n if (input.length % 4 === 1) {\n throw new Error('bad atob input');\n }\n for (\n // initialize result and counters\n var bc = 0, bs, buffer, idx = 0, output = '';\n // get next character\n (buffer = input.charAt(idx++));\n // character found in table?\n // initialize bit storage and add its ascii value\n ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,\n // and if not first of each 4 characters,\n // convert the first 8 bits to one ascii character\n bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0\n ) {\n // try to find character in table (0-63, not found => -1)\n buffer = digits.indexOf(buffer);\n }\n return output;\n };\n})();\n\n// Function.prototype.bind?\n// Support: Android<4.0, iOS<6.0\n(function checkFunctionPrototypeBindCompatibility() {\n if (typeof Function.prototype.bind !== 'undefined') {\n return;\n }\n\n Function.prototype.bind = function functionPrototypeBind(obj) {\n var fn = this, headArgs = Array.prototype.slice.call(arguments, 1);\n var bound = function functionPrototypeBindBound() {\n var args = headArgs.concat(Array.prototype.slice.call(arguments));\n return fn.apply(obj, args);\n };\n return bound;\n };\n})();\n\n// HTMLElement dataset property\n// Support: IE<11, Safari<5.1, Android<4.0\n(function checkDatasetProperty() {\n if (!hasDOM) {\n return;\n }\n var div = document.createElement('div');\n if ('dataset' in div) {\n return; // dataset property exists\n }\n\n Object.defineProperty(HTMLElement.prototype, 'dataset', {\n get() {\n if (this._dataset) {\n return this._dataset;\n }\n\n var dataset = {};\n for (var j = 0, jj = this.attributes.length; j < jj; j++) {\n var attribute = this.attributes[j];\n if (attribute.name.substring(0, 5) !== 'data-') {\n continue;\n }\n var key = attribute.name.substring(5).replace(/\\-([a-z])/g,\n function(all, ch) {\n return ch.toUpperCase();\n });\n dataset[key] = attribute.value;\n }\n\n Object.defineProperty(this, '_dataset', {\n value: dataset,\n writable: false,\n enumerable: false,\n });\n return dataset;\n },\n enumerable: true,\n });\n})();\n\n// HTMLElement classList property\n// Support: IE<10, Android<4.0, iOS<5.0\n(function checkClassListProperty() {\n function changeList(element, itemName, add, remove) {\n var s = element.className || '';\n var list = s.split(/\\s+/g);\n if (list[0] === '') {\n list.shift();\n }\n var index = list.indexOf(itemName);\n if (index < 0 && add) {\n list.push(itemName);\n }\n if (index >= 0 && remove) {\n list.splice(index, 1);\n }\n element.className = list.join(' ');\n return (index >= 0);\n }\n\n if (!hasDOM) {\n return;\n }\n\n var div = document.createElement('div');\n if ('classList' in div) {\n return; // classList property exists\n }\n\n var classListPrototype = {\n add(name) {\n changeList(this.element, name, true, false);\n },\n contains(name) {\n return changeList(this.element, name, false, false);\n },\n remove(name) {\n changeList(this.element, name, false, true);\n },\n toggle(name) {\n changeList(this.element, name, true, true);\n },\n };\n\n Object.defineProperty(HTMLElement.prototype, 'classList', {\n get() {\n if (this._classList) {\n return this._classList;\n }\n\n var classList = Object.create(classListPrototype, {\n element: {\n value: this,\n writable: false,\n enumerable: true,\n },\n });\n Object.defineProperty(this, '_classList', {\n value: classList,\n writable: false,\n enumerable: false,\n });\n return classList;\n },\n enumerable: true,\n });\n})();\n\n// Checking if worker has console support. Forwarding all messages to the main\n// thread if console object is absent.\n(function checkWorkerConsoleCompatibility() {\n if (typeof importScripts === 'undefined' || 'console' in globalScope) {\n return;\n }\n\n var consoleTimer = {};\n\n var workerConsole = {\n log: function log() {\n var args = Array.prototype.slice.call(arguments);\n globalScope.postMessage({\n targetName: 'main',\n action: 'console_log',\n data: args,\n });\n },\n\n error: function error() {\n var args = Array.prototype.slice.call(arguments);\n globalScope.postMessage({\n targetName: 'main',\n action: 'console_error',\n data: args,\n });\n },\n\n time: function time(name) {\n consoleTimer[name] = Date.now();\n },\n\n timeEnd: function timeEnd(name) {\n var time = consoleTimer[name];\n if (!time) {\n throw new Error('Unknown timer name ' + name);\n }\n this.log('Timer:', name, Date.now() - time);\n },\n };\n\n globalScope.console = workerConsole;\n})();\n\n// Check console compatibility\n// In older IE versions the console object is not available\n// unless console is open.\n// Support: IE<10\n(function checkConsoleCompatibility() {\n if (!hasDOM) {\n return;\n }\n if (!('console' in window)) {\n window.console = {\n log() {},\n error() {},\n warn() {},\n };\n return;\n }\n if (!('bind' in console.log)) {\n // native functions in IE9 might not have bind\n console.log = (function(fn) {\n return function(msg) {\n return fn(msg);\n };\n })(console.log);\n console.error = (function(fn) {\n return function(msg) {\n return fn(msg);\n };\n })(console.error);\n console.warn = (function(fn) {\n return function(msg) {\n return fn(msg);\n };\n })(console.warn);\n return;\n }\n})();\n\n// Check onclick compatibility in Opera\n// Support: Opera<15\n(function checkOnClickCompatibility() {\n // workaround for reported Opera bug DSK-354448:\n // onclick fires on disabled buttons with opaque content\n function ignoreIfTargetDisabled(event) {\n if (isDisabled(event.target)) {\n event.stopPropagation();\n }\n }\n function isDisabled(node) {\n return node.disabled || (node.parentNode && isDisabled(node.parentNode));\n }\n if (isOpera) {\n // use browser detection since we cannot feature-check this bug\n document.addEventListener('click', ignoreIfTargetDisabled, true);\n }\n})();\n\n// Checks if possible to use URL.createObjectURL()\n// Support: IE, Chrome on iOS\n(function checkOnBlobSupport() {\n // sometimes IE and Chrome on iOS loosing the data created with\n // createObjectURL(), see #3977 and #8081\n if (isIE || isIOSChrome) {\n PDFJS.disableCreateObjectURL = true;\n }\n})();\n\n// Checks if navigator.language is supported\n(function checkNavigatorLanguage() {\n if (typeof navigator === 'undefined') {\n return;\n }\n if ('language' in navigator) {\n return;\n }\n PDFJS.locale = navigator.userLanguage || 'en-US';\n})();\n\n// Support: Safari 6.0+, Android<3.0, Chrome 39/40, iOS\n(function checkRangeRequests() {\n // Safari has issues with cached range requests see:\n // https://github.com/mozilla/pdf.js/issues/3260\n // Last tested with version 6.0.4.\n\n // Older versions of Android (pre 3.0) has issues with range requests, see:\n // https://github.com/mozilla/pdf.js/issues/3381.\n // Make sure that we only match webkit-based Android browsers,\n // since Firefox/Fennec works as expected.\n\n // Range requests are broken in Chrome 39 and 40, https://crbug.com/442318\n if (isSafari || isAndroidPre3 || isChromeWithRangeBug || isIOS) {\n PDFJS.disableRange = true;\n PDFJS.disableStream = true;\n }\n})();\n\n// Check if the browser supports manipulation of the history.\n// Support: IE<10, Android<4.2\n(function checkHistoryManipulation() {\n if (!hasDOM) {\n return;\n }\n // Android 2.x has so buggy pushState support that it was removed in\n // Android 3.0 and restored as late as in Android 4.2.\n // Support: Android 2.x\n if (!history.pushState || isAndroidPre3) {\n PDFJS.disableHistory = true;\n }\n})();\n\n// Support: IE<11, Chrome<21, Android<4.4, Safari<6\n(function checkSetPresenceInImageData() {\n if (!hasDOM) {\n return;\n }\n // IE < 11 will use window.CanvasPixelArray which lacks set function.\n if (window.CanvasPixelArray) {\n if (typeof window.CanvasPixelArray.prototype.set !== 'function') {\n window.CanvasPixelArray.prototype.set = function(arr) {\n for (var i = 0, ii = this.length; i < ii; i++) {\n this[i] = arr[i];\n }\n };\n }\n } else {\n // Old Chrome and Android use an inaccessible CanvasPixelArray prototype.\n // Because we cannot feature detect it, we rely on user agent parsing.\n var polyfill = false, versionMatch;\n if (isChrome) {\n versionMatch = userAgent.match(/Chrom(e|ium)\\/([0-9]+)\\./);\n // Chrome < 21 lacks the set function.\n polyfill = versionMatch && parseInt(versionMatch[2]) < 21;\n } else if (isAndroid) {\n // Android < 4.4 lacks the set function.\n // Android >= 4.4 will contain Chrome in the user agent,\n // thus pass the Chrome check above and not reach this block.\n polyfill = isAndroidPre5;\n } else if (isSafari) {\n versionMatch = userAgent.\n match(/Version\\/([0-9]+)\\.([0-9]+)\\.([0-9]+) Safari\\//);\n // Safari < 6 lacks the set function.\n polyfill = versionMatch && parseInt(versionMatch[1]) < 6;\n }\n\n if (polyfill) {\n var contextPrototype = window.CanvasRenderingContext2D.prototype;\n var createImageData = contextPrototype.createImageData;\n contextPrototype.createImageData = function(w, h) {\n var imageData = createImageData.call(this, w, h);\n imageData.data.set = function(arr) {\n for (var i = 0, ii = this.length; i < ii; i++) {\n this[i] = arr[i];\n }\n };\n return imageData;\n };\n // this closure will be kept referenced, so clear its vars\n contextPrototype = null;\n }\n }\n})();\n\n// Support: IE<10, Android<4.0, iOS\n(function checkRequestAnimationFrame() {\n function installFakeAnimationFrameFunctions() {\n window.requestAnimationFrame = function (callback) {\n return window.setTimeout(callback, 20);\n };\n window.cancelAnimationFrame = function (timeoutID) {\n window.clearTimeout(timeoutID);\n };\n }\n\n if (!hasDOM) {\n return;\n }\n if (isIOS) {\n // requestAnimationFrame on iOS is broken, replacing with fake one.\n installFakeAnimationFrameFunctions();\n return;\n }\n if ('requestAnimationFrame' in window) {\n return;\n }\n window.requestAnimationFrame = window.mozRequestAnimationFrame ||\n window.webkitRequestAnimationFrame;\n if (window.requestAnimationFrame) {\n return;\n }\n installFakeAnimationFrameFunctions();\n})();\n\n// Support: Android, iOS\n(function checkCanvasSizeLimitation() {\n if (isIOS || isAndroid) {\n // 5MP\n PDFJS.maxCanvasPixels = 5242880;\n }\n})();\n\n// Disable fullscreen support for certain problematic configurations.\n// Support: IE11+ (when embedded).\n(function checkFullscreenSupport() {\n if (!hasDOM) {\n return;\n }\n if (isIE && window.parent !== window) {\n PDFJS.disableFullscreen = true;\n }\n})();\n\n// Provides document.currentScript support\n// Support: IE, Chrome<29.\n(function checkCurrentScript() {\n if (!hasDOM) {\n return;\n }\n if ('currentScript' in document) {\n return;\n }\n Object.defineProperty(document, 'currentScript', {\n get() {\n var scripts = document.getElementsByTagName('script');\n return scripts[scripts.length - 1];\n },\n enumerable: true,\n configurable: true,\n });\n})();\n\n// Provides `input.type = 'type'` runtime failure protection.\n// Support: IE9,10.\n(function checkInputTypeNumberAssign() {\n if (!hasDOM) {\n return;\n }\n var el = document.createElement('input');\n try {\n el.type = 'number';\n } catch (ex) {\n var inputProto = el.constructor.prototype;\n var typeProperty = Object.getOwnPropertyDescriptor(inputProto, 'type');\n Object.defineProperty(inputProto, 'type', {\n get() {\n return typeProperty.get.call(this);\n },\n set(value) {\n typeProperty.set.call(this, value === 'number' ? 'text' : value);\n },\n enumerable: true,\n configurable: true,\n });\n }\n})();\n\n// Provides correct document.readyState value for legacy browsers.\n// Support: IE9,10.\n(function checkDocumentReadyState() {\n if (!hasDOM) {\n return;\n }\n if (!document.attachEvent) {\n return;\n }\n var documentProto = document.constructor.prototype;\n var readyStateProto = Object.getOwnPropertyDescriptor(documentProto,\n 'readyState');\n Object.defineProperty(documentProto, 'readyState', {\n get() {\n var value = readyStateProto.get.call(this);\n return value === 'interactive' ? 'loading' : value;\n },\n set(value) {\n readyStateProto.set.call(this, value);\n },\n enumerable: true,\n configurable: true,\n });\n})();\n\n// Provides support for ChildNode.remove in legacy browsers.\n// Support: IE.\n(function checkChildNodeRemove() {\n if (!hasDOM) {\n return;\n }\n if (typeof Element.prototype.remove !== 'undefined') {\n return;\n }\n Element.prototype.remove = function () {\n if (this.parentNode) {\n this.parentNode.removeChild(this);\n }\n };\n})();\n\n// Provides support for Number.isNaN in legacy browsers.\n// Support: IE.\n(function checkNumberIsNaN() {\n if (Number.isNaN) {\n return;\n }\n Number.isNaN = function(value) {\n return typeof value === 'number' && isNaN(value);\n };\n})();\n\n// Provides support for Number.isInteger in legacy browsers.\n// Support: IE.\n(function checkNumberIsInteger() {\n if (Number.isInteger) {\n return;\n }\n Number.isInteger = function(value) {\n return typeof value === 'number' && isFinite(value) &&\n Math.floor(value) === value;\n };\n})();\n\n/**\n * Polyfill for Promises:\n * The following promise implementation tries to generally implement the\n * Promise/A+ spec. Some notable differences from other promise libraries are:\n * - There currently isn't a separate deferred and promise object.\n * - Unhandled rejections eventually show an error if they aren't handled.\n *\n * Based off of the work in:\n * https://bugzilla.mozilla.org/show_bug.cgi?id=810490\n */\n(function checkPromise() {\n if (globalScope.Promise) {\n // Promises existing in the DOM/Worker, checking presence of all/resolve\n if (typeof globalScope.Promise.all !== 'function') {\n globalScope.Promise.all = function (iterable) {\n var count = 0, results = [], resolve, reject;\n var promise = new globalScope.Promise(function (resolve_, reject_) {\n resolve = resolve_;\n reject = reject_;\n });\n iterable.forEach(function (p, i) {\n count++;\n p.then(function (result) {\n results[i] = result;\n count--;\n if (count === 0) {\n resolve(results);\n }\n }, reject);\n });\n if (count === 0) {\n resolve(results);\n }\n return promise;\n };\n }\n if (typeof globalScope.Promise.resolve !== 'function') {\n globalScope.Promise.resolve = function (value) {\n return new globalScope.Promise(function (resolve) {\n resolve(value);\n });\n };\n }\n if (typeof globalScope.Promise.reject !== 'function') {\n globalScope.Promise.reject = function (reason) {\n return new globalScope.Promise(function (resolve, reject) {\n reject(reason);\n });\n };\n }\n if (typeof globalScope.Promise.prototype.catch !== 'function') {\n globalScope.Promise.prototype.catch = function (onReject) {\n return globalScope.Promise.prototype.then(undefined, onReject);\n };\n }\n return;\n }\n\n var STATUS_PENDING = 0;\n var STATUS_RESOLVED = 1;\n var STATUS_REJECTED = 2;\n\n // In an attempt to avoid silent exceptions, unhandled rejections are\n // tracked and if they aren't handled in a certain amount of time an\n // error is logged.\n var REJECTION_TIMEOUT = 500;\n\n var HandlerManager = {\n handlers: [],\n running: false,\n unhandledRejections: [],\n pendingRejectionCheck: false,\n\n scheduleHandlers: function scheduleHandlers(promise) {\n if (promise._status === STATUS_PENDING) {\n return;\n }\n\n this.handlers = this.handlers.concat(promise._handlers);\n promise._handlers = [];\n\n if (this.running) {\n return;\n }\n this.running = true;\n\n setTimeout(this.runHandlers.bind(this), 0);\n },\n\n runHandlers: function runHandlers() {\n var RUN_TIMEOUT = 1; // ms\n var timeoutAt = Date.now() + RUN_TIMEOUT;\n while (this.handlers.length > 0) {\n var handler = this.handlers.shift();\n\n var nextStatus = handler.thisPromise._status;\n var nextValue = handler.thisPromise._value;\n\n try {\n if (nextStatus === STATUS_RESOLVED) {\n if (typeof handler.onResolve === 'function') {\n nextValue = handler.onResolve(nextValue);\n }\n } else if (typeof handler.onReject === 'function') {\n nextValue = handler.onReject(nextValue);\n nextStatus = STATUS_RESOLVED;\n\n if (handler.thisPromise._unhandledRejection) {\n this.removeUnhandeledRejection(handler.thisPromise);\n }\n }\n } catch (ex) {\n nextStatus = STATUS_REJECTED;\n nextValue = ex;\n }\n\n handler.nextPromise._updateStatus(nextStatus, nextValue);\n if (Date.now() >= timeoutAt) {\n break;\n }\n }\n\n if (this.handlers.length > 0) {\n setTimeout(this.runHandlers.bind(this), 0);\n return;\n }\n\n this.running = false;\n },\n\n addUnhandledRejection: function addUnhandledRejection(promise) {\n this.unhandledRejections.push({\n promise,\n time: Date.now(),\n });\n this.scheduleRejectionCheck();\n },\n\n removeUnhandeledRejection: function removeUnhandeledRejection(promise) {\n promise._unhandledRejection = false;\n for (var i = 0; i < this.unhandledRejections.length; i++) {\n if (this.unhandledRejections[i].promise === promise) {\n this.unhandledRejections.splice(i);\n i--;\n }\n }\n },\n\n scheduleRejectionCheck: function scheduleRejectionCheck() {\n if (this.pendingRejectionCheck) {\n return;\n }\n this.pendingRejectionCheck = true;\n setTimeout(() => {\n this.pendingRejectionCheck = false;\n var now = Date.now();\n for (var i = 0; i < this.unhandledRejections.length; i++) {\n if (now - this.unhandledRejections[i].time > REJECTION_TIMEOUT) {\n var unhandled = this.unhandledRejections[i].promise._value;\n var msg = 'Unhandled rejection: ' + unhandled;\n if (unhandled.stack) {\n msg += '\\n' + unhandled.stack;\n }\n // Raising and catching the error, so debugger can break on it.\n try {\n throw new Error(msg);\n } catch (_) {\n console.warn(msg);\n }\n this.unhandledRejections.splice(i);\n i--;\n }\n }\n if (this.unhandledRejections.length) {\n this.scheduleRejectionCheck();\n }\n }, REJECTION_TIMEOUT);\n },\n };\n\n var Promise = function Promise(resolver) {\n this._status = STATUS_PENDING;\n this._handlers = [];\n try {\n resolver.call(this, this._resolve.bind(this), this._reject.bind(this));\n } catch (e) {\n this._reject(e);\n }\n };\n\n /**\n * Builds a promise that is resolved when all the passed in promises are\n * resolved.\n * @param {array} promises array of data and/or promises to wait for.\n * @return {Promise} New dependent promise.\n */\n Promise.all = function Promise_all(promises) {\n var resolveAll, rejectAll;\n var deferred = new Promise(function (resolve, reject) {\n resolveAll = resolve;\n rejectAll = reject;\n });\n var unresolved = promises.length;\n var results = [];\n if (unresolved === 0) {\n resolveAll(results);\n return deferred;\n }\n function reject(reason) {\n if (deferred._status === STATUS_REJECTED) {\n return;\n }\n results = [];\n rejectAll(reason);\n }\n for (var i = 0, ii = promises.length; i < ii; ++i) {\n var promise = promises[i];\n var resolve = (function(i) {\n return function(value) {\n if (deferred._status === STATUS_REJECTED) {\n return;\n }\n results[i] = value;\n unresolved--;\n if (unresolved === 0) {\n resolveAll(results);\n }\n };\n })(i);\n if (Promise.isPromise(promise)) {\n promise.then(resolve, reject);\n } else {\n resolve(promise);\n }\n }\n return deferred;\n };\n\n /**\n * Checks if the value is likely a promise (has a 'then' function).\n * @return {boolean} true if value is thenable\n */\n Promise.isPromise = function Promise_isPromise(value) {\n return value && typeof value.then === 'function';\n };\n\n /**\n * Creates resolved promise\n * @param value resolve value\n * @returns {Promise}\n */\n Promise.resolve = function Promise_resolve(value) {\n return new Promise(function (resolve) {\n resolve(value);\n });\n };\n\n /**\n * Creates rejected promise\n * @param reason rejection value\n * @returns {Promise}\n */\n Promise.reject = function Promise_reject(reason) {\n return new Promise(function (resolve, reject) {\n reject(reason);\n });\n };\n\n Promise.prototype = {\n _status: null,\n _value: null,\n _handlers: null,\n _unhandledRejection: null,\n\n _updateStatus: function Promise__updateStatus(status, value) {\n if (this._status === STATUS_RESOLVED ||\n this._status === STATUS_REJECTED) {\n return;\n }\n\n if (status === STATUS_RESOLVED &&\n Promise.isPromise(value)) {\n value.then(this._updateStatus.bind(this, STATUS_RESOLVED),\n this._updateStatus.bind(this, STATUS_REJECTED));\n return;\n }\n\n this._status = status;\n this._value = value;\n\n if (status === STATUS_REJECTED && this._handlers.length === 0) {\n this._unhandledRejection = true;\n HandlerManager.addUnhandledRejection(this);\n }\n\n HandlerManager.scheduleHandlers(this);\n },\n\n _resolve: function Promise_resolve(value) {\n this._updateStatus(STATUS_RESOLVED, value);\n },\n\n _reject: function Promise_reject(reason) {\n this._updateStatus(STATUS_REJECTED, reason);\n },\n\n then: function Promise_then(onResolve, onReject) {\n var nextPromise = new Promise(function (resolve, reject) {\n this.resolve = resolve;\n this.reject = reject;\n });\n this._handlers.push({\n thisPromise: this,\n onResolve,\n onReject,\n nextPromise,\n });\n HandlerManager.scheduleHandlers(this);\n return nextPromise;\n },\n\n catch: function Promise_catch(onReject) {\n return this.then(undefined, onReject);\n },\n };\n\n globalScope.Promise = Promise;\n})();\n\n(function checkWeakMap() {\n if (globalScope.WeakMap) {\n return;\n }\n\n var id = 0;\n function WeakMap() {\n this.id = '$weakmap' + (id++);\n }\n WeakMap.prototype = {\n has(obj) {\n if ((typeof obj !== 'object' && typeof obj !== 'function') ||\n obj === null) {\n return false;\n }\n return !!Object.getOwnPropertyDescriptor(obj, this.id);\n },\n get(obj) {\n return this.has(obj) ? obj[this.id] : undefined;\n },\n set(obj, value) {\n Object.defineProperty(obj, this.id, {\n value,\n enumerable: false,\n configurable: true,\n });\n },\n delete(obj) {\n delete obj[this.id];\n },\n };\n\n globalScope.WeakMap = WeakMap;\n})();\n\n// Polyfill from https://github.com/Polymer/URL\n/* Any copyright is dedicated to the Public Domain.\n * http://creativecommons.org/publicdomain/zero/1.0/ */\n(function checkURLConstructor() {\n // feature detect for URL constructor\n var hasWorkingUrl = false;\n try {\n if (typeof URL === 'function' &&\n typeof URL.prototype === 'object' &&\n ('origin' in URL.prototype)) {\n var u = new URL('b', 'http://a');\n u.pathname = 'c%20d';\n hasWorkingUrl = u.href === 'http://a/c%20d';\n }\n } catch (e) { }\n\n if (hasWorkingUrl) {\n return;\n }\n\n var relative = Object.create(null);\n relative['ftp'] = 21;\n relative['file'] = 0;\n relative['gopher'] = 70;\n relative['http'] = 80;\n relative['https'] = 443;\n relative['ws'] = 80;\n relative['wss'] = 443;\n\n var relativePathDotMapping = Object.create(null);\n relativePathDotMapping['%2e'] = '.';\n relativePathDotMapping['.%2e'] = '..';\n relativePathDotMapping['%2e.'] = '..';\n relativePathDotMapping['%2e%2e'] = '..';\n\n function isRelativeScheme(scheme) {\n return relative[scheme] !== undefined;\n }\n\n function invalid() {\n clear.call(this);\n this._isInvalid = true;\n }\n\n function IDNAToASCII(h) {\n if (h === '') {\n invalid.call(this);\n }\n // XXX\n return h.toLowerCase();\n }\n\n function percentEscape(c) {\n var unicode = c.charCodeAt(0);\n if (unicode > 0x20 &&\n unicode < 0x7F &&\n // \" # < > ? `\n [0x22, 0x23, 0x3C, 0x3E, 0x3F, 0x60].indexOf(unicode) === -1\n ) {\n return c;\n }\n return encodeURIComponent(c);\n }\n\n function percentEscapeQuery(c) {\n // XXX This actually needs to encode c using encoding and then\n // convert the bytes one-by-one.\n\n var unicode = c.charCodeAt(0);\n if (unicode > 0x20 &&\n unicode < 0x7F &&\n // \" # < > ` (do not escape '?')\n [0x22, 0x23, 0x3C, 0x3E, 0x60].indexOf(unicode) === -1\n ) {\n return c;\n }\n return encodeURIComponent(c);\n }\n\n var EOF, ALPHA = /[a-zA-Z]/,\n ALPHANUMERIC = /[a-zA-Z0-9\\+\\-\\.]/;\n\n function parse(input, stateOverride, base) {\n function err(message) {\n errors.push(message);\n }\n\n var state = stateOverride || 'scheme start',\n cursor = 0,\n buffer = '',\n seenAt = false,\n seenBracket = false,\n errors = [];\n\n loop: while ((input[cursor - 1] !== EOF || cursor === 0) &&\n !this._isInvalid) {\n var c = input[cursor];\n switch (state) {\n case 'scheme start':\n if (c && ALPHA.test(c)) {\n buffer += c.toLowerCase(); // ASCII-safe\n state = 'scheme';\n } else if (!stateOverride) {\n buffer = '';\n state = 'no scheme';\n continue;\n } else {\n err('Invalid scheme.');\n break loop;\n }\n break;\n\n case 'scheme':\n if (c && ALPHANUMERIC.test(c)) {\n buffer += c.toLowerCase(); // ASCII-safe\n } else if (c === ':') {\n this._scheme = buffer;\n buffer = '';\n if (stateOverride) {\n break loop;\n }\n if (isRelativeScheme(this._scheme)) {\n this._isRelative = true;\n }\n if (this._scheme === 'file') {\n state = 'relative';\n } else if (this._isRelative && base &&\n base._scheme === this._scheme) {\n state = 'relative or authority';\n } else if (this._isRelative) {\n state = 'authority first slash';\n } else {\n state = 'scheme data';\n }\n } else if (!stateOverride) {\n buffer = '';\n cursor = 0;\n state = 'no scheme';\n continue;\n } else if (c === EOF) {\n break loop;\n } else {\n err('Code point not allowed in scheme: ' + c);\n break loop;\n }\n break;\n\n case 'scheme data':\n if (c === '?') {\n this._query = '?';\n state = 'query';\n } else if (c === '#') {\n this._fragment = '#';\n state = 'fragment';\n } else {\n // XXX error handling\n if (c !== EOF && c !== '\\t' && c !== '\\n' && c !== '\\r') {\n this._schemeData += percentEscape(c);\n }\n }\n break;\n\n case 'no scheme':\n if (!base || !(isRelativeScheme(base._scheme))) {\n err('Missing scheme.');\n invalid.call(this);\n } else {\n state = 'relative';\n continue;\n }\n break;\n\n case 'relative or authority':\n if (c === '/' && input[cursor + 1] === '/') {\n state = 'authority ignore slashes';\n } else {\n err('Expected /, got: ' + c);\n state = 'relative';\n continue;\n }\n break;\n\n case 'relative':\n this._isRelative = true;\n if (this._scheme !== 'file') {\n this._scheme = base._scheme;\n }\n if (c === EOF) {\n this._host = base._host;\n this._port = base._port;\n this._path = base._path.slice();\n this._query = base._query;\n this._username = base._username;\n this._password = base._password;\n break loop;\n } else if (c === '/' || c === '\\\\') {\n if (c === '\\\\') {\n err('\\\\ is an invalid code point.');\n }\n state = 'relative slash';\n } else if (c === '?') {\n this._host = base._host;\n this._port = base._port;\n this._path = base._path.slice();\n this._query = '?';\n this._username = base._username;\n this._password = base._password;\n state = 'query';\n } else if (c === '#') {\n this._host = base._host;\n this._port = base._port;\n this._path = base._path.slice();\n this._query = base._query;\n this._fragment = '#';\n this._username = base._username;\n this._password = base._password;\n state = 'fragment';\n } else {\n var nextC = input[cursor + 1];\n var nextNextC = input[cursor + 2];\n if (this._scheme !== 'file' || !ALPHA.test(c) ||\n (nextC !== ':' && nextC !== '|') ||\n (nextNextC !== EOF && nextNextC !== '/' && nextNextC !== '\\\\' &&\n nextNextC !== '?' && nextNextC !== '#')) {\n this._host = base._host;\n this._port = base._port;\n this._username = base._username;\n this._password = base._password;\n this._path = base._path.slice();\n this._path.pop();\n }\n state = 'relative path';\n continue;\n }\n break;\n\n case 'relative slash':\n if (c === '/' || c === '\\\\') {\n if (c === '\\\\') {\n err('\\\\ is an invalid code point.');\n }\n if (this._scheme === 'file') {\n state = 'file host';\n } else {\n state = 'authority ignore slashes';\n }\n } else {\n if (this._scheme !== 'file') {\n this._host = base._host;\n this._port = base._port;\n this._username = base._username;\n this._password = base._password;\n }\n state = 'relative path';\n continue;\n }\n break;\n\n case 'authority first slash':\n if (c === '/') {\n state = 'authority second slash';\n } else {\n err('Expected \\'/\\', got: ' + c);\n state = 'authority ignore slashes';\n continue;\n }\n break;\n\n case 'authority second slash':\n state = 'authority ignore slashes';\n if (c !== '/') {\n err('Expected \\'/\\', got: ' + c);\n continue;\n }\n break;\n\n case 'authority ignore slashes':\n if (c !== '/' && c !== '\\\\') {\n state = 'authority';\n continue;\n } else {\n err('Expected authority, got: ' + c);\n }\n break;\n\n case 'authority':\n if (c === '@') {\n if (seenAt) {\n err('@ already seen.');\n buffer += '%40';\n }\n seenAt = true;\n for (var i = 0; i < buffer.length; i++) {\n var cp = buffer[i];\n if (cp === '\\t' || cp === '\\n' || cp === '\\r') {\n err('Invalid whitespace in authority.');\n continue;\n }\n // XXX check URL code points\n if (cp === ':' && this._password === null) {\n this._password = '';\n continue;\n }\n var tempC = percentEscape(cp);\n if (this._password !== null) {\n this._password += tempC;\n } else {\n this._username += tempC;\n }\n }\n buffer = '';\n } else if (c === EOF || c === '/' || c === '\\\\' ||\n c === '?' || c === '#') {\n cursor -= buffer.length;\n buffer = '';\n state = 'host';\n continue;\n } else {\n buffer += c;\n }\n break;\n\n case 'file host':\n if (c === EOF || c === '/' || c === '\\\\' || c === '?' || c === '#') {\n if (buffer.length === 2 && ALPHA.test(buffer[0]) &&\n (buffer[1] === ':' || buffer[1] === '|')) {\n state = 'relative path';\n } else if (buffer.length === 0) {\n state = 'relative path start';\n } else {\n this._host = IDNAToASCII.call(this, buffer);\n buffer = '';\n state = 'relative path start';\n }\n continue;\n } else if (c === '\\t' || c === '\\n' || c === '\\r') {\n err('Invalid whitespace in file host.');\n } else {\n buffer += c;\n }\n break;\n\n case 'host':\n case 'hostname':\n if (c === ':' && !seenBracket) {\n // XXX host parsing\n this._host = IDNAToASCII.call(this, buffer);\n buffer = '';\n state = 'port';\n if (stateOverride === 'hostname') {\n break loop;\n }\n } else if (c === EOF || c === '/' ||\n c === '\\\\' || c === '?' || c === '#') {\n this._host = IDNAToASCII.call(this, buffer);\n buffer = '';\n state = 'relative path start';\n if (stateOverride) {\n break loop;\n }\n continue;\n } else if (c !== '\\t' && c !== '\\n' && c !== '\\r') {\n if (c === '[') {\n seenBracket = true;\n } else if (c === ']') {\n seenBracket = false;\n }\n buffer += c;\n } else {\n err('Invalid code point in host/hostname: ' + c);\n }\n break;\n\n case 'port':\n if (/[0-9]/.test(c)) {\n buffer += c;\n } else if (c === EOF || c === '/' || c === '\\\\' ||\n c === '?' || c === '#' || stateOverride) {\n if (buffer !== '') {\n var temp = parseInt(buffer, 10);\n if (temp !== relative[this._scheme]) {\n this._port = temp + '';\n }\n buffer = '';\n }\n if (stateOverride) {\n break loop;\n }\n state = 'relative path start';\n continue;\n } else if (c === '\\t' || c === '\\n' || c === '\\r') {\n err('Invalid code point in port: ' + c);\n } else {\n invalid.call(this);\n }\n break;\n\n case 'relative path start':\n if (c === '\\\\') {\n err('\\'\\\\\\' not allowed in path.');\n }\n state = 'relative path';\n if (c !== '/' && c !== '\\\\') {\n continue;\n }\n break;\n\n case 'relative path':\n if (c === EOF || c === '/' || c === '\\\\' ||\n (!stateOverride && (c === '?' || c === '#'))) {\n if (c === '\\\\') {\n err('\\\\ not allowed in relative path.');\n }\n var tmp;\n if ((tmp = relativePathDotMapping[buffer.toLowerCase()])) {\n buffer = tmp;\n }\n if (buffer === '..') {\n this._path.pop();\n if (c !== '/' && c !== '\\\\') {\n this._path.push('');\n }\n } else if (buffer === '.' && c !== '/' && c !== '\\\\') {\n this._path.push('');\n } else if (buffer !== '.') {\n if (this._scheme === 'file' && this._path.length === 0 &&\n buffer.length === 2 && ALPHA.test(buffer[0]) &&\n buffer[1] === '|') {\n buffer = buffer[0] + ':';\n }\n this._path.push(buffer);\n }\n buffer = '';\n if (c === '?') {\n this._query = '?';\n state = 'query';\n } else if (c === '#') {\n this._fragment = '#';\n state = 'fragment';\n }\n } else if (c !== '\\t' && c !== '\\n' && c !== '\\r') {\n buffer += percentEscape(c);\n }\n break;\n\n case 'query':\n if (!stateOverride && c === '#') {\n this._fragment = '#';\n state = 'fragment';\n } else if (c !== EOF && c !== '\\t' && c !== '\\n' && c !== '\\r') {\n this._query += percentEscapeQuery(c);\n }\n break;\n\n case 'fragment':\n if (c !== EOF && c !== '\\t' && c !== '\\n' && c !== '\\r') {\n this._fragment += c;\n }\n break;\n }\n\n cursor++;\n }\n }\n\n function clear() {\n this._scheme = '';\n this._schemeData = '';\n this._username = '';\n this._password = null;\n this._host = '';\n this._port = '';\n this._path = [];\n this._query = '';\n this._fragment = '';\n this._isInvalid = false;\n this._isRelative = false;\n }\n\n // Does not process domain names or IP addresses.\n // Does not handle encoding for the query parameter.\n function JURL(url, base /* , encoding */) {\n if (base !== undefined && !(base instanceof JURL)) {\n base = new JURL(String(base));\n }\n\n this._url = url;\n clear.call(this);\n\n var input = url.replace(/^[ \\t\\r\\n\\f]+|[ \\t\\r\\n\\f]+$/g, '');\n // encoding = encoding || 'utf-8'\n\n parse.call(this, input, null, base);\n }\n\n JURL.prototype = {\n toString() {\n return this.href;\n },\n get href() {\n if (this._isInvalid) {\n return this._url;\n }\n var authority = '';\n if (this._username !== '' || this._password !== null) {\n authority = this._username +\n (this._password !== null ? ':' + this._password : '') + '@';\n }\n\n return this.protocol +\n (this._isRelative ? '//' + authority + this.host : '') +\n this.pathname + this._query + this._fragment;\n },\n // The named parameter should be different from the setter's function name.\n // Otherwise Safari 5 will throw an error (see issue 8541)\n set href(value) {\n clear.call(this);\n parse.call(this, value);\n },\n\n get protocol() {\n return this._scheme + ':';\n },\n set protocol(value) {\n if (this._isInvalid) {\n return;\n }\n parse.call(this, value + ':', 'scheme start');\n },\n\n get host() {\n return this._isInvalid ? '' : this._port ?\n this._host + ':' + this._port : this._host;\n },\n set host(value) {\n if (this._isInvalid || !this._isRelative) {\n return;\n }\n parse.call(this, value, 'host');\n },\n\n get hostname() {\n return this._host;\n },\n set hostname(value) {\n if (this._isInvalid || !this._isRelative) {\n return;\n }\n parse.call(this, value, 'hostname');\n },\n\n get port() {\n return this._port;\n },\n set port(value) {\n if (this._isInvalid || !this._isRelative) {\n return;\n }\n parse.call(this, value, 'port');\n },\n\n get pathname() {\n return this._isInvalid ? '' : this._isRelative ?\n '/' + this._path.join('/') : this._schemeData;\n },\n set pathname(value) {\n if (this._isInvalid || !this._isRelative) {\n return;\n }\n this._path = [];\n parse.call(this, value, 'relative path start');\n },\n\n get search() {\n return this._isInvalid || !this._query || this._query === '?' ?\n '' : this._query;\n },\n set search(value) {\n if (this._isInvalid || !this._isRelative) {\n return;\n }\n this._query = '?';\n if (value[0] === '?') {\n value = value.slice(1);\n }\n parse.call(this, value, 'query');\n },\n\n get hash() {\n return this._isInvalid || !this._fragment || this._fragment === '#' ?\n '' : this._fragment;\n },\n set hash(value) {\n if (this._isInvalid) {\n return;\n }\n this._fragment = '#';\n if (value[0] === '#') {\n value = value.slice(1);\n }\n parse.call(this, value, 'fragment');\n },\n\n get origin() {\n var host;\n if (this._isInvalid || !this._scheme) {\n return '';\n }\n // javascript: Gecko returns String(\"\"), WebKit/Blink String(\"null\")\n // Gecko throws error for \"data://\"\n // data: Gecko returns \"\", Blink returns \"data://\", WebKit returns \"null\"\n // Gecko returns String(\"\") for file: mailto:\n // WebKit/Blink returns String(\"SCHEME://\") for file: mailto:\n switch (this._scheme) {\n case 'data':\n case 'file':\n case 'javascript':\n case 'mailto':\n return 'null';\n case 'blob':\n // Special case of blob: -- returns valid origin of _schemeData.\n try {\n return new JURL(this._schemeData).origin || 'null';\n } catch (_) {\n // Invalid _schemeData origin -- ignoring errors.\n }\n return 'null';\n }\n host = this.host;\n if (!host) {\n return '';\n }\n return this._scheme + '://' + host;\n },\n };\n\n // Copy over the static methods\n var OriginalURL = globalScope.URL;\n if (OriginalURL) {\n JURL.createObjectURL = function(blob) {\n // IE extension allows a second optional options argument.\n // http://msdn.microsoft.com/en-us/library/ie/hh772302(v=vs.85).aspx\n return OriginalURL.createObjectURL.apply(OriginalURL, arguments);\n };\n JURL.revokeObjectURL = function(url) {\n OriginalURL.revokeObjectURL(url);\n };\n }\n\n globalScope.URL = JURL;\n})();\n\n}\n\n\n\n// WEBPACK FOOTER //\n// src/shared/compatibility.js","/* Copyright 2017 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nlet isReadableStreamSupported = false;\nif (typeof ReadableStream !== 'undefined') {\n // MS Edge may say it has ReadableStream but they are not up to spec yet.\n try {\n // eslint-disable-next-line no-new\n new ReadableStream({\n start(controller) {\n controller.close();\n },\n });\n isReadableStreamSupported = true;\n } catch (e) {\n // The ReadableStream constructor cannot be used.\n }\n}\nif (isReadableStreamSupported) {\n exports.ReadableStream = ReadableStream;\n} else {\n if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('CHROME')) {\n throw new Error('ReadableStream polyfill is not found for Chrome bundle');\n }\n exports.ReadableStream =\n require('../../external/streams/streams-lib').ReadableStream;\n}\n\n\n\n// WEBPACK FOOTER //\n// src/shared/streams_polyfill.js"],"sourceRoot":""} \ No newline at end of file diff --git a/twake/frontend/public/public/viewer/PDFViewer/viewer.css b/twake/frontend/public/public/viewer/PDFViewer/viewer.css new file mode 100755 index 00000000..8613ff46 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/viewer.css @@ -0,0 +1,2368 @@ +/* Copyright 2014 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. + */ + +.textLayer { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + overflow: hidden; + opacity: 0.2; + line-height: 1.0; +} + +.textLayer > div { + color: transparent; + position: absolute; + white-space: pre; + cursor: text; + -webkit-transform-origin: 0% 0%; + -moz-transform-origin: 0% 0%; + -o-transform-origin: 0% 0%; + -ms-transform-origin: 0% 0%; + transform-origin: 0% 0%; +} + +.textLayer .highlight { + margin: -1px; + padding: 1px; + + background-color: rgb(180, 0, 170); + border-radius: 4px; +} + +.textLayer .highlight.begin { + border-radius: 4px 0px 0px 4px; +} + +.textLayer .highlight.end { + border-radius: 0px 4px 4px 0px; +} + +.textLayer .highlight.middle { + border-radius: 0px; +} + +.textLayer .highlight.selected { + background-color: rgb(0, 100, 0); +} + +.textLayer ::selection { + background: rgb(0, 0, 255); +} + +.textLayer ::-moz-selection { + background: rgb(0, 0, 255); +} + +.textLayer .endOfContent { + display: block; + position: absolute; + left: 0px; + top: 100%; + right: 0px; + bottom: 0px; + z-index: -1; + cursor: default; + -webkit-user-select: none; + -ms-user-select: none; + -moz-user-select: none; +} + +.textLayer .endOfContent.active { + top: 0px; +} + +.annotationLayer section { + position: absolute; +} + +.annotationLayer .linkAnnotation > a { + position: absolute; + font-size: 1em; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.annotationLayer .linkAnnotation > a /* -ms-a */ +{ + background: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7") 0 0 repeat; +} + +.annotationLayer .linkAnnotation > a:hover { + opacity: 0.2; + background: #ff0; + box-shadow: 0px 2px 10px #ff0; +} + +.annotationLayer .textAnnotation img { + position: absolute; + cursor: pointer; +} + +.annotationLayer .textWidgetAnnotation input, +.annotationLayer .textWidgetAnnotation textarea, +.annotationLayer .choiceWidgetAnnotation select, +.annotationLayer .buttonWidgetAnnotation.checkBox input, +.annotationLayer .buttonWidgetAnnotation.radioButton input { + background-color: rgba(0, 54, 255, 0.13); + border: 1px solid transparent; + box-sizing: border-box; + font-size: 9px; + height: 100%; + padding: 0 3px; + vertical-align: top; + width: 100%; +} + +.annotationLayer .textWidgetAnnotation textarea { + font: message-box; + font-size: 9px; + resize: none; +} + +.annotationLayer .textWidgetAnnotation input[disabled], +.annotationLayer .textWidgetAnnotation textarea[disabled], +.annotationLayer .choiceWidgetAnnotation select[disabled], +.annotationLayer .buttonWidgetAnnotation.checkBox input[disabled], +.annotationLayer .buttonWidgetAnnotation.radioButton input[disabled] { + background: none; + border: 1px solid transparent; + cursor: not-allowed; +} + +.annotationLayer .textWidgetAnnotation input:hover, +.annotationLayer .textWidgetAnnotation textarea:hover, +.annotationLayer .choiceWidgetAnnotation select:hover, +.annotationLayer .buttonWidgetAnnotation.checkBox input:hover, +.annotationLayer .buttonWidgetAnnotation.radioButton input:hover { + border: 1px solid #000; +} + +.annotationLayer .textWidgetAnnotation input:focus, +.annotationLayer .textWidgetAnnotation textarea:focus, +.annotationLayer .choiceWidgetAnnotation select:focus { + background: none; + border: 1px solid transparent; +} + +.annotationLayer .textWidgetAnnotation input.comb { + font-family: monospace; + padding-left: 2px; + padding-right: 0; +} + +.annotationLayer .textWidgetAnnotation input.comb:focus { + /* + * Letter spacing is placed on the right side of each character. Hence, the + * letter spacing of the last character may be placed outside the visible + * 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%; +} + +.annotationLayer .buttonWidgetAnnotation.checkBox input, +.annotationLayer .buttonWidgetAnnotation.radioButton input { + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; +} + +.annotationLayer .popupWrapper { + position: absolute; + width: 20em; +} + +.annotationLayer .popup { + position: absolute; + z-index: 200; + max-width: 20em; + background-color: #FFFF99; + box-shadow: 0px 2px 5px #333; + border-radius: 2px; + padding: 0.6em; + margin-left: 5px; + cursor: pointer; + word-wrap: break-word; +} + +.annotationLayer .popup h1 { + font-size: 1em; + border-bottom: 1px solid #000000; + padding-bottom: 0.2em; +} + +.annotationLayer .popup p { + padding-top: 0.2em; +} + +.annotationLayer .highlightAnnotation, +.annotationLayer .underlineAnnotation, +.annotationLayer .squigglyAnnotation, +.annotationLayer .strikeoutAnnotation, +.annotationLayer .lineAnnotation svg line, +.annotationLayer .fileAttachmentAnnotation { + cursor: pointer; +} + +.pdfViewer .canvasWrapper { + overflow: hidden; +} + +.pdfViewer .page { + direction: ltr; + width: 816px; + height: 1056px; + margin: 1px auto -8px auto; + position: relative; + overflow: visible; + border: 9px solid transparent; + background-clip: content-box; + border-image: url(images/shadow.png) 9 9 repeat; + background-color: white; +} + +.pdfViewer.removePageBorders .page { + margin: 0px auto 10px auto; + border: none; +} + +.pdfViewer.singlePageView { + display: inline-block; +} + +.pdfViewer.singlePageView .page { + margin: 0; + border: none; +} + +.pdfViewer .page canvas { + margin: 0; + display: block; +} + +.pdfViewer .page canvas[hidden] { + display: none; +} + +.pdfViewer .page .loadingIcon { + position: absolute; + display: block; + left: 0; + top: 0; + right: 0; + bottom: 0; + background: url('images/loading-icon.gif') center no-repeat; +} + +.pdfPresentationMode:-webkit-full-screen .pdfViewer .page { + margin-bottom: 100%; + border: 0; +} + +.pdfPresentationMode:-moz-full-screen .pdfViewer .page { + margin-bottom: 100%; + border: 0; +} + +.pdfPresentationMode:-ms-fullscreen .pdfViewer .page { + margin-bottom: 100% !important; + border: 0; +} + +.pdfPresentationMode:fullscreen .pdfViewer .page { + margin-bottom: 100%; + border: 0; +} + +* { + padding: 0; + margin: 0; +} + +html { + height: 100%; + width: 100%; + /* Font size is needed to make the activity bar the correct size. */ + font-size: 10px; +} + +body { + height: 100%; + width: 100%; + background-color: #20282f; +} + +body, +input, +button, +select { + font: message-box; + outline: none; +} + +.hidden { + display: none !important; +} + +[hidden] { + display: none !important; +} + +#viewerContainer.pdfPresentationMode:-webkit-full-screen { + top: 0px; + border-top: 2px solid transparent; + background-color: #000; + width: 100%; + height: 100%; + overflow: hidden; + cursor: none; + -webkit-user-select: none; +} + +#viewerContainer.pdfPresentationMode:-moz-full-screen { + top: 0px; + border-top: 2px solid transparent; + background-color: #000; + width: 100%; + height: 100%; + overflow: hidden; + cursor: none; + -moz-user-select: none; +} + +#viewerContainer.pdfPresentationMode:-ms-fullscreen { + top: 0px !important; + border-top: 2px solid transparent; + width: 100%; + height: 100%; + overflow: hidden !important; + cursor: none; + -ms-user-select: none; +} + +#viewerContainer.pdfPresentationMode:-ms-fullscreen::-ms-backdrop { + background-color: #000; +} + +#viewerContainer.pdfPresentationMode:fullscreen { + top: 0px; + border-top: 2px solid transparent; + background-color: #000; + width: 100%; + height: 100%; + overflow: hidden; + cursor: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} + +.pdfPresentationMode:-webkit-full-screen a:not(.internalLink) { + display: none; +} + +.pdfPresentationMode:-moz-full-screen a:not(.internalLink) { + display: none; +} + +.pdfPresentationMode:-ms-fullscreen a:not(.internalLink) { + display: none !important; +} + +.pdfPresentationMode:fullscreen a:not(.internalLink) { + display: none; +} + +.pdfPresentationMode:-webkit-full-screen .textLayer > div { + cursor: none; +} + +.pdfPresentationMode:-moz-full-screen .textLayer > div { + cursor: none; +} + +.pdfPresentationMode:-ms-fullscreen .textLayer > div { + cursor: none; +} + +.pdfPresentationMode:fullscreen .textLayer > div { + cursor: none; +} + +.pdfPresentationMode.pdfPresentationModeControls > *, +.pdfPresentationMode.pdfPresentationModeControls .textLayer > div { + cursor: default; +} + +#outerContainer { + width: 100%; + height: 100%; + position: relative; +} + +#sidebarContainer { + position: absolute; + top: 0; + bottom: 0; + width: 200px; + visibility: hidden; + -webkit-transition-duration: 200ms; + -webkit-transition-timing-function: ease; + transition-duration: 200ms; + transition-timing-function: ease; + +} + +html[dir='ltr'] #sidebarContainer { + -webkit-transition-property: left; + transition-property: left; + left: -200px; +} + +html[dir='rtl'] #sidebarContainer { + -webkit-transition-property: right; + transition-property: right; + right: -200px; +} + +#outerContainer.sidebarMoving > #sidebarContainer, +#outerContainer.sidebarOpen > #sidebarContainer { + visibility: visible; +} + +html[dir='ltr'] #outerContainer.sidebarOpen > #sidebarContainer { + left: 0px; +} + +html[dir='rtl'] #outerContainer.sidebarOpen > #sidebarContainer { + right: 0px; +} + +#mainContainer { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + min-width: 320px; + -webkit-transition-duration: 200ms; + -webkit-transition-timing-function: ease; + transition-duration: 200ms; + transition-timing-function: ease; +} + +html[dir='ltr'] #outerContainer.sidebarOpen > #mainContainer { + -webkit-transition-property: left; + transition-property: left; + left: 200px; +} + +html[dir='rtl'] #outerContainer.sidebarOpen > #mainContainer { + -webkit-transition-property: right; + transition-property: right; + right: 200px; +} + +#sidebarContent { + top: 32px; + bottom: 0; + overflow-y: auto; + overflow-x: hidden; + -webkit-overflow-scrolling: touch; + -webkit-overflow-scrolling: touch; + position: absolute; + width: 200px; + background-color: hsla(0, 0%, 0%, .1); +} + +html[dir='ltr'] #sidebarContent { + left: 0; + box-shadow: inset -1px 0 0 hsla(0, 0%, 0%, .25); +} + +html[dir='rtl'] #sidebarContent { + right: 0; + box-shadow: inset 1px 0 0 hsla(0, 0%, 0%, .25); +} + +#viewerContainer { + overflow-y: auto; + overflow-x: hidden; + -webkit-overflow-scrolling: touch; + -webkit-overflow-scrolling: touch; + position: absolute; + top: 32px; + right: 0; + bottom: 0; + left: 0; + outline: none; +} + +html[dir='ltr'] #viewerContainer { + box-shadow: inset 1px 0 0 hsla(0, 0%, 100%, .05); +} + +html[dir='rtl'] #viewerContainer { + box-shadow: inset -1px 0 0 hsla(0, 0%, 100%, .05); +} + +.toolbar { + position: relative; + left: 0; + right: 0; + z-index: 9999; + cursor: default; +} + +#toolbarContainer { + width: 100%; +} + +#toolbarSidebar { + width: 200px; + height: 32px; + background-color: #3b4b58; /* fallback */ +} + +html[dir='ltr'] #toolbarSidebar { +} + +html[dir='rtl'] #toolbarSidebar { +} + +#toolbarContainer, .findbar, .secondaryToolbar { + position: relative; + height: 32px; + background-color: #3b4b58; /* fallback */ +} + +html[dir='ltr'] #toolbarContainer, .findbar, .secondaryToolbar { +} + +html[dir='rtl'] #toolbarContainer, .findbar, .secondaryToolbar { +} + +#toolbarViewer { + height: 32px; +} + +#loadingBar { + position: relative; + width: 100%; + height: 4px; + background-color: #333; + border-bottom: 1px solid #333; +} + +#loadingBar .progress { + position: absolute; + top: 0; + left: 0; + width: 0%; + height: 100%; + background-color: #ddd; + overflow: hidden; + -webkit-transition: width 200ms; + transition: width 200ms; +} + +@-webkit-keyframes progressIndeterminate { + 0% { + left: -142px; + } + 100% { + left: 0; + } +} + +@keyframes progressIndeterminate { + 0% { + left: -142px; + } + 100% { + left: 0; + } +} + +#loadingBar .progress.indeterminate { + background-color: #999; + -webkit-transition: none; + transition: none; +} + +#loadingBar .progress.indeterminate .glimmer { + position: absolute; + top: 0; + left: 0; + height: 100%; + width: calc(100% + 150px); + + background: repeating-linear-gradient(135deg, + #bbb 0, #999 5px, + #999 45px, #ddd 55px, + #ddd 95px, #bbb 100px); + + -webkit-animation: progressIndeterminate 950ms linear infinite; + animation: progressIndeterminate 950ms linear infinite; +} + +.findbar, .secondaryToolbar { + top: 32px; + position: absolute; + z-index: 10000; + height: auto; + min-width: 16px; + padding: 0px 6px 0px 6px; + margin: 4px 2px 4px 2px; + color: hsl(0, 0%, 85%); + font-size: 12px; + line-height: 14px; + text-align: left; + cursor: default; +} + +.findbar { + min-width: 300px; +} + +.findbar > div { + height: 32px; +} + +.findbar.wrapContainers > div { + clear: both; +} + +.findbar.wrapContainers > div#findbarMessageContainer { + height: auto; +} + +html[dir='ltr'] .findbar { + left: 68px; +} + +html[dir='rtl'] .findbar { + right: 68px; +} + +.findbar label { + -webkit-user-select: none; + -moz-user-select: none; +} + +#findInput { + width: 200px; +} + +#findInput::-webkit-input-placeholder { + font-style: italic; +} + +#findInput::-moz-placeholder { + font-style: italic; +} + +#findInput:-ms-input-placeholder { + font-style: italic; +} + +#findInput::placeholder { + font-style: italic; +} + +#findInput[data-status="pending"] { + background-image: url(images/loading-small.png); + background-repeat: no-repeat; + background-position: right; +} + +html[dir='rtl'] #findInput[data-status="pending"] { + background-position: left; +} + +.secondaryToolbar { + padding: 6px; + height: auto; + z-index: 30000; +} + +html[dir='ltr'] .secondaryToolbar { + right: 4px; +} + +html[dir='rtl'] .secondaryToolbar { + left: 4px; +} + +#secondaryToolbarButtonContainer { + max-width: 200px; + max-height: 400px; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + margin-bottom: -4px; +} + +.doorHanger, +.doorHangerRight { + border: 1px solid hsla(0, 0%, 0%, .5); + border-radius: 2px; + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); +} + +.doorHanger:after, .doorHanger:before, +.doorHangerRight:after, .doorHangerRight:before { + bottom: 100%; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; +} + +.doorHanger:after, +.doorHangerRight:after { + border-bottom-color: hsla(0, 0%, 32%, .99); + border-width: 8px; +} + +.doorHanger:before, +.doorHangerRight:before { + border-bottom-color: hsla(0, 0%, 0%, .5); + border-width: 9px; +} + +html[dir='ltr'] .doorHanger:after, +html[dir='rtl'] .doorHangerRight:after { + left: 13px; + margin-left: -8px; +} + +html[dir='ltr'] .doorHanger:before, +html[dir='rtl'] .doorHangerRight:before { + left: 13px; + margin-left: -9px; +} + +html[dir='rtl'] .doorHanger:after, +html[dir='ltr'] .doorHangerRight:after { + right: 13px; + margin-right: -8px; +} + +html[dir='rtl'] .doorHanger:before, +html[dir='ltr'] .doorHangerRight:before { + right: 13px; + margin-right: -9px; +} + +#findResultsCount { + background-color: hsl(0, 0%, 85%); + color: hsl(0, 0%, 32%); + text-align: center; + padding: 3px 4px; +} + +#findMsg { + font-style: italic; + color: #A6B7D0; +} + +#findMsg:empty { + display: none; +} + +#findInput.notFound { + background-color: rgb(255, 102, 102); +} + +#toolbarViewerMiddle { + position: absolute; + left: 50%; + transform: translateX(-50%); +} + +html[dir='ltr'] #toolbarViewerLeft, +html[dir='rtl'] #toolbarViewerRight { + 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; + float: right; +} + +html[dir='ltr'] .splitToolbarButton { + margin: 3px 2px 4px 0; + display: inline-block; +} + +html[dir='rtl'] .splitToolbarButton { + margin: 3px 0 4px 2px; + display: inline-block; +} + +html[dir='ltr'] .splitToolbarButton > .toolbarButton { + border-radius: 0; + float: left; +} + +html[dir='rtl'] .splitToolbarButton > .toolbarButton { + border-radius: 0; + float: right; +} + +.toolbarButton, +.secondaryToolbarButton, +.overlayButton { + border: 0 none; + background: none; + width: 32px; + height: 25px; +} + +.toolbarButton > span { + display: inline-block; + width: 0; + height: 0; + overflow: hidden; +} + +.toolbarButton[disabled], +.secondaryToolbarButton[disabled], +.overlayButton[disabled] { + opacity: .5; +} + +.splitToolbarButton.toggled .toolbarButton { + margin: 0; +} + +.splitToolbarButton:hover > .toolbarButton, +.splitToolbarButton:focus > .toolbarButton, +.splitToolbarButton.toggled > .toolbarButton, +.toolbarButton.textButton { + background-color: hsla(0, 0%, 0%, .12); + background-image: linear-gradient(hsla(0, 0%, 100%, .05), hsla(0, 0%, 100%, 0)); + background-clip: padding-box; + border: 1px solid hsla(0, 0%, 0%, .35); + border-color: hsla(0, 0%, 0%, .32) hsla(0, 0%, 0%, .38) hsla(0, 0%, 0%, .42); + box-shadow: 0 1px 0 hsla(0, 0%, 100%, .05) inset, + 0 0 1px hsla(0, 0%, 100%, .15) inset, + 0 1px 0 hsla(0, 0%, 100%, .05); + -webkit-transition-property: background-color, border-color, box-shadow; + -webkit-transition-duration: 150ms; + -webkit-transition-timing-function: ease; + transition-property: background-color, border-color, box-shadow; + transition-duration: 150ms; + transition-timing-function: ease; + +} + +.splitToolbarButton > .toolbarButton:hover, +.splitToolbarButton > .toolbarButton:focus, +.dropdownToolbarButton:hover, +.overlayButton:hover, +.overlayButton:focus, +.toolbarButton.textButton:hover, +.toolbarButton.textButton:focus { + background-color: hsla(0, 0%, 0%, .2); + box-shadow: 0 1px 0 hsla(0, 0%, 100%, .05) inset, + 0 0 1px hsla(0, 0%, 100%, .15) inset, + 0 0 1px hsla(0, 0%, 0%, .05); + z-index: 199; +} + +.splitToolbarButton > .toolbarButton { + position: relative; +} + +html[dir='ltr'] .splitToolbarButton > .toolbarButton:first-child, +html[dir='rtl'] .splitToolbarButton > .toolbarButton:last-child { + position: relative; + margin: 0; + margin-right: -1px; + border-top-left-radius: 2px; + border-bottom-left-radius: 2px; + border-right-color: transparent; +} + +html[dir='ltr'] .splitToolbarButton > .toolbarButton:last-child, +html[dir='rtl'] .splitToolbarButton > .toolbarButton:first-child { + position: relative; + margin: 0; + margin-left: -1px; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-left-color: transparent; +} + +.splitToolbarButtonSeparator { + padding: 8px 0; + width: 1px; + background-color: hsla(0, 0%, 0%, .5); + z-index: 99; + box-shadow: 0 0 0 1px hsla(0, 0%, 100%, .08); + display: inline-block; + margin: 5px 0; +} + +html[dir='ltr'] .splitToolbarButtonSeparator { + float: left; +} + +html[dir='rtl'] .splitToolbarButtonSeparator { + float: right; +} + +.splitToolbarButton:hover > .splitToolbarButtonSeparator, +.splitToolbarButton.toggled > .splitToolbarButtonSeparator { + padding: 12px 0; + margin: 1px 0; + box-shadow: 0 0 0 1px hsla(0, 0%, 100%, .03); + -webkit-transition-property: padding; + -webkit-transition-duration: 10ms; + -webkit-transition-timing-function: ease; + transition-property: padding; + transition-duration: 10ms; + transition-timing-function: ease; +} + +.toolbarButton, +.dropdownToolbarButton, +.secondaryToolbarButton, +.overlayButton { + min-width: 16px; + padding: 2px 6px 0; + border: 1px solid transparent; + border-radius: 2px; + color: hsla(0, 0%, 100%, .8); + font-size: 12px; + line-height: 14px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + /* Opera does not support user-select, use <... unselectable="on"> instead */ + cursor: default; + -webkit-transition-property: background-color, border-color, box-shadow; + -webkit-transition-duration: 150ms; + -webkit-transition-timing-function: ease; + transition-property: background-color, border-color, box-shadow; + transition-duration: 150ms; + transition-timing-function: ease; +} + +html[dir='ltr'] .toolbarButton, +html[dir='ltr'] .overlayButton, +html[dir='ltr'] .dropdownToolbarButton { + margin: 3px 2px 4px 0; +} + +html[dir='rtl'] .toolbarButton, +html[dir='rtl'] .overlayButton, +html[dir='rtl'] .dropdownToolbarButton { + margin: 3px 0 4px 2px; +} + +.toolbarButton:hover, +.toolbarButton:focus, +.dropdownToolbarButton, +.overlayButton, +.secondaryToolbarButton:hover, +.secondaryToolbarButton:focus { + background-color: hsla(0, 0%, 0%, .12); + background-image: linear-gradient(hsla(0, 0%, 100%, .05), hsla(0, 0%, 100%, 0)); + background-clip: padding-box; + border: 1px solid hsla(0, 0%, 0%, .35); + border-color: hsla(0, 0%, 0%, .32) hsla(0, 0%, 0%, .38) hsla(0, 0%, 0%, .42); + box-shadow: 0 1px 0 hsla(0, 0%, 100%, .05) inset, + 0 0 1px hsla(0, 0%, 100%, .15) inset, + 0 1px 0 hsla(0, 0%, 100%, .05); +} + +.toolbarButton:hover:active, +.overlayButton:hover:active, +.dropdownToolbarButton:hover:active, +.secondaryToolbarButton:hover:active { + background-color: hsla(0, 0%, 0%, .2); + background-image: linear-gradient(hsla(0, 0%, 100%, .05), hsla(0, 0%, 100%, 0)); + border-color: hsla(0, 0%, 0%, .35) hsla(0, 0%, 0%, .4) hsla(0, 0%, 0%, .45); + box-shadow: 0 1px 1px hsla(0, 0%, 0%, .1) inset, + 0 0 1px hsla(0, 0%, 0%, .2) inset, + 0 1px 0 hsla(0, 0%, 100%, .05); + -webkit-transition-property: background-color, border-color, box-shadow; + -webkit-transition-duration: 10ms; + -webkit-transition-timing-function: linear; + transition-property: background-color, border-color, box-shadow; + transition-duration: 10ms; + transition-timing-function: linear; +} + +.toolbarButton.toggled, +.splitToolbarButton.toggled > .toolbarButton.toggled, +.secondaryToolbarButton.toggled { + background-color: hsla(0, 0%, 0%, .3); + background-image: linear-gradient(hsla(0, 0%, 100%, .05), hsla(0, 0%, 100%, 0)); + border-color: hsla(0, 0%, 0%, .4) hsla(0, 0%, 0%, .45) hsla(0, 0%, 0%, .5); + box-shadow: 0 1px 1px hsla(0, 0%, 0%, .1) inset, + 0 0 1px hsla(0, 0%, 0%, .2) inset, + 0 1px 0 hsla(0, 0%, 100%, .05); + -webkit-transition-property: background-color, border-color, box-shadow; + -webkit-transition-duration: 10ms; + -webkit-transition-timing-function: linear; + transition-property: background-color, border-color, box-shadow; + transition-duration: 10ms; + transition-timing-function: linear; +} + +.toolbarButton.toggled:hover:active, +.splitToolbarButton.toggled > .toolbarButton.toggled:hover:active, +.secondaryToolbarButton.toggled:hover:active { + background-color: hsla(0, 0%, 0%, .4); + border-color: hsla(0, 0%, 0%, .4) hsla(0, 0%, 0%, .5) hsla(0, 0%, 0%, .55); + box-shadow: 0 1px 1px hsla(0, 0%, 0%, .2) inset, + 0 0 1px hsla(0, 0%, 0%, .3) inset, + 0 1px 0 hsla(0, 0%, 100%, .05); +} + +.dropdownToolbarButton { + width: 120px; + max-width: 120px; + padding: 0; + overflow: hidden; + background: url(images/toolbarButton-menuArrows.png) no-repeat; +} + +html[dir='ltr'] .dropdownToolbarButton { + background-position: 95%; +} + +html[dir='rtl'] .dropdownToolbarButton { + background-position: 5%; +} + +.dropdownToolbarButton > select { + min-width: 140px; + font-size: 12px; + color: hsl(0, 0%, 95%); + margin: 0; + padding: 3px 2px 2px; + border: none; + background: rgba(0, 0, 0, 0); /* Opera does not support 'transparent' +
+ +
+ +
+ + +
+ + + + + +
+ +
+ +
+ + + + +
+
+
+
+ +
+ + +
+ +
+ +
+ + +
+
+ + + + + + + + + +
+ + +
+
+
+ +
+ +
+ + + +
+
+
+
+
+
+
+
+
+
+ + + + + + + + +
+
+
+ + + + + + + +
+
Loading...
+ + + + diff --git a/twake/frontend/public/public/viewer/PDFViewer/viewer.js b/twake/frontend/public/public/viewer/PDFViewer/viewer.js new file mode 100755 index 00000000..fa5ca272 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/viewer.js @@ -0,0 +1,10936 @@ +/* Copyright 2017 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. + */ + +/******/ +(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; + /******/ + /******/ // identity function for calling harmony imports with the correct context + /******/ + __webpack_require__.i = function (value) { + return value; + }; + /******/ + /******/ // define getter function for harmony exports + /******/ + __webpack_require__.d = function (exports, name, getter) { + /******/ + if (!__webpack_require__.o(exports, name)) { + /******/ + Object.defineProperty(exports, name, { + /******/ configurable: false, + /******/ enumerable: true, + /******/ get: getter + /******/ + }); + /******/ + } + /******/ + }; + /******/ + /******/ // 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 = 33); + /******/ +}) +/************************************************************************/ +/******/([ + /* 0 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.localized = exports.animationStarted = exports.normalizeWheelEventDelta = exports.binarySearchFirstItem = exports.watchScroll = exports.scrollIntoView = exports.getOutputScale = exports.approximateFraction = exports.roundToDivide = exports.getVisibleElements = exports.parseQueryString = exports.noContextMenuHandler = exports.getPDFFileNameFromURL = exports.ProgressBar = exports.EventBus = exports.NullL10n = exports.mozL10n = exports.RendererType = exports.cloneObj = 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 = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _pdfjsLib = __webpack_require__(1); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var CSS_UNITS = 96.0 / 72.0; + var DEFAULT_SCALE_VALUE = 'auto'; + var DEFAULT_SCALE = 1.0; + var MIN_SCALE = 0.25; + var MAX_SCALE = 10.0; + var UNKNOWN_SCALE = 0; + var MAX_AUTO_SCALE = 1.25; + var SCROLLBAR_PADDING = 40; + var VERTICAL_PADDING = 5; + var RendererType = { + CANVAS: 'canvas', + SVG: 'svg' + }; + + function formatL10nValue(text, args) { + if (!args) { + return text; + } + return text.replace(/\{\{\s*(\w+)\s*\}\}/g, function (all, name) { + return name in args ? args[name] : '{{' + name + '}}'; + }); + } + + var NullL10n = { + get: function get(property, args, fallback) { + return Promise.resolve(formatL10nValue(fallback, args)); + }, + translate: function translate(element) { + return Promise.resolve(); + } + }; + _pdfjsLib.PDFJS.disableFullscreen = _pdfjsLib.PDFJS.disableFullscreen === undefined ? false : _pdfjsLib.PDFJS.disableFullscreen; + _pdfjsLib.PDFJS.useOnlyCssZoom = _pdfjsLib.PDFJS.useOnlyCssZoom === undefined ? false : _pdfjsLib.PDFJS.useOnlyCssZoom; + _pdfjsLib.PDFJS.maxCanvasPixels = _pdfjsLib.PDFJS.maxCanvasPixels === undefined ? 16777216 : _pdfjsLib.PDFJS.maxCanvasPixels; + _pdfjsLib.PDFJS.disableHistory = _pdfjsLib.PDFJS.disableHistory === undefined ? false : _pdfjsLib.PDFJS.disableHistory; + _pdfjsLib.PDFJS.disableTextLayer = _pdfjsLib.PDFJS.disableTextLayer === undefined ? false : _pdfjsLib.PDFJS.disableTextLayer; + _pdfjsLib.PDFJS.ignoreCurrentPositionOnZoom = _pdfjsLib.PDFJS.ignoreCurrentPositionOnZoom === undefined ? false : _pdfjsLib.PDFJS.ignoreCurrentPositionOnZoom; + { + _pdfjsLib.PDFJS.locale = _pdfjsLib.PDFJS.locale === undefined && typeof navigator !== 'undefined' ? navigator.language : _pdfjsLib.PDFJS.locale; + } + + function getOutputScale(ctx) { + var devicePixelRatio = window.devicePixelRatio || 1; + var backingStoreRatio = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1; + var pixelRatio = devicePixelRatio / backingStoreRatio; + return { + sx: pixelRatio, + sy: pixelRatio, + scaled: pixelRatio !== 1 + }; + } + + function scrollIntoView(element, spot) { + var skipOverflowHiddenElements = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + + var parent = element.offsetParent; + if (!parent) { + console.error('offsetParent is not set -- cannot scroll'); + return; + } + var offsetY = element.offsetTop + element.clientTop; + var offsetX = element.offsetLeft + element.clientLeft; + while (parent.clientHeight === parent.scrollHeight || skipOverflowHiddenElements && getComputedStyle(parent).overflow === 'hidden') { + if (parent.dataset._scaleY) { + offsetY /= parent.dataset._scaleY; + offsetX /= parent.dataset._scaleX; + } + offsetY += parent.offsetTop; + offsetX += parent.offsetLeft; + parent = parent.offsetParent; + if (!parent) { + return; + } + } + if (spot) { + if (spot.top !== undefined) { + offsetY += spot.top; + } + if (spot.left !== undefined) { + offsetX += spot.left; + parent.scrollLeft = offsetX; + } + } + parent.scrollTop = offsetY; + } + + function watchScroll(viewAreaElement, callback) { + var debounceScroll = function debounceScroll(evt) { + if (rAF) { + return; + } + rAF = window.requestAnimationFrame(function viewAreaElementScrolled() { + rAF = null; + var currentY = viewAreaElement.scrollTop; + var lastY = state.lastY; + if (currentY !== lastY) { + state.down = currentY > lastY; + } + state.lastY = currentY; + callback(state); + }); + }; + var state = { + down: true, + lastY: viewAreaElement.scrollTop, + _eventHandler: debounceScroll + }; + var rAF = null; + viewAreaElement.addEventListener('scroll', debounceScroll, true); + return state; + } + + function parseQueryString(query) { + var parts = query.split('&'); + var params = Object.create(null); + for (var i = 0, ii = parts.length; i < ii; ++i) { + var param = parts[i].split('='); + var key = param[0].toLowerCase(); + var value = param.length > 1 ? param[1] : null; + params[decodeURIComponent(key)] = decodeURIComponent(value); + } + return params; + } + + function binarySearchFirstItem(items, condition) { + var minIndex = 0; + var maxIndex = items.length - 1; + if (items.length === 0 || !condition(items[maxIndex])) { + return items.length; + } + if (condition(items[minIndex])) { + return minIndex; + } + while (minIndex < maxIndex) { + var currentIndex = minIndex + maxIndex >> 1; + var currentItem = items[currentIndex]; + if (condition(currentItem)) { + maxIndex = currentIndex; + } else { + minIndex = currentIndex + 1; + } + } + return minIndex; + } + + function approximateFraction(x) { + if (Math.floor(x) === x) { + return [x, 1]; + } + var xinv = 1 / x; + var limit = 8; + if (xinv > limit) { + return [1, limit]; + } else if (Math.floor(xinv) === xinv) { + return [1, xinv]; + } + var x_ = x > 1 ? xinv : x; + var a = 0, + b = 1, + c = 1, + d = 1; + while (true) { + var p = a + c, + q = b + d; + if (q > limit) { + break; + } + if (x_ <= p / q) { + c = p; + d = q; + } else { + a = p; + b = q; + } + } + var result = void 0; + if (x_ - a / b < c / d - x_) { + result = x_ === x ? [a, b] : [b, a]; + } else { + result = x_ === x ? [c, d] : [d, c]; + } + return result; + } + + function roundToDivide(x, div) { + var r = x % div; + return r === 0 ? x : Math.round(x - r + div); + } + + function getVisibleElements(scrollEl, views) { + var sortByVisibility = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + + var top = scrollEl.scrollTop, + bottom = top + scrollEl.clientHeight; + var left = scrollEl.scrollLeft, + right = left + scrollEl.clientWidth; + + function isElementBottomBelowViewTop(view) { + var element = view.div; + var elementBottom = element.offsetTop + element.clientTop + element.clientHeight; + return elementBottom > top; + } + + var visible = [], + view = void 0, + element = void 0; + var currentHeight = void 0, + viewHeight = void 0, + hiddenHeight = void 0, + percentHeight = void 0; + var currentWidth = void 0, + viewWidth = void 0; + var firstVisibleElementInd = views.length === 0 ? 0 : binarySearchFirstItem(views, isElementBottomBelowViewTop); + for (var i = firstVisibleElementInd, ii = views.length; i < ii; i++) { + view = views[i]; + element = view.div; + currentHeight = element.offsetTop + element.clientTop; + viewHeight = element.clientHeight; + if (currentHeight > bottom) { + break; + } + currentWidth = element.offsetLeft + element.clientLeft; + viewWidth = element.clientWidth; + if (currentWidth + viewWidth < left || currentWidth > right) { + continue; + } + hiddenHeight = Math.max(0, top - currentHeight) + Math.max(0, currentHeight + viewHeight - bottom); + percentHeight = (viewHeight - hiddenHeight) * 100 / viewHeight | 0; + visible.push({ + id: view.id, + x: currentWidth, + y: currentHeight, + view: view, + percent: percentHeight + }); + } + var first = visible[0]; + var last = visible[visible.length - 1]; + if (sortByVisibility) { + visible.sort(function (a, b) { + var pc = a.percent - b.percent; + if (Math.abs(pc) > 0.001) { + return -pc; + } + return a.id - b.id; + }); + } + return { + first: first, + last: last, + views: visible + }; + } + + function noContextMenuHandler(evt) { + evt.preventDefault(); + } + + function isDataSchema(url) { + var i = 0, + ii = url.length; + while (i < ii && url[i].trim() === '') { + i++; + } + return url.substr(i, 5).toLowerCase() === 'data:'; + } + + function getPDFFileNameFromURL(url) { + var defaultFilename = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'document.pdf'; + + if (isDataSchema(url)) { + console.warn('getPDFFileNameFromURL: ' + 'ignoring "data:" URL for performance reasons.'); + return defaultFilename; + } + var reURI = /^(?:(?:[^:]+:)?\/\/[^\/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/; + var reFilename = /[^\/?#=]+\.pdf\b(?!.*\.pdf\b)/i; + var splitURI = reURI.exec(url); + var suggestedFilename = reFilename.exec(splitURI[1]) || reFilename.exec(splitURI[2]) || reFilename.exec(splitURI[3]); + if (suggestedFilename) { + suggestedFilename = suggestedFilename[0]; + if (suggestedFilename.indexOf('%') !== -1) { + try { + suggestedFilename = reFilename.exec(decodeURIComponent(suggestedFilename))[0]; + } catch (ex) { + } + } + } + return suggestedFilename || defaultFilename; + } + + function normalizeWheelEventDelta(evt) { + var delta = Math.sqrt(evt.deltaX * evt.deltaX + evt.deltaY * evt.deltaY); + var angle = Math.atan2(evt.deltaY, evt.deltaX); + if (-0.25 * Math.PI < angle && angle < 0.75 * Math.PI) { + delta = -delta; + } + var MOUSE_DOM_DELTA_PIXEL_MODE = 0; + var MOUSE_DOM_DELTA_LINE_MODE = 1; + var MOUSE_PIXELS_PER_LINE = 30; + var MOUSE_LINES_PER_PAGE = 30; + if (evt.deltaMode === MOUSE_DOM_DELTA_PIXEL_MODE) { + delta /= MOUSE_PIXELS_PER_LINE * MOUSE_LINES_PER_PAGE; + } else if (evt.deltaMode === MOUSE_DOM_DELTA_LINE_MODE) { + delta /= MOUSE_LINES_PER_PAGE; + } + return delta; + } + + function cloneObj(obj) { + var result = Object.create(null); + for (var i in obj) { + if (Object.prototype.hasOwnProperty.call(obj, i)) { + result[i] = obj[i]; + } + } + return result; + } + + var animationStarted = new Promise(function (resolve) { + window.requestAnimationFrame(resolve); + }); + var mozL10n = void 0; + var localized = Promise.resolve(); + + var EventBus = function () { + function EventBus() { + _classCallCheck(this, EventBus); + + this._listeners = Object.create(null); + } + + _createClass(EventBus, [{ + key: 'on', + value: function on(eventName, listener) { + var eventListeners = this._listeners[eventName]; + if (!eventListeners) { + eventListeners = []; + this._listeners[eventName] = eventListeners; + } + eventListeners.push(listener); + } + }, { + key: 'off', + value: function off(eventName, listener) { + var eventListeners = this._listeners[eventName]; + var i = void 0; + if (!eventListeners || (i = eventListeners.indexOf(listener)) < 0) { + return; + } + eventListeners.splice(i, 1); + } + }, { + key: 'dispatch', + value: function dispatch(eventName) { + var eventListeners = this._listeners[eventName]; + if (!eventListeners || eventListeners.length === 0) { + return; + } + var args = Array.prototype.slice.call(arguments, 1); + eventListeners.slice(0).forEach(function (listener) { + listener.apply(null, args); + }); + } + }]); + + return EventBus; + }(); + + function clamp(v, min, max) { + return Math.min(Math.max(v, min), max); + } + + var ProgressBar = function () { + function ProgressBar(id) { + var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, + height = _ref.height, + width = _ref.width, + units = _ref.units; + + _classCallCheck(this, ProgressBar); + + 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; + } + + _createClass(ProgressBar, [{ + key: '_updateBar', + value: function _updateBar() { + if (this._indeterminate) { + this.div.classList.add('indeterminate'); + this.div.style.width = this.width + this.units; + return; + } + this.div.classList.remove('indeterminate'); + var progressSize = this.width * this._percent / 100; + this.div.style.width = progressSize + this.units; + } + }, { + key: 'setWidth', + value: function setWidth(viewer) { + if (!viewer) { + return; + } + var container = viewer.parentNode; + var scrollbarWidth = container.offsetWidth - viewer.offsetWidth; + if (scrollbarWidth > 0) { + this.bar.setAttribute('style', 'width: calc(100% - ' + scrollbarWidth + 'px);'); + } + } + }, { + key: 'hide', + value: function hide() { + if (!this.visible) { + return; + } + this.visible = false; + this.bar.classList.add('hidden'); + document.body.classList.remove('loadingInProgress'); + } + }, { + key: 'show', + value: function show() { + if (this.visible) { + return; + } + this.visible = true; + document.body.classList.add('loadingInProgress'); + this.bar.classList.remove('hidden'); + } + }, { + key: 'percent', + get: function get() { + return this._percent; + }, + set: function set(val) { + this._indeterminate = isNaN(val); + this._percent = clamp(val, 0, 100); + this._updateBar(); + } + }]); + + return ProgressBar; + }(); + + exports.CSS_UNITS = CSS_UNITS; + exports.DEFAULT_SCALE_VALUE = DEFAULT_SCALE_VALUE; + exports.DEFAULT_SCALE = DEFAULT_SCALE; + exports.MIN_SCALE = MIN_SCALE; + exports.MAX_SCALE = MAX_SCALE; + exports.UNKNOWN_SCALE = UNKNOWN_SCALE; + exports.MAX_AUTO_SCALE = MAX_AUTO_SCALE; + exports.SCROLLBAR_PADDING = SCROLLBAR_PADDING; + exports.VERTICAL_PADDING = VERTICAL_PADDING; + exports.cloneObj = cloneObj; + exports.RendererType = RendererType; + exports.mozL10n = mozL10n; + exports.NullL10n = NullL10n; + exports.EventBus = EventBus; + exports.ProgressBar = ProgressBar; + exports.getPDFFileNameFromURL = getPDFFileNameFromURL; + exports.noContextMenuHandler = noContextMenuHandler; + exports.parseQueryString = parseQueryString; + exports.getVisibleElements = getVisibleElements; + exports.roundToDivide = roundToDivide; + exports.approximateFraction = approximateFraction; + exports.getOutputScale = getOutputScale; + exports.scrollIntoView = scrollIntoView; + exports.watchScroll = watchScroll; + exports.binarySearchFirstItem = binarySearchFirstItem; + exports.normalizeWheelEventDelta = normalizeWheelEventDelta; + exports.animationStarted = animationStarted; + exports.localized = localized; + + /***/ + }), + /* 1 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + var pdfjsLib; + if (typeof window !== 'undefined' && window['pdfjs-dist/build/pdf']) { + pdfjsLib = window['pdfjs-dist/build/pdf']; + } else { + pdfjsLib = require('/apps/PDFViewer/pdf.js'); + } + module.exports = pdfjsLib; + + /***/ + }), + /* 2 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.getGlobalEventBus = exports.attachDOMEventsToEventBus = undefined; + + var _ui_utils = __webpack_require__(0); + + function attachDOMEventsToEventBus(eventBus) { + eventBus.on('documentload', function () { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('documentload', true, true, {}); + window.dispatchEvent(event); + }); + eventBus.on('pagerendered', function (evt) { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('pagerendered', true, true, { + pageNumber: evt.pageNumber, + cssTransform: evt.cssTransform + }); + evt.source.div.dispatchEvent(event); + }); + eventBus.on('textlayerrendered', function (evt) { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('textlayerrendered', true, true, {pageNumber: evt.pageNumber}); + evt.source.textLayerDiv.dispatchEvent(event); + }); + eventBus.on('pagechange', function (evt) { + var event = document.createEvent('UIEvents'); + event.initUIEvent('pagechange', true, true, window, 0); + event.pageNumber = evt.pageNumber; + evt.source.container.dispatchEvent(event); + }); + eventBus.on('pagesinit', function (evt) { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('pagesinit', true, true, null); + evt.source.container.dispatchEvent(event); + }); + eventBus.on('pagesloaded', function (evt) { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('pagesloaded', true, true, {pagesCount: evt.pagesCount}); + evt.source.container.dispatchEvent(event); + }); + eventBus.on('scalechange', function (evt) { + var event = document.createEvent('UIEvents'); + event.initUIEvent('scalechange', true, true, window, 0); + event.scale = evt.scale; + event.presetValue = evt.presetValue; + evt.source.container.dispatchEvent(event); + }); + eventBus.on('updateviewarea', function (evt) { + var event = document.createEvent('UIEvents'); + event.initUIEvent('updateviewarea', true, true, window, 0); + event.location = evt.location; + evt.source.container.dispatchEvent(event); + }); + eventBus.on('find', function (evt) { + if (evt.source === window) { + return; + } + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('find' + evt.type, true, true, { + query: evt.query, + phraseSearch: evt.phraseSearch, + caseSensitive: evt.caseSensitive, + highlightAll: evt.highlightAll, + findPrevious: evt.findPrevious + }); + window.dispatchEvent(event); + }); + eventBus.on('attachmentsloaded', function (evt) { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('attachmentsloaded', true, true, {attachmentsCount: evt.attachmentsCount}); + evt.source.container.dispatchEvent(event); + }); + eventBus.on('sidebarviewchanged', function (evt) { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('sidebarviewchanged', true, true, {view: evt.view}); + evt.source.outerContainer.dispatchEvent(event); + }); + eventBus.on('pagemode', function (evt) { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('pagemode', true, true, {mode: evt.mode}); + evt.source.pdfViewer.container.dispatchEvent(event); + }); + eventBus.on('namedaction', function (evt) { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('namedaction', true, true, {action: evt.action}); + evt.source.pdfViewer.container.dispatchEvent(event); + }); + eventBus.on('presentationmodechanged', function (evt) { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('presentationmodechanged', true, true, { + active: evt.active, + switchInProgress: evt.switchInProgress + }); + window.dispatchEvent(event); + }); + eventBus.on('outlineloaded', function (evt) { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('outlineloaded', true, true, {outlineCount: evt.outlineCount}); + evt.source.container.dispatchEvent(event); + }); + } + + var globalEventBus = null; + + function getGlobalEventBus() { + if (globalEventBus) { + return globalEventBus; + } + globalEventBus = new _ui_utils.EventBus(); + attachDOMEventsToEventBus(globalEventBus); + return globalEventBus; + } + + exports.attachDOMEventsToEventBus = attachDOMEventsToEventBus; + exports.getGlobalEventBus = getGlobalEventBus; + + /***/ + }), + /* 3 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var CLEANUP_TIMEOUT = 30000; + var RenderingStates = { + INITIAL: 0, + RUNNING: 1, + PAUSED: 2, + FINISHED: 3 + }; + + var PDFRenderingQueue = function () { + function PDFRenderingQueue() { + _classCallCheck(this, PDFRenderingQueue); + + this.pdfViewer = null; + this.pdfThumbnailViewer = null; + this.onIdle = null; + this.highestPriorityPage = null; + this.idleTimeout = null; + this.printing = false; + this.isThumbnailViewEnabled = false; + } + + _createClass(PDFRenderingQueue, [{ + key: "setViewer", + value: function setViewer(pdfViewer) { + this.pdfViewer = pdfViewer; + } + }, { + key: "setThumbnailViewer", + value: function setThumbnailViewer(pdfThumbnailViewer) { + this.pdfThumbnailViewer = pdfThumbnailViewer; + } + }, { + key: "isHighestPriority", + value: function isHighestPriority(view) { + return this.highestPriorityPage === view.renderingId; + } + }, { + key: "renderHighestPriority", + value: function 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); + } + } + }, { + key: "getHighestPriority", + value: function getHighestPriority(visible, views, scrolledDown) { + var visibleViews = visible.views; + var numVisible = visibleViews.length; + if (numVisible === 0) { + return false; + } + for (var i = 0; i < numVisible; ++i) { + var view = visibleViews[i].view; + if (!this.isViewFinished(view)) { + return view; + } + } + if (scrolledDown) { + var nextPageIndex = visible.last.id; + if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex])) { + return views[nextPageIndex]; + } + } else { + var previousPageIndex = visible.first.id - 2; + if (views[previousPageIndex] && !this.isViewFinished(views[previousPageIndex])) { + return views[previousPageIndex]; + } + } + return null; + } + }, { + key: "isViewFinished", + value: function isViewFinished(view) { + return view.renderingState === RenderingStates.FINISHED; + } + }, { + key: "renderView", + value: function renderView(view) { + var _this = this; + + 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; + var continueRendering = function continueRendering() { + _this.renderHighestPriority(); + }; + view.draw().then(continueRendering, continueRendering); + break; + } + return true; + } + }]); + + return PDFRenderingQueue; + }(); + + exports.RenderingStates = RenderingStates; + exports.PDFRenderingQueue = PDFRenderingQueue; + + /***/ + }), + /* 4 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFPrintServiceFactory = exports.DefaultExternalServices = exports.PDFViewerApplication = undefined; + + var _slicedToArray = function () { + function sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"]) _i["return"](); + } finally { + if (_d) throw _e; + } + } + return _arr; + } + + return function (arr, i) { + if (Array.isArray(arr)) { + return arr; + } else if (Symbol.iterator in Object(arr)) { + return sliceIterator(arr, i); + } else { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + }; + }(); + + var _ui_utils = __webpack_require__(0); + + var _pdfjsLib = __webpack_require__(1); + + var _pdf_cursor_tools = __webpack_require__(6); + + var _pdf_rendering_queue = __webpack_require__(3); + + var _pdf_sidebar = __webpack_require__(24); + + var _pdf_viewer = __webpack_require__(27); + + var _dom_events = __webpack_require__(2); + + var _overlay_manager = __webpack_require__(15); + + var _password_prompt = __webpack_require__(16); + + var _pdf_attachment_viewer = __webpack_require__(17); + + var _pdf_document_properties = __webpack_require__(18); + + var _pdf_find_bar = __webpack_require__(19); + + var _pdf_find_controller = __webpack_require__(7); + + var _pdf_history = __webpack_require__(20); + + var _pdf_link_service = __webpack_require__(5); + + var _pdf_outline_viewer = __webpack_require__(21); + + var _pdf_presentation_mode = __webpack_require__(23); + + var _pdf_thumbnail_viewer = __webpack_require__(26); + + var _secondary_toolbar = __webpack_require__(29); + + var _toolbar = __webpack_require__(31); + + var _view_history = __webpack_require__(32); + + var DEFAULT_SCALE_DELTA = 1.1; + var DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000; + + function configure(PDFJS) { + PDFJS.imageResourcesPath = './images/'; + PDFJS.workerSrc = './pdf.worker.js'; + PDFJS.cMapUrl = './cmaps/'; + PDFJS.cMapPacked = true; + } + + var DefaultExternalServices = { + updateFindControlState: function updateFindControlState(data) { + }, + initPassiveLoading: function initPassiveLoading(callbacks) { + }, + fallback: function fallback(data, callback) { + }, + reportTelemetry: function reportTelemetry(data) { + }, + createDownloadManager: function createDownloadManager() { + throw new Error('Not implemented: createDownloadManager'); + }, + createPreferences: function createPreferences() { + throw new Error('Not implemented: createPreferences'); + }, + createL10n: function createL10n() { + throw new Error('Not implemented: createL10n'); + }, + + supportsIntegratedFind: false, + supportsDocumentFonts: true, + supportsDocumentColors: true, + supportedMouseWheelZoomModifierKeys: { + ctrlKey: true, + metaKey: true + } + }; + var PDFViewerApplication = { + initialBookmark: document.location.hash.substring(1), + initialDestination: null, + initialized: false, + 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, + pdfOutlineViewer: null, + pdfAttachmentViewer: null, + pdfCursorTools: null, + store: null, + downloadManager: null, + overlayManager: null, + preferences: null, + toolbar: null, + secondaryToolbar: null, + eventBus: null, + l10n: null, + isInitialViewSet: false, + downloadComplete: false, + viewerPrefs: { + sidebarViewOnLoad: _pdf_sidebar.SidebarView.NONE, + pdfBugEnabled: false, + showPreviousViewOnLoad: true, + defaultZoomValue: '', + disablePageMode: false, + disablePageLabels: false, + renderer: 'canvas', + enhanceTextSelection: false, + renderInteractiveForms: false, + enablePrintAutoRotate: false + }, + isViewerEmbedded: window.parent !== window, + url: '', + baseUrl: '', + externalServices: DefaultExternalServices, + _boundEvents: {}, + initialize: function initialize(appConfig) { + var _this = this; + + this.preferences = this.externalServices.createPreferences(); + configure(_pdfjsLib.PDFJS); + this.appConfig = appConfig; + return this._readPreferences().then(function () { + return _this._initializeL10n(); + }).then(function () { + return _this._initializeViewerComponents(); + }).then(function () { + _this.bindEvents(); + _this.bindWindowEvents(); + var appContainer = appConfig.appContainer || document.documentElement; + _this.l10n.translate(appContainer).then(function () { + _this.eventBus.dispatch('localized'); + }); + if (_this.isViewerEmbedded && !_pdfjsLib.PDFJS.isExternalLinkTargetSet()) { + _pdfjsLib.PDFJS.externalLinkTarget = _pdfjsLib.PDFJS.LinkTarget.TOP; + } + _this.initialized = true; + }); + }, + _readPreferences: function _readPreferences() { + var preferences = this.preferences, + viewerPrefs = this.viewerPrefs; + + return Promise.all([preferences.get('enableWebGL').then(function resolved(value) { + _pdfjsLib.PDFJS.disableWebGL = !value; + }), preferences.get('sidebarViewOnLoad').then(function resolved(value) { + viewerPrefs['sidebarViewOnLoad'] = value; + }), preferences.get('pdfBugEnabled').then(function resolved(value) { + viewerPrefs['pdfBugEnabled'] = value; + }), preferences.get('showPreviousViewOnLoad').then(function resolved(value) { + viewerPrefs['showPreviousViewOnLoad'] = value; + }), preferences.get('defaultZoomValue').then(function resolved(value) { + viewerPrefs['defaultZoomValue'] = value; + }), preferences.get('enhanceTextSelection').then(function resolved(value) { + viewerPrefs['enhanceTextSelection'] = value; + }), preferences.get('disableTextLayer').then(function resolved(value) { + if (_pdfjsLib.PDFJS.disableTextLayer === true) { + return; + } + _pdfjsLib.PDFJS.disableTextLayer = value; + }), preferences.get('disableRange').then(function resolved(value) { + if (_pdfjsLib.PDFJS.disableRange === true) { + return; + } + _pdfjsLib.PDFJS.disableRange = value; + }), preferences.get('disableStream').then(function resolved(value) { + if (_pdfjsLib.PDFJS.disableStream === true) { + return; + } + _pdfjsLib.PDFJS.disableStream = value; + }), preferences.get('disableAutoFetch').then(function resolved(value) { + _pdfjsLib.PDFJS.disableAutoFetch = value; + }), preferences.get('disableFontFace').then(function resolved(value) { + if (_pdfjsLib.PDFJS.disableFontFace === true) { + return; + } + _pdfjsLib.PDFJS.disableFontFace = value; + }), preferences.get('useOnlyCssZoom').then(function resolved(value) { + _pdfjsLib.PDFJS.useOnlyCssZoom = value; + }), preferences.get('externalLinkTarget').then(function resolved(value) { + if (_pdfjsLib.PDFJS.isExternalLinkTargetSet()) { + return; + } + _pdfjsLib.PDFJS.externalLinkTarget = value; + }), preferences.get('renderer').then(function resolved(value) { + viewerPrefs['renderer'] = value; + }), preferences.get('renderInteractiveForms').then(function resolved(value) { + viewerPrefs['renderInteractiveForms'] = value; + }), preferences.get('disablePageMode').then(function resolved(value) { + viewerPrefs['disablePageMode'] = value; + }), preferences.get('disablePageLabels').then(function resolved(value) { + viewerPrefs['disablePageLabels'] = value; + }), preferences.get('enablePrintAutoRotate').then(function resolved(value) { + viewerPrefs['enablePrintAutoRotate'] = value; + })]).catch(function (reason) { + }); + }, + _initializeL10n: function _initializeL10n() { + if (this.viewerPrefs['pdfBugEnabled']) { + var hash = document.location.hash.substring(1); + var hashParams = (0, _ui_utils.parseQueryString)(hash); + if ('locale' in hashParams) { + _pdfjsLib.PDFJS.locale = hashParams['locale']; + } + } + this.l10n = this.externalServices.createL10n(); + return this.l10n.getDirection().then(function (dir) { + document.getElementsByTagName('html')[0].dir = dir; + }); + }, + _initializeViewerComponents: function _initializeViewerComponents() { + var _this2 = this; + + var appConfig = this.appConfig; + return new Promise(function (resolve, reject) { + _this2.overlayManager = new _overlay_manager.OverlayManager(); + var eventBus = appConfig.eventBus || (0, _dom_events.getGlobalEventBus)(); + _this2.eventBus = eventBus; + var pdfRenderingQueue = new _pdf_rendering_queue.PDFRenderingQueue(); + pdfRenderingQueue.onIdle = _this2.cleanup.bind(_this2); + _this2.pdfRenderingQueue = pdfRenderingQueue; + var pdfLinkService = new _pdf_link_service.PDFLinkService({eventBus: eventBus}); + _this2.pdfLinkService = pdfLinkService; + var downloadManager = _this2.externalServices.createDownloadManager(); + _this2.downloadManager = downloadManager; + var container = appConfig.mainContainer; + var viewer = appConfig.viewerContainer; + _this2.pdfViewer = new _pdf_viewer.PDFViewer({ + container: container, + viewer: viewer, + eventBus: eventBus, + renderingQueue: pdfRenderingQueue, + linkService: pdfLinkService, + downloadManager: downloadManager, + renderer: _this2.viewerPrefs['renderer'], + l10n: _this2.l10n, + enhanceTextSelection: _this2.viewerPrefs['enhanceTextSelection'], + renderInteractiveForms: _this2.viewerPrefs['renderInteractiveForms'], + enablePrintAutoRotate: _this2.viewerPrefs['enablePrintAutoRotate'] + }); + pdfRenderingQueue.setViewer(_this2.pdfViewer); + pdfLinkService.setViewer(_this2.pdfViewer); + var thumbnailContainer = appConfig.sidebar.thumbnailView; + _this2.pdfThumbnailViewer = new _pdf_thumbnail_viewer.PDFThumbnailViewer({ + container: thumbnailContainer, + renderingQueue: pdfRenderingQueue, + linkService: pdfLinkService, + l10n: _this2.l10n + }); + pdfRenderingQueue.setThumbnailViewer(_this2.pdfThumbnailViewer); + _this2.pdfHistory = new _pdf_history.PDFHistory({ + linkService: pdfLinkService, + eventBus: eventBus + }); + pdfLinkService.setHistory(_this2.pdfHistory); + _this2.findController = new _pdf_find_controller.PDFFindController({pdfViewer: _this2.pdfViewer}); + _this2.findController.onUpdateResultsCount = function (matchCount) { + if (_this2.supportsIntegratedFind) { + return; + } + _this2.findBar.updateResultsCount(matchCount); + }; + _this2.findController.onUpdateState = function (state, previous, matchCount) { + if (_this2.supportsIntegratedFind) { + _this2.externalServices.updateFindControlState({ + result: state, + findPrevious: previous + }); + } else { + _this2.findBar.updateUIState(state, previous, matchCount); + } + }; + _this2.pdfViewer.setFindController(_this2.findController); + var findBarConfig = Object.create(appConfig.findBar); + findBarConfig.findController = _this2.findController; + findBarConfig.eventBus = eventBus; + _this2.findBar = new _pdf_find_bar.PDFFindBar(findBarConfig, _this2.l10n); + _this2.pdfDocumentProperties = new _pdf_document_properties.PDFDocumentProperties(appConfig.documentProperties, _this2.overlayManager, _this2.l10n); + _this2.pdfCursorTools = new _pdf_cursor_tools.PDFCursorTools({ + container: container, + eventBus: eventBus, + preferences: _this2.preferences + }); + _this2.toolbar = new _toolbar.Toolbar(appConfig.toolbar, container, eventBus, _this2.l10n); + _this2.secondaryToolbar = new _secondary_toolbar.SecondaryToolbar(appConfig.secondaryToolbar, container, eventBus); + if (_this2.supportsFullscreen) { + _this2.pdfPresentationMode = new _pdf_presentation_mode.PDFPresentationMode({ + container: container, + viewer: viewer, + pdfViewer: _this2.pdfViewer, + eventBus: eventBus, + contextMenuItems: appConfig.fullscreen + }); + } + _this2.passwordPrompt = new _password_prompt.PasswordPrompt(appConfig.passwordOverlay, _this2.overlayManager, _this2.l10n); + _this2.pdfOutlineViewer = new _pdf_outline_viewer.PDFOutlineViewer({ + container: appConfig.sidebar.outlineView, + eventBus: eventBus, + linkService: pdfLinkService + }); + _this2.pdfAttachmentViewer = new _pdf_attachment_viewer.PDFAttachmentViewer({ + container: appConfig.sidebar.attachmentsView, + eventBus: eventBus, + downloadManager: downloadManager + }); + var sidebarConfig = Object.create(appConfig.sidebar); + sidebarConfig.pdfViewer = _this2.pdfViewer; + sidebarConfig.pdfThumbnailViewer = _this2.pdfThumbnailViewer; + sidebarConfig.pdfOutlineViewer = _this2.pdfOutlineViewer; + sidebarConfig.eventBus = eventBus; + _this2.pdfSidebar = new _pdf_sidebar.PDFSidebar(sidebarConfig, _this2.l10n); + _this2.pdfSidebar.onToggled = _this2.forceRendering.bind(_this2); + resolve(undefined); + }); + }, + run: function run(config) { + this.initialize(config).then(webViewerInitialized); + }, + zoomIn: function zoomIn(ticks) { + var 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: function zoomOut(ticks) { + var 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; + }, + + get pagesCount() { + return this.pdfDocument ? this.pdfDocument.numPages : 0; + }, + get pageRotation() { + return this.pdfViewer.pagesRotation; + }, + set page(val) { + this.pdfViewer.currentPageNumber = val; + }, + get page() { + return this.pdfViewer.currentPageNumber; + }, + get printing() { + return !!this.printService; + }, + get supportsPrinting() { + return PDFPrintServiceFactory.instance.supportsPrinting; + }, + get supportsFullscreen() { + var support = void 0; + var 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; + } + if (support && _pdfjsLib.PDFJS.disableFullscreen === true) { + support = false; + } + return (0, _pdfjsLib.shadow)(this, 'supportsFullscreen', support); + }, + get supportsIntegratedFind() { + return this.externalServices.supportsIntegratedFind; + }, + get supportsDocumentFonts() { + return this.externalServices.supportsDocumentFonts; + }, + get supportsDocumentColors() { + return this.externalServices.supportsDocumentColors; + }, + get loadingBar() { + var bar = new _ui_utils.ProgressBar('#loadingBar'); + return (0, _pdfjsLib.shadow)(this, 'loadingBar', bar); + }, + get supportedMouseWheelZoomModifierKeys() { + return this.externalServices.supportedMouseWheelZoomModifierKeys; + }, + initPassiveLoading: function initPassiveLoading() { + throw new Error('Not implemented: initPassiveLoading'); + }, + setTitleUsingUrl: function setTitleUsingUrl(url) { + this.url = url; + this.baseUrl = url.split('#')[0]; + var title = (0, _ui_utils.getPDFFileNameFromURL)(url, ''); + if (!title) { + try { + title = decodeURIComponent((0, _pdfjsLib.getFilenameFromUrl)(url)) || url; + } catch (ex) { + title = url; + } + } + this.setTitle(title); + }, + setTitle: function setTitle(title) { + if (this.isViewerEmbedded) { + return; + } + document.title = title; + }, + close: function close() { + var errorWrapper = this.appConfig.errorWrapper.container; + errorWrapper.setAttribute('hidden', 'true'); + if (!this.pdfLoadingTask) { + return Promise.resolve(); + } + var 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, null); + this.pdfDocumentProperties.setDocument(null, null); + } + this.store = null; + this.isInitialViewSet = false; + this.downloadComplete = false; + this.pdfSidebar.reset(); + this.pdfOutlineViewer.reset(); + this.pdfAttachmentViewer.reset(); + this.findController.reset(); + this.findBar.reset(); + this.toolbar.reset(); + this.secondaryToolbar.reset(); + if (typeof PDFBug !== 'undefined') { + PDFBug.cleanup(); + } + return promise; + }, + open: function open(file, args) { + var _this3 = this; + + if (arguments.length > 2 || typeof args === 'number') { + return Promise.reject(new Error('Call of open() with obsolete signature.')); + } + if (this.pdfLoadingTask) { + return this.close().then(function () { + _this3.preferences.reload(); + return _this3.open(file, args); + }); + } + var parameters = Object.create(null), + scale = void 0; + 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; + } + if (args) { + for (var prop in args) { + parameters[prop] = args[prop]; + } + if (args.scale) { + scale = args.scale; + } + if (args.length) { + this.pdfDocumentProperties.setFileSize(args.length); + } + } + var loadingTask = (0, _pdfjsLib.getDocument)(parameters); + this.pdfLoadingTask = loadingTask; + loadingTask.onPassword = function (updateCallback, reason) { + _this3.passwordPrompt.setUpdateCallback(updateCallback, reason); + _this3.passwordPrompt.open(); + }; + loadingTask.onProgress = function (_ref) { + var loaded = _ref.loaded, + total = _ref.total; + + _this3.progress(loaded / total); + }; + loadingTask.onUnsupportedFeature = this.fallback.bind(this); + return loadingTask.promise.then(function (pdfDocument) { + _this3.load(pdfDocument, scale); + }, function (exception) { + var message = exception && exception.message; + var loadingErrorMessage = void 0; + if (exception instanceof _pdfjsLib.InvalidPDFException) { + loadingErrorMessage = _this3.l10n.get('invalid_file_error', null, 'Invalid or corrupted PDF file.'); + } else if (exception instanceof _pdfjsLib.MissingPDFException) { + loadingErrorMessage = _this3.l10n.get('missing_file_error', null, 'Missing PDF file.'); + } else if (exception instanceof _pdfjsLib.UnexpectedResponseException) { + loadingErrorMessage = _this3.l10n.get('unexpected_response_error', null, 'Unexpected server response.'); + } else { + loadingErrorMessage = _this3.l10n.get('loading_error', null, 'An error occurred while loading the PDF.'); + } + return loadingErrorMessage.then(function (msg) { + _this3.error(msg, {message: message}); + throw new Error(msg); + }); + }); + }, + download: function download() { + var _this4 = this; + + function downloadByUrl() { + downloadManager.downloadUrl(url, filename); + } + + var url = this.baseUrl; + var filename = (0, _ui_utils.getPDFFileNameFromURL)(this.url); + var downloadManager = this.downloadManager; + downloadManager.onerror = function (err) { + _this4.error('PDF failed to download: ' + err); + }; + if (!this.pdfDocument || !this.downloadComplete) { + downloadByUrl(); + return; + } + this.pdfDocument.getData().then(function (data) { + var blob = (0, _pdfjsLib.createBlob)(data, 'application/pdf'); + downloadManager.download(blob, url, filename); + }).catch(downloadByUrl); + }, + fallback: function fallback(featureId) { + }, + error: function error(message, moreInfo) { + var 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}}')); + } + } + } + var errorWrapperConfig = this.appConfig.errorWrapper; + var errorWrapper = errorWrapperConfig.container; + errorWrapper.removeAttribute('hidden'); + var errorMessage = errorWrapperConfig.errorMessage; + errorMessage.textContent = message; + var closeButton = errorWrapperConfig.closeButton; + closeButton.onclick = function () { + errorWrapper.setAttribute('hidden', 'true'); + }; + var errorMoreInfo = errorWrapperConfig.errorMoreInfo; + var moreInfoButton = errorWrapperConfig.moreInfoButton; + var 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(function (parts) { + errorMoreInfo.value = parts.join('\n'); + }); + }, + progress: function progress(level) { + var _this5 = this; + + if (this.downloadComplete) { + return; + } + var percent = Math.round(level * 100); + if (percent > this.loadingBar.percent || isNaN(percent)) { + this.loadingBar.percent = percent; + if (_pdfjsLib.PDFJS.disableAutoFetch && percent) { + if (this.disableAutoFetchLoadingBarTimeout) { + clearTimeout(this.disableAutoFetchLoadingBarTimeout); + this.disableAutoFetchLoadingBarTimeout = null; + } + this.loadingBar.show(); + this.disableAutoFetchLoadingBarTimeout = setTimeout(function () { + _this5.loadingBar.hide(); + _this5.disableAutoFetchLoadingBarTimeout = null; + }, DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT); + } + } + }, + load: function load(pdfDocument, scale) { + var _this6 = this; + + scale = scale || _ui_utils.UNKNOWN_SCALE; + this.pdfDocument = pdfDocument; + pdfDocument.getDownloadInfo().then(function () { + _this6.downloadComplete = true; + _this6.loadingBar.hide(); + firstPagePromise.then(function () { + _this6.eventBus.dispatch('documentload', {source: _this6}); + }); + }); + var pageModePromise = pdfDocument.getPageMode().catch(function () { + }); + this.toolbar.setPagesCount(pdfDocument.numPages, false); + this.secondaryToolbar.setPagesCount(pdfDocument.numPages); + var id = this.documentFingerprint = pdfDocument.fingerprint; + var store = this.store = new _view_history.ViewHistory(id); + var baseDocumentUrl = void 0; + baseDocumentUrl = null; + this.pdfLinkService.setDocument(pdfDocument, baseDocumentUrl); + this.pdfDocumentProperties.setDocument(pdfDocument, this.url); + var pdfViewer = this.pdfViewer; + pdfViewer.setDocument(pdfDocument); + var firstPagePromise = pdfViewer.firstPagePromise; + var pagesPromise = pdfViewer.pagesPromise; + var onePageRendered = pdfViewer.onePageRendered; + var pdfThumbnailViewer = this.pdfThumbnailViewer; + pdfThumbnailViewer.setDocument(pdfDocument); + firstPagePromise.then(function (pdfPage) { + _this6.loadingBar.setWidth(_this6.appConfig.viewerContainer); + if (!_pdfjsLib.PDFJS.disableHistory && !_this6.isViewerEmbedded) { + if (!_this6.viewerPrefs['showPreviousViewOnLoad']) { + _this6.pdfHistory.clearHistoryState(); + } + _this6.pdfHistory.initialize(_this6.documentFingerprint); + if (_this6.pdfHistory.initialDestination) { + _this6.initialDestination = _this6.pdfHistory.initialDestination; + } else if (_this6.pdfHistory.initialBookmark) { + _this6.initialBookmark = _this6.pdfHistory.initialBookmark; + } + } + var initialParams = { + destination: _this6.initialDestination, + bookmark: _this6.initialBookmark, + hash: null + }; + var storePromise = store.getMultiple({ + exists: false, + page: '1', + zoom: _ui_utils.DEFAULT_SCALE_VALUE, + scrollLeft: '0', + scrollTop: '0', + sidebarView: _pdf_sidebar.SidebarView.NONE + }).catch(function () { + }); + Promise.all([storePromise, pageModePromise]).then(function (_ref2) { + var _ref3 = _slicedToArray(_ref2, 2), + _ref3$ = _ref3[0], + values = _ref3$ === undefined ? {} : _ref3$, + pageMode = _ref3[1]; + + var hash = _this6.viewerPrefs['defaultZoomValue'] ? 'zoom=' + _this6.viewerPrefs['defaultZoomValue'] : null; + var sidebarView = _this6.viewerPrefs['sidebarViewOnLoad']; + if (values.exists && _this6.viewerPrefs['showPreviousViewOnLoad']) { + hash = 'page=' + values.page + '&zoom=' + (_this6.viewerPrefs['defaultZoomValue'] || values.zoom) + ',' + values.scrollLeft + ',' + values.scrollTop; + sidebarView = sidebarView || values.sidebarView | 0; + } + if (pageMode && !_this6.viewerPrefs['disablePageMode']) { + sidebarView = sidebarView || apiPageModeToSidebarView(pageMode); + } + return { + hash: hash, + sidebarView: sidebarView + }; + }).then(function (_ref4) { + var hash = _ref4.hash, + sidebarView = _ref4.sidebarView; + + _this6.setInitialView(hash, { + sidebarView: sidebarView, + scale: scale + }); + initialParams.hash = hash; + if (!_this6.isViewerEmbedded) { + pdfViewer.focus(); + } + return pagesPromise; + }).then(function () { + if (!initialParams.destination && !initialParams.bookmark && !initialParams.hash) { + return; + } + if (pdfViewer.hasEqualPageSizes) { + return; + } + _this6.initialDestination = initialParams.destination; + _this6.initialBookmark = initialParams.bookmark; + pdfViewer.currentScaleValue = pdfViewer.currentScaleValue; + _this6.setInitialView(initialParams.hash); + }).then(function () { + pdfViewer.update(); + }); + }); + pdfDocument.getPageLabels().then(function (labels) { + if (!labels || _this6.viewerPrefs['disablePageLabels']) { + return; + } + var i = 0, + numLabels = labels.length; + if (numLabels !== _this6.pagesCount) { + console.error('The number of Page Labels does not match ' + 'the number of pages in the document.'); + return; + } + while (i < numLabels && labels[i] === (i + 1).toString()) { + i++; + } + if (i === numLabels) { + return; + } + pdfViewer.setPageLabels(labels); + pdfThumbnailViewer.setPageLabels(labels); + _this6.toolbar.setPagesCount(pdfDocument.numPages, true); + _this6.toolbar.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel); + }); + pagesPromise.then(function () { + if (!_this6.supportsPrinting) { + return; + } + pdfDocument.getJavaScript().then(function (javaScript) { + if (javaScript.length) { + console.warn('Warning: JavaScript is not supported'); + _this6.fallback(_pdfjsLib.UNSUPPORTED_FEATURES.javaScript); + } + var regex = /\bprint\s*\(/; + for (var i = 0, ii = javaScript.length; i < ii; i++) { + var js = javaScript[i]; + if (js && regex.test(js)) { + setTimeout(function () { + window.print(); + }); + return; + } + } + }); + }); + Promise.all([onePageRendered, _ui_utils.animationStarted]).then(function () { + pdfDocument.getOutline().then(function (outline) { + _this6.pdfOutlineViewer.render({outline: outline}); + }); + pdfDocument.getAttachments().then(function (attachments) { + _this6.pdfAttachmentViewer.render({attachments: attachments}); + }); + }); + pdfDocument.getMetadata().then(function (_ref5) { + var info = _ref5.info, + metadata = _ref5.metadata; + + _this6.documentInfo = info; + _this6.metadata = metadata; + console.log('PDF ' + pdfDocument.fingerprint + ' [' + info.PDFFormatVersion + ' ' + (info.Producer || '-').trim() + ' / ' + (info.Creator || '-').trim() + ']' + ' (PDF.js: ' + (_pdfjsLib.version || '-') + (!_pdfjsLib.PDFJS.disableWebGL ? ' [WebGL]' : '') + ')'); + var pdfTitle = void 0; + if (metadata && metadata.has('dc:title')) { + var title = metadata.get('dc:title'); + if (title !== 'Untitled') { + pdfTitle = title; + } + } + if (!pdfTitle && info && info['Title']) { + pdfTitle = info['Title']; + } + if (pdfTitle) { + _this6.setTitle(pdfTitle + ' - ' + document.title); + } + if (info.IsAcroFormPresent) { + console.warn('Warning: AcroForm/XFA is not supported'); + _this6.fallback(_pdfjsLib.UNSUPPORTED_FEATURES.forms); + } + }); + }, + setInitialView: function setInitialView(storedHash) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var _options$scale = options.scale, + scale = _options$scale === undefined ? 0 : _options$scale, + _options$sidebarView = options.sidebarView, + sidebarView = _options$sidebarView === undefined ? _pdf_sidebar.SidebarView.NONE : _options$sidebarView; + + this.isInitialViewSet = true; + this.pdfSidebar.setInitialView(sidebarView); + if (this.initialDestination) { + this.pdfLinkService.navigateTo(this.initialDestination); + this.initialDestination = null; + } else if (this.initialBookmark) { + this.pdfLinkService.setHash(this.initialBookmark); + this.pdfHistory.push({hash: this.initialBookmark}, true); + this.initialBookmark = null; + } else if (storedHash) { + this.pdfLinkService.setHash(storedHash); + } else if (scale) { + this.pdfViewer.currentScaleValue = scale; + this.page = 1; + } + 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: function cleanup() { + if (!this.pdfDocument) { + return; + } + this.pdfViewer.cleanup(); + this.pdfThumbnailViewer.cleanup(); + if (this.pdfViewer.renderer !== _ui_utils.RendererType.SVG) { + this.pdfDocument.cleanup(); + } + }, + forceRendering: function forceRendering() { + this.pdfRenderingQueue.printing = this.printing; + this.pdfRenderingQueue.isThumbnailViewEnabled = this.pdfSidebar.isThumbnailViewVisible; + this.pdfRenderingQueue.renderHighestPriority(); + }, + beforePrint: function beforePrint() { + var _this7 = this; + + if (this.printService) { + return; + } + if (!this.supportsPrinting) { + this.l10n.get('printing_not_supported', null, 'Warning: Printing is not fully supported by ' + 'this browser.').then(function (printMessage) { + _this7.error(printMessage); + }); + return; + } + if (!this.pdfViewer.pageViewsReady) { + this.l10n.get('printing_not_ready', null, 'Warning: The PDF is not fully loaded for printing.').then(function (notReadyMessage) { + window.alert(notReadyMessage); + }); + return; + } + var pagesOverview = this.pdfViewer.getPagesOverview(); + var printContainer = this.appConfig.printContainer; + var printService = PDFPrintServiceFactory.instance.createPrintService(this.pdfDocument, pagesOverview, printContainer, this.l10n); + this.printService = printService; + this.forceRendering(); + printService.layout(); + }, + + afterPrint: function pdfViewSetupAfterPrint() { + if (this.printService) { + this.printService.destroy(); + this.printService = null; + } + this.forceRendering(); + }, + rotatePages: function rotatePages(delta) { + if (!this.pdfDocument) { + return; + } + var pdfViewer = this.pdfViewer, + pdfThumbnailViewer = this.pdfThumbnailViewer; + + var pageNumber = pdfViewer.currentPageNumber; + var newRotation = (pdfViewer.pagesRotation + 360 + delta) % 360; + pdfViewer.pagesRotation = newRotation; + pdfThumbnailViewer.pagesRotation = newRotation; + this.forceRendering(); + pdfViewer.currentPageNumber = pageNumber; + }, + requestPresentationMode: function requestPresentationMode() { + if (!this.pdfPresentationMode) { + return; + } + this.pdfPresentationMode.request(); + }, + bindEvents: function bindEvents() { + var eventBus = this.eventBus, + _boundEvents = this._boundEvents; + + _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('textlayerrendered', webViewerTextLayerRendered); + eventBus.on('updateviewarea', webViewerUpdateViewarea); + eventBus.on('pagechanging', webViewerPageChanging); + eventBus.on('scalechanging', webViewerScaleChanging); + eventBus.on('sidebarviewchanged', webViewerSidebarViewChanged); + eventBus.on('pagemode', webViewerPageMode); + eventBus.on('namedaction', webViewerNamedAction); + eventBus.on('presentationmodechanged', webViewerPresentationModeChanged); + eventBus.on('presentationmode', webViewerPresentationMode); + eventBus.on('openfile', webViewerOpenFile); + 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('pagenumberchanged', webViewerPageNumberChanged); + eventBus.on('scalechanged', webViewerScaleChanged); + eventBus.on('rotatecw', webViewerRotateCw); + eventBus.on('rotateccw', webViewerRotateCcw); + eventBus.on('documentproperties', webViewerDocumentProperties); + eventBus.on('find', webViewerFind); + eventBus.on('findfromurlhash', webViewerFindFromUrlHash); + eventBus.on('fileinputchange', webViewerFileInputChange); + }, + bindWindowEvents: function bindWindowEvents() { + var eventBus = this.eventBus, + _boundEvents = this._boundEvents; + + _boundEvents.windowResize = function () { + eventBus.dispatch('resize'); + }; + _boundEvents.windowHashChange = function () { + eventBus.dispatch('hashchange', {hash: document.location.hash.substring(1)}); + }; + _boundEvents.windowBeforePrint = function () { + eventBus.dispatch('beforeprint'); + }; + _boundEvents.windowAfterPrint = function () { + eventBus.dispatch('afterprint'); + }; + window.addEventListener('wheel', webViewerWheel); + 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); + _boundEvents.windowChange = function (evt) { + var files = evt.target.files; + if (!files || files.length === 0) { + return; + } + eventBus.dispatch('fileinputchange', {fileInput: evt.target}); + }; + window.addEventListener('change', _boundEvents.windowChange); + }, + unbindEvents: function unbindEvents() { + var eventBus = this.eventBus, + _boundEvents = this._boundEvents; + + eventBus.off('resize', webViewerResize); + eventBus.off('hashchange', webViewerHashchange); + eventBus.off('beforeprint', _boundEvents.beforePrint); + eventBus.off('afterprint', _boundEvents.afterPrint); + eventBus.off('pagerendered', webViewerPageRendered); + eventBus.off('textlayerrendered', webViewerTextLayerRendered); + eventBus.off('updateviewarea', webViewerUpdateViewarea); + eventBus.off('pagechanging', webViewerPageChanging); + eventBus.off('scalechanging', webViewerScaleChanging); + eventBus.off('sidebarviewchanged', webViewerSidebarViewChanged); + eventBus.off('pagemode', webViewerPageMode); + eventBus.off('namedaction', webViewerNamedAction); + eventBus.off('presentationmodechanged', webViewerPresentationModeChanged); + eventBus.off('presentationmode', webViewerPresentationMode); + eventBus.off('openfile', webViewerOpenFile); + 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('pagenumberchanged', webViewerPageNumberChanged); + eventBus.off('scalechanged', webViewerScaleChanged); + eventBus.off('rotatecw', webViewerRotateCw); + eventBus.off('rotateccw', webViewerRotateCcw); + eventBus.off('documentproperties', webViewerDocumentProperties); + eventBus.off('find', webViewerFind); + eventBus.off('findfromurlhash', webViewerFindFromUrlHash); + eventBus.off('fileinputchange', webViewerFileInputChange); + _boundEvents.beforePrint = null; + _boundEvents.afterPrint = null; + }, + unbindWindowEvents: function unbindWindowEvents() { + var _boundEvents = this._boundEvents; + + window.removeEventListener('wheel', webViewerWheel); + 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('change', _boundEvents.windowChange); + _boundEvents.windowChange = null; + _boundEvents.windowResize = null; + _boundEvents.windowHashChange = null; + _boundEvents.windowBeforePrint = null; + _boundEvents.windowAfterPrint = null; + } + }; + var validateFileURL = void 0; + { + var HOSTED_VIEWER_ORIGINS = ['null', 'http://mozilla.github.io', 'https://mozilla.github.io']; + validateFileURL = function validateFileURL(file) { + return true; + if (file === undefined) { + return; + } + try { + var viewerOrigin = new URL(window.location.href).origin || 'null'; + if (HOSTED_VIEWER_ORIGINS.indexOf(viewerOrigin) >= 0) { + return; + } + var fileOrigin = new URL(file, window.location.href).origin; + if (fileOrigin !== viewerOrigin) { + throw new Error('file origin does not match viewer\'s'); + } + } catch (ex) { + var message = ex && ex.message; + PDFViewerApplication.l10n.get('loading_error', null, 'An error occurred while loading the PDF.').then(function (loadingErrorMessage) { + PDFViewerApplication.error(loadingErrorMessage, {message: message}); + }); + throw ex; + } + }; + } + + function loadAndEnablePDFBug(enabledTabs) { + return new Promise(function (resolve, reject) { + var appConfig = PDFViewerApplication.appConfig; + var script = document.createElement('script'); + script.src = appConfig.debuggerScriptPath; + script.onload = function () { + PDFBug.enable(enabledTabs); + PDFBug.init({ + PDFJS: _pdfjsLib.PDFJS, + OPS: _pdfjsLib.OPS + }, appConfig.mainContainer); + resolve(); + }; + script.onerror = function () { + reject(new Error('Cannot load debugger at ' + script.src)); + }; + (document.getElementsByTagName('head')[0] || document.body).appendChild(script); + }); + } + + function webViewerInitialized() { + var appConfig = PDFViewerApplication.appConfig; + var file = void 0; + var queryString = document.location.search.substring(1); + var params = (0, _ui_utils.parseQueryString)(queryString); + file = 'file' in params ? params.file : appConfig.defaultUrl; + validateFileURL(file); + var waitForBeforeOpening = []; + var 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; + } + if (PDFViewerApplication.viewerPrefs['pdfBugEnabled']) { + var hash = document.location.hash.substring(1); + var hashParams = (0, _ui_utils.parseQueryString)(hash); + if ('disableworker' in hashParams) { + _pdfjsLib.PDFJS.disableWorker = hashParams['disableworker'] === 'true'; + } + if ('disablerange' in hashParams) { + _pdfjsLib.PDFJS.disableRange = hashParams['disablerange'] === 'true'; + } + if ('disablestream' in hashParams) { + _pdfjsLib.PDFJS.disableStream = hashParams['disablestream'] === 'true'; + } + if ('disableautofetch' in hashParams) { + _pdfjsLib.PDFJS.disableAutoFetch = hashParams['disableautofetch'] === 'true'; + } + if ('disablefontface' in hashParams) { + _pdfjsLib.PDFJS.disableFontFace = hashParams['disablefontface'] === 'true'; + } + if ('disablehistory' in hashParams) { + _pdfjsLib.PDFJS.disableHistory = hashParams['disablehistory'] === 'true'; + } + if ('webgl' in hashParams) { + _pdfjsLib.PDFJS.disableWebGL = hashParams['webgl'] !== 'true'; + } + if ('useonlycsszoom' in hashParams) { + _pdfjsLib.PDFJS.useOnlyCssZoom = hashParams['useonlycsszoom'] === 'true'; + } + if ('verbosity' in hashParams) { + _pdfjsLib.PDFJS.verbosity = hashParams['verbosity'] | 0; + } + if ('ignorecurrentpositiononzoom' in hashParams) { + _pdfjsLib.PDFJS.ignoreCurrentPositionOnZoom = hashParams['ignorecurrentpositiononzoom'] === 'true'; + } + if ('textlayer' in hashParams) { + switch (hashParams['textlayer']) { + case 'off': + _pdfjsLib.PDFJS.disableTextLayer = true; + break; + case 'visible': + case 'shadow': + case 'hover': + var viewer = appConfig.viewerContainer; + viewer.classList.add('textLayer-' + hashParams['textlayer']); + break; + } + } + if ('pdfbug' in hashParams) { + _pdfjsLib.PDFJS.pdfBug = true; + var pdfBug = hashParams['pdfbug']; + var enabled = pdfBug.split(','); + waitForBeforeOpening.push(loadAndEnablePDFBug(enabled)); + } + } + 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.sidebar.mainContainer.addEventListener('transitionend', function (evt) { + if (evt.target === this) { + PDFViewerApplication.eventBus.dispatch('resize'); + } + }, true); + appConfig.sidebar.toggleButton.addEventListener('click', function () { + PDFViewerApplication.pdfSidebar.toggle(); + }); + Promise.all(waitForBeforeOpening).then(function () { + webViewerOpenFileViaURL(file); + }).catch(function (reason) { + PDFViewerApplication.l10n.get('loading_error', null, 'An error occurred while opening.').then(function (msg) { + PDFViewerApplication.error(msg, reason); + }); + }); + } + + var webViewerOpenFileViaURL = void 0; + { + webViewerOpenFileViaURL = function webViewerOpenFileViaURL(file) { + if (file && file.lastIndexOf('file:', 0) === 0) { + PDFViewerApplication.setTitleUsingUrl(file); + var xhr = new XMLHttpRequest(); + xhr.onload = function () { + PDFViewerApplication.open(new Uint8Array(xhr.response)); + }; + try { + xhr.open('GET', file); + xhr.responseType = 'arraybuffer'; + xhr.send(); + } catch (ex) { + PDFViewerApplication.l10n.get('loading_error', null, 'An error occurred while loading the PDF.').then(function (msg) { + PDFViewerApplication.error(msg, ex); + }); + } + return; + } + if (file) { + PDFViewerApplication.open(file); + } + }; + } + + function webViewerPageRendered(evt) { + var pageNumber = evt.pageNumber; + var pageIndex = pageNumber - 1; + var pageView = PDFViewerApplication.pdfViewer.getPageView(pageIndex); + if (pageNumber === PDFViewerApplication.page) { + PDFViewerApplication.toolbar.updateLoadingIndicatorState(false); + } + if (!pageView) { + return; + } + if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) { + var thumbnailView = PDFViewerApplication.pdfThumbnailViewer.getThumbnail(pageIndex); + thumbnailView.setImage(pageView); + } + if (_pdfjsLib.PDFJS.pdfBug && 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(function (msg) { + PDFViewerApplication.error(msg, pageView.error); + }); + } + } + + function webViewerTextLayerRendered(evt) { + } + + function webViewerPageMode(evt) { + var mode = evt.mode, + view = void 0; + 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 'none': + view = _pdf_sidebar.SidebarView.NONE; + break; + default: + console.error('Invalid "pagemode" hash parameter: ' + mode); + return; + } + PDFViewerApplication.pdfSidebar.switchView(view, true); + } + + function webViewerNamedAction(evt) { + var action = evt.action; + switch (action) { + case 'GoToPage': + PDFViewerApplication.appConfig.toolbar.pageNumber.select(); + break; + case 'Find': + if (!PDFViewerApplication.supportsIntegratedFind) { + PDFViewerApplication.findBar.toggle(); + } + break; + } + } + + function webViewerPresentationModeChanged(evt) { + var active = evt.active, + switchInProgress = evt.switchInProgress; + + PDFViewerApplication.pdfViewer.presentationModeState = switchInProgress ? _pdf_viewer.PresentationModeState.CHANGING : active ? _pdf_viewer.PresentationModeState.FULLSCREEN : _pdf_viewer.PresentationModeState.NORMAL; + } + + function webViewerSidebarViewChanged(evt) { + PDFViewerApplication.pdfRenderingQueue.isThumbnailViewEnabled = PDFViewerApplication.pdfSidebar.isThumbnailViewVisible; + var store = PDFViewerApplication.store; + if (store && PDFViewerApplication.isInitialViewSet) { + store.set('sidebarView', evt.view).catch(function () { + }); + } + } + + function webViewerUpdateViewarea(evt) { + var location = evt.location, + store = PDFViewerApplication.store; + if (store && PDFViewerApplication.isInitialViewSet) { + store.setMultiple({ + 'exists': true, + 'page': location.pageNumber, + 'zoom': location.scale, + 'scrollLeft': location.left, + 'scrollTop': location.top + }).catch(function () { + }); + } + var href = PDFViewerApplication.pdfLinkService.getAnchorUrl(location.pdfOpenParams); + PDFViewerApplication.appConfig.toolbar.viewBookmark.href = href; + PDFViewerApplication.appConfig.secondaryToolbar.viewBookmarkButton.href = href; + PDFViewerApplication.pdfHistory.updateCurrentBookmark(location.pdfOpenParams, location.pageNumber); + var currentPage = PDFViewerApplication.pdfViewer.getPageView(PDFViewerApplication.page - 1); + var loading = currentPage.renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED; + PDFViewerApplication.toolbar.updateLoadingIndicatorState(loading); + } + + function webViewerResize() { + var pdfDocument = PDFViewerApplication.pdfDocument, + pdfViewer = PDFViewerApplication.pdfViewer; + + if (!pdfDocument) { + return; + } + var currentScaleValue = pdfViewer.currentScaleValue; + if (currentScaleValue === 'auto' || currentScaleValue === 'page-fit' || currentScaleValue === 'page-width') { + pdfViewer.currentScaleValue = currentScaleValue; + } + pdfViewer.update(); + } + + function webViewerHashchange(evt) { + if (PDFViewerApplication.pdfHistory.isHashChangeUnlocked) { + var hash = evt.hash; + if (!hash) { + return; + } + if (!PDFViewerApplication.isInitialViewSet) { + PDFViewerApplication.initialBookmark = hash; + } else { + PDFViewerApplication.pdfLinkService.setHash(hash); + } + } + } + + var webViewerFileInputChange = void 0; + { + webViewerFileInputChange = function webViewerFileInputChange(evt) { + var file = evt.fileInput.files[0]; + if (!_pdfjsLib.PDFJS.disableCreateObjectURL && URL.createObjectURL) { + PDFViewerApplication.open(URL.createObjectURL(file)); + } else { + var fileReader = new FileReader(); + fileReader.onload = function webViewerChangeFileReaderOnload(evt) { + var buffer = evt.target.result; + PDFViewerApplication.open(new Uint8Array(buffer)); + }; + fileReader.readAsArrayBuffer(file); + } + PDFViewerApplication.setTitleUsingUrl(file.name); + var 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'); + }; + } + + function webViewerPresentationMode() { + PDFViewerApplication.requestPresentationMode(); + } + + function webViewerOpenFile() { + var openFileInputName = PDFViewerApplication.appConfig.openFileInputName; + document.getElementById(openFileInputName).click(); + } + + function webViewerPrint() { + window.print(); + } + + function webViewerDownload() { + PDFViewerApplication.download(); + } + + 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 webViewerPageNumberChanged(evt) { + var pdfViewer = PDFViewerApplication.pdfViewer; + 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 webViewerDocumentProperties() { + PDFViewerApplication.pdfDocumentProperties.open(); + } + + function webViewerFind(evt) { + PDFViewerApplication.findController.executeCommand('find' + evt.type, { + query: evt.query, + phraseSearch: evt.phraseSearch, + caseSensitive: evt.caseSensitive, + highlightAll: evt.highlightAll, + findPrevious: evt.findPrevious + }); + } + + function webViewerFindFromUrlHash(evt) { + PDFViewerApplication.findController.executeCommand('find', { + query: evt.query, + phraseSearch: evt.phraseSearch, + caseSensitive: false, + highlightAll: true, + findPrevious: false + }); + } + + function webViewerScaleChanging(evt) { + PDFViewerApplication.toolbar.setPageScale(evt.presetValue, evt.scale); + PDFViewerApplication.pdfViewer.update(); + } + + function webViewerPageChanging(evt) { + var page = evt.pageNumber; + PDFViewerApplication.toolbar.setPageNumber(page, evt.pageLabel || null); + PDFViewerApplication.secondaryToolbar.setPageNumber(page); + if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) { + PDFViewerApplication.pdfThumbnailViewer.scrollThumbnailIntoView(page); + } + if (_pdfjsLib.PDFJS.pdfBug && Stats.enabled) { + var pageView = PDFViewerApplication.pdfViewer.getPageView(page - 1); + if (pageView.stats) { + Stats.add(page, pageView.stats); + } + } + } + + var zoomDisabled = false, + zoomDisabledTimeout = void 0; + + function webViewerWheel(evt) { + var pdfViewer = PDFViewerApplication.pdfViewer; + if (pdfViewer.isInPresentationMode) { + return; + } + if (evt.ctrlKey || evt.metaKey) { + var support = PDFViewerApplication.supportedMouseWheelZoomModifierKeys; + if (evt.ctrlKey && !support.ctrlKey || evt.metaKey && !support.metaKey) { + return; + } + evt.preventDefault(); + if (zoomDisabled) { + return; + } + var previousScale = pdfViewer.currentScale; + var delta = (0, _ui_utils.normalizeWheelEventDelta)(evt); + var MOUSE_WHEEL_DELTA_PER_PAGE_SCALE = 3.0; + var ticks = delta * MOUSE_WHEEL_DELTA_PER_PAGE_SCALE; + if (ticks < 0) { + PDFViewerApplication.zoomOut(-ticks); + } else { + PDFViewerApplication.zoomIn(ticks); + } + var currentScale = pdfViewer.currentScale; + if (previousScale !== currentScale) { + var scaleCorrectionFactor = currentScale / previousScale - 1; + var rect = pdfViewer.container.getBoundingClientRect(); + var dx = evt.clientX - rect.left; + var dy = evt.clientY - rect.top; + pdfViewer.container.scrollLeft += dx * scaleCorrectionFactor; + pdfViewer.container.scrollTop += dy * scaleCorrectionFactor; + } + } else { + zoomDisabled = true; + clearTimeout(zoomDisabledTimeout); + zoomDisabledTimeout = setTimeout(function () { + zoomDisabled = false; + }, 1000); + } + } + + function webViewerClick(evt) { + if (!PDFViewerApplication.secondaryToolbar.isOpen) { + return; + } + var 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; + } + var handled = false, + ensureViewerFocused = false; + var cmd = (evt.ctrlKey ? 1 : 0) | (evt.altKey ? 2 : 0) | (evt.shiftKey ? 4 : 0) | (evt.metaKey ? 8 : 0); + var pdfViewer = PDFViewerApplication.pdfViewer; + var 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) { + var findState = PDFViewerApplication.findController.state; + if (findState) { + PDFViewerApplication.findController.executeCommand('findagain', { + query: findState.query, + phraseSearch: findState.phraseSearch, + caseSensitive: findState.caseSensitive, + 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 () { + pdfViewer.currentScaleValue = _ui_utils.DEFAULT_SCALE_VALUE; + }); + 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: + PDFViewerApplication.download(); + 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; + } + var curElement = document.activeElement || document.querySelector(':focus'); + var curElementTagName = curElement && curElement.tagName.toUpperCase(); + if (curElementTagName === 'INPUT' || curElementTagName === 'TEXTAREA' || curElementTagName === 'SELECT') { + if (evt.keyCode !== 27) { + return; + } + } + if (cmd === 0) { + switch (evt.keyCode) { + case 38: + case 33: + case 8: + if (!isViewerInPresentationMode && pdfViewer.currentScaleValue !== 'page-fit') { + break; + } + case 37: + if (pdfViewer.isHorizontalScrollbarEnabled) { + break; + } + case 75: + case 80: + if (PDFViewerApplication.page > 1) { + PDFViewerApplication.page--; + } + handled = true; + 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: + case 32: + if (!isViewerInPresentationMode && pdfViewer.currentScaleValue !== 'page-fit') { + break; + } + case 39: + if (pdfViewer.isHorizontalScrollbarEnabled) { + break; + } + case 74: + case 78: + if (PDFViewerApplication.page < PDFViewerApplication.pagesCount) { + PDFViewerApplication.page++; + } + handled = true; + 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; + } + } + if (cmd === 4) { + switch (evt.keyCode) { + 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 (cmd === 2) { + switch (evt.keyCode) { + case 37: + if (isViewerInPresentationMode) { + PDFViewerApplication.pdfHistory.back(); + handled = true; + } + break; + case 39: + if (isViewerInPresentationMode) { + PDFViewerApplication.pdfHistory.forward(); + handled = true; + } + break; + } + } + if (ensureViewerFocused && !pdfViewer.containsElement(curElement)) { + pdfViewer.focus(); + } + if (handled) { + evt.preventDefault(); + } + } + + 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.NONE; + } + + var PDFPrintServiceFactory = { + instance: { + supportsPrinting: false, + createPrintService: function createPrintService() { + throw new Error('Not implemented: createPrintService'); + } + } + }; + exports.PDFViewerApplication = PDFViewerApplication; + exports.DefaultExternalServices = DefaultExternalServices; + exports.PDFPrintServiceFactory = PDFPrintServiceFactory; + + /***/ + }), + /* 5 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.SimpleLinkService = exports.PDFLinkService = undefined; + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _dom_events = __webpack_require__(2); + + var _ui_utils = __webpack_require__(0); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var PDFLinkService = function () { + function PDFLinkService() { + var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, + eventBus = _ref.eventBus; + + _classCallCheck(this, PDFLinkService); + + this.eventBus = eventBus || (0, _dom_events.getGlobalEventBus)(); + this.baseUrl = null; + this.pdfDocument = null; + this.pdfViewer = null; + this.pdfHistory = null; + this._pagesRefCache = null; + } + + _createClass(PDFLinkService, [{ + key: 'setDocument', + value: function setDocument(pdfDocument, baseUrl) { + this.baseUrl = baseUrl; + this.pdfDocument = pdfDocument; + this._pagesRefCache = Object.create(null); + } + }, { + key: 'setViewer', + value: function setViewer(pdfViewer) { + this.pdfViewer = pdfViewer; + } + }, { + key: 'setHistory', + value: function setHistory(pdfHistory) { + this.pdfHistory = pdfHistory; + } + }, { + key: 'navigateTo', + value: function navigateTo(dest) { + var _this = this; + + var goToDestination = function goToDestination(_ref2) { + var namedDest = _ref2.namedDest, + explicitDest = _ref2.explicitDest; + + var destRef = explicitDest[0], + pageNumber = void 0; + if (destRef instanceof Object) { + pageNumber = _this._cachedPageNumber(destRef); + if (pageNumber === null) { + _this.pdfDocument.getPageIndex(destRef).then(function (pageIndex) { + _this.cachePageRef(pageIndex + 1, destRef); + goToDestination({ + namedDest: namedDest, + explicitDest: explicitDest + }); + }).catch(function () { + console.error('PDFLinkService.navigateTo: "' + destRef + '" is not ' + ('a valid page reference, for dest="' + dest + '".')); + }); + return; + } + } else if ((destRef | 0) === 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; + } + _this.pdfViewer.scrollPageIntoView({ + pageNumber: pageNumber, + destArray: explicitDest + }); + if (_this.pdfHistory) { + _this.pdfHistory.push({ + dest: explicitDest, + hash: namedDest, + page: pageNumber + }); + } + }; + new Promise(function (resolve, reject) { + if (typeof dest === 'string') { + _this.pdfDocument.getDestination(dest).then(function (destArray) { + resolve({ + namedDest: dest, + explicitDest: destArray + }); + }); + return; + } + resolve({ + namedDest: '', + explicitDest: dest + }); + }).then(function (data) { + if (!(data.explicitDest instanceof Array)) { + console.error('PDFLinkService.navigateTo: "' + data.explicitDest + '" is' + (' not a valid destination array, for dest="' + dest + '".')); + return; + } + goToDestination(data); + }); + } + }, { + key: 'getDestinationHash', + value: function getDestinationHash(dest) { + if (typeof dest === 'string') { + return this.getAnchorUrl('#' + escape(dest)); + } + if (dest instanceof Array) { + var str = JSON.stringify(dest); + return this.getAnchorUrl('#' + escape(str)); + } + return this.getAnchorUrl(''); + } + }, { + key: 'getAnchorUrl', + value: function getAnchorUrl(anchor) { + return (this.baseUrl || '') + anchor; + } + }, { + key: 'setHash', + value: function setHash(hash) { + var pageNumber = void 0, + dest = void 0; + if (hash.indexOf('=') >= 0) { + var 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 ('nameddest' in params) { + if (this.pdfHistory) { + this.pdfHistory.updateNextHashParam(params.nameddest); + } + this.navigateTo(params.nameddest); + return; + } + if ('page' in params) { + pageNumber = params.page | 0 || 1; + } + if ('zoom' in params) { + var zoomArgs = params.zoom.split(','); + var zoomArg = zoomArgs[0]; + var zoomArgNumber = parseFloat(zoomArg); + if (zoomArg.indexOf('Fit') === -1) { + 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 + }); + } + } else { + if (/^\d+$/.test(hash) && hash <= this.pagesCount) { + console.warn('PDFLinkService_setHash: specifying a page number ' + 'directly after the hash symbol (#) is deprecated, ' + ('please use the "#page=' + hash + '" form instead.')); + this.page = hash | 0; + } + dest = unescape(hash); + try { + dest = JSON.parse(dest); + if (!(dest instanceof Array)) { + dest = dest.toString(); + } + } catch (ex) { + } + if (typeof dest === 'string' || isValidExplicitDestination(dest)) { + if (this.pdfHistory) { + this.pdfHistory.updateNextHashParam(dest); + } + this.navigateTo(dest); + return; + } + console.error('PDFLinkService.setHash: "' + unescape(hash) + '" is not ' + 'a valid destination.'); + } + } + }, { + key: 'executeNamedAction', + value: function 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: action + }); + } + }, { + key: 'onFileAttachmentAnnotation', + value: function onFileAttachmentAnnotation(_ref3) { + var id = _ref3.id, + filename = _ref3.filename, + content = _ref3.content; + + this.eventBus.dispatch('fileattachmentannotation', { + source: this, + id: id, + filename: filename, + content: content + }); + } + }, { + key: 'cachePageRef', + value: function cachePageRef(pageNum, pageRef) { + var refStr = pageRef.num + ' ' + pageRef.gen + ' R'; + this._pagesRefCache[refStr] = pageNum; + } + }, { + key: '_cachedPageNumber', + value: function _cachedPageNumber(pageRef) { + var refStr = pageRef.num + ' ' + pageRef.gen + ' R'; + return this._pagesRefCache && this._pagesRefCache[refStr] || null; + } + }, { + key: 'pagesCount', + get: function get() { + return this.pdfDocument ? this.pdfDocument.numPages : 0; + } + }, { + key: 'page', + get: function get() { + return this.pdfViewer.currentPageNumber; + }, + set: function set(value) { + this.pdfViewer.currentPageNumber = value; + } + }]); + + return PDFLinkService; + }(); + + function isValidExplicitDestination(dest) { + if (!(dest instanceof Array)) { + return false; + } + var destLength = dest.length, + allowNull = true; + if (destLength < 2) { + return false; + } + var page = dest[0]; + if (!((typeof page === 'undefined' ? 'undefined' : _typeof(page)) === 'object' && typeof page.num === 'number' && (page.num | 0) === page.num && typeof page.gen === 'number' && (page.gen | 0) === page.gen) && !(typeof page === 'number' && (page | 0) === page && page >= 0)) { + return false; + } + var zoom = dest[1]; + if (!((typeof zoom === 'undefined' ? 'undefined' : _typeof(zoom)) === 'object' && typeof zoom.name === 'string')) { + return false; + } + 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 (var i = 2; i < destLength; i++) { + var param = dest[i]; + if (!(typeof param === 'number' || allowNull && param === null)) { + return false; + } + } + return true; + } + + var SimpleLinkService = function () { + function SimpleLinkService() { + _classCallCheck(this, SimpleLinkService); + } + + _createClass(SimpleLinkService, [{ + key: 'navigateTo', + value: function navigateTo(dest) { + } + }, { + key: 'getDestinationHash', + value: function getDestinationHash(dest) { + return '#'; + } + }, { + key: 'getAnchorUrl', + value: function getAnchorUrl(hash) { + return '#'; + } + }, { + key: 'setHash', + value: function setHash(hash) { + } + }, { + key: 'executeNamedAction', + value: function executeNamedAction(action) { + } + }, { + key: 'onFileAttachmentAnnotation', + value: function onFileAttachmentAnnotation(_ref4) { + var id = _ref4.id, + filename = _ref4.filename, + content = _ref4.content; + } + }, { + key: 'cachePageRef', + value: function cachePageRef(pageNum, pageRef) { + } + }, { + key: 'page', + get: function get() { + return 0; + }, + set: function set(value) { + } + }]); + + return SimpleLinkService; + }(); + + exports.PDFLinkService = PDFLinkService; + exports.SimpleLinkService = SimpleLinkService; + + /***/ + }), + /* 6 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFCursorTools = exports.CursorTool = undefined; + + var _slicedToArray = function () { + function sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"]) _i["return"](); + } finally { + if (_d) throw _e; + } + } + return _arr; + } + + return function (arr, i) { + if (Array.isArray(arr)) { + return arr; + } else if (Symbol.iterator in Object(arr)) { + return sliceIterator(arr, i); + } else { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + }; + }(); + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _grab_to_pan = __webpack_require__(14); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var CursorTool = { + SELECT: 0, + HAND: 1, + ZOOM: 2 + }; + + var PDFCursorTools = function () { + function PDFCursorTools(_ref) { + var _this = this; + + var container = _ref.container, + eventBus = _ref.eventBus, + preferences = _ref.preferences; + + _classCallCheck(this, PDFCursorTools); + + this.container = container; + this.eventBus = eventBus; + this.active = CursorTool.SELECT; + this.activeBeforePresentationMode = null; + this.handTool = new _grab_to_pan.GrabToPan({element: this.container}); + this._addEventListeners(); + Promise.all([preferences.get('cursorToolOnLoad'), preferences.get('enableHandToolOnLoad')]).then(function (_ref2) { + var _ref3 = _slicedToArray(_ref2, 2), + cursorToolPref = _ref3[0], + handToolPref = _ref3[1]; + + if (handToolPref === true) { + preferences.set('enableHandToolOnLoad', false); + if (cursorToolPref === CursorTool.SELECT) { + cursorToolPref = CursorTool.HAND; + preferences.set('cursorToolOnLoad', cursorToolPref).catch(function () { + }); + } + } + _this.switchTool(cursorToolPref); + }).catch(function () { + }); + } + + _createClass(PDFCursorTools, [{ + key: 'switchTool', + value: function switchTool(tool) { + var _this2 = this; + + if (this.activeBeforePresentationMode !== null) { + return; + } + if (tool === this.active) { + return; + } + var disableActiveTool = function disableActiveTool() { + switch (_this2.active) { + case CursorTool.SELECT: + break; + case CursorTool.HAND: + _this2.handTool.deactivate(); + break; + case CursorTool.ZOOM: + } + }; + switch (tool) { + case CursorTool.SELECT: + disableActiveTool(); + break; + case CursorTool.HAND: + disableActiveTool(); + this.handTool.activate(); + break; + case CursorTool.ZOOM: + default: + console.error('switchTool: "' + tool + '" is an unsupported value.'); + return; + } + this.active = tool; + this._dispatchEvent(); + } + }, { + key: '_dispatchEvent', + value: function _dispatchEvent() { + this.eventBus.dispatch('cursortoolchanged', { + source: this, + tool: this.active + }); + } + }, { + key: '_addEventListeners', + value: function _addEventListeners() { + var _this3 = this; + + this.eventBus.on('switchcursortool', function (evt) { + _this3.switchTool(evt.tool); + }); + this.eventBus.on('presentationmodechanged', function (evt) { + if (evt.switchInProgress) { + return; + } + var previouslyActive = void 0; + if (evt.active) { + previouslyActive = _this3.active; + _this3.switchTool(CursorTool.SELECT); + _this3.activeBeforePresentationMode = previouslyActive; + } else { + previouslyActive = _this3.activeBeforePresentationMode; + _this3.activeBeforePresentationMode = null; + _this3.switchTool(previouslyActive); + } + }); + } + }, { + key: 'activeTool', + get: function get() { + return this.active; + } + }]); + + return PDFCursorTools; + }(); + + exports.CursorTool = CursorTool; + exports.PDFCursorTools = PDFCursorTools; + + /***/ + }), + /* 7 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFFindController = exports.FindState = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _pdfjsLib = __webpack_require__(1); + + var _ui_utils = __webpack_require__(0); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var FindState = { + FOUND: 0, + NOT_FOUND: 1, + WRAPPED: 2, + PENDING: 3 + }; + var FIND_SCROLL_OFFSET_TOP = -50; + var FIND_SCROLL_OFFSET_LEFT = -400; + var FIND_TIMEOUT = 250; + var CHARACTERS_TO_NORMALIZE = { + '\u2018': '\'', + '\u2019': '\'', + '\u201A': '\'', + '\u201B': '\'', + '\u201C': '"', + '\u201D': '"', + '\u201E': '"', + '\u201F': '"', + '\xBC': '1/4', + '\xBD': '1/2', + '\xBE': '3/4' + }; + + var PDFFindController = function () { + function PDFFindController(_ref) { + var pdfViewer = _ref.pdfViewer; + + _classCallCheck(this, PDFFindController); + + this.pdfViewer = pdfViewer; + this.onUpdateResultsCount = null; + this.onUpdateState = null; + this.reset(); + var replace = Object.keys(CHARACTERS_TO_NORMALIZE).join(''); + this.normalizationRegex = new RegExp('[' + replace + ']', 'g'); + } + + _createClass(PDFFindController, [{ + key: 'reset', + value: function reset() { + var _this = this; + + this.startedTextExtraction = false; + this.extractTextPromises = []; + this.pendingFindMatches = Object.create(null); + this.active = false; + this.pageContents = []; + this.pageMatches = []; + this.pageMatchesLength = null; + this.matchCount = 0; + this.selected = { + pageIdx: -1, + matchIdx: -1 + }; + this.offset = { + pageIdx: null, + matchIdx: null + }; + this.pagesToSearch = null; + this.resumePageIdx = null; + this.state = null; + this.dirtyMatch = false; + this.findTimeout = null; + this._firstPagePromise = new Promise(function (resolve) { + _this.resolveFirstPage = resolve; + }); + } + }, { + key: 'normalize', + value: function normalize(text) { + return text.replace(this.normalizationRegex, function (ch) { + return CHARACTERS_TO_NORMALIZE[ch]; + }); + } + }, { + key: '_prepareMatches', + value: function _prepareMatches(matchesWithLength, matches, matchesLength) { + function isSubTerm(matchesWithLength, currentIndex) { + var currentElem = matchesWithLength[currentIndex]; + var nextElem = matchesWithLength[currentIndex + 1]; + if (currentIndex < matchesWithLength.length - 1 && currentElem.match === nextElem.match) { + currentElem.skipped = true; + return true; + } + for (var i = currentIndex - 1; i >= 0; i--) { + var 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 (var i = 0, len = matchesWithLength.length; i < len; i++) { + if (isSubTerm(matchesWithLength, i)) { + continue; + } + matches.push(matchesWithLength[i].match); + matchesLength.push(matchesWithLength[i].matchLength); + } + } + }, { + key: 'calcFindPhraseMatch', + value: function calcFindPhraseMatch(query, pageIndex, pageContent) { + var matches = []; + var queryLen = query.length; + var matchIdx = -queryLen; + while (true) { + matchIdx = pageContent.indexOf(query, matchIdx + queryLen); + if (matchIdx === -1) { + break; + } + matches.push(matchIdx); + } + this.pageMatches[pageIndex] = matches; + } + }, { + key: 'calcFindWordMatch', + value: function calcFindWordMatch(query, pageIndex, pageContent) { + var matchesWithLength = []; + var queryArray = query.match(/\S+/g); + for (var i = 0, len = queryArray.length; i < len; i++) { + var subquery = queryArray[i]; + var subqueryLen = subquery.length; + var matchIdx = -subqueryLen; + while (true) { + matchIdx = pageContent.indexOf(subquery, matchIdx + subqueryLen); + if (matchIdx === -1) { + break; + } + matchesWithLength.push({ + match: matchIdx, + matchLength: subqueryLen, + skipped: false + }); + } + } + if (!this.pageMatchesLength) { + this.pageMatchesLength = []; + } + this.pageMatchesLength[pageIndex] = []; + this.pageMatches[pageIndex] = []; + this._prepareMatches(matchesWithLength, this.pageMatches[pageIndex], this.pageMatchesLength[pageIndex]); + } + }, { + key: 'calcFindMatch', + value: function calcFindMatch(pageIndex) { + var pageContent = this.normalize(this.pageContents[pageIndex]); + var query = this.normalize(this.state.query); + var caseSensitive = this.state.caseSensitive; + var phraseSearch = this.state.phraseSearch; + var queryLen = query.length; + if (queryLen === 0) { + return; + } + if (!caseSensitive) { + pageContent = pageContent.toLowerCase(); + query = query.toLowerCase(); + } + if (phraseSearch) { + this.calcFindPhraseMatch(query, pageIndex, pageContent); + } else { + this.calcFindWordMatch(query, pageIndex, pageContent); + } + this.updatePage(pageIndex); + if (this.resumePageIdx === pageIndex) { + this.resumePageIdx = null; + this.nextPageMatch(); + } + if (this.pageMatches[pageIndex].length > 0) { + this.matchCount += this.pageMatches[pageIndex].length; + this.updateUIResultsCount(); + } + } + }, { + key: 'extractText', + value: function extractText() { + var _this2 = this; + + if (this.startedTextExtraction) { + return; + } + this.startedTextExtraction = true; + this.pageContents.length = 0; + var promise = Promise.resolve(); + + var _loop = function _loop(i, ii) { + var extractTextCapability = (0, _pdfjsLib.createPromiseCapability)(); + _this2.extractTextPromises[i] = extractTextCapability.promise; + promise = promise.then(function () { + return _this2.pdfViewer.getPageTextContent(i).then(function (textContent) { + var textItems = textContent.items; + var strBuf = []; + for (var j = 0, jj = textItems.length; j < jj; j++) { + strBuf.push(textItems[j].str); + } + _this2.pageContents[i] = strBuf.join(''); + extractTextCapability.resolve(i); + }, function (reason) { + console.error('Unable to get page ' + (i + 1) + ' text content', reason); + _this2.pageContents[i] = ''; + extractTextCapability.resolve(i); + }); + }); + }; + + for (var i = 0, ii = this.pdfViewer.pagesCount; i < ii; i++) { + _loop(i, ii); + } + } + }, { + key: 'executeCommand', + value: function executeCommand(cmd, state) { + var _this3 = this; + + if (this.state === null || cmd !== 'findagain') { + this.dirtyMatch = true; + } + this.state = state; + this.updateUIState(FindState.PENDING); + this._firstPagePromise.then(function () { + _this3.extractText(); + clearTimeout(_this3.findTimeout); + if (cmd === 'find') { + _this3.findTimeout = setTimeout(_this3.nextMatch.bind(_this3), FIND_TIMEOUT); + } else { + _this3.nextMatch(); + } + }); + } + }, { + key: 'updatePage', + value: function updatePage(index) { + if (this.selected.pageIdx === index) { + this.pdfViewer.currentPageNumber = index + 1; + } + var page = this.pdfViewer.getPageView(index); + if (page.textLayer) { + page.textLayer.updateMatches(); + } + } + }, { + key: 'nextMatch', + value: function nextMatch() { + var _this4 = this; + + var previous = this.state.findPrevious; + var currentPageIndex = this.pdfViewer.currentPageNumber - 1; + var numPages = this.pdfViewer.pagesCount; + this.active = true; + if (this.dirtyMatch) { + this.dirtyMatch = false; + this.selected.pageIdx = this.selected.matchIdx = -1; + this.offset.pageIdx = currentPageIndex; + this.offset.matchIdx = null; + this.hadMatch = false; + this.resumePageIdx = null; + this.pageMatches = []; + this.matchCount = 0; + this.pageMatchesLength = null; + for (var i = 0; i < numPages; i++) { + this.updatePage(i); + if (!(i in this.pendingFindMatches)) { + this.pendingFindMatches[i] = true; + this.extractTextPromises[i].then(function (pageIdx) { + delete _this4.pendingFindMatches[pageIdx]; + _this4.calcFindMatch(pageIdx); + }); + } + } + } + if (this.state.query === '') { + this.updateUIState(FindState.FOUND); + return; + } + if (this.resumePageIdx) { + return; + } + var offset = this.offset; + this.pagesToSearch = numPages; + if (offset.matchIdx !== null) { + var numPageMatches = this.pageMatches[offset.pageIdx].length; + if (!previous && offset.matchIdx + 1 < numPageMatches || previous && offset.matchIdx > 0) { + this.hadMatch = true; + offset.matchIdx = previous ? offset.matchIdx - 1 : offset.matchIdx + 1; + this.updateMatch(true); + return; + } + this.advanceOffsetPage(previous); + } + this.nextPageMatch(); + } + }, { + key: 'matchesReady', + value: function matchesReady(matches) { + var offset = this.offset; + var numMatches = matches.length; + var previous = this.state.findPrevious; + if (numMatches) { + this.hadMatch = true; + offset.matchIdx = previous ? numMatches - 1 : 0; + this.updateMatch(true); + return true; + } + this.advanceOffsetPage(previous); + if (offset.wrapped) { + offset.matchIdx = null; + if (this.pagesToSearch < 0) { + this.updateMatch(false); + return true; + } + } + return false; + } + }, { + key: 'updateMatchPosition', + value: function updateMatchPosition(pageIndex, matchIndex, elements, beginIdx) { + if (this.selected.matchIdx === matchIndex && this.selected.pageIdx === pageIndex) { + var spot = { + top: FIND_SCROLL_OFFSET_TOP, + left: FIND_SCROLL_OFFSET_LEFT + }; + (0, _ui_utils.scrollIntoView)(elements[beginIdx], spot, true); + } + } + }, { + key: 'nextPageMatch', + value: function nextPageMatch() { + if (this.resumePageIdx !== null) { + console.error('There can only be one pending page.'); + } + var matches = null; + do { + var pageIdx = this.offset.pageIdx; + matches = this.pageMatches[pageIdx]; + if (!matches) { + this.resumePageIdx = pageIdx; + break; + } + } while (!this.matchesReady(matches)); + } + }, { + key: 'advanceOffsetPage', + value: function advanceOffsetPage(previous) { + var offset = this.offset; + var numPages = this.extractTextPromises.length; + offset.pageIdx = previous ? offset.pageIdx - 1 : offset.pageIdx + 1; + offset.matchIdx = null; + this.pagesToSearch--; + if (offset.pageIdx >= numPages || offset.pageIdx < 0) { + offset.pageIdx = previous ? numPages - 1 : 0; + offset.wrapped = true; + } + } + }, { + key: 'updateMatch', + value: function updateMatch() { + var found = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + var state = FindState.NOT_FOUND; + var wrapped = this.offset.wrapped; + this.offset.wrapped = false; + if (found) { + var previousPage = this.selected.pageIdx; + this.selected.pageIdx = this.offset.pageIdx; + this.selected.matchIdx = this.offset.matchIdx; + state = wrapped ? FindState.WRAPPED : FindState.FOUND; + if (previousPage !== -1 && previousPage !== this.selected.pageIdx) { + this.updatePage(previousPage); + } + } + this.updateUIState(state, this.state.findPrevious); + if (this.selected.pageIdx !== -1) { + this.updatePage(this.selected.pageIdx); + } + } + }, { + key: 'updateUIResultsCount', + value: function updateUIResultsCount() { + if (this.onUpdateResultsCount) { + this.onUpdateResultsCount(this.matchCount); + } + } + }, { + key: 'updateUIState', + value: function updateUIState(state, previous) { + if (this.onUpdateState) { + this.onUpdateState(state, previous, this.matchCount); + } + } + }]); + + return PDFFindController; + }(); + + exports.FindState = FindState; + exports.PDFFindController = PDFFindController; + + /***/ + }), + /* 8 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.GenericCom = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _app = __webpack_require__(4); + + var _preferences = __webpack_require__(28); + + var _download_manager = __webpack_require__(12); + + var _genericl10n = __webpack_require__(13); + + var _pdfjsLib = __webpack_require__(1); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + function _possibleConstructorReturn(self, call) { + if (!self) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + return call && (typeof call === "object" || typeof call === "function") ? call : self; + } + + function _inherits(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); + } + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; + } + + ; + var GenericCom = {}; + + var GenericPreferences = function (_BasePreferences) { + _inherits(GenericPreferences, _BasePreferences); + + function GenericPreferences() { + _classCallCheck(this, GenericPreferences); + + return _possibleConstructorReturn(this, (GenericPreferences.__proto__ || Object.getPrototypeOf(GenericPreferences)).apply(this, arguments)); + } + + _createClass(GenericPreferences, [{ + key: '_writeToStorage', + value: function _writeToStorage(prefObj) { + return new Promise(function (resolve) { + localStorage.setItem('pdfjs.preferences', JSON.stringify(prefObj)); + resolve(); + }); + } + }, { + key: '_readFromStorage', + value: function _readFromStorage(prefObj) { + return new Promise(function (resolve) { + var readPrefs = JSON.parse(localStorage.getItem('pdfjs.preferences')); + resolve(readPrefs); + }); + } + }]); + + return GenericPreferences; + }(_preferences.BasePreferences); + + var GenericExternalServices = Object.create(_app.DefaultExternalServices); + GenericExternalServices.createDownloadManager = function () { + return new _download_manager.DownloadManager(); + }; + GenericExternalServices.createPreferences = function () { + return new GenericPreferences(); + }; + GenericExternalServices.createL10n = function () { + return new _genericl10n.GenericL10n(_pdfjsLib.PDFJS.locale); + }; + _app.PDFViewerApplication.externalServices = GenericExternalServices; + exports.GenericCom = GenericCom; + + /***/ + }), + /* 9 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFPrintService = undefined; + + var _ui_utils = __webpack_require__(0); + + var _app = __webpack_require__(4); + + var _pdfjsLib = __webpack_require__(1); + + var activeService = null; + var overlayManager = null; + + function renderPage(activeServiceOnEntry, pdfDocument, pageNumber, size) { + var scratchCanvas = activeService.scratchCanvas; + var PRINT_RESOLUTION = 150; + var PRINT_UNITS = PRINT_RESOLUTION / 72.0; + scratchCanvas.width = Math.floor(size.width * PRINT_UNITS); + scratchCanvas.height = Math.floor(size.height * PRINT_UNITS); + var width = Math.floor(size.width * _ui_utils.CSS_UNITS) + 'px'; + var height = Math.floor(size.height * _ui_utils.CSS_UNITS) + 'px'; + var 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) { + var renderContext = { + canvasContext: ctx, + transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0], + viewport: pdfPage.getViewport(1, size.rotation), + intent: 'print' + }; + return pdfPage.render(renderContext).promise; + }).then(function () { + return { + width: width, + height: height + }; + }); + } + + function PDFPrintService(pdfDocument, pagesOverview, printContainer, l10n) { + this.pdfDocument = pdfDocument; + this.pagesOverview = pagesOverview; + this.printContainer = printContainer; + this.l10n = l10n || _ui_utils.NullL10n; + this.currentPage = -1; + this.scratchCanvas = document.createElement('canvas'); + } + + PDFPrintService.prototype = { + layout: function layout() { + this.throwIfInactive(); + var body = document.querySelector('body'); + body.setAttribute('data-pdfjsprinting', true); + var hasEqualPageSizes = this.pagesOverview.every(function (size) { + return size.width === this.pagesOverview[0].width && size.height === this.pagesOverview[0].height; + }, this); + if (!hasEqualPageSizes) { + console.warn('Not all pages have the same size. The printed ' + 'result may be incorrect!'); + } + this.pageStyleSheet = document.createElement('style'); + var 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); + }, + destroy: function destroy() { + if (activeService !== this) { + return; + } + this.printContainer.textContent = ''; + if (this.pageStyleSheet && this.pageStyleSheet.parentNode) { + this.pageStyleSheet.parentNode.removeChild(this.pageStyleSheet); + this.pageStyleSheet = null; + } + this.scratchCanvas.width = this.scratchCanvas.height = 0; + this.scratchCanvas = null; + activeService = null; + ensureOverlay().then(function () { + if (overlayManager.active !== 'printServiceOverlay') { + return; + } + overlayManager.close('printServiceOverlay'); + }); + }, + renderPages: function renderPages() { + var _this = this; + + var pageCount = this.pagesOverview.length; + var renderNextPage = function renderNextPage(resolve, reject) { + _this.throwIfInactive(); + if (++_this.currentPage >= pageCount) { + renderProgress(pageCount, pageCount, _this.l10n); + resolve(); + return; + } + var index = _this.currentPage; + renderProgress(index, pageCount, _this.l10n); + renderPage(_this, _this.pdfDocument, index + 1, _this.pagesOverview[index]).then(_this.useRenderedPage.bind(_this)).then(function () { + renderNextPage(resolve, reject); + }, reject); + }; + return new Promise(renderNextPage); + }, + useRenderedPage: function useRenderedPage(printItem) { + this.throwIfInactive(); + var img = document.createElement('img'); + img.style.width = printItem.width; + img.style.height = printItem.height; + var scratchCanvas = this.scratchCanvas; + if ('toBlob' in scratchCanvas && !_pdfjsLib.PDFJS.disableCreateObjectURL) { + scratchCanvas.toBlob(function (blob) { + img.src = URL.createObjectURL(blob); + }); + } else { + img.src = scratchCanvas.toDataURL(); + } + var wrapper = document.createElement('div'); + wrapper.appendChild(img); + this.printContainer.appendChild(wrapper); + return new Promise(function (resolve, reject) { + img.onload = resolve; + img.onerror = reject; + }); + }, + performPrint: function performPrint() { + var _this2 = this; + + this.throwIfInactive(); + return new Promise(function (resolve) { + setTimeout(function () { + if (!_this2.active) { + resolve(); + return; + } + print.call(window); + setTimeout(resolve, 20); + }, 0); + }); + }, + + get active() { + return this === activeService; + }, + throwIfInactive: function throwIfInactive() { + if (!this.active) { + throw new Error('This print request was cancelled or completed.'); + } + } + }; + var print = window.print; + window.print = function print() { + if (activeService) { + console.warn('Ignored window.print() because of a pending print job.'); + return; + } + ensureOverlay().then(function () { + if (activeService) { + overlayManager.open('printServiceOverlay'); + } + }); + try { + dispatchEvent('beforeprint'); + } finally { + if (!activeService) { + console.error('Expected print service to be initialized.'); + ensureOverlay().then(function () { + if (overlayManager.active === 'printServiceOverlay') { + overlayManager.close('printServiceOverlay'); + } + }); + return; + } + var activeServiceOnEntry = activeService; + activeService.renderPages().then(function () { + return activeServiceOnEntry.performPrint(); + }).catch(function () { + }).then(function () { + if (activeServiceOnEntry.active) { + abort(); + } + }); + } + }; + + function dispatchEvent(eventType) { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent(eventType, false, false, 'custom'); + window.dispatchEvent(event); + } + + function abort() { + if (activeService) { + activeService.destroy(); + dispatchEvent('afterprint'); + } + } + + function renderProgress(index, total, l10n) { + var progressContainer = document.getElementById('printServiceOverlay'); + var progress = Math.round(100 * index / total); + var progressBar = progressContainer.querySelector('progress'); + var progressPerc = progressContainer.querySelector('.relative-progress'); + progressBar.value = progress; + l10n.get('print_progress_percent', {progress: progress}, progress + '%').then(function (msg) { + progressPerc.textContent = msg; + }); + } + + var hasAttachEvent = !!document.attachEvent; + window.addEventListener('keydown', function (event) { + if (event.keyCode === 80 && (event.ctrlKey || event.metaKey) && !event.altKey && (!event.shiftKey || window.chrome || window.opera)) { + window.print(); + if (hasAttachEvent) { + return; + } + event.preventDefault(); + if (event.stopImmediatePropagation) { + event.stopImmediatePropagation(); + } else { + event.stopPropagation(); + } + return; + } + }, true); + if (hasAttachEvent) { + document.attachEvent('onkeydown', function (event) { + event = event || window.event; + if (event.keyCode === 80 && event.ctrlKey) { + event.keyCode = 0; + return false; + } + }); + } + if ('onbeforeprint' in window) { + var stopPropagationIfNeeded = function stopPropagationIfNeeded(event) { + if (event.detail !== 'custom' && event.stopImmediatePropagation) { + event.stopImmediatePropagation(); + } + }; + window.addEventListener('beforeprint', stopPropagationIfNeeded); + window.addEventListener('afterprint', stopPropagationIfNeeded); + } + var overlayPromise; + + function ensureOverlay() { + if (!overlayPromise) { + overlayManager = _app.PDFViewerApplication.overlayManager; + if (!overlayManager) { + throw new Error('The overlay manager has not yet been initialized.'); + } + overlayPromise = overlayManager.register('printServiceOverlay', document.getElementById('printServiceOverlay'), abort, true); + document.getElementById('printCancel').onclick = abort; + } + return overlayPromise; + } + + _app.PDFPrintServiceFactory.instance = { + supportsPrinting: true, + createPrintService: function createPrintService(pdfDocument, pagesOverview, printContainer, l10n) { + if (activeService) { + throw new Error('The print service is created and active.'); + } + activeService = new PDFPrintService(pdfDocument, pagesOverview, printContainer, l10n); + return activeService; + } + }; + exports.PDFPrintService = PDFPrintService; + + /***/ + }), + /* 10 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + document.webL10n = function (window, document, undefined) { + var gL10nData = {}; + var gTextData = ''; + var gTextProp = 'textContent'; + var gLanguage = ''; + var gMacros = {}; + var gReadyState = 'loading'; + var gAsyncResourceLoading = true; + + function getL10nResourceLinks() { + return document.querySelectorAll('link[type="application/l10n"]'); + } + + function getL10nDictionary() { + var script = document.querySelector('script[type="application/l10n"]'); + return script ? JSON.parse(script.innerHTML) : null; + } + + function getTranslatableChildren(element) { + return element ? element.querySelectorAll('*[data-l10n-id]') : []; + } + + function getL10nAttributes(element) { + if (!element) return {}; + var l10nId = element.getAttribute('data-l10n-id'); + var l10nArgs = element.getAttribute('data-l10n-args'); + var args = {}; + if (l10nArgs) { + try { + args = JSON.parse(l10nArgs); + } catch (e) { + console.warn('could not parse arguments for #' + l10nId); + } + } + return { + id: l10nId, + args: args + }; + } + + function fireL10nReadyEvent(lang) { + var evtObject = document.createEvent('Event'); + evtObject.initEvent('localized', true, false); + evtObject.language = lang; + document.dispatchEvent(evtObject); + } + + function xhrLoadText(url, onSuccess, onFailure) { + onSuccess = onSuccess || function _onSuccess(data) { + }; + onFailure = onFailure || function _onFailure() { + }; + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, gAsyncResourceLoading); + if (xhr.overrideMimeType) { + xhr.overrideMimeType('text/plain; charset=utf-8'); + } + xhr.onreadystatechange = function () { + if (xhr.readyState == 4) { + if (xhr.status == 200 || xhr.status === 0) { + onSuccess(xhr.responseText); + } else { + onFailure(); + } + } + }; + xhr.onerror = onFailure; + xhr.ontimeout = onFailure; + try { + xhr.send(null); + } catch (e) { + onFailure(); + } + } + + function parseResource(href, lang, successCallback, failureCallback) { + var baseURL = href.replace(/[^\/]*$/, '') || './'; + + function evalString(text) { + if (text.lastIndexOf('\\') < 0) return text; + return text.replace(/\\\\/g, '\\').replace(/\\n/g, '\n').replace(/\\r/g, '\r').replace(/\\t/g, '\t').replace(/\\b/g, '\b').replace(/\\f/g, '\f').replace(/\\{/g, '{').replace(/\\}/g, '}').replace(/\\"/g, '"').replace(/\\'/g, "'"); + } + + function parseProperties(text, parsedPropertiesCallback) { + var dictionary = {}; + var reBlank = /^\s*|\s*$/; + var reComment = /^\s*#|^\s*$/; + var reSection = /^\s*\[(.*)\]\s*$/; + var reImport = /^\s*@import\s+url\((.*)\)\s*$/i; + var reSplit = /^([^=\s]*)\s*=\s*(.+)$/; + + function parseRawLines(rawText, extendedSyntax, parsedRawLinesCallback) { + var entries = rawText.replace(reBlank, '').split(/[\r\n]+/); + var currentLang = '*'; + var genericLang = lang.split('-', 1)[0]; + var skipLang = false; + var match = ''; + + function nextEntry() { + while (true) { + if (!entries.length) { + parsedRawLinesCallback(); + return; + } + var line = entries.shift(); + if (reComment.test(line)) continue; + if (extendedSyntax) { + match = reSection.exec(line); + if (match) { + currentLang = match[1].toLowerCase(); + skipLang = currentLang !== '*' && currentLang !== lang && currentLang !== genericLang; + continue; + } else if (skipLang) { + continue; + } + match = reImport.exec(line); + if (match) { + loadImport(baseURL + match[1], nextEntry); + return; + } + } + var tmp = line.match(reSplit); + if (tmp && tmp.length == 3) { + dictionary[tmp[1]] = evalString(tmp[2]); + } + } + } + + nextEntry(); + } + + function loadImport(url, callback) { + xhrLoadText(url, function (content) { + parseRawLines(content, false, callback); + }, function () { + console.warn(url + ' not found.'); + callback(); + }); + } + + parseRawLines(text, true, function () { + parsedPropertiesCallback(dictionary); + }); + } + + xhrLoadText(href, function (response) { + gTextData += response; + parseProperties(response, function (data) { + for (var key in data) { + var id, + prop, + index = key.lastIndexOf('.'); + if (index > 0) { + id = key.substring(0, index); + prop = key.substr(index + 1); + } else { + id = key; + prop = gTextProp; + } + if (!gL10nData[id]) { + gL10nData[id] = {}; + } + gL10nData[id][prop] = data[key]; + } + if (successCallback) { + successCallback(); + } + }); + }, failureCallback); + } + + function loadLocale(lang, callback) { + if (lang) { + lang = lang.toLowerCase(); + } + callback = callback || function _callback() { + }; + clear(); + gLanguage = lang; + var langLinks = getL10nResourceLinks(); + var langCount = langLinks.length; + if (langCount === 0) { + var dict = getL10nDictionary(); + if (dict && dict.locales && dict.default_locale) { + console.log('using the embedded JSON directory, early way out'); + gL10nData = dict.locales[lang]; + if (!gL10nData) { + var defaultLocale = dict.default_locale.toLowerCase(); + for (var anyCaseLang in dict.locales) { + anyCaseLang = anyCaseLang.toLowerCase(); + if (anyCaseLang === lang) { + gL10nData = dict.locales[lang]; + break; + } else if (anyCaseLang === defaultLocale) { + gL10nData = dict.locales[defaultLocale]; + } + } + } + callback(); + } else { + console.log('no resource to load, early way out'); + } + fireL10nReadyEvent(lang); + gReadyState = 'complete'; + return; + } + var onResourceLoaded = null; + var gResourceCount = 0; + onResourceLoaded = function onResourceLoaded() { + gResourceCount++; + if (gResourceCount >= langCount) { + callback(); + fireL10nReadyEvent(lang); + gReadyState = 'complete'; + } + }; + + function L10nResourceLink(link) { + var href = link.href; + this.load = function (lang, callback) { + parseResource(href, lang, callback, function () { + console.warn(href + ' not found.'); + console.warn('"' + lang + '" resource not found'); + gLanguage = ''; + callback(); + }); + }; + } + + for (var i = 0; i < langCount; i++) { + var resource = new L10nResourceLink(langLinks[i]); + resource.load(lang, onResourceLoaded); + } + } + + function clear() { + gL10nData = {}; + gTextData = ''; + gLanguage = ''; + } + + function getPluralRules(lang) { + var locales2rules = { + 'af': 3, + 'ak': 4, + 'am': 4, + 'ar': 1, + 'asa': 3, + 'az': 0, + 'be': 11, + 'bem': 3, + 'bez': 3, + 'bg': 3, + 'bh': 4, + 'bm': 0, + 'bn': 3, + 'bo': 0, + 'br': 20, + 'brx': 3, + 'bs': 11, + 'ca': 3, + 'cgg': 3, + 'chr': 3, + 'cs': 12, + 'cy': 17, + 'da': 3, + 'de': 3, + 'dv': 3, + 'dz': 0, + 'ee': 3, + 'el': 3, + 'en': 3, + 'eo': 3, + 'es': 3, + 'et': 3, + 'eu': 3, + 'fa': 0, + 'ff': 5, + 'fi': 3, + 'fil': 4, + 'fo': 3, + 'fr': 5, + 'fur': 3, + 'fy': 3, + 'ga': 8, + 'gd': 24, + 'gl': 3, + 'gsw': 3, + 'gu': 3, + 'guw': 4, + 'gv': 23, + 'ha': 3, + 'haw': 3, + 'he': 2, + 'hi': 4, + 'hr': 11, + 'hu': 0, + 'id': 0, + 'ig': 0, + 'ii': 0, + 'is': 3, + 'it': 3, + 'iu': 7, + 'ja': 0, + 'jmc': 3, + 'jv': 0, + 'ka': 0, + 'kab': 5, + 'kaj': 3, + 'kcg': 3, + 'kde': 0, + 'kea': 0, + 'kk': 3, + 'kl': 3, + 'km': 0, + 'kn': 0, + 'ko': 0, + 'ksb': 3, + 'ksh': 21, + 'ku': 3, + 'kw': 7, + 'lag': 18, + 'lb': 3, + 'lg': 3, + 'ln': 4, + 'lo': 0, + 'lt': 10, + 'lv': 6, + 'mas': 3, + 'mg': 4, + 'mk': 16, + 'ml': 3, + 'mn': 3, + 'mo': 9, + 'mr': 3, + 'ms': 0, + 'mt': 15, + 'my': 0, + 'nah': 3, + 'naq': 7, + 'nb': 3, + 'nd': 3, + 'ne': 3, + 'nl': 3, + 'nn': 3, + 'no': 3, + 'nr': 3, + 'nso': 4, + 'ny': 3, + 'nyn': 3, + 'om': 3, + 'or': 3, + 'pa': 3, + 'pap': 3, + 'pl': 13, + 'ps': 3, + 'pt': 3, + 'rm': 3, + 'ro': 9, + 'rof': 3, + 'ru': 11, + 'rwk': 3, + 'sah': 0, + 'saq': 3, + 'se': 7, + 'seh': 3, + 'ses': 0, + 'sg': 0, + 'sh': 11, + 'shi': 19, + 'sk': 12, + 'sl': 14, + 'sma': 7, + 'smi': 7, + 'smj': 7, + 'smn': 7, + 'sms': 7, + 'sn': 3, + 'so': 3, + 'sq': 3, + 'sr': 11, + 'ss': 3, + 'ssy': 3, + 'st': 3, + 'sv': 3, + 'sw': 3, + 'syr': 3, + 'ta': 3, + 'te': 3, + 'teo': 3, + 'th': 0, + 'ti': 4, + 'tig': 3, + 'tk': 3, + 'tl': 4, + 'tn': 3, + 'to': 0, + 'tr': 0, + 'ts': 3, + 'tzm': 22, + 'uk': 11, + 'ur': 3, + 've': 3, + 'vi': 0, + 'vun': 3, + 'wa': 4, + 'wae': 3, + 'wo': 0, + 'xh': 3, + 'xog': 3, + 'yo': 0, + 'zh': 0, + 'zu': 3 + }; + + function isIn(n, list) { + return list.indexOf(n) !== -1; + } + + function isBetween(n, start, end) { + return start <= n && n <= end; + } + + var pluralRules = { + '0': function _(n) { + return 'other'; + }, + '1': function _(n) { + if (isBetween(n % 100, 3, 10)) return 'few'; + if (n === 0) return 'zero'; + if (isBetween(n % 100, 11, 99)) return 'many'; + if (n == 2) return 'two'; + if (n == 1) return 'one'; + return 'other'; + }, + '2': function _(n) { + if (n !== 0 && n % 10 === 0) return 'many'; + if (n == 2) return 'two'; + if (n == 1) return 'one'; + return 'other'; + }, + '3': function _(n) { + if (n == 1) return 'one'; + return 'other'; + }, + '4': function _(n) { + if (isBetween(n, 0, 1)) return 'one'; + return 'other'; + }, + '5': function _(n) { + if (isBetween(n, 0, 2) && n != 2) return 'one'; + return 'other'; + }, + '6': function _(n) { + if (n === 0) return 'zero'; + if (n % 10 == 1 && n % 100 != 11) return 'one'; + return 'other'; + }, + '7': function _(n) { + if (n == 2) return 'two'; + if (n == 1) return 'one'; + return 'other'; + }, + '8': function _(n) { + if (isBetween(n, 3, 6)) return 'few'; + if (isBetween(n, 7, 10)) return 'many'; + if (n == 2) return 'two'; + if (n == 1) return 'one'; + return 'other'; + }, + '9': function _(n) { + if (n === 0 || n != 1 && isBetween(n % 100, 1, 19)) return 'few'; + if (n == 1) return 'one'; + return 'other'; + }, + '10': function _(n) { + if (isBetween(n % 10, 2, 9) && !isBetween(n % 100, 11, 19)) return 'few'; + if (n % 10 == 1 && !isBetween(n % 100, 11, 19)) return 'one'; + return 'other'; + }, + '11': function _(n) { + if (isBetween(n % 10, 2, 4) && !isBetween(n % 100, 12, 14)) return 'few'; + if (n % 10 === 0 || isBetween(n % 10, 5, 9) || isBetween(n % 100, 11, 14)) return 'many'; + if (n % 10 == 1 && n % 100 != 11) return 'one'; + return 'other'; + }, + '12': function _(n) { + if (isBetween(n, 2, 4)) return 'few'; + if (n == 1) return 'one'; + return 'other'; + }, + '13': function _(n) { + if (isBetween(n % 10, 2, 4) && !isBetween(n % 100, 12, 14)) return 'few'; + if (n != 1 && isBetween(n % 10, 0, 1) || isBetween(n % 10, 5, 9) || isBetween(n % 100, 12, 14)) return 'many'; + if (n == 1) return 'one'; + return 'other'; + }, + '14': function _(n) { + if (isBetween(n % 100, 3, 4)) return 'few'; + if (n % 100 == 2) return 'two'; + if (n % 100 == 1) return 'one'; + return 'other'; + }, + '15': function _(n) { + if (n === 0 || isBetween(n % 100, 2, 10)) return 'few'; + if (isBetween(n % 100, 11, 19)) return 'many'; + if (n == 1) return 'one'; + return 'other'; + }, + '16': function _(n) { + if (n % 10 == 1 && n != 11) return 'one'; + return 'other'; + }, + '17': function _(n) { + if (n == 3) return 'few'; + if (n === 0) return 'zero'; + if (n == 6) return 'many'; + if (n == 2) return 'two'; + if (n == 1) return 'one'; + return 'other'; + }, + '18': function _(n) { + if (n === 0) return 'zero'; + if (isBetween(n, 0, 2) && n !== 0 && n != 2) return 'one'; + return 'other'; + }, + '19': function _(n) { + if (isBetween(n, 2, 10)) return 'few'; + if (isBetween(n, 0, 1)) return 'one'; + return 'other'; + }, + '20': function _(n) { + if ((isBetween(n % 10, 3, 4) || n % 10 == 9) && !(isBetween(n % 100, 10, 19) || isBetween(n % 100, 70, 79) || isBetween(n % 100, 90, 99))) return 'few'; + if (n % 1000000 === 0 && n !== 0) return 'many'; + if (n % 10 == 2 && !isIn(n % 100, [12, 72, 92])) return 'two'; + if (n % 10 == 1 && !isIn(n % 100, [11, 71, 91])) return 'one'; + return 'other'; + }, + '21': function _(n) { + if (n === 0) return 'zero'; + if (n == 1) return 'one'; + return 'other'; + }, + '22': function _(n) { + if (isBetween(n, 0, 1) || isBetween(n, 11, 99)) return 'one'; + return 'other'; + }, + '23': function _(n) { + if (isBetween(n % 10, 1, 2) || n % 20 === 0) return 'one'; + return 'other'; + }, + '24': function _(n) { + if (isBetween(n, 3, 10) || isBetween(n, 13, 19)) return 'few'; + if (isIn(n, [2, 12])) return 'two'; + if (isIn(n, [1, 11])) return 'one'; + return 'other'; + } + }; + var index = locales2rules[lang.replace(/-.*$/, '')]; + if (!(index in pluralRules)) { + console.warn('plural form unknown for [' + lang + ']'); + return function () { + return 'other'; + }; + } + return pluralRules[index]; + } + + gMacros.plural = function (str, param, key, prop) { + var n = parseFloat(param); + if (isNaN(n)) return str; + if (prop != gTextProp) return str; + if (!gMacros._pluralRules) { + gMacros._pluralRules = getPluralRules(gLanguage); + } + var index = '[' + gMacros._pluralRules(n) + ']'; + if (n === 0 && key + '[zero]' in gL10nData) { + str = gL10nData[key + '[zero]'][prop]; + } else if (n == 1 && key + '[one]' in gL10nData) { + str = gL10nData[key + '[one]'][prop]; + } else if (n == 2 && key + '[two]' in gL10nData) { + str = gL10nData[key + '[two]'][prop]; + } else if (key + index in gL10nData) { + str = gL10nData[key + index][prop]; + } else if (key + '[other]' in gL10nData) { + str = gL10nData[key + '[other]'][prop]; + } + return str; + }; + + function getL10nData(key, args, fallback) { + var data = gL10nData[key]; + if (!data) { + console.warn('#' + key + ' is undefined.'); + if (!fallback) { + return null; + } + data = fallback; + } + var rv = {}; + for (var prop in data) { + var str = data[prop]; + str = substIndexes(str, args, key, prop); + str = substArguments(str, args, key); + rv[prop] = str; + } + return rv; + } + + function substIndexes(str, args, key, prop) { + var reIndex = /\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)\s*\]\}/; + var reMatch = reIndex.exec(str); + if (!reMatch || !reMatch.length) return str; + var macroName = reMatch[1]; + var paramName = reMatch[2]; + var param; + if (args && paramName in args) { + param = args[paramName]; + } else if (paramName in gL10nData) { + param = gL10nData[paramName]; + } + if (macroName in gMacros) { + var macro = gMacros[macroName]; + str = macro(str, param, key, prop); + } + return str; + } + + function substArguments(str, args, key) { + var reArgs = /\{\{\s*(.+?)\s*\}\}/g; + return str.replace(reArgs, function (matched_text, arg) { + if (args && arg in args) { + return args[arg]; + } + if (arg in gL10nData) { + return gL10nData[arg]; + } + console.log('argument {{' + arg + '}} for #' + key + ' is undefined.'); + return matched_text; + }); + } + + function translateElement(element) { + var l10n = getL10nAttributes(element); + if (!l10n.id) return; + var data = getL10nData(l10n.id, l10n.args); + if (!data) { + console.warn('#' + l10n.id + ' is undefined.'); + return; + } + if (data[gTextProp]) { + if (getChildElementCount(element) === 0) { + element[gTextProp] = data[gTextProp]; + } else { + var children = element.childNodes; + var found = false; + for (var i = 0, l = children.length; i < l; i++) { + if (children[i].nodeType === 3 && /\S/.test(children[i].nodeValue)) { + if (found) { + children[i].nodeValue = ''; + } else { + children[i].nodeValue = data[gTextProp]; + found = true; + } + } + } + if (!found) { + var textNode = document.createTextNode(data[gTextProp]); + element.insertBefore(textNode, element.firstChild); + } + } + delete data[gTextProp]; + } + for (var k in data) { + element[k] = data[k]; + } + } + + function getChildElementCount(element) { + if (element.children) { + return element.children.length; + } + if (typeof element.childElementCount !== 'undefined') { + return element.childElementCount; + } + var count = 0; + for (var i = 0; i < element.childNodes.length; i++) { + count += element.nodeType === 1 ? 1 : 0; + } + return count; + } + + function translateFragment(element) { + element = element || document.documentElement; + var children = getTranslatableChildren(element); + var elementCount = children.length; + for (var i = 0; i < elementCount; i++) { + translateElement(children[i]); + } + translateElement(element); + } + + return { + get: function get(key, args, fallbackString) { + var index = key.lastIndexOf('.'); + var prop = gTextProp; + if (index > 0) { + prop = key.substr(index + 1); + key = key.substring(0, index); + } + var fallback; + if (fallbackString) { + fallback = {}; + fallback[prop] = fallbackString; + } + var data = getL10nData(key, args, fallback); + if (data && prop in data) { + return data[prop]; + } + return '{{' + key + '}}'; + }, + getData: function getData() { + return gL10nData; + }, + getText: function getText() { + return gTextData; + }, + getLanguage: function getLanguage() { + return gLanguage; + }, + setLanguage: function setLanguage(lang, callback) { + loadLocale(lang, function () { + if (callback) callback(); + }); + }, + getDirection: function getDirection() { + var rtlList = ['ar', 'he', 'fa', 'ps', 'ur']; + var shortCode = gLanguage.split('-', 1)[0]; + return rtlList.indexOf(shortCode) >= 0 ? 'rtl' : 'ltr'; + }, + translate: translateFragment, + getReadyState: function getReadyState() { + return gReadyState; + }, + ready: function ready(callback) { + if (!callback) { + return; + } else if (gReadyState == 'complete' || gReadyState == 'interactive') { + window.setTimeout(function () { + callback(); + }); + } else if (document.addEventListener) { + document.addEventListener('localized', function once() { + document.removeEventListener('localized', once); + callback(); + }); + } + } + }; + }(window, document); + + /***/ + }), + /* 11 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.DefaultAnnotationLayerFactory = exports.AnnotationLayerBuilder = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _pdfjsLib = __webpack_require__(1); + + var _ui_utils = __webpack_require__(0); + + var _pdf_link_service = __webpack_require__(5); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var AnnotationLayerBuilder = function () { + function AnnotationLayerBuilder(_ref) { + var pageDiv = _ref.pageDiv, + pdfPage = _ref.pdfPage, + linkService = _ref.linkService, + downloadManager = _ref.downloadManager, + _ref$renderInteractiv = _ref.renderInteractiveForms, + renderInteractiveForms = _ref$renderInteractiv === undefined ? false : _ref$renderInteractiv, + _ref$l10n = _ref.l10n, + l10n = _ref$l10n === undefined ? _ui_utils.NullL10n : _ref$l10n; + + _classCallCheck(this, AnnotationLayerBuilder); + + this.pageDiv = pageDiv; + this.pdfPage = pdfPage; + this.linkService = linkService; + this.downloadManager = downloadManager; + this.renderInteractiveForms = renderInteractiveForms; + this.l10n = l10n; + this.div = null; + } + + _createClass(AnnotationLayerBuilder, [{ + key: 'render', + value: function render(viewport) { + var _this = this; + + var intent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'display'; + + this.pdfPage.getAnnotations({intent: intent}).then(function (annotations) { + var parameters = { + viewport: viewport.clone({dontFlip: true}), + div: _this.div, + annotations: annotations, + page: _this.pdfPage, + renderInteractiveForms: _this.renderInteractiveForms, + linkService: _this.linkService, + downloadManager: _this.downloadManager + }; + if (_this.div) { + _pdfjsLib.AnnotationLayer.update(parameters); + } else { + if (annotations.length === 0) { + return; + } + _this.div = document.createElement('div'); + _this.div.className = 'annotationLayer'; + _this.pageDiv.appendChild(_this.div); + parameters.div = _this.div; + _pdfjsLib.AnnotationLayer.render(parameters); + _this.l10n.translate(_this.div); + } + }); + } + }, { + key: 'hide', + value: function hide() { + if (!this.div) { + return; + } + this.div.setAttribute('hidden', 'true'); + } + }]); + + return AnnotationLayerBuilder; + }(); + + var DefaultAnnotationLayerFactory = function () { + function DefaultAnnotationLayerFactory() { + _classCallCheck(this, DefaultAnnotationLayerFactory); + } + + _createClass(DefaultAnnotationLayerFactory, [{ + key: 'createAnnotationLayerBuilder', + value: function createAnnotationLayerBuilder(pageDiv, pdfPage) { + var renderInteractiveForms = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + var l10n = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : _ui_utils.NullL10n; + + return new AnnotationLayerBuilder({ + pageDiv: pageDiv, + pdfPage: pdfPage, + renderInteractiveForms: renderInteractiveForms, + linkService: new _pdf_link_service.SimpleLinkService(), + l10n: l10n + }); + } + }]); + + return DefaultAnnotationLayerFactory; + }(); + + exports.AnnotationLayerBuilder = AnnotationLayerBuilder; + exports.DefaultAnnotationLayerFactory = DefaultAnnotationLayerFactory; + + /***/ + }), + /* 12 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.DownloadManager = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _pdfjsLib = __webpack_require__(1); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + ; + + function _download(blobUrl, filename) { + var a = document.createElement('a'); + if (a.click) { + a.href = blobUrl; + a.target = '_parent'; + if ('download' in a) { + a.download = filename; + } + (document.body || document.documentElement).appendChild(a); + a.click(); + a.parentNode.removeChild(a); + } else { + if (window.top === window && blobUrl.split('#')[0] === window.location.href.split('#')[0]) { + var padCharacter = blobUrl.indexOf('?') === -1 ? '?' : '&'; + blobUrl = blobUrl.replace(/#|$/, padCharacter + '$&'); + } + window.open(blobUrl, '_parent'); + } + } + + var DownloadManager = function () { + function DownloadManager() { + _classCallCheck(this, DownloadManager); + } + + _createClass(DownloadManager, [{ + key: 'downloadUrl', + value: function downloadUrl(url, filename) { + if (!(0, _pdfjsLib.createValidAbsoluteUrl)(url, 'http://example.com')) { + return; + } + _download(url + '#pdfjs.action=download', filename); + } + }, { + key: 'downloadData', + value: function downloadData(data, filename, contentType) { + if (navigator.msSaveBlob) { + return navigator.msSaveBlob(new Blob([data], {type: contentType}), filename); + } + var blobUrl = (0, _pdfjsLib.createObjectURL)(data, contentType, _pdfjsLib.PDFJS.disableCreateObjectURL); + _download(blobUrl, filename); + } + }, { + key: 'download', + value: function download(blob, url, filename) { + if (navigator.msSaveBlob) { + if (!navigator.msSaveBlob(blob, filename)) { + this.downloadUrl(url, filename); + } + return; + } + if (_pdfjsLib.PDFJS.disableCreateObjectURL) { + this.downloadUrl(url, filename); + return; + } + var blobUrl = URL.createObjectURL(blob); + _download(blobUrl, filename); + } + }]); + + return DownloadManager; + }(); + + exports.DownloadManager = DownloadManager; + + /***/ + }), + /* 13 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.GenericL10n = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + __webpack_require__(10); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var webL10n = document.webL10n; + + var GenericL10n = function () { + function GenericL10n(lang) { + _classCallCheck(this, GenericL10n); + + this._lang = lang; + this._ready = new Promise(function (resolve, reject) { + webL10n.setLanguage(lang, function () { + resolve(webL10n); + }); + }); + } + + _createClass(GenericL10n, [{ + key: 'getDirection', + value: function getDirection() { + return this._ready.then(function (l10n) { + return l10n.getDirection(); + }); + } + }, { + key: 'get', + value: function get(property, args, fallback) { + return this._ready.then(function (l10n) { + return l10n.get(property, args, fallback); + }); + } + }, { + key: 'translate', + value: function translate(element) { + return this._ready.then(function (l10n) { + return l10n.translate(element); + }); + } + }]); + + return GenericL10n; + }(); + + exports.GenericL10n = GenericL10n; + + /***/ + }), + /* 14 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + + function GrabToPan(options) { + this.element = options.element; + this.document = options.element.ownerDocument; + 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); + var 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() { + 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); + } + } + }, + deactivate: function GrabToPan_deactivate() { + if (this.active) { + this.active = false; + this.element.removeEventListener('mousedown', this._onmousedown, true); + this._endPan(); + this.element.classList.remove(this.CSS_CLASS_GRAB); + if (this.onActiveChanged) { + this.onActiveChanged(false); + } + } + }, + toggle: function GrabToPan_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) { + if (event.button !== 0 || this.ignoreTarget(event.target)) { + return; + } + if (event.originalTarget) { + try { + event.originalTarget.tagName; + } catch (e) { + return; + } + } + this.scrollLeftStart = this.element.scrollLeft; + this.scrollTopStart = this.element.scrollTop; + this.clientXStart = event.clientX; + this.clientYStart = event.clientY; + this.document.addEventListener('mousemove', this._onmousemove, true); + this.document.addEventListener('mouseup', this._endPan, true); + this.element.addEventListener('scroll', this._endPan, true); + event.preventDefault(); + event.stopPropagation(); + var focusedElement = document.activeElement; + if (focusedElement && !focusedElement.contains(event.target)) { + focusedElement.blur(); + } + }, + _onmousemove: function GrabToPan__onmousemove(event) { + this.element.removeEventListener('scroll', this._endPan, true); + if (isLeftMouseReleased(event)) { + this._endPan(); + return; + } + var xDiff = event.clientX - this.clientXStart; + var yDiff = event.clientY - this.clientYStart; + var scrollTop = this.scrollTopStart - yDiff; + var scrollLeft = this.scrollLeftStart - xDiff; + if (this.element.scrollTo) { + this.element.scrollTo({ + top: scrollTop, + left: scrollLeft, + behavior: 'instant' + }); + } else { + this.element.scrollTop = scrollTop; + this.element.scrollLeft = scrollLeft; + } + if (!this.overlay.parentNode) { + document.body.appendChild(this.overlay); + } + }, + _endPan: function GrabToPan__endPan() { + this.element.removeEventListener('scroll', this._endPan, true); + this.document.removeEventListener('mousemove', this._onmousemove, true); + this.document.removeEventListener('mouseup', this._endPan, true); + this.overlay.remove(); + } + }; + var matchesSelector; + ['webkitM', 'mozM', 'msM', 'oM', 'm'].some(function (prefix) { + var name = prefix + 'atches'; + if (name in document.documentElement) { + matchesSelector = name; + } + name += 'Selector'; + if (name in document.documentElement) { + matchesSelector = name; + } + return matchesSelector; + }); + var isNotIEorIsIE10plus = !document.documentMode || document.documentMode > 9; + var chrome = window.chrome; + var isChrome15OrOpera15plus = chrome && (chrome.webstore || chrome.app); + var 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; + } + } + + exports.GrabToPan = GrabToPan; + + /***/ + }), + /* 15 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var OverlayManager = function () { + function OverlayManager() { + _classCallCheck(this, OverlayManager); + + this._overlays = {}; + this._active = null; + this._keyDownBound = this._keyDown.bind(this); + } + + _createClass(OverlayManager, [{ + key: 'register', + value: function register(name, element) { + var _this = this; + + var callerCloseMethod = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + var canForceClose = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + + return new Promise(function (resolve) { + var container = void 0; + if (!name || !element || !(container = element.parentNode)) { + throw new Error('Not enough parameters.'); + } else if (_this._overlays[name]) { + throw new Error('The overlay is already registered.'); + } + _this._overlays[name] = { + element: element, + container: container, + callerCloseMethod: callerCloseMethod, + canForceClose: canForceClose + }; + resolve(); + }); + } + }, { + key: 'unregister', + value: function unregister(name) { + var _this2 = this; + + return new Promise(function (resolve) { + if (!_this2._overlays[name]) { + throw new Error('The overlay does not exist.'); + } else if (_this2._active === name) { + throw new Error('The overlay cannot be removed while it is active.'); + } + delete _this2._overlays[name]; + resolve(); + }); + } + }, { + key: 'open', + value: function open(name) { + var _this3 = this; + + return new Promise(function (resolve) { + if (!_this3._overlays[name]) { + throw new Error('The overlay does not exist.'); + } else if (_this3._active) { + if (_this3._overlays[name].canForceClose) { + _this3._closeThroughCaller(); + } else if (_this3._active === name) { + throw new Error('The overlay is already active.'); + } else { + throw new Error('Another overlay is currently active.'); + } + } + _this3._active = name; + _this3._overlays[_this3._active].element.classList.remove('hidden'); + _this3._overlays[_this3._active].container.classList.remove('hidden'); + window.addEventListener('keydown', _this3._keyDownBound); + resolve(); + }); + } + }, { + key: 'close', + value: function close(name) { + var _this4 = this; + + return new Promise(function (resolve) { + if (!_this4._overlays[name]) { + throw new Error('The overlay does not exist.'); + } else if (!_this4._active) { + throw new Error('The overlay is currently not active.'); + } else if (_this4._active !== name) { + throw new Error('Another overlay is currently active.'); + } + _this4._overlays[_this4._active].container.classList.add('hidden'); + _this4._overlays[_this4._active].element.classList.add('hidden'); + _this4._active = null; + window.removeEventListener('keydown', _this4._keyDownBound); + resolve(); + }); + } + }, { + key: '_keyDown', + value: function _keyDown(evt) { + if (this._active && evt.keyCode === 27) { + this._closeThroughCaller(); + evt.preventDefault(); + } + } + }, { + key: '_closeThroughCaller', + value: function _closeThroughCaller() { + if (this._overlays[this._active].callerCloseMethod) { + this._overlays[this._active].callerCloseMethod(); + } + if (this._active) { + this.close(this._active); + } + } + }, { + key: 'active', + get: function get() { + return this._active; + } + }]); + + return OverlayManager; + }(); + + exports.OverlayManager = OverlayManager; + + /***/ + }), + /* 16 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PasswordPrompt = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _ui_utils = __webpack_require__(0); + + var _pdfjsLib = __webpack_require__(1); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var PasswordPrompt = function () { + function PasswordPrompt(options, overlayManager) { + var _this = this; + + var l10n = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _ui_utils.NullL10n; + + _classCallCheck(this, PasswordPrompt); + + this.overlayName = options.overlayName; + this.container = options.container; + 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.cancelButton.addEventListener('click', this.close.bind(this)); + this.input.addEventListener('keydown', function (e) { + if (e.keyCode === 13) { + _this.verify(); + } + }); + this.overlayManager.register(this.overlayName, this.container, this.close.bind(this), true); + } + + _createClass(PasswordPrompt, [{ + key: 'open', + value: function open() { + var _this2 = this; + + this.overlayManager.open(this.overlayName).then(function () { + _this2.input.focus(); + var promptString = void 0; + if (_this2.reason === _pdfjsLib.PasswordResponses.INCORRECT_PASSWORD) { + promptString = _this2.l10n.get('password_invalid', null, 'Invalid password. Please try again.'); + } else { + promptString = _this2.l10n.get('password_label', null, 'Enter the password to open this PDF file.'); + } + promptString.then(function (msg) { + _this2.label.textContent = msg; + }); + }); + } + }, { + key: 'close', + value: function close() { + var _this3 = this; + + this.overlayManager.close(this.overlayName).then(function () { + _this3.input.value = ''; + }); + } + }, { + key: 'verify', + value: function verify() { + var password = this.input.value; + if (password && password.length > 0) { + this.close(); + return this.updateCallback(password); + } + } + }, { + key: 'setUpdateCallback', + value: function setUpdateCallback(updateCallback, reason) { + this.updateCallback = updateCallback; + this.reason = reason; + } + }]); + + return PasswordPrompt; + }(); + + exports.PasswordPrompt = PasswordPrompt; + + /***/ + }), + /* 17 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFAttachmentViewer = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _pdfjsLib = __webpack_require__(1); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var PDFAttachmentViewer = function () { + function PDFAttachmentViewer(_ref) { + var container = _ref.container, + eventBus = _ref.eventBus, + downloadManager = _ref.downloadManager; + + _classCallCheck(this, PDFAttachmentViewer); + + this.attachments = null; + this.container = container; + this.eventBus = eventBus; + this.downloadManager = downloadManager; + this._renderedCapability = (0, _pdfjsLib.createPromiseCapability)(); + this.eventBus.on('fileattachmentannotation', this._appendAttachment.bind(this)); + } + + _createClass(PDFAttachmentViewer, [{ + key: 'reset', + value: function reset() { + var keepRenderedCapability = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + this.attachments = null; + this.container.textContent = ''; + if (!keepRenderedCapability) { + this._renderedCapability = (0, _pdfjsLib.createPromiseCapability)(); + } + } + }, { + key: '_dispatchEvent', + value: function _dispatchEvent(attachmentsCount) { + this.eventBus.dispatch('attachmentsloaded', { + source: this, + attachmentsCount: attachmentsCount + }); + this._renderedCapability.resolve(); + } + }, { + key: '_bindPdfLink', + value: function _bindPdfLink(button, content, filename) { + if (_pdfjsLib.PDFJS.disableCreateObjectURL) { + throw new Error('bindPdfLink: ' + 'Unsupported "PDFJS.disableCreateObjectURL" value.'); + } + var blobUrl = void 0; + button.onclick = function () { + if (!blobUrl) { + blobUrl = (0, _pdfjsLib.createObjectURL)(content, 'application/pdf'); + } + var viewerUrl = void 0; + viewerUrl = '?file=' + encodeURIComponent(blobUrl + '#' + filename); + window.open(viewerUrl); + return false; + }; + } + }, { + key: '_bindLink', + value: function _bindLink(button, content, filename) { + var _this = this; + + button.onclick = function () { + _this.downloadManager.downloadData(content, filename, ''); + return false; + }; + } + }, { + key: 'render', + value: function render(_ref2) { + var attachments = _ref2.attachments, + _ref2$keepRenderedCap = _ref2.keepRenderedCapability, + keepRenderedCapability = _ref2$keepRenderedCap === undefined ? false : _ref2$keepRenderedCap; + + var attachmentsCount = 0; + if (this.attachments) { + this.reset(keepRenderedCapability === true); + } + this.attachments = attachments || null; + if (!attachments) { + this._dispatchEvent(attachmentsCount); + return; + } + var names = Object.keys(attachments).sort(function (a, b) { + return a.toLowerCase().localeCompare(b.toLowerCase()); + }); + attachmentsCount = names.length; + for (var i = 0; i < attachmentsCount; i++) { + var item = attachments[names[i]]; + var filename = (0, _pdfjsLib.removeNullCharacters)((0, _pdfjsLib.getFilenameFromUrl)(item.filename)); + var div = document.createElement('div'); + div.className = 'attachmentsItem'; + var button = document.createElement('button'); + button.textContent = filename; + if (/\.pdf$/i.test(filename) && !_pdfjsLib.PDFJS.disableCreateObjectURL) { + this._bindPdfLink(button, item.content, filename); + } else { + this._bindLink(button, item.content, filename); + } + div.appendChild(button); + this.container.appendChild(div); + } + this._dispatchEvent(attachmentsCount); + } + }, { + key: '_appendAttachment', + value: function _appendAttachment(_ref3) { + var _this2 = this; + + var id = _ref3.id, + filename = _ref3.filename, + content = _ref3.content; + + this._renderedCapability.promise.then(function () { + var attachments = _this2.attachments; + if (!attachments) { + attachments = Object.create(null); + } else { + for (var name in attachments) { + if (id === name) { + return; + } + } + } + attachments[id] = { + filename: filename, + content: content + }; + _this2.render({ + attachments: attachments, + keepRenderedCapability: true + }); + }); + } + }]); + + return PDFAttachmentViewer; + }(); + + exports.PDFAttachmentViewer = PDFAttachmentViewer; + + /***/ + }), + /* 18 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFDocumentProperties = undefined; + + var _slicedToArray = function () { + function sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"]) _i["return"](); + } finally { + if (_d) throw _e; + } + } + return _arr; + } + + return function (arr, i) { + if (Array.isArray(arr)) { + return arr; + } else if (Symbol.iterator in Object(arr)) { + return sliceIterator(arr, i); + } else { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + }; + }(); + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _ui_utils = __webpack_require__(0); + + var _pdfjsLib = __webpack_require__(1); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var DEFAULT_FIELD_CONTENT = '-'; + + var PDFDocumentProperties = function () { + function PDFDocumentProperties(_ref, overlayManager) { + var overlayName = _ref.overlayName, + fields = _ref.fields, + container = _ref.container, + closeButton = _ref.closeButton; + var l10n = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _ui_utils.NullL10n; + + _classCallCheck(this, PDFDocumentProperties); + + this.overlayName = overlayName; + this.fields = fields; + this.container = container; + this.overlayManager = overlayManager; + this.l10n = l10n; + this._reset(); + if (closeButton) { + closeButton.addEventListener('click', this.close.bind(this)); + } + this.overlayManager.register(this.overlayName, this.container, this.close.bind(this)); + } + + _createClass(PDFDocumentProperties, [{ + key: 'open', + value: function open() { + var _this = this; + + var freezeFieldData = function freezeFieldData(data) { + Object.defineProperty(_this, 'fieldData', { + value: Object.freeze(data), + writable: false, + enumerable: true, + configurable: true + }); + }; + Promise.all([this.overlayManager.open(this.overlayName), this._dataAvailableCapability.promise]).then(function () { + if (_this.fieldData) { + _this._updateUI(); + return; + } + _this.pdfDocument.getMetadata().then(function (_ref2) { + var info = _ref2.info, + metadata = _ref2.metadata; + + return Promise.all([info, metadata, _this._parseFileSize(_this.maybeFileSize), _this._parseDate(info.CreationDate), _this._parseDate(info.ModDate)]); + }).then(function (_ref3) { + var _ref4 = _slicedToArray(_ref3, 5), + info = _ref4[0], + metadata = _ref4[1], + fileSize = _ref4[2], + creationDate = _ref4[3], + modificationDate = _ref4[4]; + + freezeFieldData({ + 'fileName': (0, _ui_utils.getPDFFileNameFromURL)(_this.url), + 'fileSize': fileSize, + 'title': info.Title, + 'author': info.Author, + 'subject': info.Subject, + 'keywords': info.Keywords, + 'creationDate': creationDate, + 'modificationDate': modificationDate, + 'creator': info.Creator, + 'producer': info.Producer, + 'version': info.PDFFormatVersion, + 'pageCount': _this.pdfDocument.numPages + }); + _this._updateUI(); + return _this.pdfDocument.getDownloadInfo(); + }).then(function (_ref5) { + var length = _ref5.length; + + return _this._parseFileSize(length); + }).then(function (fileSize) { + var data = (0, _ui_utils.cloneObj)(_this.fieldData); + data['fileSize'] = fileSize; + freezeFieldData(data); + _this._updateUI(); + }); + }); + } + }, { + key: 'close', + value: function close() { + this.overlayManager.close(this.overlayName); + } + }, { + key: 'setDocument', + value: function setDocument(pdfDocument, url) { + if (this.pdfDocument) { + this._reset(); + this._updateUI(true); + } + if (!pdfDocument) { + return; + } + this.pdfDocument = pdfDocument; + this.url = url; + this._dataAvailableCapability.resolve(); + } + }, { + key: 'setFileSize', + value: function setFileSize(fileSize) { + if (typeof fileSize === 'number' && fileSize > 0) { + this.maybeFileSize = fileSize; + } + } + }, { + key: '_reset', + value: function _reset() { + this.pdfDocument = null; + this.url = null; + this.maybeFileSize = 0; + delete this.fieldData; + this._dataAvailableCapability = (0, _pdfjsLib.createPromiseCapability)(); + } + }, { + key: '_updateUI', + value: function _updateUI() { + var reset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + if (reset || !this.fieldData) { + for (var id in this.fields) { + this.fields[id].textContent = DEFAULT_FIELD_CONTENT; + } + return; + } + if (this.overlayManager.active !== this.overlayName) { + return; + } + for (var _id in this.fields) { + var content = this.fieldData[_id]; + this.fields[_id].textContent = content || content === 0 ? content : DEFAULT_FIELD_CONTENT; + } + } + }, { + key: '_parseFileSize', + value: function _parseFileSize() { + var fileSize = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + + var kb = fileSize / 1024; + if (!kb) { + return Promise.resolve(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(), + size_b: fileSize.toLocaleString() + }, '{{size_mb}} MB ({{size_b}} bytes)'); + } + }, { + key: '_parseDate', + value: function _parseDate(inputDate) { + if (!inputDate) { + return; + } + var dateToParse = inputDate; + if (dateToParse.substring(0, 2) === 'D:') { + dateToParse = dateToParse.substring(2); + } + var year = parseInt(dateToParse.substring(0, 4), 10); + var month = parseInt(dateToParse.substring(4, 6), 10) - 1; + var day = parseInt(dateToParse.substring(6, 8), 10); + var hours = parseInt(dateToParse.substring(8, 10), 10); + var minutes = parseInt(dateToParse.substring(10, 12), 10); + var seconds = parseInt(dateToParse.substring(12, 14), 10); + var utRel = dateToParse.substring(14, 15); + var offsetHours = parseInt(dateToParse.substring(15, 17), 10); + var offsetMinutes = parseInt(dateToParse.substring(18, 20), 10); + if (utRel === '-') { + hours += offsetHours; + minutes += offsetMinutes; + } else if (utRel === '+') { + hours -= offsetHours; + minutes -= offsetMinutes; + } + var date = new Date(Date.UTC(year, month, day, hours, minutes, seconds)); + var dateString = date.toLocaleDateString(); + var timeString = date.toLocaleTimeString(); + return this.l10n.get('document_properties_date_string', { + date: dateString, + time: timeString + }, '{{date}}, {{time}}'); + } + }]); + + return PDFDocumentProperties; + }(); + + exports.PDFDocumentProperties = PDFDocumentProperties; + + /***/ + }), + /* 19 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFFindBar = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _pdf_find_controller = __webpack_require__(7); + + var _ui_utils = __webpack_require__(0); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var PDFFindBar = function () { + function PDFFindBar(options) { + var _this = this; + + var l10n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _ui_utils.NullL10n; + + _classCallCheck(this, PDFFindBar); + + 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.findMsg = options.findMsg || null; + this.findResultsCount = options.findResultsCount || null; + this.findStatusIcon = options.findStatusIcon || null; + this.findPreviousButton = options.findPreviousButton || null; + this.findNextButton = options.findNextButton || null; + this.findController = options.findController || null; + this.eventBus = options.eventBus; + this.l10n = l10n; + if (this.findController === null) { + throw new Error('PDFFindBar cannot be used without a ' + 'PDFFindController instance.'); + } + this.toggleButton.addEventListener('click', function () { + _this.toggle(); + }); + this.findField.addEventListener('input', function () { + _this.dispatchEvent(''); + }); + this.bar.addEventListener('keydown', function (e) { + switch (e.keyCode) { + case 13: + if (e.target === _this.findField) { + _this.dispatchEvent('again', e.shiftKey); + } + break; + case 27: + _this.close(); + break; + } + }); + this.findPreviousButton.addEventListener('click', function () { + _this.dispatchEvent('again', true); + }); + this.findNextButton.addEventListener('click', function () { + _this.dispatchEvent('again', false); + }); + this.highlightAll.addEventListener('click', function () { + _this.dispatchEvent('highlightallchange'); + }); + this.caseSensitive.addEventListener('click', function () { + _this.dispatchEvent('casesensitivitychange'); + }); + this.eventBus.on('resize', this._adjustWidth.bind(this)); + } + + _createClass(PDFFindBar, [{ + key: 'reset', + value: function reset() { + this.updateUIState(); + } + }, { + key: 'dispatchEvent', + value: function dispatchEvent(type, findPrev) { + this.eventBus.dispatch('find', { + source: this, + type: type, + query: this.findField.value, + caseSensitive: this.caseSensitive.checked, + phraseSearch: true, + highlightAll: this.highlightAll.checked, + findPrevious: findPrev + }); + } + }, { + key: 'updateUIState', + value: function updateUIState(state, previous, matchCount) { + var _this2 = this; + + var notFound = false; + var findMsg = ''; + var status = ''; + switch (state) { + case _pdf_find_controller.FindState.FOUND: + break; + case _pdf_find_controller.FindState.PENDING: + status = 'pending'; + break; + case _pdf_find_controller.FindState.NOT_FOUND: + findMsg = this.l10n.get('find_not_found', null, 'Phrase not found'); + notFound = true; + 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'); + } + break; + } + if (notFound) { + this.findField.classList.add('notFound'); + } else { + this.findField.classList.remove('notFound'); + } + this.findField.setAttribute('data-status', status); + Promise.resolve(findMsg).then(function (msg) { + _this2.findMsg.textContent = msg; + _this2._adjustWidth(); + }); + this.updateResultsCount(matchCount); + } + }, { + key: 'updateResultsCount', + value: function updateResultsCount(matchCount) { + if (!this.findResultsCount) { + return; + } + if (!matchCount) { + this.findResultsCount.classList.add('hidden'); + this.findResultsCount.textContent = ''; + } else { + this.findResultsCount.textContent = matchCount.toLocaleString(); + this.findResultsCount.classList.remove('hidden'); + } + this._adjustWidth(); + } + }, { + key: 'open', + value: function open() { + if (!this.opened) { + this.opened = true; + this.toggleButton.classList.add('toggled'); + this.bar.classList.remove('hidden'); + } + this.findField.select(); + this.findField.focus(); + this._adjustWidth(); + } + }, { + key: 'close', + value: function close() { + if (!this.opened) { + return; + } + this.opened = false; + this.toggleButton.classList.remove('toggled'); + this.bar.classList.add('hidden'); + this.findController.active = false; + } + }, { + key: 'toggle', + value: function toggle() { + if (this.opened) { + this.close(); + } else { + this.open(); + } + } + }, { + key: '_adjustWidth', + value: function _adjustWidth() { + if (!this.opened) { + return; + } + this.bar.classList.remove('wrapContainers'); + var findbarHeight = this.bar.clientHeight; + var inputContainerHeight = this.bar.firstElementChild.clientHeight; + if (findbarHeight > inputContainerHeight) { + this.bar.classList.add('wrapContainers'); + } + } + }]); + + return PDFFindBar; + }(); + + exports.PDFFindBar = PDFFindBar; + + /***/ + }), + /* 20 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFHistory = undefined; + + var _dom_events = __webpack_require__(2); + + function PDFHistory(options) { + this.linkService = options.linkService; + this.eventBus = options.eventBus || (0, _dom_events.getGlobalEventBus)(); + this.initialized = false; + this.initialDestination = null; + this.initialBookmark = null; + } + + PDFHistory.prototype = { + initialize: function pdfHistoryInitialize(fingerprint) { + this.initialized = true; + this.reInitialized = false; + this.allowHashChange = true; + this.historyUnlocked = true; + this.isViewerInPresentationMode = false; + this.previousHash = window.location.hash.substring(1); + this.currentBookmark = ''; + this.currentPage = 0; + this.updatePreviousBookmark = false; + this.previousBookmark = ''; + this.previousPage = 0; + this.nextHashParam = ''; + this.fingerprint = fingerprint; + this.currentUid = this.uid = 0; + this.current = {}; + var state = window.history.state; + if (this._isStateObjectDefined(state)) { + if (state.target.dest) { + this.initialDestination = state.target.dest; + } else { + this.initialBookmark = state.target.hash; + } + this.currentUid = state.uid; + this.uid = state.uid + 1; + this.current = state.target; + } else { + if (state && state.fingerprint && this.fingerprint !== state.fingerprint) { + this.reInitialized = true; + } + this._pushOrReplaceState({fingerprint: this.fingerprint}, true); + } + var self = this; + window.addEventListener('popstate', function pdfHistoryPopstate(evt) { + if (!self.historyUnlocked) { + return; + } + if (evt.state) { + self._goTo(evt.state); + return; + } + if (self.uid === 0) { + var previousParams = self.previousHash && self.currentBookmark && self.previousHash !== self.currentBookmark ? { + hash: self.currentBookmark, + page: self.currentPage + } : {page: 1}; + replacePreviousHistoryState(previousParams, function () { + updateHistoryWithCurrentHash(); + }); + } else { + updateHistoryWithCurrentHash(); + } + }); + + function updateHistoryWithCurrentHash() { + self.previousHash = window.location.hash.slice(1); + self._pushToHistory({hash: self.previousHash}, false, true); + self._updatePreviousBookmark(); + } + + function replacePreviousHistoryState(params, callback) { + self.historyUnlocked = false; + self.allowHashChange = false; + window.addEventListener('popstate', rewriteHistoryAfterBack); + history.back(); + + function rewriteHistoryAfterBack() { + window.removeEventListener('popstate', rewriteHistoryAfterBack); + window.addEventListener('popstate', rewriteHistoryAfterForward); + self._pushToHistory(params, false, true); + history.forward(); + } + + function rewriteHistoryAfterForward() { + window.removeEventListener('popstate', rewriteHistoryAfterForward); + self.allowHashChange = true; + self.historyUnlocked = true; + callback(); + } + } + + function pdfHistoryBeforeUnload() { + var previousParams = self._getPreviousParams(null, true); + if (previousParams) { + var replacePrevious = !self.current.dest && self.current.hash !== self.previousHash; + self._pushToHistory(previousParams, false, replacePrevious); + self._updatePreviousBookmark(); + } + window.removeEventListener('beforeunload', pdfHistoryBeforeUnload); + } + + window.addEventListener('beforeunload', pdfHistoryBeforeUnload); + window.addEventListener('pageshow', function pdfHistoryPageShow(evt) { + window.addEventListener('beforeunload', pdfHistoryBeforeUnload); + }); + self.eventBus.on('presentationmodechanged', function (e) { + self.isViewerInPresentationMode = e.active; + }); + }, + clearHistoryState: function pdfHistory_clearHistoryState() { + this._pushOrReplaceState(null, true); + }, + _isStateObjectDefined: function pdfHistory_isStateObjectDefined(state) { + return state && state.uid >= 0 && state.fingerprint && this.fingerprint === state.fingerprint && state.target && state.target.hash ? true : false; + }, + _pushOrReplaceState: function pdfHistory_pushOrReplaceState(stateObj, replace) { + if (replace) { + window.history.replaceState(stateObj, '', document.URL); + } else { + window.history.pushState(stateObj, '', document.URL); + } + }, + get isHashChangeUnlocked() { + if (!this.initialized) { + return true; + } + return this.allowHashChange; + }, + _updatePreviousBookmark: function pdfHistory_updatePreviousBookmark() { + if (this.updatePreviousBookmark && this.currentBookmark && this.currentPage) { + this.previousBookmark = this.currentBookmark; + this.previousPage = this.currentPage; + this.updatePreviousBookmark = false; + } + }, + updateCurrentBookmark: function pdfHistoryUpdateCurrentBookmark(bookmark, pageNum) { + if (this.initialized) { + this.currentBookmark = bookmark.substring(1); + this.currentPage = pageNum | 0; + this._updatePreviousBookmark(); + } + }, + updateNextHashParam: function pdfHistoryUpdateNextHashParam(param) { + if (this.initialized) { + this.nextHashParam = param; + } + }, + push: function pdfHistoryPush(params, isInitialBookmark) { + if (!(this.initialized && this.historyUnlocked)) { + return; + } + if (params.dest && !params.hash) { + params.hash = this.current.hash && this.current.dest && this.current.dest === params.dest ? this.current.hash : this.linkService.getDestinationHash(params.dest).split('#')[1]; + } + if (params.page) { + params.page |= 0; + } + if (isInitialBookmark) { + var target = window.history.state.target; + if (!target) { + this._pushToHistory(params, false); + this.previousHash = window.location.hash.substring(1); + } + this.updatePreviousBookmark = this.nextHashParam ? false : true; + if (target) { + this._updatePreviousBookmark(); + } + return; + } + if (this.nextHashParam) { + if (this.nextHashParam === params.hash) { + this.nextHashParam = null; + this.updatePreviousBookmark = true; + return; + } + this.nextHashParam = null; + } + if (params.hash) { + if (this.current.hash) { + if (this.current.hash !== params.hash) { + this._pushToHistory(params, true); + } else { + if (!this.current.page && params.page) { + this._pushToHistory(params, false, true); + } + this.updatePreviousBookmark = true; + } + } else { + this._pushToHistory(params, true); + } + } else if (this.current.page && params.page && this.current.page !== params.page) { + this._pushToHistory(params, true); + } + }, + _getPreviousParams: function pdfHistory_getPreviousParams(onlyCheckPage, beforeUnload) { + if (!(this.currentBookmark && this.currentPage)) { + return null; + } else if (this.updatePreviousBookmark) { + this.updatePreviousBookmark = false; + } + if (this.uid > 0 && !(this.previousBookmark && this.previousPage)) { + return null; + } + if (!this.current.dest && !onlyCheckPage || beforeUnload) { + if (this.previousBookmark === this.currentBookmark) { + return null; + } + } else if (this.current.page || onlyCheckPage) { + if (this.previousPage === this.currentPage) { + return null; + } + } else { + return null; + } + var params = { + hash: this.currentBookmark, + page: this.currentPage + }; + if (this.isViewerInPresentationMode) { + params.hash = null; + } + return params; + }, + _stateObj: function pdfHistory_stateObj(params) { + return { + fingerprint: this.fingerprint, + uid: this.uid, + target: params + }; + }, + _pushToHistory: function pdfHistory_pushToHistory(params, addPrevious, overwrite) { + if (!this.initialized) { + return; + } + if (!params.hash && params.page) { + params.hash = 'page=' + params.page; + } + if (addPrevious && !overwrite) { + var previousParams = this._getPreviousParams(); + if (previousParams) { + var replacePrevious = !this.current.dest && this.current.hash !== this.previousHash; + this._pushToHistory(previousParams, false, replacePrevious); + } + } + this._pushOrReplaceState(this._stateObj(params), overwrite || this.uid === 0); + this.currentUid = this.uid++; + this.current = params; + this.updatePreviousBookmark = true; + }, + _goTo: function pdfHistory_goTo(state) { + if (!(this.initialized && this.historyUnlocked && this._isStateObjectDefined(state))) { + return; + } + if (!this.reInitialized && state.uid < this.currentUid) { + var previousParams = this._getPreviousParams(true); + if (previousParams) { + this._pushToHistory(this.current, false); + this._pushToHistory(previousParams, false); + this.currentUid = state.uid; + window.history.back(); + return; + } + } + this.historyUnlocked = false; + if (state.target.dest) { + this.linkService.navigateTo(state.target.dest); + } else { + this.linkService.setHash(state.target.hash); + } + this.currentUid = state.uid; + if (state.uid > this.uid) { + this.uid = state.uid; + } + this.current = state.target; + this.updatePreviousBookmark = true; + var currentHash = window.location.hash.substring(1); + if (this.previousHash !== currentHash) { + this.allowHashChange = false; + } + this.previousHash = currentHash; + this.historyUnlocked = true; + }, + back: function pdfHistoryBack() { + this.go(-1); + }, + forward: function pdfHistoryForward() { + this.go(1); + }, + go: function pdfHistoryGo(direction) { + if (this.initialized && this.historyUnlocked) { + var state = window.history.state; + if (direction === -1 && state && state.uid > 0) { + window.history.back(); + } else if (direction === 1 && state && state.uid < this.uid - 1) { + window.history.forward(); + } + } + } + }; + exports.PDFHistory = PDFHistory; + + /***/ + }), + /* 21 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFOutlineViewer = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _pdfjsLib = __webpack_require__(1); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var DEFAULT_TITLE = '\u2013'; + + var PDFOutlineViewer = function () { + function PDFOutlineViewer(_ref) { + var container = _ref.container, + linkService = _ref.linkService, + eventBus = _ref.eventBus; + + _classCallCheck(this, PDFOutlineViewer); + + this.outline = null; + this.lastToggleIsShow = true; + this.container = container; + this.linkService = linkService; + this.eventBus = eventBus; + } + + _createClass(PDFOutlineViewer, [{ + key: 'reset', + value: function reset() { + this.outline = null; + this.lastToggleIsShow = true; + this.container.textContent = ''; + this.container.classList.remove('outlineWithDeepNesting'); + } + }, { + key: '_dispatchEvent', + value: function _dispatchEvent(outlineCount) { + this.eventBus.dispatch('outlineloaded', { + source: this, + outlineCount: outlineCount + }); + } + }, { + key: '_bindLink', + value: function _bindLink(element, item) { + var _this = this; + + if (item.url) { + (0, _pdfjsLib.addLinkAttributes)(element, { + url: item.url, + target: item.newWindow ? _pdfjsLib.PDFJS.LinkTarget.BLANK : undefined + }); + return; + } + var destination = item.dest; + element.href = this.linkService.getDestinationHash(destination); + element.onclick = function () { + if (destination) { + _this.linkService.navigateTo(destination); + } + return false; + }; + } + }, { + key: '_setStyles', + value: function _setStyles(element, item) { + var styleStr = ''; + if (item.bold) { + styleStr += 'font-weight: bold;'; + } + if (item.italic) { + styleStr += 'font-style: italic;'; + } + if (styleStr) { + element.setAttribute('style', styleStr); + } + } + }, { + key: '_addToggleButton', + value: function _addToggleButton(div) { + var _this2 = this; + + var toggler = document.createElement('div'); + toggler.className = 'outlineItemToggler'; + toggler.onclick = function (evt) { + evt.stopPropagation(); + toggler.classList.toggle('outlineItemsHidden'); + if (evt.shiftKey) { + var shouldShowAll = !toggler.classList.contains('outlineItemsHidden'); + _this2._toggleOutlineItem(div, shouldShowAll); + } + }; + div.insertBefore(toggler, div.firstChild); + } + }, { + key: '_toggleOutlineItem', + value: function _toggleOutlineItem(root, show) { + this.lastToggleIsShow = show; + var togglers = root.querySelectorAll('.outlineItemToggler'); + for (var i = 0, ii = togglers.length; i < ii; ++i) { + togglers[i].classList[show ? 'remove' : 'add']('outlineItemsHidden'); + } + } + }, { + key: 'toggleOutlineTree', + value: function toggleOutlineTree() { + if (!this.outline) { + return; + } + this._toggleOutlineItem(this.container, !this.lastToggleIsShow); + } + }, { + key: 'render', + value: function render(_ref2) { + var outline = _ref2.outline; + + var outlineCount = 0; + if (this.outline) { + this.reset(); + } + this.outline = outline || null; + if (!outline) { + this._dispatchEvent(outlineCount); + return; + } + var fragment = document.createDocumentFragment(); + var queue = [{ + parent: fragment, + items: this.outline + }]; + var hasAnyNesting = false; + while (queue.length > 0) { + var levelData = queue.shift(); + for (var i = 0, len = levelData.items.length; i < len; i++) { + var item = levelData.items[i]; + var div = document.createElement('div'); + div.className = 'outlineItem'; + var element = document.createElement('a'); + this._bindLink(element, item); + this._setStyles(element, item); + element.textContent = (0, _pdfjsLib.removeNullCharacters)(item.title) || DEFAULT_TITLE; + div.appendChild(element); + if (item.items.length > 0) { + hasAnyNesting = true; + this._addToggleButton(div); + var itemsDiv = document.createElement('div'); + itemsDiv.className = 'outlineItems'; + div.appendChild(itemsDiv); + queue.push({ + parent: itemsDiv, + items: item.items + }); + } + levelData.parent.appendChild(div); + outlineCount++; + } + } + if (hasAnyNesting) { + this.container.classList.add('outlineWithDeepNesting'); + } + this.container.appendChild(fragment); + this._dispatchEvent(outlineCount); + } + }]); + + return PDFOutlineViewer; + }(); + + exports.PDFOutlineViewer = PDFOutlineViewer; + + /***/ + }), + /* 22 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFPageView = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _ui_utils = __webpack_require__(0); + + var _pdfjsLib = __webpack_require__(1); + + var _dom_events = __webpack_require__(2); + + var _pdf_rendering_queue = __webpack_require__(3); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var PDFPageView = function () { + function PDFPageView(options) { + _classCallCheck(this, PDFPageView); + + var container = options.container; + var defaultViewport = options.defaultViewport; + this.id = options.id; + this.renderingId = 'page' + this.id; + this.pdfPage = null; + this.pageLabel = null; + this.rotation = 0; + this.scale = options.scale || _ui_utils.DEFAULT_SCALE; + this.viewport = defaultViewport; + this.pdfPageRotate = defaultViewport.rotation; + this.hasRestrictedScaling = false; + this.enhanceTextSelection = options.enhanceTextSelection || false; + this.renderInteractiveForms = options.renderInteractiveForms || false; + this.eventBus = options.eventBus || (0, _dom_events.getGlobalEventBus)(); + this.renderingQueue = options.renderingQueue; + this.textLayerFactory = options.textLayerFactory; + this.annotationLayerFactory = options.annotationLayerFactory; + this.renderer = options.renderer || _ui_utils.RendererType.CANVAS; + this.l10n = options.l10n || _ui_utils.NullL10n; + this.paintTask = null; + this.paintedViewportMap = new WeakMap(); + this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL; + this.resume = null; + this.error = null; + this.onBeforeDraw = null; + this.onAfterDraw = null; + this.annotationLayer = null; + this.textLayer = null; + this.zoomLayer = null; + var 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); + this.div = div; + container.appendChild(div); + } + + _createClass(PDFPageView, [{ + key: 'setPdfPage', + value: function setPdfPage(pdfPage) { + this.pdfPage = pdfPage; + this.pdfPageRotate = pdfPage.rotate; + var totalRotation = (this.rotation + this.pdfPageRotate) % 360; + this.viewport = pdfPage.getViewport(this.scale * _ui_utils.CSS_UNITS, totalRotation); + this.stats = pdfPage.stats; + this.reset(); + } + }, { + key: 'destroy', + value: function destroy() { + this.reset(); + if (this.pdfPage) { + this.pdfPage.cleanup(); + this.pdfPage = null; + } + } + }, { + key: '_resetZoomLayer', + value: function _resetZoomLayer() { + var removeFromDOM = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + if (!this.zoomLayer) { + return; + } + var zoomLayerCanvas = this.zoomLayer.firstChild; + this.paintedViewportMap.delete(zoomLayerCanvas); + zoomLayerCanvas.width = 0; + zoomLayerCanvas.height = 0; + if (removeFromDOM) { + this.zoomLayer.remove(); + } + this.zoomLayer = null; + } + }, { + key: 'reset', + value: function reset() { + var keepZoomLayer = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + var keepAnnotations = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + this.cancelRendering(); + var div = this.div; + div.style.width = Math.floor(this.viewport.width) + 'px'; + div.style.height = Math.floor(this.viewport.height) + 'px'; + var childNodes = div.childNodes; + var currentZoomLayerNode = keepZoomLayer && this.zoomLayer || null; + var currentAnnotationNode = keepAnnotations && this.annotationLayer && this.annotationLayer.div || null; + for (var i = childNodes.length - 1; i >= 0; i--) { + var node = childNodes[i]; + if (currentZoomLayerNode === node || currentAnnotationNode === node) { + continue; + } + div.removeChild(node); + } + div.removeAttribute('data-loaded'); + if (currentAnnotationNode) { + this.annotationLayer.hide(); + } else { + this.annotationLayer = null; + } + if (!currentZoomLayerNode) { + if (this.canvas) { + this.paintedViewportMap.delete(this.canvas); + this.canvas.width = 0; + this.canvas.height = 0; + delete this.canvas; + } + this._resetZoomLayer(); + } + if (this.svg) { + this.paintedViewportMap.delete(this.svg); + delete this.svg; + } + this.loadingIconDiv = document.createElement('div'); + this.loadingIconDiv.className = 'loadingIcon'; + div.appendChild(this.loadingIconDiv); + } + }, { + key: 'update', + value: function update(scale, rotation) { + this.scale = scale || this.scale; + if (typeof rotation !== 'undefined') { + this.rotation = rotation; + } + var totalRotation = (this.rotation + this.pdfPageRotate) % 360; + this.viewport = this.viewport.clone({ + scale: this.scale * _ui_utils.CSS_UNITS, + rotation: totalRotation + }); + if (this.svg) { + this.cssTransform(this.svg, true); + this.eventBus.dispatch('pagerendered', { + source: this, + pageNumber: this.id, + cssTransform: true + }); + return; + } + var isScalingRestricted = false; + if (this.canvas && _pdfjsLib.PDFJS.maxCanvasPixels > 0) { + var outputScale = this.outputScale; + if ((Math.floor(this.viewport.width) * outputScale.sx | 0) * (Math.floor(this.viewport.height) * outputScale.sy | 0) > _pdfjsLib.PDFJS.maxCanvasPixels) { + isScalingRestricted = true; + } + } + if (this.canvas) { + if (_pdfjsLib.PDFJS.useOnlyCssZoom || this.hasRestrictedScaling && isScalingRestricted) { + this.cssTransform(this.canvas, true); + this.eventBus.dispatch('pagerendered', { + source: this, + pageNumber: this.id, + cssTransform: true + }); + return; + } + if (!this.zoomLayer && !this.canvas.hasAttribute('hidden')) { + this.zoomLayer = this.canvas.parentNode; + this.zoomLayer.style.position = 'absolute'; + } + } + if (this.zoomLayer) { + this.cssTransform(this.zoomLayer.firstChild); + } + this.reset(true, true); + } + }, { + key: 'cancelRendering', + value: function cancelRendering() { + if (this.paintTask) { + this.paintTask.cancel(); + this.paintTask = null; + } + this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL; + this.resume = null; + if (this.textLayer) { + this.textLayer.cancel(); + this.textLayer = null; + } + } + }, { + key: 'cssTransform', + value: function cssTransform(target) { + var redrawAnnotations = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + var width = this.viewport.width; + var height = this.viewport.height; + var div = this.div; + target.style.width = target.parentNode.style.width = div.style.width = Math.floor(width) + 'px'; + target.style.height = target.parentNode.style.height = div.style.height = Math.floor(height) + 'px'; + var relativeRotation = this.viewport.rotation - this.paintedViewportMap.get(target).rotation; + var absRotation = Math.abs(relativeRotation); + var scaleX = 1, + scaleY = 1; + if (absRotation === 90 || absRotation === 270) { + scaleX = height / width; + scaleY = width / height; + } + var cssTransform = 'rotate(' + relativeRotation + 'deg) ' + 'scale(' + scaleX + ',' + scaleY + ')'; + _pdfjsLib.CustomStyle.setProp('transform', target, cssTransform); + if (this.textLayer) { + var textLayerViewport = this.textLayer.viewport; + var textRelativeRotation = this.viewport.rotation - textLayerViewport.rotation; + var textAbsRotation = Math.abs(textRelativeRotation); + var scale = width / textLayerViewport.width; + if (textAbsRotation === 90 || textAbsRotation === 270) { + scale = width / textLayerViewport.height; + } + var textLayerDiv = this.textLayer.textLayerDiv; + var transX = void 0, + transY = void 0; + switch (textAbsRotation) { + case 0: + transX = transY = 0; + break; + case 90: + transX = 0; + transY = '-' + textLayerDiv.style.height; + break; + case 180: + transX = '-' + textLayerDiv.style.width; + transY = '-' + textLayerDiv.style.height; + break; + case 270: + transX = '-' + textLayerDiv.style.width; + transY = 0; + break; + default: + console.error('Bad rotation value.'); + break; + } + _pdfjsLib.CustomStyle.setProp('transform', textLayerDiv, 'rotate(' + textAbsRotation + 'deg) ' + 'scale(' + scale + ', ' + scale + ') ' + 'translate(' + transX + ', ' + transY + ')'); + _pdfjsLib.CustomStyle.setProp('transformOrigin', textLayerDiv, '0% 0%'); + } + if (redrawAnnotations && this.annotationLayer) { + this.annotationLayer.render(this.viewport, 'display'); + } + } + }, { + key: 'getPagePoint', + value: function getPagePoint(x, y) { + return this.viewport.convertToPdfPoint(x, y); + } + }, { + key: 'draw', + value: function draw() { + var _this = this; + + if (this.renderingState !== _pdf_rendering_queue.RenderingStates.INITIAL) { + console.error('Must be in new state before drawing'); + this.reset(); + } + if (!this.pdfPage) { + this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; + return Promise.reject(new Error('Page is not loaded')); + } + this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING; + var pdfPage = this.pdfPage; + var div = this.div; + var canvasWrapper = document.createElement('div'); + canvasWrapper.style.width = div.style.width; + canvasWrapper.style.height = div.style.height; + canvasWrapper.classList.add('canvasWrapper'); + if (this.annotationLayer && this.annotationLayer.div) { + div.insertBefore(canvasWrapper, this.annotationLayer.div); + } else { + div.appendChild(canvasWrapper); + } + var textLayer = null; + if (this.textLayerFactory) { + var 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); + } else { + div.appendChild(textLayerDiv); + } + textLayer = this.textLayerFactory.createTextLayerBuilder(textLayerDiv, this.id - 1, this.viewport, this.enhanceTextSelection); + } + this.textLayer = textLayer; + var renderContinueCallback = null; + if (this.renderingQueue) { + renderContinueCallback = function renderContinueCallback(cont) { + if (!_this.renderingQueue.isHighestPriority(_this)) { + _this.renderingState = _pdf_rendering_queue.RenderingStates.PAUSED; + _this.resume = function () { + _this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING; + cont(); + }; + return; + } + cont(); + }; + } + var finishPaintTask = function finishPaintTask(error) { + if (paintTask === _this.paintTask) { + _this.paintTask = null; + } + if (error === 'cancelled' || error instanceof _pdfjsLib.RenderingCancelledException) { + _this.error = null; + return Promise.resolve(undefined); + } + _this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; + if (_this.loadingIconDiv) { + div.removeChild(_this.loadingIconDiv); + delete _this.loadingIconDiv; + } + _this._resetZoomLayer(true); + _this.error = error; + _this.stats = pdfPage.stats; + if (_this.onAfterDraw) { + _this.onAfterDraw(); + } + _this.eventBus.dispatch('pagerendered', { + source: _this, + pageNumber: _this.id, + cssTransform: false + }); + if (error) { + return Promise.reject(error); + } + return Promise.resolve(undefined); + }; + var paintTask = this.renderer === _ui_utils.RendererType.SVG ? this.paintOnSvg(canvasWrapper) : this.paintOnCanvas(canvasWrapper); + paintTask.onRenderContinue = renderContinueCallback; + this.paintTask = paintTask; + var resultPromise = paintTask.promise.then(function () { + return finishPaintTask(null).then(function () { + if (textLayer) { + var readableStream = pdfPage.streamTextContent({normalizeWhitespace: true}); + textLayer.setTextContentStream(readableStream); + textLayer.render(); + } + }); + }, function (reason) { + return finishPaintTask(reason); + }); + if (this.annotationLayerFactory) { + if (!this.annotationLayer) { + this.annotationLayer = this.annotationLayerFactory.createAnnotationLayerBuilder(div, pdfPage, this.renderInteractiveForms, this.l10n); + } + this.annotationLayer.render(this.viewport, 'display'); + } + div.setAttribute('data-loaded', true); + if (this.onBeforeDraw) { + this.onBeforeDraw(); + } + return resultPromise; + } + }, { + key: 'paintOnCanvas', + value: function paintOnCanvas(canvasWrapper) { + var renderCapability = (0, _pdfjsLib.createPromiseCapability)(); + var result = { + promise: renderCapability.promise, + onRenderContinue: function onRenderContinue(cont) { + cont(); + }, + cancel: function cancel() { + renderTask.cancel(); + } + }; + var viewport = this.viewport; + var canvas = document.createElement('canvas'); + canvas.id = this.renderingId; + canvas.setAttribute('hidden', 'hidden'); + var isCanvasHidden = true; + var showCanvas = function showCanvas() { + if (isCanvasHidden) { + canvas.removeAttribute('hidden'); + isCanvasHidden = false; + } + }; + canvasWrapper.appendChild(canvas); + this.canvas = canvas; + canvas.mozOpaque = true; + var ctx = canvas.getContext('2d', {alpha: false}); + var outputScale = (0, _ui_utils.getOutputScale)(ctx); + this.outputScale = outputScale; + if (_pdfjsLib.PDFJS.useOnlyCssZoom) { + var actualSizeViewport = viewport.clone({scale: _ui_utils.CSS_UNITS}); + outputScale.sx *= actualSizeViewport.width / viewport.width; + outputScale.sy *= actualSizeViewport.height / viewport.height; + outputScale.scaled = true; + } + if (_pdfjsLib.PDFJS.maxCanvasPixels > 0) { + var pixelsInViewport = viewport.width * viewport.height; + var maxScale = Math.sqrt(_pdfjsLib.PDFJS.maxCanvasPixels / pixelsInViewport); + if (outputScale.sx > maxScale || outputScale.sy > maxScale) { + outputScale.sx = maxScale; + outputScale.sy = maxScale; + outputScale.scaled = true; + this.hasRestrictedScaling = true; + } else { + this.hasRestrictedScaling = false; + } + } + var sfx = (0, _ui_utils.approximateFraction)(outputScale.sx); + var sfy = (0, _ui_utils.approximateFraction)(outputScale.sy); + canvas.width = (0, _ui_utils.roundToDivide)(viewport.width * outputScale.sx, sfx[0]); + canvas.height = (0, _ui_utils.roundToDivide)(viewport.height * outputScale.sy, sfy[0]); + 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); + var transform = !outputScale.scaled ? null : [outputScale.sx, 0, 0, outputScale.sy, 0, 0]; + var renderContext = { + canvasContext: ctx, + transform: transform, + viewport: this.viewport, + renderInteractiveForms: this.renderInteractiveForms + }; + var renderTask = this.pdfPage.render(renderContext); + renderTask.onContinue = function (cont) { + showCanvas(); + if (result.onRenderContinue) { + result.onRenderContinue(cont); + } else { + cont(); + } + }; + renderTask.promise.then(function () { + showCanvas(); + renderCapability.resolve(undefined); + }, function (error) { + showCanvas(); + renderCapability.reject(error); + }); + return result; + } + }, { + key: 'paintOnSvg', + value: function paintOnSvg(wrapper) { + var _this2 = this; + + var cancelled = false; + var ensureNotCancelled = function ensureNotCancelled() { + if (cancelled) { + if (_pdfjsLib.PDFJS.pdfjsNext) { + throw new _pdfjsLib.RenderingCancelledException('Rendering cancelled, page ' + _this2.id, 'svg'); + } else { + throw 'cancelled'; + } + } + }; + var pdfPage = this.pdfPage; + var actualSizeViewport = this.viewport.clone({scale: _ui_utils.CSS_UNITS}); + var promise = pdfPage.getOperatorList().then(function (opList) { + ensureNotCancelled(); + var svgGfx = new _pdfjsLib.SVGGraphics(pdfPage.commonObjs, pdfPage.objs); + return svgGfx.getSVG(opList, actualSizeViewport).then(function (svg) { + ensureNotCancelled(); + _this2.svg = svg; + _this2.paintedViewportMap.set(svg, actualSizeViewport); + svg.style.width = wrapper.style.width; + svg.style.height = wrapper.style.height; + _this2.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; + wrapper.appendChild(svg); + }); + }); + return { + promise: promise, + onRenderContinue: function onRenderContinue(cont) { + cont(); + }, + cancel: function cancel() { + cancelled = true; + } + }; + } + }, { + key: 'setPageLabel', + value: function setPageLabel(label) { + this.pageLabel = typeof label === 'string' ? label : null; + if (this.pageLabel !== null) { + this.div.setAttribute('data-page-label', this.pageLabel); + } else { + this.div.removeAttribute('data-page-label'); + } + } + }, { + key: 'width', + get: function get() { + return this.viewport.width; + } + }, { + key: 'height', + get: function get() { + return this.viewport.height; + } + }]); + + return PDFPageView; + }(); + + exports.PDFPageView = PDFPageView; + + /***/ + }), + /* 23 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFPresentationMode = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _ui_utils = __webpack_require__(0); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS = 1500; + var DELAY_BEFORE_HIDING_CONTROLS = 3000; + var ACTIVE_SELECTOR = 'pdfPresentationMode'; + var CONTROLS_SELECTOR = 'pdfPresentationModeControls'; + var MOUSE_SCROLL_COOLDOWN_TIME = 50; + var PAGE_SWITCH_THRESHOLD = 0.1; + var SWIPE_MIN_DISTANCE_THRESHOLD = 50; + var SWIPE_ANGLE_THRESHOLD = Math.PI / 6; + + var PDFPresentationMode = function () { + function PDFPresentationMode(_ref) { + var _this = this; + + var container = _ref.container, + _ref$viewer = _ref.viewer, + viewer = _ref$viewer === undefined ? null : _ref$viewer, + pdfViewer = _ref.pdfViewer, + eventBus = _ref.eventBus, + _ref$contextMenuItems = _ref.contextMenuItems, + contextMenuItems = _ref$contextMenuItems === undefined ? null : _ref$contextMenuItems; + + _classCallCheck(this, PDFPresentationMode); + + this.container = container; + this.viewer = viewer || container.firstElementChild; + 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', function () { + _this.contextMenuOpen = false; + _this.eventBus.dispatch('firstpage'); + }); + contextMenuItems.contextLastPage.addEventListener('click', function () { + _this.contextMenuOpen = false; + _this.eventBus.dispatch('lastpage'); + }); + contextMenuItems.contextPageRotateCw.addEventListener('click', function () { + _this.contextMenuOpen = false; + _this.eventBus.dispatch('rotatecw'); + }); + contextMenuItems.contextPageRotateCcw.addEventListener('click', function () { + _this.contextMenuOpen = false; + _this.eventBus.dispatch('rotateccw'); + }); + } + } + + _createClass(PDFPresentationMode, [{ + key: 'request', + value: function request() { + if (this.switchInProgress || this.active || !this.viewer.hasChildNodes()) { + 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 + }; + return true; + } + }, { + key: '_mouseWheel', + value: function _mouseWheel(evt) { + if (!this.active) { + return; + } + evt.preventDefault(); + var delta = (0, _ui_utils.normalizeWheelEventDelta)(evt); + var currentTime = new Date().getTime(); + var storedTime = this.mouseScrollTimeStamp; + if (currentTime > storedTime && currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) { + return; + } + if (this.mouseScrollDelta > 0 && delta < 0 || this.mouseScrollDelta < 0 && delta > 0) { + this._resetMouseScrollState(); + } + this.mouseScrollDelta += delta; + if (Math.abs(this.mouseScrollDelta) >= PAGE_SWITCH_THRESHOLD) { + var totalDelta = this.mouseScrollDelta; + this._resetMouseScrollState(); + var success = totalDelta > 0 ? this._goToPreviousPage() : this._goToNextPage(); + if (success) { + this.mouseScrollTimeStamp = currentTime; + } + } + } + }, { + key: '_goToPreviousPage', + value: function _goToPreviousPage() { + var page = this.pdfViewer.currentPageNumber; + if (page <= 1) { + return false; + } + this.pdfViewer.currentPageNumber = page - 1; + return true; + } + }, { + key: '_goToNextPage', + value: function _goToNextPage() { + var page = this.pdfViewer.currentPageNumber; + if (page >= this.pdfViewer.pagesCount) { + return false; + } + this.pdfViewer.currentPageNumber = page + 1; + return true; + } + }, { + key: '_notifyStateChange', + value: function _notifyStateChange() { + this.eventBus.dispatch('presentationmodechanged', { + source: this, + active: this.active, + switchInProgress: !!this.switchInProgress + }); + } + }, { + key: '_setSwitchInProgress', + value: function _setSwitchInProgress() { + var _this2 = this; + + if (this.switchInProgress) { + clearTimeout(this.switchInProgress); + } + this.switchInProgress = setTimeout(function () { + _this2._removeFullscreenChangeListeners(); + delete _this2.switchInProgress; + _this2._notifyStateChange(); + }, DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS); + } + }, { + key: '_resetSwitchInProgress', + value: function _resetSwitchInProgress() { + if (this.switchInProgress) { + clearTimeout(this.switchInProgress); + delete this.switchInProgress; + } + } + }, { + key: '_enter', + value: function _enter() { + var _this3 = this; + + this.active = true; + this._resetSwitchInProgress(); + this._notifyStateChange(); + this.container.classList.add(ACTIVE_SELECTOR); + setTimeout(function () { + _this3.pdfViewer.currentPageNumber = _this3.args.page; + _this3.pdfViewer.currentScaleValue = 'page-fit'; + }, 0); + this._addWindowListeners(); + this._showControls(); + this.contextMenuOpen = false; + this.container.setAttribute('contextmenu', 'viewerContextMenu'); + window.getSelection().removeAllRanges(); + } + }, { + key: '_exit', + value: function _exit() { + var _this4 = this; + + var page = this.pdfViewer.currentPageNumber; + this.container.classList.remove(ACTIVE_SELECTOR); + setTimeout(function () { + _this4.active = false; + _this4._removeFullscreenChangeListeners(); + _this4._notifyStateChange(); + _this4.pdfViewer.currentScaleValue = _this4.args.previousScale; + _this4.pdfViewer.currentPageNumber = page; + _this4.args = null; + }, 0); + this._removeWindowListeners(); + this._hideControls(); + this._resetMouseScrollState(); + this.container.removeAttribute('contextmenu'); + this.contextMenuOpen = false; + } + }, { + key: '_mouseDown', + value: function _mouseDown(evt) { + if (this.contextMenuOpen) { + this.contextMenuOpen = false; + evt.preventDefault(); + return; + } + if (evt.button === 0) { + var isInternalLink = evt.target.href && evt.target.classList.contains('internalLink'); + if (!isInternalLink) { + evt.preventDefault(); + if (evt.shiftKey) { + this._goToPreviousPage(); + } else { + this._goToNextPage(); + } + } + } + } + }, { + key: '_contextMenu', + value: function _contextMenu() { + this.contextMenuOpen = true; + } + }, { + key: '_showControls', + value: function _showControls() { + var _this5 = this; + + if (this.controlsTimeout) { + clearTimeout(this.controlsTimeout); + } else { + this.container.classList.add(CONTROLS_SELECTOR); + } + this.controlsTimeout = setTimeout(function () { + _this5.container.classList.remove(CONTROLS_SELECTOR); + delete _this5.controlsTimeout; + }, DELAY_BEFORE_HIDING_CONTROLS); + } + }, { + key: '_hideControls', + value: function _hideControls() { + if (!this.controlsTimeout) { + return; + } + clearTimeout(this.controlsTimeout); + this.container.classList.remove(CONTROLS_SELECTOR); + delete this.controlsTimeout; + } + }, { + key: '_resetMouseScrollState', + value: function _resetMouseScrollState() { + this.mouseScrollTimeStamp = 0; + this.mouseScrollDelta = 0; + } + }, { + key: '_touchSwipe', + value: function _touchSwipe(evt) { + if (!this.active) { + return; + } + if (evt.touches.length > 1) { + this.touchSwipeState = null; + return; + } + switch (evt.type) { + case 'touchstart': + this.touchSwipeState = { + startX: evt.touches[0].pageX, + startY: evt.touches[0].pageY, + endX: evt.touches[0].pageX, + endY: evt.touches[0].pageY + }; + break; + case 'touchmove': + if (this.touchSwipeState === null) { + return; + } + this.touchSwipeState.endX = evt.touches[0].pageX; + this.touchSwipeState.endY = evt.touches[0].pageY; + evt.preventDefault(); + break; + case 'touchend': + if (this.touchSwipeState === null) { + return; + } + var delta = 0; + var dx = this.touchSwipeState.endX - this.touchSwipeState.startX; + var dy = this.touchSwipeState.endY - this.touchSwipeState.startY; + var absAngle = Math.abs(Math.atan2(dy, dx)); + if (Math.abs(dx) > SWIPE_MIN_DISTANCE_THRESHOLD && (absAngle <= SWIPE_ANGLE_THRESHOLD || absAngle >= Math.PI - SWIPE_ANGLE_THRESHOLD)) { + delta = dx; + } else if (Math.abs(dy) > SWIPE_MIN_DISTANCE_THRESHOLD && Math.abs(absAngle - Math.PI / 2) <= SWIPE_ANGLE_THRESHOLD) { + delta = dy; + } + if (delta > 0) { + this._goToPreviousPage(); + } else if (delta < 0) { + this._goToNextPage(); + } + break; + } + } + }, { + key: '_addWindowListeners', + value: function _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); + window.addEventListener('keydown', this.resetMouseScrollStateBind); + window.addEventListener('contextmenu', this.contextMenuBind); + window.addEventListener('touchstart', this.touchSwipeBind); + window.addEventListener('touchmove', this.touchSwipeBind); + window.addEventListener('touchend', this.touchSwipeBind); + } + }, { + key: '_removeWindowListeners', + value: function _removeWindowListeners() { + window.removeEventListener('mousemove', this.showControlsBind); + window.removeEventListener('mousedown', this.mouseDownBind); + window.removeEventListener('wheel', this.mouseWheelBind); + window.removeEventListener('keydown', this.resetMouseScrollStateBind); + window.removeEventListener('contextmenu', this.contextMenuBind); + window.removeEventListener('touchstart', this.touchSwipeBind); + window.removeEventListener('touchmove', this.touchSwipeBind); + window.removeEventListener('touchend', this.touchSwipeBind); + delete this.showControlsBind; + delete this.mouseDownBind; + delete this.mouseWheelBind; + delete this.resetMouseScrollStateBind; + delete this.contextMenuBind; + delete this.touchSwipeBind; + } + }, { + key: '_fullscreenChange', + value: function _fullscreenChange() { + if (this.isFullscreen) { + this._enter(); + } else { + this._exit(); + } + } + }, { + key: '_addFullscreenChangeListeners', + value: function _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); + } + }, { + key: '_removeFullscreenChangeListeners', + value: function _removeFullscreenChangeListeners() { + window.removeEventListener('fullscreenchange', this.fullscreenChangeBind); + window.removeEventListener('mozfullscreenchange', this.fullscreenChangeBind); + window.removeEventListener('webkitfullscreenchange', this.fullscreenChangeBind); + window.removeEventListener('MSFullscreenChange', this.fullscreenChangeBind); + delete this.fullscreenChangeBind; + } + }, { + key: 'isFullscreen', + get: function get() { + return !!(document.fullscreenElement || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement); + } + }]); + + return PDFPresentationMode; + }(); + + exports.PDFPresentationMode = PDFPresentationMode; + + /***/ + }), + /* 24 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFSidebar = exports.SidebarView = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _ui_utils = __webpack_require__(0); + + var _pdf_rendering_queue = __webpack_require__(3); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var UI_NOTIFICATION_CLASS = 'pdfSidebarNotification'; + var SidebarView = { + NONE: 0, + THUMBS: 1, + OUTLINE: 2, + ATTACHMENTS: 3 + }; + + var PDFSidebar = function () { + function PDFSidebar(options) { + var l10n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _ui_utils.NullL10n; + + _classCallCheck(this, PDFSidebar); + + this.isOpen = false; + this.active = SidebarView.THUMBS; + this.isInitialViewSet = false; + this.onToggled = null; + this.pdfViewer = options.pdfViewer; + this.pdfThumbnailViewer = options.pdfThumbnailViewer; + this.pdfOutlineViewer = options.pdfOutlineViewer; + this.mainContainer = options.mainContainer; + this.outerContainer = options.outerContainer; + this.eventBus = options.eventBus; + this.toggleButton = options.toggleButton; + this.thumbnailButton = options.thumbnailButton; + this.outlineButton = options.outlineButton; + this.attachmentsButton = options.attachmentsButton; + this.thumbnailView = options.thumbnailView; + this.outlineView = options.outlineView; + this.attachmentsView = options.attachmentsView; + this.disableNotification = options.disableNotification || false; + this.l10n = l10n; + this._addEventListeners(); + } + + _createClass(PDFSidebar, [{ + key: 'reset', + value: function reset() { + this.isInitialViewSet = false; + this._hideUINotification(null); + this.switchView(SidebarView.THUMBS); + this.outlineButton.disabled = false; + this.attachmentsButton.disabled = false; + } + }, { + key: 'setInitialView', + value: function setInitialView(view) { + if (this.isInitialViewSet) { + return; + } + this.isInitialViewSet = true; + if (this.isOpen && view === SidebarView.NONE) { + this._dispatchEvent(); + return; + } + var isViewPreserved = view === this.visibleView; + this.switchView(view, true); + if (isViewPreserved) { + this._dispatchEvent(); + } + } + }, { + key: 'switchView', + value: function switchView(view) { + var forceOpen = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (view === SidebarView.NONE) { + this.close(); + return; + } + var isViewChanged = view !== this.active; + var shouldForceRendering = false; + switch (view) { + case SidebarView.THUMBS: + this.thumbnailButton.classList.add('toggled'); + this.outlineButton.classList.remove('toggled'); + this.attachmentsButton.classList.remove('toggled'); + this.thumbnailView.classList.remove('hidden'); + this.outlineView.classList.add('hidden'); + this.attachmentsView.classList.add('hidden'); + if (this.isOpen && isViewChanged) { + this._updateThumbnailViewer(); + shouldForceRendering = true; + } + break; + case SidebarView.OUTLINE: + if (this.outlineButton.disabled) { + return; + } + this.thumbnailButton.classList.remove('toggled'); + this.outlineButton.classList.add('toggled'); + this.attachmentsButton.classList.remove('toggled'); + this.thumbnailView.classList.add('hidden'); + this.outlineView.classList.remove('hidden'); + this.attachmentsView.classList.add('hidden'); + break; + case SidebarView.ATTACHMENTS: + if (this.attachmentsButton.disabled) { + return; + } + this.thumbnailButton.classList.remove('toggled'); + this.outlineButton.classList.remove('toggled'); + this.attachmentsButton.classList.add('toggled'); + this.thumbnailView.classList.add('hidden'); + this.outlineView.classList.add('hidden'); + this.attachmentsView.classList.remove('hidden'); + break; + default: + console.error('PDFSidebar_switchView: "' + view + '" is an unsupported value.'); + return; + } + this.active = view | 0; + if (forceOpen && !this.isOpen) { + this.open(); + return; + } + if (shouldForceRendering) { + this._forceRendering(); + } + if (isViewChanged) { + this._dispatchEvent(); + } + this._hideUINotification(this.active); + } + }, { + key: 'open', + value: function open() { + if (this.isOpen) { + return; + } + this.isOpen = true; + this.toggleButton.classList.add('toggled'); + this.outerContainer.classList.add('sidebarMoving'); + this.outerContainer.classList.add('sidebarOpen'); + if (this.active === SidebarView.THUMBS) { + this._updateThumbnailViewer(); + } + this._forceRendering(); + this._dispatchEvent(); + this._hideUINotification(this.active); + } + }, { + key: 'close', + value: function 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(); + } + }, { + key: 'toggle', + value: function toggle() { + if (this.isOpen) { + this.close(); + } else { + this.open(); + } + } + }, { + key: '_dispatchEvent', + value: function _dispatchEvent() { + this.eventBus.dispatch('sidebarviewchanged', { + source: this, + view: this.visibleView + }); + } + }, { + key: '_forceRendering', + value: function _forceRendering() { + if (this.onToggled) { + this.onToggled(); + } else { + this.pdfViewer.forceRendering(); + this.pdfThumbnailViewer.forceRendering(); + } + } + }, { + key: '_updateThumbnailViewer', + value: function _updateThumbnailViewer() { + var pdfViewer = this.pdfViewer, + pdfThumbnailViewer = this.pdfThumbnailViewer; + + var pagesCount = pdfViewer.pagesCount; + for (var pageIndex = 0; pageIndex < pagesCount; pageIndex++) { + var pageView = pdfViewer.getPageView(pageIndex); + if (pageView && pageView.renderingState === _pdf_rendering_queue.RenderingStates.FINISHED) { + var thumbnailView = pdfThumbnailViewer.getThumbnail(pageIndex); + thumbnailView.setImage(pageView); + } + } + pdfThumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber); + } + }, { + key: '_showUINotification', + value: function _showUINotification(view) { + var _this = this; + + if (this.disableNotification) { + return; + } + this.l10n.get('toggle_sidebar_notification.title', null, 'Toggle Sidebar (document contains outline/attachments)').then(function (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; + } + } + }, { + key: '_hideUINotification', + value: function _hideUINotification(view) { + var _this2 = this; + + if (this.disableNotification) { + return; + } + var removeNotification = function removeNotification(view) { + switch (view) { + case SidebarView.OUTLINE: + _this2.outlineButton.classList.remove(UI_NOTIFICATION_CLASS); + break; + case SidebarView.ATTACHMENTS: + _this2.attachmentsButton.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(function (msg) { + _this2.toggleButton.title = msg; + }); + } + }, { + key: '_addEventListeners', + value: function _addEventListeners() { + var _this3 = this; + + this.mainContainer.addEventListener('transitionend', function (evt) { + if (evt.target === _this3.mainContainer) { + _this3.outerContainer.classList.remove('sidebarMoving'); + } + }); + this.thumbnailButton.addEventListener('click', function () { + _this3.switchView(SidebarView.THUMBS); + }); + this.outlineButton.addEventListener('click', function () { + _this3.switchView(SidebarView.OUTLINE); + }); + this.outlineButton.addEventListener('dblclick', function () { + _this3.pdfOutlineViewer.toggleOutlineTree(); + }); + this.attachmentsButton.addEventListener('click', function () { + _this3.switchView(SidebarView.ATTACHMENTS); + }); + this.eventBus.on('outlineloaded', function (evt) { + var outlineCount = evt.outlineCount; + _this3.outlineButton.disabled = !outlineCount; + if (outlineCount) { + _this3._showUINotification(SidebarView.OUTLINE); + } else if (_this3.active === SidebarView.OUTLINE) { + _this3.switchView(SidebarView.THUMBS); + } + }); + this.eventBus.on('attachmentsloaded', function (evt) { + var attachmentsCount = evt.attachmentsCount; + _this3.attachmentsButton.disabled = !attachmentsCount; + if (attachmentsCount) { + _this3._showUINotification(SidebarView.ATTACHMENTS); + } else if (_this3.active === SidebarView.ATTACHMENTS) { + _this3.switchView(SidebarView.THUMBS); + } + }); + this.eventBus.on('presentationmodechanged', function (evt) { + if (!evt.active && !evt.switchInProgress && _this3.isThumbnailViewVisible) { + _this3._updateThumbnailViewer(); + } + }); + } + }, { + key: 'visibleView', + get: function get() { + return this.isOpen ? this.active : SidebarView.NONE; + } + }, { + key: 'isThumbnailViewVisible', + get: function get() { + return this.isOpen && this.active === SidebarView.THUMBS; + } + }, { + key: 'isOutlineViewVisible', + get: function get() { + return this.isOpen && this.active === SidebarView.OUTLINE; + } + }, { + key: 'isAttachmentsViewVisible', + get: function get() { + return this.isOpen && this.active === SidebarView.ATTACHMENTS; + } + }]); + + return PDFSidebar; + }(); + + exports.SidebarView = SidebarView; + exports.PDFSidebar = PDFSidebar; + + /***/ + }), + /* 25 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFThumbnailView = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _pdfjsLib = __webpack_require__(1); + + var _ui_utils = __webpack_require__(0); + + var _pdf_rendering_queue = __webpack_require__(3); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var MAX_NUM_SCALING_STEPS = 3; + var THUMBNAIL_CANVAS_BORDER_WIDTH = 1; + var THUMBNAIL_WIDTH = 98; + var TempImageFactory = function TempImageFactoryClosure() { + var tempCanvasCache = null; + return { + getCanvas: function getCanvas(width, height) { + var tempCanvas = tempCanvasCache; + if (!tempCanvas) { + tempCanvas = document.createElement('canvas'); + tempCanvasCache = tempCanvas; + } + tempCanvas.width = width; + tempCanvas.height = height; + tempCanvas.mozOpaque = true; + var ctx = tempCanvas.getContext('2d', {alpha: false}); + ctx.save(); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, width, height); + ctx.restore(); + return tempCanvas; + }, + destroyCanvas: function destroyCanvas() { + var tempCanvas = tempCanvasCache; + if (tempCanvas) { + tempCanvas.width = 0; + tempCanvas.height = 0; + } + tempCanvasCache = null; + } + }; + }(); + + var PDFThumbnailView = function () { + function PDFThumbnailView(_ref) { + var container = _ref.container, + id = _ref.id, + defaultViewport = _ref.defaultViewport, + linkService = _ref.linkService, + renderingQueue = _ref.renderingQueue, + _ref$disableCanvasToI = _ref.disableCanvasToImageConversion, + disableCanvasToImageConversion = _ref$disableCanvasToI === undefined ? false : _ref$disableCanvasToI, + _ref$l10n = _ref.l10n, + l10n = _ref$l10n === undefined ? _ui_utils.NullL10n : _ref$l10n; + + _classCallCheck(this, PDFThumbnailView); + + this.id = id; + this.renderingId = 'thumbnail' + id; + this.pageLabel = null; + this.pdfPage = null; + this.rotation = 0; + this.viewport = defaultViewport; + this.pdfPageRotate = defaultViewport.rotation; + this.linkService = linkService; + this.renderingQueue = renderingQueue; + this.renderTask = null; + this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL; + this.resume = null; + this.disableCanvasToImageConversion = disableCanvasToImageConversion; + this.pageWidth = this.viewport.width; + this.pageHeight = this.viewport.height; + this.pageRatio = this.pageWidth / this.pageHeight; + this.canvasWidth = THUMBNAIL_WIDTH; + this.canvasHeight = this.canvasWidth / this.pageRatio | 0; + this.scale = this.canvasWidth / this.pageWidth; + this.l10n = l10n; + var anchor = document.createElement('a'); + anchor.href = linkService.getAnchorUrl('#page=' + id); + this.l10n.get('thumb_page_title', {page: id}, 'Page {{page}}').then(function (msg) { + anchor.title = msg; + }); + anchor.onclick = function () { + linkService.page = id; + return false; + }; + this.anchor = anchor; + var div = document.createElement('div'); + div.className = 'thumbnail'; + div.setAttribute('data-page-number', this.id); + this.div = div; + if (id === 1) { + div.classList.add('selected'); + } + var ring = document.createElement('div'); + ring.className = 'thumbnailSelectionRing'; + var borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH; + 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); + } + + _createClass(PDFThumbnailView, [{ + key: 'setPdfPage', + value: function setPdfPage(pdfPage) { + this.pdfPage = pdfPage; + this.pdfPageRotate = pdfPage.rotate; + var totalRotation = (this.rotation + this.pdfPageRotate) % 360; + this.viewport = pdfPage.getViewport(1, totalRotation); + this.reset(); + } + }, { + key: 'reset', + value: function reset() { + this.cancelRendering(); + 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.div.removeAttribute('data-loaded'); + var ring = this.ring; + var childNodes = ring.childNodes; + for (var i = childNodes.length - 1; i >= 0; i--) { + ring.removeChild(childNodes[i]); + } + var borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH; + ring.style.width = this.canvasWidth + borderAdjustment + 'px'; + ring.style.height = this.canvasHeight + borderAdjustment + 'px'; + if (this.canvas) { + this.canvas.width = 0; + this.canvas.height = 0; + delete this.canvas; + } + if (this.image) { + this.image.removeAttribute('src'); + delete this.image; + } + } + }, { + key: 'update', + value: function update(rotation) { + if (typeof rotation !== 'undefined') { + this.rotation = rotation; + } + var totalRotation = (this.rotation + this.pdfPageRotate) % 360; + this.viewport = this.viewport.clone({ + scale: 1, + rotation: totalRotation + }); + this.reset(); + } + }, { + key: 'cancelRendering', + value: function cancelRendering() { + if (this.renderTask) { + this.renderTask.cancel(); + this.renderTask = null; + } + this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL; + this.resume = null; + } + }, { + key: '_getPageDrawContext', + value: function _getPageDrawContext() { + var noCtxScale = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + var canvas = document.createElement('canvas'); + this.canvas = canvas; + canvas.mozOpaque = true; + var ctx = canvas.getContext('2d', {alpha: false}); + var 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; + } + }, { + key: '_convertCanvasToImage', + value: function _convertCanvasToImage() { + var _this = this; + + if (!this.canvas) { + return; + } + if (this.renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED) { + return; + } + var id = this.renderingId; + var className = 'thumbnailImage'; + if (this.disableCanvasToImageConversion) { + this.canvas.id = id; + this.canvas.className = className; + this.l10n.get('thumb_page_canvas', {page: this.pageId}, 'Thumbnail of Page {{page}}').then(function (msg) { + _this.canvas.setAttribute('aria-label', msg); + }); + this.div.setAttribute('data-loaded', true); + this.ring.appendChild(this.canvas); + return; + } + var image = document.createElement('img'); + image.id = id; + image.className = className; + this.l10n.get('thumb_page_canvas', {page: this.pageId}, 'Thumbnail of Page {{page}}').then(function (msg) { + image.setAttribute('aria-label', msg); + }); + image.style.width = this.canvasWidth + 'px'; + image.style.height = this.canvasHeight + 'px'; + image.src = this.canvas.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; + } + }, { + key: 'draw', + value: function draw() { + var _this2 = this; + + if (this.renderingState !== _pdf_rendering_queue.RenderingStates.INITIAL) { + console.error('Must be in new state before drawing'); + return Promise.resolve(undefined); + } + this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING; + var renderCapability = (0, _pdfjsLib.createPromiseCapability)(); + var finishRenderTask = function finishRenderTask(error) { + if (renderTask === _this2.renderTask) { + _this2.renderTask = null; + } + if (error === 'cancelled' || error instanceof _pdfjsLib.RenderingCancelledException) { + renderCapability.resolve(undefined); + return; + } + _this2.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; + _this2._convertCanvasToImage(); + if (!error) { + renderCapability.resolve(undefined); + } else { + renderCapability.reject(error); + } + }; + var ctx = this._getPageDrawContext(); + var drawViewport = this.viewport.clone({scale: this.scale}); + var renderContinueCallback = function renderContinueCallback(cont) { + if (!_this2.renderingQueue.isHighestPriority(_this2)) { + _this2.renderingState = _pdf_rendering_queue.RenderingStates.PAUSED; + _this2.resume = function () { + _this2.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING; + cont(); + }; + return; + } + cont(); + }; + var renderContext = { + canvasContext: ctx, + viewport: drawViewport + }; + var renderTask = this.renderTask = this.pdfPage.render(renderContext); + renderTask.onContinue = renderContinueCallback; + renderTask.promise.then(function () { + finishRenderTask(null); + }, function (error) { + finishRenderTask(error); + }); + return renderCapability.promise; + } + }, { + key: 'setImage', + value: function setImage(pageView) { + if (this.renderingState !== _pdf_rendering_queue.RenderingStates.INITIAL) { + return; + } + var img = pageView.canvas; + if (!img) { + return; + } + if (!this.pdfPage) { + this.setPdfPage(pageView.pdfPage); + } + this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; + var ctx = this._getPageDrawContext(true); + var canvas = ctx.canvas; + if (img.width <= 2 * canvas.width) { + ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height); + this._convertCanvasToImage(); + return; + } + var reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS; + var reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS; + var reducedImage = TempImageFactory.getCanvas(reducedWidth, reducedHeight); + var reducedImageCtx = reducedImage.getContext('2d'); + while (reducedWidth > img.width || reducedHeight > img.height) { + reducedWidth >>= 1; + reducedHeight >>= 1; + } + reducedImageCtx.drawImage(img, 0, 0, img.width, img.height, 0, 0, reducedWidth, reducedHeight); + while (reducedWidth > 2 * canvas.width) { + reducedImageCtx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, reducedWidth >> 1, reducedHeight >> 1); + reducedWidth >>= 1; + reducedHeight >>= 1; + } + ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, canvas.width, canvas.height); + this._convertCanvasToImage(); + } + }, { + key: 'setPageLabel', + value: function setPageLabel(label) { + var _this3 = this; + + this.pageLabel = typeof label === 'string' ? label : null; + this.l10n.get('thumb_page_title', {page: this.pageId}, 'Page {{page}}').then(function (msg) { + _this3.anchor.title = msg; + }); + if (this.renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED) { + return; + } + this.l10n.get('thumb_page_canvas', {page: this.pageId}, 'Thumbnail of Page {{page}}').then(function (ariaLabel) { + if (_this3.image) { + _this3.image.setAttribute('aria-label', ariaLabel); + } else if (_this3.disableCanvasToImageConversion && _this3.canvas) { + _this3.canvas.setAttribute('aria-label', ariaLabel); + } + }); + } + }, { + key: 'pageId', + get: function get() { + return this.pageLabel !== null ? this.pageLabel : this.id; + } + }], [{ + key: 'cleanup', + value: function cleanup() { + TempImageFactory.destroyCanvas(); + } + }]); + + return PDFThumbnailView; + }(); + + exports.PDFThumbnailView = PDFThumbnailView; + + /***/ + }), + /* 26 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFThumbnailViewer = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _ui_utils = __webpack_require__(0); + + var _pdf_thumbnail_view = __webpack_require__(25); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var THUMBNAIL_SCROLL_MARGIN = -19; + + var PDFThumbnailViewer = function () { + function PDFThumbnailViewer(_ref) { + var container = _ref.container, + linkService = _ref.linkService, + renderingQueue = _ref.renderingQueue, + _ref$l10n = _ref.l10n, + l10n = _ref$l10n === undefined ? _ui_utils.NullL10n : _ref$l10n; + + _classCallCheck(this, PDFThumbnailViewer); + + this.container = container; + this.linkService = linkService; + this.renderingQueue = renderingQueue; + this.l10n = l10n; + this.scroll = (0, _ui_utils.watchScroll)(this.container, this._scrollUpdated.bind(this)); + this._resetView(); + } + + _createClass(PDFThumbnailViewer, [{ + key: '_scrollUpdated', + value: function _scrollUpdated() { + this.renderingQueue.renderHighestPriority(); + } + }, { + key: 'getThumbnail', + value: function getThumbnail(index) { + return this._thumbnails[index]; + } + }, { + key: '_getVisibleThumbs', + value: function _getVisibleThumbs() { + return (0, _ui_utils.getVisibleElements)(this.container, this._thumbnails); + } + }, { + key: 'scrollThumbnailIntoView', + value: function scrollThumbnailIntoView(page) { + var selected = document.querySelector('.thumbnail.selected'); + if (selected) { + selected.classList.remove('selected'); + } + var thumbnail = document.querySelector('div.thumbnail[data-page-number="' + page + '"]'); + if (thumbnail) { + thumbnail.classList.add('selected'); + } + var visibleThumbs = this._getVisibleThumbs(); + var numVisibleThumbs = visibleThumbs.views.length; + if (numVisibleThumbs > 0) { + var first = visibleThumbs.first.id; + var last = numVisibleThumbs > 1 ? visibleThumbs.last.id : first; + if (page <= first || page >= last) { + (0, _ui_utils.scrollIntoView)(thumbnail, {top: THUMBNAIL_SCROLL_MARGIN}); + } + } + } + }, { + key: 'cleanup', + value: function cleanup() { + _pdf_thumbnail_view.PDFThumbnailView.cleanup(); + } + }, { + key: '_resetView', + value: function _resetView() { + this._thumbnails = []; + this._pageLabels = null; + this._pagesRotation = 0; + this._pagesRequests = []; + this.container.textContent = ''; + } + }, { + key: 'setDocument', + value: function setDocument(pdfDocument) { + var _this = this; + + if (this.pdfDocument) { + this._cancelRendering(); + this._resetView(); + } + this.pdfDocument = pdfDocument; + if (!pdfDocument) { + return; + } + pdfDocument.getPage(1).then(function (firstPage) { + var pagesCount = pdfDocument.numPages; + var viewport = firstPage.getViewport(1.0); + for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { + var thumbnail = new _pdf_thumbnail_view.PDFThumbnailView({ + container: _this.container, + id: pageNum, + defaultViewport: viewport.clone(), + linkService: _this.linkService, + renderingQueue: _this.renderingQueue, + disableCanvasToImageConversion: false, + l10n: _this.l10n + }); + _this._thumbnails.push(thumbnail); + } + }).catch(function (reason) { + console.error('Unable to initialize thumbnail viewer', reason); + }); + } + }, { + key: '_cancelRendering', + value: function _cancelRendering() { + for (var i = 0, ii = this._thumbnails.length; i < ii; i++) { + if (this._thumbnails[i]) { + this._thumbnails[i].cancelRendering(); + } + } + } + }, { + key: 'setPageLabels', + value: function setPageLabels(labels) { + if (!this.pdfDocument) { + return; + } + if (!labels) { + this._pageLabels = null; + } else if (!(labels instanceof Array && this.pdfDocument.numPages === labels.length)) { + this._pageLabels = null; + console.error('PDFThumbnailViewer_setPageLabels: Invalid page labels.'); + } else { + this._pageLabels = labels; + } + for (var i = 0, ii = this._thumbnails.length; i < ii; i++) { + var label = this._pageLabels && this._pageLabels[i]; + this._thumbnails[i].setPageLabel(label); + } + } + }, { + key: '_ensurePdfPageLoaded', + value: function _ensurePdfPageLoaded(thumbView) { + var _this2 = this; + + if (thumbView.pdfPage) { + return Promise.resolve(thumbView.pdfPage); + } + var pageNumber = thumbView.id; + if (this._pagesRequests[pageNumber]) { + return this._pagesRequests[pageNumber]; + } + var promise = this.pdfDocument.getPage(pageNumber).then(function (pdfPage) { + thumbView.setPdfPage(pdfPage); + _this2._pagesRequests[pageNumber] = null; + return pdfPage; + }).catch(function (reason) { + console.error('Unable to get page for thumb view', reason); + _this2._pagesRequests[pageNumber] = null; + }); + this._pagesRequests[pageNumber] = promise; + return promise; + } + }, { + key: 'forceRendering', + value: function forceRendering() { + var _this3 = this; + + var visibleThumbs = this._getVisibleThumbs(); + var thumbView = this.renderingQueue.getHighestPriority(visibleThumbs, this._thumbnails, this.scroll.down); + if (thumbView) { + this._ensurePdfPageLoaded(thumbView).then(function () { + _this3.renderingQueue.renderView(thumbView); + }); + return true; + } + return false; + } + }, { + key: 'pagesRotation', + get: function get() { + return this._pagesRotation; + }, + set: function set(rotation) { + if (!(typeof rotation === 'number' && rotation % 90 === 0)) { + throw new Error('Invalid thumbnails rotation angle.'); + } + if (!this.pdfDocument) { + return; + } + this._pagesRotation = rotation; + for (var i = 0, ii = this._thumbnails.length; i < ii; i++) { + this._thumbnails[i].update(rotation); + } + } + }]); + + return PDFThumbnailViewer; + }(); + + exports.PDFThumbnailViewer = PDFThumbnailViewer; + + /***/ + }), + /* 27 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.PDFViewer = exports.PresentationModeState = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _pdfjsLib = __webpack_require__(1); + + var _ui_utils = __webpack_require__(0); + + var _pdf_rendering_queue = __webpack_require__(3); + + var _annotation_layer_builder = __webpack_require__(11); + + var _dom_events = __webpack_require__(2); + + var _pdf_page_view = __webpack_require__(22); + + var _pdf_link_service = __webpack_require__(5); + + var _text_layer_builder = __webpack_require__(30); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var PresentationModeState = { + UNKNOWN: 0, + NORMAL: 1, + CHANGING: 2, + FULLSCREEN: 3 + }; + var DEFAULT_CACHE_SIZE = 10; + + function PDFPageViewBuffer(size) { + var data = []; + this.push = function cachePush(view) { + var i = data.indexOf(view); + if (i >= 0) { + data.splice(i, 1); + } + data.push(view); + if (data.length > size) { + data.shift().destroy(); + } + }; + this.resize = function (newSize) { + size = newSize; + while (data.length > size) { + data.shift().destroy(); + } + }; + } + + function isSameScale(oldScale, newScale) { + if (newScale === oldScale) { + return true; + } + if (Math.abs(newScale - oldScale) < 1e-15) { + return true; + } + return false; + } + + function isPortraitOrientation(size) { + return size.width <= size.height; + } + + var PDFViewer = function () { + function PDFViewer(options) { + _classCallCheck(this, PDFViewer); + + this.container = options.container; + this.viewer = options.viewer || options.container.firstElementChild; + this.eventBus = options.eventBus || (0, _dom_events.getGlobalEventBus)(); + this.linkService = options.linkService || new _pdf_link_service.SimpleLinkService(); + this.downloadManager = options.downloadManager || null; + this.removePageBorders = options.removePageBorders || false; + this.enhanceTextSelection = options.enhanceTextSelection || false; + this.renderInteractiveForms = options.renderInteractiveForms || false; + this.enablePrintAutoRotate = options.enablePrintAutoRotate || false; + this.renderer = options.renderer || _ui_utils.RendererType.CANVAS; + this.l10n = options.l10n || _ui_utils.NullL10n; + this.defaultRenderingQueue = !options.renderingQueue; + if (this.defaultRenderingQueue) { + this.renderingQueue = new _pdf_rendering_queue.PDFRenderingQueue(); + this.renderingQueue.setViewer(this); + } else { + this.renderingQueue = options.renderingQueue; + } + this.scroll = (0, _ui_utils.watchScroll)(this.container, this._scrollUpdate.bind(this)); + this.presentationModeState = PresentationModeState.UNKNOWN; + this._resetView(); + if (this.removePageBorders) { + this.viewer.classList.add('removePageBorders'); + } + } + + _createClass(PDFViewer, [{ + key: 'getPageView', + value: function getPageView(index) { + return this._pages[index]; + } + }, { + key: '_setCurrentPageNumber', + value: function _setCurrentPageNumber(val) { + var resetCurrentPageView = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (this._currentPageNumber === val) { + if (resetCurrentPageView) { + this._resetCurrentPageView(); + } + return; + } + if (!(0 < val && val <= this.pagesCount)) { + console.error('PDFViewer._setCurrentPageNumber: "' + val + '" is out of bounds.'); + return; + } + var arg = { + source: this, + pageNumber: val, + pageLabel: this._pageLabels && this._pageLabels[val - 1] + }; + this._currentPageNumber = val; + this.eventBus.dispatch('pagechanging', arg); + this.eventBus.dispatch('pagechange', arg); + if (resetCurrentPageView) { + this._resetCurrentPageView(); + } + } + }, { + key: 'setDocument', + value: function setDocument(pdfDocument) { + var _this = this; + + if (this.pdfDocument) { + this._cancelRendering(); + this._resetView(); + } + this.pdfDocument = pdfDocument; + if (!pdfDocument) { + return; + } + var pagesCount = pdfDocument.numPages; + var pagesCapability = (0, _pdfjsLib.createPromiseCapability)(); + this.pagesPromise = pagesCapability.promise; + pagesCapability.promise.then(function () { + _this._pageViewsReady = true; + _this.eventBus.dispatch('pagesloaded', { + source: _this, + pagesCount: pagesCount + }); + }); + var isOnePageRenderedResolved = false; + var onePageRenderedCapability = (0, _pdfjsLib.createPromiseCapability)(); + this.onePageRendered = onePageRenderedCapability.promise; + var bindOnAfterAndBeforeDraw = function bindOnAfterAndBeforeDraw(pageView) { + pageView.onBeforeDraw = function () { + _this._buffer.push(pageView); + }; + pageView.onAfterDraw = function () { + if (!isOnePageRenderedResolved) { + isOnePageRenderedResolved = true; + onePageRenderedCapability.resolve(); + } + }; + }; + var firstPagePromise = pdfDocument.getPage(1); + this.firstPagePromise = firstPagePromise; + firstPagePromise.then(function (pdfPage) { + var scale = _this.currentScale; + var viewport = pdfPage.getViewport(scale * _ui_utils.CSS_UNITS); + for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { + var textLayerFactory = null; + if (!_pdfjsLib.PDFJS.disableTextLayer) { + textLayerFactory = _this; + } + var pageView = new _pdf_page_view.PDFPageView({ + container: _this.viewer, + eventBus: _this.eventBus, + id: pageNum, + scale: scale, + defaultViewport: viewport.clone(), + renderingQueue: _this.renderingQueue, + textLayerFactory: textLayerFactory, + annotationLayerFactory: _this, + enhanceTextSelection: _this.enhanceTextSelection, + renderInteractiveForms: _this.renderInteractiveForms, + renderer: _this.renderer, + l10n: _this.l10n + }); + bindOnAfterAndBeforeDraw(pageView); + _this._pages.push(pageView); + } + onePageRenderedCapability.promise.then(function () { + if (_pdfjsLib.PDFJS.disableAutoFetch) { + pagesCapability.resolve(); + return; + } + var getPagesLeft = pagesCount; + + var _loop = function _loop(_pageNum) { + pdfDocument.getPage(_pageNum).then(function (pdfPage) { + var pageView = _this._pages[_pageNum - 1]; + if (!pageView.pdfPage) { + pageView.setPdfPage(pdfPage); + } + _this.linkService.cachePageRef(_pageNum, pdfPage.ref); + if (--getPagesLeft === 0) { + pagesCapability.resolve(); + } + }, function (reason) { + console.error('Unable to get page ' + _pageNum + ' to initialize viewer', reason); + if (--getPagesLeft === 0) { + pagesCapability.resolve(); + } + }); + }; + + for (var _pageNum = 1; _pageNum <= pagesCount; ++_pageNum) { + _loop(_pageNum); + } + }); + _this.eventBus.dispatch('pagesinit', {source: _this}); + if (_this.defaultRenderingQueue) { + _this.update(); + } + if (_this.findController) { + _this.findController.resolveFirstPage(); + } + }).catch(function (reason) { + console.error('Unable to initialize viewer', reason); + }); + } + }, { + key: 'setPageLabels', + value: function setPageLabels(labels) { + if (!this.pdfDocument) { + return; + } + if (!labels) { + this._pageLabels = null; + } else if (!(labels instanceof Array && this.pdfDocument.numPages === labels.length)) { + this._pageLabels = null; + console.error('PDFViewer.setPageLabels: Invalid page labels.'); + } else { + this._pageLabels = labels; + } + for (var i = 0, ii = this._pages.length; i < ii; i++) { + var pageView = this._pages[i]; + var label = this._pageLabels && this._pageLabels[i]; + pageView.setPageLabel(label); + } + } + }, { + key: '_resetView', + value: function _resetView() { + this._pages = []; + this._currentPageNumber = 1; + this._currentScale = _ui_utils.UNKNOWN_SCALE; + this._currentScaleValue = null; + this._pageLabels = null; + this._buffer = new PDFPageViewBuffer(DEFAULT_CACHE_SIZE); + this._location = null; + this._pagesRotation = 0; + this._pagesRequests = []; + this._pageViewsReady = false; + this.viewer.textContent = ''; + } + }, { + key: '_scrollUpdate', + value: function _scrollUpdate() { + if (this.pagesCount === 0) { + return; + } + this.update(); + } + }, { + key: '_setScaleDispatchEvent', + value: function _setScaleDispatchEvent(newScale, newValue) { + var preset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + + var arg = { + source: this, + scale: newScale, + presetValue: preset ? newValue : undefined + }; + this.eventBus.dispatch('scalechanging', arg); + this.eventBus.dispatch('scalechange', arg); + } + }, { + key: '_setScaleUpdatePages', + value: function _setScaleUpdatePages(newScale, newValue) { + var noScroll = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + var preset = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + + this._currentScaleValue = newValue.toString(); + if (isSameScale(this._currentScale, newScale)) { + if (preset) { + this._setScaleDispatchEvent(newScale, newValue, true); + } + return; + } + for (var i = 0, ii = this._pages.length; i < ii; i++) { + this._pages[i].update(newScale); + } + this._currentScale = newScale; + if (!noScroll) { + var page = this._currentPageNumber, + dest = void 0; + if (this._location && !_pdfjsLib.PDFJS.ignoreCurrentPositionOnZoom && !(this.isInPresentationMode || this.isChangingPresentationMode)) { + page = this._location.pageNumber; + dest = [null, {name: 'XYZ'}, this._location.left, this._location.top, null]; + } + this.scrollPageIntoView({ + pageNumber: page, + destArray: dest, + allowNegativeOffset: true + }); + } + this._setScaleDispatchEvent(newScale, newValue, preset); + if (this.defaultRenderingQueue) { + this.update(); + } + } + }, { + key: '_setScale', + value: function _setScale(value) { + var noScroll = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + var scale = parseFloat(value); + if (scale > 0) { + this._setScaleUpdatePages(scale, value, noScroll, false); + } else { + var currentPage = this._pages[this._currentPageNumber - 1]; + if (!currentPage) { + return; + } + var hPadding = this.isInPresentationMode || this.removePageBorders ? 0 : _ui_utils.SCROLLBAR_PADDING; + var vPadding = this.isInPresentationMode || this.removePageBorders ? 0 : _ui_utils.VERTICAL_PADDING; + var pageWidthScale = (this.container.clientWidth - hPadding) / currentPage.width * currentPage.scale; + var pageHeightScale = (this.container.clientHeight - vPadding) / currentPage.height * currentPage.scale; + switch (value) { + case 'page-actual': + scale = 1; + break; + case 'page-width': + scale = pageWidthScale; + break; + case 'page-height': + scale = pageHeightScale; + break; + case 'page-fit': + scale = Math.min(pageWidthScale, pageHeightScale); + break; + case 'auto': + var isLandscape = currentPage.width > currentPage.height; + var horizontalScale = isLandscape ? Math.min(pageHeightScale, pageWidthScale) : pageWidthScale; + scale = Math.min(_ui_utils.MAX_AUTO_SCALE, horizontalScale); + break; + default: + console.error('PDFViewer._setScale: "' + value + '" is an unknown zoom value.'); + return; + } + this._setScaleUpdatePages(scale, value, noScroll, true); + } + } + }, { + key: '_resetCurrentPageView', + value: function _resetCurrentPageView() { + if (this.isInPresentationMode) { + this._setScale(this._currentScaleValue, true); + } + var pageView = this._pages[this._currentPageNumber - 1]; + (0, _ui_utils.scrollIntoView)(pageView.div); + } + }, { + key: 'scrollPageIntoView', + value: function scrollPageIntoView(params) { + if (!this.pdfDocument) { + return; + } + if (arguments.length > 1 || typeof params === 'number') { + console.warn('Call of scrollPageIntoView() with obsolete signature.'); + var paramObj = {}; + if (typeof params === 'number') { + paramObj.pageNumber = params; + } + if (arguments[1] instanceof Array) { + paramObj.destArray = arguments[1]; + } + params = paramObj; + } + var pageNumber = params.pageNumber || 0; + var dest = params.destArray || null; + var allowNegativeOffset = params.allowNegativeOffset || false; + if (this.isInPresentationMode || !dest) { + this._setCurrentPageNumber(pageNumber, true); + return; + } + var pageView = this._pages[pageNumber - 1]; + if (!pageView) { + console.error('PDFViewer.scrollPageIntoView: Invalid "pageNumber" parameter.'); + return; + } + var x = 0, + y = 0; + var width = 0, + height = 0, + widthScale = void 0, + heightScale = void 0; + var changeOrientation = pageView.rotation % 180 === 0 ? false : true; + var pageWidth = (changeOrientation ? pageView.height : pageView.width) / pageView.scale / _ui_utils.CSS_UNITS; + var pageHeight = (changeOrientation ? pageView.width : pageView.height) / pageView.scale / _ui_utils.CSS_UNITS; + var scale = 0; + switch (dest[1].name) { + case 'XYZ': + x = dest[2]; + y = dest[3]; + scale = dest[4]; + x = x !== null ? x : 0; + y = y !== null ? y : pageHeight; + break; + case 'Fit': + case 'FitB': + scale = 'page-fit'; + break; + case 'FitH': + case 'FitBH': + y = dest[2]; + scale = 'page-width'; + if (y === null && this._location) { + x = this._location.left; + y = this._location.top; + } + break; + case 'FitV': + case 'FitBV': + x = dest[2]; + width = pageWidth; + height = pageHeight; + scale = 'page-height'; + break; + case 'FitR': + x = dest[2]; + y = dest[3]; + width = dest[4] - x; + height = dest[5] - y; + var hPadding = this.removePageBorders ? 0 : _ui_utils.SCROLLBAR_PADDING; + var 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; + scale = Math.min(Math.abs(widthScale), Math.abs(heightScale)); + break; + default: + console.error('PDFViewer.scrollPageIntoView: "' + dest[1].name + '" ' + 'is not a valid destination type.'); + return; + } + if (scale && scale !== this._currentScale) { + this.currentScaleValue = scale; + } else if (this._currentScale === _ui_utils.UNKNOWN_SCALE) { + this.currentScaleValue = _ui_utils.DEFAULT_SCALE_VALUE; + } + if (scale === 'page-fit' && !dest[4]) { + (0, _ui_utils.scrollIntoView)(pageView.div); + return; + } + var boundingRect = [pageView.viewport.convertToViewportPoint(x, y), pageView.viewport.convertToViewportPoint(x + width, y + height)]; + var left = Math.min(boundingRect[0][0], boundingRect[1][0]); + var top = Math.min(boundingRect[0][1], boundingRect[1][1]); + if (!allowNegativeOffset) { + left = Math.max(left, 0); + top = Math.max(top, 0); + } + (0, _ui_utils.scrollIntoView)(pageView.div, { + left: left, + top: top + }); + } + }, { + key: '_updateLocation', + value: function _updateLocation(firstPage) { + var currentScale = this._currentScale; + var currentScaleValue = this._currentScaleValue; + var normalizedScaleValue = parseFloat(currentScaleValue) === currentScale ? Math.round(currentScale * 10000) / 100 : currentScaleValue; + var pageNumber = firstPage.id; + var pdfOpenParams = '#page=' + pageNumber; + pdfOpenParams += '&zoom=' + normalizedScaleValue; + var currentPageView = this._pages[pageNumber - 1]; + var container = this.container; + var topLeft = currentPageView.getPagePoint(container.scrollLeft - firstPage.x, container.scrollTop - firstPage.y); + var intLeft = Math.round(topLeft[0]); + var intTop = Math.round(topLeft[1]); + pdfOpenParams += ',' + intLeft + ',' + intTop; + this._location = { + pageNumber: pageNumber, + scale: normalizedScaleValue, + top: intTop, + left: intLeft, + pdfOpenParams: pdfOpenParams + }; + } + }, { + key: 'update', + value: function update() { + var visible = this._getVisiblePages(); + var visiblePages = visible.views; + if (visiblePages.length === 0) { + return; + } + var suggestedCacheSize = Math.max(DEFAULT_CACHE_SIZE, 2 * visiblePages.length + 1); + this._buffer.resize(suggestedCacheSize); + this.renderingQueue.renderHighestPriority(visible); + var currentId = this._currentPageNumber; + var firstPage = visible.first; + var stillFullyVisible = false; + for (var i = 0, ii = visiblePages.length; i < ii; ++i) { + var page = visiblePages[i]; + if (page.percent < 100) { + break; + } + if (page.id === currentId) { + stillFullyVisible = true; + break; + } + } + if (!stillFullyVisible) { + currentId = visiblePages[0].id; + } + if (!this.isInPresentationMode) { + this._setCurrentPageNumber(currentId); + } + this._updateLocation(firstPage); + this.eventBus.dispatch('updateviewarea', { + source: this, + location: this._location + }); + } + }, { + key: 'containsElement', + value: function containsElement(element) { + return this.container.contains(element); + } + }, { + key: 'focus', + value: function focus() { + this.container.focus(); + } + }, { + key: '_getVisiblePages', + value: function _getVisiblePages() { + if (!this.isInPresentationMode) { + return (0, _ui_utils.getVisibleElements)(this.container, this._pages, true); + } + var visible = []; + var currentPage = this._pages[this._currentPageNumber - 1]; + visible.push({ + id: currentPage.id, + view: currentPage + }); + return { + first: currentPage, + last: currentPage, + views: visible + }; + } + }, { + key: 'cleanup', + value: function cleanup() { + for (var 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(); + } + } + } + }, { + key: '_cancelRendering', + value: function _cancelRendering() { + for (var i = 0, ii = this._pages.length; i < ii; i++) { + if (this._pages[i]) { + this._pages[i].cancelRendering(); + } + } + } + }, { + key: '_ensurePdfPageLoaded', + value: function _ensurePdfPageLoaded(pageView) { + var _this2 = this; + + if (pageView.pdfPage) { + return Promise.resolve(pageView.pdfPage); + } + var pageNumber = pageView.id; + if (this._pagesRequests[pageNumber]) { + return this._pagesRequests[pageNumber]; + } + var promise = this.pdfDocument.getPage(pageNumber).then(function (pdfPage) { + if (!pageView.pdfPage) { + pageView.setPdfPage(pdfPage); + } + _this2._pagesRequests[pageNumber] = null; + return pdfPage; + }).catch(function (reason) { + console.error('Unable to get page for page view', reason); + _this2._pagesRequests[pageNumber] = null; + }); + this._pagesRequests[pageNumber] = promise; + return promise; + } + }, { + key: 'forceRendering', + value: function forceRendering(currentlyVisiblePages) { + var _this3 = this; + + var visiblePages = currentlyVisiblePages || this._getVisiblePages(); + var pageView = this.renderingQueue.getHighestPriority(visiblePages, this._pages, this.scroll.down); + if (pageView) { + this._ensurePdfPageLoaded(pageView).then(function () { + _this3.renderingQueue.renderView(pageView); + }); + return true; + } + return false; + } + }, { + key: 'getPageTextContent', + value: function getPageTextContent(pageIndex) { + return this.pdfDocument.getPage(pageIndex + 1).then(function (page) { + return page.getTextContent({normalizeWhitespace: true}); + }); + } + }, { + key: 'createTextLayerBuilder', + value: function createTextLayerBuilder(textLayerDiv, pageIndex, viewport) { + var enhanceTextSelection = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + + return new _text_layer_builder.TextLayerBuilder({ + textLayerDiv: textLayerDiv, + eventBus: this.eventBus, + pageIndex: pageIndex, + viewport: viewport, + findController: this.isInPresentationMode ? null : this.findController, + enhanceTextSelection: this.isInPresentationMode ? false : enhanceTextSelection + }); + } + }, { + key: 'createAnnotationLayerBuilder', + value: function createAnnotationLayerBuilder(pageDiv, pdfPage) { + var renderInteractiveForms = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + var l10n = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : _ui_utils.NullL10n; + + return new _annotation_layer_builder.AnnotationLayerBuilder({ + pageDiv: pageDiv, + pdfPage: pdfPage, + renderInteractiveForms: renderInteractiveForms, + linkService: this.linkService, + downloadManager: this.downloadManager, + l10n: l10n + }); + } + }, { + key: 'setFindController', + value: function setFindController(findController) { + this.findController = findController; + } + }, { + key: 'getPagesOverview', + value: function getPagesOverview() { + var pagesOverview = this._pages.map(function (pageView) { + var viewport = pageView.pdfPage.getViewport(1); + return { + width: viewport.width, + height: viewport.height, + rotation: viewport.rotation + }; + }); + if (!this.enablePrintAutoRotate) { + return pagesOverview; + } + var isFirstPagePortrait = isPortraitOrientation(pagesOverview[0]); + return pagesOverview.map(function (size) { + if (isFirstPagePortrait === isPortraitOrientation(size)) { + return size; + } + return { + width: size.height, + height: size.width, + rotation: (size.rotation + 90) % 360 + }; + }); + } + }, { + key: 'pagesCount', + get: function get() { + return this._pages.length; + } + }, { + key: 'pageViewsReady', + get: function get() { + return this._pageViewsReady; + } + }, { + key: 'currentPageNumber', + get: function get() { + return this._currentPageNumber; + }, + set: function set(val) { + if ((val | 0) !== val) { + throw new Error('Invalid page number.'); + } + if (!this.pdfDocument) { + return; + } + this._setCurrentPageNumber(val, true); + } + }, { + key: 'currentPageLabel', + get: function get() { + return this._pageLabels && this._pageLabels[this._currentPageNumber - 1]; + }, + set: function set(val) { + var pageNumber = val | 0; + if (this._pageLabels) { + var i = this._pageLabels.indexOf(val); + if (i >= 0) { + pageNumber = i + 1; + } + } + this.currentPageNumber = pageNumber; + } + }, { + key: 'currentScale', + get: function get() { + return this._currentScale !== _ui_utils.UNKNOWN_SCALE ? this._currentScale : _ui_utils.DEFAULT_SCALE; + }, + set: function set(val) { + if (isNaN(val)) { + throw new Error('Invalid numeric scale'); + } + if (!this.pdfDocument) { + return; + } + this._setScale(val, false); + } + }, { + key: 'currentScaleValue', + get: function get() { + return this._currentScaleValue; + }, + set: function set(val) { + if (!this.pdfDocument) { + return; + } + this._setScale(val, false); + } + }, { + key: 'pagesRotation', + get: function get() { + return this._pagesRotation; + }, + set: function set(rotation) { + if (!(typeof rotation === 'number' && rotation % 90 === 0)) { + throw new Error('Invalid pages rotation angle.'); + } + if (!this.pdfDocument) { + return; + } + this._pagesRotation = rotation; + for (var i = 0, ii = this._pages.length; i < ii; i++) { + var pageView = this._pages[i]; + pageView.update(pageView.scale, rotation); + } + this._setScale(this._currentScaleValue, true); + if (this.defaultRenderingQueue) { + this.update(); + } + } + }, { + key: 'isInPresentationMode', + get: function get() { + return this.presentationModeState === PresentationModeState.FULLSCREEN; + } + }, { + key: 'isChangingPresentationMode', + get: function get() { + return this.presentationModeState === PresentationModeState.CHANGING; + } + }, { + key: 'isHorizontalScrollbarEnabled', + get: function get() { + return this.isInPresentationMode ? false : this.container.scrollWidth > this.container.clientWidth; + } + }, { + key: 'hasEqualPageSizes', + get: function get() { + var firstPageView = this._pages[0]; + for (var i = 1, ii = this._pages.length; i < ii; ++i) { + var pageView = this._pages[i]; + if (pageView.width !== firstPageView.width || pageView.height !== firstPageView.height) { + return false; + } + } + return true; + } + }]); + + return PDFViewer; + }(); + + exports.PresentationModeState = PresentationModeState; + exports.PDFViewer = PDFViewer; + + /***/ + }), + /* 28 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.BasePreferences = undefined; + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _ui_utils = __webpack_require__(0); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var defaultPreferences = null; + + function getDefaultPreferences() { + if (!defaultPreferences) { + defaultPreferences = Promise.resolve({ + "showPreviousViewOnLoad": true, + "defaultZoomValue": "", + "sidebarViewOnLoad": 0, + "enableHandToolOnLoad": false, + "cursorToolOnLoad": 0, + "enableWebGL": false, + "pdfBugEnabled": false, + "disableRange": false, + "disableStream": false, + "disableAutoFetch": false, + "disableFontFace": false, + "disableTextLayer": false, + "useOnlyCssZoom": false, + "externalLinkTarget": 0, + "enhanceTextSelection": false, + "renderer": "canvas", + "renderInteractiveForms": false, + "enablePrintAutoRotate": false, + "disablePageMode": false, + "disablePageLabels": false + }); + } + return defaultPreferences; + } + + var BasePreferences = function () { + function BasePreferences() { + var _this = this; + + _classCallCheck(this, BasePreferences); + + if (this.constructor === BasePreferences) { + throw new Error('Cannot initialize BasePreferences.'); + } + this.prefs = null; + this._initializedPromise = getDefaultPreferences().then(function (defaults) { + Object.defineProperty(_this, 'defaults', { + value: Object.freeze(defaults), + writable: false, + enumerable: true, + configurable: false + }); + _this.prefs = (0, _ui_utils.cloneObj)(defaults); + return _this._readFromStorage(defaults); + }).then(function (prefObj) { + if (prefObj) { + _this.prefs = prefObj; + } + }); + } + + _createClass(BasePreferences, [{ + key: "_writeToStorage", + value: function _writeToStorage(prefObj) { + return Promise.reject(new Error('Not implemented: _writeToStorage')); + } + }, { + key: "_readFromStorage", + value: function _readFromStorage(prefObj) { + return Promise.reject(new Error('Not implemented: _readFromStorage')); + } + }, { + key: "reset", + value: function reset() { + var _this2 = this; + + return this._initializedPromise.then(function () { + _this2.prefs = (0, _ui_utils.cloneObj)(_this2.defaults); + return _this2._writeToStorage(_this2.defaults); + }); + } + }, { + key: "reload", + value: function reload() { + var _this3 = this; + + return this._initializedPromise.then(function () { + return _this3._readFromStorage(_this3.defaults); + }).then(function (prefObj) { + if (prefObj) { + _this3.prefs = prefObj; + } + }); + } + }, { + key: "set", + value: function set(name, value) { + var _this4 = this; + + return this._initializedPromise.then(function () { + if (_this4.defaults[name] === undefined) { + throw new Error("Set preference: \"" + name + "\" is undefined."); + } else if (value === undefined) { + throw new Error('Set preference: no value is specified.'); + } + var valueType = typeof value === "undefined" ? "undefined" : _typeof(value); + var defaultType = _typeof(_this4.defaults[name]); + if (valueType !== defaultType) { + if (valueType === 'number' && defaultType === 'string') { + value = value.toString(); + } else { + throw new Error("Set preference: \"" + value + "\" is a " + valueType + ", " + ("expected a " + defaultType + ".")); + } + } else { + if (valueType === 'number' && (value | 0) !== value) { + throw new Error("Set preference: \"" + value + "\" must be an integer."); + } + } + _this4.prefs[name] = value; + return _this4._writeToStorage(_this4.prefs); + }); + } + }, { + key: "get", + value: function get(name) { + var _this5 = this; + + return this._initializedPromise.then(function () { + var defaultValue = _this5.defaults[name]; + if (defaultValue === undefined) { + throw new Error("Get preference: \"" + name + "\" is undefined."); + } else { + var prefValue = _this5.prefs[name]; + if (prefValue !== undefined) { + return prefValue; + } + } + return defaultValue; + }); + } + }]); + + return BasePreferences; + }(); + + exports.BasePreferences = BasePreferences; + + /***/ + }), + /* 29 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.SecondaryToolbar = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _pdf_cursor_tools = __webpack_require__(6); + + var _ui_utils = __webpack_require__(0); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var SecondaryToolbar = function () { + function SecondaryToolbar(options, mainContainer, eventBus) { + _classCallCheck(this, SecondaryToolbar); + + 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', + close: true + }, { + element: options.downloadButton, + eventName: 'download', + close: true + }, { + element: options.viewBookmarkButton, + eventName: null, + close: true + }, { + element: options.firstPageButton, + eventName: 'firstpage', + close: true + }, { + element: options.lastPageButton, + eventName: 'lastpage', + close: true + }, { + element: options.pageRotateCwButton, + eventName: 'rotatecw', + close: false + }, { + element: options.pageRotateCcwButton, + eventName: 'rotateccw', + close: false + }, { + element: options.cursorSelectToolButton, + eventName: 'switchcursortool', + eventDetails: {tool: _pdf_cursor_tools.CursorTool.SELECT}, + close: true + }, { + element: options.cursorHandToolButton, + eventName: 'switchcursortool', + eventDetails: {tool: _pdf_cursor_tools.CursorTool.HAND}, + close: true + }, { + element: options.documentPropertiesButton, + eventName: 'documentproperties', + 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.reset(); + this._bindClickListeners(); + this._bindCursorToolsListener(options); + this.eventBus.on('resize', this._setMaxHeight.bind(this)); + } + + _createClass(SecondaryToolbar, [{ + key: 'setPageNumber', + value: function setPageNumber(pageNumber) { + this.pageNumber = pageNumber; + this._updateUIState(); + } + }, { + key: 'setPagesCount', + value: function setPagesCount(pagesCount) { + this.pagesCount = pagesCount; + this._updateUIState(); + } + }, { + key: 'reset', + value: function reset() { + this.pageNumber = 0; + this.pagesCount = 0; + this._updateUIState(); + } + }, { + key: '_updateUIState', + value: function _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; + } + }, { + key: '_bindClickListeners', + value: function _bindClickListeners() { + var _this = this; + + this.toggleButton.addEventListener('click', this.toggle.bind(this)); + + var _loop = function _loop(button) { + var _buttons$button = _this.buttons[button], + element = _buttons$button.element, + eventName = _buttons$button.eventName, + close = _buttons$button.close, + eventDetails = _buttons$button.eventDetails; + + element.addEventListener('click', function (evt) { + if (eventName !== null) { + var details = {source: _this}; + for (var property in eventDetails) { + details[property] = eventDetails[property]; + } + _this.eventBus.dispatch(eventName, details); + } + if (close) { + _this.close(); + } + }); + }; + + for (var button in this.buttons) { + _loop(button); + } + } + }, { + key: '_bindCursorToolsListener', + value: function _bindCursorToolsListener(buttons) { + this.eventBus.on('cursortoolchanged', function (evt) { + buttons.cursorSelectToolButton.classList.remove('toggled'); + buttons.cursorHandToolButton.classList.remove('toggled'); + switch (evt.tool) { + case _pdf_cursor_tools.CursorTool.SELECT: + buttons.cursorSelectToolButton.classList.add('toggled'); + break; + case _pdf_cursor_tools.CursorTool.HAND: + buttons.cursorHandToolButton.classList.add('toggled'); + break; + } + }); + } + }, { + key: 'open', + value: function open() { + if (this.opened) { + return; + } + this.opened = true; + this._setMaxHeight(); + this.toggleButton.classList.add('toggled'); + this.toolbar.classList.remove('hidden'); + } + }, { + key: 'close', + value: function close() { + if (!this.opened) { + return; + } + this.opened = false; + this.toolbar.classList.add('hidden'); + this.toggleButton.classList.remove('toggled'); + } + }, { + key: 'toggle', + value: function toggle() { + if (this.opened) { + this.close(); + } else { + this.open(); + } + } + }, { + key: '_setMaxHeight', + value: function _setMaxHeight() { + if (!this.opened) { + return; + } + this.containerHeight = this.mainContainer.clientHeight; + if (this.containerHeight === this.previousContainerHeight) { + return; + } + this.toolbarButtonContainer.setAttribute('style', 'max-height: ' + (this.containerHeight - _ui_utils.SCROLLBAR_PADDING) + 'px;'); + this.previousContainerHeight = this.containerHeight; + } + }, { + key: 'isOpen', + get: function get() { + return this.opened; + } + }]); + + return SecondaryToolbar; + }(); + + exports.SecondaryToolbar = SecondaryToolbar; + + /***/ + }), + /* 30 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.DefaultTextLayerFactory = exports.TextLayerBuilder = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _dom_events = __webpack_require__(2); + + var _pdfjsLib = __webpack_require__(1); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var EXPAND_DIVS_TIMEOUT = 300; + + var TextLayerBuilder = function () { + function TextLayerBuilder(_ref) { + var textLayerDiv = _ref.textLayerDiv, + eventBus = _ref.eventBus, + pageIndex = _ref.pageIndex, + viewport = _ref.viewport, + _ref$findController = _ref.findController, + findController = _ref$findController === undefined ? null : _ref$findController, + _ref$enhanceTextSelec = _ref.enhanceTextSelection, + enhanceTextSelection = _ref$enhanceTextSelec === undefined ? false : _ref$enhanceTextSelec; + + _classCallCheck(this, TextLayerBuilder); + + this.textLayerDiv = textLayerDiv; + this.eventBus = eventBus || (0, _dom_events.getGlobalEventBus)(); + 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._bindMouse(); + } + + _createClass(TextLayerBuilder, [{ + key: '_finishRendering', + value: function _finishRendering() { + this.renderingDone = true; + if (!this.enhanceTextSelection) { + var endOfContent = document.createElement('div'); + endOfContent.className = 'endOfContent'; + this.textLayerDiv.appendChild(endOfContent); + } + this.eventBus.dispatch('textlayerrendered', { + source: this, + pageNumber: this.pageNumber, + numTextDivs: this.textDivs.length + }); + } + }, { + key: 'render', + value: function render() { + var _this = this; + + var timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + + if (!(this.textContent || this.textContentStream) || this.renderingDone) { + return; + } + this.cancel(); + this.textDivs = []; + var 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: timeout, + enhanceTextSelection: this.enhanceTextSelection + }); + this.textLayerRenderTask.promise.then(function () { + _this.textLayerDiv.appendChild(textLayerFrag); + _this._finishRendering(); + _this.updateMatches(); + }, function (reason) { + }); + } + }, { + key: 'cancel', + value: function cancel() { + if (this.textLayerRenderTask) { + this.textLayerRenderTask.cancel(); + this.textLayerRenderTask = null; + } + } + }, { + key: 'setTextContentStream', + value: function setTextContentStream(readableStream) { + this.cancel(); + this.textContentStream = readableStream; + } + }, { + key: 'setTextContent', + value: function setTextContent(textContent) { + this.cancel(); + this.textContent = textContent; + } + }, { + key: 'convertMatches', + value: function convertMatches(matches, matchesLength) { + var i = 0; + var iIndex = 0; + var textContentItemsStr = this.textContentItemsStr; + var end = textContentItemsStr.length - 1; + var queryLen = this.findController === null ? 0 : this.findController.state.query.length; + var ret = []; + if (!matches) { + return ret; + } + for (var m = 0, len = matches.length; m < len; m++) { + var matchIdx = matches[m]; + while (i !== end && matchIdx >= iIndex + textContentItemsStr[i].length) { + iIndex += textContentItemsStr[i].length; + i++; + } + if (i === textContentItemsStr.length) { + console.error('Could not find a matching mapping'); + } + var match = { + begin: { + divIdx: i, + offset: matchIdx - iIndex + } + }; + if (matchesLength) { + matchIdx += matchesLength[m]; + } else { + matchIdx += queryLen; + } + while (i !== end && matchIdx > iIndex + textContentItemsStr[i].length) { + iIndex += textContentItemsStr[i].length; + i++; + } + match.end = { + divIdx: i, + offset: matchIdx - iIndex + }; + ret.push(match); + } + return ret; + } + }, { + key: 'renderMatches', + value: function renderMatches(matches) { + if (matches.length === 0) { + return; + } + var textContentItemsStr = this.textContentItemsStr; + var textDivs = this.textDivs; + var prevEnd = null; + var pageIdx = this.pageIdx; + var isSelectedPage = this.findController === null ? false : pageIdx === this.findController.selected.pageIdx; + var selectedMatchIdx = this.findController === null ? -1 : this.findController.selected.matchIdx; + var highlightAll = this.findController === null ? false : this.findController.state.highlightAll; + var infinity = { + divIdx: -1, + offset: undefined + }; + + function beginText(begin, className) { + var divIdx = begin.divIdx; + textDivs[divIdx].textContent = ''; + appendTextToDiv(divIdx, 0, begin.offset, className); + } + + function appendTextToDiv(divIdx, fromOffset, toOffset, className) { + var div = textDivs[divIdx]; + var content = textContentItemsStr[divIdx].substring(fromOffset, toOffset); + var node = document.createTextNode(content); + if (className) { + var span = document.createElement('span'); + span.className = className; + span.appendChild(node); + div.appendChild(span); + return; + } + div.appendChild(node); + } + + var i0 = selectedMatchIdx, + i1 = i0 + 1; + if (highlightAll) { + i0 = 0; + i1 = matches.length; + } else if (!isSelectedPage) { + return; + } + for (var i = i0; i < i1; i++) { + var match = matches[i]; + var begin = match.begin; + var end = match.end; + var isSelected = isSelectedPage && i === selectedMatchIdx; + var highlightSuffix = isSelected ? ' selected' : ''; + if (this.findController) { + this.findController.updateMatchPosition(pageIdx, i, textDivs, begin.divIdx); + } + if (!prevEnd || begin.divIdx !== prevEnd.divIdx) { + if (prevEnd !== null) { + appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset); + } + beginText(begin); + } else { + appendTextToDiv(prevEnd.divIdx, prevEnd.offset, begin.offset); + } + if (begin.divIdx === end.divIdx) { + appendTextToDiv(begin.divIdx, begin.offset, end.offset, 'highlight' + highlightSuffix); + } else { + appendTextToDiv(begin.divIdx, begin.offset, infinity.offset, 'highlight begin' + highlightSuffix); + for (var n0 = begin.divIdx + 1, n1 = end.divIdx; n0 < n1; n0++) { + textDivs[n0].className = 'highlight middle' + highlightSuffix; + } + beginText(end, 'highlight end' + highlightSuffix); + } + prevEnd = end; + } + if (prevEnd) { + appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset); + } + } + }, { + key: 'updateMatches', + value: function updateMatches() { + if (!this.renderingDone) { + return; + } + var matches = this.matches; + var textDivs = this.textDivs; + var textContentItemsStr = this.textContentItemsStr; + var clearedUntilDivIdx = -1; + for (var i = 0, len = matches.length; i < len; i++) { + var match = matches[i]; + var begin = Math.max(clearedUntilDivIdx, match.begin.divIdx); + for (var n = begin, end = match.end.divIdx; n <= end; n++) { + var div = textDivs[n]; + div.textContent = textContentItemsStr[n]; + div.className = ''; + } + clearedUntilDivIdx = match.end.divIdx + 1; + } + if (this.findController === null || !this.findController.active) { + return; + } + var pageMatches = void 0, + pageMatchesLength = void 0; + if (this.findController !== null) { + pageMatches = this.findController.pageMatches[this.pageIdx] || null; + pageMatchesLength = this.findController.pageMatchesLength ? this.findController.pageMatchesLength[this.pageIdx] || null : null; + } + this.matches = this.convertMatches(pageMatches, pageMatchesLength); + this.renderMatches(this.matches); + } + }, { + key: '_bindMouse', + value: function _bindMouse() { + var _this2 = this; + + var div = this.textLayerDiv; + var expandDivsTimer = null; + div.addEventListener('mousedown', function (evt) { + if (_this2.enhanceTextSelection && _this2.textLayerRenderTask) { + _this2.textLayerRenderTask.expandTextDivs(true); + if (expandDivsTimer) { + clearTimeout(expandDivsTimer); + expandDivsTimer = null; + } + return; + } + var end = div.querySelector('.endOfContent'); + if (!end) { + return; + } + var adjustTop = evt.target !== div; + adjustTop = adjustTop && window.getComputedStyle(end).getPropertyValue('-moz-user-select') !== 'none'; + if (adjustTop) { + var divBounds = div.getBoundingClientRect(); + var r = Math.max(0, (evt.pageY - divBounds.top) / divBounds.height); + end.style.top = (r * 100).toFixed(2) + '%'; + } + end.classList.add('active'); + }); + div.addEventListener('mouseup', function () { + if (_this2.enhanceTextSelection && _this2.textLayerRenderTask) { + expandDivsTimer = setTimeout(function () { + if (_this2.textLayerRenderTask) { + _this2.textLayerRenderTask.expandTextDivs(false); + } + expandDivsTimer = null; + }, EXPAND_DIVS_TIMEOUT); + return; + } + var end = div.querySelector('.endOfContent'); + if (!end) { + return; + } + end.style.top = ''; + end.classList.remove('active'); + }); + } + }]); + + return TextLayerBuilder; + }(); + + var DefaultTextLayerFactory = function () { + function DefaultTextLayerFactory() { + _classCallCheck(this, DefaultTextLayerFactory); + } + + _createClass(DefaultTextLayerFactory, [{ + key: 'createTextLayerBuilder', + value: function createTextLayerBuilder(textLayerDiv, pageIndex, viewport) { + var enhanceTextSelection = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + + return new TextLayerBuilder({ + textLayerDiv: textLayerDiv, + pageIndex: pageIndex, + viewport: viewport, + enhanceTextSelection: enhanceTextSelection + }); + } + }]); + + return DefaultTextLayerFactory; + }(); + + exports.TextLayerBuilder = TextLayerBuilder; + exports.DefaultTextLayerFactory = DefaultTextLayerFactory; + + /***/ + }), + /* 31 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.Toolbar = undefined; + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var _ui_utils = __webpack_require__(0); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var PAGE_NUMBER_LOADING_INDICATOR = 'visiblePageIsLoading'; + var SCALE_SELECT_CONTAINER_PADDING = 8; + var SCALE_SELECT_PADDING = 22; + + var Toolbar = function () { + function Toolbar(options, mainContainer, eventBus) { + var l10n = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : _ui_utils.NullL10n; + + _classCallCheck(this, Toolbar); + + this.toolbar = options.container; + this.mainContainer = mainContainer; + this.eventBus = eventBus; + this.l10n = l10n; + this.items = options; + this._wasLocalized = false; + this.reset(); + this._bindListeners(); + } + + _createClass(Toolbar, [{ + key: 'setPageNumber', + value: function setPageNumber(pageNumber, pageLabel) { + this.pageNumber = pageNumber; + this.pageLabel = pageLabel; + this._updateUIState(false); + } + }, { + key: 'setPagesCount', + value: function setPagesCount(pagesCount, hasPageLabels) { + this.pagesCount = pagesCount; + this.hasPageLabels = hasPageLabels; + this._updateUIState(true); + } + }, { + key: 'setPageScale', + value: function setPageScale(pageScaleValue, pageScale) { + this.pageScaleValue = pageScaleValue; + this.pageScale = pageScale; + this._updateUIState(false); + } + }, { + key: 'reset', + value: function reset() { + this.pageNumber = 0; + this.pageLabel = null; + this.hasPageLabels = false; + this.pagesCount = 0; + this.pageScaleValue = _ui_utils.DEFAULT_SCALE_VALUE; + this.pageScale = _ui_utils.DEFAULT_SCALE; + this._updateUIState(true); + } + }, { + key: '_bindListeners', + value: function _bindListeners() { + var _this = this; + + var eventBus = this.eventBus, + items = this.items; + + var self = this; + items.previous.addEventListener('click', function () { + eventBus.dispatch('previouspage'); + }); + items.next.addEventListener('click', function () { + eventBus.dispatch('nextpage'); + }); + items.zoomIn.addEventListener('click', function () { + eventBus.dispatch('zoomin'); + }); + items.zoomOut.addEventListener('click', function () { + eventBus.dispatch('zoomout'); + }); + items.pageNumber.addEventListener('click', function () { + this.select(); + }); + items.pageNumber.addEventListener('change', function () { + eventBus.dispatch('pagenumberchanged', { + source: self, + value: this.value + }); + }); + items.scaleSelect.addEventListener('change', function () { + if (this.value === 'custom') { + return; + } + eventBus.dispatch('scalechanged', { + source: self, + value: this.value + }); + }); + items.presentationModeButton.addEventListener('click', function () { + eventBus.dispatch('presentationmode'); + }); + items.openFile.addEventListener('click', function () { + eventBus.dispatch('openfile'); + }); + items.print.addEventListener('click', function () { + eventBus.dispatch('print'); + }); + items.download.addEventListener('click', function () { + eventBus.dispatch('download'); + }); + items.scaleSelect.oncontextmenu = _ui_utils.noContextMenuHandler; + eventBus.on('localized', function () { + _this._localized(); + }); + } + }, { + key: '_localized', + value: function _localized() { + this._wasLocalized = true; + this._adjustScaleWidth(); + this._updateUIState(true); + } + }, { + key: '_updateUIState', + value: function _updateUIState() { + var resetNumPages = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + if (!this._wasLocalized) { + return; + } + var pageNumber = this.pageNumber, + pagesCount = this.pagesCount, + items = this.items; + + var scaleValue = (this.pageScaleValue || this.pageScale).toString(); + var scale = this.pageScale; + if (resetNumPages) { + if (this.hasPageLabels) { + items.pageNumber.type = 'text'; + } else { + items.pageNumber.type = 'number'; + this.l10n.get('of_pages', {pagesCount: pagesCount}, 'of {{pagesCount}}').then(function (msg) { + items.numPages.textContent = msg; + }); + } + items.pageNumber.max = pagesCount; + } + if (this.hasPageLabels) { + items.pageNumber.value = this.pageLabel; + this.l10n.get('page_of_pages', { + pageNumber: pageNumber, + pagesCount: pagesCount + }, '({{pageNumber}} of {{pagesCount}})').then(function (msg) { + items.numPages.textContent = msg; + }); + } else { + items.pageNumber.value = pageNumber; + } + items.previous.disabled = pageNumber <= 1; + items.next.disabled = pageNumber >= pagesCount; + items.zoomOut.disabled = scale <= _ui_utils.MIN_SCALE; + items.zoomIn.disabled = scale >= _ui_utils.MAX_SCALE; + var customScale = Math.round(scale * 10000) / 100; + this.l10n.get('page_scale_percent', {scale: customScale}, '{{scale}}%').then(function (msg) { + var options = items.scaleSelect.options; + var predefinedValueFound = false; + for (var i = 0, ii = options.length; i < ii; i++) { + var option = options[i]; + if (option.value !== scaleValue) { + option.selected = false; + continue; + } + option.selected = true; + predefinedValueFound = true; + } + if (!predefinedValueFound) { + items.customScaleOption.textContent = msg; + items.customScaleOption.selected = true; + } + }); + } + }, { + key: 'updateLoadingIndicatorState', + value: function updateLoadingIndicatorState() { + var loading = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + var pageNumberInput = this.items.pageNumber; + if (loading) { + document.querySelector("#loader").style.display = "none"; + pageNumberInput.classList.add(PAGE_NUMBER_LOADING_INDICATOR); + } else { + pageNumberInput.classList.remove(PAGE_NUMBER_LOADING_INDICATOR); + } + } + }, { + key: '_adjustScaleWidth', + value: function _adjustScaleWidth() { + var container = this.items.scaleSelectContainer; + var select = this.items.scaleSelect; + _ui_utils.animationStarted.then(function () { + if (container.clientWidth === 0) { + container.setAttribute('style', 'display: inherit;'); + } + if (container.clientWidth > 0) { + select.setAttribute('style', 'min-width: inherit;'); + var width = select.clientWidth + SCALE_SELECT_CONTAINER_PADDING; + select.setAttribute('style', 'min-width: ' + (width + SCALE_SELECT_PADDING) + 'px;'); + container.setAttribute('style', 'min-width: ' + width + 'px; ' + 'max-width: ' + width + 'px;'); + } + }); + } + }]); + + return Toolbar; + }(); + + exports.Toolbar = Toolbar; + + /***/ + }), + /* 32 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + + Object.defineProperty(exports, "__esModule", { + value: true + }); + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var DEFAULT_VIEW_HISTORY_CACHE_SIZE = 20; + + var ViewHistory = function () { + function ViewHistory(fingerprint) { + var _this = this; + + var cacheSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_VIEW_HISTORY_CACHE_SIZE; + + _classCallCheck(this, ViewHistory); + + this.fingerprint = fingerprint; + this.cacheSize = cacheSize; + this._initializedPromise = this._readFromStorage().then(function (databaseStr) { + var database = JSON.parse(databaseStr || '{}'); + if (!('files' in database)) { + database.files = []; + } + if (database.files.length >= _this.cacheSize) { + database.files.shift(); + } + var index = void 0; + for (var i = 0, length = database.files.length; i < length; i++) { + var branch = database.files[i]; + if (branch.fingerprint === _this.fingerprint) { + index = i; + break; + } + } + if (typeof index !== 'number') { + index = database.files.push({fingerprint: _this.fingerprint}) - 1; + } + _this.file = database.files[index]; + _this.database = database; + }); + } + + _createClass(ViewHistory, [{ + key: '_writeToStorage', + value: function _writeToStorage() { + var _this2 = this; + + return new Promise(function (resolve) { + var databaseStr = JSON.stringify(_this2.database); + localStorage.setItem('pdfjs.history', databaseStr); + resolve(); + }); + } + }, { + key: '_readFromStorage', + value: function _readFromStorage() { + return new Promise(function (resolve) { + var value = localStorage.getItem('pdfjs.history'); + if (!value) { + var databaseStr = localStorage.getItem('database'); + if (databaseStr) { + try { + var database = JSON.parse(databaseStr); + if (typeof database.files[0].fingerprint === 'string') { + localStorage.setItem('pdfjs.history', databaseStr); + localStorage.removeItem('database'); + value = databaseStr; + } + } catch (ex) { + } + } + } + resolve(value); + }); + } + }, { + key: 'set', + value: function set(name, val) { + var _this3 = this; + + return this._initializedPromise.then(function () { + _this3.file[name] = val; + return _this3._writeToStorage(); + }); + } + }, { + key: 'setMultiple', + value: function setMultiple(properties) { + var _this4 = this; + + return this._initializedPromise.then(function () { + for (var name in properties) { + _this4.file[name] = properties[name]; + } + return _this4._writeToStorage(); + }); + } + }, { + key: 'get', + value: function get(name, defaultValue) { + var _this5 = this; + + return this._initializedPromise.then(function () { + var val = _this5.file[name]; + return val !== undefined ? val : defaultValue; + }); + } + }, { + key: 'getMultiple', + value: function getMultiple(properties) { + var _this6 = this; + + return this._initializedPromise.then(function () { + var values = Object.create(null); + for (var name in properties) { + var val = _this6.file[name]; + values[name] = val !== undefined ? val : properties[name]; + } + return values; + }); + } + }]); + + return ViewHistory; + }(); + + exports.ViewHistory = ViewHistory; + + /***/ + }), + /* 33 */ + /***/ (function (module, exports, __webpack_require__) { + + "use strict"; + + ; + window.pdfjsWebApp = void 0; + { + window.pdfjsWebApp = __webpack_require__(4); + } + ; + { + __webpack_require__(8); + } + ; + { + __webpack_require__(9); + } + + /***/ + }) + /******/]); +//# sourceMappingURL=viewer.js.map diff --git a/twake/frontend/public/public/viewer/PDFViewer/viewer.js.map b/twake/frontend/public/public/viewer/PDFViewer/viewer.js.map new file mode 100755 index 00000000..b20a5726 --- /dev/null +++ b/twake/frontend/public/public/viewer/PDFViewer/viewer.js.map @@ -0,0 +1,81 @@ +{ + "version": 3, + "sources": [ + "webpack:///webpack/bootstrap 67a151ebb5e544e5a40d", + "webpack:///web/ui_utils.js", + "webpack:///web/pdfjs.js", + "webpack:///web/dom_events.js", + "webpack:///web/pdf_rendering_queue.js", + "webpack:///web/app.js", + "webpack:///web/pdf_link_service.js", + "webpack:///web/pdf_cursor_tools.js", + "webpack:///web/pdf_find_controller.js", + "webpack:///web/genericcom.js", + "webpack:///web/pdf_print_service.js", + "webpack:///external/webL10n/l10n.js", + "webpack:///web/annotation_layer_builder.js", + "webpack:///web/download_manager.js", + "webpack:///web/genericl10n.js", + "webpack:///web/grab_to_pan.js", + "webpack:///web/overlay_manager.js", + "webpack:///web/password_prompt.js", + "webpack:///web/pdf_attachment_viewer.js", + "webpack:///web/pdf_document_properties.js", + "webpack:///web/pdf_find_bar.js", + "webpack:///web/pdf_history.js", + "webpack:///web/pdf_outline_viewer.js", + "webpack:///web/pdf_page_view.js", + "webpack:///web/pdf_presentation_mode.js", + "webpack:///web/pdf_sidebar.js", + "webpack:///web/pdf_thumbnail_view.js", + "webpack:///web/pdf_thumbnail_viewer.js", + "webpack:///web/pdf_viewer.js", + "webpack:///web/preferences.js", + "webpack:///web/secondary_toolbar.js", + "webpack:///web/text_layer_builder.js", + "webpack:///web/toolbar.js", + "webpack:///web/view_history.js", + "webpack:///web/viewer.js" + ], + "names": [], + "mappings": "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QoB;AAgVxD,WAAS,QAAQ;AACf,gBAAY;AACZ,gBAAY;AACZ,gBAAY;AAnV0C;AAyWxD,WAAS,eAAe,MAAM;AAC5B,QAAI;AACF,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,aAAO;AACP,YAAM;AACN,YAAM;AACN,aAAO;AACP,aAAO;AACP,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,aAAO;AACP,YAAM;AACN,YAAM;AACN,aAAO;AACP,aAAO;AACP,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,aAAO;AACP,YAAM;AACN,YAAM;AACN,aAAO;AACP,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,aAAO;AACP,YAAM;AACN,aAAO;AACP,YAAM;AACN,YAAM;AACN,aAAO;AACP,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,aAAO;AACP,YAAM;AACN,YAAM;AACN,aAAO;AACP,aAAO;AACP,aAAO;AACP,aAAO;AACP,aAAO;AACP,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,aAAO;AACP,aAAO;AACP,YAAM;AACN,YAAM;AACN,aAAO;AACP,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,aAAO;AACP,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,aAAO;AACP,aAAO;AACP,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,YAAM;AACN,aAAO;AACP,YAAM;AACN,aAAO;AACP,YAAM;AACN,YAAM;AACN,YAAM;AACN,a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", + "file": "viewer.js", + "sourcesContent": [ + " \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 33);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 67a151ebb5e544e5a40d", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { PDFJS } from 'pdfjs-lib';\n\nconst CSS_UNITS = 96.0 / 72.0;\nconst DEFAULT_SCALE_VALUE = 'auto';\nconst DEFAULT_SCALE = 1.0;\nconst MIN_SCALE = 0.25;\nconst MAX_SCALE = 10.0;\nconst UNKNOWN_SCALE = 0;\nconst MAX_AUTO_SCALE = 1.25;\nconst SCROLLBAR_PADDING = 40;\nconst VERTICAL_PADDING = 5;\n\nconst RendererType = {\n CANVAS: 'canvas',\n SVG: 'svg',\n};\n\n// Replaces {{arguments}} with their values.\nfunction formatL10nValue(text, args) {\n if (!args) {\n return text;\n }\n return text.replace(/\\{\\{\\s*(\\w+)\\s*\\}\\}/g, (all, name) => {\n return (name in args ? args[name] : '{{' + name + '}}');\n });\n}\n\n/**\n * No-op implemetation of the localization service.\n * @implements {IL10n}\n */\nlet NullL10n = {\n get(property, args, fallback) {\n return Promise.resolve(formatL10nValue(fallback, args));\n },\n\n translate(element) {\n return Promise.resolve();\n },\n};\n\n/**\n * Disables fullscreen support, and by extension Presentation Mode,\n * in browsers which support the fullscreen API.\n * @var {boolean}\n */\nPDFJS.disableFullscreen = (PDFJS.disableFullscreen === undefined ?\n false : PDFJS.disableFullscreen);\n\n/**\n * Enables CSS only zooming.\n * @var {boolean}\n */\nPDFJS.useOnlyCssZoom = (PDFJS.useOnlyCssZoom === undefined ?\n false : PDFJS.useOnlyCssZoom);\n\n/**\n * The maximum supported canvas size in total pixels e.g. width * height.\n * The default value is 4096 * 4096. Use -1 for no limit.\n * @var {number}\n */\nPDFJS.maxCanvasPixels = (PDFJS.maxCanvasPixels === undefined ?\n 16777216 : PDFJS.maxCanvasPixels);\n\n/**\n * Disables saving of the last position of the viewed PDF.\n * @var {boolean}\n */\nPDFJS.disableHistory = (PDFJS.disableHistory === undefined ?\n false : PDFJS.disableHistory);\n\n/**\n * Disables creation of the text layer that used for text selection and search.\n * @var {boolean}\n */\nPDFJS.disableTextLayer = (PDFJS.disableTextLayer === undefined ?\n false : PDFJS.disableTextLayer);\n\n/**\n * Disables maintaining the current position in the document when zooming.\n */\nPDFJS.ignoreCurrentPositionOnZoom = (PDFJS.ignoreCurrentPositionOnZoom ===\n undefined ? false : PDFJS.ignoreCurrentPositionOnZoom);\n\nif (typeof PDFJSDev === 'undefined' ||\n !PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n /**\n * Interface locale settings.\n * @var {string}\n */\n PDFJS.locale =\n (PDFJS.locale === undefined && typeof navigator !== 'undefined' ?\n navigator.language : PDFJS.locale);\n}\n\n/**\n * Returns scale factor for the canvas. It makes sense for the HiDPI displays.\n * @return {Object} The object with horizontal (sx) and vertical (sy)\n scales. The scaled property is set to false if scaling is\n not required, true otherwise.\n */\nfunction getOutputScale(ctx) {\n let devicePixelRatio = window.devicePixelRatio || 1;\n let backingStoreRatio = ctx.webkitBackingStorePixelRatio ||\n ctx.mozBackingStorePixelRatio ||\n ctx.msBackingStorePixelRatio ||\n ctx.oBackingStorePixelRatio ||\n ctx.backingStorePixelRatio || 1;\n let pixelRatio = devicePixelRatio / backingStoreRatio;\n return {\n sx: pixelRatio,\n sy: pixelRatio,\n scaled: pixelRatio !== 1,\n };\n}\n\n/**\n * Scrolls specified element into view of its parent.\n * @param {Object} element - The element to be visible.\n * @param {Object} spot - An object with optional top and left properties,\n * specifying the offset from the top left edge.\n * @param {boolean} skipOverflowHiddenElements - Ignore elements that have\n * the CSS rule `overflow: hidden;` set. The default is false.\n */\nfunction scrollIntoView(element, spot, skipOverflowHiddenElements = false) {\n // Assuming offsetParent is available (it's not available when viewer is in\n // hidden iframe or object). We have to scroll: if the offsetParent is not set\n // producing the error. See also animationStarted.\n let parent = element.offsetParent;\n if (!parent) {\n console.error('offsetParent is not set -- cannot scroll');\n return;\n }\n let offsetY = element.offsetTop + element.clientTop;\n let offsetX = element.offsetLeft + element.clientLeft;\n while (parent.clientHeight === parent.scrollHeight ||\n (skipOverflowHiddenElements &&\n getComputedStyle(parent).overflow === 'hidden')) {\n if (parent.dataset._scaleY) {\n offsetY /= parent.dataset._scaleY;\n offsetX /= parent.dataset._scaleX;\n }\n offsetY += parent.offsetTop;\n offsetX += parent.offsetLeft;\n parent = parent.offsetParent;\n if (!parent) {\n return; // no need to scroll\n }\n }\n if (spot) {\n if (spot.top !== undefined) {\n offsetY += spot.top;\n }\n if (spot.left !== undefined) {\n offsetX += spot.left;\n parent.scrollLeft = offsetX;\n }\n }\n parent.scrollTop = offsetY;\n}\n\n/**\n * Helper function to start monitoring the scroll event and converting them into\n * PDF.js friendly one: with scroll debounce and scroll direction.\n */\nfunction watchScroll(viewAreaElement, callback) {\n let debounceScroll = function(evt) {\n if (rAF) {\n return;\n }\n // schedule an invocation of scroll for next animation frame.\n rAF = window.requestAnimationFrame(function viewAreaElementScrolled() {\n rAF = null;\n\n let currentY = viewAreaElement.scrollTop;\n let lastY = state.lastY;\n if (currentY !== lastY) {\n state.down = currentY > lastY;\n }\n state.lastY = currentY;\n callback(state);\n });\n };\n\n let state = {\n down: true,\n lastY: viewAreaElement.scrollTop,\n _eventHandler: debounceScroll,\n };\n\n let rAF = null;\n viewAreaElement.addEventListener('scroll', debounceScroll, true);\n return state;\n}\n\n/**\n * Helper function to parse query string (e.g. ?param1=value&parm2=...).\n */\nfunction parseQueryString(query) {\n let parts = query.split('&');\n let params = Object.create(null);\n for (let i = 0, ii = parts.length; i < ii; ++i) {\n let param = parts[i].split('=');\n let key = param[0].toLowerCase();\n let value = param.length > 1 ? param[1] : null;\n params[decodeURIComponent(key)] = decodeURIComponent(value);\n }\n return params;\n}\n\n/**\n * Use binary search to find the index of the first item in a given array which\n * passes a given condition. The items are expected to be sorted in the sense\n * that if the condition is true for one item in the array, then it is also true\n * for all following items.\n *\n * @returns {Number} Index of the first array element to pass the test,\n * or |items.length| if no such element exists.\n */\nfunction binarySearchFirstItem(items, condition) {\n let minIndex = 0;\n let maxIndex = items.length - 1;\n\n if (items.length === 0 || !condition(items[maxIndex])) {\n return items.length;\n }\n if (condition(items[minIndex])) {\n return minIndex;\n }\n\n while (minIndex < maxIndex) {\n let currentIndex = (minIndex + maxIndex) >> 1;\n let currentItem = items[currentIndex];\n if (condition(currentItem)) {\n maxIndex = currentIndex;\n } else {\n minIndex = currentIndex + 1;\n }\n }\n return minIndex; /* === maxIndex */\n}\n\n/**\n * Approximates float number as a fraction using Farey sequence (max order\n * of 8).\n * @param {number} x - Positive float number.\n * @returns {Array} Estimated fraction: the first array item is a numerator,\n * the second one is a denominator.\n */\nfunction approximateFraction(x) {\n // Fast paths for int numbers or their inversions.\n if (Math.floor(x) === x) {\n return [x, 1];\n }\n let xinv = 1 / x;\n let limit = 8;\n if (xinv > limit) {\n return [1, limit];\n } else if (Math.floor(xinv) === xinv) {\n return [1, xinv];\n }\n\n let x_ = x > 1 ? xinv : x;\n // a/b and c/d are neighbours in Farey sequence.\n let a = 0, b = 1, c = 1, d = 1;\n // Limiting search to order 8.\n while (true) {\n // Generating next term in sequence (order of q).\n let p = a + c, q = b + d;\n if (q > limit) {\n break;\n }\n if (x_ <= p / q) {\n c = p; d = q;\n } else {\n a = p; b = q;\n }\n }\n let result;\n // Select closest of the neighbours to x.\n if (x_ - a / b < c / d - x_) {\n result = x_ === x ? [a, b] : [b, a];\n } else {\n result = x_ === x ? [c, d] : [d, c];\n }\n return result;\n}\n\nfunction roundToDivide(x, div) {\n let r = x % div;\n return r === 0 ? x : Math.round(x - r + div);\n}\n\n/**\n * Generic helper to find out what elements are visible within a scroll pane.\n */\nfunction getVisibleElements(scrollEl, views, sortByVisibility = false) {\n let top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight;\n let left = scrollEl.scrollLeft, right = left + scrollEl.clientWidth;\n\n function isElementBottomBelowViewTop(view) {\n let element = view.div;\n let elementBottom =\n element.offsetTop + element.clientTop + element.clientHeight;\n return elementBottom > top;\n }\n\n let visible = [], view, element;\n let currentHeight, viewHeight, hiddenHeight, percentHeight;\n let currentWidth, viewWidth;\n let firstVisibleElementInd = views.length === 0 ? 0 :\n binarySearchFirstItem(views, isElementBottomBelowViewTop);\n\n for (let i = firstVisibleElementInd, ii = views.length; i < ii; i++) {\n view = views[i];\n element = view.div;\n currentHeight = element.offsetTop + element.clientTop;\n viewHeight = element.clientHeight;\n\n if (currentHeight > bottom) {\n break;\n }\n\n currentWidth = element.offsetLeft + element.clientLeft;\n viewWidth = element.clientWidth;\n if (currentWidth + viewWidth < left || currentWidth > right) {\n continue;\n }\n hiddenHeight = Math.max(0, top - currentHeight) +\n Math.max(0, currentHeight + viewHeight - bottom);\n percentHeight = ((viewHeight - hiddenHeight) * 100 / viewHeight) | 0;\n\n visible.push({\n id: view.id,\n x: currentWidth,\n y: currentHeight,\n view,\n percent: percentHeight,\n });\n }\n\n let first = visible[0];\n let last = visible[visible.length - 1];\n\n if (sortByVisibility) {\n visible.sort(function(a, b) {\n let pc = a.percent - b.percent;\n if (Math.abs(pc) > 0.001) {\n return -pc;\n }\n return a.id - b.id; // ensure stability\n });\n }\n return { first, last, views: visible, };\n}\n\n/**\n * Event handler to suppress context menu.\n */\nfunction noContextMenuHandler(evt) {\n evt.preventDefault();\n}\n\nfunction isDataSchema(url) {\n let i = 0, ii = url.length;\n while (i < ii && url[i].trim() === '') {\n i++;\n }\n return url.substr(i, 5).toLowerCase() === 'data:';\n}\n\n/**\n * Returns the filename or guessed filename from the url (see issue 3455).\n * @param {string} url - The original PDF location.\n * @param {string} defaultFilename - The value returned if the filename is\n * unknown, or the protocol is unsupported.\n * @returns {string} Guessed PDF filename.\n */\nfunction getPDFFileNameFromURL(url, defaultFilename = 'document.pdf') {\n if (isDataSchema(url)) {\n console.warn('getPDFFileNameFromURL: ' +\n 'ignoring \"data:\" URL for performance reasons.');\n return defaultFilename;\n }\n const reURI = /^(?:(?:[^:]+:)?\\/\\/[^\\/]+)?([^?#]*)(\\?[^#]*)?(#.*)?$/;\n // SCHEME HOST 1.PATH 2.QUERY 3.REF\n // Pattern to get last matching NAME.pdf\n const reFilename = /[^\\/?#=]+\\.pdf\\b(?!.*\\.pdf\\b)/i;\n let splitURI = reURI.exec(url);\n let suggestedFilename = reFilename.exec(splitURI[1]) ||\n reFilename.exec(splitURI[2]) ||\n reFilename.exec(splitURI[3]);\n if (suggestedFilename) {\n suggestedFilename = suggestedFilename[0];\n if (suggestedFilename.indexOf('%') !== -1) {\n // URL-encoded %2Fpath%2Fto%2Ffile.pdf should be file.pdf\n try {\n suggestedFilename =\n reFilename.exec(decodeURIComponent(suggestedFilename))[0];\n } catch (ex) { // Possible (extremely rare) errors:\n // URIError \"Malformed URI\", e.g. for \"%AA.pdf\"\n // TypeError \"null has no properties\", e.g. for \"%2F.pdf\"\n }\n }\n }\n return suggestedFilename || defaultFilename;\n}\n\nfunction normalizeWheelEventDelta(evt) {\n let delta = Math.sqrt(evt.deltaX * evt.deltaX + evt.deltaY * evt.deltaY);\n let angle = Math.atan2(evt.deltaY, evt.deltaX);\n if (-0.25 * Math.PI < angle && angle < 0.75 * Math.PI) {\n // All that is left-up oriented has to change the sign.\n delta = -delta;\n }\n\n const MOUSE_DOM_DELTA_PIXEL_MODE = 0;\n const MOUSE_DOM_DELTA_LINE_MODE = 1;\n const MOUSE_PIXELS_PER_LINE = 30;\n const MOUSE_LINES_PER_PAGE = 30;\n\n // Converts delta to per-page units\n if (evt.deltaMode === MOUSE_DOM_DELTA_PIXEL_MODE) {\n delta /= MOUSE_PIXELS_PER_LINE * MOUSE_LINES_PER_PAGE;\n } else if (evt.deltaMode === MOUSE_DOM_DELTA_LINE_MODE) {\n delta /= MOUSE_LINES_PER_PAGE;\n }\n return delta;\n}\n\nfunction cloneObj(obj) {\n let result = Object.create(null);\n for (let i in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, i)) {\n result[i] = obj[i];\n }\n }\n return result;\n}\n\n/**\n * Promise that is resolved when DOM window becomes visible.\n */\nlet animationStarted = new Promise(function (resolve) {\n window.requestAnimationFrame(resolve);\n});\n\n/**\n * (deprecated) External localization service.\n */\nlet mozL10n;\n\n/**\n * (deprecated) Promise that is resolved when UI localization is finished.\n */\nlet localized = Promise.resolve();\n\n/**\n * Simple event bus for an application. Listeners are attached using the\n * `on` and `off` methods. To raise an event, the `dispatch` method shall be\n * used.\n */\nclass EventBus {\n constructor() {\n this._listeners = Object.create(null);\n }\n\n on(eventName, listener) {\n let eventListeners = this._listeners[eventName];\n if (!eventListeners) {\n eventListeners = [];\n this._listeners[eventName] = eventListeners;\n }\n eventListeners.push(listener);\n }\n\n off(eventName, listener) {\n let eventListeners = this._listeners[eventName];\n let i;\n if (!eventListeners || ((i = eventListeners.indexOf(listener)) < 0)) {\n return;\n }\n eventListeners.splice(i, 1);\n }\n\n dispatch(eventName) {\n let eventListeners = this._listeners[eventName];\n if (!eventListeners || eventListeners.length === 0) {\n return;\n }\n // Passing all arguments after the eventName to the listeners.\n let args = Array.prototype.slice.call(arguments, 1);\n // Making copy of the listeners array in case if it will be modified\n // during dispatch.\n eventListeners.slice(0).forEach(function (listener) {\n listener.apply(null, args);\n });\n }\n}\n\nfunction clamp(v, min, max) {\n return Math.min(Math.max(v, min), max);\n}\n\nclass ProgressBar {\n constructor(id, { height, width, units, } = {}) {\n this.visible = true;\n\n // Fetch the sub-elements for later.\n this.div = document.querySelector(id + ' .progress');\n // Get the loading bar element, so it can be resized to fit the viewer.\n this.bar = this.div.parentNode;\n\n // Get options, with sensible defaults.\n this.height = height || 100;\n this.width = width || 100;\n this.units = units || '%';\n\n // Initialize heights.\n this.div.style.height = this.height + this.units;\n this.percent = 0;\n }\n\n _updateBar() {\n if (this._indeterminate) {\n this.div.classList.add('indeterminate');\n this.div.style.width = this.width + this.units;\n return;\n }\n\n this.div.classList.remove('indeterminate');\n let progressSize = this.width * this._percent / 100;\n this.div.style.width = progressSize + this.units;\n }\n\n get percent() {\n return this._percent;\n }\n\n set percent(val) {\n this._indeterminate = isNaN(val);\n this._percent = clamp(val, 0, 100);\n this._updateBar();\n }\n\n setWidth(viewer) {\n if (!viewer) {\n return;\n }\n let container = viewer.parentNode;\n let scrollbarWidth = container.offsetWidth - viewer.offsetWidth;\n if (scrollbarWidth > 0) {\n this.bar.setAttribute('style', 'width: calc(100% - ' +\n scrollbarWidth + 'px);');\n }\n }\n\n hide() {\n if (!this.visible) {\n return;\n }\n this.visible = false;\n this.bar.classList.add('hidden');\n document.body.classList.remove('loadingInProgress');\n }\n\n show() {\n if (this.visible) {\n return;\n }\n this.visible = true;\n document.body.classList.add('loadingInProgress');\n this.bar.classList.remove('hidden');\n }\n}\n\nexport {\n CSS_UNITS,\n DEFAULT_SCALE_VALUE,\n DEFAULT_SCALE,\n MIN_SCALE,\n MAX_SCALE,\n UNKNOWN_SCALE,\n MAX_AUTO_SCALE,\n SCROLLBAR_PADDING,\n VERTICAL_PADDING,\n cloneObj,\n RendererType,\n mozL10n,\n NullL10n,\n EventBus,\n ProgressBar,\n getPDFFileNameFromURL,\n noContextMenuHandler,\n parseQueryString,\n getVisibleElements,\n roundToDivide,\n approximateFraction,\n getOutputScale,\n scrollIntoView,\n watchScroll,\n binarySearchFirstItem,\n normalizeWheelEventDelta,\n animationStarted,\n localized,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/ui_utils.js", + "/* Copyright 2016 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* globals module, __non_webpack_require__ */\n\n'use strict';\n\nvar pdfjsLib;\nif (typeof window !== 'undefined' && window['pdfjs-dist/build/pdf']) {\n pdfjsLib = window['pdfjs-dist/build/pdf'];\n} else {\n pdfjsLib = __non_webpack_require__('../build/pdf.js');\n}\nmodule.exports = pdfjsLib;\n\n\n\n// WEBPACK FOOTER //\n// web/pdfjs.js", + "/* Copyright 2016 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { EventBus } from './ui_utils';\n\n// Attaching to the application event bus to dispatch events to the DOM for\n// backwards viewer API compatibility.\nfunction attachDOMEventsToEventBus(eventBus) {\n eventBus.on('documentload', function() {\n let event = document.createEvent('CustomEvent');\n event.initCustomEvent('documentload', true, true, {});\n window.dispatchEvent(event);\n });\n eventBus.on('pagerendered', function(evt) {\n let event = document.createEvent('CustomEvent');\n event.initCustomEvent('pagerendered', true, true, {\n pageNumber: evt.pageNumber,\n cssTransform: evt.cssTransform,\n });\n evt.source.div.dispatchEvent(event);\n });\n eventBus.on('textlayerrendered', function(evt) {\n let event = document.createEvent('CustomEvent');\n event.initCustomEvent('textlayerrendered', true, true, {\n pageNumber: evt.pageNumber,\n });\n evt.source.textLayerDiv.dispatchEvent(event);\n });\n eventBus.on('pagechange', function(evt) {\n let event = document.createEvent('UIEvents');\n event.initUIEvent('pagechange', true, true, window, 0);\n event.pageNumber = evt.pageNumber;\n evt.source.container.dispatchEvent(event);\n });\n eventBus.on('pagesinit', function(evt) {\n let event = document.createEvent('CustomEvent');\n event.initCustomEvent('pagesinit', true, true, null);\n evt.source.container.dispatchEvent(event);\n });\n eventBus.on('pagesloaded', function(evt) {\n let event = document.createEvent('CustomEvent');\n event.initCustomEvent('pagesloaded', true, true, {\n pagesCount: evt.pagesCount,\n });\n evt.source.container.dispatchEvent(event);\n });\n eventBus.on('scalechange', function(evt) {\n let event = document.createEvent('UIEvents');\n event.initUIEvent('scalechange', true, true, window, 0);\n event.scale = evt.scale;\n event.presetValue = evt.presetValue;\n evt.source.container.dispatchEvent(event);\n });\n eventBus.on('updateviewarea', function(evt) {\n let event = document.createEvent('UIEvents');\n event.initUIEvent('updateviewarea', true, true, window, 0);\n event.location = evt.location;\n evt.source.container.dispatchEvent(event);\n });\n eventBus.on('find', function(evt) {\n if (evt.source === window) {\n return; // event comes from FirefoxCom, no need to replicate\n }\n let event = document.createEvent('CustomEvent');\n event.initCustomEvent('find' + evt.type, true, true, {\n query: evt.query,\n phraseSearch: evt.phraseSearch,\n caseSensitive: evt.caseSensitive,\n highlightAll: evt.highlightAll,\n findPrevious: evt.findPrevious,\n });\n window.dispatchEvent(event);\n });\n eventBus.on('attachmentsloaded', function(evt) {\n let event = document.createEvent('CustomEvent');\n event.initCustomEvent('attachmentsloaded', true, true, {\n attachmentsCount: evt.attachmentsCount,\n });\n evt.source.container.dispatchEvent(event);\n });\n eventBus.on('sidebarviewchanged', function(evt) {\n let event = document.createEvent('CustomEvent');\n event.initCustomEvent('sidebarviewchanged', true, true, {\n view: evt.view,\n });\n evt.source.outerContainer.dispatchEvent(event);\n });\n eventBus.on('pagemode', function(evt) {\n let event = document.createEvent('CustomEvent');\n event.initCustomEvent('pagemode', true, true, {\n mode: evt.mode,\n });\n evt.source.pdfViewer.container.dispatchEvent(event);\n });\n eventBus.on('namedaction', function(evt) {\n let event = document.createEvent('CustomEvent');\n event.initCustomEvent('namedaction', true, true, {\n action: evt.action,\n });\n evt.source.pdfViewer.container.dispatchEvent(event);\n });\n eventBus.on('presentationmodechanged', function(evt) {\n let event = document.createEvent('CustomEvent');\n event.initCustomEvent('presentationmodechanged', true, true, {\n active: evt.active,\n switchInProgress: evt.switchInProgress,\n });\n window.dispatchEvent(event);\n });\n eventBus.on('outlineloaded', function(evt) {\n let event = document.createEvent('CustomEvent');\n event.initCustomEvent('outlineloaded', true, true, {\n outlineCount: evt.outlineCount,\n });\n evt.source.container.dispatchEvent(event);\n });\n}\n\nlet globalEventBus = null;\nfunction getGlobalEventBus() {\n if (globalEventBus) {\n return globalEventBus;\n }\n globalEventBus = new EventBus();\n attachDOMEventsToEventBus(globalEventBus);\n return globalEventBus;\n}\n\nexport {\n attachDOMEventsToEventBus,\n getGlobalEventBus,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/dom_events.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst CLEANUP_TIMEOUT = 30000;\n\nconst RenderingStates = {\n INITIAL: 0,\n RUNNING: 1,\n PAUSED: 2,\n FINISHED: 3,\n};\n\n/**\n * Controls rendering of the views for pages and thumbnails.\n */\nclass PDFRenderingQueue {\n constructor() {\n this.pdfViewer = null;\n this.pdfThumbnailViewer = null;\n this.onIdle = null;\n this.highestPriorityPage = null;\n this.idleTimeout = null;\n this.printing = false;\n this.isThumbnailViewEnabled = false;\n }\n\n /**\n * @param {PDFViewer} pdfViewer\n */\n setViewer(pdfViewer) {\n this.pdfViewer = pdfViewer;\n }\n\n /**\n * @param {PDFThumbnailViewer} pdfThumbnailViewer\n */\n setThumbnailViewer(pdfThumbnailViewer) {\n this.pdfThumbnailViewer = pdfThumbnailViewer;\n }\n\n /**\n * @param {IRenderableView} view\n * @returns {boolean}\n */\n isHighestPriority(view) {\n return this.highestPriorityPage === view.renderingId;\n }\n\n /**\n * @param {Object} currentlyVisiblePages\n */\n renderHighestPriority(currentlyVisiblePages) {\n if (this.idleTimeout) {\n clearTimeout(this.idleTimeout);\n this.idleTimeout = null;\n }\n\n // Pages have a higher priority than thumbnails, so check them first.\n if (this.pdfViewer.forceRendering(currentlyVisiblePages)) {\n return;\n }\n // No pages needed rendering, so check thumbnails.\n if (this.pdfThumbnailViewer && this.isThumbnailViewEnabled) {\n if (this.pdfThumbnailViewer.forceRendering()) {\n return;\n }\n }\n\n if (this.printing) {\n // If printing is currently ongoing do not reschedule cleanup.\n return;\n }\n\n if (this.onIdle) {\n this.idleTimeout = setTimeout(this.onIdle.bind(this), CLEANUP_TIMEOUT);\n }\n }\n\n /**\n * @param {Object} visible\n * @param {Array} views\n * @param {boolean} scrolledDown\n */\n getHighestPriority(visible, views, scrolledDown) {\n /**\n * The state has changed. Figure out which page has the highest priority to\n * render next (if any).\n *\n * Priority:\n * 1. visible pages\n * 2. if last scrolled down, the page after the visible pages, or\n * if last scrolled up, the page before the visible pages\n */\n var visibleViews = visible.views;\n\n var numVisible = visibleViews.length;\n if (numVisible === 0) {\n return false;\n }\n for (var i = 0; i < numVisible; ++i) {\n var view = visibleViews[i].view;\n if (!this.isViewFinished(view)) {\n return view;\n }\n }\n\n // All the visible views have rendered; try to render next/previous pages.\n if (scrolledDown) {\n var nextPageIndex = visible.last.id;\n // IDs start at 1, so no need to add 1.\n if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex])) {\n return views[nextPageIndex];\n }\n } else {\n var previousPageIndex = visible.first.id - 2;\n if (views[previousPageIndex] &&\n !this.isViewFinished(views[previousPageIndex])) {\n return views[previousPageIndex];\n }\n }\n // Everything that needs to be rendered has been.\n return null;\n }\n\n /**\n * @param {IRenderableView} view\n * @returns {boolean}\n */\n isViewFinished(view) {\n return view.renderingState === RenderingStates.FINISHED;\n }\n\n /**\n * Render a page or thumbnail view. This calls the appropriate function\n * based on the views state. If the view is already rendered it will return\n * `false`.\n *\n * @param {IRenderableView} view\n */\n renderView(view) {\n switch (view.renderingState) {\n case RenderingStates.FINISHED:\n return false;\n case RenderingStates.PAUSED:\n this.highestPriorityPage = view.renderingId;\n view.resume();\n break;\n case RenderingStates.RUNNING:\n this.highestPriorityPage = view.renderingId;\n break;\n case RenderingStates.INITIAL:\n this.highestPriorityPage = view.renderingId;\n var continueRendering = () => {\n this.renderHighestPriority();\n };\n view.draw().then(continueRendering, continueRendering);\n break;\n }\n return true;\n }\n}\n\nexport {\n RenderingStates,\n PDFRenderingQueue,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/pdf_rendering_queue.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* globals PDFBug, Stats */\n\nimport {\n animationStarted, DEFAULT_SCALE_VALUE, getPDFFileNameFromURL, MAX_SCALE,\n MIN_SCALE, noContextMenuHandler, normalizeWheelEventDelta,\n parseQueryString, ProgressBar, RendererType, UNKNOWN_SCALE\n} from './ui_utils';\nimport {\n build, createBlob, getDocument, getFilenameFromUrl, InvalidPDFException,\n MissingPDFException, OPS, PDFJS, shadow, UnexpectedResponseException,\n UNSUPPORTED_FEATURES, version\n} from 'pdfjs-lib';\nimport { CursorTool, PDFCursorTools } from './pdf_cursor_tools';\nimport { PDFRenderingQueue, RenderingStates } from './pdf_rendering_queue';\nimport { PDFSidebar, SidebarView } from './pdf_sidebar';\nimport { PDFViewer, PresentationModeState } from './pdf_viewer';\nimport { getGlobalEventBus } from './dom_events';\nimport { OverlayManager } from './overlay_manager';\nimport { PasswordPrompt } from './password_prompt';\nimport { PDFAttachmentViewer } from './pdf_attachment_viewer';\nimport { PDFDocumentProperties } from './pdf_document_properties';\nimport { PDFFindBar } from './pdf_find_bar';\nimport { PDFFindController } from './pdf_find_controller';\nimport { PDFHistory } from './pdf_history';\nimport { PDFLinkService } from './pdf_link_service';\nimport { PDFOutlineViewer } from './pdf_outline_viewer';\nimport { PDFPresentationMode } from './pdf_presentation_mode';\nimport { PDFThumbnailViewer } from './pdf_thumbnail_viewer';\nimport { SecondaryToolbar } from './secondary_toolbar';\nimport { Toolbar } from './toolbar';\nimport { ViewHistory } from './view_history';\n\nconst DEFAULT_SCALE_DELTA = 1.1;\nconst DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000;\n\nfunction configure(PDFJS) {\n PDFJS.imageResourcesPath = './images/';\n if (typeof PDFJSDev !== 'undefined' &&\n PDFJSDev.test('FIREFOX || MOZCENTRAL || GENERIC || CHROME')) {\n PDFJS.workerSrc = '../build/pdf.worker.js';\n }\n if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('PRODUCTION')) {\n PDFJS.cMapUrl = '../external/bcmaps/';\n PDFJS.cMapPacked = true;\n PDFJS.workerSrc = '../src/worker_loader.js';\n PDFJS.pdfjsNext = true;\n } else {\n PDFJS.cMapUrl = '../web/cmaps/';\n PDFJS.cMapPacked = true;\n }\n}\n\nconst DefaultExternalServices = {\n updateFindControlState(data) {},\n initPassiveLoading(callbacks) {},\n fallback(data, callback) {},\n reportTelemetry(data) {},\n createDownloadManager() {\n throw new Error('Not implemented: createDownloadManager');\n },\n createPreferences() {\n throw new Error('Not implemented: createPreferences');\n },\n createL10n() {\n throw new Error('Not implemented: createL10n');\n },\n supportsIntegratedFind: false,\n supportsDocumentFonts: true,\n supportsDocumentColors: true,\n supportedMouseWheelZoomModifierKeys: {\n ctrlKey: true,\n metaKey: true,\n },\n};\n\nlet PDFViewerApplication = {\n initialBookmark: document.location.hash.substring(1),\n initialDestination: null,\n initialized: false,\n fellback: false,\n appConfig: null,\n pdfDocument: null,\n pdfLoadingTask: null,\n printService: null,\n /** @type {PDFViewer} */\n pdfViewer: null,\n /** @type {PDFThumbnailViewer} */\n pdfThumbnailViewer: null,\n /** @type {PDFRenderingQueue} */\n pdfRenderingQueue: null,\n /** @type {PDFPresentationMode} */\n pdfPresentationMode: null,\n /** @type {PDFDocumentProperties} */\n pdfDocumentProperties: null,\n /** @type {PDFLinkService} */\n pdfLinkService: null,\n /** @type {PDFHistory} */\n pdfHistory: null,\n /** @type {PDFSidebar} */\n pdfSidebar: null,\n /** @type {PDFOutlineViewer} */\n pdfOutlineViewer: null,\n /** @type {PDFAttachmentViewer} */\n pdfAttachmentViewer: null,\n /** @type {PDFCursorTools} */\n pdfCursorTools: null,\n /** @type {ViewHistory} */\n store: null,\n /** @type {DownloadManager} */\n downloadManager: null,\n /** @type {OverlayManager} */\n overlayManager: null,\n /** @type {Preferences} */\n preferences: null,\n /** @type {Toolbar} */\n toolbar: null,\n /** @type {SecondaryToolbar} */\n secondaryToolbar: null,\n /** @type {EventBus} */\n eventBus: null,\n /** @type {IL10n} */\n l10n: null,\n isInitialViewSet: false,\n downloadComplete: false,\n viewerPrefs: {\n sidebarViewOnLoad: SidebarView.NONE,\n pdfBugEnabled: false,\n showPreviousViewOnLoad: true,\n defaultZoomValue: '',\n disablePageMode: false,\n disablePageLabels: false,\n renderer: 'canvas',\n enhanceTextSelection: false,\n renderInteractiveForms: false,\n enablePrintAutoRotate: false,\n },\n isViewerEmbedded: (window.parent !== window),\n url: '',\n baseUrl: '',\n externalServices: DefaultExternalServices,\n _boundEvents: {},\n\n // Called once when the document is loaded.\n initialize(appConfig) {\n this.preferences = this.externalServices.createPreferences();\n\n configure(PDFJS);\n this.appConfig = appConfig;\n\n return this._readPreferences().then(() => {\n return this._initializeL10n();\n }).then(() => {\n return this._initializeViewerComponents();\n }).then(() => {\n // Bind the various event handlers *after* the viewer has been\n // initialized, to prevent errors if an event arrives too soon.\n this.bindEvents();\n this.bindWindowEvents();\n\n // We can start UI localization now.\n let appContainer = appConfig.appContainer || document.documentElement;\n this.l10n.translate(appContainer).then(() => {\n // Dispatch the 'localized' event on the `eventBus` once the viewer\n // has been fully initialized and translated.\n this.eventBus.dispatch('localized');\n });\n\n if (this.isViewerEmbedded && !PDFJS.isExternalLinkTargetSet()) {\n // Prevent external links from \"replacing\" the viewer,\n // when it's embedded in e.g. an iframe or an object.\n PDFJS.externalLinkTarget = PDFJS.LinkTarget.TOP;\n }\n\n this.initialized = true;\n });\n },\n\n /**\n * @private\n */\n _readPreferences() {\n let { preferences, viewerPrefs, } = this;\n\n return Promise.all([\n preferences.get('enableWebGL').then(function resolved(value) {\n PDFJS.disableWebGL = !value;\n }),\n preferences.get('sidebarViewOnLoad').then(function resolved(value) {\n viewerPrefs['sidebarViewOnLoad'] = value;\n }),\n preferences.get('pdfBugEnabled').then(function resolved(value) {\n viewerPrefs['pdfBugEnabled'] = value;\n }),\n preferences.get('showPreviousViewOnLoad').then(function resolved(value) {\n viewerPrefs['showPreviousViewOnLoad'] = value;\n }),\n preferences.get('defaultZoomValue').then(function resolved(value) {\n viewerPrefs['defaultZoomValue'] = value;\n }),\n preferences.get('enhanceTextSelection').then(function resolved(value) {\n viewerPrefs['enhanceTextSelection'] = value;\n }),\n preferences.get('disableTextLayer').then(function resolved(value) {\n if (PDFJS.disableTextLayer === true) {\n return;\n }\n PDFJS.disableTextLayer = value;\n }),\n preferences.get('disableRange').then(function resolved(value) {\n if (PDFJS.disableRange === true) {\n return;\n }\n PDFJS.disableRange = value;\n }),\n preferences.get('disableStream').then(function resolved(value) {\n if (PDFJS.disableStream === true) {\n return;\n }\n PDFJS.disableStream = value;\n }),\n preferences.get('disableAutoFetch').then(function resolved(value) {\n PDFJS.disableAutoFetch = value;\n }),\n preferences.get('disableFontFace').then(function resolved(value) {\n if (PDFJS.disableFontFace === true) {\n return;\n }\n PDFJS.disableFontFace = value;\n }),\n preferences.get('useOnlyCssZoom').then(function resolved(value) {\n PDFJS.useOnlyCssZoom = value;\n }),\n preferences.get('externalLinkTarget').then(function resolved(value) {\n if (PDFJS.isExternalLinkTargetSet()) {\n return;\n }\n PDFJS.externalLinkTarget = value;\n }),\n preferences.get('renderer').then(function resolved(value) {\n viewerPrefs['renderer'] = value;\n }),\n preferences.get('renderInteractiveForms').then(function resolved(value) {\n viewerPrefs['renderInteractiveForms'] = value;\n }),\n preferences.get('disablePageMode').then(function resolved(value) {\n viewerPrefs['disablePageMode'] = value;\n }),\n preferences.get('disablePageLabels').then(function resolved(value) {\n viewerPrefs['disablePageLabels'] = value;\n }),\n preferences.get('enablePrintAutoRotate').then(function resolved(value) {\n viewerPrefs['enablePrintAutoRotate'] = value;\n }),\n ]).catch(function(reason) { });\n },\n\n _initializeL10n() {\n // Locale can be changed only when special debugging flags is present in\n // the hash section of the URL, or development version of viewer is used.\n // It is not possible to change locale for Firefox extension builds.\n if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('PRODUCTION') ||\n (!PDFJSDev.test('FIREFOX || MOZCENTRAL') &&\n this.viewerPrefs['pdfBugEnabled'])) {\n let hash = document.location.hash.substring(1);\n let hashParams = parseQueryString(hash);\n if ('locale' in hashParams) {\n PDFJS.locale = hashParams['locale'];\n }\n }\n this.l10n = this.externalServices.createL10n();\n return this.l10n.getDirection().then((dir) => {\n document.getElementsByTagName('html')[0].dir = dir;\n });\n },\n\n /**\n * @private\n */\n _initializeViewerComponents() {\n let appConfig = this.appConfig;\n\n return new Promise((resolve, reject) => {\n this.overlayManager = new OverlayManager();\n\n let eventBus = appConfig.eventBus || getGlobalEventBus();\n this.eventBus = eventBus;\n\n let pdfRenderingQueue = new PDFRenderingQueue();\n pdfRenderingQueue.onIdle = this.cleanup.bind(this);\n this.pdfRenderingQueue = pdfRenderingQueue;\n\n let pdfLinkService = new PDFLinkService({\n eventBus,\n });\n this.pdfLinkService = pdfLinkService;\n\n let downloadManager = this.externalServices.createDownloadManager();\n this.downloadManager = downloadManager;\n\n let container = appConfig.mainContainer;\n let viewer = appConfig.viewerContainer;\n this.pdfViewer = new PDFViewer({\n container,\n viewer,\n eventBus,\n renderingQueue: pdfRenderingQueue,\n linkService: pdfLinkService,\n downloadManager,\n renderer: this.viewerPrefs['renderer'],\n l10n: this.l10n,\n enhanceTextSelection: this.viewerPrefs['enhanceTextSelection'],\n renderInteractiveForms: this.viewerPrefs['renderInteractiveForms'],\n enablePrintAutoRotate: this.viewerPrefs['enablePrintAutoRotate'],\n });\n pdfRenderingQueue.setViewer(this.pdfViewer);\n pdfLinkService.setViewer(this.pdfViewer);\n\n let thumbnailContainer = appConfig.sidebar.thumbnailView;\n this.pdfThumbnailViewer = new PDFThumbnailViewer({\n container: thumbnailContainer,\n renderingQueue: pdfRenderingQueue,\n linkService: pdfLinkService,\n l10n: this.l10n,\n });\n pdfRenderingQueue.setThumbnailViewer(this.pdfThumbnailViewer);\n\n this.pdfHistory = new PDFHistory({\n linkService: pdfLinkService,\n eventBus,\n });\n pdfLinkService.setHistory(this.pdfHistory);\n\n this.findController = new PDFFindController({\n pdfViewer: this.pdfViewer,\n });\n this.findController.onUpdateResultsCount = (matchCount) => {\n if (this.supportsIntegratedFind) {\n return;\n }\n this.findBar.updateResultsCount(matchCount);\n };\n this.findController.onUpdateState = (state, previous, matchCount) => {\n if (this.supportsIntegratedFind) {\n this.externalServices.updateFindControlState({\n result: state,\n findPrevious: previous,\n });\n } else {\n this.findBar.updateUIState(state, previous, matchCount);\n }\n };\n\n this.pdfViewer.setFindController(this.findController);\n\n // TODO: improve `PDFFindBar` constructor parameter passing\n let findBarConfig = Object.create(appConfig.findBar);\n findBarConfig.findController = this.findController;\n findBarConfig.eventBus = eventBus;\n this.findBar = new PDFFindBar(findBarConfig, this.l10n);\n\n this.pdfDocumentProperties =\n new PDFDocumentProperties(appConfig.documentProperties,\n this.overlayManager, this.l10n);\n\n this.pdfCursorTools = new PDFCursorTools({\n container,\n eventBus,\n preferences: this.preferences,\n });\n\n this.toolbar = new Toolbar(appConfig.toolbar, container, eventBus,\n this.l10n);\n\n this.secondaryToolbar =\n new SecondaryToolbar(appConfig.secondaryToolbar, container, eventBus);\n\n if (this.supportsFullscreen) {\n this.pdfPresentationMode = new PDFPresentationMode({\n container,\n viewer,\n pdfViewer: this.pdfViewer,\n eventBus,\n contextMenuItems: appConfig.fullscreen,\n });\n }\n\n this.passwordPrompt = new PasswordPrompt(appConfig.passwordOverlay,\n this.overlayManager, this.l10n);\n\n this.pdfOutlineViewer = new PDFOutlineViewer({\n container: appConfig.sidebar.outlineView,\n eventBus,\n linkService: pdfLinkService,\n });\n\n this.pdfAttachmentViewer = new PDFAttachmentViewer({\n container: appConfig.sidebar.attachmentsView,\n eventBus,\n downloadManager,\n });\n\n // TODO: improve `PDFSidebar` constructor parameter passing\n let sidebarConfig = Object.create(appConfig.sidebar);\n sidebarConfig.pdfViewer = this.pdfViewer;\n sidebarConfig.pdfThumbnailViewer = this.pdfThumbnailViewer;\n sidebarConfig.pdfOutlineViewer = this.pdfOutlineViewer;\n sidebarConfig.eventBus = eventBus;\n this.pdfSidebar = new PDFSidebar(sidebarConfig, this.l10n);\n this.pdfSidebar.onToggled = this.forceRendering.bind(this);\n\n resolve(undefined);\n });\n },\n\n run(config) {\n this.initialize(config).then(webViewerInitialized);\n },\n\n zoomIn(ticks) {\n let newScale = this.pdfViewer.currentScale;\n do {\n newScale = (newScale * DEFAULT_SCALE_DELTA).toFixed(2);\n newScale = Math.ceil(newScale * 10) / 10;\n newScale = Math.min(MAX_SCALE, newScale);\n } while (--ticks > 0 && newScale < MAX_SCALE);\n this.pdfViewer.currentScaleValue = newScale;\n },\n\n zoomOut(ticks) {\n let newScale = this.pdfViewer.currentScale;\n do {\n newScale = (newScale / DEFAULT_SCALE_DELTA).toFixed(2);\n newScale = Math.floor(newScale * 10) / 10;\n newScale = Math.max(MIN_SCALE, newScale);\n } while (--ticks > 0 && newScale > MIN_SCALE);\n this.pdfViewer.currentScaleValue = newScale;\n },\n\n get pagesCount() {\n return this.pdfDocument ? this.pdfDocument.numPages : 0;\n },\n\n get pageRotation() {\n return this.pdfViewer.pagesRotation;\n },\n\n set page(val) {\n this.pdfViewer.currentPageNumber = val;\n },\n\n get page() {\n return this.pdfViewer.currentPageNumber;\n },\n\n get printing() {\n return !!this.printService;\n },\n\n get supportsPrinting() {\n return PDFPrintServiceFactory.instance.supportsPrinting;\n },\n\n get supportsFullscreen() {\n let support;\n if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('MOZCENTRAL')) {\n support = document.fullscreenEnabled === true ||\n document.mozFullScreenEnabled === true;\n } else {\n let doc = document.documentElement;\n support = !!(doc.requestFullscreen || doc.mozRequestFullScreen ||\n doc.webkitRequestFullScreen || doc.msRequestFullscreen);\n\n if (document.fullscreenEnabled === false ||\n document.mozFullScreenEnabled === false ||\n document.webkitFullscreenEnabled === false ||\n document.msFullscreenEnabled === false) {\n support = false;\n }\n }\n if (support && PDFJS.disableFullscreen === true) {\n support = false;\n }\n\n return shadow(this, 'supportsFullscreen', support);\n },\n\n get supportsIntegratedFind() {\n return this.externalServices.supportsIntegratedFind;\n },\n\n get supportsDocumentFonts() {\n return this.externalServices.supportsDocumentFonts;\n },\n\n get supportsDocumentColors() {\n return this.externalServices.supportsDocumentColors;\n },\n\n get loadingBar() {\n let bar = new ProgressBar('#loadingBar');\n return shadow(this, 'loadingBar', bar);\n },\n\n get supportedMouseWheelZoomModifierKeys() {\n return this.externalServices.supportedMouseWheelZoomModifierKeys;\n },\n\n initPassiveLoading() {\n if (typeof PDFJSDev === 'undefined' ||\n !PDFJSDev.test('FIREFOX || MOZCENTRAL || CHROME')) {\n throw new Error('Not implemented: initPassiveLoading');\n }\n this.externalServices.initPassiveLoading({\n onOpenWithTransport(url, length, transport) {\n PDFViewerApplication.open(url, { range: transport, });\n\n if (length) {\n PDFViewerApplication.pdfDocumentProperties.setFileSize(length);\n }\n },\n onOpenWithData(data) {\n PDFViewerApplication.open(data);\n },\n onOpenWithURL(url, length, originalURL) {\n let file = url, args = null;\n if (length !== undefined) {\n args = { length, };\n }\n if (originalURL !== undefined) {\n file = { file: url, originalURL, };\n }\n PDFViewerApplication.open(file, args);\n },\n onError(err) {\n PDFViewerApplication.l10n.get('loading_error', null,\n 'An error occurred while loading the PDF.').then((msg) => {\n PDFViewerApplication.error(msg, err);\n });\n },\n onProgress(loaded, total) {\n PDFViewerApplication.progress(loaded / total);\n },\n });\n },\n\n setTitleUsingUrl(url) {\n this.url = url;\n this.baseUrl = url.split('#')[0];\n let title = getPDFFileNameFromURL(url, '');\n if (!title) {\n try {\n title = decodeURIComponent(getFilenameFromUrl(url)) || url;\n } catch (ex) {\n // decodeURIComponent may throw URIError,\n // fall back to using the unprocessed url in that case\n title = url;\n }\n }\n this.setTitle(title);\n },\n\n setTitle(title) {\n if (this.isViewerEmbedded) {\n // Embedded PDF viewers should not be changing their parent page's title.\n return;\n }\n document.title = title;\n },\n\n /**\n * Closes opened PDF document.\n * @returns {Promise} - Returns the promise, which is resolved when all\n * destruction is completed.\n */\n close() {\n let errorWrapper = this.appConfig.errorWrapper.container;\n errorWrapper.setAttribute('hidden', 'true');\n\n if (!this.pdfLoadingTask) {\n return Promise.resolve();\n }\n\n let promise = this.pdfLoadingTask.destroy();\n this.pdfLoadingTask = null;\n\n if (this.pdfDocument) {\n this.pdfDocument = null;\n\n this.pdfThumbnailViewer.setDocument(null);\n this.pdfViewer.setDocument(null);\n this.pdfLinkService.setDocument(null, null);\n this.pdfDocumentProperties.setDocument(null, null);\n }\n this.store = null;\n this.isInitialViewSet = false;\n this.downloadComplete = false;\n\n this.pdfSidebar.reset();\n this.pdfOutlineViewer.reset();\n this.pdfAttachmentViewer.reset();\n\n this.findController.reset();\n this.findBar.reset();\n this.toolbar.reset();\n this.secondaryToolbar.reset();\n\n if (typeof PDFBug !== 'undefined') {\n PDFBug.cleanup();\n }\n return promise;\n },\n\n /**\n * Opens PDF document specified by URL or array with additional arguments.\n * @param {string|TypedArray|ArrayBuffer} file - PDF location or binary data.\n * @param {Object} args - (optional) Additional arguments for the getDocument\n * call, e.g. HTTP headers ('httpHeaders') or\n * alternative data transport ('range').\n * @returns {Promise} - Returns the promise, which is resolved when document\n * is opened.\n */\n open(file, args) {\n if ((typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) &&\n (arguments.length > 2 || typeof args === 'number')) {\n return Promise.reject(\n new Error('Call of open() with obsolete signature.'));\n }\n if (this.pdfLoadingTask) {\n // We need to destroy already opened document.\n return this.close().then(() => {\n // Reload the preferences if a document was previously opened.\n this.preferences.reload();\n // ... and repeat the open() call.\n return this.open(file, args);\n });\n }\n\n let parameters = Object.create(null), scale;\n if (typeof file === 'string') { // URL\n this.setTitleUsingUrl(file);\n parameters.url = file;\n } else if (file && 'byteLength' in file) { // ArrayBuffer\n parameters.data = file;\n } else if (file.url && file.originalUrl) {\n this.setTitleUsingUrl(file.originalUrl);\n parameters.url = file.url;\n }\n if (typeof PDFJSDev !== 'undefined' &&\n PDFJSDev.test('FIREFOX || MOZCENTRAL || CHROME')) {\n parameters.docBaseUrl = this.baseUrl;\n }\n\n if (args) {\n for (let prop in args) {\n parameters[prop] = args[prop];\n }\n\n if (args.scale) {\n scale = args.scale;\n }\n if (args.length) {\n this.pdfDocumentProperties.setFileSize(args.length);\n }\n }\n\n let loadingTask = getDocument(parameters);\n this.pdfLoadingTask = loadingTask;\n\n loadingTask.onPassword = (updateCallback, reason) => {\n this.passwordPrompt.setUpdateCallback(updateCallback, reason);\n this.passwordPrompt.open();\n };\n\n loadingTask.onProgress = ({ loaded, total, }) => {\n this.progress(loaded / total);\n };\n\n // Listen for unsupported features to trigger the fallback UI.\n loadingTask.onUnsupportedFeature = this.fallback.bind(this);\n\n return loadingTask.promise.then((pdfDocument) => {\n this.load(pdfDocument, scale);\n }, (exception) => {\n let message = exception && exception.message;\n let loadingErrorMessage;\n if (exception instanceof InvalidPDFException) {\n // change error message also for other builds\n loadingErrorMessage = this.l10n.get('invalid_file_error', null,\n 'Invalid or corrupted PDF file.');\n } else if (exception instanceof MissingPDFException) {\n // special message for missing PDF's\n loadingErrorMessage = this.l10n.get('missing_file_error', null,\n 'Missing PDF file.');\n } else if (exception instanceof UnexpectedResponseException) {\n loadingErrorMessage = this.l10n.get('unexpected_response_error', null,\n 'Unexpected server response.');\n } else {\n loadingErrorMessage = this.l10n.get('loading_error', null,\n 'An error occurred while loading the PDF.');\n }\n\n return loadingErrorMessage.then((msg) => {\n this.error(msg, { message, });\n throw new Error(msg);\n });\n });\n },\n\n download() {\n function downloadByUrl() {\n downloadManager.downloadUrl(url, filename);\n }\n\n let url = this.baseUrl;\n // Use this.url instead of this.baseUrl to perform filename detection based\n // on the reference fragment as ultimate fallback if needed.\n let filename = getPDFFileNameFromURL(this.url);\n let downloadManager = this.downloadManager;\n downloadManager.onerror = (err) => {\n // This error won't really be helpful because it's likely the\n // fallback won't work either (or is already open).\n this.error(`PDF failed to download: ${err}`);\n };\n\n // When the PDF document isn't ready, or the PDF file is still downloading,\n // simply download using the URL.\n if (!this.pdfDocument || !this.downloadComplete) {\n downloadByUrl();\n return;\n }\n\n this.pdfDocument.getData().then(function(data) {\n let blob = createBlob(data, 'application/pdf');\n downloadManager.download(blob, url, filename);\n }).catch(downloadByUrl); // Error occurred, try downloading with the URL.\n },\n\n fallback(featureId) {\n if (typeof PDFJSDev !== 'undefined' &&\n PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n // Only trigger the fallback once so we don't spam the user with messages\n // for one PDF.\n if (this.fellback) {\n return;\n }\n this.fellback = true;\n this.externalServices.fallback({\n featureId,\n url: this.baseUrl,\n }, function response(download) {\n if (!download) {\n return;\n }\n PDFViewerApplication.download();\n });\n }\n },\n\n /**\n * Show the error box.\n * @param {String} message A message that is human readable.\n * @param {Object} moreInfo (optional) Further information about the error\n * that is more technical. Should have a 'message'\n * and optionally a 'stack' property.\n */\n error(message, moreInfo) {\n let moreInfoText = [this.l10n.get('error_version_info',\n { version: version || '?', build: build || '?', },\n 'PDF.js v{{version}} (build: {{build}})')];\n if (moreInfo) {\n moreInfoText.push(\n this.l10n.get('error_message', { message: moreInfo.message, },\n 'Message: {{message}}'));\n if (moreInfo.stack) {\n moreInfoText.push(\n this.l10n.get('error_stack', { stack: moreInfo.stack, },\n 'Stack: {{stack}}'));\n } else {\n if (moreInfo.filename) {\n moreInfoText.push(\n this.l10n.get('error_file', { file: moreInfo.filename, },\n 'File: {{file}}'));\n }\n if (moreInfo.lineNumber) {\n moreInfoText.push(\n this.l10n.get('error_line', { line: moreInfo.lineNumber, },\n 'Line: {{line}}'));\n }\n }\n }\n\n if (typeof PDFJSDev === 'undefined' ||\n !PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n let errorWrapperConfig = this.appConfig.errorWrapper;\n let errorWrapper = errorWrapperConfig.container;\n errorWrapper.removeAttribute('hidden');\n\n let errorMessage = errorWrapperConfig.errorMessage;\n errorMessage.textContent = message;\n\n let closeButton = errorWrapperConfig.closeButton;\n closeButton.onclick = function() {\n errorWrapper.setAttribute('hidden', 'true');\n };\n\n let errorMoreInfo = errorWrapperConfig.errorMoreInfo;\n let moreInfoButton = errorWrapperConfig.moreInfoButton;\n let lessInfoButton = errorWrapperConfig.lessInfoButton;\n moreInfoButton.onclick = function() {\n errorMoreInfo.removeAttribute('hidden');\n moreInfoButton.setAttribute('hidden', 'true');\n lessInfoButton.removeAttribute('hidden');\n errorMoreInfo.style.height = errorMoreInfo.scrollHeight + 'px';\n };\n lessInfoButton.onclick = function() {\n errorMoreInfo.setAttribute('hidden', 'true');\n moreInfoButton.removeAttribute('hidden');\n lessInfoButton.setAttribute('hidden', 'true');\n };\n moreInfoButton.oncontextmenu = noContextMenuHandler;\n lessInfoButton.oncontextmenu = noContextMenuHandler;\n closeButton.oncontextmenu = noContextMenuHandler;\n moreInfoButton.removeAttribute('hidden');\n lessInfoButton.setAttribute('hidden', 'true');\n Promise.all(moreInfoText).then((parts) => {\n errorMoreInfo.value = parts.join('\\n');\n });\n } else {\n console.error(message + '\\n' + moreInfoText);\n this.fallback();\n }\n },\n\n progress(level) {\n if (this.downloadComplete) {\n // Don't accidentally show the loading bar again when the entire file has\n // already been fetched (only an issue when disableAutoFetch is enabled).\n return;\n }\n let percent = Math.round(level * 100);\n // When we transition from full request to range requests, it's possible\n // that we discard some of the loaded data. This can cause the loading\n // bar to move backwards. So prevent this by only updating the bar if it\n // increases.\n if (percent > this.loadingBar.percent || isNaN(percent)) {\n this.loadingBar.percent = percent;\n\n // When disableAutoFetch is enabled, it's not uncommon for the entire file\n // to never be fetched (depends on e.g. the file structure). In this case\n // the loading bar will not be completely filled, nor will it be hidden.\n // To prevent displaying a partially filled loading bar permanently, we\n // hide it when no data has been loaded during a certain amount of time.\n if (PDFJS.disableAutoFetch && percent) {\n if (this.disableAutoFetchLoadingBarTimeout) {\n clearTimeout(this.disableAutoFetchLoadingBarTimeout);\n this.disableAutoFetchLoadingBarTimeout = null;\n }\n this.loadingBar.show();\n\n this.disableAutoFetchLoadingBarTimeout = setTimeout(() => {\n this.loadingBar.hide();\n this.disableAutoFetchLoadingBarTimeout = null;\n }, DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT);\n }\n }\n },\n\n load(pdfDocument, scale) {\n scale = scale || UNKNOWN_SCALE;\n this.pdfDocument = pdfDocument;\n\n pdfDocument.getDownloadInfo().then(() => {\n this.downloadComplete = true;\n this.loadingBar.hide();\n\n firstPagePromise.then(() => {\n this.eventBus.dispatch('documentload', { source: this, });\n });\n });\n\n // Since the `setInitialView` call below depends on this being resolved,\n // fetch it early to avoid delaying initial rendering of the PDF document.\n let pageModePromise = pdfDocument.getPageMode().catch(\n function() { /* Avoid breaking initial rendering; ignoring errors. */ });\n\n this.toolbar.setPagesCount(pdfDocument.numPages, false);\n this.secondaryToolbar.setPagesCount(pdfDocument.numPages);\n\n let id = this.documentFingerprint = pdfDocument.fingerprint;\n let store = this.store = new ViewHistory(id);\n\n let baseDocumentUrl;\n if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {\n baseDocumentUrl = null;\n } else if (PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n baseDocumentUrl = this.baseUrl;\n } else if (PDFJSDev.test('CHROME')) {\n baseDocumentUrl = location.href.split('#')[0];\n }\n this.pdfLinkService.setDocument(pdfDocument, baseDocumentUrl);\n this.pdfDocumentProperties.setDocument(pdfDocument, this.url);\n\n let pdfViewer = this.pdfViewer;\n pdfViewer.setDocument(pdfDocument);\n let firstPagePromise = pdfViewer.firstPagePromise;\n let pagesPromise = pdfViewer.pagesPromise;\n let onePageRendered = pdfViewer.onePageRendered;\n\n let pdfThumbnailViewer = this.pdfThumbnailViewer;\n pdfThumbnailViewer.setDocument(pdfDocument);\n\n firstPagePromise.then((pdfPage) => {\n this.loadingBar.setWidth(this.appConfig.viewerContainer);\n\n if (!PDFJS.disableHistory && !this.isViewerEmbedded) {\n // The browsing history is only enabled when the viewer is standalone,\n // i.e. not when it is embedded in a web page.\n if (!this.viewerPrefs['showPreviousViewOnLoad']) {\n this.pdfHistory.clearHistoryState();\n }\n this.pdfHistory.initialize(this.documentFingerprint);\n\n if (this.pdfHistory.initialDestination) {\n this.initialDestination = this.pdfHistory.initialDestination;\n } else if (this.pdfHistory.initialBookmark) {\n this.initialBookmark = this.pdfHistory.initialBookmark;\n }\n }\n\n let initialParams = {\n destination: this.initialDestination,\n bookmark: this.initialBookmark,\n hash: null,\n };\n let storePromise = store.getMultiple({\n exists: false,\n page: '1',\n zoom: DEFAULT_SCALE_VALUE,\n scrollLeft: '0',\n scrollTop: '0',\n sidebarView: SidebarView.NONE,\n }).catch(() => { /* Unable to read from storage; ignoring errors. */ });\n\n Promise.all([storePromise, pageModePromise]).then(\n ([values = {}, pageMode]) => {\n // Initialize the default values, from user preferences.\n let hash = this.viewerPrefs['defaultZoomValue'] ?\n ('zoom=' + this.viewerPrefs['defaultZoomValue']) : null;\n let sidebarView = this.viewerPrefs['sidebarViewOnLoad'];\n\n if (values.exists && this.viewerPrefs['showPreviousViewOnLoad']) {\n hash = 'page=' + values.page +\n '&zoom=' + (this.viewerPrefs['defaultZoomValue'] || values.zoom) +\n ',' + values.scrollLeft + ',' + values.scrollTop;\n sidebarView = sidebarView || (values.sidebarView | 0);\n }\n if (pageMode && !this.viewerPrefs['disablePageMode']) {\n // Always let the user preference/history take precedence.\n sidebarView = sidebarView || apiPageModeToSidebarView(pageMode);\n }\n return {\n hash,\n sidebarView,\n };\n }).then(({ hash, sidebarView, }) => {\n this.setInitialView(hash, { sidebarView, scale, });\n initialParams.hash = hash;\n\n // Make all navigation keys work on document load,\n // unless the viewer is embedded in a web page.\n if (!this.isViewerEmbedded) {\n pdfViewer.focus();\n }\n return pagesPromise;\n }).then(() => {\n // For documents with different page sizes, once all pages are resolved,\n // ensure that the correct location becomes visible on load.\n if (!initialParams.destination && !initialParams.bookmark &&\n !initialParams.hash) {\n return;\n }\n if (pdfViewer.hasEqualPageSizes) {\n return;\n }\n this.initialDestination = initialParams.destination;\n this.initialBookmark = initialParams.bookmark;\n\n pdfViewer.currentScaleValue = pdfViewer.currentScaleValue;\n this.setInitialView(initialParams.hash);\n }).then(function() {\n // At this point, rendering of the initial page(s) should always have\n // started (and may even have completed).\n // To prevent any future issues, e.g. the document being completely\n // blank on load, always trigger rendering here.\n pdfViewer.update();\n });\n });\n\n pdfDocument.getPageLabels().then((labels) => {\n if (!labels || this.viewerPrefs['disablePageLabels']) {\n return;\n }\n let i = 0, numLabels = labels.length;\n if (numLabels !== this.pagesCount) {\n console.error('The number of Page Labels does not match ' +\n 'the number of pages in the document.');\n return;\n }\n // Ignore page labels that correspond to standard page numbering.\n while (i < numLabels && labels[i] === (i + 1).toString()) {\n i++;\n }\n if (i === numLabels) {\n return;\n }\n\n pdfViewer.setPageLabels(labels);\n pdfThumbnailViewer.setPageLabels(labels);\n\n // Changing toolbar page display to use labels and we need to set\n // the label of the current page.\n this.toolbar.setPagesCount(pdfDocument.numPages, true);\n this.toolbar.setPageNumber(pdfViewer.currentPageNumber,\n pdfViewer.currentPageLabel);\n });\n\n pagesPromise.then(() => {\n if (!this.supportsPrinting) {\n return;\n }\n pdfDocument.getJavaScript().then((javaScript) => {\n if (javaScript.length) {\n console.warn('Warning: JavaScript is not supported');\n this.fallback(UNSUPPORTED_FEATURES.javaScript);\n }\n // Hack to support auto printing.\n let regex = /\\bprint\\s*\\(/;\n for (let i = 0, ii = javaScript.length; i < ii; i++) {\n let js = javaScript[i];\n if (js && regex.test(js)) {\n setTimeout(function() {\n window.print();\n });\n return;\n }\n }\n });\n });\n\n Promise.all([onePageRendered, animationStarted]).then(() => {\n pdfDocument.getOutline().then((outline) => {\n this.pdfOutlineViewer.render({ outline, });\n });\n pdfDocument.getAttachments().then((attachments) => {\n this.pdfAttachmentViewer.render({ attachments, });\n });\n });\n\n pdfDocument.getMetadata().then(({ info, metadata, }) => {\n this.documentInfo = info;\n this.metadata = metadata;\n\n // Provides some basic debug information\n console.log('PDF ' + pdfDocument.fingerprint + ' [' +\n info.PDFFormatVersion + ' ' + (info.Producer || '-').trim() +\n ' / ' + (info.Creator || '-').trim() + ']' +\n ' (PDF.js: ' + (version || '-') +\n (!PDFJS.disableWebGL ? ' [WebGL]' : '') + ')');\n\n let pdfTitle;\n if (metadata && metadata.has('dc:title')) {\n let title = metadata.get('dc:title');\n // Ghostscript sometimes return 'Untitled', sets the title to 'Untitled'\n if (title !== 'Untitled') {\n pdfTitle = title;\n }\n }\n\n if (!pdfTitle && info && info['Title']) {\n pdfTitle = info['Title'];\n }\n\n if (pdfTitle) {\n this.setTitle(pdfTitle + ' - ' + document.title);\n }\n\n if (info.IsAcroFormPresent) {\n console.warn('Warning: AcroForm/XFA is not supported');\n this.fallback(UNSUPPORTED_FEATURES.forms);\n }\n\n if (typeof PDFJSDev !== 'undefined' &&\n PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n let versionId = String(info.PDFFormatVersion).slice(-1) | 0;\n let generatorId = 0;\n const KNOWN_GENERATORS = [\n 'acrobat distiller', 'acrobat pdfwriter', 'adobe livecycle',\n 'adobe pdf library', 'adobe photoshop', 'ghostscript', 'tcpdf',\n 'cairo', 'dvipdfm', 'dvips', 'pdftex', 'pdfkit', 'itext', 'prince',\n 'quarkxpress', 'mac os x', 'microsoft', 'openoffice', 'oracle',\n 'luradocument', 'pdf-xchange', 'antenna house', 'aspose.cells', 'fpdf'\n ];\n if (info.Producer) {\n KNOWN_GENERATORS.some(function (generator, s, i) {\n if (generator.indexOf(s) < 0) {\n return false;\n }\n generatorId = i + 1;\n return true;\n }.bind(null, info.Producer.toLowerCase()));\n }\n let formType = !info.IsAcroFormPresent ? null : info.IsXFAPresent ?\n 'xfa' : 'acroform';\n this.externalServices.reportTelemetry({\n type: 'documentInfo',\n version: versionId,\n generator: generatorId,\n formType,\n });\n }\n });\n },\n\n setInitialView(storedHash, options = {}) {\n let { scale = 0, sidebarView = SidebarView.NONE, } = options;\n\n this.isInitialViewSet = true;\n this.pdfSidebar.setInitialView(sidebarView);\n\n if (this.initialDestination) {\n this.pdfLinkService.navigateTo(this.initialDestination);\n this.initialDestination = null;\n } else if (this.initialBookmark) {\n this.pdfLinkService.setHash(this.initialBookmark);\n this.pdfHistory.push({ hash: this.initialBookmark, }, true);\n this.initialBookmark = null;\n } else if (storedHash) {\n this.pdfLinkService.setHash(storedHash);\n } else if (scale) {\n this.pdfViewer.currentScaleValue = scale;\n this.page = 1;\n }\n\n // Ensure that the correct page number is displayed in the UI,\n // even if the active page didn't change during document load.\n this.toolbar.setPageNumber(this.pdfViewer.currentPageNumber,\n this.pdfViewer.currentPageLabel);\n this.secondaryToolbar.setPageNumber(this.pdfViewer.currentPageNumber);\n\n if (!this.pdfViewer.currentScaleValue) {\n // Scale was not initialized: invalid bookmark or scale was not specified.\n // Setting the default one.\n this.pdfViewer.currentScaleValue = DEFAULT_SCALE_VALUE;\n }\n },\n\n cleanup() {\n if (!this.pdfDocument) {\n return; // run cleanup when document is loaded\n }\n this.pdfViewer.cleanup();\n this.pdfThumbnailViewer.cleanup();\n\n // We don't want to remove fonts used by active page SVGs.\n if (this.pdfViewer.renderer !== RendererType.SVG) {\n this.pdfDocument.cleanup();\n }\n },\n\n forceRendering() {\n this.pdfRenderingQueue.printing = this.printing;\n this.pdfRenderingQueue.isThumbnailViewEnabled =\n this.pdfSidebar.isThumbnailViewVisible;\n this.pdfRenderingQueue.renderHighestPriority();\n },\n\n beforePrint() {\n if (this.printService) {\n // There is no way to suppress beforePrint/afterPrint events,\n // but PDFPrintService may generate double events -- this will ignore\n // the second event that will be coming from native window.print().\n return;\n }\n\n if (!this.supportsPrinting) {\n this.l10n.get('printing_not_supported', null,\n 'Warning: Printing is not fully supported by ' +\n 'this browser.').then((printMessage) => {\n this.error(printMessage);\n });\n return;\n }\n\n // The beforePrint is a sync method and we need to know layout before\n // returning from this method. Ensure that we can get sizes of the pages.\n if (!this.pdfViewer.pageViewsReady) {\n this.l10n.get('printing_not_ready', null,\n 'Warning: The PDF is not fully loaded for printing.').\n then((notReadyMessage) => {\n window.alert(notReadyMessage);\n });\n return;\n }\n\n let pagesOverview = this.pdfViewer.getPagesOverview();\n let printContainer = this.appConfig.printContainer;\n let printService = PDFPrintServiceFactory.instance.createPrintService(\n this.pdfDocument, pagesOverview, printContainer, this.l10n);\n this.printService = printService;\n this.forceRendering();\n\n printService.layout();\n\n if (typeof PDFJSDev !== 'undefined' &&\n PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n this.externalServices.reportTelemetry({\n type: 'print',\n });\n }\n },\n\n afterPrint: function pdfViewSetupAfterPrint() {\n if (this.printService) {\n this.printService.destroy();\n this.printService = null;\n }\n this.forceRendering();\n },\n\n rotatePages(delta) {\n if (!this.pdfDocument) {\n return;\n }\n let { pdfViewer, pdfThumbnailViewer, } = this;\n let pageNumber = pdfViewer.currentPageNumber;\n let newRotation = (pdfViewer.pagesRotation + 360 + delta) % 360;\n\n pdfViewer.pagesRotation = newRotation;\n pdfThumbnailViewer.pagesRotation = newRotation;\n\n this.forceRendering();\n // Ensure that the active page doesn't change during rotation.\n pdfViewer.currentPageNumber = pageNumber;\n },\n\n requestPresentationMode() {\n if (!this.pdfPresentationMode) {\n return;\n }\n this.pdfPresentationMode.request();\n },\n\n bindEvents() {\n let { eventBus, _boundEvents, } = this;\n\n _boundEvents.beforePrint = this.beforePrint.bind(this);\n _boundEvents.afterPrint = this.afterPrint.bind(this);\n\n eventBus.on('resize', webViewerResize);\n eventBus.on('hashchange', webViewerHashchange);\n eventBus.on('beforeprint', _boundEvents.beforePrint);\n eventBus.on('afterprint', _boundEvents.afterPrint);\n eventBus.on('pagerendered', webViewerPageRendered);\n eventBus.on('textlayerrendered', webViewerTextLayerRendered);\n eventBus.on('updateviewarea', webViewerUpdateViewarea);\n eventBus.on('pagechanging', webViewerPageChanging);\n eventBus.on('scalechanging', webViewerScaleChanging);\n eventBus.on('sidebarviewchanged', webViewerSidebarViewChanged);\n eventBus.on('pagemode', webViewerPageMode);\n eventBus.on('namedaction', webViewerNamedAction);\n eventBus.on('presentationmodechanged', webViewerPresentationModeChanged);\n eventBus.on('presentationmode', webViewerPresentationMode);\n eventBus.on('openfile', webViewerOpenFile);\n eventBus.on('print', webViewerPrint);\n eventBus.on('download', webViewerDownload);\n eventBus.on('firstpage', webViewerFirstPage);\n eventBus.on('lastpage', webViewerLastPage);\n eventBus.on('nextpage', webViewerNextPage);\n eventBus.on('previouspage', webViewerPreviousPage);\n eventBus.on('zoomin', webViewerZoomIn);\n eventBus.on('zoomout', webViewerZoomOut);\n eventBus.on('pagenumberchanged', webViewerPageNumberChanged);\n eventBus.on('scalechanged', webViewerScaleChanged);\n eventBus.on('rotatecw', webViewerRotateCw);\n eventBus.on('rotateccw', webViewerRotateCcw);\n eventBus.on('documentproperties', webViewerDocumentProperties);\n eventBus.on('find', webViewerFind);\n eventBus.on('findfromurlhash', webViewerFindFromUrlHash);\n if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {\n eventBus.on('fileinputchange', webViewerFileInputChange);\n }\n },\n\n bindWindowEvents() {\n let { eventBus, _boundEvents, } = this;\n\n _boundEvents.windowResize = () => {\n eventBus.dispatch('resize');\n };\n _boundEvents.windowHashChange = () => {\n eventBus.dispatch('hashchange', {\n hash: document.location.hash.substring(1),\n });\n };\n _boundEvents.windowBeforePrint = () => {\n eventBus.dispatch('beforeprint');\n };\n _boundEvents.windowAfterPrint = () => {\n eventBus.dispatch('afterprint');\n };\n\n window.addEventListener('wheel', webViewerWheel);\n window.addEventListener('click', webViewerClick);\n window.addEventListener('keydown', webViewerKeyDown);\n window.addEventListener('resize', _boundEvents.windowResize);\n window.addEventListener('hashchange', _boundEvents.windowHashChange);\n window.addEventListener('beforeprint', _boundEvents.windowBeforePrint);\n window.addEventListener('afterprint', _boundEvents.windowAfterPrint);\n if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {\n _boundEvents.windowChange = (evt) => {\n let files = evt.target.files;\n if (!files || files.length === 0) {\n return;\n }\n eventBus.dispatch('fileinputchange', {\n fileInput: evt.target,\n });\n };\n window.addEventListener('change', _boundEvents.windowChange);\n }\n },\n\n unbindEvents() {\n let { eventBus, _boundEvents, } = this;\n\n eventBus.off('resize', webViewerResize);\n eventBus.off('hashchange', webViewerHashchange);\n eventBus.off('beforeprint', _boundEvents.beforePrint);\n eventBus.off('afterprint', _boundEvents.afterPrint);\n eventBus.off('pagerendered', webViewerPageRendered);\n eventBus.off('textlayerrendered', webViewerTextLayerRendered);\n eventBus.off('updateviewarea', webViewerUpdateViewarea);\n eventBus.off('pagechanging', webViewerPageChanging);\n eventBus.off('scalechanging', webViewerScaleChanging);\n eventBus.off('sidebarviewchanged', webViewerSidebarViewChanged);\n eventBus.off('pagemode', webViewerPageMode);\n eventBus.off('namedaction', webViewerNamedAction);\n eventBus.off('presentationmodechanged', webViewerPresentationModeChanged);\n eventBus.off('presentationmode', webViewerPresentationMode);\n eventBus.off('openfile', webViewerOpenFile);\n eventBus.off('print', webViewerPrint);\n eventBus.off('download', webViewerDownload);\n eventBus.off('firstpage', webViewerFirstPage);\n eventBus.off('lastpage', webViewerLastPage);\n eventBus.off('nextpage', webViewerNextPage);\n eventBus.off('previouspage', webViewerPreviousPage);\n eventBus.off('zoomin', webViewerZoomIn);\n eventBus.off('zoomout', webViewerZoomOut);\n eventBus.off('pagenumberchanged', webViewerPageNumberChanged);\n eventBus.off('scalechanged', webViewerScaleChanged);\n eventBus.off('rotatecw', webViewerRotateCw);\n eventBus.off('rotateccw', webViewerRotateCcw);\n eventBus.off('documentproperties', webViewerDocumentProperties);\n eventBus.off('find', webViewerFind);\n eventBus.off('findfromurlhash', webViewerFindFromUrlHash);\n if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {\n eventBus.off('fileinputchange', webViewerFileInputChange);\n }\n\n _boundEvents.beforePrint = null;\n _boundEvents.afterPrint = null;\n },\n\n unbindWindowEvents() {\n let { _boundEvents, } = this;\n\n window.removeEventListener('wheel', webViewerWheel);\n window.removeEventListener('click', webViewerClick);\n window.removeEventListener('keydown', webViewerKeyDown);\n window.removeEventListener('resize', _boundEvents.windowResize);\n window.removeEventListener('hashchange', _boundEvents.windowHashChange);\n window.removeEventListener('beforeprint', _boundEvents.windowBeforePrint);\n window.removeEventListener('afterprint', _boundEvents.windowAfterPrint);\n if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {\n window.removeEventListener('change', _boundEvents.windowChange);\n _boundEvents.windowChange = null;\n }\n\n _boundEvents.windowResize = null;\n _boundEvents.windowHashChange = null;\n _boundEvents.windowBeforePrint = null;\n _boundEvents.windowAfterPrint = null;\n },\n};\n\nlet validateFileURL;\nif (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {\n const HOSTED_VIEWER_ORIGINS = ['null',\n 'http://mozilla.github.io', 'https://mozilla.github.io'];\n validateFileURL = function validateFileURL(file) {\n if (file === undefined) {\n return;\n }\n try {\n let viewerOrigin = new URL(window.location.href).origin || 'null';\n if (HOSTED_VIEWER_ORIGINS.indexOf(viewerOrigin) >= 0) {\n // Hosted or local viewer, allow for any file locations\n return;\n }\n let fileOrigin = new URL(file, window.location.href).origin;\n // Removing of the following line will not guarantee that the viewer will\n // start accepting URLs from foreign origin -- CORS headers on the remote\n // server must be properly configured.\n if (fileOrigin !== viewerOrigin) {\n throw new Error('file origin does not match viewer\\'s');\n }\n } catch (ex) {\n let message = ex && ex.message;\n PDFViewerApplication.l10n.get('loading_error', null,\n 'An error occurred while loading the PDF.').\n then((loadingErrorMessage) => {\n PDFViewerApplication.error(loadingErrorMessage, { message, });\n });\n throw ex;\n }\n };\n}\n\nfunction loadAndEnablePDFBug(enabledTabs) {\n return new Promise(function (resolve, reject) {\n let appConfig = PDFViewerApplication.appConfig;\n let script = document.createElement('script');\n script.src = appConfig.debuggerScriptPath;\n script.onload = function () {\n PDFBug.enable(enabledTabs);\n PDFBug.init({\n PDFJS,\n OPS,\n }, appConfig.mainContainer);\n resolve();\n };\n script.onerror = function () {\n reject(new Error('Cannot load debugger at ' + script.src));\n };\n (document.getElementsByTagName('head')[0] || document.body).\n appendChild(script);\n });\n}\n\nfunction webViewerInitialized() {\n let appConfig = PDFViewerApplication.appConfig;\n let file;\n if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {\n let queryString = document.location.search.substring(1);\n let params = parseQueryString(queryString);\n file = 'file' in params ? params.file : appConfig.defaultUrl;\n validateFileURL(file);\n } else if (PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n file = window.location.href.split('#')[0];\n } else if (PDFJSDev.test('CHROME')) {\n file = appConfig.defaultUrl;\n }\n\n let waitForBeforeOpening = [];\n if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {\n let fileInput = document.createElement('input');\n fileInput.id = appConfig.openFileInputName;\n fileInput.className = 'fileInput';\n fileInput.setAttribute('type', 'file');\n fileInput.oncontextmenu = noContextMenuHandler;\n document.body.appendChild(fileInput);\n\n if (!window.File || !window.FileReader ||\n !window.FileList || !window.Blob) {\n appConfig.toolbar.openFile.setAttribute('hidden', 'true');\n appConfig.secondaryToolbar.openFileButton.setAttribute('hidden', 'true');\n } else {\n fileInput.value = null;\n }\n } else {\n appConfig.toolbar.openFile.setAttribute('hidden', 'true');\n appConfig.secondaryToolbar.openFileButton.setAttribute('hidden', 'true');\n }\n\n if ((typeof PDFJSDev === 'undefined' || !PDFJSDev.test('PRODUCTION')) ||\n PDFViewerApplication.viewerPrefs['pdfBugEnabled']) {\n // Special debugging flags in the hash section of the URL.\n let hash = document.location.hash.substring(1);\n let hashParams = parseQueryString(hash);\n\n if ('disableworker' in hashParams) {\n PDFJS.disableWorker = (hashParams['disableworker'] === 'true');\n }\n if ('disablerange' in hashParams) {\n PDFJS.disableRange = (hashParams['disablerange'] === 'true');\n }\n if ('disablestream' in hashParams) {\n PDFJS.disableStream = (hashParams['disablestream'] === 'true');\n }\n if ('disableautofetch' in hashParams) {\n PDFJS.disableAutoFetch = (hashParams['disableautofetch'] === 'true');\n }\n if ('disablefontface' in hashParams) {\n PDFJS.disableFontFace = (hashParams['disablefontface'] === 'true');\n }\n if ('disablehistory' in hashParams) {\n PDFJS.disableHistory = (hashParams['disablehistory'] === 'true');\n }\n if ('webgl' in hashParams) {\n PDFJS.disableWebGL = (hashParams['webgl'] !== 'true');\n }\n if ('useonlycsszoom' in hashParams) {\n PDFJS.useOnlyCssZoom = (hashParams['useonlycsszoom'] === 'true');\n }\n if ('verbosity' in hashParams) {\n PDFJS.verbosity = hashParams['verbosity'] | 0;\n }\n if ('ignorecurrentpositiononzoom' in hashParams) {\n PDFJS.ignoreCurrentPositionOnZoom =\n (hashParams['ignorecurrentpositiononzoom'] === 'true');\n }\n if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('PRODUCTION')) {\n if ('disablebcmaps' in hashParams && hashParams['disablebcmaps']) {\n PDFJS.cMapUrl = '../external/cmaps/';\n PDFJS.cMapPacked = false;\n }\n }\n if ('textlayer' in hashParams) {\n switch (hashParams['textlayer']) {\n case 'off':\n PDFJS.disableTextLayer = true;\n break;\n case 'visible':\n case 'shadow':\n case 'hover':\n let viewer = appConfig.viewerContainer;\n viewer.classList.add('textLayer-' + hashParams['textlayer']);\n break;\n }\n }\n if ('pdfbug' in hashParams) {\n PDFJS.pdfBug = true;\n let pdfBug = hashParams['pdfbug'];\n let enabled = pdfBug.split(',');\n waitForBeforeOpening.push(loadAndEnablePDFBug(enabled));\n }\n }\n\n if (typeof PDFJSDev !== 'undefined' &&\n PDFJSDev.test('FIREFOX || MOZCENTRAL') &&\n !PDFViewerApplication.supportsDocumentFonts) {\n PDFJS.disableFontFace = true;\n PDFViewerApplication.l10n.get('web_fonts_disabled', null,\n 'Web fonts are disabled: unable to use embedded PDF fonts.').\n then((msg) => {\n console.warn(msg);\n });\n }\n\n if (!PDFViewerApplication.supportsPrinting) {\n appConfig.toolbar.print.classList.add('hidden');\n appConfig.secondaryToolbar.printButton.classList.add('hidden');\n }\n\n if (!PDFViewerApplication.supportsFullscreen) {\n appConfig.toolbar.presentationModeButton.classList.add('hidden');\n appConfig.secondaryToolbar.presentationModeButton.classList.add('hidden');\n }\n\n if (PDFViewerApplication.supportsIntegratedFind) {\n appConfig.toolbar.viewFind.classList.add('hidden');\n }\n\n appConfig.sidebar.mainContainer.addEventListener('transitionend',\n function(evt) {\n if (evt.target === /* mainContainer */ this) {\n PDFViewerApplication.eventBus.dispatch('resize');\n }\n }, true);\n\n appConfig.sidebar.toggleButton.addEventListener('click', function() {\n PDFViewerApplication.pdfSidebar.toggle();\n });\n\n Promise.all(waitForBeforeOpening).then(function () {\n webViewerOpenFileViaURL(file);\n }).catch(function (reason) {\n PDFViewerApplication.l10n.get('loading_error', null,\n 'An error occurred while opening.').then((msg) => {\n PDFViewerApplication.error(msg, reason);\n });\n });\n}\n\nlet webViewerOpenFileViaURL;\nif (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {\n webViewerOpenFileViaURL = function webViewerOpenFileViaURL(file) {\n if (file && file.lastIndexOf('file:', 0) === 0) {\n // file:-scheme. Load the contents in the main thread because QtWebKit\n // cannot load file:-URLs in a Web Worker. file:-URLs are usually loaded\n // very quickly, so there is no need to set up progress event listeners.\n PDFViewerApplication.setTitleUsingUrl(file);\n let xhr = new XMLHttpRequest();\n xhr.onload = function() {\n PDFViewerApplication.open(new Uint8Array(xhr.response));\n };\n try {\n xhr.open('GET', file);\n xhr.responseType = 'arraybuffer';\n xhr.send();\n } catch (ex) {\n PDFViewerApplication.l10n.get('loading_error', null,\n 'An error occurred while loading the PDF.').then((msg) => {\n PDFViewerApplication.error(msg, ex);\n });\n }\n return;\n }\n\n if (file) {\n PDFViewerApplication.open(file);\n }\n };\n} else if (PDFJSDev.test('FIREFOX || MOZCENTRAL || CHROME')) {\n webViewerOpenFileViaURL = function webViewerOpenFileViaURL(file) {\n PDFViewerApplication.setTitleUsingUrl(file);\n PDFViewerApplication.initPassiveLoading();\n };\n} else {\n webViewerOpenFileViaURL = function webViewerOpenFileURL(file) {\n if (file) {\n throw new Error('Not implemented: webViewerOpenFileURL');\n }\n };\n}\n\nfunction webViewerPageRendered(evt) {\n let pageNumber = evt.pageNumber;\n let pageIndex = pageNumber - 1;\n let pageView = PDFViewerApplication.pdfViewer.getPageView(pageIndex);\n\n // If the page is still visible when it has finished rendering,\n // ensure that the page number input loading indicator is hidden.\n if (pageNumber === PDFViewerApplication.page) {\n PDFViewerApplication.toolbar.updateLoadingIndicatorState(false);\n }\n\n // Prevent errors in the edge-case where the PDF document is removed *before*\n // the 'pagerendered' event handler is invoked.\n if (!pageView) {\n return;\n }\n\n // Use the rendered page to set the corresponding thumbnail image.\n if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) {\n let thumbnailView = PDFViewerApplication.pdfThumbnailViewer.\n getThumbnail(pageIndex);\n thumbnailView.setImage(pageView);\n }\n\n if (PDFJS.pdfBug && Stats.enabled && pageView.stats) {\n Stats.add(pageNumber, pageView.stats);\n }\n\n if (pageView.error) {\n PDFViewerApplication.l10n.get('rendering_error', null,\n 'An error occurred while rendering the page.').then((msg) => {\n PDFViewerApplication.error(msg, pageView.error);\n });\n }\n\n if (typeof PDFJSDev !== 'undefined' &&\n PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n PDFViewerApplication.externalServices.reportTelemetry({\n type: 'pageInfo',\n });\n // It is a good time to report stream and font types.\n PDFViewerApplication.pdfDocument.getStats().then(function (stats) {\n PDFViewerApplication.externalServices.reportTelemetry({\n type: 'documentStats',\n stats,\n });\n });\n }\n}\n\nfunction webViewerTextLayerRendered(evt) {\n if (typeof PDFJSDev !== 'undefined' &&\n PDFJSDev.test('FIREFOX || MOZCENTRAL') &&\n evt.numTextDivs > 0 && !PDFViewerApplication.supportsDocumentColors) {\n PDFViewerApplication.l10n.get('document_colors_not_allowed', null,\n 'PDF documents are not allowed to use their own colors: ' +\n '\\'Allow pages to choose their own colors\\' ' +\n 'is deactivated in the browser.').\n then((msg) => {\n console.error(msg);\n });\n PDFViewerApplication.fallback();\n }\n}\n\nfunction webViewerPageMode(evt) {\n // Handle the 'pagemode' hash parameter, see also `PDFLinkService_setHash`.\n let mode = evt.mode, view;\n switch (mode) {\n case 'thumbs':\n view = SidebarView.THUMBS;\n break;\n case 'bookmarks':\n case 'outline':\n view = SidebarView.OUTLINE;\n break;\n case 'attachments':\n view = SidebarView.ATTACHMENTS;\n break;\n case 'none':\n view = SidebarView.NONE;\n break;\n default:\n console.error('Invalid \"pagemode\" hash parameter: ' + mode);\n return;\n }\n PDFViewerApplication.pdfSidebar.switchView(view, /* forceOpen = */ true);\n}\n\nfunction webViewerNamedAction(evt) {\n // Processing couple of named actions that might be useful.\n // See also PDFLinkService.executeNamedAction\n let action = evt.action;\n switch (action) {\n case 'GoToPage':\n PDFViewerApplication.appConfig.toolbar.pageNumber.select();\n break;\n\n case 'Find':\n if (!PDFViewerApplication.supportsIntegratedFind) {\n PDFViewerApplication.findBar.toggle();\n }\n break;\n }\n}\n\nfunction webViewerPresentationModeChanged(evt) {\n let { active, switchInProgress, } = evt;\n PDFViewerApplication.pdfViewer.presentationModeState =\n switchInProgress ? PresentationModeState.CHANGING :\n active ? PresentationModeState.FULLSCREEN : PresentationModeState.NORMAL;\n}\n\nfunction webViewerSidebarViewChanged(evt) {\n PDFViewerApplication.pdfRenderingQueue.isThumbnailViewEnabled =\n PDFViewerApplication.pdfSidebar.isThumbnailViewVisible;\n\n let store = PDFViewerApplication.store;\n if (store && PDFViewerApplication.isInitialViewSet) {\n // Only update the storage when the document has been loaded *and* rendered.\n store.set('sidebarView', evt.view).catch(function() { });\n }\n}\n\nfunction webViewerUpdateViewarea(evt) {\n let location = evt.location, store = PDFViewerApplication.store;\n\n if (store && PDFViewerApplication.isInitialViewSet) {\n store.setMultiple({\n 'exists': true,\n 'page': location.pageNumber,\n 'zoom': location.scale,\n 'scrollLeft': location.left,\n 'scrollTop': location.top,\n }).catch(function() { /* unable to write to storage */ });\n }\n let href =\n PDFViewerApplication.pdfLinkService.getAnchorUrl(location.pdfOpenParams);\n PDFViewerApplication.appConfig.toolbar.viewBookmark.href = href;\n PDFViewerApplication.appConfig.secondaryToolbar.viewBookmarkButton.href =\n href;\n\n // Update the current bookmark in the browsing history.\n PDFViewerApplication.pdfHistory.updateCurrentBookmark(location.pdfOpenParams,\n location.pageNumber);\n\n // Show/hide the loading indicator in the page number input element.\n let currentPage =\n PDFViewerApplication.pdfViewer.getPageView(PDFViewerApplication.page - 1);\n let loading = currentPage.renderingState !== RenderingStates.FINISHED;\n PDFViewerApplication.toolbar.updateLoadingIndicatorState(loading);\n}\n\nfunction webViewerResize() {\n let { pdfDocument, pdfViewer, } = PDFViewerApplication;\n if (!pdfDocument) {\n return;\n }\n let currentScaleValue = pdfViewer.currentScaleValue;\n if (currentScaleValue === 'auto' ||\n currentScaleValue === 'page-fit' ||\n currentScaleValue === 'page-width') {\n // Note: the scale is constant for 'page-actual'.\n pdfViewer.currentScaleValue = currentScaleValue;\n }\n pdfViewer.update();\n}\n\nfunction webViewerHashchange(evt) {\n if (PDFViewerApplication.pdfHistory.isHashChangeUnlocked) {\n let hash = evt.hash;\n if (!hash) {\n return;\n }\n if (!PDFViewerApplication.isInitialViewSet) {\n PDFViewerApplication.initialBookmark = hash;\n } else {\n PDFViewerApplication.pdfLinkService.setHash(hash);\n }\n }\n}\n\nlet webViewerFileInputChange;\nif (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {\n webViewerFileInputChange = function webViewerFileInputChange(evt) {\n let file = evt.fileInput.files[0];\n\n if (!PDFJS.disableCreateObjectURL && URL.createObjectURL) {\n PDFViewerApplication.open(URL.createObjectURL(file));\n } else {\n // Read the local file into a Uint8Array.\n let fileReader = new FileReader();\n fileReader.onload = function webViewerChangeFileReaderOnload(evt) {\n let buffer = evt.target.result;\n PDFViewerApplication.open(new Uint8Array(buffer));\n };\n fileReader.readAsArrayBuffer(file);\n }\n\n PDFViewerApplication.setTitleUsingUrl(file.name);\n\n // URL does not reflect proper document location - hiding some icons.\n let appConfig = PDFViewerApplication.appConfig;\n appConfig.toolbar.viewBookmark.setAttribute('hidden', 'true');\n appConfig.secondaryToolbar.viewBookmarkButton.setAttribute('hidden',\n 'true');\n appConfig.toolbar.download.setAttribute('hidden', 'true');\n appConfig.secondaryToolbar.downloadButton.setAttribute('hidden', 'true');\n };\n}\n\nfunction webViewerPresentationMode() {\n PDFViewerApplication.requestPresentationMode();\n}\nfunction webViewerOpenFile() {\n let openFileInputName = PDFViewerApplication.appConfig.openFileInputName;\n document.getElementById(openFileInputName).click();\n}\nfunction webViewerPrint() {\n window.print();\n}\nfunction webViewerDownload() {\n PDFViewerApplication.download();\n}\nfunction webViewerFirstPage() {\n if (PDFViewerApplication.pdfDocument) {\n PDFViewerApplication.page = 1;\n }\n}\nfunction webViewerLastPage() {\n if (PDFViewerApplication.pdfDocument) {\n PDFViewerApplication.page = PDFViewerApplication.pagesCount;\n }\n}\nfunction webViewerNextPage() {\n PDFViewerApplication.page++;\n}\nfunction webViewerPreviousPage() {\n PDFViewerApplication.page--;\n}\nfunction webViewerZoomIn() {\n PDFViewerApplication.zoomIn();\n}\nfunction webViewerZoomOut() {\n PDFViewerApplication.zoomOut();\n}\nfunction webViewerPageNumberChanged(evt) {\n let pdfViewer = PDFViewerApplication.pdfViewer;\n pdfViewer.currentPageLabel = evt.value;\n\n // Ensure that the page number input displays the correct value, even if the\n // value entered by the user was invalid (e.g. a floating point number).\n if (evt.value !== pdfViewer.currentPageNumber.toString() &&\n evt.value !== pdfViewer.currentPageLabel) {\n PDFViewerApplication.toolbar.setPageNumber(\n pdfViewer.currentPageNumber, pdfViewer.currentPageLabel);\n }\n}\nfunction webViewerScaleChanged(evt) {\n PDFViewerApplication.pdfViewer.currentScaleValue = evt.value;\n}\nfunction webViewerRotateCw() {\n PDFViewerApplication.rotatePages(90);\n}\nfunction webViewerRotateCcw() {\n PDFViewerApplication.rotatePages(-90);\n}\nfunction webViewerDocumentProperties() {\n PDFViewerApplication.pdfDocumentProperties.open();\n}\n\nfunction webViewerFind(evt) {\n PDFViewerApplication.findController.executeCommand('find' + evt.type, {\n query: evt.query,\n phraseSearch: evt.phraseSearch,\n caseSensitive: evt.caseSensitive,\n highlightAll: evt.highlightAll,\n findPrevious: evt.findPrevious,\n });\n}\n\nfunction webViewerFindFromUrlHash(evt) {\n PDFViewerApplication.findController.executeCommand('find', {\n query: evt.query,\n phraseSearch: evt.phraseSearch,\n caseSensitive: false,\n highlightAll: true,\n findPrevious: false,\n });\n}\n\nfunction webViewerScaleChanging(evt) {\n PDFViewerApplication.toolbar.setPageScale(evt.presetValue, evt.scale);\n\n PDFViewerApplication.pdfViewer.update();\n}\n\nfunction webViewerPageChanging(evt) {\n let page = evt.pageNumber;\n\n PDFViewerApplication.toolbar.setPageNumber(page, evt.pageLabel || null);\n PDFViewerApplication.secondaryToolbar.setPageNumber(page);\n\n if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) {\n PDFViewerApplication.pdfThumbnailViewer.scrollThumbnailIntoView(page);\n }\n\n // we need to update stats\n if (PDFJS.pdfBug && Stats.enabled) {\n let pageView = PDFViewerApplication.pdfViewer.getPageView(page - 1);\n if (pageView.stats) {\n Stats.add(page, pageView.stats);\n }\n }\n}\n\nlet zoomDisabled = false, zoomDisabledTimeout;\nfunction webViewerWheel(evt) {\n let pdfViewer = PDFViewerApplication.pdfViewer;\n if (pdfViewer.isInPresentationMode) {\n return;\n }\n\n if (evt.ctrlKey || evt.metaKey) {\n let support = PDFViewerApplication.supportedMouseWheelZoomModifierKeys;\n if ((evt.ctrlKey && !support.ctrlKey) ||\n (evt.metaKey && !support.metaKey)) {\n return;\n }\n // Only zoom the pages, not the entire viewer.\n evt.preventDefault();\n // NOTE: this check must be placed *after* preventDefault.\n if (zoomDisabled) {\n return;\n }\n\n let previousScale = pdfViewer.currentScale;\n\n let delta = normalizeWheelEventDelta(evt);\n\n const MOUSE_WHEEL_DELTA_PER_PAGE_SCALE = 3.0;\n let ticks = delta * MOUSE_WHEEL_DELTA_PER_PAGE_SCALE;\n if (ticks < 0) {\n PDFViewerApplication.zoomOut(-ticks);\n } else {\n PDFViewerApplication.zoomIn(ticks);\n }\n\n let currentScale = pdfViewer.currentScale;\n if (previousScale !== currentScale) {\n // After scaling the page via zoomIn/zoomOut, the position of the upper-\n // left corner is restored. When the mouse wheel is used, the position\n // under the cursor should be restored instead.\n let scaleCorrectionFactor = currentScale / previousScale - 1;\n let rect = pdfViewer.container.getBoundingClientRect();\n let dx = evt.clientX - rect.left;\n let dy = evt.clientY - rect.top;\n pdfViewer.container.scrollLeft += dx * scaleCorrectionFactor;\n pdfViewer.container.scrollTop += dy * scaleCorrectionFactor;\n }\n } else {\n zoomDisabled = true;\n clearTimeout(zoomDisabledTimeout);\n zoomDisabledTimeout = setTimeout(function () {\n zoomDisabled = false;\n }, 1000);\n }\n}\n\nfunction webViewerClick(evt) {\n if (!PDFViewerApplication.secondaryToolbar.isOpen) {\n return;\n }\n let appConfig = PDFViewerApplication.appConfig;\n if (PDFViewerApplication.pdfViewer.containsElement(evt.target) ||\n (appConfig.toolbar.container.contains(evt.target) &&\n evt.target !== appConfig.secondaryToolbar.toggleButton)) {\n PDFViewerApplication.secondaryToolbar.close();\n }\n}\n\nfunction webViewerKeyDown(evt) {\n if (PDFViewerApplication.overlayManager.active) {\n return;\n }\n\n let handled = false, ensureViewerFocused = false;\n let cmd = (evt.ctrlKey ? 1 : 0) |\n (evt.altKey ? 2 : 0) |\n (evt.shiftKey ? 4 : 0) |\n (evt.metaKey ? 8 : 0);\n\n let pdfViewer = PDFViewerApplication.pdfViewer;\n let isViewerInPresentationMode = pdfViewer && pdfViewer.isInPresentationMode;\n\n // First, handle the key bindings that are independent whether an input\n // control is selected or not.\n if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) {\n // either CTRL or META key with optional SHIFT.\n switch (evt.keyCode) {\n case 70: // f\n if (!PDFViewerApplication.supportsIntegratedFind) {\n PDFViewerApplication.findBar.open();\n handled = true;\n }\n break;\n case 71: // g\n if (!PDFViewerApplication.supportsIntegratedFind) {\n let findState = PDFViewerApplication.findController.state;\n if (findState) {\n PDFViewerApplication.findController.executeCommand('findagain', {\n query: findState.query,\n phraseSearch: findState.phraseSearch,\n caseSensitive: findState.caseSensitive,\n highlightAll: findState.highlightAll,\n findPrevious: cmd === 5 || cmd === 12,\n });\n }\n handled = true;\n }\n break;\n case 61: // FF/Mac '='\n case 107: // FF '+' and '='\n case 187: // Chrome '+'\n case 171: // FF with German keyboard\n if (!isViewerInPresentationMode) {\n PDFViewerApplication.zoomIn();\n }\n handled = true;\n break;\n case 173: // FF/Mac '-'\n case 109: // FF '-'\n case 189: // Chrome '-'\n if (!isViewerInPresentationMode) {\n PDFViewerApplication.zoomOut();\n }\n handled = true;\n break;\n case 48: // '0'\n case 96: // '0' on Numpad of Swedish keyboard\n if (!isViewerInPresentationMode) {\n // keeping it unhandled (to restore page zoom to 100%)\n setTimeout(function () {\n // ... and resetting the scale after browser adjusts its scale\n pdfViewer.currentScaleValue = DEFAULT_SCALE_VALUE;\n });\n handled = false;\n }\n break;\n\n case 38: // up arrow\n if (isViewerInPresentationMode || PDFViewerApplication.page > 1) {\n PDFViewerApplication.page = 1;\n handled = true;\n ensureViewerFocused = true;\n }\n break;\n case 40: // down arrow\n if (isViewerInPresentationMode ||\n PDFViewerApplication.page < PDFViewerApplication.pagesCount) {\n PDFViewerApplication.page = PDFViewerApplication.pagesCount;\n handled = true;\n ensureViewerFocused = true;\n }\n break;\n }\n }\n\n if (typeof PDFJSDev === 'undefined' ||\n !PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n // CTRL or META without shift\n if (cmd === 1 || cmd === 8) {\n switch (evt.keyCode) {\n case 83: // s\n PDFViewerApplication.download();\n handled = true;\n break;\n }\n }\n }\n\n // CTRL+ALT or Option+Command\n if (cmd === 3 || cmd === 10) {\n switch (evt.keyCode) {\n case 80: // p\n PDFViewerApplication.requestPresentationMode();\n handled = true;\n break;\n case 71: // g\n // focuses input#pageNumber field\n PDFViewerApplication.appConfig.toolbar.pageNumber.select();\n handled = true;\n break;\n }\n }\n\n if (handled) {\n if (ensureViewerFocused && !isViewerInPresentationMode) {\n pdfViewer.focus();\n }\n evt.preventDefault();\n return;\n }\n\n // Some shortcuts should not get handled if a control/input element\n // is selected.\n let curElement = document.activeElement || document.querySelector(':focus');\n let curElementTagName = curElement && curElement.tagName.toUpperCase();\n if (curElementTagName === 'INPUT' ||\n curElementTagName === 'TEXTAREA' ||\n curElementTagName === 'SELECT') {\n // Make sure that the secondary toolbar is closed when Escape is pressed.\n if (evt.keyCode !== 27) { // 'Esc'\n return;\n }\n }\n\n if (cmd === 0) { // no control key pressed at all.\n switch (evt.keyCode) {\n case 38: // up arrow\n case 33: // pg up\n case 8: // backspace\n if (!isViewerInPresentationMode &&\n pdfViewer.currentScaleValue !== 'page-fit') {\n break;\n }\n /* in presentation mode */\n /* falls through */\n case 37: // left arrow\n // horizontal scrolling using arrow keys\n if (pdfViewer.isHorizontalScrollbarEnabled) {\n break;\n }\n /* falls through */\n case 75: // 'k'\n case 80: // 'p'\n if (PDFViewerApplication.page > 1) {\n PDFViewerApplication.page--;\n }\n handled = true;\n break;\n case 27: // esc key\n if (PDFViewerApplication.secondaryToolbar.isOpen) {\n PDFViewerApplication.secondaryToolbar.close();\n handled = true;\n }\n if (!PDFViewerApplication.supportsIntegratedFind &&\n PDFViewerApplication.findBar.opened) {\n PDFViewerApplication.findBar.close();\n handled = true;\n }\n break;\n case 40: // down arrow\n case 34: // pg down\n case 32: // spacebar\n if (!isViewerInPresentationMode &&\n pdfViewer.currentScaleValue !== 'page-fit') {\n break;\n }\n /* falls through */\n case 39: // right arrow\n // horizontal scrolling using arrow keys\n if (pdfViewer.isHorizontalScrollbarEnabled) {\n break;\n }\n /* falls through */\n case 74: // 'j'\n case 78: // 'n'\n if (PDFViewerApplication.page < PDFViewerApplication.pagesCount) {\n PDFViewerApplication.page++;\n }\n handled = true;\n break;\n\n case 36: // home\n if (isViewerInPresentationMode || PDFViewerApplication.page > 1) {\n PDFViewerApplication.page = 1;\n handled = true;\n ensureViewerFocused = true;\n }\n break;\n case 35: // end\n if (isViewerInPresentationMode ||\n PDFViewerApplication.page < PDFViewerApplication.pagesCount) {\n PDFViewerApplication.page = PDFViewerApplication.pagesCount;\n handled = true;\n ensureViewerFocused = true;\n }\n break;\n\n case 83: // 's'\n PDFViewerApplication.pdfCursorTools.switchTool(CursorTool.SELECT);\n break;\n case 72: // 'h'\n PDFViewerApplication.pdfCursorTools.switchTool(CursorTool.HAND);\n break;\n\n case 82: // 'r'\n PDFViewerApplication.rotatePages(90);\n break;\n }\n }\n\n if (cmd === 4) { // shift-key\n switch (evt.keyCode) {\n case 32: // spacebar\n if (!isViewerInPresentationMode &&\n pdfViewer.currentScaleValue !== 'page-fit') {\n break;\n }\n if (PDFViewerApplication.page > 1) {\n PDFViewerApplication.page--;\n }\n handled = true;\n break;\n\n case 82: // 'r'\n PDFViewerApplication.rotatePages(-90);\n break;\n }\n }\n\n if (!handled && !isViewerInPresentationMode) {\n // 33=Page Up 34=Page Down 35=End 36=Home\n // 37=Left 38=Up 39=Right 40=Down\n // 32=Spacebar\n if ((evt.keyCode >= 33 && evt.keyCode <= 40) ||\n (evt.keyCode === 32 && curElementTagName !== 'BUTTON')) {\n ensureViewerFocused = true;\n }\n }\n\n if (cmd === 2) { // alt-key\n switch (evt.keyCode) {\n case 37: // left arrow\n if (isViewerInPresentationMode) {\n PDFViewerApplication.pdfHistory.back();\n handled = true;\n }\n break;\n case 39: // right arrow\n if (isViewerInPresentationMode) {\n PDFViewerApplication.pdfHistory.forward();\n handled = true;\n }\n break;\n }\n }\n\n if (ensureViewerFocused && !pdfViewer.containsElement(curElement)) {\n // The page container is not focused, but a page navigation key has been\n // pressed. Change the focus to the viewer container to make sure that\n // navigation by keyboard works as expected.\n pdfViewer.focus();\n }\n\n if (handled) {\n evt.preventDefault();\n }\n}\n\n/**\n * Converts API PageMode values to the format used by `PDFSidebar`.\n * NOTE: There's also a \"FullScreen\" parameter which is not possible to support,\n * since the Fullscreen API used in browsers requires that entering\n * fullscreen mode only occurs as a result of a user-initiated event.\n * @param {string} mode - The API PageMode value.\n * @returns {number} A value from {SidebarView}.\n */\nfunction apiPageModeToSidebarView(mode) {\n switch (mode) {\n case 'UseNone':\n return SidebarView.NONE;\n case 'UseThumbs':\n return SidebarView.THUMBS;\n case 'UseOutlines':\n return SidebarView.OUTLINE;\n case 'UseAttachments':\n return SidebarView.ATTACHMENTS;\n case 'UseOC':\n // Not implemented, since we don't support Optional Content Groups yet.\n }\n return SidebarView.NONE; // Default value.\n}\n\n/* Abstract factory for the print service. */\nlet PDFPrintServiceFactory = {\n instance: {\n supportsPrinting: false,\n createPrintService() {\n throw new Error('Not implemented: createPrintService');\n },\n },\n};\n\nexport {\n PDFViewerApplication,\n DefaultExternalServices,\n PDFPrintServiceFactory,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/app.js", + "/* Copyright 2015 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getGlobalEventBus } from './dom_events';\nimport { parseQueryString } from './ui_utils';\n\n/**\n * @typedef {Object} PDFLinkServiceOptions\n * @property {EventBus} eventBus - The application event bus.\n */\n\n/**\n * Performs navigation functions inside PDF, such as opening specified page,\n * or destination.\n * @implements {IPDFLinkService}\n */\nclass PDFLinkService {\n /**\n * @param {PDFLinkServiceOptions} options\n */\n constructor({ eventBus, } = {}) {\n this.eventBus = eventBus || getGlobalEventBus();\n this.baseUrl = null;\n this.pdfDocument = null;\n this.pdfViewer = null;\n this.pdfHistory = null;\n\n this._pagesRefCache = null;\n }\n\n setDocument(pdfDocument, baseUrl) {\n this.baseUrl = baseUrl;\n this.pdfDocument = pdfDocument;\n this._pagesRefCache = Object.create(null);\n }\n\n setViewer(pdfViewer) {\n this.pdfViewer = pdfViewer;\n }\n\n setHistory(pdfHistory) {\n this.pdfHistory = pdfHistory;\n }\n\n /**\n * @returns {number}\n */\n get pagesCount() {\n return this.pdfDocument ? this.pdfDocument.numPages : 0;\n }\n\n /**\n * @returns {number}\n */\n get page() {\n return this.pdfViewer.currentPageNumber;\n }\n\n /**\n * @param {number} value\n */\n set page(value) {\n this.pdfViewer.currentPageNumber = value;\n }\n\n /**\n * @param {string|Array} dest - The named, or explicit, PDF destination.\n */\n navigateTo(dest) {\n let goToDestination = ({ namedDest, explicitDest, }) => {\n // Dest array looks like that: \n let destRef = explicitDest[0], pageNumber;\n\n if (destRef instanceof Object) {\n pageNumber = this._cachedPageNumber(destRef);\n\n if (pageNumber === null) {\n // Fetch the page reference if it's not yet available. This could\n // only occur during loading, before all pages have been resolved.\n this.pdfDocument.getPageIndex(destRef).then((pageIndex) => {\n this.cachePageRef(pageIndex + 1, destRef);\n goToDestination({ namedDest, explicitDest, });\n }).catch(() => {\n console.error(`PDFLinkService.navigateTo: \"${destRef}\" is not ` +\n `a valid page reference, for dest=\"${dest}\".`);\n });\n return;\n }\n } else if ((destRef | 0) === destRef) { // Integer\n pageNumber = destRef + 1;\n } else {\n console.error(`PDFLinkService.navigateTo: \"${destRef}\" is not ` +\n `a valid destination reference, for dest=\"${dest}\".`);\n return;\n }\n if (!pageNumber || pageNumber < 1 || pageNumber > this.pagesCount) {\n console.error(`PDFLinkService.navigateTo: \"${pageNumber}\" is not ` +\n `a valid page number, for dest=\"${dest}\".`);\n return;\n }\n\n this.pdfViewer.scrollPageIntoView({\n pageNumber,\n destArray: explicitDest,\n });\n\n if (this.pdfHistory) { // Update the browsing history, if enabled.\n this.pdfHistory.push({\n dest: explicitDest,\n hash: namedDest,\n page: pageNumber,\n });\n }\n };\n\n new Promise((resolve, reject) => {\n if (typeof dest === 'string') {\n this.pdfDocument.getDestination(dest).then((destArray) => {\n resolve({\n namedDest: dest,\n explicitDest: destArray,\n });\n });\n return;\n }\n resolve({\n namedDest: '',\n explicitDest: dest,\n });\n }).then((data) => {\n if (!(data.explicitDest instanceof Array)) {\n console.error(`PDFLinkService.navigateTo: \"${data.explicitDest}\" is` +\n ` not a valid destination array, for dest=\"${dest}\".`);\n return;\n }\n goToDestination(data);\n });\n }\n\n /**\n * @param {string|Array} dest - The PDF destination object.\n * @returns {string} The hyperlink to the PDF object.\n */\n getDestinationHash(dest) {\n if (typeof dest === 'string') {\n return this.getAnchorUrl('#' + escape(dest));\n }\n if (dest instanceof Array) {\n let str = JSON.stringify(dest);\n return this.getAnchorUrl('#' + escape(str));\n }\n return this.getAnchorUrl('');\n }\n\n /**\n * Prefix the full url on anchor links to make sure that links are resolved\n * relative to the current URL instead of the one defined in .\n * @param {String} anchor The anchor hash, including the #.\n * @returns {string} The hyperlink to the PDF object.\n */\n getAnchorUrl(anchor) {\n return (this.baseUrl || '') + anchor;\n }\n\n /**\n * @param {string} hash\n */\n setHash(hash) {\n let pageNumber, dest;\n if (hash.indexOf('=') >= 0) {\n let params = parseQueryString(hash);\n if ('search' in params) {\n this.eventBus.dispatch('findfromurlhash', {\n source: this,\n query: params['search'].replace(/\"/g, ''),\n phraseSearch: (params['phrase'] === 'true'),\n });\n }\n // borrowing syntax from \"Parameters for Opening PDF Files\"\n if ('nameddest' in params) {\n if (this.pdfHistory) {\n this.pdfHistory.updateNextHashParam(params.nameddest);\n }\n this.navigateTo(params.nameddest);\n return;\n }\n if ('page' in params) {\n pageNumber = (params.page | 0) || 1;\n }\n if ('zoom' in params) {\n // Build the destination array.\n let zoomArgs = params.zoom.split(','); // scale,left,top\n let zoomArg = zoomArgs[0];\n let zoomArgNumber = parseFloat(zoomArg);\n\n if (zoomArg.indexOf('Fit') === -1) {\n // If the zoomArg is a number, it has to get divided by 100. If it's\n // a string, it should stay as it is.\n dest = [null, { name: 'XYZ', },\n zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null,\n zoomArgs.length > 2 ? (zoomArgs[2] | 0) : null,\n (zoomArgNumber ? zoomArgNumber / 100 : zoomArg)];\n } else {\n if (zoomArg === 'Fit' || zoomArg === 'FitB') {\n dest = [null, { name: zoomArg, }];\n } else if ((zoomArg === 'FitH' || zoomArg === 'FitBH') ||\n (zoomArg === 'FitV' || zoomArg === 'FitBV')) {\n dest = [null, { name: zoomArg, },\n zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null];\n } else if (zoomArg === 'FitR') {\n if (zoomArgs.length !== 5) {\n console.error(\n 'PDFLinkService.setHash: Not enough parameters for \"FitR\".');\n } else {\n dest = [null, { name: zoomArg, },\n (zoomArgs[1] | 0), (zoomArgs[2] | 0),\n (zoomArgs[3] | 0), (zoomArgs[4] | 0)];\n }\n } else {\n console.error(`PDFLinkService.setHash: \"${zoomArg}\" is not ` +\n 'a valid zoom value.');\n }\n }\n }\n if (dest) {\n this.pdfViewer.scrollPageIntoView({\n pageNumber: pageNumber || this.page,\n destArray: dest,\n allowNegativeOffset: true,\n });\n } else if (pageNumber) {\n this.page = pageNumber; // simple page\n }\n if ('pagemode' in params) {\n this.eventBus.dispatch('pagemode', {\n source: this,\n mode: params.pagemode,\n });\n }\n } else { // Named (or explicit) destination.\n if ((typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) &&\n /^\\d+$/.test(hash) && hash <= this.pagesCount) {\n console.warn('PDFLinkService_setHash: specifying a page number ' +\n 'directly after the hash symbol (#) is deprecated, ' +\n `please use the \"#page=${hash}\" form instead.`);\n this.page = hash | 0;\n }\n\n dest = unescape(hash);\n try {\n dest = JSON.parse(dest);\n\n if (!(dest instanceof Array)) {\n // Avoid incorrectly rejecting a valid named destination, such as\n // e.g. \"4.3\" or \"true\", because `JSON.parse` converted its type.\n dest = dest.toString();\n }\n } catch (ex) {}\n\n if (typeof dest === 'string' || isValidExplicitDestination(dest)) {\n if (this.pdfHistory) {\n this.pdfHistory.updateNextHashParam(dest);\n }\n this.navigateTo(dest);\n return;\n }\n console.error(`PDFLinkService.setHash: \"${unescape(hash)}\" is not ` +\n 'a valid destination.');\n }\n }\n\n /**\n * @param {string} action\n */\n executeNamedAction(action) {\n // See PDF reference, table 8.45 - Named action\n switch (action) {\n case 'GoBack':\n if (this.pdfHistory) {\n this.pdfHistory.back();\n }\n break;\n\n case 'GoForward':\n if (this.pdfHistory) {\n this.pdfHistory.forward();\n }\n break;\n\n case 'NextPage':\n if (this.page < this.pagesCount) {\n this.page++;\n }\n break;\n\n case 'PrevPage':\n if (this.page > 1) {\n this.page--;\n }\n break;\n\n case 'LastPage':\n this.page = this.pagesCount;\n break;\n\n case 'FirstPage':\n this.page = 1;\n break;\n\n default:\n break; // No action according to spec\n }\n\n this.eventBus.dispatch('namedaction', {\n source: this,\n action,\n });\n }\n\n /**\n * @param {Object} params\n */\n onFileAttachmentAnnotation({ id, filename, content, }) {\n this.eventBus.dispatch('fileattachmentannotation', {\n source: this,\n id,\n filename,\n content,\n });\n }\n\n /**\n * @param {number} pageNum - page number.\n * @param {Object} pageRef - reference to the page.\n */\n cachePageRef(pageNum, pageRef) {\n let refStr = pageRef.num + ' ' + pageRef.gen + ' R';\n this._pagesRefCache[refStr] = pageNum;\n }\n\n _cachedPageNumber(pageRef) {\n let refStr = pageRef.num + ' ' + pageRef.gen + ' R';\n return (this._pagesRefCache && this._pagesRefCache[refStr]) || null;\n }\n}\n\nfunction isValidExplicitDestination(dest) {\n if (!(dest instanceof Array)) {\n return false;\n }\n let destLength = dest.length, allowNull = true;\n if (destLength < 2) {\n return false;\n }\n let page = dest[0];\n if (!(typeof page === 'object' &&\n typeof page.num === 'number' && (page.num | 0) === page.num &&\n typeof page.gen === 'number' && (page.gen | 0) === page.gen) &&\n !(typeof page === 'number' && (page | 0) === page && page >= 0)) {\n return false;\n }\n let zoom = dest[1];\n if (!(typeof zoom === 'object' && typeof zoom.name === 'string')) {\n return false;\n }\n switch (zoom.name) {\n case 'XYZ':\n if (destLength !== 5) {\n return false;\n }\n break;\n case 'Fit':\n case 'FitB':\n return destLength === 2;\n case 'FitH':\n case 'FitBH':\n case 'FitV':\n case 'FitBV':\n if (destLength !== 3) {\n return false;\n }\n break;\n case 'FitR':\n if (destLength !== 6) {\n return false;\n }\n allowNull = false;\n break;\n default:\n return false;\n }\n for (let i = 2; i < destLength; i++) {\n let param = dest[i];\n if (!(typeof param === 'number' || (allowNull && param === null))) {\n return false;\n }\n }\n return true;\n}\n\nclass SimpleLinkService {\n /**\n * @returns {number}\n */\n get page() {\n return 0;\n }\n /**\n * @param {number} value\n */\n set page(value) {}\n /**\n * @param dest - The PDF destination object.\n */\n navigateTo(dest) {}\n /**\n * @param dest - The PDF destination object.\n * @returns {string} The hyperlink to the PDF object.\n */\n getDestinationHash(dest) {\n return '#';\n }\n /**\n * @param hash - The PDF parameters/hash.\n * @returns {string} The hyperlink to the PDF object.\n */\n getAnchorUrl(hash) {\n return '#';\n }\n /**\n * @param {string} hash\n */\n setHash(hash) {}\n /**\n * @param {string} action\n */\n executeNamedAction(action) {}\n /**\n * @param {Object} params\n */\n onFileAttachmentAnnotation({ id, filename, content, }) {}\n /**\n * @param {number} pageNum - page number.\n * @param {Object} pageRef - reference to the page.\n */\n cachePageRef(pageNum, pageRef) {}\n}\n\nexport {\n PDFLinkService,\n SimpleLinkService,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/pdf_link_service.js", + "/* Copyright 2017 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { GrabToPan } from './grab_to_pan';\n\nconst CursorTool = {\n SELECT: 0, // The default value.\n HAND: 1,\n ZOOM: 2,\n};\n\n/**\n * @typedef {Object} PDFCursorToolsOptions\n * @property {HTMLDivElement} container - The document container.\n * @property {EventBus} eventBus - The application event bus.\n * @property {BasePreferences} preferences - Object for reading/writing\n * persistent settings.\n */\n\nclass PDFCursorTools {\n /**\n * @param {PDFCursorToolsOptions} options\n */\n constructor({ container, eventBus, preferences, }) {\n this.container = container;\n this.eventBus = eventBus;\n\n this.active = CursorTool.SELECT;\n this.activeBeforePresentationMode = null;\n\n this.handTool = new GrabToPan({\n element: this.container,\n });\n\n this._addEventListeners();\n\n Promise.all([\n preferences.get('cursorToolOnLoad'),\n preferences.get('enableHandToolOnLoad')\n ]).then(([cursorToolPref, handToolPref]) => {\n // If the 'cursorToolOnLoad' preference has not been set to a non-default\n // value, attempt to convert the old 'enableHandToolOnLoad' preference.\n // TODO: Remove this conversion after a suitable number of releases.\n if (handToolPref === true) {\n preferences.set('enableHandToolOnLoad', false);\n\n if (cursorToolPref === CursorTool.SELECT) {\n cursorToolPref = CursorTool.HAND;\n preferences.set('cursorToolOnLoad', cursorToolPref).catch(() => { });\n }\n }\n this.switchTool(cursorToolPref);\n }).catch(() => { });\n }\n\n /**\n * @returns {number} One of the values in {CursorTool}.\n */\n get activeTool() {\n return this.active;\n }\n\n /**\n * NOTE: This method is ignored while Presentation Mode is active.\n * @param {number} tool - The cursor mode that should be switched to,\n * must be one of the values in {CursorTool}.\n */\n switchTool(tool) {\n if (this.activeBeforePresentationMode !== null) {\n return; // Cursor tools cannot be used in Presentation Mode.\n }\n if (tool === this.active) {\n return; // The requested tool is already active.\n }\n\n let disableActiveTool = () => {\n switch (this.active) {\n case CursorTool.SELECT:\n break;\n case CursorTool.HAND:\n this.handTool.deactivate();\n break;\n case CursorTool.ZOOM:\n /* falls through */\n }\n };\n\n switch (tool) { // Enable the new cursor tool.\n case CursorTool.SELECT:\n disableActiveTool();\n break;\n case CursorTool.HAND:\n disableActiveTool();\n this.handTool.activate();\n break;\n case CursorTool.ZOOM:\n /* falls through */\n default:\n console.error(`switchTool: \"${tool}\" is an unsupported value.`);\n return;\n }\n // Update the active tool *after* it has been validated above,\n // in order to prevent setting it to an invalid state.\n this.active = tool;\n\n this._dispatchEvent();\n }\n\n /**\n * @private\n */\n _dispatchEvent() {\n this.eventBus.dispatch('cursortoolchanged', {\n source: this,\n tool: this.active,\n });\n }\n\n /**\n * @private\n */\n _addEventListeners() {\n this.eventBus.on('switchcursortool', (evt) => {\n this.switchTool(evt.tool);\n });\n\n this.eventBus.on('presentationmodechanged', (evt) => {\n if (evt.switchInProgress) {\n return;\n }\n let previouslyActive;\n\n if (evt.active) {\n previouslyActive = this.active;\n\n this.switchTool(CursorTool.SELECT);\n this.activeBeforePresentationMode = previouslyActive;\n } else {\n previouslyActive = this.activeBeforePresentationMode;\n\n this.activeBeforePresentationMode = null;\n this.switchTool(previouslyActive);\n }\n });\n }\n}\n\nexport {\n CursorTool,\n PDFCursorTools,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/pdf_cursor_tools.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createPromiseCapability } from 'pdfjs-lib';\nimport { scrollIntoView } from './ui_utils';\n\nconst FindState = {\n FOUND: 0,\n NOT_FOUND: 1,\n WRAPPED: 2,\n PENDING: 3,\n};\n\nconst FIND_SCROLL_OFFSET_TOP = -50;\nconst FIND_SCROLL_OFFSET_LEFT = -400;\nconst FIND_TIMEOUT = 250; // ms\n\nconst CHARACTERS_TO_NORMALIZE = {\n '\\u2018': '\\'', // Left single quotation mark\n '\\u2019': '\\'', // Right single quotation mark\n '\\u201A': '\\'', // Single low-9 quotation mark\n '\\u201B': '\\'', // Single high-reversed-9 quotation mark\n '\\u201C': '\"', // Left double quotation mark\n '\\u201D': '\"', // Right double quotation mark\n '\\u201E': '\"', // Double low-9 quotation mark\n '\\u201F': '\"', // Double high-reversed-9 quotation mark\n '\\u00BC': '1/4', // Vulgar fraction one quarter\n '\\u00BD': '1/2', // Vulgar fraction one half\n '\\u00BE': '3/4', // Vulgar fraction three quarters\n};\n\n/**\n * Provides search functionality to find a given string in a PDF document.\n */\nclass PDFFindController {\n constructor({ pdfViewer, }) {\n this.pdfViewer = pdfViewer;\n\n this.onUpdateResultsCount = null;\n this.onUpdateState = null;\n\n this.reset();\n\n // Compile the regular expression for text normalization once.\n let replace = Object.keys(CHARACTERS_TO_NORMALIZE).join('');\n this.normalizationRegex = new RegExp('[' + replace + ']', 'g');\n }\n\n reset() {\n this.startedTextExtraction = false;\n this.extractTextPromises = [];\n this.pendingFindMatches = Object.create(null);\n this.active = false; // If active, find results will be highlighted.\n this.pageContents = []; // Stores the text for each page.\n this.pageMatches = [];\n this.pageMatchesLength = null;\n this.matchCount = 0;\n this.selected = { // Currently selected match.\n pageIdx: -1,\n matchIdx: -1,\n };\n this.offset = { // Where the find algorithm currently is in the document.\n pageIdx: null,\n matchIdx: null,\n };\n this.pagesToSearch = null;\n this.resumePageIdx = null;\n this.state = null;\n this.dirtyMatch = false;\n this.findTimeout = null;\n\n this._firstPagePromise = new Promise((resolve) => {\n this.resolveFirstPage = resolve;\n });\n }\n\n normalize(text) {\n return text.replace(this.normalizationRegex, function (ch) {\n return CHARACTERS_TO_NORMALIZE[ch];\n });\n }\n\n /**\n * Helper for multi-term search that fills the `matchesWithLength` array\n * and handles cases where one search term includes another search term (for\n * example, \"tamed tame\" or \"this is\"). It looks for intersecting terms in\n * the `matches` and keeps elements with a longer match length.\n */\n _prepareMatches(matchesWithLength, matches, matchesLength) {\n function isSubTerm(matchesWithLength, currentIndex) {\n let currentElem = matchesWithLength[currentIndex];\n let nextElem = matchesWithLength[currentIndex + 1];\n\n // Check for cases like \"TAMEd TAME\".\n if (currentIndex < matchesWithLength.length - 1 &&\n currentElem.match === nextElem.match) {\n currentElem.skipped = true;\n return true;\n }\n\n // Check for cases like \"thIS IS\".\n for (let i = currentIndex - 1; i >= 0; i--) {\n let prevElem = matchesWithLength[i];\n if (prevElem.skipped) {\n continue;\n }\n if (prevElem.match + prevElem.matchLength < currentElem.match) {\n break;\n }\n if (prevElem.match + prevElem.matchLength >=\n currentElem.match + currentElem.matchLength) {\n currentElem.skipped = true;\n return true;\n }\n }\n return false;\n }\n\n // Sort the array of `{ match: , matchLength: }`\n // objects on increasing index first and on the length otherwise.\n matchesWithLength.sort(function(a, b) {\n return a.match === b.match ? a.matchLength - b.matchLength :\n a.match - b.match;\n });\n for (let i = 0, len = matchesWithLength.length; i < len; i++) {\n if (isSubTerm(matchesWithLength, i)) {\n continue;\n }\n matches.push(matchesWithLength[i].match);\n matchesLength.push(matchesWithLength[i].matchLength);\n }\n }\n\n calcFindPhraseMatch(query, pageIndex, pageContent) {\n let matches = [];\n let queryLen = query.length;\n let matchIdx = -queryLen;\n while (true) {\n matchIdx = pageContent.indexOf(query, matchIdx + queryLen);\n if (matchIdx === -1) {\n break;\n }\n matches.push(matchIdx);\n }\n this.pageMatches[pageIndex] = matches;\n }\n\n calcFindWordMatch(query, pageIndex, pageContent) {\n let matchesWithLength = [];\n // Divide the query into pieces and search for text in each piece.\n let queryArray = query.match(/\\S+/g);\n for (let i = 0, len = queryArray.length; i < len; i++) {\n let subquery = queryArray[i];\n let subqueryLen = subquery.length;\n let matchIdx = -subqueryLen;\n while (true) {\n matchIdx = pageContent.indexOf(subquery, matchIdx + subqueryLen);\n if (matchIdx === -1) {\n break;\n }\n // Other searches do not, so we store the length.\n matchesWithLength.push({\n match: matchIdx,\n matchLength: subqueryLen,\n skipped: false,\n });\n }\n }\n\n // Prepare arrays for storing the matches.\n if (!this.pageMatchesLength) {\n this.pageMatchesLength = [];\n }\n this.pageMatchesLength[pageIndex] = [];\n this.pageMatches[pageIndex] = [];\n\n // Sort `matchesWithLength`, remove intersecting terms and put the result\n // into the two arrays.\n this._prepareMatches(matchesWithLength, this.pageMatches[pageIndex],\n this.pageMatchesLength[pageIndex]);\n }\n\n calcFindMatch(pageIndex) {\n let pageContent = this.normalize(this.pageContents[pageIndex]);\n let query = this.normalize(this.state.query);\n let caseSensitive = this.state.caseSensitive;\n let phraseSearch = this.state.phraseSearch;\n let queryLen = query.length;\n\n if (queryLen === 0) {\n // Do nothing: the matches should be wiped out already.\n return;\n }\n\n if (!caseSensitive) {\n pageContent = pageContent.toLowerCase();\n query = query.toLowerCase();\n }\n\n if (phraseSearch) {\n this.calcFindPhraseMatch(query, pageIndex, pageContent);\n } else {\n this.calcFindWordMatch(query, pageIndex, pageContent);\n }\n\n this.updatePage(pageIndex);\n if (this.resumePageIdx === pageIndex) {\n this.resumePageIdx = null;\n this.nextPageMatch();\n }\n\n // Update the match count.\n if (this.pageMatches[pageIndex].length > 0) {\n this.matchCount += this.pageMatches[pageIndex].length;\n this.updateUIResultsCount();\n }\n }\n\n extractText() {\n if (this.startedTextExtraction) {\n return;\n }\n this.startedTextExtraction = true;\n this.pageContents.length = 0;\n\n let promise = Promise.resolve();\n for (let i = 0, ii = this.pdfViewer.pagesCount; i < ii; i++) {\n let extractTextCapability = createPromiseCapability();\n this.extractTextPromises[i] = extractTextCapability.promise;\n\n promise = promise.then(() => {\n return this.pdfViewer.getPageTextContent(i).then((textContent) => {\n let textItems = textContent.items;\n let strBuf = [];\n\n for (let j = 0, jj = textItems.length; j < jj; j++) {\n strBuf.push(textItems[j].str);\n }\n // Store the pageContent as a string.\n this.pageContents[i] = strBuf.join('');\n extractTextCapability.resolve(i);\n }, (reason) => {\n console.error(`Unable to get page ${i + 1} text content`, reason);\n // Page error -- assuming no text content.\n this.pageContents[i] = '';\n extractTextCapability.resolve(i);\n });\n });\n }\n }\n\n executeCommand(cmd, state) {\n if (this.state === null || cmd !== 'findagain') {\n this.dirtyMatch = true;\n }\n this.state = state;\n this.updateUIState(FindState.PENDING);\n\n this._firstPagePromise.then(() => {\n this.extractText();\n\n clearTimeout(this.findTimeout);\n if (cmd === 'find') {\n // Trigger the find action with a small delay to avoid starting the\n // search when the user is still typing (saving resources).\n this.findTimeout = setTimeout(this.nextMatch.bind(this), FIND_TIMEOUT);\n } else {\n this.nextMatch();\n }\n });\n }\n\n updatePage(index) {\n if (this.selected.pageIdx === index) {\n // If the page is selected, scroll the page into view, which triggers\n // rendering the page, which adds the textLayer. Once the textLayer is\n // build, it will scroll onto the selected match.\n this.pdfViewer.currentPageNumber = index + 1;\n }\n\n let page = this.pdfViewer.getPageView(index);\n if (page.textLayer) {\n page.textLayer.updateMatches();\n }\n }\n\n nextMatch() {\n let previous = this.state.findPrevious;\n let currentPageIndex = this.pdfViewer.currentPageNumber - 1;\n let numPages = this.pdfViewer.pagesCount;\n\n this.active = true;\n\n if (this.dirtyMatch) {\n // Need to recalculate the matches, reset everything.\n this.dirtyMatch = false;\n this.selected.pageIdx = this.selected.matchIdx = -1;\n this.offset.pageIdx = currentPageIndex;\n this.offset.matchIdx = null;\n this.hadMatch = false;\n this.resumePageIdx = null;\n this.pageMatches = [];\n this.matchCount = 0;\n this.pageMatchesLength = null;\n\n for (let i = 0; i < numPages; i++) {\n // Wipe out any previously highlighted matches.\n this.updatePage(i);\n\n // Start finding the matches as soon as the text is extracted.\n if (!(i in this.pendingFindMatches)) {\n this.pendingFindMatches[i] = true;\n this.extractTextPromises[i].then((pageIdx) => {\n delete this.pendingFindMatches[pageIdx];\n this.calcFindMatch(pageIdx);\n });\n }\n }\n }\n\n // If there's no query there's no point in searching.\n if (this.state.query === '') {\n this.updateUIState(FindState.FOUND);\n return;\n }\n\n // If we're waiting on a page, we return since we can't do anything else.\n if (this.resumePageIdx) {\n return;\n }\n\n let offset = this.offset;\n // Keep track of how many pages we should maximally iterate through.\n this.pagesToSearch = numPages;\n // If there's already a `matchIdx` that means we are iterating through a\n // page's matches.\n if (offset.matchIdx !== null) {\n let numPageMatches = this.pageMatches[offset.pageIdx].length;\n if ((!previous && offset.matchIdx + 1 < numPageMatches) ||\n (previous && offset.matchIdx > 0)) {\n // The simple case; we just have advance the matchIdx to select\n // the next match on the page.\n this.hadMatch = true;\n offset.matchIdx = (previous ? offset.matchIdx - 1 :\n offset.matchIdx + 1);\n this.updateMatch(true);\n return;\n }\n // We went beyond the current page's matches, so we advance to\n // the next page.\n this.advanceOffsetPage(previous);\n }\n // Start searching through the page.\n this.nextPageMatch();\n }\n\n matchesReady(matches) {\n let offset = this.offset;\n let numMatches = matches.length;\n let previous = this.state.findPrevious;\n\n if (numMatches) {\n // There were matches for the page, so initialize `matchIdx`.\n this.hadMatch = true;\n offset.matchIdx = (previous ? numMatches - 1 : 0);\n this.updateMatch(true);\n return true;\n }\n // No matches, so attempt to search the next page.\n this.advanceOffsetPage(previous);\n if (offset.wrapped) {\n offset.matchIdx = null;\n if (this.pagesToSearch < 0) {\n // No point in wrapping again, there were no matches.\n this.updateMatch(false);\n // While matches were not found, searching for a page\n // with matches should nevertheless halt.\n return true;\n }\n }\n // Matches were not found (and searching is not done).\n return false;\n }\n\n /**\n * Called from the text layer when match presentation is updated.\n *\n * @param {number} pageIndex - The index of the page.\n * @param {number} matchIndex - The index of the match.\n * @param {Array} elements - Text layer `div` elements.\n * @param {number} beginIdx - Start index of the `div` array for the match.\n */\n updateMatchPosition(pageIndex, matchIndex, elements, beginIdx) {\n if (this.selected.matchIdx === matchIndex &&\n this.selected.pageIdx === pageIndex) {\n let spot = {\n top: FIND_SCROLL_OFFSET_TOP,\n left: FIND_SCROLL_OFFSET_LEFT,\n };\n scrollIntoView(elements[beginIdx], spot,\n /* skipOverflowHiddenElements = */ true);\n }\n }\n\n nextPageMatch() {\n if (this.resumePageIdx !== null) {\n console.error('There can only be one pending page.');\n }\n\n let matches = null;\n do {\n let pageIdx = this.offset.pageIdx;\n matches = this.pageMatches[pageIdx];\n if (!matches) {\n // The matches don't exist yet for processing by `matchesReady`,\n // so set a resume point for when they do exist.\n this.resumePageIdx = pageIdx;\n break;\n }\n } while (!this.matchesReady(matches));\n }\n\n advanceOffsetPage(previous) {\n let offset = this.offset;\n let numPages = this.extractTextPromises.length;\n offset.pageIdx = (previous ? offset.pageIdx - 1 : offset.pageIdx + 1);\n offset.matchIdx = null;\n\n this.pagesToSearch--;\n\n if (offset.pageIdx >= numPages || offset.pageIdx < 0) {\n offset.pageIdx = (previous ? numPages - 1 : 0);\n offset.wrapped = true;\n }\n }\n\n updateMatch(found = false) {\n let state = FindState.NOT_FOUND;\n let wrapped = this.offset.wrapped;\n this.offset.wrapped = false;\n\n if (found) {\n let previousPage = this.selected.pageIdx;\n this.selected.pageIdx = this.offset.pageIdx;\n this.selected.matchIdx = this.offset.matchIdx;\n state = (wrapped ? FindState.WRAPPED : FindState.FOUND);\n\n // Update the currently selected page to wipe out any selected matches.\n if (previousPage !== -1 && previousPage !== this.selected.pageIdx) {\n this.updatePage(previousPage);\n }\n }\n\n this.updateUIState(state, this.state.findPrevious);\n if (this.selected.pageIdx !== -1) {\n this.updatePage(this.selected.pageIdx);\n }\n }\n\n updateUIResultsCount() {\n if (this.onUpdateResultsCount) {\n this.onUpdateResultsCount(this.matchCount);\n }\n }\n\n updateUIState(state, previous) {\n if (this.onUpdateState) {\n this.onUpdateState(state, previous, this.matchCount);\n }\n }\n}\n\nexport {\n FindState,\n PDFFindController,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/pdf_find_controller.js", + "/* Copyright 2017 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DefaultExternalServices, PDFViewerApplication } from './app';\nimport { BasePreferences } from './preferences';\nimport { DownloadManager } from './download_manager';\nimport { GenericL10n } from './genericl10n';\nimport { PDFJS } from 'pdfjs-lib';\n\nif (typeof PDFJSDev !== 'undefined' && !PDFJSDev.test('GENERIC')) {\n throw new Error('Module \"pdfjs-web/genericcom\" shall not be used outside ' +\n 'GENERIC build.');\n}\n\nvar GenericCom = {};\n\nclass GenericPreferences extends BasePreferences {\n _writeToStorage(prefObj) {\n return new Promise(function(resolve) {\n localStorage.setItem('pdfjs.preferences', JSON.stringify(prefObj));\n resolve();\n });\n }\n\n _readFromStorage(prefObj) {\n return new Promise(function(resolve) {\n var readPrefs = JSON.parse(localStorage.getItem('pdfjs.preferences'));\n resolve(readPrefs);\n });\n }\n}\n\nvar GenericExternalServices = Object.create(DefaultExternalServices);\nGenericExternalServices.createDownloadManager = function() {\n return new DownloadManager();\n};\nGenericExternalServices.createPreferences = function() {\n return new GenericPreferences();\n};\nGenericExternalServices.createL10n = function () {\n return new GenericL10n(PDFJS.locale);\n};\nPDFViewerApplication.externalServices = GenericExternalServices;\n\nexport {\n GenericCom,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/genericcom.js", + "/* Copyright 2016 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CSS_UNITS, NullL10n } from './ui_utils';\nimport { PDFPrintServiceFactory, PDFViewerApplication } from './app';\nimport { PDFJS } from 'pdfjs-lib';\n\nlet activeService = null;\nlet overlayManager = null;\n\n// Renders the page to the canvas of the given print service, and returns\n// the suggested dimensions of the output page.\nfunction renderPage(activeServiceOnEntry, pdfDocument, pageNumber, size) {\n var scratchCanvas = activeService.scratchCanvas;\n\n // The size of the canvas in pixels for printing.\n var PRINT_RESOLUTION = 150;\n var PRINT_UNITS = PRINT_RESOLUTION / 72.0;\n scratchCanvas.width = Math.floor(size.width * PRINT_UNITS);\n scratchCanvas.height = Math.floor(size.height * PRINT_UNITS);\n\n // The physical size of the img as specified by the PDF document.\n var width = Math.floor(size.width * CSS_UNITS) + 'px';\n var height = Math.floor(size.height * CSS_UNITS) + 'px';\n\n var ctx = scratchCanvas.getContext('2d');\n ctx.save();\n ctx.fillStyle = 'rgb(255, 255, 255)';\n ctx.fillRect(0, 0, scratchCanvas.width, scratchCanvas.height);\n ctx.restore();\n\n return pdfDocument.getPage(pageNumber).then(function (pdfPage) {\n var renderContext = {\n canvasContext: ctx,\n transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0],\n viewport: pdfPage.getViewport(1, size.rotation),\n intent: 'print',\n };\n return pdfPage.render(renderContext).promise;\n }).then(function () {\n return {\n width,\n height,\n };\n });\n}\n\nfunction PDFPrintService(pdfDocument, pagesOverview, printContainer, l10n) {\n this.pdfDocument = pdfDocument;\n this.pagesOverview = pagesOverview;\n this.printContainer = printContainer;\n this.l10n = l10n || NullL10n;\n this.currentPage = -1;\n // The temporary canvas where renderPage paints one page at a time.\n this.scratchCanvas = document.createElement('canvas');\n}\n\nPDFPrintService.prototype = {\n layout() {\n this.throwIfInactive();\n\n var body = document.querySelector('body');\n body.setAttribute('data-pdfjsprinting', true);\n\n var hasEqualPageSizes = this.pagesOverview.every(function (size) {\n return size.width === this.pagesOverview[0].width &&\n size.height === this.pagesOverview[0].height;\n }, this);\n if (!hasEqualPageSizes) {\n console.warn('Not all pages have the same size. The printed ' +\n 'result may be incorrect!');\n }\n\n // Insert a @page + size rule to make sure that the page size is correctly\n // set. Note that we assume that all pages have the same size, because\n // variable-size pages are not supported yet (e.g. in Chrome & Firefox).\n // TODO(robwu): Use named pages when size calculation bugs get resolved\n // (e.g. https://crbug.com/355116) AND when support for named pages is\n // added (http://www.w3.org/TR/css3-page/#using-named-pages).\n // In browsers where @page + size is not supported (such as Firefox,\n // https://bugzil.la/851441), the next stylesheet will be ignored and the\n // user has to select the correct paper size in the UI if wanted.\n this.pageStyleSheet = document.createElement('style');\n var pageSize = this.pagesOverview[0];\n this.pageStyleSheet.textContent =\n // \"size: \" is what we need. But also add \"A4\" because\n // Firefox incorrectly reports support for the other value.\n '@supports ((size:A4) and (size:1pt 1pt)) {' +\n '@page { size: ' + pageSize.width + 'pt ' + pageSize.height + 'pt;}' +\n '}';\n body.appendChild(this.pageStyleSheet);\n },\n\n destroy() {\n if (activeService !== this) {\n // |activeService| cannot be replaced without calling destroy() first,\n // so if it differs then an external consumer has a stale reference to\n // us.\n return;\n }\n this.printContainer.textContent = '';\n if (this.pageStyleSheet && this.pageStyleSheet.parentNode) {\n this.pageStyleSheet.parentNode.removeChild(this.pageStyleSheet);\n this.pageStyleSheet = null;\n }\n this.scratchCanvas.width = this.scratchCanvas.height = 0;\n this.scratchCanvas = null;\n activeService = null;\n ensureOverlay().then(function () {\n if (overlayManager.active !== 'printServiceOverlay') {\n return; // overlay was already closed\n }\n overlayManager.close('printServiceOverlay');\n });\n },\n\n renderPages() {\n var pageCount = this.pagesOverview.length;\n var renderNextPage = (resolve, reject) => {\n this.throwIfInactive();\n if (++this.currentPage >= pageCount) {\n renderProgress(pageCount, pageCount, this.l10n);\n resolve();\n return;\n }\n var index = this.currentPage;\n renderProgress(index, pageCount, this.l10n);\n renderPage(this, this.pdfDocument, index + 1, this.pagesOverview[index])\n .then(this.useRenderedPage.bind(this))\n .then(function () {\n renderNextPage(resolve, reject);\n }, reject);\n };\n return new Promise(renderNextPage);\n },\n\n useRenderedPage(printItem) {\n this.throwIfInactive();\n var img = document.createElement('img');\n img.style.width = printItem.width;\n img.style.height = printItem.height;\n\n var scratchCanvas = this.scratchCanvas;\n if (('toBlob' in scratchCanvas) && !PDFJS.disableCreateObjectURL) {\n scratchCanvas.toBlob(function (blob) {\n img.src = URL.createObjectURL(blob);\n });\n } else {\n img.src = scratchCanvas.toDataURL();\n }\n\n var wrapper = document.createElement('div');\n wrapper.appendChild(img);\n this.printContainer.appendChild(wrapper);\n\n return new Promise(function (resolve, reject) {\n img.onload = resolve;\n img.onerror = reject;\n });\n },\n\n performPrint() {\n this.throwIfInactive();\n return new Promise((resolve) => {\n // Push window.print in the macrotask queue to avoid being affected by\n // the deprecation of running print() code in a microtask, see\n // https://github.com/mozilla/pdf.js/issues/7547.\n setTimeout(() => {\n if (!this.active) {\n resolve();\n return;\n }\n print.call(window);\n // Delay promise resolution in case print() was not synchronous.\n setTimeout(resolve, 20); // Tidy-up.\n }, 0);\n });\n },\n\n get active() {\n return this === activeService;\n },\n\n throwIfInactive() {\n if (!this.active) {\n throw new Error('This print request was cancelled or completed.');\n }\n },\n};\n\n\nvar print = window.print;\nwindow.print = function print() {\n if (activeService) {\n console.warn('Ignored window.print() because of a pending print job.');\n return;\n }\n ensureOverlay().then(function () {\n if (activeService) {\n overlayManager.open('printServiceOverlay');\n }\n });\n\n try {\n dispatchEvent('beforeprint');\n } finally {\n if (!activeService) {\n console.error('Expected print service to be initialized.');\n ensureOverlay().then(function () {\n if (overlayManager.active === 'printServiceOverlay') {\n overlayManager.close('printServiceOverlay');\n }\n });\n return; // eslint-disable-line no-unsafe-finally\n }\n var activeServiceOnEntry = activeService;\n activeService.renderPages().then(function () {\n return activeServiceOnEntry.performPrint();\n }).catch(function () {\n // Ignore any error messages.\n }).then(function () {\n // aborts acts on the \"active\" print request, so we need to check\n // whether the print request (activeServiceOnEntry) is still active.\n // Without the check, an unrelated print request (created after aborting\n // this print request while the pages were being generated) would be\n // aborted.\n if (activeServiceOnEntry.active) {\n abort();\n }\n });\n }\n};\n\nfunction dispatchEvent(eventType) {\n var event = document.createEvent('CustomEvent');\n event.initCustomEvent(eventType, false, false, 'custom');\n window.dispatchEvent(event);\n}\n\nfunction abort() {\n if (activeService) {\n activeService.destroy();\n dispatchEvent('afterprint');\n }\n}\n\nfunction renderProgress(index, total, l10n) {\n var progressContainer = document.getElementById('printServiceOverlay');\n var progress = Math.round(100 * index / total);\n var progressBar = progressContainer.querySelector('progress');\n var progressPerc = progressContainer.querySelector('.relative-progress');\n progressBar.value = progress;\n l10n.get('print_progress_percent', { progress, }, progress + '%').\n then((msg) => {\n progressPerc.textContent = msg;\n });\n}\n\nvar hasAttachEvent = !!document.attachEvent;\n\nwindow.addEventListener('keydown', function(event) {\n // Intercept Cmd/Ctrl + P in all browsers.\n // Also intercept Cmd/Ctrl + Shift + P in Chrome and Opera\n if (event.keyCode === /* P= */ 80 && (event.ctrlKey || event.metaKey) &&\n !event.altKey && (!event.shiftKey || window.chrome || window.opera)) {\n window.print();\n if (hasAttachEvent) {\n // Only attachEvent can cancel Ctrl + P dialog in IE <=10\n // attachEvent is gone in IE11, so the dialog will re-appear in IE11.\n return;\n }\n event.preventDefault();\n if (event.stopImmediatePropagation) {\n event.stopImmediatePropagation();\n } else {\n event.stopPropagation();\n }\n return;\n }\n}, true);\nif (hasAttachEvent) {\n document.attachEvent('onkeydown', function(event) {\n event = event || window.event;\n if (event.keyCode === /* P= */ 80 && event.ctrlKey) {\n event.keyCode = 0;\n return false;\n }\n });\n}\n\nif ('onbeforeprint' in window) {\n // Do not propagate before/afterprint events when they are not triggered\n // from within this polyfill. (FF/IE).\n var stopPropagationIfNeeded = function(event) {\n if (event.detail !== 'custom' && event.stopImmediatePropagation) {\n event.stopImmediatePropagation();\n }\n };\n window.addEventListener('beforeprint', stopPropagationIfNeeded);\n window.addEventListener('afterprint', stopPropagationIfNeeded);\n}\n\nvar overlayPromise;\nfunction ensureOverlay() {\n if (!overlayPromise) {\n overlayManager = PDFViewerApplication.overlayManager;\n if (!overlayManager) {\n throw new Error('The overlay manager has not yet been initialized.');\n }\n\n overlayPromise = overlayManager.register('printServiceOverlay',\n document.getElementById('printServiceOverlay'), abort, true);\n document.getElementById('printCancel').onclick = abort;\n }\n return overlayPromise;\n}\n\nPDFPrintServiceFactory.instance = {\n supportsPrinting: true,\n\n createPrintService(pdfDocument, pagesOverview, printContainer, l10n) {\n if (activeService) {\n throw new Error('The print service is created and active.');\n }\n activeService = new PDFPrintService(pdfDocument, pagesOverview,\n printContainer, l10n);\n return activeService;\n },\n};\n\nexport {\n PDFPrintService,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/pdf_print_service.js", + "/**\n * Copyright (c) 2011-2013 Fabien Cazenave, Mozilla.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n/*\n Additional modifications for PDF.js project:\n - Disables language initialization on page loading.\n - Disables document translation on page loading.\n - Removes consoleWarn and consoleLog and use console.log/warn directly.\n - Removes window._ assignment.\n - Remove compatibility code for OldIE.\n*/\n\n/*jshint browser: true, devel: true, es5: true, globalstrict: true */\n'use strict';\n\ndocument.webL10n = (function(window, document, undefined) {\n var gL10nData = {};\n var gTextData = '';\n var gTextProp = 'textContent';\n var gLanguage = '';\n var gMacros = {};\n var gReadyState = 'loading';\n\n\n /**\n * Synchronously loading l10n resources significantly minimizes flickering\n * from displaying the app with non-localized strings and then updating the\n * strings. Although this will block all script execution on this page, we\n * expect that the l10n resources are available locally on flash-storage.\n *\n * As synchronous XHR is generally considered as a bad idea, we're still\n * loading l10n resources asynchronously -- but we keep this in a setting,\n * just in case... and applications using this library should hide their\n * content until the `localized' event happens.\n */\n\n var gAsyncResourceLoading = true; // read-only\n\n\n /**\n * DOM helpers for the so-called \"HTML API\".\n *\n * These functions are written for modern browsers. For old versions of IE,\n * they're overridden in the 'startup' section at the end of this file.\n */\n\n function getL10nResourceLinks() {\n return document.querySelectorAll('link[type=\"application/l10n\"]');\n }\n\n function getL10nDictionary() {\n var script = document.querySelector('script[type=\"application/l10n\"]');\n // TODO: support multiple and external JSON dictionaries\n return script ? JSON.parse(script.innerHTML) : null;\n }\n\n function getTranslatableChildren(element) {\n return element ? element.querySelectorAll('*[data-l10n-id]') : [];\n }\n\n function getL10nAttributes(element) {\n if (!element)\n return {};\n\n var l10nId = element.getAttribute('data-l10n-id');\n var l10nArgs = element.getAttribute('data-l10n-args');\n var args = {};\n if (l10nArgs) {\n try {\n args = JSON.parse(l10nArgs);\n } catch (e) {\n console.warn('could not parse arguments for #' + l10nId);\n }\n }\n return { id: l10nId, args: args };\n }\n\n function fireL10nReadyEvent(lang) {\n var evtObject = document.createEvent('Event');\n evtObject.initEvent('localized', true, false);\n evtObject.language = lang;\n document.dispatchEvent(evtObject);\n }\n\n function xhrLoadText(url, onSuccess, onFailure) {\n onSuccess = onSuccess || function _onSuccess(data) {};\n onFailure = onFailure || function _onFailure() {};\n\n var xhr = new XMLHttpRequest();\n xhr.open('GET', url, gAsyncResourceLoading);\n if (xhr.overrideMimeType) {\n xhr.overrideMimeType('text/plain; charset=utf-8');\n }\n xhr.onreadystatechange = function() {\n if (xhr.readyState == 4) {\n if (xhr.status == 200 || xhr.status === 0) {\n onSuccess(xhr.responseText);\n } else {\n onFailure();\n }\n }\n };\n xhr.onerror = onFailure;\n xhr.ontimeout = onFailure;\n\n // in Firefox OS with the app:// protocol, trying to XHR a non-existing\n // URL will raise an exception here -- hence this ugly try...catch.\n try {\n xhr.send(null);\n } catch (e) {\n onFailure();\n }\n }\n\n\n /**\n * l10n resource parser:\n * - reads (async XHR) the l10n resource matching `lang';\n * - imports linked resources (synchronously) when specified;\n * - parses the text data (fills `gL10nData' and `gTextData');\n * - triggers success/failure callbacks when done.\n *\n * @param {string} href\n * URL of the l10n resource to parse.\n *\n * @param {string} lang\n * locale (language) to parse. Must be a lowercase string.\n *\n * @param {Function} successCallback\n * triggered when the l10n resource has been successully parsed.\n *\n * @param {Function} failureCallback\n * triggered when the an error has occured.\n *\n * @return {void}\n * uses the following global variables: gL10nData, gTextData, gTextProp.\n */\n\n function parseResource(href, lang, successCallback, failureCallback) {\n var baseURL = href.replace(/[^\\/]*$/, '') || './';\n\n // handle escaped characters (backslashes) in a string\n function evalString(text) {\n if (text.lastIndexOf('\\\\') < 0)\n return text;\n return text.replace(/\\\\\\\\/g, '\\\\')\n .replace(/\\\\n/g, '\\n')\n .replace(/\\\\r/g, '\\r')\n .replace(/\\\\t/g, '\\t')\n .replace(/\\\\b/g, '\\b')\n .replace(/\\\\f/g, '\\f')\n .replace(/\\\\{/g, '{')\n .replace(/\\\\}/g, '}')\n .replace(/\\\\\"/g, '\"')\n .replace(/\\\\'/g, \"'\");\n }\n\n // parse *.properties text data into an l10n dictionary\n // If gAsyncResourceLoading is false, then the callback will be called\n // synchronously. Otherwise it is called asynchronously.\n function parseProperties(text, parsedPropertiesCallback) {\n var dictionary = {};\n\n // token expressions\n var reBlank = /^\\s*|\\s*$/;\n var reComment = /^\\s*#|^\\s*$/;\n var reSection = /^\\s*\\[(.*)\\]\\s*$/;\n var reImport = /^\\s*@import\\s+url\\((.*)\\)\\s*$/i;\n var reSplit = /^([^=\\s]*)\\s*=\\s*(.+)$/; // TODO: escape EOLs with '\\'\n\n // parse the *.properties file into an associative array\n function parseRawLines(rawText, extendedSyntax, parsedRawLinesCallback) {\n var entries = rawText.replace(reBlank, '').split(/[\\r\\n]+/);\n var currentLang = '*';\n var genericLang = lang.split('-', 1)[0];\n var skipLang = false;\n var match = '';\n\n function nextEntry() {\n // Use infinite loop instead of recursion to avoid reaching the\n // maximum recursion limit for content with many lines.\n while (true) {\n if (!entries.length) {\n parsedRawLinesCallback();\n return;\n }\n var line = entries.shift();\n\n // comment or blank line?\n if (reComment.test(line))\n continue;\n\n // the extended syntax supports [lang] sections and @import rules\n if (extendedSyntax) {\n match = reSection.exec(line);\n if (match) { // section start?\n // RFC 4646, section 4.4, \"All comparisons MUST be performed\n // in a case-insensitive manner.\"\n\n currentLang = match[1].toLowerCase();\n skipLang = (currentLang !== '*') &&\n (currentLang !== lang) && (currentLang !== genericLang);\n continue;\n } else if (skipLang) {\n continue;\n }\n match = reImport.exec(line);\n if (match) { // @import rule?\n loadImport(baseURL + match[1], nextEntry);\n return;\n }\n }\n\n // key-value pair\n var tmp = line.match(reSplit);\n if (tmp && tmp.length == 3) {\n dictionary[tmp[1]] = evalString(tmp[2]);\n }\n }\n }\n nextEntry();\n }\n\n // import another *.properties file\n function loadImport(url, callback) {\n xhrLoadText(url, function(content) {\n parseRawLines(content, false, callback); // don't allow recursive imports\n }, function () {\n console.warn(url + ' not found.');\n callback();\n });\n }\n\n // fill the dictionary\n parseRawLines(text, true, function() {\n parsedPropertiesCallback(dictionary);\n });\n }\n\n // load and parse l10n data (warning: global variables are used here)\n xhrLoadText(href, function(response) {\n gTextData += response; // mostly for debug\n\n // parse *.properties text data into an l10n dictionary\n parseProperties(response, function(data) {\n\n // find attribute descriptions, if any\n for (var key in data) {\n var id, prop, index = key.lastIndexOf('.');\n if (index > 0) { // an attribute has been specified\n id = key.substring(0, index);\n prop = key.substr(index + 1);\n } else { // no attribute: assuming text content by default\n id = key;\n prop = gTextProp;\n }\n if (!gL10nData[id]) {\n gL10nData[id] = {};\n }\n gL10nData[id][prop] = data[key];\n }\n\n // trigger callback\n if (successCallback) {\n successCallback();\n }\n });\n }, failureCallback);\n }\n\n // load and parse all resources for the specified locale\n function loadLocale(lang, callback) {\n // RFC 4646, section 2.1 states that language tags have to be treated as\n // case-insensitive. Convert to lowercase for case-insensitive comparisons.\n if (lang) {\n lang = lang.toLowerCase();\n }\n\n callback = callback || function _callback() {};\n\n clear();\n gLanguage = lang;\n\n // check all nodes\n // and load the resource files\n var langLinks = getL10nResourceLinks();\n var langCount = langLinks.length;\n if (langCount === 0) {\n // we might have a pre-compiled dictionary instead\n var dict = getL10nDictionary();\n if (dict && dict.locales && dict.default_locale) {\n console.log('using the embedded JSON directory, early way out');\n gL10nData = dict.locales[lang];\n if (!gL10nData) {\n var defaultLocale = dict.default_locale.toLowerCase();\n for (var anyCaseLang in dict.locales) {\n anyCaseLang = anyCaseLang.toLowerCase();\n if (anyCaseLang === lang) {\n gL10nData = dict.locales[lang];\n break;\n } else if (anyCaseLang === defaultLocale) {\n gL10nData = dict.locales[defaultLocale];\n }\n }\n }\n callback();\n } else {\n console.log('no resource to load, early way out');\n }\n // early way out\n fireL10nReadyEvent(lang);\n gReadyState = 'complete';\n return;\n }\n\n // start the callback when all resources are loaded\n var onResourceLoaded = null;\n var gResourceCount = 0;\n onResourceLoaded = function() {\n gResourceCount++;\n if (gResourceCount >= langCount) {\n callback();\n fireL10nReadyEvent(lang);\n gReadyState = 'complete';\n }\n };\n\n // load all resource files\n function L10nResourceLink(link) {\n var href = link.href;\n // Note: If |gAsyncResourceLoading| is false, then the following callbacks\n // are synchronously called.\n this.load = function(lang, callback) {\n parseResource(href, lang, callback, function() {\n console.warn(href + ' not found.');\n // lang not found, used default resource instead\n console.warn('\"' + lang + '\" resource not found');\n gLanguage = '';\n // Resource not loaded, but we still need to call the callback.\n callback();\n });\n };\n }\n\n for (var i = 0; i < langCount; i++) {\n var resource = new L10nResourceLink(langLinks[i]);\n resource.load(lang, onResourceLoaded);\n }\n }\n\n // clear all l10n data\n function clear() {\n gL10nData = {};\n gTextData = '';\n gLanguage = '';\n // TODO: clear all non predefined macros.\n // There's no such macro /yet/ but we're planning to have some...\n }\n\n\n /**\n * Get rules for plural forms (shared with JetPack), see:\n * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html\n * https://github.com/mozilla/addon-sdk/blob/master/python-lib/plural-rules-generator.p\n *\n * @param {string} lang\n * locale (language) used.\n *\n * @return {Function}\n * returns a function that gives the plural form name for a given integer:\n * var fun = getPluralRules('en');\n * fun(1) -> 'one'\n * fun(0) -> 'other'\n * fun(1000) -> 'other'.\n */\n\n function getPluralRules(lang) {\n var locales2rules = {\n 'af': 3,\n 'ak': 4,\n 'am': 4,\n 'ar': 1,\n 'asa': 3,\n 'az': 0,\n 'be': 11,\n 'bem': 3,\n 'bez': 3,\n 'bg': 3,\n 'bh': 4,\n 'bm': 0,\n 'bn': 3,\n 'bo': 0,\n 'br': 20,\n 'brx': 3,\n 'bs': 11,\n 'ca': 3,\n 'cgg': 3,\n 'chr': 3,\n 'cs': 12,\n 'cy': 17,\n 'da': 3,\n 'de': 3,\n 'dv': 3,\n 'dz': 0,\n 'ee': 3,\n 'el': 3,\n 'en': 3,\n 'eo': 3,\n 'es': 3,\n 'et': 3,\n 'eu': 3,\n 'fa': 0,\n 'ff': 5,\n 'fi': 3,\n 'fil': 4,\n 'fo': 3,\n 'fr': 5,\n 'fur': 3,\n 'fy': 3,\n 'ga': 8,\n 'gd': 24,\n 'gl': 3,\n 'gsw': 3,\n 'gu': 3,\n 'guw': 4,\n 'gv': 23,\n 'ha': 3,\n 'haw': 3,\n 'he': 2,\n 'hi': 4,\n 'hr': 11,\n 'hu': 0,\n 'id': 0,\n 'ig': 0,\n 'ii': 0,\n 'is': 3,\n 'it': 3,\n 'iu': 7,\n 'ja': 0,\n 'jmc': 3,\n 'jv': 0,\n 'ka': 0,\n 'kab': 5,\n 'kaj': 3,\n 'kcg': 3,\n 'kde': 0,\n 'kea': 0,\n 'kk': 3,\n 'kl': 3,\n 'km': 0,\n 'kn': 0,\n 'ko': 0,\n 'ksb': 3,\n 'ksh': 21,\n 'ku': 3,\n 'kw': 7,\n 'lag': 18,\n 'lb': 3,\n 'lg': 3,\n 'ln': 4,\n 'lo': 0,\n 'lt': 10,\n 'lv': 6,\n 'mas': 3,\n 'mg': 4,\n 'mk': 16,\n 'ml': 3,\n 'mn': 3,\n 'mo': 9,\n 'mr': 3,\n 'ms': 0,\n 'mt': 15,\n 'my': 0,\n 'nah': 3,\n 'naq': 7,\n 'nb': 3,\n 'nd': 3,\n 'ne': 3,\n 'nl': 3,\n 'nn': 3,\n 'no': 3,\n 'nr': 3,\n 'nso': 4,\n 'ny': 3,\n 'nyn': 3,\n 'om': 3,\n 'or': 3,\n 'pa': 3,\n 'pap': 3,\n 'pl': 13,\n 'ps': 3,\n 'pt': 3,\n 'rm': 3,\n 'ro': 9,\n 'rof': 3,\n 'ru': 11,\n 'rwk': 3,\n 'sah': 0,\n 'saq': 3,\n 'se': 7,\n 'seh': 3,\n 'ses': 0,\n 'sg': 0,\n 'sh': 11,\n 'shi': 19,\n 'sk': 12,\n 'sl': 14,\n 'sma': 7,\n 'smi': 7,\n 'smj': 7,\n 'smn': 7,\n 'sms': 7,\n 'sn': 3,\n 'so': 3,\n 'sq': 3,\n 'sr': 11,\n 'ss': 3,\n 'ssy': 3,\n 'st': 3,\n 'sv': 3,\n 'sw': 3,\n 'syr': 3,\n 'ta': 3,\n 'te': 3,\n 'teo': 3,\n 'th': 0,\n 'ti': 4,\n 'tig': 3,\n 'tk': 3,\n 'tl': 4,\n 'tn': 3,\n 'to': 0,\n 'tr': 0,\n 'ts': 3,\n 'tzm': 22,\n 'uk': 11,\n 'ur': 3,\n 've': 3,\n 'vi': 0,\n 'vun': 3,\n 'wa': 4,\n 'wae': 3,\n 'wo': 0,\n 'xh': 3,\n 'xog': 3,\n 'yo': 0,\n 'zh': 0,\n 'zu': 3\n };\n\n // utility functions for plural rules methods\n function isIn(n, list) {\n return list.indexOf(n) !== -1;\n }\n function isBetween(n, start, end) {\n return start <= n && n <= end;\n }\n\n // list of all plural rules methods:\n // map an integer to the plural form name to use\n var pluralRules = {\n '0': function(n) {\n return 'other';\n },\n '1': function(n) {\n if ((isBetween((n % 100), 3, 10)))\n return 'few';\n if (n === 0)\n return 'zero';\n if ((isBetween((n % 100), 11, 99)))\n return 'many';\n if (n == 2)\n return 'two';\n if (n == 1)\n return 'one';\n return 'other';\n },\n '2': function(n) {\n if (n !== 0 && (n % 10) === 0)\n return 'many';\n if (n == 2)\n return 'two';\n if (n == 1)\n return 'one';\n return 'other';\n },\n '3': function(n) {\n if (n == 1)\n return 'one';\n return 'other';\n },\n '4': function(n) {\n if ((isBetween(n, 0, 1)))\n return 'one';\n return 'other';\n },\n '5': function(n) {\n if ((isBetween(n, 0, 2)) && n != 2)\n return 'one';\n return 'other';\n },\n '6': function(n) {\n if (n === 0)\n return 'zero';\n if ((n % 10) == 1 && (n % 100) != 11)\n return 'one';\n return 'other';\n },\n '7': function(n) {\n if (n == 2)\n return 'two';\n if (n == 1)\n return 'one';\n return 'other';\n },\n '8': function(n) {\n if ((isBetween(n, 3, 6)))\n return 'few';\n if ((isBetween(n, 7, 10)))\n return 'many';\n if (n == 2)\n return 'two';\n if (n == 1)\n return 'one';\n return 'other';\n },\n '9': function(n) {\n if (n === 0 || n != 1 && (isBetween((n % 100), 1, 19)))\n return 'few';\n if (n == 1)\n return 'one';\n return 'other';\n },\n '10': function(n) {\n if ((isBetween((n % 10), 2, 9)) && !(isBetween((n % 100), 11, 19)))\n return 'few';\n if ((n % 10) == 1 && !(isBetween((n % 100), 11, 19)))\n return 'one';\n return 'other';\n },\n '11': function(n) {\n if ((isBetween((n % 10), 2, 4)) && !(isBetween((n % 100), 12, 14)))\n return 'few';\n if ((n % 10) === 0 ||\n (isBetween((n % 10), 5, 9)) ||\n (isBetween((n % 100), 11, 14)))\n return 'many';\n if ((n % 10) == 1 && (n % 100) != 11)\n return 'one';\n return 'other';\n },\n '12': function(n) {\n if ((isBetween(n, 2, 4)))\n return 'few';\n if (n == 1)\n return 'one';\n return 'other';\n },\n '13': function(n) {\n if ((isBetween((n % 10), 2, 4)) && !(isBetween((n % 100), 12, 14)))\n return 'few';\n if (n != 1 && (isBetween((n % 10), 0, 1)) ||\n (isBetween((n % 10), 5, 9)) ||\n (isBetween((n % 100), 12, 14)))\n return 'many';\n if (n == 1)\n return 'one';\n return 'other';\n },\n '14': function(n) {\n if ((isBetween((n % 100), 3, 4)))\n return 'few';\n if ((n % 100) == 2)\n return 'two';\n if ((n % 100) == 1)\n return 'one';\n return 'other';\n },\n '15': function(n) {\n if (n === 0 || (isBetween((n % 100), 2, 10)))\n return 'few';\n if ((isBetween((n % 100), 11, 19)))\n return 'many';\n if (n == 1)\n return 'one';\n return 'other';\n },\n '16': function(n) {\n if ((n % 10) == 1 && n != 11)\n return 'one';\n return 'other';\n },\n '17': function(n) {\n if (n == 3)\n return 'few';\n if (n === 0)\n return 'zero';\n if (n == 6)\n return 'many';\n if (n == 2)\n return 'two';\n if (n == 1)\n return 'one';\n return 'other';\n },\n '18': function(n) {\n if (n === 0)\n return 'zero';\n if ((isBetween(n, 0, 2)) && n !== 0 && n != 2)\n return 'one';\n return 'other';\n },\n '19': function(n) {\n if ((isBetween(n, 2, 10)))\n return 'few';\n if ((isBetween(n, 0, 1)))\n return 'one';\n return 'other';\n },\n '20': function(n) {\n if ((isBetween((n % 10), 3, 4) || ((n % 10) == 9)) && !(\n isBetween((n % 100), 10, 19) ||\n isBetween((n % 100), 70, 79) ||\n isBetween((n % 100), 90, 99)\n ))\n return 'few';\n if ((n % 1000000) === 0 && n !== 0)\n return 'many';\n if ((n % 10) == 2 && !isIn((n % 100), [12, 72, 92]))\n return 'two';\n if ((n % 10) == 1 && !isIn((n % 100), [11, 71, 91]))\n return 'one';\n return 'other';\n },\n '21': function(n) {\n if (n === 0)\n return 'zero';\n if (n == 1)\n return 'one';\n return 'other';\n },\n '22': function(n) {\n if ((isBetween(n, 0, 1)) || (isBetween(n, 11, 99)))\n return 'one';\n return 'other';\n },\n '23': function(n) {\n if ((isBetween((n % 10), 1, 2)) || (n % 20) === 0)\n return 'one';\n return 'other';\n },\n '24': function(n) {\n if ((isBetween(n, 3, 10) || isBetween(n, 13, 19)))\n return 'few';\n if (isIn(n, [2, 12]))\n return 'two';\n if (isIn(n, [1, 11]))\n return 'one';\n return 'other';\n }\n };\n\n // return a function that gives the plural form name for a given integer\n var index = locales2rules[lang.replace(/-.*$/, '')];\n if (!(index in pluralRules)) {\n console.warn('plural form unknown for [' + lang + ']');\n return function() { return 'other'; };\n }\n return pluralRules[index];\n }\n\n // pre-defined 'plural' macro\n gMacros.plural = function(str, param, key, prop) {\n var n = parseFloat(param);\n if (isNaN(n))\n return str;\n\n // TODO: support other properties (l20n still doesn't...)\n if (prop != gTextProp)\n return str;\n\n // initialize _pluralRules\n if (!gMacros._pluralRules) {\n gMacros._pluralRules = getPluralRules(gLanguage);\n }\n var index = '[' + gMacros._pluralRules(n) + ']';\n\n // try to find a [zero|one|two] key if it's defined\n if (n === 0 && (key + '[zero]') in gL10nData) {\n str = gL10nData[key + '[zero]'][prop];\n } else if (n == 1 && (key + '[one]') in gL10nData) {\n str = gL10nData[key + '[one]'][prop];\n } else if (n == 2 && (key + '[two]') in gL10nData) {\n str = gL10nData[key + '[two]'][prop];\n } else if ((key + index) in gL10nData) {\n str = gL10nData[key + index][prop];\n } else if ((key + '[other]') in gL10nData) {\n str = gL10nData[key + '[other]'][prop];\n }\n\n return str;\n };\n\n\n /**\n * l10n dictionary functions\n */\n\n // fetch an l10n object, warn if not found, apply `args' if possible\n function getL10nData(key, args, fallback) {\n var data = gL10nData[key];\n if (!data) {\n console.warn('#' + key + ' is undefined.');\n if (!fallback) {\n return null;\n }\n data = fallback;\n }\n\n /** This is where l10n expressions should be processed.\n * The plan is to support C-style expressions from the l20n project;\n * until then, only two kinds of simple expressions are supported:\n * {[ index ]} and {{ arguments }}.\n */\n var rv = {};\n for (var prop in data) {\n var str = data[prop];\n str = substIndexes(str, args, key, prop);\n str = substArguments(str, args, key);\n rv[prop] = str;\n }\n return rv;\n }\n\n // replace {[macros]} with their values\n function substIndexes(str, args, key, prop) {\n var reIndex = /\\{\\[\\s*([a-zA-Z]+)\\(([a-zA-Z]+)\\)\\s*\\]\\}/;\n var reMatch = reIndex.exec(str);\n if (!reMatch || !reMatch.length)\n return str;\n\n // an index/macro has been found\n // Note: at the moment, only one parameter is supported\n var macroName = reMatch[1];\n var paramName = reMatch[2];\n var param;\n if (args && paramName in args) {\n param = args[paramName];\n } else if (paramName in gL10nData) {\n param = gL10nData[paramName];\n }\n\n // there's no macro parser yet: it has to be defined in gMacros\n if (macroName in gMacros) {\n var macro = gMacros[macroName];\n str = macro(str, param, key, prop);\n }\n return str;\n }\n\n // replace {{arguments}} with their values\n function substArguments(str, args, key) {\n var reArgs = /\\{\\{\\s*(.+?)\\s*\\}\\}/g;\n return str.replace(reArgs, function(matched_text, arg) {\n if (args && arg in args) {\n return args[arg];\n }\n if (arg in gL10nData) {\n return gL10nData[arg];\n }\n console.log('argument {{' + arg + '}} for #' + key + ' is undefined.');\n return matched_text;\n });\n }\n\n // translate an HTML element\n function translateElement(element) {\n var l10n = getL10nAttributes(element);\n if (!l10n.id)\n return;\n\n // get the related l10n object\n var data = getL10nData(l10n.id, l10n.args);\n if (!data) {\n console.warn('#' + l10n.id + ' is undefined.');\n return;\n }\n\n // translate element (TODO: security checks?)\n if (data[gTextProp]) { // XXX\n if (getChildElementCount(element) === 0) {\n element[gTextProp] = data[gTextProp];\n } else {\n // this element has element children: replace the content of the first\n // (non-empty) child textNode and clear other child textNodes\n var children = element.childNodes;\n var found = false;\n for (var i = 0, l = children.length; i < l; i++) {\n if (children[i].nodeType === 3 && /\\S/.test(children[i].nodeValue)) {\n if (found) {\n children[i].nodeValue = '';\n } else {\n children[i].nodeValue = data[gTextProp];\n found = true;\n }\n }\n }\n // if no (non-empty) textNode is found, insert a textNode before the\n // first element child.\n if (!found) {\n var textNode = document.createTextNode(data[gTextProp]);\n element.insertBefore(textNode, element.firstChild);\n }\n }\n delete data[gTextProp];\n }\n\n for (var k in data) {\n element[k] = data[k];\n }\n }\n\n // webkit browsers don't currently support 'children' on SVG elements...\n function getChildElementCount(element) {\n if (element.children) {\n return element.children.length;\n }\n if (typeof element.childElementCount !== 'undefined') {\n return element.childElementCount;\n }\n var count = 0;\n for (var i = 0; i < element.childNodes.length; i++) {\n count += element.nodeType === 1 ? 1 : 0;\n }\n return count;\n }\n\n // translate an HTML subtree\n function translateFragment(element) {\n element = element || document.documentElement;\n\n // check all translatable children (= w/ a `data-l10n-id' attribute)\n var children = getTranslatableChildren(element);\n var elementCount = children.length;\n for (var i = 0; i < elementCount; i++) {\n translateElement(children[i]);\n }\n\n // translate element itself if necessary\n translateElement(element);\n }\n\n return {\n // get a localized string\n get: function(key, args, fallbackString) {\n var index = key.lastIndexOf('.');\n var prop = gTextProp;\n if (index > 0) { // An attribute has been specified\n prop = key.substr(index + 1);\n key = key.substring(0, index);\n }\n var fallback;\n if (fallbackString) {\n fallback = {};\n fallback[prop] = fallbackString;\n }\n var data = getL10nData(key, args, fallback);\n if (data && prop in data) {\n return data[prop];\n }\n return '{{' + key + '}}';\n },\n\n // debug\n getData: function() { return gL10nData; },\n getText: function() { return gTextData; },\n\n // get|set the document language\n getLanguage: function() { return gLanguage; },\n setLanguage: function(lang, callback) {\n loadLocale(lang, function() {\n if (callback)\n callback();\n });\n },\n\n // get the direction (ltr|rtl) of the current language\n getDirection: function() {\n // http://www.w3.org/International/questions/qa-scripts\n // Arabic, Hebrew, Farsi, Pashto, Urdu\n var rtlList = ['ar', 'he', 'fa', 'ps', 'ur'];\n var shortCode = gLanguage.split('-', 1)[0];\n return (rtlList.indexOf(shortCode) >= 0) ? 'rtl' : 'ltr';\n },\n\n // translate an element or document fragment\n translate: translateFragment,\n\n // this can be used to prevent race conditions\n getReadyState: function() { return gReadyState; },\n ready: function(callback) {\n if (!callback) {\n return;\n } else if (gReadyState == 'complete' || gReadyState == 'interactive') {\n window.setTimeout(function() {\n callback();\n });\n } else if (document.addEventListener) {\n document.addEventListener('localized', function once() {\n document.removeEventListener('localized', once);\n callback();\n });\n }\n }\n };\n}) (window, document);\n\n\n\n// WEBPACK FOOTER //\n// external/webL10n/l10n.js", + "/* Copyright 2014 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AnnotationLayer } from 'pdfjs-lib';\nimport { NullL10n } from './ui_utils';\nimport { SimpleLinkService } from './pdf_link_service';\n\n/**\n * @typedef {Object} AnnotationLayerBuilderOptions\n * @property {HTMLDivElement} pageDiv\n * @property {PDFPage} pdfPage\n * @property {boolean} renderInteractiveForms\n * @property {IPDFLinkService} linkService\n * @property {DownloadManager} downloadManager\n * @property {IL10n} l10n - Localization service.\n */\n\nclass AnnotationLayerBuilder {\n /**\n * @param {AnnotationLayerBuilderOptions} options\n */\n constructor({ pageDiv, pdfPage, linkService, downloadManager,\n renderInteractiveForms = false, l10n = NullL10n, }) {\n this.pageDiv = pageDiv;\n this.pdfPage = pdfPage;\n this.linkService = linkService;\n this.downloadManager = downloadManager;\n this.renderInteractiveForms = renderInteractiveForms;\n this.l10n = l10n;\n\n this.div = null;\n }\n\n /**\n * @param {PageViewport} viewport\n * @param {string} intent (default value is 'display')\n */\n render(viewport, intent = 'display') {\n this.pdfPage.getAnnotations({ intent, }).then((annotations) => {\n let parameters = {\n viewport: viewport.clone({ dontFlip: true, }),\n div: this.div,\n annotations,\n page: this.pdfPage,\n renderInteractiveForms: this.renderInteractiveForms,\n linkService: this.linkService,\n downloadManager: this.downloadManager,\n };\n\n if (this.div) {\n // If an annotationLayer already exists, refresh its children's\n // transformation matrices.\n AnnotationLayer.update(parameters);\n } else {\n // Create an annotation layer div and render the annotations\n // if there is at least one annotation.\n if (annotations.length === 0) {\n return;\n }\n this.div = document.createElement('div');\n this.div.className = 'annotationLayer';\n this.pageDiv.appendChild(this.div);\n parameters.div = this.div;\n\n AnnotationLayer.render(parameters);\n this.l10n.translate(this.div);\n }\n });\n }\n\n hide() {\n if (!this.div) {\n return;\n }\n this.div.setAttribute('hidden', 'true');\n }\n}\n\n/**\n * @implements IPDFAnnotationLayerFactory\n */\nclass DefaultAnnotationLayerFactory {\n /**\n * @param {HTMLDivElement} pageDiv\n * @param {PDFPage} pdfPage\n * @param {boolean} renderInteractiveForms\n * @param {IL10n} l10n\n * @returns {AnnotationLayerBuilder}\n */\n createAnnotationLayerBuilder(pageDiv, pdfPage, renderInteractiveForms = false,\n l10n = NullL10n) {\n return new AnnotationLayerBuilder({\n pageDiv,\n pdfPage,\n renderInteractiveForms,\n linkService: new SimpleLinkService(),\n l10n,\n });\n }\n}\n\nexport {\n AnnotationLayerBuilder,\n DefaultAnnotationLayerFactory,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/annotation_layer_builder.js", + "/* Copyright 2013 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createObjectURL, createValidAbsoluteUrl, PDFJS } from 'pdfjs-lib';\n\nif (typeof PDFJSDev !== 'undefined' && !PDFJSDev.test('CHROME || GENERIC')) {\n throw new Error('Module \"pdfjs-web/download_manager\" shall not be used ' +\n 'outside CHROME and GENERIC builds.');\n}\n\nfunction download(blobUrl, filename) {\n let a = document.createElement('a');\n if (a.click) {\n // Use a.click() if available. Otherwise, Chrome might show\n // \"Unsafe JavaScript attempt to initiate a navigation change\n // for frame with URL\" and not open the PDF at all.\n // Supported by (not mentioned = untested):\n // - Firefox 6 - 19 (4- does not support a.click, 5 ignores a.click)\n // - Chrome 19 - 26 (18- does not support a.click)\n // - Opera 9 - 12.15\n // - Internet Explorer 6 - 10\n // - Safari 6 (5.1- does not support a.click)\n a.href = blobUrl;\n a.target = '_parent';\n // Use a.download if available. This increases the likelihood that\n // the file is downloaded instead of opened by another PDF plugin.\n if ('download' in a) {\n a.download = filename;\n }\n // must be in the document for IE and recent Firefox versions.\n // (otherwise .click() is ignored)\n (document.body || document.documentElement).appendChild(a);\n a.click();\n a.parentNode.removeChild(a);\n } else {\n if (window.top === window &&\n blobUrl.split('#')[0] === window.location.href.split('#')[0]) {\n // If _parent == self, then opening an identical URL with different\n // location hash will only cause a navigation, not a download.\n let padCharacter = blobUrl.indexOf('?') === -1 ? '?' : '&';\n blobUrl = blobUrl.replace(/#|$/, padCharacter + '$&');\n }\n window.open(blobUrl, '_parent');\n }\n}\n\nclass DownloadManager {\n downloadUrl(url, filename) {\n if (!createValidAbsoluteUrl(url, 'http://example.com')) {\n return; // restricted/invalid URL\n }\n download(url + '#pdfjs.action=download', filename);\n }\n\n downloadData(data, filename, contentType) {\n if (navigator.msSaveBlob) { // IE10 and above\n return navigator.msSaveBlob(new Blob([data], { type: contentType, }),\n filename);\n }\n let blobUrl = createObjectURL(data, contentType,\n PDFJS.disableCreateObjectURL);\n download(blobUrl, filename);\n }\n\n download(blob, url, filename) {\n if (navigator.msSaveBlob) {\n // IE10 / IE11\n if (!navigator.msSaveBlob(blob, filename)) {\n this.downloadUrl(url, filename);\n }\n return;\n }\n\n if (PDFJS.disableCreateObjectURL) {\n // URL.createObjectURL is not supported\n this.downloadUrl(url, filename);\n return;\n }\n\n let blobUrl = URL.createObjectURL(blob);\n download(blobUrl, filename);\n }\n}\n\nexport {\n DownloadManager,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/download_manager.js", + "/* Copyright 2017 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport '../external/webL10n/l10n';\n\nvar webL10n = document.webL10n;\n\nclass GenericL10n {\n constructor(lang) {\n this._lang = lang;\n this._ready = new Promise((resolve, reject) => {\n webL10n.setLanguage(lang, () => {\n resolve(webL10n);\n });\n });\n }\n\n getDirection() {\n return this._ready.then((l10n) => {\n return l10n.getDirection();\n });\n }\n\n get(property, args, fallback) {\n return this._ready.then((l10n) => {\n return l10n.get(property, args, fallback);\n });\n }\n\n translate(element) {\n return this._ready.then((l10n) => {\n return l10n.translate(element);\n });\n }\n}\n\nexport {\n GenericL10n,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/genericl10n.js", + "/* Copyright 2013 Rob Wu \n * https://github.com/Rob--W/grab-to-pan.js\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Construct a GrabToPan instance for a given HTML element.\n * @param options.element {Element}\n * @param options.ignoreTarget {function} optional. See `ignoreTarget(node)`\n * @param options.onActiveChanged {function(boolean)} optional. Called\n * when grab-to-pan is (de)activated. The first argument is a boolean that\n * shows whether grab-to-pan is activated.\n */\nfunction GrabToPan(options) {\n this.element = options.element;\n this.document = options.element.ownerDocument;\n if (typeof options.ignoreTarget === 'function') {\n this.ignoreTarget = options.ignoreTarget;\n }\n this.onActiveChanged = options.onActiveChanged;\n\n // Bind the contexts to ensure that `this` always points to\n // the GrabToPan instance.\n this.activate = this.activate.bind(this);\n this.deactivate = this.deactivate.bind(this);\n this.toggle = this.toggle.bind(this);\n this._onmousedown = this._onmousedown.bind(this);\n this._onmousemove = this._onmousemove.bind(this);\n this._endPan = this._endPan.bind(this);\n\n // This overlay will be inserted in the document when the mouse moves during\n // a grab operation, to ensure that the cursor has the desired appearance.\n var overlay = this.overlay = document.createElement('div');\n overlay.className = 'grab-to-pan-grabbing';\n}\nGrabToPan.prototype = {\n /**\n * Class name of element which can be grabbed\n */\n CSS_CLASS_GRAB: 'grab-to-pan-grab',\n\n /**\n * Bind a mousedown event to the element to enable grab-detection.\n */\n activate: function GrabToPan_activate() {\n if (!this.active) {\n this.active = true;\n this.element.addEventListener('mousedown', this._onmousedown, true);\n this.element.classList.add(this.CSS_CLASS_GRAB);\n if (this.onActiveChanged) {\n this.onActiveChanged(true);\n }\n }\n },\n\n /**\n * Removes all events. Any pending pan session is immediately stopped.\n */\n deactivate: function GrabToPan_deactivate() {\n if (this.active) {\n this.active = false;\n this.element.removeEventListener('mousedown', this._onmousedown, true);\n this._endPan();\n this.element.classList.remove(this.CSS_CLASS_GRAB);\n if (this.onActiveChanged) {\n this.onActiveChanged(false);\n }\n }\n },\n\n toggle: function GrabToPan_toggle() {\n if (this.active) {\n this.deactivate();\n } else {\n this.activate();\n }\n },\n\n /**\n * Whether to not pan if the target element is clicked.\n * Override this method to change the default behaviour.\n *\n * @param node {Element} The target of the event\n * @return {boolean} Whether to not react to the click event.\n */\n ignoreTarget: function GrabToPan_ignoreTarget(node) {\n // Use matchesSelector to check whether the clicked element\n // is (a child of) an input element / link\n return node[matchesSelector](\n 'a[href], a[href] *, input, textarea, button, button *, select, option'\n );\n },\n\n /**\n * @private\n */\n _onmousedown: function GrabToPan__onmousedown(event) {\n if (event.button !== 0 || this.ignoreTarget(event.target)) {\n return;\n }\n if (event.originalTarget) {\n try {\n // eslint-disable-next-line no-unused-expressions\n event.originalTarget.tagName;\n } catch (e) {\n // Mozilla-specific: element is a scrollbar (XUL element)\n return;\n }\n }\n\n this.scrollLeftStart = this.element.scrollLeft;\n this.scrollTopStart = this.element.scrollTop;\n this.clientXStart = event.clientX;\n this.clientYStart = event.clientY;\n this.document.addEventListener('mousemove', this._onmousemove, true);\n this.document.addEventListener('mouseup', this._endPan, true);\n // When a scroll event occurs before a mousemove, assume that the user\n // dragged a scrollbar (necessary for Opera Presto, Safari and IE)\n // (not needed for Chrome/Firefox)\n this.element.addEventListener('scroll', this._endPan, true);\n event.preventDefault();\n event.stopPropagation();\n\n var focusedElement = document.activeElement;\n if (focusedElement && !focusedElement.contains(event.target)) {\n focusedElement.blur();\n }\n },\n\n /**\n * @private\n */\n _onmousemove: function GrabToPan__onmousemove(event) {\n this.element.removeEventListener('scroll', this._endPan, true);\n if (isLeftMouseReleased(event)) {\n this._endPan();\n return;\n }\n var xDiff = event.clientX - this.clientXStart;\n var yDiff = event.clientY - this.clientYStart;\n var scrollTop = this.scrollTopStart - yDiff;\n var scrollLeft = this.scrollLeftStart - xDiff;\n if (this.element.scrollTo) {\n this.element.scrollTo({\n top: scrollTop,\n left: scrollLeft,\n behavior: 'instant',\n });\n } else {\n this.element.scrollTop = scrollTop;\n this.element.scrollLeft = scrollLeft;\n }\n if (!this.overlay.parentNode) {\n document.body.appendChild(this.overlay);\n }\n },\n\n /**\n * @private\n */\n _endPan: function GrabToPan__endPan() {\n this.element.removeEventListener('scroll', this._endPan, true);\n this.document.removeEventListener('mousemove', this._onmousemove, true);\n this.document.removeEventListener('mouseup', this._endPan, true);\n // Note: ChildNode.remove doesn't throw if the parentNode is undefined.\n this.overlay.remove();\n },\n};\n\n// Get the correct (vendor-prefixed) name of the matches method.\nvar matchesSelector;\n['webkitM', 'mozM', 'msM', 'oM', 'm'].some(function(prefix) {\n var name = prefix + 'atches';\n if (name in document.documentElement) {\n matchesSelector = name;\n }\n name += 'Selector';\n if (name in document.documentElement) {\n matchesSelector = name;\n }\n return matchesSelector; // If found, then truthy, and [].some() ends.\n});\n\n// Browser sniffing because it's impossible to feature-detect\n// whether event.which for onmousemove is reliable\nvar isNotIEorIsIE10plus = !document.documentMode || document.documentMode > 9;\nvar chrome = window.chrome;\nvar isChrome15OrOpera15plus = chrome && (chrome.webstore || chrome.app);\n// ^ Chrome 15+ ^ Opera 15+\nvar isSafari6plus = /Apple/.test(navigator.vendor) &&\n /Version\\/([6-9]\\d*|[1-5]\\d+)/.test(navigator.userAgent);\n\n/**\n * Whether the left mouse is not pressed.\n * @param event {MouseEvent}\n * @return {boolean} True if the left mouse button is not pressed.\n * False if unsure or if the left mouse button is pressed.\n */\nfunction isLeftMouseReleased(event) {\n if ('buttons' in event && isNotIEorIsIE10plus) {\n // http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-buttons\n // Firefox 15+\n // Internet Explorer 10+\n return !(event.buttons & 1);\n }\n if (isChrome15OrOpera15plus || isSafari6plus) {\n // Chrome 14+\n // Opera 15+\n // Safari 6.0+\n return event.which === 0;\n }\n}\n\nexport {\n GrabToPan,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/grab_to_pan.js", + "/* Copyright 2014 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nclass OverlayManager {\n constructor() {\n this._overlays = {};\n this._active = null;\n this._keyDownBound = this._keyDown.bind(this);\n }\n\n get active() {\n return this._active;\n }\n\n /**\n * @param {string} name - The name of the overlay that is registered.\n * @param {HTMLDivElement} element - The overlay's DOM element.\n * @param {function} callerCloseMethod - (optional) The method that, if\n * present, calls `OverlayManager.close` from the object\n * registering the overlay. Access to this method is\n * necessary in order to run cleanup code when e.g.\n * the overlay is force closed. The default is `null`.\n * @param {boolean} canForceClose - (optional) Indicates if opening the\n * overlay closes an active overlay. The default is `false`.\n * @returns {Promise} A promise that is resolved when the overlay has been\n * registered.\n */\n register(name, element, callerCloseMethod = null, canForceClose = false) {\n return new Promise((resolve) => {\n let container;\n if (!name || !element || !(container = element.parentNode)) {\n throw new Error('Not enough parameters.');\n } else if (this._overlays[name]) {\n throw new Error('The overlay is already registered.');\n }\n this._overlays[name] = {\n element,\n container,\n callerCloseMethod,\n canForceClose,\n };\n resolve();\n });\n }\n\n /**\n * @param {string} name - The name of the overlay that is unregistered.\n * @returns {Promise} A promise that is resolved when the overlay has been\n * unregistered.\n */\n unregister(name) {\n return new Promise((resolve) => {\n if (!this._overlays[name]) {\n throw new Error('The overlay does not exist.');\n } else if (this._active === name) {\n throw new Error('The overlay cannot be removed while it is active.');\n }\n delete this._overlays[name];\n resolve();\n });\n }\n\n /**\n * @param {string} name - The name of the overlay that should be opened.\n * @returns {Promise} A promise that is resolved when the overlay has been\n * opened.\n */\n open(name) {\n return new Promise((resolve) => {\n if (!this._overlays[name]) {\n throw new Error('The overlay does not exist.');\n } else if (this._active) {\n if (this._overlays[name].canForceClose) {\n this._closeThroughCaller();\n } else if (this._active === name) {\n throw new Error('The overlay is already active.');\n } else {\n throw new Error('Another overlay is currently active.');\n }\n }\n this._active = name;\n this._overlays[this._active].element.classList.remove('hidden');\n this._overlays[this._active].container.classList.remove('hidden');\n\n window.addEventListener('keydown', this._keyDownBound);\n resolve();\n });\n }\n\n /**\n * @param {string} name - The name of the overlay that should be closed.\n * @returns {Promise} A promise that is resolved when the overlay has been\n * closed.\n */\n close(name) {\n return new Promise((resolve) => {\n if (!this._overlays[name]) {\n throw new Error('The overlay does not exist.');\n } else if (!this._active) {\n throw new Error('The overlay is currently not active.');\n } else if (this._active !== name) {\n throw new Error('Another overlay is currently active.');\n }\n this._overlays[this._active].container.classList.add('hidden');\n this._overlays[this._active].element.classList.add('hidden');\n this._active = null;\n\n window.removeEventListener('keydown', this._keyDownBound);\n resolve();\n });\n }\n\n /**\n * @private\n */\n _keyDown(evt) {\n if (this._active && evt.keyCode === 27) { // Esc key.\n this._closeThroughCaller();\n evt.preventDefault();\n }\n }\n\n /**\n * @private\n */\n _closeThroughCaller() {\n if (this._overlays[this._active].callerCloseMethod) {\n this._overlays[this._active].callerCloseMethod();\n }\n if (this._active) {\n this.close(this._active);\n }\n }\n}\n\nexport {\n OverlayManager,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/overlay_manager.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { NullL10n } from './ui_utils';\nimport { PasswordResponses } from 'pdfjs-lib';\n\n/**\n * @typedef {Object} PasswordPromptOptions\n * @property {string} overlayName - Name of the overlay for the overlay manager.\n * @property {HTMLDivElement} container - Div container for the overlay.\n * @property {HTMLParagraphElement} label - Label containing instructions for\n * entering the password.\n * @property {HTMLInputElement} input - Input field for entering the password.\n * @property {HTMLButtonElement} submitButton - Button for submitting the\n * password.\n * @property {HTMLButtonElement} cancelButton - Button for cancelling password\n * entry.\n */\n\nclass PasswordPrompt {\n /**\n * @param {PasswordPromptOptions} options\n * @param {OverlayManager} overlayManager - Manager for the viewer overlays.\n * @param {IL10n} l10n - Localization service.\n */\n constructor(options, overlayManager, l10n = NullL10n) {\n this.overlayName = options.overlayName;\n this.container = options.container;\n this.label = options.label;\n this.input = options.input;\n this.submitButton = options.submitButton;\n this.cancelButton = options.cancelButton;\n this.overlayManager = overlayManager;\n this.l10n = l10n;\n\n this.updateCallback = null;\n this.reason = null;\n\n // Attach the event listeners.\n this.submitButton.addEventListener('click', this.verify.bind(this));\n this.cancelButton.addEventListener('click', this.close.bind(this));\n this.input.addEventListener('keydown', (e) => {\n if (e.keyCode === 13) { // Enter key\n this.verify();\n }\n });\n\n this.overlayManager.register(this.overlayName, this.container,\n this.close.bind(this), true);\n }\n\n open() {\n this.overlayManager.open(this.overlayName).then(() => {\n this.input.focus();\n\n let promptString;\n if (this.reason === PasswordResponses.INCORRECT_PASSWORD) {\n promptString = this.l10n.get('password_invalid', null,\n 'Invalid password. Please try again.');\n } else {\n promptString = this.l10n.get('password_label', null,\n 'Enter the password to open this PDF file.');\n }\n\n promptString.then((msg) => {\n this.label.textContent = msg;\n });\n });\n }\n\n close() {\n this.overlayManager.close(this.overlayName).then(() => {\n this.input.value = '';\n });\n }\n\n verify() {\n let password = this.input.value;\n if (password && password.length > 0) {\n this.close();\n return this.updateCallback(password);\n }\n }\n\n setUpdateCallback(updateCallback, reason) {\n this.updateCallback = updateCallback;\n this.reason = reason;\n }\n}\n\nexport {\n PasswordPrompt,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/password_prompt.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createObjectURL, createPromiseCapability, getFilenameFromUrl, PDFJS,\n removeNullCharacters\n} from 'pdfjs-lib';\n\n/**\n * @typedef {Object} PDFAttachmentViewerOptions\n * @property {HTMLDivElement} container - The viewer element.\n * @property {EventBus} eventBus - The application event bus.\n * @property {DownloadManager} downloadManager - The download manager.\n */\n\n/**\n * @typedef {Object} PDFAttachmentViewerRenderParameters\n * @property {Object|null} attachments - A lookup table of attachment objects.\n */\n\nclass PDFAttachmentViewer {\n /**\n * @param {PDFAttachmentViewerOptions} options\n */\n constructor({ container, eventBus, downloadManager, }) {\n this.attachments = null;\n\n this.container = container;\n this.eventBus = eventBus;\n this.downloadManager = downloadManager;\n\n this._renderedCapability = createPromiseCapability();\n this.eventBus.on('fileattachmentannotation',\n this._appendAttachment.bind(this));\n }\n\n reset(keepRenderedCapability = false) {\n this.attachments = null;\n\n // Remove the attachments from the DOM.\n this.container.textContent = '';\n\n if (!keepRenderedCapability) {\n // NOTE: The *only* situation in which the `_renderedCapability` should\n // not be replaced is when appending file attachment annotations.\n this._renderedCapability = createPromiseCapability();\n }\n }\n\n /**\n * @private\n */\n _dispatchEvent(attachmentsCount) {\n this.eventBus.dispatch('attachmentsloaded', {\n source: this,\n attachmentsCount,\n });\n\n this._renderedCapability.resolve();\n }\n\n /**\n * @private\n */\n _bindPdfLink(button, content, filename) {\n if (PDFJS.disableCreateObjectURL) {\n throw new Error('bindPdfLink: ' +\n 'Unsupported \"PDFJS.disableCreateObjectURL\" value.');\n }\n let blobUrl;\n button.onclick = function() {\n if (!blobUrl) {\n blobUrl = createObjectURL(content, 'application/pdf');\n }\n let viewerUrl;\n if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {\n // The current URL is the viewer, let's use it and append the file.\n viewerUrl = '?file=' + encodeURIComponent(blobUrl + '#' + filename);\n } else if (PDFJSDev.test('CHROME')) {\n // In the Chrome extension, the URL is rewritten using the history API\n // in viewer.js, so an absolute URL must be generated.\n // eslint-disable-next-line no-undef\n viewerUrl = chrome.runtime.getURL('/content/web/viewer.html') +\n '?file=' + encodeURIComponent(blobUrl + '#' + filename);\n } else if (PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n // Let Firefox's content handler catch the URL and display the PDF.\n viewerUrl = blobUrl + '?' + encodeURIComponent(filename);\n }\n window.open(viewerUrl);\n return false;\n };\n }\n\n /**\n * @private\n */\n _bindLink(button, content, filename) {\n button.onclick = () => {\n this.downloadManager.downloadData(content, filename, '');\n return false;\n };\n }\n\n /**\n * @param {PDFAttachmentViewerRenderParameters} params\n */\n render({ attachments, keepRenderedCapability = false, }) {\n let attachmentsCount = 0;\n\n if (this.attachments) {\n this.reset(keepRenderedCapability === true);\n }\n this.attachments = attachments || null;\n\n if (!attachments) {\n this._dispatchEvent(attachmentsCount);\n return;\n }\n\n let names = Object.keys(attachments).sort(function(a, b) {\n return a.toLowerCase().localeCompare(b.toLowerCase());\n });\n attachmentsCount = names.length;\n\n for (let i = 0; i < attachmentsCount; i++) {\n let item = attachments[names[i]];\n let filename = removeNullCharacters(getFilenameFromUrl(item.filename));\n\n let div = document.createElement('div');\n div.className = 'attachmentsItem';\n let button = document.createElement('button');\n button.textContent = filename;\n if (/\\.pdf$/i.test(filename) && !PDFJS.disableCreateObjectURL) {\n this._bindPdfLink(button, item.content, filename);\n } else {\n this._bindLink(button, item.content, filename);\n }\n\n div.appendChild(button);\n this.container.appendChild(div);\n }\n\n this._dispatchEvent(attachmentsCount);\n }\n\n /**\n * Used to append FileAttachment annotations to the sidebar.\n * @private\n */\n _appendAttachment({ id, filename, content, }) {\n this._renderedCapability.promise.then(() => {\n let attachments = this.attachments;\n\n if (!attachments) {\n attachments = Object.create(null);\n } else {\n for (let name in attachments) {\n if (id === name) {\n return; // Ignore the new attachment if it already exists.\n }\n }\n }\n attachments[id] = {\n filename,\n content,\n };\n this.render({\n attachments,\n keepRenderedCapability: true,\n });\n });\n }\n}\n\nexport {\n PDFAttachmentViewer,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/pdf_attachment_viewer.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { cloneObj, getPDFFileNameFromURL, NullL10n } from './ui_utils';\nimport { createPromiseCapability } from 'pdfjs-lib';\n\nconst DEFAULT_FIELD_CONTENT = '-';\n\n/**\n * @typedef {Object} PDFDocumentPropertiesOptions\n * @property {string} overlayName - Name/identifier for the overlay.\n * @property {Object} fields - Names and elements of the overlay's fields.\n * @property {HTMLDivElement} container - Div container for the overlay.\n * @property {HTMLButtonElement} closeButton - Button for closing the overlay.\n */\n\nclass PDFDocumentProperties {\n /**\n * @param {PDFDocumentPropertiesOptions} options\n * @param {OverlayManager} overlayManager - Manager for the viewer overlays.\n * @param {IL10n} l10n - Localization service.\n */\n constructor({ overlayName, fields, container, closeButton, },\n overlayManager, l10n = NullL10n) {\n this.overlayName = overlayName;\n this.fields = fields;\n this.container = container;\n this.overlayManager = overlayManager;\n this.l10n = l10n;\n\n this._reset();\n\n if (closeButton) { // Bind the event listener for the Close button.\n closeButton.addEventListener('click', this.close.bind(this));\n }\n this.overlayManager.register(this.overlayName, this.container,\n this.close.bind(this));\n }\n\n /**\n * Open the document properties overlay.\n */\n open() {\n let freezeFieldData = (data) => {\n Object.defineProperty(this, 'fieldData', {\n value: Object.freeze(data),\n writable: false,\n enumerable: true,\n configurable: true,\n });\n };\n\n Promise.all([this.overlayManager.open(this.overlayName),\n this._dataAvailableCapability.promise]).then(() => {\n // If the document properties were previously fetched (for this PDF file),\n // just update the dialog immediately to avoid redundant lookups.\n if (this.fieldData) {\n this._updateUI();\n return;\n }\n // Get the document properties.\n this.pdfDocument.getMetadata().then(({ info, metadata, }) => {\n return Promise.all([\n info,\n metadata,\n this._parseFileSize(this.maybeFileSize),\n this._parseDate(info.CreationDate),\n this._parseDate(info.ModDate)\n ]);\n }).then(([info, metadata, fileSize, creationDate, modificationDate]) => {\n freezeFieldData({\n 'fileName': getPDFFileNameFromURL(this.url),\n 'fileSize': fileSize,\n 'title': info.Title,\n 'author': info.Author,\n 'subject': info.Subject,\n 'keywords': info.Keywords,\n 'creationDate': creationDate,\n 'modificationDate': modificationDate,\n 'creator': info.Creator,\n 'producer': info.Producer,\n 'version': info.PDFFormatVersion,\n 'pageCount': this.pdfDocument.numPages,\n });\n this._updateUI();\n\n // Get the correct fileSize, since it may not have been set (if\n // `this.setFileSize` wasn't called) or may be incorrectly set.\n return this.pdfDocument.getDownloadInfo();\n }).then(({ length, }) => {\n return this._parseFileSize(length);\n }).then((fileSize) => {\n let data = cloneObj(this.fieldData);\n data['fileSize'] = fileSize;\n\n freezeFieldData(data);\n this._updateUI();\n });\n });\n }\n\n /**\n * Close the document properties overlay.\n */\n close() {\n this.overlayManager.close(this.overlayName);\n }\n\n /**\n * Set a reference to the PDF document and the URL in order\n * to populate the overlay fields with the document properties.\n * Note that the overlay will contain no information if this method\n * is not called.\n *\n * @param {Object} pdfDocument - A reference to the PDF document.\n * @param {string} url - The URL of the document.\n */\n setDocument(pdfDocument, url) {\n if (this.pdfDocument) {\n this._reset();\n this._updateUI(true);\n }\n if (!pdfDocument) {\n return;\n }\n this.pdfDocument = pdfDocument;\n this.url = url;\n\n this._dataAvailableCapability.resolve();\n }\n\n /**\n * Set the file size of the PDF document. This method is used to\n * update the file size in the document properties overlay once it\n * is known so we do not have to wait until the entire file is loaded.\n *\n * @param {number} fileSize - The file size of the PDF document.\n */\n setFileSize(fileSize) {\n if (typeof fileSize === 'number' && fileSize > 0) {\n this.maybeFileSize = fileSize;\n }\n }\n\n /**\n * @private\n */\n _reset() {\n this.pdfDocument = null;\n this.url = null;\n\n this.maybeFileSize = 0;\n delete this.fieldData;\n this._dataAvailableCapability = createPromiseCapability();\n }\n\n /**\n * Always updates all of the dialog fields, to prevent inconsistent UI state.\n * NOTE: If the contents of a particular field is neither a non-empty string,\n * nor a number, it will fall back to `DEFAULT_FIELD_CONTENT`.\n * @private\n */\n _updateUI(reset = false) {\n if (reset || !this.fieldData) {\n for (let id in this.fields) {\n this.fields[id].textContent = DEFAULT_FIELD_CONTENT;\n }\n return;\n }\n if (this.overlayManager.active !== this.overlayName) {\n // Don't bother updating the dialog if has already been closed,\n // since it will be updated the next time `this.open` is called.\n return;\n }\n for (let id in this.fields) {\n let content = this.fieldData[id];\n this.fields[id].textContent = (content || content === 0) ?\n content : DEFAULT_FIELD_CONTENT;\n }\n }\n\n /**\n * @private\n */\n _parseFileSize(fileSize = 0) {\n let kb = fileSize / 1024;\n if (!kb) {\n return Promise.resolve(undefined);\n } else if (kb < 1024) {\n return this.l10n.get('document_properties_kb', {\n size_kb: (+kb.toPrecision(3)).toLocaleString(),\n size_b: fileSize.toLocaleString(),\n }, '{{size_kb}} KB ({{size_b}} bytes)');\n }\n return this.l10n.get('document_properties_mb', {\n size_mb: (+(kb / 1024).toPrecision(3)).toLocaleString(),\n size_b: fileSize.toLocaleString(),\n }, '{{size_mb}} MB ({{size_b}} bytes)');\n }\n\n /**\n * @private\n */\n _parseDate(inputDate) {\n if (!inputDate) {\n return;\n }\n // This is implemented according to the PDF specification, but note that\n // Adobe Reader doesn't handle changing the date to universal time\n // and doesn't use the user's time zone (they're effectively ignoring\n // the HH' and mm' parts of the date string).\n let dateToParse = inputDate;\n\n // Remove the D: prefix if it is available.\n if (dateToParse.substring(0, 2) === 'D:') {\n dateToParse = dateToParse.substring(2);\n }\n\n // Get all elements from the PDF date string.\n // JavaScript's `Date` object expects the month to be between\n // 0 and 11 instead of 1 and 12, so we're correcting for this.\n let year = parseInt(dateToParse.substring(0, 4), 10);\n let month = parseInt(dateToParse.substring(4, 6), 10) - 1;\n let day = parseInt(dateToParse.substring(6, 8), 10);\n let hours = parseInt(dateToParse.substring(8, 10), 10);\n let minutes = parseInt(dateToParse.substring(10, 12), 10);\n let seconds = parseInt(dateToParse.substring(12, 14), 10);\n let utRel = dateToParse.substring(14, 15);\n let offsetHours = parseInt(dateToParse.substring(15, 17), 10);\n let offsetMinutes = parseInt(dateToParse.substring(18, 20), 10);\n\n // As per spec, utRel = 'Z' means equal to universal time.\n // The other cases ('-' and '+') have to be handled here.\n if (utRel === '-') {\n hours += offsetHours;\n minutes += offsetMinutes;\n } else if (utRel === '+') {\n hours -= offsetHours;\n minutes -= offsetMinutes;\n }\n\n // Return the new date format from the user's locale.\n let date = new Date(Date.UTC(year, month, day, hours, minutes, seconds));\n let dateString = date.toLocaleDateString();\n let timeString = date.toLocaleTimeString();\n return this.l10n.get('document_properties_date_string',\n { date: dateString, time: timeString, },\n '{{date}}, {{time}}');\n }\n}\n\nexport {\n PDFDocumentProperties,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/pdf_document_properties.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FindState } from './pdf_find_controller';\nimport { NullL10n } from './ui_utils';\n\n/**\n * Creates a \"search bar\" given a set of DOM elements that act as controls\n * for searching or for setting search preferences in the UI. This object\n * also sets up the appropriate events for the controls. Actual searching\n * is done by PDFFindController.\n */\nclass PDFFindBar {\n constructor(options, l10n = NullL10n) {\n this.opened = false;\n\n this.bar = options.bar || null;\n this.toggleButton = options.toggleButton || null;\n this.findField = options.findField || null;\n this.highlightAll = options.highlightAllCheckbox || null;\n this.caseSensitive = options.caseSensitiveCheckbox || null;\n this.findMsg = options.findMsg || null;\n this.findResultsCount = options.findResultsCount || null;\n this.findStatusIcon = options.findStatusIcon || null;\n this.findPreviousButton = options.findPreviousButton || null;\n this.findNextButton = options.findNextButton || null;\n this.findController = options.findController || null;\n this.eventBus = options.eventBus;\n this.l10n = l10n;\n\n if (this.findController === null) {\n throw new Error('PDFFindBar cannot be used without a ' +\n 'PDFFindController instance.');\n }\n\n // Add event listeners to the DOM elements.\n this.toggleButton.addEventListener('click', () => {\n this.toggle();\n });\n\n this.findField.addEventListener('input', () => {\n this.dispatchEvent('');\n });\n\n this.bar.addEventListener('keydown', (e) => {\n switch (e.keyCode) {\n case 13: // Enter\n if (e.target === this.findField) {\n this.dispatchEvent('again', e.shiftKey);\n }\n break;\n case 27: // Escape\n this.close();\n break;\n }\n });\n\n this.findPreviousButton.addEventListener('click', () => {\n this.dispatchEvent('again', true);\n });\n\n this.findNextButton.addEventListener('click', () => {\n this.dispatchEvent('again', false);\n });\n\n this.highlightAll.addEventListener('click', () => {\n this.dispatchEvent('highlightallchange');\n });\n\n this.caseSensitive.addEventListener('click', () => {\n this.dispatchEvent('casesensitivitychange');\n });\n\n this.eventBus.on('resize', this._adjustWidth.bind(this));\n }\n\n reset() {\n this.updateUIState();\n }\n\n dispatchEvent(type, findPrev) {\n this.eventBus.dispatch('find', {\n source: this,\n type,\n query: this.findField.value,\n caseSensitive: this.caseSensitive.checked,\n phraseSearch: true,\n highlightAll: this.highlightAll.checked,\n findPrevious: findPrev,\n });\n }\n\n updateUIState(state, previous, matchCount) {\n let notFound = false;\n let findMsg = '';\n let status = '';\n\n switch (state) {\n case FindState.FOUND:\n break;\n\n case FindState.PENDING:\n status = 'pending';\n break;\n\n case FindState.NOT_FOUND:\n findMsg = this.l10n.get('find_not_found', null, 'Phrase not found');\n notFound = true;\n break;\n\n case FindState.WRAPPED:\n if (previous) {\n findMsg = this.l10n.get('find_reached_top', null,\n 'Reached top of document, continued from bottom');\n } else {\n findMsg = this.l10n.get('find_reached_bottom', null,\n 'Reached end of document, continued from top');\n }\n break;\n }\n\n if (notFound) {\n this.findField.classList.add('notFound');\n } else {\n this.findField.classList.remove('notFound');\n }\n\n this.findField.setAttribute('data-status', status);\n Promise.resolve(findMsg).then((msg) => {\n this.findMsg.textContent = msg;\n this._adjustWidth();\n });\n\n this.updateResultsCount(matchCount);\n }\n\n updateResultsCount(matchCount) {\n if (!this.findResultsCount) {\n return; // No UI control is provided.\n }\n\n if (!matchCount) {\n // If there are no matches, hide and reset the counter.\n this.findResultsCount.classList.add('hidden');\n this.findResultsCount.textContent = '';\n } else {\n // Update and show the match counter.\n this.findResultsCount.textContent = matchCount.toLocaleString();\n this.findResultsCount.classList.remove('hidden');\n }\n // Since `updateResultsCount` may be called from `PDFFindController`,\n // ensure that the width of the findbar is always updated correctly.\n this._adjustWidth();\n }\n\n open() {\n if (!this.opened) {\n this.opened = true;\n this.toggleButton.classList.add('toggled');\n this.bar.classList.remove('hidden');\n }\n this.findField.select();\n this.findField.focus();\n\n this._adjustWidth();\n }\n\n close() {\n if (!this.opened) {\n return;\n }\n this.opened = false;\n this.toggleButton.classList.remove('toggled');\n this.bar.classList.add('hidden');\n this.findController.active = false;\n }\n\n toggle() {\n if (this.opened) {\n this.close();\n } else {\n this.open();\n }\n }\n\n /**\n * @private\n */\n _adjustWidth() {\n if (!this.opened) {\n return;\n }\n\n // The find bar has an absolute position and thus the browser extends\n // its width to the maximum possible width once the find bar does not fit\n // entirely within the window anymore (and its elements are automatically\n // wrapped). Here we detect and fix that.\n this.bar.classList.remove('wrapContainers');\n\n let findbarHeight = this.bar.clientHeight;\n let inputContainerHeight = this.bar.firstElementChild.clientHeight;\n\n if (findbarHeight > inputContainerHeight) {\n // The findbar is taller than the input container, which means that\n // the browser wrapped some of the elements. For a consistent look,\n // wrap all of them to adjust the width of the find bar.\n this.bar.classList.add('wrapContainers');\n }\n }\n}\n\nexport {\n PDFFindBar,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/pdf_find_bar.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* globals chrome */\n\nimport { getGlobalEventBus } from './dom_events';\n\nfunction PDFHistory(options) {\n this.linkService = options.linkService;\n this.eventBus = options.eventBus || getGlobalEventBus();\n\n this.initialized = false;\n this.initialDestination = null;\n this.initialBookmark = null;\n}\n\nPDFHistory.prototype = {\n /**\n * @param {string} fingerprint\n */\n initialize: function pdfHistoryInitialize(fingerprint) {\n this.initialized = true;\n this.reInitialized = false;\n this.allowHashChange = true;\n this.historyUnlocked = true;\n this.isViewerInPresentationMode = false;\n\n this.previousHash = window.location.hash.substring(1);\n this.currentBookmark = '';\n this.currentPage = 0;\n this.updatePreviousBookmark = false;\n this.previousBookmark = '';\n this.previousPage = 0;\n this.nextHashParam = '';\n\n this.fingerprint = fingerprint;\n this.currentUid = this.uid = 0;\n this.current = {};\n\n var state = window.history.state;\n if (this._isStateObjectDefined(state)) {\n // This corresponds to navigating back to the document\n // from another page in the browser history.\n if (state.target.dest) {\n this.initialDestination = state.target.dest;\n } else {\n this.initialBookmark = state.target.hash;\n }\n this.currentUid = state.uid;\n this.uid = state.uid + 1;\n this.current = state.target;\n } else {\n // This corresponds to the loading of a new document.\n if (state && state.fingerprint &&\n this.fingerprint !== state.fingerprint) {\n // Reinitialize the browsing history when a new document\n // is opened in the web viewer.\n this.reInitialized = true;\n }\n this._pushOrReplaceState({ fingerprint: this.fingerprint, }, true);\n }\n\n var self = this;\n window.addEventListener('popstate', function pdfHistoryPopstate(evt) {\n if (!self.historyUnlocked) {\n return;\n }\n if (evt.state) {\n // Move back/forward in the history.\n self._goTo(evt.state);\n return;\n }\n\n // If the state is not set, then the user tried to navigate to a\n // different hash by manually editing the URL and pressing Enter, or by\n // clicking on an in-page link (e.g. the \"current view\" link).\n // Save the current view state to the browser history.\n\n // Note: In Firefox, history.null could also be null after an in-page\n // navigation to the same URL, and without dispatching the popstate\n // event: https://bugzilla.mozilla.org/show_bug.cgi?id=1183881\n\n if (self.uid === 0) {\n // Replace the previous state if it was not explicitly set.\n var previousParams = (self.previousHash && self.currentBookmark &&\n self.previousHash !== self.currentBookmark) ?\n { hash: self.currentBookmark, page: self.currentPage, } :\n { page: 1, };\n replacePreviousHistoryState(previousParams, function() {\n updateHistoryWithCurrentHash();\n });\n } else {\n updateHistoryWithCurrentHash();\n }\n });\n\n\n function updateHistoryWithCurrentHash() {\n self.previousHash = window.location.hash.slice(1);\n self._pushToHistory({ hash: self.previousHash, }, false, true);\n self._updatePreviousBookmark();\n }\n\n function replacePreviousHistoryState(params, callback) {\n // To modify the previous history entry, the following happens:\n // 1. history.back()\n // 2. _pushToHistory, which calls history.replaceState( ... )\n // 3. history.forward()\n // Because a navigation via the history API does not immediately update\n // the history state, the popstate event is used for synchronization.\n self.historyUnlocked = false;\n\n // Suppress the hashchange event to avoid side effects caused by\n // navigating back and forward.\n self.allowHashChange = false;\n window.addEventListener('popstate', rewriteHistoryAfterBack);\n history.back();\n\n function rewriteHistoryAfterBack() {\n window.removeEventListener('popstate', rewriteHistoryAfterBack);\n window.addEventListener('popstate', rewriteHistoryAfterForward);\n self._pushToHistory(params, false, true);\n history.forward();\n }\n function rewriteHistoryAfterForward() {\n window.removeEventListener('popstate', rewriteHistoryAfterForward);\n self.allowHashChange = true;\n self.historyUnlocked = true;\n callback();\n }\n }\n\n function pdfHistoryBeforeUnload() {\n var previousParams = self._getPreviousParams(null, true);\n if (previousParams) {\n var replacePrevious = (!self.current.dest &&\n self.current.hash !== self.previousHash);\n self._pushToHistory(previousParams, false, replacePrevious);\n self._updatePreviousBookmark();\n }\n // Remove the event listener when navigating away from the document,\n // since 'beforeunload' prevents Firefox from caching the document.\n window.removeEventListener('beforeunload', pdfHistoryBeforeUnload);\n }\n\n window.addEventListener('beforeunload', pdfHistoryBeforeUnload);\n\n window.addEventListener('pageshow', function pdfHistoryPageShow(evt) {\n // If the entire viewer (including the PDF file) is cached in\n // the browser, we need to reattach the 'beforeunload' event listener\n // since the 'DOMContentLoaded' event is not fired on 'pageshow'.\n window.addEventListener('beforeunload', pdfHistoryBeforeUnload);\n });\n\n self.eventBus.on('presentationmodechanged', function(e) {\n self.isViewerInPresentationMode = e.active;\n });\n },\n\n clearHistoryState: function pdfHistory_clearHistoryState() {\n this._pushOrReplaceState(null, true);\n },\n\n _isStateObjectDefined: function pdfHistory_isStateObjectDefined(state) {\n return (state && state.uid >= 0 &&\n state.fingerprint && this.fingerprint === state.fingerprint &&\n state.target && state.target.hash) ? true : false;\n },\n\n _pushOrReplaceState: function pdfHistory_pushOrReplaceState(stateObj,\n replace) {\n // history.state.chromecomState is managed by chromecom.js.\n if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('CHROME') &&\n window.history.state && 'chromecomState' in window.history.state) {\n stateObj = stateObj || {};\n stateObj.chromecomState = window.history.state.chromecomState;\n }\n if (replace) {\n if (typeof PDFJSDev === 'undefined' ||\n PDFJSDev.test('GENERIC || CHROME')) {\n window.history.replaceState(stateObj, '', document.URL);\n } else {\n window.history.replaceState(stateObj, '');\n }\n } else {\n if (typeof PDFJSDev === 'undefined' ||\n PDFJSDev.test('GENERIC || CHROME')) {\n window.history.pushState(stateObj, '', document.URL);\n } else {\n window.history.pushState(stateObj, '');\n }\n if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('CHROME') &&\n top === window) {\n chrome.runtime.sendMessage('showPageAction');\n }\n }\n },\n\n get isHashChangeUnlocked() {\n if (!this.initialized) {\n return true;\n }\n return this.allowHashChange;\n },\n\n _updatePreviousBookmark: function pdfHistory_updatePreviousBookmark() {\n if (this.updatePreviousBookmark &&\n this.currentBookmark && this.currentPage) {\n this.previousBookmark = this.currentBookmark;\n this.previousPage = this.currentPage;\n this.updatePreviousBookmark = false;\n }\n },\n\n updateCurrentBookmark: function pdfHistoryUpdateCurrentBookmark(bookmark,\n pageNum) {\n if (this.initialized) {\n this.currentBookmark = bookmark.substring(1);\n this.currentPage = pageNum | 0;\n this._updatePreviousBookmark();\n }\n },\n\n updateNextHashParam: function pdfHistoryUpdateNextHashParam(param) {\n if (this.initialized) {\n this.nextHashParam = param;\n }\n },\n\n push: function pdfHistoryPush(params, isInitialBookmark) {\n if (!(this.initialized && this.historyUnlocked)) {\n return;\n }\n if (params.dest && !params.hash) {\n params.hash = (this.current.hash && this.current.dest &&\n this.current.dest === params.dest) ?\n this.current.hash :\n this.linkService.getDestinationHash(params.dest).split('#')[1];\n }\n if (params.page) {\n params.page |= 0;\n }\n if (isInitialBookmark) {\n var target = window.history.state.target;\n if (!target) {\n // Invoked when the user specifies an initial bookmark,\n // thus setting initialBookmark, when the document is loaded.\n this._pushToHistory(params, false);\n this.previousHash = window.location.hash.substring(1);\n }\n this.updatePreviousBookmark = this.nextHashParam ? false : true;\n if (target) {\n // If the current document is reloaded,\n // avoid creating duplicate entries in the history.\n this._updatePreviousBookmark();\n }\n return;\n }\n if (this.nextHashParam) {\n if (this.nextHashParam === params.hash) {\n this.nextHashParam = null;\n this.updatePreviousBookmark = true;\n return;\n }\n this.nextHashParam = null;\n }\n\n if (params.hash) {\n if (this.current.hash) {\n if (this.current.hash !== params.hash) {\n this._pushToHistory(params, true);\n } else {\n if (!this.current.page && params.page) {\n this._pushToHistory(params, false, true);\n }\n this.updatePreviousBookmark = true;\n }\n } else {\n this._pushToHistory(params, true);\n }\n } else if (this.current.page && params.page &&\n this.current.page !== params.page) {\n this._pushToHistory(params, true);\n }\n },\n\n _getPreviousParams: function pdfHistory_getPreviousParams(onlyCheckPage,\n beforeUnload) {\n if (!(this.currentBookmark && this.currentPage)) {\n return null;\n } else if (this.updatePreviousBookmark) {\n this.updatePreviousBookmark = false;\n }\n if (this.uid > 0 && !(this.previousBookmark && this.previousPage)) {\n // Prevent the history from getting stuck in the current state,\n // effectively preventing the user from going back/forward in\n // the history.\n //\n // This happens if the current position in the document didn't change\n // when the history was previously updated. The reasons for this are\n // either:\n // 1. The current zoom value is such that the document does not need to,\n // or cannot, be scrolled to display the destination.\n // 2. The previous destination is broken, and doesn't actally point to a\n // position within the document.\n // (This is either due to a bad PDF generator, or the user making a\n // mistake when entering a destination in the hash parameters.)\n return null;\n }\n if ((!this.current.dest && !onlyCheckPage) || beforeUnload) {\n if (this.previousBookmark === this.currentBookmark) {\n return null;\n }\n } else if (this.current.page || onlyCheckPage) {\n if (this.previousPage === this.currentPage) {\n return null;\n }\n } else {\n return null;\n }\n var params = { hash: this.currentBookmark, page: this.currentPage, };\n if (this.isViewerInPresentationMode) {\n params.hash = null;\n }\n return params;\n },\n\n _stateObj: function pdfHistory_stateObj(params) {\n return { fingerprint: this.fingerprint, uid: this.uid, target: params, };\n },\n\n _pushToHistory: function pdfHistory_pushToHistory(params,\n addPrevious, overwrite) {\n if (!this.initialized) {\n return;\n }\n if (!params.hash && params.page) {\n params.hash = ('page=' + params.page);\n }\n if (addPrevious && !overwrite) {\n var previousParams = this._getPreviousParams();\n if (previousParams) {\n var replacePrevious = (!this.current.dest &&\n this.current.hash !== this.previousHash);\n this._pushToHistory(previousParams, false, replacePrevious);\n }\n }\n this._pushOrReplaceState(this._stateObj(params),\n (overwrite || this.uid === 0));\n this.currentUid = this.uid++;\n this.current = params;\n this.updatePreviousBookmark = true;\n },\n\n _goTo: function pdfHistory_goTo(state) {\n if (!(this.initialized && this.historyUnlocked &&\n this._isStateObjectDefined(state))) {\n return;\n }\n if (!this.reInitialized && state.uid < this.currentUid) {\n var previousParams = this._getPreviousParams(true);\n if (previousParams) {\n this._pushToHistory(this.current, false);\n this._pushToHistory(previousParams, false);\n this.currentUid = state.uid;\n window.history.back();\n return;\n }\n }\n this.historyUnlocked = false;\n\n if (state.target.dest) {\n this.linkService.navigateTo(state.target.dest);\n } else {\n this.linkService.setHash(state.target.hash);\n }\n this.currentUid = state.uid;\n if (state.uid > this.uid) {\n this.uid = state.uid;\n }\n this.current = state.target;\n this.updatePreviousBookmark = true;\n\n var currentHash = window.location.hash.substring(1);\n if (this.previousHash !== currentHash) {\n this.allowHashChange = false;\n }\n this.previousHash = currentHash;\n\n this.historyUnlocked = true;\n },\n\n back: function pdfHistoryBack() {\n this.go(-1);\n },\n\n forward: function pdfHistoryForward() {\n this.go(1);\n },\n\n go: function pdfHistoryGo(direction) {\n if (this.initialized && this.historyUnlocked) {\n var state = window.history.state;\n if (direction === -1 && state && state.uid > 0) {\n window.history.back();\n } else if (direction === 1 && state && state.uid < (this.uid - 1)) {\n window.history.forward();\n }\n }\n },\n};\n\nexport {\n PDFHistory,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/pdf_history.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n addLinkAttributes, PDFJS, removeNullCharacters\n} from 'pdfjs-lib';\n\nconst DEFAULT_TITLE = '\\u2013';\n\n/**\n * @typedef {Object} PDFOutlineViewerOptions\n * @property {HTMLDivElement} container - The viewer element.\n * @property {IPDFLinkService} linkService - The navigation/linking service.\n * @property {EventBus} eventBus - The application event bus.\n */\n\n/**\n * @typedef {Object} PDFOutlineViewerRenderParameters\n * @property {Array|null} outline - An array of outline objects.\n */\n\nclass PDFOutlineViewer {\n /**\n * @param {PDFOutlineViewerOptions} options\n */\n constructor({ container, linkService, eventBus, }) {\n this.outline = null;\n this.lastToggleIsShow = true;\n\n this.container = container;\n this.linkService = linkService;\n this.eventBus = eventBus;\n }\n\n reset() {\n this.outline = null;\n this.lastToggleIsShow = true;\n\n // Remove the outline from the DOM.\n this.container.textContent = '';\n\n // Ensure that the left (right in RTL locales) margin is always reset,\n // to prevent incorrect outline alignment if a new document is opened.\n this.container.classList.remove('outlineWithDeepNesting');\n }\n\n /**\n * @private\n */\n _dispatchEvent(outlineCount) {\n this.eventBus.dispatch('outlineloaded', {\n source: this,\n outlineCount,\n });\n }\n\n /**\n * @private\n */\n _bindLink(element, item) {\n if (item.url) {\n addLinkAttributes(element, {\n url: item.url,\n target: (item.newWindow ? PDFJS.LinkTarget.BLANK : undefined),\n });\n return;\n }\n let destination = item.dest;\n\n element.href = this.linkService.getDestinationHash(destination);\n element.onclick = () => {\n if (destination) {\n this.linkService.navigateTo(destination);\n }\n return false;\n };\n }\n\n /**\n * @private\n */\n _setStyles(element, item) {\n let styleStr = '';\n if (item.bold) {\n styleStr += 'font-weight: bold;';\n }\n if (item.italic) {\n styleStr += 'font-style: italic;';\n }\n\n if (styleStr) {\n element.setAttribute('style', styleStr);\n }\n }\n\n /**\n * Prepend a button before an outline item which allows the user to toggle\n * the visibility of all outline items at that level.\n *\n * @private\n */\n _addToggleButton(div) {\n let toggler = document.createElement('div');\n toggler.className = 'outlineItemToggler';\n toggler.onclick = (evt) => {\n evt.stopPropagation();\n toggler.classList.toggle('outlineItemsHidden');\n\n if (evt.shiftKey) {\n let shouldShowAll = !toggler.classList.contains('outlineItemsHidden');\n this._toggleOutlineItem(div, shouldShowAll);\n }\n };\n div.insertBefore(toggler, div.firstChild);\n }\n\n /**\n * Toggle the visibility of the subtree of an outline item.\n *\n * @param {Element} root - the root of the outline (sub)tree.\n * @param {boolean} show - whether to show the outline (sub)tree. If false,\n * the outline subtree rooted at |root| will be collapsed.\n *\n * @private\n */\n _toggleOutlineItem(root, show) {\n this.lastToggleIsShow = show;\n let togglers = root.querySelectorAll('.outlineItemToggler');\n for (let i = 0, ii = togglers.length; i < ii; ++i) {\n togglers[i].classList[show ? 'remove' : 'add']('outlineItemsHidden');\n }\n }\n\n /**\n * Collapse or expand all subtrees of the outline.\n */\n toggleOutlineTree() {\n if (!this.outline) {\n return;\n }\n this._toggleOutlineItem(this.container, !this.lastToggleIsShow);\n }\n\n /**\n * @param {PDFOutlineViewerRenderParameters} params\n */\n render({ outline, }) {\n let outlineCount = 0;\n\n if (this.outline) {\n this.reset();\n }\n this.outline = outline || null;\n\n if (!outline) {\n this._dispatchEvent(outlineCount);\n return;\n }\n\n let fragment = document.createDocumentFragment();\n let queue = [{ parent: fragment, items: this.outline, }];\n let hasAnyNesting = false;\n while (queue.length > 0) {\n let levelData = queue.shift();\n for (let i = 0, len = levelData.items.length; i < len; i++) {\n let item = levelData.items[i];\n\n let div = document.createElement('div');\n div.className = 'outlineItem';\n\n let element = document.createElement('a');\n this._bindLink(element, item);\n this._setStyles(element, item);\n element.textContent =\n removeNullCharacters(item.title) || DEFAULT_TITLE;\n\n div.appendChild(element);\n\n if (item.items.length > 0) {\n hasAnyNesting = true;\n this._addToggleButton(div);\n\n let itemsDiv = document.createElement('div');\n itemsDiv.className = 'outlineItems';\n div.appendChild(itemsDiv);\n queue.push({ parent: itemsDiv, items: item.items, });\n }\n\n levelData.parent.appendChild(div);\n outlineCount++;\n }\n }\n if (hasAnyNesting) {\n this.container.classList.add('outlineWithDeepNesting');\n }\n\n this.container.appendChild(fragment);\n\n this._dispatchEvent(outlineCount);\n }\n}\n\nexport {\n PDFOutlineViewer,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/pdf_outline_viewer.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n approximateFraction, CSS_UNITS, DEFAULT_SCALE, getOutputScale, NullL10n,\n RendererType, roundToDivide\n} from './ui_utils';\nimport {\n createPromiseCapability, CustomStyle, PDFJS, RenderingCancelledException,\n SVGGraphics\n} from 'pdfjs-lib';\nimport { getGlobalEventBus } from './dom_events';\nimport { RenderingStates } from './pdf_rendering_queue';\n\n/**\n * @typedef {Object} PDFPageViewOptions\n * @property {HTMLDivElement} container - The viewer element.\n * @property {EventBus} eventBus - The application event bus.\n * @property {number} id - The page unique ID (normally its number).\n * @property {number} scale - The page scale display.\n * @property {PageViewport} defaultViewport - The page viewport.\n * @property {PDFRenderingQueue} renderingQueue - The rendering queue object.\n * @property {IPDFTextLayerFactory} textLayerFactory\n * @property {IPDFAnnotationLayerFactory} annotationLayerFactory\n * @property {boolean} enhanceTextSelection - Turns on the text selection\n * enhancement. The default is `false`.\n * @property {boolean} renderInteractiveForms - Turns on rendering of\n * interactive form elements. The default is `false`.\n * @property {string} renderer - 'canvas' or 'svg'. The default is 'canvas'.\n * @property {IL10n} l10n - Localization service.\n */\n\n/**\n * @implements {IRenderableView}\n */\nclass PDFPageView {\n /**\n * @param {PDFPageViewOptions} options\n */\n constructor(options) {\n let container = options.container;\n let defaultViewport = options.defaultViewport;\n\n this.id = options.id;\n this.renderingId = 'page' + this.id;\n\n this.pdfPage = null;\n this.pageLabel = null;\n this.rotation = 0;\n this.scale = options.scale || DEFAULT_SCALE;\n this.viewport = defaultViewport;\n this.pdfPageRotate = defaultViewport.rotation;\n this.hasRestrictedScaling = false;\n this.enhanceTextSelection = options.enhanceTextSelection || false;\n this.renderInteractiveForms = options.renderInteractiveForms || false;\n\n this.eventBus = options.eventBus || getGlobalEventBus();\n this.renderingQueue = options.renderingQueue;\n this.textLayerFactory = options.textLayerFactory;\n this.annotationLayerFactory = options.annotationLayerFactory;\n this.renderer = options.renderer || RendererType.CANVAS;\n this.l10n = options.l10n || NullL10n;\n\n this.paintTask = null;\n this.paintedViewportMap = new WeakMap();\n this.renderingState = RenderingStates.INITIAL;\n this.resume = null;\n this.error = null;\n\n this.onBeforeDraw = null;\n this.onAfterDraw = null;\n\n this.annotationLayer = null;\n this.textLayer = null;\n this.zoomLayer = null;\n\n let div = document.createElement('div');\n div.className = 'page';\n div.style.width = Math.floor(this.viewport.width) + 'px';\n div.style.height = Math.floor(this.viewport.height) + 'px';\n div.setAttribute('data-page-number', this.id);\n this.div = div;\n\n container.appendChild(div);\n }\n\n setPdfPage(pdfPage) {\n this.pdfPage = pdfPage;\n this.pdfPageRotate = pdfPage.rotate;\n\n let totalRotation = (this.rotation + this.pdfPageRotate) % 360;\n this.viewport = pdfPage.getViewport(this.scale * CSS_UNITS,\n totalRotation);\n this.stats = pdfPage.stats;\n this.reset();\n }\n\n destroy() {\n this.reset();\n if (this.pdfPage) {\n this.pdfPage.cleanup();\n this.pdfPage = null;\n }\n }\n\n /**\n * @private\n */\n _resetZoomLayer(removeFromDOM = false) {\n if (!this.zoomLayer) {\n return;\n }\n let zoomLayerCanvas = this.zoomLayer.firstChild;\n this.paintedViewportMap.delete(zoomLayerCanvas);\n // Zeroing the width and height causes Firefox to release graphics\n // resources immediately, which can greatly reduce memory consumption.\n zoomLayerCanvas.width = 0;\n zoomLayerCanvas.height = 0;\n\n if (removeFromDOM) {\n // Note: `ChildNode.remove` doesn't throw if the parent node is undefined.\n this.zoomLayer.remove();\n }\n this.zoomLayer = null;\n }\n\n reset(keepZoomLayer = false, keepAnnotations = false) {\n this.cancelRendering();\n\n let div = this.div;\n div.style.width = Math.floor(this.viewport.width) + 'px';\n div.style.height = Math.floor(this.viewport.height) + 'px';\n\n let childNodes = div.childNodes;\n let currentZoomLayerNode = (keepZoomLayer && this.zoomLayer) || null;\n let currentAnnotationNode = (keepAnnotations && this.annotationLayer &&\n this.annotationLayer.div) || null;\n for (let i = childNodes.length - 1; i >= 0; i--) {\n let node = childNodes[i];\n if (currentZoomLayerNode === node || currentAnnotationNode === node) {\n continue;\n }\n div.removeChild(node);\n }\n div.removeAttribute('data-loaded');\n\n if (currentAnnotationNode) {\n // Hide the annotation layer until all elements are resized\n // so they are not displayed on the already resized page.\n this.annotationLayer.hide();\n } else {\n this.annotationLayer = null;\n }\n\n if (!currentZoomLayerNode) {\n if (this.canvas) {\n this.paintedViewportMap.delete(this.canvas);\n // Zeroing the width and height causes Firefox to release graphics\n // resources immediately, which can greatly reduce memory consumption.\n this.canvas.width = 0;\n this.canvas.height = 0;\n delete this.canvas;\n }\n this._resetZoomLayer();\n }\n if (this.svg) {\n this.paintedViewportMap.delete(this.svg);\n delete this.svg;\n }\n\n this.loadingIconDiv = document.createElement('div');\n this.loadingIconDiv.className = 'loadingIcon';\n div.appendChild(this.loadingIconDiv);\n }\n\n update(scale, rotation) {\n this.scale = scale || this.scale;\n if (typeof rotation !== 'undefined') { // The rotation may be zero.\n this.rotation = rotation;\n }\n\n let totalRotation = (this.rotation + this.pdfPageRotate) % 360;\n this.viewport = this.viewport.clone({\n scale: this.scale * CSS_UNITS,\n rotation: totalRotation,\n });\n\n if (this.svg) {\n this.cssTransform(this.svg, true);\n\n this.eventBus.dispatch('pagerendered', {\n source: this,\n pageNumber: this.id,\n cssTransform: true,\n });\n return;\n }\n\n let isScalingRestricted = false;\n if (this.canvas && PDFJS.maxCanvasPixels > 0) {\n let outputScale = this.outputScale;\n if (((Math.floor(this.viewport.width) * outputScale.sx) | 0) *\n ((Math.floor(this.viewport.height) * outputScale.sy) | 0) >\n PDFJS.maxCanvasPixels) {\n isScalingRestricted = true;\n }\n }\n\n if (this.canvas) {\n if (PDFJS.useOnlyCssZoom ||\n (this.hasRestrictedScaling && isScalingRestricted)) {\n this.cssTransform(this.canvas, true);\n\n this.eventBus.dispatch('pagerendered', {\n source: this,\n pageNumber: this.id,\n cssTransform: true,\n });\n return;\n }\n if (!this.zoomLayer && !this.canvas.hasAttribute('hidden')) {\n this.zoomLayer = this.canvas.parentNode;\n this.zoomLayer.style.position = 'absolute';\n }\n }\n if (this.zoomLayer) {\n this.cssTransform(this.zoomLayer.firstChild);\n }\n this.reset(/* keepZoomLayer = */ true, /* keepAnnotations = */ true);\n }\n\n cancelRendering() {\n if (this.paintTask) {\n this.paintTask.cancel();\n this.paintTask = null;\n }\n this.renderingState = RenderingStates.INITIAL;\n this.resume = null;\n\n if (this.textLayer) {\n this.textLayer.cancel();\n this.textLayer = null;\n }\n }\n\n cssTransform(target, redrawAnnotations = false) {\n // Scale target (canvas or svg), its wrapper and page container.\n let width = this.viewport.width;\n let height = this.viewport.height;\n let div = this.div;\n target.style.width = target.parentNode.style.width = div.style.width =\n Math.floor(width) + 'px';\n target.style.height = target.parentNode.style.height = div.style.height =\n Math.floor(height) + 'px';\n // The canvas may have been originally rotated; rotate relative to that.\n let relativeRotation = this.viewport.rotation -\n this.paintedViewportMap.get(target).rotation;\n let absRotation = Math.abs(relativeRotation);\n let scaleX = 1, scaleY = 1;\n if (absRotation === 90 || absRotation === 270) {\n // Scale x and y because of the rotation.\n scaleX = height / width;\n scaleY = width / height;\n }\n let cssTransform = 'rotate(' + relativeRotation + 'deg) ' +\n 'scale(' + scaleX + ',' + scaleY + ')';\n CustomStyle.setProp('transform', target, cssTransform);\n\n if (this.textLayer) {\n // Rotating the text layer is more complicated since the divs inside the\n // the text layer are rotated.\n // TODO: This could probably be simplified by drawing the text layer in\n // one orientation and then rotating overall.\n let textLayerViewport = this.textLayer.viewport;\n let textRelativeRotation = this.viewport.rotation -\n textLayerViewport.rotation;\n let textAbsRotation = Math.abs(textRelativeRotation);\n let scale = width / textLayerViewport.width;\n if (textAbsRotation === 90 || textAbsRotation === 270) {\n scale = width / textLayerViewport.height;\n }\n let textLayerDiv = this.textLayer.textLayerDiv;\n let transX, transY;\n switch (textAbsRotation) {\n case 0:\n transX = transY = 0;\n break;\n case 90:\n transX = 0;\n transY = '-' + textLayerDiv.style.height;\n break;\n case 180:\n transX = '-' + textLayerDiv.style.width;\n transY = '-' + textLayerDiv.style.height;\n break;\n case 270:\n transX = '-' + textLayerDiv.style.width;\n transY = 0;\n break;\n default:\n console.error('Bad rotation value.');\n break;\n }\n CustomStyle.setProp('transform', textLayerDiv,\n 'rotate(' + textAbsRotation + 'deg) ' +\n 'scale(' + scale + ', ' + scale + ') ' +\n 'translate(' + transX + ', ' + transY + ')');\n CustomStyle.setProp('transformOrigin', textLayerDiv, '0% 0%');\n }\n\n if (redrawAnnotations && this.annotationLayer) {\n this.annotationLayer.render(this.viewport, 'display');\n }\n }\n\n get width() {\n return this.viewport.width;\n }\n\n get height() {\n return this.viewport.height;\n }\n\n getPagePoint(x, y) {\n return this.viewport.convertToPdfPoint(x, y);\n }\n\n draw() {\n if (this.renderingState !== RenderingStates.INITIAL) {\n console.error('Must be in new state before drawing');\n this.reset(); // Ensure that we reset all state to prevent issues.\n }\n\n if (!this.pdfPage) {\n this.renderingState = RenderingStates.FINISHED;\n return Promise.reject(new Error('Page is not loaded'));\n }\n\n this.renderingState = RenderingStates.RUNNING;\n\n let pdfPage = this.pdfPage;\n let div = this.div;\n // Wrap the canvas so that if it has a CSS transform for high DPI the\n // overflow will be hidden in Firefox.\n let canvasWrapper = document.createElement('div');\n canvasWrapper.style.width = div.style.width;\n canvasWrapper.style.height = div.style.height;\n canvasWrapper.classList.add('canvasWrapper');\n\n if (this.annotationLayer && this.annotationLayer.div) {\n // The annotation layer needs to stay on top.\n div.insertBefore(canvasWrapper, this.annotationLayer.div);\n } else {\n div.appendChild(canvasWrapper);\n }\n\n let textLayer = null;\n if (this.textLayerFactory) {\n let textLayerDiv = document.createElement('div');\n textLayerDiv.className = 'textLayer';\n textLayerDiv.style.width = canvasWrapper.style.width;\n textLayerDiv.style.height = canvasWrapper.style.height;\n if (this.annotationLayer && this.annotationLayer.div) {\n // The annotation layer needs to stay on top.\n div.insertBefore(textLayerDiv, this.annotationLayer.div);\n } else {\n div.appendChild(textLayerDiv);\n }\n\n textLayer = this.textLayerFactory.\n createTextLayerBuilder(textLayerDiv, this.id - 1, this.viewport,\n this.enhanceTextSelection);\n }\n this.textLayer = textLayer;\n\n let renderContinueCallback = null;\n if (this.renderingQueue) {\n renderContinueCallback = (cont) => {\n if (!this.renderingQueue.isHighestPriority(this)) {\n this.renderingState = RenderingStates.PAUSED;\n this.resume = () => {\n this.renderingState = RenderingStates.RUNNING;\n cont();\n };\n return;\n }\n cont();\n };\n }\n\n let finishPaintTask = (error) => {\n // The paintTask may have been replaced by a new one, so only remove\n // the reference to the paintTask if it matches the one that is\n // triggering this callback.\n if (paintTask === this.paintTask) {\n this.paintTask = null;\n }\n\n if (((typeof PDFJSDev === 'undefined' ||\n !PDFJSDev.test('PDFJS_NEXT')) && error === 'cancelled') ||\n error instanceof RenderingCancelledException) {\n this.error = null;\n return Promise.resolve(undefined);\n }\n\n this.renderingState = RenderingStates.FINISHED;\n\n if (this.loadingIconDiv) {\n div.removeChild(this.loadingIconDiv);\n delete this.loadingIconDiv;\n }\n this._resetZoomLayer(/* removeFromDOM = */ true);\n\n this.error = error;\n this.stats = pdfPage.stats;\n if (this.onAfterDraw) {\n this.onAfterDraw();\n }\n this.eventBus.dispatch('pagerendered', {\n source: this,\n pageNumber: this.id,\n cssTransform: false,\n });\n\n if (error) {\n return Promise.reject(error);\n }\n return Promise.resolve(undefined);\n };\n\n let paintTask = this.renderer === RendererType.SVG ?\n this.paintOnSvg(canvasWrapper) :\n this.paintOnCanvas(canvasWrapper);\n paintTask.onRenderContinue = renderContinueCallback;\n this.paintTask = paintTask;\n\n let resultPromise = paintTask.promise.then(function() {\n return finishPaintTask(null).then(function () {\n if (textLayer) {\n let readableStream = pdfPage.streamTextContent({\n normalizeWhitespace: true,\n });\n textLayer.setTextContentStream(readableStream);\n textLayer.render();\n }\n });\n }, function(reason) {\n return finishPaintTask(reason);\n });\n\n if (this.annotationLayerFactory) {\n if (!this.annotationLayer) {\n this.annotationLayer = this.annotationLayerFactory.\n createAnnotationLayerBuilder(div, pdfPage,\n this.renderInteractiveForms, this.l10n);\n }\n this.annotationLayer.render(this.viewport, 'display');\n }\n div.setAttribute('data-loaded', true);\n\n if (this.onBeforeDraw) {\n this.onBeforeDraw();\n }\n return resultPromise;\n }\n\n paintOnCanvas(canvasWrapper) {\n let renderCapability = createPromiseCapability();\n let result = {\n promise: renderCapability.promise,\n onRenderContinue(cont) {\n cont();\n },\n cancel() {\n renderTask.cancel();\n },\n };\n\n let viewport = this.viewport;\n let canvas = document.createElement('canvas');\n canvas.id = this.renderingId;\n\n // Keep the canvas hidden until the first draw callback, or until drawing\n // is complete when `!this.renderingQueue`, to prevent black flickering.\n canvas.setAttribute('hidden', 'hidden');\n let isCanvasHidden = true;\n let showCanvas = function () {\n if (isCanvasHidden) {\n canvas.removeAttribute('hidden');\n isCanvasHidden = false;\n }\n };\n\n canvasWrapper.appendChild(canvas);\n this.canvas = canvas;\n\n if (typeof PDFJSDev === 'undefined' ||\n PDFJSDev.test('MOZCENTRAL || FIREFOX || GENERIC')) {\n canvas.mozOpaque = true;\n }\n\n let ctx = canvas.getContext('2d', { alpha: false, });\n let outputScale = getOutputScale(ctx);\n this.outputScale = outputScale;\n\n if (PDFJS.useOnlyCssZoom) {\n let actualSizeViewport = viewport.clone({ scale: CSS_UNITS, });\n // Use a scale that makes the canvas have the originally intended size\n // of the page.\n outputScale.sx *= actualSizeViewport.width / viewport.width;\n outputScale.sy *= actualSizeViewport.height / viewport.height;\n outputScale.scaled = true;\n }\n\n if (PDFJS.maxCanvasPixels > 0) {\n let pixelsInViewport = viewport.width * viewport.height;\n let maxScale = Math.sqrt(PDFJS.maxCanvasPixels / pixelsInViewport);\n if (outputScale.sx > maxScale || outputScale.sy > maxScale) {\n outputScale.sx = maxScale;\n outputScale.sy = maxScale;\n outputScale.scaled = true;\n this.hasRestrictedScaling = true;\n } else {\n this.hasRestrictedScaling = false;\n }\n }\n\n let sfx = approximateFraction(outputScale.sx);\n let sfy = approximateFraction(outputScale.sy);\n canvas.width = roundToDivide(viewport.width * outputScale.sx, sfx[0]);\n canvas.height = roundToDivide(viewport.height * outputScale.sy, sfy[0]);\n canvas.style.width = roundToDivide(viewport.width, sfx[1]) + 'px';\n canvas.style.height = roundToDivide(viewport.height, sfy[1]) + 'px';\n // Add the viewport so it's known what it was originally drawn with.\n this.paintedViewportMap.set(canvas, viewport);\n\n // Rendering area\n let transform = !outputScale.scaled ? null :\n [outputScale.sx, 0, 0, outputScale.sy, 0, 0];\n let renderContext = {\n canvasContext: ctx,\n transform,\n viewport: this.viewport,\n renderInteractiveForms: this.renderInteractiveForms,\n };\n let renderTask = this.pdfPage.render(renderContext);\n renderTask.onContinue = function (cont) {\n showCanvas();\n if (result.onRenderContinue) {\n result.onRenderContinue(cont);\n } else {\n cont();\n }\n };\n\n renderTask.promise.then(function() {\n showCanvas();\n renderCapability.resolve(undefined);\n }, function(error) {\n showCanvas();\n renderCapability.reject(error);\n });\n return result;\n }\n\n paintOnSvg(wrapper) {\n if (typeof PDFJSDev !== 'undefined' &&\n PDFJSDev.test('FIREFOX || MOZCENTRAL || CHROME')) {\n // Return a mock object, to prevent errors such as e.g.\n // \"TypeError: paintTask.promise is undefined\".\n return {\n promise: Promise.reject(new Error('SVG rendering is not supported.')),\n onRenderContinue(cont) { },\n cancel() { },\n };\n }\n\n let cancelled = false;\n let ensureNotCancelled = () => {\n if (cancelled) {\n if ((typeof PDFJSDev !== 'undefined' &&\n PDFJSDev.test('PDFJS_NEXT')) || PDFJS.pdfjsNext) {\n throw new RenderingCancelledException(\n 'Rendering cancelled, page ' + this.id, 'svg');\n } else {\n throw 'cancelled'; // eslint-disable-line no-throw-literal\n }\n }\n };\n\n let pdfPage = this.pdfPage;\n let actualSizeViewport = this.viewport.clone({ scale: CSS_UNITS, });\n let promise = pdfPage.getOperatorList().then((opList) => {\n ensureNotCancelled();\n let svgGfx = new SVGGraphics(pdfPage.commonObjs, pdfPage.objs);\n return svgGfx.getSVG(opList, actualSizeViewport).then((svg) => {\n ensureNotCancelled();\n this.svg = svg;\n this.paintedViewportMap.set(svg, actualSizeViewport);\n\n svg.style.width = wrapper.style.width;\n svg.style.height = wrapper.style.height;\n this.renderingState = RenderingStates.FINISHED;\n wrapper.appendChild(svg);\n });\n });\n\n return {\n promise,\n onRenderContinue(cont) {\n cont();\n },\n cancel() {\n cancelled = true;\n },\n };\n }\n\n /**\n * @param {string|null} label\n */\n setPageLabel(label) {\n this.pageLabel = (typeof label === 'string' ? label : null);\n\n if (this.pageLabel !== null) {\n this.div.setAttribute('data-page-label', this.pageLabel);\n } else {\n this.div.removeAttribute('data-page-label');\n }\n }\n}\n\nexport {\n PDFPageView,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/pdf_page_view.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { normalizeWheelEventDelta } from './ui_utils';\n\nconst DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS = 1500; // in ms\nconst DELAY_BEFORE_HIDING_CONTROLS = 3000; // in ms\nconst ACTIVE_SELECTOR = 'pdfPresentationMode';\nconst CONTROLS_SELECTOR = 'pdfPresentationModeControls';\nconst MOUSE_SCROLL_COOLDOWN_TIME = 50; // in ms\nconst PAGE_SWITCH_THRESHOLD = 0.1;\n\n// Number of CSS pixels for a movement to count as a swipe.\nconst SWIPE_MIN_DISTANCE_THRESHOLD = 50;\n\n// Swipe angle deviation from the x or y axis before it is not\n// considered a swipe in that direction any more.\nconst SWIPE_ANGLE_THRESHOLD = Math.PI / 6;\n\n/**\n * @typedef {Object} PDFPresentationModeOptions\n * @property {HTMLDivElement} container - The container for the viewer element.\n * @property {HTMLDivElement} viewer - (optional) The viewer element.\n * @property {PDFViewer} pdfViewer - The document viewer.\n * @property {EventBus} eventBus - The application event bus.\n * @property {Array} contextMenuItems - (optional) The menuitems that are added\n * to the context menu in Presentation Mode.\n */\n\nclass PDFPresentationMode {\n /**\n * @param {PDFPresentationModeOptions} options\n */\n constructor({ container, viewer = null, pdfViewer, eventBus,\n contextMenuItems = null, }) {\n this.container = container;\n this.viewer = viewer || container.firstElementChild;\n this.pdfViewer = pdfViewer;\n this.eventBus = eventBus;\n\n this.active = false;\n this.args = null;\n this.contextMenuOpen = false;\n this.mouseScrollTimeStamp = 0;\n this.mouseScrollDelta = 0;\n this.touchSwipeState = null;\n\n if (contextMenuItems) {\n contextMenuItems.contextFirstPage.addEventListener('click', () => {\n this.contextMenuOpen = false;\n this.eventBus.dispatch('firstpage');\n });\n contextMenuItems.contextLastPage.addEventListener('click', () => {\n this.contextMenuOpen = false;\n this.eventBus.dispatch('lastpage');\n });\n contextMenuItems.contextPageRotateCw.addEventListener('click', () => {\n this.contextMenuOpen = false;\n this.eventBus.dispatch('rotatecw');\n });\n contextMenuItems.contextPageRotateCcw.addEventListener('click', () => {\n this.contextMenuOpen = false;\n this.eventBus.dispatch('rotateccw');\n });\n }\n }\n\n /**\n * Request the browser to enter fullscreen mode.\n * @returns {boolean} Indicating if the request was successful.\n */\n request() {\n if (this.switchInProgress || this.active || !this.viewer.hasChildNodes()) {\n return false;\n }\n this._addFullscreenChangeListeners();\n this._setSwitchInProgress();\n this._notifyStateChange();\n\n if (this.container.requestFullscreen) {\n this.container.requestFullscreen();\n } else if (this.container.mozRequestFullScreen) {\n this.container.mozRequestFullScreen();\n } else if (this.container.webkitRequestFullscreen) {\n this.container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);\n } else if (this.container.msRequestFullscreen) {\n this.container.msRequestFullscreen();\n } else {\n return false;\n }\n\n this.args = {\n page: this.pdfViewer.currentPageNumber,\n previousScale: this.pdfViewer.currentScaleValue,\n };\n\n return true;\n }\n\n /**\n * @private\n */\n _mouseWheel(evt) {\n if (!this.active) {\n return;\n }\n\n evt.preventDefault();\n\n let delta = normalizeWheelEventDelta(evt);\n let currentTime = (new Date()).getTime();\n let storedTime = this.mouseScrollTimeStamp;\n\n // If we've already switched page, avoid accidentally switching again.\n if (currentTime > storedTime &&\n currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) {\n return;\n }\n // If the scroll direction changed, reset the accumulated scroll delta.\n if ((this.mouseScrollDelta > 0 && delta < 0) ||\n (this.mouseScrollDelta < 0 && delta > 0)) {\n this._resetMouseScrollState();\n }\n this.mouseScrollDelta += delta;\n\n if (Math.abs(this.mouseScrollDelta) >= PAGE_SWITCH_THRESHOLD) {\n let totalDelta = this.mouseScrollDelta;\n this._resetMouseScrollState();\n let success = totalDelta > 0 ? this._goToPreviousPage()\n : this._goToNextPage();\n if (success) {\n this.mouseScrollTimeStamp = currentTime;\n }\n }\n }\n\n get isFullscreen() {\n return !!(document.fullscreenElement || document.mozFullScreen ||\n document.webkitIsFullScreen || document.msFullscreenElement);\n }\n\n /**\n * @private\n */\n _goToPreviousPage() {\n let page = this.pdfViewer.currentPageNumber;\n // If we're at the first page, we don't need to do anything.\n if (page <= 1) {\n return false;\n }\n this.pdfViewer.currentPageNumber = (page - 1);\n return true;\n }\n\n /**\n * @private\n */\n _goToNextPage() {\n let page = this.pdfViewer.currentPageNumber;\n // If we're at the last page, we don't need to do anything.\n if (page >= this.pdfViewer.pagesCount) {\n return false;\n }\n this.pdfViewer.currentPageNumber = (page + 1);\n return true;\n }\n\n /**\n * @private\n */\n _notifyStateChange() {\n this.eventBus.dispatch('presentationmodechanged', {\n source: this,\n active: this.active,\n switchInProgress: !!this.switchInProgress,\n });\n }\n\n /**\n * Used to initialize a timeout when requesting Presentation Mode,\n * i.e. when the browser is requested to enter fullscreen mode.\n * This timeout is used to prevent the current page from being scrolled\n * partially, or completely, out of view when entering Presentation Mode.\n * NOTE: This issue seems limited to certain zoom levels (e.g. page-width).\n *\n * @private\n */\n _setSwitchInProgress() {\n if (this.switchInProgress) {\n clearTimeout(this.switchInProgress);\n }\n this.switchInProgress = setTimeout(() => {\n this._removeFullscreenChangeListeners();\n delete this.switchInProgress;\n this._notifyStateChange();\n }, DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS);\n }\n\n /**\n * @private\n */\n _resetSwitchInProgress() {\n if (this.switchInProgress) {\n clearTimeout(this.switchInProgress);\n delete this.switchInProgress;\n }\n }\n\n /**\n * @private\n */\n _enter() {\n this.active = true;\n this._resetSwitchInProgress();\n this._notifyStateChange();\n this.container.classList.add(ACTIVE_SELECTOR);\n\n // Ensure that the correct page is scrolled into view when entering\n // Presentation Mode, by waiting until fullscreen mode in enabled.\n setTimeout(() => {\n this.pdfViewer.currentPageNumber = this.args.page;\n this.pdfViewer.currentScaleValue = 'page-fit';\n }, 0);\n\n this._addWindowListeners();\n this._showControls();\n this.contextMenuOpen = false;\n this.container.setAttribute('contextmenu', 'viewerContextMenu');\n\n // Text selection is disabled in Presentation Mode, thus it's not possible\n // for the user to deselect text that is selected (e.g. with \"Select all\")\n // when entering Presentation Mode, hence we remove any active selection.\n window.getSelection().removeAllRanges();\n }\n\n /**\n * @private\n */\n _exit() {\n let page = this.pdfViewer.currentPageNumber;\n this.container.classList.remove(ACTIVE_SELECTOR);\n\n // Ensure that the correct page is scrolled into view when exiting\n // Presentation Mode, by waiting until fullscreen mode is disabled.\n setTimeout(() => {\n this.active = false;\n this._removeFullscreenChangeListeners();\n this._notifyStateChange();\n\n this.pdfViewer.currentScaleValue = this.args.previousScale;\n this.pdfViewer.currentPageNumber = page;\n this.args = null;\n }, 0);\n\n this._removeWindowListeners();\n this._hideControls();\n this._resetMouseScrollState();\n this.container.removeAttribute('contextmenu');\n this.contextMenuOpen = false;\n }\n\n /**\n * @private\n */\n _mouseDown(evt) {\n if (this.contextMenuOpen) {\n this.contextMenuOpen = false;\n evt.preventDefault();\n return;\n }\n if (evt.button === 0) {\n // Enable clicking of links in presentation mode. Note: only links\n // pointing to destinations in the current PDF document work.\n let isInternalLink = (evt.target.href &&\n evt.target.classList.contains('internalLink'));\n if (!isInternalLink) {\n // Unless an internal link was clicked, advance one page.\n evt.preventDefault();\n\n if (evt.shiftKey) {\n this._goToPreviousPage();\n } else {\n this._goToNextPage();\n }\n }\n }\n }\n\n /**\n * @private\n */\n _contextMenu() {\n this.contextMenuOpen = true;\n }\n\n /**\n * @private\n */\n _showControls() {\n if (this.controlsTimeout) {\n clearTimeout(this.controlsTimeout);\n } else {\n this.container.classList.add(CONTROLS_SELECTOR);\n }\n this.controlsTimeout = setTimeout(() => {\n this.container.classList.remove(CONTROLS_SELECTOR);\n delete this.controlsTimeout;\n }, DELAY_BEFORE_HIDING_CONTROLS);\n }\n\n /**\n * @private\n */\n _hideControls() {\n if (!this.controlsTimeout) {\n return;\n }\n clearTimeout(this.controlsTimeout);\n this.container.classList.remove(CONTROLS_SELECTOR);\n delete this.controlsTimeout;\n }\n\n /**\n * Resets the properties used for tracking mouse scrolling events.\n *\n * @private\n */\n _resetMouseScrollState() {\n this.mouseScrollTimeStamp = 0;\n this.mouseScrollDelta = 0;\n }\n\n /**\n * @private\n */\n _touchSwipe(evt) {\n if (!this.active) {\n return;\n }\n if (evt.touches.length > 1) {\n // Multiple touch points detected; cancel the swipe.\n this.touchSwipeState = null;\n return;\n }\n\n switch (evt.type) {\n case 'touchstart':\n this.touchSwipeState = {\n startX: evt.touches[0].pageX,\n startY: evt.touches[0].pageY,\n endX: evt.touches[0].pageX,\n endY: evt.touches[0].pageY,\n };\n break;\n case 'touchmove':\n if (this.touchSwipeState === null) {\n return;\n }\n this.touchSwipeState.endX = evt.touches[0].pageX;\n this.touchSwipeState.endY = evt.touches[0].pageY;\n // Avoid the swipe from triggering browser gestures (Chrome in\n // particular has some sort of swipe gesture in fullscreen mode).\n evt.preventDefault();\n break;\n case 'touchend':\n if (this.touchSwipeState === null) {\n return;\n }\n let delta = 0;\n let dx = this.touchSwipeState.endX - this.touchSwipeState.startX;\n let dy = this.touchSwipeState.endY - this.touchSwipeState.startY;\n let absAngle = Math.abs(Math.atan2(dy, dx));\n if (Math.abs(dx) > SWIPE_MIN_DISTANCE_THRESHOLD &&\n (absAngle <= SWIPE_ANGLE_THRESHOLD ||\n absAngle >= (Math.PI - SWIPE_ANGLE_THRESHOLD))) {\n // Horizontal swipe.\n delta = dx;\n } else if (Math.abs(dy) > SWIPE_MIN_DISTANCE_THRESHOLD &&\n Math.abs(absAngle - (Math.PI / 2)) <= SWIPE_ANGLE_THRESHOLD) {\n // Vertical swipe.\n delta = dy;\n }\n if (delta > 0) {\n this._goToPreviousPage();\n } else if (delta < 0) {\n this._goToNextPage();\n }\n break;\n }\n }\n\n /**\n * @private\n */\n _addWindowListeners() {\n this.showControlsBind = this._showControls.bind(this);\n this.mouseDownBind = this._mouseDown.bind(this);\n this.mouseWheelBind = this._mouseWheel.bind(this);\n this.resetMouseScrollStateBind = this._resetMouseScrollState.bind(this);\n this.contextMenuBind = this._contextMenu.bind(this);\n this.touchSwipeBind = this._touchSwipe.bind(this);\n\n window.addEventListener('mousemove', this.showControlsBind);\n window.addEventListener('mousedown', this.mouseDownBind);\n window.addEventListener('wheel', this.mouseWheelBind);\n window.addEventListener('keydown', this.resetMouseScrollStateBind);\n window.addEventListener('contextmenu', this.contextMenuBind);\n window.addEventListener('touchstart', this.touchSwipeBind);\n window.addEventListener('touchmove', this.touchSwipeBind);\n window.addEventListener('touchend', this.touchSwipeBind);\n }\n\n /**\n * @private\n */\n _removeWindowListeners() {\n window.removeEventListener('mousemove', this.showControlsBind);\n window.removeEventListener('mousedown', this.mouseDownBind);\n window.removeEventListener('wheel', this.mouseWheelBind);\n window.removeEventListener('keydown', this.resetMouseScrollStateBind);\n window.removeEventListener('contextmenu', this.contextMenuBind);\n window.removeEventListener('touchstart', this.touchSwipeBind);\n window.removeEventListener('touchmove', this.touchSwipeBind);\n window.removeEventListener('touchend', this.touchSwipeBind);\n\n delete this.showControlsBind;\n delete this.mouseDownBind;\n delete this.mouseWheelBind;\n delete this.resetMouseScrollStateBind;\n delete this.contextMenuBind;\n delete this.touchSwipeBind;\n }\n\n /**\n * @private\n */\n _fullscreenChange() {\n if (this.isFullscreen) {\n this._enter();\n } else {\n this._exit();\n }\n }\n\n /**\n * @private\n */\n _addFullscreenChangeListeners() {\n this.fullscreenChangeBind = this._fullscreenChange.bind(this);\n\n window.addEventListener('fullscreenchange', this.fullscreenChangeBind);\n window.addEventListener('mozfullscreenchange', this.fullscreenChangeBind);\n if (typeof PDFJSDev === 'undefined' ||\n !PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n window.addEventListener('webkitfullscreenchange',\n this.fullscreenChangeBind);\n window.addEventListener('MSFullscreenChange',\n this.fullscreenChangeBind);\n }\n }\n\n /**\n * @private\n */\n _removeFullscreenChangeListeners() {\n window.removeEventListener('fullscreenchange', this.fullscreenChangeBind);\n window.removeEventListener('mozfullscreenchange',\n this.fullscreenChangeBind);\n if (typeof PDFJSDev === 'undefined' ||\n !PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n window.removeEventListener('webkitfullscreenchange',\n this.fullscreenChangeBind);\n window.removeEventListener('MSFullscreenChange',\n this.fullscreenChangeBind);\n }\n\n delete this.fullscreenChangeBind;\n }\n}\n\nexport {\n PDFPresentationMode,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/pdf_presentation_mode.js", + "/* Copyright 2016 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { NullL10n } from './ui_utils';\nimport { RenderingStates } from './pdf_rendering_queue';\n\nconst UI_NOTIFICATION_CLASS = 'pdfSidebarNotification';\n\nconst SidebarView = {\n NONE: 0,\n THUMBS: 1,\n OUTLINE: 2,\n ATTACHMENTS: 3,\n};\n\n/**\n * @typedef {Object} PDFSidebarOptions\n * @property {PDFViewer} pdfViewer - The document viewer.\n * @property {PDFThumbnailViewer} pdfThumbnailViewer - The thumbnail viewer.\n * @property {PDFOutlineViewer} pdfOutlineViewer - The outline viewer.\n * @property {HTMLDivElement} mainContainer - The main container\n * (in which the viewer element is placed).\n * @property {HTMLDivElement} outerContainer - The outer container\n * (encasing both the viewer and sidebar elements).\n * @property {EventBus} eventBus - The application event bus.\n * @property {HTMLButtonElement} toggleButton - The button used for\n * opening/closing the sidebar.\n * @property {HTMLButtonElement} thumbnailButton - The button used to show\n * the thumbnail view.\n * @property {HTMLButtonElement} outlineButton - The button used to show\n * the outline view.\n * @property {HTMLButtonElement} attachmentsButton - The button used to show\n * the attachments view.\n * @property {HTMLDivElement} thumbnailView - The container in which\n * the thumbnails are placed.\n * @property {HTMLDivElement} outlineView - The container in which\n * the outline is placed.\n * @property {HTMLDivElement} attachmentsView - The container in which\n * the attachments are placed.\n * @property {boolean} disableNotification - (optional) Disable the notification\n * for documents containing outline/attachments. The default value is `false`.\n */\n\nclass PDFSidebar {\n /**\n * @param {PDFSidebarOptions} options\n * @param {IL10n} l10n - Localization service.\n */\n constructor(options, l10n = NullL10n) {\n this.isOpen = false;\n this.active = SidebarView.THUMBS;\n this.isInitialViewSet = false;\n\n /**\n * Callback used when the sidebar has been opened/closed, to ensure that\n * the viewers (PDFViewer/PDFThumbnailViewer) are updated correctly.\n */\n this.onToggled = null;\n\n this.pdfViewer = options.pdfViewer;\n this.pdfThumbnailViewer = options.pdfThumbnailViewer;\n this.pdfOutlineViewer = options.pdfOutlineViewer;\n\n this.mainContainer = options.mainContainer;\n this.outerContainer = options.outerContainer;\n this.eventBus = options.eventBus;\n this.toggleButton = options.toggleButton;\n\n this.thumbnailButton = options.thumbnailButton;\n this.outlineButton = options.outlineButton;\n this.attachmentsButton = options.attachmentsButton;\n\n this.thumbnailView = options.thumbnailView;\n this.outlineView = options.outlineView;\n this.attachmentsView = options.attachmentsView;\n\n this.disableNotification = options.disableNotification || false;\n\n this.l10n = l10n;\n\n this._addEventListeners();\n }\n\n reset() {\n this.isInitialViewSet = false;\n\n this._hideUINotification(null);\n this.switchView(SidebarView.THUMBS);\n\n this.outlineButton.disabled = false;\n this.attachmentsButton.disabled = false;\n }\n\n /**\n * @returns {number} One of the values in {SidebarView}.\n */\n get visibleView() {\n return (this.isOpen ? this.active : SidebarView.NONE);\n }\n\n get isThumbnailViewVisible() {\n return (this.isOpen && this.active === SidebarView.THUMBS);\n }\n\n get isOutlineViewVisible() {\n return (this.isOpen && this.active === SidebarView.OUTLINE);\n }\n\n get isAttachmentsViewVisible() {\n return (this.isOpen && this.active === SidebarView.ATTACHMENTS);\n }\n\n /**\n * @param {number} view - The sidebar view that should become visible,\n * must be one of the values in {SidebarView}.\n */\n setInitialView(view) {\n if (this.isInitialViewSet) {\n return;\n }\n this.isInitialViewSet = true;\n\n if (this.isOpen && view === SidebarView.NONE) {\n this._dispatchEvent();\n // If the user has already manually opened the sidebar,\n // immediately closing it would be bad UX.\n return;\n }\n let isViewPreserved = (view === this.visibleView);\n this.switchView(view, /* forceOpen */ true);\n\n if (isViewPreserved) {\n // Prevent dispatching two back-to-back `sidebarviewchanged` events,\n // since `this.switchView` dispatched the event if the view changed.\n this._dispatchEvent();\n }\n }\n\n /**\n * @param {number} view - The sidebar view that should be switched to,\n * must be one of the values in {SidebarView}.\n * @param {boolean} forceOpen - (optional) Ensure that the sidebar is open.\n * The default value is `false`.\n */\n switchView(view, forceOpen = false) {\n if (view === SidebarView.NONE) {\n this.close();\n return;\n }\n let isViewChanged = (view !== this.active);\n let shouldForceRendering = false;\n\n switch (view) {\n case SidebarView.THUMBS:\n this.thumbnailButton.classList.add('toggled');\n this.outlineButton.classList.remove('toggled');\n this.attachmentsButton.classList.remove('toggled');\n\n this.thumbnailView.classList.remove('hidden');\n this.outlineView.classList.add('hidden');\n this.attachmentsView.classList.add('hidden');\n\n if (this.isOpen && isViewChanged) {\n this._updateThumbnailViewer();\n shouldForceRendering = true;\n }\n break;\n case SidebarView.OUTLINE:\n if (this.outlineButton.disabled) {\n return;\n }\n this.thumbnailButton.classList.remove('toggled');\n this.outlineButton.classList.add('toggled');\n this.attachmentsButton.classList.remove('toggled');\n\n this.thumbnailView.classList.add('hidden');\n this.outlineView.classList.remove('hidden');\n this.attachmentsView.classList.add('hidden');\n break;\n case SidebarView.ATTACHMENTS:\n if (this.attachmentsButton.disabled) {\n return;\n }\n this.thumbnailButton.classList.remove('toggled');\n this.outlineButton.classList.remove('toggled');\n this.attachmentsButton.classList.add('toggled');\n\n this.thumbnailView.classList.add('hidden');\n this.outlineView.classList.add('hidden');\n this.attachmentsView.classList.remove('hidden');\n break;\n default:\n console.error('PDFSidebar_switchView: \"' + view +\n '\" is an unsupported value.');\n return;\n }\n // Update the active view *after* it has been validated above,\n // in order to prevent setting it to an invalid state.\n this.active = view | 0;\n\n if (forceOpen && !this.isOpen) {\n this.open();\n return; // NOTE: Opening will trigger rendering, and dispatch the event.\n }\n if (shouldForceRendering) {\n this._forceRendering();\n }\n if (isViewChanged) {\n this._dispatchEvent();\n }\n this._hideUINotification(this.active);\n }\n\n open() {\n if (this.isOpen) {\n return;\n }\n this.isOpen = true;\n this.toggleButton.classList.add('toggled');\n\n this.outerContainer.classList.add('sidebarMoving');\n this.outerContainer.classList.add('sidebarOpen');\n\n if (this.active === SidebarView.THUMBS) {\n this._updateThumbnailViewer();\n }\n this._forceRendering();\n this._dispatchEvent();\n\n this._hideUINotification(this.active);\n }\n\n close() {\n if (!this.isOpen) {\n return;\n }\n this.isOpen = false;\n this.toggleButton.classList.remove('toggled');\n\n this.outerContainer.classList.add('sidebarMoving');\n this.outerContainer.classList.remove('sidebarOpen');\n\n this._forceRendering();\n this._dispatchEvent();\n }\n\n toggle() {\n if (this.isOpen) {\n this.close();\n } else {\n this.open();\n }\n }\n\n /**\n * @private\n */\n _dispatchEvent() {\n this.eventBus.dispatch('sidebarviewchanged', {\n source: this,\n view: this.visibleView,\n });\n }\n\n /**\n * @private\n */\n _forceRendering() {\n if (this.onToggled) {\n this.onToggled();\n } else { // Fallback\n this.pdfViewer.forceRendering();\n this.pdfThumbnailViewer.forceRendering();\n }\n }\n\n /**\n * @private\n */\n _updateThumbnailViewer() {\n let { pdfViewer, pdfThumbnailViewer, } = this;\n\n // Use the rendered pages to set the corresponding thumbnail images.\n let pagesCount = pdfViewer.pagesCount;\n for (let pageIndex = 0; pageIndex < pagesCount; pageIndex++) {\n let pageView = pdfViewer.getPageView(pageIndex);\n if (pageView && pageView.renderingState === RenderingStates.FINISHED) {\n let thumbnailView = pdfThumbnailViewer.getThumbnail(pageIndex);\n thumbnailView.setImage(pageView);\n }\n }\n pdfThumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber);\n }\n\n /**\n * @private\n */\n _showUINotification(view) {\n if (this.disableNotification) {\n return;\n }\n\n this.l10n.get('toggle_sidebar_notification.title', null,\n 'Toggle Sidebar (document contains outline/attachments)').\n then((msg) => {\n this.toggleButton.title = msg;\n });\n\n if (!this.isOpen) {\n // Only show the notification on the `toggleButton` if the sidebar is\n // currently closed, to avoid unnecessarily bothering the user.\n this.toggleButton.classList.add(UI_NOTIFICATION_CLASS);\n } else if (view === this.active) {\n // If the sidebar is currently open *and* the `view` is visible, do not\n // bother the user with a notification on the corresponding button.\n return;\n }\n\n switch (view) {\n case SidebarView.OUTLINE:\n this.outlineButton.classList.add(UI_NOTIFICATION_CLASS);\n break;\n case SidebarView.ATTACHMENTS:\n this.attachmentsButton.classList.add(UI_NOTIFICATION_CLASS);\n break;\n }\n }\n\n /**\n * @private\n */\n _hideUINotification(view) {\n if (this.disableNotification) {\n return;\n }\n\n let removeNotification = (view) => {\n switch (view) {\n case SidebarView.OUTLINE:\n this.outlineButton.classList.remove(UI_NOTIFICATION_CLASS);\n break;\n case SidebarView.ATTACHMENTS:\n this.attachmentsButton.classList.remove(UI_NOTIFICATION_CLASS);\n break;\n }\n };\n\n if (!this.isOpen && view !== null) {\n // Only hide the notifications when the sidebar is currently open,\n // or when it is being reset (i.e. `view === null`).\n return;\n }\n this.toggleButton.classList.remove(UI_NOTIFICATION_CLASS);\n\n if (view !== null) {\n removeNotification(view);\n return;\n }\n for (view in SidebarView) { // Remove all sidebar notifications on reset.\n removeNotification(SidebarView[view]);\n }\n\n this.l10n.get('toggle_sidebar.title', null, 'Toggle Sidebar').\n then((msg) => {\n this.toggleButton.title = msg;\n });\n }\n\n /**\n * @private\n */\n _addEventListeners() {\n this.mainContainer.addEventListener('transitionend', (evt) => {\n if (evt.target === this.mainContainer) {\n this.outerContainer.classList.remove('sidebarMoving');\n }\n });\n\n // Buttons for switching views.\n this.thumbnailButton.addEventListener('click', () => {\n this.switchView(SidebarView.THUMBS);\n });\n\n this.outlineButton.addEventListener('click', () => {\n this.switchView(SidebarView.OUTLINE);\n });\n this.outlineButton.addEventListener('dblclick', () => {\n this.pdfOutlineViewer.toggleOutlineTree();\n });\n\n this.attachmentsButton.addEventListener('click', () => {\n this.switchView(SidebarView.ATTACHMENTS);\n });\n\n // Disable/enable views.\n this.eventBus.on('outlineloaded', (evt) => {\n let outlineCount = evt.outlineCount;\n\n this.outlineButton.disabled = !outlineCount;\n\n if (outlineCount) {\n this._showUINotification(SidebarView.OUTLINE);\n } else if (this.active === SidebarView.OUTLINE) {\n // If the outline view was opened during document load, switch away\n // from it if it turns out that the document has no outline.\n this.switchView(SidebarView.THUMBS);\n }\n });\n\n this.eventBus.on('attachmentsloaded', (evt) => {\n let attachmentsCount = evt.attachmentsCount;\n\n this.attachmentsButton.disabled = !attachmentsCount;\n\n if (attachmentsCount) {\n this._showUINotification(SidebarView.ATTACHMENTS);\n } else if (this.active === SidebarView.ATTACHMENTS) {\n // If the attachment view was opened during document load, switch away\n // from it if it turns out that the document has no attachments.\n this.switchView(SidebarView.THUMBS);\n }\n });\n\n // Update the thumbnailViewer, if visible, when exiting presentation mode.\n this.eventBus.on('presentationmodechanged', (evt) => {\n if (!evt.active && !evt.switchInProgress && this.isThumbnailViewVisible) {\n this._updateThumbnailViewer();\n }\n });\n }\n}\n\nexport {\n SidebarView,\n PDFSidebar,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/pdf_sidebar.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createPromiseCapability, RenderingCancelledException\n} from 'pdfjs-lib';\nimport { getOutputScale, NullL10n } from './ui_utils';\nimport { RenderingStates } from './pdf_rendering_queue';\n\nconst MAX_NUM_SCALING_STEPS = 3;\nconst THUMBNAIL_CANVAS_BORDER_WIDTH = 1; // px\nconst THUMBNAIL_WIDTH = 98; // px\n\n/**\n * @typedef {Object} PDFThumbnailViewOptions\n * @property {HTMLDivElement} container - The viewer element.\n * @property {number} id - The thumbnail's unique ID (normally its number).\n * @property {PageViewport} defaultViewport - The page viewport.\n * @property {IPDFLinkService} linkService - The navigation/linking service.\n * @property {PDFRenderingQueue} renderingQueue - The rendering queue object.\n * @property {boolean} disableCanvasToImageConversion - (optional) Don't convert\n * the canvas thumbnails to images. This prevents `toDataURL` calls,\n * but increases the overall memory usage. The default value is `false`.\n * @property {IL10n} l10n - Localization service.\n */\n\nconst TempImageFactory = (function TempImageFactoryClosure() {\n let tempCanvasCache = null;\n\n return {\n getCanvas(width, height) {\n let tempCanvas = tempCanvasCache;\n if (!tempCanvas) {\n tempCanvas = document.createElement('canvas');\n tempCanvasCache = tempCanvas;\n }\n tempCanvas.width = width;\n tempCanvas.height = height;\n\n // Since this is a temporary canvas, we need to fill it with a white\n // background ourselves. `_getPageDrawContext` uses CSS rules for this.\n if (typeof PDFJSDev === 'undefined' ||\n PDFJSDev.test('MOZCENTRAL || FIREFOX || GENERIC')) {\n tempCanvas.mozOpaque = true;\n }\n\n let ctx = tempCanvas.getContext('2d', { alpha: false, });\n ctx.save();\n ctx.fillStyle = 'rgb(255, 255, 255)';\n ctx.fillRect(0, 0, width, height);\n ctx.restore();\n return tempCanvas;\n },\n\n destroyCanvas() {\n let tempCanvas = tempCanvasCache;\n if (tempCanvas) {\n // Zeroing the width and height causes Firefox to release graphics\n // resources immediately, which can greatly reduce memory consumption.\n tempCanvas.width = 0;\n tempCanvas.height = 0;\n }\n tempCanvasCache = null;\n },\n };\n})();\n\n/**\n * @implements {IRenderableView}\n */\nclass PDFThumbnailView {\n /**\n * @param {PDFThumbnailViewOptions} options\n */\n constructor({ container, id, defaultViewport, linkService, renderingQueue,\n disableCanvasToImageConversion = false, l10n = NullL10n, }) {\n this.id = id;\n this.renderingId = 'thumbnail' + id;\n this.pageLabel = null;\n\n this.pdfPage = null;\n this.rotation = 0;\n this.viewport = defaultViewport;\n this.pdfPageRotate = defaultViewport.rotation;\n\n this.linkService = linkService;\n this.renderingQueue = renderingQueue;\n\n this.renderTask = null;\n this.renderingState = RenderingStates.INITIAL;\n this.resume = null;\n this.disableCanvasToImageConversion = disableCanvasToImageConversion;\n\n this.pageWidth = this.viewport.width;\n this.pageHeight = this.viewport.height;\n this.pageRatio = this.pageWidth / this.pageHeight;\n\n this.canvasWidth = THUMBNAIL_WIDTH;\n this.canvasHeight = (this.canvasWidth / this.pageRatio) | 0;\n this.scale = this.canvasWidth / this.pageWidth;\n\n this.l10n = l10n;\n\n let anchor = document.createElement('a');\n anchor.href = linkService.getAnchorUrl('#page=' + id);\n this.l10n.get('thumb_page_title', { page: id, }, 'Page {{page}}').\n then((msg) => {\n anchor.title = msg;\n });\n anchor.onclick = function() {\n linkService.page = id;\n return false;\n };\n this.anchor = anchor;\n\n let div = document.createElement('div');\n div.className = 'thumbnail';\n div.setAttribute('data-page-number', this.id);\n this.div = div;\n\n if (id === 1) {\n // Highlight the thumbnail of the first page when no page number is\n // specified (or exists in cache) when the document is loaded.\n div.classList.add('selected');\n }\n\n let ring = document.createElement('div');\n ring.className = 'thumbnailSelectionRing';\n let borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH;\n ring.style.width = this.canvasWidth + borderAdjustment + 'px';\n ring.style.height = this.canvasHeight + borderAdjustment + 'px';\n this.ring = ring;\n\n div.appendChild(ring);\n anchor.appendChild(div);\n container.appendChild(anchor);\n }\n\n setPdfPage(pdfPage) {\n this.pdfPage = pdfPage;\n this.pdfPageRotate = pdfPage.rotate;\n let totalRotation = (this.rotation + this.pdfPageRotate) % 360;\n this.viewport = pdfPage.getViewport(1, totalRotation);\n this.reset();\n }\n\n reset() {\n this.cancelRendering();\n\n this.pageWidth = this.viewport.width;\n this.pageHeight = this.viewport.height;\n this.pageRatio = this.pageWidth / this.pageHeight;\n\n this.canvasHeight = (this.canvasWidth / this.pageRatio) | 0;\n this.scale = (this.canvasWidth / this.pageWidth);\n\n this.div.removeAttribute('data-loaded');\n let ring = this.ring;\n let childNodes = ring.childNodes;\n for (let i = childNodes.length - 1; i >= 0; i--) {\n ring.removeChild(childNodes[i]);\n }\n let borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH;\n ring.style.width = this.canvasWidth + borderAdjustment + 'px';\n ring.style.height = this.canvasHeight + borderAdjustment + 'px';\n\n if (this.canvas) {\n // Zeroing the width and height causes Firefox to release graphics\n // resources immediately, which can greatly reduce memory consumption.\n this.canvas.width = 0;\n this.canvas.height = 0;\n delete this.canvas;\n }\n if (this.image) {\n this.image.removeAttribute('src');\n delete this.image;\n }\n }\n\n update(rotation) {\n if (typeof rotation !== 'undefined') {\n this.rotation = rotation;\n }\n let totalRotation = (this.rotation + this.pdfPageRotate) % 360;\n this.viewport = this.viewport.clone({\n scale: 1,\n rotation: totalRotation,\n });\n this.reset();\n }\n\n cancelRendering() {\n if (this.renderTask) {\n this.renderTask.cancel();\n this.renderTask = null;\n }\n this.renderingState = RenderingStates.INITIAL;\n this.resume = null;\n }\n\n /**\n * @private\n */\n _getPageDrawContext(noCtxScale = false) {\n let canvas = document.createElement('canvas');\n // Keep the no-thumbnail outline visible, i.e. `data-loaded === false`,\n // until rendering/image conversion is complete, to avoid display issues.\n this.canvas = canvas;\n\n if (typeof PDFJSDev === 'undefined' ||\n PDFJSDev.test('MOZCENTRAL || FIREFOX || GENERIC')) {\n canvas.mozOpaque = true;\n }\n let ctx = canvas.getContext('2d', { alpha: false, });\n let outputScale = getOutputScale(ctx);\n\n canvas.width = (this.canvasWidth * outputScale.sx) | 0;\n canvas.height = (this.canvasHeight * outputScale.sy) | 0;\n canvas.style.width = this.canvasWidth + 'px';\n canvas.style.height = this.canvasHeight + 'px';\n\n if (!noCtxScale && outputScale.scaled) {\n ctx.scale(outputScale.sx, outputScale.sy);\n }\n return ctx;\n }\n\n /**\n * @private\n */\n _convertCanvasToImage() {\n if (!this.canvas) {\n return;\n }\n if (this.renderingState !== RenderingStates.FINISHED) {\n return;\n }\n let id = this.renderingId;\n let className = 'thumbnailImage';\n\n if (this.disableCanvasToImageConversion) {\n this.canvas.id = id;\n this.canvas.className = className;\n this.l10n.get('thumb_page_canvas', { page: this.pageId, },\n 'Thumbnail of Page {{page}}').then((msg) => {\n this.canvas.setAttribute('aria-label', msg);\n });\n\n this.div.setAttribute('data-loaded', true);\n this.ring.appendChild(this.canvas);\n return;\n }\n let image = document.createElement('img');\n image.id = id;\n image.className = className;\n this.l10n.get('thumb_page_canvas', { page: this.pageId, },\n 'Thumbnail of Page {{page}}').\n then((msg) => {\n image.setAttribute('aria-label', msg);\n });\n\n image.style.width = this.canvasWidth + 'px';\n image.style.height = this.canvasHeight + 'px';\n\n image.src = this.canvas.toDataURL();\n this.image = image;\n\n this.div.setAttribute('data-loaded', true);\n this.ring.appendChild(image);\n\n // Zeroing the width and height causes Firefox to release graphics\n // resources immediately, which can greatly reduce memory consumption.\n this.canvas.width = 0;\n this.canvas.height = 0;\n delete this.canvas;\n }\n\n draw() {\n if (this.renderingState !== RenderingStates.INITIAL) {\n console.error('Must be in new state before drawing');\n return Promise.resolve(undefined);\n }\n this.renderingState = RenderingStates.RUNNING;\n\n let renderCapability = createPromiseCapability();\n let finishRenderTask = (error) => {\n // The renderTask may have been replaced by a new one, so only remove\n // the reference to the renderTask if it matches the one that is\n // triggering this callback.\n if (renderTask === this.renderTask) {\n this.renderTask = null;\n }\n\n if (((typeof PDFJSDev === 'undefined' ||\n !PDFJSDev.test('PDFJS_NEXT')) && error === 'cancelled') ||\n error instanceof RenderingCancelledException) {\n renderCapability.resolve(undefined);\n return;\n }\n\n this.renderingState = RenderingStates.FINISHED;\n this._convertCanvasToImage();\n\n if (!error) {\n renderCapability.resolve(undefined);\n } else {\n renderCapability.reject(error);\n }\n };\n\n let ctx = this._getPageDrawContext();\n let drawViewport = this.viewport.clone({ scale: this.scale, });\n let renderContinueCallback = (cont) => {\n if (!this.renderingQueue.isHighestPriority(this)) {\n this.renderingState = RenderingStates.PAUSED;\n this.resume = () => {\n this.renderingState = RenderingStates.RUNNING;\n cont();\n };\n return;\n }\n cont();\n };\n\n let renderContext = {\n canvasContext: ctx,\n viewport: drawViewport,\n };\n let renderTask = this.renderTask = this.pdfPage.render(renderContext);\n renderTask.onContinue = renderContinueCallback;\n\n renderTask.promise.then(function() {\n finishRenderTask(null);\n }, function(error) {\n finishRenderTask(error);\n });\n return renderCapability.promise;\n }\n\n setImage(pageView) {\n if (this.renderingState !== RenderingStates.INITIAL) {\n return;\n }\n let img = pageView.canvas;\n if (!img) {\n return;\n }\n if (!this.pdfPage) {\n this.setPdfPage(pageView.pdfPage);\n }\n\n this.renderingState = RenderingStates.FINISHED;\n\n let ctx = this._getPageDrawContext(true);\n let canvas = ctx.canvas;\n if (img.width <= 2 * canvas.width) {\n ctx.drawImage(img, 0, 0, img.width, img.height,\n 0, 0, canvas.width, canvas.height);\n this._convertCanvasToImage();\n return;\n }\n\n // drawImage does an awful job of rescaling the image, doing it gradually.\n let reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS;\n let reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS;\n let reducedImage = TempImageFactory.getCanvas(reducedWidth,\n reducedHeight);\n let reducedImageCtx = reducedImage.getContext('2d');\n\n while (reducedWidth > img.width || reducedHeight > img.height) {\n reducedWidth >>= 1;\n reducedHeight >>= 1;\n }\n reducedImageCtx.drawImage(img, 0, 0, img.width, img.height,\n 0, 0, reducedWidth, reducedHeight);\n while (reducedWidth > 2 * canvas.width) {\n reducedImageCtx.drawImage(reducedImage,\n 0, 0, reducedWidth, reducedHeight,\n 0, 0, reducedWidth >> 1, reducedHeight >> 1);\n reducedWidth >>= 1;\n reducedHeight >>= 1;\n }\n ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight,\n 0, 0, canvas.width, canvas.height);\n this._convertCanvasToImage();\n }\n\n get pageId() {\n return (this.pageLabel !== null ? this.pageLabel : this.id);\n }\n\n /**\n * @param {string|null} label\n */\n setPageLabel(label) {\n this.pageLabel = (typeof label === 'string' ? label : null);\n\n this.l10n.get('thumb_page_title', { page: this.pageId, },\n 'Page {{page}}').then((msg) => {\n this.anchor.title = msg;\n });\n\n if (this.renderingState !== RenderingStates.FINISHED) {\n return;\n }\n\n this.l10n.get('thumb_page_canvas', { page: this.pageId, },\n 'Thumbnail of Page {{page}}').then((ariaLabel) => {\n if (this.image) {\n this.image.setAttribute('aria-label', ariaLabel);\n } else if (this.disableCanvasToImageConversion && this.canvas) {\n this.canvas.setAttribute('aria-label', ariaLabel);\n }\n });\n }\n\n static cleanup() {\n TempImageFactory.destroyCanvas();\n }\n}\n\nexport {\n PDFThumbnailView,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/pdf_thumbnail_view.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n getVisibleElements, NullL10n, scrollIntoView, watchScroll\n} from './ui_utils';\nimport { PDFThumbnailView } from './pdf_thumbnail_view';\n\nconst THUMBNAIL_SCROLL_MARGIN = -19;\n\n/**\n * @typedef {Object} PDFThumbnailViewerOptions\n * @property {HTMLDivElement} container - The container for the thumbnail\n * elements.\n * @property {IPDFLinkService} linkService - The navigation/linking service.\n * @property {PDFRenderingQueue} renderingQueue - The rendering queue object.\n * @property {IL10n} l10n - Localization service.\n */\n\n/**\n * Viewer control to display thumbnails for pages in a PDF document.\n *\n * @implements {IRenderableView}\n */\nclass PDFThumbnailViewer {\n /**\n * @param {PDFThumbnailViewerOptions} options\n */\n constructor({ container, linkService, renderingQueue, l10n = NullL10n, }) {\n this.container = container;\n this.linkService = linkService;\n this.renderingQueue = renderingQueue;\n this.l10n = l10n;\n\n this.scroll = watchScroll(this.container, this._scrollUpdated.bind(this));\n this._resetView();\n }\n\n /**\n * @private\n */\n _scrollUpdated() {\n this.renderingQueue.renderHighestPriority();\n }\n\n getThumbnail(index) {\n return this._thumbnails[index];\n }\n\n /**\n * @private\n */\n _getVisibleThumbs() {\n return getVisibleElements(this.container, this._thumbnails);\n }\n\n scrollThumbnailIntoView(page) {\n let selected = document.querySelector('.thumbnail.selected');\n if (selected) {\n selected.classList.remove('selected');\n }\n let thumbnail = document.querySelector(\n 'div.thumbnail[data-page-number=\"' + page + '\"]');\n if (thumbnail) {\n thumbnail.classList.add('selected');\n }\n let visibleThumbs = this._getVisibleThumbs();\n let numVisibleThumbs = visibleThumbs.views.length;\n\n // If the thumbnail isn't currently visible, scroll it into view.\n if (numVisibleThumbs > 0) {\n let first = visibleThumbs.first.id;\n // Account for only one thumbnail being visible.\n let last = (numVisibleThumbs > 1 ? visibleThumbs.last.id : first);\n if (page <= first || page >= last) {\n scrollIntoView(thumbnail, { top: THUMBNAIL_SCROLL_MARGIN, });\n }\n }\n }\n\n get pagesRotation() {\n return this._pagesRotation;\n }\n\n set pagesRotation(rotation) {\n if (!(typeof rotation === 'number' && rotation % 90 === 0)) {\n throw new Error('Invalid thumbnails rotation angle.');\n }\n if (!this.pdfDocument) {\n return;\n }\n this._pagesRotation = rotation;\n\n for (let i = 0, ii = this._thumbnails.length; i < ii; i++) {\n this._thumbnails[i].update(rotation);\n }\n }\n\n cleanup() {\n PDFThumbnailView.cleanup();\n }\n\n /**\n * @private\n */\n _resetView() {\n this._thumbnails = [];\n this._pageLabels = null;\n this._pagesRotation = 0;\n this._pagesRequests = [];\n\n // Remove the thumbnails from the DOM.\n this.container.textContent = '';\n }\n\n setDocument(pdfDocument) {\n if (this.pdfDocument) {\n this._cancelRendering();\n this._resetView();\n }\n\n this.pdfDocument = pdfDocument;\n if (!pdfDocument) {\n return;\n }\n\n pdfDocument.getPage(1).then((firstPage) => {\n let pagesCount = pdfDocument.numPages;\n let viewport = firstPage.getViewport(1.0);\n for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) {\n let thumbnail = new PDFThumbnailView({\n container: this.container,\n id: pageNum,\n defaultViewport: viewport.clone(),\n linkService: this.linkService,\n renderingQueue: this.renderingQueue,\n disableCanvasToImageConversion: false,\n l10n: this.l10n,\n });\n this._thumbnails.push(thumbnail);\n }\n }).catch((reason) => {\n console.error('Unable to initialize thumbnail viewer', reason);\n });\n }\n\n /**\n * @private\n */\n _cancelRendering() {\n for (let i = 0, ii = this._thumbnails.length; i < ii; i++) {\n if (this._thumbnails[i]) {\n this._thumbnails[i].cancelRendering();\n }\n }\n }\n\n /**\n * @param {Array|null} labels\n */\n setPageLabels(labels) {\n if (!this.pdfDocument) {\n return;\n }\n if (!labels) {\n this._pageLabels = null;\n } else if (!(labels instanceof Array &&\n this.pdfDocument.numPages === labels.length)) {\n this._pageLabels = null;\n console.error('PDFThumbnailViewer_setPageLabels: Invalid page labels.');\n } else {\n this._pageLabels = labels;\n }\n // Update all the `PDFThumbnailView` instances.\n for (let i = 0, ii = this._thumbnails.length; i < ii; i++) {\n let label = this._pageLabels && this._pageLabels[i];\n this._thumbnails[i].setPageLabel(label);\n }\n }\n\n /**\n * @param {PDFThumbnailView} thumbView\n * @returns {PDFPage}\n * @private\n */\n _ensurePdfPageLoaded(thumbView) {\n if (thumbView.pdfPage) {\n return Promise.resolve(thumbView.pdfPage);\n }\n let pageNumber = thumbView.id;\n if (this._pagesRequests[pageNumber]) {\n return this._pagesRequests[pageNumber];\n }\n let promise = this.pdfDocument.getPage(pageNumber).then((pdfPage) => {\n thumbView.setPdfPage(pdfPage);\n this._pagesRequests[pageNumber] = null;\n return pdfPage;\n }).catch((reason) => {\n console.error('Unable to get page for thumb view', reason);\n // Page error -- there is nothing can be done.\n this._pagesRequests[pageNumber] = null;\n });\n this._pagesRequests[pageNumber] = promise;\n return promise;\n }\n\n forceRendering() {\n let visibleThumbs = this._getVisibleThumbs();\n let thumbView = this.renderingQueue.getHighestPriority(visibleThumbs,\n this._thumbnails,\n this.scroll.down);\n if (thumbView) {\n this._ensurePdfPageLoaded(thumbView).then(() => {\n this.renderingQueue.renderView(thumbView);\n });\n return true;\n }\n return false;\n }\n}\n\nexport {\n PDFThumbnailViewer,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/pdf_thumbnail_viewer.js", + "/* Copyright 2014 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createPromiseCapability, PDFJS } from 'pdfjs-lib';\nimport {\n CSS_UNITS, DEFAULT_SCALE, DEFAULT_SCALE_VALUE, getVisibleElements,\n MAX_AUTO_SCALE, NullL10n, RendererType, SCROLLBAR_PADDING, scrollIntoView,\n UNKNOWN_SCALE, VERTICAL_PADDING, watchScroll\n} from './ui_utils';\nimport { PDFRenderingQueue, RenderingStates } from './pdf_rendering_queue';\nimport { AnnotationLayerBuilder } from './annotation_layer_builder';\nimport { getGlobalEventBus } from './dom_events';\nimport { PDFPageView } from './pdf_page_view';\nimport { SimpleLinkService } from './pdf_link_service';\nimport { TextLayerBuilder } from './text_layer_builder';\n\nconst PresentationModeState = {\n UNKNOWN: 0,\n NORMAL: 1,\n CHANGING: 2,\n FULLSCREEN: 3,\n};\n\nconst DEFAULT_CACHE_SIZE = 10;\n\n/**\n * @typedef {Object} PDFViewerOptions\n * @property {HTMLDivElement} container - The container for the viewer element.\n * @property {HTMLDivElement} viewer - (optional) The viewer element.\n * @property {EventBus} eventBus - The application event bus.\n * @property {IPDFLinkService} linkService - The navigation/linking service.\n * @property {DownloadManager} downloadManager - (optional) The download\n * manager component.\n * @property {PDFRenderingQueue} renderingQueue - (optional) The rendering\n * queue object.\n * @property {boolean} removePageBorders - (optional) Removes the border shadow\n * around the pages. The default is false.\n * @property {boolean} enhanceTextSelection - (optional) Enables the improved\n * text selection behaviour. The default is `false`.\n * @property {boolean} renderInteractiveForms - (optional) Enables rendering of\n * interactive form elements. The default is `false`.\n * @property {boolean} enablePrintAutoRotate - (optional) Enables automatic\n * rotation of pages whose orientation differ from the first page upon\n * printing. The default is `false`.\n * @property {string} renderer - 'canvas' or 'svg'. The default is 'canvas'.\n * @property {IL10n} l10n - Localization service.\n */\n\nfunction PDFPageViewBuffer(size) {\n let data = [];\n this.push = function cachePush(view) {\n let i = data.indexOf(view);\n if (i >= 0) {\n data.splice(i, 1);\n }\n data.push(view);\n if (data.length > size) {\n data.shift().destroy();\n }\n };\n this.resize = function (newSize) {\n size = newSize;\n while (data.length > size) {\n data.shift().destroy();\n }\n };\n}\n\nfunction isSameScale(oldScale, newScale) {\n if (newScale === oldScale) {\n return true;\n }\n if (Math.abs(newScale - oldScale) < 1e-15) {\n // Prevent unnecessary re-rendering of all pages when the scale\n // changes only because of limited numerical precision.\n return true;\n }\n return false;\n}\n\nfunction isPortraitOrientation(size) {\n return size.width <= size.height;\n}\n\n/**\n * Simple viewer control to display PDF content/pages.\n * @implements {IRenderableView}\n */\nclass PDFViewer {\n /**\n * @param {PDFViewerOptions} options\n */\n constructor(options) {\n this.container = options.container;\n this.viewer = options.viewer || options.container.firstElementChild;\n this.eventBus = options.eventBus || getGlobalEventBus();\n this.linkService = options.linkService || new SimpleLinkService();\n this.downloadManager = options.downloadManager || null;\n this.removePageBorders = options.removePageBorders || false;\n this.enhanceTextSelection = options.enhanceTextSelection || false;\n this.renderInteractiveForms = options.renderInteractiveForms || false;\n this.enablePrintAutoRotate = options.enablePrintAutoRotate || false;\n this.renderer = options.renderer || RendererType.CANVAS;\n this.l10n = options.l10n || NullL10n;\n\n this.defaultRenderingQueue = !options.renderingQueue;\n if (this.defaultRenderingQueue) {\n // Custom rendering queue is not specified, using default one\n this.renderingQueue = new PDFRenderingQueue();\n this.renderingQueue.setViewer(this);\n } else {\n this.renderingQueue = options.renderingQueue;\n }\n\n this.scroll = watchScroll(this.container, this._scrollUpdate.bind(this));\n this.presentationModeState = PresentationModeState.UNKNOWN;\n this._resetView();\n\n if (this.removePageBorders) {\n this.viewer.classList.add('removePageBorders');\n }\n }\n\n get pagesCount() {\n return this._pages.length;\n }\n\n getPageView(index) {\n return this._pages[index];\n }\n\n /**\n * @returns {boolean} true if all {PDFPageView} objects are initialized.\n */\n get pageViewsReady() {\n return this._pageViewsReady;\n }\n\n /**\n * @returns {number}\n */\n get currentPageNumber() {\n return this._currentPageNumber;\n }\n\n /**\n * @param {number} val - The page number.\n */\n set currentPageNumber(val) {\n if ((val | 0) !== val) { // Ensure that `val` is an integer.\n throw new Error('Invalid page number.');\n }\n if (!this.pdfDocument) {\n return;\n }\n // The intent can be to just reset a scroll position and/or scale.\n this._setCurrentPageNumber(val, /* resetCurrentPageView = */ true);\n }\n\n /**\n * @private\n */\n _setCurrentPageNumber(val, resetCurrentPageView = false) {\n if (this._currentPageNumber === val) {\n if (resetCurrentPageView) {\n this._resetCurrentPageView();\n }\n return;\n }\n\n if (!(0 < val && val <= this.pagesCount)) {\n console.error(\n `PDFViewer._setCurrentPageNumber: \"${val}\" is out of bounds.`);\n return;\n }\n\n let arg = {\n source: this,\n pageNumber: val,\n pageLabel: this._pageLabels && this._pageLabels[val - 1],\n };\n this._currentPageNumber = val;\n this.eventBus.dispatch('pagechanging', arg);\n this.eventBus.dispatch('pagechange', arg);\n\n if (resetCurrentPageView) {\n this._resetCurrentPageView();\n }\n }\n\n /**\n * @returns {string|null} Returns the current page label,\n * or `null` if no page labels exist.\n */\n get currentPageLabel() {\n return this._pageLabels && this._pageLabels[this._currentPageNumber - 1];\n }\n\n /**\n * @param {string} val - The page label.\n */\n set currentPageLabel(val) {\n let pageNumber = val | 0; // Fallback page number.\n if (this._pageLabels) {\n let i = this._pageLabels.indexOf(val);\n if (i >= 0) {\n pageNumber = i + 1;\n }\n }\n this.currentPageNumber = pageNumber;\n }\n\n /**\n * @returns {number}\n */\n get currentScale() {\n return this._currentScale !== UNKNOWN_SCALE ? this._currentScale :\n DEFAULT_SCALE;\n }\n\n /**\n * @param {number} val - Scale of the pages in percents.\n */\n set currentScale(val) {\n if (isNaN(val)) {\n throw new Error('Invalid numeric scale');\n }\n if (!this.pdfDocument) {\n return;\n }\n this._setScale(val, false);\n }\n\n /**\n * @returns {string}\n */\n get currentScaleValue() {\n return this._currentScaleValue;\n }\n\n /**\n * @param val - The scale of the pages (in percent or predefined value).\n */\n set currentScaleValue(val) {\n if (!this.pdfDocument) {\n return;\n }\n this._setScale(val, false);\n }\n\n /**\n * @returns {number}\n */\n get pagesRotation() {\n return this._pagesRotation;\n }\n\n /**\n * @param {number} rotation - The rotation of the pages (0, 90, 180, 270).\n */\n set pagesRotation(rotation) {\n if (!(typeof rotation === 'number' && rotation % 90 === 0)) {\n throw new Error('Invalid pages rotation angle.');\n }\n if (!this.pdfDocument) {\n return;\n }\n this._pagesRotation = rotation;\n\n for (let i = 0, ii = this._pages.length; i < ii; i++) {\n let pageView = this._pages[i];\n pageView.update(pageView.scale, rotation);\n }\n\n this._setScale(this._currentScaleValue, true);\n\n if (this.defaultRenderingQueue) {\n this.update();\n }\n }\n\n /**\n * @param pdfDocument {PDFDocument}\n */\n setDocument(pdfDocument) {\n if (this.pdfDocument) {\n this._cancelRendering();\n this._resetView();\n }\n\n this.pdfDocument = pdfDocument;\n if (!pdfDocument) {\n return;\n }\n let pagesCount = pdfDocument.numPages;\n\n let pagesCapability = createPromiseCapability();\n this.pagesPromise = pagesCapability.promise;\n\n pagesCapability.promise.then(() => {\n this._pageViewsReady = true;\n this.eventBus.dispatch('pagesloaded', {\n source: this,\n pagesCount,\n });\n });\n\n let isOnePageRenderedResolved = false;\n let onePageRenderedCapability = createPromiseCapability();\n this.onePageRendered = onePageRenderedCapability.promise;\n\n let bindOnAfterAndBeforeDraw = (pageView) => {\n pageView.onBeforeDraw = () => {\n // Add the page to the buffer at the start of drawing. That way it can\n // be evicted from the buffer and destroyed even if we pause its\n // rendering.\n this._buffer.push(pageView);\n };\n pageView.onAfterDraw = () => {\n if (!isOnePageRenderedResolved) {\n isOnePageRenderedResolved = true;\n onePageRenderedCapability.resolve();\n }\n };\n };\n\n let firstPagePromise = pdfDocument.getPage(1);\n this.firstPagePromise = firstPagePromise;\n\n // Fetch a single page so we can get a viewport that will be the default\n // viewport for all pages\n firstPagePromise.then((pdfPage) => {\n let scale = this.currentScale;\n let viewport = pdfPage.getViewport(scale * CSS_UNITS);\n for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) {\n let textLayerFactory = null;\n if (!PDFJS.disableTextLayer) {\n textLayerFactory = this;\n }\n let pageView = new PDFPageView({\n container: this.viewer,\n eventBus: this.eventBus,\n id: pageNum,\n scale,\n defaultViewport: viewport.clone(),\n renderingQueue: this.renderingQueue,\n textLayerFactory,\n annotationLayerFactory: this,\n enhanceTextSelection: this.enhanceTextSelection,\n renderInteractiveForms: this.renderInteractiveForms,\n renderer: this.renderer,\n l10n: this.l10n,\n });\n bindOnAfterAndBeforeDraw(pageView);\n this._pages.push(pageView);\n }\n\n // Fetch all the pages since the viewport is needed before printing\n // starts to create the correct size canvas. Wait until one page is\n // rendered so we don't tie up too many resources early on.\n onePageRenderedCapability.promise.then(() => {\n if (PDFJS.disableAutoFetch) {\n // XXX: Printing is semi-broken with auto fetch disabled.\n pagesCapability.resolve();\n return;\n }\n let getPagesLeft = pagesCount;\n for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) {\n pdfDocument.getPage(pageNum).then((pdfPage) => {\n let pageView = this._pages[pageNum - 1];\n if (!pageView.pdfPage) {\n pageView.setPdfPage(pdfPage);\n }\n this.linkService.cachePageRef(pageNum, pdfPage.ref);\n if (--getPagesLeft === 0) {\n pagesCapability.resolve();\n }\n }, (reason) => {\n console.error(`Unable to get page ${pageNum} to initialize viewer`,\n reason);\n if (--getPagesLeft === 0) {\n pagesCapability.resolve();\n }\n });\n }\n });\n\n this.eventBus.dispatch('pagesinit', { source: this, });\n\n if (this.defaultRenderingQueue) {\n this.update();\n }\n\n if (this.findController) {\n this.findController.resolveFirstPage();\n }\n }).catch((reason) => {\n console.error('Unable to initialize viewer', reason);\n });\n }\n\n /**\n * @param {Array|null} labels\n */\n setPageLabels(labels) {\n if (!this.pdfDocument) {\n return;\n }\n if (!labels) {\n this._pageLabels = null;\n } else if (!(labels instanceof Array &&\n this.pdfDocument.numPages === labels.length)) {\n this._pageLabels = null;\n console.error('PDFViewer.setPageLabels: Invalid page labels.');\n } else {\n this._pageLabels = labels;\n }\n // Update all the `PDFPageView` instances.\n for (let i = 0, ii = this._pages.length; i < ii; i++) {\n let pageView = this._pages[i];\n let label = this._pageLabels && this._pageLabels[i];\n pageView.setPageLabel(label);\n }\n }\n\n _resetView() {\n this._pages = [];\n this._currentPageNumber = 1;\n this._currentScale = UNKNOWN_SCALE;\n this._currentScaleValue = null;\n this._pageLabels = null;\n this._buffer = new PDFPageViewBuffer(DEFAULT_CACHE_SIZE);\n this._location = null;\n this._pagesRotation = 0;\n this._pagesRequests = [];\n this._pageViewsReady = false;\n\n // Remove the pages from the DOM.\n this.viewer.textContent = '';\n }\n\n _scrollUpdate() {\n if (this.pagesCount === 0) {\n return;\n }\n this.update();\n }\n\n _setScaleDispatchEvent(newScale, newValue, preset = false) {\n let arg = {\n source: this,\n scale: newScale,\n presetValue: preset ? newValue : undefined,\n };\n this.eventBus.dispatch('scalechanging', arg);\n this.eventBus.dispatch('scalechange', arg);\n }\n\n _setScaleUpdatePages(newScale, newValue, noScroll = false, preset = false) {\n this._currentScaleValue = newValue.toString();\n\n if (isSameScale(this._currentScale, newScale)) {\n if (preset) {\n this._setScaleDispatchEvent(newScale, newValue, true);\n }\n return;\n }\n\n for (let i = 0, ii = this._pages.length; i < ii; i++) {\n this._pages[i].update(newScale);\n }\n this._currentScale = newScale;\n\n if (!noScroll) {\n let page = this._currentPageNumber, dest;\n if (this._location && !PDFJS.ignoreCurrentPositionOnZoom &&\n !(this.isInPresentationMode || this.isChangingPresentationMode)) {\n page = this._location.pageNumber;\n dest = [null, { name: 'XYZ', }, this._location.left,\n this._location.top, null];\n }\n this.scrollPageIntoView({\n pageNumber: page,\n destArray: dest,\n allowNegativeOffset: true,\n });\n }\n\n this._setScaleDispatchEvent(newScale, newValue, preset);\n\n if (this.defaultRenderingQueue) {\n this.update();\n }\n }\n\n _setScale(value, noScroll = false) {\n let scale = parseFloat(value);\n\n if (scale > 0) {\n this._setScaleUpdatePages(scale, value, noScroll, /* preset = */ false);\n } else {\n let currentPage = this._pages[this._currentPageNumber - 1];\n if (!currentPage) {\n return;\n }\n let hPadding = (this.isInPresentationMode || this.removePageBorders) ?\n 0 : SCROLLBAR_PADDING;\n let vPadding = (this.isInPresentationMode || this.removePageBorders) ?\n 0 : VERTICAL_PADDING;\n let pageWidthScale = (this.container.clientWidth - hPadding) /\n currentPage.width * currentPage.scale;\n let pageHeightScale = (this.container.clientHeight - vPadding) /\n currentPage.height * currentPage.scale;\n switch (value) {\n case 'page-actual':\n scale = 1;\n break;\n case 'page-width':\n scale = pageWidthScale;\n break;\n case 'page-height':\n scale = pageHeightScale;\n break;\n case 'page-fit':\n scale = Math.min(pageWidthScale, pageHeightScale);\n break;\n case 'auto':\n let isLandscape = (currentPage.width > currentPage.height);\n // For pages in landscape mode, fit the page height to the viewer\n // *unless* the page would thus become too wide to fit horizontally.\n let horizontalScale = isLandscape ?\n Math.min(pageHeightScale, pageWidthScale) : pageWidthScale;\n scale = Math.min(MAX_AUTO_SCALE, horizontalScale);\n break;\n default:\n console.error(\n `PDFViewer._setScale: \"${value}\" is an unknown zoom value.`);\n return;\n }\n this._setScaleUpdatePages(scale, value, noScroll, /* preset = */ true);\n }\n }\n\n /**\n * Refreshes page view: scrolls to the current page and updates the scale.\n * @private\n */\n _resetCurrentPageView() {\n if (this.isInPresentationMode) {\n // Fixes the case when PDF has different page sizes.\n this._setScale(this._currentScaleValue, true);\n }\n\n let pageView = this._pages[this._currentPageNumber - 1];\n scrollIntoView(pageView.div);\n }\n\n /**\n * @typedef ScrollPageIntoViewParameters\n * @property {number} pageNumber - The page number.\n * @property {Array} destArray - (optional) The original PDF destination\n * array, in the format: \n * @property {boolean} allowNegativeOffset - (optional) Allow negative page\n * offsets. The default value is `false`.\n */\n\n /**\n * Scrolls page into view.\n * @param {ScrollPageIntoViewParameters} params\n */\n scrollPageIntoView(params) {\n if (!this.pdfDocument) {\n return;\n }\n if ((typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) &&\n (arguments.length > 1 || typeof params === 'number')) {\n console.warn('Call of scrollPageIntoView() with obsolete signature.');\n let paramObj = {};\n if (typeof params === 'number') {\n paramObj.pageNumber = params; // pageNumber argument was found.\n }\n if (arguments[1] instanceof Array) {\n paramObj.destArray = arguments[1]; // destArray argument was found.\n }\n params = paramObj;\n }\n let pageNumber = params.pageNumber || 0;\n let dest = params.destArray || null;\n let allowNegativeOffset = params.allowNegativeOffset || false;\n\n if (this.isInPresentationMode || !dest) {\n this._setCurrentPageNumber(pageNumber, /* resetCurrentPageView = */ true);\n return;\n }\n\n let pageView = this._pages[pageNumber - 1];\n if (!pageView) {\n console.error(\n 'PDFViewer.scrollPageIntoView: Invalid \"pageNumber\" parameter.');\n return;\n }\n let x = 0, y = 0;\n let width = 0, height = 0, widthScale, heightScale;\n let changeOrientation = (pageView.rotation % 180 === 0 ? false : true);\n let pageWidth = (changeOrientation ? pageView.height : pageView.width) /\n pageView.scale / CSS_UNITS;\n let pageHeight = (changeOrientation ? pageView.width : pageView.height) /\n pageView.scale / CSS_UNITS;\n let scale = 0;\n switch (dest[1].name) {\n case 'XYZ':\n x = dest[2];\n y = dest[3];\n scale = dest[4];\n // If x and/or y coordinates are not supplied, default to\n // _top_ left of the page (not the obvious bottom left,\n // since aligning the bottom of the intended page with the\n // top of the window is rarely helpful).\n x = x !== null ? x : 0;\n y = y !== null ? y : pageHeight;\n break;\n case 'Fit':\n case 'FitB':\n scale = 'page-fit';\n break;\n case 'FitH':\n case 'FitBH':\n y = dest[2];\n scale = 'page-width';\n // According to the PDF spec, section 12.3.2.2, a `null` value in the\n // parameter should maintain the position relative to the new page.\n if (y === null && this._location) {\n x = this._location.left;\n y = this._location.top;\n }\n break;\n case 'FitV':\n case 'FitBV':\n x = dest[2];\n width = pageWidth;\n height = pageHeight;\n scale = 'page-height';\n break;\n case 'FitR':\n x = dest[2];\n y = dest[3];\n width = dest[4] - x;\n height = dest[5] - y;\n let hPadding = this.removePageBorders ? 0 : SCROLLBAR_PADDING;\n let vPadding = this.removePageBorders ? 0 : VERTICAL_PADDING;\n\n widthScale = (this.container.clientWidth - hPadding) /\n width / CSS_UNITS;\n heightScale = (this.container.clientHeight - vPadding) /\n height / CSS_UNITS;\n scale = Math.min(Math.abs(widthScale), Math.abs(heightScale));\n break;\n default:\n console.error(`PDFViewer.scrollPageIntoView: \"${dest[1].name}\" ` +\n 'is not a valid destination type.');\n return;\n }\n\n if (scale && scale !== this._currentScale) {\n this.currentScaleValue = scale;\n } else if (this._currentScale === UNKNOWN_SCALE) {\n this.currentScaleValue = DEFAULT_SCALE_VALUE;\n }\n\n if (scale === 'page-fit' && !dest[4]) {\n scrollIntoView(pageView.div);\n return;\n }\n\n let boundingRect = [\n pageView.viewport.convertToViewportPoint(x, y),\n pageView.viewport.convertToViewportPoint(x + width, y + height)\n ];\n let left = Math.min(boundingRect[0][0], boundingRect[1][0]);\n let top = Math.min(boundingRect[0][1], boundingRect[1][1]);\n\n if (!allowNegativeOffset) {\n // Some bad PDF generators will create destinations with e.g. top values\n // that exceeds the page height. Ensure that offsets are not negative,\n // to prevent a previous page from becoming visible (fixes bug 874482).\n left = Math.max(left, 0);\n top = Math.max(top, 0);\n }\n scrollIntoView(pageView.div, { left, top, });\n }\n\n _updateLocation(firstPage) {\n let currentScale = this._currentScale;\n let currentScaleValue = this._currentScaleValue;\n let normalizedScaleValue =\n parseFloat(currentScaleValue) === currentScale ?\n Math.round(currentScale * 10000) / 100 : currentScaleValue;\n\n let pageNumber = firstPage.id;\n let pdfOpenParams = '#page=' + pageNumber;\n pdfOpenParams += '&zoom=' + normalizedScaleValue;\n let currentPageView = this._pages[pageNumber - 1];\n let container = this.container;\n let topLeft = currentPageView.getPagePoint(\n (container.scrollLeft - firstPage.x),\n (container.scrollTop - firstPage.y));\n let intLeft = Math.round(topLeft[0]);\n let intTop = Math.round(topLeft[1]);\n pdfOpenParams += ',' + intLeft + ',' + intTop;\n\n this._location = {\n pageNumber,\n scale: normalizedScaleValue,\n top: intTop,\n left: intLeft,\n pdfOpenParams,\n };\n }\n\n update() {\n let visible = this._getVisiblePages();\n let visiblePages = visible.views;\n if (visiblePages.length === 0) {\n return;\n }\n\n let suggestedCacheSize = Math.max(DEFAULT_CACHE_SIZE,\n 2 * visiblePages.length + 1);\n this._buffer.resize(suggestedCacheSize);\n\n this.renderingQueue.renderHighestPriority(visible);\n\n let currentId = this._currentPageNumber;\n let firstPage = visible.first;\n let stillFullyVisible = false;\n\n for (let i = 0, ii = visiblePages.length; i < ii; ++i) {\n let page = visiblePages[i];\n\n if (page.percent < 100) {\n break;\n }\n if (page.id === currentId) {\n stillFullyVisible = true;\n break;\n }\n }\n\n if (!stillFullyVisible) {\n currentId = visiblePages[0].id;\n }\n\n if (!this.isInPresentationMode) {\n this._setCurrentPageNumber(currentId);\n }\n\n this._updateLocation(firstPage);\n\n this.eventBus.dispatch('updateviewarea', {\n source: this,\n location: this._location,\n });\n }\n\n containsElement(element) {\n return this.container.contains(element);\n }\n\n focus() {\n this.container.focus();\n }\n\n get isInPresentationMode() {\n return this.presentationModeState === PresentationModeState.FULLSCREEN;\n }\n\n get isChangingPresentationMode() {\n return this.presentationModeState === PresentationModeState.CHANGING;\n }\n\n get isHorizontalScrollbarEnabled() {\n return (this.isInPresentationMode ?\n false : (this.container.scrollWidth > this.container.clientWidth));\n }\n\n _getVisiblePages() {\n if (!this.isInPresentationMode) {\n return getVisibleElements(this.container, this._pages, true);\n }\n // The algorithm in getVisibleElements doesn't work in all browsers and\n // configurations when presentation mode is active.\n let visible = [];\n let currentPage = this._pages[this._currentPageNumber - 1];\n visible.push({ id: currentPage.id, view: currentPage, });\n return { first: currentPage, last: currentPage, views: visible, };\n }\n\n cleanup() {\n for (let i = 0, ii = this._pages.length; i < ii; i++) {\n if (this._pages[i] &&\n this._pages[i].renderingState !== RenderingStates.FINISHED) {\n this._pages[i].reset();\n }\n }\n }\n\n /**\n * @private\n */\n _cancelRendering() {\n for (let i = 0, ii = this._pages.length; i < ii; i++) {\n if (this._pages[i]) {\n this._pages[i].cancelRendering();\n }\n }\n }\n\n /**\n * @param {PDFPageView} pageView\n * @returns {Promise} Returns a promise containing a {PDFPageProxy} object.\n * @private\n */\n _ensurePdfPageLoaded(pageView) {\n if (pageView.pdfPage) {\n return Promise.resolve(pageView.pdfPage);\n }\n let pageNumber = pageView.id;\n if (this._pagesRequests[pageNumber]) {\n return this._pagesRequests[pageNumber];\n }\n let promise = this.pdfDocument.getPage(pageNumber).then((pdfPage) => {\n if (!pageView.pdfPage) {\n pageView.setPdfPage(pdfPage);\n }\n this._pagesRequests[pageNumber] = null;\n return pdfPage;\n }).catch((reason) => {\n console.error('Unable to get page for page view', reason);\n // Page error -- there is nothing can be done.\n this._pagesRequests[pageNumber] = null;\n });\n this._pagesRequests[pageNumber] = promise;\n return promise;\n }\n\n forceRendering(currentlyVisiblePages) {\n let visiblePages = currentlyVisiblePages || this._getVisiblePages();\n let pageView = this.renderingQueue.getHighestPriority(visiblePages,\n this._pages,\n this.scroll.down);\n if (pageView) {\n this._ensurePdfPageLoaded(pageView).then(() => {\n this.renderingQueue.renderView(pageView);\n });\n return true;\n }\n return false;\n }\n\n getPageTextContent(pageIndex) {\n return this.pdfDocument.getPage(pageIndex + 1).then(function(page) {\n return page.getTextContent({\n normalizeWhitespace: true,\n });\n });\n }\n\n /**\n * @param {HTMLDivElement} textLayerDiv\n * @param {number} pageIndex\n * @param {PageViewport} viewport\n * @returns {TextLayerBuilder}\n */\n createTextLayerBuilder(textLayerDiv, pageIndex, viewport,\n enhanceTextSelection = false) {\n return new TextLayerBuilder({\n textLayerDiv,\n eventBus: this.eventBus,\n pageIndex,\n viewport,\n findController: this.isInPresentationMode ? null : this.findController,\n enhanceTextSelection: this.isInPresentationMode ? false :\n enhanceTextSelection,\n });\n }\n\n /**\n * @param {HTMLDivElement} pageDiv\n * @param {PDFPage} pdfPage\n * @param {boolean} renderInteractiveForms\n * @param {IL10n} l10n\n * @returns {AnnotationLayerBuilder}\n */\n createAnnotationLayerBuilder(pageDiv, pdfPage, renderInteractiveForms = false,\n l10n = NullL10n) {\n return new AnnotationLayerBuilder({\n pageDiv,\n pdfPage,\n renderInteractiveForms,\n linkService: this.linkService,\n downloadManager: this.downloadManager,\n l10n,\n });\n }\n\n setFindController(findController) {\n this.findController = findController;\n }\n\n /**\n * @returns {boolean} Whether all pages of the PDF document have identical\n * widths and heights.\n */\n get hasEqualPageSizes() {\n let firstPageView = this._pages[0];\n for (let i = 1, ii = this._pages.length; i < ii; ++i) {\n let pageView = this._pages[i];\n if (pageView.width !== firstPageView.width ||\n pageView.height !== firstPageView.height) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Returns sizes of the pages.\n * @returns {Array} Array of objects with width/height/rotation fields.\n */\n getPagesOverview() {\n let pagesOverview = this._pages.map(function(pageView) {\n let viewport = pageView.pdfPage.getViewport(1);\n return {\n width: viewport.width,\n height: viewport.height,\n rotation: viewport.rotation,\n };\n });\n if (!this.enablePrintAutoRotate) {\n return pagesOverview;\n }\n let isFirstPagePortrait = isPortraitOrientation(pagesOverview[0]);\n return pagesOverview.map(function (size) {\n if (isFirstPagePortrait === isPortraitOrientation(size)) {\n return size;\n }\n return {\n width: size.height,\n height: size.width,\n rotation: (size.rotation + 90) % 360,\n };\n });\n }\n}\n\nexport {\n PresentationModeState,\n PDFViewer,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/pdf_viewer.js", + "/* Copyright 2013 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { cloneObj } from './ui_utils';\n\nvar defaultPreferences = null;\nfunction getDefaultPreferences() {\n if (!defaultPreferences) {\n if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('PRODUCTION')) {\n defaultPreferences = Promise.resolve(\n PDFJSDev.json('$ROOT/web/default_preferences.json'));\n } else {\n defaultPreferences = new Promise(function (resolve) {\n var xhr = new XMLHttpRequest();\n xhr.open('GET', 'default_preferences.json');\n xhr.onload = xhr.onerror = function loaded() {\n try {\n resolve(JSON.parse(xhr.responseText));\n } catch (e) {\n console.error(`Unable to load default preferences: ${e}`);\n resolve({});\n }\n };\n xhr.send();\n });\n }\n }\n return defaultPreferences;\n}\n\n/**\n * BasePreferences - Abstract base class for storing persistent settings.\n * Used for settings that should be applied to all opened documents,\n * or every time the viewer is loaded.\n */\nclass BasePreferences {\n constructor() {\n if (this.constructor === BasePreferences) {\n throw new Error('Cannot initialize BasePreferences.');\n }\n this.prefs = null;\n\n this._initializedPromise = getDefaultPreferences().then((defaults) => {\n Object.defineProperty(this, 'defaults', {\n value: Object.freeze(defaults),\n writable: false,\n enumerable: true,\n configurable: false,\n });\n\n this.prefs = cloneObj(defaults);\n return this._readFromStorage(defaults);\n }).then((prefObj) => {\n if (prefObj) {\n this.prefs = prefObj;\n }\n });\n }\n\n /**\n * Stub function for writing preferences to storage.\n * @param {Object} prefObj The preferences that should be written to storage.\n * @return {Promise} A promise that is resolved when the preference values\n * have been written.\n */\n _writeToStorage(prefObj) {\n return Promise.reject(new Error('Not implemented: _writeToStorage'));\n }\n\n /**\n * Stub function for reading preferences from storage.\n * @param {Object} prefObj The preferences that should be read from storage.\n * @return {Promise} A promise that is resolved with an {Object} containing\n * the preferences that have been read.\n */\n _readFromStorage(prefObj) {\n return Promise.reject(new Error('Not implemented: _readFromStorage'));\n }\n\n /**\n * Reset the preferences to their default values and update storage.\n * @return {Promise} A promise that is resolved when the preference values\n * have been reset.\n */\n reset() {\n return this._initializedPromise.then(() => {\n this.prefs = cloneObj(this.defaults);\n return this._writeToStorage(this.defaults);\n });\n }\n\n /**\n * Replace the current preference values with the ones from storage.\n * @return {Promise} A promise that is resolved when the preference values\n * have been updated.\n */\n reload() {\n return this._initializedPromise.then(() => {\n return this._readFromStorage(this.defaults);\n }).then((prefObj) => {\n if (prefObj) {\n this.prefs = prefObj;\n }\n });\n }\n\n /**\n * Set the value of a preference.\n * @param {string} name The name of the preference that should be changed.\n * @param {boolean|number|string} value The new value of the preference.\n * @return {Promise} A promise that is resolved when the value has been set,\n * provided that the preference exists and the types match.\n */\n set(name, value) {\n return this._initializedPromise.then(() => {\n if (this.defaults[name] === undefined) {\n throw new Error(`Set preference: \"${name}\" is undefined.`);\n } else if (value === undefined) {\n throw new Error('Set preference: no value is specified.');\n }\n var valueType = typeof value;\n var defaultType = typeof this.defaults[name];\n\n if (valueType !== defaultType) {\n if (valueType === 'number' && defaultType === 'string') {\n value = value.toString();\n } else {\n throw new Error(`Set preference: \"${value}\" is a ${valueType}, ` +\n `expected a ${defaultType}.`);\n }\n } else {\n if (valueType === 'number' && (value | 0) !== value) {\n throw new Error(`Set preference: \"${value}\" must be an integer.`);\n }\n }\n this.prefs[name] = value;\n return this._writeToStorage(this.prefs);\n });\n }\n\n /**\n * Get the value of a preference.\n * @param {string} name The name of the preference whose value is requested.\n * @return {Promise} A promise that is resolved with a {boolean|number|string}\n * containing the value of the preference.\n */\n get(name) {\n return this._initializedPromise.then(() => {\n var defaultValue = this.defaults[name];\n\n if (defaultValue === undefined) {\n throw new Error(`Get preference: \"${name}\" is undefined.`);\n } else {\n var prefValue = this.prefs[name];\n\n if (prefValue !== undefined) {\n return prefValue;\n }\n }\n return defaultValue;\n });\n }\n}\n\nexport {\n BasePreferences,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/preferences.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CursorTool } from './pdf_cursor_tools';\nimport { SCROLLBAR_PADDING } from './ui_utils';\n\n/**\n * @typedef {Object} SecondaryToolbarOptions\n * @property {HTMLDivElement} toolbar - Container for the secondary toolbar.\n * @property {HTMLButtonElement} toggleButton - Button to toggle the visibility\n * of the secondary toolbar.\n * @property {HTMLDivElement} toolbarButtonContainer - Container where all the\n * toolbar buttons are placed. The maximum height of the toolbar is controlled\n * dynamically by adjusting the 'max-height' CSS property of this DOM element.\n * @property {HTMLButtonElement} presentationModeButton - Button for entering\n * presentation mode.\n * @property {HTMLButtonElement} openFileButton - Button to open a file.\n * @property {HTMLButtonElement} printButton - Button to print the document.\n * @property {HTMLButtonElement} downloadButton - Button to download the\n * document.\n * @property {HTMLLinkElement} viewBookmarkButton - Button to obtain a bookmark\n * link to the current location in the document.\n * @property {HTMLButtonElement} firstPageButton - Button to go to the first\n * page in the document.\n * @property {HTMLButtonElement} lastPageButton - Button to go to the last page\n * in the document.\n * @property {HTMLButtonElement} pageRotateCwButton - Button to rotate the pages\n * clockwise.\n * @property {HTMLButtonElement} pageRotateCcwButton - Button to rotate the\n * pages counterclockwise.\n * @property {HTMLButtonElement} cursorSelectToolButton - Button to enable the\n * select tool.\n * @property {HTMLButtonElement} cursorHandToolButton - Button to enable the\n * hand tool.\n * @property {HTMLButtonElement} documentPropertiesButton - Button for opening\n * the document properties dialog.\n */\n\nclass SecondaryToolbar {\n /**\n * @param {SecondaryToolbarOptions} options\n * @param {HTMLDivElement} mainContainer\n * @param {EventBus} eventBus\n */\n constructor(options, mainContainer, eventBus) {\n this.toolbar = options.toolbar;\n this.toggleButton = options.toggleButton;\n this.toolbarButtonContainer = options.toolbarButtonContainer;\n this.buttons = [\n { element: options.presentationModeButton, eventName: 'presentationmode',\n close: true, },\n { element: options.openFileButton, eventName: 'openfile', close: true, },\n { element: options.printButton, eventName: 'print', close: true, },\n { element: options.downloadButton, eventName: 'download', close: true, },\n { element: options.viewBookmarkButton, eventName: null, close: true, },\n { element: options.firstPageButton, eventName: 'firstpage',\n close: true, },\n { element: options.lastPageButton, eventName: 'lastpage', close: true, },\n { element: options.pageRotateCwButton, eventName: 'rotatecw',\n close: false, },\n { element: options.pageRotateCcwButton, eventName: 'rotateccw',\n close: false, },\n { element: options.cursorSelectToolButton, eventName: 'switchcursortool',\n eventDetails: { tool: CursorTool.SELECT, }, close: true, },\n { element: options.cursorHandToolButton, eventName: 'switchcursortool',\n eventDetails: { tool: CursorTool.HAND, }, close: true, },\n { element: options.documentPropertiesButton,\n eventName: 'documentproperties', close: true, },\n ];\n this.items = {\n firstPage: options.firstPageButton,\n lastPage: options.lastPageButton,\n pageRotateCw: options.pageRotateCwButton,\n pageRotateCcw: options.pageRotateCcwButton,\n };\n\n this.mainContainer = mainContainer;\n this.eventBus = eventBus;\n\n this.opened = false;\n this.containerHeight = null;\n this.previousContainerHeight = null;\n\n this.reset();\n\n // Bind the event listeners for click and cursor tool actions.\n this._bindClickListeners();\n this._bindCursorToolsListener(options);\n\n // Bind the event listener for adjusting the 'max-height' of the toolbar.\n this.eventBus.on('resize', this._setMaxHeight.bind(this));\n }\n\n /**\n * @return {boolean}\n */\n get isOpen() {\n return this.opened;\n }\n\n setPageNumber(pageNumber) {\n this.pageNumber = pageNumber;\n this._updateUIState();\n }\n\n setPagesCount(pagesCount) {\n this.pagesCount = pagesCount;\n this._updateUIState();\n }\n\n reset() {\n this.pageNumber = 0;\n this.pagesCount = 0;\n this._updateUIState();\n }\n\n _updateUIState() {\n this.items.firstPage.disabled = (this.pageNumber <= 1);\n this.items.lastPage.disabled = (this.pageNumber >= this.pagesCount);\n this.items.pageRotateCw.disabled = this.pagesCount === 0;\n this.items.pageRotateCcw.disabled = this.pagesCount === 0;\n }\n\n _bindClickListeners() {\n // Button to toggle the visibility of the secondary toolbar.\n this.toggleButton.addEventListener('click', this.toggle.bind(this));\n\n // All items within the secondary toolbar.\n for (let button in this.buttons) {\n let { element, eventName, close, eventDetails, } = this.buttons[button];\n\n element.addEventListener('click', (evt) => {\n if (eventName !== null) {\n let details = { source: this, };\n for (let property in eventDetails) {\n details[property] = eventDetails[property];\n }\n this.eventBus.dispatch(eventName, details);\n }\n if (close) {\n this.close();\n }\n });\n }\n }\n\n _bindCursorToolsListener(buttons) {\n this.eventBus.on('cursortoolchanged', function(evt) {\n buttons.cursorSelectToolButton.classList.remove('toggled');\n buttons.cursorHandToolButton.classList.remove('toggled');\n\n switch (evt.tool) {\n case CursorTool.SELECT:\n buttons.cursorSelectToolButton.classList.add('toggled');\n break;\n case CursorTool.HAND:\n buttons.cursorHandToolButton.classList.add('toggled');\n break;\n }\n });\n }\n\n open() {\n if (this.opened) {\n return;\n }\n this.opened = true;\n this._setMaxHeight();\n\n this.toggleButton.classList.add('toggled');\n this.toolbar.classList.remove('hidden');\n }\n\n close() {\n if (!this.opened) {\n return;\n }\n this.opened = false;\n this.toolbar.classList.add('hidden');\n this.toggleButton.classList.remove('toggled');\n }\n\n toggle() {\n if (this.opened) {\n this.close();\n } else {\n this.open();\n }\n }\n\n /**\n * @private\n */\n _setMaxHeight() {\n if (!this.opened) {\n return; // Only adjust the 'max-height' if the toolbar is visible.\n }\n this.containerHeight = this.mainContainer.clientHeight;\n\n if (this.containerHeight === this.previousContainerHeight) {\n return;\n }\n this.toolbarButtonContainer.setAttribute('style',\n 'max-height: ' + (this.containerHeight - SCROLLBAR_PADDING) + 'px;');\n\n this.previousContainerHeight = this.containerHeight;\n }\n}\n\nexport {\n SecondaryToolbar,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/secondary_toolbar.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getGlobalEventBus } from './dom_events';\nimport { renderTextLayer } from 'pdfjs-lib';\n\nconst EXPAND_DIVS_TIMEOUT = 300; // ms\n\n/**\n * @typedef {Object} TextLayerBuilderOptions\n * @property {HTMLDivElement} textLayerDiv - The text layer container.\n * @property {EventBus} eventBus - The application event bus.\n * @property {number} pageIndex - The page index.\n * @property {PageViewport} viewport - The viewport of the text layer.\n * @property {PDFFindController} findController\n * @property {boolean} enhanceTextSelection - Option to turn on improved\n * text selection.\n */\n\n/**\n * The text layer builder provides text selection functionality for the PDF.\n * It does this by creating overlay divs over the PDF's text. These divs\n * contain text that matches the PDF text they are overlaying. This object\n * also provides a way to highlight text that is being searched for.\n */\nclass TextLayerBuilder {\n constructor({ textLayerDiv, eventBus, pageIndex, viewport,\n findController = null, enhanceTextSelection = false, }) {\n this.textLayerDiv = textLayerDiv;\n this.eventBus = eventBus || getGlobalEventBus();\n this.textContent = null;\n this.textContentItemsStr = [];\n this.textContentStream = null;\n this.renderingDone = false;\n this.pageIdx = pageIndex;\n this.pageNumber = this.pageIdx + 1;\n this.matches = [];\n this.viewport = viewport;\n this.textDivs = [];\n this.findController = findController;\n this.textLayerRenderTask = null;\n this.enhanceTextSelection = enhanceTextSelection;\n\n this._bindMouse();\n }\n\n /**\n * @private\n */\n _finishRendering() {\n this.renderingDone = true;\n\n if (!this.enhanceTextSelection) {\n let endOfContent = document.createElement('div');\n endOfContent.className = 'endOfContent';\n this.textLayerDiv.appendChild(endOfContent);\n }\n\n this.eventBus.dispatch('textlayerrendered', {\n source: this,\n pageNumber: this.pageNumber,\n numTextDivs: this.textDivs.length,\n });\n }\n\n /**\n * Renders the text layer.\n *\n * @param {number} timeout - (optional) wait for a specified amount of\n * milliseconds before rendering\n */\n render(timeout = 0) {\n if (!(this.textContent || this.textContentStream) || this.renderingDone) {\n return;\n }\n this.cancel();\n\n this.textDivs = [];\n let textLayerFrag = document.createDocumentFragment();\n this.textLayerRenderTask = renderTextLayer({\n textContent: this.textContent,\n textContentStream: this.textContentStream,\n container: textLayerFrag,\n viewport: this.viewport,\n textDivs: this.textDivs,\n textContentItemsStr: this.textContentItemsStr,\n timeout,\n enhanceTextSelection: this.enhanceTextSelection,\n });\n this.textLayerRenderTask.promise.then(() => {\n this.textLayerDiv.appendChild(textLayerFrag);\n this._finishRendering();\n this.updateMatches();\n }, function (reason) {\n // Cancelled or failed to render text layer; skipping errors.\n });\n }\n\n /**\n * Cancel rendering of the text layer.\n */\n cancel() {\n if (this.textLayerRenderTask) {\n this.textLayerRenderTask.cancel();\n this.textLayerRenderTask = null;\n }\n }\n\n setTextContentStream(readableStream) {\n this.cancel();\n this.textContentStream = readableStream;\n }\n\n setTextContent(textContent) {\n this.cancel();\n this.textContent = textContent;\n }\n\n convertMatches(matches, matchesLength) {\n let i = 0;\n let iIndex = 0;\n let textContentItemsStr = this.textContentItemsStr;\n let end = textContentItemsStr.length - 1;\n let queryLen = (this.findController === null ?\n 0 : this.findController.state.query.length);\n let ret = [];\n if (!matches) {\n return ret;\n }\n for (let m = 0, len = matches.length; m < len; m++) {\n // Calculate the start position.\n let matchIdx = matches[m];\n\n // Loop over the divIdxs.\n while (i !== end && matchIdx >=\n (iIndex + textContentItemsStr[i].length)) {\n iIndex += textContentItemsStr[i].length;\n i++;\n }\n\n if (i === textContentItemsStr.length) {\n console.error('Could not find a matching mapping');\n }\n\n let match = {\n begin: {\n divIdx: i,\n offset: matchIdx - iIndex,\n },\n };\n\n // Calculate the end position.\n if (matchesLength) { // Multiterm search.\n matchIdx += matchesLength[m];\n } else { // Phrase search.\n matchIdx += queryLen;\n }\n\n // Somewhat the same array as above, but use > instead of >= to get\n // the end position right.\n while (i !== end && matchIdx >\n (iIndex + textContentItemsStr[i].length)) {\n iIndex += textContentItemsStr[i].length;\n i++;\n }\n\n match.end = {\n divIdx: i,\n offset: matchIdx - iIndex,\n };\n ret.push(match);\n }\n\n return ret;\n }\n\n renderMatches(matches) {\n // Early exit if there is nothing to render.\n if (matches.length === 0) {\n return;\n }\n\n let textContentItemsStr = this.textContentItemsStr;\n let textDivs = this.textDivs;\n let prevEnd = null;\n let pageIdx = this.pageIdx;\n let isSelectedPage = (this.findController === null ?\n false : (pageIdx === this.findController.selected.pageIdx));\n let selectedMatchIdx = (this.findController === null ?\n -1 : this.findController.selected.matchIdx);\n let highlightAll = (this.findController === null ?\n false : this.findController.state.highlightAll);\n let infinity = {\n divIdx: -1,\n offset: undefined,\n };\n\n function beginText(begin, className) {\n let divIdx = begin.divIdx;\n textDivs[divIdx].textContent = '';\n appendTextToDiv(divIdx, 0, begin.offset, className);\n }\n\n function appendTextToDiv(divIdx, fromOffset, toOffset, className) {\n let div = textDivs[divIdx];\n let content = textContentItemsStr[divIdx].substring(fromOffset, toOffset);\n let node = document.createTextNode(content);\n if (className) {\n let span = document.createElement('span');\n span.className = className;\n span.appendChild(node);\n div.appendChild(span);\n return;\n }\n div.appendChild(node);\n }\n\n let i0 = selectedMatchIdx, i1 = i0 + 1;\n if (highlightAll) {\n i0 = 0;\n i1 = matches.length;\n } else if (!isSelectedPage) {\n // Not highlighting all and this isn't the selected page, so do nothing.\n return;\n }\n\n for (let i = i0; i < i1; i++) {\n let match = matches[i];\n let begin = match.begin;\n let end = match.end;\n let isSelected = (isSelectedPage && i === selectedMatchIdx);\n let highlightSuffix = (isSelected ? ' selected' : '');\n\n if (this.findController) {\n this.findController.updateMatchPosition(pageIdx, i, textDivs,\n begin.divIdx);\n }\n\n // Match inside new div.\n if (!prevEnd || begin.divIdx !== prevEnd.divIdx) {\n // If there was a previous div, then add the text at the end.\n if (prevEnd !== null) {\n appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);\n }\n // Clear the divs and set the content until the starting point.\n beginText(begin);\n } else {\n appendTextToDiv(prevEnd.divIdx, prevEnd.offset, begin.offset);\n }\n\n if (begin.divIdx === end.divIdx) {\n appendTextToDiv(begin.divIdx, begin.offset, end.offset,\n 'highlight' + highlightSuffix);\n } else {\n appendTextToDiv(begin.divIdx, begin.offset, infinity.offset,\n 'highlight begin' + highlightSuffix);\n for (let n0 = begin.divIdx + 1, n1 = end.divIdx; n0 < n1; n0++) {\n textDivs[n0].className = 'highlight middle' + highlightSuffix;\n }\n beginText(end, 'highlight end' + highlightSuffix);\n }\n prevEnd = end;\n }\n\n if (prevEnd) {\n appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);\n }\n }\n\n updateMatches() {\n // Only show matches when all rendering is done.\n if (!this.renderingDone) {\n return;\n }\n\n // Clear all matches.\n let matches = this.matches;\n let textDivs = this.textDivs;\n let textContentItemsStr = this.textContentItemsStr;\n let clearedUntilDivIdx = -1;\n\n // Clear all current matches.\n for (let i = 0, len = matches.length; i < len; i++) {\n let match = matches[i];\n let begin = Math.max(clearedUntilDivIdx, match.begin.divIdx);\n for (let n = begin, end = match.end.divIdx; n <= end; n++) {\n let div = textDivs[n];\n div.textContent = textContentItemsStr[n];\n div.className = '';\n }\n clearedUntilDivIdx = match.end.divIdx + 1;\n }\n\n if (this.findController === null || !this.findController.active) {\n return;\n }\n\n // Convert the matches on the page controller into the match format\n // used for the textLayer.\n let pageMatches, pageMatchesLength;\n if (this.findController !== null) {\n pageMatches = this.findController.pageMatches[this.pageIdx] || null;\n pageMatchesLength = (this.findController.pageMatchesLength) ?\n this.findController.pageMatchesLength[this.pageIdx] || null : null;\n }\n\n this.matches = this.convertMatches(pageMatches, pageMatchesLength);\n this.renderMatches(this.matches);\n }\n\n /**\n * Improves text selection by adding an additional div where the mouse was\n * clicked. This reduces flickering of the content if the mouse is slowly\n * dragged up or down.\n *\n * @private\n */\n _bindMouse() {\n let div = this.textLayerDiv;\n let expandDivsTimer = null;\n\n div.addEventListener('mousedown', (evt) => {\n if (this.enhanceTextSelection && this.textLayerRenderTask) {\n this.textLayerRenderTask.expandTextDivs(true);\n if ((typeof PDFJSDev === 'undefined' ||\n !PDFJSDev.test('FIREFOX || MOZCENTRAL')) &&\n expandDivsTimer) {\n clearTimeout(expandDivsTimer);\n expandDivsTimer = null;\n }\n return;\n }\n\n let end = div.querySelector('.endOfContent');\n if (!end) {\n return;\n }\n if (typeof PDFJSDev === 'undefined' ||\n !PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n // On non-Firefox browsers, the selection will feel better if the height\n // of the `endOfContent` div is adjusted to start at mouse click\n // location. This avoids flickering when the selection moves up.\n // However it does not work when selection is started on empty space.\n let adjustTop = evt.target !== div;\n if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {\n adjustTop = adjustTop && window.getComputedStyle(end).\n getPropertyValue('-moz-user-select') !== 'none';\n }\n if (adjustTop) {\n let divBounds = div.getBoundingClientRect();\n let r = Math.max(0, (evt.pageY - divBounds.top) / divBounds.height);\n end.style.top = (r * 100).toFixed(2) + '%';\n }\n }\n end.classList.add('active');\n });\n\n div.addEventListener('mouseup', () => {\n if (this.enhanceTextSelection && this.textLayerRenderTask) {\n if (typeof PDFJSDev === 'undefined' ||\n !PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n expandDivsTimer = setTimeout(() => {\n if (this.textLayerRenderTask) {\n this.textLayerRenderTask.expandTextDivs(false);\n }\n expandDivsTimer = null;\n }, EXPAND_DIVS_TIMEOUT);\n } else {\n this.textLayerRenderTask.expandTextDivs(false);\n }\n return;\n }\n\n let end = div.querySelector('.endOfContent');\n if (!end) {\n return;\n }\n if (typeof PDFJSDev === 'undefined' ||\n !PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n end.style.top = '';\n }\n end.classList.remove('active');\n });\n }\n}\n\n/**\n * @implements IPDFTextLayerFactory\n */\nclass DefaultTextLayerFactory {\n /**\n * @param {HTMLDivElement} textLayerDiv\n * @param {number} pageIndex\n * @param {PageViewport} viewport\n * @param {boolean} enhanceTextSelection\n * @returns {TextLayerBuilder}\n */\n createTextLayerBuilder(textLayerDiv, pageIndex, viewport,\n enhanceTextSelection = false) {\n return new TextLayerBuilder({\n textLayerDiv,\n pageIndex,\n viewport,\n enhanceTextSelection,\n });\n }\n}\n\nexport {\n TextLayerBuilder,\n DefaultTextLayerFactory,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/text_layer_builder.js", + "/* Copyright 2016 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n animationStarted, DEFAULT_SCALE, DEFAULT_SCALE_VALUE, MAX_SCALE,\n MIN_SCALE, noContextMenuHandler, NullL10n\n} from './ui_utils';\n\nconst PAGE_NUMBER_LOADING_INDICATOR = 'visiblePageIsLoading';\nconst SCALE_SELECT_CONTAINER_PADDING = 8;\nconst SCALE_SELECT_PADDING = 22;\n\n/**\n * @typedef {Object} ToolbarOptions\n * @property {HTMLDivElement} container - Container for the secondary toolbar.\n * @property {HTMLSpanElement} numPages - Label that contains number of pages.\n * @property {HTMLInputElement} pageNumber - Control for display and user input\n * of the current page number.\n * @property {HTMLSpanElement} scaleSelectContainer - Container where scale\n * controls are placed. The width is adjusted on UI initialization.\n * @property {HTMLSelectElement} scaleSelect - Scale selection control.\n * @property {HTMLOptionElement} customScaleOption - The item used to display\n * a non-predefined scale.\n * @property {HTMLButtonElement} previous - Button to go to the previous page.\n * @property {HTMLButtonElement} next - Button to go to the next page.\n * @property {HTMLButtonElement} zoomIn - Button to zoom in the pages.\n * @property {HTMLButtonElement} zoomOut - Button to zoom out the pages.\n * @property {HTMLButtonElement} viewFind - Button to open find bar.\n * @property {HTMLButtonElement} openFile - Button to open a new document.\n * @property {HTMLButtonElement} presentationModeButton - Button to switch to\n * presentation mode.\n * @property {HTMLButtonElement} download - Button to download the document.\n * @property {HTMLAElement} viewBookmark - Element to link current url of\n * the page view.\n */\n\nclass Toolbar {\n /**\n * @param {ToolbarOptions} options\n * @param {HTMLDivElement} mainContainer\n * @param {EventBus} eventBus\n * @param {IL10n} l10n - Localization service.\n */\n constructor(options, mainContainer, eventBus, l10n = NullL10n) {\n this.toolbar = options.container;\n this.mainContainer = mainContainer;\n this.eventBus = eventBus;\n this.l10n = l10n;\n this.items = options;\n\n this._wasLocalized = false;\n this.reset();\n\n // Bind the event listeners for click and hand tool actions.\n this._bindListeners();\n }\n\n setPageNumber(pageNumber, pageLabel) {\n this.pageNumber = pageNumber;\n this.pageLabel = pageLabel;\n this._updateUIState(false);\n }\n\n setPagesCount(pagesCount, hasPageLabels) {\n this.pagesCount = pagesCount;\n this.hasPageLabels = hasPageLabels;\n this._updateUIState(true);\n }\n\n setPageScale(pageScaleValue, pageScale) {\n this.pageScaleValue = pageScaleValue;\n this.pageScale = pageScale;\n this._updateUIState(false);\n }\n\n reset() {\n this.pageNumber = 0;\n this.pageLabel = null;\n this.hasPageLabels = false;\n this.pagesCount = 0;\n this.pageScaleValue = DEFAULT_SCALE_VALUE;\n this.pageScale = DEFAULT_SCALE;\n this._updateUIState(true);\n }\n\n _bindListeners() {\n let { eventBus, items, } = this;\n let self = this;\n\n items.previous.addEventListener('click', function() {\n eventBus.dispatch('previouspage');\n });\n\n items.next.addEventListener('click', function() {\n eventBus.dispatch('nextpage');\n });\n\n items.zoomIn.addEventListener('click', function() {\n eventBus.dispatch('zoomin');\n });\n\n items.zoomOut.addEventListener('click', function() {\n eventBus.dispatch('zoomout');\n });\n\n items.pageNumber.addEventListener('click', function() {\n this.select();\n });\n\n items.pageNumber.addEventListener('change', function() {\n eventBus.dispatch('pagenumberchanged', {\n source: self,\n value: this.value,\n });\n });\n\n items.scaleSelect.addEventListener('change', function() {\n if (this.value === 'custom') {\n return;\n }\n eventBus.dispatch('scalechanged', {\n source: self,\n value: this.value,\n });\n });\n\n items.presentationModeButton.addEventListener('click', function() {\n eventBus.dispatch('presentationmode');\n });\n\n items.openFile.addEventListener('click', function() {\n eventBus.dispatch('openfile');\n });\n\n items.print.addEventListener('click', function() {\n eventBus.dispatch('print');\n });\n\n items.download.addEventListener('click', function() {\n eventBus.dispatch('download');\n });\n\n // Suppress context menus for some controls.\n items.scaleSelect.oncontextmenu = noContextMenuHandler;\n\n eventBus.on('localized', () => {\n this._localized();\n });\n }\n\n _localized() {\n this._wasLocalized = true;\n this._adjustScaleWidth();\n this._updateUIState(true);\n }\n\n _updateUIState(resetNumPages = false) {\n if (!this._wasLocalized) {\n // Don't update the UI state until we localize the toolbar.\n return;\n }\n let { pageNumber, pagesCount, items, } = this;\n let scaleValue = (this.pageScaleValue || this.pageScale).toString();\n let scale = this.pageScale;\n\n if (resetNumPages) {\n if (this.hasPageLabels) {\n items.pageNumber.type = 'text';\n } else {\n items.pageNumber.type = 'number';\n this.l10n.get('of_pages', { pagesCount, }, 'of {{pagesCount}}').\n then((msg) => {\n items.numPages.textContent = msg;\n });\n }\n items.pageNumber.max = pagesCount;\n }\n\n if (this.hasPageLabels) {\n items.pageNumber.value = this.pageLabel;\n this.l10n.get('page_of_pages', { pageNumber, pagesCount, },\n '({{pageNumber}} of {{pagesCount}})').then((msg) => {\n items.numPages.textContent = msg;\n });\n } else {\n items.pageNumber.value = pageNumber;\n }\n\n items.previous.disabled = (pageNumber <= 1);\n items.next.disabled = (pageNumber >= pagesCount);\n\n items.zoomOut.disabled = (scale <= MIN_SCALE);\n items.zoomIn.disabled = (scale >= MAX_SCALE);\n\n let customScale = Math.round(scale * 10000) / 100;\n this.l10n.get('page_scale_percent', { scale: customScale, },\n '{{scale}}%').then((msg) => {\n let options = items.scaleSelect.options;\n let predefinedValueFound = false;\n for (let i = 0, ii = options.length; i < ii; i++) {\n let option = options[i];\n if (option.value !== scaleValue) {\n option.selected = false;\n continue;\n }\n option.selected = true;\n predefinedValueFound = true;\n }\n if (!predefinedValueFound) {\n items.customScaleOption.textContent = msg;\n items.customScaleOption.selected = true;\n }\n });\n }\n\n updateLoadingIndicatorState(loading = false) {\n let pageNumberInput = this.items.pageNumber;\n\n if (loading) {\n pageNumberInput.classList.add(PAGE_NUMBER_LOADING_INDICATOR);\n } else {\n pageNumberInput.classList.remove(PAGE_NUMBER_LOADING_INDICATOR);\n }\n }\n\n _adjustScaleWidth() {\n let container = this.items.scaleSelectContainer;\n let select = this.items.scaleSelect;\n\n animationStarted.then(function() {\n // Adjust the width of the zoom box to fit the content.\n // Note: If the window is narrow enough that the zoom box is not\n // visible, we temporarily show it to be able to adjust its width.\n if (container.clientWidth === 0) {\n container.setAttribute('style', 'display: inherit;');\n }\n if (container.clientWidth > 0) {\n select.setAttribute('style', 'min-width: inherit;');\n let width = select.clientWidth + SCALE_SELECT_CONTAINER_PADDING;\n select.setAttribute('style', 'min-width: ' +\n (width + SCALE_SELECT_PADDING) + 'px;');\n container.setAttribute('style', 'min-width: ' + width + 'px; ' +\n 'max-width: ' + width + 'px;');\n }\n });\n }\n}\n\nexport {\n Toolbar,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/toolbar.js", + "/* Copyright 2012 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst DEFAULT_VIEW_HISTORY_CACHE_SIZE = 20;\n\n/**\n * View History - This is a utility for saving various view parameters for\n * recently opened files.\n *\n * The way that the view parameters are stored depends on how PDF.js is built,\n * for 'gulp ' the following cases exist:\n * - FIREFOX or MOZCENTRAL - uses sessionStorage.\n * - GENERIC or CHROME - uses localStorage, if it is available.\n */\nclass ViewHistory {\n constructor(fingerprint, cacheSize = DEFAULT_VIEW_HISTORY_CACHE_SIZE) {\n this.fingerprint = fingerprint;\n this.cacheSize = cacheSize;\n\n this._initializedPromise = this._readFromStorage().then((databaseStr) => {\n let database = JSON.parse(databaseStr || '{}');\n if (!('files' in database)) {\n database.files = [];\n }\n if (database.files.length >= this.cacheSize) {\n database.files.shift();\n }\n let index;\n for (let i = 0, length = database.files.length; i < length; i++) {\n let branch = database.files[i];\n if (branch.fingerprint === this.fingerprint) {\n index = i;\n break;\n }\n }\n if (typeof index !== 'number') {\n index = database.files.push({ fingerprint: this.fingerprint, }) - 1;\n }\n this.file = database.files[index];\n this.database = database;\n });\n }\n\n _writeToStorage() {\n return new Promise((resolve) => {\n let databaseStr = JSON.stringify(this.database);\n\n if (typeof PDFJSDev !== 'undefined' &&\n PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n sessionStorage.setItem('pdfjs.history', databaseStr);\n } else {\n localStorage.setItem('pdfjs.history', databaseStr);\n }\n resolve();\n });\n }\n\n _readFromStorage() {\n return new Promise(function(resolve) {\n if (typeof PDFJSDev !== 'undefined' &&\n PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n resolve(sessionStorage.getItem('pdfjs.history'));\n } else {\n let value = localStorage.getItem('pdfjs.history');\n\n // TODO: Remove this key-name conversion after a suitable time-frame.\n // Note that we only remove the old 'database' entry if it looks like\n // it was created by PDF.js, to avoid removing someone else's data.\n if (!value) {\n let databaseStr = localStorage.getItem('database');\n if (databaseStr) {\n try {\n let database = JSON.parse(databaseStr);\n if (typeof database.files[0].fingerprint === 'string') {\n localStorage.setItem('pdfjs.history', databaseStr);\n localStorage.removeItem('database');\n value = databaseStr;\n }\n } catch (ex) { }\n }\n }\n resolve(value);\n }\n });\n }\n\n set(name, val) {\n return this._initializedPromise.then(() => {\n this.file[name] = val;\n return this._writeToStorage();\n });\n }\n\n setMultiple(properties) {\n return this._initializedPromise.then(() => {\n for (let name in properties) {\n this.file[name] = properties[name];\n }\n return this._writeToStorage();\n });\n }\n\n get(name, defaultValue) {\n return this._initializedPromise.then(() => {\n let val = this.file[name];\n return val !== undefined ? val : defaultValue;\n });\n }\n\n getMultiple(properties) {\n return this._initializedPromise.then(() => {\n let values = Object.create(null);\n\n for (let name in properties) {\n let val = this.file[name];\n values[name] = val !== undefined ? val : properties[name];\n }\n return values;\n });\n }\n}\n\nexport {\n ViewHistory,\n};\n\n\n\n// WEBPACK FOOTER //\n// web/view_history.js", + "/* Copyright 2016 Mozilla Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/* globals chrome */\n\n'use strict';\n\nlet DEFAULT_URL = 'compressed.tracemonkey-pldi-09.pdf';\n\nif (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('CHROME')) {\n (function rewriteUrlClosure() {\n // Run this code outside DOMContentLoaded to make sure that the URL\n // is rewritten as soon as possible.\n let queryString = document.location.search.slice(1);\n let m = /(^|&)file=([^&]*)/.exec(queryString);\n DEFAULT_URL = m ? decodeURIComponent(m[2]) : '';\n\n // Example: chrome-extension://.../http://example.com/file.pdf\n let humanReadableUrl = '/' + DEFAULT_URL + location.hash;\n history.replaceState(history.state, '', humanReadableUrl);\n if (top === window) {\n chrome.runtime.sendMessage('showPageAction');\n }\n })();\n}\n\nlet pdfjsWebApp;\nif (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('PRODUCTION')) {\n pdfjsWebApp = require('./app.js');\n}\n\nif (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('FIREFOX || MOZCENTRAL')) {\n require('./firefoxcom.js');\n require('./firefox_print_service.js');\n}\nif (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('GENERIC')) {\n require('./genericcom.js');\n}\nif (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('CHROME')) {\n require('./chromecom.js');\n}\nif (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('CHROME || GENERIC')) {\n require('./pdf_print_service.js');\n}\n\nfunction getViewerConfiguration() {\n return {\n appContainer: document.body,\n mainContainer: document.getElementById('viewerContainer'),\n viewerContainer: document.getElementById('viewer'),\n eventBus: null, // using global event bus with DOM events\n toolbar: {\n container: document.getElementById('toolbarViewer'),\n numPages: document.getElementById('numPages'),\n pageNumber: document.getElementById('pageNumber'),\n scaleSelectContainer: document.getElementById('scaleSelectContainer'),\n scaleSelect: document.getElementById('scaleSelect'),\n customScaleOption: document.getElementById('customScaleOption'),\n previous: document.getElementById('previous'),\n next: document.getElementById('next'),\n zoomIn: document.getElementById('zoomIn'),\n zoomOut: document.getElementById('zoomOut'),\n viewFind: document.getElementById('viewFind'),\n openFile: document.getElementById('openFile'),\n print: document.getElementById('print'),\n presentationModeButton: document.getElementById('presentationMode'),\n download: document.getElementById('download'),\n viewBookmark: document.getElementById('viewBookmark'),\n },\n secondaryToolbar: {\n toolbar: document.getElementById('secondaryToolbar'),\n toggleButton: document.getElementById('secondaryToolbarToggle'),\n toolbarButtonContainer:\n document.getElementById('secondaryToolbarButtonContainer'),\n presentationModeButton:\n document.getElementById('secondaryPresentationMode'),\n openFileButton: document.getElementById('secondaryOpenFile'),\n printButton: document.getElementById('secondaryPrint'),\n downloadButton: document.getElementById('secondaryDownload'),\n viewBookmarkButton: document.getElementById('secondaryViewBookmark'),\n firstPageButton: document.getElementById('firstPage'),\n lastPageButton: document.getElementById('lastPage'),\n pageRotateCwButton: document.getElementById('pageRotateCw'),\n pageRotateCcwButton: document.getElementById('pageRotateCcw'),\n cursorSelectToolButton: document.getElementById('cursorSelectTool'),\n cursorHandToolButton: document.getElementById('cursorHandTool'),\n documentPropertiesButton: document.getElementById('documentProperties'),\n },\n fullscreen: {\n contextFirstPage: document.getElementById('contextFirstPage'),\n contextLastPage: document.getElementById('contextLastPage'),\n contextPageRotateCw: document.getElementById('contextPageRotateCw'),\n contextPageRotateCcw: document.getElementById('contextPageRotateCcw'),\n },\n sidebar: {\n // Divs (and sidebar button)\n mainContainer: document.getElementById('mainContainer'),\n outerContainer: document.getElementById('outerContainer'),\n toggleButton: document.getElementById('sidebarToggle'),\n // Buttons\n thumbnailButton: document.getElementById('viewThumbnail'),\n outlineButton: document.getElementById('viewOutline'),\n attachmentsButton: document.getElementById('viewAttachments'),\n // Views\n thumbnailView: document.getElementById('thumbnailView'),\n outlineView: document.getElementById('outlineView'),\n attachmentsView: document.getElementById('attachmentsView'),\n },\n findBar: {\n bar: document.getElementById('findbar'),\n toggleButton: document.getElementById('viewFind'),\n findField: document.getElementById('findInput'),\n highlightAllCheckbox: document.getElementById('findHighlightAll'),\n caseSensitiveCheckbox: document.getElementById('findMatchCase'),\n findMsg: document.getElementById('findMsg'),\n findResultsCount: document.getElementById('findResultsCount'),\n findStatusIcon: document.getElementById('findStatusIcon'),\n findPreviousButton: document.getElementById('findPrevious'),\n findNextButton: document.getElementById('findNext'),\n },\n passwordOverlay: {\n overlayName: 'passwordOverlay',\n container: document.getElementById('passwordOverlay'),\n label: document.getElementById('passwordText'),\n input: document.getElementById('password'),\n submitButton: document.getElementById('passwordSubmit'),\n cancelButton: document.getElementById('passwordCancel'),\n },\n documentProperties: {\n overlayName: 'documentPropertiesOverlay',\n container: document.getElementById('documentPropertiesOverlay'),\n closeButton: document.getElementById('documentPropertiesClose'),\n fields: {\n 'fileName': document.getElementById('fileNameField'),\n 'fileSize': document.getElementById('fileSizeField'),\n 'title': document.getElementById('titleField'),\n 'author': document.getElementById('authorField'),\n 'subject': document.getElementById('subjectField'),\n 'keywords': document.getElementById('keywordsField'),\n 'creationDate': document.getElementById('creationDateField'),\n 'modificationDate': document.getElementById('modificationDateField'),\n 'creator': document.getElementById('creatorField'),\n 'producer': document.getElementById('producerField'),\n 'version': document.getElementById('versionField'),\n 'pageCount': document.getElementById('pageCountField'),\n },\n },\n errorWrapper: {\n container: document.getElementById('errorWrapper'),\n errorMessage: document.getElementById('errorMessage'),\n closeButton: document.getElementById('errorClose'),\n errorMoreInfo: document.getElementById('errorMoreInfo'),\n moreInfoButton: document.getElementById('errorShowMore'),\n lessInfoButton: document.getElementById('errorShowLess'),\n },\n printContainer: document.getElementById('printContainer'),\n openFileInputName: 'fileInput',\n debuggerScriptPath: './debugger.js',\n defaultUrl: DEFAULT_URL,\n };\n}\n\nfunction webViewerLoad() {\n let config = getViewerConfiguration();\n if (typeof PDFJSDev === 'undefined' || !PDFJSDev.test('PRODUCTION')) {\n Promise.all([\n SystemJS.import('pdfjs-web/app'),\n SystemJS.import('pdfjs-web/genericcom'),\n SystemJS.import('pdfjs-web/pdf_print_service'),\n ]).then(function([app, ...otherModules]) {\n window.PDFViewerApplication = app.PDFViewerApplication;\n app.PDFViewerApplication.run(config);\n });\n } else {\n window.PDFViewerApplication = pdfjsWebApp.PDFViewerApplication;\n pdfjsWebApp.PDFViewerApplication.run(config);\n }\n}\n\nif (document.readyState === 'interactive' ||\n document.readyState === 'complete') {\n webViewerLoad();\n} else {\n document.addEventListener('DOMContentLoaded', webViewerLoad, true);\n}\n\n\n\n// WEBPACK FOOTER //\n// web/viewer.js" + ], + "sourceRoot": "" +} \ No newline at end of file diff --git a/twake/frontend/public/public/viewer/VideoViewer/viewer.html b/twake/frontend/public/public/viewer/VideoViewer/viewer.html new file mode 100755 index 00000000..3cc1832b --- /dev/null +++ b/twake/frontend/public/public/viewer/VideoViewer/viewer.html @@ -0,0 +1,38 @@ + + + + + + + + + + diff --git a/twake/frontend/public/robots.txt b/twake/frontend/public/robots.txt new file mode 100644 index 00000000..e9e57dc4 --- /dev/null +++ b/twake/frontend/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/twake/frontend/scripts/build.js b/twake/frontend/scripts/build.js new file mode 100644 index 00000000..40319770 --- /dev/null +++ b/twake/frontend/scripts/build.js @@ -0,0 +1,198 @@ +'use strict'; + +// Do this as the first thing so that any code reading it knows the right env. +process.env.BABEL_ENV = 'production'; +process.env.NODE_ENV = 'production'; + +// Makes the script crash on unhandled rejections instead of silently +// ignoring them. In the future, promise rejections that are not handled will +// terminate the Node.js process with a non-zero exit code. +process.on('unhandledRejection', err => { + throw err; +}); + +// Ensure environment variables are read. +require('../config/env'); + +const path = require('path'); +const chalk = require('react-dev-utils/chalk'); +const fs = require('fs-extra'); +const webpack = require('webpack'); +const configFactory = require('../config/webpack.config'); +const paths = require('../config/paths'); +const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); +const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages'); +const printHostingInstructions = require('react-dev-utils/printHostingInstructions'); +const FileSizeReporter = require('react-dev-utils/FileSizeReporter'); +const printBuildError = require('react-dev-utils/printBuildError'); + +const measureFileSizesBeforeBuild = FileSizeReporter.measureFileSizesBeforeBuild; +const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild; +const useYarn = fs.existsSync(paths.yarnLockFile); + +// These sizes are pretty large. We'll warn for bundles exceeding them. +const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024; +const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024; + +const isInteractive = process.stdout.isTTY; + +// Warn and crash if required files are missing +if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { + process.exit(1); +} + +// Generate configuration +const config = configFactory('production'); + +// We require that you explicitly set browsers and do not fall back to +// browserslist defaults. +const { checkBrowsers } = require('react-dev-utils/browsersHelper'); +checkBrowsers(paths.appPath, isInteractive) + .then(() => { + // First, read the current file sizes in build directory. + // This lets us display how much they changed later. + return measureFileSizesBeforeBuild(paths.appBuild); + }) + .then(previousFileSizes => { + // Remove all content but keep the directory so that + // if you're in it, you don't end up in Trash + fs.emptyDirSync(paths.appBuild); + // Merge with the public folder + copyPublicFolder(); + // Start the webpack build + return build(previousFileSizes); + }) + .then( + ({ stats, previousFileSizes, warnings }) => { + if (warnings.length) { + console.log(chalk.yellow('Compiled with warnings.\n')); + console.log(warnings.join('\n\n')); + console.log( + '\nSearch for the ' + + chalk.underline(chalk.yellow('keywords')) + + ' to learn more about each warning.', + ); + console.log( + 'To ignore, add ' + chalk.cyan('// eslint-disable-next-line') + ' to the line before.\n', + ); + } else { + console.log(chalk.green('Compiled successfully.\n')); + } + + console.log('File sizes after gzip:\n'); + printFileSizesAfterBuild( + stats, + previousFileSizes, + paths.appBuild, + WARN_AFTER_BUNDLE_GZIP_SIZE, + WARN_AFTER_CHUNK_GZIP_SIZE, + ); + console.log(); + + const appPackage = require(paths.appPackageJson); + const publicUrl = paths.publicUrlOrPath; + const publicPath = config.output.publicPath; + const buildFolder = path.relative(process.cwd(), paths.appBuild); + printHostingInstructions(appPackage, publicUrl, publicPath, buildFolder, useYarn); + }, + err => { + const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true'; + if (tscCompileOnError) { + console.log( + chalk.yellow( + 'Compiled with the following type errors (you may want to check these before deploying your app):\n', + ), + ); + printBuildError(err); + } else { + console.log(chalk.red('Failed to compile.\n')); + printBuildError(err); + process.exit(1); + } + }, + ) + .catch(err => { + if (err && err.message) { + console.log(err.message); + } + process.exit(1); + }); + +// Create the production build and print the deployment instructions. +function build(previousFileSizes) { + // We used to support resolving modules according to `NODE_PATH`. + // This now has been deprecated in favor of jsconfig/tsconfig.json + // This lets you use absolute paths in imports inside large monorepos: + if (process.env.NODE_PATH) { + console.log( + chalk.yellow( + 'Setting NODE_PATH to resolve modules absolutely has been deprecated in favor of setting baseUrl in jsconfig.json (or tsconfig.json if you are using TypeScript) and will be removed in a future major release of create-react-app.', + ), + ); + console.log(); + } + + console.log('Creating an optimized production build...'); + + const compiler = webpack(config); + return new Promise((resolve, reject) => { + compiler.run((err, stats) => { + let messages; + if (err) { + if (!err.message) { + return reject(err); + } + + let errMessage = err.message; + + // Add additional information for postcss errors + if (Object.prototype.hasOwnProperty.call(err, 'postcssNode')) { + errMessage += '\nCompileError: Begins at CSS selector ' + err['postcssNode'].selector; + } + + messages = formatWebpackMessages({ + errors: [errMessage], + warnings: [], + }); + } else { + messages = formatWebpackMessages( + stats.toJson({ all: false, warnings: true, errors: true }), + ); + } + if (messages.errors.length) { + // Only keep the first error. Others are often indicative + // of the same problem, but confuse the reader with noise. + if (messages.errors.length > 1) { + messages.errors.length = 1; + } + return reject(new Error(messages.errors.join('\n\n'))); + } + if ( + process.env.CI && + (typeof process.env.CI !== 'string' || process.env.CI.toLowerCase() !== 'false') && + messages.warnings.length + ) { + console.log( + chalk.yellow( + '\nTreating warnings as errors because process.env.CI = true.\n' + + 'Most CI servers set it automatically.\n', + ), + ); + return reject(new Error(messages.warnings.join('\n\n'))); + } + + return resolve({ + stats, + previousFileSizes, + warnings: messages.warnings, + }); + }); + }); +} + +function copyPublicFolder() { + fs.copySync(paths.appPublic, paths.appBuild, { + dereference: true, + filter: file => file !== paths.appHtml, + }); +} diff --git a/twake/frontend/scripts/envBuilding.js b/twake/frontend/scripts/envBuilding.js new file mode 100755 index 00000000..c182e1c8 --- /dev/null +++ b/twake/frontend/scripts/envBuilding.js @@ -0,0 +1,21 @@ +var exec = require('child_process').exec; +const fs = require('fs'); + +var args = process.argv.slice(2); +const oldVersionDetails = args[0]; +const newVersionDetails = args[1]; +const newVersion = args[2]; + +const relativeEnvironment = './src/app/environment/version.ts'; +const relativeIndex = './public/index.html'; + +exec('cat ' + relativeEnvironment, (err, stdout, stderr) => { + stdout = stdout.replace("'" + oldVersionDetails + "'", "'" + newVersionDetails + "'"); + stdout = stdout.replace("'" + oldVersionDetails.substr(0, 3) + "'", "'" + newVersion + "'"); + fs.writeFileSync(relativeEnvironment, stdout); +}); + +exec('cat ' + relativeIndex, (err, stdout, stderr) => { + stdout = stdout.replace(oldVersionDetails, newVersionDetails); + fs.writeFileSync(relativeIndex, stdout); +}); diff --git a/twake/frontend/scripts/formatFilesAndFolders.js b/twake/frontend/scripts/formatFilesAndFolders.js new file mode 100755 index 00000000..29b938c0 --- /dev/null +++ b/twake/frontend/scripts/formatFilesAndFolders.js @@ -0,0 +1,143 @@ +const fs = require('fs'); +const Path = require('path'); +const _ = require('lodash'); + +const appUrl = '../src/app'; +const componentsUrl = `${appUrl}/components`; +const modelsUrl = `${appUrl}/models`; +const scenesUrl = `${appUrl}/scenes`; +const servicesUrl = `${appUrl}/services`; + +const routes = new Map(); + +const isDirectory = path => fs.lstatSync(path).isDirectory(); + +// pwd must start with 'src/...' +const getAbsolutePath = (path, pwd = appUrl) => { + if (path[0] === '.') { + const mergePath = Path.resolve(pwd, path); + + console.log({ pwd, path, resolve: mergePath }); + return mergePath; + } + + path = path.replace(/^app\//, appUrl + '/'); + path = path.replace(/^environment\//, appUrl + '/environment/'); + path = path.replace(/^common\//, appUrl + '/common/'); + path = path.replace(/^components\//, appUrl + '/components/'); + path = path.replace(/^services\//, appUrl + '/services/'); + path = path.replace(/^scenes\//, appUrl + '/scenes/'); + path = path.replace(/^apps\//, appUrl + '/apps/'); + + return Path.resolve(path); +}; +const renameItem = item => { + // Keywords that should be skipped + const toSkip = [ + '.', + '..', + 'feather', + 'README.md', + 'react-feather', + 'unicons.eot', + 'unicons.svg', + 'unicons.ttf', + 'unicons.woff', + 'unicons.woff2', + ]; + + const name = item.split('.')[0]; + const extension = item.split('.')[1] ? `.${item.split('.')[1]}` : undefined; + + return toSkip.includes(item) + ? item + : `${_.lowerCase(name).replace(/ /g, '-')}${extension ? extension : ''}`; +}; + +const updateMap = (rootUrl, fileOrFolderPath = false) => { + let newFileOrFolderPath = rootUrl; + if (fileOrFolderPath) { + const oldFileOrFolderPath = `${rootUrl}/${fileOrFolderPath}`; + newFileOrFolderPath = `${rootUrl}/${fileOrFolderPath}`; + routes.set(getAbsolutePath(oldFileOrFolderPath, '.'), true); + } + + if (isDirectory(newFileOrFolderPath)) { + const files = fs.readdirSync(newFileOrFolderPath); + files.forEach(fileOrFolderPath => { + updateMap(newFileOrFolderPath, fileOrFolderPath); + }); + } +}; + +const processRename = (rootUrl, fileOrFolderPath = false) => { + let newFileOrFolderPath = rootUrl; + + if (fileOrFolderPath) { + const newFileOrFolderName = renameItem(fileOrFolderPath); + const oldFileOrFolderPath = `${rootUrl}/${fileOrFolderPath}`; + newFileOrFolderPath = `${rootUrl}/${newFileOrFolderName}`; + + fs.renameSync(oldFileOrFolderPath, newFileOrFolderPath); + } + + if (isDirectory(newFileOrFolderPath)) { + const files = fs.readdirSync(newFileOrFolderPath); + files.forEach(fileOrFolderPath => { + processRename(newFileOrFolderPath, fileOrFolderPath); + }); + } +}; + +const recursiveWatchingImports = (rootPath, fileOrFolderPath = false) => { + const nextPath = fileOrFolderPath ? `${rootPath}/${fileOrFolderPath}` : rootPath; + if (!isDirectory(nextPath)) { + let content = fs.readFileSync(nextPath, { encoding: 'utf-8' }); + + if (nextPath.includes('/environment/')) { + return; + } + + const importedPaths = Array.from( + content.matchAll(/^(import|export .*?from) .*?('|")(.*?)('|").*?$/gm), + ).map(s => s[3]); + + importedPaths.forEach(path => { + const absolutePath = getAbsolutePath(path, rootPath); + + //Test if absolutePath is in map + if ( + routes.has(absolutePath) || + routes.has(absolutePath + '.js') || + routes.has(absolutePath + '.jsx') || + routes.has(absolutePath + '.ts') || + routes.has(absolutePath + '.tsx') || + routes.has(absolutePath + '.scss') || + routes.has(absolutePath + '.less') + ) { + const newPath = path.split('/').map(renameItem).join('/'); + content = content.replace(path, newPath); + } + }); + + fs.writeFileSync(nextPath, content); + } else { + const files = fs.readdirSync(nextPath); + files.forEach(fileOrFolderPath => { + recursiveWatchingImports(nextPath, fileOrFolderPath); + }); + } +}; + +const cleanFiles = async () => { + //Fill up map with all the files we gonna rename + updateMap(componentsUrl); + + // Now we should look at each files to see if there is a match with the previous changes and modify the related imports + recursiveWatchingImports(appUrl); + + //Rename files and folders recursivelly + processRename(componentsUrl); +}; + +cleanFiles(); diff --git a/twake/frontend/scripts/server.js b/twake/frontend/scripts/server.js new file mode 100755 index 00000000..32cd3ec2 --- /dev/null +++ b/twake/frontend/scripts/server.js @@ -0,0 +1,13 @@ +var connect = require('connect'); +var serveStatic = require('serve-static'); +connect() + .use(serveStatic(__dirname + '/../public/'), { + fallthrough: true, + }) + .use((req, res, next) => { + req.path = req.url = '/index.html'; + serveStatic(__dirname + '/../public/')(req, res, next); + }) + .listen(8080, function() { + console.log('Server running on 8080...'); + }); diff --git a/twake/frontend/scripts/start.js b/twake/frontend/scripts/start.js new file mode 100644 index 00000000..623809af --- /dev/null +++ b/twake/frontend/scripts/start.js @@ -0,0 +1,138 @@ +'use strict'; + +// Do this as the first thing so that any code reading it knows the right env. +process.env.BABEL_ENV = 'development'; +process.env.NODE_ENV = 'development'; + +// Makes the script crash on unhandled rejections instead of silently +// ignoring them. In the future, promise rejections that are not handled will +// terminate the Node.js process with a non-zero exit code. +process.on('unhandledRejection', err => { + throw err; +}); + +// Ensure environment variables are read. +require('../config/env'); + +const fs = require('fs'); +const chalk = require('react-dev-utils/chalk'); +const webpack = require('webpack'); +const WebpackDevServer = require('webpack-dev-server'); +const clearConsole = require('react-dev-utils/clearConsole'); +const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); +const { + choosePort, + createCompiler, + prepareProxy, + prepareUrls, +} = require('react-dev-utils/WebpackDevServerUtils'); +const openBrowser = require('react-dev-utils/openBrowser'); +const paths = require('../config/paths'); +const configFactory = require('../config/webpack.config'); +const createDevServerConfig = require('../config/webpackDevServer.config'); + +const useYarn = fs.existsSync(paths.yarnLockFile); +const isInteractive = process.stdout.isTTY; + +// Warn and crash if required files are missing +if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { + process.exit(1); +} + +// Tools like Cloud9 rely on this. +const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000; +const HOST = process.env.HOST || '0.0.0.0'; + +if (process.env.HOST) { + console.log( + chalk.cyan( + `Attempting to bind to HOST environment variable: ${chalk.yellow( + chalk.bold(process.env.HOST), + )}`, + ), + ); + console.log(`If this was unintentional, check that you haven't mistakenly set it in your shell.`); + console.log(`Learn more here: ${chalk.yellow('https://bit.ly/CRA-advanced-config')}`); + console.log(); +} + +// We require that you explicitly set browsers and do not fall back to +// browserslist defaults. +const { checkBrowsers } = require('react-dev-utils/browsersHelper'); +checkBrowsers(paths.appPath, isInteractive) + .then(() => { + // We attempt to use the default port but if it is busy, we offer the user to + // run on a different port. `choosePort()` Promise resolves to the next free port. + return choosePort(HOST, DEFAULT_PORT); + }) + .then(port => { + if (port == null) { + // We have not found a port. + return; + } + + const config = configFactory('development'); + const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; + const appName = require(paths.appPackageJson).name; + const useTypeScript = fs.existsSync(paths.appTsConfig); + const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true'; + const urls = prepareUrls(protocol, HOST, port, paths.publicUrlOrPath.slice(0, -1)); + const devSocket = { + warnings: warnings => devServer.sockWrite(devServer.sockets, 'warnings', warnings), + errors: errors => devServer.sockWrite(devServer.sockets, 'errors', errors), + }; + // Create a webpack compiler that is configured with custom messages. + const compiler = createCompiler({ + appName, + config, + devSocket, + urls, + useYarn, + useTypeScript, + tscCompileOnError, + webpack, + }); + // Load proxy config + const proxySetting = require(paths.appPackageJson).proxy; + const proxyConfig = prepareProxy(proxySetting, paths.appPublic, paths.publicUrlOrPath); + // Serve webpack assets generated by the compiler over a web server. + const serverConfig = createDevServerConfig(proxyConfig, urls.lanUrlForConfig); + const devServer = new WebpackDevServer(compiler, serverConfig); + // Launch WebpackDevServer. + devServer.listen(port, HOST, err => { + if (err) { + return console.log(err); + } + if (isInteractive) { + clearConsole(); + } + + // We used to support resolving modules according to `NODE_PATH`. + // This now has been deprecated in favor of jsconfig/tsconfig.json + // This lets you use absolute paths in imports inside large monorepos: + if (process.env.NODE_PATH) { + console.log( + chalk.yellow( + 'Setting NODE_PATH to resolve modules absolutely has been deprecated in favor of setting baseUrl in jsconfig.json (or tsconfig.json if you are using TypeScript) and will be removed in a future major release of create-react-app.', + ), + ); + console.log(); + } + + console.log(chalk.cyan('Starting the development server...\n')); + openBrowser(urls.localUrlForBrowser); + }); + + ['SIGINT', 'SIGTERM'].forEach(function (sig) { + process.on(sig, function () { + devServer.close(); + process.exit(); + }); + }); + }) + .catch(err => { + if (err && err.message) { + console.log(err.message); + } + process.exit(1); + }); diff --git a/twake/frontend/scripts/test.js b/twake/frontend/scripts/test.js new file mode 100644 index 00000000..b57cb383 --- /dev/null +++ b/twake/frontend/scripts/test.js @@ -0,0 +1,53 @@ +'use strict'; + +// Do this as the first thing so that any code reading it knows the right env. +process.env.BABEL_ENV = 'test'; +process.env.NODE_ENV = 'test'; +process.env.PUBLIC_URL = ''; + +// Makes the script crash on unhandled rejections instead of silently +// ignoring them. In the future, promise rejections that are not handled will +// terminate the Node.js process with a non-zero exit code. +process.on('unhandledRejection', err => { + throw err; +}); + +// Ensure environment variables are read. +require('../config/env'); + + +const jest = require('jest'); +const execSync = require('child_process').execSync; +let argv = process.argv.slice(2); + +function isInGitRepository() { + try { + execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' }); + return true; + } catch (e) { + return false; + } +} + +function isInMercurialRepository() { + try { + execSync('hg --cwd . root', { stdio: 'ignore' }); + return true; + } catch (e) { + return false; + } +} + +// Watch unless on CI or explicitly running all tests +if ( + !process.env.CI && + argv.indexOf('--watchAll') === -1 && + argv.indexOf('--watchAll=false') === -1 +) { + // https://github.com/facebook/create-react-app/issues/5210 + const hasSourceControl = isInGitRepository() || isInMercurialRepository(); + argv.push(hasSourceControl ? '--watch' : '--watchAll'); +} + + +jest.run(argv); diff --git a/twake/frontend/src/app/app.tsx b/twake/frontend/src/app/app.tsx new file mode 100755 index 00000000..21840e61 --- /dev/null +++ b/twake/frontend/src/app/app.tsx @@ -0,0 +1,97 @@ +// eslint-disable-next-line @typescript-eslint/no-use-before-define +import React, { useEffect, useState } from 'react'; +import { Router } from 'react-router'; +import { Switch, Route } from 'react-router-dom'; +import { RecoilRoot } from 'recoil'; + +import MobileRedirect from './views/mobile-redirect'; +import Integration from 'app/views/integration'; +import RouterServices, { RouteType } from './features/router/services/router-service'; +import ErrorBoundary from 'app/views/error/error-boundary'; +import InitService from './features/global/services/init-service'; +import useTimeout from 'app/features/global/hooks/use-timeout'; +import ApplicationLoader from './components/loader/application-loader'; + +import DebugState from './components/debug/debug-state'; +import 'app/styles/index.less'; + +const delayMessage = 5000; + +export default () => { + const [displayDelayLoader, setDisplayDelayLoader] = useState(false); + const [firstRenderDate] = useState(Date.now()); + + useEffect(() => { + InitService.init(); + }, []); + + const server_infos_loaded = InitService.useWatcher(() => InitService.server_infos_loaded); + + useTimeout(() => { + if (!server_infos_loaded && Date.now() >= firstRenderDate + delayMessage) { + setDisplayDelayLoader(true); + } + }, delayMessage); + + useEffect(() => { + if (server_infos_loaded) { + setDisplayDelayLoader(false); + try { + window.document.getElementById('app_loader')?.remove(); + } catch (err) { + //Null + } + } + }, [server_infos_loaded]); + + if (displayDelayLoader && !server_infos_loaded) { + return ; + } + + if (!server_infos_loaded) { + return <>; + } + + return ( + + + + + + + {RouterServices.routes.map((route: RouteType, index: number) => ( + + route.options?.withErrorBoundary ? ( + + + + ) : ( + + ) + } + /> + ))} + { + { + RouterServices.replace( + `${ + RouterServices.pathnames.LOGIN + }?auto&${RouterServices.history.location.search.substr(1)}`, + ); + return
; + }} + /> + } + + + + + + ); +}; diff --git a/twake/frontend/src/app/atoms/_avatar/avatar.tsx b/twake/frontend/src/app/atoms/_avatar/avatar.tsx new file mode 100644 index 00000000..971e96da --- /dev/null +++ b/twake/frontend/src/app/atoms/_avatar/avatar.tsx @@ -0,0 +1,44 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import _ from 'lodash'; + +export default function Avatar( + props: any & { + avatar: string; + size: 28 | 14 | 48; + }, +) { + const size = props.size || 14; + const className = + ' inline-block h-' + + size + + ' w-' + + size + + ' rounded-full overflow-hidden bg-zinc-200 ' + + (props.className || ''); + + if (props.avatar || props.src) { + return ( +
+ ); + } + + return ( + + + + + + ); +} diff --git a/twake/frontend/src/app/atoms/alert/index.tsx b/twake/frontend/src/app/atoms/alert/index.tsx new file mode 100644 index 00000000..37bc8902 --- /dev/null +++ b/twake/frontend/src/app/atoms/alert/index.tsx @@ -0,0 +1,51 @@ +export const Alert = (props: { + theme: 'success' | 'danger' | 'warning' | 'gray' | 'primary'; + title: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + icon: any; + className?: string; + bullets?: string[]; + children?: React.ReactNode; +}) => { + let color = 'blue'; + let textColor = 'white'; + if (props.theme === 'success') color = 'green-500'; + if (props.theme === 'danger') color = 'red-500'; + if (props.theme === 'warning') color = 'orange-500'; + if (props.theme === 'gray') { + color = 'zinc-50'; + textColor = 'zinc-900'; + } + if (props.theme === 'primary') { + color = 'blue-100'; + textColor = 'zinc-900'; + } + + return ( +
+
+
+
+
+

{props.title}

+ {(props.bullets || []).length > 0 && ( +
+
    + {(props.bullets || []).map(bullet => ( +
  • {bullet}
  • + ))} +
+
+ )} + {props.children} +
+
+
+ ); +}; diff --git a/twake/frontend/src/app/atoms/avatar/index.stories.tsx b/twake/frontend/src/app/atoms/avatar/index.stories.tsx new file mode 100644 index 00000000..46250349 --- /dev/null +++ b/twake/frontend/src/app/atoms/avatar/index.stories.tsx @@ -0,0 +1,56 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { ComponentStory } from '@storybook/react'; +import Avatar from '.'; +import { UsersIcon } from '../icons-agnostic'; + +export default { + title: '@atoms/avatar', +}; +type sizeType = 'lg' | 'md' | 'sm'; +type shapeType = 'circle' | 'square'; + +const Template: ComponentStory = (args: { title: string }) => { + const types = ['circle', 'square'] as shapeType[]; + const sizes = ['lg', 'md', 'sm'] as sizeType[]; + const values = [ + { title: args.title }, + { + title: args.title, + avatar: + 'https://images.freeimages.com/images/small-previews/d67/experimenting-with-nature-1547377.jpg', + }, + { + icon: , + className: '', + }, + ]; + + return ( + <> +
+ {sizes.map(size => ( +
+ {types.map(tp => + values.map(val => ( + + )), + )} +
+ ))} +
+ + ); +}; + +export const Default = Template.bind({}); +Default.args = { + title: 'User Name', +}; diff --git a/twake/frontend/src/app/atoms/avatar/index.tsx b/twake/frontend/src/app/atoms/avatar/index.tsx new file mode 100644 index 00000000..e41630fb --- /dev/null +++ b/twake/frontend/src/app/atoms/avatar/index.tsx @@ -0,0 +1,101 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import React from 'react'; +import _ from 'lodash'; +import CryptoJS from 'crypto-js'; + +// @ts-ignore + +interface AvatarProps extends React.InputHTMLAttributes { + type?: 'circle' | 'square'; + size?: 'xl' | 'lg' | 'md' | 'sm' | 'xs'; + avatar?: string; + icon?: JSX.Element | false; + title?: string; + nogradient?: boolean; +} + +const sizes = { xl: 24, lg: 14, md: 11, sm: 9, xs: 6 }; +const fontSizes = { xl: '2xl', lg: '2xl', md: 'lg', sm: 'md', xs: 'sm' }; + +export const getGradient = (name: string) => { + const seed = parseInt(CryptoJS.MD5(name).toString().slice(0, 8), 16); + const canvas: HTMLCanvasElement = document.createElement('canvas'); + canvas.width = 254; + canvas.height = 254; + const ctx = canvas.getContext('2d'); + const gradient = ctx!.createLinearGradient(254, 254, 0, 0); + gradient.addColorStop(0, 'hsl(' + seed + ', 90%, 70%)'); + gradient.addColorStop(1, 'hsl(' + Math.abs(seed - 60) + ', 90%, 70%)'); + ctx!.fillStyle = gradient; + ctx!.fillRect(0, 0, 254, 254); + const b64 = canvas.toDataURL('image/jpeg'); + return b64; +}; + +export default function Avatar(props: AvatarProps) { + const avatarType = props.type || 'circle'; + const avatarSize = sizes[props.size || 'md']; + const fontSize = fontSizes[props.size || 'md']; + const addedClassName = props.className || ''; + const avatarTitle = props.title || ''; + const restProps = _.omit(props, 'size', 'type', 'avatar', 'title', 'className', 'icon'); + + let className = `w-${avatarSize} h-${avatarSize} ${ + avatarType === 'circle' ? 'rounded-full' : 'rounded-sm' + } `; + + className += + ' border border-gray flex items-center justify-center bg-center bg-cover ' + + (props.nogradient ? ' bg-zinc-100 dark:bg-zinc-800 text-zinc-900 dark:text-white ' : ''); + + const spl_title = avatarTitle.split(' '); + + let letters = avatarTitle.slice(0, 1); + if (spl_title.length > 1) { + letters = spl_title[0].slice(0, 1) + spl_title[1].slice(0, 1); + } + + const lettersClass = + `font-medium bg-gray text-${fontSize}` + + (props.nogradient ? ' text-zinc-900 dark:text-white ' : ' text-white'); + + const style = props.nogradient + ? {} + : { backgroundImage: `url('${getGradient(props.title || '')}')` }; + + if (props.icon) { + className += ' '; + return ( +
+ {props.icon} +
+ ); + } + + if (props.avatar) { + return ( +
+ {props.title} +
+ ); + } + + return ( +
+
{letters.toUpperCase()}
+
+ ); +} diff --git a/twake/frontend/src/app/atoms/badge/index.stories.tsx b/twake/frontend/src/app/atoms/badge/index.stories.tsx new file mode 100644 index 00000000..709e3f56 --- /dev/null +++ b/twake/frontend/src/app/atoms/badge/index.stories.tsx @@ -0,0 +1,108 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { ComponentStory } from '@storybook/react'; +import { Badge } from '.'; +import { PlusIcon, SearchIcon } from '@heroicons/react/solid'; +import { TrashIcon } from '@heroicons/react/outline'; + +export default { + title: '@atoms/button', +}; + +const Template: ComponentStory = (props: { + text: string; + disabled: boolean; + loading: boolean; +}) => { + return ( + <> + + {props.text} + + + + {props.text} + + + + {props.text} + + + + {props.text} + + + + {props.text} + + +
+ + + Search + + + + Add + + + + +
+ + + {props.text} + + + + {props.text} + + + + {props.text} + + +
+ + + + + + + +
+ + + Add + + + ); +}; + +export const Default = Template.bind({}); +Default.args = { + text: 'Text', + loading: false, +}; diff --git a/twake/frontend/src/app/atoms/badge/index.tsx b/twake/frontend/src/app/atoms/badge/index.tsx new file mode 100644 index 00000000..87a99175 --- /dev/null +++ b/twake/frontend/src/app/atoms/badge/index.tsx @@ -0,0 +1,76 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React from 'react'; +import _ from 'lodash'; + +interface BadgeProps extends Omit, 'size'> { + theme?: 'primary' | 'secondary' | 'danger' | 'default' | 'outline'; + size?: 'md' | 'lg' | 'sm'; + icon?: (props: any) => JSX.Element; + loading?: boolean; + children?: React.ReactNode; +} + +export const Badge = (props: BadgeProps) => { + let className = 'text-white bg-blue-500 border-transparent '; + + if (props.theme === 'secondary') className = 'text-blue-500 bg-blue-100 border-transparent '; + + if (props.theme === 'danger') className = 'text-white bg-rose-500 border-transparent '; + + if (props.theme === 'default') + className = 'text-black dark:text-white bg-white dark:bg-zinc-800 border-gray-300'; + + if (props.theme === 'outline') + className = 'text-blue-500 bg-white dark:bg-zinc-800 border-blue-500'; + + if (props.size === 'lg') className = className + ' text-lg h-11'; + else if (props.size === 'sm') className = className + ' text-sm h-7 px-3'; + else className = className + ' text-base h-9'; + + if (!props.children) { + if (props.size === 'lg') className = className + ' w-11 !p-0 justify-center'; + else if (props.size === 'sm') className = className + ' w-7 !p-0 justify-center'; + else className = className + ' w-9 !p-0 justify-center'; + } + + return ( +
+ {props.loading && ( + <> + + + + {' '} + + )} + {props.icon && !(props.loading && !props.children) && ( + + )} + {props.children} +
+ ); +}; diff --git a/twake/frontend/src/app/atoms/button/button.stories.tsx b/twake/frontend/src/app/atoms/button/button.stories.tsx new file mode 100644 index 00000000..aa47cb94 --- /dev/null +++ b/twake/frontend/src/app/atoms/button/button.stories.tsx @@ -0,0 +1,181 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React from 'react'; +import { ComponentStory } from '@storybook/react'; +import { Button } from './button'; +import { PlusIcon, SearchIcon } from '@heroicons/react/solid'; +import { TrashIcon } from '@heroicons/react/outline'; +import { UserAddIcon } from '@atoms/icons-agnostic/index'; + +export default { + title: '@atoms/button', +}; + +const Template: ComponentStory = (props: { + text: string; + disabled: boolean; + loading: boolean; +}) => { + return ( + <> + + + + + + + + + + +
+ + + + + + + + + + + +
+ + + + + + ); +}; + +export const Default = Template.bind({}); +Default.args = { + text: 'Text', + loading: false, + disabled: false, +}; diff --git a/twake/frontend/src/app/atoms/button/button.tsx b/twake/frontend/src/app/atoms/button/button.tsx new file mode 100644 index 00000000..685be3f0 --- /dev/null +++ b/twake/frontend/src/app/atoms/button/button.tsx @@ -0,0 +1,98 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React from 'react'; +import _ from 'lodash'; + +interface ButtonProps extends React.ButtonHTMLAttributes { + theme?: 'primary' | 'secondary' | 'danger' | 'default' | 'outline' | 'dark'; + size?: 'md' | 'lg' | 'sm'; + icon?: (props: any) => JSX.Element; + iconSize?: 'md' | 'lg'; + loading?: boolean; + disabled?: boolean; + children?: React.ReactNode; +} + +export const Button = (props: ButtonProps) => { + const disabled = props.disabled || props.loading; + + let className = 'text-white bg-blue-500 hover:bg-blue-700 active:bg-blue-800 border-transparent '; + + if (props.theme === 'secondary') + className = + 'text-blue-500 bg-blue-100 hover:bg-blue-200 active:bg-blue-300 border-transparent '; + + if (props.theme === 'danger') + className = 'text-white bg-rose-500 hover:bg-rose-600 active:bg-rose-700 border-transparent '; + + if (props.theme === 'default') + className = + 'text-black dark:text-white bg-white dark:bg-zinc-800 dark:hover:bg-zinc-700 dark:active:bg-zinc-900 hover:bg-gray-50 active:bg-gray-200 border-gray-300'; + + if (props.theme === 'outline') + className = + 'text-blue-500 bg-white dark:bg-zinc-800 dark:hover:bg-zinc-700 dark:active:bg-zinc-900 hover:bg-gray-50 active:bg-gray-200 border-blue-500'; + + if (props.theme === 'dark') + className = + 'text-zinc-300 border-0 bg-zinc-900 hover:bg-zinc-800 hover:text-white active:bg-zinc-900'; + + if (disabled) className += ' opacity-50 pointer-events-none'; + + if (props.size === 'lg') className = className + ' text-lg h-11'; + else if (props.size === 'sm') className = className + ' text-sm h-7 px-3'; + else className = className + ' text-base h-9'; + + if (!props.children) { + if (props.size === 'lg') className = className + ' w-11 !p-0 justify-center'; + else if (props.size === 'sm') className = className + ' w-7 !p-0 justify-center'; + else className = className + ' w-9 !p-0 justify-center'; + } + + return ( + + ); +}; diff --git a/twake/frontend/src/app/atoms/button/confirm.stories.tsx b/twake/frontend/src/app/atoms/button/confirm.stories.tsx new file mode 100644 index 00000000..10b45ce8 --- /dev/null +++ b/twake/frontend/src/app/atoms/button/confirm.stories.tsx @@ -0,0 +1,57 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React from 'react'; +import { ComponentStory } from '@storybook/react'; +import { ButtonConfirm } from './confirm'; +import { RecoilRoot } from 'recoil'; + +export default { + title: '@atoms/button-confirm', +}; + +const Template: ComponentStory = (props: { + text: string; + disabled: boolean; + loading: boolean; +}) => { + return ( + + + {props.text} + +
+ + {props.text} + +
+ + {props.text} + +
+ + {props.text} + +
+ ); +}; + +export const Default = Template.bind({}); +Default.args = { + text: 'Text', + loading: false, + disabled: false, +}; diff --git a/twake/frontend/src/app/atoms/button/confirm.tsx b/twake/frontend/src/app/atoms/button/confirm.tsx new file mode 100644 index 00000000..1cad49ab --- /dev/null +++ b/twake/frontend/src/app/atoms/button/confirm.tsx @@ -0,0 +1,82 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React from 'react'; +import { ExclamationCircleIcon } from '@heroicons/react/outline'; +import _ from 'lodash'; +import { useState } from 'react'; +import { Button } from './button'; +import { Modal, ModalContent } from '../modal'; + +interface ButtonProps extends React.ButtonHTMLAttributes { + theme?: 'primary' | 'secondary' | 'danger' | 'default' | 'outline'; + size?: 'md' | 'lg' | 'sm'; + icon?: (props: any) => JSX.Element; + loading?: boolean; + disabled?: boolean; + confirmTitle?: string; + confirmMessage?: string; + confirmIcon?: React.ReactNode; + confirmButtonTheme?: 'primary' | 'secondary' | 'danger' | 'default'; + confirmButtonText?: string; + cancelButtonText?: string; + children?: React.ReactNode; +} + +export const ButtonConfirm = (props: ButtonProps) => { + const [inConfirm, setInConfirm] = useState(false); + return ( + <> + + + + } + /> + + + ); +}; diff --git a/twake/frontend/src/app/atoms/colors/index.stories.tsx b/twake/frontend/src/app/atoms/colors/index.stories.tsx new file mode 100644 index 00000000..dc5ac058 --- /dev/null +++ b/twake/frontend/src/app/atoms/colors/index.stories.tsx @@ -0,0 +1,52 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React from 'react'; +import { ComponentStory } from '@storybook/react'; + +export default { + title: '@atoms/colors', +}; + +const Template: ComponentStory = () => { + return ( + <> +
+ {['zink', 'red', 'orange', 'green', 'blue'].map(color => ( +
+
+
+
+
+ {color} +
+
+
+
+ {[50, 100, 200, 300, 400, 500, 600, 700, 800, 900].map(shade => ( +
+
+
+
+ {shade} +
+
+ #... +
+
+
+ ))} +
+
+
+ ))} +
+ + ); +}; + +export const Default = Template.bind({}); +Default.args = {}; diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/check-outline.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/check-outline.svg new file mode 100644 index 00000000..347bf63f --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/check-outline.svg @@ -0,0 +1,3 @@ + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/check.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/check.svg new file mode 100644 index 00000000..bd25dd19 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/check.svg @@ -0,0 +1,3 @@ + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/copy.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/copy.svg new file mode 100644 index 00000000..29ca723b --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/copy.svg @@ -0,0 +1,3 @@ + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/delete.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/delete.svg new file mode 100644 index 00000000..a508bd50 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/delete.svg @@ -0,0 +1,3 @@ + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/download.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/download.svg new file mode 100644 index 00000000..452d1edc --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/download.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/eye.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/eye.svg new file mode 100644 index 00000000..c19b8afc --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/eye.svg @@ -0,0 +1,3 @@ + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/input-clear.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/input-clear.svg new file mode 100644 index 00000000..95b3dd51 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/input-clear.svg @@ -0,0 +1,3 @@ + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/plus.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/plus.svg new file mode 100644 index 00000000..d0c661be --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/rotate-cw.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/rotate-cw.svg new file mode 100644 index 00000000..923d226c --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/rotate-cw.svg @@ -0,0 +1,4 @@ + + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/share.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/share.svg new file mode 100644 index 00000000..1de8c4a9 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/share.svg @@ -0,0 +1,3 @@ + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/status-check-double.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/status-check-double.svg new file mode 100644 index 00000000..06adcf30 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/status-check-double.svg @@ -0,0 +1,4 @@ + + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/status-check.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/status-check.svg new file mode 100644 index 00000000..34dc0e5e --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/status-check.svg @@ -0,0 +1,3 @@ + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/up.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/up.svg new file mode 100644 index 00000000..205b0645 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/up.svg @@ -0,0 +1,3 @@ + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/upload.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/upload.svg new file mode 100644 index 00000000..be06382d --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/upload.svg @@ -0,0 +1,3 @@ + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/user-add.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/user-add.svg new file mode 100644 index 00000000..49305f33 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/user-add.svg @@ -0,0 +1,3 @@ + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/users.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/users.svg new file mode 100644 index 00000000..eb588880 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/users.svg @@ -0,0 +1,3 @@ + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/vertical-dots.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/vertical-dots.svg new file mode 100644 index 00000000..3cd84b75 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/vertical-dots.svg @@ -0,0 +1,3 @@ + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/x.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/x.svg new file mode 100644 index 00000000..6eaebcca --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/x.svg @@ -0,0 +1,3 @@ + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/zoom-in.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/zoom-in.svg new file mode 100644 index 00000000..3a6104da --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/zoom-in.svg @@ -0,0 +1,4 @@ + + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/assets/zoom-out.svg b/twake/frontend/src/app/atoms/icons-agnostic/assets/zoom-out.svg new file mode 100644 index 00000000..96b455f9 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/assets/zoom-out.svg @@ -0,0 +1,4 @@ + + + + diff --git a/twake/frontend/src/app/atoms/icons-agnostic/icons-agnostic.stories.tsx b/twake/frontend/src/app/atoms/icons-agnostic/icons-agnostic.stories.tsx new file mode 100644 index 00000000..40644a80 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/icons-agnostic.stories.tsx @@ -0,0 +1,79 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React, { cloneElement } from 'react'; +import { ComponentStory } from '@storybook/react'; +import { + CopyIcon, + DeleteIcon, + DownloadIcon, + EyeIcon, + InputClearIcon, + ShareIcon, + UserAddIcon, + CheckIcon, + ZoomInIcon, + ZoomOutIcon, + VerticalDotsIcon, + RotateCwIcon, + UploadCwIcon, + PlusIcon, + UpIcon, + XIcon, + StatusCheckDoubleIcon, + StatusCheckIcon, + UsersIcon, + CheckOutlineIcon, +} from '@atoms/icons-agnostic/index'; + +export default { + title: '@atoms/icons-agnostic', +}; + +type PropsType = { + icon: JSX.Element; + title: string; +}; + +const Icon = ({ icon, title }: PropsType): JSX.Element => { + const comp = cloneElement(icon, { className: 'w-8 h-8' }); + + return ( +
+ {comp} +
{title}
+
+ ); +}; + +// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args +const Template: ComponentStory = () => { + return ( + <> +
+ } title="Copy" /> + } title="Delete" /> + } title="Download" /> + } title="Eye" /> + } title="Share" /> + } title="InputClear" /> + } title="User" /> + } title="Check" /> + } title="CheckOutline" /> + } title="ZoomIn" /> + } title="ZoomOut" /> + } title="VerticalDots" /> + } title="RotateCw" /> + } title="Upload" /> + } title="Plus" /> + } title="Up" /> + } title="X" /> + } title="StatusCheckDouble" /> + } title="StatusCheck" /> + } title="Users" /> +
+ + ); +}; + +export const Default = Template.bind({}); +// More on args: https://storybook.js.org/docs/react/writing-stories/args +Default.args = {}; diff --git a/twake/frontend/src/app/atoms/icons-agnostic/index.tsx b/twake/frontend/src/app/atoms/icons-agnostic/index.tsx new file mode 100644 index 00000000..8145185f --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-agnostic/index.tsx @@ -0,0 +1,45 @@ +import React, { ComponentProps } from 'react'; + +import { ReactComponent as CopySvg } from './assets/copy.svg'; +import { ReactComponent as DeleteSvg } from './assets/delete.svg'; +import { ReactComponent as DownloadSvg } from './assets/download.svg'; +import { ReactComponent as UploadSvg } from './assets/upload.svg'; +import { ReactComponent as InputClearSvg } from './assets/input-clear.svg'; +import { ReactComponent as ShareSvg } from './assets/share.svg'; +import { ReactComponent as EyeSvg } from './assets/eye.svg'; +import { ReactComponent as UserAddSvg } from './assets/user-add.svg'; +import { ReactComponent as CheckSvg } from './assets/check.svg'; +import { ReactComponent as CheckOutlineSvg } from './assets/check-outline.svg'; +import { ReactComponent as ZommInSvg } from './assets/zoom-in.svg'; +import { ReactComponent as ZoomOutSvg } from './assets/zoom-out.svg'; +import { ReactComponent as VerticalDotsSvg } from './assets/vertical-dots.svg'; +import { ReactComponent as RotateCwSvg } from './assets/rotate-cw.svg'; +import { ReactComponent as Plus } from './assets/plus.svg'; +import { ReactComponent as Up } from './assets/up.svg'; +import { ReactComponent as X } from './assets/x.svg'; +import { ReactComponent as StatusCheckDouble } from './assets/status-check-double.svg'; +import { ReactComponent as StatusCheck } from './assets/status-check.svg'; +import { ReactComponent as Users } from './assets/users.svg'; + +export const CopyIcon = (props: ComponentProps<'svg'>) => ; +export const DeleteIcon = (props: ComponentProps<'svg'>) => ; +export const DownloadIcon = (props: ComponentProps<'svg'>) => ; +export const EyeIcon = (props: ComponentProps<'svg'>) => ; +export const InputClearIcon = (props: ComponentProps<'svg'>) => ; +export const ShareIcon = (props: ComponentProps<'svg'>) => ; +export const UserAddIcon = (props: ComponentProps<'svg'>) => ; +export const CheckIcon = (props: ComponentProps<'svg'>) => ; +export const CheckOutlineIcon = (props: ComponentProps<'svg'>) => ; +export const ZoomInIcon = (props: ComponentProps<'svg'>) => ; +export const ZoomOutIcon = (props: ComponentProps<'svg'>) => ; +export const VerticalDotsIcon = (props: ComponentProps<'svg'>) => ; +export const RotateCwIcon = (props: ComponentProps<'svg'>) => ; +export const UploadCwIcon = (props: ComponentProps<'svg'>) => ; +export const PlusIcon = (props: ComponentProps<'svg'>) => ; +export const UpIcon = (props: ComponentProps<'svg'>) => ; +export const XIcon = (props: ComponentProps<'svg'>) => ; +export const StatusCheckDoubleIcon = (props: ComponentProps<'svg'>) => ( + +); +export const StatusCheckIcon = (props: ComponentProps<'svg'>) => ; +export const UsersIcon = (props: ComponentProps<'svg'>) => ; diff --git a/twake/frontend/src/app/atoms/icons-colored/assets/dismiss.svg b/twake/frontend/src/app/atoms/icons-colored/assets/dismiss.svg new file mode 100644 index 00000000..c68dff3a --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-colored/assets/dismiss.svg @@ -0,0 +1,4 @@ + + + + diff --git a/twake/frontend/src/app/atoms/icons-colored/assets/file-type-archive.svg b/twake/frontend/src/app/atoms/icons-colored/assets/file-type-archive.svg new file mode 100644 index 00000000..c5222d38 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-colored/assets/file-type-archive.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/twake/frontend/src/app/atoms/icons-colored/assets/file-type-document.svg b/twake/frontend/src/app/atoms/icons-colored/assets/file-type-document.svg new file mode 100644 index 00000000..a6c3a23b --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-colored/assets/file-type-document.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/twake/frontend/src/app/atoms/icons-colored/assets/file-type-media.svg b/twake/frontend/src/app/atoms/icons-colored/assets/file-type-media.svg new file mode 100644 index 00000000..379d5eb2 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-colored/assets/file-type-media.svg @@ -0,0 +1,4 @@ + + + + diff --git a/twake/frontend/src/app/atoms/icons-colored/assets/file-type-pdf.svg b/twake/frontend/src/app/atoms/icons-colored/assets/file-type-pdf.svg new file mode 100644 index 00000000..e1a2c0ef --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-colored/assets/file-type-pdf.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/twake/frontend/src/app/atoms/icons-colored/assets/file-type-slides.svg b/twake/frontend/src/app/atoms/icons-colored/assets/file-type-slides.svg new file mode 100644 index 00000000..82643018 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-colored/assets/file-type-slides.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/twake/frontend/src/app/atoms/icons-colored/assets/file-type-spreadsheet.svg b/twake/frontend/src/app/atoms/icons-colored/assets/file-type-spreadsheet.svg new file mode 100644 index 00000000..152ee1f0 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-colored/assets/file-type-spreadsheet.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/twake/frontend/src/app/atoms/icons-colored/assets/file-type-unknown.svg b/twake/frontend/src/app/atoms/icons-colored/assets/file-type-unknown.svg new file mode 100644 index 00000000..7dfc969c --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-colored/assets/file-type-unknown.svg @@ -0,0 +1,4 @@ + + + + diff --git a/twake/frontend/src/app/atoms/icons-colored/assets/not-found.svg b/twake/frontend/src/app/atoms/icons-colored/assets/not-found.svg new file mode 100644 index 00000000..e22a154b --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-colored/assets/not-found.svg @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/twake/frontend/src/app/atoms/icons-colored/assets/remove.svg b/twake/frontend/src/app/atoms/icons-colored/assets/remove.svg new file mode 100644 index 00000000..76b4e679 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-colored/assets/remove.svg @@ -0,0 +1,3 @@ + + + diff --git a/twake/frontend/src/app/atoms/icons-colored/assets/sent.svg b/twake/frontend/src/app/atoms/icons-colored/assets/sent.svg new file mode 100644 index 00000000..23af0eb3 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-colored/assets/sent.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/twake/frontend/src/app/atoms/icons-colored/icons-colored.stories.tsx b/twake/frontend/src/app/atoms/icons-colored/icons-colored.stories.tsx new file mode 100644 index 00000000..bad7ed8b --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-colored/icons-colored.stories.tsx @@ -0,0 +1,68 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React, { cloneElement } from 'react'; +import { ComponentStory } from '@storybook/react'; +import { + DismissIcon, + FileTypeArchiveIcon, + FileTypeDocumentIcon, + FileTypePdfIcon, + FileTypeSpreadsheetIcon, + FileTypeUnknownIcon, + FileTypeMediaIcon, + FileTypeSlidesIcon, + NotFoundIcon, + RemoveIcon, + SentIcon, +} from '@atoms/icons-colored/index'; + +export default { + title: '@atoms/icons-colored', +}; + +type PropsType = { + icon: JSX.Element; + title: string; +}; + +const Icon = ({ icon, title }: PropsType): JSX.Element => { + const comp = cloneElement(icon, { className: 'w-8 h-8' }); + + return ( +
+ {comp} +
{title}
+
+ ); +}; + +// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args +const Template: ComponentStory = () => { + return ( + <> +

General

+
+ } title="Dismiss" /> +
+

FileTypes

+
+ } title="FileTypeArchive" /> + } title="FileTypePdf" /> + } title="FileTypeDocument" /> + } title="FileTypeSpreadsheet" /> + } title="FileTypeUnknown" /> + } title="FileTypeMedia" /> + } title="FileTypeSlides" /> +
+

Component specific

+
+ } title="NotFound" /> + } title="Remove" /> + } title="Remove" /> +
+ + ); +}; + +export const Default = Template.bind({}); +// More on args: https://storybook.js.org/docs/react/writing-stories/args +Default.args = {}; diff --git a/twake/frontend/src/app/atoms/icons-colored/index.tsx b/twake/frontend/src/app/atoms/icons-colored/index.tsx new file mode 100644 index 00000000..f20d2311 --- /dev/null +++ b/twake/frontend/src/app/atoms/icons-colored/index.tsx @@ -0,0 +1,39 @@ +import React, { ComponentProps } from 'react'; + +import { ReactComponent as DismissSvg } from './assets/dismiss.svg'; +import { ReactComponent as NotFoundSvg } from './assets/not-found.svg'; +import { ReactComponent as FileTypeArchiveSvg } from './assets/file-type-archive.svg'; +import { ReactComponent as FileTypeDocumentSvg } from './assets/file-type-document.svg'; +import { ReactComponent as FileTypePdfSvg } from './assets/file-type-pdf.svg'; +import { ReactComponent as FileTypeSpreadsheetSvg } from './assets/file-type-spreadsheet.svg'; +import { ReactComponent as FileTypeUnknownSvg } from './assets/file-type-unknown.svg'; +import { ReactComponent as FileTypeMediaSvg } from './assets/file-type-media.svg'; +import { ReactComponent as FileTypeSlidesSvg } from './assets/file-type-slides.svg'; +import { ReactComponent as RemoveSvg } from './assets/remove.svg'; +import { ReactComponent as SentSvg } from './assets/sent.svg'; + +export const DismissIcon = (props: ComponentProps<'svg'>) => ; +export const NotFoundIcon = (props: ComponentProps<'svg'>) => ; +export const FileTypeArchiveIcon = (props: ComponentProps<'svg'>) => ( + +); +export const FileTypePdfIcon = (props: ComponentProps<'svg'>) => ; +export const FileTypeDocumentIcon = (props: ComponentProps<'svg'>) => ( + +); +export const FileTypeSpreadsheetIcon = (props: ComponentProps<'svg'>) => ( + +); +export const FileTypeUnknownIcon = (props: ComponentProps<'svg'>) => ( + +); + +export const FileTypeMediaIcon = (props: ComponentProps<'svg'>) => ; + +export const FileTypeSlidesIcon = (props: ComponentProps<'svg'>) => ( + +); + +export const RemoveIcon = (props: ComponentProps<'svg'>) => ; + +export const SentIcon = (props: ComponentProps<'svg'>) => ; diff --git a/twake/frontend/src/app/atoms/input/input-checkbox.tsx b/twake/frontend/src/app/atoms/input/input-checkbox.tsx new file mode 100644 index 00000000..b5103135 --- /dev/null +++ b/twake/frontend/src/app/atoms/input/input-checkbox.tsx @@ -0,0 +1,54 @@ +import { CheckOutlineIcon } from '../icons-agnostic'; +import { BaseSmall } from '../text'; + +export const Checkbox = (props: { + label?: string; + onChange?: (status: boolean) => void; + value?: boolean; + className?: string; + disabled?: boolean; +}) => { + const renderSwitch = () => { + const className = props.className || ''; + + return ( +
+ !props.label && !props.disabled && props.onChange && props.onChange(!props.value) + } + > + {props.value && } +
+ ); + }; + + if (props.label) { + return ( +
{ + if (!props.disabled) { + props.onChange && props.onChange(!props.value); + } + }} + > + {renderSwitch()} + + {props.label} + +
+ ); + } else { + return renderSwitch(); + } +}; diff --git a/twake/frontend/src/app/atoms/input/input-decoration-icon.tsx b/twake/frontend/src/app/atoms/input/input-decoration-icon.tsx new file mode 100644 index 00000000..349ea14b --- /dev/null +++ b/twake/frontend/src/app/atoms/input/input-decoration-icon.tsx @@ -0,0 +1,23 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { ReactNode } from 'react'; + +interface InputLabelProps { + prefix?: (props: any) => JSX.Element; + suffix?: (props: any) => JSX.Element; + input: ({ className }: { className: string }) => ReactNode; + className?: string; +} + +export const InputDecorationIcon = (props: InputLabelProps) => { + return ( +
+ {props.prefix && ( + + )} + {props.input({ className: (props.prefix ? 'pl-9 ' : '') + (props.suffix ? 'pr-9 ' : '') })} + {props.suffix && ( + + )} +
+ ); +}; diff --git a/twake/frontend/src/app/atoms/input/input-decoration-label.tsx b/twake/frontend/src/app/atoms/input/input-decoration-label.tsx new file mode 100644 index 00000000..8af12ffc --- /dev/null +++ b/twake/frontend/src/app/atoms/input/input-decoration-label.tsx @@ -0,0 +1,27 @@ +import { Info } from '../text'; + +interface InputLabelProps { + label?: string; + feedback?: string; + hasError?: boolean; + input?: React.ReactNode; + className?: string; +} + +export const InputLabel = (props: InputLabelProps) => { + return ( + <> + {props.label && ( +
+ +
{props.input}
+ {props.feedback && ( + + {props.feedback} + + )} +
+ )} + + ); +}; diff --git a/twake/frontend/src/app/atoms/input/input-select.tsx b/twake/frontend/src/app/atoms/input/input-select.tsx new file mode 100644 index 00000000..971e90c2 --- /dev/null +++ b/twake/frontend/src/app/atoms/input/input-select.tsx @@ -0,0 +1,32 @@ +import _ from 'lodash'; +import { defaultInputClassName, errorInputClassName } from './input-text'; + +interface InputProps extends Omit, 'size'> { + theme?: 'plain' | 'outline'; + hasError?: boolean; + size?: 'md' | 'lg' | 'sm'; + className?: string; + children?: React.ReactNode; +} + +export function Select(props: InputProps) { + let inputClassName = props.hasError + ? errorInputClassName(props.theme) + : defaultInputClassName(props.theme); + inputClassName = inputClassName + (props.disabled ? ' opacity-75' : ''); + + if (props.size === 'lg') inputClassName = inputClassName + ' text-lg h-11'; + else if (props.size === 'sm') inputClassName = inputClassName + ' text-sm h-7 py-0 px-3'; + else inputClassName = inputClassName + ' text-base h-9 py-1'; + + return ( + + ); +} + +export default Select; diff --git a/twake/frontend/src/app/atoms/input/input-text.tsx b/twake/frontend/src/app/atoms/input/input-text.tsx new file mode 100644 index 00000000..5b35e1a6 --- /dev/null +++ b/twake/frontend/src/app/atoms/input/input-text.tsx @@ -0,0 +1,76 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import _ from 'lodash'; +import React from 'react'; + +interface InputProps + extends Omit< + React.InputHTMLAttributes & React.TextareaHTMLAttributes, + 'size' + > { + theme?: 'plain' | 'outline'; + label?: string; + size?: 'sm' | 'md' | 'lg'; + feedback?: string; + hasError?: boolean; + multiline?: boolean; + inputComponent?: React.ReactNode; + inputClassName?: string; + className?: string; + inputRef?: React.Ref; +} + +const baseInputClassName = + 'tw-input block w-full rounded-md focus:ring-1 focus:ring-blue-500 z-0 focus:z-10 dark:text-white text-black '; + +export const defaultInputClassName = (theme: 'plain' | 'outline' = 'plain') => { + return ( + baseInputClassName + + (theme === 'plain' + ? 'bg-zinc-200 border-zinc-200 dark:bg-zinc-800 dark:border-zinc-800' + : 'bg-zinc-50 border-zinc-300 dark:bg-zinc-800 dark:border-zinc-700') + ); +}; + +export const errorInputClassName = (theme: 'plain' | 'outline' = 'plain') => { + return ( + baseInputClassName + + (theme === 'plain' + ? 'bg-red-200 border-red-200 dark:bg-red-800 dark:border-red-800' + : 'bg-red-50 border-red-300 dark:bg-red-900 dark:border-red-800') + ); +}; + +export const Input = (props: InputProps) => { + let inputClassName = props.hasError + ? errorInputClassName(props.theme) + : defaultInputClassName(props.theme); + inputClassName = inputClassName + (props.disabled ? ' opacity-75' : ''); + + if (!props.multiline) { + if (props.size === 'lg') inputClassName = inputClassName + ' h-11'; + else if (props.size === 'sm') inputClassName = inputClassName + ' h-7'; + else inputClassName = inputClassName + ' h-9'; + } + + return ( + <> + {props.inputComponent || + (props.multiline ? ( + + ) : ( + } + type="text" + className={inputClassName + ' ' + props.inputClassName + ' ' + props.className} + {..._.omit(props, 'label', 'inputClassName', 'className', 'size')} + /> + ))} + + ); +}; diff --git a/twake/frontend/src/app/atoms/input/stories/checkbox.stories.tsx b/twake/frontend/src/app/atoms/input/stories/checkbox.stories.tsx new file mode 100644 index 00000000..36f624dc --- /dev/null +++ b/twake/frontend/src/app/atoms/input/stories/checkbox.stories.tsx @@ -0,0 +1,41 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { ComponentStory } from '@storybook/react'; +import { useState } from 'react'; +import { Checkbox } from '../input-checkbox'; + +export default { + title: '@atoms/checkbox', +}; + +const Template: ComponentStory = (props: { label: string; disabled: boolean }) => { + const [checked, setChecked] = useState(false); + + return ( +
+ { + setChecked(e); + }} + value={checked} + disabled={props.disabled} + /> + +
+ + { + setChecked(e); + }} + value={checked} + disabled={props.disabled} + label={props.label} + /> +
+ ); +}; + +export const Default = Template.bind({}); +Default.args = { + label: 'Checkbox label', + disabled: false, +}; diff --git a/twake/frontend/src/app/atoms/input/stories/input-groups.stories.tsx b/twake/frontend/src/app/atoms/input/stories/input-groups.stories.tsx new file mode 100644 index 00000000..d16e4a20 --- /dev/null +++ b/twake/frontend/src/app/atoms/input/stories/input-groups.stories.tsx @@ -0,0 +1,107 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { ComponentStory } from '@storybook/react'; +import { SearchIcon } from '@heroicons/react/solid'; +import { Title } from '@atoms/text'; +import { Input } from '../input-text'; +import { FilterIcon, CogIcon } from '@heroicons/react/outline'; +import Select from '../input-select'; +import { InputDecorationIcon } from '../input-decoration-icon'; + +export default { + title: '@atoms/input-groups', +}; + +const Template: ComponentStory = () => { + return ( + <> + Icons +
+ + } + /> +
+ + } + /> +
+ + } + /> +
+ + ( + + )} + /> +
+ + ( + + )} + /> + +
+
+ Groups +
+ +
+ + +
+ +
+
+ Mixed +
+ +
+ ( + + )} + /> + ( + + )} + /> +
+ + ); +}; + +export const Default = Template.bind({}); +Default.args = { + text: 'Text', + disabled: false, +}; diff --git a/twake/frontend/src/app/atoms/input/stories/input.stories.tsx b/twake/frontend/src/app/atoms/input/stories/input.stories.tsx new file mode 100644 index 00000000..309c835c --- /dev/null +++ b/twake/frontend/src/app/atoms/input/stories/input.stories.tsx @@ -0,0 +1,73 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { ComponentStory } from '@storybook/react'; +import { Input } from '../input-text'; +import { Title } from '../../text'; +import { InputLabel } from '../input-decoration-label'; + +export default { + title: '@atoms/input', +}; + +const Template: ComponentStory = (props: { + text: string; + disabled: boolean; + loading: boolean; +}) => { + return ( +
+ Sizes and themes plain / outline +
+ + +
+ +
+ +
+ + +
+ +
+ +
+ Labels and errors +
+ + +
+ + } + /> +
+ + } + /> +
+ ); +}; + +export const Default = Template.bind({}); +Default.args = { + text: 'Text', + disabled: false, +}; diff --git a/twake/frontend/src/app/atoms/input/stories/select.stories.tsx b/twake/frontend/src/app/atoms/input/stories/select.stories.tsx new file mode 100644 index 00000000..885b2810 --- /dev/null +++ b/twake/frontend/src/app/atoms/input/stories/select.stories.tsx @@ -0,0 +1,58 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { ComponentStory } from '@storybook/react'; +import { Title } from '@atoms/text'; +import { InputLabel } from '../input-decoration-label'; +import Select from '../input-select'; + +export default { + title: '@atoms/select', +}; + +const Template: ComponentStory = (props: { + text: string; + disabled: boolean; + loading: boolean; +}) => { + return ( +
+ Sizes and with error +
+ + +
+ +
+ +
+ + Labels +
+ + + + + + } + /> +
+ ); +}; + +export const Default = Template.bind({}); +Default.args = { + disabled: false, +}; diff --git a/twake/frontend/src/app/atoms/layout/single-center-card.tsx b/twake/frontend/src/app/atoms/layout/single-center-card.tsx new file mode 100644 index 00000000..47299be5 --- /dev/null +++ b/twake/frontend/src/app/atoms/layout/single-center-card.tsx @@ -0,0 +1,48 @@ +export default function SingleCenterCard(props: { + logo?: boolean; + insetLogo?: boolean; + title?: string | React.ReactNode; + subtitle?: string | React.ReactNode; + children: React.ReactNode; +}) { + return ( +
+ {(!!props.logo || !!props.title || !!props.subtitle) && ( +
+ Workflow + {!!props.title && ( +

+ {props.title} +

+ )} + {!!props.subtitle && ( +

+ {props.subtitle} +

+ )} +
+ )} + +
+
+ {props.insetLogo && ( + Workflow + )} + + {props.children} +
+
+
+ ); +} diff --git a/twake/frontend/src/app/atoms/link/index.tsx b/twake/frontend/src/app/atoms/link/index.tsx new file mode 100644 index 00000000..d5aac855 --- /dev/null +++ b/twake/frontend/src/app/atoms/link/index.tsx @@ -0,0 +1,36 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import _ from 'lodash'; +import { Link } from 'react-router-dom'; + +export default function A( + props: any & { + to?: string; + href?: string; + children: React.ReactNode; + noColor?: boolean; + }, +) { + const colors = props.noColor ? '' : 'hover:text-blue-700 active:text-blue-800 text-blue-500'; + + if (props.to) { + return ( + + {props.children} + + ); + } + + return ( +
+ {props.children} + + ); +} diff --git a/twake/frontend/src/app/atoms/link/link.stories.tsx b/twake/frontend/src/app/atoms/link/link.stories.tsx new file mode 100644 index 00000000..f5e1d151 --- /dev/null +++ b/twake/frontend/src/app/atoms/link/link.stories.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { MemoryRouter } from 'react-router-dom'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import A from './index'; + +export default { + title: '@atoms/link', + component: A, + decorators: [(Story) => ()] +} as ComponentMeta; + +const Template: ComponentStory = args => ; + +export const Default = Template.bind({}); +Default.args = { + href: 'https://www.google.com', + children: 'Link', +} + +export const noColor = Template.bind({}); +noColor.args = { + href: 'https://www.google.com', + children: 'Link', + noColor: true, +}; + +export const internal = Template.bind({}); +internal.args = { + to: '/', + children: 'Link', +}; diff --git a/twake/frontend/src/app/atoms/loader/index.tsx b/twake/frontend/src/app/atoms/loader/index.tsx new file mode 100644 index 00000000..a2692306 --- /dev/null +++ b/twake/frontend/src/app/atoms/loader/index.tsx @@ -0,0 +1,24 @@ +export const Loader = (props: { className?: string }) => { + return ( + + + + + ); +}; diff --git a/twake/frontend/src/app/atoms/logo/index.tsx b/twake/frontend/src/app/atoms/logo/index.tsx new file mode 100644 index 00000000..cc1086f8 --- /dev/null +++ b/twake/frontend/src/app/atoms/logo/index.tsx @@ -0,0 +1,23 @@ +import _ from 'lodash'; +import React from 'react'; + +interface PropsType extends Omit, 'size'> { + size?: 16 | 32 | 64 | 128 | 256; +} + +export const Logo = (props: PropsType): React.ReactElement => { + const { size = 128 } = props; + + return ( +
+ Twake logo +
+ ); +}; diff --git a/twake/frontend/src/app/atoms/logo/logo.stories.tsx b/twake/frontend/src/app/atoms/logo/logo.stories.tsx new file mode 100644 index 00000000..83ad70b9 --- /dev/null +++ b/twake/frontend/src/app/atoms/logo/logo.stories.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { Logo } from '.'; + +export default { + title: '@atoms/logo', + component: Logo, +} as ComponentMeta; + +const Template: ComponentStory = args => ; + +export const Default = Template.bind({}); +Default.args = {}; + +export const extraSmall = Template.bind({}); +extraSmall.args = { + size: 16, +}; + +export const small = Template.bind({}); +small.args = { + size: 32, +}; + +export const mediumSmall = Template.bind({}); +mediumSmall.args = { + size: 64, +}; + +export const medium = Template.bind({}); +medium.args = { + size: 128, +}; + +export const large = Template.bind({}); +large.args = { + size: 256, +}; diff --git a/twake/frontend/src/app/atoms/modal/index.stories.tsx b/twake/frontend/src/app/atoms/modal/index.stories.tsx new file mode 100644 index 00000000..034d3fb9 --- /dev/null +++ b/twake/frontend/src/app/atoms/modal/index.stories.tsx @@ -0,0 +1,93 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React, { useState } from 'react'; +import { RecoilRoot } from 'recoil'; +import { ComponentStory } from '@storybook/react'; +import { Modal, ModalContent } from '.'; +import { Button } from '../button/button'; +import { ButtonConfirm } from '../button/confirm'; +import { CheckCircleIcon, ExclamationCircleIcon } from '@heroicons/react/outline'; +import { Title } from '../text'; + +export default { + title: '@atoms/modal', +}; + +const Template: ComponentStory = () => { + const [openA, setOpenA] = useState(false); + const [openB, setOpenB] = useState(false); + + return ( + + setOpenB(false)}> + Title + Hello this is the modal B
+ No more popup now +
+ setOpenA(false)}> + Title + Hello this is the modal A
+ setOpenB(true)}>Open B +
+ +
+ ); +}; + +export const Default = Template.bind({}); +Default.args = {}; + +const TemplateWithContent: ComponentStory = () => { + const [openA, setOpenA] = useState(false); + const [openB, setOpenB] = useState(false); + + return ( + + setOpenB(false)}> + + + + + } + /> + + setOpenA(false)}> + + setOpenB(true)}>Open modal B + + } + /> + + + + ); +}; + +export const WithModalContent = TemplateWithContent.bind({}); +WithModalContent.args = {}; diff --git a/twake/frontend/src/app/atoms/modal/index.tsx b/twake/frontend/src/app/atoms/modal/index.tsx new file mode 100644 index 00000000..c8570d07 --- /dev/null +++ b/twake/frontend/src/app/atoms/modal/index.tsx @@ -0,0 +1,197 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { Dialog, Transition } from '@headlessui/react'; +import { Fragment, ReactNode, useCallback, useEffect, useState } from 'react'; +import { atom, useRecoilState } from 'recoil'; +import { DismissIcon } from '../icons-colored'; +import { Title } from '../text'; + +const ModalsCountState = atom({ + key: 'ModalsState', + default: 0, +}); + +let visibleModals = 0; + +export const Modal = (props: { + open?: boolean; + onClose?: () => void; + children?: React.ReactNode; + closable?: boolean; + className?: string; + style?: React.CSSProperties; + positioned?: boolean; +}) => { + const [open, setOpen] = useState(false); + const [, setModalsCountState] = useRecoilState(ModalsCountState); + const [level, setLevel] = useState(0); + const [didOpenOnce, setDidOpenOnce] = useState(false); + + const onClose = useCallback(() => { + visibleModals += -1; + setModalsCountState(visibleModals); + }, [setModalsCountState]); + + const onOpen = useCallback(() => { + visibleModals += 1; + setLevel(visibleModals); + setModalsCountState(visibleModals); + }, [setModalsCountState]); + + useEffect(() => { + if (props.open !== open) { + setOpen(props.open || false); + if (props.open) { + onOpen(); + } else { + onClose(); + } + } + if (!didOpenOnce && props.open) setDidOpenOnce(true); + }, [props.open]); + + useEffect(() => { + return () => { + if (open) onClose(); + }; + }, []); + + const zIndex = 'z-' + level + '0'; + + return ( + + props.onClose && props.closable && props.onClose()} + > + +
+ + +
+
+ { + /* This element is to trick the browser into centering the modal contents. */ + !props.positioned && ( + + ) + } + + + {props.closable !== false && ( +
+ +
+ )} + {didOpenOnce && props.children} +
+
+
+
+
+
+ ); +}; + +export const ModalContent = (props: { + title: ReactNode | string; + text?: string; + textCenter?: boolean; + buttons?: ReactNode; + children?: ReactNode; + icon?: any; + theme?: 'success' | 'danger' | 'warning' | 'gray'; +}) => { + let color = 'blue'; + if (props.theme === 'success') color = 'green'; + if (props.theme === 'danger') color = 'red'; + if (props.theme === 'warning') color = 'orange'; + if (props.theme === 'gray') color = 'gray'; + return ( + <> +
+ {props.icon && ( +
+
+ )} +
+ {props.title} +
+

{props.text || ''}

+
+
+
+ {props.buttons && ( +
+ {props.buttons} +
+ )} + {props.children} + + ); +}; diff --git a/twake/frontend/src/app/atoms/text/index.stories.tsx b/twake/frontend/src/app/atoms/text/index.stories.tsx new file mode 100644 index 00000000..3303591b --- /dev/null +++ b/twake/frontend/src/app/atoms/text/index.stories.tsx @@ -0,0 +1,32 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React from 'react'; +import { ComponentStory } from '@storybook/react'; + +import * as Text from '.'; + +export default { + title: '@atoms/text', +}; + +// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args +const Template: ComponentStory = (props: { text: string }) => ( + <> + {props.text || 'Title'} +
+ {props.text || 'Subtitle'} +
+ {props.text || 'Base'} +
+ {props.text || 'BaseSmall'} +
+ {props.text || 'Info'} +
+ {props.text || 'InfoSmall'} +
+ +); + +export const Default = Template.bind({}); +Default.args = { + text: '', +}; diff --git a/twake/frontend/src/app/atoms/text/index.tsx b/twake/frontend/src/app/atoms/text/index.tsx new file mode 100644 index 00000000..6f71c559 --- /dev/null +++ b/twake/frontend/src/app/atoms/text/index.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import _ from 'lodash'; +import { ReactNode } from 'react'; + +type TextProps = { + type: 'title' | 'subtitle' | 'base' | 'base-small' | 'info' | 'info-small'; + children: ReactNode | ReactNode[]; + className?: string; + noColor?: boolean; +} & Omit< + React.ButtonHTMLAttributes, + 'children' | 'className' | 'type' | 'noColor' +>; + +type TypedTextProps = Omit; + +export const Title = (props: TypedTextProps) => Text({ type: 'title', ...props }); + +export const Subtitle = (props: TypedTextProps) => Text({ type: 'subtitle', ...props }); + +export const Base = (props: TypedTextProps) => Text({ type: 'base', ...props }); + +export const BaseSmall = (props: TypedTextProps) => Text({ type: 'base-small', ...props }); + +export const Info = (props: TypedTextProps) => Text({ type: 'info', ...props }); + +export const InfoSmall = (props: TypedTextProps) => Text({ type: 'info-small', ...props }); + +const Text = (props: TextProps) => { + let defaultClassName = ''; + + switch (props.type) { + case 'title': + defaultClassName = + 'text-lg font-semibold block ' + + ' ' + + (props.noColor ? '' : 'text-zinc-900 dark:text-white'); + break; + case 'subtitle': + defaultClassName = + 'text-base font-semibold' + ' ' + (props.noColor ? '' : 'text-zinc-800 dark:text-white'); + break; + case 'base': + defaultClassName = + 'text-base font-normal' + ' ' + (props.noColor ? '' : 'text-zinc-800 dark:text-white'); + break; + case 'base-small': + defaultClassName = + 'text-sm font-normal' + ' ' + (props.noColor ? '' : 'text-zinc-800 dark:text-white'); + break; + case 'info': + defaultClassName = + 'text-sm font-normal' + + ' ' + + (props.noColor ? '' : 'text-zinc-400 dark:text-white dark:opacity-50'); + break; + case 'info-small': + defaultClassName = + 'text-xs font-normal' + + ' ' + + (props.noColor ? '' : 'text-zinc-400 dark:text-white dark:opacity-50'); + break; + } + + return ( + + {props.children} + + ); +}; + +export default Text; diff --git a/twake/frontend/src/app/components/add-user-button/add-user-button.scss b/twake/frontend/src/app/components/add-user-button/add-user-button.scss new file mode 100644 index 00000000..14137faa --- /dev/null +++ b/twake/frontend/src/app/components/add-user-button/add-user-button.scss @@ -0,0 +1,18 @@ +.addUserButton { + color: var(--primary); + + .icon { + .iconBox { + width: 18px; + height: 18px; + background-color: var(--primary-background); + border-radius: 4px; + padding-left: 2px; + + .icon-unicon { + color: var(--primary) !important; + } + } + color: var(--primary) !important ; + } +} diff --git a/twake/frontend/src/app/components/add-user-button/add-user-button.tsx b/twake/frontend/src/app/components/add-user-button/add-user-button.tsx new file mode 100644 index 00000000..1c097943 --- /dev/null +++ b/twake/frontend/src/app/components/add-user-button/add-user-button.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import Icon from 'app/components/icon/icon.jsx'; +import Languages from 'app/features/global/services/languages-service'; +import './add-user-button.scss'; +import { useRecoilState } from 'recoil'; +import { invitationState } from 'app/features/invitation/state/invitation'; +import { useInvitationUsers } from 'app/features/invitation/hooks/use-invitation-users'; +import AccessRightsService from 'app/features/workspace-members/services/workspace-members-access-rights-service'; +import { useCurrentWorkspace } from 'app/features/workspaces/hooks/use-workspaces'; + +export default () => { + const [, setInvitationOpen] = useRecoilState(invitationState); + const { allowed_guests, allowed_members } = useInvitationUsers(); + const { workspace } = useCurrentWorkspace(); + + return AccessRightsService.hasLevel(workspace?.id, 'moderator') && + (allowed_guests > 0 || allowed_members > 0) ? ( +
{ + setInvitationOpen(true); + }} + > +
+
+ +
+
+
+ {Languages.t( + 'scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button', + [], + 'Ajouter des collaborateurs', + )} +
+
+ ) : ( + <> + ); +}; diff --git a/twake/frontend/src/app/components/attachment-picker/attachment-picker.jsx b/twake/frontend/src/app/components/attachment-picker/attachment-picker.jsx new file mode 100755 index 00000000..c8e7bf46 --- /dev/null +++ b/twake/frontend/src/app/components/attachment-picker/attachment-picker.jsx @@ -0,0 +1,199 @@ +/* eslint-disable react/prop-types */ +import React, { Component } from 'react'; + +import File from 'components/drive/file'; +import FilePicker from 'components/drive/file-picker/file-picker.jsx'; +import TaskPicker from 'components/task-picker/task-picker.jsx'; +import Menu from 'components/menus/menu.jsx'; +import Icon from 'app/components/icon/icon.jsx'; +import Button from 'components/buttons/button.jsx'; +import UploadZone from 'components/uploads/upload-zone'; +import MenusManager from 'app/components/menus/menus-manager.jsx'; +import Workspaces from 'app/deprecated/workspaces/workspaces.jsx'; +import Languages from 'app/features/global/services/languages-service'; +import './attachment-picker.scss'; + +export default class AttachmentPicker extends Component { + /* + props : { + readOnly : bool + attachments : [] + onChange + className + } + */ + + getIcon(att) { + if (att.type.toLocaleLowerCase() === 'event') { + return 'calendar-alt'; + } + if (att.type.toLocaleLowerCase() === 'file') { + return 'folder'; + } + if (att.type.toLocaleLowerCase() === 'task') { + return 'check-square'; + } + } + addAttachment(attachment) { + var attachments = this.props.attachments || []; + attachments.push(attachment); + if (this.props.onChange) { + this.props.onChange(attachments); + } + } + removeAttachment(attachment) { + var attachments = this.props.attachments || []; + var index = attachments.indexOf(attachment); + if (index >= 0) { + attachments.splice(index, 1); + if (this.props.onChange) { + this.props.onChange(attachments); + } + } + } + render() { + return ( +
+
+ {(Object.values(this.props.attachments || {}) || []).map(att => { + if (att.type === 'file') { + var additionalMenu = []; + if (!this.props.readOnly) { + additionalMenu = [ + { + type: 'menu', + text: Languages.t( + 'components.attachmentpicker.remove_attach', + [], + 'Remove attachment', + ), + onClick: () => { + this.removeAttachment(att); + }, + }, + ]; + } + return ( +
+ +
+ ); + } + return ( +
+ + {att.name} + {!this.props.readOnly && ( + { + this.removeAttachment(att); + }} + /> + )} +
+ ); + })} +
+ {!this.props.readOnly && ( + { + this.upload_zone.open(); + MenusManager.closeMenu(); + }, + }, + { + type: 'menu', + icon: 'folder', + text: Languages.t( + 'components.attachmentpicker.from_twake', + [], + 'From Twake Documents', + ), + submenu: [ + { + type: 'react-element', + reactElement: ( + { + this.addAttachment({ type: 'file', id: res.id, name: res.name }); + MenusManager.closeMenu(); + }} + initialDirectory={{ id: '' }} + /> + ), + }, + ], + }, + ], + }, + { + type: 'menu', + text: Languages.t('scenes.apps.tasks.task', [], 'Task'), + icon: 'check-square', + submenu: [ + { + type: 'react-element', + reactElement: ( + { + this.addAttachment({ type: 'task', id: res.id, name: res.title }); + MenusManager.closeMenu(); + }} + /> + ), + }, + ], + }, + ]} + > + {' '} + + + )} + + (this.upload_zone = node)} + disableClick + parent={''} + driveCollectionKey={'attachment_' + Workspaces.currentWorkspaceId} + uploadOptions={{ workspace_id: Workspaces.currentWorkspaceId, detached: true }} + onUploaded={res => { + this.addAttachment({ type: 'file', id: res.id, name: res.name }); + }} + multiple={false} + /> +
+ ); + } +} diff --git a/twake/frontend/src/app/components/attachment-picker/attachment-picker.scss b/twake/frontend/src/app/components/attachment-picker/attachment-picker.scss new file mode 100755 index 00000000..1641b683 --- /dev/null +++ b/twake/frontend/src/app/components/attachment-picker/attachment-picker.scss @@ -0,0 +1,39 @@ +.attachmentPicker { + .attachment { + display: inline-block; + font-size: 12px; + color: var(--black); + border: solid 1px var(--grey-background); + height: 32px; + box-sizing: border-box; + border-radius: var(--border-radius-large); + padding: 4px; + padding-right: 8px; + line-height: 24px; + margin-right: 8px; + margin-bottom: 8px; + + &.attachment_file { + border: 0; + padding: 0; + height: auto; + } + } + + i.app-icon { + margin-right: 4px; + margin-left: 4px; + font-size: 14px; + position: relative; + top: -1px; + vertical-align: top; + } + + .remove { + opacity: 0.5; + cursor: pointer; + &:hover { + opacity: 1; + } + } +} diff --git a/twake/frontend/src/app/components/auto-complete-extended/auto-complete-extended.tsx b/twake/frontend/src/app/components/auto-complete-extended/auto-complete-extended.tsx new file mode 100644 index 00000000..edf214fa --- /dev/null +++ b/twake/frontend/src/app/components/auto-complete-extended/auto-complete-extended.tsx @@ -0,0 +1,61 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React, { useState, ReactElement } from 'react'; +import { AutoComplete } from 'antd'; +import { AutoCompleteProps } from 'antd/lib/auto-complete'; + +const { Option } = AutoComplete; + +export default ( + props: { + maxItems?: number; + render?: (item: any) => ReactElement; + onSearch?: (query: string, callback: (res: string[]) => void) => void; + onSelect?: (id: string) => void; + align?: 'top' | 'bottom'; + } & Omit, +) => { + const [list, setList] = useState([]); + const [inputValue, setInputValue] = useState(''); + + const resetInputValue = () => setInputValue(''); + + return ( + { + props.onSearch && + props.onSearch(text, (res: any[]) => { + setList(res); + }); + }} + value={inputValue} + onSelect={(id: string) => { + resetInputValue(); + props.onSelect && props.onSelect(id); + }} + onChange={e => setInputValue(e || '')} + > + {list.slice(0, props.maxItems || 10).map((item: any) => { + return item ? ( + + ) : ( + <> + ); + })} + + ); +}; diff --git a/twake/frontend/src/app/components/auto-complete/auto-complete.scss b/twake/frontend/src/app/components/auto-complete/auto-complete.scss new file mode 100755 index 00000000..ce3760dc --- /dev/null +++ b/twake/frontend/src/app/components/auto-complete/auto-complete.scss @@ -0,0 +1,23 @@ +.autocomplete { + position: relative; + border-radius: 1px solid rgba(0, 0, 0, 0.2); + transition: box-shadow 0.2s; + + .dropmenu { + opacity: 0; + transition: opacity 0.2s; + pointer-events: none; + } + + &.focused { + .dropmenu { + opacity: 1; + pointer-events: all; + } + } + + input, + textarea { + margin: 0px !important; + } +} diff --git a/twake/frontend/src/app/components/auto-complete/auto-complete.tsx b/twake/frontend/src/app/components/auto-complete/auto-complete.tsx new file mode 100644 index 00000000..bcf4129a --- /dev/null +++ b/twake/frontend/src/app/components/auto-complete/auto-complete.tsx @@ -0,0 +1,399 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React, { Component } from 'react'; +import AutoHeight from '../auto-height/auto-height'; +import Input from '../inputs/input'; +import './auto-complete.scss'; + +type State = { + currentList: any[]; + selected: number; + resultPosition: string; + selectedUser: object; + focused: any; +}; + +type Props = { + onResize?: any; + autoHeight?: any; + className?: string; + placeholder?: string; + search: ((text: string, cb: (arr: any) => any) => void)[]; + max: number[]; + onSelect?: (obj: object, other: any) => void; + renderItem: ((obj: object) => any)[]; + renderItemChoosen: ((el: any) => any)[]; + regexHooked: any; + onChange?: any; + value?: any; + onChangeCurrentList?: any; + hideResult?: any; + onBackspace?: any; + disableNavigationKey?: any; + showResultsOnInit?: any; + position?: any; + onHide?: any; + onEscape?: any; + keyUp?: any; + onKeyUp?: any; + onKeyDown?: any; + onKeyPress?: any; + onPaste?: any; + onFocusChange?: any; + big?: boolean; + small?: boolean; + autoFocus?: any; +}; + +export default class AutoComplete extends Component { + currentIdFromList = ''; + is_open = false; + input: any; + container: any; + outsideClickListener: any; + currentRegexUsed: any = -1; + + constructor(props: any) { + super(props); + + this.state = { + currentList: [], + selected: -1, + resultPosition: '', + selectedUser: {}, + focused: '', + }; + + this.keyUp = this.keyUp.bind(this); + this.keyDown = this.keyDown.bind(this); + } + keyDown(ev: any) { + const key = ev.which || window.event; + + if ( + this.is_open && + key && + this.currentRegexUsed >= 0 && + this.state.currentList.length > 0 && + (key === 13 || key === 9 || key === 38 || key === 40) + ) { + ev.preventDefault(); + ev.stopPropagation(); + } + if (key === 27 && !this.is_open && this.props.onEscape) { + this.props.onEscape(); + } + if (key === 27 && this.is_open && this.props.onHide) { + this.is_open = false; + this.props.onHide(); + } + } + keyUp(ev: any) { + const key = ev.which; + const allText = this.getValueBeforeCaret(); + if (key === 8 && this.input.value.length === 0 && this.props.onBackspace) { + this.props.onBackspace(); + } + for (let i = 0; i < this.props.regexHooked.length; i++) { + let text = allText.match(this.props.regexHooked[i]); + if (text && allText) { + if (this.currentRegexUsed < 0 || this.currentRegexUsed !== i) { + this.currentRegexUsed = i; + } + text = text[1] || ''; + if ( + key && + !this.props.disableNavigationKey && + (key === 13 || key === 9 || key === 38 || key === 40) && + this.state.currentList.length > 0 + ) { + ev.preventDefault(); + ev.stopPropagation(); + if (key === 13 || key === 9) { + //Select (enter) + this.select((this.state.currentList || {})[this.state.selected]); + } else if (key === 38 || key === 40) { + //Up // down + let nextState = 0; + if ( + (key === 38 && this.state.resultPosition === 'top') || + (key === 40 && this.state.resultPosition === 'bottom') + ) { + nextState = (this.state.selected + 1) % this.state.currentList.length; + } else { + nextState = + (this.state.selected + this.state.currentList.length - 1) % + this.state.currentList.length; + } + this.setState({ + selected: nextState, + }); + this.currentIdFromList = this.getCurrentIdFromList(this.state.currentList, nextState); + } + } else { + this.is_open = true; + this.search(text, i); + } + if (this.props.onChangeCurrentList) { + this.props.onChangeCurrentList(this.state.currentList, this.state.selected); + } + return; + } + } + + this.currentRegexUsed = -1; + this.setState({ currentList: [], resultPosition: '' }); + this.props.keyUp && this.props.keyUp(ev); + } + + getCurrentIdFromList(list: any[], pos: number) { + if (!list[pos]) { + return; + } + const id = list[pos].id || JSON.stringify(list[pos]); + return id; + } + + componentWillUnmount() { + document.removeEventListener('click', this.outsideClickListener); + this.input.removeEventListener('keydown', this.keyDown); + this.input.removeEventListener('keyup', this.keyUp); + } + componentDidMount() { + const element = this.container; + this.outsideClickListener = (event: any) => { + if (!element.contains(event.target) && document.contains(event.target)) { + this.setState({ focused: false }); + } + }; + this.outsideClickListener = this.outsideClickListener.bind(this); + document.addEventListener('click', this.outsideClickListener); + + this.input.addEventListener('keydown', this.keyDown); + this.input.addEventListener('keyup', this.keyUp); + + if (this.props.showResultsOnInit) { + this.currentRegexUsed = 0; + this.search('', 0); + this.props.onChangeCurrentList(this.state.currentList, this.state.selected); + } + } + search(query: any, i: any) { + this.props.search[this.currentRegexUsed](query, results => { + if (!this.is_open) { + return; + } + + const suggestions: any[] = []; + for (let j = 0; j < Math.min(this.props.max[this.currentRegexUsed], results.length); j++) { + results[j].autocomplete_id = j; + suggestions.push(results[j]); + } + + let selection = 0; + + const idsFromSuggestedList = suggestions.map( + (item, index) => (item = this.getCurrentIdFromList(suggestions, index)), + ); + + selection = Math.max(idsFromSuggestedList.indexOf(this.currentIdFromList), 0); + + this.currentRegexUsed = i; + this.setState({ + selected: selection, + currentList: suggestions, + }); + + this.currentIdFromList = this.getCurrentIdFromList(suggestions, selection); + + if (this.props.onChangeCurrentList) { + this.props.onChangeCurrentList(suggestions, this.state.selected); + } + }); + } + getValueBeforeCaret() { + return this.input.value.substr(0, this.input.selectionStart); + } + putTextAtCursor(text: string, alreadyTypedLength: any) { + alreadyTypedLength = alreadyTypedLength || 0; + + const myValue = text; + + if (this.input.selectionStart || this.input.selectionStart === '0') { + const startPos = this.input.selectionStart; + const endPos = this.input.selectionEnd; + this.input.value = + this.input.value.substring(0, startPos - alreadyTypedLength) + + myValue + + this.input.value.substring(endPos, this.input.value.length); + this.input.selectionStart = this.input.selectionStart + myValue.length; + this.input.selectionEnd = this.input.selectionStart + myValue.length; + } else { + this.input.value += myValue; + } + + if (this.props.onChange) this.props.onChange({ target: { value: this.input.value } }); + + this.input.focus(); + this.input.dispatchEvent(new Event('input')); + + this.setState({ + selected: -1, + currentList: [], + }); + } + select(item: any) { + if (!item) { + return; + } + + const m = this.getValueBeforeCaret().match(this.props.regexHooked[this.currentRegexUsed]); + if (m === null) { + return; + } + const alreadyTypedLength = m[0].length; + + this.putTextAtCursor( + this.props.renderItemChoosen[this.currentRegexUsed](item), + alreadyTypedLength, + ); + + if (this.props.onSelect) { + this.props.onSelect(item, this.currentRegexUsed); + } + this.is_open = false; + } + setPositionResult() { + if (this.input && this.state.resultPosition === '' && this.state.currentList.length > 0) { + const size = this.state.currentList.length * 32 + 5; + if ( + document.documentElement.clientHeight - (window as any).getBoundingClientRect(this.input).bottom < + size || + this.props.position === 'top' + ) { + this.setState({ resultPosition: 'top' }); + } else { + this.setState({ resultPosition: 'bottom' }); + } + } + } + focus() { + if (!this.input) { + return; + } + this.input.focus(); + this.setState({ focused: true }); + this.keyUp({}); + } + blur() { + this.input.blur(); + this.setState({ focused: false }); + } + setContent(content: any) { + this.input.value = content; + } + render() { + this.setPositionResult(); + return ( +
{ + this.focus(); + this.setState({ focused: true }); + }} + ref={node => (this.container = node)} + > +
+ {this.props.autoHeight && ( + { + this.input = ref; + }} + onResize={this.props.onResize} + placeholder={this.props.placeholder} + value={this.props.value} + onChange={this.props.onChange} + onKeyUp={this.props.onKeyUp} + onKeyDown={this.props.onKeyDown} + onKeyPress={this.props.onKeyPress} + onPaste={this.props.onPaste} + onFocus={() => { + if (this.props.onFocusChange) { + this.props.onFocusChange(true); + } + }} + onBlur={() => { + if (this.props.onFocusChange) { + this.props.onFocusChange(false); + } + }} + autoFocus={this.props.autoFocus} + /> + )} + {!this.props.autoHeight && ( + { + this.input = ref; + }} + placeholder={this.props.placeholder} + value={this.props.value} + onChange={this.props.onChange} + onKeyUp={this.props.onKeyUp} + onKeyDown={this.props.onKeyDown} + onKeyPress={this.props.onKeyPress} + onPaste={this.props.onPaste} + onFocus={() => { + if (this.props.onFocusChange) { + this.props.onFocusChange(true); + } + }} + onBlur={() => { + if (this.props.onFocusChange) { + this.props.onFocusChange(false); + } + }} + autoFocus={this.props.autoFocus} + /> + )} + {!this.props.hideResult && this.state.currentList.length > 0 ? ( +
+ {this.state.currentList.map((item, index) => { + return ( +
this.select(item)} + > + {item && this.props.renderItem[this.currentRegexUsed](item)} +
+ ); + })} +
+ ) : ( + '' + )} +
+
+ ); + } +} diff --git a/twake/frontend/src/app/components/auto-height/auto-height.jsx b/twake/frontend/src/app/components/auto-height/auto-height.jsx new file mode 100755 index 00000000..4915cca1 --- /dev/null +++ b/twake/frontend/src/app/components/auto-height/auto-height.jsx @@ -0,0 +1,95 @@ +/* eslint-disable react/prop-types */ +import React, { Component } from 'react'; +import './auto-height.scss'; + +export default class AutoHeight extends Component { + constructor() { + super(); + this.change = this.change.bind(this); + } + componentDidMount() { + this.textarea_offset = + parseInt(this.textarea.style.paddingTop || 0) + + parseInt(this.textarea.style.paddingBottom || 0); + window.addEventListener('resize', this.change); + this.change(); + } + componentWillUnmount() { + window.removeEventListener('resize', this.change); + } + change() { + this.textarea.style.height = '1px'; + var totalHeight = this.textarea.scrollHeight - this.textarea_offset; + this.textarea.style.height = totalHeight + 'px'; + this.container.style.height = totalHeight + 'px'; + if (this.oldHeight !== totalHeight && this.props.onResize) { + this.props.onResize(); + } + this.oldHeight = totalHeight; + } + componentDidUpdate() { + this.change(); + } + render() { + var className = this.props.className || ''; + + if (this.props.big) { + className += ' big '; + } + if (this.props.medium) { + className += ' medium '; + } + if (this.props.small) { + className += ' small '; + } + + if ( + className.indexOf('medium') === className.indexOf('small') && + className.indexOf('big') === className.indexOf('small') && + className.indexOf('big') < 0 + ) { + className += ' medium'; + } + + return ( +
(this.container = node)} + className={'input autoheight_container ' + className} + style={{ + display: 'inline-block', + width: '100%', + minHeight: this.props.minHeight ? this.props.minHeight : '', + maxHeight: this.props.maxHeight ? this.props.maxHeight : '', + }} + onMouseEnter={() => { + this.change(); + }} + > + +
+ ); + } +} diff --git a/twake/frontend/src/app/components/auto-height/auto-height.scss b/twake/frontend/src/app/components/auto-height/auto-height.scss new file mode 100755 index 00000000..15989900 --- /dev/null +++ b/twake/frontend/src/app/components/auto-height/auto-height.scss @@ -0,0 +1,54 @@ +.input.autoheight_container { + textarea { + padding: 16px; + resize: none; + font-size: 14px; + &::-webkit-input-placeholder { + /* Chrome/Opera/Safari */ + white-space: nowrap; + } + &::-moz-placeholder { + /* Firefox 19+ */ + white-space: nowrap; + } + &:-ms-input-placeholder { + /* IE 10+ */ + white-space: nowrap; + } + &:-moz-placeholder { + /* Firefox 18- */ + white-space: nowrap; + } + } + + &.small, + &.medium, + &.big { + padding: 0px; + } + + &.small { + textarea { + padding: 4px 8px; + resize: none; + font-size: 14px; + line-height: 16px; + } + } + &.medium { + textarea { + padding: 13px 16px; + resize: none; + font-size: 14px; + line-height: 16px; + } + } + &.big { + textarea { + padding: 16px; + resize: none; + font-size: 16px; + line-height: 18px; + } + } +} diff --git a/twake/frontend/src/app/components/avatar/avatar.scss b/twake/frontend/src/app/components/avatar/avatar.scss new file mode 100644 index 00000000..aa0b384d --- /dev/null +++ b/twake/frontend/src/app/components/avatar/avatar.scss @@ -0,0 +1,5 @@ +.avatar-component-container { + display: flex !important; + align-items: center; + justify-content: center; +} diff --git a/twake/frontend/src/app/components/avatar/avatar.tsx b/twake/frontend/src/app/components/avatar/avatar.tsx new file mode 100644 index 00000000..6eee1109 --- /dev/null +++ b/twake/frontend/src/app/components/avatar/avatar.tsx @@ -0,0 +1,34 @@ +import React from 'react'; + +import { Avatar, AvatarProps, Image } from 'antd'; + +import './avatar.scss'; + +type PropsType = { + url?: string; + size?: number; + shape?: AvatarProps['shape']; + borderRadius?: React.CSSProperties['borderRadius']; + fallback?: string; + onClick?: ((event: React.MouseEvent) => void) | undefined; +}; + +const AvatarComponent = ({ url, shape, size, borderRadius, fallback, onClick }: PropsType) => ( +
+ + } + /> +
+); + +export default AvatarComponent; diff --git a/twake/frontend/src/app/components/banner/banner.scss b/twake/frontend/src/app/components/banner/banner.scss new file mode 100644 index 00000000..7816c33f --- /dev/null +++ b/twake/frontend/src/app/components/banner/banner.scss @@ -0,0 +1,43 @@ + + +.ant-layout-header.banner-container { + padding: 0 16px; + + &.primary { + background-color: var(--primary); + color: var(--white); + } + + &.secondary { + background-color: var(--secondary); + color: var(--white); + border-bottom: 1px solid var(--black); + } + + &.default { + background-color: var(--primary-background); + color: var(--black); + } + + &.warning { + background-color: var(--warning); + color: var(--white); + } + &.important { + background-color: var(--red); + color: var(--white); + } + + &.ghost { + background-color: transparent; + color: var(--black); + } + + .banner-col-icon { + display: flex; + align-items: center; + .icon { + cursor: pointer; + } + } +} diff --git a/twake/frontend/src/app/components/banner/banner.tsx b/twake/frontend/src/app/components/banner/banner.tsx new file mode 100644 index 00000000..49f711f6 --- /dev/null +++ b/twake/frontend/src/app/components/banner/banner.tsx @@ -0,0 +1,50 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React, { FC } from 'react'; +import { Col, Layout, Row } from 'antd'; +import './banner.scss'; +import { X } from 'react-feather'; +import { CSSProperties } from '@material-ui/styles'; + +type PropsType = { + closable?: boolean; + content?: string | JSX.Element; + onClose?: () => any; + height?: string | number; + type: 'primary' | 'secondary' | 'default' | 'warning' | 'important' | 'ghost'; + style?: CSSProperties; + contentColumnStyle?: CSSProperties; + className?: string; + children?: JSX.Element | JSX.Element[]; +}; + +const Banner: FC = ({ + closable, + content, + onClose, + height, + type, + children, + style, + contentColumnStyle, + className, +}) => { + const headerStyle = { + height: height ? height : 68, + lineHeight: height ? `${height}px` : '68px', + ...style, + }; + + return ( + + + + {content || children || ''} + + {closable && } + + + + ); +}; + +export default Banner; diff --git a/twake/frontend/src/app/components/buttons/button-with-timeout.jsx b/twake/frontend/src/app/components/buttons/button-with-timeout.jsx new file mode 100755 index 00000000..4d33b9c3 --- /dev/null +++ b/twake/frontend/src/app/components/buttons/button-with-timeout.jsx @@ -0,0 +1,74 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; + +import Loader from 'components/loader/loader.jsx'; +import Button from './button.jsx'; +import './buttons.scss'; + +export default class ButtonWithTimeout extends React.Component { + /* + props = { + loading : boolean + value : text in button + loadingTimeout : time before show loading + disabled + onClick + style + className + } + */ + constructor() { + super(); + this.state = { + showLoader: false, + }; + this.timeout = ''; + } + componentWillUnmount() { + clearTimeout(this.timeout); + } + componentDidUpdate(prevProps) { + // eslint-disable-next-line @typescript-eslint/no-this-alias + var that = this; + if (prevProps.loading && !this.props.loading) { + if (this.state.showLoader) { + this.setState({ showLoader: false }); + } + clearTimeout(this.timeout); + } else if (!prevProps.loading && this.props.loading) { + this.timeout = setTimeout(function () { + that.setState({ showLoader: true }); + }, this.props.loadingTimeout || 2000); + } + } + render() { + return ( +
+ +
+ {this.state.showLoader && } +
+
+ ); + } +} diff --git a/twake/frontend/src/app/components/buttons/button.jsx b/twake/frontend/src/app/components/buttons/button.jsx new file mode 100755 index 00000000..a4c260b0 --- /dev/null +++ b/twake/frontend/src/app/components/buttons/button.jsx @@ -0,0 +1,40 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; +import './buttons.scss'; + +export default class Button extends React.Component { + render() { + var className = this.props.className || ''; + + if (this.props.big) { + className += ' big '; + } + if (this.props.medium) { + className += ' medium '; + } + if (this.props.small) { + className += ' small '; + } + + if ( + className.indexOf('medium') === className.indexOf('small') && + className.indexOf('big') === className.indexOf('small') && + className.indexOf('big') < 0 + ) { + className += ' small'; + } + return ( + + ); + } +} diff --git a/twake/frontend/src/app/components/buttons/buttons.scss b/twake/frontend/src/app/components/buttons/buttons.scss new file mode 100755 index 00000000..7013a393 --- /dev/null +++ b/twake/frontend/src/app/components/buttons/buttons.scss @@ -0,0 +1,185 @@ +.buttonWithTimeout_container { + position: relative; + pointer-events: none; + + & > * { + pointer-events: all; + } + + .buttonWithTimeout { + padding: 0px 35px; + transition: padding 0.5s; + } + .loaderContainer { + color: #fff; + top: 0px; + right: 8px; + position: absolute; + display: inline-block; + transition: opacity 0.5s; + opacity: 0; + height: 100%; + align-items: center; + display: inline-flex; + .loader { + width: 30px; + height: 30px; + } + } + + &.is_loading { + .buttonWithTimeout { + padding-right: 45px; + padding-left: 25px; + } + .loaderContainer { + opacity: 1; + } + } +} + +.button, .button.no-tw { + background-color: var(--primary); + color: var(--white); + font-weight: 500; + border: 0px; + border-radius: var(--border-radius-base); + display: inline-block; + vertical-align: middle; + cursor: pointer; + + &:hover { + background-color: var(--primary-hover); + } + &:active { + background-color: var(--primary); + } + &:focus { + outline: none; + } + &.disabled, + &:disabled { + background-color: var(--primary-background); + pointer-events: none; + } + + &.small { + height: 32px; + line-height: 32px; + padding: 0px 8px; + font-size: 14px; + } + + &.medium { + height: 40px; + line-height: 40px; + padding: 0px 12px; + font-size: 16px; + } + + &.big { + height: 64px; + font-size: 18px; + line-height: 64px; + padding: 0px 24px; + } + + &.secondary { + background: #807f8a; + color: var(--white); + + &:hover { + background: #706f79; + } + &:active { + background: #696871; + } + &.disabled, + &:disabled { + background: #bcbcc2; + } + } + + &.danger { + background: #ff1020; + color: var(--white); + + &:hover { + background: #f00010; + } + &:active { + background: #d80000; + } + &.disabled, + &:disabled { + background: #ffa0a0; + } + } + + &.secondary-light { + background-color: var(--grey-light); + color: var(--black); + + &:hover, + &:active { + opacity: 0.9; + } + &.disabled, + &:disabled { + background-color: var(--grey-background); + color: var(--grey-dark); + } + } + + &.primary-text { + background: transparent; + color: var(--primary); + font-size: 12px; + padding: 0 2px; + .m-icon-small { + font-size: 14px !important; + &:before { + margin: 0px; + } + } + &.disabled, + &:disabled { + color: var(--primary-background); + } + &:hover { + color: var(--primary-hover); + // background-color: var(--primary-background); + } + &:active { + // background-color: var(--primary-background); + } + } + + &.secondary-text { + background: transparent; + color: var(--grey-dark); + font-size: 12px; + padding: 0 2px; + .m-icon-small { + font-size: 14px !important; + &:before { + margin: 0px; + } + } + &.disabled, + &:disabled { + color: var(--primary-background); + } + &:hover { + color: var(--black); + //background-color: var(--grey-background); + } + &:active { + color: var(--black); + } + } + + .m-icon-small { + height: 100%; + } +} diff --git a/twake/frontend/src/app/components/calendar/calendar-selector/calendar-selector.jsx b/twake/frontend/src/app/components/calendar/calendar-selector/calendar-selector.jsx new file mode 100755 index 00000000..5b3d3155 --- /dev/null +++ b/twake/frontend/src/app/components/calendar/calendar-selector/calendar-selector.jsx @@ -0,0 +1,159 @@ +/* eslint-disable react/prop-types */ +/* eslint-disable react/jsx-key */ +import React from 'react'; +import './calendar-selector.scss'; +import Collections from 'app/deprecated/CollectionsV1/Collections/Collections.js'; +import Select from 'components/select/select.jsx'; +import MenusManager from 'app/components/menus/menus-manager.jsx'; +import WorkspacesService from 'app/deprecated/workspaces/workspaces.jsx'; +import Languages from 'app/features/global/services/languages-service'; + +export default class CalendarSelector extends React.Component { + constructor(props) { + super(); + this.props = props; + + this.state = { + selected: [], + }; + } + + delete(item) { + var list = this.props.value.map(item => item.calendar_id); + const index = list.indexOf(item.id); + if (index >= 0) { + list.splice(index, 1); + this.change(list); + } + MenusManager.closeMenu(); + } + + openMenu(evt, item) { + if (this.props.readonly) { + return; + } + MenusManager.openMenu( + [ + { + className: 'error', + icon: 'trash', + text: Languages.t('components.calendar.calendarselector.remove', [], 'Retirer'), + onClick: () => { + this.delete(item); + }, + }, + ], + { x: evt.clientX, y: evt.clientY, width: 150 }, + 'bottom', + ); + } + + change(list) { + if (this.props.onChange) + this.props.onChange( + list + .map(id => { + var cal = Collections.get('calendars').find(id); + if (!cal) { + return undefined; + } + return { + calendar_id: cal.id, + workspace_id: cal.workspace_id, + }; + }) + .filter(item => item), + ); + } + + render() { + return ( +
+
+ {this.props.value.map(ws_cal_id => { + var item = Collections.get('calendars').find(ws_cal_id.calendar_id); + if (!item || item.workspace_id !== WorkspacesService.currentWorkspaceId) { + return ''; + } + return ( +
(this.node = node)} + onClick={evt => this.openMenu(evt, item)} + className={'calendar_item ' + (this.props.readonly ? '' : 'removable')} + > +
+ {'' + item.title} +
+ ); + })} + + {(!this.props.value || this.props.value.length === 0) && ( +
+ {Languages.t( + 'components.calendar.calendarselector.no_workspace_calendar', + [], + "Aucun calendrier d'espace de travail.", + )} +
+ )} +
+ + {!this.props.readonly && ( +
+ this.input.blur()} + onEnter={() => this.input.blur()} + onBlur={() => this.blur()} + onFocus={() => this.focus()} + placeholder={'No date'} + value={this.state.time_ts ? this.state.time_string : ''} + style={{ maxWidth: 108 }} + onChange={evt => this.process(evt.target.value)} + refInput={node => (this.input = node)} + big={this.props.big} + medium={this.props.medium} + small={this.props.small} + /> + {this.props.withReset && ( +
{ + this.setState({ time_ts: false }); + this.props.onChangeBlur(this.state.time_ts); + this.setState({}); + }} + > + +
+ )} + +
+ ); + } +} diff --git a/twake/frontend/src/app/components/calendar/date-picker.scss b/twake/frontend/src/app/components/calendar/date-picker.scss new file mode 100755 index 00000000..ee6dd11b --- /dev/null +++ b/twake/frontend/src/app/components/calendar/date-picker.scss @@ -0,0 +1,18 @@ +.date_selector { + .reset_date { + width: 16px; + height: 16px; + position: absolute; + right: 8px; + top: 12px; + background: #eee; + border-radius: var(--border-radius-large); + font-size: 12px; + color: #444; + cursor: pointer; + + &:hover { + background: #ddd; + } + } +} diff --git a/twake/frontend/src/app/components/calendar/day-picker/day-picker.jsx b/twake/frontend/src/app/components/calendar/day-picker/day-picker.jsx new file mode 100755 index 00000000..99bff9f9 --- /dev/null +++ b/twake/frontend/src/app/components/calendar/day-picker/day-picker.jsx @@ -0,0 +1,164 @@ +/* eslint-disable react/prop-types */ +import React, { Component } from 'react'; +import Icon from 'app/components/icon/icon.jsx'; +import moment from 'moment'; +import './day-picker.scss'; + +export default class DayPicker extends Component { + /* + this.props :{ + onChange(day) + value : Array of selected days + } + */ + constructor(props) { + super(props); + this.state = { + days: [], + currentDate: moment(), + }; + this.openSelected = false; + window.moment = moment; + } + componentDidMount() { + this.setState(this.updateDay()); + } + UNSAFE_componentWillUpdate(nextProps, nextState) { + if (moment(nextProps.value).valueOf() != this.oldProp) { + var obj = this.updateDay(nextProps.value); + nextState.days = obj.days; + nextState.currentDate = obj.currentDate; + } + this.oldProp = moment(nextProps.value).valueOf(); + } + updateDay(date) { + var searchedDate = date || moment(); + var days = []; + var first_day_of_month = moment(searchedDate).startOf('month').startOf('week'); + for (var i = 0; i < 35; i++) { + days.push(moment(moment(first_day_of_month).add(i, 'days'))); + } + return { + days: days, + currentDate: searchedDate, + }; + } + isSelected(day) { + if (this.props.value) { + if ( + Array.isArray(this.props.value) && + this.props.value.length == 2 && + this.props.value[0] && + this.props.value[1] + ) { + return day.isBetween(this.props.value[0], this.props.value[1], 'day', '[]'); + } else if ( + Array.isArray(this.props.value) && + this.props.value.length >= 1 && + this.props.value[0] + ) { + return day.isSame(this.props.value[0], 'day'); + } else if (!Array.isArray(this.props.value) && this.props.value) { + return day.isSame(this.props.value, 'day'); + } + } + return false; + } + isLast(day) { + if (this.props.value) { + if ( + Array.isArray(this.props.value) && + this.props.value.length == 2 && + this.props.value[0] && + this.props.value[1] + ) { + return day.isSame(this.props.value[1], 'day'); + } else if ( + Array.isArray(this.props.value) && + this.props.value.length >= 1 && + this.props.value[0] + ) { + return day.isSame(this.props.value[0], 'day'); + } else if (!Array.isArray(this.props.value) && this.props.value) { + return day.isSame(this.props.value, 'day'); + } + } + return false; + } + render() { + var last_week = -1; + return ( +
this.props.onClick && this.props.onClick()} + onMouseDown={this.props.onMouseDown} + > +
+
{moment(this.state.currentDate).format('MMMM YYYY')}
+
+
{ + this.setState(this.updateDay(moment(this.state.currentDate).subtract(1, 'months'))); + }} + > + +
+
{ + this.setState(this.updateDay(moment(this.state.currentDate).add(1, 'months'))); + }} + > + +
+
+
+
+
+ Wk +
+ {this.state.days.map((day, index) => { + if (index < 7) { + return ( +
+ {day.format('ddd')} +
+ ); + } + })} + {this.state.days.map(day => { + var list = []; + if (day.week() != last_week) { + last_week = day.week(); + list.push(
{last_week}
); + } + list.push( +
{ + if (this.props.onChange) { + this.props.onChange(day); + } + }} + className={ + 'day ' + + (day.month() == this.state.currentDate.month() ? '' : 'notInMonth') + + ' ' + + (day.format('YYYY MM DD') == moment().format('YYYY MM DD') ? 'today' : '') + + ' ' + + (this.isSelected(day) ? 'selected' : '') + + ' ' + + (this.isLast(day) ? 'last' : '') + } + > + {day.date()} +
, + ); + return list; + })} +
+
+ ); + } +} diff --git a/twake/frontend/src/app/components/calendar/day-picker/day-picker.scss b/twake/frontend/src/app/components/calendar/day-picker/day-picker.scss new file mode 100755 index 00000000..8fa3a3cd --- /dev/null +++ b/twake/frontend/src/app/components/calendar/day-picker/day-picker.scss @@ -0,0 +1,97 @@ +.dayPicker { + width: 200px; + font-size: 14px; + font-weight: 500; + + .titleDayPicker { + display: flex; + margin-top: -8px; + margin-bottom: -4px; + .month { + display: inline-block; + text-transform: capitalize; + line-height: 30px; + } + .chevron { + flex: 1; + text-align: right; + display: inline-block; + .move_icon { + display: inline-block; + font-size: 14px; + opacity: 1; + padding: 5px; + border-radius: var(--border-radius-base); + } + .move_icon:hover { + cursor: pointer; + background: rgba(55, 53, 47, 0.08); + } + } + } + .days { + .weeknumber { + background: #dfdfdf; + height: 26px; + line-height: 26px; + vertical-align: top; + display: inline-block; + font-size: 12px; + color: #000; + opacity: 0.3; + padding: 0 1px; + box-sizing: border-box; + width: 12.5%; + text-align: center; + } + .dayName { + display: inline-block; + width: 12.5%; + text-align: center; + height: 28px; + line-height: 28px; + font-size: 11px; + border-radius: var(--border-radius-base); + opacity: 0.6; + } + .dayName:first-child { + opacity: 0.3; + } + .day { + display: inline-block; + width: 12.5%; + text-align: center; + height: 24px; + line-height: 24px; + margin-bottom: 2px; + border-radius: var(--border-radius-base); + } + .day:not(.selected):hover { + background: rgba(45, 156, 219, 0.2); + } + .day:hover { + cursor: pointer; + } + .notInMonth { + opacity: 0.5; + } + .selected + .selected:not(.last) { + border-radius: 0px; + } + .selected { + background: #827dff; + border-radius: var(--border-radius-base) 0px 0px var(--border-radius-base); + color: white; + } + .selected + .last { + border-radius: 0px 4px 4px 0px; + } + :not(.selected) + .last { + border-radius: var(--border-radius-base); + } + .today:not(.selected) { + color: rgb(235, 87, 87); + border-radius: var(--border-radius-base); + } + } +} diff --git a/twake/frontend/src/app/components/calendar/event/event.jsx b/twake/frontend/src/app/components/calendar/event/event.jsx new file mode 100755 index 00000000..2ede0d6a --- /dev/null +++ b/twake/frontend/src/app/components/calendar/event/event.jsx @@ -0,0 +1,123 @@ +/* eslint-disable react/prop-types */ +import React, { Component } from 'react'; +import './event.scss'; +import Collections from 'app/deprecated/CollectionsV1/Collections/Collections.js'; +import Icon from 'app/components/icon/icon.jsx'; +import Languages from 'app/features/global/services/languages-service'; +import UserListManager from 'components/user-list-manager-depreciated/user-list-manager'; + +import moment from 'moment'; + +export default class Event extends Component { + constructor(props) { + super(); + this.props = props; + } + render() { + var className = ''; + var icon = ''; + var event_duration = ''; + var classNameUser = ''; + if (this.props.inEvent) { + classNameUser = 'inEvent'; + } + + var event_name = + this.props.event.title || Languages.t('scenes.apps.drive.navigators.new_file.untitled'); + + var event_start = moment(parseInt(this.props.event.from) * 1000).format('LT'); + + var event_end = moment(parseInt(this.props.event.to) * 1000).format('LT'); + + var location = this.props.event.location || ''; + + if (event_start) event_duration = event_start; + if (event_end) + event_duration = + event_duration + Languages.t('components.calendar.event.to', [], ' Γ  ') + event_end; + + var duration = (parseInt(this.props.event.to) - parseInt(this.props.event.from)) / 60; + + if ( + (duration > 0 && duration <= 15) || + this.props.event.type == 'deadline' || + this.props.event.type == 'remind' + ) { + className += ' size_15 '; + } else if ((duration > 15 && duration <= 30) || this.props.event.all_day) { + className += ' size_30'; + if (location) event_duration += ', ' + location; + } else if (duration > 30 && duration <= 45) { + className += ' size_45'; + } else if (duration > 45 && duration <= 60) { + className += ' size_60'; + } + + className += ' ' + this.props.event.type; + + if (this.props.event.type == 'remind') { + icon = 'stopwatch'; + } else if (this.props.event.type == 'deadline') { + icon = 'stopwatch-slash'; + } else if (this.props.event.type == 'move') { + icon = 'car-sideview'; + } + + var users = []; + var emails = []; + + (this.props.event.participants || []).map(obj => { + if (obj) { + var regex = /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i; + if (obj.user_id_or_mail.match(regex)) { + var user = Collections.get('users').find(obj.user_id_or_mail); + users.push(user); + } else { + var email = obj.user_id_or_mail; + emails.push(email); + } + } + }); + + return ( +
+
+ {icon && } + + + {event_name} + + {(duration <= 30 || this.props.event.all_day) && ', ' + event_start} + + +
+ + {duration > 30 && !this.props.event.all_day && ( +
+ {event_duration} +
+ )} + +
+ {'' + location} +
+ +
+ { + return { id: u.user_id_or_mail }; + })} + max={4} + readOnly + collapsed + medium + /> +
+
+ ); + } +} diff --git a/twake/frontend/src/app/components/calendar/event/event.scss b/twake/frontend/src/app/components/calendar/event/event.scss new file mode 100755 index 00000000..c959d537 --- /dev/null +++ b/twake/frontend/src/app/components/calendar/event/event.scss @@ -0,0 +1,144 @@ +.event_container { + margin: 0px; + width: auto; + height: auto; + border-radius: var(--border-radius-base); + color: var(--white); + box-sizing: border-box; + padding-left: 4px; + padding-right: 2px; + padding-top: 2px; + position: relative; + transition: box-shadow 0.2s; + cursor: pointer; + + & > div { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + &:hover { + box-shadow: 0 0px 1000px 0px rgba(0, 0, 0, 0.1) inset; + } + + .icon { + display: inline-block; + font-size: 14px; + font-weight: 700; + margin-left: -2px; + } + + .text { + &.title { + font-size: 12px; + font-weight: 700; + } + + &.simple { + font-size: 11px; + font-weight: 500; + } + } + + .time, + .place, + .description, + .users { + display: flex; + flex-direction: row; + text-overflow: ellipsis; + } + + .users { + position: absolute; + bottom: 2px; + right: 2px; + display: flex; + align-items: center; + height: 28px; + + .emoji-container { + width: 24px; + text-align: center; + } + + .more { + font-size: 12px; + margin: 0 2px; + font-weight: 700; + opacity: 0.8; + } + } + + .time.size_15, + .place.size_15, + .place.size_30, + .users.size_15, + .users.size_30, + .users.size_45 { + .user_head { + width: 12px !important; + height: 12px !important; + } + } + + .place.size_45 { + margin-top: 8px; + } + + .users > div { + border-radius: var(--border-radius-base); + margin-left: 2px; + } + + //event + min-height: 60px; + + &.size_15 { + min-height: 16px; + height: 16px; + font-size: 11px; + } + + &.size_30 { + min-height: 24px; + height: 24px; + } + + &.size_45 { + min-height: 32px; + height: 32px; + } + + &.size_60 { + min-height: 48px; + } + + .inEvent { + border-style: solid; + border: 0px; + } + + //rappel + &.remind { + border-radius: var(--border-radius-large); + min-height: 18px; + } + + //deadline + + &.deadline { + border-top-left-radius: 1px; + border-top-right-radius: 1px; + box-shadow: 0 2px 0px 0px rgba(255, 0, 0, 0.5) inset; + min-height: 18px; + } + + //deplacement + + &.move { + border-radius: var(--border-radius-large); + border-top-left-radius: 4px; + } +} diff --git a/twake/frontend/src/app/components/calendar/time-selector.jsx b/twake/frontend/src/app/components/calendar/time-selector.jsx new file mode 100755 index 00000000..5b8d12f9 --- /dev/null +++ b/twake/frontend/src/app/components/calendar/time-selector.jsx @@ -0,0 +1,121 @@ +/* eslint-disable react/prop-types */ +/* eslint-disable react/no-direct-mutation-state */ +import React, { Component } from 'react'; +import Input from 'components/inputs/input.jsx'; +import Tooltip from 'components/tooltip/tooltip.jsx'; +import moment from 'moment'; +import DateTimeUtils from 'app/features/global/utils/datetime.js'; +import Languages from 'app/features/global/services/languages-service'; + +export default class TimeSelector extends Component { + constructor(props) { + super(props); + this.state = { + time_ts: props.ts, + time_string: moment(new Date(props.ts * 1000)).format(DateTimeUtils.getDefaultTimeFormat()), + }; + this.old_ts = props.ts; + this.focus = false; + } + + shouldComponentUpdate(nextProps, nextStates) { + if (nextProps.ts != this.old_ts) { + this.old_ts = nextProps.ts; + nextStates.time_ts = nextProps.ts; + if (!this.focus) { + nextStates.time_string = moment(new Date(nextProps.ts * 1000)).format( + DateTimeUtils.getDefaultTimeFormat(), + ); + } + } + return true; + } + + process(string) { + var h, m, am_pm; + var error = false; + + if (string) { + var match = string.match(/^[^0-9]*([0-9]+)([^0-9]+)?([0-9]*)?(.*?)$/); + + if (match) { + h = parseInt(match[1]); + m = parseInt(match[3] || '0'); + am_pm = ((match[4] ? match[4] : match[2]) || '').toLocaleLowerCase(); + if (am_pm && (am_pm[0] == 'p' || am_pm.indexOf('pm') >= 0)) { + am_pm = 'PM'; + } else if (am_pm && (am_pm[0] == 'a' || am_pm.indexOf('am') >= 0)) { + am_pm = 'AM'; + } else { + if (h == 12) { + am_pm = 'PM'; + } else { + am_pm = 'AM'; + } + } + } else { + error = true; + } + + if (h > 12) { + am_pm = ''; + } + + if (h > 23) { + error = true; + } + + if (m > 59) { + error = true; + } + } else { + error = true; + } + + this.state.time_string = string; + + if (!error) { + var d = moment(h + ':' + m + am_pm, 'LT').toDate(); + var date = new Date(this.state.time_ts * 1000); + date.setHours(d.getHours()); + date.setMinutes(d.getMinutes()); + this.state.time_ts = date.getTime() / 1000; + this.state.error = false; + this.state.time_string_formatted = moment(this.state.time_ts * 1000).format( + DateTimeUtils.getDefaultTimeFormat(), + ); + this.props.onChange && this.props.onChange(this.state.time_ts); + } else { + this.state.error = true; + } + this.setState({}); + } + + blur() { + this.focus = false; + this.setState({ time_string: this.state.time_string_formatted, error: false }); + this.props.onChangeBlur && this.props.onChangeBlur(this.state.time_ts); + this.props.onChange && this.props.onChange(this.state.time_ts); + } + + render() { + return ( +
+ + this.blur()} + onFocus={() => (this.focus = true)} + value={this.state.time_string} + style={{ maxWidth: 94 }} + onChange={evt => this.process(evt.target.value)} + /> + +
+ ); + } +} diff --git a/twake/frontend/src/app/components/channel-attachement-list/channel-attachement-list.tsx b/twake/frontend/src/app/components/channel-attachement-list/channel-attachement-list.tsx new file mode 100644 index 00000000..0a62132e --- /dev/null +++ b/twake/frontend/src/app/components/channel-attachement-list/channel-attachement-list.tsx @@ -0,0 +1,44 @@ +import { Modal, ModalContent } from 'app/atoms/modal'; +import { + channelAttachmentListState, + activeChannelAttachementListTabState, +} from 'app/features/channels/state/channel-attachment-list'; +import Languages from 'app/features/global/services/languages-service'; +import Tab from 'app/molecules/tabs'; +import React from 'react'; +import { useRecoilState } from 'recoil'; +import ChannelFiles from './parts/channel-files'; +import ChannelMedias from './parts/channel-medias'; + +enum Tabs { + Medias = 0, + Files = 1, +} + +export default (): React.ReactElement => { + const [open, setOpen] = useRecoilState(channelAttachmentListState); + const [activeTab, setActiveTab] = useRecoilState(activeChannelAttachementListTabState); + + return ( + setOpen(false)} className="sm:w-[60vw] sm:max-w-2xl"> + + +
+ {Languages.t('components.channel_attachement_list.medias')} +
+
, +
+
{Languages.t('components.channel_attachement_list.files')}
+
, + ]} + selected={activeTab} + onClick={index => setActiveTab(index)} + /> + {activeTab === Tabs.Medias && } + {activeTab === Tabs.Files && } + + + ); +}; diff --git a/twake/frontend/src/app/components/channel-attachement-list/parts/channel-attachment.tsx b/twake/frontend/src/app/components/channel-attachement-list/parts/channel-attachment.tsx new file mode 100644 index 00000000..0da3ac28 --- /dev/null +++ b/twake/frontend/src/app/components/channel-attachement-list/parts/channel-attachment.tsx @@ -0,0 +1,176 @@ +import { Button } from 'app/atoms/button/button'; +import { DownloadIcon } from 'app/atoms/icons-agnostic'; +import { + FileTypeArchiveIcon, + FileTypeDocumentIcon, + FileTypePdfIcon, + FileTypeSlidesIcon, + FileTypeSpreadsheetIcon, + FileTypeUnknownIcon, +} from 'app/atoms/icons-colored'; +import { Base, Info } from 'app/atoms/text'; +import { channelAttachmentListState } from 'app/features/channels/state/channel-attachment-list'; +import fileUploadApiClient from 'app/features/files/api/file-upload-api-client'; +import fileUploadService from 'app/features/files/services/file-upload-service'; +import { formatDate } from 'app/features/global/utils/format-date'; +import { formatSize } from 'app/features/global/utils/format-file-size'; +import { Message, MessageFileType } from 'app/features/messages/types/message'; +import routerService from 'app/features/router/services/router-service'; +import { UserType } from 'app/features/users/types/user'; +import { useFileViewerModal } from 'app/features/viewer/hooks/use-viewer'; +import Media from 'app/molecules/media'; +import React from 'react'; +import { ArrowRight } from 'react-feather'; +import { useRecoilState } from 'recoil'; + +type FileMessageType = { + message?: Message; +}; + +type FileUserType = { + user?: UserType; +}; + +type PropsType = { + file: MessageFileType & FileMessageType & FileUserType; + is_media: boolean; +}; + +type FilePreviewType = { + file: MessageFileType & FileMessageType & FileUserType; +}; + +export default ({ file, is_media }: PropsType): React.ReactElement => { + return is_media ? : ; +}; + +const ChannelFile = ({ file }: FilePreviewType): React.ReactElement => { + const [, setOpen] = useRecoilState(channelAttachmentListState); + const name = file?.metadata?.name; + const extension = name?.split('.').pop(); + const previewUrl = fileUploadApiClient.getFileThumbnailUrlFromMessageFile(file); + const fileType = fileUploadApiClient.mimeToType(file?.metadata?.mime || ''); + const { open: openViewer } = useFileViewerModal(); + + const iconClassName = previewUrl + ? 'absolute left-0 top-0 bottom-0 right-0 m-auto w-8 h-8' + : 'absolute bottom-1 left-1 w-6 h-6'; + + return ( +
openViewer(file)} + > +
+ + {(!['image', 'video'].includes(fileType) || !previewUrl) && ( + <> + {fileType === 'archive' ? ( + + ) : fileType === 'pdf' ? ( + + ) : fileType === 'document' ? ( + + ) : fileType === 'slides' ? ( + + ) : fileType === 'spreadsheet' ? ( + + ) : ( + + )} + + )} +
+
+ {name} + + {extension?.toLocaleUpperCase()} β€’ {formatDate(file?.message?.created_at)} β€’{' '} + {formatSize(file?.metadata?.size)} + +
+
{ + e.preventDefault(); + e.stopPropagation(); + }} + > + + + {!!file.message && ( + + )} +
+
+ ); +}; + +const ChannelMedia = ({ file }: FilePreviewType): React.ReactElement => { + const previewUrl = fileUploadApiClient.getFileThumbnailUrlFromMessageFile(file); + const type = fileUploadApiClient.mimeToType(file?.metadata?.mime || ''); + const { open: openViewer } = useFileViewerModal(); + + return ( +
openViewer(file)} + > + +
+ ); +}; + +const getFileDownloadRoute = (file: MessageFileType): string => { + if (file?.metadata?.source !== 'internal') { + return ''; + } + + return fileUploadService.getDownloadRoute({ + companyId: file.metadata?.external_id?.company_id, + fileId: file.metadata?.external_id?.id, + }); +}; + +const downloadFile = (file: MessageFileType): void => { + const url = getFileDownloadRoute(file); + + if (url) { + window.location.href = url; + } +}; + +const gotoMessage = (message: Message): void => { + routerService.push( + routerService.generateRouteFromState({ + companyId: message?.cache?.company_id, + channelId: message?.cache?.channel_id, + threadId: message?.thread_id, + workspaceId: message?.cache?.workspace_id, + ...(message.id !== message?.thread_id ? { messageId: message.id } : {}), + }), + ); +}; diff --git a/twake/frontend/src/app/components/channel-attachement-list/parts/channel-files.tsx b/twake/frontend/src/app/components/channel-attachement-list/parts/channel-files.tsx new file mode 100644 index 00000000..ba273508 --- /dev/null +++ b/twake/frontend/src/app/components/channel-attachement-list/parts/channel-files.tsx @@ -0,0 +1,36 @@ +import { useChannelFileList } from 'app/features/channels/hooks/use-channel-media-files'; +import React, { useEffect } from 'react'; +import ChannelAttachment from './channel-attachment'; +import { LoadingAttachements, NoAttachements } from './commun'; +import PerfectScrollbar from 'react-perfect-scrollbar'; + +type PropsType = { + maxItems?: number; +}; + +export default ({ maxItems }: PropsType): React.ReactElement => { + const { loading, result, loadMore, loadItems } = useChannelFileList(); + + useEffect(() => { + loadItems(); + }, []); + + return ( + loadMore()} + > + {result.length === 0 && !loading && } + {loading ? ( + + ) : ( + result + .slice(0, maxItems || result.length) + .map(file => ) + )} + + ); +}; diff --git a/twake/frontend/src/app/components/channel-attachement-list/parts/channel-medias.tsx b/twake/frontend/src/app/components/channel-attachement-list/parts/channel-medias.tsx new file mode 100644 index 00000000..8404d77c --- /dev/null +++ b/twake/frontend/src/app/components/channel-attachement-list/parts/channel-medias.tsx @@ -0,0 +1,44 @@ +import { useChannelMediaList } from 'app/features/channels/hooks/use-channel-media-files'; +import fileUploadApiClient from 'app/features/files/api/file-upload-api-client'; +import React, { useEffect } from 'react'; +import ChannelAttachment from './channel-attachment'; +import { LoadingAttachements, NoAttachements } from './commun'; +import PerfectScrollbar from 'react-perfect-scrollbar'; + +type PropsType = { + maxItems?: number; +}; + +export default ({ maxItems }: PropsType): React.ReactElement => { + const { loading, result, loadMore, loadItems } = useChannelMediaList(); + + useEffect(() => { + loadItems(); + }, []); + + return ( + <> + loadMore()} + > + {result.length === 0 && !loading && } + {loading ? ( + + ) : ( + result + .slice(0, maxItems || result.length) + .map(file => { + const url = fileUploadApiClient.getFileThumbnailUrlFromMessageFile(file); + + return url && ; + }) + .filter(Boolean) + )} + + + ); +}; diff --git a/twake/frontend/src/app/components/channel-attachement-list/parts/commun.tsx b/twake/frontend/src/app/components/channel-attachement-list/parts/commun.tsx new file mode 100644 index 00000000..24ba5228 --- /dev/null +++ b/twake/frontend/src/app/components/channel-attachement-list/parts/commun.tsx @@ -0,0 +1,22 @@ +import { Loader } from 'app/atoms/loader'; +import { Info } from 'app/atoms/text'; +import Languages from 'app/features/global/services/languages-service'; +import React from 'react'; + +export const LoadingAttachements = (): React.ReactElement => { + return ( +
+ +
+ ); +}; + +export const NoAttachements = (): React.ReactElement => { + return ( +
+ + {Languages.t('components.channel_attachement_list.nothing_found')} + +
+ ); +}; diff --git a/twake/frontend/src/app/components/channel-members-list/channel-members-modal.tsx b/twake/frontend/src/app/components/channel-members-list/channel-members-modal.tsx new file mode 100644 index 00000000..1a524bb9 --- /dev/null +++ b/twake/frontend/src/app/components/channel-members-list/channel-members-modal.tsx @@ -0,0 +1,178 @@ +import { InformationCircleIcon } from '@heroicons/react/outline'; +import { SearchIcon } from '@heroicons/react/solid'; +import { Alert } from 'app/atoms/alert'; +import { InputDecorationIcon } from 'app/atoms/input/input-decoration-icon'; +import { Input } from 'app/atoms/input/input-text'; +import Text, { Info } from 'app/atoms/text'; +import { useSearchChannelMembersAll } from 'app/features/channel-members-search/hooks/use-search-all'; +import Languages from 'app/features/global/services/languages-service'; +import { delayRequest } from 'app/features/global/utils/managedSearchRequest'; +import Strings from 'app/features/global/utils/strings'; +import { useInvitationUsers } from 'app/features/invitation/hooks/use-invitation-users'; +import { invitationState } from 'app/features/invitation/state/invitation'; +import useRouterChannel from 'app/features/router/hooks/use-router-channel'; +import { useEffect, useState } from 'react'; +import PerfectScrollbar from 'react-perfect-scrollbar'; +import { useRecoilState } from 'recoil'; +import { EmailItem } from './email-item'; +import { MemberItem } from './member-item'; +import { UserItem } from './user-item'; +import AccessRightsService from 'app/features/workspace-members/services/workspace-members-access-rights-service'; +import { useCurrentWorkspace } from 'app/features/workspaces/hooks/use-workspaces'; + +export const ChannelMembersListModal = (): JSX.Element => { + const channelId = useRouterChannel(); + const [query, setQuery] = useState(''); + + const { addEmailSuggestion, pendingEmailList, channelMembersList, usersList, search, refresh } = + useSearchChannelMembersAll({ + channelId, + }); + + useEffect(() => { + delayRequest('ChannelMembersListModal', async () => { + search(query); + }); + }, [search, query]); + + useEffect(() => { + if (channelId) refresh(); + }, [channelId]); + + return ( +
+
+ ( + { + setQuery(e.target.value); + }} + value={query} + /> + )} + /> + {pendingEmailList?.length === 0 && channelMembersList?.length <= 1 && ( + + )} +
+
+ +
+ {addEmailSuggestion && + pendingEmailList?.length === 0 && + channelMembersList?.length === 0 && + usersList?.length === 0 && + !Strings.verifyMail(query) && ( + <> + + {Languages.t( + 'scenes.client.channelbar.channelmemberslist.search_invite_type_email', + )} + + + )} + {addEmailSuggestion && } + {pendingEmailList?.length > 0 && ( + <> + + {Languages.t('scenes.client.channelbar.channelmemberslist.pending_section')} + + + )} + {pendingEmailList && + pendingEmailList.map((item, index) => { + return ( +
+ +
+ ); + })} + {channelMembersList?.length > 0 && ( + <> + + {Languages.t('scenes.client.channelbar.channelmemberslist.members_section')} + + + )} + {channelMembersList && + channelMembersList + .filter(a => a && a?.user) + .map(cMember => { + return ( +
+ +
+ ); + })} + {usersList?.length > 0 && ( + <> + + {Languages.t('scenes.client.channelbar.channelmemberslist.not_members_section')} + + + )} + {usersList && + usersList.map(user => { + return ( +
+ +
+ ); + })} +
+
+
+
+ ); +}; + +const EmailSuggestion = ({ email }: { email: string }) => { + const [, setInvitationOpen] = useRecoilState(invitationState); + const { addInvitation, allowed_guests, allowed_members } = useInvitationUsers(); + const { workspace } = useCurrentWorkspace(); + + const invite = () => { + addInvitation(email); + setInvitationOpen(true); + }; + if (!email || !Strings.verifyMail(email)) { + return <>; + } + + return AccessRightsService.hasLevel(workspace?.id, 'moderator') && + (allowed_guests > 0 || allowed_members > 0) ? ( +
+ + invite()}> + {Languages.t( + 'scenes.client.channelbar.channelmemberslist.invite_to_workspace', + [email], + `Invite ${email} to the workspace ➑`, + )} + + +
+ ) : ( + <> + ); +}; diff --git a/twake/frontend/src/app/components/channel-members-list/email-item.tsx b/twake/frontend/src/app/components/channel-members-list/email-item.tsx new file mode 100644 index 00000000..a3741725 --- /dev/null +++ b/twake/frontend/src/app/components/channel-members-list/email-item.tsx @@ -0,0 +1,106 @@ +import { MailIcon } from '@heroicons/react/outline'; +import { XIcon } from '@heroicons/react/solid'; +import { Tooltip } from 'antd'; +import { Button } from 'app/atoms/button/button'; +import { Modal, ModalContent } from 'app/atoms/modal'; +import { Info } from 'app/atoms/text'; +import { usePendingEmail } from 'app/features/channel-members-search/hooks/use-pending-email-hook'; +import Languages from 'app/features/global/services/languages-service'; +import { PendingEmail } from 'app/features/pending-emails/types/pending-email'; +import useRouterCompany from 'app/features/router/hooks/use-router-company'; +import useRouterWorkspace from 'app/features/router/hooks/use-router-workspace'; +import WorkspaceUserAPIClient from 'app/features/workspace-members/api/workspace-members-api-client'; +import { WorkspacePendingUserType } from 'app/features/workspaces/types/workspace'; +import { useState } from 'react'; + +type IProps = { + email: PendingEmail; +}; + +export const EmailItem = (props: IProps): JSX.Element => { + const { email } = props.email; + const { loading, cancelInvite } = usePendingEmail(email); + const workspaceId = useRouterWorkspace(); + const companyId = useRouterCompany(); + const [cancelWorkspaceInvitation, setCancelWorkspaceInvitation] = + useState(null); + + const _cancelInvite = async () => { + //Also check if the user is pending in the workspace and display something if that's the case + const pending = await WorkspaceUserAPIClient.listPending(companyId, workspaceId); + const foundWorkspacePending = pending.find( + p => p.email.toLocaleLowerCase() === email.toLocaleLowerCase(), + ); + if (foundWorkspacePending) { + //Propose to also cancel workspace invitation + setCancelWorkspaceInvitation(foundWorkspacePending); + } else { + await cancelInvite(); + } + }; + + return ( + <> + setCancelWorkspaceInvitation(null)}> + { + setCancelWorkspaceInvitation(null); + cancelInvite(); + }} + > + {Languages.t('general.no')} + , + , + ]} + > + +
+ +
+ + {email}{' '} + + ( + {Languages.t( + 'scenes.client.channels_bar.modals.parts.channel_member_row.label.pending_email', + )} + ) + + +
+
+
+ + + +
+ + ); +}; diff --git a/twake/frontend/src/app/components/channel-members-list/member-item.tsx b/twake/frontend/src/app/components/channel-members-list/member-item.tsx new file mode 100644 index 00000000..c7ad9c7f --- /dev/null +++ b/twake/frontend/src/app/components/channel-members-list/member-item.tsx @@ -0,0 +1,81 @@ +import Avatar from 'app/atoms/avatar'; +import { ChannelMemberWithUser } from 'app/features/channel-members-search/types/channel-members'; +import Languages from 'app/features/global/services/languages-service'; +import UsersService from 'app/features/users/services/current-user-service'; +import useRouterCompany from 'app/features/router/hooks/use-router-company'; +import useRouterWorkspace from 'app/features/router/hooks/use-router-workspace'; +import useRouterChannel from 'app/features/router/hooks/use-router-channel'; +import { useChannelMember } from 'app/features/channel-members-search/hooks/member-hook'; +import { LogoutIcon } from '@heroicons/react/outline'; +import { Tooltip } from 'antd'; +import { ButtonConfirm } from 'app/atoms/button/confirm'; +import MemberGrade from 'app/views/client/popup/WorkspaceParameter/Pages/WorkspacePartnerTabs/MemberGrade'; + +type IMemberProps = { + member: ChannelMemberWithUser; + userId?: string; +}; + +export const MemberItem = (props: IMemberProps): JSX.Element => { + const { member, userId } = props; + const { first_name, email } = member.user; + const companyId = useRouterCompany(); + const workspaceId = useRouterWorkspace(); + const channelId = useRouterChannel(); + + const parameters = { companyId, workspaceId, channelId }; + + const { leave, loading } = useChannelMember(userId || '', parameters); + + const isCurrentUser = (): boolean => { + const currentUserId: string = UsersService.getCurrentUserId(); + + return props.userId === currentUserId; + }; + + return ( + <> +
+ +
+
+
+ {first_name} + {email} +
+
+
+ c.company.id === companyId)?.role || ''} + workspaceRole={member.user.workspaces?.find(c => c.id === workspaceId)?.role || ''} + /> +
+
+ {isCurrentUser() ? ( + + leave(props.userId || '')} + /> + + ) : ( + + leave(props.userId || '')} + /> + + )} +
+ + ); +}; diff --git a/twake/frontend/src/app/components/channel-members-list/user-item.tsx b/twake/frontend/src/app/components/channel-members-list/user-item.tsx new file mode 100644 index 00000000..81982c98 --- /dev/null +++ b/twake/frontend/src/app/components/channel-members-list/user-item.tsx @@ -0,0 +1,100 @@ +import Avatar from 'app/atoms/avatar'; +import UsersService from 'app/features/users/services/current-user-service'; +import { useUser } from 'app/features/users/hooks/use-user'; +import { Button } from 'app/atoms/button/button'; +import Languages from 'app/features/global/services/languages-service'; +import { useChannelMember } from 'app/features/channel-members-search/hooks/member-hook'; +import { PlusIcon } from '@heroicons/react/solid'; +import useRouterWorkspace from 'app/features/router/hooks/use-router-workspace'; +import React from 'react'; +import { Modal, ModalContent } from 'app/atoms/modal'; +import useRouterCompany from 'app/features/router/hooks/use-router-company'; +import ConsoleService from 'app/features/console/services/console-service'; +import MemberGrade from 'app/views/client/popup/WorkspaceParameter/Pages/WorkspacePartnerTabs/MemberGrade'; + +type IUserProps = { + userId: string; +}; + +export const UserItem = (props: IUserProps): JSX.Element => { + const { userId } = props; + const user = useUser(userId || ''); + const workspaceId = useRouterWorkspace(); + const companyId = useRouterCompany(); + const [confirmWorkspaceInvitation, setConfirmWorkspaceInvitation] = + React.useState(false); + + if (!user) { + return <>; + } + + const { addMember, loading } = useChannelMember(userId || ''); + const [full_name, avatar] = [UsersService.getFullName(user), UsersService.getThumbnail(user)]; + + const _addMember = () => { + if (!(user.workspaces || []).map(w => w.id).includes(workspaceId)) { + //Ask for confirmation to invite the user to the workspace first + setConfirmWorkspaceInvitation(true); + } else { + addMember(userId || ''); + } + }; + + return ( + <> + setConfirmWorkspaceInvitation(false)}> + setConfirmWorkspaceInvitation(false)}> + {Languages.t('general.no')} + , + , + ]} + > + + +
+ +
+
+
+ {full_name} + {user.email} +
+
+
+ c.company.id === companyId)?.role || ''} + workspaceRole={user.workspaces?.find(c => c.id === workspaceId)?.role || ''} + /> +
+
+
+ + ); +}; diff --git a/twake/frontend/src/app/components/channel-members-list/users-search-modal.tsx b/twake/frontend/src/app/components/channel-members-list/users-search-modal.tsx new file mode 100644 index 00000000..7543b427 --- /dev/null +++ b/twake/frontend/src/app/components/channel-members-list/users-search-modal.tsx @@ -0,0 +1,19 @@ +import { Modal, ModalContent } from 'app/atoms/modal'; +import { useUsersSearchModal } from 'app/features/channel-members-search/state/search-channel-member'; +import Languages from 'app/features/global/services/languages-service'; +import { ChannelMembersListModal } from './channel-members-modal'; + +export default () => { + const { open, setOpen } = useUsersSearchModal(); + + return ( + setOpen(false)} className="sm:w-[80vw] sm:max-w-xl"> + + + + + ); +}; diff --git a/twake/frontend/src/app/components/channels-selector/index.tsx b/twake/frontend/src/app/components/channels-selector/index.tsx new file mode 100644 index 00000000..1e13c54c --- /dev/null +++ b/twake/frontend/src/app/components/channels-selector/index.tsx @@ -0,0 +1,164 @@ +import { SearchIcon } from '@heroicons/react/outline'; +import Avatar from 'app/atoms/avatar'; +import { InputDecorationIcon } from 'app/atoms/input/input-decoration-icon'; +import { Input } from 'app/atoms/input/input-text'; +import { Loader } from 'app/atoms/loader'; +import { Modal, ModalContent } from 'app/atoms/modal'; +import { Base, Info } from 'app/atoms/text'; +import { + useSearchChannels, + useSearchChannelsLoading, +} from 'app/features/search/hooks/use-search-channels'; +import { SearchInputState } from 'app/features/search/state/search-input'; +import Block from 'app/molecules/grouped-rows/base'; +import { useEffect, useState } from 'react'; +import PerfectScrollbar from 'react-perfect-scrollbar'; +import { atom, useRecoilState, useSetRecoilState } from 'recoil'; +import Button from '../buttons/button'; +import Emojione from '../emojione/emojione'; +import UsersService from 'app/features/users/services/current-user-service'; +import { ChannelType } from 'app/features/channels/types/channel'; +import { Checkbox } from 'app/atoms/input/input-checkbox'; +import Languages from '../../features/global/services/languages-service'; +import Icon from '../icon/icon'; + +export const SelectChannelModalAtom = atom({ + key: 'SelectChannelModalAtom', + default: false, +}); + +export const ChannelSelectorModal = (props: { + initialChannels: ChannelType[]; + onChange: (channels: ChannelType[]) => void; + lockDefaultChannels?: boolean; +}) => { + const [open, setOpen] = useRecoilState(SelectChannelModalAtom); + const [channels, setChannels] = useState([]); + + return ( + setOpen(false)}> + + { + setChannels(channels); + }} + lockDefaultChannels={props.lockDefaultChannels} + /> + + + + ); +}; + +export const ChannelSelector = (props: { + initialChannels: ChannelType[]; + onChange: (channels: ChannelType[]) => void; + lockDefaultChannels?: boolean; +}) => { + const [selectedChannels, setSelectedChannels] = useState(props.initialChannels); + const setSearch = useSetRecoilState(SearchInputState); + const { channels } = useSearchChannels(); + const loading = useSearchChannelsLoading(); + + const displayedChannels = props.lockDefaultChannels + ? [ + ...channels.filter(channel => channel.is_default), + ...channels.filter(channel => !channel.is_default), + ] + : channels; + + useEffect(() => { + props.onChange(selectedChannels); + }, [selectedChannels]); + + return ( + <> + ( +
+ +
+ ) + : SearchIcon + } + input={({ className }) => ( + setSearch({ query: e.target.value })} + /> + )} + /> + + + {displayedChannels.map(channel => { + const name = + channel.name || channel.users?.map(u => UsersService.getFullName(u)).join(', '); + + return ( + + +
+ ) + } + title={name || ''} + /> + } + title={{name}} + subtitle={ + {`${ + channel.stats?.members || channel.members?.length || 0 + } members`} + } + suffix={ +
+ {props.lockDefaultChannels && + props.initialChannels.find(({ id }) => channel.id === id) && + channel.is_default ? ( +
+ +
+ ) : ( + channel.id === id)} + onChange={() => { + if (selectedChannels.includes(channel)) { + setSelectedChannels(selectedChannels.filter(c => c.id !== channel.id)); + } else if (channel.id) { + setSelectedChannels([...selectedChannels, channel]); + } + }} + /> + )} +
+ } + className="py-2" + /> + ); + })} + + + ); +}; diff --git a/twake/frontend/src/app/components/color-picker/color-picker.jsx b/twake/frontend/src/app/components/color-picker/color-picker.jsx new file mode 100755 index 00000000..f009e468 --- /dev/null +++ b/twake/frontend/src/app/components/color-picker/color-picker.jsx @@ -0,0 +1,55 @@ +/* eslint-disable react/prop-types */ +/* eslint-disable react/jsx-key */ +import React, { Component } from 'react'; +import './color-picker.scss'; +import CheckIcon from '@material-ui/icons/CheckOutlined'; + +export default class ColorPicker extends Component { + static colors = [ + '#D50000', + '#E67C73', + '#F4511E', + '#F6BF26', + '#33B679', + '#0B8043', + '#039BE5', + '#3F51B5', + '#7986CB', + '#8E24AA', + '#801515', + '#616161', + ]; + + /* + props = { + value : default color + onChange : called when a color is selected + } + */ + constructor() { + super(); + this.colors = ColorPicker.colors; + } + render() { + var showed_selected = this.colors.indexOf(this.props.value) >= 0; + var colors = this.colors; + if (!showed_selected) { + colors = this.colors.concat([this.props.value]); + } + return ( +
+ {colors.map(color => { + return ( +
this.props.onChange(color)} + > + {this.props.value == color && } +
+ ); + })} +
+ ); + } +} diff --git a/twake/frontend/src/app/components/color-picker/color-picker.scss b/twake/frontend/src/app/components/color-picker/color-picker.scss new file mode 100755 index 00000000..b1ebae5a --- /dev/null +++ b/twake/frontend/src/app/components/color-picker/color-picker.scss @@ -0,0 +1,18 @@ +.colorPicker { + .color { + width: 16px; + height: 16px; + border-radius: var(--border-radius-large); + display: inline-block; + margin: 10px; + position: relative; + cursor: pointer; + + .m-icon-small { + color: #fff; + width: 16px; + height: 16px; + position: absolute; + } + } +} diff --git a/twake/frontend/src/app/components/company-messages-counter/company-messages-counter.scss b/twake/frontend/src/app/components/company-messages-counter/company-messages-counter.scss new file mode 100644 index 00000000..bfbe28d4 --- /dev/null +++ b/twake/frontend/src/app/components/company-messages-counter/company-messages-counter.scss @@ -0,0 +1,11 @@ +.companyMessagesCounter { + margin-right: 8px; + + .info { + font-weight: 400; + opacity: 0.5; + } + .link { + margin-top: 4px; + } +} diff --git a/twake/frontend/src/app/components/company-messages-counter/company-messages-counter.tsx b/twake/frontend/src/app/components/company-messages-counter/company-messages-counter.tsx new file mode 100644 index 00000000..51346ddf --- /dev/null +++ b/twake/frontend/src/app/components/company-messages-counter/company-messages-counter.tsx @@ -0,0 +1,71 @@ +import React, { useEffect, useState } from 'react'; +import { Col, Progress, Row, Typography } from 'antd'; +import './company-messages-counter.scss'; +import i18n from 'i18next'; + +import Languages from 'app/features/global/services/languages-service'; +import { useCurrentCompany } from 'app/features/companies/hooks/use-companies'; +import FeatureTogglesService, { + FeatureNames, +} from 'app/features/global/services/feature-toggles-service'; +import MessageHistoryService from 'app/features/messages/services/message-history-service'; +import consoleService from 'app/features/console/services/console-service'; + +const { Text, Title, Link } = Typography; +const CompanyMessagesCounter = () => { + const [messagesCount, setMessagesCount] = useState(1); + const companyMessagesLimit = MessageHistoryService.getLimitCompanyMessages(); + + const { company } = useCurrentCompany(); + + const companySubscriptionUrl = consoleService.getCompanySubscriptionUrl(company.id); + + const onClickLink = () => window.open(companySubscriptionUrl, 'blank'); + + useEffect(() => { + if (company) { + setMessagesCount(company.stats?.total_messages || 1); + } + }, [company]); + + return !FeatureTogglesService.isActiveFeatureName(FeatureNames.MESSAGE_HISTORY) ? ( + <> + + + + {Languages.t('scenes.app.channelsbar.currentuser.company_messages_counter_header', [])} + + + {Languages.t('scenes.app.channelsbar.currentuser.company_messages_counter_info', [ + Intl.NumberFormat(i18n.language).format(companyMessagesLimit), + ])} + +
+ + {Languages.t('scenes.app.channelsbar.currentuser.company_messages_counter_link', [])} + +
+ + + (messagesCount / 1000).toFixed(1) + 'k'} + percent={(messagesCount / companyMessagesLimit) * 100} + width={55} + /> + +
+ + ) : ( + <> + ); +}; +export default CompanyMessagesCounter; diff --git a/twake/frontend/src/app/components/components-tester/component-doc.jsx b/twake/frontend/src/app/components/components-tester/component-doc.jsx new file mode 100755 index 00000000..985c48f0 --- /dev/null +++ b/twake/frontend/src/app/components/components-tester/component-doc.jsx @@ -0,0 +1,59 @@ +/* eslint-disable react/jsx-key */ +import React, { Component } from 'react'; +import InputWithClipBoard from 'components/input-with-clip-board/input-with-clip-board.jsx'; +import './component-doc.scss'; + +export default class ComponentDoc extends React.Component { + constructor() { + super(); + } + render() { + return ( +
+
+ {this.props.title &&
{this.props.title}
} + {this.props.import && ( + + )} +
+
{this.props.children}
+
+ {this.props.properties && [ +
Properties
, + + + + + + + + + + {this.props.properties.map(property => { + return ( + + + + + + + ); + })} +
PropertyTypeDefaultDescription
{property[0]} + {property[1].split(',').map(item => ( + {item} + ))} + {property[2]}{property[3]}
, +
, +
, + ]} + + {this.props.infos && [ +
Infos
, +
{this.props.infos}
, + ]} +
+
+ ); + } +} diff --git a/twake/frontend/src/app/components/components-tester/component-doc.scss b/twake/frontend/src/app/components/components-tester/component-doc.scss new file mode 100755 index 00000000..1fc53cbe --- /dev/null +++ b/twake/frontend/src/app/components/components-tester/component-doc.scss @@ -0,0 +1,50 @@ +.component_doc { + background: var(--grey-background); + padding: 25px; + max-height: 100vh; + overflow: scroll; + box-sizing: border-box; + + .section { + background: var(--white); + max-width: 900px; + margin: auto; + left: 0; + right: 0; + padding: 25px; + box-sizing: border-box; + border-radius: var(--border-radius-base); + margin-top: 25px; + } + + .header { + input { + background: var(--black); + color: #fff; + font-family: monospace; + } + } + + .subtitle { + font-weight: 700; + } + + .properties { + border-collapse: collapse; + width: 100%; + + thead { + font-weight: 700; + } + + td { + border: 1px solid var(--grey-background); + padding: 8px; + } + .type { + background: var(--grey-background); + padding: 2px 4px; + border-radius: var(--border-radius-base); + } + } +} diff --git a/twake/frontend/src/app/components/components-tester/components-tester.jsx b/twake/frontend/src/app/components/components-tester/components-tester.jsx new file mode 100755 index 00000000..d93b1901 --- /dev/null +++ b/twake/frontend/src/app/components/components-tester/components-tester.jsx @@ -0,0 +1,370 @@ +/* eslint-disable react/jsx-key */ +import React, { Component } from 'react'; +import Emojione from 'components/emojione/emojione'; +import Icon from 'app/components/icon/icon.jsx'; +import Menu from 'components/menus/menu.jsx'; +import MenusBodyLayer from 'app/components/menus/menus-body-layer.jsx'; +import AutoComplete from 'components/auto-complete/auto-complete'; +import UserPicker from 'components/user-picker/user-picker.jsx'; +import EmojiPicker from 'components/emoji-picker/emoji-picker.jsx'; + +import Directory from 'components/drive/directory.jsx'; +import File from 'components/drive/file'; +import DriveMultiSelector from 'components/drive/drive-multi-selector.jsx'; + +import Rounded from 'components/inputs/rounded.jsx'; + +import DraggableBodyLayer from 'components/draggable/draggable-body-layer.jsx'; + +import emojiService from 'app/components/rich-text-editor/emojis-service.jsx'; +import User from 'components/ui/user.jsx'; + +import AutoHeight from 'components/auto-height/auto-height.jsx'; +import Tooltip from 'components/tooltip/tooltip.jsx'; +import InputWithClipBoard from 'components/input-with-clip-board/input-with-clip-board.jsx'; + +import './components-tester.scss'; +import GroupInputs from './group/inputs.js'; + +export default class ComponentsTester extends React.Component { + constructor() { + super(); + this.state = { + autocompValue: '', + visible: false, + }; + } + render() { + return [ +
+
+
Test des composants
+
ctrl+alt+e pour revenir Γ  Twake
+
+ + + +
+
Icones
+ +
+ Title +
+
+ Sub title +
+
+ Text +
+
+ +
+
Emojione
+
+ Title +
+
+ Subtitle +
+
+ Text +
+
+
+
Tooltip
+
+ (this.tooltip = o)} + tooltip={'toolltiiiiiiiiip'} + position={'top'} + overable={false} + > +
this is my tooltip top
+
+
+ +
+ +
this is my tooltip top
+
+
+
+ +
+
Input with clipboard
+
+ +
+
+ +
+
Menus
+ + salut
, + }, + ], + }, + { type: 'separator' }, + { type: 'text', text: 'Du texte' }, + ]} + > + Click here ! + +
+
+
Auto complete one line
+ { + cb( + [ + { + id: 1, + username: 'benoit', + mail: 'benoit.tallandier@g.a', + userimage: 'https://randomuser.me/api/portraits/men/40.jpg', + }, + { + id: 2, + username: 'romaric', + mail: 'romaric.mourgues@g.a', + userimage: 'https://randomuser.me/api/portraits/men/41.jpg', + }, + { + id: 3, + username: 'guillaume', + mail: 'romaric.mourgues@g.a', + userimage: 'https://randomuser.me/api/portraits/men/42.jpg', + }, + { + id: 4, + username: 'Amandine', + mail: 'romaric.mourgues@g.a', + userimage: 'https://randomuser.me/api/portraits/women/40.jpg', + }, + ].filter(function (item) { + if (item && item.username.indexOf(text) !== -1) { + return true; + } + return false; + }), + ); + }, + (text, cb) => { + cb(emojiService.search(text)); + }, + ]} + max={[5, 5]} + renderItemChoosen={[ + item => { + return '@' + (item || {}).username + ' '; + }, + item => { + return item.shortname + ' '; + }, + ]} + renderItem={[ + item => { + return ( +
+ +
+ ); + }, + item => { + return ( +
+ {item.shortname} +
+ ); + }, + ]} + regexHooked={[/\B@([\-+\w]*)$/, /\B:([\-+\w]{0}[\-+\w]*)$/]} + placeholder="Placeholder" + autoHeight + /> +
+
+
Multi-line input
+ + +
+
+
Users picker
+
In menu
+ this.setState({ users_picker_value: list })} + /> + ), + }, + ]} + > +
Open menu
+
+ +
+
+
Inline
+ + this.setState({ users_picker_value: list })} + inline + /> + +
+
Inline read only
+ + + +
+
Inline read only miniatures
+ + +
+
+
Emoji picker
+ }]}> + Click here ! + +
+ +
+ + +
Drive
+ +
+ TODO: Tester drag drop depuis ordinateur +
+ TODO: Faire apparaitre l'icone "drag + menu" au survol +
+ + +
+
Dossiers
+ + + + + + + + + +
+
+ +
Fichiers
+ + + + + + + + + +
+
+
+
, + , + , + ]; + } +} diff --git a/twake/frontend/src/app/components/components-tester/components-tester.scss b/twake/frontend/src/app/components/components-tester/components-tester.scss new file mode 100755 index 00000000..3f42f35e --- /dev/null +++ b/twake/frontend/src/app/components/components-tester/components-tester.scss @@ -0,0 +1,19 @@ +.componentTester { + background: #f5f5f7; + padding: 25px; + max-height: 100vh; + overflow: scroll; + box-sizing: border-box; + + .section { + background: #fff; + max-width: 900px; + margin: auto; + left: 0; + right: 0; + padding: 25px; + box-sizing: border-box; + border-radius: var(--border-radius-base); + margin-top: 25px; + } +} diff --git a/twake/frontend/src/app/components/components-tester/group/inputs.jsx b/twake/frontend/src/app/components/components-tester/group/inputs.jsx new file mode 100755 index 00000000..040d872c --- /dev/null +++ b/twake/frontend/src/app/components/components-tester/group/inputs.jsx @@ -0,0 +1,124 @@ +/* eslint-disable react/jsx-key */ +import React, { Component } from 'react'; + +import Checkbox from 'app/components/inputs/deprecated_checkbox.jsx'; +import Switch from 'components/inputs/switch'; +import Button from 'components/buttons/button.jsx'; +import Input from 'components/inputs/input.jsx'; + +import StepCounter from 'components/step-counter/step-counter.jsx'; +import Languages from 'app/features/global/services/languages-service'; +import { lang } from 'moment'; + +export default class GroupInputs extends React.Component { + constructor() { + super(); + this.state = { + input: 'Example', + }; + } + render() { + return [ +
+
Formulaires
+ +
className="big"
+ this.setState({ input: evt.target.value })} + /> +
+ this.setState({ input: value })} + /> +
+ this.setState({ input: value })} + /> +
+ +
className="medium"
+ this.setState({ input: evt.target.value })} + /> +
+ this.setState({ input: value })} + /> +
+ this.setState({ input: value })} + /> +
+ +
className="small"
+ this.setState({ input: evt.target.value })} + /> +
+ this.setState({ input: value })} + /> +
+ this.setState({ input: value })} + /> +
+
, +
+
+ +
Create my company 3/4
+
+ {Languages.t( + 'scenes.app.workspaces.create_company.importations.title_1', + [], + 'Already working with digital tools? Import or integrate your tools now!', + )} +
+ {Languages.t( + 'scenes.app.workspaces.create_company.importations.title_2', + [], + 'No worries, you can do this later!', + )} +
+ +
+
+
What's your company name ?
+ this.setState({ company_name: evt.target.value })} + placeholder="Ex : Google, Aircall, Doctolib" + /> +
+
+ +
+
+
+
, + ]; + } +} diff --git a/twake/frontend/src/app/components/configurators/config-body-layer.jsx b/twake/frontend/src/app/components/configurators/config-body-layer.jsx new file mode 100755 index 00000000..1dbf53d6 --- /dev/null +++ b/twake/frontend/src/app/components/configurators/config-body-layer.jsx @@ -0,0 +1,119 @@ +import React from 'react'; + +import ConfiguratorsManager from 'app/deprecated/Configurators/ConfiguratorsManager.js'; +import WorkspacesApps from 'app/deprecated/workspaces/workspaces_apps.jsx'; +import CloseIcon from '@material-ui/icons/CloseOutlined'; +import './configurators.scss'; +import Blocks from '../../views/applications/messages/message/parts/Blocks'; + +/* + Where the configurators will be displayed, this component should be in app.js (menus should be over all elements of the page) +*/ +export default class ConfigBodyLayer extends React.Component { + constructor() { + super(); + this.state = {}; + ConfiguratorsManager.addListener(this); + } + componentWillUnmount() { + ConfiguratorsManager.removeListener(this); + clearTimeout(this.loading_interaction_timeout); + } + UNSAFE_componentWillMount() { + this.generateData(); + } + shouldComponentUpdate(nextProps, nextState) { + this.generateData(); + var string = JSON.stringify(this.configurator); + if (string != this.saved) { + nextState.loading_interaction = false; + clearTimeout(this.loading_interaction_timeout); + this.saved = string; + return true; + } + return nextState.loading_interaction ? true : false; + } + generateData() { + if (ConfiguratorsManager.configurator_order.length == 0) { + this.configurator = null; + } + this.configurator = + ConfiguratorsManager.currentConfigurators[ + ConfiguratorsManager.configurator_order[ConfiguratorsManager.configurator_order.length - 1] + ]; + } + onAction(type, id, context, passives) { + if (type == 'interactive_action') { + this.setState({ loading_interaction: true }); + clearTimeout(this.loading_interaction_timeout); + this.loading_interaction_timeout = setTimeout(() => { + this.setState({ loading_interaction: false }); + }, 5000); + var app_id = this.configurator.app.id; + var ntype = 'interactive_configuration_action'; + var event = id; + var data = { + interactive_context: context, + form: passives, + hidden_data: this.configurator.hidden_data, + configurator_id: this.configurator.id, + }; + WorkspacesApps.notifyApp(app_id, ntype, event, data); + } + } + render() { + if (!this.configurator) { + return ''; + } + + return ( +
+
+
+
+
+
+
{this.configurator.app.identity?.name}
+ + { + ConfiguratorsManager.closeConfigurator(this.configurator.app); + }} + /> +
+
+ + this.onAction(type, id, context, passives, evt) + } + allowAdvancedBlocks={true} + /> +
+
+
+
+
+ ); + } +} diff --git a/twake/frontend/src/app/components/configurators/configurators.scss b/twake/frontend/src/app/components/configurators/configurators.scss new file mode 100755 index 00000000..df002a59 --- /dev/null +++ b/twake/frontend/src/app/components/configurators/configurators.scss @@ -0,0 +1,60 @@ +.config_modal { + height: 100%; + width: 100%; + background: rgba(255, 255, 255, 0.5); + position: absolute; + z-index: 200; + top: 0; + + .modal { + width: 0px; + height: 0px; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + margin: auto; + .component { + background: white; + border-radius: var(--border-radius-base); + box-shadow: var(--box-shadow-base); + position: relative; + display: inline-flex; + flex-direction: column; + transform: translateX(-50%) translateY(-50%); + .header { + padding: 15px; + border-bottom: 1px solid #ddd; + display: flex; + + .app_logo { + height: 30px; + width: 30px; + background-size: contain; + background-position: center; + border-radius: var(--border-radius-base); + margin-right: 5px; + } + .app_name { + line-height: 30px; + flex: auto; + } + .close { + margin: 2px; + opacity: 0.5; + cursor: pointer; + &:hover { + opacity: 1; + } + } + } + .content { + flex: 1; + overflow: auto; + padding: 15px; + box-sizing: border-box; + } + } + } +} diff --git a/twake/frontend/src/app/components/connection-indicator/connection-indicator.scss b/twake/frontend/src/app/components/connection-indicator/connection-indicator.scss new file mode 100644 index 00000000..e2ce840a --- /dev/null +++ b/twake/frontend/src/app/components/connection-indicator/connection-indicator.scss @@ -0,0 +1,31 @@ +.connection_indicator { + position: absolute; + box-shadow: 0 0 4px 4px rgba(0, 0, 0, 0.1); + padding: 8px; + bottom: 16px; + left: 16px; + background: var(--secondary); + color: var(--white); + font-size: 12px; + border-radius: var(--border-radius-base); + pointer-events: none; + opacity: 0; + transition: opacity 1s; + transition-delay: 2s; + + span, + svg { + line-height: 14px; + vertical-align: middle; + } + + svg { + width: 12px; + height: 12px; + } + + &.visible { + opacity: 1; + transition: opacity 0.2s; + } +} diff --git a/twake/frontend/src/app/components/connection-indicator/connection-indicator.tsx b/twake/frontend/src/app/components/connection-indicator/connection-indicator.tsx new file mode 100644 index 00000000..22d0c911 --- /dev/null +++ b/twake/frontend/src/app/components/connection-indicator/connection-indicator.tsx @@ -0,0 +1,42 @@ +import React, { useEffect } from 'react'; +import './connection-indicator.scss'; +import ErrorOutlinedIcon from '@material-ui/icons/ErrorOutlined'; +import HourglassEmpty from '@material-ui/icons/HourglassEmpty'; +import CheckCircleIcon from '@material-ui/icons/CheckCircle'; +import Languages from 'app/features/global/services/languages-service'; +import { ConnectedState } from 'app/features/users/state/atoms/connected'; +import { useRecoilState } from 'recoil'; +import WebSocket, { WebsocketEvents } from 'app/features/global/types/websocket-types'; + +export default () => { + const [{ connected, reconnecting }, setState] = useRecoilState(ConnectedState); + + useEffect(() => { + WebSocket.get().on(WebsocketEvents.Disconnected, () => { + setState({ connected: false, reconnecting: false }); + }); + WebSocket.get().on(WebsocketEvents.Connected, () => { + setState({ connected: true, reconnecting: false }); + }); + }, [setState]); + + return ( +
+ {connected === false && reconnecting !== true && ( +
+ {Languages.t('general.connexion_status.disconnected')} +
+ )} + {connected === false && reconnecting === true && ( +
+ {Languages.t('general.connexion_status.connecting')} +
+ )} + {connected === true && ( +
+ {Languages.t('general.connexion_status.connected')} +
+ )} +
+ ); +}; diff --git a/twake/frontend/src/app/components/connectors-list-manager/connectors-list-manager.jsx b/twake/frontend/src/app/components/connectors-list-manager/connectors-list-manager.jsx new file mode 100755 index 00000000..f62f1160 --- /dev/null +++ b/twake/frontend/src/app/components/connectors-list-manager/connectors-list-manager.jsx @@ -0,0 +1,139 @@ +/* eslint-disable react/prop-types */ +/* eslint-disable react/no-direct-mutation-state */ +import React, { Component } from 'react'; +import CloseIcon from '@material-ui/icons/CloseOutlined'; +import AddIcon from '@material-ui/icons/AddOutlined'; +import GearIcon from '@material-ui/icons/BuildOutlined'; +import Input from 'components/inputs/input.jsx'; +import './connectors-list-manager.scss'; +import Languages from 'app/features/global/services/languages-service'; +import WorkspacesApps from 'app/deprecated/workspaces/workspaces_apps.jsx'; +import { getCompanyApplication as getApplication } from 'app/features/applications/state/company-applications'; + +export default class ConnectorsListManager extends Component { + constructor(props) { + super(); + this.props = props; + this.state = { + connectors_ids: props.current.map(item => item.id || ''), + filtered: [], + input: '', + }; + } + filter(text) { + this.state.input = text; + var list = this.props.list; + var res = list + .filter(el => { + return el.identity.name.toLocaleLowerCase().indexOf(text.toLocaleLowerCase()) >= 0; + }) + .map(el => el); + this.setState({ filtered: res }); + } + componentDidMount() { + this.filter(''); + } + + renderLine(item, added) { + var id = item.id || item; + + item = getApplication(id); + + var text = ''; + var button = ''; + + text = ( +
+ {WorkspacesApps.getAppIconComponent(item)} + {item.identity.name} +
+ ); + + if (added) { + button = ( +
+ { + this.props.onConfig(item); + }} + /> + { + this.state.connectors_ids = this.state.connectors_ids.filter(id => + typeof item == 'string' ? item != id : item.id != id, + ); + this.setState({}); + this.props.onChange(this.state.connectors_ids); + }} + /> +
+ ); + } else { + button = ( +
+ { + this.state.connectors_ids.push(item.id || this.state.input.toLocaleLowerCase()); + this.setState({ input: '' }); + this.props.onChange(this.state.connectors_ids); + }} + /> +
+ ); + } + + return ( +
+ {text} + {button} +
+ ); + } + render() { + return ( +
+
+
+ {Languages.t('scenes.apps.tasks.connectors_menu', [], 'Connecteurs')} +
+
+ + {this.state.connectors_ids.length == 0 && ( +
+ {Languages.t('scenes.apps.tasks.no_connector', [], 'Aucun connecteurs.')} +
+ )} + {this.state.connectors_ids.map(id => { + return this.renderLine(id, true); + })} +
+
+ {Languages.t('components.connectorslistmanager.add_connectors')} +
+
+ +
+
+ this.filter(evt.target.value)} + /> +
+
+ + {this.state.filtered.slice(0, 5).map(item => { + if (this.state.connectors_ids.indexOf(item.id) >= 0) { + return ''; + } + return this.renderLine(item, false); + })} +
+ ); + } +} diff --git a/twake/frontend/src/app/components/connectors-list-manager/connectors-list-manager.scss b/twake/frontend/src/app/components/connectors-list-manager/connectors-list-manager.scss new file mode 100755 index 00000000..9046fa62 --- /dev/null +++ b/twake/frontend/src/app/components/connectors-list-manager/connectors-list-manager.scss @@ -0,0 +1,49 @@ +.connectorsListManager { + margin: 0px -16px; + margin-top: -8px; + + .menu-app-icon { + width: 18px; + height: 18px; + display: inline-block; + background-position: center; + background-size: contain; + border-radius: var(--border-radius-base); + vertical-align: middle; + margin-right: 8px; + } + + .emoji-container { + margin-right: 5px; + top: 1px; + position: relative; + } + + .menu-buttons { + padding: 0px 8px; + margin: 0px 8px; + } + + .more { + width: auto !important; + margin-right: -5px; + + .m-icon-small { + margin: 3px; + } + + &:hover { + .m-icon-small { + &.remove:hover { + color: var(--red); + } + &.config:hover { + color: var(--primary); + } + &.add { + color: var(--primary); + } + } + } + } +} diff --git a/twake/frontend/src/app/components/debug/debug-state.tsx b/twake/frontend/src/app/components/debug/debug-state.tsx new file mode 100644 index 00000000..45a66d8a --- /dev/null +++ b/twake/frontend/src/app/components/debug/debug-state.tsx @@ -0,0 +1,94 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React from 'react'; +import { useRecoilCallback } from 'recoil'; + +interface TwakeDebugState { + dumpStateSnapshot?(): void; + get?(key: string): void; + getAllAtoms?(): void; +} + +const twakeDebugState: TwakeDebugState = {}; + +const useDebugRecoilState = () => { + /** + * Get the value of an atom by key + * + * @param {string} key - The key of the atom + * @returns {void} + */ + twakeDebugState.get = useRecoilCallback( + ({ snapshot }) => + async (key: string) => { + const allNodes = Array.from(snapshot.getNodes_UNSTABLE()); + const node = allNodes.find(node => node.key === key); + + if (node) { + console.debug(key, await snapshot.getPromise(node)); + } + }, + [], + ); + + /** + * Dump the current state of the application to a json file + * + * @returns {void} + */ + twakeDebugState.dumpStateSnapshot = useRecoilCallback( + ({ snapshot }) => + async () => { + const result: Record = { + localStorage: {}, + }; + + for (const node of snapshot.getNodes_UNSTABLE()) { + const value = await snapshot.getPromise(node); + + result[node.key] = value; + } + + for (const key of Object.keys(window.localStorage)) { + result.localStorage[key] = window.localStorage.getItem(key); + } + + const json = JSON.stringify(result, null, 2); + const blob = new Blob([json], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + + link.href = url; + link.download = `twake-state-${new Date().toISOString()}.json`; + + link.click(); + URL.revokeObjectURL(url); + }, + [], + ); + + /** + * lists the value of all atoms + * + * @returns {void} + */ + twakeDebugState.getAllAtoms = useRecoilCallback( + ({ snapshot }) => + async () => { + for (const node of snapshot.getNodes_UNSTABLE()) { + const value = await snapshot.getPromise(node); + + console.debug(node.key, value); + } + }, + [], + ); + + (window as any).twakeDebugState = twakeDebugState; +}; + + +export default (): React.ReactElement => { + useDebugRecoilState(); + + return <>; +}; diff --git a/twake/frontend/src/app/components/download-app-banner/download-app-banner.tsx b/twake/frontend/src/app/components/download-app-banner/download-app-banner.tsx new file mode 100644 index 00000000..11c13d2f --- /dev/null +++ b/twake/frontend/src/app/components/download-app-banner/download-app-banner.tsx @@ -0,0 +1,39 @@ +import React, { useEffect, useState } from 'react'; +import InitService from '../../features/global/services/init-service'; +import LocalStorage from '../../features/global/framework/local-storage-service'; +import DownloadBanner from 'app/molecules/download-banner'; +import { detectDesktopAppPresence } from '../../../utils/browser-detect'; + +export default (): React.ReactElement => { + const [showBanner, setShowBanner] = useState(false); + + const download = (): void => { + const appDownloadUrl = InitService?.server_infos?.configuration?.app_download_url; + + if (appDownloadUrl) { + window.open(appDownloadUrl, '_blank'); + } + }; + + const removeBanner = (): void => { + LocalStorage.setItem('show_app_banner', 'false'); + setShowBanner(false); + }; + + useEffect(() => { + if (LocalStorage.getItem('show_app_banner') === 'false') { + setShowBanner(false); + return; + } + + detectDesktopAppPresence().then(detected => { + if (!detected && LocalStorage.getItem('show_app_banner') === null) { + setShowBanner(true); + } else { + LocalStorage.setItem('show_app_banner', 'false'); + } + }); + }, []); + + return showBanner ? : <>; +}; diff --git a/twake/frontend/src/app/components/draggable/draggable-body-layer.jsx b/twake/frontend/src/app/components/draggable/draggable-body-layer.jsx new file mode 100755 index 00000000..d37734c9 --- /dev/null +++ b/twake/frontend/src/app/components/draggable/draggable-body-layer.jsx @@ -0,0 +1,23 @@ +import React, { Component } from 'react'; + +import DraggableManager from './draggable-manager.js'; + +export default class DraggableBodyLayer extends Component { + constructor() { + super(); + this.state = { + draggable_manager: DraggableManager, + }; + this.draggable_body_dom = null; + DraggableManager.addListener(this); + } + componentDidMount() { + DraggableManager.registerContainer(this.draggable_body_dom); + } + componentWillUnmount() { + DraggableManager.removeListener(this); + } + render() { + return
(this.draggable_body_dom = node)} />; + } +} diff --git a/twake/frontend/src/app/components/draggable/draggable-manager.js b/twake/frontend/src/app/components/draggable/draggable-manager.js new file mode 100755 index 00000000..9af86534 --- /dev/null +++ b/twake/frontend/src/app/components/draggable/draggable-manager.js @@ -0,0 +1,238 @@ +import React, { Component } from 'react'; + +import Observable from 'app/deprecated/CollectionsV1/observable.js'; +import SelectionsManager from 'app/deprecated/SelectionsManager/SelectionsManager.js'; + +class DraggableManager extends Observable { + constructor() { + super(); + this.setObservableName('draggable_manager'); + this.container = null; + + this.move = this.move.bind(this); + this.end = this.end.bind(this); + this.start = this.start.bind(this); + + this.drag = false; + this.clone_created = false; + this.drag_initial_point = []; + this.current_node_initial_position = []; + } + + registerContainer(container) { + this.container = container; + } + + setDropCallback(key, callback) { + this.callback_key = key; + this.callback = callback; + } + + removeDropCallback(key) { + if (this.callback_key == key) { + this.callback = false; + this.callback_key = null; + } + } + + start(evt, node, react_draggable) { + if (this.dragging) { + return; + } + + if (react_draggable.props.dragHandler) { + var onHandler = false; + var handlers = node.getElementsByClassName(react_draggable.props.dragHandler); + if (handlers.length > 0) { + Array.from(handlers).forEach(item => { + if (item == evt.target || item.contains(evt.target)) { + onHandler = true; + } + }); + } + + if (!onHandler) { + return; + } + } + + this.data = {}; + if (node) { + this.current_node = node; + } + if (react_draggable) { + this.current_react_draggable = react_draggable; + this.props = { + parentClassOnDrag: this.current_react_draggable.props.parentClassOnDrag, + minMove: this.current_react_draggable.props.minMove, + }; + this.data = this.current_react_draggable.props.data; + } + + this.selected_number = 1; + if (this.data.selection_type) { + this.selected_number = SelectionsManager.selected_per_type[this.data.selection_type]; + if (this.selected_number) { + this.selected_number = Object.keys(this.selected_number).length; + } + + if (!this.selected_number) { + this.selected_number = 1; + } + } + + evt.stopPropagation(); + evt.preventDefault(); + + document.addEventListener('mousemove', this.move); + document.addEventListener('mouseup', this.end); + var rect = window.getBoundingClientRect(this.current_node); + rect.x = rect.x || rect.left; + rect.y = rect.y || rect.top; + + this.clone_created = false; + this.drag_initial_point = [evt.clientX, evt.clientY]; + this.current_node_initial_position = [rect.left, rect.top, node.clientWidth, node.clientHeight]; + + this.drag = true; + if (this.current_react_draggable) this.current_react_draggable.setState({ drag: true }); + } + end(evt, node, react_draggable) { + if (this.dragging) { + evt.preventDefault(); + evt.stopPropagation(); + } + + this.current_react_draggable && this.current_react_draggable.setState({ hide_original: false }); + + if (!this.data) { + return; + } + + if (node) { + this.current_node = node; + } + if (react_draggable) { + this.current_react_draggable = react_draggable; + this.props = { + parentClassOnDrag: this.current_react_draggable.props.parentClassOnDrag, + minMove: this.current_react_draggable.props.minMove, + }; + } + + document.removeEventListener('mousemove', this.move); + document.removeEventListener('mouseup', this.end); + + document.body.classList.remove('dragging'); + document.body.classList.remove('drag_' + this.data.type); + this.drag = false; + this.dragging = false; + if (this.current_react_draggable) + this.current_react_draggable.setState({ drag: false, dragging: false }); + + var delete_delay = 0; + if (this.callback) { + this.callback(this.data); + } else { + if (this.clone) { + this.clone.style.transition = 'transform 0.2s'; + this.clone.style.transform = + 'translateX(' + + this.current_node_initial_position[0] + + 'px) translateY(' + + this.current_node_initial_position[1] + + 'px)'; + } + delete_delay = 200; + } + + setTimeout(() => { + if (this.clone) { + try { + this.container.removeChild(this.clone); + } catch (e) {} + } + if (this.current_react_draggable) + this.current_react_draggable.setState({ hide_original: false }); + if (this.props.parentClassOnDrag) { + this.props.parentClassOnDrag.split(' ').forEach(c => { + this.container.classList.remove(c); + }); + } + }, delete_delay); + + this.data = {}; + } + move(evt) { + if (!this.data) { + return; + } + + var deltaX = evt.clientX - this.drag_initial_point[0]; + var deltaY = evt.clientY - this.drag_initial_point[1]; + + if ( + !this.clone_created && + Math.max(Math.abs(deltaX), Math.abs(deltaY)) < (this.props.minMove || 10) + ) { + return; + } + + if (this.drag) { + if (!this.clone_created) { + var html = this.current_node.outerHTML; + var div = document.createElement('div'); + div.classList.add('draggable_clone'); + div.innerHTML = html.trim(); + div.firstChild.classList.remove('dragging_opacity'); + div.firstChild.classList.remove('fade_in'); + div.firstChild.classList.remove('is_selected'); + + div.style.width = this.current_node_initial_position[2] + 'px'; + div.style.height = this.current_node_initial_position[3] + 'px'; + + this.clone = div; + + if (this.selected_number > 1) { + var div_number = document.createElement('div'); + div_number.classList.add('draggable_number'); + div_number.innerHTML = this.selected_number; + this.clone.appendChild(div_number); + } + + this.container.appendChild(this.clone); + this.clone_created = true; + + if (this.props.parentClassOnDrag) { + this.props.parentClassOnDrag.split(' ').forEach(c => { + this.container.classList.add(c); + }); + } + + if ( + this.current_react_draggable && + this.current_react_draggable.props && + this.current_react_draggable.props.onDragStart + ) { + this.current_react_draggable.props.onDragStart(evt); + } + + this.dragging = true; + if (this.current_react_draggable) + this.current_react_draggable.setState({ dragging: true, hide_original: true }); + } + + document.body.classList.add('dragging'); + document.body.classList.add('drag_' + this.data.type); + this.clone.style.transform = + 'translateX(' + + (deltaX + this.current_node_initial_position[0]) + + 'px) translateY(' + + (deltaY + this.current_node_initial_position[1]) + + 'px)'; + } + } +} + +const service = new DraggableManager(); +export default service; diff --git a/twake/frontend/src/app/components/draggable/draggable.scss b/twake/frontend/src/app/components/draggable/draggable.scss new file mode 100755 index 00000000..77d2d039 --- /dev/null +++ b/twake/frontend/src/app/components/draggable/draggable.scss @@ -0,0 +1,87 @@ +.draggable { + .js-drag-handler { + cursor: grab; + width: 100%; + min-height: 16px; + } +} + +.dragging { + cursor: grabbing !important; +} + +.draggable_clone { + position: absolute; + z-index: 1000; + left: 0px; + top: 0px; + pointer-events: none; + + & > * { + opacity: 0.5; + } + + .draggable_number { + opacity: 1; + position: absolute; + right: -10px; + bottom: -10px; + background: #fff; + color: var(--primary); + font-size: 16px; + width: 40px; + height: 40px; + text-align: center; + line-height: 40px; + border-radius: 50%; + box-shadow: var(--box-shadow-base); + } +} + +.dragging_opacity { + //opacity: 0.5; +} + +.droppable_zone { + background: #f2f2f200; + margin: 0px; + border-radius: var(--border-radius-base); + transition: margin 0.2s, border 0.2s; + border: 0px dashed #ffffff00; + + .empty { + border-radius: var(--border-radius-base); + background: #ffffff; + padding: 0px; + text-align: center; + color: #00000088; + margin: 0px; + opacity: 0; + overflow: hidden; + max-height: 0px; + transition: margin 0.2s, opacity 0.2s, height 0.2s, padding 0.2s, max-height 0.2s; + } +} + +.dragging.drag_channel .droppable_zone.for_channel, +.dragging.drag_message .droppable_zone.for_message { + border: 2px dashed #f2f2f2; + margin: 10px 0px; + + .empty { + padding: 10px; + opacity: 1; + max-height: 40px; + .m-icon-small { + vertical-align: bottom; + } + } + + &:hover { + border: 2px dashed #eaeaea; + background: #f2f2f2; + .empty { + background: #f2f2f2; + } + } +} diff --git a/twake/frontend/src/app/components/draggable/draggable.tsx b/twake/frontend/src/app/components/draggable/draggable.tsx new file mode 100755 index 00000000..9bf5234e --- /dev/null +++ b/twake/frontend/src/app/components/draggable/draggable.tsx @@ -0,0 +1,44 @@ +/* eslint-disable react/prop-types */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +// eslint-disable-next-line @typescript-eslint/no-use-before-define +import React from 'react'; +import './draggable.scss'; +import DraggableManager from './draggable-manager.js'; +import classNames from 'classnames'; + +type PropsType = { [key: string]: any }; + +type StateType = { [key: string]: any }; + +export default class Draggable extends React.Component { + node: HTMLDivElement | null | undefined; + + render() { + return ( +
{ + this.node = node; + if (this.props.refDraggable) { + this.props.refDraggable(node); + } + }} + onClick={this.props.onClick} + onMouseDown={evt => { + !this.props?.deactivated && DraggableManager.start(evt, this.node, this); + }} + onMouseUp={evt => { + !this.props?.deactivated && DraggableManager.end(evt, this.node, this); + }} + onMouseOver={this.props.onMouseOver} + onMouseOut={this.props.onMouseOut} + onDoubleClick={this.props.onDoubleClick} + > + {this.props.children} +
+ ); + } +} diff --git a/twake/frontend/src/app/components/draggable/droppable-zone.jsx b/twake/frontend/src/app/components/draggable/droppable-zone.jsx new file mode 100755 index 00000000..a80b8b05 --- /dev/null +++ b/twake/frontend/src/app/components/draggable/droppable-zone.jsx @@ -0,0 +1,74 @@ +/* eslint-disable react/prop-types */ +import React, { Component } from 'react'; + +import DraggableManager from './draggable-manager.js'; +import Number from 'app/features/global/utils/Numbers'; +import './draggable.scss'; + +export default class DroppableZone extends Component { + constructor() { + super(); + this.unique_drop_key = Number.unid(); + this.longOverTimeout = ''; + } + onDrop(data) { + if (!data) { + return; + } + if (this.props.types && data.type) { + if (this.props.types.indexOf(data.type) < 0) { + return; + } + } + if (this.props.onDrop) { + this.props.onDrop(data); + } + } + componentWillUnmount() { + DraggableManager.removeDropCallback(this.unique_drop_key); + clearTimeout(this.longOverTimeout); + } + onEnter() { + if (DraggableManager.drag) { + this.longOverTimeout = setTimeout(() => { + if (DraggableManager.drag) { + if (this.props.onClick && !this.props.disableLongOver) { + this.props.onClick(); + } + if (this.props.onLongOver) { + this.props.onLongOver(); + } + } + }, 1500); + DraggableManager.setDropCallback(this.unique_drop_key, d => this.onDrop(d)); + } + } + onLeave() { + DraggableManager.removeDropCallback(this.unique_drop_key); + clearTimeout(this.longOverTimeout); + } + render() { + return ( +
{ + if (!this.props.deactivated) { + this.onEnter(); + } + }} + onMouseLeave={() => { + if (!this.props.deactivated) { + this.onLeave(); + } + }} + > + {this.props.children} + {!this.props.children && !this.props.deactivated && ( +
{this.props.empty || ''}
+ )} +
+ ); + } +} diff --git a/twake/frontend/src/app/components/drive/directory.jsx b/twake/frontend/src/app/components/drive/directory.jsx new file mode 100755 index 00000000..b07c0165 --- /dev/null +++ b/twake/frontend/src/app/components/drive/directory.jsx @@ -0,0 +1,87 @@ +import React from 'react'; +import DriveElement from './drive-element.jsx'; +import UIDirectory from './ui/directory.jsx'; +import Loader from 'components/loader/loader.jsx'; + +import WorkspaceUserRights from 'app/features/workspaces/services/workspace-user-rights-service'; +import Draggable from 'components/draggable/draggable'; +import DroppableZone from 'components/draggable/droppable-zone.jsx'; +import Languages from 'app/features/global/services/languages-service'; +import './drive.scss'; + +export default class Directory extends DriveElement { + constructor(props) { + super(); + this.props = props; + this.state = { + loading: true, + }; + } + componentDidMount() { + super.componentDidMount(); + if (this.state.loading) { + setTimeout(() => { + this.setState({ loading: false }); + }, 4000); + } + } + render() { + if (!this.state.element || !this.state.element.front_id) { + return ( +
+ {this.state.loading && } + {!this.state.loading && ( + + {Languages.t( + 'components.drive.navigators.directory_not_found', + [], + 'Directory not found.', + )} + + )} +
+ ); + } else { + this.state.loading = false; + } + + if (this.props.hide) { + return ''; + } + + return ( + this.dropFile(data)} + onLongOver={this.props.onClick} + className="directory_drop_zone" + > + (this.node = node)} + onClick={evt => { + this.clickElement(evt); + }} + onDoubleClick={this.props.onDoubleClick} + parentClassOnDrag="grid" + onDragStart={evt => { + this.dragElement(evt); + }} + minMove={10} + data={{ type: 'file', selection_type: this.props.selectionType, data: this.props.data }} + > + + + + ); + } +} diff --git a/twake/frontend/src/app/components/drive/drive-element.jsx b/twake/frontend/src/app/components/drive/drive-element.jsx new file mode 100755 index 00000000..58e21ed0 --- /dev/null +++ b/twake/frontend/src/app/components/drive/drive-element.jsx @@ -0,0 +1,645 @@ +/* eslint-disable react/prop-types */ +/* eslint-disable react/no-direct-mutation-state */ +import React, { useState } from 'react'; + +import SelectionsManager from 'app/deprecated/SelectionsManager/SelectionsManager.js'; +import DriveService from 'app/deprecated/Apps/Drive/Drive.js'; +import AlertManager from 'app/features/global/services/alert-manager-service'; +import MenuManager from 'app/components/menus/menus-manager.jsx'; +import Workspaces from 'app/deprecated/workspaces/workspaces.jsx'; +import Collections from 'app/deprecated/CollectionsV1/Collections/Collections.js'; +import FilePicker from 'components/drive/file-picker/file-picker.jsx'; +import Button from 'components/buttons/button.jsx'; +import Input from 'components/inputs/input.jsx'; +import VersionDetails from './version-details.jsx'; +import WorkspacesApps from 'app/deprecated/workspaces/workspaces_apps.jsx'; +import InputWithClipBoard from 'components/input-with-clip-board/input-with-clip-board.jsx'; +import WorkspaceUserRights from 'app/features/workspaces/services/workspace-user-rights-service'; +import MediumPopupManager from 'app/components/modal/modal-manager'; +import Languages from 'app/features/global/services/languages-service'; +import TagPicker from 'components/tag-picker/tag-picker.jsx'; +import RouterServices from 'app/features/router/services/router-service'; +import { getAsFrontUrl } from 'app/features/global/utils/URLUtils'; +import FeatureTogglesService, { + FeatureNames, +} from 'app/features/global/services/feature-toggles-service'; +import ModalManager from 'app/components/modal/modal-manager'; +import LockedOnlyOfficePopup from 'app/components/locked-features-components/locked-only-office-popup/locked-only-office-popup'; + +const RenameInput = props => { + const [value, setValue] = useState(props.value); + return ( +
+
+ { + if ((value || '').trim().length > 0) { + props.rename(value); + } + }} + className="full_width bottom-margin" + onEchap={() => { + MenuManager.closeMenu(); + }} + autoFocus + value={value} + onChange={evt => setValue(evt.target.value)} + /> +
+
+
+
+ ); +}; + +const PublicSharing = props => { + Collections.get('drive').useListener(useState); + const element = Collections.get('drive').find(props?.id); + if (!element) { + return
; + } + const sharedUrl = RouterServices.generateRouteFromState({ + workspaceId: element.workspace_id, + documentId: element?.id, + appName: 'drive', + shared: true, + token: (element.acces_info || {}).token, + }); + return ( +
+ {(element.acces_info || {}).token && ( +
+ +
+
+
+ )} + {!(element.acces_info || {}).token && ( +
+
+ )} +
+ ); +}; + +export default class DriveElement extends React.Component { + constructor() { + super(); + this.state = { + selections_manager: SelectionsManager, + }; + SelectionsManager.addListener(this); + + this.driveCollectionKey = ''; + + this.driveSelectorOver = this.driveSelectorOver.bind(this); + this.driveSelectorOut = this.driveSelectorOut.bind(this); + Collections.get('drive').addListener(this); + } + componentWillUnmount() { + SelectionsManager.removeListener(this); + Collections.get('drive').removeListener(this); + if (this.node) { + this.node.removeEventListener('drive_selector_over', this.driveSelectorOver); + this.node.removeEventListener('drive_selector_out', this.driveSelectorOut); + } + + if (this.driveCollectionKey && this.driveCollectionKey != this.props.driveCollectionKey) { + Collections.get('drive').removeSource(this.driveCollectionKey); + } + } + UNSAFE_componentWillMount() { + if (this.props && this.props.data && this.props.data.front_id) { + Collections.get('drive').listenOnly(this, [this.props.data.front_id]); + } + + this.state.element = DriveService.find( + Workspaces.currentWorkspaceId, + this.props.data?.id, + el => { + this.setState({ element: el }); + }, + ); + this.updateMenu(); + } + componentDidMount() { + if (this.node) { + this.node.addEventListener('drive_selector_over', this.driveSelectorOver); + this.node.addEventListener('drive_selector_out', this.driveSelectorOut); + this.node.setAttribute('drive_selector_unid', this.state.element?.id); + } + + if (this.props && this.props.data && this.props.data?.id) { + SelectionsManager.listenOnly(this, [this.props.data?.id]); + } + } + driveSelectorOut() { + if (this.state.selected) this.setState({ selected: false }); + } + driveSelectorOver() { + if (!this.state.selected) this.setState({ selected: true }); + } + + dropFile(data, directory) { + var destination = directory || this.props.data; + + var objects = data.data?.id; + if (data.selection_type) { + var selected = Object.keys(SelectionsManager.selected_per_type[data.selection_type] || {}); + if (selected && selected.length > 1) { + objects = selected; + } + } + + DriveService.moveFile( + objects, + destination, + this.props.driveCollectionKey || this.driveCollectionKey, + ); + } + + dragElement(evt) { + SelectionsManager.setType(this.props.selectionType); + if ( + !evt.shiftKey && + !SelectionsManager.selected_per_type[this.props.selectionType][this.state.element?.id] + ) { + SelectionsManager.unselectAll(); + } + SelectionsManager.select(this.state.element?.id); + } + + clickElement(evt, previewonly = false) { + evt.stopPropagation(); + evt.preventDefault(); + + if (this.props.notInDrive) { + if (this.props.onClick) { + this.props.onClick(); + } else { + DriveService.viewDocument(this.state.element, previewonly); + } + } else { + SelectionsManager.setType(this.props.selectionType); + if (!evt.shiftKey) { + if (this.props.onClick) { + this.props.onClick(); + } else { + DriveService.viewDocument(this.state.element, previewonly); + } + + var oldStatus = + SelectionsManager.selected_per_type[this.props.selectionType][this.state.element?.id]; + SelectionsManager.unselectAll(); + if (oldStatus) { + SelectionsManager.unselect(this.state.element?.id); + } else { + SelectionsManager.select(this.state.element?.id); + } + } else { + SelectionsManager.toggle(this.state.element?.id); + } + } + } + UNSAFE_componentWillUpdate(nextProps, nextState) { + nextState.element = + Collections.get('drive').find(this.props.data?.id) || + DriveService.find(Workspaces.currentWorkspaceId, this.props.data?.id, el => { + this.setState({ element: el }); + }); + this.state.element = nextState.element; + + if ( + this.state.element && + SelectionsManager.selected_per_type[nextProps.selectionType] && + SelectionsManager.selected_per_type[nextProps.selectionType][this.state.element?.id] != + this.old_selection_state + ) { + nextState.selected = + SelectionsManager.selected_per_type[nextProps.selectionType][nextProps.data?.id]; + this.old_selection_state = nextState.selected; + } + + if (this.state.element && !this.props.driveCollectionKey) { + this.channel = 'standalone_drive_collection_' + this.state.element.parent_id; + var parent_id = this.state.element.parent_id; + if (this.state.element.parent_id == 'detached') { + parent_id += '_' + this.state.element.workspace_id; + } + var old_collection_key = this.driveCollectionKey; + this.driveCollectionKey = DriveService.addSourceIfNotExist( + Workspaces.currentWorkspaceId, + this.channel, + parent_id, + 'standalone', + ); + if (old_collection_key && old_collection_key != this.driveCollectionKey) { + Collections.get('drive').removeSource(old_collection_key); + } + } + + this.updateMenu(); + + return true; + } + + moveTo(new_parent) { + DriveService.moveFile( + [this.state.element?.id], + new_parent, + this.props.driveCollectionKey || this.driveCollectionKey, + ); + } + + rename(new_name) { + if (!this.state.element.is_directory) { + new_name = new_name + '.' + this.state.element.extension; + } + this.state.element.name = new_name || this.state.element.name; + new_name = undefined; + MenuManager.closeMenu(); + DriveService.save(this.state.element, this.props.driveCollectionKey || this.driveCollectionKey); + } + + updateMenu() { + if (!this.state.element) { + this.common_menu = []; + return; + } + + this.common_menu = []; + + //-- All files + if (!this.state.element.is_directory) { + this.common_menu = [ + { + type: 'menu', + text: Languages.t('components.drive.elements.see', [], 'Voir'), + onClick: () => { + DriveService.viewDocument(this.state.element); + }, + }, + ]; + + var candidates = DriveService.getEditorsCandidates(this.state.element); + var editor_candidate = candidates.preview_candidate || []; + + if (editor_candidate.length > 0 && editor_candidate[0].app) { + this.common_menu.push({ + type: 'menu', + text: Languages.t( + 'scenes.apps.drive.viewer.edit_with_button', + [editor_candidate[0].app?.identity?.name], + 'Editer avec $1', + ), + onClick: () => { + if (FeatureTogglesService.isActiveFeatureName(FeatureNames.EDIT_FILES)) { + var app = editor_candidate[0]; + if (app.url && app.is_url_file) { + window.open(app.url); + } + app = app.app; + DriveService.getFileUrlForEdition( + app.display?.twake?.files?.editor?.edition_url, + app, + this.state.element?.id, + url => { + window.open(url); + }, + ); + } else { + ModalManager.open( + , + { + position: 'center', + size: { width: '600px' }, + }, + false, + ); + } + }, + }); + } + } + + this.common_menu.push({ + type: 'menu', + text: + this.state.element.url && this.state.element.extension == 'url' + ? Languages.t('scenes.apps.drive.open_link', [], 'Open link') + : Languages.t('scenes.apps.drive.download_button', [], 'Télécharger'), + onClick: () => { + var link = DriveService.getLink(this.state.element, undefined, 1); + if (this.state.element.url) { + window.open(link, '_blank'); + } else { + window.open(link); + } + }, + }); + + if (!WorkspaceUserRights.isNotConnected()) { + //-- All files + if (this.state.element.detached) { + this.common_menu.push({ + type: 'menu', + text: Languages.t('scenes.apps.drive.move_text2', [], 'Déplacer'), + submenu_replace: true, + submenu: [ + { + type: 'react-element', + reactElement: () => ( + this.moveTo(res)} + initialDirectory={{ id: '' }} + /> + ), + }, + ], + }); + } + + if (!this.props.notInDrive && !this.state.element.detached) { + if (this.common_menu.length > 0) { + this.common_menu.push({ type: 'separator' }); + } + + if (!this.state.element.detached && this.state.element.parent_id) { + this.common_menu = this.common_menu.concat([ + { + type: 'menu', + text: Languages.t('scenes.app.mainview.tabs.rename', [], 'Renommer'), + submenu_replace: true, + submenu: [ + { + type: 'title', + text: Languages.t('scenes.app.mainview.tabs.rename', [], 'Renommer'), + }, + { + type: 'text', + text: + Languages.t('components.drive.elements.current_name', [], 'Nom actuel : ') + + this.state.element.name, + }, + { + type: 'react-element', + reactElement: () => ( + { + this.rename(name); + }} + value={ + this.state.element.is_directory + ? this.state.element.name + : this.state.element.name.replace(/\.[^.]*$/, '') + } + /> + ), + }, + ], + }, + ]); + } + + if (!this.state.element.trash) { + this.common_menu = this.common_menu.concat([ + { + type: 'menu', + text: Languages.t('scenes.apps.drive.right_preview.public', [], 'Accès public...'), + submenu_replace: true, + submenu: [ + { + type: 'title', + text: Languages.t( + 'scenes.apps.drive.right_preview.public_link', + [], + "Lien d'accès public", + ), + }, + { + //TODO menu react-element to refactor + type: 'react-element', + reactElement: () => ( + + ), + }, + ], + }, + ]); + + if (!(this.state.element.application_id && this.state.element.is_directory)) { + this.common_menu.push({ + type: 'menu', + text: Languages.t('scenes.apps.drive.move_text', [], 'Déplacer'), + submenu_replace: true, + submenu: [ + { + type: 'react-element', + reactElement: () => ( + this.moveTo(res)} + initialDirectory={{ id: this.state.element.parent_id }} + /> + ), + }, + ], + }); + } + + if (WorkspaceUserRights.hasWorkspacePrivilege()) { + if (this.state.element.application_id && this.state.element.is_directory) { + this.common_menu.push({ + type: 'menu', + text: Languages.t( + 'components.drive.elements.configurate_mod', + [], + 'Configurer le module...', + ), + onClick: () => { + var data = { + drive_element: this.state.element, + }; + WorkspacesApps.notifyApp( + this.state.element.application_id, + 'configuration', + 'drive', + data, + ); + }, + }); + } + } + + if (!this.state.element.is_directory && !this.state.element.url) { + var versions_indicator = ''; + if ((this.state.element.versions || {}).length > 1) { + versions_indicator = ' (' + (this.state.element.versions || {}).length + ')'; + } + this.common_menu.push( + { + type: 'menu', + text: + Languages.t( + 'components.drive.elements.manage_version', + [], + 'Gérer les versions', + ) + + versions_indicator + + '...', + onClick: () => { + MediumPopupManager.open(, { + size: { width: 600 }, + }); + }, + }, + { + type: 'menu', + text: Languages.t( + 'scenes.apps.drive.navigators.navigator_labels.title', + [], + 'Labels', + ), + submenu_replace: true, + submenu: [ + { + type: 'title', + text: Languages.t( + 'scenes.apps.drive.navigators.navigator_labels.title', + [], + 'Labels', + ), + }, + { + type: 'react-element', + reactElement: level => ( +
+ { + this.state.element.tags = values; + MenuManager.closeMenu(); + DriveService.save( + this.state.element, + this.props.driveCollectionKey || this.driveCollectionKey, + ); + }} + /> +
+ ), + }, + ], + }, + ); + } + + if (this.props.attachmentMenu) { + this.common_menu.push(this.props.attachment_menu); + } + + this.common_menu.push({ type: 'separator' }); + + this.common_menu.push({ + type: 'menu', + text: Languages.t( + 'scenes.apps.drive.right_preview.operations_delete', + [], + 'Mettre Γ  la corbeille', + ), + className: 'error', + onClick: () => { + DriveService.remove( + [this.props.data], + this.props.driveCollectionKey || this.driveCollectionKey, + ); + }, + }); + } else { + this.common_menu.push({ + type: 'menu', + text: Languages.t( + 'scenes.apps.drive.right_preview.operations_restore', + [], + 'Restaurer', + ), + onClick: () => { + DriveService.restore( + [this.props.data], + this.props.driveCollectionKey || this.driveCollectionKey, + ); + }, + }); + this.common_menu.push({ + type: 'menu', + text: Languages.t( + 'scenes.apps.drive.remove_definitely_menu', + [], + 'Supprimer dΓ©finitivement', + ), + className: 'error', + onClick: () => { + AlertManager.confirm(() => { + DriveService.removeDefinitively( + [this.props.data], + this.props.driveCollectionKey || this.driveCollectionKey, + ); + }); + }, + }); + } + } + + if (this.props.additionalMenu && this.props.additionalMenu.length > 0) { + this.common_menu.push({ type: 'separator' }); + this.common_menu = this.common_menu.concat(this.props.additionalMenu); + } + } + } +} diff --git a/twake/frontend/src/app/components/drive/drive-multi-selector.jsx b/twake/frontend/src/app/components/drive/drive-multi-selector.jsx new file mode 100755 index 00000000..679c1310 --- /dev/null +++ b/twake/frontend/src/app/components/drive/drive-multi-selector.jsx @@ -0,0 +1,278 @@ +/* eslint-disable react/prop-types */ +/* eslint-disable react/no-direct-mutation-state */ +import React, { Component } from 'react'; + +import './drive-multi-selector.scss'; +import SelectionsManager from 'app/deprecated/SelectionsManager/SelectionsManager.js'; +import './drive.scss'; + +export default class DriveMultiSelector extends Component { + constructor() { + super(); + this.state = { + start_drag: false, + dragging: true, + }; + this.move = this.move.bind(this); + this.end = this.end.bind(this); + this.start = this.start.bind(this); + this.pause = this.pause.bind(this); + this.unpause = this.unpause.bind(this); + + this.currentSelection = {}; + this.currentSelectionCount = 0; + + this.noMovementRefreshAnyway = setTimeout(''); + } + componentDidMount() { + this.scroller_container = this.props.scroller; + } + componentWillUnmount() { + clearInterval(this.noMovementRefreshAnyway); + + this.container.removeEventListener('mouseleave', this.pause); + this.container.removeEventListener('mouseenter', this.unpause); + document.removeEventListener('mousemove', this.move); + document.removeEventListener('mouseup', this.end); + document.body.classList.remove('no_select'); + } + pause() { + clearInterval(this.noMovementRefreshAnyway); + + this.setState({ dragging: false }); + } + unpause() { + this.setState({ dragging: true }); + } + end(evt) { + clearInterval(this.noMovementRefreshAnyway); + + this.setState({ start_drag: false }); + + document.removeEventListener('mousemove', this.move); + document.removeEventListener('mouseup', this.end); + this.container.removeEventListener('mouseleave', this.pause); + this.container.removeEventListener('mouseenter', this.unpause); + + document.body.classList.remove('no_select'); + + if (!this.did_drag) { + if (!evt.shiftKey && !this.did_start_drag == 0) { + SelectionsManager.unselectAll(); + } + this.did_start_drag = false; + return; + } + this.did_drag = false; + + Object.keys(this.currentSelection).forEach(id => { + if (this.currentSelection[id]) { + SelectionsManager.select(id); + } else { + SelectionsManager.unselect(id); + } + }); + this.did_start_drag = false; + + this.noMovementRefreshAnyway = setTimeout(() => { + this.state.left = 0; + this.state.right = 0; + this.state.width = 0; + this.state.height = 0; + this.setState({}); + }, 500); + } + start(evt) { + this.did_drag = false; + this.did_start_drag = true; + + this.element_position_cache = {}; + + SelectionsManager.setType(this.props.selectionType); + + clearInterval(this.noMovementRefreshAnyway); + this.currentSelection = {}; + + this.state.start_drag = true; + this.state.dragging = true; + var rect = window.getBoundingClientRect(this.container); + rect.x = rect.x || rect.left; + rect.y = rect.y || rect.top; + + this.drag_add = evt.nativeEvent.shiftKey; + this.drag_start = [ + evt.clientX - rect.left, + evt.clientY - rect.top, + this.container.scrollLeft, + this.container.scrollTop, + ]; + + document.addEventListener('mousemove', this.move); + document.addEventListener('mouseup', this.end); + this.container.addEventListener('mouseleave', this.pause); + this.container.addEventListener('mouseenter', this.unpause); + + document.body.classList.add('no_select'); + + rect = {}; + rect.width = 0; + rect.height = 0; + rect.left = evt.clientX; + rect.top = evt.clientY; + this.autoSelect(rect); + } + move(evt) { + clearInterval(this.noMovementRefreshAnyway); + var rect = window.getBoundingClientRect(this.container); + rect.x = rect.x || rect.left; + rect.y = rect.y || rect.top; + var pos = []; + + if (this.state.start_drag && this.state.dragging) { + this.did_drag = true; + + pos = [evt.clientX - rect.left, evt.clientY - rect.top]; + + pos[0] = Math.min(pos[0], rect.width - 5); + pos[0] = Math.max(pos[0], 5); + + pos[1] = Math.min(pos[1], rect.height - 5); + pos[1] = Math.max(pos[1], 5); + + var w = this.drag_start[0] + this.drag_start[2] - (pos[0] + this.container.scrollLeft); + var h = this.drag_start[1] + this.drag_start[3] - (pos[1] + this.container.scrollTop); + var winv = w > 0; + var hinv = h > 0; + var selectorRect = { + width: Math.abs(w), + height: Math.abs(h), + left: this.drag_start[0] + this.drag_start[2] - Math.abs(winv ? w : 0), + top: this.drag_start[1] + this.drag_start[3] - Math.abs(hinv ? h : 0), + }; + this.setState(selectorRect); + + rect = window.getBoundingClientRect(this.selector); + rect.x = rect.x || rect.left; + rect.y = rect.y || rect.top; + this.autoSelect(rect); + } + + pos = [evt.clientX, evt.clientY]; + + if ( + rect.height + rect.top < pos[1] || + rect.top > pos[1] || + rect.width + rect.left < pos[0] || + rect.left > pos[0] + ) { + var newScrollTop = + this.container.scrollTop + + (pos[1] - ((pos[1] > rect.height + rect.top ? rect.height : 0) + rect.top)) / 10; + var newScrollLeft = + this.container.scrollLeft + + (pos[0] - ((pos[0] > rect.width + rect.top ? rect.width : 0) + rect.left)) / 10; + + if (this.container.scrollTop != newScrollTop || this.container.scrollLeft != newScrollLeft) { + this.container.scrollTop = newScrollTop; + this.container.scrollLeft = newScrollLeft; + this.state.dragging = true; + + this.noMovementRefreshAnyway = setTimeout(() => { + this.move({ + clientX: evt.clientX, + clientY: evt.clientY, + }); + }, 50); + } else { + this.state.dragging = false; + } + } + } + autoSelect(rect) { + this.currentSelectionCount = 0; + var scroll_top = this.container.scrollTop; + if (this.old_scroll_top != scroll_top) { + this.element_position_cache = {}; + } + this.old_scroll_top = scroll_top; + + Array.from(this.container.getElementsByClassName('js-drive-multi-selector-selectable')).forEach( + element => { + var element_id = element.getAttribute('drive_selector_unid'); + + var selected = SelectionsManager.selected_per_type[this.props.selectionType][element_id]; + + var over = false; + var elementRect = {}; + + if (this.element_position_cache[element_id]) { + elementRect = JSON.parse(JSON.stringify(this.element_position_cache[element_id])); + } else { + var er = window.getBoundingClientRect(element); + er.x = er.x || er.left; + er.y = er.y || er.top; + elementRect = JSON.parse(JSON.stringify(er)); + this.element_position_cache[element_id] = elementRect; + } + + if ( + !( + rect.left > elementRect.left + elementRect.width || + elementRect.left > rect.left + rect.width || + rect.top > elementRect.top + elementRect.height || + elementRect.top > rect.top + rect.height + ) + ) { + over = true; + } + + if ( + (over && this.drag_add && selected) || + (!over && this.drag_add && !selected) || + (!over && !this.drag_add) + ) { + element.dispatchEvent(new Event('drive_selector_out')); + this.currentSelection[element_id] = false; + } + if ( + (over && this.drag_add && !selected) || + (over && !this.drag_add) || + (!over && this.drag_add && selected) + ) { + element.dispatchEvent(new Event('drive_selector_over')); + this.currentSelection[element_id] = true; + this.currentSelectionCount++; + } + }, + ); + } + render() { + return ( +
{ + this.start(evt); + }} + onMouseUp={evt => { + this.end(evt); + }} + ref={node => (this.container = node)} + style={this.props.style || {}} + className={'drive_multiselector'} + > +
(this.selector = node)} + className={ + 'selectionRect ' + (this.state.start_drag && this.state.dragging ? 'visible ' : '') + } + style={{ + width: this.state.width, + height: this.state.height, + left: this.state.left, + top: this.state.top, + }} + /> + {this.props.children} +
+ ); + } +} diff --git a/twake/frontend/src/app/components/drive/drive-multi-selector.scss b/twake/frontend/src/app/components/drive/drive-multi-selector.scss new file mode 100755 index 00000000..4599207b --- /dev/null +++ b/twake/frontend/src/app/components/drive/drive-multi-selector.scss @@ -0,0 +1,28 @@ +body.no_select { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.drive_multiselector { + position: relative; + overflow-x: visible; + overflow-y: scroll; +} + +.selectionRect { + background: var(--primary); + z-index: 10; + border-radius: var(--border-radius-base); + position: absolute; + pointer-events: none; + opacity: 0; + transition: opacity 0.2s; + + &.visible { + opacity: 0.2; + } +} diff --git a/twake/frontend/src/app/components/drive/drive.scss b/twake/frontend/src/app/components/drive/drive.scss new file mode 100755 index 00000000..433aef9a --- /dev/null +++ b/twake/frontend/src/app/components/drive/drive.scss @@ -0,0 +1,522 @@ +/* Drive */ + +.directory, +.file { + .file_loader { + width: 32px; + height: 32px; + display: inline-block; + margin: auto; + } + .options { + padding-left: 5px; + display: none; + } + + &:hover { + .options { + display: block; + } + } +} + +.directory_drop_zone { + display: inline-block; +} +.directory { + background: #fff; + border: 1px solid var(--grey-background); + height: 50px; + box-sizing: border-box; + display: inline-flex; + flex-direction: row; + line-height: 32px; + margin-right: 16px; + margin-bottom: 16px; + border-radius: var(--border-radius-base); + font-size: 13px; + vertical-align: middle; + width: 200px; + padding: 8px; + font-weight: 500; + padding-right: 12px; + cursor: pointer; + + .text { + font-size: 12px; + font-weight: bold; + } + + &:hover:not(.notInDrive) { + box-shadow: 4px 4px 16px 0 #00000022; + border-color: #fff; + } + + .options { + .m-icon-small { + font-size: 20px !important; + } + } + + .app_icon { + width: 20px; + background-size: contain; + background-position: center; + background-repeat: no-repeat; + height: 20px; + margin-top: 2px; + } + + .icon { + font-size: 14px; + padding-right: 8px; + margin-left: 6px; + padding-top: 4px; + + .m-icon-small { + color: var(--warning); + font-size: 20px !important; + } + + i.icon-fontastic { + position: relative; + top: 8px; + } + + .icon { + height: 30px; + background-size: 16px auto; + background-position: center left; + background-repeat: no-repeat; + } + } +} + +.file { + overflow: hidden; + border: 1px solid var(--grey-background); + background: #fff; + height: 180px; + width: 216px; + box-sizing: border-box; + display: inline-flex; + flex-direction: column; + line-height: 30px; + margin-right: 16px; + margin-bottom: 16px; + border-radius: var(--border-radius-base); + font-size: 13px; + vertical-align: middle; + position: relative; + cursor: pointer; + + &:hover:not(.notInDrive) { + box-shadow: 4px 4px 16px 0 #00000022; + border-color: #fff; + } + + .options { + .m-icon-small { + font-size: 20px !important; + } + } + + &.mini { + height: 32px; + + .data { + border-top: none; + .no-grid { + display: none; + } + } + + .preview { + height: 32px; + background: #fff !important; + + &:after { + content: none; + } + } + } + + .preview { + width: 216px; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + background-color: #f5f5f7; + flex: 1; + + .tags_list { + position: absolute; + top: 4px; + padding-left: 8px; + line-height: 30px; + } + + &.no_preview { + background-color: #f5f5f7; + background-repeat: no-repeat; + background-size: 64px; + } + + /*&:after { + content: ""; + position: absolute; + width: 100%; + height: 100%; + background: linear-gradient(180deg, rgba(0,0,0,0) 40%, rgba(0,0,0,0.05) 70%, rgba(0,0,0,0.5) 100%); + }*/ + } + + .data { + display: flex; + flex-direction: row; + padding-left: 8px; + padding-right: 8px; + bottom: 0px; + color: var(--black); + height: 32px; + font-weight: 500; + width: 100%; + box-sizing: border-box; + border-top: 1px solid var(--grey-background); + + .icon { + height: 20px; + width: 20px; + box-sizing: border-box; + border-radius: var(--border-radius-base); + margin-right: 6px; + margin-left: -3px; + margin-top: 5px; + color: #fff; + text-align: center; + background-size: 70%; + background-repeat: no-repeat; + background-position: center; + + i.icon-fontastic { + position: relative; + top: 4px; + } + } + } +} + +.draggable_clone { + .file, + .directory { + opacity: 1; + box-shadow: 4px 4px 16px 0 #00000022; + border-color: #fff; + } +} + +.dragging.drag_file .drive_multiselector { + .file.is_selected, + .directory.is_selected { + opacity: 0; + transition: opacity 0.2s; + } +} + +.file, +.directory { + transition: opacity 0s; + + &.notInDrive { + margin-bottom: 0px; + } + + &.dragging_opacity { + opacity: 0; + } + + &.is_selected { + background: var(--primary); + color: #fff; + box-shadow: none; + + .file_type_icon svg, + .file_type_icon svg * { + fill: #fff; + } + + &:hover:not(.notInDrive), + .data { + background-color: var(--primary); + color: #fff; + } + } + + .text { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .created-by, + .last-modified { + width: 200px; + } + + .size { + text-align: right; + width: 70px; + } + + .last-modified { + text-align: right; + width: 120px; + } + + .detail_preview_parent { + width: 32px; + margin-left: 12px; + + .detail_preview { + width: 32px; + height: 32px; + border-radius: var(--border-radius-base); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + background-color: var(--primary-background); + + &.no_preview { + background-size: 60%; + } + } + } +} + +.drive_view.list { + .directory_drop_zone { + display: inherit; + } +} + +.drive_view.list .directory, +.drive_view.list .file { + margin-right: 0px; + margin-bottom: 0px; + border: 0; + border-bottom: 1px solid var(--grey-background); + border-top: 1px solid var(--grey-background); + border-radius: 2px; + width: 100%; + height: 64px; + padding-top: 16px; + color: var(--black); + margin-top: -1px; + padding-right: 12px; + + &.exit-active, + &.enter-active { + margin-top: -1px !important; + } + + .data { + border-top: 0px; + bottom: -1px; + } + + .text { + font-size: 14px; + } + + .options { + display: block; + } + + &:hover:not(.notInDrive):not(.is_selected) { + box-shadow: none; + background: var(--primary-background); + } + + &.is_selected { + background: var(--primary); + color: #fff; + box-shadow: none; + } +} + +.drive_view.list .file .preview { + display: none; +} + +.drive_view.list { + .rounded-btn { + margin-top: 10px; + } +} + +.drive_view.grid { + .is_selected.file { + background: var(--primary); + color: #fff; + box-shadow: none; + } +} + +.drive_view.grid .no-grid { + display: none; +} +.drive_view.list .no-list { + display: none; +} + +.file_type_icon { + line-height: 38px; + width: 24px; + + svg, + svg * { + fill: var(--primary); + } + + &.link { + background-image: url('./icons/link.svg'); + } + + &.code { + background-image: url('./icons/code.svg'); + } + + &.document { + background-image: url('./icons/document.svg'); + } + + &.image { + background-image: url('./icons/image.svg'); + } + + &.pdf { + background-image: url('./icons/pdf.svg'); + } + + &.slides { + background-image: url('./icons/slides.svg'); + } + + &.sound, &.audio { + background-image: url('./icons/sound.svg'); + } + + &.spreadsheet { + background-image: url('./icons/spreadsheet.svg'); + } + + &.svg { + background-image: url('./icons/svg.svg'); + } + + &.video { + background-image: url('./icons/video.svg'); + } + + &.archive { + background-image: url('./icons/archive.svg'); + } + + &.other { + background-image: url('./icons/file.svg'); + } +} + +.drive_view.list .file_type_icon { + line-height: 38px; + width: 34px; + text-align: center; +} + +/* version details */ +.versionDetails { + min-height: 250px; + + .text.no-more { + text-align: center; + width: 100%; + opacity: 0.5; + margin-top: 32px; + margin-bottom: 32px; + } + + .version { + display: flex; + padding: 24px 0px; + border-bottom: solid 1px var(--grey-background); + .titleVersionDetails { + font-size: 24px; + color: var(--black); + font-weight: bold; + margin-bottom: 24px; + } + .info { + flex: 0.5; + margin-bottom: 8px; + .versionTitle { + font-size: 14px; + font-weight: bold; + color: var(--black); + } + .versionDate { + font-size: 14px; + color: var(--black); + } + } + .name { + flex: 0.5; + font-size: 14px; + line-height: 24px; + color: var(--black); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .more { + } + } +} +.footerVersionDetails { + display: flex; + .addVersion { + flex: 1; + .addVersionButton { + width: 100%; + height: 24px; + line-height: 24px; + } + .addVersionButton:hover { + cursor: pointer; + opacity: 0.8; + } + .icon { + display: inline-block; + width: 24px; + height: 24px; + .iconWithBackground { + width: 24px; + height: 24px; + display: inline-block; + background-color: var(--grey-background); + border-radius: var(--border-radius-base); + } + } + .footerTitle { + margin-left: 8px; + display: inline-block; + font-size: 14px; + font-weight: bold; + color: var(--black); + .addVersionButton:hover { + cursor: pointer; + opacity: 0.8; + } + } + } +} diff --git a/twake/frontend/src/app/components/drive/file-picker/file-picker.jsx b/twake/frontend/src/app/components/drive/file-picker/file-picker.jsx new file mode 100755 index 00000000..c7ade5d6 --- /dev/null +++ b/twake/frontend/src/app/components/drive/file-picker/file-picker.jsx @@ -0,0 +1,213 @@ +/* eslint-disable react/prop-types */ +import React, { Component } from 'react'; + +import DriveService from 'app/deprecated/Apps/Drive/Drive.js'; +import Workspaces from 'app/deprecated/workspaces/workspaces.jsx'; +import Languages from 'app/features/global/services/languages-service'; +import Collections from 'app/deprecated/CollectionsV1/Collections/Collections.js'; +import UIFile from '../ui/file.jsx'; +import UIDirectory from '../ui/directory.jsx'; +import LeftIcon from '@material-ui/icons/KeyboardArrowLeftOutlined'; +import NewFolderIcon from '@material-ui/icons/CreateNewFolderOutlined'; +import Menu from 'components/menus/menu.jsx'; +import Button from 'components/buttons/button.jsx'; +import Input from 'components/inputs/input.jsx'; +import './file-picker.scss'; + +export default class FilePicker extends Component { + constructor() { + super(); + this.drive_channel = 'file_picker_' + Workspaces.currentWorkspaceId; + this.drive_collection_key = this.drive_channel; + + this.state = { + i18n: Languages, + drive_repository: Collections.get('drive'), + app_drive_service: DriveService, + current_selection: {}, + creating_folder: false, + }; + + Languages.addListener(this); + Collections.get('drive').addListener(this); + DriveService.addListener(this); + } + componentWillUnmount() { + Languages.removeListener(this); + Collections.get('drive').removeListener(this); + DriveService.removeListener(this); + + if (this.drive_channel) { + Collections.get('drive').removeSource( + this.state.app_drive_service.current_collection_key_channels[this.drive_channel], + ); + } + } + componentDidMount() { + this.changeCurrentDirectory({ id: (this.props.initialDirectory || {}).id || '' }); + } + clickOnFile(file) { + if (this.props.mode == 'select_file') { + this.setState({ current_selection: file }); + } + } + changeCurrentDirectory(directory) { + if (this.props.mode == 'select_file') { + this.setState({ current_selection: {} }); + } + if (this.props.mode == 'select_location') { + this.setState({ current_selection: directory }); + } + DriveService.changeCurrentDirectory(this.drive_channel, directory); + } + submit() { + var result = null; + if (this.props.mode == 'select_file') { + result = this.state.current_selection; + } + if (this.props.mode == 'select_location') { + result = this.state.app_drive_service.current_directory_channels[this.drive_channel] || {}; + } + Menu.closeAll(); + if (this.props.onChoose) this.props.onChoose(result); + } + render() { + var workspace_id = Workspaces.currentWorkspaceId; + var directory = + this.state.app_drive_service.current_directory_channels[this.drive_channel] || {}; + var directory_id = directory.id; + + var filter_dir = { + workspace_id: workspace_id, + parent_id: directory_id, + is_directory: true, + trash: false, + }; + var directories = this.state.drive_repository + .findBy(filter_dir) + .sort((a, b) => (a.name || '').localeCompare(b.name || '')); + + var filter_files = { + workspace_id: workspace_id, + parent_id: directory_id, + is_directory: false, + trash: false, + }; + var files = this.state.drive_repository + .findBy(filter_files) + .sort((a, b) => (a.name || '').localeCompare(b.name || '')); + + var allow_go_parent = true; + var drive_channel = null; + if (!drive_channel && (this.props.initialDirectory || {}).id == directory_id) { + allow_go_parent = false; + } + + return ( +
+
+ {directory.parent_id && allow_go_parent && ( + { + this.changeCurrentDirectory({ id: directory.parent_id }); + }} + /> + )}{' '} + {directory.parent_id + ? directory.name + : Languages.t('app.identity?.name.twake_drive', [], 'Documents')} +
+
+ {directories.map((item, index) => ( +
DriveService.changeCurrentDirectory(this.drive_channel, item)} + > + +
+ ))} + {files.map((item, index) => ( +
this.clickOnFile(item)} + > + +
+ ))} +
+ + {this.state.creating_folder && ( +
+ + (node ? node.focus() : '')} + type="text" + defaultValue={''} + placeholder={Languages.t( + 'scenes.apps.drive.navigators.navigator_content.directory_name', + [], + 'Nom du dossier', + )} + onKeyPress={e => { + if (e.key === 'Enter') { + DriveService.createDirectory( + directory.workspace_id, + e.target.value, + directory, + DriveService.current_collection_key_channels[this.drive_channel], + res => { + this.changeCurrentDirectory(res); + }, + ); + this.setState({ creating_folder: false }); + } + }} + /> +
+ )} + {!this.state.creating_folder && ( +
+ {!this.state.creating_folder && directory.workspace_id && ( + + )} + {this.props.mode == 'select_location' && ( +
+ )} +
+ ); + } +} diff --git a/twake/frontend/src/app/components/drive/file-picker/file-picker.scss b/twake/frontend/src/app/components/drive/file-picker/file-picker.scss new file mode 100755 index 00000000..f3f2c1f2 --- /dev/null +++ b/twake/frontend/src/app/components/drive/file-picker/file-picker.scss @@ -0,0 +1,84 @@ +.filepicker { + margin: -5px 0; + + .no-filepicker { + display: none; + } + + .file_type_icon { + width: 20px; + margin-right: 4px; + } + + .title { + background: #ffffff; + margin-bottom: 0px; + font-size: 16px; + color: #000; + line-height: 20px; + padding-bottom: 8px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .getback { + background: var(--grey-background); + border-radius: var(--border-radius-base); + width: 20px; + height: 20px; + vertical-align: top; + margin-right: 5px; + margin-left: 0px; + cursor: pointer; + &:hover { + background: #f0f0f0; + } + } + + .menu-buttons { + text-align: right; + padding: 8px 0px; + } + + .drive_view.list { + height: 150px; + overflow: auto; + width: 100%; + + .file .icon { + width: 20px; + background-size: 60%; + } + + .directory .icon { + width: 24px; + } + + .directory .app_icon { + height: 16px; + } + + .file, + .directory { + height: 40px; + padding-top: 4px; + + .text { + line-height: 30px; + margin-left: 6px; + } + + .icon { + padding-top: 3px; + padding-right: 0px; + padding-left: 5px; + } + + &.disabled { + opacity: 0.5; + pointer-events: none; + } + } + } +} diff --git a/twake/frontend/src/app/components/drive/file.tsx b/twake/frontend/src/app/components/drive/file.tsx new file mode 100755 index 00000000..8c036f01 --- /dev/null +++ b/twake/frontend/src/app/components/drive/file.tsx @@ -0,0 +1,91 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React from 'react'; +import Draggable from 'components/draggable/draggable'; +import DriveElement from './drive-element.jsx'; +import './drive.scss'; +import UIFile from './ui/file.jsx'; +import Loader from 'components/loader/loader.jsx'; +import WorkspaceUserRights from 'app/features/workspaces/services/workspace-user-rights-service'; +import Languages from 'app/features/global/services/languages-service'; + +type StateType = any; + +type NodeType = any; + +export default class File extends DriveElement { + node: NodeType; + state: StateType; + constructor() { + super(); + this.state = { + loading: true, + }; + } + componentDidMount() { + super.componentDidMount(); + if (this.state.loading) { + setTimeout(() => { + this.setState({ loading: false }); + }, 4000); + } + } + render() { + if (!this.state.element || !this.state.element.front_id) { + return ( +
+ {this.state.loading && } + {!this.state.loading && ( + + {Languages.t('scenes.apps.drive.preview_bloc.error_file', [], 'File not found.')} + + )} +
+ ); + } else { + this.state.loading = false; + } + + if (this.props.hide) { + return ''; + } + + const mini = (!this.state.element.has_preview && this.props.notInDrive) || this.props.mini; + return ( + (this.node = node)} + onClick={(evt: any) => this.clickElement(evt, this.props.previewonly)} + onDoubleClick={this.props.onDoubleClick} + parentClassOnDrag="drive_view list" + onDragStart={(evt: any) => { + this.dragElement(evt); + }} + minMove={10} + data={{ type: 'file', selection_type: this.props.selectionType, data: this.props.data }} + deactivated={WorkspaceUserRights.isNotConnected() || this.props.notInDrive} + > + { + e.preventDefault(); + e.stopPropagation(); + this.props.removeOnClick(); + }} + /> + + ); + } +} diff --git a/twake/frontend/src/app/components/drive/icons/archive.jsx b/twake/frontend/src/app/components/drive/icons/archive.jsx new file mode 100755 index 00000000..44e4e817 --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/archive.jsx @@ -0,0 +1,19 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; + +const SvgComponent = props => ( + + + +); + +export default SvgComponent; diff --git a/twake/frontend/src/app/components/drive/icons/archive.svg b/twake/frontend/src/app/components/drive/icons/archive.svg new file mode 100755 index 00000000..af396f1f --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/archive.svg @@ -0,0 +1,15 @@ + + + + + + diff --git a/twake/frontend/src/app/components/drive/icons/code.jsx b/twake/frontend/src/app/components/drive/icons/code.jsx new file mode 100755 index 00000000..c83b6ec4 --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/code.jsx @@ -0,0 +1,19 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; + +const SvgComponent = props => ( + + + +); + +export default SvgComponent; diff --git a/twake/frontend/src/app/components/drive/icons/code.svg b/twake/frontend/src/app/components/drive/icons/code.svg new file mode 100755 index 00000000..4359143b --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/code.svg @@ -0,0 +1,17 @@ + + + + + + diff --git a/twake/frontend/src/app/components/drive/icons/document.jsx b/twake/frontend/src/app/components/drive/icons/document.jsx new file mode 100755 index 00000000..2db77ebc --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/document.jsx @@ -0,0 +1,20 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; + +const SvgComponent = props => ( + + + + + +); + +export default SvgComponent; diff --git a/twake/frontend/src/app/components/drive/icons/document.svg b/twake/frontend/src/app/components/drive/icons/document.svg new file mode 100755 index 00000000..7160424e --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/document.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/twake/frontend/src/app/components/drive/icons/file.jsx b/twake/frontend/src/app/components/drive/icons/file.jsx new file mode 100755 index 00000000..46da903b --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/file.jsx @@ -0,0 +1,19 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; + +const SvgComponent = props => ( + + + +); + +export default SvgComponent; diff --git a/twake/frontend/src/app/components/drive/icons/file.svg b/twake/frontend/src/app/components/drive/icons/file.svg new file mode 100755 index 00000000..8b32e854 --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/file.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/twake/frontend/src/app/components/drive/icons/image.jsx b/twake/frontend/src/app/components/drive/icons/image.jsx new file mode 100755 index 00000000..ee544c5c --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/image.jsx @@ -0,0 +1,24 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; + +const SvgComponent = props => ( + + + + + + +); + +export default SvgComponent; diff --git a/twake/frontend/src/app/components/drive/icons/image.svg b/twake/frontend/src/app/components/drive/icons/image.svg new file mode 100755 index 00000000..477b7a5d --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/image.svg @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/twake/frontend/src/app/components/drive/icons/link.jsx b/twake/frontend/src/app/components/drive/icons/link.jsx new file mode 100755 index 00000000..cf5fad3d --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/link.jsx @@ -0,0 +1,24 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; + +const SvgComponent = props => ( + + + + + + +); + +export default SvgComponent; diff --git a/twake/frontend/src/app/components/drive/icons/link.svg b/twake/frontend/src/app/components/drive/icons/link.svg new file mode 100755 index 00000000..2a14d480 --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/link.svg @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/twake/frontend/src/app/components/drive/icons/pdf.jsx b/twake/frontend/src/app/components/drive/icons/pdf.jsx new file mode 100755 index 00000000..b508a39a --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/pdf.jsx @@ -0,0 +1,19 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; + +const SvgComponent = props => ( + + + +); + +export default SvgComponent; diff --git a/twake/frontend/src/app/components/drive/icons/pdf.svg b/twake/frontend/src/app/components/drive/icons/pdf.svg new file mode 100755 index 00000000..366c9b15 --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/pdf.svg @@ -0,0 +1,30 @@ + + + + + + diff --git a/twake/frontend/src/app/components/drive/icons/slides.jsx b/twake/frontend/src/app/components/drive/icons/slides.jsx new file mode 100755 index 00000000..16cca67d --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/slides.jsx @@ -0,0 +1,25 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; + +const SvgComponent = props => ( + + + + + + + +); + +export default SvgComponent; diff --git a/twake/frontend/src/app/components/drive/icons/slides.svg b/twake/frontend/src/app/components/drive/icons/slides.svg new file mode 100755 index 00000000..98dea993 --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/slides.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/twake/frontend/src/app/components/drive/icons/sound.jsx b/twake/frontend/src/app/components/drive/icons/sound.jsx new file mode 100755 index 00000000..398d4307 --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/sound.jsx @@ -0,0 +1,19 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; + +const SvgComponent = props => ( + + + +); + +export default SvgComponent; diff --git a/twake/frontend/src/app/components/drive/icons/sound.svg b/twake/frontend/src/app/components/drive/icons/sound.svg new file mode 100755 index 00000000..58ca3b76 --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/sound.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/twake/frontend/src/app/components/drive/icons/spreadsheet.jsx b/twake/frontend/src/app/components/drive/icons/spreadsheet.jsx new file mode 100755 index 00000000..b4f6523f --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/spreadsheet.jsx @@ -0,0 +1,28 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; + +const SvgComponent = props => ( + + + + + + + +); + +export default SvgComponent; diff --git a/twake/frontend/src/app/components/drive/icons/spreadsheet.svg b/twake/frontend/src/app/components/drive/icons/spreadsheet.svg new file mode 100755 index 00000000..a0ddedfd --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/spreadsheet.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/twake/frontend/src/app/components/drive/icons/svg.jsx b/twake/frontend/src/app/components/drive/icons/svg.jsx new file mode 100755 index 00000000..33a46b88 --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/svg.jsx @@ -0,0 +1,33 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; + +const SvgComponent = props => ( + + + + + + +); + +export default SvgComponent; diff --git a/twake/frontend/src/app/components/drive/icons/svg.svg b/twake/frontend/src/app/components/drive/icons/svg.svg new file mode 100755 index 00000000..1347b9b1 --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/svg.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/twake/frontend/src/app/components/drive/icons/video.jsx b/twake/frontend/src/app/components/drive/icons/video.jsx new file mode 100755 index 00000000..4356053b --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/video.jsx @@ -0,0 +1,19 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; + +const SvgComponent = props => ( + + + +); + +export default SvgComponent; diff --git a/twake/frontend/src/app/components/drive/icons/video.svg b/twake/frontend/src/app/components/drive/icons/video.svg new file mode 100755 index 00000000..3b554029 --- /dev/null +++ b/twake/frontend/src/app/components/drive/icons/video.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/twake/frontend/src/app/components/drive/ui/directory.jsx b/twake/frontend/src/app/components/drive/ui/directory.jsx new file mode 100755 index 00000000..1af75a04 --- /dev/null +++ b/twake/frontend/src/app/components/drive/ui/directory.jsx @@ -0,0 +1,56 @@ +/* eslint-disable react/prop-types */ +/* eslint-disable react/jsx-key */ +import React from 'react'; + +import Icon from 'app/components/icon/icon.jsx'; +import FolderIcon from '@material-ui/icons/FolderOutlined'; +import Menu from 'components/menus/menu.jsx'; +import Numbers from 'app/features/global/utils/Numbers'; +import '../drive.scss'; +import 'moment-timezone'; +import { getCompanyApplication as getApplication } from 'app/features/applications/state/company-applications'; + +export default class Directory extends React.Component { + constructor() { + super(); + } + render() { + var app = {}; + if (this.props.data.application_id && this.props.data.external_storage) { + app = getApplication(this.props.data.application_id); + } + + return [ +
+
+ {!app.id && } + {!!app.id && ( +
+ )} +
+
+ {this.props.data.name} + {!!app.id && ({app.identity?.name})} +
+ + {(this.props.data.acces_info || {}).token && ( + + )} + + {this.props.details && ( +
+ {this.props.data.size ? Numbers.humanFileSize(this.props.data.size, true) : '-'} +
+ )} + {this.props.menu && this.props.menu.length > 0 && ( + + + + )} +
, + ]; + } +} diff --git a/twake/frontend/src/app/components/drive/ui/file-type.jsx b/twake/frontend/src/app/components/drive/ui/file-type.jsx new file mode 100755 index 00000000..3a2a764f --- /dev/null +++ b/twake/frontend/src/app/components/drive/ui/file-type.jsx @@ -0,0 +1,63 @@ +/* eslint-disable react/prop-types */ +import React, { Component } from 'react'; + +import Archive from '../icons/archive.jsx'; +import Code from '../icons/code.jsx'; +import Document from '../icons/document.jsx'; +import Files from '../icons/file.jsx'; +import Images from '../icons/image.jsx'; +import Link from '../icons/link.jsx'; +import Pdf from '../icons/pdf.jsx'; +import Slide from '../icons/slides.jsx'; +import Sound from '../icons/sound.jsx'; +import Spreadsheet from '../icons/spreadsheet.jsx'; +import Svg from '../icons/svg.jsx'; +import Video from '../icons/video.jsx'; + +export default class FileType extends Component { + /* props : type (string) */ + constructor() { + super(); + } + render() { + var type = this.props.type; + var TypeIcon = Files; + switch (type) { + case 'link': + TypeIcon = Link; + break; + case 'code': + TypeIcon = Code; + break; + case 'document': + TypeIcon = Document; + break; + case 'image': + TypeIcon = Images; + break; + case 'pdf': + TypeIcon = Pdf; + break; + case 'slides': + TypeIcon = Slide; + break; + case 'audio': + TypeIcon = Sound; + break; + case 'spreadsheet': + TypeIcon = Spreadsheet; + break; + case 'svg': + TypeIcon = Svg; + break; + case 'video': + TypeIcon = Video; + break; + case 'archive': + TypeIcon = Archive; + break; + default: + } + return ; + } +} diff --git a/twake/frontend/src/app/components/drive/ui/file.jsx b/twake/frontend/src/app/components/drive/ui/file.jsx new file mode 100755 index 00000000..c2e308b4 --- /dev/null +++ b/twake/frontend/src/app/components/drive/ui/file.jsx @@ -0,0 +1,118 @@ +/* eslint-disable react/prop-types */ +/* eslint-disable react/jsx-key */ +import React from 'react'; +import moment from 'moment'; +import 'moment-timezone'; + +import Icon from 'app/components/icon/icon'; +import Menu from 'components/menus/menu'; +import DriveService from 'app/deprecated/Apps/Drive/Drive'; +import Numbers from 'app/features/global/utils/Numbers'; +import FileType from './file-type'; +import TagPicker from 'components/tag-picker/tag-picker'; +import { addApiUrlIfNeeded } from 'app/features/global/utils/URLUtils'; +import '../drive.scss'; +import { formatTime } from '@features/global/utils/Numbers'; + +export default class File extends React.Component { + constructor() { + super(); + } + render() { + var date = false; + if (this.props.data.modified) { + date = new Date(this.props.data.modified * 1000); + } + if (this.props.data.added && this.props.isVersion) { + date = new Date(this.props.data.added * 1000); + } + + var date_string = date ? formatTime(date) : '-'; + + return [ +
+
+ +
+
, +
+
+ +
+
+ {!!this.props.versionLabel &&
{this.props.versionLabel}
} + {this.props.data.name} + {!this.props.isVersion && (this.props.data.versions || {}).length > 1 && ( + + ({(this.props.data.versions || {}).length} versions) + + )} +    + +
+ + {(this.props.data.acces_info || {}).token && ( + + )} + {this.props.data.url && } + + {/* +
+ {this.state.element.created_by || "-"} +
+ */} + {this.props.details && [ +
{date_string}
, +
+ {this.props.data.size ? Numbers.humanFileSize(this.props.data.size, true) : '-'} +
, + ]} + {!this.props.isVersion && ( +
+
+
+ )} + {this.props.menu && this.props.menu.length > 0 && ( + + + + )} + + {this.props.removeIcon === true && ( + + )} +
, + ]; + } +} diff --git a/twake/frontend/src/app/components/drive/version-details.jsx b/twake/frontend/src/app/components/drive/version-details.jsx new file mode 100755 index 00000000..4a7bae3e --- /dev/null +++ b/twake/frontend/src/app/components/drive/version-details.jsx @@ -0,0 +1,128 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; +import Languages from 'app/features/global/services/languages-service'; +import Icon from 'app/components/icon/icon.jsx'; +import Collections from 'app/deprecated/CollectionsV1/Collections/Collections.js'; +import Workspaces from 'app/deprecated/workspaces/workspaces.jsx'; +import DriveService from 'app/deprecated/Apps/Drive/Drive.js'; +import UploadZone from 'components/uploads/upload-zone'; +import WorkspaceUserRights from 'app/features/workspaces/services/workspace-user-rights-service'; +import MediumPopupManager from 'app/components/modal/modal-manager'; +import { ObjectModal, ObjectModalTitle } from 'components/object-modal/deprecated-object-modal.jsx'; +import UIFile from './ui/file.jsx'; +import 'moment-timezone'; + +import './drive.scss'; + +export default class VersionDetails extends React.Component { + constructor() { + super(); + this.state = { + workspaces: Workspaces, + i18n: Languages, + }; + Languages.addListener(this); + DriveService.addListener(this); + Collections.get('drive').addListener(this); + } + componentWillUnmount() { + Languages.removeListener(this); + DriveService.removeListener(this); + Collections.get('drive').removeListener(this); + } + render() { + var countVersion = (this.props.file.versions || []).length; + return ( + MediumPopupManager.closeAll()} + footer={ +
+
+
{ + if (this.upload_zone) { + this.upload_zone.open(); + } + }} + > +
+ +
+
+ {Languages.t('components.drive.new_versions', [], 'Ajouter une nouvelle version')} +
+
+
+
+ } + title={ +
+ + {Languages.t('scenes.apps.drive.right_preview.versions', [], 'Versions')} + +
+ } + > +
+ (this.upload_zone = node)} + parent={this.props.file.parent_id} + driveCollectionKey={{ id: this.props.file.parent_id }} + uploadOptions={{ + workspace_id: this.state.workspaces.currentWorkspaceId, + new_version: true, + file_id: this.props.file.id, + }} + allowPaste={true} + > + {(this.props.file.versions || []) + .sort((a, b) => { + return b.added - a.added; + }) + .map((version, index) => { + var data = {}; + if (index > 0) { + data.extension = this.props.file.extension; + data.name = version.name; + data.creator = version.creator; + data.size = version.size; + } else { + data = JSON.parse(JSON.stringify(this.props.file)); + } + data.added = version.added; + return ( +
+ { + var link = DriveService.getLink(this.props.file, version.id, 1); + window.open(link); + }, + }, + ]} + details={true} + /> +
+ ); + })} +
+
+
+ ); + } +} diff --git a/twake/frontend/src/app/components/edit-channel/channel-access.tsx b/twake/frontend/src/app/components/edit-channel/channel-access.tsx new file mode 100644 index 00000000..7de5e929 --- /dev/null +++ b/twake/frontend/src/app/components/edit-channel/channel-access.tsx @@ -0,0 +1,101 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { Button } from 'app/atoms/button/button'; +import { BaseSmall } from 'app/atoms/text'; +import Switch from 'app/components/inputs/switch'; +import { ChannelType } from 'app/features/channels/types/channel'; +import Languages from 'app/features/global/services/languages-service'; +import Block from 'app/molecules/grouped-rows/base'; +import { useState } from 'react'; + +export const ChannelAccessForm = (props: { + channel?: ChannelType; + onChange: (change: { + visibility: 'private' | 'public'; + is_default: boolean; + is_readonly: boolean; + }) => void; +}) => { + const [visibility, setVisibility] = useState<'private' | 'public'>( + props.channel?.visibility || ('private' as any), + ); + const [isDefault, setIsDefault] = useState(props.channel?.is_default || false); + const [isReadOnly, setIsReadOnly] = useState(props.channel?.is_readonly || false); + const [loading, setLoading] = useState(false); + + return ( +
+ } + title={Languages.t('scenes.app.channelsbar.channel_access.visibility')} + subtitle={ + + {Languages.t('scenes.app.channelsbar.channel_access.visibility.info')} + + } + suffix={ + { + if (visibility === 'public') setIsDefault(false); + setVisibility(visibility === 'public' ? 'private' : 'public'); + }} + /> + } + /> + + } + title={Languages.t('scenes.app.channelsbar.channel_access.default')} + subtitle={ + + {Languages.t('scenes.app.channelsbar.channel_access.default.info')} + + } + suffix={ + { + setIsDefault(!isDefault); + if (visibility === 'private' && !isDefault) setVisibility('public'); + }} + /> + } + /> + + } + title={Languages.t('scenes.app.channelsbar.channel_access.readonly')} + subtitle={ + + {Languages.t('scenes.app.channelsbar.channel_access.readonly.info')} + + } + suffix={ + { + setIsReadOnly(!isReadOnly); + }} + /> + } + /> + +
+ +
+
+ ); +}; diff --git a/twake/frontend/src/app/components/edit-channel/channel-information.tsx b/twake/frontend/src/app/components/edit-channel/channel-information.tsx new file mode 100644 index 00000000..27fca977 --- /dev/null +++ b/twake/frontend/src/app/components/edit-channel/channel-information.tsx @@ -0,0 +1,248 @@ +import Avatar from 'app/atoms/avatar'; +import { Button } from 'app/atoms/button/button'; +import { Checkbox } from 'app/atoms/input/input-checkbox'; +import { InputLabel } from 'app/atoms/input/input-decoration-label'; +import Select from 'app/atoms/input/input-select'; +import { Input } from 'app/atoms/input/input-text'; +import A from 'app/atoms/link'; +import { Modal, ModalContent } from 'app/atoms/modal'; +import { usePublicOrPrivateChannels } from 'app/features/channels/hooks/use-public-or-private-channels'; +import { ChannelType } from 'app/features/channels/types/channel'; +import Languages from 'app/features/global/services/languages-service'; +import { getBase64 } from 'app/features/global/utils/strings'; +import Block from 'app/molecules/grouped-rows/base'; +import _ from 'lodash'; +import { useEffect, useState } from 'react'; +import Emojione from '../emojione/emojione'; + +const ChannelGroupSelector = (props: { group: string; onChange: (str: string) => void }) => { + const clean = (str?: string) => str?.toLocaleLowerCase().trim().replace(/ +/, ' '); + + const [group, setGroup] = useState(clean(props.group) || ''); + const [newGroup, setNewGroup] = useState(''); + const { publicChannels, privateChannels } = usePublicOrPrivateChannels(); + const groups = _.uniq( + [...publicChannels, ...privateChannels] + .filter(p => p.channel_group) + .map(p => clean(p.channel_group) || ''), + ).sort(); + + useEffect(() => { + if (!groups.includes(group) && !newGroup) setNewGroup(group); + }, [groups]); + + return ( +
+
+ + {groups.map(g => ( + } + title={_.capitalize(g)} + suffix={ + { + setGroup(v ? g : ''); + }} + value={g === group} + /> + } + subtitle={<>} + /> + ))} + + } + title={ +
+ { + setNewGroup(e.target.value); + setGroup(clean(e.target.value) || ''); + }} + value={newGroup} + className="" + placeholder={Languages.t('scenes.app.channelsbar.channel_information.group.new')} + /> +
+ } + suffix={ + { + setGroup(v ? newGroup : ''); + }} + value={!!group && clean(newGroup) === clean(group)} + /> + } + subtitle={<>} + /> + +
+ +
+
+ ); +}; + +export const ChannelInformationForm = (props: { + channel?: ChannelType; + onChange: (change: { + name: string; + icon: string; + description: string; + channel_group: string; + }) => void; +}) => { + const [channelGroupModal, setChannelGroupModal] = useState(false); + + const [group, setGroup] = useState(props.channel?.channel_group || ''); + const [name, setName] = useState(props.channel?.name || ''); + const [description, setDescription] = useState(props.channel?.description || ''); + const [icon, setIcon] = useState(props.channel?.icon || ''); + + return ( +
+ setChannelGroupModal(false)}> + + { + setChannelGroupModal(false); + setGroup(group); + }} + /> + + + + + + setName(e.target.value)} + /> + } + /> + + setDescription(e.target.value)} + multiline + /> + } + /> + + { + e.preventDefault(); + e.stopPropagation(); + setChannelGroupModal(group || ''); + }} + > + +
+ } + /> + +
+ +
+
+ ); +}; diff --git a/twake/frontend/src/app/components/edit-channel/channel-notifications.tsx b/twake/frontend/src/app/components/edit-channel/channel-notifications.tsx new file mode 100644 index 00000000..87247108 --- /dev/null +++ b/twake/frontend/src/app/components/edit-channel/channel-notifications.tsx @@ -0,0 +1,89 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { Checkbox } from 'app/atoms/input/input-checkbox'; +import { useChannelMemberCurrentUser } from 'app/features/channel-members-search/hooks/member-hook'; +import { ChannelType } from 'app/features/channels/types/channel'; +import Languages from 'app/features/global/services/languages-service'; +import { ToasterService } from 'app/features/global/services/toaster-service'; +import Block from 'app/molecules/grouped-rows/base'; +import { useState } from 'react'; + +export const ChannelNotificationsForm = (props: { channel?: ChannelType; onBack: () => void }) => { + const { member, setNotificationPreference } = useChannelMemberCurrentUser( + props.channel?.id || '', + ); + const [value, _setValue] = useState(member?.notification_level || 'all'); + + const setValue = (value: any) => { + _setValue(value); + setNotificationPreference(value).finally(() => ToasterService.success('Updated')); + props.onBack(); + }; + + return ( +
+ } + title={Languages.t('scenes.apps.messages.left_bar.stream.notifications.all')} + subtitle={<>} + suffix={ + { + setValue('all'); + }} + /> + } + /> + + } + title={Languages.t('scenes.apps.messages.left_bar.stream.notifications.mentions', [ + '@all', + '@here', + `@[you]`, + ])} + subtitle={<>} + suffix={ + { + setValue('mentions'); + }} + /> + } + /> + + } + title={Languages.t('scenes.apps.messages.left_bar.stream.notifications.me', [`@[you]`])} + subtitle={<>} + suffix={ + { + setValue('me'); + }} + /> + } + /> + + } + title={Languages.t('scenes.apps.messages.left_bar.stream.notifications.never')} + subtitle={<>} + suffix={ + { + setValue('none'); + }} + /> + } + /> +
+ ); +}; diff --git a/twake/frontend/src/app/components/edit-channel/channel-settings-menu.tsx b/twake/frontend/src/app/components/edit-channel/channel-settings-menu.tsx new file mode 100644 index 00000000..10ffe838 --- /dev/null +++ b/twake/frontend/src/app/components/edit-channel/channel-settings-menu.tsx @@ -0,0 +1,368 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +/* eslint-disable @typescript-eslint/ban-types */ +import { + BellIcon, + ChevronRightIcon, + HandIcon, + LinkIcon, + LogoutIcon, + PhotographIcon, + StarIcon, + TrashIcon, +} from '@heroicons/react/outline'; +import { StarIcon as StarIconSolid } from '@heroicons/react/solid'; +import Avatar from 'app/atoms/avatar'; +import { UsersIcon } from 'app/atoms/icons-agnostic'; +import A from 'app/atoms/link'; +import { Loader } from 'app/atoms/loader'; +import { Base, Info } from 'app/atoms/text'; +import { useChannelMemberCurrentUser } from 'app/features/channel-members-search/hooks/member-hook'; +import ChannelsMineAPIClient from 'app/features/channels/api/channels-mine-api-client'; +import { useFavoriteChannels } from 'app/features/channels/hooks/use-favorite-channels'; +import { ChannelType } from 'app/features/channels/types/channel'; +import { isDirectChannel, isPrivateChannel } from 'app/features/channels/utils/utils'; +import AlertManager from 'app/features/global/services/alert-manager-service'; +import Languages from 'app/features/global/services/languages-service'; +import { ToasterService } from 'app/features/global/services/toaster-service'; +import { copyToClipboard } from 'app/features/global/utils/CopyClipboard'; +import RouterServices from 'app/features/router/services/router-service'; +import { useCurrentUser } from 'app/features/users/hooks/use-current-user'; +import workspaceUserRightsService from 'app/features/workspaces/services/workspace-user-rights-service'; +import Block from 'app/molecules/grouped-rows/base'; +import { addUrlTryDesktop } from 'app/views/desktop-redirect'; +import { useState } from 'react'; + +export const ChannelSettingsMenu = (props: { + channel?: ChannelType; + onEditChannel?: Function; + onAccess?: Function; + onMedias?: Function; + onNotifications?: Function; + onMembers?: Function; + onFavorite?: Function; + onClose?: Function; +}) => { + const icon = props.channel?.icon || ''; + const name = props.channel?.name || ''; + + const { user } = useCurrentUser(); + const canEdit = + props.channel?.owner === user?.id || workspaceUserRightsService.hasWorkspacePrivilege(); + const isGuest = workspaceUserRightsService.isInvite(); + const isDirect = isDirectChannel(props.channel?.visibility || ''); + const canLeave = !isGuest || isDirect; + const canRemove = + user?.id === props.channel?.owner || workspaceUserRightsService.hasWorkspacePrivilege(); + + return ( +
+ {!isDirect && ( + <> + { + canEdit && props.onEditChannel && props.onEditChannel(); + }} + className={ + '-mx-2 my-2 p-2 rounded-md ' + + (canEdit ? 'cursor-pointer hover:bg-blue-50 dark:hover:bg-zinc-800' : '') + } + title={{name || ''}} + subtitle={ + canEdit ? ( + + {Languages.t('scenes.app.channelsbar.channel_information')} + + ) : ( + <> + ) + } + avatar={ 20 ? icon : ''} title={name || ''} />} + suffix={canEdit ? : <>} + /> + {canRemove && } + +
+ { + canEdit && props.onAccess && props.onAccess(); + }} + className={ + '-mx-2 my-1 p-2 rounded-md ' + + (canEdit ? 'cursor-pointer hover:bg-blue-50 dark:hover:bg-zinc-800' : '') + } + title={ + + {Languages.t('scenes.app.channelsbar.channel_access')} + + } + subtitle={<>} + avatar={} + suffix={ +
+ + {props.channel?.visibility === 'public' ? 'Public' : 'Private'} + + {canEdit ? : <> } +
+ } + /> + {!isGuest && !!props.onMembers && ( + { + props.onMembers && props.onMembers(); + }} + className={ + '-mx-2 my-1 p-2 rounded-md ' + + (canEdit ? 'cursor-pointer hover:bg-blue-50 dark:hover:bg-zinc-800' : '') + } + title={ + + {Languages.t('scenes.apps.parameters.workspace_sections.members')} + + } + subtitle={<>} + avatar={} + suffix={} + /> + )} + + )} + { + props.onMedias && props.onMedias(); + }} + className="-mx-2 my-1 p-2 rounded-md cursor-pointer hover:bg-blue-50 dark:hover:bg-zinc-800" + title={ + + {Languages.t('components.channel_attachement_list.title')} + + } + subtitle={<>} + avatar={} + suffix={} + /> +
+ + { + const url = addUrlTryDesktop( + `${document.location.origin}${RouterServices.generateRouteFromState({ + workspaceId: props.channel?.workspace_id || '', + companyId: props.channel?.company_id, + channelId: props.channel?.id, + })}`, + ); + copyToClipboard(url); + ToasterService.success(Languages.t('components.input.copied')); + }} + className={ + '-mx-2 my-1 p-2 rounded-md cursor-pointer hover:bg-blue-50 dark:hover:bg-zinc-800' + } + title={ + + {Languages.t('scenes.app.channelsbar.channel_copy_link')} + + } + subtitle={<>} + avatar={} + suffix={<>} + /> + + {!isDirect && ( + { + props.onNotifications && props.onNotifications(); + }} + /> + )} + + {canLeave && } +
+
+ ); +}; + +const RemoveBlock = (props: { channel?: ChannelType; onLeave?: Function }) => { + const { refresh: refreshAllChannels } = useFavoriteChannels(); + const [loading, setLoading] = useState(false); + + return ( + { + AlertManager.confirm(async () => { + setLoading(true); + await ChannelsMineAPIClient.removeChannel( + props.channel?.company_id || '', + props.channel?.workspace_id || '', + props.channel?.id || '', + ); + await refreshAllChannels(); + + RouterServices.push( + RouterServices.generateRouteFromState({ + companyId: props.channel?.company_id || '', + workspaceId: props.channel?.workspace_id || '', + channelId: '', + }), + ); + + props.onLeave && props.onLeave(); + }); + }} + className="-mx-2 my-1 p-2 rounded-md cursor-pointer hover:bg-red-50 dark:hover:bg-red-800" + title={ + + {Languages.t('scenes.app.channelsbar.channel_removing')} + + } + subtitle={<>} + avatar={ + loading ? ( + + ) : ( + + ) + } + /> + ); +}; + +const LeaveBlock = (props: { channel?: ChannelType; onLeave?: Function }) => { + const { refresh: refreshAllChannels } = useFavoriteChannels(); + const { user } = useCurrentUser(); + const [loading, setLoading] = useState(false); + + const leaveChannel = async (isDirectChannel = false) => { + setLoading(true); + if (props.channel?.id && props.channel?.company_id && props.channel.workspace_id) { + const res = await ChannelsMineAPIClient.removeUser(user?.id || '', { + companyId: props.channel.company_id, + workspaceId: isDirectChannel ? 'direct' : props.channel.workspace_id, + channelId: props.channel.id, + }); + + if (res?.error?.length && res?.message?.length) { + ToasterService.error(`${res.error} - ${res.message}`); + } else { + await refreshAllChannels(); + + RouterServices.push( + RouterServices.generateRouteFromState({ + companyId: props.channel?.company_id || '', + workspaceId: props.channel?.workspace_id || '', + channelId: '', + }), + ); + + props.onLeave && props.onLeave(); + } + await refreshAllChannels(); + } + + setLoading(false); + }; + + return ( + { + if (props.channel!.visibility) { + if (isPrivateChannel(props.channel!.visibility)) { + return AlertManager.confirm(() => leaveChannel(), undefined, { + title: Languages.t('components.alert.leave_private_channel.title'), + text: Languages.t('components.alert.leave_private_channel.description'), + }); + } + if (isDirectChannel(props.channel!.visibility)) { + return leaveChannel(true); + } + } + + return leaveChannel(); + }} + className="-mx-2 my-1 p-2 rounded-md cursor-pointer hover:bg-red-50 dark:hover:bg-red-800" + title={ + + {Languages.t('scenes.app.channelsbar.channel_leaving')} + + } + subtitle={<>} + avatar={ + loading ? ( + + ) : ( + + ) + } + /> + ); +}; + +const NotificationsBlock = (props: { channel?: ChannelType; onClick: Function }) => { + const { member } = useChannelMemberCurrentUser(props.channel?.id || ''); + + return ( + { + props.onClick(); + }} + className="-mx-2 my-1 p-2 rounded-md cursor-pointer hover:bg-blue-50 dark:hover:bg-zinc-800" + title={ + + {Languages.t('scenes.app.channelsbar.currentuser.user_parameter')} + + } + subtitle={<>} + avatar={} + suffix={ +
+ + {member?.notification_level === 'all' && + Languages.t('scenes.apps.messages.left_bar.stream.notifications.all')} + {member?.notification_level === 'mentions' && '@all, @[you]'} + {member?.notification_level === 'me' && + Languages.t('scenes.apps.messages.left_bar.stream.notifications.me', [`@[you]`])} + {member?.notification_level === 'none' && + Languages.t('scenes.apps.messages.left_bar.stream.notifications.never')} + + +
+ } + /> + ); +}; + +const FavoriteBlock = (props: { channel?: ChannelType }) => { + const { favorite, setFavorite } = useChannelMemberCurrentUser(props.channel?.id || ''); + const [loading, setLoading] = useState(false); + + return ( + { + setLoading(true); + await setFavorite(!favorite); + setLoading(false); + }} + className="-mx-2 my-1 p-2 rounded-md cursor-pointer hover:bg-blue-50 dark:hover:bg-zinc-800" + title={ + + {Languages.t( + favorite + ? 'scenes.apps.messages.left_bar.stream.remove_from_favorites' + : 'scenes.apps.messages.left_bar.stream.add_to_favorites', + )} + + } + subtitle={<>} + avatar={ + loading ? ( + + ) : favorite ? ( + + ) : ( + + ) + } + /> + ); +}; diff --git a/twake/frontend/src/app/components/edit-channel/index.tsx b/twake/frontend/src/app/components/edit-channel/index.tsx new file mode 100644 index 00000000..dc97247a --- /dev/null +++ b/twake/frontend/src/app/components/edit-channel/index.tsx @@ -0,0 +1,261 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +import { Transition } from '@headlessui/react'; +import { ChevronLeftIcon } from '@heroicons/react/outline'; +import A from 'app/atoms/link'; +import { Loader } from 'app/atoms/loader'; +import { Modal, ModalContent } from 'app/atoms/modal'; +import { useUsersSearchModal } from 'app/features/channel-members-search/state/search-channel-member'; +import ChannelAPIClient from 'app/features/channels/api/channel-api-client'; +import { useChannel } from 'app/features/channels/hooks/use-channel'; +import { useFavoriteChannels } from 'app/features/channels/hooks/use-favorite-channels'; +import { channelAttachmentListState } from 'app/features/channels/state/channel-attachment-list'; +import { ChannelType } from 'app/features/channels/types/channel'; +import useRouteState from 'app/features/router/hooks/use-route-state'; +import { useEffect, useState } from 'react'; +import { atom, useRecoilState, useSetRecoilState } from 'recoil'; +import { slideXTransition, slideXTransitionReverted } from 'src/utils/transitions'; +import { ChannelAccessForm } from './channel-access'; +import { ChannelInformationForm } from './channel-information'; +import { ChannelNotificationsForm } from './channel-notifications'; +import { ChannelSettingsMenu } from './channel-settings-menu'; +import RouterServices from '@features/router/services/router-service'; +import Languages from 'app/features/global/services/languages-service'; + +const EditChannelModalAtom = atom({ + key: 'EditChannelModalAtom', + default: { + open: false, + channelId: '', + }, +}); + +export const useOpenChannelModal = () => { + const setModal = useSetRecoilState(EditChannelModalAtom); + return (channelId: string) => setModal({ open: true, channelId }); +}; + +export const EditChannelModal = () => { + const [channelModal, setChannelModal] = useRecoilState(EditChannelModalAtom); + + return ( + setChannelModal({ ...channelModal, open: false })} + className="int-channel-edit-modal !max-w-sm" + > + {!channelModal.channelId && } + {!!channelModal.channelId && } + + ); +}; + +const EditChannelForm = () => { + const [channelModal, setChannelModal] = useRecoilState(EditChannelModalAtom); + const [page, setPage] = useState<'information' | 'access' | 'notifications' | 'menu'>('menu'); + const { setOpen: setParticipantsOpen } = useUsersSearchModal(); + const [, setChannelAttachmentState] = useRecoilState(channelAttachmentListState); + const { refresh } = useFavoriteChannels(); + + const { channel } = useChannel(channelModal.channelId); + + return ( + + {page !== 'menu' && ( + setPage('menu')}> + + + )} + {Languages.t('scenes.app.channelsbar.modify_channel_menu')} +
+ } + > +
+ +
+ + setPage('information')} + onAccess={() => setPage('access')} + onNotifications={() => setPage('notifications')} + onClose={() => { + setChannelModal({ ...channelModal, open: false }); + }} + onMembers={() => { + setChannelModal({ ...channelModal, open: false }); + setTimeout(() => setParticipantsOpen(true), 500); + }} + onMedias={() => { + setChannelModal({ ...channelModal, open: false }); + setTimeout(() => setChannelAttachmentState(true), 500); + }} + channel={channel} + /> + + + { + setPage('menu'); + await ChannelAPIClient.save( + { ...channel, ...changes }, + { + companyId: channel.company_id!, + workspaceId: channel.workspace_id!, + channelId: channel.id, + }, + ); + await refresh(); + }} + channel={channel} + /> + + + { + await ChannelAPIClient.save( + { ...channel, ...changes }, + { + companyId: channel.company_id!, + workspaceId: channel.workspace_id!, + channelId: channel.id, + }, + ); + await refresh(); + setPage('menu'); + }} + channel={channel} + /> + + + setPage('menu')} channel={channel} /> + +
+ + ); +}; + +const CreateChannelForm = () => { + const setChannelModal = useSetRecoilState(EditChannelModalAtom); + const { setOpen: setParticipantsOpen } = useUsersSearchModal(); + const { companyId, workspaceId } = useRouteState(); + const { refresh } = useFavoriteChannels(); + + const [step, setStep] = useState(0); + const [channel, setChannel] = useState>({}); + + useEffect(() => { + if (step === 2) { + (async () => { + const created = await ChannelAPIClient.save(channel, { + companyId: companyId!, + workspaceId: workspaceId!, + }); + await refresh(); + RouterServices.push(RouterServices.generateRouteFromState({ channelId: created.id })); + setChannelModal({ open: false, channelId: '' }); + setTimeout(() => { + setParticipantsOpen(true); + }, 500); + })(); + } + }, [step]); + + return ( + +
+ +
+ + { + setStep(1); + setChannel({ ...channel, ...changes }); + }} + /> + + + + { + setStep(2); + setChannel({ ...channel, ...changes }); + }} + /> + + + +
+ +
+
+
+
+ ); +}; diff --git a/twake/frontend/src/app/components/editable-text/editable-text.jsx b/twake/frontend/src/app/components/editable-text/editable-text.jsx new file mode 100755 index 00000000..acb509c4 --- /dev/null +++ b/twake/frontend/src/app/components/editable-text/editable-text.jsx @@ -0,0 +1,26 @@ +import React, { Component } from 'react'; +import './editable-text.scss'; + +import Input from 'components/inputs/input.jsx'; + +export default class EditableText extends React.Component { + constructor(props) { + super(); + this.props = props; + + this.state = { + value: '#FF0000', + }; + } + render() { + return ( +
+ this.setState({ value: evt.target.value })} + /> +
+
+ ); + } +} diff --git a/twake/frontend/src/app/components/editable-text/editable-text.scss b/twake/frontend/src/app/components/editable-text/editable-text.scss new file mode 100755 index 00000000..b44898cd --- /dev/null +++ b/twake/frontend/src/app/components/editable-text/editable-text.scss @@ -0,0 +1,19 @@ +.color_input { + position: relative; + + .color_square { + position: absolute; + left: 8px; + top: 8px; + width: 24px; + height: 24px; + border-radius: var(--border-radius-base); + } + + input { + background: #888; + padding-left: 40px !important; + box-sizing: border-box; + width: 120px; + } +} diff --git a/twake/frontend/src/app/components/emoji-picker/emoji-picker.jsx b/twake/frontend/src/app/components/emoji-picker/emoji-picker.jsx new file mode 100755 index 00000000..e232d9c8 --- /dev/null +++ b/twake/frontend/src/app/components/emoji-picker/emoji-picker.jsx @@ -0,0 +1,142 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; +import { Picker } from 'emoji-mart'; +import Emojione from 'components/emojione/emojione'; +import { getAsFrontUrl } from 'app/features/global/utils/URLUtils'; +import './emoji-picker.scss'; +import 'emoji-mart/css/emoji-mart.css'; +import Languages from 'app/features/global/services/languages-service'; +import { isArray } from 'lodash'; + +Picker.defaultProps.backgroundImageFn = function backgroundImageFn(set, sheetSize) { + sheetSize = 20; + return getAsFrontUrl( + '/public/emoji-datasource/'.concat(set, '/sheets-256/').concat(sheetSize, '.png'), + ); +}; +export default class EmojiPicker extends React.Component { + /* + props = { + preferedEmoji : Array of emoji's shortname + onChange : called when a smiley is selected + } + */ + constructor(props) { + super(); + this.props = props; + this.state = { + suggestions: [], + currentTitle: '', + availableCategories: [], + scrollToRow: 0, + loaded: false, + }; + this.currentTitleIndex = 100000; + this.clickScrollToRow = 0; + } + onChange(list) { + if (list.length > 0) { + if (this.props.onChange) { + this.props.onChange(list[0]); + } + this.setState({ list: [] }); + } + } + renderItemChoosen(item) { + return ( +
+ +
+ ); + } + renderItem(item) { + return ( +
+ +
+ ); + } + scrollToCategory(category) { + var index = 0; + this.state.suggestions.forEach((item, i) => { + if (item.value == category) { + index = i; + return false; + } + }); + this.clickScrollToRow = index; + if (this.state.scrollToRow != index) { + this.setState({ scrollToRow: index }); + } else { + this.list_node.forceUpdateGrid(); + } + } + select(emoji) { + if (this.picker) { + this.picker.onSelect(emoji); + } else { + this.onChange([emoji]); + } + } + getPrefered() { + var pref = this.props.preferedEmoji || [ + ':thumbsup:', + ':thumbsdown:', + ':hearts:', + ':tada:', + ':smile:', + ':confused:', + ]; + if ( + typeof this.props.selected === 'string' && + this.props.selected && + pref.indexOf(this.props.selected) < 0 + ) { + pref.unshift(this.props.selected); + } + if (isArray(this.props.selected)) { + this.props.selected.forEach(s => pref.unshift(s)); + } + return pref; + } + componentDidMount() { + setTimeout(() => { + this.setState({ loaded: true }); + }, 300); + } + render() { + if (!this.state.loaded) { + return
; + } + return ( +
+ +
+ ); + } +} diff --git a/twake/frontend/src/app/components/emoji-picker/emoji-picker.scss b/twake/frontend/src/app/components/emoji-picker/emoji-picker.scss new file mode 100755 index 00000000..98fa496f --- /dev/null +++ b/twake/frontend/src/app/components/emoji-picker/emoji-picker.scss @@ -0,0 +1,19 @@ +.emoji-mart { + border: none; + color: var(--grey-dark); + font-size: 14px; + width: unset !important; + left: 0px; + .emoji-mart-emoji { + padding: 7px; + } +} + +.emoji-mart-search > input { + padding-top: 6px; + font-size: 14px; +} +.emoji-mart-emoji { + display: inline-flex; + align-items: center; +} diff --git a/twake/frontend/src/app/components/emojione/emojione.scss b/twake/frontend/src/app/components/emojione/emojione.scss new file mode 100755 index 00000000..80051e3c --- /dev/null +++ b/twake/frontend/src/app/components/emojione/emojione.scss @@ -0,0 +1,39 @@ +/* Emojione */ + +img.emojione { + width: 18px; + height: 18px; + bottom: 0px; + display: inline-block; + position: relative; + vertical-align: middle; +} + +i.emojione.emoji-image { + width: 1em; + height: 1em; + display: inline-block; + background-size: contain; + background-position: center; + vertical-align: middle; + margin-top: -4px; + font-size: 1.1em; +} + +.trash_emoji { + font-size: 16px; + position: relative; + top: 1px; +} + +.emoji-container { + vertical-align: middle; + display: inline-flex; + + &.emoji-text .emoji-container { + &, + img.emojione { + vertical-align: top; + } + } +} diff --git a/twake/frontend/src/app/components/emojione/emojione.tsx b/twake/frontend/src/app/components/emojione/emojione.tsx new file mode 100755 index 00000000..716394a6 --- /dev/null +++ b/twake/frontend/src/app/components/emojione/emojione.tsx @@ -0,0 +1,109 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React, { Component } from 'react'; + +import 'emoji-mart/css/emoji-mart.css'; + +import { getEmojiDataFromNative, Emoji } from 'emoji-mart'; +import data from 'emoji-mart/data/all.json'; + +import emojione from 'emojione'; +import Icon from 'app/components/icon/icon.jsx'; + +import './emojione.scss'; +import { getAsFrontUrl } from 'app/features/global/utils/URLUtils'; + +type Props = { + type: string; + size?: number; + className?: string; + s64?: boolean; + s128?: boolean; + emoji?: string; +}; + +const type_to_uni: any = {}; + +const getFromEmojione = (props: Props) => { + //Use from local server + let html: string | '' = ''; + html = emojione.toImage(props.type || props.emoji || ''); + html = html?.replace('https://cdn.jsdelivr.net/emojione/assets/3.1/png/', '/public/emojione/'); + + if (props.s64) { + html = html?.replace('/32/', '/64/'); + } else if (props.s128) { + html = html?.replace('/32/', '/128/'); + } + return { __html: html }; +}; + +class EmojioneFallback extends Component { + // WIP + render() { + return ( + + ); + } +} + +const Emojione = React.memo((props: Props) => { + if (typeof props.type != 'string') { + return <>; + } + + if (props.type === 'trash') { + return ; + } + + if (props.type.substr(0, 7) === ':twake-') { + return ( + + ); + } + + if (props.type.substr(0, 7) === 'http://' || props.type.substr(0, 8) === 'https://') { + return ( + + ); + } + + let size = props.size || 16; + if (size > 32 || props.s64 || props.s128) { + return ; + } + + const uni = + type_to_uni[props.type] || + getEmojiDataFromNative(emojione.shortnameToUnicode(props.type), 'apple', data); + type_to_uni[props.type] = uni; + + return ( + + { + if ([16, 20, 32, 64].indexOf(size) < 0) { + size = 64; + } + return getAsFrontUrl( + '/public/emoji-datasource/'.concat(set, '/sheets-256/').concat(size.toString(), '.png'), + ); + }} + emoji={uni || props.type} + set="apple" + size={size} + fallback={() => } + /> + + ); +}); + +export default Emojione; diff --git a/twake/frontend/src/app/components/file-uploads/pending-file-components/pending-file-row.tsx b/twake/frontend/src/app/components/file-uploads/pending-file-components/pending-file-row.tsx new file mode 100644 index 00000000..ba47ec81 --- /dev/null +++ b/twake/frontend/src/app/components/file-uploads/pending-file-components/pending-file-row.tsx @@ -0,0 +1,195 @@ +import React from 'react'; +import { PauseCircle, PlayCircle, Trash2 } from 'react-feather'; +import { Row, Col, Typography, Divider, Progress, Button, Tooltip } from 'antd'; +import { capitalize } from 'lodash'; + +import { + isPendingFileStatusCancel, + isPendingFileStatusError, + isPendingFileStatusPause, + isPendingFileStatusPending, + isPendingFileStatusSuccess, +} from '../../../features/files/utils/pending-files'; +import Languages from 'app/features/global/services/languages-service'; +import { useUpload } from 'app/features/files/hooks/use-upload'; +import { PendingFileRecoilType, PendingFileType } from 'app/features/files/types/file'; + +import '../../file/file.scss'; + +type PropsType = { + pendingFileState: PendingFileRecoilType; + pendingFile: PendingFileType; +}; + +const { Text } = Typography; +export default ({ pendingFileState, pendingFile }: PropsType) => { + const { pauseOrResumeUpload, cancelUpload } = useUpload(); + + const getProgressStrokeColor = (status: PendingFileRecoilType['status']) => { + if (isPendingFileStatusCancel(status)) return 'var(--error)'; + if (isPendingFileStatusError(status)) return 'var(--error)'; + if (isPendingFileStatusPause(status)) return 'var(--warning)'; + if (isPendingFileStatusPending(status)) return 'var(--progress-bar-color)'; + + return 'var(--success)'; + }; + + const setStatus = () => { + switch (pendingFileState.status) { + case 'error': + case 'pause': + case 'cancel': + return 'exception'; + case 'pending': + return 'active'; + case 'success': + return 'success'; + default: + return 'normal'; + } + }; + + return ( +
+ + + {pendingFile?.originalFile.name ? ( + + + {capitalize(pendingFile?.originalFile.name)} + + {isPendingFileStatusPause(pendingFile.status) && ( + + {/* TODO Add translation here */} + (paused) + + )} + + ) : ( +
+ )} + + + + {pendingFileState.id ? ( + !isPendingFileStatusSuccess(pendingFileState.status) && + !isPendingFileStatusError(pendingFileState.status) ? ( + + + + ); +}; diff --git a/twake/frontend/src/app/components/highlighted-code/highlighted-code.tsx b/twake/frontend/src/app/components/highlighted-code/highlighted-code.tsx new file mode 100755 index 00000000..b665270c --- /dev/null +++ b/twake/frontend/src/app/components/highlighted-code/highlighted-code.tsx @@ -0,0 +1,52 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React, { useEffect, useState } from 'react'; +import hljs from 'highlight.js'; +import 'highlight.js/styles/railscasts.css'; //monokai-sublime +import { Copy } from 'react-feather'; +import { Tooltip } from 'antd'; +import { ToasterService } from 'app/features/global/services/toaster-service'; + +export default ({ code, className }: { code: string; className?: string }) => { + let renderedCode = code.replace(/\t/g, ' '); + + const [expanded, setExpanded] = useState(renderedCode.split('\n').length < 5); + const ref = React.createRef(); + + useEffect(() => { + hljs.highlightElement(ref.current); + }, [expanded]); + + renderedCode = renderedCode + .split('\n') + .slice(0, expanded ? 100000000 : 5) + .join('\n'); + + const copy = () => { + navigator.clipboard.writeText(code).then(function () { + ToasterService.success('Content copied!'); + }); + }; + + return ( +
+
+        {renderedCode}
+      
+ {!expanded && ( + { + setExpanded(true); + }} + > + Click to expand ({code.split('\n').length} lines) + + )} + + + + + +
+ ); +}; diff --git a/twake/frontend/src/app/components/icon/animation.scss b/twake/frontend/src/app/components/icon/animation.scss new file mode 100755 index 00000000..53eb9893 --- /dev/null +++ b/twake/frontend/src/app/components/icon/animation.scss @@ -0,0 +1,413 @@ +/* Spin Animation Start */ +.animate.spin { + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + -webkit-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; + display: inline-block; +} + +.animate.spin-slow { + -moz-animation: spin 4s infinite linear; + -o-animation: spin 4s infinite linear; + -webkit-animation: spin 4s infinite linear; + animation: spin 4s infinite linear; + display: inline-block; +} + +.animate.spin-fast { + -moz-animation: spin 1s infinite linear; + -o-animation: spin 1s infinite linear; + -webkit-animation: spin 1s infinite linear; + animation: spin 1s infinite linear; + display: inline-block; +} + +@keyframes spin { + 0% { + -moz-transform: rotate(0deg); + -o-transform: rotate(0deg); + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + 100% { + -moz-transform: rotate(359deg); + -o-transform: rotate(359deg); + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} + +@-moz-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + -o-transform: rotate(0deg); + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + 100% { + -moz-transform: rotate(359deg); + -o-transform: rotate(359deg); + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} + +@-o-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + -o-transform: rotate(0deg); + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + 100% { + -moz-transform: rotate(359deg); + -o-transform: rotate(359deg); + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} + +@-webkit-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + -o-transform: rotate(0deg); + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + 100% { + -moz-transform: rotate(359deg); + -o-transform: rotate(359deg); + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} + +@-ms-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + -o-transform: rotate(0deg); + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + 100% { + -moz-transform: rotate(359deg); + -o-transform: rotate(359deg); + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} + +/* Spin Animation End */ + +/* Pulse Animation Start */ + +.animate.pulse { + -moz-animation: pulse 2s infinite linear; + -o-animation: pulse 2s infinite linear; + -webkit-animation: pulse 2s infinite linear; + animation: pulse 2s infinite linear; + display: inline-block; +} + +.animate.pulse-slow { + -moz-animation: pulse 4s infinite linear; + -o-animation: pulse 4s infinite linear; + -webkit-animation: pulse 4s infinite linear; + animation: pulse 4s infinite linear; + display: inline-block; +} + +.animate.pulse-fast { + -moz-animation: pulse 1s infinite linear; + -o-animation: pulse 1s infinite linear; + -webkit-animation: pulse 1s infinite linear; + animation: pulse 1s infinite linear; + display: inline-block; +} + +@keyframes pulse { + 50% { + -moz-transform: scale(0.5); + -o-transform: scale(0.5); + -webkit-transform: scale(0.5); + transform: scale(0.5); + } +} + +@-moz-keyframes pulse { + 50% { + -moz-transform: scale(0.5); + -o-transform: scale(0.5); + -webkit-transform: scale(0.5); + transform: scale(0.5); + } +} + +@-o-keyframes pulse { + 50% { + -moz-transform: scale(0.5); + -o-transform: scale(0.5); + -webkit-transform: scale(0.5); + transform: scale(0.5); + } +} + +@-webkit-keyframes pulse { + 50% { + -moz-transform: scale(0.5); + -o-transform: scale(0.5); + -webkit-transform: scale(0.5); + transform: scale(0.5); + } +} + +@-ms-keyframes pulse { + 50% { + -moz-transform: scale(0.5); + -o-transform: scale(0.5); + -webkit-transform: scale(0.5); + transform: scale(0.5); + } +} + +/* Pulse Animation End */ + +/* Vibrate Animation Start */ + +.animate.vibrate { + -moz-animation: vibrate 0.1s infinite linear; + -o-animation: vibrate 0.1s infinite linear; + -webkit-animation: vibrate 0.1s infinite linear; + animation: vibrate 0.1s infinite linear; + display: inline-block; +} + +.animate.vibrate-slow { + -moz-animation: vibrate 0.2s infinite linear; + -o-animation: vibrate 0.2s infinite linear; + -webkit-animation: vibrate 0.2s infinite linear; + animation: vibrate 0.2s infinite linear; + display: inline-block; +} + +.animate.vibrate-fast { + -moz-animation: vibrate 0.07s infinite linear; + -o-animation: vibrate 0.07s infinite linear; + -webkit-animation: vibrate 0.07s infinite linear; + animation: vibrate 0.07s infinite linear; + display: inline-block; +} + +@keyframes vibrate { + 25% { + -moz-transform: translate(-2px); + -o-transform: translate(-2px); + -webkit-transform: translate(-2px); + transform: translate(-2px); + } + + 75% { + -moz-transform: translate(2px); + -o-transform: translate(2px); + -webkit-transform: translate(2px); + transform: translate(2px); + } +} + +@-moz-keyframes vibrate { + 25% { + -moz-transform: translate(-2px); + -o-transform: translate(-2px); + -webkit-transform: translate(-2px); + transform: translate(-2px); + } + + 75% { + -moz-transform: translate(2px); + -o-transform: translate(2px); + -webkit-transform: translate(2px); + transform: translate(2px); + } +} + +@-o-keyframes vibrate { + 25% { + -moz-transform: translate(-2px); + -o-transform: translate(-2px); + -webkit-transform: translate(-2px); + transform: translate(-2px); + } + + 75% { + -moz-transform: translate(2px); + -o-transform: translate(2px); + -webkit-transform: translate(2px); + transform: translate(2px); + } +} + +@-webkit-keyframes vibrate { + 25% { + -moz-transform: translate(-2px); + -o-transform: translate(-2px); + -webkit-transform: translate(-2px); + transform: translate(-2px); + } + + 75% { + -moz-transform: translate(2px); + -o-transform: translate(2px); + -webkit-transform: translate(2px); + transform: translate(2px); + } +} + +@-ms-keyframes vibrate { + 25% { + -moz-transform: translate(-2px); + -o-transform: translate(-2px); + -webkit-transform: translate(-2px); + transform: translate(-2px); + } + + 75% { + -moz-transform: translate(2px); + -o-transform: translate(2px); + -webkit-transform: translate(2px); + transform: translate(2px); + } +} + +/* Vibrate Animation End */ + +/* Blink Smooth Animation Start */ + +.animate.blink-smooth { + -moz-animation: blink-s 0.8s infinite linear; + -o-animation: blink-s 0.8s infinite linear; + -webkit-animation: blink-s 0.8s infinite linear; + animation: blink-s 0.8s infinite linear; + display: inline-block; +} + +.animate.blink-smooth-slow { + -moz-animation: blink-s 1.2s infinite linear; + -o-animation: blink-s 1.2s infinite linear; + -webkit-animation: blink-s 1.2s infinite linear; + animation: blink-s 1.2s infinite linear; + display: inline-block; +} + +.animate.blink-smooth-fast { + -moz-animation: blink-s 0.4s infinite linear; + -o-animation: blink-s 0.4s infinite linear; + -webkit-animation: blink-s 0.4s infinite linear; + animation: blink-s 0.4s infinite linear; + display: inline-block; +} + +@keyframes blink-s { + 50% { + opacity: 0; + filter: alpha(opacity=100); + } +} + +@-moz-keyframes blink-s { + 50% { + opacity: 0; + filter: alpha(opacity=100); + } +} + +@-o-keyframes blink-s { + 50% { + opacity: 0; + filter: alpha(opacity=100); + } +} + +@-webkit-keyframes blink-s { + 50% { + opacity: 0; + filter: alpha(opacity=100); + } +} + +@-ms-keyframes blink-s { + 50% { + opacity: 0; + filter: alpha(opacity=100); + } +} + +/* Blink Smooth Animation End */ + +/* Blink Animation Start */ + +.animate.blink { + -moz-animation: blink 0.8s infinite linear; + -o-animation: blink 0.8s infinite linear; + -webkit-animation: blink 0.8s infinite linear; + animation: blink 0.8s infinite linear; + display: inline-block; +} + +.animate.blink-slow { + -moz-animation: blink 1.2s infinite linear; + -o-animation: blink 1.2s infinite linear; + -webkit-animation: blink 1.2s infinite linear; + animation: blink 1.2s infinite linear; + display: inline-block; +} + +.animate.blink-fast { + -moz-animation: blink 0.4s infinite linear; + -o-animation: blink 0.4s infinite linear; + -webkit-animation: blink 0.4s infinite linear; + animation: blink 0.4s infinite linear; + display: inline-block; +} + +@keyframes blink { + 50%, + 100% { + visibility: hidden; + } +} + +@-moz-keyframes blink { + 50%, + 100% { + visibility: hidden; + } +} + +@-o-keyframes blink { + 50%, + 100% { + visibility: hidden; + } +} + +@-webkit-keyframes blink { + 50%, + 100% { + visibility: hidden; + } +} + +@-ms-keyframes blink { + 50%, + 100% { + visibility: hidden; + } +} + +/* Blink Animation End */ diff --git a/twake/frontend/src/app/components/icon/icon.jsx b/twake/frontend/src/app/components/icon/icon.jsx new file mode 100755 index 00000000..79e69f33 --- /dev/null +++ b/twake/frontend/src/app/components/icon/icon.jsx @@ -0,0 +1,43 @@ +/* eslint-disable react/prop-types */ +import React, { Component } from 'react'; + +import './animation.scss'; +import './unicons.scss'; + +export default class Icon extends Component { + /* + props = { + type : icon name + } + */ + constructor() { + super(); + } + shouldComponentUpdate(nextProps) { + if (nextProps.type != this.props.type || nextProps.className != this.props.className) { + return true; + } + return false; + } + render() { + if ((this.props.type || '').indexOf('http') === 0) { + return ( +
+ ); + } else { + return ( + + ); + } + } +} diff --git a/twake/frontend/src/app/components/icon/unicons-font/unicons.eot b/twake/frontend/src/app/components/icon/unicons-font/unicons.eot new file mode 100755 index 00000000..d0d5402a Binary files /dev/null and b/twake/frontend/src/app/components/icon/unicons-font/unicons.eot differ diff --git a/twake/frontend/src/app/components/icon/unicons-font/unicons.svg b/twake/frontend/src/app/components/icon/unicons-font/unicons.svg new file mode 100755 index 00000000..6c177b84 --- /dev/null +++ b/twake/frontend/src/app/components/icon/unicons-font/unicons.svg @@ -0,0 +1,2148 @@ + + + +Iconscout + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/twake/frontend/src/app/components/icon/unicons-font/unicons.ttf b/twake/frontend/src/app/components/icon/unicons-font/unicons.ttf new file mode 100755 index 00000000..28f9428e Binary files /dev/null and b/twake/frontend/src/app/components/icon/unicons-font/unicons.ttf differ diff --git a/twake/frontend/src/app/components/icon/unicons-font/unicons.woff b/twake/frontend/src/app/components/icon/unicons-font/unicons.woff new file mode 100755 index 00000000..204efa91 Binary files /dev/null and b/twake/frontend/src/app/components/icon/unicons-font/unicons.woff differ diff --git a/twake/frontend/src/app/components/icon/unicons-font/unicons.woff2 b/twake/frontend/src/app/components/icon/unicons-font/unicons.woff2 new file mode 100755 index 00000000..88f14e6b Binary files /dev/null and b/twake/frontend/src/app/components/icon/unicons-font/unicons.woff2 differ diff --git a/twake/frontend/src/app/components/icon/unicons.scss b/twake/frontend/src/app/components/icon/unicons.scss new file mode 100755 index 00000000..40e31754 --- /dev/null +++ b/twake/frontend/src/app/components/icon/unicons.scss @@ -0,0 +1,3269 @@ +@font-face { + font-family: 'unicons'; + src: url('./unicons-font/unicons.eot?34404611'); + src: url('./unicons-font/unicons.eot?34404611#iefix') format('embedded-opentype'), + url('./unicons-font/unicons.woff2?34404611') format('woff2'), + url('./unicons-font/unicons.woff?34404611') format('woff'), + url('./unicons-font/unicons.ttf?34404611') format('truetype'), + url('./unicons-font/unicons.svg?34404611#unicons') format('svg'); + font-weight: normal; + font-style: normal; +} +/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ +/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ +/* +@media screen and (-webkit-min-device-pixel-ratio:0) { + @font-face { + font-family: 'unicons'; + src: url('../font/unicons.svg?34404611#unicons') format('svg'); + } +} +*/ + +.no-margin-left::before { + margin-left: 0 !important; +} + +[class^='uil-']:before, +[class*=' uil-']:before { + font-family: 'unicons'; + font-style: normal; + font-weight: normal; + speak: none; + + display: inline-block; + text-decoration: inherit; + width: 1em; + margin-right: 0.2em; + text-align: center; + /* opacity: .8; */ + + /* For safety - reset parent styles, that can break glyph codes*/ + font-variant: normal; + text-transform: none; + + /* fix buttons height, for twitter bootstrap */ + line-height: 1em; + + /* Animation center compensation - margins should be symmetric */ + /* remove if not needed */ + margin-left: 0.2em; + + /* you can be more comfortable with increased icons size */ + /* font-size: 120%; */ + + /* Font smoothing. That was taken from TWBS */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + /* Uncomment for 3D effect */ + /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ +} + +.uil-0-plus:before { + content: '\e800'; +} /* 'ξ €' */ +.uil-10-plus:before { + content: '\e801'; +} /* '' */ +.uil-12-plus:before { + content: '\e802'; +} /* 'ξ ‚' */ +.uil-13-plus:before { + content: '\e803'; +} /* 'ξ ƒ' */ +.uil-16-plus:before { + content: '\e804'; +} /* 'ξ „' */ +.uil-17-plus:before { + content: '\e805'; +} /* 'ξ …' */ +.uil-18-plus:before { + content: '\e806'; +} /* 'ξ †' */ +.uil-21-plus:before { + content: '\e807'; +} /* 'ξ ‡' */ +.uil-3-plus:before { + content: '\e808'; +} /* '' */ +.uil-500px:before { + content: '\e809'; +} /* 'ξ ‰' */ +.uil-6-plus:before { + content: '\e80a'; +} /* '' */ +.uil-abacus:before { + content: '\e80b'; +} /* 'ξ ‹' */ +.uil-accessible-icon-alt:before { + content: '\e80c'; +} /* '' */ +.uil-adjust-alt:before { + content: '\e80d'; +} /* '' */ +.uil-adjust-circle:before { + content: '\e80e'; +} /* '' */ +.uil-adjust-half:before { + content: '\e80f'; +} /* '' */ +.uil-adjust:before { + content: '\e810'; +} /* '' */ +.uil-adobe:before { + content: '\e811'; +} /* 'ξ ‘' */ +.uil-airplay:before { + content: '\e812'; +} /* 'ξ ’' */ +.uil-align-alt:before { + content: '\e813'; +} /* 'ξ “' */ +.uil-align-center-alt:before { + content: '\e814'; +} /* 'ξ ”' */ +.uil-align-center-h:before { + content: '\e815'; +} /* 'ξ •' */ +.uil-align-center-justify:before { + content: '\e816'; +} /* 'ξ –' */ +.uil-align-center-v:before { + content: '\e817'; +} /* 'ξ —' */ +.uil-align-center:before { + content: '\e818'; +} /* '' */ +.uil-align-justify:before { + content: '\e819'; +} /* 'ξ ™' */ +.uil-align-left-justify:before { + content: '\e81a'; +} /* '' */ +.uil-align-left:before { + content: '\e81b'; +} /* 'ξ ›' */ +.uil-align-letter-right:before { + content: '\e81c'; +} /* '' */ +.uil-align-right-justify:before { + content: '\e81d'; +} /* '' */ +.uil-align-right:before { + content: '\e81e'; +} /* '' */ +.uil-align:before { + content: '\e81f'; +} /* '' */ +.uil-ambulance:before { + content: '\e820'; +} /* 'ξ  ' */ +.uil-analysis:before { + content: '\e821'; +} /* 'ξ ‘' */ +.uil-analytics:before { + content: '\e822'; +} /* 'ξ ’' */ +.uil-anchor:before { + content: '\e823'; +} /* 'ξ £' */ +.uil-android-phone-slash:before { + content: '\e824'; +} /* 'ξ €' */ +.uil-angle-double-down:before { + content: '\e825'; +} /* 'ξ ₯' */ +.uil-angle-double-left:before { + content: '\e826'; +} /* 'ξ ¦' */ +.uil-angle-double-right:before { + content: '\e827'; +} /* 'ξ §' */ +.uil-angle-double-up:before { + content: '\e828'; +} /* 'ξ ¨' */ +.uil-angle-down:before { + content: '\e829'; +} /* 'ξ ©' */ +.uil-angle-left:before { + content: '\e82a'; +} /* 'ξ ͺ' */ +.uil-angle-right-b:before { + content: '\e82b'; +} /* 'ξ «' */ +.uil-angle-right:before { + content: '\e82c'; +} /* 'ξ ¬' */ +.uil-angle-up:before { + content: '\e82d'; +} /* 'ξ ­' */ +.uil-angry:before { + content: '\e82e'; +} /* 'ξ ' */ +.uil-ankh:before { + content: '\e82f'; +} /* 'ξ ―' */ +.uil-annoyed-alt:before { + content: '\e830'; +} /* 'ξ °' */ +.uil-annoyed:before { + content: '\e831'; +} /* 'ξ ±' */ +.uil-apple:before { + content: '\e832'; +} /* 'ξ ²' */ +.uil-apps:before { + content: '\e833'; +} /* 'ξ ³' */ +.uil-archive-alt:before { + content: '\e834'; +} /* 'ξ ΄' */ +.uil-archive:before { + content: '\e835'; +} /* 'ξ ΅' */ +.uil-archway:before { + content: '\e836'; +} /* 'ξ Ά' */ +.uil-arrow-break:before { + content: '\e837'; +} /* 'ξ ·' */ +.uil-arrow-circle-down:before { + content: '\e838'; +} /* 'ξ Έ' */ +.uil-arrow-circle-left:before { + content: '\e839'; +} /* 'ξ Ή' */ +.uil-arrow-circle-right:before { + content: '\e83a'; +} /* 'ξ Ί' */ +.uil-arrow-circle-up:before { + content: '\e83b'; +} /* 'ξ »' */ +.uil-arrow-compress-h:before { + content: '\e83c'; +} /* 'ξ Ό' */ +.uil-arrow-down-left:before { + content: '\e83d'; +} /* 'ξ ½' */ +.uil-arrow-down-right:before { + content: '\e83e'; +} /* 'ξ Ύ' */ +.uil-arrow-down:before { + content: '\e83f'; +} /* 'ξ Ώ' */ +.uil-arrow-from-right:before { + content: '\e840'; +} /* 'ξ‘€' */ +.uil-arrow-from-top:before { + content: '\e841'; +} /* '' */ +.uil-arrow-growth:before { + content: '\e842'; +} /* 'ξ‘‚' */ +.uil-arrow-left:before { + content: '\e843'; +} /* '' */ +.uil-arrow-random:before { + content: '\e844'; +} /* 'ξ‘„' */ +.uil-arrow-resize-diagonal:before { + content: '\e845'; +} /* 'ξ‘…' */ +.uil-arrow-right:before { + content: '\e846'; +} /* '' */ +.uil-arrow-to-bottom:before { + content: '\e847'; +} /* '' */ +.uil-arrow-to-right:before { + content: '\e848'; +} /* '' */ +.uil-arrow-up-left:before { + content: '\e849'; +} /* '' */ +.uil-arrow-up-right:before { + content: '\e84a'; +} /* '' */ +.uil-arrow-up:before { + content: '\e84b'; +} /* 'ξ‘‹' */ +.uil-arrows-h-alt:before { + content: '\e84c'; +} /* '' */ +.uil-arrows-h:before { + content: '\e84d'; +} /* '' */ +.uil-arrows-left-down:before { + content: '\e84e'; +} /* '' */ +.uil-arrows-maximize:before { + content: '\e84f'; +} /* '' */ +.uil-arrows-merge:before { + content: '\e850'; +} /* '' */ +.uil-arrows-resize-h:before { + content: '\e851'; +} /* 'ξ‘‘' */ +.uil-arrows-resize-v:before { + content: '\e852'; +} /* 'ξ‘’' */ +.uil-arrows-resize:before { + content: '\e853'; +} /* 'ξ‘“' */ +.uil-arrows-right-down:before { + content: '\e854'; +} /* 'ξ‘”' */ +.uil-arrows-shrink-h:before { + content: '\e855'; +} /* 'ξ‘•' */ +.uil-arrows-shrink-v:before { + content: '\e856'; +} /* 'ξ‘–' */ +.uil-arrows-up-right:before { + content: '\e857'; +} /* 'ξ‘—' */ +.uil-arrows-v-alt:before { + content: '\e858'; +} /* '' */ +.uil-arrows-v:before { + content: '\e859'; +} /* 'ξ‘™' */ +.uil-assistive-listening-systems:before { + content: '\e85a'; +} /* '' */ +.uil-asterisk:before { + content: '\e85b'; +} /* 'ξ‘›' */ +.uil-at:before { + content: '\e85c'; +} /* '' */ +.uil-atm-card:before { + content: '\e85d'; +} /* '' */ +.uil-atom:before { + content: '\e85e'; +} /* '' */ +.uil-auto-flash:before { + content: '\e85f'; +} /* '' */ +.uil-award-alt:before { + content: '\e860'; +} /* 'ξ‘ ' */ +.uil-award:before { + content: '\e861'; +} /* 'ξ‘‘' */ +.uil-baby-carriage:before { + content: '\e862'; +} /* 'ξ‘’' */ +.uil-backpack:before { + content: '\e863'; +} /* 'ξ‘£' */ +.uil-backspace:before { + content: '\e864'; +} /* 'ξ‘€' */ +.uil-backward:before { + content: '\e865'; +} /* 'ξ‘₯' */ +.uil-bag-alt:before { + content: '\e866'; +} /* '' */ +.uil-bag-slash:before { + content: '\e867'; +} /* 'ξ‘§' */ +.uil-bag:before { + content: '\e868'; +} /* '' */ +.uil-balance-scale:before { + content: '\e869'; +} /* 'ξ‘©' */ +.uil-ball:before { + content: '\e86a'; +} /* 'ξ‘ͺ' */ +.uil-ban:before { + content: '\e86b'; +} /* 'ξ‘«' */ +.uil-bars:before { + content: '\e86c'; +} /* '' */ +.uil-basketball-hoop:before { + content: '\e86d'; +} /* 'ξ‘­' */ +.uil-basketball:before { + content: '\e86e'; +} /* 'ξ‘' */ +.uil-battery-bolt:before { + content: '\e86f'; +} /* 'ξ‘―' */ +.uil-battery-empty:before { + content: '\e870'; +} /* 'ξ‘°' */ +.uil-bed-double:before { + content: '\e871'; +} /* 'ξ‘±' */ +.uil-bed:before { + content: '\e872'; +} /* 'ξ‘²' */ +.uil-behance:before { + content: '\e873'; +} /* 'ξ‘³' */ +.uil-bell-school:before { + content: '\e874'; +} /* 'ξ‘΄' */ +.uil-bell-slash:before { + content: '\e875'; +} /* 'ξ‘΅' */ +.uil-bell:before { + content: '\e876'; +} /* 'ξ‘Ά' */ +.uil-bill:before { + content: '\e877'; +} /* 'ξ‘·' */ +.uil-bitcoin-circle:before { + content: '\e878'; +} /* 'ξ‘Έ' */ +.uil-bitcoin:before { + content: '\e879'; +} /* 'ξ‘Ή' */ +.uil-black-berry:before { + content: '\e87a'; +} /* 'ξ‘Ί' */ +.uil-bluetooth-b:before { + content: '\e87b'; +} /* 'ξ‘»' */ +.uil-bold:before { + content: '\e87c'; +} /* 'ξ‘Ό' */ +.uil-bolt-alt:before { + content: '\e87d'; +} /* 'ξ‘½' */ +.uil-bolt-slash:before { + content: '\e87e'; +} /* 'ξ‘Ύ' */ +.uil-bolt:before { + content: '\e87f'; +} /* 'ξ‘Ώ' */ +.uil-book-alt:before { + content: '\e880'; +} /* 'ξ’€' */ +.uil-book-medical:before { + content: '\e881'; +} /* '' */ +.uil-book-open:before { + content: '\e882'; +} /* 'ξ’‚' */ +.uil-book-reader:before { + content: '\e883'; +} /* 'ξ’ƒ' */ +.uil-book:before { + content: '\e884'; +} /* 'ξ’„' */ +.uil-bookmark-full:before { + content: '\e885'; +} /* 'ξ’…' */ +.uil-bookmark:before { + content: '\e886'; +} /* 'ξ’†' */ +.uil-books:before { + content: '\e887'; +} /* 'ξ’‡' */ +.uil-boombox:before { + content: '\e888'; +} /* '' */ +.uil-border-alt:before { + content: '\e889'; +} /* 'ξ’‰' */ +.uil-border-bottom:before { + content: '\e88a'; +} /* '' */ +.uil-border-clear:before { + content: '\e88b'; +} /* 'ξ’‹' */ +.uil-border-horizontal:before { + content: '\e88c'; +} /* '' */ +.uil-border-inner:before { + content: '\e88d'; +} /* '' */ +.uil-border-left:before { + content: '\e88e'; +} /* '' */ +.uil-border-out:before { + content: '\e88f'; +} /* '' */ +.uil-border-right:before { + content: '\e890'; +} /* '' */ +.uil-border-top:before { + content: '\e891'; +} /* 'ξ’‘' */ +.uil-border-vertical:before { + content: '\e892'; +} /* 'ξ’’' */ +.uil-box:before { + content: '\e893'; +} /* 'ξ’“' */ +.uil-briefcase-alt:before { + content: '\e894'; +} /* 'ξ’”' */ +.uil-briefcase:before { + content: '\e895'; +} /* 'ξ’•' */ +.uil-bright:before { + content: '\e896'; +} /* 'ξ’–' */ +.uil-brightness-empty:before { + content: '\e897'; +} /* 'ξ’—' */ +.uil-brightness-half:before { + content: '\e898'; +} /* '' */ +.uil-brightness-low:before { + content: '\e899'; +} /* 'ξ’™' */ +.uil-brightness-minus:before { + content: '\e89a'; +} /* '' */ +.uil-brightness-plus:before { + content: '\e89b'; +} /* 'ξ’›' */ +.uil-brightness:before { + content: '\e89c'; +} /* '' */ +.uil-bring-bottom:before { + content: '\e89d'; +} /* '' */ +.uil-bring-front:before { + content: '\e89e'; +} /* '' */ +.uil-brush-alt:before { + content: '\e89f'; +} /* '' */ +.uil-bug:before { + content: '\e8a0'; +} /* 'ξ’ ' */ +.uil-building:before { + content: '\e8a1'; +} /* 'ξ’‘' */ +.uil-bullseye:before { + content: '\e8a2'; +} /* 'ξ’’' */ +.uil-bus-alt:before { + content: '\e8a3'; +} /* 'ξ’£' */ +.uil-bus-school:before { + content: '\e8a4'; +} /* 'ξ’€' */ +.uil-bus:before { + content: '\e8a5'; +} /* 'ξ’₯' */ +.uil-calcualtor:before { + content: '\e8a6'; +} /* 'ξ’¦' */ +.uil-calculator-alt:before { + content: '\e8a7'; +} /* 'ξ’§' */ +.uil-calendar-alt:before { + content: '\e8a8'; +} /* 'ξ’¨' */ +.uil-calendar-slash:before { + content: '\e8a9'; +} /* 'ξ’©' */ +.uil-calender:before { + content: '\e8aa'; +} /* 'ξ’ͺ' */ +.uil-calling:before { + content: '\e8ab'; +} /* 'ξ’«' */ +.uil-camera-change:before { + content: '\e8ac'; +} /* 'ξ’¬' */ +.uil-camera-plus:before { + content: '\e8ad'; +} /* 'ξ’­' */ +.uil-camera-slash:before { + content: '\e8ae'; +} /* 'ξ’' */ +.uil-camera:before { + content: '\e8af'; +} /* 'ξ’―' */ +.uil-cancel:before { + content: '\e8b0'; +} /* 'ξ’°' */ +.uil-capsule:before { + content: '\e8b1'; +} /* 'ξ’±' */ +.uil-capture:before { + content: '\e8b2'; +} /* 'ξ’²' */ +.uil-car-sideview:before { + content: '\e8b3'; +} /* 'ξ’³' */ +.uil-car-slash:before { + content: '\e8b4'; +} /* 'ξ’΄' */ +.uil-car-wash:before { + content: '\e8b5'; +} /* 'ξ’΅' */ +.uil-car:before { + content: '\e8b6'; +} /* 'ξ’Ά' */ +.uil-card-atm:before { + content: '\e8b7'; +} /* 'ξ’·' */ +.uil-caret-right:before { + content: '\e8b8'; +} /* 'ξ’Έ' */ +.uil-cart:before { + content: '\e8b9'; +} /* 'ξ’Ή' */ +.uil-cell:before { + content: '\e8ba'; +} /* 'ξ’Ί' */ +.uil-celsius:before { + content: '\e8bb'; +} /* 'ξ’»' */ +.uil-chart-bar-alt:before { + content: '\e8bc'; +} /* 'ξ’Ό' */ +.uil-chart-bar:before { + content: '\e8bd'; +} /* 'ξ’½' */ +.uil-chart-down:before { + content: '\e8be'; +} /* 'ξ’Ύ' */ +.uil-chart-growth-alt:before { + content: '\e8bf'; +} /* 'ξ’Ώ' */ +.uil-chart-growth:before { + content: '\e8c0'; +} /* 'ξ£€' */ +.uil-chart-line:before { + content: '\e8c1'; +} /* '' */ +.uil-chart-pie-alt:before { + content: '\e8c2'; +} /* '' */ +.uil-chart-pie:before { + content: '\e8c3'; +} /* '' */ +.uil-chart:before { + content: '\e8c4'; +} /* '' */ +.uil-chat-bubble-user:before { + content: '\e8c5'; +} /* 'ξ£…' */ +.uil-chat-info:before { + content: '\e8c6'; +} /* '' */ +.uil-chat:before { + content: '\e8c7'; +} /* '' */ +.uil-check-circle:before { + content: '\e8c8'; +} /* '' */ +.uil-check-square:before { + content: '\e8c9'; +} /* '' */ +.uil-check:before { + content: '\e8ca'; +} /* '' */ +.uil-circle-layer:before { + content: '\e8cb'; +} /* '' */ +.uil-circle:before { + content: '\e8cc'; +} /* '' */ +.uil-circuit:before { + content: '\e8cd'; +} /* '' */ +.uil-clapper-board:before { + content: '\e8ce'; +} /* '' */ +.uil-clipboard-alt:before { + content: '\e8cf'; +} /* '' */ +.uil-clipboard-blank:before { + content: '\e8d0'; +} /* '' */ +.uil-clipboard-notes:before { + content: '\e8d1'; +} /* '' */ +.uil-clipboard:before { + content: '\e8d2'; +} /* 'ξ£’' */ +.uil-clock-eight:before { + content: '\e8d3'; +} /* '' */ +.uil-clock-five:before { + content: '\e8d4'; +} /* 'ξ£”' */ +.uil-clock-nine:before { + content: '\e8d5'; +} /* '' */ +.uil-clock-seven:before { + content: '\e8d6'; +} /* 'ξ£–' */ +.uil-clock-ten:before { + content: '\e8d7'; +} /* 'ξ£—' */ +.uil-clock-three:before { + content: '\e8d8'; +} /* '' */ +.uil-clock-two:before { + content: '\e8d9'; +} /* 'ξ£™' */ +.uil-clock:before { + content: '\e8da'; +} /* '' */ +.uil-closed-captioning:before { + content: '\e8db'; +} /* 'ξ£›' */ +.uil-cloud-block:before { + content: '\e8dc'; +} /* '' */ +.uil-cloud-bookmark:before { + content: '\e8dd'; +} /* '' */ +.uil-cloud-check:before { + content: '\e8de'; +} /* '' */ +.uil-cloud-computing:before { + content: '\e8df'; +} /* '' */ +.uil-cloud-data-connection:before { + content: '\e8e0'; +} /* 'ξ£ ' */ +.uil-cloud-database-tree:before { + content: '\e8e1'; +} /* '' */ +.uil-cloud-download:before { + content: '\e8e2'; +} /* 'ξ£’' */ +.uil-cloud-drizzle:before { + content: '\e8e3'; +} /* 'ξ££' */ +.uil-cloud-exclamation:before { + content: '\e8e4'; +} /* 'ξ£€' */ +.uil-cloud-hail:before { + content: '\e8e5'; +} /* 'ξ£₯' */ +.uil-cloud-heart:before { + content: '\e8e6'; +} /* '' */ +.uil-cloud-info:before { + content: '\e8e7'; +} /* 'ξ£§' */ +.uil-cloud-lock:before { + content: '\e8e8'; +} /* '' */ +.uil-cloud-meatball:before { + content: '\e8e9'; +} /* '' */ +.uil-cloud-moon-hail:before { + content: '\e8ea'; +} /* 'ξ£ͺ' */ +.uil-cloud-moon-meatball:before { + content: '\e8eb'; +} /* '' */ +.uil-cloud-moon-rain:before { + content: '\e8ec'; +} /* '' */ +.uil-cloud-moon-showers:before { + content: '\e8ed'; +} /* 'ξ£­' */ +.uil-cloud-moon:before { + content: '\e8ee'; +} /* 'ξ£' */ +.uil-cloud-question:before { + content: '\e8ef'; +} /* 'ξ£―' */ +.uil-cloud-rain-sun:before { + content: '\e8f0'; +} /* 'ξ£°' */ +.uil-cloud-rain:before { + content: '\e8f1'; +} /* 'ξ£±' */ +.uil-cloud-redo:before { + content: '\e8f2'; +} /* 'ξ£²' */ +.uil-cloud-set:before { + content: '\e8f3'; +} /* 'ξ£³' */ +.uil-cloud-share:before { + content: '\e8f4'; +} /* '' */ +.uil-cloud-shield:before { + content: '\e8f5'; +} /* '' */ +.uil-cloud-showers-alt:before { + content: '\e8f6'; +} /* 'ξ£Ά' */ +.uil-cloud-showers-heavy:before { + content: '\e8f7'; +} /* 'ξ£·' */ +.uil-cloud-showers:before { + content: '\e8f8'; +} /* 'ξ£Έ' */ +.uil-cloud-slash:before { + content: '\e8f9'; +} /* 'ξ£Ή' */ +.uil-cloud-sun-hail:before { + content: '\e8fa'; +} /* 'ξ£Ί' */ +.uil-cloud-sun-meatball:before { + content: '\e8fb'; +} /* 'ξ£»' */ +.uil-cloud-sun-rain-alt:before { + content: '\e8fc'; +} /* 'ξ£Ό' */ +.uil-cloud-sun-rain:before { + content: '\e8fd'; +} /* 'ξ£½' */ +.uil-cloud-sun-tear:before { + content: '\e8fe'; +} /* 'ξ£Ύ' */ +.uil-cloud-sun:before { + content: '\e8ff'; +} /* 'ξ£Ώ' */ +.uil-cloud-times:before { + content: '\e900'; +} /* 'ξ€€' */ +.uil-cloud-unlock:before { + content: '\e901'; +} /* '' */ +.uil-cloud-upload:before { + content: '\e902'; +} /* '' */ +.uil-cloud-wifi:before { + content: '\e903'; +} /* '' */ +.uil-cloud-wind:before { + content: '\e904'; +} /* '' */ +.uil-cloud:before { + content: '\e905'; +} /* 'ξ€…' */ +.uil-clouds:before { + content: '\e906'; +} /* '' */ +.uil-club:before { + content: '\e907'; +} /* '' */ +.uil-code:before { + content: '\e908'; +} /* '' */ +.uil-coffee:before { + content: '\e909'; +} /* '' */ +.uil-cog:before { + content: '\e90a'; +} /* '' */ +.uil-coins:before { + content: '\e90b'; +} /* '' */ +.uil-columns:before { + content: '\e90c'; +} /* '' */ +.uil-comment-alt-block:before { + content: '\e90d'; +} /* '' */ +.uil-comment-alt-chart-lines:before { + content: '\e90e'; +} /* '' */ +.uil-comment-alt-check:before { + content: '\e90f'; +} /* '' */ +.uil-comment-alt-dots:before { + content: '\e910'; +} /* '' */ +.uil-comment-alt-download:before { + content: '\e911'; +} /* '' */ +.uil-comment-alt-edit:before { + content: '\e912'; +} /* 'ξ€’' */ +.uil-comment-alt-exclamation:before { + content: '\e913'; +} /* '' */ +.uil-comment-alt-heart:before { + content: '\e914'; +} /* 'ξ€”' */ +.uil-comment-alt-image:before { + content: '\e915'; +} /* '' */ +.uil-comment-alt-info:before { + content: '\e916'; +} /* 'ξ€–' */ +.uil-comment-alt-lines:before { + content: '\e917'; +} /* 'ξ€—' */ +.uil-comment-alt-lock:before { + content: '\e918'; +} /* '' */ +.uil-comment-alt-medical:before { + content: '\e919'; +} /* 'ξ€™' */ +.uil-comment-alt-message:before { + content: '\e91a'; +} /* '' */ +.uil-comment-alt-notes:before { + content: '\e91b'; +} /* 'ξ€›' */ +.uil-comment-alt-plus:before { + content: '\e91c'; +} /* '' */ +.uil-comment-alt-question:before { + content: '\e91d'; +} /* '' */ +.uil-comment-alt-redo:before { + content: '\e91e'; +} /* '' */ +.uil-comment-alt-search:before { + content: '\e91f'; +} /* '' */ +.uil-comment-alt-share:before { + content: '\e920'; +} /* 'ξ€ ' */ +.uil-comment-alt-shield:before { + content: '\e921'; +} /* '' */ +.uil-comment-alt-slash:before { + content: '\e922'; +} /* 'ξ€’' */ +.uil-comment-alt-upload:before { + content: '\e923'; +} /* 'ξ€£' */ +.uil-comment-alt-verify:before { + content: '\e924'; +} /* 'ξ€€' */ +.uil-comment-alt:before { + content: '\e925'; +} /* 'ξ€₯' */ +.uil-comment-block:before { + content: '\e926'; +} /* '' */ +.uil-comment-chart-line:before { + content: '\e927'; +} /* 'ξ€§' */ +.uil-comment-check:before { + content: '\e928'; +} /* '' */ +.uil-comment-dots:before { + content: '\e929'; +} /* '' */ +.uil-comment-download:before { + content: '\e92a'; +} /* 'ξ€ͺ' */ +.uil-comment-edit:before { + content: '\e92b'; +} /* '' */ +.uil-comment-exclamation:before { + content: '\e92c'; +} /* '' */ +.uil-comment-heart:before { + content: '\e92d'; +} /* 'ξ€­' */ +.uil-comment-image:before { + content: '\e92e'; +} /* 'ξ€' */ +.uil-comment-info-alt:before { + content: '\e92f'; +} /* 'ξ€―' */ +.uil-comment-info:before { + content: '\e930'; +} /* 'ξ€°' */ +.uil-comment-lines:before { + content: '\e931'; +} /* 'ξ€±' */ +.uil-comment-lock:before { + content: '\e932'; +} /* 'ξ€²' */ +.uil-comment-medical:before { + content: '\e933'; +} /* 'ξ€³' */ +.uil-comment-message:before { + content: '\e934'; +} /* '' */ +.uil-comment-notes:before { + content: '\e935'; +} /* '' */ +.uil-comment-plus:before { + content: '\e936'; +} /* 'ξ€Ά' */ +.uil-comment-question:before { + content: '\e937'; +} /* 'ξ€·' */ +.uil-comment-redo:before { + content: '\e938'; +} /* 'ξ€Έ' */ +.uil-comment-search:before { + content: '\e939'; +} /* 'ξ€Ή' */ +.uil-comment-share:before { + content: '\e93a'; +} /* 'ξ€Ί' */ +.uil-comment-shield:before { + content: '\e93b'; +} /* 'ξ€»' */ +.uil-comment-slash:before { + content: '\e93c'; +} /* 'ξ€Ό' */ +.uil-comment-upload:before { + content: '\e93d'; +} /* 'ξ€½' */ +.uil-comment-verify:before { + content: '\e93e'; +} /* 'ξ€Ύ' */ +.uil-comment:before { + content: '\e93f'; +} /* 'ξ€Ώ' */ +.uil-comments-alt:before { + content: '\e940'; +} /* 'ξ₯€' */ +.uil-comments:before { + content: '\e941'; +} /* 'ξ₯' */ +.uil-commnet-alt-slash:before { + content: '\e942'; +} /* 'ξ₯‚' */ +.uil-compact-disc:before { + content: '\e943'; +} /* 'ξ₯ƒ' */ +.uil-compass:before { + content: '\e944'; +} /* 'ξ₯„' */ +.uil-compress-alt-left:before { + content: '\e945'; +} /* 'ξ₯…' */ +.uil-compress-alt:before { + content: '\e946'; +} /* 'ξ₯†' */ +.uil-compress-arrows:before { + content: '\e947'; +} /* 'ξ₯‡' */ +.uil-compress-lines:before { + content: '\e948'; +} /* 'ξ₯ˆ' */ +.uil-compress-point:before { + content: '\e949'; +} /* 'ξ₯‰' */ +.uil-compress-v:before { + content: '\e94a'; +} /* 'ξ₯Š' */ +.uil-compress:before { + content: '\e94b'; +} /* 'ξ₯‹' */ +.uil-computer-mouse:before { + content: '\e94c'; +} /* 'ξ₯Œ' */ +.uil-confused:before { + content: '\e94d'; +} /* 'ξ₯' */ +.uil-constructor:before { + content: '\e94e'; +} /* 'ξ₯Ž' */ +.uil-copy-alt:before { + content: '\e94f'; +} /* 'ξ₯' */ +.uil-copy-landscape:before { + content: '\e950'; +} /* 'ξ₯' */ +.uil-copy:before { + content: '\e951'; +} /* 'ξ₯‘' */ +.uil-copyright:before { + content: '\e952'; +} /* 'ξ₯’' */ +.uil-corner-down-left:before { + content: '\e953'; +} /* 'ξ₯“' */ +.uil-corner-down-right-alt:before { + content: '\e954'; +} /* 'ξ₯”' */ +.uil-corner-down-right:before { + content: '\e955'; +} /* 'ξ₯•' */ +.uil-corner-left-down:before { + content: '\e956'; +} /* 'ξ₯–' */ +.uil-corner-right-down:before { + content: '\e957'; +} /* 'ξ₯—' */ +.uil-corner-up-left-alt:before { + content: '\e958'; +} /* 'ξ₯˜' */ +.uil-corner-up-left:before { + content: '\e959'; +} /* 'ξ₯™' */ +.uil-corner-up-right-alt:before { + content: '\e95a'; +} /* 'ξ₯š' */ +.uil-corner-up-right:before { + content: '\e95b'; +} /* 'ξ₯›' */ +.uil-creative-commons-pd-alt:before { + content: '\e95c'; +} /* 'ξ₯œ' */ +.uil-creative-commons-pd:before { + content: '\e95d'; +} /* 'ξ₯' */ +.uil-crockery:before { + content: '\e95e'; +} /* 'ξ₯ž' */ +.uil-crop-alt-rotate-left:before { + content: '\e95f'; +} /* 'ξ₯Ÿ' */ +.uil-crop-alt-rotate-right:before { + content: '\e960'; +} /* 'ξ₯ ' */ +.uil-crop-alt:before { + content: '\e961'; +} /* 'ξ₯‘' */ +.uil-crosshair-alt:before { + content: '\e962'; +} /* 'ξ₯’' */ +.uil-crosshair:before { + content: '\e963'; +} /* 'ξ₯£' */ +.uil-crosshairs:before { + content: '\e964'; +} /* 'ξ₯€' */ +.uil-cube:before { + content: '\e965'; +} /* 'ξ₯₯' */ +.uil-dashboard:before { + content: '\e966'; +} /* 'ξ₯¦' */ +.uil-data-sharing:before { + content: '\e967'; +} /* 'ξ₯§' */ +.uil-database-alt:before { + content: '\e968'; +} /* 'ξ₯¨' */ +.uil-database:before { + content: '\e969'; +} /* 'ξ₯©' */ +.uil-desert:before { + content: '\e96a'; +} /* 'ξ₯ͺ' */ +.uil-desktop-alt-slash:before { + content: '\e96b'; +} /* 'ξ₯«' */ +.uil-desktop-alt:before { + content: '\e96c'; +} /* 'ξ₯¬' */ +.uil-desktop-cloud-alt:before { + content: '\e96d'; +} /* 'ξ₯­' */ +.uil-desktop-slash:before { + content: '\e96e'; +} /* 'ξ₯' */ +.uil-desktop:before { + content: '\e96f'; +} /* 'ξ₯―' */ +.uil-dialpad-alt:before { + content: '\e970'; +} /* 'ξ₯°' */ +.uil-dialpad:before { + content: '\e971'; +} /* 'ξ₯±' */ +.uil-diamond:before { + content: '\e972'; +} /* 'ξ₯²' */ +.uil-diary-alt:before { + content: '\e973'; +} /* 'ξ₯³' */ +.uil-diary:before { + content: '\e974'; +} /* 'ξ₯΄' */ +.uil-dice-five:before { + content: '\e975'; +} /* 'ξ₯΅' */ +.uil-dice-four:before { + content: '\e976'; +} /* 'ξ₯Ά' */ +.uil-dice-one:before { + content: '\e977'; +} /* 'ξ₯·' */ +.uil-dice-six:before { + content: '\e978'; +} /* 'ξ₯Έ' */ +.uil-dice-three:before { + content: '\e979'; +} /* 'ξ₯Ή' */ +.uil-dice-two:before { + content: '\e97a'; +} /* 'ξ₯Ί' */ +.uil-direction:before { + content: '\e97b'; +} /* 'ξ₯»' */ +.uil-directions:before { + content: '\e97c'; +} /* 'ξ₯Ό' */ +.uil-dizzy-meh:before { + content: '\e97d'; +} /* 'ξ₯½' */ +.uil-dna:before { + content: '\e97e'; +} /* 'ξ₯Ύ' */ +.uil-document-layout-center:before { + content: '\e97f'; +} /* 'ξ₯Ώ' */ +.uil-document-layout-left:before { + content: '\e980'; +} /* '' */ +.uil-document-layout-right:before { + content: '\e981'; +} /* '' */ +.uil-document:before { + content: '\e982'; +} /* '' */ +.uil-dollar-alt:before { + content: '\e983'; +} /* '' */ +.uil-dollar-sign-alt:before { + content: '\e984'; +} /* '' */ +.uil-dollar-sign:before { + content: '\e985'; +} /* 'ξ¦…' */ +.uil-down-arrow:before { + content: '\e986'; +} /* '' */ +.uil-download-alt:before { + content: '\e987'; +} /* '' */ +.uil-dribbble:before { + content: '\e988'; +} /* '' */ +.uil-drill:before { + content: '\e989'; +} /* '' */ +.uil-dropbox:before { + content: '\e98a'; +} /* '' */ +.uil-dumbbell:before { + content: '\e98b'; +} /* '' */ +.uil-ear:before { + content: '\e98c'; +} /* '' */ +.uil-edit-alt:before { + content: '\e98d'; +} /* '' */ +.uil-edit:before { + content: '\e98e'; +} /* '' */ +.uil-ellipsis-h:before { + content: '\e98f'; +} /* '' */ +.uil-ellipsis-v:before { + content: '\e990'; +} /* '' */ +.uil-emoji:before { + content: '\e991'; +} /* '' */ +.uil-enter:before { + content: '\e992'; +} /* 'ξ¦’' */ +.uil-entry:before { + content: '\e993'; +} /* '' */ +.uil-envelope-add:before { + content: '\e994'; +} /* '' */ +.uil-envelope-alt:before { + content: '\e995'; +} /* '' */ +.uil-envelope-block:before { + content: '\e996'; +} /* 'ξ¦–' */ +.uil-envelope-bookmark:before { + content: '\e997'; +} /* 'ξ¦—' */ +.uil-envelope-check:before { + content: '\e998'; +} /* '' */ +.uil-envelope-download-alt:before { + content: '\e999'; +} /* '' */ +.uil-envelope-download:before { + content: '\e99a'; +} /* '' */ +.uil-envelope-edit:before { + content: '\e99b'; +} /* '' */ +.uil-envelope-exclamation:before { + content: '\e99c'; +} /* '' */ +.uil-envelope-heart:before { + content: '\e99d'; +} /* '' */ +.uil-envelope-info:before { + content: '\e99e'; +} /* '' */ +.uil-envelope-lock:before { + content: '\e99f'; +} /* '' */ +.uil-envelope-minus:before { + content: '\e9a0'; +} /* 'ξ¦ ' */ +.uil-envelope-open:before { + content: '\e9a1'; +} /* '' */ +.uil-envelope-question:before { + content: '\e9a2'; +} /* 'ξ¦’' */ +.uil-envelope-receive:before { + content: '\e9a3'; +} /* '' */ +.uil-envelope-redo:before { + content: '\e9a4'; +} /* '' */ +.uil-envelope-search:before { + content: '\e9a5'; +} /* 'ξ¦₯' */ +.uil-envelope-send:before { + content: '\e9a6'; +} /* '' */ +.uil-envelope-share:before { + content: '\e9a7'; +} /* '' */ +.uil-envelope-shield:before { + content: '\e9a8'; +} /* '' */ +.uil-envelope-star:before { + content: '\e9a9'; +} /* '' */ +.uil-envelope-times:before { + content: '\e9aa'; +} /* 'ξ¦ͺ' */ +.uil-envelope-upload-alt:before { + content: '\e9ab'; +} /* '' */ +.uil-envelope-upload:before { + content: '\e9ac'; +} /* '' */ +.uil-envelope:before { + content: '\e9ad'; +} /* 'ξ¦­' */ +.uil-envelopes:before { + content: '\e9ae'; +} /* 'ξ¦' */ +.uil-equal-circle:before { + content: '\e9af'; +} /* 'ξ¦―' */ +.uil-euro-circle:before { + content: '\e9b0'; +} /* 'ξ¦°' */ +.uil-euro:before { + content: '\e9b1'; +} /* '' */ +.uil-exchange-alt:before { + content: '\e9b2'; +} /* '' */ +.uil-exchange:before { + content: '\e9b3'; +} /* '' */ +.uil-exclamation-circle:before { + content: '\e9b4'; +} /* '' */ +.uil-exclamation-octagon:before { + content: '\e9b5'; +} /* '' */ +.uil-exclamation-triangle:before { + content: '\e9b6'; +} /* 'ξ¦Ά' */ +.uil-exclude:before { + content: '\e9b7'; +} /* 'ξ¦·' */ +.uil-exit:before { + content: '\e9b8'; +} /* 'ξ¦Έ' */ +.uil-expand-alt:before { + content: '\e9b9'; +} /* 'ξ¦Ή' */ +.uil-expand-arrows-alt:before { + content: '\e9ba'; +} /* 'ξ¦Ί' */ +.uil-expand-arrows:before { + content: '\e9bb'; +} /* '' */ +.uil-expand-from-corner:before { + content: '\e9bc'; +} /* 'ξ¦Ό' */ +.uil-expand-left:before { + content: '\e9bd'; +} /* '' */ +.uil-expand-right:before { + content: '\e9be'; +} /* 'ξ¦Ύ' */ +.uil-export:before { + content: '\e9bf'; +} /* 'ξ¦Ώ' */ +.uil-exposure-alt:before { + content: '\e9c0'; +} /* 'ξ§€' */ +.uil-exposure-increase:before { + content: '\e9c1'; +} /* '' */ +.uil-external-link-alt:before { + content: '\e9c2'; +} /* 'ξ§‚' */ +.uil-eye-slash:before { + content: '\e9c3'; +} /* '' */ +.uil-eye:before { + content: '\e9c4'; +} /* 'ξ§„' */ +.uil-facebook-f:before { + content: '\e9c5'; +} /* 'ξ§…' */ +.uil-facebook-messenger:before { + content: '\e9c6'; +} /* '' */ +.uil-facebook:before { + content: '\e9c7'; +} /* '' */ +.uil-fahrenheit:before { + content: '\e9c8'; +} /* '' */ +.uil-fast-mail-alt:before { + content: '\e9c9'; +} /* '' */ +.uil-fast-mail:before { + content: '\e9ca'; +} /* '' */ +.uil-favorite:before { + content: '\e9cb'; +} /* 'ξ§‹' */ +.uil-feedback:before { + content: '\e9cc'; +} /* '' */ +.uil-file-alt:before { + content: '\e9cd'; +} /* '' */ +.uil-file-blank:before { + content: '\e9ce'; +} /* '' */ +.uil-file-block-alt:before { + content: '\e9cf'; +} /* '' */ +.uil-file-bookmark-alt:before { + content: '\e9d0'; +} /* '' */ +.uil-file-check-alt:before { + content: '\e9d1'; +} /* 'ξ§‘' */ +.uil-file-check:before { + content: '\e9d2'; +} /* 'ξ§’' */ +.uil-file-contract-dollar:before { + content: '\e9d3'; +} /* 'ξ§“' */ +.uil-file-copy-alt:before { + content: '\e9d4'; +} /* 'ξ§”' */ +.uil-file-download-alt:before { + content: '\e9d5'; +} /* 'ξ§•' */ +.uil-file-download:before { + content: '\e9d6'; +} /* 'ξ§–' */ +.uil-file-edit-alt:before { + content: '\e9d7'; +} /* 'ξ§—' */ +.uil-file-exclamation-alt:before { + content: '\e9d8'; +} /* '' */ +.uil-file-exclamation:before { + content: '\e9d9'; +} /* 'ξ§™' */ +.uil-file-heart:before { + content: '\e9da'; +} /* '' */ +.uil-file-info-alt:before { + content: '\e9db'; +} /* 'ξ§›' */ +.uil-file-landscape-alt:before { + content: '\e9dc'; +} /* '' */ +.uil-file-landscape:before { + content: '\e9dd'; +} /* '' */ +.uil-file-lanscape-slash:before { + content: '\e9de'; +} /* '' */ +.uil-file-lock-alt:before { + content: '\e9df'; +} /* '' */ +.uil-file-medical-alt:before { + content: '\e9e0'; +} /* 'ξ§ ' */ +.uil-file-medical:before { + content: '\e9e1'; +} /* 'ξ§‘' */ +.uil-file-minus-alt:before { + content: '\e9e2'; +} /* 'ξ§’' */ +.uil-file-minus:before { + content: '\e9e3'; +} /* 'ξ§£' */ +.uil-file-network:before { + content: '\e9e4'; +} /* 'ξ§€' */ +.uil-file-plus-alt:before { + content: '\e9e5'; +} /* 'ξ§₯' */ +.uil-file-plus:before { + content: '\e9e6'; +} /* '' */ +.uil-file-question-alt:before { + content: '\e9e7'; +} /* 'ξ§§' */ +.uil-file-question:before { + content: '\e9e8'; +} /* '' */ +.uil-file-redo-alt:before { + content: '\e9e9'; +} /* 'ξ§©' */ +.uil-file-search-alt:before { + content: '\e9ea'; +} /* 'ξ§ͺ' */ +.uil-file-share-alt:before { + content: '\e9eb'; +} /* 'ξ§«' */ +.uil-file-shield-alt:before { + content: '\e9ec'; +} /* '' */ +.uil-file-slash:before { + content: '\e9ed'; +} /* 'ξ§­' */ +.uil-file-times-alt:before { + content: '\e9ee'; +} /* 'ξ§' */ +.uil-file-times:before { + content: '\e9ef'; +} /* 'ξ§―' */ +.uil-file-upload-alt:before { + content: '\e9f0'; +} /* 'ξ§°' */ +.uil-file-upload:before { + content: '\e9f1'; +} /* 'ξ§±' */ +.uil-file:before { + content: '\e9f2'; +} /* 'ξ§²' */ +.uil-files-landscapes-alt:before { + content: '\e9f3'; +} /* 'ξ§³' */ +.uil-files-landscapes:before { + content: '\e9f4'; +} /* 'ξ§΄' */ +.uil-film:before { + content: '\e9f5'; +} /* 'ξ§΅' */ +.uil-filter-slash:before { + content: '\e9f6'; +} /* 'ξ§Ά' */ +.uil-filter:before { + content: '\e9f7'; +} /* 'ξ§·' */ +.uil-flask-potion:before { + content: '\e9f8'; +} /* 'ξ§Έ' */ +.uil-flask:before { + content: '\e9f9'; +} /* 'ξ§Ή' */ +.uil-flip-h-alt:before { + content: '\e9fa'; +} /* 'ξ§Ί' */ +.uil-flip-h:before { + content: '\e9fb'; +} /* 'ξ§»' */ +.uil-flip-v-alt:before { + content: '\e9fc'; +} /* 'ξ§Ό' */ +.uil-flip-v:before { + content: '\e9fd'; +} /* 'ξ§½' */ +.uil-flower:before { + content: '\e9fe'; +} /* 'ξ§Ύ' */ +.uil-focus-add:before { + content: '\e9ff'; +} /* 'ξ§Ώ' */ +.uil-focus-target:before { + content: '\ea00'; +} /* '' */ +.uil-focus:before { + content: '\ea01'; +} /* '' */ +.uil-folder-check:before { + content: '\ea02'; +} /* '' */ +.uil-folder-download:before { + content: '\ea03'; +} /* '' */ +.uil-folder-exclamation:before { + content: '\ea04'; +} /* '' */ +.uil-folder-heart:before { + content: '\ea05'; +} /* 'ξ¨…' */ +.uil-folder-info:before { + content: '\ea06'; +} /* '' */ +.uil-folder-lock:before { + content: '\ea07'; +} /* '' */ +.uil-folder-medical:before { + content: '\ea08'; +} /* '' */ +.uil-folder-minus:before { + content: '\ea09'; +} /* '' */ +.uil-folder-network:before { + content: '\ea0a'; +} /* '' */ +.uil-folder-plus:before { + content: '\ea0b'; +} /* '' */ +.uil-folder-question:before { + content: '\ea0c'; +} /* '' */ +.uil-folder-slash:before { + content: '\ea0d'; +} /* '' */ +.uil-folder-times:before { + content: '\ea0e'; +} /* '' */ +.uil-folder-upload:before { + content: '\ea0f'; +} /* '' */ +.uil-folder:before { + content: '\ea10'; +} /* '' */ +.uil-food:before { + content: '\ea11'; +} /* '' */ +.uil-football-american:before { + content: '\ea12'; +} /* 'ξ¨’' */ +.uil-football-ball:before { + content: '\ea13'; +} /* '' */ +.uil-football:before { + content: '\ea14'; +} /* '' */ +.uil-forecastcloud-moon-tear:before { + content: '\ea15'; +} /* '' */ +.uil-forwaded-call:before { + content: '\ea16'; +} /* 'ξ¨–' */ +.uil-forward:before { + content: '\ea17'; +} /* 'ξ¨—' */ +.uil-frown:before { + content: '\ea18'; +} /* '' */ +.uil-game-structure:before { + content: '\ea19'; +} /* '' */ +.uil-game:before { + content: '\ea1a'; +} /* '' */ +.uil-gift:before { + content: '\ea1b'; +} /* '' */ +.uil-github-alt:before { + content: '\ea1c'; +} /* '' */ +.uil-github:before { + content: '\ea1d'; +} /* '' */ +.uil-glass-martini-alt-slash:before { + content: '\ea1e'; +} /* '' */ +.uil-glass-martini-alt:before { + content: '\ea1f'; +} /* '' */ +.uil-glass-martini:before { + content: '\ea20'; +} /* 'ξ¨ ' */ +.uil-glass-tea:before { + content: '\ea21'; +} /* '' */ +.uil-glass:before { + content: '\ea22'; +} /* 'ξ¨’' */ +.uil-globe:before { + content: '\ea23'; +} /* '' */ +.uil-gold:before { + content: '\ea24'; +} /* '' */ +.uil-google-drive-alt:before { + content: '\ea25'; +} /* 'ξ¨₯' */ +.uil-google-drive:before { + content: '\ea26'; +} /* '' */ +.uil-google-hangouts:before { + content: '\ea27'; +} /* '' */ +.uil-google-play:before { + content: '\ea28'; +} /* '' */ +.uil-google:before { + content: '\ea29'; +} /* '' */ +.uil-graduation-hat:before { + content: '\ea2a'; +} /* 'ξ¨ͺ' */ +.uil-graph-bar:before { + content: '\ea2b'; +} /* '' */ +.uil-grid:before { + content: '\ea2c'; +} /* '' */ +.uil-grids:before { + content: '\ea2d'; +} /* 'ξ¨­' */ +.uil-grin-tongue-wink-alt:before { + content: '\ea2e'; +} /* 'ξ¨' */ +.uil-grin-tongue-wink:before { + content: '\ea2f'; +} /* 'ξ¨―' */ +.uil-grin:before { + content: '\ea30'; +} /* 'ξ¨°' */ +.uil-grip-horizontal-line:before { + content: '\ea31'; +} /* '' */ +.uil-hdd:before { + content: '\ea32'; +} /* '' */ +.uil-headphones-alt:before { + content: '\ea33'; +} /* '' */ +.uil-headphones:before { + content: '\ea34'; +} /* '' */ +.uil-heart-alt:before { + content: '\ea35'; +} /* '' */ +.uil-heart-medical:before { + content: '\ea36'; +} /* 'ξ¨Ά' */ +.uil-heart-rate:before { + content: '\ea37'; +} /* 'ξ¨·' */ +.uil-heart-sign:before { + content: '\ea38'; +} /* 'ξ¨Έ' */ +.uil-heart:before { + content: '\ea39'; +} /* 'ξ¨Ή' */ +.uil-heartbeat:before { + content: '\ea3a'; +} /* 'ξ¨Ί' */ +.uil-history-alt:before { + content: '\ea3b'; +} /* '' */ +.uil-history:before { + content: '\ea3c'; +} /* 'ξ¨Ό' */ +.uil-home-alt:before { + content: '\ea3d'; +} /* '' */ +.uil-home:before { + content: '\ea3e'; +} /* 'ξ¨Ύ' */ +.uil-horizontal-align-center:before { + content: '\ea3f'; +} /* 'ξ¨Ώ' */ +.uil-horizontal-align-left:before { + content: '\ea40'; +} /* 'ξ©€' */ +.uil-horizontal-align-right:before { + content: '\ea41'; +} /* '' */ +.uil-horizontal-distribution-center:before { + content: '\ea42'; +} /* 'ξ©‚' */ +.uil-horizontal-distribution-left:before { + content: '\ea43'; +} /* '' */ +.uil-horizontal-distribution-right:before { + content: '\ea44'; +} /* 'ξ©„' */ +.uil-hunting:before { + content: '\ea45'; +} /* 'ξ©…' */ +.uil-image-alt-slash:before { + content: '\ea46'; +} /* '' */ +.uil-image-block:before { + content: '\ea47'; +} /* '' */ +.uil-image-broken:before { + content: '\ea48'; +} /* '' */ +.uil-image-check:before { + content: '\ea49'; +} /* '' */ +.uil-image-download:before { + content: '\ea4a'; +} /* '' */ +.uil-image-edit:before { + content: '\ea4b'; +} /* 'ξ©‹' */ +.uil-image-lock:before { + content: '\ea4c'; +} /* '' */ +.uil-image-minus:before { + content: '\ea4d'; +} /* '' */ +.uil-image-plus:before { + content: '\ea4e'; +} /* '' */ +.uil-image-question:before { + content: '\ea4f'; +} /* '' */ +.uil-image-redo:before { + content: '\ea50'; +} /* '' */ +.uil-image-resize-landscape:before { + content: '\ea51'; +} /* 'ξ©‘' */ +.uil-image-resize-square:before { + content: '\ea52'; +} /* 'ξ©’' */ +.uil-image-search:before { + content: '\ea53'; +} /* 'ξ©“' */ +.uil-image-share:before { + content: '\ea54'; +} /* 'ξ©”' */ +.uil-image-shield:before { + content: '\ea55'; +} /* 'ξ©•' */ +.uil-image-slash:before { + content: '\ea56'; +} /* 'ξ©–' */ +.uil-image-times:before { + content: '\ea57'; +} /* 'ξ©—' */ +.uil-image-upload:before { + content: '\ea58'; +} /* '' */ +.uil-image-v:before { + content: '\ea59'; +} /* 'ξ©™' */ +.uil-image:before { + content: '\ea5a'; +} /* '' */ +.uil-images:before { + content: '\ea5b'; +} /* 'ξ©›' */ +.uil-incoming-call:before { + content: '\ea5c'; +} /* '' */ +.uil-info-circle:before { + content: '\ea5d'; +} /* '' */ +.uil-instagram-alt:before { + content: '\ea5e'; +} /* '' */ +.uil-instagram:before { + content: '\ea5f'; +} /* '' */ +.uil-intercom:before { + content: '\ea60'; +} /* 'ξ© ' */ +.uil-invoice:before { + content: '\ea61'; +} /* 'ξ©‘' */ +.uil-italic:before { + content: '\ea62'; +} /* 'ξ©’' */ +.uil-jackhammer:before { + content: '\ea63'; +} /* 'ξ©£' */ +.uil-java-script:before { + content: '\ea64'; +} /* 'ξ©€' */ +.uil-kayak:before { + content: '\ea65'; +} /* 'ξ©₯' */ +.uil-key-skeleton-alt:before { + content: '\ea66'; +} /* '' */ +.uil-key-skeleton:before { + content: '\ea67'; +} /* 'ξ©§' */ +.uil-keyboard-alt:before { + content: '\ea68'; +} /* '' */ +.uil-keyboard-hide:before { + content: '\ea69'; +} /* 'ξ©©' */ +.uil-keyboard-show:before { + content: '\ea6a'; +} /* 'ξ©ͺ' */ +.uil-keyboard:before { + content: '\ea6b'; +} /* 'ξ©«' */ +.uil-keyhole-circle:before { + content: '\ea6c'; +} /* '' */ +.uil-keyhole-square-full:before { + content: '\ea6d'; +} /* 'ξ©­' */ +.uil-keyhole-square:before { + content: '\ea6e'; +} /* 'ξ©' */ +.uil-kid:before { + content: '\ea6f'; +} /* 'ξ©―' */ +.uil-label-alt:before { + content: '\ea70'; +} /* 'ξ©°' */ +.uil-label:before { + content: '\ea71'; +} /* 'ξ©±' */ +.uil-lamp:before { + content: '\ea72'; +} /* 'ξ©²' */ +.uil-laptop-cloud:before { + content: '\ea73'; +} /* 'ξ©³' */ +.uil-laptop:before { + content: '\ea74'; +} /* 'ξ©΄' */ +.uil-laughing:before { + content: '\ea75'; +} /* 'ξ©΅' */ +.uil-layer-group-slash:before { + content: '\ea76'; +} /* 'ξ©Ά' */ +.uil-layer-group:before { + content: '\ea77'; +} /* 'ξ©·' */ +.uil-layers-alt:before { + content: '\ea78'; +} /* 'ξ©Έ' */ +.uil-layers-slash:before { + content: '\ea79'; +} /* 'ξ©Ή' */ +.uil-layers:before { + content: '\ea7a'; +} /* 'ξ©Ί' */ +.uil-left-arrow-from-left:before { + content: '\ea7b'; +} /* 'ξ©»' */ +.uil-left-arrow-to-left:before { + content: '\ea7c'; +} /* 'ξ©Ό' */ +.uil-left-indent-alt:before { + content: '\ea7d'; +} /* 'ξ©½' */ +.uil-left-indent:before { + content: '\ea7e'; +} /* 'ξ©Ύ' */ +.uil-left-to-right-text-direction:before { + content: '\ea7f'; +} /* 'ξ©Ώ' */ +.uil-life-ring:before { + content: '\ea80'; +} /* 'ξͺ€' */ +.uil-lightbulb-alt:before { + content: '\ea81'; +} /* 'ξͺ' */ +.uil-lightbulb:before { + content: '\ea82'; +} /* 'ξͺ‚' */ +.uil-line-alt:before { + content: '\ea83'; +} /* 'ξͺƒ' */ +.uil-line-spacing:before { + content: '\ea84'; +} /* 'ξͺ„' */ +.uil-line:before { + content: '\ea85'; +} /* 'ξͺ…' */ +.uil-link-alt:before { + content: '\ea86'; +} /* 'ξͺ†' */ +.uil-link-broken:before { + content: '\ea87'; +} /* 'ξͺ‡' */ +.uil-link-h:before { + content: '\ea88'; +} /* 'ξͺˆ' */ +.uil-link:before { + content: '\ea89'; +} /* 'ξͺ‰' */ +.uil-linkedin-alt:before { + content: '\ea8a'; +} /* 'ξͺŠ' */ +.uil-linkedin:before { + content: '\ea8b'; +} /* 'ξͺ‹' */ +.uil-list-ui-alt:before { + content: '\ea8c'; +} /* 'ξͺŒ' */ +.uil-list-ul:before { + content: '\ea8d'; +} /* 'ξͺ' */ +.uil-location-arrow-alt:before { + content: '\ea8e'; +} /* 'ξͺŽ' */ +.uil-location-arrow:before { + content: '\ea8f'; +} /* 'ξͺ' */ +.uil-location-pin-alt:before { + content: '\ea90'; +} /* 'ξͺ' */ +.uil-location-point:before { + content: '\ea91'; +} /* 'ξͺ‘' */ +.uil-location:before { + content: '\ea92'; +} /* 'ξͺ’' */ +.uil-lock-access:before { + content: '\ea93'; +} /* 'ξͺ“' */ +.uil-lock-alt:before { + content: '\ea94'; +} /* 'ξͺ”' */ +.uil-lock-open-alt:before { + content: '\ea95'; +} /* 'ξͺ•' */ +.uil-lock-slash:before { + content: '\ea96'; +} /* 'ξͺ–' */ +.uil-lock:before { + content: '\ea97'; +} /* 'ξͺ—' */ +.uil-mailbox-alt:before { + content: '\ea98'; +} /* 'ξͺ˜' */ +.uil-mailbox:before { + content: '\ea99'; +} /* 'ξͺ™' */ +.uil-map-marker-alt:before { + content: '\ea9a'; +} /* 'ξͺš' */ +.uil-map-marker-edit:before { + content: '\ea9b'; +} /* 'ξͺ›' */ +.uil-map-marker-info:before { + content: '\ea9c'; +} /* 'ξͺœ' */ +.uil-map-marker-minus:before { + content: '\ea9d'; +} /* 'ξͺ' */ +.uil-map-marker-plus:before { + content: '\ea9e'; +} /* 'ξͺž' */ +.uil-map-marker-question:before { + content: '\ea9f'; +} /* 'ξͺŸ' */ +.uil-map-marker-shield:before { + content: '\eaa0'; +} /* 'ξͺ ' */ +.uil-map-marker-slash:before { + content: '\eaa1'; +} /* 'ξͺ‘' */ +.uil-map-marker:before { + content: '\eaa2'; +} /* 'ξͺ’' */ +.uil-map-pin-alt:before { + content: '\eaa3'; +} /* 'ξͺ£' */ +.uil-map-pin:before { + content: '\eaa4'; +} /* 'ξͺ€' */ +.uil-map:before { + content: '\eaa5'; +} /* 'ξͺ₯' */ +.uil-mars:before { + content: '\eaa6'; +} /* 'ξͺ¦' */ +.uil-maximize-left:before { + content: '\eaa7'; +} /* 'ξͺ§' */ +.uil-medal:before { + content: '\eaa8'; +} /* 'ξͺ¨' */ +.uil-medical-drip:before { + content: '\eaa9'; +} /* 'ξͺ©' */ +.uil-medical-square-full:before { + content: '\eaaa'; +} /* 'ξͺͺ' */ +.uil-medical-square:before { + content: '\eaab'; +} /* 'ξͺ«' */ +.uil-medical:before { + content: '\eaac'; +} /* 'ξͺ¬' */ +.uil-medium-m:before { + content: '\eaad'; +} /* 'ξͺ­' */ +.uil-medkit:before { + content: '\eaae'; +} /* 'ξͺ' */ +.uil-meeting-board:before { + content: '\eaaf'; +} /* 'ξͺ―' */ +.uil-meh-alt:before { + content: '\eab0'; +} /* 'ξͺ°' */ +.uil-meh-closed-eye:before { + content: '\eab1'; +} /* 'ξͺ±' */ +.uil-meh:before { + content: '\eab2'; +} /* 'ξͺ²' */ +.uil-message:before { + content: '\eab3'; +} /* 'ξͺ³' */ +.uil-microphone-slash:before { + content: '\eab4'; +} /* 'ξͺ΄' */ +.uil-microphone:before { + content: '\eab5'; +} /* 'ξͺ΅' */ +.uil-minus-circle:before { + content: '\eab6'; +} /* 'ξͺΆ' */ +.uil-minus-path:before { + content: '\eab7'; +} /* 'ξͺ·' */ +.uil-minus-square-full:before { + content: '\eab8'; +} /* 'ξͺΈ' */ +.uil-minus-square:before { + content: '\eab9'; +} /* 'ξͺΉ' */ +.uil-minus:before { + content: '\eaba'; +} /* 'ξͺΊ' */ +.uil-missed-call:before { + content: '\eabb'; +} /* 'ξͺ»' */ +.uil-mobey-bill-slash:before { + content: '\eabc'; +} /* 'ξͺΌ' */ +.uil-mobile-android-alt:before { + content: '\eabd'; +} /* 'ξͺ½' */ +.uil-mobile-android:before { + content: '\eabe'; +} /* 'ξͺΎ' */ +.uil-mobile-vibrate:before { + content: '\eabf'; +} /* 'ξͺΏ' */ +.uil-modem:before { + content: '\eac0'; +} /* 'ξ«€' */ +.uil-money-bill-stack:before { + content: '\eac1'; +} /* '' */ +.uil-money-bill:before { + content: '\eac2'; +} /* 'ξ«‚' */ +.uil-money-insert:before { + content: '\eac3'; +} /* '' */ +.uil-money-stack:before { + content: '\eac4'; +} /* 'ξ«„' */ +.uil-money-withdraw:before { + content: '\eac5'; +} /* 'ξ«…' */ +.uil-money-withdrawal:before { + content: '\eac6'; +} /* '' */ +.uil-moneybag-alt:before { + content: '\eac7'; +} /* '' */ +.uil-moneybag:before { + content: '\eac8'; +} /* '' */ +.uil-monitor-heart-rate:before { + content: '\eac9'; +} /* '' */ +.uil-monitor:before { + content: '\eaca'; +} /* '' */ +.uil-moon-eclipse:before { + content: '\eacb'; +} /* 'ξ«‹' */ +.uil-moon:before { + content: '\eacc'; +} /* '' */ +.uil-moonset:before { + content: '\eacd'; +} /* '' */ +.uil-mountains-sun:before { + content: '\eace'; +} /* '' */ +.uil-mountains:before { + content: '\eacf'; +} /* '' */ +.uil-mouse-alt:before { + content: '\ead0'; +} /* '' */ +.uil-mouse:before { + content: '\ead1'; +} /* 'ξ«‘' */ +.uil-multiply:before { + content: '\ead2'; +} /* 'ξ«’' */ +.uil-music-note:before { + content: '\ead3'; +} /* 'ξ«“' */ +.uil-music-tune-slash:before { + content: '\ead4'; +} /* 'ξ«”' */ +.uil-music:before { + content: '\ead5'; +} /* 'ξ«•' */ +.uil-n-a:before { + content: '\ead6'; +} /* 'ξ«–' */ +.uil-navigator:before { + content: '\ead7'; +} /* 'ξ«—' */ +.uil-nerd:before { + content: '\ead8'; +} /* '' */ +.uil-newspaper:before { + content: '\ead9'; +} /* 'ξ«™' */ +.uil-ninja:before { + content: '\eada'; +} /* '' */ +.uil-no-entry:before { + content: '\eadb'; +} /* 'ξ«›' */ +.uil-notebooks:before { + content: '\eadc'; +} /* '' */ +.uil-notes:before { + content: '\eadd'; +} /* '' */ +.uil-object-group:before { + content: '\eade'; +} /* '' */ +.uil-object-ungroup:before { + content: '\eadf'; +} /* '' */ +.uil-octagon:before { + content: '\eae0'; +} /* 'ξ« ' */ +.uil-outgoing-call:before { + content: '\eae1'; +} /* 'ξ«‘' */ +.uil-package:before { + content: '\eae2'; +} /* 'ξ«’' */ +.uil-padlock:before { + content: '\eae3'; +} /* 'ξ«£' */ +.uil-paint-tool:before { + content: '\eae4'; +} /* 'ξ«€' */ +.uil-palette:before { + content: '\eae5'; +} /* 'ξ«₯' */ +.uil-panorama-h-alt:before { + content: '\eae6'; +} /* '' */ +.uil-panorama-h:before { + content: '\eae7'; +} /* 'ξ«§' */ +.uil-panorama-v:before { + content: '\eae8'; +} /* '' */ +.uil-paperclip:before { + content: '\eae9'; +} /* 'ξ«©' */ +.uil-paragraph:before { + content: '\eaea'; +} /* 'ξ«ͺ' */ +.uil-parcel:before { + content: '\eaeb'; +} /* 'ξ««' */ +.uil-parking-square:before { + content: '\eaec'; +} /* '' */ +.uil-pathfinder-unite:before { + content: '\eaed'; +} /* 'ξ«­' */ +.uil-pathfinder:before { + content: '\eaee'; +} /* 'ξ«' */ +.uil-pause-circle:before { + content: '\eaef'; +} /* 'ξ«―' */ +.uil-pause:before { + content: '\eaf0'; +} /* 'ξ«°' */ +.uil-paypal:before { + content: '\eaf1'; +} /* 'ξ«±' */ +.uil-pen:before { + content: '\eaf2'; +} /* 'ξ«²' */ +.uil-pentagon:before { + content: '\eaf3'; +} /* 'ξ«³' */ +.uil-phone-alt:before { + content: '\eaf4'; +} /* 'ξ«΄' */ +.uil-phone-pause:before { + content: '\eaf5'; +} /* 'ξ«΅' */ +.uil-phone-slash:before { + content: '\eaf6'; +} /* 'ξ«Ά' */ +.uil-phone-times:before { + content: '\eaf7'; +} /* 'ξ«·' */ +.uil-phone-volume:before { + content: '\eaf8'; +} /* 'ξ«Έ' */ +.uil-phone:before { + content: '\eaf9'; +} /* 'ξ«Ή' */ +.uil-picture:before { + content: '\eafa'; +} /* 'ξ«Ί' */ +.uil-plane-arrival:before { + content: '\eafb'; +} /* 'ξ«»' */ +.uil-plane-departure:before { + content: '\eafc'; +} /* 'ξ«Ό' */ +.uil-plane-fly:before { + content: '\eafd'; +} /* 'ξ«½' */ +.uil-plane:before { + content: '\eafe'; +} /* 'ξ«Ύ' */ +.uil-play-circle:before { + content: '\eaff'; +} /* 'ξ«Ώ' */ +.uil-play:before { + content: '\eb00'; +} /* '' */ +.uil-plug:before { + content: '\eb01'; +} /* '' */ +.uil-plus-circle:before { + content: '\eb02'; +} /* '' */ +.uil-plus-square:before { + content: '\eb03'; +} /* '' */ +.uil-plus:before { + content: '\eb04'; +} /* '' */ +.uil-podium:before { + content: '\eb05'; +} /* 'ξ¬…' */ +.uil-polygon:before { + content: '\eb06'; +} /* '' */ +.uil-post-stamp:before { + content: '\eb07'; +} /* '' */ +.uil-postcard:before { + content: '\eb08'; +} /* '' */ +.uil-pound-circle:before { + content: '\eb09'; +} /* '' */ +.uil-pound:before { + content: '\eb0a'; +} /* '' */ +.uil-power:before { + content: '\eb0b'; +} /* '' */ +.uil-prescription-bottle:before { + content: '\eb0c'; +} /* '' */ +.uil-presentation-check:before { + content: '\eb0d'; +} /* '' */ +.uil-presentation-edit:before { + content: '\eb0e'; +} /* '' */ +.uil-presentation-line:before { + content: '\eb0f'; +} /* '' */ +.uil-presentation-lines-alt:before { + content: '\eb10'; +} /* '' */ +.uil-presentation-minus:before { + content: '\eb11'; +} /* '' */ +.uil-presentation-play:before { + content: '\eb12'; +} /* 'ξ¬’' */ +.uil-presentation-plus:before { + content: '\eb13'; +} /* '' */ +.uil-presentation-times:before { + content: '\eb14'; +} /* '' */ +.uil-presentation:before { + content: '\eb15'; +} /* '' */ +.uil-previous:before { + content: '\eb16'; +} /* 'ξ¬–' */ +.uil-pricetag-alt:before { + content: '\eb17'; +} /* 'ξ¬—' */ +.uil-print-slash:before { + content: '\eb18'; +} /* '' */ +.uil-print:before { + content: '\eb19'; +} /* '' */ +.uil-processor:before { + content: '\eb1a'; +} /* '' */ +.uil-pump:before { + content: '\eb1b'; +} /* '' */ +.uil-puzzle-piece:before { + content: '\eb1c'; +} /* '' */ +.uil-question-circle:before { + content: '\eb1d'; +} /* '' */ +.uil-raddit-alien-alt:before { + content: '\eb1e'; +} /* '' */ +.uil-rainbow:before { + content: '\eb1f'; +} /* '' */ +.uil-raindrops-alt:before { + content: '\eb20'; +} /* 'ξ¬ ' */ +.uil-raindrops:before { + content: '\eb21'; +} /* '' */ +.uil-receipt-alt:before { + content: '\eb22'; +} /* 'ξ¬’' */ +.uil-receipt:before { + content: '\eb23'; +} /* '' */ +.uil-record-audio:before { + content: '\eb24'; +} /* '' */ +.uil-redo:before { + content: '\eb25'; +} /* 'ξ¬₯' */ +.uil-refresh:before { + content: '\eb26'; +} /* '' */ +.uil-registered:before { + content: '\eb27'; +} /* '' */ +.uil-repeat:before { + content: '\eb28'; +} /* '' */ +.uil-restaurant:before { + content: '\eb29'; +} /* '' */ +.uil-right-indent-alt:before { + content: '\eb2a'; +} /* 'ξ¬ͺ' */ +.uil-right-to-left-text-direction:before { + content: '\eb2b'; +} /* '' */ +.uil-robot:before { + content: '\eb2c'; +} /* '' */ +.uil-rope-way:before { + content: '\eb2d'; +} /* 'ξ¬­' */ +.uil-rotate-360:before { + content: '\eb2e'; +} /* 'ξ¬' */ +.uil-rss-alt:before { + content: '\eb2f'; +} /* 'ξ¬―' */ +.uil-rss-interface:before { + content: '\eb30'; +} /* 'ξ¬°' */ +.uil-rss:before { + content: '\eb31'; +} /* '' */ +.uil-ruler-combined:before { + content: '\eb32'; +} /* '' */ +.uil-ruler:before { + content: '\eb33'; +} /* '' */ +.uil-sad-cry:before { + content: '\eb34'; +} /* '' */ +.uil-sad-crying:before { + content: '\eb35'; +} /* '' */ +.uil-sad-dizzy:before { + content: '\eb36'; +} /* 'ξ¬Ά' */ +.uil-sad-squint:before { + content: '\eb37'; +} /* 'ξ¬·' */ +.uil-sad:before { + content: '\eb38'; +} /* 'ξ¬Έ' */ +.uil-scaling-left:before { + content: '\eb39'; +} /* 'ξ¬Ή' */ +.uil-scaling-right:before { + content: '\eb3a'; +} /* 'ξ¬Ί' */ +.uil-scenery:before { + content: '\eb3b'; +} /* '' */ +.uil-schedule:before { + content: '\eb3c'; +} /* 'ξ¬Ό' */ +.uil-science:before { + content: '\eb3d'; +} /* '' */ +.uil-screw:before { + content: '\eb3e'; +} /* 'ξ¬Ύ' */ +.uil-scroll-h:before { + content: '\eb3f'; +} /* 'ξ¬Ώ' */ +.uil-scroll:before { + content: '\eb40'; +} /* 'ξ­€' */ +.uil-search-alt:before { + content: '\eb41'; +} /* '' */ +.uil-search-minus:before { + content: '\eb42'; +} /* 'ξ­‚' */ +.uil-search-plus:before { + content: '\eb43'; +} /* 'ξ­ƒ' */ +.uil-search:before { + content: '\eb44'; +} /* 'ξ­„' */ +.uil-selfie:before { + content: '\eb45'; +} /* 'ξ­…' */ +.uil-server-alt:before { + content: '\eb46'; +} /* 'ξ­†' */ +.uil-server-connection:before { + content: '\eb47'; +} /* 'ξ­‡' */ +.uil-server-network-alt:before { + content: '\eb48'; +} /* '' */ +.uil-server-network:before { + content: '\eb49'; +} /* 'ξ­‰' */ +.uil-server:before { + content: '\eb4a'; +} /* '' */ +.uil-servers:before { + content: '\eb4b'; +} /* 'ξ­‹' */ +.uil-servicemark:before { + content: '\eb4c'; +} /* '' */ +.uil-share-alt:before { + content: '\eb4d'; +} /* '' */ +.uil-shield-check:before { + content: '\eb4e'; +} /* '' */ +.uil-shield-exclamation:before { + content: '\eb4f'; +} /* '' */ +.uil-shield-question:before { + content: '\eb50'; +} /* '' */ +.uil-shield-slash:before { + content: '\eb51'; +} /* 'ξ­‘' */ +.uil-shield:before { + content: '\eb52'; +} /* 'ξ­’' */ +.uil-ship:before { + content: '\eb53'; +} /* 'ξ­“' */ +.uil-shop:before { + content: '\eb54'; +} /* 'ξ­”' */ +.uil-shopping-basket:before { + content: '\eb55'; +} /* 'ξ­•' */ +.uil-shopping-cart-alt:before { + content: '\eb56'; +} /* 'ξ­–' */ +.uil-shopping-trolley:before { + content: '\eb57'; +} /* 'ξ­—' */ +.uil-shovel:before { + content: '\eb58'; +} /* '' */ +.uil-shrink:before { + content: '\eb59'; +} /* 'ξ­™' */ +.uil-shuffle:before { + content: '\eb5a'; +} /* '' */ +.uil-shutter-alt:before { + content: '\eb5b'; +} /* 'ξ­›' */ +.uil-shutter:before { + content: '\eb5c'; +} /* '' */ +.uil-sick:before { + content: '\eb5d'; +} /* '' */ +.uil-sigma:before { + content: '\eb5e'; +} /* '' */ +.uil-sign-alt:before { + content: '\eb5f'; +} /* '' */ +.uil-sign-in-alt:before { + content: '\eb60'; +} /* 'ξ­ ' */ +.uil-sign-left:before { + content: '\eb61'; +} /* 'ξ­‘' */ +.uil-sign-out-alt:before { + content: '\eb62'; +} /* 'ξ­’' */ +.uil-sign-right:before { + content: '\eb63'; +} /* 'ξ­£' */ +.uil-signal-alt-3:before { + content: '\eb64'; +} /* 'ξ­€' */ +.uil-signal-alt:before { + content: '\eb65'; +} /* 'ξ­₯' */ +.uil-signal:before { + content: '\eb66'; +} /* 'ξ­¦' */ +.uil-silence:before { + content: '\eb67'; +} /* 'ξ­§' */ +.uil-silent-squint:before { + content: '\eb68'; +} /* 'ξ­¨' */ +.uil-sim-card:before { + content: '\eb69'; +} /* 'ξ­©' */ +.uil-sitemap:before { + content: '\eb6a'; +} /* 'ξ­ͺ' */ +.uil-skip-forward-alt:before { + content: '\eb6b'; +} /* 'ξ­«' */ +.uil-skip-forward-circle:before { + content: '\eb6c'; +} /* 'ξ­¬' */ +.uil-skip-forward:before { + content: '\eb6d'; +} /* 'ξ­­' */ +.uil-slack-alt:before { + content: '\eb6e'; +} /* 'ξ­' */ +.uil-slack:before { + content: '\eb6f'; +} /* 'ξ­―' */ +.uil-sliders-v-alt:before { + content: '\eb70'; +} /* 'ξ­°' */ +.uil-sliders-v:before { + content: '\eb71'; +} /* 'ξ­±' */ +.uil-smile-beam:before { + content: '\eb72'; +} /* 'ξ­²' */ +.uil-smile-dizzy:before { + content: '\eb73'; +} /* 'ξ­³' */ +.uil-smile-squint-wink-alt:before { + content: '\eb74'; +} /* 'ξ­΄' */ +.uil-smile-squint-wink:before { + content: '\eb75'; +} /* 'ξ­΅' */ +.uil-smile-wink-alt:before { + content: '\eb76'; +} /* 'ξ­Ά' */ +.uil-smile-wink:before { + content: '\eb77'; +} /* 'ξ­·' */ +.uil-smile:before { + content: '\eb78'; +} /* 'ξ­Έ' */ +.uil-snapchat-ghost:before { + content: '\eb79'; +} /* 'ξ­Ή' */ +.uil-snapchat-square:before { + content: '\eb7a'; +} /* 'ξ­Ί' */ +.uil-snow-flake:before { + content: '\eb7b'; +} /* 'ξ­»' */ +.uil-snowflake-alt:before { + content: '\eb7c'; +} /* 'ξ­Ό' */ +.uil-snowflake:before { + content: '\eb7d'; +} /* 'ξ­½' */ +.uil-sort-amount-down:before { + content: '\eb7e'; +} /* 'ξ­Ύ' */ +.uil-sort-amount-up:before { + content: '\eb7f'; +} /* 'ξ­Ώ' */ +.uil-sort:before { + content: '\eb80'; +} /* 'ξ€' */ +.uil-sorting:before { + content: '\eb81'; +} /* 'ξ' */ +.uil-space-key:before { + content: '\eb82'; +} /* 'ξ‚' */ +.uil-spade:before { + content: '\eb83'; +} /* 'ξƒ' */ +.uil-sperms:before { + content: '\eb84'; +} /* 'ξ„' */ +.uil-spin:before { + content: '\eb85'; +} /* 'ξ…' */ +.uil-sport:before { + content: '\eb86'; +} /* 'ξ†' */ +.uil-square-full:before { + content: '\eb87'; +} /* 'ξ‡' */ +.uil-square-shape:before { + content: '\eb88'; +} /* 'ξˆ' */ +.uil-square:before { + content: '\eb89'; +} /* 'ξ‰' */ +.uil-squint:before { + content: '\eb8a'; +} /* 'ξŠ' */ +.uil-star-half-alt:before { + content: '\eb8b'; +} /* 'ξ‹' */ +.uil-star:before { + content: '\eb8c'; +} /* 'ξŒ' */ +.uil-step-backward-alt:before { + content: '\eb8d'; +} /* 'ξ' */ +.uil-step-backward-circle:before { + content: '\eb8e'; +} /* 'ξŽ' */ +.uil-step-backward:before { + content: '\eb8f'; +} /* 'ξ' */ +.uil-step-forward:before { + content: '\eb90'; +} /* 'ξ' */ +.uil-stop-circle:before { + content: '\eb91'; +} /* 'ξ‘' */ +.uil-stopwatch-slash:before { + content: '\eb92'; +} /* 'ξ’' */ +.uil-stopwatch:before { + content: '\eb93'; +} /* 'ξ“' */ +.uil-store-alt:before { + content: '\eb94'; +} /* 'ξ”' */ +.uil-store:before { + content: '\eb95'; +} /* 'ξ•' */ +.uil-streering:before { + content: '\eb96'; +} /* 'ξ–' */ +.uil-stretcher:before { + content: '\eb97'; +} /* 'ξ—' */ +.uil-subject:before { + content: '\eb98'; +} /* 'ξ˜' */ +.uil-subway-alt:before { + content: '\eb99'; +} /* 'ξ™' */ +.uil-subway:before { + content: '\eb9a'; +} /* 'ξš' */ +.uil-suitcase-alt:before { + content: '\eb9b'; +} /* 'ξ›' */ +.uil-suitcase:before { + content: '\eb9c'; +} /* 'ξœ' */ +.uil-sun:before { + content: '\eb9d'; +} /* 'ξ' */ +.uil-sunset:before { + content: '\eb9e'; +} /* 'ξž' */ +.uil-surprise:before { + content: '\eb9f'; +} /* 'ξŸ' */ +.uil-swatchbook:before { + content: '\eba0'; +} /* 'ξ ' */ +.uil-swimmer:before { + content: '\eba1'; +} /* 'ξ‘' */ +.uil-symbol:before { + content: '\eba2'; +} /* 'ξ’' */ +.uil-sync-exclamation:before { + content: '\eba3'; +} /* 'ξ£' */ +.uil-sync-slash:before { + content: '\eba4'; +} /* 'ξ€' */ +.uil-sync:before { + content: '\eba5'; +} /* 'ξ₯' */ +.uil-syringe:before { + content: '\eba6'; +} /* 'ξ¦' */ +.uil-table:before { + content: '\eba7'; +} /* 'ξ§' */ +.uil-tablet:before { + content: '\eba8'; +} /* 'ξ¨' */ +.uil-tablets:before { + content: '\eba9'; +} /* 'ξ©' */ +.uil-tachometer-fast:before { + content: '\ebaa'; +} /* 'ξͺ' */ +.uil-tag-alt:before { + content: '\ebab'; +} /* 'ξ«' */ +.uil-tag:before { + content: '\ebac'; +} /* 'ξ¬' */ +.uil-tape:before { + content: '\ebad'; +} /* 'ξ­' */ +.uil-taxi:before { + content: '\ebae'; +} /* 'ξ' */ +.uil-tear:before { + content: '\ebaf'; +} /* 'ξ―' */ +.uil-technology:before { + content: '\ebb0'; +} /* 'ξ°' */ +.uil-telescope:before { + content: '\ebb1'; +} /* 'ξ±' */ +.uil-temperature-empty:before { + content: '\ebb2'; +} /* 'ξ²' */ +.uil-temperature-half:before { + content: '\ebb3'; +} /* 'ξ³' */ +.uil-temperature-minus:before { + content: '\ebb4'; +} /* 'ξ΄' */ +.uil-temperature-plus:before { + content: '\ebb5'; +} /* 'ξ΅' */ +.uil-temperature-quarter:before { + content: '\ebb6'; +} /* 'ξΆ' */ +.uil-temperature-three-quarter:before { + content: '\ebb7'; +} /* 'ξ·' */ +.uil-temperature:before { + content: '\ebb8'; +} /* 'ξΈ' */ +.uil-text-fields:before { + content: '\ebb9'; +} /* 'ξΉ' */ +.uil-text-size:before { + content: '\ebba'; +} /* 'ξΊ' */ +.uil-text-strike-through:before { + content: '\ebbb'; +} /* 'ξ»' */ +.uil-text:before { + content: '\ebbc'; +} /* 'ξΌ' */ +.uil-th-large:before { + content: '\ebbd'; +} /* 'ξ½' */ +.uil-th-slash:before { + content: '\ebbe'; +} /* 'ξΎ' */ +.uil-th:before { + content: '\ebbf'; +} /* 'ξΏ' */ +.uil-thermometer:before { + content: '\ebc0'; +} /* 'ξ―€' */ +.uil-thumbs-down:before { + content: '\ebc1'; +} /* '' */ +.uil-thumbs-up:before { + content: '\ebc2'; +} /* 'ξ―‚' */ +.uil-thunderstorm-moon:before { + content: '\ebc3'; +} /* 'ξ―ƒ' */ +.uil-thunderstorm-sun:before { + content: '\ebc4'; +} /* 'ξ―„' */ +.uil-thunderstorm:before { + content: '\ebc5'; +} /* 'ξ―…' */ +.uil-ticket:before { + content: '\ebc6'; +} /* 'ξ―†' */ +.uil-times-circle:before { + content: '\ebc7'; +} /* 'ξ―‡' */ +.uil-times-square:before { + content: '\ebc8'; +} /* '' */ +.uil-times:before { + content: '\ebc9'; +} /* 'ξ―‰' */ +.uil-toggle-off:before { + content: '\ebca'; +} /* '' */ +.uil-toggle-on:before { + content: '\ebcb'; +} /* 'ξ―‹' */ +.uil-top-arrow-from-top:before { + content: '\ebcc'; +} /* '' */ +.uil-top-arrow-to-top:before { + content: '\ebcd'; +} /* '' */ +.uil-tornado:before { + content: '\ebce'; +} /* '' */ +.uil-trademark-circle:before { + content: '\ebcf'; +} /* '' */ +.uil-trademark:before { + content: '\ebd0'; +} /* '' */ +.uil-traffic-barrier:before { + content: '\ebd1'; +} /* 'ξ―‘' */ +.uil-trash-alt:before { + content: '\ebd2'; +} /* 'ξ―’' */ +.uil-trash:before { + content: '\ebd3'; +} /* 'ξ―“' */ +.uil-trees:before { + content: '\ebd4'; +} /* 'ξ―”' */ +.uil-triangle:before { + content: '\ebd5'; +} /* 'ξ―•' */ +.uil-trophy:before { + content: '\ebd6'; +} /* 'ξ―–' */ +.uil-trowel:before { + content: '\ebd7'; +} /* 'ξ―—' */ +.uil-truck-case:before { + content: '\ebd8'; +} /* '' */ +.uil-truck-loading:before { + content: '\ebd9'; +} /* 'ξ―™' */ +.uil-truck:before { + content: '\ebda'; +} /* '' */ +.uil-tumblr-square:before { + content: '\ebdb'; +} /* 'ξ―›' */ +.uil-tumblr:before { + content: '\ebdc'; +} /* '' */ +.uil-tv-retro-slash:before { + content: '\ebdd'; +} /* '' */ +.uil-tv-retro:before { + content: '\ebde'; +} /* '' */ +.uil-twitter:before { + content: '\ebdf'; +} /* '' */ +.uil-umbrella:before { + content: '\ebe0'; +} /* 'ξ― ' */ +.uil-unamused:before { + content: '\ebe1'; +} /* 'ξ―‘' */ +.uil-underline:before { + content: '\ebe2'; +} /* 'ξ―’' */ +.uil-unlock-alt:before { + content: '\ebe3'; +} /* 'ξ―£' */ +.uil-unlock:before { + content: '\ebe4'; +} /* 'ξ―€' */ +.uil-upload-alt:before { + content: '\ebe5'; +} /* 'ξ―₯' */ +.uil-upload:before { + content: '\ebe6'; +} /* 'ξ―¦' */ +.uil-usd-circle:before { + content: '\ebe7'; +} /* 'ξ―§' */ +.uil-usd-square:before { + content: '\ebe8'; +} /* 'ξ―¨' */ +.uil-user-check:before { + content: '\ebe9'; +} /* 'ξ―©' */ +.uil-user-circle:before { + content: '\ebea'; +} /* 'ξ―ͺ' */ +.uil-user-exclamation:before { + content: '\ebeb'; +} /* 'ξ―«' */ +.uil-user-hard-hat:before { + content: '\ebec'; +} /* 'ξ―¬' */ +.uil-user-minus:before { + content: '\ebed'; +} /* 'ξ―­' */ +.uil-user-plus:before { + content: '\ebee'; +} /* 'ξ―' */ +.uil-user-square:before { + content: '\ebef'; +} /* 'ξ――' */ +.uil-user-times:before { + content: '\ebf0'; +} /* 'ξ―°' */ +.uil-user:before { + content: '\ebf1'; +} /* 'ξ―±' */ +.uil-users-alt:before { + content: '\ebf2'; +} /* 'ξ―²' */ +.uil-utensils-alt:before { + content: '\ebf3'; +} /* 'ξ―³' */ +.uil-utensils:before { + content: '\ebf4'; +} /* 'ξ―΄' */ +.uil-vector-square-alt:before { + content: '\ebf5'; +} /* 'ξ―΅' */ +.uil-vector-square:before { + content: '\ebf6'; +} /* 'ξ―Ά' */ +.uil-venus:before { + content: '\ebf7'; +} /* 'ξ―·' */ +.uil-vertical-align-bottom:before { + content: '\ebf8'; +} /* 'ξ―Έ' */ +.uil-vertical-align-center:before { + content: '\ebf9'; +} /* 'ξ―Ή' */ +.uil-vertical-align-top:before { + content: '\ebfa'; +} /* 'ξ―Ί' */ +.uil-vertical-distribute-bottom:before { + content: '\ebfb'; +} /* 'ξ―»' */ +.uil-vertical-distribution-center:before { + content: '\ebfc'; +} /* 'ξ―Ό' */ +.uil-vertical-distribution-top:before { + content: '\ebfd'; +} /* 'ξ―½' */ +.uil-video-slash:before { + content: '\ebfe'; +} /* 'ξ―Ύ' */ +.uil-video:before { + content: '\ebff'; +} /* 'ξ―Ώ' */ +.uil-visual-studio:before { + content: '\ec00'; +} /* 'ξ°€' */ +.uil-voicemail-rectangle:before { + content: '\ec01'; +} /* '' */ +.uil-voicemail:before { + content: '\ec02'; +} /* 'ξ°‚' */ +.uil-volleyball:before { + content: '\ec03'; +} /* 'ξ°ƒ' */ +.uil-volume-down:before { + content: '\ec04'; +} /* 'ξ°„' */ +.uil-volume-mute:before { + content: '\ec05'; +} /* 'ξ°…' */ +.uil-volume-off:before { + content: '\ec06'; +} /* 'ξ°†' */ +.uil-volume-up:before { + content: '\ec07'; +} /* 'ξ°‡' */ +.uil-volume:before { + content: '\ec08'; +} /* '' */ +.uil-vuejs-alt:before { + content: '\ec09'; +} /* 'ξ°‰' */ +.uil-vuejs:before { + content: '\ec0a'; +} /* '' */ +.uil-wall:before { + content: '\ec0b'; +} /* 'ξ°‹' */ +.uil-wallet:before { + content: '\ec0c'; +} /* '' */ +.uil-watch-alt:before { + content: '\ec0d'; +} /* '' */ +.uil-watch:before { + content: '\ec0e'; +} /* '' */ +.uil-water-drop-slash:before { + content: '\ec0f'; +} /* '' */ +.uil-water-glass:before { + content: '\ec10'; +} /* '' */ +.uil-water:before { + content: '\ec11'; +} /* 'ξ°‘' */ +.uil-web-grid-alt:before { + content: '\ec12'; +} /* 'ξ°’' */ +.uil-web-grid:before { + content: '\ec13'; +} /* 'ξ°“' */ +.uil-web-section-alt:before { + content: '\ec14'; +} /* 'ξ°”' */ +.uil-web-section:before { + content: '\ec15'; +} /* 'ξ°•' */ +.uil-webcam:before { + content: '\ec16'; +} /* 'ξ°–' */ +.uil-weight:before { + content: '\ec17'; +} /* 'ξ°—' */ +.uil-whatsapp:before { + content: '\ec18'; +} /* '' */ +.uil-wheel-barrow:before { + content: '\ec19'; +} /* 'ξ°™' */ +.uil-wheelchair-alt:before { + content: '\ec1a'; +} /* '' */ +.uil-wheelchair:before { + content: '\ec1b'; +} /* 'ξ°›' */ +.uil-wifi-router:before { + content: '\ec1c'; +} /* '' */ +.uil-wifi-slash:before { + content: '\ec1d'; +} /* '' */ +.uil-wifi:before { + content: '\ec1e'; +} /* '' */ +.uil-wind:before { + content: '\ec1f'; +} /* '' */ +.uil-window-grid:before { + content: '\ec20'; +} /* 'ξ° ' */ +.uil-window-maximize:before { + content: '\ec21'; +} /* 'ξ°‘' */ +.uil-window-restore:before { + content: '\ec22'; +} /* 'ξ°’' */ +.uil-window-section:before { + content: '\ec23'; +} /* 'ξ°£' */ +.uil-window:before { + content: '\ec24'; +} /* 'ξ°€' */ +.uil-windsock:before { + content: '\ec25'; +} /* 'ξ°₯' */ +.uil-wrap-text:before { + content: '\ec26'; +} /* 'ξ°¦' */ +.uil-wrench:before { + content: '\ec27'; +} /* 'ξ°§' */ +.uil-yellow:before { + content: '\ec28'; +} /* 'ξ°¨' */ +.uil-yen-circle:before { + content: '\ec29'; +} /* 'ξ°©' */ +.uil-yen:before { + content: '\ec2a'; +} /* 'ξ°ͺ' */ +.uil-youtube-alt:before { + content: '\ec2b'; +} /* 'ξ°«' */ +.uil-youtube:before { + content: '\ec2c'; +} /* 'ξ°¬' */ diff --git a/twake/frontend/src/app/components/infinite-messages/infinite-messages-tester.jsx b/twake/frontend/src/app/components/infinite-messages/infinite-messages-tester.jsx new file mode 100755 index 00000000..0ccbe4c4 --- /dev/null +++ b/twake/frontend/src/app/components/infinite-messages/infinite-messages-tester.jsx @@ -0,0 +1,74 @@ +import React, { Component } from 'react'; + +import InfiniteMessages from './infinite-messages.js'; + +export default class InfiniteMessagesTester extends Component { + constructor() { + super(); + + ///////// Simulate messages + this.messages = []; + this.i = 0; + for (this.i; this.i < 10000; this.i++) { + this.messages.push({ + content: 'message ' + this.i, + height: 40 + Math.random() * 100, + id: this.i, + }); + } + setInterval(() => { + this.messages.push({ + content: 'message ' + this.i, + height: 40 + Math.random() * 100, + id: this.i, + }); + this.i++; + this.setState({}); + }, 1000); + /////////// + + this.infinieMessages = null; + } + getMessages(offset, limit, callback) { + if (!offset) { + setTimeout(() => { + callback(this.messages.slice(this.messages.length - limit, this.messages.length)); + }, 10); + } else { + var offsetPos = 0; + this.messages.every(m => { + if (m.id >= offset) { + return false; + } + offsetPos++; + return true; + }); + + setTimeout(() => { + if (limit > 0) { + callback(this.messages.slice(offsetPos - limit, offsetPos)); + } else { + callback(this.messages.slice(offsetPos + 1, offsetPos - limit)); + } + }, 10); + } + } + render() { + return ( +
+ (this.infinieMessages = node)} + getMessages={(offset, limit, callback) => this.getMessages(offset, limit, callback)} + messages={this.messages} + offsetKey={'id'} + top={''} + renderMessage={(message, oldmessage, measure) => ( +
+ {message.content} +
+ )} + /> +
+ ); + } +} diff --git a/twake/frontend/src/app/components/infinite-messages/infinite-messages.jsx b/twake/frontend/src/app/components/infinite-messages/infinite-messages.jsx new file mode 100755 index 00000000..bc1ad2f4 --- /dev/null +++ b/twake/frontend/src/app/components/infinite-messages/infinite-messages.jsx @@ -0,0 +1,472 @@ +/* eslint-disable react/no-direct-mutation-state */ +import React, { Component } from 'react'; + +import Button from 'components/buttons/button.jsx'; +import './infinite-messages.scss'; + +export default class InfiniteMessages extends Component { + constructor(props) { + super(props); + + window.test = this; + + this.init(props); + + this.onScroll = this.onScroll.bind(this); + this.onUpdate = this.onUpdate.bind(this); + } + + init(props) { + props = props || this.props; + + this.on_load_min = {}; + if (props.messages.length > 60) { + this.on_load_min = props.messages.slice(props.messages.length - 60, props.messages.length)[0]; + } else { + this.on_load_min = props.messages[0] || {}; + } + + this.state = { + messages: props.messages.filter(m => this.compare(m, this.on_load_min) >= 0), + }; + this.shouldAutoScroll = true; + this.messages_min = this.state.messages[0] || {}; + this.messages_med = this.state.messages[this.state.messages.length - 1] || {}; + this.messages_max = this.state.messages[this.state.messages.length - 1] || {}; + this.bloc_top_height = 0; + + this.did_update_messages_data = {}; + + this.dom_messages = {}; + + this.max_known = this.messages_max; + } + + componentDidMount() { + this.did_update_messages = true; + this.did_update_messages_data = { + direction: 'bottom_auto_add', + bloc_top_height: this.dom_visualized_messages_top.clientHeight, + bloc_bottom_height: this.dom_visualized_messages_bottom.clientHeight, + scroll_top: this.dom_infinite_messages.scrollTop, + scroll_height: this.dom_infinite_messages.scrollHeight, + }; + + // this.dom_infinite_messages.addEventListener("scroll", this.onScroll); + window.addEventListener('resize', this.onUpdate); + + this.onUpdate(); + } + componentWillUnmount() { + window.removeEventListener('resize', this.onUpdate); + // this.dom_infinite_messages.removeEventListener("scroll", this.onScroll); + } + UNSAFE_componentWillUpdate(nextProps, nextState) { + this.scroll_distance_from_bottom = + this.dom_infinite_messages.scrollHeight - + this.dom_infinite_messages.clientHeight - + this.dom_infinite_messages.scrollTop; + + if (nextProps.messages.length) { + if (nextProps.messages[nextProps.messages.length - 1].id) { + if (this.messages_med.id == this.max_known.id) { + this.messages_med = nextProps.messages[nextProps.messages.length - 1]; + this.messages_max = nextProps.messages[nextProps.messages.length - 1]; + } + this.max_known = nextProps.messages[nextProps.messages.length - 1]; + } + } + if (this.max_known.id == this.messages_med.id) { + nextState.messages = nextProps.messages.filter(m => { + return !m.id || this.compare(m, this.on_load_min) >= 0; + }); + this.did_update_messages = true; + this.did_update_messages_data = { + direction: 'bottom_auto_add', + bloc_top_height: this.dom_visualized_messages_top.clientHeight, + bloc_bottom_height: this.dom_visualized_messages_bottom.clientHeight, + scroll_top: this.dom_infinite_messages.scrollTop, + scroll_height: this.dom_infinite_messages.scrollHeight, + }; + } + } + componentDidUpdate() { + this.onUpdate(); + } + + onUpdate() { + this.did_auto_scroll = new Date(); + + this.scrollToBottom(); + var dom_fake_separator_top_visible = Math.max( + 0, + this.dom_infinite_messages.clientHeight - this.dom_visualized_messages_top.clientHeight, + ); + if (dom_fake_separator_top_visible == 0) { + this.dom_fake_separator_top.style.display = 'none'; + } else { + this.dom_fake_separator_top.style.display = 'block'; + } + + if (this.did_update_messages) { + this.did_update_messages = false; + this.bloc_top_height = this.dom_visualized_messages_top.clientHeight; + this.bloc_bottom_height = this.dom_visualized_messages_bottom.clientHeight; + + if (this.did_update_messages_data.direction == 'bottom') { + this.scrollToPosition( + this.dom_anything_on_top.clientHeight + + (this.did_update_messages_data.bloc_bottom_height - + (this.did_update_messages_data.scroll_height - + this.did_update_messages_data.scroll_top)), + ); + } else if (this.did_update_messages_data.direction == 'bottom_auto_add') { + //Nothing + } else { + this.scrollToPosition(this.bloc_top_height + this.did_update_messages_data.scroll_top); + } + + this.getVisibleMessages(); + } + } + + onScroll(evt) { + if (new Date() - this.did_auto_scroll < 100) { + return; + } + + if ( + this.dom_infinite_messages.scrollHeight != this.last_scrollHeight && + this.shouldAutoScroll + ) { + this.last_scrollHeight = this.dom_infinite_messages.scrollHeight; + this.scrollToBottom(); + } else { + var shouldAutoScroll = this.shouldAutoScroll; + this.shouldAutoScroll = false; + if (this.props.onAutoScrollChange && shouldAutoScroll) this.props.onAutoScrollChange(false); + } + + if (this.dom_infinite_messages.scrollTop <= this.dom_infinite_messages.scrollHeight / 8) { + this.onScrollTop(); + } + var dist_from_bottom = + this.dom_infinite_messages.scrollHeight - + this.dom_infinite_messages.scrollTop - + this.dom_infinite_messages.clientHeight; + if (dist_from_bottom <= Math.max(10, this.dom_infinite_messages.scrollHeight / 8)) { + if ( + dist_from_bottom <= 10 && + (this.shouldAutoScroll || + this.max_known.id == this.state.messages[this.state.messages.length - 1].id) + ) { + // eslint-disable-next-line no-redeclare + var shouldAutoScroll = this.shouldAutoScroll; + this.shouldAutoScroll = true; + if (this.props.onAutoScrollChange && !shouldAutoScroll) this.props.onAutoScrollChange(true); + } else if (dist_from_bottom <= 10 || this.max_known.id != this.messages_med.id) { + this.onScrollBottom(); + } + } + + this.getVisibleMessages(); + } + + getVisibleMessages() { + if ( + this.last_get && + Math.abs(this.last_get.scroll_top - this.dom_infinite_messages.scrollTop) < 40 + ) { + return [this.last_get.first]; + } + + var first = null; + + var frame = window.getBoundingClientRect(this.dom_infinite_messages); + frame.x = frame.x || frame.left; + frame.y = frame.y || frame.top; + frame.scrollTop = this.dom_infinite_messages.scrollTop; + + Object.keys(this.dom_messages).every(i => { + var item = this.dom_messages[i]; + if (item.node && item.scrollTop === undefined) { + item.scrollTop = window.getBoundingClientRect(item.node).top + frame.scrollTop - frame.y; + } + if (item.node) { + if (!first && item.scrollTop > frame.scrollTop) { + first = item.message; + return false; + } + } + return true; + }); + + var first_date = new Date((first || {}).creation_date * 1000).setHours(0, 0, 0, 0); + + if (first_date != (this.last_get || {}).first_date) { + if (this.props.onFirstDateChange) this.props.onFirstDateChange(first_date); + } + + this.last_get = { + scroll_top: frame.scrollTop, + first: first, + first_date: first_date, + }; + + return [this.last_get.first]; + } + + scrollToBottom(force) { + if (this.shouldAutoScroll || force) { + //Make sure we display the last bloc ! + if ( + this.messages_med.id != this.messages_min.id && + this.messages_med.id != this.messages_max.id + ) { + this.init(); + this.did_update_messages = true; + this.did_update_messages_data = { + direction: 'bottom_auto_add', + bloc_top_height: this.dom_visualized_messages_top.clientHeight, + bloc_bottom_height: this.dom_visualized_messages_bottom.clientHeight, + scroll_top: this.dom_infinite_messages.scrollTop, + scroll_height: this.dom_infinite_messages.scrollHeight, + }; + + this.onUpdate(); + } + + var old_position = this.dom_infinite_messages.scrollTop; + this.dom_infinite_messages.scrollTop = this.dom_infinite_messages.scrollHeight; + if (old_position != this.dom_infinite_messages.scrollTop) { + this.did_auto_scroll = new Date(); + } + + var shouldAutoScroll = this.shouldAutoScroll; + this.shouldAutoScroll = true; + if (this.props.onAutoScrollChange && !shouldAutoScroll) this.props.onAutoScrollChange(true); + } + } + scrollToPosition(scrollTop) { + var old_position = this.dom_infinite_messages.scrollTop; + this.dom_infinite_messages.scrollTop = scrollTop; + this.did_auto_scroll = new Date(); + } + + onScrollTop() { + if (this.is_getting_top_messages) { + return; + } + + if (this.no_more_before && this.messages_min.id == this.no_more_before.id) { + return; + } + this.number_of_messages_to_load = 2 * (this.dom_infinite_messages.clientHeight / 20); + this.is_getting_top_messages = true; + + this.props.getMessages(this.messages_min.id, parseInt(this.number_of_messages_to_load), res => { + if (res.length == 0) { + this.is_getting_top_messages = false; + this.no_more_before = this.messages_min; + return; + } + + var top_list = this.state.messages.filter( + m => this.compare(m, this.messages_min) >= 0 && this.compare(m, this.messages_med) <= 0, + ); + top_list = res.concat(top_list); + + this.messages_med = res[res.length - 1]; + this.messages_min = res[0]; + this.messages_max = top_list[top_list.length - 1]; + + this.did_update_messages = true; + this.did_update_messages_data = { + direction: 'top', + bloc_top_height: this.dom_visualized_messages_top.clientHeight, + bloc_bottom_height: this.dom_visualized_messages_bottom.clientHeight, + scroll_top: this.dom_infinite_messages.scrollTop, + scroll_height: this.dom_infinite_messages.scrollHeight, + }; + + this.dom_messages = {}; + + this.setState({ messages: top_list }); + + this.is_getting_top_messages = false; + }); + } + + onScrollBottom() { + if (this.is_getting_bottom_messages) { + return; + } + + this.number_of_messages_to_load = 2 * (this.dom_infinite_messages.clientHeight / 20); + this.is_getting_bottom_messages = true; + + this.props.getMessages( + this.messages_max.id, + -parseInt(this.number_of_messages_to_load), + res => { + if (res.length == 0) { + this.is_getting_bottom_messages = false; + var shouldAutoScroll = this.shouldAutoScroll; + this.shouldAutoScroll = true; + if (this.props.onAutoScrollChange && !shouldAutoScroll) + this.props.onAutoScrollChange(true); + + this.max_known = this.state.messages[this.state.messages.length - 1]; + this.messages_min = this.state.messages[0]; + this.messages_max = this.state.messages[this.state.messages.length - 1]; + this.messages_med = this.messages_max; + + return; + } + + if (this.compare(res[res.length - 1], this.on_load_min) >= 0) { + var top_list = this.state.messages.filter(m => this.compare(m, res[res.length - 1]) >= 0); + top_list = top_list.concat(res); + + this.state.messages = this.props.messages.filter( + m => this.compare(m, this.on_load_min) > 0, + ); + + this.max_known = this.state.messages[this.state.messages.length - 1]; + this.messages_min = this.state.messages[0]; + this.messages_max = this.state.messages[this.state.messages.length - 1]; + this.messages_med = this.messages_max; + + this.did_update_messages = true; + this.did_update_messages_data = { + direction: 'bottom_auto_add', + bloc_top_height: this.dom_visualized_messages_top.clientHeight, + bloc_bottom_height: this.dom_visualized_messages_bottom.clientHeight, + scroll_top: this.dom_infinite_messages.scrollTop, + scroll_height: this.dom_infinite_messages.scrollHeight, + }; + + this.dom_messages = {}; + + this.setState({ messages: this.state.messages }); + } else { + // eslint-disable-next-line no-redeclare + var top_list = this.state.messages.filter( + m => this.compare(m, this.messages_med) > 0 && this.compare(m, this.messages_max) <= 0, + ); + top_list = top_list.concat(res); + + this.messages_min = top_list[0]; + this.messages_med = this.messages_max; + this.messages_max = top_list[top_list.length - 1]; + + this.did_update_messages = true; + this.did_update_messages_data = { + direction: 'bottom', + bloc_top_height: this.dom_visualized_messages_top.clientHeight, + bloc_bottom_height: this.dom_visualized_messages_bottom.clientHeight, + scroll_top: this.dom_infinite_messages.scrollTop, + scroll_height: this.dom_infinite_messages.scrollHeight, + }; + + this.dom_messages = {}; + + this.setState({ messages: top_list }); + } + + this.is_getting_bottom_messages = false; + }, + ); + } + + measure(message) { + if (this.dom_infinite_messages) { + this.scrollToBottom(); + } + } + + //Returns a-b as int + compare(a, b) { + if (this.props.compare) { + return this.props.compare(a, b); + } + return a.id - b.id; + } + + render() { + var previous_message = null; + + return ( +
(this.dom_infinite_messages = node)}> +
(this.dom_anything_on_top = node)}> + {this.props.top || ''} + {!this.no_more_before && ( +
+ +
+ )} +
+
(this.dom_fake_separator_top = node)} /> +
(this.dom_visualized_messages_top = node)} + > + {this.state.messages.map((message, _i) => { + if (this.compare(message, this.messages_med) <= 0) { + var tmp = previous_message; + previous_message = message; + var i = _i; + return ( +
+ (this.dom_messages[i] = { + node: node, + message: message, + scrollTop: (this.dom_messages[i] || {}).scrollTop, + }) + } + > + {this.props.renderMessage(message, tmp, () => this.measure(message))} +
+ ); + } + })} +
+
(this.dom_visualized_messages_bottom = node)} + > + {this.state.messages.map((message, _i) => { + if (this.compare(message, this.messages_med) > 0) { + var tmp = previous_message; + previous_message = message; + var i = _i; + return ( +
+ (this.dom_messages[i] = { + node: node, + message: message, + scrollTop: (this.dom_messages[i] || {}).scrollTop, + }) + } + > + {this.props.renderMessage(message, tmp, () => this.measure(message))} +
+ ); + } + })} +
+
+ ); + } +} diff --git a/twake/frontend/src/app/components/infinite-messages/infinite-messages.scss b/twake/frontend/src/app/components/infinite-messages/infinite-messages.scss new file mode 100755 index 00000000..7990a8cb --- /dev/null +++ b/twake/frontend/src/app/components/infinite-messages/infinite-messages.scss @@ -0,0 +1,31 @@ +.infinite_messages { + overflow: auto; + flex: 1; + display: flex; + flex-direction: column; + + .message { + box-sizing: border-box; + } + + .fake_separator_top { + background: transparent; + flex: 1; + } +} + +.infinite_messages_tester { + height: 90vh; + display: flex; + width: 100%; + .message { + box-sizing: border-box; + border: 1px solid #f00; + border-bottom: 5px solid #0f0; + } + .visualized_messages.top { + .message { + background: #fee; + } + } +} diff --git a/twake/frontend/src/app/components/inline-tag-picker/inline-tag-picker.jsx b/twake/frontend/src/app/components/inline-tag-picker/inline-tag-picker.jsx new file mode 100644 index 00000000..fcc2b1af --- /dev/null +++ b/twake/frontend/src/app/components/inline-tag-picker/inline-tag-picker.jsx @@ -0,0 +1,28 @@ +import React, { Component } from 'react'; +import './inline-tag-picker.scss'; + +export default class InlineTagPicker extends Component { + render() { + return this.props.available.map(item => { + return ( +
{ + let array = (this.props.value || []).map(a => a); + if (this.props.value.includes(item)) { + array = this.props.value.filter(val => item !== val); + } else { + array.push(item); + } + this.props.onChange(array); + }} + > + {item} +
+ ); + }); + } +} diff --git a/twake/frontend/src/app/components/inline-tag-picker/inline-tag-picker.scss b/twake/frontend/src/app/components/inline-tag-picker/inline-tag-picker.scss new file mode 100644 index 00000000..fd14ea1c --- /dev/null +++ b/twake/frontend/src/app/components/inline-tag-picker/inline-tag-picker.scss @@ -0,0 +1,23 @@ +.inline-tag { + cursor: pointer; + background: var(--grey-light); + border-radius: var(--border-radius-base); + height: 20px; + color: var(--grey-dark); + font-size: 12px; + padding: 0 5px; + line-height: 18px; + box-sizing: border-box; + width: auto; + display: inline-block; + margin-right: 6px; + font-weight: normal; + &.selected { + background: var(--green); + color: var(--white); + } + &:hover { + transition: 0.3s; + opacity: 0.9; + } +} diff --git a/twake/frontend/src/app/components/input-with-clip-board/input-with-clip-board.jsx b/twake/frontend/src/app/components/input-with-clip-board/input-with-clip-board.jsx new file mode 100755 index 00000000..14ad9e77 --- /dev/null +++ b/twake/frontend/src/app/components/input-with-clip-board/input-with-clip-board.jsx @@ -0,0 +1,59 @@ +/* eslint-disable react/prop-types */ +import React, { Component } from 'react'; + +import Languages from 'app/features/global/services/languages-service'; +import Tooltip from 'components/tooltip/tooltip.jsx'; +import InputWithButton from 'components/inputs/input-with-button.jsx'; + +export default class InputWithClipBoard extends Component { + /* + props = { + value : "", + disabled : true|false + } + */ + constructor(props) { + super(props); + this.props = props; + + this.state = { + i18n: Languages, + }; + + Languages.addListener(this); + this.inputElement = false; + } + componentWillUnmount() { + Languages.removeListener(this); + } + selectAll() { + this.inputElement.focus(); + this.inputElement.select(); + } + copy() { + this.inputElement.disabled = false; + this.inputElement.focus(); + this.inputElement.select(); + document.execCommand('copy'); + this.inputElement.disabled = this.props.disabled; + this.tooltip.openWithTimeOut(2); + } + render() { + return ( + (this.tooltip = obj)} + overable={false} + tooltip={Languages.t('components.input.copied', [], 'CopiΓ©')} + > + (this.inputElement = obj)} + btnAction={() => this.copy()} + icon="copy" + hideBtn={this.props.hideBtn} + value={this.props.value} + disabled={this.props.disabled} + /> + + ); + } +} diff --git a/twake/frontend/src/app/components/inputs/deprecated_checkbox.jsx b/twake/frontend/src/app/components/inputs/deprecated_checkbox.jsx new file mode 100755 index 00000000..351d7602 --- /dev/null +++ b/twake/frontend/src/app/components/inputs/deprecated_checkbox.jsx @@ -0,0 +1,95 @@ +/* eslint-disable react/prop-types */ +import React, { Component } from 'react'; + +import './inputs.scss'; +import CheckIcon from '@material-ui/icons/CheckOutlined'; + +export default class Checkbox extends Component { + constructor() { + super(); + } + renderSwitch() { + var className = this.props.className || ''; + + if (this.props.big) { + className += ' big '; + } + if (this.props.medium) { + className += ' medium '; + } + if (this.props.small) { + className += ' small '; + } + + if ( + className.indexOf('medium') === className.indexOf('small') && + className.indexOf('big') === className.indexOf('small') && + className.indexOf('big') < 0 + ) { + className += ' medium'; + } + + return ( +
{ + if (!this.props.label && !this.props.disabled) { + this.props.onChange(!this.props.value); + } + }} + > +
+ +
+
+ ); + } + render() { + var parentClassName = ''; + + if (this.props.big) { + parentClassName += ' big '; + } + if (this.props.medium) { + parentClassName += ' medium '; + } + if (this.props.small) { + parentClassName += ' small '; + } + + if ( + parentClassName.indexOf('medium') === parentClassName.indexOf('small') && + parentClassName.indexOf('big') === parentClassName.indexOf('small') && + parentClassName.indexOf('big') < 0 + ) { + parentClassName += ' medium'; + } + + if (this.props.label) { + return ( +
{ + if (!this.props.disabled) { + this.props.onChange(!this.props.value); + } + }} + > + {this.renderSwitch()} +
{this.props.label}
+
+ ); + } else { + return this.renderSwitch(); + } + } +} diff --git a/twake/frontend/src/app/components/inputs/input-enter.jsx b/twake/frontend/src/app/components/inputs/input-enter.jsx new file mode 100755 index 00000000..903ef1c9 --- /dev/null +++ b/twake/frontend/src/app/components/inputs/input-enter.jsx @@ -0,0 +1,46 @@ +/* eslint-disable react/prop-types */ +import React, { Component } from 'react'; + +import Input from './input.jsx'; +import Icon from 'app/components/icon/icon.jsx'; +import './inputs.scss'; + +export default class InputEnter extends Component { + constructor() { + super(); + } + render() { + var parentClassName = ''; + + if (this.props.big) { + parentClassName += ' big '; + } + if (this.props.medium) { + parentClassName += ' medium '; + } + if (this.props.small) { + parentClassName += ' small '; + } + + if ( + parentClassName.indexOf('medium') === parentClassName.indexOf('small') && + parentClassName.indexOf('big') === parentClassName.indexOf('small') && + parentClassName.indexOf('big') < 0 + ) { + parentClassName += ' medium'; + } + + return ( +
+ + +
+ ); + } +} diff --git a/twake/frontend/src/app/components/inputs/input-icon.jsx b/twake/frontend/src/app/components/inputs/input-icon.jsx new file mode 100755 index 00000000..10b29e5b --- /dev/null +++ b/twake/frontend/src/app/components/inputs/input-icon.jsx @@ -0,0 +1,47 @@ +/* eslint-disable react/prop-types */ +import React, { Component } from 'react'; + +import Input from './input.jsx'; +import Icon from 'app/components/icon/icon.jsx'; +import './inputs.scss'; + +export default class InputIcon extends Component { + constructor() { + super(); + } + render() { + var parentClassName = ''; + + if (this.props.big) { + parentClassName += ' big '; + } + if (this.props.medium) { + parentClassName += ' medium '; + } + if (this.props.small) { + parentClassName += ' small '; + } + + if ( + parentClassName.indexOf('medium') === parentClassName.indexOf('small') && + parentClassName.indexOf('big') === parentClassName.indexOf('small') && + parentClassName.indexOf('big') < 0 + ) { + parentClassName += ' medium'; + } + + return ( +
+ + +
+ ); + } +} diff --git a/twake/frontend/src/app/components/inputs/input-with-button.jsx b/twake/frontend/src/app/components/inputs/input-with-button.jsx new file mode 100644 index 00000000..45159598 --- /dev/null +++ b/twake/frontend/src/app/components/inputs/input-with-button.jsx @@ -0,0 +1,54 @@ +/* eslint-disable react/prop-types */ +import React, { Component } from 'react'; + +import Languages from 'app/features/global/services/languages-service'; +import './input-with-button.scss'; +import Icon from 'app/components/icon/icon.jsx'; +import Input from './input.jsx'; + +export default class InputWithButton extends Component { + /* + props = { + value : "", + disabled : true|false + } + */ + constructor(props) { + super(props); + this.props = props; + + this.state = { + i18n: Languages, + }; + + Languages.addListener(this); + this.inputElement = false; + } + + componentWillUnmount() { + Languages.removeListener(this); + } + + render() { + return ( +
+ { + this.inputElement = obj; + this.props.refInput && this.props.refInput(); + }} + {...this.props} + /> + {!this.props.hideBtn && ( +
this.props.btnAction()} + > + +
+ )} +
+ ); + } +} diff --git a/twake/frontend/src/app/components/inputs/input-with-button.scss b/twake/frontend/src/app/components/inputs/input-with-button.scss new file mode 100755 index 00000000..ab22c850 --- /dev/null +++ b/twake/frontend/src/app/components/inputs/input-with-button.scss @@ -0,0 +1,29 @@ +.inputWithButton { + display: flex; + position: relative; + input.input { + padding-right: 50px; + } + .button-icon { + position: absolute; + height: 40px; + right: 0px; + box-sizing: border-box; + padding: 10px; + border-radius: 0px 4px 4px 0px; + border-left: solid 1px var(--grey-light); + font-size: 16px; + cursor: pointer; + } + + .danger { + background-color: var(--grey-background); + color: var(--grey-dark); + } + + .danger:hover { + transition: 0.5s; + background-color: var(--grey-light); + color: var(--red); + } +} diff --git a/twake/frontend/src/app/components/inputs/input-with-color.jsx b/twake/frontend/src/app/components/inputs/input-with-color.jsx new file mode 100755 index 00000000..61c6829f --- /dev/null +++ b/twake/frontend/src/app/components/inputs/input-with-color.jsx @@ -0,0 +1,129 @@ +/* eslint-disable react/prop-types */ +import React, { Component } from 'react'; + +import MenusManager from 'app/components/menus/menus-manager.jsx'; +import ColorPicker from 'components/color-picker/color-picker.jsx'; +import Input from 'components/inputs/input.jsx'; +import './inputs.scss'; + +export default class InputWithColor extends Component { + constructor() { + super(); + } + outsideMenuListener() { + this.closeColorPicker(); + } + componentWillUnmount() { + document.removeEventListener('click', this.outsideClickListener); + } + componentDidMount() { + if (this.props.focusOnDidMount && this.input) { + this.input.focus(); + } + this.outsideClickListener = event => { + if ( + this.colorPickerIsOpen && + this.colorpicker_dom && + !this.colorpicker_dom.contains(event.target) && + document.contains(event.target) + ) { + this.outsideMenuListener(); + } + }; + this.outsideClickListener = this.outsideClickListener.bind(this); + document.addEventListener('click', this.outsideClickListener); + } + closeColorPicker() { + if (!this.colorPickerIsOpen) { + return; + } + + if (this.props.menu_level !== undefined) { + MenusManager.closeSubMenu(this.props.menu_level); + } else { + MenusManager.closeMenu(); + } + + this.colorPickerIsOpen = false; + } + openColorPicker() { + if (this.colorPickerIsOpen) { + return; + } + + var menu = [ + { + type: 'react-element', + reactElement: () => { + return ( + (this.colorpicker_dom = node)} + value={this.props.value[0]} + onChange={color => this.selectColor(color)} + /> + ); + }, + }, + ]; + var elementRect = window.getBoundingClientRect(this.color_dom); + elementRect.x = elementRect.x || elementRect.left; + elementRect.y = elementRect.y || elementRect.top; + if (this.props.menu_level !== undefined) { + MenusManager.openSubMenu(menu, elementRect, this.props.menu_level, 'bottom'); + } else { + MenusManager.openMenu(menu, elementRect, 'bottom'); + } + + setTimeout(() => { + this.colorPickerIsOpen = true; + }, 200); + } + selectColor(color) { + this.closeColorPicker(); + var value = [color, this.props.value[1]]; + this.onChange(value); + } + onChange(value) { + if (this.props.onChange) { + this.props.onChange(value); + } + } + render() { + if (!this.props.value[0]) { + this.onChange([ + ColorPicker.colors[parseInt(Math.random() * ColorPicker.colors.length)], + this.props.value[1], + ]); + } + return ( +
+
(this.color_dom = node)} + onClick={() => { + this.openColorPicker(); + }} + > +
+
+
+ (this.input = obj)} + type="text" + placeholder={this.props.placeholder} + value={this.props.value[1]} + onKeyDown={e => { + if (e.keyCode == 13 && this.props.onEnter) { + this.props.onEnter(); + } + }} + onChange={evt => { + if (this.onChange) this.onChange([this.props.value[0], evt.target.value]); + }} + /> +
+
+ ); + } +} diff --git a/twake/frontend/src/app/components/inputs/input-with-icon.tsx b/twake/frontend/src/app/components/inputs/input-with-icon.tsx new file mode 100755 index 00000000..17de3a9d --- /dev/null +++ b/twake/frontend/src/app/components/inputs/input-with-icon.tsx @@ -0,0 +1,203 @@ +/* eslint-disable react/prop-types */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React from 'react'; +import { Input, Col, Row } from 'antd'; + +import Emojione from 'components/emojione/emojione'; +import MenusManager from 'app/components/menus/menus-manager.jsx'; +import EmojiPicker from 'components/emoji-picker/emoji-picker.jsx'; + +import './inputs.scss'; + +type PropsType = { [key: string]: any }; +type StateType = { [key: string]: any }; + +export default class InputWithIcon extends React.Component { + outsideClickListener: (event: any) => void = () => undefined; + input: any; + emojiPickerIsOpen: any; + emojipicker_dom: any; + allChanEmojies = [ + ':8ball:', + ':dart:', + ':joystick:', + ':video_game:', + ':bar_chart:', + ':crystal_ball:', + ':speech_balloon:', + ':bulb:', + ':deciduous_tree:', + ':palm_tree:', + ':earth_americas:', + ':open_file_folder:', + ':penguin:', + ':seedling:', + ':sailboat:', + ':fire_engine:', + ':scroll:', + ':newspaper:', + ':factory:', + ':package:', + ':mailbox:', + ':moneybag:', + ':smiley_cat:', + ':sunglasses:', + ]; + emoji_dom: any; + + UNSAFE_componentWillMount() { + this.randomizeEmojies(); + } + + randomizeEmojies() { + this.allChanEmojies.sort((a, b) => { + if (b === this.props.value[0]) { + return -1; + } + if (a === this.props.value[0]) { + return 1; + } + return Math.floor(Math.random() * 3) - 1; + }); + } + + outsideMenuListener() { + this.closeEmojiPicker(); + } + + componentWillUnmount() { + document.removeEventListener('click', this.outsideClickListener); + } + + componentDidMount() { + if (this.props.focusOnDidMount && this.input) { + this.input.focus(); + } + + this.outsideClickListener = event => { + if ( + this.emojiPickerIsOpen && + this.emojipicker_dom && + !this.emojipicker_dom.contains(event.target) && + document.contains(event.target) + ) { + this.outsideMenuListener(); + } + }; + + this.outsideClickListener = this.outsideClickListener.bind(this); + document.addEventListener('click', this.outsideClickListener); + } + + closeEmojiPicker() { + if (!this.emojiPickerIsOpen) { + return; + } + + if (this.props.menu_level !== undefined) { + MenusManager.closeSubMenu(this.props.menu_level); + } else { + MenusManager.closeMenu(); + } + + this.emojiPickerIsOpen = false; + } + + openEmojiPicker() { + if (this.emojiPickerIsOpen) { + return; + } + + let preferedEmojis = [this.props.value[0]]; + if (this.props.preferedEmoji) { + preferedEmojis = this.props.preferedEmoji; + } else { + this.randomizeEmojies(); + for (let i = 0; i < 5; i++) { + preferedEmojis[i + 1] = this.allChanEmojies[i]; + } + } + + const menu = [ + { + type: 'react-element', + className: 'menu-cancel-margin', + reactElement: () => { + return ( + (this.emojipicker_dom = node)} + onChange={(emoji: any) => this.selectEmoji(emoji)} + /> + ); + }, + }, + ]; + const elementRect = (window as any).getBoundingClientRect(this.emoji_dom); + elementRect.x = elementRect.x || elementRect.left; + elementRect.y = elementRect.y || elementRect.top; + if (this.props.menu_level !== undefined) { + MenusManager.openSubMenu(menu, elementRect, this.props.menu_level, 'bottom'); + } else { + MenusManager.openMenu(menu, elementRect, 'bottom', {}); + } + + setTimeout(() => { + this.emojiPickerIsOpen = true; + }, 200); + } + selectEmoji(emoji: any) { + this.closeEmojiPicker(); + const value = [emoji.native, this.props.value[1]]; + this.onChange(value); + } + onChange(value: any) { + if (this.props.onChange) { + this.props.onChange(value); + } + } + render() { + let icon = this.props.value[0]; + if (!this.props.value[0]) { + this.onChange([this.allChanEmojies[0], this.props.value[1]]); + icon = this.allChanEmojies[0]; + } + return ( + + + +
(this.emoji_dom = node)} + onClick={() => { + this.openEmojiPicker(); + }} + > + +
+ + + {(!this.props.children && ( + { + this.input = obj; + if (this.props.inputRef) this.props.inputRef(obj); + }} + type="text" + placeholder={this.props.placeholder} + value={this.props.value[1]} + onPressEnter={this.props.onEnter} + onChange={evt => { + if (this.onChange) this.onChange([this.props.value[0], evt.target.value]); + }} + /> + )) || + this.props.children} + +
+
+ ); + } +} diff --git a/twake/frontend/src/app/components/inputs/input-with-select.scss b/twake/frontend/src/app/components/inputs/input-with-select.scss new file mode 100644 index 00000000..d16d0954 --- /dev/null +++ b/twake/frontend/src/app/components/inputs/input-with-select.scss @@ -0,0 +1,47 @@ +.group-container { + .ant-btn-icon-only { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + background-color: var(--grey-background); + border-radius: var(--border-radius-base) 0px 0px var(--border-radius-base); + padding: 0; + + &:hover { + background-color: var(--grey-background); + } + } + + .ant-select { + max-width: 120px; + + .ant-select-selector { + border-radius: 0 !important; + } + + .ant-select-selector, + .border-radius-left { + border-radius: var(--border-radius-base) 0 0 var(--border-radius-base) !important; + } + } + + .group-divider { + height: 100%; + margin: 0; + top: 0; + background-color: var(--black-alpha-70); + opacity: 0.28; + } + + .ant-btn .small-margin-left { + color: var(--grey-dark); + &:hover { + color: var(--primary); + } + } + + .ant-input { + border-radius: 0 var(--border-radius-base) var(--border-radius-base) 0; + } +} diff --git a/twake/frontend/src/app/components/inputs/input-with-select.tsx b/twake/frontend/src/app/components/inputs/input-with-select.tsx new file mode 100644 index 00000000..6ff6e7c9 --- /dev/null +++ b/twake/frontend/src/app/components/inputs/input-with-select.tsx @@ -0,0 +1,105 @@ +import React, { useEffect, useState } from 'react'; +import { Input, Col, Row, Select, Typography, Button, Divider, Tooltip } from 'antd'; +import { ChannelType } from 'app/features/channels/types/channel'; +import { List, X } from 'react-feather'; +import Languages from 'app/features/global/services/languages-service'; +import './input-with-select.scss'; + +type PropsType = { + channel: ChannelType | undefined; + onChange: (array: string[]) => void; + groups: string[]; +}; + +const { Group } = Input; +const { Option } = Select; +const InputWithSelect = ({ groups, channel, onChange }: PropsType): JSX.Element => { + const [group, setGroup] = useState(channel?.channel_group || ''); + const [channelName, setChannelName] = useState(channel?.name || ''); + const [searchedGroup, setSearchedGroup] = useState(''); + const [displaySelector, setDisplaySelector] = useState( + channel?.channel_group ? true : false, + ); + + useEffect(() => { + onChange([group || '', channelName]); + }); + + return ( + + + {!displaySelector && ( + + + + + + + ) : ( + + )} + + + ); +}; diff --git a/twake/frontend/src/app/components/invitation/parts/allow-anyone-by-email.tsx b/twake/frontend/src/app/components/invitation/parts/allow-anyone-by-email.tsx new file mode 100644 index 00000000..4b4cabcb --- /dev/null +++ b/twake/frontend/src/app/components/invitation/parts/allow-anyone-by-email.tsx @@ -0,0 +1,62 @@ +import { Info, Subtitle } from 'app/atoms/text'; +import Switch from 'app/components/inputs/switch'; +import Languages from 'app/features/global/services/languages-service'; +import { ToasterService } from 'app/features/global/services/toaster-service'; +import { useInvitationUsers } from 'app/features/invitation/hooks/use-invitation-users'; +import { useCurrentUser } from 'app/features/users/hooks/use-current-user'; +import workspaceApiClient from 'app/features/workspaces/api/workspace-api-client'; +import { useCurrentWorkspace } from 'app/features/workspaces/hooks/use-workspaces'; +import React, { useState } from 'react'; + +export default (): React.ReactElement => { + const { user } = useCurrentUser(); + const { members_limit_reached } = useInvitationUsers(); + const { workspace } = useCurrentWorkspace(); + const [allow, setAllow] = useState(!!workspace?.preferences?.invite_domain); + + const currentUserDomain = user?.email.split('@').pop(); + + const handleChange = async (value: boolean): Promise => { + if (value) { + try { + await workspaceApiClient.setInvitationDomain( + workspace?.company_id as string, + workspace?.id as string, + currentUserDomain as string, + ); + setAllow(true); + ToasterService.success('Invitation domain updated'); + } catch (error) { + ToasterService.error('Failed to set invitation domain'); + } + } + }; + + return !members_limit_reached ? ( + <> + Automatically invite my business + + If this is enabled, anyone creating a Twake account with your business email will + automatically be added to this company and this workspace. + +
+
+ {Languages.t( + 'components.invitation.allow_anyone_by_email.text', + [workspace?.preferences?.invite_domain || currentUserDomain], + `Let anyone with @${ + workspace?.preferences?.invite_domain || currentUserDomain + } email join this workspace`, + )} +
+ +
+ + ) : ( + <> + ); +}; diff --git a/twake/frontend/src/app/components/invitation/parts/bulk-invitation.tsx b/twake/frontend/src/app/components/invitation/parts/bulk-invitation.tsx new file mode 100644 index 00000000..b0a8d307 --- /dev/null +++ b/twake/frontend/src/app/components/invitation/parts/bulk-invitation.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import InvitationInputBulk from './invitation-input-bulk'; + +export default (): React.ReactElement => { + return ( +
+ +
+ ); +}; diff --git a/twake/frontend/src/app/components/invitation/parts/custom-role-invitation.tsx b/twake/frontend/src/app/components/invitation/parts/custom-role-invitation.tsx new file mode 100644 index 00000000..979bdf01 --- /dev/null +++ b/twake/frontend/src/app/components/invitation/parts/custom-role-invitation.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import InvitationInputList from './invitation-input-list'; + +export default (): React.ReactElement => { + return ( +
+ +
+ ); +}; diff --git a/twake/frontend/src/app/components/invitation/parts/invitation-channels.tsx b/twake/frontend/src/app/components/invitation/parts/invitation-channels.tsx new file mode 100644 index 00000000..0360bb5d --- /dev/null +++ b/twake/frontend/src/app/components/invitation/parts/invitation-channels.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { Button } from 'app/atoms/button/button'; +import { Modal, ModalContent } from 'app/atoms/modal'; +import { ChannelSelector } from 'app/components/channels-selector'; +import { ChannelType } from 'app/features/channels/types/channel'; +import { useInvitationChannels } from 'app/features/invitation/hooks/use-invitation-channels'; +import { uniqBy } from 'lodash'; +import Languages from 'app/features/global/services/languages-service'; + +export default (): React.ReactElement => { + const { selectedChannels, closeSelection, setChannels, open } = useInvitationChannels(); + + const handleSelectionChange = (channels: ChannelType[]) => { + setChannels(uniqBy(channels, 'id')); + }; + + return ( + closeSelection()} className="sm:w-[20vw] sm:max-w-xl"> + + + + + + + ); +}; diff --git a/twake/frontend/src/app/components/invitation/parts/invitation-input-bulk.tsx b/twake/frontend/src/app/components/invitation/parts/invitation-input-bulk.tsx new file mode 100644 index 00000000..fe3b04b7 --- /dev/null +++ b/twake/frontend/src/app/components/invitation/parts/invitation-input-bulk.tsx @@ -0,0 +1,85 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React from 'react'; +import { + invitationEmailsState, + invitationTypeState, + InvitedUser, +} from 'app/features/invitation/state/invitation'; +import { useRecoilState } from 'recoil'; +import ChipInput from 'material-ui-chip-input'; +import { RemoveIcon } from 'app/atoms/icons-colored'; +import PerfectScrollbar from 'react-perfect-scrollbar'; +import { useCurrentUser } from 'app/features/users/hooks/use-current-user'; +import { useInvitationUsers } from 'app/features/invitation/hooks/use-invitation-users'; +import ReachedLimit from './reached-limit'; + +const emailRegex = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/; + +export default (): React.ReactElement => { + const [invitations, setInvitations] = useRecoilState(invitationEmailsState); + const [role] = useRecoilState(invitationTypeState); + const { user } = useCurrentUser(); + const { can_add_invitations, members_limit_reached } = useInvitationUsers(); + + const emails = (invitations || []).map(invitation => invitation.email); + const currentUserEmailDomain = user?.email.split('@').pop(); + + const handleChange = (chips: string[]) => { + const newInvitations: InvitedUser[] = chips + .filter(chip => !invitations.find(invitation => invitation.email === chip)) + .map(chip => ({ email: chip, role })); + const updatedInvitations = [...invitations, ...newInvitations]; + + setInvitations(updatedInvitations); + }; + + const validate = (chip: string): boolean => { + return emailRegex.test(chip) && currentUserEmailDomain === chip.split('@').pop(); + }; + + const handleDelete = (chip: string) => { + const updatedInvitations = invitations.filter(({ email }) => email !== chip); + + setInvitations(updatedInvitations); + }; + + const rederChip = ( + { chip, handleDelete }: { chip: string; handleDelete: React.EventHandler }, + key: string, + ): React.ReactElement => { + return ( +
+ +
{chip}
+
+ ); + }; + + return ( + + { members_limit_reached && } + + + ); +}; diff --git a/twake/frontend/src/app/components/invitation/parts/invitation-input-list.tsx b/twake/frontend/src/app/components/invitation/parts/invitation-input-list.tsx new file mode 100644 index 00000000..a495b5a4 --- /dev/null +++ b/twake/frontend/src/app/components/invitation/parts/invitation-input-list.tsx @@ -0,0 +1,150 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { Button } from 'app/atoms/button/button'; +import { RemoveIcon } from 'app/atoms/icons-colored'; +import { Input } from 'app/atoms/input/input-text'; +import { + invitationEmailsState, + InvitationType, + invitationTypeState, +} from 'app/features/invitation/state/invitation'; +import React, { useState } from 'react'; +import { useRecoilState } from 'recoil'; +import PerfectScrollbar from 'react-perfect-scrollbar'; +import { useCurrentUser } from 'app/features/users/hooks/use-current-user'; +import { useInvitationUsers } from 'app/features/invitation/hooks/use-invitation-users'; +import ReachedLimit from './reached-limit'; +import Languages from 'app/features/global/services/languages-service'; +import { PlusIcon } from '@heroicons/react/outline'; +import Select from 'app/atoms/input/input-select'; + +export default (): React.ReactElement => { + const [invitations, setInvitations] = useRecoilState(invitationEmailsState); + const [currentInput, setCurrentInput] = useState(''); + const [notValidEmail, setNotValidEmail] = useState(false); + const [invitationTargetType] = useRecoilState(invitationTypeState); + const { user } = useCurrentUser(); + const emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/; + const currentUserEmailDomain = user?.email.split('@').pop(); + const { can_add_invitations, members_limit_reached, allowed_members, allowed_guests } = + useInvitationUsers(); + + const emailExists = (target: string): boolean => + !!invitations.find(invitation => invitation.email === target); + + const handleEnter = (event: unknown): void => { + if ((event as KeyboardEvent).key === 'Enter') { + handleAdd(); + } + }; + + const handleAdd = (): void => { + const role = invitationTargetType; + if (emailRegex.test(currentInput) && !emailExists(currentInput)) { + setInvitations([...invitations, { email: currentInput, role }]); + setCurrentInput(''); + setNotValidEmail(false); + } else { + setNotValidEmail(true); + } + }; + + const removeEmail = (targetEmail: string): void => { + setInvitations(invitations.filter(invitation => invitation.email !== targetEmail)); + }; + + const handleInput = (event: any): void => { + setCurrentInput(event.target.value); + setNotValidEmail(!emailRegex.test(event.target.value) || emailExists(event.target.value)); + }; + + const handleRoleChange = (email: string, role: InvitationType): void => { + if (role === InvitationType.guest && allowed_guests <= 0) return; + if (role === InvitationType.member && allowed_members <= 0) return; + + const changedInvitations = invitations.map(invitation => { + if (invitation.email === email) { + return { + email, + role, + }; + } + + return invitation; + }); + + setInvitations(changedInvitations); + }; + + return ( +
+ {can_add_invitations ? ( +
+ + +
+ ) : members_limit_reached ? ( + + ) : ( + <> + )} + + {invitations.map(invitation => ( +
+ removeEmail(invitation.email)} + /> + + +
+ ))} +
+
+ ); +}; diff --git a/twake/frontend/src/app/components/invitation/parts/invitation-sent.tsx b/twake/frontend/src/app/components/invitation/parts/invitation-sent.tsx new file mode 100644 index 00000000..d1313351 --- /dev/null +++ b/twake/frontend/src/app/components/invitation/parts/invitation-sent.tsx @@ -0,0 +1,53 @@ +import { SentIcon } from 'app/atoms/icons-colored'; +import { Title, Base } from 'app/atoms/text'; +import Link from 'app/atoms/link'; +import React from 'react'; +import { Button } from 'app/atoms/button/button'; +import { useInvitation } from 'app/features/invitation/hooks/use-invitation'; +import Languages from 'app/features/global/services/languages-service'; + +export default (): React.ReactElement => { + const { reset } = useInvitation(); + + return ( +
+
+ +
+
+ + {Languages.t( + 'components.invitation.invitation_sent.title', + [], + 'Invitations have successfully been sent', + )} + +
+
+ + {Languages.t( + 'components.invitation.invitation_sent.subtitle_status', + [], + 'You can track invitaion status in:', + )} + + {Languages.t( + 'components.invitation.invitation_sent.subtitle_location', + [], + 'Workspace settings > Member management', + )} + +
+
+ + {Languages.t('components.invitation.invitation_sent.link', [], 'Check invitation status')} + +
+
+ +
+
+ ); +}; diff --git a/twake/frontend/src/app/components/invitation/parts/invitation-target.tsx b/twake/frontend/src/app/components/invitation/parts/invitation-target.tsx new file mode 100644 index 00000000..8cdad06f --- /dev/null +++ b/twake/frontend/src/app/components/invitation/parts/invitation-target.tsx @@ -0,0 +1,53 @@ +import { BaseSmall } from 'app/atoms/text'; +import Switch from 'app/components/inputs/switch'; +import Languages from 'app/features/global/services/languages-service'; +import { useInvitationChannels } from 'app/features/invitation/hooks/use-invitation-channels'; +import { useInvitationUsers } from 'app/features/invitation/hooks/use-invitation-users'; +import { + invitationEmailsState, + InvitationType, + invitationTypeState, +} from 'app/features/invitation/state/invitation'; +import React from 'react'; +import { useRecoilState } from 'recoil'; + +export default (): React.ReactElement => { + const [invitationType, setInvitationType] = useRecoilState(invitationTypeState); + const { openSelection, selectedChannels } = useInvitationChannels(); + const [invitations, setInvitations] = useRecoilState(invitationEmailsState); + const { allowed_guests, allowed_members } = useInvitationUsers(); + + const changeInvitationType = (type: InvitationType) => { + setInvitationType(type); + + if (type === InvitationType.guest && allowed_guests <= 0) return; + if (type === InvitationType.member && allowed_members <= 0) return; + setInvitations(invitations.map(({ email }) => ({ email, role: type }))); + }; + + return ( +
+
+ + {Languages.t('components.invitation.invitation_target.invite_as_guests')} + + changeInvitationType(e ? InvitationType.guest : InvitationType.member)} + /> +
+
+
openSelection()} + > + {Languages.t('components.invitation.invitation_target.channels_button')} +
+ {selectedChannels.length} +
+
+
+
+ ); +}; diff --git a/twake/frontend/src/app/components/invitation/parts/reached-limit.tsx b/twake/frontend/src/app/components/invitation/parts/reached-limit.tsx new file mode 100644 index 00000000..3e9a63b1 --- /dev/null +++ b/twake/frontend/src/app/components/invitation/parts/reached-limit.tsx @@ -0,0 +1,15 @@ +import Text from 'app/atoms/text'; +import Languages from 'app/features/global/services/languages-service'; +import React from 'react'; + +export default (): React.ReactElement => { + return ( + + {Languages.t( + 'components.invitation.reached_limit.text', + [], + 'you reached the maximum number of users inside your company. Increase your subscription or add these users as guests.', + )} + + ); +}; diff --git a/twake/frontend/src/app/components/invitation/parts/workspace-link.tsx b/twake/frontend/src/app/components/invitation/parts/workspace-link.tsx new file mode 100644 index 00000000..6ced3624 --- /dev/null +++ b/twake/frontend/src/app/components/invitation/parts/workspace-link.tsx @@ -0,0 +1,59 @@ +import { Button } from 'app/atoms/button/button'; +import React, { useState } from 'react'; +import { CopyIcon } from '@atoms/icons-agnostic'; +import { Base } from 'app/atoms/text'; +import { useInvitation } from 'app/features/invitation/hooks/use-invitation'; +import Languages from 'app/features/global/services/languages-service'; +import MagicLinks from 'app/views/client/popup/AddUser/MagicLinks'; +import { Input } from 'app/atoms/input/input-text'; +import { InputDecorationIcon } from 'app/atoms/input/input-decoration-icon'; +import { LinkIcon } from '@heroicons/react/outline'; +import { copyToClipboard } from 'app/features/global/utils/CopyClipboard'; +import { ToasterService } from 'app/features/global/services/toaster-service'; + +export default (): React.ReactElement => { + const { generateInvitationLink } = useInvitation(); + const [loading, setLoading] = useState(false); + + const copyLink = async () => { + setLoading(true); + const link = await generateInvitationLink(); + + if (link) { + copyToClipboard(link); + ToasterService.success('Link copied to clipboard'); + } + setLoading(false); + }; + + return ( +
+ ( + + )} + prefix={LinkIcon} + /> + +
+ ); +}; diff --git a/twake/frontend/src/app/components/loader/application-loader.tsx b/twake/frontend/src/app/components/loader/application-loader.tsx new file mode 100644 index 00000000..c5331542 --- /dev/null +++ b/twake/frontend/src/app/components/loader/application-loader.tsx @@ -0,0 +1,32 @@ +// eslint-disable-next-line @typescript-eslint/no-use-before-define +import React from 'react'; +import Languages from 'app/features/global/services/languages-service'; + +type PropsType = { + message?: string; +}; + +export default (props: PropsType) => ( +
+
+ {props.message || + Languages.t( + 'application.load.longer', + [], + 'Server takes longer than expected to reply, please wait or reload the page...', + )} +
+
+); diff --git a/twake/frontend/src/app/components/loader/loader.jsx b/twake/frontend/src/app/components/loader/loader.jsx new file mode 100755 index 00000000..5441b327 --- /dev/null +++ b/twake/frontend/src/app/components/loader/loader.jsx @@ -0,0 +1,26 @@ +import React, { Component } from 'react'; + +export default class Loader extends React.Component { + render() { + return ( +
+ + + + + +
+ ); + } +} diff --git a/twake/frontend/src/app/components/locked-features-components/feature-toggles-hooks.tsx b/twake/frontend/src/app/components/locked-features-components/feature-toggles-hooks.tsx new file mode 100644 index 00000000..1dc531b5 --- /dev/null +++ b/twake/frontend/src/app/components/locked-features-components/feature-toggles-hooks.tsx @@ -0,0 +1,25 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { useEffect } from 'react'; +import FeatureTogglesService, { + FeatureNames, +} from 'app/features/global/services/feature-toggles-service'; +import { FeatureToggles, Feature, withFeatures } from '@paralleldrive/react-feature-toggles'; +import { useCurrentCompany } from 'app/features/companies/hooks/use-companies'; + +export const useFeatureToggles = () => { + const { activeFeatureNames } = FeatureTogglesService; + const { company } = useCurrentCompany(); + + useEffect(() => { + const companyPlan = company?.plan; + companyPlan && FeatureTogglesService.setFeaturesFromCompanyPlan(companyPlan as any); + }, [JSON.stringify(company)]); + + return { + activeFeatureNames, + FeatureToggles, + Feature, + withFeatures, + FeatureNames, + }; +}; diff --git a/twake/frontend/src/app/components/locked-features-components/locked-drive-popup/locked-drive-popup.tsx b/twake/frontend/src/app/components/locked-features-components/locked-drive-popup/locked-drive-popup.tsx new file mode 100644 index 00000000..2c318485 --- /dev/null +++ b/twake/frontend/src/app/components/locked-features-components/locked-drive-popup/locked-drive-popup.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import ObjectModal from 'app/components/object-modal/object-modal'; +import { Button, Row, Typography } from 'antd'; +import ModalManager from 'app/components/modal/modal-manager'; +import Languages from 'app/features/global/services/languages-service'; +import consoleService from 'app/features/console/services/console-service'; +import useRouterCompany from 'app/features/router/hooks/use-router-company'; + +const { Title, Text } = Typography; +export default () => { + const companyId = useRouterCompany(); + return ( + + + + {Languages.t('components.locked_features.locked_guests_popup.or')} + + +
+ } + hideFooterDivider + footerAlign="center" + footerStyle={{ marginBottom: 16 }} + > + + + </Row> + + <Row justify="center"> + <Text + style={{ + textAlign: 'center', + width: '404px', + }} + children={Languages.t('components.locked_features.locked_only_office_popup.text')} + /> + </Row> + </ObjectModal> +)}; diff --git a/twake/frontend/src/app/components/locked-features-components/locked-guests-popup/locked-guests-popup.tsx b/twake/frontend/src/app/components/locked-features-components/locked-guests-popup/locked-guests-popup.tsx new file mode 100644 index 00000000..6da2cb7d --- /dev/null +++ b/twake/frontend/src/app/components/locked-features-components/locked-guests-popup/locked-guests-popup.tsx @@ -0,0 +1,78 @@ +import { Button, Row, Typography } from 'antd'; +import ObjectModal from 'app/components/object-modal/object-modal'; +import React from 'react'; +import ModalManager from 'app/components/modal/modal-manager'; +import Languages from 'app/features/global/services/languages-service'; +import Emojione from 'app/components/emojione/emojione'; + +type PropsType = { + companySubscriptionUrl: string; +}; + +const LockedGuestsPopup = ({ companySubscriptionUrl }: PropsType): JSX.Element => { + const onClickLearnMore = () => window.open(companySubscriptionUrl, 'blank'); + const onClickSkipForNow = () => ModalManager.close(); + + return ( + <ObjectModal + titleCenter + titleLevel={2} + title={ + <div + style={{ + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + }} + > + {Languages.t('components.locked_features.locked_guests_popup.title')} + <Emojione type=":lock:" s128 /> + </div> + } + style={{ padding: 32 }} + hideFooterDivider + footerAlign="center" + footerStyle={{ marginBottom: 16 }} + footer={ + <div + style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', marginTop: 32 }} + > + <Button type="primary" size="large" onClick={onClickLearnMore}> + {Languages.t('components.locked_features.locked_guests_popup.learn_more_button')} + </Button> + <Typography.Text style={{ margin: '16px 0 ' }} strong> + {Languages.t('components.locked_features.locked_guests_popup.or')} + </Typography.Text> + <Button type="ghost" style={{ height: 36, width: 163 }} onClick={onClickSkipForNow}> + {Languages.t('components.locked_features.locked_guests_popup.skip_for_now_button')} + </Button> + </div> + } + > + <Row justify="center" style={{ margin: '12px 0 32px 0', height: '25px' }}> + <Typography.Title + level={3} + style={{ + textAlign: 'center', + margin: 0, + }} + > + {Languages.t('components.locked_features.locked_guests_popup.subtitle')} + </Typography.Title> + </Row> + + <Row justify="center"> + <Typography.Text + style={{ + textAlign: 'center', + width: '404px', + }} + > + {Languages.t('components.locked_features.locked_guests_popup.description')} + </Typography.Text> + </Row> + </ObjectModal> + ); +}; + +export default LockedGuestsPopup; diff --git a/twake/frontend/src/app/components/locked-features-components/locked-history-banner/locked-history-banner.scss b/twake/frontend/src/app/components/locked-features-components/locked-history-banner/locked-history-banner.scss new file mode 100644 index 00000000..01efc43f --- /dev/null +++ b/twake/frontend/src/app/components/locked-features-components/locked-history-banner/locked-history-banner.scss @@ -0,0 +1,21 @@ +.locked-history-banner { + .title-container { + display: flex; + align-items: center; + height: 24px; + margin: 16px 0 8px 0px; + + .title { + line-height: 16px; + margin: 0; + margin-left: 8px; + font-size: 16px; + } + } + + .description { + height: 30px; + text-align: center; + font-size: 12px; + } +} diff --git a/twake/frontend/src/app/components/locked-features-components/locked-history-banner/locked-history-banner.tsx b/twake/frontend/src/app/components/locked-features-components/locked-history-banner/locked-history-banner.tsx new file mode 100644 index 00000000..545dca6b --- /dev/null +++ b/twake/frontend/src/app/components/locked-features-components/locked-history-banner/locked-history-banner.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { Typography, Button } from 'antd'; +import Banner from 'app/components/banner/banner'; +import Emojione from 'app/components/emojione/emojione'; +import Languages from 'app/features/global/services/languages-service'; +import './locked-history-banner.scss'; +import consoleService from 'app/features/console/services/console-service'; +import useRouterCompany from 'app/features/router/hooks/use-router-company'; + +const { Title, Text } = Typography; +const LockedHistoryBanner = (): JSX.Element => { + + const companyId = useRouterCompany(); + + const onClickBtn = () => + window.open( + consoleService.getCompanySubscriptionUrl(companyId), + 'blank', + ); + + return ( + <Banner + type="ghost" + height={135} + className="locked-history-banner" + contentColumnStyle={{ + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + height: '100%', + width: '380px', + }} + > + <div className="title-container"> + <Emojione type=":rocket:" s64 /> + <Title level={5} className="title"> + {Languages.t('components.locked_features.locked_history_banner.title')} + +
+ + {Languages.t('components.locked_features.locked_history_banner.description')} + + + + ); +}; + +export default LockedHistoryBanner; diff --git a/twake/frontend/src/app/components/locked-features-components/locked-invite-alert/index.tsx b/twake/frontend/src/app/components/locked-features-components/locked-invite-alert/index.tsx new file mode 100644 index 00000000..28a36216 --- /dev/null +++ b/twake/frontend/src/app/components/locked-features-components/locked-invite-alert/index.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import { Typography, Alert } from 'antd'; +import Languages from 'app/features/global/services/languages-service'; +import { AlertTriangle } from 'react-feather'; +import { CompanyLimitsEnum, CompanyType } from 'app/features/companies/types/company'; +import consoleService from 'app/features/console/services/console-service'; + +type PropsType = { company: Partial; magicLink?: boolean }; + +const { Text, Link } = Typography; +const LockedInviteAlert = (props: PropsType): JSX.Element => { + const limit = props?.company?.plan?.limits?.[CompanyLimitsEnum.COMPANY_MEMBERS_LIMIT] || 0; + const onClickBtn = () => + window.open( + consoleService.getCompanySubscriptionUrl(props.company.id || ""), + 'blank', + ); + + return ( + + + + {Languages.t( + 'components.locked_features_components.locked_invite_alert.message_part_1', + [limit], + )} + {props.magicLink ? ( + <> + {Languages.t( + 'components.locked_features_components.locked_invite_alert.message_magic_link', + )} + + ) : ( + <> + + {Languages.t( + 'components.locked_features_components.locked_invite_alert.message_link', + )} + + {Languages.t( + 'components.locked_features_components.locked_invite_alert.message_part_2', + )} + + )} + + + } + /> + ); +}; + +export default LockedInviteAlert; diff --git a/twake/frontend/src/app/components/locked-features-components/locked-only-office-popup/locked-only-office-popup.tsx b/twake/frontend/src/app/components/locked-features-components/locked-only-office-popup/locked-only-office-popup.tsx new file mode 100644 index 00000000..c1f25d67 --- /dev/null +++ b/twake/frontend/src/app/components/locked-features-components/locked-only-office-popup/locked-only-office-popup.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import ObjectModal from 'app/components/object-modal/object-modal'; +import { Button, Row, Typography } from 'antd'; +import ModalManager from 'app/components/modal/modal-manager'; +import Languages from 'app/features/global/services/languages-service'; +import useRouterCompany from 'app/features/router/hooks/use-router-company'; +import consoleService from 'app/features/console/services/console-service'; + +const { Title, Text } = Typography; +export default () => { + const companyId = useRouterCompany(); + return ( + + + + {Languages.t('components.locked_features.locked_guests_popup.or')} + + +
+ } + hideFooterDivider + footerAlign="center" + footerStyle={{ marginBottom: 16 }} + > + + + </Row> + + <Row justify="center"> + <Text + style={{ + textAlign: 'center', + width: '404px', + }} + children={Languages.t('components.locked_features.locked_only_office_popup.text')} + /> + </Row> + </ObjectModal> +)}; diff --git a/twake/frontend/src/app/components/locked-features-components/locked-workspace-popup/locked-workspace-popup.tsx b/twake/frontend/src/app/components/locked-features-components/locked-workspace-popup/locked-workspace-popup.tsx new file mode 100644 index 00000000..e78882de --- /dev/null +++ b/twake/frontend/src/app/components/locked-features-components/locked-workspace-popup/locked-workspace-popup.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import ObjectModal from 'app/components/object-modal/object-modal'; +import { Button, Row, Typography } from 'antd'; +import ModalManager from 'app/components/modal/modal-manager'; +import Languages from 'app/features/global/services/languages-service'; +import consoleService from 'app/features/console/services/console-service'; +import useRouterCompany from 'app/features/router/hooks/use-router-company'; + +const { Title, Text } = Typography; +export default () => { + const companyId = useRouterCompany(); + return ( + <ObjectModal + titleCenter + titleLevel={2} + title={Languages.t('components.locked_features.locked_workspace_popup.title')} + titleTypographyStyle={{ textAlign: 'center', marginBottom: 32 }} + style={{ padding: 32 }} + contentStyle={{ display: 'flex', flexDirection: 'column', justifyContent: 'center' }} + footer={ + <div + style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', marginTop: 32 }} + > + <Button + type="primary" + size="large" + style={{ marginTop: 8 }} + onClick={() => + window.open( + consoleService.getCompanySubscriptionUrl(companyId), + 'blank', + ) + } + > + {Languages.t('components.locked_features.locked_guests_popup.learn_more_button')} + </Button> + <Text style={{ margin: '16px 0 ' }} strong> + {Languages.t('components.locked_features.locked_guests_popup.or')} + </Text> + <Button + type="ghost" + style={{ height: 36, width: 163 }} + onClick={() => ModalManager.closeAll()} + > + {Languages.t('components.locked_features.locked_guests_popup.skip_for_now_button')} + </Button> + </div> + } + hideFooterDivider + footerAlign="center" + footerStyle={{ marginBottom: 16 }} + > + <Row justify="center" align="middle" className="bottom-margin"> + <Title + level={3} + children={Languages.t('components.locked_features.locked_workspace_popup.subtitle')} + style={{ + textAlign: 'center', + margin: 0, + }} + /> + </Row> + + <Row justify="center"> + <Text + style={{ + textAlign: 'center', + width: '404px', + }} + children={Languages.t('components.locked_features.locked_workspace_popup.text')} + /> + </Row> + </ObjectModal> +)}; diff --git a/twake/frontend/src/app/components/main-plus/main-plus.jsx b/twake/frontend/src/app/components/main-plus/main-plus.jsx new file mode 100755 index 00000000..311ec5ee --- /dev/null +++ b/twake/frontend/src/app/components/main-plus/main-plus.jsx @@ -0,0 +1,24 @@ +import React, { Component } from 'react'; +import Icon from 'app/components/icon/icon.jsx'; +import Menu from 'components/menus/menu.jsx'; +import './main-plus.scss'; + +export default class MainPlus extends Component { + constructor(props) { + super(props); + } + render() { + if (this.props.onClick) { + return ( + <div className="main_plus_button" onClick={this.props.onClick}> + <Icon type="plus" className="m-icon-small" /> + </div> + ); + } + return ( + <Menu menu={this.props.menu} className="main_plus_button" position={'top'}> + <Icon type="plus" className="m-icon-small" /> + </Menu> + ); + } +} diff --git a/twake/frontend/src/app/components/main-plus/main-plus.scss b/twake/frontend/src/app/components/main-plus/main-plus.scss new file mode 100755 index 00000000..e69de29b diff --git a/twake/frontend/src/app/components/member/user-parts.tsx b/twake/frontend/src/app/components/member/user-parts.tsx new file mode 100644 index 00000000..1d26108d --- /dev/null +++ b/twake/frontend/src/app/components/member/user-parts.tsx @@ -0,0 +1,140 @@ +import React from 'react'; +import { Avatar, Badge, Tag } from 'antd'; +import { DashOutlined } from '@ant-design/icons'; +import { User } from 'react-feather'; +import Languages from 'app/features/global/services/languages-service'; +import RouterServices from 'app/features/router/services/router-service'; +import { UserType } from 'app/features/users/types/user'; +import UserService from 'app/features/users/services/current-user-service'; +import UsersService from 'app/features/users/services/current-user-service'; +import UserIcon from 'components/user/user'; +import { getUser } from 'app/features/users/hooks/use-user-list'; + +export type UserPartsType = { + avatar: JSX.Element; + name: string; + users: UserType[]; + companyRole: JSX.Element; +}; + +type PropsType = { + usersIds: string[]; + keepMyself?: boolean; + displayOnline?: boolean; + max?: number; + size?: number; +}; + +export const getUserParts = (props: PropsType): UserPartsType => { + const { companyId } = RouterServices.getStateFromRoute(); + const avatarSize = props.size || 20; + + let channelMembers = (props.usersIds || []).filter( + e => + props.keepMyself || + (props.usersIds.length || 0) === 1 || + e !== UsersService.getCurrentUserId(), + ); + channelMembers = channelMembers.filter((e, i) => channelMembers.indexOf(e) === i); + + let avatar: JSX.Element = ( + <Avatar size={avatarSize} icon={<User size={12} style={{ margin: 4 }} />} /> + ); + let channelName: string[] = []; + + const users: UserType[] = []; + + channelMembers?.forEach(userId => users.push(getUser(userId))); + + if (channelMembers?.length === 1) { + const avatarSrc = users[0]?.id ? ( + <UserIcon user={users[0]} withStatus={props.displayOnline} size={avatarSize} /> + ) : ( + UserService.getThumbnail(users[0]) + ); + avatar = ( + <Badge count={0} size="default" dot offset={[-4, 16]}> + <Avatar style={{ overflow: 'visible' }} size={avatarSize} src={avatarSrc} /> + </Badge> + ); + channelName = [UserService.getFullName(users[0])]; + } else if (channelMembers?.length || 0 > 1) { + avatar = ( + <Avatar.Group + maxCount={(props.max || 3) + 1} + maxStyle={{ + color: '#FFFFFF', + backgroundColor: `var(--grey-dark)`, + width: avatarSize, + height: avatarSize, + display: 'flex', + alignItems: 'center', + }} + > + {users + .filter((_, i) => i < (props.max || 3)) + .map(member => { + channelName.push(UserService.getFullName(member)); + return ( + member && ( + <Avatar key={member.id} size={avatarSize} src={UserService.getThumbnail(member)} /> + ) + ); + })} + {users.length > (props.max || 3) && ( + <Avatar + size={avatarSize} + style={{ backgroundColor: 'var(--grey-dark)' }} + icon={<DashOutlined />} + /> + )} + </Avatar.Group> + ); + } + + const roleOriginalString = UserService.getUserRole(users[0], companyId); + const companyRoleObject = getCurrentCompanyRoleObject(roleOriginalString); + const companyRole = + companyRoleObject.name !== 'unknown' ? ( + <Tag color={companyRoleObject.color}>{companyRoleObject.name}</Tag> + ) : ( + <></> + ); + + const shouldDisplayNotShowedUsersCount = users.length > (props.max || 3); + const notShowedUsersCount = users.length - (props.max || 3) + 1; /* myself */ + const name = `${channelName.join(', ')}${ + shouldDisplayNotShowedUsersCount + ? Languages.t('components.member.user_parts.and_more_user_text', [notShowedUsersCount]) + : '' + }`; + + return { + avatar, + name, + users, + companyRole, + }; +}; + +const getCurrentCompanyRoleObject = (role: string) => { + switch (role) { + case 'admin': + return { + color: 'var(--red)', + name: Languages.t('general.user.role.company.admin'), + }; + case 'member': + return { + color: 'var(--primary)', + name: Languages.t('general.user.role.company.member'), + }; + case 'guest': + return { + color: 'var(--grey-dark)', + name: Languages.t('general.user.role.company.guest'), + }; + default: + return { name: 'unknown' }; + } +}; diff --git a/twake/frontend/src/app/components/menus/menu-component.jsx b/twake/frontend/src/app/components/menus/menu-component.jsx new file mode 100755 index 00000000..f991bb66 --- /dev/null +++ b/twake/frontend/src/app/components/menus/menu-component.jsx @@ -0,0 +1,143 @@ +import React, { Component } from 'react'; + +import Icon from 'app/components/icon/icon.jsx'; +import Emojione from 'components/emojione/emojione'; +import MenusManager from 'app/components/menus/menus-manager.jsx'; +import './menu.scss'; + +/* + One menu +*/ +export default class MenuComponent extends React.Component { + constructor(props) { + super(); + this.state = { + menus_manager: MenusManager, + }; + MenusManager.addListener(this); + } + componentWillUnmount() { + MenusManager.removeListener(this); + } + openSubMenu(dom_element, menu, level) { + var elementRect = window.getBoundingClientRect(dom_element); + elementRect.x = elementRect.x || elementRect.left; + elementRect.y = elementRect.y || elementRect.top; + MenusManager.openSubMenu(menu, elementRect, level); + } + closeSubMenu(level) { + MenusManager.closeSubMenu(level); + } + hoverMenu(dom_element, item) { + if (item.submenu && !item.submenu_replace) { + this.last_hovered = item; + this.openSubMenu(dom_element, item.submenu, this.props.level || 0); + } else { + this.closeSubMenu(this.props.level || 0); + } + } + clickMenu(dom_element, item, evt) { + if(Date.now() - this.props.openAt < 200 ){ + // When a menu is open and another one opens above it, you have to block the buttons for a while. Otherwise, the hovered option of the new menu will be clicked + return; + } + if (item.submenu_replace) { + MenusManager.openMenu(item.submenu, { x: evt.clientX, y: evt.clientY }, 'center'); + return; + } + if (item.onClick) { + var res = item.onClick(evt); + if (res !== false) { + MenusManager.closeMenu(); + } + } + } + render() { + return ( + <div + ref={node => (this.original_menu = node)} + className={ + 'menu-list ' + (this.props.withFrame ? 'as_frame ' : '') + this.props.animationClass + } + > + {(this.props.menu || []) + .filter(item => item && !item.hide) + .map((item, index) => { + if (item.type == 'separator') { + return <div key={'menu_' + index} className="menu-separator" />; + } else if (item.type == 'title') { + return ( + <div key={'menu_' + index} className={'menu-title ' + item.className}> + {item.text} + </div> + ); + } else if (item.type == 'text') { + return ( + <div + key={'menu_' + index} + ref={node => (item.ref = node)} + className={'menu-text ' + item.className} + onMouseEnter={evt => { + this.hoverMenu(item.ref, item); + }} + > + {item.text} + </div> + ); + } else if (item.type == 'react-element') { + return ( + <div + key={'menu_' + index} + className={'menu-custom ' + item.className} + onClick={item.onClick} + > + {typeof item.reactElement == 'function' + ? item.reactElement(this.props.level) + : item.reactElement} + </div> + ); + } else { + return ( + <div + key={'menu_' + index} + ref={node => (item.ref = node)} + className={ + 'menu ' + + item.className + + ' ' + + (this.state.menus_manager.max_level > this.props.level && + this.last_hovered == item + ? 'hovered ' + : '') + + (item.selected ? 'selected ' : '') + } + onMouseEnter={evt => { + this.hoverMenu(item.ref, item); + }} + onClick={evt => { + this.clickMenu(item.ref, item, evt); + }} + > + {item.icon && ( + <div className="icon"> + {typeof item.icon === 'string' ? <Icon type={item.icon} /> : item.icon} + </div> + )} + {item.emoji && ( + <div className="icon"> + <Emojione type={item.emoji} /> + </div> + )} + <div className="text">{item.text}</div> + <div className="more"> + {item.rightIcon && <Icon type={item.rightIcon} />} + {item.submenu && !item.submenu_replace && <Icon type="angle-right" />} + </div> + </div> + ); + } + })} + </div> + ); + } +} diff --git a/twake/frontend/src/app/components/menus/menu.jsx b/twake/frontend/src/app/components/menus/menu.jsx new file mode 100755 index 00000000..7ec8fc63 --- /dev/null +++ b/twake/frontend/src/app/components/menus/menu.jsx @@ -0,0 +1,107 @@ +import React, { Component } from 'react'; + +import MenusManager from 'app/components/menus/menus-manager.jsx'; + +/* + One menu +*/ +export default class Menu extends React.Component { + /* + props = { + menu : menu object ex. {type:"menu", text:"Un menu", icon:"list"}, + {type:"menu", text:"Un menu avec sous menu", icon:"grid", submenu: [ + {text:"Sub menu 4", icon: "search"}, + {text:"Sub menu 5", icon: "search"}, + {text:"Sub menu 6", icon: "search"} + ]}, + {type:"menu", text:"Un menu avec sous menu", icon:"grid", submenu: [ + {type:"react-element", text:"Sub menu 6", icon: "search", reactElement:<div className="hello">salut</div>} + ]}, + {type:"separator"}, + {type:"text", text:"Du texte"} + {type:"react-element", reactElement: <Element />} + } + */ + + static closeAll() { + MenusManager.closeMenu(); + } + + constructor(props) { + super(); + this.state = { + menus_manager: MenusManager, + }; + MenusManager.addListener(this); + } + componentWillUnmount() { + if (this.props.onClose && this.open) { + this.props.onClose(); + } + MenusManager.removeListener(this); + } + openMenuFromParent(menu, rect, position) { + MenusManager.openMenu(menu, rect, position); + } + openMenu(evt) { + this.open = true; + evt.preventDefault(); + evt.stopPropagation(); + var elementRect = window.getBoundingClientRect(this.container); + elementRect.x = elementRect.x || elementRect.left; + elementRect.y = elementRect.y || elementRect.top; + this.previous_menus_id = MenusManager.openMenu( + this.props.menu, + elementRect, + this.props.position, + ); + if (this.props.onOpen) this.props.onOpen(); + } + shouldComponentUpdate(nextProps, nextState) { + if (nextProps.menu != this.props.menu && this.open) { + this.setState({}); + } + + if ( + (this.state.menus_manager.menus.length == 0 && this.previous_menus_number > 0) || + this.state.menus_manager.last_opened_id != this.previous_menus_id + ) { + if (this.open && this.props.onClose) { + this.props.onClose(); + } + this.open = false; + } + if (this.previous_menus_number != this.state.menus_manager.menus.length) { + this.previous_menus_number = this.state.menus_manager.menus.length; + } + + if (this.props.style !== nextProps.style || this.props.className !== nextProps.className) { + return true; + } + + return false; + } + render() { + return ( + <div + ref={node => (this.container = node)} + style={this.props.style} + onClick={evt => { + if (this.props.toggle) { + if (!this.open) { + this.openMenu(evt); + } else { + MenusManager.closeMenu(); + this.props.onClose && this.props.onClose(); + } + } else { + this.openMenu(evt); + } + }} + className={this.props.className} + > + {this.props.children} + </div> + ); + } +} diff --git a/twake/frontend/src/app/components/menus/menu.scss b/twake/frontend/src/app/components/menus/menu.scss new file mode 100755 index 00000000..c8670159 --- /dev/null +++ b/twake/frontend/src/app/components/menus/menu.scss @@ -0,0 +1,238 @@ +/* Dropmenu */ + +.menu-list { + width: 100%; + box-sizing: border-box; + padding: 8px 0; + + &.inline, + &.inline.as_frame { + width: 100%; + position: absolute; + top: 100%; + z-index: 1050; + + &.top { + bottom: 100%; + top: auto; + display: flex; + flex-direction: column-reverse; + + &::before { + height: calc(100% + 34px); + top: 0; + } + } + } + + &.as_frame { + border-radius: var(--border-radius-base); + box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.05), 0 0 20px 0 rgba(0, 0, 0, 0.15); + background-color: var(--white); + width: 250px; + max-height: 80vh; + overflow: auto; + } + + .menu-title { + height: 32px; + line-height: 32px; + font-size: 14px; + font-weight: bold; + color: var(--black); + margin: 0 8px; + padding: 0 8px; + } + + .menu-text { + font-size: 12px; + font-weight: 500; + margin: 8px 16px; + color: var(--grey-dark); + } + + .menu-custom { + font-size: 12px; + font-weight: 500; + margin: 8px 8px; + padding: 0 8px; + + .menu-cancel-margin, + &.menu-cancel-margin { + margin: -8px 0; + width: 100%; + padding: 0; + + & > .menu, + & > .menu-text, + & > .menu-custom, + & > .menu-title { + margin: -8px 0; + } + } + + &.menu-cancel-left-padding { + padding-left: 0; + } + + &.menu-cancel-top-margin { + margin-top: 0; + } + } + + + .menu { + height: 32px; + line-height: 32px; + font-size: 14px; + color: var(--black); + margin: 0 8px; + padding: 0 8px; + border-radius: var(--border-radius-base); + font-weight: 500; + display: flex; + overflow: hidden; + &:not(.no-background) { + cursor: pointer; + } + + &.no-background { + background: transparent !important; + &:hover { + color: var(--black); + } + } + + &.selected, + &.selected:hover, + &.is_selected, + &.is_selected:hover { + background: var(--primary); + color: var(--white); + .icon { + color: var(--white); + } + } + + &:hover { + background: var(--primary-background); + color: var(--primary); + .icon { + color: var(--primary); + } + } + + &.primary { + color: var(--primary); + .icon { + color: var(--primary); + } + } + + &.error, + &.danger { + color: var(--red); + .icon { + color: var(--red); + } + } + } + + .menu-custom, + .menu { + .icon { + display: flex; + align-items: center; + width: 30px; + font-size: 18px; + margin-left: -5px; + color: var(--grey-dark); + align-items: center; + justify-content: center; + + .emoji-container { + height: 28px; + } + + .user_head { + margin-left: 5px; + border: 0; + } + + .letter { + font-size: 10px; + width: 16px; + height: 16px; + text-align: center; + line-height: 16px; + border-radius: var(--border-radius-small); + font-weight: 500; + margin-left: 5px; + background: var(--grey-dark); + color: var(--white); + } + + .emojione { + width: 16px; + height: 16px; + margin-left: 5px; + margin-top: -2px; + } + + .emoji-image { + margin-top: 0px; + border-radius: var(--border-radius-small); + } + } + + .image { + width: 24px; + height: 24px; + border-radius: var(--border-radius-small); + background-color: var(--grey-dark); + display: inline-block; + background-size: contain; + background-position: center; + margin-right: 5px; + box-sizing: border-box; + vertical-align: middle; + line-height: 24px; + text-align: center; + color: var(--secondary); + &.has_image { + font-size: 0px; + } + } + + .text { + flex: 1; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + .more { + width: 18px; + font-size: 18px; + display: flex; + align-items: center; + height: 32px; + } + } + + .menu-separator { + border-top: 1px solid var(--grey-background); + height: 8px; + margin-top: 8px; + width: auto; + margin-left: 8px; + margin-right: 8px; + } + &.as_frame { + .menu-separator { + width: 100%; + margin-left: 0px; + margin-right: 0px; + } + } +} diff --git a/twake/frontend/src/app/components/menus/menus-body-layer.jsx b/twake/frontend/src/app/components/menus/menus-body-layer.jsx new file mode 100755 index 00000000..79455183 --- /dev/null +++ b/twake/frontend/src/app/components/menus/menus-body-layer.jsx @@ -0,0 +1,225 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import MenusManager from 'app/components/menus/menus-manager.jsx'; +import MenuComponent from './menu-component.jsx'; +import OutsideClickHandler from 'react-outside-click-handler'; + +/* + Where the menu will be displayed, this component should be in app.js (menus should be over all elements of the page) +*/ +export default class MenusBodyLayer extends React.Component { + constructor(props) { + super(); + this.state = { + menus_manager: MenusManager, + }; + this.menus_dom = null; + this.menu_observer = {}; + MenusManager.addListener(this); + this.outsideMenuListener = this.outsideMenuListener.bind(this); + this.outsideMenuListenerUp = this.outsideMenuListenerUp.bind(this); + + this.lastUpdatePosition = {}; + this.indexUpdatePosition = {}; + } + outsideMenuListener() { + //NOT WORKING + if ( + MenusManager.menus.length > 0 && + MenusManager.menus[MenusManager.menus.length - 1].allowClickOut + ) { + this.will_close_on_up = true; + } else { + this.will_close_on_up = false; + } + } + outsideMenuListenerUp() { + //NOT WORKING + if ( + MenusManager.menus.length > 0 && + MenusManager.menus[MenusManager.menus.length - 1].allowClickOut + ) { + if (this.will_close_on_up) { + MenusManager.closeMenu(); + } + } else { + this.will_close_on_up = false; + } + } + UNSAFE_componentWillMount() { + if (!document.getElementById('context-menu-layer')) { + const div = document.createElement('div'); + div.setAttribute('id', 'context-menu-layer'); + document.body.appendChild(div); + } + } + componentWillUnmount() { + MenusManager.removeListener(this); + document.removeEventListener('mousedown', this.outsideClickListener); + document.removeEventListener('mouseup', this.outsideClickListenerUp); + + Object.keys(this.menu_observer).forEach(index => { + this.menu_observer[index].disconnect(); + }); + } + componentDidMount() { + var element = this.menus_dom; + this.outsideClickListener = event => { + if (!element.contains(event.target) && document.contains(event.target)) { + this.outsideMenuListener(); + } + }; + this.outsideClickListenerUp = event => { + if (!element.contains(event.target) && document.contains(event.target)) { + this.outsideMenuListenerUp(); + } + }; + document.addEventListener('mousedown', this.outsideClickListener); + document.addEventListener('mouseup', this.outsideClickListenerUp); + } + fixMenuPosition(node, item, index) { + if (!node) { + return; + } + + if (this.lastUpdatePosition[item.id] !== parseInt(new Date().getTime() / 1000)) { + this.lastUpdatePosition[item.id] = parseInt(new Date().getTime() / 1000); + this.indexUpdatePosition[item.id] = 0; + } else if (this.indexUpdatePosition[item.id] > 2) { + return; + } + this.indexUpdatePosition[item.id]++; + + if (this.menu_observer[index]) { + this.menu_observer[index].disconnect(); + } + + var config = { childList: true, subtree: true }; + this.menu_observer[index] = new MutationObserver(() => { + this.fixMenuPosition(node, item); + }); + this.menu_observer[index].observe(node, config); + + var nr = window.getBoundingClientRect(node); + nr.x = nr.x || nr.left; + nr.y = nr.y || nr.top; + var rect = JSON.parse(JSON.stringify(nr || {})); + rect.height = Math.max(node.offsetHeight, rect.height); + rect.bottom = rect.height + rect.y; + + var max_bottom = document.documentElement.clientHeight; + if (item.positionType === 'top') { + max_bottom = item.position.y; + } + + //Top + if (rect.top < 5 || (rect.top > 10 && item.position.marginTop > 0)) { + item.position.marginTop = Math.max(0, (item.position.marginTop || 0) - rect.top + 5); + MenusManager.notify(); + } + + //Bottom + if (item.position.marginTop === undefined || item.position.marginTop < 0) { + //Else we are on the top top + if ( + rect.bottom > Math.min(document.documentElement.clientHeight, max_bottom) - 5 || + (rect.bottom < Math.min(document.documentElement.clientHeight, max_bottom) - 10 && + item.position.marginTop < 0) + ) { + item.position.marginTop = Math.min( + 0, + (item.position.marginTop || 0) - + (rect.bottom - Math.min(document.documentElement.clientHeight, max_bottom) + 5), + ); + MenusManager.notify(); + } + } + + //Left + if (rect.left < 5 || (rect.left > 10 && item.position.marginLeft > 0)) { + item.position.marginLeft = Math.max(0, (item.position.marginLeft || 0) - rect.left + 5); + MenusManager.notify(); + } + //Right + else if ( + rect.right > document.documentElement.clientWidth - 5 || + (rect.right < document.documentElement.clientWidth - 10 && item.position.marginLeft < 0) + ) { + item.position.marginLeft = Math.min( + 0, + (item.position.marginLeft || 0) - (rect.right - document.documentElement.clientWidth + 5), + ); + MenusManager.notify(); + } + } + shouldComponentUpdate(nextProps, nextState) { + if (nextState.menus_manager.willClose !== this.willClose) { + this.willClose = nextState.menus_manager.willClose; + return true; + } + if (this.state.menus_manager.menus.length > 0 || this.last_menu_length > 0) { + this.last_menu_length = this.state.menus_manager.menus.length; + return true; + } + return false; + } + render() { + return ReactDOM.createPortal( + <OutsideClickHandler + onOutsideClick={() => { + MenusManager.closeMenu(); + }} + > + <div ref={node => (this.menus_dom = node)}> + {this.state.menus_manager.menus.map((item, i) => { + var menu = ( + <OutsideClickHandler + key={item.id} + onOutsideClick={() => { + if (i === this.state.menus_manager.menus.length - 1) { + MenusManager.closeSubMenu(item.level - 1); + } + }} + > + <div + ref={node => this.fixMenuPosition(node, item, i)} + style={{ + zIndex: 1050, + position: 'absolute', + transform: item.positionType === 'bottom' ? '' : 'translateY(-50%)', + left: item.position.x, + top: item.position.y, + marginTop: item.position.marginTop, + marginLeft: item.position.marginLeft, + }} + > + <MenuComponent + withFrame + menu={item.menu} + openAt={item.openAt} + level={item.level} + animationClass={ + this.state.menus_manager.willClose || item.willClose + ? 'fade_out' + : item.level === 0 || item.positionType + ? item.positionType === 'bottom' + ? 'skew_in_bottom_nobounce' + : item.left + ? 'skew_in_left_nobounce' + : 'skew_in_right_nobounce' + : 'fade_in' + } + /> + </div> + </OutsideClickHandler> + ); + + return menu; + })} + </div> + </OutsideClickHandler>, + document.getElementById('context-menu-layer'), + ); + } +} diff --git a/twake/frontend/src/app/components/menus/menus-manager.jsx b/twake/frontend/src/app/components/menus/menus-manager.jsx new file mode 100755 index 00000000..e40fd538 --- /dev/null +++ b/twake/frontend/src/app/components/menus/menus-manager.jsx @@ -0,0 +1,184 @@ +import Observable from 'app/deprecated/CollectionsV1/observable.js'; +import Number from 'app/features/global/utils/Numbers'; +import Globals from 'app/features/global/services/globals-twake-app-service'; + +/** + * Menus manager service, choose where to generate menu + */ +class MenusManager extends Observable { + constructor() { + super(); + this.setObservableName('menus_manager'); + + window.menusService = this; + + this.menus = []; + this.lastOpen = 0; + this.willClose = false; + this.max_level = 0; + + var that = this; + Globals.window.addEventListener('keydown', function (evt) { + evt = evt || window.event; + var isEscape = false; + if ('key' in evt) { + isEscape = evt.key === 'Escape' || evt.key === 'Esc'; + } else { + isEscape = evt.keyCode === 27; + } + if (isEscape) { + that.closeMenu(); + } + }); + + this.closeMenu.bind(this); + this.openMenu.bind(this); + } + closeMenu() { + if (this.menus.length === 0) { + this.willClose = false; + return; + } + + if (new Date().getTime() - this.lastOpen < 500) { + return; + } + this.willClose = true; + + if (this.closeMenuTimeout) { + clearTimeout(this.closeMenuTimeout); + } + this.closeMenuTimeout = setTimeout(() => { + this.willClose = false; + this.menus = []; + this.notify(); + }, 200); + + this.notify(); + } + async openMenu(menu, domRect, positionType, options) { + + if(typeof menu === 'function') { + menu = await menu(); + } + + this.menus = []; + + if (this.closeMenuTimeout) { + this.willClose = false; + clearTimeout(this.closeMenuTimeout); + } + + if (!options) { + options = {}; + } + + var position = this.bestPosition(domRect, positionType, { margin: options.margin || 0 }); + + this.menus.push({ + menu: menu, + positionType: positionType, + position: position, + left: position.left, + openAt: Date.now(), + level: 0, + id: Number.unid(), + allowClickOut: options.allowClickOut !== undefined ? options.allowClickOut : true, + }); + this.last_opened_id = Number.unid(); + this.notify(); + this.lastOpen = new Date().getTime(); + + return this.last_opened_id; + } + openSubMenu(menu, domRect, level, positionType) { + this.max_level = level + 1; + this.closeSubMenu(level); + var position = this.bestPosition(domRect, positionType); + this.menus.push({ + menu: menu, + positionType: positionType, + position: position, + left: position.left, + openAt: Date.now(), + level: level + 1, + id: Number.unid(), + }); + + this.notify(); + } + closeSubMenu(level) { + this.max_level = level; + this.menus.forEach(item => { + if (item.level > level) { + item.willClose = true; + } + }); + this.notify(); + setTimeout(() => { + var new_menus = []; + this.menus.forEach(item => { + if (!(item.level > level && item.willClose)) { + new_menus.push(item); + } + }); + this.menus = new_menus; + this.notify(); + }, 200); + } + + bestPosition(rect, position, options) { + if (Globals.isReactNative) { + return {}; + } + + options = options || {}; + options.margin = options.margin || 0; + + rect = { + left: rect.left - options.margin, + x: rect.x - options.margin, + top: rect.top - options.margin, + y: rect.y - options.margin, + right: rect.right + options.margin, + bottom: rect.bottom + options.margin, + width: rect.width + 2 * options.margin, + height: rect.height + 2 * options.margin, + }; + + var x = rect.right || rect.x; + var y = rect.y; + + if (position === 'top' || position === 'bottom' || position === 'center') { + x = rect.x; + y = rect.bottom || rect.y; + if (position === 'top') { + y = rect.top || rect.y; + } + + return { + x: x + (rect.width || 0) / 2 - 100, + y: y, + left: false, + }; + } + + var left = false; + if (rect.right + 200 > document.documentElement.clientWidth) { + x = (rect.left || rect.x) - 200; + left = true; + } + if (x < 0) { + x = 0; + left = false; + } + + return { + x: x, + y: y + (rect.height || 0) / 2, + left: left, + }; + } +} + +export default new MenusManager(); diff --git a/twake/frontend/src/app/components/message-seen-by/message-seen-by.tsx b/twake/frontend/src/app/components/message-seen-by/message-seen-by.tsx new file mode 100644 index 00000000..11099696 --- /dev/null +++ b/twake/frontend/src/app/components/message-seen-by/message-seen-by.tsx @@ -0,0 +1,68 @@ +import UserBlock from 'app/molecules/grouped-rows/user'; +import { Modal, ModalContent } from 'app/atoms/modal'; +import messageApiClient from 'app/features/messages/api/message-api-client'; +import { UserType } from 'app/features/users/types/user'; +import React, { useEffect, useState } from 'react'; +import Avatar from 'app/atoms/avatar'; +import { useMessageSeenBy } from 'app/features/messages/hooks/use-message-seen-by'; +import Loader from '../loader/loader'; +import Languages from 'app/features/global/services/languages-service'; +import { Base } from 'app/atoms/text'; + +export default (): React.ReactElement => { + const { isOpen, closeSeenBy, seenMessage } = useMessageSeenBy(); + const [users, setUsers] = useState<UserType[]>(); + const [loading, setLoading] = useState(true); + + useEffect(() => { + if (isOpen && seenMessage) { + const { company_id, message_id, thread_id, workspace_id } = seenMessage; + + setLoading(true); + messageApiClient.seenBy(message_id, thread_id, company_id, workspace_id).then(users => { + setLoading(false); + setUsers(users); + }); + } + }, [open, seenMessage]); + + return ( + <Modal open={isOpen} onClose={() => closeSeenBy()} className="sm:w-[60vw] sm:max-w-2xl"> + <ModalContent + textCenter + title={Languages.t('components.message_seen_by.title', [], "Users who've seen the message")} + > + {loading ? ( + <div className="flex h-full justify-center items-center px-2"> + <Loader className="h-8 w-8 m-auto" /> + </div> + ) : ( + <div className="flex"> + <div className="w-[60vw] rounded-sm px-2 m-2"> + {users && users.length ? ( + users.map(user => ( + <UserBlock + avatar={ + <Avatar title={user.full_name ?? user.username} avatar={user.thumbnail} /> + } + title={user.full_name ?? user.username} + subtitle={user.email} + key={user.id} + /> + )) + ) : ( + <Base className='pt-4'> + {Languages.t( + 'components.message_seen_by.none_seen_it', + [], + 'No one has seen the message yet', + )} + </Base> + )} + </div> + </div> + )} + </ModalContent> + </Modal> + ); +}; diff --git a/twake/frontend/src/app/components/modal/modal-component.scss b/twake/frontend/src/app/components/modal/modal-component.scss new file mode 100755 index 00000000..e7e957c2 --- /dev/null +++ b/twake/frontend/src/app/components/modal/modal-component.scss @@ -0,0 +1,44 @@ +.mediumPopupComponent { + .background { + position: absolute; + z-index: 8; + left: 0; + top: 0; + width: 100%; + height: 100%; + background: #0000002e; + } + + .componentContainer { + position: absolute; + margin: auto; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: 0px; + height: 0px; + z-index: 9; + transition: top 0.2s, bottom 0.2s, left 0.2s, right 0.2s; + + .component { + max-height: 80vh; + transform: translateX(-50%) translateY(-50%); + position: relative; + height: auto; + min-width: 325px; + background: #fff; + z-index: 1; + box-shadow: 0 2px 32px rgba(0, 0, 0, 0.2); + border-radius: var(--border-radius-base); + padding: 16px; + box-sizing: border-box; + + & > .scrollbar-container { + margin: -16px; + padding: 16px; + max-height: calc(80vh - 200px); + } + } + } +} diff --git a/twake/frontend/src/app/components/modal/modal-component.tsx b/twake/frontend/src/app/components/modal/modal-component.tsx new file mode 100755 index 00000000..af0bd85d --- /dev/null +++ b/twake/frontend/src/app/components/modal/modal-component.tsx @@ -0,0 +1,51 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React, { useEffect, useMemo } from 'react'; +import { Modal } from 'antd'; +import './modal-component.scss'; +import ModalManager from 'app/components/modal/modal-manager'; + +let component: any = null; +export default () => { + const open = ModalManager.useWatcher(() => ModalManager.isOpen()); + + const eventClose = useMemo( + () => (evt: any) => { + if (evt.keyCode === 27 && ModalManager.canClose()) { + close(); + } + }, + [], + ); + + const close = () => { + if (ModalManager.canClose()) { + ModalManager.close(); + } + }; + + /* eslint-disable react-hooks/exhaustive-deps */ + useEffect(() => { + document.addEventListener('keydown', eventClose); + return () => { + document.removeEventListener('keydown', eventClose); + }; + }, []); + /* eslint-enable react-hooks/exhaustive-deps */ + + component = ModalManager.getComponent() || component; + + return ( + <Modal + onCancel={close} + centered + closable={false} + title={null} + visible={open} + footer={null} + destroyOnClose={true} + width={ModalManager.getPosition()?.size?.width || '700px'} + > + {component} + </Modal> + ); +}; diff --git a/twake/frontend/src/app/components/modal/modal-manager.ts b/twake/frontend/src/app/components/modal/modal-manager.ts new file mode 100755 index 00000000..765044d3 --- /dev/null +++ b/twake/frontend/src/app/components/modal/modal-manager.ts @@ -0,0 +1,82 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import Observable from 'app/deprecated/Observable/Observable'; +import MenusManager from 'app/components/menus/menus-manager.jsx'; + +class ModalManagerService extends Observable { + static service: ModalManagerService = new ModalManagerService(); + private component: any[] = []; + private popupStates: any = {}; + private position: any = null; + private mountedComponent: any = null; + private closing = false; + private creationTimeout: any = null; + + getPosition() { + return this.position; + } + + updateHighlight(highlight: any) { + if (this.position) this.position.highlight = highlight; + this.notify(); + } + + open(component: any, position: any, canClose?: boolean, clearState?: any) { + this.close(); + + this.mountedComponent = null; + + this.creationTimeout && clearTimeout(this.creationTimeout); + this.creationTimeout = setTimeout(() => { + this.component = []; + this.position = position || {}; + MenusManager.closeMenu(); + if (clearState) { + delete this.popupStates[clearState]; + } + this.component.push({ component: component, canClose: canClose !== false }); + this.notify(); + }, 100); + } + + isOpen() { + return this.component.length > 0; + } + + close() { + if (this.closing) { + return false; + } + if (this.isOpen()) { + this.closing = true; + (this.mountedComponent || {}).onMediumPopupClose && + this.mountedComponent.onMediumPopupClose(); + + this.mountedComponent = null; + this.component.splice(-1, 1); + this.notify(); + this.closing = false; + } + } + closeAll() { + if (this.isOpen()) { + (this.mountedComponent || {}).onMediumPopupClose && + this.mountedComponent.onMediumPopupClose(); + + this.mountedComponent = null; + this.component = []; + this.notify(); + } + } + canClose() { + if (this.isOpen()) { + return this.component[this.component.length - 1].canClose; + } + return null; + } + getComponent() { + return this.component[this.component.length - 1]?.component || ''; + } +} + +const ModalManager = ModalManagerService.service; +export default ModalManager; diff --git a/twake/frontend/src/app/components/new-version/new-version-component.tsx b/twake/frontend/src/app/components/new-version/new-version-component.tsx new file mode 100644 index 00000000..bf17a145 --- /dev/null +++ b/twake/frontend/src/app/components/new-version/new-version-component.tsx @@ -0,0 +1,108 @@ +import React, { useMemo, useState } from 'react'; +import { Col, Row, Typography } from 'antd'; + +import Api from 'app/features/global/framework/api-service'; +import Banner from 'app/components/banner/banner'; +import Emojione from 'app/components/emojione/emojione'; +import Languages from 'app/features/global/services/languages-service'; +import Globals from 'app/features/global/services/globals-twake-app-service'; +import ModalManager from 'app/components/modal/modal-manager'; +import NewVersionModal from './new-version-modal'; +import { ServerInfoType } from 'app/features/global/services/init-service'; + +let lastScrape = 0; + +const NewVersionComponent = (): JSX.Element => { + const [displayBanner, setDisplayBanner] = useState<boolean>(false); + + const compareVersion: (v1: string, v2: string) => number = (v1: string, v2: string) => { + const toNumber: (v: string) => number = (v: string) => { + const a = v.split('.').map((s: string) => parseInt(s.replace(/[^0-9]/g, ''))); + return 1000000 * (1000 * a[0] + a[1]) + a[2]; + }; + return toNumber(v1) - toNumber(v2); + }; + + useMemo(() => { + const getConfiguration = async () => { + if (new Date().getTime() - lastScrape < 15 * 60 * 1000) { + return; + } + lastScrape = new Date().getTime(); + + const config = await Api.get<ServerInfoType>( + '/internal/services/general/v1/server', + undefined, + false, + { + disableJWTAuthentication: true, + }, + ); + const currentVersion: string = Globals.version.version_detail; + const newestVersion: string = config?.version?.current || ''; + const minimalWebVersion: string = config?.version?.minimal?.web || ''; + + const shouldDisplayModal: boolean = + minimalWebVersion && compareVersion(minimalWebVersion, currentVersion) > 0 ? true : false; + const shouldDisplayBanner: boolean = + newestVersion && compareVersion(newestVersion, currentVersion) > 0 && !shouldDisplayModal + ? true + : false; + + if (shouldDisplayModal) { + return ModalManager.open( + <NewVersionModal />, + { + position: 'center', + size: { width: '600px' }, + }, + false, + ); + } + + if (shouldDisplayBanner) { + return setDisplayBanner(shouldDisplayBanner); + } + }; + + document.addEventListener('visibilitychange', () => { + getConfiguration(); + }); + window.addEventListener('focus', () => { + getConfiguration(); + }); + getConfiguration(); + }, []); + + return ( + <> + {displayBanner && ( + <Banner + height={32} + type="primary" + content={ + <Row align="middle" gutter={[8, 0]}> + <Col> + <b>{Languages.t('components.newversion.new_version_component.row.part_1')}</b>,{' '} + {Languages.t('components.newversion.new_version_component.row.part_2')}{' '} + <Emojione type="rocket" /> + </Col> + <Col> + <Typography.Link + style={{ color: 'var(--white)' }} + underline + onClick={() => window.location.reload()} + > + {Languages.t('components.newversion.new_version_component.link')} + </Typography.Link> + </Col> + </Row> + } + closable + onClose={() => setDisplayBanner(false)} + /> + )} + </> + ); +}; +export default NewVersionComponent; diff --git a/twake/frontend/src/app/components/new-version/new-version-modal.tsx b/twake/frontend/src/app/components/new-version/new-version-modal.tsx new file mode 100644 index 00000000..f4415f29 --- /dev/null +++ b/twake/frontend/src/app/components/new-version/new-version-modal.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import ObjectModal from '../object-modal/object-modal'; +import Languages from 'app/features/global/services/languages-service'; +import Emojione from '../emojione/emojione'; +import { Button } from 'antd'; + +const NewVersionModal = () => { + const onClickBtn = () => { + return window.location.reload(); + }; + + return ( + <ObjectModal + title={ + <> + {Languages.t('components.newversion.new_version_modal.title')} <Emojione type="rocket" /> + </> + } + footer={ + <Button type="primary" onClick={onClickBtn}> + {Languages.t('scenes.app.header.disconnected.reload')} + </Button> + } + > + <div className="x-margin"> + <b>{Languages.t('components.newversion.new_version_component.row.part_1')}</b>,{' '} + {Languages.t('components.newversion.new_version_component.row.part_2')} + </div> + </ObjectModal> + ); +}; + +export default NewVersionModal; diff --git a/twake/frontend/src/app/components/object-modal/deprecated-object-modal.jsx b/twake/frontend/src/app/components/object-modal/deprecated-object-modal.jsx new file mode 100755 index 00000000..86cf5075 --- /dev/null +++ b/twake/frontend/src/app/components/object-modal/deprecated-object-modal.jsx @@ -0,0 +1,118 @@ +import React, { Component } from 'react'; +import Icon from 'app/components/icon/icon.jsx'; +import PerfectScrollbar from 'react-perfect-scrollbar'; +import Tabs from 'components/tabs/tabs.jsx'; +import './deprecated-object-modal.scss'; +import { Divider } from 'antd'; + +export class ObjectModalTitle extends Component { + render() { + return ( + <div className={'modal_title ' + this.props.className} style={this.props.style}> + {this.props.children} + </div> + ); + } +} +//ObjectModalSeparator +export class ObjectModalSeparator extends Component { + render() { + return <div className="separator"></div>; + } +} +//ObjectModalSectionTitle +export class ObjectModalSectionTitle extends Component { + render() { + return ( + <div + style={{ + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + marginBottom: this.props.smallMargin ? '16px' : '', + }} + > + <b>{this.props.title || this.props.children}</b> + <div>{this.props.action}</div> + </div> + ); + } +} + +// ObjectModalFormTitle +export class ObjectModalFormTitle extends Component { + render() { + return ( + <div className={'section_title ' + this.props.className} style={this.props.style}> + {this.props.icon && <Icon type={this.props.icon} className="m-icon-small" />} + <span>{this.props.name}</span> + </div> + ); + } +} + +export class ObjectModal extends Component { + constructor(props) { + super(); + this.state = {}; + } + render() { + return ( + <div className={'object_modal ' + this.props.className}> + <div className="top_right_buttons"> + {this.props.onEdit && ( + <div className="square_button" onClick={this.props.onEdit}> + <Icon type="edit-alt" className="m-icon-small" /> + </div> + )} + {this.props.onClose && ( + <div className="square_button" onClick={this.props.onClose}> + <Icon type="times" className="m-icon-small" /> + </div> + )} + </div> + + <div className={!this.props.noCloseButton ? 'title' : ''}>{this.props.title}</div> + + {this.props.tabs && ( + <Tabs + tabs={this.props.tabs.map(item => { + return { + title: item.title || '', + render: ( + <div className="body"> + <PerfectScrollbar options={{ suppressScrollX: true }} component="div"> + {item.render} + </PerfectScrollbar> + </div> + ), + }; + })} + /> + )} + + {!this.props.tabs && ( + <div className="body"> + {!!this.props.noScrollBar && ( + <div className="child-with-margin">{this.props.children}</div> + )} + {!this.props.noScrollBar && ( + <PerfectScrollbar options={{ suppressScrollX: true }} component="div"> + {this.props.children} + </PerfectScrollbar> + )} + </div> + )} + + {this.props.footer && <div className="separator" style={{ marginTop: 0 }} />} + {this.props.footer && ( + <div className="footer bottom-margin"> + <Divider /> + <div className="x-margin">{this.props.footer}</div> + </div> + )} + </div> + ); + } +} diff --git a/twake/frontend/src/app/components/object-modal/deprecated-object-modal.scss b/twake/frontend/src/app/components/object-modal/deprecated-object-modal.scss new file mode 100755 index 00000000..c376b19c --- /dev/null +++ b/twake/frontend/src/app/components/object-modal/deprecated-object-modal.scss @@ -0,0 +1,64 @@ +.object_modal { + position: relative; + display: flex; + flex-direction: column; + margin-bottom: 24px; + + & > .title { + padding-right: 56px; + margin: 16px 0 11px 16px; + } + + & > .top_right_buttons { + position: absolute; + top: 16px; + right: 16px; + left: 16px; + text-align: right; + + .square_button { + vertical-align: top; + display: inline-block; + width: 24px; + height: 24px; + line-height: 24px; + border-radius: var(--border-radius-base); + margin-left: 8px; + background: var(--grey-background); + cursor: pointer; + + &:hover { + background: var(--primary-background); + } + } + } + + & > .body { + margin: 0 0; + .scrollbar-container, + .child-with-margin { + padding: 16px; + max-height: calc(80vh - 200px); + } + } + + .modal_title { + font-size: 24px; + color: var(--black); + } +} + +.section_title { + color: var(--grey-dark); + font-size: 14px; + font-weight: 500; + margin-bottom: 8px; + margin-top: 24px; + + i { + margin-right: 4px; + &:before { + margin-left: 0px; + } + } +} diff --git a/twake/frontend/src/app/components/object-modal/object-modal.scss b/twake/frontend/src/app/components/object-modal/object-modal.scss new file mode 100644 index 00000000..75354ec9 --- /dev/null +++ b/twake/frontend/src/app/components/object-modal/object-modal.scss @@ -0,0 +1,59 @@ +.modal-layout { + padding: 0px; + + h2.ant-typography img.emojione { + width: 40px !important; + height: 40px !important; + margin-left: 8px; + } + + &, + .modal-layout-footer { + background: transparent !important; + height: auto; + min-height: 64px; + } + + .modal-layout-header { + border-top-left-radius: var(--border-radius-large); + border-top-right-radius: var(--border-radius-large); + padding: 0; + background: var(--white); + height: auto; + + & .modal-layout-row, + & { + min-height: 64px; + } + + .square-button { + vertical-align: top; + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + line-height: 24px; + border-radius: var(--border-radius-large); + cursor: pointer; + background: var(--grey-background); + + &.red { + color: var(--red); + background: var(--white); + } + &:hover { + opacity: 0.9; + } + } + } + + .modal-layout-row { + height: 100%; + padding: 0 22px; + } + + .modal-layout-footer { + padding: 0; + } +} diff --git a/twake/frontend/src/app/components/object-modal/object-modal.tsx b/twake/frontend/src/app/components/object-modal/object-modal.tsx new file mode 100644 index 00000000..62238ec0 --- /dev/null +++ b/twake/frontend/src/app/components/object-modal/object-modal.tsx @@ -0,0 +1,95 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React, { FC } from 'react'; + +import classNames from 'classnames'; +import { Divider, Layout, Typography, Col, Row } from 'antd'; + +import ModalManager from 'app/components/modal/modal-manager'; +import Icon from 'app/components/icon/icon.jsx'; + +import './object-modal.scss'; + +type PropsType = { + title?: string | JSX.Element; + closable?: boolean; + children?: React.Component | JSX.Element | any; + footer?: React.Component | JSX.Element | any; + hideFooterDivider?: boolean; + footerAlign?: 'start' | 'end' | 'center' | 'space-around' | 'space-between' | undefined; + titleCenter?: boolean; + style?: React.CSSProperties; + headerStyle?: React.CSSProperties; + footerStyle?: React.CSSProperties; + titleLevel?: 5 | 1 | 2 | 3 | 4 | undefined; + titleColor?: string; + colTitleStyle?: React.CSSProperties; + contentStyle?: React.CSSProperties; + titleTypographyStyle?: React.CSSProperties; + className?: string; + footerDividerStyle?: React.CSSProperties; + onClose?: () => void; +}; + +const { Header, Content, Footer } = Layout; +const ObjectModal: FC<PropsType> = (props: PropsType) => { + return ( + <Layout + className={classNames('modal-layout', props.className)} + hasSider={false} + style={props.style || {}} + > + <Header className="modal-layout-header" style={props.headerStyle || {}}> + <Row justify="space-between" align="middle" className="modal-layout-row" wrap={false}> + {props.titleCenter && <Col style={{ width: 32 }}></Col>} + {props.title && ( + <Col style={props.colTitleStyle}> + <Typography.Title + level={props.titleLevel || 5} + style={{ + margin: 0, + marginTop: props.titleCenter ? 8 : 0, + color: props.titleColor, + ...props.titleTypographyStyle, + }} + > + {props.title} + </Typography.Title> + </Col> + )} + {(props.closable === true && ( + <Col> + <Icon + type="times" + className={`m-icon-small square-button ${ + props.headerStyle?.backgroundColor ? 'red' : '' + }`} + onClick={() => (props?.onClose ? props.onClose() : ModalManager.closeAll())} + /> + </Col> + )) || <Col style={{ width: 32 }}></Col>} + </Row> + </Header> + {props.children && <Content style={props.contentStyle}>{props.children}</Content>} + {props.footer && ( + <Footer className="modal-layout-footer"> + {!props.hideFooterDivider && ( + <Divider className="y-margin" style={props.footerDividerStyle} /> + )} + <Row align="middle" justify={props.footerAlign || 'end'}> + <Col + style={{ + marginBottom: props.footerAlign === 'center' ? 54 : 16, + marginRight: !props.footerAlign ? 16 : 0, + ...props.footerStyle, + }} + > + {props.footer} + </Col> + </Row> + </Footer> + )} + </Layout> + ); +}; + +export default ObjectModal; diff --git a/twake/frontend/src/app/components/on-boarding/account-status-component.tsx b/twake/frontend/src/app/components/on-boarding/account-status-component.tsx new file mode 100644 index 00000000..88e6545e --- /dev/null +++ b/twake/frontend/src/app/components/on-boarding/account-status-component.tsx @@ -0,0 +1,78 @@ +import React from 'react'; + +import Banner from 'app/components/banner/banner'; +import { Button, Typography } from 'antd'; +import Languages from 'app/features/global/services/languages-service'; +import ModalManager from 'app/components/modal/modal-manager'; +import UnverifiedAccount from './popups/unverified-account'; +import BlockedAccount from './popups/blocked-account'; +import InitService from 'app/features/global/services/init-service'; +import { useCurrentUser } from 'app/features/users/hooks/use-current-user'; + +const AccountStatusComponent = (): JSX.Element => { + const { user } = useCurrentUser(); + const maxUnverifiedDays = + InitService.server_infos?.configuration?.accounts?.console?.max_unverified_days || 7; + const oneDay = 1000 * 60 * 60 * 24; + const periodLimit = (user?.created_at || 0) + maxUnverifiedDays * oneDay; + const daysLeft = Math.ceil((periodLimit - Date.now()) / oneDay); + + if (!user || InitService.server_infos?.configuration?.accounts?.type !== 'console') { + return <></>; + } + + const showBlockedModal = () => { + if (InitService.server_infos?.configuration?.accounts?.type === 'console') + return ModalManager.open( + <BlockedAccount email={user?.email} />, + { + position: 'center', + size: { width: '600px' }, + }, + false, + ); + }; + + const showUnverifiedModal = () => { + if (InitService.server_infos?.configuration?.accounts?.type === 'console') + return ModalManager.open( + <UnverifiedAccount daysLeft={daysLeft} limit={maxUnverifiedDays} email={user.email} />, + { + position: 'center', + size: { width: '600px' }, + }, + ); + }; + + if (!user.is_verified && daysLeft <= 0) { + showBlockedModal(); + } + + const showBanner = !user.is_verified; + return ( + <> + {showBanner && ( + <Banner + type="important" + content={ + <div style={{ display: 'flex', alignItems: 'center' }}> + <Typography.Title level={5} style={{ marginBottom: 0, color: 'var(--white)' }}> + {Languages.t('components.account_verification_status_sentence', [ + Languages.t('components.account_verication_status_unverified'), + ])} + </Typography.Title> + <Button + style={{ marginLeft: 17, height: 32, color: 'var(--red)' }} + onClick={showUnverifiedModal} + > + {Languages.t('general.verify')} + </Button> + </div> + } + /> + )} + </> + ); +}; + +export default AccountStatusComponent; diff --git a/twake/frontend/src/app/components/on-boarding/company-billing-banner.tsx b/twake/frontend/src/app/components/on-boarding/company-billing-banner.tsx new file mode 100644 index 00000000..9f676d83 --- /dev/null +++ b/twake/frontend/src/app/components/on-boarding/company-billing-banner.tsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { Row, Typography } from 'antd'; +import Banner from '../banner/banner'; +import { CompanyType } from 'app/features/companies/types/company'; +import Groups from 'app/deprecated/workspaces/groups.js'; +import Languages from 'app/features/global/services/languages-service'; +import { AlertTriangle } from 'react-feather'; +import consoleService from 'app/features/console/services/console-service'; + +type PropsType = { + companyId: string; +}; + +const { Link } = Typography; +export default ({ companyId }: PropsType): JSX.Element => { + const companySubscriptionUrl = consoleService.getCompanySubscriptionUrl(companyId); + const userGroups: { [key: string]: CompanyType } = Groups.user_groups; + const currentUserGroup = userGroups[companyId]; + const isCurrentUserAdminOrOwner = + currentUserGroup?.role === 'admin' || currentUserGroup?.role === 'owner'; + + const onClickLink = () => window.open(companySubscriptionUrl, 'blank'); + + const shouldDisplayBanner = currentUserGroup?.plan?.billing?.status === 'warning'; + return shouldDisplayBanner ? ( + <Banner type="important"> + <Row align="middle"> + <AlertTriangle size={24} /> + <div className="small-x-margin"> + {Languages.t( + isCurrentUserAdminOrOwner + ? 'components.on_boarding.company_billing_banner.admin_or_owner_text' + : 'components.on_boarding.company_billing_banner.guest_or_member_text', + )} + </div> + {isCurrentUserAdminOrOwner && ( + <Link onClick={onClickLink}> + {Languages.t('components.on_boarding.company_billing_banner.link')} + </Link> + )} + </Row> + </Banner> + ) : ( + <></> + ); +}; diff --git a/twake/frontend/src/app/components/on-boarding/company-status-component.tsx b/twake/frontend/src/app/components/on-boarding/company-status-component.tsx new file mode 100644 index 00000000..d9ad1c9f --- /dev/null +++ b/twake/frontend/src/app/components/on-boarding/company-status-component.tsx @@ -0,0 +1,76 @@ +import React, { useEffect } from 'react'; +import ModalManager from 'app/components/modal/modal-manager'; +import UserService from 'app/features/users/services/current-user-service'; +import WelcomeOnTwake from './popups/welcome-on-twake'; +import DepreciatedCollections from 'app/deprecated/CollectionsV1/Collections/Collections.js'; +import InitService from 'app/features/global/services/init-service'; +import Groups from 'app/deprecated/workspaces/groups.js'; +import { CompanyType } from 'app/features/companies/types/company'; +import BlockedCompany from './popups/blocked-company'; +import useRouterCompany from 'app/features/router/hooks/use-router-company'; +import useRouterWorkspace from 'app/features/router/hooks/use-router-workspace'; + +const CompanyStatusComponent = (): JSX.Element => { + const companyId = useRouterCompany(); + const workspaceId = useRouterWorkspace(); + const user = UserService.getCurrentUser(); + const onboarding: string | null = localStorage.getItem(`onboarding_${companyId}`); + const workspace = DepreciatedCollections.get('workspaces').find(workspaceId); + + useEffect(() => { + if (InitService.server_infos?.configuration?.accounts?.type === 'console') { + isNewAccount(); + } + + isBlockedCompany(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [companyId]); + + const isNewCompany = (): boolean => { + const oneDay = 1000 * 60 * 60 * 24; + const createdDay = workspace?.group?.stats?.created_at; + const currentDay = Date.now(); + const currentPeriod = Math.round(Math.round(currentDay - createdDay) / oneDay); + + return currentPeriod <= 7 ? true : false; + }; + + const isNewAccount = () => { + if (!workspace?.id) return; + + const isNewUser: boolean = + onboarding !== 'completed' && + workspace?.group?.stats?.total_members <= 1 && + isNewCompany() && + !user?.is_verified; + + if (isNewUser) { + localStorage.setItem(`onboarding_${companyId}`, 'completed'); + return ModalManager.open(<WelcomeOnTwake email={user.email} />, { + position: 'center', + size: { width: '600px' }, + }); + } + }; + + const isBlockedCompany = () => { + if (!companyId) return; + const userGroups: { [key: string]: CompanyType } = Groups.user_groups; + const currentGroup = userGroups[companyId]; + + if (currentGroup?.plan?.billing?.status === 'error') { + return ModalManager.open( + <BlockedCompany />, + { + position: 'center', + size: { width: '600px' }, + }, + false, + ); + } + }; + + return <></>; +}; + +export default CompanyStatusComponent; diff --git a/twake/frontend/src/app/components/on-boarding/popups/add-mails-in-workspace.tsx b/twake/frontend/src/app/components/on-boarding/popups/add-mails-in-workspace.tsx new file mode 100644 index 00000000..9a7dbff7 --- /dev/null +++ b/twake/frontend/src/app/components/on-boarding/popups/add-mails-in-workspace.tsx @@ -0,0 +1,81 @@ +import React, { useState } from 'react'; +import { Button, Col, Row, Typography } from 'antd'; +import AutoHeight from '../../auto-height/auto-height'; +import ObjectModal from '../../object-modal/object-modal'; +import Languages from 'app/features/global/services/languages-service'; +import ModalManager from 'app/components/modal/modal-manager'; +import ConsoleService from 'app/features/console/services/console-service'; +import RouterServices from 'app/features/router/services/router-service'; +import WorkspacesUsers from 'app/features/workspace-members/services/workspace-members-service'; + +export default (): JSX.Element => { + const { companyId, workspaceId } = RouterServices.getStateFromRoute(); + const [emails, _setEmails] = useState<string[]>([]); + const [loading, setLoading] = useState<boolean>(false); + + const setEmails = (str: string) => + _setEmails(WorkspacesUsers.fullStringToEmails(str) as string[]); + + const onChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => setEmails(e.target.value); + + const onClickButton = async () => { + setLoading(true); + + return await ConsoleService.addMailsInWorkspace({ + workspace_id: workspaceId || '', + company_id: companyId || '', + emails, + }).finally(() => { + setLoading(false); + return ModalManager.close(); + }); + }; + + return ( + <ObjectModal + title={Languages.t('components.add_mails_workspace.title_1')} + closable + style={{ height: 600 }} + titleLevel={2} + titleCenter + hideFooterDivider + footerAlign="center" + footer={ + <Row className="x-margin" justify="center"> + <Button onClick={onClickButton} type="primary" size="large" loading={loading}> + {Languages.t('components.add_mails_workspace.button')} + </Button> + </Row> + } + > + <Row + className="x-margin" + style={{ padding: '0 16px', marginTop: 16, marginBottom: 62 }} + justify="center" + > + <Typography.Text + style={{ textAlign: 'center', width: '464px', fontSize: 17, height: '44px' }} + > + {Languages.t('components.add_mails_workspace.title_2')} + </Typography.Text> + </Row> + + <Row className="x-margin" style={{ marginBottom: 12, paddingTop: 32 }} justify="center"> + <Col style={{ width: 400 }}> + <AutoHeight + minHeight="110px" + maxHeight="300px" + onChange={onChange} + placeholder={Languages.t('components.add_mails_workspace.text_area_placeholder')} + /> + </Col> + </Row> + + <Row className="x-margin" style={{ display: 'flex', justifyContent: 'center' }}> + <Typography.Text type="secondary" style={{ width: 380, fontSize: 13, height: 32 }}> + {Languages.t('scenes.app.popup.adduser.adresses_message')} + </Typography.Text> + </Row> + </ObjectModal> + ); +}; diff --git a/twake/frontend/src/app/components/on-boarding/popups/blocked-account.tsx b/twake/frontend/src/app/components/on-boarding/popups/blocked-account.tsx new file mode 100644 index 00000000..b40dca93 --- /dev/null +++ b/twake/frontend/src/app/components/on-boarding/popups/blocked-account.tsx @@ -0,0 +1,94 @@ +/* eslint-disable jsx-a11y/anchor-is-valid */ +import React, { useState } from 'react'; +import { Button, Row, Typography } from 'antd'; +import ObjectModal from '../../object-modal/object-modal'; +import Languages from 'app/features/global/services/languages-service'; +import ConsoleService from 'app/features/console/services/console-service'; +import LoginService from 'app/features/auth/login-service'; + +type PropsType = { + email: string; +}; + +export default ({ email }: PropsType): JSX.Element => { + const [loading, setLoading] = useState<boolean>(false); + + const onClickButton = () => { + setLoading(true); + return ConsoleService.verifyMail().finally(() => setLoading(false)); + }; + + return ( + <ObjectModal + title={Languages.t('components.account_verification_status_sentence', [ + Languages.t('components.account_verication_status_blocked'), + ])} + titleColor="var(--white)" + titleCenter + headerStyle={{ backgroundColor: 'var(--red)', color: 'var(--white)', height: 76 }} + hideFooterDivider + footerAlign="center" + footer={ + <> + <Button type="ghost" size="small" onClick={onClickButton} loading={loading}> + {Languages.t('general.re_send')} + </Button> + + <Row justify="center" style={{ marginTop: 16 }}> + <a className="blue_link" onClick={() => LoginService.logout()}> + {Languages.t('scenes.apps.account.account.logout')} + </a> + </Row> + </> + } + > + <Row justify="center" style={{ marginTop: 36 }}> + <Typography.Title + level={3} + style={{ + textAlign: 'center', + margin: 0, + width: 493, + }} + > + {Languages.t('components.blocked_account.trial_period_over')} + </Typography.Title> + </Row> + + <Row justify="center" style={{ marginTop: 24 }}> + <Typography.Text + style={{ + textAlign: 'center', + height: 22, + }} + > + {Languages.t('components.unverified_account.verification_details')} + </Typography.Text> + </Row> + + <Row justify="center" style={{ marginTop: 12 }}> + <Typography.Text + strong + style={{ + textAlign: 'center', + height: '22px', + }} + > + {email} + </Typography.Text> + </Row> + + <Row justify="center" style={{ marginTop: 32, marginBottom: 8 }}> + <Typography.Text + style={{ + textAlign: 'center', + fontSize: 15, + height: '22px', + }} + > + {Languages.t('components.unverified_account.re_send_email')} + </Typography.Text> + </Row> + </ObjectModal> + ); +}; diff --git a/twake/frontend/src/app/components/on-boarding/popups/blocked-company.tsx b/twake/frontend/src/app/components/on-boarding/popups/blocked-company.tsx new file mode 100644 index 00000000..a3c1e653 --- /dev/null +++ b/twake/frontend/src/app/components/on-boarding/popups/blocked-company.tsx @@ -0,0 +1,138 @@ +import React from 'react'; +import { Button, Row, Typography, Select } from 'antd'; +import ObjectModal from '../../object-modal/object-modal'; +import Languages from 'app/features/global/services/languages-service'; +import LoginService from 'app/features/auth/login-service'; +import { CompanyType } from 'app/features/companies/types/company'; +import { capitalize } from 'lodash'; +import ModalManager from 'app/components/modal/modal-manager'; +import UserService from 'app/features/users/services/current-user-service'; +import Groups from 'app/deprecated/workspaces/groups.js'; +import { AlertTriangle } from 'react-feather'; +import consoleService from 'app/features/console/services/console-service'; +import useRouterCompany from 'app/features/router/hooks/use-router-company'; + +type SwitchCompanyPropsType = { + placeholder?: string; + companiesIds: string[]; +}; + +const { Option } = Select; +const { Text, Title } = Typography; +const SwitchCompany = ({ placeholder, companiesIds }: SwitchCompanyPropsType): JSX.Element => { + const userGroups: { [key: string]: CompanyType } = Groups.user_groups; + const companies = companiesIds + .map(id => userGroups[id]) + .filter(company => company.plan?.billing?.status !== 'error'); + + const onSelect = (companyId: string) => { + Groups.select(userGroups[companyId]); + return ModalManager.close(); + }; + + const onClickBtn = () => LoginService.logout(); + + return ( + (!!companies.length && ( + <Select + placeholder={placeholder || 'Select a company'} + onSelect={onSelect} + style={{ width: 224 }} + > + {companies.map(company => ( + <Option key={company.id} value={company.id}> + {capitalize(company.name)} + </Option> + ))} + </Select> + )) || ( + <Button + type="primary" + style={{ height: 36, width: 163, backgroundColor: 'var(--red)' }} + onClick={onClickBtn} + > + {Languages.t('scenes.app.channelsbar.currentuser.logout')} + </Button> + ) + ); +}; + +export default (): JSX.Element => { + const companyId = useRouterCompany(); + const onClickButton = () => + window.open( + consoleService.getCompanySubscriptionUrl(companyId), + 'blank', + ); + + return ( + <ObjectModal + title={ + <div style={{ display: 'flex' }}> + <AlertTriangle size={24} /> + <span className="small-left-margin"> + {Languages.t('components.on_boarding.popups.blocked_company.title')} + </span> + </div> + } + titleColor="var(--white)" + titleCenter + headerStyle={{ backgroundColor: 'var(--red)', color: 'var(--white)', height: 76 }} + hideFooterDivider + footerAlign="center" + footerStyle={{ marginBottom: 24 }} + footer={ + <Row justify="space-between" align="middle"> + <div + style={{ + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + marginTop: 32, + }} + > + <Button type="ghost" size="large" onClick={onClickButton}> + {Languages.t( + 'components.on_boarding.popups.blocked_company.company_subscription_plan_button', + )} + </Button> + <Text style={{ margin: '8px 0 ' }} strong> + {Languages.t('components.on_boarding.popups.blocked_company.or')} + </Text> + <SwitchCompany + placeholder={Languages.t( + 'components.on_boarding.popups.blocked_company.company_selector', + )} + companiesIds={[...(UserService.getCurrentUser()?.groups_id || [])]} + /> + </div> + </Row> + } + > + <Row justify="center" style={{ marginTop: 36 }}> + <Title + level={3} + style={{ + textAlign: 'center', + margin: 0, + width: 493, + }} + > + {Languages.t('components.on_boarding.popups.blocked_company.description')} + + + + + + {Languages.t('components.on_boarding.popups.blocked_company.learn_more_text')} + + + + ); +}; diff --git a/twake/frontend/src/app/components/on-boarding/popups/unverified-account.tsx b/twake/frontend/src/app/components/on-boarding/popups/unverified-account.tsx new file mode 100644 index 00000000..2f7186ef --- /dev/null +++ b/twake/frontend/src/app/components/on-boarding/popups/unverified-account.tsx @@ -0,0 +1,86 @@ +import React, { useState } from 'react'; +import { Button, Row, Typography } from 'antd'; +import ObjectModal from '../../object-modal/object-modal'; +import Languages from 'app/features/global/services/languages-service'; +import ConsoleService from 'app/features/console/services/console-service'; + +type PropsType = { + daysLeft: number; + limit: number; + email: string; +}; + +export default ({ daysLeft, email, limit }: PropsType): JSX.Element => { + const [loading, setLoading] = useState(false); + + const onClickButton = () => { + setLoading(true); + return ConsoleService.verifyMail().finally(() => setLoading(false)); + }; + + return ( + + {Languages.t('general.re_send')} + + } + > + + + {Languages.t('components.unverified_account.typography_text_danger', [daysLeft, limit])} + + + + + + {Languages.t('components.unverified_account.verification_details')} + + + + + + {email} + + + + + + {Languages.t('components.unverified_account.re_send_email')} + + + + ); +}; diff --git a/twake/frontend/src/app/components/on-boarding/popups/welcome-on-twake.tsx b/twake/frontend/src/app/components/on-boarding/popups/welcome-on-twake.tsx new file mode 100644 index 00000000..2413dff2 --- /dev/null +++ b/twake/frontend/src/app/components/on-boarding/popups/welcome-on-twake.tsx @@ -0,0 +1,119 @@ +import { Button, Row, Typography } from 'antd'; +import React, { useState } from 'react'; +import Emojione from '../../emojione/emojione'; +import ObjectModal from '../../object-modal/object-modal'; +import Languages from 'app/features/global/services/languages-service'; +import ModalManager from 'app/components/modal/modal-manager'; +import AddMailsInWorkspace from './add-mails-in-workspace'; +import ConsoleService from 'app/features/console/services/console-service'; + +type PropsType = { + email: string; +}; + +export default ({ email }: PropsType) => { + const [loading, setLoading] = useState(false); + const openAddMembers = () => + ModalManager.open(, { + position: 'center', + size: { width: '600px' }, + }); + + const onClickButton = () => { + setLoading(true); + return ConsoleService.verifyMail().finally(() => setLoading(false)); + }; + + return ( + + {Languages.t('components.verify_mail.title_1')} + +
+ } + closable + style={{ height: 600 }} + titleLevel={2} + titleCenter + footerAlign="center" + hideFooterDivider + footer={ + + } + > + + + {Languages.t('components.verify_mail.title_2')} + + + + + {Languages.t('components.verify_mail.text')} + + + + + + {email} + + + + + + {Languages.t('components.verify_mail.paragraph')} + + + + + + {Languages.t('components.unverified_account.re_send_email')} + + + + + + + + ); +}; diff --git a/twake/frontend/src/app/components/online-user-status/online-user-status.scss b/twake/frontend/src/app/components/online-user-status/online-user-status.scss new file mode 100644 index 00000000..43f4307a --- /dev/null +++ b/twake/frontend/src/app/components/online-user-status/online-user-status.scss @@ -0,0 +1,30 @@ +.online_user_status { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--grey-dark); + border: 1px solid var(--grey-background); + + &.online { + background: var(--green); + } + + &.offline { + background: var(--red); + } + + &.small { + width: 6px; + height: 6px; + } + + &.medium { + width: 8px; + height: 8px; + } + + &.big { + width: 12px; + height: 12px; + } +} \ No newline at end of file diff --git a/twake/frontend/src/app/components/online-user-status/online-user-status.tsx b/twake/frontend/src/app/components/online-user-status/online-user-status.tsx new file mode 100644 index 00000000..6447ffb0 --- /dev/null +++ b/twake/frontend/src/app/components/online-user-status/online-user-status.tsx @@ -0,0 +1,47 @@ +// eslint-disable-next-line @typescript-eslint/no-use-before-define +import React, { Suspense } from 'react'; +import classNames from 'classnames'; + +import { UserType } from 'app/features/users/types/user'; +import { useOnlineUser } from 'app/features/users/hooks/use-online-user'; + +import './online-user-status.scss'; +import { useUser } from 'app/features/users/hooks/use-user'; + +type PropsType = { + user: UserType; + size?: 'small' | 'medium' | 'big'; +}; + +const WrappedUserStatus = ({ user: _user, size = 'medium' }: PropsType): JSX.Element => { + const user = useUser(_user.id || ''); + const userOnlineStatus = useOnlineUser(_user.id as string); + //const lastSeen = userOnlineStatus?.lastSeen || user.last_seen; + const online = + (userOnlineStatus && userOnlineStatus.connected) || + (!userOnlineStatus?.lastSeen && + user?.is_connected && + (user?.last_seen || 0) > Date.now() - 10 * 60 * 1000); + + return ( +
+ ); +}; + +const UserOnlineStatus = (props: PropsType): JSX.Element => { + return ( + }> + + + ); +}; + +export default UserOnlineStatus; diff --git a/twake/frontend/src/app/components/open-desktop-popup/open-desktop-popup.tsx b/twake/frontend/src/app/components/open-desktop-popup/open-desktop-popup.tsx new file mode 100644 index 00000000..a5a25f51 --- /dev/null +++ b/twake/frontend/src/app/components/open-desktop-popup/open-desktop-popup.tsx @@ -0,0 +1,39 @@ +import React, { useState, useEffect } from 'react'; +import { Logo } from 'app/atoms/logo'; +import { Subtitle } from 'app/atoms/text'; +import A from 'app/atoms/link'; +import { useRecoilState } from 'recoil'; +import { useWebState } from 'app/features/global/state/atoms/use-web'; +import Languages from 'app/features/global/services/languages-service'; + +export const OpenDesktopPopup = (): React.ReactElement => { + const [showLink, setShowLink] = useState(true); + const [, setUseWeb] = useRecoilState(useWebState); + + useEffect(() => { + setTimeout(() => { + setShowLink(true); + }, 5000); + }, []); + + return ( +
+ + + {Languages.t('components.open_desktop_popup.subtitle')} + + {showLink && ( + <> + { + setUseWeb(true); + }} + > + {Languages.t('components.open_desktop_popup.open_here_link')} + + + )} +
+ ); +}; diff --git a/twake/frontend/src/app/components/parameters/attribute.jsx b/twake/frontend/src/app/components/parameters/attribute.jsx new file mode 100755 index 00000000..3bbe597c --- /dev/null +++ b/twake/frontend/src/app/components/parameters/attribute.jsx @@ -0,0 +1,87 @@ +import React, { Component } from 'react'; + +import Number from 'app/features/global/utils/Numbers'; +import AttributesManager from './attributes-manager.js'; +import './parameters.scss'; +import Languages from 'app/features/global/services/languages-service'; + +export default class Attribute extends React.Component { + constructor(props) { + super(); + + this.id = Number.unid(); + + this.state = { + parameters_attributes: AttributesManager, + i18n: Languages, + }; + + this.timeout = setTimeout(''); + + Languages.addListener(this); + AttributesManager.addListener(this); + } + componentDidMount() { + if (this.props.autoOpen) { + AttributesManager.toggle(this.id); + } + } + componentWillUnmount() { + clearTimeout(this.timeout); + Languages.removeListener(this); + AttributesManager.removeListener(this); + } + componentDidUpdate() { + var open = this.state.parameters_attributes.open == this.id; + if (open && !this.was_open) { + this.value_node.style.maxHeight = 'none'; + this.value_height = window.getBoundingClientRect(this.value_node).height; + this.value_node.style.maxHeight = '0px'; + clearTimeout(this.timeout); + this.timeout = setTimeout(() => { + this.value_node.style.maxHeight = this.value_height + 'px'; + + this.timeout = setTimeout(() => { + this.value_node.style.maxHeight = 'none'; + this.value_height = window.getBoundingClientRect(this.value_node).height; + }, 200); + }, 50); + + if (this.props.focusOnOpen) { + this.props.focusOnOpen.focus(); + } + } else if (!open && this.was_open) { + clearTimeout(this.timeout); + + this.value_node.style.maxHeight = this.value_height + 'px'; + this.timeout = setTimeout(() => { + this.value_node.style.maxHeight = '0px'; + }, 50); + } + this.was_open = open; + } + render() { + return ( +
+
AttributesManager.toggle(this.id)}> + {!this.props.autoOpen && ( + + {this.state.parameters_attributes.open == this.id + ? this.state.i18n.t('general.close') + : this.state.i18n.t('general.open')} + + )} +
{this.props.label}
+
{this.props.description}
+
+
(this.value_node = node)} className="value"> + {this.props.children} +
+
+ ); + } +} diff --git a/twake/frontend/src/app/components/parameters/attributes-manager.js b/twake/frontend/src/app/components/parameters/attributes-manager.js new file mode 100755 index 00000000..76886190 --- /dev/null +++ b/twake/frontend/src/app/components/parameters/attributes-manager.js @@ -0,0 +1,26 @@ +import React, { Component } from 'react'; + +import Observable from 'app/deprecated/CollectionsV1/observable.js'; + +/* + Menus manager service, choose where to generate menu +*/ +class AttributesManager extends Observable { + constructor() { + super(); + this.setObservableName('parameters_attributes'); + + this.open = ''; + } + toggle(id) { + if (this.open == id) { + this.open = ''; + } else { + this.open = id; + } + this.notify(); + } +} + +const service = new AttributesManager(); +export default service; diff --git a/twake/frontend/src/app/components/parameters/parameters.scss b/twake/frontend/src/app/components/parameters/parameters.scss new file mode 100755 index 00000000..12faa22a --- /dev/null +++ b/twake/frontend/src/app/components/parameters/parameters.scss @@ -0,0 +1,56 @@ +.parameters_attribute { + padding-bottom: 10px; + opacity: 0.8; + + &:not(.open) { + &:hover { + opacity: 1; + + .label a { + text-decoration: underline; + } + } + } + &.open { + opacity: 1; + + .value { + border-radius: var(--border-radius-large); + box-sizing: border-box; + opacity: 1; + overflow: visible; + transition-delay: overflow 0.2s; + } + } + + & > .label { + font-size: 15px; + margin-bottom: 5px; + cursor: pointer; + + a { + font-size: 13px; + margin-top: 2px; + float: right; + + &:hover { + text-decoration: underline; + } + } + + .description { + font-size: 13px; + margin-top: 5px; + opacity: 0.4; + } + } + + & > .value { + font-size: 14px; + max-height: 0; + transition: max-height 0.2s, opacity 0.2s; + overflow: hidden; + opacity: 0; + display: flex; + } +} diff --git a/twake/frontend/src/app/components/picker/picker.jsx b/twake/frontend/src/app/components/picker/picker.jsx new file mode 100755 index 00000000..fb89ab3a --- /dev/null +++ b/twake/frontend/src/app/components/picker/picker.jsx @@ -0,0 +1,262 @@ +/* eslint-disable react/jsx-key */ +import React, { Component } from 'react'; +import AutoComplete from 'components/auto-complete/auto-complete'; +import Icon from 'app/components/icon/icon.jsx'; +import Languages from 'app/features/global/services/languages-service'; +import './picker.scss'; + +export default class Picker extends React.Component { + /* + placeholder : string, + search : Array of search function, + renderItem(item) : how to render item + renderItemChoosen(item) : how to add item in input + renderItemSimply(item) : what user will type on input and what we have to replace + onChangeSuggested(list) + onChange(list) : + canCreate + onCreate + disableNavigationKey : + */ + constructor(props) { + super(props); + this.state = { + currentSelected: props.value || [], + inputValue: '', + currentList: [], + selected: [], + }; + this.alreadyBackspace = false; + } + componentWillUnmount() { + document.removeEventListener('click', this.outsideClickListener); + } + componentDidMount() { + if (!this.props.inline) { + this.focus(); + } + + var element = this.container; + this.outsideClickListener = event => { + if (!element.contains(event.target) && document.contains(event.target)) { + this.setState({ focused: false }); + } + }; + this.outsideClickListener = this.outsideClickListener.bind(this); + document.addEventListener('click', this.outsideClickListener); + } + UNSAFE_componentWillUpdate(nextProps, nextState) { + if (nextProps.value != this.props.value) { + nextState.currentSelected = nextProps.value; + } + return true; + } + onSelect(item) { + this.alreadyBackspace = true; + if (item && (item.id === undefined || item.id < 0) && item.front_id === undefined) { + this.onCreate(item.textSearched); + return; + } + var newList = this.state.currentSelected; + for (var i = 0; i < newList.length; i++) { + if (newList[i].id == item.id) { + this.setState({ inputValue: '' }); + return false; + } + } + newList.push(item); + this.setState({ currentSelected: newList }); + this.setState({ inputValue: '' }); + if (this.props.onChange) { + this.props.onChange(newList); + } + this.focus(); + } + onRemove(item) { + var newList = this.state.currentSelected; + var index = newList.indexOf(item); + if (index >= 0) { + newList.splice(index, 1); + this.setState({ currentSelected: newList }); + if (this.props.onChange) { + this.props.onChange(newList); + } + } + this.focus(); + } + onBackspace() { + if (this.alreadyBackspace) { + // if already typed on backspace once + var newList = this.state.currentSelected; + newList.splice(newList.length - 1, 1); + this.setState({ currentSelected: newList }); + } else { + this.alreadyBackspace = true; + } + } + onCreate(text) { + if (this.props.onCreate) { + var item = this.props.onCreate(text, item => { + this.onSelect(item); + }); + } + } + focus() { + if (this.autocomplete_node) { + this.autocomplete_node.focus(); + } + } + render() { + var that = this; + var objects = [ +
+
+ {this.state.currentSelected.map(item => { + return this.props.renderItemChoosen(item); + })} + {!this.props.readOnly && ( + { + text = this.state.inputValue; + this.props.search(text, list => { + if (that.props.canCreate && text.length > 0) { + list.push({ id: -1, autocomplete_id: list.length, textSearched: text }); + } + cb(list); + }); + }, + ]} + renderItemChoosen={[ + item => { + if (item.id < 0 && this.props.canCreate) { + return item.textSearched; + } else { + return this.props.renderItemSimply(item); + } + }, + ]} + max={[this.props.max || 10]} + renderItem={[() => {}]} + regexHooked={[/(.*)/]} + placeholder={ + this.state.currentSelected.length + ? '' + : this.props.placeholder || + Languages.t('scenes.apps.drive.left.search', [], 'Search') + } + onChange={evt => { + this.alreadyBackspace = false; + this.setState({ inputValue: evt.target.value }); + }} + onSelect={item => { + this.onSelect(item); + }} + value={this.state.inputValue} + onChangeCurrentList={(list, selected) => { + this.setState({ currentList: list, selected: selected }); + if (this.props.onChangeSuggested) { + this.props.onChangeSuggested(list); + } + }} + hideResult={true} + onBackspace={() => { + this.onBackspace(); + }} + disableNavigationKey={this.props.disableNavigationKey} + showResultsOnInit={true} + onHide={() => this.setState({ focused: false })} + ref={node => { + this.autocomplete_node = node; + }} + /> + )} +
+
, + ]; + + if (!this.props.readOnly) { + if (!this.props.inline) { + objects.push(
{!!this.props.title && this.props.title}
); + } + + var results = []; + + if (this.state.currentList.length > 0) { + results = this.state.currentList.map((item, index) => { + if (item.id < 0) { + return ( +
{ + evt.stopPropagation(); + evt.preventDefault(); + this.onSelect(item); + }} + > +
+ + Create {this.props.renderItem(item.textSearched)} +
+
+ ); + } else { + return ( +
{ + evt.stopPropagation(); + evt.preventDefault(); + this.onSelect(item); + }} + > +
{this.props.renderItem(item)}
+
+ ); + } + }); + } + if (this.props.inline) { + results = ( +
+ {results} +
+ ); + } + objects = objects.concat(results); + } + + objects = ( +
{ + this.focus(); + this.setState({ focused: true }); + }} + ref={node => (this.container = node)} + className={ + 'picker_container ' + + (this.props.readOnly ? 'readOnly ' : '') + + (this.props.inline ? 'inline ' : '') + + (this.state.focused ? 'focused ' : '') + + this.props.className + } + > + {objects} +
+ ); + + return objects; + } +} diff --git a/twake/frontend/src/app/components/picker/picker.scss b/twake/frontend/src/app/components/picker/picker.scss new file mode 100755 index 00000000..48bd9b66 --- /dev/null +++ b/twake/frontend/src/app/components/picker/picker.scss @@ -0,0 +1,55 @@ +.picker_container { + position: relative; + border-radius: var(--border-radius-large); + &.inline { + transition: box-shadow 0.2s; + + .dropmenu { + opacity: 0; + transition: opacity 0.2s; + pointer-events: none; + } + + &.focused { + &.readOnly { + box-shadow: none !important; + } + + .autocomplete { + box-shadow: none !important; + } + .dropmenu { + opacity: 1; + pointer-events: all; + } + } + } +} + +.picker { + .pickerInput { + border-radius: var(--border-radius-base); + display: flex; + flex-wrap: wrap; + position: relative; + background: #f2f2f2; + + &.readOnly { + margin: 0; + display: inline; + padding: 0; + background: transparent; + } + + .autocomplete { + flex: 1; + min-width: 50px; + position: unset; + input { + background: inherit; + margin-top: 0px; + margin-bottom: 0px; + } + } + } +} diff --git a/twake/frontend/src/app/components/popup-component/popup-component.jsx b/twake/frontend/src/app/components/popup-component/popup-component.jsx new file mode 100755 index 00000000..8e80b718 --- /dev/null +++ b/twake/frontend/src/app/components/popup-component/popup-component.jsx @@ -0,0 +1,42 @@ +import React, { Component } from 'react'; +import './popup-component.scss'; +import popupManager from 'app/deprecated/popupManager/popupManager.js'; +import CloseIcon from '@material-ui/icons/CloseOutlined'; + +export default class PopupComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + popupManager: popupManager, + }; + popupManager.addListener(this); + } + componentWillUnmount() { + popupManager.removeListener(this); + document.removeEventListener('keydown', this.eventClose); + } + componentDidMount() { + document.addEventListener('keydown', this.eventClose); + } + eventClose(evt) { + if (evt.keyCode == 27 && popupManager.canClose()) { + popupManager.close(); + } + } + render() { + return ( +
+ {this.state.popupManager.canClose() && ( +
+
this.state.popupManager.close()}> + +
+
+ )} +
+
{this.state.popupManager.getComponent()}
+
+
+ ); + } +} diff --git a/twake/frontend/src/app/components/popup-component/popup-component.scss b/twake/frontend/src/app/components/popup-component/popup-component.scss new file mode 100755 index 00000000..cdda6b8a --- /dev/null +++ b/twake/frontend/src/app/components/popup-component/popup-component.scss @@ -0,0 +1,104 @@ +.popupComponent { + height: 100%; + width: 100%; + background: white; + + position: absolute; + z-index: 100; + width: 90vw; + height: 90vh; + transform: translate(-50%, -50%); + top: 50%; + left: 50%; + box-shadow: 0 0 0px 1000px #00000088; + border-radius: 16px; + overflow: hidden; + + display: flex; + + @media (max-width: 800px) { + border-radius: 0px; + width: 100vw; + height: 100vh; + max-height: -webkit-fill-available; + } + + .header { + .close { + background: #f2f2f2; + border-radius: 50%; + width: 44px; + height: 44px; + line-height: 40px; + padding: 8px; + box-sizing: border-box; + position: absolute; + right: 24px; + top: 24px; + border: 4px solid #fff; + cursor: pointer; + z-index: 10; + line-height: normal; + + &:hover { + background: #eee; + & > * { + opacity: 0.8; + } + } + & > * { + opacity: 0.5; + } + } + } + + .componentContainer { + flex: 1; + overflow: hidden; + position: relative; + + .component { + overflow: hidden; + height: 100%; + + & > div { + overflow: hidden; + height: 100%; + } + + .main { + display: flex; + width: 100%; + height: 100%; + position: relative; + box-sizing: border-box; + + .sideBar { + width: 220px; + padding-top: 32px; + margin-left: 15px; + } + + .content { + padding-top: 32px; + max-height: 100%; + } + } + } + } + + @media only screen and (max-width: 600px) { + .header { + .close { + right: auto; + left: 16px; + } + } + .main .content { + margin-left: 0px !important; + } + .main .sideBar { + display: none; + } + } +} diff --git a/twake/frontend/src/app/components/quoted-message/quoted-message.tsx b/twake/frontend/src/app/components/quoted-message/quoted-message.tsx new file mode 100644 index 00000000..c3b04b46 --- /dev/null +++ b/twake/frontend/src/app/components/quoted-message/quoted-message.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { useMessage } from 'app/features/messages/hooks/use-message'; +import useRouterCompany from 'app/features/router/hooks/use-router-company'; +import MessageQuote from 'app/molecules/message-quote'; +import { useUser } from 'app/features/users/hooks/use-user'; +import { useMessageQuoteReply } from 'app/features/messages/hooks/use-message-quote-reply'; +import useRouterChannel from 'app/features/router/hooks/use-router-channel'; +import User from 'app/features/users/services/current-user-service'; +import { gotoMessage } from 'src/utils/messages'; +import useRouterWorkspace from 'app/features/router/hooks/use-router-workspace'; +import QuotedContent from 'app/molecules/quoted-content'; +import { NodeMessage } from 'app/features/messages/types/message'; + +type PropsType = { + closable?: boolean; + onClose?: () => void; +}; + +export default ({ closable = true, onClose }: PropsType): React.ReactElement => { + const companyId = useRouterCompany(); + const channelId = useRouterChannel(); + const workspaceId = useRouterWorkspace(); + const { message: quotedMessageId } = useMessageQuoteReply(channelId); + const quotedMessage = useMessage({ + companyId, + threadId: quotedMessageId, + id: quotedMessageId, + }); + + if (!quotedMessage.message) { + return <>; + } + + const { message } = quotedMessage; + const author = useUser(message.user_id); + const authorName = author ? User.getFullName(author) : 'Anonymous'; + const deleted = message.subtype === 'deleted'; + + const quotedContent = ( + + ); + + return ( + gotoMessage(message, companyId, channelId, workspaceId)} + /> + ); +}; diff --git a/twake/frontend/src/app/components/reminder-selector/reminder-selector.jsx b/twake/frontend/src/app/components/reminder-selector/reminder-selector.jsx new file mode 100755 index 00000000..414620b0 --- /dev/null +++ b/twake/frontend/src/app/components/reminder-selector/reminder-selector.jsx @@ -0,0 +1,199 @@ +/* eslint-disable react/no-direct-mutation-state */ +import React, { Component } from 'react'; +import Button from 'components/buttons/button.jsx'; +import Input from 'components/inputs/input.jsx'; +import Icon from 'app/components/icon/icon.jsx'; +import Select from 'components/select/select.jsx'; +import './reminder-selector.scss'; +import Languages from 'app/features/global/services/languages-service'; + +export default class ReminderSelector extends React.Component { + constructor(props) { + super(props); + + this.state = { + reminders: [], + }; + + this.old_value = JSON.stringify(props.reminders || []); + } + + componentDidMount() { + this.updateFromProps(this.props); + } + + shouldComponentUpdate(nextProps, nextState) { + if (this.old_value != JSON.stringify(nextProps.reminders)) { + this.old_value = JSON.stringify(nextProps.reminders); + this.updateFromProps(nextProps); + } + return true; + } + + remove(i) { + delete this.state.reminders[i]; + this.update(); + } + + add() { + this.state.reminders.push({ + mode: 'push', + delay_unit: 'minutes', + delay_value: '30', + }); + this.update(); + } + + update() { + var ret = []; + this.state.reminders.forEach(item => { + if (item.delay_unit == 'minutes' && item.delay_value > 59) { + item.delay_value = 30; + } + if (item.delay_unit == 'hours' && item.delay_value > 23) { + item.delay_value = 1; + } + if (item.delay_unit == 'days' && item.delay_value > 13) { + item.delay_value = 1; + } + if (item.delay_unit == 'weeks' && item.delay_value < 2) { + item.delay_value = 2; + } + + ret.push({ + mode: item.mode, + delay: + parseInt(item.delay_value) * + 60 * + (item.delay_unit == 'hours' ? 60 : 1) * + (item.delay_unit == 'days' ? 60 * 24 : 1) * + (item.delay_unit == 'weeks' ? 60 * 24 * 7 : 1), + }); + }); + + if (this.props.onChange) { + this.props.onChange(ret); + } + + this.setState({}); + } + + updateFromProps(nextProps) { + var props = nextProps || this.props; + + var reminders = []; + + (props.reminders || []).forEach(item => { + var delay_value = parseInt(item.delay / 60); + var delay_unit = 'minutes'; + if (item.delay > 59 * 60) { + delay_value = parseInt(item.delay / (60 * 60)); + delay_unit = 'hours'; + } + if (item.delay > 23 * 60 * 60) { + delay_value = parseInt(item.delay / (60 * 60 * 24)); + delay_unit = 'days'; + } + if (item.delay > 13 * 24 * 60 * 60) { + delay_value = parseInt(item.delay / (60 * 60 * 24 * 7)); + delay_unit = 'weeks'; + } + reminders.push({ + mode: item.mode, + delay_value: delay_value, + delay_unit: delay_unit, + }); + }); + + this.setState({ reminders: reminders }); + } + + render() { + return ( +
+ {this.state.reminders.map((reminder, i) => { + return ( +
+ { + this.state.reminders[i].delay_value = evt.target.value; + if (!evt.target.value) { + return; + } + this.update(); + }} + style={{ width: 60 }} + /> + + setInput({ ...input, query: e.target.value })} + value={input.query} + className={className + ' rounded-tr-none rounded-br-none'} + placeholder={Languages.t('scenes.app.mainview.quick_search_placeholder')} + /> + )} + /> + +
+ ); +}; diff --git a/twake/frontend/src/app/components/search-popup/search-popup.scss b/twake/frontend/src/app/components/search-popup/search-popup.scss new file mode 100755 index 00000000..27169056 --- /dev/null +++ b/twake/frontend/src/app/components/search-popup/search-popup.scss @@ -0,0 +1,516 @@ +//@import url("https://fonts.googleapis.com/css?family=Inter:400,500,600,700"); + +:root { + --white: #fff; + --border-radius-base: 8px; + + --accentlight: #007aff; + --backgroundlight: #ffffff; + --iconlight: #818c99; + --messagebubblelight: #ebedf0; + --separatorlight: #d7d8d9; + --textprimary: #ffffff; + --textprimarylight: #000000; + --texttertiarylight: #818c99; + + --font-size-l: 15px; + --font-size-m: 14px; + --font-size-s: 13px; + --font-size-xl: 16px; + --font-size-xxl: 17px; + --font-size-xxxl: 21px; + --font-size-xxxxl: 24px; + + --font-weight-regular: 400; + --font-weight-medium: 500; + --font-weight-semibold: 600; + --font-weight-bold: 700; + + --font-family-inter: 'Inter', Helvetica; +} + +.screen input:focus { + outline: none; +} + +.screen * { + -webkit-font-smoothing: antialiased; + box-sizing: border-box; +} + +.screen div { + -webkit-text-size-adjust: none; +} + +.container-center-horizontal { + display: flex; + flex-direction: row; + justify-content: center; + pointer-events: none; + width: 100%; +} + +.container-center-horizontal > * { + flex-shrink: 0; + pointer-events: auto; +} + +@keyframes reveal { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +input:focus { + outline: none; +} + +* { + box-sizing: border-box; +} + +/* screen - search */ + +.search-popup .overlay { + position: absolute; + z-index: 8; + left: 0; + top: 0; + width: 100%; + height: 100%; + background: #0000002e; +} + +.search-popup .component-container { + position: absolute; + margin: auto; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: 0px; + height: 0px; + z-index: 9; + //transition: opacity 1s easy-out, top 0.2s, bottom 0.2s, left 0.2s, right 0.2s; + margin-top: 30vh; +} + +.search-popup { + .searchLoading { + text-align: center; + } +} + +.search { + justify-content: flex-start; + mix-blend-mode: normal; + + //position: absolute; + height: calc(100vh - 20px); + transform: translate(-50%, -29%); + background: var(--white); + box-shadow: 0 2px 32px rgba(0, 0, 0, 0.2); + + .tabs-wrapper { + width: 100%; + align-items: flex-start; + display: flex; + flex-direction: column; + justify-content: flex-start; + mix-blend-mode: normal; + //position: absolute; + //top: 112px; + .tab-items-wrapper { + align-items: flex-start; + display: flex; + justify-content: flex-start; + overflow: hidden; + + .tab-item-wrapper { + align-items: center; + display: flex; + height: 48px; + justify-content: flex-start; + min-width: 73px; + padding-left: 16px; + padding-right: 16px; + z-index: 1; + + .tab-item-active { + border-bottom: 2px solid var(--accentlight); + } + + .tab-item-title { + color: var(--iconlight); + font-family: var(--font-family-inter); + font-size: var(--font-size-xl); + font-style: normal; + font-weight: var(--font-weight-medium); + letter-spacing: -0.16px; + line-height: 20px; + mix-blend-mode: normal; + position: relative; + text-align: center; + white-space: nowrap; + width: auto; + padding: 0px 10px; + } + + .tab-item-active .tab-item-title { + color: var(--accentlight); + } + + .tab-item-indicator { + align-self: stretch; + + height: 6.5px; + position: relative; + } + } + } + + .tab-horizontal-separator { + height: 1px; + background-color: var(--separatorlight); + mix-blend-mode: normal; + width: calc(100% - 30px); + margin: 0px 15px; + margin-top: -11px; + } + } + + .input-wrapper { + position: relative; + width: 100%; + padding: 0 12px; + + .input.big { + height: 36px; + background-color: var(--messagebubblelight); + padding-left: 36px; + font-weight: var(--font-weight-regular); + } + + .input_icon.big > i { + padding-top: 6px; + padding-left: 8px; + font-size: 16px; + } + + .input-clear-btn { + position: absolute; + top: 10px; + right: 24px; + cursor: pointer; + } + } + + .header-wrapper { + width: 100%; + min-height: 52px; + position: relative; + } + + .header-title { + margin: 0 auto; + padding-top: 16px; + color: var(--textprimarylight); + font-family: var(--font-family-inter); + font-size: var(--font-size-xxxl); + font-style: normal; + font-weight: 700; + letter-spacing: 0px; + line-height: 26px; + mix-blend-mode: normal; + position: relative; + text-align: center; + white-space: nowrap; + width: 100%; + } + + .header-close-btn { + border-radius: 10px; + height: 25px; + top: 17px; + right: 12px; + position: absolute; + width: 25px; + cursor: pointer; + } + + .results-wrapper { + //* {box-shadow: 0 0 0 1px gray;} + + overflow: hidden; + margin-top: 4px; + margin-left: 18px; + width: calc(100% - 36px); + + .results-group { + margin-bottom: 15px; + } + + .results-group:last-child { + margin-bottom: 0; + } + + .results-group-title { + margin-bottom: 10px; + letter-spacing: -0.15px; + line-height: 18px; + mix-blend-mode: normal; + text-align: left; + white-space: nowrap; + color: var(--textprimarylight); + font-family: var(--font-family-inter); + font-size: var(--font-size-l); + font-style: normal; + font-weight: var(--font-weight-semibold); + } + } + + .search-results { + .result-items { + margin-top: 10px; + margin-bottom: 20px; + + .result-item { + display: flex; + margin-bottom: 15px; + cursor: pointer; + + .component-channel-avatar .channel-icon-wrapper { + width: 60px; + height: 60px; + } + + .result-item-icon { + height: 58px; + width: 58px; + position: relative; + } + + .result-item-content { + margin-left: 10px; + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; + flex: 1 1 auto; + -webkit-mask-image: linear-gradient(to right, black 85%, transparent 100%); + mask-image: linear-gradient(to right, black 85%, transparent 100%); + overflow: hidden; + + .channel-title { + letter-spacing: -0.41px; + line-height: 22px; + mix-blend-mode: normal; + text-align: left; + white-space: nowrap; + color: var(--textprimarylight); + font-family: var(--font-family-inter); + font-size: var(--font-size-xxl); + font-style: normal; + font-weight: var(--font-weight-semibold); + margin-bottom: 1px; + } + + .channel-description { + color: #6d7885; + font-family: var(--font-family-inter); + font-size: var(--font-size-l); + font-style: normal; + font-weight: var(--font-weight-regular); + height: 16px; + letter-spacing: -0.24px; + line-height: 20px; + mix-blend-mode: normal; + text-align: left; + white-space: nowrap; + margin-bottom: 5px; + } + + .messages-title { + font-family: var(--font-family-inter); + font-style: normal; + font-weight: 600; + font-size: 15px; + line-height: 16px; + display: flex; + align-items: center; + text-align: center; + letter-spacing: -0.352941px; + } + + .messages-author { + color: var(--textprimarylight); + font-family: var(--font-family-inter); + font-size: var(--font-size-m); + font-style: normal; + font-weight: var(--font-weight-regular); + + letter-spacing: -0.15px; + line-height: 18px; + mix-blend-mode: normal; + text-align: center; + white-space: nowrap; + } + + .messages-text { + font-style: normal; + letter-spacing: -0.02px; + color: var(--iconlight); + font-family: var(--font-family-inter); + font-size: var(--font-size-m); + font-weight: var(--font-weight-regular); + line-height: 16px; + margin-bottom: 2px; + } + + .highlight { + color: var(--accentlight); + } + + .messages-text .highlight { + color: var(--accentlight); + font-family: var(--font-family-inter); + font-style: normal; + font-weight: var(--font-weight-medium); + letter-spacing: -0.02px; + } + } + + .result-item-postfix { + color: #b8c1cc; + font-family: var(--font-family-inter); + font-size: var(--font-size-s); + font-style: normal; + font-weight: var(--font-weight-medium); + height: auto; + letter-spacing: -0.14px; + line-height: 20px; + mix-blend-mode: normal; + text-align: right; + white-space: nowrap; + width: auto; + } + + .result-item-icon { + .result-item-icon-title { + line-height: 38pt; + font-size: 46pt; + } + + .result-item-icon-back { + height: 56px; + mix-blend-mode: normal; + position: absolute; + width: 56px; + visibility: visible; + border-radius: 50%; + background-size: cover; + background-position: center; + } + } + + //.result-item-channel-icon { + // .result-item-icon-title { + // line-height: 44pt; + // font-size: 20pt; + // padding-left: 16px; + // } + //} + } + } + } + + .search-results { + .result-items-channel { + padding: 4px; + display: flex; + flex-direction: row; + height: 110px; + border-bottom: 0.5px solid #ddd; + + -webkit-mask-image: linear-gradient(to right, black 92%, transparent 100%); + mask-image: linear-gradient(to right, black 92%, transparent 100%); + + .result-item { + margin-right: 4px; + cursor: pointer; + } + + .component-channel-avatar { + .channel-icon-wrapper { + transition: transform 0.15s; + } + } + + .component-channel-avatar:hover { + .channel-icon-wrapper { + transform: scale(1.1); + } + } + } + + .result-items-files { + display: flex; + flex-direction: column; + max-height: 520px; + + .result-item { + display: flex; + flex-direction: row; + margin-bottom: 10px; + padding-bottom: 5px; + border-bottom: 0.5px solid #ddd; + + .result-item-icon { + } + .result-item-info { + width: 100%; + margin-left: 10px; + .filename { + font-weight: 400; + font-size: 15px; + line-height: 20px; + letter-spacing: -0.272px; + color: #000000; + } + .details { + font-style: normal; + font-weight: 400; + font-size: 11px; + line-height: 14px; + letter-spacing: -0.192px; + color: #6d7885; + } + .sender { + margin-top: 2px; + font-style: normal; + font-weight: 400; + font-size: 12px; + line-height: 20px; + letter-spacing: -0.24px; + } + } + } + } + } + + .recent-results.tab-all { + .result-items-files { + max-height: 206px; + } + } + + .recent-results.tab-media { + .result-items-media { + flex-flow: row wrap; + height: 508px; + } + } +} diff --git a/twake/frontend/src/app/components/search-popup/search-popup.tsx b/twake/frontend/src/app/components/search-popup/search-popup.tsx new file mode 100755 index 00000000..54fdc23e --- /dev/null +++ b/twake/frontend/src/app/components/search-popup/search-popup.tsx @@ -0,0 +1,24 @@ +import { Modal, ModalContent } from '@atoms/modal'; +import Languages from 'app/features/global/services/languages-service'; +import { useSearchModal } from 'app/features/search/hooks/use-search'; +import { SearchInput } from './search-input'; +import { SearchResultsIndex } from './search-tabs'; + +export default () => { + const { open, setOpen } = useSearchModal(); + + return ( + setOpen(false)} className="sm:w-[80vw] sm:max-w-4xl"> + + + ); +}; + +const SearchBox = () => { + return ( + + + + + ); +}; diff --git a/twake/frontend/src/app/components/search-popup/search-tabs.tsx b/twake/frontend/src/app/components/search-popup/search-tabs.tsx new file mode 100755 index 00000000..bff1812a --- /dev/null +++ b/twake/frontend/src/app/components/search-popup/search-tabs.tsx @@ -0,0 +1,111 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import Tabs from '@molecules/tabs'; +import Languages from 'app/features/global/services/languages-service'; +import { useSearchChannels } from 'app/features/search/hooks/use-search-channels'; +import { + useSearchMessagesFiles, + useSearchMessagesMedias, +} from 'app/features/search/hooks/use-search-files-or-medias'; +import { useSearchMessages } from 'app/features/search/hooks/use-search-messages'; +import { useSearchDriveItems } from 'app/features/search/hooks/use-search-drive-items'; +import { SearchInputState, SearchTabsState } from 'app/features/search/state/search-input'; +import PerfectScrollbar from 'react-perfect-scrollbar'; +import { useRecoilState, useRecoilValue } from 'recoil'; +import SearchResultsAll from './tabs/all'; +import SearchResultsChannels from './tabs/channels'; +import SearchResultsFiles from './tabs/files'; +import SearchResultsMedias from './tabs/medias'; +import SearchResultsMessages from './tabs/messages'; +import SearchResulsDriveItems from './tabs/drive'; + +const orderedTabs = ['all', 'messages', 'medias', 'files', 'channels', 'drive']; + +export const SearchResultsIndex = () => { + const input = useRecoilValue(SearchInputState); + const hasInput = input?.query?.length > 0; + const [tab, setTab] = useRecoilState(SearchTabsState); + + const { messages } = useSearchMessages(); + const { files } = useSearchMessagesFiles(); + const { files: medias } = useSearchMessagesMedias(); + const { driveItems } = useSearchDriveItems(); + + return ( + <> + {Languages.t('components.searchpopup.all')}
, +
+
+ {Languages.t('components.searchpopup.messages')} + {hasInput && } +
+
, +
+
+ {Languages.t('components.searchpopup.media')} + {hasInput && } +
+
, +
+
+ {Languages.t('components.searchpopup.files')} + {hasInput && } +
+
, + .../*!input.channelId + ?*/ [ +
+ +
, + ], + /*: []*/ +
+
+ {Languages.t('components.searchpopup.drive')} + {hasInput && } +
+
, + ]} + selected={orderedTabs.indexOf(tab)} + onClick={idx => setTab(orderedTabs[idx] as any)} + /> + + + {tab === 'all' && } + {tab === 'messages' && } + {tab === 'medias' && } + {tab === 'files' && } + {tab === 'channels' && } + {tab === 'drive' && } + + + ); +}; + +const ChannelsTab = () => { + const input = useRecoilValue(SearchInputState); + const hasInput = input?.query?.length > 0; + const { channels } = useSearchChannels(); + + return ( +
+ {Languages.t('components.searchpopup.channels')} + {hasInput && } +
+ ); +}; + +const SearchCounterBadge = (props: { count: number }) => { + const count = props.count < 100 ? props.count : '99+'; + return ( +
+ {count} +
+ ); +}; diff --git a/twake/frontend/src/app/components/search-popup/tabs/all.tsx b/twake/frontend/src/app/components/search-popup/tabs/all.tsx new file mode 100644 index 00000000..6b5f4a3b --- /dev/null +++ b/twake/frontend/src/app/components/search-popup/tabs/all.tsx @@ -0,0 +1,117 @@ +import * as Text from '@atoms/text'; +import A from 'app/atoms/link'; +import Languages from 'app/features/global/services/languages-service'; +import { useSearchChannels } from 'app/features/search/hooks/use-search-channels'; +import { + useSearchMessagesFiles, + useSearchMessagesMedias, +} from 'app/features/search/hooks/use-search-files-or-medias'; +import { useSearchMessages } from 'app/features/search/hooks/use-search-messages'; +import { SearchInputState, SearchTabsState } from 'app/features/search/state/search-input'; +import { useRecoilValue, useSetRecoilState } from 'recoil'; +import { ChannelsResults, ChannelsRowResults } from './channels'; +import { FilesResults } from './files'; +import { MediasResults } from './medias'; +import { MessagesResults } from './messages'; + +export default () => { + const setTab = useSetRecoilState(SearchTabsState); + + const input = useRecoilValue(SearchInputState); + const isRecent = input?.query?.trim()?.length === 0; + + const { channels } = useSearchChannels(); + const { messages } = useSearchMessages(); + const { files } = useSearchMessagesFiles(); + const { files: medias } = useSearchMessagesMedias(); + + return ( +
+ {channels.length > 0 && ( + <> +
+ + {isRecent + ? Languages.t('components.searchpopup.recent_channels_and_contacts') + : Languages.t('components.searchpopup.channels')} + + {channels.length > 6 && ( + + )} +
+ {isRecent && ( +
+ +
+ )} + {!isRecent && ( +
+ +
+ )} + + )} + + {medias.length > 0 && ( + <> +
+ + {isRecent + ? Languages.t('components.searchpopup.recent_media') + : Languages.t('components.searchpopup.media')} + + {medias.length > 6 && ( + + )} +
+
+ +
+ + )} + + {files.length > 0 && ( + <> +
+ + {isRecent + ? Languages.t('components.searchpopup.recent_files') + : Languages.t('components.searchpopup.files')} + + {files.length > 6 && ( + + )} +
+
+ +
+ + )} + + {messages.length > 0 && ( + <> +
+ + {Languages.t('components.searchpopup.messages')} + +
+
+ +
+ + )} +
+ ); +}; diff --git a/twake/frontend/src/app/components/search-popup/tabs/channels.tsx b/twake/frontend/src/app/components/search-popup/tabs/channels.tsx new file mode 100644 index 00000000..cb3d9052 --- /dev/null +++ b/twake/frontend/src/app/components/search-popup/tabs/channels.tsx @@ -0,0 +1,87 @@ +import * as Text from '@atoms/text'; +import Languages from 'app/features/global/services/languages-service'; +import { useSearchChannels } from 'app/features/search/hooks/use-search-channels'; +import { SearchInputState } from 'app/features/search/state/search-input'; +import { useRecoilValue } from 'recoil'; +import ChannelLineResult from '../parts/channel-line-result'; +import ChannelResult from '../parts/channel-result'; +import NothingFound from '../parts/nothing-found'; + +export default () => { + const input = useRecoilValue(SearchInputState); + const isRecent = input?.query?.trim()?.length === 0; + const { channels, loading } = useSearchChannels(); + + if (channels.length === 0 && !loading) return ; + + const topChannels = channels + .slice() + .filter(a => Date.now() - (a.last_activity || 0) < 1000 * 60 * 60 * 24 * 31) + .sort((a, b) => Math.min(50, b?.stats?.messages || 0) - Math.min(50, a?.stats?.messages || 0)) + .slice(0, 5); + + return ( +
+ {!!isRecent && !!topChannels.length && ( +
+ + {Languages.t('components.searchpopup.recent_channels_and_contacts')} + + +
+ {topChannels.map(channel => ( +
+ +
+ ))} +
+
+ )} + + {!!isRecent && ( + + {Languages.t('components.searchpopup.channels')} + + )} +
+ +
+
+ ); +}; + +export const ChannelsRowResults = (props: { max?: number }) => { + const { channels, loading } = useSearchChannels(); + + if (channels.length === 0 && !loading) return ; + + return ( + <> + {channels.slice(0, props?.max || channels.length).map(channel => ( +
+ +
+ ))} + + ); +}; + +export const ChannelsResults = (props: { max?: number }) => { + const { channels, loading } = useSearchChannels(); + + if (channels.length === 0 && !loading) return ; + + return ( + <> + {channels.slice(0, props?.max || channels.length).map(channel => ( + + ))} + + ); +}; diff --git a/twake/frontend/src/app/components/search-popup/tabs/drive.tsx b/twake/frontend/src/app/components/search-popup/tabs/drive.tsx new file mode 100644 index 00000000..8b6dc2ea --- /dev/null +++ b/twake/frontend/src/app/components/search-popup/tabs/drive.tsx @@ -0,0 +1,43 @@ +import * as Text from '@atoms/text'; +import Languages from 'app/features/global/services/languages-service'; +import { useSearchDriveItems } from 'app/features/search/hooks/use-search-drive-items'; +import { SearchInputState } from 'app/features/search/state/search-input'; +import { useRecoilValue } from 'recoil'; +import DriveItemResult from '../parts/drive-item-result'; +import NothingFound from '../parts/nothing-found'; + +export default () => { + const input = useRecoilValue(SearchInputState); + const isRecent = input?.query?.trim()?.length === 0; + const { driveItems, loading } = useSearchDriveItems(); + + if (driveItems.length === 0 && !loading) return ; + + return ( +
+ {!!isRecent && ( + + {Languages.t('components.searchpopup.recent_files')} + + )} + +
+ +
+
+ ); +}; + +export const DriveItemsResults = (props: { max?: number }) => { + const { driveItems, loading } = useSearchDriveItems(); + + if (driveItems.length === 0 && !loading) return ; + + return ( + <> + {driveItems.slice(0, props?.max || driveItems.length).map(item => ( + + ))} + + ); +}; diff --git a/twake/frontend/src/app/components/search-popup/tabs/files.tsx b/twake/frontend/src/app/components/search-popup/tabs/files.tsx new file mode 100644 index 00000000..6a6d18cc --- /dev/null +++ b/twake/frontend/src/app/components/search-popup/tabs/files.tsx @@ -0,0 +1,43 @@ +import * as Text from '@atoms/text'; +import Languages from 'app/features/global/services/languages-service'; +import { useSearchMessagesFiles } from 'app/features/search/hooks/use-search-files-or-medias'; +import { SearchInputState } from 'app/features/search/state/search-input'; +import { useRecoilValue } from 'recoil'; +import FileResult from '../parts/file-result'; +import NothingFound from '../parts/nothing-found'; + +export default () => { + const input = useRecoilValue(SearchInputState); + const isRecent = input?.query?.trim()?.length === 0; + const { files, loading } = useSearchMessagesFiles(); + + if (files.length === 0 && !loading) return ; + + return ( +
+ {!!isRecent && ( + + {Languages.t('components.searchpopup.recent_files')} + + )} + +
+ +
+
+ ); +}; + +export const FilesResults = (props: { max?: number }) => { + const { files, loading } = useSearchMessagesFiles(); + + if (files.length === 0 && !loading) return ; + + return ( + <> + {files.slice(0, props?.max || files.length).map(file => ( + + ))} + + ); +}; diff --git a/twake/frontend/src/app/components/search-popup/tabs/medias.tsx b/twake/frontend/src/app/components/search-popup/tabs/medias.tsx new file mode 100644 index 00000000..76ce0373 --- /dev/null +++ b/twake/frontend/src/app/components/search-popup/tabs/medias.tsx @@ -0,0 +1,51 @@ +import * as Text from '@atoms/text'; +import FileUploadAPIClient from '@features/files/api/file-upload-api-client'; +import Languages from '@features/global/services/languages-service'; +import { useSearchMessagesMedias } from '@features/search/hooks/use-search-files-or-medias'; +import { SearchInputState } from '@features/search/state/search-input'; +import { useRecoilValue } from 'recoil'; +import FileResult from '../parts/file-result'; +import MediaResult from '../parts/media-result'; +import NothingFound from '../parts/nothing-found'; + +export default () => { + const input = useRecoilValue(SearchInputState); + const isRecent = input?.query?.trim()?.length === 0; + + return ( +
+ {!!isRecent && ( + + {Languages.t('components.searchpopup.recent_media')} + + )} + +
+ +
+
+ ); +}; + +export const MediasResults = (props: { max?: number; showAsFiles?: boolean }) => { + const { files, loading } = useSearchMessagesMedias(); + + if (files.length === 0 && !loading) return ; + + return ( + <> + {files + .slice(0, props?.max || files.length) + .map(file => { + const url = FileUploadAPIClient.getFileThumbnailUrlFromMessageFile(file); + if (url || props.showAsFiles) + return props.showAsFiles ? ( + + ) : ( + + ); + }) + .filter(a => a)} + + ); +}; diff --git a/twake/frontend/src/app/components/search-popup/tabs/messages.tsx b/twake/frontend/src/app/components/search-popup/tabs/messages.tsx new file mode 100644 index 00000000..8d5231de --- /dev/null +++ b/twake/frontend/src/app/components/search-popup/tabs/messages.tsx @@ -0,0 +1,41 @@ +import { SearchInputState } from '@features/search/state/search-input'; +import { useSearchMessages } from 'app/features/search/hooks/use-search-messages'; +import { useRecoilValue } from 'recoil'; +import MessageResult from '../parts/message-result'; +import NothingFound from '../parts/nothing-found'; +import NothingSearched from '../parts/nothing-searched'; + +export default () => { + return ( +
+
+ +
+
+ ); +}; + +export const MessagesResults = () => { + const input = useRecoilValue(SearchInputState); + const isRecent = input?.query?.trim()?.length === 0; + const { messages, loading } = useSearchMessages(); + + if (isRecent) return ; + if (messages.length === 0 && !loading) return ; + + return ( + <> +
+ {messages + .map(message => { + return ( +
+ +
+ ); + }) + .filter(a => a)} +
+ + ); +}; diff --git a/twake/frontend/src/app/components/select/select.jsx b/twake/frontend/src/app/components/select/select.jsx new file mode 100755 index 00000000..25f7094b --- /dev/null +++ b/twake/frontend/src/app/components/select/select.jsx @@ -0,0 +1,71 @@ +import React, { Component } from 'react'; + +import MenusManager from 'app/components/menus/menus-manager.jsx'; +import Icon from 'app/components/icon/icon.jsx'; +import './select.scss'; + +export default class Select extends React.Component { + constructor(props) { + super(); + this.props = props; + } + select(value) { + this.props.onChange(value); + } + openMenu(evt) { + var pos = window.getBoundingClientRect(this.node); + pos.x = pos.x || pos.left; + pos.y = pos.y || pos.top; + MenusManager.openMenu( + this.props.options.map(item => { + return { + type: item.type || 'menu', + text: item.text, + className: item.className, + icon: item.icon, + emoji: item.emoji, + reactElement: item.reactElement, + onClick: () => this.select(item.value), + }; + }), + { x: pos.x + pos.width / 2, y: pos.y + pos.height }, + 'bottom', + ); + } + render() { + var className = this.props.className || ''; + + if (this.props.big) { + className += ' big '; + } + if (this.props.medium) { + className += ' medium '; + } + if (this.props.small) { + className += ' small '; + } + + if ( + className.indexOf('medium') === className.indexOf('small') && + className.indexOf('big') === className.indexOf('small') && + className.indexOf('big') < 0 + ) { + className += ' small'; + } + + var current = + this.props.options.filter(item => { + return item.value == this.props.value; + })[0] || {}; + + return ( +
(this.node = node)} + className={'select ' + className} + onClick={evt => this.openMenu(evt)} + > + {current.icon && } {current.text || current.title || '-'} +
+ ); + } +} diff --git a/twake/frontend/src/app/components/select/select.scss b/twake/frontend/src/app/components/select/select.scss new file mode 100755 index 00000000..c7dd387f --- /dev/null +++ b/twake/frontend/src/app/components/select/select.scss @@ -0,0 +1,39 @@ +.select { + box-sizing: border-box; + width: auto; + vertical-align: middle; + background-color: var(--grey-background); + border: 0px; + text-overflow: ellipsis; + padding-right: 24px; + overflow: hidden; + white-space: nowrap; + + &.full_width { + width: 100%; + } + + &.small { + height: 32px; + line-height: 32px; + padding: 0 8px; + padding-right: 32px; + font-size: 14px; + } + + &.medium { + height: 40px; + line-height: 40px; + padding: 0 12px; + padding-right: 32px; + font-size: 16px; + } + + &.big { + height: 64px; + font-size: 18px; + line-height: 64px; + padding: 0 24px; + padding-right: 40px; + } +} diff --git a/twake/frontend/src/app/components/step-counter/step-counter.jsx b/twake/frontend/src/app/components/step-counter/step-counter.jsx new file mode 100755 index 00000000..b78e96f6 --- /dev/null +++ b/twake/frontend/src/app/components/step-counter/step-counter.jsx @@ -0,0 +1,37 @@ +import React, { Component } from 'react'; + +import './step-counter.scss'; + +export default class StepCounter extends React.Component { + /* + props : { + current : int + total : int + } + */ + constructor() { + super(); + } + displayStep() { + var ret = []; + for (var i = 0; i < this.props.total; i++) { + ret.push( +
, + ); + } + return ret; + } + render() { + return ( +
+ {this.displayStep().map(item => { + return item; + })} +
+ ); + } +} diff --git a/twake/frontend/src/app/components/step-counter/step-counter.scss b/twake/frontend/src/app/components/step-counter/step-counter.scss new file mode 100755 index 00000000..f31a32a7 --- /dev/null +++ b/twake/frontend/src/app/components/step-counter/step-counter.scss @@ -0,0 +1,18 @@ +.stepCounter { + display: flex; + width: 100%; + display: flex; + margin: auto; + margin-bottom: 24px; + .step { + height: 8px; + background: black; + border-radius: var(--border-radius-base); + margin: 0px 5px; + background: var(--primary-background); + transition: background 0.2s; + } + .setSelected { + background: var(--primary); + } +} diff --git a/twake/frontend/src/app/components/table/table.scss b/twake/frontend/src/app/components/table/table.scss new file mode 100755 index 00000000..7feb9aaf --- /dev/null +++ b/twake/frontend/src/app/components/table/table.scss @@ -0,0 +1,98 @@ +rm .table { + overflow: hidden; + border-radius: var(--border-radius-base); + margin-bottom: 16px; + border: 1px solid var(--grey-background); + font-weight: 500; + + &.unfocused { + box-shadow: none; + } + + &.loading { + opacity: 0.5; + + .tr .item .line { + pointer-events: none; + border-radius: var(--border-radius-large); + height: 16px; + margin-top: 8px; + width: 200px; + animation-duration: 1s; + animation-fill-mode: forwards; + animation-iteration-count: infinite; + animation-name: placeHolderShimmer; + animation-timing-function: linear; + background-repeat: repeat !important; + background-image: linear-gradient( + to right, + var(--grey-light) 0px, + #f2f2f2 120px, + var(--grey-light) 234px + ) !important; + + & > * { + opacity: 0 !important; + } + } + } + + .headerTable { + background: var(--grey-background); + font-weight: 700; + font-size: 14px; + display: flex; + padding: 8px; + border-bottom: 1px solid var(--grey-background); + } + + .footerTable { + text-align: center; + line-height: 32px; + font-size: 14px; + padding: 5px 10px; + border-top: 1px solid var(--grey-background); + border-bottom: 1px solid var(--grey-background); + } + .contentTable { + .tr { + display: flex; + border-bottom: 1px solid var(--grey-background); + padding: 8px; + font-size: 12px; + + &:hover { + background: var(--grey-background); + } + + &:last-child { + border-bottom: none; + } + + & > div { + position: relative; + min-height: 32px; + + & > .absolute_position { + width: 100%; + position: absolute; + height: 100%; + display: flex; + } + } + } + + .fix_text_padding_medium { + padding: 8px 0; + display: inline-block; + line-height: 18px; + } + + .text-complete-width { + overflow: hidden; + flex: 1; + white-space: nowrap; + text-overflow: ellipsis; + } + } +} diff --git a/twake/frontend/src/app/components/table/table.tsx b/twake/frontend/src/app/components/table/table.tsx new file mode 100755 index 00000000..a1660bd5 --- /dev/null +++ b/twake/frontend/src/app/components/table/table.tsx @@ -0,0 +1,243 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable jsx-a11y/anchor-is-valid */ +import React, { Component } from 'react'; +import Languages from 'app/features/global/services/languages-service'; +import Button from 'components/buttons/button.jsx'; +import InputIcon from 'components/inputs/input-icon.jsx'; +import './table.scss'; + +type Props = { + column?: any; + noHeader: boolean; + onAdd: () => void; + onRequestMore: (refresh: boolean) => Promise; + onSearch: (query: string, maxResults: number, callback: (res: any[]) => void) => Promise; + updatedData: (data: any) => any; + addText?: string; + resultsPerPage?: number; + unFocused: boolean; +}; +type State = { + data: null | any[]; + searchResults: any[]; + loading: boolean; + has_more: boolean; + page: number; + searching: boolean; +}; + +export default class Table extends Component { + searchFieldValue = ''; + searchRunning = false; + searchRunningTimeout: number | null = null; + + constructor(props: Props) { + super(props); + this.state = { + data: null, + searchResults: [], + loading: true, + has_more: true, + page: 0, + searching: false, + }; + Languages.addListener(this); + } + + componentWillUnmount() { + Languages.removeListener(this); + } + + componentDidMount() { + if (this.state.data === null) { + this.requestMore(true); + } + } + + search() { + if (this.searchFieldValue?.length <= 2) { + return false; + } + if (this.searchRunning) { + clearTimeout(this.searchRunningTimeout as number); + this.searchRunningTimeout = window.setTimeout(() => { + this.search(); + }, 1000); + return; + } + + this.setState({ + loading: true, + }); + + this.searchRunning = true; + this.props.onSearch(this.searchFieldValue, 10, (data: any[]) => { + this.searchRunning = false; + this.setState({ + loading: false, + searchResults: data, + }); + }); + } + + renderItem(col: any, item: any) { + if (col.render) { + return col.render(item); + } else { + return
{col.dataIndex ? item[col.dataIndex] : ''}
; + } + } + + requestMore(refresh = false) { + this.setState({ loading: true }); + this.props.onRequestMore(refresh).then(res => { + const hasMore = res.length !== (this.state.data || []).length; + this.setState({ loading: false, data: res, has_more: hasMore }); + }); + } + + setPosition() { + if (!!this.props.onSearch && !this.props.onAdd) return 'flex-end'; + else return 'space-between'; + } + + nextPage() { + this.setState({ page: this.state.page + 1 }); + if (this.getPageData().length < (this.state.page + 1) * this.getResultsPerPage()) { + this.requestMore(); + } + } + + getPageData() { + const from = this.state.page * this.getResultsPerPage(); + return (this.state.data || []).slice(0, from + this.getResultsPerPage()); + } + + getResultsPerPage(): number { + return this.props.resultsPerPage || 50; + } + + render() { + let page_data = this.state.searching ? this.state.searchResults : this.getPageData(); + page_data = page_data + .map(data => { + data = this.props.updatedData ? this.props.updatedData(data) : data; + if (!data) { + return false; + } + return data; + }) + .filter(i => i); + + return ( +
+
+ {this.props.onAdd && ( +
+ +
+ {!this.props.noHeader && ( +
+ {this.props.column.map((col: any, i: number) => { + return ( +
+ {col.title} +
+ ); + })} +
+ )} +
+ {(page_data || []).length === 0 && !this.state.loading && ( +
+
+ {Languages.t('components.user_picker.modal_no_result')} +
+
+ )} + {(page_data || []).length === 0 && + !!this.state.loading && + Array(this.state.searching ? 1 : this.getResultsPerPage()).map((_, i: number) => { + return ( +
+
+
+
+
+ ); + })} + {(page_data || []).map((data: any, i: number) => { + return ( +
+ {this.props.column.map((col: any, j: number) => { + return ( +
+ {this.renderItem(col, data)} +
+ ); + })} +
+ ); + })} +
+ {!this.state.searching && + !!this.state.has_more && + page_data.length >= this.getResultsPerPage() && ( + + )} +
+
+ ); + } +} diff --git a/twake/frontend/src/app/components/tabs/tabs.jsx b/twake/frontend/src/app/components/tabs/tabs.jsx new file mode 100755 index 00000000..b02fbfd3 --- /dev/null +++ b/twake/frontend/src/app/components/tabs/tabs.jsx @@ -0,0 +1,69 @@ +/* eslint-disable react/jsx-key */ +import React, { Component } from 'react'; + +import Languages from 'app/features/global/services/languages-service'; +import PerfectScrollbar from 'react-perfect-scrollbar'; +import './tabs.scss'; + +export default class Tabs extends Component { + constructor(props) { + super(props); + this.state = { + i18n: Languages, + tab: props.selected, + }; + Languages.addListener(this); + } + componentWillUnmount() { + Languages.removeListener(this); + } + select(i) { + this.setState({ tab: i }); + this.props.onChange && this.props.onChange(i); + } + UNSAFE_componentWillUpdate(nextProps, nextState) { + if (nextProps.selected && JSON.stringify(nextProps.selected) != this.oldSelected) { + nextState.tab = nextProps.selected; + this.oldSelected = JSON.stringify(nextProps.selected); + } + } + render() { + var selected = this.state.tab || Object.keys(this.props.tabs || {})[0]; + if (!this.props.tabs[selected]) { + selected = Object.keys(this.props.tabs || {})[0]; + } + + return ( +
+ + {Object.keys(this.props.tabs || {}).map(i => { + var item = this.props.tabs[i]; + return ( +
this.select(i)} + > + {typeof item.title == 'function' ? item.title() : item.title} +
+ ); + })} +
+
+ {typeof this.props.tabs[selected].render == 'function' + ? this.props.tabs[selected].render() + : this.props.tabs[selected].render} +
+
+ ); + } +} diff --git a/twake/frontend/src/app/components/tabs/tabs.scss b/twake/frontend/src/app/components/tabs/tabs.scss new file mode 100755 index 00000000..e38981db --- /dev/null +++ b/twake/frontend/src/app/components/tabs/tabs.scss @@ -0,0 +1,58 @@ +.component_tabs { + position: relative; + overflow: hidden; + + &::before { + content: ''; + position: relative; + right: 0px; + left: auto; + top: 0px; + height: 100%; + width: 50px; + z-index: 1; + pointer-events: none; + background: linear-gradient(to right, #ffffff00 0%, #ffffffff 100%); + } + + & > .component_tabs_tabs { + border-bottom: 1px solid var(--grey-background); + padding: 0 16px; + white-space: nowrap; + max-width: 100%; + box-sizing: border-box; + + .component_tabs_tab { + height: 40px; + box-sizing: border-box; + border-radius: 0; + display: inline-block; + padding: 8px 16px; + font-weight: 500; + color: var(--grey-dark); + font-size: 14px; + cursor: pointer; + + &:hover { + background: transparent; + color: var(--black); + } + + &.selected { + background: transparent; + border-bottom: 4px solid var(--primary); + color: var(--black); + } + } + } + & > .body { + padding: 16px; + } + + &.full-body { + & > .body, + & > .component_tabs_tabs { + padding: 0px; + } + } +} diff --git a/twake/frontend/src/app/components/tag-picker/tag-picker.jsx b/twake/frontend/src/app/components/tag-picker/tag-picker.jsx new file mode 100755 index 00000000..90fb2da1 --- /dev/null +++ b/twake/frontend/src/app/components/tag-picker/tag-picker.jsx @@ -0,0 +1,196 @@ +/* eslint-disable react/jsx-key */ +/* eslint-disable react/no-direct-mutation-state */ +import React, { Component } from 'react'; +import Icon from 'app/components/icon/icon.jsx'; +import Button from 'components/buttons/button.jsx'; +import './tag-picker.scss'; +import MenusManager from 'app/components/menus/menus-manager.jsx'; +import TagSelector from './tag-selector.jsx'; +import Workspaces from 'app/deprecated/workspaces/workspaces.jsx'; +import Collections from 'app/deprecated/CollectionsV1/Collections/Collections.js'; +import Languages from 'app/features/global/services/languages-service'; + +export default class TagPicker extends React.Component { + constructor(props) { + super(); + this.props = props; + this.state = { + currentSelected: [], + inputValue: '', + currentList: [], + selected: [], + value: this.props.value || [], + list: props.data || [ + { id: 1, name: Languages.t('scenes.apps.tasks.task_status.todo', [], 'To do') }, + { id: 2, name: Languages.t('scenes.apps.tasks.task_status.current', [], 'Doing') }, + { id: 3, name: Languages.t('scenes.apps.tasks.task_status.done', [], 'Done') }, + ], + }; + } + UNSAFE_componentWillUpdate(nextProps, nextState) { + if (JSON.stringify(nextProps.value) != JSON.stringify(this.props.value)) { + this.state.value = nextProps.value; + } + } + UNSAFE_componentWillMount() { + if (!this.props.data) { + Collections.get('tags').addListener(this); + Collections.get('tags').addSource( + { + http_base_url: 'globalsearch/tags', + http_options: { + workspace_id: Workspaces.currentWorkspaceId, + }, + websockets: [{ uri: 'tags/' + Workspaces.currentWorkspaceId, options: { type: 'tags' } }], + }, + Workspaces.currentWorkspaceId, + ); + } + } + componentWillUnmount() { + if (!this.props.data) { + Collections.get('tags').removeListener(this); + } + } + addTags(evt) { + var menu = [ + { + type: 'react-element', + reactElement: level => { + return ( + { + if (typeof a == 'string') { + return { name: a, id: a, color: '#888' }; + } else { + return a; + } + }) + : false + } + canCreate={this.props.canCreate} + disabledTags={ + this.state.value.map(item => { + return typeof item == 'string' ? item : item.id; + }) || [] + } + onChange={value => { + value.forEach(tag => { + if ( + this.state.value + .map(item => { + return typeof item == 'string' ? item : item.id; + }) + .indexOf(tag.id || tag.name || tag) < 0 + ) { + this.state.value.push(tag.id || tag.name || tag); + } + }); + if (!this.props.saveButton) this.props.onChange(this.state.value); + this.setState({}); + if (this.props.menu_level !== undefined) { + MenusManager.closeSubMenu(this.props.menu_level); + } else { + MenusManager.closeMenu(); + } + }} + /> + ); + }, + }, + ]; + if (this.props.menu_level !== undefined) { + MenusManager.openSubMenu( + menu, + { x: evt.clientX, y: evt.clientY }, + this.props.menu_level, + 'right', + ); + } else { + MenusManager.openMenu(menu, { x: evt.clientX, y: evt.clientY }, 'right'); + } + } + render() { + var value = this.state.value || []; + + var tag_list = value.map(tag_id => { + var tag = false; + if (this.props.data) { + if (typeof tag_id == 'string') { + tag = { name: tag_id, id: tag_id, color: '#888' }; + } else { + tag = tag_id; + tag.id = tag.id || tag.name; + tag.color = tag.color || '#888'; + } + } else { + tag = Collections.get('tags').find(tag_id); + } + if (!tag) { + return ''; + } + var name = tag.name; + return ( +
+ {name}{' '} + {!this.props.readOnly && ( + { + this.state.value.splice(this.state.value.indexOf(tag.id), 1); + if (!this.props.saveButton) this.props.onChange(this.state.value); + this.setState({}); + }} + /> + )} +
+ ); + }); + + if (this.props.inline) { + return tag_list; + } + + return ( +
+ {!this.props.readOnly && value.length == 0 && ( +
{Languages.t('components.tagpicker.notag', [], 'No tag')}
+ )} + + {tag_list} + + {!this.props.readOnly && ( + + )} + + {this.props.saveButton && ( +
+
+ )} +
+ ); + } +} diff --git a/twake/frontend/src/app/components/tag-picker/tag-picker.scss b/twake/frontend/src/app/components/tag-picker/tag-picker.scss new file mode 100755 index 00000000..b8856f8f --- /dev/null +++ b/twake/frontend/src/app/components/tag-picker/tag-picker.scss @@ -0,0 +1,104 @@ +.tagPicker .tag, +.inline-tag { + height: 22px; + border-radius: var(--border-radius-base); + background: var(--grey-dark); + color: #fff; + line-height: 22px; + vertical-align: top; + margin-bottom: 8px; + margin-right: 8px; + font-size: 12px; + font-weight: bold; + padding: 0 4px; + padding-left: 6px; + + &.notag { + background: var(--grey-background); + color: var(--grey-dark); + } + + .remove { + opacity: 0.5; + cursor: pointer; + &:hover { + opacity: 1; + } + } + .remove:before { + margin: 0px; + } + + &.disabled { + opacity: 0.5; + } +} + +.tagPicker { + .tag_selectable { + display: flex; + .tag_part { + flex: 1; + } + .edit { + } + } + + .secondary-text { + height: 22px; + line-height: 22px; + } + + &.disabled { + opacity: 0.5; + pointer-events: none; + } + + .pickerInput { + padding-left: 5px; + + &.readOnly { + padding-left: 0px; + } + } + .itemSelected { + display: inline-block; + .close { + font-size: 8px; + margin-left: 5px; + opacity: 0.4; + display: inline-block; + margin-right: -1px; + bottom: 0px; + position: relative; + } + .close:hover { + opacity: 0.8; + cursor: pointer; + } + } + .itemContoured { + padding: 1px 6px; + display: inline-block; + background-color: var(--primary); + box-sizing: border-box; + color: #fff; + border-radius: var(--border-radius-base); + margin: 5px 0px; + margin-right: 5px; + height: 18px; + line-height: 16px; + font-size: 12px; + } + .menu { + .itemContoured { + margin: 3px 0; + } + } +} + +.inline-tag { + display: inline-block; + margin-bottom: 0px; + vertical-align: middle; +} diff --git a/twake/frontend/src/app/components/tag-picker/tag-selector.jsx b/twake/frontend/src/app/components/tag-picker/tag-selector.jsx new file mode 100755 index 00000000..63ed8d32 --- /dev/null +++ b/twake/frontend/src/app/components/tag-picker/tag-selector.jsx @@ -0,0 +1,220 @@ +/* eslint-disable react/no-direct-mutation-state */ +import React, { Component } from 'react'; +import Picker from 'components/picker/picker.jsx'; +import Button from 'components/buttons/button.jsx'; +import Workspaces from 'app/deprecated/workspaces/workspaces.jsx'; +import Collections from 'app/deprecated/CollectionsV1/Collections/Collections.js'; +import Icon from 'app/components/icon/icon.jsx'; +import ColorPicker from 'components/color-picker/color-picker.jsx'; +import Strings from 'app/features/global/utils/strings'; +import InputWithColor from 'components/inputs/input-with-color.jsx'; +import AlertManager from 'app/features/global/services/alert-manager-service'; +import Languages from 'app/features/global/services/languages-service'; +import MenusManager from 'app/components/menus/menus-manager.jsx'; + +class TagEditor extends React.Component { + constructor(props) { + super(); + this.props = props; + this.state = { + edited_tag_name: '', + edited_tag_color: '', + }; + } + UNSAFE_componentWillMount() { + var tag = this.props.tag; + this.state.edited_tag_color = tag.color; + this.state.edited_tag_name = tag.name; + } + saveTag(tag) { + tag.color = this.state.edited_tag_color || tag.color; + tag.name = this.state.edited_tag_name || tag.name; + Collections.get('tags').save(tag, Workspaces.currentWorkspaceId); + MenusManager.closeSubMenu(this.props.level - 1); + } + render() { + var tag = this.props.tag; + return ( +
+ { + this.saveTag(tag); + }} + onChange={value => { + this.setState({ edited_tag_color: value[0], edited_tag_name: value[1] }); + }} + /> +
+
+
+ ); + } +} + +export default class TagSelector extends React.Component { + constructor(props) { + super(); + this.props = props; + this.state = { + edited_tag_name: '', + edited_tag_color: '', + }; + + this.colors_random_list = ColorPicker.colors.map(a => a).sort(() => Math.random() - 0.5); + this.next_new_color = 0; + } + onUpdate(item) {} + onCreate(text, cb) { + var color = this.colors_random_list[this.next_new_color]; + this.next_new_color = (this.next_new_color + 1) % this.colors_random_list.length; + + var new_tag = Collections.get('tags').edit(); + new_tag.name = text; + new_tag.color = color; + new_tag.workspace_id = Workspaces.currentWorkspaceId; + Collections.get('tags').save(new_tag, Workspaces.currentWorkspaceId, tag => { + cb(new_tag); + }); + + return new_tag; + } + onRemove(item, ev) {} + renderItemChoosen(item) { + return ''; + } + editTag(evt, id) { + var tag = Collections.get('tags').find(id); + if (!tag) { + return; + } + var menu = [ + { type: 'title', text: Languages.t('general.edit') }, + { + type: 'react-element', + reactElement: level => { + return ; + }, + }, + { type: 'separator' }, + { + text: Languages.t('general.remove'), + className: 'error', + icon: 'trash', + onClick: ev => { + var tag = Collections.get('tags').find(id); + if (tag) { + AlertManager.confirm(() => { + MenusManager.closeSubMenu(this.props.level - 1); + Collections.get('tags').remove(tag, Workspaces.currentWorkspaceId); + }); + } + return false; + }, + }, + ]; + MenusManager.openSubMenu(menu, { x: evt.clientX, y: evt.clientY }, this.props.level, 'right'); + } + renderItem(item) { + var add_option = false; + if (typeof item == 'string') { + add_option = true; + item = { name: item, color: this.colors_random_list[this.next_new_color] }; + } + var tag = ( +
= 0 ? 'disabled' : '') + } + style={{ backgroundColor: item.color, margin: '5px 0' }} + > + {item.name} +
+ ); + + if (add_option) { + return tag; + } + + return ( +
+
{tag}
+ {!add_option && !this.props.data && ( +
{ + ev.stopPropagation(); + ev.preventDefault(); + this.editTag(ev, item.id); + }} + > + +
+ )} +
+ ); + } + search(text, cb) { + var res = Collections.get('tags').findBy({ workspace_id: Workspaces.currentWorkspaceId }); + if (this.props.data) { + res = this.props.data; + } + + res = res + .filter(function (item) { + if ( + Strings.removeAccents(item.name.toLowerCase().replace(/ +/, '')).indexOf( + Strings.removeAccents(text.toLowerCase().replace(/ +/, '')), + ) !== -1 + ) { + return true; + } + return false; + }) + .sort((a, b) => { + return this.props.disabledTags.indexOf(a.id) >= 0 ? -1 : 1; + }); + cb(res); + } + render() { + return ( + { + this.picker = picker; + }} + title={false} + search={(text, cb) => { + this.search(text, cb); + }} + renderItem={item => { + return this.renderItem(item); + }} + renderItemChoosen={item => { + return this.renderItemChoosen(item); + }} + renderItemSimply={item => { + return item.name; + }} + canCreate={this.props.canCreate !== false} + onCreate={(text, cb) => this.onCreate(text, cb)} + onSelect={item => this.onSelect(item)} + onChange={this.props.onChange} + value={this.props.value} + readOnly={this.props.readOnly} + inline={this.props.inline} + /> + ); + } +} diff --git a/twake/frontend/src/app/components/task-picker/task-picker.jsx b/twake/frontend/src/app/components/task-picker/task-picker.jsx new file mode 100755 index 00000000..189de0d6 --- /dev/null +++ b/twake/frontend/src/app/components/task-picker/task-picker.jsx @@ -0,0 +1,255 @@ +/* eslint-disable react/jsx-key */ +import React, { Component } from 'react'; +import Workspaces from 'app/deprecated/workspaces/workspaces.jsx'; +import Button from 'components/buttons/button.jsx'; +import Languages from 'app/features/global/services/languages-service'; +import Collections from 'app/deprecated/CollectionsV1/Collections/Collections.js'; +import Emojione from 'components/emojione/emojione'; +import Loader from 'components/loader/loader.jsx'; +import TasksService from 'app/deprecated/Apps/Tasks/Tasks.js'; +import LeftIcon from '@material-ui/icons/KeyboardArrowLeftOutlined'; + +import './task-picker.scss'; + +export default class TaskPicker extends Component { + /* + props : { + mode : "select_board" / "select_task" + } + */ + + constructor(props) { + super(props); + this.tasks_collection_key = 'tasks_picker_' + Workspaces.currentWorkspaceId; + this.collection_key = []; + + this.state = { + taskRepository: Collections.get('task'), + currentBoard: null, + currentList: null, + taskSelected: null, + boardRepository: Collections.get('boards'), + }; + Languages.addListener(this); + Collections.get('boards').addListener(this); + Collections.get('lists').addListener(this); + Collections.get('tasks').addListener(this); + Collections.get('boards').addSource( + { + http_base_url: 'tasks/board', + http_options: { + workspace_id: Workspaces.currentWorkspaceId, + }, + websockets: [ + { uri: 'boards/' + Workspaces.currentWorkspaceId, options: { type: 'board' } }, + ], + }, + this.tasks_collection_key, + ); + } + componentWillUnmount() { + Languages.removeListener(this); + Collections.get('boards').removeSource(this.tasks_collection_key); + Collections.get('lists').removeSource(this.tasks_collection_key); + Collections.get('tasks').removeSource(this.tasks_collection_key); + Collections.get('boards').removeListener(); + Collections.get('lists').removeListener(); + Collections.get('tasks').removeListener(); + } + selectBoard(board) { + if (this.collection_key.indexOf(this.tasks_collection_key + '_' + board.id) < 0) { + this.collection_key.push(this.tasks_collection_key + '_' + board.id); + Collections.get('lists').addSource( + { + http_base_url: 'tasks/list', + http_options: { + board_id: board.id, + }, + websockets: [{ uri: 'board_lists/' + board.id, options: { type: 'list' } }], + }, + this.tasks_collection_key + '_' + board.id, + ); + Collections.get('tasks').addSource( + { + http_base_url: 'tasks/task', + http_options: { + board_id: board.id, + }, + websockets: [{ uri: 'board_tasks/' + board.id, options: { type: 'task' } }], + }, + this.tasks_collection_key + '_' + board.id + '_tasks', + ); + } + this.setState({ currentBoard: board }); + } + selectList(list) { + this.setState({ currentList: list }); + } + selectTask(task) { + this.setState({ taskSelected: task }); + } + submit() { + if (this.props.mode === 'select_task' && this.state.taskSelected) { + if (this.props.onChoose) { + this.props.onChoose(this.state.taskSelected); + } + } + } + renderBoardPicker() { + var boards = Collections.get('boards').findBy({ workspace_id: Workspaces.currentWorkspaceId }); + var loading = + !Collections.get('boards').did_load_first_time[this.tasks_collection_key] && + boards.length === 0; + return ( +
+ {loading && ( +
+ +
+ )} + {!loading && + boards.map(board => { + return ( +
this.selectBoard(board)}> +
+ {board.emoji && ( + + )} +
{board.title}
+
+
+ ); + })} +
+ ); + } + renderListPicker() { + var loading = + !Collections.get('lists').did_load_first_time[ + this.tasks_collection_key + '_' + this.state.currentBoard.id + ]; + var lists = Collections.get('lists').findBy({ board_id: this.state.currentBoard.id }); + return ( +
+ {loading && ( +
+ +
+ )} + {!loading && + lists + .sort( + (a, b) => + TasksService.getElementIndex(a, 'lists_' + a.board_id) - + TasksService.getElementIndex(b, 'lists_' + b.board_id), + ) + .map((item, index) => { + return ( +
{ + this.selectList(item); + }} + > +
+
{item.title}
+
+ ); + })} +
+ ); + } + renderTaskPicker() { + var loading = + !Collections.get('tasks').did_load_first_time[ + this.tasks_collection_key + '_' + this.state.currentBoard.id + '_tasks' + ]; + var tasks = Collections.get('tasks').findBy({ + board_id: this.state.currentBoard.id, + list_id: this.state.currentList.id, + archived: false, + }); + return ( +
+ {loading && ( +
+ +
+ )} + {!loading && + (tasks || []) + .sort( + (a, b) => + TasksService.getElementIndex(a, 'tasks_' + a.list_id) - + TasksService.getElementIndex(b, 'tasks_' + b.list_id), + ) + .map((item, index) => ( +
{ + this.selectTask(item); + }} + > +
{item.title}
+
+ ))} +
+ ); + } + render() { + return ( +
+ {!this.state.currentBoard && ( +
{Languages.t('scenes.apps.tasks.task')}
+ )} + {this.state.currentBoard && !this.state.currentList && ( +
+ { + Collections.get('lists').removeListener(); + this.setState({ currentBoard: null }); + }} + /> + {this.state.currentBoard.title} +
+ )} + {this.state.currentBoard && this.state.currentList && ( +
+ { + Collections.get('tasks').removeListener(); + this.setState({ currentList: null }); + }} + /> + {this.state.currentBoard.title} - {this.state.currentList.title} +
+ )} +
+ {!this.state.currentBoard && this.renderBoardPicker()} + {this.state.currentBoard && !this.state.currentList && this.renderListPicker()} + {this.state.currentBoard && this.state.currentList && this.renderTaskPicker()} +
+
+ {this.props.mode === 'select_task' && + this.state.taskSelected && + this.state.taskSelected.id && ( +
+
+ ); + } +} diff --git a/twake/frontend/src/app/components/task-picker/task-picker.scss b/twake/frontend/src/app/components/task-picker/task-picker.scss new file mode 100755 index 00000000..494d8ed0 --- /dev/null +++ b/twake/frontend/src/app/components/task-picker/task-picker.scss @@ -0,0 +1,76 @@ +.taskPicker { + position: relative; + .title { + background: #ffffff; + margin-bottom: 0px; + font-size: 16px; + color: #000; + line-height: 20px; + padding-bottom: 8px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + .getback { + background: var(--grey-background); + border-radius: var(--border-radius-base); + width: 20px; + height: 20px; + vertical-align: top; + margin-right: 5px; + margin-left: 0px; + cursor: pointer; + } + } + .list { + height: 150px; + overflow: auto; + width: 100%; + .loading { + position: absolute; + margin: auto; + width: 50px; + height: 50px; + right: 0px; + bottom: 0px; + top: 0px; + left: 0px; + } + .picker_item { + display: flex; + flex-direction: row; + padding-left: 8px; + padding-right: 8px; + bottom: 0px; + color: var(--black); + height: 40px; + font-weight: 500; + width: 100%; + box-sizing: border-box; + border-top: 1px solid var(--grey-background); + font-size: 14px; + cursor: pointer; + .text { + display: inline-block; + line-height: 40px; + margin-left: 6px; + } + .board_emoji_picker { + vertical-align: top; + line-height: 40px; + } + .colorBloc { + height: 30px; + width: 4px; + margin-top: 5px; + } + } + .picker_item:hover { + background: var(--primary-background); + border-color: #fff; + } + .is_selected { + background: var(--primary); + color: #fff; + } + } +} diff --git a/twake/frontend/src/app/components/tooltip/tooltip.jsx b/twake/frontend/src/app/components/tooltip/tooltip.jsx new file mode 100755 index 00000000..dd31d61f --- /dev/null +++ b/twake/frontend/src/app/components/tooltip/tooltip.jsx @@ -0,0 +1,113 @@ +import React, { Component } from 'react'; + +import './tooltip.scss'; + +export default class Tooltip extends Component { + /* + props = { + tooltip : text or react element to show + visible : + overable : default : true + position : + } + */ + constructor(props) { + super(props); + this.state = { + top: 'unset', + left: 'unset', + right: 'unset', + bottom: '0px', + }; + } + componentWillUnmount() {} + componentDidUpdate(prevProps, prevState) { + if (this.props.visible === true && prevProps.visible === false) { + this.open(); + } else if (this.props.visible === false && prevProps.visible === true) { + this.close(); + } + } + openWithTimeOut(timeout = 5) { + var that = this; + that.open(); + setTimeout(() => { + that.close(); + }, timeout * 1000); + } + open() { + if (this.props.position === 'left') { + this.setState({ + visible: true, + left: (this.tooltip.clientWidth + 8) * -1 + 'px', + right: 'unset', + }); + } else if (this.props.position === 'right') { + this.setState({ + visible: true, + right: (this.tooltip.clientWidth + 8) * -1 + 'px', + left: 'unset', + }); + } else if (this.props.position === 'bottom') { + this.setState({ + visible: true, + bottom: (this.tooltip.clientHeight + 5) * -1 + 'px', + top: 'unset', + }); + } else { + this.setState({ + visible: true, + top: (this.tooltip.clientHeight + 5) * -1 + 'px', + bottom: 'unset', + }); + } + } + close() { + this.setState({ visible: false, top: 'unset', left: '0px', right: 'unset', bottom: '0px' }); + } + componentDidMount() { + var that = this; + if (this.parent && this.children) { + window.tooltip = this.tooltip; + this.parent.addEventListener('mouseenter', () => { + if (this.props.overable !== false) { + that.open(); + } + }); + this.parent.addEventListener('mouseleave', () => { + if (this.props.overable !== false) { + that.close(); + } + }); + } + } + render() { + return ( +
(this.parent = parent)} + > +
(this.tooltip = obj)} + > + {this.props.tooltip} +
+
(this.children = children)}> + {this.props.children} +
+
+ ); + } +} diff --git a/twake/frontend/src/app/components/tooltip/tooltip.scss b/twake/frontend/src/app/components/tooltip/tooltip.scss new file mode 100755 index 00000000..4c6c5918 --- /dev/null +++ b/twake/frontend/src/app/components/tooltip/tooltip.scss @@ -0,0 +1,68 @@ +.tooltip { + position: relative; + display: inline-block; + width: 100%; + font-size: 14px; + font-weight: 500; + .tooltipAbsolute { + position: absolute; + opacity: 0; + z-index: -1; + background: black; + color: white; + border-bottom: 1px dotted black; + padding: 5px 10px; + border-radius: var(--border-radius-base); + text-align: center; + font-size: 12px; + line-height: 16px; + } + .tooltipAbsolute::after { + content: ''; + position: absolute; + border-width: 5px; + border-style: solid; + } + .right, + .left { + top: 50% !important; + transform: translateY(-50%); + } + .top, + .bottom { + left: 50% !important; + transform: translateX(-50%); + } + .top::after { + left: calc(50% - 5px); + top: 100%; + border-color: black transparent transparent transparent; + } + .right::after { + left: -10px; + border-color: transparent black transparent transparent; + top: calc(50% - 5px); + margin-top: -5px; + } + .bottom::after { + bottom: 100%; + border-color: transparent transparent black transparent; + left: calc(50% - 5px); + margin-left: -5px; + } + .left::after { + right: -10px; + border-color: transparent transparent transparent black; + top: calc(50% - 5px); + margin-top: -5px; + } + .visible { + z-index: 50; + opacity: 1; + transition: opacity 0.2s; + } + .contentTooltip { + width: 100%; + display: inline-block; + } +} diff --git a/twake/frontend/src/app/components/twacode/blocks/chan.tsx b/twake/frontend/src/app/components/twacode/blocks/chan.tsx new file mode 100755 index 00000000..c05db283 --- /dev/null +++ b/twake/frontend/src/app/components/twacode/blocks/chan.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import Emojione from 'components/emojione/emojione'; +import MainViewService from 'app/features/router/services/main-view-service'; +import { useChannel } from 'app/features/channels/hooks/use-channel'; + +type PropsType = { + // channel id + id: string; + // channel name + name: string; +}; + +export default (props: PropsType): JSX.Element => { + const { channel } = useChannel(props.id); + + if (!props.id || !channel) { + return #{props.name}; + } + + return ( +
{ + MainViewService.select(props.id, { + app: { + identity: { + code: 'messages', + name: '', + icon: '', + description: '', + website: '', + categories: [], + compatibility: [], + }, + }, + context: { type: 'channel' }, + hasTabs: channel.visibility !== 'direct', + }); + }} + > + + {channel.name} +
+ ); +}; diff --git a/twake/frontend/src/app/components/twacode/blocks/user.tsx b/twake/frontend/src/app/components/twacode/blocks/user.tsx new file mode 100644 index 00000000..e3704a31 --- /dev/null +++ b/twake/frontend/src/app/components/twacode/blocks/user.tsx @@ -0,0 +1,96 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React, { useEffect, useRef, useState } from 'react'; +import classNames from 'classnames'; +import UserService from 'app/features/users/services/current-user-service'; +import MenusManager from 'app/components/menus/menus-manager.jsx'; +import UserCard from 'app/components/user-card/user-card'; +import { UserType } from 'app/features/users/types/user'; +import { useUser, useUserByUsername } from 'app/features/users/hooks/use-user'; +import Collections from 'app/deprecated/CollectionsV1/Collections/Collections'; +import { useDirectChannels } from 'app/features/channels/hooks/use-direct-channels'; + +const globalMentions = ['channel', 'everyone', 'all', 'here']; + +type PropsType = { + // User id + id?: string; + // user username + username?: string; + // should we hide the user image? + hideUserImage?: boolean; +}; + +export default (props: PropsType): JSX.Element => { + const { openDiscussion } = useDirectChannels(); + const collection = Collections.get('users'); + const nodeRef = useRef(null); + let user: UserType | undefined; + if (props.id) { + user = useUser(props.id || ''); + } else { + user = useUserByUsername(props.username || ''); + } + + useEffect(() => { + const listener = collection.addListener(useState, [user]); + + return () => { + collection.removeListener(listener); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [user]); + + const displayUserCard = (user: UserType): void => { + if (!nodeRef.current) { + return; + } + + MenusManager.openMenu( + [ + { + type: 'react-element', + reactElement: () => ( + openDiscussion([user.id || ''])} /> + ), + }, + ], + (window as any).getBoundingClientRect(nodeRef.current), + null, + { margin: 8 }, + ); + }; + + const highlighted = + user?.id === UserService.getCurrentUserId() || + globalMentions.includes(props.username || props.id || ''); + + if (user) { + return ( +
displayUserCard(user as UserType)} + style={{ + paddingLeft: props.hideUserImage ? 5 : 0, + backgroundColor: props.hideUserImage ? 'var(--grey-background)' : '', + }} + > + {!props.hideUserImage && ( +
+ )} + {UserService.getFullName(user)} +
+ ); + } else { + return ( + + @{props.username || 'unknown'} + + ); + } +}; diff --git a/twake/frontend/src/app/components/twacode/blocksCompiler.ts b/twake/frontend/src/app/components/twacode/blocksCompiler.ts new file mode 100644 index 00000000..1028b0b1 --- /dev/null +++ b/twake/frontend/src/app/components/twacode/blocksCompiler.ts @@ -0,0 +1,262 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { + Block, + BlockActions, + BlockContext, + BlockDivider, + BlockElementButton, + BlockElementCheckboxes, + BlockElementDatePicker, + BlockElementImage, + BlockElementMultiselectMenu, + BlockElementOverflowMenus, + BlockElementProgressBar, + BlockElementRadioButtonInput, + BlockElementSelectMenus, + BlockIframe, + BlockImage, + BlockInput, + BlockSection, +} from './types'; + +export const formatData = ( + object: any, + content: any, + flatted: Block[], + level: number | null = null, +) => { + for (let i = 0; i < object.length; i++) { + const recursif = + object[content] && typeof object[content] !== 'string' ? { ...object[content] } : null; + + delete object[content]; + flatted.push(object[i]); + const currentLevel = level ? level + 1 : 1; + if (recursif) { + formatData(recursif, content, flatted, currentLevel); + } + } +}; + +export const blocksToTwacode = (event: Block[]) => { + const blocks: any[] = []; + + event.forEach((obj: Block) => { + let object = obj; + + switch (object.type) { + case 'actions': + object = object as BlockActions; + for (let i = 0; i < object.elements.length; i++) { + const element = object.elements[i]; + createTwacodeElements(element, blocks); + } + lineBreak(blocks); + break; + case 'context': + object = object as BlockContext; + for (let i = 0; i < object.elements.length; i++) { + const element = object.elements[i]; + createTwacodeElements(element, blocks); + } + lineBreak(blocks); + break; + case 'divider': + object = object as BlockDivider; + blocks.push(blocks); + break; + case 'header': + createTwacodeElements({ type: 'mrkdwn', text: `\n **${object.text.text}** \n` }, blocks); + + break; + case 'image': + object = object as BlockImage; + createTwacodeElements(object, blocks, object.type); + lineBreak(blocks); + break; + + case 'input': + object = object as BlockInput; + createTwacodeElements(object, blocks); + break; + case 'section': + object = object as BlockSection; + if (object.text) { + createTwacodeElements(object.text, blocks); + lineBreak(blocks); + } + if (object.fields) { + for (let i = 0; i < object.fields.length; i++) { + const element = object.fields[i]; + createTwacodeElements(element, blocks); + lineBreak(blocks); + } + } + if (object.accessory) { + const element = object.accessory; + createTwacodeElements(element, blocks); + } + lineBreak(blocks); + + break; + case 'iframe': + object = object as BlockIframe; + createTwacodeElements( + { + type: 'iframe', + src: object.iframe_url, + width: object.width, + height: object.height, + }, + blocks, + object.type, + ); + break; + case 'twacode': + blocks.push(object.elements); + break; + default: + // TODO + } + }); + return blocks; +}; + +const createTwacodeElements = (object: any, blocks: any[], type?: any) => { + switch (object.type) { + case 'button': + object = object as BlockElementButton; + blocks.push({ + type: 'button', + content: + object.text.emoji === true + ? { type: 'compile', content: object.text.text } + : object.text.text, + action_id: object.action_id, + value: object.value, + style: object.style ? object.style : 'default', + url: object.url, + }); + break; + case 'checkboxes': + object = object as BlockElementCheckboxes; + blocks.push({ type: 'checkboxes' }); + break; + case 'datepicker': + object = object as BlockElementDatePicker; + blocks.push({ type: 'datepicker' }); + break; + case 'image': + object = object as BlockElementImage; + // eslint-disable-next-line @typescript-eslint/no-unused-expressions + object.title + ? blocks.push({ + type: 'system', + content: { + type: 'compile', + content: object.title.text + '\n', + }, + }) + : null; + + blocks.push({ + type: type === 'image' ? 'image' : 'icon', + src: object.image_url, + }); + break; + case 'progress_bar': + object = object as BlockElementProgressBar; + blocks.push({ + type: 'compile', + content: object.title + '\n', + }); + blocks.push({ + type: 'progress_bar', + value: object.value, + }); + break; + case 'multi_static_select': + object = object as BlockElementMultiselectMenu; + blocks.push(generateSelect(object)); + break; + case 'overflow': + object = object as BlockElementOverflowMenus; + blocks.push(generateSelect(object)); + break; + case 'input': + // eslint-disable-next-line @typescript-eslint/no-unused-expressions + object.label.text + ? createTwacodeElements( + { type: 'mrkdwn', text: `**${object.label.text}** \n` }, + blocks, + type, + ) + : null; + createTwacodeElements(object.element, blocks, type); + + break; + case 'plain_text_input': + if (object.readonly === true && object.copiable === true) { + blocks.push({ + type: 'copiable', + content: object.initial_value ? object.initial_value : '', + }); + } else { + blocks.push({ + type: 'input', + placeholder: object.placeholder ? object.placeholder.text : null, + passive_id: object.action_id, + }); + lineBreak(blocks); + } + break; + case 'radio_buttons': + object = object as BlockElementRadioButtonInput; + blocks.push(generateSelect(object)); + break; + case 'static_select': + object = object as BlockElementSelectMenus; + blocks.push(generateSelect(object)); + break; + case 'timepicker': + //not implemented yet + break; + case 'context': + if (object.elements[0].type === 'mrkdwn') { + createTwacodeElements(object.elements[0], blocks); + } else { + createTwacodeElements(object.elements[0], blocks); + } + break; + case 'mrkdwn': + blocks.push({ + type: 'compile', + content: object.text, + }); + break; + case 'plain_text': + blocks.push({ + type: 'text', + content: object.text, + }); + break; + default: + // TODO + } +}; + +const generateSelect = (object: any) => { + return { + type: 'select', + //placeholder not yet implemented + title: '', + values: object.options.map((option: any) => { + return { name: option.text.text, value: option.value }; + }), + action_id: object.action_id, + }; +}; + +const lineBreak = (blocks: any[]) => { + createTwacodeElements({ type: 'mrkdwn', text: '\n' }, blocks); +}; diff --git a/twake/frontend/src/app/components/twacode/compile.tsx b/twake/frontend/src/app/components/twacode/compile.tsx new file mode 100644 index 00000000..f8f9d818 --- /dev/null +++ b/twake/frontend/src/app/components/twacode/compile.tsx @@ -0,0 +1,118 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import _ from 'lodash'; +import React from 'react'; +import PseudoMarkdownCompiler from 'app/features/global/services/pseudo-markdown-compiler-service'; +import { DynamicComponent } from './pseudo-markdown-dictionary'; + +type Props = { + content: any; + isApp: boolean; + eventContainer: any; + textTransform?: any; +}; + +const Compile = (props: Props) => { + let content = props.content; + const isApp = props.isApp; + const eventContainer = props.eventContainer; + let textTransform = props.textTransform; + + if (!content) { + return PseudoMarkdownCompiler.pseudo_markdown['text'].object(''); + } + + if (!textTransform) textTransform = {}; + if (content.formatted || content.prepared) content = content.formatted || content.prepared; + if (typeof content === 'string') content = [content]; + if (content.type || content.start) content = [content]; + + if (!_.isArray(content)) { + content = [content]; + } + + try { + return ( + <> + {content.map((item: any, index: number) => { + if (typeof item === 'string') { + return ( + + {item} + + ); + } else if (Array.isArray(item)) { + return ( + + ); + } else { + let type = PseudoMarkdownCompiler.pseudo_markdown[item.start]; + if (item.type === 'compile' && isApp && typeof item.content === 'string') { + return ( + + ); + } else { + if (item.type) { + type = PseudoMarkdownCompiler.pseudo_markdown_types[item.type]; + } + if (type) { + if (!type.apps_only || isApp) { + //If text transform do it + const old_textTransform = JSON.parse(JSON.stringify(textTransform)); + textTransform = JSON.parse(JSON.stringify(textTransform)); + if (type.textTransform) { + Object.keys(type.textTransform).forEach(key => { + textTransform[key] = type.textTransform[key]; + }); + } + + textTransform = old_textTransform; + + return ( + + + } + data={item} + eventContainer={eventContainer} + textTransform={textTransform} + /> + + ); + } + } + } + } + })} + + ); + } catch (e) { + //Nothing + } + + return ( + + An error occured while showing PseudoMarkdownCompiler message. + + ); +}; + +export default Compile; diff --git a/twake/frontend/src/app/components/twacode/pseudo-markdown-dictionary.tsx b/twake/frontend/src/app/components/twacode/pseudo-markdown-dictionary.tsx new file mode 100644 index 00000000..b9463ff6 --- /dev/null +++ b/twake/frontend/src/app/components/twacode/pseudo-markdown-dictionary.tsx @@ -0,0 +1,383 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import React, { ReactNode } from 'react'; + +import Emojione from 'components/emojione/emojione'; +import HighlightedCode from 'components/highlighted-code/highlighted-code'; +import User from './blocks/user'; +import Chan from './blocks/chan'; +import File from 'components/drive/file'; +import InputWithClipBoard from 'components/input-with-clip-board/input-with-clip-board.jsx'; +import UserService from 'app/features/users/services/current-user-service'; +import Button from 'components/buttons/button.jsx'; +import Input from 'components/inputs/input.jsx'; + +export const DynamicComponent = ({ + type, + child, + data, + eventContainer, + textTransform, +}: { + type?: string; + child?: ReactNode; + data?: any; + eventContainer?: any; + textTransform?: any; +}) => { + if (type === 'text_block_parent') { + return {child}; + } + if (type === 'text') { + return {child}; + } + if (type === 'br') { + return ( + <> +
+ {child} + + ); + } + if (type === 'emoji') { + return ; + } + if (type === 'user') { + const split = (data.content || '').split(':'); + const id = data.id || split[1]; + const username = split[0]; + return ( + <> + + + + ); + } + if (type === 'channel') { + const split = (data.content || '').split(':'); + const id = data.id || split[1]; + const name = split[0]; + return ( + <> + + + + ); + } + if (type === 'underline') return
{child}
; + if (type === 'strikethrough') return
{child}
; + if (type === 'bold') return
{child}
; + if (type === 'italic') return
{child}
; + if (type === 'mquote') return
{child}
; + if (type === 'quote') return
{child}
; + if (type === 'nop') { + return <>{child}; + } + + if (type === 'mcode') { + return ; + } + if (type === 'icode') { + return
{(data.content || '').trim()}
; + } + if (type === 'url') { + if (!data.url && data.url !== undefined) { + return {child}; + } + let url = setUrlProtocol(data.url || data.content); + if (data.user_identifier && UserService.getCurrentUser()) { + let separator = '?'; + if (url.indexOf('?') > 0) { + separator = '&'; + } + url += separator + 'twake_user=' + UserService.getCurrentUser().id; + } + return ( + // eslint-disable-next-line react/jsx-no-target-blank + + {child} + + ); + } + if (type === 'markdown_link') { + const linkData = data.content.split(']('); + const url = linkData[1] || ''; + + return ( + + {linkData[0]} + + ); + } + if (type === 'email') { + return ( + + {child} + + ); + } + if (type === 'system') { + return {child}; + } + + if (type === 'file') { + return ( +
+ +
+ ); + } + if (type === 'iframe') { + return ( +